From 6221bbc5a7312598a9d83bd29c9a6136d01b9323 Mon Sep 17 00:00:00 2001 From: king6cong Date: Sat, 30 Sep 2017 14:55:16 +0800 Subject: [PATCH 0001/5092] update trans_fulfill_obligation call signature --- src/librustc_mir/interpret/eval_context.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 3388031a30ca..b483cf1aed86 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -6,6 +6,7 @@ use rustc::hir::map::definitions::DefPathData; use rustc::middle::const_val::ConstVal; use rustc::middle::region; use rustc::mir; +use rustc::traits; use rustc::traits::Reveal; use rustc::ty::layout::{self, Layout, Size, Align, HasDataLayout}; use rustc::ty::subst::{Subst, Substs, Kind}; @@ -2411,7 +2412,7 @@ fn resolve_associated_item<'a, 'tcx>( ); let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); - let vtbl = tcx.trans_fulfill_obligation(DUMMY_SP, ty::Binder(trait_ref)); + let vtbl = tcx.trans_fulfill_obligation(DUMMY_SP, ty::ParamEnv::empty(traits::Reveal::All), ty::Binder(trait_ref)); // Now that we know which impl is being used, we can dispatch to // the actual function: From 3d1332d7f813fece8a0e98124aa6a7595e58d512 Mon Sep 17 00:00:00 2001 From: king6cong Date: Sat, 30 Sep 2017 15:07:07 +0800 Subject: [PATCH 0002/5092] update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 22cb5aed79b1..7660735a7cef 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ how to fix it, you could send a PR. :smile: ## Running tests ```sh -cargo run --bin miri tests/run-pass/vecs.rs # Or whatever test you like. +cargo run --bin miri tests/run-pass-fullmir/vecs.rs # Or whatever test you like. ``` ## Debugging From 52599adf2752feb4432422b355dac22e66a1cf09 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 5 Oct 2017 12:31:47 +0200 Subject: [PATCH 0003/5092] Miri core has moved to rustc::mir::interpret --- Cargo.lock | 96 +- Cargo.toml | 1 - miri/fn_call.rs | 16 +- miri/helpers.rs | 2 +- miri/intrinsic.rs | 4 +- miri/lib.rs | 25 +- miri/memory.rs | 6 +- miri/operator.rs | 4 +- src/librustc_mir/Cargo.toml | 19 - src/librustc_mir/interpret/cast.rs | 122 - src/librustc_mir/interpret/const_eval.rs | 259 -- src/librustc_mir/interpret/error.rs | 313 -- src/librustc_mir/interpret/eval_context.rs | 2535 ----------------- src/librustc_mir/interpret/lvalue.rs | 506 ---- src/librustc_mir/interpret/machine.rs | 82 - src/librustc_mir/interpret/memory.rs | 1700 ----------- src/librustc_mir/interpret/mod.rs | 42 - src/librustc_mir/interpret/operator.rs | 268 -- src/librustc_mir/interpret/range_map.rs | 250 -- src/librustc_mir/interpret/step.rs | 402 --- src/librustc_mir/interpret/terminator/drop.rs | 83 - src/librustc_mir/interpret/terminator/mod.rs | 411 --- src/librustc_mir/interpret/traits.rs | 137 - src/librustc_mir/interpret/validation.rs | 727 ----- src/librustc_mir/interpret/value.rs | 405 --- src/librustc_mir/lib.rs | 26 - 26 files changed, 36 insertions(+), 8405 deletions(-) delete mode 100644 src/librustc_mir/Cargo.toml delete mode 100644 src/librustc_mir/interpret/cast.rs delete mode 100644 src/librustc_mir/interpret/const_eval.rs delete mode 100644 src/librustc_mir/interpret/error.rs delete mode 100644 src/librustc_mir/interpret/eval_context.rs delete mode 100644 src/librustc_mir/interpret/lvalue.rs delete mode 100644 src/librustc_mir/interpret/machine.rs delete mode 100644 src/librustc_mir/interpret/memory.rs delete mode 100644 src/librustc_mir/interpret/mod.rs delete mode 100644 src/librustc_mir/interpret/operator.rs delete mode 100644 src/librustc_mir/interpret/range_map.rs delete mode 100644 src/librustc_mir/interpret/step.rs delete mode 100644 src/librustc_mir/interpret/terminator/drop.rs delete mode 100644 src/librustc_mir/interpret/terminator/mod.rs delete mode 100644 src/librustc_mir/interpret/traits.rs delete mode 100644 src/librustc_mir/interpret/validation.rs delete mode 100644 src/librustc_mir/interpret/value.rs delete mode 100644 src/librustc_mir/lib.rs diff --git a/Cargo.lock b/Cargo.lock index c84d79a089c3..ecc1e85596c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,13 +1,13 @@ [root] -name = "rustc_miri" +name = "miri" version = "0.1.0" dependencies = [ - "backtrace 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "compiletest_rs 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -18,29 +18,6 @@ dependencies = [ "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "backtrace" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "backtrace-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "backtrace-sys" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "bitflags" version = "0.7.0" @@ -61,11 +38,6 @@ dependencies = [ "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "cfg-if" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "compiletest_rs" version = "0.3.1" @@ -93,15 +65,6 @@ name = "custom_derive" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "dbghelp-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "diff" version = "0.1.10" @@ -129,11 +92,6 @@ dependencies = [ "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "gcc" -version = "0.3.53" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "getopts" version = "0.2.15" @@ -144,15 +102,6 @@ name = "itoa" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "lazy_static" version = "0.2.8" @@ -201,19 +150,6 @@ dependencies = [ "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "miri" -version = "0.1.0" -dependencies = [ - "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "compiletest_rs 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_miri 0.1.0", -] - [[package]] name = "num-traits" version = "0.1.40" @@ -250,11 +186,6 @@ name = "regex-syntax" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "rustc-demangle" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "rustc-serialize" version = "0.3.24" @@ -353,36 +284,20 @@ name = "void" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [metadata] "checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" -"checksum backtrace 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "99f2ce94e22b8e664d95c57fff45b98a966c2252b60691d0b7aeeccd88d70983" -"checksum backtrace-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "afccc5772ba333abccdf60d55200fa3406f8c59dcf54d5f7998c9107d3799c7c" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d" "checksum cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "be1057b8462184f634c3a208ee35b0f935cfd94b694b26deadccd98732088d7b" -"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "checksum compiletest_rs 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "86f4663adfd113e17109c35c2067194eca782a5baf9c90f4696ca13d04631adb" "checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299" "checksum custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" -"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" "checksum diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0a515461b6c8c08419850ced27bc29e86166dcdcde8fbe76f8b1f0589bb49472" "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" "checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b" "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" -"checksum gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)" = "e8310f7e9c890398b0e80e301c4f474e9918d2b27fca8f48486ca775fa9ffc5a" "checksum getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "65922871abd2f101a2eb0eaebadc66668e54a87ad9c3dd82520b5f86ede5eff9" "checksum itoa 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f74cf6ca1bdbc28496a2b9798ab7fccc2ca5a42cace95bb2b219577216a5fb90" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" "checksum libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)" = "2370ca07ec338939e356443dac2296f581453c35fe1e3a3ed06023c49435f915" "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" @@ -395,7 +310,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "eb250fd207a4729c976794d03db689c9be1d634ab5a1c9da9492a13d8fecbcdf" "checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b" "checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" -"checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f7726f29ddf9731b17ff113c461e362c381d9d69433f79de4f3dd572488823e9" "checksum serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cf823e706be268e73e7747b147aa31c8f633ab4ba31f115efb57e5047c3a76dd" @@ -409,5 +323,3 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/Cargo.toml b/Cargo.toml index b3db572871da..34cbfcc03a2f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,6 @@ env_logger = "0.4.3" log = "0.3.6" log_settings = "0.1.1" cargo_metadata = { version = "0.2", optional = true } -rustc_miri = { path = "src/librustc_mir" } [features] cargo_miri = ["cargo_metadata"] diff --git a/miri/fn_call.rs b/miri/fn_call.rs index 79ef3f97a9e9..77a22ac9c35f 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -7,7 +7,8 @@ use syntax::codemap::Span; use std::mem; -use rustc_miri::interpret::*; +use rustc::mir::interpret::*; +use rustc::traits; use super::{TlsKey, EvalContext}; @@ -109,7 +110,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> self.write_null(dest, dest_ty)?; } else { let align = self.memory.pointer_size(); - let ptr = self.memory.allocate(size, align, MemoryKind::C.into())?; + let ptr = self.memory.allocate(size, align, Some(MemoryKind::C.into()))?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } } @@ -305,7 +306,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> let value_copy = self.memory.allocate( (value.len() + 1) as u64, 1, - MemoryKind::Env.into(), + Some(MemoryKind::Env.into()), )?; self.memory.write_bytes(value_copy.into(), &value)?; let trailing_zero_ptr = value_copy.offset(value.len() as u64, &self)?.into(); @@ -381,9 +382,10 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> }; // compute global if not cached let val = match self.globals.get(&cid).cloned() { - Some(ptr) => self.value_to_primval(ValTy { value: Value::ByRef(ptr), ty: args[0].ty })?.to_u64()?, - None => eval_body_as_primval(self.tcx, instance)?.0.to_u64()?, + Some(ptr) => ptr, + None => eval_body(self.tcx, instance, ty::ParamEnv::empty(traits::Reveal::All))?.0, }; + let val = self.value_to_primval(ValTy { value: Value::ByRef(val), ty: args[0].ty })?.to_u64()?; if val == name { result = Some(path_value); break; @@ -558,7 +560,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory.allocate(size, align, MemoryKind::Rust.into())?; + let ptr = self.memory.allocate(size, align, Some(MemoryKind::Rust.into()))?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } "alloc::heap::::__rust_alloc_zeroed" => { @@ -570,7 +572,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory.allocate(size, align, MemoryKind::Rust.into())?; + let ptr = self.memory.allocate(size, align, Some(MemoryKind::Rust.into()))?; self.memory.write_repeat(ptr.into(), 0, size)?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } diff --git a/miri/helpers.rs b/miri/helpers.rs index 809e5ebfacdb..3ee148afb2b2 100644 --- a/miri/helpers.rs +++ b/miri/helpers.rs @@ -1,4 +1,4 @@ -use rustc_miri::interpret::{Pointer, EvalResult, PrimVal, EvalContext}; +use rustc::mir::interpret::{Pointer, EvalResult, PrimVal, EvalContext}; use rustc::ty::Ty; diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index bcff3b4aa991..b41a75351971 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -3,7 +3,7 @@ use rustc::traits::Reveal; use rustc::ty::layout::Layout; use rustc::ty::{self, Ty}; -use rustc_miri::interpret::{EvalResult, Lvalue, LvalueExtra, PrimVal, PrimValKind, Value, Pointer, +use rustc::mir::interpret::{EvalResult, Lvalue, LvalueExtra, PrimVal, PrimValKind, Value, Pointer, HasMemory, AccessKind, EvalContext, PtrAndAlign, ValTy}; use helpers::EvalContextExt as HelperEvalContextExt; @@ -654,7 +654,7 @@ fn numeric_intrinsic<'tcx>( ) -> EvalResult<'tcx, PrimVal> { macro_rules! integer_intrinsic { ($method:ident) => ({ - use rustc_miri::interpret::PrimValKind::*; + use rustc::mir::interpret::PrimValKind::*; let result_bytes = match kind { I8 => (bytes as i8).$method() as u128, U8 => (bytes as u8).$method() as u128, diff --git a/miri/lib.rs b/miri/lib.rs index f6ecd6e0b00b..27bd3d5939f3 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -14,15 +14,14 @@ use rustc::ty::{self, TyCtxt}; use rustc::ty::layout::Layout; use rustc::hir::def_id::DefId; use rustc::mir; +use rustc::traits; use syntax::ast::Mutability; use syntax::codemap::Span; use std::collections::{HashMap, BTreeMap}; -#[macro_use] -extern crate rustc_miri; -pub use rustc_miri::interpret::*; +pub use rustc::mir::interpret::*; mod fn_call; mod operator; @@ -43,7 +42,7 @@ pub fn eval_main<'a, 'tcx: 'a>( limits: ResourceLimits, ) { fn run_main<'a, 'tcx: 'a>( - ecx: &mut rustc_miri::interpret::EvalContext<'a, 'tcx, Evaluator>, + ecx: &mut rustc::mir::interpret::EvalContext<'a, 'tcx, Evaluator>, main_id: DefId, start_wrapper: Option, ) -> EvalResult<'tcx> { @@ -72,7 +71,7 @@ pub fn eval_main<'a, 'tcx: 'a>( // Return value let size = ecx.tcx.data_layout.pointer_size.bytes(); let align = ecx.tcx.data_layout.pointer_align.abi(); - let ret_ptr = ecx.memory_mut().allocate(size, align, MemoryKind::Stack)?; + let ret_ptr = ecx.memory_mut().allocate(size, align, Some(MemoryKind::Stack))?; cleanup_ptr = Some(ret_ptr); // Push our stack frame @@ -108,9 +107,9 @@ pub fn eval_main<'a, 'tcx: 'a>( // Third argument (argv): &[b"foo"] let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?; let ty = ecx.tcx.mk_imm_ptr(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8)); - let foo = ecx.memory.allocate_cached(b"foo\0")?; + let foo = ecx.memory.allocate_cached(b"foo\0"); let ptr_size = ecx.memory.pointer_size(); - let foo_ptr = ecx.memory.allocate(ptr_size * 1, ptr_size, MemoryKind::UninitializedStatic)?; + let foo_ptr = ecx.memory.allocate(ptr_size * 1, ptr_size, None)?; ecx.memory.write_primval(foo_ptr.into(), PrimVal::Ptr(foo.into()), ptr_size, false)?; ecx.memory.mark_static_initalized(foo_ptr.alloc_id, Mutability::Immutable)?; ecx.write_ptr(dest, foo_ptr.into(), ty)?; @@ -186,6 +185,12 @@ impl<'tcx> Machine<'tcx> for Evaluator { type MemoryData = MemoryData<'tcx>; type MemoryKinds = memory::MemoryKind; + fn param_env<'a>( + _: &EvalContext<'a, 'tcx, Self>, + ) -> ty::ParamEnv<'tcx> { + ty::ParamEnv::empty(traits::Reveal::All) + } + /// Returns Ok() when the function was handled, fail otherwise fn eval_fn_call<'a>( ecx: &mut EvalContext<'a, 'tcx, Self>, @@ -199,7 +204,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { } fn call_intrinsic<'a>( - ecx: &mut rustc_miri::interpret::EvalContext<'a, 'tcx, Self>, + ecx: &mut rustc::mir::interpret::EvalContext<'a, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[ValTy<'tcx>], dest: Lvalue, @@ -211,7 +216,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { } fn try_ptr_op<'a>( - ecx: &rustc_miri::interpret::EvalContext<'a, 'tcx, Self>, + ecx: &rustc::mir::interpret::EvalContext<'a, 'tcx, Self>, bin_op: mir::BinOp, left: PrimVal, left_ty: ty::Ty<'tcx>, @@ -292,7 +297,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { let ptr = ecx.memory.allocate( ptr_size, ptr_size, - MemoryKind::UninitializedStatic, + None, )?; ecx.memory.write_ptr_sized_unsigned(ptr, PrimVal::Bytes(0))?; ecx.memory.mark_static_initalized(ptr.alloc_id, mutability)?; diff --git a/miri/memory.rs b/miri/memory.rs index 110540c0cf1d..0daba8e280ef 100644 --- a/miri/memory.rs +++ b/miri/memory.rs @@ -9,8 +9,8 @@ pub enum MemoryKind { Env, } -impl Into<::rustc_miri::interpret::MemoryKind> for MemoryKind { - fn into(self) -> ::rustc_miri::interpret::MemoryKind { - ::rustc_miri::interpret::MemoryKind::Machine(self) +impl Into<::rustc::mir::interpret::MemoryKind> for MemoryKind { + fn into(self) -> ::rustc::mir::interpret::MemoryKind { + ::rustc::mir::interpret::MemoryKind::Machine(self) } } diff --git a/miri/operator.rs b/miri/operator.rs index 6d68aadf96cc..04e84d27201b 100644 --- a/miri/operator.rs +++ b/miri/operator.rs @@ -1,7 +1,7 @@ use rustc::ty; use rustc::mir; -use rustc_miri::interpret::*; +use rustc::mir::interpret::*; use helpers::EvalContextExt as HelperEvalContextExt; @@ -33,7 +33,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> right: PrimVal, right_ty: ty::Ty<'tcx>, ) -> EvalResult<'tcx, Option<(PrimVal, bool)>> { - use rustc_miri::interpret::PrimValKind::*; + use rustc::mir::interpret::PrimValKind::*; use rustc::mir::BinOp::*; let usize = PrimValKind::from_uint_size(self.memory.pointer_size()); let isize = PrimValKind::from_int_size(self.memory.pointer_size()); diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml deleted file mode 100644 index c72de828c8d2..000000000000 --- a/src/librustc_mir/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -authors = ["Scott Olson "] -description = "An experimental interpreter for Rust MIR." -license = "MIT/Apache-2.0" -name = "rustc_miri" -repository = "https://github.com/solson/miri" -version = "0.1.0" -workspace = "../.." - -[lib] -path = "lib.rs" - -[dependencies] -byteorder = { version = "1.1", features = ["i128"]} -log = "0.3.6" -log_settings = "0.1.1" -lazy_static = "0.2.8" -regex = "0.2.2" -backtrace = "0.3.3" diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs deleted file mode 100644 index 5ae7c9da31c0..000000000000 --- a/src/librustc_mir/interpret/cast.rs +++ /dev/null @@ -1,122 +0,0 @@ -use rustc::ty::{self, Ty}; -use syntax::ast::{FloatTy, IntTy, UintTy}; - -use super::{PrimVal, EvalContext, EvalResult, MemoryPointer, PointerArithmetic, Machine}; - -impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { - pub(super) fn cast_primval( - &self, - val: PrimVal, - src_ty: Ty<'tcx>, - dest_ty: Ty<'tcx>, - ) -> EvalResult<'tcx, PrimVal> { - trace!("Casting {:?}: {:?} to {:?}", val, src_ty, dest_ty); - let src_kind = self.ty_to_primval_kind(src_ty)?; - - match val { - PrimVal::Undef => Ok(PrimVal::Undef), - PrimVal::Ptr(ptr) => self.cast_from_ptr(ptr, dest_ty), - val @ PrimVal::Bytes(_) => { - use super::PrimValKind::*; - match src_kind { - F32 => self.cast_from_float(val.to_f32()? as f64, dest_ty), - F64 => self.cast_from_float(val.to_f64()?, dest_ty), - - I8 | I16 | I32 | I64 | I128 => { - self.cast_from_signed_int(val.to_i128()?, dest_ty) - } - - Bool | Char | U8 | U16 | U32 | U64 | U128 | FnPtr | Ptr => { - self.cast_from_int(val.to_u128()?, dest_ty, false) - } - } - } - } - } - - fn cast_from_signed_int(&self, val: i128, ty: ty::Ty<'tcx>) -> EvalResult<'tcx, PrimVal> { - self.cast_from_int(val as u128, ty, val < 0) - } - - fn int_to_int(&self, v: i128, ty: IntTy) -> u128 { - match ty { - IntTy::I8 => v as i8 as u128, - IntTy::I16 => v as i16 as u128, - IntTy::I32 => v as i32 as u128, - IntTy::I64 => v as i64 as u128, - IntTy::I128 => v as u128, - IntTy::Is => { - let ty = self.tcx.sess.target.isize_ty; - self.int_to_int(v, ty) - } - } - } - fn int_to_uint(&self, v: u128, ty: UintTy) -> u128 { - match ty { - UintTy::U8 => v as u8 as u128, - UintTy::U16 => v as u16 as u128, - UintTy::U32 => v as u32 as u128, - UintTy::U64 => v as u64 as u128, - UintTy::U128 => v, - UintTy::Us => { - let ty = self.tcx.sess.target.usize_ty; - self.int_to_uint(v, ty) - } - } - } - - fn cast_from_int( - &self, - v: u128, - ty: ty::Ty<'tcx>, - negative: bool, - ) -> EvalResult<'tcx, PrimVal> { - trace!("cast_from_int: {}, {}, {}", v, ty, negative); - use rustc::ty::TypeVariants::*; - match ty.sty { - // Casts to bool are not permitted by rustc, no need to handle them here. - TyInt(ty) => Ok(PrimVal::Bytes(self.int_to_int(v as i128, ty))), - TyUint(ty) => Ok(PrimVal::Bytes(self.int_to_uint(v, ty))), - - TyFloat(FloatTy::F64) if negative => Ok(PrimVal::from_f64(v as i128 as f64)), - TyFloat(FloatTy::F64) => Ok(PrimVal::from_f64(v as f64)), - TyFloat(FloatTy::F32) if negative => Ok(PrimVal::from_f32(v as i128 as f32)), - TyFloat(FloatTy::F32) => Ok(PrimVal::from_f32(v as f32)), - - TyChar if v as u8 as u128 == v => Ok(PrimVal::Bytes(v)), - TyChar => err!(InvalidChar(v)), - - // No alignment check needed for raw pointers. But we have to truncate to target ptr size. - TyRawPtr(_) => Ok(PrimVal::Bytes(self.memory.truncate_to_ptr(v).0 as u128)), - - _ => err!(Unimplemented(format!("int to {:?} cast", ty))), - } - } - - fn cast_from_float(&self, val: f64, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> { - use rustc::ty::TypeVariants::*; - match ty.sty { - // Casting negative floats to unsigned integers yields zero. - TyUint(_) if val < 0.0 => self.cast_from_int(0, ty, false), - TyInt(_) if val < 0.0 => self.cast_from_int(val as i128 as u128, ty, true), - - TyInt(_) | ty::TyUint(_) => self.cast_from_int(val as u128, ty, false), - - TyFloat(FloatTy::F64) => Ok(PrimVal::from_f64(val)), - TyFloat(FloatTy::F32) => Ok(PrimVal::from_f32(val as f32)), - _ => err!(Unimplemented(format!("float to {:?} cast", ty))), - } - } - - fn cast_from_ptr(&self, ptr: MemoryPointer, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> { - use rustc::ty::TypeVariants::*; - match ty.sty { - // Casting to a reference or fn pointer is not permitted by rustc, no need to support it here. - TyRawPtr(_) | - TyInt(IntTy::Is) | - TyUint(UintTy::Us) => Ok(PrimVal::Ptr(ptr)), - TyInt(_) | TyUint(_) => err!(ReadPointerAsBytes), - _ => err!(Unimplemented(format!("ptr to {:?} cast", ty))), - } - } -} diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs deleted file mode 100644 index 075880fc5bfd..000000000000 --- a/src/librustc_mir/interpret/const_eval.rs +++ /dev/null @@ -1,259 +0,0 @@ -use rustc::traits::Reveal; -use rustc::ty::{self, TyCtxt, Ty, Instance, layout}; -use rustc::mir; - -use syntax::ast::Mutability; -use syntax::codemap::Span; - -use super::{EvalResult, EvalError, EvalErrorKind, GlobalId, Lvalue, Value, PrimVal, EvalContext, - StackPopCleanup, PtrAndAlign, MemoryKind, ValTy}; - -use rustc_const_math::ConstInt; - -use std::fmt; -use std::error::Error; - -pub fn eval_body_as_primval<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - instance: Instance<'tcx>, -) -> EvalResult<'tcx, (PrimVal, Ty<'tcx>)> { - let limits = super::ResourceLimits::default(); - let mut ecx = EvalContext::::new(tcx, limits, (), ()); - let cid = GlobalId { - instance, - promoted: None, - }; - if ecx.tcx.has_attr(instance.def_id(), "linkage") { - return Err(ConstEvalError::NotConst("extern global".to_string()).into()); - } - - let mir = ecx.load_mir(instance.def)?; - if !ecx.globals.contains_key(&cid) { - let size = ecx.type_size_with_substs(mir.return_ty, instance.substs)? - .expect("unsized global"); - let align = ecx.type_align_with_substs(mir.return_ty, instance.substs)?; - let ptr = ecx.memory.allocate( - size, - align, - MemoryKind::UninitializedStatic, - )?; - let aligned = !ecx.is_packed(mir.return_ty)?; - ecx.globals.insert( - cid, - PtrAndAlign { - ptr: ptr.into(), - aligned, - }, - ); - let mutable = !mir.return_ty.is_freeze( - ecx.tcx, - ty::ParamEnv::empty(Reveal::All), - mir.span, - ); - let mutability = if mutable { - Mutability::Mutable - } else { - Mutability::Immutable - }; - let cleanup = StackPopCleanup::MarkStatic(mutability); - let name = ty::tls::with(|tcx| tcx.item_path_str(instance.def_id())); - trace!("const_eval: pushing stack frame for global: {}", name); - ecx.push_stack_frame( - instance, - mir.span, - mir, - Lvalue::from_ptr(ptr), - cleanup, - )?; - - while ecx.step()? {} - } - let value = Value::ByRef(*ecx.globals.get(&cid).expect("global not cached")); - let valty = ValTy { - value, - ty: mir.return_ty, - }; - Ok((ecx.value_to_primval(valty)?, mir.return_ty)) -} - -pub fn eval_body_as_integer<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - instance: Instance<'tcx>, -) -> EvalResult<'tcx, ConstInt> { - let (prim, ty) = eval_body_as_primval(tcx, instance)?; - let prim = prim.to_bytes()?; - use syntax::ast::{IntTy, UintTy}; - use rustc::ty::TypeVariants::*; - use rustc_const_math::{ConstIsize, ConstUsize}; - Ok(match ty.sty { - TyInt(IntTy::I8) => ConstInt::I8(prim as i128 as i8), - TyInt(IntTy::I16) => ConstInt::I16(prim as i128 as i16), - TyInt(IntTy::I32) => ConstInt::I32(prim as i128 as i32), - TyInt(IntTy::I64) => ConstInt::I64(prim as i128 as i64), - TyInt(IntTy::I128) => ConstInt::I128(prim as i128), - TyInt(IntTy::Is) => ConstInt::Isize( - ConstIsize::new(prim as i128 as i64, tcx.sess.target.isize_ty) - .expect("miri should already have errored"), - ), - TyUint(UintTy::U8) => ConstInt::U8(prim as u8), - TyUint(UintTy::U16) => ConstInt::U16(prim as u16), - TyUint(UintTy::U32) => ConstInt::U32(prim as u32), - TyUint(UintTy::U64) => ConstInt::U64(prim as u64), - TyUint(UintTy::U128) => ConstInt::U128(prim), - TyUint(UintTy::Us) => ConstInt::Usize( - ConstUsize::new(prim as u64, tcx.sess.target.usize_ty) - .expect("miri should already have errored"), - ), - _ => { - return Err( - ConstEvalError::NeedsRfc( - "evaluating anything other than isize/usize during typeck".to_string(), - ).into(), - ) - } - }) -} - -struct CompileTimeFunctionEvaluator; - -impl<'tcx> Into> for ConstEvalError { - fn into(self) -> EvalError<'tcx> { - EvalErrorKind::MachineError(Box::new(self)).into() - } -} - -#[derive(Clone, Debug)] -enum ConstEvalError { - NeedsRfc(String), - NotConst(String), -} - -impl fmt::Display for ConstEvalError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use self::ConstEvalError::*; - match *self { - NeedsRfc(ref msg) => { - write!( - f, - "\"{}\" needs an rfc before being allowed inside constants", - msg - ) - } - NotConst(ref msg) => write!(f, "Cannot evaluate within constants: \"{}\"", msg), - } - } -} - -impl Error for ConstEvalError { - fn description(&self) -> &str { - use self::ConstEvalError::*; - match *self { - NeedsRfc(_) => "this feature needs an rfc before being allowed inside constants", - NotConst(_) => "this feature is not compatible with constant evaluation", - } - } - - fn cause(&self) -> Option<&Error> { - None - } -} - -impl<'tcx> super::Machine<'tcx> for CompileTimeFunctionEvaluator { - type Data = (); - type MemoryData = (); - type MemoryKinds = !; - fn eval_fn_call<'a>( - ecx: &mut EvalContext<'a, 'tcx, Self>, - instance: ty::Instance<'tcx>, - destination: Option<(Lvalue, mir::BasicBlock)>, - _args: &[ValTy<'tcx>], - span: Span, - _sig: ty::FnSig<'tcx>, - ) -> EvalResult<'tcx, bool> { - if !ecx.tcx.is_const_fn(instance.def_id()) { - return Err( - ConstEvalError::NotConst(format!("calling non-const fn `{}`", instance)).into(), - ); - } - let mir = match ecx.load_mir(instance.def) { - Ok(mir) => mir, - Err(EvalError { kind: EvalErrorKind::NoMirFor(path), .. }) => { - // some simple things like `malloc` might get accepted in the future - return Err( - ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path)) - .into(), - ); - } - Err(other) => return Err(other), - }; - let (return_lvalue, return_to_block) = match destination { - Some((lvalue, block)) => (lvalue, StackPopCleanup::Goto(block)), - None => (Lvalue::undef(), StackPopCleanup::None), - }; - - ecx.push_stack_frame( - instance, - span, - mir, - return_lvalue, - return_to_block, - )?; - - Ok(false) - } - - fn call_intrinsic<'a>( - _ecx: &mut EvalContext<'a, 'tcx, Self>, - _instance: ty::Instance<'tcx>, - _args: &[ValTy<'tcx>], - _dest: Lvalue, - _dest_ty: Ty<'tcx>, - _dest_layout: &'tcx layout::Layout, - _target: mir::BasicBlock, - ) -> EvalResult<'tcx> { - Err( - ConstEvalError::NeedsRfc("calling intrinsics".to_string()).into(), - ) - } - - fn try_ptr_op<'a>( - _ecx: &EvalContext<'a, 'tcx, Self>, - _bin_op: mir::BinOp, - left: PrimVal, - _left_ty: Ty<'tcx>, - right: PrimVal, - _right_ty: Ty<'tcx>, - ) -> EvalResult<'tcx, Option<(PrimVal, bool)>> { - if left.is_bytes() && right.is_bytes() { - Ok(None) - } else { - Err( - ConstEvalError::NeedsRfc("Pointer arithmetic or comparison".to_string()).into(), - ) - } - } - - fn mark_static_initialized(m: !) -> EvalResult<'tcx> { - m - } - - fn box_alloc<'a>( - _ecx: &mut EvalContext<'a, 'tcx, Self>, - _ty: ty::Ty<'tcx>, - _dest: Lvalue, - ) -> EvalResult<'tcx> { - Err( - ConstEvalError::NeedsRfc("Heap allocations via `box` keyword".to_string()).into(), - ) - } - - fn global_item_with_linkage<'a>( - _ecx: &mut EvalContext<'a, 'tcx, Self>, - _instance: ty::Instance<'tcx>, - _mutability: Mutability, - ) -> EvalResult<'tcx> { - Err( - ConstEvalError::NotConst("statics with `linkage` attribute".to_string()).into(), - ) - } -} diff --git a/src/librustc_mir/interpret/error.rs b/src/librustc_mir/interpret/error.rs deleted file mode 100644 index 96911c10cca8..000000000000 --- a/src/librustc_mir/interpret/error.rs +++ /dev/null @@ -1,313 +0,0 @@ -use std::error::Error; -use std::{fmt, env}; - -use rustc::mir; -use rustc::ty::{FnSig, Ty, layout}; - -use super::{ - MemoryPointer, Lock, AccessKind -}; - -use rustc_const_math::ConstMathErr; -use syntax::codemap::Span; -use backtrace::Backtrace; - -#[derive(Debug)] -pub struct EvalError<'tcx> { - pub kind: EvalErrorKind<'tcx>, - pub backtrace: Option, -} - -impl<'tcx> From> for EvalError<'tcx> { - fn from(kind: EvalErrorKind<'tcx>) -> Self { - let backtrace = match env::var("RUST_BACKTRACE") { - Ok(ref val) if !val.is_empty() => Some(Backtrace::new_unresolved()), - _ => None - }; - EvalError { - kind, - backtrace, - } - } -} - -#[derive(Debug)] -pub enum EvalErrorKind<'tcx> { - /// This variant is used by machines to signal their own errors that do not - /// match an existing variant - MachineError(Box), - FunctionPointerTyMismatch(FnSig<'tcx>, FnSig<'tcx>), - NoMirFor(String), - UnterminatedCString(MemoryPointer), - DanglingPointerDeref, - DoubleFree, - InvalidMemoryAccess, - InvalidFunctionPointer, - InvalidBool, - InvalidDiscriminant, - PointerOutOfBounds { - ptr: MemoryPointer, - access: bool, - allocation_size: u64, - }, - InvalidNullPointerUsage, - ReadPointerAsBytes, - ReadBytesAsPointer, - InvalidPointerMath, - ReadUndefBytes, - DeadLocal, - InvalidBoolOp(mir::BinOp), - Unimplemented(String), - DerefFunctionPointer, - ExecuteMemory, - ArrayIndexOutOfBounds(Span, u64, u64), - Math(Span, ConstMathErr), - Intrinsic(String), - OverflowingMath, - InvalidChar(u128), - OutOfMemory { - allocation_size: u64, - memory_size: u64, - memory_usage: u64, - }, - ExecutionTimeLimitReached, - StackFrameLimitReached, - OutOfTls, - TlsOutOfBounds, - AbiViolation(String), - AlignmentCheckFailed { - required: u64, - has: u64, - }, - MemoryLockViolation { - ptr: MemoryPointer, - len: u64, - frame: usize, - access: AccessKind, - lock: Lock, - }, - MemoryAcquireConflict { - ptr: MemoryPointer, - len: u64, - kind: AccessKind, - lock: Lock, - }, - InvalidMemoryLockRelease { - ptr: MemoryPointer, - len: u64, - frame: usize, - lock: Lock, - }, - DeallocatedLockedMemory { - ptr: MemoryPointer, - lock: Lock, - }, - ValidationFailure(String), - CalledClosureAsFunction, - VtableForArgumentlessMethod, - ModifiedConstantMemory, - AssumptionNotHeld, - InlineAsm, - TypeNotPrimitive(Ty<'tcx>), - ReallocatedWrongMemoryKind(String, String), - DeallocatedWrongMemoryKind(String, String), - ReallocateNonBasePtr, - DeallocateNonBasePtr, - IncorrectAllocationInformation, - Layout(layout::LayoutError<'tcx>), - HeapAllocZeroBytes, - HeapAllocNonPowerOfTwoAlignment(u64), - Unreachable, - Panic, - ReadFromReturnPointer, - PathNotFound(Vec), -} - -pub type EvalResult<'tcx, T = ()> = Result>; - -impl<'tcx> Error for EvalError<'tcx> { - fn description(&self) -> &str { - use self::EvalErrorKind::*; - match self.kind { - MachineError(ref inner) => inner.description(), - FunctionPointerTyMismatch(..) => - "tried to call a function through a function pointer of a different type", - InvalidMemoryAccess => - "tried to access memory through an invalid pointer", - DanglingPointerDeref => - "dangling pointer was dereferenced", - DoubleFree => - "tried to deallocate dangling pointer", - InvalidFunctionPointer => - "tried to use a function pointer after offsetting it", - InvalidBool => - "invalid boolean value read", - InvalidDiscriminant => - "invalid enum discriminant value read", - PointerOutOfBounds { .. } => - "pointer offset outside bounds of allocation", - InvalidNullPointerUsage => - "invalid use of NULL pointer", - MemoryLockViolation { .. } => - "memory access conflicts with lock", - MemoryAcquireConflict { .. } => - "new memory lock conflicts with existing lock", - ValidationFailure(..) => - "type validation failed", - InvalidMemoryLockRelease { .. } => - "invalid attempt to release write lock", - DeallocatedLockedMemory { .. } => - "tried to deallocate memory in conflict with a lock", - ReadPointerAsBytes => - "a raw memory access tried to access part of a pointer value as raw bytes", - ReadBytesAsPointer => - "a memory access tried to interpret some bytes as a pointer", - InvalidPointerMath => - "attempted to do invalid arithmetic on pointers that would leak base addresses, e.g. comparing pointers into different allocations", - ReadUndefBytes => - "attempted to read undefined bytes", - DeadLocal => - "tried to access a dead local variable", - InvalidBoolOp(_) => - "invalid boolean operation", - Unimplemented(ref msg) => msg, - DerefFunctionPointer => - "tried to dereference a function pointer", - ExecuteMemory => - "tried to treat a memory pointer as a function pointer", - ArrayIndexOutOfBounds(..) => - "array index out of bounds", - Math(..) => - "mathematical operation failed", - Intrinsic(..) => - "intrinsic failed", - OverflowingMath => - "attempted to do overflowing math", - NoMirFor(..) => - "mir not found", - InvalidChar(..) => - "tried to interpret an invalid 32-bit value as a char", - OutOfMemory{..} => - "could not allocate more memory", - ExecutionTimeLimitReached => - "reached the configured maximum execution time", - StackFrameLimitReached => - "reached the configured maximum number of stack frames", - OutOfTls => - "reached the maximum number of representable TLS keys", - TlsOutOfBounds => - "accessed an invalid (unallocated) TLS key", - AbiViolation(ref msg) => msg, - AlignmentCheckFailed{..} => - "tried to execute a misaligned read or write", - CalledClosureAsFunction => - "tried to call a closure through a function pointer", - VtableForArgumentlessMethod => - "tried to call a vtable function without arguments", - ModifiedConstantMemory => - "tried to modify constant memory", - AssumptionNotHeld => - "`assume` argument was false", - InlineAsm => - "miri does not support inline assembly", - TypeNotPrimitive(_) => - "expected primitive type, got nonprimitive", - ReallocatedWrongMemoryKind(_, _) => - "tried to reallocate memory from one kind to another", - DeallocatedWrongMemoryKind(_, _) => - "tried to deallocate memory of the wrong kind", - ReallocateNonBasePtr => - "tried to reallocate with a pointer not to the beginning of an existing object", - DeallocateNonBasePtr => - "tried to deallocate with a pointer not to the beginning of an existing object", - IncorrectAllocationInformation => - "tried to deallocate or reallocate using incorrect alignment or size", - Layout(_) => - "rustc layout computation failed", - UnterminatedCString(_) => - "attempted to get length of a null terminated string, but no null found before end of allocation", - HeapAllocZeroBytes => - "tried to re-, de- or allocate zero bytes on the heap", - HeapAllocNonPowerOfTwoAlignment(_) => - "tried to re-, de-, or allocate heap memory with alignment that is not a power of two", - Unreachable => - "entered unreachable code", - Panic => - "the evaluated program panicked", - ReadFromReturnPointer => - "tried to read from the return pointer", - EvalErrorKind::PathNotFound(_) => - "a path could not be resolved, maybe the crate is not loaded", - } - } - - fn cause(&self) -> Option<&Error> { - use self::EvalErrorKind::*; - match self.kind { - MachineError(ref inner) => Some(&**inner), - _ => None, - } - } -} - -impl<'tcx> fmt::Display for EvalError<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use self::EvalErrorKind::*; - match self.kind { - PointerOutOfBounds { ptr, access, allocation_size } => { - write!(f, "{} at offset {}, outside bounds of allocation {} which has size {}", - if access { "memory access" } else { "pointer computed" }, - ptr.offset, ptr.alloc_id, allocation_size) - }, - MemoryLockViolation { ptr, len, frame, access, ref lock } => { - write!(f, "{:?} access by frame {} at {:?}, size {}, is in conflict with lock {:?}", - access, frame, ptr, len, lock) - } - MemoryAcquireConflict { ptr, len, kind, ref lock } => { - write!(f, "new {:?} lock at {:?}, size {}, is in conflict with lock {:?}", - kind, ptr, len, lock) - } - InvalidMemoryLockRelease { ptr, len, frame, ref lock } => { - write!(f, "frame {} tried to release memory write lock at {:?}, size {}, but cannot release lock {:?}", - frame, ptr, len, lock) - } - DeallocatedLockedMemory { ptr, ref lock } => { - write!(f, "tried to deallocate memory at {:?} in conflict with lock {:?}", - ptr, lock) - } - ValidationFailure(ref err) => { - write!(f, "type validation failed: {}", err) - } - NoMirFor(ref func) => write!(f, "no mir for `{}`", func), - FunctionPointerTyMismatch(sig, got) => - write!(f, "tried to call a function with sig {} through a function pointer of type {}", sig, got), - ArrayIndexOutOfBounds(span, len, index) => - write!(f, "index out of bounds: the len is {} but the index is {} at {:?}", len, index, span), - ReallocatedWrongMemoryKind(ref old, ref new) => - write!(f, "tried to reallocate memory from {} to {}", old, new), - DeallocatedWrongMemoryKind(ref old, ref new) => - write!(f, "tried to deallocate {} memory but gave {} as the kind", old, new), - Math(span, ref err) => - write!(f, "{:?} at {:?}", err, span), - Intrinsic(ref err) => - write!(f, "{}", err), - InvalidChar(c) => - write!(f, "tried to interpret an invalid 32-bit value as a char: {}", c), - OutOfMemory { allocation_size, memory_size, memory_usage } => - write!(f, "tried to allocate {} more bytes, but only {} bytes are free of the {} byte memory", - allocation_size, memory_size - memory_usage, memory_size), - AlignmentCheckFailed { required, has } => - write!(f, "tried to access memory with alignment {}, but alignment {} is required", - has, required), - TypeNotPrimitive(ty) => - write!(f, "expected primitive type, got {}", ty), - Layout(ref err) => - write!(f, "rustc layout computation failed: {:?}", err), - PathNotFound(ref path) => - write!(f, "Cannot find path {:?}", path), - MachineError(ref inner) => - write!(f, "machine error: {}", inner), - _ => write!(f, "{}", self.description()), - } - } -} diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs deleted file mode 100644 index b483cf1aed86..000000000000 --- a/src/librustc_mir/interpret/eval_context.rs +++ /dev/null @@ -1,2535 +0,0 @@ -use std::collections::{HashMap, HashSet}; -use std::fmt::Write; - -use rustc::hir::def_id::DefId; -use rustc::hir::map::definitions::DefPathData; -use rustc::middle::const_val::ConstVal; -use rustc::middle::region; -use rustc::mir; -use rustc::traits; -use rustc::traits::Reveal; -use rustc::ty::layout::{self, Layout, Size, Align, HasDataLayout}; -use rustc::ty::subst::{Subst, Substs, Kind}; -use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc_data_structures::indexed_vec::Idx; -use syntax::codemap::{self, DUMMY_SP}; -use syntax::ast::Mutability; -use syntax::abi::Abi; - -use super::{EvalError, EvalResult, EvalErrorKind, GlobalId, Lvalue, LvalueExtra, Memory, - MemoryPointer, HasMemory, MemoryKind, operator, PrimVal, PrimValKind, Value, Pointer, - ValidationQuery, Machine}; - -pub struct EvalContext<'a, 'tcx: 'a, M: Machine<'tcx>> { - /// Stores data required by the `Machine` - pub machine_data: M::Data, - - /// The results of the type checker, from rustc. - pub tcx: TyCtxt<'a, 'tcx, 'tcx>, - - /// The virtual memory system. - pub memory: Memory<'a, 'tcx, M>, - - /// Lvalues that were suspended by the validation subsystem, and will be recovered later - pub(crate) suspended: HashMap>>, - - /// Precomputed statics, constants and promoteds. - pub globals: HashMap, PtrAndAlign>, - - /// The virtual call stack. - pub(crate) stack: Vec>, - - /// The maximum number of stack frames allowed - pub(crate) stack_limit: usize, - - /// The maximum number of operations that may be executed. - /// This prevents infinite loops and huge computations from freezing up const eval. - /// Remove once halting problem is solved. - pub(crate) steps_remaining: u64, -} - -/// A stack frame. -pub struct Frame<'tcx> { - //////////////////////////////////////////////////////////////////////////////// - // Function and callsite information - //////////////////////////////////////////////////////////////////////////////// - /// The MIR for the function called on this frame. - pub mir: &'tcx mir::Mir<'tcx>, - - /// The def_id and substs of the current function - pub instance: ty::Instance<'tcx>, - - /// The span of the call site. - pub span: codemap::Span, - - //////////////////////////////////////////////////////////////////////////////// - // Return lvalue and locals - //////////////////////////////////////////////////////////////////////////////// - /// The block to return to when returning from the current stack frame - pub return_to_block: StackPopCleanup, - - /// The location where the result of the current stack frame should be written to. - pub return_lvalue: Lvalue, - - /// The list of locals for this stack frame, stored in order as - /// `[arguments..., variables..., temporaries...]`. The locals are stored as `Option`s. - /// `None` represents a local that is currently dead, while a live local - /// can either directly contain `PrimVal` or refer to some part of an `Allocation`. - /// - /// Before being initialized, arguments are `Value::ByVal(PrimVal::Undef)` and other locals are `None`. - pub locals: Vec>, - - //////////////////////////////////////////////////////////////////////////////// - // Current position within the function - //////////////////////////////////////////////////////////////////////////////// - /// The block that is currently executed (or will be executed after the above call stacks - /// return). - pub block: mir::BasicBlock, - - /// The index of the currently evaluated statment. - pub stmt: usize, -} - -#[derive(Clone, Debug, Eq, PartialEq, Hash)] -pub enum StackPopCleanup { - /// The stackframe existed to compute the initial value of a static/constant, make sure it - /// isn't modifyable afterwards in case of constants. - /// In case of `static mut`, mark the memory to ensure it's never marked as immutable through - /// references or deallocated - MarkStatic(Mutability), - /// A regular stackframe added due to a function call will need to get forwarded to the next - /// block - Goto(mir::BasicBlock), - /// The main function and diverging functions have nowhere to return to - None, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub struct DynamicLifetime { - pub frame: usize, - pub region: Option, // "None" indicates "until the function ends" -} - -#[derive(Copy, Clone, Debug)] -pub struct ResourceLimits { - pub memory_size: u64, - pub step_limit: u64, - pub stack_limit: usize, -} - -impl Default for ResourceLimits { - fn default() -> Self { - ResourceLimits { - memory_size: 100 * 1024 * 1024, // 100 MB - step_limit: 1_000_000, - stack_limit: 100, - } - } -} - -#[derive(Copy, Clone, Debug)] -pub struct TyAndPacked<'tcx> { - pub ty: Ty<'tcx>, - pub packed: bool, -} - -#[derive(Copy, Clone, Debug)] -pub struct ValTy<'tcx> { - pub value: Value, - pub ty: Ty<'tcx>, -} - -impl<'tcx> ::std::ops::Deref for ValTy<'tcx> { - type Target = Value; - fn deref(&self) -> &Value { - &self.value - } -} - -#[derive(Copy, Clone, Debug)] -pub struct PtrAndAlign { - pub ptr: Pointer, - /// Remember whether this lvalue is *supposed* to be aligned. - pub aligned: bool, -} - -impl PtrAndAlign { - pub fn to_ptr<'tcx>(self) -> EvalResult<'tcx, MemoryPointer> { - self.ptr.to_ptr() - } - pub fn offset<'tcx, C: HasDataLayout>(self, i: u64, cx: C) -> EvalResult<'tcx, Self> { - Ok(PtrAndAlign { - ptr: self.ptr.offset(i, cx)?, - aligned: self.aligned, - }) - } -} - -impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { - pub fn new( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - limits: ResourceLimits, - machine_data: M::Data, - memory_data: M::MemoryData, - ) -> Self { - EvalContext { - machine_data, - tcx, - memory: Memory::new(&tcx.data_layout, limits.memory_size, memory_data), - suspended: HashMap::new(), - globals: HashMap::new(), - stack: Vec::new(), - stack_limit: limits.stack_limit, - steps_remaining: limits.step_limit, - } - } - - pub fn alloc_ptr(&mut self, ty: Ty<'tcx>) -> EvalResult<'tcx, MemoryPointer> { - let substs = self.substs(); - self.alloc_ptr_with_substs(ty, substs) - } - - pub fn alloc_ptr_with_substs( - &mut self, - ty: Ty<'tcx>, - substs: &'tcx Substs<'tcx>, - ) -> EvalResult<'tcx, MemoryPointer> { - let size = self.type_size_with_substs(ty, substs)?.expect( - "cannot alloc memory for unsized type", - ); - let align = self.type_align_with_substs(ty, substs)?; - self.memory.allocate(size, align, MemoryKind::Stack) - } - - pub fn memory(&self) -> &Memory<'a, 'tcx, M> { - &self.memory - } - - pub fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx, M> { - &mut self.memory - } - - pub fn stack(&self) -> &[Frame<'tcx>] { - &self.stack - } - - #[inline] - pub fn cur_frame(&self) -> usize { - assert!(self.stack.len() > 0); - self.stack.len() - 1 - } - - pub fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value> { - let ptr = self.memory.allocate_cached(s.as_bytes())?; - Ok(Value::ByValPair( - PrimVal::Ptr(ptr), - PrimVal::from_u128(s.len() as u128), - )) - } - - pub(super) fn const_to_value(&mut self, const_val: &ConstVal<'tcx>) -> EvalResult<'tcx, Value> { - use rustc::middle::const_val::ConstVal::*; - - let primval = match *const_val { - Integral(const_int) => PrimVal::Bytes(const_int.to_u128_unchecked()), - - Float(val) => PrimVal::Bytes(val.bits), - - Bool(b) => PrimVal::from_bool(b), - Char(c) => PrimVal::from_char(c), - - Str(ref s) => return self.str_to_value(s), - - ByteStr(ref bs) => { - let ptr = self.memory.allocate_cached(bs.data)?; - PrimVal::Ptr(ptr) - } - - Unevaluated(def_id, substs) => { - let instance = self.resolve_associated_const(def_id, substs); - let cid = GlobalId { - instance, - promoted: None, - }; - return Ok(Value::ByRef(*self.globals.get(&cid).expect("static/const not cached"))); - } - - Aggregate(..) | - Variant(_) => bug!("should not have aggregate or variant constants in MIR"), - // function items are zero sized and thus have no readable value - Function(..) => PrimVal::Undef, - }; - - Ok(Value::ByVal(primval)) - } - - pub(super) fn type_is_sized(&self, ty: Ty<'tcx>) -> bool { - // generics are weird, don't run this function on a generic - assert!(!ty.needs_subst()); - ty.is_sized(self.tcx, ty::ParamEnv::empty(Reveal::All), DUMMY_SP) - } - - pub fn load_mir( - &self, - instance: ty::InstanceDef<'tcx>, - ) -> EvalResult<'tcx, &'tcx mir::Mir<'tcx>> { - trace!("load mir {:?}", instance); - match instance { - ty::InstanceDef::Item(def_id) => { - self.tcx.maybe_optimized_mir(def_id).ok_or_else(|| { - EvalErrorKind::NoMirFor(self.tcx.item_path_str(def_id)).into() - }) - } - _ => Ok(self.tcx.instance_mir(instance)), - } - } - - pub fn monomorphize(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { - // miri doesn't care about lifetimes, and will choke on some crazy ones - // let's simply get rid of them - let without_lifetimes = self.tcx.erase_regions(&ty); - let substituted = without_lifetimes.subst(self.tcx, substs); - let substituted = self.tcx.normalize_associated_type(&substituted); - substituted - } - - /// Return the size and aligment of the value at the given type. - /// Note that the value does not matter if the type is sized. For unsized types, - /// the value has to be a fat pointer, and we only care about the "extra" data in it. - pub fn size_and_align_of_dst( - &mut self, - ty: ty::Ty<'tcx>, - value: Value, - ) -> EvalResult<'tcx, (u64, u64)> { - if let Some(size) = self.type_size(ty)? { - Ok((size as u64, self.type_align(ty)? as u64)) - } else { - match ty.sty { - ty::TyAdt(..) | ty::TyTuple(..) => { - // First get the size of all statically known fields. - // Don't use type_of::sizing_type_of because that expects t to be sized, - // and it also rounds up to alignment, which we want to avoid, - // as the unsized field's alignment could be smaller. - assert!(!ty.is_simd()); - let layout = self.type_layout(ty)?; - debug!("DST {} layout: {:?}", ty, layout); - - let (sized_size, sized_align) = match *layout { - ty::layout::Layout::Univariant { ref variant, .. } => { - ( - variant.offsets.last().map_or(0, |o| o.bytes()), - variant.align, - ) - } - _ => { - bug!( - "size_and_align_of_dst: expcted Univariant for `{}`, found {:#?}", - ty, - layout - ); - } - }; - debug!( - "DST {} statically sized prefix size: {} align: {:?}", - ty, - sized_size, - sized_align - ); - - // Recurse to get the size of the dynamically sized field (must be - // the last field). - let (unsized_size, unsized_align) = match ty.sty { - ty::TyAdt(def, substs) => { - let last_field = def.struct_variant().fields.last().unwrap(); - let field_ty = self.field_ty(substs, last_field); - self.size_and_align_of_dst(field_ty, value)? - } - ty::TyTuple(ref types, _) => { - let field_ty = types.last().unwrap(); - let field_ty = self.tcx.normalize_associated_type(field_ty); - self.size_and_align_of_dst(field_ty, value)? - } - _ => bug!("We already checked that we know this type"), - }; - - // FIXME (#26403, #27023): We should be adding padding - // to `sized_size` (to accommodate the `unsized_align` - // required of the unsized field that follows) before - // summing it with `sized_size`. (Note that since #26403 - // is unfixed, we do not yet add the necessary padding - // here. But this is where the add would go.) - - // Return the sum of sizes and max of aligns. - let size = sized_size + unsized_size; - - // Choose max of two known alignments (combined value must - // be aligned according to more restrictive of the two). - let align = - sized_align.max(Align::from_bytes(unsized_align, unsized_align).unwrap()); - - // Issue #27023: must add any necessary padding to `size` - // (to make it a multiple of `align`) before returning it. - // - // Namely, the returned size should be, in C notation: - // - // `size + ((size & (align-1)) ? align : 0)` - // - // emulated via the semi-standard fast bit trick: - // - // `(size + (align-1)) & -align` - - let size = Size::from_bytes(size).abi_align(align).bytes(); - Ok((size, align.abi())) - } - ty::TyDynamic(..) => { - let (_, vtable) = value.into_ptr_vtable_pair(&mut self.memory)?; - // the second entry in the vtable is the dynamic size of the object. - self.read_size_and_align_from_vtable(vtable) - } - - ty::TySlice(_) | ty::TyStr => { - let elem_ty = ty.sequence_element_type(self.tcx); - let elem_size = self.type_size(elem_ty)?.expect( - "slice element must be sized", - ) as u64; - let (_, len) = value.into_slice(&mut self.memory)?; - let align = self.type_align(elem_ty)?; - Ok((len * elem_size, align as u64)) - } - - _ => bug!("size_of_val::<{:?}>", ty), - } - } - } - - /// Returns the normalized type of a struct field - fn field_ty(&self, param_substs: &Substs<'tcx>, f: &ty::FieldDef) -> ty::Ty<'tcx> { - self.tcx.normalize_associated_type( - &f.ty(self.tcx, param_substs), - ) - } - - pub fn type_size(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, Option> { - self.type_size_with_substs(ty, self.substs()) - } - - pub fn type_align(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, u64> { - self.type_align_with_substs(ty, self.substs()) - } - - pub fn type_size_with_substs( - &self, - ty: Ty<'tcx>, - substs: &'tcx Substs<'tcx>, - ) -> EvalResult<'tcx, Option> { - let layout = self.type_layout_with_substs(ty, substs)?; - if layout.is_unsized() { - Ok(None) - } else { - Ok(Some(layout.size(&self.tcx.data_layout).bytes())) - } - } - - pub fn type_align_with_substs( - &self, - ty: Ty<'tcx>, - substs: &'tcx Substs<'tcx>, - ) -> EvalResult<'tcx, u64> { - self.type_layout_with_substs(ty, substs).map(|layout| { - layout.align(&self.tcx.data_layout).abi() - }) - } - - pub fn type_layout(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, &'tcx Layout> { - self.type_layout_with_substs(ty, self.substs()) - } - - fn type_layout_with_substs( - &self, - ty: Ty<'tcx>, - substs: &'tcx Substs<'tcx>, - ) -> EvalResult<'tcx, &'tcx Layout> { - // TODO(solson): Is this inefficient? Needs investigation. - let ty = self.monomorphize(ty, substs); - - ty.layout(self.tcx, ty::ParamEnv::empty(Reveal::All)) - .map_err(|layout| EvalErrorKind::Layout(layout).into()) - } - - pub fn push_stack_frame( - &mut self, - instance: ty::Instance<'tcx>, - span: codemap::Span, - mir: &'tcx mir::Mir<'tcx>, - return_lvalue: Lvalue, - return_to_block: StackPopCleanup, - ) -> EvalResult<'tcx> { - ::log_settings::settings().indentation += 1; - - /// Return the set of locals that have a storage annotation anywhere - fn collect_storage_annotations<'tcx>(mir: &'tcx mir::Mir<'tcx>) -> HashSet { - use rustc::mir::StatementKind::*; - - let mut set = HashSet::new(); - for block in mir.basic_blocks() { - for stmt in block.statements.iter() { - match stmt.kind { - StorageLive(local) | - StorageDead(local) => { - set.insert(local); - } - _ => {} - } - } - } - set - } - - // Subtract 1 because `local_decls` includes the ReturnMemoryPointer, but we don't store a local - // `Value` for that. - let num_locals = mir.local_decls.len() - 1; - - let locals = { - let annotated_locals = collect_storage_annotations(mir); - let mut locals = vec![None; num_locals]; - for i in 0..num_locals { - let local = mir::Local::new(i + 1); - if !annotated_locals.contains(&local) { - locals[i] = Some(Value::ByVal(PrimVal::Undef)); - } - } - locals - }; - - self.stack.push(Frame { - mir, - block: mir::START_BLOCK, - return_to_block, - return_lvalue, - locals, - span, - instance, - stmt: 0, - }); - - self.memory.cur_frame = self.cur_frame(); - - if self.stack.len() > self.stack_limit { - err!(StackFrameLimitReached) - } else { - Ok(()) - } - } - - pub(super) fn pop_stack_frame(&mut self) -> EvalResult<'tcx> { - ::log_settings::settings().indentation -= 1; - self.end_region(None)?; - let frame = self.stack.pop().expect( - "tried to pop a stack frame, but there were none", - ); - if !self.stack.is_empty() { - // TODO: Is this the correct time to start considering these accesses as originating from the returned-to stack frame? - self.memory.cur_frame = self.cur_frame(); - } - match frame.return_to_block { - StackPopCleanup::MarkStatic(mutable) => { - if let Lvalue::Ptr { ptr, .. } = frame.return_lvalue { - // FIXME: to_ptr()? might be too extreme here, static zsts might reach this under certain conditions - self.memory.mark_static_initalized( - ptr.to_ptr()?.alloc_id, - mutable, - )? - } else { - bug!("StackPopCleanup::MarkStatic on: {:?}", frame.return_lvalue); - } - } - StackPopCleanup::Goto(target) => self.goto_block(target), - StackPopCleanup::None => {} - } - // deallocate all locals that are backed by an allocation - for local in frame.locals { - self.deallocate_local(local)?; - } - - Ok(()) - } - - pub fn deallocate_local(&mut self, local: Option) -> EvalResult<'tcx> { - if let Some(Value::ByRef(ptr)) = local { - trace!("deallocating local"); - let ptr = ptr.to_ptr()?; - self.memory.dump_alloc(ptr.alloc_id); - match self.memory.get(ptr.alloc_id)?.kind { - // for a constant like `const FOO: &i32 = &1;` the local containing - // the `1` is referred to by the global. We transitively marked everything - // the global refers to as static itself, so we don't free it here - MemoryKind::Static => {} - MemoryKind::Stack => self.memory.deallocate(ptr, None, MemoryKind::Stack)?, - other => bug!("local contained non-stack memory: {:?}", other), - } - }; - Ok(()) - } - - pub fn assign_discr_and_fields( - &mut self, - dest: Lvalue, - dest_ty: Ty<'tcx>, - discr_offset: u64, - operands: &[mir::Operand<'tcx>], - discr_val: u128, - variant_idx: usize, - discr_size: u64, - discr_signed: bool, - ) -> EvalResult<'tcx> { - // FIXME(solson) - let dest_ptr = self.force_allocation(dest)?.to_ptr()?; - - let discr_dest = dest_ptr.offset(discr_offset, &self)?; - self.memory.write_primval(discr_dest, PrimVal::Bytes(discr_val), discr_size, discr_signed)?; - - let dest = Lvalue::Ptr { - ptr: PtrAndAlign { - ptr: dest_ptr.into(), - aligned: true, - }, - extra: LvalueExtra::DowncastVariant(variant_idx), - }; - - self.assign_fields(dest, dest_ty, operands) - } - - pub fn assign_fields( - &mut self, - dest: Lvalue, - dest_ty: Ty<'tcx>, - operands: &[mir::Operand<'tcx>], - ) -> EvalResult<'tcx> { - if self.type_size(dest_ty)? == Some(0) { - // zst assigning is a nop - return Ok(()); - } - if self.ty_to_primval_kind(dest_ty).is_ok() { - assert_eq!(operands.len(), 1); - let value = self.eval_operand(&operands[0])?; - return self.write_value(value, dest); - } - for (field_index, operand) in operands.iter().enumerate() { - let value = self.eval_operand(operand)?; - let field_dest = self.lvalue_field(dest, mir::Field::new(field_index), dest_ty, value.ty)?; - self.write_value(value, field_dest)?; - } - Ok(()) - } - - /// Evaluate an assignment statement. - /// - /// There is no separate `eval_rvalue` function. Instead, the code for handling each rvalue - /// type writes its results directly into the memory specified by the lvalue. - pub(super) fn eval_rvalue_into_lvalue( - &mut self, - rvalue: &mir::Rvalue<'tcx>, - lvalue: &mir::Lvalue<'tcx>, - ) -> EvalResult<'tcx> { - let dest = self.eval_lvalue(lvalue)?; - let dest_ty = self.lvalue_ty(lvalue); - let dest_layout = self.type_layout(dest_ty)?; - - use rustc::mir::Rvalue::*; - match *rvalue { - Use(ref operand) => { - let value = self.eval_operand(operand)?.value; - let valty = ValTy { - value, - ty: dest_ty, - }; - self.write_value(valty, dest)?; - } - - BinaryOp(bin_op, ref left, ref right) => { - let left = self.eval_operand(left)?; - let right = self.eval_operand(right)?; - if self.intrinsic_overflowing( - bin_op, - left, - right, - dest, - dest_ty, - )? - { - // There was an overflow in an unchecked binop. Right now, we consider this an error and bail out. - // The rationale is that the reason rustc emits unchecked binops in release mode (vs. the checked binops - // it emits in debug mode) is performance, but it doesn't cost us any performance in miri. - // If, however, the compiler ever starts transforming unchecked intrinsics into unchecked binops, - // we have to go back to just ignoring the overflow here. - return err!(OverflowingMath); - } - } - - CheckedBinaryOp(bin_op, ref left, ref right) => { - let left = self.eval_operand(left)?; - let right = self.eval_operand(right)?; - self.intrinsic_with_overflow( - bin_op, - left, - right, - dest, - dest_ty, - )?; - } - - UnaryOp(un_op, ref operand) => { - let val = self.eval_operand_to_primval(operand)?; - let kind = self.ty_to_primval_kind(dest_ty)?; - self.write_primval( - dest, - operator::unary_op(un_op, val, kind)?, - dest_ty, - )?; - } - - // Skip everything for zsts - Aggregate(..) if self.type_size(dest_ty)? == Some(0) => {} - - Aggregate(ref kind, ref operands) => { - self.inc_step_counter_and_check_limit(operands.len() as u64)?; - use rustc::ty::layout::Layout::*; - match *dest_layout { - Univariant { ref variant, .. } => { - self.write_maybe_aligned_mut(!variant.packed, |ecx| { - ecx.assign_fields(dest, dest_ty, operands) - })?; - } - - Array { .. } => { - self.assign_fields(dest, dest_ty, operands)?; - } - - General { - discr, - ref variants, - .. - } => { - if let mir::AggregateKind::Adt(adt_def, variant, _, _) = **kind { - let discr_val = adt_def - .discriminants(self.tcx) - .nth(variant) - .expect("broken mir: Adt variant id invalid") - .to_u128_unchecked(); - let discr_size = discr.size().bytes(); - - self.assign_discr_and_fields( - dest, - dest_ty, - variants[variant].offsets[0].bytes(), - operands, - discr_val, - variant, - discr_size, - false, - )?; - } else { - bug!("tried to assign {:?} to Layout::General", kind); - } - } - - RawNullablePointer { nndiscr, .. } => { - if let mir::AggregateKind::Adt(_, variant, _, _) = **kind { - if nndiscr == variant as u64 { - assert_eq!(operands.len(), 1); - let operand = &operands[0]; - let value = self.eval_operand(operand)?; - self.write_value(value, dest)?; - } else { - if let Some(operand) = operands.get(0) { - assert_eq!(operands.len(), 1); - let operand_ty = self.operand_ty(operand); - assert_eq!(self.type_size(operand_ty)?, Some(0)); - } - self.write_null(dest, dest_ty)?; - } - } else { - bug!("tried to assign {:?} to Layout::RawNullablePointer", kind); - } - } - - StructWrappedNullablePointer { - nndiscr, - ref discrfield_source, - ref nonnull, - .. - } => { - if let mir::AggregateKind::Adt(_, variant, _, _) = **kind { - if nndiscr == variant as u64 { - self.write_maybe_aligned_mut(!nonnull.packed, |ecx| { - ecx.assign_fields(dest, dest_ty, operands) - })?; - } else { - for operand in operands { - let operand_ty = self.operand_ty(operand); - assert_eq!(self.type_size(operand_ty)?, Some(0)); - } - self.write_struct_wrapped_null_pointer( - dest_ty, - nndiscr, - discrfield_source, - dest, - )?; - } - } else { - bug!("tried to assign {:?} to Layout::RawNullablePointer", kind); - } - } - - CEnum { .. } => { - assert_eq!(operands.len(), 0); - if let mir::AggregateKind::Adt(adt_def, variant, _, _) = **kind { - let n = adt_def - .discriminants(self.tcx) - .nth(variant) - .expect("broken mir: Adt variant index invalid") - .to_u128_unchecked(); - self.write_primval(dest, PrimVal::Bytes(n), dest_ty)?; - } else { - bug!("tried to assign {:?} to Layout::CEnum", kind); - } - } - - Vector { count, .. } => { - debug_assert_eq!(count, operands.len() as u64); - self.assign_fields(dest, dest_ty, operands)?; - } - - UntaggedUnion { ref variants } => { - assert_eq!(operands.len(), 1); - let operand = &operands[0]; - let value = self.eval_operand(operand)?; - self.write_maybe_aligned_mut(!variants.packed, |ecx| { - ecx.write_value(value, dest) - })?; - } - - _ => { - return err!(Unimplemented(format!( - "can't handle destination layout {:?} when assigning {:?}", - dest_layout, - kind - ))); - } - } - } - - Repeat(ref operand, _) => { - let (elem_ty, length) = match dest_ty.sty { - ty::TyArray(elem_ty, n) => (elem_ty, n.val.to_const_int().unwrap().to_u64().unwrap()), - _ => { - bug!( - "tried to assign array-repeat to non-array type {:?}", - dest_ty - ) - } - }; - self.inc_step_counter_and_check_limit(length)?; - let elem_size = self.type_size(elem_ty)?.expect( - "repeat element type must be sized", - ); - let value = self.eval_operand(operand)?.value; - - // FIXME(solson) - let dest = Pointer::from(self.force_allocation(dest)?.to_ptr()?); - - for i in 0..length { - let elem_dest = dest.offset(i * elem_size, &self)?; - self.write_value_to_ptr(value, elem_dest, elem_ty)?; - } - } - - Len(ref lvalue) => { - // FIXME(CTFE): don't allow computing the length of arrays in const eval - let src = self.eval_lvalue(lvalue)?; - let ty = self.lvalue_ty(lvalue); - let (_, len) = src.elem_ty_and_len(ty); - self.write_primval( - dest, - PrimVal::from_u128(len as u128), - dest_ty, - )?; - } - - Ref(_, _, ref lvalue) => { - let src = self.eval_lvalue(lvalue)?; - // We ignore the alignment of the lvalue here -- special handling for packed structs ends - // at the `&` operator. - let (ptr, extra) = self.force_allocation(src)?.to_ptr_extra_aligned(); - - let val = match extra { - LvalueExtra::None => ptr.ptr.to_value(), - LvalueExtra::Length(len) => ptr.ptr.to_value_with_len(len), - LvalueExtra::Vtable(vtable) => ptr.ptr.to_value_with_vtable(vtable), - LvalueExtra::DowncastVariant(..) => { - bug!("attempted to take a reference to an enum downcast lvalue") - } - }; - let valty = ValTy { - value: val, - ty: dest_ty, - }; - self.write_value(valty, dest)?; - } - - NullaryOp(mir::NullOp::Box, ty) => { - M::box_alloc(self, ty, dest)?; - } - - NullaryOp(mir::NullOp::SizeOf, ty) => { - let size = self.type_size(ty)?.expect( - "SizeOf nullary MIR operator called for unsized type", - ); - self.write_primval( - dest, - PrimVal::from_u128(size as u128), - dest_ty, - )?; - } - - Cast(kind, ref operand, cast_ty) => { - debug_assert_eq!(self.monomorphize(cast_ty, self.substs()), dest_ty); - use rustc::mir::CastKind::*; - match kind { - Unsize => { - let src = self.eval_operand(operand)?; - self.unsize_into(src.value, src.ty, dest, dest_ty)?; - } - - Misc => { - let src = self.eval_operand(operand)?; - if self.type_is_fat_ptr(src.ty) { - match (src.value, self.type_is_fat_ptr(dest_ty)) { - (Value::ByRef { .. }, _) | - (Value::ByValPair(..), true) => { - let valty = ValTy { - value: src.value, - ty: dest_ty, - }; - self.write_value(valty, dest)?; - } - (Value::ByValPair(data, _), false) => { - let valty = ValTy { - value: Value::ByVal(data), - ty: dest_ty, - }; - self.write_value(valty, dest)?; - } - (Value::ByVal(_), _) => bug!("expected fat ptr"), - } - } else { - let src_val = self.value_to_primval(src)?; - let dest_val = self.cast_primval(src_val, src.ty, dest_ty)?; - let valty = ValTy { - value: Value::ByVal(dest_val), - ty: dest_ty, - }; - self.write_value(valty, dest)?; - } - } - - ReifyFnPointer => { - match self.operand_ty(operand).sty { - ty::TyFnDef(def_id, substs) => { - let instance = resolve(self.tcx, def_id, substs); - let fn_ptr = self.memory.create_fn_alloc(instance); - let valty = ValTy { - value: Value::ByVal(PrimVal::Ptr(fn_ptr)), - ty: dest_ty, - }; - self.write_value(valty, dest)?; - } - ref other => bug!("reify fn pointer on {:?}", other), - } - } - - UnsafeFnPointer => { - match dest_ty.sty { - ty::TyFnPtr(_) => { - let mut src = self.eval_operand(operand)?; - src.ty = dest_ty; - self.write_value(src, dest)?; - } - ref other => bug!("fn to unsafe fn cast on {:?}", other), - } - } - - ClosureFnPointer => { - match self.operand_ty(operand).sty { - ty::TyClosure(def_id, substs) => { - let instance = resolve_closure( - self.tcx, - def_id, - substs, - ty::ClosureKind::FnOnce, - ); - let fn_ptr = self.memory.create_fn_alloc(instance); - let valty = ValTy { - value: Value::ByVal(PrimVal::Ptr(fn_ptr)), - ty: dest_ty, - }; - self.write_value(valty, dest)?; - } - ref other => bug!("closure fn pointer on {:?}", other), - } - } - } - } - - Discriminant(ref lvalue) => { - let lval = self.eval_lvalue(lvalue)?; - let ty = self.lvalue_ty(lvalue); - let ptr = self.force_allocation(lval)?.to_ptr()?; - let discr_val = self.read_discriminant_value(ptr, ty)?; - if let ty::TyAdt(adt_def, _) = ty.sty { - trace!("Read discriminant {}, valid discriminants {:?}", discr_val, adt_def.discriminants(self.tcx).collect::>()); - if adt_def.discriminants(self.tcx).all(|v| { - discr_val != v.to_u128_unchecked() - }) - { - return err!(InvalidDiscriminant); - } - self.write_primval(dest, PrimVal::Bytes(discr_val), dest_ty)?; - } else { - bug!("rustc only generates Rvalue::Discriminant for enums"); - } - } - } - - if log_enabled!(::log::LogLevel::Trace) { - self.dump_local(dest); - } - - Ok(()) - } - - pub(crate) fn write_struct_wrapped_null_pointer( - &mut self, - dest_ty: ty::Ty<'tcx>, - nndiscr: u64, - discrfield_source: &layout::FieldPath, - dest: Lvalue, - ) -> EvalResult<'tcx> { - let (offset, TyAndPacked { ty, packed }) = self.nonnull_offset_and_ty( - dest_ty, - nndiscr, - discrfield_source, - )?; - let nonnull = self.force_allocation(dest)?.to_ptr()?.offset( - offset.bytes(), - &self, - )?; - trace!("struct wrapped nullable pointer type: {}", ty); - // only the pointer part of a fat pointer is used for this space optimization - let discr_size = self.type_size(ty)?.expect( - "bad StructWrappedNullablePointer discrfield", - ); - self.memory.write_maybe_aligned_mut(!packed, |mem| { - // We're writing 0, signedness does not matter - mem.write_primval(nonnull, PrimVal::Bytes(0), discr_size, false) - }) - } - - pub(super) fn type_is_fat_ptr(&self, ty: Ty<'tcx>) -> bool { - match ty.sty { - ty::TyRawPtr(ref tam) | - ty::TyRef(_, ref tam) => !self.type_is_sized(tam.ty), - ty::TyAdt(def, _) if def.is_box() => !self.type_is_sized(ty.boxed_ty()), - _ => false, - } - } - - pub(super) fn nonnull_offset_and_ty( - &self, - ty: Ty<'tcx>, - nndiscr: u64, - discrfield: &[u32], - ) -> EvalResult<'tcx, (Size, TyAndPacked<'tcx>)> { - // Skip the constant 0 at the start meant for LLVM GEP and the outer non-null variant - let path = discrfield.iter().skip(2).map(|&i| i as usize); - - // Handle the field index for the outer non-null variant. - let (inner_offset, inner_ty) = match ty.sty { - ty::TyAdt(adt_def, substs) => { - let variant = &adt_def.variants[nndiscr as usize]; - let index = discrfield[1]; - let field = &variant.fields[index as usize]; - ( - self.get_field_offset(ty, index as usize)?, - field.ty(self.tcx, substs), - ) - } - _ => bug!("non-enum for StructWrappedNullablePointer: {}", ty), - }; - - self.field_path_offset_and_ty(inner_offset, inner_ty, path) - } - - fn field_path_offset_and_ty>( - &self, - mut offset: Size, - mut ty: Ty<'tcx>, - path: I, - ) -> EvalResult<'tcx, (Size, TyAndPacked<'tcx>)> { - // Skip the initial 0 intended for LLVM GEP. - let mut packed = false; - for field_index in path { - let field_offset = self.get_field_offset(ty, field_index)?; - trace!( - "field_path_offset_and_ty: {}, {}, {:?}, {:?}", - field_index, - ty, - field_offset, - offset - ); - let field_ty = self.get_field_ty(ty, field_index)?; - ty = field_ty.ty; - packed = packed || field_ty.packed; - offset = offset - .checked_add(field_offset, &self.tcx.data_layout) - .unwrap(); - } - - Ok((offset, TyAndPacked { ty, packed })) - } - fn get_fat_field( - &self, - pointee_ty: Ty<'tcx>, - field_index: usize, - ) -> EvalResult<'tcx, Ty<'tcx>> { - match (field_index, &self.tcx.struct_tail(pointee_ty).sty) { - (1, &ty::TyStr) | - (1, &ty::TySlice(_)) => Ok(self.tcx.types.usize), - (1, &ty::TyDynamic(..)) | - (0, _) => Ok(self.tcx.mk_imm_ptr(self.tcx.types.u8)), - _ => bug!("invalid fat pointee type: {}", pointee_ty), - } - } - - /// Returns the field type and whether the field is packed - pub fn get_field_ty( - &self, - ty: Ty<'tcx>, - field_index: usize, - ) -> EvalResult<'tcx, TyAndPacked<'tcx>> { - match ty.sty { - ty::TyAdt(adt_def, _) if adt_def.is_box() => Ok(TyAndPacked { - ty: self.get_fat_field(ty.boxed_ty(), field_index)?, - packed: false, - }), - ty::TyAdt(adt_def, substs) if adt_def.is_enum() => { - use rustc::ty::layout::Layout::*; - match *self.type_layout(ty)? { - RawNullablePointer { nndiscr, .. } => Ok(TyAndPacked { - ty: adt_def.variants[nndiscr as usize].fields[field_index].ty( - self.tcx, - substs, - ), - packed: false, - }), - StructWrappedNullablePointer { - nndiscr, - ref nonnull, - .. - } => { - let ty = adt_def.variants[nndiscr as usize].fields[field_index].ty( - self.tcx, - substs, - ); - Ok(TyAndPacked { - ty, - packed: nonnull.packed, - }) - } - // mir optimizations treat single variant enums as structs - General { .. } if adt_def.variants.len() == 1 => Ok(TyAndPacked { - ty: adt_def.variants[0].fields[field_index].ty(self.tcx, substs), - packed: false, - }), - _ => { - err!(Unimplemented(format!( - "get_field_ty can't handle enum type: {:?}, {:?}", - ty, - ty.sty - ))) - } - } - } - ty::TyAdt(adt_def, substs) => { - let variant_def = adt_def.struct_variant(); - use rustc::ty::layout::Layout::*; - match *self.type_layout(ty)? { - UntaggedUnion { ref variants } => Ok(TyAndPacked { - ty: variant_def.fields[field_index].ty(self.tcx, substs), - packed: variants.packed, - }), - Univariant { ref variant, .. } => Ok(TyAndPacked { - ty: variant_def.fields[field_index].ty(self.tcx, substs), - packed: variant.packed, - }), - _ => { - err!(Unimplemented(format!( - "get_field_ty can't handle struct type: {:?}, {:?}", - ty, - ty.sty - ))) - } - } - } - - ty::TyTuple(fields, _) => Ok(TyAndPacked { - ty: fields[field_index], - packed: false, - }), - - ty::TyRef(_, ref tam) | - ty::TyRawPtr(ref tam) => Ok(TyAndPacked { - ty: self.get_fat_field(tam.ty, field_index)?, - packed: false, - }), - - ty::TyArray(ref inner, _) => Ok(TyAndPacked { - ty: inner, - packed: false, - }), - - ty::TyClosure(def_id, ref closure_substs) => Ok(TyAndPacked { - ty: closure_substs.upvar_tys(def_id, self.tcx).nth(field_index).unwrap(), - packed: false, - }), - - _ => { - err!(Unimplemented( - format!("can't handle type: {:?}, {:?}", ty, ty.sty), - )) - } - } - } - - fn get_field_offset(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Size> { - // Also see lvalue_field in lvalue.rs, which handles more cases but needs an actual value at the given type - let layout = self.type_layout(ty)?; - - use rustc::ty::layout::Layout::*; - match *layout { - Univariant { ref variant, .. } => Ok(variant.offsets[field_index]), - FatPointer { .. } => { - let bytes = field_index as u64 * self.memory.pointer_size(); - Ok(Size::from_bytes(bytes)) - } - StructWrappedNullablePointer { ref nonnull, .. } => Ok(nonnull.offsets[field_index]), - UntaggedUnion { .. } => Ok(Size::from_bytes(0)), - // mir optimizations treat single variant enums as structs - General { ref variants, .. } if variants.len() == 1 => Ok(variants[0].offsets[field_index]), - _ => { - let msg = format!( - "get_field_offset: can't handle type: {:?}, with layout: {:?}", - ty, - layout - ); - err!(Unimplemented(msg)) - } - } - } - - pub fn get_field_count(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, u64> { - let layout = self.type_layout(ty)?; - - use rustc::ty::layout::Layout::*; - match *layout { - Univariant { ref variant, .. } => Ok(variant.offsets.len() as u64), - FatPointer { .. } => Ok(2), - StructWrappedNullablePointer { ref nonnull, .. } => Ok(nonnull.offsets.len() as u64), - Vector { count, .. } | - Array { count, .. } => Ok(count), - Scalar { .. } => Ok(0), - UntaggedUnion { .. } => Ok(1), - _ => { - let msg = format!( - "get_field_count: can't handle type: {:?}, with layout: {:?}", - ty, - layout - ); - err!(Unimplemented(msg)) - } - } - } - - pub(super) fn eval_operand_to_primval( - &mut self, - op: &mir::Operand<'tcx>, - ) -> EvalResult<'tcx, PrimVal> { - let valty = self.eval_operand(op)?; - self.value_to_primval(valty) - } - - pub(crate) fn operands_to_args( - &mut self, - ops: &[mir::Operand<'tcx>], - ) -> EvalResult<'tcx, Vec>> { - ops.into_iter() - .map(|op| self.eval_operand(op)) - .collect() - } - - pub fn eval_operand(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<'tcx, ValTy<'tcx>> { - use rustc::mir::Operand::*; - match *op { - Consume(ref lvalue) => { - Ok(ValTy { - value: self.eval_and_read_lvalue(lvalue)?, - ty: self.operand_ty(op), - }) - }, - - Constant(ref constant) => { - use rustc::mir::Literal; - let mir::Constant { ref literal, .. } = **constant; - let value = match *literal { - Literal::Value { ref value } => self.const_to_value(&value.val)?, - - Literal::Promoted { index } => { - let cid = GlobalId { - instance: self.frame().instance, - promoted: Some(index), - }; - Value::ByRef(*self.globals.get(&cid).expect("promoted not cached")) - } - }; - - Ok(ValTy { - value, - ty: self.operand_ty(op), - }) - } - } - } - - pub fn read_discriminant_value( - &self, - adt_ptr: MemoryPointer, - adt_ty: Ty<'tcx>, - ) -> EvalResult<'tcx, u128> { - use rustc::ty::layout::Layout::*; - let adt_layout = self.type_layout(adt_ty)?; - //trace!("read_discriminant_value {:#?}", adt_layout); - - let discr_val = match *adt_layout { - General { discr, .. } => { - let discr_size = discr.size().bytes(); - self.memory.read_primval(adt_ptr, discr_size, false)?.to_bytes()? - } - - CEnum { - discr, - signed, - .. - } => { - let discr_size = discr.size().bytes(); - self.memory.read_primval(adt_ptr, discr_size, signed)?.to_bytes()? - } - - RawNullablePointer { nndiscr, value } => { - let discr_size = value.size(&self.tcx.data_layout).bytes(); - trace!("rawnullablepointer with size {}", discr_size); - self.read_nonnull_discriminant_value( - adt_ptr, - nndiscr as u128, - discr_size, - )? - } - - StructWrappedNullablePointer { - nndiscr, - ref discrfield_source, - .. - } => { - let (offset, TyAndPacked { ty, packed }) = self.nonnull_offset_and_ty( - adt_ty, - nndiscr, - discrfield_source, - )?; - let nonnull = adt_ptr.offset(offset.bytes(), &*self)?; - trace!("struct wrapped nullable pointer type: {}", ty); - // only the pointer part of a fat pointer is used for this space optimization - let discr_size = self.type_size(ty)?.expect( - "bad StructWrappedNullablePointer discrfield", - ); - self.read_maybe_aligned(!packed, |ectx| { - ectx.read_nonnull_discriminant_value(nonnull, nndiscr as u128, discr_size) - })? - } - - // The discriminant_value intrinsic returns 0 for non-sum types. - Array { .. } | - FatPointer { .. } | - Scalar { .. } | - Univariant { .. } | - Vector { .. } | - UntaggedUnion { .. } => 0, - }; - - Ok(discr_val) - } - - fn read_nonnull_discriminant_value( - &self, - ptr: MemoryPointer, - nndiscr: u128, - discr_size: u64, - ) -> EvalResult<'tcx, u128> { - trace!( - "read_nonnull_discriminant_value: {:?}, {}, {}", - ptr, - nndiscr, - discr_size - ); - // We are only interested in 0 vs. non-0, the sign does not matter for this - let null = match self.memory.read_primval(ptr, discr_size, false)? { - PrimVal::Bytes(0) => true, - PrimVal::Bytes(_) | - PrimVal::Ptr(..) => false, - PrimVal::Undef => return err!(ReadUndefBytes), - }; - assert!(nndiscr == 0 || nndiscr == 1); - Ok(if !null { nndiscr } else { 1 - nndiscr }) - } - - pub fn read_global_as_value(&self, gid: GlobalId) -> Value { - Value::ByRef(*self.globals.get(&gid).expect("global not cached")) - } - - pub fn operand_ty(&self, operand: &mir::Operand<'tcx>) -> Ty<'tcx> { - self.monomorphize(operand.ty(self.mir(), self.tcx), self.substs()) - } - - fn copy(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx> { - let size = self.type_size(ty)?.expect( - "cannot copy from an unsized type", - ); - let align = self.type_align(ty)?; - self.memory.copy(src, dest, size, align, false)?; - Ok(()) - } - - pub fn is_packed(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, bool> { - let layout = self.type_layout(ty)?; - use rustc::ty::layout::Layout::*; - Ok(match *layout { - Univariant { ref variant, .. } => variant.packed, - - StructWrappedNullablePointer { ref nonnull, .. } => nonnull.packed, - - UntaggedUnion { ref variants } => variants.packed, - - // can only apply #[repr(packed)] to struct and union - _ => false, - }) - } - - pub fn force_allocation(&mut self, lvalue: Lvalue) -> EvalResult<'tcx, Lvalue> { - let new_lvalue = match lvalue { - Lvalue::Local { frame, local } => { - // -1 since we don't store the return value - match self.stack[frame].locals[local.index() - 1] { - None => return err!(DeadLocal), - Some(Value::ByRef(ptr)) => { - Lvalue::Ptr { - ptr, - extra: LvalueExtra::None, - } - } - Some(val) => { - let ty = self.stack[frame].mir.local_decls[local].ty; - let ty = self.monomorphize(ty, self.stack[frame].instance.substs); - let substs = self.stack[frame].instance.substs; - let ptr = self.alloc_ptr_with_substs(ty, substs)?; - self.stack[frame].locals[local.index() - 1] = - Some(Value::by_ref(ptr.into())); // it stays live - self.write_value_to_ptr(val, ptr.into(), ty)?; - Lvalue::from_ptr(ptr) - } - } - } - Lvalue::Ptr { .. } => lvalue, - }; - Ok(new_lvalue) - } - - /// ensures this Value is not a ByRef - pub(super) fn follow_by_ref_value( - &self, - value: Value, - ty: Ty<'tcx>, - ) -> EvalResult<'tcx, Value> { - match value { - Value::ByRef(PtrAndAlign { ptr, aligned }) => { - self.read_maybe_aligned(aligned, |ectx| ectx.read_value(ptr, ty)) - } - other => Ok(other), - } - } - - pub fn value_to_primval( - &self, - ValTy { value, ty } : ValTy<'tcx>, - ) -> EvalResult<'tcx, PrimVal> { - match self.follow_by_ref_value(value, ty)? { - Value::ByRef { .. } => bug!("follow_by_ref_value can't result in `ByRef`"), - - Value::ByVal(primval) => { - // TODO: Do we really want insta-UB here? - self.ensure_valid_value(primval, ty)?; - Ok(primval) - } - - Value::ByValPair(..) => bug!("value_to_primval can't work with fat pointers"), - } - } - - pub fn write_null(&mut self, dest: Lvalue, dest_ty: Ty<'tcx>) -> EvalResult<'tcx> { - self.write_primval(dest, PrimVal::Bytes(0), dest_ty) - } - - pub fn write_ptr(&mut self, dest: Lvalue, val: Pointer, dest_ty: Ty<'tcx>) -> EvalResult<'tcx> { - let valty = ValTy { - value: val.to_value(), - ty: dest_ty, - }; - self.write_value(valty, dest) - } - - pub fn write_primval( - &mut self, - dest: Lvalue, - val: PrimVal, - dest_ty: Ty<'tcx>, - ) -> EvalResult<'tcx> { - let valty = ValTy { - value: Value::ByVal(val), - ty: dest_ty, - }; - self.write_value(valty, dest) - } - - pub fn write_value( - &mut self, - ValTy { value: src_val, ty: dest_ty } : ValTy<'tcx>, - dest: Lvalue, - ) -> EvalResult<'tcx> { - //trace!("Writing {:?} to {:?} at type {:?}", src_val, dest, dest_ty); - // Note that it is really important that the type here is the right one, and matches the type things are read at. - // In case `src_val` is a `ByValPair`, we don't do any magic here to handle padding properly, which is only - // correct if we never look at this data with the wrong type. - - match dest { - Lvalue::Ptr { - ptr: PtrAndAlign { ptr, aligned }, - extra, - } => { - assert_eq!(extra, LvalueExtra::None); - self.write_maybe_aligned_mut( - aligned, - |ectx| ectx.write_value_to_ptr(src_val, ptr, dest_ty), - ) - } - - Lvalue::Local { frame, local } => { - let dest = self.stack[frame].get_local(local)?; - self.write_value_possibly_by_val( - src_val, - |this, val| this.stack[frame].set_local(local, val), - dest, - dest_ty, - ) - } - } - } - - // The cases here can be a bit subtle. Read carefully! - fn write_value_possibly_by_val EvalResult<'tcx>>( - &mut self, - src_val: Value, - write_dest: F, - old_dest_val: Value, - dest_ty: Ty<'tcx>, - ) -> EvalResult<'tcx> { - if let Value::ByRef(PtrAndAlign { - ptr: dest_ptr, - aligned, - }) = old_dest_val - { - // If the value is already `ByRef` (that is, backed by an `Allocation`), - // then we must write the new value into this allocation, because there may be - // other pointers into the allocation. These other pointers are logically - // pointers into the local variable, and must be able to observe the change. - // - // Thus, it would be an error to replace the `ByRef` with a `ByVal`, unless we - // knew for certain that there were no outstanding pointers to this allocation. - self.write_maybe_aligned_mut(aligned, |ectx| { - ectx.write_value_to_ptr(src_val, dest_ptr, dest_ty) - })?; - - } else if let Value::ByRef(PtrAndAlign { - ptr: src_ptr, - aligned, - }) = src_val - { - // If the value is not `ByRef`, then we know there are no pointers to it - // and we can simply overwrite the `Value` in the locals array directly. - // - // In this specific case, where the source value is `ByRef`, we must duplicate - // the allocation, because this is a by-value operation. It would be incorrect - // if they referred to the same allocation, since then a change to one would - // implicitly change the other. - // - // It is a valid optimization to attempt reading a primitive value out of the - // source and write that into the destination without making an allocation, so - // we do so here. - self.read_maybe_aligned_mut(aligned, |ectx| { - if let Ok(Some(src_val)) = ectx.try_read_value(src_ptr, dest_ty) { - write_dest(ectx, src_val)?; - } else { - let dest_ptr = ectx.alloc_ptr(dest_ty)?.into(); - ectx.copy(src_ptr, dest_ptr, dest_ty)?; - write_dest(ectx, Value::by_ref(dest_ptr))?; - } - Ok(()) - })?; - - } else { - // Finally, we have the simple case where neither source nor destination are - // `ByRef`. We may simply copy the source value over the the destintion. - write_dest(self, src_val)?; - } - Ok(()) - } - - pub fn write_value_to_ptr( - &mut self, - value: Value, - dest: Pointer, - dest_ty: Ty<'tcx>, - ) -> EvalResult<'tcx> { - match value { - Value::ByRef(PtrAndAlign { ptr, aligned }) => { - self.read_maybe_aligned_mut(aligned, |ectx| ectx.copy(ptr, dest, dest_ty)) - } - Value::ByVal(primval) => { - let size = self.type_size(dest_ty)?.expect("dest type must be sized"); - if size == 0 { - assert!(primval.is_undef()); - Ok(()) - } else { - // TODO: Do we need signedness? - self.memory.write_primval(dest.to_ptr()?, primval, size, false) - } - } - Value::ByValPair(a, b) => self.write_pair_to_ptr(a, b, dest.to_ptr()?, dest_ty), - } - } - - pub fn write_pair_to_ptr( - &mut self, - a: PrimVal, - b: PrimVal, - ptr: MemoryPointer, - mut ty: Ty<'tcx>, - ) -> EvalResult<'tcx> { - let mut packed = false; - while self.get_field_count(ty)? == 1 { - let field = self.get_field_ty(ty, 0)?; - ty = field.ty; - packed = packed || field.packed; - } - assert_eq!(self.get_field_count(ty)?, 2); - let field_0 = self.get_field_offset(ty, 0)?; - let field_1 = self.get_field_offset(ty, 1)?; - let field_0_ty = self.get_field_ty(ty, 0)?; - let field_1_ty = self.get_field_ty(ty, 1)?; - assert_eq!( - field_0_ty.packed, - field_1_ty.packed, - "the two fields must agree on being packed" - ); - packed = packed || field_0_ty.packed; - let field_0_size = self.type_size(field_0_ty.ty)?.expect( - "pair element type must be sized", - ); - let field_1_size = self.type_size(field_1_ty.ty)?.expect( - "pair element type must be sized", - ); - let field_0_ptr = ptr.offset(field_0.bytes(), &self)?.into(); - let field_1_ptr = ptr.offset(field_1.bytes(), &self)?.into(); - // TODO: What about signedess? - self.write_maybe_aligned_mut(!packed, |ectx| { - ectx.memory.write_primval(field_0_ptr, a, field_0_size, false) - })?; - self.write_maybe_aligned_mut(!packed, |ectx| { - ectx.memory.write_primval(field_1_ptr, b, field_1_size, false) - })?; - Ok(()) - } - - pub fn ty_to_primval_kind(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimValKind> { - use syntax::ast::FloatTy; - - let kind = match ty.sty { - ty::TyBool => PrimValKind::Bool, - ty::TyChar => PrimValKind::Char, - - ty::TyInt(int_ty) => { - use syntax::ast::IntTy::*; - let size = match int_ty { - I8 => 1, - I16 => 2, - I32 => 4, - I64 => 8, - I128 => 16, - Is => self.memory.pointer_size(), - }; - PrimValKind::from_int_size(size) - } - - ty::TyUint(uint_ty) => { - use syntax::ast::UintTy::*; - let size = match uint_ty { - U8 => 1, - U16 => 2, - U32 => 4, - U64 => 8, - U128 => 16, - Us => self.memory.pointer_size(), - }; - PrimValKind::from_uint_size(size) - } - - ty::TyFloat(FloatTy::F32) => PrimValKind::F32, - ty::TyFloat(FloatTy::F64) => PrimValKind::F64, - - ty::TyFnPtr(_) => PrimValKind::FnPtr, - - ty::TyRef(_, ref tam) | - ty::TyRawPtr(ref tam) if self.type_is_sized(tam.ty) => PrimValKind::Ptr, - - ty::TyAdt(def, _) if def.is_box() => PrimValKind::Ptr, - - ty::TyAdt(def, substs) => { - use rustc::ty::layout::Layout::*; - match *self.type_layout(ty)? { - CEnum { discr, signed, .. } => { - let size = discr.size().bytes(); - if signed { - PrimValKind::from_int_size(size) - } else { - PrimValKind::from_uint_size(size) - } - } - - RawNullablePointer { value, .. } => { - use rustc::ty::layout::Primitive::*; - match value { - // TODO(solson): Does signedness matter here? What should the sign be? - Int(int) => PrimValKind::from_uint_size(int.size().bytes()), - F32 => PrimValKind::F32, - F64 => PrimValKind::F64, - Pointer => PrimValKind::Ptr, - } - } - - // represent single field structs as their single field - Univariant { .. } => { - // enums with just one variant are no different, but `.struct_variant()` doesn't work for enums - let variant = &def.variants[0]; - // FIXME: also allow structs with only a single non zst field - if variant.fields.len() == 1 { - return self.ty_to_primval_kind(variant.fields[0].ty(self.tcx, substs)); - } else { - return err!(TypeNotPrimitive(ty)); - } - } - - _ => return err!(TypeNotPrimitive(ty)), - } - } - - _ => return err!(TypeNotPrimitive(ty)), - }; - - Ok(kind) - } - - fn ensure_valid_value(&self, val: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx> { - match ty.sty { - ty::TyBool if val.to_bytes()? > 1 => err!(InvalidBool), - - ty::TyChar if ::std::char::from_u32(val.to_bytes()? as u32).is_none() => { - err!(InvalidChar(val.to_bytes()? as u32 as u128)) - } - - _ => Ok(()), - } - } - - pub fn read_value(&self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> { - if let Some(val) = self.try_read_value(ptr, ty)? { - Ok(val) - } else { - bug!("primitive read failed for type: {:?}", ty); - } - } - - pub(crate) fn read_ptr( - &self, - ptr: MemoryPointer, - pointee_ty: Ty<'tcx>, - ) -> EvalResult<'tcx, Value> { - let ptr_size = self.memory.pointer_size(); - let p : Pointer = self.memory.read_ptr_sized_unsigned(ptr)?.into(); - if self.type_is_sized(pointee_ty) { - Ok(p.to_value()) - } else { - trace!("reading fat pointer extra of type {}", pointee_ty); - let extra = ptr.offset(ptr_size, self)?; - match self.tcx.struct_tail(pointee_ty).sty { - ty::TyDynamic(..) => Ok(p.to_value_with_vtable( - self.memory.read_ptr_sized_unsigned(extra)?.to_ptr()?, - )), - ty::TySlice(..) | ty::TyStr => Ok( - p.to_value_with_len(self.memory.read_ptr_sized_unsigned(extra)?.to_bytes()? as u64), - ), - _ => bug!("unsized primval ptr read from {:?}", pointee_ty), - } - } - } - - fn try_read_value(&self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Option> { - use syntax::ast::FloatTy; - - let ptr = ptr.to_ptr()?; - let val = match ty.sty { - ty::TyBool => { - let val = self.memory.read_primval(ptr, 1, false)?; - let val = match val { - PrimVal::Bytes(0) => false, - PrimVal::Bytes(1) => true, - // TODO: This seems a little overeager, should reading at bool type already be insta-UB? - _ => return err!(InvalidBool), - }; - PrimVal::from_bool(val) - } - ty::TyChar => { - let c = self.memory.read_primval(ptr, 4, false)?.to_bytes()? as u32; - match ::std::char::from_u32(c) { - Some(ch) => PrimVal::from_char(ch), - None => return err!(InvalidChar(c as u128)), - } - } - - ty::TyInt(int_ty) => { - use syntax::ast::IntTy::*; - let size = match int_ty { - I8 => 1, - I16 => 2, - I32 => 4, - I64 => 8, - I128 => 16, - Is => self.memory.pointer_size(), - }; - self.memory.read_primval(ptr, size, true)? - } - - ty::TyUint(uint_ty) => { - use syntax::ast::UintTy::*; - let size = match uint_ty { - U8 => 1, - U16 => 2, - U32 => 4, - U64 => 8, - U128 => 16, - Us => self.memory.pointer_size(), - }; - self.memory.read_primval(ptr, size, false)? - } - - ty::TyFloat(FloatTy::F32) => PrimVal::Bytes(self.memory.read_primval(ptr, 4, false)?.to_bytes()?), - ty::TyFloat(FloatTy::F64) => PrimVal::Bytes(self.memory.read_primval(ptr, 8, false)?.to_bytes()?), - - ty::TyFnPtr(_) => self.memory.read_ptr_sized_unsigned(ptr)?, - ty::TyRef(_, ref tam) | - ty::TyRawPtr(ref tam) => return self.read_ptr(ptr, tam.ty).map(Some), - - ty::TyAdt(def, _) => { - if def.is_box() { - return self.read_ptr(ptr, ty.boxed_ty()).map(Some); - } - use rustc::ty::layout::Layout::*; - if let CEnum { discr, signed, .. } = *self.type_layout(ty)? { - let size = discr.size().bytes(); - self.memory.read_primval(ptr, size, signed)? - } else { - return Ok(None); - } - } - - _ => return Ok(None), - }; - - Ok(Some(Value::ByVal(val))) - } - - pub fn frame(&self) -> &Frame<'tcx> { - self.stack.last().expect("no call frames exist") - } - - pub(super) fn frame_mut(&mut self) -> &mut Frame<'tcx> { - self.stack.last_mut().expect("no call frames exist") - } - - pub(super) fn mir(&self) -> &'tcx mir::Mir<'tcx> { - self.frame().mir - } - - pub(super) fn substs(&self) -> &'tcx Substs<'tcx> { - self.frame().instance.substs - } - - fn unsize_into_ptr( - &mut self, - src: Value, - src_ty: Ty<'tcx>, - dest: Lvalue, - dest_ty: Ty<'tcx>, - sty: Ty<'tcx>, - dty: Ty<'tcx>, - ) -> EvalResult<'tcx> { - // A -> A conversion - let (src_pointee_ty, dest_pointee_ty) = self.tcx.struct_lockstep_tails(sty, dty); - - match (&src_pointee_ty.sty, &dest_pointee_ty.sty) { - (&ty::TyArray(_, length), &ty::TySlice(_)) => { - let ptr = src.into_ptr(&self.memory)?; - // u64 cast is from usize to u64, which is always good - let valty = ValTy { - value: ptr.to_value_with_len(length.val.to_const_int().unwrap().to_u64().unwrap() ), - ty: dest_ty, - }; - self.write_value(valty, dest) - } - (&ty::TyDynamic(..), &ty::TyDynamic(..)) => { - // For now, upcasts are limited to changes in marker - // traits, and hence never actually require an actual - // change to the vtable. - let valty = ValTy { - value: src, - ty: dest_ty, - }; - self.write_value(valty, dest) - } - (_, &ty::TyDynamic(ref data, _)) => { - let trait_ref = data.principal().unwrap().with_self_ty( - self.tcx, - src_pointee_ty, - ); - let trait_ref = self.tcx.erase_regions(&trait_ref); - let vtable = self.get_vtable(src_pointee_ty, trait_ref)?; - let ptr = src.into_ptr(&self.memory)?; - let valty = ValTy { - value: ptr.to_value_with_vtable(vtable), - ty: dest_ty, - }; - self.write_value(valty, dest) - } - - _ => bug!("invalid unsizing {:?} -> {:?}", src_ty, dest_ty), - } - } - - fn unsize_into( - &mut self, - src: Value, - src_ty: Ty<'tcx>, - dest: Lvalue, - dest_ty: Ty<'tcx>, - ) -> EvalResult<'tcx> { - match (&src_ty.sty, &dest_ty.sty) { - (&ty::TyRef(_, ref s), &ty::TyRef(_, ref d)) | - (&ty::TyRef(_, ref s), &ty::TyRawPtr(ref d)) | - (&ty::TyRawPtr(ref s), &ty::TyRawPtr(ref d)) => { - self.unsize_into_ptr(src, src_ty, dest, dest_ty, s.ty, d.ty) - } - (&ty::TyAdt(def_a, substs_a), &ty::TyAdt(def_b, substs_b)) => { - if def_a.is_box() || def_b.is_box() { - if !def_a.is_box() || !def_b.is_box() { - panic!("invalid unsizing between {:?} -> {:?}", src_ty, dest_ty); - } - return self.unsize_into_ptr( - src, - src_ty, - dest, - dest_ty, - src_ty.boxed_ty(), - dest_ty.boxed_ty(), - ); - } - if self.ty_to_primval_kind(src_ty).is_ok() { - // TODO: We ignore the packed flag here - let sty = self.get_field_ty(src_ty, 0)?.ty; - let dty = self.get_field_ty(dest_ty, 0)?.ty; - return self.unsize_into(src, sty, dest, dty); - } - // unsizing of generic struct with pointer fields - // Example: `Arc` -> `Arc` - // here we need to increase the size of every &T thin ptr field to a fat ptr - - assert_eq!(def_a, def_b); - - let src_fields = def_a.variants[0].fields.iter(); - let dst_fields = def_b.variants[0].fields.iter(); - - //let src = adt::MaybeSizedValue::sized(src); - //let dst = adt::MaybeSizedValue::sized(dst); - let src_ptr = match src { - Value::ByRef(PtrAndAlign { ptr, aligned: true }) => ptr, - // TODO: Is it possible for unaligned pointers to occur here? - _ => bug!("expected aligned pointer, got {:?}", src), - }; - - // FIXME(solson) - let dest = self.force_allocation(dest)?.to_ptr()?; - let iter = src_fields.zip(dst_fields).enumerate(); - for (i, (src_f, dst_f)) in iter { - let src_fty = self.field_ty(substs_a, src_f); - let dst_fty = self.field_ty(substs_b, dst_f); - if self.type_size(dst_fty)? == Some(0) { - continue; - } - let src_field_offset = self.get_field_offset(src_ty, i)?.bytes(); - let dst_field_offset = self.get_field_offset(dest_ty, i)?.bytes(); - let src_f_ptr = src_ptr.offset(src_field_offset, &self)?; - let dst_f_ptr = dest.offset(dst_field_offset, &self)?; - if src_fty == dst_fty { - self.copy(src_f_ptr, dst_f_ptr.into(), src_fty)?; - } else { - self.unsize_into( - Value::by_ref(src_f_ptr), - src_fty, - Lvalue::from_ptr(dst_f_ptr), - dst_fty, - )?; - } - } - Ok(()) - } - _ => { - bug!( - "unsize_into: invalid conversion: {:?} -> {:?}", - src_ty, - dest_ty - ) - } - } - } - - pub fn dump_local(&self, lvalue: Lvalue) { - // Debug output - match lvalue { - Lvalue::Local { frame, local } => { - let mut allocs = Vec::new(); - let mut msg = format!("{:?}", local); - if frame != self.cur_frame() { - write!(msg, " ({} frames up)", self.cur_frame() - frame).unwrap(); - } - write!(msg, ":").unwrap(); - - match self.stack[frame].get_local(local) { - Err(EvalError { kind: EvalErrorKind::DeadLocal, .. }) => { - write!(msg, " is dead").unwrap(); - } - Err(err) => { - panic!("Failed to access local: {:?}", err); - } - Ok(Value::ByRef(PtrAndAlign { ptr, aligned })) => { - match ptr.into_inner_primval() { - PrimVal::Ptr(ptr) => { - write!(msg, " by {}ref:", if aligned { "" } else { "unaligned " }) - .unwrap(); - allocs.push(ptr.alloc_id); - } - ptr => write!(msg, " integral by ref: {:?}", ptr).unwrap(), - } - } - Ok(Value::ByVal(val)) => { - write!(msg, " {:?}", val).unwrap(); - if let PrimVal::Ptr(ptr) = val { - allocs.push(ptr.alloc_id); - } - } - Ok(Value::ByValPair(val1, val2)) => { - write!(msg, " ({:?}, {:?})", val1, val2).unwrap(); - if let PrimVal::Ptr(ptr) = val1 { - allocs.push(ptr.alloc_id); - } - if let PrimVal::Ptr(ptr) = val2 { - allocs.push(ptr.alloc_id); - } - } - } - - trace!("{}", msg); - self.memory.dump_allocs(allocs); - } - Lvalue::Ptr { ptr: PtrAndAlign { ptr, aligned }, .. } => { - match ptr.into_inner_primval() { - PrimVal::Ptr(ptr) => { - trace!("by {}ref:", if aligned { "" } else { "unaligned " }); - self.memory.dump_alloc(ptr.alloc_id); - } - ptr => trace!(" integral by ref: {:?}", ptr), - } - } - } - } - - /// Convenience function to ensure correct usage of locals - pub fn modify_local(&mut self, frame: usize, local: mir::Local, f: F) -> EvalResult<'tcx> - where - F: FnOnce(&mut Self, Value) -> EvalResult<'tcx, Value>, - { - let val = self.stack[frame].get_local(local)?; - let new_val = f(self, val)?; - self.stack[frame].set_local(local, new_val)?; - // FIXME(solson): Run this when setting to Undef? (See previous version of this code.) - // if let Value::ByRef(ptr) = self.stack[frame].get_local(local) { - // self.memory.deallocate(ptr)?; - // } - Ok(()) - } - - pub fn report(&self, e: &mut EvalError) { - if let Some(ref mut backtrace) = e.backtrace { - let mut trace_text = "\n\nAn error occurred in miri:\n".to_string(); - let mut skip_init = true; - backtrace.resolve(); - 'frames: for (i, frame) in backtrace.frames().iter().enumerate() { - for symbol in frame.symbols() { - if let Some(name) = symbol.name() { - // unmangle the symbol via `to_string` - let name = name.to_string(); - if name.starts_with("miri::after_analysis") { - // don't report initialization gibberish - break 'frames; - } else if name.starts_with("backtrace::capture::Backtrace::new") - // debug mode produces funky symbol names - || name.starts_with("backtrace::capture::{{impl}}::new") - { - // don't report backtrace internals - skip_init = false; - continue 'frames; - } - } - } - if skip_init { - continue; - } - for symbol in frame.symbols() { - write!(trace_text, "{}: ", i).unwrap(); - if let Some(name) = symbol.name() { - write!(trace_text, "{}\n", name).unwrap(); - } else { - write!(trace_text, "\n").unwrap(); - } - write!(trace_text, "\tat ").unwrap(); - if let Some(file_path) = symbol.filename() { - write!(trace_text, "{}", file_path.display()).unwrap(); - } else { - write!(trace_text, "").unwrap(); - } - if let Some(line) = symbol.lineno() { - write!(trace_text, ":{}\n", line).unwrap(); - } else { - write!(trace_text, "\n").unwrap(); - } - } - } - error!("{}", trace_text); - } - if let Some(frame) = self.stack().last() { - let block = &frame.mir.basic_blocks()[frame.block]; - let span = if frame.stmt < block.statements.len() { - block.statements[frame.stmt].source_info.span - } else { - block.terminator().source_info.span - }; - let mut err = self.tcx.sess.struct_span_err(span, &e.to_string()); - for &Frame { instance, span, .. } in self.stack().iter().rev() { - if self.tcx.def_key(instance.def_id()).disambiguated_data.data == - DefPathData::ClosureExpr - { - err.span_note(span, "inside call to closure"); - continue; - } - err.span_note(span, &format!("inside call to {}", instance)); - } - err.emit(); - } else { - self.tcx.sess.err(&e.to_string()); - } - } -} - -impl<'tcx> Frame<'tcx> { - pub fn get_local(&self, local: mir::Local) -> EvalResult<'tcx, Value> { - // Subtract 1 because we don't store a value for the ReturnPointer, the local with index 0. - self.locals[local.index() - 1].ok_or(EvalErrorKind::DeadLocal.into()) - } - - fn set_local(&mut self, local: mir::Local, value: Value) -> EvalResult<'tcx> { - // Subtract 1 because we don't store a value for the ReturnPointer, the local with index 0. - match self.locals[local.index() - 1] { - None => err!(DeadLocal), - Some(ref mut local) => { - *local = value; - Ok(()) - } - } - } - - pub fn storage_live(&mut self, local: mir::Local) -> EvalResult<'tcx, Option> { - trace!("{:?} is now live", local); - - let old = self.locals[local.index() - 1]; - self.locals[local.index() - 1] = Some(Value::ByVal(PrimVal::Undef)); // StorageLive *always* kills the value that's currently stored - return Ok(old); - } - - /// Returns the old value of the local - pub fn storage_dead(&mut self, local: mir::Local) -> EvalResult<'tcx, Option> { - trace!("{:?} is now dead", local); - - let old = self.locals[local.index() - 1]; - self.locals[local.index() - 1] = None; - return Ok(old); - } -} - -// TODO(solson): Upstream these methods into rustc::ty::layout. - -pub(super) trait IntegerExt { - fn size(self) -> Size; -} - -impl IntegerExt for layout::Integer { - fn size(self) -> Size { - use rustc::ty::layout::Integer::*; - match self { - I1 | I8 => Size::from_bits(8), - I16 => Size::from_bits(16), - I32 => Size::from_bits(32), - I64 => Size::from_bits(64), - I128 => Size::from_bits(128), - } - } -} - -/// FIXME: expose trans::monomorphize::resolve_closure -pub fn resolve_closure<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - substs: ty::ClosureSubsts<'tcx>, - requested_kind: ty::ClosureKind, -) -> ty::Instance<'tcx> { - let actual_kind = tcx.closure_kind(def_id); - match needs_fn_once_adapter_shim(actual_kind, requested_kind) { - Ok(true) => fn_once_adapter_instance(tcx, def_id, substs), - _ => ty::Instance::new(def_id, substs.substs), - } -} - -fn fn_once_adapter_instance<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - closure_did: DefId, - substs: ty::ClosureSubsts<'tcx>, -) -> ty::Instance<'tcx> { - debug!("fn_once_adapter_shim({:?}, {:?})", closure_did, substs); - let fn_once = tcx.lang_items().fn_once_trait().unwrap(); - let call_once = tcx.associated_items(fn_once) - .find(|it| it.kind == ty::AssociatedKind::Method) - .unwrap() - .def_id; - let def = ty::InstanceDef::ClosureOnceShim { call_once }; - - let self_ty = tcx.mk_closure_from_closure_substs(closure_did, substs); - - let sig = tcx.fn_sig(closure_did).subst(tcx, substs.substs); - let sig = tcx.erase_late_bound_regions_and_normalize(&sig); - assert_eq!(sig.inputs().len(), 1); - let substs = tcx.mk_substs( - [Kind::from(self_ty), Kind::from(sig.inputs()[0])] - .iter() - .cloned(), - ); - - debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig); - ty::Instance { def, substs } -} - -fn needs_fn_once_adapter_shim( - actual_closure_kind: ty::ClosureKind, - trait_closure_kind: ty::ClosureKind, -) -> Result { - match (actual_closure_kind, trait_closure_kind) { - (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | - (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => { - // No adapter needed. - Ok(false) - } - (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => { - // The closure fn `llfn` is a `fn(&self, ...)`. We want a - // `fn(&mut self, ...)`. In fact, at trans time, these are - // basically the same thing, so we can just return llfn. - Ok(false) - } - (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { - // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut - // self, ...)`. We want a `fn(self, ...)`. We can produce - // this by doing something like: - // - // fn call_once(self, ...) { call_mut(&self, ...) } - // fn call_once(mut self, ...) { call_mut(&mut self, ...) } - // - // These are both the same at trans time. - Ok(true) - } - _ => Err(()), - } -} - -/// The point where linking happens. Resolve a (def_id, substs) -/// pair to an instance. -pub fn resolve<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - substs: &'tcx Substs<'tcx>, -) -> ty::Instance<'tcx> { - debug!("resolve(def_id={:?}, substs={:?})", def_id, substs); - let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) { - debug!(" => associated item, attempting to find impl"); - let item = tcx.associated_item(def_id); - resolve_associated_item(tcx, &item, trait_def_id, substs) - } else { - let item_type = def_ty(tcx, def_id, substs); - let def = match item_type.sty { - ty::TyFnDef(..) - if { - let f = item_type.fn_sig(tcx); - f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic - } => { - debug!(" => intrinsic"); - ty::InstanceDef::Intrinsic(def_id) - } - _ => { - if Some(def_id) == tcx.lang_items().drop_in_place_fn() { - let ty = substs.type_at(0); - if needs_drop_glue(tcx, ty) { - debug!(" => nontrivial drop glue"); - ty::InstanceDef::DropGlue(def_id, Some(ty)) - } else { - debug!(" => trivial drop glue"); - ty::InstanceDef::DropGlue(def_id, None) - } - } else { - debug!(" => free item"); - ty::InstanceDef::Item(def_id) - } - } - }; - ty::Instance { def, substs } - }; - debug!( - "resolve(def_id={:?}, substs={:?}) = {}", - def_id, - substs, - result - ); - result -} - -pub fn needs_drop_glue<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, t: Ty<'tcx>) -> bool { - assert!(t.is_normalized_for_trans()); - - let t = tcx.erase_regions(&t); - - // FIXME (#22815): note that type_needs_drop conservatively - // approximates in some cases and may say a type expression - // requires drop glue when it actually does not. - // - // (In this case it is not clear whether any harm is done, i.e. - // erroneously returning `true` in some cases where we could have - // returned `false` does not appear unsound. The impact on - // code quality is unknown at this time.) - - let env = ty::ParamEnv::empty(Reveal::All); - if !t.needs_drop(tcx, env) { - return false; - } - match t.sty { - ty::TyAdt(def, _) if def.is_box() => { - let typ = t.boxed_ty(); - if !typ.needs_drop(tcx, env) && type_is_sized(tcx, typ) { - let layout = t.layout(tcx, ty::ParamEnv::empty(Reveal::All)).unwrap(); - // `Box` does not allocate. - layout.size(&tcx.data_layout).bytes() != 0 - } else { - true - } - } - _ => true, - } -} - -fn resolve_associated_item<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - trait_item: &ty::AssociatedItem, - trait_id: DefId, - rcvr_substs: &'tcx Substs<'tcx>, -) -> ty::Instance<'tcx> { - let def_id = trait_item.def_id; - debug!( - "resolve_associated_item(trait_item={:?}, \ - trait_id={:?}, \ - rcvr_substs={:?})", - def_id, - trait_id, - rcvr_substs - ); - - let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); - let vtbl = tcx.trans_fulfill_obligation(DUMMY_SP, ty::ParamEnv::empty(traits::Reveal::All), ty::Binder(trait_ref)); - - // Now that we know which impl is being used, we can dispatch to - // the actual function: - match vtbl { - ::rustc::traits::VtableImpl(impl_data) => { - let (def_id, substs) = - ::rustc::traits::find_associated_item(tcx, trait_item, rcvr_substs, &impl_data); - let substs = tcx.erase_regions(&substs); - ty::Instance::new(def_id, substs) - } - ::rustc::traits::VtableGenerator(closure_data) => { - ty::Instance { - def: ty::InstanceDef::Item(closure_data.closure_def_id), - substs: closure_data.substs.substs - } - } - ::rustc::traits::VtableClosure(closure_data) => { - let trait_closure_kind = tcx.lang_items().fn_trait_kind(trait_id).unwrap(); - resolve_closure( - tcx, - closure_data.closure_def_id, - closure_data.substs, - trait_closure_kind, - ) - } - ::rustc::traits::VtableFnPointer(ref data) => { - ty::Instance { - def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty), - substs: rcvr_substs, - } - } - ::rustc::traits::VtableObject(ref data) => { - let index = tcx.get_vtable_index_of_object_method(data, def_id); - ty::Instance { - def: ty::InstanceDef::Virtual(def_id, index), - substs: rcvr_substs, - } - } - ::rustc::traits::VtableBuiltin(..) if Some(trait_id) == tcx.lang_items().clone_trait() => { - ty::Instance { - def: ty::InstanceDef::CloneShim(def_id, trait_ref.self_ty()), - substs: rcvr_substs - } - } - _ => bug!("static call to invalid vtable: {:?}", vtbl), - } -} - -pub fn def_ty<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - substs: &'tcx Substs<'tcx>, -) -> Ty<'tcx> { - let ty = tcx.type_of(def_id); - apply_param_substs(tcx, substs, &ty) -} - -/// Monomorphizes a type from the AST by first applying the in-scope -/// substitutions and then normalizing any associated types. -pub fn apply_param_substs<'a, 'tcx, T>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_substs: &Substs<'tcx>, - value: &T, -) -> T -where - T: ::rustc::infer::TransNormalize<'tcx>, -{ - debug!( - "apply_param_substs(param_substs={:?}, value={:?})", - param_substs, - value - ); - let substituted = value.subst(tcx, param_substs); - let substituted = tcx.erase_regions(&substituted); - AssociatedTypeNormalizer { tcx }.fold(&substituted) -} - - -struct AssociatedTypeNormalizer<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, -} - -impl<'a, 'tcx> AssociatedTypeNormalizer<'a, 'tcx> { - fn fold>(&mut self, value: &T) -> T { - if !value.has_projections() { - value.clone() - } else { - value.fold_with(self) - } - } -} - -impl<'a, 'tcx> ::rustc::ty::fold::TypeFolder<'tcx, 'tcx> for AssociatedTypeNormalizer<'a, 'tcx> { - fn tcx<'c>(&'c self) -> TyCtxt<'c, 'tcx, 'tcx> { - self.tcx - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if !ty.has_projections() { - ty - } else { - self.tcx.normalize_associated_type(&ty) - } - } -} - -fn type_is_sized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { - // generics are weird, don't run this function on a generic - assert!(!ty.needs_subst()); - ty.is_sized(tcx, ty::ParamEnv::empty(Reveal::All), DUMMY_SP) -} - -pub fn resolve_drop_in_place<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - ty: Ty<'tcx>, -) -> ty::Instance<'tcx> { - let def_id = tcx.require_lang_item(::rustc::middle::lang_items::DropInPlaceFnLangItem); - let substs = tcx.intern_substs(&[Kind::from(ty)]); - resolve(tcx, def_id, substs) -} diff --git a/src/librustc_mir/interpret/lvalue.rs b/src/librustc_mir/interpret/lvalue.rs deleted file mode 100644 index 36b396a7a2ba..000000000000 --- a/src/librustc_mir/interpret/lvalue.rs +++ /dev/null @@ -1,506 +0,0 @@ -use rustc::mir; -use rustc::ty::layout::{Size, Align}; -use rustc::ty::{self, Ty}; -use rustc_data_structures::indexed_vec::Idx; - -use super::{EvalResult, EvalContext, MemoryPointer, PrimVal, Value, Pointer, Machine, PtrAndAlign, ValTy}; - -#[derive(Copy, Clone, Debug)] -pub enum Lvalue { - /// An lvalue referring to a value allocated in the `Memory` system. - Ptr { - /// An lvalue may have an invalid (integral or undef) pointer, - /// since it might be turned back into a reference - /// before ever being dereferenced. - ptr: PtrAndAlign, - extra: LvalueExtra, - }, - - /// An lvalue referring to a value on the stack. Represented by a stack frame index paired with - /// a Mir local index. - Local { frame: usize, local: mir::Local }, -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum LvalueExtra { - None, - Length(u64), - Vtable(MemoryPointer), - DowncastVariant(usize), -} - -/// Uniquely identifies a specific constant or static. -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] -pub struct GlobalId<'tcx> { - /// For a constant or static, the `Instance` of the item itself. - /// For a promoted global, the `Instance` of the function they belong to. - pub instance: ty::Instance<'tcx>, - - /// The index for promoted globals within their function's `Mir`. - pub promoted: Option, -} - -impl<'tcx> Lvalue { - /// Produces an Lvalue that will error if attempted to be read from - pub fn undef() -> Self { - Self::from_primval_ptr(PrimVal::Undef.into()) - } - - pub fn from_primval_ptr(ptr: Pointer) -> Self { - Lvalue::Ptr { - ptr: PtrAndAlign { ptr, aligned: true }, - extra: LvalueExtra::None, - } - } - - pub fn from_ptr(ptr: MemoryPointer) -> Self { - Self::from_primval_ptr(ptr.into()) - } - - pub(super) fn to_ptr_extra_aligned(self) -> (PtrAndAlign, LvalueExtra) { - match self { - Lvalue::Ptr { ptr, extra } => (ptr, extra), - _ => bug!("to_ptr_and_extra: expected Lvalue::Ptr, got {:?}", self), - - } - } - - pub fn to_ptr(self) -> EvalResult<'tcx, MemoryPointer> { - let (ptr, extra) = self.to_ptr_extra_aligned(); - // At this point, we forget about the alignment information -- the lvalue has been turned into a reference, - // and no matter where it came from, it now must be aligned. - assert_eq!(extra, LvalueExtra::None); - ptr.to_ptr() - } - - pub(super) fn elem_ty_and_len(self, ty: Ty<'tcx>) -> (Ty<'tcx>, u64) { - match ty.sty { - ty::TyArray(elem, n) => (elem, n.val.to_const_int().unwrap().to_u64().unwrap() as u64), - - ty::TySlice(elem) => { - match self { - Lvalue::Ptr { extra: LvalueExtra::Length(len), .. } => (elem, len), - _ => { - bug!( - "elem_ty_and_len of a TySlice given non-slice lvalue: {:?}", - self - ) - } - } - } - - _ => bug!("elem_ty_and_len expected array or slice, got {:?}", ty), - } - } -} - -impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { - /// Reads a value from the lvalue without going through the intermediate step of obtaining - /// a `miri::Lvalue` - pub fn try_read_lvalue( - &mut self, - lvalue: &mir::Lvalue<'tcx>, - ) -> EvalResult<'tcx, Option> { - use rustc::mir::Lvalue::*; - match *lvalue { - // Might allow this in the future, right now there's no way to do this from Rust code anyway - Local(mir::RETURN_POINTER) => err!(ReadFromReturnPointer), - // Directly reading a local will always succeed - Local(local) => self.frame().get_local(local).map(Some), - // Directly reading a static will always succeed - Static(ref static_) => { - let instance = ty::Instance::mono(self.tcx, static_.def_id); - let cid = GlobalId { - instance, - promoted: None, - }; - Ok(Some(Value::ByRef( - *self.globals.get(&cid).expect("global not cached"), - ))) - } - Projection(ref proj) => self.try_read_lvalue_projection(proj), - } - } - - fn try_read_lvalue_projection( - &mut self, - proj: &mir::LvalueProjection<'tcx>, - ) -> EvalResult<'tcx, Option> { - use rustc::mir::ProjectionElem::*; - let base = match self.try_read_lvalue(&proj.base)? { - Some(base) => base, - None => return Ok(None), - }; - let base_ty = self.lvalue_ty(&proj.base); - match proj.elem { - Field(field, _) => match (field.index(), base) { - // the only field of a struct - (0, Value::ByVal(val)) => Ok(Some(Value::ByVal(val))), - // split fat pointers, 2 element tuples, ... - (0...1, Value::ByValPair(a, b)) if self.get_field_count(base_ty)? == 2 => { - let val = [a, b][field.index()]; - Ok(Some(Value::ByVal(val))) - }, - // the only field of a struct is a fat pointer - (0, Value::ByValPair(..)) => Ok(Some(base)), - _ => Ok(None), - }, - // The NullablePointer cases should work fine, need to take care for normal enums - Downcast(..) | - Subslice { .. } | - // reading index 0 or index 1 from a ByVal or ByVal pair could be optimized - ConstantIndex { .. } | Index(_) | - // No way to optimize this projection any better than the normal lvalue path - Deref => Ok(None), - } - } - - /// Returns a value and (in case of a ByRef) if we are supposed to use aligned accesses. - pub(super) fn eval_and_read_lvalue( - &mut self, - lvalue: &mir::Lvalue<'tcx>, - ) -> EvalResult<'tcx, Value> { - // Shortcut for things like accessing a fat pointer's field, - // which would otherwise (in the `eval_lvalue` path) require moving a `ByValPair` to memory - // and returning an `Lvalue::Ptr` to it - if let Some(val) = self.try_read_lvalue(lvalue)? { - return Ok(val); - } - let lvalue = self.eval_lvalue(lvalue)?; - self.read_lvalue(lvalue) - } - - pub fn read_lvalue(&self, lvalue: Lvalue) -> EvalResult<'tcx, Value> { - match lvalue { - Lvalue::Ptr { ptr, extra } => { - assert_eq!(extra, LvalueExtra::None); - Ok(Value::ByRef(ptr)) - } - Lvalue::Local { frame, local } => self.stack[frame].get_local(local), - } - } - - pub fn eval_lvalue(&mut self, mir_lvalue: &mir::Lvalue<'tcx>) -> EvalResult<'tcx, Lvalue> { - use rustc::mir::Lvalue::*; - let lvalue = match *mir_lvalue { - Local(mir::RETURN_POINTER) => self.frame().return_lvalue, - Local(local) => Lvalue::Local { - frame: self.cur_frame(), - local, - }, - - Static(ref static_) => { - let instance = ty::Instance::mono(self.tcx, static_.def_id); - let gid = GlobalId { - instance, - promoted: None, - }; - Lvalue::Ptr { - ptr: *self.globals.get(&gid).expect("uncached global"), - extra: LvalueExtra::None, - } - } - - Projection(ref proj) => { - let ty = self.lvalue_ty(&proj.base); - let lvalue = self.eval_lvalue(&proj.base)?; - return self.eval_lvalue_projection(lvalue, ty, &proj.elem); - } - }; - - if log_enabled!(::log::LogLevel::Trace) { - self.dump_local(lvalue); - } - - Ok(lvalue) - } - - pub fn lvalue_field( - &mut self, - base: Lvalue, - field: mir::Field, - base_ty: Ty<'tcx>, - field_ty: Ty<'tcx>, - ) -> EvalResult<'tcx, Lvalue> { - use rustc::ty::layout::Layout::*; - - let base_layout = self.type_layout(base_ty)?; - let field_index = field.index(); - let (offset, packed) = match *base_layout { - Univariant { ref variant, .. } => (variant.offsets[field_index], variant.packed), - - // mir optimizations treat single variant enums as structs - General { ref variants, .. } if variants.len() == 1 => { - (variants[0].offsets[field_index], variants[0].packed) - } - - General { ref variants, .. } => { - let (_, base_extra) = base.to_ptr_extra_aligned(); - if let LvalueExtra::DowncastVariant(variant_idx) = base_extra { - // +1 for the discriminant, which is field 0 - assert!(!variants[variant_idx].packed); - (variants[variant_idx].offsets[field_index + 1], false) - } else { - bug!("field access on enum had no variant index"); - } - } - - RawNullablePointer { .. } => { - assert_eq!(field_index, 0); - return Ok(base); - } - - StructWrappedNullablePointer { ref nonnull, .. } => { - (nonnull.offsets[field_index], nonnull.packed) - } - - UntaggedUnion { .. } => return Ok(base), - - Vector { element, count } => { - let field = field_index as u64; - assert!(field < count); - let elem_size = element.size(&self.tcx.data_layout).bytes(); - (Size::from_bytes(field * elem_size), false) - } - - // We treat arrays + fixed sized indexing like field accesses - Array { .. } => { - let field = field_index as u64; - let elem_size = match base_ty.sty { - ty::TyArray(elem_ty, n) => { - assert!(field < n.val.to_const_int().unwrap().to_u64().unwrap() as u64); - self.type_size(elem_ty)?.expect("array elements are sized") as u64 - } - _ => { - bug!( - "lvalue_field: got Array layout but non-array type {:?}", - base_ty - ) - } - }; - (Size::from_bytes(field * elem_size), false) - } - - FatPointer { .. } => { - let bytes = field_index as u64 * self.memory.pointer_size(); - let offset = Size::from_bytes(bytes); - (offset, false) - } - - _ => bug!("field access on non-product type: {:?}", base_layout), - }; - - // Do not allocate in trivial cases - let (base_ptr, base_extra) = match base { - Lvalue::Ptr { ptr, extra } => (ptr, extra), - Lvalue::Local { frame, local } => { - match self.stack[frame].get_local(local)? { - // in case the type has a single field, just return the value - Value::ByVal(_) - if self.get_field_count(base_ty).map(|c| c == 1).unwrap_or( - false, - ) => { - assert_eq!( - offset.bytes(), - 0, - "ByVal can only have 1 non zst field with offset 0" - ); - return Ok(base); - } - Value::ByRef { .. } | - Value::ByValPair(..) | - Value::ByVal(_) => self.force_allocation(base)?.to_ptr_extra_aligned(), - } - } - }; - - let offset = match base_extra { - LvalueExtra::Vtable(tab) => { - let (_, align) = self.size_and_align_of_dst( - base_ty, - base_ptr.ptr.to_value_with_vtable(tab), - )?; - offset - .abi_align(Align::from_bytes(align, align).unwrap()) - .bytes() - } - _ => offset.bytes(), - }; - - let mut ptr = base_ptr.offset(offset, &self)?; - // if we were unaligned, stay unaligned - // no matter what we were, if we are packed, we must not be aligned anymore - ptr.aligned &= !packed; - - let field_ty = self.monomorphize(field_ty, self.substs()); - - let extra = if self.type_is_sized(field_ty) { - LvalueExtra::None - } else { - match base_extra { - LvalueExtra::None => bug!("expected fat pointer"), - LvalueExtra::DowncastVariant(..) => { - bug!("Rust doesn't support unsized fields in enum variants") - } - LvalueExtra::Vtable(_) | - LvalueExtra::Length(_) => {} - } - base_extra - }; - - Ok(Lvalue::Ptr { ptr, extra }) - } - - pub(super) fn val_to_lvalue(&self, val: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, Lvalue> { - Ok(match self.tcx.struct_tail(ty).sty { - ty::TyDynamic(..) => { - let (ptr, vtable) = val.into_ptr_vtable_pair(&self.memory)?; - Lvalue::Ptr { - ptr: PtrAndAlign { ptr, aligned: true }, - extra: LvalueExtra::Vtable(vtable), - } - } - ty::TyStr | ty::TySlice(_) => { - let (ptr, len) = val.into_slice(&self.memory)?; - Lvalue::Ptr { - ptr: PtrAndAlign { ptr, aligned: true }, - extra: LvalueExtra::Length(len), - } - } - _ => Lvalue::from_primval_ptr(val.into_ptr(&self.memory)?), - }) - } - - pub(super) fn lvalue_index( - &mut self, - base: Lvalue, - outer_ty: Ty<'tcx>, - n: u64, - ) -> EvalResult<'tcx, Lvalue> { - // Taking the outer type here may seem odd; it's needed because for array types, the outer type gives away the length. - let base = self.force_allocation(base)?; - let (base_ptr, _) = base.to_ptr_extra_aligned(); - - let (elem_ty, len) = base.elem_ty_and_len(outer_ty); - let elem_size = self.type_size(elem_ty)?.expect( - "slice element must be sized", - ); - assert!( - n < len, - "Tried to access element {} of array/slice with length {}", - n, - len - ); - let ptr = base_ptr.offset(n * elem_size, self.memory.layout)?; - Ok(Lvalue::Ptr { - ptr, - extra: LvalueExtra::None, - }) - } - - pub(super) fn eval_lvalue_projection( - &mut self, - base: Lvalue, - base_ty: Ty<'tcx>, - proj_elem: &mir::ProjectionElem<'tcx, mir::Local, Ty<'tcx>>, - ) -> EvalResult<'tcx, Lvalue> { - use rustc::mir::ProjectionElem::*; - let (ptr, extra) = match *proj_elem { - Field(field, field_ty) => { - return self.lvalue_field(base, field, base_ty, field_ty); - } - - Downcast(_, variant) => { - let base_layout = self.type_layout(base_ty)?; - // FIXME(solson) - let base = self.force_allocation(base)?; - let (base_ptr, base_extra) = base.to_ptr_extra_aligned(); - - use rustc::ty::layout::Layout::*; - let extra = match *base_layout { - General { .. } => LvalueExtra::DowncastVariant(variant), - RawNullablePointer { .. } | - StructWrappedNullablePointer { .. } => base_extra, - _ => bug!("variant downcast on non-aggregate: {:?}", base_layout), - }; - (base_ptr, extra) - } - - Deref => { - let val = self.read_lvalue(base)?; - - let pointee_type = match base_ty.sty { - ty::TyRawPtr(ref tam) | - ty::TyRef(_, ref tam) => tam.ty, - ty::TyAdt(def, _) if def.is_box() => base_ty.boxed_ty(), - _ => bug!("can only deref pointer types"), - }; - - trace!("deref to {} on {:?}", pointee_type, val); - - return self.val_to_lvalue(val, pointee_type); - } - - Index(local) => { - let value = self.frame().get_local(local)?; - let ty = self.tcx.types.usize; - let n = self.value_to_primval(ValTy { value, ty })?.to_u64()?; - return self.lvalue_index(base, base_ty, n); - } - - ConstantIndex { - offset, - min_length, - from_end, - } => { - // FIXME(solson) - let base = self.force_allocation(base)?; - let (base_ptr, _) = base.to_ptr_extra_aligned(); - - let (elem_ty, n) = base.elem_ty_and_len(base_ty); - let elem_size = self.type_size(elem_ty)?.expect( - "sequence element must be sized", - ); - assert!(n >= min_length as u64); - - let index = if from_end { - n - u64::from(offset) - } else { - u64::from(offset) - }; - - let ptr = base_ptr.offset(index * elem_size, &self)?; - (ptr, LvalueExtra::None) - } - - Subslice { from, to } => { - // FIXME(solson) - let base = self.force_allocation(base)?; - let (base_ptr, _) = base.to_ptr_extra_aligned(); - - let (elem_ty, n) = base.elem_ty_and_len(base_ty); - let elem_size = self.type_size(elem_ty)?.expect( - "slice element must be sized", - ); - assert!(u64::from(from) <= n - u64::from(to)); - let ptr = base_ptr.offset(u64::from(from) * elem_size, &self)?; - // sublicing arrays produces arrays - let extra = if self.type_is_sized(base_ty) { - LvalueExtra::None - } else { - LvalueExtra::Length(n - u64::from(to) - u64::from(from)) - }; - (ptr, extra) - } - }; - - Ok(Lvalue::Ptr { ptr, extra }) - } - - pub fn lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> Ty<'tcx> { - self.monomorphize( - lvalue.ty(self.mir(), self.tcx).to_ty(self.tcx), - self.substs(), - ) - } -} diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs deleted file mode 100644 index 3df5d1b6a31b..000000000000 --- a/src/librustc_mir/interpret/machine.rs +++ /dev/null @@ -1,82 +0,0 @@ -//! This module contains everything needed to instantiate an interpreter. -//! This separation exists to ensure that no fancy miri features like -//! interpreting common C functions leak into CTFE. - -use super::{EvalResult, EvalContext, Lvalue, PrimVal, ValTy}; - -use rustc::{mir, ty}; -use syntax::codemap::Span; -use syntax::ast::Mutability; - -/// Methods of this trait signifies a point where CTFE evaluation would fail -/// and some use case dependent behaviour can instead be applied -pub trait Machine<'tcx>: Sized { - /// Additional data that can be accessed via the EvalContext - type Data; - - /// Additional data that can be accessed via the Memory - type MemoryData; - - /// Additional memory kinds a machine wishes to distinguish from the builtin ones - type MemoryKinds: ::std::fmt::Debug + PartialEq + Copy + Clone; - - /// Entry point to all function calls. - /// - /// Returns Ok(true) when the function was handled completely - /// e.g. due to missing mir - /// - /// Returns Ok(false) if a new stack frame was pushed - fn eval_fn_call<'a>( - ecx: &mut EvalContext<'a, 'tcx, Self>, - instance: ty::Instance<'tcx>, - destination: Option<(Lvalue, mir::BasicBlock)>, - args: &[ValTy<'tcx>], - span: Span, - sig: ty::FnSig<'tcx>, - ) -> EvalResult<'tcx, bool>; - - /// directly process an intrinsic without pushing a stack frame. - fn call_intrinsic<'a>( - ecx: &mut EvalContext<'a, 'tcx, Self>, - instance: ty::Instance<'tcx>, - args: &[ValTy<'tcx>], - dest: Lvalue, - dest_ty: ty::Ty<'tcx>, - dest_layout: &'tcx ty::layout::Layout, - target: mir::BasicBlock, - ) -> EvalResult<'tcx>; - - /// Called for all binary operations except on float types. - /// - /// Returns `None` if the operation should be handled by the integer - /// op code in order to share more code between machines - /// - /// Returns a (value, overflowed) pair if the operation succeeded - fn try_ptr_op<'a>( - ecx: &EvalContext<'a, 'tcx, Self>, - bin_op: mir::BinOp, - left: PrimVal, - left_ty: ty::Ty<'tcx>, - right: PrimVal, - right_ty: ty::Ty<'tcx>, - ) -> EvalResult<'tcx, Option<(PrimVal, bool)>>; - - /// Called when trying to mark machine defined `MemoryKinds` as static - fn mark_static_initialized(m: Self::MemoryKinds) -> EvalResult<'tcx>; - - /// Heap allocations via the `box` keyword - /// - /// Returns a pointer to the allocated memory - fn box_alloc<'a>( - ecx: &mut EvalContext<'a, 'tcx, Self>, - ty: ty::Ty<'tcx>, - dest: Lvalue, - ) -> EvalResult<'tcx>; - - /// Called when trying to access a global declared with a `linkage` attribute - fn global_item_with_linkage<'a>( - ecx: &mut EvalContext<'a, 'tcx, Self>, - instance: ty::Instance<'tcx>, - mutability: Mutability, - ) -> EvalResult<'tcx>; -} diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs deleted file mode 100644 index bde79294adda..000000000000 --- a/src/librustc_mir/interpret/memory.rs +++ /dev/null @@ -1,1700 +0,0 @@ -use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian, BigEndian}; -use std::collections::{btree_map, BTreeMap, HashMap, HashSet, VecDeque}; -use std::{fmt, iter, ptr, mem, io}; -use std::cell::Cell; - -use rustc::ty::Instance; -use rustc::ty::layout::{self, TargetDataLayout, HasDataLayout}; -use syntax::ast::Mutability; -use rustc::middle::region; - -use super::{EvalResult, EvalErrorKind, PrimVal, Pointer, EvalContext, DynamicLifetime, Machine, - RangeMap, AbsLvalue}; - -//////////////////////////////////////////////////////////////////////////////// -// Locks -//////////////////////////////////////////////////////////////////////////////// - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum AccessKind { - Read, - Write, -} - -/// Information about a lock that is currently held. -#[derive(Clone, Debug)] -struct LockInfo<'tcx> { - /// Stores for which lifetimes (of the original write lock) we got - /// which suspensions. - suspended: HashMap, Vec>, - /// The current state of the lock that's actually effective. - active: Lock, -} - -/// Write locks are identified by a stack frame and an "abstract" (untyped) lvalue. -/// It may be tempting to use the lifetime as identifier, but that does not work -/// for two reasons: -/// * First of all, due to subtyping, the same lock may be referred to with different -/// lifetimes. -/// * Secondly, different write locks may actually have the same lifetime. See `test2` -/// in `run-pass/many_shr_bor.rs`. -/// The Id is "captured" when the lock is first suspended; at that point, the borrow checker -/// considers the path frozen and hence the Id remains stable. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -struct WriteLockId<'tcx> { - frame: usize, - path: AbsLvalue<'tcx>, -} - -#[derive(Clone, Debug, PartialEq)] -pub enum Lock { - NoLock, - WriteLock(DynamicLifetime), - ReadLock(Vec), // This should never be empty -- that would be a read lock held and nobody there to release it... -} -use self::Lock::*; - -impl<'tcx> Default for LockInfo<'tcx> { - fn default() -> Self { - LockInfo::new(NoLock) - } -} - -impl<'tcx> LockInfo<'tcx> { - fn new(lock: Lock) -> LockInfo<'tcx> { - LockInfo { - suspended: HashMap::new(), - active: lock, - } - } - - fn access_permitted(&self, frame: Option, access: AccessKind) -> bool { - use self::AccessKind::*; - match (&self.active, access) { - (&NoLock, _) => true, - (&ReadLock(ref lfts), Read) => { - assert!(!lfts.is_empty(), "Someone left an empty read lock behind."); - // Read access to read-locked region is okay, no matter who's holding the read lock. - true - } - (&WriteLock(ref lft), _) => { - // All access is okay if we are the ones holding it - Some(lft.frame) == frame - } - _ => false, // Nothing else is okay. - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Allocations and pointers -//////////////////////////////////////////////////////////////////////////////// - -#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct AllocId(u64); - -#[derive(Debug)] -pub enum AllocIdKind { - /// We can't ever have more than `usize::max_value` functions at the same time - /// since we never "deallocate" functions - Function(usize), - /// Locals and heap allocations (also statics for now, but those will get their - /// own variant soonish). - Runtime(u64), -} - -impl AllocIdKind { - pub fn into_alloc_id(self) -> AllocId { - match self { - AllocIdKind::Function(n) => AllocId(n as u64), - AllocIdKind::Runtime(n) => AllocId((1 << 63) | n), - } - } -} - -impl AllocId { - /// Currently yields the top bit to discriminate the `AllocIdKind`s - fn discriminant(self) -> u64 { - self.0 >> 63 - } - /// Yields everything but the discriminant bits - pub fn index(self) -> u64 { - self.0 & ((1 << 63) - 1) - } - pub fn into_alloc_id_kind(self) -> AllocIdKind { - match self.discriminant() { - 0 => AllocIdKind::Function(self.index() as usize), - 1 => AllocIdKind::Runtime(self.index()), - n => bug!("got discriminant {} for AllocId", n), - } - } -} - -impl fmt::Display for AllocId { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}", self.into_alloc_id_kind()) - } -} - -impl fmt::Debug for AllocId { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}", self.into_alloc_id_kind()) - } -} - -#[derive(Debug)] -pub struct Allocation<'tcx, M> { - /// The actual bytes of the allocation. - /// Note that the bytes of a pointer represent the offset of the pointer - pub bytes: Vec, - /// Maps from byte addresses to allocations. - /// Only the first byte of a pointer is inserted into the map. - pub relocations: BTreeMap, - /// Denotes undefined memory. Reading from undefined memory is forbidden in miri - pub undef_mask: UndefMask, - /// The alignment of the allocation to detect unaligned reads. - pub align: u64, - /// Whether the allocation may be modified. - pub mutable: Mutability, - /// Use the `mark_static_initalized` method of `Memory` to ensure that an error occurs, if the memory of this - /// allocation is modified or deallocated in the future. - /// Helps guarantee that stack allocations aren't deallocated via `rust_deallocate` - pub kind: MemoryKind, - /// Memory regions that are locked by some function - locks: RangeMap>, -} - -impl<'tcx, M> Allocation<'tcx, M> { - fn check_locks( - &self, - frame: Option, - offset: u64, - len: u64, - access: AccessKind, - ) -> Result<(), LockInfo<'tcx>> { - if len == 0 { - return Ok(()); - } - for lock in self.locks.iter(offset, len) { - // Check if the lock is in conflict with the access. - if !lock.access_permitted(frame, access) { - return Err(lock.clone()); - } - } - Ok(()) - } -} - -#[derive(Debug, PartialEq, Copy, Clone)] -pub enum MemoryKind { - /// Error if deallocated except during a stack pop - Stack, - /// Static in the process of being initialized. - /// The difference is important: An immutable static referring to a - /// mutable initialized static will freeze immutably and would not - /// be able to distinguish already initialized statics from uninitialized ones - UninitializedStatic, - /// May never be deallocated - Static, - /// Additional memory kinds a machine wishes to distinguish from the builtin ones - Machine(T), -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct MemoryPointer { - pub alloc_id: AllocId, - pub offset: u64, -} - -impl<'tcx> MemoryPointer { - pub fn new(alloc_id: AllocId, offset: u64) -> Self { - MemoryPointer { alloc_id, offset } - } - - pub(crate) fn wrapping_signed_offset(self, i: i64, cx: C) -> Self { - MemoryPointer::new( - self.alloc_id, - cx.data_layout().wrapping_signed_offset(self.offset, i), - ) - } - - pub fn overflowing_signed_offset(self, i: i128, cx: C) -> (Self, bool) { - let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset, i); - (MemoryPointer::new(self.alloc_id, res), over) - } - - pub(crate) fn signed_offset(self, i: i64, cx: C) -> EvalResult<'tcx, Self> { - Ok(MemoryPointer::new( - self.alloc_id, - cx.data_layout().signed_offset(self.offset, i)?, - )) - } - - pub fn overflowing_offset(self, i: u64, cx: C) -> (Self, bool) { - let (res, over) = cx.data_layout().overflowing_offset(self.offset, i); - (MemoryPointer::new(self.alloc_id, res), over) - } - - pub fn offset(self, i: u64, cx: C) -> EvalResult<'tcx, Self> { - Ok(MemoryPointer::new( - self.alloc_id, - cx.data_layout().offset(self.offset, i)?, - )) - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Top-level interpreter memory -//////////////////////////////////////////////////////////////////////////////// - -pub struct Memory<'a, 'tcx, M: Machine<'tcx>> { - /// Additional data required by the Machine - pub data: M::MemoryData, - - /// Actual memory allocations (arbitrary bytes, may contain pointers into other allocations). - alloc_map: HashMap>, - - /// The AllocId to assign to the next new regular allocation. Always incremented, never gets smaller. - next_alloc_id: u64, - - /// Number of virtual bytes allocated. - memory_usage: u64, - - /// Maximum number of virtual bytes that may be allocated. - memory_size: u64, - - /// Function "allocations". They exist solely so pointers have something to point to, and - /// we can figure out what they point to. - functions: Vec>, - - /// Inverse map of `functions` so we don't allocate a new pointer every time we need one - function_alloc_cache: HashMap, AllocId>, - - /// Target machine data layout to emulate. - pub layout: &'a TargetDataLayout, - - /// A cache for basic byte allocations keyed by their contents. This is used to deduplicate - /// allocations for string and bytestring literals. - literal_alloc_cache: HashMap, AllocId>, - - /// To avoid having to pass flags to every single memory access, we have some global state saying whether - /// alignment checking is currently enforced for read and/or write accesses. - reads_are_aligned: Cell, - writes_are_aligned: Cell, - - /// The current stack frame. Used to check accesses against locks. - pub(super) cur_frame: usize, -} - -impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { - pub fn new(layout: &'a TargetDataLayout, max_memory: u64, data: M::MemoryData) -> Self { - Memory { - data, - alloc_map: HashMap::new(), - functions: Vec::new(), - function_alloc_cache: HashMap::new(), - next_alloc_id: 0, - layout, - memory_size: max_memory, - memory_usage: 0, - literal_alloc_cache: HashMap::new(), - reads_are_aligned: Cell::new(true), - writes_are_aligned: Cell::new(true), - cur_frame: usize::max_value(), - } - } - - pub fn allocations<'x>( - &'x self, - ) -> impl Iterator)> { - self.alloc_map.iter().map(|(&id, alloc)| { - (AllocIdKind::Runtime(id).into_alloc_id(), alloc) - }) - } - - pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> MemoryPointer { - if let Some(&alloc_id) = self.function_alloc_cache.get(&instance) { - return MemoryPointer::new(alloc_id, 0); - } - let id = self.functions.len(); - debug!("creating fn ptr: {}", id); - self.functions.push(instance); - let alloc_id = AllocIdKind::Function(id).into_alloc_id(); - self.function_alloc_cache.insert(instance, alloc_id); - MemoryPointer::new(alloc_id, 0) - } - - pub fn allocate_cached(&mut self, bytes: &[u8]) -> EvalResult<'tcx, MemoryPointer> { - if let Some(&alloc_id) = self.literal_alloc_cache.get(bytes) { - return Ok(MemoryPointer::new(alloc_id, 0)); - } - - let ptr = self.allocate( - bytes.len() as u64, - 1, - MemoryKind::UninitializedStatic, - )?; - self.write_bytes(ptr.into(), bytes)?; - self.mark_static_initalized( - ptr.alloc_id, - Mutability::Immutable, - )?; - self.literal_alloc_cache.insert( - bytes.to_vec(), - ptr.alloc_id, - ); - Ok(ptr) - } - - pub fn allocate( - &mut self, - size: u64, - align: u64, - kind: MemoryKind, - ) -> EvalResult<'tcx, MemoryPointer> { - assert_ne!(align, 0); - assert!(align.is_power_of_two()); - - if self.memory_size - self.memory_usage < size { - return err!(OutOfMemory { - allocation_size: size, - memory_size: self.memory_size, - memory_usage: self.memory_usage, - }); - } - self.memory_usage += size; - assert_eq!(size as usize as u64, size); - let alloc = Allocation { - bytes: vec![0; size as usize], - relocations: BTreeMap::new(), - undef_mask: UndefMask::new(size), - align, - kind, - mutable: Mutability::Mutable, - locks: RangeMap::new(), - }; - let id = self.next_alloc_id; - self.next_alloc_id += 1; - self.alloc_map.insert(id, alloc); - Ok(MemoryPointer::new( - AllocIdKind::Runtime(id).into_alloc_id(), - 0, - )) - } - - pub fn reallocate( - &mut self, - ptr: MemoryPointer, - old_size: u64, - old_align: u64, - new_size: u64, - new_align: u64, - kind: MemoryKind, - ) -> EvalResult<'tcx, MemoryPointer> { - use std::cmp::min; - - if ptr.offset != 0 { - return err!(ReallocateNonBasePtr); - } - if let Ok(alloc) = self.get(ptr.alloc_id) { - if alloc.kind != kind { - return err!(ReallocatedWrongMemoryKind( - format!("{:?}", alloc.kind), - format!("{:?}", kind), - )); - } - } - - // For simplicities' sake, we implement reallocate as "alloc, copy, dealloc" - let new_ptr = self.allocate(new_size, new_align, kind)?; - self.copy( - ptr.into(), - new_ptr.into(), - min(old_size, new_size), - min(old_align, new_align), - /*nonoverlapping*/ - true, - )?; - self.deallocate(ptr, Some((old_size, old_align)), kind)?; - - Ok(new_ptr) - } - - pub fn deallocate( - &mut self, - ptr: MemoryPointer, - size_and_align: Option<(u64, u64)>, - kind: MemoryKind, - ) -> EvalResult<'tcx> { - if ptr.offset != 0 { - return err!(DeallocateNonBasePtr); - } - - let alloc_id = match ptr.alloc_id.into_alloc_id_kind() { - AllocIdKind::Function(_) => { - return err!(DeallocatedWrongMemoryKind( - "function".to_string(), - format!("{:?}", kind), - )) - } - AllocIdKind::Runtime(id) => id, - }; - - let alloc = match self.alloc_map.remove(&alloc_id) { - Some(alloc) => alloc, - None => return err!(DoubleFree), - }; - - // It is okay for us to still holds locks on deallocation -- for example, we could store data we own - // in a local, and the local could be deallocated (from StorageDead) before the function returns. - // However, we should check *something*. For now, we make sure that there is no conflicting write - // lock by another frame. We *have* to permit deallocation if we hold a read lock. - // TODO: Figure out the exact rules here. - alloc - .check_locks( - Some(self.cur_frame), - 0, - alloc.bytes.len() as u64, - AccessKind::Read, - ) - .map_err(|lock| { - EvalErrorKind::DeallocatedLockedMemory { - ptr, - lock: lock.active, - } - })?; - - if alloc.kind != kind { - return err!(DeallocatedWrongMemoryKind( - format!("{:?}", alloc.kind), - format!("{:?}", kind), - )); - } - if let Some((size, align)) = size_and_align { - if size != alloc.bytes.len() as u64 || align != alloc.align { - return err!(IncorrectAllocationInformation); - } - } - - self.memory_usage -= alloc.bytes.len() as u64; - debug!("deallocated : {}", ptr.alloc_id); - - Ok(()) - } - - pub fn pointer_size(&self) -> u64 { - self.layout.pointer_size.bytes() - } - - pub fn endianess(&self) -> layout::Endian { - self.layout.endian - } - - /// Check that the pointer is aligned AND non-NULL. - pub fn check_align(&self, ptr: Pointer, align: u64, access: Option) -> EvalResult<'tcx> { - // Check non-NULL/Undef, extract offset - let (offset, alloc_align) = match ptr.into_inner_primval() { - PrimVal::Ptr(ptr) => { - let alloc = self.get(ptr.alloc_id)?; - (ptr.offset, alloc.align) - } - PrimVal::Bytes(bytes) => { - let v = ((bytes as u128) % (1 << self.pointer_size())) as u64; - if v == 0 { - return err!(InvalidNullPointerUsage); - } - (v, align) // the base address if the "integer allocation" is 0 and hence always aligned - } - PrimVal::Undef => return err!(ReadUndefBytes), - }; - // See if alignment checking is disabled - let enforce_alignment = match access { - Some(AccessKind::Read) => self.reads_are_aligned.get(), - Some(AccessKind::Write) => self.writes_are_aligned.get(), - None => true, - }; - if !enforce_alignment { - return Ok(()); - } - // Check alignment - if alloc_align < align { - return err!(AlignmentCheckFailed { - has: alloc_align, - required: align, - }); - } - if offset % align == 0 { - Ok(()) - } else { - err!(AlignmentCheckFailed { - has: offset % align, - required: align, - }) - } - } - - pub fn check_bounds(&self, ptr: MemoryPointer, access: bool) -> EvalResult<'tcx> { - let alloc = self.get(ptr.alloc_id)?; - let allocation_size = alloc.bytes.len() as u64; - if ptr.offset > allocation_size { - return err!(PointerOutOfBounds { - ptr, - access, - allocation_size, - }); - } - Ok(()) - } -} - -/// Locking -impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { - pub(crate) fn check_locks( - &self, - ptr: MemoryPointer, - len: u64, - access: AccessKind, - ) -> EvalResult<'tcx> { - if len == 0 { - return Ok(()); - } - let alloc = self.get(ptr.alloc_id)?; - let frame = self.cur_frame; - alloc - .check_locks(Some(frame), ptr.offset, len, access) - .map_err(|lock| { - EvalErrorKind::MemoryLockViolation { - ptr, - len, - frame, - access, - lock: lock.active, - }.into() - }) - } - - /// Acquire the lock for the given lifetime - pub(crate) fn acquire_lock( - &mut self, - ptr: MemoryPointer, - len: u64, - region: Option, - kind: AccessKind, - ) -> EvalResult<'tcx> { - let frame = self.cur_frame; - assert!(len > 0); - trace!( - "Frame {} acquiring {:?} lock at {:?}, size {} for region {:?}", - frame, - kind, - ptr, - len, - region - ); - self.check_bounds(ptr.offset(len, self.layout)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow) - let alloc = self.get_mut_unchecked(ptr.alloc_id)?; - - // Iterate over our range and acquire the lock. If the range is already split into pieces, - // we have to manipulate all of them. - let lifetime = DynamicLifetime { frame, region }; - for lock in alloc.locks.iter_mut(ptr.offset, len) { - if !lock.access_permitted(None, kind) { - return err!(MemoryAcquireConflict { - ptr, - len, - kind, - lock: lock.active.clone(), - }); - } - // See what we have to do - match (&mut lock.active, kind) { - (active @ &mut NoLock, AccessKind::Write) => { - *active = WriteLock(lifetime); - } - (active @ &mut NoLock, AccessKind::Read) => { - *active = ReadLock(vec![lifetime]); - } - (&mut ReadLock(ref mut lifetimes), AccessKind::Read) => { - lifetimes.push(lifetime); - } - _ => bug!("We already checked that there is no conflicting lock"), - } - } - Ok(()) - } - - /// Release or suspend a write lock of the given lifetime prematurely. - /// When releasing, if there is a read lock or someone else's write lock, that's an error. - /// If no lock is held, that's fine. This can happen when e.g. a local is initialized - /// from a constant, and then suspended. - /// When suspending, the same cases are fine; we just register an additional suspension. - pub(crate) fn suspend_write_lock( - &mut self, - ptr: MemoryPointer, - len: u64, - lock_path: &AbsLvalue<'tcx>, - suspend: Option, - ) -> EvalResult<'tcx> { - assert!(len > 0); - let cur_frame = self.cur_frame; - let alloc = self.get_mut_unchecked(ptr.alloc_id)?; - - 'locks: for lock in alloc.locks.iter_mut(ptr.offset, len) { - let is_our_lock = match lock.active { - WriteLock(lft) => - // Double-check that we are holding the lock. - // (Due to subtyping, checking the region would not make any sense.) - lft.frame == cur_frame, - ReadLock(_) | NoLock => false, - }; - if is_our_lock { - trace!("Releasing {:?}", lock.active); - // Disable the lock - lock.active = NoLock; - } else { - trace!( - "Not touching {:?} as it is not our lock", - lock.active, - ); - } - // Check if we want to register a suspension - if let Some(suspend_region) = suspend { - let lock_id = WriteLockId { - frame: cur_frame, - path: lock_path.clone(), - }; - trace!("Adding suspension to {:?}", lock_id); - let mut new_suspension = false; - lock.suspended - .entry(lock_id) - // Remember whether we added a new suspension or not - .or_insert_with(|| { new_suspension = true; Vec::new() }) - .push(suspend_region); - // If the suspension is new, we should have owned this. - // If there already was a suspension, we should NOT have owned this. - if new_suspension == is_our_lock { - // All is well - continue 'locks; - } - } else { - if !is_our_lock { - // All is well. - continue 'locks; - } - } - // If we get here, releasing this is an error except for NoLock. - if lock.active != NoLock { - return err!(InvalidMemoryLockRelease { - ptr, - len, - frame: cur_frame, - lock: lock.active.clone(), - }); - } - } - - Ok(()) - } - - /// Release a suspension from the write lock. If this is the last suspension or if there is no suspension, acquire the lock. - pub(crate) fn recover_write_lock( - &mut self, - ptr: MemoryPointer, - len: u64, - lock_path: &AbsLvalue<'tcx>, - lock_region: Option, - suspended_region: region::Scope, - ) -> EvalResult<'tcx> { - assert!(len > 0); - let cur_frame = self.cur_frame; - let lock_id = WriteLockId { - frame: cur_frame, - path: lock_path.clone(), - }; - let alloc = self.get_mut_unchecked(ptr.alloc_id)?; - - for lock in alloc.locks.iter_mut(ptr.offset, len) { - // Check if we have a suspension here - let (got_the_lock, remove_suspension) = match lock.suspended.get_mut(&lock_id) { - None => { - trace!("No suspension around, we can just acquire"); - (true, false) - } - Some(suspensions) => { - trace!("Found suspension of {:?}, removing it", lock_id); - // That's us! Remove suspension (it should be in there). The same suspension can - // occur multiple times (when there are multiple shared borrows of this that have the same - // lifetime); only remove one of them. - let idx = match suspensions.iter().enumerate().find(|&(_, re)| re == &suspended_region) { - None => // TODO: Can the user trigger this? - bug!("We have this lock suspended, but not for the given region."), - Some((idx, _)) => idx - }; - suspensions.remove(idx); - let got_lock = suspensions.is_empty(); - if got_lock { - trace!("All suspensions are gone, we can have the lock again"); - } - (got_lock, got_lock) - } - }; - if remove_suspension { - // with NLL, we could do that up in the match above... - assert!(got_the_lock); - lock.suspended.remove(&lock_id); - } - if got_the_lock { - match lock.active { - ref mut active @ NoLock => { - *active = WriteLock( - DynamicLifetime { - frame: cur_frame, - region: lock_region, - } - ); - } - _ => { - return err!(MemoryAcquireConflict { - ptr, - len, - kind: AccessKind::Write, - lock: lock.active.clone(), - }) - } - } - } - } - - Ok(()) - } - - pub(crate) fn locks_lifetime_ended(&mut self, ending_region: Option) { - let cur_frame = self.cur_frame; - trace!( - "Releasing frame {} locks that expire at {:?}", - cur_frame, - ending_region - ); - let has_ended = |lifetime: &DynamicLifetime| -> bool { - if lifetime.frame != cur_frame { - return false; - } - match ending_region { - None => true, // When a function ends, we end *all* its locks. It's okay for a function to still have lifetime-related locks - // when it returns, that can happen e.g. with NLL when a lifetime can, but does not have to, extend beyond the - // end of a function. Same for a function still having recoveries. - Some(ending_region) => lifetime.region == Some(ending_region), - } - }; - - for alloc in self.alloc_map.values_mut() { - for lock in alloc.locks.iter_mut_all() { - // Delete everything that ends now -- i.e., keep only all the other lifetimes. - let lock_ended = match lock.active { - WriteLock(ref lft) => has_ended(lft), - ReadLock(ref mut lfts) => { - lfts.retain(|lft| !has_ended(lft)); - lfts.is_empty() - } - NoLock => false, - }; - if lock_ended { - lock.active = NoLock; - } - // Also clean up suspended write locks when the function returns - if ending_region.is_none() { - lock.suspended.retain(|id, _suspensions| id.frame != cur_frame); - } - } - // Clean up the map - alloc.locks.retain(|lock| match lock.active { - NoLock => lock.suspended.len() > 0, - _ => true, - }); - } - } -} - -/// Allocation accessors -impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { - pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation<'tcx, M::MemoryKinds>> { - match id.into_alloc_id_kind() { - AllocIdKind::Function(_) => err!(DerefFunctionPointer), - AllocIdKind::Runtime(id) => { - match self.alloc_map.get(&id) { - Some(alloc) => Ok(alloc), - None => err!(DanglingPointerDeref), - } - } - } - } - - fn get_mut_unchecked( - &mut self, - id: AllocId, - ) -> EvalResult<'tcx, &mut Allocation<'tcx, M::MemoryKinds>> { - match id.into_alloc_id_kind() { - AllocIdKind::Function(_) => err!(DerefFunctionPointer), - AllocIdKind::Runtime(id) => { - match self.alloc_map.get_mut(&id) { - Some(alloc) => Ok(alloc), - None => err!(DanglingPointerDeref), - } - } - } - } - - fn get_mut(&mut self, id: AllocId) -> EvalResult<'tcx, &mut Allocation<'tcx, M::MemoryKinds>> { - let alloc = self.get_mut_unchecked(id)?; - if alloc.mutable == Mutability::Mutable { - Ok(alloc) - } else { - err!(ModifiedConstantMemory) - } - } - - pub fn get_fn(&self, ptr: MemoryPointer) -> EvalResult<'tcx, Instance<'tcx>> { - if ptr.offset != 0 { - return err!(InvalidFunctionPointer); - } - debug!("reading fn ptr: {}", ptr.alloc_id); - match ptr.alloc_id.into_alloc_id_kind() { - AllocIdKind::Function(id) => Ok(self.functions[id]), - AllocIdKind::Runtime(_) => err!(ExecuteMemory), - } - } - - /// For debugging, print an allocation and all allocations it points to, recursively. - pub fn dump_alloc(&self, id: AllocId) { - self.dump_allocs(vec![id]); - } - - /// For debugging, print a list of allocations and all allocations they point to, recursively. - pub fn dump_allocs(&self, mut allocs: Vec) { - use std::fmt::Write; - allocs.sort(); - allocs.dedup(); - let mut allocs_to_print = VecDeque::from(allocs); - let mut allocs_seen = HashSet::new(); - - while let Some(id) = allocs_to_print.pop_front() { - let mut msg = format!("Alloc {:<5} ", format!("{}:", id)); - let prefix_len = msg.len(); - let mut relocations = vec![]; - - let alloc = match id.into_alloc_id_kind() { - AllocIdKind::Function(id) => { - trace!("{} {}", msg, self.functions[id]); - continue; - } - AllocIdKind::Runtime(id) => { - match self.alloc_map.get(&id) { - Some(a) => a, - None => { - trace!("{} (deallocated)", msg); - continue; - } - } - } - }; - - for i in 0..(alloc.bytes.len() as u64) { - if let Some(&target_id) = alloc.relocations.get(&i) { - if allocs_seen.insert(target_id) { - allocs_to_print.push_back(target_id); - } - relocations.push((i, target_id)); - } - if alloc.undef_mask.is_range_defined(i, i + 1) { - // this `as usize` is fine, since `i` came from a `usize` - write!(msg, "{:02x} ", alloc.bytes[i as usize]).unwrap(); - } else { - msg.push_str("__ "); - } - } - - let immutable = match (alloc.kind, alloc.mutable) { - (MemoryKind::UninitializedStatic, _) => { - " (static in the process of initialization)".to_owned() - } - (MemoryKind::Static, Mutability::Mutable) => " (static mut)".to_owned(), - (MemoryKind::Static, Mutability::Immutable) => " (immutable)".to_owned(), - (MemoryKind::Machine(m), _) => format!(" ({:?})", m), - (MemoryKind::Stack, _) => " (stack)".to_owned(), - }; - trace!( - "{}({} bytes, alignment {}){}", - msg, - alloc.bytes.len(), - alloc.align, - immutable - ); - - if !relocations.is_empty() { - msg.clear(); - write!(msg, "{:1$}", "", prefix_len).unwrap(); // Print spaces. - let mut pos = 0; - let relocation_width = (self.pointer_size() - 1) * 3; - for (i, target_id) in relocations { - // this `as usize` is fine, since we can't print more chars than `usize::MAX` - write!(msg, "{:1$}", "", ((i - pos) * 3) as usize).unwrap(); - let target = format!("({})", target_id); - // this `as usize` is fine, since we can't print more chars than `usize::MAX` - write!(msg, "└{0:─^1$}┘ ", target, relocation_width as usize).unwrap(); - pos = i + self.pointer_size(); - } - trace!("{}", msg); - } - } - } - - pub fn leak_report(&self) -> usize { - trace!("### LEAK REPORT ###"); - let leaks: Vec<_> = self.alloc_map - .iter() - .filter_map(|(&key, val)| if val.kind != MemoryKind::Static { - Some(AllocIdKind::Runtime(key).into_alloc_id()) - } else { - None - }) - .collect(); - let n = leaks.len(); - self.dump_allocs(leaks); - n - } -} - -/// Byte accessors -impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { - fn get_bytes_unchecked( - &self, - ptr: MemoryPointer, - size: u64, - align: u64, - ) -> EvalResult<'tcx, &[u8]> { - // Zero-sized accesses can use dangling pointers, but they still have to be aligned and non-NULL - self.check_align(ptr.into(), align, Some(AccessKind::Read))?; - if size == 0 { - return Ok(&[]); - } - self.check_locks(ptr, size, AccessKind::Read)?; - self.check_bounds(ptr.offset(size, self)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow) - let alloc = self.get(ptr.alloc_id)?; - assert_eq!(ptr.offset as usize as u64, ptr.offset); - assert_eq!(size as usize as u64, size); - let offset = ptr.offset as usize; - Ok(&alloc.bytes[offset..offset + size as usize]) - } - - fn get_bytes_unchecked_mut( - &mut self, - ptr: MemoryPointer, - size: u64, - align: u64, - ) -> EvalResult<'tcx, &mut [u8]> { - // Zero-sized accesses can use dangling pointers, but they still have to be aligned and non-NULL - self.check_align(ptr.into(), align, Some(AccessKind::Write))?; - if size == 0 { - return Ok(&mut []); - } - self.check_locks(ptr, size, AccessKind::Write)?; - self.check_bounds(ptr.offset(size, self.layout)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow) - let alloc = self.get_mut(ptr.alloc_id)?; - assert_eq!(ptr.offset as usize as u64, ptr.offset); - assert_eq!(size as usize as u64, size); - let offset = ptr.offset as usize; - Ok(&mut alloc.bytes[offset..offset + size as usize]) - } - - fn get_bytes(&self, ptr: MemoryPointer, size: u64, align: u64) -> EvalResult<'tcx, &[u8]> { - assert_ne!(size, 0); - if self.relocations(ptr, size)?.count() != 0 { - return err!(ReadPointerAsBytes); - } - self.check_defined(ptr, size)?; - self.get_bytes_unchecked(ptr, size, align) - } - - fn get_bytes_mut( - &mut self, - ptr: MemoryPointer, - size: u64, - align: u64, - ) -> EvalResult<'tcx, &mut [u8]> { - assert_ne!(size, 0); - self.clear_relocations(ptr, size)?; - self.mark_definedness(ptr.into(), size, true)?; - self.get_bytes_unchecked_mut(ptr, size, align) - } -} - -/// Reading and writing -impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { - /// mark an allocation pointed to by a static as static and initialized - fn mark_inner_allocation_initialized( - &mut self, - alloc: AllocId, - mutability: Mutability, - ) -> EvalResult<'tcx> { - // relocations into other statics are not "inner allocations" - if self.get(alloc).ok().map_or(false, |alloc| { - alloc.kind != MemoryKind::UninitializedStatic - }) - { - self.mark_static_initalized(alloc, mutability)?; - } - Ok(()) - } - - /// mark an allocation as static and initialized, either mutable or not - pub fn mark_static_initalized( - &mut self, - alloc_id: AllocId, - mutability: Mutability, - ) -> EvalResult<'tcx> { - trace!( - "mark_static_initalized {:?}, mutability: {:?}", - alloc_id, - mutability - ); - // do not use `self.get_mut(alloc_id)` here, because we might have already marked a - // sub-element or have circular pointers (e.g. `Rc`-cycles) - let alloc_id = match alloc_id.into_alloc_id_kind() { - AllocIdKind::Function(_) => return Ok(()), - AllocIdKind::Runtime(id) => id, - }; - let relocations = match self.alloc_map.get_mut(&alloc_id) { - Some(&mut Allocation { - ref mut relocations, - ref mut kind, - ref mut mutable, - .. - }) => { - match *kind { - // const eval results can refer to "locals". - // E.g. `const Foo: &u32 = &1;` refers to the temp local that stores the `1` - MemoryKind::Stack | - // The entire point of this function - MemoryKind::UninitializedStatic => {}, - MemoryKind::Machine(m) => M::mark_static_initialized(m)?, - MemoryKind::Static => { - trace!("mark_static_initalized: skipping already initialized static referred to by static currently being initialized"); - return Ok(()); - }, - } - *kind = MemoryKind::Static; - *mutable = mutability; - // take out the relocations vector to free the borrow on self, so we can call - // mark recursively - mem::replace(relocations, Default::default()) - } - None => return err!(DanglingPointerDeref), - }; - // recurse into inner allocations - for &alloc in relocations.values() { - self.mark_inner_allocation_initialized(alloc, mutability)?; - } - // put back the relocations - self.alloc_map - .get_mut(&alloc_id) - .expect("checked above") - .relocations = relocations; - Ok(()) - } - - pub fn copy( - &mut self, - src: Pointer, - dest: Pointer, - size: u64, - align: u64, - nonoverlapping: bool, - ) -> EvalResult<'tcx> { - // Empty accesses don't need to be valid pointers, but they should still be aligned - self.check_align(src, align, Some(AccessKind::Read))?; - self.check_align(dest, align, Some(AccessKind::Write))?; - if size == 0 { - return Ok(()); - } - let src = src.to_ptr()?; - let dest = dest.to_ptr()?; - self.check_relocation_edges(src, size)?; - - // first copy the relocations to a temporary buffer, because - // `get_bytes_mut` will clear the relocations, which is correct, - // since we don't want to keep any relocations at the target. - - let relocations: Vec<_> = self.relocations(src, size)? - .map(|(&offset, &alloc_id)| { - // Update relocation offsets for the new positions in the destination allocation. - (offset + dest.offset - src.offset, alloc_id) - }) - .collect(); - - let src_bytes = self.get_bytes_unchecked(src, size, align)?.as_ptr(); - let dest_bytes = self.get_bytes_mut(dest, size, align)?.as_mut_ptr(); - - // SAFE: The above indexing would have panicked if there weren't at least `size` bytes - // behind `src` and `dest`. Also, we use the overlapping-safe `ptr::copy` if `src` and - // `dest` could possibly overlap. - unsafe { - assert_eq!(size as usize as u64, size); - if src.alloc_id == dest.alloc_id { - if nonoverlapping { - if (src.offset <= dest.offset && src.offset + size > dest.offset) || - (dest.offset <= src.offset && dest.offset + size > src.offset) - { - return err!(Intrinsic( - format!("copy_nonoverlapping called on overlapping ranges"), - )); - } - } - ptr::copy(src_bytes, dest_bytes, size as usize); - } else { - ptr::copy_nonoverlapping(src_bytes, dest_bytes, size as usize); - } - } - - self.copy_undef_mask(src, dest, size)?; - // copy back the relocations - self.get_mut(dest.alloc_id)?.relocations.extend(relocations); - - Ok(()) - } - - pub fn read_c_str(&self, ptr: MemoryPointer) -> EvalResult<'tcx, &[u8]> { - let alloc = self.get(ptr.alloc_id)?; - assert_eq!(ptr.offset as usize as u64, ptr.offset); - let offset = ptr.offset as usize; - match alloc.bytes[offset..].iter().position(|&c| c == 0) { - Some(size) => { - if self.relocations(ptr, (size + 1) as u64)?.count() != 0 { - return err!(ReadPointerAsBytes); - } - self.check_defined(ptr, (size + 1) as u64)?; - self.check_locks(ptr, (size + 1) as u64, AccessKind::Read)?; - Ok(&alloc.bytes[offset..offset + size]) - } - None => err!(UnterminatedCString(ptr)), - } - } - - pub fn read_bytes(&self, ptr: Pointer, size: u64) -> EvalResult<'tcx, &[u8]> { - // Empty accesses don't need to be valid pointers, but they should still be non-NULL - self.check_align(ptr, 1, Some(AccessKind::Read))?; - if size == 0 { - return Ok(&[]); - } - self.get_bytes(ptr.to_ptr()?, size, 1) - } - - pub fn write_bytes(&mut self, ptr: Pointer, src: &[u8]) -> EvalResult<'tcx> { - // Empty accesses don't need to be valid pointers, but they should still be non-NULL - self.check_align(ptr, 1, Some(AccessKind::Write))?; - if src.is_empty() { - return Ok(()); - } - let bytes = self.get_bytes_mut(ptr.to_ptr()?, src.len() as u64, 1)?; - bytes.clone_from_slice(src); - Ok(()) - } - - pub fn write_repeat(&mut self, ptr: Pointer, val: u8, count: u64) -> EvalResult<'tcx> { - // Empty accesses don't need to be valid pointers, but they should still be non-NULL - self.check_align(ptr, 1, Some(AccessKind::Write))?; - if count == 0 { - return Ok(()); - } - let bytes = self.get_bytes_mut(ptr.to_ptr()?, count, 1)?; - for b in bytes { - *b = val; - } - Ok(()) - } - - pub fn read_primval(&self, ptr: MemoryPointer, size: u64, signed: bool) -> EvalResult<'tcx, PrimVal> { - self.check_relocation_edges(ptr, size)?; // Make sure we don't read part of a pointer as a pointer - let endianess = self.endianess(); - let bytes = self.get_bytes_unchecked(ptr, size, self.int_align(size))?; - // Undef check happens *after* we established that the alignment is correct. - // We must not return Ok() for unaligned pointers! - if self.check_defined(ptr, size).is_err() { - return Ok(PrimVal::Undef.into()); - } - // Now we do the actual reading - let bytes = if signed { - read_target_int(endianess, bytes).unwrap() as u128 - } else { - read_target_uint(endianess, bytes).unwrap() - }; - // See if we got a pointer - if size != self.pointer_size() { - if self.relocations(ptr, size)?.count() != 0 { - return err!(ReadPointerAsBytes); - } - } else { - let alloc = self.get(ptr.alloc_id)?; - match alloc.relocations.get(&ptr.offset) { - Some(&alloc_id) => return Ok(PrimVal::Ptr(MemoryPointer::new(alloc_id, bytes as u64))), - None => {}, - } - } - // We don't. Just return the bytes. - Ok(PrimVal::Bytes(bytes)) - } - - pub fn read_ptr_sized_unsigned(&self, ptr: MemoryPointer) -> EvalResult<'tcx, PrimVal> { - self.read_primval(ptr, self.pointer_size(), false) - } - - pub fn write_primval(&mut self, ptr: MemoryPointer, val: PrimVal, size: u64, signed: bool) -> EvalResult<'tcx> { - let endianess = self.endianess(); - - let bytes = match val { - PrimVal::Ptr(val) => { - assert_eq!(size, self.pointer_size()); - val.offset as u128 - } - - PrimVal::Bytes(bytes) => { - // We need to mask here, or the byteorder crate can die when given a u64 larger - // than fits in an integer of the requested size. - let mask = match size { - 1 => !0u8 as u128, - 2 => !0u16 as u128, - 4 => !0u32 as u128, - 8 => !0u64 as u128, - 16 => !0, - n => bug!("unexpected PrimVal::Bytes size: {}", n), - }; - bytes & mask - } - - PrimVal::Undef => { - self.mark_definedness(PrimVal::Ptr(ptr).into(), size, false)?; - return Ok(()); - } - }; - - { - let align = self.int_align(size); - let dst = self.get_bytes_mut(ptr, size, align)?; - if signed { - write_target_int(endianess, dst, bytes as i128).unwrap(); - } else { - write_target_uint(endianess, dst, bytes).unwrap(); - } - } - - // See if we have to also write a relocation - match val { - PrimVal::Ptr(val) => { - self.get_mut(ptr.alloc_id)?.relocations.insert( - ptr.offset, - val.alloc_id, - ); - } - _ => {} - } - - Ok(()) - } - - pub fn write_ptr_sized_unsigned(&mut self, ptr: MemoryPointer, val: PrimVal) -> EvalResult<'tcx> { - let ptr_size = self.pointer_size(); - self.write_primval(ptr, val, ptr_size, false) - } - - fn int_align(&self, size: u64) -> u64 { - // We assume pointer-sized integers have the same alignment as pointers. - // We also assume signed and unsigned integers of the same size have the same alignment. - match size { - 1 => self.layout.i8_align.abi(), - 2 => self.layout.i16_align.abi(), - 4 => self.layout.i32_align.abi(), - 8 => self.layout.i64_align.abi(), - 16 => self.layout.i128_align.abi(), - _ => bug!("bad integer size: {}", size), - } - } -} - -/// Relocations -impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { - fn relocations( - &self, - ptr: MemoryPointer, - size: u64, - ) -> EvalResult<'tcx, btree_map::Range> { - let start = ptr.offset.saturating_sub(self.pointer_size() - 1); - let end = ptr.offset + size; - Ok(self.get(ptr.alloc_id)?.relocations.range(start..end)) - } - - fn clear_relocations(&mut self, ptr: MemoryPointer, size: u64) -> EvalResult<'tcx> { - // Find all relocations overlapping the given range. - let keys: Vec<_> = self.relocations(ptr, size)?.map(|(&k, _)| k).collect(); - if keys.is_empty() { - return Ok(()); - } - - // Find the start and end of the given range and its outermost relocations. - let start = ptr.offset; - let end = start + size; - let first = *keys.first().unwrap(); - let last = *keys.last().unwrap() + self.pointer_size(); - - let alloc = self.get_mut(ptr.alloc_id)?; - - // Mark parts of the outermost relocations as undefined if they partially fall outside the - // given range. - if first < start { - alloc.undef_mask.set_range(first, start, false); - } - if last > end { - alloc.undef_mask.set_range(end, last, false); - } - - // Forget all the relocations. - for k in keys { - alloc.relocations.remove(&k); - } - - Ok(()) - } - - fn check_relocation_edges(&self, ptr: MemoryPointer, size: u64) -> EvalResult<'tcx> { - let overlapping_start = self.relocations(ptr, 0)?.count(); - let overlapping_end = self.relocations(ptr.offset(size, self.layout)?, 0)?.count(); - if overlapping_start + overlapping_end != 0 { - return err!(ReadPointerAsBytes); - } - Ok(()) - } -} - -/// Undefined bytes -impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { - // FIXME(solson): This is a very naive, slow version. - fn copy_undef_mask( - &mut self, - src: MemoryPointer, - dest: MemoryPointer, - size: u64, - ) -> EvalResult<'tcx> { - // The bits have to be saved locally before writing to dest in case src and dest overlap. - assert_eq!(size as usize as u64, size); - let mut v = Vec::with_capacity(size as usize); - for i in 0..size { - let defined = self.get(src.alloc_id)?.undef_mask.get(src.offset + i); - v.push(defined); - } - for (i, defined) in v.into_iter().enumerate() { - self.get_mut(dest.alloc_id)?.undef_mask.set( - dest.offset + - i as u64, - defined, - ); - } - Ok(()) - } - - fn check_defined(&self, ptr: MemoryPointer, size: u64) -> EvalResult<'tcx> { - let alloc = self.get(ptr.alloc_id)?; - if !alloc.undef_mask.is_range_defined( - ptr.offset, - ptr.offset + size, - ) - { - return err!(ReadUndefBytes); - } - Ok(()) - } - - pub fn mark_definedness( - &mut self, - ptr: Pointer, - size: u64, - new_state: bool, - ) -> EvalResult<'tcx> { - if size == 0 { - return Ok(()); - } - let ptr = ptr.to_ptr()?; - let alloc = self.get_mut(ptr.alloc_id)?; - alloc.undef_mask.set_range( - ptr.offset, - ptr.offset + size, - new_state, - ); - Ok(()) - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Methods to access integers in the target endianess -//////////////////////////////////////////////////////////////////////////////// - -fn write_target_uint( - endianess: layout::Endian, - mut target: &mut [u8], - data: u128, -) -> Result<(), io::Error> { - let len = target.len(); - match endianess { - layout::Endian::Little => target.write_uint128::(data, len), - layout::Endian::Big => target.write_uint128::(data, len), - } -} -fn write_target_int( - endianess: layout::Endian, - mut target: &mut [u8], - data: i128, -) -> Result<(), io::Error> { - let len = target.len(); - match endianess { - layout::Endian::Little => target.write_int128::(data, len), - layout::Endian::Big => target.write_int128::(data, len), - } -} - -fn read_target_uint(endianess: layout::Endian, mut source: &[u8]) -> Result { - match endianess { - layout::Endian::Little => source.read_uint128::(source.len()), - layout::Endian::Big => source.read_uint128::(source.len()), - } -} - -fn read_target_int(endianess: layout::Endian, mut source: &[u8]) -> Result { - match endianess { - layout::Endian::Little => source.read_int128::(source.len()), - layout::Endian::Big => source.read_int128::(source.len()), - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Undefined byte tracking -//////////////////////////////////////////////////////////////////////////////// - -type Block = u64; -const BLOCK_SIZE: u64 = 64; - -#[derive(Clone, Debug)] -pub struct UndefMask { - blocks: Vec, - len: u64, -} - -impl UndefMask { - fn new(size: u64) -> Self { - let mut m = UndefMask { - blocks: vec![], - len: 0, - }; - m.grow(size, false); - m - } - - /// Check whether the range `start..end` (end-exclusive) is entirely defined. - pub fn is_range_defined(&self, start: u64, end: u64) -> bool { - if end > self.len { - return false; - } - for i in start..end { - if !self.get(i) { - return false; - } - } - true - } - - fn set_range(&mut self, start: u64, end: u64, new_state: bool) { - let len = self.len; - if end > len { - self.grow(end - len, new_state); - } - self.set_range_inbounds(start, end, new_state); - } - - fn set_range_inbounds(&mut self, start: u64, end: u64, new_state: bool) { - for i in start..end { - self.set(i, new_state); - } - } - - fn get(&self, i: u64) -> bool { - let (block, bit) = bit_index(i); - (self.blocks[block] & 1 << bit) != 0 - } - - fn set(&mut self, i: u64, new_state: bool) { - let (block, bit) = bit_index(i); - if new_state { - self.blocks[block] |= 1 << bit; - } else { - self.blocks[block] &= !(1 << bit); - } - } - - fn grow(&mut self, amount: u64, new_state: bool) { - let unused_trailing_bits = self.blocks.len() as u64 * BLOCK_SIZE - self.len; - if amount > unused_trailing_bits { - let additional_blocks = amount / BLOCK_SIZE + 1; - assert_eq!(additional_blocks as usize as u64, additional_blocks); - self.blocks.extend( - iter::repeat(0).take(additional_blocks as usize), - ); - } - let start = self.len; - self.len += amount; - self.set_range_inbounds(start, start + amount, new_state); - } -} - -fn bit_index(bits: u64) -> (usize, usize) { - let a = bits / BLOCK_SIZE; - let b = bits % BLOCK_SIZE; - assert_eq!(a as usize as u64, a); - assert_eq!(b as usize as u64, b); - (a as usize, b as usize) -} - -//////////////////////////////////////////////////////////////////////////////// -// Unaligned accesses -//////////////////////////////////////////////////////////////////////////////// - -pub trait HasMemory<'a, 'tcx, M: Machine<'tcx>> { - fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx, M>; - fn memory(&self) -> &Memory<'a, 'tcx, M>; - - // These are not supposed to be overriden. - fn read_maybe_aligned(&self, aligned: bool, f: F) -> EvalResult<'tcx, T> - where - F: FnOnce(&Self) -> EvalResult<'tcx, T>, - { - let old = self.memory().reads_are_aligned.get(); - // Do alignment checking if *all* nested calls say it has to be aligned. - self.memory().reads_are_aligned.set(old && aligned); - let t = f(self); - self.memory().reads_are_aligned.set(old); - t - } - - fn read_maybe_aligned_mut(&mut self, aligned: bool, f: F) -> EvalResult<'tcx, T> - where - F: FnOnce(&mut Self) -> EvalResult<'tcx, T>, - { - let old = self.memory().reads_are_aligned.get(); - // Do alignment checking if *all* nested calls say it has to be aligned. - self.memory().reads_are_aligned.set(old && aligned); - let t = f(self); - self.memory().reads_are_aligned.set(old); - t - } - - fn write_maybe_aligned_mut(&mut self, aligned: bool, f: F) -> EvalResult<'tcx, T> - where - F: FnOnce(&mut Self) -> EvalResult<'tcx, T>, - { - let old = self.memory().writes_are_aligned.get(); - // Do alignment checking if *all* nested calls say it has to be aligned. - self.memory().writes_are_aligned.set(old && aligned); - let t = f(self); - self.memory().writes_are_aligned.set(old); - t - } -} - -impl<'a, 'tcx, M: Machine<'tcx>> HasMemory<'a, 'tcx, M> for Memory<'a, 'tcx, M> { - #[inline] - fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx, M> { - self - } - - #[inline] - fn memory(&self) -> &Memory<'a, 'tcx, M> { - self - } -} - -impl<'a, 'tcx, M: Machine<'tcx>> HasMemory<'a, 'tcx, M> for EvalContext<'a, 'tcx, M> { - #[inline] - fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx, M> { - &mut self.memory - } - - #[inline] - fn memory(&self) -> &Memory<'a, 'tcx, M> { - &self.memory - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Pointer arithmetic -//////////////////////////////////////////////////////////////////////////////// - -pub trait PointerArithmetic: layout::HasDataLayout { - // These are not supposed to be overriden. - - //// Trunace the given value to the pointer size; also return whether there was an overflow - fn truncate_to_ptr(self, val: u128) -> (u64, bool) { - let max_ptr_plus_1 = 1u128 << self.data_layout().pointer_size.bits(); - ((val % max_ptr_plus_1) as u64, val >= max_ptr_plus_1) - } - - // Overflow checking only works properly on the range from -u64 to +u64. - fn overflowing_signed_offset(self, val: u64, i: i128) -> (u64, bool) { - // FIXME: is it possible to over/underflow here? - if i < 0 { - // trickery to ensure that i64::min_value() works fine - // this formula only works for true negative values, it panics for zero! - let n = u64::max_value() - (i as u64) + 1; - val.overflowing_sub(n) - } else { - self.overflowing_offset(val, i as u64) - } - } - - fn overflowing_offset(self, val: u64, i: u64) -> (u64, bool) { - let (res, over1) = val.overflowing_add(i); - let (res, over2) = self.truncate_to_ptr(res as u128); - (res, over1 || over2) - } - - fn signed_offset<'tcx>(self, val: u64, i: i64) -> EvalResult<'tcx, u64> { - let (res, over) = self.overflowing_signed_offset(val, i as i128); - if over { err!(OverflowingMath) } else { Ok(res) } - } - - fn offset<'tcx>(self, val: u64, i: u64) -> EvalResult<'tcx, u64> { - let (res, over) = self.overflowing_offset(val, i); - if over { err!(OverflowingMath) } else { Ok(res) } - } - - fn wrapping_signed_offset(self, val: u64, i: i64) -> u64 { - self.overflowing_signed_offset(val, i as i128).0 - } -} - -impl PointerArithmetic for T {} - -impl<'a, 'tcx, M: Machine<'tcx>> layout::HasDataLayout for &'a Memory<'a, 'tcx, M> { - #[inline] - fn data_layout(&self) -> &TargetDataLayout { - self.layout - } -} -impl<'a, 'tcx, M: Machine<'tcx>> layout::HasDataLayout for &'a EvalContext<'a, 'tcx, M> { - #[inline] - fn data_layout(&self) -> &TargetDataLayout { - self.memory().layout - } -} - -impl<'c, 'b, 'a, 'tcx, M: Machine<'tcx>> layout::HasDataLayout - for &'c &'b mut EvalContext<'a, 'tcx, M> { - #[inline] - fn data_layout(&self) -> &TargetDataLayout { - self.memory().layout - } -} diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs deleted file mode 100644 index 08837c4fb6d7..000000000000 --- a/src/librustc_mir/interpret/mod.rs +++ /dev/null @@ -1,42 +0,0 @@ -//! An interpreter for MIR used in CTFE and by miri - -#[macro_export] -macro_rules! err { - ($($tt:tt)*) => { Err($crate::interpret::EvalErrorKind::$($tt)*.into()) }; -} - -mod cast; -mod const_eval; -mod error; -mod eval_context; -mod lvalue; -mod validation; -mod machine; -mod memory; -mod operator; -mod range_map; -mod step; -mod terminator; -mod traits; -mod value; - -pub use self::error::{EvalError, EvalResult, EvalErrorKind}; - -pub use self::eval_context::{EvalContext, Frame, ResourceLimits, StackPopCleanup, DynamicLifetime, - TyAndPacked, PtrAndAlign, ValTy}; - -pub use self::lvalue::{Lvalue, LvalueExtra, GlobalId}; - -pub use self::memory::{AllocId, Memory, MemoryPointer, MemoryKind, HasMemory, AccessKind, AllocIdKind}; - -use self::memory::{PointerArithmetic, Lock}; - -use self::range_map::RangeMap; - -pub use self::value::{PrimVal, PrimValKind, Value, Pointer}; - -pub use self::const_eval::{eval_body_as_integer, eval_body_as_primval}; - -pub use self::machine::Machine; - -pub use self::validation::{ValidationQuery, AbsLvalue}; diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs deleted file mode 100644 index 7fe4691ffff0..000000000000 --- a/src/librustc_mir/interpret/operator.rs +++ /dev/null @@ -1,268 +0,0 @@ -use rustc::mir; -use rustc::ty::Ty; -use rustc_const_math::ConstFloat; -use syntax::ast::FloatTy; -use std::cmp::Ordering; - -use super::{EvalResult, EvalContext, Lvalue, Machine, ValTy}; - -use super::value::{PrimVal, PrimValKind, Value, bytes_to_f32, bytes_to_f64, f32_to_bytes, - f64_to_bytes}; - -impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { - fn binop_with_overflow( - &mut self, - op: mir::BinOp, - left: ValTy<'tcx>, - right: ValTy<'tcx>, - ) -> EvalResult<'tcx, (PrimVal, bool)> { - let left_val = self.value_to_primval(left)?; - let right_val = self.value_to_primval(right)?; - self.binary_op(op, left_val, left.ty, right_val, right.ty) - } - - /// Applies the binary operation `op` to the two operands and writes a tuple of the result - /// and a boolean signifying the potential overflow to the destination. - pub fn intrinsic_with_overflow( - &mut self, - op: mir::BinOp, - left: ValTy<'tcx>, - right: ValTy<'tcx>, - dest: Lvalue, - dest_ty: Ty<'tcx>, - ) -> EvalResult<'tcx> { - let (val, overflowed) = self.binop_with_overflow(op, left, right)?; - let val = Value::ByValPair(val, PrimVal::from_bool(overflowed)); - let valty = ValTy { - value: val, - ty: dest_ty, - }; - self.write_value(valty, dest) - } - - /// Applies the binary operation `op` to the arguments and writes the result to the - /// destination. Returns `true` if the operation overflowed. - pub fn intrinsic_overflowing( - &mut self, - op: mir::BinOp, - left: ValTy<'tcx>, - right: ValTy<'tcx>, - dest: Lvalue, - dest_ty: Ty<'tcx>, - ) -> EvalResult<'tcx, bool> { - let (val, overflowed) = self.binop_with_overflow(op, left, right)?; - self.write_primval(dest, val, dest_ty)?; - Ok(overflowed) - } -} - -macro_rules! overflow { - ($op:ident, $l:expr, $r:expr) => ({ - let (val, overflowed) = $l.$op($r); - let primval = PrimVal::Bytes(val as u128); - Ok((primval, overflowed)) - }) -} - -macro_rules! int_arithmetic { - ($kind:expr, $int_op:ident, $l:expr, $r:expr) => ({ - let l = $l; - let r = $r; - use super::PrimValKind::*; - match $kind { - I8 => overflow!($int_op, l as i8, r as i8), - I16 => overflow!($int_op, l as i16, r as i16), - I32 => overflow!($int_op, l as i32, r as i32), - I64 => overflow!($int_op, l as i64, r as i64), - I128 => overflow!($int_op, l as i128, r as i128), - U8 => overflow!($int_op, l as u8, r as u8), - U16 => overflow!($int_op, l as u16, r as u16), - U32 => overflow!($int_op, l as u32, r as u32), - U64 => overflow!($int_op, l as u64, r as u64), - U128 => overflow!($int_op, l as u128, r as u128), - _ => bug!("int_arithmetic should only be called on int primvals"), - } - }) -} - -macro_rules! int_shift { - ($kind:expr, $int_op:ident, $l:expr, $r:expr) => ({ - let l = $l; - let r = $r; - let r_wrapped = r as u32; - match $kind { - I8 => overflow!($int_op, l as i8, r_wrapped), - I16 => overflow!($int_op, l as i16, r_wrapped), - I32 => overflow!($int_op, l as i32, r_wrapped), - I64 => overflow!($int_op, l as i64, r_wrapped), - I128 => overflow!($int_op, l as i128, r_wrapped), - U8 => overflow!($int_op, l as u8, r_wrapped), - U16 => overflow!($int_op, l as u16, r_wrapped), - U32 => overflow!($int_op, l as u32, r_wrapped), - U64 => overflow!($int_op, l as u64, r_wrapped), - U128 => overflow!($int_op, l as u128, r_wrapped), - _ => bug!("int_shift should only be called on int primvals"), - }.map(|(val, over)| (val, over || r != r_wrapped as u128)) - }) -} - -impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { - /// Returns the result of the specified operation and whether it overflowed. - pub fn binary_op( - &self, - bin_op: mir::BinOp, - left: PrimVal, - left_ty: Ty<'tcx>, - right: PrimVal, - right_ty: Ty<'tcx>, - ) -> EvalResult<'tcx, (PrimVal, bool)> { - use rustc::mir::BinOp::*; - use super::PrimValKind::*; - - let left_kind = self.ty_to_primval_kind(left_ty)?; - let right_kind = self.ty_to_primval_kind(right_ty)?; - //trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})", bin_op, left, left_kind, right, right_kind); - - // I: Handle operations that support pointers - if !left_kind.is_float() && !right_kind.is_float() { - if let Some(handled) = M::try_ptr_op(self, bin_op, left, left_ty, right, right_ty)? { - return Ok(handled); - } - } - - // II: From now on, everything must be bytes, no pointers - let l = left.to_bytes()?; - let r = right.to_bytes()?; - - // These ops can have an RHS with a different numeric type. - if right_kind.is_int() && (bin_op == Shl || bin_op == Shr) { - return match bin_op { - Shl => int_shift!(left_kind, overflowing_shl, l, r), - Shr => int_shift!(left_kind, overflowing_shr, l, r), - _ => bug!("it has already been checked that this is a shift op"), - }; - } - - if left_kind != right_kind { - let msg = format!( - "unimplemented binary op {:?}: {:?} ({:?}), {:?} ({:?})", - bin_op, - left, - left_kind, - right, - right_kind - ); - return err!(Unimplemented(msg)); - } - - let float_op = |op, l, r, ty| { - let l = ConstFloat { - bits: l, - ty, - }; - let r = ConstFloat { - bits: r, - ty, - }; - match op { - Eq => PrimVal::from_bool(l.try_cmp(r).unwrap() == Ordering::Equal), - Ne => PrimVal::from_bool(l.try_cmp(r).unwrap() != Ordering::Equal), - Lt => PrimVal::from_bool(l.try_cmp(r).unwrap() == Ordering::Less), - Le => PrimVal::from_bool(l.try_cmp(r).unwrap() != Ordering::Greater), - Gt => PrimVal::from_bool(l.try_cmp(r).unwrap() == Ordering::Greater), - Ge => PrimVal::from_bool(l.try_cmp(r).unwrap() != Ordering::Less), - Add => PrimVal::Bytes((l + r).unwrap().bits), - Sub => PrimVal::Bytes((l - r).unwrap().bits), - Mul => PrimVal::Bytes((l * r).unwrap().bits), - Div => PrimVal::Bytes((l / r).unwrap().bits), - Rem => PrimVal::Bytes((l % r).unwrap().bits), - _ => bug!("invalid float op: `{:?}`", op), - } - }; - - let val = match (bin_op, left_kind) { - (_, F32) => float_op(bin_op, l, r, FloatTy::F32), - (_, F64) => float_op(bin_op, l, r, FloatTy::F64), - - - (Eq, _) => PrimVal::from_bool(l == r), - (Ne, _) => PrimVal::from_bool(l != r), - - (Lt, k) if k.is_signed_int() => PrimVal::from_bool((l as i128) < (r as i128)), - (Lt, _) => PrimVal::from_bool(l < r), - (Le, k) if k.is_signed_int() => PrimVal::from_bool((l as i128) <= (r as i128)), - (Le, _) => PrimVal::from_bool(l <= r), - (Gt, k) if k.is_signed_int() => PrimVal::from_bool((l as i128) > (r as i128)), - (Gt, _) => PrimVal::from_bool(l > r), - (Ge, k) if k.is_signed_int() => PrimVal::from_bool((l as i128) >= (r as i128)), - (Ge, _) => PrimVal::from_bool(l >= r), - - (BitOr, _) => PrimVal::Bytes(l | r), - (BitAnd, _) => PrimVal::Bytes(l & r), - (BitXor, _) => PrimVal::Bytes(l ^ r), - - (Add, k) if k.is_int() => return int_arithmetic!(k, overflowing_add, l, r), - (Sub, k) if k.is_int() => return int_arithmetic!(k, overflowing_sub, l, r), - (Mul, k) if k.is_int() => return int_arithmetic!(k, overflowing_mul, l, r), - (Div, k) if k.is_int() => return int_arithmetic!(k, overflowing_div, l, r), - (Rem, k) if k.is_int() => return int_arithmetic!(k, overflowing_rem, l, r), - - _ => { - let msg = format!( - "unimplemented binary op {:?}: {:?} ({:?}), {:?} ({:?})", - bin_op, - left, - left_kind, - right, - right_kind - ); - return err!(Unimplemented(msg)); - } - }; - - Ok((val, false)) - } -} - -pub fn unary_op<'tcx>( - un_op: mir::UnOp, - val: PrimVal, - val_kind: PrimValKind, -) -> EvalResult<'tcx, PrimVal> { - use rustc::mir::UnOp::*; - use super::PrimValKind::*; - - let bytes = val.to_bytes()?; - - let result_bytes = match (un_op, val_kind) { - (Not, Bool) => !val.to_bool()? as u128, - - (Not, U8) => !(bytes as u8) as u128, - (Not, U16) => !(bytes as u16) as u128, - (Not, U32) => !(bytes as u32) as u128, - (Not, U64) => !(bytes as u64) as u128, - (Not, U128) => !bytes, - - (Not, I8) => !(bytes as i8) as u128, - (Not, I16) => !(bytes as i16) as u128, - (Not, I32) => !(bytes as i32) as u128, - (Not, I64) => !(bytes as i64) as u128, - (Not, I128) => !(bytes as i128) as u128, - - (Neg, I8) => -(bytes as i8) as u128, - (Neg, I16) => -(bytes as i16) as u128, - (Neg, I32) => -(bytes as i32) as u128, - (Neg, I64) => -(bytes as i64) as u128, - (Neg, I128) => -(bytes as i128) as u128, - - (Neg, F32) => f32_to_bytes(-bytes_to_f32(bytes)), - (Neg, F64) => f64_to_bytes(-bytes_to_f64(bytes)), - - _ => { - let msg = format!("unimplemented unary op: {:?}, {:?}", un_op, val); - return err!(Unimplemented(msg)); - } - }; - - Ok(PrimVal::Bytes(result_bytes)) -} diff --git a/src/librustc_mir/interpret/range_map.rs b/src/librustc_mir/interpret/range_map.rs deleted file mode 100644 index 5cdcbe35121a..000000000000 --- a/src/librustc_mir/interpret/range_map.rs +++ /dev/null @@ -1,250 +0,0 @@ -//! Implements a map from integer indices to data. -//! Rather than storing data for every index, internally, this maps entire ranges to the data. -//! To this end, the APIs all work on ranges, not on individual integers. Ranges are split as -//! necessary (e.g. when [0,5) is first associated with X, and then [1,2) is mutated). -//! Users must not depend on whether a range is coalesced or not, even though this is observable -//! via the iteration APIs. -use std::collections::BTreeMap; -use std::ops; - -#[derive(Clone, Debug)] -pub struct RangeMap { - map: BTreeMap, -} - -// The derived `Ord` impl sorts first by the first field, then, if the fields are the same, -// by the second field. -// This is exactly what we need for our purposes, since a range query on a BTReeSet/BTreeMap will give us all -// `MemoryRange`s whose `start` is <= than the one we're looking for, but not > the end of the range we're checking. -// At the same time the `end` is irrelevant for the sorting and range searching, but used for the check. -// This kind of search breaks, if `end < start`, so don't do that! -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] -struct Range { - start: u64, - end: u64, // Invariant: end > start -} - -impl Range { - fn range(offset: u64, len: u64) -> ops::Range { - assert!(len > 0); - // We select all elements that are within - // the range given by the offset into the allocation and the length. - // This is sound if all ranges that intersect with the argument range, are in the - // resulting range of ranges. - let left = Range { - // lowest range to include `offset` - start: 0, - end: offset + 1, - }; - let right = Range { - // lowest (valid) range not to include `offset+len` - start: offset + len, - end: offset + len + 1, - }; - left..right - } - - /// Tests if all of [offset, offset+len) are contained in this range. - fn overlaps(&self, offset: u64, len: u64) -> bool { - assert!(len > 0); - offset < self.end && offset + len >= self.start - } -} - -impl RangeMap { - pub fn new() -> RangeMap { - RangeMap { map: BTreeMap::new() } - } - - fn iter_with_range<'a>( - &'a self, - offset: u64, - len: u64, - ) -> impl Iterator + 'a { - assert!(len > 0); - self.map.range(Range::range(offset, len)).filter_map( - move |(range, - data)| { - if range.overlaps(offset, len) { - Some((range, data)) - } else { - None - } - }, - ) - } - - pub fn iter<'a>(&'a self, offset: u64, len: u64) -> impl Iterator + 'a { - self.iter_with_range(offset, len).map(|(_, data)| data) - } - - fn split_entry_at(&mut self, offset: u64) - where - T: Clone, - { - let range = match self.iter_with_range(offset, 1).next() { - Some((&range, _)) => range, - None => return, - }; - assert!( - range.start <= offset && range.end > offset, - "We got a range that doesn't even contain what we asked for." - ); - // There is an entry overlapping this position, see if we have to split it - if range.start < offset { - let data = self.map.remove(&range).unwrap(); - let old = self.map.insert( - Range { - start: range.start, - end: offset, - }, - data.clone(), - ); - assert!(old.is_none()); - let old = self.map.insert( - Range { - start: offset, - end: range.end, - }, - data, - ); - assert!(old.is_none()); - } - } - - pub fn iter_mut_all<'a>(&'a mut self) -> impl Iterator + 'a { - self.map.values_mut() - } - - /// Provide mutable iteration over everything in the given range. As a side-effect, - /// this will split entries in the map that are only partially hit by the given range, - /// to make sure that when they are mutated, the effect is constrained to the given range. - pub fn iter_mut_with_gaps<'a>( - &'a mut self, - offset: u64, - len: u64, - ) -> impl Iterator + 'a - where - T: Clone, - { - assert!(len > 0); - // Preparation: Split first and last entry as needed. - self.split_entry_at(offset); - self.split_entry_at(offset + len); - // Now we can provide a mutable iterator - self.map.range_mut(Range::range(offset, len)).filter_map( - move |(&range, data)| { - if range.overlaps(offset, len) { - assert!( - offset <= range.start && offset + len >= range.end, - "The splitting went wrong" - ); - Some(data) - } else { - // Skip this one - None - } - }, - ) - } - - /// Provide a mutable iterator over everything in the given range, with the same side-effects as - /// iter_mut_with_gaps. Furthermore, if there are gaps between ranges, fill them with the given default. - /// This is also how you insert. - pub fn iter_mut<'a>(&'a mut self, offset: u64, len: u64) -> impl Iterator + 'a - where - T: Clone + Default, - { - // Do a first iteration to collect the gaps - let mut gaps = Vec::new(); - let mut last_end = offset; - for (range, _) in self.iter_with_range(offset, len) { - if last_end < range.start { - gaps.push(Range { - start: last_end, - end: range.start, - }); - } - last_end = range.end; - } - if last_end < offset + len { - gaps.push(Range { - start: last_end, - end: offset + len, - }); - } - - // Add default for all gaps - for gap in gaps { - let old = self.map.insert(gap, Default::default()); - assert!(old.is_none()); - } - - // Now provide mutable iteration - self.iter_mut_with_gaps(offset, len) - } - - pub fn retain(&mut self, mut f: F) - where - F: FnMut(&T) -> bool, - { - let mut remove = Vec::new(); - for (range, data) in self.map.iter() { - if !f(data) { - remove.push(*range); - } - } - - for range in remove { - self.map.remove(&range); - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - /// Query the map at every offset in the range and collect the results. - fn to_vec(map: &RangeMap, offset: u64, len: u64) -> Vec { - (offset..offset + len) - .into_iter() - .map(|i| *map.iter(i, 1).next().unwrap()) - .collect() - } - - #[test] - fn basic_insert() { - let mut map = RangeMap::::new(); - // Insert - for x in map.iter_mut(10, 1) { - *x = 42; - } - // Check - assert_eq!(to_vec(&map, 10, 1), vec![42]); - } - - #[test] - fn gaps() { - let mut map = RangeMap::::new(); - for x in map.iter_mut(11, 1) { - *x = 42; - } - for x in map.iter_mut(15, 1) { - *x = 42; - } - - // Now request a range that needs three gaps filled - for x in map.iter_mut(10, 10) { - if *x != 42 { - *x = 23; - } - } - - assert_eq!( - to_vec(&map, 10, 10), - vec![23, 42, 23, 23, 23, 42, 23, 23, 23, 23] - ); - assert_eq!(to_vec(&map, 13, 5), vec![23, 23, 42, 23, 23]); - } -} diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs deleted file mode 100644 index c701ebfbf4c7..000000000000 --- a/src/librustc_mir/interpret/step.rs +++ /dev/null @@ -1,402 +0,0 @@ -//! This module contains the `EvalContext` methods for executing a single step of the interpreter. -//! -//! The main entry point is the `step` method. - -use rustc::hir::def_id::DefId; -use rustc::hir; -use rustc::mir::visit::{Visitor, LvalueContext}; -use rustc::mir; -use rustc::traits::Reveal; -use rustc::ty; -use rustc::ty::layout::Layout; -use rustc::ty::subst::Substs; -use rustc::middle::const_val::ConstVal; - -use super::{EvalResult, EvalContext, StackPopCleanup, PtrAndAlign, GlobalId, Lvalue, - MemoryKind, Machine, PrimVal}; - -use syntax::codemap::Span; -use syntax::ast::Mutability; - -impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { - pub fn inc_step_counter_and_check_limit(&mut self, n: u64) -> EvalResult<'tcx> { - self.steps_remaining = self.steps_remaining.saturating_sub(n); - if self.steps_remaining > 0 { - Ok(()) - } else { - err!(ExecutionTimeLimitReached) - } - } - - /// Returns true as long as there are more things to do. - pub fn step(&mut self) -> EvalResult<'tcx, bool> { - self.inc_step_counter_and_check_limit(1)?; - if self.stack.is_empty() { - return Ok(false); - } - - let block = self.frame().block; - let stmt_id = self.frame().stmt; - let mir = self.mir(); - let basic_block = &mir.basic_blocks()[block]; - - if let Some(stmt) = basic_block.statements.get(stmt_id) { - let mut new = Ok(0); - ConstantExtractor { - span: stmt.source_info.span, - instance: self.frame().instance, - ecx: self, - mir, - new_constants: &mut new, - }.visit_statement( - block, - stmt, - mir::Location { - block, - statement_index: stmt_id, - }, - ); - // if ConstantExtractor added new frames, we don't execute anything here - // but await the next call to step - if new? == 0 { - self.statement(stmt)?; - } - return Ok(true); - } - - let terminator = basic_block.terminator(); - let mut new = Ok(0); - ConstantExtractor { - span: terminator.source_info.span, - instance: self.frame().instance, - ecx: self, - mir, - new_constants: &mut new, - }.visit_terminator( - block, - terminator, - mir::Location { - block, - statement_index: stmt_id, - }, - ); - // if ConstantExtractor added new frames, we don't execute anything here - // but await the next call to step - if new? == 0 { - self.terminator(terminator)?; - } - Ok(true) - } - - fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> EvalResult<'tcx> { - trace!("{:?}", stmt); - - use rustc::mir::StatementKind::*; - - // Some statements (e.g. box) push new stack frames. We have to record the stack frame number - // *before* executing the statement. - let frame_idx = self.cur_frame(); - - match stmt.kind { - Assign(ref lvalue, ref rvalue) => self.eval_rvalue_into_lvalue(rvalue, lvalue)?, - - SetDiscriminant { - ref lvalue, - variant_index, - } => { - let dest = self.eval_lvalue(lvalue)?; - let dest_ty = self.lvalue_ty(lvalue); - let dest_layout = self.type_layout(dest_ty)?; - - match *dest_layout { - Layout::General { discr, .. } => { - let discr_size = discr.size().bytes(); - let dest_ptr = self.force_allocation(dest)?.to_ptr()?; - self.memory.write_primval( - dest_ptr, - PrimVal::Bytes(variant_index as u128), - discr_size, - false - )? - } - - Layout::RawNullablePointer { nndiscr, .. } => { - if variant_index as u64 != nndiscr { - self.write_null(dest, dest_ty)?; - } - } - - Layout::StructWrappedNullablePointer { - nndiscr, - ref discrfield_source, - .. - } => { - if variant_index as u64 != nndiscr { - self.write_struct_wrapped_null_pointer( - dest_ty, - nndiscr, - discrfield_source, - dest, - )?; - } - } - - _ => { - bug!( - "SetDiscriminant on {} represented as {:#?}", - dest_ty, - dest_layout - ) - } - } - } - - // Mark locals as alive - StorageLive(local) => { - let old_val = self.frame_mut().storage_live(local)?; - self.deallocate_local(old_val)?; - } - - // Mark locals as dead - StorageDead(local) => { - let old_val = self.frame_mut().storage_dead(local)?; - self.deallocate_local(old_val)?; - } - - // Validity checks. - Validate(op, ref lvalues) => { - for operand in lvalues { - self.validation_op(op, operand)?; - } - } - EndRegion(ce) => { - self.end_region(Some(ce))?; - } - - // Defined to do nothing. These are added by optimization passes, to avoid changing the - // size of MIR constantly. - Nop => {} - - InlineAsm { .. } => return err!(InlineAsm), - } - - self.stack[frame_idx].stmt += 1; - Ok(()) - } - - fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> EvalResult<'tcx> { - trace!("{:?}", terminator.kind); - self.eval_terminator(terminator)?; - if !self.stack.is_empty() { - trace!("// {:?}", self.frame().block); - } - Ok(()) - } - - /// returns `true` if a stackframe was pushed - fn global_item( - &mut self, - def_id: DefId, - substs: &'tcx Substs<'tcx>, - span: Span, - mutability: Mutability, - ) -> EvalResult<'tcx, bool> { - let instance = self.resolve_associated_const(def_id, substs); - let cid = GlobalId { - instance, - promoted: None, - }; - if self.globals.contains_key(&cid) { - return Ok(false); - } - if self.tcx.has_attr(def_id, "linkage") { - M::global_item_with_linkage(self, cid.instance, mutability)?; - return Ok(false); - } - let mir = self.load_mir(instance.def)?; - let size = self.type_size_with_substs(mir.return_ty, substs)?.expect( - "unsized global", - ); - let align = self.type_align_with_substs(mir.return_ty, substs)?; - let ptr = self.memory.allocate( - size, - align, - MemoryKind::UninitializedStatic, - )?; - let aligned = !self.is_packed(mir.return_ty)?; - self.globals.insert( - cid, - PtrAndAlign { - ptr: ptr.into(), - aligned, - }, - ); - let internally_mutable = !mir.return_ty.is_freeze( - self.tcx, - ty::ParamEnv::empty(Reveal::All), - span, - ); - let mutability = if mutability == Mutability::Mutable || internally_mutable { - Mutability::Mutable - } else { - Mutability::Immutable - }; - let cleanup = StackPopCleanup::MarkStatic(mutability); - let name = ty::tls::with(|tcx| tcx.item_path_str(def_id)); - trace!("pushing stack frame for global: {}", name); - self.push_stack_frame( - instance, - span, - mir, - Lvalue::from_ptr(ptr), - cleanup, - )?; - Ok(true) - } -} - -// WARNING: This code pushes new stack frames. Make sure that any methods implemented on this -// type don't ever access ecx.stack[ecx.cur_frame()], as that will change. This includes, e.g., -// using the current stack frame's substitution. -// Basically don't call anything other than `load_mir`, `alloc_ptr`, `push_stack_frame`. -struct ConstantExtractor<'a, 'b: 'a, 'tcx: 'b, M: Machine<'tcx> + 'a> { - span: Span, - ecx: &'a mut EvalContext<'b, 'tcx, M>, - mir: &'tcx mir::Mir<'tcx>, - instance: ty::Instance<'tcx>, - new_constants: &'a mut EvalResult<'tcx, u64>, -} - -impl<'a, 'b, 'tcx, M: Machine<'tcx>> ConstantExtractor<'a, 'b, 'tcx, M> { - fn try EvalResult<'tcx, bool>>(&mut self, f: F) { - // previous constant errored - let n = match *self.new_constants { - Ok(n) => n, - Err(_) => return, - }; - match f(self) { - // everything ok + a new stackframe - Ok(true) => *self.new_constants = Ok(n + 1), - // constant correctly evaluated, but no new stackframe - Ok(false) => {} - // constant eval errored - Err(err) => *self.new_constants = Err(err), - } - } -} - -impl<'a, 'b, 'tcx, M: Machine<'tcx>> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx, M> { - fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: mir::Location) { - self.super_constant(constant, location); - match constant.literal { - // already computed by rustc - mir::Literal::Value { value: &ty::Const { val: ConstVal::Unevaluated(def_id, substs), .. } } => { - self.try(|this| { - this.ecx.global_item( - def_id, - substs, - constant.span, - Mutability::Immutable, - ) - }); - } - mir::Literal::Value { .. } => {} - mir::Literal::Promoted { index } => { - let cid = GlobalId { - instance: self.instance, - promoted: Some(index), - }; - if self.ecx.globals.contains_key(&cid) { - return; - } - let mir = &self.mir.promoted[index]; - self.try(|this| { - let size = this.ecx - .type_size_with_substs(mir.return_ty, this.instance.substs)? - .expect("unsized global"); - let align = this.ecx.type_align_with_substs( - mir.return_ty, - this.instance.substs, - )?; - let ptr = this.ecx.memory.allocate( - size, - align, - MemoryKind::UninitializedStatic, - )?; - let aligned = !this.ecx.is_packed(mir.return_ty)?; - this.ecx.globals.insert( - cid, - PtrAndAlign { - ptr: ptr.into(), - aligned, - }, - ); - trace!("pushing stack frame for {:?}", index); - this.ecx.push_stack_frame( - this.instance, - constant.span, - mir, - Lvalue::from_ptr(ptr), - StackPopCleanup::MarkStatic(Mutability::Immutable), - )?; - Ok(true) - }); - } - } - } - - fn visit_lvalue( - &mut self, - lvalue: &mir::Lvalue<'tcx>, - context: LvalueContext<'tcx>, - location: mir::Location, - ) { - self.super_lvalue(lvalue, context, location); - if let mir::Lvalue::Static(ref static_) = *lvalue { - let def_id = static_.def_id; - let substs = self.ecx.tcx.intern_substs(&[]); - let span = self.span; - if let Some(node_item) = self.ecx.tcx.hir.get_if_local(def_id) { - if let hir::map::Node::NodeItem(&hir::Item { ref node, .. }) = node_item { - if let hir::ItemStatic(_, m, _) = *node { - self.try(|this| { - this.ecx.global_item( - def_id, - substs, - span, - if m == hir::MutMutable { - Mutability::Mutable - } else { - Mutability::Immutable - }, - ) - }); - return; - } else { - bug!("static def id doesn't point to static"); - } - } else { - bug!("static def id doesn't point to item"); - } - } else { - let def = self.ecx.tcx.describe_def(def_id).expect("static not found"); - if let hir::def::Def::Static(_, mutable) = def { - self.try(|this| { - this.ecx.global_item( - def_id, - substs, - span, - if mutable { - Mutability::Mutable - } else { - Mutability::Immutable - }, - ) - }); - } else { - bug!("static found but isn't a static: {:?}", def); - } - } - } - } -} diff --git a/src/librustc_mir/interpret/terminator/drop.rs b/src/librustc_mir/interpret/terminator/drop.rs deleted file mode 100644 index 6596cf951fd9..000000000000 --- a/src/librustc_mir/interpret/terminator/drop.rs +++ /dev/null @@ -1,83 +0,0 @@ -use rustc::mir::BasicBlock; -use rustc::ty::{self, Ty}; -use syntax::codemap::Span; - -use interpret::{EvalResult, EvalContext, Lvalue, LvalueExtra, PrimVal, Value, - Machine, ValTy}; - -impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { - pub(crate) fn drop_lvalue( - &mut self, - lval: Lvalue, - instance: ty::Instance<'tcx>, - ty: Ty<'tcx>, - span: Span, - target: BasicBlock, - ) -> EvalResult<'tcx> { - trace!("drop_lvalue: {:#?}", lval); - // We take the address of the object. This may well be unaligned, which is fine for us here. - // However, unaligned accesses will probably make the actual drop implementation fail -- a problem shared - // by rustc. - let val = match self.force_allocation(lval)? { - Lvalue::Ptr { - ptr, - extra: LvalueExtra::Vtable(vtable), - } => ptr.ptr.to_value_with_vtable(vtable), - Lvalue::Ptr { - ptr, - extra: LvalueExtra::Length(len), - } => ptr.ptr.to_value_with_len(len), - Lvalue::Ptr { - ptr, - extra: LvalueExtra::None, - } => ptr.ptr.to_value(), - _ => bug!("force_allocation broken"), - }; - self.drop(val, instance, ty, span, target) - } - - fn drop( - &mut self, - arg: Value, - instance: ty::Instance<'tcx>, - ty: Ty<'tcx>, - span: Span, - target: BasicBlock, - ) -> EvalResult<'tcx> { - trace!("drop: {:#?}, {:?}, {:?}", arg, ty.sty, instance.def); - - let instance = match ty.sty { - ty::TyDynamic(..) => { - let vtable = match arg { - Value::ByValPair(_, PrimVal::Ptr(vtable)) => vtable, - _ => bug!("expected fat ptr, got {:?}", arg), - }; - match self.read_drop_type_from_vtable(vtable)? { - Some(func) => func, - // no drop fn -> bail out - None => { - self.goto_block(target); - return Ok(()) - }, - } - } - _ => instance, - }; - - // the drop function expects a reference to the value - let valty = ValTy { - value: arg, - ty: self.tcx.mk_mut_ptr(ty), - }; - - let fn_sig = self.tcx.fn_sig(instance.def_id()).skip_binder().clone(); - - self.eval_fn_call( - instance, - Some((Lvalue::undef(), target)), - &vec![valty], - span, - fn_sig, - ) - } -} diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs deleted file mode 100644 index e01777cdb4e7..000000000000 --- a/src/librustc_mir/interpret/terminator/mod.rs +++ /dev/null @@ -1,411 +0,0 @@ -use rustc::mir; -use rustc::ty::{self, TypeVariants}; -use rustc::ty::layout::Layout; -use syntax::codemap::Span; -use syntax::abi::Abi; - -use super::{EvalResult, EvalContext, eval_context, - PtrAndAlign, Lvalue, PrimVal, Value, Machine, ValTy}; - -use rustc_data_structures::indexed_vec::Idx; - -mod drop; - -impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { - pub fn goto_block(&mut self, target: mir::BasicBlock) { - self.frame_mut().block = target; - self.frame_mut().stmt = 0; - } - - pub(super) fn eval_terminator( - &mut self, - terminator: &mir::Terminator<'tcx>, - ) -> EvalResult<'tcx> { - use rustc::mir::TerminatorKind::*; - match terminator.kind { - Return => { - self.dump_local(self.frame().return_lvalue); - self.pop_stack_frame()? - } - - Goto { target } => self.goto_block(target), - - SwitchInt { - ref discr, - ref values, - ref targets, - .. - } => { - // FIXME(CTFE): forbid branching - let discr_val = self.eval_operand(discr)?; - let discr_prim = self.value_to_primval(discr_val)?; - - // Branch to the `otherwise` case by default, if no match is found. - let mut target_block = targets[targets.len() - 1]; - - for (index, const_int) in values.iter().enumerate() { - let prim = PrimVal::Bytes(const_int.to_u128_unchecked()); - if discr_prim.to_bytes()? == prim.to_bytes()? { - target_block = targets[index]; - break; - } - } - - self.goto_block(target_block); - } - - Call { - ref func, - ref args, - ref destination, - .. - } => { - let destination = match *destination { - Some((ref lv, target)) => Some((self.eval_lvalue(lv)?, target)), - None => None, - }; - - let func_ty = self.operand_ty(func); - let (fn_def, sig) = match func_ty.sty { - ty::TyFnPtr(sig) => { - let fn_ptr = self.eval_operand_to_primval(func)?.to_ptr()?; - let instance = self.memory.get_fn(fn_ptr)?; - let instance_ty = instance.def.def_ty(self.tcx); - let instance_ty = self.monomorphize(instance_ty, instance.substs); - match instance_ty.sty { - ty::TyFnDef(..) => { - let real_sig = instance_ty.fn_sig(self.tcx); - let sig = self.tcx.erase_late_bound_regions_and_normalize(&sig); - let real_sig = self.tcx.erase_late_bound_regions_and_normalize(&real_sig); - if !self.check_sig_compat(sig, real_sig)? { - return err!(FunctionPointerTyMismatch(real_sig, sig)); - } - } - ref other => bug!("instance def ty: {:?}", other), - } - (instance, sig) - } - ty::TyFnDef(def_id, substs) => ( - eval_context::resolve(self.tcx, def_id, substs), - func_ty.fn_sig(self.tcx), - ), - _ => { - let msg = format!("can't handle callee of type {:?}", func_ty); - return err!(Unimplemented(msg)); - } - }; - let args = self.operands_to_args(args)?; - let sig = self.tcx.erase_late_bound_regions_and_normalize(&sig); - self.eval_fn_call( - fn_def, - destination, - &args, - terminator.source_info.span, - sig, - )?; - } - - Drop { - ref location, - target, - .. - } => { - // FIXME(CTFE): forbid drop in const eval - let lval = self.eval_lvalue(location)?; - let ty = self.lvalue_ty(location); - let ty = eval_context::apply_param_substs(self.tcx, self.substs(), &ty); - trace!("TerminatorKind::drop: {:?}, type {}", location, ty); - - let instance = eval_context::resolve_drop_in_place(self.tcx, ty); - self.drop_lvalue( - lval, - instance, - ty, - terminator.source_info.span, - target, - )?; - } - - Assert { - ref cond, - expected, - ref msg, - target, - .. - } => { - let cond_val = self.eval_operand_to_primval(cond)?.to_bool()?; - if expected == cond_val { - self.goto_block(target); - } else { - use rustc::mir::AssertMessage::*; - return match *msg { - BoundsCheck { ref len, ref index } => { - let span = terminator.source_info.span; - let len = self.eval_operand_to_primval(len) - .expect("can't eval len") - .to_u64()?; - let index = self.eval_operand_to_primval(index) - .expect("can't eval index") - .to_u64()?; - err!(ArrayIndexOutOfBounds(span, len, index)) - } - Math(ref err) => { - err!(Math(terminator.source_info.span, err.clone())) - } - GeneratorResumedAfterReturn | - GeneratorResumedAfterPanic => unimplemented!(), - }; - } - } - - Yield { .. } => unimplemented!("{:#?}", terminator.kind), - GeneratorDrop => unimplemented!(), - DropAndReplace { .. } => unimplemented!(), - Resume => unimplemented!(), - Unreachable => return err!(Unreachable), - } - - Ok(()) - } - - /// Decides whether it is okay to call the method with signature `real_sig` using signature `sig`. - /// FIXME: This should take into account the platform-dependent ABI description. - fn check_sig_compat( - &mut self, - sig: ty::FnSig<'tcx>, - real_sig: ty::FnSig<'tcx>, - ) -> EvalResult<'tcx, bool> { - fn check_ty_compat<'tcx>(ty: ty::Ty<'tcx>, real_ty: ty::Ty<'tcx>) -> bool { - if ty == real_ty { - return true; - } // This is actually a fast pointer comparison - return match (&ty.sty, &real_ty.sty) { - // Permit changing the pointer type of raw pointers and references as well as - // mutability of raw pointers. - // TODO: Should not be allowed when fat pointers are involved. - (&TypeVariants::TyRawPtr(_), &TypeVariants::TyRawPtr(_)) => true, - (&TypeVariants::TyRef(_, _), &TypeVariants::TyRef(_, _)) => { - ty.is_mutable_pointer() == real_ty.is_mutable_pointer() - } - // rule out everything else - _ => false, - }; - } - - if sig.abi == real_sig.abi && sig.variadic == real_sig.variadic && - sig.inputs_and_output.len() == real_sig.inputs_and_output.len() && - sig.inputs_and_output - .iter() - .zip(real_sig.inputs_and_output) - .all(|(ty, real_ty)| check_ty_compat(ty, real_ty)) - { - // Definitely good. - return Ok(true); - } - - if sig.variadic || real_sig.variadic { - // We're not touching this - return Ok(false); - } - - // We need to allow what comes up when a non-capturing closure is cast to a fn(). - match (sig.abi, real_sig.abi) { - (Abi::Rust, Abi::RustCall) // check the ABIs. This makes the test here non-symmetric. - if check_ty_compat(sig.output(), real_sig.output()) && real_sig.inputs_and_output.len() == 3 => { - // First argument of real_sig must be a ZST - let fst_ty = real_sig.inputs_and_output[0]; - let layout = self.type_layout(fst_ty)?; - let size = layout.size(&self.tcx.data_layout).bytes(); - if size == 0 { - // Second argument must be a tuple matching the argument list of sig - let snd_ty = real_sig.inputs_and_output[1]; - match snd_ty.sty { - TypeVariants::TyTuple(tys, _) if sig.inputs().len() == tys.len() => - if sig.inputs().iter().zip(tys).all(|(ty, real_ty)| check_ty_compat(ty, real_ty)) { - return Ok(true) - }, - _ => {} - } - } - } - _ => {} - }; - - // Nope, this doesn't work. - return Ok(false); - } - - fn eval_fn_call( - &mut self, - instance: ty::Instance<'tcx>, - destination: Option<(Lvalue, mir::BasicBlock)>, - args: &[ValTy<'tcx>], - span: Span, - sig: ty::FnSig<'tcx>, - ) -> EvalResult<'tcx> { - trace!("eval_fn_call: {:#?}", instance); - match instance.def { - ty::InstanceDef::Intrinsic(..) => { - let (ret, target) = match destination { - Some(dest) => dest, - _ => return err!(Unreachable), - }; - let ty = sig.output(); - let layout = self.type_layout(ty)?; - M::call_intrinsic(self, instance, args, ret, ty, layout, target)?; - self.dump_local(ret); - Ok(()) - } - // FIXME: figure out why we can't just go through the shim - ty::InstanceDef::ClosureOnceShim { .. } => { - if M::eval_fn_call(self, instance, destination, args, span, sig)? { - return Ok(()); - } - let mut arg_locals = self.frame().mir.args_iter(); - match sig.abi { - // closure as closure once - Abi::RustCall => { - for (arg_local, &valty) in arg_locals.zip(args) { - let dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?; - self.write_value(valty, dest)?; - } - } - // non capture closure as fn ptr - // need to inject zst ptr for closure object (aka do nothing) - // and need to pack arguments - Abi::Rust => { - trace!( - "arg_locals: {:?}", - self.frame().mir.args_iter().collect::>() - ); - trace!("args: {:?}", args); - let local = arg_locals.nth(1).unwrap(); - for (i, &valty) in args.into_iter().enumerate() { - let dest = self.eval_lvalue(&mir::Lvalue::Local(local).field( - mir::Field::new(i), - valty.ty, - ))?; - self.write_value(valty, dest)?; - } - } - _ => bug!("bad ABI for ClosureOnceShim: {:?}", sig.abi), - } - Ok(()) - } - ty::InstanceDef::FnPtrShim(..) | - ty::InstanceDef::DropGlue(..) | - ty::InstanceDef::CloneShim(..) | - ty::InstanceDef::Item(_) => { - // Push the stack frame, and potentially be entirely done if the call got hooked - if M::eval_fn_call(self, instance, destination, args, span, sig)? { - return Ok(()); - } - - // Pass the arguments - let mut arg_locals = self.frame().mir.args_iter(); - trace!("ABI: {:?}", sig.abi); - trace!( - "arg_locals: {:?}", - self.frame().mir.args_iter().collect::>() - ); - trace!("args: {:?}", args); - match sig.abi { - Abi::RustCall => { - assert_eq!(args.len(), 2); - - { - // write first argument - let first_local = arg_locals.next().unwrap(); - let dest = self.eval_lvalue(&mir::Lvalue::Local(first_local))?; - self.write_value(args[0], dest)?; - } - - // unpack and write all other args - let layout = self.type_layout(args[1].ty)?; - if let (&ty::TyTuple(fields, _), - &Layout::Univariant { ref variant, .. }) = (&args[1].ty.sty, layout) - { - trace!("fields: {:?}", fields); - if self.frame().mir.args_iter().count() == fields.len() + 1 { - let offsets = variant.offsets.iter().map(|s| s.bytes()); - match args[1].value { - Value::ByRef(PtrAndAlign { ptr, aligned }) => { - assert!( - aligned, - "Unaligned ByRef-values cannot occur as function arguments" - ); - for ((offset, ty), arg_local) in - offsets.zip(fields).zip(arg_locals) - { - let arg = Value::by_ref(ptr.offset(offset, &self)?); - let dest = - self.eval_lvalue(&mir::Lvalue::Local(arg_local))?; - trace!( - "writing arg {:?} to {:?} (type: {})", - arg, - dest, - ty - ); - let valty = ValTy { - value: arg, - ty, - }; - self.write_value(valty, dest)?; - } - } - Value::ByVal(PrimVal::Undef) => {} - other => { - assert_eq!(fields.len(), 1); - let dest = self.eval_lvalue(&mir::Lvalue::Local( - arg_locals.next().unwrap(), - ))?; - let valty = ValTy { - value: other, - ty: fields[0], - }; - self.write_value(valty, dest)?; - } - } - } else { - trace!("manual impl of rust-call ABI"); - // called a manual impl of a rust-call function - let dest = self.eval_lvalue( - &mir::Lvalue::Local(arg_locals.next().unwrap()), - )?; - self.write_value(args[1], dest)?; - } - } else { - bug!( - "rust-call ABI tuple argument was {:#?}, {:#?}", - args[1].ty, - layout - ); - } - } - _ => { - for (arg_local, &valty) in arg_locals.zip(args) { - let dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?; - self.write_value(valty, dest)?; - } - } - } - Ok(()) - } - // cannot use the shim here, because that will only result in infinite recursion - ty::InstanceDef::Virtual(_, idx) => { - let ptr_size = self.memory.pointer_size(); - let (ptr, vtable) = args[0].into_ptr_vtable_pair(&self.memory)?; - let fn_ptr = self.memory.read_ptr_sized_unsigned( - vtable.offset(ptr_size * (idx as u64 + 3), &self)? - )?.to_ptr()?; - let instance = self.memory.get_fn(fn_ptr)?; - let mut args = args.to_vec(); - let ty = self.get_field_ty(args[0].ty, 0)?.ty; // TODO: packed flag is ignored - args[0].ty = ty; - args[0].value = ptr.to_value(); - // recurse with concrete function - self.eval_fn_call(instance, destination, &args, span, sig) - } - } - } -} diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs deleted file mode 100644 index 3f7e10a9eaff..000000000000 --- a/src/librustc_mir/interpret/traits.rs +++ /dev/null @@ -1,137 +0,0 @@ -use rustc::traits::{self, Reveal}; -use rustc::hir::def_id::DefId; -use rustc::ty::subst::Substs; -use rustc::ty::{self, Ty}; -use syntax::codemap::DUMMY_SP; -use syntax::ast::{self, Mutability}; - -use super::{EvalResult, EvalContext, eval_context, MemoryPointer, MemoryKind, Value, PrimVal, - Machine}; - -impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { - pub(crate) fn fulfill_obligation( - &self, - trait_ref: ty::PolyTraitRef<'tcx>, - ) -> traits::Vtable<'tcx, ()> { - // Do the initial selection for the obligation. This yields the shallow result we are - // looking for -- that is, what specific impl. - self.tcx.infer_ctxt().enter(|infcx| { - let mut selcx = traits::SelectionContext::new(&infcx); - - let obligation = traits::Obligation::new( - traits::ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID), - ty::ParamEnv::empty(Reveal::All), - trait_ref.to_poly_trait_predicate(), - ); - let selection = selcx.select(&obligation).unwrap().unwrap(); - - // Currently, we use a fulfillment context to completely resolve all nested obligations. - // This is because they can inform the inference of the impl's type parameters. - let mut fulfill_cx = traits::FulfillmentContext::new(); - let vtable = selection.map(|predicate| { - fulfill_cx.register_predicate_obligation(&infcx, predicate); - }); - infcx.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &vtable) - }) - } - - /// Creates a dynamic vtable for the given type and vtable origin. This is used only for - /// objects. - /// - /// The `trait_ref` encodes the erased self type. Hence if we are - /// making an object `Foo` from a value of type `Foo`, then - /// `trait_ref` would map `T:Trait`. - pub fn get_vtable( - &mut self, - ty: Ty<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, - ) -> EvalResult<'tcx, MemoryPointer> { - debug!("get_vtable(trait_ref={:?})", trait_ref); - - let size = self.type_size(trait_ref.self_ty())?.expect( - "can't create a vtable for an unsized type", - ); - let align = self.type_align(trait_ref.self_ty())?; - - let ptr_size = self.memory.pointer_size(); - let methods = ::rustc::traits::get_vtable_methods(self.tcx, trait_ref); - let vtable = self.memory.allocate( - ptr_size * (3 + methods.count() as u64), - ptr_size, - MemoryKind::UninitializedStatic, - )?; - - let drop = eval_context::resolve_drop_in_place(self.tcx, ty); - let drop = self.memory.create_fn_alloc(drop); - self.memory.write_ptr_sized_unsigned(vtable, PrimVal::Ptr(drop))?; - - let size_ptr = vtable.offset(ptr_size, &self)?; - self.memory.write_ptr_sized_unsigned(size_ptr, PrimVal::Bytes(size as u128))?; - let align_ptr = vtable.offset(ptr_size * 2, &self)?; - self.memory.write_ptr_sized_unsigned(align_ptr, PrimVal::Bytes(align as u128))?; - - for (i, method) in ::rustc::traits::get_vtable_methods(self.tcx, trait_ref).enumerate() { - if let Some((def_id, substs)) = method { - let instance = eval_context::resolve(self.tcx, def_id, substs); - let fn_ptr = self.memory.create_fn_alloc(instance); - let method_ptr = vtable.offset(ptr_size * (3 + i as u64), &self)?; - self.memory.write_ptr_sized_unsigned(method_ptr, PrimVal::Ptr(fn_ptr))?; - } - } - - self.memory.mark_static_initalized( - vtable.alloc_id, - Mutability::Mutable, - )?; - - Ok(vtable) - } - - pub fn read_drop_type_from_vtable( - &self, - vtable: MemoryPointer, - ) -> EvalResult<'tcx, Option>> { - // we don't care about the pointee type, we just want a pointer - match self.read_ptr(vtable, self.tcx.mk_nil_ptr())? { - // some values don't need to call a drop impl, so the value is null - Value::ByVal(PrimVal::Bytes(0)) => Ok(None), - Value::ByVal(PrimVal::Ptr(drop_fn)) => self.memory.get_fn(drop_fn).map(Some), - _ => err!(ReadBytesAsPointer), - } - } - - pub fn read_size_and_align_from_vtable( - &self, - vtable: MemoryPointer, - ) -> EvalResult<'tcx, (u64, u64)> { - let pointer_size = self.memory.pointer_size(); - let size = self.memory.read_ptr_sized_unsigned(vtable.offset(pointer_size, self)?)?.to_bytes()? as u64; - let align = self.memory.read_ptr_sized_unsigned( - vtable.offset(pointer_size * 2, self)? - )?.to_bytes()? as u64; - Ok((size, align)) - } - - pub(crate) fn resolve_associated_const( - &self, - def_id: DefId, - substs: &'tcx Substs<'tcx>, - ) -> ty::Instance<'tcx> { - if let Some(trait_id) = self.tcx.trait_of_item(def_id) { - let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, substs)); - let vtable = self.fulfill_obligation(trait_ref); - if let traits::VtableImpl(vtable_impl) = vtable { - let name = self.tcx.item_name(def_id); - let assoc_const_opt = self.tcx.associated_items(vtable_impl.impl_def_id).find( - |item| { - item.kind == ty::AssociatedKind::Const && item.name == name - }, - ); - if let Some(assoc_const) = assoc_const_opt { - return ty::Instance::new(assoc_const.def_id, vtable_impl.substs); - } - } - } - ty::Instance::new(def_id, substs) - } -} diff --git a/src/librustc_mir/interpret/validation.rs b/src/librustc_mir/interpret/validation.rs deleted file mode 100644 index 9be9341ee239..000000000000 --- a/src/librustc_mir/interpret/validation.rs +++ /dev/null @@ -1,727 +0,0 @@ -use rustc::hir::{self, Mutability}; -use rustc::hir::Mutability::*; -use rustc::mir::{self, ValidationOp, ValidationOperand}; -use rustc::ty::{self, Ty, TypeFoldable, TyCtxt}; -use rustc::ty::subst::{Substs, Subst}; -use rustc::traits; -use rustc::infer::InferCtxt; -use rustc::traits::Reveal; -use rustc::middle::region; -use rustc_data_structures::indexed_vec::Idx; - -use super::{EvalError, EvalResult, EvalErrorKind, EvalContext, DynamicLifetime, AccessKind, Value, - Lvalue, LvalueExtra, Machine, ValTy}; - -pub type ValidationQuery<'tcx> = ValidationOperand<'tcx, (AbsLvalue<'tcx>, Lvalue)>; - -#[derive(Copy, Clone, Debug, PartialEq)] -enum ValidationMode { - Acquire, - /// Recover because the given region ended - Recover(region::Scope), - ReleaseUntil(Option), -} - -impl ValidationMode { - fn acquiring(self) -> bool { - use self::ValidationMode::*; - match self { - Acquire | Recover(_) => true, - ReleaseUntil(_) => false, - } - } -} - -// Abstract lvalues -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub enum AbsLvalue<'tcx> { - Local(mir::Local), - Static(hir::def_id::DefId), - Projection(Box>), -} - -type AbsLvalueProjection<'tcx> = mir::Projection<'tcx, AbsLvalue<'tcx>, u64, ()>; -type AbsLvalueElem<'tcx> = mir::ProjectionElem<'tcx, u64, ()>; - -impl<'tcx> AbsLvalue<'tcx> { - pub fn field(self, f: mir::Field) -> AbsLvalue<'tcx> { - self.elem(mir::ProjectionElem::Field(f, ())) - } - - pub fn deref(self) -> AbsLvalue<'tcx> { - self.elem(mir::ProjectionElem::Deref) - } - - pub fn downcast(self, adt_def: &'tcx ty::AdtDef, variant_index: usize) -> AbsLvalue<'tcx> { - self.elem(mir::ProjectionElem::Downcast(adt_def, variant_index)) - } - - pub fn index(self, index: u64) -> AbsLvalue<'tcx> { - self.elem(mir::ProjectionElem::Index(index)) - } - - fn elem(self, elem: AbsLvalueElem<'tcx>) -> AbsLvalue<'tcx> { - AbsLvalue::Projection(Box::new(AbsLvalueProjection { - base: self, - elem, - })) - } -} - -impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { - fn abstract_lvalue_projection(&self, proj: &mir::LvalueProjection<'tcx>) -> EvalResult<'tcx, AbsLvalueProjection<'tcx>> { - use self::mir::ProjectionElem::*; - - let elem = match proj.elem { - Deref => Deref, - Field(f, _) => Field(f, ()), - Index(v) => { - let value = self.frame().get_local(v)?; - let ty = self.tcx.types.usize; - let n = self.value_to_primval(ValTy { value, ty })?.to_u64()?; - Index(n) - }, - ConstantIndex { offset, min_length, from_end } => - ConstantIndex { offset, min_length, from_end }, - Subslice { from, to } => - Subslice { from, to }, - Downcast(adt, sz) => Downcast(adt, sz), - }; - Ok(AbsLvalueProjection { - base: self.abstract_lvalue(&proj.base)?, - elem - }) - } - - fn abstract_lvalue(&self, lval: &mir::Lvalue<'tcx>) -> EvalResult<'tcx, AbsLvalue<'tcx>> { - Ok(match lval { - &mir::Lvalue::Local(l) => AbsLvalue::Local(l), - &mir::Lvalue::Static(ref s) => AbsLvalue::Static(s.def_id), - &mir::Lvalue::Projection(ref p) => - AbsLvalue::Projection(Box::new(self.abstract_lvalue_projection(&*p)?)), - }) - } - - // Validity checks - pub(crate) fn validation_op( - &mut self, - op: ValidationOp, - operand: &ValidationOperand<'tcx, mir::Lvalue<'tcx>>, - ) -> EvalResult<'tcx> { - // If mir-emit-validate is set to 0 (i.e., disabled), we may still see validation commands - // because other crates may have been compiled with mir-emit-validate > 0. Ignore those - // commands. This makes mir-emit-validate also a flag to control whether miri will do - // validation or not. - if self.tcx.sess.opts.debugging_opts.mir_emit_validate == 0 { - return Ok(()); - } - debug_assert!(self.memory.cur_frame == self.cur_frame()); - - // HACK: Determine if this method is whitelisted and hence we do not perform any validation. - // We currently insta-UB on anything passing around uninitialized memory, so we have to whitelist - // the places that are allowed to do that. - // The second group is stuff libstd does that is forbidden even under relaxed validation. - { - // The regexp we use for filtering - use regex::Regex; - lazy_static! { - static ref RE: Regex = Regex::new("^(\ - (std|alloc::heap::__core)::mem::(uninitialized|forget)::|\ - <(std|alloc)::heap::Heap as (std::heap|alloc::allocator)::Alloc>::|\ - <(std|alloc::heap::__core)::mem::ManuallyDrop><.*>::new$|\ - <(std|alloc::heap::__core)::mem::ManuallyDrop as std::ops::DerefMut><.*>::deref_mut$|\ - (std|alloc::heap::__core)::ptr::read::|\ - \ - ><.*>::inner$|\ - ><.*>::drop_slow$|\ - (std::heap|alloc::allocator)::Layout::for_value::|\ - (std|alloc::heap::__core)::mem::(size|align)_of_val::\ - )").unwrap(); - } - // Now test - let name = self.stack[self.cur_frame()].instance.to_string(); - if RE.is_match(&name) { - return Ok(()); - } - } - - // We need to monomorphize ty *without* erasing lifetimes - let ty = operand.ty.subst(self.tcx, self.substs()); - let lval = self.eval_lvalue(&operand.lval)?; - let abs_lval = self.abstract_lvalue(&operand.lval)?; - let query = ValidationQuery { - lval: (abs_lval, lval), - ty, - re: operand.re, - mutbl: operand.mutbl, - }; - - // Check the mode, and also perform mode-specific operations - let mode = match op { - ValidationOp::Acquire => ValidationMode::Acquire, - ValidationOp::Release => ValidationMode::ReleaseUntil(None), - ValidationOp::Suspend(scope) => { - if query.mutbl == MutMutable { - let lft = DynamicLifetime { - frame: self.cur_frame(), - region: Some(scope), // Notably, we only ever suspend things for given regions. - // Suspending for the entire function does not make any sense. - }; - trace!("Suspending {:?} until {:?}", query, scope); - self.suspended.entry(lft).or_insert_with(Vec::new).push( - query.clone(), - ); - } - ValidationMode::ReleaseUntil(Some(scope)) - } - }; - self.validate(query, mode) - } - - /// Release locks and executes suspensions of the given region (or the entire fn, in case of None). - pub(crate) fn end_region(&mut self, scope: Option) -> EvalResult<'tcx> { - debug_assert!(self.memory.cur_frame == self.cur_frame()); - self.memory.locks_lifetime_ended(scope); - match scope { - Some(scope) => { - // Recover suspended lvals - let lft = DynamicLifetime { - frame: self.cur_frame(), - region: Some(scope), - }; - if let Some(queries) = self.suspended.remove(&lft) { - for query in queries { - trace!("Recovering {:?} from suspension", query); - self.validate(query, ValidationMode::Recover(scope))?; - } - } - } - None => { - // Clean suspension table of current frame - let cur_frame = self.cur_frame(); - self.suspended.retain(|lft, _| { - lft.frame != cur_frame // keep only what is in the other (lower) frames - }); - } - } - Ok(()) - } - - fn normalize_type_unerased(&self, ty: Ty<'tcx>) -> Ty<'tcx> { - return normalize_associated_type(self.tcx, &ty); - - use syntax::codemap::{Span, DUMMY_SP}; - - // We copy a bunch of stuff from rustc/infer/mod.rs to be able to tweak its behavior - fn normalize_projections_in<'a, 'gcx, 'tcx, T>( - self_: &InferCtxt<'a, 'gcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - value: &T, - ) -> T::Lifted - where - T: TypeFoldable<'tcx> + ty::Lift<'gcx>, - { - let mut selcx = traits::SelectionContext::new(self_); - let cause = traits::ObligationCause::dummy(); - let traits::Normalized { - value: result, - obligations, - } = traits::normalize(&mut selcx, param_env, cause, value); - - let mut fulfill_cx = traits::FulfillmentContext::new(); - - for obligation in obligations { - fulfill_cx.register_predicate_obligation(self_, obligation); - } - - drain_fulfillment_cx_or_panic(self_, DUMMY_SP, &mut fulfill_cx, &result) - } - - fn drain_fulfillment_cx_or_panic<'a, 'gcx, 'tcx, T>( - self_: &InferCtxt<'a, 'gcx, 'tcx>, - span: Span, - fulfill_cx: &mut traits::FulfillmentContext<'tcx>, - result: &T, - ) -> T::Lifted - where - T: TypeFoldable<'tcx> + ty::Lift<'gcx>, - { - // In principle, we only need to do this so long as `result` - // contains unbound type parameters. It could be a slight - // optimization to stop iterating early. - match fulfill_cx.select_all_or_error(self_) { - Ok(()) => { } - Err(errors) => { - span_bug!( - span, - "Encountered errors `{:?}` resolving bounds after type-checking", - errors - ); - } - } - - let result = self_.resolve_type_vars_if_possible(result); - let result = self_.tcx.fold_regions( - &result, - &mut false, - |r, _| match *r { - ty::ReVar(_) => self_.tcx.types.re_erased, - _ => r, - }, - ); - - match self_.tcx.lift_to_global(&result) { - Some(result) => result, - None => { - span_bug!(span, "Uninferred types/regions in `{:?}`", result); - } - } - } - - trait MyTransNormalize<'gcx>: TypeFoldable<'gcx> { - fn my_trans_normalize<'a, 'tcx>( - &self, - infcx: &InferCtxt<'a, 'gcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> Self; - } - - macro_rules! items { ($($item:item)+) => ($($item)+) } - macro_rules! impl_trans_normalize { - ($lt_gcx:tt, $($ty:ty),+) => { - items!($(impl<$lt_gcx> MyTransNormalize<$lt_gcx> for $ty { - fn my_trans_normalize<'a, 'tcx>(&self, - infcx: &InferCtxt<'a, $lt_gcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>) - -> Self { - normalize_projections_in(infcx, param_env, self) - } - })+); - } - } - - impl_trans_normalize!('gcx, - Ty<'gcx>, - &'gcx Substs<'gcx>, - ty::FnSig<'gcx>, - ty::PolyFnSig<'gcx>, - ty::ClosureSubsts<'gcx>, - ty::PolyTraitRef<'gcx>, - ty::ExistentialTraitRef<'gcx> - ); - - fn normalize_associated_type<'a, 'tcx, T>(self_: TyCtxt<'a, 'tcx, 'tcx>, value: &T) -> T - where - T: MyTransNormalize<'tcx>, - { - let param_env = ty::ParamEnv::empty(Reveal::All); - - if !value.has_projections() { - return value.clone(); - } - - self_.infer_ctxt().enter(|infcx| { - value.my_trans_normalize(&infcx, param_env) - }) - } - } - - fn validate_variant( - &mut self, - query: ValidationQuery<'tcx>, - variant: &ty::VariantDef, - subst: &ty::subst::Substs<'tcx>, - mode: ValidationMode, - ) -> EvalResult<'tcx> { - // TODO: Maybe take visibility/privacy into account. - for (idx, field_def) in variant.fields.iter().enumerate() { - let field_ty = field_def.ty(self.tcx, subst); - let field = mir::Field::new(idx); - let field_lvalue = self.lvalue_field(query.lval.1, field, query.ty, field_ty)?; - self.validate( - ValidationQuery { - lval: (query.lval.0.clone().field(field), field_lvalue), - ty: field_ty, - ..query - }, - mode, - )?; - } - Ok(()) - } - - fn validate_ptr( - &mut self, - val: Value, - abs_lval: AbsLvalue<'tcx>, - pointee_ty: Ty<'tcx>, - re: Option, - mutbl: Mutability, - mode: ValidationMode, - ) -> EvalResult<'tcx> { - // Check alignment and non-NULLness - let (_, align) = self.size_and_align_of_dst(pointee_ty, val)?; - let ptr = val.into_ptr(&self.memory)?; - self.memory.check_align(ptr, align, None)?; - - // Recurse - let pointee_lvalue = self.val_to_lvalue(val, pointee_ty)?; - self.validate( - ValidationQuery { - lval: (abs_lval.deref(), pointee_lvalue), - ty: pointee_ty, - re, - mutbl, - }, - mode, - ) - } - - /// Validate the lvalue at the given type. If `acquire` is false, just do a release of all write locks - fn validate( - &mut self, - mut query: ValidationQuery<'tcx>, - mode: ValidationMode, - ) -> EvalResult<'tcx> { - use rustc::ty::TypeVariants::*; - use rustc::ty::RegionKind::*; - use rustc::ty::AdtKind; - - // No point releasing shared stuff. - if !mode.acquiring() && query.mutbl == MutImmutable { - return Ok(()); - } - // When we recover, we may see data whose validity *just* ended. Do not acquire it. - if let ValidationMode::Recover(ending_ce) = mode { - if query.re == Some(ending_ce) { - return Ok(()); - } - } - - query.ty = self.normalize_type_unerased(&query.ty); - trace!("{:?} on {:?}", mode, query); - - // Decide whether this type *owns* the memory it covers (like integers), or whether it - // just assembles pieces (that each own their memory) together to a larger whole. - // TODO: Currently, we don't acquire locks for padding and discriminants. We should. - let is_owning = match query.ty.sty { - TyInt(_) | TyUint(_) | TyRawPtr(_) | TyBool | TyFloat(_) | TyChar | TyStr | - TyRef(..) | TyFnPtr(..) | TyFnDef(..) | TyNever => true, - TyAdt(adt, _) if adt.is_box() => true, - TySlice(_) | TyAdt(_, _) | TyTuple(..) | TyClosure(..) | TyArray(..) | - TyDynamic(..) | TyGenerator(..) => false, - TyParam(_) | TyInfer(_) | TyProjection(_) | TyAnon(..) | TyError => { - bug!("I got an incomplete/unnormalized type for validation") - } - }; - if is_owning { - // We need to lock. So we need memory. So we have to force_acquire. - // Tracking the same state for locals not backed by memory would just duplicate too - // much machinery. - // FIXME: We ignore alignment. - let (ptr, extra) = self.force_allocation(query.lval.1)?.to_ptr_extra_aligned(); - // Determine the size - // FIXME: Can we reuse size_and_align_of_dst for Lvalues? - let len = match self.type_size(query.ty)? { - Some(size) => { - assert_eq!(extra, LvalueExtra::None, "Got a fat ptr to a sized type"); - size - } - None => { - // The only unsized typ we concider "owning" is TyStr. - assert_eq!( - query.ty.sty, - TyStr, - "Found a surprising unsized owning type" - ); - // The extra must be the length, in bytes. - match extra { - LvalueExtra::Length(len) => len, - _ => bug!("TyStr must have a length as extra"), - } - } - }; - // Handle locking - if len > 0 { - let ptr = ptr.to_ptr()?; - match query.mutbl { - MutImmutable => { - if mode.acquiring() { - self.memory.acquire_lock( - ptr, - len, - query.re, - AccessKind::Read, - )?; - } - } - // No releasing of read locks, ever. - MutMutable => { - match mode { - ValidationMode::Acquire => { - self.memory.acquire_lock( - ptr, - len, - query.re, - AccessKind::Write, - )? - } - ValidationMode::Recover(ending_ce) => { - self.memory.recover_write_lock( - ptr, - len, - &query.lval.0, - query.re, - ending_ce, - )? - } - ValidationMode::ReleaseUntil(suspended_ce) => { - self.memory.suspend_write_lock( - ptr, - len, - &query.lval.0, - suspended_ce, - )? - } - } - } - } - } - } - - let res = do catch { - match query.ty.sty { - TyInt(_) | TyUint(_) | TyRawPtr(_) => { - if mode.acquiring() { - // Make sure we can read this. - let val = self.read_lvalue(query.lval.1)?; - self.follow_by_ref_value(val, query.ty)?; - // FIXME: It would be great to rule out Undef here, but that doesn't actually work. - // Passing around undef data is a thing that e.g. Vec::extend_with does. - } - Ok(()) - } - TyBool | TyFloat(_) | TyChar => { - if mode.acquiring() { - let val = self.read_lvalue(query.lval.1)?; - let val = self.value_to_primval(ValTy { value: val, ty: query.ty })?; - val.to_bytes()?; - // TODO: Check if these are valid bool/float/codepoint/UTF-8 - } - Ok(()) - } - TyNever => err!(ValidationFailure(format!("The empty type is never valid."))), - TyRef(region, - ty::TypeAndMut { - ty: pointee_ty, - mutbl, - }) => { - let val = self.read_lvalue(query.lval.1)?; - // Sharing restricts our context - if mutbl == MutImmutable { - query.mutbl = MutImmutable; - } - // Inner lifetimes *outlive* outer ones, so only if we have no lifetime restriction yet, - // we record the region of this borrow to the context. - if query.re == None { - match *region { - ReScope(scope) => query.re = Some(scope), - // It is possible for us to encounter erased lifetimes here because the lifetimes in - // this functions' Subst will be erased. - _ => {} - } - } - self.validate_ptr(val, query.lval.0, pointee_ty, query.re, query.mutbl, mode) - } - TyAdt(adt, _) if adt.is_box() => { - let val = self.read_lvalue(query.lval.1)?; - self.validate_ptr(val, query.lval.0, query.ty.boxed_ty(), query.re, query.mutbl, mode) - } - TyFnPtr(_sig) => { - let ptr = self.read_lvalue(query.lval.1)? - .into_ptr(&self.memory)? - .to_ptr()?; - self.memory.get_fn(ptr)?; - // TODO: Check if the signature matches (should be the same check as what terminator/mod.rs already does on call?). - Ok(()) - } - TyFnDef(..) => { - // This is a zero-sized type with all relevant data sitting in the type. - // There is nothing to validate. - Ok(()) - } - - // Compound types - TyStr => { - // TODO: Validate strings - Ok(()) - } - TySlice(elem_ty) => { - let len = match query.lval.1 { - Lvalue::Ptr { extra: LvalueExtra::Length(len), .. } => len, - _ => { - bug!( - "acquire_valid of a TySlice given non-slice lvalue: {:?}", - query.lval - ) - } - }; - for i in 0..len { - let inner_lvalue = self.lvalue_index(query.lval.1, query.ty, i)?; - self.validate( - ValidationQuery { - lval: (query.lval.0.clone().index(i), inner_lvalue), - ty: elem_ty, - ..query - }, - mode, - )?; - } - Ok(()) - } - TyArray(elem_ty, len) => { - let len = len.val.to_const_int().unwrap().to_u64().unwrap(); - for i in 0..len { - let inner_lvalue = self.lvalue_index(query.lval.1, query.ty, i as u64)?; - self.validate( - ValidationQuery { - lval: (query.lval.0.clone().index(i as u64), inner_lvalue), - ty: elem_ty, - ..query - }, - mode, - )?; - } - Ok(()) - } - TyDynamic(_data, _region) => { - // Check that this is a valid vtable - let vtable = match query.lval.1 { - Lvalue::Ptr { extra: LvalueExtra::Vtable(vtable), .. } => vtable, - _ => { - bug!( - "acquire_valid of a TyDynamic given non-trait-object lvalue: {:?}", - query.lval - ) - } - }; - self.read_size_and_align_from_vtable(vtable)?; - // TODO: Check that the vtable contains all the function pointers we expect it to have. - // Trait objects cannot have any operations performed - // on them directly. We cannot, in general, even acquire any locks as the trait object *could* - // contain an UnsafeCell. If we call functions to get access to data, we will validate - // their return values. So, it doesn't seem like there's anything else to do. - Ok(()) - } - TyAdt(adt, subst) => { - if Some(adt.did) == self.tcx.lang_items().unsafe_cell_type() && - query.mutbl == MutImmutable - { - // No locks for shared unsafe cells. Also no other validation, the only field is private anyway. - return Ok(()); - } - - match adt.adt_kind() { - AdtKind::Enum => { - // TODO: Can we get the discriminant without forcing an allocation? - let ptr = self.force_allocation(query.lval.1)?.to_ptr()?; - let discr = self.read_discriminant_value(ptr, query.ty)?; - - // Get variant index for discriminant - let variant_idx = adt.discriminants(self.tcx).position(|variant_discr| { - variant_discr.to_u128_unchecked() == discr - }); - let variant_idx = match variant_idx { - Some(val) => val, - None => return err!(InvalidDiscriminant), - }; - let variant = &adt.variants[variant_idx]; - - if variant.fields.len() > 0 { - // Downcast to this variant, if needed - let lval = if adt.variants.len() > 1 { - ( - query.lval.0.downcast(adt, variant_idx), - self.eval_lvalue_projection( - query.lval.1, - query.ty, - &mir::ProjectionElem::Downcast(adt, variant_idx), - )?, - ) - } else { - query.lval - }; - - // Recursively validate the fields - self.validate_variant( - ValidationQuery { lval, ..query }, - variant, - subst, - mode, - ) - } else { - // No fields, nothing left to check. Downcasting may fail, e.g. in case of a CEnum. - Ok(()) - } - } - AdtKind::Struct => { - self.validate_variant(query, adt.struct_variant(), subst, mode) - } - AdtKind::Union => { - // No guarantees are provided for union types. - // TODO: Make sure that all access to union fields is unsafe; otherwise, we may have some checking to do (but what exactly?) - Ok(()) - } - } - } - TyTuple(ref types, _) => { - for (idx, field_ty) in types.iter().enumerate() { - let field = mir::Field::new(idx); - let field_lvalue = self.lvalue_field(query.lval.1, field, query.ty, field_ty)?; - self.validate( - ValidationQuery { - lval: (query.lval.0.clone().field(field), field_lvalue), - ty: field_ty, - ..query - }, - mode, - )?; - } - Ok(()) - } - TyClosure(def_id, ref closure_substs) => { - for (idx, field_ty) in closure_substs.upvar_tys(def_id, self.tcx).enumerate() { - let field = mir::Field::new(idx); - let field_lvalue = self.lvalue_field(query.lval.1, field, query.ty, field_ty)?; - self.validate( - ValidationQuery { - lval: (query.lval.0.clone().field(field), field_lvalue), - ty: field_ty, - ..query - }, - mode, - )?; - } - // TODO: Check if the signature matches (should be the same check as what terminator/mod.rs already does on call?). - // Is there other things we can/should check? Like vtable pointers? - Ok(()) - } - // FIXME: generators aren't validated right now - TyGenerator(..) => Ok(()), - _ => bug!("We already established that this is a type we support. ({})", query.ty), - } - }; - match res { - // ReleaseUntil(None) of an uninitalized variable is a NOP. This is needed because - // we have to release the return value of a function; due to destination-passing-style - // the callee may directly write there. - // TODO: Ideally we would know whether the destination is already initialized, and only - // release if it is. But of course that can't even always be statically determined. - Err(EvalError { kind: EvalErrorKind::ReadUndefBytes, .. }) - if mode == ValidationMode::ReleaseUntil(None) => { - return Ok(()); - } - res => res, - } - } -} diff --git a/src/librustc_mir/interpret/value.rs b/src/librustc_mir/interpret/value.rs deleted file mode 100644 index e052ec1e391c..000000000000 --- a/src/librustc_mir/interpret/value.rs +++ /dev/null @@ -1,405 +0,0 @@ -#![allow(unknown_lints)] - -use rustc::ty::layout::HasDataLayout; - -use super::{EvalResult, Memory, MemoryPointer, HasMemory, PointerArithmetic, Machine, PtrAndAlign}; - -pub(super) fn bytes_to_f32(bytes: u128) -> f32 { - f32::from_bits(bytes as u32) -} - -pub(super) fn bytes_to_f64(bytes: u128) -> f64 { - f64::from_bits(bytes as u64) -} - -pub(super) fn f32_to_bytes(f: f32) -> u128 { - f.to_bits() as u128 -} - -pub(super) fn f64_to_bytes(f: f64) -> u128 { - f.to_bits() as u128 -} - -/// A `Value` represents a single self-contained Rust value. -/// -/// A `Value` can either refer to a block of memory inside an allocation (`ByRef`) or to a primitve -/// value held directly, outside of any allocation (`ByVal`). For `ByRef`-values, we remember -/// whether the pointer is supposed to be aligned or not (also see Lvalue). -/// -/// For optimization of a few very common cases, there is also a representation for a pair of -/// primitive values (`ByValPair`). It allows Miri to avoid making allocations for checked binary -/// operations and fat pointers. This idea was taken from rustc's trans. -#[derive(Clone, Copy, Debug)] -pub enum Value { - ByRef(PtrAndAlign), - ByVal(PrimVal), - ByValPair(PrimVal, PrimVal), -} - -/// A wrapper type around `PrimVal` that cannot be turned back into a `PrimVal` accidentally. -/// This type clears up a few APIs where having a `PrimVal` argument for something that is -/// potentially an integer pointer or a pointer to an allocation was unclear. -/// -/// I (@oli-obk) believe it is less easy to mix up generic primvals and primvals that are just -/// the representation of pointers. Also all the sites that convert between primvals and pointers -/// are explicit now (and rare!) -#[derive(Clone, Copy, Debug)] -pub struct Pointer { - primval: PrimVal, -} - -impl<'tcx> Pointer { - pub fn null() -> Self { - PrimVal::Bytes(0).into() - } - pub fn to_ptr(self) -> EvalResult<'tcx, MemoryPointer> { - self.primval.to_ptr() - } - pub fn into_inner_primval(self) -> PrimVal { - self.primval - } - - pub fn signed_offset(self, i: i64, cx: C) -> EvalResult<'tcx, Self> { - let layout = cx.data_layout(); - match self.primval { - PrimVal::Bytes(b) => { - assert_eq!(b as u64 as u128, b); - Ok(Pointer::from( - PrimVal::Bytes(layout.signed_offset(b as u64, i)? as u128), - )) - } - PrimVal::Ptr(ptr) => ptr.signed_offset(i, layout).map(Pointer::from), - PrimVal::Undef => err!(ReadUndefBytes), - } - } - - pub fn offset(self, i: u64, cx: C) -> EvalResult<'tcx, Self> { - let layout = cx.data_layout(); - match self.primval { - PrimVal::Bytes(b) => { - assert_eq!(b as u64 as u128, b); - Ok(Pointer::from( - PrimVal::Bytes(layout.offset(b as u64, i)? as u128), - )) - } - PrimVal::Ptr(ptr) => ptr.offset(i, layout).map(Pointer::from), - PrimVal::Undef => err!(ReadUndefBytes), - } - } - - pub fn wrapping_signed_offset(self, i: i64, cx: C) -> EvalResult<'tcx, Self> { - let layout = cx.data_layout(); - match self.primval { - PrimVal::Bytes(b) => { - assert_eq!(b as u64 as u128, b); - Ok(Pointer::from(PrimVal::Bytes( - layout.wrapping_signed_offset(b as u64, i) as u128, - ))) - } - PrimVal::Ptr(ptr) => Ok(Pointer::from(ptr.wrapping_signed_offset(i, layout))), - PrimVal::Undef => err!(ReadUndefBytes), - } - } - - pub fn is_null(self) -> EvalResult<'tcx, bool> { - match self.primval { - PrimVal::Bytes(b) => Ok(b == 0), - PrimVal::Ptr(_) => Ok(false), - PrimVal::Undef => err!(ReadUndefBytes), - } - } - - pub fn to_value_with_len(self, len: u64) -> Value { - Value::ByValPair(self.primval, PrimVal::from_u128(len as u128)) - } - - pub fn to_value_with_vtable(self, vtable: MemoryPointer) -> Value { - Value::ByValPair(self.primval, PrimVal::Ptr(vtable)) - } - - pub fn to_value(self) -> Value { - Value::ByVal(self.primval) - } -} - -impl ::std::convert::From for Pointer { - fn from(primval: PrimVal) -> Self { - Pointer { primval } - } -} - -impl ::std::convert::From for Pointer { - fn from(ptr: MemoryPointer) -> Self { - PrimVal::Ptr(ptr).into() - } -} - -/// A `PrimVal` represents an immediate, primitive value existing outside of a -/// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in -/// size. Like a range of bytes in an `Allocation`, a `PrimVal` can either represent the raw bytes -/// of a simple value, a pointer into another `Allocation`, or be undefined. -#[derive(Clone, Copy, Debug)] -pub enum PrimVal { - /// The raw bytes of a simple value. - Bytes(u128), - - /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of - /// relocations, but a `PrimVal` is only large enough to contain one, so we just represent the - /// relocation and its associated offset together as a `MemoryPointer` here. - Ptr(MemoryPointer), - - /// An undefined `PrimVal`, for representing values that aren't safe to examine, but are safe - /// to copy around, just like undefined bytes in an `Allocation`. - Undef, -} - -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum PrimValKind { - I8, I16, I32, I64, I128, - U8, U16, U32, U64, U128, - F32, F64, - Ptr, FnPtr, - Bool, - Char, -} - -impl<'a, 'tcx: 'a> Value { - #[inline] - pub fn by_ref(ptr: Pointer) -> Self { - Value::ByRef(PtrAndAlign { ptr, aligned: true }) - } - - /// Convert the value into a pointer (or a pointer-sized integer). If the value is a ByRef, - /// this may have to perform a load. - pub fn into_ptr>( - &self, - mem: &Memory<'a, 'tcx, M>, - ) -> EvalResult<'tcx, Pointer> { - use self::Value::*; - Ok(match *self { - ByRef(PtrAndAlign { ptr, aligned }) => { - mem.read_maybe_aligned(aligned, |mem| mem.read_ptr_sized_unsigned(ptr.to_ptr()?))? - } - ByVal(ptr) | - ByValPair(ptr, _) => ptr, - }.into()) - } - - pub(super) fn into_ptr_vtable_pair>( - &self, - mem: &Memory<'a, 'tcx, M>, - ) -> EvalResult<'tcx, (Pointer, MemoryPointer)> { - use self::Value::*; - match *self { - ByRef(PtrAndAlign { - ptr: ref_ptr, - aligned, - }) => { - mem.read_maybe_aligned(aligned, |mem| { - let ptr = mem.read_ptr_sized_unsigned(ref_ptr.to_ptr()?)?.into(); - let vtable = mem.read_ptr_sized_unsigned( - ref_ptr.offset(mem.pointer_size(), mem.layout)?.to_ptr()?, - )?.to_ptr()?; - Ok((ptr, vtable)) - }) - } - - ByValPair(ptr, vtable) => Ok((ptr.into(), vtable.to_ptr()?)), - - ByVal(PrimVal::Undef) => err!(ReadUndefBytes), - _ => bug!("expected ptr and vtable, got {:?}", self), - } - } - - pub(super) fn into_slice>( - &self, - mem: &Memory<'a, 'tcx, M>, - ) -> EvalResult<'tcx, (Pointer, u64)> { - use self::Value::*; - match *self { - ByRef(PtrAndAlign { - ptr: ref_ptr, - aligned, - }) => { - mem.read_maybe_aligned(aligned, |mem| { - let ptr = mem.read_ptr_sized_unsigned(ref_ptr.to_ptr()?)?.into(); - let len = mem.read_ptr_sized_unsigned( - ref_ptr.offset(mem.pointer_size(), mem.layout)?.to_ptr()?, - )?.to_bytes()? as u64; - Ok((ptr, len)) - }) - } - ByValPair(ptr, val) => { - let len = val.to_u128()?; - assert_eq!(len as u64 as u128, len); - Ok((ptr.into(), len as u64)) - } - ByVal(PrimVal::Undef) => err!(ReadUndefBytes), - ByVal(_) => bug!("expected ptr and length, got {:?}", self), - } - } -} - -impl<'tcx> PrimVal { - pub fn from_u128(n: u128) -> Self { - PrimVal::Bytes(n) - } - - pub fn from_i128(n: i128) -> Self { - PrimVal::Bytes(n as u128) - } - - pub fn from_f32(f: f32) -> Self { - PrimVal::Bytes(f32_to_bytes(f)) - } - - pub fn from_f64(f: f64) -> Self { - PrimVal::Bytes(f64_to_bytes(f)) - } - - pub fn from_bool(b: bool) -> Self { - PrimVal::Bytes(b as u128) - } - - pub fn from_char(c: char) -> Self { - PrimVal::Bytes(c as u128) - } - - pub fn to_bytes(self) -> EvalResult<'tcx, u128> { - match self { - PrimVal::Bytes(b) => Ok(b), - PrimVal::Ptr(_) => err!(ReadPointerAsBytes), - PrimVal::Undef => err!(ReadUndefBytes), - } - } - - pub fn to_ptr(self) -> EvalResult<'tcx, MemoryPointer> { - match self { - PrimVal::Bytes(_) => err!(ReadBytesAsPointer), - PrimVal::Ptr(p) => Ok(p), - PrimVal::Undef => err!(ReadUndefBytes), - } - } - - pub fn is_bytes(self) -> bool { - match self { - PrimVal::Bytes(_) => true, - _ => false, - } - } - - pub fn is_ptr(self) -> bool { - match self { - PrimVal::Ptr(_) => true, - _ => false, - } - } - - pub fn is_undef(self) -> bool { - match self { - PrimVal::Undef => true, - _ => false, - } - } - - pub fn to_u128(self) -> EvalResult<'tcx, u128> { - self.to_bytes() - } - - pub fn to_u64(self) -> EvalResult<'tcx, u64> { - self.to_bytes().map(|b| { - assert_eq!(b as u64 as u128, b); - b as u64 - }) - } - - pub fn to_i32(self) -> EvalResult<'tcx, i32> { - self.to_bytes().map(|b| { - assert_eq!(b as i32 as u128, b); - b as i32 - }) - } - - pub fn to_i128(self) -> EvalResult<'tcx, i128> { - self.to_bytes().map(|b| b as i128) - } - - pub fn to_i64(self) -> EvalResult<'tcx, i64> { - self.to_bytes().map(|b| { - assert_eq!(b as i64 as u128, b); - b as i64 - }) - } - - pub fn to_f32(self) -> EvalResult<'tcx, f32> { - self.to_bytes().map(bytes_to_f32) - } - - pub fn to_f64(self) -> EvalResult<'tcx, f64> { - self.to_bytes().map(bytes_to_f64) - } - - pub fn to_bool(self) -> EvalResult<'tcx, bool> { - match self.to_bytes()? { - 0 => Ok(false), - 1 => Ok(true), - _ => err!(InvalidBool), - } - } -} - -impl PrimValKind { - pub fn is_int(self) -> bool { - use self::PrimValKind::*; - match self { - I8 | I16 | I32 | I64 | I128 | U8 | U16 | U32 | U64 | U128 => true, - _ => false, - } - } - - pub fn is_signed_int(self) -> bool { - use self::PrimValKind::*; - match self { - I8 | I16 | I32 | I64 | I128 => true, - _ => false, - } - } - - pub fn is_float(self) -> bool { - use self::PrimValKind::*; - match self { - F32 | F64 => true, - _ => false, - } - } - - pub fn from_uint_size(size: u64) -> Self { - match size { - 1 => PrimValKind::U8, - 2 => PrimValKind::U16, - 4 => PrimValKind::U32, - 8 => PrimValKind::U64, - 16 => PrimValKind::U128, - _ => bug!("can't make uint with size {}", size), - } - } - - pub fn from_int_size(size: u64) -> Self { - match size { - 1 => PrimValKind::I8, - 2 => PrimValKind::I16, - 4 => PrimValKind::I32, - 8 => PrimValKind::I64, - 16 => PrimValKind::I128, - _ => bug!("can't make int with size {}", size), - } - } - - pub fn is_ptr(self) -> bool { - use self::PrimValKind::*; - match self { - Ptr | FnPtr => true, - _ => false, - } - } -} diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs deleted file mode 100644 index c640932e50e2..000000000000 --- a/src/librustc_mir/lib.rs +++ /dev/null @@ -1,26 +0,0 @@ -#![feature( - i128_type, - rustc_private, - conservative_impl_trait, - never_type, - catch_expr, -)] - -// From rustc. -#[macro_use] -extern crate log; -extern crate log_settings; -#[macro_use] -extern crate rustc; -extern crate rustc_const_math; -extern crate rustc_data_structures; -extern crate syntax; - -// From crates.io. -extern crate byteorder; -#[macro_use] -extern crate lazy_static; -extern crate regex; -extern crate backtrace; - -pub mod interpret; From 8d546e8b9ae47ce7200db469cb8807f6df2dd3d3 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 6 Oct 2017 17:12:07 +0200 Subject: [PATCH 0004/5092] Use rustc's logging libraries in order to be able to log rustc::mir::interpret --- Cargo.lock | 96 ------------------------------------------------------ Cargo.toml | 3 -- 2 files changed, 99 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ecc1e85596c5..a66207a614f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,17 +5,6 @@ dependencies = [ "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "compiletest_rs 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "aho-corasick" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -75,15 +64,6 @@ name = "dtoa" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "env_logger" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "filetime" version = "0.1.10" @@ -102,11 +82,6 @@ name = "itoa" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "lazy_static" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "libc" version = "0.2.30" @@ -117,14 +92,6 @@ name = "log" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "log_settings" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "magenta" version = "0.1.1" @@ -142,14 +109,6 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "memchr" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "num-traits" version = "0.1.40" @@ -169,23 +128,6 @@ dependencies = [ "magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "regex" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex-syntax" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "rustc-serialize" version = "0.3.24" @@ -252,40 +194,12 @@ dependencies = [ "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "thread_local" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "unicode-xid" version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "unreachable" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "utf8-ranges" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [metadata] -"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d" "checksum cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "be1057b8462184f634c3a208ee35b0f935cfd94b694b26deadccd98732088d7b" @@ -294,22 +208,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" "checksum diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0a515461b6c8c08419850ced27bc29e86166dcdcde8fbe76f8b1f0589bb49472" "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" -"checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b" "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" "checksum getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "65922871abd2f101a2eb0eaebadc66668e54a87ad9c3dd82520b5f86ede5eff9" "checksum itoa 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f74cf6ca1bdbc28496a2b9798ab7fccc2ca5a42cace95bb2b219577216a5fb90" -"checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" "checksum libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)" = "2370ca07ec338939e356443dac2296f581453c35fe1e3a3ed06023c49435f915" "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" -"checksum log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3d382732ea0fbc09790c4899db3255bdea0fc78b54bf234bd18a63bb603915b6" "checksum magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf0336886480e671965f794bc9b6fce88503563013d1bfb7a502c81fe3ac527" "checksum magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40d014c7011ac470ae28e2f76a02bfea4a8480f73e701353b49ad7a8d75f4699" -"checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" "checksum num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "99843c856d68d8b4313b03a17e33c4bb42ae8f6610ea81b28abe076ac721b9b0" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "eb250fd207a4729c976794d03db689c9be1d634ab5a1c9da9492a13d8fecbcdf" -"checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b" -"checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f7726f29ddf9731b17ff113c461e362c381d9d69433f79de4f3dd572488823e9" "checksum serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cf823e706be268e73e7747b147aa31c8f633ab4ba31f115efb57e5047c3a76dd" @@ -318,8 +226,4 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6" -"checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" -"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" -"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" diff --git a/Cargo.toml b/Cargo.toml index 34cbfcc03a2f..19ba30eb5486 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,9 +23,6 @@ path = "miri/lib.rs" [dependencies] byteorder = { version = "1.1", features = ["i128"]} -env_logger = "0.4.3" -log = "0.3.6" -log_settings = "0.1.1" cargo_metadata = { version = "0.2", optional = true } [features] From 072c02f9a3e1767a7b9121ef5217415bbbc8711f Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 6 Oct 2017 17:12:32 +0200 Subject: [PATCH 0005/5092] Use numbers instead of indentations Noone can differentiate between 8 and 9 spaces if they aren't aligned --- miri/bin/miri.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/miri/bin/miri.rs b/miri/bin/miri.rs index d38f63610a0e..6ea1fac605e1 100644 --- a/miri/bin/miri.rs +++ b/miri/bin/miri.rs @@ -193,14 +193,13 @@ fn resource_limits_from_attributes(state: &CompileState) -> miri::ResourceLimits fn init_logger() { let format = |record: &log::LogRecord| { if record.level() == log::LogLevel::Trace { - // prepend spaces to indent the final string + // prepend frame number let indentation = log_settings::settings().indentation; format!( - "{lvl}:{module}:{indent: Date: Thu, 12 Oct 2017 11:13:34 +0200 Subject: [PATCH 0006/5092] Use host floats for the intrinsics that we don't have soft float impls for --- miri/intrinsic.rs | 58 +++++++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index b41a75351971..aa17422159c4 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -245,7 +245,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" => { - let f = self.value_to_primval(args[0])?.to_f32()?; + let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = f32::from_bits(f as u32); let f = match intrinsic_name { "sinf32" => f.sin(), "fabsf32" => f.abs(), @@ -261,12 +262,13 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "truncf32" => f.trunc(), _ => bug!(), }; - self.write_primval(dest, PrimVal::from_f32(f), dest_ty)?; + self.write_primval(dest, PrimVal::Bytes(f.to_bits() as u128), dest_ty)?; } "sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" | "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" => { - let f = self.value_to_primval(args[0])?.to_f64()?; + let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = f64::from_bits(f as u64); let f = match intrinsic_name { "sinf64" => f.sin(), "fabsf64" => f.abs(), @@ -282,7 +284,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "truncf64" => f.trunc(), _ => bug!(), }; - self.write_primval(dest, PrimVal::from_f64(f), dest_ty)?; + self.write_primval(dest, PrimVal::Bytes(f.to_bits() as u128), dest_ty)?; } "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { @@ -413,63 +415,75 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> } "powf32" => { - let f = self.value_to_primval(args[0])?.to_f32()?; - let f2 = self.value_to_primval(args[1])?.to_f32()?; + let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = f32::from_bits(f as u32); + let f2 = self.value_to_primval(args[1])?.to_bytes()?; + let f2 = f32::from_bits(f2 as u32); self.write_primval( dest, - PrimVal::from_f32(f.powf(f2)), + PrimVal::Bytes(f.powf(f2).to_bits() as u128), dest_ty, )?; } "powf64" => { - let f = self.value_to_primval(args[0])?.to_f64()?; - let f2 = self.value_to_primval(args[1])?.to_f64()?; + let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = f64::from_bits(f as u64); + let f2 = self.value_to_primval(args[1])?.to_bytes()?; + let f2 = f64::from_bits(f2 as u64); self.write_primval( dest, - PrimVal::from_f64(f.powf(f2)), + PrimVal::Bytes(f.powf(f2).to_bits() as u128), dest_ty, )?; } "fmaf32" => { - let a = self.value_to_primval(args[0])?.to_f32()?; - let b = self.value_to_primval(args[1])?.to_f32()?; - let c = self.value_to_primval(args[2])?.to_f32()?; + let a = self.value_to_primval(args[0])?.to_bytes()?; + let a = f32::from_bits(a as u32); + let b = self.value_to_primval(args[1])?.to_bytes()?; + let b = f32::from_bits(b as u32); + let c = self.value_to_primval(args[2])?.to_bytes()?; + let c = f32::from_bits(c as u32); self.write_primval( dest, - PrimVal::from_f32(a * b + c), + PrimVal::Bytes((a * b + c).to_bits() as u128), dest_ty, )?; } "fmaf64" => { - let a = self.value_to_primval(args[0])?.to_f64()?; - let b = self.value_to_primval(args[1])?.to_f64()?; - let c = self.value_to_primval(args[2])?.to_f64()?; + let a = self.value_to_primval(args[0])?.to_bytes()?; + let a = f64::from_bits(a as u64); + let b = self.value_to_primval(args[1])?.to_bytes()?; + let b = f64::from_bits(b as u64); + let c = self.value_to_primval(args[2])?.to_bytes()?; + let c = f64::from_bits(c as u64); self.write_primval( dest, - PrimVal::from_f64(a * b + c), + PrimVal::Bytes((a * b + c).to_bits() as u128), dest_ty, )?; } "powif32" => { - let f = self.value_to_primval(args[0])?.to_f32()?; + let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = f32::from_bits(f as u32); let i = self.value_to_primval(args[1])?.to_i128()?; self.write_primval( dest, - PrimVal::from_f32(f.powi(i as i32)), + PrimVal::Bytes(f.powi(i as i32).to_bits() as u128), dest_ty, )?; } "powif64" => { - let f = self.value_to_primval(args[0])?.to_f64()?; + let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = f64::from_bits(f as u64); let i = self.value_to_primval(args[1])?.to_i128()?; self.write_primval( dest, - PrimVal::from_f64(f.powi(i as i32)), + PrimVal::Bytes(f.powi(i as i32).to_bits() as u128), dest_ty, )?; } From 042430270f6c1561f6496359bb488d2547672f00 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 12 Oct 2017 11:13:56 +0200 Subject: [PATCH 0007/5092] repeat expressions abort due to OOM instead of execution time exhaustion --- tests/compile-fail/repeat2.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile-fail/repeat2.rs b/tests/compile-fail/repeat2.rs index d489342b8599..61aa855a798f 100644 --- a/tests/compile-fail/repeat2.rs +++ b/tests/compile-fail/repeat2.rs @@ -1,5 +1,5 @@ fn main() { let data: [u8; 1024*1024*1024] = [42; 1024*1024*1024]; - //~^ ERROR: reached the configured maximum execution time + //~^ ERROR: tried to allocate assert_eq!(data.len(), 1024*1024*1024); } From 25e0f5b5db8f7770858f3807e4873873b5773dd6 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 16 Oct 2017 16:21:49 +0200 Subject: [PATCH 0008/5092] Rustup --- miri/bin/miri.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri/bin/miri.rs b/miri/bin/miri.rs index 6ea1fac605e1..d74c05c0462d 100644 --- a/miri/bin/miri.rs +++ b/miri/bin/miri.rs @@ -116,7 +116,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { let did = self.1.hir.body_owner_def_id(body_id); println!( "running test: {}", - self.1.hir.def_path(did).to_string(self.1) + self.1.def_path_debug_str(did), ); miri::eval_main(self.1, did, None, self.0); self.2.session.abort_if_errors(); From 6dbfe23c4d1af109c894ff9d7d5da97c025584e5 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 2 Nov 2017 11:15:50 +0100 Subject: [PATCH 0009/5092] Rustup --- Cargo.lock | 229 ------------------------------------------------ miri/fn_call.rs | 4 +- miri/lib.rs | 2 +- 3 files changed, 3 insertions(+), 232 deletions(-) delete mode 100644 Cargo.lock diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index a66207a614f7..000000000000 --- a/Cargo.lock +++ /dev/null @@ -1,229 +0,0 @@ -[root] -name = "miri" -version = "0.1.0" -dependencies = [ - "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "compiletest_rs 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bitflags" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "byteorder" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "cargo_metadata" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "compiletest_rs" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "conv" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "custom_derive" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "diff" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "dtoa" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "filetime" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "getopts" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "itoa" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libc" -version = "0.2.30" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "log" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "magenta" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "magenta-sys" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-traits" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "quote" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rand" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", - "magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rustc-serialize" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "serde" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "serde_derive" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_derive_internals" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", - "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_json" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "syn" -version = "0.11.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "synom" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tempdir" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-xid" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" -"checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d" -"checksum cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "be1057b8462184f634c3a208ee35b0f935cfd94b694b26deadccd98732088d7b" -"checksum compiletest_rs 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "86f4663adfd113e17109c35c2067194eca782a5baf9c90f4696ca13d04631adb" -"checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299" -"checksum custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" -"checksum diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0a515461b6c8c08419850ced27bc29e86166dcdcde8fbe76f8b1f0589bb49472" -"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" -"checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" -"checksum getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "65922871abd2f101a2eb0eaebadc66668e54a87ad9c3dd82520b5f86ede5eff9" -"checksum itoa 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f74cf6ca1bdbc28496a2b9798ab7fccc2ca5a42cace95bb2b219577216a5fb90" -"checksum libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)" = "2370ca07ec338939e356443dac2296f581453c35fe1e3a3ed06023c49435f915" -"checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" -"checksum magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf0336886480e671965f794bc9b6fce88503563013d1bfb7a502c81fe3ac527" -"checksum magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40d014c7011ac470ae28e2f76a02bfea4a8480f73e701353b49ad7a8d75f4699" -"checksum num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "99843c856d68d8b4313b03a17e33c4bb42ae8f6610ea81b28abe076ac721b9b0" -"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" -"checksum rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "eb250fd207a4729c976794d03db689c9be1d634ab5a1c9da9492a13d8fecbcdf" -"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" -"checksum serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f7726f29ddf9731b17ff113c461e362c381d9d69433f79de4f3dd572488823e9" -"checksum serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cf823e706be268e73e7747b147aa31c8f633ab4ba31f115efb57e5047c3a76dd" -"checksum serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37aee4e0da52d801acfbc0cc219eb1eda7142112339726e427926a6f6ee65d3a" -"checksum serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "48b04779552e92037212c3615370f6bd57a40ebba7f20e554ff9f55e41a69a7b" -"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" -"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" -"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6" -"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" diff --git a/miri/fn_call.rs b/miri/fn_call.rs index 77a22ac9c35f..6c393ded638d 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -381,9 +381,9 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> promoted: None, }; // compute global if not cached - let val = match self.globals.get(&cid).cloned() { + let val = match self.tcx.interpret_interner.borrow().get_cached(cid) { Some(ptr) => ptr, - None => eval_body(self.tcx, instance, ty::ParamEnv::empty(traits::Reveal::All))?.0, + None => eval_body(self.tcx, instance, ty::ParamEnv::empty(traits::Reveal::All)).0?.0, }; let val = self.value_to_primval(ValTy { value: Value::ByRef(val), ty: args[0].ty })?.to_u64()?; if val == name { diff --git a/miri/lib.rs b/miri/lib.rs index 27bd3d5939f3..6e8571556602 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -301,7 +301,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { )?; ecx.memory.write_ptr_sized_unsigned(ptr, PrimVal::Bytes(0))?; ecx.memory.mark_static_initalized(ptr.alloc_id, mutability)?; - ecx.globals.insert( + ecx.tcx.interpret_interner.borrow_mut().cache( GlobalId { instance, promoted: None, From a107f14ed8abee5a4e0b3776ca55fe92438cccfd Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 21 Nov 2017 13:32:40 +0100 Subject: [PATCH 0010/5092] Rustup after layout optimizations --- miri/fn_call.rs | 11 +++-- miri/intrinsic.rs | 102 +++++++++++++++++++++++----------------------- miri/lib.rs | 9 ++-- 3 files changed, 63 insertions(+), 59 deletions(-) diff --git a/miri/fn_call.rs b/miri/fn_call.rs index 6c393ded638d..4c17b4db3307 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -45,6 +45,8 @@ pub trait EvalContextExt<'tcx> { span: Span, sig: ty::FnSig<'tcx>, ) -> EvalResult<'tcx, bool>; + + fn write_null(&mut self, dest: Lvalue, dest_ty: Ty<'tcx>) -> EvalResult<'tcx>; } impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> { @@ -416,10 +418,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> // Figure out how large a pthread TLS key actually is. This is libc::pthread_key_t. let key_type = args[0].ty.builtin_deref(true, ty::LvaluePreference::NoPreference) .ok_or(EvalErrorKind::AbiViolation("Wrong signature used for pthread_key_create: First argument must be a raw pointer.".to_owned()))?.ty; - let key_size = { - let layout = self.type_layout(key_type)?; - layout.size(&self.tcx.data_layout) - }; + let key_size = self.type_layout(key_type)?.size; // Create key and write it into the memory where key_ptr wants it let key = self.memory.create_tls_key(dtor) as u128; @@ -655,4 +654,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> self.goto_block(dest_block); return Ok(()); } + + fn write_null(&mut self, dest: Lvalue, dest_ty: Ty<'tcx>) -> EvalResult<'tcx> { + self.write_primval(dest, PrimVal::Bytes(0), dest_ty) + } } diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index aa17422159c4..79dc3c7fe2ab 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -1,7 +1,7 @@ use rustc::mir; use rustc::traits::Reveal; -use rustc::ty::layout::Layout; -use rustc::ty::{self, Ty}; +use rustc::ty::layout::TyLayout; +use rustc::ty; use rustc::mir::interpret::{EvalResult, Lvalue, LvalueExtra, PrimVal, PrimValKind, Value, Pointer, HasMemory, AccessKind, EvalContext, PtrAndAlign, ValTy}; @@ -14,8 +14,7 @@ pub trait EvalContextExt<'tcx> { instance: ty::Instance<'tcx>, args: &[ValTy<'tcx>], dest: Lvalue, - dest_ty: Ty<'tcx>, - dest_layout: &'tcx Layout, + dest_layout: TyLayout<'tcx>, target: mir::BasicBlock, ) -> EvalResult<'tcx>; } @@ -26,8 +25,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> instance: ty::Instance<'tcx>, args: &[ValTy<'tcx>], dest: Lvalue, - dest_ty: Ty<'tcx>, - dest_layout: &'tcx Layout, + dest_layout: TyLayout<'tcx>, target: mir::BasicBlock, ) -> EvalResult<'tcx> { let substs = instance.substs; @@ -37,7 +35,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "align_offset" => { // FIXME: return a real value in case the target allocation has an // alignment bigger than the one requested - self.write_primval(dest, PrimVal::Bytes(u128::max_value()), dest_ty)?; + self.write_primval(dest, PrimVal::Bytes(u128::max_value()), dest_layout.ty)?; }, "add_with_overflow" => { @@ -46,7 +44,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> args[0], args[1], dest, - dest_ty, + dest_layout.ty, )? } @@ -56,7 +54,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> args[0], args[1], dest, - dest_ty, + dest_layout.ty, )? } @@ -66,7 +64,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> args[0], args[1], dest, - dest_ty, + dest_layout.ty, )? } @@ -74,7 +72,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> let offset = self.value_to_primval(args[1])?.to_i128()? as i64; let ptr = args[0].into_ptr(&self.memory)?; let result_ptr = self.wrapping_pointer_offset(ptr, substs.type_at(0), offset)?; - self.write_ptr(dest, result_ptr, dest_ty)?; + self.write_ptr(dest, result_ptr, dest_layout.ty)?; } "assume" => { @@ -139,8 +137,11 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> Value::ByValPair(..) => bug!("atomic_cxchg doesn't work with nonprimitives"), }; let (val, _) = self.binary_op(mir::BinOp::Eq, old, ty, expect_old, ty)?; - let dest = self.force_allocation(dest)?.to_ptr()?; - self.write_pair_to_ptr(old, val, dest, dest_ty)?; + let valty = ValTy { + value: Value::ByValPair(old, val), + ty: dest_layout.ty, + }; + self.write_value(valty, dest)?; self.write_primval( Lvalue::from_primval_ptr(ptr), change, @@ -238,9 +239,10 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "discriminant_value" => { let ty = substs.type_at(0); - let adt_ptr = args[0].into_ptr(&self.memory)?.to_ptr()?; - let discr_val = self.read_discriminant_value(adt_ptr, ty)?; - self.write_primval(dest, PrimVal::Bytes(discr_val), dest_ty)?; + let adt_ptr = args[0].into_ptr(&self.memory)?; + let lval = Lvalue::from_primval_ptr(adt_ptr); + let discr_val = self.read_discriminant_value(lval, ty)?; + self.write_primval(dest, PrimVal::Bytes(discr_val), dest_layout.ty)?; } "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | @@ -262,7 +264,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "truncf32" => f.trunc(), _ => bug!(), }; - self.write_primval(dest, PrimVal::Bytes(f.to_bits() as u128), dest_ty)?; + self.write_primval(dest, PrimVal::Bytes(f.to_bits() as u128), dest_layout.ty)?; } "sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" | @@ -284,7 +286,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "truncf64" => f.trunc(), _ => bug!(), }; - self.write_primval(dest, PrimVal::Bytes(f.to_bits() as u128), dest_ty)?; + self.write_primval(dest, PrimVal::Bytes(f.to_bits() as u128), dest_layout.ty)?; } "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { @@ -300,13 +302,13 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> _ => bug!(), }; let result = self.binary_op(op, a, ty, b, ty)?; - self.write_primval(dest, result.0, dest_ty)?; + self.write_primval(dest, result.0, dest_layout.ty)?; } "likely" | "unlikely" | "forget" => {} "init" => { - let size = self.type_size(dest_ty)?.expect("cannot zero unsized value"); + let size = self.type_size(dest_layout.ty)?.expect("cannot zero unsized value"); let init = |this: &mut Self, val: Value| { let zero_val = match val { Value::ByRef(PtrAndAlign { ptr, .. }) => { @@ -316,10 +318,10 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> } // TODO(solson): Revisit this, it's fishy to check for Undef here. Value::ByVal(PrimVal::Undef) => { - match this.ty_to_primval_kind(dest_ty) { + match this.ty_to_primval_kind(dest_layout.ty) { Ok(_) => Value::ByVal(PrimVal::Bytes(0)), Err(_) => { - let ptr = this.alloc_ptr_with_substs(dest_ty, substs)?; + let ptr = this.alloc_ptr_with_substs(dest_layout.ty, substs)?; let ptr = Pointer::from(PrimVal::Ptr(ptr)); this.memory.write_repeat(ptr, 0, size)?; Value::by_ref(ptr) @@ -349,15 +351,15 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> let elem_ty = substs.type_at(0); let elem_align = self.type_align(elem_ty)?; let align_val = PrimVal::from_u128(elem_align as u128); - self.write_primval(dest, align_val, dest_ty)?; + self.write_primval(dest, align_val, dest_layout.ty)?; } "pref_align_of" => { let ty = substs.type_at(0); let layout = self.type_layout(ty)?; - let align = layout.align(&self.tcx.data_layout).pref(); + let align = layout.align.pref(); let align_val = PrimVal::from_u128(align as u128); - self.write_primval(dest, align_val, dest_ty)?; + self.write_primval(dest, align_val, dest_layout.ty)?; } "move_val_init" => { @@ -373,7 +375,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> self.write_primval( dest, PrimVal::from_bool(needs_drop), - dest_ty, + dest_layout.ty, )?; } @@ -381,7 +383,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> let offset = self.value_to_primval(args[1])?.to_i128()? as i64; let ptr = args[0].into_ptr(&self.memory)?; let result_ptr = self.pointer_offset(ptr, substs.type_at(0), offset)?; - self.write_ptr(dest, result_ptr, dest_ty)?; + self.write_ptr(dest, result_ptr, dest_layout.ty)?; } "overflowing_sub" => { @@ -390,7 +392,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> args[0], args[1], dest, - dest_ty, + dest_layout.ty, )?; } @@ -400,7 +402,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> args[0], args[1], dest, - dest_ty, + dest_layout.ty, )?; } @@ -410,7 +412,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> args[0], args[1], dest, - dest_ty, + dest_layout.ty, )?; } @@ -422,7 +424,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> self.write_primval( dest, PrimVal::Bytes(f.powf(f2).to_bits() as u128), - dest_ty, + dest_layout.ty, )?; } @@ -434,7 +436,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> self.write_primval( dest, PrimVal::Bytes(f.powf(f2).to_bits() as u128), - dest_ty, + dest_layout.ty, )?; } @@ -448,7 +450,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> self.write_primval( dest, PrimVal::Bytes((a * b + c).to_bits() as u128), - dest_ty, + dest_layout.ty, )?; } @@ -462,7 +464,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> self.write_primval( dest, PrimVal::Bytes((a * b + c).to_bits() as u128), - dest_ty, + dest_layout.ty, )?; } @@ -473,7 +475,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> self.write_primval( dest, PrimVal::Bytes(f.powi(i as i32).to_bits() as u128), - dest_ty, + dest_layout.ty, )?; } @@ -484,7 +486,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> self.write_primval( dest, PrimVal::Bytes(f.powi(i as i32).to_bits() as u128), - dest_ty, + dest_layout.ty, )?; } @@ -493,7 +495,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> let size = self.type_size(ty)?.expect( "size_of intrinsic called on unsized value", ) as u128; - self.write_primval(dest, PrimVal::from_u128(size), dest_ty)?; + self.write_primval(dest, PrimVal::from_u128(size), dest_layout.ty)?; } "size_of_val" => { @@ -501,8 +503,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> let (size, _) = self.size_and_align_of_dst(ty, args[0].value)?; self.write_primval( dest, - PrimVal::from_u128(size as u128), - dest_ty, + PrimVal::from_u128(size.bytes() as u128), + dest_layout.ty, )?; } @@ -512,8 +514,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> let (_, align) = self.size_and_align_of_dst(ty, args[0].value)?; self.write_primval( dest, - PrimVal::from_u128(align as u128), - dest_ty, + PrimVal::from_u128(align.pref() as u128), + dest_layout.ty, )?; } @@ -521,12 +523,12 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> let ty = substs.type_at(0); let ty_name = ty.to_string(); let value = self.str_to_value(&ty_name)?; - self.write_value(ValTy { value, ty: dest_ty }, dest)?; + self.write_value(ValTy { value, ty: dest_layout.ty }, dest)?; } "type_id" => { let ty = substs.type_at(0); let n = self.tcx.type_id_hash(ty); - self.write_primval(dest, PrimVal::Bytes(n as u128), dest_ty)?; + self.write_primval(dest, PrimVal::Bytes(n as u128), dest_layout.ty)?; } "transmute" => { @@ -542,7 +544,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> } "unchecked_shl" => { - let bits = self.type_size(dest_ty)?.expect( + let bits = self.type_size(dest_layout.ty)?.expect( "intrinsic can't be called on unsized type", ) as u128 * 8; let rhs = self.value_to_primval(args[1])? @@ -557,12 +559,12 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> args[0], args[1], dest, - dest_ty, + dest_layout.ty, )?; } "unchecked_shr" => { - let bits = self.type_size(dest_ty)?.expect( + let bits = self.type_size(dest_layout.ty)?.expect( "intrinsic can't be called on unsized type", ) as u128 * 8; let rhs = self.value_to_primval(args[1])? @@ -577,7 +579,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> args[0], args[1], dest, - dest_ty, + dest_layout.ty, )?; } @@ -592,7 +594,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> args[0], args[1], dest, - dest_ty, + dest_layout.ty, )?; } @@ -607,12 +609,12 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> args[0], args[1], dest, - dest_ty, + dest_layout.ty, )?; } "uninit" => { - let size = dest_layout.size(&self.tcx.data_layout).bytes(); + let size = dest_layout.size.bytes(); let uninit = |this: &mut Self, val: Value| match val { Value::ByRef(PtrAndAlign { ptr, .. }) => { this.memory.mark_definedness(ptr, size, false)?; diff --git a/miri/lib.rs b/miri/lib.rs index 6e8571556602..e5566bfe9471 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -11,7 +11,7 @@ extern crate rustc; extern crate syntax; use rustc::ty::{self, TyCtxt}; -use rustc::ty::layout::Layout; +use rustc::ty::layout::TyLayout; use rustc::hir::def_id::DefId; use rustc::mir; use rustc::traits; @@ -50,7 +50,7 @@ pub fn eval_main<'a, 'tcx: 'a>( let main_mir = ecx.load_mir(main_instance.def)?; let mut cleanup_ptr = None; // Pointer to be deallocated when we are done - if !main_mir.return_ty.is_nil() || main_mir.arg_count != 0 { + if !main_mir.return_ty().is_nil() || main_mir.arg_count != 0 { return err!(Unimplemented( "miri does not support main functions without `fn()` type signatures" .to_owned(), @@ -208,11 +208,10 @@ impl<'tcx> Machine<'tcx> for Evaluator { instance: ty::Instance<'tcx>, args: &[ValTy<'tcx>], dest: Lvalue, - dest_ty: ty::Ty<'tcx>, - dest_layout: &'tcx Layout, + dest_layout: TyLayout<'tcx>, target: mir::BasicBlock, ) -> EvalResult<'tcx> { - ecx.call_intrinsic(instance, args, dest, dest_ty, dest_layout, target) + ecx.call_intrinsic(instance, args, dest, dest_layout, target) } fn try_ptr_op<'a>( From 4e8b9451ab940b976b56072f3a341c6e93cbdc29 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 27 Nov 2017 14:31:51 +0100 Subject: [PATCH 0011/5092] Update error messages --- tests/compile-fail/deallocate-bad-alignment.rs | 2 +- tests/compile-fail/deallocate-bad-size.rs | 2 +- tests/compile-fail/invalid_bool.rs | 4 ++-- tests/compile-fail/match_char.rs | 4 ++-- tests/compile-fail/reallocate-bad-alignment-2.rs | 2 +- tests/compile-fail/reallocate-bad-alignment.rs | 2 +- tests/compile-fail/reallocate-bad-size.rs | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/compile-fail/deallocate-bad-alignment.rs b/tests/compile-fail/deallocate-bad-alignment.rs index c1ae7477c81a..b64740de81f4 100644 --- a/tests/compile-fail/deallocate-bad-alignment.rs +++ b/tests/compile-fail/deallocate-bad-alignment.rs @@ -5,7 +5,7 @@ extern crate alloc; use alloc::heap::Heap; use alloc::allocator::*; -// error-pattern: tried to deallocate or reallocate using incorrect alignment or size +// error-pattern: incorrect alloc info: expected size 1 and align 2, got size 1 and align 1 fn main() { unsafe { diff --git a/tests/compile-fail/deallocate-bad-size.rs b/tests/compile-fail/deallocate-bad-size.rs index 5577f10736d2..f5b82f65d2af 100644 --- a/tests/compile-fail/deallocate-bad-size.rs +++ b/tests/compile-fail/deallocate-bad-size.rs @@ -5,7 +5,7 @@ extern crate alloc; use alloc::heap::Heap; use alloc::allocator::*; -// error-pattern: tried to deallocate or reallocate using incorrect alignment or size +// error-pattern: incorrect alloc info: expected size 2 and align 1, got size 1 and align 1 fn main() { unsafe { diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index c30c9b439a46..9de2630797ec 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -1,4 +1,4 @@ fn main() { - let b = unsafe { std::mem::transmute::(2) }; //~ ERROR: invalid boolean value read - if b { unreachable!() } else { unreachable!() } + let b = unsafe { std::mem::transmute::(2) }; + if b { unreachable!() } else { unreachable!() } //~ ERROR: invalid boolean value read } diff --git a/tests/compile-fail/match_char.rs b/tests/compile-fail/match_char.rs index 4fee6e692bad..a91c7fef6aa1 100644 --- a/tests/compile-fail/match_char.rs +++ b/tests/compile-fail/match_char.rs @@ -1,7 +1,7 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); - match unsafe { std::mem::transmute::(-1) } { //~ERROR tried to interpret an invalid 32-bit value as a char: 4294967295 - 'a' => {}, + match unsafe { std::mem::transmute::(-1) } { + 'a' => {}, //~ERROR tried to interpret an invalid 32-bit value as a char: 4294967295 'b' => {}, _ => {}, } diff --git a/tests/compile-fail/reallocate-bad-alignment-2.rs b/tests/compile-fail/reallocate-bad-alignment-2.rs index cd6214440ff2..fae8246c5d29 100644 --- a/tests/compile-fail/reallocate-bad-alignment-2.rs +++ b/tests/compile-fail/reallocate-bad-alignment-2.rs @@ -5,7 +5,7 @@ extern crate alloc; use alloc::heap::Heap; use alloc::allocator::*; -// error-pattern: tried to deallocate or reallocate using incorrect alignment or size +// error-pattern: incorrect alloc info: expected size 1 and align 2, got size 1 and align 1 fn main() { unsafe { diff --git a/tests/compile-fail/reallocate-bad-alignment.rs b/tests/compile-fail/reallocate-bad-alignment.rs index da5fe1d81909..6a928de07eec 100644 --- a/tests/compile-fail/reallocate-bad-alignment.rs +++ b/tests/compile-fail/reallocate-bad-alignment.rs @@ -5,7 +5,7 @@ extern crate alloc; use alloc::heap::Heap; use alloc::allocator::*; -// error-pattern: tried to deallocate or reallocate using incorrect alignment or size +// error-pattern: incorrect alloc info: expected size 1 and align 1, got size 1 and align 2 fn main() { unsafe { diff --git a/tests/compile-fail/reallocate-bad-size.rs b/tests/compile-fail/reallocate-bad-size.rs index 953178742c46..d57c610d9337 100644 --- a/tests/compile-fail/reallocate-bad-size.rs +++ b/tests/compile-fail/reallocate-bad-size.rs @@ -5,7 +5,7 @@ extern crate alloc; use alloc::heap::Heap; use alloc::allocator::*; -// error-pattern: tried to deallocate or reallocate using incorrect alignment or size +// error-pattern: incorrect alloc info: expected size 2 and align 1, got size 1 and align 1 fn main() { unsafe { From ab0a805440ccd4d254d77b6214440e5382f91307 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 27 Nov 2017 14:32:09 +0100 Subject: [PATCH 0012/5092] Use correct alignment --- miri/intrinsic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index 79dc3c7fe2ab..ccc2a9dd2574 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -514,7 +514,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> let (_, align) = self.size_and_align_of_dst(ty, args[0].value)?; self.write_primval( dest, - PrimVal::from_u128(align.pref() as u128), + PrimVal::from_u128(align.abi() as u128), dest_layout.ty, )?; } From fd77411a1841f4b19ee80c5f1c623b605ac22594 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 30 Nov 2017 12:49:19 +0100 Subject: [PATCH 0013/5092] Compiler bug --- tests/run-pass/{packed_struct.rs => packed_struct.rs_broken} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/run-pass/{packed_struct.rs => packed_struct.rs_broken} (100%) diff --git a/tests/run-pass/packed_struct.rs b/tests/run-pass/packed_struct.rs_broken similarity index 100% rename from tests/run-pass/packed_struct.rs rename to tests/run-pass/packed_struct.rs_broken From bf26b96dc7506b2f1fac9265489a6f3cd4d99dfc Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 5 Dec 2017 17:06:03 +0100 Subject: [PATCH 0014/5092] Update to latest rustc changes --- .gitignore | 1 + Cargo.toml | 2 +- miri/fn_call.rs | 2 +- miri/lib.rs | 10 +++++----- miri/tls.rs | 2 +- tests/compile-fail/invalid_bool.rs | 4 ++-- tests/compile-fail/match_char.rs | 4 ++-- tests/compile-fail/never_say_never.rs | 2 +- tests/compile-fail/reference_to_packed.rs | 2 +- tests/run-pass/issue-36278-prefix-nesting.rs | 3 +++ 10 files changed, 18 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index d32d9eb99afd..dcca7ec10a30 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ tex/*/out *.dot *.mir *.rs.bk +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml index 19ba30eb5486..9d1f615e8d1b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ cargo_metadata = { version = "0.2", optional = true } cargo_miri = ["cargo_metadata"] [dev-dependencies] -compiletest_rs = { version = "0.3", features = ["tmp"] } +compiletest_rs = { version = "0.3.3", features = ["tmp"] } [workspace] exclude = ["xargo", "cargo-miri-test", "rustc_tests"] diff --git a/miri/fn_call.rs b/miri/fn_call.rs index 4c17b4db3307..adb235edb67b 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -187,7 +187,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> .to_owned(), ), )?; - let arg_dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?; + let arg_dest = self.eval_lvalue(&mir::Place::Local(arg_local))?; self.write_ptr(arg_dest, data, u8_ptr_ty)?; assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected"); diff --git a/miri/lib.rs b/miri/lib.rs index e5566bfe9471..b03518468b69 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -87,7 +87,7 @@ pub fn eval_main<'a, 'tcx: 'a>( // First argument: pointer to main() let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance); - let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?; + let dest = ecx.eval_lvalue(&mir::Place::Local(args.next().unwrap()))?; let main_ty = main_instance.def.def_ty(ecx.tcx); let main_ptr_ty = ecx.tcx.mk_fn_ptr(main_ty.fn_sig(ecx.tcx)); ecx.write_value( @@ -99,13 +99,13 @@ pub fn eval_main<'a, 'tcx: 'a>( )?; // Second argument (argc): 1 - let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?; + let dest = ecx.eval_lvalue(&mir::Place::Local(args.next().unwrap()))?; let ty = ecx.tcx.types.isize; ecx.write_primval(dest, PrimVal::Bytes(1), ty)?; // FIXME: extract main source file path // Third argument (argv): &[b"foo"] - let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?; + let dest = ecx.eval_lvalue(&mir::Place::Local(args.next().unwrap()))?; let ty = ecx.tcx.mk_imm_ptr(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8)); let foo = ecx.memory.allocate_cached(b"foo\0"); let ptr_size = ecx.memory.pointer_size(); @@ -261,7 +261,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { let usize = ecx.tcx.types.usize; // First argument: size - let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?; + let dest = ecx.eval_lvalue(&mir::Place::Local(args.next().unwrap()))?; ecx.write_value( ValTy { value: Value::ByVal(PrimVal::Bytes(size as u128)), @@ -271,7 +271,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { )?; // Second argument: align - let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?; + let dest = ecx.eval_lvalue(&mir::Place::Local(args.next().unwrap()))?; ecx.write_value( ValTy { value: Value::ByVal(PrimVal::Bytes(align as u128)), diff --git a/miri/tls.rs b/miri/tls.rs index e592478f6f9e..8ec31f00e7f1 100644 --- a/miri/tls.rs +++ b/miri/tls.rs @@ -125,7 +125,7 @@ impl<'a, 'tcx: 'a> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, Evaluator> { let arg_local = self.frame().mir.args_iter().next().ok_or( EvalErrorKind::AbiViolation("TLS dtor does not take enough arguments.".to_owned()), )?; - let dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?; + let dest = self.eval_lvalue(&mir::Place::Local(arg_local))?; let ty = self.tcx.mk_mut_ptr(self.tcx.types.u8); self.write_ptr(dest, ptr, ty)?; diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index 9de2630797ec..c30c9b439a46 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -1,4 +1,4 @@ fn main() { - let b = unsafe { std::mem::transmute::(2) }; - if b { unreachable!() } else { unreachable!() } //~ ERROR: invalid boolean value read + let b = unsafe { std::mem::transmute::(2) }; //~ ERROR: invalid boolean value read + if b { unreachable!() } else { unreachable!() } } diff --git a/tests/compile-fail/match_char.rs b/tests/compile-fail/match_char.rs index a91c7fef6aa1..4fee6e692bad 100644 --- a/tests/compile-fail/match_char.rs +++ b/tests/compile-fail/match_char.rs @@ -1,7 +1,7 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); - match unsafe { std::mem::transmute::(-1) } { - 'a' => {}, //~ERROR tried to interpret an invalid 32-bit value as a char: 4294967295 + match unsafe { std::mem::transmute::(-1) } { //~ERROR tried to interpret an invalid 32-bit value as a char: 4294967295 + 'a' => {}, 'b' => {}, _ => {}, } diff --git a/tests/compile-fail/never_say_never.rs b/tests/compile-fail/never_say_never.rs index 6aa4e281818c..71306cc62bf7 100644 --- a/tests/compile-fail/never_say_never.rs +++ b/tests/compile-fail/never_say_never.rs @@ -7,7 +7,7 @@ fn main() { let y = &5; let x: ! = unsafe { - *(y as *const _ as *const !) //~ ERROR tried to access a dead local variable + *(y as *const _ as *const !) //~ ERROR entered unreachable code }; f(x) } diff --git a/tests/compile-fail/reference_to_packed.rs b/tests/compile-fail/reference_to_packed.rs index cc927f879504..064386b3d010 100644 --- a/tests/compile-fail/reference_to_packed.rs +++ b/tests/compile-fail/reference_to_packed.rs @@ -14,6 +14,6 @@ fn main() { x: 42, y: 99, }; - let p = &foo.x; + let p = unsafe { &foo.x }; let i = *p; //~ ERROR tried to access memory with alignment 1, but alignment 4 is required } diff --git a/tests/run-pass/issue-36278-prefix-nesting.rs b/tests/run-pass/issue-36278-prefix-nesting.rs index 95269d0569de..dc807bfde7a3 100644 --- a/tests/run-pass/issue-36278-prefix-nesting.rs +++ b/tests/run-pass/issue-36278-prefix-nesting.rs @@ -22,7 +22,10 @@ fn main() { let size_of_sized; let size_of_unsized; let x: Box> = Box::new(P([0; SZ], P([0; SZ], [0; 0]))); size_of_sized = mem::size_of_val::>(&x); + let align_of_sized = mem::align_of_val::>(&x); let y: Box> = x; size_of_unsized = mem::size_of_val::>(&y); assert_eq!(size_of_sized, size_of_unsized); + assert_eq!(align_of_sized, 1); + assert_eq!(mem::align_of_val::>(&y), 1); } From dd630a2a263105f104b82dd53a1b9b90d4206a3d Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 6 Dec 2017 08:39:31 +0100 Subject: [PATCH 0015/5092] Rename lvalue to place --- miri/fn_call.rs | 30 +++++++++++++++--------------- miri/intrinsic.rs | 32 ++++++++++++++++---------------- miri/lib.rs | 20 ++++++++++---------- miri/tls.rs | 6 +++--- tex/report/miri-report.tex | 10 +++++----- 5 files changed, 49 insertions(+), 49 deletions(-) diff --git a/miri/fn_call.rs b/miri/fn_call.rs index adb235edb67b..1d02c979ba74 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -21,7 +21,7 @@ pub trait EvalContextExt<'tcx> { &mut self, def_id: DefId, args: &[ValTy<'tcx>], - dest: Lvalue, + dest: Place, dest_ty: Ty<'tcx>, dest_block: mir::BasicBlock, ) -> EvalResult<'tcx>; @@ -31,7 +31,7 @@ pub trait EvalContextExt<'tcx> { fn call_missing_fn( &mut self, instance: ty::Instance<'tcx>, - destination: Option<(Lvalue, mir::BasicBlock)>, + destination: Option<(Place, mir::BasicBlock)>, args: &[ValTy<'tcx>], sig: ty::FnSig<'tcx>, path: String, @@ -40,20 +40,20 @@ pub trait EvalContextExt<'tcx> { fn eval_fn_call( &mut self, instance: ty::Instance<'tcx>, - destination: Option<(Lvalue, mir::BasicBlock)>, + destination: Option<(Place, mir::BasicBlock)>, args: &[ValTy<'tcx>], span: Span, sig: ty::FnSig<'tcx>, ) -> EvalResult<'tcx, bool>; - fn write_null(&mut self, dest: Lvalue, dest_ty: Ty<'tcx>) -> EvalResult<'tcx>; + fn write_null(&mut self, dest: Place, dest_ty: Ty<'tcx>) -> EvalResult<'tcx>; } impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> { fn eval_fn_call( &mut self, instance: ty::Instance<'tcx>, - destination: Option<(Lvalue, mir::BasicBlock)>, + destination: Option<(Place, mir::BasicBlock)>, args: &[ValTy<'tcx>], span: Span, sig: ty::FnSig<'tcx>, @@ -75,16 +75,16 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> Err(other) => return Err(other), }; - let (return_lvalue, return_to_block) = match destination { - Some((lvalue, block)) => (lvalue, StackPopCleanup::Goto(block)), - None => (Lvalue::undef(), StackPopCleanup::None), + let (return_place, return_to_block) = match destination { + Some((place, block)) => (place, StackPopCleanup::Goto(block)), + None => (Place::undef(), StackPopCleanup::None), }; self.push_stack_frame( instance, span, mir, - return_lvalue, + return_place, return_to_block, )?; @@ -95,7 +95,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> &mut self, def_id: DefId, args: &[ValTy<'tcx>], - dest: Lvalue, + dest: Place, dest_ty: Ty<'tcx>, dest_block: mir::BasicBlock, ) -> EvalResult<'tcx> { @@ -176,7 +176,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> f_instance, mir.span, mir, - Lvalue::undef(), + Place::undef(), StackPopCleanup::Goto(dest_block), )?; let mut args = self.frame().mir.args_iter(); @@ -187,7 +187,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> .to_owned(), ), )?; - let arg_dest = self.eval_lvalue(&mir::Place::Local(arg_local))?; + let arg_dest = self.eval_place(&mir::Place::Local(arg_local))?; self.write_ptr(arg_dest, data, u8_ptr_ty)?; assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected"); @@ -416,7 +416,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> }; // Figure out how large a pthread TLS key actually is. This is libc::pthread_key_t. - let key_type = args[0].ty.builtin_deref(true, ty::LvaluePreference::NoPreference) + let key_type = args[0].ty.builtin_deref(true, ty::PlacePreference::NoPreference) .ok_or(EvalErrorKind::AbiViolation("Wrong signature used for pthread_key_create: First argument must be a raw pointer.".to_owned()))?.ty; let key_size = self.type_layout(key_type)?.size; @@ -516,7 +516,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> fn call_missing_fn( &mut self, instance: ty::Instance<'tcx>, - destination: Option<(Lvalue, mir::BasicBlock)>, + destination: Option<(Place, mir::BasicBlock)>, args: &[ValTy<'tcx>], sig: ty::FnSig<'tcx>, path: String, @@ -655,7 +655,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> return Ok(()); } - fn write_null(&mut self, dest: Lvalue, dest_ty: Ty<'tcx>) -> EvalResult<'tcx> { + fn write_null(&mut self, dest: Place, dest_ty: Ty<'tcx>) -> EvalResult<'tcx> { self.write_primval(dest, PrimVal::Bytes(0), dest_ty) } } diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index ccc2a9dd2574..0db3f4f2542f 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -3,7 +3,7 @@ use rustc::traits::Reveal; use rustc::ty::layout::TyLayout; use rustc::ty; -use rustc::mir::interpret::{EvalResult, Lvalue, LvalueExtra, PrimVal, PrimValKind, Value, Pointer, +use rustc::mir::interpret::{EvalResult, Place, PlaceExtra, PrimVal, PrimValKind, Value, Pointer, HasMemory, AccessKind, EvalContext, PtrAndAlign, ValTy}; use helpers::EvalContextExt as HelperEvalContextExt; @@ -13,7 +13,7 @@ pub trait EvalContextExt<'tcx> { &mut self, instance: ty::Instance<'tcx>, args: &[ValTy<'tcx>], - dest: Lvalue, + dest: Place, dest_layout: TyLayout<'tcx>, target: mir::BasicBlock, ) -> EvalResult<'tcx>; @@ -24,7 +24,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> &mut self, instance: ty::Instance<'tcx>, args: &[ValTy<'tcx>], - dest: Lvalue, + dest: Place, dest_layout: TyLayout<'tcx>, target: mir::BasicBlock, ) -> EvalResult<'tcx> { @@ -119,7 +119,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> }; self.write_primval(dest, old, ty)?; self.write_primval( - Lvalue::from_primval_ptr(ptr), + Place::from_primval_ptr(ptr), change, ty, )?; @@ -143,7 +143,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> }; self.write_value(valty, dest)?; self.write_primval( - Lvalue::from_primval_ptr(ptr), + Place::from_primval_ptr(ptr), change, ty, )?; @@ -196,7 +196,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> }; // FIXME: what do atomics do on overflow? let (val, _) = self.binary_op(op, old, ty, change, ty)?; - self.write_primval(Lvalue::from_primval_ptr(ptr), val, ty)?; + self.write_primval(Place::from_primval_ptr(ptr), val, ty)?; } "breakpoint" => unimplemented!(), // halt miri @@ -240,8 +240,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "discriminant_value" => { let ty = substs.type_at(0); let adt_ptr = args[0].into_ptr(&self.memory)?; - let lval = Lvalue::from_primval_ptr(adt_ptr); - let discr_val = self.read_discriminant_value(lval, ty)?; + let place = Place::from_primval_ptr(adt_ptr); + let discr_val = self.read_discriminant_value(place, ty)?; self.write_primval(dest, PrimVal::Bytes(discr_val), dest_layout.ty)?; } @@ -336,12 +336,12 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> Ok(zero_val) }; match dest { - Lvalue::Local { frame, local } => self.modify_local(frame, local, init)?, - Lvalue::Ptr { + Place::Local { frame, local } => self.modify_local(frame, local, init)?, + Place::Ptr { ptr: PtrAndAlign { ptr, aligned: true }, - extra: LvalueExtra::None, + extra: PlaceExtra::None, } => self.memory.write_repeat(ptr, 0, size)?, - Lvalue::Ptr { .. } => { + Place::Ptr { .. } => { bug!("init intrinsic tried to write to fat or unaligned ptr target") } } @@ -623,12 +623,12 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> _ => Ok(Value::ByVal(PrimVal::Undef)), }; match dest { - Lvalue::Local { frame, local } => self.modify_local(frame, local, uninit)?, - Lvalue::Ptr { + Place::Local { frame, local } => self.modify_local(frame, local, uninit)?, + Place::Ptr { ptr: PtrAndAlign { ptr, aligned: true }, - extra: LvalueExtra::None, + extra: PlaceExtra::None, } => self.memory.mark_definedness(ptr, size, false)?, - Lvalue::Ptr { .. } => { + Place::Ptr { .. } => { bug!("uninit intrinsic tried to write to fat or unaligned ptr target") } } diff --git a/miri/lib.rs b/miri/lib.rs index b03518468b69..399418f6734b 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -79,7 +79,7 @@ pub fn eval_main<'a, 'tcx: 'a>( start_instance, start_mir.span, start_mir, - Lvalue::from_ptr(ret_ptr), + Place::from_ptr(ret_ptr), StackPopCleanup::None, )?; @@ -87,7 +87,7 @@ pub fn eval_main<'a, 'tcx: 'a>( // First argument: pointer to main() let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance); - let dest = ecx.eval_lvalue(&mir::Place::Local(args.next().unwrap()))?; + let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let main_ty = main_instance.def.def_ty(ecx.tcx); let main_ptr_ty = ecx.tcx.mk_fn_ptr(main_ty.fn_sig(ecx.tcx)); ecx.write_value( @@ -99,13 +99,13 @@ pub fn eval_main<'a, 'tcx: 'a>( )?; // Second argument (argc): 1 - let dest = ecx.eval_lvalue(&mir::Place::Local(args.next().unwrap()))?; + let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let ty = ecx.tcx.types.isize; ecx.write_primval(dest, PrimVal::Bytes(1), ty)?; // FIXME: extract main source file path // Third argument (argv): &[b"foo"] - let dest = ecx.eval_lvalue(&mir::Place::Local(args.next().unwrap()))?; + let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let ty = ecx.tcx.mk_imm_ptr(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8)); let foo = ecx.memory.allocate_cached(b"foo\0"); let ptr_size = ecx.memory.pointer_size(); @@ -120,7 +120,7 @@ pub fn eval_main<'a, 'tcx: 'a>( main_instance, main_mir.span, main_mir, - Lvalue::undef(), + Place::undef(), StackPopCleanup::None, )?; @@ -195,7 +195,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { fn eval_fn_call<'a>( ecx: &mut EvalContext<'a, 'tcx, Self>, instance: ty::Instance<'tcx>, - destination: Option<(Lvalue, mir::BasicBlock)>, + destination: Option<(Place, mir::BasicBlock)>, args: &[ValTy<'tcx>], span: Span, sig: ty::FnSig<'tcx>, @@ -207,7 +207,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { ecx: &mut rustc::mir::interpret::EvalContext<'a, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[ValTy<'tcx>], - dest: Lvalue, + dest: Place, dest_layout: TyLayout<'tcx>, target: mir::BasicBlock, ) -> EvalResult<'tcx> { @@ -237,7 +237,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { fn box_alloc<'a>( ecx: &mut EvalContext<'a, 'tcx, Self>, ty: ty::Ty<'tcx>, - dest: Lvalue, + dest: Place, ) -> EvalResult<'tcx> { let size = ecx.type_size(ty)?.expect("box only works with sized types"); let align = ecx.type_align(ty)?; @@ -261,7 +261,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { let usize = ecx.tcx.types.usize; // First argument: size - let dest = ecx.eval_lvalue(&mir::Place::Local(args.next().unwrap()))?; + let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; ecx.write_value( ValTy { value: Value::ByVal(PrimVal::Bytes(size as u128)), @@ -271,7 +271,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { )?; // Second argument: align - let dest = ecx.eval_lvalue(&mir::Place::Local(args.next().unwrap()))?; + let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; ecx.write_value( ValTy { value: Value::ByVal(PrimVal::Bytes(align as u128)), diff --git a/miri/tls.rs b/miri/tls.rs index 8ec31f00e7f1..0a0ba1c03b67 100644 --- a/miri/tls.rs +++ b/miri/tls.rs @@ -1,6 +1,6 @@ use rustc::{ty, mir}; -use super::{TlsKey, TlsEntry, EvalResult, EvalErrorKind, Pointer, Memory, Evaluator, Lvalue, +use super::{TlsKey, TlsEntry, EvalResult, EvalErrorKind, Pointer, Memory, Evaluator, Place, StackPopCleanup, EvalContext}; pub trait MemoryExt<'tcx> { @@ -119,13 +119,13 @@ impl<'a, 'tcx: 'a> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, Evaluator> { instance, mir.span, mir, - Lvalue::undef(), + Place::undef(), StackPopCleanup::None, )?; let arg_local = self.frame().mir.args_iter().next().ok_or( EvalErrorKind::AbiViolation("TLS dtor does not take enough arguments.".to_owned()), )?; - let dest = self.eval_lvalue(&mir::Place::Local(arg_local))?; + let dest = self.eval_place(&mir::Place::Local(arg_local))?; let ty = self.tcx.mk_mut_ptr(self.tcx.types.u8); self.write_ptr(dest, ptr, ty)?; diff --git a/tex/report/miri-report.tex b/tex/report/miri-report.tex index f8bb37b91133..27a063de0272 100644 --- a/tex/report/miri-report.tex +++ b/tex/report/miri-report.tex @@ -52,10 +52,10 @@ features in compile-time execution. The Rust compiler generates an instance of \rust{Mir} for each function [\autoref{fig:mir}]. Each \rust{Mir} structure represents a control-flow graph for a given function, and contains a list of ``basic blocks'' which in turn contain a list of statements followed by a single terminator. Each -statement is of the form \rust{lvalue = rvalue}. An \rust{Lvalue} is used for referencing variables +statement is of the form \rust{place = rvalue}. An \rust{Place} is used for referencing variables and calculating addresses such as when dereferencing pointers, accessing fields, or indexing arrays. An \rust{Rvalue} represents the core set of operations possible in MIR, including reading a value -from an lvalue, performing math operations, creating new pointers, structures, and arrays, and so +from an place, performing math operations, creating new pointers, structures, and arrays, and so on. Finally, a terminator decides where control will flow next, optionally based on the value of a boolean or integer. @@ -73,7 +73,7 @@ boolean or integer. } struct Statement { - lvalue: Lvalue, + place: Place, rvalue: Rvalue } @@ -99,7 +99,7 @@ boolean or integer. To investigate the possibility of executing Rust at compile-time I wrote an interpreter for MIR called Miri\footnote{\url{https://github.com/solson/miri}}. The structure of the interpreter closely mirrors the structure of MIR itself. It starts executing a function by iterating the statement list -in the starting basic block, translating the lvalue into a pointer and using the rvalue to decide +in the starting basic block, translating the place into a pointer and using the rvalue to decide what to write into that pointer. Evaluating the rvalue may involve reads (such as for the two sides of a binary operation) or construction of new values. When the terminator is reached, it is used to decide which basic block to jump to next. Finally, Miri repeats this entire process, reading @@ -343,7 +343,7 @@ Aggregates include types declared with \rust{struct} or \rust{enum} as well as t closures. Miri supports all common usage of all of these types. The main missing piece is to handle \texttt{\#[repr(..)]} annotations which adjust the layout of a \rust{struct} or \rust{enum}. -\subsection{Lvalue projections} +\subsection{Place projections} This category includes field accesses, dereferencing, accessing data in an \rust{enum} variant, and indexing arrays. Miri supports all of these, including nested projections such as From eccf680b5d191bb39ef2fc5ae51bf3909c312bbe Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 6 Dec 2017 15:03:24 +0100 Subject: [PATCH 0016/5092] Remove type_size and type_align calls --- miri/fn_call.rs | 11 ++++++----- miri/helpers.rs | 9 +++------ miri/intrinsic.rs | 37 +++++++++++++++---------------------- miri/lib.rs | 21 ++++++--------------- 4 files changed, 30 insertions(+), 48 deletions(-) diff --git a/miri/fn_call.rs b/miri/fn_call.rs index 1d02c979ba74..8961ae4d2029 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -1,4 +1,5 @@ use rustc::ty::{self, Ty}; +use rustc::ty::layout::LayoutOf; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use syntax::attr; @@ -261,7 +262,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> let result = { let name_ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?; let name = self.memory.read_c_str(name_ptr)?; - match self.machine_data.env_vars.get(name) { + match self.machine.env_vars.get(name) { Some(&var) => PrimVal::Ptr(var), None => PrimVal::Bytes(0), } @@ -276,7 +277,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> if !name_ptr.is_null()? { let name = self.memory.read_c_str(name_ptr.to_ptr()?)?; if !name.is_empty() && !name.contains(&b'=') { - success = Some(self.machine_data.env_vars.remove(name)); + success = Some(self.machine.env_vars.remove(name)); } } } @@ -313,7 +314,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> self.memory.write_bytes(value_copy.into(), &value)?; let trailing_zero_ptr = value_copy.offset(value.len() as u64, &self)?.into(); self.memory.write_bytes(trailing_zero_ptr, &[0])?; - if let Some(var) = self.machine_data.env_vars.insert( + if let Some(var) = self.machine.env_vars.insert( name.to_owned(), value_copy, ) @@ -416,9 +417,9 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> }; // Figure out how large a pthread TLS key actually is. This is libc::pthread_key_t. - let key_type = args[0].ty.builtin_deref(true, ty::PlacePreference::NoPreference) + let key_type = args[0].ty.builtin_deref(true, ty::LvaluePreference::NoPreference) .ok_or(EvalErrorKind::AbiViolation("Wrong signature used for pthread_key_create: First argument must be a raw pointer.".to_owned()))?.ty; - let key_size = self.type_layout(key_type)?.size; + let key_size = self.layout_of(key_type)?.size; // Create key and write it into the memory where key_ptr wants it let key = self.memory.create_tls_key(dtor) as u128; diff --git a/miri/helpers.rs b/miri/helpers.rs index 3ee148afb2b2..9ca85a6018e1 100644 --- a/miri/helpers.rs +++ b/miri/helpers.rs @@ -1,6 +1,7 @@ use rustc::mir::interpret::{Pointer, EvalResult, PrimVal, EvalContext}; use rustc::ty::Ty; +use rustc::ty::layout::LayoutOf; pub trait EvalContextExt<'tcx> { fn wrapping_pointer_offset( @@ -26,9 +27,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> offset: i64, ) -> EvalResult<'tcx, Pointer> { // FIXME: assuming here that type size is < i64::max_value() - let pointee_size = self.type_size(pointee_ty)?.expect( - "cannot offset a pointer to an unsized type", - ) as i64; + let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; let offset = offset.overflowing_mul(pointee_size).0; ptr.wrapping_signed_offset(offset, self) } @@ -53,9 +52,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> }; } // FIXME: assuming here that type size is < i64::max_value() - let pointee_size = self.type_size(pointee_ty)?.expect( - "cannot offset a pointer to an unsized type", - ) as i64; + let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; return if let Some(offset) = offset.checked_mul(pointee_size) { let ptr = ptr.signed_offset(offset, self)?; // Do not do bounds-checking for integers; they can never alias a normal pointer anyway. diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index 0db3f4f2542f..a509606aaaa0 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -1,6 +1,6 @@ use rustc::mir; use rustc::traits::Reveal; -use rustc::ty::layout::TyLayout; +use rustc::ty::layout::{TyLayout, LayoutOf}; use rustc::ty; use rustc::mir::interpret::{EvalResult, Place, PlaceExtra, PrimVal, PrimValKind, Value, Pointer, @@ -204,12 +204,13 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "copy" | "copy_nonoverlapping" => { let elem_ty = substs.type_at(0); - let elem_size = self.type_size(elem_ty)?.expect("cannot copy unsized value"); + let elem_layout = self.layout_of(elem_ty)?; + let elem_size = elem_layout.size.bytes(); let count = self.value_to_primval(args[2])?.to_u64()?; if count * elem_size != 0 { // TODO: We do not even validate alignment for the 0-bytes case. libstd relies on this in vec::IntoIter::next. // Also see the write_bytes intrinsic. - let elem_align = self.type_align(elem_ty)?; + let elem_align = elem_layout.align.abi(); let src = args[0].into_ptr(&self.memory)?; let dest = args[1].into_ptr(&self.memory)?; self.memory.copy( @@ -308,7 +309,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "likely" | "unlikely" | "forget" => {} "init" => { - let size = self.type_size(dest_layout.ty)?.expect("cannot zero unsized value"); + let size = dest_layout.size.bytes(); let init = |this: &mut Self, val: Value| { let zero_val = match val { Value::ByRef(PtrAndAlign { ptr, .. }) => { @@ -321,7 +322,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> match this.ty_to_primval_kind(dest_layout.ty) { Ok(_) => Value::ByVal(PrimVal::Bytes(0)), Err(_) => { - let ptr = this.alloc_ptr_with_substs(dest_layout.ty, substs)?; + // FIXME(oli-obk): pass TyLayout to alloc_ptr instead of Ty + let ptr = this.alloc_ptr(dest_layout.ty)?; let ptr = Pointer::from(PrimVal::Ptr(ptr)); this.memory.write_repeat(ptr, 0, size)?; Value::by_ref(ptr) @@ -349,14 +351,14 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "min_align_of" => { let elem_ty = substs.type_at(0); - let elem_align = self.type_align(elem_ty)?; + let elem_align = self.layout_of(elem_ty)?.align.abi(); let align_val = PrimVal::from_u128(elem_align as u128); self.write_primval(dest, align_val, dest_layout.ty)?; } "pref_align_of" => { let ty = substs.type_at(0); - let layout = self.type_layout(ty)?; + let layout = self.layout_of(ty)?; let align = layout.align.pref(); let align_val = PrimVal::from_u128(align as u128); self.write_primval(dest, align_val, dest_layout.ty)?; @@ -492,9 +494,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "size_of" => { let ty = substs.type_at(0); - let size = self.type_size(ty)?.expect( - "size_of intrinsic called on unsized value", - ) as u128; + let size = self.layout_of(ty)?.size.bytes().into(); self.write_primval(dest, PrimVal::from_u128(size), dest_layout.ty)?; } @@ -544,9 +544,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> } "unchecked_shl" => { - let bits = self.type_size(dest_layout.ty)?.expect( - "intrinsic can't be called on unsized type", - ) as u128 * 8; + let bits = dest_layout.size.bytes() as u128 * 8; let rhs = self.value_to_primval(args[1])? .to_bytes()?; if rhs >= bits { @@ -564,9 +562,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> } "unchecked_shr" => { - let bits = self.type_size(dest_layout.ty)?.expect( - "intrinsic can't be called on unsized type", - ) as u128 * 8; + let bits = dest_layout.size.bytes() as u128 * 8; let rhs = self.value_to_primval(args[1])? .to_bytes()?; if rhs >= bits { @@ -636,18 +632,15 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "write_bytes" => { let ty = substs.type_at(0); - let ty_align = self.type_align(ty)?; + let ty_layout = self.layout_of(ty)?; let val_byte = self.value_to_primval(args[1])?.to_u128()? as u8; - let size = self.type_size(ty)?.expect( - "write_bytes() type must be sized", - ); let ptr = args[0].into_ptr(&self.memory)?; let count = self.value_to_primval(args[2])?.to_u64()?; if count > 0 { // HashMap relies on write_bytes on a NULL ptr with count == 0 to work // TODO: Should we, at least, validate the alignment? (Also see the copy intrinsic) - self.memory.check_align(ptr, ty_align, Some(AccessKind::Write))?; - self.memory.write_repeat(ptr, val_byte, size * count)?; + self.memory.check_align(ptr, ty_layout.align.abi(), Some(AccessKind::Write))?; + self.memory.write_repeat(ptr, val_byte, ty_layout.size.bytes() * count)?; } } diff --git a/miri/lib.rs b/miri/lib.rs index 399418f6734b..398062b8c224 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -11,7 +11,7 @@ extern crate rustc; extern crate syntax; use rustc::ty::{self, TyCtxt}; -use rustc::ty::layout::TyLayout; +use rustc::ty::layout::{TyLayout, LayoutOf}; use rustc::hir::def_id::DefId; use rustc::mir; use rustc::traits; @@ -141,7 +141,7 @@ pub fn eval_main<'a, 'tcx: 'a>( Ok(()) } - let mut ecx = EvalContext::new(tcx, limits, Default::default(), Default::default()); + let mut ecx = EvalContext::new(tcx, ty::ParamEnv::empty(traits::Reveal::All), limits, Default::default(), Default::default()); match run_main(&mut ecx, main_id, start_wrapper) { Ok(()) => { let leaks = ecx.memory().leak_report(); @@ -155,9 +155,8 @@ pub fn eval_main<'a, 'tcx: 'a>( } } -pub struct Evaluator; #[derive(Default)] -pub struct EvaluatorData { +pub struct Evaluator { /// Environment variables set by `setenv` /// Miri does not expose env vars from the host to the emulated program pub(crate) env_vars: HashMap, MemoryPointer>, @@ -181,16 +180,9 @@ pub struct MemoryData<'tcx> { } impl<'tcx> Machine<'tcx> for Evaluator { - type Data = EvaluatorData; type MemoryData = MemoryData<'tcx>; type MemoryKinds = memory::MemoryKind; - fn param_env<'a>( - _: &EvalContext<'a, 'tcx, Self>, - ) -> ty::ParamEnv<'tcx> { - ty::ParamEnv::empty(traits::Reveal::All) - } - /// Returns Ok() when the function was handled, fail otherwise fn eval_fn_call<'a>( ecx: &mut EvalContext<'a, 'tcx, Self>, @@ -239,8 +231,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { ty: ty::Ty<'tcx>, dest: Place, ) -> EvalResult<'tcx> { - let size = ecx.type_size(ty)?.expect("box only works with sized types"); - let align = ecx.type_align(ty)?; + let layout = ecx.layout_of(ty)?; // Call the `exchange_malloc` lang item let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap(); @@ -264,7 +255,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; ecx.write_value( ValTy { - value: Value::ByVal(PrimVal::Bytes(size as u128)), + value: Value::ByVal(PrimVal::Bytes(layout.size.bytes().into())), ty: usize, }, dest, @@ -274,7 +265,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; ecx.write_value( ValTy { - value: Value::ByVal(PrimVal::Bytes(align as u128)), + value: Value::ByVal(PrimVal::Bytes(layout.align.abi().into())), ty: usize, }, dest, From bde093fa140cbf95023482a94b92b0b16af4b521 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 14 Dec 2017 11:03:55 +0100 Subject: [PATCH 0017/5092] Move validation from rustc to miri --- Cargo.toml | 2 + miri/fn_call.rs | 45 ++- miri/helpers.rs | 5 +- miri/intrinsic.rs | 30 +- miri/lib.rs | 92 ++++- miri/locks.rs | 405 ++++++++++++++++++++++ miri/memory.rs | 6 +- miri/operator.rs | 4 +- miri/range_map.rs | 250 ++++++++++++++ miri/tls.rs | 4 +- miri/validation.rs | 843 +++++++++++++++++++++++++++++++++++++++++++++ 11 files changed, 1633 insertions(+), 53 deletions(-) create mode 100644 miri/locks.rs create mode 100644 miri/range_map.rs create mode 100644 miri/validation.rs diff --git a/Cargo.toml b/Cargo.toml index 9d1f615e8d1b..79fad037385c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,8 @@ path = "miri/lib.rs" [dependencies] byteorder = { version = "1.1", features = ["i128"]} cargo_metadata = { version = "0.2", optional = true } +regex = "0.2.2" +lazy_static = "1.0" [features] cargo_miri = ["cargo_metadata"] diff --git a/miri/fn_call.rs b/miri/fn_call.rs index 8961ae4d2029..71da97b5ab9b 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -8,10 +8,9 @@ use syntax::codemap::Span; use std::mem; -use rustc::mir::interpret::*; use rustc::traits; -use super::{TlsKey, EvalContext}; +use super::*; use tls::MemoryExt; @@ -50,7 +49,7 @@ pub trait EvalContextExt<'tcx> { fn write_null(&mut self, dest: Place, dest_ty: Ty<'tcx>) -> EvalResult<'tcx>; } -impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> { +impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'tcx>> { fn eval_fn_call( &mut self, instance: ty::Instance<'tcx>, @@ -119,7 +118,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> } "free" => { - let ptr = args[0].into_ptr(&mut self.memory)?; + let ptr = self.into_ptr(args[0].value)?; if !ptr.is_null()? { self.memory.deallocate( ptr.to_ptr()?, @@ -150,8 +149,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> } "dlsym" => { - let _handle = args[0].into_ptr(&mut self.memory)?; - let symbol = args[1].into_ptr(&mut self.memory)?.to_ptr()?; + let _handle = self.into_ptr(args[0].value)?; + let symbol = self.into_ptr(args[1].value)?.to_ptr()?; let symbol_name = self.memory.read_c_str(symbol)?; let err = format!("bad c unicode symbol: {:?}", symbol_name); let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err); @@ -165,8 +164,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> // fn __rust_maybe_catch_panic(f: fn(*mut u8), data: *mut u8, data_ptr: *mut usize, vtable_ptr: *mut usize) -> u32 // We abort on panic, so not much is going on here, but we still have to call the closure let u8_ptr_ty = self.tcx.mk_mut_ptr(self.tcx.types.u8); - let f = args[0].into_ptr(&mut self.memory)?.to_ptr()?; - let data = args[1].into_ptr(&mut self.memory)?; + let f = self.into_ptr(args[0].value)?.to_ptr()?; + let data = self.into_ptr(args[1].value)?; let f_instance = self.memory.get_fn(f)?; self.write_null(dest, dest_ty)?; @@ -205,8 +204,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> } "memcmp" => { - let left = args[0].into_ptr(&mut self.memory)?; - let right = args[1].into_ptr(&mut self.memory)?; + let left = self.into_ptr(args[0].value)?; + let right = self.into_ptr(args[1].value)?; let n = self.value_to_primval(args[2])?.to_u64()?; let result = { @@ -229,7 +228,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> } "memrchr" => { - let ptr = args[0].into_ptr(&mut self.memory)?; + let ptr = self.into_ptr(args[0].value)?; let val = self.value_to_primval(args[1])?.to_u64()? as u8; let num = self.value_to_primval(args[2])?.to_u64()?; if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().rev().position( @@ -244,7 +243,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> } "memchr" => { - let ptr = args[0].into_ptr(&mut self.memory)?; + let ptr = self.into_ptr(args[0].value)?; let val = self.value_to_primval(args[1])?.to_u64()? as u8; let num = self.value_to_primval(args[2])?.to_u64()?; if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().position( @@ -260,7 +259,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "getenv" => { let result = { - let name_ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?; + let name_ptr = self.into_ptr(args[0].value)?.to_ptr()?; let name = self.memory.read_c_str(name_ptr)?; match self.machine.env_vars.get(name) { Some(&var) => PrimVal::Ptr(var), @@ -273,7 +272,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "unsetenv" => { let mut success = None; { - let name_ptr = args[0].into_ptr(&mut self.memory)?; + let name_ptr = self.into_ptr(args[0].value)?; if !name_ptr.is_null()? { let name = self.memory.read_c_str(name_ptr.to_ptr()?)?; if !name.is_empty() && !name.contains(&b'=') { @@ -294,8 +293,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "setenv" => { let mut new = None; { - let name_ptr = args[0].into_ptr(&mut self.memory)?; - let value_ptr = args[1].into_ptr(&mut self.memory)?.to_ptr()?; + let name_ptr = self.into_ptr(args[0].value)?; + let value_ptr = self.into_ptr(args[1].value)?.to_ptr()?; let value = self.memory.read_c_str(value_ptr)?; if !name_ptr.is_null()? { let name = self.memory.read_c_str(name_ptr.to_ptr()?)?; @@ -329,7 +328,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "write" => { let fd = self.value_to_primval(args[0])?.to_u64()?; - let buf = args[1].into_ptr(&mut self.memory)?; + let buf = self.into_ptr(args[1].value)?; let n = self.value_to_primval(args[2])?.to_u64()?; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { @@ -358,7 +357,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> } "strlen" => { - let ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?; + let ptr = self.into_ptr(args[0].value)?.to_ptr()?; let n = self.memory.read_c_str(ptr)?.len(); self.write_primval(dest, PrimVal::Bytes(n as u128), dest_ty)?; } @@ -406,10 +405,10 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> // Hook pthread calls that go to the thread-local storage memory subsystem "pthread_key_create" => { - let key_ptr = args[0].into_ptr(&mut self.memory)?; + let key_ptr = self.into_ptr(args[0].value)?; // Extract the function type out of the signature (that seems easier than constructing it ourselves...) - let dtor = match args[1].into_ptr(&mut self.memory)?.into_inner_primval() { + let dtor = match self.into_ptr(args[1].value)?.into_inner_primval() { PrimVal::Ptr(dtor_ptr) => Some(self.memory.get_fn(dtor_ptr)?), PrimVal::Bytes(0) => None, PrimVal::Bytes(_) => return err!(ReadBytesAsPointer), @@ -452,7 +451,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "pthread_setspecific" => { // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t let key = self.value_to_primval(args[0])?.to_u64()? as TlsKey; - let new_ptr = args[1].into_ptr(&mut self.memory)?; + let new_ptr = self.into_ptr(args[1].value)?; self.memory.store_tls(key, new_ptr)?; // Return success (0) @@ -577,7 +576,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } "alloc::heap::::__rust_dealloc" => { - let ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?; + let ptr = self.into_ptr(args[0].value)?.to_ptr()?; let old_size = self.value_to_primval(args[1])?.to_u64()?; let align = self.value_to_primval(args[2])?.to_u64()?; if old_size == 0 { @@ -593,7 +592,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> )?; } "alloc::heap::::__rust_realloc" => { - let ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?; + let ptr = self.into_ptr(args[0].value)?.to_ptr()?; let old_size = self.value_to_primval(args[1])?.to_u64()?; let old_align = self.value_to_primval(args[2])?.to_u64()?; let new_size = self.value_to_primval(args[3])?.to_u64()?; diff --git a/miri/helpers.rs b/miri/helpers.rs index 9ca85a6018e1..0e541cf29208 100644 --- a/miri/helpers.rs +++ b/miri/helpers.rs @@ -1,5 +1,4 @@ -use rustc::mir::interpret::{Pointer, EvalResult, PrimVal, EvalContext}; - +use super::{Pointer, EvalResult, PrimVal, EvalContext}; use rustc::ty::Ty; use rustc::ty::layout::LayoutOf; @@ -19,7 +18,7 @@ pub trait EvalContextExt<'tcx> { ) -> EvalResult<'tcx, Pointer>; } -impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> { +impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'tcx>> { fn wrapping_pointer_offset( &self, ptr: Pointer, diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index a509606aaaa0..705c33252339 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -3,8 +3,8 @@ use rustc::traits::Reveal; use rustc::ty::layout::{TyLayout, LayoutOf}; use rustc::ty; -use rustc::mir::interpret::{EvalResult, Place, PlaceExtra, PrimVal, PrimValKind, Value, Pointer, - HasMemory, AccessKind, EvalContext, PtrAndAlign, ValTy}; +use rustc::mir::interpret::{EvalResult, PrimVal, PrimValKind, Value, Pointer, AccessKind, PtrAndAlign}; +use rustc_mir::interpret::{Place, PlaceExtra, HasMemory, EvalContext, ValTy}; use helpers::EvalContextExt as HelperEvalContextExt; @@ -19,7 +19,7 @@ pub trait EvalContextExt<'tcx> { ) -> EvalResult<'tcx>; } -impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> { +impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'tcx>> { fn call_intrinsic( &mut self, instance: ty::Instance<'tcx>, @@ -70,7 +70,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "arith_offset" => { let offset = self.value_to_primval(args[1])?.to_i128()? as i64; - let ptr = args[0].into_ptr(&self.memory)?; + let ptr = self.into_ptr(args[0].value)?; let result_ptr = self.wrapping_pointer_offset(ptr, substs.type_at(0), offset)?; self.write_ptr(dest, result_ptr, dest_layout.ty)?; } @@ -86,7 +86,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "atomic_load_relaxed" | "atomic_load_acq" | "volatile_load" => { - let ptr = args[0].into_ptr(&self.memory)?; + let ptr = self.into_ptr(args[0].value)?; let valty = ValTy { value: Value::by_ref(ptr), ty: substs.type_at(0), @@ -99,7 +99,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "atomic_store_rel" | "volatile_store" => { let ty = substs.type_at(0); - let dest = args[0].into_ptr(&self.memory)?; + let dest = self.into_ptr(args[0].value)?; self.write_value_to_ptr(args[1].value, dest, ty)?; } @@ -109,7 +109,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> _ if intrinsic_name.starts_with("atomic_xchg") => { let ty = substs.type_at(0); - let ptr = args[0].into_ptr(&self.memory)?; + let ptr = self.into_ptr(args[0].value)?; let change = self.value_to_primval(args[1])?; let old = self.read_value(ptr, ty)?; let old = match old { @@ -127,7 +127,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> _ if intrinsic_name.starts_with("atomic_cxchg") => { let ty = substs.type_at(0); - let ptr = args[0].into_ptr(&self.memory)?; + let ptr = self.into_ptr(args[0].value)?; let expect_old = self.value_to_primval(args[1])?; let change = self.value_to_primval(args[2])?; let old = self.read_value(ptr, ty)?; @@ -175,7 +175,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "atomic_xsub_acqrel" | "atomic_xsub_relaxed" => { let ty = substs.type_at(0); - let ptr = args[0].into_ptr(&self.memory)?; + let ptr = self.into_ptr(args[0].value)?; let change = self.value_to_primval(args[1])?; let old = self.read_value(ptr, ty)?; let old = match old { @@ -211,8 +211,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> // TODO: We do not even validate alignment for the 0-bytes case. libstd relies on this in vec::IntoIter::next. // Also see the write_bytes intrinsic. let elem_align = elem_layout.align.abi(); - let src = args[0].into_ptr(&self.memory)?; - let dest = args[1].into_ptr(&self.memory)?; + let src = self.into_ptr(args[0].value)?; + let dest = self.into_ptr(args[1].value)?; self.memory.copy( src, dest, @@ -240,7 +240,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "discriminant_value" => { let ty = substs.type_at(0); - let adt_ptr = args[0].into_ptr(&self.memory)?; + let adt_ptr = self.into_ptr(args[0].value)?; let place = Place::from_primval_ptr(adt_ptr); let discr_val = self.read_discriminant_value(place, ty)?; self.write_primval(dest, PrimVal::Bytes(discr_val), dest_layout.ty)?; @@ -366,7 +366,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "move_val_init" => { let ty = substs.type_at(0); - let ptr = args[0].into_ptr(&self.memory)?; + let ptr = self.into_ptr(args[0].value)?; self.write_value_to_ptr(args[1].value, ptr, ty)?; } @@ -383,7 +383,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "offset" => { let offset = self.value_to_primval(args[1])?.to_i128()? as i64; - let ptr = args[0].into_ptr(&self.memory)?; + let ptr = self.into_ptr(args[0].value)?; let result_ptr = self.pointer_offset(ptr, substs.type_at(0), offset)?; self.write_ptr(dest, result_ptr, dest_layout.ty)?; } @@ -634,7 +634,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> let ty = substs.type_at(0); let ty_layout = self.layout_of(ty)?; let val_byte = self.value_to_primval(args[1])?.to_u128()? as u8; - let ptr = args[0].into_ptr(&self.memory)?; + let ptr = self.into_ptr(args[0].value)?; let count = self.value_to_primval(args[2])?.to_u64()?; if count > 0 { // HashMap relies on write_bytes on a NULL ptr with count == 0 to work diff --git a/miri/lib.rs b/miri/lib.rs index 398062b8c224..739ccfbf7671 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -1,6 +1,8 @@ #![feature( i128_type, rustc_private, + conservative_impl_trait, + catch_expr, )] // From rustc. @@ -8,7 +10,12 @@ extern crate log; #[macro_use] extern crate rustc; +extern crate rustc_mir; +extern crate rustc_data_structures; extern crate syntax; +extern crate regex; +#[macro_use] +extern crate lazy_static; use rustc::ty::{self, TyCtxt}; use rustc::ty::layout::{TyLayout, LayoutOf}; @@ -22,6 +29,7 @@ use syntax::codemap::Span; use std::collections::{HashMap, BTreeMap}; pub use rustc::mir::interpret::*; +pub use rustc_mir::interpret::*; mod fn_call; mod operator; @@ -29,11 +37,19 @@ mod intrinsic; mod helpers; mod memory; mod tls; +mod locks; +mod range_map; +mod validation; use fn_call::EvalContextExt as MissingFnsEvalContextExt; use operator::EvalContextExt as OperatorEvalContextExt; use intrinsic::EvalContextExt as IntrinsicEvalContextExt; use tls::EvalContextExt as TlsEvalContextExt; +use locks::LockInfo; +use locks::MemoryExt as LockMemoryExt; +use validation::EvalContextExt as ValidationEvalContextExt; +use range_map::RangeMap; +use validation::{ValidationQuery, AbsPlace}; pub fn eval_main<'a, 'tcx: 'a>( tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -42,7 +58,7 @@ pub fn eval_main<'a, 'tcx: 'a>( limits: ResourceLimits, ) { fn run_main<'a, 'tcx: 'a>( - ecx: &mut rustc::mir::interpret::EvalContext<'a, 'tcx, Evaluator>, + ecx: &mut rustc_mir::interpret::EvalContext<'a, 'tcx, Evaluator<'tcx>>, main_id: DefId, start_wrapper: Option, ) -> EvalResult<'tcx> { @@ -156,10 +172,13 @@ pub fn eval_main<'a, 'tcx: 'a>( } #[derive(Default)] -pub struct Evaluator { +pub struct Evaluator<'tcx> { /// Environment variables set by `setenv` /// Miri does not expose env vars from the host to the emulated program pub(crate) env_vars: HashMap, MemoryPointer>, + + /// Places that were suspended by the validation subsystem, and will be recovered later + pub(crate) suspended: HashMap>>, } pub type TlsKey = usize; @@ -177,9 +196,15 @@ pub struct MemoryData<'tcx> { /// pthreads-style thread-local storage. thread_local: BTreeMap>, + + /// Memory regions that are locked by some function + /// + /// Only mutable (static mut, heap, stack) allocations have an entry in this map. + /// The entry is created when allocating the memory and deleted after deallocation. + locks: HashMap>>, } -impl<'tcx> Machine<'tcx> for Evaluator { +impl<'tcx> Machine<'tcx> for Evaluator<'tcx> { type MemoryData = MemoryData<'tcx>; type MemoryKinds = memory::MemoryKind; @@ -196,7 +221,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { } fn call_intrinsic<'a>( - ecx: &mut rustc::mir::interpret::EvalContext<'a, 'tcx, Self>, + ecx: &mut rustc_mir::interpret::EvalContext<'a, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[ValTy<'tcx>], dest: Place, @@ -207,7 +232,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { } fn try_ptr_op<'a>( - ecx: &rustc::mir::interpret::EvalContext<'a, 'tcx, Self>, + ecx: &rustc_mir::interpret::EvalContext<'a, 'tcx, Self>, bin_op: mir::BinOp, left: PrimVal, left_ty: ty::Ty<'tcx>, @@ -303,4 +328,61 @@ impl<'tcx> Machine<'tcx> for Evaluator { ); Ok(()) } + + fn check_locks<'a>( + mem: &Memory<'a, 'tcx, Self>, + ptr: MemoryPointer, + size: u64, + access: AccessKind, + ) -> EvalResult<'tcx> { + mem.check_locks(ptr, size, access) + } + + fn add_lock<'a>( + mem: &mut Memory<'a, 'tcx, Self>, + id: u64, + ) { + mem.data.locks.insert(id, RangeMap::new()); + } + + fn free_lock<'a>( + mem: &mut Memory<'a, 'tcx, Self>, + id: u64, + len: u64, + ) -> EvalResult<'tcx> { + mem.data.locks + .remove(&id) + .expect("allocation has no corresponding locks") + .check( + Some(mem.cur_frame), + 0, + len, + AccessKind::Read, + ) + .map_err(|lock| { + EvalErrorKind::DeallocatedLockedMemory { + //ptr, FIXME + ptr: MemoryPointer { + alloc_id: AllocId(0), + offset: 0, + }, + lock: lock.active, + }.into() + }) + } + + fn end_region<'a>( + ecx: &mut EvalContext<'a, 'tcx, Self>, + reg: Option<::rustc::middle::region::Scope>, + ) -> EvalResult<'tcx> { + ecx.end_region(reg) + } + + fn validation_op<'a>( + ecx: &mut EvalContext<'a, 'tcx, Self>, + op: ::rustc::mir::ValidationOp, + operand: &::rustc::mir::ValidationOperand<'tcx, ::rustc::mir::Place<'tcx>>, + ) -> EvalResult<'tcx> { + ecx.validation_op(op, operand) + } } diff --git a/miri/locks.rs b/miri/locks.rs new file mode 100644 index 000000000000..3a9df6a38dff --- /dev/null +++ b/miri/locks.rs @@ -0,0 +1,405 @@ +use super::*; +use rustc::middle::region; + +//////////////////////////////////////////////////////////////////////////////// +// Locks +//////////////////////////////////////////////////////////////////////////////// + +/// Information about a lock that is currently held. +#[derive(Clone, Debug)] +pub struct LockInfo<'tcx> { + /// Stores for which lifetimes (of the original write lock) we got + /// which suspensions. + suspended: HashMap, Vec>, + /// The current state of the lock that's actually effective. + pub active: Lock, +} + +/// Write locks are identified by a stack frame and an "abstract" (untyped) place. +/// It may be tempting to use the lifetime as identifier, but that does not work +/// for two reasons: +/// * First of all, due to subtyping, the same lock may be referred to with different +/// lifetimes. +/// * Secondly, different write locks may actually have the same lifetime. See `test2` +/// in `run-pass/many_shr_bor.rs`. +/// The Id is "captured" when the lock is first suspended; at that point, the borrow checker +/// considers the path frozen and hence the Id remains stable. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct WriteLockId<'tcx> { + frame: usize, + path: AbsPlace<'tcx>, +} + + +use rustc::mir::interpret::Lock::*; +use rustc::mir::interpret::Lock; + +impl<'tcx> Default for LockInfo<'tcx> { + fn default() -> Self { + LockInfo::new(NoLock) + } +} + +impl<'tcx> LockInfo<'tcx> { + fn new(lock: Lock) -> LockInfo<'tcx> { + LockInfo { + suspended: HashMap::new(), + active: lock, + } + } + + fn access_permitted(&self, frame: Option, access: AccessKind) -> bool { + use super::AccessKind::*; + match (&self.active, access) { + (&NoLock, _) => true, + (&ReadLock(ref lfts), Read) => { + assert!(!lfts.is_empty(), "Someone left an empty read lock behind."); + // Read access to read-locked region is okay, no matter who's holding the read lock. + true + } + (&WriteLock(ref lft), _) => { + // All access is okay if we are the ones holding it + Some(lft.frame) == frame + } + _ => false, // Nothing else is okay. + } + } +} + +pub trait MemoryExt<'tcx> { + fn check_locks( + &self, + ptr: MemoryPointer, + len: u64, + access: AccessKind, + ) -> EvalResult<'tcx>; + fn acquire_lock( + &mut self, + ptr: MemoryPointer, + len: u64, + region: Option, + kind: AccessKind, + ) -> EvalResult<'tcx>; + fn suspend_write_lock( + &mut self, + ptr: MemoryPointer, + len: u64, + lock_path: &AbsPlace<'tcx>, + suspend: Option, + ) -> EvalResult<'tcx>; + fn recover_write_lock( + &mut self, + ptr: MemoryPointer, + len: u64, + lock_path: &AbsPlace<'tcx>, + lock_region: Option, + suspended_region: region::Scope, + ) -> EvalResult<'tcx>; + fn locks_lifetime_ended(&mut self, ending_region: Option); +} + + +impl<'a, 'tcx: 'a> MemoryExt<'tcx> for Memory<'a, 'tcx, Evaluator<'tcx>> { + fn check_locks( + &self, + ptr: MemoryPointer, + len: u64, + access: AccessKind, + ) -> EvalResult<'tcx> { + if len == 0 { + return Ok(()); + } + let locks = match self.data.locks.get(&ptr.alloc_id.0) { + Some(locks) => locks, + // immutable static or other constant memory + None => return Ok(()), + }; + let frame = self.cur_frame; + locks + .check(Some(frame), ptr.offset, len, access) + .map_err(|lock| { + EvalErrorKind::MemoryLockViolation { + ptr, + len, + frame, + access, + lock: lock.active, + }.into() + }) + } + + /// Acquire the lock for the given lifetime + fn acquire_lock( + &mut self, + ptr: MemoryPointer, + len: u64, + region: Option, + kind: AccessKind, + ) -> EvalResult<'tcx> { + let frame = self.cur_frame; + assert!(len > 0); + trace!( + "Frame {} acquiring {:?} lock at {:?}, size {} for region {:?}", + frame, + kind, + ptr, + len, + region + ); + self.check_bounds(ptr.offset(len, &*self)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow) + + let locks = match self.data.locks.get_mut(&ptr.alloc_id.0) { + Some(locks) => locks, + // immutable static or other constant memory + None => return Ok(()), + }; + + // Iterate over our range and acquire the lock. If the range is already split into pieces, + // we have to manipulate all of them. + let lifetime = DynamicLifetime { frame, region }; + for lock in locks.iter_mut(ptr.offset, len) { + if !lock.access_permitted(None, kind) { + return err!(MemoryAcquireConflict { + ptr, + len, + kind, + lock: lock.active.clone(), + }); + } + // See what we have to do + match (&mut lock.active, kind) { + (active @ &mut NoLock, AccessKind::Write) => { + *active = WriteLock(lifetime); + } + (active @ &mut NoLock, AccessKind::Read) => { + *active = ReadLock(vec![lifetime]); + } + (&mut ReadLock(ref mut lifetimes), AccessKind::Read) => { + lifetimes.push(lifetime); + } + _ => bug!("We already checked that there is no conflicting lock"), + } + } + Ok(()) + } + + /// Release or suspend a write lock of the given lifetime prematurely. + /// When releasing, if there is a read lock or someone else's write lock, that's an error. + /// If no lock is held, that's fine. This can happen when e.g. a local is initialized + /// from a constant, and then suspended. + /// When suspending, the same cases are fine; we just register an additional suspension. + fn suspend_write_lock( + &mut self, + ptr: MemoryPointer, + len: u64, + lock_path: &AbsPlace<'tcx>, + suspend: Option, + ) -> EvalResult<'tcx> { + assert!(len > 0); + let cur_frame = self.cur_frame; + let locks = match self.data.locks.get_mut(&ptr.alloc_id.0) { + Some(locks) => locks, + // immutable static or other constant memory + None => return Ok(()), + }; + + 'locks: for lock in locks.iter_mut(ptr.offset, len) { + let is_our_lock = match lock.active { + WriteLock(lft) => + // Double-check that we are holding the lock. + // (Due to subtyping, checking the region would not make any sense.) + lft.frame == cur_frame, + ReadLock(_) | NoLock => false, + }; + if is_our_lock { + trace!("Releasing {:?}", lock.active); + // Disable the lock + lock.active = NoLock; + } else { + trace!( + "Not touching {:?} as it is not our lock", + lock.active, + ); + } + // Check if we want to register a suspension + if let Some(suspend_region) = suspend { + let lock_id = WriteLockId { + frame: cur_frame, + path: lock_path.clone(), + }; + trace!("Adding suspension to {:?}", lock_id); + let mut new_suspension = false; + lock.suspended + .entry(lock_id) + // Remember whether we added a new suspension or not + .or_insert_with(|| { new_suspension = true; Vec::new() }) + .push(suspend_region); + // If the suspension is new, we should have owned this. + // If there already was a suspension, we should NOT have owned this. + if new_suspension == is_our_lock { + // All is well + continue 'locks; + } + } else { + if !is_our_lock { + // All is well. + continue 'locks; + } + } + // If we get here, releasing this is an error except for NoLock. + if lock.active != NoLock { + return err!(InvalidMemoryLockRelease { + ptr, + len, + frame: cur_frame, + lock: lock.active.clone(), + }); + } + } + + Ok(()) + } + + /// Release a suspension from the write lock. If this is the last suspension or if there is no suspension, acquire the lock. + fn recover_write_lock( + &mut self, + ptr: MemoryPointer, + len: u64, + lock_path: &AbsPlace<'tcx>, + lock_region: Option, + suspended_region: region::Scope, + ) -> EvalResult<'tcx> { + assert!(len > 0); + let cur_frame = self.cur_frame; + let lock_id = WriteLockId { + frame: cur_frame, + path: lock_path.clone(), + }; + let locks = match self.data.locks.get_mut(&ptr.alloc_id.0) { + Some(locks) => locks, + // immutable static or other constant memory + None => return Ok(()), + }; + + for lock in locks.iter_mut(ptr.offset, len) { + // Check if we have a suspension here + let (got_the_lock, remove_suspension) = match lock.suspended.get_mut(&lock_id) { + None => { + trace!("No suspension around, we can just acquire"); + (true, false) + } + Some(suspensions) => { + trace!("Found suspension of {:?}, removing it", lock_id); + // That's us! Remove suspension (it should be in there). The same suspension can + // occur multiple times (when there are multiple shared borrows of this that have the same + // lifetime); only remove one of them. + let idx = match suspensions.iter().enumerate().find(|&(_, re)| re == &suspended_region) { + None => // TODO: Can the user trigger this? + bug!("We have this lock suspended, but not for the given region."), + Some((idx, _)) => idx + }; + suspensions.remove(idx); + let got_lock = suspensions.is_empty(); + if got_lock { + trace!("All suspensions are gone, we can have the lock again"); + } + (got_lock, got_lock) + } + }; + if remove_suspension { + // with NLL, we could do that up in the match above... + assert!(got_the_lock); + lock.suspended.remove(&lock_id); + } + if got_the_lock { + match lock.active { + ref mut active @ NoLock => { + *active = WriteLock( + DynamicLifetime { + frame: cur_frame, + region: lock_region, + } + ); + } + _ => { + return err!(MemoryAcquireConflict { + ptr, + len, + kind: AccessKind::Write, + lock: lock.active.clone(), + }) + } + } + } + } + + Ok(()) + } + + fn locks_lifetime_ended(&mut self, ending_region: Option) { + let cur_frame = self.cur_frame; + trace!( + "Releasing frame {} locks that expire at {:?}", + cur_frame, + ending_region + ); + let has_ended = |lifetime: &DynamicLifetime| -> bool { + if lifetime.frame != cur_frame { + return false; + } + match ending_region { + None => true, // When a function ends, we end *all* its locks. It's okay for a function to still have lifetime-related locks + // when it returns, that can happen e.g. with NLL when a lifetime can, but does not have to, extend beyond the + // end of a function. Same for a function still having recoveries. + Some(ending_region) => lifetime.region == Some(ending_region), + } + }; + + for alloc_locks in self.data.locks.values_mut() { + for lock in alloc_locks.iter_mut_all() { + // Delete everything that ends now -- i.e., keep only all the other lifetimes. + let lock_ended = match lock.active { + WriteLock(ref lft) => has_ended(lft), + ReadLock(ref mut lfts) => { + lfts.retain(|lft| !has_ended(lft)); + lfts.is_empty() + } + NoLock => false, + }; + if lock_ended { + lock.active = NoLock; + } + // Also clean up suspended write locks when the function returns + if ending_region.is_none() { + lock.suspended.retain(|id, _suspensions| id.frame != cur_frame); + } + } + // Clean up the map + alloc_locks.retain(|lock| match lock.active { + NoLock => lock.suspended.len() > 0, + _ => true, + }); + } + } +} + +impl<'tcx> RangeMap> { + pub fn check( + &self, + frame: Option, + offset: u64, + len: u64, + access: AccessKind, + ) -> Result<(), LockInfo<'tcx>> { + if len == 0 { + return Ok(()); + } + for lock in self.iter(offset, len) { + // Check if the lock is in conflict with the access. + if !lock.access_permitted(frame, access) { + return Err(lock.clone()); + } + } + Ok(()) + } +} diff --git a/miri/memory.rs b/miri/memory.rs index 0daba8e280ef..bed0eb28c25c 100644 --- a/miri/memory.rs +++ b/miri/memory.rs @@ -9,8 +9,8 @@ pub enum MemoryKind { Env, } -impl Into<::rustc::mir::interpret::MemoryKind> for MemoryKind { - fn into(self) -> ::rustc::mir::interpret::MemoryKind { - ::rustc::mir::interpret::MemoryKind::Machine(self) +impl Into<::rustc_mir::interpret::MemoryKind> for MemoryKind { + fn into(self) -> ::rustc_mir::interpret::MemoryKind { + ::rustc_mir::interpret::MemoryKind::Machine(self) } } diff --git a/miri/operator.rs b/miri/operator.rs index 04e84d27201b..e70f1b12628a 100644 --- a/miri/operator.rs +++ b/miri/operator.rs @@ -1,7 +1,7 @@ use rustc::ty; use rustc::mir; -use rustc::mir::interpret::*; +use super::*; use helpers::EvalContextExt as HelperEvalContextExt; @@ -24,7 +24,7 @@ pub trait EvalContextExt<'tcx> { ) -> EvalResult<'tcx, (PrimVal, bool)>; } -impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> { +impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'tcx>> { fn ptr_op( &self, bin_op: mir::BinOp, diff --git a/miri/range_map.rs b/miri/range_map.rs new file mode 100644 index 000000000000..5cdcbe35121a --- /dev/null +++ b/miri/range_map.rs @@ -0,0 +1,250 @@ +//! Implements a map from integer indices to data. +//! Rather than storing data for every index, internally, this maps entire ranges to the data. +//! To this end, the APIs all work on ranges, not on individual integers. Ranges are split as +//! necessary (e.g. when [0,5) is first associated with X, and then [1,2) is mutated). +//! Users must not depend on whether a range is coalesced or not, even though this is observable +//! via the iteration APIs. +use std::collections::BTreeMap; +use std::ops; + +#[derive(Clone, Debug)] +pub struct RangeMap { + map: BTreeMap, +} + +// The derived `Ord` impl sorts first by the first field, then, if the fields are the same, +// by the second field. +// This is exactly what we need for our purposes, since a range query on a BTReeSet/BTreeMap will give us all +// `MemoryRange`s whose `start` is <= than the one we're looking for, but not > the end of the range we're checking. +// At the same time the `end` is irrelevant for the sorting and range searching, but used for the check. +// This kind of search breaks, if `end < start`, so don't do that! +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] +struct Range { + start: u64, + end: u64, // Invariant: end > start +} + +impl Range { + fn range(offset: u64, len: u64) -> ops::Range { + assert!(len > 0); + // We select all elements that are within + // the range given by the offset into the allocation and the length. + // This is sound if all ranges that intersect with the argument range, are in the + // resulting range of ranges. + let left = Range { + // lowest range to include `offset` + start: 0, + end: offset + 1, + }; + let right = Range { + // lowest (valid) range not to include `offset+len` + start: offset + len, + end: offset + len + 1, + }; + left..right + } + + /// Tests if all of [offset, offset+len) are contained in this range. + fn overlaps(&self, offset: u64, len: u64) -> bool { + assert!(len > 0); + offset < self.end && offset + len >= self.start + } +} + +impl RangeMap { + pub fn new() -> RangeMap { + RangeMap { map: BTreeMap::new() } + } + + fn iter_with_range<'a>( + &'a self, + offset: u64, + len: u64, + ) -> impl Iterator + 'a { + assert!(len > 0); + self.map.range(Range::range(offset, len)).filter_map( + move |(range, + data)| { + if range.overlaps(offset, len) { + Some((range, data)) + } else { + None + } + }, + ) + } + + pub fn iter<'a>(&'a self, offset: u64, len: u64) -> impl Iterator + 'a { + self.iter_with_range(offset, len).map(|(_, data)| data) + } + + fn split_entry_at(&mut self, offset: u64) + where + T: Clone, + { + let range = match self.iter_with_range(offset, 1).next() { + Some((&range, _)) => range, + None => return, + }; + assert!( + range.start <= offset && range.end > offset, + "We got a range that doesn't even contain what we asked for." + ); + // There is an entry overlapping this position, see if we have to split it + if range.start < offset { + let data = self.map.remove(&range).unwrap(); + let old = self.map.insert( + Range { + start: range.start, + end: offset, + }, + data.clone(), + ); + assert!(old.is_none()); + let old = self.map.insert( + Range { + start: offset, + end: range.end, + }, + data, + ); + assert!(old.is_none()); + } + } + + pub fn iter_mut_all<'a>(&'a mut self) -> impl Iterator + 'a { + self.map.values_mut() + } + + /// Provide mutable iteration over everything in the given range. As a side-effect, + /// this will split entries in the map that are only partially hit by the given range, + /// to make sure that when they are mutated, the effect is constrained to the given range. + pub fn iter_mut_with_gaps<'a>( + &'a mut self, + offset: u64, + len: u64, + ) -> impl Iterator + 'a + where + T: Clone, + { + assert!(len > 0); + // Preparation: Split first and last entry as needed. + self.split_entry_at(offset); + self.split_entry_at(offset + len); + // Now we can provide a mutable iterator + self.map.range_mut(Range::range(offset, len)).filter_map( + move |(&range, data)| { + if range.overlaps(offset, len) { + assert!( + offset <= range.start && offset + len >= range.end, + "The splitting went wrong" + ); + Some(data) + } else { + // Skip this one + None + } + }, + ) + } + + /// Provide a mutable iterator over everything in the given range, with the same side-effects as + /// iter_mut_with_gaps. Furthermore, if there are gaps between ranges, fill them with the given default. + /// This is also how you insert. + pub fn iter_mut<'a>(&'a mut self, offset: u64, len: u64) -> impl Iterator + 'a + where + T: Clone + Default, + { + // Do a first iteration to collect the gaps + let mut gaps = Vec::new(); + let mut last_end = offset; + for (range, _) in self.iter_with_range(offset, len) { + if last_end < range.start { + gaps.push(Range { + start: last_end, + end: range.start, + }); + } + last_end = range.end; + } + if last_end < offset + len { + gaps.push(Range { + start: last_end, + end: offset + len, + }); + } + + // Add default for all gaps + for gap in gaps { + let old = self.map.insert(gap, Default::default()); + assert!(old.is_none()); + } + + // Now provide mutable iteration + self.iter_mut_with_gaps(offset, len) + } + + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&T) -> bool, + { + let mut remove = Vec::new(); + for (range, data) in self.map.iter() { + if !f(data) { + remove.push(*range); + } + } + + for range in remove { + self.map.remove(&range); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// Query the map at every offset in the range and collect the results. + fn to_vec(map: &RangeMap, offset: u64, len: u64) -> Vec { + (offset..offset + len) + .into_iter() + .map(|i| *map.iter(i, 1).next().unwrap()) + .collect() + } + + #[test] + fn basic_insert() { + let mut map = RangeMap::::new(); + // Insert + for x in map.iter_mut(10, 1) { + *x = 42; + } + // Check + assert_eq!(to_vec(&map, 10, 1), vec![42]); + } + + #[test] + fn gaps() { + let mut map = RangeMap::::new(); + for x in map.iter_mut(11, 1) { + *x = 42; + } + for x in map.iter_mut(15, 1) { + *x = 42; + } + + // Now request a range that needs three gaps filled + for x in map.iter_mut(10, 10) { + if *x != 42 { + *x = 23; + } + } + + assert_eq!( + to_vec(&map, 10, 10), + vec![23, 42, 23, 23, 23, 42, 23, 23, 23, 23] + ); + assert_eq!(to_vec(&map, 13, 5), vec![23, 23, 42, 23, 23]); + } +} diff --git a/miri/tls.rs b/miri/tls.rs index 0a0ba1c03b67..7f4f194c67f1 100644 --- a/miri/tls.rs +++ b/miri/tls.rs @@ -18,7 +18,7 @@ pub trait EvalContextExt<'tcx> { fn run_tls_dtors(&mut self) -> EvalResult<'tcx>; } -impl<'a, 'tcx: 'a> MemoryExt<'tcx> for Memory<'a, 'tcx, Evaluator> { +impl<'a, 'tcx: 'a> MemoryExt<'tcx> for Memory<'a, 'tcx, Evaluator<'tcx>> { fn create_tls_key(&mut self, dtor: Option>) -> TlsKey { let new_key = self.data.next_thread_local; self.data.next_thread_local += 1; @@ -106,7 +106,7 @@ impl<'a, 'tcx: 'a> MemoryExt<'tcx> for Memory<'a, 'tcx, Evaluator> { } } -impl<'a, 'tcx: 'a> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, Evaluator> { +impl<'a, 'tcx: 'a> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, Evaluator<'tcx>> { fn run_tls_dtors(&mut self) -> EvalResult<'tcx> { let mut dtor = self.memory.fetch_tls_dtor(None)?; // FIXME: replace loop by some structure that works with stepping diff --git a/miri/validation.rs b/miri/validation.rs new file mode 100644 index 000000000000..52f0c24bd6d1 --- /dev/null +++ b/miri/validation.rs @@ -0,0 +1,843 @@ +use rustc::hir::{self, Mutability}; +use rustc::hir::Mutability::*; +use rustc::mir::{self, ValidationOp, ValidationOperand}; +use rustc::ty::{self, Ty, TypeFoldable, TyCtxt}; +use rustc::ty::layout::LayoutOf; +use rustc::ty::subst::{Substs, Subst}; +use rustc::traits; +use rustc::infer::InferCtxt; +use rustc::traits::Reveal; +use rustc::middle::region; +use rustc_data_structures::indexed_vec::Idx; +use rustc_mir::interpret::HasMemory; + +use super::{EvalContext, Place, PlaceExtra, ValTy}; +use rustc::mir::interpret::{DynamicLifetime, AccessKind, EvalErrorKind, Value, EvalError, EvalResult}; +use locks::MemoryExt; + +pub type ValidationQuery<'tcx> = ValidationOperand<'tcx, (AbsPlace<'tcx>, Place)>; + +#[derive(Copy, Clone, Debug, PartialEq)] +pub(crate) enum ValidationMode { + Acquire, + /// Recover because the given region ended + Recover(region::Scope), + ReleaseUntil(Option), +} + +impl ValidationMode { + fn acquiring(self) -> bool { + use self::ValidationMode::*; + match self { + Acquire | Recover(_) => true, + ReleaseUntil(_) => false, + } + } +} + +// Abstract places +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum AbsPlace<'tcx> { + Local(mir::Local), + Static(hir::def_id::DefId), + Projection(Box>), +} + +type AbsPlaceProjection<'tcx> = mir::Projection<'tcx, AbsPlace<'tcx>, u64, ()>; +type AbsPlaceElem<'tcx> = mir::ProjectionElem<'tcx, u64, ()>; + +impl<'tcx> AbsPlace<'tcx> { + pub fn field(self, f: mir::Field) -> AbsPlace<'tcx> { + self.elem(mir::ProjectionElem::Field(f, ())) + } + + pub fn deref(self) -> AbsPlace<'tcx> { + self.elem(mir::ProjectionElem::Deref) + } + + pub fn downcast(self, adt_def: &'tcx ty::AdtDef, variant_index: usize) -> AbsPlace<'tcx> { + self.elem(mir::ProjectionElem::Downcast(adt_def, variant_index)) + } + + pub fn index(self, index: u64) -> AbsPlace<'tcx> { + self.elem(mir::ProjectionElem::Index(index)) + } + + fn elem(self, elem: AbsPlaceElem<'tcx>) -> AbsPlace<'tcx> { + AbsPlace::Projection(Box::new(AbsPlaceProjection { + base: self, + elem, + })) + } +} + +pub(crate) trait EvalContextExt<'tcx> { + fn abstract_place_projection(&self, proj: &mir::PlaceProjection<'tcx>) -> EvalResult<'tcx, AbsPlaceProjection<'tcx>>; + fn abstract_place(&self, place: &mir::Place<'tcx>) -> EvalResult<'tcx, AbsPlace<'tcx>>; + fn validation_op( + &mut self, + op: ValidationOp, + operand: &ValidationOperand<'tcx, mir::Place<'tcx>>, + ) -> EvalResult<'tcx>; + fn end_region(&mut self, scope: Option) -> EvalResult<'tcx>; + fn normalize_type_unerased(&self, ty: Ty<'tcx>) -> Ty<'tcx>; + fn field_with_lifetimes( + &mut self, + base: Place, + layout: ty::layout::TyLayout<'tcx>, + i: usize, + ) -> EvalResult<'tcx, Ty<'tcx>>; + fn validate_fields( + &mut self, + query: ValidationQuery<'tcx>, + mode: ValidationMode, + ) -> EvalResult<'tcx>; + fn validate_ptr( + &mut self, + val: Value, + abs_place: AbsPlace<'tcx>, + pointee_ty: Ty<'tcx>, + re: Option, + mutbl: Mutability, + mode: ValidationMode, + ) -> EvalResult<'tcx>; + fn validate( + &mut self, + query: ValidationQuery<'tcx>, + mode: ValidationMode, + ) -> EvalResult<'tcx>; +} + +impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'tcx>> { + fn abstract_place_projection(&self, proj: &mir::PlaceProjection<'tcx>) -> EvalResult<'tcx, AbsPlaceProjection<'tcx>> { + use self::mir::ProjectionElem::*; + + let elem = match proj.elem { + Deref => Deref, + Field(f, _) => Field(f, ()), + Index(v) => { + let value = self.frame().get_local(v)?; + let ty = self.tcx.types.usize; + let n = self.value_to_primval(ValTy { value, ty })?.to_u64()?; + Index(n) + }, + ConstantIndex { offset, min_length, from_end } => + ConstantIndex { offset, min_length, from_end }, + Subslice { from, to } => + Subslice { from, to }, + Downcast(adt, sz) => Downcast(adt, sz), + }; + Ok(AbsPlaceProjection { + base: self.abstract_place(&proj.base)?, + elem + }) + } + + fn abstract_place(&self, place: &mir::Place<'tcx>) -> EvalResult<'tcx, AbsPlace<'tcx>> { + Ok(match place { + &mir::Place::Local(l) => AbsPlace::Local(l), + &mir::Place::Static(ref s) => AbsPlace::Static(s.def_id), + &mir::Place::Projection(ref p) => + AbsPlace::Projection(Box::new(self.abstract_place_projection(&*p)?)), + }) + } + + // Validity checks + fn validation_op( + &mut self, + op: ValidationOp, + operand: &ValidationOperand<'tcx, mir::Place<'tcx>>, + ) -> EvalResult<'tcx> { + // If mir-emit-validate is set to 0 (i.e., disabled), we may still see validation commands + // because other crates may have been compiled with mir-emit-validate > 0. Ignore those + // commands. This makes mir-emit-validate also a flag to control whether miri will do + // validation or not. + if self.tcx.sess.opts.debugging_opts.mir_emit_validate == 0 { + return Ok(()); + } + debug_assert!(self.memory.cur_frame == self.cur_frame()); + + // HACK: Determine if this method is whitelisted and hence we do not perform any validation. + // We currently insta-UB on anything passing around uninitialized memory, so we have to whitelist + // the places that are allowed to do that. + // The second group is stuff libstd does that is forbidden even under relaxed validation. + { + // The regexp we use for filtering + use regex::Regex; + lazy_static! { + static ref RE: Regex = Regex::new("^(\ + (std|alloc::heap::__core)::mem::(uninitialized|forget)::|\ + <(std|alloc)::heap::Heap as (std::heap|alloc::allocator)::Alloc>::|\ + <(std|alloc::heap::__core)::mem::ManuallyDrop><.*>::new$|\ + <(std|alloc::heap::__core)::mem::ManuallyDrop as std::ops::DerefMut><.*>::deref_mut$|\ + (std|alloc::heap::__core)::ptr::read::|\ + \ + ><.*>::inner$|\ + ><.*>::drop_slow$|\ + (std::heap|alloc::allocator)::Layout::for_value::|\ + (std|alloc::heap::__core)::mem::(size|align)_of_val::\ + )").unwrap(); + } + // Now test + let name = self.frame().instance.to_string(); + if RE.is_match(&name) { + return Ok(()); + } + } + + // We need to monomorphize ty *without* erasing lifetimes + trace!("validation_op1: {:?}", operand.ty.sty); + let ty = operand.ty.subst(self.tcx, self.substs()); + trace!("validation_op2: {:?}", operand.ty.sty); + let place = self.eval_place(&operand.place)?; + let abs_place = self.abstract_place(&operand.place)?; + let query = ValidationQuery { + place: (abs_place, place), + ty, + re: operand.re, + mutbl: operand.mutbl, + }; + + // Check the mode, and also perform mode-specific operations + let mode = match op { + ValidationOp::Acquire => ValidationMode::Acquire, + ValidationOp::Release => ValidationMode::ReleaseUntil(None), + ValidationOp::Suspend(scope) => { + if query.mutbl == MutMutable { + let lft = DynamicLifetime { + frame: self.cur_frame(), + region: Some(scope), // Notably, we only ever suspend things for given regions. + // Suspending for the entire function does not make any sense. + }; + trace!("Suspending {:?} until {:?}", query, scope); + self.machine.suspended.entry(lft).or_insert_with(Vec::new).push( + query.clone(), + ); + } + ValidationMode::ReleaseUntil(Some(scope)) + } + }; + self.validate(query, mode) + } + + /// Release locks and executes suspensions of the given region (or the entire fn, in case of None). + fn end_region(&mut self, scope: Option) -> EvalResult<'tcx> { + debug_assert!(self.memory.cur_frame == self.cur_frame()); + self.memory.locks_lifetime_ended(scope); + match scope { + Some(scope) => { + // Recover suspended places + let lft = DynamicLifetime { + frame: self.cur_frame(), + region: Some(scope), + }; + if let Some(queries) = self.machine.suspended.remove(&lft) { + for query in queries { + trace!("Recovering {:?} from suspension", query); + self.validate(query, ValidationMode::Recover(scope))?; + } + } + } + None => { + // Clean suspension table of current frame + let cur_frame = self.cur_frame(); + self.machine.suspended.retain(|lft, _| { + lft.frame != cur_frame // keep only what is in the other (lower) frames + }); + } + } + Ok(()) + } + + fn normalize_type_unerased(&self, ty: Ty<'tcx>) -> Ty<'tcx> { + return normalize_associated_type(self.tcx, &ty); + + use syntax::codemap::{Span, DUMMY_SP}; + + // We copy a bunch of stuff from rustc/infer/mod.rs to be able to tweak its behavior + fn normalize_projections_in<'a, 'gcx, 'tcx, T>( + self_: &InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + value: &T, + ) -> T::Lifted + where + T: TypeFoldable<'tcx> + ty::Lift<'gcx>, + { + let mut selcx = traits::SelectionContext::new(self_); + let cause = traits::ObligationCause::dummy(); + let traits::Normalized { + value: result, + obligations, + } = traits::normalize(&mut selcx, param_env, cause, value); + + let mut fulfill_cx = traits::FulfillmentContext::new(); + + for obligation in obligations { + fulfill_cx.register_predicate_obligation(self_, obligation); + } + + drain_fulfillment_cx_or_panic(self_, DUMMY_SP, &mut fulfill_cx, &result) + } + + fn drain_fulfillment_cx_or_panic<'a, 'gcx, 'tcx, T>( + self_: &InferCtxt<'a, 'gcx, 'tcx>, + span: Span, + fulfill_cx: &mut traits::FulfillmentContext<'tcx>, + result: &T, + ) -> T::Lifted + where + T: TypeFoldable<'tcx> + ty::Lift<'gcx>, + { + // In principle, we only need to do this so long as `result` + // contains unbound type parameters. It could be a slight + // optimization to stop iterating early. + match fulfill_cx.select_all_or_error(self_) { + Ok(()) => { } + Err(errors) => { + span_bug!( + span, + "Encountered errors `{:?}` resolving bounds after type-checking", + errors + ); + } + } + + let result = self_.resolve_type_vars_if_possible(result); + let result = self_.tcx.fold_regions( + &result, + &mut false, + |r, _| match *r { + ty::ReVar(_) => self_.tcx.types.re_erased, + _ => r, + }, + ); + + match self_.tcx.lift_to_global(&result) { + Some(result) => result, + None => { + span_bug!(span, "Uninferred types/regions in `{:?}`", result); + } + } + } + + trait MyTransNormalize<'gcx>: TypeFoldable<'gcx> { + fn my_trans_normalize<'a, 'tcx>( + &self, + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> Self; + } + + macro_rules! items { ($($item:item)+) => ($($item)+) } + macro_rules! impl_trans_normalize { + ($lt_gcx:tt, $($ty:ty),+) => { + items!($(impl<$lt_gcx> MyTransNormalize<$lt_gcx> for $ty { + fn my_trans_normalize<'a, 'tcx>(&self, + infcx: &InferCtxt<'a, $lt_gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>) + -> Self { + normalize_projections_in(infcx, param_env, self) + } + })+); + } + } + + impl_trans_normalize!('gcx, + Ty<'gcx>, + &'gcx Substs<'gcx>, + ty::FnSig<'gcx>, + ty::PolyFnSig<'gcx>, + ty::ClosureSubsts<'gcx>, + ty::PolyTraitRef<'gcx>, + ty::ExistentialTraitRef<'gcx> + ); + + fn normalize_associated_type<'a, 'tcx, T>(self_: TyCtxt<'a, 'tcx, 'tcx>, value: &T) -> T + where + T: MyTransNormalize<'tcx>, + { + let param_env = ty::ParamEnv::empty(Reveal::All); + + if !value.has_projections() { + return value.clone(); + } + + self_.infer_ctxt().enter(|infcx| { + value.my_trans_normalize(&infcx, param_env) + }) + } + } + + // This is a copy of `Layout::field` + // + // FIXME: remove once validation does not depend on lifetimes + fn field_with_lifetimes( + &mut self, + base: Place, + mut layout: ty::layout::TyLayout<'tcx>, + i: usize, + ) -> EvalResult<'tcx, Ty<'tcx>> { + match base { + Place::Ptr { extra: PlaceExtra::DowncastVariant(variant_index), .. } => { + layout = layout.for_variant(&self, variant_index); + } + _ => {} + } + let tcx = self.tcx; + Ok(match layout.ty.sty { + ty::TyBool | + ty::TyChar | + ty::TyInt(_) | + ty::TyUint(_) | + ty::TyFloat(_) | + ty::TyFnPtr(_) | + ty::TyNever | + ty::TyFnDef(..) | + ty::TyDynamic(..) | + ty::TyForeign(..) => { + bug!("TyLayout::field_type({:?}): not applicable", layout) + } + + // Potentially-fat pointers. + ty::TyRef(_, ty::TypeAndMut { ty: pointee, .. }) | + ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => { + assert!(i < 2); + + // Reuse the fat *T type as its own thin pointer data field. + // This provides information about e.g. DST struct pointees + // (which may have no non-DST form), and will work as long + // as the `Abi` or `FieldPlacement` is checked by users. + if i == 0 { + return Ok(layout.ty); + } + + match tcx.struct_tail(pointee).sty { + ty::TySlice(_) | + ty::TyStr => tcx.types.usize, + ty::TyDynamic(..) => { + // FIXME(eddyb) use an usize/fn() array with + // the correct number of vtables slots. + tcx.mk_imm_ref(tcx.types.re_static, tcx.mk_nil()) + } + _ => bug!("TyLayout::field_type({:?}): not applicable", layout) + } + } + + // Arrays and slices. + ty::TyArray(element, _) | + ty::TySlice(element) => element, + ty::TyStr => tcx.types.u8, + + // Tuples, generators and closures. + ty::TyClosure(def_id, ref substs) => { + substs.upvar_tys(def_id, tcx).nth(i).unwrap() + } + + ty::TyGenerator(def_id, ref substs, _) => { + substs.field_tys(def_id, tcx).nth(i).unwrap() + } + + ty::TyTuple(tys, _) => tys[i], + + // SIMD vector types. + ty::TyAdt(def, ..) if def.repr.simd() => { + layout.ty.simd_type(tcx) + } + + // ADTs. + ty::TyAdt(def, substs) => { + use rustc::ty::layout::Variants; + match layout.variants { + Variants::Single { index } => { + def.variants[index].fields[i].ty(tcx, substs) + } + + // Discriminant field for enums (where applicable). + Variants::Tagged { ref discr, .. } | + Variants::NicheFilling { niche: ref discr, .. } => { + assert_eq!(i, 0); + return Ok(discr.value.to_ty(tcx)) + } + } + } + + ty::TyProjection(_) | ty::TyAnon(..) | ty::TyParam(_) | + ty::TyInfer(_) | ty::TyError => { + bug!("TyLayout::field_type: unexpected type `{}`", layout.ty) + } + }) + } + + fn validate_fields( + &mut self, + query: ValidationQuery<'tcx>, + mode: ValidationMode, + ) -> EvalResult<'tcx> { + let mut layout = self.layout_of(query.ty)?; + layout.ty = query.ty; + + // TODO: Maybe take visibility/privacy into account. + for idx in 0..layout.fields.count() { + let field = mir::Field::new(idx); + let (field_place, field_layout) = + self.place_field(query.place.1, field, layout)?; + // layout stuff erases lifetimes, get the field ourselves + let field_ty = self.field_with_lifetimes(query.place.1, layout, idx)?; + trace!("assuming \n{:?}\n == \n{:?}\n except for lifetimes", field_layout.ty, field_ty); + self.validate( + ValidationQuery { + place: (query.place.0.clone().field(field), field_place), + ty: field_ty, + ..query + }, + mode, + )?; + } + + Ok(()) + } + + fn validate_ptr( + &mut self, + val: Value, + abs_place: AbsPlace<'tcx>, + pointee_ty: Ty<'tcx>, + re: Option, + mutbl: Mutability, + mode: ValidationMode, + ) -> EvalResult<'tcx> { + // Check alignment and non-NULLness + let (_, align) = self.size_and_align_of_dst(pointee_ty, val)?; + let ptr = self.into_ptr(val)?; + self.memory.check_align(ptr, align.abi(), None)?; + + // Recurse + let pointee_place = self.val_to_place(val, pointee_ty)?; + self.validate( + ValidationQuery { + place: (abs_place.deref(), pointee_place), + ty: pointee_ty, + re, + mutbl, + }, + mode, + ) + } + + /// Validate the place at the given type. If `acquire` is false, just do a release of all write locks + fn validate( + &mut self, + mut query: ValidationQuery<'tcx>, + mode: ValidationMode, + ) -> EvalResult<'tcx> { + use rustc::ty::TypeVariants::*; + use rustc::ty::RegionKind::*; + use rustc::ty::AdtKind; + + // No point releasing shared stuff. + if !mode.acquiring() && query.mutbl == MutImmutable { + return Ok(()); + } + // When we recover, we may see data whose validity *just* ended. Do not acquire it. + if let ValidationMode::Recover(ending_ce) = mode { + if query.re == Some(ending_ce) { + return Ok(()); + } + } + + query.ty = self.normalize_type_unerased(&query.ty); + trace!("{:?} on {:#?}", mode, query); + trace!("{:#?}", query.ty.sty); + + // Decide whether this type *owns* the memory it covers (like integers), or whether it + // just assembles pieces (that each own their memory) together to a larger whole. + // TODO: Currently, we don't acquire locks for padding and discriminants. We should. + let is_owning = match query.ty.sty { + TyInt(_) | TyUint(_) | TyRawPtr(_) | TyBool | TyFloat(_) | TyChar | TyStr | + TyRef(..) | TyFnPtr(..) | TyFnDef(..) | TyNever => true, + TyAdt(adt, _) if adt.is_box() => true, + TySlice(_) | TyAdt(_, _) | TyTuple(..) | TyClosure(..) | TyArray(..) | + TyDynamic(..) | TyGenerator(..) | TyForeign(_) => false, + TyParam(_) | TyInfer(_) | TyProjection(_) | TyAnon(..) | TyError => { + bug!("I got an incomplete/unnormalized type for validation") + } + }; + if is_owning { + // We need to lock. So we need memory. So we have to force_acquire. + // Tracking the same state for locals not backed by memory would just duplicate too + // much machinery. + // FIXME: We ignore alignment. + let (ptr, extra) = self.force_allocation(query.place.1)?.to_ptr_extra_aligned(); + // Determine the size + // FIXME: Can we reuse size_and_align_of_dst for Places? + let layout = self.layout_of(query.ty)?; + let len = if !layout.is_unsized() { + assert_eq!(extra, PlaceExtra::None, "Got a fat ptr to a sized type"); + layout.size.bytes() + } else { + // The only unsized typ we concider "owning" is TyStr. + assert_eq!( + query.ty.sty, + TyStr, + "Found a surprising unsized owning type" + ); + // The extra must be the length, in bytes. + match extra { + PlaceExtra::Length(len) => len, + _ => bug!("TyStr must have a length as extra"), + } + }; + // Handle locking + if len > 0 { + let ptr = ptr.to_ptr()?; + match query.mutbl { + MutImmutable => { + if mode.acquiring() { + self.memory.acquire_lock( + ptr, + len, + query.re, + AccessKind::Read, + )?; + } + } + // No releasing of read locks, ever. + MutMutable => { + match mode { + ValidationMode::Acquire => { + self.memory.acquire_lock( + ptr, + len, + query.re, + AccessKind::Write, + )? + } + ValidationMode::Recover(ending_ce) => { + self.memory.recover_write_lock( + ptr, + len, + &query.place.0, + query.re, + ending_ce, + )? + } + ValidationMode::ReleaseUntil(suspended_ce) => { + self.memory.suspend_write_lock( + ptr, + len, + &query.place.0, + suspended_ce, + )? + } + } + } + } + } + } + + let res = do catch { + match query.ty.sty { + TyInt(_) | TyUint(_) | TyRawPtr(_) => { + if mode.acquiring() { + // Make sure we can read this. + let val = self.read_place(query.place.1)?; + self.follow_by_ref_value(val, query.ty)?; + // FIXME: It would be great to rule out Undef here, but that doesn't actually work. + // Passing around undef data is a thing that e.g. Vec::extend_with does. + } + Ok(()) + } + TyBool | TyFloat(_) | TyChar => { + if mode.acquiring() { + let val = self.read_place(query.place.1)?; + let val = self.value_to_primval(ValTy { value: val, ty: query.ty })?; + val.to_bytes()?; + // TODO: Check if these are valid bool/float/codepoint/UTF-8 + } + Ok(()) + } + TyNever => err!(ValidationFailure(format!("The empty type is never valid."))), + TyRef(region, + ty::TypeAndMut { + ty: pointee_ty, + mutbl, + }) => { + let val = self.read_place(query.place.1)?; + // Sharing restricts our context + if mutbl == MutImmutable { + query.mutbl = MutImmutable; + } + // Inner lifetimes *outlive* outer ones, so only if we have no lifetime restriction yet, + // we record the region of this borrow to the context. + if query.re == None { + match *region { + ReScope(scope) => query.re = Some(scope), + // It is possible for us to encounter erased lifetimes here because the lifetimes in + // this functions' Subst will be erased. + _ => {} + } + } + self.validate_ptr(val, query.place.0, pointee_ty, query.re, query.mutbl, mode) + } + TyAdt(adt, _) if adt.is_box() => { + let val = self.read_place(query.place.1)?; + self.validate_ptr(val, query.place.0, query.ty.boxed_ty(), query.re, query.mutbl, mode) + } + TyFnPtr(_sig) => { + let ptr = self.read_place(query.place.1)?; + let ptr = self.into_ptr(ptr)?.to_ptr()?; + self.memory.get_fn(ptr)?; + // TODO: Check if the signature matches (should be the same check as what terminator/mod.rs already does on call?). + Ok(()) + } + TyFnDef(..) => { + // This is a zero-sized type with all relevant data sitting in the type. + // There is nothing to validate. + Ok(()) + } + + // Compound types + TyStr => { + // TODO: Validate strings + Ok(()) + } + TySlice(elem_ty) => { + let len = match query.place.1 { + Place::Ptr { extra: PlaceExtra::Length(len), .. } => len, + _ => { + bug!( + "acquire_valid of a TySlice given non-slice place: {:?}", + query.place + ) + } + }; + for i in 0..len { + let inner_place = self.place_index(query.place.1, query.ty, i)?; + self.validate( + ValidationQuery { + place: (query.place.0.clone().index(i), inner_place), + ty: elem_ty, + ..query + }, + mode, + )?; + } + Ok(()) + } + TyArray(elem_ty, len) => { + let len = len.val.to_const_int().unwrap().to_u64().unwrap(); + for i in 0..len { + let inner_place = self.place_index(query.place.1, query.ty, i as u64)?; + self.validate( + ValidationQuery { + place: (query.place.0.clone().index(i as u64), inner_place), + ty: elem_ty, + ..query + }, + mode, + )?; + } + Ok(()) + } + TyDynamic(_data, _region) => { + // Check that this is a valid vtable + let vtable = match query.place.1 { + Place::Ptr { extra: PlaceExtra::Vtable(vtable), .. } => vtable, + _ => { + bug!( + "acquire_valid of a TyDynamic given non-trait-object place: {:?}", + query.place + ) + } + }; + self.read_size_and_align_from_vtable(vtable)?; + // TODO: Check that the vtable contains all the function pointers we expect it to have. + // Trait objects cannot have any operations performed + // on them directly. We cannot, in general, even acquire any locks as the trait object *could* + // contain an UnsafeCell. If we call functions to get access to data, we will validate + // their return values. So, it doesn't seem like there's anything else to do. + Ok(()) + } + TyAdt(adt, _) => { + if Some(adt.did) == self.tcx.lang_items().unsafe_cell_type() && + query.mutbl == MutImmutable + { + // No locks for shared unsafe cells. Also no other validation, the only field is private anyway. + return Ok(()); + } + + match adt.adt_kind() { + AdtKind::Enum => { + let discr = self.read_discriminant_value(query.place.1, query.ty)?; + + // Get variant index for discriminant + let variant_idx = adt.discriminants(self.tcx).position(|variant_discr| { + variant_discr.to_u128_unchecked() == discr + }); + let variant_idx = match variant_idx { + Some(val) => val, + None => return err!(InvalidDiscriminant), + }; + let variant = &adt.variants[variant_idx]; + + if variant.fields.len() > 0 { + // Downcast to this variant, if needed + let place = if adt.is_enum() { + ( + query.place.0.downcast(adt, variant_idx), + self.eval_place_projection( + query.place.1, + query.ty, + &mir::ProjectionElem::Downcast(adt, variant_idx), + )?, + ) + } else { + query.place + }; + + // Recursively validate the fields + self.validate_fields( + ValidationQuery { place, ..query }, + mode, + ) + } else { + // No fields, nothing left to check. Downcasting may fail, e.g. in case of a CEnum. + Ok(()) + } + } + AdtKind::Struct => { + self.validate_fields(query, mode) + } + AdtKind::Union => { + // No guarantees are provided for union types. + // TODO: Make sure that all access to union fields is unsafe; otherwise, we may have some checking to do (but what exactly?) + Ok(()) + } + } + } + TyTuple(..) | + TyClosure(..) => { + // TODO: Check if the signature matches for `TyClosure` + // (should be the same check as what terminator/mod.rs already does on call?). + // Is there other things we can/should check? Like vtable pointers? + self.validate_fields(query, mode) + } + // FIXME: generators aren't validated right now + TyGenerator(..) => Ok(()), + _ => bug!("We already established that this is a type we support. ({})", query.ty), + } + }; + match res { + // ReleaseUntil(None) of an uninitalized variable is a NOP. This is needed because + // we have to release the return value of a function; due to destination-passing-style + // the callee may directly write there. + // TODO: Ideally we would know whether the destination is already initialized, and only + // release if it is. But of course that can't even always be statically determined. + Err(EvalError { kind: EvalErrorKind::ReadUndefBytes, .. }) + if mode == ValidationMode::ReleaseUntil(None) => { + return Ok(()); + } + res => res, + } + } +} From fc587ac6ae2b49096f440aea37a77b39b6b03971 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 15 Dec 2017 09:32:10 +0100 Subject: [PATCH 0018/5092] Without a Cargo.lock it makes no sense to use --locked --- .travis.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 86577702e96d..97f1da545be4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,9 +16,9 @@ script: xargo/build.sh - | # Test plain miri - cargo build --locked --release --all-features && - cargo test --locked --release --all-features --all && - cargo install --locked --all-features + cargo build --release --all-features && + cargo test --release --all-features --all && + cargo install --all-features - | # Test cargo miri cd cargo-miri-test && @@ -27,11 +27,11 @@ script: cd .. - | # and run all tests with full mir - MIRI_SYSROOT=~/.xargo/HOST cargo test --locked --release + MIRI_SYSROOT=~/.xargo/HOST cargo test --release - | # test that the rustc_tests binary compiles cd rustc_tests && - cargo build --locked --release && + cargo build --release && cd .. notifications: email: From aa9177fec6b080024ffaf6e287cd3dc25bbad9b5 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 15 Dec 2017 09:54:53 +0100 Subject: [PATCH 0019/5092] Also update rustc_tests to unrelated rustc changes --- rustc_tests/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rustc_tests/src/main.rs b/rustc_tests/src/main.rs index 819721c1cd0f..29b2dc2b7a42 100644 --- a/rustc_tests/src/main.rs +++ b/rustc_tests/src/main.rs @@ -90,7 +90,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { if let hir::Item_::ItemFn(_, _, _, _, _, body_id) = i.node { if i.attrs.iter().any(|attr| attr.name().map_or(false, |n| n == "test")) { let did = self.1.hir.body_owner_def_id(body_id); - println!("running test: {}", self.1.hir.def_path(did).to_string(self.1)); + println!("running test: {}", self.1.def_path_debug_str(did)); miri::eval_main(self.1, did, None, self.0); self.2.session.abort_if_errors(); } From 2671cf34a58b11f995add8402e75c1cd94ed051e Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 15 Dec 2017 10:14:02 +0100 Subject: [PATCH 0020/5092] Update to some cleanups in rustc --- miri/fn_call.rs | 2 +- miri/lib.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/miri/fn_call.rs b/miri/fn_call.rs index 71da97b5ab9b..3ca71e9b90c2 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -385,7 +385,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' // compute global if not cached let val = match self.tcx.interpret_interner.borrow().get_cached(cid) { Some(ptr) => ptr, - None => eval_body(self.tcx, instance, ty::ParamEnv::empty(traits::Reveal::All)).0?.0, + None => eval_body(self.tcx, instance, ty::ParamEnv::empty(traits::Reveal::All))?.0, }; let val = self.value_to_primval(ValTy { value: Value::ByRef(val), ty: args[0].ty })?.to_u64()?; if val == name { diff --git a/miri/lib.rs b/miri/lib.rs index 739ccfbf7671..fc282104e116 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -20,6 +20,7 @@ extern crate lazy_static; use rustc::ty::{self, TyCtxt}; use rustc::ty::layout::{TyLayout, LayoutOf}; use rustc::hir::def_id::DefId; +use rustc::ty::subst::Substs; use rustc::mir; use rustc::traits; @@ -157,7 +158,7 @@ pub fn eval_main<'a, 'tcx: 'a>( Ok(()) } - let mut ecx = EvalContext::new(tcx, ty::ParamEnv::empty(traits::Reveal::All), limits, Default::default(), Default::default()); + let mut ecx = EvalContext::new(tcx, ty::ParamEnv::empty(traits::Reveal::All), limits, Default::default(), Default::default(), Substs::empty()); match run_main(&mut ecx, main_id, start_wrapper) { Ok(()) => { let leaks = ecx.memory().leak_report(); From b7d382a95673e7ba0dc9edebaf9bd6f5b50e39e0 Mon Sep 17 00:00:00 2001 From: kennytm Date: Sat, 16 Dec 2017 03:58:17 +0800 Subject: [PATCH 0021/5092] Remove the [workspace] section. Miri does not need to maintain a workspace anymore. Also, keeping miri a workspace conflicts with rustc's own workspace. --- Cargo.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 79fad037385c..bbb3958ac35f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,3 @@ cargo_miri = ["cargo_metadata"] [dev-dependencies] compiletest_rs = { version = "0.3.3", features = ["tmp"] } - -[workspace] -exclude = ["xargo", "cargo-miri-test", "rustc_tests"] From a23e587dc3a55a766ddd95454fd8368988cc7a3a Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 16 Dec 2017 19:48:08 -0600 Subject: [PATCH 0022/5092] stop using Instance::def_ty that function has been removed --- miri/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri/lib.rs b/miri/lib.rs index fc282104e116..d4c211e1fd95 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -105,7 +105,7 @@ pub fn eval_main<'a, 'tcx: 'a>( // First argument: pointer to main() let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance); let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - let main_ty = main_instance.def.def_ty(ecx.tcx); + let main_ty = main_instance.ty(ecx.tcx); let main_ptr_ty = ecx.tcx.mk_fn_ptr(main_ty.fn_sig(ecx.tcx)); ecx.write_value( ValTy { From 30496f5dd27b02c5433956c2704cef41a5b119ad Mon Sep 17 00:00:00 2001 From: David Renshaw Date: Sun, 31 Dec 2017 08:35:02 -0500 Subject: [PATCH 0023/5092] update compiletest dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index bbb3958ac35f..4f0d0fe2ef1c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,4 +31,4 @@ lazy_static = "1.0" cargo_miri = ["cargo_metadata"] [dev-dependencies] -compiletest_rs = { version = "0.3.3", features = ["tmp"] } +compiletest_rs = { version = "0.3.4", features = ["tmp"] } From 03aa8765b19a561e85441c6ed94ba3d646477807 Mon Sep 17 00:00:00 2001 From: David Renshaw Date: Tue, 2 Jan 2018 17:43:03 -0500 Subject: [PATCH 0024/5092] pass typecheck --- miri/fn_call.rs | 27 ++++++++++++------ miri/intrinsic.rs | 68 ++++++++++++++++++++++++---------------------- miri/lib.rs | 22 +++++++-------- miri/operator.rs | 2 +- miri/validation.rs | 4 +-- 5 files changed, 67 insertions(+), 56 deletions(-) diff --git a/miri/fn_call.rs b/miri/fn_call.rs index 3ca71e9b90c2..df101739ed91 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -1,5 +1,5 @@ use rustc::ty::{self, Ty}; -use rustc::ty::layout::LayoutOf; +use rustc::ty::layout::{Align, LayoutOf}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use syntax::attr; @@ -111,7 +111,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' if size == 0 { self.write_null(dest, dest_ty)?; } else { - let align = self.memory.pointer_size(); + let align = self.tcx.data_layout.pointer_align; let ptr = self.memory.allocate(size, align, Some(MemoryKind::C.into()))?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } @@ -307,7 +307,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' // +1 for the null terminator let value_copy = self.memory.allocate( (value.len() + 1) as u64, - 1, + Align::from_bytes(1, 1).unwrap(), Some(MemoryKind::Env.into()), )?; self.memory.write_bytes(value_copy.into(), &value)?; @@ -369,6 +369,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' "sysconf" => { let name = self.value_to_primval(args[0])?.to_u64()?; + let name_align = self.layout_of(args[0].ty)?.align; + trace!("sysconf() called with name {}", name); // cache the sysconf integers via miri's global cache let paths = &[ @@ -387,7 +389,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' Some(ptr) => ptr, None => eval_body(self.tcx, instance, ty::ParamEnv::empty(traits::Reveal::All))?.0, }; - let val = self.value_to_primval(ValTy { value: Value::ByRef(val), ty: args[0].ty })?.to_u64()?; + let val = self.value_to_primval(ValTy { value: Value::ByRef(val, name_align), + ty: args[0].ty })?.to_u64()?; if val == name { result = Some(path_value); break; @@ -406,6 +409,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' // Hook pthread calls that go to the thread-local storage memory subsystem "pthread_key_create" => { let key_ptr = self.into_ptr(args[0].value)?; + let key_align = self.layout_of(args[0].ty)?.align; // Extract the function type out of the signature (that seems easier than constructing it ourselves...) let dtor = match self.into_ptr(args[1].value)?.into_inner_primval() { @@ -427,6 +431,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' } self.memory.write_primval( key_ptr.to_ptr()?, + key_align, PrimVal::Bytes(key), key_size.bytes(), false, @@ -559,7 +564,9 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory.allocate(size, align, Some(MemoryKind::Rust.into()))?; + let ptr = self.memory.allocate(size, + Align::from_bytes(align, align).unwrap(), + Some(MemoryKind::Rust.into()))?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } "alloc::heap::::__rust_alloc_zeroed" => { @@ -571,7 +578,9 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory.allocate(size, align, Some(MemoryKind::Rust.into()))?; + let ptr = self.memory.allocate(size, + Align::from_bytes(align, align).unwrap(), + Some(MemoryKind::Rust.into()))?; self.memory.write_repeat(ptr.into(), 0, size)?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } @@ -587,7 +596,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' } self.memory.deallocate( ptr, - Some((old_size, align)), + Some((old_size, Align::from_bytes(align, align).unwrap())), MemoryKind::Rust.into(), )?; } @@ -609,9 +618,9 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' let new_ptr = self.memory.reallocate( ptr, old_size, - old_align, + Align::from_bytes(old_align, old_align).unwrap(), new_size, - new_align, + Align::from_bytes(new_align, new_align).unwrap(), MemoryKind::Rust.into(), )?; self.write_primval(dest, PrimVal::Ptr(new_ptr), dest_ty)?; diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index 705c33252339..3357f0bba392 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -3,7 +3,7 @@ use rustc::traits::Reveal; use rustc::ty::layout::{TyLayout, LayoutOf}; use rustc::ty; -use rustc::mir::interpret::{EvalResult, PrimVal, PrimValKind, Value, Pointer, AccessKind, PtrAndAlign}; +use rustc::mir::interpret::{EvalResult, PrimVal, PrimValKind, Value, Pointer}; use rustc_mir::interpret::{Place, PlaceExtra, HasMemory, EvalContext, ValTy}; use helpers::EvalContextExt as HelperEvalContextExt; @@ -87,8 +87,10 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' "atomic_load_acq" | "volatile_load" => { let ptr = self.into_ptr(args[0].value)?; + let align = self.layout_of(args[0].ty)?.align; + let valty = ValTy { - value: Value::by_ref(ptr), + value: Value::ByRef(ptr, align), ty: substs.type_at(0), }; self.write_value(valty, dest)?; @@ -99,8 +101,9 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' "atomic_store_rel" | "volatile_store" => { let ty = substs.type_at(0); + let align = self.layout_of(ty)?.align; let dest = self.into_ptr(args[0].value)?; - self.write_value_to_ptr(args[1].value, dest, ty)?; + self.write_value_to_ptr(args[1].value, dest, align, ty)?; } "atomic_fence_acq" => { @@ -109,9 +112,10 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' _ if intrinsic_name.starts_with("atomic_xchg") => { let ty = substs.type_at(0); + let align = self.layout_of(ty)?.align; let ptr = self.into_ptr(args[0].value)?; let change = self.value_to_primval(args[1])?; - let old = self.read_value(ptr, ty)?; + let old = self.read_value(ptr, align, ty)?; let old = match old { Value::ByVal(val) => val, Value::ByRef { .. } => bug!("just read the value, can't be byref"), @@ -119,7 +123,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' }; self.write_primval(dest, old, ty)?; self.write_primval( - Place::from_primval_ptr(ptr), + Place::from_primval_ptr(ptr, align), change, ty, )?; @@ -127,10 +131,11 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' _ if intrinsic_name.starts_with("atomic_cxchg") => { let ty = substs.type_at(0); + let align = self.layout_of(ty)?.align; let ptr = self.into_ptr(args[0].value)?; let expect_old = self.value_to_primval(args[1])?; let change = self.value_to_primval(args[2])?; - let old = self.read_value(ptr, ty)?; + let old = self.read_value(ptr, align, ty)?; let old = match old { Value::ByVal(val) => val, Value::ByRef { .. } => bug!("just read the value, can't be byref"), @@ -143,7 +148,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' }; self.write_value(valty, dest)?; self.write_primval( - Place::from_primval_ptr(ptr), + Place::from_primval_ptr(ptr, dest_layout.align), change, ty, )?; @@ -175,9 +180,10 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' "atomic_xsub_acqrel" | "atomic_xsub_relaxed" => { let ty = substs.type_at(0); + let align = self.layout_of(ty)?.align; let ptr = self.into_ptr(args[0].value)?; let change = self.value_to_primval(args[1])?; - let old = self.read_value(ptr, ty)?; + let old = self.read_value(ptr, align, ty)?; let old = match old { Value::ByVal(val) => val, Value::ByRef { .. } => bug!("just read the value, can't be byref"), @@ -196,7 +202,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' }; // FIXME: what do atomics do on overflow? let (val, _) = self.binary_op(op, old, ty, change, ty)?; - self.write_primval(Place::from_primval_ptr(ptr), val, ty)?; + self.write_primval(Place::from_primval_ptr(ptr, dest_layout.align), val, ty)?; } "breakpoint" => unimplemented!(), // halt miri @@ -210,14 +216,16 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' if count * elem_size != 0 { // TODO: We do not even validate alignment for the 0-bytes case. libstd relies on this in vec::IntoIter::next. // Also see the write_bytes intrinsic. - let elem_align = elem_layout.align.abi(); + let elem_align = elem_layout.align; let src = self.into_ptr(args[0].value)?; + let src_align = self.layout_of(args[0].ty)?.align; let dest = self.into_ptr(args[1].value)?; self.memory.copy( src, + src_align, dest, - count * elem_size, elem_align, + count * elem_size, intrinsic_name.ends_with("_nonoverlapping"), )?; } @@ -241,7 +249,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' "discriminant_value" => { let ty = substs.type_at(0); let adt_ptr = self.into_ptr(args[0].value)?; - let place = Place::from_primval_ptr(adt_ptr); + let adt_align = self.layout_of(args[0].ty)?.align; + let place = Place::from_primval_ptr(adt_ptr, adt_align); let discr_val = self.read_discriminant_value(place, ty)?; self.write_primval(dest, PrimVal::Bytes(discr_val), dest_layout.ty)?; } @@ -312,7 +321,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' let size = dest_layout.size.bytes(); let init = |this: &mut Self, val: Value| { let zero_val = match val { - Value::ByRef(PtrAndAlign { ptr, .. }) => { + Value::ByRef(ptr, _) => { // These writes have no alignment restriction anyway. this.memory.write_repeat(ptr, 0, size)?; val @@ -326,7 +335,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' let ptr = this.alloc_ptr(dest_layout.ty)?; let ptr = Pointer::from(PrimVal::Ptr(ptr)); this.memory.write_repeat(ptr, 0, size)?; - Value::by_ref(ptr) + Value::ByRef(ptr, dest_layout.align) } } } @@ -340,12 +349,11 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' match dest { Place::Local { frame, local } => self.modify_local(frame, local, init)?, Place::Ptr { - ptr: PtrAndAlign { ptr, aligned: true }, + ptr: ptr, + align: _align, extra: PlaceExtra::None, } => self.memory.write_repeat(ptr, 0, size)?, - Place::Ptr { .. } => { - bug!("init intrinsic tried to write to fat or unaligned ptr target") - } + _ => bug!("TODO"), } } @@ -367,7 +375,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' "move_val_init" => { let ty = substs.type_at(0); let ptr = self.into_ptr(args[0].value)?; - self.write_value_to_ptr(args[1].value, ptr, ty)?; + let align = self.layout_of(args[0].ty)?.align; + self.write_value_to_ptr(args[1].value, ptr, align, ty)?; } "needs_drop" => { @@ -533,14 +542,10 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' "transmute" => { let src_ty = substs.type_at(0); + let src_align = self.layout_of(src_ty)?.align; let ptr = self.force_allocation(dest)?.to_ptr()?; - self.write_maybe_aligned_mut( - /*aligned*/ - false, - |ectx| { - ectx.write_value_to_ptr(args[0].value, ptr.into(), src_ty) - }, - )?; + let dest_align = self.layout_of(substs.type_at(1))?.align; + self.write_value_to_ptr(args[0].value, ptr.into(), dest_align, src_ty); } "unchecked_shl" => { @@ -612,7 +617,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' "uninit" => { let size = dest_layout.size.bytes(); let uninit = |this: &mut Self, val: Value| match val { - Value::ByRef(PtrAndAlign { ptr, .. }) => { + Value::ByRef(ptr, _) => { this.memory.mark_definedness(ptr, size, false)?; Ok(val) } @@ -621,12 +626,11 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' match dest { Place::Local { frame, local } => self.modify_local(frame, local, uninit)?, Place::Ptr { - ptr: PtrAndAlign { ptr, aligned: true }, + ptr: ptr, + align: _align, extra: PlaceExtra::None, } => self.memory.mark_definedness(ptr, size, false)?, - Place::Ptr { .. } => { - bug!("uninit intrinsic tried to write to fat or unaligned ptr target") - } + _ => bug!("todo"), } } @@ -639,7 +643,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' if count > 0 { // HashMap relies on write_bytes on a NULL ptr with count == 0 to work // TODO: Should we, at least, validate the alignment? (Also see the copy intrinsic) - self.memory.check_align(ptr, ty_layout.align.abi(), Some(AccessKind::Write))?; + self.memory.check_align(ptr, ty_layout.align)?; self.memory.write_repeat(ptr, val_byte, ty_layout.size.bytes() * count)?; } } diff --git a/miri/lib.rs b/miri/lib.rs index d4c211e1fd95..d458a3c47e8c 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -20,7 +20,6 @@ extern crate lazy_static; use rustc::ty::{self, TyCtxt}; use rustc::ty::layout::{TyLayout, LayoutOf}; use rustc::hir::def_id::DefId; -use rustc::ty::subst::Substs; use rustc::mir; use rustc::traits; @@ -87,7 +86,7 @@ pub fn eval_main<'a, 'tcx: 'a>( // Return value let size = ecx.tcx.data_layout.pointer_size.bytes(); - let align = ecx.tcx.data_layout.pointer_align.abi(); + let align = ecx.tcx.data_layout.pointer_align; let ret_ptr = ecx.memory_mut().allocate(size, align, Some(MemoryKind::Stack))?; cleanup_ptr = Some(ret_ptr); @@ -96,7 +95,7 @@ pub fn eval_main<'a, 'tcx: 'a>( start_instance, start_mir.span, start_mir, - Place::from_ptr(ret_ptr), + Place::from_ptr(ret_ptr, align), StackPopCleanup::None, )?; @@ -126,8 +125,9 @@ pub fn eval_main<'a, 'tcx: 'a>( let ty = ecx.tcx.mk_imm_ptr(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8)); let foo = ecx.memory.allocate_cached(b"foo\0"); let ptr_size = ecx.memory.pointer_size(); - let foo_ptr = ecx.memory.allocate(ptr_size * 1, ptr_size, None)?; - ecx.memory.write_primval(foo_ptr.into(), PrimVal::Ptr(foo.into()), ptr_size, false)?; + let ptr_align = ecx.tcx.data_layout.pointer_align; + let foo_ptr = ecx.memory.allocate(ptr_size, ptr_align, None)?; + ecx.memory.write_primval(foo_ptr, ptr_align, PrimVal::Ptr(foo.into()), ptr_size, false)?; ecx.memory.mark_static_initalized(foo_ptr.alloc_id, Mutability::Immutable)?; ecx.write_ptr(dest, foo_ptr.into(), ty)?; @@ -158,7 +158,7 @@ pub fn eval_main<'a, 'tcx: 'a>( Ok(()) } - let mut ecx = EvalContext::new(tcx, ty::ParamEnv::empty(traits::Reveal::All), limits, Default::default(), Default::default(), Substs::empty()); + let mut ecx = EvalContext::new(tcx, ty::ParamEnv::empty(traits::Reveal::All), limits, Default::default(), Default::default()); match run_main(&mut ecx, main_id, start_wrapper) { Ok(()) => { let leaks = ecx.memory().leak_report(); @@ -310,22 +310,20 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> { // FIXME: check that it's `#[linkage = "extern_weak"]` trace!("Initializing an extern global with NULL"); let ptr_size = ecx.memory.pointer_size(); + let ptr_align = ecx.tcx.data_layout.pointer_align; let ptr = ecx.memory.allocate( ptr_size, - ptr_size, + ptr_align, None, )?; - ecx.memory.write_ptr_sized_unsigned(ptr, PrimVal::Bytes(0))?; + ecx.memory.write_ptr_sized_unsigned(ptr, ptr_align, PrimVal::Bytes(0))?; ecx.memory.mark_static_initalized(ptr.alloc_id, mutability)?; ecx.tcx.interpret_interner.borrow_mut().cache( GlobalId { instance, promoted: None, }, - PtrAndAlign { - ptr: ptr.into(), - aligned: true, - }, + ptr.into(), ); Ok(()) } diff --git a/miri/operator.rs b/miri/operator.rs index e70f1b12628a..919997a5217c 100644 --- a/miri/operator.rs +++ b/miri/operator.rs @@ -153,7 +153,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' map_to_primval(left.overflowing_offset(right as u64, self)), BitAnd if !signed => { - let base_mask : u64 = !(self.memory.get(left.alloc_id)?.align - 1); + let base_mask : u64 = !(self.memory.get(left.alloc_id)?.align.abi() - 1); let right = right as u64; if right & base_mask == base_mask { // Case 1: The base address bits are all preserved, i.e., right is all-1 there diff --git a/miri/validation.rs b/miri/validation.rs index 52f0c24bd6d1..843dcd4041d7 100644 --- a/miri/validation.rs +++ b/miri/validation.rs @@ -509,7 +509,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' // Check alignment and non-NULLness let (_, align) = self.size_and_align_of_dst(pointee_ty, val)?; let ptr = self.into_ptr(val)?; - self.memory.check_align(ptr, align.abi(), None)?; + self.memory.check_align(ptr, align)?; // Recurse let pointee_place = self.val_to_place(val, pointee_ty)?; @@ -567,7 +567,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' // Tracking the same state for locals not backed by memory would just duplicate too // much machinery. // FIXME: We ignore alignment. - let (ptr, extra) = self.force_allocation(query.place.1)?.to_ptr_extra_aligned(); + let (ptr, _, extra) = self.force_allocation(query.place.1)?.to_ptr_align_extra(); // Determine the size // FIXME: Can we reuse size_and_align_of_dst for Places? let layout = self.layout_of(query.ty)?; From cabdc5597c6adc2e9f492c9cb682a3b58518bd8c Mon Sep 17 00:00:00 2001 From: David Renshaw Date: Sat, 6 Jan 2018 10:21:24 -0500 Subject: [PATCH 0025/5092] update log deps --- Cargo.toml | 2 ++ miri/bin/miri.rs | 21 ++++++++++++--------- miri/lib.rs | 3 ++- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4f0d0fe2ef1c..cc7de42ceabf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,8 @@ byteorder = { version = "1.1", features = ["i128"]} cargo_metadata = { version = "0.2", optional = true } regex = "0.2.2" lazy_static = "1.0" +env_logger = "0.5.0-rc.1" +log = "0.4" [features] cargo_miri = ["cargo_metadata"] diff --git a/miri/bin/miri.rs b/miri/bin/miri.rs index d74c05c0462d..c3d422a6ff5d 100644 --- a/miri/bin/miri.rs +++ b/miri/bin/miri.rs @@ -191,38 +191,41 @@ fn resource_limits_from_attributes(state: &CompileState) -> miri::ResourceLimits } fn init_logger() { - let format = |record: &log::LogRecord| { - if record.level() == log::LogLevel::Trace { + let format = |formatter: &mut env_logger::fmt::Formatter, record: &log::Record| { + use std::io::Write; + if record.level() == log::Level::Trace { // prepend frame number let indentation = log_settings::settings().indentation; - format!( + writeln!( + formatter, "{indentation}:{lvl}:{module}: {text}", lvl = record.level(), - module = record.location().module_path(), + module = record.module_path().unwrap_or(""), indentation = indentation, text = record.args(), ) } else { - format!( + writeln!( + formatter, "{lvl}:{module}: {text}", lvl = record.level(), - module = record.location().module_path(), + module = record.module_path().unwrap_or(""), text = record.args(), ) } }; - let mut builder = env_logger::LogBuilder::new(); + let mut builder = env_logger::Builder::new(); builder.format(format).filter( None, - log::LogLevelFilter::Info, + log::LevelFilter::Info, ); if std::env::var("MIRI_LOG").is_ok() { builder.parse(&std::env::var("MIRI_LOG").unwrap()); } - builder.init().unwrap(); + builder.init(); } fn find_sysroot() -> String { diff --git a/miri/lib.rs b/miri/lib.rs index d458a3c47e8c..9f6550ac072e 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -5,9 +5,10 @@ catch_expr, )] -// From rustc. #[macro_use] extern crate log; + +// From rustc. #[macro_use] extern crate rustc; extern crate rustc_mir; From 33af3208fdb2180570c3ef266abc634a45158ef1 Mon Sep 17 00:00:00 2001 From: David Renshaw Date: Sun, 14 Jan 2018 22:31:59 -0500 Subject: [PATCH 0026/5092] update for rust/47205 --- miri/fn_call.rs | 2 +- miri/lib.rs | 8 ++++---- miri/locks.rs | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/miri/fn_call.rs b/miri/fn_call.rs index df101739ed91..b46f712818f2 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -386,7 +386,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' }; // compute global if not cached let val = match self.tcx.interpret_interner.borrow().get_cached(cid) { - Some(ptr) => ptr, + Some(ptr) => MemoryPointer::new(ptr, 0).into(), None => eval_body(self.tcx, instance, ty::ParamEnv::empty(traits::Reveal::All))?.0, }; let val = self.value_to_primval(ValTy { value: Value::ByRef(val, name_align), diff --git a/miri/lib.rs b/miri/lib.rs index 9f6550ac072e..92ae0ab8a820 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -203,7 +203,7 @@ pub struct MemoryData<'tcx> { /// /// Only mutable (static mut, heap, stack) allocations have an entry in this map. /// The entry is created when allocating the memory and deleted after deallocation. - locks: HashMap>>, + locks: HashMap>>, } impl<'tcx> Machine<'tcx> for Evaluator<'tcx> { @@ -324,7 +324,7 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> { instance, promoted: None, }, - ptr.into(), + ptr.alloc_id, ); Ok(()) } @@ -340,14 +340,14 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> { fn add_lock<'a>( mem: &mut Memory<'a, 'tcx, Self>, - id: u64, + id: AllocId, ) { mem.data.locks.insert(id, RangeMap::new()); } fn free_lock<'a>( mem: &mut Memory<'a, 'tcx, Self>, - id: u64, + id: AllocId, len: u64, ) -> EvalResult<'tcx> { mem.data.locks diff --git a/miri/locks.rs b/miri/locks.rs index 3a9df6a38dff..f0e8815c4fc5 100644 --- a/miri/locks.rs +++ b/miri/locks.rs @@ -109,7 +109,7 @@ impl<'a, 'tcx: 'a> MemoryExt<'tcx> for Memory<'a, 'tcx, Evaluator<'tcx>> { if len == 0 { return Ok(()); } - let locks = match self.data.locks.get(&ptr.alloc_id.0) { + let locks = match self.data.locks.get(&ptr.alloc_id) { Some(locks) => locks, // immutable static or other constant memory None => return Ok(()), @@ -148,7 +148,7 @@ impl<'a, 'tcx: 'a> MemoryExt<'tcx> for Memory<'a, 'tcx, Evaluator<'tcx>> { ); self.check_bounds(ptr.offset(len, &*self)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow) - let locks = match self.data.locks.get_mut(&ptr.alloc_id.0) { + let locks = match self.data.locks.get_mut(&ptr.alloc_id) { Some(locks) => locks, // immutable static or other constant memory None => return Ok(()), @@ -197,7 +197,7 @@ impl<'a, 'tcx: 'a> MemoryExt<'tcx> for Memory<'a, 'tcx, Evaluator<'tcx>> { ) -> EvalResult<'tcx> { assert!(len > 0); let cur_frame = self.cur_frame; - let locks = match self.data.locks.get_mut(&ptr.alloc_id.0) { + let locks = match self.data.locks.get_mut(&ptr.alloc_id) { Some(locks) => locks, // immutable static or other constant memory None => return Ok(()), @@ -275,7 +275,7 @@ impl<'a, 'tcx: 'a> MemoryExt<'tcx> for Memory<'a, 'tcx, Evaluator<'tcx>> { frame: cur_frame, path: lock_path.clone(), }; - let locks = match self.data.locks.get_mut(&ptr.alloc_id.0) { + let locks = match self.data.locks.get_mut(&ptr.alloc_id) { Some(locks) => locks, // immutable static or other constant memory None => return Ok(()), From d289c0f46467fc8abd7b89129116e8dd959c3e34 Mon Sep 17 00:00:00 2001 From: David Renshaw Date: Mon, 15 Jan 2018 09:47:17 -0500 Subject: [PATCH 0027/5092] partially deal with rust/46479 --- miri/lib.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/miri/lib.rs b/miri/lib.rs index 92ae0ab8a820..091a3b7e1dfb 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -75,7 +75,14 @@ pub fn eval_main<'a, 'tcx: 'a>( } if let Some(start_id) = start_wrapper { - let start_instance = ty::Instance::mono(ecx.tcx, start_id); + let main_ret_ty = ecx.tcx.fn_sig(main_id).output(); + let main_ret_ty = main_ret_ty.no_late_bound_regions().unwrap(); + let start_instance = ty::Instance::resolve( + ecx.tcx, + ty::ParamEnv::empty(traits::Reveal::All), + start_id, + ecx.tcx.mk_substs( + ::std::iter::once(ty::subst::Kind::from(main_ret_ty)))).unwrap(); let start_mir = ecx.load_mir(start_instance.def)?; if start_mir.arg_count != 3 { From 61833b9aeab8bf8f0c0c0e42b7c96b6eceb37d0d Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 30 Jan 2018 15:11:09 +0100 Subject: [PATCH 0028/5092] Update compiletest_rs dependency to match clippy's --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index bbb3958ac35f..70457fed9077 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,4 +31,4 @@ lazy_static = "1.0" cargo_miri = ["cargo_metadata"] [dev-dependencies] -compiletest_rs = { version = "0.3.3", features = ["tmp"] } +compiletest_rs = { version = "0.3.6", features = ["tmp"] } From d4712ca37500f26bbcbf97edcb27820717f769f7 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 6 Mar 2018 15:36:52 +0100 Subject: [PATCH 0029/5092] Update compiletest_rs dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 70457fed9077..b32f0d0e9a72 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,4 +31,4 @@ lazy_static = "1.0" cargo_miri = ["cargo_metadata"] [dev-dependencies] -compiletest_rs = { version = "0.3.6", features = ["tmp"] } +compiletest_rs = { version = "0.3.7", features = ["tmp"] } From 753da676bacd058cd6ef58aa23f02b787381421e Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 14 Jan 2018 18:59:13 +0100 Subject: [PATCH 0030/5092] Rustup --- miri/bin/miri.rs | 65 +++++++------------------------------ miri/fn_call.rs | 24 +++++++------- miri/helpers.rs | 2 +- miri/intrinsic.rs | 15 ++++----- miri/lib.rs | 81 +++++++++++++++++++++++++++------------------- miri/locks.rs | 2 +- miri/operator.rs | 4 +-- miri/tls.rs | 4 +-- miri/validation.rs | 44 ++++++++++++++++--------- 9 files changed, 113 insertions(+), 128 deletions(-) diff --git a/miri/bin/miri.rs b/miri/bin/miri.rs index c3d422a6ff5d..bbc8322194fa 100644 --- a/miri/bin/miri.rs +++ b/miri/bin/miri.rs @@ -5,6 +5,7 @@ extern crate miri; extern crate rustc; extern crate rustc_driver; extern crate rustc_errors; +extern crate rustc_trans_utils; extern crate env_logger; extern crate log_settings; extern crate syntax; @@ -17,7 +18,8 @@ use rustc_driver::driver::{CompileState, CompileController}; use rustc::session::config::{self, Input, ErrorOutputType}; use rustc::hir::{self, itemlikevisit}; use rustc::ty::TyCtxt; -use syntax::ast::{self, MetaItemKind, NestedMetaItemKind}; +use rustc_trans_utils::trans_crate::TransCrate; +use syntax::ast; use std::path::PathBuf; struct MiriCompilerCalls { @@ -61,6 +63,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { } fn late_callback( &mut self, + trans: &TransCrate, matches: &getopts::Matches, sess: &Session, cstore: &CrateStore, @@ -68,7 +71,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { odir: &Option, ofile: &Option, ) -> Compilation { - self.default.late_callback(matches, sess, cstore, input, odir, ofile) + self.default.late_callback(trans, matches, sess, cstore, input, odir, ofile) } fn build_controller( &mut self, @@ -98,11 +101,9 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { state.session.abort_if_errors(); let tcx = state.tcx.unwrap(); - let limits = resource_limits_from_attributes(state); if std::env::args().any(|arg| arg == "--test") { struct Visitor<'a, 'tcx: 'a>( - miri::ResourceLimits, TyCtxt<'a, 'tcx, 'tcx>, &'a CompileState<'a, 'tcx> ); @@ -113,13 +114,13 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { attr.name().map_or(false, |n| n == "test") }) { - let did = self.1.hir.body_owner_def_id(body_id); + let did = self.0.hir.body_owner_def_id(body_id); println!( "running test: {}", - self.1.def_path_debug_str(did), + self.0.def_path_debug_str(did), ); - miri::eval_main(self.1, did, None, self.0); - self.2.session.abort_if_errors(); + miri::eval_main(self.0, did, None); + self.1.session.abort_if_errors(); } } } @@ -127,7 +128,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {} } state.hir_crate.unwrap().visit_all_item_likes( - &mut Visitor(limits, tcx, state), + &mut Visitor(tcx, state), ); } else if let Some((entry_node_id, _)) = *state.session.entry_fn.borrow() { let entry_def_id = tcx.hir.local_def_id(entry_node_id); @@ -138,7 +139,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { None } }); - miri::eval_main(tcx, entry_def_id, start_wrapper, limits); + miri::eval_main(tcx, entry_def_id, start_wrapper); state.session.abort_if_errors(); } else { @@ -146,50 +147,6 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { } } -fn resource_limits_from_attributes(state: &CompileState) -> miri::ResourceLimits { - let mut limits = miri::ResourceLimits::default(); - let krate = state.hir_crate.as_ref().unwrap(); - let err_msg = "miri attributes need to be in the form `miri(key = value)`"; - let extract_int = |lit: &syntax::ast::Lit| -> u128 { - match lit.node { - syntax::ast::LitKind::Int(i, _) => i, - _ => { - state.session.span_fatal( - lit.span, - "expected an integer literal", - ) - } - } - }; - - for attr in krate.attrs.iter().filter(|a| { - a.name().map_or(false, |n| n == "miri") - }) - { - if let Some(items) = attr.meta_item_list() { - for item in items { - if let NestedMetaItemKind::MetaItem(ref inner) = item.node { - if let MetaItemKind::NameValue(ref value) = inner.node { - match &inner.name().as_str()[..] { - "memory_size" => limits.memory_size = extract_int(value) as u64, - "step_limit" => limits.step_limit = extract_int(value) as u64, - "stack_limit" => limits.stack_limit = extract_int(value) as usize, - _ => state.session.span_err(item.span, "unknown miri attribute"), - } - } else { - state.session.span_err(inner.span, err_msg); - } - } else { - state.session.span_err(item.span, err_msg); - } - } - } else { - state.session.span_err(attr.span, err_msg); - } - } - limits -} - fn init_logger() { let format = |formatter: &mut env_logger::fmt::Formatter, record: &log::Record| { use std::io::Write; diff --git a/miri/fn_call.rs b/miri/fn_call.rs index b46f712818f2..d07929e0d560 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -8,8 +8,6 @@ use syntax::codemap::Span; use std::mem; -use rustc::traits; - use super::*; use tls::MemoryExt; @@ -49,7 +47,7 @@ pub trait EvalContextExt<'tcx> { fn write_null(&mut self, dest: Place, dest_ty: Ty<'tcx>) -> EvalResult<'tcx>; } -impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'tcx>> { +impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { fn eval_fn_call( &mut self, instance: ty::Instance<'tcx>, @@ -385,13 +383,17 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' promoted: None, }; // compute global if not cached - let val = match self.tcx.interpret_interner.borrow().get_cached(cid) { - Some(ptr) => MemoryPointer::new(ptr, 0).into(), - None => eval_body(self.tcx, instance, ty::ParamEnv::empty(traits::Reveal::All))?.0, + let value: Value = match self.tcx.interpret_interner.get_cached(instance.def_id()) { + Some(ptr) => { + Value::ByRef(MemoryPointer::new(ptr, 0).into(), name_align) + } + None => { + let res: Option<(Value, Pointer, Ty)> = eval_body(self.tcx.tcx, cid, ty::ParamEnv::reveal_all()); + res.ok_or_else(||EvalErrorKind::MachineError("".to_string()))?.0 + }, }; - let val = self.value_to_primval(ValTy { value: Value::ByRef(val, name_align), - ty: args[0].ty })?.to_u64()?; - if val == name { + let value = self.value_to_primval(ValTy { value, ty: args[0].ty })?.to_u64()?; + if value == name { result = Some(path_value); break; } @@ -420,7 +422,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' }; // Figure out how large a pthread TLS key actually is. This is libc::pthread_key_t. - let key_type = args[0].ty.builtin_deref(true, ty::LvaluePreference::NoPreference) + let key_type = args[0].ty.builtin_deref(true) .ok_or(EvalErrorKind::AbiViolation("Wrong signature used for pthread_key_create: First argument must be a raw pointer.".to_owned()))?.ty; let key_size = self.layout_of(key_type)?.size; @@ -502,7 +504,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' for item in mem::replace(&mut items, Default::default()).iter() { if item.ident.name == *segment { if path_it.peek().is_none() { - return Some(ty::Instance::mono(self.tcx, item.def.def_id())); + return Some(ty::Instance::mono(self.tcx.tcx, item.def.def_id())); } items = self.tcx.item_children(item.def.def_id()); diff --git a/miri/helpers.rs b/miri/helpers.rs index 0e541cf29208..3dd499f7a62e 100644 --- a/miri/helpers.rs +++ b/miri/helpers.rs @@ -18,7 +18,7 @@ pub trait EvalContextExt<'tcx> { ) -> EvalResult<'tcx, Pointer>; } -impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'tcx>> { +impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { fn wrapping_pointer_offset( &self, ptr: Pointer, diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index 3357f0bba392..5047ab5b6ac2 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -1,5 +1,4 @@ use rustc::mir; -use rustc::traits::Reveal; use rustc::ty::layout::{TyLayout, LayoutOf}; use rustc::ty; @@ -19,7 +18,7 @@ pub trait EvalContextExt<'tcx> { ) -> EvalResult<'tcx>; } -impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'tcx>> { +impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { fn call_intrinsic( &mut self, instance: ty::Instance<'tcx>, @@ -349,7 +348,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' match dest { Place::Local { frame, local } => self.modify_local(frame, local, init)?, Place::Ptr { - ptr: ptr, + ptr, align: _align, extra: PlaceExtra::None, } => self.memory.write_repeat(ptr, 0, size)?, @@ -381,8 +380,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' "needs_drop" => { let ty = substs.type_at(0); - let env = ty::ParamEnv::empty(Reveal::All); - let needs_drop = ty.needs_drop(self.tcx, env); + let env = ty::ParamEnv::reveal_all(); + let needs_drop = ty.needs_drop(self.tcx.tcx, env); self.write_primval( dest, PrimVal::from_bool(needs_drop), @@ -542,10 +541,10 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' "transmute" => { let src_ty = substs.type_at(0); - let src_align = self.layout_of(src_ty)?.align; + let _src_align = self.layout_of(src_ty)?.align; let ptr = self.force_allocation(dest)?.to_ptr()?; let dest_align = self.layout_of(substs.type_at(1))?.align; - self.write_value_to_ptr(args[0].value, ptr.into(), dest_align, src_ty); + self.write_value_to_ptr(args[0].value, ptr.into(), dest_align, src_ty).unwrap(); } "unchecked_shl" => { @@ -626,7 +625,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' match dest { Place::Local { frame, local } => self.modify_local(frame, local, uninit)?, Place::Ptr { - ptr: ptr, + ptr, align: _align, extra: PlaceExtra::None, } => self.memory.mark_definedness(ptr, size, false)?, diff --git a/miri/lib.rs b/miri/lib.rs index 091a3b7e1dfb..99bc91a17177 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -22,7 +22,6 @@ use rustc::ty::{self, TyCtxt}; use rustc::ty::layout::{TyLayout, LayoutOf}; use rustc::hir::def_id::DefId; use rustc::mir; -use rustc::traits; use syntax::ast::Mutability; use syntax::codemap::Span; @@ -56,14 +55,13 @@ pub fn eval_main<'a, 'tcx: 'a>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, start_wrapper: Option, - limits: ResourceLimits, ) { - fn run_main<'a, 'tcx: 'a>( - ecx: &mut rustc_mir::interpret::EvalContext<'a, 'tcx, Evaluator<'tcx>>, + fn run_main<'a, 'mir: 'a, 'tcx: 'mir>( + ecx: &mut rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>, main_id: DefId, start_wrapper: Option, ) -> EvalResult<'tcx> { - let main_instance = ty::Instance::mono(ecx.tcx, main_id); + let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; let mut cleanup_ptr = None; // Pointer to be deallocated when we are done @@ -78,8 +76,8 @@ pub fn eval_main<'a, 'tcx: 'a>( let main_ret_ty = ecx.tcx.fn_sig(main_id).output(); let main_ret_ty = main_ret_ty.no_late_bound_regions().unwrap(); let start_instance = ty::Instance::resolve( - ecx.tcx, - ty::ParamEnv::empty(traits::Reveal::All), + ecx.tcx.tcx, + ty::ParamEnv::reveal_all(), start_id, ecx.tcx.mk_substs( ::std::iter::once(ty::subst::Kind::from(main_ret_ty)))).unwrap(); @@ -112,8 +110,8 @@ pub fn eval_main<'a, 'tcx: 'a>( // First argument: pointer to main() let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance); let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - let main_ty = main_instance.ty(ecx.tcx); - let main_ptr_ty = ecx.tcx.mk_fn_ptr(main_ty.fn_sig(ecx.tcx)); + let main_ty = main_instance.ty(ecx.tcx.tcx); + let main_ptr_ty = ecx.tcx.mk_fn_ptr(main_ty.fn_sig(ecx.tcx.tcx)); ecx.write_value( ValTy { value: Value::ByVal(PrimVal::Ptr(main_ptr)), @@ -136,7 +134,7 @@ pub fn eval_main<'a, 'tcx: 'a>( let ptr_align = ecx.tcx.data_layout.pointer_align; let foo_ptr = ecx.memory.allocate(ptr_size, ptr_align, None)?; ecx.memory.write_primval(foo_ptr, ptr_align, PrimVal::Ptr(foo.into()), ptr_size, false)?; - ecx.memory.mark_static_initalized(foo_ptr.alloc_id, Mutability::Immutable)?; + ecx.memory.mark_static_initialized(foo_ptr.alloc_id, Mutability::Immutable)?; ecx.write_ptr(dest, foo_ptr.into(), ty)?; assert!(args.next().is_none(), "start lang item has more arguments than expected"); @@ -166,7 +164,7 @@ pub fn eval_main<'a, 'tcx: 'a>( Ok(()) } - let mut ecx = EvalContext::new(tcx, ty::ParamEnv::empty(traits::Reveal::All), limits, Default::default(), Default::default()); + let mut ecx = EvalContext::new(tcx.at(syntax::codemap::DUMMY_SP), ty::ParamEnv::reveal_all(), Default::default(), Default::default()); match run_main(&mut ecx, main_id, start_wrapper) { Ok(()) => { let leaks = ecx.memory().leak_report(); @@ -175,7 +173,7 @@ pub fn eval_main<'a, 'tcx: 'a>( } } Err(mut e) => { - ecx.report(&mut e); + ecx.report(&mut e, true, None); } } } @@ -213,13 +211,13 @@ pub struct MemoryData<'tcx> { locks: HashMap>>, } -impl<'tcx> Machine<'tcx> for Evaluator<'tcx> { +impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryData = MemoryData<'tcx>; type MemoryKinds = memory::MemoryKind; /// Returns Ok() when the function was handled, fail otherwise fn eval_fn_call<'a>( - ecx: &mut EvalContext<'a, 'tcx, Self>, + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, destination: Option<(Place, mir::BasicBlock)>, args: &[ValTy<'tcx>], @@ -230,7 +228,7 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> { } fn call_intrinsic<'a>( - ecx: &mut rustc_mir::interpret::EvalContext<'a, 'tcx, Self>, + ecx: &mut rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[ValTy<'tcx>], dest: Place, @@ -241,7 +239,7 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> { } fn try_ptr_op<'a>( - ecx: &rustc_mir::interpret::EvalContext<'a, 'tcx, Self>, + ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, bin_op: mir::BinOp, left: PrimVal, left_ty: ty::Ty<'tcx>, @@ -251,17 +249,35 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> { ecx.ptr_op(bin_op, left, left_ty, right, right_ty) } - fn mark_static_initialized(m: memory::MemoryKind) -> EvalResult<'tcx> { - use memory::MemoryKind::*; + fn mark_static_initialized<'a>( + _mem: &mut Memory<'a, 'mir, 'tcx, Self>, + _id: AllocId, + _mutability: Mutability, + ) -> EvalResult<'tcx, bool> { + /*use memory::MemoryKind::*; match m { // FIXME: This could be allowed, but not for env vars set during miri execution Env => err!(Unimplemented("statics can't refer to env vars".to_owned())), - _ => Ok(()), - } + _ => Ok(false), // TODO: What does the bool mean? + }*/ + Ok(true) + } + + fn init_static<'a>( + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + cid: GlobalId<'tcx>, + ) -> EvalResult<'tcx, AllocId> { + let def_id = cid.instance.def_id(); + let ty = ecx.tcx.type_of(def_id); + let layout = ecx.tcx.layout_of(ty::ParamEnvAnd { + param_env: ty::ParamEnv::reveal_all(), + value: ty + }).expect("Couldn't compute layout for the type of a static"); + ecx.memory.allocate(layout.size.bytes(), layout.align, None).map(|mptr|mptr.alloc_id) } fn box_alloc<'a>( - ecx: &mut EvalContext<'a, 'tcx, Self>, + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, ty: ty::Ty<'tcx>, dest: Place, ) -> EvalResult<'tcx> { @@ -269,7 +285,7 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> { // Call the `exchange_malloc` lang item let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap(); - let malloc = ty::Instance::mono(ecx.tcx, malloc); + let malloc = ty::Instance::mono(ecx.tcx.tcx, malloc); let malloc_mir = ecx.load_mir(malloc.def)?; ecx.push_stack_frame( malloc, @@ -311,7 +327,7 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> { } fn global_item_with_linkage<'a>( - ecx: &mut EvalContext<'a, 'tcx, Self>, + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, mutability: Mutability, ) -> EvalResult<'tcx> { @@ -325,19 +341,16 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> { None, )?; ecx.memory.write_ptr_sized_unsigned(ptr, ptr_align, PrimVal::Bytes(0))?; - ecx.memory.mark_static_initalized(ptr.alloc_id, mutability)?; - ecx.tcx.interpret_interner.borrow_mut().cache( - GlobalId { - instance, - promoted: None, - }, + ecx.memory.mark_static_initialized(ptr.alloc_id, mutability)?; + ecx.tcx.interpret_interner.cache( + instance.def_id(), ptr.alloc_id, ); Ok(()) } fn check_locks<'a>( - mem: &Memory<'a, 'tcx, Self>, + mem: &Memory<'a, 'mir, 'tcx, Self>, ptr: MemoryPointer, size: u64, access: AccessKind, @@ -346,14 +359,14 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> { } fn add_lock<'a>( - mem: &mut Memory<'a, 'tcx, Self>, + mem: &mut Memory<'a, 'mir, 'tcx, Self>, id: AllocId, ) { mem.data.locks.insert(id, RangeMap::new()); } fn free_lock<'a>( - mem: &mut Memory<'a, 'tcx, Self>, + mem: &mut Memory<'a, 'mir, 'tcx, Self>, id: AllocId, len: u64, ) -> EvalResult<'tcx> { @@ -379,14 +392,14 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> { } fn end_region<'a>( - ecx: &mut EvalContext<'a, 'tcx, Self>, + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, reg: Option<::rustc::middle::region::Scope>, ) -> EvalResult<'tcx> { ecx.end_region(reg) } fn validation_op<'a>( - ecx: &mut EvalContext<'a, 'tcx, Self>, + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, op: ::rustc::mir::ValidationOp, operand: &::rustc::mir::ValidationOperand<'tcx, ::rustc::mir::Place<'tcx>>, ) -> EvalResult<'tcx> { diff --git a/miri/locks.rs b/miri/locks.rs index f0e8815c4fc5..677b0454a546 100644 --- a/miri/locks.rs +++ b/miri/locks.rs @@ -99,7 +99,7 @@ pub trait MemoryExt<'tcx> { } -impl<'a, 'tcx: 'a> MemoryExt<'tcx> for Memory<'a, 'tcx, Evaluator<'tcx>> { +impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evaluator<'tcx>> { fn check_locks( &self, ptr: MemoryPointer, diff --git a/miri/operator.rs b/miri/operator.rs index 919997a5217c..220f8f9acd54 100644 --- a/miri/operator.rs +++ b/miri/operator.rs @@ -24,7 +24,7 @@ pub trait EvalContextExt<'tcx> { ) -> EvalResult<'tcx, (PrimVal, bool)>; } -impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'tcx>> { +impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { fn ptr_op( &self, bin_op: mir::BinOp, @@ -42,7 +42,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' match bin_op { Offset if left_kind == Ptr && right_kind == usize => { let pointee_ty = left_ty - .builtin_deref(true, ty::LvaluePreference::NoPreference) + .builtin_deref(true) .expect("Offset called on non-ptr type") .ty; let ptr = self.pointer_offset( diff --git a/miri/tls.rs b/miri/tls.rs index 7f4f194c67f1..e55cbede2339 100644 --- a/miri/tls.rs +++ b/miri/tls.rs @@ -18,7 +18,7 @@ pub trait EvalContextExt<'tcx> { fn run_tls_dtors(&mut self) -> EvalResult<'tcx>; } -impl<'a, 'tcx: 'a> MemoryExt<'tcx> for Memory<'a, 'tcx, Evaluator<'tcx>> { +impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evaluator<'tcx>> { fn create_tls_key(&mut self, dtor: Option>) -> TlsKey { let new_key = self.data.next_thread_local; self.data.next_thread_local += 1; @@ -106,7 +106,7 @@ impl<'a, 'tcx: 'a> MemoryExt<'tcx> for Memory<'a, 'tcx, Evaluator<'tcx>> { } } -impl<'a, 'tcx: 'a> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, Evaluator<'tcx>> { +impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>> { fn run_tls_dtors(&mut self) -> EvalResult<'tcx> { let mut dtor = self.memory.fetch_tls_dtor(None)?; // FIXME: replace loop by some structure that works with stepping diff --git a/miri/validation.rs b/miri/validation.rs index 843dcd4041d7..801fd952f666 100644 --- a/miri/validation.rs +++ b/miri/validation.rs @@ -1,15 +1,16 @@ use rustc::hir::{self, Mutability}; use rustc::hir::Mutability::*; use rustc::mir::{self, ValidationOp, ValidationOperand}; -use rustc::ty::{self, Ty, TypeFoldable, TyCtxt}; +use rustc::mir::interpret::GlobalId; +use rustc::ty::{self, Ty, TypeFoldable, TyCtxt, Instance}; use rustc::ty::layout::LayoutOf; use rustc::ty::subst::{Substs, Subst}; use rustc::traits; use rustc::infer::InferCtxt; -use rustc::traits::Reveal; use rustc::middle::region; +use rustc::middle::const_val::ConstVal; use rustc_data_structures::indexed_vec::Idx; -use rustc_mir::interpret::HasMemory; +use rustc_mir::interpret::{HasMemory, eval_body}; use super::{EvalContext, Place, PlaceExtra, ValTy}; use rustc::mir::interpret::{DynamicLifetime, AccessKind, EvalErrorKind, Value, EvalError, EvalResult}; @@ -108,7 +109,7 @@ pub(crate) trait EvalContextExt<'tcx> { ) -> EvalResult<'tcx>; } -impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'tcx>> { +impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { fn abstract_place_projection(&self, proj: &mir::PlaceProjection<'tcx>) -> EvalResult<'tcx, AbsPlaceProjection<'tcx>> { use self::mir::ProjectionElem::*; @@ -117,7 +118,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' Field(f, _) => Field(f, ()), Index(v) => { let value = self.frame().get_local(v)?; - let ty = self.tcx.types.usize; + let ty = self.tcx.tcx.types.usize; let n = self.value_to_primval(ValTy { value, ty })?.to_u64()?; Index(n) }, @@ -152,7 +153,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' // because other crates may have been compiled with mir-emit-validate > 0. Ignore those // commands. This makes mir-emit-validate also a flag to control whether miri will do // validation or not. - if self.tcx.sess.opts.debugging_opts.mir_emit_validate == 0 { + if self.tcx.tcx.sess.opts.debugging_opts.mir_emit_validate == 0 { return Ok(()); } debug_assert!(self.memory.cur_frame == self.cur_frame()); @@ -187,7 +188,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' // We need to monomorphize ty *without* erasing lifetimes trace!("validation_op1: {:?}", operand.ty.sty); - let ty = operand.ty.subst(self.tcx, self.substs()); + let ty = operand.ty.subst(self.tcx.tcx, self.substs()); trace!("validation_op2: {:?}", operand.ty.sty); let place = self.eval_place(&operand.place)?; let abs_place = self.abstract_place(&operand.place)?; @@ -250,7 +251,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' } fn normalize_type_unerased(&self, ty: Ty<'tcx>) -> Ty<'tcx> { - return normalize_associated_type(self.tcx, &ty); + return normalize_associated_type(self.tcx.tcx, &ty); use syntax::codemap::{Span, DUMMY_SP}; @@ -356,7 +357,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' where T: MyTransNormalize<'tcx>, { - let param_env = ty::ParamEnv::empty(Reveal::All); + let param_env = ty::ParamEnv::reveal_all(); if !value.has_projections() { return value.clone(); @@ -383,7 +384,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' } _ => {} } - let tcx = self.tcx; + let tcx = self.tcx.tcx; Ok(match layout.ty.sty { ty::TyBool | ty::TyChar | @@ -393,6 +394,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' ty::TyFnPtr(_) | ty::TyNever | ty::TyFnDef(..) | + ty::TyGeneratorWitness(..) | ty::TyDynamic(..) | ty::TyForeign(..) => { bug!("TyLayout::field_type({:?}): not applicable", layout) @@ -437,7 +439,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' substs.field_tys(def_id, tcx).nth(i).unwrap() } - ty::TyTuple(tys, _) => tys[i], + ty::TyTuple(tys) => tys[i], // SIMD vector types. ty::TyAdt(def, ..) if def.repr.simd() => { @@ -558,6 +560,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' TyAdt(adt, _) if adt.is_box() => true, TySlice(_) | TyAdt(_, _) | TyTuple(..) | TyClosure(..) | TyArray(..) | TyDynamic(..) | TyGenerator(..) | TyForeign(_) => false, + TyGeneratorWitness(..) => bug!("I'm not sure what to return here"), TyParam(_) | TyInfer(_) | TyProjection(_) | TyAnon(..) | TyError => { bug!("I got an incomplete/unnormalized type for validation") } @@ -725,7 +728,18 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' Ok(()) } TyArray(elem_ty, len) => { - let len = len.val.to_const_int().unwrap().to_u64().unwrap(); + let len_val = match len.val { + ConstVal::Unevaluated(def_id, substs) => { + eval_body(self.tcx.tcx, GlobalId { + instance: Instance::new(def_id, substs), + promoted: None, + }, ty::ParamEnv::reveal_all()) + .ok_or_else(||EvalErrorKind::MachineError("".to_string()))? + .0 + } + ConstVal::Value(val) => val, + }; + let len = ConstVal::Value(len_val).unwrap_u64(); for i in 0..len { let inner_place = self.place_index(query.place.1, query.ty, i as u64)?; self.validate( @@ -759,7 +773,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' Ok(()) } TyAdt(adt, _) => { - if Some(adt.did) == self.tcx.lang_items().unsafe_cell_type() && + if Some(adt.did) == self.tcx.tcx.lang_items().unsafe_cell_type() && query.mutbl == MutImmutable { // No locks for shared unsafe cells. Also no other validation, the only field is private anyway. @@ -771,8 +785,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' let discr = self.read_discriminant_value(query.place.1, query.ty)?; // Get variant index for discriminant - let variant_idx = adt.discriminants(self.tcx).position(|variant_discr| { - variant_discr.to_u128_unchecked() == discr + let variant_idx = adt.discriminants(self.tcx.tcx).position(|variant_discr| { + variant_discr.val == discr }); let variant_idx = match variant_idx { Some(val) => val, From a3a01ba5b7c955f65d576d8f51b57d9cb307f481 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 17 Mar 2018 18:57:18 +0100 Subject: [PATCH 0031/5092] Add stack guard shim --- miri/fn_call.rs | 71 ++++++++++++++++++++++++++++++++++++++++++++++++- miri/lib.rs | 1 + 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/miri/fn_call.rs b/miri/fn_call.rs index d07929e0d560..d5d77c5d3259 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -1,7 +1,8 @@ use rustc::ty::{self, Ty}; -use rustc::ty::layout::{Align, LayoutOf}; +use rustc::ty::layout::{self, Align, LayoutOf}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; +use rustc_data_structures::indexed_vec::Idx; use syntax::attr; use syntax::abi::Abi; use syntax::codemap::Span; @@ -14,6 +15,50 @@ use tls::MemoryExt; use super::memory::MemoryKind; +fn write_discriminant_value<'a, 'mir, 'tcx: 'a + 'mir>( + ecx: &mut EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>>, + dest_ty: Ty<'tcx>, + dest: Place, + variant_index: usize, + ) -> EvalResult<'tcx> { + let layout = ecx.layout_of(dest_ty)?; + + match layout.variants { + layout::Variants::Single { index } => { + if index != variant_index { + // If the layout of an enum is `Single`, all + // other variants are necessarily uninhabited. + assert_eq!(layout.for_variant(&ecx, variant_index).abi, + layout::Abi::Uninhabited); + } + } + layout::Variants::Tagged { .. } => { + let discr_val = dest_ty.ty_adt_def().unwrap() + .discriminant_for_variant(*ecx.tcx, variant_index) + .val; + + let (discr_dest, discr) = ecx.place_field(dest, mir::Field::new(0), layout)?; + ecx.write_primval(discr_dest, PrimVal::Bytes(discr_val), discr.ty)?; + } + layout::Variants::NicheFilling { + dataful_variant, + ref niche_variants, + niche_start, + .. + } => { + if variant_index != dataful_variant { + let (niche_dest, niche) = + ecx.place_field(dest, mir::Field::new(0), layout)?; + let niche_value = ((variant_index - niche_variants.start) as u128) + .wrapping_add(niche_start); + ecx.write_primval(niche_dest, PrimVal::Bytes(niche_value), niche.ty)?; + } + } + } + + Ok(()) + } + pub trait EvalContextExt<'tcx> { fn call_c_abi( &mut self, @@ -58,6 +103,30 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' ) -> EvalResult<'tcx, bool> { trace!("eval_fn_call: {:#?}, {:#?}", instance, destination); + let def_id = instance.def_id(); + let item_path = self.tcx.absolute_item_path_str(def_id); + if item_path.starts_with("std::") { + println!("{}", item_path); + } + match &*item_path { + "std::sys::unix::thread::guard::init" | "std::sys::unix::thread::guard::current" => { + // Return None, as it doesn't make sense to return Some, because miri detects stack overflow itself. + let ret_ty = sig.output(); + match ret_ty.sty { + ty::TyAdt(ref adt_def, _) => { + assert!(adt_def.is_enum(), "Unexpected return type for {}", item_path); + let none_variant_index = adt_def.variants.iter().enumerate().find(|&(_i, ref def)| { + def.name.as_str() == "None" + }).expect("No None variant").0; + write_discriminant_value(self, ret_ty, destination.unwrap().0, none_variant_index)?; + return Ok(true); + } + _ => panic!("Unexpected return type for {}", item_path) + } + } + _ => {} + } + let mir = match self.load_mir(instance.def) { Ok(mir) => mir, Err(EvalError { kind: EvalErrorKind::NoMirFor(path), .. }) => { diff --git a/miri/lib.rs b/miri/lib.rs index 99bc91a17177..85827da5dd3c 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -3,6 +3,7 @@ rustc_private, conservative_impl_trait, catch_expr, + inclusive_range_fields )] #[macro_use] From cd89e56f152798ef437377acd7d503dae2b3cb99 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sun, 18 Mar 2018 13:18:41 +0100 Subject: [PATCH 0032/5092] Get the tests one step further --- miri/fn_call.rs | 6 ++++-- tests/compiletest.rs | 10 +++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/miri/fn_call.rs b/miri/fn_call.rs index d5d77c5d3259..70b4900a4eff 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -106,7 +106,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let def_id = instance.def_id(); let item_path = self.tcx.absolute_item_path_str(def_id); if item_path.starts_with("std::") { - println!("{}", item_path); + //println!("{}", item_path); } match &*item_path { "std::sys::unix::thread::guard::init" | "std::sys::unix::thread::guard::current" => { @@ -118,7 +118,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let none_variant_index = adt_def.variants.iter().enumerate().find(|&(_i, ref def)| { def.name.as_str() == "None" }).expect("No None variant").0; - write_discriminant_value(self, ret_ty, destination.unwrap().0, none_variant_index)?; + let (return_place, return_to_block) = destination.unwrap(); + write_discriminant_value(self, ret_ty, return_place, none_variant_index)?; + self.goto_block(return_to_block); return Ok(true); } _ => panic!("Unexpected return type for {}", item_path) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index b1ea3fc8b0d4..e2e00d828c1a 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -53,10 +53,10 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, fullmir: b let sysroot = std::env::home_dir().unwrap() .join(".xargo") .join("HOST"); - config.target_rustcflags = Some(format!("--sysroot {}", sysroot.to_str().unwrap())); + flags.push(format!("--sysroot {}", sysroot.to_str().unwrap())); config.src_base = PathBuf::from(path.to_string()); } else { - config.target_rustcflags = Some(format!("--sysroot {}", sysroot.to_str().unwrap())); + flags.push(format!("--sysroot {}", sysroot.to_str().unwrap())); config.src_base = PathBuf::from(path.to_string()); } flags.push("-Zmir-emit-validate=1".to_owned()); @@ -206,8 +206,8 @@ fn compile_fail_miri() { let sysroot = get_sysroot(); let host = get_host(); - for_all_targets(&sysroot, |target| { - compile_fail(&sysroot, "tests/compile-fail", &target, &host, false); - }); + // FIXME: run tests for other targets, too + compile_fail(&sysroot, "tests/compile-fail", &host, &host, true); + compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true); } From d4f30aa9c1bc9e343cd47904ac8deef479fcf047 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 18 Mar 2018 19:25:13 +0100 Subject: [PATCH 0033/5092] Fix alignment issue --- miri/intrinsic.rs | 10 +++++++++- xargo/Cargo.lock | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index 5047ab5b6ac2..d01d52ad1af7 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -217,8 +217,16 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // Also see the write_bytes intrinsic. let elem_align = elem_layout.align; let src = self.into_ptr(args[0].value)?; - let src_align = self.layout_of(args[0].ty)?.align; + //let src_align = self.layout_of(args[0].ty)?.align; + let src_align = ty::layout::Align::from_bytes(1, 1).unwrap(); let dest = self.into_ptr(args[1].value)?; + /*self.tcx.sess.warn(&format!("src_ty: {:?} src_align: {} elem_align: {} src_aligned: {:?} dst_aligned: {:?}", + args[0].ty, + src_align.abi(), + elem_align.abi(), + self.memory.check_align(src, src_align), + self.memory.check_align(dest, elem_align) + ));*/ self.memory.copy( src, src_align, diff --git a/xargo/Cargo.lock b/xargo/Cargo.lock index 031ad9a87954..c85820b708b6 100644 --- a/xargo/Cargo.lock +++ b/xargo/Cargo.lock @@ -1,4 +1,4 @@ -[root] +[[package]] name = "miri-xargo" version = "0.0.0" From 4ecbcc5577ad74ded0f564af28530007bbaa31cd Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Mon, 19 Mar 2018 08:09:50 +0100 Subject: [PATCH 0034/5092] Dont claim to have marked static initialized --- miri/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri/lib.rs b/miri/lib.rs index 85827da5dd3c..8af33e30a5ef 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -261,7 +261,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { Env => err!(Unimplemented("statics can't refer to env vars".to_owned())), _ => Ok(false), // TODO: What does the bool mean? }*/ - Ok(true) + Ok(false) } fn init_static<'a>( From 6a85104945c9b07b9ef26cf50026bee467a56aa4 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Mon, 19 Mar 2018 08:12:53 +0100 Subject: [PATCH 0035/5092] Use elem align as src align in copy intrinsic --- miri/intrinsic.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index d01d52ad1af7..d6807f83c18d 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -218,7 +218,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let elem_align = elem_layout.align; let src = self.into_ptr(args[0].value)?; //let src_align = self.layout_of(args[0].ty)?.align; - let src_align = ty::layout::Align::from_bytes(1, 1).unwrap(); + //let src_align = ty::layout::Align::from_bytes(1, 1).unwrap(); let dest = self.into_ptr(args[1].value)?; /*self.tcx.sess.warn(&format!("src_ty: {:?} src_align: {} elem_align: {} src_aligned: {:?} dst_aligned: {:?}", args[0].ty, @@ -229,7 +229,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: ));*/ self.memory.copy( src, - src_align, + elem_align, dest, elem_align, count * elem_size, From 680bcf86f03632e0f1d17fdf89f5274a2f42da92 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Mon, 19 Mar 2018 08:35:01 +0100 Subject: [PATCH 0036/5092] Hack: copy init_static from rustc CompileTimeEvaluator to try to fix uninitialized static error --- miri/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/miri/lib.rs b/miri/lib.rs index 8af33e30a5ef..5305eb9d154d 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -268,6 +268,12 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, cid: GlobalId<'tcx>, ) -> EvalResult<'tcx, AllocId> { +ecx.const_eval(cid)?; + return Ok(ecx + .tcx + .interpret_interner + .get_cached(cid.instance.def_id()) + .expect("uncached static")); let def_id = cid.instance.def_id(); let ty = ecx.tcx.type_of(def_id); let layout = ecx.tcx.layout_of(ty::ParamEnvAnd { From 878d66692c2037c2d42532f1a127f2d825700658 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Mon, 19 Mar 2018 11:46:18 +0100 Subject: [PATCH 0037/5092] Maybe prevent marking statics as immutable --- miri/lib.rs | 76 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 63 insertions(+), 13 deletions(-) diff --git a/miri/lib.rs b/miri/lib.rs index 5305eb9d154d..0e3d00f1f15a 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -268,19 +268,69 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, cid: GlobalId<'tcx>, ) -> EvalResult<'tcx, AllocId> { -ecx.const_eval(cid)?; - return Ok(ecx - .tcx - .interpret_interner - .get_cached(cid.instance.def_id()) - .expect("uncached static")); - let def_id = cid.instance.def_id(); - let ty = ecx.tcx.type_of(def_id); - let layout = ecx.tcx.layout_of(ty::ParamEnvAnd { - param_env: ty::ParamEnv::reveal_all(), - value: ty - }).expect("Couldn't compute layout for the type of a static"); - ecx.memory.allocate(layout.size.bytes(), layout.align, None).map(|mptr|mptr.alloc_id) + let tcx = self.tcx.tcx; + let mir = None; + let param_env = ty::ParamEnv::reveal_all(); + // we start out with the best span we have + // and try improving it down the road when more information is available + let res = (|| { + let mut mir = match mir { + Some(mir) => mir, + None => ecx.load_mir(cid.instance.def)?, + }; + if let Some(index) = cid.promoted { + mir = &mir.promoted[index]; + } + span = mir.span; + let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; + let alloc = tcx.interpret_interner.get_cached(cid.instance.def_id()); + let is_static = tcx.is_static(cid.instance.def_id()).is_some(); + let alloc = match alloc { + Some(alloc) => { + assert!(cid.promoted.is_none()); + assert!(param_env.caller_bounds.is_empty()); + alloc + }, + None => { + assert!(!layout.is_unsized()); + let ptr = ecx.memory.allocate( + layout.size.bytes(), + layout.align, + None, + )?; + if is_static { + tcx.interpret_interner.cache(cid.instance.def_id(), ptr.alloc_id); + } + let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span); + let mutability = tcx.is_static(cid.instance.def_id()); + let mutability = if mutability == Some(hir::Mutability::MutMutable) || internally_mutable { + Mutability::Mutable + } else { + Mutability::Immutable + }; + let cleanup = StackPopCleanup::MarkStatic(mutability); + let name = ty::tls::with(|tcx| tcx.item_path_str(cid.instance.def_id())); + let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p)); + trace!("const_eval: pushing stack frame for global: {}{}", name, prom); + assert!(mir.arg_count == 0); + ecx.push_stack_frame( + cid.instance, + mir.span, + mir, + Place::from_ptr(ptr, layout.align), + cleanup, + )?; + + while ecx.step()? {} + ptr.alloc_id + } + }; + let ptr = MemoryPointer::new(alloc, 0).into(); + // always try to read the value and report errors + Ok((ptr, layout.ty)) + })(); + let (mem_ptr, _) = res?; + Ok(mem_ptr.alloc_id) } fn box_alloc<'a>( From f55d07745f8aa17d2dd7b73180bb95ecdc97e35f Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Fri, 23 Mar 2018 12:06:32 +0100 Subject: [PATCH 0038/5092] Fix init_static --- miri/lib.rs | 85 ++++++++++++++--------------------------------------- 1 file changed, 22 insertions(+), 63 deletions(-) diff --git a/miri/lib.rs b/miri/lib.rs index 0e3d00f1f15a..fb79780c3820 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -210,6 +210,8 @@ pub struct MemoryData<'tcx> { /// Only mutable (static mut, heap, stack) allocations have an entry in this map. /// The entry is created when allocating the memory and deleted after deallocation. locks: HashMap>>, + + mut_statics: HashMap, AllocId>, } impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { @@ -268,69 +270,26 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, cid: GlobalId<'tcx>, ) -> EvalResult<'tcx, AllocId> { - let tcx = self.tcx.tcx; - let mir = None; - let param_env = ty::ParamEnv::reveal_all(); - // we start out with the best span we have - // and try improving it down the road when more information is available - let res = (|| { - let mut mir = match mir { - Some(mir) => mir, - None => ecx.load_mir(cid.instance.def)?, - }; - if let Some(index) = cid.promoted { - mir = &mir.promoted[index]; - } - span = mir.span; - let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; - let alloc = tcx.interpret_interner.get_cached(cid.instance.def_id()); - let is_static = tcx.is_static(cid.instance.def_id()).is_some(); - let alloc = match alloc { - Some(alloc) => { - assert!(cid.promoted.is_none()); - assert!(param_env.caller_bounds.is_empty()); - alloc - }, - None => { - assert!(!layout.is_unsized()); - let ptr = ecx.memory.allocate( - layout.size.bytes(), - layout.align, - None, - )?; - if is_static { - tcx.interpret_interner.cache(cid.instance.def_id(), ptr.alloc_id); - } - let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span); - let mutability = tcx.is_static(cid.instance.def_id()); - let mutability = if mutability == Some(hir::Mutability::MutMutable) || internally_mutable { - Mutability::Mutable - } else { - Mutability::Immutable - }; - let cleanup = StackPopCleanup::MarkStatic(mutability); - let name = ty::tls::with(|tcx| tcx.item_path_str(cid.instance.def_id())); - let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p)); - trace!("const_eval: pushing stack frame for global: {}{}", name, prom); - assert!(mir.arg_count == 0); - ecx.push_stack_frame( - cid.instance, - mir.span, - mir, - Place::from_ptr(ptr, layout.align), - cleanup, - )?; - - while ecx.step()? {} - ptr.alloc_id - } - }; - let ptr = MemoryPointer::new(alloc, 0).into(); - // always try to read the value and report errors - Ok((ptr, layout.ty)) - })(); - let (mem_ptr, _) = res?; - Ok(mem_ptr.alloc_id) + if let Some(alloc_id) = ecx.memory.data.get(&cid) { + return Ok(alloc_id); + } + let mir = ecx.load_mir(cid.instance.def)?; + let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; + let to_ptr = ecx.memory.allocate( + layout.size.bytes(), + layout.align, + None, + )?; + ecx.const_eval(cid)?; + let ptr = ecx + .tcx + .interpret_interner + .get_cached(cid.instance.def_id()) + .expect("uncached static"); + ecx.memory.copy(ptr, layout.align, to_ptr.into(), layout.align, layout.size.bytes(), true)?; + ecx.memory.mark_static_initialized(to_ptr.alloc_id, ::syntax::ast::Mutability::Mutable)?; + assert!(ecx.memory.data.insert(cid, to_ptr.alloc_id).is_none()); + Ok(to_ptr.alloc_id) } fn box_alloc<'a>( From ac42af3789e6a536cabd900611e703c363aec3b3 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Fri, 23 Mar 2018 12:08:15 +0100 Subject: [PATCH 0039/5092] travis: cache build dir --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 97f1da545be4..b02b14392dae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ language: rust +cache: cargo rust: - nightly before_script: From a6cdd8a81b6dfd89a717b44cff6c4e489bd67bea Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Fri, 23 Mar 2018 12:18:33 +0100 Subject: [PATCH 0040/5092] Fix it --- miri/bin/miri.rs | 2 +- miri/fn_call.rs | 9 ++++ miri/lib.rs | 65 ++++++++++++++++++------ miri/validation.rs | 2 +- tests/run-pass-fullmir/u128.rs | 2 - tests/run-pass/generator_control_flow.rs | 2 +- tests/run-pass/subslice_array.rs | 1 - tests/run-pass/vec-matching-fold.rs | 2 - 8 files changed, 62 insertions(+), 23 deletions(-) diff --git a/miri/bin/miri.rs b/miri/bin/miri.rs index bbc8322194fa..cb90bbd704a8 100644 --- a/miri/bin/miri.rs +++ b/miri/bin/miri.rs @@ -1,4 +1,4 @@ -#![feature(rustc_private, i128_type)] +#![feature(rustc_private)] extern crate getopts; extern crate miri; diff --git a/miri/fn_call.rs b/miri/fn_call.rs index 70b4900a4eff..b4328ef88c00 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -126,6 +126,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' _ => panic!("Unexpected return type for {}", item_path) } } + "std::sys_common::thread_info::set" | "std::sys_common::cleanup" => { + // TODO rustc creates invalid mir inside std::cell::BorrowRef::new which is used by this function + let (_return_place, return_to_block) = destination.unwrap(); + self.goto_block(return_to_block); + return Ok(true); + } _ => {} } @@ -535,6 +541,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // Return success (0) self.write_null(dest, dest_ty)?; } + "_tlv_atexit" => { + // TODO: handle it + } // Stub out all the other pthread calls to just return 0 link_name if link_name.starts_with("pthread_") => { diff --git a/miri/lib.rs b/miri/lib.rs index fb79780c3820..42b0cacbd053 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -1,7 +1,5 @@ #![feature( - i128_type, rustc_private, - conservative_impl_trait, catch_expr, inclusive_range_fields )] @@ -21,6 +19,7 @@ extern crate lazy_static; use rustc::ty::{self, TyCtxt}; use rustc::ty::layout::{TyLayout, LayoutOf}; +use rustc::ty::subst::Subst; use rustc::hir::def_id::DefId; use rustc::mir; @@ -170,7 +169,7 @@ pub fn eval_main<'a, 'tcx: 'a>( Ok(()) => { let leaks = ecx.memory().leak_report(); if leaks != 0 { - tcx.sess.err("the evaluated program leaked memory"); + //tcx.sess.err("the evaluated program leaked memory"); } } Err(mut e) => { @@ -270,26 +269,59 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, cid: GlobalId<'tcx>, ) -> EvalResult<'tcx, AllocId> { - if let Some(alloc_id) = ecx.memory.data.get(&cid) { - return Ok(alloc_id); + if let Some(alloc_id) = ecx.memory.data.mut_statics.get(&cid) { + return Ok(*alloc_id); } - let mir = ecx.load_mir(cid.instance.def)?; + + let tcx = ecx.tcx.tcx; + let param_env = ty::ParamEnv::reveal_all(); + + let mut mir = ecx.load_mir(cid.instance.def)?; + if let Some(index) = cid.promoted { + mir = &mir.promoted[index]; + } + assert!(mir.arg_count == 0); + + // we start out with the best span we have + // and try improving it down the road when more information is available let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; - let to_ptr = ecx.memory.allocate( + assert!(!layout.is_unsized()); + let ptr = ecx.memory.allocate( layout.size.bytes(), layout.align, None, )?; - ecx.const_eval(cid)?; - let ptr = ecx + + let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span); + let mutability = tcx.is_static(cid.instance.def_id()); + if mutability != Some(::rustc::hir::Mutability::MutMutable) && !internally_mutable { + ecx.const_eval(cid)?; + return Ok(ecx .tcx .interpret_interner .get_cached(cid.instance.def_id()) - .expect("uncached static"); - ecx.memory.copy(ptr, layout.align, to_ptr.into(), layout.align, layout.size.bytes(), true)?; - ecx.memory.mark_static_initialized(to_ptr.alloc_id, ::syntax::ast::Mutability::Mutable)?; - assert!(ecx.memory.data.insert(cid, to_ptr.alloc_id).is_none()); - Ok(to_ptr.alloc_id) + .expect("uncached static")); + } + + //let cleanup = StackPopCleanup::MarkStatic(Mutability::Mutable); + let cleanup = StackPopCleanup::None; + let name = ty::tls::with(|tcx| tcx.item_path_str(cid.instance.def_id())); + let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p)); + trace!("const_eval: pushing stack frame for global: {}{}", name, prom); + let caller_stackframe = ecx.stack().len(); + ecx.push_stack_frame( + cid.instance, + mir.span, + mir, + Place::from_ptr(ptr, layout.align), + cleanup, + )?; + + while ecx.step()? && ecx.stack().len() > caller_stackframe {} + + assert!(ecx.memory.data.mut_statics.insert(cid, ptr.alloc_id).is_none()); + + Ok(ptr.alloc_id) } fn box_alloc<'a>( @@ -321,7 +353,10 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; ecx.write_value( ValTy { - value: Value::ByVal(PrimVal::Bytes(layout.size.bytes().into())), + value: Value::ByVal(PrimVal::Bytes(match layout.size.bytes() { + 0 => 1, + size => size, + }.into())), ty: usize, }, dest, diff --git a/miri/validation.rs b/miri/validation.rs index 801fd952f666..ec8901dca5d4 100644 --- a/miri/validation.rs +++ b/miri/validation.rs @@ -5,7 +5,7 @@ use rustc::mir::interpret::GlobalId; use rustc::ty::{self, Ty, TypeFoldable, TyCtxt, Instance}; use rustc::ty::layout::LayoutOf; use rustc::ty::subst::{Substs, Subst}; -use rustc::traits; +use rustc::traits::{self, TraitEngine}; use rustc::infer::InferCtxt; use rustc::middle::region; use rustc::middle::const_val::ConstVal; diff --git a/tests/run-pass-fullmir/u128.rs b/tests/run-pass-fullmir/u128.rs index 5b2efdd20517..d7764bf6201a 100644 --- a/tests/run-pass-fullmir/u128.rs +++ b/tests/run-pass-fullmir/u128.rs @@ -10,8 +10,6 @@ //ignore-msvc -#![feature(i128_type)] - fn b(t: T) -> T { t } fn main() { diff --git a/tests/run-pass/generator_control_flow.rs b/tests/run-pass/generator_control_flow.rs index f15c7db9c203..900ff0e34904 100644 --- a/tests/run-pass/generator_control_flow.rs +++ b/tests/run-pass/generator_control_flow.rs @@ -16,7 +16,7 @@ fn finish(mut amt: usize, mut t: T) -> T::Return where T: Generator { loop { - match t.resume() { + match unsafe { t.resume() } { GeneratorState::Yielded(()) => amt -= 1, GeneratorState::Complete(ret) => { assert_eq!(amt, 0); diff --git a/tests/run-pass/subslice_array.rs b/tests/run-pass/subslice_array.rs index 468cc9f09416..5bbbffe4e60e 100644 --- a/tests/run-pass/subslice_array.rs +++ b/tests/run-pass/subslice_array.rs @@ -1,4 +1,3 @@ -#![feature(advanced_slice_patterns)] #![feature(slice_patterns)] fn bar(a: &'static str, b: &'static str) -> [&'static str; 4] { diff --git a/tests/run-pass/vec-matching-fold.rs b/tests/run-pass/vec-matching-fold.rs index ac80a4211ada..1a30f875580c 100644 --- a/tests/run-pass/vec-matching-fold.rs +++ b/tests/run-pass/vec-matching-fold.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -#![feature(advanced_slice_patterns)] #![feature(slice_patterns)] use std::fmt::Debug; From e09a996b2a7aa4d0bc6f93b91dce21037d67fe6d Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Wed, 4 Apr 2018 15:54:40 +0200 Subject: [PATCH 0041/5092] Fix some more tests with some unsafe code --- miri/fn_call.rs | 6 ++++++ miri/lib.rs | 50 +++++++++++++++++++++++++------------------- tests/compiletest.rs | 1 + 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/miri/fn_call.rs b/miri/fn_call.rs index b4328ef88c00..cce36e6bacc6 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -132,6 +132,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.goto_block(return_to_block); return Ok(true); } + "std::sys::unix::fast_thread_local::register_dtor" => { + // TODO: register the dtor + let (_return_place, return_to_block) = destination.unwrap(); + self.goto_block(return_to_block); + return Ok(true); + } _ => {} } diff --git a/miri/lib.rs b/miri/lib.rs index 42b0cacbd053..f9332ccc629d 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -269,21 +269,21 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, cid: GlobalId<'tcx>, ) -> EvalResult<'tcx, AllocId> { + // Step 1: If the static has already been evaluated return the cached version if let Some(alloc_id) = ecx.memory.data.mut_statics.get(&cid) { return Ok(*alloc_id); } let tcx = ecx.tcx.tcx; - let param_env = ty::ParamEnv::reveal_all(); + // Step 2: Load mir let mut mir = ecx.load_mir(cid.instance.def)?; if let Some(index) = cid.promoted { mir = &mir.promoted[index]; } assert!(mir.arg_count == 0); - // we start out with the best span we have - // and try improving it down the road when more information is available + // Step 3: Allocate storage let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; assert!(!layout.is_unsized()); let ptr = ecx.memory.allocate( @@ -292,23 +292,11 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { None, )?; - let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span); - let mutability = tcx.is_static(cid.instance.def_id()); - if mutability != Some(::rustc::hir::Mutability::MutMutable) && !internally_mutable { - ecx.const_eval(cid)?; - return Ok(ecx - .tcx - .interpret_interner - .get_cached(cid.instance.def_id()) - .expect("uncached static")); - } + // Step 4: Cache allocation id for recursive statics + assert!(ecx.memory.data.mut_statics.insert(cid, ptr.alloc_id).is_none()); - //let cleanup = StackPopCleanup::MarkStatic(Mutability::Mutable); + // Step 5: Push stackframe to evaluate static let cleanup = StackPopCleanup::None; - let name = ty::tls::with(|tcx| tcx.item_path_str(cid.instance.def_id())); - let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p)); - trace!("const_eval: pushing stack frame for global: {}{}", name, prom); - let caller_stackframe = ecx.stack().len(); ecx.push_stack_frame( cid.instance, mir.span, @@ -317,10 +305,30 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { cleanup, )?; - while ecx.step()? && ecx.stack().len() > caller_stackframe {} - - assert!(ecx.memory.data.mut_statics.insert(cid, ptr.alloc_id).is_none()); + // Step 6: Step until static has been initialized + let call_stackframe = ecx.stack().len(); + while ecx.step()? && ecx.stack().len() >= call_stackframe { + if ecx.stack().len() == call_stackframe { + let frame = ecx.stack().last().unwrap(); + let bb = &frame.mir.basic_blocks()[frame.block]; + if bb.statements.len() == frame.stmt && !bb.is_cleanup { + match bb.terminator().kind { + ::rustc::mir::TerminatorKind::Return => { + for (local, _local_decl) in mir.local_decls.iter_enumerated().skip(1) { + // Don't deallocate locals, because the return value might reference them + // ------------------------------------------------------------ + // ||||||||||||| TODO: remove this horrible hack |||||||||||||| + // ------------------------------------------------------------ + unsafe { &mut *(frame as *const Frame as *mut Frame) }.storage_dead(local); + } + } + _ => {} + } + } + } + } + // Step 7: Return the alloc Ok(ptr.alloc_id) } diff --git a/tests/compiletest.rs b/tests/compiletest.rs index e2e00d828c1a..a1a28d4e4a68 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -202,6 +202,7 @@ fn run_pass_rustc() { } #[test] +#[ignore] // TODO: update test errors fn compile_fail_miri() { let sysroot = get_sysroot(); let host = get_host(); From 73658c40bb02762d9e68690bc5ebf7695f9d34b7 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 7 Apr 2018 10:44:19 +0200 Subject: [PATCH 0042/5092] Remove unsafe code --- miri/lib.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/miri/lib.rs b/miri/lib.rs index f9332ccc629d..cc564d1afe3f 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -309,17 +309,14 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { let call_stackframe = ecx.stack().len(); while ecx.step()? && ecx.stack().len() >= call_stackframe { if ecx.stack().len() == call_stackframe { - let frame = ecx.stack().last().unwrap(); + let frame = ecx.frame_mut(); let bb = &frame.mir.basic_blocks()[frame.block]; if bb.statements.len() == frame.stmt && !bb.is_cleanup { match bb.terminator().kind { ::rustc::mir::TerminatorKind::Return => { for (local, _local_decl) in mir.local_decls.iter_enumerated().skip(1) { // Don't deallocate locals, because the return value might reference them - // ------------------------------------------------------------ - // ||||||||||||| TODO: remove this horrible hack |||||||||||||| - // ------------------------------------------------------------ - unsafe { &mut *(frame as *const Frame as *mut Frame) }.storage_dead(local); + frame.storage_dead(local); } } _ => {} From 7bd20f1b12bc68396acb387884902a1308a045e5 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 7 Apr 2018 11:43:46 +0200 Subject: [PATCH 0043/5092] Some cleanups --- miri/fn_call.rs | 23 ++++------------------- miri/intrinsic.rs | 17 ++++++----------- miri/lib.rs | 21 +++++++++++---------- miri/validation.rs | 2 +- rust-toolchain | 1 + 5 files changed, 23 insertions(+), 41 deletions(-) create mode 100644 rust-toolchain diff --git a/miri/fn_call.rs b/miri/fn_call.rs index cce36e6bacc6..26a3829e7e8d 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -115,9 +115,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match ret_ty.sty { ty::TyAdt(ref adt_def, _) => { assert!(adt_def.is_enum(), "Unexpected return type for {}", item_path); - let none_variant_index = adt_def.variants.iter().enumerate().find(|&(_i, ref def)| { + let none_variant_index = adt_def.variants.iter().position(|def| { def.name.as_str() == "None" - }).expect("No None variant").0; + }).expect("No None variant"); let (return_place, return_to_block) = destination.unwrap(); write_discriminant_value(self, ret_ty, return_place, none_variant_index)?; self.goto_block(return_to_block); @@ -126,12 +126,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' _ => panic!("Unexpected return type for {}", item_path) } } - "std::sys_common::thread_info::set" | "std::sys_common::cleanup" => { - // TODO rustc creates invalid mir inside std::cell::BorrowRef::new which is used by this function - let (_return_place, return_to_block) = destination.unwrap(); - self.goto_block(return_to_block); - return Ok(true); - } "std::sys::unix::fast_thread_local::register_dtor" => { // TODO: register the dtor let (_return_place, return_to_block) = destination.unwrap(); @@ -465,17 +459,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' instance, promoted: None, }; - // compute global if not cached - let value: Value = match self.tcx.interpret_interner.get_cached(instance.def_id()) { - Some(ptr) => { - Value::ByRef(MemoryPointer::new(ptr, 0).into(), name_align) - } - None => { - let res: Option<(Value, Pointer, Ty)> = eval_body(self.tcx.tcx, cid, ty::ParamEnv::reveal_all()); - res.ok_or_else(||EvalErrorKind::MachineError("".to_string()))?.0 - }, - }; - let value = self.value_to_primval(ValTy { value, ty: args[0].ty })?.to_u64()?; + let const_val = self.const_eval(cid)?; + let value = const_val.val.unwrap_u64(); if value == name { result = Some(path_value); break; diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index d6807f83c18d..60f176dd95db 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -217,16 +217,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // Also see the write_bytes intrinsic. let elem_align = elem_layout.align; let src = self.into_ptr(args[0].value)?; - //let src_align = self.layout_of(args[0].ty)?.align; - //let src_align = ty::layout::Align::from_bytes(1, 1).unwrap(); let dest = self.into_ptr(args[1].value)?; - /*self.tcx.sess.warn(&format!("src_ty: {:?} src_align: {} elem_align: {} src_aligned: {:?} dst_aligned: {:?}", - args[0].ty, - src_align.abi(), - elem_align.abi(), - self.memory.check_align(src, src_align), - self.memory.check_align(dest, elem_align) - ));*/ self.memory.copy( src, elem_align, @@ -360,7 +351,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: align: _align, extra: PlaceExtra::None, } => self.memory.write_repeat(ptr, 0, size)?, - _ => bug!("TODO"), + Place::Ptr { .. } => { + bug!("init intrinsic tried to write to fat or unaligned ptr target") + } } } @@ -637,7 +630,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: align: _align, extra: PlaceExtra::None, } => self.memory.mark_definedness(ptr, size, false)?, - _ => bug!("todo"), + Place::Ptr { .. } => { + bug!("uninit intrinsic tried to write to fat or unaligned ptr target") + } } } diff --git a/miri/lib.rs b/miri/lib.rs index cc564d1afe3f..d9afd0860a52 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -210,7 +210,7 @@ pub struct MemoryData<'tcx> { /// The entry is created when allocating the memory and deleted after deallocation. locks: HashMap>>, - mut_statics: HashMap, AllocId>, + statics: HashMap, AllocId>, } impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { @@ -252,17 +252,16 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { } fn mark_static_initialized<'a>( - _mem: &mut Memory<'a, 'mir, 'tcx, Self>, - _id: AllocId, + mem: &mut Memory<'a, 'mir, 'tcx, Self>, + id: AllocId, _mutability: Mutability, ) -> EvalResult<'tcx, bool> { - /*use memory::MemoryKind::*; - match m { + use memory::MemoryKind::*; + match mem.get_alloc_kind(id) { // FIXME: This could be allowed, but not for env vars set during miri execution - Env => err!(Unimplemented("statics can't refer to env vars".to_owned())), + Some(MemoryKind::Machine(Env)) => err!(Unimplemented("statics can't refer to env vars".to_owned())), _ => Ok(false), // TODO: What does the bool mean? - }*/ - Ok(false) + } } fn init_static<'a>( @@ -270,7 +269,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { cid: GlobalId<'tcx>, ) -> EvalResult<'tcx, AllocId> { // Step 1: If the static has already been evaluated return the cached version - if let Some(alloc_id) = ecx.memory.data.mut_statics.get(&cid) { + if let Some(alloc_id) = ecx.memory.data.statics.get(&cid) { return Ok(*alloc_id); } @@ -293,7 +292,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { )?; // Step 4: Cache allocation id for recursive statics - assert!(ecx.memory.data.mut_statics.insert(cid, ptr.alloc_id).is_none()); + assert!(ecx.memory.data.statics.insert(cid, ptr.alloc_id).is_none()); // Step 5: Push stackframe to evaluate static let cleanup = StackPopCleanup::None; @@ -325,6 +324,8 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { } } + // TODO: Freeze immutable statics without copying them to the global static cache + // Step 7: Return the alloc Ok(ptr.alloc_id) } diff --git a/miri/validation.rs b/miri/validation.rs index ec8901dca5d4..c83c1a515fc6 100644 --- a/miri/validation.rs +++ b/miri/validation.rs @@ -560,7 +560,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' TyAdt(adt, _) if adt.is_box() => true, TySlice(_) | TyAdt(_, _) | TyTuple(..) | TyClosure(..) | TyArray(..) | TyDynamic(..) | TyGenerator(..) | TyForeign(_) => false, - TyGeneratorWitness(..) => bug!("I'm not sure what to return here"), + TyGeneratorWitness(..) => unreachable!("TyGeneratorWitness in validate"), TyParam(_) | TyInfer(_) | TyProjection(_) | TyAnon(..) | TyError => { bug!("I got an incomplete/unnormalized type for validation") } diff --git a/rust-toolchain b/rust-toolchain new file mode 100644 index 000000000000..bf867e0ae5b6 --- /dev/null +++ b/rust-toolchain @@ -0,0 +1 @@ +nightly From 9d186d914e378426064f7158c4cba8149ba44eb2 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 7 Apr 2018 14:31:39 +0200 Subject: [PATCH 0044/5092] Update Cargo.lock and some improvements --- Cargo.toml | 2 +- miri/bin/cargo-miri.rs | 4 +++- miri/fn_call.rs | 1 - miri/lib.rs | 1 + 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index cc7de42ceabf..444c6f60d544 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ path = "miri/lib.rs" [dependencies] byteorder = { version = "1.1", features = ["i128"]} -cargo_metadata = { version = "0.2", optional = true } +cargo_metadata = { version = "0.5", optional = true } regex = "0.2.2" lazy_static = "1.0" env_logger = "0.5.0-rc.1" diff --git a/miri/bin/cargo-miri.rs b/miri/bin/cargo-miri.rs index 06d5b3e9971f..39a41583a39e 100644 --- a/miri/bin/cargo-miri.rs +++ b/miri/bin/cargo-miri.rs @@ -121,7 +121,9 @@ fn main() { let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); - let sys_root = if let (Some(home), Some(toolchain)) = (home, toolchain) { + let sys_root = if let Ok(sysroot) = ::std::env::var("MIRI_SYSROOT") { + sysroot + } else if let (Some(home), Some(toolchain)) = (home, toolchain) { format!("{}/toolchains/{}", home, toolchain) } else { option_env!("RUST_SYSROOT") diff --git a/miri/fn_call.rs b/miri/fn_call.rs index 26a3829e7e8d..16a7c5ad77c1 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -444,7 +444,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "sysconf" => { let name = self.value_to_primval(args[0])?.to_u64()?; - let name_align = self.layout_of(args[0].ty)?.align; trace!("sysconf() called with name {}", name); // cache the sysconf integers via miri's global cache diff --git a/miri/lib.rs b/miri/lib.rs index d9afd0860a52..16510a5f17b2 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -173,6 +173,7 @@ pub fn eval_main<'a, 'tcx: 'a>( } } Err(mut e) => { + ecx.tcx.sess.err(&e.to_string()); ecx.report(&mut e, true, None); } } From 95a8771bf15c5231c0269a062a4c9a0562694c95 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 13 Apr 2018 16:02:55 +0200 Subject: [PATCH 0045/5092] Fixup various things needed to get miri working on rustc --- miri/bin/miri.rs | 1 + miri/fn_call.rs | 2 +- miri/intrinsic.rs | 4 +++- miri/lib.rs | 2 +- miri/validation.rs | 11 +---------- 5 files changed, 7 insertions(+), 13 deletions(-) diff --git a/miri/bin/miri.rs b/miri/bin/miri.rs index cb90bbd704a8..506845dd76ad 100644 --- a/miri/bin/miri.rs +++ b/miri/bin/miri.rs @@ -206,6 +206,7 @@ fn find_sysroot() -> String { } fn main() { + rustc_driver::init_rustc_env_logger(); init_logger(); let mut args: Vec = std::env::args().collect(); diff --git a/miri/fn_call.rs b/miri/fn_call.rs index 16a7c5ad77c1..a824cbab40a0 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -499,7 +499,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' return err!(OutOfTls); } self.memory.write_primval( - key_ptr.to_ptr()?, + key_ptr, key_align, PrimVal::Bytes(key), key_size.bytes(), diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index 60f176dd95db..ea9f0428964a 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -34,7 +34,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "align_offset" => { // FIXME: return a real value in case the target allocation has an // alignment bigger than the one requested - self.write_primval(dest, PrimVal::Bytes(u128::max_value()), dest_layout.ty)?; + let n = u128::max_value(); + let amt = 128 - self.memory.pointer_size() * 8; + self.write_primval(dest, PrimVal::Bytes((n << amt) >> amt), dest_layout.ty)?; }, "add_with_overflow" => { diff --git a/miri/lib.rs b/miri/lib.rs index 16510a5f17b2..4d4af6e3adc2 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -133,7 +133,7 @@ pub fn eval_main<'a, 'tcx: 'a>( let ptr_size = ecx.memory.pointer_size(); let ptr_align = ecx.tcx.data_layout.pointer_align; let foo_ptr = ecx.memory.allocate(ptr_size, ptr_align, None)?; - ecx.memory.write_primval(foo_ptr, ptr_align, PrimVal::Ptr(foo.into()), ptr_size, false)?; + ecx.memory.write_primval(foo_ptr.into(), ptr_align, PrimVal::Ptr(foo.into()), ptr_size, false)?; ecx.memory.mark_static_initialized(foo_ptr.alloc_id, Mutability::Immutable)?; ecx.write_ptr(dest, foo_ptr.into(), ty)?; diff --git a/miri/validation.rs b/miri/validation.rs index c83c1a515fc6..b2c6f427c51a 100644 --- a/miri/validation.rs +++ b/miri/validation.rs @@ -782,16 +782,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match adt.adt_kind() { AdtKind::Enum => { - let discr = self.read_discriminant_value(query.place.1, query.ty)?; - - // Get variant index for discriminant - let variant_idx = adt.discriminants(self.tcx.tcx).position(|variant_discr| { - variant_discr.val == discr - }); - let variant_idx = match variant_idx { - Some(val) => val, - None => return err!(InvalidDiscriminant), - }; + let variant_idx = self.read_discriminant_value_as_variant_index(query.place.1, query.ty)?; let variant = &adt.variants[variant_idx]; if variant.fields.len() > 0 { From 3f1b2bdd6895f9aedb22601bd28bc690d5a55a1e Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 13 Apr 2018 16:25:26 +0200 Subject: [PATCH 0046/5092] Mirror function rename in rustc --- miri/validation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri/validation.rs b/miri/validation.rs index b2c6f427c51a..85dd89577636 100644 --- a/miri/validation.rs +++ b/miri/validation.rs @@ -782,7 +782,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match adt.adt_kind() { AdtKind::Enum => { - let variant_idx = self.read_discriminant_value_as_variant_index(query.place.1, query.ty)?; + let variant_idx = self.read_discriminant_as_variant_index(query.place.1, query.ty)?; let variant = &adt.variants[variant_idx]; if variant.fields.len() > 0 { From f48fed70d4447445b586a35c4ae88683542ffc72 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 17 Apr 2018 14:26:17 +0200 Subject: [PATCH 0047/5092] Rustup --- miri/bin/miri.rs | 2 +- miri/lib.rs | 23 ++++------------------- miri/validation.rs | 28 +++++++++------------------- 3 files changed, 14 insertions(+), 39 deletions(-) diff --git a/miri/bin/miri.rs b/miri/bin/miri.rs index 506845dd76ad..6ba86c81e040 100644 --- a/miri/bin/miri.rs +++ b/miri/bin/miri.rs @@ -130,7 +130,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { state.hir_crate.unwrap().visit_all_item_likes( &mut Visitor(tcx, state), ); - } else if let Some((entry_node_id, _)) = *state.session.entry_fn.borrow() { + } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { let entry_def_id = tcx.hir.local_def_id(entry_node_id); let start_wrapper = tcx.lang_items().start_fn().and_then(|start_fn| { if tcx.is_mir_available(start_fn) { diff --git a/miri/lib.rs b/miri/lib.rs index 4d4af6e3adc2..7c8183b50984 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -385,26 +385,11 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { } fn global_item_with_linkage<'a>( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - instance: ty::Instance<'tcx>, - mutability: Mutability, + _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + _instance: ty::Instance<'tcx>, + _mutability: Mutability, ) -> EvalResult<'tcx> { - // FIXME: check that it's `#[linkage = "extern_weak"]` - trace!("Initializing an extern global with NULL"); - let ptr_size = ecx.memory.pointer_size(); - let ptr_align = ecx.tcx.data_layout.pointer_align; - let ptr = ecx.memory.allocate( - ptr_size, - ptr_align, - None, - )?; - ecx.memory.write_ptr_sized_unsigned(ptr, ptr_align, PrimVal::Bytes(0))?; - ecx.memory.mark_static_initialized(ptr.alloc_id, mutability)?; - ecx.tcx.interpret_interner.cache( - instance.def_id(), - ptr.alloc_id, - ); - Ok(()) + panic!("remove this function from rustc"); } fn check_locks<'a>( diff --git a/miri/validation.rs b/miri/validation.rs index 85dd89577636..2de620510ffe 100644 --- a/miri/validation.rs +++ b/miri/validation.rs @@ -638,7 +638,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } } - let res = do catch { + let res: EvalResult<'tcx> = do catch { match query.ty.sty { TyInt(_) | TyUint(_) | TyRawPtr(_) => { if mode.acquiring() { @@ -648,7 +648,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // FIXME: It would be great to rule out Undef here, but that doesn't actually work. // Passing around undef data is a thing that e.g. Vec::extend_with does. } - Ok(()) } TyBool | TyFloat(_) | TyChar => { if mode.acquiring() { @@ -657,9 +656,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' val.to_bytes()?; // TODO: Check if these are valid bool/float/codepoint/UTF-8 } - Ok(()) } - TyNever => err!(ValidationFailure(format!("The empty type is never valid."))), + TyNever => return err!(ValidationFailure(format!("The empty type is never valid."))), TyRef(region, ty::TypeAndMut { ty: pointee_ty, @@ -680,29 +678,26 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' _ => {} } } - self.validate_ptr(val, query.place.0, pointee_ty, query.re, query.mutbl, mode) + self.validate_ptr(val, query.place.0, pointee_ty, query.re, query.mutbl, mode)?; } TyAdt(adt, _) if adt.is_box() => { let val = self.read_place(query.place.1)?; - self.validate_ptr(val, query.place.0, query.ty.boxed_ty(), query.re, query.mutbl, mode) + self.validate_ptr(val, query.place.0, query.ty.boxed_ty(), query.re, query.mutbl, mode)?; } TyFnPtr(_sig) => { let ptr = self.read_place(query.place.1)?; let ptr = self.into_ptr(ptr)?.to_ptr()?; self.memory.get_fn(ptr)?; // TODO: Check if the signature matches (should be the same check as what terminator/mod.rs already does on call?). - Ok(()) } TyFnDef(..) => { // This is a zero-sized type with all relevant data sitting in the type. // There is nothing to validate. - Ok(()) } // Compound types TyStr => { // TODO: Validate strings - Ok(()) } TySlice(elem_ty) => { let len = match query.place.1 { @@ -725,7 +720,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' mode, )?; } - Ok(()) } TyArray(elem_ty, len) => { let len_val = match len.val { @@ -751,7 +745,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' mode, )?; } - Ok(()) } TyDynamic(_data, _region) => { // Check that this is a valid vtable @@ -770,7 +763,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // on them directly. We cannot, in general, even acquire any locks as the trait object *could* // contain an UnsafeCell. If we call functions to get access to data, we will validate // their return values. So, it doesn't seem like there's anything else to do. - Ok(()) } TyAdt(adt, _) => { if Some(adt.did) == self.tcx.tcx.lang_items().unsafe_cell_type() && @@ -804,19 +796,17 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.validate_fields( ValidationQuery { place, ..query }, mode, - ) + )?; } else { // No fields, nothing left to check. Downcasting may fail, e.g. in case of a CEnum. - Ok(()) } } AdtKind::Struct => { - self.validate_fields(query, mode) + self.validate_fields(query, mode)?; } AdtKind::Union => { // No guarantees are provided for union types. // TODO: Make sure that all access to union fields is unsafe; otherwise, we may have some checking to do (but what exactly?) - Ok(()) } } } @@ -825,10 +815,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // TODO: Check if the signature matches for `TyClosure` // (should be the same check as what terminator/mod.rs already does on call?). // Is there other things we can/should check? Like vtable pointers? - self.validate_fields(query, mode) + self.validate_fields(query, mode)?; } // FIXME: generators aren't validated right now - TyGenerator(..) => Ok(()), + TyGenerator(..) => {}, _ => bug!("We already established that this is a type we support. ({})", query.ty), } }; @@ -840,7 +830,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // release if it is. But of course that can't even always be statically determined. Err(EvalError { kind: EvalErrorKind::ReadUndefBytes, .. }) if mode == ValidationMode::ReleaseUntil(None) => { - return Ok(()); + Ok(()) } res => res, } From ba1c88a3c15929692af82798f055885e972af417 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 1 May 2018 11:04:01 +0200 Subject: [PATCH 0048/5092] Rustup to rustc 1.27.0-nightly (79252ff4e 2018-04-29) --- miri/fn_call.rs | 4 ++-- miri/intrinsic.rs | 2 +- miri/lib.rs | 1 + miri/validation.rs | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/miri/fn_call.rs b/miri/fn_call.rs index a824cbab40a0..15b67cca9397 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -2,9 +2,9 @@ use rustc::ty::{self, Ty}; use rustc::ty::layout::{self, Align, LayoutOf}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; +use rustc_target::spec::abi::Abi; use rustc_data_structures::indexed_vec::Idx; use syntax::attr; -use syntax::abi::Abi; use syntax::codemap::Span; use std::mem; @@ -177,7 +177,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let attrs = self.tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { Some(name) => name.as_str(), - None => self.tcx.item_name(def_id), + None => self.tcx.item_name(def_id).as_str(), }; match &link_name[..] { diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index ea9f0428964a..9f4950e8c9fb 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -29,7 +29,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: ) -> EvalResult<'tcx> { let substs = instance.substs; - let intrinsic_name = &self.tcx.item_name(instance.def_id())[..]; + let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..]; match intrinsic_name { "align_offset" => { // FIXME: return a real value in case the target allocation has an diff --git a/miri/lib.rs b/miri/lib.rs index 7c8183b50984..73437d713d01 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -11,6 +11,7 @@ extern crate log; #[macro_use] extern crate rustc; extern crate rustc_mir; +extern crate rustc_target; extern crate rustc_data_structures; extern crate syntax; extern crate regex; diff --git a/miri/validation.rs b/miri/validation.rs index 2de620510ffe..51b407721399 100644 --- a/miri/validation.rs +++ b/miri/validation.rs @@ -3,7 +3,7 @@ use rustc::hir::Mutability::*; use rustc::mir::{self, ValidationOp, ValidationOperand}; use rustc::mir::interpret::GlobalId; use rustc::ty::{self, Ty, TypeFoldable, TyCtxt, Instance}; -use rustc::ty::layout::LayoutOf; +use rustc::ty::layout::{LayoutOf, PrimitiveExt}; use rustc::ty::subst::{Substs, Subst}; use rustc::traits::{self, TraitEngine}; use rustc::infer::InferCtxt; From 3dba298f1419d8c3ca9766aaeacdc4c5087c0f44 Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Tue, 1 May 2018 17:13:22 +0100 Subject: [PATCH 0049/5092] Fixed build for latest nightly --- miri/fn_call.rs | 6 +++--- miri/helpers.rs | 6 ++++-- miri/intrinsic.rs | 2 +- miri/lib.rs | 4 +++- miri/validation.rs | 2 +- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/miri/fn_call.rs b/miri/fn_call.rs index a824cbab40a0..c763802bec9d 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -3,8 +3,8 @@ use rustc::ty::layout::{self, Align, LayoutOf}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc_data_structures::indexed_vec::Idx; +use rustc_target::spec::abi::Abi; use syntax::attr; -use syntax::abi::Abi; use syntax::codemap::Span; use std::mem; @@ -49,7 +49,7 @@ fn write_discriminant_value<'a, 'mir, 'tcx: 'a + 'mir>( if variant_index != dataful_variant { let (niche_dest, niche) = ecx.place_field(dest, mir::Field::new(0), layout)?; - let niche_value = ((variant_index - niche_variants.start) as u128) + let niche_value = ((variant_index - niche_variants.start()) as u128) .wrapping_add(niche_start); ecx.write_primval(niche_dest, PrimVal::Bytes(niche_value), niche.ty)?; } @@ -177,7 +177,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let attrs = self.tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { Some(name) => name.as_str(), - None => self.tcx.item_name(def_id), + None => self.tcx.item_name(def_id).as_str(), }; match &link_name[..] { diff --git a/miri/helpers.rs b/miri/helpers.rs index 3dd499f7a62e..b941e65437d9 100644 --- a/miri/helpers.rs +++ b/miri/helpers.rs @@ -1,7 +1,9 @@ -use super::{Pointer, EvalResult, PrimVal, EvalContext}; +use mir; use rustc::ty::Ty; use rustc::ty::layout::LayoutOf; +use super::{Pointer, EvalResult, PrimVal, EvalContext}; + pub trait EvalContextExt<'tcx> { fn wrapping_pointer_offset( &self, @@ -63,7 +65,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } Ok(ptr) } else { - err!(OverflowingMath) + err!(Overflow(mir::BinOp::Mul)) }; } } diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index ea9f0428964a..9f4950e8c9fb 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -29,7 +29,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: ) -> EvalResult<'tcx> { let substs = instance.substs; - let intrinsic_name = &self.tcx.item_name(instance.def_id())[..]; + let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..]; match intrinsic_name { "align_offset" => { // FIXME: return a real value in case the target allocation has an diff --git a/miri/lib.rs b/miri/lib.rs index 7c8183b50984..adc19ba0a7ae 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -1,7 +1,8 @@ #![feature( rustc_private, catch_expr, - inclusive_range_fields + inclusive_range_fields, + inclusive_range_methods, )] #[macro_use] @@ -12,6 +13,7 @@ extern crate log; extern crate rustc; extern crate rustc_mir; extern crate rustc_data_structures; +extern crate rustc_target; extern crate syntax; extern crate regex; #[macro_use] diff --git a/miri/validation.rs b/miri/validation.rs index 2de620510ffe..51b407721399 100644 --- a/miri/validation.rs +++ b/miri/validation.rs @@ -3,7 +3,7 @@ use rustc::hir::Mutability::*; use rustc::mir::{self, ValidationOp, ValidationOperand}; use rustc::mir::interpret::GlobalId; use rustc::ty::{self, Ty, TypeFoldable, TyCtxt, Instance}; -use rustc::ty::layout::LayoutOf; +use rustc::ty::layout::{LayoutOf, PrimitiveExt}; use rustc::ty::subst::{Substs, Subst}; use rustc::traits::{self, TraitEngine}; use rustc::infer::InferCtxt; From 915695371ff79f7df437494790bcec378996adff Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Thu, 3 May 2018 21:57:50 +0100 Subject: [PATCH 0050/5092] Minor fix to get build working --- miri/bin/miri.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri/bin/miri.rs b/miri/bin/miri.rs index 6ba86c81e040..5491762c3395 100644 --- a/miri/bin/miri.rs +++ b/miri/bin/miri.rs @@ -111,7 +111,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::Item_::ItemFn(_, _, _, _, _, body_id) = i.node { if i.attrs.iter().any(|attr| { - attr.name().map_or(false, |n| n == "test") + attr.name() == "test" }) { let did = self.0.hir.body_owner_def_id(body_id); From 3d8c7a8dba7cab5d2d222cc08eaac648d6529b6a Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Thu, 3 May 2018 23:29:13 +0100 Subject: [PATCH 0051/5092] Fixed build for latest nightly --- miri/fn_call.rs | 1 - miri/lib.rs | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/miri/fn_call.rs b/miri/fn_call.rs index 51e5547de438..c763802bec9d 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -2,7 +2,6 @@ use rustc::ty::{self, Ty}; use rustc::ty::layout::{self, Align, LayoutOf}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; -use rustc_target::spec::abi::Abi; use rustc_data_structures::indexed_vec::Idx; use rustc_target::spec::abi::Abi; use syntax::attr; diff --git a/miri/lib.rs b/miri/lib.rs index 9b1888845164..8359f0ad7ad0 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -11,9 +11,8 @@ extern crate log; // From rustc. #[macro_use] extern crate rustc; -extern crate rustc_mir; -extern crate rustc_target; extern crate rustc_data_structures; +extern crate rustc_mir; extern crate rustc_target; extern crate syntax; extern crate regex; From b0d3daed4050874bbc4cfeaaf1fb6b1ec4e29221 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 7 May 2018 10:18:45 +0200 Subject: [PATCH 0052/5092] Rustup --- miri/bin/miri.rs | 2 +- miri/fn_call.rs | 1 - miri/lib.rs | 1 - miri/validation.rs | 5 ++++- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/miri/bin/miri.rs b/miri/bin/miri.rs index 6ba86c81e040..5491762c3395 100644 --- a/miri/bin/miri.rs +++ b/miri/bin/miri.rs @@ -111,7 +111,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::Item_::ItemFn(_, _, _, _, _, body_id) = i.node { if i.attrs.iter().any(|attr| { - attr.name().map_or(false, |n| n == "test") + attr.name() == "test" }) { let did = self.0.hir.body_owner_def_id(body_id); diff --git a/miri/fn_call.rs b/miri/fn_call.rs index 51e5547de438..336c9e67a134 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -4,7 +4,6 @@ use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc_target::spec::abi::Abi; use rustc_data_structures::indexed_vec::Idx; -use rustc_target::spec::abi::Abi; use syntax::attr; use syntax::codemap::Span; diff --git a/miri/lib.rs b/miri/lib.rs index 9b1888845164..b44b70faa891 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -14,7 +14,6 @@ extern crate rustc; extern crate rustc_mir; extern crate rustc_target; extern crate rustc_data_structures; -extern crate rustc_target; extern crate syntax; extern crate regex; #[macro_use] diff --git a/miri/validation.rs b/miri/validation.rs index 51b407721399..5b919a09bd91 100644 --- a/miri/validation.rs +++ b/miri/validation.rs @@ -455,7 +455,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } // Discriminant field for enums (where applicable). - Variants::Tagged { ref discr, .. } | + Variants::Tagged { ref tag, .. } => { + assert_eq!(i, 0); + return Ok(tag.value.to_ty(tcx)) + }, Variants::NicheFilling { niche: ref discr, .. } => { assert_eq!(i, 0); return Ok(discr.value.to_ty(tcx)) From 6bc35f77cec4947dd9cb38e34dc6354745645d82 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Mon, 7 May 2018 10:38:13 +0200 Subject: [PATCH 0053/5092] Fix allocator api and temporarily disable validation_op --- miri/fn_call.rs | 22 +++++++++------------- miri/lib.rs | 4 +++- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/miri/fn_call.rs b/miri/fn_call.rs index c763802bec9d..c862238e889c 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -627,7 +627,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match &path[..] { // Allocators are magic. They have no MIR, even when the rest of libstd does. - "alloc::heap::::__rust_alloc" => { + "alloc::alloc::::__rust_alloc" => { let size = self.value_to_primval(args[0])?.to_u64()?; let align = self.value_to_primval(args[1])?.to_u64()?; if size == 0 { @@ -641,7 +641,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Some(MemoryKind::Rust.into()))?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } - "alloc::heap::::__rust_alloc_zeroed" => { + "alloc::alloc::::__rust_alloc_zeroed" => { let size = self.value_to_primval(args[0])?.to_u64()?; let align = self.value_to_primval(args[1])?.to_u64()?; if size == 0 { @@ -656,7 +656,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.memory.write_repeat(ptr.into(), 0, size)?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } - "alloc::heap::::__rust_dealloc" => { + "alloc::alloc::::__rust_dealloc" => { let ptr = self.into_ptr(args[0].value)?.to_ptr()?; let old_size = self.value_to_primval(args[1])?.to_u64()?; let align = self.value_to_primval(args[2])?.to_u64()?; @@ -672,27 +672,23 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' MemoryKind::Rust.into(), )?; } - "alloc::heap::::__rust_realloc" => { + "alloc::alloc::::__rust_realloc" => { let ptr = self.into_ptr(args[0].value)?.to_ptr()?; let old_size = self.value_to_primval(args[1])?.to_u64()?; - let old_align = self.value_to_primval(args[2])?.to_u64()?; + let align = self.value_to_primval(args[2])?.to_u64()?; let new_size = self.value_to_primval(args[3])?.to_u64()?; - let new_align = self.value_to_primval(args[4])?.to_u64()?; if old_size == 0 || new_size == 0 { return err!(HeapAllocZeroBytes); } - if !old_align.is_power_of_two() { - return err!(HeapAllocNonPowerOfTwoAlignment(old_align)); - } - if !new_align.is_power_of_two() { - return err!(HeapAllocNonPowerOfTwoAlignment(new_align)); + if !align.is_power_of_two() { + return err!(HeapAllocNonPowerOfTwoAlignment(align)); } let new_ptr = self.memory.reallocate( ptr, old_size, - Align::from_bytes(old_align, old_align).unwrap(), + Align::from_bytes(align, align).unwrap(), new_size, - Align::from_bytes(new_align, new_align).unwrap(), + Align::from_bytes(align, align).unwrap(), MemoryKind::Rust.into(), )?; self.write_primval(dest, PrimVal::Ptr(new_ptr), dest_ty)?; diff --git a/miri/lib.rs b/miri/lib.rs index 8359f0ad7ad0..ca479e765ce5 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -448,6 +448,8 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { op: ::rustc::mir::ValidationOp, operand: &::rustc::mir::ValidationOperand<'tcx, ::rustc::mir::Place<'tcx>>, ) -> EvalResult<'tcx> { - ecx.validation_op(op, operand) + // FIXME: prevent this from ICEing + //ecx.validation_op(op, operand) + Ok(()) } } From 860e2b802f6ef77b64c1cc25219e6548a0a851cb Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 7 May 2018 10:44:18 +0200 Subject: [PATCH 0054/5092] Dedup tag reading --- miri/validation.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/miri/validation.rs b/miri/validation.rs index 5b919a09bd91..8f444f19bd86 100644 --- a/miri/validation.rs +++ b/miri/validation.rs @@ -455,10 +455,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } // Discriminant field for enums (where applicable). - Variants::Tagged { ref tag, .. } => { - assert_eq!(i, 0); - return Ok(tag.value.to_ty(tcx)) - }, + Variants::Tagged { tag: ref discr, .. } | Variants::NicheFilling { niche: ref discr, .. } => { assert_eq!(i, 0); return Ok(discr.value.to_ty(tcx)) From 0eb3c18565070e4af530e0ec0f707d99be7c5cef Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 7 May 2018 10:46:32 +0200 Subject: [PATCH 0055/5092] Use a deterministic method for executing the start lang item --- miri/bin/miri.rs | 22 +++++++++++++++++++--- tests/compiletest.rs | 1 + 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/miri/bin/miri.rs b/miri/bin/miri.rs index 5491762c3395..4e0be7bd3204 100644 --- a/miri/bin/miri.rs +++ b/miri/bin/miri.rs @@ -24,6 +24,10 @@ use std::path::PathBuf; struct MiriCompilerCalls { default: RustcDefaultCalls, + /// Whether to begin interpretation at the start_fn lang item or not + /// + /// If false, the interpretation begins at the `main` function + start_fn: bool, } impl<'a> CompilerCalls<'a> for MiriCompilerCalls { @@ -80,7 +84,8 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { ) -> CompileController<'a> { let mut control = self.default.build_controller(sess, matches); control.after_hir_lowering.callback = Box::new(after_hir_lowering); - control.after_analysis.callback = Box::new(after_analysis); + let start_fn = self.start_fn; + control.after_analysis.callback = Box::new(move |state| after_analysis(state, start_fn)); if sess.target.target != sess.host { // only fully compile targets on the host. linking will fail for cross-compilation. control.after_analysis.stop = Compilation::Stop; @@ -97,7 +102,7 @@ fn after_hir_lowering(state: &mut CompileState) { state.session.plugin_attributes.borrow_mut().push(attr); } -fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { +fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>, use_start_fn: bool) { state.session.abort_if_errors(); let tcx = state.tcx.unwrap(); @@ -133,7 +138,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { let entry_def_id = tcx.hir.local_def_id(entry_node_id); let start_wrapper = tcx.lang_items().start_fn().and_then(|start_fn| { - if tcx.is_mir_available(start_fn) { + if use_start_fn { Some(start_fn) } else { None @@ -216,10 +221,21 @@ fn main() { args.push(find_sysroot()); } + let mut start_fn = false; + args.retain(|arg| { + if arg == "-Zmiri-start-fn" { + start_fn = true; + false + } else { + true + } + }); + // Make sure we always have all the MIR (e.g. for auxilary builds in unit tests). args.push("-Zalways-encode-mir".to_owned()); rustc_driver::run_compiler(&args, &mut MiriCompilerCalls { default: RustcDefaultCalls, + start_fn, }, None, None); } diff --git a/tests/compiletest.rs b/tests/compiletest.rs index a1a28d4e4a68..3fb7f2784a6a 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -114,6 +114,7 @@ fn miri_pass(path: &str, target: &str, host: &str, fullmir: bool, opt: bool) { .join(".xargo") .join("HOST"); + flags.push("-Zmiri-start-fn".to_owned()); flags.push(format!("--sysroot {}", sysroot.to_str().unwrap())); } if opt { From 0a88698daf8b5bc63de8297b287c82df82c07c36 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 7 May 2018 10:49:54 +0200 Subject: [PATCH 0056/5092] Hide some warnings/Fix build --- miri/fn_call.rs | 1 + miri/lib.rs | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/miri/fn_call.rs b/miri/fn_call.rs index de69c58fb4ac..c862238e889c 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -3,6 +3,7 @@ use rustc::ty::layout::{self, Align, LayoutOf}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc_data_structures::indexed_vec::Idx; +use rustc_target::spec::abi::Abi; use syntax::attr; use syntax::codemap::Span; diff --git a/miri/lib.rs b/miri/lib.rs index ca479e765ce5..5818a2708504 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -444,9 +444,9 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { } fn validation_op<'a>( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - op: ::rustc::mir::ValidationOp, - operand: &::rustc::mir::ValidationOperand<'tcx, ::rustc::mir::Place<'tcx>>, + _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + _op: ::rustc::mir::ValidationOp, + _operand: &::rustc::mir::ValidationOperand<'tcx, ::rustc::mir::Place<'tcx>>, ) -> EvalResult<'tcx> { // FIXME: prevent this from ICEing //ecx.validation_op(op, operand) From 6653bb38d5bb95bda0937e876094ef3b8bfca92c Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 7 May 2018 18:02:57 +0200 Subject: [PATCH 0057/5092] Implement missing intrinsic --- miri/intrinsic.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index 9f4950e8c9fb..453e834566a6 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -315,6 +315,20 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: self.write_primval(dest, result.0, dest_layout.ty)?; } + "exact_div" => { + // Performs an exact division, resulting in undefined behavior where + // `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1` + let ty = substs.type_at(0); + let a = self.value_to_primval(args[0])?; + let b = self.value_to_primval(args[1])?; + // check x % y != 0 + if self.binary_op(mir::BinOp::Rem, a, ty, b, ty)?.0 != PrimVal::Bytes(0) { + return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b))); + } + let result = self.binary_op(mir::BinOp::Div, a, ty, b, ty)?; + self.write_primval(dest, result.0, dest_layout.ty)?; + }, + "likely" | "unlikely" | "forget" => {} "init" => { From e0e1bd7ff778e5913b566c9e03224faecc0eb486 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 7 May 2018 18:03:28 +0200 Subject: [PATCH 0058/5092] Pointers must be valid, even pointers to zsts --- miri/lib.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/miri/lib.rs b/miri/lib.rs index 5818a2708504..dce31c4ed338 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -145,7 +145,7 @@ pub fn eval_main<'a, 'tcx: 'a>( main_instance, main_mir.span, main_mir, - Place::undef(), + Place::from_primval_ptr(PrimVal::Bytes(1).into(), ty::layout::Align::from_bytes(1, 1).unwrap()), StackPopCleanup::None, )?; @@ -177,6 +177,16 @@ pub fn eval_main<'a, 'tcx: 'a>( Err(mut e) => { ecx.tcx.sess.err(&e.to_string()); ecx.report(&mut e, true, None); + for (i, frame) in ecx.stack().iter().enumerate() { + trace!("-------------------"); + trace!("Frame {}", i); + trace!(" return: {:#?}", frame.return_place); + for (i, local) in frame.locals.iter().enumerate() { + if let Some(local) = local { + trace!(" local {}: {:?}", i, local); + } + } + } } } } From ce7605caaa46e0a218fe10f1294491ab336e4afc Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 9 May 2018 11:52:41 +0200 Subject: [PATCH 0059/5092] Fix some bad conversions on 32 bit emulation --- miri/helpers.rs | 59 ++++++++++++++++++++++++++++++++++++++++++++++- miri/intrinsic.rs | 18 +++++++-------- 2 files changed, 67 insertions(+), 10 deletions(-) diff --git a/miri/helpers.rs b/miri/helpers.rs index b941e65437d9..a7b94a656da4 100644 --- a/miri/helpers.rs +++ b/miri/helpers.rs @@ -2,7 +2,8 @@ use mir; use rustc::ty::Ty; use rustc::ty::layout::LayoutOf; -use super::{Pointer, EvalResult, PrimVal, EvalContext}; +use super::{Pointer, EvalResult, PrimVal, EvalContext, ValTy}; +use rustc_mir::interpret::sign_extend; pub trait EvalContextExt<'tcx> { fn wrapping_pointer_offset( @@ -18,6 +19,26 @@ pub trait EvalContextExt<'tcx> { pointee_ty: Ty<'tcx>, offset: i64, ) -> EvalResult<'tcx, Pointer>; + + fn value_to_isize( + &self, + value: ValTy<'tcx>, + ) -> EvalResult<'tcx, i64>; + + fn value_to_usize( + &self, + value: ValTy<'tcx>, + ) -> EvalResult<'tcx, u64>; + + fn value_to_i32( + &self, + value: ValTy<'tcx>, + ) -> EvalResult<'tcx, i32>; + + fn value_to_u8( + &self, + value: ValTy<'tcx>, + ) -> EvalResult<'tcx, u8>; } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { @@ -68,4 +89,40 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: err!(Overflow(mir::BinOp::Mul)) }; } + + fn value_to_isize( + &self, + value: ValTy<'tcx>, + ) -> EvalResult<'tcx, i64> { + assert_eq!(value.ty, self.tcx.types.isize); + let raw = self.value_to_primval(value)?.to_bytes()?; + let raw = sign_extend(self.tcx.tcx, raw, self.tcx.types.isize)?; + Ok(raw as i64) + } + + fn value_to_usize( + &self, + value: ValTy<'tcx>, + ) -> EvalResult<'tcx, u64> { + assert_eq!(value.ty, self.tcx.types.usize); + self.value_to_primval(value)?.to_bytes().map(|v| v as u64) + } + + fn value_to_i32( + &self, + value: ValTy<'tcx>, + ) -> EvalResult<'tcx, i32> { + assert_eq!(value.ty, self.tcx.types.i32); + let raw = self.value_to_primval(value)?.to_bytes()?; + let raw = sign_extend(self.tcx.tcx, raw, self.tcx.types.i32)?; + Ok(raw as i32) + } + + fn value_to_u8( + &self, + value: ValTy<'tcx>, + ) -> EvalResult<'tcx, u8> { + assert_eq!(value.ty, self.tcx.types.u8); + self.value_to_primval(value)?.to_bytes().map(|v| v as u8) + } } diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index 453e834566a6..234d1ee78483 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -70,7 +70,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "arith_offset" => { - let offset = self.value_to_primval(args[1])?.to_i128()? as i64; + let offset = self.value_to_isize(args[1])?; let ptr = self.into_ptr(args[0].value)?; let result_ptr = self.wrapping_pointer_offset(ptr, substs.type_at(0), offset)?; self.write_ptr(dest, result_ptr, dest_layout.ty)?; @@ -213,7 +213,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let elem_ty = substs.type_at(0); let elem_layout = self.layout_of(elem_ty)?; let elem_size = elem_layout.size.bytes(); - let count = self.value_to_primval(args[2])?.to_u64()?; + let count = self.value_to_usize(args[2])?; if count * elem_size != 0 { // TODO: We do not even validate alignment for the 0-bytes case. libstd relies on this in vec::IntoIter::next. // Also see the write_bytes intrinsic. @@ -407,7 +407,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "offset" => { - let offset = self.value_to_primval(args[1])?.to_i128()? as i64; + let offset = self.value_to_isize(args[1])?; let ptr = self.into_ptr(args[0].value)?; let result_ptr = self.pointer_offset(ptr, substs.type_at(0), offset)?; self.write_ptr(dest, result_ptr, dest_layout.ty)?; @@ -498,10 +498,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "powif32" => { let f = self.value_to_primval(args[0])?.to_bytes()?; let f = f32::from_bits(f as u32); - let i = self.value_to_primval(args[1])?.to_i128()?; + let i = self.value_to_i32(args[1])?; self.write_primval( dest, - PrimVal::Bytes(f.powi(i as i32).to_bits() as u128), + PrimVal::Bytes(f.powi(i).to_bits() as u128), dest_layout.ty, )?; } @@ -509,10 +509,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "powif64" => { let f = self.value_to_primval(args[0])?.to_bytes()?; let f = f64::from_bits(f as u64); - let i = self.value_to_primval(args[1])?.to_i128()?; + let i = self.value_to_i32(args[1])?; self.write_primval( dest, - PrimVal::Bytes(f.powi(i as i32).to_bits() as u128), + PrimVal::Bytes(f.powi(i).to_bits() as u128), dest_layout.ty, )?; } @@ -655,9 +655,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "write_bytes" => { let ty = substs.type_at(0); let ty_layout = self.layout_of(ty)?; - let val_byte = self.value_to_primval(args[1])?.to_u128()? as u8; + let val_byte = self.value_to_u8(args[1])?; let ptr = self.into_ptr(args[0].value)?; - let count = self.value_to_primval(args[2])?.to_u64()?; + let count = self.value_to_usize(args[2])?; if count > 0 { // HashMap relies on write_bytes on a NULL ptr with count == 0 to work // TODO: Should we, at least, validate the alignment? (Also see the copy intrinsic) From a4fdcd29b5c4cd5f733e7f920c4e33f21c6fd15a Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 9 May 2018 13:43:31 +0200 Subject: [PATCH 0060/5092] Disable cargo miri test for now --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b02b14392dae..9b6bd15b1eb9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,7 +24,7 @@ script: # Test cargo miri cd cargo-miri-test && cargo miri && - cargo miri test && + #cargo miri test && cd .. - | # and run all tests with full mir From c05d570d6e048db69116ebdd6af3ebb18bf08670 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 9 May 2018 14:05:51 +0200 Subject: [PATCH 0061/5092] Update the rustc_tests crate --- rustc_tests/src/main.rs | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/rustc_tests/src/main.rs b/rustc_tests/src/main.rs index 29b2dc2b7a42..77e4a3df406b 100644 --- a/rustc_tests/src/main.rs +++ b/rustc_tests/src/main.rs @@ -1,9 +1,10 @@ -#![feature(rustc_private, i128_type)] +#![feature(rustc_private)] extern crate miri; extern crate getopts; extern crate rustc; extern crate rustc_driver; extern crate rustc_errors; +extern crate rustc_trans_utils; extern crate syntax; use std::path::{PathBuf, Path}; @@ -18,6 +19,7 @@ use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls}; use rustc_driver::driver::{CompileState, CompileController}; use rustc::session::config::{self, Input, ErrorOutputType}; use rustc::hir::{self, itemlikevisit}; +use rustc_trans_utils::trans_crate::TransCrate; use rustc::ty::TyCtxt; use syntax::ast; @@ -51,14 +53,15 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { } fn late_callback( &mut self, + trans: &TransCrate, matches: &getopts::Matches, sess: &Session, cstore: &CrateStore, input: &Input, odir: &Option, - ofile: &Option + ofile: &Option, ) -> Compilation { - self.default.late_callback(matches, sess, cstore, input, odir, ofile) + self.default.late_callback(trans, matches, sess, cstore, input, odir, ofile) } fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> CompileController<'a> { let mut control = self.default.build_controller(sess, matches); @@ -81,30 +84,29 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { state.session.abort_if_errors(); let tcx = state.tcx.unwrap(); - let limits = Default::default(); if std::env::args().any(|arg| arg == "--test") { - struct Visitor<'a, 'tcx: 'a>(miri::ResourceLimits, TyCtxt<'a, 'tcx, 'tcx>, &'a CompileState<'a, 'tcx>); + struct Visitor<'a, 'tcx: 'a>(TyCtxt<'a, 'tcx, 'tcx>, &'a CompileState<'a, 'tcx>); impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::Item_::ItemFn(_, _, _, _, _, body_id) = i.node { - if i.attrs.iter().any(|attr| attr.name().map_or(false, |n| n == "test")) { - let did = self.1.hir.body_owner_def_id(body_id); - println!("running test: {}", self.1.def_path_debug_str(did)); - miri::eval_main(self.1, did, None, self.0); - self.2.session.abort_if_errors(); + if i.attrs.iter().any(|attr| attr.name() == "test") { + let did = self.0.hir.body_owner_def_id(body_id); + println!("running test: {}", self.0.def_path_debug_str(did)); + miri::eval_main(self.0, did, None); + self.1.session.abort_if_errors(); } } } fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {} fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {} } - state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(limits, tcx, state)); - } else if let Some((entry_node_id, _)) = *state.session.entry_fn.borrow() { + state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(tcx, state)); + } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { let entry_def_id = tcx.hir.local_def_id(entry_node_id); let start_wrapper = tcx.lang_items().start_fn().and_then(|start_fn| if tcx.is_mir_available(start_fn) { Some(start_fn) } else { None }); - miri::eval_main(tcx, entry_def_id, start_wrapper, limits); + miri::eval_main(tcx, entry_def_id, start_wrapper); state.session.abort_if_errors(); } else { From e1013e011ca698fff257704522f9a8088d594b24 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 9 May 2018 14:33:17 +0200 Subject: [PATCH 0062/5092] Appveyor update to ignore Cargo.lock --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 86f9b19af87f..40ecd9492c1a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -33,8 +33,8 @@ build: false test_script: - set RUST_BACKTRACE=1 - - cargo build --locked --release - - cargo test --locked --release + - cargo build --release + - cargo test --release notifications: - provider: Email From 27fe2636698f814debae621f00e1e3df8a7fca85 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 9 May 2018 14:37:00 +0200 Subject: [PATCH 0063/5092] Move back to a normal folder structure --- Cargo.toml | 7 ++----- {miri => src}/bin/cargo-miri.rs | 0 {miri => src}/bin/miri.rs | 0 {miri => src}/fn_call.rs | 0 {miri => src}/helpers.rs | 0 {miri => src}/intrinsic.rs | 0 {miri => src}/lib.rs | 0 {miri => src}/locks.rs | 0 {miri => src}/memory.rs | 0 {miri => src}/operator.rs | 0 {miri => src}/range_map.rs | 0 {miri => src}/tls.rs | 0 {miri => src}/validation.rs | 0 13 files changed, 2 insertions(+), 5 deletions(-) rename {miri => src}/bin/cargo-miri.rs (100%) rename {miri => src}/bin/miri.rs (100%) rename {miri => src}/fn_call.rs (100%) rename {miri => src}/helpers.rs (100%) rename {miri => src}/intrinsic.rs (100%) rename {miri => src}/lib.rs (100%) rename {miri => src}/locks.rs (100%) rename {miri => src}/memory.rs (100%) rename {miri => src}/operator.rs (100%) rename {miri => src}/range_map.rs (100%) rename {miri => src}/tls.rs (100%) rename {miri => src}/validation.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index 444c6f60d544..86ac2c040fd1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,17 +10,14 @@ build = "build.rs" [[bin]] doc = false name = "miri" -path = "miri/bin/miri.rs" +path = "src/bin/miri.rs" [[bin]] doc = false name = "cargo-miri" -path = "miri/bin/cargo-miri.rs" +path = "src/bin/cargo-miri.rs" required-features = ["cargo_miri"] -[lib] -path = "miri/lib.rs" - [dependencies] byteorder = { version = "1.1", features = ["i128"]} cargo_metadata = { version = "0.5", optional = true } diff --git a/miri/bin/cargo-miri.rs b/src/bin/cargo-miri.rs similarity index 100% rename from miri/bin/cargo-miri.rs rename to src/bin/cargo-miri.rs diff --git a/miri/bin/miri.rs b/src/bin/miri.rs similarity index 100% rename from miri/bin/miri.rs rename to src/bin/miri.rs diff --git a/miri/fn_call.rs b/src/fn_call.rs similarity index 100% rename from miri/fn_call.rs rename to src/fn_call.rs diff --git a/miri/helpers.rs b/src/helpers.rs similarity index 100% rename from miri/helpers.rs rename to src/helpers.rs diff --git a/miri/intrinsic.rs b/src/intrinsic.rs similarity index 100% rename from miri/intrinsic.rs rename to src/intrinsic.rs diff --git a/miri/lib.rs b/src/lib.rs similarity index 100% rename from miri/lib.rs rename to src/lib.rs diff --git a/miri/locks.rs b/src/locks.rs similarity index 100% rename from miri/locks.rs rename to src/locks.rs diff --git a/miri/memory.rs b/src/memory.rs similarity index 100% rename from miri/memory.rs rename to src/memory.rs diff --git a/miri/operator.rs b/src/operator.rs similarity index 100% rename from miri/operator.rs rename to src/operator.rs diff --git a/miri/range_map.rs b/src/range_map.rs similarity index 100% rename from miri/range_map.rs rename to src/range_map.rs diff --git a/miri/tls.rs b/src/tls.rs similarity index 100% rename from miri/tls.rs rename to src/tls.rs diff --git a/miri/validation.rs b/src/validation.rs similarity index 100% rename from miri/validation.rs rename to src/validation.rs From 9068a2a4b36ac7f008c52b8f6d5b874ec8a37739 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 9 May 2018 15:13:36 +0200 Subject: [PATCH 0064/5092] cargo cache was messing up xargo/miri install --- .travis.yml | 4 ++-- appveyor.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9b6bd15b1eb9..360b741106e5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ before_script: - rustup target add i686-pc-windows-gnu - rustup target add i686-pc-windows-msvc - rustup component add rust-src -- cargo install --git https://github.com/japaric/xargo.git +- cargo install xargo || echo "skipping xargo install" - export RUST_SYSROOT=$HOME/rust script: - set -e @@ -19,7 +19,7 @@ script: # Test plain miri cargo build --release --all-features && cargo test --release --all-features --all && - cargo install --all-features + cargo install --all-features --force - | # Test cargo miri cd cargo-miri-test && diff --git a/appveyor.yml b/appveyor.yml index 40ecd9492c1a..46580f274bf6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -22,7 +22,7 @@ install: - rustc -V - cargo -V - rustup component add rust-src - - cargo install --git https://github.com/japaric/xargo.git + - cargo install xargo - cd xargo - set RUSTFLAGS=-Zalways-encode-mir -Zmir-emit-validate=1 - xargo build From 8d6a893a4a47828fa0e9727545b6a0accf63a55d Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Fri, 11 May 2018 09:38:13 +0200 Subject: [PATCH 0065/5092] Rustup to 1.27.0-nightly (acd3871ba 2018-05-10) --- src/validation.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/validation.rs b/src/validation.rs index 8f444f19bd86..b274b4650157 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -401,7 +401,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } // Potentially-fat pointers. - ty::TyRef(_, ty::TypeAndMut { ty: pointee, .. }) | + ty::TyRef(_, pointee, _) | ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => { assert!(i < 2); @@ -658,11 +658,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } } TyNever => return err!(ValidationFailure(format!("The empty type is never valid."))), - TyRef(region, - ty::TypeAndMut { - ty: pointee_ty, - mutbl, - }) => { + TyRef(region, pointee_ty, mutbl) => { let val = self.read_place(query.place.1)?; // Sharing restricts our context if mutbl == MutImmutable { From 20c2e0bede0877abe79dda162922ec8c267105fe Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 19 Jul 2017 15:06:21 +0200 Subject: [PATCH 0066/5092] Test miri on mac os --- .travis.yml | 9 +++++++++ src/fn_call.rs | 11 +++++++++-- tests/run-pass-fullmir/catch.rs | 1 + tests/run-pass-fullmir/format.rs | 1 + tests/run-pass-fullmir/hello.rs | 1 + tests/run-pass-fullmir/issue-3794.rs | 1 + 6 files changed, 22 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 360b741106e5..6a987f93748c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,17 @@ language: rust cache: cargo + +os: +- osx +- linux + rust: - nightly before_script: +# mac os weirdness (https://github.com/travis-ci/travis-ci/issues/6307) +- curl -sSL https://rvm.io/mpapis.asc | gpg --import - +- rvm get stable +# actual travis code - export PATH=$HOME/.local/bin:$PATH - rustup target add i686-unknown-linux-gnu - rustup target add i686-pc-windows-gnu diff --git a/src/fn_call.rs b/src/fn_call.rs index c862238e889c..2b4e7b736628 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -531,9 +531,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // Return success (0) self.write_null(dest, dest_ty)?; } + "_tlv_atexit" => { - // TODO: handle it - } + return err!(Unimplemented("can't interpret with full mir for osx target".to_owned())); + }, // Stub out all the other pthread calls to just return 0 link_name if link_name.starts_with("pthread_") => { @@ -541,6 +542,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.write_null(dest, dest_ty)?; } + "mmap" => { + // This is a horrible hack, but well... the guard page mechanism calls mmap and expects a particular return value, so we give it that value + let addr = self.into_ptr(args[0].value)?; + self.write_ptr(dest, addr, dest_ty)?; + } + _ => { return err!(Unimplemented( format!("can't call C ABI function: {}", link_name), diff --git a/tests/run-pass-fullmir/catch.rs b/tests/run-pass-fullmir/catch.rs index 490f17d4cf4f..60c86c99e9aa 100644 --- a/tests/run-pass-fullmir/catch.rs +++ b/tests/run-pass-fullmir/catch.rs @@ -1,4 +1,5 @@ //ignore-msvc +//ignore-macos use std::panic::{catch_unwind, AssertUnwindSafe}; fn main() { diff --git a/tests/run-pass-fullmir/format.rs b/tests/run-pass-fullmir/format.rs index a14d7054e729..59af803b59f0 100644 --- a/tests/run-pass-fullmir/format.rs +++ b/tests/run-pass-fullmir/format.rs @@ -1,4 +1,5 @@ //ignore-msvc +//ignore-macos fn main() { println!("Hello {}", 13); } diff --git a/tests/run-pass-fullmir/hello.rs b/tests/run-pass-fullmir/hello.rs index 986efcaf9005..a0d73733bdfc 100644 --- a/tests/run-pass-fullmir/hello.rs +++ b/tests/run-pass-fullmir/hello.rs @@ -1,4 +1,5 @@ //ignore-msvc +//ignore-macos fn main() { println!("Hello, world!"); } diff --git a/tests/run-pass-fullmir/issue-3794.rs b/tests/run-pass-fullmir/issue-3794.rs index 8d55af58eeca..8b653f0f95fc 100644 --- a/tests/run-pass-fullmir/issue-3794.rs +++ b/tests/run-pass-fullmir/issue-3794.rs @@ -9,6 +9,7 @@ // except according to those terms. //ignore-msvc +//ignore-macos #![feature(box_syntax)] trait T { From 6a4c62c1673c3dabcc9a0c99018bd08fec46fda7 Mon Sep 17 00:00:00 2001 From: David Renshaw Date: Sat, 6 Jan 2018 16:50:21 -0500 Subject: [PATCH 0067/5092] add iter_any test --- tests/run-pass/iter_any.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/run-pass/iter_any.rs diff --git a/tests/run-pass/iter_any.rs b/tests/run-pass/iter_any.rs new file mode 100644 index 000000000000..b14eb074488b --- /dev/null +++ b/tests/run-pass/iter_any.rs @@ -0,0 +1,12 @@ +pub fn main() { + let f = |x: &u8| { 10u8 == *x }; + f(&1u8); + + let g = |(), x: &u8| { 10u8 == *x }; + g((), &1u8); + + let h = |(), (), x: &u8| { 10u8 == *x }; + h((), (), &1u8); + + [1, 2, 3u8].into_iter().any(|elt| 10 == *elt); +} From 68378a7b9772a58c6b1035e998f7d4d6ee2a6725 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 13 May 2018 13:14:26 +0200 Subject: [PATCH 0068/5092] Rustup to rustc 1.27.0-nightly (ff2ac35db 2018-05-12) --- src/fn_call.rs | 2 +- src/validation.rs | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 2b4e7b736628..272c27e40219 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -459,7 +459,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' promoted: None, }; let const_val = self.const_eval(cid)?; - let value = const_val.val.unwrap_u64(); + let value = const_val.unwrap_usize(self.tcx.tcx); if value == name { result = Some(path_value); break; diff --git a/src/validation.rs b/src/validation.rs index b274b4650157..deb1c5d5bc07 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -10,7 +10,7 @@ use rustc::infer::InferCtxt; use rustc::middle::region; use rustc::middle::const_val::ConstVal; use rustc_data_structures::indexed_vec::Idx; -use rustc_mir::interpret::{HasMemory, eval_body}; +use rustc_mir::interpret::HasMemory; use super::{EvalContext, Place, PlaceExtra, ValTy}; use rustc::mir::interpret::{DynamicLifetime, AccessKind, EvalErrorKind, Value, EvalError, EvalResult}; @@ -718,18 +718,17 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } } TyArray(elem_ty, len) => { - let len_val = match len.val { + let len = match len.val { ConstVal::Unevaluated(def_id, substs) => { - eval_body(self.tcx.tcx, GlobalId { + self.tcx.const_eval(self.tcx.param_env(def_id).and(GlobalId { instance: Instance::new(def_id, substs), promoted: None, - }, ty::ParamEnv::reveal_all()) - .ok_or_else(||EvalErrorKind::MachineError("".to_string()))? - .0 + })) + .map_err(|_err|EvalErrorKind::MachineError("".to_string()))? } - ConstVal::Value(val) => val, + ConstVal::Value(_) => len, }; - let len = ConstVal::Value(len_val).unwrap_u64(); + let len = len.unwrap_usize(self.tcx.tcx); for i in 0..len { let inner_place = self.place_index(query.place.1, query.ty, i as u64)?; self.validate( From 1bf0ffcb27ff8e38424f1e4115b52752cd0eeb70 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 13 May 2018 15:32:35 +0200 Subject: [PATCH 0069/5092] Enable backtraces for tests --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6a987f93748c..9aa632da05e0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,7 +27,7 @@ script: - | # Test plain miri cargo build --release --all-features && - cargo test --release --all-features --all && + RUST_BACKTRACE=1 cargo test --release --all-features --all && cargo install --all-features --force - | # Test cargo miri From d3b9085f1aec3cd60818e76fc2436145081cf7c6 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 19 May 2018 12:14:13 +0200 Subject: [PATCH 0070/5092] Rustup to rustc 1.28.0-nightly (952f344cd 2018-05-18) --- src/bin/miri.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 4e0be7bd3204..5ae9626f01fb 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -5,7 +5,7 @@ extern crate miri; extern crate rustc; extern crate rustc_driver; extern crate rustc_errors; -extern crate rustc_trans_utils; +extern crate rustc_codegen_utils; extern crate env_logger; extern crate log_settings; extern crate syntax; @@ -18,7 +18,7 @@ use rustc_driver::driver::{CompileState, CompileController}; use rustc::session::config::{self, Input, ErrorOutputType}; use rustc::hir::{self, itemlikevisit}; use rustc::ty::TyCtxt; -use rustc_trans_utils::trans_crate::TransCrate; +use rustc_codegen_utils::codegen_backend::CodegenBackend; use syntax::ast; use std::path::PathBuf; @@ -67,7 +67,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { } fn late_callback( &mut self, - trans: &TransCrate, + trans: &CodegenBackend, matches: &getopts::Matches, sess: &Session, cstore: &CrateStore, From 04608016ecd042308f2c55d652f67cac9025ae78 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sat, 19 May 2018 14:09:29 +0200 Subject: [PATCH 0071/5092] trans -> codegen_backend --- src/bin/miri.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 5ae9626f01fb..8d80135cde30 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -67,7 +67,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { } fn late_callback( &mut self, - trans: &CodegenBackend, + codegen_backend: &CodegenBackend, matches: &getopts::Matches, sess: &Session, cstore: &CrateStore, @@ -75,7 +75,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { odir: &Option, ofile: &Option, ) -> Compilation { - self.default.late_callback(trans, matches, sess, cstore, input, odir, ofile) + self.default.late_callback(codegen_backend, matches, sess, cstore, input, odir, ofile) } fn build_controller( &mut self, From 7d953a65f368fb2b60af5c0dc7ce51e3856ca4d6 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 20 May 2018 11:26:40 +0200 Subject: [PATCH 0072/5092] Rustup to rustc 1.28.0-nightly (a3085756e 2018-05-19) --- src/fn_call.rs | 34 +++++++++++++++++----------------- src/intrinsic.rs | 12 ++++++------ src/lib.rs | 16 ++++++++-------- src/locks.rs | 11 ++++++----- src/operator.rs | 10 +++++----- 5 files changed, 42 insertions(+), 41 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 272c27e40219..e7250eca949d 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -1,5 +1,5 @@ use rustc::ty::{self, Ty}; -use rustc::ty::layout::{self, Align, LayoutOf}; +use rustc::ty::layout::{self, Align, LayoutOf, Size}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc_data_structures::indexed_vec::Idx; @@ -187,7 +187,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.write_null(dest, dest_ty)?; } else { let align = self.tcx.data_layout.pointer_align; - let ptr = self.memory.allocate(size, align, Some(MemoryKind::C.into()))?; + let ptr = self.memory.allocate(Size::from_bytes(size), align, Some(MemoryKind::C.into()))?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } } @@ -281,7 +281,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memcmp" => { let left = self.into_ptr(args[0].value)?; let right = self.into_ptr(args[1].value)?; - let n = self.value_to_primval(args[2])?.to_u64()?; + let n = Size::from_bytes(self.value_to_primval(args[2])?.to_u64()?); let result = { let left_bytes = self.memory.read_bytes(left, n)?; @@ -306,11 +306,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let ptr = self.into_ptr(args[0].value)?; let val = self.value_to_primval(args[1])?.to_u64()? as u8; let num = self.value_to_primval(args[2])?.to_u64()?; - if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().rev().position( + if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().rev().position( |&c| c == val, ) { - let new_ptr = ptr.offset(num - idx as u64 - 1, &self)?; + let new_ptr = ptr.offset(Size::from_bytes(num - idx as u64 - 1), &self)?; self.write_ptr(dest, new_ptr, dest_ty)?; } else { self.write_null(dest, dest_ty)?; @@ -321,11 +321,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let ptr = self.into_ptr(args[0].value)?; let val = self.value_to_primval(args[1])?.to_u64()? as u8; let num = self.value_to_primval(args[2])?.to_u64()?; - if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().position( + if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().position( |&c| c == val, ) { - let new_ptr = ptr.offset(idx as u64, &self)?; + let new_ptr = ptr.offset(Size::from_bytes(idx as u64), &self)?; self.write_ptr(dest, new_ptr, dest_ty)?; } else { self.write_null(dest, dest_ty)?; @@ -381,12 +381,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' if let Some((name, value)) = new { // +1 for the null terminator let value_copy = self.memory.allocate( - (value.len() + 1) as u64, + Size::from_bytes((value.len() + 1) as u64), Align::from_bytes(1, 1).unwrap(), Some(MemoryKind::Env.into()), )?; self.memory.write_bytes(value_copy.into(), &value)?; - let trailing_zero_ptr = value_copy.offset(value.len() as u64, &self)?.into(); + let trailing_zero_ptr = value_copy.offset(Size::from_bytes(value.len() as u64), &self)?.into(); self.memory.write_bytes(trailing_zero_ptr, &[0])?; if let Some(var) = self.machine.env_vars.insert( name.to_owned(), @@ -410,7 +410,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // stdout/stderr use std::io::{self, Write}; - let buf_cont = self.memory.read_bytes(buf, n)?; + let buf_cont = self.memory.read_bytes(buf, Size::from_bytes(n))?; let res = if fd == 1 { io::stdout().write(buf_cont) } else { @@ -502,7 +502,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' key_ptr, key_align, PrimVal::Bytes(key), - key_size.bytes(), + key_size, false, )?; @@ -643,7 +643,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory.allocate(size, + let ptr = self.memory.allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), Some(MemoryKind::Rust.into()))?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; @@ -657,10 +657,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory.allocate(size, + let ptr = self.memory.allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), Some(MemoryKind::Rust.into()))?; - self.memory.write_repeat(ptr.into(), 0, size)?; + self.memory.write_repeat(ptr.into(), 0, Size::from_bytes(size))?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } "alloc::alloc::::__rust_dealloc" => { @@ -675,7 +675,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } self.memory.deallocate( ptr, - Some((old_size, Align::from_bytes(align, align).unwrap())), + Some((Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap())), MemoryKind::Rust.into(), )?; } @@ -692,9 +692,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } let new_ptr = self.memory.reallocate( ptr, - old_size, + Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap(), - new_size, + Size::from_bytes(new_size), Align::from_bytes(align, align).unwrap(), MemoryKind::Rust.into(), )?; diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 234d1ee78483..30de1c68ca61 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -1,5 +1,5 @@ use rustc::mir; -use rustc::ty::layout::{TyLayout, LayoutOf}; +use rustc::ty::layout::{TyLayout, LayoutOf, Size}; use rustc::ty; use rustc::mir::interpret::{EvalResult, PrimVal, PrimValKind, Value, Pointer}; @@ -35,7 +35,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // FIXME: return a real value in case the target allocation has an // alignment bigger than the one requested let n = u128::max_value(); - let amt = 128 - self.memory.pointer_size() * 8; + let amt = 128 - self.memory.pointer_size().bytes() * 8; self.write_primval(dest, PrimVal::Bytes((n << amt) >> amt), dest_layout.ty)?; }, @@ -225,7 +225,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: elem_align, dest, elem_align, - count * elem_size, + Size::from_bytes(count * elem_size), intrinsic_name.ends_with("_nonoverlapping"), )?; } @@ -332,7 +332,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "likely" | "unlikely" | "forget" => {} "init" => { - let size = dest_layout.size.bytes(); + let size = dest_layout.size; let init = |this: &mut Self, val: Value| { let zero_val = match val { Value::ByRef(ptr, _) => { @@ -631,7 +631,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "uninit" => { - let size = dest_layout.size.bytes(); + let size = dest_layout.size; let uninit = |this: &mut Self, val: Value| match val { Value::ByRef(ptr, _) => { this.memory.mark_definedness(ptr, size, false)?; @@ -662,7 +662,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // HashMap relies on write_bytes on a NULL ptr with count == 0 to work // TODO: Should we, at least, validate the alignment? (Also see the copy intrinsic) self.memory.check_align(ptr, ty_layout.align)?; - self.memory.write_repeat(ptr, val_byte, ty_layout.size.bytes() * count)?; + self.memory.write_repeat(ptr, val_byte, ty_layout.size * count)?; } } diff --git a/src/lib.rs b/src/lib.rs index dce31c4ed338..66ad6377e327 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,7 @@ extern crate regex; extern crate lazy_static; use rustc::ty::{self, TyCtxt}; -use rustc::ty::layout::{TyLayout, LayoutOf}; +use rustc::ty::layout::{TyLayout, LayoutOf, Size}; use rustc::ty::subst::Subst; use rustc::hir::def_id::DefId; use rustc::mir; @@ -93,7 +93,7 @@ pub fn eval_main<'a, 'tcx: 'a>( } // Return value - let size = ecx.tcx.data_layout.pointer_size.bytes(); + let size = ecx.tcx.data_layout.pointer_size; let align = ecx.tcx.data_layout.pointer_align; let ret_ptr = ecx.memory_mut().allocate(size, align, Some(MemoryKind::Stack))?; cleanup_ptr = Some(ret_ptr); @@ -299,7 +299,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; assert!(!layout.is_unsized()); let ptr = ecx.memory.allocate( - layout.size.bytes(), + layout.size, layout.align, None, )?; @@ -373,8 +373,8 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx.write_value( ValTy { value: Value::ByVal(PrimVal::Bytes(match layout.size.bytes() { - 0 => 1, - size => size, + 0 => 1 as u128, + size => size as u128, }.into())), ty: usize, }, @@ -407,10 +407,10 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn check_locks<'a>( mem: &Memory<'a, 'mir, 'tcx, Self>, ptr: MemoryPointer, - size: u64, + size: Size, access: AccessKind, ) -> EvalResult<'tcx> { - mem.check_locks(ptr, size, access) + mem.check_locks(ptr, size.bytes(), access) } fn add_lock<'a>( @@ -439,7 +439,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { //ptr, FIXME ptr: MemoryPointer { alloc_id: AllocId(0), - offset: 0, + offset: Size::from_bytes(0), }, lock: lock.active, }.into() diff --git a/src/locks.rs b/src/locks.rs index 677b0454a546..9efbabc7171b 100644 --- a/src/locks.rs +++ b/src/locks.rs @@ -1,5 +1,6 @@ use super::*; use rustc::middle::region; +use rustc::ty::layout::Size; //////////////////////////////////////////////////////////////////////////////// // Locks @@ -116,7 +117,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu }; let frame = self.cur_frame; locks - .check(Some(frame), ptr.offset, len, access) + .check(Some(frame), ptr.offset.bytes(), len, access) .map_err(|lock| { EvalErrorKind::MemoryLockViolation { ptr, @@ -146,7 +147,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu len, region ); - self.check_bounds(ptr.offset(len, &*self)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow) + self.check_bounds(ptr.offset(Size::from_bytes(len), &*self)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow) let locks = match self.data.locks.get_mut(&ptr.alloc_id) { Some(locks) => locks, @@ -157,7 +158,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu // Iterate over our range and acquire the lock. If the range is already split into pieces, // we have to manipulate all of them. let lifetime = DynamicLifetime { frame, region }; - for lock in locks.iter_mut(ptr.offset, len) { + for lock in locks.iter_mut(ptr.offset.bytes(), len) { if !lock.access_permitted(None, kind) { return err!(MemoryAcquireConflict { ptr, @@ -203,7 +204,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu None => return Ok(()), }; - 'locks: for lock in locks.iter_mut(ptr.offset, len) { + 'locks: for lock in locks.iter_mut(ptr.offset.bytes(), len) { let is_our_lock = match lock.active { WriteLock(lft) => // Double-check that we are holding the lock. @@ -281,7 +282,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu None => return Ok(()), }; - for lock in locks.iter_mut(ptr.offset, len) { + for lock in locks.iter_mut(ptr.offset.bytes(), len) { // Check if we have a suspension here let (got_the_lock, remove_suspension) = match lock.suspended.get_mut(&lock_id) { None => { diff --git a/src/operator.rs b/src/operator.rs index 220f8f9acd54..557e07975d73 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -89,9 +89,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Sub => { return self.binary_op( Sub, - PrimVal::Bytes(left.offset as u128), + PrimVal::Bytes(left.offset.bytes() as u128), self.tcx.types.usize, - PrimVal::Bytes(right.offset as u128), + PrimVal::Bytes(right.offset.bytes() as u128), self.tcx.types.usize, ).map(Some) } @@ -150,17 +150,17 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Add if signed => map_to_primval(left.overflowing_signed_offset(right, self)), Add if !signed => - map_to_primval(left.overflowing_offset(right as u64, self)), + map_to_primval(left.overflowing_offset(Size::from_bytes(right as u64), self)), BitAnd if !signed => { let base_mask : u64 = !(self.memory.get(left.alloc_id)?.align.abi() - 1); let right = right as u64; if right & base_mask == base_mask { // Case 1: The base address bits are all preserved, i.e., right is all-1 there - (PrimVal::Ptr(MemoryPointer::new(left.alloc_id, left.offset & right)), false) + (PrimVal::Ptr(MemoryPointer::new(left.alloc_id, Size::from_bytes(left.offset.bytes() & right))), false) } else if right & base_mask == 0 { // Case 2: The base address bits are all taken away, i.e., right is all-0 there - (PrimVal::from_u128((left.offset & right) as u128), false) + (PrimVal::from_u128((left.offset.bytes() & right) as u128), false) } else { return err!(ReadPointerAsBytes); } From 850841e9ed18b111f9574224d28f7643c1b037c2 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Fri, 25 May 2018 14:37:12 +0200 Subject: [PATCH 0073/5092] s/allocate_cached/allocate_bytes --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 66ad6377e327..f8119245b484 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -131,7 +131,7 @@ pub fn eval_main<'a, 'tcx: 'a>( // Third argument (argv): &[b"foo"] let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let ty = ecx.tcx.mk_imm_ptr(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8)); - let foo = ecx.memory.allocate_cached(b"foo\0"); + let foo = ecx.memory.allocate_bytes(b"foo\0"); let ptr_size = ecx.memory.pointer_size(); let ptr_align = ecx.tcx.data_layout.pointer_align; let foo_ptr = ecx.memory.allocate(ptr_size, ptr_align, None)?; From 49ca1746482e3c8221d8e8c7161b7d92ae076c8f Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 26 May 2018 17:07:34 +0200 Subject: [PATCH 0074/5092] Partial rustup --- benches/helpers/miri_helper.rs | 9 +- src/fn_call.rs | 114 +++++++++--------- src/helpers.rs | 34 +++--- src/intrinsic.rs | 206 +++++++++++++++++---------------- src/lib.rs | 104 ++++++++++++++--- src/locks.rs | 16 +-- src/operator.rs | 101 +++++++++------- src/tls.rs | 24 ++-- src/validation.rs | 6 +- 9 files changed, 358 insertions(+), 256 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 6657ba119976..2bf78b0a71cc 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -55,16 +55,13 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls<'a> { state.session.abort_if_errors(); let tcx = state.tcx.unwrap(); - let (entry_node_id, _) = state.session.entry_fn.borrow().expect( + let (entry_node_id, _, _) = state.session.entry_fn.borrow().expect( "no main or start function found", ); - let entry_def_id = tcx.map.local_def_id(entry_node_id); + let entry_def_id = tcx.hir.local_def_id(entry_node_id); - let memory_size = 100 * 1024 * 1024; // 100MB - let step_limit = 1000_000; - let stack_limit = 100; bencher.borrow_mut().iter(|| { - eval_main(tcx, entry_def_id, memory_size, step_limit, stack_limit); + eval_main(tcx, entry_def_id, None); }); state.session.abort_if_errors(); diff --git a/src/fn_call.rs b/src/fn_call.rs index e7250eca949d..ea0c5eb8b26e 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -38,7 +38,7 @@ fn write_discriminant_value<'a, 'mir, 'tcx: 'a + 'mir>( .val; let (discr_dest, discr) = ecx.place_field(dest, mir::Field::new(0), layout)?; - ecx.write_primval(discr_dest, PrimVal::Bytes(discr_val), discr.ty)?; + ecx.write_scalar(discr_dest, Scalar::from_u128(discr_val), discr.ty)?; } layout::Variants::NicheFilling { dataful_variant, @@ -51,7 +51,7 @@ fn write_discriminant_value<'a, 'mir, 'tcx: 'a + 'mir>( ecx.place_field(dest, mir::Field::new(0), layout)?; let niche_value = ((variant_index - niche_variants.start()) as u128) .wrapping_add(niche_start); - ecx.write_primval(niche_dest, PrimVal::Bytes(niche_value), niche.ty)?; + ecx.write_scalar(niche_dest, Scalar::from_u128(niche_value), niche.ty)?; } } } @@ -182,13 +182,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match &link_name[..] { "malloc" => { - let size = self.value_to_primval(args[0])?.to_u64()?; + let size = self.value_to_scalar(args[0])?.to_u64()?; if size == 0 { self.write_null(dest, dest_ty)?; } else { let align = self.tcx.data_layout.pointer_align; let ptr = self.memory.allocate(Size::from_bytes(size), align, Some(MemoryKind::C.into()))?; - self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; + self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; } } @@ -209,7 +209,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // // libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK) // is called if a `HashMap` is created the regular way. - match self.value_to_primval(args[0])?.to_u64()? { + match self.value_to_scalar(args[0])?.to_u64()? { 318 | 511 => { return err!(Unimplemented( "miri does not support random number generators".to_owned(), @@ -281,7 +281,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memcmp" => { let left = self.into_ptr(args[0].value)?; let right = self.into_ptr(args[1].value)?; - let n = Size::from_bytes(self.value_to_primval(args[2])?.to_u64()?); + let n = Size::from_bytes(self.value_to_scalar(args[2])?.to_u64()?); let result = { let left_bytes = self.memory.read_bytes(left, n)?; @@ -295,22 +295,22 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } }; - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes(result as u128), + Scalar::from_i8(result), dest_ty, )?; } "memrchr" => { let ptr = self.into_ptr(args[0].value)?; - let val = self.value_to_primval(args[1])?.to_u64()? as u8; - let num = self.value_to_primval(args[2])?.to_u64()?; + let val = self.value_to_scalar(args[1])?.to_u64()? as u8; + let num = self.value_to_scalar(args[2])?.to_u64()?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().rev().position( |&c| c == val, ) { - let new_ptr = ptr.offset(Size::from_bytes(num - idx as u64 - 1), &self)?; + let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), &self)?; self.write_ptr(dest, new_ptr, dest_ty)?; } else { self.write_null(dest, dest_ty)?; @@ -319,13 +319,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memchr" => { let ptr = self.into_ptr(args[0].value)?; - let val = self.value_to_primval(args[1])?.to_u64()? as u8; - let num = self.value_to_primval(args[2])?.to_u64()?; + let val = self.value_to_scalar(args[1])?.to_u64()? as u8; + let num = self.value_to_scalar(args[2])?.to_u64()?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().position( |&c| c == val, ) { - let new_ptr = ptr.offset(Size::from_bytes(idx as u64), &self)?; + let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), &self)?; self.write_ptr(dest, new_ptr, dest_ty)?; } else { self.write_null(dest, dest_ty)?; @@ -337,11 +337,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let name_ptr = self.into_ptr(args[0].value)?.to_ptr()?; let name = self.memory.read_c_str(name_ptr)?; match self.machine.env_vars.get(name) { - Some(&var) => PrimVal::Ptr(var), - None => PrimVal::Bytes(0), + Some(&var) => Scalar::Ptr(var), + None => Scalar::null(), } }; - self.write_primval(dest, result, dest_ty)?; + self.write_scalar(dest, result, dest_ty)?; } "unsetenv" => { @@ -361,7 +361,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } self.write_null(dest, dest_ty)?; } else { - self.write_primval(dest, PrimVal::from_i128(-1), dest_ty)?; + self.write_scalar(dest, Scalar::from_i128(-1), dest_ty)?; } } @@ -397,14 +397,14 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } self.write_null(dest, dest_ty)?; } else { - self.write_primval(dest, PrimVal::from_i128(-1), dest_ty)?; + self.write_scalar(dest, Scalar::from_i128(-1), dest_ty)?; } } "write" => { - let fd = self.value_to_primval(args[0])?.to_u64()?; + let fd = self.value_to_scalar(args[0])?.to_u64()?; let buf = self.into_ptr(args[1].value)?; - let n = self.value_to_primval(args[2])?.to_u64()?; + let n = self.value_to_scalar(args[2])?.to_u64()?; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { // stdout/stderr @@ -417,16 +417,17 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' io::stderr().write(buf_cont) }; match res { - Ok(n) => n as isize, + Ok(n) => n as i64, Err(_) => -1, } } else { warn!("Ignored output to FD {}", fd); - n as isize // pretend it all went well + n as i64 // pretend it all went well }; // now result is the value we return back to the program - self.write_primval( + let ptr_size = self.memory.pointer_size(); + self.write_scalar( dest, - PrimVal::Bytes(result as u128), + Scalar::from_isize(result, ptr_size), dest_ty, )?; } @@ -434,22 +435,23 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "strlen" => { let ptr = self.into_ptr(args[0].value)?.to_ptr()?; let n = self.memory.read_c_str(ptr)?.len(); - self.write_primval(dest, PrimVal::Bytes(n as u128), dest_ty)?; + let ptr_size = self.memory.pointer_size(); + self.write_scalar(dest, Scalar::from_usize(n as u64, ptr_size), dest_ty)?; } // Some things needed for sys::thread initialization to go through "signal" | "sigaction" | "sigaltstack" => { - self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?; + self.write_scalar(dest, Scalar::null(), dest_ty)?; } "sysconf" => { - let name = self.value_to_primval(args[0])?.to_u64()?; + let name = self.value_to_scalar(args[0])?.to_u64()?; trace!("sysconf() called with name {}", name); // cache the sysconf integers via miri's global cache let paths = &[ - (&["libc", "_SC_PAGESIZE"], PrimVal::Bytes(4096)), - (&["libc", "_SC_GETPW_R_SIZE_MAX"], PrimVal::from_i128(-1)), + (&["libc", "_SC_PAGESIZE"], Scalar::from_i128(4096)), + (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_i128(-1)), ]; let mut result = None; for &(path, path_value) in paths { @@ -467,7 +469,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } } if let Some(result) = result { - self.write_primval(dest, result, dest_ty)?; + self.write_scalar(dest, result, dest_ty)?; } else { return err!(Unimplemented( format!("Unimplemented sysconf name: {}", name), @@ -481,11 +483,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let key_align = self.layout_of(args[0].ty)?.align; // Extract the function type out of the signature (that seems easier than constructing it ourselves...) - let dtor = match self.into_ptr(args[1].value)?.into_inner_primval() { - PrimVal::Ptr(dtor_ptr) => Some(self.memory.get_fn(dtor_ptr)?), - PrimVal::Bytes(0) => None, - PrimVal::Bytes(_) => return err!(ReadBytesAsPointer), - PrimVal::Undef => return err!(ReadUndefBytes), + let dtor = match self.into_ptr(args[1].value)? { + Scalar::Ptr(dtor_ptr) => Some(self.memory.get_fn(dtor_ptr)?), + Scalar::Bits { defined: 0, .. } => return err!(ReadUndefBytes), + Scalar::Bits { bits: 0, .. } => None, + Scalar::Bits { .. } => return err!(ReadBytesAsPointer), }; // Figure out how large a pthread TLS key actually is. This is libc::pthread_key_t. @@ -498,10 +500,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' if key_size.bits() < 128 && key >= (1u128 << key_size.bits() as u128) { return err!(OutOfTls); } - self.memory.write_primval( + self.memory.write_scalar( key_ptr, key_align, - PrimVal::Bytes(key), + Scalar::from_u128(key), key_size, false, )?; @@ -511,20 +513,20 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "pthread_key_delete" => { // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t - let key = self.value_to_primval(args[0])?.to_u64()? as TlsKey; + let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey; self.memory.delete_tls_key(key)?; // Return success (0) self.write_null(dest, dest_ty)?; } "pthread_getspecific" => { // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t - let key = self.value_to_primval(args[0])?.to_u64()? as TlsKey; + let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey; let ptr = self.memory.load_tls(key)?; self.write_ptr(dest, ptr, dest_ty)?; } "pthread_setspecific" => { // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t - let key = self.value_to_primval(args[0])?.to_u64()? as TlsKey; + let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey; let new_ptr = self.into_ptr(args[1].value)?; self.memory.store_tls(key, new_ptr)?; @@ -635,8 +637,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match &path[..] { // Allocators are magic. They have no MIR, even when the rest of libstd does. "alloc::alloc::::__rust_alloc" => { - let size = self.value_to_primval(args[0])?.to_u64()?; - let align = self.value_to_primval(args[1])?.to_u64()?; + let size = self.value_to_scalar(args[0])?.to_u64()?; + let align = self.value_to_scalar(args[1])?.to_u64()?; if size == 0 { return err!(HeapAllocZeroBytes); } @@ -646,11 +648,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let ptr = self.memory.allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), Some(MemoryKind::Rust.into()))?; - self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; + self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; } "alloc::alloc::::__rust_alloc_zeroed" => { - let size = self.value_to_primval(args[0])?.to_u64()?; - let align = self.value_to_primval(args[1])?.to_u64()?; + let size = self.value_to_scalar(args[0])?.to_u64()?; + let align = self.value_to_scalar(args[1])?.to_u64()?; if size == 0 { return err!(HeapAllocZeroBytes); } @@ -661,12 +663,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Align::from_bytes(align, align).unwrap(), Some(MemoryKind::Rust.into()))?; self.memory.write_repeat(ptr.into(), 0, Size::from_bytes(size))?; - self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; + self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; } "alloc::alloc::::__rust_dealloc" => { let ptr = self.into_ptr(args[0].value)?.to_ptr()?; - let old_size = self.value_to_primval(args[1])?.to_u64()?; - let align = self.value_to_primval(args[2])?.to_u64()?; + let old_size = self.value_to_scalar(args[1])?.to_u64()?; + let align = self.value_to_scalar(args[2])?.to_u64()?; if old_size == 0 { return err!(HeapAllocZeroBytes); } @@ -681,9 +683,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "alloc::alloc::::__rust_realloc" => { let ptr = self.into_ptr(args[0].value)?.to_ptr()?; - let old_size = self.value_to_primval(args[1])?.to_u64()?; - let align = self.value_to_primval(args[2])?.to_u64()?; - let new_size = self.value_to_primval(args[3])?.to_u64()?; + let old_size = self.value_to_scalar(args[1])?.to_u64()?; + let align = self.value_to_scalar(args[2])?.to_u64()?; + let new_size = self.value_to_scalar(args[3])?.to_u64()?; if old_size == 0 || new_size == 0 { return err!(HeapAllocZeroBytes); } @@ -698,7 +700,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Align::from_bytes(align, align).unwrap(), MemoryKind::Rust.into(), )?; - self.write_primval(dest, PrimVal::Ptr(new_ptr), dest_ty)?; + self.write_scalar(dest, Scalar::Ptr(new_ptr), dest_ty)?; } // A Rust function is missing, which means we are running with MIR missing for libstd (or other dependencies). @@ -720,13 +722,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "std::rt::panicking" => { // we abort on panic -> `std::rt::panicking` always returns false let bool = self.tcx.types.bool; - self.write_primval(dest, PrimVal::from_bool(false), bool)?; + self.write_scalar(dest, Scalar::from_bool(false), bool)?; } "std::sys::imp::c::::AddVectoredExceptionHandler" | "std::sys::imp::c::::SetThreadStackGuarantee" => { let usize = self.tcx.types.usize; // any non zero value works for the stdlib. This is just used for stackoverflows anyway - self.write_primval(dest, PrimVal::Bytes(1), usize)?; + self.write_scalar(dest, Scalar::from_u128(1), usize)?; }, _ => return err!(NoMirFor(path)), } @@ -740,6 +742,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } fn write_null(&mut self, dest: Place, dest_ty: Ty<'tcx>) -> EvalResult<'tcx> { - self.write_primval(dest, PrimVal::Bytes(0), dest_ty) + self.write_scalar(dest, Scalar::null(), dest_ty) } } diff --git a/src/helpers.rs b/src/helpers.rs index a7b94a656da4..d881d5c27110 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,24 +1,24 @@ use mir; use rustc::ty::Ty; -use rustc::ty::layout::LayoutOf; +use rustc::ty::layout::{LayoutOf, Size}; -use super::{Pointer, EvalResult, PrimVal, EvalContext, ValTy}; +use super::{Scalar, ScalarExt, EvalResult, EvalContext, ValTy}; use rustc_mir::interpret::sign_extend; pub trait EvalContextExt<'tcx> { fn wrapping_pointer_offset( &self, - ptr: Pointer, + ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Pointer>; + ) -> EvalResult<'tcx, Scalar>; fn pointer_offset( &self, - ptr: Pointer, + ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Pointer>; + ) -> EvalResult<'tcx, Scalar>; fn value_to_isize( &self, @@ -44,22 +44,22 @@ pub trait EvalContextExt<'tcx> { impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { fn wrapping_pointer_offset( &self, - ptr: Pointer, + ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Pointer> { + ) -> EvalResult<'tcx, Scalar> { // FIXME: assuming here that type size is < i64::max_value() let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; let offset = offset.overflowing_mul(pointee_size).0; - ptr.wrapping_signed_offset(offset, self) + ptr.ptr_wrapping_signed_offset(offset, self) } fn pointer_offset( &self, - ptr: Pointer, + ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Pointer> { + ) -> EvalResult<'tcx, Scalar> { // This function raises an error if the offset moves the pointer outside of its allocation. We consider // ZSTs their own huge allocation that doesn't overlap with anything (and nothing moves in there because the size is 0). // We also consider the NULL pointer its own separate allocation, and all the remaining integers pointers their own @@ -76,9 +76,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // FIXME: assuming here that type size is < i64::max_value() let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; return if let Some(offset) = offset.checked_mul(pointee_size) { - let ptr = ptr.signed_offset(offset, self)?; + let ptr = ptr.ptr_signed_offset(offset, self)?; // Do not do bounds-checking for integers; they can never alias a normal pointer anyway. - if let PrimVal::Ptr(ptr) = ptr.into_inner_primval() { + if let Scalar::Ptr(ptr) = ptr { self.memory.check_bounds(ptr, false)?; } else if ptr.is_null()? { // We moved *to* a NULL pointer. That seems wrong, LLVM considers the NULL pointer its own small allocation. Reject this, for now. @@ -95,7 +95,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: value: ValTy<'tcx>, ) -> EvalResult<'tcx, i64> { assert_eq!(value.ty, self.tcx.types.isize); - let raw = self.value_to_primval(value)?.to_bytes()?; + let raw = self.value_to_scalar(value)?.to_bits(self.memory.pointer_size())?; let raw = sign_extend(self.tcx.tcx, raw, self.tcx.types.isize)?; Ok(raw as i64) } @@ -105,7 +105,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: value: ValTy<'tcx>, ) -> EvalResult<'tcx, u64> { assert_eq!(value.ty, self.tcx.types.usize); - self.value_to_primval(value)?.to_bytes().map(|v| v as u64) + self.value_to_scalar(value)?.to_bits(self.memory.pointer_size()).map(|v| v as u64) } fn value_to_i32( @@ -113,7 +113,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: value: ValTy<'tcx>, ) -> EvalResult<'tcx, i32> { assert_eq!(value.ty, self.tcx.types.i32); - let raw = self.value_to_primval(value)?.to_bytes()?; + let raw = self.value_to_scalar(value)?.to_bits(Size::from_bits(32))?; let raw = sign_extend(self.tcx.tcx, raw, self.tcx.types.i32)?; Ok(raw as i32) } @@ -123,6 +123,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: value: ValTy<'tcx>, ) -> EvalResult<'tcx, u8> { assert_eq!(value.ty, self.tcx.types.u8); - self.value_to_primval(value)?.to_bytes().map(|v| v as u8) + self.value_to_scalar(value)?.to_bits(Size::from_bits(8)).map(|v| v as u8) } } diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 30de1c68ca61..3d537ea629c3 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -1,12 +1,14 @@ use rustc::mir; -use rustc::ty::layout::{TyLayout, LayoutOf, Size}; +use rustc::ty::layout::{TyLayout, LayoutOf, Size, Primitive, Integer::*}; use rustc::ty; -use rustc::mir::interpret::{EvalResult, PrimVal, PrimValKind, Value, Pointer}; +use rustc::mir::interpret::{EvalResult, Scalar, Value}; use rustc_mir::interpret::{Place, PlaceExtra, HasMemory, EvalContext, ValTy}; use helpers::EvalContextExt as HelperEvalContextExt; +use super::ScalarExt; + pub trait EvalContextExt<'tcx> { fn call_intrinsic( &mut self, @@ -36,7 +38,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // alignment bigger than the one requested let n = u128::max_value(); let amt = 128 - self.memory.pointer_size().bytes() * 8; - self.write_primval(dest, PrimVal::Bytes((n << amt) >> amt), dest_layout.ty)?; + self.write_scalar(dest, Scalar::from_u128((n << amt) >> amt), dest_layout.ty)?; }, "add_with_overflow" => { @@ -77,7 +79,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "assume" => { - let cond = self.value_to_primval(args[0])?.to_bool()?; + let cond = self.value_to_scalar(args[0])?.to_bool()?; if !cond { return err!(AssumptionNotHeld); } @@ -115,16 +117,16 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ty = substs.type_at(0); let align = self.layout_of(ty)?.align; let ptr = self.into_ptr(args[0].value)?; - let change = self.value_to_primval(args[1])?; + let change = self.value_to_scalar(args[1])?; let old = self.read_value(ptr, align, ty)?; let old = match old { - Value::ByVal(val) => val, + Value::Scalar(val) => val, Value::ByRef { .. } => bug!("just read the value, can't be byref"), - Value::ByValPair(..) => bug!("atomic_xchg doesn't work with nonprimitives"), + Value::ScalarPair(..) => bug!("atomic_xchg doesn't work with nonprimitives"), }; - self.write_primval(dest, old, ty)?; - self.write_primval( - Place::from_primval_ptr(ptr, align), + self.write_scalar(dest, old, ty)?; + self.write_scalar( + Place::from_scalar_ptr(ptr, align), change, ty, )?; @@ -134,22 +136,22 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ty = substs.type_at(0); let align = self.layout_of(ty)?.align; let ptr = self.into_ptr(args[0].value)?; - let expect_old = self.value_to_primval(args[1])?; - let change = self.value_to_primval(args[2])?; + let expect_old = self.value_to_scalar(args[1])?; + let change = self.value_to_scalar(args[2])?; let old = self.read_value(ptr, align, ty)?; let old = match old { - Value::ByVal(val) => val, + Value::Scalar(val) => val, Value::ByRef { .. } => bug!("just read the value, can't be byref"), - Value::ByValPair(..) => bug!("atomic_cxchg doesn't work with nonprimitives"), + Value::ScalarPair(..) => bug!("atomic_cxchg doesn't work with nonprimitives"), }; let (val, _) = self.binary_op(mir::BinOp::Eq, old, ty, expect_old, ty)?; let valty = ValTy { - value: Value::ByValPair(old, val), + value: Value::ScalarPair(old, val), ty: dest_layout.ty, }; self.write_value(valty, dest)?; - self.write_primval( - Place::from_primval_ptr(ptr, dest_layout.align), + self.write_scalar( + Place::from_scalar_ptr(ptr, dest_layout.align), change, ty, )?; @@ -183,16 +185,16 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ty = substs.type_at(0); let align = self.layout_of(ty)?.align; let ptr = self.into_ptr(args[0].value)?; - let change = self.value_to_primval(args[1])?; + let change = self.value_to_scalar(args[1])?; let old = self.read_value(ptr, align, ty)?; let old = match old { - Value::ByVal(val) => val, + Value::Scalar(val) => val, Value::ByRef { .. } => bug!("just read the value, can't be byref"), - Value::ByValPair(..) => { + Value::ScalarPair(..) => { bug!("atomic_xadd_relaxed doesn't work with nonprimitives") } }; - self.write_primval(dest, old, ty)?; + self.write_scalar(dest, old, ty)?; let op = match intrinsic_name.split('_').nth(1).unwrap() { "or" => mir::BinOp::BitOr, "xor" => mir::BinOp::BitXor, @@ -203,7 +205,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: }; // FIXME: what do atomics do on overflow? let (val, _) = self.binary_op(op, old, ty, change, ty)?; - self.write_primval(Place::from_primval_ptr(ptr, dest_layout.align), val, ty)?; + self.write_scalar(Place::from_scalar_ptr(ptr, dest_layout.align), val, ty)?; } "breakpoint" => unimplemented!(), // halt miri @@ -233,8 +235,11 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "ctpop" | "cttz" | "cttz_nonzero" | "ctlz" | "ctlz_nonzero" | "bswap" => { let ty = substs.type_at(0); - let num = self.value_to_primval(args[0])?.to_bytes()?; - let kind = self.ty_to_primval_kind(ty)?; + let num = self.value_to_scalar(args[0])?.to_bytes()?; + let kind = match self.layout_of(ty)?.abi { + ty::layout::Abi::Scalar(ref scalar) => scalar.value, + _ => Err(::rustc::mir::interpret::EvalErrorKind::TypeNotPrimitive(ty))?, + }; let num = if intrinsic_name.ends_with("_nonzero") { if num == 0 { return err!(Intrinsic(format!("{} called on 0", intrinsic_name))); @@ -243,21 +248,21 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } else { numeric_intrinsic(intrinsic_name, num, kind)? }; - self.write_primval(dest, num, ty)?; + self.write_scalar(dest, num, ty)?; } "discriminant_value" => { let ty = substs.type_at(0); let adt_ptr = self.into_ptr(args[0].value)?; let adt_align = self.layout_of(args[0].ty)?.align; - let place = Place::from_primval_ptr(adt_ptr, adt_align); + let place = Place::from_scalar_ptr(adt_ptr, adt_align); let discr_val = self.read_discriminant_value(place, ty)?; - self.write_primval(dest, PrimVal::Bytes(discr_val), dest_layout.ty)?; + self.write_scalar(dest, Scalar::from_u128(discr_val), dest_layout.ty)?; } "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bytes()?; let f = f32::from_bits(f as u32); let f = match intrinsic_name { "sinf32" => f.sin(), @@ -274,12 +279,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "truncf32" => f.trunc(), _ => bug!(), }; - self.write_primval(dest, PrimVal::Bytes(f.to_bits() as u128), dest_layout.ty)?; + self.write_scalar(dest, Scalar::from_f32(f), dest_layout.ty)?; } "sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" | "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bytes()?; let f = f64::from_bits(f as u64); let f = match intrinsic_name { "sinf64" => f.sin(), @@ -296,13 +301,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "truncf64" => f.trunc(), _ => bug!(), }; - self.write_primval(dest, PrimVal::Bytes(f.to_bits() as u128), dest_layout.ty)?; + self.write_scalar(dest, Scalar::from_f64(f), dest_layout.ty)?; } "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { let ty = substs.type_at(0); - let a = self.value_to_primval(args[0])?; - let b = self.value_to_primval(args[1])?; + let a = self.value_to_scalar(args[0])?; + let b = self.value_to_scalar(args[1])?; let op = match intrinsic_name { "fadd_fast" => mir::BinOp::Add, "fsub_fast" => mir::BinOp::Sub, @@ -312,21 +317,21 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: _ => bug!(), }; let result = self.binary_op(op, a, ty, b, ty)?; - self.write_primval(dest, result.0, dest_layout.ty)?; + self.write_scalar(dest, result.0, dest_layout.ty)?; } "exact_div" => { // Performs an exact division, resulting in undefined behavior where // `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1` let ty = substs.type_at(0); - let a = self.value_to_primval(args[0])?; - let b = self.value_to_primval(args[1])?; + let a = self.value_to_scalar(args[0])?; + let b = self.value_to_scalar(args[1])?; // check x % y != 0 - if self.binary_op(mir::BinOp::Rem, a, ty, b, ty)?.0 != PrimVal::Bytes(0) { + if self.binary_op(mir::BinOp::Rem, a, ty, b, ty)?.0 != Scalar::null() { return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b))); } let result = self.binary_op(mir::BinOp::Div, a, ty, b, ty)?; - self.write_primval(dest, result.0, dest_layout.ty)?; + self.write_scalar(dest, result.0, dest_layout.ty)?; }, "likely" | "unlikely" | "forget" => {} @@ -341,21 +346,21 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: val } // TODO(solson): Revisit this, it's fishy to check for Undef here. - Value::ByVal(PrimVal::Undef) => { - match this.ty_to_primval_kind(dest_layout.ty) { - Ok(_) => Value::ByVal(PrimVal::Bytes(0)), - Err(_) => { + Value::Scalar(Scalar::Bits { defined: 0, .. }) => { + match this.layout_of(dest_layout.ty)?.abi { + ty::layout::Abi::Scalar(_) => Value::Scalar(Scalar::null()), + _ => { // FIXME(oli-obk): pass TyLayout to alloc_ptr instead of Ty let ptr = this.alloc_ptr(dest_layout.ty)?; - let ptr = Pointer::from(PrimVal::Ptr(ptr)); + let ptr = Scalar::Ptr(ptr); this.memory.write_repeat(ptr, 0, size)?; Value::ByRef(ptr, dest_layout.align) } } } - Value::ByVal(_) => Value::ByVal(PrimVal::Bytes(0)), - Value::ByValPair(..) => { - Value::ByValPair(PrimVal::Bytes(0), PrimVal::Bytes(0)) + Value::Scalar(_) => Value::Scalar(Scalar::null()), + Value::ScalarPair(..) => { + Value::ScalarPair(Scalar::null(), Scalar::null()) } }; Ok(zero_val) @@ -376,16 +381,16 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "min_align_of" => { let elem_ty = substs.type_at(0); let elem_align = self.layout_of(elem_ty)?.align.abi(); - let align_val = PrimVal::from_u128(elem_align as u128); - self.write_primval(dest, align_val, dest_layout.ty)?; + let align_val = Scalar::from_u128(elem_align as u128); + self.write_scalar(dest, align_val, dest_layout.ty)?; } "pref_align_of" => { let ty = substs.type_at(0); let layout = self.layout_of(ty)?; let align = layout.align.pref(); - let align_val = PrimVal::from_u128(align as u128); - self.write_primval(dest, align_val, dest_layout.ty)?; + let align_val = Scalar::from_u128(align as u128); + self.write_scalar(dest, align_val, dest_layout.ty)?; } "move_val_init" => { @@ -399,9 +404,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ty = substs.type_at(0); let env = ty::ParamEnv::reveal_all(); let needs_drop = ty.needs_drop(self.tcx.tcx, env); - self.write_primval( + self.write_scalar( dest, - PrimVal::from_bool(needs_drop), + Scalar::from_bool(needs_drop), dest_layout.ty, )?; } @@ -444,75 +449,75 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "powf32" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(32))?; let f = f32::from_bits(f as u32); - let f2 = self.value_to_primval(args[1])?.to_bytes()?; + let f2 = self.value_to_scalar(args[1])?.to_bits(Size::from_bits(32))?; let f2 = f32::from_bits(f2 as u32); - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes(f.powf(f2).to_bits() as u128), + Scalar::from_f32(f.powf(f2)), dest_layout.ty, )?; } "powf64" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(64))?; let f = f64::from_bits(f as u64); - let f2 = self.value_to_primval(args[1])?.to_bytes()?; + let f2 = self.value_to_scalar(args[1])?.to_bits(Size::from_bits(64))?; let f2 = f64::from_bits(f2 as u64); - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes(f.powf(f2).to_bits() as u128), + Scalar::from_f64(f.powf(f2)), dest_layout.ty, )?; } "fmaf32" => { - let a = self.value_to_primval(args[0])?.to_bytes()?; + let a = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(32))?; let a = f32::from_bits(a as u32); - let b = self.value_to_primval(args[1])?.to_bytes()?; + let b = self.value_to_scalar(args[1])?.to_bits(Size::from_bits(32))?; let b = f32::from_bits(b as u32); - let c = self.value_to_primval(args[2])?.to_bytes()?; + let c = self.value_to_scalar(args[2])?.to_bits(Size::from_bits(32))?; let c = f32::from_bits(c as u32); - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes((a * b + c).to_bits() as u128), + Scalar::from_f32(a * b + c), dest_layout.ty, )?; } "fmaf64" => { - let a = self.value_to_primval(args[0])?.to_bytes()?; + let a = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(64))?; let a = f64::from_bits(a as u64); - let b = self.value_to_primval(args[1])?.to_bytes()?; + let b = self.value_to_scalar(args[1])?.to_bits(Size::from_bits(64))?; let b = f64::from_bits(b as u64); - let c = self.value_to_primval(args[2])?.to_bytes()?; + let c = self.value_to_scalar(args[2])?.to_bits(Size::from_bits(64))?; let c = f64::from_bits(c as u64); - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes((a * b + c).to_bits() as u128), + Scalar::from_f64(a * b + c), dest_layout.ty, )?; } "powif32" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(32))?; let f = f32::from_bits(f as u32); let i = self.value_to_i32(args[1])?; - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes(f.powi(i).to_bits() as u128), + Scalar::from_f32(f.powi(i)), dest_layout.ty, )?; } "powif64" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(64))?; let f = f64::from_bits(f as u64); let i = self.value_to_i32(args[1])?; - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes(f.powi(i).to_bits() as u128), + Scalar::from_f64(f.powi(i)), dest_layout.ty, )?; } @@ -520,15 +525,15 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "size_of" => { let ty = substs.type_at(0); let size = self.layout_of(ty)?.size.bytes().into(); - self.write_primval(dest, PrimVal::from_u128(size), dest_layout.ty)?; + self.write_scalar(dest, Scalar::from_u128(size), dest_layout.ty)?; } "size_of_val" => { let ty = substs.type_at(0); let (size, _) = self.size_and_align_of_dst(ty, args[0].value)?; - self.write_primval( + self.write_scalar( dest, - PrimVal::from_u128(size.bytes() as u128), + Scalar::from_u128(size.bytes() as u128), dest_layout.ty, )?; } @@ -537,9 +542,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "align_of_val" => { let ty = substs.type_at(0); let (_, align) = self.size_and_align_of_dst(ty, args[0].value)?; - self.write_primval( + self.write_scalar( dest, - PrimVal::from_u128(align.abi() as u128), + Scalar::from_u128(align.abi() as u128), dest_layout.ty, )?; } @@ -553,7 +558,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "type_id" => { let ty = substs.type_at(0); let n = self.tcx.type_id_hash(ty); - self.write_primval(dest, PrimVal::Bytes(n as u128), dest_layout.ty)?; + self.write_scalar(dest, Scalar::Bits { bits: n as u128, defined: 64 }, dest_layout.ty)?; } "transmute" => { @@ -566,7 +571,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "unchecked_shl" => { let bits = dest_layout.size.bytes() as u128 * 8; - let rhs = self.value_to_primval(args[1])? + let rhs = self.value_to_scalar(args[1])? .to_bytes()?; if rhs >= bits { return err!(Intrinsic( @@ -584,7 +589,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "unchecked_shr" => { let bits = dest_layout.size.bytes() as u128 * 8; - let rhs = self.value_to_primval(args[1])? + let rhs = self.value_to_scalar(args[1])? .to_bytes()?; if rhs >= bits { return err!(Intrinsic( @@ -601,7 +606,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "unchecked_div" => { - let rhs = self.value_to_primval(args[1])? + let rhs = self.value_to_scalar(args[1])? .to_bytes()?; if rhs == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_div"))); @@ -616,7 +621,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "unchecked_rem" => { - let rhs = self.value_to_primval(args[1])? + let rhs = self.value_to_scalar(args[1])? .to_bytes()?; if rhs == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_rem"))); @@ -637,7 +642,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: this.memory.mark_definedness(ptr, size, false)?; Ok(val) } - _ => Ok(Value::ByVal(PrimVal::Undef)), + _ => Ok(Value::Scalar(Scalar::undef())), }; match dest { Place::Local { frame, local } => self.modify_local(frame, local, uninit)?, @@ -681,26 +686,25 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: fn numeric_intrinsic<'tcx>( name: &str, bytes: u128, - kind: PrimValKind, -) -> EvalResult<'tcx, PrimVal> { + kind: Primitive, +) -> EvalResult<'tcx, Scalar> { macro_rules! integer_intrinsic { ($method:ident) => ({ - use rustc::mir::interpret::PrimValKind::*; let result_bytes = match kind { - I8 => (bytes as i8).$method() as u128, - U8 => (bytes as u8).$method() as u128, - I16 => (bytes as i16).$method() as u128, - U16 => (bytes as u16).$method() as u128, - I32 => (bytes as i32).$method() as u128, - U32 => (bytes as u32).$method() as u128, - I64 => (bytes as i64).$method() as u128, - U64 => (bytes as u64).$method() as u128, - I128 => (bytes as i128).$method() as u128, - U128 => bytes.$method() as u128, + Primitive::Int(I8, true) => (bytes as i8).$method() as u128, + Primitive::Int(I8, false) => (bytes as u8).$method() as u128, + Primitive::Int(I16, true) => (bytes as i16).$method() as u128, + Primitive::Int(I16, false) => (bytes as u16).$method() as u128, + Primitive::Int(I32, true) => (bytes as i32).$method() as u128, + Primitive::Int(I32, false) => (bytes as u32).$method() as u128, + Primitive::Int(I64, true) => (bytes as i64).$method() as u128, + Primitive::Int(I64, false) => (bytes as u64).$method() as u128, + Primitive::Int(I128, true) => (bytes as i128).$method() as u128, + Primitive::Int(I128, false) => bytes.$method() as u128, _ => bug!("invalid `{}` argument: {:?}", name, bytes), }; - PrimVal::Bytes(result_bytes) + Scalar::from_u128(result_bytes) }); } diff --git a/src/lib.rs b/src/lib.rs index f8119245b484..e3c83c284db9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,6 +53,81 @@ use validation::EvalContextExt as ValidationEvalContextExt; use range_map::RangeMap; use validation::{ValidationQuery, AbsPlace}; +pub trait ScalarExt { + fn null() -> Self; + fn from_i8(i: i8) -> Self; + fn from_u128(i: u128) -> Self; + fn from_i128(i: i128) -> Self; + fn from_usize(i: u64, ptr_size: Size) -> Self; + fn from_isize(i: i64, ptr_size: Size) -> Self; + fn from_f32(f: f32) -> Self; + fn from_f64(f: f64) -> Self; + fn to_u64(self) -> EvalResult<'static, u64>; + fn is_null(self) -> EvalResult<'static, bool>; + fn to_bytes(self) -> EvalResult<'static, u128>; +} + +impl ScalarExt for Scalar { + fn null() -> Self { + Scalar::Bits { bits: 0, defined: 128 } + } + + fn from_i8(i: i8) -> Self { + Scalar::Bits { bits: i as i128 as u128, defined: 8 } + } + + fn from_u128(i: u128) -> Self { + Scalar::Bits { bits: i, defined: 128 } + } + + fn from_i128(i: i128) -> Self { + Scalar::Bits { bits: i as u128, defined: 128 } + } + + fn from_usize(i: u64, ptr_size: Size) -> Self { + Scalar::Bits { bits: i as u128, defined: ptr_size.bits() as u8 } + } + + fn from_isize(i: i64, ptr_size: Size) -> Self { + Scalar::Bits { bits: i as i128 as u128, defined: ptr_size.bits() as u8 } + } + + fn from_f32(f: f32) -> Self { + Scalar::Bits { bits: f.to_bits() as u128, defined: 32 } + } + + fn from_f64(f: f64) -> Self { + Scalar::Bits { bits: f.to_bits() as u128, defined: 64 } + } + + fn to_u64(self) -> EvalResult<'static, u64> { + let b = self.to_bits(Size::from_bits(64))?; + assert_eq!(b as u64 as u128, b); + Ok(b as u64) + } + + fn is_null(self) -> EvalResult<'static, bool> { + match self { + Scalar::Bits { bits, defined } => { + if defined > 0 { + Ok(bits == 0) + } else { + err!(ReadUndefBytes) + } + } + Scalar::Ptr(_) => Ok(false) + } + } + + fn to_bytes(self) -> EvalResult<'static, u128> { + match self { + Scalar::Bits { defined: 0, .. } => err!(ReadUndefBytes), + Scalar::Bits { bits, .. } => Ok(bits), + Scalar::Ptr(_) => err!(ReadPointerAsBytes), + } + } +} + pub fn eval_main<'a, 'tcx: 'a>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, @@ -65,7 +140,7 @@ pub fn eval_main<'a, 'tcx: 'a>( ) -> EvalResult<'tcx> { let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; - let mut cleanup_ptr = None; // Pointer to be deallocated when we are done + let mut cleanup_ptr = None; // Scalar to be deallocated when we are done if !main_mir.return_ty().is_nil() || main_mir.arg_count != 0 { return err!(Unimplemented( @@ -116,7 +191,7 @@ pub fn eval_main<'a, 'tcx: 'a>( let main_ptr_ty = ecx.tcx.mk_fn_ptr(main_ty.fn_sig(ecx.tcx.tcx)); ecx.write_value( ValTy { - value: Value::ByVal(PrimVal::Ptr(main_ptr)), + value: Value::Scalar(Scalar::Ptr(main_ptr)), ty: main_ptr_ty, }, dest, @@ -125,7 +200,7 @@ pub fn eval_main<'a, 'tcx: 'a>( // Second argument (argc): 1 let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let ty = ecx.tcx.types.isize; - ecx.write_primval(dest, PrimVal::Bytes(1), ty)?; + ecx.write_scalar(dest, Scalar::from_u128(1), ty)?; // FIXME: extract main source file path // Third argument (argv): &[b"foo"] @@ -135,7 +210,7 @@ pub fn eval_main<'a, 'tcx: 'a>( let ptr_size = ecx.memory.pointer_size(); let ptr_align = ecx.tcx.data_layout.pointer_align; let foo_ptr = ecx.memory.allocate(ptr_size, ptr_align, None)?; - ecx.memory.write_primval(foo_ptr.into(), ptr_align, PrimVal::Ptr(foo.into()), ptr_size, false)?; + ecx.memory.write_scalar(foo_ptr.into(), ptr_align, Scalar::Ptr(foo), ptr_size, false)?; ecx.memory.mark_static_initialized(foo_ptr.alloc_id, Mutability::Immutable)?; ecx.write_ptr(dest, foo_ptr.into(), ty)?; @@ -145,7 +220,7 @@ pub fn eval_main<'a, 'tcx: 'a>( main_instance, main_mir.span, main_mir, - Place::from_primval_ptr(PrimVal::Bytes(1).into(), ty::layout::Align::from_bytes(1, 1).unwrap()), + Place::from_scalar_ptr(Scalar::from_u128(1), ty::layout::Align::from_bytes(1, 1).unwrap()), StackPopCleanup::None, )?; @@ -187,6 +262,7 @@ pub fn eval_main<'a, 'tcx: 'a>( } } } + ::std::process::exit(1); } } } @@ -195,7 +271,7 @@ pub fn eval_main<'a, 'tcx: 'a>( pub struct Evaluator<'tcx> { /// Environment variables set by `setenv` /// Miri does not expose env vars from the host to the emulated program - pub(crate) env_vars: HashMap, MemoryPointer>, + pub(crate) env_vars: HashMap, Pointer>, /// Places that were suspended by the validation subsystem, and will be recovered later pub(crate) suspended: HashMap>>, @@ -205,7 +281,7 @@ pub type TlsKey = usize; #[derive(Copy, Clone, Debug)] pub struct TlsEntry<'tcx> { - data: Pointer, // Will eventually become a map from thread IDs to `Pointer`s, if we ever support more than one thread. + data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. dtor: Option>, } @@ -256,11 +332,11 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn try_ptr_op<'a>( ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, bin_op: mir::BinOp, - left: PrimVal, + left: Scalar, left_ty: ty::Ty<'tcx>, - right: PrimVal, + right: Scalar, right_ty: ty::Ty<'tcx>, - ) -> EvalResult<'tcx, Option<(PrimVal, bool)>> { + ) -> EvalResult<'tcx, Option<(Scalar, bool)>> { ecx.ptr_op(bin_op, left, left_ty, right, right_ty) } @@ -372,7 +448,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; ecx.write_value( ValTy { - value: Value::ByVal(PrimVal::Bytes(match layout.size.bytes() { + value: Value::Scalar(Scalar::from_u128(match layout.size.bytes() { 0 => 1 as u128, size => size as u128, }.into())), @@ -385,7 +461,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; ecx.write_value( ValTy { - value: Value::ByVal(PrimVal::Bytes(layout.align.abi().into())), + value: Value::Scalar(Scalar::from_u128(layout.align.abi().into())), ty: usize, }, dest, @@ -406,7 +482,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn check_locks<'a>( mem: &Memory<'a, 'mir, 'tcx, Self>, - ptr: MemoryPointer, + ptr: Pointer, size: Size, access: AccessKind, ) -> EvalResult<'tcx> { @@ -437,7 +513,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { .map_err(|lock| { EvalErrorKind::DeallocatedLockedMemory { //ptr, FIXME - ptr: MemoryPointer { + ptr: Pointer { alloc_id: AllocId(0), offset: Size::from_bytes(0), }, diff --git a/src/locks.rs b/src/locks.rs index 9efbabc7171b..a463f8ba575e 100644 --- a/src/locks.rs +++ b/src/locks.rs @@ -70,27 +70,27 @@ impl<'tcx> LockInfo<'tcx> { pub trait MemoryExt<'tcx> { fn check_locks( &self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, access: AccessKind, ) -> EvalResult<'tcx>; fn acquire_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, region: Option, kind: AccessKind, ) -> EvalResult<'tcx>; fn suspend_write_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, lock_path: &AbsPlace<'tcx>, suspend: Option, ) -> EvalResult<'tcx>; fn recover_write_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, lock_path: &AbsPlace<'tcx>, lock_region: Option, @@ -103,7 +103,7 @@ pub trait MemoryExt<'tcx> { impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evaluator<'tcx>> { fn check_locks( &self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, access: AccessKind, ) -> EvalResult<'tcx> { @@ -132,7 +132,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu /// Acquire the lock for the given lifetime fn acquire_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, region: Option, kind: AccessKind, @@ -191,7 +191,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu /// When suspending, the same cases are fine; we just register an additional suspension. fn suspend_write_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, lock_path: &AbsPlace<'tcx>, suspend: Option, @@ -264,7 +264,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu /// Release a suspension from the write lock. If this is the last suspension or if there is no suspension, acquire the lock. fn recover_write_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, lock_path: &AbsPlace<'tcx>, lock_region: Option, diff --git a/src/operator.rs b/src/operator.rs index 557e07975d73..721b4f0bfdda 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,4 +1,5 @@ use rustc::ty; +use rustc::ty::layout::Primitive; use rustc::mir; use super::*; @@ -9,38 +10,58 @@ pub trait EvalContextExt<'tcx> { fn ptr_op( &self, bin_op: mir::BinOp, - left: PrimVal, + left: Scalar, left_ty: ty::Ty<'tcx>, - right: PrimVal, + right: Scalar, right_ty: ty::Ty<'tcx>, - ) -> EvalResult<'tcx, Option<(PrimVal, bool)>>; + ) -> EvalResult<'tcx, Option<(Scalar, bool)>>; fn ptr_int_arithmetic( &self, bin_op: mir::BinOp, - left: MemoryPointer, + left: Pointer, right: i128, signed: bool, - ) -> EvalResult<'tcx, (PrimVal, bool)>; + ) -> EvalResult<'tcx, (Scalar, bool)>; } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { fn ptr_op( &self, bin_op: mir::BinOp, - left: PrimVal, + left: Scalar, left_ty: ty::Ty<'tcx>, - right: PrimVal, + right: Scalar, right_ty: ty::Ty<'tcx>, - ) -> EvalResult<'tcx, Option<(PrimVal, bool)>> { - use rustc::mir::interpret::PrimValKind::*; + ) -> EvalResult<'tcx, Option<(Scalar, bool)>> { use rustc::mir::BinOp::*; - let usize = PrimValKind::from_uint_size(self.memory.pointer_size()); - let isize = PrimValKind::from_int_size(self.memory.pointer_size()); - let left_kind = self.ty_to_primval_kind(left_ty)?; - let right_kind = self.ty_to_primval_kind(right_ty)?; + use rustc::ty::layout::Integer::*; + let usize = Primitive::Int(match self.memory.pointer_size().bytes() { + 1 => I8, + 2 => I16, + 4 => I32, + 8 => I64, + 16 => I128, + _ => unreachable!(), + }, false); + let isize = Primitive::Int(match self.memory.pointer_size().bytes() { + 1 => I8, + 2 => I16, + 4 => I32, + 8 => I64, + 16 => I128, + _ => unreachable!(), + }, true); + let left_kind = match self.layout_of(left_ty)?.abi { + ty::layout::Abi::Scalar(ref scalar) => scalar.value, + _ => Err(EvalErrorKind::TypeNotPrimitive(left_ty))?, + }; + let right_kind = match self.layout_of(right_ty)?.abi { + ty::layout::Abi::Scalar(ref scalar) => scalar.value, + _ => Err(EvalErrorKind::TypeNotPrimitive(right_ty))?, + }; match bin_op { - Offset if left_kind == Ptr && right_kind == usize => { + Offset if left_kind == Primitive::Pointer && right_kind == usize => { let pointee_ty = left_ty .builtin_deref(true) .expect("Offset called on non-ptr type") @@ -48,35 +69,35 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ptr = self.pointer_offset( left.into(), pointee_ty, - right.to_bytes()? as i64, + right.to_bits(self.memory.pointer_size())? as i64, )?; - Ok(Some((ptr.into_inner_primval(), false))) + Ok(Some((ptr, false))) } // These work on anything Eq if left_kind == right_kind => { let result = match (left, right) { - (PrimVal::Bytes(left), PrimVal::Bytes(right)) => left == right, - (PrimVal::Ptr(left), PrimVal::Ptr(right)) => left == right, - (PrimVal::Undef, _) | - (_, PrimVal::Undef) => return err!(ReadUndefBytes), + (Scalar::Bits { .. }, Scalar::Bits { .. }) => { + left.to_bits(self.memory.pointer_size())? == right.to_bits(self.memory.pointer_size())? + }, + (Scalar::Ptr(left), Scalar::Ptr(right)) => left == right, _ => false, }; - Ok(Some((PrimVal::from_bool(result), false))) + Ok(Some((Scalar::from_bool(result), false))) } Ne if left_kind == right_kind => { let result = match (left, right) { - (PrimVal::Bytes(left), PrimVal::Bytes(right)) => left != right, - (PrimVal::Ptr(left), PrimVal::Ptr(right)) => left != right, - (PrimVal::Undef, _) | - (_, PrimVal::Undef) => return err!(ReadUndefBytes), + (Scalar::Bits { .. }, Scalar::Bits { .. }) => { + left.to_bits(self.memory.pointer_size())? != right.to_bits(self.memory.pointer_size())? + }, + (Scalar::Ptr(left), Scalar::Ptr(right)) => left != right, _ => true, }; - Ok(Some((PrimVal::from_bool(result), false))) + Ok(Some((Scalar::from_bool(result), false))) } // These need both pointers to be in the same allocation Lt | Le | Gt | Ge | Sub if left_kind == right_kind && - (left_kind == Ptr || left_kind == usize || left_kind == isize) && + (left_kind == Primitive::Pointer || left_kind == usize || left_kind == isize) && left.is_ptr() && right.is_ptr() => { let left = left.to_ptr()?; let right = right.to_ptr()?; @@ -89,15 +110,15 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Sub => { return self.binary_op( Sub, - PrimVal::Bytes(left.offset.bytes() as u128), + Scalar::Bits { bits: left.offset.bytes() as u128, defined: self.memory.pointer_size().bits() as u8 }, self.tcx.types.usize, - PrimVal::Bytes(right.offset.bytes() as u128), + Scalar::Bits { bits: right.offset.bytes() as u128, defined: self.memory.pointer_size().bits() as u8 }, self.tcx.types.usize, ).map(Some) } _ => bug!("We already established it has to be one of these operators."), }; - Ok(Some((PrimVal::from_bool(res), false))) + Ok(Some((Scalar::from_bool(res), false))) } else { // Both are pointers, but from different allocations. err!(InvalidPointerMath) @@ -106,23 +127,23 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // These work if one operand is a pointer, the other an integer Add | BitAnd | Sub if left_kind == right_kind && (left_kind == usize || left_kind == isize) && - left.is_ptr() && right.is_bytes() => { + left.is_ptr() && right.is_bits() => { // Cast to i128 is fine as we checked the kind to be ptr-sized self.ptr_int_arithmetic( bin_op, left.to_ptr()?, - right.to_bytes()? as i128, + right.to_bits(self.memory.pointer_size())? as i128, left_kind == isize, ).map(Some) } Add | BitAnd if left_kind == right_kind && (left_kind == usize || left_kind == isize) && - left.is_bytes() && right.is_ptr() => { + left.is_bits() && right.is_ptr() => { // This is a commutative operation, just swap the operands self.ptr_int_arithmetic( bin_op, right.to_ptr()?, - left.to_bytes()? as i128, + left.to_bits(self.memory.pointer_size())? as i128, left_kind == isize, ).map(Some) } @@ -133,14 +154,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: fn ptr_int_arithmetic( &self, bin_op: mir::BinOp, - left: MemoryPointer, + left: Pointer, right: i128, signed: bool, - ) -> EvalResult<'tcx, (PrimVal, bool)> { + ) -> EvalResult<'tcx, (Scalar, bool)> { use rustc::mir::BinOp::*; - fn map_to_primval((res, over): (MemoryPointer, bool)) -> (PrimVal, bool) { - (PrimVal::Ptr(res), over) + fn map_to_primval((res, over): (Pointer, bool)) -> (Scalar, bool) { + (Scalar::Ptr(res), over) } Ok(match bin_op { @@ -157,10 +178,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let right = right as u64; if right & base_mask == base_mask { // Case 1: The base address bits are all preserved, i.e., right is all-1 there - (PrimVal::Ptr(MemoryPointer::new(left.alloc_id, Size::from_bytes(left.offset.bytes() & right))), false) + (Scalar::Ptr(Pointer::new(left.alloc_id, Size::from_bytes(left.offset.bytes() & right))), false) } else if right & base_mask == 0 { // Case 2: The base address bits are all taken away, i.e., right is all-0 there - (PrimVal::from_u128((left.offset.bytes() & right) as u128), false) + (Scalar::Bits { bits: (left.offset.bytes() & right) as u128, defined: 128 }, false) } else { return err!(ReadPointerAsBytes); } diff --git a/src/tls.rs b/src/tls.rs index e55cbede2339..7f49509ef42e 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -1,17 +1,17 @@ use rustc::{ty, mir}; -use super::{TlsKey, TlsEntry, EvalResult, EvalErrorKind, Pointer, Memory, Evaluator, Place, - StackPopCleanup, EvalContext}; +use super::{TlsKey, TlsEntry, EvalResult, EvalErrorKind, Scalar, ScalarExt, Memory, Evaluator, + Place, StackPopCleanup, EvalContext}; pub trait MemoryExt<'tcx> { fn create_tls_key(&mut self, dtor: Option>) -> TlsKey; fn delete_tls_key(&mut self, key: TlsKey) -> EvalResult<'tcx>; - fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Pointer>; - fn store_tls(&mut self, key: TlsKey, new_data: Pointer) -> EvalResult<'tcx>; + fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar>; + fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx>; fn fetch_tls_dtor( &mut self, key: Option, - ) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Pointer, TlsKey)>>; + ) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Scalar, TlsKey)>>; } pub trait EvalContextExt<'tcx> { @@ -25,7 +25,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu self.data.thread_local.insert( new_key, TlsEntry { - data: Pointer::null(), + data: Scalar::null(), dtor, }, ); @@ -43,7 +43,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu }; } - fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Pointer> { + fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar> { return match self.data.thread_local.get(&key) { Some(&TlsEntry { data, .. }) => { trace!("TLS key {} loaded: {:?}", key, data); @@ -53,7 +53,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu }; } - fn store_tls(&mut self, key: TlsKey, new_data: Pointer) -> EvalResult<'tcx> { + fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx> { return match self.data.thread_local.get_mut(&key) { Some(&mut TlsEntry { ref mut data, .. }) => { trace!("TLS key {} stored: {:?}", key, new_data); @@ -85,19 +85,21 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu fn fetch_tls_dtor( &mut self, key: Option, - ) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Pointer, TlsKey)>> { + ) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Scalar, TlsKey)>> { use std::collections::Bound::*; + + let thread_local = &mut self.data.thread_local; let start = match key { Some(key) => Excluded(key), None => Unbounded, }; for (&key, &mut TlsEntry { ref mut data, dtor }) in - self.data.thread_local.range_mut((start, Unbounded)) + thread_local.range_mut((start, Unbounded)) { if !data.is_null()? { if let Some(dtor) = dtor { let ret = Some((dtor, *data, key)); - *data = Pointer::null(); + *data = Scalar::null(); return Ok(ret); } } diff --git a/src/validation.rs b/src/validation.rs index deb1c5d5bc07..24ddffee9def 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -12,7 +12,7 @@ use rustc::middle::const_val::ConstVal; use rustc_data_structures::indexed_vec::Idx; use rustc_mir::interpret::HasMemory; -use super::{EvalContext, Place, PlaceExtra, ValTy}; +use super::{EvalContext, Place, PlaceExtra, ValTy, ScalarExt}; use rustc::mir::interpret::{DynamicLifetime, AccessKind, EvalErrorKind, Value, EvalError, EvalResult}; use locks::MemoryExt; @@ -119,7 +119,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Index(v) => { let value = self.frame().get_local(v)?; let ty = self.tcx.tcx.types.usize; - let n = self.value_to_primval(ValTy { value, ty })?.to_u64()?; + let n = self.value_to_scalar(ValTy { value, ty })?.to_u64()?; Index(n) }, ConstantIndex { offset, min_length, from_end } => @@ -652,7 +652,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' TyBool | TyFloat(_) | TyChar => { if mode.acquiring() { let val = self.read_place(query.place.1)?; - let val = self.value_to_primval(ValTy { value: val, ty: query.ty })?; + let val = self.value_to_scalar(ValTy { value: val, ty: query.ty })?; val.to_bytes()?; // TODO: Check if these are valid bool/float/codepoint/UTF-8 } From b0ee05e86115d39e0c111e78e1d017f334b065a6 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 30 May 2018 14:29:32 +0200 Subject: [PATCH 0075/5092] `memcmp` returns `i32` --- src/fn_call.rs | 4 ++-- src/lib.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index ea0c5eb8b26e..6a2255e57772 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -289,7 +289,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' use std::cmp::Ordering::*; match left_bytes.cmp(right_bytes) { - Less => -1i8, + Less => -1i32, Equal => 0, Greater => 1, } @@ -297,7 +297,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.write_scalar( dest, - Scalar::from_i8(result), + Scalar::from_i32(result), dest_ty, )?; } diff --git a/src/lib.rs b/src/lib.rs index e3c83c284db9..079560c0ca95 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,7 +55,7 @@ use validation::{ValidationQuery, AbsPlace}; pub trait ScalarExt { fn null() -> Self; - fn from_i8(i: i8) -> Self; + fn from_i32(i: i32) -> Self; fn from_u128(i: u128) -> Self; fn from_i128(i: i128) -> Self; fn from_usize(i: u64, ptr_size: Size) -> Self; @@ -72,8 +72,8 @@ impl ScalarExt for Scalar { Scalar::Bits { bits: 0, defined: 128 } } - fn from_i8(i: i8) -> Self { - Scalar::Bits { bits: i as i128 as u128, defined: 8 } + fn from_i32(i: i32) -> Self { + Scalar::Bits { bits: i as u32 as u128, defined: 32 } } fn from_u128(i: u128) -> Self { From f927014c8a147208cbeb373c714d2748c33ae7b9 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 30 May 2018 14:29:54 +0200 Subject: [PATCH 0076/5092] Comparing Scalar's with differend `defined` values is false --- src/intrinsic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 3d537ea629c3..1e8090dc1897 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -327,7 +327,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let a = self.value_to_scalar(args[0])?; let b = self.value_to_scalar(args[1])?; // check x % y != 0 - if self.binary_op(mir::BinOp::Rem, a, ty, b, ty)?.0 != Scalar::null() { + if !self.binary_op(mir::BinOp::Rem, a, ty, b, ty)?.0.is_null()? { return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b))); } let result = self.binary_op(mir::BinOp::Div, a, ty, b, ty)?; From ac667d372f4094debfb9b7e29041f9e4a874fa6c Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 30 May 2018 14:30:15 +0200 Subject: [PATCH 0077/5092] Comparing non-pointer-size types should be possible --- src/operator.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index 721b4f0bfdda..f36e749dc927 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -52,11 +52,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: 16 => I128, _ => unreachable!(), }, true); - let left_kind = match self.layout_of(left_ty)?.abi { + let left_layout = self.layout_of(left_ty)?; + let left_kind = match left_layout.abi { ty::layout::Abi::Scalar(ref scalar) => scalar.value, _ => Err(EvalErrorKind::TypeNotPrimitive(left_ty))?, }; - let right_kind = match self.layout_of(right_ty)?.abi { + let right_layout = self.layout_of(right_ty)?; + let right_kind = match right_layout.abi { ty::layout::Abi::Scalar(ref scalar) => scalar.value, _ => Err(EvalErrorKind::TypeNotPrimitive(right_ty))?, }; @@ -77,7 +79,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Eq if left_kind == right_kind => { let result = match (left, right) { (Scalar::Bits { .. }, Scalar::Bits { .. }) => { - left.to_bits(self.memory.pointer_size())? == right.to_bits(self.memory.pointer_size())? + left.to_bits(left_layout.size)? == right.to_bits(right_layout.size)? }, (Scalar::Ptr(left), Scalar::Ptr(right)) => left == right, _ => false, @@ -87,7 +89,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Ne if left_kind == right_kind => { let result = match (left, right) { (Scalar::Bits { .. }, Scalar::Bits { .. }) => { - left.to_bits(self.memory.pointer_size())? != right.to_bits(self.memory.pointer_size())? + left.to_bits(left_layout.size)? != right.to_bits(right_layout.size)? }, (Scalar::Ptr(left), Scalar::Ptr(right)) => left != right, _ => true, From e4f075459c5b9bb83ca695cf139581e07587bc15 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 30 May 2018 15:59:04 +0200 Subject: [PATCH 0078/5092] TlsKey is messy because it changes types between systems --- src/fn_call.rs | 9 +++------ src/lib.rs | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 6a2255e57772..d1a483d2e804 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -512,21 +512,18 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.write_null(dest, dest_ty)?; } "pthread_key_delete" => { - // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t - let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey; + let key = self.value_to_scalar(args[0])?.to_bytes()?; self.memory.delete_tls_key(key)?; // Return success (0) self.write_null(dest, dest_ty)?; } "pthread_getspecific" => { - // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t - let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey; + let key = self.value_to_scalar(args[0])?.to_bytes()?; let ptr = self.memory.load_tls(key)?; self.write_ptr(dest, ptr, dest_ty)?; } "pthread_setspecific" => { - // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t - let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey; + let key = self.value_to_scalar(args[0])?.to_bytes()?; let new_ptr = self.into_ptr(args[1].value)?; self.memory.store_tls(key, new_ptr)?; diff --git a/src/lib.rs b/src/lib.rs index 079560c0ca95..6d7c0b05f80f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -277,7 +277,7 @@ pub struct Evaluator<'tcx> { pub(crate) suspended: HashMap>>, } -pub type TlsKey = usize; +pub type TlsKey = u128; #[derive(Copy, Clone, Debug)] pub struct TlsEntry<'tcx> { From ea2c8bfb041bad805578d0ec50b46b0675ca0187 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 30 May 2018 17:43:27 +0200 Subject: [PATCH 0079/5092] `align_offset` intrinsic is now a lang item --- src/fn_call.rs | 12 ++++++++++++ src/intrinsic.rs | 8 -------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index d1a483d2e804..fdaa819c08f7 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -135,6 +135,18 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' _ => {} } + if self.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { + // FIXME: return a real value in case the target allocation has an + // alignment bigger than the one requested + let n = u128::max_value(); + let amt = 128 - self.memory.pointer_size().bytes() * 8; + let (dest, return_to_block) = destination.unwrap(); + let ty = self.tcx.types.usize; + self.write_scalar(dest, Scalar::from_u128((n << amt) >> amt), ty)?; + self.goto_block(return_to_block); + return Ok(true); + } + let mir = match self.load_mir(instance.def) { Ok(mir) => mir, Err(EvalError { kind: EvalErrorKind::NoMirFor(path), .. }) => { diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 1e8090dc1897..cee2f1ab7682 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -33,14 +33,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..]; match intrinsic_name { - "align_offset" => { - // FIXME: return a real value in case the target allocation has an - // alignment bigger than the one requested - let n = u128::max_value(); - let amt = 128 - self.memory.pointer_size().bytes() * 8; - self.write_scalar(dest, Scalar::from_u128((n << amt) >> amt), dest_layout.ty)?; - }, - "add_with_overflow" => { self.intrinsic_with_overflow( mir::BinOp::Add, From 066a284557ff6e6a2aa19084f599f167a724af7b Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 30 May 2018 17:43:54 +0200 Subject: [PATCH 0080/5092] `to_u64` and `to_bytes` are horribly easy to use wrongly. --- src/fn_call.rs | 8 ++++---- src/lib.rs | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index fdaa819c08f7..72efcd6ede07 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -316,7 +316,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memrchr" => { let ptr = self.into_ptr(args[0].value)?; - let val = self.value_to_scalar(args[1])?.to_u64()? as u8; + let val = self.value_to_scalar(args[1])?.to_bytes()? as u8; let num = self.value_to_scalar(args[2])?.to_u64()?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().rev().position( |&c| c == val, @@ -331,7 +331,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memchr" => { let ptr = self.into_ptr(args[0].value)?; - let val = self.value_to_scalar(args[1])?.to_u64()? as u8; + let val = self.value_to_scalar(args[1])?.to_bytes()? as u8; let num = self.value_to_scalar(args[2])?.to_u64()?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().position( |&c| c == val, @@ -414,9 +414,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "write" => { - let fd = self.value_to_scalar(args[0])?.to_u64()?; + let fd = self.value_to_scalar(args[0])?.to_bytes()?; let buf = self.into_ptr(args[1].value)?; - let n = self.value_to_scalar(args[2])?.to_u64()?; + let n = self.value_to_scalar(args[2])?.to_bytes()? as u64; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { // stdout/stderr diff --git a/src/lib.rs b/src/lib.rs index 6d7c0b05f80f..550965573cb4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,6 +64,9 @@ pub trait ScalarExt { fn from_f64(f: f64) -> Self; fn to_u64(self) -> EvalResult<'static, u64>; fn is_null(self) -> EvalResult<'static, bool>; + /// HACK: this function just extracts all bits if `defined != 0` + /// Mainly used for args of C-functions and we should totally correctly fetch the size + /// of their arguments fn to_bytes(self) -> EvalResult<'static, u128>; } From e29b696e8d10978914cb5c20329cb2ac0d5bdb91 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sun, 3 Jun 2018 11:54:17 +0200 Subject: [PATCH 0081/5092] Use correct bit size when reading usize values --- src/fn_call.rs | 30 +++++++++++++++--------------- src/lib.rs | 6 +++--- src/validation.rs | 2 +- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 72efcd6ede07..36cc29a2b5b5 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -194,7 +194,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match &link_name[..] { "malloc" => { - let size = self.value_to_scalar(args[0])?.to_u64()?; + let size = self.value_to_scalar(args[0])?.to_usize(self)?; if size == 0 { self.write_null(dest, dest_ty)?; } else { @@ -221,7 +221,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // // libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK) // is called if a `HashMap` is created the regular way. - match self.value_to_scalar(args[0])?.to_u64()? { + match self.value_to_scalar(args[0])?.to_usize(self)? { 318 | 511 => { return err!(Unimplemented( "miri does not support random number generators".to_owned(), @@ -293,7 +293,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memcmp" => { let left = self.into_ptr(args[0].value)?; let right = self.into_ptr(args[1].value)?; - let n = Size::from_bytes(self.value_to_scalar(args[2])?.to_u64()?); + let n = Size::from_bytes(self.value_to_scalar(args[2])?.to_usize(self)?); let result = { let left_bytes = self.memory.read_bytes(left, n)?; @@ -317,7 +317,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memrchr" => { let ptr = self.into_ptr(args[0].value)?; let val = self.value_to_scalar(args[1])?.to_bytes()? as u8; - let num = self.value_to_scalar(args[2])?.to_u64()?; + let num = self.value_to_scalar(args[2])?.to_usize(self)?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().rev().position( |&c| c == val, ) @@ -332,7 +332,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memchr" => { let ptr = self.into_ptr(args[0].value)?; let val = self.value_to_scalar(args[1])?.to_bytes()? as u8; - let num = self.value_to_scalar(args[2])?.to_u64()?; + let num = self.value_to_scalar(args[2])?.to_usize(self)?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().position( |&c| c == val, ) @@ -457,7 +457,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "sysconf" => { - let name = self.value_to_scalar(args[0])?.to_u64()?; + let name = self.value_to_scalar(args[0])?.to_usize(self)?; trace!("sysconf() called with name {}", name); // cache the sysconf integers via miri's global cache @@ -646,8 +646,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match &path[..] { // Allocators are magic. They have no MIR, even when the rest of libstd does. "alloc::alloc::::__rust_alloc" => { - let size = self.value_to_scalar(args[0])?.to_u64()?; - let align = self.value_to_scalar(args[1])?.to_u64()?; + let size = self.value_to_scalar(args[0])?.to_usize(self)?; + let align = self.value_to_scalar(args[1])?.to_usize(self)?; if size == 0 { return err!(HeapAllocZeroBytes); } @@ -660,8 +660,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; } "alloc::alloc::::__rust_alloc_zeroed" => { - let size = self.value_to_scalar(args[0])?.to_u64()?; - let align = self.value_to_scalar(args[1])?.to_u64()?; + let size = self.value_to_scalar(args[0])?.to_usize(self)?; + let align = self.value_to_scalar(args[1])?.to_usize(self)?; if size == 0 { return err!(HeapAllocZeroBytes); } @@ -676,8 +676,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "alloc::alloc::::__rust_dealloc" => { let ptr = self.into_ptr(args[0].value)?.to_ptr()?; - let old_size = self.value_to_scalar(args[1])?.to_u64()?; - let align = self.value_to_scalar(args[2])?.to_u64()?; + let old_size = self.value_to_scalar(args[1])?.to_usize(self)?; + let align = self.value_to_scalar(args[2])?.to_usize(self)?; if old_size == 0 { return err!(HeapAllocZeroBytes); } @@ -692,9 +692,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "alloc::alloc::::__rust_realloc" => { let ptr = self.into_ptr(args[0].value)?.to_ptr()?; - let old_size = self.value_to_scalar(args[1])?.to_u64()?; - let align = self.value_to_scalar(args[2])?.to_u64()?; - let new_size = self.value_to_scalar(args[3])?.to_u64()?; + let old_size = self.value_to_scalar(args[1])?.to_usize(self)?; + let align = self.value_to_scalar(args[2])?.to_usize(self)?; + let new_size = self.value_to_scalar(args[3])?.to_usize(self)?; if old_size == 0 || new_size == 0 { return err!(HeapAllocZeroBytes); } diff --git a/src/lib.rs b/src/lib.rs index 550965573cb4..a29211df996b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,7 +62,7 @@ pub trait ScalarExt { fn from_isize(i: i64, ptr_size: Size) -> Self; fn from_f32(f: f32) -> Self; fn from_f64(f: f64) -> Self; - fn to_u64(self) -> EvalResult<'static, u64>; + fn to_usize<'a, 'mir, 'tcx>(self, ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>) -> EvalResult<'static, u64>; fn is_null(self) -> EvalResult<'static, bool>; /// HACK: this function just extracts all bits if `defined != 0` /// Mainly used for args of C-functions and we should totally correctly fetch the size @@ -103,8 +103,8 @@ impl ScalarExt for Scalar { Scalar::Bits { bits: f.to_bits() as u128, defined: 64 } } - fn to_u64(self) -> EvalResult<'static, u64> { - let b = self.to_bits(Size::from_bits(64))?; + fn to_usize<'a, 'mir, 'tcx>(self, ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>) -> EvalResult<'static, u64> { + let b = self.to_bits(ecx.memory.pointer_size())?; assert_eq!(b as u64 as u128, b); Ok(b as u64) } diff --git a/src/validation.rs b/src/validation.rs index 24ddffee9def..d82a345c2512 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -119,7 +119,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Index(v) => { let value = self.frame().get_local(v)?; let ty = self.tcx.tcx.types.usize; - let n = self.value_to_scalar(ValTy { value, ty })?.to_u64()?; + let n = self.value_to_scalar(ValTy { value, ty })?.to_usize(self)?; Index(n) }, ConstantIndex { offset, min_length, from_end } => From dbadf1e3fbc7a26a560e570efb6c5c4468e046e4 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sun, 3 Jun 2018 12:13:30 +0200 Subject: [PATCH 0082/5092] Update cargo-miri --- cargo-miri-test/Cargo.lock | 12 ++++++------ src/bin/cargo-miri.rs | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cargo-miri-test/Cargo.lock b/cargo-miri-test/Cargo.lock index 8b2387fa6410..85c3c08dba01 100644 --- a/cargo-miri-test/Cargo.lock +++ b/cargo-miri-test/Cargo.lock @@ -1,14 +1,14 @@ -[root] +[[package]] +name = "byteorder" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "cargo-miri-test" version = "0.1.0" dependencies = [ "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "byteorder" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [metadata] "checksum byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c40977b0ee6b9885c9013cd41d9feffdd22deb3bb4dc3a71d901cc7a77de18c8" diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 39a41583a39e..010f25e8152d 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -154,7 +154,7 @@ fn main() { // this check ensures that dependencies are built but not interpreted and the final crate is // interpreted but not built - let miri_enabled = std::env::args().any(|s| s == "-Zno-trans"); + let miri_enabled = std::env::args().any(|s| s == "--emit=dep-info,metadata"); let mut command = if miri_enabled { let mut path = std::env::current_exe().expect("current executable path invalid"); @@ -193,7 +193,7 @@ where if !found_dashes { args.push("--".to_owned()); } - args.push("-Zno-trans".to_owned()); + args.push("--emit=dep-info,metadata".to_owned()); args.push("--cfg".to_owned()); args.push(r#"feature="cargo-miri""#.to_owned()); From 10078dd6d0d056d19e4c64fc8bf4c8b1ec02a86b Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sun, 3 Jun 2018 12:54:43 +0200 Subject: [PATCH 0083/5092] Reenable the rustc tester --- rustc_tests/Cargo.lock | 209 +++++++++++++++++++++++++--------------- rustc_tests/src/main.rs | 10 +- src/lib.rs | 1 - 3 files changed, 134 insertions(+), 86 deletions(-) diff --git a/rustc_tests/Cargo.lock b/rustc_tests/Cargo.lock index a1e273a96bdb..9cf4fe0d1342 100644 --- a/rustc_tests/Cargo.lock +++ b/rustc_tests/Cargo.lock @@ -1,10 +1,3 @@ -[root] -name = "rustc_tests" -version = "0.1.0" -dependencies = [ - "miri 0.1.0", -] - [[package]] name = "aho-corasick" version = "0.6.3" @@ -14,26 +7,13 @@ dependencies = [ ] [[package]] -name = "backtrace" -version = "0.3.3" +name = "atty" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "backtrace-sys" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -46,36 +26,24 @@ name = "cfg-if" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "dbghelp-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "env_logger" -version = "0.4.3" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "gcc" -version = "0.3.53" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "kernel32-sys" -version = "0.2.2" +name = "humantime" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -83,6 +51,11 @@ name = "lazy_static" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "lazy_static" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "libc" version = "0.2.30" @@ -90,15 +63,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "log" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "log_settings" -version = "0.1.1" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -109,15 +77,41 @@ dependencies = [ "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "memchr" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "miri" version = "0.1.0" dependencies = [ "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_miri 0.1.0", + "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quick-error" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "redox_syscall" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "redox_termios" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -132,26 +126,54 @@ dependencies = [ "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "regex" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "regex-syntax" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "rustc-demangle" -version = "0.1.5" +name = "regex-syntax" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] -name = "rustc_miri" +name = "rustc_tests" version = "0.1.0" dependencies = [ - "backtrace 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "miri 0.1.0", +] + +[[package]] +name = "termcolor" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "termion" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -163,6 +185,11 @@ dependencies = [ "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ucd-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unreachable" version = "1.0.0" @@ -183,35 +210,59 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi" -version = "0.2.8" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "winapi-build" -version = "0.1.1" +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "wincolor" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [metadata] "checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" -"checksum backtrace 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "99f2ce94e22b8e664d95c57fff45b98a966c2252b60691d0b7aeeccd88d70983" -"checksum backtrace-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "afccc5772ba333abccdf60d55200fa3406f8c59dcf54d5f7998c9107d3799c7c" +"checksum atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2fc4a1aa4c24c0718a250f0681885c1af91419d242f29eb8f2ab28502d80dbd1" "checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" -"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" -"checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b" -"checksum gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)" = "e8310f7e9c890398b0e80e301c4f474e9918d2b27fca8f48486ca775fa9ffc5a" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0e6e40ebb0e66918a37b38c7acab4e10d299e0463fe2af5d29b9cc86710cfd2a" +"checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" "checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" +"checksum lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e6412c5e2ad9584b0b8e979393122026cdd6d2a80b933f890dcd694ddbe73739" "checksum libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)" = "2370ca07ec338939e356443dac2296f581453c35fe1e3a3ed06023c49435f915" -"checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" -"checksum log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3d382732ea0fbc09790c4899db3255bdea0fc78b54bf234bd18a63bb603915b6" +"checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" +"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" +"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" +"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" +"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b" +"checksum regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75ecf88252dce580404a22444fc7d626c01815debba56a7f4f536772a5ff19d3" "checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" -"checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e" +"checksum regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1ac0f60d675cc6cf13a20ec076568254472551051ad5dd050364d70671bf6b" +"checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83" +"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14" +"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" +"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb06499a3a4d44302791052df005d5232b927ed1a9658146d842165c4de7767" diff --git a/rustc_tests/src/main.rs b/rustc_tests/src/main.rs index 77e4a3df406b..ecc5287c7277 100644 --- a/rustc_tests/src/main.rs +++ b/rustc_tests/src/main.rs @@ -4,7 +4,7 @@ extern crate getopts; extern crate rustc; extern crate rustc_driver; extern crate rustc_errors; -extern crate rustc_trans_utils; +extern crate rustc_codegen_utils; extern crate syntax; use std::path::{PathBuf, Path}; @@ -19,7 +19,7 @@ use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls}; use rustc_driver::driver::{CompileState, CompileController}; use rustc::session::config::{self, Input, ErrorOutputType}; use rustc::hir::{self, itemlikevisit}; -use rustc_trans_utils::trans_crate::TransCrate; +use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc::ty::TyCtxt; use syntax::ast; @@ -53,7 +53,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { } fn late_callback( &mut self, - trans: &TransCrate, + trans: &CodegenBackend, matches: &getopts::Matches, sess: &Session, cstore: &CrateStore, @@ -104,9 +104,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(tcx, state)); } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { let entry_def_id = tcx.hir.local_def_id(entry_node_id); - let start_wrapper = tcx.lang_items().start_fn().and_then(|start_fn| - if tcx.is_mir_available(start_fn) { Some(start_fn) } else { None }); - miri::eval_main(tcx, entry_def_id, start_wrapper); + miri::eval_main(tcx, entry_def_id, None); state.session.abort_if_errors(); } else { diff --git a/src/lib.rs b/src/lib.rs index a29211df996b..1ba763349aa7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -265,7 +265,6 @@ pub fn eval_main<'a, 'tcx: 'a>( } } } - ::std::process::exit(1); } } } From 574aa3bc42a02348ee8b7bd61fbea480f48c01d5 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 13 May 2018 13:14:26 +0200 Subject: [PATCH 0084/5092] Rustup to rustc 1.27.0-nightly (ff2ac35db 2018-05-12) --- src/fn_call.rs | 2 +- src/validation.rs | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 2b4e7b736628..272c27e40219 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -459,7 +459,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' promoted: None, }; let const_val = self.const_eval(cid)?; - let value = const_val.val.unwrap_u64(); + let value = const_val.unwrap_usize(self.tcx.tcx); if value == name { result = Some(path_value); break; diff --git a/src/validation.rs b/src/validation.rs index b274b4650157..deb1c5d5bc07 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -10,7 +10,7 @@ use rustc::infer::InferCtxt; use rustc::middle::region; use rustc::middle::const_val::ConstVal; use rustc_data_structures::indexed_vec::Idx; -use rustc_mir::interpret::{HasMemory, eval_body}; +use rustc_mir::interpret::HasMemory; use super::{EvalContext, Place, PlaceExtra, ValTy}; use rustc::mir::interpret::{DynamicLifetime, AccessKind, EvalErrorKind, Value, EvalError, EvalResult}; @@ -718,18 +718,17 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } } TyArray(elem_ty, len) => { - let len_val = match len.val { + let len = match len.val { ConstVal::Unevaluated(def_id, substs) => { - eval_body(self.tcx.tcx, GlobalId { + self.tcx.const_eval(self.tcx.param_env(def_id).and(GlobalId { instance: Instance::new(def_id, substs), promoted: None, - }, ty::ParamEnv::reveal_all()) - .ok_or_else(||EvalErrorKind::MachineError("".to_string()))? - .0 + })) + .map_err(|_err|EvalErrorKind::MachineError("".to_string()))? } - ConstVal::Value(val) => val, + ConstVal::Value(_) => len, }; - let len = ConstVal::Value(len_val).unwrap_u64(); + let len = len.unwrap_usize(self.tcx.tcx); for i in 0..len { let inner_place = self.place_index(query.place.1, query.ty, i as u64)?; self.validate( From c8ff634f828b62290a5ee9798687bca2ec300f71 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 13 May 2018 15:32:35 +0200 Subject: [PATCH 0085/5092] Enable backtraces for tests --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6a987f93748c..9aa632da05e0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,7 +27,7 @@ script: - | # Test plain miri cargo build --release --all-features && - cargo test --release --all-features --all && + RUST_BACKTRACE=1 cargo test --release --all-features --all && cargo install --all-features --force - | # Test cargo miri From b906ce84ec0635e2033b94415f6ad3ef938c7489 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 19 May 2018 12:14:13 +0200 Subject: [PATCH 0086/5092] Rustup to rustc 1.28.0-nightly (952f344cd 2018-05-18) --- src/bin/miri.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 4e0be7bd3204..5ae9626f01fb 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -5,7 +5,7 @@ extern crate miri; extern crate rustc; extern crate rustc_driver; extern crate rustc_errors; -extern crate rustc_trans_utils; +extern crate rustc_codegen_utils; extern crate env_logger; extern crate log_settings; extern crate syntax; @@ -18,7 +18,7 @@ use rustc_driver::driver::{CompileState, CompileController}; use rustc::session::config::{self, Input, ErrorOutputType}; use rustc::hir::{self, itemlikevisit}; use rustc::ty::TyCtxt; -use rustc_trans_utils::trans_crate::TransCrate; +use rustc_codegen_utils::codegen_backend::CodegenBackend; use syntax::ast; use std::path::PathBuf; @@ -67,7 +67,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { } fn late_callback( &mut self, - trans: &TransCrate, + trans: &CodegenBackend, matches: &getopts::Matches, sess: &Session, cstore: &CrateStore, From 601673d06fd2ddee44dfb437f56afeee36f0e96f Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sat, 19 May 2018 14:09:29 +0200 Subject: [PATCH 0087/5092] trans -> codegen_backend --- src/bin/miri.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 5ae9626f01fb..8d80135cde30 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -67,7 +67,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { } fn late_callback( &mut self, - trans: &CodegenBackend, + codegen_backend: &CodegenBackend, matches: &getopts::Matches, sess: &Session, cstore: &CrateStore, @@ -75,7 +75,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { odir: &Option, ofile: &Option, ) -> Compilation { - self.default.late_callback(trans, matches, sess, cstore, input, odir, ofile) + self.default.late_callback(codegen_backend, matches, sess, cstore, input, odir, ofile) } fn build_controller( &mut self, From 98802769a1d3df9b106ad89221679aef0e8aede1 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 20 May 2018 11:26:40 +0200 Subject: [PATCH 0088/5092] Rustup to rustc 1.28.0-nightly (a3085756e 2018-05-19) --- src/fn_call.rs | 34 +++++++++++++++++----------------- src/intrinsic.rs | 12 ++++++------ src/lib.rs | 16 ++++++++-------- src/locks.rs | 11 ++++++----- src/operator.rs | 10 +++++----- 5 files changed, 42 insertions(+), 41 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 272c27e40219..e7250eca949d 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -1,5 +1,5 @@ use rustc::ty::{self, Ty}; -use rustc::ty::layout::{self, Align, LayoutOf}; +use rustc::ty::layout::{self, Align, LayoutOf, Size}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc_data_structures::indexed_vec::Idx; @@ -187,7 +187,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.write_null(dest, dest_ty)?; } else { let align = self.tcx.data_layout.pointer_align; - let ptr = self.memory.allocate(size, align, Some(MemoryKind::C.into()))?; + let ptr = self.memory.allocate(Size::from_bytes(size), align, Some(MemoryKind::C.into()))?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } } @@ -281,7 +281,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memcmp" => { let left = self.into_ptr(args[0].value)?; let right = self.into_ptr(args[1].value)?; - let n = self.value_to_primval(args[2])?.to_u64()?; + let n = Size::from_bytes(self.value_to_primval(args[2])?.to_u64()?); let result = { let left_bytes = self.memory.read_bytes(left, n)?; @@ -306,11 +306,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let ptr = self.into_ptr(args[0].value)?; let val = self.value_to_primval(args[1])?.to_u64()? as u8; let num = self.value_to_primval(args[2])?.to_u64()?; - if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().rev().position( + if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().rev().position( |&c| c == val, ) { - let new_ptr = ptr.offset(num - idx as u64 - 1, &self)?; + let new_ptr = ptr.offset(Size::from_bytes(num - idx as u64 - 1), &self)?; self.write_ptr(dest, new_ptr, dest_ty)?; } else { self.write_null(dest, dest_ty)?; @@ -321,11 +321,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let ptr = self.into_ptr(args[0].value)?; let val = self.value_to_primval(args[1])?.to_u64()? as u8; let num = self.value_to_primval(args[2])?.to_u64()?; - if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().position( + if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().position( |&c| c == val, ) { - let new_ptr = ptr.offset(idx as u64, &self)?; + let new_ptr = ptr.offset(Size::from_bytes(idx as u64), &self)?; self.write_ptr(dest, new_ptr, dest_ty)?; } else { self.write_null(dest, dest_ty)?; @@ -381,12 +381,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' if let Some((name, value)) = new { // +1 for the null terminator let value_copy = self.memory.allocate( - (value.len() + 1) as u64, + Size::from_bytes((value.len() + 1) as u64), Align::from_bytes(1, 1).unwrap(), Some(MemoryKind::Env.into()), )?; self.memory.write_bytes(value_copy.into(), &value)?; - let trailing_zero_ptr = value_copy.offset(value.len() as u64, &self)?.into(); + let trailing_zero_ptr = value_copy.offset(Size::from_bytes(value.len() as u64), &self)?.into(); self.memory.write_bytes(trailing_zero_ptr, &[0])?; if let Some(var) = self.machine.env_vars.insert( name.to_owned(), @@ -410,7 +410,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // stdout/stderr use std::io::{self, Write}; - let buf_cont = self.memory.read_bytes(buf, n)?; + let buf_cont = self.memory.read_bytes(buf, Size::from_bytes(n))?; let res = if fd == 1 { io::stdout().write(buf_cont) } else { @@ -502,7 +502,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' key_ptr, key_align, PrimVal::Bytes(key), - key_size.bytes(), + key_size, false, )?; @@ -643,7 +643,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory.allocate(size, + let ptr = self.memory.allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), Some(MemoryKind::Rust.into()))?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; @@ -657,10 +657,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory.allocate(size, + let ptr = self.memory.allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), Some(MemoryKind::Rust.into()))?; - self.memory.write_repeat(ptr.into(), 0, size)?; + self.memory.write_repeat(ptr.into(), 0, Size::from_bytes(size))?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } "alloc::alloc::::__rust_dealloc" => { @@ -675,7 +675,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } self.memory.deallocate( ptr, - Some((old_size, Align::from_bytes(align, align).unwrap())), + Some((Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap())), MemoryKind::Rust.into(), )?; } @@ -692,9 +692,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } let new_ptr = self.memory.reallocate( ptr, - old_size, + Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap(), - new_size, + Size::from_bytes(new_size), Align::from_bytes(align, align).unwrap(), MemoryKind::Rust.into(), )?; diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 234d1ee78483..30de1c68ca61 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -1,5 +1,5 @@ use rustc::mir; -use rustc::ty::layout::{TyLayout, LayoutOf}; +use rustc::ty::layout::{TyLayout, LayoutOf, Size}; use rustc::ty; use rustc::mir::interpret::{EvalResult, PrimVal, PrimValKind, Value, Pointer}; @@ -35,7 +35,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // FIXME: return a real value in case the target allocation has an // alignment bigger than the one requested let n = u128::max_value(); - let amt = 128 - self.memory.pointer_size() * 8; + let amt = 128 - self.memory.pointer_size().bytes() * 8; self.write_primval(dest, PrimVal::Bytes((n << amt) >> amt), dest_layout.ty)?; }, @@ -225,7 +225,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: elem_align, dest, elem_align, - count * elem_size, + Size::from_bytes(count * elem_size), intrinsic_name.ends_with("_nonoverlapping"), )?; } @@ -332,7 +332,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "likely" | "unlikely" | "forget" => {} "init" => { - let size = dest_layout.size.bytes(); + let size = dest_layout.size; let init = |this: &mut Self, val: Value| { let zero_val = match val { Value::ByRef(ptr, _) => { @@ -631,7 +631,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "uninit" => { - let size = dest_layout.size.bytes(); + let size = dest_layout.size; let uninit = |this: &mut Self, val: Value| match val { Value::ByRef(ptr, _) => { this.memory.mark_definedness(ptr, size, false)?; @@ -662,7 +662,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // HashMap relies on write_bytes on a NULL ptr with count == 0 to work // TODO: Should we, at least, validate the alignment? (Also see the copy intrinsic) self.memory.check_align(ptr, ty_layout.align)?; - self.memory.write_repeat(ptr, val_byte, ty_layout.size.bytes() * count)?; + self.memory.write_repeat(ptr, val_byte, ty_layout.size * count)?; } } diff --git a/src/lib.rs b/src/lib.rs index dce31c4ed338..66ad6377e327 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,7 @@ extern crate regex; extern crate lazy_static; use rustc::ty::{self, TyCtxt}; -use rustc::ty::layout::{TyLayout, LayoutOf}; +use rustc::ty::layout::{TyLayout, LayoutOf, Size}; use rustc::ty::subst::Subst; use rustc::hir::def_id::DefId; use rustc::mir; @@ -93,7 +93,7 @@ pub fn eval_main<'a, 'tcx: 'a>( } // Return value - let size = ecx.tcx.data_layout.pointer_size.bytes(); + let size = ecx.tcx.data_layout.pointer_size; let align = ecx.tcx.data_layout.pointer_align; let ret_ptr = ecx.memory_mut().allocate(size, align, Some(MemoryKind::Stack))?; cleanup_ptr = Some(ret_ptr); @@ -299,7 +299,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; assert!(!layout.is_unsized()); let ptr = ecx.memory.allocate( - layout.size.bytes(), + layout.size, layout.align, None, )?; @@ -373,8 +373,8 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx.write_value( ValTy { value: Value::ByVal(PrimVal::Bytes(match layout.size.bytes() { - 0 => 1, - size => size, + 0 => 1 as u128, + size => size as u128, }.into())), ty: usize, }, @@ -407,10 +407,10 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn check_locks<'a>( mem: &Memory<'a, 'mir, 'tcx, Self>, ptr: MemoryPointer, - size: u64, + size: Size, access: AccessKind, ) -> EvalResult<'tcx> { - mem.check_locks(ptr, size, access) + mem.check_locks(ptr, size.bytes(), access) } fn add_lock<'a>( @@ -439,7 +439,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { //ptr, FIXME ptr: MemoryPointer { alloc_id: AllocId(0), - offset: 0, + offset: Size::from_bytes(0), }, lock: lock.active, }.into() diff --git a/src/locks.rs b/src/locks.rs index 677b0454a546..9efbabc7171b 100644 --- a/src/locks.rs +++ b/src/locks.rs @@ -1,5 +1,6 @@ use super::*; use rustc::middle::region; +use rustc::ty::layout::Size; //////////////////////////////////////////////////////////////////////////////// // Locks @@ -116,7 +117,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu }; let frame = self.cur_frame; locks - .check(Some(frame), ptr.offset, len, access) + .check(Some(frame), ptr.offset.bytes(), len, access) .map_err(|lock| { EvalErrorKind::MemoryLockViolation { ptr, @@ -146,7 +147,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu len, region ); - self.check_bounds(ptr.offset(len, &*self)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow) + self.check_bounds(ptr.offset(Size::from_bytes(len), &*self)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow) let locks = match self.data.locks.get_mut(&ptr.alloc_id) { Some(locks) => locks, @@ -157,7 +158,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu // Iterate over our range and acquire the lock. If the range is already split into pieces, // we have to manipulate all of them. let lifetime = DynamicLifetime { frame, region }; - for lock in locks.iter_mut(ptr.offset, len) { + for lock in locks.iter_mut(ptr.offset.bytes(), len) { if !lock.access_permitted(None, kind) { return err!(MemoryAcquireConflict { ptr, @@ -203,7 +204,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu None => return Ok(()), }; - 'locks: for lock in locks.iter_mut(ptr.offset, len) { + 'locks: for lock in locks.iter_mut(ptr.offset.bytes(), len) { let is_our_lock = match lock.active { WriteLock(lft) => // Double-check that we are holding the lock. @@ -281,7 +282,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu None => return Ok(()), }; - for lock in locks.iter_mut(ptr.offset, len) { + for lock in locks.iter_mut(ptr.offset.bytes(), len) { // Check if we have a suspension here let (got_the_lock, remove_suspension) = match lock.suspended.get_mut(&lock_id) { None => { diff --git a/src/operator.rs b/src/operator.rs index 220f8f9acd54..557e07975d73 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -89,9 +89,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Sub => { return self.binary_op( Sub, - PrimVal::Bytes(left.offset as u128), + PrimVal::Bytes(left.offset.bytes() as u128), self.tcx.types.usize, - PrimVal::Bytes(right.offset as u128), + PrimVal::Bytes(right.offset.bytes() as u128), self.tcx.types.usize, ).map(Some) } @@ -150,17 +150,17 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Add if signed => map_to_primval(left.overflowing_signed_offset(right, self)), Add if !signed => - map_to_primval(left.overflowing_offset(right as u64, self)), + map_to_primval(left.overflowing_offset(Size::from_bytes(right as u64), self)), BitAnd if !signed => { let base_mask : u64 = !(self.memory.get(left.alloc_id)?.align.abi() - 1); let right = right as u64; if right & base_mask == base_mask { // Case 1: The base address bits are all preserved, i.e., right is all-1 there - (PrimVal::Ptr(MemoryPointer::new(left.alloc_id, left.offset & right)), false) + (PrimVal::Ptr(MemoryPointer::new(left.alloc_id, Size::from_bytes(left.offset.bytes() & right))), false) } else if right & base_mask == 0 { // Case 2: The base address bits are all taken away, i.e., right is all-0 there - (PrimVal::from_u128((left.offset & right) as u128), false) + (PrimVal::from_u128((left.offset.bytes() & right) as u128), false) } else { return err!(ReadPointerAsBytes); } From 1437a975d64b0e04f807abfbca78deb4c93f928e Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Fri, 25 May 2018 14:37:12 +0200 Subject: [PATCH 0089/5092] s/allocate_cached/allocate_bytes --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 66ad6377e327..f8119245b484 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -131,7 +131,7 @@ pub fn eval_main<'a, 'tcx: 'a>( // Third argument (argv): &[b"foo"] let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let ty = ecx.tcx.mk_imm_ptr(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8)); - let foo = ecx.memory.allocate_cached(b"foo\0"); + let foo = ecx.memory.allocate_bytes(b"foo\0"); let ptr_size = ecx.memory.pointer_size(); let ptr_align = ecx.tcx.data_layout.pointer_align; let foo_ptr = ecx.memory.allocate(ptr_size, ptr_align, None)?; From 4143922d1d613154ad2c3369b3e2c6a6fd4ef35e Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 26 May 2018 17:07:34 +0200 Subject: [PATCH 0090/5092] Partial rustup --- benches/helpers/miri_helper.rs | 9 +- src/fn_call.rs | 114 +++++++++--------- src/helpers.rs | 34 +++--- src/intrinsic.rs | 206 +++++++++++++++++---------------- src/lib.rs | 104 ++++++++++++++--- src/locks.rs | 16 +-- src/operator.rs | 101 +++++++++------- src/tls.rs | 24 ++-- src/validation.rs | 6 +- 9 files changed, 358 insertions(+), 256 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 6657ba119976..2bf78b0a71cc 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -55,16 +55,13 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls<'a> { state.session.abort_if_errors(); let tcx = state.tcx.unwrap(); - let (entry_node_id, _) = state.session.entry_fn.borrow().expect( + let (entry_node_id, _, _) = state.session.entry_fn.borrow().expect( "no main or start function found", ); - let entry_def_id = tcx.map.local_def_id(entry_node_id); + let entry_def_id = tcx.hir.local_def_id(entry_node_id); - let memory_size = 100 * 1024 * 1024; // 100MB - let step_limit = 1000_000; - let stack_limit = 100; bencher.borrow_mut().iter(|| { - eval_main(tcx, entry_def_id, memory_size, step_limit, stack_limit); + eval_main(tcx, entry_def_id, None); }); state.session.abort_if_errors(); diff --git a/src/fn_call.rs b/src/fn_call.rs index e7250eca949d..ea0c5eb8b26e 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -38,7 +38,7 @@ fn write_discriminant_value<'a, 'mir, 'tcx: 'a + 'mir>( .val; let (discr_dest, discr) = ecx.place_field(dest, mir::Field::new(0), layout)?; - ecx.write_primval(discr_dest, PrimVal::Bytes(discr_val), discr.ty)?; + ecx.write_scalar(discr_dest, Scalar::from_u128(discr_val), discr.ty)?; } layout::Variants::NicheFilling { dataful_variant, @@ -51,7 +51,7 @@ fn write_discriminant_value<'a, 'mir, 'tcx: 'a + 'mir>( ecx.place_field(dest, mir::Field::new(0), layout)?; let niche_value = ((variant_index - niche_variants.start()) as u128) .wrapping_add(niche_start); - ecx.write_primval(niche_dest, PrimVal::Bytes(niche_value), niche.ty)?; + ecx.write_scalar(niche_dest, Scalar::from_u128(niche_value), niche.ty)?; } } } @@ -182,13 +182,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match &link_name[..] { "malloc" => { - let size = self.value_to_primval(args[0])?.to_u64()?; + let size = self.value_to_scalar(args[0])?.to_u64()?; if size == 0 { self.write_null(dest, dest_ty)?; } else { let align = self.tcx.data_layout.pointer_align; let ptr = self.memory.allocate(Size::from_bytes(size), align, Some(MemoryKind::C.into()))?; - self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; + self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; } } @@ -209,7 +209,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // // libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK) // is called if a `HashMap` is created the regular way. - match self.value_to_primval(args[0])?.to_u64()? { + match self.value_to_scalar(args[0])?.to_u64()? { 318 | 511 => { return err!(Unimplemented( "miri does not support random number generators".to_owned(), @@ -281,7 +281,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memcmp" => { let left = self.into_ptr(args[0].value)?; let right = self.into_ptr(args[1].value)?; - let n = Size::from_bytes(self.value_to_primval(args[2])?.to_u64()?); + let n = Size::from_bytes(self.value_to_scalar(args[2])?.to_u64()?); let result = { let left_bytes = self.memory.read_bytes(left, n)?; @@ -295,22 +295,22 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } }; - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes(result as u128), + Scalar::from_i8(result), dest_ty, )?; } "memrchr" => { let ptr = self.into_ptr(args[0].value)?; - let val = self.value_to_primval(args[1])?.to_u64()? as u8; - let num = self.value_to_primval(args[2])?.to_u64()?; + let val = self.value_to_scalar(args[1])?.to_u64()? as u8; + let num = self.value_to_scalar(args[2])?.to_u64()?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().rev().position( |&c| c == val, ) { - let new_ptr = ptr.offset(Size::from_bytes(num - idx as u64 - 1), &self)?; + let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), &self)?; self.write_ptr(dest, new_ptr, dest_ty)?; } else { self.write_null(dest, dest_ty)?; @@ -319,13 +319,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memchr" => { let ptr = self.into_ptr(args[0].value)?; - let val = self.value_to_primval(args[1])?.to_u64()? as u8; - let num = self.value_to_primval(args[2])?.to_u64()?; + let val = self.value_to_scalar(args[1])?.to_u64()? as u8; + let num = self.value_to_scalar(args[2])?.to_u64()?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().position( |&c| c == val, ) { - let new_ptr = ptr.offset(Size::from_bytes(idx as u64), &self)?; + let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), &self)?; self.write_ptr(dest, new_ptr, dest_ty)?; } else { self.write_null(dest, dest_ty)?; @@ -337,11 +337,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let name_ptr = self.into_ptr(args[0].value)?.to_ptr()?; let name = self.memory.read_c_str(name_ptr)?; match self.machine.env_vars.get(name) { - Some(&var) => PrimVal::Ptr(var), - None => PrimVal::Bytes(0), + Some(&var) => Scalar::Ptr(var), + None => Scalar::null(), } }; - self.write_primval(dest, result, dest_ty)?; + self.write_scalar(dest, result, dest_ty)?; } "unsetenv" => { @@ -361,7 +361,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } self.write_null(dest, dest_ty)?; } else { - self.write_primval(dest, PrimVal::from_i128(-1), dest_ty)?; + self.write_scalar(dest, Scalar::from_i128(-1), dest_ty)?; } } @@ -397,14 +397,14 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } self.write_null(dest, dest_ty)?; } else { - self.write_primval(dest, PrimVal::from_i128(-1), dest_ty)?; + self.write_scalar(dest, Scalar::from_i128(-1), dest_ty)?; } } "write" => { - let fd = self.value_to_primval(args[0])?.to_u64()?; + let fd = self.value_to_scalar(args[0])?.to_u64()?; let buf = self.into_ptr(args[1].value)?; - let n = self.value_to_primval(args[2])?.to_u64()?; + let n = self.value_to_scalar(args[2])?.to_u64()?; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { // stdout/stderr @@ -417,16 +417,17 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' io::stderr().write(buf_cont) }; match res { - Ok(n) => n as isize, + Ok(n) => n as i64, Err(_) => -1, } } else { warn!("Ignored output to FD {}", fd); - n as isize // pretend it all went well + n as i64 // pretend it all went well }; // now result is the value we return back to the program - self.write_primval( + let ptr_size = self.memory.pointer_size(); + self.write_scalar( dest, - PrimVal::Bytes(result as u128), + Scalar::from_isize(result, ptr_size), dest_ty, )?; } @@ -434,22 +435,23 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "strlen" => { let ptr = self.into_ptr(args[0].value)?.to_ptr()?; let n = self.memory.read_c_str(ptr)?.len(); - self.write_primval(dest, PrimVal::Bytes(n as u128), dest_ty)?; + let ptr_size = self.memory.pointer_size(); + self.write_scalar(dest, Scalar::from_usize(n as u64, ptr_size), dest_ty)?; } // Some things needed for sys::thread initialization to go through "signal" | "sigaction" | "sigaltstack" => { - self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?; + self.write_scalar(dest, Scalar::null(), dest_ty)?; } "sysconf" => { - let name = self.value_to_primval(args[0])?.to_u64()?; + let name = self.value_to_scalar(args[0])?.to_u64()?; trace!("sysconf() called with name {}", name); // cache the sysconf integers via miri's global cache let paths = &[ - (&["libc", "_SC_PAGESIZE"], PrimVal::Bytes(4096)), - (&["libc", "_SC_GETPW_R_SIZE_MAX"], PrimVal::from_i128(-1)), + (&["libc", "_SC_PAGESIZE"], Scalar::from_i128(4096)), + (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_i128(-1)), ]; let mut result = None; for &(path, path_value) in paths { @@ -467,7 +469,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } } if let Some(result) = result { - self.write_primval(dest, result, dest_ty)?; + self.write_scalar(dest, result, dest_ty)?; } else { return err!(Unimplemented( format!("Unimplemented sysconf name: {}", name), @@ -481,11 +483,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let key_align = self.layout_of(args[0].ty)?.align; // Extract the function type out of the signature (that seems easier than constructing it ourselves...) - let dtor = match self.into_ptr(args[1].value)?.into_inner_primval() { - PrimVal::Ptr(dtor_ptr) => Some(self.memory.get_fn(dtor_ptr)?), - PrimVal::Bytes(0) => None, - PrimVal::Bytes(_) => return err!(ReadBytesAsPointer), - PrimVal::Undef => return err!(ReadUndefBytes), + let dtor = match self.into_ptr(args[1].value)? { + Scalar::Ptr(dtor_ptr) => Some(self.memory.get_fn(dtor_ptr)?), + Scalar::Bits { defined: 0, .. } => return err!(ReadUndefBytes), + Scalar::Bits { bits: 0, .. } => None, + Scalar::Bits { .. } => return err!(ReadBytesAsPointer), }; // Figure out how large a pthread TLS key actually is. This is libc::pthread_key_t. @@ -498,10 +500,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' if key_size.bits() < 128 && key >= (1u128 << key_size.bits() as u128) { return err!(OutOfTls); } - self.memory.write_primval( + self.memory.write_scalar( key_ptr, key_align, - PrimVal::Bytes(key), + Scalar::from_u128(key), key_size, false, )?; @@ -511,20 +513,20 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "pthread_key_delete" => { // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t - let key = self.value_to_primval(args[0])?.to_u64()? as TlsKey; + let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey; self.memory.delete_tls_key(key)?; // Return success (0) self.write_null(dest, dest_ty)?; } "pthread_getspecific" => { // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t - let key = self.value_to_primval(args[0])?.to_u64()? as TlsKey; + let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey; let ptr = self.memory.load_tls(key)?; self.write_ptr(dest, ptr, dest_ty)?; } "pthread_setspecific" => { // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t - let key = self.value_to_primval(args[0])?.to_u64()? as TlsKey; + let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey; let new_ptr = self.into_ptr(args[1].value)?; self.memory.store_tls(key, new_ptr)?; @@ -635,8 +637,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match &path[..] { // Allocators are magic. They have no MIR, even when the rest of libstd does. "alloc::alloc::::__rust_alloc" => { - let size = self.value_to_primval(args[0])?.to_u64()?; - let align = self.value_to_primval(args[1])?.to_u64()?; + let size = self.value_to_scalar(args[0])?.to_u64()?; + let align = self.value_to_scalar(args[1])?.to_u64()?; if size == 0 { return err!(HeapAllocZeroBytes); } @@ -646,11 +648,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let ptr = self.memory.allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), Some(MemoryKind::Rust.into()))?; - self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; + self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; } "alloc::alloc::::__rust_alloc_zeroed" => { - let size = self.value_to_primval(args[0])?.to_u64()?; - let align = self.value_to_primval(args[1])?.to_u64()?; + let size = self.value_to_scalar(args[0])?.to_u64()?; + let align = self.value_to_scalar(args[1])?.to_u64()?; if size == 0 { return err!(HeapAllocZeroBytes); } @@ -661,12 +663,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Align::from_bytes(align, align).unwrap(), Some(MemoryKind::Rust.into()))?; self.memory.write_repeat(ptr.into(), 0, Size::from_bytes(size))?; - self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; + self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; } "alloc::alloc::::__rust_dealloc" => { let ptr = self.into_ptr(args[0].value)?.to_ptr()?; - let old_size = self.value_to_primval(args[1])?.to_u64()?; - let align = self.value_to_primval(args[2])?.to_u64()?; + let old_size = self.value_to_scalar(args[1])?.to_u64()?; + let align = self.value_to_scalar(args[2])?.to_u64()?; if old_size == 0 { return err!(HeapAllocZeroBytes); } @@ -681,9 +683,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "alloc::alloc::::__rust_realloc" => { let ptr = self.into_ptr(args[0].value)?.to_ptr()?; - let old_size = self.value_to_primval(args[1])?.to_u64()?; - let align = self.value_to_primval(args[2])?.to_u64()?; - let new_size = self.value_to_primval(args[3])?.to_u64()?; + let old_size = self.value_to_scalar(args[1])?.to_u64()?; + let align = self.value_to_scalar(args[2])?.to_u64()?; + let new_size = self.value_to_scalar(args[3])?.to_u64()?; if old_size == 0 || new_size == 0 { return err!(HeapAllocZeroBytes); } @@ -698,7 +700,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Align::from_bytes(align, align).unwrap(), MemoryKind::Rust.into(), )?; - self.write_primval(dest, PrimVal::Ptr(new_ptr), dest_ty)?; + self.write_scalar(dest, Scalar::Ptr(new_ptr), dest_ty)?; } // A Rust function is missing, which means we are running with MIR missing for libstd (or other dependencies). @@ -720,13 +722,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "std::rt::panicking" => { // we abort on panic -> `std::rt::panicking` always returns false let bool = self.tcx.types.bool; - self.write_primval(dest, PrimVal::from_bool(false), bool)?; + self.write_scalar(dest, Scalar::from_bool(false), bool)?; } "std::sys::imp::c::::AddVectoredExceptionHandler" | "std::sys::imp::c::::SetThreadStackGuarantee" => { let usize = self.tcx.types.usize; // any non zero value works for the stdlib. This is just used for stackoverflows anyway - self.write_primval(dest, PrimVal::Bytes(1), usize)?; + self.write_scalar(dest, Scalar::from_u128(1), usize)?; }, _ => return err!(NoMirFor(path)), } @@ -740,6 +742,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } fn write_null(&mut self, dest: Place, dest_ty: Ty<'tcx>) -> EvalResult<'tcx> { - self.write_primval(dest, PrimVal::Bytes(0), dest_ty) + self.write_scalar(dest, Scalar::null(), dest_ty) } } diff --git a/src/helpers.rs b/src/helpers.rs index a7b94a656da4..d881d5c27110 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,24 +1,24 @@ use mir; use rustc::ty::Ty; -use rustc::ty::layout::LayoutOf; +use rustc::ty::layout::{LayoutOf, Size}; -use super::{Pointer, EvalResult, PrimVal, EvalContext, ValTy}; +use super::{Scalar, ScalarExt, EvalResult, EvalContext, ValTy}; use rustc_mir::interpret::sign_extend; pub trait EvalContextExt<'tcx> { fn wrapping_pointer_offset( &self, - ptr: Pointer, + ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Pointer>; + ) -> EvalResult<'tcx, Scalar>; fn pointer_offset( &self, - ptr: Pointer, + ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Pointer>; + ) -> EvalResult<'tcx, Scalar>; fn value_to_isize( &self, @@ -44,22 +44,22 @@ pub trait EvalContextExt<'tcx> { impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { fn wrapping_pointer_offset( &self, - ptr: Pointer, + ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Pointer> { + ) -> EvalResult<'tcx, Scalar> { // FIXME: assuming here that type size is < i64::max_value() let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; let offset = offset.overflowing_mul(pointee_size).0; - ptr.wrapping_signed_offset(offset, self) + ptr.ptr_wrapping_signed_offset(offset, self) } fn pointer_offset( &self, - ptr: Pointer, + ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Pointer> { + ) -> EvalResult<'tcx, Scalar> { // This function raises an error if the offset moves the pointer outside of its allocation. We consider // ZSTs their own huge allocation that doesn't overlap with anything (and nothing moves in there because the size is 0). // We also consider the NULL pointer its own separate allocation, and all the remaining integers pointers their own @@ -76,9 +76,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // FIXME: assuming here that type size is < i64::max_value() let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; return if let Some(offset) = offset.checked_mul(pointee_size) { - let ptr = ptr.signed_offset(offset, self)?; + let ptr = ptr.ptr_signed_offset(offset, self)?; // Do not do bounds-checking for integers; they can never alias a normal pointer anyway. - if let PrimVal::Ptr(ptr) = ptr.into_inner_primval() { + if let Scalar::Ptr(ptr) = ptr { self.memory.check_bounds(ptr, false)?; } else if ptr.is_null()? { // We moved *to* a NULL pointer. That seems wrong, LLVM considers the NULL pointer its own small allocation. Reject this, for now. @@ -95,7 +95,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: value: ValTy<'tcx>, ) -> EvalResult<'tcx, i64> { assert_eq!(value.ty, self.tcx.types.isize); - let raw = self.value_to_primval(value)?.to_bytes()?; + let raw = self.value_to_scalar(value)?.to_bits(self.memory.pointer_size())?; let raw = sign_extend(self.tcx.tcx, raw, self.tcx.types.isize)?; Ok(raw as i64) } @@ -105,7 +105,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: value: ValTy<'tcx>, ) -> EvalResult<'tcx, u64> { assert_eq!(value.ty, self.tcx.types.usize); - self.value_to_primval(value)?.to_bytes().map(|v| v as u64) + self.value_to_scalar(value)?.to_bits(self.memory.pointer_size()).map(|v| v as u64) } fn value_to_i32( @@ -113,7 +113,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: value: ValTy<'tcx>, ) -> EvalResult<'tcx, i32> { assert_eq!(value.ty, self.tcx.types.i32); - let raw = self.value_to_primval(value)?.to_bytes()?; + let raw = self.value_to_scalar(value)?.to_bits(Size::from_bits(32))?; let raw = sign_extend(self.tcx.tcx, raw, self.tcx.types.i32)?; Ok(raw as i32) } @@ -123,6 +123,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: value: ValTy<'tcx>, ) -> EvalResult<'tcx, u8> { assert_eq!(value.ty, self.tcx.types.u8); - self.value_to_primval(value)?.to_bytes().map(|v| v as u8) + self.value_to_scalar(value)?.to_bits(Size::from_bits(8)).map(|v| v as u8) } } diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 30de1c68ca61..3d537ea629c3 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -1,12 +1,14 @@ use rustc::mir; -use rustc::ty::layout::{TyLayout, LayoutOf, Size}; +use rustc::ty::layout::{TyLayout, LayoutOf, Size, Primitive, Integer::*}; use rustc::ty; -use rustc::mir::interpret::{EvalResult, PrimVal, PrimValKind, Value, Pointer}; +use rustc::mir::interpret::{EvalResult, Scalar, Value}; use rustc_mir::interpret::{Place, PlaceExtra, HasMemory, EvalContext, ValTy}; use helpers::EvalContextExt as HelperEvalContextExt; +use super::ScalarExt; + pub trait EvalContextExt<'tcx> { fn call_intrinsic( &mut self, @@ -36,7 +38,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // alignment bigger than the one requested let n = u128::max_value(); let amt = 128 - self.memory.pointer_size().bytes() * 8; - self.write_primval(dest, PrimVal::Bytes((n << amt) >> amt), dest_layout.ty)?; + self.write_scalar(dest, Scalar::from_u128((n << amt) >> amt), dest_layout.ty)?; }, "add_with_overflow" => { @@ -77,7 +79,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "assume" => { - let cond = self.value_to_primval(args[0])?.to_bool()?; + let cond = self.value_to_scalar(args[0])?.to_bool()?; if !cond { return err!(AssumptionNotHeld); } @@ -115,16 +117,16 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ty = substs.type_at(0); let align = self.layout_of(ty)?.align; let ptr = self.into_ptr(args[0].value)?; - let change = self.value_to_primval(args[1])?; + let change = self.value_to_scalar(args[1])?; let old = self.read_value(ptr, align, ty)?; let old = match old { - Value::ByVal(val) => val, + Value::Scalar(val) => val, Value::ByRef { .. } => bug!("just read the value, can't be byref"), - Value::ByValPair(..) => bug!("atomic_xchg doesn't work with nonprimitives"), + Value::ScalarPair(..) => bug!("atomic_xchg doesn't work with nonprimitives"), }; - self.write_primval(dest, old, ty)?; - self.write_primval( - Place::from_primval_ptr(ptr, align), + self.write_scalar(dest, old, ty)?; + self.write_scalar( + Place::from_scalar_ptr(ptr, align), change, ty, )?; @@ -134,22 +136,22 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ty = substs.type_at(0); let align = self.layout_of(ty)?.align; let ptr = self.into_ptr(args[0].value)?; - let expect_old = self.value_to_primval(args[1])?; - let change = self.value_to_primval(args[2])?; + let expect_old = self.value_to_scalar(args[1])?; + let change = self.value_to_scalar(args[2])?; let old = self.read_value(ptr, align, ty)?; let old = match old { - Value::ByVal(val) => val, + Value::Scalar(val) => val, Value::ByRef { .. } => bug!("just read the value, can't be byref"), - Value::ByValPair(..) => bug!("atomic_cxchg doesn't work with nonprimitives"), + Value::ScalarPair(..) => bug!("atomic_cxchg doesn't work with nonprimitives"), }; let (val, _) = self.binary_op(mir::BinOp::Eq, old, ty, expect_old, ty)?; let valty = ValTy { - value: Value::ByValPair(old, val), + value: Value::ScalarPair(old, val), ty: dest_layout.ty, }; self.write_value(valty, dest)?; - self.write_primval( - Place::from_primval_ptr(ptr, dest_layout.align), + self.write_scalar( + Place::from_scalar_ptr(ptr, dest_layout.align), change, ty, )?; @@ -183,16 +185,16 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ty = substs.type_at(0); let align = self.layout_of(ty)?.align; let ptr = self.into_ptr(args[0].value)?; - let change = self.value_to_primval(args[1])?; + let change = self.value_to_scalar(args[1])?; let old = self.read_value(ptr, align, ty)?; let old = match old { - Value::ByVal(val) => val, + Value::Scalar(val) => val, Value::ByRef { .. } => bug!("just read the value, can't be byref"), - Value::ByValPair(..) => { + Value::ScalarPair(..) => { bug!("atomic_xadd_relaxed doesn't work with nonprimitives") } }; - self.write_primval(dest, old, ty)?; + self.write_scalar(dest, old, ty)?; let op = match intrinsic_name.split('_').nth(1).unwrap() { "or" => mir::BinOp::BitOr, "xor" => mir::BinOp::BitXor, @@ -203,7 +205,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: }; // FIXME: what do atomics do on overflow? let (val, _) = self.binary_op(op, old, ty, change, ty)?; - self.write_primval(Place::from_primval_ptr(ptr, dest_layout.align), val, ty)?; + self.write_scalar(Place::from_scalar_ptr(ptr, dest_layout.align), val, ty)?; } "breakpoint" => unimplemented!(), // halt miri @@ -233,8 +235,11 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "ctpop" | "cttz" | "cttz_nonzero" | "ctlz" | "ctlz_nonzero" | "bswap" => { let ty = substs.type_at(0); - let num = self.value_to_primval(args[0])?.to_bytes()?; - let kind = self.ty_to_primval_kind(ty)?; + let num = self.value_to_scalar(args[0])?.to_bytes()?; + let kind = match self.layout_of(ty)?.abi { + ty::layout::Abi::Scalar(ref scalar) => scalar.value, + _ => Err(::rustc::mir::interpret::EvalErrorKind::TypeNotPrimitive(ty))?, + }; let num = if intrinsic_name.ends_with("_nonzero") { if num == 0 { return err!(Intrinsic(format!("{} called on 0", intrinsic_name))); @@ -243,21 +248,21 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } else { numeric_intrinsic(intrinsic_name, num, kind)? }; - self.write_primval(dest, num, ty)?; + self.write_scalar(dest, num, ty)?; } "discriminant_value" => { let ty = substs.type_at(0); let adt_ptr = self.into_ptr(args[0].value)?; let adt_align = self.layout_of(args[0].ty)?.align; - let place = Place::from_primval_ptr(adt_ptr, adt_align); + let place = Place::from_scalar_ptr(adt_ptr, adt_align); let discr_val = self.read_discriminant_value(place, ty)?; - self.write_primval(dest, PrimVal::Bytes(discr_val), dest_layout.ty)?; + self.write_scalar(dest, Scalar::from_u128(discr_val), dest_layout.ty)?; } "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bytes()?; let f = f32::from_bits(f as u32); let f = match intrinsic_name { "sinf32" => f.sin(), @@ -274,12 +279,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "truncf32" => f.trunc(), _ => bug!(), }; - self.write_primval(dest, PrimVal::Bytes(f.to_bits() as u128), dest_layout.ty)?; + self.write_scalar(dest, Scalar::from_f32(f), dest_layout.ty)?; } "sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" | "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bytes()?; let f = f64::from_bits(f as u64); let f = match intrinsic_name { "sinf64" => f.sin(), @@ -296,13 +301,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "truncf64" => f.trunc(), _ => bug!(), }; - self.write_primval(dest, PrimVal::Bytes(f.to_bits() as u128), dest_layout.ty)?; + self.write_scalar(dest, Scalar::from_f64(f), dest_layout.ty)?; } "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { let ty = substs.type_at(0); - let a = self.value_to_primval(args[0])?; - let b = self.value_to_primval(args[1])?; + let a = self.value_to_scalar(args[0])?; + let b = self.value_to_scalar(args[1])?; let op = match intrinsic_name { "fadd_fast" => mir::BinOp::Add, "fsub_fast" => mir::BinOp::Sub, @@ -312,21 +317,21 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: _ => bug!(), }; let result = self.binary_op(op, a, ty, b, ty)?; - self.write_primval(dest, result.0, dest_layout.ty)?; + self.write_scalar(dest, result.0, dest_layout.ty)?; } "exact_div" => { // Performs an exact division, resulting in undefined behavior where // `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1` let ty = substs.type_at(0); - let a = self.value_to_primval(args[0])?; - let b = self.value_to_primval(args[1])?; + let a = self.value_to_scalar(args[0])?; + let b = self.value_to_scalar(args[1])?; // check x % y != 0 - if self.binary_op(mir::BinOp::Rem, a, ty, b, ty)?.0 != PrimVal::Bytes(0) { + if self.binary_op(mir::BinOp::Rem, a, ty, b, ty)?.0 != Scalar::null() { return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b))); } let result = self.binary_op(mir::BinOp::Div, a, ty, b, ty)?; - self.write_primval(dest, result.0, dest_layout.ty)?; + self.write_scalar(dest, result.0, dest_layout.ty)?; }, "likely" | "unlikely" | "forget" => {} @@ -341,21 +346,21 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: val } // TODO(solson): Revisit this, it's fishy to check for Undef here. - Value::ByVal(PrimVal::Undef) => { - match this.ty_to_primval_kind(dest_layout.ty) { - Ok(_) => Value::ByVal(PrimVal::Bytes(0)), - Err(_) => { + Value::Scalar(Scalar::Bits { defined: 0, .. }) => { + match this.layout_of(dest_layout.ty)?.abi { + ty::layout::Abi::Scalar(_) => Value::Scalar(Scalar::null()), + _ => { // FIXME(oli-obk): pass TyLayout to alloc_ptr instead of Ty let ptr = this.alloc_ptr(dest_layout.ty)?; - let ptr = Pointer::from(PrimVal::Ptr(ptr)); + let ptr = Scalar::Ptr(ptr); this.memory.write_repeat(ptr, 0, size)?; Value::ByRef(ptr, dest_layout.align) } } } - Value::ByVal(_) => Value::ByVal(PrimVal::Bytes(0)), - Value::ByValPair(..) => { - Value::ByValPair(PrimVal::Bytes(0), PrimVal::Bytes(0)) + Value::Scalar(_) => Value::Scalar(Scalar::null()), + Value::ScalarPair(..) => { + Value::ScalarPair(Scalar::null(), Scalar::null()) } }; Ok(zero_val) @@ -376,16 +381,16 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "min_align_of" => { let elem_ty = substs.type_at(0); let elem_align = self.layout_of(elem_ty)?.align.abi(); - let align_val = PrimVal::from_u128(elem_align as u128); - self.write_primval(dest, align_val, dest_layout.ty)?; + let align_val = Scalar::from_u128(elem_align as u128); + self.write_scalar(dest, align_val, dest_layout.ty)?; } "pref_align_of" => { let ty = substs.type_at(0); let layout = self.layout_of(ty)?; let align = layout.align.pref(); - let align_val = PrimVal::from_u128(align as u128); - self.write_primval(dest, align_val, dest_layout.ty)?; + let align_val = Scalar::from_u128(align as u128); + self.write_scalar(dest, align_val, dest_layout.ty)?; } "move_val_init" => { @@ -399,9 +404,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ty = substs.type_at(0); let env = ty::ParamEnv::reveal_all(); let needs_drop = ty.needs_drop(self.tcx.tcx, env); - self.write_primval( + self.write_scalar( dest, - PrimVal::from_bool(needs_drop), + Scalar::from_bool(needs_drop), dest_layout.ty, )?; } @@ -444,75 +449,75 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "powf32" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(32))?; let f = f32::from_bits(f as u32); - let f2 = self.value_to_primval(args[1])?.to_bytes()?; + let f2 = self.value_to_scalar(args[1])?.to_bits(Size::from_bits(32))?; let f2 = f32::from_bits(f2 as u32); - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes(f.powf(f2).to_bits() as u128), + Scalar::from_f32(f.powf(f2)), dest_layout.ty, )?; } "powf64" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(64))?; let f = f64::from_bits(f as u64); - let f2 = self.value_to_primval(args[1])?.to_bytes()?; + let f2 = self.value_to_scalar(args[1])?.to_bits(Size::from_bits(64))?; let f2 = f64::from_bits(f2 as u64); - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes(f.powf(f2).to_bits() as u128), + Scalar::from_f64(f.powf(f2)), dest_layout.ty, )?; } "fmaf32" => { - let a = self.value_to_primval(args[0])?.to_bytes()?; + let a = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(32))?; let a = f32::from_bits(a as u32); - let b = self.value_to_primval(args[1])?.to_bytes()?; + let b = self.value_to_scalar(args[1])?.to_bits(Size::from_bits(32))?; let b = f32::from_bits(b as u32); - let c = self.value_to_primval(args[2])?.to_bytes()?; + let c = self.value_to_scalar(args[2])?.to_bits(Size::from_bits(32))?; let c = f32::from_bits(c as u32); - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes((a * b + c).to_bits() as u128), + Scalar::from_f32(a * b + c), dest_layout.ty, )?; } "fmaf64" => { - let a = self.value_to_primval(args[0])?.to_bytes()?; + let a = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(64))?; let a = f64::from_bits(a as u64); - let b = self.value_to_primval(args[1])?.to_bytes()?; + let b = self.value_to_scalar(args[1])?.to_bits(Size::from_bits(64))?; let b = f64::from_bits(b as u64); - let c = self.value_to_primval(args[2])?.to_bytes()?; + let c = self.value_to_scalar(args[2])?.to_bits(Size::from_bits(64))?; let c = f64::from_bits(c as u64); - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes((a * b + c).to_bits() as u128), + Scalar::from_f64(a * b + c), dest_layout.ty, )?; } "powif32" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(32))?; let f = f32::from_bits(f as u32); let i = self.value_to_i32(args[1])?; - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes(f.powi(i).to_bits() as u128), + Scalar::from_f32(f.powi(i)), dest_layout.ty, )?; } "powif64" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(64))?; let f = f64::from_bits(f as u64); let i = self.value_to_i32(args[1])?; - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes(f.powi(i).to_bits() as u128), + Scalar::from_f64(f.powi(i)), dest_layout.ty, )?; } @@ -520,15 +525,15 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "size_of" => { let ty = substs.type_at(0); let size = self.layout_of(ty)?.size.bytes().into(); - self.write_primval(dest, PrimVal::from_u128(size), dest_layout.ty)?; + self.write_scalar(dest, Scalar::from_u128(size), dest_layout.ty)?; } "size_of_val" => { let ty = substs.type_at(0); let (size, _) = self.size_and_align_of_dst(ty, args[0].value)?; - self.write_primval( + self.write_scalar( dest, - PrimVal::from_u128(size.bytes() as u128), + Scalar::from_u128(size.bytes() as u128), dest_layout.ty, )?; } @@ -537,9 +542,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "align_of_val" => { let ty = substs.type_at(0); let (_, align) = self.size_and_align_of_dst(ty, args[0].value)?; - self.write_primval( + self.write_scalar( dest, - PrimVal::from_u128(align.abi() as u128), + Scalar::from_u128(align.abi() as u128), dest_layout.ty, )?; } @@ -553,7 +558,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "type_id" => { let ty = substs.type_at(0); let n = self.tcx.type_id_hash(ty); - self.write_primval(dest, PrimVal::Bytes(n as u128), dest_layout.ty)?; + self.write_scalar(dest, Scalar::Bits { bits: n as u128, defined: 64 }, dest_layout.ty)?; } "transmute" => { @@ -566,7 +571,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "unchecked_shl" => { let bits = dest_layout.size.bytes() as u128 * 8; - let rhs = self.value_to_primval(args[1])? + let rhs = self.value_to_scalar(args[1])? .to_bytes()?; if rhs >= bits { return err!(Intrinsic( @@ -584,7 +589,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "unchecked_shr" => { let bits = dest_layout.size.bytes() as u128 * 8; - let rhs = self.value_to_primval(args[1])? + let rhs = self.value_to_scalar(args[1])? .to_bytes()?; if rhs >= bits { return err!(Intrinsic( @@ -601,7 +606,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "unchecked_div" => { - let rhs = self.value_to_primval(args[1])? + let rhs = self.value_to_scalar(args[1])? .to_bytes()?; if rhs == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_div"))); @@ -616,7 +621,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "unchecked_rem" => { - let rhs = self.value_to_primval(args[1])? + let rhs = self.value_to_scalar(args[1])? .to_bytes()?; if rhs == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_rem"))); @@ -637,7 +642,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: this.memory.mark_definedness(ptr, size, false)?; Ok(val) } - _ => Ok(Value::ByVal(PrimVal::Undef)), + _ => Ok(Value::Scalar(Scalar::undef())), }; match dest { Place::Local { frame, local } => self.modify_local(frame, local, uninit)?, @@ -681,26 +686,25 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: fn numeric_intrinsic<'tcx>( name: &str, bytes: u128, - kind: PrimValKind, -) -> EvalResult<'tcx, PrimVal> { + kind: Primitive, +) -> EvalResult<'tcx, Scalar> { macro_rules! integer_intrinsic { ($method:ident) => ({ - use rustc::mir::interpret::PrimValKind::*; let result_bytes = match kind { - I8 => (bytes as i8).$method() as u128, - U8 => (bytes as u8).$method() as u128, - I16 => (bytes as i16).$method() as u128, - U16 => (bytes as u16).$method() as u128, - I32 => (bytes as i32).$method() as u128, - U32 => (bytes as u32).$method() as u128, - I64 => (bytes as i64).$method() as u128, - U64 => (bytes as u64).$method() as u128, - I128 => (bytes as i128).$method() as u128, - U128 => bytes.$method() as u128, + Primitive::Int(I8, true) => (bytes as i8).$method() as u128, + Primitive::Int(I8, false) => (bytes as u8).$method() as u128, + Primitive::Int(I16, true) => (bytes as i16).$method() as u128, + Primitive::Int(I16, false) => (bytes as u16).$method() as u128, + Primitive::Int(I32, true) => (bytes as i32).$method() as u128, + Primitive::Int(I32, false) => (bytes as u32).$method() as u128, + Primitive::Int(I64, true) => (bytes as i64).$method() as u128, + Primitive::Int(I64, false) => (bytes as u64).$method() as u128, + Primitive::Int(I128, true) => (bytes as i128).$method() as u128, + Primitive::Int(I128, false) => bytes.$method() as u128, _ => bug!("invalid `{}` argument: {:?}", name, bytes), }; - PrimVal::Bytes(result_bytes) + Scalar::from_u128(result_bytes) }); } diff --git a/src/lib.rs b/src/lib.rs index f8119245b484..e3c83c284db9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,6 +53,81 @@ use validation::EvalContextExt as ValidationEvalContextExt; use range_map::RangeMap; use validation::{ValidationQuery, AbsPlace}; +pub trait ScalarExt { + fn null() -> Self; + fn from_i8(i: i8) -> Self; + fn from_u128(i: u128) -> Self; + fn from_i128(i: i128) -> Self; + fn from_usize(i: u64, ptr_size: Size) -> Self; + fn from_isize(i: i64, ptr_size: Size) -> Self; + fn from_f32(f: f32) -> Self; + fn from_f64(f: f64) -> Self; + fn to_u64(self) -> EvalResult<'static, u64>; + fn is_null(self) -> EvalResult<'static, bool>; + fn to_bytes(self) -> EvalResult<'static, u128>; +} + +impl ScalarExt for Scalar { + fn null() -> Self { + Scalar::Bits { bits: 0, defined: 128 } + } + + fn from_i8(i: i8) -> Self { + Scalar::Bits { bits: i as i128 as u128, defined: 8 } + } + + fn from_u128(i: u128) -> Self { + Scalar::Bits { bits: i, defined: 128 } + } + + fn from_i128(i: i128) -> Self { + Scalar::Bits { bits: i as u128, defined: 128 } + } + + fn from_usize(i: u64, ptr_size: Size) -> Self { + Scalar::Bits { bits: i as u128, defined: ptr_size.bits() as u8 } + } + + fn from_isize(i: i64, ptr_size: Size) -> Self { + Scalar::Bits { bits: i as i128 as u128, defined: ptr_size.bits() as u8 } + } + + fn from_f32(f: f32) -> Self { + Scalar::Bits { bits: f.to_bits() as u128, defined: 32 } + } + + fn from_f64(f: f64) -> Self { + Scalar::Bits { bits: f.to_bits() as u128, defined: 64 } + } + + fn to_u64(self) -> EvalResult<'static, u64> { + let b = self.to_bits(Size::from_bits(64))?; + assert_eq!(b as u64 as u128, b); + Ok(b as u64) + } + + fn is_null(self) -> EvalResult<'static, bool> { + match self { + Scalar::Bits { bits, defined } => { + if defined > 0 { + Ok(bits == 0) + } else { + err!(ReadUndefBytes) + } + } + Scalar::Ptr(_) => Ok(false) + } + } + + fn to_bytes(self) -> EvalResult<'static, u128> { + match self { + Scalar::Bits { defined: 0, .. } => err!(ReadUndefBytes), + Scalar::Bits { bits, .. } => Ok(bits), + Scalar::Ptr(_) => err!(ReadPointerAsBytes), + } + } +} + pub fn eval_main<'a, 'tcx: 'a>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, @@ -65,7 +140,7 @@ pub fn eval_main<'a, 'tcx: 'a>( ) -> EvalResult<'tcx> { let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; - let mut cleanup_ptr = None; // Pointer to be deallocated when we are done + let mut cleanup_ptr = None; // Scalar to be deallocated when we are done if !main_mir.return_ty().is_nil() || main_mir.arg_count != 0 { return err!(Unimplemented( @@ -116,7 +191,7 @@ pub fn eval_main<'a, 'tcx: 'a>( let main_ptr_ty = ecx.tcx.mk_fn_ptr(main_ty.fn_sig(ecx.tcx.tcx)); ecx.write_value( ValTy { - value: Value::ByVal(PrimVal::Ptr(main_ptr)), + value: Value::Scalar(Scalar::Ptr(main_ptr)), ty: main_ptr_ty, }, dest, @@ -125,7 +200,7 @@ pub fn eval_main<'a, 'tcx: 'a>( // Second argument (argc): 1 let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let ty = ecx.tcx.types.isize; - ecx.write_primval(dest, PrimVal::Bytes(1), ty)?; + ecx.write_scalar(dest, Scalar::from_u128(1), ty)?; // FIXME: extract main source file path // Third argument (argv): &[b"foo"] @@ -135,7 +210,7 @@ pub fn eval_main<'a, 'tcx: 'a>( let ptr_size = ecx.memory.pointer_size(); let ptr_align = ecx.tcx.data_layout.pointer_align; let foo_ptr = ecx.memory.allocate(ptr_size, ptr_align, None)?; - ecx.memory.write_primval(foo_ptr.into(), ptr_align, PrimVal::Ptr(foo.into()), ptr_size, false)?; + ecx.memory.write_scalar(foo_ptr.into(), ptr_align, Scalar::Ptr(foo), ptr_size, false)?; ecx.memory.mark_static_initialized(foo_ptr.alloc_id, Mutability::Immutable)?; ecx.write_ptr(dest, foo_ptr.into(), ty)?; @@ -145,7 +220,7 @@ pub fn eval_main<'a, 'tcx: 'a>( main_instance, main_mir.span, main_mir, - Place::from_primval_ptr(PrimVal::Bytes(1).into(), ty::layout::Align::from_bytes(1, 1).unwrap()), + Place::from_scalar_ptr(Scalar::from_u128(1), ty::layout::Align::from_bytes(1, 1).unwrap()), StackPopCleanup::None, )?; @@ -187,6 +262,7 @@ pub fn eval_main<'a, 'tcx: 'a>( } } } + ::std::process::exit(1); } } } @@ -195,7 +271,7 @@ pub fn eval_main<'a, 'tcx: 'a>( pub struct Evaluator<'tcx> { /// Environment variables set by `setenv` /// Miri does not expose env vars from the host to the emulated program - pub(crate) env_vars: HashMap, MemoryPointer>, + pub(crate) env_vars: HashMap, Pointer>, /// Places that were suspended by the validation subsystem, and will be recovered later pub(crate) suspended: HashMap>>, @@ -205,7 +281,7 @@ pub type TlsKey = usize; #[derive(Copy, Clone, Debug)] pub struct TlsEntry<'tcx> { - data: Pointer, // Will eventually become a map from thread IDs to `Pointer`s, if we ever support more than one thread. + data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. dtor: Option>, } @@ -256,11 +332,11 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn try_ptr_op<'a>( ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, bin_op: mir::BinOp, - left: PrimVal, + left: Scalar, left_ty: ty::Ty<'tcx>, - right: PrimVal, + right: Scalar, right_ty: ty::Ty<'tcx>, - ) -> EvalResult<'tcx, Option<(PrimVal, bool)>> { + ) -> EvalResult<'tcx, Option<(Scalar, bool)>> { ecx.ptr_op(bin_op, left, left_ty, right, right_ty) } @@ -372,7 +448,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; ecx.write_value( ValTy { - value: Value::ByVal(PrimVal::Bytes(match layout.size.bytes() { + value: Value::Scalar(Scalar::from_u128(match layout.size.bytes() { 0 => 1 as u128, size => size as u128, }.into())), @@ -385,7 +461,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; ecx.write_value( ValTy { - value: Value::ByVal(PrimVal::Bytes(layout.align.abi().into())), + value: Value::Scalar(Scalar::from_u128(layout.align.abi().into())), ty: usize, }, dest, @@ -406,7 +482,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn check_locks<'a>( mem: &Memory<'a, 'mir, 'tcx, Self>, - ptr: MemoryPointer, + ptr: Pointer, size: Size, access: AccessKind, ) -> EvalResult<'tcx> { @@ -437,7 +513,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { .map_err(|lock| { EvalErrorKind::DeallocatedLockedMemory { //ptr, FIXME - ptr: MemoryPointer { + ptr: Pointer { alloc_id: AllocId(0), offset: Size::from_bytes(0), }, diff --git a/src/locks.rs b/src/locks.rs index 9efbabc7171b..a463f8ba575e 100644 --- a/src/locks.rs +++ b/src/locks.rs @@ -70,27 +70,27 @@ impl<'tcx> LockInfo<'tcx> { pub trait MemoryExt<'tcx> { fn check_locks( &self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, access: AccessKind, ) -> EvalResult<'tcx>; fn acquire_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, region: Option, kind: AccessKind, ) -> EvalResult<'tcx>; fn suspend_write_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, lock_path: &AbsPlace<'tcx>, suspend: Option, ) -> EvalResult<'tcx>; fn recover_write_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, lock_path: &AbsPlace<'tcx>, lock_region: Option, @@ -103,7 +103,7 @@ pub trait MemoryExt<'tcx> { impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evaluator<'tcx>> { fn check_locks( &self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, access: AccessKind, ) -> EvalResult<'tcx> { @@ -132,7 +132,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu /// Acquire the lock for the given lifetime fn acquire_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, region: Option, kind: AccessKind, @@ -191,7 +191,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu /// When suspending, the same cases are fine; we just register an additional suspension. fn suspend_write_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, lock_path: &AbsPlace<'tcx>, suspend: Option, @@ -264,7 +264,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu /// Release a suspension from the write lock. If this is the last suspension or if there is no suspension, acquire the lock. fn recover_write_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, lock_path: &AbsPlace<'tcx>, lock_region: Option, diff --git a/src/operator.rs b/src/operator.rs index 557e07975d73..721b4f0bfdda 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,4 +1,5 @@ use rustc::ty; +use rustc::ty::layout::Primitive; use rustc::mir; use super::*; @@ -9,38 +10,58 @@ pub trait EvalContextExt<'tcx> { fn ptr_op( &self, bin_op: mir::BinOp, - left: PrimVal, + left: Scalar, left_ty: ty::Ty<'tcx>, - right: PrimVal, + right: Scalar, right_ty: ty::Ty<'tcx>, - ) -> EvalResult<'tcx, Option<(PrimVal, bool)>>; + ) -> EvalResult<'tcx, Option<(Scalar, bool)>>; fn ptr_int_arithmetic( &self, bin_op: mir::BinOp, - left: MemoryPointer, + left: Pointer, right: i128, signed: bool, - ) -> EvalResult<'tcx, (PrimVal, bool)>; + ) -> EvalResult<'tcx, (Scalar, bool)>; } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { fn ptr_op( &self, bin_op: mir::BinOp, - left: PrimVal, + left: Scalar, left_ty: ty::Ty<'tcx>, - right: PrimVal, + right: Scalar, right_ty: ty::Ty<'tcx>, - ) -> EvalResult<'tcx, Option<(PrimVal, bool)>> { - use rustc::mir::interpret::PrimValKind::*; + ) -> EvalResult<'tcx, Option<(Scalar, bool)>> { use rustc::mir::BinOp::*; - let usize = PrimValKind::from_uint_size(self.memory.pointer_size()); - let isize = PrimValKind::from_int_size(self.memory.pointer_size()); - let left_kind = self.ty_to_primval_kind(left_ty)?; - let right_kind = self.ty_to_primval_kind(right_ty)?; + use rustc::ty::layout::Integer::*; + let usize = Primitive::Int(match self.memory.pointer_size().bytes() { + 1 => I8, + 2 => I16, + 4 => I32, + 8 => I64, + 16 => I128, + _ => unreachable!(), + }, false); + let isize = Primitive::Int(match self.memory.pointer_size().bytes() { + 1 => I8, + 2 => I16, + 4 => I32, + 8 => I64, + 16 => I128, + _ => unreachable!(), + }, true); + let left_kind = match self.layout_of(left_ty)?.abi { + ty::layout::Abi::Scalar(ref scalar) => scalar.value, + _ => Err(EvalErrorKind::TypeNotPrimitive(left_ty))?, + }; + let right_kind = match self.layout_of(right_ty)?.abi { + ty::layout::Abi::Scalar(ref scalar) => scalar.value, + _ => Err(EvalErrorKind::TypeNotPrimitive(right_ty))?, + }; match bin_op { - Offset if left_kind == Ptr && right_kind == usize => { + Offset if left_kind == Primitive::Pointer && right_kind == usize => { let pointee_ty = left_ty .builtin_deref(true) .expect("Offset called on non-ptr type") @@ -48,35 +69,35 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ptr = self.pointer_offset( left.into(), pointee_ty, - right.to_bytes()? as i64, + right.to_bits(self.memory.pointer_size())? as i64, )?; - Ok(Some((ptr.into_inner_primval(), false))) + Ok(Some((ptr, false))) } // These work on anything Eq if left_kind == right_kind => { let result = match (left, right) { - (PrimVal::Bytes(left), PrimVal::Bytes(right)) => left == right, - (PrimVal::Ptr(left), PrimVal::Ptr(right)) => left == right, - (PrimVal::Undef, _) | - (_, PrimVal::Undef) => return err!(ReadUndefBytes), + (Scalar::Bits { .. }, Scalar::Bits { .. }) => { + left.to_bits(self.memory.pointer_size())? == right.to_bits(self.memory.pointer_size())? + }, + (Scalar::Ptr(left), Scalar::Ptr(right)) => left == right, _ => false, }; - Ok(Some((PrimVal::from_bool(result), false))) + Ok(Some((Scalar::from_bool(result), false))) } Ne if left_kind == right_kind => { let result = match (left, right) { - (PrimVal::Bytes(left), PrimVal::Bytes(right)) => left != right, - (PrimVal::Ptr(left), PrimVal::Ptr(right)) => left != right, - (PrimVal::Undef, _) | - (_, PrimVal::Undef) => return err!(ReadUndefBytes), + (Scalar::Bits { .. }, Scalar::Bits { .. }) => { + left.to_bits(self.memory.pointer_size())? != right.to_bits(self.memory.pointer_size())? + }, + (Scalar::Ptr(left), Scalar::Ptr(right)) => left != right, _ => true, }; - Ok(Some((PrimVal::from_bool(result), false))) + Ok(Some((Scalar::from_bool(result), false))) } // These need both pointers to be in the same allocation Lt | Le | Gt | Ge | Sub if left_kind == right_kind && - (left_kind == Ptr || left_kind == usize || left_kind == isize) && + (left_kind == Primitive::Pointer || left_kind == usize || left_kind == isize) && left.is_ptr() && right.is_ptr() => { let left = left.to_ptr()?; let right = right.to_ptr()?; @@ -89,15 +110,15 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Sub => { return self.binary_op( Sub, - PrimVal::Bytes(left.offset.bytes() as u128), + Scalar::Bits { bits: left.offset.bytes() as u128, defined: self.memory.pointer_size().bits() as u8 }, self.tcx.types.usize, - PrimVal::Bytes(right.offset.bytes() as u128), + Scalar::Bits { bits: right.offset.bytes() as u128, defined: self.memory.pointer_size().bits() as u8 }, self.tcx.types.usize, ).map(Some) } _ => bug!("We already established it has to be one of these operators."), }; - Ok(Some((PrimVal::from_bool(res), false))) + Ok(Some((Scalar::from_bool(res), false))) } else { // Both are pointers, but from different allocations. err!(InvalidPointerMath) @@ -106,23 +127,23 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // These work if one operand is a pointer, the other an integer Add | BitAnd | Sub if left_kind == right_kind && (left_kind == usize || left_kind == isize) && - left.is_ptr() && right.is_bytes() => { + left.is_ptr() && right.is_bits() => { // Cast to i128 is fine as we checked the kind to be ptr-sized self.ptr_int_arithmetic( bin_op, left.to_ptr()?, - right.to_bytes()? as i128, + right.to_bits(self.memory.pointer_size())? as i128, left_kind == isize, ).map(Some) } Add | BitAnd if left_kind == right_kind && (left_kind == usize || left_kind == isize) && - left.is_bytes() && right.is_ptr() => { + left.is_bits() && right.is_ptr() => { // This is a commutative operation, just swap the operands self.ptr_int_arithmetic( bin_op, right.to_ptr()?, - left.to_bytes()? as i128, + left.to_bits(self.memory.pointer_size())? as i128, left_kind == isize, ).map(Some) } @@ -133,14 +154,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: fn ptr_int_arithmetic( &self, bin_op: mir::BinOp, - left: MemoryPointer, + left: Pointer, right: i128, signed: bool, - ) -> EvalResult<'tcx, (PrimVal, bool)> { + ) -> EvalResult<'tcx, (Scalar, bool)> { use rustc::mir::BinOp::*; - fn map_to_primval((res, over): (MemoryPointer, bool)) -> (PrimVal, bool) { - (PrimVal::Ptr(res), over) + fn map_to_primval((res, over): (Pointer, bool)) -> (Scalar, bool) { + (Scalar::Ptr(res), over) } Ok(match bin_op { @@ -157,10 +178,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let right = right as u64; if right & base_mask == base_mask { // Case 1: The base address bits are all preserved, i.e., right is all-1 there - (PrimVal::Ptr(MemoryPointer::new(left.alloc_id, Size::from_bytes(left.offset.bytes() & right))), false) + (Scalar::Ptr(Pointer::new(left.alloc_id, Size::from_bytes(left.offset.bytes() & right))), false) } else if right & base_mask == 0 { // Case 2: The base address bits are all taken away, i.e., right is all-0 there - (PrimVal::from_u128((left.offset.bytes() & right) as u128), false) + (Scalar::Bits { bits: (left.offset.bytes() & right) as u128, defined: 128 }, false) } else { return err!(ReadPointerAsBytes); } diff --git a/src/tls.rs b/src/tls.rs index e55cbede2339..7f49509ef42e 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -1,17 +1,17 @@ use rustc::{ty, mir}; -use super::{TlsKey, TlsEntry, EvalResult, EvalErrorKind, Pointer, Memory, Evaluator, Place, - StackPopCleanup, EvalContext}; +use super::{TlsKey, TlsEntry, EvalResult, EvalErrorKind, Scalar, ScalarExt, Memory, Evaluator, + Place, StackPopCleanup, EvalContext}; pub trait MemoryExt<'tcx> { fn create_tls_key(&mut self, dtor: Option>) -> TlsKey; fn delete_tls_key(&mut self, key: TlsKey) -> EvalResult<'tcx>; - fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Pointer>; - fn store_tls(&mut self, key: TlsKey, new_data: Pointer) -> EvalResult<'tcx>; + fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar>; + fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx>; fn fetch_tls_dtor( &mut self, key: Option, - ) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Pointer, TlsKey)>>; + ) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Scalar, TlsKey)>>; } pub trait EvalContextExt<'tcx> { @@ -25,7 +25,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu self.data.thread_local.insert( new_key, TlsEntry { - data: Pointer::null(), + data: Scalar::null(), dtor, }, ); @@ -43,7 +43,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu }; } - fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Pointer> { + fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar> { return match self.data.thread_local.get(&key) { Some(&TlsEntry { data, .. }) => { trace!("TLS key {} loaded: {:?}", key, data); @@ -53,7 +53,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu }; } - fn store_tls(&mut self, key: TlsKey, new_data: Pointer) -> EvalResult<'tcx> { + fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx> { return match self.data.thread_local.get_mut(&key) { Some(&mut TlsEntry { ref mut data, .. }) => { trace!("TLS key {} stored: {:?}", key, new_data); @@ -85,19 +85,21 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu fn fetch_tls_dtor( &mut self, key: Option, - ) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Pointer, TlsKey)>> { + ) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Scalar, TlsKey)>> { use std::collections::Bound::*; + + let thread_local = &mut self.data.thread_local; let start = match key { Some(key) => Excluded(key), None => Unbounded, }; for (&key, &mut TlsEntry { ref mut data, dtor }) in - self.data.thread_local.range_mut((start, Unbounded)) + thread_local.range_mut((start, Unbounded)) { if !data.is_null()? { if let Some(dtor) = dtor { let ret = Some((dtor, *data, key)); - *data = Pointer::null(); + *data = Scalar::null(); return Ok(ret); } } diff --git a/src/validation.rs b/src/validation.rs index deb1c5d5bc07..24ddffee9def 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -12,7 +12,7 @@ use rustc::middle::const_val::ConstVal; use rustc_data_structures::indexed_vec::Idx; use rustc_mir::interpret::HasMemory; -use super::{EvalContext, Place, PlaceExtra, ValTy}; +use super::{EvalContext, Place, PlaceExtra, ValTy, ScalarExt}; use rustc::mir::interpret::{DynamicLifetime, AccessKind, EvalErrorKind, Value, EvalError, EvalResult}; use locks::MemoryExt; @@ -119,7 +119,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Index(v) => { let value = self.frame().get_local(v)?; let ty = self.tcx.tcx.types.usize; - let n = self.value_to_primval(ValTy { value, ty })?.to_u64()?; + let n = self.value_to_scalar(ValTy { value, ty })?.to_u64()?; Index(n) }, ConstantIndex { offset, min_length, from_end } => @@ -652,7 +652,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' TyBool | TyFloat(_) | TyChar => { if mode.acquiring() { let val = self.read_place(query.place.1)?; - let val = self.value_to_primval(ValTy { value: val, ty: query.ty })?; + let val = self.value_to_scalar(ValTy { value: val, ty: query.ty })?; val.to_bytes()?; // TODO: Check if these are valid bool/float/codepoint/UTF-8 } From 1bd088a96c03ae38ccea15403487da6a10d978f3 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 30 May 2018 14:29:32 +0200 Subject: [PATCH 0091/5092] `memcmp` returns `i32` --- src/fn_call.rs | 4 ++-- src/lib.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index ea0c5eb8b26e..6a2255e57772 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -289,7 +289,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' use std::cmp::Ordering::*; match left_bytes.cmp(right_bytes) { - Less => -1i8, + Less => -1i32, Equal => 0, Greater => 1, } @@ -297,7 +297,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.write_scalar( dest, - Scalar::from_i8(result), + Scalar::from_i32(result), dest_ty, )?; } diff --git a/src/lib.rs b/src/lib.rs index e3c83c284db9..079560c0ca95 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,7 +55,7 @@ use validation::{ValidationQuery, AbsPlace}; pub trait ScalarExt { fn null() -> Self; - fn from_i8(i: i8) -> Self; + fn from_i32(i: i32) -> Self; fn from_u128(i: u128) -> Self; fn from_i128(i: i128) -> Self; fn from_usize(i: u64, ptr_size: Size) -> Self; @@ -72,8 +72,8 @@ impl ScalarExt for Scalar { Scalar::Bits { bits: 0, defined: 128 } } - fn from_i8(i: i8) -> Self { - Scalar::Bits { bits: i as i128 as u128, defined: 8 } + fn from_i32(i: i32) -> Self { + Scalar::Bits { bits: i as u32 as u128, defined: 32 } } fn from_u128(i: u128) -> Self { From 9655aaf3aa74e948935b1749fbdff2f8f774226b Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 30 May 2018 14:29:54 +0200 Subject: [PATCH 0092/5092] Comparing Scalar's with differend `defined` values is false --- src/intrinsic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 3d537ea629c3..1e8090dc1897 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -327,7 +327,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let a = self.value_to_scalar(args[0])?; let b = self.value_to_scalar(args[1])?; // check x % y != 0 - if self.binary_op(mir::BinOp::Rem, a, ty, b, ty)?.0 != Scalar::null() { + if !self.binary_op(mir::BinOp::Rem, a, ty, b, ty)?.0.is_null()? { return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b))); } let result = self.binary_op(mir::BinOp::Div, a, ty, b, ty)?; From 062be7c047fa6c276b48c7b024725e90d3a93c25 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 30 May 2018 14:30:15 +0200 Subject: [PATCH 0093/5092] Comparing non-pointer-size types should be possible --- src/operator.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index 721b4f0bfdda..f36e749dc927 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -52,11 +52,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: 16 => I128, _ => unreachable!(), }, true); - let left_kind = match self.layout_of(left_ty)?.abi { + let left_layout = self.layout_of(left_ty)?; + let left_kind = match left_layout.abi { ty::layout::Abi::Scalar(ref scalar) => scalar.value, _ => Err(EvalErrorKind::TypeNotPrimitive(left_ty))?, }; - let right_kind = match self.layout_of(right_ty)?.abi { + let right_layout = self.layout_of(right_ty)?; + let right_kind = match right_layout.abi { ty::layout::Abi::Scalar(ref scalar) => scalar.value, _ => Err(EvalErrorKind::TypeNotPrimitive(right_ty))?, }; @@ -77,7 +79,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Eq if left_kind == right_kind => { let result = match (left, right) { (Scalar::Bits { .. }, Scalar::Bits { .. }) => { - left.to_bits(self.memory.pointer_size())? == right.to_bits(self.memory.pointer_size())? + left.to_bits(left_layout.size)? == right.to_bits(right_layout.size)? }, (Scalar::Ptr(left), Scalar::Ptr(right)) => left == right, _ => false, @@ -87,7 +89,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Ne if left_kind == right_kind => { let result = match (left, right) { (Scalar::Bits { .. }, Scalar::Bits { .. }) => { - left.to_bits(self.memory.pointer_size())? != right.to_bits(self.memory.pointer_size())? + left.to_bits(left_layout.size)? != right.to_bits(right_layout.size)? }, (Scalar::Ptr(left), Scalar::Ptr(right)) => left != right, _ => true, From 1d9c56ddf40fd43231c3caa167465167738ebfda Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 30 May 2018 15:59:04 +0200 Subject: [PATCH 0094/5092] TlsKey is messy because it changes types between systems --- src/fn_call.rs | 9 +++------ src/lib.rs | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 6a2255e57772..d1a483d2e804 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -512,21 +512,18 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.write_null(dest, dest_ty)?; } "pthread_key_delete" => { - // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t - let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey; + let key = self.value_to_scalar(args[0])?.to_bytes()?; self.memory.delete_tls_key(key)?; // Return success (0) self.write_null(dest, dest_ty)?; } "pthread_getspecific" => { - // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t - let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey; + let key = self.value_to_scalar(args[0])?.to_bytes()?; let ptr = self.memory.load_tls(key)?; self.write_ptr(dest, ptr, dest_ty)?; } "pthread_setspecific" => { - // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t - let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey; + let key = self.value_to_scalar(args[0])?.to_bytes()?; let new_ptr = self.into_ptr(args[1].value)?; self.memory.store_tls(key, new_ptr)?; diff --git a/src/lib.rs b/src/lib.rs index 079560c0ca95..6d7c0b05f80f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -277,7 +277,7 @@ pub struct Evaluator<'tcx> { pub(crate) suspended: HashMap>>, } -pub type TlsKey = usize; +pub type TlsKey = u128; #[derive(Copy, Clone, Debug)] pub struct TlsEntry<'tcx> { From 77c8582031ca4084651d2cf365f81f19bbd50fcc Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 30 May 2018 17:43:27 +0200 Subject: [PATCH 0095/5092] `align_offset` intrinsic is now a lang item --- src/fn_call.rs | 12 ++++++++++++ src/intrinsic.rs | 8 -------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index d1a483d2e804..fdaa819c08f7 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -135,6 +135,18 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' _ => {} } + if self.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { + // FIXME: return a real value in case the target allocation has an + // alignment bigger than the one requested + let n = u128::max_value(); + let amt = 128 - self.memory.pointer_size().bytes() * 8; + let (dest, return_to_block) = destination.unwrap(); + let ty = self.tcx.types.usize; + self.write_scalar(dest, Scalar::from_u128((n << amt) >> amt), ty)?; + self.goto_block(return_to_block); + return Ok(true); + } + let mir = match self.load_mir(instance.def) { Ok(mir) => mir, Err(EvalError { kind: EvalErrorKind::NoMirFor(path), .. }) => { diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 1e8090dc1897..cee2f1ab7682 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -33,14 +33,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..]; match intrinsic_name { - "align_offset" => { - // FIXME: return a real value in case the target allocation has an - // alignment bigger than the one requested - let n = u128::max_value(); - let amt = 128 - self.memory.pointer_size().bytes() * 8; - self.write_scalar(dest, Scalar::from_u128((n << amt) >> amt), dest_layout.ty)?; - }, - "add_with_overflow" => { self.intrinsic_with_overflow( mir::BinOp::Add, From 8284b4e912baf72473c3696ce9e46cc334da18e4 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 30 May 2018 17:43:54 +0200 Subject: [PATCH 0096/5092] `to_u64` and `to_bytes` are horribly easy to use wrongly. --- src/fn_call.rs | 8 ++++---- src/lib.rs | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index fdaa819c08f7..72efcd6ede07 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -316,7 +316,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memrchr" => { let ptr = self.into_ptr(args[0].value)?; - let val = self.value_to_scalar(args[1])?.to_u64()? as u8; + let val = self.value_to_scalar(args[1])?.to_bytes()? as u8; let num = self.value_to_scalar(args[2])?.to_u64()?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().rev().position( |&c| c == val, @@ -331,7 +331,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memchr" => { let ptr = self.into_ptr(args[0].value)?; - let val = self.value_to_scalar(args[1])?.to_u64()? as u8; + let val = self.value_to_scalar(args[1])?.to_bytes()? as u8; let num = self.value_to_scalar(args[2])?.to_u64()?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().position( |&c| c == val, @@ -414,9 +414,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "write" => { - let fd = self.value_to_scalar(args[0])?.to_u64()?; + let fd = self.value_to_scalar(args[0])?.to_bytes()?; let buf = self.into_ptr(args[1].value)?; - let n = self.value_to_scalar(args[2])?.to_u64()?; + let n = self.value_to_scalar(args[2])?.to_bytes()? as u64; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { // stdout/stderr diff --git a/src/lib.rs b/src/lib.rs index 6d7c0b05f80f..550965573cb4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,6 +64,9 @@ pub trait ScalarExt { fn from_f64(f: f64) -> Self; fn to_u64(self) -> EvalResult<'static, u64>; fn is_null(self) -> EvalResult<'static, bool>; + /// HACK: this function just extracts all bits if `defined != 0` + /// Mainly used for args of C-functions and we should totally correctly fetch the size + /// of their arguments fn to_bytes(self) -> EvalResult<'static, u128>; } From cec51f8513bc1fa6344b702a4e5036c4961fda04 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sun, 3 Jun 2018 11:54:17 +0200 Subject: [PATCH 0097/5092] Use correct bit size when reading usize values --- src/fn_call.rs | 30 +++++++++++++++--------------- src/lib.rs | 6 +++--- src/validation.rs | 2 +- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 72efcd6ede07..36cc29a2b5b5 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -194,7 +194,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match &link_name[..] { "malloc" => { - let size = self.value_to_scalar(args[0])?.to_u64()?; + let size = self.value_to_scalar(args[0])?.to_usize(self)?; if size == 0 { self.write_null(dest, dest_ty)?; } else { @@ -221,7 +221,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // // libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK) // is called if a `HashMap` is created the regular way. - match self.value_to_scalar(args[0])?.to_u64()? { + match self.value_to_scalar(args[0])?.to_usize(self)? { 318 | 511 => { return err!(Unimplemented( "miri does not support random number generators".to_owned(), @@ -293,7 +293,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memcmp" => { let left = self.into_ptr(args[0].value)?; let right = self.into_ptr(args[1].value)?; - let n = Size::from_bytes(self.value_to_scalar(args[2])?.to_u64()?); + let n = Size::from_bytes(self.value_to_scalar(args[2])?.to_usize(self)?); let result = { let left_bytes = self.memory.read_bytes(left, n)?; @@ -317,7 +317,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memrchr" => { let ptr = self.into_ptr(args[0].value)?; let val = self.value_to_scalar(args[1])?.to_bytes()? as u8; - let num = self.value_to_scalar(args[2])?.to_u64()?; + let num = self.value_to_scalar(args[2])?.to_usize(self)?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().rev().position( |&c| c == val, ) @@ -332,7 +332,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memchr" => { let ptr = self.into_ptr(args[0].value)?; let val = self.value_to_scalar(args[1])?.to_bytes()? as u8; - let num = self.value_to_scalar(args[2])?.to_u64()?; + let num = self.value_to_scalar(args[2])?.to_usize(self)?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().position( |&c| c == val, ) @@ -457,7 +457,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "sysconf" => { - let name = self.value_to_scalar(args[0])?.to_u64()?; + let name = self.value_to_scalar(args[0])?.to_usize(self)?; trace!("sysconf() called with name {}", name); // cache the sysconf integers via miri's global cache @@ -646,8 +646,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match &path[..] { // Allocators are magic. They have no MIR, even when the rest of libstd does. "alloc::alloc::::__rust_alloc" => { - let size = self.value_to_scalar(args[0])?.to_u64()?; - let align = self.value_to_scalar(args[1])?.to_u64()?; + let size = self.value_to_scalar(args[0])?.to_usize(self)?; + let align = self.value_to_scalar(args[1])?.to_usize(self)?; if size == 0 { return err!(HeapAllocZeroBytes); } @@ -660,8 +660,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; } "alloc::alloc::::__rust_alloc_zeroed" => { - let size = self.value_to_scalar(args[0])?.to_u64()?; - let align = self.value_to_scalar(args[1])?.to_u64()?; + let size = self.value_to_scalar(args[0])?.to_usize(self)?; + let align = self.value_to_scalar(args[1])?.to_usize(self)?; if size == 0 { return err!(HeapAllocZeroBytes); } @@ -676,8 +676,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "alloc::alloc::::__rust_dealloc" => { let ptr = self.into_ptr(args[0].value)?.to_ptr()?; - let old_size = self.value_to_scalar(args[1])?.to_u64()?; - let align = self.value_to_scalar(args[2])?.to_u64()?; + let old_size = self.value_to_scalar(args[1])?.to_usize(self)?; + let align = self.value_to_scalar(args[2])?.to_usize(self)?; if old_size == 0 { return err!(HeapAllocZeroBytes); } @@ -692,9 +692,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "alloc::alloc::::__rust_realloc" => { let ptr = self.into_ptr(args[0].value)?.to_ptr()?; - let old_size = self.value_to_scalar(args[1])?.to_u64()?; - let align = self.value_to_scalar(args[2])?.to_u64()?; - let new_size = self.value_to_scalar(args[3])?.to_u64()?; + let old_size = self.value_to_scalar(args[1])?.to_usize(self)?; + let align = self.value_to_scalar(args[2])?.to_usize(self)?; + let new_size = self.value_to_scalar(args[3])?.to_usize(self)?; if old_size == 0 || new_size == 0 { return err!(HeapAllocZeroBytes); } diff --git a/src/lib.rs b/src/lib.rs index 550965573cb4..a29211df996b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,7 +62,7 @@ pub trait ScalarExt { fn from_isize(i: i64, ptr_size: Size) -> Self; fn from_f32(f: f32) -> Self; fn from_f64(f: f64) -> Self; - fn to_u64(self) -> EvalResult<'static, u64>; + fn to_usize<'a, 'mir, 'tcx>(self, ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>) -> EvalResult<'static, u64>; fn is_null(self) -> EvalResult<'static, bool>; /// HACK: this function just extracts all bits if `defined != 0` /// Mainly used for args of C-functions and we should totally correctly fetch the size @@ -103,8 +103,8 @@ impl ScalarExt for Scalar { Scalar::Bits { bits: f.to_bits() as u128, defined: 64 } } - fn to_u64(self) -> EvalResult<'static, u64> { - let b = self.to_bits(Size::from_bits(64))?; + fn to_usize<'a, 'mir, 'tcx>(self, ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>) -> EvalResult<'static, u64> { + let b = self.to_bits(ecx.memory.pointer_size())?; assert_eq!(b as u64 as u128, b); Ok(b as u64) } diff --git a/src/validation.rs b/src/validation.rs index 24ddffee9def..d82a345c2512 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -119,7 +119,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Index(v) => { let value = self.frame().get_local(v)?; let ty = self.tcx.tcx.types.usize; - let n = self.value_to_scalar(ValTy { value, ty })?.to_u64()?; + let n = self.value_to_scalar(ValTy { value, ty })?.to_usize(self)?; Index(n) }, ConstantIndex { offset, min_length, from_end } => From 675587280f5cee0ea99ebb4c4f70043e89aa1aed Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sun, 3 Jun 2018 12:13:30 +0200 Subject: [PATCH 0098/5092] Update cargo-miri --- cargo-miri-test/Cargo.lock | 12 ++++++------ src/bin/cargo-miri.rs | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cargo-miri-test/Cargo.lock b/cargo-miri-test/Cargo.lock index 8b2387fa6410..85c3c08dba01 100644 --- a/cargo-miri-test/Cargo.lock +++ b/cargo-miri-test/Cargo.lock @@ -1,14 +1,14 @@ -[root] +[[package]] +name = "byteorder" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "cargo-miri-test" version = "0.1.0" dependencies = [ "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "byteorder" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [metadata] "checksum byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c40977b0ee6b9885c9013cd41d9feffdd22deb3bb4dc3a71d901cc7a77de18c8" diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 39a41583a39e..010f25e8152d 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -154,7 +154,7 @@ fn main() { // this check ensures that dependencies are built but not interpreted and the final crate is // interpreted but not built - let miri_enabled = std::env::args().any(|s| s == "-Zno-trans"); + let miri_enabled = std::env::args().any(|s| s == "--emit=dep-info,metadata"); let mut command = if miri_enabled { let mut path = std::env::current_exe().expect("current executable path invalid"); @@ -193,7 +193,7 @@ where if !found_dashes { args.push("--".to_owned()); } - args.push("-Zno-trans".to_owned()); + args.push("--emit=dep-info,metadata".to_owned()); args.push("--cfg".to_owned()); args.push(r#"feature="cargo-miri""#.to_owned()); From e1734470e780e05a3366a2f74cfa25ea88a518a5 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sun, 3 Jun 2018 12:54:43 +0200 Subject: [PATCH 0099/5092] Reenable the rustc tester --- rustc_tests/Cargo.lock | 209 +++++++++++++++++++++++++--------------- rustc_tests/src/main.rs | 10 +- src/lib.rs | 1 - 3 files changed, 134 insertions(+), 86 deletions(-) diff --git a/rustc_tests/Cargo.lock b/rustc_tests/Cargo.lock index a1e273a96bdb..9cf4fe0d1342 100644 --- a/rustc_tests/Cargo.lock +++ b/rustc_tests/Cargo.lock @@ -1,10 +1,3 @@ -[root] -name = "rustc_tests" -version = "0.1.0" -dependencies = [ - "miri 0.1.0", -] - [[package]] name = "aho-corasick" version = "0.6.3" @@ -14,26 +7,13 @@ dependencies = [ ] [[package]] -name = "backtrace" -version = "0.3.3" +name = "atty" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "backtrace-sys" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -46,36 +26,24 @@ name = "cfg-if" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "dbghelp-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "env_logger" -version = "0.4.3" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "gcc" -version = "0.3.53" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "kernel32-sys" -version = "0.2.2" +name = "humantime" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -83,6 +51,11 @@ name = "lazy_static" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "lazy_static" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "libc" version = "0.2.30" @@ -90,15 +63,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "log" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "log_settings" -version = "0.1.1" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -109,15 +77,41 @@ dependencies = [ "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "memchr" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "miri" version = "0.1.0" dependencies = [ "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_miri 0.1.0", + "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quick-error" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "redox_syscall" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "redox_termios" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -132,26 +126,54 @@ dependencies = [ "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "regex" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "regex-syntax" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "rustc-demangle" -version = "0.1.5" +name = "regex-syntax" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] -name = "rustc_miri" +name = "rustc_tests" version = "0.1.0" dependencies = [ - "backtrace 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "miri 0.1.0", +] + +[[package]] +name = "termcolor" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "termion" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -163,6 +185,11 @@ dependencies = [ "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ucd-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unreachable" version = "1.0.0" @@ -183,35 +210,59 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi" -version = "0.2.8" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "winapi-build" -version = "0.1.1" +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "wincolor" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [metadata] "checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" -"checksum backtrace 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "99f2ce94e22b8e664d95c57fff45b98a966c2252b60691d0b7aeeccd88d70983" -"checksum backtrace-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "afccc5772ba333abccdf60d55200fa3406f8c59dcf54d5f7998c9107d3799c7c" +"checksum atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2fc4a1aa4c24c0718a250f0681885c1af91419d242f29eb8f2ab28502d80dbd1" "checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" -"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" -"checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b" -"checksum gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)" = "e8310f7e9c890398b0e80e301c4f474e9918d2b27fca8f48486ca775fa9ffc5a" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0e6e40ebb0e66918a37b38c7acab4e10d299e0463fe2af5d29b9cc86710cfd2a" +"checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" "checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" +"checksum lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e6412c5e2ad9584b0b8e979393122026cdd6d2a80b933f890dcd694ddbe73739" "checksum libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)" = "2370ca07ec338939e356443dac2296f581453c35fe1e3a3ed06023c49435f915" -"checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" -"checksum log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3d382732ea0fbc09790c4899db3255bdea0fc78b54bf234bd18a63bb603915b6" +"checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" +"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" +"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" +"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" +"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b" +"checksum regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75ecf88252dce580404a22444fc7d626c01815debba56a7f4f536772a5ff19d3" "checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" -"checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e" +"checksum regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1ac0f60d675cc6cf13a20ec076568254472551051ad5dd050364d70671bf6b" +"checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83" +"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14" +"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" +"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb06499a3a4d44302791052df005d5232b927ed1a9658146d842165c4de7767" diff --git a/rustc_tests/src/main.rs b/rustc_tests/src/main.rs index 77e4a3df406b..ecc5287c7277 100644 --- a/rustc_tests/src/main.rs +++ b/rustc_tests/src/main.rs @@ -4,7 +4,7 @@ extern crate getopts; extern crate rustc; extern crate rustc_driver; extern crate rustc_errors; -extern crate rustc_trans_utils; +extern crate rustc_codegen_utils; extern crate syntax; use std::path::{PathBuf, Path}; @@ -19,7 +19,7 @@ use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls}; use rustc_driver::driver::{CompileState, CompileController}; use rustc::session::config::{self, Input, ErrorOutputType}; use rustc::hir::{self, itemlikevisit}; -use rustc_trans_utils::trans_crate::TransCrate; +use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc::ty::TyCtxt; use syntax::ast; @@ -53,7 +53,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { } fn late_callback( &mut self, - trans: &TransCrate, + trans: &CodegenBackend, matches: &getopts::Matches, sess: &Session, cstore: &CrateStore, @@ -104,9 +104,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(tcx, state)); } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { let entry_def_id = tcx.hir.local_def_id(entry_node_id); - let start_wrapper = tcx.lang_items().start_fn().and_then(|start_fn| - if tcx.is_mir_available(start_fn) { Some(start_fn) } else { None }); - miri::eval_main(tcx, entry_def_id, start_wrapper); + miri::eval_main(tcx, entry_def_id, None); state.session.abort_if_errors(); } else { diff --git a/src/lib.rs b/src/lib.rs index a29211df996b..1ba763349aa7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -265,7 +265,6 @@ pub fn eval_main<'a, 'tcx: 'a>( } } } - ::std::process::exit(1); } } } From 3db0568c408e0b22088d889ad95fccd8659f1fcc Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Wed, 9 May 2018 15:54:45 +0200 Subject: [PATCH 0100/5092] Fix a couple of tests --- tests/compile-fail/copy_nonoverlapping.rs | 2 -- tests/compile-fail/deallocate-bad-alignment.rs | 8 ++++---- tests/compile-fail/deallocate-bad-size.rs | 8 ++++---- tests/compile-fail/deallocate-twice.rs | 10 +++++----- tests/compile-fail/never_transmute_humans.rs | 17 ----------------- tests/compile-fail/out_of_bounds_ptr_2.rs | 2 +- tests/compile-fail/ptr_offset_overflow.rs | 2 +- .../compile-fail/reallocate-bad-alignment-2.rs | 16 ---------------- tests/compile-fail/reallocate-bad-alignment.rs | 16 ---------------- tests/compile-fail/reallocate-bad-size.rs | 8 ++++---- tests/compile-fail/reallocate-change-alloc.rs | 10 +++++----- tests/compile-fail/reallocate-dangling.rs | 10 +++++----- tests/compile-fail/repeat.rs | 3 ++- tests/compile-fail/repeat2.rs | 2 ++ tests/compile-fail/transmute_fat.rs | 3 +-- tests/compile-fail/transmute_fat2.rs | 2 -- tests/compile-fail/validation_aliasing_mut1.rs | 2 ++ tests/compile-fail/validation_aliasing_mut2.rs | 2 ++ tests/compile-fail/validation_aliasing_mut3.rs | 2 ++ tests/compile-fail/validation_aliasing_mut4.rs | 2 ++ .../validation_buggy_as_mut_slice.rs | 2 ++ .../validation_buggy_split_at_mut.rs | 2 ++ tests/compile-fail/validation_illegal_write.rs | 2 ++ tests/compile-fail/validation_lock_confusion.rs | 2 ++ .../validation_pointer_smuggling.rs | 2 ++ tests/compile-fail/validation_recover1.rs | 2 ++ tests/compile-fail/validation_recover2.rs | 2 ++ tests/compile-fail/validation_recover3.rs | 2 ++ tests/compile-fail/validation_undef.rs | 2 ++ 29 files changed, 60 insertions(+), 85 deletions(-) delete mode 100644 tests/compile-fail/never_transmute_humans.rs delete mode 100644 tests/compile-fail/reallocate-bad-alignment-2.rs delete mode 100644 tests/compile-fail/reallocate-bad-alignment.rs diff --git a/tests/compile-fail/copy_nonoverlapping.rs b/tests/compile-fail/copy_nonoverlapping.rs index f4acbadfd549..18fbc61b6d07 100644 --- a/tests/compile-fail/copy_nonoverlapping.rs +++ b/tests/compile-fail/copy_nonoverlapping.rs @@ -10,8 +10,6 @@ #![feature(core_intrinsics)] -use std::intrinsics::*; - //error-pattern: copy_nonoverlapping called on overlapping ranges fn main() { diff --git a/tests/compile-fail/deallocate-bad-alignment.rs b/tests/compile-fail/deallocate-bad-alignment.rs index b64740de81f4..36e99cb11f72 100644 --- a/tests/compile-fail/deallocate-bad-alignment.rs +++ b/tests/compile-fail/deallocate-bad-alignment.rs @@ -2,14 +2,14 @@ extern crate alloc; -use alloc::heap::Heap; -use alloc::allocator::*; +use alloc::alloc::Global; +use std::alloc::*; // error-pattern: incorrect alloc info: expected size 1 and align 2, got size 1 and align 1 fn main() { unsafe { - let x = Heap.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); - Heap.dealloc(x, Layout::from_size_align_unchecked(1, 2)); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)); + Global.dealloc(x, Layout::from_size_align_unchecked(1, 2)); } } diff --git a/tests/compile-fail/deallocate-bad-size.rs b/tests/compile-fail/deallocate-bad-size.rs index f5b82f65d2af..f1271cefd1ac 100644 --- a/tests/compile-fail/deallocate-bad-size.rs +++ b/tests/compile-fail/deallocate-bad-size.rs @@ -2,14 +2,14 @@ extern crate alloc; -use alloc::heap::Heap; -use alloc::allocator::*; +use alloc::alloc::Global; +use std::alloc::*; // error-pattern: incorrect alloc info: expected size 2 and align 1, got size 1 and align 1 fn main() { unsafe { - let x = Heap.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); - Heap.dealloc(x, Layout::from_size_align_unchecked(2, 1)); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)); + Global.dealloc(x, Layout::from_size_align_unchecked(2, 1)); } } diff --git a/tests/compile-fail/deallocate-twice.rs b/tests/compile-fail/deallocate-twice.rs index e11df0eb4147..58fcb7409495 100644 --- a/tests/compile-fail/deallocate-twice.rs +++ b/tests/compile-fail/deallocate-twice.rs @@ -2,15 +2,15 @@ extern crate alloc; -use alloc::heap::Heap; -use alloc::allocator::*; +use alloc::alloc::Global; +use std::alloc::*; // error-pattern: tried to deallocate dangling pointer fn main() { unsafe { - let x = Heap.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); - Heap.dealloc(x, Layout::from_size_align_unchecked(1, 1)); - Heap.dealloc(x, Layout::from_size_align_unchecked(1, 1)); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)); + Global.dealloc(x, Layout::from_size_align_unchecked(1, 1)); + Global.dealloc(x, Layout::from_size_align_unchecked(1, 1)); } } diff --git a/tests/compile-fail/never_transmute_humans.rs b/tests/compile-fail/never_transmute_humans.rs deleted file mode 100644 index 7390596cf7fa..000000000000 --- a/tests/compile-fail/never_transmute_humans.rs +++ /dev/null @@ -1,17 +0,0 @@ -// This should fail even without validation -// compile-flags: -Zmir-emit-validate=0 - -#![feature(never_type)] -#![allow(unreachable_code)] -#![allow(unused_variables)] - -struct Human; - -fn main() { - let x: ! = unsafe { - std::mem::transmute::(Human) //~ ERROR entered unreachable code - }; - f(x) -} - -fn f(x: !) -> ! { x } diff --git a/tests/compile-fail/out_of_bounds_ptr_2.rs b/tests/compile-fail/out_of_bounds_ptr_2.rs index f7546494574b..e19a616a1916 100644 --- a/tests/compile-fail/out_of_bounds_ptr_2.rs +++ b/tests/compile-fail/out_of_bounds_ptr_2.rs @@ -1,4 +1,4 @@ -// error-pattern: overflowing math +// error-pattern: attempt to add with overflow fn main() { let v = [0i8; 4]; let x = &v as *const i8; diff --git a/tests/compile-fail/ptr_offset_overflow.rs b/tests/compile-fail/ptr_offset_overflow.rs index 578468c3399b..32ab2daebf0d 100644 --- a/tests/compile-fail/ptr_offset_overflow.rs +++ b/tests/compile-fail/ptr_offset_overflow.rs @@ -1,4 +1,4 @@ -//error-pattern: overflowing math +//error-pattern: attempt to add with overflow fn main() { let v = [1i8, 2]; let x = &v[1] as *const i8; diff --git a/tests/compile-fail/reallocate-bad-alignment-2.rs b/tests/compile-fail/reallocate-bad-alignment-2.rs deleted file mode 100644 index fae8246c5d29..000000000000 --- a/tests/compile-fail/reallocate-bad-alignment-2.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![feature(alloc, allocator_api)] - -extern crate alloc; - -use alloc::heap::Heap; -use alloc::allocator::*; - -// error-pattern: incorrect alloc info: expected size 1 and align 2, got size 1 and align 1 - -fn main() { - unsafe { - let x = Heap.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); - // Try realloc with a too big alignment. - let _y = Heap.realloc(x, Layout::from_size_align_unchecked(1, 2), Layout::from_size_align_unchecked(1, 1)).unwrap(); - } -} diff --git a/tests/compile-fail/reallocate-bad-alignment.rs b/tests/compile-fail/reallocate-bad-alignment.rs deleted file mode 100644 index 6a928de07eec..000000000000 --- a/tests/compile-fail/reallocate-bad-alignment.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![feature(alloc, allocator_api)] - -extern crate alloc; - -use alloc::heap::Heap; -use alloc::allocator::*; - -// error-pattern: incorrect alloc info: expected size 1 and align 1, got size 1 and align 2 - -fn main() { - unsafe { - let x = Heap.alloc(Layout::from_size_align_unchecked(1, 2)).unwrap(); - // Try realloc with a too small alignment. - let _y = Heap.realloc(x, Layout::from_size_align_unchecked(1, 1), Layout::from_size_align_unchecked(1, 2)).unwrap(); - } -} diff --git a/tests/compile-fail/reallocate-bad-size.rs b/tests/compile-fail/reallocate-bad-size.rs index d57c610d9337..d75c195d521e 100644 --- a/tests/compile-fail/reallocate-bad-size.rs +++ b/tests/compile-fail/reallocate-bad-size.rs @@ -2,14 +2,14 @@ extern crate alloc; -use alloc::heap::Heap; -use alloc::allocator::*; +use alloc::alloc::Global; +use std::alloc::*; // error-pattern: incorrect alloc info: expected size 2 and align 1, got size 1 and align 1 fn main() { unsafe { - let x = Heap.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); - let _y = Heap.realloc(x, Layout::from_size_align_unchecked(2, 1), Layout::from_size_align_unchecked(1, 1)).unwrap(); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)); + let _y = Global.realloc(x, Layout::from_size_align_unchecked(2, 1), 1); } } diff --git a/tests/compile-fail/reallocate-change-alloc.rs b/tests/compile-fail/reallocate-change-alloc.rs index 290c966a2bc8..8a788104d869 100644 --- a/tests/compile-fail/reallocate-change-alloc.rs +++ b/tests/compile-fail/reallocate-change-alloc.rs @@ -2,13 +2,13 @@ extern crate alloc; -use alloc::heap::Heap; -use alloc::allocator::*; +use alloc::alloc::Global; +use std::alloc::*; fn main() { unsafe { - let x = Heap.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); - let _y = Heap.realloc(x, Layout::from_size_align_unchecked(1, 1), Layout::from_size_align_unchecked(1, 1)).unwrap(); - let _z = *x; //~ ERROR: dangling pointer was dereferenced + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)); + let _y = Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1); + let _z = *(x as *mut u8); //~ ERROR: dangling pointer was dereferenced } } diff --git a/tests/compile-fail/reallocate-dangling.rs b/tests/compile-fail/reallocate-dangling.rs index 6225879a5a2a..39b60407160e 100644 --- a/tests/compile-fail/reallocate-dangling.rs +++ b/tests/compile-fail/reallocate-dangling.rs @@ -2,15 +2,15 @@ extern crate alloc; -use alloc::heap::Heap; -use alloc::allocator::*; +use alloc::alloc::Global; +use std::alloc::*; // error-pattern: dangling pointer was dereferenced fn main() { unsafe { - let x = Heap.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); - Heap.dealloc(x, Layout::from_size_align_unchecked(1, 1)); - Heap.realloc(x, Layout::from_size_align_unchecked(1, 1), Layout::from_size_align_unchecked(1, 1)); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)); + Global.dealloc(x, Layout::from_size_align_unchecked(1, 1)); + Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1); } } diff --git a/tests/compile-fail/repeat.rs b/tests/compile-fail/repeat.rs index abe89e233e7c..0367580f4ce9 100644 --- a/tests/compile-fail/repeat.rs +++ b/tests/compile-fail/repeat.rs @@ -1,5 +1,6 @@ +// error-pattern the type `[u8; + fn main() { let data: [u8; std::usize::MAX] = [42; std::usize::MAX]; - //~^ ERROR: rustc layout computation failed: SizeOverflow([u8; assert_eq!(data.len(), 1024); } diff --git a/tests/compile-fail/repeat2.rs b/tests/compile-fail/repeat2.rs index 61aa855a798f..16cd9c1df813 100644 --- a/tests/compile-fail/repeat2.rs +++ b/tests/compile-fail/repeat2.rs @@ -1,3 +1,5 @@ +// ignore-test + fn main() { let data: [u8; 1024*1024*1024] = [42; 1024*1024*1024]; //~^ ERROR: tried to allocate diff --git a/tests/compile-fail/transmute_fat.rs b/tests/compile-fail/transmute_fat.rs index 7d5d95a1dc6d..a2ebb6b21aa2 100644 --- a/tests/compile-fail/transmute_fat.rs +++ b/tests/compile-fail/transmute_fat.rs @@ -1,6 +1,5 @@ // This should fail even without validation // compile-flags: -Zmir-emit-validate=0 -#![feature(i128_type)] fn main() { #[cfg(target_pointer_width="64")] @@ -11,5 +10,5 @@ fn main() { let bad = unsafe { std::mem::transmute::<&[u8], u64>(&[1u8]) }; - bad + 1; //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes + let _ = bad + 1; //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/transmute_fat2.rs b/tests/compile-fail/transmute_fat2.rs index 028ed613eee7..3121a139d920 100644 --- a/tests/compile-fail/transmute_fat2.rs +++ b/tests/compile-fail/transmute_fat2.rs @@ -1,5 +1,3 @@ -#![feature(i128_type)] - fn main() { #[cfg(target_pointer_width="64")] let bad = unsafe { diff --git a/tests/compile-fail/validation_aliasing_mut1.rs b/tests/compile-fail/validation_aliasing_mut1.rs index 86aa57447fe6..e812e13e702c 100644 --- a/tests/compile-fail/validation_aliasing_mut1.rs +++ b/tests/compile-fail/validation_aliasing_mut1.rs @@ -1,3 +1,5 @@ +// ignore-test validation_op is disabled + #![allow(unused_variables)] mod safe { diff --git a/tests/compile-fail/validation_aliasing_mut2.rs b/tests/compile-fail/validation_aliasing_mut2.rs index ed7497e5e546..36ebcc2b4ac6 100644 --- a/tests/compile-fail/validation_aliasing_mut2.rs +++ b/tests/compile-fail/validation_aliasing_mut2.rs @@ -1,3 +1,5 @@ +// ignore-test validation_op is disabled + #![allow(unused_variables)] mod safe { diff --git a/tests/compile-fail/validation_aliasing_mut3.rs b/tests/compile-fail/validation_aliasing_mut3.rs index 69fbbc167ca0..ad50fbd61b45 100644 --- a/tests/compile-fail/validation_aliasing_mut3.rs +++ b/tests/compile-fail/validation_aliasing_mut3.rs @@ -1,3 +1,5 @@ +// ignore-test validation_op is disabled + #![allow(unused_variables)] mod safe { diff --git a/tests/compile-fail/validation_aliasing_mut4.rs b/tests/compile-fail/validation_aliasing_mut4.rs index 3dac55aeaac9..a0f0a3cf9753 100644 --- a/tests/compile-fail/validation_aliasing_mut4.rs +++ b/tests/compile-fail/validation_aliasing_mut4.rs @@ -1,3 +1,5 @@ +// ignore-test validation_op is disabled + #![allow(unused_variables)] mod safe { diff --git a/tests/compile-fail/validation_buggy_as_mut_slice.rs b/tests/compile-fail/validation_buggy_as_mut_slice.rs index 98eca8d3607f..282e536ce9b7 100644 --- a/tests/compile-fail/validation_buggy_as_mut_slice.rs +++ b/tests/compile-fail/validation_buggy_as_mut_slice.rs @@ -1,3 +1,5 @@ +// ignore-test validation_op is disabled + #![allow(unused_variables)] // For some reason, the error location is different when using fullmir diff --git a/tests/compile-fail/validation_buggy_split_at_mut.rs b/tests/compile-fail/validation_buggy_split_at_mut.rs index 9e67b2a4ab18..a750f1466f51 100644 --- a/tests/compile-fail/validation_buggy_split_at_mut.rs +++ b/tests/compile-fail/validation_buggy_split_at_mut.rs @@ -1,3 +1,5 @@ +// ignore-test validation_op is disabled + #![allow(unused_variables)] mod safe { diff --git a/tests/compile-fail/validation_illegal_write.rs b/tests/compile-fail/validation_illegal_write.rs index 1432f4cc9f17..cb3e4b3c1a20 100644 --- a/tests/compile-fail/validation_illegal_write.rs +++ b/tests/compile-fail/validation_illegal_write.rs @@ -1,3 +1,5 @@ +// ignore-test validation_op is disabled + #![allow(unused_variables)] mod safe { diff --git a/tests/compile-fail/validation_lock_confusion.rs b/tests/compile-fail/validation_lock_confusion.rs index b352346114d7..2a0857659622 100644 --- a/tests/compile-fail/validation_lock_confusion.rs +++ b/tests/compile-fail/validation_lock_confusion.rs @@ -1,3 +1,5 @@ +// ignore-test validation_op is disabled + // Make sure validation can handle many overlapping shared borrows for different parts of a data structure #![allow(unused_variables)] use std::cell::RefCell; diff --git a/tests/compile-fail/validation_pointer_smuggling.rs b/tests/compile-fail/validation_pointer_smuggling.rs index 3320d2a89d35..14d624286038 100644 --- a/tests/compile-fail/validation_pointer_smuggling.rs +++ b/tests/compile-fail/validation_pointer_smuggling.rs @@ -1,3 +1,5 @@ +// ignore-test validation_op is disabled + #![allow(unused_variables)] static mut PTR: *mut u8 = 0 as *mut _; diff --git a/tests/compile-fail/validation_recover1.rs b/tests/compile-fail/validation_recover1.rs index 55c38a694c55..9061070ef67e 100644 --- a/tests/compile-fail/validation_recover1.rs +++ b/tests/compile-fail/validation_recover1.rs @@ -1,3 +1,5 @@ +// ignore-test validation_op is disabled + #![allow(unused_variables)] #[repr(u32)] diff --git a/tests/compile-fail/validation_recover2.rs b/tests/compile-fail/validation_recover2.rs index 756be9fde6fc..7a4a417ab1db 100644 --- a/tests/compile-fail/validation_recover2.rs +++ b/tests/compile-fail/validation_recover2.rs @@ -1,3 +1,5 @@ +// ignore-test validation_op is disabled + #![allow(unused_variables)] mod safe { diff --git a/tests/compile-fail/validation_recover3.rs b/tests/compile-fail/validation_recover3.rs index afe6fe7c0bb9..5cfc8aaa66b5 100644 --- a/tests/compile-fail/validation_recover3.rs +++ b/tests/compile-fail/validation_recover3.rs @@ -1,3 +1,5 @@ +// ignore-test validation_op is disabled + #![allow(unused_variables)] mod safe { diff --git a/tests/compile-fail/validation_undef.rs b/tests/compile-fail/validation_undef.rs index b889b1ea5317..939e93a264e8 100644 --- a/tests/compile-fail/validation_undef.rs +++ b/tests/compile-fail/validation_undef.rs @@ -1,3 +1,5 @@ +// ignore-test validation_op is disabled + #![allow(unused_variables)] // error-pattern: attempted to read undefined bytes From 569792acbc6fccc13a7cb7377948912f6bba0aab Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Wed, 9 May 2018 17:30:16 +0200 Subject: [PATCH 0101/5092] Address some review comments --- tests/compile-fail/never_transmute_humans.rs | 18 ++++++++++++++++++ tests/compile-fail/oom2.rs | 14 -------------- tests/compile-fail/repeat2.rs | 7 ------- tests/compile-fail/timeout.rs | 9 --------- tests/compiletest.rs | 2 +- 5 files changed, 19 insertions(+), 31 deletions(-) create mode 100644 tests/compile-fail/never_transmute_humans.rs delete mode 100644 tests/compile-fail/oom2.rs delete mode 100644 tests/compile-fail/repeat2.rs delete mode 100644 tests/compile-fail/timeout.rs diff --git a/tests/compile-fail/never_transmute_humans.rs b/tests/compile-fail/never_transmute_humans.rs new file mode 100644 index 000000000000..d0662c917ba7 --- /dev/null +++ b/tests/compile-fail/never_transmute_humans.rs @@ -0,0 +1,18 @@ +// This should fail even without validation +// compile-fail causes rustc ICE: rust-lang/rust#50570 +// compile-flags: -Zmir-emit-validate=0 + +#![feature(never_type)] +#![allow(unreachable_code)] +#![allow(unused_variables)] + +struct Human; + +fn main() { + let x: ! = unsafe { + std::mem::transmute::(Human) //~ ERROR entered unreachable code + }; + f(x) +} + +fn f(x: !) -> ! { x } diff --git a/tests/compile-fail/oom2.rs b/tests/compile-fail/oom2.rs deleted file mode 100644 index 6c973bcf4016..000000000000 --- a/tests/compile-fail/oom2.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Validation forces more allocation; disable it. -// compile-flags: -Zmir-emit-validate=0 -#![feature(box_syntax, custom_attribute, attr_literals)] -#![miri(memory_size=1024)] - -// On 64bit platforms, the allocator needs 32 bytes allocated to pass a return value, so that's the error we see. -// On 32bit platforms, it's just 16 bytes. -// error-pattern: tried to allocate - -fn main() { - loop { - ::std::mem::forget(box 42); - } -} diff --git a/tests/compile-fail/repeat2.rs b/tests/compile-fail/repeat2.rs deleted file mode 100644 index 16cd9c1df813..000000000000 --- a/tests/compile-fail/repeat2.rs +++ /dev/null @@ -1,7 +0,0 @@ -// ignore-test - -fn main() { - let data: [u8; 1024*1024*1024] = [42; 1024*1024*1024]; - //~^ ERROR: tried to allocate - assert_eq!(data.len(), 1024*1024*1024); -} diff --git a/tests/compile-fail/timeout.rs b/tests/compile-fail/timeout.rs deleted file mode 100644 index edd4c3186691..000000000000 --- a/tests/compile-fail/timeout.rs +++ /dev/null @@ -1,9 +0,0 @@ -//error-pattern: reached the configured maximum execution time -#![feature(custom_attribute, attr_literals)] -#![miri(step_limit=1000)] - -fn main() { - for i in 0..1000000 { - assert!(i < 1000); - } -} diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 3fb7f2784a6a..e62fa4e65e63 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -203,7 +203,7 @@ fn run_pass_rustc() { } #[test] -#[ignore] // TODO: update test errors +#[should_panic] // TODO: update test errors fn compile_fail_miri() { let sysroot = get_sysroot(); let host = get_host(); From 8ae66db798ae61342442eaafca8cd4dddab47a91 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Wed, 9 May 2018 17:45:16 +0200 Subject: [PATCH 0102/5092] Convert some of the tests to the new format --- tests/compile-fail/alignment.rs | 3 ++- tests/compile-fail/assume.rs | 3 ++- tests/compile-fail/bitop-beyond-alignment.rs | 5 +++-- tests/compile-fail/cast_box_int_to_fn_ptr.rs | 3 ++- tests/compile-fail/cast_fn_ptr.rs | 3 ++- tests/compile-fail/cast_fn_ptr2.rs | 3 ++- tests/compile-fail/cast_int_to_fn_ptr.rs | 3 ++- tests/compile-fail/ctlz_nonzero.rs | 3 ++- tests/compile-fail/cttz_nonzero.rs | 3 ++- tests/compile-fail/dangling_pointer_deref.rs | 3 ++- tests/compile-fail/deref_fn_ptr.rs | 3 ++- tests/compile-fail/div-by-zero-2.rs | 3 ++- tests/compile-fail/execute_memory.rs | 3 ++- tests/compile-fail/fn_ptr_offset.rs | 3 ++- tests/compile-fail/invalid_bool.rs | 5 +++-- tests/compile-fail/invalid_enum_discriminant.rs | 5 +++-- tests/compile-fail/modifying_constants.rs | 3 ++- tests/compile-fail/never_say_never.rs | 3 ++- tests/compile-fail/never_transmute_humans.rs | 2 +- tests/compile-fail/never_transmute_void.rs | 5 +++-- tests/compile-fail/null_pointer_deref.rs | 3 ++- tests/compile-fail/oom.rs | 7 ------- tests/compile-fail/out_of_bounds_read.rs | 3 ++- tests/compile-fail/out_of_bounds_read2.rs | 3 ++- tests/compile-fail/overflowing-lsh-neg.rs | 3 ++- tests/compile-fail/overflowing-rsh.rs | 3 ++- ...rwriting_part_of_relocation_makes_the_rest_undefined.rs | 3 ++- tests/compile-fail/pointer_byte_read_1.rs | 3 ++- tests/compile-fail/pointer_byte_read_2.rs | 3 ++- .../pointers_to_different_allocations_are_unorderable.rs | 3 ++- tests/compile-fail/ptr_bitops.rs | 3 ++- tests/compile-fail/ptr_int_cast.rs | 3 ++- tests/compile-fail/reading_half_a_pointer.rs | 3 ++- tests/compile-fail/reallocate-change-alloc.rs | 3 ++- tests/compile-fail/reference_to_packed.rs | 3 ++- tests/compile-fail/static_memory_modification2.rs | 3 ++- tests/compile-fail/static_memory_modification3.rs | 3 ++- tests/compile-fail/transmute-pair-undef.rs | 3 ++- tests/compile-fail/transmute_fat.rs | 3 ++- tests/compile-fail/transmute_fat2.rs | 3 ++- tests/compile-fail/unaligned_ptr_cast.rs | 3 ++- tests/compile-fail/unaligned_ptr_cast2.rs | 3 ++- tests/compile-fail/unaligned_ptr_cast_zst.rs | 3 ++- tests/compile-fail/wild_pointer_deref.rs | 3 ++- tests/compile-fail/zst.rs | 3 ++- 45 files changed, 91 insertions(+), 55 deletions(-) delete mode 100644 tests/compile-fail/oom.rs diff --git a/tests/compile-fail/alignment.rs b/tests/compile-fail/alignment.rs index 4faaa359df62..9730fe473aa5 100644 --- a/tests/compile-fail/alignment.rs +++ b/tests/compile-fail/alignment.rs @@ -5,7 +5,8 @@ fn main() { let x_ptr: *mut u8 = &mut x[0]; let y_ptr = x_ptr as *mut u64; unsafe { - *y_ptr = 42; //~ ERROR tried to access memory with alignment 1, but alignment + *y_ptr = 42; //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to access memory with alignment 1, but alignment } panic!("unreachable in miri"); } diff --git a/tests/compile-fail/assume.rs b/tests/compile-fail/assume.rs index 69758a5d7fe8..cf0632393ad6 100644 --- a/tests/compile-fail/assume.rs +++ b/tests/compile-fail/assume.rs @@ -5,6 +5,7 @@ fn main() { unsafe { std::intrinsics::assume(x < 10); std::intrinsics::assume(x > 1); - std::intrinsics::assume(x > 42); //~ ERROR: `assume` argument was false + std::intrinsics::assume(x > 42); //~ ERROR constant evaluation error [E0080] + //~^ NOTE `assume` argument was false } } diff --git a/tests/compile-fail/bitop-beyond-alignment.rs b/tests/compile-fail/bitop-beyond-alignment.rs index a30c054ab5d0..89f5e048a36d 100644 --- a/tests/compile-fail/bitop-beyond-alignment.rs +++ b/tests/compile-fail/bitop-beyond-alignment.rs @@ -28,10 +28,11 @@ fn mk_rec() -> Rec { fn is_u64_aligned(u: &Tag) -> bool { let p: usize = unsafe { mem::transmute(u) }; let u64_align = std::mem::align_of::(); - return (p & (u64_align + 1)) == 0; //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes + return (p & (u64_align + 1)) == 0; //~ ERROR constant evaluation error [E0080] + //~^ NOTE a raw memory access tried to access part of a pointer value as raw bytes } pub fn main() { let x = mk_rec(); - assert!(is_u64_aligned(&x.t)); + assert!(is_u64_aligned(&x.t)); //~ NOTE inside call to `is_u64_aligned } diff --git a/tests/compile-fail/cast_box_int_to_fn_ptr.rs b/tests/compile-fail/cast_box_int_to_fn_ptr.rs index 912b1bd7d91f..39b53da0b75c 100644 --- a/tests/compile-fail/cast_box_int_to_fn_ptr.rs +++ b/tests/compile-fail/cast_box_int_to_fn_ptr.rs @@ -7,5 +7,6 @@ fn main() { std::mem::transmute::<&usize, &fn(i32)>(&b) }; - (*g)(42) //~ ERROR a memory access tried to interpret some bytes as a pointer + (*g)(42) //~ ERROR constant evaluation error [E0080] + //~^ NOTE a memory access tried to interpret some bytes as a pointer } diff --git a/tests/compile-fail/cast_fn_ptr.rs b/tests/compile-fail/cast_fn_ptr.rs index 7509ae6ed77c..19344b13ba7c 100644 --- a/tests/compile-fail/cast_fn_ptr.rs +++ b/tests/compile-fail/cast_fn_ptr.rs @@ -5,5 +5,6 @@ fn main() { std::mem::transmute::(f) }; - g(42) //~ ERROR tried to call a function with sig fn() through a function pointer of type fn(i32) + g(42) //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to call a function with sig fn() through a function pointer of type fn(i32) } diff --git a/tests/compile-fail/cast_fn_ptr2.rs b/tests/compile-fail/cast_fn_ptr2.rs index 5d902e1f9aaa..23868c0e57db 100644 --- a/tests/compile-fail/cast_fn_ptr2.rs +++ b/tests/compile-fail/cast_fn_ptr2.rs @@ -5,5 +5,6 @@ fn main() { std::mem::transmute::(f) }; - g(42) //~ ERROR tried to call a function with sig fn((i32, i32)) through a function pointer of type fn(i32) + g(42) //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to call a function with sig fn((i32, i32)) through a function pointer of type fn(i32) } diff --git a/tests/compile-fail/cast_int_to_fn_ptr.rs b/tests/compile-fail/cast_int_to_fn_ptr.rs index 23f85dbaf3ec..c7556ae06b93 100644 --- a/tests/compile-fail/cast_int_to_fn_ptr.rs +++ b/tests/compile-fail/cast_int_to_fn_ptr.rs @@ -6,5 +6,6 @@ fn main() { std::mem::transmute::(42) }; - g(42) //~ ERROR a memory access tried to interpret some bytes as a pointer + g(42) //~ ERROR constant evaluation error [E0080] + //~^ NOTE a memory access tried to interpret some bytes as a pointer } diff --git a/tests/compile-fail/ctlz_nonzero.rs b/tests/compile-fail/ctlz_nonzero.rs index 704c4d4b7d46..d952187eba45 100644 --- a/tests/compile-fail/ctlz_nonzero.rs +++ b/tests/compile-fail/ctlz_nonzero.rs @@ -10,6 +10,7 @@ pub fn main() { unsafe { use rusti::*; - ctlz_nonzero(0u8); //~ ERROR: ctlz_nonzero called on 0 + ctlz_nonzero(0u8); //~ ERROR constant evaluation error [E0080] + //~^ NOTE ctlz_nonzero called on 0 } } diff --git a/tests/compile-fail/cttz_nonzero.rs b/tests/compile-fail/cttz_nonzero.rs index eda25c661521..b308484622bc 100644 --- a/tests/compile-fail/cttz_nonzero.rs +++ b/tests/compile-fail/cttz_nonzero.rs @@ -10,6 +10,7 @@ pub fn main() { unsafe { use rusti::*; - cttz_nonzero(0u8); //~ ERROR: cttz_nonzero called on 0 + cttz_nonzero(0u8); //~ ERROR constant evaluation error [E0080] + //~^ NOTE cttz_nonzero called on 0 } } diff --git a/tests/compile-fail/dangling_pointer_deref.rs b/tests/compile-fail/dangling_pointer_deref.rs index 0ede7c96f004..d42c1d33b530 100644 --- a/tests/compile-fail/dangling_pointer_deref.rs +++ b/tests/compile-fail/dangling_pointer_deref.rs @@ -3,6 +3,7 @@ fn main() { let b = Box::new(42); &*b as *const i32 }; - let x = unsafe { *p }; //~ ERROR: dangling pointer was dereferenced + let x = unsafe { *p }; //~ ERROR constant evaluation error [E0080] + //~^ NOTE dangling pointer was dereferenced panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/deref_fn_ptr.rs b/tests/compile-fail/deref_fn_ptr.rs index c1eaf7eaa61d..a56df5bce408 100644 --- a/tests/compile-fail/deref_fn_ptr.rs +++ b/tests/compile-fail/deref_fn_ptr.rs @@ -2,7 +2,8 @@ fn f() {} fn main() { let x: i32 = unsafe { - *std::mem::transmute::(f) //~ ERROR: tried to dereference a function pointer + *std::mem::transmute::(f) //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to dereference a function pointer }; panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/div-by-zero-2.rs b/tests/compile-fail/div-by-zero-2.rs index 3e869ad4a507..c90ca8d15cce 100644 --- a/tests/compile-fail/div-by-zero-2.rs +++ b/tests/compile-fail/div-by-zero-2.rs @@ -11,5 +11,6 @@ #![allow(const_err)] fn main() { - let _n = 1 / 0; //~ ERROR: DivisionByZero + let _n = 1 / 0; //~ ERROR constant evaluation error [E0080] + //~^ NOTE attempt to divide by zero } diff --git a/tests/compile-fail/execute_memory.rs b/tests/compile-fail/execute_memory.rs index 87d975e1f9d4..014c551df0f1 100644 --- a/tests/compile-fail/execute_memory.rs +++ b/tests/compile-fail/execute_memory.rs @@ -7,6 +7,7 @@ fn main() { let x = box 42; unsafe { let f = std::mem::transmute::, fn()>(x); - f() //~ ERROR: tried to treat a memory pointer as a function pointer + f() //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to treat a memory pointer as a function pointer } } diff --git a/tests/compile-fail/fn_ptr_offset.rs b/tests/compile-fail/fn_ptr_offset.rs index 45e32142a8c4..20eb6573989c 100644 --- a/tests/compile-fail/fn_ptr_offset.rs +++ b/tests/compile-fail/fn_ptr_offset.rs @@ -10,5 +10,6 @@ fn main() { let y : *mut u8 = unsafe { mem::transmute(x) }; let y = y.wrapping_offset(1); let x : fn() = unsafe { mem::transmute(y) }; - x(); //~ ERROR: tried to use a function pointer after offsetting it + x(); //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to use a function pointer after offsetting it } diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index c30c9b439a46..07c407966a8f 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -1,4 +1,5 @@ fn main() { - let b = unsafe { std::mem::transmute::(2) }; //~ ERROR: invalid boolean value read - if b { unreachable!() } else { unreachable!() } + let b = unsafe { std::mem::transmute::(2) }; + if b { unreachable!() } else { unreachable!() } //~ ERROR constant evaluation error [E0080] + //~^ NOTE invalid boolean value read } diff --git a/tests/compile-fail/invalid_enum_discriminant.rs b/tests/compile-fail/invalid_enum_discriminant.rs index 9ce6d44ca460..69d7e3e427d4 100644 --- a/tests/compile-fail/invalid_enum_discriminant.rs +++ b/tests/compile-fail/invalid_enum_discriminant.rs @@ -9,9 +9,10 @@ pub enum Foo { fn main() { let f = unsafe { std::mem::transmute::(42) }; match f { - Foo::A => {}, //~ ERROR invalid enum discriminant value read + Foo::A => {}, Foo::B => {}, Foo::C => {}, Foo::D => {}, } -} +} //~ ERROR constant evaluation error [E0080] +//~^ NOTE entered unreachable code diff --git a/tests/compile-fail/modifying_constants.rs b/tests/compile-fail/modifying_constants.rs index cb2e7217d579..06920fa0acf1 100644 --- a/tests/compile-fail/modifying_constants.rs +++ b/tests/compile-fail/modifying_constants.rs @@ -1,6 +1,7 @@ fn main() { let x = &1; // the `&1` is promoted to a constant, but it used to be that only the pointer is marked static, not the pointee let y = unsafe { &mut *(x as *const i32 as *mut i32) }; - *y = 42; //~ ERROR tried to modify constant memory + *y = 42; //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to modify constant memory assert_eq!(*x, 42); } diff --git a/tests/compile-fail/never_say_never.rs b/tests/compile-fail/never_say_never.rs index 71306cc62bf7..de8815ffd9c4 100644 --- a/tests/compile-fail/never_say_never.rs +++ b/tests/compile-fail/never_say_never.rs @@ -7,7 +7,8 @@ fn main() { let y = &5; let x: ! = unsafe { - *(y as *const _ as *const !) //~ ERROR entered unreachable code + *(y as *const _ as *const !) //~ ERROR constant evaluation error [E0080] + //~^ NOTE entered unreachable code }; f(x) } diff --git a/tests/compile-fail/never_transmute_humans.rs b/tests/compile-fail/never_transmute_humans.rs index d0662c917ba7..3924dc7371e7 100644 --- a/tests/compile-fail/never_transmute_humans.rs +++ b/tests/compile-fail/never_transmute_humans.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-fail causes rustc ICE: rust-lang/rust#50570 +// ignore-test causes rustc ICE: rust-lang/rust#50570 // compile-flags: -Zmir-emit-validate=0 #![feature(never_type)] diff --git a/tests/compile-fail/never_transmute_void.rs b/tests/compile-fail/never_transmute_void.rs index 0b0897644409..4f1499483eda 100644 --- a/tests/compile-fail/never_transmute_void.rs +++ b/tests/compile-fail/never_transmute_void.rs @@ -8,12 +8,13 @@ enum Void {} fn f(v: Void) -> ! { - match v {} //~ ERROR entered unreachable code + match v {} //~ ERROR constant evaluation error [E0080] + //~^ NOTE entered unreachable code } fn main() { let v: Void = unsafe { std::mem::transmute::<(), Void>(()) }; - f(v); + f(v); //~ inside call to `f` } diff --git a/tests/compile-fail/null_pointer_deref.rs b/tests/compile-fail/null_pointer_deref.rs index 5a26856eba08..70df937c4c7c 100644 --- a/tests/compile-fail/null_pointer_deref.rs +++ b/tests/compile-fail/null_pointer_deref.rs @@ -1,4 +1,5 @@ fn main() { - let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR: invalid use of NULL pointer + let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR constant evaluation error [E0080] + //~^ NOTE invalid use of NULL pointer panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/oom.rs b/tests/compile-fail/oom.rs deleted file mode 100644 index d4aebb912ee1..000000000000 --- a/tests/compile-fail/oom.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![feature(custom_attribute, attr_literals)] -#![miri(memory_size=4095)] - -fn main() { - let _x = [42; 1024]; - //~^ERROR tried to allocate 4096 more bytes, but only -} diff --git a/tests/compile-fail/out_of_bounds_read.rs b/tests/compile-fail/out_of_bounds_read.rs index 8c56b14bdf22..d8811e7abcd2 100644 --- a/tests/compile-fail/out_of_bounds_read.rs +++ b/tests/compile-fail/out_of_bounds_read.rs @@ -1,5 +1,6 @@ fn main() { let v: Vec = vec![1, 2]; - let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR: which has size 2 + let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR constant evaluation error [E0080] + //~^ NOTE which has size 2 panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/out_of_bounds_read2.rs b/tests/compile-fail/out_of_bounds_read2.rs index d29b22ffb2a6..54738cf81fbd 100644 --- a/tests/compile-fail/out_of_bounds_read2.rs +++ b/tests/compile-fail/out_of_bounds_read2.rs @@ -1,5 +1,6 @@ fn main() { let v: Vec = vec![1, 2]; - let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR: memory access at offset 6, outside bounds of allocation + let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR constant evaluation error [E0080] + //~^ NOTE memory access at offset 6, outside bounds of allocation panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/overflowing-lsh-neg.rs b/tests/compile-fail/overflowing-lsh-neg.rs index 3a889be741ef..e50e42503649 100644 --- a/tests/compile-fail/overflowing-lsh-neg.rs +++ b/tests/compile-fail/overflowing-lsh-neg.rs @@ -12,5 +12,6 @@ #![allow(const_err)] fn main() { - let _n = 2i64 << -1; //~ Overflow(Shl) + let _n = 2i64 << -1; //~ ERROR constant evaluation error [E0080] + //~^ NOTE attempt to shift left with overflow } diff --git a/tests/compile-fail/overflowing-rsh.rs b/tests/compile-fail/overflowing-rsh.rs index a7ac9d1d5039..c291815e2e79 100644 --- a/tests/compile-fail/overflowing-rsh.rs +++ b/tests/compile-fail/overflowing-rsh.rs @@ -11,5 +11,6 @@ #![allow(exceeding_bitshifts)] fn main() { - let _n = 1i64 >> 64; //~ Overflow(Shr) + let _n = 1i64 >> 64; //~ ERROR constant evaluation error [E0080] + //~^ NOTE attempt to shift right with overflow } diff --git a/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs b/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs index 50f51d0ba9ca..fabbef5004d7 100644 --- a/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs +++ b/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs @@ -6,6 +6,7 @@ fn main() { // "attempted to interpret some raw bytes as a pointer address" instead of // "attempted to read undefined bytes" } - let x = *p; //~ ERROR: attempted to read undefined bytes + let x = *p; //~ ERROR constant evaluation error [E0080] + //~^ NOTE attempted to read undefined bytes panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/pointer_byte_read_1.rs b/tests/compile-fail/pointer_byte_read_1.rs index 342eb28a970f..012af897e837 100644 --- a/tests/compile-fail/pointer_byte_read_1.rs +++ b/tests/compile-fail/pointer_byte_read_1.rs @@ -3,5 +3,6 @@ fn main() { let y = &x; let z = &y as *const &i32 as *const usize; let ptr_bytes = unsafe { *z }; // the actual deref is fine, because we read the entire pointer at once - let _ = ptr_bytes % 432; //~ ERROR: tried to access part of a pointer value as raw bytes + let _ = ptr_bytes % 432; //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/pointer_byte_read_2.rs b/tests/compile-fail/pointer_byte_read_2.rs index b0f619332e00..4d25a36a3c88 100644 --- a/tests/compile-fail/pointer_byte_read_2.rs +++ b/tests/compile-fail/pointer_byte_read_2.rs @@ -3,5 +3,6 @@ fn main() { let y = &x; let z = &y as *const &i32 as *const u8; // the deref fails, because we are reading only a part of the pointer - let _ = unsafe { *z }; //~ ERROR: tried to access part of a pointer value as raw bytes + let _ = unsafe { *z }; //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs b/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs index 245b7527c55b..72ae1b123e8a 100644 --- a/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs +++ b/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs @@ -1,7 +1,8 @@ fn main() { let x: *const u8 = &1; let y: *const u8 = &2; - if x < y { //~ ERROR: attempted to do invalid arithmetic on pointers + if x < y { //~ ERROR constant evaluation error [E0080] + //~^ NOTE attempted to do invalid arithmetic on pointers unreachable!() } } diff --git a/tests/compile-fail/ptr_bitops.rs b/tests/compile-fail/ptr_bitops.rs index 78fd8e912b5e..52bcf24cf6b8 100644 --- a/tests/compile-fail/ptr_bitops.rs +++ b/tests/compile-fail/ptr_bitops.rs @@ -2,6 +2,7 @@ fn main() { let bytes = [0i8, 1, 2, 3, 4, 5, 6, 7, 8, 9]; let one = bytes.as_ptr().wrapping_offset(1); let three = bytes.as_ptr().wrapping_offset(3); - let res = (one as usize) | (three as usize); //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes + let res = (one as usize) | (three as usize); //~ ERROR constant evaluation error [E0080] + //~^ NOTE a raw memory access tried to access part of a pointer value as raw bytes println!("{}", res); } diff --git a/tests/compile-fail/ptr_int_cast.rs b/tests/compile-fail/ptr_int_cast.rs index 396c71ebb03d..56403d619ffa 100644 --- a/tests/compile-fail/ptr_int_cast.rs +++ b/tests/compile-fail/ptr_int_cast.rs @@ -2,7 +2,8 @@ fn main() { let x = &1; // Casting down to u8 and back up to a pointer loses too much precision; this must not work. let x = x as *const i32; - let x = x as u8; //~ ERROR: a raw memory access tried to access part of a pointer value as raw bytes + let x = x as u8; //~ ERROR constant evaluation error [E0080] + //~^ NOTE a raw memory access tried to access part of a pointer value as raw bytes let x = x as *const i32; let _ = unsafe { *x }; } diff --git a/tests/compile-fail/reading_half_a_pointer.rs b/tests/compile-fail/reading_half_a_pointer.rs index cc41b52f3337..e44f26c4c4cf 100644 --- a/tests/compile-fail/reading_half_a_pointer.rs +++ b/tests/compile-fail/reading_half_a_pointer.rs @@ -24,6 +24,7 @@ fn main() { // starts 1 byte to the right, so using it would actually be wrong! let d_alias = &mut w.data as *mut _ as *mut *const u8; unsafe { - let _x = *d_alias; //~ ERROR: tried to access part of a pointer value as raw bytes + let _x = *d_alias; //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to access part of a pointer value as raw bytes } } diff --git a/tests/compile-fail/reallocate-change-alloc.rs b/tests/compile-fail/reallocate-change-alloc.rs index 8a788104d869..d8234e933300 100644 --- a/tests/compile-fail/reallocate-change-alloc.rs +++ b/tests/compile-fail/reallocate-change-alloc.rs @@ -9,6 +9,7 @@ fn main() { unsafe { let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)); let _y = Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1); - let _z = *(x as *mut u8); //~ ERROR: dangling pointer was dereferenced + let _z = *(x as *mut u8); //~ ERROR constant evaluation error [E0080] + //~^ NOTE dangling pointer was dereferenced } } diff --git a/tests/compile-fail/reference_to_packed.rs b/tests/compile-fail/reference_to_packed.rs index 064386b3d010..16b452ca0e3c 100644 --- a/tests/compile-fail/reference_to_packed.rs +++ b/tests/compile-fail/reference_to_packed.rs @@ -15,5 +15,6 @@ fn main() { y: 99, }; let p = unsafe { &foo.x }; - let i = *p; //~ ERROR tried to access memory with alignment 1, but alignment 4 is required + let i = *p; //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to access memory with alignment 1, but alignment 4 is required } diff --git a/tests/compile-fail/static_memory_modification2.rs b/tests/compile-fail/static_memory_modification2.rs index f030a9c281de..6abe6de1fcf4 100644 --- a/tests/compile-fail/static_memory_modification2.rs +++ b/tests/compile-fail/static_memory_modification2.rs @@ -7,6 +7,7 @@ use std::mem::transmute; fn main() { unsafe { let s = "this is a test"; - transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; //~ ERROR: tried to modify constant memory + transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to modify constant memory } } diff --git a/tests/compile-fail/static_memory_modification3.rs b/tests/compile-fail/static_memory_modification3.rs index 743fbe60efff..0891756f0ec6 100644 --- a/tests/compile-fail/static_memory_modification3.rs +++ b/tests/compile-fail/static_memory_modification3.rs @@ -4,6 +4,7 @@ use std::mem::transmute; fn main() { unsafe { let bs = b"this is a test"; - transmute::<&[u8], &mut [u8]>(bs)[4] = 42; //~ ERROR: tried to modify constant memory + transmute::<&[u8], &mut [u8]>(bs)[4] = 42; //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to modify constant memory } } diff --git a/tests/compile-fail/transmute-pair-undef.rs b/tests/compile-fail/transmute-pair-undef.rs index acc6098af7ee..6b4fe2273a08 100644 --- a/tests/compile-fail/transmute-pair-undef.rs +++ b/tests/compile-fail/transmute-pair-undef.rs @@ -16,5 +16,6 @@ fn main() { assert_eq!(byte, 0); } let v = unsafe { *z.offset(first_undef) }; - if v == 0 {} //~ ERROR attempted to read undefined bytes + if v == 0 {} //~ ERROR constant evaluation error [E0080] + //~^ NOTE attempted to read undefined bytes } diff --git a/tests/compile-fail/transmute_fat.rs b/tests/compile-fail/transmute_fat.rs index a2ebb6b21aa2..81d783807c58 100644 --- a/tests/compile-fail/transmute_fat.rs +++ b/tests/compile-fail/transmute_fat.rs @@ -10,5 +10,6 @@ fn main() { let bad = unsafe { std::mem::transmute::<&[u8], u64>(&[1u8]) }; - let _ = bad + 1; //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes + let _ = bad + 1; //~ ERROR constant evaluation error [E0080] + //~^ NOTE a raw memory access tried to access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/transmute_fat2.rs b/tests/compile-fail/transmute_fat2.rs index 3121a139d920..96a713305e6b 100644 --- a/tests/compile-fail/transmute_fat2.rs +++ b/tests/compile-fail/transmute_fat2.rs @@ -7,5 +7,6 @@ fn main() { let bad = unsafe { std::mem::transmute::(42) }; - bad[0]; //~ ERROR index out of bounds: the len is 0 but the index is 0 + bad[0]; //~ ERROR constant evaluation error [E0080] + //~^ NOTE index out of bounds: the len is 0 but the index is 0 } diff --git a/tests/compile-fail/unaligned_ptr_cast.rs b/tests/compile-fail/unaligned_ptr_cast.rs index 8ad1b323250c..cb9523395391 100644 --- a/tests/compile-fail/unaligned_ptr_cast.rs +++ b/tests/compile-fail/unaligned_ptr_cast.rs @@ -2,5 +2,6 @@ fn main() { let x = &2u16; let x = x as *const _ as *const u32; // This must fail because alignment is violated - let _x = unsafe { *x }; //~ ERROR: tried to access memory with alignment 2, but alignment 4 is required + let _x = unsafe { *x }; //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to access memory with alignment 2, but alignment 4 is required } diff --git a/tests/compile-fail/unaligned_ptr_cast2.rs b/tests/compile-fail/unaligned_ptr_cast2.rs index 15fb7dd31368..dee2bbc9972f 100644 --- a/tests/compile-fail/unaligned_ptr_cast2.rs +++ b/tests/compile-fail/unaligned_ptr_cast2.rs @@ -3,5 +3,6 @@ fn main() { let x = x as *const _ as *const *const u8; // This must fail because alignment is violated. Test specifically for loading pointers, which have special code // in miri's memory. - let _x = unsafe { *x }; //~ ERROR: tried to access memory with alignment 2, but alignment + let _x = unsafe { *x }; //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to access memory with alignment 2, but alignment } diff --git a/tests/compile-fail/unaligned_ptr_cast_zst.rs b/tests/compile-fail/unaligned_ptr_cast_zst.rs index fc603840684e..eba17ab6c640 100644 --- a/tests/compile-fail/unaligned_ptr_cast_zst.rs +++ b/tests/compile-fail/unaligned_ptr_cast_zst.rs @@ -2,5 +2,6 @@ fn main() { let x = &2u16; let x = x as *const _ as *const [u32; 0]; // This must fail because alignment is violated. Test specifically for loading ZST. - let _x = unsafe { *x }; //~ ERROR: tried to access memory with alignment 2, but alignment 4 is required + let _x = unsafe { *x }; //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to access memory with alignment 2, but alignment 4 is required } diff --git a/tests/compile-fail/wild_pointer_deref.rs b/tests/compile-fail/wild_pointer_deref.rs index 57da8dfc01b2..035d979c5b07 100644 --- a/tests/compile-fail/wild_pointer_deref.rs +++ b/tests/compile-fail/wild_pointer_deref.rs @@ -1,5 +1,6 @@ fn main() { let p = 44 as *const i32; - let x = unsafe { *p }; //~ ERROR: a memory access tried to interpret some bytes as a pointer + let x = unsafe { *p }; //~ ERROR constant evaluation error [E0080] + //~^ NOTE a memory access tried to interpret some bytes as a pointer panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/zst.rs b/tests/compile-fail/zst.rs index 343982404794..d6518a48aa82 100644 --- a/tests/compile-fail/zst.rs +++ b/tests/compile-fail/zst.rs @@ -1,4 +1,5 @@ fn main() { let x = &() as *const () as *const i32; - let _ = unsafe { *x }; //~ ERROR: tried to access memory with alignment 1, but alignment 4 is required + let _ = unsafe { *x }; //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to access memory with alignment 1, but alignment 4 is required } From 94754de60010dba845ea9c299c9616dbc2022c86 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Wed, 9 May 2018 19:24:25 +0200 Subject: [PATCH 0103/5092] Convert legitimate failing errors to the new error format --- src/lib.rs | 1 + tests/compile-fail/match_char.rs | 3 ++- tests/compile-fail/overflowing-rsh-2.rs | 3 ++- tests/compile-fail/repeat.rs | 6 ------ tests/compile-fail/static_memory_modification.rs | 3 ++- 5 files changed, 7 insertions(+), 9 deletions(-) delete mode 100644 tests/compile-fail/repeat.rs diff --git a/src/lib.rs b/src/lib.rs index 1ba763349aa7..e8bbe164611d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -249,6 +249,7 @@ pub fn eval_main<'a, 'tcx: 'a>( Ok(()) => { let leaks = ecx.memory().leak_report(); if leaks != 0 { + // TODO: Prevent leaks which aren't supposed to be there //tcx.sess.err("the evaluated program leaked memory"); } } diff --git a/tests/compile-fail/match_char.rs b/tests/compile-fail/match_char.rs index 4fee6e692bad..15ce2f2f7952 100644 --- a/tests/compile-fail/match_char.rs +++ b/tests/compile-fail/match_char.rs @@ -1,6 +1,7 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); - match unsafe { std::mem::transmute::(-1) } { //~ERROR tried to interpret an invalid 32-bit value as a char: 4294967295 + match unsafe { std::mem::transmute::(-1) } { //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to interpret an invalid 32-bit value as a char: 4294967295 'a' => {}, 'b' => {}, _ => {}, diff --git a/tests/compile-fail/overflowing-rsh-2.rs b/tests/compile-fail/overflowing-rsh-2.rs index ac09a1740c43..4447b9d7579a 100644 --- a/tests/compile-fail/overflowing-rsh-2.rs +++ b/tests/compile-fail/overflowing-rsh-2.rs @@ -12,5 +12,6 @@ fn main() { // Make sure we catch overflows that would be hidden by first casting the RHS to u32 - let _n = 1i64 >> (u32::max_value() as i64 + 1); //~ Overflow(Shr) + let _n = 1i64 >> (u32::max_value() as i64 + 1); //~ ERROR constant evaluation error [E0080] + //~^ NOTE suiriuruihrihue } diff --git a/tests/compile-fail/repeat.rs b/tests/compile-fail/repeat.rs deleted file mode 100644 index 0367580f4ce9..000000000000 --- a/tests/compile-fail/repeat.rs +++ /dev/null @@ -1,6 +0,0 @@ -// error-pattern the type `[u8; - -fn main() { - let data: [u8; std::usize::MAX] = [42; std::usize::MAX]; - assert_eq!(data.len(), 1024); -} diff --git a/tests/compile-fail/static_memory_modification.rs b/tests/compile-fail/static_memory_modification.rs index 11961becb246..7182f40d994d 100644 --- a/tests/compile-fail/static_memory_modification.rs +++ b/tests/compile-fail/static_memory_modification.rs @@ -3,7 +3,8 @@ static X: usize = 5; #[allow(mutable_transmutes)] fn main() { unsafe { - *std::mem::transmute::<&usize, &mut usize>(&X) = 6; //~ ERROR: tried to modify constant memory + *std::mem::transmute::<&usize, &mut usize>(&X) = 6; //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to modify constant memory assert_eq!(X, 6); } } From ac25a513af7900a5ad2b10498d50591f28ba0db4 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 20 May 2018 15:08:15 +0200 Subject: [PATCH 0104/5092] Re-enable never_transmute_humans.rs --- tests/compile-fail/never_transmute_humans.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/compile-fail/never_transmute_humans.rs b/tests/compile-fail/never_transmute_humans.rs index 3924dc7371e7..3422d52f9c04 100644 --- a/tests/compile-fail/never_transmute_humans.rs +++ b/tests/compile-fail/never_transmute_humans.rs @@ -1,5 +1,4 @@ // This should fail even without validation -// ignore-test causes rustc ICE: rust-lang/rust#50570 // compile-flags: -Zmir-emit-validate=0 #![feature(never_type)] @@ -10,7 +9,8 @@ struct Human; fn main() { let x: ! = unsafe { - std::mem::transmute::(Human) //~ ERROR entered unreachable code + std::mem::transmute::(Human) //~ ERROR constant evaluation error [E0080] + //^~ NOTE entered unreachable code }; f(x) } From 60669cbdfd5d0aa4ed7528e3cddac71047e378ac Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 10 Jun 2018 11:23:56 +0200 Subject: [PATCH 0105/5092] Rustup to rustc 1.28.0-nightly (2a0062974 2018-06-09) --- benches/helpers/miri_helper.rs | 46 +++++++++++++--------------------- src/bin/miri.rs | 15 +++++------ src/lib.rs | 24 +++++++++++++++--- 3 files changed, 46 insertions(+), 39 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 2bf78b0a71cc..0fbb46246aea 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -5,8 +5,7 @@ extern crate rustc_driver; extern crate test; use self::miri::eval_main; -use self::rustc::session::Session; -use self::rustc_driver::{driver, CompilerCalls, Compilation}; +use self::rustc_driver::{driver, Compilation}; use std::cell::RefCell; use std::rc::Rc; use test::Bencher; @@ -36,37 +35,26 @@ pub fn run(filename: &str, bencher: &mut Bencher) { "--sysroot".to_string(), find_sysroot(), ]; - let compiler_calls = &mut MiriCompilerCalls(Rc::new(RefCell::new(bencher))); - rustc_driver::run_compiler(args, compiler_calls, None, None); -} + let bencher = RefCell::new(bencher); -impl<'a> CompilerCalls<'a> for MiriCompilerCalls<'a> { - fn build_controller( - &mut self, - _: &Session, - _: &getopts::Matches, - ) -> driver::CompileController<'a> { - let mut control: driver::CompileController<'a> = driver::CompileController::basic(); + let mut control = driver::CompileController::basic(); - let bencher = self.0.clone(); + control.after_analysis.stop = Compilation::Stop; + control.after_analysis.callback = Box::new(move |state| { + state.session.abort_if_errors(); - control.after_analysis.stop = Compilation::Stop; - control.after_analysis.callback = Box::new(move |state| { - state.session.abort_if_errors(); + let tcx = state.tcx.unwrap(); + let (entry_node_id, _, _) = state.session.entry_fn.borrow().expect( + "no main or start function found", + ); + let entry_def_id = tcx.hir.local_def_id(entry_node_id); - let tcx = state.tcx.unwrap(); - let (entry_node_id, _, _) = state.session.entry_fn.borrow().expect( - "no main or start function found", - ); - let entry_def_id = tcx.hir.local_def_id(entry_node_id); - - bencher.borrow_mut().iter(|| { - eval_main(tcx, entry_def_id, None); - }); - - state.session.abort_if_errors(); + bencher.borrow_mut().iter(|| { + eval_main(tcx, entry_def_id, None); }); - control - } + state.session.abort_if_errors(); + }); + + rustc_driver::run_compiler(args, Box::new(control), None, None); } diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 8d80135cde30..35e83d49125e 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -23,7 +23,7 @@ use syntax::ast; use std::path::PathBuf; struct MiriCompilerCalls { - default: RustcDefaultCalls, + default: Box, /// Whether to begin interpretation at the start_fn lang item or not /// /// If false, the interpretation begins at the `main` function @@ -78,13 +78,14 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { self.default.late_callback(codegen_backend, matches, sess, cstore, input, odir, ofile) } fn build_controller( - &mut self, + self: Box, sess: &Session, matches: &getopts::Matches, ) -> CompileController<'a> { - let mut control = self.default.build_controller(sess, matches); + let this = *self; + let mut control = this.default.build_controller(sess, matches); control.after_hir_lowering.callback = Box::new(after_hir_lowering); - let start_fn = self.start_fn; + let start_fn = this.start_fn; control.after_analysis.callback = Box::new(move |state| after_analysis(state, start_fn)); if sess.target.target != sess.host { // only fully compile targets on the host. linking will fail for cross-compilation. @@ -234,8 +235,8 @@ fn main() { // Make sure we always have all the MIR (e.g. for auxilary builds in unit tests). args.push("-Zalways-encode-mir".to_owned()); - rustc_driver::run_compiler(&args, &mut MiriCompilerCalls { - default: RustcDefaultCalls, + rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls { + default: Box::new(RustcDefaultCalls), start_fn, - }, None, None); + }), None, None); } diff --git a/src/lib.rs b/src/lib.rs index e8bbe164611d..d2ee39dd995a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,6 +24,7 @@ use rustc::ty::layout::{TyLayout, LayoutOf, Size}; use rustc::ty::subst::Subst; use rustc::hir::def_id::DefId; use rustc::mir; +use rustc::middle::const_val; use syntax::ast::Mutability; use syntax::codemap::Span; @@ -253,9 +254,26 @@ pub fn eval_main<'a, 'tcx: 'a>( //tcx.sess.err("the evaluated program leaked memory"); } } - Err(mut e) => { - ecx.tcx.sess.err(&e.to_string()); - ecx.report(&mut e, true, None); + Err(e) => { + if let Some(frame) = ecx.stack().last() { + let block = &frame.mir.basic_blocks()[frame.block]; + let span = if frame.stmt < block.statements.len() { + block.statements[frame.stmt].source_info.span + } else { + block.terminator().source_info.span + }; + + let mut err = const_val::struct_error(ecx.tcx.tcx.at(span), "constant evaluation error"); + let (frames, span) = ecx.generate_stacktrace(None); + err.span_label(span, e.to_string()); + for const_val::FrameInfo { span, location, .. } in frames { + err.span_note(span, &format!("inside call to `{}`", location)); + } + err.emit(); + } else { + ecx.tcx.sess.err(&e.to_string()); + } + for (i, frame) in ecx.stack().iter().enumerate() { trace!("-------------------"); trace!("Frame {}", i); From 25ca33d1073cfcd53c12f43df4e3a315411bef9d Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 10 Jun 2018 11:47:04 +0200 Subject: [PATCH 0106/5092] Fix rustc_tests --- rustc_tests/src/main.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/rustc_tests/src/main.rs b/rustc_tests/src/main.rs index ecc5287c7277..3e2cd032a80e 100644 --- a/rustc_tests/src/main.rs +++ b/rustc_tests/src/main.rs @@ -24,7 +24,7 @@ use rustc::ty::TyCtxt; use syntax::ast; struct MiriCompilerCalls { - default: RustcDefaultCalls, + default: Box, /// whether we are building for the host host_target: bool, } @@ -63,11 +63,12 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { ) -> Compilation { self.default.late_callback(trans, matches, sess, cstore, input, odir, ofile) } - fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> CompileController<'a> { - let mut control = self.default.build_controller(sess, matches); + fn build_controller(self: Box, sess: &Session, matches: &getopts::Matches) -> CompileController<'a> { + let this = *self; + let mut control = this.default.build_controller(sess, matches); control.after_hir_lowering.callback = Box::new(after_hir_lowering); control.after_analysis.callback = Box::new(after_analysis); - if !self.host_target { + if !this.host_target { // only fully compile targets on the host control.after_analysis.stop = Compilation::Stop; } @@ -182,10 +183,10 @@ fn main() { let buf = BufWriter::default(); let output = buf.clone(); let result = std::panic::catch_unwind(|| { - rustc_driver::run_compiler(&args, &mut MiriCompilerCalls { - default: RustcDefaultCalls, + rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls { + default: Box::new(RustcDefaultCalls), host_target, - }, None, Some(Box::new(buf))); + }), None, Some(Box::new(buf))); }); match result { From b04391c56555e518092fef78263d30d2dd3ac755 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Mon, 11 Jun 2018 18:49:17 +0200 Subject: [PATCH 0107/5092] Split create_ecx out of eval_main --- src/lib.rs | 205 +++++++++++++++++++++++++++-------------------------- 1 file changed, 106 insertions(+), 99 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d2ee39dd995a..cfe79f7602d7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -132,107 +132,116 @@ impl ScalarExt for Scalar { } } +fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + main_id: DefId, + start_wrapper: Option, +) -> EvalResult<'tcx, (EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>, Option)> { + let mut ecx = EvalContext::new(tcx.at(syntax::codemap::DUMMY_SP), ty::ParamEnv::reveal_all(), Default::default(), Default::default()); + + let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); + let main_mir = ecx.load_mir(main_instance.def)?; + let mut cleanup_ptr = None; // Scalar to be deallocated when we are done + + if !main_mir.return_ty().is_nil() || main_mir.arg_count != 0 { + return err!(Unimplemented( + "miri does not support main functions without `fn()` type signatures" + .to_owned(), + )); + } + + if let Some(start_id) = start_wrapper { + let main_ret_ty = ecx.tcx.fn_sig(main_id).output(); + let main_ret_ty = main_ret_ty.no_late_bound_regions().unwrap(); + let start_instance = ty::Instance::resolve( + ecx.tcx.tcx, + ty::ParamEnv::reveal_all(), + start_id, + ecx.tcx.mk_substs( + ::std::iter::once(ty::subst::Kind::from(main_ret_ty))) + ).unwrap(); + let start_mir = ecx.load_mir(start_instance.def)?; + + if start_mir.arg_count != 3 { + return err!(AbiViolation(format!( + "'start' lang item should have three arguments, but has {}", + start_mir.arg_count + ))); + } + + // Return value + let size = ecx.tcx.data_layout.pointer_size; + let align = ecx.tcx.data_layout.pointer_align; + let ret_ptr = ecx.memory_mut().allocate(size, align, Some(MemoryKind::Stack))?; + cleanup_ptr = Some(ret_ptr); + + // Push our stack frame + ecx.push_stack_frame( + start_instance, + start_mir.span, + start_mir, + Place::from_ptr(ret_ptr, align), + StackPopCleanup::None, + )?; + + let mut args = ecx.frame().mir.args_iter(); + + // First argument: pointer to main() + let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance); + let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; + let main_ty = main_instance.ty(ecx.tcx.tcx); + let main_ptr_ty = ecx.tcx.mk_fn_ptr(main_ty.fn_sig(ecx.tcx.tcx)); + ecx.write_value( + ValTy { + value: Value::Scalar(Scalar::Ptr(main_ptr)), + ty: main_ptr_ty, + }, + dest, + )?; + + // Second argument (argc): 1 + let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; + let ty = ecx.tcx.types.isize; + ecx.write_scalar(dest, Scalar::from_u128(1), ty)?; + + // FIXME: extract main source file path + // Third argument (argv): &[b"foo"] + let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; + let ty = ecx.tcx.mk_imm_ptr(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8)); + let foo = ecx.memory.allocate_bytes(b"foo\0"); + let ptr_size = ecx.memory.pointer_size(); + let ptr_align = ecx.tcx.data_layout.pointer_align; + let foo_ptr = ecx.memory.allocate(ptr_size, ptr_align, None)?; + ecx.memory.write_scalar(foo_ptr.into(), ptr_align, Scalar::Ptr(foo), ptr_size, false)?; + ecx.memory.mark_static_initialized(foo_ptr.alloc_id, Mutability::Immutable)?; + ecx.write_ptr(dest, foo_ptr.into(), ty)?; + + assert!(args.next().is_none(), "start lang item has more arguments than expected"); + } else { + ecx.push_stack_frame( + main_instance, + main_mir.span, + main_mir, + Place::from_scalar_ptr(Scalar::from_u128(1), ty::layout::Align::from_bytes(1, 1).unwrap()), + StackPopCleanup::None, + )?; + + // No arguments + let mut args = ecx.frame().mir.args_iter(); + assert!(args.next().is_none(), "main function must not have arguments"); + } + + Ok((ecx, cleanup_ptr)) +} + pub fn eval_main<'a, 'tcx: 'a>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, start_wrapper: Option, ) { - fn run_main<'a, 'mir: 'a, 'tcx: 'mir>( - ecx: &mut rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>, - main_id: DefId, - start_wrapper: Option, - ) -> EvalResult<'tcx> { - let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); - let main_mir = ecx.load_mir(main_instance.def)?; - let mut cleanup_ptr = None; // Scalar to be deallocated when we are done - - if !main_mir.return_ty().is_nil() || main_mir.arg_count != 0 { - return err!(Unimplemented( - "miri does not support main functions without `fn()` type signatures" - .to_owned(), - )); - } - - if let Some(start_id) = start_wrapper { - let main_ret_ty = ecx.tcx.fn_sig(main_id).output(); - let main_ret_ty = main_ret_ty.no_late_bound_regions().unwrap(); - let start_instance = ty::Instance::resolve( - ecx.tcx.tcx, - ty::ParamEnv::reveal_all(), - start_id, - ecx.tcx.mk_substs( - ::std::iter::once(ty::subst::Kind::from(main_ret_ty)))).unwrap(); - let start_mir = ecx.load_mir(start_instance.def)?; - - if start_mir.arg_count != 3 { - return err!(AbiViolation(format!( - "'start' lang item should have three arguments, but has {}", - start_mir.arg_count - ))); - } - - // Return value - let size = ecx.tcx.data_layout.pointer_size; - let align = ecx.tcx.data_layout.pointer_align; - let ret_ptr = ecx.memory_mut().allocate(size, align, Some(MemoryKind::Stack))?; - cleanup_ptr = Some(ret_ptr); - - // Push our stack frame - ecx.push_stack_frame( - start_instance, - start_mir.span, - start_mir, - Place::from_ptr(ret_ptr, align), - StackPopCleanup::None, - )?; - - let mut args = ecx.frame().mir.args_iter(); - - // First argument: pointer to main() - let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance); - let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - let main_ty = main_instance.ty(ecx.tcx.tcx); - let main_ptr_ty = ecx.tcx.mk_fn_ptr(main_ty.fn_sig(ecx.tcx.tcx)); - ecx.write_value( - ValTy { - value: Value::Scalar(Scalar::Ptr(main_ptr)), - ty: main_ptr_ty, - }, - dest, - )?; - - // Second argument (argc): 1 - let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - let ty = ecx.tcx.types.isize; - ecx.write_scalar(dest, Scalar::from_u128(1), ty)?; - - // FIXME: extract main source file path - // Third argument (argv): &[b"foo"] - let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - let ty = ecx.tcx.mk_imm_ptr(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8)); - let foo = ecx.memory.allocate_bytes(b"foo\0"); - let ptr_size = ecx.memory.pointer_size(); - let ptr_align = ecx.tcx.data_layout.pointer_align; - let foo_ptr = ecx.memory.allocate(ptr_size, ptr_align, None)?; - ecx.memory.write_scalar(foo_ptr.into(), ptr_align, Scalar::Ptr(foo), ptr_size, false)?; - ecx.memory.mark_static_initialized(foo_ptr.alloc_id, Mutability::Immutable)?; - ecx.write_ptr(dest, foo_ptr.into(), ty)?; - - assert!(args.next().is_none(), "start lang item has more arguments than expected"); - } else { - ecx.push_stack_frame( - main_instance, - main_mir.span, - main_mir, - Place::from_scalar_ptr(Scalar::from_u128(1), ty::layout::Align::from_bytes(1, 1).unwrap()), - StackPopCleanup::None, - )?; - - // No arguments - let mut args = ecx.frame().mir.args_iter(); - assert!(args.next().is_none(), "main function must not have arguments"); - } + let (mut ecx, cleanup_ptr) = create_ecx(tcx, main_id, start_wrapper).expect("Couldn't create ecx"); + let res: EvalResult = do catch { while ecx.step()? {} ecx.run_tls_dtors()?; if let Some(cleanup_ptr) = cleanup_ptr { @@ -242,11 +251,9 @@ pub fn eval_main<'a, 'tcx: 'a>( MemoryKind::Stack, )?; } - Ok(()) - } + }; - let mut ecx = EvalContext::new(tcx.at(syntax::codemap::DUMMY_SP), ty::ParamEnv::reveal_all(), Default::default(), Default::default()); - match run_main(&mut ecx, main_id, start_wrapper) { + match res { Ok(()) => { let leaks = ecx.memory().leak_report(); if leaks != 0 { From d1de6781e83969a03b59d5fffdda59c69ad68d49 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 12 Jun 2018 07:30:29 +0200 Subject: [PATCH 0108/5092] Add missing pub --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index cfe79f7602d7..e3fd5b8a068b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -132,7 +132,7 @@ impl ScalarExt for Scalar { } } -fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( +pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, start_wrapper: Option, From d4b98b221ddc74524e3c3824e28126b9965150bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Fri, 29 Jun 2018 12:52:04 +0200 Subject: [PATCH 0109/5092] Rusutp --- rustc_tests/src/main.rs | 2 +- src/bin/miri.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rustc_tests/src/main.rs b/rustc_tests/src/main.rs index 3e2cd032a80e..64cd380970e4 100644 --- a/rustc_tests/src/main.rs +++ b/rustc_tests/src/main.rs @@ -90,7 +90,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { struct Visitor<'a, 'tcx: 'a>(TyCtxt<'a, 'tcx, 'tcx>, &'a CompileState<'a, 'tcx>); impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { - if let hir::Item_::ItemFn(_, _, _, _, _, body_id) = i.node { + if let hir::Item_::ItemFn(.., body_id) = i.node { if i.attrs.iter().any(|attr| attr.name() == "test") { let did = self.0.hir.body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 35e83d49125e..3001500d2e07 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -25,7 +25,7 @@ use std::path::PathBuf; struct MiriCompilerCalls { default: Box, /// Whether to begin interpretation at the start_fn lang item or not - /// + /// /// If false, the interpretation begins at the `main` function start_fn: bool, } @@ -115,7 +115,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>, use_start_fn: bo ); impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { - if let hir::Item_::ItemFn(_, _, _, _, _, body_id) = i.node { + if let hir::Item_::ItemFn(.., body_id) = i.node { if i.attrs.iter().any(|attr| { attr.name() == "test" }) From 5a7f4412eed61ac82880d67d2bc5275c5dee4922 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 29 Jun 2018 12:48:55 -0700 Subject: [PATCH 0110/5092] Implement `Eq` and `Hash` for MemoryData and Evaluator In order to implement infinite loop detection while executing MIR, both the implementor of `Machine` (`Evaluator`) and its associated type (`MemoryData`), must implement `Eq` and `Hash`. This PR adds the required trait implementations. It's possible that the `Hash` implementations need to be improved; only the `env_vars` field of `Evaluator` and the `thread_local` field of `MemoryData` are actually being hashed. Omitting fields from a `Hash` implementation is not incorrect, but could lead to collisions if the ignored fields are changing constantly. Perhaps I should instead derive `Hash` on a few more fields related to MIR validation? --- src/lib.rs | 41 ++++++++++++++++++++++++++++++++++++++--- src/locks.rs | 2 +- src/range_map.rs | 2 +- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e3fd5b8a068b..ffb17527ad04 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,10 +26,13 @@ use rustc::hir::def_id::DefId; use rustc::mir; use rustc::middle::const_val; +use rustc_data_structures::fx::FxHasher; + use syntax::ast::Mutability; use syntax::codemap::Span; use std::collections::{HashMap, BTreeMap}; +use std::hash::{Hash, Hasher}; pub use rustc::mir::interpret::*; pub use rustc_mir::interpret::*; @@ -295,7 +298,7 @@ pub fn eval_main<'a, 'tcx: 'a>( } } -#[derive(Default)] +#[derive(Clone, Default, PartialEq, Eq)] pub struct Evaluator<'tcx> { /// Environment variables set by `setenv` /// Miri does not expose env vars from the host to the emulated program @@ -305,15 +308,34 @@ pub struct Evaluator<'tcx> { pub(crate) suspended: HashMap>>, } +impl<'tcx> Hash for Evaluator<'tcx> { + fn hash(&self, state: &mut H) { + let Evaluator { + env_vars, + suspended: _, + } = self; + + env_vars.iter() + .map(|(env, ptr)| { + let mut h = FxHasher::default(); + env.hash(&mut h); + ptr.hash(&mut h); + h.finish() + }) + .fold(0u64, |acc, hash| acc.wrapping_add(hash)) + .hash(state); + } +} + pub type TlsKey = u128; -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub struct TlsEntry<'tcx> { data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. dtor: Option>, } -#[derive(Default)] +#[derive(Clone, Default, PartialEq, Eq)] pub struct MemoryData<'tcx> { /// The Key to use for the next thread-local allocation. next_thread_local: TlsKey, @@ -330,6 +352,19 @@ pub struct MemoryData<'tcx> { statics: HashMap, AllocId>, } +impl<'tcx> Hash for MemoryData<'tcx> { + fn hash(&self, state: &mut H) { + let MemoryData { + next_thread_local: _, + thread_local, + locks: _, + statics: _, + } = self; + + thread_local.hash(state); + } +} + impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryData = MemoryData<'tcx>; type MemoryKinds = memory::MemoryKind; diff --git a/src/locks.rs b/src/locks.rs index a463f8ba575e..9947609d3755 100644 --- a/src/locks.rs +++ b/src/locks.rs @@ -7,7 +7,7 @@ use rustc::ty::layout::Size; //////////////////////////////////////////////////////////////////////////////// /// Information about a lock that is currently held. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct LockInfo<'tcx> { /// Stores for which lifetimes (of the original write lock) we got /// which suspensions. diff --git a/src/range_map.rs b/src/range_map.rs index 5cdcbe35121a..118be32a2993 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -7,7 +7,7 @@ use std::collections::BTreeMap; use std::ops; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct RangeMap { map: BTreeMap, } From e1dbbe538f5fe978333dfa9f63533f5ead2866ae Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sun, 1 Jul 2018 16:01:42 +0200 Subject: [PATCH 0111/5092] Rustup --- src/lib.rs | 5 ++--- src/validation.rs | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e3fd5b8a068b..896c8c5428fb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,7 +24,6 @@ use rustc::ty::layout::{TyLayout, LayoutOf, Size}; use rustc::ty::subst::Subst; use rustc::hir::def_id::DefId; use rustc::mir; -use rustc::middle::const_val; use syntax::ast::Mutability; use syntax::codemap::Span; @@ -270,10 +269,10 @@ pub fn eval_main<'a, 'tcx: 'a>( block.terminator().source_info.span }; - let mut err = const_val::struct_error(ecx.tcx.tcx.at(span), "constant evaluation error"); + let mut err = mir::interpret::struct_error(ecx.tcx.tcx.at(span), "constant evaluation error"); let (frames, span) = ecx.generate_stacktrace(None); err.span_label(span, e.to_string()); - for const_val::FrameInfo { span, location, .. } in frames { + for mir::interpret::FrameInfo { span, location, .. } in frames { err.span_note(span, &format!("inside call to `{}`", location)); } err.emit(); diff --git a/src/validation.rs b/src/validation.rs index d82a345c2512..90ac0a803f9b 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -8,7 +8,6 @@ use rustc::ty::subst::{Substs, Subst}; use rustc::traits::{self, TraitEngine}; use rustc::infer::InferCtxt; use rustc::middle::region; -use rustc::middle::const_val::ConstVal; use rustc_data_structures::indexed_vec::Idx; use rustc_mir::interpret::HasMemory; @@ -719,14 +718,14 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } TyArray(elem_ty, len) => { let len = match len.val { - ConstVal::Unevaluated(def_id, substs) => { + mir::interpret::ConstValue::Unevaluated(def_id, substs) => { self.tcx.const_eval(self.tcx.param_env(def_id).and(GlobalId { instance: Instance::new(def_id, substs), promoted: None, })) .map_err(|_err|EvalErrorKind::MachineError("".to_string()))? } - ConstVal::Value(_) => len, + _ => len, }; let len = len.unwrap_usize(self.tcx.tcx); for i in 0..len { From 5b7bb32b0e46d195b80c4da09b560ac7fc92015d Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Mon, 2 Jul 2018 17:00:36 +0100 Subject: [PATCH 0112/5092] Rustup --- src/fn_call.rs | 8 ++++---- src/lib.rs | 10 +++++----- src/validation.rs | 3 ++- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 36cc29a2b5b5..1c3998a4f022 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -199,7 +199,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.write_null(dest, dest_ty)?; } else { let align = self.tcx.data_layout.pointer_align; - let ptr = self.memory.allocate(Size::from_bytes(size), align, Some(MemoryKind::C.into()))?; + let ptr = self.memory.allocate(Size::from_bytes(size), align, MemoryKind::C.into())?; self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; } } @@ -395,7 +395,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let value_copy = self.memory.allocate( Size::from_bytes((value.len() + 1) as u64), Align::from_bytes(1, 1).unwrap(), - Some(MemoryKind::Env.into()), + MemoryKind::Env.into(), )?; self.memory.write_bytes(value_copy.into(), &value)?; let trailing_zero_ptr = value_copy.offset(Size::from_bytes(value.len() as u64), &self)?.into(); @@ -656,7 +656,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } let ptr = self.memory.allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), - Some(MemoryKind::Rust.into()))?; + MemoryKind::Rust.into())?; self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; } "alloc::alloc::::__rust_alloc_zeroed" => { @@ -670,7 +670,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } let ptr = self.memory.allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), - Some(MemoryKind::Rust.into()))?; + MemoryKind::Rust.into())?; self.memory.write_repeat(ptr.into(), 0, Size::from_bytes(size))?; self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; } diff --git a/src/lib.rs b/src/lib.rs index 896c8c5428fb..d6b0bd045099 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -171,7 +171,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // Return value let size = ecx.tcx.data_layout.pointer_size; let align = ecx.tcx.data_layout.pointer_align; - let ret_ptr = ecx.memory_mut().allocate(size, align, Some(MemoryKind::Stack))?; + let ret_ptr = ecx.memory_mut().allocate(size, align, MemoryKind::Stack)?; cleanup_ptr = Some(ret_ptr); // Push our stack frame @@ -210,7 +210,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let foo = ecx.memory.allocate_bytes(b"foo\0"); let ptr_size = ecx.memory.pointer_size(); let ptr_align = ecx.tcx.data_layout.pointer_align; - let foo_ptr = ecx.memory.allocate(ptr_size, ptr_align, None)?; + let foo_ptr = ecx.memory.allocate(ptr_size, ptr_align, MemoryKind::Stack)?; ecx.memory.write_scalar(foo_ptr.into(), ptr_align, Scalar::Ptr(foo), ptr_size, false)?; ecx.memory.mark_static_initialized(foo_ptr.alloc_id, Mutability::Immutable)?; ecx.write_ptr(dest, foo_ptr.into(), ty)?; @@ -269,10 +269,10 @@ pub fn eval_main<'a, 'tcx: 'a>( block.terminator().source_info.span }; - let mut err = mir::interpret::struct_error(ecx.tcx.tcx.at(span), "constant evaluation error"); + let mut err = struct_error(ecx.tcx.tcx.at(span), "constant evaluation error"); let (frames, span) = ecx.generate_stacktrace(None); err.span_label(span, e.to_string()); - for mir::interpret::FrameInfo { span, location, .. } in frames { + for FrameInfo { span, location, .. } in frames { err.span_note(span, &format!("inside call to `{}`", location)); } err.emit(); @@ -404,7 +404,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { let ptr = ecx.memory.allocate( layout.size, layout.align, - None, + MemoryKind::Stack, )?; // Step 4: Cache allocation id for recursive statics diff --git a/src/validation.rs b/src/validation.rs index 90ac0a803f9b..851f5df9792e 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -8,6 +8,7 @@ use rustc::ty::subst::{Substs, Subst}; use rustc::traits::{self, TraitEngine}; use rustc::infer::InferCtxt; use rustc::middle::region; +use rustc::mir::interpret::{ConstValue}; use rustc_data_structures::indexed_vec::Idx; use rustc_mir::interpret::HasMemory; @@ -718,7 +719,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } TyArray(elem_ty, len) => { let len = match len.val { - mir::interpret::ConstValue::Unevaluated(def_id, substs) => { + ConstValue::Unevaluated(def_id, substs) => { self.tcx.const_eval(self.tcx.param_env(def_id).and(GlobalId { instance: Instance::new(def_id, substs), promoted: None, From f321593655b9ba2d5e475474dbc9ee2b5ae6285d Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 10 Jul 2018 17:20:07 +0200 Subject: [PATCH 0113/5092] Workaround for rustc bug --- src/range_map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/range_map.rs b/src/range_map.rs index 5cdcbe35121a..df1235f96c0d 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -19,7 +19,7 @@ pub struct RangeMap { // At the same time the `end` is irrelevant for the sorting and range searching, but used for the check. // This kind of search breaks, if `end < start`, so don't do that! #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] -struct Range { +pub struct Range { start: u64, end: u64, // Invariant: end > start } From 52bf4732fd51332632f4154bb45df13871320ceb Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 10 Jul 2018 17:32:38 +0200 Subject: [PATCH 0114/5092] Fix some clippy lints --- src/fn_call.rs | 6 +++--- src/helpers.rs | 4 ++-- src/lib.rs | 15 +++++++-------- src/locks.rs | 10 ++++------ src/operator.rs | 2 +- src/range_map.rs | 2 +- src/tls.rs | 20 ++++++++++---------- src/validation.rs | 26 +++++++++++--------------- 8 files changed, 39 insertions(+), 46 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 1c3998a4f022..d2149ee5dbe7 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -268,7 +268,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' )?; let mut args = self.frame().mir.args_iter(); - let arg_local = args.next().ok_or( + let arg_local = args.next().ok_or_else(|| EvalErrorKind::AbiViolation( "Argument to __rust_maybe_catch_panic does not take enough arguments." .to_owned(), @@ -504,7 +504,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // Figure out how large a pthread TLS key actually is. This is libc::pthread_key_t. let key_type = args[0].ty.builtin_deref(true) - .ok_or(EvalErrorKind::AbiViolation("Wrong signature used for pthread_key_create: First argument must be a raw pointer.".to_owned()))?.ty; + .ok_or_else(|| EvalErrorKind::AbiViolation("Wrong signature used for pthread_key_create: First argument must be a raw pointer.".to_owned()))?.ty; let key_size = self.layout_of(key_type)?.size; // Create key and write it into the memory where key_ptr wants it @@ -747,7 +747,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // current frame. self.dump_local(dest); self.goto_block(dest_block); - return Ok(()); + Ok(()) } fn write_null(&mut self, dest: Place, dest_ty: Ty<'tcx>) -> EvalResult<'tcx> { diff --git a/src/helpers.rs b/src/helpers.rs index d881d5c27110..aa699b509fad 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -75,7 +75,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } // FIXME: assuming here that type size is < i64::max_value() let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; - return if let Some(offset) = offset.checked_mul(pointee_size) { + if let Some(offset) = offset.checked_mul(pointee_size) { let ptr = ptr.ptr_signed_offset(offset, self)?; // Do not do bounds-checking for integers; they can never alias a normal pointer anyway. if let Scalar::Ptr(ptr) = ptr { @@ -87,7 +87,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Ok(ptr) } else { err!(Overflow(mir::BinOp::Mul)) - }; + } } fn value_to_isize( diff --git a/src/lib.rs b/src/lib.rs index d6b0bd045099..88bca91aa2de 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,8 @@ inclusive_range_methods, )] +#![cfg_attr(feature = "cargo-clippy", allow(cast_lossless))] + #[macro_use] extern crate log; @@ -427,14 +429,11 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { let frame = ecx.frame_mut(); let bb = &frame.mir.basic_blocks()[frame.block]; if bb.statements.len() == frame.stmt && !bb.is_cleanup { - match bb.terminator().kind { - ::rustc::mir::TerminatorKind::Return => { - for (local, _local_decl) in mir.local_decls.iter_enumerated().skip(1) { - // Don't deallocate locals, because the return value might reference them - frame.storage_dead(local); - } + if let ::rustc::mir::TerminatorKind::Return = bb.terminator().kind { + for (local, _local_decl) in mir.local_decls.iter_enumerated().skip(1) { + // Don't deallocate locals, because the return value might reference them + frame.storage_dead(local); } - _ => {} } } } @@ -478,7 +477,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { value: Value::Scalar(Scalar::from_u128(match layout.size.bytes() { 0 => 1 as u128, size => size as u128, - }.into())), + })), ty: usize, }, dest, diff --git a/src/locks.rs b/src/locks.rs index a463f8ba575e..3b67c9bb7f3e 100644 --- a/src/locks.rs +++ b/src/locks.rs @@ -241,11 +241,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu // All is well continue 'locks; } - } else { - if !is_our_lock { - // All is well. - continue 'locks; - } + } else if !is_our_lock { + // All is well. + continue 'locks; } // If we get here, releasing this is an error except for NoLock. if lock.active != NoLock { @@ -377,7 +375,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu } // Clean up the map alloc_locks.retain(|lock| match lock.active { - NoLock => lock.suspended.len() > 0, + NoLock => !lock.suspended.is_empty(), _ => true, }); } diff --git a/src/operator.rs b/src/operator.rs index f36e749dc927..1440f1dab4e0 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -69,7 +69,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: .expect("Offset called on non-ptr type") .ty; let ptr = self.pointer_offset( - left.into(), + left, pointee_ty, right.to_bits(self.memory.pointer_size())? as i64, )?; diff --git a/src/range_map.rs b/src/range_map.rs index df1235f96c0d..fcffaf7128f1 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -189,7 +189,7 @@ impl RangeMap { F: FnMut(&T) -> bool, { let mut remove = Vec::new(); - for (range, data) in self.map.iter() { + for (range, data) in &self.map { if !f(data) { remove.push(*range); } diff --git a/src/tls.rs b/src/tls.rs index 7f49509ef42e..45805f3aa8cc 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -30,38 +30,38 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu }, ); trace!("New TLS key allocated: {} with dtor {:?}", new_key, dtor); - return new_key; + new_key } fn delete_tls_key(&mut self, key: TlsKey) -> EvalResult<'tcx> { - return match self.data.thread_local.remove(&key) { + match self.data.thread_local.remove(&key) { Some(_) => { trace!("TLS key {} removed", key); Ok(()) } None => err!(TlsOutOfBounds), - }; + } } fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar> { - return match self.data.thread_local.get(&key) { + match self.data.thread_local.get(&key) { Some(&TlsEntry { data, .. }) => { trace!("TLS key {} loaded: {:?}", key, data); Ok(data) } None => err!(TlsOutOfBounds), - }; + } } fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx> { - return match self.data.thread_local.get_mut(&key) { + match self.data.thread_local.get_mut(&key) { Some(&mut TlsEntry { ref mut data, .. }) => { trace!("TLS key {} stored: {:?}", key, new_data); *data = new_data; Ok(()) } None => err!(TlsOutOfBounds), - }; + } } /// Returns a dtor, its argument and its index, if one is supposed to run @@ -104,7 +104,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu } } } - return Ok(None); + Ok(None) } } @@ -124,8 +124,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Place::undef(), StackPopCleanup::None, )?; - let arg_local = self.frame().mir.args_iter().next().ok_or( - EvalErrorKind::AbiViolation("TLS dtor does not take enough arguments.".to_owned()), + let arg_local = self.frame().mir.args_iter().next().ok_or_else( + || EvalErrorKind::AbiViolation("TLS dtor does not take enough arguments.".to_owned()), )?; let dest = self.eval_place(&mir::Place::Local(arg_local))?; let ty = self.tcx.mk_mut_ptr(self.tcx.types.u8); diff --git a/src/validation.rs b/src/validation.rs index 851f5df9792e..758fd5d27470 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -135,10 +135,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } fn abstract_place(&self, place: &mir::Place<'tcx>) -> EvalResult<'tcx, AbsPlace<'tcx>> { - Ok(match place { - &mir::Place::Local(l) => AbsPlace::Local(l), - &mir::Place::Static(ref s) => AbsPlace::Static(s.def_id), - &mir::Place::Projection(ref p) => + Ok(match *place { + mir::Place::Local(l) => AbsPlace::Local(l), + mir::Place::Static(ref s) => AbsPlace::Static(s.def_id), + mir::Place::Projection(ref p) => AbsPlace::Projection(Box::new(self.abstract_place_projection(&*p)?)), }) } @@ -378,11 +378,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' mut layout: ty::layout::TyLayout<'tcx>, i: usize, ) -> EvalResult<'tcx, Ty<'tcx>> { - match base { - Place::Ptr { extra: PlaceExtra::DowncastVariant(variant_index), .. } => { - layout = layout.for_variant(&self, variant_index); - } - _ => {} + if let Place::Ptr { extra: PlaceExtra::DowncastVariant(variant_index), .. } = base { + layout = layout.for_variant(&self, variant_index); } let tcx = self.tcx.tcx; Ok(match layout.ty.sty { @@ -667,12 +664,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // Inner lifetimes *outlive* outer ones, so only if we have no lifetime restriction yet, // we record the region of this borrow to the context. if query.re == None { - match *region { - ReScope(scope) => query.re = Some(scope), - // It is possible for us to encounter erased lifetimes here because the lifetimes in - // this functions' Subst will be erased. - _ => {} + if let ReScope(scope) = *region { + query.re = Some(scope); } + // It is possible for us to encounter erased lifetimes here because the lifetimes in + // this functions' Subst will be erased. } self.validate_ptr(val, query.place.0, pointee_ty, query.re, query.mutbl, mode)?; } @@ -772,7 +768,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let variant_idx = self.read_discriminant_as_variant_index(query.place.1, query.ty)?; let variant = &adt.variants[variant_idx]; - if variant.fields.len() > 0 { + if !variant.fields.is_empty() { // Downcast to this variant, if needed let place = if adt.is_enum() { ( From d4e8d0b935900e716b6154a9458730c29a67c182 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Jul 2018 17:42:35 +0200 Subject: [PATCH 0115/5092] fix deprecation warning: use dirs crate for home_dir --- Cargo.toml | 1 + tests/compiletest.rs | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 86ac2c040fd1..54a1c5456e47 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,3 +31,4 @@ cargo_miri = ["cargo_metadata"] [dev-dependencies] compiletest_rs = { version = "0.3.4", features = ["tmp"] } +dirs = "1.0.2" diff --git a/tests/compiletest.rs b/tests/compiletest.rs index e62fa4e65e63..342ea92280de 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -1,6 +1,7 @@ #![feature(slice_concat_ext)] extern crate compiletest_rs as compiletest; +extern crate dirs; use std::slice::SliceConcatExt; use std::path::{PathBuf, Path}; @@ -50,7 +51,7 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, fullmir: b // skip fullmir on nonhost return; } - let sysroot = std::env::home_dir().unwrap() + let sysroot = dirs::home_dir().unwrap() .join(".xargo") .join("HOST"); flags.push(format!("--sysroot {}", sysroot.to_str().unwrap())); @@ -110,7 +111,7 @@ fn miri_pass(path: &str, target: &str, host: &str, fullmir: bool, opt: bool) { // skip fullmir on nonhost return; } - let sysroot = std::env::home_dir().unwrap() + let sysroot = dirs::home_dir().unwrap() .join(".xargo") .join("HOST"); From 7023126094a33c0be77f9c5c3dbdd5ef9e136064 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Jul 2018 17:53:44 +0200 Subject: [PATCH 0116/5092] stop producing binaries --- src/bin/miri.rs | 5 +---- tests/run-pass/aux_test.rs | 9 --------- tests/run-pass/auxiliary/dep.rs | 1 - 3 files changed, 1 insertion(+), 14 deletions(-) delete mode 100644 tests/run-pass/aux_test.rs delete mode 100644 tests/run-pass/auxiliary/dep.rs diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 3001500d2e07..f6dc65a0d27c 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -87,10 +87,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { control.after_hir_lowering.callback = Box::new(after_hir_lowering); let start_fn = this.start_fn; control.after_analysis.callback = Box::new(move |state| after_analysis(state, start_fn)); - if sess.target.target != sess.host { - // only fully compile targets on the host. linking will fail for cross-compilation. - control.after_analysis.stop = Compilation::Stop; - } + control.after_analysis.stop = Compilation::Stop; control } } diff --git a/tests/run-pass/aux_test.rs b/tests/run-pass/aux_test.rs deleted file mode 100644 index beed82e05802..000000000000 --- a/tests/run-pass/aux_test.rs +++ /dev/null @@ -1,9 +0,0 @@ -// aux-build:dep.rs - -// ignore-cross-compile - -extern crate dep; - -fn main() { - dep::foo(); -} diff --git a/tests/run-pass/auxiliary/dep.rs b/tests/run-pass/auxiliary/dep.rs deleted file mode 100644 index b76b4321d62a..000000000000 --- a/tests/run-pass/auxiliary/dep.rs +++ /dev/null @@ -1 +0,0 @@ -pub fn foo() {} From 197b75764cb1069c7fb063e9ef25d41cb36729d2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Jul 2018 19:33:52 +0200 Subject: [PATCH 0117/5092] without aux builds, we don't need to set always-encode-mir any more --- src/bin/miri.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index f6dc65a0d27c..2cc22d7a7deb 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -229,9 +229,6 @@ fn main() { } }); - // Make sure we always have all the MIR (e.g. for auxilary builds in unit tests). - args.push("-Zalways-encode-mir".to_owned()); - rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls { default: Box::new(RustcDefaultCalls), start_fn, From dd7cc47e5c73eeff21c358e6bf10d6db656ce0c4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Jul 2018 19:39:09 +0200 Subject: [PATCH 0118/5092] document -Zmiri-start-fn; make its logic more clear --- README.md | 3 +++ src/bin/miri.rs | 9 ++------- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 7660735a7cef..32eca3652945 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,9 @@ MIRI_SYSROOT=~/.xargo/HOST cargo run --bin miri tests/run-pass-fullmir/vecs.rs Notice that you will have to re-run the last step of the preparations above when your toolchain changes (e.g., when you update the nightly). +You can also set `-Zmiri-start-fn` to make miri start evaluation with the +`start_fn` lang item, instead of starting at the `main` function. + ## Contributing and getting help Check out the issues on this GitHub repository for some ideas. There's lots that diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 3001500d2e07..bd0a930471b2 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -138,13 +138,8 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>, use_start_fn: bo ); } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { let entry_def_id = tcx.hir.local_def_id(entry_node_id); - let start_wrapper = tcx.lang_items().start_fn().and_then(|start_fn| { - if use_start_fn { - Some(start_fn) - } else { - None - } - }); + // Use start_fn lang item if it is available and we have -Zmiri-start-fn set + let start_wrapper = if use_start_fn { tcx.lang_items().start_fn() } else { None }; miri::eval_main(tcx, entry_def_id, start_wrapper); state.session.abort_if_errors(); From e5de51a322e944f5dc7a0bcf9d8afcb3275c7daf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Jul 2018 19:50:13 +0200 Subject: [PATCH 0119/5092] use -Zmiri-start-fn as a clue to REQUIRE the lang item to be present --- src/bin/miri.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index bd0a930471b2..82261f9dfac9 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -138,8 +138,12 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>, use_start_fn: bo ); } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { let entry_def_id = tcx.hir.local_def_id(entry_node_id); - // Use start_fn lang item if it is available and we have -Zmiri-start-fn set - let start_wrapper = if use_start_fn { tcx.lang_items().start_fn() } else { None }; + // Use start_fn lang item if we have -Zmiri-start-fn set + let start_wrapper = if use_start_fn { + Some(tcx.lang_items().start_fn().unwrap()) + } else { + None + }; miri::eval_main(tcx, entry_def_id, start_wrapper); state.session.abort_if_errors(); From 5fc990cebdf2c3732b65ab921f9c7e2c8ba79dc3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Jul 2018 10:17:50 +0200 Subject: [PATCH 0120/5092] bump dependencies --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 54a1c5456e47..c6128b2405aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,8 +20,8 @@ required-features = ["cargo_miri"] [dependencies] byteorder = { version = "1.1", features = ["i128"]} -cargo_metadata = { version = "0.5", optional = true } -regex = "0.2.2" +cargo_metadata = { version = "0.6", optional = true } +regex = "1.0" lazy_static = "1.0" env_logger = "0.5.0-rc.1" log = "0.4" From ff5b0fee33b38f15d1bac51e19c6cb2b739e2879 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Jul 2018 21:07:17 +0200 Subject: [PATCH 0121/5092] fix many tests and ignore some others; enable compile_fail tests again --- tests/compile-fail-fullmir/undefined_byte_read.rs | 3 ++- tests/compile-fail/deallocate-bad-alignment.rs | 2 +- tests/compile-fail/deallocate-bad-size.rs | 2 +- tests/compile-fail/deallocate-twice.rs | 2 +- tests/compile-fail/match_char.rs | 2 ++ tests/compile-fail/memleak.rs | 1 + tests/compile-fail/memleak_rc.rs | 1 + tests/compile-fail/overflowing-rsh-2.rs | 2 +- tests/compile-fail/reallocate-bad-size.rs | 4 ++-- tests/compile-fail/reallocate-change-alloc.rs | 6 +++--- tests/compile-fail/reallocate-dangling.rs | 4 ++-- tests/compile-fail/static_memory_modification.rs | 1 + tests/compiletest.rs | 6 +++--- 13 files changed, 21 insertions(+), 15 deletions(-) diff --git a/tests/compile-fail-fullmir/undefined_byte_read.rs b/tests/compile-fail-fullmir/undefined_byte_read.rs index 99404b7d5f3f..24718bce7db9 100644 --- a/tests/compile-fail-fullmir/undefined_byte_read.rs +++ b/tests/compile-fail-fullmir/undefined_byte_read.rs @@ -4,6 +4,7 @@ fn main() { let v: Vec = Vec::with_capacity(10); let undef = unsafe { *v.get_unchecked(5) }; - let x = undef + 1; //~ ERROR: attempted to read undefined bytes + let x = undef + 1; //~ ERROR: error + //~^ NOTE attempted to read undefined bytes panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/deallocate-bad-alignment.rs b/tests/compile-fail/deallocate-bad-alignment.rs index 36e99cb11f72..4b89f0ac70c7 100644 --- a/tests/compile-fail/deallocate-bad-alignment.rs +++ b/tests/compile-fail/deallocate-bad-alignment.rs @@ -9,7 +9,7 @@ use std::alloc::*; fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); Global.dealloc(x, Layout::from_size_align_unchecked(1, 2)); } } diff --git a/tests/compile-fail/deallocate-bad-size.rs b/tests/compile-fail/deallocate-bad-size.rs index f1271cefd1ac..3a74245816c4 100644 --- a/tests/compile-fail/deallocate-bad-size.rs +++ b/tests/compile-fail/deallocate-bad-size.rs @@ -9,7 +9,7 @@ use std::alloc::*; fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); Global.dealloc(x, Layout::from_size_align_unchecked(2, 1)); } } diff --git a/tests/compile-fail/deallocate-twice.rs b/tests/compile-fail/deallocate-twice.rs index 58fcb7409495..613edf3c6af9 100644 --- a/tests/compile-fail/deallocate-twice.rs +++ b/tests/compile-fail/deallocate-twice.rs @@ -9,7 +9,7 @@ use std::alloc::*; fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); Global.dealloc(x, Layout::from_size_align_unchecked(1, 1)); Global.dealloc(x, Layout::from_size_align_unchecked(1, 1)); } diff --git a/tests/compile-fail/match_char.rs b/tests/compile-fail/match_char.rs index 15ce2f2f7952..0d45d70eb781 100644 --- a/tests/compile-fail/match_char.rs +++ b/tests/compile-fail/match_char.rs @@ -1,3 +1,5 @@ +// ignore-test FIXME: we are not checking these things on match any more? + fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); match unsafe { std::mem::transmute::(-1) } { //~ ERROR constant evaluation error [E0080] diff --git a/tests/compile-fail/memleak.rs b/tests/compile-fail/memleak.rs index 71b4e2f442f3..c03cf50eb27f 100644 --- a/tests/compile-fail/memleak.rs +++ b/tests/compile-fail/memleak.rs @@ -1,3 +1,4 @@ +// ignore-test FIXME: leak detection is disabled //error-pattern: the evaluated program leaked memory fn main() { diff --git a/tests/compile-fail/memleak_rc.rs b/tests/compile-fail/memleak_rc.rs index b2bc6722afb0..da3a58118a2a 100644 --- a/tests/compile-fail/memleak_rc.rs +++ b/tests/compile-fail/memleak_rc.rs @@ -1,3 +1,4 @@ +// ignore-test FIXME: leak detection is disabled //error-pattern: the evaluated program leaked memory use std::rc::Rc; diff --git a/tests/compile-fail/overflowing-rsh-2.rs b/tests/compile-fail/overflowing-rsh-2.rs index 4447b9d7579a..967c8b020cca 100644 --- a/tests/compile-fail/overflowing-rsh-2.rs +++ b/tests/compile-fail/overflowing-rsh-2.rs @@ -13,5 +13,5 @@ fn main() { // Make sure we catch overflows that would be hidden by first casting the RHS to u32 let _n = 1i64 >> (u32::max_value() as i64 + 1); //~ ERROR constant evaluation error [E0080] - //~^ NOTE suiriuruihrihue + //~^ NOTE attempt to shift right with overflow } diff --git a/tests/compile-fail/reallocate-bad-size.rs b/tests/compile-fail/reallocate-bad-size.rs index d75c195d521e..f85b651e8573 100644 --- a/tests/compile-fail/reallocate-bad-size.rs +++ b/tests/compile-fail/reallocate-bad-size.rs @@ -9,7 +9,7 @@ use std::alloc::*; fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)); - let _y = Global.realloc(x, Layout::from_size_align_unchecked(2, 1), 1); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); + let _y = Global.realloc(x, Layout::from_size_align_unchecked(2, 1), 1).unwrap(); } } diff --git a/tests/compile-fail/reallocate-change-alloc.rs b/tests/compile-fail/reallocate-change-alloc.rs index d8234e933300..03040cd178da 100644 --- a/tests/compile-fail/reallocate-change-alloc.rs +++ b/tests/compile-fail/reallocate-change-alloc.rs @@ -7,9 +7,9 @@ use std::alloc::*; fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)); - let _y = Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1); - let _z = *(x as *mut u8); //~ ERROR constant evaluation error [E0080] + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); + let _y = Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1).unwrap(); + let _z = *(x.as_ptr() as *mut u8); //~ ERROR constant evaluation error [E0080] //~^ NOTE dangling pointer was dereferenced } } diff --git a/tests/compile-fail/reallocate-dangling.rs b/tests/compile-fail/reallocate-dangling.rs index 39b60407160e..6dfb7fe2b966 100644 --- a/tests/compile-fail/reallocate-dangling.rs +++ b/tests/compile-fail/reallocate-dangling.rs @@ -9,8 +9,8 @@ use std::alloc::*; fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); Global.dealloc(x, Layout::from_size_align_unchecked(1, 1)); - Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1); + Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1).unwrap(); } } diff --git a/tests/compile-fail/static_memory_modification.rs b/tests/compile-fail/static_memory_modification.rs index 7182f40d994d..a85ff545ee42 100644 --- a/tests/compile-fail/static_memory_modification.rs +++ b/tests/compile-fail/static_memory_modification.rs @@ -1,3 +1,4 @@ +// ignore-test FIXME: we are not making these statics read-only any more? static X: usize = 5; #[allow(mutable_transmutes)] diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 342ea92280de..401499f6c5fa 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -192,7 +192,9 @@ fn run_pass_miri_noopt() { } #[test] -#[ignore] // FIXME: Disabled for now, as the optimizer is pretty broken and crashes... +#[ignore] +// FIXME: Disabled for now, as the optimizer is pretty broken and crashes... +// See https://github.com/rust-lang/rust/issues/50411 fn run_pass_miri_opt() { run_pass_miri(true); } @@ -204,13 +206,11 @@ fn run_pass_rustc() { } #[test] -#[should_panic] // TODO: update test errors fn compile_fail_miri() { let sysroot = get_sysroot(); let host = get_host(); // FIXME: run tests for other targets, too compile_fail(&sysroot, "tests/compile-fail", &host, &host, true); - compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true); } From 5f2f2546957e473bf146bcb35a96d80d60e4022d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Jul 2018 21:13:42 +0200 Subject: [PATCH 0122/5092] move tests that no longer need MIR out of fullmir --- README.md | 2 +- .../undefined_byte_read.rs | 0 tests/compiletest.rs | 2 +- tests/{run-pass-fullmir => run-pass}/heap.rs | 0 tests/{run-pass-fullmir => run-pass}/issue-15080.rs | 0 tests/{run-pass-fullmir => run-pass}/move-arg-2-unique.rs | 0 tests/{run-pass-fullmir => run-pass}/regions-mock-trans.rs | 0 tests/{run-pass-fullmir => run-pass}/vecs.rs | 0 8 files changed, 2 insertions(+), 2 deletions(-) rename tests/{compile-fail-fullmir => compile-fail}/undefined_byte_read.rs (100%) rename tests/{run-pass-fullmir => run-pass}/heap.rs (100%) rename tests/{run-pass-fullmir => run-pass}/issue-15080.rs (100%) rename tests/{run-pass-fullmir => run-pass}/move-arg-2-unique.rs (100%) rename tests/{run-pass-fullmir => run-pass}/regions-mock-trans.rs (100%) rename tests/{run-pass-fullmir => run-pass}/vecs.rs (100%) diff --git a/README.md b/README.md index 32eca3652945..38bf1147dab0 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ RUSTFLAGS='-Zalways-encode-mir' xargo build Now you can run miri against the libstd compiled by xargo: ```sh -MIRI_SYSROOT=~/.xargo/HOST cargo run --bin miri tests/run-pass-fullmir/vecs.rs +MIRI_SYSROOT=~/.xargo/HOST cargo run --bin miri tests/run-pass-fullmir/hashmap.rs ``` Notice that you will have to re-run the last step of the preparations above when diff --git a/tests/compile-fail-fullmir/undefined_byte_read.rs b/tests/compile-fail/undefined_byte_read.rs similarity index 100% rename from tests/compile-fail-fullmir/undefined_byte_read.rs rename to tests/compile-fail/undefined_byte_read.rs diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 401499f6c5fa..d5ed02504ab6 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -212,5 +212,5 @@ fn compile_fail_miri() { // FIXME: run tests for other targets, too compile_fail(&sysroot, "tests/compile-fail", &host, &host, true); - compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true); + //compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true); } diff --git a/tests/run-pass-fullmir/heap.rs b/tests/run-pass/heap.rs similarity index 100% rename from tests/run-pass-fullmir/heap.rs rename to tests/run-pass/heap.rs diff --git a/tests/run-pass-fullmir/issue-15080.rs b/tests/run-pass/issue-15080.rs similarity index 100% rename from tests/run-pass-fullmir/issue-15080.rs rename to tests/run-pass/issue-15080.rs diff --git a/tests/run-pass-fullmir/move-arg-2-unique.rs b/tests/run-pass/move-arg-2-unique.rs similarity index 100% rename from tests/run-pass-fullmir/move-arg-2-unique.rs rename to tests/run-pass/move-arg-2-unique.rs diff --git a/tests/run-pass-fullmir/regions-mock-trans.rs b/tests/run-pass/regions-mock-trans.rs similarity index 100% rename from tests/run-pass-fullmir/regions-mock-trans.rs rename to tests/run-pass/regions-mock-trans.rs diff --git a/tests/run-pass-fullmir/vecs.rs b/tests/run-pass/vecs.rs similarity index 100% rename from tests/run-pass-fullmir/vecs.rs rename to tests/run-pass/vecs.rs From eb8195f095e651842a93710ad005e6f1724373f4 Mon Sep 17 00:00:00 2001 From: memoryleak47 Date: Thu, 5 Apr 2018 04:25:43 +0200 Subject: [PATCH 0123/5092] typo --- tests/run-pass/regions-mock-trans.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/regions-mock-trans.rs b/tests/run-pass/regions-mock-trans.rs index cef62e47a56c..74e94ddbf84f 100644 --- a/tests/run-pass/regions-mock-trans.rs +++ b/tests/run-pass/regions-mock-trans.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME: We handle uninitialzied storage here, which currently makes validation fail. +// FIXME: We handle uninitialized storage here, which currently makes validation fail. // compile-flags: -Zmir-emit-validate=0 //ignore-msvc From 949106148cb7611ee2d8288b1092d1fa3ccdcbb0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Jul 2018 10:24:25 +0200 Subject: [PATCH 0124/5092] ignore panic test on Windows --- tests/compile-fail/panic.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/compile-fail/panic.rs b/tests/compile-fail/panic.rs index 80149eeffaa6..1f9e8f6e1d0b 100644 --- a/tests/compile-fail/panic.rs +++ b/tests/compile-fail/panic.rs @@ -1,3 +1,4 @@ +//ignore-windows // FIXME: Something in panic handling fails validation with full-MIR // compile-flags: -Zmir-emit-validate=0 //error-pattern: the evaluated program panicked From 01578ca6b3b976799c6cc6ba607143ed81f09a79 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Jul 2018 10:58:48 +0200 Subject: [PATCH 0125/5092] don't run all compile-fail tests with full MIR --- .../deallocate-bad-alignment.rs | 0 .../deallocate-bad-size.rs | 0 .../deallocate-twice.rs | 0 .../out_of_bounds_ptr_1.rs | 0 .../out_of_bounds_ptr_2.rs | 0 .../ptr_offset_overflow.rs | 0 .../reallocate-bad-size.rs | 0 .../reallocate-change-alloc.rs | 0 .../reallocate-dangling.rs | 0 tests/{compile-fail => compile-fail-fullmir}/stack_free.rs | 0 tests/compiletest.rs | 4 ++-- 11 files changed, 2 insertions(+), 2 deletions(-) rename tests/{compile-fail => compile-fail-fullmir}/deallocate-bad-alignment.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/deallocate-bad-size.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/deallocate-twice.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/out_of_bounds_ptr_1.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/out_of_bounds_ptr_2.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/ptr_offset_overflow.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/reallocate-bad-size.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/reallocate-change-alloc.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/reallocate-dangling.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stack_free.rs (100%) diff --git a/tests/compile-fail/deallocate-bad-alignment.rs b/tests/compile-fail-fullmir/deallocate-bad-alignment.rs similarity index 100% rename from tests/compile-fail/deallocate-bad-alignment.rs rename to tests/compile-fail-fullmir/deallocate-bad-alignment.rs diff --git a/tests/compile-fail/deallocate-bad-size.rs b/tests/compile-fail-fullmir/deallocate-bad-size.rs similarity index 100% rename from tests/compile-fail/deallocate-bad-size.rs rename to tests/compile-fail-fullmir/deallocate-bad-size.rs diff --git a/tests/compile-fail/deallocate-twice.rs b/tests/compile-fail-fullmir/deallocate-twice.rs similarity index 100% rename from tests/compile-fail/deallocate-twice.rs rename to tests/compile-fail-fullmir/deallocate-twice.rs diff --git a/tests/compile-fail/out_of_bounds_ptr_1.rs b/tests/compile-fail-fullmir/out_of_bounds_ptr_1.rs similarity index 100% rename from tests/compile-fail/out_of_bounds_ptr_1.rs rename to tests/compile-fail-fullmir/out_of_bounds_ptr_1.rs diff --git a/tests/compile-fail/out_of_bounds_ptr_2.rs b/tests/compile-fail-fullmir/out_of_bounds_ptr_2.rs similarity index 100% rename from tests/compile-fail/out_of_bounds_ptr_2.rs rename to tests/compile-fail-fullmir/out_of_bounds_ptr_2.rs diff --git a/tests/compile-fail/ptr_offset_overflow.rs b/tests/compile-fail-fullmir/ptr_offset_overflow.rs similarity index 100% rename from tests/compile-fail/ptr_offset_overflow.rs rename to tests/compile-fail-fullmir/ptr_offset_overflow.rs diff --git a/tests/compile-fail/reallocate-bad-size.rs b/tests/compile-fail-fullmir/reallocate-bad-size.rs similarity index 100% rename from tests/compile-fail/reallocate-bad-size.rs rename to tests/compile-fail-fullmir/reallocate-bad-size.rs diff --git a/tests/compile-fail/reallocate-change-alloc.rs b/tests/compile-fail-fullmir/reallocate-change-alloc.rs similarity index 100% rename from tests/compile-fail/reallocate-change-alloc.rs rename to tests/compile-fail-fullmir/reallocate-change-alloc.rs diff --git a/tests/compile-fail/reallocate-dangling.rs b/tests/compile-fail-fullmir/reallocate-dangling.rs similarity index 100% rename from tests/compile-fail/reallocate-dangling.rs rename to tests/compile-fail-fullmir/reallocate-dangling.rs diff --git a/tests/compile-fail/stack_free.rs b/tests/compile-fail-fullmir/stack_free.rs similarity index 100% rename from tests/compile-fail/stack_free.rs rename to tests/compile-fail-fullmir/stack_free.rs diff --git a/tests/compiletest.rs b/tests/compiletest.rs index d5ed02504ab6..a521217fc5c2 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -211,6 +211,6 @@ fn compile_fail_miri() { let host = get_host(); // FIXME: run tests for other targets, too - compile_fail(&sysroot, "tests/compile-fail", &host, &host, true); - //compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true); + compile_fail(&sysroot, "tests/compile-fail", &host, &host, false); + compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true); } From 8ce16a7c30b551cf36314af183fd5c49308d60cc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Jul 2018 11:01:09 +0200 Subject: [PATCH 0126/5092] remove xargo logic; instead rely on MIRI_SYSROOT being set to run full MIR tests --- Cargo.toml | 1 - tests/compiletest.rs | 78 +++++++++++++++++++++++--------------------- 2 files changed, 40 insertions(+), 39 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 54a1c5456e47..86ac2c040fd1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,4 +31,3 @@ cargo_miri = ["cargo_metadata"] [dev-dependencies] compiletest_rs = { version = "0.3.4", features = ["tmp"] } -dirs = "1.0.2" diff --git a/tests/compiletest.rs b/tests/compiletest.rs index a521217fc5c2..9a2fd02f88cd 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -1,7 +1,6 @@ #![feature(slice_concat_ext)] extern crate compiletest_rs as compiletest; -extern crate dirs; use std::slice::SliceConcatExt; use std::path::{PathBuf, Path}; @@ -31,7 +30,21 @@ fn rustc_lib_path() -> PathBuf { option_env!("RUSTC_LIB_PATH").unwrap().into() } -fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, fullmir: bool) { +fn have_fullmir() -> bool { + // We assume we have full MIR when MIRI_SYSROOT is set or when we are in rustc + std::env::var("MIRI_SYSROOT").is_ok() || rustc_test_suite().is_some() +} + +fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: bool) { + if need_fullmir && !have_fullmir() { + eprintln!( + "## Skipping compile-fail tests in {} against miri for target {} due to missing mir", + path, + target + ); + return; + } + eprintln!( "## Running compile-fail tests in {} against miri for target {}", path, @@ -45,28 +58,16 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, fullmir: b config.run_lib_path = rustc_lib_path(); config.compile_lib_path = rustc_lib_path(); } - // if we are building as part of the rustc test suite, we already have fullmir for everything - if fullmir && rustc_test_suite().is_none() { - if host != target { - // skip fullmir on nonhost - return; - } - let sysroot = dirs::home_dir().unwrap() - .join(".xargo") - .join("HOST"); - flags.push(format!("--sysroot {}", sysroot.to_str().unwrap())); - config.src_base = PathBuf::from(path.to_string()); - } else { - flags.push(format!("--sysroot {}", sysroot.to_str().unwrap())); - config.src_base = PathBuf::from(path.to_string()); - } + flags.push(format!("--sysroot {}", sysroot.display())); + config.src_base = PathBuf::from(path.to_string()); flags.push("-Zmir-emit-validate=1".to_owned()); config.target_rustcflags = Some(flags.join(" ")); config.target = target.to_owned(); + config.host = host.to_owned(); compiletest::run_tests(&config); } -fn run_pass(path: &str) { +fn rustc_pass(sysroot: &Path, path: &str) { eprintln!("## Running run-pass tests in {} against rustc", path); let mut config = compiletest::Config::default().tempdir(); config.mode = "run-pass".parse().expect("Invalid mode"); @@ -75,7 +76,7 @@ fn run_pass(path: &str) { config.rustc_path = rustc_path; config.run_lib_path = rustc_lib_path(); config.compile_lib_path = rustc_lib_path(); - config.target_rustcflags = Some(format!("-Dwarnings --sysroot {}", get_sysroot().display())); + config.target_rustcflags = Some(format!("-Dwarnings --sysroot {}", sysroot.display())); } else { config.target_rustcflags = Some("-Dwarnings".to_owned()); } @@ -83,7 +84,16 @@ fn run_pass(path: &str) { compiletest::run_tests(&config); } -fn miri_pass(path: &str, target: &str, host: &str, fullmir: bool, opt: bool) { +fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: bool, opt: bool) { + if need_fullmir && !have_fullmir() { + eprintln!( + "## Skipping run-pass tests in {} against miri for target {} due to missing mir", + path, + target + ); + return; + } + let opt_str = if opt { " with optimizations" } else { "" }; eprintln!( "## Running run-pass tests in {} against miri for target {}{}", @@ -102,21 +112,9 @@ fn miri_pass(path: &str, target: &str, host: &str, fullmir: bool, opt: bool) { config.compile_lib_path = rustc_lib_path(); } let mut flags = Vec::new(); - // Control miri logging. This is okay despite concurrent test execution as all tests - // will set this env var to the same value. - env::set_var("MIRI_LOG", "warn"); - // if we are building as part of the rustc test suite, we already have fullmir for everything - if fullmir && rustc_test_suite().is_none() { - if host != target { - // skip fullmir on nonhost - return; - } - let sysroot = dirs::home_dir().unwrap() - .join(".xargo") - .join("HOST"); - + flags.push(format!("--sysroot {}", sysroot.display())); + if have_fullmir() { flags.push("-Zmiri-start-fn".to_owned()); - flags.push(format!("--sysroot {}", sysroot.to_str().unwrap())); } if opt { flags.push("-Zmir-opt-level=3".to_owned()); @@ -125,6 +123,9 @@ fn miri_pass(path: &str, target: &str, host: &str, fullmir: bool, opt: bool) { // For now, only validate without optimizations. Inlining breaks validation. flags.push("-Zmir-emit-validate=1".to_owned()); } + // Control miri logging. This is okay despite concurrent test execution as all tests + // will set this env var to the same value. + env::set_var("MIRI_LOG", "warn"); config.target_rustcflags = Some(flags.join(" ")); compiletest::run_tests(&config); } @@ -181,9 +182,9 @@ fn run_pass_miri(opt: bool) { let host = get_host(); for_all_targets(&sysroot, |target| { - miri_pass("tests/run-pass", &target, &host, false, opt); + miri_pass(&sysroot, "tests/run-pass", &target, &host, false, opt); }); - miri_pass("tests/run-pass-fullmir", &host, &host, true, opt); + miri_pass(&sysroot, "tests/run-pass-fullmir", &host, &host, true, opt); } #[test] @@ -201,8 +202,9 @@ fn run_pass_miri_opt() { #[test] fn run_pass_rustc() { - run_pass("tests/run-pass"); - run_pass("tests/run-pass-fullmir"); + let sysroot = get_sysroot(); + rustc_pass(&sysroot, "tests/run-pass"); + rustc_pass(&sysroot, "tests/run-pass-fullmir"); } #[test] From 9718d73ac86a428b7e11de8ef0215ff6ac85d9fb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Jul 2018 11:26:09 +0200 Subject: [PATCH 0127/5092] colored test output! --- Cargo.toml | 1 + tests/compiletest.rs | 21 ++++++++++++--------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 86ac2c040fd1..d01ce4f5baf8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,3 +31,4 @@ cargo_miri = ["cargo_metadata"] [dev-dependencies] compiletest_rs = { version = "0.3.4", features = ["tmp"] } +colored = "1.6" diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 9a2fd02f88cd..cfbfa70d42ee 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -1,6 +1,9 @@ #![feature(slice_concat_ext)] extern crate compiletest_rs as compiletest; +extern crate colored; + +use colored::*; use std::slice::SliceConcatExt; use std::path::{PathBuf, Path}; @@ -37,19 +40,19 @@ fn have_fullmir() -> bool { fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: bool) { if need_fullmir && !have_fullmir() { - eprintln!( + eprintln!("{}", format!( "## Skipping compile-fail tests in {} against miri for target {} due to missing mir", path, target - ); + ).yellow().bold()); return; } - eprintln!( + eprintln!("{}", format!( "## Running compile-fail tests in {} against miri for target {}", path, target - ); + ).green().bold()); let mut config = compiletest::Config::default().tempdir(); config.mode = "compile-fail".parse().expect("Invalid mode"); config.rustc_path = miri_path(); @@ -68,7 +71,7 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullm } fn rustc_pass(sysroot: &Path, path: &str) { - eprintln!("## Running run-pass tests in {} against rustc", path); + eprintln!("{}", format!("## Running run-pass tests in {} against rustc", path).green().bold()); let mut config = compiletest::Config::default().tempdir(); config.mode = "run-pass".parse().expect("Invalid mode"); config.src_base = PathBuf::from(path); @@ -86,21 +89,21 @@ fn rustc_pass(sysroot: &Path, path: &str) { fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: bool, opt: bool) { if need_fullmir && !have_fullmir() { - eprintln!( + eprintln!("{}", format!( "## Skipping run-pass tests in {} against miri for target {} due to missing mir", path, target - ); + ).yellow().bold()); return; } let opt_str = if opt { " with optimizations" } else { "" }; - eprintln!( + eprintln!("{}", format!( "## Running run-pass tests in {} against miri for target {}{}", path, target, opt_str - ); + ).green().bold()); let mut config = compiletest::Config::default().tempdir(); config.mode = "ui".parse().expect("Invalid mode"); config.src_base = PathBuf::from(path); From 105f7e7fb28041a7e0fb13123d5caadbaf881f24 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Jul 2018 14:24:35 +0200 Subject: [PATCH 0128/5092] update debugging instructions in the README --- README.md | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 38bf1147dab0..d0ae5ec46ff9 100644 --- a/README.md +++ b/README.md @@ -42,10 +42,22 @@ cargo run --bin miri tests/run-pass-fullmir/vecs.rs # Or whatever test you like. ## Debugging -You can get detailed, statement-by-statement traces by setting the `MIRI_LOG` -environment variable to `trace`. These traces are indented based on call stack -depth. You can get a much less verbose set of information with other logging -levels such as `warn`. +Since the heart of miri (the main interpreter engine) lives in rustc, tracing +the interpreter requires a version of rustc compiled with tracing. To this +end, you will have to compile your own rustc: +``` +git clone https://github.com/rust-lang/rust/ rustc +cd rustc +cp config.toml.example config.toml +# Now edit `config.toml` and set `debug-assertions = true` +./x.py build +rustup toolchain link custom build/x86_64-unknown-linux-gnu/stage2 +``` +The `build` step can take 30 to 60 minutes. + +Now, in the miri directory, you can `rustup override set custom` and re-build +everything. Finally, if you now set `RUST_LOG=rustc_mir::interpret=trace` as +environment variable, you will get detailed step-by-step tracing information. ## Running miri on your own project('s test suite) From 25c067ac7a82027c01035824257010dd6f84cb42 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Jul 2018 15:01:10 +0200 Subject: [PATCH 0129/5092] testsuite: put everything into a single test to fix interleaved output mess --- tests/compiletest.rs | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index cfbfa70d42ee..896d1cae5969 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -190,27 +190,12 @@ fn run_pass_miri(opt: bool) { miri_pass(&sysroot, "tests/run-pass-fullmir", &host, &host, true, opt); } -#[test] -fn run_pass_miri_noopt() { - run_pass_miri(false); -} - -#[test] -#[ignore] -// FIXME: Disabled for now, as the optimizer is pretty broken and crashes... -// See https://github.com/rust-lang/rust/issues/50411 -fn run_pass_miri_opt() { - run_pass_miri(true); -} - -#[test] fn run_pass_rustc() { let sysroot = get_sysroot(); rustc_pass(&sysroot, "tests/run-pass"); rustc_pass(&sysroot, "tests/run-pass-fullmir"); } -#[test] fn compile_fail_miri() { let sysroot = get_sysroot(); let host = get_host(); @@ -219,3 +204,20 @@ fn compile_fail_miri() { compile_fail(&sysroot, "tests/compile-fail", &host, &host, false); compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true); } + +#[test] +fn test() { + // We put everything into a single test to avoid the parallelism `cargo test` + // introduces. We still get parallelism within our tests because `compiletest` + // uses `libtest` which runs jobs in parallel. + + run_pass_rustc(); + + run_pass_miri(false); + + // FIXME: Disabled for now, as the optimizer is pretty broken and crashes... + // See https://github.com/rust-lang/rust/issues/50411 + //run_pass_miri(true); + + compile_fail_miri(); +} From 473c50405da7f11d2b33921d2910ae82184ad7fa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 14 Jul 2018 11:02:09 +0200 Subject: [PATCH 0130/5092] refine rustc build instructions --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d0ae5ec46ff9..4891575c05e5 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ git clone https://github.com/rust-lang/rust/ rustc cd rustc cp config.toml.example config.toml # Now edit `config.toml` and set `debug-assertions = true` -./x.py build +./x.py build src/rustc rustup toolchain link custom build/x86_64-unknown-linux-gnu/stage2 ``` The `build` step can take 30 to 60 minutes. From 30185d09f627e15effbb346bcacf06a37c7299e7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 15 Jul 2018 11:21:56 +0200 Subject: [PATCH 0131/5092] make sure we show error messages even when we cannot show span --- src/lib.rs | 6 ++++-- tests/compile-fail-fullmir/reallocate-change-alloc.rs | 2 +- tests/compile-fail/alignment.rs | 2 +- tests/compile-fail/assume.rs | 2 +- tests/compile-fail/bitop-beyond-alignment.rs | 2 +- tests/compile-fail/cast_box_int_to_fn_ptr.rs | 2 +- tests/compile-fail/cast_fn_ptr.rs | 2 +- tests/compile-fail/cast_fn_ptr2.rs | 2 +- tests/compile-fail/cast_int_to_fn_ptr.rs | 2 +- tests/compile-fail/ctlz_nonzero.rs | 2 +- tests/compile-fail/cttz_nonzero.rs | 2 +- tests/compile-fail/dangling_pointer_deref.rs | 2 +- tests/compile-fail/deref_fn_ptr.rs | 2 +- tests/compile-fail/div-by-zero-2.rs | 2 +- tests/compile-fail/execute_memory.rs | 2 +- tests/compile-fail/fn_ptr_offset.rs | 2 +- tests/compile-fail/invalid_bool.rs | 2 +- tests/compile-fail/invalid_enum_discriminant.rs | 2 +- tests/compile-fail/match_char.rs | 2 +- tests/compile-fail/modifying_constants.rs | 2 +- tests/compile-fail/never_say_never.rs | 2 +- tests/compile-fail/never_transmute_humans.rs | 2 +- tests/compile-fail/never_transmute_void.rs | 2 +- tests/compile-fail/null_pointer_deref.rs | 2 +- tests/compile-fail/out_of_bounds_read.rs | 2 +- tests/compile-fail/out_of_bounds_read2.rs | 2 +- tests/compile-fail/overflowing-lsh-neg.rs | 2 +- tests/compile-fail/overflowing-rsh-2.rs | 2 +- tests/compile-fail/overflowing-rsh.rs | 2 +- ...erwriting_part_of_relocation_makes_the_rest_undefined.rs | 2 +- tests/compile-fail/pointer_byte_read_1.rs | 2 +- tests/compile-fail/pointer_byte_read_2.rs | 2 +- .../pointers_to_different_allocations_are_unorderable.rs | 2 +- tests/compile-fail/ptr_bitops.rs | 2 +- tests/compile-fail/ptr_int_cast.rs | 2 +- tests/compile-fail/reading_half_a_pointer.rs | 2 +- tests/compile-fail/reference_to_packed.rs | 2 +- tests/compile-fail/static_memory_modification.rs | 2 +- tests/compile-fail/static_memory_modification2.rs | 2 +- tests/compile-fail/static_memory_modification3.rs | 2 +- tests/compile-fail/transmute-pair-undef.rs | 2 +- tests/compile-fail/transmute_fat.rs | 2 +- tests/compile-fail/transmute_fat2.rs | 2 +- tests/compile-fail/unaligned_ptr_cast.rs | 2 +- tests/compile-fail/unaligned_ptr_cast2.rs | 2 +- tests/compile-fail/unaligned_ptr_cast_zst.rs | 2 +- tests/compile-fail/wild_pointer_deref.rs | 2 +- tests/compile-fail/zst.rs | 2 +- 48 files changed, 51 insertions(+), 49 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 75397262b225..520d696405a1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -274,9 +274,11 @@ pub fn eval_main<'a, 'tcx: 'a>( block.terminator().source_info.span }; - let mut err = struct_error(ecx.tcx.tcx.at(span), "constant evaluation error"); + let e = e.to_string(); + let msg = format!("constant evaluation error: {}", e); + let mut err = struct_error(ecx.tcx.tcx.at(span), msg.as_str()); let (frames, span) = ecx.generate_stacktrace(None); - err.span_label(span, e.to_string()); + err.span_label(span, e); for FrameInfo { span, location, .. } in frames { err.span_note(span, &format!("inside call to `{}`", location)); } diff --git a/tests/compile-fail-fullmir/reallocate-change-alloc.rs b/tests/compile-fail-fullmir/reallocate-change-alloc.rs index 03040cd178da..a44ccf4c49cd 100644 --- a/tests/compile-fail-fullmir/reallocate-change-alloc.rs +++ b/tests/compile-fail-fullmir/reallocate-change-alloc.rs @@ -9,7 +9,7 @@ fn main() { unsafe { let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); let _y = Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1).unwrap(); - let _z = *(x.as_ptr() as *mut u8); //~ ERROR constant evaluation error [E0080] + let _z = *(x.as_ptr() as *mut u8); //~ ERROR constant evaluation error //~^ NOTE dangling pointer was dereferenced } } diff --git a/tests/compile-fail/alignment.rs b/tests/compile-fail/alignment.rs index 9730fe473aa5..71161f5d6da0 100644 --- a/tests/compile-fail/alignment.rs +++ b/tests/compile-fail/alignment.rs @@ -5,7 +5,7 @@ fn main() { let x_ptr: *mut u8 = &mut x[0]; let y_ptr = x_ptr as *mut u64; unsafe { - *y_ptr = 42; //~ ERROR constant evaluation error [E0080] + *y_ptr = 42; //~ ERROR constant evaluation error //~^ NOTE tried to access memory with alignment 1, but alignment } panic!("unreachable in miri"); diff --git a/tests/compile-fail/assume.rs b/tests/compile-fail/assume.rs index cf0632393ad6..d9eec480cd0c 100644 --- a/tests/compile-fail/assume.rs +++ b/tests/compile-fail/assume.rs @@ -5,7 +5,7 @@ fn main() { unsafe { std::intrinsics::assume(x < 10); std::intrinsics::assume(x > 1); - std::intrinsics::assume(x > 42); //~ ERROR constant evaluation error [E0080] + std::intrinsics::assume(x > 42); //~ ERROR constant evaluation error //~^ NOTE `assume` argument was false } } diff --git a/tests/compile-fail/bitop-beyond-alignment.rs b/tests/compile-fail/bitop-beyond-alignment.rs index 89f5e048a36d..c8cbc9a91841 100644 --- a/tests/compile-fail/bitop-beyond-alignment.rs +++ b/tests/compile-fail/bitop-beyond-alignment.rs @@ -28,7 +28,7 @@ fn mk_rec() -> Rec { fn is_u64_aligned(u: &Tag) -> bool { let p: usize = unsafe { mem::transmute(u) }; let u64_align = std::mem::align_of::(); - return (p & (u64_align + 1)) == 0; //~ ERROR constant evaluation error [E0080] + return (p & (u64_align + 1)) == 0; //~ ERROR constant evaluation error //~^ NOTE a raw memory access tried to access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/cast_box_int_to_fn_ptr.rs b/tests/compile-fail/cast_box_int_to_fn_ptr.rs index 39b53da0b75c..2a317f579f5e 100644 --- a/tests/compile-fail/cast_box_int_to_fn_ptr.rs +++ b/tests/compile-fail/cast_box_int_to_fn_ptr.rs @@ -7,6 +7,6 @@ fn main() { std::mem::transmute::<&usize, &fn(i32)>(&b) }; - (*g)(42) //~ ERROR constant evaluation error [E0080] + (*g)(42) //~ ERROR constant evaluation error //~^ NOTE a memory access tried to interpret some bytes as a pointer } diff --git a/tests/compile-fail/cast_fn_ptr.rs b/tests/compile-fail/cast_fn_ptr.rs index 19344b13ba7c..0a8f5ef752a6 100644 --- a/tests/compile-fail/cast_fn_ptr.rs +++ b/tests/compile-fail/cast_fn_ptr.rs @@ -5,6 +5,6 @@ fn main() { std::mem::transmute::(f) }; - g(42) //~ ERROR constant evaluation error [E0080] + g(42) //~ ERROR constant evaluation error //~^ NOTE tried to call a function with sig fn() through a function pointer of type fn(i32) } diff --git a/tests/compile-fail/cast_fn_ptr2.rs b/tests/compile-fail/cast_fn_ptr2.rs index 23868c0e57db..cb80521c60ee 100644 --- a/tests/compile-fail/cast_fn_ptr2.rs +++ b/tests/compile-fail/cast_fn_ptr2.rs @@ -5,6 +5,6 @@ fn main() { std::mem::transmute::(f) }; - g(42) //~ ERROR constant evaluation error [E0080] + g(42) //~ ERROR constant evaluation error //~^ NOTE tried to call a function with sig fn((i32, i32)) through a function pointer of type fn(i32) } diff --git a/tests/compile-fail/cast_int_to_fn_ptr.rs b/tests/compile-fail/cast_int_to_fn_ptr.rs index c7556ae06b93..29d16e9a4259 100644 --- a/tests/compile-fail/cast_int_to_fn_ptr.rs +++ b/tests/compile-fail/cast_int_to_fn_ptr.rs @@ -6,6 +6,6 @@ fn main() { std::mem::transmute::(42) }; - g(42) //~ ERROR constant evaluation error [E0080] + g(42) //~ ERROR constant evaluation error //~^ NOTE a memory access tried to interpret some bytes as a pointer } diff --git a/tests/compile-fail/ctlz_nonzero.rs b/tests/compile-fail/ctlz_nonzero.rs index d952187eba45..167100903f4d 100644 --- a/tests/compile-fail/ctlz_nonzero.rs +++ b/tests/compile-fail/ctlz_nonzero.rs @@ -10,7 +10,7 @@ pub fn main() { unsafe { use rusti::*; - ctlz_nonzero(0u8); //~ ERROR constant evaluation error [E0080] + ctlz_nonzero(0u8); //~ ERROR constant evaluation error //~^ NOTE ctlz_nonzero called on 0 } } diff --git a/tests/compile-fail/cttz_nonzero.rs b/tests/compile-fail/cttz_nonzero.rs index b308484622bc..7d9ac5a0212d 100644 --- a/tests/compile-fail/cttz_nonzero.rs +++ b/tests/compile-fail/cttz_nonzero.rs @@ -10,7 +10,7 @@ pub fn main() { unsafe { use rusti::*; - cttz_nonzero(0u8); //~ ERROR constant evaluation error [E0080] + cttz_nonzero(0u8); //~ ERROR constant evaluation error //~^ NOTE cttz_nonzero called on 0 } } diff --git a/tests/compile-fail/dangling_pointer_deref.rs b/tests/compile-fail/dangling_pointer_deref.rs index d42c1d33b530..434f5c780b46 100644 --- a/tests/compile-fail/dangling_pointer_deref.rs +++ b/tests/compile-fail/dangling_pointer_deref.rs @@ -3,7 +3,7 @@ fn main() { let b = Box::new(42); &*b as *const i32 }; - let x = unsafe { *p }; //~ ERROR constant evaluation error [E0080] + let x = unsafe { *p }; //~ ERROR constant evaluation error //~^ NOTE dangling pointer was dereferenced panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/deref_fn_ptr.rs b/tests/compile-fail/deref_fn_ptr.rs index a56df5bce408..fb3aea67e821 100644 --- a/tests/compile-fail/deref_fn_ptr.rs +++ b/tests/compile-fail/deref_fn_ptr.rs @@ -2,7 +2,7 @@ fn f() {} fn main() { let x: i32 = unsafe { - *std::mem::transmute::(f) //~ ERROR constant evaluation error [E0080] + *std::mem::transmute::(f) //~ ERROR constant evaluation error //~^ NOTE tried to dereference a function pointer }; panic!("this should never print: {}", x); diff --git a/tests/compile-fail/div-by-zero-2.rs b/tests/compile-fail/div-by-zero-2.rs index c90ca8d15cce..94145c2cf32f 100644 --- a/tests/compile-fail/div-by-zero-2.rs +++ b/tests/compile-fail/div-by-zero-2.rs @@ -11,6 +11,6 @@ #![allow(const_err)] fn main() { - let _n = 1 / 0; //~ ERROR constant evaluation error [E0080] + let _n = 1 / 0; //~ ERROR constant evaluation error //~^ NOTE attempt to divide by zero } diff --git a/tests/compile-fail/execute_memory.rs b/tests/compile-fail/execute_memory.rs index 014c551df0f1..bcde13d13ee7 100644 --- a/tests/compile-fail/execute_memory.rs +++ b/tests/compile-fail/execute_memory.rs @@ -7,7 +7,7 @@ fn main() { let x = box 42; unsafe { let f = std::mem::transmute::, fn()>(x); - f() //~ ERROR constant evaluation error [E0080] + f() //~ ERROR constant evaluation error //~^ NOTE tried to treat a memory pointer as a function pointer } } diff --git a/tests/compile-fail/fn_ptr_offset.rs b/tests/compile-fail/fn_ptr_offset.rs index 20eb6573989c..0c0590e375bb 100644 --- a/tests/compile-fail/fn_ptr_offset.rs +++ b/tests/compile-fail/fn_ptr_offset.rs @@ -10,6 +10,6 @@ fn main() { let y : *mut u8 = unsafe { mem::transmute(x) }; let y = y.wrapping_offset(1); let x : fn() = unsafe { mem::transmute(y) }; - x(); //~ ERROR constant evaluation error [E0080] + x(); //~ ERROR constant evaluation error //~^ NOTE tried to use a function pointer after offsetting it } diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index 07c407966a8f..1aa5d9bf77bc 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -1,5 +1,5 @@ fn main() { let b = unsafe { std::mem::transmute::(2) }; - if b { unreachable!() } else { unreachable!() } //~ ERROR constant evaluation error [E0080] + if b { unreachable!() } else { unreachable!() } //~ ERROR constant evaluation error //~^ NOTE invalid boolean value read } diff --git a/tests/compile-fail/invalid_enum_discriminant.rs b/tests/compile-fail/invalid_enum_discriminant.rs index 69d7e3e427d4..760b6563d27c 100644 --- a/tests/compile-fail/invalid_enum_discriminant.rs +++ b/tests/compile-fail/invalid_enum_discriminant.rs @@ -14,5 +14,5 @@ fn main() { Foo::C => {}, Foo::D => {}, } -} //~ ERROR constant evaluation error [E0080] +} //~ ERROR constant evaluation error //~^ NOTE entered unreachable code diff --git a/tests/compile-fail/match_char.rs b/tests/compile-fail/match_char.rs index 0d45d70eb781..52f33b58e6fb 100644 --- a/tests/compile-fail/match_char.rs +++ b/tests/compile-fail/match_char.rs @@ -2,7 +2,7 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); - match unsafe { std::mem::transmute::(-1) } { //~ ERROR constant evaluation error [E0080] + match unsafe { std::mem::transmute::(-1) } { //~ ERROR constant evaluation error //~^ NOTE tried to interpret an invalid 32-bit value as a char: 4294967295 'a' => {}, 'b' => {}, diff --git a/tests/compile-fail/modifying_constants.rs b/tests/compile-fail/modifying_constants.rs index 06920fa0acf1..c10657ae75a7 100644 --- a/tests/compile-fail/modifying_constants.rs +++ b/tests/compile-fail/modifying_constants.rs @@ -1,7 +1,7 @@ fn main() { let x = &1; // the `&1` is promoted to a constant, but it used to be that only the pointer is marked static, not the pointee let y = unsafe { &mut *(x as *const i32 as *mut i32) }; - *y = 42; //~ ERROR constant evaluation error [E0080] + *y = 42; //~ ERROR constant evaluation error //~^ NOTE tried to modify constant memory assert_eq!(*x, 42); } diff --git a/tests/compile-fail/never_say_never.rs b/tests/compile-fail/never_say_never.rs index de8815ffd9c4..fd76ecbd1503 100644 --- a/tests/compile-fail/never_say_never.rs +++ b/tests/compile-fail/never_say_never.rs @@ -7,7 +7,7 @@ fn main() { let y = &5; let x: ! = unsafe { - *(y as *const _ as *const !) //~ ERROR constant evaluation error [E0080] + *(y as *const _ as *const !) //~ ERROR constant evaluation error //~^ NOTE entered unreachable code }; f(x) diff --git a/tests/compile-fail/never_transmute_humans.rs b/tests/compile-fail/never_transmute_humans.rs index 3422d52f9c04..7652cdfdd3df 100644 --- a/tests/compile-fail/never_transmute_humans.rs +++ b/tests/compile-fail/never_transmute_humans.rs @@ -9,7 +9,7 @@ struct Human; fn main() { let x: ! = unsafe { - std::mem::transmute::(Human) //~ ERROR constant evaluation error [E0080] + std::mem::transmute::(Human) //~ ERROR constant evaluation error //^~ NOTE entered unreachable code }; f(x) diff --git a/tests/compile-fail/never_transmute_void.rs b/tests/compile-fail/never_transmute_void.rs index 4f1499483eda..9329cd365994 100644 --- a/tests/compile-fail/never_transmute_void.rs +++ b/tests/compile-fail/never_transmute_void.rs @@ -8,7 +8,7 @@ enum Void {} fn f(v: Void) -> ! { - match v {} //~ ERROR constant evaluation error [E0080] + match v {} //~ ERROR constant evaluation error //~^ NOTE entered unreachable code } diff --git a/tests/compile-fail/null_pointer_deref.rs b/tests/compile-fail/null_pointer_deref.rs index 70df937c4c7c..f69308296bc2 100644 --- a/tests/compile-fail/null_pointer_deref.rs +++ b/tests/compile-fail/null_pointer_deref.rs @@ -1,5 +1,5 @@ fn main() { - let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR constant evaluation error [E0080] + let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR constant evaluation error //~^ NOTE invalid use of NULL pointer panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/out_of_bounds_read.rs b/tests/compile-fail/out_of_bounds_read.rs index d8811e7abcd2..3ccdb365feeb 100644 --- a/tests/compile-fail/out_of_bounds_read.rs +++ b/tests/compile-fail/out_of_bounds_read.rs @@ -1,6 +1,6 @@ fn main() { let v: Vec = vec![1, 2]; - let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR constant evaluation error [E0080] + let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR constant evaluation error //~^ NOTE which has size 2 panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/out_of_bounds_read2.rs b/tests/compile-fail/out_of_bounds_read2.rs index 54738cf81fbd..811ba7d4b26c 100644 --- a/tests/compile-fail/out_of_bounds_read2.rs +++ b/tests/compile-fail/out_of_bounds_read2.rs @@ -1,6 +1,6 @@ fn main() { let v: Vec = vec![1, 2]; - let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR constant evaluation error [E0080] + let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR constant evaluation error //~^ NOTE memory access at offset 6, outside bounds of allocation panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/overflowing-lsh-neg.rs b/tests/compile-fail/overflowing-lsh-neg.rs index e50e42503649..825a82226634 100644 --- a/tests/compile-fail/overflowing-lsh-neg.rs +++ b/tests/compile-fail/overflowing-lsh-neg.rs @@ -12,6 +12,6 @@ #![allow(const_err)] fn main() { - let _n = 2i64 << -1; //~ ERROR constant evaluation error [E0080] + let _n = 2i64 << -1; //~ ERROR constant evaluation error //~^ NOTE attempt to shift left with overflow } diff --git a/tests/compile-fail/overflowing-rsh-2.rs b/tests/compile-fail/overflowing-rsh-2.rs index 967c8b020cca..cf107a76ae29 100644 --- a/tests/compile-fail/overflowing-rsh-2.rs +++ b/tests/compile-fail/overflowing-rsh-2.rs @@ -12,6 +12,6 @@ fn main() { // Make sure we catch overflows that would be hidden by first casting the RHS to u32 - let _n = 1i64 >> (u32::max_value() as i64 + 1); //~ ERROR constant evaluation error [E0080] + let _n = 1i64 >> (u32::max_value() as i64 + 1); //~ ERROR constant evaluation error //~^ NOTE attempt to shift right with overflow } diff --git a/tests/compile-fail/overflowing-rsh.rs b/tests/compile-fail/overflowing-rsh.rs index c291815e2e79..ea53d7e73092 100644 --- a/tests/compile-fail/overflowing-rsh.rs +++ b/tests/compile-fail/overflowing-rsh.rs @@ -11,6 +11,6 @@ #![allow(exceeding_bitshifts)] fn main() { - let _n = 1i64 >> 64; //~ ERROR constant evaluation error [E0080] + let _n = 1i64 >> 64; //~ ERROR constant evaluation error //~^ NOTE attempt to shift right with overflow } diff --git a/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs b/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs index fabbef5004d7..7c38c0574698 100644 --- a/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs +++ b/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs @@ -6,7 +6,7 @@ fn main() { // "attempted to interpret some raw bytes as a pointer address" instead of // "attempted to read undefined bytes" } - let x = *p; //~ ERROR constant evaluation error [E0080] + let x = *p; //~ ERROR constant evaluation error //~^ NOTE attempted to read undefined bytes panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/pointer_byte_read_1.rs b/tests/compile-fail/pointer_byte_read_1.rs index 012af897e837..b3aaec759ce0 100644 --- a/tests/compile-fail/pointer_byte_read_1.rs +++ b/tests/compile-fail/pointer_byte_read_1.rs @@ -3,6 +3,6 @@ fn main() { let y = &x; let z = &y as *const &i32 as *const usize; let ptr_bytes = unsafe { *z }; // the actual deref is fine, because we read the entire pointer at once - let _ = ptr_bytes % 432; //~ ERROR constant evaluation error [E0080] + let _ = ptr_bytes % 432; //~ ERROR constant evaluation error //~^ NOTE tried to access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/pointer_byte_read_2.rs b/tests/compile-fail/pointer_byte_read_2.rs index 4d25a36a3c88..c8a1a2e10f50 100644 --- a/tests/compile-fail/pointer_byte_read_2.rs +++ b/tests/compile-fail/pointer_byte_read_2.rs @@ -3,6 +3,6 @@ fn main() { let y = &x; let z = &y as *const &i32 as *const u8; // the deref fails, because we are reading only a part of the pointer - let _ = unsafe { *z }; //~ ERROR constant evaluation error [E0080] + let _ = unsafe { *z }; //~ ERROR constant evaluation error //~^ NOTE tried to access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs b/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs index 72ae1b123e8a..89cf357e201c 100644 --- a/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs +++ b/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs @@ -1,7 +1,7 @@ fn main() { let x: *const u8 = &1; let y: *const u8 = &2; - if x < y { //~ ERROR constant evaluation error [E0080] + if x < y { //~ ERROR constant evaluation error //~^ NOTE attempted to do invalid arithmetic on pointers unreachable!() } diff --git a/tests/compile-fail/ptr_bitops.rs b/tests/compile-fail/ptr_bitops.rs index 52bcf24cf6b8..ecd47a186efb 100644 --- a/tests/compile-fail/ptr_bitops.rs +++ b/tests/compile-fail/ptr_bitops.rs @@ -2,7 +2,7 @@ fn main() { let bytes = [0i8, 1, 2, 3, 4, 5, 6, 7, 8, 9]; let one = bytes.as_ptr().wrapping_offset(1); let three = bytes.as_ptr().wrapping_offset(3); - let res = (one as usize) | (three as usize); //~ ERROR constant evaluation error [E0080] + let res = (one as usize) | (three as usize); //~ ERROR constant evaluation error //~^ NOTE a raw memory access tried to access part of a pointer value as raw bytes println!("{}", res); } diff --git a/tests/compile-fail/ptr_int_cast.rs b/tests/compile-fail/ptr_int_cast.rs index 56403d619ffa..11243921bfd4 100644 --- a/tests/compile-fail/ptr_int_cast.rs +++ b/tests/compile-fail/ptr_int_cast.rs @@ -2,7 +2,7 @@ fn main() { let x = &1; // Casting down to u8 and back up to a pointer loses too much precision; this must not work. let x = x as *const i32; - let x = x as u8; //~ ERROR constant evaluation error [E0080] + let x = x as u8; //~ ERROR constant evaluation error //~^ NOTE a raw memory access tried to access part of a pointer value as raw bytes let x = x as *const i32; let _ = unsafe { *x }; diff --git a/tests/compile-fail/reading_half_a_pointer.rs b/tests/compile-fail/reading_half_a_pointer.rs index e44f26c4c4cf..3ea693a3f0fb 100644 --- a/tests/compile-fail/reading_half_a_pointer.rs +++ b/tests/compile-fail/reading_half_a_pointer.rs @@ -24,7 +24,7 @@ fn main() { // starts 1 byte to the right, so using it would actually be wrong! let d_alias = &mut w.data as *mut _ as *mut *const u8; unsafe { - let _x = *d_alias; //~ ERROR constant evaluation error [E0080] + let _x = *d_alias; //~ ERROR constant evaluation error //~^ NOTE tried to access part of a pointer value as raw bytes } } diff --git a/tests/compile-fail/reference_to_packed.rs b/tests/compile-fail/reference_to_packed.rs index 16b452ca0e3c..946a6b89a777 100644 --- a/tests/compile-fail/reference_to_packed.rs +++ b/tests/compile-fail/reference_to_packed.rs @@ -15,6 +15,6 @@ fn main() { y: 99, }; let p = unsafe { &foo.x }; - let i = *p; //~ ERROR constant evaluation error [E0080] + let i = *p; //~ ERROR constant evaluation error //~^ NOTE tried to access memory with alignment 1, but alignment 4 is required } diff --git a/tests/compile-fail/static_memory_modification.rs b/tests/compile-fail/static_memory_modification.rs index a85ff545ee42..e28bcb37fb72 100644 --- a/tests/compile-fail/static_memory_modification.rs +++ b/tests/compile-fail/static_memory_modification.rs @@ -4,7 +4,7 @@ static X: usize = 5; #[allow(mutable_transmutes)] fn main() { unsafe { - *std::mem::transmute::<&usize, &mut usize>(&X) = 6; //~ ERROR constant evaluation error [E0080] + *std::mem::transmute::<&usize, &mut usize>(&X) = 6; //~ ERROR constant evaluation error //~^ NOTE tried to modify constant memory assert_eq!(X, 6); } diff --git a/tests/compile-fail/static_memory_modification2.rs b/tests/compile-fail/static_memory_modification2.rs index 6abe6de1fcf4..2f702f09c804 100644 --- a/tests/compile-fail/static_memory_modification2.rs +++ b/tests/compile-fail/static_memory_modification2.rs @@ -7,7 +7,7 @@ use std::mem::transmute; fn main() { unsafe { let s = "this is a test"; - transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; //~ ERROR constant evaluation error [E0080] + transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; //~ ERROR constant evaluation error //~^ NOTE tried to modify constant memory } } diff --git a/tests/compile-fail/static_memory_modification3.rs b/tests/compile-fail/static_memory_modification3.rs index 0891756f0ec6..37d8bfe02ceb 100644 --- a/tests/compile-fail/static_memory_modification3.rs +++ b/tests/compile-fail/static_memory_modification3.rs @@ -4,7 +4,7 @@ use std::mem::transmute; fn main() { unsafe { let bs = b"this is a test"; - transmute::<&[u8], &mut [u8]>(bs)[4] = 42; //~ ERROR constant evaluation error [E0080] + transmute::<&[u8], &mut [u8]>(bs)[4] = 42; //~ ERROR constant evaluation error //~^ NOTE tried to modify constant memory } } diff --git a/tests/compile-fail/transmute-pair-undef.rs b/tests/compile-fail/transmute-pair-undef.rs index 6b4fe2273a08..9509bb60e8b1 100644 --- a/tests/compile-fail/transmute-pair-undef.rs +++ b/tests/compile-fail/transmute-pair-undef.rs @@ -16,6 +16,6 @@ fn main() { assert_eq!(byte, 0); } let v = unsafe { *z.offset(first_undef) }; - if v == 0 {} //~ ERROR constant evaluation error [E0080] + if v == 0 {} //~ ERROR constant evaluation error //~^ NOTE attempted to read undefined bytes } diff --git a/tests/compile-fail/transmute_fat.rs b/tests/compile-fail/transmute_fat.rs index 81d783807c58..dad5f4df2da3 100644 --- a/tests/compile-fail/transmute_fat.rs +++ b/tests/compile-fail/transmute_fat.rs @@ -10,6 +10,6 @@ fn main() { let bad = unsafe { std::mem::transmute::<&[u8], u64>(&[1u8]) }; - let _ = bad + 1; //~ ERROR constant evaluation error [E0080] + let _ = bad + 1; //~ ERROR constant evaluation error //~^ NOTE a raw memory access tried to access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/transmute_fat2.rs b/tests/compile-fail/transmute_fat2.rs index 96a713305e6b..e9e21a84294d 100644 --- a/tests/compile-fail/transmute_fat2.rs +++ b/tests/compile-fail/transmute_fat2.rs @@ -7,6 +7,6 @@ fn main() { let bad = unsafe { std::mem::transmute::(42) }; - bad[0]; //~ ERROR constant evaluation error [E0080] + bad[0]; //~ ERROR constant evaluation error //~^ NOTE index out of bounds: the len is 0 but the index is 0 } diff --git a/tests/compile-fail/unaligned_ptr_cast.rs b/tests/compile-fail/unaligned_ptr_cast.rs index cb9523395391..f91def30d120 100644 --- a/tests/compile-fail/unaligned_ptr_cast.rs +++ b/tests/compile-fail/unaligned_ptr_cast.rs @@ -2,6 +2,6 @@ fn main() { let x = &2u16; let x = x as *const _ as *const u32; // This must fail because alignment is violated - let _x = unsafe { *x }; //~ ERROR constant evaluation error [E0080] + let _x = unsafe { *x }; //~ ERROR constant evaluation error //~^ NOTE tried to access memory with alignment 2, but alignment 4 is required } diff --git a/tests/compile-fail/unaligned_ptr_cast2.rs b/tests/compile-fail/unaligned_ptr_cast2.rs index dee2bbc9972f..f87dab76ba30 100644 --- a/tests/compile-fail/unaligned_ptr_cast2.rs +++ b/tests/compile-fail/unaligned_ptr_cast2.rs @@ -3,6 +3,6 @@ fn main() { let x = x as *const _ as *const *const u8; // This must fail because alignment is violated. Test specifically for loading pointers, which have special code // in miri's memory. - let _x = unsafe { *x }; //~ ERROR constant evaluation error [E0080] + let _x = unsafe { *x }; //~ ERROR constant evaluation error //~^ NOTE tried to access memory with alignment 2, but alignment } diff --git a/tests/compile-fail/unaligned_ptr_cast_zst.rs b/tests/compile-fail/unaligned_ptr_cast_zst.rs index eba17ab6c640..45016473c975 100644 --- a/tests/compile-fail/unaligned_ptr_cast_zst.rs +++ b/tests/compile-fail/unaligned_ptr_cast_zst.rs @@ -2,6 +2,6 @@ fn main() { let x = &2u16; let x = x as *const _ as *const [u32; 0]; // This must fail because alignment is violated. Test specifically for loading ZST. - let _x = unsafe { *x }; //~ ERROR constant evaluation error [E0080] + let _x = unsafe { *x }; //~ ERROR constant evaluation error //~^ NOTE tried to access memory with alignment 2, but alignment 4 is required } diff --git a/tests/compile-fail/wild_pointer_deref.rs b/tests/compile-fail/wild_pointer_deref.rs index 035d979c5b07..4096cfb93e72 100644 --- a/tests/compile-fail/wild_pointer_deref.rs +++ b/tests/compile-fail/wild_pointer_deref.rs @@ -1,6 +1,6 @@ fn main() { let p = 44 as *const i32; - let x = unsafe { *p }; //~ ERROR constant evaluation error [E0080] + let x = unsafe { *p }; //~ ERROR constant evaluation error //~^ NOTE a memory access tried to interpret some bytes as a pointer panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/zst.rs b/tests/compile-fail/zst.rs index d6518a48aa82..efb2dafd36fc 100644 --- a/tests/compile-fail/zst.rs +++ b/tests/compile-fail/zst.rs @@ -1,5 +1,5 @@ fn main() { let x = &() as *const () as *const i32; - let _ = unsafe { *x }; //~ ERROR constant evaluation error [E0080] + let _ = unsafe { *x }; //~ ERROR constant evaluation error //~^ NOTE tried to access memory with alignment 1, but alignment 4 is required } From 0b8809bf5f1616082da31c63b0119fd45869ddbe Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 15 Jul 2018 12:00:02 +0200 Subject: [PATCH 0132/5092] port some tests to check the new error format --- tests/compile-fail/ctlz_nonzero.rs | 3 +-- tests/compile-fail/cttz_nonzero.rs | 3 +-- tests/compile-fail/deref_fn_ptr.rs | 3 +-- tests/compile-fail/null_pointer_deref.rs | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/tests/compile-fail/ctlz_nonzero.rs b/tests/compile-fail/ctlz_nonzero.rs index 167100903f4d..4e2ccd0ac508 100644 --- a/tests/compile-fail/ctlz_nonzero.rs +++ b/tests/compile-fail/ctlz_nonzero.rs @@ -10,7 +10,6 @@ pub fn main() { unsafe { use rusti::*; - ctlz_nonzero(0u8); //~ ERROR constant evaluation error - //~^ NOTE ctlz_nonzero called on 0 + ctlz_nonzero(0u8); //~ ERROR constant evaluation error: ctlz_nonzero called on 0 } } diff --git a/tests/compile-fail/cttz_nonzero.rs b/tests/compile-fail/cttz_nonzero.rs index 7d9ac5a0212d..50b8df619982 100644 --- a/tests/compile-fail/cttz_nonzero.rs +++ b/tests/compile-fail/cttz_nonzero.rs @@ -10,7 +10,6 @@ pub fn main() { unsafe { use rusti::*; - cttz_nonzero(0u8); //~ ERROR constant evaluation error - //~^ NOTE cttz_nonzero called on 0 + cttz_nonzero(0u8); //~ ERROR constant evaluation error: cttz_nonzero called on 0 } } diff --git a/tests/compile-fail/deref_fn_ptr.rs b/tests/compile-fail/deref_fn_ptr.rs index fb3aea67e821..1b36c77bd32a 100644 --- a/tests/compile-fail/deref_fn_ptr.rs +++ b/tests/compile-fail/deref_fn_ptr.rs @@ -2,8 +2,7 @@ fn f() {} fn main() { let x: i32 = unsafe { - *std::mem::transmute::(f) //~ ERROR constant evaluation error - //~^ NOTE tried to dereference a function pointer + *std::mem::transmute::(f) //~ ERROR constant evaluation error: tried to dereference a function pointer }; panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/null_pointer_deref.rs b/tests/compile-fail/null_pointer_deref.rs index f69308296bc2..08ea63f58ff5 100644 --- a/tests/compile-fail/null_pointer_deref.rs +++ b/tests/compile-fail/null_pointer_deref.rs @@ -1,5 +1,4 @@ fn main() { - let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR constant evaluation error - //~^ NOTE invalid use of NULL pointer + let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR constant evaluation error: invalid use of NULL pointer panic!("this should never print: {}", x); } From 60d18dbf87cbb1baceccb69a87b109de93ff1ff0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 15 Jul 2018 21:03:52 +0200 Subject: [PATCH 0133/5092] handle all foreign items like we handle C ABI shims --- src/fn_call.rs | 167 ++++++++++++++++++++++++------------------------- 1 file changed, 83 insertions(+), 84 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index d2149ee5dbe7..8105330b3263 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -3,7 +3,6 @@ use rustc::ty::layout::{self, Align, LayoutOf, Size}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc_data_structures::indexed_vec::Idx; -use rustc_target::spec::abi::Abi; use syntax::attr; use syntax::codemap::Span; @@ -60,7 +59,7 @@ fn write_discriminant_value<'a, 'mir, 'tcx: 'a + 'mir>( } pub trait EvalContextExt<'tcx> { - fn call_c_abi( + fn call_foreign_item( &mut self, def_id: DefId, args: &[ValTy<'tcx>], @@ -105,9 +104,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let def_id = instance.def_id(); let item_path = self.tcx.absolute_item_path_str(def_id); - if item_path.starts_with("std::") { - //println!("{}", item_path); - } match &*item_path { "std::sys::unix::thread::guard::init" | "std::sys::unix::thread::guard::current" => { // Return None, as it doesn't make sense to return Some, because miri detects stack overflow itself. @@ -178,7 +174,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Ok(false) } - fn call_c_abi( + fn call_foreign_item( &mut self, def_id: DefId, args: &[ValTy<'tcx>], @@ -215,6 +211,73 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } } + "__rust_alloc" => { + let size = self.value_to_scalar(args[0])?.to_usize(self)?; + let align = self.value_to_scalar(args[1])?.to_usize(self)?; + if size == 0 { + return err!(HeapAllocZeroBytes); + } + if !align.is_power_of_two() { + return err!(HeapAllocNonPowerOfTwoAlignment(align)); + } + let ptr = self.memory.allocate(Size::from_bytes(size), + Align::from_bytes(align, align).unwrap(), + MemoryKind::Rust.into())?; + self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; + } + "__rust_alloc_zeroed" => { + let size = self.value_to_scalar(args[0])?.to_usize(self)?; + let align = self.value_to_scalar(args[1])?.to_usize(self)?; + if size == 0 { + return err!(HeapAllocZeroBytes); + } + if !align.is_power_of_two() { + return err!(HeapAllocNonPowerOfTwoAlignment(align)); + } + let ptr = self.memory.allocate(Size::from_bytes(size), + Align::from_bytes(align, align).unwrap(), + MemoryKind::Rust.into())?; + self.memory.write_repeat(ptr.into(), 0, Size::from_bytes(size))?; + self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; + } + "__rust_dealloc" => { + let ptr = self.into_ptr(args[0].value)?.to_ptr()?; + let old_size = self.value_to_scalar(args[1])?.to_usize(self)?; + let align = self.value_to_scalar(args[2])?.to_usize(self)?; + if old_size == 0 { + return err!(HeapAllocZeroBytes); + } + if !align.is_power_of_two() { + return err!(HeapAllocNonPowerOfTwoAlignment(align)); + } + self.memory.deallocate( + ptr, + Some((Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap())), + MemoryKind::Rust.into(), + )?; + } + "__rust_realloc" => { + let ptr = self.into_ptr(args[0].value)?.to_ptr()?; + let old_size = self.value_to_scalar(args[1])?.to_usize(self)?; + let align = self.value_to_scalar(args[2])?.to_usize(self)?; + let new_size = self.value_to_scalar(args[3])?.to_usize(self)?; + if old_size == 0 || new_size == 0 { + return err!(HeapAllocZeroBytes); + } + if !align.is_power_of_two() { + return err!(HeapAllocNonPowerOfTwoAlignment(align)); + } + let new_ptr = self.memory.reallocate( + ptr, + Size::from_bytes(old_size), + Align::from_bytes(align, align).unwrap(), + Size::from_bytes(new_size), + Align::from_bytes(align, align).unwrap(), + MemoryKind::Rust.into(), + )?; + self.write_scalar(dest, Scalar::Ptr(new_ptr), dest_ty)?; + } + "syscall" => { // TODO: read `syscall` ids like `sysconf` ids and // figure out some way to actually process some of them @@ -559,9 +622,18 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.write_ptr(dest, addr, dest_ty)?; } + // Windows API subs + "AddVectoredExceptionHandler" | + "SetThreadStackGuarantee" => { + let usize = self.tcx.types.usize; + // any non zero value works for the stdlib. This is just used for stackoverflows anyway + self.write_scalar(dest, Scalar::from_u128(1), usize)?; + }, + + // We can't execute anything else _ => { return err!(Unimplemented( - format!("can't call C ABI function: {}", link_name), + format!("can't call foreign function: {}", link_name), )); } } @@ -629,11 +701,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' || EvalErrorKind::NoMirFor(path.clone()), )?; - if sig.abi == Abi::C { - // An external C function + if self.tcx.is_foreign_item(instance.def_id()) { + // An external function // TODO: That functions actually has a similar preamble to what follows here. May make sense to // unify these two mechanisms for "hooking into missing functions". - self.call_c_abi( + self.call_foreign_item( instance.def_id(), args, dest, @@ -644,74 +716,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } match &path[..] { - // Allocators are magic. They have no MIR, even when the rest of libstd does. - "alloc::alloc::::__rust_alloc" => { - let size = self.value_to_scalar(args[0])?.to_usize(self)?; - let align = self.value_to_scalar(args[1])?.to_usize(self)?; - if size == 0 { - return err!(HeapAllocZeroBytes); - } - if !align.is_power_of_two() { - return err!(HeapAllocNonPowerOfTwoAlignment(align)); - } - let ptr = self.memory.allocate(Size::from_bytes(size), - Align::from_bytes(align, align).unwrap(), - MemoryKind::Rust.into())?; - self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; - } - "alloc::alloc::::__rust_alloc_zeroed" => { - let size = self.value_to_scalar(args[0])?.to_usize(self)?; - let align = self.value_to_scalar(args[1])?.to_usize(self)?; - if size == 0 { - return err!(HeapAllocZeroBytes); - } - if !align.is_power_of_two() { - return err!(HeapAllocNonPowerOfTwoAlignment(align)); - } - let ptr = self.memory.allocate(Size::from_bytes(size), - Align::from_bytes(align, align).unwrap(), - MemoryKind::Rust.into())?; - self.memory.write_repeat(ptr.into(), 0, Size::from_bytes(size))?; - self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; - } - "alloc::alloc::::__rust_dealloc" => { - let ptr = self.into_ptr(args[0].value)?.to_ptr()?; - let old_size = self.value_to_scalar(args[1])?.to_usize(self)?; - let align = self.value_to_scalar(args[2])?.to_usize(self)?; - if old_size == 0 { - return err!(HeapAllocZeroBytes); - } - if !align.is_power_of_two() { - return err!(HeapAllocNonPowerOfTwoAlignment(align)); - } - self.memory.deallocate( - ptr, - Some((Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap())), - MemoryKind::Rust.into(), - )?; - } - "alloc::alloc::::__rust_realloc" => { - let ptr = self.into_ptr(args[0].value)?.to_ptr()?; - let old_size = self.value_to_scalar(args[1])?.to_usize(self)?; - let align = self.value_to_scalar(args[2])?.to_usize(self)?; - let new_size = self.value_to_scalar(args[3])?.to_usize(self)?; - if old_size == 0 || new_size == 0 { - return err!(HeapAllocZeroBytes); - } - if !align.is_power_of_two() { - return err!(HeapAllocNonPowerOfTwoAlignment(align)); - } - let new_ptr = self.memory.reallocate( - ptr, - Size::from_bytes(old_size), - Align::from_bytes(align, align).unwrap(), - Size::from_bytes(new_size), - Align::from_bytes(align, align).unwrap(), - MemoryKind::Rust.into(), - )?; - self.write_scalar(dest, Scalar::Ptr(new_ptr), dest_ty)?; - } - // A Rust function is missing, which means we are running with MIR missing for libstd (or other dependencies). // Still, we can make many things mostly work by "emulating" or ignoring some functions. "std::io::_print" => { @@ -733,12 +737,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let bool = self.tcx.types.bool; self.write_scalar(dest, Scalar::from_bool(false), bool)?; } - "std::sys::imp::c::::AddVectoredExceptionHandler" | - "std::sys::imp::c::::SetThreadStackGuarantee" => { - let usize = self.tcx.types.usize; - // any non zero value works for the stdlib. This is just used for stackoverflows anyway - self.write_scalar(dest, Scalar::from_u128(1), usize)?; - }, + _ => return err!(NoMirFor(path)), } From 5be8bd987de6cf72d858b21bdc62fe4125b2890d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 15 Jul 2018 21:25:03 +0200 Subject: [PATCH 0134/5092] Test some new capabilities we gained from a rustc update --- src/operator.rs | 4 ++++ tests/run-pass/pointers.rs | 1 + 2 files changed, 5 insertions(+) diff --git a/src/operator.rs b/src/operator.rs index 1440f1dab4e0..207324cfcb00 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -34,6 +34,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: right: Scalar, right_ty: ty::Ty<'tcx>, ) -> EvalResult<'tcx, Option<(Scalar, bool)>> { + trace!("ptr_op: {:?} {:?} {:?}", left, bin_op, right); + use rustc::mir::BinOp::*; use rustc::ty::layout::Integer::*; let usize = Primitive::Int(match self.memory.pointer_size().bytes() { @@ -81,7 +83,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: (Scalar::Bits { .. }, Scalar::Bits { .. }) => { left.to_bits(left_layout.size)? == right.to_bits(right_layout.size)? }, + // FIXME: Test if both allocations are still live *or* if they are in the same allocation? (same for Ne below) (Scalar::Ptr(left), Scalar::Ptr(right)) => left == right, + // FIXME: We should probably error out when comparing anything but NULL with a pointer (same for Ne below) _ => false, }; Ok(Some((Scalar::from_bool(result), false))) diff --git a/tests/run-pass/pointers.rs b/tests/run-pass/pointers.rs index f3ae3ab913a3..936ec73bcb8c 100644 --- a/tests/run-pass/pointers.rs +++ b/tests/run-pass/pointers.rs @@ -57,4 +57,5 @@ fn main() { assert_eq!(match_ref_mut(), 42); // FIXME: improve this test... how? assert!(dangling_pointer() != std::ptr::null()); + assert!(match dangling_pointer() as usize { 0 => false, _ => true }); } From a39f25c8132950212d46c5989f906e98c5604a59 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 15 Jul 2018 23:17:06 +0200 Subject: [PATCH 0135/5092] update rustc build instructions to mention keep-stage Also move them further down because it is probably less relevant than some of the other stuff. --- README.md | 54 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 4891575c05e5..d515aad8bea5 100644 --- a/README.md +++ b/README.md @@ -40,25 +40,6 @@ how to fix it, you could send a PR. :smile: cargo run --bin miri tests/run-pass-fullmir/vecs.rs # Or whatever test you like. ``` -## Debugging - -Since the heart of miri (the main interpreter engine) lives in rustc, tracing -the interpreter requires a version of rustc compiled with tracing. To this -end, you will have to compile your own rustc: -``` -git clone https://github.com/rust-lang/rust/ rustc -cd rustc -cp config.toml.example config.toml -# Now edit `config.toml` and set `debug-assertions = true` -./x.py build src/rustc -rustup toolchain link custom build/x86_64-unknown-linux-gnu/stage2 -``` -The `build` step can take 30 to 60 minutes. - -Now, in the miri directory, you can `rustup override set custom` and re-build -everything. Finally, if you now set `RUST_LOG=rustc_mir::interpret=trace` as -environment variable, you will get detailed step-by-step tracing information. - ## Running miri on your own project('s test suite) Install miri as a cargo subcommand with `cargo install --debug`. @@ -68,8 +49,8 @@ through miri. ## Running miri with full libstd -Per default libstd does not contain the MIR of non-polymorphic functions. When -miri hits a call to such a function, execution terminates. To fix this, it is +Per default libstd does not contain the MIR of non-polymorphic functions. When +miri hits a call to such a function, execution terminates. To fix this, it is possible to compile libstd with full MIR: ```sh @@ -91,6 +72,37 @@ your toolchain changes (e.g., when you update the nightly). You can also set `-Zmiri-start-fn` to make miri start evaluation with the `start_fn` lang item, instead of starting at the `main` function. +## Development and Debugging + +Since the heart of miri (the main interpreter engine) lives in rustc, working on +miri will often require using a locally built rustc. This includes getting a +trace of the execution, as distributed rustc has `trace!` disabled. + +The first-time setup for a local rustc looks as follows: +``` +git clone https://github.com/rust-lang/rust/ rustc +cd rustc +cp config.toml.example config.toml +# Now edit `config.toml` and set `debug-assertions = true` +./x.py build src/rustc +# You may have to change the architecture in the next command +rustup toolchain link custom build/x86_64-unknown-linux-gnu/stage2 +# Now cd to your miri directory +rustup override set custom +``` +The `build` step can take 30 minutes and more. + +Now you can `cargo build` miri, and you can `cargo test --tests`. (`--tests` +is needed to skip doctests because we have not built rustdoc for your custom +toolchain.) You can also set `RUST_LOG=rustc_mir::interpret=trace` as +environment variable to get a step-by-step trace. + +If you changed something in rustc and want to re-build, run +``` +./x.py build src/rustc --keep-stage 0 +``` +This avoids rebuilding the entire stage 0, which can save a lot of time. + ## Contributing and getting help Check out the issues on this GitHub repository for some ideas. There's lots that From d11c668a3900fcbad336eb470da8748a04000253 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 16 Jul 2018 08:39:06 +0200 Subject: [PATCH 0136/5092] no longer run rustc on the tests; instead make sure we actually deny all warnings Also fix the fallout from that --- .../reallocate-bad-size.rs | 2 +- .../reallocate-change-alloc.rs | 2 +- tests/compiletest.rs | 28 ++----------------- tests/run-pass/box_box_trait.rs | 2 ++ 4 files changed, 6 insertions(+), 28 deletions(-) diff --git a/tests/compile-fail-fullmir/reallocate-bad-size.rs b/tests/compile-fail-fullmir/reallocate-bad-size.rs index f85b651e8573..489b7bebcdc8 100644 --- a/tests/compile-fail-fullmir/reallocate-bad-size.rs +++ b/tests/compile-fail-fullmir/reallocate-bad-size.rs @@ -10,6 +10,6 @@ use std::alloc::*; fn main() { unsafe { let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); - let _y = Global.realloc(x, Layout::from_size_align_unchecked(2, 1), 1).unwrap(); + Global.realloc(x, Layout::from_size_align_unchecked(2, 1), 1).unwrap(); } } diff --git a/tests/compile-fail-fullmir/reallocate-change-alloc.rs b/tests/compile-fail-fullmir/reallocate-change-alloc.rs index a44ccf4c49cd..c73f86bc1721 100644 --- a/tests/compile-fail-fullmir/reallocate-change-alloc.rs +++ b/tests/compile-fail-fullmir/reallocate-change-alloc.rs @@ -8,7 +8,7 @@ use std::alloc::*; fn main() { unsafe { let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); - let _y = Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1).unwrap(); + Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1).unwrap(); let _z = *(x.as_ptr() as *mut u8); //~ ERROR constant evaluation error //~^ NOTE dangling pointer was dereferenced } diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 896d1cae5969..38d806967281 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -62,6 +62,7 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullm config.compile_lib_path = rustc_lib_path(); } flags.push(format!("--sysroot {}", sysroot.display())); + flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs config.src_base = PathBuf::from(path.to_string()); flags.push("-Zmir-emit-validate=1".to_owned()); config.target_rustcflags = Some(flags.join(" ")); @@ -70,23 +71,6 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullm compiletest::run_tests(&config); } -fn rustc_pass(sysroot: &Path, path: &str) { - eprintln!("{}", format!("## Running run-pass tests in {} against rustc", path).green().bold()); - let mut config = compiletest::Config::default().tempdir(); - config.mode = "run-pass".parse().expect("Invalid mode"); - config.src_base = PathBuf::from(path); - if let Some(rustc_path) = rustc_test_suite() { - config.rustc_path = rustc_path; - config.run_lib_path = rustc_lib_path(); - config.compile_lib_path = rustc_lib_path(); - config.target_rustcflags = Some(format!("-Dwarnings --sysroot {}", sysroot.display())); - } else { - config.target_rustcflags = Some("-Dwarnings".to_owned()); - } - config.host_rustcflags = Some("-Dwarnings".to_string()); - compiletest::run_tests(&config); -} - fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: bool, opt: bool) { if need_fullmir && !have_fullmir() { eprintln!("{}", format!( @@ -116,6 +100,7 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: } let mut flags = Vec::new(); flags.push(format!("--sysroot {}", sysroot.display())); + flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs if have_fullmir() { flags.push("-Zmiri-start-fn".to_owned()); } @@ -190,12 +175,6 @@ fn run_pass_miri(opt: bool) { miri_pass(&sysroot, "tests/run-pass-fullmir", &host, &host, true, opt); } -fn run_pass_rustc() { - let sysroot = get_sysroot(); - rustc_pass(&sysroot, "tests/run-pass"); - rustc_pass(&sysroot, "tests/run-pass-fullmir"); -} - fn compile_fail_miri() { let sysroot = get_sysroot(); let host = get_host(); @@ -211,10 +190,7 @@ fn test() { // introduces. We still get parallelism within our tests because `compiletest` // uses `libtest` which runs jobs in parallel. - run_pass_rustc(); - run_pass_miri(false); - // FIXME: Disabled for now, as the optimizer is pretty broken and crashes... // See https://github.com/rust-lang/rust/issues/50411 //run_pass_miri(true); diff --git a/tests/run-pass/box_box_trait.rs b/tests/run-pass/box_box_trait.rs index 57eef52d573b..7fe568522d53 100644 --- a/tests/run-pass/box_box_trait.rs +++ b/tests/run-pass/box_box_trait.rs @@ -13,7 +13,9 @@ impl Drop for DroppableStruct { trait MyTrait { fn dummy(&self) { } } impl MyTrait for Box {} +#[allow(dead_code)] struct Whatever { w: Box } + impl Whatever { fn new(w: Box) -> Whatever { Whatever { w: w } From fb3ac376ad61e2b57a2f110a1f71d7318bf4238f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 13 Jul 2018 16:29:00 +0200 Subject: [PATCH 0137/5092] run fullMIR tests in appveyor --- appveyor.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index 46580f274bf6..2e2920591f76 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -35,6 +35,8 @@ test_script: - set RUST_BACKTRACE=1 - cargo build --release - cargo test --release + - set MIRI_SYSROOT=C:\Users\appveyor\.xargo\HOST + - cargo test --release notifications: - provider: Email From 9396310317481963aeb0aa44d8f54911e94f8a1d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 13 Jul 2018 16:30:27 +0200 Subject: [PATCH 0138/5092] appveyor: put 64bit config first, it seems to usually be faster --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 2e2920591f76..6aee7e75a956 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,10 +2,10 @@ environment: global: PROJECT_NAME: miri matrix: - - TARGET: i686-pc-windows-msvc - MSYS2_BITS: 32 - TARGET: x86_64-pc-windows-msvc MSYS2_BITS: 64 + - TARGET: i686-pc-windows-msvc + MSYS2_BITS: 32 # branches to build branches: From 216b8f74075a6f555c3cc1bf8a2dab16af35ca0a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 15 Jul 2018 23:47:28 +0200 Subject: [PATCH 0139/5092] shim some Windows functions --- src/fn_call.rs | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 8105330b3263..de40ef943a55 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -623,11 +623,24 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } // Windows API subs - "AddVectoredExceptionHandler" | - "SetThreadStackGuarantee" => { - let usize = self.tcx.types.usize; + "AddVectoredExceptionHandler" => { // any non zero value works for the stdlib. This is just used for stackoverflows anyway - self.write_scalar(dest, Scalar::from_u128(1), usize)?; + self.write_scalar(dest, Scalar::from_u128(1), dest_ty)?; + }, + "GetModuleHandleW" | + "GetProcAddress" | + "InitializeCriticalSection" | + "EnterCriticalSection" | + "TryEnterCriticalSection" | + "LeaveCriticalSection" | + "DeleteCriticalSection" | + "SetLastError" => { + // pretend these do not exist/nothing happened, by returning zero + self.write_scalar(dest, Scalar::from_u128(0), dest_ty)?; + }, + "GetLastError" => { + // this is c::ERROR_CALL_NOT_IMPLEMENTED + self.write_scalar(dest, Scalar::from_u128(120), dest_ty)?; }, // We can't execute anything else From e1a3b9606e712dac18bae566498d2fa93ca0c276 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 16 Jul 2018 11:42:46 +0200 Subject: [PATCH 0140/5092] TLS on Windows --- src/fn_call.rs | 30 +++++++++++++++++++++++++++++- src/lib.rs | 20 ++++++++++++++++++-- src/tls.rs | 1 + 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index de40ef943a55..31b3b4b18d17 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -607,7 +607,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "_tlv_atexit" => { - return err!(Unimplemented("can't interpret with full mir for osx target".to_owned())); + return err!(Unimplemented("Thread-local store is not fully supported on macOS".to_owned())); }, // Stub out all the other pthread calls to just return 0 @@ -643,6 +643,34 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.write_scalar(dest, Scalar::from_u128(120), dest_ty)?; }, + // Windows TLS + "TlsAlloc" => { + // This just creates a key; Windows does not natively support TLS dtors. + + // Figure out how large a TLS key actually is. This is c::DWORD. + let key_size = self.layout_of(dest_ty)?.size; + + // Create key and return it + let key = self.memory.create_tls_key(None) as u128; + if key_size.bits() < 128 && key >= (1u128 << key_size.bits() as u128) { + return err!(OutOfTls); + } + self.write_scalar(dest, Scalar::from_u128(key), dest_ty)?; + } + "TlsGetValue" => { + let key = self.value_to_scalar(args[0])?.to_bytes()?; + let ptr = self.memory.load_tls(key)?; + self.write_ptr(dest, ptr, dest_ty)?; + } + "TlsSetValue" => { + let key = self.value_to_scalar(args[0])?.to_bytes()?; + let new_ptr = self.into_ptr(args[1].value)?; + self.memory.store_tls(key, new_ptr)?; + + // Return success (1) + self.write_scalar(dest, Scalar::from_u128(1), dest_ty)?; + } + // We can't execute anything else _ => { return err!(Unimplemented( diff --git a/src/lib.rs b/src/lib.rs index 520d696405a1..5a2d7e77d65f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -141,7 +141,12 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( main_id: DefId, start_wrapper: Option, ) -> EvalResult<'tcx, (EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>, Option)> { - let mut ecx = EvalContext::new(tcx.at(syntax::codemap::DUMMY_SP), ty::ParamEnv::reveal_all(), Default::default(), Default::default()); + let mut ecx = EvalContext::new( + tcx.at(syntax::codemap::DUMMY_SP), + ty::ParamEnv::reveal_all(), + Default::default(), + MemoryData::new() + ); let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; @@ -338,7 +343,7 @@ pub struct TlsEntry<'tcx> { dtor: Option>, } -#[derive(Clone, Default, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq)] pub struct MemoryData<'tcx> { /// The Key to use for the next thread-local allocation. next_thread_local: TlsKey, @@ -355,6 +360,17 @@ pub struct MemoryData<'tcx> { statics: HashMap, AllocId>, } +impl<'tcx> MemoryData<'tcx> { + fn new() -> Self { + MemoryData { + next_thread_local: 1, // start with 1 as we must not use 0 on Windows + thread_local: BTreeMap::new(), + locks: HashMap::new(), + statics: HashMap::new(), + } + } +} + impl<'tcx> Hash for MemoryData<'tcx> { fn hash(&self, state: &mut H) { let MemoryData { diff --git a/src/tls.rs b/src/tls.rs index 45805f3aa8cc..ffcf86291590 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -139,6 +139,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' None => self.memory.fetch_tls_dtor(None)?, }; } + // FIXME: On a windows target, call `unsafe extern "system" fn on_tls_callback`. Ok(()) } } From f9a8d2618e0f6e7f8070a6b367bcdf101df75481 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 16 Jul 2018 22:26:32 +0200 Subject: [PATCH 0141/5092] fix for latest rust nightly --- src/bin/miri.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 51c53b4af275..29e2e50d5d68 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -112,7 +112,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>, use_start_fn: bo ); impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { - if let hir::Item_::ItemFn(.., body_id) = i.node { + if let hir::ItemKind::Fn(.., body_id) = i.node { if i.attrs.iter().any(|attr| { attr.name() == "test" }) From 72756b7071953413aee87c4f9f17ebcf75a16b7e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 17 Jul 2018 08:56:06 +0200 Subject: [PATCH 0142/5092] also fix rustc_tests --- rustc_tests/Cargo.lock | 21 +-------------------- rustc_tests/src/main.rs | 2 +- 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/rustc_tests/Cargo.lock b/rustc_tests/Cargo.lock index 9cf4fe0d1342..0154ecc2ccbd 100644 --- a/rustc_tests/Cargo.lock +++ b/rustc_tests/Cargo.lock @@ -93,7 +93,7 @@ dependencies = [ "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -114,18 +114,6 @@ dependencies = [ "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "regex" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "regex" version = "1.0.0" @@ -138,11 +126,6 @@ dependencies = [ "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "regex-syntax" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "regex-syntax" version = "0.6.0" @@ -251,9 +234,7 @@ dependencies = [ "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b" "checksum regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75ecf88252dce580404a22444fc7d626c01815debba56a7f4f536772a5ff19d3" -"checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" "checksum regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1ac0f60d675cc6cf13a20ec076568254472551051ad5dd050364d70671bf6b" "checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" diff --git a/rustc_tests/src/main.rs b/rustc_tests/src/main.rs index 64cd380970e4..1891e3dba103 100644 --- a/rustc_tests/src/main.rs +++ b/rustc_tests/src/main.rs @@ -90,7 +90,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { struct Visitor<'a, 'tcx: 'a>(TyCtxt<'a, 'tcx, 'tcx>, &'a CompileState<'a, 'tcx>); impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { - if let hir::Item_::ItemFn(.., body_id) = i.node { + if let hir::ItemKind::Fn(.., body_id) = i.node { if i.attrs.iter().any(|attr| attr.name() == "test") { let did = self.0.hir.body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); From 2a29ed01427b50eeb10ed2ea02128d7bb55cab8f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Jul 2018 09:48:49 +0200 Subject: [PATCH 0143/5092] use default-run --- Cargo.toml | 3 +++ README.md | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c46ba7c41429..417d76c54cb3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,5 @@ +cargo-features = ["default-run"] + [package] authors = ["Scott Olson "] description = "An experimental interpreter for Rust MIR." @@ -6,6 +8,7 @@ name = "miri" repository = "https://github.com/solson/miri" version = "0.1.0" build = "build.rs" +default-run = "miri" [[bin]] doc = false diff --git a/README.md b/README.md index d515aad8bea5..b7dfab27ef1c 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ how to fix it, you could send a PR. :smile: ## Running tests ```sh -cargo run --bin miri tests/run-pass-fullmir/vecs.rs # Or whatever test you like. +cargo run tests/run-pass-fullmir/vecs.rs # Or whatever test you like. ``` ## Running miri on your own project('s test suite) @@ -63,7 +63,7 @@ RUSTFLAGS='-Zalways-encode-mir' xargo build Now you can run miri against the libstd compiled by xargo: ```sh -MIRI_SYSROOT=~/.xargo/HOST cargo run --bin miri tests/run-pass-fullmir/hashmap.rs +MIRI_SYSROOT=~/.xargo/HOST cargo run tests/run-pass-fullmir/hashmap.rs ``` Notice that you will have to re-run the last step of the preparations above when From 444d97fc7d94c9a8bb2f9d87c7393c6e3a6c2f12 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Jul 2018 09:51:23 +0200 Subject: [PATCH 0144/5092] fix vecs.rs path --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b7dfab27ef1c..8c476270db1a 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ how to fix it, you could send a PR. :smile: ## Running tests ```sh -cargo run tests/run-pass-fullmir/vecs.rs # Or whatever test you like. +cargo run tests/run-pass/vecs.rs # Or whatever test you like. ``` ## Running miri on your own project('s test suite) From b055ff03f13a668c44fda89768205cf69bf67f56 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 25 Jul 2018 17:28:16 +0200 Subject: [PATCH 0145/5092] Produce the exit codes that compiletest expects --- src/bin/miri.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 29e2e50d5d68..e380317138aa 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -228,8 +228,12 @@ fn main() { } }); - rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls { - default: Box::new(RustcDefaultCalls), - start_fn, - }), None, None); + + let result = rustc_driver::run(move || { + rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls { + default: Box::new(RustcDefaultCalls), + start_fn, + }), None, None) + }); + std::process::exit(result as i32); } From 53114e3b36942138d4f9dd575f61e5493bc578f6 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 5 Jun 2018 10:21:28 +0200 Subject: [PATCH 0146/5092] Update to rustc sanity check branch --- src/intrinsic.rs | 3 ++- src/validation.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index cee2f1ab7682..6c8fd0af4036 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -245,10 +245,11 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "discriminant_value" => { let ty = substs.type_at(0); + let layout = self.layout_of(ty)?; let adt_ptr = self.into_ptr(args[0].value)?; let adt_align = self.layout_of(args[0].ty)?.align; let place = Place::from_scalar_ptr(adt_ptr, adt_align); - let discr_val = self.read_discriminant_value(place, ty)?; + let discr_val = self.read_discriminant_value(place, layout)?; self.write_scalar(dest, Scalar::from_u128(discr_val), dest_layout.ty)?; } diff --git a/src/validation.rs b/src/validation.rs index 758fd5d27470..caa5b702e61a 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -765,7 +765,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match adt.adt_kind() { AdtKind::Enum => { - let variant_idx = self.read_discriminant_as_variant_index(query.place.1, query.ty)?; + let layout = self.layout_of(query.ty)?; + let variant_idx = self.read_discriminant_as_variant_index(query.place.1, layout)?; let variant = &adt.variants[variant_idx]; if !variant.fields.is_empty() { From e849fa47fb121caa30b408e84cf28a7d078f542b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 24 Jul 2018 22:20:50 +0200 Subject: [PATCH 0147/5092] make miri compile again --- src/intrinsic.rs | 2 +- src/validation.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 6c8fd0af4036..dc2224c4ceef 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -344,7 +344,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: ty::layout::Abi::Scalar(_) => Value::Scalar(Scalar::null()), _ => { // FIXME(oli-obk): pass TyLayout to alloc_ptr instead of Ty - let ptr = this.alloc_ptr(dest_layout.ty)?; + let ptr = this.alloc_ptr(dest_layout)?; let ptr = Scalar::Ptr(ptr); this.memory.write_repeat(ptr, 0, size)?; Value::ByRef(ptr, dest_layout.align) diff --git a/src/validation.rs b/src/validation.rs index caa5b702e61a..676718ad7fe7 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -140,6 +140,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' mir::Place::Static(ref s) => AbsPlace::Static(s.def_id), mir::Place::Projection(ref p) => AbsPlace::Projection(Box::new(self.abstract_place_projection(&*p)?)), + _ => unimplemented!("validation is not currently maintained"), }) } From b7c57fee610f8128b454e22898371167287b0ddc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 24 Jul 2018 22:29:08 +0200 Subject: [PATCH 0148/5092] Ignore tests the bool thing will be fixed by the validation I have planned, and we already ignored another test around modifing constants. --- tests/compile-fail/invalid_bool.rs | 2 ++ tests/compile-fail/modifying_constants.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index 1aa5d9bf77bc..6ac7f3e60c0d 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -1,3 +1,5 @@ +//ignore-test FIXME (do some basic validation of invariants for all values in flight) + fn main() { let b = unsafe { std::mem::transmute::(2) }; if b { unreachable!() } else { unreachable!() } //~ ERROR constant evaluation error diff --git a/tests/compile-fail/modifying_constants.rs b/tests/compile-fail/modifying_constants.rs index c10657ae75a7..6ffba89fa5ef 100644 --- a/tests/compile-fail/modifying_constants.rs +++ b/tests/compile-fail/modifying_constants.rs @@ -1,3 +1,5 @@ +// ignore-test FIXME: we are not making these statics read-only any more? + fn main() { let x = &1; // the `&1` is promoted to a constant, but it used to be that only the pointer is marked static, not the pointee let y = unsafe { &mut *(x as *const i32 as *mut i32) }; From 305d8aeafe4ab53d7809ec6a1b9227166bd4fa63 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 25 Jul 2018 15:48:20 +0200 Subject: [PATCH 0149/5092] Disable blood letting edge features --- Cargo.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 417d76c54cb3..c46ba7c41429 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,3 @@ -cargo-features = ["default-run"] - [package] authors = ["Scott Olson "] description = "An experimental interpreter for Rust MIR." @@ -8,7 +6,6 @@ name = "miri" repository = "https://github.com/solson/miri" version = "0.1.0" build = "build.rs" -default-run = "miri" [[bin]] doc = false From e6f1e15676c26fdc7c4713647fe007b26f361a8e Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 26 Jul 2018 14:37:43 +0200 Subject: [PATCH 0150/5092] Bump min dependency version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c46ba7c41429..07ebca6491dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,5 +30,5 @@ log = "0.4" cargo_miri = ["cargo_metadata"] [dev-dependencies] -compiletest_rs = { version = "0.3.4", features = ["tmp"] } +compiletest_rs = { version = "0.3.12", features = ["tmp"] } colored = "1.6" From 851f2ab98e9ff67bdfb2bb20c9a639b35bc71799 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Jul 2018 16:43:45 +0200 Subject: [PATCH 0151/5092] test `cargo miri` output --- .travis.yml | 8 ++++++-- cargo-miri-test/.gitignore | 1 + cargo-miri-test/src/main.rs | 2 ++ cargo-miri-test/stderr.ref | 1 + cargo-miri-test/stdout.ref | 1 + src/fn_call.rs | 2 +- 6 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 cargo-miri-test/.gitignore create mode 100644 cargo-miri-test/stderr.ref create mode 100644 cargo-miri-test/stdout.ref diff --git a/.travis.yml b/.travis.yml index 9aa632da05e0..b130c6dc5b2b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,9 +30,13 @@ script: RUST_BACKTRACE=1 cargo test --release --all-features --all && cargo install --all-features --force - | - # Test cargo miri + # Test `cargo miri` cd cargo-miri-test && - cargo miri && + MIRI_SYSROOT=~/.xargo/HOST cargo miri -q -- -Zmiri-start-fn >stdout.real 2>stderr.real && + # Test `cargo miri` output. + diff stdout.ref stdout.real && + diff stderr.ref stderr.real && + # Test `cargo miri test` #cargo miri test && cd .. - | diff --git a/cargo-miri-test/.gitignore b/cargo-miri-test/.gitignore new file mode 100644 index 000000000000..56f307a7fb13 --- /dev/null +++ b/cargo-miri-test/.gitignore @@ -0,0 +1 @@ +*.real diff --git a/cargo-miri-test/src/main.rs b/cargo-miri-test/src/main.rs index 07b0e4cee4e5..6ad516710e1b 100644 --- a/cargo-miri-test/src/main.rs +++ b/cargo-miri-test/src/main.rs @@ -6,4 +6,6 @@ fn main() { let buf = &[1,2,3,4]; let n = ::read_u32(buf); assert_eq!(n, 0x01020304); + println!("{:#x}", n); + eprintln!("standard error"); } diff --git a/cargo-miri-test/stderr.ref b/cargo-miri-test/stderr.ref new file mode 100644 index 000000000000..aa7d1a2bdec7 --- /dev/null +++ b/cargo-miri-test/stderr.ref @@ -0,0 +1 @@ +standard error diff --git a/cargo-miri-test/stdout.ref b/cargo-miri-test/stdout.ref new file mode 100644 index 000000000000..53fefc734c85 --- /dev/null +++ b/cargo-miri-test/stdout.ref @@ -0,0 +1 @@ +0x1020304 diff --git a/src/fn_call.rs b/src/fn_call.rs index 31b3b4b18d17..a51ff73008ec 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -612,7 +612,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // Stub out all the other pthread calls to just return 0 link_name if link_name.starts_with("pthread_") => { - info!("ignoring C ABI call: {}", link_name); + debug!("ignoring C ABI call: {}", link_name); self.write_null(dest, dest_ty)?; } From ee9879918541e55f246d1f969022303c33e7feb4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Jul 2018 16:49:10 +0200 Subject: [PATCH 0152/5092] we no longer need to mess with the environment in our test suite --- tests/compiletest.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 38d806967281..82a2144a337d 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -8,7 +8,6 @@ use colored::*; use std::slice::SliceConcatExt; use std::path::{PathBuf, Path}; use std::io::Write; -use std::env; macro_rules! eprintln { ($($arg:tt)*) => { @@ -111,9 +110,6 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: // For now, only validate without optimizations. Inlining breaks validation. flags.push("-Zmir-emit-validate=1".to_owned()); } - // Control miri logging. This is okay despite concurrent test execution as all tests - // will set this env var to the same value. - env::set_var("MIRI_LOG", "warn"); config.target_rustcflags = Some(flags.join(" ")); compiletest::run_tests(&config); } From 5bd02b7c075802df68e215125e0b0cf7cce1aaa4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Jul 2018 17:08:29 +0200 Subject: [PATCH 0153/5092] also show the output (though we lost the interleaving) --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index b130c6dc5b2b..44a124efda3a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,6 +33,7 @@ script: # Test `cargo miri` cd cargo-miri-test && MIRI_SYSROOT=~/.xargo/HOST cargo miri -q -- -Zmiri-start-fn >stdout.real 2>stderr.real && + cat stdout.real stderr.real && # Test `cargo miri` output. diff stdout.ref stdout.real && diff stderr.ref stderr.real && From f6d4814fb34e5ed3e35f0bd0e070d244fd48f485 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Jul 2018 17:30:52 +0200 Subject: [PATCH 0154/5092] detect another printing function for nicer error --- src/fn_call.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index a51ff73008ec..9dfff9f55398 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -759,7 +759,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match &path[..] { // A Rust function is missing, which means we are running with MIR missing for libstd (or other dependencies). // Still, we can make many things mostly work by "emulating" or ignoring some functions. - "std::io::_print" => { + "std::io::_print" | + "std::io::_eprint" => { warn!( "Ignoring output. To run programs that print, make sure you have a libstd with full MIR." ); From ae830f61153e079e0ed030351f22cd0fa14abf1a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Jul 2018 17:41:45 +0200 Subject: [PATCH 0155/5092] dont test cargo miri output on mac. no idea what that system is doing. --- .travis.yml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 44a124efda3a..865da6f66499 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,11 +32,16 @@ script: - | # Test `cargo miri` cd cargo-miri-test && - MIRI_SYSROOT=~/.xargo/HOST cargo miri -q -- -Zmiri-start-fn >stdout.real 2>stderr.real && - cat stdout.real stderr.real && - # Test `cargo miri` output. - diff stdout.ref stdout.real && - diff stderr.ref stderr.real && + if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then + MIRI_SYSROOT=~/.xargo/HOST cargo miri -q -- -Zmiri-start-fn + else + MIRI_SYSROOT=~/.xargo/HOST cargo miri -q -- -Zmiri-start-fn >stdout.real 2>stderr.real && + cat stdout.real stderr.real && + # Test `cargo miri` output. Not on mac because output redirecting doesn't + # work. There is no error. It just stops CI. + diff stdout.ref stdout.real && + diff stderr.ref stderr.real + fi && # Test `cargo miri test` #cargo miri test && cd .. From c490151b16a07ccd261af44b4ddf5832ceda8c5a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Jul 2018 17:58:37 +0200 Subject: [PATCH 0156/5092] memrchr currently does not work --- cargo-miri-test/src/main.rs | 2 +- cargo-miri-test/stdout.ref | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/cargo-miri-test/src/main.rs b/cargo-miri-test/src/main.rs index 6ad516710e1b..3fb265f6a7ba 100644 --- a/cargo-miri-test/src/main.rs +++ b/cargo-miri-test/src/main.rs @@ -6,6 +6,6 @@ fn main() { let buf = &[1,2,3,4]; let n = ::read_u32(buf); assert_eq!(n, 0x01020304); - println!("{:#x}", n); + //println!("{:#x}", n); FIXME enable once memrchr works in miri eprintln!("standard error"); } diff --git a/cargo-miri-test/stdout.ref b/cargo-miri-test/stdout.ref index 53fefc734c85..e69de29bb2d1 100644 --- a/cargo-miri-test/stdout.ref +++ b/cargo-miri-test/stdout.ref @@ -1 +0,0 @@ -0x1020304 From e2c1b7008642cfea12b347ed3dc4a7dd0e1f0ad0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Jul 2018 18:15:51 +0200 Subject: [PATCH 0157/5092] nicer diff formating --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 865da6f66499..d05661a48487 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,8 +39,8 @@ script: cat stdout.real stderr.real && # Test `cargo miri` output. Not on mac because output redirecting doesn't # work. There is no error. It just stops CI. - diff stdout.ref stdout.real && - diff stderr.ref stderr.real + diff -u stdout.ref stdout.real && + diff -u stderr.ref stderr.real fi && # Test `cargo miri test` #cargo miri test && From ff3efb4e04ed2e915bda0cef3d2c7c9e4145ab34 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 Jul 2018 14:49:01 +0200 Subject: [PATCH 0158/5092] clarify error message when sysroot was not found --- src/bin/miri.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index e380317138aa..58897541491d 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -200,7 +200,8 @@ fn find_sysroot() -> String { _ => { option_env!("RUST_SYSROOT") .expect( - "need to specify RUST_SYSROOT env var or use rustup or multirust", + "Could not find sysroot. Either set MIRI_SYSROOT at run-time, or at \ + build-time specify RUST_SYSROOT env var or use rustup or multirust", ) .to_owned() } From 1538b36c8042f22f7c3fe191016c8469991c1c89 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 31 Jul 2018 20:27:36 +0200 Subject: [PATCH 0159/5092] make sure that StorageDead invalidates the backing store --- tests/compile-fail/storage_dead_dangling.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/compile-fail/storage_dead_dangling.rs diff --git a/tests/compile-fail/storage_dead_dangling.rs b/tests/compile-fail/storage_dead_dangling.rs new file mode 100644 index 000000000000..6abae2069fc2 --- /dev/null +++ b/tests/compile-fail/storage_dead_dangling.rs @@ -0,0 +1,20 @@ +static mut LEAK: usize = 0; + +fn fill(v: &mut i32) { + unsafe { LEAK = v as *mut _ as usize; } +} + +fn evil() { + let v = unsafe { &mut *(LEAK as *mut i32) }; + let _x = *v; //~ ERROR dangling pointer was dereferenced +} + +fn main() { + let _y; + { + let mut x = 0i32; + fill(&mut x); + _y = x; + } + evil(); +} From b45885d31fb32d0c9e05b054ef18698579c244ab Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 Aug 2018 16:34:39 +0200 Subject: [PATCH 0160/5092] Revert "Disable blood letting edge features" This reverts commit 305d8aeafe4ab53d7809ec6a1b9227166bd4fa63. --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 07ebca6491dd..23c7856cc773 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,5 @@ +cargo-features = ["default-run"] + [package] authors = ["Scott Olson "] description = "An experimental interpreter for Rust MIR." @@ -6,6 +8,7 @@ name = "miri" repository = "https://github.com/solson/miri" version = "0.1.0" build = "build.rs" +default-run = "miri" [[bin]] doc = false From 18546308cefd4edd51aaab6fbf5e896130b3532e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Aug 2018 00:17:02 +0200 Subject: [PATCH 0161/5092] mem(r)chr is working in miri now --- cargo-miri-test/src/main.rs | 2 +- cargo-miri-test/stdout.ref | 1 + tests/run-pass-fullmir/memchr.rs | 90 ++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 tests/run-pass-fullmir/memchr.rs diff --git a/cargo-miri-test/src/main.rs b/cargo-miri-test/src/main.rs index 3fb265f6a7ba..6ad516710e1b 100644 --- a/cargo-miri-test/src/main.rs +++ b/cargo-miri-test/src/main.rs @@ -6,6 +6,6 @@ fn main() { let buf = &[1,2,3,4]; let n = ::read_u32(buf); assert_eq!(n, 0x01020304); - //println!("{:#x}", n); FIXME enable once memrchr works in miri + println!("{:#x}", n); eprintln!("standard error"); } diff --git a/cargo-miri-test/stdout.ref b/cargo-miri-test/stdout.ref index e69de29bb2d1..6710f307cb26 100644 --- a/cargo-miri-test/stdout.ref +++ b/cargo-miri-test/stdout.ref @@ -0,0 +1 @@ +0x01020304 diff --git a/tests/run-pass-fullmir/memchr.rs b/tests/run-pass-fullmir/memchr.rs new file mode 100644 index 000000000000..36eb85dcf7e8 --- /dev/null +++ b/tests/run-pass-fullmir/memchr.rs @@ -0,0 +1,90 @@ +#![feature(slice_internals)] + +extern crate core; +use core::slice::memchr::{memchr, memrchr}; + +// test fallback implementations on all platforms +fn matches_one() { + assert_eq!(Some(0), memchr(b'a', b"a")); +} + +fn matches_begin() { + assert_eq!(Some(0), memchr(b'a', b"aaaa")); +} + +fn matches_end() { + assert_eq!(Some(4), memchr(b'z', b"aaaaz")); +} + +fn matches_nul() { + assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00")); +} + +fn matches_past_nul() { + assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z")); +} + +fn no_match_empty() { + assert_eq!(None, memchr(b'a', b"")); +} + +fn no_match() { + assert_eq!(None, memchr(b'a', b"xyz")); +} + +fn matches_one_reversed() { + assert_eq!(Some(0), memrchr(b'a', b"a")); +} + +fn matches_begin_reversed() { + assert_eq!(Some(3), memrchr(b'a', b"aaaa")); +} + +fn matches_end_reversed() { + assert_eq!(Some(0), memrchr(b'z', b"zaaaa")); +} + +fn matches_nul_reversed() { + assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00")); +} + +fn matches_past_nul_reversed() { + assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa")); +} + +fn no_match_empty_reversed() { + assert_eq!(None, memrchr(b'a', b"")); +} + +fn no_match_reversed() { + assert_eq!(None, memrchr(b'a', b"xyz")); +} + +fn each_alignment_reversed() { + let mut data = [1u8; 64]; + let needle = 2; + let pos = 40; + data[pos] = needle; + for start in 0..16 { + assert_eq!(Some(pos - start), memrchr(needle, &data[start..])); + } +} + +fn main() { + matches_one(); + matches_begin(); + matches_end(); + matches_nul(); + matches_past_nul(); + no_match_empty(); + no_match(); + + matches_one_reversed(); + matches_begin_reversed(); + matches_end_reversed(); + matches_nul_reversed(); + matches_past_nul_reversed(); + no_match_empty_reversed(); + no_match_reversed(); + each_alignment_reversed(); +} From d844792d761b920fb05aedb6d84e071afe805545 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Aug 2018 10:45:08 +0200 Subject: [PATCH 0162/5092] fix format string to obtain desired output --- cargo-miri-test/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-miri-test/src/main.rs b/cargo-miri-test/src/main.rs index 6ad516710e1b..4e1501dd57f2 100644 --- a/cargo-miri-test/src/main.rs +++ b/cargo-miri-test/src/main.rs @@ -6,6 +6,6 @@ fn main() { let buf = &[1,2,3,4]; let n = ::read_u32(buf); assert_eq!(n, 0x01020304); - println!("{:#x}", n); + println!("{:#010x}", n); eprintln!("standard error"); } From 3783cebe80b3ac0b6acb28452962e6131bb03a2c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Aug 2018 12:16:02 +0200 Subject: [PATCH 0163/5092] remove dependency on lazy_static and regex by getting rid of some dead validation hack --- Cargo.toml | 4 +--- src/lib.rs | 3 --- src/validation.rs | 28 ---------------------------- 3 files changed, 1 insertion(+), 34 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 07ebca6491dd..fd62625be131 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,9 +21,7 @@ required-features = ["cargo_miri"] [dependencies] byteorder = { version = "1.1", features = ["i128"]} cargo_metadata = { version = "0.6", optional = true } -regex = "1.0" -lazy_static = "1.0" -env_logger = "0.5.0-rc.1" +env_logger = "0.5" log = "0.4" [features] diff --git a/src/lib.rs b/src/lib.rs index 5a2d7e77d65f..f16471352c8f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,9 +17,6 @@ extern crate rustc_data_structures; extern crate rustc_mir; extern crate rustc_target; extern crate syntax; -extern crate regex; -#[macro_use] -extern crate lazy_static; use rustc::ty::{self, TyCtxt}; use rustc::ty::layout::{TyLayout, LayoutOf, Size}; diff --git a/src/validation.rs b/src/validation.rs index 676718ad7fe7..8d55f8ab0afe 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -159,34 +159,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } debug_assert!(self.memory.cur_frame == self.cur_frame()); - // HACK: Determine if this method is whitelisted and hence we do not perform any validation. - // We currently insta-UB on anything passing around uninitialized memory, so we have to whitelist - // the places that are allowed to do that. - // The second group is stuff libstd does that is forbidden even under relaxed validation. - { - // The regexp we use for filtering - use regex::Regex; - lazy_static! { - static ref RE: Regex = Regex::new("^(\ - (std|alloc::heap::__core)::mem::(uninitialized|forget)::|\ - <(std|alloc)::heap::Heap as (std::heap|alloc::allocator)::Alloc>::|\ - <(std|alloc::heap::__core)::mem::ManuallyDrop><.*>::new$|\ - <(std|alloc::heap::__core)::mem::ManuallyDrop as std::ops::DerefMut><.*>::deref_mut$|\ - (std|alloc::heap::__core)::ptr::read::|\ - \ - ><.*>::inner$|\ - ><.*>::drop_slow$|\ - (std::heap|alloc::allocator)::Layout::for_value::|\ - (std|alloc::heap::__core)::mem::(size|align)_of_val::\ - )").unwrap(); - } - // Now test - let name = self.frame().instance.to_string(); - if RE.is_match(&name) { - return Ok(()); - } - } - // We need to monomorphize ty *without* erasing lifetimes trace!("validation_op1: {:?}", operand.ty.sty); let ty = operand.ty.subst(self.tcx.tcx, self.substs()); From be91aea0fa285a86291e70259fb7be1d472674a8 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 7 Aug 2018 15:22:11 +0200 Subject: [PATCH 0164/5092] Rustup --- src/bin/miri.rs | 5 +- src/fn_call.rs | 142 +++++++++++++++++++++++--------------------- src/helpers.rs | 10 ++-- src/intrinsic.rs | 148 ++++++++++++++++++++++------------------------ src/lib.rs | 77 ++++++++++-------------- src/operator.rs | 7 ++- src/tls.rs | 22 +++---- src/validation.rs | 8 +-- 8 files changed, 206 insertions(+), 213 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 58897541491d..57d49b2e6bc5 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -3,6 +3,7 @@ extern crate getopts; extern crate miri; extern crate rustc; +extern crate rustc_metadata; extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_codegen_utils; @@ -12,7 +13,7 @@ extern crate syntax; extern crate log; use rustc::session::Session; -use rustc::middle::cstore::CrateStore; +use rustc_metadata::cstore::CStore; use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls}; use rustc_driver::driver::{CompileState, CompileController}; use rustc::session::config::{self, Input, ErrorOutputType}; @@ -70,7 +71,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { codegen_backend: &CodegenBackend, matches: &getopts::Matches, sess: &Session, - cstore: &CrateStore, + cstore: &CStore, input: &Input, odir: &Option, ofile: &Option, diff --git a/src/fn_call.rs b/src/fn_call.rs index 9dfff9f55398..11b0ae345c7f 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -37,7 +37,7 @@ fn write_discriminant_value<'a, 'mir, 'tcx: 'a + 'mir>( .val; let (discr_dest, discr) = ecx.place_field(dest, mir::Field::new(0), layout)?; - ecx.write_scalar(discr_dest, Scalar::from_u128(discr_val), discr.ty)?; + ecx.write_scalar(discr_dest, Scalar::from_uint(discr_val, discr.size), discr.ty)?; } layout::Variants::NicheFilling { dataful_variant, @@ -50,7 +50,7 @@ fn write_discriminant_value<'a, 'mir, 'tcx: 'a + 'mir>( ecx.place_field(dest, mir::Field::new(0), layout)?; let niche_value = ((variant_index - niche_variants.start()) as u128) .wrapping_add(niche_start); - ecx.write_scalar(niche_dest, Scalar::from_u128(niche_value), niche.ty)?; + ecx.write_scalar(niche_dest, Scalar::from_uint(niche_value, niche.size), niche.ty)?; } } } @@ -88,7 +88,7 @@ pub trait EvalContextExt<'tcx> { sig: ty::FnSig<'tcx>, ) -> EvalResult<'tcx, bool>; - fn write_null(&mut self, dest: Place, dest_ty: Ty<'tcx>) -> EvalResult<'tcx>; + fn write_null(&mut self, dest: Place, dest_layout: TyLayout<'tcx>) -> EvalResult<'tcx>; } impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { @@ -138,7 +138,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let amt = 128 - self.memory.pointer_size().bytes() * 8; let (dest, return_to_block) = destination.unwrap(); let ty = self.tcx.types.usize; - self.write_scalar(dest, Scalar::from_u128((n << amt) >> amt), ty)?; + let ptr_size = self.memory.pointer_size(); + self.write_scalar(dest, Scalar::from_uint((n << amt) >> amt, ptr_size), ty)?; self.goto_block(return_to_block); return Ok(true); } @@ -187,12 +188,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Some(name) => name.as_str(), None => self.tcx.item_name(def_id).as_str(), }; + let dest_layout = self.layout_of(dest_ty)?; match &link_name[..] { "malloc" => { let size = self.value_to_scalar(args[0])?.to_usize(self)?; if size == 0 { - self.write_null(dest, dest_ty)?; + self.write_null(dest, dest_layout)?; } else { let align = self.tcx.data_layout.pointer_align; let ptr = self.memory.allocate(Size::from_bytes(size), align, MemoryKind::C.into())?; @@ -201,8 +203,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "free" => { - let ptr = self.into_ptr(args[0].value)?; - if !ptr.is_null()? { + let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; + if !ptr.is_null() { self.memory.deallocate( ptr.to_ptr()?, None, @@ -241,7 +243,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; } "__rust_dealloc" => { - let ptr = self.into_ptr(args[0].value)?.to_ptr()?; + let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?.to_ptr()?; let old_size = self.value_to_scalar(args[1])?.to_usize(self)?; let align = self.value_to_scalar(args[2])?.to_usize(self)?; if old_size == 0 { @@ -257,7 +259,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' )?; } "__rust_realloc" => { - let ptr = self.into_ptr(args[0].value)?.to_ptr()?; + let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?.to_ptr()?; let old_size = self.value_to_scalar(args[1])?.to_usize(self)?; let align = self.value_to_scalar(args[2])?.to_usize(self)?; let new_size = self.value_to_scalar(args[3])?.to_usize(self)?; @@ -300,7 +302,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "dlsym" => { let _handle = self.into_ptr(args[0].value)?; - let symbol = self.into_ptr(args[1].value)?.to_ptr()?; + let symbol = self.into_ptr(args[1].value)?.unwrap_or_err()?.to_ptr()?; let symbol_name = self.memory.read_c_str(symbol)?; let err = format!("bad c unicode symbol: {:?}", symbol_name); let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err); @@ -314,10 +316,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // fn __rust_maybe_catch_panic(f: fn(*mut u8), data: *mut u8, data_ptr: *mut usize, vtable_ptr: *mut usize) -> u32 // We abort on panic, so not much is going on here, but we still have to call the closure let u8_ptr_ty = self.tcx.mk_mut_ptr(self.tcx.types.u8); - let f = self.into_ptr(args[0].value)?.to_ptr()?; - let data = self.into_ptr(args[1].value)?; + let f = self.into_ptr(args[0].value)?.unwrap_or_err()?.to_ptr()?; + let data = self.into_ptr(args[1].value)?.unwrap_or_err()?; let f_instance = self.memory.get_fn(f)?; - self.write_null(dest, dest_ty)?; + self.write_null(dest, dest_layout)?; // Now we make a function call. TODO: Consider making this re-usable? EvalContext::step does sth. similar for the TLS dtors, // and of course eval_main. @@ -343,7 +345,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected"); // We ourselves return 0 - self.write_null(dest, dest_ty)?; + self.write_null(dest, dest_layout)?; // Don't fall through return Ok(()); @@ -354,8 +356,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "memcmp" => { - let left = self.into_ptr(args[0].value)?; - let right = self.into_ptr(args[1].value)?; + let left = self.into_ptr(args[0].value)?.unwrap_or_err()?; + let right = self.into_ptr(args[1].value)?.unwrap_or_err()?; let n = Size::from_bytes(self.value_to_scalar(args[2])?.to_usize(self)?); let result = { @@ -378,7 +380,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "memrchr" => { - let ptr = self.into_ptr(args[0].value)?; + let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; let val = self.value_to_scalar(args[1])?.to_bytes()? as u8; let num = self.value_to_scalar(args[2])?.to_usize(self)?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().rev().position( @@ -388,12 +390,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), &self)?; self.write_ptr(dest, new_ptr, dest_ty)?; } else { - self.write_null(dest, dest_ty)?; + self.write_null(dest, dest_layout)?; } } "memchr" => { - let ptr = self.into_ptr(args[0].value)?; + let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; let val = self.value_to_scalar(args[1])?.to_bytes()? as u8; let num = self.value_to_scalar(args[2])?.to_usize(self)?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().position( @@ -403,17 +405,17 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), &self)?; self.write_ptr(dest, new_ptr, dest_ty)?; } else { - self.write_null(dest, dest_ty)?; + self.write_null(dest, dest_layout)?; } } "getenv" => { let result = { - let name_ptr = self.into_ptr(args[0].value)?.to_ptr()?; + let name_ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?.to_ptr()?; let name = self.memory.read_c_str(name_ptr)?; match self.machine.env_vars.get(name) { Some(&var) => Scalar::Ptr(var), - None => Scalar::null(), + None => Scalar::null(self.memory.pointer_size()), } }; self.write_scalar(dest, result, dest_ty)?; @@ -422,8 +424,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "unsetenv" => { let mut success = None; { - let name_ptr = self.into_ptr(args[0].value)?; - if !name_ptr.is_null()? { + let name_ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; + if !name_ptr.is_null() { let name = self.memory.read_c_str(name_ptr.to_ptr()?)?; if !name.is_empty() && !name.contains(&b'=') { success = Some(self.machine.env_vars.remove(name)); @@ -434,19 +436,19 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' if let Some(var) = old { self.memory.deallocate(var, None, MemoryKind::Env.into())?; } - self.write_null(dest, dest_ty)?; + self.write_null(dest, dest_layout)?; } else { - self.write_scalar(dest, Scalar::from_i128(-1), dest_ty)?; + self.write_scalar(dest, Scalar::from_int(-1, dest_layout.size), dest_ty)?; } } "setenv" => { let mut new = None; { - let name_ptr = self.into_ptr(args[0].value)?; - let value_ptr = self.into_ptr(args[1].value)?.to_ptr()?; + let name_ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; + let value_ptr = self.into_ptr(args[1].value)?.unwrap_or_err()?.to_ptr()?; let value = self.memory.read_c_str(value_ptr)?; - if !name_ptr.is_null()? { + if !name_ptr.is_null() { let name = self.memory.read_c_str(name_ptr.to_ptr()?)?; if !name.is_empty() && !name.contains(&b'=') { new = Some((name.to_owned(), value.to_owned())); @@ -470,15 +472,15 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' { self.memory.deallocate(var, None, MemoryKind::Env.into())?; } - self.write_null(dest, dest_ty)?; + self.write_null(dest, dest_layout)?; } else { - self.write_scalar(dest, Scalar::from_i128(-1), dest_ty)?; + self.write_scalar(dest, Scalar::from_int(-1, dest_layout.size), dest_ty)?; } } "write" => { let fd = self.value_to_scalar(args[0])?.to_bytes()?; - let buf = self.into_ptr(args[1].value)?; + let buf = self.into_ptr(args[1].value)?.unwrap_or_err()?; let n = self.value_to_scalar(args[2])?.to_bytes()? as u64; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { @@ -502,31 +504,33 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let ptr_size = self.memory.pointer_size(); self.write_scalar( dest, - Scalar::from_isize(result, ptr_size), + Scalar::from_int(result, ptr_size), dest_ty, )?; } "strlen" => { - let ptr = self.into_ptr(args[0].value)?.to_ptr()?; + let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?.to_ptr()?; let n = self.memory.read_c_str(ptr)?.len(); let ptr_size = self.memory.pointer_size(); - self.write_scalar(dest, Scalar::from_usize(n as u64, ptr_size), dest_ty)?; + self.write_scalar(dest, Scalar::from_uint(n as u64, ptr_size), dest_ty)?; } // Some things needed for sys::thread initialization to go through "signal" | "sigaction" | "sigaltstack" => { - self.write_scalar(dest, Scalar::null(), dest_ty)?; + let ptr_size = self.memory.pointer_size(); + self.write_scalar(dest, Scalar::null(ptr_size), dest_ty)?; } "sysconf" => { let name = self.value_to_scalar(args[0])?.to_usize(self)?; + let ptr_size = self.memory.pointer_size(); trace!("sysconf() called with name {}", name); // cache the sysconf integers via miri's global cache let paths = &[ - (&["libc", "_SC_PAGESIZE"], Scalar::from_i128(4096)), - (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_i128(-1)), + (&["libc", "_SC_PAGESIZE"], Scalar::from_int(4096, ptr_size)), + (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, ptr_size)), ]; let mut result = None; for &(path, path_value) in paths { @@ -554,43 +558,45 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // Hook pthread calls that go to the thread-local storage memory subsystem "pthread_key_create" => { - let key_ptr = self.into_ptr(args[0].value)?; - let key_align = self.layout_of(args[0].ty)?.align; + let key_ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; // Extract the function type out of the signature (that seems easier than constructing it ourselves...) - let dtor = match self.into_ptr(args[1].value)? { + let dtor = match self.into_ptr(args[1].value)?.unwrap_or_err()? { Scalar::Ptr(dtor_ptr) => Some(self.memory.get_fn(dtor_ptr)?), - Scalar::Bits { defined: 0, .. } => return err!(ReadUndefBytes), - Scalar::Bits { bits: 0, .. } => None, + Scalar::Bits { bits: 0, size } => { + assert_eq!(size as u64, self.memory.pointer_size().bytes()); + None + }, Scalar::Bits { .. } => return err!(ReadBytesAsPointer), }; // Figure out how large a pthread TLS key actually is. This is libc::pthread_key_t. let key_type = args[0].ty.builtin_deref(true) .ok_or_else(|| EvalErrorKind::AbiViolation("Wrong signature used for pthread_key_create: First argument must be a raw pointer.".to_owned()))?.ty; - let key_size = self.layout_of(key_type)?.size; + let key_layout = self.layout_of(key_type)?; // Create key and write it into the memory where key_ptr wants it let key = self.memory.create_tls_key(dtor) as u128; - if key_size.bits() < 128 && key >= (1u128 << key_size.bits() as u128) { + if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) { return err!(OutOfTls); } self.memory.write_scalar( key_ptr, - key_align, - Scalar::from_u128(key), - key_size, + key_layout.align, + Scalar::from_uint(key, key_layout.size).into(), + key_layout.size, + key_layout.align, false, )?; // Return success (0) - self.write_null(dest, dest_ty)?; + self.write_null(dest, dest_layout)?; } "pthread_key_delete" => { let key = self.value_to_scalar(args[0])?.to_bytes()?; self.memory.delete_tls_key(key)?; // Return success (0) - self.write_null(dest, dest_ty)?; + self.write_null(dest, dest_layout)?; } "pthread_getspecific" => { let key = self.value_to_scalar(args[0])?.to_bytes()?; @@ -599,11 +605,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "pthread_setspecific" => { let key = self.value_to_scalar(args[0])?.to_bytes()?; - let new_ptr = self.into_ptr(args[1].value)?; + let new_ptr = self.into_ptr(args[1].value)?.unwrap_or_err()?; self.memory.store_tls(key, new_ptr)?; // Return success (0) - self.write_null(dest, dest_ty)?; + self.write_null(dest, dest_layout)?; } "_tlv_atexit" => { @@ -613,19 +619,20 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // Stub out all the other pthread calls to just return 0 link_name if link_name.starts_with("pthread_") => { debug!("ignoring C ABI call: {}", link_name); - self.write_null(dest, dest_ty)?; + self.write_null(dest, dest_layout)?; } "mmap" => { // This is a horrible hack, but well... the guard page mechanism calls mmap and expects a particular return value, so we give it that value - let addr = self.into_ptr(args[0].value)?; + let addr = self.into_ptr(args[0].value)?.unwrap_or_err()?; self.write_ptr(dest, addr, dest_ty)?; } // Windows API subs "AddVectoredExceptionHandler" => { // any non zero value works for the stdlib. This is just used for stackoverflows anyway - self.write_scalar(dest, Scalar::from_u128(1), dest_ty)?; + let ptr_size = self.memory.pointer_size(); + self.write_scalar(dest, Scalar::from_int(1, ptr_size), dest_ty)?; }, "GetModuleHandleW" | "GetProcAddress" | @@ -636,26 +643,28 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "DeleteCriticalSection" | "SetLastError" => { // pretend these do not exist/nothing happened, by returning zero - self.write_scalar(dest, Scalar::from_u128(0), dest_ty)?; + let ptr_size = self.memory.pointer_size(); + self.write_scalar(dest, Scalar::from_int(0, ptr_size), dest_ty)?; }, "GetLastError" => { // this is c::ERROR_CALL_NOT_IMPLEMENTED - self.write_scalar(dest, Scalar::from_u128(120), dest_ty)?; + let ptr_size = self.memory.pointer_size(); + self.write_scalar(dest, Scalar::from_int(120, ptr_size), dest_ty)?; }, // Windows TLS "TlsAlloc" => { // This just creates a key; Windows does not natively support TLS dtors. - // Figure out how large a TLS key actually is. This is c::DWORD. - let key_size = self.layout_of(dest_ty)?.size; - // Create key and return it let key = self.memory.create_tls_key(None) as u128; - if key_size.bits() < 128 && key >= (1u128 << key_size.bits() as u128) { + + // Figure out how large a TLS key actually is. This is c::DWORD. + if dest_layout.size.bits() < 128 && key >= (1u128 << dest_layout.size.bits() as u128) { return err!(OutOfTls); } - self.write_scalar(dest, Scalar::from_u128(key), dest_ty)?; + let ptr_size = self.memory.pointer_size(); + self.write_scalar(dest, Scalar::from_uint(key, ptr_size), dest_layout.ty)?; } "TlsGetValue" => { let key = self.value_to_scalar(args[0])?.to_bytes()?; @@ -664,11 +673,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "TlsSetValue" => { let key = self.value_to_scalar(args[0])?.to_bytes()?; - let new_ptr = self.into_ptr(args[1].value)?; + let new_ptr = self.into_ptr(args[1].value)?.unwrap_or_err()?; self.memory.store_tls(key, new_ptr)?; + let ptr_size = self.memory.pointer_size(); // Return success (1) - self.write_scalar(dest, Scalar::from_u128(1), dest_ty)?; + self.write_scalar(dest, Scalar::from_int(1, ptr_size), dest_ty)?; } // We can't execute anything else @@ -791,7 +801,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Ok(()) } - fn write_null(&mut self, dest: Place, dest_ty: Ty<'tcx>) -> EvalResult<'tcx> { - self.write_scalar(dest, Scalar::null(), dest_ty) + fn write_null(&mut self, dest: Place, dest_layout: TyLayout<'tcx>) -> EvalResult<'tcx> { + self.write_scalar(dest, Scalar::null(dest_layout.size), dest_layout.ty) } } diff --git a/src/helpers.rs b/src/helpers.rs index aa699b509fad..8482c484608b 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -51,7 +51,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // FIXME: assuming here that type size is < i64::max_value() let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; let offset = offset.overflowing_mul(pointee_size).0; - ptr.ptr_wrapping_signed_offset(offset, self) + Ok(ptr.ptr_wrapping_signed_offset(offset, self)) } fn pointer_offset( @@ -65,7 +65,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // We also consider the NULL pointer its own separate allocation, and all the remaining integers pointers their own // allocation. - if ptr.is_null()? { + if ptr.is_null() { // NULL pointers must only be offset by 0 return if offset == 0 { Ok(ptr) @@ -80,7 +80,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // Do not do bounds-checking for integers; they can never alias a normal pointer anyway. if let Scalar::Ptr(ptr) = ptr { self.memory.check_bounds(ptr, false)?; - } else if ptr.is_null()? { + } else if ptr.is_null() { // We moved *to* a NULL pointer. That seems wrong, LLVM considers the NULL pointer its own small allocation. Reject this, for now. return err!(InvalidNullPointerUsage); } @@ -96,7 +96,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: ) -> EvalResult<'tcx, i64> { assert_eq!(value.ty, self.tcx.types.isize); let raw = self.value_to_scalar(value)?.to_bits(self.memory.pointer_size())?; - let raw = sign_extend(self.tcx.tcx, raw, self.tcx.types.isize)?; + let raw = sign_extend(raw, self.layout_of(self.tcx.types.isize).unwrap()); Ok(raw as i64) } @@ -114,7 +114,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: ) -> EvalResult<'tcx, i32> { assert_eq!(value.ty, self.tcx.types.i32); let raw = self.value_to_scalar(value)?.to_bits(Size::from_bits(32))?; - let raw = sign_extend(self.tcx.tcx, raw, self.tcx.types.i32)?; + let raw = sign_extend(raw, self.layout_of(self.tcx.types.i32).unwrap()); Ok(raw as i32) } diff --git a/src/intrinsic.rs b/src/intrinsic.rs index dc2224c4ceef..5c6e7f9b2dc1 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -2,7 +2,7 @@ use rustc::mir; use rustc::ty::layout::{TyLayout, LayoutOf, Size, Primitive, Integer::*}; use rustc::ty; -use rustc::mir::interpret::{EvalResult, Scalar, Value}; +use rustc::mir::interpret::{EvalResult, Scalar, Value, ScalarMaybeUndef}; use rustc_mir::interpret::{Place, PlaceExtra, HasMemory, EvalContext, ValTy}; use helpers::EvalContextExt as HelperEvalContextExt; @@ -65,7 +65,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "arith_offset" => { let offset = self.value_to_isize(args[1])?; - let ptr = self.into_ptr(args[0].value)?; + let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; let result_ptr = self.wrapping_pointer_offset(ptr, substs.type_at(0), offset)?; self.write_ptr(dest, result_ptr, dest_layout.ty)?; } @@ -81,7 +81,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "atomic_load_relaxed" | "atomic_load_acq" | "volatile_load" => { - let ptr = self.into_ptr(args[0].value)?; + let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; let align = self.layout_of(args[0].ty)?.align; let valty = ValTy { @@ -97,7 +97,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "volatile_store" => { let ty = substs.type_at(0); let align = self.layout_of(ty)?.align; - let dest = self.into_ptr(args[0].value)?; + let dest = self.into_ptr(args[0].value)?.unwrap_or_err()?; self.write_value_to_ptr(args[1].value, dest, align, ty)?; } @@ -108,7 +108,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: _ if intrinsic_name.starts_with("atomic_xchg") => { let ty = substs.type_at(0); let align = self.layout_of(ty)?.align; - let ptr = self.into_ptr(args[0].value)?; + let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; let change = self.value_to_scalar(args[1])?; let old = self.read_value(ptr, align, ty)?; let old = match old { @@ -118,7 +118,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: }; self.write_scalar(dest, old, ty)?; self.write_scalar( - Place::from_scalar_ptr(ptr, align), + Place::from_scalar_ptr(ptr.into(), align), change, ty, )?; @@ -127,23 +127,23 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: _ if intrinsic_name.starts_with("atomic_cxchg") => { let ty = substs.type_at(0); let align = self.layout_of(ty)?.align; - let ptr = self.into_ptr(args[0].value)?; + let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; let expect_old = self.value_to_scalar(args[1])?; let change = self.value_to_scalar(args[2])?; let old = self.read_value(ptr, align, ty)?; let old = match old { - Value::Scalar(val) => val, + Value::Scalar(val) => val.unwrap_or_err()?, Value::ByRef { .. } => bug!("just read the value, can't be byref"), Value::ScalarPair(..) => bug!("atomic_cxchg doesn't work with nonprimitives"), }; let (val, _) = self.binary_op(mir::BinOp::Eq, old, ty, expect_old, ty)?; let valty = ValTy { - value: Value::ScalarPair(old, val), + value: Value::ScalarPair(old.into(), val.into()), ty: dest_layout.ty, }; self.write_value(valty, dest)?; self.write_scalar( - Place::from_scalar_ptr(ptr, dest_layout.align), + Place::from_scalar_ptr(ptr.into(), dest_layout.align), change, ty, )?; @@ -176,7 +176,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "atomic_xsub_relaxed" => { let ty = substs.type_at(0); let align = self.layout_of(ty)?.align; - let ptr = self.into_ptr(args[0].value)?; + let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; let change = self.value_to_scalar(args[1])?; let old = self.read_value(ptr, align, ty)?; let old = match old { @@ -196,8 +196,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: _ => bug!(), }; // FIXME: what do atomics do on overflow? - let (val, _) = self.binary_op(op, old, ty, change, ty)?; - self.write_scalar(Place::from_scalar_ptr(ptr, dest_layout.align), val, ty)?; + let (val, _) = self.binary_op(op, old.unwrap_or_err()?, ty, change, ty)?; + self.write_scalar(Place::from_scalar_ptr(ptr.into(), dest_layout.align), val, ty)?; } "breakpoint" => unimplemented!(), // halt miri @@ -212,8 +212,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // TODO: We do not even validate alignment for the 0-bytes case. libstd relies on this in vec::IntoIter::next. // Also see the write_bytes intrinsic. let elem_align = elem_layout.align; - let src = self.into_ptr(args[0].value)?; - let dest = self.into_ptr(args[1].value)?; + let src = self.into_ptr(args[0].value)?.unwrap_or_err()?; + let dest = self.into_ptr(args[1].value)?.unwrap_or_err()?; self.memory.copy( src, elem_align, @@ -250,7 +250,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let adt_align = self.layout_of(args[0].ty)?.align; let place = Place::from_scalar_ptr(adt_ptr, adt_align); let discr_val = self.read_discriminant_value(place, layout)?; - self.write_scalar(dest, Scalar::from_u128(discr_val), dest_layout.ty)?; + let ptr_size = self.memory.pointer_size(); + self.write_scalar(dest, Scalar::from_uint(discr_val, ptr_size), dest_layout.ty)?; } "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | @@ -320,7 +321,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let a = self.value_to_scalar(args[0])?; let b = self.value_to_scalar(args[1])?; // check x % y != 0 - if !self.binary_op(mir::BinOp::Rem, a, ty, b, ty)?.0.is_null()? { + if !self.binary_op(mir::BinOp::Rem, a, ty, b, ty)?.0.is_null() { return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b))); } let result = self.binary_op(mir::BinOp::Div, a, ty, b, ty)?; @@ -330,41 +331,24 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "likely" | "unlikely" | "forget" => {} "init" => { - let size = dest_layout.size; - let init = |this: &mut Self, val: Value| { - let zero_val = match val { - Value::ByRef(ptr, _) => { - // These writes have no alignment restriction anyway. - this.memory.write_repeat(ptr, 0, size)?; - val - } - // TODO(solson): Revisit this, it's fishy to check for Undef here. - Value::Scalar(Scalar::Bits { defined: 0, .. }) => { - match this.layout_of(dest_layout.ty)?.abi { - ty::layout::Abi::Scalar(_) => Value::Scalar(Scalar::null()), - _ => { - // FIXME(oli-obk): pass TyLayout to alloc_ptr instead of Ty - let ptr = this.alloc_ptr(dest_layout)?; - let ptr = Scalar::Ptr(ptr); - this.memory.write_repeat(ptr, 0, size)?; - Value::ByRef(ptr, dest_layout.align) - } + match dest { + Place::Local { frame, local } => { + match self.stack()[frame].locals[local].access()? { + Value::ByRef(ptr, _) => { + // These writes have no alignment restriction anyway. + self.memory.write_repeat(ptr, 0, dest_layout.size)?; + } + Value::Scalar(_) => self.write_value(ValTy { value: Value::Scalar(Scalar::null(dest_layout.size).into()), ty: dest_layout.ty }, dest)?, + Value::ScalarPair(..) => { + self.write_value(ValTy { value: Value::ScalarPair(Scalar::null(dest_layout.size).into(), Scalar::null(dest_layout.size).into()), ty: dest_layout.ty }, dest)?; } } - Value::Scalar(_) => Value::Scalar(Scalar::null()), - Value::ScalarPair(..) => { - Value::ScalarPair(Scalar::null(), Scalar::null()) - } - }; - Ok(zero_val) - }; - match dest { - Place::Local { frame, local } => self.modify_local(frame, local, init)?, + }, Place::Ptr { ptr, align: _align, extra: PlaceExtra::None, - } => self.memory.write_repeat(ptr, 0, size)?, + } => self.memory.write_repeat(ptr.unwrap_or_err()?, 0, dest_layout.size)?, Place::Ptr { .. } => { bug!("init intrinsic tried to write to fat or unaligned ptr target") } @@ -374,7 +358,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "min_align_of" => { let elem_ty = substs.type_at(0); let elem_align = self.layout_of(elem_ty)?.align.abi(); - let align_val = Scalar::from_u128(elem_align as u128); + let ptr_size = self.memory.pointer_size(); + let align_val = Scalar::from_uint(elem_align as u128, ptr_size); self.write_scalar(dest, align_val, dest_layout.ty)?; } @@ -382,13 +367,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ty = substs.type_at(0); let layout = self.layout_of(ty)?; let align = layout.align.pref(); - let align_val = Scalar::from_u128(align as u128); + let ptr_size = self.memory.pointer_size(); + let align_val = Scalar::from_uint(align as u128, ptr_size); self.write_scalar(dest, align_val, dest_layout.ty)?; } "move_val_init" => { let ty = substs.type_at(0); - let ptr = self.into_ptr(args[0].value)?; + let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; let align = self.layout_of(args[0].ty)?.align; self.write_value_to_ptr(args[1].value, ptr, align, ty)?; } @@ -406,7 +392,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "offset" => { let offset = self.value_to_isize(args[1])?; - let ptr = self.into_ptr(args[0].value)?; + let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; let result_ptr = self.pointer_offset(ptr, substs.type_at(0), offset)?; self.write_ptr(dest, result_ptr, dest_layout.ty)?; } @@ -517,16 +503,18 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "size_of" => { let ty = substs.type_at(0); - let size = self.layout_of(ty)?.size.bytes().into(); - self.write_scalar(dest, Scalar::from_u128(size), dest_layout.ty)?; + let size = self.layout_of(ty)?.size.bytes(); + let ptr_size = self.memory.pointer_size(); + self.write_scalar(dest, Scalar::from_uint(size, ptr_size), dest_layout.ty)?; } "size_of_val" => { let ty = substs.type_at(0); let (size, _) = self.size_and_align_of_dst(ty, args[0].value)?; + let ptr_size = self.memory.pointer_size(); self.write_scalar( dest, - Scalar::from_u128(size.bytes() as u128), + Scalar::from_uint(size.bytes() as u128, ptr_size), dest_layout.ty, )?; } @@ -535,9 +523,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "align_of_val" => { let ty = substs.type_at(0); let (_, align) = self.size_and_align_of_dst(ty, args[0].value)?; + let ptr_size = self.memory.pointer_size(); self.write_scalar( dest, - Scalar::from_u128(align.abi() as u128), + Scalar::from_uint(align.abi(), ptr_size), dest_layout.ty, )?; } @@ -551,7 +540,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "type_id" => { let ty = substs.type_at(0); let n = self.tcx.type_id_hash(ty); - self.write_scalar(dest, Scalar::Bits { bits: n as u128, defined: 64 }, dest_layout.ty)?; + self.write_scalar(dest, Scalar::Bits { bits: n as u128, size: 8 }, dest_layout.ty)?; } "transmute" => { @@ -629,21 +618,24 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "uninit" => { - let size = dest_layout.size; - let uninit = |this: &mut Self, val: Value| match val { - Value::ByRef(ptr, _) => { - this.memory.mark_definedness(ptr, size, false)?; - Ok(val) - } - _ => Ok(Value::Scalar(Scalar::undef())), - }; match dest { - Place::Local { frame, local } => self.modify_local(frame, local, uninit)?, + Place::Local { frame, local } => { + match self.stack()[frame].locals[local].access()? { + Value::ByRef(ptr, _) => { + // These writes have no alignment restriction anyway. + self.memory.mark_definedness(ptr, dest_layout.size, false)?; + } + Value::Scalar(_) => self.write_value(ValTy { value: Value::Scalar(ScalarMaybeUndef::Undef), ty: dest_layout.ty }, dest)?, + Value::ScalarPair(..) => { + self.write_value(ValTy { value: Value::ScalarPair(ScalarMaybeUndef::Undef, ScalarMaybeUndef::Undef), ty: dest_layout.ty }, dest)?; + } + } + }, Place::Ptr { ptr, align: _align, extra: PlaceExtra::None, - } => self.memory.mark_definedness(ptr, size, false)?, + } => self.memory.mark_definedness(ptr.unwrap_or_err()?, dest_layout.size, false)?, Place::Ptr { .. } => { bug!("uninit intrinsic tried to write to fat or unaligned ptr target") } @@ -654,7 +646,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ty = substs.type_at(0); let ty_layout = self.layout_of(ty)?; let val_byte = self.value_to_u8(args[1])?; - let ptr = self.into_ptr(args[0].value)?; + let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; let count = self.value_to_usize(args[2])?; if count > 0 { // HashMap relies on write_bytes on a NULL ptr with count == 0 to work @@ -683,21 +675,21 @@ fn numeric_intrinsic<'tcx>( ) -> EvalResult<'tcx, Scalar> { macro_rules! integer_intrinsic { ($method:ident) => ({ - let result_bytes = match kind { - Primitive::Int(I8, true) => (bytes as i8).$method() as u128, - Primitive::Int(I8, false) => (bytes as u8).$method() as u128, - Primitive::Int(I16, true) => (bytes as i16).$method() as u128, - Primitive::Int(I16, false) => (bytes as u16).$method() as u128, - Primitive::Int(I32, true) => (bytes as i32).$method() as u128, - Primitive::Int(I32, false) => (bytes as u32).$method() as u128, - Primitive::Int(I64, true) => (bytes as i64).$method() as u128, - Primitive::Int(I64, false) => (bytes as u64).$method() as u128, - Primitive::Int(I128, true) => (bytes as i128).$method() as u128, - Primitive::Int(I128, false) => bytes.$method() as u128, + let (result_bytes, size) = match kind { + Primitive::Int(I8, true) => ((bytes as i8).$method() as u128, 1), + Primitive::Int(I8, false) => ((bytes as u8).$method() as u128, 1), + Primitive::Int(I16, true) => ((bytes as i16).$method() as u128, 2), + Primitive::Int(I16, false) => ((bytes as u16).$method() as u128, 2), + Primitive::Int(I32, true) => ((bytes as i32).$method() as u128, 4), + Primitive::Int(I32, false) => ((bytes as u32).$method() as u128, 4), + Primitive::Int(I64, true) => ((bytes as i64).$method() as u128, 8), + Primitive::Int(I64, false) => ((bytes as u64).$method() as u128, 8), + Primitive::Int(I128, true) => ((bytes as i128).$method() as u128, 16), + Primitive::Int(I128, false) => (bytes.$method() as u128, 16), _ => bug!("invalid `{}` argument: {:?}", name, bytes), }; - Scalar::from_u128(result_bytes) + Scalar::from_uint(result_bytes, Size::from_bytes(size)) }); } diff --git a/src/lib.rs b/src/lib.rs index f16471352c8f..b08f63e095d8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,16 +56,14 @@ use range_map::RangeMap; use validation::{ValidationQuery, AbsPlace}; pub trait ScalarExt { - fn null() -> Self; + fn null(size: Size) -> Self; fn from_i32(i: i32) -> Self; - fn from_u128(i: u128) -> Self; - fn from_i128(i: i128) -> Self; - fn from_usize(i: u64, ptr_size: Size) -> Self; - fn from_isize(i: i64, ptr_size: Size) -> Self; + fn from_uint(i: impl Into, ptr_size: Size) -> Self; + fn from_int(i: impl Into, ptr_size: Size) -> Self; fn from_f32(f: f32) -> Self; fn from_f64(f: f64) -> Self; fn to_usize<'a, 'mir, 'tcx>(self, ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>) -> EvalResult<'static, u64>; - fn is_null(self) -> EvalResult<'static, bool>; + fn is_null(self) -> bool; /// HACK: this function just extracts all bits if `defined != 0` /// Mainly used for args of C-functions and we should totally correctly fetch the size /// of their arguments @@ -73,36 +71,28 @@ pub trait ScalarExt { } impl ScalarExt for Scalar { - fn null() -> Self { - Scalar::Bits { bits: 0, defined: 128 } + fn null(size: Size) -> Self { + Scalar::Bits { bits: 0, size: size.bytes() as u8 } } fn from_i32(i: i32) -> Self { - Scalar::Bits { bits: i as u32 as u128, defined: 32 } + Scalar::Bits { bits: i as u32 as u128, size: 4 } } - fn from_u128(i: u128) -> Self { - Scalar::Bits { bits: i, defined: 128 } + fn from_uint(i: impl Into, ptr_size: Size) -> Self { + Scalar::Bits { bits: i.into(), size: ptr_size.bytes() as u8 } } - fn from_i128(i: i128) -> Self { - Scalar::Bits { bits: i as u128, defined: 128 } - } - - fn from_usize(i: u64, ptr_size: Size) -> Self { - Scalar::Bits { bits: i as u128, defined: ptr_size.bits() as u8 } - } - - fn from_isize(i: i64, ptr_size: Size) -> Self { - Scalar::Bits { bits: i as i128 as u128, defined: ptr_size.bits() as u8 } + fn from_int(i: impl Into, ptr_size: Size) -> Self { + Scalar::Bits { bits: i.into() as u128, size: ptr_size.bytes() as u8 } } fn from_f32(f: f32) -> Self { - Scalar::Bits { bits: f.to_bits() as u128, defined: 32 } + Scalar::Bits { bits: f.to_bits() as u128, size: 4 } } fn from_f64(f: f64) -> Self { - Scalar::Bits { bits: f.to_bits() as u128, defined: 64 } + Scalar::Bits { bits: f.to_bits() as u128, size: 8 } } fn to_usize<'a, 'mir, 'tcx>(self, ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>) -> EvalResult<'static, u64> { @@ -111,23 +101,19 @@ impl ScalarExt for Scalar { Ok(b as u64) } - fn is_null(self) -> EvalResult<'static, bool> { + fn is_null(self) -> bool { match self { - Scalar::Bits { bits, defined } => { - if defined > 0 { - Ok(bits == 0) - } else { - err!(ReadUndefBytes) - } - } - Scalar::Ptr(_) => Ok(false) + Scalar::Bits { bits, .. } => bits == 0, + Scalar::Ptr(_) => false } } fn to_bytes(self) -> EvalResult<'static, u128> { match self { - Scalar::Bits { defined: 0, .. } => err!(ReadUndefBytes), - Scalar::Bits { bits, .. } => Ok(bits), + Scalar::Bits { bits, size } => { + assert_ne!(size, 0); + Ok(bits) + }, Scalar::Ptr(_) => err!(ReadPointerAsBytes), } } @@ -155,6 +141,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( .to_owned(), )); } + let ptr_size = ecx.memory.pointer_size(); if let Some(start_id) = start_wrapper { let main_ret_ty = ecx.tcx.fn_sig(main_id).output(); @@ -199,7 +186,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let main_ptr_ty = ecx.tcx.mk_fn_ptr(main_ty.fn_sig(ecx.tcx.tcx)); ecx.write_value( ValTy { - value: Value::Scalar(Scalar::Ptr(main_ptr)), + value: Value::Scalar(Scalar::Ptr(main_ptr).into()), ty: main_ptr_ty, }, dest, @@ -208,17 +195,16 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // Second argument (argc): 1 let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let ty = ecx.tcx.types.isize; - ecx.write_scalar(dest, Scalar::from_u128(1), ty)?; + ecx.write_scalar(dest, Scalar::from_int(1, ptr_size), ty)?; // FIXME: extract main source file path // Third argument (argv): &[b"foo"] let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let ty = ecx.tcx.mk_imm_ptr(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8)); let foo = ecx.memory.allocate_bytes(b"foo\0"); - let ptr_size = ecx.memory.pointer_size(); let ptr_align = ecx.tcx.data_layout.pointer_align; let foo_ptr = ecx.memory.allocate(ptr_size, ptr_align, MemoryKind::Stack)?; - ecx.memory.write_scalar(foo_ptr.into(), ptr_align, Scalar::Ptr(foo), ptr_size, false)?; + ecx.memory.write_scalar(foo_ptr.into(), ptr_align, Scalar::Ptr(foo).into(), ptr_size, ptr_align, false)?; ecx.memory.mark_static_initialized(foo_ptr.alloc_id, Mutability::Immutable)?; ecx.write_ptr(dest, foo_ptr.into(), ty)?; @@ -228,7 +214,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( main_instance, main_mir.span, main_mir, - Place::from_scalar_ptr(Scalar::from_u128(1), ty::layout::Align::from_bytes(1, 1).unwrap()), + Place::from_scalar_ptr(Scalar::from_int(1, ptr_size).into(), ty::layout::Align::from_bytes(1, 1).unwrap()), StackPopCleanup::None, )?; @@ -294,7 +280,7 @@ pub fn eval_main<'a, 'tcx: 'a>( trace!("Frame {}", i); trace!(" return: {:#?}", frame.return_place); for (i, local) in frame.locals.iter().enumerate() { - if let Some(local) = local { + if let Ok(local) = local.access() { trace!(" local {}: {:?}", i, local); } } @@ -519,15 +505,16 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { let mut args = ecx.frame().mir.args_iter(); let usize = ecx.tcx.types.usize; + let ptr_size = ecx.memory.pointer_size(); // First argument: size let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; ecx.write_value( ValTy { - value: Value::Scalar(Scalar::from_u128(match layout.size.bytes() { - 0 => 1 as u128, - size => size as u128, - })), + value: Value::Scalar(Scalar::from_uint(match layout.size.bytes() { + 0 => 1, + size => size, + }, ptr_size).into()), ty: usize, }, dest, @@ -537,7 +524,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; ecx.write_value( ValTy { - value: Value::Scalar(Scalar::from_u128(layout.align.abi().into())), + value: Value::Scalar(Scalar::from_uint(layout.align.abi(), ptr_size).into()), ty: usize, }, dest, diff --git a/src/operator.rs b/src/operator.rs index 207324cfcb00..7be77771a7ca 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -116,9 +116,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Sub => { return self.binary_op( Sub, - Scalar::Bits { bits: left.offset.bytes() as u128, defined: self.memory.pointer_size().bits() as u8 }, + Scalar::Bits { bits: left.offset.bytes() as u128, size: self.memory.pointer_size().bytes() as u8 }, self.tcx.types.usize, - Scalar::Bits { bits: right.offset.bytes() as u128, defined: self.memory.pointer_size().bits() as u8 }, + Scalar::Bits { bits: right.offset.bytes() as u128, size: self.memory.pointer_size().bytes() as u8 }, self.tcx.types.usize, ).map(Some) } @@ -182,12 +182,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: BitAnd if !signed => { let base_mask : u64 = !(self.memory.get(left.alloc_id)?.align.abi() - 1); let right = right as u64; + let ptr_size = self.memory.pointer_size().bytes() as u8; if right & base_mask == base_mask { // Case 1: The base address bits are all preserved, i.e., right is all-1 there (Scalar::Ptr(Pointer::new(left.alloc_id, Size::from_bytes(left.offset.bytes() & right))), false) } else if right & base_mask == 0 { // Case 2: The base address bits are all taken away, i.e., right is all-0 there - (Scalar::Bits { bits: (left.offset.bytes() & right) as u128, defined: 128 }, false) + (Scalar::Bits { bits: (left.offset.bytes() & right) as u128, size: ptr_size }, false) } else { return err!(ReadPointerAsBytes); } diff --git a/src/tls.rs b/src/tls.rs index ffcf86291590..9f0fb2c8f62a 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -11,7 +11,7 @@ pub trait MemoryExt<'tcx> { fn fetch_tls_dtor( &mut self, key: Option, - ) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Scalar, TlsKey)>>; + ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)>; } pub trait EvalContextExt<'tcx> { @@ -22,10 +22,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu fn create_tls_key(&mut self, dtor: Option>) -> TlsKey { let new_key = self.data.next_thread_local; self.data.next_thread_local += 1; + let ptr_size = self.pointer_size(); self.data.thread_local.insert( new_key, TlsEntry { - data: Scalar::null(), + data: Scalar::null(ptr_size).into(), dtor, }, ); @@ -85,9 +86,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu fn fetch_tls_dtor( &mut self, key: Option, - ) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Scalar, TlsKey)>> { + ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { use std::collections::Bound::*; + let ptr_size = self.pointer_size(); let thread_local = &mut self.data.thread_local; let start = match key { Some(key) => Excluded(key), @@ -96,21 +98,21 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu for (&key, &mut TlsEntry { ref mut data, dtor }) in thread_local.range_mut((start, Unbounded)) { - if !data.is_null()? { + if !data.is_null() { if let Some(dtor) = dtor { let ret = Some((dtor, *data, key)); - *data = Scalar::null(); - return Ok(ret); + *data = Scalar::null(ptr_size); + return ret; } } } - Ok(None) + None } } impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>> { fn run_tls_dtors(&mut self) -> EvalResult<'tcx> { - let mut dtor = self.memory.fetch_tls_dtor(None)?; + let mut dtor = self.memory.fetch_tls_dtor(None); // FIXME: replace loop by some structure that works with stepping while let Some((instance, ptr, key)) = dtor { trace!("Running TLS dtor {:?} on {:?}", instance, ptr); @@ -134,9 +136,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // step until out of stackframes while self.step()? {} - dtor = match self.memory.fetch_tls_dtor(Some(key))? { + dtor = match self.memory.fetch_tls_dtor(Some(key)) { dtor @ Some(_) => dtor, - None => self.memory.fetch_tls_dtor(None)?, + None => self.memory.fetch_tls_dtor(None), }; } // FIXME: On a windows target, call `unsafe extern "system" fn on_tls_callback`. diff --git a/src/validation.rs b/src/validation.rs index 8d55f8ab0afe..7f0abb9ae0ba 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -117,7 +117,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Deref => Deref, Field(f, _) => Field(f, ()), Index(v) => { - let value = self.frame().get_local(v)?; + let value = self.frame().locals[v].access()?; let ty = self.tcx.tcx.types.usize; let n = self.value_to_scalar(ValTy { value, ty })?.to_usize(self)?; Index(n) @@ -480,7 +480,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' ) -> EvalResult<'tcx> { // Check alignment and non-NULLness let (_, align) = self.size_and_align_of_dst(pointee_ty, val)?; - let ptr = self.into_ptr(val)?; + let ptr = self.into_ptr(val)?.unwrap_or_err()?; self.memory.check_align(ptr, align)?; // Recurse @@ -562,7 +562,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' }; // Handle locking if len > 0 { - let ptr = ptr.to_ptr()?; + let ptr = ptr.unwrap_or_err()?.to_ptr()?; match query.mutbl { MutImmutable => { if mode.acquiring() { @@ -651,7 +651,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } TyFnPtr(_sig) => { let ptr = self.read_place(query.place.1)?; - let ptr = self.into_ptr(ptr)?.to_ptr()?; + let ptr = self.into_ptr(ptr)?.unwrap_or_err()?.to_ptr()?; self.memory.get_fn(ptr)?; // TODO: Check if the signature matches (should be the same check as what terminator/mod.rs already does on call?). } From 7b4402746fca13ea8901ed9f440b22073123c6c9 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 8 Aug 2018 10:34:49 +0200 Subject: [PATCH 0165/5092] Add comments explaining why we do something complex for (un)init --- src/intrinsic.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 5c6e7f9b2dc1..f31156a03e49 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -331,6 +331,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "likely" | "unlikely" | "forget" => {} "init" => { + // we don't want to force an allocation in case the destination is a simple value match dest { Place::Local { frame, local } => { match self.stack()[frame].locals[local].access()? { @@ -618,6 +619,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "uninit" => { + // we don't want to force an allocation in case the destination is a simple value match dest { Place::Local { frame, local } => { match self.stack()[frame].locals[local].access()? { From 1ec87283259b38d0e729495953dddc206d74a52f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 00:54:04 +0200 Subject: [PATCH 0166/5092] document and fully use rust-toolchain file --- .travis.yml | 2 ++ README.md | 27 ++++----------------------- rust-toolchain | 2 +- 3 files changed, 7 insertions(+), 24 deletions(-) diff --git a/.travis.yml b/.travis.yml index d05661a48487..bded347b825a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,8 @@ before_script: # mac os weirdness (https://github.com/travis-ci/travis-ci/issues/6307) - curl -sSL https://rvm.io/mpapis.asc | gpg --import - - rvm get stable +# in a cronjob, use latest (not pinned) nightly +- if [ "$TRAVIS_EVENT_TYPE" = cron ]; then rustup override set nightly; fi # actual travis code - export PATH=$HOME/.local/bin:$PATH - rustup target add i686-unknown-linux-gnu diff --git a/README.md b/README.md index 8c476270db1a..d14467be9144 100644 --- a/README.md +++ b/README.md @@ -5,35 +5,16 @@ An experimental interpreter for [Rust][rust]'s [mid-level intermediate representation][mir] (MIR). This project began as part of my work for the undergraduate research course at the [University of Saskatchewan][usask]. -## Installing Rust - -I recommend that you install [rustup][rustup] and then use it to install the -current Rust nightly version: - -```sh -rustup update nightly -``` - -You should also make `nightly` the default version for your Miri directory by -running the following command while you're in it. If you don't do this, you can -run the later `cargo` commands by using `cargo +nightly` instead. - -```sh -rustup override add nightly -``` - ## Building Miri +I recommend that you install [rustup][rustup] to obtain Rust. miri comes with a +`rust-toolchain` file so rustup will automatically pick a suitable nightly +version. Then all you have to do is: + ```sh cargo build ``` -If Miri fails to build, it's likely because a change in the latest nightly -compiler broke it. You could try an older nightly with `rustup update -nightly-` where `` is a few days or weeks ago, e.g. `2016-05-20` for -May 20th. Otherwise, you could notify me in an issue or on IRC. Or, if you know -how to fix it, you could send a PR. :smile: - ## Running tests ```sh diff --git a/rust-toolchain b/rust-toolchain index bf867e0ae5b6..8e23548106cb 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly +nightly-2018-08-03 From f0070fca1e47c836cd2c13524a37e0781fd76a3d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 09:35:31 +0200 Subject: [PATCH 0167/5092] remove unnecessary features --- src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b08f63e095d8..705f56d38f39 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,6 @@ #![feature( rustc_private, catch_expr, - inclusive_range_fields, - inclusive_range_methods, )] #![cfg_attr(feature = "cargo-clippy", allow(cast_lossless))] From bed48ce5dfcda3423037e9cfcba0ba2ea5870f27 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 09:40:00 +0200 Subject: [PATCH 0168/5092] bump toolchain --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 8e23548106cb..ec8c56dc6248 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-08-03 +nightly-2018-08-14 From 034bb25f548fff29d9caab6f0ebe232b9ba11278 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 09:34:41 +0200 Subject: [PATCH 0169/5092] fix 'cargo miri test' for full MIR, and run it on CI --- .travis.yml | 27 ++++++++++++++------------- xargo/Xargo.toml | 7 +++++-- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index bded347b825a..1be324cba35e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,20 +24,26 @@ before_script: script: - set -e - | - # get ourselves a MIR-ful libstd - xargo/build.sh -- | - # Test plain miri + # Test and install plain miri cargo build --release --all-features && RUST_BACKTRACE=1 cargo test --release --all-features --all && cargo install --all-features --force +- | + # test that the rustc_tests binary compiles + cd rustc_tests && + cargo build --release && + cd .. +- | + # get ourselves a MIR-full libstd + xargo/build.sh && + export MIRI_SYSROOT=~/.xargo/HOST - | # Test `cargo miri` cd cargo-miri-test && if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - MIRI_SYSROOT=~/.xargo/HOST cargo miri -q -- -Zmiri-start-fn + cargo miri -q -- -Zmiri-start-fn else - MIRI_SYSROOT=~/.xargo/HOST cargo miri -q -- -Zmiri-start-fn >stdout.real 2>stderr.real && + cargo miri -q -- -Zmiri-start-fn >stdout.real 2>stderr.real && cat stdout.real stderr.real && # Test `cargo miri` output. Not on mac because output redirecting doesn't # work. There is no error. It just stops CI. @@ -45,16 +51,11 @@ script: diff -u stderr.ref stderr.real fi && # Test `cargo miri test` - #cargo miri test && + cargo miri test && cd .. - | # and run all tests with full mir - MIRI_SYSROOT=~/.xargo/HOST cargo test --release -- | - # test that the rustc_tests binary compiles - cd rustc_tests && - cargo build --release && - cd .. + cargo test --release notifications: email: on_success: never diff --git a/xargo/Xargo.toml b/xargo/Xargo.toml index 4b650b97de56..c022837a5e61 100644 --- a/xargo/Xargo.toml +++ b/xargo/Xargo.toml @@ -1,2 +1,5 @@ -[dependencies] -std = {features = ["panic_unwind", "jemalloc", "backtrace"]} +[dependencies.std] +features = ["panic_unwind", "jemalloc", "backtrace"] + +[dependencies.test] +stage = 1 From c4c8c60279aa58616412289c0d832251b62d7ad3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 09:35:00 +0200 Subject: [PATCH 0170/5092] update README: 'cargo miri' with full MIR; consistent capitalization --- README.md | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index d14467be9144..314e27de0aa2 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ undergraduate research course at the [University of Saskatchewan][usask]. ## Building Miri -I recommend that you install [rustup][rustup] to obtain Rust. miri comes with a +I recommend that you install [rustup][rustup] to obtain Rust. Miri comes with a `rust-toolchain` file so rustup will automatically pick a suitable nightly version. Then all you have to do is: @@ -15,33 +15,25 @@ version. Then all you have to do is: cargo build ``` -## Running tests +## Running Miri ```sh cargo run tests/run-pass/vecs.rs # Or whatever test you like. ``` -## Running miri on your own project('s test suite) - -Install miri as a cargo subcommand with `cargo install --debug`. -Then, inside your own project, use `cargo +nightly miri` to run your project, if it is -a bin project, or run `cargo +nightly miri test` to run all tests in your project -through miri. - -## Running miri with full libstd +## Running Miri with full libstd Per default libstd does not contain the MIR of non-polymorphic functions. When -miri hits a call to such a function, execution terminates. To fix this, it is +Miri hits a call to such a function, execution terminates. To fix this, it is possible to compile libstd with full MIR: ```sh rustup component add rust-src cargo install xargo -cd xargo/ -RUSTFLAGS='-Zalways-encode-mir' xargo build +xargo/build.sh ``` -Now you can run miri against the libstd compiled by xargo: +Now you can run Miri against the libstd compiled by xargo: ```sh MIRI_SYSROOT=~/.xargo/HOST cargo run tests/run-pass-fullmir/hashmap.rs @@ -50,13 +42,23 @@ MIRI_SYSROOT=~/.xargo/HOST cargo run tests/run-pass-fullmir/hashmap.rs Notice that you will have to re-run the last step of the preparations above when your toolchain changes (e.g., when you update the nightly). -You can also set `-Zmiri-start-fn` to make miri start evaluation with the +You can also set `-Zmiri-start-fn` to make Miri start evaluation with the `start_fn` lang item, instead of starting at the `main` function. +## Running Miri on your own project('s test suite) + +Install Miri as a cargo subcommand with `cargo install --all-features`, and install +a full libstd as described above. + +Then, inside your own project, use `MIRI_SYSROOT=~/.xargo/HOST cargo +nightly +miri` to run your project, if it is a bin project, or run +`MIRI_SYSROOT=~/.xargo/HOST cargo +nightly miri test` to run all tests in your +project through Miri. + ## Development and Debugging -Since the heart of miri (the main interpreter engine) lives in rustc, working on -miri will often require using a locally built rustc. This includes getting a +Since the heart of Miri (the main interpreter engine) lives in rustc, working on +Miri will often require using a locally built rustc. This includes getting a trace of the execution, as distributed rustc has `trace!` disabled. The first-time setup for a local rustc looks as follows: @@ -68,12 +70,12 @@ cp config.toml.example config.toml ./x.py build src/rustc # You may have to change the architecture in the next command rustup toolchain link custom build/x86_64-unknown-linux-gnu/stage2 -# Now cd to your miri directory +# Now cd to your Miri directory rustup override set custom ``` The `build` step can take 30 minutes and more. -Now you can `cargo build` miri, and you can `cargo test --tests`. (`--tests` +Now you can `cargo build` Miri, and you can `cargo test --tests`. (`--tests` is needed to skip doctests because we have not built rustdoc for your custom toolchain.) You can also set `RUST_LOG=rustc_mir::interpret=trace` as environment variable to get a step-by-step trace. From ad5403e2e5d071583d741701f00f56e9a4336f1b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 15:58:29 +0200 Subject: [PATCH 0171/5092] fix layout in discriminant_value --- src/intrinsic.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index f31156a03e49..cd953ba7c569 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -250,8 +250,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let adt_align = self.layout_of(args[0].ty)?.align; let place = Place::from_scalar_ptr(adt_ptr, adt_align); let discr_val = self.read_discriminant_value(place, layout)?; - let ptr_size = self.memory.pointer_size(); - self.write_scalar(dest, Scalar::from_uint(discr_val, ptr_size), dest_layout.ty)?; + self.write_scalar(dest, Scalar::from_uint(discr_val, dest_layout.size), dest_layout.ty)?; } "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | From 30cef4e9a1fe0312803357f4141ceea8700c770b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 16:45:18 +0200 Subject: [PATCH 0172/5092] fix rustc_tests --- rustc_tests/Cargo.lock | 8 -------- rustc_tests/src/main.rs | 5 +++-- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/rustc_tests/Cargo.lock b/rustc_tests/Cargo.lock index 0154ecc2ccbd..c206ecd64492 100644 --- a/rustc_tests/Cargo.lock +++ b/rustc_tests/Cargo.lock @@ -51,11 +51,6 @@ name = "lazy_static" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "lazy_static" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "libc" version = "0.2.30" @@ -91,9 +86,7 @@ version = "0.1.0" dependencies = [ "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -226,7 +219,6 @@ dependencies = [ "checksum env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0e6e40ebb0e66918a37b38c7acab4e10d299e0463fe2af5d29b9cc86710cfd2a" "checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" "checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" -"checksum lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e6412c5e2ad9584b0b8e979393122026cdd6d2a80b933f890dcd694ddbe73739" "checksum libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)" = "2370ca07ec338939e356443dac2296f581453c35fe1e3a3ed06023c49435f915" "checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" diff --git a/rustc_tests/src/main.rs b/rustc_tests/src/main.rs index 1891e3dba103..969888ec991e 100644 --- a/rustc_tests/src/main.rs +++ b/rustc_tests/src/main.rs @@ -2,6 +2,7 @@ extern crate miri; extern crate getopts; extern crate rustc; +extern crate rustc_metadata; extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_codegen_utils; @@ -14,7 +15,7 @@ use std::io; use rustc::session::Session; -use rustc::middle::cstore::CrateStore; +use rustc_metadata::cstore::CStore; use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls}; use rustc_driver::driver::{CompileState, CompileController}; use rustc::session::config::{self, Input, ErrorOutputType}; @@ -56,7 +57,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { trans: &CodegenBackend, matches: &getopts::Matches, sess: &Session, - cstore: &CrateStore, + cstore: &CStore, input: &Input, odir: &Option, ofile: &Option, From 354ec11c3e1e29a2ee2241f74d8fcb4f5376b5d2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 17:19:46 +0200 Subject: [PATCH 0173/5092] try using types with lower alignment, maybe that helps for Windows --- tests/compile-fail/transmute_fat.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/compile-fail/transmute_fat.rs b/tests/compile-fail/transmute_fat.rs index dad5f4df2da3..3e3bf51c3f27 100644 --- a/tests/compile-fail/transmute_fat.rs +++ b/tests/compile-fail/transmute_fat.rs @@ -4,12 +4,12 @@ fn main() { #[cfg(target_pointer_width="64")] let bad = unsafe { - std::mem::transmute::<&[u8], u128>(&[1u8]) + std::mem::transmute::<&[u8], [u8; 16]>(&[1u8]) }; #[cfg(target_pointer_width="32")] let bad = unsafe { - std::mem::transmute::<&[u8], u64>(&[1u8]) + std::mem::transmute::<&[u8], [u8; 8]>(&[1u8]) }; - let _ = bad + 1; //~ ERROR constant evaluation error + let _ = bad[0] + bad[bad.len()-1]; //~ ERROR constant evaluation error //~^ NOTE a raw memory access tried to access part of a pointer value as raw bytes } From e10d83c8bb3436398ef47183e15d4ab3a2036547 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 18:44:31 +0200 Subject: [PATCH 0174/5092] fix windows hooks --- src/fn_call.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 11b0ae345c7f..b475837a6e52 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -634,14 +634,16 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let ptr_size = self.memory.pointer_size(); self.write_scalar(dest, Scalar::from_int(1, ptr_size), dest_ty)?; }, - "GetModuleHandleW" | - "GetProcAddress" | "InitializeCriticalSection" | "EnterCriticalSection" | - "TryEnterCriticalSection" | "LeaveCriticalSection" | "DeleteCriticalSection" | "SetLastError" => { + // Function does not return anything, nothing to do + }, + "GetModuleHandleW" | + "GetProcAddress" | + "TryEnterCriticalSection" => { // pretend these do not exist/nothing happened, by returning zero let ptr_size = self.memory.pointer_size(); self.write_scalar(dest, Scalar::from_int(0, ptr_size), dest_ty)?; From 7c73df9985871a5a76c55d48f1dc0797111181be Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 17:21:02 +0200 Subject: [PATCH 0175/5092] avoid recompiling miri for 2nd test run; avoid unreadable output due to backtraces also some travis config cleanup --- .travis.yml | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1be324cba35e..7f346b5104c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,32 +1,32 @@ language: rust cache: cargo - -os: -- osx -- linux - rust: - nightly + +os: +- linux +- osx + before_script: # mac os weirdness (https://github.com/travis-ci/travis-ci/issues/6307) - curl -sSL https://rvm.io/mpapis.asc | gpg --import - - rvm get stable # in a cronjob, use latest (not pinned) nightly - if [ "$TRAVIS_EVENT_TYPE" = cron ]; then rustup override set nightly; fi -# actual travis code +# prepare - export PATH=$HOME/.local/bin:$PATH - rustup target add i686-unknown-linux-gnu - rustup target add i686-pc-windows-gnu - rustup target add i686-pc-windows-msvc - rustup component add rust-src - cargo install xargo || echo "skipping xargo install" -- export RUST_SYSROOT=$HOME/rust + script: - set -e - | # Test and install plain miri cargo build --release --all-features && - RUST_BACKTRACE=1 cargo test --release --all-features --all && + cargo test --release --all-features && cargo install --all-features --force - | # test that the rustc_tests binary compiles @@ -55,7 +55,8 @@ script: cd .. - | # and run all tests with full mir - cargo test --release + cargo test --release --all-features + notifications: email: on_success: never From 1fbf998b652af1c3e1cf888a9dfceb9eaeecc475 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 19:00:18 +0200 Subject: [PATCH 0176/5092] Fix remaining windows hooks --- appveyor.yml | 2 +- src/fn_call.rs | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 6aee7e75a956..14532416978c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -26,12 +26,12 @@ install: - cd xargo - set RUSTFLAGS=-Zalways-encode-mir -Zmir-emit-validate=1 - xargo build - - set RUSTFLAGS= - cd .. build: false test_script: + - set RUSTFLAGS=-g - set RUST_BACKTRACE=1 - cargo build --release - cargo test --release diff --git a/src/fn_call.rs b/src/fn_call.rs index b475837a6e52..509119beb35c 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -645,13 +645,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "GetProcAddress" | "TryEnterCriticalSection" => { // pretend these do not exist/nothing happened, by returning zero - let ptr_size = self.memory.pointer_size(); - self.write_scalar(dest, Scalar::from_int(0, ptr_size), dest_ty)?; + self.write_scalar(dest, Scalar::from_int(0, dest_layout.size), dest_ty)?; }, "GetLastError" => { // this is c::ERROR_CALL_NOT_IMPLEMENTED - let ptr_size = self.memory.pointer_size(); - self.write_scalar(dest, Scalar::from_int(120, ptr_size), dest_ty)?; + self.write_scalar(dest, Scalar::from_int(120, dest_layout.size), dest_ty)?; }, // Windows TLS @@ -665,8 +663,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' if dest_layout.size.bits() < 128 && key >= (1u128 << dest_layout.size.bits() as u128) { return err!(OutOfTls); } - let ptr_size = self.memory.pointer_size(); - self.write_scalar(dest, Scalar::from_uint(key, ptr_size), dest_layout.ty)?; + self.write_scalar(dest, Scalar::from_uint(key, dest_layout.size), dest_layout.ty)?; } "TlsGetValue" => { let key = self.value_to_scalar(args[0])?.to_bytes()?; @@ -677,10 +674,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let key = self.value_to_scalar(args[0])?.to_bytes()?; let new_ptr = self.into_ptr(args[1].value)?.unwrap_or_err()?; self.memory.store_tls(key, new_ptr)?; - let ptr_size = self.memory.pointer_size(); // Return success (1) - self.write_scalar(dest, Scalar::from_int(1, ptr_size), dest_ty)?; + self.write_scalar(dest, Scalar::from_int(1, dest_layout.size), dest_ty)?; } // We can't execute anything else From 93fef9a6a2958a0cef2cef64afd1ffa478aef5fe Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 09:51:31 +0200 Subject: [PATCH 0177/5092] reenable an old test --- tests/run-pass/intrinsics.rs | 0 tests/run-pass/{packed_struct.rs_broken => packed_struct.rs} | 2 -- 2 files changed, 2 deletions(-) mode change 100755 => 100644 tests/run-pass/intrinsics.rs rename tests/run-pass/{packed_struct.rs_broken => packed_struct.rs} (91%) diff --git a/tests/run-pass/intrinsics.rs b/tests/run-pass/intrinsics.rs old mode 100755 new mode 100644 diff --git a/tests/run-pass/packed_struct.rs_broken b/tests/run-pass/packed_struct.rs similarity index 91% rename from tests/run-pass/packed_struct.rs_broken rename to tests/run-pass/packed_struct.rs index e0387a5f405f..7bd04c44438c 100644 --- a/tests/run-pass/packed_struct.rs_broken +++ b/tests/run-pass/packed_struct.rs @@ -1,5 +1,3 @@ -// FIXME: We have to disable this, force_allocation fails. -// TODO: I think this can be triggered even without validation. // compile-flags: -Zmir-emit-validate=0 #![allow(dead_code)] #![feature(unsize, coerce_unsized)] From 2b40d39c1e26c0964180fde51c5bfcf9247a70a8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 20:00:18 +0200 Subject: [PATCH 0178/5092] support computing the remainder of a ptr, if covered by alignment --- src/operator.rs | 25 ++++++++++++++++++++--- tests/compile-fail/pointer_byte_read_1.rs | 2 +- tests/compile-fail/ptr_bitops2.rs | 5 +++++ tests/compile-fail/ptr_rem.rs | 5 +++++ tests/run-pass/ptr_int_ops.rs | 20 ++++++++++++++++++ 5 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 tests/compile-fail/ptr_bitops2.rs create mode 100644 tests/compile-fail/ptr_rem.rs create mode 100644 tests/run-pass/ptr_int_ops.rs diff --git a/src/operator.rs b/src/operator.rs index 7be77771a7ca..ab1701c6cbf1 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -130,8 +130,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: err!(InvalidPointerMath) } } - // These work if one operand is a pointer, the other an integer - Add | BitAnd | Sub + // These work if the left operand is a pointer, the right an integer + Add | BitAnd | Sub | Rem if left_kind == right_kind && (left_kind == usize || left_kind == isize) && left.is_ptr() && right.is_bits() => { // Cast to i128 is fine as we checked the kind to be ptr-sized @@ -142,6 +142,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: left_kind == isize, ).map(Some) } + // Commutative operators also work if the integer is on the left Add | BitAnd if left_kind == right_kind && (left_kind == usize || left_kind == isize) && left.is_bits() && right.is_ptr() => { @@ -180,7 +181,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: map_to_primval(left.overflowing_offset(Size::from_bytes(right as u64), self)), BitAnd if !signed => { - let base_mask : u64 = !(self.memory.get(left.alloc_id)?.align.abi() - 1); + let ptr_base_align = self.memory.get(left.alloc_id)?.align.abi(); + let base_mask : u64 = !(ptr_base_align - 1); let right = right as u64; let ptr_size = self.memory.pointer_size().bytes() as u8; if right & base_mask == base_mask { @@ -194,6 +196,23 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } } + Rem if !signed => { + // Doing modulo a multiple of the alignment is allowed + let ptr_base_align = self.memory.get(left.alloc_id)?.align.abi(); + let right = right as u64; + let ptr_size = self.memory.pointer_size().bytes() as u8; + if right == 1 { + // modulo 1 is always 0 + (Scalar::Bits { bits: 0, size: ptr_size }, false) + } else if right % ptr_base_align == 0 { + // the base address would be cancelled out by the modulo operation, so we can + // just take the modulo of the offset + (Scalar::Bits { bits: (left.offset.bytes() % right) as u128, size: ptr_size }, false) + } else { + return err!(ReadPointerAsBytes); + } + } + _ => { let msg = format!("unimplemented binary op on pointer {:?}: {:?}, {:?} ({})", bin_op, left, right, if signed { "signed" } else { "unsigned" }); return err!(Unimplemented(msg)); diff --git a/tests/compile-fail/pointer_byte_read_1.rs b/tests/compile-fail/pointer_byte_read_1.rs index b3aaec759ce0..4cfdfb62e27f 100644 --- a/tests/compile-fail/pointer_byte_read_1.rs +++ b/tests/compile-fail/pointer_byte_read_1.rs @@ -3,6 +3,6 @@ fn main() { let y = &x; let z = &y as *const &i32 as *const usize; let ptr_bytes = unsafe { *z }; // the actual deref is fine, because we read the entire pointer at once - let _ = ptr_bytes % 432; //~ ERROR constant evaluation error + let _ = ptr_bytes / 432; //~ ERROR constant evaluation error //~^ NOTE tried to access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/ptr_bitops2.rs b/tests/compile-fail/ptr_bitops2.rs new file mode 100644 index 000000000000..233c9a733c99 --- /dev/null +++ b/tests/compile-fail/ptr_bitops2.rs @@ -0,0 +1,5 @@ +fn main() { + let val = 13usize; + let addr = &val as *const _ as usize; + let _ = addr & 13; //~ ERROR access part of a pointer value as raw bytes +} diff --git a/tests/compile-fail/ptr_rem.rs b/tests/compile-fail/ptr_rem.rs new file mode 100644 index 000000000000..26fba9b82c53 --- /dev/null +++ b/tests/compile-fail/ptr_rem.rs @@ -0,0 +1,5 @@ +fn main() { + let val = 13usize; + let addr = &val as *const _ as usize; + let _ = addr % 2; //~ ERROR access part of a pointer value as raw bytes +} diff --git a/tests/run-pass/ptr_int_ops.rs b/tests/run-pass/ptr_int_ops.rs new file mode 100644 index 000000000000..9a29c2d30837 --- /dev/null +++ b/tests/run-pass/ptr_int_ops.rs @@ -0,0 +1,20 @@ +fn main() { + let v = [1i16, 2]; + let x = &v[1] as *const i16 as usize; + // arithmetic + let _y = x + 4; + let _y = 4 + x; + let _y = x - 2; + // bit-operations, covered by alignment + assert_eq!(x & 1, 0); + assert_eq!(x & 0, 0); + assert_eq!(1 & (x+1), 1); + let _y = !1 & x; + let _y = !0 & x; + let _y = x & !1; + // remainder, covered by alignment + assert_eq!(x % 2, 0); + assert_eq!((x+1) % 2, 1); + // remainder with 1 is always 0 + assert_eq!(x % 1, 0); +} From 04b925135d2e2078340618c7fae1ac776b9d9028 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 12:16:29 +0200 Subject: [PATCH 0179/5092] fix modulo logic --- src/operator.rs | 5 +++-- tests/compile-fail/ptr_rem.rs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index ab1701c6cbf1..ef297397fc5e 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -197,14 +197,15 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } Rem if !signed => { - // Doing modulo a multiple of the alignment is allowed + // Doing modulo a divisor of the alignment is allowed. + // (Intuition: Modulo a divisor leaks less information.) let ptr_base_align = self.memory.get(left.alloc_id)?.align.abi(); let right = right as u64; let ptr_size = self.memory.pointer_size().bytes() as u8; if right == 1 { // modulo 1 is always 0 (Scalar::Bits { bits: 0, size: ptr_size }, false) - } else if right % ptr_base_align == 0 { + } else if ptr_base_align % right == 0 { // the base address would be cancelled out by the modulo operation, so we can // just take the modulo of the offset (Scalar::Bits { bits: (left.offset.bytes() % right) as u128, size: ptr_size }, false) diff --git a/tests/compile-fail/ptr_rem.rs b/tests/compile-fail/ptr_rem.rs index 26fba9b82c53..8a3665872f7c 100644 --- a/tests/compile-fail/ptr_rem.rs +++ b/tests/compile-fail/ptr_rem.rs @@ -1,5 +1,5 @@ fn main() { let val = 13usize; let addr = &val as *const _ as usize; - let _ = addr % 2; //~ ERROR access part of a pointer value as raw bytes + let _ = addr % 16; //~ ERROR access part of a pointer value as raw bytes } From bfda0a0a90bc37f683e99bbff75fbf59abe48991 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 18:51:15 +0200 Subject: [PATCH 0180/5092] add a scary test case --- tests/run-pass/transmute_fat.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 tests/run-pass/transmute_fat.rs diff --git a/tests/run-pass/transmute_fat.rs b/tests/run-pass/transmute_fat.rs new file mode 100644 index 000000000000..ec887902d054 --- /dev/null +++ b/tests/run-pass/transmute_fat.rs @@ -0,0 +1,10 @@ +fn main() { + // If we are careful, we can exploit data layout... + let raw = unsafe { + std::mem::transmute::<&[u8], [usize; 2]>(&[42]) + }; + let ptr = raw[0] + raw[1]; + let ptr = ptr as *const u8; + // The pointer is one-past-the end, but we decrement it into bounds before using it + assert_eq!(unsafe { *ptr.offset(-1) }, 42); +} From 98a5b24ef7eb05ae52d63ce9e050d6ac144ba345 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 20:09:07 +0200 Subject: [PATCH 0181/5092] test some more things around packed structs --- tests/run-pass/dst-struct.rs | 4 ++-- tests/run-pass/packed_struct.rs | 39 +++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/dst-struct.rs b/tests/run-pass/dst-struct.rs index 932b571eccdb..0820614ab5c8 100644 --- a/tests/run-pass/dst-struct.rs +++ b/tests/run-pass/dst-struct.rs @@ -65,9 +65,9 @@ impl ToBar for Bar { pub fn main() { // With a vec of ints. - let f1 = Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + let f1 : Fat<[isize; 3]> = Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; foo(&f1); - let f2 = &f1; + let f2 : &Fat<[isize; 3]> = &f1; foo(f2); let f3: &Fat<[isize]> = f2; foo(f3); diff --git a/tests/run-pass/packed_struct.rs b/tests/run-pass/packed_struct.rs index 7bd04c44438c..e10781e65605 100644 --- a/tests/run-pass/packed_struct.rs +++ b/tests/run-pass/packed_struct.rs @@ -45,6 +45,43 @@ fn test_unsizing() { let _unused = &arr_unaligned; // forcing an allocation, which could also yield "unaligned write"-errors } +fn test_drop() { + struct Wrap(u32); + impl Drop for Wrap { + fn drop(&mut self) { + // Do an (aligned) load + let _test = self.0; + // For the fun of it, test alignment + assert_eq!(&self.0 as *const _ as usize % std::mem::align_of::(), 0); + } + } + + #[repr(packed,C)] + struct Packed { + f1: u8, // this should move the second field to something not very aligned + f2: T, + } + + let p = Packed { f1: 42, f2: Wrap(23) }; + drop(p); +} + +fn test_inner_packed() { + // Even if just the inner struct is packed, accesses to the outer field can get unaligned. + // Make sure that works. + #[repr(packed)] + #[derive(Clone,Copy)] + struct Inner(u32); + + #[derive(Clone,Copy)] + struct Outer(u8, Inner); + + let o = Outer(0, Inner(42)); + let _x = o.1; + let _y = (o.1).0; + let _o2 = o.clone(); +} + fn main() { let mut x = S { a: 42, @@ -64,4 +101,6 @@ fn main() { test(Test2 { x: 0, other: &Test1 { x: 0, other: &42 }}); test_unsizing(); + test_drop(); + test_inner_packed(); } From 1179d4f8a4286f8ad0555b56ce65871f242a5d5b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 20:25:56 +0200 Subject: [PATCH 0182/5092] fix int ptr ops on 32bit --- src/operator.rs | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index ef297397fc5e..078cbc12369f 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -20,7 +20,7 @@ pub trait EvalContextExt<'tcx> { &self, bin_op: mir::BinOp, left: Pointer, - right: i128, + right: u128, signed: bool, ) -> EvalResult<'tcx, (Scalar, bool)>; } @@ -138,7 +138,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: self.ptr_int_arithmetic( bin_op, left.to_ptr()?, - right.to_bits(self.memory.pointer_size())? as i128, + right.to_bits(self.memory.pointer_size())?, left_kind == isize, ).map(Some) } @@ -150,7 +150,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: self.ptr_int_arithmetic( bin_op, right.to_ptr()?, - left.to_bits(self.memory.pointer_size())? as i128, + left.to_bits(self.memory.pointer_size())?, left_kind == isize, ).map(Some) } @@ -162,7 +162,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: &self, bin_op: mir::BinOp, left: Pointer, - right: i128, + right: u128, signed: bool, ) -> EvalResult<'tcx, (Scalar, bool)> { use rustc::mir::BinOp::*; @@ -174,23 +174,31 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Ok(match bin_op { Sub => // The only way this can overflow is by underflowing, so signdeness of the right operands does not matter - map_to_primval(left.overflowing_signed_offset(-right, self)), + map_to_primval(left.overflowing_signed_offset(-(right as i128), self)), Add if signed => - map_to_primval(left.overflowing_signed_offset(right, self)), + map_to_primval(left.overflowing_signed_offset(right as i128, self)), Add if !signed => map_to_primval(left.overflowing_offset(Size::from_bytes(right as u64), self)), BitAnd if !signed => { let ptr_base_align = self.memory.get(left.alloc_id)?.align.abi(); - let base_mask : u64 = !(ptr_base_align - 1); - let right = right as u64; + let base_mask = { + // FIXME: Use interpret::truncate, once that takes a Size instead of a Layout + let shift = 128 - self.memory.pointer_size().bits(); + let value = !(ptr_base_align as u128 - 1); + // truncate (shift left to drop out leftover values, shift right to fill with zeroes) + (value << shift) >> shift + }; let ptr_size = self.memory.pointer_size().bytes() as u8; + trace!("Ptr BitAnd, align {}, operand {:#010x}, base_mask {:#010x}", + ptr_base_align, right, base_mask); if right & base_mask == base_mask { // Case 1: The base address bits are all preserved, i.e., right is all-1 there - (Scalar::Ptr(Pointer::new(left.alloc_id, Size::from_bytes(left.offset.bytes() & right))), false) + let offset = (left.offset.bytes() as u128 & right) as u64; + (Scalar::Ptr(Pointer::new(left.alloc_id, Size::from_bytes(offset))), false) } else if right & base_mask == 0 { // Case 2: The base address bits are all taken away, i.e., right is all-0 there - (Scalar::Bits { bits: (left.offset.bytes() & right) as u128, size: ptr_size }, false) + (Scalar::Bits { bits: (left.offset.bytes() as u128) & right, size: ptr_size }, false) } else { return err!(ReadPointerAsBytes); } From 51dbb5aa29f2ba8f0e694291299be1c22c5e6419 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 20:57:58 +0200 Subject: [PATCH 0183/5092] tweak test config in Cargo.toml --- Cargo.toml | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7773bd3812f1..3f7aabe03ce2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,15 +10,19 @@ version = "0.1.0" build = "build.rs" default-run = "miri" -[[bin]] -doc = false -name = "miri" -path = "src/bin/miri.rs" +[lib] +test = true # we have unit tests +doctest = false # but no doc tests + +[[bin]] +name = "miri" +test = false # we have no unit tests +doctest = false # and no doc tests [[bin]] -doc = false name = "cargo-miri" -path = "src/bin/cargo-miri.rs" +test = false # we have no unit tests +doctest = false # and no doc tests required-features = ["cargo_miri"] [dependencies] From 259cc6e3dccdf7dd7f9c8e2052c6dea19fe066d9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 Aug 2018 21:01:40 +0200 Subject: [PATCH 0184/5092] rustup for big refactor; kill most of validation --- src/fn_call.rs | 295 ++++---- src/helpers.rs | 227 +++--- src/intrinsic.rs | 474 ++++++------- src/lib.rs | 226 ++---- src/locks.rs | 320 +-------- src/operator.rs | 83 ++- src/range_map.rs | 2 + src/tls.rs | 6 +- src/validation.rs | 803 ---------------------- tests/run-pass/atomic-compare_exchange.rs | 18 +- 10 files changed, 576 insertions(+), 1878 deletions(-) delete mode 100644 src/validation.rs diff --git a/src/fn_call.rs b/src/fn_call.rs index 509119beb35c..559f3adb90f1 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -1,8 +1,7 @@ -use rustc::ty::{self, Ty}; -use rustc::ty::layout::{self, Align, LayoutOf, Size}; +use rustc::ty; +use rustc::ty::layout::{Align, LayoutOf, Size}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; -use rustc_data_structures::indexed_vec::Idx; use syntax::attr; use syntax::codemap::Span; @@ -14,57 +13,12 @@ use tls::MemoryExt; use super::memory::MemoryKind; -fn write_discriminant_value<'a, 'mir, 'tcx: 'a + 'mir>( - ecx: &mut EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>>, - dest_ty: Ty<'tcx>, - dest: Place, - variant_index: usize, - ) -> EvalResult<'tcx> { - let layout = ecx.layout_of(dest_ty)?; - - match layout.variants { - layout::Variants::Single { index } => { - if index != variant_index { - // If the layout of an enum is `Single`, all - // other variants are necessarily uninhabited. - assert_eq!(layout.for_variant(&ecx, variant_index).abi, - layout::Abi::Uninhabited); - } - } - layout::Variants::Tagged { .. } => { - let discr_val = dest_ty.ty_adt_def().unwrap() - .discriminant_for_variant(*ecx.tcx, variant_index) - .val; - - let (discr_dest, discr) = ecx.place_field(dest, mir::Field::new(0), layout)?; - ecx.write_scalar(discr_dest, Scalar::from_uint(discr_val, discr.size), discr.ty)?; - } - layout::Variants::NicheFilling { - dataful_variant, - ref niche_variants, - niche_start, - .. - } => { - if variant_index != dataful_variant { - let (niche_dest, niche) = - ecx.place_field(dest, mir::Field::new(0), layout)?; - let niche_value = ((variant_index - niche_variants.start()) as u128) - .wrapping_add(niche_start); - ecx.write_scalar(niche_dest, Scalar::from_uint(niche_value, niche.size), niche.ty)?; - } - } - } - - Ok(()) - } - pub trait EvalContextExt<'tcx> { fn call_foreign_item( &mut self, def_id: DefId, - args: &[ValTy<'tcx>], - dest: Place, - dest_ty: Ty<'tcx>, + args: &[OpTy<'tcx>], + dest: PlaceTy<'tcx>, dest_block: mir::BasicBlock, ) -> EvalResult<'tcx>; @@ -73,49 +27,46 @@ pub trait EvalContextExt<'tcx> { fn call_missing_fn( &mut self, instance: ty::Instance<'tcx>, - destination: Option<(Place, mir::BasicBlock)>, - args: &[ValTy<'tcx>], - sig: ty::FnSig<'tcx>, + destination: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, + args: &[OpTy<'tcx>], path: String, ) -> EvalResult<'tcx>; fn eval_fn_call( &mut self, instance: ty::Instance<'tcx>, - destination: Option<(Place, mir::BasicBlock)>, - args: &[ValTy<'tcx>], + destination: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, + args: &[OpTy<'tcx>], span: Span, - sig: ty::FnSig<'tcx>, ) -> EvalResult<'tcx, bool>; - fn write_null(&mut self, dest: Place, dest_layout: TyLayout<'tcx>) -> EvalResult<'tcx>; + fn write_null(&mut self, dest: PlaceTy<'tcx>) -> EvalResult<'tcx>; } impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { fn eval_fn_call( &mut self, instance: ty::Instance<'tcx>, - destination: Option<(Place, mir::BasicBlock)>, - args: &[ValTy<'tcx>], + destination: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, + args: &[OpTy<'tcx>], span: Span, - sig: ty::FnSig<'tcx>, ) -> EvalResult<'tcx, bool> { - trace!("eval_fn_call: {:#?}, {:#?}", instance, destination); + trace!("eval_fn_call: {:#?}, {:?}", instance, destination.map(|(place, bb)| (*place, bb))); let def_id = instance.def_id(); let item_path = self.tcx.absolute_item_path_str(def_id); match &*item_path { "std::sys::unix::thread::guard::init" | "std::sys::unix::thread::guard::current" => { // Return None, as it doesn't make sense to return Some, because miri detects stack overflow itself. - let ret_ty = sig.output(); - match ret_ty.sty { + let (return_place, return_to_block) = destination.unwrap(); + match return_place.layout.ty.sty { ty::TyAdt(ref adt_def, _) => { assert!(adt_def.is_enum(), "Unexpected return type for {}", item_path); let none_variant_index = adt_def.variants.iter().position(|def| { def.name.as_str() == "None" }).expect("No None variant"); - let (return_place, return_to_block) = destination.unwrap(); - write_discriminant_value(self, ret_ty, return_place, none_variant_index)?; + + self.write_discriminant_value(none_variant_index, return_place)?; self.goto_block(return_to_block); return Ok(true); } @@ -135,11 +86,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // FIXME: return a real value in case the target allocation has an // alignment bigger than the one requested let n = u128::max_value(); - let amt = 128 - self.memory.pointer_size().bytes() * 8; let (dest, return_to_block) = destination.unwrap(); - let ty = self.tcx.types.usize; - let ptr_size = self.memory.pointer_size(); - self.write_scalar(dest, Scalar::from_uint((n << amt) >> amt, ptr_size), ty)?; + let n = self.truncate(n, dest.layout); + self.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; self.goto_block(return_to_block); return Ok(true); } @@ -151,7 +100,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' instance, destination, args, - sig, path, )?; return Ok(true); @@ -160,8 +108,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' }; let (return_place, return_to_block) = match destination { - Some((place, block)) => (place, StackPopCleanup::Goto(block)), - None => (Place::undef(), StackPopCleanup::None), + Some((place, block)) => (*place, StackPopCleanup::Goto(block)), + None => (Place::null(&self), StackPopCleanup::None), }; self.push_stack_frame( @@ -178,9 +126,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' fn call_foreign_item( &mut self, def_id: DefId, - args: &[ValTy<'tcx>], - dest: Place, - dest_ty: Ty<'tcx>, + args: &[OpTy<'tcx>], + dest: PlaceTy<'tcx>, dest_block: mir::BasicBlock, ) -> EvalResult<'tcx> { let attrs = self.tcx.get_attrs(def_id); @@ -188,22 +135,21 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Some(name) => name.as_str(), None => self.tcx.item_name(def_id).as_str(), }; - let dest_layout = self.layout_of(dest_ty)?; match &link_name[..] { "malloc" => { - let size = self.value_to_scalar(args[0])?.to_usize(self)?; + let size = self.read_scalar(args[0])?.to_usize(&self)?; if size == 0 { - self.write_null(dest, dest_layout)?; + self.write_null(dest)?; } else { let align = self.tcx.data_layout.pointer_align; let ptr = self.memory.allocate(Size::from_bytes(size), align, MemoryKind::C.into())?; - self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; + self.write_scalar(Scalar::Ptr(ptr), dest)?; } } "free" => { - let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; + let ptr = self.read_scalar(args[0])?.not_undef()?; if !ptr.is_null() { self.memory.deallocate( ptr.to_ptr()?, @@ -214,8 +160,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "__rust_alloc" => { - let size = self.value_to_scalar(args[0])?.to_usize(self)?; - let align = self.value_to_scalar(args[1])?.to_usize(self)?; + let size = self.read_scalar(args[0])?.to_usize(&self)?; + let align = self.read_scalar(args[1])?.to_usize(&self)?; if size == 0 { return err!(HeapAllocZeroBytes); } @@ -225,11 +171,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let ptr = self.memory.allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), MemoryKind::Rust.into())?; - self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; + self.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_alloc_zeroed" => { - let size = self.value_to_scalar(args[0])?.to_usize(self)?; - let align = self.value_to_scalar(args[1])?.to_usize(self)?; + let size = self.read_scalar(args[0])?.to_usize(&self)?; + let align = self.read_scalar(args[1])?.to_usize(&self)?; if size == 0 { return err!(HeapAllocZeroBytes); } @@ -240,12 +186,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Align::from_bytes(align, align).unwrap(), MemoryKind::Rust.into())?; self.memory.write_repeat(ptr.into(), 0, Size::from_bytes(size))?; - self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; + self.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_dealloc" => { - let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?.to_ptr()?; - let old_size = self.value_to_scalar(args[1])?.to_usize(self)?; - let align = self.value_to_scalar(args[2])?.to_usize(self)?; + let ptr = self.read_scalar(args[0])?.to_ptr()?; + let old_size = self.read_scalar(args[1])?.to_usize(&self)?; + let align = self.read_scalar(args[2])?.to_usize(&self)?; if old_size == 0 { return err!(HeapAllocZeroBytes); } @@ -259,10 +205,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' )?; } "__rust_realloc" => { - let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?.to_ptr()?; - let old_size = self.value_to_scalar(args[1])?.to_usize(self)?; - let align = self.value_to_scalar(args[2])?.to_usize(self)?; - let new_size = self.value_to_scalar(args[3])?.to_usize(self)?; + let ptr = self.read_scalar(args[0])?.to_ptr()?; + let old_size = self.read_scalar(args[1])?.to_usize(&self)?; + let align = self.read_scalar(args[2])?.to_usize(&self)?; + let new_size = self.read_scalar(args[3])?.to_usize(&self)?; if old_size == 0 || new_size == 0 { return err!(HeapAllocZeroBytes); } @@ -277,7 +223,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Align::from_bytes(align, align).unwrap(), MemoryKind::Rust.into(), )?; - self.write_scalar(dest, Scalar::Ptr(new_ptr), dest_ty)?; + self.write_scalar(Scalar::Ptr(new_ptr), dest)?; } "syscall" => { @@ -286,7 +232,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // // libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK) // is called if a `HashMap` is created the regular way. - match self.value_to_scalar(args[0])?.to_usize(self)? { + match self.read_scalar(args[0])?.to_usize(&self)? { 318 | 511 => { return err!(Unimplemented( "miri does not support random number generators".to_owned(), @@ -301,8 +247,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "dlsym" => { - let _handle = self.into_ptr(args[0].value)?; - let symbol = self.into_ptr(args[1].value)?.unwrap_or_err()?.to_ptr()?; + let _handle = self.read_scalar(args[0])?; + let symbol = self.read_scalar(args[1])?.to_ptr()?; let symbol_name = self.memory.read_c_str(symbol)?; let err = format!("bad c unicode symbol: {:?}", symbol_name); let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err); @@ -315,20 +261,20 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "__rust_maybe_catch_panic" => { // fn __rust_maybe_catch_panic(f: fn(*mut u8), data: *mut u8, data_ptr: *mut usize, vtable_ptr: *mut usize) -> u32 // We abort on panic, so not much is going on here, but we still have to call the closure - let u8_ptr_ty = self.tcx.mk_mut_ptr(self.tcx.types.u8); - let f = self.into_ptr(args[0].value)?.unwrap_or_err()?.to_ptr()?; - let data = self.into_ptr(args[1].value)?.unwrap_or_err()?; + let f = self.read_scalar(args[0])?.to_ptr()?; + let data = self.read_scalar(args[1])?.not_undef()?; let f_instance = self.memory.get_fn(f)?; - self.write_null(dest, dest_layout)?; + self.write_null(dest)?; // Now we make a function call. TODO: Consider making this re-usable? EvalContext::step does sth. similar for the TLS dtors, // and of course eval_main. let mir = self.load_mir(f_instance.def)?; + let ret = Place::null(&self); self.push_stack_frame( f_instance, mir.span, mir, - Place::undef(), + ret, StackPopCleanup::Goto(dest_block), )?; let mut args = self.frame().mir.args_iter(); @@ -340,12 +286,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' ), )?; let arg_dest = self.eval_place(&mir::Place::Local(arg_local))?; - self.write_ptr(arg_dest, data, u8_ptr_ty)?; + self.write_scalar(data, arg_dest)?; assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected"); // We ourselves return 0 - self.write_null(dest, dest_layout)?; + self.write_null(dest)?; // Don't fall through return Ok(()); @@ -356,9 +302,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "memcmp" => { - let left = self.into_ptr(args[0].value)?.unwrap_or_err()?; - let right = self.into_ptr(args[1].value)?.unwrap_or_err()?; - let n = Size::from_bytes(self.value_to_scalar(args[2])?.to_usize(self)?); + let left = self.read_scalar(args[0])?.not_undef()?; + let right = self.read_scalar(args[1])?.not_undef()?; + let n = Size::from_bytes(self.read_scalar(args[2])?.to_usize(&self)?); let result = { let left_bytes = self.memory.read_bytes(left, n)?; @@ -373,58 +319,57 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' }; self.write_scalar( - dest, Scalar::from_i32(result), - dest_ty, + dest, )?; } "memrchr" => { - let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; - let val = self.value_to_scalar(args[1])?.to_bytes()? as u8; - let num = self.value_to_scalar(args[2])?.to_usize(self)?; + let ptr = self.read_scalar(args[0])?.not_undef()?; + let val = self.read_scalar(args[1])?.to_bytes()? as u8; + let num = self.read_scalar(args[2])?.to_usize(&self)?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().rev().position( |&c| c == val, ) { let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), &self)?; - self.write_ptr(dest, new_ptr, dest_ty)?; + self.write_scalar(new_ptr, dest)?; } else { - self.write_null(dest, dest_layout)?; + self.write_null(dest)?; } } "memchr" => { - let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; - let val = self.value_to_scalar(args[1])?.to_bytes()? as u8; - let num = self.value_to_scalar(args[2])?.to_usize(self)?; + let ptr = self.read_scalar(args[0])?.not_undef()?; + let val = self.read_scalar(args[1])?.to_bytes()? as u8; + let num = self.read_scalar(args[2])?.to_usize(&self)?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().position( |&c| c == val, ) { let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), &self)?; - self.write_ptr(dest, new_ptr, dest_ty)?; + self.write_scalar(new_ptr, dest)?; } else { - self.write_null(dest, dest_layout)?; + self.write_null(dest)?; } } "getenv" => { let result = { - let name_ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?.to_ptr()?; + let name_ptr = self.read_scalar(args[0])?.to_ptr()?; let name = self.memory.read_c_str(name_ptr)?; match self.machine.env_vars.get(name) { Some(&var) => Scalar::Ptr(var), None => Scalar::null(self.memory.pointer_size()), } }; - self.write_scalar(dest, result, dest_ty)?; + self.write_scalar(result, dest)?; } "unsetenv" => { let mut success = None; { - let name_ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; + let name_ptr = self.read_scalar(args[0])?.not_undef()?; if !name_ptr.is_null() { let name = self.memory.read_c_str(name_ptr.to_ptr()?)?; if !name.is_empty() && !name.contains(&b'=') { @@ -436,17 +381,17 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' if let Some(var) = old { self.memory.deallocate(var, None, MemoryKind::Env.into())?; } - self.write_null(dest, dest_layout)?; + self.write_null(dest)?; } else { - self.write_scalar(dest, Scalar::from_int(-1, dest_layout.size), dest_ty)?; + self.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; } } "setenv" => { let mut new = None; { - let name_ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; - let value_ptr = self.into_ptr(args[1].value)?.unwrap_or_err()?.to_ptr()?; + let name_ptr = self.read_scalar(args[0])?.not_undef()?; + let value_ptr = self.read_scalar(args[1])?.to_ptr()?; let value = self.memory.read_c_str(value_ptr)?; if !name_ptr.is_null() { let name = self.memory.read_c_str(name_ptr.to_ptr()?)?; @@ -472,16 +417,16 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' { self.memory.deallocate(var, None, MemoryKind::Env.into())?; } - self.write_null(dest, dest_layout)?; + self.write_null(dest)?; } else { - self.write_scalar(dest, Scalar::from_int(-1, dest_layout.size), dest_ty)?; + self.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; } } "write" => { - let fd = self.value_to_scalar(args[0])?.to_bytes()?; - let buf = self.into_ptr(args[1].value)?.unwrap_or_err()?; - let n = self.value_to_scalar(args[2])?.to_bytes()? as u64; + let fd = self.read_scalar(args[0])?.to_bytes()?; + let buf = self.read_scalar(args[1])?.not_undef()?; + let n = self.read_scalar(args[2])?.to_bytes()? as u64; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { // stdout/stderr @@ -501,36 +446,31 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' warn!("Ignored output to FD {}", fd); n as i64 // pretend it all went well }; // now result is the value we return back to the program - let ptr_size = self.memory.pointer_size(); self.write_scalar( + Scalar::from_int(result, dest.layout.size), dest, - Scalar::from_int(result, ptr_size), - dest_ty, )?; } "strlen" => { - let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?.to_ptr()?; + let ptr = self.read_scalar(args[0])?.to_ptr()?; let n = self.memory.read_c_str(ptr)?.len(); - let ptr_size = self.memory.pointer_size(); - self.write_scalar(dest, Scalar::from_uint(n as u64, ptr_size), dest_ty)?; + self.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; } // Some things needed for sys::thread initialization to go through "signal" | "sigaction" | "sigaltstack" => { - let ptr_size = self.memory.pointer_size(); - self.write_scalar(dest, Scalar::null(ptr_size), dest_ty)?; + self.write_scalar(Scalar::null(dest.layout.size), dest)?; } "sysconf" => { - let name = self.value_to_scalar(args[0])?.to_usize(self)?; - let ptr_size = self.memory.pointer_size(); + let name = self.read_scalar(args[0])?.to_usize(&self)?; trace!("sysconf() called with name {}", name); // cache the sysconf integers via miri's global cache let paths = &[ - (&["libc", "_SC_PAGESIZE"], Scalar::from_int(4096, ptr_size)), - (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, ptr_size)), + (&["libc", "_SC_PAGESIZE"], Scalar::from_int(4096, dest.layout.size)), + (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)), ]; let mut result = None; for &(path, path_value) in paths { @@ -548,7 +488,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } } if let Some(result) = result { - self.write_scalar(dest, result, dest_ty)?; + self.write_scalar(result, dest)?; } else { return err!(Unimplemented( format!("Unimplemented sysconf name: {}", name), @@ -558,10 +498,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // Hook pthread calls that go to the thread-local storage memory subsystem "pthread_key_create" => { - let key_ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; + let key_ptr = self.read_scalar(args[0])?.not_undef()?; // Extract the function type out of the signature (that seems easier than constructing it ourselves...) - let dtor = match self.into_ptr(args[1].value)?.unwrap_or_err()? { + let dtor = match self.read_scalar(args[1])?.not_undef()? { Scalar::Ptr(dtor_ptr) => Some(self.memory.get_fn(dtor_ptr)?), Scalar::Bits { bits: 0, size } => { assert_eq!(size as u64, self.memory.pointer_size().bytes()); @@ -571,7 +511,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' }; // Figure out how large a pthread TLS key actually is. This is libc::pthread_key_t. - let key_type = args[0].ty.builtin_deref(true) + let key_type = args[0].layout.ty.builtin_deref(true) .ok_or_else(|| EvalErrorKind::AbiViolation("Wrong signature used for pthread_key_create: First argument must be a raw pointer.".to_owned()))?.ty; let key_layout = self.layout_of(key_type)?; @@ -590,26 +530,26 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' )?; // Return success (0) - self.write_null(dest, dest_layout)?; + self.write_null(dest)?; } "pthread_key_delete" => { - let key = self.value_to_scalar(args[0])?.to_bytes()?; + let key = self.read_scalar(args[0])?.to_bytes()?; self.memory.delete_tls_key(key)?; // Return success (0) - self.write_null(dest, dest_layout)?; + self.write_null(dest)?; } "pthread_getspecific" => { - let key = self.value_to_scalar(args[0])?.to_bytes()?; + let key = self.read_scalar(args[0])?.to_bytes()?; let ptr = self.memory.load_tls(key)?; - self.write_ptr(dest, ptr, dest_ty)?; + self.write_scalar(ptr, dest)?; } "pthread_setspecific" => { - let key = self.value_to_scalar(args[0])?.to_bytes()?; - let new_ptr = self.into_ptr(args[1].value)?.unwrap_or_err()?; + let key = self.read_scalar(args[0])?.to_bytes()?; + let new_ptr = self.read_scalar(args[1])?.not_undef()?; self.memory.store_tls(key, new_ptr)?; // Return success (0) - self.write_null(dest, dest_layout)?; + self.write_null(dest)?; } "_tlv_atexit" => { @@ -619,20 +559,19 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // Stub out all the other pthread calls to just return 0 link_name if link_name.starts_with("pthread_") => { debug!("ignoring C ABI call: {}", link_name); - self.write_null(dest, dest_layout)?; + self.write_null(dest)?; } "mmap" => { // This is a horrible hack, but well... the guard page mechanism calls mmap and expects a particular return value, so we give it that value - let addr = self.into_ptr(args[0].value)?.unwrap_or_err()?; - self.write_ptr(dest, addr, dest_ty)?; + let addr = self.read_scalar(args[0])?.not_undef()?; + self.write_scalar(addr, dest)?; } // Windows API subs "AddVectoredExceptionHandler" => { // any non zero value works for the stdlib. This is just used for stackoverflows anyway - let ptr_size = self.memory.pointer_size(); - self.write_scalar(dest, Scalar::from_int(1, ptr_size), dest_ty)?; + self.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; }, "InitializeCriticalSection" | "EnterCriticalSection" | @@ -645,11 +584,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "GetProcAddress" | "TryEnterCriticalSection" => { // pretend these do not exist/nothing happened, by returning zero - self.write_scalar(dest, Scalar::from_int(0, dest_layout.size), dest_ty)?; + self.write_null(dest)?; }, "GetLastError" => { // this is c::ERROR_CALL_NOT_IMPLEMENTED - self.write_scalar(dest, Scalar::from_int(120, dest_layout.size), dest_ty)?; + self.write_scalar(Scalar::from_int(120, dest.layout.size), dest)?; }, // Windows TLS @@ -660,23 +599,23 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let key = self.memory.create_tls_key(None) as u128; // Figure out how large a TLS key actually is. This is c::DWORD. - if dest_layout.size.bits() < 128 && key >= (1u128 << dest_layout.size.bits() as u128) { + if dest.layout.size.bits() < 128 && key >= (1u128 << dest.layout.size.bits() as u128) { return err!(OutOfTls); } - self.write_scalar(dest, Scalar::from_uint(key, dest_layout.size), dest_layout.ty)?; + self.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { - let key = self.value_to_scalar(args[0])?.to_bytes()?; + let key = self.read_scalar(args[0])?.to_bytes()?; let ptr = self.memory.load_tls(key)?; - self.write_ptr(dest, ptr, dest_ty)?; + self.write_scalar(ptr, dest)?; } "TlsSetValue" => { - let key = self.value_to_scalar(args[0])?.to_bytes()?; - let new_ptr = self.into_ptr(args[1].value)?.unwrap_or_err()?; + let key = self.read_scalar(args[0])?.to_bytes()?; + let new_ptr = self.read_scalar(args[1])?.not_undef()?; self.memory.store_tls(key, new_ptr)?; // Return success (1) - self.write_scalar(dest, Scalar::from_int(1, dest_layout.size), dest_ty)?; + self.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; } // We can't execute anything else @@ -690,7 +629,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // Since we pushed no stack frame, the main loop will act // as if the call just completed and it's returning to the // current frame. - self.dump_local(dest); + self.dump_place(*dest); self.goto_block(dest_block); Ok(()) } @@ -732,9 +671,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' fn call_missing_fn( &mut self, instance: ty::Instance<'tcx>, - destination: Option<(Place, mir::BasicBlock)>, - args: &[ValTy<'tcx>], - sig: ty::FnSig<'tcx>, + destination: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, + args: &[OpTy<'tcx>], path: String, ) -> EvalResult<'tcx> { // In some cases in non-MIR libstd-mode, not having a destination is legit. Handle these early. @@ -745,7 +683,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' _ => {} } - let dest_ty = sig.output(); let (dest, dest_block) = destination.ok_or_else( || EvalErrorKind::NoMirFor(path.clone()), )?; @@ -758,7 +695,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' instance.def_id(), args, dest, - dest_ty, dest_block, )?; return Ok(()); @@ -784,8 +720,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "std::panicking::panicking" | "std::rt::panicking" => { // we abort on panic -> `std::rt::panicking` always returns false - let bool = self.tcx.types.bool; - self.write_scalar(dest, Scalar::from_bool(false), bool)?; + self.write_scalar(Scalar::from_bool(false), dest)?; } _ => return err!(NoMirFor(path)), @@ -794,12 +729,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // Since we pushed no stack frame, the main loop will act // as if the call just completed and it's returning to the // current frame. - self.dump_local(dest); + self.dump_place(*dest); self.goto_block(dest_block); Ok(()) } - fn write_null(&mut self, dest: Place, dest_layout: TyLayout<'tcx>) -> EvalResult<'tcx> { - self.write_scalar(dest, Scalar::null(dest_layout.size), dest_layout.ty) + fn write_null(&mut self, dest: PlaceTy<'tcx>) -> EvalResult<'tcx> { + self.write_scalar(Scalar::null(dest.layout.size), dest) } } diff --git a/src/helpers.rs b/src/helpers.rs index 8482c484608b..606f1bb4ecb4 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,128 +1,121 @@ -use mir; -use rustc::ty::Ty; -use rustc::ty::layout::{LayoutOf, Size}; +use rustc::ty::layout::{Size, HasDataLayout}; -use super::{Scalar, ScalarExt, EvalResult, EvalContext, ValTy}; +use super::{Scalar, ScalarMaybeUndef, EvalResult}; use rustc_mir::interpret::sign_extend; -pub trait EvalContextExt<'tcx> { - fn wrapping_pointer_offset( - &self, - ptr: Scalar, - pointee_ty: Ty<'tcx>, - offset: i64, - ) -> EvalResult<'tcx, Scalar>; - - fn pointer_offset( - &self, - ptr: Scalar, - pointee_ty: Ty<'tcx>, - offset: i64, - ) -> EvalResult<'tcx, Scalar>; - - fn value_to_isize( - &self, - value: ValTy<'tcx>, - ) -> EvalResult<'tcx, i64>; - - fn value_to_usize( - &self, - value: ValTy<'tcx>, - ) -> EvalResult<'tcx, u64>; - - fn value_to_i32( - &self, - value: ValTy<'tcx>, - ) -> EvalResult<'tcx, i32>; - - fn value_to_u8( - &self, - value: ValTy<'tcx>, - ) -> EvalResult<'tcx, u8>; +pub trait ScalarExt { + fn null(size: Size) -> Self; + fn from_i32(i: i32) -> Self; + fn from_uint(i: impl Into, ptr_size: Size) -> Self; + fn from_int(i: impl Into, ptr_size: Size) -> Self; + fn from_f32(f: f32) -> Self; + fn from_f64(f: f64) -> Self; + fn is_null(self) -> bool; } -impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { - fn wrapping_pointer_offset( - &self, - ptr: Scalar, - pointee_ty: Ty<'tcx>, - offset: i64, - ) -> EvalResult<'tcx, Scalar> { - // FIXME: assuming here that type size is < i64::max_value() - let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; - let offset = offset.overflowing_mul(pointee_size).0; - Ok(ptr.ptr_wrapping_signed_offset(offset, self)) +pub trait FalibleScalarExt { + fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'static, u64>; + fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'static, i64>; + fn to_i32(self) -> EvalResult<'static, i32>; + fn to_u8(self) -> EvalResult<'static, u8>; + + /// HACK: this function just extracts all bits if `defined != 0` + /// Mainly used for args of C-functions and we should totally correctly fetch the size + /// of their arguments + fn to_bytes(self) -> EvalResult<'static, u128>; +} + +impl ScalarExt for Scalar { + fn null(size: Size) -> Self { + Scalar::Bits { bits: 0, size: size.bytes() as u8 } } - fn pointer_offset( - &self, - ptr: Scalar, - pointee_ty: Ty<'tcx>, - offset: i64, - ) -> EvalResult<'tcx, Scalar> { - // This function raises an error if the offset moves the pointer outside of its allocation. We consider - // ZSTs their own huge allocation that doesn't overlap with anything (and nothing moves in there because the size is 0). - // We also consider the NULL pointer its own separate allocation, and all the remaining integers pointers their own - // allocation. + fn from_i32(i: i32) -> Self { + Scalar::Bits { bits: i as u32 as u128, size: 4 } + } - if ptr.is_null() { - // NULL pointers must only be offset by 0 - return if offset == 0 { - Ok(ptr) - } else { - err!(InvalidNullPointerUsage) - }; + fn from_uint(i: impl Into, size: Size) -> Self { + Scalar::Bits { bits: i.into(), size: size.bytes() as u8 } + } + + fn from_int(i: impl Into, size: Size) -> Self { + Scalar::Bits { bits: i.into() as u128, size: size.bytes() as u8 } + } + + fn from_f32(f: f32) -> Self { + Scalar::Bits { bits: f.to_bits() as u128, size: 4 } + } + + fn from_f64(f: f64) -> Self { + Scalar::Bits { bits: f.to_bits() as u128, size: 8 } + } + + fn is_null(self) -> bool { + match self { + Scalar::Bits { bits, .. } => bits == 0, + Scalar::Ptr(_) => false } - // FIXME: assuming here that type size is < i64::max_value() - let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; - if let Some(offset) = offset.checked_mul(pointee_size) { - let ptr = ptr.ptr_signed_offset(offset, self)?; - // Do not do bounds-checking for integers; they can never alias a normal pointer anyway. - if let Scalar::Ptr(ptr) = ptr { - self.memory.check_bounds(ptr, false)?; - } else if ptr.is_null() { - // We moved *to* a NULL pointer. That seems wrong, LLVM considers the NULL pointer its own small allocation. Reject this, for now. - return err!(InvalidNullPointerUsage); - } - Ok(ptr) - } else { - err!(Overflow(mir::BinOp::Mul)) - } - } - - fn value_to_isize( - &self, - value: ValTy<'tcx>, - ) -> EvalResult<'tcx, i64> { - assert_eq!(value.ty, self.tcx.types.isize); - let raw = self.value_to_scalar(value)?.to_bits(self.memory.pointer_size())?; - let raw = sign_extend(raw, self.layout_of(self.tcx.types.isize).unwrap()); - Ok(raw as i64) - } - - fn value_to_usize( - &self, - value: ValTy<'tcx>, - ) -> EvalResult<'tcx, u64> { - assert_eq!(value.ty, self.tcx.types.usize); - self.value_to_scalar(value)?.to_bits(self.memory.pointer_size()).map(|v| v as u64) - } - - fn value_to_i32( - &self, - value: ValTy<'tcx>, - ) -> EvalResult<'tcx, i32> { - assert_eq!(value.ty, self.tcx.types.i32); - let raw = self.value_to_scalar(value)?.to_bits(Size::from_bits(32))?; - let raw = sign_extend(raw, self.layout_of(self.tcx.types.i32).unwrap()); - Ok(raw as i32) - } - - fn value_to_u8( - &self, - value: ValTy<'tcx>, - ) -> EvalResult<'tcx, u8> { - assert_eq!(value.ty, self.tcx.types.u8); - self.value_to_scalar(value)?.to_bits(Size::from_bits(8)).map(|v| v as u8) + } +} + +impl FalibleScalarExt for Scalar { + fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'static, u64> { + let b = self.to_bits(cx.data_layout().pointer_size)?; + assert_eq!(b as u64 as u128, b); + Ok(b as u64) + } + + fn to_u8(self) -> EvalResult<'static, u8> { + let sz = Size::from_bits(8); + let b = self.to_bits(sz)?; + assert_eq!(b as u8 as u128, b); + Ok(b as u8) + } + + fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'static, i64> { + let b = self.to_bits(cx.data_layout().pointer_size)?; + let b = sign_extend(b, cx.data_layout().pointer_size) as i128; + assert_eq!(b as i64 as i128, b); + Ok(b as i64) + } + + fn to_i32(self) -> EvalResult<'static, i32> { + let sz = Size::from_bits(32); + let b = self.to_bits(sz)?; + let b = sign_extend(b, sz) as i128; + assert_eq!(b as i32 as i128, b); + Ok(b as i32) + } + + fn to_bytes(self) -> EvalResult<'static, u128> { + match self { + Scalar::Bits { bits, size } => { + assert_ne!(size, 0); + Ok(bits) + }, + Scalar::Ptr(_) => err!(ReadPointerAsBytes), + } + } +} + +impl FalibleScalarExt for ScalarMaybeUndef { + fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'static, u64> { + self.not_undef()?.to_usize(cx) + } + + fn to_u8(self) -> EvalResult<'static, u8> { + self.not_undef()?.to_u8() + } + + fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'static, i64> { + self.not_undef()?.to_isize(cx) + } + + fn to_i32(self) -> EvalResult<'static, i32> { + self.not_undef()?.to_i32() + } + + fn to_bytes(self) -> EvalResult<'static, u128> { + self.not_undef()?.to_bytes() } } diff --git a/src/intrinsic.rs b/src/intrinsic.rs index cd953ba7c569..631653b97b6b 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -1,21 +1,20 @@ use rustc::mir; -use rustc::ty::layout::{TyLayout, LayoutOf, Size, Primitive, Integer::*}; +use rustc::ty::layout::{self, LayoutOf, Size, Primitive, Integer::*}; use rustc::ty; -use rustc::mir::interpret::{EvalResult, Scalar, Value, ScalarMaybeUndef}; -use rustc_mir::interpret::{Place, PlaceExtra, HasMemory, EvalContext, ValTy}; +use rustc::mir::interpret::{EvalResult, Scalar, ScalarMaybeUndef}; +use rustc_mir::interpret::{ + PlaceExtra, PlaceTy, EvalContext, OpTy, Value +}; -use helpers::EvalContextExt as HelperEvalContextExt; - -use super::ScalarExt; +use super::{ScalarExt, FalibleScalarExt, OperatorEvalContextExt}; pub trait EvalContextExt<'tcx> { fn call_intrinsic( &mut self, instance: ty::Instance<'tcx>, - args: &[ValTy<'tcx>], - dest: Place, - dest_layout: TyLayout<'tcx>, + args: &[OpTy<'tcx>], + dest: PlaceTy<'tcx>, target: mir::BasicBlock, ) -> EvalResult<'tcx>; } @@ -24,9 +23,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: fn call_intrinsic( &mut self, instance: ty::Instance<'tcx>, - args: &[ValTy<'tcx>], - dest: Place, - dest_layout: TyLayout<'tcx>, + args: &[OpTy<'tcx>], + dest: PlaceTy<'tcx>, target: mir::BasicBlock, ) -> EvalResult<'tcx> { let substs = instance.substs; @@ -34,44 +32,51 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..]; match intrinsic_name { "add_with_overflow" => { - self.intrinsic_with_overflow( + let l = self.read_value(args[0])?; + let r = self.read_value(args[1])?; + self.binop_with_overflow( mir::BinOp::Add, - args[0], - args[1], + l, + r, dest, - dest_layout.ty, )? } "sub_with_overflow" => { - self.intrinsic_with_overflow( + let l = self.read_value(args[0])?; + let r = self.read_value(args[1])?; + self.binop_with_overflow( mir::BinOp::Sub, - args[0], - args[1], + l, + r, dest, - dest_layout.ty, )? } "mul_with_overflow" => { - self.intrinsic_with_overflow( + let l = self.read_value(args[0])?; + let r = self.read_value(args[1])?; + self.binop_with_overflow( mir::BinOp::Mul, - args[0], - args[1], + l, + r, dest, - dest_layout.ty, )? } "arith_offset" => { - let offset = self.value_to_isize(args[1])?; - let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; - let result_ptr = self.wrapping_pointer_offset(ptr, substs.type_at(0), offset)?; - self.write_ptr(dest, result_ptr, dest_layout.ty)?; + let offset = self.read_scalar(args[1])?.to_isize(&self)?; + let ptr = self.read_scalar(args[0])?.not_undef()?; + + let pointee_ty = substs.type_at(0); + let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; + let offset = offset.overflowing_mul(pointee_size).0; + let result_ptr = ptr.ptr_wrapping_signed_offset(offset, &self); + self.write_scalar(result_ptr, dest)?; } "assume" => { - let cond = self.value_to_scalar(args[0])?.to_bool()?; + let cond = self.read_scalar(args[0])?.to_bool()?; if !cond { return err!(AssumptionNotHeld); } @@ -81,24 +86,18 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "atomic_load_relaxed" | "atomic_load_acq" | "volatile_load" => { - let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; - let align = self.layout_of(args[0].ty)?.align; - - let valty = ValTy { - value: Value::ByRef(ptr, align), - ty: substs.type_at(0), - }; - self.write_value(valty, dest)?; + let ptr = self.ref_to_mplace(self.read_value(args[0])?)?; + let val = self.read_scalar(ptr.into())?; // make sure it fits into a scalar; otherwise it cannot be atomic + self.write_scalar(val, dest)?; } "atomic_store" | "atomic_store_relaxed" | "atomic_store_rel" | "volatile_store" => { - let ty = substs.type_at(0); - let align = self.layout_of(ty)?.align; - let dest = self.into_ptr(args[0].value)?.unwrap_or_err()?; - self.write_value_to_ptr(args[1].value, dest, align, ty)?; + let ptr = self.ref_to_mplace(self.read_value(args[0])?)?; + let val = self.read_scalar(args[1])?; // make sure it fits into a scalar; otherwise it cannot be atomic + self.write_scalar(val, ptr.into())?; } "atomic_fence_acq" => { @@ -106,47 +105,26 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } _ if intrinsic_name.starts_with("atomic_xchg") => { - let ty = substs.type_at(0); - let align = self.layout_of(ty)?.align; - let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; - let change = self.value_to_scalar(args[1])?; - let old = self.read_value(ptr, align, ty)?; - let old = match old { - Value::Scalar(val) => val, - Value::ByRef { .. } => bug!("just read the value, can't be byref"), - Value::ScalarPair(..) => bug!("atomic_xchg doesn't work with nonprimitives"), - }; - self.write_scalar(dest, old, ty)?; - self.write_scalar( - Place::from_scalar_ptr(ptr.into(), align), - change, - ty, - )?; + let ptr = self.ref_to_mplace(self.read_value(args[0])?)?; + let new = self.read_scalar(args[1])?; + let old = self.read_scalar(ptr.into())?; + self.write_scalar(old, dest)?; // old value is returned + self.write_scalar(new, ptr.into())?; } _ if intrinsic_name.starts_with("atomic_cxchg") => { - let ty = substs.type_at(0); - let align = self.layout_of(ty)?.align; - let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; - let expect_old = self.value_to_scalar(args[1])?; - let change = self.value_to_scalar(args[2])?; - let old = self.read_value(ptr, align, ty)?; - let old = match old { - Value::Scalar(val) => val.unwrap_or_err()?, - Value::ByRef { .. } => bug!("just read the value, can't be byref"), - Value::ScalarPair(..) => bug!("atomic_cxchg doesn't work with nonprimitives"), - }; - let (val, _) = self.binary_op(mir::BinOp::Eq, old, ty, expect_old, ty)?; - let valty = ValTy { - value: Value::ScalarPair(old.into(), val.into()), - ty: dest_layout.ty, - }; - self.write_value(valty, dest)?; - self.write_scalar( - Place::from_scalar_ptr(ptr.into(), dest_layout.align), - change, - ty, - )?; + let ptr = self.ref_to_mplace(self.read_value(args[0])?)?; + let expect_old = self.read_value(args[1])?; // read as value for the sake of `binary_op()` + let new = self.read_scalar(args[2])?; + let old = self.read_value(ptr.into())?; // read as value for the sake of `binary_op()` + // binary_op will bail if either of them is not a scalar + let (eq, _) = self.binary_op(mir::BinOp::Eq, old, expect_old)?; + let res = Value::ScalarPair(old.to_scalar_or_undef(), eq.into()); + self.write_value(res, dest)?; // old value is returned + // update ptr depending on comparison + if eq.to_bool()? { + self.write_scalar(new, ptr.into())?; + } } "atomic_or" | @@ -174,19 +152,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "atomic_xsub_rel" | "atomic_xsub_acqrel" | "atomic_xsub_relaxed" => { - let ty = substs.type_at(0); - let align = self.layout_of(ty)?.align; - let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; - let change = self.value_to_scalar(args[1])?; - let old = self.read_value(ptr, align, ty)?; - let old = match old { - Value::Scalar(val) => val, - Value::ByRef { .. } => bug!("just read the value, can't be byref"), - Value::ScalarPair(..) => { - bug!("atomic_xadd_relaxed doesn't work with nonprimitives") - } - }; - self.write_scalar(dest, old, ty)?; + let ptr = self.ref_to_mplace(self.read_value(args[0])?)?; + let rhs = self.read_value(args[1])?; + let old = self.read_value(ptr.into())?; + self.write_value(*old, dest)?; // old value is returned let op = match intrinsic_name.split('_').nth(1).unwrap() { "or" => mir::BinOp::BitOr, "xor" => mir::BinOp::BitXor, @@ -196,8 +165,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: _ => bug!(), }; // FIXME: what do atomics do on overflow? - let (val, _) = self.binary_op(op, old.unwrap_or_err()?, ty, change, ty)?; - self.write_scalar(Place::from_scalar_ptr(ptr.into(), dest_layout.align), val, ty)?; + let (val, _) = self.binary_op(op, old, rhs)?; + self.write_scalar(val, ptr.into())?; } "breakpoint" => unimplemented!(), // halt miri @@ -207,13 +176,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let elem_ty = substs.type_at(0); let elem_layout = self.layout_of(elem_ty)?; let elem_size = elem_layout.size.bytes(); - let count = self.value_to_usize(args[2])?; + let count = self.read_scalar(args[2])?.to_usize(&self)?; if count * elem_size != 0 { // TODO: We do not even validate alignment for the 0-bytes case. libstd relies on this in vec::IntoIter::next. // Also see the write_bytes intrinsic. let elem_align = elem_layout.align; - let src = self.into_ptr(args[0].value)?.unwrap_or_err()?; - let dest = self.into_ptr(args[1].value)?.unwrap_or_err()?; + let src = self.read_scalar(args[0])?.not_undef()?; + let dest = self.read_scalar(args[1])?.not_undef()?; self.memory.copy( src, elem_align, @@ -227,7 +196,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "ctpop" | "cttz" | "cttz_nonzero" | "ctlz" | "ctlz_nonzero" | "bswap" => { let ty = substs.type_at(0); - let num = self.value_to_scalar(args[0])?.to_bytes()?; + let num = self.read_scalar(args[0])?.to_bytes()?; let kind = match self.layout_of(ty)?.abi { ty::layout::Abi::Scalar(ref scalar) => scalar.value, _ => Err(::rustc::mir::interpret::EvalErrorKind::TypeNotPrimitive(ty))?, @@ -240,22 +209,18 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } else { numeric_intrinsic(intrinsic_name, num, kind)? }; - self.write_scalar(dest, num, ty)?; + self.write_scalar(num, dest)?; } "discriminant_value" => { - let ty = substs.type_at(0); - let layout = self.layout_of(ty)?; - let adt_ptr = self.into_ptr(args[0].value)?; - let adt_align = self.layout_of(args[0].ty)?.align; - let place = Place::from_scalar_ptr(adt_ptr, adt_align); - let discr_val = self.read_discriminant_value(place, layout)?; - self.write_scalar(dest, Scalar::from_uint(discr_val, dest_layout.size), dest_layout.ty)?; + let place = self.ref_to_mplace(self.read_value(args[0])?)?; + let discr_val = self.read_discriminant_value(place.into())?; + self.write_scalar(Scalar::from_uint(discr_val, dest.layout.size), dest)?; } "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" => { - let f = self.value_to_scalar(args[0])?.to_bytes()?; + let f = self.read_scalar(args[0])?.to_bytes()?; let f = f32::from_bits(f as u32); let f = match intrinsic_name { "sinf32" => f.sin(), @@ -272,12 +237,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "truncf32" => f.trunc(), _ => bug!(), }; - self.write_scalar(dest, Scalar::from_f32(f), dest_layout.ty)?; + self.write_scalar(Scalar::from_f32(f), dest)?; } "sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" | "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" => { - let f = self.value_to_scalar(args[0])?.to_bytes()?; + let f = self.read_scalar(args[0])?.to_bytes()?; let f = f64::from_bits(f as u64); let f = match intrinsic_name { "sinf64" => f.sin(), @@ -294,13 +259,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "truncf64" => f.trunc(), _ => bug!(), }; - self.write_scalar(dest, Scalar::from_f64(f), dest_layout.ty)?; + self.write_scalar(Scalar::from_f64(f), dest)?; } "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { - let ty = substs.type_at(0); - let a = self.value_to_scalar(args[0])?; - let b = self.value_to_scalar(args[1])?; + let a = self.read_value(args[0])?; + let b = self.read_value(args[1])?; let op = match intrinsic_name { "fadd_fast" => mir::BinOp::Add, "fsub_fast" => mir::BinOp::Sub, @@ -309,48 +273,43 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "frem_fast" => mir::BinOp::Rem, _ => bug!(), }; - let result = self.binary_op(op, a, ty, b, ty)?; - self.write_scalar(dest, result.0, dest_layout.ty)?; + let result = self.binary_op(op, a, b)?; + self.write_scalar(result.0, dest)?; } "exact_div" => { // Performs an exact division, resulting in undefined behavior where // `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1` - let ty = substs.type_at(0); - let a = self.value_to_scalar(args[0])?; - let b = self.value_to_scalar(args[1])?; + let a = self.read_value(args[0])?; + let b = self.read_value(args[1])?; // check x % y != 0 - if !self.binary_op(mir::BinOp::Rem, a, ty, b, ty)?.0.is_null() { + if !self.binary_op(mir::BinOp::Rem, a, b)?.0.is_null() { return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b))); } - let result = self.binary_op(mir::BinOp::Div, a, ty, b, ty)?; - self.write_scalar(dest, result.0, dest_layout.ty)?; + let result = self.binary_op(mir::BinOp::Div, a, b)?; + self.write_scalar(result.0, dest)?; }, "likely" | "unlikely" | "forget" => {} "init" => { - // we don't want to force an allocation in case the destination is a simple value - match dest { - Place::Local { frame, local } => { - match self.stack()[frame].locals[local].access()? { - Value::ByRef(ptr, _) => { - // These writes have no alignment restriction anyway. - self.memory.write_repeat(ptr, 0, dest_layout.size)?; - } - Value::Scalar(_) => self.write_value(ValTy { value: Value::Scalar(Scalar::null(dest_layout.size).into()), ty: dest_layout.ty }, dest)?, - Value::ScalarPair(..) => { - self.write_value(ValTy { value: Value::ScalarPair(Scalar::null(dest_layout.size).into(), Scalar::null(dest_layout.size).into()), ty: dest_layout.ty }, dest)?; - } - } - }, - Place::Ptr { - ptr, - align: _align, - extra: PlaceExtra::None, - } => self.memory.write_repeat(ptr.unwrap_or_err()?, 0, dest_layout.size)?, - Place::Ptr { .. } => { - bug!("init intrinsic tried to write to fat or unaligned ptr target") + // Check fast path: we don't want to force an allocation in case the destination is a simple value, + // but we also do not want to create a new allocation with 0s and then copy that over. + match dest.layout.abi { + layout::Abi::Scalar(ref s) => { + let x = Scalar::null(s.value.size(&self)); + self.write_value(Value::Scalar(x.into()), dest)?; + } + layout::Abi::ScalarPair(ref s1, ref s2) => { + let x = Scalar::null(s1.value.size(&self)); + let y = Scalar::null(s2.value.size(&self)); + self.write_value(Value::ScalarPair(x.into(), y.into()), dest)?; + } + _ => { + // Do it in memory + let mplace = self.force_allocation(dest)?; + assert_eq!(mplace.extra, PlaceExtra::None); + self.memory.write_repeat(mplace.ptr, 0, dest.layout.size)?; } } } @@ -360,7 +319,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let elem_align = self.layout_of(elem_ty)?.align.abi(); let ptr_size = self.memory.pointer_size(); let align_val = Scalar::from_uint(elem_align as u128, ptr_size); - self.write_scalar(dest, align_val, dest_layout.ty)?; + self.write_scalar(align_val, dest)?; } "pref_align_of" => { @@ -369,14 +328,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let align = layout.align.pref(); let ptr_size = self.memory.pointer_size(); let align_val = Scalar::from_uint(align as u128, ptr_size); - self.write_scalar(dest, align_val, dest_layout.ty)?; + self.write_scalar(align_val, dest)?; } "move_val_init" => { - let ty = substs.type_at(0); - let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; - let align = self.layout_of(args[0].ty)?.align; - self.write_value_to_ptr(args[1].value, ptr, align, ty)?; + let ptr = self.ref_to_mplace(self.read_value(args[0])?)?; + self.copy_op(args[1], ptr.into())?; } "needs_drop" => { @@ -384,120 +341,116 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let env = ty::ParamEnv::reveal_all(); let needs_drop = ty.needs_drop(self.tcx.tcx, env); self.write_scalar( - dest, Scalar::from_bool(needs_drop), - dest_layout.ty, + dest, )?; } "offset" => { - let offset = self.value_to_isize(args[1])?; - let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; - let result_ptr = self.pointer_offset(ptr, substs.type_at(0), offset)?; - self.write_ptr(dest, result_ptr, dest_layout.ty)?; + let offset = self.read_scalar(args[1])?.to_isize(&self)?; + let ptr = self.read_scalar(args[0])?.not_undef()?; + let result_ptr = self.pointer_offset_inbounds(ptr, substs.type_at(0), offset)?; + self.write_scalar(result_ptr, dest)?; } "overflowing_sub" => { - self.intrinsic_overflowing( + let l = self.read_value(args[0])?; + let r = self.read_value(args[1])?; + self.binop_ignore_overflow( mir::BinOp::Sub, - args[0], - args[1], + l, + r, dest, - dest_layout.ty, )?; } "overflowing_mul" => { - self.intrinsic_overflowing( + let l = self.read_value(args[0])?; + let r = self.read_value(args[1])?; + self.binop_ignore_overflow( mir::BinOp::Mul, - args[0], - args[1], + r, + l, dest, - dest_layout.ty, )?; } "overflowing_add" => { - self.intrinsic_overflowing( + let l = self.read_value(args[0])?; + let r = self.read_value(args[1])?; + self.binop_ignore_overflow( mir::BinOp::Add, - args[0], - args[1], + r, + l, dest, - dest_layout.ty, )?; } "powf32" => { - let f = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(32))?; + let f = self.read_scalar(args[0])?.to_bits(Size::from_bits(32))?; let f = f32::from_bits(f as u32); - let f2 = self.value_to_scalar(args[1])?.to_bits(Size::from_bits(32))?; + let f2 = self.read_scalar(args[1])?.to_bits(Size::from_bits(32))?; let f2 = f32::from_bits(f2 as u32); self.write_scalar( - dest, Scalar::from_f32(f.powf(f2)), - dest_layout.ty, + dest, )?; } "powf64" => { - let f = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(64))?; + let f = self.read_scalar(args[0])?.to_bits(Size::from_bits(64))?; let f = f64::from_bits(f as u64); - let f2 = self.value_to_scalar(args[1])?.to_bits(Size::from_bits(64))?; + let f2 = self.read_scalar(args[1])?.to_bits(Size::from_bits(64))?; let f2 = f64::from_bits(f2 as u64); self.write_scalar( - dest, Scalar::from_f64(f.powf(f2)), - dest_layout.ty, + dest, )?; } "fmaf32" => { - let a = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(32))?; + let a = self.read_scalar(args[0])?.to_bits(Size::from_bits(32))?; let a = f32::from_bits(a as u32); - let b = self.value_to_scalar(args[1])?.to_bits(Size::from_bits(32))?; + let b = self.read_scalar(args[1])?.to_bits(Size::from_bits(32))?; let b = f32::from_bits(b as u32); - let c = self.value_to_scalar(args[2])?.to_bits(Size::from_bits(32))?; + let c = self.read_scalar(args[2])?.to_bits(Size::from_bits(32))?; let c = f32::from_bits(c as u32); self.write_scalar( - dest, Scalar::from_f32(a * b + c), - dest_layout.ty, + dest, )?; } "fmaf64" => { - let a = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(64))?; + let a = self.read_scalar(args[0])?.to_bits(Size::from_bits(64))?; let a = f64::from_bits(a as u64); - let b = self.value_to_scalar(args[1])?.to_bits(Size::from_bits(64))?; + let b = self.read_scalar(args[1])?.to_bits(Size::from_bits(64))?; let b = f64::from_bits(b as u64); - let c = self.value_to_scalar(args[2])?.to_bits(Size::from_bits(64))?; + let c = self.read_scalar(args[2])?.to_bits(Size::from_bits(64))?; let c = f64::from_bits(c as u64); self.write_scalar( - dest, Scalar::from_f64(a * b + c), - dest_layout.ty, + dest, )?; } "powif32" => { - let f = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(32))?; + let f = self.read_scalar(args[0])?.to_bits(Size::from_bits(32))?; let f = f32::from_bits(f as u32); - let i = self.value_to_i32(args[1])?; + let i = self.read_scalar(args[1])?.to_i32()?; self.write_scalar( - dest, Scalar::from_f32(f.powi(i)), - dest_layout.ty, + dest, )?; } "powif64" => { - let f = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(64))?; + let f = self.read_scalar(args[0])?.to_bits(Size::from_bits(64))?; let f = f64::from_bits(f as u64); - let i = self.value_to_i32(args[1])?; + let i = self.read_scalar(args[1])?.to_i32()?; self.write_scalar( - dest, Scalar::from_f64(f.powi(i)), - dest_layout.ty, + dest, )?; } @@ -505,29 +458,27 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ty = substs.type_at(0); let size = self.layout_of(ty)?.size.bytes(); let ptr_size = self.memory.pointer_size(); - self.write_scalar(dest, Scalar::from_uint(size, ptr_size), dest_layout.ty)?; + self.write_scalar(Scalar::from_uint(size, ptr_size), dest)?; } "size_of_val" => { - let ty = substs.type_at(0); - let (size, _) = self.size_and_align_of_dst(ty, args[0].value)?; + let mplace = self.ref_to_mplace(self.read_value(args[0])?)?; + let (size, _) = self.size_and_align_of_mplace(mplace)?; let ptr_size = self.memory.pointer_size(); self.write_scalar( - dest, Scalar::from_uint(size.bytes() as u128, ptr_size), - dest_layout.ty, + dest, )?; } "min_align_of_val" | "align_of_val" => { - let ty = substs.type_at(0); - let (_, align) = self.size_and_align_of_dst(ty, args[0].value)?; + let mplace = self.ref_to_mplace(self.read_value(args[0])?)?; + let (_, align) = self.size_and_align_of_mplace(mplace)?; let ptr_size = self.memory.pointer_size(); self.write_scalar( - dest, Scalar::from_uint(align.abi(), ptr_size), - dest_layout.ty, + dest, )?; } @@ -535,110 +486,105 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ty = substs.type_at(0); let ty_name = ty.to_string(); let value = self.str_to_value(&ty_name)?; - self.write_value(ValTy { value, ty: dest_layout.ty }, dest)?; + self.write_value(value, dest)?; } "type_id" => { let ty = substs.type_at(0); let n = self.tcx.type_id_hash(ty); - self.write_scalar(dest, Scalar::Bits { bits: n as u128, size: 8 }, dest_layout.ty)?; + self.write_scalar(Scalar::Bits { bits: n as u128, size: 8 }, dest)?; } "transmute" => { - let src_ty = substs.type_at(0); - let _src_align = self.layout_of(src_ty)?.align; - let ptr = self.force_allocation(dest)?.to_ptr()?; - let dest_align = self.layout_of(substs.type_at(1))?.align; - self.write_value_to_ptr(args[0].value, ptr.into(), dest_align, src_ty).unwrap(); + // Go through an allocation, to make sure the completely different layouts + // do not pose a problem. (When the user transmutes through a union, + // there will not be a layout mismatch.) + let dest = self.force_allocation(dest)?; + self.copy_op(args[0], dest.into())?; } "unchecked_shl" => { - let bits = dest_layout.size.bytes() as u128 * 8; - let rhs = self.value_to_scalar(args[1])? - .to_bytes()?; - if rhs >= bits { + let bits = dest.layout.size.bytes() as u128 * 8; + let l = self.read_value(args[0])?; + let r = self.read_value(args[1])?; + let rval = r.to_scalar()?.to_bytes()?; + if rval >= bits { return err!(Intrinsic( - format!("Overflowing shift by {} in unchecked_shl", rhs), + format!("Overflowing shift by {} in unchecked_shl", rval), )); } - self.intrinsic_overflowing( + self.binop_ignore_overflow( mir::BinOp::Shl, - args[0], - args[1], + l, + r, dest, - dest_layout.ty, )?; } "unchecked_shr" => { - let bits = dest_layout.size.bytes() as u128 * 8; - let rhs = self.value_to_scalar(args[1])? - .to_bytes()?; - if rhs >= bits { + let bits = dest.layout.size.bytes() as u128 * 8; + let l = self.read_value(args[0])?; + let r = self.read_value(args[1])?; + let rval = r.to_scalar()?.to_bytes()?; + if rval >= bits { return err!(Intrinsic( - format!("Overflowing shift by {} in unchecked_shr", rhs), + format!("Overflowing shift by {} in unchecked_shr", rval), )); } - self.intrinsic_overflowing( + self.binop_ignore_overflow( mir::BinOp::Shr, - args[0], - args[1], + l, + r, dest, - dest_layout.ty, )?; } "unchecked_div" => { - let rhs = self.value_to_scalar(args[1])? - .to_bytes()?; - if rhs == 0 { + let l = self.read_value(args[0])?; + let r = self.read_value(args[1])?; + let rval = r.to_scalar()?.to_bytes()?; + if rval == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_div"))); } - self.intrinsic_overflowing( + self.binop_ignore_overflow( mir::BinOp::Div, - args[0], - args[1], + l, + r, dest, - dest_layout.ty, )?; } "unchecked_rem" => { - let rhs = self.value_to_scalar(args[1])? - .to_bytes()?; - if rhs == 0 { + let l = self.read_value(args[0])?; + let r = self.read_value(args[1])?; + let rval = r.to_scalar()?.to_bytes()?; + if rval == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_rem"))); } - self.intrinsic_overflowing( + self.binop_ignore_overflow( mir::BinOp::Rem, - args[0], - args[1], + l, + r, dest, - dest_layout.ty, )?; } "uninit" => { - // we don't want to force an allocation in case the destination is a simple value - match dest { - Place::Local { frame, local } => { - match self.stack()[frame].locals[local].access()? { - Value::ByRef(ptr, _) => { - // These writes have no alignment restriction anyway. - self.memory.mark_definedness(ptr, dest_layout.size, false)?; - } - Value::Scalar(_) => self.write_value(ValTy { value: Value::Scalar(ScalarMaybeUndef::Undef), ty: dest_layout.ty }, dest)?, - Value::ScalarPair(..) => { - self.write_value(ValTy { value: Value::ScalarPair(ScalarMaybeUndef::Undef, ScalarMaybeUndef::Undef), ty: dest_layout.ty }, dest)?; - } - } - }, - Place::Ptr { - ptr, - align: _align, - extra: PlaceExtra::None, - } => self.memory.mark_definedness(ptr.unwrap_or_err()?, dest_layout.size, false)?, - Place::Ptr { .. } => { - bug!("uninit intrinsic tried to write to fat or unaligned ptr target") + // Check fast path: we don't want to force an allocation in case the destination is a simple value, + // but we also do not want to create a new allocation with 0s and then copy that over. + match dest.layout.abi { + layout::Abi::Scalar(..) => { + let x = ScalarMaybeUndef::Undef; + self.write_value(Value::Scalar(x), dest)?; + } + layout::Abi::ScalarPair(..) => { + let x = ScalarMaybeUndef::Undef; + self.write_value(Value::ScalarPair(x, x), dest)?; + } + _ => { + // Do it in memory + let mplace = self.force_allocation(dest)?; + assert_eq!(mplace.extra, PlaceExtra::None); + self.memory.mark_definedness(mplace.ptr, dest.layout.size, false)?; } } } @@ -646,9 +592,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "write_bytes" => { let ty = substs.type_at(0); let ty_layout = self.layout_of(ty)?; - let val_byte = self.value_to_u8(args[1])?; - let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; - let count = self.value_to_usize(args[2])?; + let val_byte = self.read_scalar(args[1])?.to_u8()?; + let ptr = self.read_scalar(args[0])?.not_undef()?; + let count = self.read_scalar(args[2])?.to_usize(&self)?; if count > 0 { // HashMap relies on write_bytes on a NULL ptr with count == 0 to work // TODO: Should we, at least, validate the alignment? (Also see the copy intrinsic) diff --git a/src/lib.rs b/src/lib.rs index 705f56d38f39..3680d49836fb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,6 +27,7 @@ use rustc_data_structures::fx::FxHasher; use syntax::ast::Mutability; use syntax::codemap::Span; +use std::marker::PhantomData; use std::collections::{HashMap, BTreeMap}; use std::hash::{Hash, Hasher}; @@ -41,81 +42,14 @@ mod memory; mod tls; mod locks; mod range_map; -mod validation; use fn_call::EvalContextExt as MissingFnsEvalContextExt; use operator::EvalContextExt as OperatorEvalContextExt; use intrinsic::EvalContextExt as IntrinsicEvalContextExt; use tls::EvalContextExt as TlsEvalContextExt; use locks::LockInfo; -use locks::MemoryExt as LockMemoryExt; -use validation::EvalContextExt as ValidationEvalContextExt; use range_map::RangeMap; -use validation::{ValidationQuery, AbsPlace}; - -pub trait ScalarExt { - fn null(size: Size) -> Self; - fn from_i32(i: i32) -> Self; - fn from_uint(i: impl Into, ptr_size: Size) -> Self; - fn from_int(i: impl Into, ptr_size: Size) -> Self; - fn from_f32(f: f32) -> Self; - fn from_f64(f: f64) -> Self; - fn to_usize<'a, 'mir, 'tcx>(self, ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>) -> EvalResult<'static, u64>; - fn is_null(self) -> bool; - /// HACK: this function just extracts all bits if `defined != 0` - /// Mainly used for args of C-functions and we should totally correctly fetch the size - /// of their arguments - fn to_bytes(self) -> EvalResult<'static, u128>; -} - -impl ScalarExt for Scalar { - fn null(size: Size) -> Self { - Scalar::Bits { bits: 0, size: size.bytes() as u8 } - } - - fn from_i32(i: i32) -> Self { - Scalar::Bits { bits: i as u32 as u128, size: 4 } - } - - fn from_uint(i: impl Into, ptr_size: Size) -> Self { - Scalar::Bits { bits: i.into(), size: ptr_size.bytes() as u8 } - } - - fn from_int(i: impl Into, ptr_size: Size) -> Self { - Scalar::Bits { bits: i.into() as u128, size: ptr_size.bytes() as u8 } - } - - fn from_f32(f: f32) -> Self { - Scalar::Bits { bits: f.to_bits() as u128, size: 4 } - } - - fn from_f64(f: f64) -> Self { - Scalar::Bits { bits: f.to_bits() as u128, size: 8 } - } - - fn to_usize<'a, 'mir, 'tcx>(self, ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>) -> EvalResult<'static, u64> { - let b = self.to_bits(ecx.memory.pointer_size())?; - assert_eq!(b as u64 as u128, b); - Ok(b as u64) - } - - fn is_null(self) -> bool { - match self { - Scalar::Bits { bits, .. } => bits == 0, - Scalar::Ptr(_) => false - } - } - - fn to_bytes(self) -> EvalResult<'static, u128> { - match self { - Scalar::Bits { bits, size } => { - assert_ne!(size, 0); - Ok(bits) - }, - Scalar::Ptr(_) => err!(ReadPointerAsBytes), - } - } -} +use helpers::{ScalarExt, FalibleScalarExt}; pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -180,31 +114,22 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // First argument: pointer to main() let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance); let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - let main_ty = main_instance.ty(ecx.tcx.tcx); - let main_ptr_ty = ecx.tcx.mk_fn_ptr(main_ty.fn_sig(ecx.tcx.tcx)); - ecx.write_value( - ValTy { - value: Value::Scalar(Scalar::Ptr(main_ptr).into()), - ty: main_ptr_ty, - }, - dest, - )?; + ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?; // Second argument (argc): 1 let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - let ty = ecx.tcx.types.isize; - ecx.write_scalar(dest, Scalar::from_int(1, ptr_size), ty)?; + ecx.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; // FIXME: extract main source file path // Third argument (argv): &[b"foo"] let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - let ty = ecx.tcx.mk_imm_ptr(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8)); let foo = ecx.memory.allocate_bytes(b"foo\0"); - let ptr_align = ecx.tcx.data_layout.pointer_align; - let foo_ptr = ecx.memory.allocate(ptr_size, ptr_align, MemoryKind::Stack)?; - ecx.memory.write_scalar(foo_ptr.into(), ptr_align, Scalar::Ptr(foo).into(), ptr_size, ptr_align, false)?; - ecx.memory.mark_static_initialized(foo_ptr.alloc_id, Mutability::Immutable)?; - ecx.write_ptr(dest, foo_ptr.into(), ty)?; + let foo_ty = ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8); + let foo_layout = ecx.layout_of(foo_ty)?; + let foo_place = ecx.allocate(foo_layout, MemoryKind::Stack)?; + ecx.write_scalar(Scalar::Ptr(foo), foo_place.into())?; + ecx.memory.mark_static_initialized(foo_place.to_ptr()?.alloc_id, Mutability::Immutable)?; + ecx.write_scalar(foo_place.ptr, dest)?; assert!(args.next().is_none(), "start lang item has more arguments than expected"); } else { @@ -293,15 +218,15 @@ pub struct Evaluator<'tcx> { /// Miri does not expose env vars from the host to the emulated program pub(crate) env_vars: HashMap, Pointer>, - /// Places that were suspended by the validation subsystem, and will be recovered later - pub(crate) suspended: HashMap>>, + /// Use the lifetime + _dummy : PhantomData<&'tcx ()>, } impl<'tcx> Hash for Evaluator<'tcx> { fn hash(&self, state: &mut H) { let Evaluator { env_vars, - suspended: _, + _dummy: _, } = self; env_vars.iter() @@ -373,34 +298,32 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn eval_fn_call<'a>( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, - destination: Option<(Place, mir::BasicBlock)>, - args: &[ValTy<'tcx>], + destination: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, + args: &[OpTy<'tcx>], span: Span, - sig: ty::FnSig<'tcx>, ) -> EvalResult<'tcx, bool> { - ecx.eval_fn_call(instance, destination, args, span, sig) + ecx.eval_fn_call(instance, destination, args, span) } fn call_intrinsic<'a>( ecx: &mut rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, - args: &[ValTy<'tcx>], - dest: Place, - dest_layout: TyLayout<'tcx>, + args: &[OpTy<'tcx>], + dest: PlaceTy<'tcx>, target: mir::BasicBlock, ) -> EvalResult<'tcx> { - ecx.call_intrinsic(instance, args, dest, dest_layout, target) + ecx.call_intrinsic(instance, args, dest, target) } fn try_ptr_op<'a>( ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, bin_op: mir::BinOp, left: Scalar, - left_ty: ty::Ty<'tcx>, + left_layout: TyLayout<'tcx>, right: Scalar, - right_ty: ty::Ty<'tcx>, + right_layout: TyLayout<'tcx>, ) -> EvalResult<'tcx, Option<(Scalar, bool)>> { - ecx.ptr_op(bin_op, left, left_ty, right, right_ty) + ecx.ptr_op(bin_op, left, left_layout, right, right_layout) } fn mark_static_initialized<'a>( @@ -460,14 +383,16 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { let call_stackframe = ecx.stack().len(); while ecx.step()? && ecx.stack().len() >= call_stackframe { if ecx.stack().len() == call_stackframe { - let frame = ecx.frame_mut(); - let bb = &frame.mir.basic_blocks()[frame.block]; - if bb.statements.len() == frame.stmt && !bb.is_cleanup { - if let ::rustc::mir::TerminatorKind::Return = bb.terminator().kind { - for (local, _local_decl) in mir.local_decls.iter_enumerated().skip(1) { - // Don't deallocate locals, because the return value might reference them - frame.storage_dead(local); - } + let cleanup = { + let frame = ecx.frame(); + let bb = &frame.mir.basic_blocks()[frame.block]; + bb.statements.len() == frame.stmt && !bb.is_cleanup && + if let ::rustc::mir::TerminatorKind::Return = bb.terminator().kind { true } else { false } + }; + if cleanup { + for (local, _local_decl) in mir.local_decls.iter_enumerated().skip(1) { + // Don't deallocate locals, because the return value might reference them + ecx.storage_dead(local); } } } @@ -481,11 +406,9 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn box_alloc<'a>( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - ty: ty::Ty<'tcx>, - dest: Place, + dest: PlaceTy<'tcx>, ) -> EvalResult<'tcx> { - let layout = ecx.layout_of(ty)?; - + trace!("box_alloc for {:?}", dest.layout.ty); // Call the `exchange_malloc` lang item let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap(); let malloc = ty::Instance::mono(ecx.tcx.tcx, malloc); @@ -494,7 +417,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { malloc, malloc_mir.span, malloc_mir, - dest, + *dest, // Don't do anything when we are done. The statement() function will increment // the old stack frame's stmt counter to the next statement, which means that when // exchange_malloc returns, we go on evaluating exactly where we want to be. @@ -502,31 +425,18 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { )?; let mut args = ecx.frame().mir.args_iter(); - let usize = ecx.tcx.types.usize; - let ptr_size = ecx.memory.pointer_size(); + let layout = ecx.layout_of(dest.layout.ty.builtin_deref(false).unwrap().ty)?; // First argument: size - let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - ecx.write_value( - ValTy { - value: Value::Scalar(Scalar::from_uint(match layout.size.bytes() { - 0 => 1, - size => size, - }, ptr_size).into()), - ty: usize, - }, - dest, - )?; + // (0 is allowed here, this is expected to be handled by the lang item) + let arg = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; + let size = layout.size.bytes(); + ecx.write_scalar(Scalar::from_uint(size, arg.layout.size), arg)?; // Second argument: align - let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - ecx.write_value( - ValTy { - value: Value::Scalar(Scalar::from_uint(layout.align.abi(), ptr_size).into()), - ty: usize, - }, - dest, - )?; + let arg = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; + let align = layout.align.abi(); + ecx.write_scalar(Scalar::from_uint(align, arg.layout.size), arg)?; // No more arguments assert!(args.next().is_none(), "exchange_malloc lang item has more arguments than expected"); @@ -542,52 +452,32 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { } fn check_locks<'a>( - mem: &Memory<'a, 'mir, 'tcx, Self>, - ptr: Pointer, - size: Size, - access: AccessKind, + _mem: &Memory<'a, 'mir, 'tcx, Self>, + _ptr: Pointer, + _size: Size, + _access: AccessKind, ) -> EvalResult<'tcx> { - mem.check_locks(ptr, size.bytes(), access) + Ok(()) } fn add_lock<'a>( - mem: &mut Memory<'a, 'mir, 'tcx, Self>, - id: AllocId, - ) { - mem.data.locks.insert(id, RangeMap::new()); - } + _mem: &mut Memory<'a, 'mir, 'tcx, Self>, + _id: AllocId, + ) { } fn free_lock<'a>( - mem: &mut Memory<'a, 'mir, 'tcx, Self>, - id: AllocId, - len: u64, + _mem: &mut Memory<'a, 'mir, 'tcx, Self>, + _id: AllocId, + _len: u64, ) -> EvalResult<'tcx> { - mem.data.locks - .remove(&id) - .expect("allocation has no corresponding locks") - .check( - Some(mem.cur_frame), - 0, - len, - AccessKind::Read, - ) - .map_err(|lock| { - EvalErrorKind::DeallocatedLockedMemory { - //ptr, FIXME - ptr: Pointer { - alloc_id: AllocId(0), - offset: Size::from_bytes(0), - }, - lock: lock.active, - }.into() - }) + Ok(()) } fn end_region<'a>( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - reg: Option<::rustc::middle::region::Scope>, + _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + _reg: Option<::rustc::middle::region::Scope>, ) -> EvalResult<'tcx> { - ecx.end_region(reg) + Ok(()) } fn validation_op<'a>( diff --git a/src/locks.rs b/src/locks.rs index 9f4126ad82b6..a87ff6367e3a 100644 --- a/src/locks.rs +++ b/src/locks.rs @@ -1,3 +1,5 @@ +#![allow(unused)] + use super::*; use rustc::middle::region; use rustc::ty::layout::Size; @@ -6,6 +8,9 @@ use rustc::ty::layout::Size; // Locks //////////////////////////////////////////////////////////////////////////////// +// Just some dummy to keep this compiling; I think some of this will be useful later +type AbsPlace<'tcx> = ::rustc::ty::Ty<'tcx>; + /// Information about a lock that is currently held. #[derive(Clone, Debug, PartialEq, Eq)] pub struct LockInfo<'tcx> { @@ -67,321 +72,6 @@ impl<'tcx> LockInfo<'tcx> { } } -pub trait MemoryExt<'tcx> { - fn check_locks( - &self, - ptr: Pointer, - len: u64, - access: AccessKind, - ) -> EvalResult<'tcx>; - fn acquire_lock( - &mut self, - ptr: Pointer, - len: u64, - region: Option, - kind: AccessKind, - ) -> EvalResult<'tcx>; - fn suspend_write_lock( - &mut self, - ptr: Pointer, - len: u64, - lock_path: &AbsPlace<'tcx>, - suspend: Option, - ) -> EvalResult<'tcx>; - fn recover_write_lock( - &mut self, - ptr: Pointer, - len: u64, - lock_path: &AbsPlace<'tcx>, - lock_region: Option, - suspended_region: region::Scope, - ) -> EvalResult<'tcx>; - fn locks_lifetime_ended(&mut self, ending_region: Option); -} - - -impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evaluator<'tcx>> { - fn check_locks( - &self, - ptr: Pointer, - len: u64, - access: AccessKind, - ) -> EvalResult<'tcx> { - if len == 0 { - return Ok(()); - } - let locks = match self.data.locks.get(&ptr.alloc_id) { - Some(locks) => locks, - // immutable static or other constant memory - None => return Ok(()), - }; - let frame = self.cur_frame; - locks - .check(Some(frame), ptr.offset.bytes(), len, access) - .map_err(|lock| { - EvalErrorKind::MemoryLockViolation { - ptr, - len, - frame, - access, - lock: lock.active, - }.into() - }) - } - - /// Acquire the lock for the given lifetime - fn acquire_lock( - &mut self, - ptr: Pointer, - len: u64, - region: Option, - kind: AccessKind, - ) -> EvalResult<'tcx> { - let frame = self.cur_frame; - assert!(len > 0); - trace!( - "Frame {} acquiring {:?} lock at {:?}, size {} for region {:?}", - frame, - kind, - ptr, - len, - region - ); - self.check_bounds(ptr.offset(Size::from_bytes(len), &*self)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow) - - let locks = match self.data.locks.get_mut(&ptr.alloc_id) { - Some(locks) => locks, - // immutable static or other constant memory - None => return Ok(()), - }; - - // Iterate over our range and acquire the lock. If the range is already split into pieces, - // we have to manipulate all of them. - let lifetime = DynamicLifetime { frame, region }; - for lock in locks.iter_mut(ptr.offset.bytes(), len) { - if !lock.access_permitted(None, kind) { - return err!(MemoryAcquireConflict { - ptr, - len, - kind, - lock: lock.active.clone(), - }); - } - // See what we have to do - match (&mut lock.active, kind) { - (active @ &mut NoLock, AccessKind::Write) => { - *active = WriteLock(lifetime); - } - (active @ &mut NoLock, AccessKind::Read) => { - *active = ReadLock(vec![lifetime]); - } - (&mut ReadLock(ref mut lifetimes), AccessKind::Read) => { - lifetimes.push(lifetime); - } - _ => bug!("We already checked that there is no conflicting lock"), - } - } - Ok(()) - } - - /// Release or suspend a write lock of the given lifetime prematurely. - /// When releasing, if there is a read lock or someone else's write lock, that's an error. - /// If no lock is held, that's fine. This can happen when e.g. a local is initialized - /// from a constant, and then suspended. - /// When suspending, the same cases are fine; we just register an additional suspension. - fn suspend_write_lock( - &mut self, - ptr: Pointer, - len: u64, - lock_path: &AbsPlace<'tcx>, - suspend: Option, - ) -> EvalResult<'tcx> { - assert!(len > 0); - let cur_frame = self.cur_frame; - let locks = match self.data.locks.get_mut(&ptr.alloc_id) { - Some(locks) => locks, - // immutable static or other constant memory - None => return Ok(()), - }; - - 'locks: for lock in locks.iter_mut(ptr.offset.bytes(), len) { - let is_our_lock = match lock.active { - WriteLock(lft) => - // Double-check that we are holding the lock. - // (Due to subtyping, checking the region would not make any sense.) - lft.frame == cur_frame, - ReadLock(_) | NoLock => false, - }; - if is_our_lock { - trace!("Releasing {:?}", lock.active); - // Disable the lock - lock.active = NoLock; - } else { - trace!( - "Not touching {:?} as it is not our lock", - lock.active, - ); - } - // Check if we want to register a suspension - if let Some(suspend_region) = suspend { - let lock_id = WriteLockId { - frame: cur_frame, - path: lock_path.clone(), - }; - trace!("Adding suspension to {:?}", lock_id); - let mut new_suspension = false; - lock.suspended - .entry(lock_id) - // Remember whether we added a new suspension or not - .or_insert_with(|| { new_suspension = true; Vec::new() }) - .push(suspend_region); - // If the suspension is new, we should have owned this. - // If there already was a suspension, we should NOT have owned this. - if new_suspension == is_our_lock { - // All is well - continue 'locks; - } - } else if !is_our_lock { - // All is well. - continue 'locks; - } - // If we get here, releasing this is an error except for NoLock. - if lock.active != NoLock { - return err!(InvalidMemoryLockRelease { - ptr, - len, - frame: cur_frame, - lock: lock.active.clone(), - }); - } - } - - Ok(()) - } - - /// Release a suspension from the write lock. If this is the last suspension or if there is no suspension, acquire the lock. - fn recover_write_lock( - &mut self, - ptr: Pointer, - len: u64, - lock_path: &AbsPlace<'tcx>, - lock_region: Option, - suspended_region: region::Scope, - ) -> EvalResult<'tcx> { - assert!(len > 0); - let cur_frame = self.cur_frame; - let lock_id = WriteLockId { - frame: cur_frame, - path: lock_path.clone(), - }; - let locks = match self.data.locks.get_mut(&ptr.alloc_id) { - Some(locks) => locks, - // immutable static or other constant memory - None => return Ok(()), - }; - - for lock in locks.iter_mut(ptr.offset.bytes(), len) { - // Check if we have a suspension here - let (got_the_lock, remove_suspension) = match lock.suspended.get_mut(&lock_id) { - None => { - trace!("No suspension around, we can just acquire"); - (true, false) - } - Some(suspensions) => { - trace!("Found suspension of {:?}, removing it", lock_id); - // That's us! Remove suspension (it should be in there). The same suspension can - // occur multiple times (when there are multiple shared borrows of this that have the same - // lifetime); only remove one of them. - let idx = match suspensions.iter().enumerate().find(|&(_, re)| re == &suspended_region) { - None => // TODO: Can the user trigger this? - bug!("We have this lock suspended, but not for the given region."), - Some((idx, _)) => idx - }; - suspensions.remove(idx); - let got_lock = suspensions.is_empty(); - if got_lock { - trace!("All suspensions are gone, we can have the lock again"); - } - (got_lock, got_lock) - } - }; - if remove_suspension { - // with NLL, we could do that up in the match above... - assert!(got_the_lock); - lock.suspended.remove(&lock_id); - } - if got_the_lock { - match lock.active { - ref mut active @ NoLock => { - *active = WriteLock( - DynamicLifetime { - frame: cur_frame, - region: lock_region, - } - ); - } - _ => { - return err!(MemoryAcquireConflict { - ptr, - len, - kind: AccessKind::Write, - lock: lock.active.clone(), - }) - } - } - } - } - - Ok(()) - } - - fn locks_lifetime_ended(&mut self, ending_region: Option) { - let cur_frame = self.cur_frame; - trace!( - "Releasing frame {} locks that expire at {:?}", - cur_frame, - ending_region - ); - let has_ended = |lifetime: &DynamicLifetime| -> bool { - if lifetime.frame != cur_frame { - return false; - } - match ending_region { - None => true, // When a function ends, we end *all* its locks. It's okay for a function to still have lifetime-related locks - // when it returns, that can happen e.g. with NLL when a lifetime can, but does not have to, extend beyond the - // end of a function. Same for a function still having recoveries. - Some(ending_region) => lifetime.region == Some(ending_region), - } - }; - - for alloc_locks in self.data.locks.values_mut() { - for lock in alloc_locks.iter_mut_all() { - // Delete everything that ends now -- i.e., keep only all the other lifetimes. - let lock_ended = match lock.active { - WriteLock(ref lft) => has_ended(lft), - ReadLock(ref mut lfts) => { - lfts.retain(|lft| !has_ended(lft)); - lfts.is_empty() - } - NoLock => false, - }; - if lock_ended { - lock.active = NoLock; - } - // Also clean up suspended write locks when the function returns - if ending_region.is_none() { - lock.suspended.retain(|id, _suspensions| id.frame != cur_frame); - } - } - // Clean up the map - alloc_locks.retain(|lock| match lock.active { - NoLock => !lock.suspended.is_empty(), - _ => true, - }); - } - } -} - impl<'tcx> RangeMap> { pub fn check( &self, diff --git a/src/operator.rs b/src/operator.rs index 7be77771a7ca..3ff38008abd0 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,19 +1,17 @@ -use rustc::ty; -use rustc::ty::layout::Primitive; +use rustc::ty::{self, Ty}; +use rustc::ty::layout::{TyLayout, Primitive}; use rustc::mir; use super::*; -use helpers::EvalContextExt as HelperEvalContextExt; - pub trait EvalContextExt<'tcx> { fn ptr_op( &self, bin_op: mir::BinOp, left: Scalar, - left_ty: ty::Ty<'tcx>, + left_layout: TyLayout<'tcx>, right: Scalar, - right_ty: ty::Ty<'tcx>, + right_layout: TyLayout<'tcx>, ) -> EvalResult<'tcx, Option<(Scalar, bool)>>; fn ptr_int_arithmetic( @@ -23,6 +21,13 @@ pub trait EvalContextExt<'tcx> { right: i128, signed: bool, ) -> EvalResult<'tcx, (Scalar, bool)>; + + fn pointer_offset_inbounds( + &self, + ptr: Scalar, + pointee_ty: Ty<'tcx>, + offset: i64, + ) -> EvalResult<'tcx, Scalar>; } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { @@ -30,9 +35,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: &self, bin_op: mir::BinOp, left: Scalar, - left_ty: ty::Ty<'tcx>, + left_layout: TyLayout<'tcx>, right: Scalar, - right_ty: ty::Ty<'tcx>, + right_layout: TyLayout<'tcx>, ) -> EvalResult<'tcx, Option<(Scalar, bool)>> { trace!("ptr_op: {:?} {:?} {:?}", left, bin_op, right); @@ -45,7 +50,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: 8 => I64, 16 => I128, _ => unreachable!(), - }, false); + }, /*signed*/ false); let isize = Primitive::Int(match self.memory.pointer_size().bytes() { 1 => I8, 2 => I16, @@ -53,24 +58,23 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: 8 => I64, 16 => I128, _ => unreachable!(), - }, true); - let left_layout = self.layout_of(left_ty)?; + }, /*signed*/ true); let left_kind = match left_layout.abi { ty::layout::Abi::Scalar(ref scalar) => scalar.value, - _ => Err(EvalErrorKind::TypeNotPrimitive(left_ty))?, + _ => Err(EvalErrorKind::TypeNotPrimitive(left_layout.ty))?, }; - let right_layout = self.layout_of(right_ty)?; let right_kind = match right_layout.abi { ty::layout::Abi::Scalar(ref scalar) => scalar.value, - _ => Err(EvalErrorKind::TypeNotPrimitive(right_ty))?, + _ => Err(EvalErrorKind::TypeNotPrimitive(right_layout.ty))?, }; match bin_op { - Offset if left_kind == Primitive::Pointer && right_kind == usize => { - let pointee_ty = left_ty + Offset => { + assert!(left_kind == Primitive::Pointer && right_kind == usize); + let pointee_ty = left_layout.ty .builtin_deref(true) .expect("Offset called on non-ptr type") .ty; - let ptr = self.pointer_offset( + let ptr = self.pointer_offset_inbounds( left, pointee_ty, right.to_bits(self.memory.pointer_size())? as i64, @@ -114,12 +118,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Gt => left.offset > right.offset, Ge => left.offset >= right.offset, Sub => { + let left_offset = Scalar::from_uint(left.offset.bytes(), self.memory.pointer_size()); + let right_offset = Scalar::from_uint(right.offset.bytes(), self.memory.pointer_size()); + let layout = self.layout_of(self.tcx.types.usize)?; return self.binary_op( Sub, - Scalar::Bits { bits: left.offset.bytes() as u128, size: self.memory.pointer_size().bytes() as u8 }, - self.tcx.types.usize, - Scalar::Bits { bits: right.offset.bytes() as u128, size: self.memory.pointer_size().bytes() as u8 }, - self.tcx.types.usize, + ValTy { value: Value::Scalar(left_offset.into()), layout }, + ValTy { value: Value::Scalar(right_offset.into()), layout }, ).map(Some) } _ => bug!("We already established it has to be one of these operators."), @@ -200,4 +205,40 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } }) } + + /// This function raises an error if the offset moves the pointer outside of its allocation. We consider + /// ZSTs their own huge allocation that doesn't overlap with anything (and nothing moves in there because the size is 0). + /// We also consider the NULL pointer its own separate allocation, and all the remaining integers pointers their own + /// allocation. + fn pointer_offset_inbounds( + &self, + ptr: Scalar, + pointee_ty: Ty<'tcx>, + offset: i64, + ) -> EvalResult<'tcx, Scalar> { + if ptr.is_null() { + // NULL pointers must only be offset by 0 + return if offset == 0 { + Ok(ptr) + } else { + err!(InvalidNullPointerUsage) + }; + } + // FIXME: assuming here that type size is < i64::max_value() + let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; + let offset = offset.checked_mul(pointee_size).ok_or_else(|| EvalErrorKind::Overflow(mir::BinOp::Mul))?; + // Now let's see what kind of pointer this is + if let Scalar::Ptr(ptr) = ptr { + // Both old and new pointer must be in-bounds. + // (Of the same allocation, but that part is trivial with our representation.) + self.memory.check_bounds(ptr, false)?; + let ptr = ptr.signed_offset(offset, self)?; + self.memory.check_bounds(ptr, false)?; + Ok(Scalar::Ptr(ptr)) + } else { + // An integer pointer. They can move around freely, as long as they do not overflow + // (which ptr_signed_offset checks). + ptr.ptr_signed_offset(offset, self) + } + } } diff --git a/src/range_map.rs b/src/range_map.rs index 76d01ad19e3a..e55534e36fd2 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -1,3 +1,5 @@ +#![allow(unused)] + //! Implements a map from integer indices to data. //! Rather than storing data for every index, internally, this maps entire ranges to the data. //! To this end, the APIs all work on ranges, not on individual integers. Ranges are split as diff --git a/src/tls.rs b/src/tls.rs index 9f0fb2c8f62a..878884065bb7 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -119,19 +119,19 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // TODO: Potentially, this has to support all the other possible instances? // See eval_fn_call in interpret/terminator/mod.rs let mir = self.load_mir(instance.def)?; + let ret = Place::null(&self); self.push_stack_frame( instance, mir.span, mir, - Place::undef(), + ret, StackPopCleanup::None, )?; let arg_local = self.frame().mir.args_iter().next().ok_or_else( || EvalErrorKind::AbiViolation("TLS dtor does not take enough arguments.".to_owned()), )?; let dest = self.eval_place(&mir::Place::Local(arg_local))?; - let ty = self.tcx.mk_mut_ptr(self.tcx.types.u8); - self.write_ptr(dest, ptr, ty)?; + self.write_scalar(ptr, dest)?; // step until out of stackframes while self.step()? {} diff --git a/src/validation.rs b/src/validation.rs deleted file mode 100644 index 7f0abb9ae0ba..000000000000 --- a/src/validation.rs +++ /dev/null @@ -1,803 +0,0 @@ -use rustc::hir::{self, Mutability}; -use rustc::hir::Mutability::*; -use rustc::mir::{self, ValidationOp, ValidationOperand}; -use rustc::mir::interpret::GlobalId; -use rustc::ty::{self, Ty, TypeFoldable, TyCtxt, Instance}; -use rustc::ty::layout::{LayoutOf, PrimitiveExt}; -use rustc::ty::subst::{Substs, Subst}; -use rustc::traits::{self, TraitEngine}; -use rustc::infer::InferCtxt; -use rustc::middle::region; -use rustc::mir::interpret::{ConstValue}; -use rustc_data_structures::indexed_vec::Idx; -use rustc_mir::interpret::HasMemory; - -use super::{EvalContext, Place, PlaceExtra, ValTy, ScalarExt}; -use rustc::mir::interpret::{DynamicLifetime, AccessKind, EvalErrorKind, Value, EvalError, EvalResult}; -use locks::MemoryExt; - -pub type ValidationQuery<'tcx> = ValidationOperand<'tcx, (AbsPlace<'tcx>, Place)>; - -#[derive(Copy, Clone, Debug, PartialEq)] -pub(crate) enum ValidationMode { - Acquire, - /// Recover because the given region ended - Recover(region::Scope), - ReleaseUntil(Option), -} - -impl ValidationMode { - fn acquiring(self) -> bool { - use self::ValidationMode::*; - match self { - Acquire | Recover(_) => true, - ReleaseUntil(_) => false, - } - } -} - -// Abstract places -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub enum AbsPlace<'tcx> { - Local(mir::Local), - Static(hir::def_id::DefId), - Projection(Box>), -} - -type AbsPlaceProjection<'tcx> = mir::Projection<'tcx, AbsPlace<'tcx>, u64, ()>; -type AbsPlaceElem<'tcx> = mir::ProjectionElem<'tcx, u64, ()>; - -impl<'tcx> AbsPlace<'tcx> { - pub fn field(self, f: mir::Field) -> AbsPlace<'tcx> { - self.elem(mir::ProjectionElem::Field(f, ())) - } - - pub fn deref(self) -> AbsPlace<'tcx> { - self.elem(mir::ProjectionElem::Deref) - } - - pub fn downcast(self, adt_def: &'tcx ty::AdtDef, variant_index: usize) -> AbsPlace<'tcx> { - self.elem(mir::ProjectionElem::Downcast(adt_def, variant_index)) - } - - pub fn index(self, index: u64) -> AbsPlace<'tcx> { - self.elem(mir::ProjectionElem::Index(index)) - } - - fn elem(self, elem: AbsPlaceElem<'tcx>) -> AbsPlace<'tcx> { - AbsPlace::Projection(Box::new(AbsPlaceProjection { - base: self, - elem, - })) - } -} - -pub(crate) trait EvalContextExt<'tcx> { - fn abstract_place_projection(&self, proj: &mir::PlaceProjection<'tcx>) -> EvalResult<'tcx, AbsPlaceProjection<'tcx>>; - fn abstract_place(&self, place: &mir::Place<'tcx>) -> EvalResult<'tcx, AbsPlace<'tcx>>; - fn validation_op( - &mut self, - op: ValidationOp, - operand: &ValidationOperand<'tcx, mir::Place<'tcx>>, - ) -> EvalResult<'tcx>; - fn end_region(&mut self, scope: Option) -> EvalResult<'tcx>; - fn normalize_type_unerased(&self, ty: Ty<'tcx>) -> Ty<'tcx>; - fn field_with_lifetimes( - &mut self, - base: Place, - layout: ty::layout::TyLayout<'tcx>, - i: usize, - ) -> EvalResult<'tcx, Ty<'tcx>>; - fn validate_fields( - &mut self, - query: ValidationQuery<'tcx>, - mode: ValidationMode, - ) -> EvalResult<'tcx>; - fn validate_ptr( - &mut self, - val: Value, - abs_place: AbsPlace<'tcx>, - pointee_ty: Ty<'tcx>, - re: Option, - mutbl: Mutability, - mode: ValidationMode, - ) -> EvalResult<'tcx>; - fn validate( - &mut self, - query: ValidationQuery<'tcx>, - mode: ValidationMode, - ) -> EvalResult<'tcx>; -} - -impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { - fn abstract_place_projection(&self, proj: &mir::PlaceProjection<'tcx>) -> EvalResult<'tcx, AbsPlaceProjection<'tcx>> { - use self::mir::ProjectionElem::*; - - let elem = match proj.elem { - Deref => Deref, - Field(f, _) => Field(f, ()), - Index(v) => { - let value = self.frame().locals[v].access()?; - let ty = self.tcx.tcx.types.usize; - let n = self.value_to_scalar(ValTy { value, ty })?.to_usize(self)?; - Index(n) - }, - ConstantIndex { offset, min_length, from_end } => - ConstantIndex { offset, min_length, from_end }, - Subslice { from, to } => - Subslice { from, to }, - Downcast(adt, sz) => Downcast(adt, sz), - }; - Ok(AbsPlaceProjection { - base: self.abstract_place(&proj.base)?, - elem - }) - } - - fn abstract_place(&self, place: &mir::Place<'tcx>) -> EvalResult<'tcx, AbsPlace<'tcx>> { - Ok(match *place { - mir::Place::Local(l) => AbsPlace::Local(l), - mir::Place::Static(ref s) => AbsPlace::Static(s.def_id), - mir::Place::Projection(ref p) => - AbsPlace::Projection(Box::new(self.abstract_place_projection(&*p)?)), - _ => unimplemented!("validation is not currently maintained"), - }) - } - - // Validity checks - fn validation_op( - &mut self, - op: ValidationOp, - operand: &ValidationOperand<'tcx, mir::Place<'tcx>>, - ) -> EvalResult<'tcx> { - // If mir-emit-validate is set to 0 (i.e., disabled), we may still see validation commands - // because other crates may have been compiled with mir-emit-validate > 0. Ignore those - // commands. This makes mir-emit-validate also a flag to control whether miri will do - // validation or not. - if self.tcx.tcx.sess.opts.debugging_opts.mir_emit_validate == 0 { - return Ok(()); - } - debug_assert!(self.memory.cur_frame == self.cur_frame()); - - // We need to monomorphize ty *without* erasing lifetimes - trace!("validation_op1: {:?}", operand.ty.sty); - let ty = operand.ty.subst(self.tcx.tcx, self.substs()); - trace!("validation_op2: {:?}", operand.ty.sty); - let place = self.eval_place(&operand.place)?; - let abs_place = self.abstract_place(&operand.place)?; - let query = ValidationQuery { - place: (abs_place, place), - ty, - re: operand.re, - mutbl: operand.mutbl, - }; - - // Check the mode, and also perform mode-specific operations - let mode = match op { - ValidationOp::Acquire => ValidationMode::Acquire, - ValidationOp::Release => ValidationMode::ReleaseUntil(None), - ValidationOp::Suspend(scope) => { - if query.mutbl == MutMutable { - let lft = DynamicLifetime { - frame: self.cur_frame(), - region: Some(scope), // Notably, we only ever suspend things for given regions. - // Suspending for the entire function does not make any sense. - }; - trace!("Suspending {:?} until {:?}", query, scope); - self.machine.suspended.entry(lft).or_insert_with(Vec::new).push( - query.clone(), - ); - } - ValidationMode::ReleaseUntil(Some(scope)) - } - }; - self.validate(query, mode) - } - - /// Release locks and executes suspensions of the given region (or the entire fn, in case of None). - fn end_region(&mut self, scope: Option) -> EvalResult<'tcx> { - debug_assert!(self.memory.cur_frame == self.cur_frame()); - self.memory.locks_lifetime_ended(scope); - match scope { - Some(scope) => { - // Recover suspended places - let lft = DynamicLifetime { - frame: self.cur_frame(), - region: Some(scope), - }; - if let Some(queries) = self.machine.suspended.remove(&lft) { - for query in queries { - trace!("Recovering {:?} from suspension", query); - self.validate(query, ValidationMode::Recover(scope))?; - } - } - } - None => { - // Clean suspension table of current frame - let cur_frame = self.cur_frame(); - self.machine.suspended.retain(|lft, _| { - lft.frame != cur_frame // keep only what is in the other (lower) frames - }); - } - } - Ok(()) - } - - fn normalize_type_unerased(&self, ty: Ty<'tcx>) -> Ty<'tcx> { - return normalize_associated_type(self.tcx.tcx, &ty); - - use syntax::codemap::{Span, DUMMY_SP}; - - // We copy a bunch of stuff from rustc/infer/mod.rs to be able to tweak its behavior - fn normalize_projections_in<'a, 'gcx, 'tcx, T>( - self_: &InferCtxt<'a, 'gcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - value: &T, - ) -> T::Lifted - where - T: TypeFoldable<'tcx> + ty::Lift<'gcx>, - { - let mut selcx = traits::SelectionContext::new(self_); - let cause = traits::ObligationCause::dummy(); - let traits::Normalized { - value: result, - obligations, - } = traits::normalize(&mut selcx, param_env, cause, value); - - let mut fulfill_cx = traits::FulfillmentContext::new(); - - for obligation in obligations { - fulfill_cx.register_predicate_obligation(self_, obligation); - } - - drain_fulfillment_cx_or_panic(self_, DUMMY_SP, &mut fulfill_cx, &result) - } - - fn drain_fulfillment_cx_or_panic<'a, 'gcx, 'tcx, T>( - self_: &InferCtxt<'a, 'gcx, 'tcx>, - span: Span, - fulfill_cx: &mut traits::FulfillmentContext<'tcx>, - result: &T, - ) -> T::Lifted - where - T: TypeFoldable<'tcx> + ty::Lift<'gcx>, - { - // In principle, we only need to do this so long as `result` - // contains unbound type parameters. It could be a slight - // optimization to stop iterating early. - match fulfill_cx.select_all_or_error(self_) { - Ok(()) => { } - Err(errors) => { - span_bug!( - span, - "Encountered errors `{:?}` resolving bounds after type-checking", - errors - ); - } - } - - let result = self_.resolve_type_vars_if_possible(result); - let result = self_.tcx.fold_regions( - &result, - &mut false, - |r, _| match *r { - ty::ReVar(_) => self_.tcx.types.re_erased, - _ => r, - }, - ); - - match self_.tcx.lift_to_global(&result) { - Some(result) => result, - None => { - span_bug!(span, "Uninferred types/regions in `{:?}`", result); - } - } - } - - trait MyTransNormalize<'gcx>: TypeFoldable<'gcx> { - fn my_trans_normalize<'a, 'tcx>( - &self, - infcx: &InferCtxt<'a, 'gcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> Self; - } - - macro_rules! items { ($($item:item)+) => ($($item)+) } - macro_rules! impl_trans_normalize { - ($lt_gcx:tt, $($ty:ty),+) => { - items!($(impl<$lt_gcx> MyTransNormalize<$lt_gcx> for $ty { - fn my_trans_normalize<'a, 'tcx>(&self, - infcx: &InferCtxt<'a, $lt_gcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>) - -> Self { - normalize_projections_in(infcx, param_env, self) - } - })+); - } - } - - impl_trans_normalize!('gcx, - Ty<'gcx>, - &'gcx Substs<'gcx>, - ty::FnSig<'gcx>, - ty::PolyFnSig<'gcx>, - ty::ClosureSubsts<'gcx>, - ty::PolyTraitRef<'gcx>, - ty::ExistentialTraitRef<'gcx> - ); - - fn normalize_associated_type<'a, 'tcx, T>(self_: TyCtxt<'a, 'tcx, 'tcx>, value: &T) -> T - where - T: MyTransNormalize<'tcx>, - { - let param_env = ty::ParamEnv::reveal_all(); - - if !value.has_projections() { - return value.clone(); - } - - self_.infer_ctxt().enter(|infcx| { - value.my_trans_normalize(&infcx, param_env) - }) - } - } - - // This is a copy of `Layout::field` - // - // FIXME: remove once validation does not depend on lifetimes - fn field_with_lifetimes( - &mut self, - base: Place, - mut layout: ty::layout::TyLayout<'tcx>, - i: usize, - ) -> EvalResult<'tcx, Ty<'tcx>> { - if let Place::Ptr { extra: PlaceExtra::DowncastVariant(variant_index), .. } = base { - layout = layout.for_variant(&self, variant_index); - } - let tcx = self.tcx.tcx; - Ok(match layout.ty.sty { - ty::TyBool | - ty::TyChar | - ty::TyInt(_) | - ty::TyUint(_) | - ty::TyFloat(_) | - ty::TyFnPtr(_) | - ty::TyNever | - ty::TyFnDef(..) | - ty::TyGeneratorWitness(..) | - ty::TyDynamic(..) | - ty::TyForeign(..) => { - bug!("TyLayout::field_type({:?}): not applicable", layout) - } - - // Potentially-fat pointers. - ty::TyRef(_, pointee, _) | - ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => { - assert!(i < 2); - - // Reuse the fat *T type as its own thin pointer data field. - // This provides information about e.g. DST struct pointees - // (which may have no non-DST form), and will work as long - // as the `Abi` or `FieldPlacement` is checked by users. - if i == 0 { - return Ok(layout.ty); - } - - match tcx.struct_tail(pointee).sty { - ty::TySlice(_) | - ty::TyStr => tcx.types.usize, - ty::TyDynamic(..) => { - // FIXME(eddyb) use an usize/fn() array with - // the correct number of vtables slots. - tcx.mk_imm_ref(tcx.types.re_static, tcx.mk_nil()) - } - _ => bug!("TyLayout::field_type({:?}): not applicable", layout) - } - } - - // Arrays and slices. - ty::TyArray(element, _) | - ty::TySlice(element) => element, - ty::TyStr => tcx.types.u8, - - // Tuples, generators and closures. - ty::TyClosure(def_id, ref substs) => { - substs.upvar_tys(def_id, tcx).nth(i).unwrap() - } - - ty::TyGenerator(def_id, ref substs, _) => { - substs.field_tys(def_id, tcx).nth(i).unwrap() - } - - ty::TyTuple(tys) => tys[i], - - // SIMD vector types. - ty::TyAdt(def, ..) if def.repr.simd() => { - layout.ty.simd_type(tcx) - } - - // ADTs. - ty::TyAdt(def, substs) => { - use rustc::ty::layout::Variants; - match layout.variants { - Variants::Single { index } => { - def.variants[index].fields[i].ty(tcx, substs) - } - - // Discriminant field for enums (where applicable). - Variants::Tagged { tag: ref discr, .. } | - Variants::NicheFilling { niche: ref discr, .. } => { - assert_eq!(i, 0); - return Ok(discr.value.to_ty(tcx)) - } - } - } - - ty::TyProjection(_) | ty::TyAnon(..) | ty::TyParam(_) | - ty::TyInfer(_) | ty::TyError => { - bug!("TyLayout::field_type: unexpected type `{}`", layout.ty) - } - }) - } - - fn validate_fields( - &mut self, - query: ValidationQuery<'tcx>, - mode: ValidationMode, - ) -> EvalResult<'tcx> { - let mut layout = self.layout_of(query.ty)?; - layout.ty = query.ty; - - // TODO: Maybe take visibility/privacy into account. - for idx in 0..layout.fields.count() { - let field = mir::Field::new(idx); - let (field_place, field_layout) = - self.place_field(query.place.1, field, layout)?; - // layout stuff erases lifetimes, get the field ourselves - let field_ty = self.field_with_lifetimes(query.place.1, layout, idx)?; - trace!("assuming \n{:?}\n == \n{:?}\n except for lifetimes", field_layout.ty, field_ty); - self.validate( - ValidationQuery { - place: (query.place.0.clone().field(field), field_place), - ty: field_ty, - ..query - }, - mode, - )?; - } - - Ok(()) - } - - fn validate_ptr( - &mut self, - val: Value, - abs_place: AbsPlace<'tcx>, - pointee_ty: Ty<'tcx>, - re: Option, - mutbl: Mutability, - mode: ValidationMode, - ) -> EvalResult<'tcx> { - // Check alignment and non-NULLness - let (_, align) = self.size_and_align_of_dst(pointee_ty, val)?; - let ptr = self.into_ptr(val)?.unwrap_or_err()?; - self.memory.check_align(ptr, align)?; - - // Recurse - let pointee_place = self.val_to_place(val, pointee_ty)?; - self.validate( - ValidationQuery { - place: (abs_place.deref(), pointee_place), - ty: pointee_ty, - re, - mutbl, - }, - mode, - ) - } - - /// Validate the place at the given type. If `acquire` is false, just do a release of all write locks - fn validate( - &mut self, - mut query: ValidationQuery<'tcx>, - mode: ValidationMode, - ) -> EvalResult<'tcx> { - use rustc::ty::TypeVariants::*; - use rustc::ty::RegionKind::*; - use rustc::ty::AdtKind; - - // No point releasing shared stuff. - if !mode.acquiring() && query.mutbl == MutImmutable { - return Ok(()); - } - // When we recover, we may see data whose validity *just* ended. Do not acquire it. - if let ValidationMode::Recover(ending_ce) = mode { - if query.re == Some(ending_ce) { - return Ok(()); - } - } - - query.ty = self.normalize_type_unerased(&query.ty); - trace!("{:?} on {:#?}", mode, query); - trace!("{:#?}", query.ty.sty); - - // Decide whether this type *owns* the memory it covers (like integers), or whether it - // just assembles pieces (that each own their memory) together to a larger whole. - // TODO: Currently, we don't acquire locks for padding and discriminants. We should. - let is_owning = match query.ty.sty { - TyInt(_) | TyUint(_) | TyRawPtr(_) | TyBool | TyFloat(_) | TyChar | TyStr | - TyRef(..) | TyFnPtr(..) | TyFnDef(..) | TyNever => true, - TyAdt(adt, _) if adt.is_box() => true, - TySlice(_) | TyAdt(_, _) | TyTuple(..) | TyClosure(..) | TyArray(..) | - TyDynamic(..) | TyGenerator(..) | TyForeign(_) => false, - TyGeneratorWitness(..) => unreachable!("TyGeneratorWitness in validate"), - TyParam(_) | TyInfer(_) | TyProjection(_) | TyAnon(..) | TyError => { - bug!("I got an incomplete/unnormalized type for validation") - } - }; - if is_owning { - // We need to lock. So we need memory. So we have to force_acquire. - // Tracking the same state for locals not backed by memory would just duplicate too - // much machinery. - // FIXME: We ignore alignment. - let (ptr, _, extra) = self.force_allocation(query.place.1)?.to_ptr_align_extra(); - // Determine the size - // FIXME: Can we reuse size_and_align_of_dst for Places? - let layout = self.layout_of(query.ty)?; - let len = if !layout.is_unsized() { - assert_eq!(extra, PlaceExtra::None, "Got a fat ptr to a sized type"); - layout.size.bytes() - } else { - // The only unsized typ we concider "owning" is TyStr. - assert_eq!( - query.ty.sty, - TyStr, - "Found a surprising unsized owning type" - ); - // The extra must be the length, in bytes. - match extra { - PlaceExtra::Length(len) => len, - _ => bug!("TyStr must have a length as extra"), - } - }; - // Handle locking - if len > 0 { - let ptr = ptr.unwrap_or_err()?.to_ptr()?; - match query.mutbl { - MutImmutable => { - if mode.acquiring() { - self.memory.acquire_lock( - ptr, - len, - query.re, - AccessKind::Read, - )?; - } - } - // No releasing of read locks, ever. - MutMutable => { - match mode { - ValidationMode::Acquire => { - self.memory.acquire_lock( - ptr, - len, - query.re, - AccessKind::Write, - )? - } - ValidationMode::Recover(ending_ce) => { - self.memory.recover_write_lock( - ptr, - len, - &query.place.0, - query.re, - ending_ce, - )? - } - ValidationMode::ReleaseUntil(suspended_ce) => { - self.memory.suspend_write_lock( - ptr, - len, - &query.place.0, - suspended_ce, - )? - } - } - } - } - } - } - - let res: EvalResult<'tcx> = do catch { - match query.ty.sty { - TyInt(_) | TyUint(_) | TyRawPtr(_) => { - if mode.acquiring() { - // Make sure we can read this. - let val = self.read_place(query.place.1)?; - self.follow_by_ref_value(val, query.ty)?; - // FIXME: It would be great to rule out Undef here, but that doesn't actually work. - // Passing around undef data is a thing that e.g. Vec::extend_with does. - } - } - TyBool | TyFloat(_) | TyChar => { - if mode.acquiring() { - let val = self.read_place(query.place.1)?; - let val = self.value_to_scalar(ValTy { value: val, ty: query.ty })?; - val.to_bytes()?; - // TODO: Check if these are valid bool/float/codepoint/UTF-8 - } - } - TyNever => return err!(ValidationFailure(format!("The empty type is never valid."))), - TyRef(region, pointee_ty, mutbl) => { - let val = self.read_place(query.place.1)?; - // Sharing restricts our context - if mutbl == MutImmutable { - query.mutbl = MutImmutable; - } - // Inner lifetimes *outlive* outer ones, so only if we have no lifetime restriction yet, - // we record the region of this borrow to the context. - if query.re == None { - if let ReScope(scope) = *region { - query.re = Some(scope); - } - // It is possible for us to encounter erased lifetimes here because the lifetimes in - // this functions' Subst will be erased. - } - self.validate_ptr(val, query.place.0, pointee_ty, query.re, query.mutbl, mode)?; - } - TyAdt(adt, _) if adt.is_box() => { - let val = self.read_place(query.place.1)?; - self.validate_ptr(val, query.place.0, query.ty.boxed_ty(), query.re, query.mutbl, mode)?; - } - TyFnPtr(_sig) => { - let ptr = self.read_place(query.place.1)?; - let ptr = self.into_ptr(ptr)?.unwrap_or_err()?.to_ptr()?; - self.memory.get_fn(ptr)?; - // TODO: Check if the signature matches (should be the same check as what terminator/mod.rs already does on call?). - } - TyFnDef(..) => { - // This is a zero-sized type with all relevant data sitting in the type. - // There is nothing to validate. - } - - // Compound types - TyStr => { - // TODO: Validate strings - } - TySlice(elem_ty) => { - let len = match query.place.1 { - Place::Ptr { extra: PlaceExtra::Length(len), .. } => len, - _ => { - bug!( - "acquire_valid of a TySlice given non-slice place: {:?}", - query.place - ) - } - }; - for i in 0..len { - let inner_place = self.place_index(query.place.1, query.ty, i)?; - self.validate( - ValidationQuery { - place: (query.place.0.clone().index(i), inner_place), - ty: elem_ty, - ..query - }, - mode, - )?; - } - } - TyArray(elem_ty, len) => { - let len = match len.val { - ConstValue::Unevaluated(def_id, substs) => { - self.tcx.const_eval(self.tcx.param_env(def_id).and(GlobalId { - instance: Instance::new(def_id, substs), - promoted: None, - })) - .map_err(|_err|EvalErrorKind::MachineError("".to_string()))? - } - _ => len, - }; - let len = len.unwrap_usize(self.tcx.tcx); - for i in 0..len { - let inner_place = self.place_index(query.place.1, query.ty, i as u64)?; - self.validate( - ValidationQuery { - place: (query.place.0.clone().index(i as u64), inner_place), - ty: elem_ty, - ..query - }, - mode, - )?; - } - } - TyDynamic(_data, _region) => { - // Check that this is a valid vtable - let vtable = match query.place.1 { - Place::Ptr { extra: PlaceExtra::Vtable(vtable), .. } => vtable, - _ => { - bug!( - "acquire_valid of a TyDynamic given non-trait-object place: {:?}", - query.place - ) - } - }; - self.read_size_and_align_from_vtable(vtable)?; - // TODO: Check that the vtable contains all the function pointers we expect it to have. - // Trait objects cannot have any operations performed - // on them directly. We cannot, in general, even acquire any locks as the trait object *could* - // contain an UnsafeCell. If we call functions to get access to data, we will validate - // their return values. So, it doesn't seem like there's anything else to do. - } - TyAdt(adt, _) => { - if Some(adt.did) == self.tcx.tcx.lang_items().unsafe_cell_type() && - query.mutbl == MutImmutable - { - // No locks for shared unsafe cells. Also no other validation, the only field is private anyway. - return Ok(()); - } - - match adt.adt_kind() { - AdtKind::Enum => { - let layout = self.layout_of(query.ty)?; - let variant_idx = self.read_discriminant_as_variant_index(query.place.1, layout)?; - let variant = &adt.variants[variant_idx]; - - if !variant.fields.is_empty() { - // Downcast to this variant, if needed - let place = if adt.is_enum() { - ( - query.place.0.downcast(adt, variant_idx), - self.eval_place_projection( - query.place.1, - query.ty, - &mir::ProjectionElem::Downcast(adt, variant_idx), - )?, - ) - } else { - query.place - }; - - // Recursively validate the fields - self.validate_fields( - ValidationQuery { place, ..query }, - mode, - )?; - } else { - // No fields, nothing left to check. Downcasting may fail, e.g. in case of a CEnum. - } - } - AdtKind::Struct => { - self.validate_fields(query, mode)?; - } - AdtKind::Union => { - // No guarantees are provided for union types. - // TODO: Make sure that all access to union fields is unsafe; otherwise, we may have some checking to do (but what exactly?) - } - } - } - TyTuple(..) | - TyClosure(..) => { - // TODO: Check if the signature matches for `TyClosure` - // (should be the same check as what terminator/mod.rs already does on call?). - // Is there other things we can/should check? Like vtable pointers? - self.validate_fields(query, mode)?; - } - // FIXME: generators aren't validated right now - TyGenerator(..) => {}, - _ => bug!("We already established that this is a type we support. ({})", query.ty), - } - }; - match res { - // ReleaseUntil(None) of an uninitalized variable is a NOP. This is needed because - // we have to release the return value of a function; due to destination-passing-style - // the callee may directly write there. - // TODO: Ideally we would know whether the destination is already initialized, and only - // release if it is. But of course that can't even always be statically determined. - Err(EvalError { kind: EvalErrorKind::ReadUndefBytes, .. }) - if mode == ValidationMode::ReleaseUntil(None) => { - Ok(()) - } - res => res, - } - } -} diff --git a/tests/run-pass/atomic-compare_exchange.rs b/tests/run-pass/atomic-compare_exchange.rs index 61e9a9658896..ec8e16d33e42 100644 --- a/tests/run-pass/atomic-compare_exchange.rs +++ b/tests/run-pass/atomic-compare_exchange.rs @@ -15,18 +15,22 @@ static ATOMIC: AtomicIsize = ATOMIC_ISIZE_INIT; fn main() { // Make sure trans can emit all the intrinsics correctly - ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed).ok(); - ATOMIC.compare_exchange(0, 1, Acquire, Relaxed).ok(); - ATOMIC.compare_exchange(0, 1, Release, Relaxed).ok(); - ATOMIC.compare_exchange(0, 1, AcqRel, Relaxed).ok(); + assert_eq!(ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed), Ok(0)); + assert_eq!(ATOMIC.compare_exchange(0, 2, Acquire, Relaxed), Err(1)); + assert_eq!(ATOMIC.compare_exchange(0, 1, Release, Relaxed), Err(1)); + assert_eq!(ATOMIC.compare_exchange(1, 0, AcqRel, Relaxed), Ok(1)); ATOMIC.compare_exchange(0, 1, SeqCst, Relaxed).ok(); ATOMIC.compare_exchange(0, 1, Acquire, Acquire).ok(); ATOMIC.compare_exchange(0, 1, AcqRel, Acquire).ok(); ATOMIC.compare_exchange(0, 1, SeqCst, Acquire).ok(); ATOMIC.compare_exchange(0, 1, SeqCst, SeqCst).ok(); - ATOMIC.compare_exchange_weak(0, 1, Relaxed, Relaxed).ok(); - ATOMIC.compare_exchange_weak(0, 1, Acquire, Relaxed).ok(); - ATOMIC.compare_exchange_weak(0, 1, Release, Relaxed).ok(); + + ATOMIC.store(0, SeqCst); + + assert_eq!(ATOMIC.compare_exchange_weak(0, 1, Relaxed, Relaxed), Ok(0)); + assert_eq!(ATOMIC.compare_exchange_weak(0, 2, Acquire, Relaxed), Err(1)); + assert_eq!(ATOMIC.compare_exchange_weak(0, 1, Release, Relaxed), Err(1)); + assert_eq!(ATOMIC.compare_exchange_weak(1, 0, AcqRel, Relaxed), Ok(1)); ATOMIC.compare_exchange_weak(0, 1, AcqRel, Relaxed).ok(); ATOMIC.compare_exchange_weak(0, 1, SeqCst, Relaxed).ok(); ATOMIC.compare_exchange_weak(0, 1, Acquire, Acquire).ok(); From c424e21692835963cab65949d4c2421fcd05a614 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 16 Aug 2018 11:35:38 +0200 Subject: [PATCH 0185/5092] update for memory signedness removal; test some float casts --- src/fn_call.rs | 1 - tests/run-pass/floats.rs | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 559f3adb90f1..08db6a029cbe 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -526,7 +526,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Scalar::from_uint(key, key_layout.size).into(), key_layout.size, key_layout.align, - false, )?; // Return success (0) diff --git a/tests/run-pass/floats.rs b/tests/run-pass/floats.rs index 9c4d0594d1c9..39fdbce49202 100644 --- a/tests/run-pass/floats.rs +++ b/tests/run-pass/floats.rs @@ -8,4 +8,8 @@ fn main() { let x: u64 = unsafe { std::mem::transmute(42.0_f64) }; let y: f64 = unsafe { std::mem::transmute(x) }; assert_eq!(y, 42.0_f64); + + assert_eq!(5.0f32 as u32, 5); + assert_eq!(5.0f32 as i32, 5); + assert_eq!(-5.0f32 as i32, -5); } From ea27e46a3859d20b8740738ee3efea16e0a87e2e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 17 Aug 2018 09:36:53 +0200 Subject: [PATCH 0186/5092] fix compilation after rustc change --- src/helpers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers.rs b/src/helpers.rs index 606f1bb4ecb4..88dd351513a5 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,7 +1,7 @@ use rustc::ty::layout::{Size, HasDataLayout}; +use rustc::mir::interpret::sign_extend; use super::{Scalar, ScalarMaybeUndef, EvalResult}; -use rustc_mir::interpret::sign_extend; pub trait ScalarExt { fn null(size: Size) -> Self; From 6203bf445f1c7abd958ea1f79feb311381ace502 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 18 Aug 2018 11:59:28 +0200 Subject: [PATCH 0187/5092] update for rustc memory changes; fix (un)init intrinsic for ZST --- src/fn_call.rs | 3 +-- src/intrinsic.rs | 62 ++++++++++++++++++++++++++---------------------- 2 files changed, 34 insertions(+), 31 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 08db6a029cbe..605b63a10ea4 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -498,7 +498,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // Hook pthread calls that go to the thread-local storage memory subsystem "pthread_key_create" => { - let key_ptr = self.read_scalar(args[0])?.not_undef()?; + let key_ptr = self.read_scalar(args[0])?.to_ptr()?; // Extract the function type out of the signature (that seems easier than constructing it ourselves...) let dtor = match self.read_scalar(args[1])?.not_undef()? { @@ -525,7 +525,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' key_layout.align, Scalar::from_uint(key, key_layout.size).into(), key_layout.size, - key_layout.align, )?; // Return success (0) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 631653b97b6b..47399c390796 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -295,21 +295,23 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "init" => { // Check fast path: we don't want to force an allocation in case the destination is a simple value, // but we also do not want to create a new allocation with 0s and then copy that over. - match dest.layout.abi { - layout::Abi::Scalar(ref s) => { - let x = Scalar::null(s.value.size(&self)); - self.write_value(Value::Scalar(x.into()), dest)?; - } - layout::Abi::ScalarPair(ref s1, ref s2) => { - let x = Scalar::null(s1.value.size(&self)); - let y = Scalar::null(s2.value.size(&self)); - self.write_value(Value::ScalarPair(x.into(), y.into()), dest)?; - } - _ => { - // Do it in memory - let mplace = self.force_allocation(dest)?; - assert_eq!(mplace.extra, PlaceExtra::None); - self.memory.write_repeat(mplace.ptr, 0, dest.layout.size)?; + if !dest.layout.is_zst() { // notzhing to do for ZST + match dest.layout.abi { + layout::Abi::Scalar(ref s) => { + let x = Scalar::null(s.value.size(&self)); + self.write_value(Value::Scalar(x.into()), dest)?; + } + layout::Abi::ScalarPair(ref s1, ref s2) => { + let x = Scalar::null(s1.value.size(&self)); + let y = Scalar::null(s2.value.size(&self)); + self.write_value(Value::ScalarPair(x.into(), y.into()), dest)?; + } + _ => { + // Do it in memory + let mplace = self.force_allocation(dest)?; + assert_eq!(mplace.extra, PlaceExtra::None); + self.memory.write_repeat(mplace.ptr, 0, dest.layout.size)?; + } } } } @@ -571,20 +573,22 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "uninit" => { // Check fast path: we don't want to force an allocation in case the destination is a simple value, // but we also do not want to create a new allocation with 0s and then copy that over. - match dest.layout.abi { - layout::Abi::Scalar(..) => { - let x = ScalarMaybeUndef::Undef; - self.write_value(Value::Scalar(x), dest)?; - } - layout::Abi::ScalarPair(..) => { - let x = ScalarMaybeUndef::Undef; - self.write_value(Value::ScalarPair(x, x), dest)?; - } - _ => { - // Do it in memory - let mplace = self.force_allocation(dest)?; - assert_eq!(mplace.extra, PlaceExtra::None); - self.memory.mark_definedness(mplace.ptr, dest.layout.size, false)?; + if !dest.layout.is_zst() { // nothing to do for ZST + match dest.layout.abi { + layout::Abi::Scalar(..) => { + let x = ScalarMaybeUndef::Undef; + self.write_value(Value::Scalar(x), dest)?; + } + layout::Abi::ScalarPair(..) => { + let x = ScalarMaybeUndef::Undef; + self.write_value(Value::ScalarPair(x, x), dest)?; + } + _ => { + // Do it in memory + let mplace = self.force_allocation(dest)?; + assert_eq!(mplace.extra, PlaceExtra::None); + self.memory.mark_definedness(mplace.ptr.to_ptr()?, dest.layout.size, false)?; + } } } } From 1a23b3c313507c89d1fb3af9023ba058231f4254 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 20 Aug 2018 16:27:23 +0200 Subject: [PATCH 0188/5092] rustup --- src/fn_call.rs | 2 +- src/lib.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 605b63a10ea4..b4c8c6f0f431 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -3,7 +3,7 @@ use rustc::ty::layout::{Align, LayoutOf, Size}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use syntax::attr; -use syntax::codemap::Span; +use syntax::source_map::Span; use std::mem; diff --git a/src/lib.rs b/src/lib.rs index 3680d49836fb..044ce28b3014 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,7 @@ use rustc::mir; use rustc_data_structures::fx::FxHasher; use syntax::ast::Mutability; -use syntax::codemap::Span; +use syntax::source_map::Span; use std::marker::PhantomData; use std::collections::{HashMap, BTreeMap}; @@ -57,7 +57,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( start_wrapper: Option, ) -> EvalResult<'tcx, (EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>, Option)> { let mut ecx = EvalContext::new( - tcx.at(syntax::codemap::DUMMY_SP), + tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), Default::default(), MemoryData::new() From 68194180a835f30b4fec5fd04b754c4a38107167 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 Aug 2018 09:29:27 +0200 Subject: [PATCH 0189/5092] fix type renaming --- src/fn_call.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index b4c8c6f0f431..d8afe0878998 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -60,7 +60,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // Return None, as it doesn't make sense to return Some, because miri detects stack overflow itself. let (return_place, return_to_block) = destination.unwrap(); match return_place.layout.ty.sty { - ty::TyAdt(ref adt_def, _) => { + ty::Adt(ref adt_def, _) => { assert!(adt_def.is_enum(), "Unexpected return type for {}", item_path); let none_variant_index = adt_def.variants.iter().position(|def| { def.name.as_str() == "None" From 1a4ad2bb9fe3216010f33b47c6b05debaef7d604 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 Aug 2018 19:28:48 +0200 Subject: [PATCH 0190/5092] update for miri engine: new function handling, new static handling, fixed leaks --- src/fn_call.rs | 179 +++++++++--------- src/helpers.rs | 52 +---- src/intrinsic.rs | 87 +-------- src/lib.rs | 163 +++------------- src/memory.rs | 18 +- src/tls.rs | 2 +- tests/compile-fail/memleak.rs | 1 - tests/compile-fail/memleak_rc.rs | 1 - tests/compile-fail/modifying_constants.rs | 1 - .../static_memory_modification.rs | 1 - tests/run-pass/pthreads.rs | 14 ++ 11 files changed, 149 insertions(+), 370 deletions(-) create mode 100644 tests/run-pass/pthreads.rs diff --git a/src/fn_call.rs b/src/fn_call.rs index d8afe0878998..6e3fcf7d4489 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -3,7 +3,6 @@ use rustc::ty::layout::{Align, LayoutOf, Size}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use syntax::attr; -use syntax::source_map::Span; use std::mem; @@ -13,122 +12,138 @@ use tls::MemoryExt; use super::memory::MemoryKind; -pub trait EvalContextExt<'tcx> { - fn call_foreign_item( +pub trait EvalContextExt<'tcx, 'mir> { + /// Emulate calling a foreign item, fail if the item is not supported. + /// This function will handle `goto_block` if needed. + fn emulate_foreign_item( &mut self, def_id: DefId, args: &[OpTy<'tcx>], dest: PlaceTy<'tcx>, - dest_block: mir::BasicBlock, + ret: mir::BasicBlock, ) -> EvalResult<'tcx>; fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>>; - fn call_missing_fn( + /// Emulate a function that should have MIR but does not. + /// This is solely to support execution without full MIR. + /// Fail if emulating this function is not supported. + /// This function will handle `goto_block` if needed. + fn emulate_missing_fn( &mut self, - instance: ty::Instance<'tcx>, - destination: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, - args: &[OpTy<'tcx>], path: String, + args: &[OpTy<'tcx>], + dest: Option>, + ret: Option, ) -> EvalResult<'tcx>; - fn eval_fn_call( + fn find_fn( &mut self, instance: ty::Instance<'tcx>, - destination: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, args: &[OpTy<'tcx>], - span: Span, - ) -> EvalResult<'tcx, bool>; + dest: Option>, + ret: Option, + ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>>; fn write_null(&mut self, dest: PlaceTy<'tcx>) -> EvalResult<'tcx>; } -impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { - fn eval_fn_call( +impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { + fn find_fn( &mut self, instance: ty::Instance<'tcx>, - destination: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, args: &[OpTy<'tcx>], - span: Span, - ) -> EvalResult<'tcx, bool> { - trace!("eval_fn_call: {:#?}, {:?}", instance, destination.map(|(place, bb)| (*place, bb))); + dest: Option>, + ret: Option, + ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> { + trace!("eval_fn_call: {:#?}, {:?}", instance, dest.map(|place| *place)); + // first run the common hooks also supported by CTFE + if self.hook_fn(instance, args, dest)? { + self.goto_block(ret)?; + return Ok(None); + } + // there are some more lang items we want to hook that CTFE does not hook (yet) + if self.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { + // FIXME: return a real value in case the target allocation has an + // alignment bigger than the one requested + let n = u128::max_value(); + let dest = dest.unwrap(); + let n = self.truncate(n, dest.layout); + self.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; + self.goto_block(ret)?; + return Ok(None); + } + + // FIXME: Why are these hooked here, not in `emulate_missing_fn` or so? let def_id = instance.def_id(); let item_path = self.tcx.absolute_item_path_str(def_id); match &*item_path { "std::sys::unix::thread::guard::init" | "std::sys::unix::thread::guard::current" => { // Return None, as it doesn't make sense to return Some, because miri detects stack overflow itself. - let (return_place, return_to_block) = destination.unwrap(); - match return_place.layout.ty.sty { + let dest = dest.unwrap(); + match dest.layout.ty.sty { ty::Adt(ref adt_def, _) => { assert!(adt_def.is_enum(), "Unexpected return type for {}", item_path); let none_variant_index = adt_def.variants.iter().position(|def| { def.name.as_str() == "None" }).expect("No None variant"); - self.write_discriminant_value(none_variant_index, return_place)?; - self.goto_block(return_to_block); - return Ok(true); + self.write_discriminant_value(none_variant_index, dest)?; + self.goto_block(ret)?; + return Ok(None); } _ => panic!("Unexpected return type for {}", item_path) } } "std::sys::unix::fast_thread_local::register_dtor" => { // TODO: register the dtor - let (_return_place, return_to_block) = destination.unwrap(); - self.goto_block(return_to_block); - return Ok(true); + self.goto_block(ret)?; + return Ok(None); } _ => {} } - if self.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { - // FIXME: return a real value in case the target allocation has an - // alignment bigger than the one requested - let n = u128::max_value(); - let (dest, return_to_block) = destination.unwrap(); - let n = self.truncate(n, dest.layout); - self.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; - self.goto_block(return_to_block); - return Ok(true); + // Try to see if we can do something about foreign items + if self.tcx.is_foreign_item(instance.def_id()) { + // An external function that we cannot find MIR for, but we can still run enough + // of them to make miri viable. + self.emulate_foreign_item( + instance.def_id(), + args, + dest.unwrap(), + ret.unwrap(), + )?; + // `goto_block` already handled + return Ok(None); } + // Otherwise we really want to see the MIR -- but if we do not have it, maybe we can + // emulate something. This is a HACK to support running without a full-MIR libstd. let mir = match self.load_mir(instance.def) { Ok(mir) => mir, Err(EvalError { kind: EvalErrorKind::NoMirFor(path), .. }) => { - self.call_missing_fn( - instance, - destination, - args, + self.emulate_missing_fn( path, + args, + dest, + ret, )?; - return Ok(true); + // `goto_block` already handled + return Ok(None); } Err(other) => return Err(other), }; - let (return_place, return_to_block) = match destination { - Some((place, block)) => (*place, StackPopCleanup::Goto(block)), - None => (Place::null(&self), StackPopCleanup::None), - }; - - self.push_stack_frame( - instance, - span, - mir, - return_place, - return_to_block, - )?; - - Ok(false) + Ok(Some(mir)) } - fn call_foreign_item( + fn emulate_foreign_item( &mut self, def_id: DefId, args: &[OpTy<'tcx>], dest: PlaceTy<'tcx>, - dest_block: mir::BasicBlock, + ret: mir::BasicBlock, ) -> EvalResult<'tcx> { let attrs = self.tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { @@ -269,13 +284,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // Now we make a function call. TODO: Consider making this re-usable? EvalContext::step does sth. similar for the TLS dtors, // and of course eval_main. let mir = self.load_mir(f_instance.def)?; - let ret = Place::null(&self); + let closure_dest = Place::null(&self); self.push_stack_frame( f_instance, mir.span, mir, - ret, - StackPopCleanup::Goto(dest_block), + closure_dest, + StackPopCleanup::Goto(Some(ret)), // directly return to caller )?; let mut args = self.frame().mir.args_iter(); @@ -290,16 +305,15 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected"); - // We ourselves return 0 + // We ourselves will return 0, eventually (because we will not return if we paniced) self.write_null(dest)?; - // Don't fall through + // Don't fall through, we do NOT want to `goto_block`! return Ok(()); } - "__rust_start_panic" => { - return err!(Panic); - } + "__rust_start_panic" => + return err!(MachineError("the evaluated program panicked".to_string())), "memcmp" => { let left = self.read_scalar(args[0])?.not_undef()?; @@ -624,11 +638,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } } - // Since we pushed no stack frame, the main loop will act - // as if the call just completed and it's returning to the - // current frame. + self.goto_block(Some(ret))?; self.dump_place(*dest); - self.goto_block(dest_block); Ok(()) } @@ -666,38 +677,27 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' }) } - fn call_missing_fn( + fn emulate_missing_fn( &mut self, - instance: ty::Instance<'tcx>, - destination: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, - args: &[OpTy<'tcx>], path: String, + _args: &[OpTy<'tcx>], + dest: Option>, + ret: Option, ) -> EvalResult<'tcx> { // In some cases in non-MIR libstd-mode, not having a destination is legit. Handle these early. match &path[..] { "std::panicking::rust_panic_with_hook" | "core::panicking::panic_fmt::::panic_impl" | - "std::rt::begin_panic_fmt" => return err!(Panic), + "std::rt::begin_panic_fmt" => + return err!(MachineError("the evaluated program panicked".to_string())), _ => {} } - let (dest, dest_block) = destination.ok_or_else( + let dest = dest.ok_or_else( + // Must be some function we do not support || EvalErrorKind::NoMirFor(path.clone()), )?; - if self.tcx.is_foreign_item(instance.def_id()) { - // An external function - // TODO: That functions actually has a similar preamble to what follows here. May make sense to - // unify these two mechanisms for "hooking into missing functions". - self.call_foreign_item( - instance.def_id(), - args, - dest, - dest_block, - )?; - return Ok(()); - } - match &path[..] { // A Rust function is missing, which means we are running with MIR missing for libstd (or other dependencies). // Still, we can make many things mostly work by "emulating" or ignoring some functions. @@ -724,11 +724,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' _ => return err!(NoMirFor(path)), } - // Since we pushed no stack frame, the main loop will act - // as if the call just completed and it's returning to the - // current frame. + self.goto_block(ret)?; self.dump_place(*dest); - self.goto_block(dest_block); Ok(()) } diff --git a/src/helpers.rs b/src/helpers.rs index 88dd351513a5..24285fa4a6e8 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,5 +1,4 @@ -use rustc::ty::layout::{Size, HasDataLayout}; -use rustc::mir::interpret::sign_extend; +use rustc::ty::layout::Size; use super::{Scalar, ScalarMaybeUndef, EvalResult}; @@ -14,11 +13,6 @@ pub trait ScalarExt { } pub trait FalibleScalarExt { - fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'static, u64>; - fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'static, i64>; - fn to_i32(self) -> EvalResult<'static, i32>; - fn to_u8(self) -> EvalResult<'static, u8>; - /// HACK: this function just extracts all bits if `defined != 0` /// Mainly used for args of C-functions and we should totally correctly fetch the size /// of their arguments @@ -59,34 +53,6 @@ impl ScalarExt for Scalar { } impl FalibleScalarExt for Scalar { - fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'static, u64> { - let b = self.to_bits(cx.data_layout().pointer_size)?; - assert_eq!(b as u64 as u128, b); - Ok(b as u64) - } - - fn to_u8(self) -> EvalResult<'static, u8> { - let sz = Size::from_bits(8); - let b = self.to_bits(sz)?; - assert_eq!(b as u8 as u128, b); - Ok(b as u8) - } - - fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'static, i64> { - let b = self.to_bits(cx.data_layout().pointer_size)?; - let b = sign_extend(b, cx.data_layout().pointer_size) as i128; - assert_eq!(b as i64 as i128, b); - Ok(b as i64) - } - - fn to_i32(self) -> EvalResult<'static, i32> { - let sz = Size::from_bits(32); - let b = self.to_bits(sz)?; - let b = sign_extend(b, sz) as i128; - assert_eq!(b as i32 as i128, b); - Ok(b as i32) - } - fn to_bytes(self) -> EvalResult<'static, u128> { match self { Scalar::Bits { bits, size } => { @@ -99,22 +65,6 @@ impl FalibleScalarExt for Scalar { } impl FalibleScalarExt for ScalarMaybeUndef { - fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'static, u64> { - self.not_undef()?.to_usize(cx) - } - - fn to_u8(self) -> EvalResult<'static, u8> { - self.not_undef()?.to_u8() - } - - fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'static, i64> { - self.not_undef()?.to_isize(cx) - } - - fn to_i32(self) -> EvalResult<'static, i32> { - self.not_undef()?.to_i32() - } - fn to_bytes(self) -> EvalResult<'static, u128> { self.not_undef()?.to_bytes() } diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 47399c390796..62a1938d0fc1 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -1,5 +1,5 @@ use rustc::mir; -use rustc::ty::layout::{self, LayoutOf, Size, Primitive, Integer::*}; +use rustc::ty::layout::{self, LayoutOf, Size}; use rustc::ty; use rustc::mir::interpret::{EvalResult, Scalar, ScalarMaybeUndef}; @@ -15,7 +15,6 @@ pub trait EvalContextExt<'tcx> { instance: ty::Instance<'tcx>, args: &[OpTy<'tcx>], dest: PlaceTy<'tcx>, - target: mir::BasicBlock, ) -> EvalResult<'tcx>; } @@ -25,8 +24,11 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: instance: ty::Instance<'tcx>, args: &[OpTy<'tcx>], dest: PlaceTy<'tcx>, - target: mir::BasicBlock, ) -> EvalResult<'tcx> { + if self.emulate_intrinsic(instance, args, dest)? { + return Ok(()); + } + let substs = instance.substs; let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..]; @@ -194,24 +196,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } } - "ctpop" | "cttz" | "cttz_nonzero" | "ctlz" | "ctlz_nonzero" | "bswap" => { - let ty = substs.type_at(0); - let num = self.read_scalar(args[0])?.to_bytes()?; - let kind = match self.layout_of(ty)?.abi { - ty::layout::Abi::Scalar(ref scalar) => scalar.value, - _ => Err(::rustc::mir::interpret::EvalErrorKind::TypeNotPrimitive(ty))?, - }; - let num = if intrinsic_name.ends_with("_nonzero") { - if num == 0 { - return err!(Intrinsic(format!("{} called on 0", intrinsic_name))); - } - numeric_intrinsic(intrinsic_name.trim_right_matches("_nonzero"), num, kind)? - } else { - numeric_intrinsic(intrinsic_name, num, kind)? - }; - self.write_scalar(num, dest)?; - } - "discriminant_value" => { let place = self.ref_to_mplace(self.read_value(args[0])?)?; let discr_val = self.read_discriminant_value(place.into())?; @@ -316,14 +300,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } } - "min_align_of" => { - let elem_ty = substs.type_at(0); - let elem_align = self.layout_of(elem_ty)?.align.abi(); - let ptr_size = self.memory.pointer_size(); - let align_val = Scalar::from_uint(elem_align as u128, ptr_size); - self.write_scalar(align_val, dest)?; - } - "pref_align_of" => { let ty = substs.type_at(0); let layout = self.layout_of(ty)?; @@ -456,13 +432,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: )?; } - "size_of" => { - let ty = substs.type_at(0); - let size = self.layout_of(ty)?.size.bytes(); - let ptr_size = self.memory.pointer_size(); - self.write_scalar(Scalar::from_uint(size, ptr_size), dest)?; - } - "size_of_val" => { let mplace = self.ref_to_mplace(self.read_value(args[0])?)?; let (size, _) = self.size_and_align_of_mplace(mplace)?; @@ -490,11 +459,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let value = self.str_to_value(&ty_name)?; self.write_value(value, dest)?; } - "type_id" => { - let ty = substs.type_at(0); - let n = self.tcx.type_id_hash(ty); - self.write_scalar(Scalar::Bits { bits: n as u128, size: 8 }, dest)?; - } "transmute" => { // Go through an allocation, to make sure the completely different layouts @@ -610,47 +574,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: name => return err!(Unimplemented(format!("unimplemented intrinsic: {}", name))), } - self.goto_block(target); - - // Since we pushed no stack frame, the main loop will act - // as if the call just completed and it's returning to the - // current frame. Ok(()) } } - -fn numeric_intrinsic<'tcx>( - name: &str, - bytes: u128, - kind: Primitive, -) -> EvalResult<'tcx, Scalar> { - macro_rules! integer_intrinsic { - ($method:ident) => ({ - let (result_bytes, size) = match kind { - Primitive::Int(I8, true) => ((bytes as i8).$method() as u128, 1), - Primitive::Int(I8, false) => ((bytes as u8).$method() as u128, 1), - Primitive::Int(I16, true) => ((bytes as i16).$method() as u128, 2), - Primitive::Int(I16, false) => ((bytes as u16).$method() as u128, 2), - Primitive::Int(I32, true) => ((bytes as i32).$method() as u128, 4), - Primitive::Int(I32, false) => ((bytes as u32).$method() as u128, 4), - Primitive::Int(I64, true) => ((bytes as i64).$method() as u128, 8), - Primitive::Int(I64, false) => ((bytes as u64).$method() as u128, 8), - Primitive::Int(I128, true) => ((bytes as i128).$method() as u128, 16), - Primitive::Int(I128, false) => (bytes.$method() as u128, 16), - _ => bug!("invalid `{}` argument: {:?}", name, bytes), - }; - - Scalar::from_uint(result_bytes, Size::from_bytes(size)) - }); - } - - let result_val = match name { - "bswap" => integer_intrinsic!(swap_bytes), - "ctlz" => integer_intrinsic!(leading_zeros), - "ctpop" => integer_intrinsic!(count_ones), - "cttz" => integer_intrinsic!(trailing_zeros), - _ => bug!("not a numeric intrinsic: {}", name), - }; - - Ok(result_val) -} diff --git a/src/lib.rs b/src/lib.rs index 044ce28b3014..81cee6fbe42e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,14 +18,12 @@ extern crate syntax; use rustc::ty::{self, TyCtxt}; use rustc::ty::layout::{TyLayout, LayoutOf, Size}; -use rustc::ty::subst::Subst; use rustc::hir::def_id::DefId; use rustc::mir; use rustc_data_structures::fx::FxHasher; use syntax::ast::Mutability; -use syntax::source_map::Span; use std::marker::PhantomData; use std::collections::{HashMap, BTreeMap}; @@ -47,6 +45,7 @@ use fn_call::EvalContextExt as MissingFnsEvalContextExt; use operator::EvalContextExt as OperatorEvalContextExt; use intrinsic::EvalContextExt as IntrinsicEvalContextExt; use tls::EvalContextExt as TlsEvalContextExt; +use memory::MemoryKind as MiriMemoryKind; use locks::LockInfo; use range_map::RangeMap; use helpers::{ScalarExt, FalibleScalarExt}; @@ -55,7 +54,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, start_wrapper: Option, -) -> EvalResult<'tcx, (EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>, Option)> { +) -> EvalResult<'tcx, EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>> { let mut ecx = EvalContext::new( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), @@ -65,7 +64,6 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; - let mut cleanup_ptr = None; // Scalar to be deallocated when we are done if !main_mir.return_ty().is_nil() || main_mir.arg_count != 0 { return err!(Unimplemented( @@ -94,11 +92,10 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( ))); } - // Return value + // Return value (in static memory so that it does not count as leak) let size = ecx.tcx.data_layout.pointer_size; let align = ecx.tcx.data_layout.pointer_align; - let ret_ptr = ecx.memory_mut().allocate(size, align, MemoryKind::Stack)?; - cleanup_ptr = Some(ret_ptr); + let ret_ptr = ecx.memory_mut().allocate(size, align, MiriMemoryKind::MutStatic.into())?; // Push our stack frame ecx.push_stack_frame( @@ -123,12 +120,12 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // FIXME: extract main source file path // Third argument (argv): &[b"foo"] let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - let foo = ecx.memory.allocate_bytes(b"foo\0"); + let foo = ecx.memory.allocate_static_bytes(b"foo\0"); let foo_ty = ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8); let foo_layout = ecx.layout_of(foo_ty)?; - let foo_place = ecx.allocate(foo_layout, MemoryKind::Stack)?; + let foo_place = ecx.allocate(foo_layout, MemoryKind::Stack)?; // will be marked as static in just a second ecx.write_scalar(Scalar::Ptr(foo), foo_place.into())?; - ecx.memory.mark_static_initialized(foo_place.to_ptr()?.alloc_id, Mutability::Immutable)?; + ecx.memory.mark_static_initialized(foo_place.to_ptr()?.alloc_id, Mutability::Immutable)?; // marked as static ecx.write_scalar(foo_place.ptr, dest)?; assert!(args.next().is_none(), "start lang item has more arguments than expected"); @@ -146,7 +143,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( assert!(args.next().is_none(), "main function must not have arguments"); } - Ok((ecx, cleanup_ptr)) + Ok(ecx) } pub fn eval_main<'a, 'tcx: 'a>( @@ -154,26 +151,18 @@ pub fn eval_main<'a, 'tcx: 'a>( main_id: DefId, start_wrapper: Option, ) { - let (mut ecx, cleanup_ptr) = create_ecx(tcx, main_id, start_wrapper).expect("Couldn't create ecx"); + let mut ecx = create_ecx(tcx, main_id, start_wrapper).expect("Couldn't create ecx"); let res: EvalResult = do catch { - while ecx.step()? {} + ecx.run()?; ecx.run_tls_dtors()?; - if let Some(cleanup_ptr) = cleanup_ptr { - ecx.memory_mut().deallocate( - cleanup_ptr, - None, - MemoryKind::Stack, - )?; - } }; match res { Ok(()) => { let leaks = ecx.memory().leak_report(); if leaks != 0 { - // TODO: Prevent leaks which aren't supposed to be there - //tcx.sess.err("the evaluated program leaked memory"); + tcx.sess.err("the evaluated program leaked memory"); } } Err(e) => { @@ -198,6 +187,7 @@ pub fn eval_main<'a, 'tcx: 'a>( ecx.tcx.sess.err(&e.to_string()); } + /* Nice try, but with MIRI_BACKTRACE this shows 100s of backtraces. for (i, frame) in ecx.stack().iter().enumerate() { trace!("-------------------"); trace!("Frame {}", i); @@ -207,7 +197,7 @@ pub fn eval_main<'a, 'tcx: 'a>( trace!(" local {}: {:?}", i, local); } } - } + }*/ } } } @@ -262,8 +252,6 @@ pub struct MemoryData<'tcx> { /// Only mutable (static mut, heap, stack) allocations have an entry in this map. /// The entry is created when allocating the memory and deleted after deallocation. locks: HashMap>>, - - statics: HashMap, AllocId>, } impl<'tcx> MemoryData<'tcx> { @@ -272,7 +260,6 @@ impl<'tcx> MemoryData<'tcx> { next_thread_local: 1, // start with 1 as we must not use 0 on Windows thread_local: BTreeMap::new(), locks: HashMap::new(), - statics: HashMap::new(), } } } @@ -283,7 +270,6 @@ impl<'tcx> Hash for MemoryData<'tcx> { next_thread_local: _, thread_local, locks: _, - statics: _, } = self; thread_local.hash(state); @@ -295,14 +281,14 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryKinds = memory::MemoryKind; /// Returns Ok() when the function was handled, fail otherwise - fn eval_fn_call<'a>( + fn find_fn<'a>( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, - destination: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, args: &[OpTy<'tcx>], - span: Span, - ) -> EvalResult<'tcx, bool> { - ecx.eval_fn_call(instance, destination, args, span) + dest: Option>, + ret: Option, + ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> { + ecx.find_fn(instance, args, dest, ret) } fn call_intrinsic<'a>( @@ -310,9 +296,8 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { instance: ty::Instance<'tcx>, args: &[OpTy<'tcx>], dest: PlaceTy<'tcx>, - target: mir::BasicBlock, ) -> EvalResult<'tcx> { - ecx.call_intrinsic(instance, args, dest, target) + ecx.call_intrinsic(instance, args, dest) } fn try_ptr_op<'a>( @@ -326,82 +311,13 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx.ptr_op(bin_op, left, left_layout, right, right_layout) } - fn mark_static_initialized<'a>( - mem: &mut Memory<'a, 'mir, 'tcx, Self>, + fn access_static_mut<'a, 'm>( + mem: &'m mut Memory<'a, 'mir, 'tcx, Self>, id: AllocId, - _mutability: Mutability, - ) -> EvalResult<'tcx, bool> { - use memory::MemoryKind::*; - match mem.get_alloc_kind(id) { - // FIXME: This could be allowed, but not for env vars set during miri execution - Some(MemoryKind::Machine(Env)) => err!(Unimplemented("statics can't refer to env vars".to_owned())), - _ => Ok(false), // TODO: What does the bool mean? - } - } - - fn init_static<'a>( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - cid: GlobalId<'tcx>, - ) -> EvalResult<'tcx, AllocId> { - // Step 1: If the static has already been evaluated return the cached version - if let Some(alloc_id) = ecx.memory.data.statics.get(&cid) { - return Ok(*alloc_id); - } - - let tcx = ecx.tcx.tcx; - - // Step 2: Load mir - let mut mir = ecx.load_mir(cid.instance.def)?; - if let Some(index) = cid.promoted { - mir = &mir.promoted[index]; - } - assert!(mir.arg_count == 0); - - // Step 3: Allocate storage - let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; - assert!(!layout.is_unsized()); - let ptr = ecx.memory.allocate( - layout.size, - layout.align, - MemoryKind::Stack, - )?; - - // Step 4: Cache allocation id for recursive statics - assert!(ecx.memory.data.statics.insert(cid, ptr.alloc_id).is_none()); - - // Step 5: Push stackframe to evaluate static - let cleanup = StackPopCleanup::None; - ecx.push_stack_frame( - cid.instance, - mir.span, - mir, - Place::from_ptr(ptr, layout.align), - cleanup, - )?; - - // Step 6: Step until static has been initialized - let call_stackframe = ecx.stack().len(); - while ecx.step()? && ecx.stack().len() >= call_stackframe { - if ecx.stack().len() == call_stackframe { - let cleanup = { - let frame = ecx.frame(); - let bb = &frame.mir.basic_blocks()[frame.block]; - bb.statements.len() == frame.stmt && !bb.is_cleanup && - if let ::rustc::mir::TerminatorKind::Return = bb.terminator().kind { true } else { false } - }; - if cleanup { - for (local, _local_decl) in mir.local_decls.iter_enumerated().skip(1) { - // Don't deallocate locals, because the return value might reference them - ecx.storage_dead(local); - } - } - } - } - - // TODO: Freeze immutable statics without copying them to the global static cache - - // Step 7: Return the alloc - Ok(ptr.alloc_id) + ) -> EvalResult<'tcx, &'m mut Allocation> { + // Make a copy, use that. + mem.deep_copy_static(id, MiriMemoryKind::MutStatic.into())?; + mem.get_mut(id) // this is recursive, but now we know that `id` is in `alloc_map` } fn box_alloc<'a>( @@ -451,35 +367,6 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { panic!("remove this function from rustc"); } - fn check_locks<'a>( - _mem: &Memory<'a, 'mir, 'tcx, Self>, - _ptr: Pointer, - _size: Size, - _access: AccessKind, - ) -> EvalResult<'tcx> { - Ok(()) - } - - fn add_lock<'a>( - _mem: &mut Memory<'a, 'mir, 'tcx, Self>, - _id: AllocId, - ) { } - - fn free_lock<'a>( - _mem: &mut Memory<'a, 'mir, 'tcx, Self>, - _id: AllocId, - _len: u64, - ) -> EvalResult<'tcx> { - Ok(()) - } - - fn end_region<'a>( - _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - _reg: Option<::rustc::middle::region::Scope>, - ) -> EvalResult<'tcx> { - Ok(()) - } - fn validation_op<'a>( _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, _op: ::rustc::mir::ValidationOp, diff --git a/src/memory.rs b/src/memory.rs index bed0eb28c25c..bc4c5b70ece3 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -1,12 +1,24 @@ +use rustc_mir::interpret::IsStatic; -#[derive(Debug, PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Copy, Clone, Hash, Eq)] pub enum MemoryKind { - /// Error if deallocated any other way than `rust_deallocate` + /// `__rust_alloc` memory Rust, - /// Error if deallocated any other way than `free` + /// `malloc` memory C, /// Part of env var emulation Env, + // mutable statics + MutStatic, +} + +impl IsStatic for MemoryKind { + fn is_static(self) -> bool { + match self { + MemoryKind::MutStatic => true, + _ => false, + } + } } impl Into<::rustc_mir::interpret::MemoryKind> for MemoryKind { diff --git a/src/tls.rs b/src/tls.rs index 878884065bb7..955ecb225685 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -134,7 +134,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.write_scalar(ptr, dest)?; // step until out of stackframes - while self.step()? {} + self.run()?; dtor = match self.memory.fetch_tls_dtor(Some(key)) { dtor @ Some(_) => dtor, diff --git a/tests/compile-fail/memleak.rs b/tests/compile-fail/memleak.rs index c03cf50eb27f..71b4e2f442f3 100644 --- a/tests/compile-fail/memleak.rs +++ b/tests/compile-fail/memleak.rs @@ -1,4 +1,3 @@ -// ignore-test FIXME: leak detection is disabled //error-pattern: the evaluated program leaked memory fn main() { diff --git a/tests/compile-fail/memleak_rc.rs b/tests/compile-fail/memleak_rc.rs index da3a58118a2a..b2bc6722afb0 100644 --- a/tests/compile-fail/memleak_rc.rs +++ b/tests/compile-fail/memleak_rc.rs @@ -1,4 +1,3 @@ -// ignore-test FIXME: leak detection is disabled //error-pattern: the evaluated program leaked memory use std::rc::Rc; diff --git a/tests/compile-fail/modifying_constants.rs b/tests/compile-fail/modifying_constants.rs index 6ffba89fa5ef..ba46651f58ee 100644 --- a/tests/compile-fail/modifying_constants.rs +++ b/tests/compile-fail/modifying_constants.rs @@ -1,4 +1,3 @@ -// ignore-test FIXME: we are not making these statics read-only any more? fn main() { let x = &1; // the `&1` is promoted to a constant, but it used to be that only the pointer is marked static, not the pointee diff --git a/tests/compile-fail/static_memory_modification.rs b/tests/compile-fail/static_memory_modification.rs index e28bcb37fb72..9e39c2c01c2b 100644 --- a/tests/compile-fail/static_memory_modification.rs +++ b/tests/compile-fail/static_memory_modification.rs @@ -1,4 +1,3 @@ -// ignore-test FIXME: we are not making these statics read-only any more? static X: usize = 5; #[allow(mutable_transmutes)] diff --git a/tests/run-pass/pthreads.rs b/tests/run-pass/pthreads.rs new file mode 100644 index 000000000000..ec7e082a5d5f --- /dev/null +++ b/tests/run-pass/pthreads.rs @@ -0,0 +1,14 @@ +// Just instantiate some data structures to make sure we got all their foreign items covered + +use std::sync; + +fn main() { + let m = sync::Mutex::new(0); + let _ = m.lock(); + drop(m); + + let rw = sync::RwLock::new(0); + let _ = rw.read(); + let _ = rw.write(); + drop(rw); +} From 2ee4aac62f4f14204194c391f0eac267c2eee077 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 Aug 2018 21:22:57 +0200 Subject: [PATCH 0191/5092] fix leaks with -Zmiri-start-fn --- src/fn_call.rs | 59 +++++++++++++++++++++----------------------------- src/lib.rs | 31 ++++++++++++++++++++------ 2 files changed, 49 insertions(+), 41 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 6e3fcf7d4489..d16e024db47d 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -75,35 +75,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' return Ok(None); } - // FIXME: Why are these hooked here, not in `emulate_missing_fn` or so? - let def_id = instance.def_id(); - let item_path = self.tcx.absolute_item_path_str(def_id); - match &*item_path { - "std::sys::unix::thread::guard::init" | "std::sys::unix::thread::guard::current" => { - // Return None, as it doesn't make sense to return Some, because miri detects stack overflow itself. - let dest = dest.unwrap(); - match dest.layout.ty.sty { - ty::Adt(ref adt_def, _) => { - assert!(adt_def.is_enum(), "Unexpected return type for {}", item_path); - let none_variant_index = adt_def.variants.iter().position(|def| { - def.name.as_str() == "None" - }).expect("No None variant"); - - self.write_discriminant_value(none_variant_index, dest)?; - self.goto_block(ret)?; - return Ok(None); - } - _ => panic!("Unexpected return type for {}", item_path) - } - } - "std::sys::unix::fast_thread_local::register_dtor" => { - // TODO: register the dtor - self.goto_block(ret)?; - return Ok(None); - } - _ => {} - } - // Try to see if we can do something about foreign items if self.tcx.is_foreign_item(instance.def_id()) { // An external function that we cannot find MIR for, but we can still run enough @@ -280,6 +251,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' let data = self.read_scalar(args[1])?.not_undef()?; let f_instance = self.memory.get_fn(f)?; self.write_null(dest)?; + trace!("__rust_maybe_catch_panic: {:?}", f_instance); // Now we make a function call. TODO: Consider making this re-usable? EvalContext::step does sth. similar for the TLS dtors, // and of course eval_main. @@ -478,7 +450,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' } "sysconf" => { - let name = self.read_scalar(args[0])?.to_usize(&self)?; + let name = self.read_scalar(args[0])?.to_i32()?; trace!("sysconf() called with name {}", name); // cache the sysconf integers via miri's global cache @@ -494,7 +466,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' promoted: None, }; let const_val = self.const_eval(cid)?; - let value = const_val.unwrap_usize(self.tcx.tcx); + let value = const_val.unwrap_bits( + self.tcx.tcx, + ty::ParamEnv::empty().and(self.tcx.types.i32)) as i32; if value == name { result = Some(path_value); break; @@ -568,9 +542,26 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' return err!(Unimplemented("Thread-local store is not fully supported on macOS".to_owned())); }, - // Stub out all the other pthread calls to just return 0 - link_name if link_name.starts_with("pthread_") => { - debug!("ignoring C ABI call: {}", link_name); + // Determining stack base address + "pthread_attr_init" | "pthread_attr_destroy" | "pthread_attr_get_np" | + "pthread_getattr_np" | "pthread_self" => { + self.write_null(dest)?; + } + "pthread_attr_getstack" => { + // second argument is where we are supposed to write the stack size + let ptr = self.ref_to_mplace(self.read_value(args[1])?)?; + self.write_scalar(Scalar::from_int(0x80000, args[1].layout.size), ptr.into())?; + // return 0 + self.write_null(dest)?; + } + + // Stub out calls for condvar, mutex and rwlock to just return 0 + "pthread_mutexattr_init" | "pthread_mutexattr_settype" | "pthread_mutex_init" | + "pthread_mutexattr_destroy" | "pthread_mutex_lock" | "pthread_mutex_unlock" | + "pthread_mutex_destroy" | "pthread_rwlock_rdlock" | "pthread_rwlock_unlock" | + "pthread_rwlock_wrlock" | "pthread_rwlock_destroy" | "pthread_condattr_init" | + "pthread_condattr_setclock" | "pthread_cond_init" | "pthread_condattr_destroy" | + "pthread_cond_destroy" => { self.write_null(dest)?; } diff --git a/src/lib.rs b/src/lib.rs index 81cee6fbe42e..a3810516eafd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,7 @@ extern crate rustc_mir; extern crate rustc_target; extern crate syntax; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::{self, TyCtxt, query::TyCtxtAt}; use rustc::ty::layout::{TyLayout, LayoutOf, Size}; use rustc::hir::def_id::DefId; use rustc::mir; @@ -24,6 +24,7 @@ use rustc::mir; use rustc_data_structures::fx::FxHasher; use syntax::ast::Mutability; +use syntax::attr; use std::marker::PhantomData; use std::collections::{HashMap, BTreeMap}; @@ -359,12 +360,28 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { Ok(()) } - fn global_item_with_linkage<'a>( - _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - _instance: ty::Instance<'tcx>, - _mutability: Mutability, - ) -> EvalResult<'tcx> { - panic!("remove this function from rustc"); + fn find_foreign_static<'a>( + tcx: TyCtxtAt<'a, 'tcx, 'tcx>, + def_id: DefId, + ) -> EvalResult<'tcx, &'tcx Allocation> { + let attrs = tcx.get_attrs(def_id); + let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { + Some(name) => name.as_str(), + None => tcx.item_name(def_id).as_str(), + }; + + let alloc = match &link_name[..] { + "__cxa_thread_atexit_impl" => { + // This should be all-zero, pointer-sized + let data = vec![0; tcx.data_layout.pointer_size.bytes() as usize]; + let alloc = Allocation::from_bytes(&data[..], tcx.data_layout.pointer_align); + tcx.intern_const_alloc(alloc) + } + _ => return err!(Unimplemented( + format!("can't access foreign static: {}", link_name), + )), + }; + Ok(alloc) } fn validation_op<'a>( From 42bce6cb3605a36092ab86daffa52f8075e76a8b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 24 Aug 2018 17:44:04 +0200 Subject: [PATCH 0192/5092] rustup --- src/lib.rs | 10 +++++----- src/tls.rs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a3810516eafd..b529e7369002 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -104,7 +104,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( start_mir.span, start_mir, Place::from_ptr(ret_ptr, align), - StackPopCleanup::None, + StackPopCleanup::None { cleanup: true }, )?; let mut args = ecx.frame().mir.args_iter(); @@ -124,9 +124,9 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let foo = ecx.memory.allocate_static_bytes(b"foo\0"); let foo_ty = ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8); let foo_layout = ecx.layout_of(foo_ty)?; - let foo_place = ecx.allocate(foo_layout, MemoryKind::Stack)?; // will be marked as static in just a second + let foo_place = ecx.allocate(foo_layout, MemoryKind::Stack)?; // will be interned in just a second ecx.write_scalar(Scalar::Ptr(foo), foo_place.into())?; - ecx.memory.mark_static_initialized(foo_place.to_ptr()?.alloc_id, Mutability::Immutable)?; // marked as static + ecx.memory.intern_static(foo_place.to_ptr()?.alloc_id, Mutability::Immutable)?; ecx.write_scalar(foo_place.ptr, dest)?; assert!(args.next().is_none(), "start lang item has more arguments than expected"); @@ -136,7 +136,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( main_mir.span, main_mir, Place::from_scalar_ptr(Scalar::from_int(1, ptr_size).into(), ty::layout::Align::from_bytes(1, 1).unwrap()), - StackPopCleanup::None, + StackPopCleanup::None { cleanup: true }, )?; // No arguments @@ -338,7 +338,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { // Don't do anything when we are done. The statement() function will increment // the old stack frame's stmt counter to the next statement, which means that when // exchange_malloc returns, we go on evaluating exactly where we want to be. - StackPopCleanup::None, + StackPopCleanup::None { cleanup: true }, )?; let mut args = ecx.frame().mir.args_iter(); diff --git a/src/tls.rs b/src/tls.rs index 955ecb225685..6cec39483c46 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -125,7 +125,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' mir.span, mir, ret, - StackPopCleanup::None, + StackPopCleanup::None { cleanup: true }, )?; let arg_local = self.frame().mir.args_iter().next().ok_or_else( || EvalErrorKind::AbiViolation("TLS dtor does not take enough arguments.".to_owned()), From 40cc72604afa4c2fc89cca0a86cb5c0f6dd3bd63 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 24 Aug 2018 19:18:21 +0200 Subject: [PATCH 0193/5092] update for bool/char being checked at binops --- tests/compile-fail/invalid_bool.rs | 2 ++ tests/compile-fail/invalid_bool2.rs | 4 ++++ tests/compile-fail/match_char.rs | 12 +++++++----- tests/compile-fail/match_char2.rs | 5 +++++ tests/run-pass/bools.rs | 1 + 5 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 tests/compile-fail/invalid_bool2.rs create mode 100644 tests/compile-fail/match_char2.rs diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index 6ac7f3e60c0d..bd08c0ce4eb9 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -1,4 +1,6 @@ //ignore-test FIXME (do some basic validation of invariants for all values in flight) +//This does currently not get caught becuase it compiles to SwitchInt, which +//has no knowledge about data invariants. fn main() { let b = unsafe { std::mem::transmute::(2) }; diff --git a/tests/compile-fail/invalid_bool2.rs b/tests/compile-fail/invalid_bool2.rs new file mode 100644 index 000000000000..47c4e8b410eb --- /dev/null +++ b/tests/compile-fail/invalid_bool2.rs @@ -0,0 +1,4 @@ +fn main() { + let b = unsafe { std::mem::transmute::(2) }; + let _x = b == true; //~ ERROR invalid boolean value read +} diff --git a/tests/compile-fail/match_char.rs b/tests/compile-fail/match_char.rs index 52f33b58e6fb..fd4431992d9b 100644 --- a/tests/compile-fail/match_char.rs +++ b/tests/compile-fail/match_char.rs @@ -1,11 +1,13 @@ // ignore-test FIXME: we are not checking these things on match any more? +//This does currently not get caught becuase it compiles to SwitchInt, which +//has no knowledge about data invariants. fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); - match unsafe { std::mem::transmute::(-1) } { //~ ERROR constant evaluation error + let _ = match unsafe { std::mem::transmute::(-1) } { //~ ERROR constant evaluation error //~^ NOTE tried to interpret an invalid 32-bit value as a char: 4294967295 - 'a' => {}, - 'b' => {}, - _ => {}, - } + 'a' => {true}, + 'b' => {false}, + _ => {true}, + }; } diff --git a/tests/compile-fail/match_char2.rs b/tests/compile-fail/match_char2.rs new file mode 100644 index 000000000000..786dd813a1eb --- /dev/null +++ b/tests/compile-fail/match_char2.rs @@ -0,0 +1,5 @@ +fn main() { + assert!(std::char::from_u32(-1_i32 as u32).is_none()); + let c = unsafe { std::mem::transmute::(-1) }; + let _x = c == 'x'; //~ ERROR tried to interpret an invalid 32-bit value as a char +} diff --git a/tests/run-pass/bools.rs b/tests/run-pass/bools.rs index 103d7eac27cd..30fc14704d9d 100644 --- a/tests/run-pass/bools.rs +++ b/tests/run-pass/bools.rs @@ -25,4 +25,5 @@ fn main() { assert_eq!(if_false(), 0); assert_eq!(if_true(), 1); assert_eq!(match_bool(), 1); + assert_eq!(true == true, true); } From bb5079b2bfba034fc6ab8fed39348bc59c0d608b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 24 Aug 2018 19:49:57 +0200 Subject: [PATCH 0194/5092] rustup --- src/lib.rs | 11 ++++------- tests/compile-fail/stack_limit.rs | 2 +- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b529e7369002..c3f411f23063 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,4 @@ -#![feature( - rustc_private, - catch_expr, -)] +#![feature(rustc_private)] #![cfg_attr(feature = "cargo-clippy", allow(cast_lossless))] @@ -154,10 +151,10 @@ pub fn eval_main<'a, 'tcx: 'a>( ) { let mut ecx = create_ecx(tcx, main_id, start_wrapper).expect("Couldn't create ecx"); - let res: EvalResult = do catch { + let res: EvalResult = (|| { ecx.run()?; - ecx.run_tls_dtors()?; - }; + ecx.run_tls_dtors() + })(); match res { Ok(()) => { diff --git a/tests/compile-fail/stack_limit.rs b/tests/compile-fail/stack_limit.rs index c6aaf80e6ac0..5645217fe1ff 100644 --- a/tests/compile-fail/stack_limit.rs +++ b/tests/compile-fail/stack_limit.rs @@ -1,4 +1,4 @@ -#![feature(custom_attribute, attr_literals)] +#![feature(custom_attribute)] #![miri(stack_limit=16)] //error-pattern: reached the configured maximum number of stack frames From 9280d17d981a17ab6c17069c3e4e2959d4372d14 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 24 Aug 2018 19:50:31 +0200 Subject: [PATCH 0195/5092] test VecDeque --- tests/run-pass/vecdeque.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/run-pass/vecdeque.rs diff --git a/tests/run-pass/vecdeque.rs b/tests/run-pass/vecdeque.rs new file mode 100644 index 000000000000..381169505ec9 --- /dev/null +++ b/tests/run-pass/vecdeque.rs @@ -0,0 +1,15 @@ +use std::collections::VecDeque; + +fn main() { + let mut dst = VecDeque::new(); + dst.push_front(Box::new(1)); + dst.push_front(Box::new(2)); + dst.pop_back(); + + let mut src = VecDeque::new(); + src.push_front(Box::new(2)); + dst.append(&mut src); + for a in dst { + assert_eq!(*a, 2); + } +} From 823837922bfc55c715a170fda3aa5823ead2e235 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Aug 2018 11:07:21 +0200 Subject: [PATCH 0196/5092] update for enum discriminant changes --- src/intrinsic.rs | 2 +- tests/compile-fail/invalid_enum_discriminant.rs | 5 ++--- tests/compile-fail/invalid_enum_discriminant2.rs | 16 ++++++++++++++++ 3 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 tests/compile-fail/invalid_enum_discriminant2.rs diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 62a1938d0fc1..ed8514863c19 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -198,7 +198,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "discriminant_value" => { let place = self.ref_to_mplace(self.read_value(args[0])?)?; - let discr_val = self.read_discriminant_value(place.into())?; + let discr_val = self.read_discriminant(place.into())?.0; self.write_scalar(Scalar::from_uint(discr_val, dest.layout.size), dest)?; } diff --git a/tests/compile-fail/invalid_enum_discriminant.rs b/tests/compile-fail/invalid_enum_discriminant.rs index 760b6563d27c..a188623a1e0e 100644 --- a/tests/compile-fail/invalid_enum_discriminant.rs +++ b/tests/compile-fail/invalid_enum_discriminant.rs @@ -8,11 +8,10 @@ pub enum Foo { fn main() { let f = unsafe { std::mem::transmute::(42) }; - match f { + match f { //~ ERROR invalid enum discriminant Foo::A => {}, Foo::B => {}, Foo::C => {}, Foo::D => {}, } -} //~ ERROR constant evaluation error -//~^ NOTE entered unreachable code +} diff --git a/tests/compile-fail/invalid_enum_discriminant2.rs b/tests/compile-fail/invalid_enum_discriminant2.rs new file mode 100644 index 000000000000..5a5a20c48695 --- /dev/null +++ b/tests/compile-fail/invalid_enum_discriminant2.rs @@ -0,0 +1,16 @@ +// Validation makes this fail in the wrong place +// compile-flags: -Zmir-emit-validate=0 + +// error-pattern: invalid enum discriminant + +use std::mem; + +#[repr(C)] +pub enum Foo { + A, B, C, D +} + +fn main() { + let f = unsafe { std::mem::transmute::(42) }; + let _ = mem::discriminant(&f); +} From 1ba6140891cb1ecaddcb097d22007938bbb34dcd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Aug 2018 21:22:06 +0200 Subject: [PATCH 0197/5092] rustup --- src/intrinsic.rs | 6 +++--- src/lib.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index ed8514863c19..6847d8e546f3 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -4,7 +4,7 @@ use rustc::ty; use rustc::mir::interpret::{EvalResult, Scalar, ScalarMaybeUndef}; use rustc_mir::interpret::{ - PlaceExtra, PlaceTy, EvalContext, OpTy, Value + PlaceTy, EvalContext, OpTy, Value }; use super::{ScalarExt, FalibleScalarExt, OperatorEvalContextExt}; @@ -293,7 +293,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: _ => { // Do it in memory let mplace = self.force_allocation(dest)?; - assert_eq!(mplace.extra, PlaceExtra::None); + assert!(mplace.extra.is_none()); self.memory.write_repeat(mplace.ptr, 0, dest.layout.size)?; } } @@ -550,7 +550,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: _ => { // Do it in memory let mplace = self.force_allocation(dest)?; - assert_eq!(mplace.extra, PlaceExtra::None); + assert!(mplace.extra.is_none()); self.memory.mark_definedness(mplace.ptr.to_ptr()?, dest.layout.size, false)?; } } diff --git a/src/lib.rs b/src/lib.rs index c3f411f23063..b0148c16f3e8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -315,7 +315,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { ) -> EvalResult<'tcx, &'m mut Allocation> { // Make a copy, use that. mem.deep_copy_static(id, MiriMemoryKind::MutStatic.into())?; - mem.get_mut(id) // this is recursive, but now we know that `id` is in `alloc_map` + mem.get_mut(id) // this is recursive, but now we know that `id` is in `alloc_map` now } fn box_alloc<'a>( From 1b41b7182727801b186dfc03284356af6b0afd89 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Aug 2018 13:19:03 +0200 Subject: [PATCH 0198/5092] update for MUT_STATIC_KIND --- src/lib.rs | 13 +++---------- src/memory.rs | 11 ----------- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b0148c16f3e8..27abd03f2f9f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -274,10 +274,12 @@ impl<'tcx> Hash for MemoryData<'tcx> { } } -impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { +impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryData = MemoryData<'tcx>; type MemoryKinds = memory::MemoryKind; + const MUT_STATIC_KIND: Option = Some(memory::MemoryKind::MutStatic); + /// Returns Ok() when the function was handled, fail otherwise fn find_fn<'a>( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, @@ -309,15 +311,6 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx.ptr_op(bin_op, left, left_layout, right, right_layout) } - fn access_static_mut<'a, 'm>( - mem: &'m mut Memory<'a, 'mir, 'tcx, Self>, - id: AllocId, - ) -> EvalResult<'tcx, &'m mut Allocation> { - // Make a copy, use that. - mem.deep_copy_static(id, MiriMemoryKind::MutStatic.into())?; - mem.get_mut(id) // this is recursive, but now we know that `id` is in `alloc_map` now - } - fn box_alloc<'a>( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, dest: PlaceTy<'tcx>, diff --git a/src/memory.rs b/src/memory.rs index bc4c5b70ece3..d4575d677fa1 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -1,5 +1,3 @@ -use rustc_mir::interpret::IsStatic; - #[derive(Debug, PartialEq, Copy, Clone, Hash, Eq)] pub enum MemoryKind { /// `__rust_alloc` memory @@ -12,15 +10,6 @@ pub enum MemoryKind { MutStatic, } -impl IsStatic for MemoryKind { - fn is_static(self) -> bool { - match self { - MemoryKind::MutStatic => true, - _ => false, - } - } -} - impl Into<::rustc_mir::interpret::MemoryKind> for MemoryKind { fn into(self) -> ::rustc_mir::interpret::MemoryKind { ::rustc_mir::interpret::MemoryKind::Machine(self) From 5ccdbb8de208663461ea57659d06b9e800ff8905 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Aug 2018 14:34:21 +0200 Subject: [PATCH 0199/5092] small test for extern_type --- tests/run-pass/extern_types.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 tests/run-pass/extern_types.rs diff --git a/tests/run-pass/extern_types.rs b/tests/run-pass/extern_types.rs new file mode 100644 index 000000000000..b37cd8408ba1 --- /dev/null +++ b/tests/run-pass/extern_types.rs @@ -0,0 +1,10 @@ +#![feature(extern_types)] + +extern { + type Foo; +} + +fn main() { + let x: &Foo = unsafe { &*(16 as *const Foo) }; + let _y: &Foo = &*x; +} From 755c68fdd872c9c11fb27f4290ae407381f17fcc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Aug 2018 20:42:02 +0200 Subject: [PATCH 0200/5092] some unary operator tests --- tests/run-pass/unops.rs | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 tests/run-pass/unops.rs diff --git a/tests/run-pass/unops.rs b/tests/run-pass/unops.rs new file mode 100644 index 000000000000..650c51ba5d99 --- /dev/null +++ b/tests/run-pass/unops.rs @@ -0,0 +1,5 @@ +fn main() { + assert_eq!(!true, false); + assert_eq!(!0xFFu16, 0xFF00); + assert_eq!(-{1i16}, -1i16); +} From addcbd88684950071bca39d0d7408b1658a1db88 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Aug 2018 08:21:05 +0200 Subject: [PATCH 0201/5092] VecDeque now requries full MIR; update to new nightly --- rust-toolchain | 2 +- tests/{run-pass => run-pass-fullmir}/vecdeque.rs | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/{run-pass => run-pass-fullmir}/vecdeque.rs (100%) diff --git a/rust-toolchain b/rust-toolchain index ec8c56dc6248..f54012d5e14b 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-08-14 +nightly-2018-08-30 diff --git a/tests/run-pass/vecdeque.rs b/tests/run-pass-fullmir/vecdeque.rs similarity index 100% rename from tests/run-pass/vecdeque.rs rename to tests/run-pass-fullmir/vecdeque.rs From d7a3e040eb49129ce79ee604fb593671d1f86901 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Aug 2018 08:33:38 +0200 Subject: [PATCH 0202/5092] pthreads test needs full MIR on Windows --- tests/{run-pass/pthreads.rs => run-pass-fullmir/threads.rs} | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) rename tests/{run-pass/pthreads.rs => run-pass-fullmir/threads.rs} (80%) diff --git a/tests/run-pass/pthreads.rs b/tests/run-pass-fullmir/threads.rs similarity index 80% rename from tests/run-pass/pthreads.rs rename to tests/run-pass-fullmir/threads.rs index ec7e082a5d5f..93a08bfc2588 100644 --- a/tests/run-pass/pthreads.rs +++ b/tests/run-pass-fullmir/threads.rs @@ -1,4 +1,5 @@ -// Just instantiate some data structures to make sure we got all their foreign items covered +// Just instantiate some data structures to make sure we got all their foreign items covered. +// Requires full MIR on Windows. use std::sync; From 0db1c6a1b0ec2fe5e7a3c15273e8a97b8747d7b7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Aug 2018 08:57:33 +0200 Subject: [PATCH 0203/5092] ignore memory leaks on Windows --- src/lib.rs | 5 ++++- tests/compile-fail/memleak.rs | 2 ++ tests/compile-fail/memleak_rc.rs | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 27abd03f2f9f..8fff4635fa0e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -159,7 +159,10 @@ pub fn eval_main<'a, 'tcx: 'a>( match res { Ok(()) => { let leaks = ecx.memory().leak_report(); - if leaks != 0 { + // Disable the leak test on some platforms where we likely do not + // correctly implement TLS destructors. + let target_os = &ecx.tcx.tcx.sess.target.target.target_os; + if target_os.to_lowercase() != "windows" && leaks != 0 { tcx.sess.err("the evaluated program leaked memory"); } } diff --git a/tests/compile-fail/memleak.rs b/tests/compile-fail/memleak.rs index 71b4e2f442f3..7f155edc35a5 100644 --- a/tests/compile-fail/memleak.rs +++ b/tests/compile-fail/memleak.rs @@ -1,3 +1,5 @@ +// ignore-windows + //error-pattern: the evaluated program leaked memory fn main() { diff --git a/tests/compile-fail/memleak_rc.rs b/tests/compile-fail/memleak_rc.rs index b2bc6722afb0..24e8363049c8 100644 --- a/tests/compile-fail/memleak_rc.rs +++ b/tests/compile-fail/memleak_rc.rs @@ -1,3 +1,5 @@ +// ignore-windows + //error-pattern: the evaluated program leaked memory use std::rc::Rc; From b4ebe72b1be436d812ac758247ba6553b0d574c5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Aug 2018 09:04:57 +0200 Subject: [PATCH 0204/5092] stack address functions for macOS --- src/fn_call.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index d16e024db47d..167703c0f04c 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -544,16 +544,21 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' // Determining stack base address "pthread_attr_init" | "pthread_attr_destroy" | "pthread_attr_get_np" | - "pthread_getattr_np" | "pthread_self" => { + "pthread_getattr_np" | "pthread_self" | "pthread_get_stacksize_np" => { self.write_null(dest)?; } "pthread_attr_getstack" => { // second argument is where we are supposed to write the stack size let ptr = self.ref_to_mplace(self.read_value(args[1])?)?; - self.write_scalar(Scalar::from_int(0x80000, args[1].layout.size), ptr.into())?; + let stackaddr = Scalar::from_int(0x80000, args[1].layout.size); // just any address + self.write_scalar(stackaddr, ptr.into())?; // return 0 self.write_null(dest)?; } + "pthread_get_stackaddr_np" => { + let stackaddr = Scalar::from_int(0x80000, dest.layout.size); // just any address + self.write_scalar(stackaddr, dest)?; + } // Stub out calls for condvar, mutex and rwlock to just return 0 "pthread_mutexattr_init" | "pthread_mutexattr_settype" | "pthread_mutex_init" | From d1cd2540030d9fe52584d04ba2c188b9f679cb16 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Aug 2018 09:20:08 +0200 Subject: [PATCH 0205/5092] no RwLock on Windows --- tests/run-pass-fullmir/threads.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/run-pass-fullmir/threads.rs b/tests/run-pass-fullmir/threads.rs index 93a08bfc2588..f920bc52edde 100644 --- a/tests/run-pass-fullmir/threads.rs +++ b/tests/run-pass-fullmir/threads.rs @@ -8,8 +8,12 @@ fn main() { let _ = m.lock(); drop(m); - let rw = sync::RwLock::new(0); - let _ = rw.read(); - let _ = rw.write(); - drop(rw); + // We don't provide RwLock on Windows + #[cfg(not(target_os = "windows"))] + { + let rw = sync::RwLock::new(0); + let _ = rw.read(); + let _ = rw.write(); + drop(rw); + } } From e2ec521f218bbc1c3677021644fc5e63641b94d5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Aug 2018 09:22:01 +0200 Subject: [PATCH 0206/5092] pretend mprotect works --- src/fn_call.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/fn_call.rs b/src/fn_call.rs index 167703c0f04c..fb77f01876d9 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -575,6 +575,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' let addr = self.read_scalar(args[0])?.not_undef()?; self.write_scalar(addr, dest)?; } + "mprotect" => { + self.write_null(dest)?; + } // Windows API subs "AddVectoredExceptionHandler" => { From 2a244dcb4893a26b02ae2bd01309b8499685457b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Aug 2018 09:41:57 +0200 Subject: [PATCH 0207/5092] no TLS dtor and no leak checks on macOS --- src/fn_call.rs | 2 +- src/lib.rs | 5 +++-- tests/compile-fail/memleak.rs | 3 ++- tests/compile-fail/memleak_rc.rs | 3 ++- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index fb77f01876d9..a9791e2b7ca7 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -539,7 +539,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' } "_tlv_atexit" => { - return err!(Unimplemented("Thread-local store is not fully supported on macOS".to_owned())); + // FIXME: Register the dtor }, // Determining stack base address diff --git a/src/lib.rs b/src/lib.rs index 8fff4635fa0e..42dac6a28d85 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -161,8 +161,9 @@ pub fn eval_main<'a, 'tcx: 'a>( let leaks = ecx.memory().leak_report(); // Disable the leak test on some platforms where we likely do not // correctly implement TLS destructors. - let target_os = &ecx.tcx.tcx.sess.target.target.target_os; - if target_os.to_lowercase() != "windows" && leaks != 0 { + let target_os = ecx.tcx.tcx.sess.target.target.target_os.to_lowercase(); + let ignore_leaks = target_os == "windows" || target_os == "macos"; + if !ignore_leaks && leaks != 0 { tcx.sess.err("the evaluated program leaked memory"); } } diff --git a/tests/compile-fail/memleak.rs b/tests/compile-fail/memleak.rs index 7f155edc35a5..06e01d7aea3a 100644 --- a/tests/compile-fail/memleak.rs +++ b/tests/compile-fail/memleak.rs @@ -1,4 +1,5 @@ -// ignore-windows +// ignore-windows: We do not check leaks on Windows +// ignore-macos: We do not check leaks on macOS //error-pattern: the evaluated program leaked memory diff --git a/tests/compile-fail/memleak_rc.rs b/tests/compile-fail/memleak_rc.rs index 24e8363049c8..14a85ecd8947 100644 --- a/tests/compile-fail/memleak_rc.rs +++ b/tests/compile-fail/memleak_rc.rs @@ -1,4 +1,5 @@ -// ignore-windows +// ignore-windows: We do not check leaks on Windows +// ignore-macos: We do not check leaks on macOS //error-pattern: the evaluated program leaked memory From 904923fa7a4635636b0bc5c33e9901773e7f6747 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Aug 2018 20:42:26 +0200 Subject: [PATCH 0208/5092] move some more helpers to rustc --- src/fn_call.rs | 8 +++--- src/helpers.rs | 45 -------------------------------- src/intrinsic.rs | 58 ++++++++++++++++-------------------------- src/lib.rs | 2 +- src/tls.rs | 8 +++--- tests/run-pass/char.rs | 4 +-- 6 files changed, 31 insertions(+), 94 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index a9791e2b7ca7..0e768fcccf9e 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -305,7 +305,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' }; self.write_scalar( - Scalar::from_i32(result), + Scalar::from_int(result, Size::from_bits(32)), dest, )?; } @@ -346,7 +346,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' let name = self.memory.read_c_str(name_ptr)?; match self.machine.env_vars.get(name) { Some(&var) => Scalar::Ptr(var), - None => Scalar::null(self.memory.pointer_size()), + None => Scalar::ptr_null(*self.tcx), } }; self.write_scalar(result, dest)?; @@ -446,7 +446,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' // Some things needed for sys::thread initialization to go through "signal" | "sigaction" | "sigaltstack" => { - self.write_scalar(Scalar::null(dest.layout.size), dest)?; + self.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?; } "sysconf" => { @@ -729,6 +729,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' } fn write_null(&mut self, dest: PlaceTy<'tcx>) -> EvalResult<'tcx> { - self.write_scalar(Scalar::null(dest.layout.size), dest) + self.write_scalar(Scalar::from_int(0, dest.layout.size), dest) } } diff --git a/src/helpers.rs b/src/helpers.rs index 24285fa4a6e8..27b2109d18a1 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,17 +1,5 @@ -use rustc::ty::layout::Size; - use super::{Scalar, ScalarMaybeUndef, EvalResult}; -pub trait ScalarExt { - fn null(size: Size) -> Self; - fn from_i32(i: i32) -> Self; - fn from_uint(i: impl Into, ptr_size: Size) -> Self; - fn from_int(i: impl Into, ptr_size: Size) -> Self; - fn from_f32(f: f32) -> Self; - fn from_f64(f: f64) -> Self; - fn is_null(self) -> bool; -} - pub trait FalibleScalarExt { /// HACK: this function just extracts all bits if `defined != 0` /// Mainly used for args of C-functions and we should totally correctly fetch the size @@ -19,39 +7,6 @@ pub trait FalibleScalarExt { fn to_bytes(self) -> EvalResult<'static, u128>; } -impl ScalarExt for Scalar { - fn null(size: Size) -> Self { - Scalar::Bits { bits: 0, size: size.bytes() as u8 } - } - - fn from_i32(i: i32) -> Self { - Scalar::Bits { bits: i as u32 as u128, size: 4 } - } - - fn from_uint(i: impl Into, size: Size) -> Self { - Scalar::Bits { bits: i.into(), size: size.bytes() as u8 } - } - - fn from_int(i: impl Into, size: Size) -> Self { - Scalar::Bits { bits: i.into() as u128, size: size.bytes() as u8 } - } - - fn from_f32(f: f32) -> Self { - Scalar::Bits { bits: f.to_bits() as u128, size: 4 } - } - - fn from_f64(f: f64) -> Self { - Scalar::Bits { bits: f.to_bits() as u128, size: 8 } - } - - fn is_null(self) -> bool { - match self { - Scalar::Bits { bits, .. } => bits == 0, - Scalar::Ptr(_) => false - } - } -} - impl FalibleScalarExt for Scalar { fn to_bytes(self) -> EvalResult<'static, u128> { match self { diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 6847d8e546f3..695943d57b0c 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -2,12 +2,12 @@ use rustc::mir; use rustc::ty::layout::{self, LayoutOf, Size}; use rustc::ty; -use rustc::mir::interpret::{EvalResult, Scalar, ScalarMaybeUndef}; +use rustc::mir::interpret::{EvalResult, Scalar, ScalarMaybeUndef, PointerArithmetic}; use rustc_mir::interpret::{ PlaceTy, EvalContext, OpTy, Value }; -use super::{ScalarExt, FalibleScalarExt, OperatorEvalContextExt}; +use super::{FalibleScalarExt, OperatorEvalContextExt}; pub trait EvalContextExt<'tcx> { fn call_intrinsic( @@ -204,8 +204,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" => { - let f = self.read_scalar(args[0])?.to_bytes()?; - let f = f32::from_bits(f as u32); + let f = self.read_scalar(args[0])?.to_f32()?; let f = match intrinsic_name { "sinf32" => f.sin(), "fabsf32" => f.abs(), @@ -226,8 +225,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" | "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" => { - let f = self.read_scalar(args[0])?.to_bytes()?; - let f = f64::from_bits(f as u64); + let f = self.read_scalar(args[0])?.to_f64()?; let f = match intrinsic_name { "sinf64" => f.sin(), "fabsf64" => f.abs(), @@ -282,12 +280,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: if !dest.layout.is_zst() { // notzhing to do for ZST match dest.layout.abi { layout::Abi::Scalar(ref s) => { - let x = Scalar::null(s.value.size(&self)); + let x = Scalar::from_int(0, s.value.size(&self)); self.write_value(Value::Scalar(x.into()), dest)?; } layout::Abi::ScalarPair(ref s1, ref s2) => { - let x = Scalar::null(s1.value.size(&self)); - let y = Scalar::null(s2.value.size(&self)); + let x = Scalar::from_int(0, s1.value.size(&self)); + let y = Scalar::from_int(0, s2.value.size(&self)); self.write_value(Value::ScalarPair(x.into(), y.into()), dest)?; } _ => { @@ -304,7 +302,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ty = substs.type_at(0); let layout = self.layout_of(ty)?; let align = layout.align.pref(); - let ptr_size = self.memory.pointer_size(); + let ptr_size = self.pointer_size(); let align_val = Scalar::from_uint(align as u128, ptr_size); self.write_scalar(align_val, dest)?; } @@ -365,10 +363,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "powf32" => { - let f = self.read_scalar(args[0])?.to_bits(Size::from_bits(32))?; - let f = f32::from_bits(f as u32); - let f2 = self.read_scalar(args[1])?.to_bits(Size::from_bits(32))?; - let f2 = f32::from_bits(f2 as u32); + let f = self.read_scalar(args[0])?.to_f32()?; + let f2 = self.read_scalar(args[1])?.to_f32()?; self.write_scalar( Scalar::from_f32(f.powf(f2)), dest, @@ -376,10 +372,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "powf64" => { - let f = self.read_scalar(args[0])?.to_bits(Size::from_bits(64))?; - let f = f64::from_bits(f as u64); - let f2 = self.read_scalar(args[1])?.to_bits(Size::from_bits(64))?; - let f2 = f64::from_bits(f2 as u64); + let f = self.read_scalar(args[0])?.to_f64()?; + let f2 = self.read_scalar(args[1])?.to_f64()?; self.write_scalar( Scalar::from_f64(f.powf(f2)), dest, @@ -387,12 +381,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "fmaf32" => { - let a = self.read_scalar(args[0])?.to_bits(Size::from_bits(32))?; - let a = f32::from_bits(a as u32); - let b = self.read_scalar(args[1])?.to_bits(Size::from_bits(32))?; - let b = f32::from_bits(b as u32); - let c = self.read_scalar(args[2])?.to_bits(Size::from_bits(32))?; - let c = f32::from_bits(c as u32); + let a = self.read_scalar(args[0])?.to_f32()?; + let b = self.read_scalar(args[1])?.to_f32()?; + let c = self.read_scalar(args[2])?.to_f32()?; self.write_scalar( Scalar::from_f32(a * b + c), dest, @@ -400,12 +391,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "fmaf64" => { - let a = self.read_scalar(args[0])?.to_bits(Size::from_bits(64))?; - let a = f64::from_bits(a as u64); - let b = self.read_scalar(args[1])?.to_bits(Size::from_bits(64))?; - let b = f64::from_bits(b as u64); - let c = self.read_scalar(args[2])?.to_bits(Size::from_bits(64))?; - let c = f64::from_bits(c as u64); + let a = self.read_scalar(args[0])?.to_f64()?; + let b = self.read_scalar(args[1])?.to_f64()?; + let c = self.read_scalar(args[2])?.to_f64()?; self.write_scalar( Scalar::from_f64(a * b + c), dest, @@ -413,8 +401,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "powif32" => { - let f = self.read_scalar(args[0])?.to_bits(Size::from_bits(32))?; - let f = f32::from_bits(f as u32); + let f = self.read_scalar(args[0])?.to_f32()?; let i = self.read_scalar(args[1])?.to_i32()?; self.write_scalar( Scalar::from_f32(f.powi(i)), @@ -423,8 +410,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "powif64" => { - let f = self.read_scalar(args[0])?.to_bits(Size::from_bits(64))?; - let f = f64::from_bits(f as u64); + let f = self.read_scalar(args[0])?.to_f64()?; let i = self.read_scalar(args[1])?.to_i32()?; self.write_scalar( Scalar::from_f64(f.powi(i)), @@ -435,7 +421,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "size_of_val" => { let mplace = self.ref_to_mplace(self.read_value(args[0])?)?; let (size, _) = self.size_and_align_of_mplace(mplace)?; - let ptr_size = self.memory.pointer_size(); + let ptr_size = self.pointer_size(); self.write_scalar( Scalar::from_uint(size.bytes() as u128, ptr_size), dest, @@ -446,7 +432,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "align_of_val" => { let mplace = self.ref_to_mplace(self.read_value(args[0])?)?; let (_, align) = self.size_and_align_of_mplace(mplace)?; - let ptr_size = self.memory.pointer_size(); + let ptr_size = self.pointer_size(); self.write_scalar( Scalar::from_uint(align.abi(), ptr_size), dest, diff --git a/src/lib.rs b/src/lib.rs index 42dac6a28d85..0ce510a65983 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,7 +46,7 @@ use tls::EvalContextExt as TlsEvalContextExt; use memory::MemoryKind as MiriMemoryKind; use locks::LockInfo; use range_map::RangeMap; -use helpers::{ScalarExt, FalibleScalarExt}; +use helpers::FalibleScalarExt; pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, diff --git a/src/tls.rs b/src/tls.rs index 6cec39483c46..bd0318a62ed4 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -1,6 +1,6 @@ use rustc::{ty, mir}; -use super::{TlsKey, TlsEntry, EvalResult, EvalErrorKind, Scalar, ScalarExt, Memory, Evaluator, +use super::{TlsKey, TlsEntry, EvalResult, EvalErrorKind, Scalar, Memory, Evaluator, Place, StackPopCleanup, EvalContext}; pub trait MemoryExt<'tcx> { @@ -22,11 +22,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu fn create_tls_key(&mut self, dtor: Option>) -> TlsKey { let new_key = self.data.next_thread_local; self.data.next_thread_local += 1; - let ptr_size = self.pointer_size(); self.data.thread_local.insert( new_key, TlsEntry { - data: Scalar::null(ptr_size).into(), + data: Scalar::ptr_null(*self.tcx).into(), dtor, }, ); @@ -89,7 +88,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { use std::collections::Bound::*; - let ptr_size = self.pointer_size(); let thread_local = &mut self.data.thread_local; let start = match key { Some(key) => Excluded(key), @@ -101,7 +99,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu if !data.is_null() { if let Some(dtor) = dtor { let ret = Some((dtor, *data, key)); - *data = Scalar::null(ptr_size); + *data = Scalar::ptr_null(*self.tcx); return ret; } } diff --git a/tests/run-pass/char.rs b/tests/run-pass/char.rs index 505c09b0ad88..5524f0ae7abe 100644 --- a/tests/run-pass/char.rs +++ b/tests/run-pass/char.rs @@ -3,7 +3,5 @@ fn main() { assert_eq!(c, 'x'); assert!('a' < 'z'); assert!('1' < '9'); - assert_eq!(std::char::from_u32('x' as u32).unwrap(), 'x'); - // FIXME: - // assert_eq!(std::char::from_u32('x' as u32), Some('x')); + assert_eq!(std::char::from_u32('x' as u32), Some('x')); } From e239fcffc1a211ff3f2f7dce4d084615aaa73715 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Aug 2018 17:08:42 +0200 Subject: [PATCH 0209/5092] new tests for new fn arg passing code --- tests/compile-fail/cast_fn_ptr.rs | 3 +-- tests/compile-fail/cast_fn_ptr2.rs | 3 +-- tests/compile-fail/cast_fn_ptr3.rs | 10 ++++++++++ tests/compile-fail/cast_fn_ptr4.rs | 9 +++++++++ tests/run-pass/non_capture_closure_to_fn_ptr.rs | 6 ++++++ 5 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 tests/compile-fail/cast_fn_ptr3.rs create mode 100644 tests/compile-fail/cast_fn_ptr4.rs diff --git a/tests/compile-fail/cast_fn_ptr.rs b/tests/compile-fail/cast_fn_ptr.rs index 0a8f5ef752a6..0add977bf97b 100644 --- a/tests/compile-fail/cast_fn_ptr.rs +++ b/tests/compile-fail/cast_fn_ptr.rs @@ -5,6 +5,5 @@ fn main() { std::mem::transmute::(f) }; - g(42) //~ ERROR constant evaluation error - //~^ NOTE tried to call a function with sig fn() through a function pointer of type fn(i32) + g(42) //~ ERROR tried to call a function with incorrect number of arguments } diff --git a/tests/compile-fail/cast_fn_ptr2.rs b/tests/compile-fail/cast_fn_ptr2.rs index cb80521c60ee..5af527016fb6 100644 --- a/tests/compile-fail/cast_fn_ptr2.rs +++ b/tests/compile-fail/cast_fn_ptr2.rs @@ -5,6 +5,5 @@ fn main() { std::mem::transmute::(f) }; - g(42) //~ ERROR constant evaluation error - //~^ NOTE tried to call a function with sig fn((i32, i32)) through a function pointer of type fn(i32) + g(42) //~ ERROR tried to call a function with argument of type (i32, i32) passing data of type i32 } diff --git a/tests/compile-fail/cast_fn_ptr3.rs b/tests/compile-fail/cast_fn_ptr3.rs new file mode 100644 index 000000000000..29507e7c7cf5 --- /dev/null +++ b/tests/compile-fail/cast_fn_ptr3.rs @@ -0,0 +1,10 @@ +fn main() { + fn f(_ : (i32,i32)) {} + + let g = unsafe { + std::mem::transmute::(f) + }; + + g() //~ ERROR tried to call a function with incorrect number of arguments +} + diff --git a/tests/compile-fail/cast_fn_ptr4.rs b/tests/compile-fail/cast_fn_ptr4.rs new file mode 100644 index 000000000000..f9a2cf9f6965 --- /dev/null +++ b/tests/compile-fail/cast_fn_ptr4.rs @@ -0,0 +1,9 @@ +fn main() { + fn f(_ : *const [i32]) {} + + let g = unsafe { + std::mem::transmute::(f) + }; + + g(&42 as *const i32) //~ ERROR tried to call a function with argument of type *const [i32] passing data of type *const i32 +} diff --git a/tests/run-pass/non_capture_closure_to_fn_ptr.rs b/tests/run-pass/non_capture_closure_to_fn_ptr.rs index c9daff9c9f46..d48c4df45944 100644 --- a/tests/run-pass/non_capture_closure_to_fn_ptr.rs +++ b/tests/run-pass/non_capture_closure_to_fn_ptr.rs @@ -4,6 +4,9 @@ static FOO: fn() = || { assert_ne!(42, 43) }; #[allow(const_err)] static BAR: fn(i32, i32) = |a, b| { assert_ne!(a, b) }; +// use to first make the closure FnOnce() before making it fn() +fn magic(f: F) -> F { f } + fn main() { FOO(); BAR(44, 45); @@ -11,4 +14,7 @@ fn main() { unsafe { bar(46, 47) }; let boo: &Fn(i32, i32) = &BAR; boo(48, 49); + + let f = magic(||{}) as fn(); + f(); } From c44267960f4642a1875de9e39ef7287961c56d3a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 28 Aug 2018 18:13:58 +0200 Subject: [PATCH 0210/5092] ptr equality: only defined for ptrs in the same allocation and live ptrs --- src/intrinsic.rs | 19 ++- src/lib.rs | 4 +- src/operator.rs | 159 +++++++++++----------- tests/compile-fail/pointer_byte_read_1.rs | 3 +- tests/compile-fail/ptr_bitops.rs | 3 +- 5 files changed, 88 insertions(+), 100 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 695943d57b0c..1b877256c31f 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -116,11 +116,11 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: _ if intrinsic_name.starts_with("atomic_cxchg") => { let ptr = self.ref_to_mplace(self.read_value(args[0])?)?; - let expect_old = self.read_value(args[1])?; // read as value for the sake of `binary_op()` + let expect_old = self.read_value(args[1])?; // read as value for the sake of `binary_op_val()` let new = self.read_scalar(args[2])?; - let old = self.read_value(ptr.into())?; // read as value for the sake of `binary_op()` - // binary_op will bail if either of them is not a scalar - let (eq, _) = self.binary_op(mir::BinOp::Eq, old, expect_old)?; + let old = self.read_value(ptr.into())?; // read as value for the sake of `binary_op_val()` + // binary_op_val will bail if either of them is not a scalar + let (eq, _) = self.binary_op_val(mir::BinOp::Eq, old, expect_old)?; let res = Value::ScalarPair(old.to_scalar_or_undef(), eq.into()); self.write_value(res, dest)?; // old value is returned // update ptr depending on comparison @@ -167,8 +167,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: _ => bug!(), }; // FIXME: what do atomics do on overflow? - let (val, _) = self.binary_op(op, old, rhs)?; - self.write_scalar(val, ptr.into())?; + self.binop_ignore_overflow(op, old, rhs, ptr.into())?; } "breakpoint" => unimplemented!(), // halt miri @@ -255,8 +254,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "frem_fast" => mir::BinOp::Rem, _ => bug!(), }; - let result = self.binary_op(op, a, b)?; - self.write_scalar(result.0, dest)?; + self.binop_ignore_overflow(op, a, b, dest)?; } "exact_div" => { @@ -265,11 +263,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let a = self.read_value(args[0])?; let b = self.read_value(args[1])?; // check x % y != 0 - if !self.binary_op(mir::BinOp::Rem, a, b)?.0.is_null() { + if !self.binary_op_val(mir::BinOp::Rem, a, b)?.0.is_null() { return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b))); } - let result = self.binary_op(mir::BinOp::Div, a, b)?; - self.write_scalar(result.0, dest)?; + self.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; }, "likely" | "unlikely" | "forget" => {} diff --git a/src/lib.rs b/src/lib.rs index 0ce510a65983..b8d3c18c01cb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -304,14 +304,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx.call_intrinsic(instance, args, dest) } - fn try_ptr_op<'a>( + fn ptr_op<'a>( ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, bin_op: mir::BinOp, left: Scalar, left_layout: TyLayout<'tcx>, right: Scalar, right_layout: TyLayout<'tcx>, - ) -> EvalResult<'tcx, Option<(Scalar, bool)>> { + ) -> EvalResult<'tcx, (Scalar, bool)> { ecx.ptr_op(bin_op, left, left_layout, right, right_layout) } diff --git a/src/operator.rs b/src/operator.rs index 03383ae61c89..550e7014afa9 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,5 +1,4 @@ -use rustc::ty::{self, Ty}; -use rustc::ty::layout::{TyLayout, Primitive}; +use rustc::ty::{Ty, layout::TyLayout}; use rustc::mir; use super::*; @@ -12,7 +11,7 @@ pub trait EvalContextExt<'tcx> { left_layout: TyLayout<'tcx>, right: Scalar, right_layout: TyLayout<'tcx>, - ) -> EvalResult<'tcx, Option<(Scalar, bool)>>; + ) -> EvalResult<'tcx, (Scalar, bool)>; fn ptr_int_arithmetic( &self, @@ -22,6 +21,13 @@ pub trait EvalContextExt<'tcx> { signed: bool, ) -> EvalResult<'tcx, (Scalar, bool)>; + fn ptr_eq( + &self, + left: Scalar, + right: Scalar, + size: Size, + ) -> EvalResult<'tcx, bool>; + fn pointer_offset_inbounds( &self, ptr: Scalar, @@ -38,38 +44,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: left_layout: TyLayout<'tcx>, right: Scalar, right_layout: TyLayout<'tcx>, - ) -> EvalResult<'tcx, Option<(Scalar, bool)>> { - trace!("ptr_op: {:?} {:?} {:?}", left, bin_op, right); - + ) -> EvalResult<'tcx, (Scalar, bool)> { use rustc::mir::BinOp::*; - use rustc::ty::layout::Integer::*; - let usize = Primitive::Int(match self.memory.pointer_size().bytes() { - 1 => I8, - 2 => I16, - 4 => I32, - 8 => I64, - 16 => I128, - _ => unreachable!(), - }, /*signed*/ false); - let isize = Primitive::Int(match self.memory.pointer_size().bytes() { - 1 => I8, - 2 => I16, - 4 => I32, - 8 => I64, - 16 => I128, - _ => unreachable!(), - }, /*signed*/ true); - let left_kind = match left_layout.abi { - ty::layout::Abi::Scalar(ref scalar) => scalar.value, - _ => Err(EvalErrorKind::TypeNotPrimitive(left_layout.ty))?, - }; - let right_kind = match right_layout.abi { - ty::layout::Abi::Scalar(ref scalar) => scalar.value, - _ => Err(EvalErrorKind::TypeNotPrimitive(right_layout.ty))?, - }; + + trace!("ptr_op: {:?} {:?} {:?}", left, bin_op, right); + debug_assert!(left.is_ptr() || right.is_ptr() || bin_op == Offset); + match bin_op { Offset => { - assert!(left_kind == Primitive::Pointer && right_kind == usize); let pointee_ty = left_layout.ty .builtin_deref(true) .expect("Offset called on non-ptr type") @@ -77,40 +59,19 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ptr = self.pointer_offset_inbounds( left, pointee_ty, - right.to_bits(self.memory.pointer_size())? as i64, + right.to_isize(self)?, )?; - Ok(Some((ptr, false))) + Ok((ptr, false)) } // These work on anything - Eq if left_kind == right_kind => { - let result = match (left, right) { - (Scalar::Bits { .. }, Scalar::Bits { .. }) => { - left.to_bits(left_layout.size)? == right.to_bits(right_layout.size)? - }, - // FIXME: Test if both allocations are still live *or* if they are in the same allocation? (same for Ne below) - (Scalar::Ptr(left), Scalar::Ptr(right)) => left == right, - // FIXME: We should probably error out when comparing anything but NULL with a pointer (same for Ne below) - _ => false, - }; - Ok(Some((Scalar::from_bool(result), false))) - } - Ne if left_kind == right_kind => { - let result = match (left, right) { - (Scalar::Bits { .. }, Scalar::Bits { .. }) => { - left.to_bits(left_layout.size)? != right.to_bits(right_layout.size)? - }, - (Scalar::Ptr(left), Scalar::Ptr(right)) => left != right, - _ => true, - }; - Ok(Some((Scalar::from_bool(result), false))) - } - // These need both pointers to be in the same allocation - Lt | Le | Gt | Ge | Sub - if left_kind == right_kind && - (left_kind == Primitive::Pointer || left_kind == usize || left_kind == isize) && - left.is_ptr() && right.is_ptr() => { - let left = left.to_ptr()?; - let right = right.to_ptr()?; + Eq => + Ok((Scalar::from_bool(self.ptr_eq(left, right, left_layout.size)?), false)), + Ne => + Ok((Scalar::from_bool(!self.ptr_eq(left, right, left_layout.size)?), false)), + // These need both to be pointer, and fail if they are not in the same location + Lt | Le | Gt | Ge | Sub if left.is_ptr() && right.is_ptr() => { + let left = left.to_ptr().expect("we checked is_ptr"); + let right = right.to_ptr().expect("we checked is_ptr"); if left.alloc_id == right.alloc_id { let res = match bin_op { Lt => left.offset < right.offset, @@ -118,51 +79,83 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Gt => left.offset > right.offset, Ge => left.offset >= right.offset, Sub => { + // subtract the offsets let left_offset = Scalar::from_uint(left.offset.bytes(), self.memory.pointer_size()); let right_offset = Scalar::from_uint(right.offset.bytes(), self.memory.pointer_size()); let layout = self.layout_of(self.tcx.types.usize)?; return self.binary_op( Sub, - ValTy { value: Value::Scalar(left_offset.into()), layout }, - ValTy { value: Value::Scalar(right_offset.into()), layout }, - ).map(Some) + left_offset, layout, + right_offset, layout, + ) } _ => bug!("We already established it has to be one of these operators."), }; - Ok(Some((Scalar::from_bool(res), false))) + Ok((Scalar::from_bool(res), false)) } else { // Both are pointers, but from different allocations. err!(InvalidPointerMath) } } - // These work if the left operand is a pointer, the right an integer - Add | BitAnd | Sub | Rem - if left_kind == right_kind && (left_kind == usize || left_kind == isize) && - left.is_ptr() && right.is_bits() => { + // These work if the left operand is a pointer, and the right an integer + Add | BitAnd | Sub | Rem if left.is_ptr() && right.is_bits() => { // Cast to i128 is fine as we checked the kind to be ptr-sized self.ptr_int_arithmetic( bin_op, - left.to_ptr()?, - right.to_bits(self.memory.pointer_size())?, - left_kind == isize, - ).map(Some) + left.to_ptr().expect("we checked is_ptr"), + right.to_bits(self.memory.pointer_size()).expect("we checked is_bits"), + right_layout.abi.is_signed(), + ) } // Commutative operators also work if the integer is on the left - Add | BitAnd - if left_kind == right_kind && (left_kind == usize || left_kind == isize) && - left.is_bits() && right.is_ptr() => { + Add | BitAnd if left.is_bits() && right.is_ptr() => { // This is a commutative operation, just swap the operands self.ptr_int_arithmetic( bin_op, - right.to_ptr()?, - left.to_bits(self.memory.pointer_size())?, - left_kind == isize, - ).map(Some) + right.to_ptr().expect("we checked is_ptr"), + left.to_bits(self.memory.pointer_size()).expect("we checked is_bits"), + left_layout.abi.is_signed(), + ) } - _ => Ok(None), + // Nothing else works + _ => err!(InvalidPointerMath), } } + fn ptr_eq( + &self, + left: Scalar, + right: Scalar, + size: Size, + ) -> EvalResult<'tcx, bool> { + Ok(match (left, right) { + (Scalar::Bits { .. }, Scalar::Bits { .. }) => + left.to_bits(size)? == right.to_bits(size)?, + (Scalar::Ptr(left), Scalar::Ptr(right)) => { + // Comparison illegal if one of them is out-of-bounds, *unless* they + // are in the same allocation. + if left.alloc_id == right.alloc_id { + left.offset == right.offset + } else { + // This accepts one-past-the end. So technically there is still + // some non-determinism that we do not fully rule out when two + // allocations sit right next to each other. The C/C++ standards are + // somewhat fuzzy about this case, so I think for now this check is + // "good enough". + self.memory.check_bounds(left, false)?; + self.memory.check_bounds(right, false)?; + // Two live in-bounds pointers, we can compare across allocations + left == right + } + } + // Comparing ptr and integer -- we only allow compating with NULL + (Scalar::Ptr(_), Scalar::Bits { bits: 0, .. }) | + (Scalar::Bits { bits: 0, .. }, Scalar::Ptr(_)) => false, + // Nothing else is supported + _ => return err!(InvalidPointerMath), + }) + } + fn ptr_int_arithmetic( &self, bin_op: mir::BinOp, diff --git a/tests/compile-fail/pointer_byte_read_1.rs b/tests/compile-fail/pointer_byte_read_1.rs index 4cfdfb62e27f..b25f09d485fb 100644 --- a/tests/compile-fail/pointer_byte_read_1.rs +++ b/tests/compile-fail/pointer_byte_read_1.rs @@ -3,6 +3,5 @@ fn main() { let y = &x; let z = &y as *const &i32 as *const usize; let ptr_bytes = unsafe { *z }; // the actual deref is fine, because we read the entire pointer at once - let _ = ptr_bytes / 432; //~ ERROR constant evaluation error - //~^ NOTE tried to access part of a pointer value as raw bytes + let _ = ptr_bytes / 432; //~ ERROR invalid arithmetic on pointers that would leak base addresses } diff --git a/tests/compile-fail/ptr_bitops.rs b/tests/compile-fail/ptr_bitops.rs index ecd47a186efb..2706b0970d7d 100644 --- a/tests/compile-fail/ptr_bitops.rs +++ b/tests/compile-fail/ptr_bitops.rs @@ -2,7 +2,6 @@ fn main() { let bytes = [0i8, 1, 2, 3, 4, 5, 6, 7, 8, 9]; let one = bytes.as_ptr().wrapping_offset(1); let three = bytes.as_ptr().wrapping_offset(3); - let res = (one as usize) | (three as usize); //~ ERROR constant evaluation error - //~^ NOTE a raw memory access tried to access part of a pointer value as raw bytes + let res = (one as usize) | (three as usize); //~ ERROR invalid arithmetic on pointers that would leak base addresses println!("{}", res); } From fe9cd1c98d5ca861986eaf2bc0aaf953a375ca5c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Aug 2018 10:50:13 +0200 Subject: [PATCH 0211/5092] strictly enforce pointer validity even for zero-sized accesses --- src/intrinsic.rs | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 6847d8e546f3..f562aec32337 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -179,21 +179,17 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let elem_layout = self.layout_of(elem_ty)?; let elem_size = elem_layout.size.bytes(); let count = self.read_scalar(args[2])?.to_usize(&self)?; - if count * elem_size != 0 { - // TODO: We do not even validate alignment for the 0-bytes case. libstd relies on this in vec::IntoIter::next. - // Also see the write_bytes intrinsic. - let elem_align = elem_layout.align; - let src = self.read_scalar(args[0])?.not_undef()?; - let dest = self.read_scalar(args[1])?.not_undef()?; - self.memory.copy( - src, - elem_align, - dest, - elem_align, - Size::from_bytes(count * elem_size), - intrinsic_name.ends_with("_nonoverlapping"), - )?; - } + let elem_align = elem_layout.align; + let src = self.read_scalar(args[0])?.not_undef()?; + let dest = self.read_scalar(args[1])?.not_undef()?; + self.memory.copy( + src, + elem_align, + dest, + elem_align, + Size::from_bytes(count * elem_size), + intrinsic_name.ends_with("_nonoverlapping"), + )?; } "discriminant_value" => { @@ -563,12 +559,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let val_byte = self.read_scalar(args[1])?.to_u8()?; let ptr = self.read_scalar(args[0])?.not_undef()?; let count = self.read_scalar(args[2])?.to_usize(&self)?; - if count > 0 { - // HashMap relies on write_bytes on a NULL ptr with count == 0 to work - // TODO: Should we, at least, validate the alignment? (Also see the copy intrinsic) - self.memory.check_align(ptr, ty_layout.align)?; - self.memory.write_repeat(ptr, val_byte, ty_layout.size * count)?; - } + self.memory.check_align(ptr, ty_layout.align)?; + self.memory.write_repeat(ptr, val_byte, ty_layout.size * count)?; } name => return err!(Unimplemented(format!("unimplemented intrinsic: {}", name))), From 2a318264ea493c62b8ec2fe110654e3177b49939 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Aug 2018 11:04:48 +0200 Subject: [PATCH 0212/5092] also allow comparing pointers with integers so big that they cannot be equal --- src/operator.rs | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index 550e7014afa9..576c4a271f96 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -148,11 +148,30 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: left == right } } - // Comparing ptr and integer -- we only allow compating with NULL - (Scalar::Ptr(_), Scalar::Bits { bits: 0, .. }) | - (Scalar::Bits { bits: 0, .. }, Scalar::Ptr(_)) => false, - // Nothing else is supported - _ => return err!(InvalidPointerMath), + // Comparing ptr and integer -- we allow compating with NULL, and with addresses + // so close to the end of the `usize` range that they cannot overlap with an allocation + // of the given size. + (Scalar::Ptr(ptr), Scalar::Bits { bits, size }) | + (Scalar::Bits { bits, size }, Scalar::Ptr(ptr)) => { + assert_eq!(size as u64, self.pointer_size().bytes()); + if bits == 0 { + // Nothing equals 0 + false + } else { + // Compute the highest address at which this allocation could live + let alloc = self.memory.get(ptr.alloc_id)?; + let max_base_addr = + (1u128 << self.pointer_size().bits()) - alloc.bytes.len() as u128; + let max_addr = max_base_addr + ptr.offset.bytes() as u128; + if bits > max_addr { + // The integer is too big, this cannot possibly be equal + false + } else { + // TODO: We could also take alignment into account + return err!(InvalidPointerMath); + } + } + } }) } From f56841d974056509969180e03c528963b2a76481 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Aug 2018 15:57:17 +0200 Subject: [PATCH 0213/5092] unignore a bunch of tests that actually work --- tests/compile-fail/invalid_bool.rs | 2 +- tests/compile-fail/match_char.rs | 2 +- tests/compile-fail/panic.rs | 1 - tests/run-pass-fullmir/catch.rs | 3 +-- tests/run-pass-fullmir/foreign-fn-linkname.rs | 2 +- tests/run-pass-fullmir/format.rs | 3 +-- tests/run-pass-fullmir/from_utf8.rs | 1 - tests/run-pass-fullmir/hashmap.rs | 1 - tests/run-pass-fullmir/hello.rs | 3 +-- tests/run-pass-fullmir/integer-ops.rs | 3 +-- tests/run-pass-fullmir/issue-3794.rs | 3 +-- tests/run-pass-fullmir/loop-break-value.rs | 2 -- .../send-is-not-static-par-for.rs | 2 -- tests/run-pass-fullmir/u128.rs | 2 -- tests/run-pass-fullmir/unsized-tuple-impls.rs | 2 -- tests/run-pass/heap.rs | 1 - tests/run-pass/issue-15080.rs | 2 -- tests/run-pass/issue-17877.rs | 3 ++- tests/run-pass/move-arg-2-unique.rs | 2 -- tests/run-pass/regions-mock-trans.rs | 2 +- tests/run-pass/thread-local.rs | 2 +- tests/run-pass/vecs.rs | 2 -- 22 files changed, 12 insertions(+), 34 deletions(-) rename tests/{run-pass => run-pass-fullmir}/send-is-not-static-par-for.rs (98%) diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index bd08c0ce4eb9..49328ef5d74e 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -1,4 +1,4 @@ -//ignore-test FIXME (do some basic validation of invariants for all values in flight) +//ignore-test FIXME: do some basic validation of invariants for all values in flight //This does currently not get caught becuase it compiles to SwitchInt, which //has no knowledge about data invariants. diff --git a/tests/compile-fail/match_char.rs b/tests/compile-fail/match_char.rs index fd4431992d9b..e7fee1e3e361 100644 --- a/tests/compile-fail/match_char.rs +++ b/tests/compile-fail/match_char.rs @@ -1,4 +1,4 @@ -// ignore-test FIXME: we are not checking these things on match any more? +//ignore-test FIXME: do some basic validation of invariants for all values in flight //This does currently not get caught becuase it compiles to SwitchInt, which //has no knowledge about data invariants. diff --git a/tests/compile-fail/panic.rs b/tests/compile-fail/panic.rs index 1f9e8f6e1d0b..80149eeffaa6 100644 --- a/tests/compile-fail/panic.rs +++ b/tests/compile-fail/panic.rs @@ -1,4 +1,3 @@ -//ignore-windows // FIXME: Something in panic handling fails validation with full-MIR // compile-flags: -Zmir-emit-validate=0 //error-pattern: the evaluated program panicked diff --git a/tests/run-pass-fullmir/catch.rs b/tests/run-pass-fullmir/catch.rs index 60c86c99e9aa..960297daa7ef 100644 --- a/tests/run-pass-fullmir/catch.rs +++ b/tests/run-pass-fullmir/catch.rs @@ -1,5 +1,4 @@ -//ignore-msvc -//ignore-macos +//ignore-msvc: Stdout not implemented on Windows use std::panic::{catch_unwind, AssertUnwindSafe}; fn main() { diff --git a/tests/run-pass-fullmir/foreign-fn-linkname.rs b/tests/run-pass-fullmir/foreign-fn-linkname.rs index 20cb713590c9..789e3eccceb7 100644 --- a/tests/run-pass-fullmir/foreign-fn-linkname.rs +++ b/tests/run-pass-fullmir/foreign-fn-linkname.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//ignore-msvc +//ignore-windows: Uses POSIX APIs #![feature(libc)] extern crate libc; diff --git a/tests/run-pass-fullmir/format.rs b/tests/run-pass-fullmir/format.rs index 59af803b59f0..b1b05abd2965 100644 --- a/tests/run-pass-fullmir/format.rs +++ b/tests/run-pass-fullmir/format.rs @@ -1,5 +1,4 @@ -//ignore-msvc -//ignore-macos +//ignore-msvc: Stdout not implemented on Windows fn main() { println!("Hello {}", 13); } diff --git a/tests/run-pass-fullmir/from_utf8.rs b/tests/run-pass-fullmir/from_utf8.rs index c5d4abcfdaef..69e6c521af6e 100644 --- a/tests/run-pass-fullmir/from_utf8.rs +++ b/tests/run-pass-fullmir/from_utf8.rs @@ -1,4 +1,3 @@ -//ignore-msvc fn main() { let _ = ::std::str::from_utf8(b"a"); } diff --git a/tests/run-pass-fullmir/hashmap.rs b/tests/run-pass-fullmir/hashmap.rs index 99f05e25985e..f4a358174f55 100644 --- a/tests/run-pass-fullmir/hashmap.rs +++ b/tests/run-pass-fullmir/hashmap.rs @@ -1,4 +1,3 @@ -//ignore-msvc use std::collections::{self, HashMap}; use std::hash::BuildHasherDefault; diff --git a/tests/run-pass-fullmir/hello.rs b/tests/run-pass-fullmir/hello.rs index a0d73733bdfc..c92c1567f5ae 100644 --- a/tests/run-pass-fullmir/hello.rs +++ b/tests/run-pass-fullmir/hello.rs @@ -1,5 +1,4 @@ -//ignore-msvc -//ignore-macos +//ignore-msvc: Stdout not implemented on Windows fn main() { println!("Hello, world!"); } diff --git a/tests/run-pass-fullmir/integer-ops.rs b/tests/run-pass-fullmir/integer-ops.rs index 97c694fd5674..7a2335c829ef 100644 --- a/tests/run-pass-fullmir/integer-ops.rs +++ b/tests/run-pass-fullmir/integer-ops.rs @@ -11,7 +11,6 @@ // FIXME: remove -Zmir-opt-level once https://github.com/rust-lang/rust/issues/43359 is fixed // compile-flags: -Zmir-opt-level=0 -//ignore-msvc use std::i32; pub fn main() { @@ -168,7 +167,7 @@ pub fn main() { assert_eq!(0x10i32.overflowing_shr(4), (0x1, false)); assert_eq!(0x10i32.overflowing_shr(36), (0x1, true)); - + assert_eq!(10i8.overflowing_abs(), (10,false)); assert_eq!((-10i8).overflowing_abs(), (10,false)); assert_eq!((-128i8).overflowing_abs(), (-128,true)); diff --git a/tests/run-pass-fullmir/issue-3794.rs b/tests/run-pass-fullmir/issue-3794.rs index 8b653f0f95fc..32b4d27f11f5 100644 --- a/tests/run-pass-fullmir/issue-3794.rs +++ b/tests/run-pass-fullmir/issue-3794.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//ignore-msvc -//ignore-macos +//ignore-msvc: Stdout not implemented on Windows #![feature(box_syntax)] trait T { diff --git a/tests/run-pass-fullmir/loop-break-value.rs b/tests/run-pass-fullmir/loop-break-value.rs index 8a0ea113c5d6..8631909a2a96 100644 --- a/tests/run-pass-fullmir/loop-break-value.rs +++ b/tests/run-pass-fullmir/loop-break-value.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//ignore-msvc - #![feature(never_type)] #![allow(unreachable_code)] diff --git a/tests/run-pass/send-is-not-static-par-for.rs b/tests/run-pass-fullmir/send-is-not-static-par-for.rs similarity index 98% rename from tests/run-pass/send-is-not-static-par-for.rs rename to tests/run-pass-fullmir/send-is-not-static-par-for.rs index 4ac1b5436f52..1b913aed4c89 100644 --- a/tests/run-pass/send-is-not-static-par-for.rs +++ b/tests/run-pass-fullmir/send-is-not-static-par-for.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//ignore-windows - use std::sync::Mutex; fn par_for(iter: I, f: F) diff --git a/tests/run-pass-fullmir/u128.rs b/tests/run-pass-fullmir/u128.rs index d7764bf6201a..ca33bd5f9e3d 100644 --- a/tests/run-pass-fullmir/u128.rs +++ b/tests/run-pass-fullmir/u128.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//ignore-msvc - fn b(t: T) -> T { t } fn main() { diff --git a/tests/run-pass-fullmir/unsized-tuple-impls.rs b/tests/run-pass-fullmir/unsized-tuple-impls.rs index 828e5c26927e..ccb6883e8733 100644 --- a/tests/run-pass-fullmir/unsized-tuple-impls.rs +++ b/tests/run-pass-fullmir/unsized-tuple-impls.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//ignore-msvc - #![feature(unsized_tuple_coercion)] use std::mem; diff --git a/tests/run-pass/heap.rs b/tests/run-pass/heap.rs index 917d51d0e4b6..b533f9164698 100644 --- a/tests/run-pass/heap.rs +++ b/tests/run-pass/heap.rs @@ -1,4 +1,3 @@ -//ignore-msvc #![feature(box_syntax)] fn make_box() -> Box<(i16, i16)> { diff --git a/tests/run-pass/issue-15080.rs b/tests/run-pass/issue-15080.rs index 4a84f2bc5d62..b5b1edcfddd0 100644 --- a/tests/run-pass/issue-15080.rs +++ b/tests/run-pass/issue-15080.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//ignore-msvc - #![feature(slice_patterns)] fn main() { diff --git a/tests/run-pass/issue-17877.rs b/tests/run-pass/issue-17877.rs index b4b74b9905fb..762bacbe0e6f 100644 --- a/tests/run-pass/issue-17877.rs +++ b/tests/run-pass/issue-17877.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//ignore-msvc +//ignore-windows: Causes a stack overflow?!? Likely a rustc bug: https://github.com/rust-lang/rust/issues/53820 +//Once that bug is fixed, increase the size to 16*1024 and enable on all platforms. #![feature(slice_patterns)] diff --git a/tests/run-pass/move-arg-2-unique.rs b/tests/run-pass/move-arg-2-unique.rs index f3c656623765..d44c83763b7c 100644 --- a/tests/run-pass/move-arg-2-unique.rs +++ b/tests/run-pass/move-arg-2-unique.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//ignore-msvc - #![allow(unused_features, unused_variables)] #![feature(box_syntax)] diff --git a/tests/run-pass/regions-mock-trans.rs b/tests/run-pass/regions-mock-trans.rs index 74e94ddbf84f..039175e9acd6 100644 --- a/tests/run-pass/regions-mock-trans.rs +++ b/tests/run-pass/regions-mock-trans.rs @@ -11,7 +11,7 @@ // FIXME: We handle uninitialized storage here, which currently makes validation fail. // compile-flags: -Zmir-emit-validate=0 -//ignore-msvc +//ignore-windows: Uses POSIX APIs #![feature(libc)] diff --git a/tests/run-pass/thread-local.rs b/tests/run-pass/thread-local.rs index db00e42d99ac..8c20e89ab52d 100644 --- a/tests/run-pass/thread-local.rs +++ b/tests/run-pass/thread-local.rs @@ -1,4 +1,4 @@ -//ignore-windows +//ignore-windows: Uses POSIX APIs #![feature(libc)] extern crate libc; diff --git a/tests/run-pass/vecs.rs b/tests/run-pass/vecs.rs index 9a8912a6b988..776791bbc9b9 100644 --- a/tests/run-pass/vecs.rs +++ b/tests/run-pass/vecs.rs @@ -1,5 +1,3 @@ -//ignore-msvc - fn make_vec() -> Vec { let mut v = Vec::with_capacity(4); v.push(1); From 74c6a1aa49cadfc463f275a6b8d21ea5dd8d561b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 1 Sep 2018 10:33:53 +0200 Subject: [PATCH 0214/5092] bump toolchain --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index f54012d5e14b..448c24468e5c 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-08-30 +nightly-2018-09-01 From d3928f6356de808b1df402cc66e9e6d36a9dce8c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 1 Sep 2018 11:26:54 +0200 Subject: [PATCH 0215/5092] more permissive pointer comparison logic --- src/operator.rs | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index 576c4a271f96..4f697dbd5b74 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -148,28 +148,21 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: left == right } } - // Comparing ptr and integer -- we allow compating with NULL, and with addresses - // so close to the end of the `usize` range that they cannot overlap with an allocation - // of the given size. + // Comparing ptr and integer (Scalar::Ptr(ptr), Scalar::Bits { bits, size }) | (Scalar::Bits { bits, size }, Scalar::Ptr(ptr)) => { assert_eq!(size as u64, self.pointer_size().bytes()); + if bits == 0 { - // Nothing equals 0 + // Nothing equals 0, not even dangling pointers. Ideally we would + // require them to be in-bounds of their (possilby dead) allocation, + // but with the allocation gonew e cannot check that. false } else { - // Compute the highest address at which this allocation could live - let alloc = self.memory.get(ptr.alloc_id)?; - let max_base_addr = - (1u128 << self.pointer_size().bits()) - alloc.bytes.len() as u128; - let max_addr = max_base_addr + ptr.offset.bytes() as u128; - if bits > max_addr { - // The integer is too big, this cannot possibly be equal - false - } else { - // TODO: We could also take alignment into account - return err!(InvalidPointerMath); - } + // Live pointers cannot equal an integer, but again do not + // allow comparing dead pointers. + self.memory.check_bounds(ptr, false)?; + false } } }) From 90d7cb24934e26bec907d221e1709ae8b8473601 Mon Sep 17 00:00:00 2001 From: thedarkula Date: Thu, 30 Aug 2018 21:06:53 +0100 Subject: [PATCH 0216/5092] Removed transmute from intrinsic.rs --- src/intrinsic.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 6847d8e546f3..2c5b204b060a 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -460,14 +460,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: self.write_value(value, dest)?; } - "transmute" => { - // Go through an allocation, to make sure the completely different layouts - // do not pose a problem. (When the user transmutes through a union, - // there will not be a layout mismatch.) - let dest = self.force_allocation(dest)?; - self.copy_op(args[0], dest.into())?; - } - "unchecked_shl" => { let bits = dest.layout.size.bytes() as u128 * 8; let l = self.read_value(args[0])?; From 055c63ab0d299c47464bb37ee1f766e3e95a50b2 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 6 Sep 2018 16:07:13 +0200 Subject: [PATCH 0217/5092] Remove unchecked_shr/shl from intrinsics --- src/intrinsic.rs | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 056caf3cd9e1..a57307ed12e7 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -443,42 +443,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: self.write_value(value, dest)?; } - "unchecked_shl" => { - let bits = dest.layout.size.bytes() as u128 * 8; - let l = self.read_value(args[0])?; - let r = self.read_value(args[1])?; - let rval = r.to_scalar()?.to_bytes()?; - if rval >= bits { - return err!(Intrinsic( - format!("Overflowing shift by {} in unchecked_shl", rval), - )); - } - self.binop_ignore_overflow( - mir::BinOp::Shl, - l, - r, - dest, - )?; - } - - "unchecked_shr" => { - let bits = dest.layout.size.bytes() as u128 * 8; - let l = self.read_value(args[0])?; - let r = self.read_value(args[1])?; - let rval = r.to_scalar()?.to_bytes()?; - if rval >= bits { - return err!(Intrinsic( - format!("Overflowing shift by {} in unchecked_shr", rval), - )); - } - self.binop_ignore_overflow( - mir::BinOp::Shr, - l, - r, - dest, - )?; - } - "unchecked_div" => { let l = self.read_value(args[0])?; let r = self.read_value(args[1])?; From 72918c1a97458fb30163677af8dfb4fb573cdeb6 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 6 Sep 2018 16:49:08 +0200 Subject: [PATCH 0218/5092] Remove (overflowing_)add/mul/sub(_with_overflow) --- src/intrinsic.rs | 66 ------------------------------------------------ 1 file changed, 66 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index a57307ed12e7..a8cb58fdddfe 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -33,39 +33,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..]; match intrinsic_name { - "add_with_overflow" => { - let l = self.read_value(args[0])?; - let r = self.read_value(args[1])?; - self.binop_with_overflow( - mir::BinOp::Add, - l, - r, - dest, - )? - } - - "sub_with_overflow" => { - let l = self.read_value(args[0])?; - let r = self.read_value(args[1])?; - self.binop_with_overflow( - mir::BinOp::Sub, - l, - r, - dest, - )? - } - - "mul_with_overflow" => { - let l = self.read_value(args[0])?; - let r = self.read_value(args[1])?; - self.binop_with_overflow( - mir::BinOp::Mul, - l, - r, - dest, - )? - } - "arith_offset" => { let offset = self.read_scalar(args[1])?.to_isize(&self)?; let ptr = self.read_scalar(args[0])?.not_undef()?; @@ -326,39 +293,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: self.write_scalar(result_ptr, dest)?; } - "overflowing_sub" => { - let l = self.read_value(args[0])?; - let r = self.read_value(args[1])?; - self.binop_ignore_overflow( - mir::BinOp::Sub, - l, - r, - dest, - )?; - } - - "overflowing_mul" => { - let l = self.read_value(args[0])?; - let r = self.read_value(args[1])?; - self.binop_ignore_overflow( - mir::BinOp::Mul, - r, - l, - dest, - )?; - } - - "overflowing_add" => { - let l = self.read_value(args[0])?; - let r = self.read_value(args[1])?; - self.binop_ignore_overflow( - mir::BinOp::Add, - r, - l, - dest, - )?; - } - "powf32" => { let f = self.read_scalar(args[0])?.to_f32()?; let f2 = self.read_scalar(args[1])?.to_f32()?; From d889da43f8f55d2ca1a795915d2375342e2a520c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Sep 2018 10:57:39 +0200 Subject: [PATCH 0219/5092] move MemoryData to memory.rs; remove all the Hashing stuff --- src/lib.rs | 74 +++------------------------------------------------ src/memory.rs | 42 ++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 71 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b8d3c18c01cb..6758cbeb9539 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,14 +18,11 @@ use rustc::ty::layout::{TyLayout, LayoutOf, Size}; use rustc::hir::def_id::DefId; use rustc::mir; -use rustc_data_structures::fx::FxHasher; - use syntax::ast::Mutability; use syntax::attr; use std::marker::PhantomData; -use std::collections::{HashMap, BTreeMap}; -use std::hash::{Hash, Hasher}; +use std::collections::HashMap; pub use rustc::mir::interpret::*; pub use rustc_mir::interpret::*; @@ -43,7 +40,7 @@ use fn_call::EvalContextExt as MissingFnsEvalContextExt; use operator::EvalContextExt as OperatorEvalContextExt; use intrinsic::EvalContextExt as IntrinsicEvalContextExt; use tls::EvalContextExt as TlsEvalContextExt; -use memory::MemoryKind as MiriMemoryKind; +use memory::{MemoryKind as MiriMemoryKind, TlsKey, TlsEntry, MemoryData}; use locks::LockInfo; use range_map::RangeMap; use helpers::FalibleScalarExt; @@ -214,75 +211,12 @@ pub struct Evaluator<'tcx> { _dummy : PhantomData<&'tcx ()>, } -impl<'tcx> Hash for Evaluator<'tcx> { - fn hash(&self, state: &mut H) { - let Evaluator { - env_vars, - _dummy: _, - } = self; - - env_vars.iter() - .map(|(env, ptr)| { - let mut h = FxHasher::default(); - env.hash(&mut h); - ptr.hash(&mut h); - h.finish() - }) - .fold(0u64, |acc, hash| acc.wrapping_add(hash)) - .hash(state); - } -} - -pub type TlsKey = u128; - -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -pub struct TlsEntry<'tcx> { - data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. - dtor: Option>, -} - -#[derive(Clone, PartialEq, Eq)] -pub struct MemoryData<'tcx> { - /// The Key to use for the next thread-local allocation. - next_thread_local: TlsKey, - - /// pthreads-style thread-local storage. - thread_local: BTreeMap>, - - /// Memory regions that are locked by some function - /// - /// Only mutable (static mut, heap, stack) allocations have an entry in this map. - /// The entry is created when allocating the memory and deleted after deallocation. - locks: HashMap>>, -} - -impl<'tcx> MemoryData<'tcx> { - fn new() -> Self { - MemoryData { - next_thread_local: 1, // start with 1 as we must not use 0 on Windows - thread_local: BTreeMap::new(), - locks: HashMap::new(), - } - } -} - -impl<'tcx> Hash for MemoryData<'tcx> { - fn hash(&self, state: &mut H) { - let MemoryData { - next_thread_local: _, - thread_local, - locks: _, - } = self; - - thread_local.hash(state); - } -} - impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { - type MemoryData = MemoryData<'tcx>; + type MemoryData = memory::MemoryData<'tcx>; type MemoryKinds = memory::MemoryKind; const MUT_STATIC_KIND: Option = Some(memory::MemoryKind::MutStatic); + const DETECT_LOOPS: bool = false; /// Returns Ok() when the function was handled, fail otherwise fn find_fn<'a>( diff --git a/src/memory.rs b/src/memory.rs index d4575d677fa1..9f8118a223bc 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -1,4 +1,44 @@ -#[derive(Debug, PartialEq, Copy, Clone, Hash, Eq)] +use std::collections::{HashMap, BTreeMap}; + +use rustc::ty; + +use super::{AllocId, Scalar, LockInfo, RangeMap}; + +pub type TlsKey = u128; + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct TlsEntry<'tcx> { + pub(crate) data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. + pub(crate) dtor: Option>, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct MemoryData<'tcx> { + /// The Key to use for the next thread-local allocation. + pub(crate) next_thread_local: TlsKey, + + /// pthreads-style thread-local storage. + pub(crate) thread_local: BTreeMap>, + + /// Memory regions that are locked by some function + /// + /// Only mutable (static mut, heap, stack) allocations have an entry in this map. + /// The entry is created when allocating the memory and deleted after deallocation. + pub(crate) locks: HashMap>>, +} + +impl<'tcx> MemoryData<'tcx> { + pub(crate) fn new() -> Self { + MemoryData { + next_thread_local: 1, // start with 1 as we must not use 0 on Windows + thread_local: BTreeMap::new(), + locks: HashMap::new(), + } + } +} + + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum MemoryKind { /// `__rust_alloc` memory Rust, From b488b51b66c8740f8e8e3e68d225e7ef14e8cf55 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 15 Sep 2018 10:31:20 +0200 Subject: [PATCH 0220/5092] bump Rust --- rust-toolchain | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-toolchain b/rust-toolchain index 448c24468e5c..125ee2d98854 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-09-01 +nightly-2018-09-15 diff --git a/src/lib.rs b/src/lib.rs index 6758cbeb9539..8bf66999c3de 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -60,7 +60,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; - if !main_mir.return_ty().is_nil() || main_mir.arg_count != 0 { + if !main_mir.return_ty().is_unit() || main_mir.arg_count != 0 { return err!(Unimplemented( "miri does not support main functions without `fn()` type signatures" .to_owned(), From f925e5dafdbd5aeb14cf6626e059456b23b8f613 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Sep 2018 15:06:05 +0200 Subject: [PATCH 0221/5092] cargo miri: show version number --- Cargo.toml | 3 +++ build.rs | 16 ++++++++++++++++ src/bin/cargo-miri.rs | 3 ++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3f7aabe03ce2..d690f87b536c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,9 @@ cargo_metadata = { version = "0.6", optional = true } env_logger = "0.5" log = "0.4" +[build-dependencies] +vergen = "2" + [features] cargo_miri = ["cargo_metadata"] diff --git a/build.rs b/build.rs index 2f74f7f4f616..73eb68359a82 100644 --- a/build.rs +++ b/build.rs @@ -1,3 +1,5 @@ +extern crate vergen; + use std::env; fn main() { @@ -5,4 +7,18 @@ fn main() { println!("cargo:rustc-env=PROFILE={}", env::var("PROFILE").unwrap()); // Don't rebuild miri even if nothing changed println!("cargo:rerun-if-changed=build.rs"); + // vergen + vergen().expect("Unable to generate vergen constants!"); +} + +fn vergen() -> vergen::Result<()> { + use vergen::{ConstantsFlags, Vergen}; + + let vergen = Vergen::new(ConstantsFlags::all())?; + + for (k, v) in vergen.build_info() { + println!("cargo:rustc-env={}={}", k.name(), v); + } + + Ok(()) } diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 010f25e8152d..95ce9cc7ecb5 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -30,7 +30,8 @@ fn show_help() { } fn show_version() { - println!("{}", env!("CARGO_PKG_VERSION")); + println!("miri {} ({} {})", + env!("CARGO_PKG_VERSION"), env!("VERGEN_SHA_SHORT"), env!("VERGEN_COMMIT_DATE")); } fn main() { From 95eb77c18e8532d490efbedff6424d369b7e83df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Sep 2018 16:47:37 +0200 Subject: [PATCH 0222/5092] add some compile-fail tests --- tests/compile-fail/copy_null.rs | 18 ++++++++++++++++++ tests/compile-fail/copy_unaligned.rs | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/compile-fail/copy_null.rs create mode 100644 tests/compile-fail/copy_unaligned.rs diff --git a/tests/compile-fail/copy_null.rs b/tests/compile-fail/copy_null.rs new file mode 100644 index 000000000000..e46e327e6111 --- /dev/null +++ b/tests/compile-fail/copy_null.rs @@ -0,0 +1,18 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//error-pattern: invalid use of NULL pointer + +fn main() { + let mut data = [0u16; 4]; + let ptr = &mut data[0] as *mut u16; + // Even copying 0 elements from NULL should error + unsafe { ptr.copy_from(std::ptr::null(), 0); } +} diff --git a/tests/compile-fail/copy_unaligned.rs b/tests/compile-fail/copy_unaligned.rs new file mode 100644 index 000000000000..0f04dc68db90 --- /dev/null +++ b/tests/compile-fail/copy_unaligned.rs @@ -0,0 +1,18 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//error-pattern: tried to access memory with alignment 1, but alignment 2 is required + +fn main() { + let mut data = [0u16; 8]; + let ptr = (&mut data[0] as *mut u16 as *mut u8).wrapping_add(1) as *mut u16; + // Even copying 0 elements to something unaligned should error + unsafe { ptr.copy_from(&data[5], 0); } +} From c096d3405389089bab4379161a1546094b1db479 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 Sep 2018 08:40:17 +0200 Subject: [PATCH 0223/5092] bump toolchain --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 125ee2d98854..60c47a930576 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-09-15 +nightly-2018-09-17 From 130d803b3243a92f5c2d9230935cba7fa88e263e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 Sep 2018 09:18:57 +0200 Subject: [PATCH 0224/5092] fix test for rustup --- tests/compile-fail/out_of_bounds_read2.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile-fail/out_of_bounds_read2.rs b/tests/compile-fail/out_of_bounds_read2.rs index 811ba7d4b26c..e8bcf4558401 100644 --- a/tests/compile-fail/out_of_bounds_read2.rs +++ b/tests/compile-fail/out_of_bounds_read2.rs @@ -1,6 +1,6 @@ fn main() { let v: Vec = vec![1, 2]; let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR constant evaluation error - //~^ NOTE memory access at offset 6, outside bounds of allocation + //~^ NOTE outside bounds of allocation panic!("this should never print: {}", x); } From cd138bcd0b30b7af40fe0c13ce4f71f49cb59d3c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 15 Sep 2018 16:35:37 +0200 Subject: [PATCH 0225/5092] test more operations on dangling ZST pointers --- .../maybe_null_pointer_deref_zst.rs | 5 +++++ .../maybe_null_pointer_write_zst.rs | 8 ++++++++ tests/compile-fail/null_pointer_deref_zst.rs | 4 ++++ tests/compile-fail/null_pointer_write.rs | 3 +++ tests/compile-fail/null_pointer_write_zst.rs | 6 ++++++ tests/run-pass/cast-rfc0401-vtable-kinds.rs | 4 ---- tests/run-pass/const-vec-of-fns.rs | 2 -- tests/run-pass/issue-20575.rs | 2 -- tests/run-pass/pointers.rs | 6 +++++- .../regions-lifetime-nonfree-late-bound.rs | 2 -- tests/run-pass/sendable-class.rs | 2 -- tests/run-pass/zst.rs | 19 +++++++++++++++++-- tests/run-pass/zst2.rs | 12 ------------ 13 files changed, 48 insertions(+), 27 deletions(-) create mode 100644 tests/compile-fail/maybe_null_pointer_deref_zst.rs create mode 100644 tests/compile-fail/maybe_null_pointer_write_zst.rs create mode 100644 tests/compile-fail/null_pointer_deref_zst.rs create mode 100644 tests/compile-fail/null_pointer_write.rs create mode 100644 tests/compile-fail/null_pointer_write_zst.rs delete mode 100644 tests/run-pass/zst2.rs diff --git a/tests/compile-fail/maybe_null_pointer_deref_zst.rs b/tests/compile-fail/maybe_null_pointer_deref_zst.rs new file mode 100644 index 000000000000..d9f5ad4c696e --- /dev/null +++ b/tests/compile-fail/maybe_null_pointer_deref_zst.rs @@ -0,0 +1,5 @@ +fn main() { + // This pointer *could* be NULL so we cannot load from it, not even at ZST + let ptr = (&0u8 as *const u8).wrapping_sub(0x800) as *const (); + let _x: () = unsafe { *ptr }; //~ ERROR outside bounds +} diff --git a/tests/compile-fail/maybe_null_pointer_write_zst.rs b/tests/compile-fail/maybe_null_pointer_write_zst.rs new file mode 100644 index 000000000000..ef46a469c3ad --- /dev/null +++ b/tests/compile-fail/maybe_null_pointer_write_zst.rs @@ -0,0 +1,8 @@ +fn main() { + // This pointer *could* be NULL so we cannot load from it, not even at ZST. + // Not using the () type here, as writes of that type do not even have MIR generated. + // Also not assigning directly as that's array initialization, not assignment. + let zst_val = [1u8; 0]; + let ptr = (&0u8 as *const u8).wrapping_sub(0x800) as *mut [u8; 0]; + unsafe { *ptr = zst_val; } //~ ERROR outside bounds +} diff --git a/tests/compile-fail/null_pointer_deref_zst.rs b/tests/compile-fail/null_pointer_deref_zst.rs new file mode 100644 index 000000000000..a8b23368616e --- /dev/null +++ b/tests/compile-fail/null_pointer_deref_zst.rs @@ -0,0 +1,4 @@ +fn main() { + let x: () = unsafe { *std::ptr::null() }; //~ ERROR constant evaluation error: invalid use of NULL pointer + panic!("this should never print: {:?}", x); +} diff --git a/tests/compile-fail/null_pointer_write.rs b/tests/compile-fail/null_pointer_write.rs new file mode 100644 index 000000000000..affb040bdedf --- /dev/null +++ b/tests/compile-fail/null_pointer_write.rs @@ -0,0 +1,3 @@ +fn main() { + unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR constant evaluation error: invalid use of NULL pointer +} diff --git a/tests/compile-fail/null_pointer_write_zst.rs b/tests/compile-fail/null_pointer_write_zst.rs new file mode 100644 index 000000000000..433c69dbb032 --- /dev/null +++ b/tests/compile-fail/null_pointer_write_zst.rs @@ -0,0 +1,6 @@ +fn main() { + // Not using the () type here, as writes of that type do not even have MIR generated. + // Also not assigning directly as that's array initialization, not assignment. + let zst_val = [1u8; 0]; + unsafe { *std::ptr::null_mut() = zst_val }; //~ ERROR constant evaluation error: invalid use of NULL pointer +} diff --git a/tests/run-pass/cast-rfc0401-vtable-kinds.rs b/tests/run-pass/cast-rfc0401-vtable-kinds.rs index afbd4760a3c9..ebae26996b7b 100644 --- a/tests/run-pass/cast-rfc0401-vtable-kinds.rs +++ b/tests/run-pass/cast-rfc0401-vtable-kinds.rs @@ -8,10 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -// FIXME: remove the next line when https://github.com/rust-lang/rust/issues/43358 is resolved -// compile-flags: -Zmir-opt-level=0 - // Check that you can cast between different pointers to trait objects // whose vtable have the same kind (both lengths, or both trait pointers). diff --git a/tests/run-pass/const-vec-of-fns.rs b/tests/run-pass/const-vec-of-fns.rs index 0338a766e262..e100ad5f4692 100644 --- a/tests/run-pass/const-vec-of-fns.rs +++ b/tests/run-pass/const-vec-of-fns.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - /*! * Try to double-check that static fns have the right size (with or * without dummy env ptr, as appropriate) by iterating a size-2 array. diff --git a/tests/run-pass/issue-20575.rs b/tests/run-pass/issue-20575.rs index 7db7e3b28e8e..137d84c256be 100644 --- a/tests/run-pass/issue-20575.rs +++ b/tests/run-pass/issue-20575.rs @@ -10,8 +10,6 @@ // Test that overloaded calls work with zero arity closures -// pretty-expanded FIXME #23616 - fn main() { let functions: [Box Option<()>>; 1] = [Box::new(|| None)]; diff --git a/tests/run-pass/pointers.rs b/tests/run-pass/pointers.rs index 936ec73bcb8c..d8f030de0723 100644 --- a/tests/run-pass/pointers.rs +++ b/tests/run-pass/pointers.rs @@ -55,7 +55,11 @@ fn main() { assert_eq!(basic_ref_mut_var(), 3); assert_eq!(tuple_ref_mut(), (10, 22)); assert_eq!(match_ref_mut(), 42); - // FIXME: improve this test... how? + + // Compare even dangling pointers with NULL, and with others in the same allocation. assert!(dangling_pointer() != std::ptr::null()); assert!(match dangling_pointer() as usize { 0 => false, _ => true }); + let dangling = dangling_pointer(); + assert!(dangling == dangling); + assert!(dangling.wrapping_add(1) != dangling); } diff --git a/tests/run-pass/regions-lifetime-nonfree-late-bound.rs b/tests/run-pass/regions-lifetime-nonfree-late-bound.rs index 1aef95d8a3f3..96f1217a254e 100644 --- a/tests/run-pass/regions-lifetime-nonfree-late-bound.rs +++ b/tests/run-pass/regions-lifetime-nonfree-late-bound.rs @@ -22,8 +22,6 @@ // doing region-folding, when really all clients of the region-folding // case only want to see FREE lifetime variables, not bound ones. -// pretty-expanded FIXME #23616 - #![allow(unused_features)] #![feature(box_syntax)] diff --git a/tests/run-pass/sendable-class.rs b/tests/run-pass/sendable-class.rs index b3e07d00f010..66f0c84e23c1 100644 --- a/tests/run-pass/sendable-class.rs +++ b/tests/run-pass/sendable-class.rs @@ -10,8 +10,6 @@ // Test that a class with only sendable fields can be sent -// pretty-expanded FIXME #23616 - use std::sync::mpsc::channel; #[allow(dead_code)] diff --git a/tests/run-pass/zst.rs b/tests/run-pass/zst.rs index c1c88875c5c8..c3bae4062fc2 100644 --- a/tests/run-pass/zst.rs +++ b/tests/run-pass/zst.rs @@ -11,8 +11,23 @@ fn use_zst() -> A { } fn main() { + // Not using the () type here, as writes of that type do not even have MIR generated. + // Also not assigning directly as that's array initialization, not assignment. + let zst_val = [1u8; 0]; + assert_eq!(zst_ret(), A); assert_eq!(use_zst(), A); - let x = 42 as *mut (); - unsafe { *x = (); } + let x = 42 as *mut [u8; 0]; + // reading and writing is okay + unsafe { *x = zst_val; } + unsafe { let _y = *x; } + + // We should even be able to use "true" pointers for ZST when the allocation has been + // removed already. The box is for a non-ZST to make sure there actually is an allocation. + let mut x_box = Box::new(((), 1u8)); + let x = &mut x_box.0 as *mut _ as *mut [u8; 0]; + drop(x_box); + // reading and writing is okay + unsafe { *x = zst_val; } + unsafe { let _y = *x; } } diff --git a/tests/run-pass/zst2.rs b/tests/run-pass/zst2.rs deleted file mode 100644 index c2d7b88ea075..000000000000 --- a/tests/run-pass/zst2.rs +++ /dev/null @@ -1,12 +0,0 @@ -#![allow(dead_code)] - -#[derive(Debug)] -struct A; - -fn main() { - // can't use assert_eq, b/c that will try to print the pointer addresses with full MIR enabled - - // FIXME: Test disabled for now, see . - //assert!(&A as *const A as *const () == &() as *const _); - //assert!(&A as *const A == &A as *const A); -} From 18d7394071713092fd6d491fb7bcc3d98bb9a621 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 15 Sep 2018 17:12:48 +0200 Subject: [PATCH 0226/5092] more compile-fail ptr equality tests, to rule out any non-determinism; and fix ptr equality to fail all of them. At least these are the cases I can think of right now. --- src/memory.rs | 2 +- src/operator.rs | 50 +++++++++++++++---- tests/compile-fail/ptr_eq_dangling.rs | 10 ++++ tests/compile-fail/ptr_eq_integer.rs | 8 +++ tests/compile-fail/ptr_eq_out_of_bounds.rs | 9 ++++ .../compile-fail/ptr_eq_out_of_bounds_null.rs | 6 +++ tests/run-pass-fullmir/loop-break-value.rs | 4 +- tests/run-pass/pointers.rs | 27 ++++++++-- 8 files changed, 102 insertions(+), 14 deletions(-) create mode 100644 tests/compile-fail/ptr_eq_dangling.rs create mode 100644 tests/compile-fail/ptr_eq_integer.rs create mode 100644 tests/compile-fail/ptr_eq_out_of_bounds.rs create mode 100644 tests/compile-fail/ptr_eq_out_of_bounds_null.rs diff --git a/src/memory.rs b/src/memory.rs index 9f8118a223bc..4e0fcd4f511f 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -46,7 +46,7 @@ pub enum MemoryKind { C, /// Part of env var emulation Env, - // mutable statics + /// mutable statics MutStatic, } diff --git a/src/operator.rs b/src/operator.rs index 4f697dbd5b74..cf416c44c11f 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -152,18 +152,50 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: (Scalar::Ptr(ptr), Scalar::Bits { bits, size }) | (Scalar::Bits { bits, size }, Scalar::Ptr(ptr)) => { assert_eq!(size as u64, self.pointer_size().bytes()); + let bits = bits as u64; + let (alloc_size, alloc_align) = self.memory.get_size_and_align(ptr.alloc_id)?; + // Case I: Comparing with NULL if bits == 0 { - // Nothing equals 0, not even dangling pointers. Ideally we would - // require them to be in-bounds of their (possilby dead) allocation, - // but with the allocation gonew e cannot check that. - false - } else { - // Live pointers cannot equal an integer, but again do not - // allow comparing dead pointers. - self.memory.check_bounds(ptr, false)?; - false + // Test if the ptr is in-bounds. Then it cannot be NULL. + if ptr.offset <= alloc_size { + return Ok(false); + } } + // Case II: Alignment gives it away + if ptr.offset.bytes() % alloc_align.abi() == 0 { + // The offset maintains the allocation alignment, so we know `base+offset` + // is aligned by `alloc_align`. + // FIXME: We could be even more general, e.g. offset 2 into a 4-aligned + // allocation cannot equal 3. + if bits % alloc_align.abi() != 0 { + // The integer is *not* aligned. So they cannot be equal. + return Ok(false); + } + } + // Case III: The integer is too big, and the allocation goes on a bit + // without wrapping around the address space. + { + // Compute the highest address at which this allocation could live. + // Substract one more, because it must be possible to add the size + // to the base address without overflowing -- IOW, the very last address + // of the address space is never dereferencable (but it can be in-bounds, i.e., + // one-past-the-end). + let max_base_addr = + ((1u128 << self.pointer_size().bits()) + - u128::from(alloc_size.bytes()) + - 1 + ) as u64; + if let Some(max_addr) = max_base_addr.checked_add(ptr.offset.bytes()) { + if bits > max_addr { + // The integer is too big, this cannot possibly be equal + return Ok(false) + } + } + } + + // None of the supported cases. + return err!(InvalidPointerMath); } }) } diff --git a/tests/compile-fail/ptr_eq_dangling.rs b/tests/compile-fail/ptr_eq_dangling.rs new file mode 100644 index 000000000000..d05996a13d56 --- /dev/null +++ b/tests/compile-fail/ptr_eq_dangling.rs @@ -0,0 +1,10 @@ +fn main() { + let b = Box::new(0); + let x = &*b as *const i32; // soon-to-be dangling + drop(b); + let b = Box::new(0); + let y = &*b as *const i32; // different allocation + // We cannot compare these even though both are inbounds -- they *could* be + // equal if memory was reused. + assert!(x != y); //~ ERROR dangling pointer +} diff --git a/tests/compile-fail/ptr_eq_integer.rs b/tests/compile-fail/ptr_eq_integer.rs new file mode 100644 index 000000000000..10d5fbd517a3 --- /dev/null +++ b/tests/compile-fail/ptr_eq_integer.rs @@ -0,0 +1,8 @@ +use std::mem; + +fn main() { + let b = Box::new(0); + let x = &*b as *const i32; + // We cannot compare this with a non-NULL integer. After all, these *could* be equal (with the right base address). + assert!(x != mem::align_of::() as *const i32); //~ ERROR invalid arithmetic on pointers +} diff --git a/tests/compile-fail/ptr_eq_out_of_bounds.rs b/tests/compile-fail/ptr_eq_out_of_bounds.rs new file mode 100644 index 000000000000..af4eed8d4e32 --- /dev/null +++ b/tests/compile-fail/ptr_eq_out_of_bounds.rs @@ -0,0 +1,9 @@ +fn main() { + let b = Box::new(0); + let x = (&*b as *const i32).wrapping_sub(0x800); // out-of-bounds + let b = Box::new(0); + let y = &*b as *const i32; // different allocation + // We cannot compare these even though both allocations are live -- they *could* be + // equal (with the right base addresses). + assert!(x != y); //~ ERROR outside bounds +} diff --git a/tests/compile-fail/ptr_eq_out_of_bounds_null.rs b/tests/compile-fail/ptr_eq_out_of_bounds_null.rs new file mode 100644 index 000000000000..3b7b51fc1995 --- /dev/null +++ b/tests/compile-fail/ptr_eq_out_of_bounds_null.rs @@ -0,0 +1,6 @@ +fn main() { + let b = Box::new(0); + let x = (&*b as *const i32).wrapping_sub(0x800); // out-of-bounds + // We cannot compare this with NULL. After all, this *could* be NULL (with the right base address). + assert!(x != std::ptr::null()); //~ ERROR invalid arithmetic on pointers +} diff --git a/tests/run-pass-fullmir/loop-break-value.rs b/tests/run-pass-fullmir/loop-break-value.rs index 8631909a2a96..ab79a64b56e2 100644 --- a/tests/run-pass-fullmir/loop-break-value.rs +++ b/tests/run-pass-fullmir/loop-break-value.rs @@ -61,7 +61,9 @@ pub fn main() { break Default::default() }; }; - assert_eq!(trait_unified_2, [""]); + // compare lengths; ptr comparison is not deterministic + assert_eq!(trait_unified_2.len(), 1); + assert_eq!(trait_unified_2[0].len(), 0); let trait_unified_3 = loop { break if false { diff --git a/tests/run-pass/pointers.rs b/tests/run-pass/pointers.rs index d8f030de0723..2b26791328df 100644 --- a/tests/run-pass/pointers.rs +++ b/tests/run-pass/pointers.rs @@ -1,3 +1,5 @@ +use std::usize; + fn one_line_ref() -> i16 { *&1 } @@ -44,8 +46,8 @@ fn match_ref_mut() -> i8 { } fn dangling_pointer() -> *const i32 { - let b = Box::new(42); - &*b as *const i32 + let b = Box::new((42, 42)); // make it bigger than the alignment, so that there is some "room" after this pointer + &b.0 as *const i32 } fn main() { @@ -56,10 +58,29 @@ fn main() { assert_eq!(tuple_ref_mut(), (10, 22)); assert_eq!(match_ref_mut(), 42); - // Compare even dangling pointers with NULL, and with others in the same allocation. + // Compare even dangling pointers with NULL, and with others in the same allocation, including + // out-of-bounds. assert!(dangling_pointer() != std::ptr::null()); assert!(match dangling_pointer() as usize { 0 => false, _ => true }); let dangling = dangling_pointer(); assert!(dangling == dangling); assert!(dangling.wrapping_add(1) != dangling); + assert!(dangling.wrapping_sub(1) != dangling); + + // Compare pointer with BIG integers + let dangling = dangling as usize; + assert!(dangling != usize::MAX); + assert!(dangling != usize::MAX - 1); + assert!(dangling != usize::MAX - 2); + assert!(dangling != usize::MAX - 3); // this is even 4-aligned, but it still cannot be equal because of the extra "room" after this pointer + assert_eq!((usize::MAX - 3) % 4, 0); // just to be sure we got this right + + // Compare pointer with unaligned integers + assert!(dangling != 1usize); + assert!(dangling != 2usize); + assert!(dangling != 3usize); + // 4 is a possible choice! So we cannot compare with that. + assert!(dangling != 5usize); + assert!(dangling != 6usize); + assert!(dangling != 7usize); } From 83ae0530a71ad21b13cb9a1acd3ce14e8d6688d4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Sep 2018 08:32:23 +0200 Subject: [PATCH 0227/5092] update toolchain --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 60c47a930576..48282503c507 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-09-17 +nightly-2018-09-18 From ea4232cf22613aa06fb3d273dadf58f003df9388 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 20 Sep 2018 01:00:59 +0200 Subject: [PATCH 0228/5092] Move TLS data to machine data There is no good reason to let the machine store stuff in the machine *and* in memory. I plan to get rid of the latter. --- src/fn_call.rs | 36 +++++++++++------------ src/lib.rs | 39 ++++++++++++++++++------- src/memory.rs | 57 ------------------------------------ src/tls.rs | 78 ++++++++++++++++++++++++++++++++------------------ 4 files changed, 94 insertions(+), 116 deletions(-) delete mode 100644 src/memory.rs diff --git a/src/fn_call.rs b/src/fn_call.rs index 0e768fcccf9e..3e795f165331 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -8,10 +8,6 @@ use std::mem; use super::*; -use tls::MemoryExt; - -use super::memory::MemoryKind; - pub trait EvalContextExt<'tcx, 'mir> { /// Emulate calling a foreign item, fail if the item is not supported. /// This function will handle `goto_block` if needed. @@ -129,7 +125,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' self.write_null(dest)?; } else { let align = self.tcx.data_layout.pointer_align; - let ptr = self.memory.allocate(Size::from_bytes(size), align, MemoryKind::C.into())?; + let ptr = self.memory.allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into())?; self.write_scalar(Scalar::Ptr(ptr), dest)?; } } @@ -140,7 +136,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' self.memory.deallocate( ptr.to_ptr()?, None, - MemoryKind::C.into(), + MiriMemoryKind::C.into(), )?; } } @@ -156,7 +152,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' } let ptr = self.memory.allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), - MemoryKind::Rust.into())?; + MiriMemoryKind::Rust.into())?; self.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_alloc_zeroed" => { @@ -170,7 +166,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' } let ptr = self.memory.allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), - MemoryKind::Rust.into())?; + MiriMemoryKind::Rust.into())?; self.memory.write_repeat(ptr.into(), 0, Size::from_bytes(size))?; self.write_scalar(Scalar::Ptr(ptr), dest)?; } @@ -187,7 +183,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' self.memory.deallocate( ptr, Some((Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap())), - MemoryKind::Rust.into(), + MiriMemoryKind::Rust.into(), )?; } "__rust_realloc" => { @@ -207,7 +203,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' Align::from_bytes(align, align).unwrap(), Size::from_bytes(new_size), Align::from_bytes(align, align).unwrap(), - MemoryKind::Rust.into(), + MiriMemoryKind::Rust.into(), )?; self.write_scalar(Scalar::Ptr(new_ptr), dest)?; } @@ -365,7 +361,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' } if let Some(old) = success { if let Some(var) = old { - self.memory.deallocate(var, None, MemoryKind::Env.into())?; + self.memory.deallocate(var, None, MiriMemoryKind::Env.into())?; } self.write_null(dest)?; } else { @@ -391,7 +387,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' let value_copy = self.memory.allocate( Size::from_bytes((value.len() + 1) as u64), Align::from_bytes(1, 1).unwrap(), - MemoryKind::Env.into(), + MiriMemoryKind::Env.into(), )?; self.memory.write_bytes(value_copy.into(), &value)?; let trailing_zero_ptr = value_copy.offset(Size::from_bytes(value.len() as u64), &self)?.into(); @@ -401,7 +397,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' value_copy, ) { - self.memory.deallocate(var, None, MemoryKind::Env.into())?; + self.memory.deallocate(var, None, MiriMemoryKind::Env.into())?; } self.write_null(dest)?; } else { @@ -504,7 +500,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' let key_layout = self.layout_of(key_type)?; // Create key and write it into the memory where key_ptr wants it - let key = self.memory.create_tls_key(dtor) as u128; + let key = self.machine.tls.create_tls_key(dtor, *self.tcx) as u128; if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) { return err!(OutOfTls); } @@ -520,19 +516,19 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' } "pthread_key_delete" => { let key = self.read_scalar(args[0])?.to_bytes()?; - self.memory.delete_tls_key(key)?; + self.machine.tls.delete_tls_key(key)?; // Return success (0) self.write_null(dest)?; } "pthread_getspecific" => { let key = self.read_scalar(args[0])?.to_bytes()?; - let ptr = self.memory.load_tls(key)?; + let ptr = self.machine.tls.load_tls(key)?; self.write_scalar(ptr, dest)?; } "pthread_setspecific" => { let key = self.read_scalar(args[0])?.to_bytes()?; let new_ptr = self.read_scalar(args[1])?.not_undef()?; - self.memory.store_tls(key, new_ptr)?; + self.machine.tls.store_tls(key, new_ptr)?; // Return success (0) self.write_null(dest)?; @@ -607,7 +603,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' // This just creates a key; Windows does not natively support TLS dtors. // Create key and return it - let key = self.memory.create_tls_key(None) as u128; + let key = self.machine.tls.create_tls_key(None, *self.tcx) as u128; // Figure out how large a TLS key actually is. This is c::DWORD. if dest.layout.size.bits() < 128 && key >= (1u128 << dest.layout.size.bits() as u128) { @@ -617,13 +613,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' } "TlsGetValue" => { let key = self.read_scalar(args[0])?.to_bytes()?; - let ptr = self.memory.load_tls(key)?; + let ptr = self.machine.tls.load_tls(key)?; self.write_scalar(ptr, dest)?; } "TlsSetValue" => { let key = self.read_scalar(args[0])?.to_bytes()?; let new_ptr = self.read_scalar(args[1])?.not_undef()?; - self.memory.store_tls(key, new_ptr)?; + self.machine.tls.store_tls(key, new_ptr)?; // Return success (1) self.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; diff --git a/src/lib.rs b/src/lib.rs index 8bf66999c3de..98d89510251c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,17 +21,16 @@ use rustc::mir; use syntax::ast::Mutability; use syntax::attr; -use std::marker::PhantomData; use std::collections::HashMap; pub use rustc::mir::interpret::*; pub use rustc_mir::interpret::*; +pub use rustc_mir::interpret; mod fn_call; mod operator; mod intrinsic; mod helpers; -mod memory; mod tls; mod locks; mod range_map; @@ -39,9 +38,7 @@ mod range_map; use fn_call::EvalContextExt as MissingFnsEvalContextExt; use operator::EvalContextExt as OperatorEvalContextExt; use intrinsic::EvalContextExt as IntrinsicEvalContextExt; -use tls::EvalContextExt as TlsEvalContextExt; -use memory::{MemoryKind as MiriMemoryKind, TlsKey, TlsEntry, MemoryData}; -use locks::LockInfo; +use tls::{EvalContextExt as TlsEvalContextExt, TlsData}; use range_map::RangeMap; use helpers::FalibleScalarExt; @@ -54,7 +51,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), Default::default(), - MemoryData::new() + Default::default(), ); let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); @@ -201,21 +198,41 @@ pub fn eval_main<'a, 'tcx: 'a>( } } + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum MiriMemoryKind { + /// `__rust_alloc` memory + Rust, + /// `malloc` memory + C, + /// Part of env var emulation + Env, + /// mutable statics + MutStatic, +} + +impl Into> for MiriMemoryKind { + fn into(self) -> MemoryKind { + MemoryKind::Machine(self) + } +} + + #[derive(Clone, Default, PartialEq, Eq)] pub struct Evaluator<'tcx> { /// Environment variables set by `setenv` /// Miri does not expose env vars from the host to the emulated program pub(crate) env_vars: HashMap, Pointer>, - /// Use the lifetime - _dummy : PhantomData<&'tcx ()>, + /// TLS state + pub(crate) tls: TlsData<'tcx>, } impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { - type MemoryData = memory::MemoryData<'tcx>; - type MemoryKinds = memory::MemoryKind; + type MemoryData = (); + type MemoryKinds = MiriMemoryKind; - const MUT_STATIC_KIND: Option = Some(memory::MemoryKind::MutStatic); + const MUT_STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); const DETECT_LOOPS: bool = false; /// Returns Ok() when the function was handled, fail otherwise diff --git a/src/memory.rs b/src/memory.rs deleted file mode 100644 index 4e0fcd4f511f..000000000000 --- a/src/memory.rs +++ /dev/null @@ -1,57 +0,0 @@ -use std::collections::{HashMap, BTreeMap}; - -use rustc::ty; - -use super::{AllocId, Scalar, LockInfo, RangeMap}; - -pub type TlsKey = u128; - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct TlsEntry<'tcx> { - pub(crate) data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. - pub(crate) dtor: Option>, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct MemoryData<'tcx> { - /// The Key to use for the next thread-local allocation. - pub(crate) next_thread_local: TlsKey, - - /// pthreads-style thread-local storage. - pub(crate) thread_local: BTreeMap>, - - /// Memory regions that are locked by some function - /// - /// Only mutable (static mut, heap, stack) allocations have an entry in this map. - /// The entry is created when allocating the memory and deleted after deallocation. - pub(crate) locks: HashMap>>, -} - -impl<'tcx> MemoryData<'tcx> { - pub(crate) fn new() -> Self { - MemoryData { - next_thread_local: 1, // start with 1 as we must not use 0 on Windows - thread_local: BTreeMap::new(), - locks: HashMap::new(), - } - } -} - - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum MemoryKind { - /// `__rust_alloc` memory - Rust, - /// `malloc` memory - C, - /// Part of env var emulation - Env, - /// mutable statics - MutStatic, -} - -impl Into<::rustc_mir::interpret::MemoryKind> for MemoryKind { - fn into(self) -> ::rustc_mir::interpret::MemoryKind { - ::rustc_mir::interpret::MemoryKind::Machine(self) - } -} diff --git a/src/tls.rs b/src/tls.rs index bd0318a62ed4..a1ddaf64cc0f 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -1,31 +1,52 @@ -use rustc::{ty, mir}; +use std::collections::BTreeMap; -use super::{TlsKey, TlsEntry, EvalResult, EvalErrorKind, Scalar, Memory, Evaluator, +use rustc::{ty, ty::layout::HasDataLayout, mir}; + +use super::{EvalResult, EvalErrorKind, Scalar, Evaluator, Place, StackPopCleanup, EvalContext}; -pub trait MemoryExt<'tcx> { - fn create_tls_key(&mut self, dtor: Option>) -> TlsKey; - fn delete_tls_key(&mut self, key: TlsKey) -> EvalResult<'tcx>; - fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar>; - fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx>; - fn fetch_tls_dtor( - &mut self, - key: Option, - ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)>; +pub type TlsKey = u128; + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct TlsEntry<'tcx> { + pub(crate) data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. + pub(crate) dtor: Option>, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TlsData<'tcx> { + /// The Key to use for the next thread-local allocation. + pub(crate) next_key: TlsKey, + + /// pthreads-style thread-local storage. + pub(crate) keys: BTreeMap>, +} + +impl<'tcx> Default for TlsData<'tcx> { + fn default() -> Self { + TlsData { + next_key: 1, // start with 1 as we must not use 0 on Windows + keys: Default::default(), + } + } } pub trait EvalContextExt<'tcx> { fn run_tls_dtors(&mut self) -> EvalResult<'tcx>; } -impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evaluator<'tcx>> { - fn create_tls_key(&mut self, dtor: Option>) -> TlsKey { - let new_key = self.data.next_thread_local; - self.data.next_thread_local += 1; - self.data.thread_local.insert( +impl<'tcx> TlsData<'tcx> { + pub fn create_tls_key( + &mut self, + dtor: Option>, + cx: impl HasDataLayout, + ) -> TlsKey { + let new_key = self.next_key; + self.next_key += 1; + self.keys.insert( new_key, TlsEntry { - data: Scalar::ptr_null(*self.tcx).into(), + data: Scalar::ptr_null(cx).into(), dtor, }, ); @@ -33,8 +54,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu new_key } - fn delete_tls_key(&mut self, key: TlsKey) -> EvalResult<'tcx> { - match self.data.thread_local.remove(&key) { + pub fn delete_tls_key(&mut self, key: TlsKey) -> EvalResult<'tcx> { + match self.keys.remove(&key) { Some(_) => { trace!("TLS key {} removed", key); Ok(()) @@ -43,8 +64,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu } } - fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar> { - match self.data.thread_local.get(&key) { + pub fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar> { + match self.keys.get(&key) { Some(&TlsEntry { data, .. }) => { trace!("TLS key {} loaded: {:?}", key, data); Ok(data) @@ -53,8 +74,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu } } - fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx> { - match self.data.thread_local.get_mut(&key) { + pub fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx> { + match self.keys.get_mut(&key) { Some(&mut TlsEntry { ref mut data, .. }) => { trace!("TLS key {} stored: {:?}", key, new_data); *data = new_data; @@ -85,10 +106,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu fn fetch_tls_dtor( &mut self, key: Option, + cx: impl HasDataLayout, ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { use std::collections::Bound::*; - let thread_local = &mut self.data.thread_local; + let thread_local = &mut self.keys; let start = match key { Some(key) => Excluded(key), None => Unbounded, @@ -99,7 +121,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu if !data.is_null() { if let Some(dtor) = dtor { let ret = Some((dtor, *data, key)); - *data = Scalar::ptr_null(*self.tcx); + *data = Scalar::ptr_null(cx); return ret; } } @@ -110,7 +132,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>> { fn run_tls_dtors(&mut self) -> EvalResult<'tcx> { - let mut dtor = self.memory.fetch_tls_dtor(None); + let mut dtor = self.machine.tls.fetch_tls_dtor(None, *self.tcx); // FIXME: replace loop by some structure that works with stepping while let Some((instance, ptr, key)) = dtor { trace!("Running TLS dtor {:?} on {:?}", instance, ptr); @@ -134,9 +156,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // step until out of stackframes self.run()?; - dtor = match self.memory.fetch_tls_dtor(Some(key)) { + dtor = match self.machine.tls.fetch_tls_dtor(Some(key), *self.tcx) { dtor @ Some(_) => dtor, - None => self.memory.fetch_tls_dtor(None), + None => self.machine.tls.fetch_tls_dtor(None, *self.tcx), }; } // FIXME: On a windows target, call `unsafe extern "system" fn on_tls_callback`. From 8d7cdbb8536d853be6199666a72fcae5ca44d3a9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 20 Sep 2018 12:24:55 +0200 Subject: [PATCH 0229/5092] rustup --- src/lib.rs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 98d89510251c..e25ae3a27d1e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -228,15 +228,14 @@ pub struct Evaluator<'tcx> { pub(crate) tls: TlsData<'tcx>, } -impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { +impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { type MemoryData = (); type MemoryKinds = MiriMemoryKind; const MUT_STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); - const DETECT_LOOPS: bool = false; /// Returns Ok() when the function was handled, fail otherwise - fn find_fn<'a>( + fn find_fn( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx>], @@ -246,7 +245,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx.find_fn(instance, args, dest, ret) } - fn call_intrinsic<'a>( + fn call_intrinsic( ecx: &mut rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx>], @@ -255,7 +254,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx.call_intrinsic(instance, args, dest) } - fn ptr_op<'a>( + fn ptr_op( ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, bin_op: mir::BinOp, left: Scalar, @@ -266,7 +265,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx.ptr_op(bin_op, left, left_layout, right, right_layout) } - fn box_alloc<'a>( + fn box_alloc( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, dest: PlaceTy<'tcx>, ) -> EvalResult<'tcx> { @@ -305,7 +304,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { Ok(()) } - fn find_foreign_static<'a>( + fn find_foreign_static( tcx: TyCtxtAt<'a, 'tcx, 'tcx>, def_id: DefId, ) -> EvalResult<'tcx, &'tcx Allocation> { @@ -329,7 +328,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { Ok(alloc) } - fn validation_op<'a>( + fn validation_op( _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, _op: ::rustc::mir::ValidationOp, _operand: &::rustc::mir::ValidationOperand<'tcx, ::rustc::mir::Place<'tcx>>, @@ -338,4 +337,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { //ecx.validation_op(op, operand) Ok(()) } + + fn before_terminator(_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> + { + // We are not interested in detecting loops + Ok(()) + } } From a85b78d30c6e5b6c8b20c10a785679c11565cabd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 Sep 2018 18:05:36 +0200 Subject: [PATCH 0230/5092] test for interestingly aligned field access --- tests/run-pass/issue-53728.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tests/run-pass/issue-53728.rs diff --git a/tests/run-pass/issue-53728.rs b/tests/run-pass/issue-53728.rs new file mode 100644 index 000000000000..6d440b66b35a --- /dev/null +++ b/tests/run-pass/issue-53728.rs @@ -0,0 +1,16 @@ +#![allow(dead_code)] + +#[repr(u16)] +enum DeviceKind { + Nil = 0, +} +#[repr(packed)] +struct DeviceInfo { + endianness: u8, + device_kind: DeviceKind, +} +fn main() { + let _x = None::<(DeviceInfo, u8)>; + let _y = None::<(DeviceInfo, u16)>; + let _z = None::<(DeviceInfo, u64)>; +} From 6b404011cc06bcbaa9badc1db12bbdca0358ceee Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 22 Sep 2018 08:44:38 +0200 Subject: [PATCH 0231/5092] bump toolchain --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 48282503c507..c1bf4c3de804 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-09-18 +nightly-2018-09-22 From f18cb40e4ce0d0fa7ce60c17d2783edffde783f2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Sep 2018 09:14:55 +0200 Subject: [PATCH 0232/5092] test mutating a non-mut static with interior mutability --- tests/run-pass/static_memory_modification.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/run-pass/static_memory_modification.rs b/tests/run-pass/static_memory_modification.rs index a68f727322e2..6a4107817798 100644 --- a/tests/run-pass/static_memory_modification.rs +++ b/tests/run-pass/static_memory_modification.rs @@ -1,8 +1,14 @@ +use std::sync::atomic::{Ordering, AtomicUsize}; + static mut X: usize = 5; +static Y: AtomicUsize = AtomicUsize::new(5); fn main() { unsafe { X = 6; assert_eq!(X, 6); } + + Y.store(6, Ordering::Relaxed); + assert_eq!(Y.load(Ordering::Relaxed), 6); } From 4b11792259698b056615cffe06c84f6329eff9e0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Sep 2018 23:01:12 +0200 Subject: [PATCH 0233/5092] bump toolchain --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index c1bf4c3de804..8a63ffb87c6a 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-09-22 +nightly-2018-09-24 From e8f6973e2d40ab39e30cdbe0cf8e77a72c867d4f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 29 Sep 2018 19:39:34 +0200 Subject: [PATCH 0234/5092] fix test for latest rustc --- rust-toolchain | 2 +- tests/compile-fail/invalid_enum_discriminant.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-toolchain b/rust-toolchain index 8a63ffb87c6a..27d32f29541a 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-09-24 +nightly-2018-09-29 diff --git a/tests/compile-fail/invalid_enum_discriminant.rs b/tests/compile-fail/invalid_enum_discriminant.rs index a188623a1e0e..94c100b9ef51 100644 --- a/tests/compile-fail/invalid_enum_discriminant.rs +++ b/tests/compile-fail/invalid_enum_discriminant.rs @@ -8,8 +8,8 @@ pub enum Foo { fn main() { let f = unsafe { std::mem::transmute::(42) }; - match f { //~ ERROR invalid enum discriminant - Foo::A => {}, + match f { + Foo::A => {}, //~ ERROR invalid enum discriminant Foo::B => {}, Foo::C => {}, Foo::D => {}, From 1ce05523c41d97a26cc037a5fe8b2d6a8907fbd3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 1 Oct 2018 08:24:42 +0200 Subject: [PATCH 0235/5092] remove needs_drop impl --- rust-toolchain | 2 +- src/intrinsic.rs | 10 ---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/rust-toolchain b/rust-toolchain index 27d32f29541a..c062614a6f93 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-09-29 +nightly-2018-10-01 diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 5ee82bf56adb..53462488b6f7 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -272,16 +272,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: self.copy_op(args[1], ptr.into())?; } - "needs_drop" => { - let ty = substs.type_at(0); - let env = ty::ParamEnv::reveal_all(); - let needs_drop = ty.needs_drop(self.tcx.tcx, env); - self.write_scalar( - Scalar::from_bool(needs_drop), - dest, - )?; - } - "offset" => { let offset = self.read_scalar(args[1])?.to_isize(&self)?; let ptr = self.read_scalar(args[0])?.not_undef()?; From eaff451d5e8e489ec34b161022d4b82360362465 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 1 Oct 2018 08:27:03 +0200 Subject: [PATCH 0236/5092] move 'cargo miri' test down so it is not the first thing testing start-fn --- .travis.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7f346b5104c2..414b407e92fe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,7 +38,10 @@ script: xargo/build.sh && export MIRI_SYSROOT=~/.xargo/HOST - | - # Test `cargo miri` + # run all tests with full mir + cargo test --release --all-features +- | + # test `cargo miri` cd cargo-miri-test && if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then cargo miri -q -- -Zmiri-start-fn @@ -50,12 +53,9 @@ script: diff -u stdout.ref stdout.real && diff -u stderr.ref stderr.real fi && - # Test `cargo miri test` + # test `cargo miri test` cargo miri test && cd .. -- | - # and run all tests with full mir - cargo test --release --all-features notifications: email: From aa30540ce7d940fcc8e6779832e1c51311078a58 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 1 Oct 2018 12:32:22 +0200 Subject: [PATCH 0237/5092] update CI: Avoid downloading Rust twice --- .travis.yml | 34 ++++++++++++++++++++++------------ appveyor.yml | 17 ++++++++++------- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/.travis.yml b/.travis.yml index 414b407e92fe..137e61259881 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,10 @@ -language: rust -cache: cargo -rust: -- nightly +language: generic +cache: + # Cache the global cargo directory, but NOT the local `target` directory which + # we cannot reuse anyway when the nightly changes (and it grows quite large + # over time). + directories: + - /home/travis/.cargo os: - linux @@ -9,17 +12,25 @@ os: before_script: # mac os weirdness (https://github.com/travis-ci/travis-ci/issues/6307) -- curl -sSL https://rvm.io/mpapis.asc | gpg --import - - rvm get stable -# in a cronjob, use latest (not pinned) nightly -- if [ "$TRAVIS_EVENT_TYPE" = cron ]; then rustup override set nightly; fi -# prepare -- export PATH=$HOME/.local/bin:$PATH +# Compute the rust version we use. We do not use "language: rust" to have more control here. +- | + if [ "$TRAVIS_EVENT_TYPE" = cron ]; then + RUST_TOOLCHAIN=nightly + else + RUST_TOOLCHAIN=$(cat rust-toolchain) + fi +- rm rust-toolchain +# install Rust +- curl https://build.travis-ci.org/files/rustup-init.sh -sSf | sh -s -- -y --default-toolchain "$RUST_TOOLCHAIN" +- export PATH=$HOME/.cargo/bin:$PATH +- rustc --version +# customize installation - rustup target add i686-unknown-linux-gnu - rustup target add i686-pc-windows-gnu - rustup target add i686-pc-windows-msvc - rustup component add rust-src -- cargo install xargo || echo "skipping xargo install" +- cargo install xargo || echo "Skipping xargo install" script: - set -e @@ -27,7 +38,7 @@ script: # Test and install plain miri cargo build --release --all-features && cargo test --release --all-features && - cargo install --all-features --force + cargo install --all-features --force --path . - | # test that the rustc_tests binary compiles cd rustc_tests && @@ -66,4 +77,3 @@ branches: env: global: - RUST_TEST_NOCAPTURE=1 - - TRAVIS_CARGO_NIGHTLY_FEATURE="" diff --git a/appveyor.yml b/appveyor.yml index 14532416978c..4614891a3129 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -14,18 +14,21 @@ branches: - master install: - - set PATH=C:\Program Files\Git\mingw64\bin;%PATH% + # install Rust + - set PATH=C:\Program Files\Git\mingw64\bin;C:\msys64\mingw%MSYS2_BITS%\bin;%PATH% + - set /p RUST_TOOLCHAIN= Date: Tue, 2 Oct 2018 09:25:55 +0200 Subject: [PATCH 0238/5092] rustup --- src/intrinsic.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 53462488b6f7..e9a5714587fb 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -2,12 +2,13 @@ use rustc::mir; use rustc::ty::layout::{self, LayoutOf, Size}; use rustc::ty; -use rustc::mir::interpret::{EvalResult, Scalar, ScalarMaybeUndef, PointerArithmetic}; -use rustc_mir::interpret::{ - PlaceTy, EvalContext, OpTy, Value -}; +use rustc::mir::interpret::{EvalResult, PointerArithmetic}; +use rustc_mir::interpret::{EvalContext, PlaceTy, OpTy}; -use super::{FalibleScalarExt, OperatorEvalContextExt}; +use super::{ + Value, Scalar, ScalarMaybeUndef, + FalibleScalarExt, OperatorEvalContextExt +}; pub trait EvalContextExt<'tcx> { fn call_intrinsic( From 146f5d8d1063ba3ea92eba33b64fcc2b59310643 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Oct 2018 21:16:55 +0200 Subject: [PATCH 0239/5092] rustup; test for return type mismatch --- src/lib.rs | 1 + src/operator.rs | 8 ++++---- tests/compile-fail/cast_fn_ptr5.rs | 9 +++++++++ 3 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 tests/compile-fail/cast_fn_ptr5.rs diff --git a/src/lib.rs b/src/lib.rs index e25ae3a27d1e..e4a389427c52 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -233,6 +233,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { type MemoryKinds = MiriMemoryKind; const MUT_STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); + const ENFORCE_VALIDITY: bool = false; // this is still WIP /// Returns Ok() when the function was handled, fail otherwise fn find_fn( diff --git a/src/operator.rs b/src/operator.rs index cf416c44c11f..13532764c973 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -142,8 +142,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // allocations sit right next to each other. The C/C++ standards are // somewhat fuzzy about this case, so I think for now this check is // "good enough". - self.memory.check_bounds(left, false)?; - self.memory.check_bounds(right, false)?; + self.memory.check_bounds_ptr(left, false)?; + self.memory.check_bounds_ptr(right, false)?; // Two live in-bounds pointers, we can compare across allocations left == right } @@ -296,9 +296,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: if let Scalar::Ptr(ptr) = ptr { // Both old and new pointer must be in-bounds. // (Of the same allocation, but that part is trivial with our representation.) - self.memory.check_bounds(ptr, false)?; + self.memory.check_bounds_ptr(ptr, false)?; let ptr = ptr.signed_offset(offset, self)?; - self.memory.check_bounds(ptr, false)?; + self.memory.check_bounds_ptr(ptr, false)?; Ok(Scalar::Ptr(ptr)) } else { // An integer pointer. They can move around freely, as long as they do not overflow diff --git a/tests/compile-fail/cast_fn_ptr5.rs b/tests/compile-fail/cast_fn_ptr5.rs new file mode 100644 index 000000000000..e4ac95e67676 --- /dev/null +++ b/tests/compile-fail/cast_fn_ptr5.rs @@ -0,0 +1,9 @@ +fn main() { + fn f() -> u32 { 42 } + + let g = unsafe { + std::mem::transmute:: u32, fn()>(f) + }; + + g() //~ ERROR tried to call a function with return type u32 passing return place of type () +} From 959693f1e5fd8b504f0690a34b8da4673d44f8b2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Oct 2018 18:32:39 +0200 Subject: [PATCH 0240/5092] ensure that we cannot use (wrapping_)offset to go from an int ptr to a real ptr --- tests/compile-fail/ptr_offset_int_plus_ptr.rs | 9 +++++++++ tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs | 8 ++++++++ 2 files changed, 17 insertions(+) create mode 100644 tests/compile-fail/ptr_offset_int_plus_ptr.rs create mode 100644 tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs diff --git a/tests/compile-fail/ptr_offset_int_plus_ptr.rs b/tests/compile-fail/ptr_offset_int_plus_ptr.rs new file mode 100644 index 000000000000..a3895a71b1bd --- /dev/null +++ b/tests/compile-fail/ptr_offset_int_plus_ptr.rs @@ -0,0 +1,9 @@ +// error-pattern: pointer value as raw bytes + +fn main() { + let ptr = &mut *Box::new(0u32) as *mut u32; + // Can't start with an integer pointer and get to something usable + unsafe { + let _ = (1 as *mut u8).offset(ptr as isize); + } +} diff --git a/tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs b/tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs new file mode 100644 index 000000000000..0f53c1d89516 --- /dev/null +++ b/tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs @@ -0,0 +1,8 @@ +// error-pattern: pointer value as raw bytes + +fn main() { + let ptr = &mut *Box::new(0u32) as *mut u32; + // Can't start with an integer pointer and get to something usable + let ptr = (1 as *mut u8).wrapping_offset(ptr as isize); + let _ = unsafe { *ptr }; +} From 59eb3dbdae487f67d81c2e5d46dcbd636c9d0cf9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 7 Oct 2018 10:35:34 +0200 Subject: [PATCH 0241/5092] use Box::into_raw --- tests/compile-fail/ptr_offset_int_plus_ptr.rs | 2 +- tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/compile-fail/ptr_offset_int_plus_ptr.rs b/tests/compile-fail/ptr_offset_int_plus_ptr.rs index a3895a71b1bd..b45548935807 100644 --- a/tests/compile-fail/ptr_offset_int_plus_ptr.rs +++ b/tests/compile-fail/ptr_offset_int_plus_ptr.rs @@ -1,7 +1,7 @@ // error-pattern: pointer value as raw bytes fn main() { - let ptr = &mut *Box::new(0u32) as *mut u32; + let ptr = Box::into_raw(Box::new(0u32)); // Can't start with an integer pointer and get to something usable unsafe { let _ = (1 as *mut u8).offset(ptr as isize); diff --git a/tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs b/tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs index 0f53c1d89516..b3dda27fad1e 100644 --- a/tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs +++ b/tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs @@ -1,7 +1,7 @@ // error-pattern: pointer value as raw bytes fn main() { - let ptr = &mut *Box::new(0u32) as *mut u32; + let ptr = Box::into_raw(Box::new(0u32)); // Can't start with an integer pointer and get to something usable let ptr = (1 as *mut u8).wrapping_offset(ptr as isize); let _ = unsafe { *ptr }; From cc275c63a90d4bea394e76607b2e10611eb1be36 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 8 Oct 2018 13:35:54 +0200 Subject: [PATCH 0242/5092] fix for fn allocations now having an alignment (1) and a size (0) --- src/operator.rs | 2 +- tests/compile-fail/deref_fn_ptr.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index 13532764c973..6e903a8f46b3 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -153,7 +153,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: (Scalar::Bits { bits, size }, Scalar::Ptr(ptr)) => { assert_eq!(size as u64, self.pointer_size().bytes()); let bits = bits as u64; - let (alloc_size, alloc_align) = self.memory.get_size_and_align(ptr.alloc_id)?; + let (alloc_size, alloc_align) = self.memory.get_size_and_align(ptr.alloc_id); // Case I: Comparing with NULL if bits == 0 { diff --git a/tests/compile-fail/deref_fn_ptr.rs b/tests/compile-fail/deref_fn_ptr.rs index 1b36c77bd32a..68826a6ff03d 100644 --- a/tests/compile-fail/deref_fn_ptr.rs +++ b/tests/compile-fail/deref_fn_ptr.rs @@ -1,8 +1,8 @@ fn f() {} fn main() { - let x: i32 = unsafe { - *std::mem::transmute::(f) //~ ERROR constant evaluation error: tried to dereference a function pointer + let x: u8 = unsafe { + *std::mem::transmute::(f) //~ ERROR constant evaluation error: tried to dereference a function pointer }; panic!("this should never print: {}", x); } From edf28fa227c68267153dc42119f3170f46b14389 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 8 Oct 2018 10:22:26 +0200 Subject: [PATCH 0243/5092] only allow offset-by-0 on integer pointers --- src/operator.rs | 18 +++++++----------- tests/compile-fail/ptr_offset_int_plus_int.rs | 8 ++++++++ 2 files changed, 15 insertions(+), 11 deletions(-) create mode 100644 tests/compile-fail/ptr_offset_int_plus_int.rs diff --git a/src/operator.rs b/src/operator.rs index cf416c44c11f..6fed43914e16 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -281,14 +281,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: pointee_ty: Ty<'tcx>, offset: i64, ) -> EvalResult<'tcx, Scalar> { - if ptr.is_null() { - // NULL pointers must only be offset by 0 - return if offset == 0 { - Ok(ptr) - } else { - err!(InvalidNullPointerUsage) - }; - } // FIXME: assuming here that type size is < i64::max_value() let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; let offset = offset.checked_mul(pointee_size).ok_or_else(|| EvalErrorKind::Overflow(mir::BinOp::Mul))?; @@ -301,9 +293,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: self.memory.check_bounds(ptr, false)?; Ok(Scalar::Ptr(ptr)) } else { - // An integer pointer. They can move around freely, as long as they do not overflow - // (which ptr_signed_offset checks). - ptr.ptr_signed_offset(offset, self) + // An integer pointer. They can only be offset by 0, and we pretend there + // is a little zero-sized allocation here. + if offset == 0 { + Ok(ptr) + } else { + err!(InvalidPointerMath) + } } } } diff --git a/tests/compile-fail/ptr_offset_int_plus_int.rs b/tests/compile-fail/ptr_offset_int_plus_int.rs new file mode 100644 index 000000000000..fa4efa323654 --- /dev/null +++ b/tests/compile-fail/ptr_offset_int_plus_int.rs @@ -0,0 +1,8 @@ +// error-pattern: invalid arithmetic on pointers + +fn main() { + // Can't offset an integer pointer by non-zero offset. + unsafe { + let _ = (1 as *mut u8).offset(1); + } +} From 0641d5b6d30a6f66bfd8ec1ff06bc7170569e6a1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 8 Oct 2018 11:22:52 +0200 Subject: [PATCH 0244/5092] 0-offset is also not always okay --- tests/compile-fail/ptr_offset_ptr_plus_0.rs | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/compile-fail/ptr_offset_ptr_plus_0.rs diff --git a/tests/compile-fail/ptr_offset_ptr_plus_0.rs b/tests/compile-fail/ptr_offset_ptr_plus_0.rs new file mode 100644 index 000000000000..46937b1c8ce4 --- /dev/null +++ b/tests/compile-fail/ptr_offset_ptr_plus_0.rs @@ -0,0 +1,7 @@ +// error-pattern: outside bounds of allocation + +fn main() { + let x = Box::into_raw(Box::new(0u32)); + let x = x.wrapping_offset(8); // okay, this has no inbounds tag + let _x = unsafe { x.offset(0) }; // UB despite offset 0, the pointer is not inbounds of the only object it can point to +} From 5f2c74e022d5e2202c53fa2b92d5f727be0f2b13 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 9 Oct 2018 20:17:54 +0200 Subject: [PATCH 0245/5092] update to vergen 3 --- Cargo.toml | 2 +- build.rs | 15 ++------------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d690f87b536c..f7caa4d1c2c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ env_logger = "0.5" log = "0.4" [build-dependencies] -vergen = "2" +vergen = "3" [features] cargo_miri = ["cargo_metadata"] diff --git a/build.rs b/build.rs index 73eb68359a82..97bb9358832c 100644 --- a/build.rs +++ b/build.rs @@ -8,17 +8,6 @@ fn main() { // Don't rebuild miri even if nothing changed println!("cargo:rerun-if-changed=build.rs"); // vergen - vergen().expect("Unable to generate vergen constants!"); -} - -fn vergen() -> vergen::Result<()> { - use vergen::{ConstantsFlags, Vergen}; - - let vergen = Vergen::new(ConstantsFlags::all())?; - - for (k, v) in vergen.build_info() { - println!("cargo:rustc-env={}={}", k.name(), v); - } - - Ok(()) + vergen::generate_cargo_keys(vergen::ConstantsFlags::all()) + .expect("Unable to generate vergen keys!"); } From 57afd396a65d9501002feef1a7a436dd78e7dd83 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 10 Oct 2018 09:08:03 +0200 Subject: [PATCH 0246/5092] bump toolchain --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index c062614a6f93..5fb054b088e4 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-10-01 +nightly-2018-10-10 From 8ea8cd29190cae7ea50dc939ad63b0e8bc650373 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Oct 2018 18:08:50 +0200 Subject: [PATCH 0247/5092] update for ptr provenance --- src/intrinsic.rs | 4 +- src/lib.rs | 27 +++++++++---- src/mono_hash_map.rs | 91 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 9 deletions(-) create mode 100644 src/mono_hash_map.rs diff --git a/src/intrinsic.rs b/src/intrinsic.rs index e9a5714587fb..b7338d4d5214 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -252,7 +252,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: _ => { // Do it in memory let mplace = self.force_allocation(dest)?; - assert!(mplace.extra.is_none()); + assert!(mplace.meta.is_none()); self.memory.write_repeat(mplace.ptr, 0, dest.layout.size)?; } } @@ -410,7 +410,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: _ => { // Do it in memory let mplace = self.force_allocation(dest)?; - assert!(mplace.extra.is_none()); + assert!(mplace.meta.is_none()); self.memory.mark_definedness(mplace.ptr.to_ptr()?, dest.layout.size, false)?; } } diff --git a/src/lib.rs b/src/lib.rs index e4a389427c52..81a2ceead0a6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,9 @@ extern crate rustc_mir; extern crate rustc_target; extern crate syntax; +use std::collections::HashMap; +use std::borrow::Cow; + use rustc::ty::{self, TyCtxt, query::TyCtxtAt}; use rustc::ty::layout::{TyLayout, LayoutOf, Size}; use rustc::hir::def_id::DefId; @@ -21,11 +24,10 @@ use rustc::mir; use syntax::ast::Mutability; use syntax::attr; -use std::collections::HashMap; pub use rustc::mir::interpret::*; pub use rustc_mir::interpret::*; -pub use rustc_mir::interpret; +pub use rustc_mir::interpret::{self, AllocMap}; // resolve ambiguity mod fn_call; mod operator; @@ -34,6 +36,7 @@ mod helpers; mod tls; mod locks; mod range_map; +mod mono_hash_map; use fn_call::EvalContextExt as MissingFnsEvalContextExt; use operator::EvalContextExt as OperatorEvalContextExt; @@ -41,6 +44,7 @@ use intrinsic::EvalContextExt as IntrinsicEvalContextExt; use tls::{EvalContextExt as TlsEvalContextExt, TlsData}; use range_map::RangeMap; use helpers::FalibleScalarExt; +use mono_hash_map::MonoHashMap; pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -231,8 +235,11 @@ pub struct Evaluator<'tcx> { impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { type MemoryData = (); type MemoryKinds = MiriMemoryKind; + type PointerTag = (); // still WIP - const MUT_STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); + type MemoryMap = MonoHashMap, Allocation<()>)>; + + const STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); const ENFORCE_VALIDITY: bool = false; // this is still WIP /// Returns Ok() when the function was handled, fail otherwise @@ -308,7 +315,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn find_foreign_static( tcx: TyCtxtAt<'a, 'tcx, 'tcx>, def_id: DefId, - ) -> EvalResult<'tcx, &'tcx Allocation> { + ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> { let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { Some(name) => name.as_str(), @@ -319,14 +326,13 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { "__cxa_thread_atexit_impl" => { // This should be all-zero, pointer-sized let data = vec![0; tcx.data_layout.pointer_size.bytes() as usize]; - let alloc = Allocation::from_bytes(&data[..], tcx.data_layout.pointer_align); - tcx.intern_const_alloc(alloc) + Allocation::from_bytes(&data[..], tcx.data_layout.pointer_align) } _ => return err!(Unimplemented( format!("can't access foreign static: {}", link_name), )), }; - Ok(alloc) + Ok(Cow::Owned(alloc)) } fn validation_op( @@ -344,4 +350,11 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { // We are not interested in detecting loops Ok(()) } + + fn static_with_default_tag( + alloc: &'_ Allocation + ) -> Cow<'_, Allocation> { + let alloc = alloc.clone(); + Cow::Owned(alloc) + } } diff --git a/src/mono_hash_map.rs b/src/mono_hash_map.rs new file mode 100644 index 000000000000..76ca7ac6a133 --- /dev/null +++ b/src/mono_hash_map.rs @@ -0,0 +1,91 @@ +//! This is a "monotonic HashMap": A HashMap that, when shared, can be pushed to but not +//! otherwise mutated. We also Box items in the map. This means we can safely provide +//! shared references into existing items in the HashMap, because they will not be dropped +//! (from being removed) or moved (because they are boxed). +//! The API is is completely tailored to what `memory.rs` needs. It is still in +//! a separate file to minimize the amount of code that has to care about the unsafety. + +use std::collections::hash_map::Entry; +use std::cell::RefCell; +use std::hash::Hash; +use std::borrow::Borrow; + +use rustc_data_structures::fx::FxHashMap; + +use super::AllocMap; + +#[derive(Debug, Clone)] +pub struct MonoHashMap(RefCell>>); + +impl Default for MonoHashMap { + fn default() -> Self { + MonoHashMap(RefCell::new(Default::default())) + } +} + +impl AllocMap for MonoHashMap { + #[inline(always)] + fn contains_key(&mut self, k: &Q) -> bool + where K: Borrow + { + self.0.get_mut().contains_key(k) + } + + #[inline(always)] + fn insert(&mut self, k: K, v: V) -> Option + { + self.0.get_mut().insert(k, Box::new(v)).map(|x| *x) + } + + #[inline(always)] + fn remove(&mut self, k: &Q) -> Option + where K: Borrow + { + self.0.get_mut().remove(k).map(|x| *x) + } + + #[inline(always)] + fn filter_map_collect(&self, mut f: impl FnMut(&K, &V) -> Option) -> Vec { + self.0.borrow() + .iter() + .filter_map(move |(k, v)| f(k, &*v)) + .collect() + } + + /// The most interesting method: Providing a shared ref without + /// holding the `RefCell` open, and inserting new data if the key + /// is not used yet. + /// `vacant` is called if the key is not found in the map; + /// if it returns a reference, that is used directly, if it + /// returns owned data, that is put into the map and returned. + #[inline(always)] + fn get_or( + &self, + k: K, + vacant: impl FnOnce() -> Result + ) -> Result<&V, E> { + let val: *const V = match self.0.borrow_mut().entry(k) { + Entry::Occupied(entry) => &**entry.get(), + Entry::Vacant(entry) => &**entry.insert(Box::new(vacant()?)), + }; + // This is safe because `val` points into a `Box`, that we know will not move and + // will also not be dropped as long as the shared reference `self` is live. + unsafe { Ok(&*val) } + } + + #[inline(always)] + fn get_mut_or( + &mut self, + k: K, + vacant: impl FnOnce() -> Result + ) -> Result<&mut V, E> + { + match self.0.get_mut().entry(k) { + Entry::Occupied(e) => Ok(e.into_mut()), + Entry::Vacant(e) => { + let v = vacant()?; + Ok(e.insert(Box::new(v))) + } + } + } +} From cde707d28b1e3489c5bb34c0f86d650537436790 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Oct 2018 08:45:57 +0200 Subject: [PATCH 0248/5092] bump toolchain --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 5fb054b088e4..721790eb1a83 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-10-10 +nightly-2018-10-11 From ce5b183e8bbaa7a2fa7d20077808027e0cc5bd78 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 9 Oct 2018 22:03:14 +0200 Subject: [PATCH 0249/5092] update for new return place handling --- src/fn_call.rs | 3 +-- src/lib.rs | 13 ++++++------- src/tls.rs | 11 +++++++---- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 3e795f165331..9b6a9c67b16a 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -252,12 +252,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' // Now we make a function call. TODO: Consider making this re-usable? EvalContext::step does sth. similar for the TLS dtors, // and of course eval_main. let mir = self.load_mir(f_instance.def)?; - let closure_dest = Place::null(&self); self.push_stack_frame( f_instance, mir.span, mir, - closure_dest, + None, StackPopCleanup::Goto(Some(ret)), // directly return to caller )?; let mut args = self.frame().mir.args_iter(); diff --git a/src/lib.rs b/src/lib.rs index 81a2ceead0a6..04405f383d12 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,7 +67,6 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( .to_owned(), )); } - let ptr_size = ecx.memory.pointer_size(); if let Some(start_id) = start_wrapper { let main_ret_ty = ecx.tcx.fn_sig(main_id).output(); @@ -89,16 +88,15 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( } // Return value (in static memory so that it does not count as leak) - let size = ecx.tcx.data_layout.pointer_size; - let align = ecx.tcx.data_layout.pointer_align; - let ret_ptr = ecx.memory_mut().allocate(size, align, MiriMemoryKind::MutStatic.into())?; + let ret = ecx.layout_of(start_mir.return_ty())?; + let ret_ptr = ecx.allocate(ret, MiriMemoryKind::MutStatic.into())?; // Push our stack frame ecx.push_stack_frame( start_instance, start_mir.span, start_mir, - Place::from_ptr(ret_ptr, align), + Some(ret_ptr.into()), StackPopCleanup::None { cleanup: true }, )?; @@ -126,11 +124,12 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( assert!(args.next().is_none(), "start lang item has more arguments than expected"); } else { + let ret_place = MPlaceTy::dangling(ecx.layout_of(tcx.mk_unit())?, &ecx).into(); ecx.push_stack_frame( main_instance, main_mir.span, main_mir, - Place::from_scalar_ptr(Scalar::from_int(1, ptr_size).into(), ty::layout::Align::from_bytes(1, 1).unwrap()), + Some(ret_place), StackPopCleanup::None { cleanup: true }, )?; @@ -286,7 +285,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { malloc, malloc_mir.span, malloc_mir, - *dest, + Some(dest), // Don't do anything when we are done. The statement() function will increment // the old stack frame's stmt counter to the next statement, which means that when // exchange_malloc returns, we go on evaluating exactly where we want to be. diff --git a/src/tls.rs b/src/tls.rs index a1ddaf64cc0f..c04f7a9c3502 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -1,9 +1,12 @@ use std::collections::BTreeMap; +use rustc_target::abi::LayoutOf; use rustc::{ty, ty::layout::HasDataLayout, mir}; -use super::{EvalResult, EvalErrorKind, Scalar, Evaluator, - Place, StackPopCleanup, EvalContext}; +use super::{ + EvalResult, EvalErrorKind, StackPopCleanup, EvalContext, Evaluator, + MPlaceTy, Scalar, +}; pub type TlsKey = u128; @@ -139,12 +142,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // TODO: Potentially, this has to support all the other possible instances? // See eval_fn_call in interpret/terminator/mod.rs let mir = self.load_mir(instance.def)?; - let ret = Place::null(&self); + let ret_place = MPlaceTy::dangling(self.layout_of(self.tcx.mk_unit())?, &self).into(); self.push_stack_frame( instance, mir.span, mir, - ret, + Some(ret_place), StackPopCleanup::None { cleanup: true }, )?; let arg_local = self.frame().mir.args_iter().next().ok_or_else( From 791f464ea02d017f6499627223a1981b6531ca48 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 9 Oct 2018 22:35:14 +0200 Subject: [PATCH 0250/5092] update for size_and_align considering extern types --- src/intrinsic.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index b7338d4d5214..2128ff5d7aca 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -238,7 +238,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "init" => { // Check fast path: we don't want to force an allocation in case the destination is a simple value, // but we also do not want to create a new allocation with 0s and then copy that over. - if !dest.layout.is_zst() { // notzhing to do for ZST + // FIXME: We do not properly validate in case of ZSTs and when doing it in memory! + // However, this only affects direct calls of the intrinsic; calls to the stable + // functions wrapping them do get their validation. + if !dest.layout.is_zst() { // nothing to do for ZST match dest.layout.abi { layout::Abi::Scalar(ref s) => { let x = Scalar::from_int(0, s.value.size(&self)); @@ -338,7 +341,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "size_of_val" => { let mplace = self.ref_to_mplace(self.read_value(args[0])?)?; - let (size, _) = self.size_and_align_of_mplace(mplace)?; + let (size, _) = self.size_and_align_of_mplace(mplace)? + .expect("size_of_val called on extern type"); let ptr_size = self.pointer_size(); self.write_scalar( Scalar::from_uint(size.bytes() as u128, ptr_size), @@ -349,7 +353,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "min_align_of_val" | "align_of_val" => { let mplace = self.ref_to_mplace(self.read_value(args[0])?)?; - let (_, align) = self.size_and_align_of_mplace(mplace)?; + let (_, align) = self.size_and_align_of_mplace(mplace)? + .expect("size_of_val called on extern type"); let ptr_size = self.pointer_size(); self.write_scalar( Scalar::from_uint(align.abi(), ptr_size), @@ -397,6 +402,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "uninit" => { // Check fast path: we don't want to force an allocation in case the destination is a simple value, // but we also do not want to create a new allocation with 0s and then copy that over. + // FIXME: We do not properly validate in case of ZSTs and when doing it in memory! + // However, this only affects direct calls of the intrinsic; calls to the stable + // functions wrapping them do get their validation. if !dest.layout.is_zst() { // nothing to do for ZST match dest.layout.abi { layout::Abi::Scalar(..) => { From a090edbc03b95eb21f75675c026e674d646cae74 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 10 Oct 2018 09:06:44 +0200 Subject: [PATCH 0251/5092] explain a test --- tests/run-pass/ref-invalid-ptr.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/run-pass/ref-invalid-ptr.rs b/tests/run-pass/ref-invalid-ptr.rs index ebbbb77748d4..8edc944c7c88 100644 --- a/tests/run-pass/ref-invalid-ptr.rs +++ b/tests/run-pass/ref-invalid-ptr.rs @@ -1,7 +1,9 @@ fn main() { let x = 2usize as *const u32; + // this is not aligned, but we immediately cast it to a raw ptr so that must be okay let _y = unsafe { &*x as *const u32 }; let x = 0usize as *const u32; + // this is NULL, but we immediately cast it to a raw ptr so that must be okay let _y = unsafe { &*x as *const u32 }; } From d94d32e937c672317527cb440788138f688bf3c4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Oct 2018 09:02:28 +0200 Subject: [PATCH 0252/5092] enforce_validity became a function --- src/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 04405f383d12..965810d0e40f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -239,7 +239,11 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { type MemoryMap = MonoHashMap, Allocation<()>)>; const STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); - const ENFORCE_VALIDITY: bool = false; // this is still WIP + + #[inline(always)] + fn enforce_validity(_ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool { + false // this is still WIP + } /// Returns Ok() when the function was handled, fail otherwise fn find_fn( From e4dfb7013b71b9c6f573aed24e76eab5fdf088e0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Oct 2018 11:24:22 +0200 Subject: [PATCH 0253/5092] enable validation per default, but add a flag to disable it and use that for some run-pass tests compile-fail does not do validation yet --- src/bin/miri.rs | 56 ++++++++++++------- src/lib.rs | 25 +++++++-- tests/compiletest.rs | 1 + tests/run-pass/btreemap.rs | 6 +- .../run-pass/call_drop_through_owned_slice.rs | 3 + tests/run-pass/issue-29746.rs | 3 + tests/run-pass/rc.rs | 3 + tests/run-pass/ref-invalid-ptr.rs | 3 + tests/run-pass/sendable-class.rs | 3 + tests/run-pass/unique-send.rs | 3 + 10 files changed, 80 insertions(+), 26 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 57d49b2e6bc5..d7207da0b3c0 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -25,10 +25,14 @@ use std::path::PathBuf; struct MiriCompilerCalls { default: Box, - /// Whether to begin interpretation at the start_fn lang item or not + + /// Whether to begin interpretation at the start_fn lang item or not. /// - /// If false, the interpretation begins at the `main` function + /// If false, the interpretation begins at the `main` function. start_fn: bool, + + /// Whether to enforce the validity invariant. + validate: bool, } impl<'a> CompilerCalls<'a> for MiriCompilerCalls { @@ -87,7 +91,9 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { let mut control = this.default.build_controller(sess, matches); control.after_hir_lowering.callback = Box::new(after_hir_lowering); let start_fn = this.start_fn; - control.after_analysis.callback = Box::new(move |state| after_analysis(state, start_fn)); + let validate = this.validate; + control.after_analysis.callback = + Box::new(move |state| after_analysis(state, start_fn, validate)); control.after_analysis.stop = Compilation::Stop; control } @@ -101,16 +107,21 @@ fn after_hir_lowering(state: &mut CompileState) { state.session.plugin_attributes.borrow_mut().push(attr); } -fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>, use_start_fn: bool) { +fn after_analysis<'a, 'tcx>( + state: &mut CompileState<'a, 'tcx>, + use_start_fn: bool, + validate: bool, +) { state.session.abort_if_errors(); let tcx = state.tcx.unwrap(); if std::env::args().any(|arg| arg == "--test") { - struct Visitor<'a, 'tcx: 'a>( - TyCtxt<'a, 'tcx, 'tcx>, - &'a CompileState<'a, 'tcx> - ); + struct Visitor<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + state: &'a CompileState<'a, 'tcx>, + validate: bool, + }; impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.node { @@ -118,13 +129,13 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>, use_start_fn: bo attr.name() == "test" }) { - let did = self.0.hir.body_owner_def_id(body_id); + let did = self.tcx.hir.body_owner_def_id(body_id); println!( "running test: {}", - self.0.def_path_debug_str(did), + self.tcx.def_path_debug_str(did), ); - miri::eval_main(self.0, did, None); - self.1.session.abort_if_errors(); + miri::eval_main(self.tcx, did, None, self.validate); + self.state.session.abort_if_errors(); } } } @@ -132,7 +143,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>, use_start_fn: bo fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {} } state.hir_crate.unwrap().visit_all_item_likes( - &mut Visitor(tcx, state), + &mut Visitor { tcx, state, validate } ); } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { let entry_def_id = tcx.hir.local_def_id(entry_node_id); @@ -142,7 +153,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>, use_start_fn: bo } else { None }; - miri::eval_main(tcx, entry_def_id, start_wrapper); + miri::eval_main(tcx, entry_def_id, start_wrapper, validate); state.session.abort_if_errors(); } else { @@ -221,12 +232,18 @@ fn main() { } let mut start_fn = false; + let mut validate = true; args.retain(|arg| { - if arg == "-Zmiri-start-fn" { - start_fn = true; - false - } else { - true + match arg.as_str() { + "-Zmiri-start-fn" => { + start_fn = true; + false + }, + "-Zmiri-disable-validation" => { + validate = false; + false + }, + _ => true } }); @@ -235,6 +252,7 @@ fn main() { rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls { default: Box::new(RustcDefaultCalls), start_fn, + validate, }), None, None) }); std::process::exit(result as i32); diff --git a/src/lib.rs b/src/lib.rs index 965810d0e40f..13b42d8e3c27 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,11 +50,12 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, start_wrapper: Option, + validate: bool, ) -> EvalResult<'tcx, EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>> { let mut ecx = EvalContext::new( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), - Default::default(), + Evaluator::new(validate), Default::default(), ); @@ -145,8 +146,9 @@ pub fn eval_main<'a, 'tcx: 'a>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, start_wrapper: Option, + validate: bool, ) { - let mut ecx = create_ecx(tcx, main_id, start_wrapper).expect("Couldn't create ecx"); + let mut ecx = create_ecx(tcx, main_id, start_wrapper, validate).expect("Couldn't create ecx"); let res: EvalResult = (|| { ecx.run()?; @@ -221,7 +223,7 @@ impl Into> for MiriMemoryKind { } -#[derive(Clone, Default, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq)] pub struct Evaluator<'tcx> { /// Environment variables set by `setenv` /// Miri does not expose env vars from the host to the emulated program @@ -229,6 +231,19 @@ pub struct Evaluator<'tcx> { /// TLS state pub(crate) tls: TlsData<'tcx>, + + /// Whether to enforce the validity invariant + pub(crate) validate: bool, +} + +impl<'tcx> Evaluator<'tcx> { + fn new(validate: bool) -> Self { + Evaluator { + env_vars: HashMap::default(), + tls: TlsData::default(), + validate, + } + } } impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { @@ -241,8 +256,8 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { const STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); #[inline(always)] - fn enforce_validity(_ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool { - false // this is still WIP + fn enforce_validity(ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool { + ecx.machine.validate } /// Returns Ok() when the function was handled, fail otherwise diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 82a2144a337d..151aa89be3f3 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -64,6 +64,7 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullm flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs config.src_base = PathBuf::from(path.to_string()); flags.push("-Zmir-emit-validate=1".to_owned()); + flags.push("-Zmiri-disable-validation".to_owned()); config.target_rustcflags = Some(flags.join(" ")); config.target = target.to_owned(); config.host = host.to_owned(); diff --git a/tests/run-pass/btreemap.rs b/tests/run-pass/btreemap.rs index 0fd28d6f1e8d..dc0fa0987aeb 100644 --- a/tests/run-pass/btreemap.rs +++ b/tests/run-pass/btreemap.rs @@ -1,5 +1,5 @@ -// mir validation can't cope with `mem::uninitialized()`, so this test fails with validation & full-MIR. -// compile-flags: -Zmir-emit-validate=0 +// FIXME: Validation disabled due to https://github.com/rust-lang/rust/issues/54957 +// compile-flags: -Zmiri-disable-validation #[derive(PartialEq, Eq, PartialOrd, Ord)] pub enum Foo { @@ -14,4 +14,6 @@ pub fn main() { b.insert(Foo::A("/=")); b.insert(Foo::A("#")); b.insert(Foo::A("0o")); + assert!(b.remove(&Foo::A("/="))); + assert!(!b.remove(&Foo::A("/="))); } diff --git a/tests/run-pass/call_drop_through_owned_slice.rs b/tests/run-pass/call_drop_through_owned_slice.rs index 3ec6be65ed8b..b0e336c0480a 100644 --- a/tests/run-pass/call_drop_through_owned_slice.rs +++ b/tests/run-pass/call_drop_through_owned_slice.rs @@ -1,3 +1,6 @@ +// FIXME validation disabled because ptr::read uses mem::uninitialized +// compile-flags: -Zmiri-disable-validation + struct Bar; static mut DROP_COUNT: usize = 0; diff --git a/tests/run-pass/issue-29746.rs b/tests/run-pass/issue-29746.rs index 61c601ac6a90..94ca146db1cd 100644 --- a/tests/run-pass/issue-29746.rs +++ b/tests/run-pass/issue-29746.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// FIXME validation disabled because ptr::read uses mem::uninitialized +// compile-flags: -Zmiri-disable-validation + // zip!(a1,a2,a3,a4) is equivalent to: // a1.zip(a2).zip(a3).zip(a4).map(|(((x1,x2),x3),x4)| (x1,x2,x3,x4)) macro_rules! zip { diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index 0bf707503112..4d89066035ce 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -1,3 +1,6 @@ +// FIXME: Validation disabled due to https://github.com/rust-lang/rust/issues/54908 +// compile-flags: -Zmiri-disable-validation + use std::cell::RefCell; use std::rc::Rc; diff --git a/tests/run-pass/ref-invalid-ptr.rs b/tests/run-pass/ref-invalid-ptr.rs index 8edc944c7c88..627c821a9f30 100644 --- a/tests/run-pass/ref-invalid-ptr.rs +++ b/tests/run-pass/ref-invalid-ptr.rs @@ -1,3 +1,6 @@ +// FIXME validation disabled because it checks these references too eagerly +// compile-flags: -Zmiri-disable-validation + fn main() { let x = 2usize as *const u32; // this is not aligned, but we immediately cast it to a raw ptr so that must be okay diff --git a/tests/run-pass/sendable-class.rs b/tests/run-pass/sendable-class.rs index 66f0c84e23c1..7ca4e1a90841 100644 --- a/tests/run-pass/sendable-class.rs +++ b/tests/run-pass/sendable-class.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// FIXME validation disabled because ptr::read uses mem::uninitialized +// compile-flags: -Zmiri-disable-validation + // Test that a class with only sendable fields can be sent use std::sync::mpsc::channel; diff --git a/tests/run-pass/unique-send.rs b/tests/run-pass/unique-send.rs index 7644da08e4af..8a48d331f454 100644 --- a/tests/run-pass/unique-send.rs +++ b/tests/run-pass/unique-send.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// FIXME validation disabled because ptr::read uses mem::uninitialized +// compile-flags: -Zmiri-disable-validation + #![feature(box_syntax)] use std::sync::mpsc::channel; From 1846f111c987e160f880c6893b834c24ff5b816c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Oct 2018 15:28:21 +0200 Subject: [PATCH 0254/5092] fix return place for __rust_maybe_catch_panic --- src/fn_call.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 9b6a9c67b16a..812df49b0b8f 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -252,11 +252,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' // Now we make a function call. TODO: Consider making this re-usable? EvalContext::step does sth. similar for the TLS dtors, // and of course eval_main. let mir = self.load_mir(f_instance.def)?; + let ret_place = MPlaceTy::dangling(self.layout_of(self.tcx.mk_unit())?, &self).into(); self.push_stack_frame( f_instance, mir.span, mir, - None, + Some(ret_place), StackPopCleanup::Goto(Some(ret)), // directly return to caller )?; let mut args = self.frame().mir.args_iter(); From 26f9d617c347185433b77c481a5c50c55d9b72ce Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Oct 2018 16:10:04 +0200 Subject: [PATCH 0255/5092] do not validate start-fn code --- tests/compiletest.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 151aa89be3f3..43989a49b308 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -103,6 +103,8 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs if have_fullmir() { flags.push("-Zmiri-start-fn".to_owned()); + // start-fn uses ptr::read, and so fails validation + flags.push("-Zmiri-disable-validation".to_owned()); } if opt { flags.push("-Zmir-opt-level=3".to_owned()); From b99e1267be95e608fb165982a7b77fc0432be360 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 12 Oct 2018 09:07:56 +0200 Subject: [PATCH 0256/5092] atomics wrap around on overflow --- src/intrinsic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index b7338d4d5214..b62838fbc8bb 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -134,7 +134,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "xsub" => mir::BinOp::Sub, _ => bug!(), }; - // FIXME: what do atomics do on overflow? + // Atomics wrap around on overflow. self.binop_ignore_overflow(op, old, rhs, ptr.into())?; } From 62b819ba18a4a32833bb823afeb32778fd28bbde Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 12 Oct 2018 10:40:44 +0200 Subject: [PATCH 0257/5092] whitelist std::ptr::read --- src/lib.rs | 21 +++++++++++++++++-- tests/compiletest.rs | 2 -- .../run-pass/call_drop_through_owned_slice.rs | 3 --- tests/run-pass/issue-29746.rs | 3 --- tests/run-pass/sendable-class.rs | 3 --- tests/run-pass/unique-send.rs | 3 --- 6 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 13b42d8e3c27..d52fd0028039 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -255,9 +255,26 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { const STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); - #[inline(always)] fn enforce_validity(ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool { - ecx.machine.validate + if !ecx.machine.validate { + return false; + } + + // Some functions are whitelisted until we figure out how to fix them. + // We walk up the stack a few frames to also cover their callees. + const WHITELIST: &[&str] = &[ + // Uses mem::uninitialized + "std::ptr::read", + ]; + for frame in ecx.stack().iter() + .rev().take(3) + { + let name = frame.instance.to_string(); + if WHITELIST.iter().any(|white| name.starts_with(white)) { + return false; + } + } + true } /// Returns Ok() when the function was handled, fail otherwise diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 43989a49b308..151aa89be3f3 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -103,8 +103,6 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs if have_fullmir() { flags.push("-Zmiri-start-fn".to_owned()); - // start-fn uses ptr::read, and so fails validation - flags.push("-Zmiri-disable-validation".to_owned()); } if opt { flags.push("-Zmir-opt-level=3".to_owned()); diff --git a/tests/run-pass/call_drop_through_owned_slice.rs b/tests/run-pass/call_drop_through_owned_slice.rs index b0e336c0480a..3ec6be65ed8b 100644 --- a/tests/run-pass/call_drop_through_owned_slice.rs +++ b/tests/run-pass/call_drop_through_owned_slice.rs @@ -1,6 +1,3 @@ -// FIXME validation disabled because ptr::read uses mem::uninitialized -// compile-flags: -Zmiri-disable-validation - struct Bar; static mut DROP_COUNT: usize = 0; diff --git a/tests/run-pass/issue-29746.rs b/tests/run-pass/issue-29746.rs index 94ca146db1cd..61c601ac6a90 100644 --- a/tests/run-pass/issue-29746.rs +++ b/tests/run-pass/issue-29746.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME validation disabled because ptr::read uses mem::uninitialized -// compile-flags: -Zmiri-disable-validation - // zip!(a1,a2,a3,a4) is equivalent to: // a1.zip(a2).zip(a3).zip(a4).map(|(((x1,x2),x3),x4)| (x1,x2,x3,x4)) macro_rules! zip { diff --git a/tests/run-pass/sendable-class.rs b/tests/run-pass/sendable-class.rs index 7ca4e1a90841..66f0c84e23c1 100644 --- a/tests/run-pass/sendable-class.rs +++ b/tests/run-pass/sendable-class.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME validation disabled because ptr::read uses mem::uninitialized -// compile-flags: -Zmiri-disable-validation - // Test that a class with only sendable fields can be sent use std::sync::mpsc::channel; diff --git a/tests/run-pass/unique-send.rs b/tests/run-pass/unique-send.rs index 8a48d331f454..7644da08e4af 100644 --- a/tests/run-pass/unique-send.rs +++ b/tests/run-pass/unique-send.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME validation disabled because ptr::read uses mem::uninitialized -// compile-flags: -Zmiri-disable-validation - #![feature(box_syntax)] use std::sync::mpsc::channel; From c9cf0344eed9a5a475c86a7a1e8be426d1f899ef Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 12 Oct 2018 10:54:37 +0200 Subject: [PATCH 0258/5092] enable validation for compile-fail tests, and add some new ones --- tests/compile-fail/cast_box_int_to_fn_ptr.rs | 2 +- tests/compile-fail/cast_int_to_fn_ptr.rs | 2 +- tests/compile-fail/execute_memory.rs | 2 +- tests/compile-fail/fn_ptr_offset.rs | 2 +- tests/compile-fail/invalid_bool.rs | 8 +------- tests/compile-fail/invalid_bool2.rs | 3 +++ tests/compile-fail/invalid_char.rs | 8 ++++++++ .../{match_char2.rs => invalid_char2.rs} | 3 +++ tests/compile-fail/invalid_enum_discriminant.rs | 11 +---------- tests/compile-fail/invalid_enum_discriminant2.rs | 2 +- tests/compile-fail/match_char.rs | 13 ------------- tests/compile-fail/never_say_never.rs | 2 +- tests/compile-fail/never_transmute_humans.rs | 2 +- tests/compile-fail/never_transmute_void.rs | 2 +- tests/compile-fail/reference_to_packed.rs | 2 +- tests/compile-fail/storage_dead_dangling.rs | 3 +++ tests/compile-fail/validation_cast_fn_ptr1.rs | 10 ++++++++++ tests/compile-fail/validation_cast_fn_ptr2.rs | 10 ++++++++++ tests/compiletest.rs | 1 - 19 files changed, 48 insertions(+), 40 deletions(-) create mode 100644 tests/compile-fail/invalid_char.rs rename tests/compile-fail/{match_char2.rs => invalid_char2.rs} (65%) delete mode 100644 tests/compile-fail/match_char.rs create mode 100644 tests/compile-fail/validation_cast_fn_ptr1.rs create mode 100644 tests/compile-fail/validation_cast_fn_ptr2.rs diff --git a/tests/compile-fail/cast_box_int_to_fn_ptr.rs b/tests/compile-fail/cast_box_int_to_fn_ptr.rs index 2a317f579f5e..cbf370e02363 100644 --- a/tests/compile-fail/cast_box_int_to_fn_ptr.rs +++ b/tests/compile-fail/cast_box_int_to_fn_ptr.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmir-emit-validate=0 +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation fn main() { let b = Box::new(42); diff --git a/tests/compile-fail/cast_int_to_fn_ptr.rs b/tests/compile-fail/cast_int_to_fn_ptr.rs index 29d16e9a4259..2a08d9f1f9f8 100644 --- a/tests/compile-fail/cast_int_to_fn_ptr.rs +++ b/tests/compile-fail/cast_int_to_fn_ptr.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmir-emit-validate=0 +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation fn main() { let g = unsafe { diff --git a/tests/compile-fail/execute_memory.rs b/tests/compile-fail/execute_memory.rs index bcde13d13ee7..2f8fea38d8f9 100644 --- a/tests/compile-fail/execute_memory.rs +++ b/tests/compile-fail/execute_memory.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmir-emit-validate=0 +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation #![feature(box_syntax)] diff --git a/tests/compile-fail/fn_ptr_offset.rs b/tests/compile-fail/fn_ptr_offset.rs index 0c0590e375bb..e6d1da1e0736 100644 --- a/tests/compile-fail/fn_ptr_offset.rs +++ b/tests/compile-fail/fn_ptr_offset.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmir-emit-validate=0 +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation use std::mem; diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index 49328ef5d74e..af4ad67a4f09 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -1,9 +1,3 @@ -//ignore-test FIXME: do some basic validation of invariants for all values in flight -//This does currently not get caught becuase it compiles to SwitchInt, which -//has no knowledge about data invariants. - fn main() { - let b = unsafe { std::mem::transmute::(2) }; - if b { unreachable!() } else { unreachable!() } //~ ERROR constant evaluation error - //~^ NOTE invalid boolean value read + let _b = unsafe { std::mem::transmute::(2) }; //~ ERROR encountered 2, but expected something in the range 0..=1 } diff --git a/tests/compile-fail/invalid_bool2.rs b/tests/compile-fail/invalid_bool2.rs index 47c4e8b410eb..2348c62559b0 100644 --- a/tests/compile-fail/invalid_bool2.rs +++ b/tests/compile-fail/invalid_bool2.rs @@ -1,3 +1,6 @@ +// Validation makes this fail in the wrong place +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation + fn main() { let b = unsafe { std::mem::transmute::(2) }; let _x = b == true; //~ ERROR invalid boolean value read diff --git a/tests/compile-fail/invalid_char.rs b/tests/compile-fail/invalid_char.rs new file mode 100644 index 000000000000..3ff0ed60f664 --- /dev/null +++ b/tests/compile-fail/invalid_char.rs @@ -0,0 +1,8 @@ +fn main() { + assert!(std::char::from_u32(-1_i32 as u32).is_none()); + let _ = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered 4294967295, but expected something in the range 0..=1114111 + 'a' => {true}, + 'b' => {false}, + _ => {true}, + }; +} diff --git a/tests/compile-fail/match_char2.rs b/tests/compile-fail/invalid_char2.rs similarity index 65% rename from tests/compile-fail/match_char2.rs rename to tests/compile-fail/invalid_char2.rs index 786dd813a1eb..5de2d073f323 100644 --- a/tests/compile-fail/match_char2.rs +++ b/tests/compile-fail/invalid_char2.rs @@ -1,3 +1,6 @@ +// Validation makes this fail in the wrong place +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation + fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); let c = unsafe { std::mem::transmute::(-1) }; diff --git a/tests/compile-fail/invalid_enum_discriminant.rs b/tests/compile-fail/invalid_enum_discriminant.rs index 94c100b9ef51..543a797d44f2 100644 --- a/tests/compile-fail/invalid_enum_discriminant.rs +++ b/tests/compile-fail/invalid_enum_discriminant.rs @@ -1,17 +1,8 @@ -// Validation makes this fail in the wrong place -// compile-flags: -Zmir-emit-validate=0 - #[repr(C)] pub enum Foo { A, B, C, D } fn main() { - let f = unsafe { std::mem::transmute::(42) }; - match f { - Foo::A => {}, //~ ERROR invalid enum discriminant - Foo::B => {}, - Foo::C => {}, - Foo::D => {}, - } + let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR encountered invalid enum discriminant 42 } diff --git a/tests/compile-fail/invalid_enum_discriminant2.rs b/tests/compile-fail/invalid_enum_discriminant2.rs index 5a5a20c48695..ea94081693e1 100644 --- a/tests/compile-fail/invalid_enum_discriminant2.rs +++ b/tests/compile-fail/invalid_enum_discriminant2.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmir-emit-validate=0 +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation // error-pattern: invalid enum discriminant diff --git a/tests/compile-fail/match_char.rs b/tests/compile-fail/match_char.rs deleted file mode 100644 index e7fee1e3e361..000000000000 --- a/tests/compile-fail/match_char.rs +++ /dev/null @@ -1,13 +0,0 @@ -//ignore-test FIXME: do some basic validation of invariants for all values in flight -//This does currently not get caught becuase it compiles to SwitchInt, which -//has no knowledge about data invariants. - -fn main() { - assert!(std::char::from_u32(-1_i32 as u32).is_none()); - let _ = match unsafe { std::mem::transmute::(-1) } { //~ ERROR constant evaluation error - //~^ NOTE tried to interpret an invalid 32-bit value as a char: 4294967295 - 'a' => {true}, - 'b' => {false}, - _ => {true}, - }; -} diff --git a/tests/compile-fail/never_say_never.rs b/tests/compile-fail/never_say_never.rs index fd76ecbd1503..9821723deb3b 100644 --- a/tests/compile-fail/never_say_never.rs +++ b/tests/compile-fail/never_say_never.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmir-emit-validate=0 +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation #![feature(never_type)] #![allow(unreachable_code)] diff --git a/tests/compile-fail/never_transmute_humans.rs b/tests/compile-fail/never_transmute_humans.rs index 7652cdfdd3df..c5c53d4231c7 100644 --- a/tests/compile-fail/never_transmute_humans.rs +++ b/tests/compile-fail/never_transmute_humans.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmir-emit-validate=0 +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation #![feature(never_type)] #![allow(unreachable_code)] diff --git a/tests/compile-fail/never_transmute_void.rs b/tests/compile-fail/never_transmute_void.rs index 9329cd365994..11fc0f068de0 100644 --- a/tests/compile-fail/never_transmute_void.rs +++ b/tests/compile-fail/never_transmute_void.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmir-emit-validate=0 +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation #![feature(never_type)] #![allow(unreachable_code)] diff --git a/tests/compile-fail/reference_to_packed.rs b/tests/compile-fail/reference_to_packed.rs index 946a6b89a777..d18f314c8aaa 100644 --- a/tests/compile-fail/reference_to_packed.rs +++ b/tests/compile-fail/reference_to_packed.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmir-emit-validate=0 +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation #![allow(dead_code, unused_variables)] diff --git a/tests/compile-fail/storage_dead_dangling.rs b/tests/compile-fail/storage_dead_dangling.rs index 6abae2069fc2..69917dce8591 100644 --- a/tests/compile-fail/storage_dead_dangling.rs +++ b/tests/compile-fail/storage_dead_dangling.rs @@ -1,3 +1,6 @@ +// This should fail even without validation +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation + static mut LEAK: usize = 0; fn fill(v: &mut i32) { diff --git a/tests/compile-fail/validation_cast_fn_ptr1.rs b/tests/compile-fail/validation_cast_fn_ptr1.rs new file mode 100644 index 000000000000..82f2d10ee4bb --- /dev/null +++ b/tests/compile-fail/validation_cast_fn_ptr1.rs @@ -0,0 +1,10 @@ +fn main() { + // Cast a function pointer such that on a call, the argument gets transmuted + // from raw ptr to reference. This is ABI-compatible, so it's not the call that + // should fail, but validation should. + fn f(_x: &i32) { } + + let g: fn(*const i32) = unsafe { std::mem::transmute(f as fn(&i32)) }; + + g(0usize as *const i32) //~ ERROR encountered 0, but expected something greater or equal to 1 +} diff --git a/tests/compile-fail/validation_cast_fn_ptr2.rs b/tests/compile-fail/validation_cast_fn_ptr2.rs new file mode 100644 index 000000000000..2f3b91a53e62 --- /dev/null +++ b/tests/compile-fail/validation_cast_fn_ptr2.rs @@ -0,0 +1,10 @@ +fn main() { + // Cast a function pointer such that when returning, the return value gets transmuted + // from raw ptr to reference. This is ABI-compatible, so it's not the call that + // should fail, but validation should. + fn f() -> *const i32 { 0usize as *const i32 } + + let g: fn() -> &'static i32 = unsafe { std::mem::transmute(f as fn() -> *const i32) }; + + let _x = g(); //~ ERROR encountered 0, but expected something greater or equal to 1 +} diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 151aa89be3f3..82a2144a337d 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -64,7 +64,6 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullm flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs config.src_base = PathBuf::from(path.to_string()); flags.push("-Zmir-emit-validate=1".to_owned()); - flags.push("-Zmiri-disable-validation".to_owned()); config.target_rustcflags = Some(flags.join(" ")); config.target = target.to_owned(); config.host = host.to_owned(); From 99ca3820e7097f654d4ad49330534a8e49e2165a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Oct 2018 10:35:48 +0200 Subject: [PATCH 0259/5092] bump toolchain --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 721790eb1a83..abbc6c90452a 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-10-11 +nightly-2018-10-14 From b24e1b789dbf765b34c82924b1d8494fc8d84397 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Oct 2018 10:50:35 +0200 Subject: [PATCH 0260/5092] fix rustc_test compilation --- rustc_tests/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rustc_tests/src/main.rs b/rustc_tests/src/main.rs index 969888ec991e..73a8d19c309b 100644 --- a/rustc_tests/src/main.rs +++ b/rustc_tests/src/main.rs @@ -95,7 +95,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { if i.attrs.iter().any(|attr| attr.name() == "test") { let did = self.0.hir.body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); - miri::eval_main(self.0, did, None); + miri::eval_main(self.0, did, None, /*validate*/true); self.1.session.abort_if_errors(); } } @@ -106,7 +106,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(tcx, state)); } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { let entry_def_id = tcx.hir.local_def_id(entry_node_id); - miri::eval_main(tcx, entry_def_id, None); + miri::eval_main(tcx, entry_def_id, None, /*validate*/true); state.session.abort_if_errors(); } else { From 9a1dd865c1d91d6ad8561ba16209998388d98309 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Oct 2018 11:06:36 +0200 Subject: [PATCH 0261/5092] whitelist Windows Mutex --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index d52fd0028039..0bebe40d529a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -265,6 +265,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { const WHITELIST: &[&str] = &[ // Uses mem::uninitialized "std::ptr::read", + "std::sys::windows::mutex::Mutex::", ]; for frame in ecx.stack().iter() .rev().take(3) From 88ec62640e15c2227328266790f309b198e21071 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Oct 2018 11:45:56 +0200 Subject: [PATCH 0262/5092] make rustc-tests a binary in the main project --- .travis.yml | 5 - Cargo.toml | 7 + rustc_tests/Cargo.lock | 241 ------------------ rustc_tests/Cargo.toml | 7 - .../main.rs => src/bin/miri-rustc-tests.rs | 0 5 files changed, 7 insertions(+), 253 deletions(-) delete mode 100644 rustc_tests/Cargo.lock delete mode 100644 rustc_tests/Cargo.toml rename rustc_tests/src/main.rs => src/bin/miri-rustc-tests.rs (100%) diff --git a/.travis.yml b/.travis.yml index 137e61259881..9b4f75ab29cf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,11 +39,6 @@ script: cargo build --release --all-features && cargo test --release --all-features && cargo install --all-features --force --path . -- | - # test that the rustc_tests binary compiles - cd rustc_tests && - cargo build --release && - cd .. - | # get ourselves a MIR-full libstd xargo/build.sh && diff --git a/Cargo.toml b/Cargo.toml index f7caa4d1c2c8..f79609c76394 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,12 @@ test = false # we have no unit tests doctest = false # and no doc tests required-features = ["cargo_miri"] +[[bin]] +name = "miri-rustc-tests" +test = false # we have no unit tests +doctest = false # and no doc tests +required-features = ["rustc_tests"] + [dependencies] byteorder = { version = "1.1", features = ["i128"]} cargo_metadata = { version = "0.6", optional = true } @@ -36,6 +42,7 @@ vergen = "3" [features] cargo_miri = ["cargo_metadata"] +rustc_tests = [] [dev-dependencies] compiletest_rs = { version = "0.3.12", features = ["tmp"] } diff --git a/rustc_tests/Cargo.lock b/rustc_tests/Cargo.lock deleted file mode 100644 index c206ecd64492..000000000000 --- a/rustc_tests/Cargo.lock +++ /dev/null @@ -1,241 +0,0 @@ -[[package]] -name = "aho-corasick" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "atty" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "byteorder" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "cfg-if" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "env_logger" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "humantime" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "lazy_static" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libc" -version = "0.2.30" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "log" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "memchr" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "memchr" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miri" -version = "0.1.0" -dependencies = [ - "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "quick-error" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "redox_syscall" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "redox_termios" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex-syntax" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rustc_tests" -version = "0.1.0" -dependencies = [ - "miri 0.1.0", -] - -[[package]] -name = "termcolor" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "termion" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "thread_local" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ucd-util" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unreachable" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "utf8-ranges" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "wincolor" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[metadata] -"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" -"checksum atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2fc4a1aa4c24c0718a250f0681885c1af91419d242f29eb8f2ab28502d80dbd1" -"checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d" -"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" -"checksum env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0e6e40ebb0e66918a37b38c7acab4e10d299e0463fe2af5d29b9cc86710cfd2a" -"checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" -"checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" -"checksum libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)" = "2370ca07ec338939e356443dac2296f581453c35fe1e3a3ed06023c49435f915" -"checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" -"checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" -"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" -"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" -"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" -"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75ecf88252dce580404a22444fc7d626c01815debba56a7f4f536772a5ff19d3" -"checksum regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1ac0f60d675cc6cf13a20ec076568254472551051ad5dd050364d70671bf6b" -"checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83" -"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" -"checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14" -"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" -"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" -"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb06499a3a4d44302791052df005d5232b927ed1a9658146d842165c4de7767" diff --git a/rustc_tests/Cargo.toml b/rustc_tests/Cargo.toml deleted file mode 100644 index 736f0629768f..000000000000 --- a/rustc_tests/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "rustc_tests" -version = "0.1.0" -authors = ["Oliver Schneider "] - -[dependencies] -miri = { path = ".." } diff --git a/rustc_tests/src/main.rs b/src/bin/miri-rustc-tests.rs similarity index 100% rename from rustc_tests/src/main.rs rename to src/bin/miri-rustc-tests.rs From 4faf8fad106bbcff03a22b64cba57b8c09c4bb6e Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Mon, 15 Oct 2018 18:38:07 +0000 Subject: [PATCH 0263/5092] cargo-miri: support running unit tests for libraries as well as test binaries --- src/bin/cargo-miri.rs | 46 ++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 95ce9cc7ecb5..4cd209013330 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -97,24 +97,38 @@ fn main() { let kind = target.kind.get(0).expect( "badly formatted cargo metadata: target::kind is an empty array", ); - if test && kind == "test" { - if let Err(code) = process( - vec!["--test".to_string(), target.name].into_iter().chain( - args, - ), - ) - { - std::process::exit(code); + match (test, &kind[..]) { + (true, "test") => { + if let Err(code) = process( + vec!["--test".to_string(), target.name].into_iter().chain( + args, + ), + ) + { + std::process::exit(code); + } } - } else if !test && kind == "bin" { - if let Err(code) = process( - vec!["--bin".to_string(), target.name].into_iter().chain( - args, - ), - ) - { - std::process::exit(code); + (true, "lib") => { + if let Err(code) = process( + vec!["--".to_string(), "--test".to_string()].into_iter().chain( + args, + ), + ) + { + std::process::exit(code); + } } + (false, "bin") => { + if let Err(code) = process( + vec!["--bin".to_string(), target.name].into_iter().chain( + args, + ), + ) + { + std::process::exit(code); + } + } + _ => {} } } } else { From 37de74f01572ece6042a73139a95ff050cb7713a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Oct 2018 17:57:03 +0200 Subject: [PATCH 0264/5092] test with opt levels 0 and 1 --- tests/compiletest.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 82a2144a337d..b240fb31d222 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -104,7 +104,11 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: flags.push("-Zmiri-start-fn".to_owned()); } if opt { - flags.push("-Zmir-opt-level=3".to_owned()); + // FIXME: Using level 1 (instead of 3) for now, as the optimizer is pretty broken + // and crashes... + // Level 0 and 1 are not the same, so this still gives us *some* coverage. + // See https://github.com/rust-lang/rust/issues/50411 + flags.push("-Zmir-opt-level=1".to_owned()); } else { flags.push("-Zmir-opt-level=0".to_owned()); // For now, only validate without optimizations. Inlining breaks validation. @@ -187,9 +191,7 @@ fn test() { // uses `libtest` which runs jobs in parallel. run_pass_miri(false); - // FIXME: Disabled for now, as the optimizer is pretty broken and crashes... - // See https://github.com/rust-lang/rust/issues/50411 - //run_pass_miri(true); + run_pass_miri(true); compile_fail_miri(); } From f5e3cdbf03dfe27b5e64a71cf58f9f096bd25b93 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 15 Oct 2018 09:21:29 +0200 Subject: [PATCH 0265/5092] explain our flags in the README --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 314e27de0aa2..e59accaea1b9 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,14 @@ miri` to run your project, if it is a bin project, or run `MIRI_SYSROOT=~/.xargo/HOST cargo +nightly miri test` to run all tests in your project through Miri. +## Miri `-Z` flags + +Miri adds some extra `-Z` flags to control its behavior: + +* `-Zmiri-start-fn`: This makes interpretation start with `lang_start` (defined + in libstd) instead of starting with `main`. Requires full MIR! +* `-Zmiri-disable-validation` disables enforcing the validity invariant. + ## Development and Debugging Since the heart of Miri (the main interpreter engine) lives in rustc, working on From b84f7e20293cd1cebee011dbb485583c79f7ede3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Oct 2018 11:21:38 +0200 Subject: [PATCH 0266/5092] add Borrow tag to pointers; remove old locking code --- src/fn_call.rs | 28 ++++++------- src/helpers.rs | 4 +- src/intrinsic.rs | 10 ++--- src/lib.rs | 61 ++++++++++++++------------- src/locks.rs | 94 ------------------------------------------ src/operator.rs | 47 ++++++++++++--------- src/stacked_borrows.rs | 36 ++++++++++++++++ src/tls.rs | 10 ++--- 8 files changed, 119 insertions(+), 171 deletions(-) delete mode 100644 src/locks.rs create mode 100644 src/stacked_borrows.rs diff --git a/src/fn_call.rs b/src/fn_call.rs index 812df49b0b8f..280cc2bdea58 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -14,8 +14,8 @@ pub trait EvalContextExt<'tcx, 'mir> { fn emulate_foreign_item( &mut self, def_id: DefId, - args: &[OpTy<'tcx>], - dest: PlaceTy<'tcx>, + args: &[OpTy<'tcx, Borrow>], + dest: PlaceTy<'tcx, Borrow>, ret: mir::BasicBlock, ) -> EvalResult<'tcx>; @@ -28,28 +28,28 @@ pub trait EvalContextExt<'tcx, 'mir> { fn emulate_missing_fn( &mut self, path: String, - args: &[OpTy<'tcx>], - dest: Option>, + args: &[OpTy<'tcx, Borrow>], + dest: Option>, ret: Option, ) -> EvalResult<'tcx>; fn find_fn( &mut self, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx>], - dest: Option>, + args: &[OpTy<'tcx, Borrow>], + dest: Option>, ret: Option, ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>>; - fn write_null(&mut self, dest: PlaceTy<'tcx>) -> EvalResult<'tcx>; + fn write_null(&mut self, dest: PlaceTy<'tcx, Borrow>) -> EvalResult<'tcx>; } impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { fn find_fn( &mut self, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx>], - dest: Option>, + args: &[OpTy<'tcx, Borrow>], + dest: Option>, ret: Option, ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> { trace!("eval_fn_call: {:#?}, {:?}", instance, dest.map(|place| *place)); @@ -108,8 +108,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' fn emulate_foreign_item( &mut self, def_id: DefId, - args: &[OpTy<'tcx>], - dest: PlaceTy<'tcx>, + args: &[OpTy<'tcx, Borrow>], + dest: PlaceTy<'tcx, Borrow>, ret: mir::BasicBlock, ) -> EvalResult<'tcx> { let attrs = self.tcx.get_attrs(def_id); @@ -675,8 +675,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' fn emulate_missing_fn( &mut self, path: String, - _args: &[OpTy<'tcx>], - dest: Option>, + _args: &[OpTy<'tcx, Borrow>], + dest: Option>, ret: Option, ) -> EvalResult<'tcx> { // In some cases in non-MIR libstd-mode, not having a destination is legit. Handle these early. @@ -724,7 +724,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' Ok(()) } - fn write_null(&mut self, dest: PlaceTy<'tcx>) -> EvalResult<'tcx> { + fn write_null(&mut self, dest: PlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> { self.write_scalar(Scalar::from_int(0, dest.layout.size), dest) } } diff --git a/src/helpers.rs b/src/helpers.rs index 27b2109d18a1..de787145e22c 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -7,7 +7,7 @@ pub trait FalibleScalarExt { fn to_bytes(self) -> EvalResult<'static, u128>; } -impl FalibleScalarExt for Scalar { +impl FalibleScalarExt for Scalar { fn to_bytes(self) -> EvalResult<'static, u128> { match self { Scalar::Bits { bits, size } => { @@ -19,7 +19,7 @@ impl FalibleScalarExt for Scalar { } } -impl FalibleScalarExt for ScalarMaybeUndef { +impl FalibleScalarExt for ScalarMaybeUndef { fn to_bytes(self) -> EvalResult<'static, u128> { self.not_undef()?.to_bytes() } diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 19c4f04f4826..11c0bd7907c1 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -6,7 +6,7 @@ use rustc::mir::interpret::{EvalResult, PointerArithmetic}; use rustc_mir::interpret::{EvalContext, PlaceTy, OpTy}; use super::{ - Value, Scalar, ScalarMaybeUndef, + Value, Scalar, ScalarMaybeUndef, Borrow, FalibleScalarExt, OperatorEvalContextExt }; @@ -14,8 +14,8 @@ pub trait EvalContextExt<'tcx> { fn call_intrinsic( &mut self, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx>], - dest: PlaceTy<'tcx>, + args: &[OpTy<'tcx, Borrow>], + dest: PlaceTy<'tcx, Borrow>, ) -> EvalResult<'tcx>; } @@ -23,8 +23,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: fn call_intrinsic( &mut self, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx>], - dest: PlaceTy<'tcx>, + args: &[OpTy<'tcx, Borrow>], + dest: PlaceTy<'tcx, Borrow>, ) -> EvalResult<'tcx> { if self.emulate_intrinsic(instance, args, dest)? { return Ok(()); diff --git a/src/lib.rs b/src/lib.rs index 0bebe40d529a..9ac703e2675b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,11 +21,9 @@ use rustc::ty::layout::{TyLayout, LayoutOf, Size}; use rustc::hir::def_id::DefId; use rustc::mir; -use syntax::ast::Mutability; use syntax::attr; -pub use rustc::mir::interpret::*; pub use rustc_mir::interpret::*; pub use rustc_mir::interpret::{self, AllocMap}; // resolve ambiguity @@ -34,9 +32,9 @@ mod operator; mod intrinsic; mod helpers; mod tls; -mod locks; mod range_map; mod mono_hash_map; +mod stacked_borrows; use fn_call::EvalContextExt as MissingFnsEvalContextExt; use operator::EvalContextExt as OperatorEvalContextExt; @@ -45,6 +43,7 @@ use tls::{EvalContextExt as TlsEvalContextExt, TlsData}; use range_map::RangeMap; use helpers::FalibleScalarExt; use mono_hash_map::MonoHashMap; +use stacked_borrows::Borrow; pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -56,7 +55,6 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), Evaluator::new(validate), - Default::default(), ); let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); @@ -118,9 +116,9 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let foo = ecx.memory.allocate_static_bytes(b"foo\0"); let foo_ty = ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8); let foo_layout = ecx.layout_of(foo_ty)?; - let foo_place = ecx.allocate(foo_layout, MemoryKind::Stack)?; // will be interned in just a second + let foo_place = ecx.allocate(foo_layout, MiriMemoryKind::Env.into())?; ecx.write_scalar(Scalar::Ptr(foo), foo_place.into())?; - ecx.memory.intern_static(foo_place.to_ptr()?.alloc_id, Mutability::Immutable)?; + ecx.memory.mark_immutable(foo_place.to_ptr()?.alloc_id)?; ecx.write_scalar(foo_place.ptr, dest)?; assert!(args.next().is_none(), "start lang item has more arguments than expected"); @@ -227,7 +225,7 @@ impl Into> for MiriMemoryKind { pub struct Evaluator<'tcx> { /// Environment variables set by `setenv` /// Miri does not expose env vars from the host to the emulated program - pub(crate) env_vars: HashMap, Pointer>, + pub(crate) env_vars: HashMap, Pointer>, /// TLS state pub(crate) tls: TlsData<'tcx>, @@ -247,11 +245,11 @@ impl<'tcx> Evaluator<'tcx> { } impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { - type MemoryData = (); type MemoryKinds = MiriMemoryKind; - type PointerTag = (); // still WIP + type AllocExtra = (); + type PointerTag = Borrow; - type MemoryMap = MonoHashMap, Allocation<()>)>; + type MemoryMap = MonoHashMap, Allocation)>; const STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); @@ -282,8 +280,8 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn find_fn( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx>], - dest: Option>, + args: &[OpTy<'tcx, Borrow>], + dest: Option>, ret: Option, ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> { ecx.find_fn(instance, args, dest, ret) @@ -292,8 +290,8 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn call_intrinsic( ecx: &mut rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx>], - dest: PlaceTy<'tcx>, + args: &[OpTy<'tcx, Borrow>], + dest: PlaceTy<'tcx, Borrow>, ) -> EvalResult<'tcx> { ecx.call_intrinsic(instance, args, dest) } @@ -301,17 +299,17 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn ptr_op( ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, bin_op: mir::BinOp, - left: Scalar, + left: Scalar, left_layout: TyLayout<'tcx>, - right: Scalar, + right: Scalar, right_layout: TyLayout<'tcx>, - ) -> EvalResult<'tcx, (Scalar, bool)> { + ) -> EvalResult<'tcx, (Scalar, bool)> { ecx.ptr_op(bin_op, left, left_layout, right, right_layout) } fn box_alloc( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - dest: PlaceTy<'tcx>, + dest: PlaceTy<'tcx, Borrow>, ) -> EvalResult<'tcx> { trace!("box_alloc for {:?}", dest.layout.ty); // Call the `exchange_malloc` lang item @@ -351,7 +349,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn find_foreign_static( tcx: TyCtxtAt<'a, 'tcx, 'tcx>, def_id: DefId, - ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> { + ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> { let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { Some(name) => name.as_str(), @@ -371,16 +369,6 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { Ok(Cow::Owned(alloc)) } - fn validation_op( - _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - _op: ::rustc::mir::ValidationOp, - _operand: &::rustc::mir::ValidationOperand<'tcx, ::rustc::mir::Place<'tcx>>, - ) -> EvalResult<'tcx> { - // FIXME: prevent this from ICEing - //ecx.validation_op(op, operand) - Ok(()) - } - fn before_terminator(_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> { // We are not interested in detecting loops @@ -389,8 +377,19 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn static_with_default_tag( alloc: &'_ Allocation - ) -> Cow<'_, Allocation> { - let alloc = alloc.clone(); + ) -> Cow<'_, Allocation> { + let alloc: Allocation = Allocation { + bytes: alloc.bytes.clone(), + relocations: Relocations::from_presorted( + alloc.relocations.iter() + .map(|&(offset, ((), alloc))| (offset, (Borrow::default(), alloc))) + .collect() + ), + undef_mask: alloc.undef_mask.clone(), + align: alloc.align, + mutability: alloc.mutability, + extra: Self::AllocExtra::default(), + }; Cow::Owned(alloc) } } diff --git a/src/locks.rs b/src/locks.rs deleted file mode 100644 index a87ff6367e3a..000000000000 --- a/src/locks.rs +++ /dev/null @@ -1,94 +0,0 @@ -#![allow(unused)] - -use super::*; -use rustc::middle::region; -use rustc::ty::layout::Size; - -//////////////////////////////////////////////////////////////////////////////// -// Locks -//////////////////////////////////////////////////////////////////////////////// - -// Just some dummy to keep this compiling; I think some of this will be useful later -type AbsPlace<'tcx> = ::rustc::ty::Ty<'tcx>; - -/// Information about a lock that is currently held. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct LockInfo<'tcx> { - /// Stores for which lifetimes (of the original write lock) we got - /// which suspensions. - suspended: HashMap, Vec>, - /// The current state of the lock that's actually effective. - pub active: Lock, -} - -/// Write locks are identified by a stack frame and an "abstract" (untyped) place. -/// It may be tempting to use the lifetime as identifier, but that does not work -/// for two reasons: -/// * First of all, due to subtyping, the same lock may be referred to with different -/// lifetimes. -/// * Secondly, different write locks may actually have the same lifetime. See `test2` -/// in `run-pass/many_shr_bor.rs`. -/// The Id is "captured" when the lock is first suspended; at that point, the borrow checker -/// considers the path frozen and hence the Id remains stable. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct WriteLockId<'tcx> { - frame: usize, - path: AbsPlace<'tcx>, -} - - -use rustc::mir::interpret::Lock::*; -use rustc::mir::interpret::Lock; - -impl<'tcx> Default for LockInfo<'tcx> { - fn default() -> Self { - LockInfo::new(NoLock) - } -} - -impl<'tcx> LockInfo<'tcx> { - fn new(lock: Lock) -> LockInfo<'tcx> { - LockInfo { - suspended: HashMap::new(), - active: lock, - } - } - - fn access_permitted(&self, frame: Option, access: AccessKind) -> bool { - use super::AccessKind::*; - match (&self.active, access) { - (&NoLock, _) => true, - (&ReadLock(ref lfts), Read) => { - assert!(!lfts.is_empty(), "Someone left an empty read lock behind."); - // Read access to read-locked region is okay, no matter who's holding the read lock. - true - } - (&WriteLock(ref lft), _) => { - // All access is okay if we are the ones holding it - Some(lft.frame) == frame - } - _ => false, // Nothing else is okay. - } - } -} - -impl<'tcx> RangeMap> { - pub fn check( - &self, - frame: Option, - offset: u64, - len: u64, - access: AccessKind, - ) -> Result<(), LockInfo<'tcx>> { - if len == 0 { - return Ok(()); - } - for lock in self.iter(offset, len) { - // Check if the lock is in conflict with the access. - if !lock.access_permitted(frame, access) { - return Err(lock.clone()); - } - } - Ok(()) - } -} diff --git a/src/operator.rs b/src/operator.rs index 4662a162679e..dd79f293134f 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -7,44 +7,44 @@ pub trait EvalContextExt<'tcx> { fn ptr_op( &self, bin_op: mir::BinOp, - left: Scalar, + left: Scalar, left_layout: TyLayout<'tcx>, - right: Scalar, + right: Scalar, right_layout: TyLayout<'tcx>, - ) -> EvalResult<'tcx, (Scalar, bool)>; + ) -> EvalResult<'tcx, (Scalar, bool)>; fn ptr_int_arithmetic( &self, bin_op: mir::BinOp, - left: Pointer, + left: Pointer, right: u128, signed: bool, - ) -> EvalResult<'tcx, (Scalar, bool)>; + ) -> EvalResult<'tcx, (Scalar, bool)>; fn ptr_eq( &self, - left: Scalar, - right: Scalar, + left: Scalar, + right: Scalar, size: Size, ) -> EvalResult<'tcx, bool>; fn pointer_offset_inbounds( &self, - ptr: Scalar, + ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Scalar>; + ) -> EvalResult<'tcx, Scalar>; } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { fn ptr_op( &self, bin_op: mir::BinOp, - left: Scalar, + left: Scalar, left_layout: TyLayout<'tcx>, - right: Scalar, + right: Scalar, right_layout: TyLayout<'tcx>, - ) -> EvalResult<'tcx, (Scalar, bool)> { + ) -> EvalResult<'tcx, (Scalar, bool)> { use rustc::mir::BinOp::*; trace!("ptr_op: {:?} {:?} {:?}", left, bin_op, right); @@ -124,8 +124,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: fn ptr_eq( &self, - left: Scalar, - right: Scalar, + left: Scalar, + right: Scalar, size: Size, ) -> EvalResult<'tcx, bool> { Ok(match (left, right) { @@ -203,13 +203,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: fn ptr_int_arithmetic( &self, bin_op: mir::BinOp, - left: Pointer, + left: Pointer, right: u128, signed: bool, - ) -> EvalResult<'tcx, (Scalar, bool)> { + ) -> EvalResult<'tcx, (Scalar, bool)> { use rustc::mir::BinOp::*; - fn map_to_primval((res, over): (Pointer, bool)) -> (Scalar, bool) { + fn map_to_primval((res, over): (Pointer, bool)) -> (Scalar, bool) { (Scalar::Ptr(res), over) } @@ -237,7 +237,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: if right & base_mask == base_mask { // Case 1: The base address bits are all preserved, i.e., right is all-1 there let offset = (left.offset.bytes() as u128 & right) as u64; - (Scalar::Ptr(Pointer::new(left.alloc_id, Size::from_bytes(offset))), false) + ( + Scalar::Ptr(Pointer::new_with_tag( + left.alloc_id, + Size::from_bytes(offset), + left.tag, + )), + false, + ) } else if right & base_mask == 0 { // Case 2: The base address bits are all taken away, i.e., right is all-0 there (Scalar::Bits { bits: (left.offset.bytes() as u128) & right, size: ptr_size }, false) @@ -277,10 +284,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: /// allocation. fn pointer_offset_inbounds( &self, - ptr: Scalar, + ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Scalar> { + ) -> EvalResult<'tcx, Scalar> { // FIXME: assuming here that type size is < i64::max_value() let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; let offset = offset.checked_mul(pointee_size).ok_or_else(|| EvalErrorKind::Overflow(mir::BinOp::Mul))?; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs new file mode 100644 index 000000000000..dd9f1b370890 --- /dev/null +++ b/src/stacked_borrows.rs @@ -0,0 +1,36 @@ +use super::RangeMap; + +pub type Timestamp = u64; + +/// Information about a potentially mutable borrow +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub enum Mut { + /// A unique, mutable reference + Uniq(Timestamp), + /// Any raw pointer, or a shared borrow with interior mutability + Raw, +} + +/// Information about any kind of borrow +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub enum Borrow { + /// A mutable borrow, a raw pointer, or a shared borrow with interior mutability + Mut(Mut), + /// A shared borrow without interior mutability + Frz(Timestamp) +} + +/// An item in the borrow stack +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub enum BorStackItem { + /// Defines which references are permitted to mutate *if* the location is not frozen + Mut(Mut), + /// A barrier, tracking the function it belongs to by its index on the call stack + FnBarrier(usize) +} + +impl Default for Borrow { + fn default() -> Self { + Borrow::Mut(Mut::Raw) + } +} diff --git a/src/tls.rs b/src/tls.rs index c04f7a9c3502..c5d119ec7f5b 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -5,14 +5,14 @@ use rustc::{ty, ty::layout::HasDataLayout, mir}; use super::{ EvalResult, EvalErrorKind, StackPopCleanup, EvalContext, Evaluator, - MPlaceTy, Scalar, + MPlaceTy, Scalar, Borrow, }; pub type TlsKey = u128; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct TlsEntry<'tcx> { - pub(crate) data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. + pub(crate) data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. pub(crate) dtor: Option>, } @@ -67,7 +67,7 @@ impl<'tcx> TlsData<'tcx> { } } - pub fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar> { + pub fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar> { match self.keys.get(&key) { Some(&TlsEntry { data, .. }) => { trace!("TLS key {} loaded: {:?}", key, data); @@ -77,7 +77,7 @@ impl<'tcx> TlsData<'tcx> { } } - pub fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx> { + pub fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx> { match self.keys.get_mut(&key) { Some(&mut TlsEntry { ref mut data, .. }) => { trace!("TLS key {} stored: {:?}", key, new_data); @@ -110,7 +110,7 @@ impl<'tcx> TlsData<'tcx> { &mut self, key: Option, cx: impl HasDataLayout, - ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { + ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { use std::collections::Bound::*; let thread_local = &mut self.keys; From 348f782085ea60cbda5a1bd0beb8cd62b0ebd142 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Oct 2018 12:44:04 +0200 Subject: [PATCH 0267/5092] add env var emulation test, and fix it complaining about leaks --- src/lib.rs | 11 +++++++++++ tests/run-pass/env.rs | 7 +++++++ 2 files changed, 18 insertions(+) create mode 100644 tests/run-pass/env.rs diff --git a/src/lib.rs b/src/lib.rs index 9ac703e2675b..47eaee6dfac3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -215,11 +215,22 @@ pub enum MiriMemoryKind { } impl Into> for MiriMemoryKind { + #[inline(always)] fn into(self) -> MemoryKind { MemoryKind::Machine(self) } } +impl MayLeak for MiriMemoryKind { + #[inline(always)] + fn may_leak(self) -> bool { + use MiriMemoryKind::*; + match self { + Rust | C => false, + Env | MutStatic => true, + } + } +} #[derive(Clone, PartialEq, Eq)] pub struct Evaluator<'tcx> { diff --git a/tests/run-pass/env.rs b/tests/run-pass/env.rs new file mode 100644 index 000000000000..c0bf883daf9c --- /dev/null +++ b/tests/run-pass/env.rs @@ -0,0 +1,7 @@ +use std::env; + +fn main() { + assert_eq!(env::var("MIRI_TEST"), Err(env::VarError::NotPresent)); + env::set_var("MIRI_TEST", "the answer"); + assert_eq!(env::var("MIRI_TEST"), Ok("the answer".to_owned())); +} From 66b4bb7cf2e7136ca0a31d04a2abe1754e89a5b6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Oct 2018 18:01:50 +0200 Subject: [PATCH 0268/5092] stacked borrows: track refs and derefs --- src/fn_call.rs | 2 +- src/intrinsic.rs | 5 +- src/lib.rs | 49 ++++++++- src/operator.rs | 2 +- src/range_map.rs | 150 +++++++++++++++++--------- src/stacked_borrows.rs | 238 ++++++++++++++++++++++++++++++++++++++++- src/tls.rs | 8 +- 7 files changed, 388 insertions(+), 66 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 280cc2bdea58..1613da4a487a 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -44,7 +44,7 @@ pub trait EvalContextExt<'tcx, 'mir> { fn write_null(&mut self, dest: PlaceTy<'tcx, Borrow>) -> EvalResult<'tcx>; } -impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { +impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalContext<'a, 'mir, 'tcx> { fn find_fn( &mut self, instance: ty::Instance<'tcx>, diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 11c0bd7907c1..719bc9393958 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -3,10 +3,9 @@ use rustc::ty::layout::{self, LayoutOf, Size}; use rustc::ty; use rustc::mir::interpret::{EvalResult, PointerArithmetic}; -use rustc_mir::interpret::{EvalContext, PlaceTy, OpTy}; use super::{ - Value, Scalar, ScalarMaybeUndef, Borrow, + PlaceTy, OpTy, Value, Scalar, ScalarMaybeUndef, Borrow, FalibleScalarExt, OperatorEvalContextExt }; @@ -19,7 +18,7 @@ pub trait EvalContextExt<'tcx> { ) -> EvalResult<'tcx>; } -impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { +impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { fn call_intrinsic( &mut self, instance: ty::Instance<'tcx>, diff --git a/src/lib.rs b/src/lib.rs index 47eaee6dfac3..97b73e60692c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,7 @@ extern crate syntax; use std::collections::HashMap; use std::borrow::Cow; -use rustc::ty::{self, TyCtxt, query::TyCtxtAt}; +use rustc::ty::{self, Ty, TyCtxt, query::TyCtxtAt}; use rustc::ty::layout::{TyLayout, LayoutOf, Size}; use rustc::hir::def_id::DefId; use rustc::mir; @@ -43,7 +43,7 @@ use tls::{EvalContextExt as TlsEvalContextExt, TlsData}; use range_map::RangeMap; use helpers::FalibleScalarExt; use mono_hash_map::MonoHashMap; -use stacked_borrows::Borrow; +use stacked_borrows::{EvalContextExt as StackedBorEvalContextExt, Borrow}; pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -232,7 +232,6 @@ impl MayLeak for MiriMemoryKind { } } -#[derive(Clone, PartialEq, Eq)] pub struct Evaluator<'tcx> { /// Environment variables set by `setenv` /// Miri does not expose env vars from the host to the emulated program @@ -243,6 +242,9 @@ pub struct Evaluator<'tcx> { /// Whether to enforce the validity invariant pub(crate) validate: bool, + + /// Stacked Borrows state + pub(crate) stacked_borrows: stacked_borrows::State, } impl<'tcx> Evaluator<'tcx> { @@ -251,13 +253,18 @@ impl<'tcx> Evaluator<'tcx> { env_vars: HashMap::default(), tls: TlsData::default(), validate, + stacked_borrows: stacked_borrows::State::new(), } } } +#[allow(dead_code)] // FIXME https://github.com/rust-lang/rust/issues/47131 +type MiriEvalContext<'a, 'mir, 'tcx> = EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>; + + impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { type MemoryKinds = MiriMemoryKind; - type AllocExtra = (); + type AllocExtra = stacked_borrows::Stacks; type PointerTag = Borrow; type MemoryMap = MonoHashMap, Allocation)>; @@ -288,6 +295,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { } /// Returns Ok() when the function was handled, fail otherwise + #[inline(always)] fn find_fn( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, @@ -298,6 +306,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { ecx.find_fn(instance, args, dest, ret) } + #[inline(always)] fn call_intrinsic( ecx: &mut rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, @@ -307,6 +316,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { ecx.call_intrinsic(instance, args, dest) } + #[inline(always)] fn ptr_op( ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, bin_op: mir::BinOp, @@ -380,6 +390,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { Ok(Cow::Owned(alloc)) } + #[inline(always)] fn before_terminator(_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> { // We are not interested in detecting loops @@ -403,4 +414,34 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { }; Cow::Owned(alloc) } + + #[inline(always)] + fn tag_reference( + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ptr: Pointer, + pointee_ty: Ty<'tcx>, + pointee_size: Size, + borrow_kind: mir::BorrowKind, + ) -> EvalResult<'tcx, Self::PointerTag> { + if !ecx.machine.validate { + // No tracking + Ok(Borrow::default()) + } else { + ecx.tag_reference(ptr, pointee_ty, pointee_size, borrow_kind) + } + } + + #[inline(always)] + fn tag_dereference( + ecx: &EvalContext<'a, 'mir, 'tcx, Self>, + ptr: Pointer, + ptr_ty: Ty<'tcx>, + ) -> EvalResult<'tcx, Self::PointerTag> { + if !ecx.machine.validate { + // No tracking + Ok(Borrow::default()) + } else { + ecx.tag_dereference(ptr, ptr_ty) + } + } } diff --git a/src/operator.rs b/src/operator.rs index dd79f293134f..a11f8f34e7e8 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -36,7 +36,7 @@ pub trait EvalContextExt<'tcx> { ) -> EvalResult<'tcx, Scalar>; } -impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { +impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { fn ptr_op( &self, bin_op: mir::BinOp, diff --git a/src/range_map.rs b/src/range_map.rs index e55534e36fd2..1d9a38cb5ef5 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -9,11 +9,20 @@ use std::collections::BTreeMap; use std::ops; +use rustc::ty::layout::Size; + #[derive(Clone, Debug, PartialEq, Eq)] pub struct RangeMap { map: BTreeMap, } +impl Default for RangeMap { + #[inline(always)] + fn default() -> Self { + RangeMap::new() + } +} + // The derived `Ord` impl sorts first by the first field, then, if the fields are the same, // by the second field. // This is exactly what we need for our purposes, since a range query on a BTReeSet/BTreeMap will give us all @@ -21,14 +30,19 @@ pub struct RangeMap { // At the same time the `end` is irrelevant for the sorting and range searching, but used for the check. // This kind of search breaks, if `end < start`, so don't do that! #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] -pub struct Range { +struct Range { start: u64, end: u64, // Invariant: end > start } impl Range { + /// Compute a range of ranges that contains all ranges overlaping with [offset, offset+len) fn range(offset: u64, len: u64) -> ops::Range { - assert!(len > 0); + if len == 0 { + // We can produce an empty range, nothing overlaps with this. + let r = Range { start: 0, end: 1 }; + return r..r; + } // We select all elements that are within // the range given by the offset into the allocation and the length. // This is sound if all ranges that intersect with the argument range, are in the @@ -46,14 +60,20 @@ impl Range { left..right } - /// Tests if all of [offset, offset+len) are contained in this range. + /// Tests if any element of [offset, offset+len) is contained in this range. + #[inline(always)] fn overlaps(&self, offset: u64, len: u64) -> bool { - assert!(len > 0); - offset < self.end && offset + len >= self.start + if len == 0 { + // `offset` totally does not matter, we cannot overlap with an empty interval + false + } else { + offset < self.end && offset.checked_add(len).unwrap() >= self.start + } } } impl RangeMap { + #[inline(always)] pub fn new() -> RangeMap { RangeMap { map: BTreeMap::new() } } @@ -63,10 +83,9 @@ impl RangeMap { offset: u64, len: u64, ) -> impl Iterator + 'a { - assert!(len > 0); self.map.range(Range::range(offset, len)).filter_map( - move |(range, - data)| { + move |(range, data)| { + debug_assert!(len > 0); if range.overlaps(offset, len) { Some((range, data)) } else { @@ -76,8 +95,8 @@ impl RangeMap { ) } - pub fn iter<'a>(&'a self, offset: u64, len: u64) -> impl Iterator + 'a { - self.iter_with_range(offset, len).map(|(_, data)| data) + pub fn iter<'a>(&'a self, offset: Size, len: Size) -> impl Iterator + 'a { + self.iter_with_range(offset.bytes(), len.bytes()).map(|(_, data)| data) } fn split_entry_at(&mut self, offset: u64) @@ -114,28 +133,30 @@ impl RangeMap { } } - pub fn iter_mut_all<'a>(&'a mut self) -> impl Iterator + 'a { - self.map.values_mut() - } - /// Provide mutable iteration over everything in the given range. As a side-effect, /// this will split entries in the map that are only partially hit by the given range, /// to make sure that when they are mutated, the effect is constrained to the given range. + /// If there are gaps, leave them be. pub fn iter_mut_with_gaps<'a>( &'a mut self, - offset: u64, - len: u64, + offset: Size, + len: Size, ) -> impl Iterator + 'a where T: Clone, { - assert!(len > 0); - // Preparation: Split first and last entry as needed. - self.split_entry_at(offset); - self.split_entry_at(offset + len); + let offset = offset.bytes(); + let len = len.bytes(); + + if len > 0 { + // Preparation: Split first and last entry as needed. + self.split_entry_at(offset); + self.split_entry_at(offset + len); + } // Now we can provide a mutable iterator self.map.range_mut(Range::range(offset, len)).filter_map( move |(&range, data)| { + debug_assert!(len > 0); if range.overlaps(offset, len) { assert!( offset <= range.start && offset + len >= range.end, @@ -151,35 +172,41 @@ impl RangeMap { } /// Provide a mutable iterator over everything in the given range, with the same side-effects as - /// iter_mut_with_gaps. Furthermore, if there are gaps between ranges, fill them with the given default. + /// iter_mut_with_gaps. Furthermore, if there are gaps between ranges, fill them with the given default + /// before yielding them in the iterator. /// This is also how you insert. - pub fn iter_mut<'a>(&'a mut self, offset: u64, len: u64) -> impl Iterator + 'a + pub fn iter_mut<'a>(&'a mut self, offset: Size, len: Size) -> impl Iterator + 'a where T: Clone + Default, { - // Do a first iteration to collect the gaps - let mut gaps = Vec::new(); - let mut last_end = offset; - for (range, _) in self.iter_with_range(offset, len) { - if last_end < range.start { + if len.bytes() > 0 { + let offset = offset.bytes(); + let len = len.bytes(); + + // Do a first iteration to collect the gaps + let mut gaps = Vec::new(); + let mut last_end = offset; + for (range, _) in self.iter_with_range(offset, len) { + if last_end < range.start { + gaps.push(Range { + start: last_end, + end: range.start, + }); + } + last_end = range.end; + } + if last_end < offset + len { gaps.push(Range { start: last_end, - end: range.start, + end: offset + len, }); } - last_end = range.end; - } - if last_end < offset + len { - gaps.push(Range { - start: last_end, - end: offset + len, - }); - } - // Add default for all gaps - for gap in gaps { - let old = self.map.insert(gap, Default::default()); - assert!(old.is_none()); + // Add default for all gaps + for gap in gaps { + let old = self.map.insert(gap, Default::default()); + assert!(old.is_none()); + } } // Now provide mutable iteration @@ -208,10 +235,16 @@ mod tests { use super::*; /// Query the map at every offset in the range and collect the results. - fn to_vec(map: &RangeMap, offset: u64, len: u64) -> Vec { + fn to_vec(map: &RangeMap, offset: u64, len: u64, default: Option) -> Vec { (offset..offset + len) .into_iter() - .map(|i| *map.iter(i, 1).next().unwrap()) + .map(|i| map + .iter(Size::from_bytes(i), Size::from_bytes(1)) + .next() + .map(|&t| t) + .or(default) + .unwrap() + ) .collect() } @@ -219,34 +252,47 @@ mod tests { fn basic_insert() { let mut map = RangeMap::::new(); // Insert - for x in map.iter_mut(10, 1) { + for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(1)) { *x = 42; } // Check - assert_eq!(to_vec(&map, 10, 1), vec![42]); + assert_eq!(to_vec(&map, 10, 1, None), vec![42]); + + // Insert with size 0 + for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(0)) { + *x = 19; + } + for x in map.iter_mut(Size::from_bytes(11), Size::from_bytes(0)) { + *x = 19; + } + assert_eq!(to_vec(&map, 10, 2, Some(-1)), vec![42, -1]); } #[test] fn gaps() { let mut map = RangeMap::::new(); - for x in map.iter_mut(11, 1) { + for x in map.iter_mut(Size::from_bytes(11), Size::from_bytes(1)) { *x = 42; } - for x in map.iter_mut(15, 1) { - *x = 42; + for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(1)) { + *x = 43; } + assert_eq!( + to_vec(&map, 10, 10, Some(-1)), + vec![-1, 42, -1, -1, -1, 43, -1, -1, -1, -1] + ); // Now request a range that needs three gaps filled - for x in map.iter_mut(10, 10) { - if *x != 42 { + for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(10)) { + if *x < 42 { *x = 23; } } assert_eq!( - to_vec(&map, 10, 10), - vec![23, 42, 23, 23, 23, 42, 23, 23, 23, 23] + to_vec(&map, 10, 10, None), + vec![23, 42, 23, 23, 23, 43, 23, 23, 23, 23] ); - assert_eq!(to_vec(&map, 13, 5), vec![23, 23, 42, 23, 23]); + assert_eq!(to_vec(&map, 13, 5, None), vec![23, 23, 43, 23, 23]); } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index dd9f1b370890..c3514efdbe71 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -1,4 +1,12 @@ -use super::RangeMap; +use std::cell::RefCell; + +use rustc::ty::{Ty, layout::Size}; +use rustc::mir; + +use super::{ + RangeMap, EvalResult, + Pointer, +}; pub type Timestamp = u64; @@ -11,6 +19,24 @@ pub enum Mut { Raw, } +impl Mut { + #[inline(always)] + fn is_raw(self) -> bool { + match self { + Mut::Raw => true, + _ => false, + } + } + + #[inline(always)] + fn is_uniq(self) -> bool { + match self { + Mut::Uniq(_) => true, + _ => false, + } + } +} + /// Information about any kind of borrow #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum Borrow { @@ -20,6 +46,24 @@ pub enum Borrow { Frz(Timestamp) } +impl Borrow { + #[inline(always)] + fn is_mut(self) -> bool { + match self { + Borrow::Mut(_) => true, + _ => false, + } + } + + #[inline(always)] + fn is_uniq(self) -> bool { + match self { + Borrow::Mut(Mut::Uniq(_)) => true, + _ => false, + } + } +} + /// An item in the borrow stack #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum BorStackItem { @@ -34,3 +78,195 @@ impl Default for Borrow { Borrow::Mut(Mut::Raw) } } + +/// Extra global machine state +#[derive(Clone, Debug)] +pub struct State { + clock: Timestamp +} + +impl State { + pub fn new() -> State { + State { clock: 0 } + } +} + +/// Extra per-location state +#[derive(Clone, Debug)] +struct Stack { + borrows: Vec, // used as a stack + frozen_since: Option, +} + +impl Default for Stack { + fn default() -> Self { + Stack { + borrows: Vec::new(), + frozen_since: None, + } + } +} + +/// Extra per-allocation state +#[derive(Clone, Debug, Default)] +pub struct Stacks { + stacks: RefCell>, +} + +/// Core operations +impl<'tcx> Stack { + fn check(&self, bor: Borrow) -> bool { + match bor { + Borrow::Frz(acc_t) => + // Must be frozen at least as long as the `acc_t` says. + self.frozen_since.map_or(false, |loc_t| loc_t <= acc_t), + Borrow::Mut(acc_m) => + // Raw pointers are fine with frozen locations. This is important because &Cell is raw! + if self.frozen_since.is_some() { + acc_m.is_raw() + } else { + self.borrows.last().map_or(false, |&loc_itm| loc_itm == BorStackItem::Mut(acc_m)) + } + } + } + + /// Reactive `bor` for this stack. If `force_mut` is set, we want to aggressively + /// unfreeze this location (because we are about to push a `Uniq`). + fn reactivate(&mut self, bor: Borrow, force_mut: bool) -> EvalResult<'tcx> { + assert!(!force_mut || bor.is_mut()); // if `force_mut` is set, this must be a mutable borrow + // Do NOT change anything if `bor` is already active -- in particular, if + // it is a `Mut(Raw)` and we are frozen. + if !force_mut && self.check(bor) { + return Ok(()); + } + + let acc_m = match bor { + Borrow::Frz(_) => return err!(MachineError(format!("Location should be frozen but it is not"))), + Borrow::Mut(acc_m) => acc_m, + }; + // We definitely have to unfreeze this, even if we use the topmost item. + self.frozen_since = None; + // Pop until we see the one we are looking for. + while let Some(&itm) = self.borrows.last() { + match itm { + BorStackItem::FnBarrier(_) => { + return err!(MachineError(format!("Trying to reactivate a borrow that lives behind a barrier"))); + } + BorStackItem::Mut(loc_m) => { + if loc_m == acc_m { return Ok(()); } + self.borrows.pop(); + } + } + } + // Nothing to be found. Simulate a "virtual raw" element at the bottom of the stack. + if acc_m.is_raw() { + Ok(()) + } else { + err!(MachineError(format!("Borrow-to-reactivate does not exist on the stack"))) + } + } + + fn initiate(&mut self, bor: Borrow) -> EvalResult<'tcx> { + match bor { + Borrow::Frz(t) => { + match self.frozen_since { + None => self.frozen_since = Some(t), + Some(since) => assert!(since <= t), + } + } + Borrow::Mut(m) => { + match self.frozen_since { + None => self.borrows.push(BorStackItem::Mut(m)), + Some(_) => + // FIXME: Do we want an exception for raw borrows? + return err!(MachineError(format!("Trying to mutate frozen location"))) + } + } + } + Ok(()) + } +} + +impl State { + fn increment_clock(&mut self) -> Timestamp { + self.clock += 1; + self.clock + } +} + +/// Machine hooks +pub trait EvalContextExt<'tcx> { + fn tag_reference( + &mut self, + ptr: Pointer, + pointee_ty: Ty<'tcx>, + size: Size, + borrow_kind: mir::BorrowKind, + ) -> EvalResult<'tcx, Borrow>; + + fn tag_dereference( + &self, + ptr: Pointer, + ptr_ty: Ty<'tcx>, + ) -> EvalResult<'tcx, Borrow>; +} + +impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { + fn tag_reference( + &mut self, + ptr: Pointer, + pointee_ty: Ty<'tcx>, + size: Size, + borrow_kind: mir::BorrowKind, + ) -> EvalResult<'tcx, Borrow> { + let old_bor = ptr.tag; + let time = self.machine.stacked_borrows.increment_clock(); + // FIXME This does not do enough checking when only part of the data lacks + // interior mutability. + let new_bor = match borrow_kind { + mir::BorrowKind::Mut { .. } => Borrow::Mut(Mut::Uniq(time)), + _ => + if self.type_is_freeze(pointee_ty) { + Borrow::Frz(time) + } else { + Borrow::Mut(Mut::Raw) + } + }; + trace!("tag_reference: Creating new tag for {:?} (pointee {}, size {}): {:?}", ptr, pointee_ty, size.bytes(), new_bor); + + // Make sure this reference is not dangling or so + self.memory.check_bounds(ptr, size, false)?; + + // Update the stacks. We cannot use `get_mut` becuse this might be immutable + // memory. + let alloc = self.memory.get(ptr.alloc_id).expect("We checked that the ptr is fine!"); + let mut stacks = alloc.extra.stacks.borrow_mut(); + for stack in stacks.iter_mut(ptr.offset, size) { + if stack.check(new_bor) { + // The new borrow is already active! This can happen when creating multiple + // shared references from the same mutable reference. Do nothing. + } else { + // FIXME: The blog post says we should `reset` if this is a local. + stack.reactivate(old_bor, /*force_mut*/new_bor.is_uniq())?; + stack.initiate(new_bor)?; + } + } + + Ok(new_bor) + } + + fn tag_dereference( + &self, + ptr: Pointer, + ptr_ty: Ty<'tcx>, + ) -> EvalResult<'tcx, Borrow> { + // If this is a raw ptr, forget about the tag. + Ok(if ptr_ty.is_unsafe_ptr() { + trace!("tag_dereference: Erasing tag for {:?} ({})", ptr, ptr_ty); + Borrow::Mut(Mut::Raw) + } else { + // FIXME: Do we want to adjust the tag if it does not match the type? + ptr.tag + }) + } +} diff --git a/src/tls.rs b/src/tls.rs index c5d119ec7f5b..2bddc43df8c4 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -4,19 +4,19 @@ use rustc_target::abi::LayoutOf; use rustc::{ty, ty::layout::HasDataLayout, mir}; use super::{ - EvalResult, EvalErrorKind, StackPopCleanup, EvalContext, Evaluator, + EvalResult, EvalErrorKind, StackPopCleanup, MPlaceTy, Scalar, Borrow, }; pub type TlsKey = u128; -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug)] pub struct TlsEntry<'tcx> { pub(crate) data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. pub(crate) dtor: Option>, } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug)] pub struct TlsData<'tcx> { /// The Key to use for the next thread-local allocation. pub(crate) next_key: TlsKey, @@ -133,7 +133,7 @@ impl<'tcx> TlsData<'tcx> { } } -impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>> { +impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { fn run_tls_dtors(&mut self) -> EvalResult<'tcx> { let mut dtor = self.machine.tls.fetch_tls_dtor(None, *self.tcx); // FIXME: replace loop by some structure that works with stepping From d4b78b36abe896556ba04785610148b51aa67572 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Oct 2018 15:15:53 +0200 Subject: [PATCH 0269/5092] stacked borrows: enforcement at memory accesses --- src/fn_call.rs | 67 +++++++++------- src/intrinsic.rs | 15 ++-- src/lib.rs | 44 ++++++++-- src/range_map.rs | 4 + src/stacked_borrows.rs | 165 ++++++++++++++++++++++++++------------ tests/run-pass/raw.rs | 21 +++++ tests/run-pass/refcell.rs | 33 ++++++++ tests/run-pass/std.rs | 5 +- 8 files changed, 259 insertions(+), 95 deletions(-) create mode 100644 tests/run-pass/raw.rs create mode 100644 tests/run-pass/refcell.rs diff --git a/src/fn_call.rs b/src/fn_call.rs index 1613da4a487a..eb889c1d495a 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -118,6 +118,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo None => self.tcx.item_name(def_id).as_str(), }; + // All these functions take raw pointers, so if we access memory directly + // (as opposed to through a place), we have to remember to erase any tag + // that might still hang around! + match &link_name[..] { "malloc" => { let size = self.read_scalar(args[0])?.to_usize(&self)?; @@ -131,10 +135,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "free" => { - let ptr = self.read_scalar(args[0])?.not_undef()?; + let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation, no tag if !ptr.is_null() { self.memory.deallocate( - ptr.to_ptr()?, + ptr.to_ptr()?.with_default_tag(), None, MiriMemoryKind::C.into(), )?; @@ -171,7 +175,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo self.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_dealloc" => { - let ptr = self.read_scalar(args[0])?.to_ptr()?; + let ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation, no tag let old_size = self.read_scalar(args[1])?.to_usize(&self)?; let align = self.read_scalar(args[2])?.to_usize(&self)?; if old_size == 0 { @@ -181,13 +185,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo return err!(HeapAllocNonPowerOfTwoAlignment(align)); } self.memory.deallocate( - ptr, + ptr.with_default_tag(), Some((Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap())), MiriMemoryKind::Rust.into(), )?; } "__rust_realloc" => { - let ptr = self.read_scalar(args[0])?.to_ptr()?; + let ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation, no tag let old_size = self.read_scalar(args[1])?.to_usize(&self)?; let align = self.read_scalar(args[2])?.to_usize(&self)?; let new_size = self.read_scalar(args[3])?.to_usize(&self)?; @@ -198,7 +202,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo return err!(HeapAllocNonPowerOfTwoAlignment(align)); } let new_ptr = self.memory.reallocate( - ptr, + ptr.with_default_tag(), Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap(), Size::from_bytes(new_size), @@ -230,8 +234,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "dlsym" => { let _handle = self.read_scalar(args[0])?; - let symbol = self.read_scalar(args[1])?.to_ptr()?; - let symbol_name = self.memory.read_c_str(symbol)?; + let symbol = self.read_scalar(args[1])?.to_ptr()?.erase_tag(); + let symbol_name = self.memory.read_c_str(symbol.with_default_tag())?; let err = format!("bad c unicode symbol: {:?}", symbol_name); let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err); return err!(Unimplemented(format!( @@ -284,13 +288,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo return err!(MachineError("the evaluated program panicked".to_string())), "memcmp" => { - let left = self.read_scalar(args[0])?.not_undef()?; - let right = self.read_scalar(args[1])?.not_undef()?; + let left = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation + let right = self.read_scalar(args[1])?.not_undef()?.erase_tag(); // raw ptr operation let n = Size::from_bytes(self.read_scalar(args[2])?.to_usize(&self)?); let result = { - let left_bytes = self.memory.read_bytes(left, n)?; - let right_bytes = self.memory.read_bytes(right, n)?; + let left_bytes = self.memory.read_bytes(left.with_default_tag(), n)?; + let right_bytes = self.memory.read_bytes(right.with_default_tag(), n)?; use std::cmp::Ordering::*; match left_bytes.cmp(right_bytes) { @@ -307,12 +311,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "memrchr" => { - let ptr = self.read_scalar(args[0])?.not_undef()?; + let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation + let ptr = ptr.with_default_tag(); let val = self.read_scalar(args[1])?.to_bytes()? as u8; let num = self.read_scalar(args[2])?.to_usize(&self)?; - if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().rev().position( - |&c| c == val, - ) + if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))? + .iter().rev().position(|&c| c == val) { let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), &self)?; self.write_scalar(new_ptr, dest)?; @@ -322,7 +326,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "memchr" => { - let ptr = self.read_scalar(args[0])?.not_undef()?; + let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation + let ptr = ptr.with_default_tag(); let val = self.read_scalar(args[1])?.to_bytes()? as u8; let num = self.read_scalar(args[2])?.to_usize(&self)?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().position( @@ -338,8 +343,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "getenv" => { let result = { - let name_ptr = self.read_scalar(args[0])?.to_ptr()?; - let name = self.memory.read_c_str(name_ptr)?; + let name_ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation + let name = self.memory.read_c_str(name_ptr.with_default_tag())?; match self.machine.env_vars.get(name) { Some(&var) => Scalar::Ptr(var), None => Scalar::ptr_null(*self.tcx), @@ -351,9 +356,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "unsetenv" => { let mut success = None; { - let name_ptr = self.read_scalar(args[0])?.not_undef()?; + let name_ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation if !name_ptr.is_null() { - let name = self.memory.read_c_str(name_ptr.to_ptr()?)?; + let name = self.memory.read_c_str(name_ptr.to_ptr()?.with_default_tag())?; if !name.is_empty() && !name.contains(&b'=') { success = Some(self.machine.env_vars.remove(name)); } @@ -372,11 +377,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "setenv" => { let mut new = None; { - let name_ptr = self.read_scalar(args[0])?.not_undef()?; - let value_ptr = self.read_scalar(args[1])?.to_ptr()?; - let value = self.memory.read_c_str(value_ptr)?; + let name_ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation + let value_ptr = self.read_scalar(args[1])?.to_ptr()?.erase_tag(); // raw ptr operation + let value = self.memory.read_c_str(value_ptr.with_default_tag())?; if !name_ptr.is_null() { - let name = self.memory.read_c_str(name_ptr.to_ptr()?)?; + let name = self.memory.read_c_str(name_ptr.to_ptr()?.with_default_tag())?; if !name.is_empty() && !name.contains(&b'=') { new = Some((name.to_owned(), value.to_owned())); } @@ -407,14 +412,14 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "write" => { let fd = self.read_scalar(args[0])?.to_bytes()?; - let buf = self.read_scalar(args[1])?.not_undef()?; + let buf = self.read_scalar(args[1])?.not_undef()?.erase_tag(); let n = self.read_scalar(args[2])?.to_bytes()? as u64; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { // stdout/stderr use std::io::{self, Write}; - let buf_cont = self.memory.read_bytes(buf, Size::from_bytes(n))?; + let buf_cont = self.memory.read_bytes(buf.with_default_tag(), Size::from_bytes(n))?; let res = if fd == 1 { io::stdout().write(buf_cont) } else { @@ -435,8 +440,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "strlen" => { - let ptr = self.read_scalar(args[0])?.to_ptr()?; - let n = self.memory.read_c_str(ptr)?.len(); + let ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); + let n = self.memory.read_c_str(ptr.with_default_tag())?.len(); self.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; } @@ -482,7 +487,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // Hook pthread calls that go to the thread-local storage memory subsystem "pthread_key_create" => { - let key_ptr = self.read_scalar(args[0])?.to_ptr()?; + let key_ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation // Extract the function type out of the signature (that seems easier than constructing it ourselves...) let dtor = match self.read_scalar(args[1])?.not_undef()? { @@ -505,7 +510,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo return err!(OutOfTls); } self.memory.write_scalar( - key_ptr, + key_ptr.with_default_tag(), key_layout.align, Scalar::from_uint(key, key_layout.size).into(), key_layout.size, diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 719bc9393958..2b02f22a382b 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -31,6 +31,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let substs = instance.substs; + // All these intrinsics take raw pointers, so if we access memory directly + // (as opposed to through a place), we have to remember to erase any tag + // that might still hang around! + let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..]; match intrinsic_name { "arith_offset" => { @@ -146,12 +150,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let elem_size = elem_layout.size.bytes(); let count = self.read_scalar(args[2])?.to_usize(&self)?; let elem_align = elem_layout.align; - let src = self.read_scalar(args[0])?.not_undef()?; - let dest = self.read_scalar(args[1])?.not_undef()?; + // erase tags: this is a raw ptr operation + let src = self.read_scalar(args[0])?.not_undef()?.erase_tag(); + let dest = self.read_scalar(args[1])?.not_undef()?.erase_tag(); self.memory.copy( - src, + src.with_default_tag(), elem_align, - dest, + dest.with_default_tag(), elem_align, Size::from_bytes(count * elem_size), intrinsic_name.ends_with("_nonoverlapping"), @@ -428,7 +433,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let ty = substs.type_at(0); let ty_layout = self.layout_of(ty)?; let val_byte = self.read_scalar(args[1])?.to_u8()?; - let ptr = self.read_scalar(args[0])?.not_undef()?; + let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag().with_default_tag(); let count = self.read_scalar(args[2])?.to_usize(&self)?; self.memory.check_align(ptr, ty_layout.align)?; self.memory.write_repeat(ptr, val_byte, ty_layout.size * count)?; diff --git a/src/lib.rs b/src/lib.rs index 97b73e60692c..c910911f5762 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -415,14 +415,48 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { Cow::Owned(alloc) } + #[inline(always)] + fn memory_accessed( + alloc: &Allocation, + ptr: Pointer, + size: Size, + access: MemoryAccess, + ) -> EvalResult<'tcx> { + alloc.extra.memory_accessed(ptr, size, access) + } + + #[inline(always)] + fn memory_deallocated( + alloc: &mut Allocation, + ptr: Pointer, + ) -> EvalResult<'tcx> { + alloc.extra.memory_deallocated(ptr) + } + + /*/// Hook for when a reference is cast to a raw pointer + #[inline(always)] + fn ref_to_raw_cast( + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ptr: Pointer, + ptr_ty: Ty<'tcx>, + size: Size, + ) -> EvalResult<'tcx> { + if !ecx.machine.validate { + // No tracking. + Ok(()) + } else { + ecx.ref_to_raw_cast(ptr, ptr_ty, size) + } + }*/ + #[inline(always)] fn tag_reference( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - ptr: Pointer, + ptr: Pointer, pointee_ty: Ty<'tcx>, pointee_size: Size, - borrow_kind: mir::BorrowKind, - ) -> EvalResult<'tcx, Self::PointerTag> { + borrow_kind: Option, + ) -> EvalResult<'tcx, Borrow> { if !ecx.machine.validate { // No tracking Ok(Borrow::default()) @@ -434,9 +468,9 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn tag_dereference( ecx: &EvalContext<'a, 'mir, 'tcx, Self>, - ptr: Pointer, + ptr: Pointer, ptr_ty: Ty<'tcx>, - ) -> EvalResult<'tcx, Self::PointerTag> { + ) -> EvalResult<'tcx, Borrow> { if !ecx.machine.validate { // No tracking Ok(Borrow::default()) diff --git a/src/range_map.rs b/src/range_map.rs index 1d9a38cb5ef5..74a49bf83b81 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -99,6 +99,10 @@ impl RangeMap { self.iter_with_range(offset.bytes(), len.bytes()).map(|(_, data)| data) } + pub fn iter_mut_all<'a>(&'a mut self) -> impl Iterator + 'a { + self.map.values_mut() + } + fn split_entry_at(&mut self, offset: u64) where T: Clone, diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index c3514efdbe71..e4d2289bf34c 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -4,7 +4,7 @@ use rustc::ty::{Ty, layout::Size}; use rustc::mir; use super::{ - RangeMap, EvalResult, + MemoryAccess, RangeMap, EvalResult, Pointer, }; @@ -13,10 +13,10 @@ pub type Timestamp = u64; /// Information about a potentially mutable borrow #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum Mut { - /// A unique, mutable reference - Uniq(Timestamp), - /// Any raw pointer, or a shared borrow with interior mutability - Raw, + /// A unique, mutable reference + Uniq(Timestamp), + /// Any raw pointer, or a shared borrow with interior mutability + Raw, } impl Mut { @@ -27,34 +27,18 @@ impl Mut { _ => false, } } - - #[inline(always)] - fn is_uniq(self) -> bool { - match self { - Mut::Uniq(_) => true, - _ => false, - } - } } /// Information about any kind of borrow #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum Borrow { - /// A mutable borrow, a raw pointer, or a shared borrow with interior mutability - Mut(Mut), - /// A shared borrow without interior mutability - Frz(Timestamp) + /// A mutable borrow, a raw pointer, or a shared borrow with interior mutability + Mut(Mut), + /// A shared borrow without interior mutability + Frz(Timestamp) } impl Borrow { - #[inline(always)] - fn is_mut(self) -> bool { - match self { - Borrow::Mut(_) => true, - _ => false, - } - } - #[inline(always)] fn is_uniq(self) -> bool { match self { @@ -67,10 +51,11 @@ impl Borrow { /// An item in the borrow stack #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum BorStackItem { - /// Defines which references are permitted to mutate *if* the location is not frozen - Mut(Mut), - /// A barrier, tracking the function it belongs to by its index on the call stack - FnBarrier(usize) + /// Defines which references are permitted to mutate *if* the location is not frozen + Mut(Mut), + /// A barrier, tracking the function it belongs to by its index on the call stack + #[allow(dead_code)] // for future use + FnBarrier(usize) } impl Default for Borrow { @@ -133,15 +118,19 @@ impl<'tcx> Stack { /// Reactive `bor` for this stack. If `force_mut` is set, we want to aggressively /// unfreeze this location (because we are about to push a `Uniq`). fn reactivate(&mut self, bor: Borrow, force_mut: bool) -> EvalResult<'tcx> { - assert!(!force_mut || bor.is_mut()); // if `force_mut` is set, this must be a mutable borrow - // Do NOT change anything if `bor` is already active -- in particular, if - // it is a `Mut(Raw)` and we are frozen. + // Unless mutation is bound to happen, do NOT change anything if `bor` is already active. + // In particular, if it is a `Mut(Raw)` and we are frozen, this should be a NOP. if !force_mut && self.check(bor) { return Ok(()); } let acc_m = match bor { - Borrow::Frz(_) => return err!(MachineError(format!("Location should be frozen but it is not"))), + Borrow::Frz(_) => + if force_mut { + return err!(MachineError(format!("Using a shared borrow for mutation"))) + } else { + return err!(MachineError(format!("Location should be frozen but it is not"))) + } Borrow::Mut(acc_m) => acc_m, }; // We definitely have to unfreeze this, even if we use the topmost item. @@ -154,6 +143,7 @@ impl<'tcx> Stack { } BorStackItem::Mut(loc_m) => { if loc_m == acc_m { return Ok(()); } + trace!("reactivate: Popping {:?}", itm); self.borrows.pop(); } } @@ -169,12 +159,14 @@ impl<'tcx> Stack { fn initiate(&mut self, bor: Borrow) -> EvalResult<'tcx> { match bor { Borrow::Frz(t) => { + trace!("initiate: Freezing"); match self.frozen_since { None => self.frozen_since = Some(t), Some(since) => assert!(since <= t), } } Borrow::Mut(m) => { + trace!("initiate: Pushing {:?}", bor); match self.frozen_since { None => self.borrows.push(BorStackItem::Mut(m)), Some(_) => @@ -194,6 +186,58 @@ impl State { } } +/// Higher-level operations +impl<'tcx> Stacks { + pub fn memory_accessed( + &self, + ptr: Pointer, + size: Size, + access: MemoryAccess, + ) -> EvalResult<'tcx> { + trace!("memory_accessed({:?}) with tag {:?}: {:?}, size {}", access, ptr.tag, ptr, size.bytes()); + let mut stacks = self.stacks.borrow_mut(); + for stack in stacks.iter_mut(ptr.offset, size) { + // FIXME: Compare this with what the blog post says. + stack.reactivate(ptr.tag, /*force_mut*/access == MemoryAccess::Write)?; + } + Ok(()) + } + + pub fn memory_deallocated( + &mut self, + ptr: Pointer, + ) -> EvalResult<'tcx> { + trace!("memory_deallocated with tag {:?}: {:?}", ptr.tag, ptr); + let stacks = self.stacks.get_mut(); + for stack in stacks.iter_mut_all() { + // This is like mutating. + stack.reactivate(ptr.tag, /*force_mut*/true)?; + } + Ok(()) + } + + fn reborrow( + &self, + ptr: Pointer, + size: Size, + new_bor: Borrow, + ) -> EvalResult<'tcx> { + let mut stacks = self.stacks.borrow_mut(); + for stack in stacks.iter_mut(ptr.offset, size) { + if stack.check(new_bor) { + // The new borrow is already active! This can happen when creating multiple + // shared references from the same mutable reference. Do nothing. + } else { + // FIXME: The blog post says we should `reset` if this is a local. + stack.reactivate(ptr.tag, /*force_mut*/new_bor.is_uniq())?; + stack.initiate(new_bor)?; + } + } + + Ok(()) + } +} + /// Machine hooks pub trait EvalContextExt<'tcx> { fn tag_reference( @@ -201,7 +245,7 @@ pub trait EvalContextExt<'tcx> { ptr: Pointer, pointee_ty: Ty<'tcx>, size: Size, - borrow_kind: mir::BorrowKind, + borrow_kind: Option, ) -> EvalResult<'tcx, Borrow>; fn tag_dereference( @@ -209,6 +253,13 @@ pub trait EvalContextExt<'tcx> { ptr: Pointer, ptr_ty: Ty<'tcx>, ) -> EvalResult<'tcx, Borrow>; + + fn ref_to_raw_cast( + &mut self, + ptr: Pointer, + ptr_ty: Ty<'tcx>, + size: Size, + ) -> EvalResult<'tcx>; } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { @@ -217,22 +268,23 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' ptr: Pointer, pointee_ty: Ty<'tcx>, size: Size, - borrow_kind: mir::BorrowKind, + borrow_kind: Option, ) -> EvalResult<'tcx, Borrow> { - let old_bor = ptr.tag; let time = self.machine.stacked_borrows.increment_clock(); - // FIXME This does not do enough checking when only part of the data lacks + // FIXME This does not do enough checking when only part of the data has // interior mutability. let new_bor = match borrow_kind { - mir::BorrowKind::Mut { .. } => Borrow::Mut(Mut::Uniq(time)), - _ => + Some(mir::BorrowKind::Mut { .. }) => Borrow::Mut(Mut::Uniq(time)), + Some(_) => if self.type_is_freeze(pointee_ty) { Borrow::Frz(time) } else { Borrow::Mut(Mut::Raw) - } + }, + None => Borrow::Mut(Mut::Raw), }; - trace!("tag_reference: Creating new tag for {:?} (pointee {}, size {}): {:?}", ptr, pointee_ty, size.bytes(), new_bor); + trace!("tag_reference: Creating new reference ({:?}) for {:?} (pointee {}, size {}): {:?}", + borrow_kind, ptr, pointee_ty, size.bytes(), new_bor); // Make sure this reference is not dangling or so self.memory.check_bounds(ptr, size, false)?; @@ -240,17 +292,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Update the stacks. We cannot use `get_mut` becuse this might be immutable // memory. let alloc = self.memory.get(ptr.alloc_id).expect("We checked that the ptr is fine!"); - let mut stacks = alloc.extra.stacks.borrow_mut(); - for stack in stacks.iter_mut(ptr.offset, size) { - if stack.check(new_bor) { - // The new borrow is already active! This can happen when creating multiple - // shared references from the same mutable reference. Do nothing. - } else { - // FIXME: The blog post says we should `reset` if this is a local. - stack.reactivate(old_bor, /*force_mut*/new_bor.is_uniq())?; - stack.initiate(new_bor)?; - } - } + alloc.extra.reborrow(ptr, size, new_bor)?; Ok(new_bor) } @@ -269,4 +311,23 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' ptr.tag }) } + + fn ref_to_raw_cast( + &mut self, + ptr: Pointer, + _ptr_ty: Ty<'tcx>, + size: Size, + ) -> EvalResult<'tcx> { + trace!("ref_to_raw_cast: Escaping {:?}", ptr); + + // Make sure this reference is not dangling or so + self.memory.check_bounds(ptr, size, false)?; + + // Update the stacks. We cannot use `get_mut` becuse this might be immutable + // memory. + let alloc = self.memory.get(ptr.alloc_id).expect("We checked that the ptr is fine!"); + alloc.extra.reborrow(ptr, size, Borrow::Mut(Mut::Raw))?; + + Ok(()) + } } diff --git a/tests/run-pass/raw.rs b/tests/run-pass/raw.rs new file mode 100644 index 000000000000..4fbbb270957b --- /dev/null +++ b/tests/run-pass/raw.rs @@ -0,0 +1,21 @@ +fn basic_raw() { + let mut x = 12; + let x = &mut x; + + assert_eq!(*x, 12); + + let raw = x as *mut i32; + unsafe { *raw = 42; } + + assert_eq!(*x, 42); + + let raw = x as *mut i32; + unsafe { *raw = 12; } + *x = 23; + + assert_eq!(*x, 23); +} + +fn main() { + basic_raw(); +} diff --git a/tests/run-pass/refcell.rs b/tests/run-pass/refcell.rs new file mode 100644 index 000000000000..93cef1572a3e --- /dev/null +++ b/tests/run-pass/refcell.rs @@ -0,0 +1,33 @@ +use std::cell::RefCell; + +fn main() { + let c = RefCell::new(42); + { + let s1 = c.borrow(); + let _x: i32 = *s1; + let s2 = c.borrow(); + let _x: i32 = *s1; + let _y: i32 = *s2; + let _x: i32 = *s1; + let _y: i32 = *s2; + } + { + let mut m = c.borrow_mut(); + let _z: i32 = *m; + { + let s: &i32 = &*m; + let _x = *s; + } + *m = 23; + let _z: i32 = *m; + } + { + let s1 = c.borrow(); + let _x: i32 = *s1; + let s2 = c.borrow(); + let _x: i32 = *s1; + let _y: i32 = *s2; + let _x: i32 = *s1; + let _y: i32 = *s2; + } +} diff --git a/tests/run-pass/std.rs b/tests/run-pass/std.rs index e0e23812d275..7ff967b29f34 100644 --- a/tests/run-pass/std.rs +++ b/tests/run-pass/std.rs @@ -12,8 +12,9 @@ fn rc_cell() -> Rc> { fn rc_refcell() -> i32 { let r = Rc::new(RefCell::new(42)); *r.borrow_mut() += 10; - let x = *r.borrow(); - x + let x = r.borrow(); + let y = r.borrow(); + (*x + *y)/2 } fn arc() -> Arc { From 1907782b64c36f41802a41f1f784f877870293ff Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Oct 2018 16:55:59 +0200 Subject: [PATCH 0270/5092] reenable some tests that work now, and organize them better with directories --- .../stacked_borrows/alias_through_mutation.rs | 15 +++++++++++ .../aliasing_mut1.rs} | 0 .../aliasing_mut2.rs} | 0 .../aliasing_mut3.rs} | 0 .../aliasing_mut4.rs} | 0 .../buggy_as_mut_slice.rs} | 11 +++----- .../buggy_split_at_mut.rs} | 6 ++--- .../stacked_borrows/illegal_write.rs | 11 ++++++++ .../stacked_borrows/illegal_write2.rs | 10 +++++++ .../stacked_borrows/pointer_smuggling.rs | 22 ++++++++++++++++ .../stacked_borrows/shared_confusion.rs | 21 +++++++++++++++ .../compile-fail/validation_illegal_write.rs | 17 ------------ .../compile-fail/validation_lock_confusion.rs | 26 ------------------- .../validation_pointer_smuggling.rs | 22 ---------------- tests/compile-fail/validation_recover1.rs | 18 ------------- tests/compile-fail/validation_recover2.rs | 16 ------------ tests/compile-fail/validation_recover3.rs | 17 ------------ tests/compile-fail/validation_undef.rs | 16 ------------ .../cast_fn_ptr1.rs} | 0 .../cast_fn_ptr2.rs} | 0 .../{ => validity}/invalid_bool.rs | 0 .../{ => validity}/invalid_char.rs | 0 .../invalid_enum_discriminant.rs | 0 .../validity/transmute_through_ptr.rs | 16 ++++++++++++ tests/compile-fail/validity/undef.rs | 12 +++++++++ tests/compiletest.rs | 1 + 26 files changed, 114 insertions(+), 143 deletions(-) create mode 100644 tests/compile-fail/stacked_borrows/alias_through_mutation.rs rename tests/compile-fail/{validation_aliasing_mut1.rs => stacked_borrows/aliasing_mut1.rs} (100%) rename tests/compile-fail/{validation_aliasing_mut2.rs => stacked_borrows/aliasing_mut2.rs} (100%) rename tests/compile-fail/{validation_aliasing_mut3.rs => stacked_borrows/aliasing_mut3.rs} (100%) rename tests/compile-fail/{validation_aliasing_mut4.rs => stacked_borrows/aliasing_mut4.rs} (100%) rename tests/compile-fail/{validation_buggy_as_mut_slice.rs => stacked_borrows/buggy_as_mut_slice.rs} (52%) rename tests/compile-fail/{validation_buggy_split_at_mut.rs => stacked_borrows/buggy_split_at_mut.rs} (79%) create mode 100644 tests/compile-fail/stacked_borrows/illegal_write.rs create mode 100644 tests/compile-fail/stacked_borrows/illegal_write2.rs create mode 100644 tests/compile-fail/stacked_borrows/pointer_smuggling.rs create mode 100644 tests/compile-fail/stacked_borrows/shared_confusion.rs delete mode 100644 tests/compile-fail/validation_illegal_write.rs delete mode 100644 tests/compile-fail/validation_lock_confusion.rs delete mode 100644 tests/compile-fail/validation_pointer_smuggling.rs delete mode 100644 tests/compile-fail/validation_recover1.rs delete mode 100644 tests/compile-fail/validation_recover2.rs delete mode 100644 tests/compile-fail/validation_recover3.rs delete mode 100644 tests/compile-fail/validation_undef.rs rename tests/compile-fail/{validation_cast_fn_ptr1.rs => validity/cast_fn_ptr1.rs} (100%) rename tests/compile-fail/{validation_cast_fn_ptr2.rs => validity/cast_fn_ptr2.rs} (100%) rename tests/compile-fail/{ => validity}/invalid_bool.rs (100%) rename tests/compile-fail/{ => validity}/invalid_char.rs (100%) rename tests/compile-fail/{ => validity}/invalid_enum_discriminant.rs (100%) create mode 100644 tests/compile-fail/validity/transmute_through_ptr.rs create mode 100644 tests/compile-fail/validity/undef.rs diff --git a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs new file mode 100644 index 000000000000..9fa50da45bd0 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs @@ -0,0 +1,15 @@ +#![allow(unused_variables)] + +// This makes a ref that was passed to us via &mut alias with things it should not alias with +fn retarget(x: &mut &u32, target: &mut u32) { + unsafe { *x = &mut *(target as *mut _); } +} + +fn main() { + let target = &mut 42; + let mut target_alias = &42; // initial dummy value + retarget(&mut target_alias, target); + // now `target_alias` points to the same thing as `target` + *target = 13; + let _val = *target_alias; //~ ERROR should be frozen +} diff --git a/tests/compile-fail/validation_aliasing_mut1.rs b/tests/compile-fail/stacked_borrows/aliasing_mut1.rs similarity index 100% rename from tests/compile-fail/validation_aliasing_mut1.rs rename to tests/compile-fail/stacked_borrows/aliasing_mut1.rs diff --git a/tests/compile-fail/validation_aliasing_mut2.rs b/tests/compile-fail/stacked_borrows/aliasing_mut2.rs similarity index 100% rename from tests/compile-fail/validation_aliasing_mut2.rs rename to tests/compile-fail/stacked_borrows/aliasing_mut2.rs diff --git a/tests/compile-fail/validation_aliasing_mut3.rs b/tests/compile-fail/stacked_borrows/aliasing_mut3.rs similarity index 100% rename from tests/compile-fail/validation_aliasing_mut3.rs rename to tests/compile-fail/stacked_borrows/aliasing_mut3.rs diff --git a/tests/compile-fail/validation_aliasing_mut4.rs b/tests/compile-fail/stacked_borrows/aliasing_mut4.rs similarity index 100% rename from tests/compile-fail/validation_aliasing_mut4.rs rename to tests/compile-fail/stacked_borrows/aliasing_mut4.rs diff --git a/tests/compile-fail/validation_buggy_as_mut_slice.rs b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs similarity index 52% rename from tests/compile-fail/validation_buggy_as_mut_slice.rs rename to tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs index 282e536ce9b7..3345668cee00 100644 --- a/tests/compile-fail/validation_buggy_as_mut_slice.rs +++ b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs @@ -1,22 +1,17 @@ -// ignore-test validation_op is disabled - #![allow(unused_variables)] -// For some reason, the error location is different when using fullmir -// error-pattern: in conflict with lock WriteLock - mod safe { use std::slice::from_raw_parts_mut; pub fn as_mut_slice(self_: &Vec) -> &mut [T] { unsafe { - from_raw_parts_mut(self_.as_ptr() as *mut T, self_.len()) + from_raw_parts_mut(self_.as_ptr() as *mut T, self_.len()) //~ ERROR shared borrow for mutation } } } fn main() { let v = vec![0,1,2]; - let v1_ = safe::as_mut_slice(&v); - let v2_ = safe::as_mut_slice(&v); + let v1 = safe::as_mut_slice(&v); + let v2 = safe::as_mut_slice(&v); } diff --git a/tests/compile-fail/validation_buggy_split_at_mut.rs b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs similarity index 79% rename from tests/compile-fail/validation_buggy_split_at_mut.rs rename to tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs index a750f1466f51..d7f4300f82c0 100644 --- a/tests/compile-fail/validation_buggy_split_at_mut.rs +++ b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs @@ -1,5 +1,3 @@ -// ignore-test validation_op is disabled - #![allow(unused_variables)] mod safe { @@ -20,5 +18,7 @@ mod safe { fn main() { let mut array = [1,2,3,4]; - let _x = safe::split_at_mut(&mut array, 0); //~ ERROR: in conflict with lock WriteLock + let (a, b) = safe::split_at_mut(&mut array, 0); + a[1] = 5; //~ ERROR does not exist on the stack + b[1] = 6; } diff --git a/tests/compile-fail/stacked_borrows/illegal_write.rs b/tests/compile-fail/stacked_borrows/illegal_write.rs new file mode 100644 index 000000000000..6a7ccc84012c --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_write.rs @@ -0,0 +1,11 @@ +fn evil(x: &u32) { + let x : &mut u32 = unsafe { &mut *(x as *const _ as *mut _) }; + *x = 42; // mutating shared ref without `UnsafeCell` +} + +fn main() { + let target = 42; + let ref_ = ⌖ + evil(ref_); // invalidates shared ref + let _x = *ref_; //~ ERROR should be frozen +} diff --git a/tests/compile-fail/stacked_borrows/illegal_write2.rs b/tests/compile-fail/stacked_borrows/illegal_write2.rs new file mode 100644 index 000000000000..1d61b1b98896 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_write2.rs @@ -0,0 +1,10 @@ +#![allow(unused_variables)] + +fn main() { + let target = &mut 42; + let target2 = target as *mut _; + drop(&mut *target); // reborrow + // Now make sure our ref is still the only one + unsafe { *target2 = 13; } // invalidate our ref + let _val = *target; //~ ERROR does not exist on the stack +} diff --git a/tests/compile-fail/stacked_borrows/pointer_smuggling.rs b/tests/compile-fail/stacked_borrows/pointer_smuggling.rs new file mode 100644 index 000000000000..3576aa52b753 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/pointer_smuggling.rs @@ -0,0 +1,22 @@ +#![allow(unused_variables)] + +static mut PTR: *mut u8 = 0 as *mut _; + +fn fun1(x: &mut u8) { + unsafe { + PTR = x; + } +} + +fn fun2() { + // Now we use a pointer we are not allowed to use + let _x = unsafe { *PTR }; +} + +fn main() { + let val = &mut 0; // FIXME: This should also work with a local variable, but currently it does not. + fun1(val); + *val = 2; // this invalidates any raw ptrs `fun1` might have created. + fun2(); // if they now use a raw ptr they break our reference + *val = 3; //~ ERROR does not exist on the stack +} diff --git a/tests/compile-fail/stacked_borrows/shared_confusion.rs b/tests/compile-fail/stacked_borrows/shared_confusion.rs new file mode 100644 index 000000000000..584053f59323 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/shared_confusion.rs @@ -0,0 +1,21 @@ +#![allow(unused_variables)] +use std::cell::RefCell; + +fn test(r: &mut RefCell) { + let x = &*r; // not freezing because interior mutability + let mut x_ref = x.borrow_mut(); + let x_inner : &mut i32 = &mut *x_ref; // Uniq reference + let x_evil = x_inner as *mut _; + { + let x_inner_shr = &*x_inner; // frozen + let y = &*r; // outer ref, not freezing + let x_inner_shr2 = &*x_inner; // freezing again + } + // Our old raw should be dead by now + unsafe { *x_evil = 0; } // this falls back to some Raw higher up the stack + *x_inner = 12; //~ ERROR does not exist on the stack +} + +fn main() { + test(&mut RefCell::new(0)); +} diff --git a/tests/compile-fail/validation_illegal_write.rs b/tests/compile-fail/validation_illegal_write.rs deleted file mode 100644 index cb3e4b3c1a20..000000000000 --- a/tests/compile-fail/validation_illegal_write.rs +++ /dev/null @@ -1,17 +0,0 @@ -// ignore-test validation_op is disabled - -#![allow(unused_variables)] - -mod safe { - pub(crate) fn safe(x: &u32) { - let x : &mut u32 = unsafe { &mut *(x as *const _ as *mut _) }; - *x = 42; //~ ERROR: in conflict with lock ReadLock - } -} - -fn main() { - let target = &mut 42; - let target_ref = ⌖ - // do a reborrow, but we keep the lock - safe::safe(&*target); -} diff --git a/tests/compile-fail/validation_lock_confusion.rs b/tests/compile-fail/validation_lock_confusion.rs deleted file mode 100644 index 2a0857659622..000000000000 --- a/tests/compile-fail/validation_lock_confusion.rs +++ /dev/null @@ -1,26 +0,0 @@ -// ignore-test validation_op is disabled - -// Make sure validation can handle many overlapping shared borrows for different parts of a data structure -#![allow(unused_variables)] -use std::cell::RefCell; - -fn evil(x: *mut i32) { - unsafe { *x = 0; } //~ ERROR: in conflict with lock WriteLock -} - -fn test(r: &mut RefCell) { - let x = &*r; // releasing write lock, first suspension recorded - let mut x_ref = x.borrow_mut(); - let x_inner : &mut i32 = &mut *x_ref; // new inner write lock, with same lifetime as outer lock - { - let x_inner_shr = &*x_inner; // releasing inner write lock, recording suspension - let y = &*r; // second suspension for the outer write lock - let x_inner_shr2 = &*x_inner; // 2nd suspension for inner write lock - } - // If the two locks are mixed up, here we should have a write lock, but we do not. - evil(x_inner as *mut _); -} - -fn main() { - test(&mut RefCell::new(0)); -} diff --git a/tests/compile-fail/validation_pointer_smuggling.rs b/tests/compile-fail/validation_pointer_smuggling.rs deleted file mode 100644 index 14d624286038..000000000000 --- a/tests/compile-fail/validation_pointer_smuggling.rs +++ /dev/null @@ -1,22 +0,0 @@ -// ignore-test validation_op is disabled - -#![allow(unused_variables)] - -static mut PTR: *mut u8 = 0 as *mut _; - -fn fun1(x: &mut u8) { - unsafe { - PTR = x; - } -} - -fn fun2() { - // Now we use a pointer we are not allowed to use - let _x = unsafe { *PTR }; //~ ERROR: in conflict with lock WriteLock -} - -fn main() { - let mut val = 0; - fun1(&mut val); - fun2(); -} diff --git a/tests/compile-fail/validation_recover1.rs b/tests/compile-fail/validation_recover1.rs deleted file mode 100644 index 9061070ef67e..000000000000 --- a/tests/compile-fail/validation_recover1.rs +++ /dev/null @@ -1,18 +0,0 @@ -// ignore-test validation_op is disabled - -#![allow(unused_variables)] - -#[repr(u32)] -enum Bool { True } - -mod safe { - pub(crate) fn safe(x: &mut super::Bool) { - let x = x as *mut _ as *mut u32; - unsafe { *x = 44; } // out-of-bounds enum discriminant - } -} - -fn main() { - let mut x = Bool::True; - safe::safe(&mut x); //~ ERROR: invalid enum discriminant -} diff --git a/tests/compile-fail/validation_recover2.rs b/tests/compile-fail/validation_recover2.rs deleted file mode 100644 index 7a4a417ab1db..000000000000 --- a/tests/compile-fail/validation_recover2.rs +++ /dev/null @@ -1,16 +0,0 @@ -// ignore-test validation_op is disabled - -#![allow(unused_variables)] - -mod safe { - // This makes a ref that was passed to us via &mut alias with things it should not alias with - pub(crate) fn safe(x: &mut &u32, target: &mut u32) { - unsafe { *x = &mut *(target as *mut _); } - } -} - -fn main() { - let target = &mut 42; - let mut target_alias = &42; // initial dummy value - safe::safe(&mut target_alias, target); //~ ERROR: in conflict with lock ReadLock -} diff --git a/tests/compile-fail/validation_recover3.rs b/tests/compile-fail/validation_recover3.rs deleted file mode 100644 index 5cfc8aaa66b5..000000000000 --- a/tests/compile-fail/validation_recover3.rs +++ /dev/null @@ -1,17 +0,0 @@ -// ignore-test validation_op is disabled - -#![allow(unused_variables)] - -mod safe { - pub(crate) fn safe(x: *mut u32) { - unsafe { *x = 42; } //~ ERROR: in conflict with lock WriteLock - } -} - -fn main() { - let target = &mut 42u32; - let target2 = target as *mut _; - drop(&mut *target); // reborrow - // Now make sure we still got the lock - safe::safe(target2); -} diff --git a/tests/compile-fail/validation_undef.rs b/tests/compile-fail/validation_undef.rs deleted file mode 100644 index 939e93a264e8..000000000000 --- a/tests/compile-fail/validation_undef.rs +++ /dev/null @@ -1,16 +0,0 @@ -// ignore-test validation_op is disabled - -#![allow(unused_variables)] -// error-pattern: attempted to read undefined bytes - -mod safe { - use std::mem; - - pub(crate) fn make_float() -> f32 { - unsafe { mem::uninitialized() } - } -} - -fn main() { - let _x = safe::make_float(); -} diff --git a/tests/compile-fail/validation_cast_fn_ptr1.rs b/tests/compile-fail/validity/cast_fn_ptr1.rs similarity index 100% rename from tests/compile-fail/validation_cast_fn_ptr1.rs rename to tests/compile-fail/validity/cast_fn_ptr1.rs diff --git a/tests/compile-fail/validation_cast_fn_ptr2.rs b/tests/compile-fail/validity/cast_fn_ptr2.rs similarity index 100% rename from tests/compile-fail/validation_cast_fn_ptr2.rs rename to tests/compile-fail/validity/cast_fn_ptr2.rs diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/validity/invalid_bool.rs similarity index 100% rename from tests/compile-fail/invalid_bool.rs rename to tests/compile-fail/validity/invalid_bool.rs diff --git a/tests/compile-fail/invalid_char.rs b/tests/compile-fail/validity/invalid_char.rs similarity index 100% rename from tests/compile-fail/invalid_char.rs rename to tests/compile-fail/validity/invalid_char.rs diff --git a/tests/compile-fail/invalid_enum_discriminant.rs b/tests/compile-fail/validity/invalid_enum_discriminant.rs similarity index 100% rename from tests/compile-fail/invalid_enum_discriminant.rs rename to tests/compile-fail/validity/invalid_enum_discriminant.rs diff --git a/tests/compile-fail/validity/transmute_through_ptr.rs b/tests/compile-fail/validity/transmute_through_ptr.rs new file mode 100644 index 000000000000..0a4c64bb9bb1 --- /dev/null +++ b/tests/compile-fail/validity/transmute_through_ptr.rs @@ -0,0 +1,16 @@ +#![allow(unused_variables)] + +#[repr(u32)] +enum Bool { True } + +fn evil(x: &mut Bool) { + let x = x as *mut _ as *mut u32; + unsafe { *x = 44; } // out-of-bounds enum discriminant +} + +fn main() { + let mut x = Bool::True; + evil(&mut x); + let _y = x; // reading this ought to be enough to trigger validation + //~^ ERROR invalid enum discriminant 44 +} diff --git a/tests/compile-fail/validity/undef.rs b/tests/compile-fail/validity/undef.rs new file mode 100644 index 000000000000..58d3926dadaf --- /dev/null +++ b/tests/compile-fail/validity/undef.rs @@ -0,0 +1,12 @@ +#![allow(unused_variables)] +// error-pattern: encountered undefined data in pointer + +use std::mem; + +fn make_raw() -> *const f32 { + unsafe { mem::uninitialized() } +} + +fn main() { + let _x = make_raw(); +} diff --git a/tests/compiletest.rs b/tests/compiletest.rs index b240fb31d222..7bec3fa8de2c 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -63,6 +63,7 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullm flags.push(format!("--sysroot {}", sysroot.display())); flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs config.src_base = PathBuf::from(path.to_string()); + flags.push("-Zmir-opt-level=0".to_owned()); // optimization circumvents some stacked borrow checks flags.push("-Zmir-emit-validate=1".to_owned()); config.target_rustcflags = Some(flags.join(" ")); config.target = target.to_owned(); From b259512c5783f1ebda367a3094aecc5f9b7da7fd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Oct 2018 17:36:07 +0200 Subject: [PATCH 0271/5092] bump for ENABLE_PTR_TRACKING_HOOKS, and remove some dead code --- src/lib.rs | 18 ++---------------- src/stacked_borrows.rs | 26 -------------------------- 2 files changed, 2 insertions(+), 42 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c910911f5762..1ff29828dab4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -264,8 +264,10 @@ type MiriEvalContext<'a, 'mir, 'tcx> = EvalContext<'a, 'mir, 'tcx, Evaluator<'tc impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { type MemoryKinds = MiriMemoryKind; + type AllocExtra = stacked_borrows::Stacks; type PointerTag = Borrow; + const ENABLE_PTR_TRACKING_HOOKS: bool = true; type MemoryMap = MonoHashMap, Allocation)>; @@ -433,22 +435,6 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { alloc.extra.memory_deallocated(ptr) } - /*/// Hook for when a reference is cast to a raw pointer - #[inline(always)] - fn ref_to_raw_cast( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - ptr: Pointer, - ptr_ty: Ty<'tcx>, - size: Size, - ) -> EvalResult<'tcx> { - if !ecx.machine.validate { - // No tracking. - Ok(()) - } else { - ecx.ref_to_raw_cast(ptr, ptr_ty, size) - } - }*/ - #[inline(always)] fn tag_reference( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index e4d2289bf34c..19d5c723d403 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -253,13 +253,6 @@ pub trait EvalContextExt<'tcx> { ptr: Pointer, ptr_ty: Ty<'tcx>, ) -> EvalResult<'tcx, Borrow>; - - fn ref_to_raw_cast( - &mut self, - ptr: Pointer, - ptr_ty: Ty<'tcx>, - size: Size, - ) -> EvalResult<'tcx>; } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { @@ -311,23 +304,4 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' ptr.tag }) } - - fn ref_to_raw_cast( - &mut self, - ptr: Pointer, - _ptr_ty: Ty<'tcx>, - size: Size, - ) -> EvalResult<'tcx> { - trace!("ref_to_raw_cast: Escaping {:?}", ptr); - - // Make sure this reference is not dangling or so - self.memory.check_bounds(ptr, size, false)?; - - // Update the stacks. We cannot use `get_mut` becuse this might be immutable - // memory. - let alloc = self.memory.get(ptr.alloc_id).expect("We checked that the ptr is fine!"); - alloc.extra.reborrow(ptr, size, Borrow::Mut(Mut::Raw))?; - - Ok(()) - } } From 4fa5bfa2bb1d985ef69a7c09b876fc4d5319ad13 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Tue, 16 Oct 2018 18:06:24 +0000 Subject: [PATCH 0272/5092] add some comments to clarify command-line argument munging in #482 --- src/bin/cargo-miri.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 4cd209013330..3deb5b5a314a 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -99,6 +99,7 @@ fn main() { ); match (test, &kind[..]) { (true, "test") => { + // For test binaries we call `cargo rustc --test target -- ` if let Err(code) = process( vec!["--test".to_string(), target.name].into_iter().chain( args, @@ -109,6 +110,11 @@ fn main() { } } (true, "lib") => { + // For libraries we call `cargo rustc -- --test ` + // Notice now that `--test` is a rustc arg rather than a cargo arg. This tells + // rustc to build a test harness which calls all #[test] functions. We don't + // use the harness since we execute each #[test] function's MIR ourselves before + // compilation even completes, but this option is necessary to build the library. if let Err(code) = process( vec!["--".to_string(), "--test".to_string()].into_iter().chain( args, @@ -119,6 +125,7 @@ fn main() { } } (false, "bin") => { + // For ordinary binaries we call `cargo rustc --bin target -- ` if let Err(code) = process( vec!["--bin".to_string(), target.name].into_iter().chain( args, From b9fe91e48627cde55aaf9b55d016746db0b4907f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Oct 2018 12:04:41 +0200 Subject: [PATCH 0273/5092] fix for ptr-to-raw casts properly erasing the tag --- tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs index 3345668cee00..4857ada7fb2c 100644 --- a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs +++ b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs @@ -5,7 +5,7 @@ mod safe { pub fn as_mut_slice(self_: &Vec) -> &mut [T] { unsafe { - from_raw_parts_mut(self_.as_ptr() as *mut T, self_.len()) //~ ERROR shared borrow for mutation + from_raw_parts_mut(self_.as_ptr() as *mut T, self_.len()) } } } @@ -14,4 +14,6 @@ fn main() { let v = vec![0,1,2]; let v1 = safe::as_mut_slice(&v); let v2 = safe::as_mut_slice(&v); + v1[1] = 5; //~ ERROR does not exist on the stack + v1[1] = 6; } From 186e42d088bb485c156cef93f2d27aa461523fad Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Oct 2018 09:51:04 +0200 Subject: [PATCH 0274/5092] move resolve_path to helpers module --- src/fn_call.rs | 40 +---------------------------------- src/helpers.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++---- src/intrinsic.rs | 2 +- src/lib.rs | 3 ++- 4 files changed, 54 insertions(+), 45 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 812df49b0b8f..ce5b17e7b577 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -1,11 +1,9 @@ use rustc::ty; use rustc::ty::layout::{Align, LayoutOf, Size}; -use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; +use rustc::hir::def_id::DefId; use rustc::mir; use syntax::attr; -use std::mem; - use super::*; pub trait EvalContextExt<'tcx, 'mir> { @@ -19,8 +17,6 @@ pub trait EvalContextExt<'tcx, 'mir> { ret: mir::BasicBlock, ) -> EvalResult<'tcx>; - fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>>; - /// Emulate a function that should have MIR but does not. /// This is solely to support execution without full MIR. /// Fail if emulating this function is not supported. @@ -638,40 +634,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' Ok(()) } - /// Get an instance for a path. - fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>> { - self.tcx - .crates() - .iter() - .find(|&&krate| self.tcx.original_crate_name(krate) == path[0]) - .and_then(|krate| { - let krate = DefId { - krate: *krate, - index: CRATE_DEF_INDEX, - }; - let mut items = self.tcx.item_children(krate); - let mut path_it = path.iter().skip(1).peekable(); - - while let Some(segment) = path_it.next() { - for item in mem::replace(&mut items, Default::default()).iter() { - if item.ident.name == *segment { - if path_it.peek().is_none() { - return Some(ty::Instance::mono(self.tcx.tcx, item.def.def_id())); - } - - items = self.tcx.item_children(item.def.def_id()); - break; - } - } - } - None - }) - .ok_or_else(|| { - let path = path.iter().map(|&s| s.to_owned()).collect(); - EvalErrorKind::PathNotFound(path).into() - }) - } - fn emulate_missing_fn( &mut self, path: String, diff --git a/src/helpers.rs b/src/helpers.rs index 27b2109d18a1..1c63316f6080 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,13 +1,18 @@ -use super::{Scalar, ScalarMaybeUndef, EvalResult}; +use std::mem; -pub trait FalibleScalarExt { +use rustc::ty; +use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; + +use super::*; + +pub trait ScalarExt { /// HACK: this function just extracts all bits if `defined != 0` /// Mainly used for args of C-functions and we should totally correctly fetch the size /// of their arguments fn to_bytes(self) -> EvalResult<'static, u128>; } -impl FalibleScalarExt for Scalar { +impl ScalarExt for Scalar { fn to_bytes(self) -> EvalResult<'static, u128> { match self { Scalar::Bits { bits, size } => { @@ -19,8 +24,49 @@ impl FalibleScalarExt for Scalar { } } -impl FalibleScalarExt for ScalarMaybeUndef { +impl ScalarExt for ScalarMaybeUndef { fn to_bytes(self) -> EvalResult<'static, u128> { self.not_undef()?.to_bytes() } } + +pub trait EvalContextExt<'tcx> { + fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>>; +} + + +impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { + /// Get an instance for a path. + fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>> { + self.tcx + .crates() + .iter() + .find(|&&krate| self.tcx.original_crate_name(krate) == path[0]) + .and_then(|krate| { + let krate = DefId { + krate: *krate, + index: CRATE_DEF_INDEX, + }; + let mut items = self.tcx.item_children(krate); + let mut path_it = path.iter().skip(1).peekable(); + + while let Some(segment) = path_it.next() { + for item in mem::replace(&mut items, Default::default()).iter() { + if item.ident.name == *segment { + if path_it.peek().is_none() { + return Some(ty::Instance::mono(self.tcx.tcx, item.def.def_id())); + } + + items = self.tcx.item_children(item.def.def_id()); + break; + } + } + } + None + }) + .ok_or_else(|| { + let path = path.iter().map(|&s| s.to_owned()).collect(); + EvalErrorKind::PathNotFound(path).into() + }) + } +} diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 19c4f04f4826..9e209af98e3a 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -7,7 +7,7 @@ use rustc_mir::interpret::{EvalContext, PlaceTy, OpTy}; use super::{ Value, Scalar, ScalarMaybeUndef, - FalibleScalarExt, OperatorEvalContextExt + ScalarExt, OperatorEvalContextExt }; pub trait EvalContextExt<'tcx> { diff --git a/src/lib.rs b/src/lib.rs index 0bebe40d529a..ec2bc4a69f4e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,7 +43,8 @@ use operator::EvalContextExt as OperatorEvalContextExt; use intrinsic::EvalContextExt as IntrinsicEvalContextExt; use tls::{EvalContextExt as TlsEvalContextExt, TlsData}; use range_map::RangeMap; -use helpers::FalibleScalarExt; +#[allow(unused_imports)] // FIXME rustc bug https://github.com/rust-lang/rust/issues/53682 +use helpers::{ScalarExt, EvalContextExt as HelpersEvalContextExt}; use mono_hash_map::MonoHashMap; pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( From 0b6e3494177d436c64bb80e71662ea54ad2aeaa9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Oct 2018 10:07:17 +0200 Subject: [PATCH 0275/5092] automalically use start-fn if we have all the MIR --- .travis.yml | 4 ++-- src/bin/miri-rustc-tests.rs | 4 ++-- src/bin/miri.rs | 25 +++---------------------- src/lib.rs | 14 +++++++++----- tests/compiletest.rs | 3 --- 5 files changed, 16 insertions(+), 34 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9b4f75ab29cf..d2315c7e9538 100644 --- a/.travis.yml +++ b/.travis.yml @@ -50,9 +50,9 @@ script: # test `cargo miri` cd cargo-miri-test && if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - cargo miri -q -- -Zmiri-start-fn + cargo miri -q else - cargo miri -q -- -Zmiri-start-fn >stdout.real 2>stderr.real && + cargo miri -q >stdout.real 2>stderr.real && cat stdout.real stderr.real && # Test `cargo miri` output. Not on mac because output redirecting doesn't # work. There is no error. It just stops CI. diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 73a8d19c309b..fb3b231d41ce 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -95,7 +95,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { if i.attrs.iter().any(|attr| attr.name() == "test") { let did = self.0.hir.body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); - miri::eval_main(self.0, did, None, /*validate*/true); + miri::eval_main(self.0, did, /*validate*/true); self.1.session.abort_if_errors(); } } @@ -106,7 +106,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(tcx, state)); } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { let entry_def_id = tcx.hir.local_def_id(entry_node_id); - miri::eval_main(tcx, entry_def_id, None, /*validate*/true); + miri::eval_main(tcx, entry_def_id, /*validate*/true); state.session.abort_if_errors(); } else { diff --git a/src/bin/miri.rs b/src/bin/miri.rs index d7207da0b3c0..d4494a838852 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -26,11 +26,6 @@ use std::path::PathBuf; struct MiriCompilerCalls { default: Box, - /// Whether to begin interpretation at the start_fn lang item or not. - /// - /// If false, the interpretation begins at the `main` function. - start_fn: bool, - /// Whether to enforce the validity invariant. validate: bool, } @@ -90,10 +85,9 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { let this = *self; let mut control = this.default.build_controller(sess, matches); control.after_hir_lowering.callback = Box::new(after_hir_lowering); - let start_fn = this.start_fn; let validate = this.validate; control.after_analysis.callback = - Box::new(move |state| after_analysis(state, start_fn, validate)); + Box::new(move |state| after_analysis(state, validate)); control.after_analysis.stop = Compilation::Stop; control } @@ -109,7 +103,6 @@ fn after_hir_lowering(state: &mut CompileState) { fn after_analysis<'a, 'tcx>( state: &mut CompileState<'a, 'tcx>, - use_start_fn: bool, validate: bool, ) { state.session.abort_if_errors(); @@ -134,7 +127,7 @@ fn after_analysis<'a, 'tcx>( "running test: {}", self.tcx.def_path_debug_str(did), ); - miri::eval_main(self.tcx, did, None, self.validate); + miri::eval_main(self.tcx, did, self.validate); self.state.session.abort_if_errors(); } } @@ -147,13 +140,7 @@ fn after_analysis<'a, 'tcx>( ); } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { let entry_def_id = tcx.hir.local_def_id(entry_node_id); - // Use start_fn lang item if we have -Zmiri-start-fn set - let start_wrapper = if use_start_fn { - Some(tcx.lang_items().start_fn().unwrap()) - } else { - None - }; - miri::eval_main(tcx, entry_def_id, start_wrapper, validate); + miri::eval_main(tcx, entry_def_id, validate); state.session.abort_if_errors(); } else { @@ -231,14 +218,9 @@ fn main() { args.push(find_sysroot()); } - let mut start_fn = false; let mut validate = true; args.retain(|arg| { match arg.as_str() { - "-Zmiri-start-fn" => { - start_fn = true; - false - }, "-Zmiri-disable-validation" => { validate = false; false @@ -251,7 +233,6 @@ fn main() { let result = rustc_driver::run(move || { rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls { default: Box::new(RustcDefaultCalls), - start_fn, validate, }), None, None) }); diff --git a/src/lib.rs b/src/lib.rs index ec2bc4a69f4e..eba88a88487e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,7 +50,6 @@ use mono_hash_map::MonoHashMap; pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, - start_wrapper: Option, validate: bool, ) -> EvalResult<'tcx, EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>> { let mut ecx = EvalContext::new( @@ -70,8 +69,14 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( )); } - if let Some(start_id) = start_wrapper { - let main_ret_ty = ecx.tcx.fn_sig(main_id).output(); + let libstd_has_mir = { + let rustc_panic = ecx.resolve_path(&["std", "panicking", "rust_panic"])?; + ecx.load_mir(rustc_panic.def).is_ok() + }; + + if libstd_has_mir { + let start_id = tcx.lang_items().start_fn().unwrap(); + let main_ret_ty = tcx.fn_sig(main_id).output(); let main_ret_ty = main_ret_ty.no_late_bound_regions().unwrap(); let start_instance = ty::Instance::resolve( ecx.tcx.tcx, @@ -146,10 +151,9 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( pub fn eval_main<'a, 'tcx: 'a>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, - start_wrapper: Option, validate: bool, ) { - let mut ecx = create_ecx(tcx, main_id, start_wrapper, validate).expect("Couldn't create ecx"); + let mut ecx = create_ecx(tcx, main_id, validate).expect("Couldn't create ecx"); let res: EvalResult = (|| { ecx.run()?; diff --git a/tests/compiletest.rs b/tests/compiletest.rs index b240fb31d222..fa57df94dabc 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -100,9 +100,6 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: let mut flags = Vec::new(); flags.push(format!("--sysroot {}", sysroot.display())); flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs - if have_fullmir() { - flags.push("-Zmiri-start-fn".to_owned()); - } if opt { // FIXME: Using level 1 (instead of 3) for now, as the optimizer is pretty broken // and crashes... From 069b661a10773bf5f9753ccf556fd101f6b492d6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Oct 2018 10:09:53 +0200 Subject: [PATCH 0276/5092] typo --- src/fn_call.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index ce5b17e7b577..0a46c6a1fdb4 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -661,7 +661,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' "std::io::_print" | "std::io::_eprint" => { warn!( - "Ignoring output. To run programs that print, make sure you have a libstd with full MIR." + "Ignoring output. To run programs that prints, make sure you have a libstd with full MIR." ); } "std::thread::Builder::new" => { From 8134918390d29d591c0078e3ecf71cdeb20687b5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Oct 2018 11:50:17 +0200 Subject: [PATCH 0277/5092] don't use NOTE in tests --- tests/compile-fail-fullmir/reallocate-change-alloc.rs | 3 +-- tests/compile-fail/alignment.rs | 3 +-- tests/compile-fail/assume.rs | 3 +-- tests/compile-fail/bitop-beyond-alignment.rs | 5 ++--- tests/compile-fail/cast_box_int_to_fn_ptr.rs | 3 +-- tests/compile-fail/cast_int_to_fn_ptr.rs | 3 +-- tests/compile-fail/dangling_pointer_deref.rs | 3 +-- tests/compile-fail/div-by-zero-2.rs | 3 +-- tests/compile-fail/execute_memory.rs | 3 +-- tests/compile-fail/fn_ptr_offset.rs | 3 +-- tests/compile-fail/modifying_constants.rs | 3 +-- tests/compile-fail/never_say_never.rs | 3 +-- tests/compile-fail/never_transmute_void.rs | 3 +-- tests/compile-fail/out_of_bounds_read.rs | 3 +-- tests/compile-fail/out_of_bounds_read2.rs | 3 +-- tests/compile-fail/overflowing-lsh-neg.rs | 3 +-- tests/compile-fail/overflowing-rsh-2.rs | 3 +-- tests/compile-fail/overflowing-rsh.rs | 3 +-- ...verwriting_part_of_relocation_makes_the_rest_undefined.rs | 3 +-- tests/compile-fail/pointer_byte_read_2.rs | 3 +-- .../pointers_to_different_allocations_are_unorderable.rs | 3 +-- tests/compile-fail/ptr_int_cast.rs | 3 +-- tests/compile-fail/reading_half_a_pointer.rs | 3 +-- tests/compile-fail/reference_to_packed.rs | 3 +-- tests/compile-fail/static_memory_modification.rs | 3 +-- tests/compile-fail/static_memory_modification2.rs | 3 +-- tests/compile-fail/static_memory_modification3.rs | 3 +-- tests/compile-fail/transmute-pair-undef.rs | 3 +-- tests/compile-fail/transmute_fat.rs | 3 +-- tests/compile-fail/transmute_fat2.rs | 3 +-- tests/compile-fail/unaligned_ptr_cast.rs | 3 +-- tests/compile-fail/unaligned_ptr_cast2.rs | 3 +-- tests/compile-fail/unaligned_ptr_cast_zst.rs | 3 +-- tests/compile-fail/undefined_byte_read.rs | 3 +-- tests/compile-fail/wild_pointer_deref.rs | 3 +-- tests/compile-fail/zst.rs | 3 +-- 36 files changed, 37 insertions(+), 73 deletions(-) diff --git a/tests/compile-fail-fullmir/reallocate-change-alloc.rs b/tests/compile-fail-fullmir/reallocate-change-alloc.rs index c73f86bc1721..1e2178811ea3 100644 --- a/tests/compile-fail-fullmir/reallocate-change-alloc.rs +++ b/tests/compile-fail-fullmir/reallocate-change-alloc.rs @@ -9,7 +9,6 @@ fn main() { unsafe { let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1).unwrap(); - let _z = *(x.as_ptr() as *mut u8); //~ ERROR constant evaluation error - //~^ NOTE dangling pointer was dereferenced + let _z = *(x.as_ptr() as *mut u8); //~ ERROR dangling pointer was dereferenced } } diff --git a/tests/compile-fail/alignment.rs b/tests/compile-fail/alignment.rs index 71161f5d6da0..4faaa359df62 100644 --- a/tests/compile-fail/alignment.rs +++ b/tests/compile-fail/alignment.rs @@ -5,8 +5,7 @@ fn main() { let x_ptr: *mut u8 = &mut x[0]; let y_ptr = x_ptr as *mut u64; unsafe { - *y_ptr = 42; //~ ERROR constant evaluation error - //~^ NOTE tried to access memory with alignment 1, but alignment + *y_ptr = 42; //~ ERROR tried to access memory with alignment 1, but alignment } panic!("unreachable in miri"); } diff --git a/tests/compile-fail/assume.rs b/tests/compile-fail/assume.rs index d9eec480cd0c..3026124e1f9a 100644 --- a/tests/compile-fail/assume.rs +++ b/tests/compile-fail/assume.rs @@ -5,7 +5,6 @@ fn main() { unsafe { std::intrinsics::assume(x < 10); std::intrinsics::assume(x > 1); - std::intrinsics::assume(x > 42); //~ ERROR constant evaluation error - //~^ NOTE `assume` argument was false + std::intrinsics::assume(x > 42); //~ `assume` argument was false } } diff --git a/tests/compile-fail/bitop-beyond-alignment.rs b/tests/compile-fail/bitop-beyond-alignment.rs index c8cbc9a91841..a30c054ab5d0 100644 --- a/tests/compile-fail/bitop-beyond-alignment.rs +++ b/tests/compile-fail/bitop-beyond-alignment.rs @@ -28,11 +28,10 @@ fn mk_rec() -> Rec { fn is_u64_aligned(u: &Tag) -> bool { let p: usize = unsafe { mem::transmute(u) }; let u64_align = std::mem::align_of::(); - return (p & (u64_align + 1)) == 0; //~ ERROR constant evaluation error - //~^ NOTE a raw memory access tried to access part of a pointer value as raw bytes + return (p & (u64_align + 1)) == 0; //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes } pub fn main() { let x = mk_rec(); - assert!(is_u64_aligned(&x.t)); //~ NOTE inside call to `is_u64_aligned + assert!(is_u64_aligned(&x.t)); } diff --git a/tests/compile-fail/cast_box_int_to_fn_ptr.rs b/tests/compile-fail/cast_box_int_to_fn_ptr.rs index cbf370e02363..c3b1fa595888 100644 --- a/tests/compile-fail/cast_box_int_to_fn_ptr.rs +++ b/tests/compile-fail/cast_box_int_to_fn_ptr.rs @@ -7,6 +7,5 @@ fn main() { std::mem::transmute::<&usize, &fn(i32)>(&b) }; - (*g)(42) //~ ERROR constant evaluation error - //~^ NOTE a memory access tried to interpret some bytes as a pointer + (*g)(42) //~ ERROR a memory access tried to interpret some bytes as a pointer } diff --git a/tests/compile-fail/cast_int_to_fn_ptr.rs b/tests/compile-fail/cast_int_to_fn_ptr.rs index 2a08d9f1f9f8..1971ce1557e7 100644 --- a/tests/compile-fail/cast_int_to_fn_ptr.rs +++ b/tests/compile-fail/cast_int_to_fn_ptr.rs @@ -6,6 +6,5 @@ fn main() { std::mem::transmute::(42) }; - g(42) //~ ERROR constant evaluation error - //~^ NOTE a memory access tried to interpret some bytes as a pointer + g(42) //~ ERROR a memory access tried to interpret some bytes as a pointer } diff --git a/tests/compile-fail/dangling_pointer_deref.rs b/tests/compile-fail/dangling_pointer_deref.rs index 434f5c780b46..e80720773057 100644 --- a/tests/compile-fail/dangling_pointer_deref.rs +++ b/tests/compile-fail/dangling_pointer_deref.rs @@ -3,7 +3,6 @@ fn main() { let b = Box::new(42); &*b as *const i32 }; - let x = unsafe { *p }; //~ ERROR constant evaluation error - //~^ NOTE dangling pointer was dereferenced + let x = unsafe { *p }; //~ ERROR dangling pointer was dereferenced panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/div-by-zero-2.rs b/tests/compile-fail/div-by-zero-2.rs index 94145c2cf32f..181a41ce3b23 100644 --- a/tests/compile-fail/div-by-zero-2.rs +++ b/tests/compile-fail/div-by-zero-2.rs @@ -11,6 +11,5 @@ #![allow(const_err)] fn main() { - let _n = 1 / 0; //~ ERROR constant evaluation error - //~^ NOTE attempt to divide by zero + let _n = 1 / 0; //~ ERROR attempt to divide by zero } diff --git a/tests/compile-fail/execute_memory.rs b/tests/compile-fail/execute_memory.rs index 2f8fea38d8f9..d859e9072e32 100644 --- a/tests/compile-fail/execute_memory.rs +++ b/tests/compile-fail/execute_memory.rs @@ -7,7 +7,6 @@ fn main() { let x = box 42; unsafe { let f = std::mem::transmute::, fn()>(x); - f() //~ ERROR constant evaluation error - //~^ NOTE tried to treat a memory pointer as a function pointer + f() //~ ERROR tried to treat a memory pointer as a function pointer } } diff --git a/tests/compile-fail/fn_ptr_offset.rs b/tests/compile-fail/fn_ptr_offset.rs index e6d1da1e0736..cccb21790d65 100644 --- a/tests/compile-fail/fn_ptr_offset.rs +++ b/tests/compile-fail/fn_ptr_offset.rs @@ -10,6 +10,5 @@ fn main() { let y : *mut u8 = unsafe { mem::transmute(x) }; let y = y.wrapping_offset(1); let x : fn() = unsafe { mem::transmute(y) }; - x(); //~ ERROR constant evaluation error - //~^ NOTE tried to use a function pointer after offsetting it + x(); //~ ERROR tried to use a function pointer after offsetting it } diff --git a/tests/compile-fail/modifying_constants.rs b/tests/compile-fail/modifying_constants.rs index ba46651f58ee..27c74e8dc87e 100644 --- a/tests/compile-fail/modifying_constants.rs +++ b/tests/compile-fail/modifying_constants.rs @@ -2,7 +2,6 @@ fn main() { let x = &1; // the `&1` is promoted to a constant, but it used to be that only the pointer is marked static, not the pointee let y = unsafe { &mut *(x as *const i32 as *mut i32) }; - *y = 42; //~ ERROR constant evaluation error - //~^ NOTE tried to modify constant memory + *y = 42; //~ ERROR tried to modify constant memory assert_eq!(*x, 42); } diff --git a/tests/compile-fail/never_say_never.rs b/tests/compile-fail/never_say_never.rs index 9821723deb3b..634488489b53 100644 --- a/tests/compile-fail/never_say_never.rs +++ b/tests/compile-fail/never_say_never.rs @@ -7,8 +7,7 @@ fn main() { let y = &5; let x: ! = unsafe { - *(y as *const _ as *const !) //~ ERROR constant evaluation error - //~^ NOTE entered unreachable code + *(y as *const _ as *const !) //~ ERROR entered unreachable code }; f(x) } diff --git a/tests/compile-fail/never_transmute_void.rs b/tests/compile-fail/never_transmute_void.rs index 11fc0f068de0..5620b6559cfd 100644 --- a/tests/compile-fail/never_transmute_void.rs +++ b/tests/compile-fail/never_transmute_void.rs @@ -8,8 +8,7 @@ enum Void {} fn f(v: Void) -> ! { - match v {} //~ ERROR constant evaluation error - //~^ NOTE entered unreachable code + match v {} //~ ERROR entered unreachable code } fn main() { diff --git a/tests/compile-fail/out_of_bounds_read.rs b/tests/compile-fail/out_of_bounds_read.rs index 3ccdb365feeb..1ab2d9714779 100644 --- a/tests/compile-fail/out_of_bounds_read.rs +++ b/tests/compile-fail/out_of_bounds_read.rs @@ -1,6 +1,5 @@ fn main() { let v: Vec = vec![1, 2]; - let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR constant evaluation error - //~^ NOTE which has size 2 + let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR outside bounds of allocation panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/out_of_bounds_read2.rs b/tests/compile-fail/out_of_bounds_read2.rs index e8bcf4558401..1ab2d9714779 100644 --- a/tests/compile-fail/out_of_bounds_read2.rs +++ b/tests/compile-fail/out_of_bounds_read2.rs @@ -1,6 +1,5 @@ fn main() { let v: Vec = vec![1, 2]; - let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR constant evaluation error - //~^ NOTE outside bounds of allocation + let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR outside bounds of allocation panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/overflowing-lsh-neg.rs b/tests/compile-fail/overflowing-lsh-neg.rs index 825a82226634..8c70c9c7df7d 100644 --- a/tests/compile-fail/overflowing-lsh-neg.rs +++ b/tests/compile-fail/overflowing-lsh-neg.rs @@ -12,6 +12,5 @@ #![allow(const_err)] fn main() { - let _n = 2i64 << -1; //~ ERROR constant evaluation error - //~^ NOTE attempt to shift left with overflow + let _n = 2i64 << -1; //~ ERROR attempt to shift left with overflow } diff --git a/tests/compile-fail/overflowing-rsh-2.rs b/tests/compile-fail/overflowing-rsh-2.rs index cf107a76ae29..7b7486343c33 100644 --- a/tests/compile-fail/overflowing-rsh-2.rs +++ b/tests/compile-fail/overflowing-rsh-2.rs @@ -12,6 +12,5 @@ fn main() { // Make sure we catch overflows that would be hidden by first casting the RHS to u32 - let _n = 1i64 >> (u32::max_value() as i64 + 1); //~ ERROR constant evaluation error - //~^ NOTE attempt to shift right with overflow + let _n = 1i64 >> (u32::max_value() as i64 + 1); //~ ERROR attempt to shift right with overflow } diff --git a/tests/compile-fail/overflowing-rsh.rs b/tests/compile-fail/overflowing-rsh.rs index ea53d7e73092..355cbd869888 100644 --- a/tests/compile-fail/overflowing-rsh.rs +++ b/tests/compile-fail/overflowing-rsh.rs @@ -11,6 +11,5 @@ #![allow(exceeding_bitshifts)] fn main() { - let _n = 1i64 >> 64; //~ ERROR constant evaluation error - //~^ NOTE attempt to shift right with overflow + let _n = 1i64 >> 64; //~ ERROR attempt to shift right with overflow } diff --git a/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs b/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs index 7c38c0574698..5c0d5b463d51 100644 --- a/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs +++ b/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs @@ -6,7 +6,6 @@ fn main() { // "attempted to interpret some raw bytes as a pointer address" instead of // "attempted to read undefined bytes" } - let x = *p; //~ ERROR constant evaluation error - //~^ NOTE attempted to read undefined bytes + let x = *p; //~ ERROR attempted to read undefined bytes panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/pointer_byte_read_2.rs b/tests/compile-fail/pointer_byte_read_2.rs index c8a1a2e10f50..5df8c4782c7f 100644 --- a/tests/compile-fail/pointer_byte_read_2.rs +++ b/tests/compile-fail/pointer_byte_read_2.rs @@ -3,6 +3,5 @@ fn main() { let y = &x; let z = &y as *const &i32 as *const u8; // the deref fails, because we are reading only a part of the pointer - let _ = unsafe { *z }; //~ ERROR constant evaluation error - //~^ NOTE tried to access part of a pointer value as raw bytes + let _ = unsafe { *z }; //~ ERROR tried to access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs b/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs index 89cf357e201c..124f84de5bf4 100644 --- a/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs +++ b/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs @@ -1,8 +1,7 @@ fn main() { let x: *const u8 = &1; let y: *const u8 = &2; - if x < y { //~ ERROR constant evaluation error - //~^ NOTE attempted to do invalid arithmetic on pointers + if x < y { //~ ERROR attempted to do invalid arithmetic on pointers unreachable!() } } diff --git a/tests/compile-fail/ptr_int_cast.rs b/tests/compile-fail/ptr_int_cast.rs index 11243921bfd4..576f0c333d18 100644 --- a/tests/compile-fail/ptr_int_cast.rs +++ b/tests/compile-fail/ptr_int_cast.rs @@ -2,8 +2,7 @@ fn main() { let x = &1; // Casting down to u8 and back up to a pointer loses too much precision; this must not work. let x = x as *const i32; - let x = x as u8; //~ ERROR constant evaluation error - //~^ NOTE a raw memory access tried to access part of a pointer value as raw bytes + let x = x as u8; //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes let x = x as *const i32; let _ = unsafe { *x }; } diff --git a/tests/compile-fail/reading_half_a_pointer.rs b/tests/compile-fail/reading_half_a_pointer.rs index 3ea693a3f0fb..049dfca340ed 100644 --- a/tests/compile-fail/reading_half_a_pointer.rs +++ b/tests/compile-fail/reading_half_a_pointer.rs @@ -24,7 +24,6 @@ fn main() { // starts 1 byte to the right, so using it would actually be wrong! let d_alias = &mut w.data as *mut _ as *mut *const u8; unsafe { - let _x = *d_alias; //~ ERROR constant evaluation error - //~^ NOTE tried to access part of a pointer value as raw bytes + let _x = *d_alias; //~ ERROR tried to access part of a pointer value as raw bytes } } diff --git a/tests/compile-fail/reference_to_packed.rs b/tests/compile-fail/reference_to_packed.rs index d18f314c8aaa..14a2afc33f7f 100644 --- a/tests/compile-fail/reference_to_packed.rs +++ b/tests/compile-fail/reference_to_packed.rs @@ -15,6 +15,5 @@ fn main() { y: 99, }; let p = unsafe { &foo.x }; - let i = *p; //~ ERROR constant evaluation error - //~^ NOTE tried to access memory with alignment 1, but alignment 4 is required + let i = *p; //~ ERROR tried to access memory with alignment 1, but alignment 4 is required } diff --git a/tests/compile-fail/static_memory_modification.rs b/tests/compile-fail/static_memory_modification.rs index 9e39c2c01c2b..304ab6c6b740 100644 --- a/tests/compile-fail/static_memory_modification.rs +++ b/tests/compile-fail/static_memory_modification.rs @@ -3,8 +3,7 @@ static X: usize = 5; #[allow(mutable_transmutes)] fn main() { unsafe { - *std::mem::transmute::<&usize, &mut usize>(&X) = 6; //~ ERROR constant evaluation error - //~^ NOTE tried to modify constant memory + *std::mem::transmute::<&usize, &mut usize>(&X) = 6; //~ ERROR tried to modify constant memory assert_eq!(X, 6); } } diff --git a/tests/compile-fail/static_memory_modification2.rs b/tests/compile-fail/static_memory_modification2.rs index 2f702f09c804..01c3b9bb2d8d 100644 --- a/tests/compile-fail/static_memory_modification2.rs +++ b/tests/compile-fail/static_memory_modification2.rs @@ -7,7 +7,6 @@ use std::mem::transmute; fn main() { unsafe { let s = "this is a test"; - transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; //~ ERROR constant evaluation error - //~^ NOTE tried to modify constant memory + transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; //~ ERROR tried to modify constant memory } } diff --git a/tests/compile-fail/static_memory_modification3.rs b/tests/compile-fail/static_memory_modification3.rs index 37d8bfe02ceb..ff09aad1bd56 100644 --- a/tests/compile-fail/static_memory_modification3.rs +++ b/tests/compile-fail/static_memory_modification3.rs @@ -4,7 +4,6 @@ use std::mem::transmute; fn main() { unsafe { let bs = b"this is a test"; - transmute::<&[u8], &mut [u8]>(bs)[4] = 42; //~ ERROR constant evaluation error - //~^ NOTE tried to modify constant memory + transmute::<&[u8], &mut [u8]>(bs)[4] = 42; //~ ERROR tried to modify constant memory } } diff --git a/tests/compile-fail/transmute-pair-undef.rs b/tests/compile-fail/transmute-pair-undef.rs index 9509bb60e8b1..acc6098af7ee 100644 --- a/tests/compile-fail/transmute-pair-undef.rs +++ b/tests/compile-fail/transmute-pair-undef.rs @@ -16,6 +16,5 @@ fn main() { assert_eq!(byte, 0); } let v = unsafe { *z.offset(first_undef) }; - if v == 0 {} //~ ERROR constant evaluation error - //~^ NOTE attempted to read undefined bytes + if v == 0 {} //~ ERROR attempted to read undefined bytes } diff --git a/tests/compile-fail/transmute_fat.rs b/tests/compile-fail/transmute_fat.rs index 3e3bf51c3f27..e1f916910d73 100644 --- a/tests/compile-fail/transmute_fat.rs +++ b/tests/compile-fail/transmute_fat.rs @@ -10,6 +10,5 @@ fn main() { let bad = unsafe { std::mem::transmute::<&[u8], [u8; 8]>(&[1u8]) }; - let _ = bad[0] + bad[bad.len()-1]; //~ ERROR constant evaluation error - //~^ NOTE a raw memory access tried to access part of a pointer value as raw bytes + let _ = bad[0] + bad[bad.len()-1]; //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/transmute_fat2.rs b/tests/compile-fail/transmute_fat2.rs index e9e21a84294d..3121a139d920 100644 --- a/tests/compile-fail/transmute_fat2.rs +++ b/tests/compile-fail/transmute_fat2.rs @@ -7,6 +7,5 @@ fn main() { let bad = unsafe { std::mem::transmute::(42) }; - bad[0]; //~ ERROR constant evaluation error - //~^ NOTE index out of bounds: the len is 0 but the index is 0 + bad[0]; //~ ERROR index out of bounds: the len is 0 but the index is 0 } diff --git a/tests/compile-fail/unaligned_ptr_cast.rs b/tests/compile-fail/unaligned_ptr_cast.rs index f91def30d120..88285dc69f31 100644 --- a/tests/compile-fail/unaligned_ptr_cast.rs +++ b/tests/compile-fail/unaligned_ptr_cast.rs @@ -2,6 +2,5 @@ fn main() { let x = &2u16; let x = x as *const _ as *const u32; // This must fail because alignment is violated - let _x = unsafe { *x }; //~ ERROR constant evaluation error - //~^ NOTE tried to access memory with alignment 2, but alignment 4 is required + let _x = unsafe { *x }; //~ ERROR tried to access memory with alignment 2, but alignment 4 is required } diff --git a/tests/compile-fail/unaligned_ptr_cast2.rs b/tests/compile-fail/unaligned_ptr_cast2.rs index f87dab76ba30..7541079def2c 100644 --- a/tests/compile-fail/unaligned_ptr_cast2.rs +++ b/tests/compile-fail/unaligned_ptr_cast2.rs @@ -3,6 +3,5 @@ fn main() { let x = x as *const _ as *const *const u8; // This must fail because alignment is violated. Test specifically for loading pointers, which have special code // in miri's memory. - let _x = unsafe { *x }; //~ ERROR constant evaluation error - //~^ NOTE tried to access memory with alignment 2, but alignment + let _x = unsafe { *x }; //~ ERROR tried to access memory with alignment 2, but alignment } diff --git a/tests/compile-fail/unaligned_ptr_cast_zst.rs b/tests/compile-fail/unaligned_ptr_cast_zst.rs index 45016473c975..1b9b55c6be1f 100644 --- a/tests/compile-fail/unaligned_ptr_cast_zst.rs +++ b/tests/compile-fail/unaligned_ptr_cast_zst.rs @@ -2,6 +2,5 @@ fn main() { let x = &2u16; let x = x as *const _ as *const [u32; 0]; // This must fail because alignment is violated. Test specifically for loading ZST. - let _x = unsafe { *x }; //~ ERROR constant evaluation error - //~^ NOTE tried to access memory with alignment 2, but alignment 4 is required + let _x = unsafe { *x }; //~ ERROR tried to access memory with alignment 2, but alignment 4 is required } diff --git a/tests/compile-fail/undefined_byte_read.rs b/tests/compile-fail/undefined_byte_read.rs index 24718bce7db9..1f092936148e 100644 --- a/tests/compile-fail/undefined_byte_read.rs +++ b/tests/compile-fail/undefined_byte_read.rs @@ -4,7 +4,6 @@ fn main() { let v: Vec = Vec::with_capacity(10); let undef = unsafe { *v.get_unchecked(5) }; - let x = undef + 1; //~ ERROR: error - //~^ NOTE attempted to read undefined bytes + let x = undef + 1; //~ ERROR attempted to read undefined bytes panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/wild_pointer_deref.rs b/tests/compile-fail/wild_pointer_deref.rs index 4096cfb93e72..8eec9737546b 100644 --- a/tests/compile-fail/wild_pointer_deref.rs +++ b/tests/compile-fail/wild_pointer_deref.rs @@ -1,6 +1,5 @@ fn main() { let p = 44 as *const i32; - let x = unsafe { *p }; //~ ERROR constant evaluation error - //~^ NOTE a memory access tried to interpret some bytes as a pointer + let x = unsafe { *p }; //~ ERROR a memory access tried to interpret some bytes as a pointer panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/zst.rs b/tests/compile-fail/zst.rs index efb2dafd36fc..2b179dcc8a45 100644 --- a/tests/compile-fail/zst.rs +++ b/tests/compile-fail/zst.rs @@ -1,5 +1,4 @@ fn main() { let x = &() as *const () as *const i32; - let _ = unsafe { *x }; //~ ERROR constant evaluation error - //~^ NOTE tried to access memory with alignment 1, but alignment 4 is required + let _ = unsafe { *x }; //~ ERROR tried to access memory with alignment 1, but alignment 4 is required } From bbb1d80703f272a5592ceeb3832a489776512251 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Oct 2018 01:31:46 +0200 Subject: [PATCH 0278/5092] disable env var test on macOS, win --- tests/run-pass/env.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/run-pass/env.rs b/tests/run-pass/env.rs index c0bf883daf9c..8c655b953f82 100644 --- a/tests/run-pass/env.rs +++ b/tests/run-pass/env.rs @@ -1,3 +1,6 @@ +//ignore-windows: env var emulation not implemented on Windows +//ignore-macos: env var emulation not implemented on macOS + use std::env; fn main() { From 41eabb658e7a27ba77500f36341a108804c8e0d0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Oct 2018 08:41:06 +0200 Subject: [PATCH 0279/5092] bump Rust version --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index abbc6c90452a..cc0787f877e6 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-10-14 +nightly-2018-10-22 From fdb3022a1195965acf26746bf6d4c8dcae5608af Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Oct 2018 08:41:48 +0200 Subject: [PATCH 0280/5092] env vars are only available with full MIR --- tests/{run-pass => run-pass-fullmir}/env.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/{run-pass => run-pass-fullmir}/env.rs (100%) diff --git a/tests/run-pass/env.rs b/tests/run-pass-fullmir/env.rs similarity index 100% rename from tests/run-pass/env.rs rename to tests/run-pass-fullmir/env.rs From 0b22a1c9d950f741db8f144a61891166df69dbbd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Oct 2018 09:04:32 +0200 Subject: [PATCH 0281/5092] env vars should work on macOS --- tests/run-pass-fullmir/env.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/run-pass-fullmir/env.rs b/tests/run-pass-fullmir/env.rs index 8c655b953f82..0ca63e148fdb 100644 --- a/tests/run-pass-fullmir/env.rs +++ b/tests/run-pass-fullmir/env.rs @@ -1,5 +1,4 @@ //ignore-windows: env var emulation not implemented on Windows -//ignore-macos: env var emulation not implemented on macOS use std::env; From 1a7fb7ec3ce5be7205fc1b3fb40642792985d501 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Oct 2018 12:51:30 +0200 Subject: [PATCH 0282/5092] expand comment about incomplete support for interior mutability --- src/stacked_borrows.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 19d5c723d403..077deceecf2a 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -264,11 +264,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' borrow_kind: Option, ) -> EvalResult<'tcx, Borrow> { let time = self.machine.stacked_borrows.increment_clock(); - // FIXME This does not do enough checking when only part of the data has - // interior mutability. let new_bor = match borrow_kind { Some(mir::BorrowKind::Mut { .. }) => Borrow::Mut(Mut::Uniq(time)), Some(_) => + // FIXME This does not do enough checking when only part of the data has + // interior mutability. When the type is `(i32, Cell)`, we want the + // first field to be frozen but not the second. if self.type_is_freeze(pointee_ty) { Borrow::Frz(time) } else { From 1ae1b9bfeab22038a6c4674be8adb9b0606dea16 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Oct 2018 16:59:08 +0200 Subject: [PATCH 0283/5092] adapt to rustc API changes and factor out computing the tag for ty+mutbl --- src/lib.rs | 12 ++++--- src/stacked_borrows.rs | 72 +++++++++++++++++++++++++++--------------- 2 files changed, 54 insertions(+), 30 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ed23eef3f550..7841a4d3a2c0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,7 @@ use std::borrow::Cow; use rustc::ty::{self, Ty, TyCtxt, query::TyCtxtAt}; use rustc::ty::layout::{TyLayout, LayoutOf, Size}; -use rustc::hir::def_id::DefId; +use rustc::hir::{self, def_id::DefId}; use rustc::mir; use syntax::attr; @@ -446,13 +446,13 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { ptr: Pointer, pointee_ty: Ty<'tcx>, pointee_size: Size, - borrow_kind: Option, + mutability: Option, ) -> EvalResult<'tcx, Borrow> { if !ecx.machine.validate { // No tracking Ok(Borrow::default()) } else { - ecx.tag_reference(ptr, pointee_ty, pointee_size, borrow_kind) + ecx.tag_reference(ptr, pointee_ty, pointee_size, mutability) } } @@ -460,13 +460,15 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn tag_dereference( ecx: &EvalContext<'a, 'mir, 'tcx, Self>, ptr: Pointer, - ptr_ty: Ty<'tcx>, + pointee_ty: Ty<'tcx>, + pointee_size: Size, + mutability: Option, ) -> EvalResult<'tcx, Borrow> { if !ecx.machine.validate { // No tracking Ok(Borrow::default()) } else { - ecx.tag_dereference(ptr, ptr_ty) + ecx.tag_dereference(ptr, pointee_ty, pointee_size, mutability) } } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 077deceecf2a..169c8abe2b08 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -1,7 +1,8 @@ -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; -use rustc::ty::{Ty, layout::Size}; +use rustc::ty::{self, Ty, layout::Size}; use rustc::mir; +use rustc::hir; use super::{ MemoryAccess, RangeMap, EvalResult, @@ -67,12 +68,12 @@ impl Default for Borrow { /// Extra global machine state #[derive(Clone, Debug)] pub struct State { - clock: Timestamp + clock: Cell } impl State { pub fn new() -> State { - State { clock: 0 } + State { clock: Cell::new(0) } } } @@ -180,9 +181,10 @@ impl<'tcx> Stack { } impl State { - fn increment_clock(&mut self) -> Timestamp { - self.clock += 1; - self.clock + fn increment_clock(&self) -> Timestamp { + let val = self.clock.get(); + self.clock.set(val+1); + val } } @@ -238,47 +240,64 @@ impl<'tcx> Stacks { } } -/// Machine hooks pub trait EvalContextExt<'tcx> { fn tag_reference( &mut self, ptr: Pointer, pointee_ty: Ty<'tcx>, size: Size, - borrow_kind: Option, + mutability: Option, ) -> EvalResult<'tcx, Borrow>; fn tag_dereference( &self, ptr: Pointer, - ptr_ty: Ty<'tcx>, + pointee_ty: Ty<'tcx>, + size: Size, + mutability: Option, ) -> EvalResult<'tcx, Borrow>; + + fn tag_for_pointee( + &self, + pointee_ty: Ty<'tcx>, + borrow_kind: Option, + ) -> Borrow; } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { - fn tag_reference( - &mut self, - ptr: Pointer, + fn tag_for_pointee( + &self, pointee_ty: Ty<'tcx>, - size: Size, - borrow_kind: Option, - ) -> EvalResult<'tcx, Borrow> { + borrow_kind: Option, + ) -> Borrow { let time = self.machine.stacked_borrows.increment_clock(); - let new_bor = match borrow_kind { - Some(mir::BorrowKind::Mut { .. }) => Borrow::Mut(Mut::Uniq(time)), - Some(_) => + match borrow_kind { + Some(hir::MutMutable) => Borrow::Mut(Mut::Uniq(time)), + Some(hir::MutImmutable) => // FIXME This does not do enough checking when only part of the data has // interior mutability. When the type is `(i32, Cell)`, we want the // first field to be frozen but not the second. if self.type_is_freeze(pointee_ty) { Borrow::Frz(time) } else { + // Shared reference with interior mutability. Borrow::Mut(Mut::Raw) }, None => Borrow::Mut(Mut::Raw), - }; + } + } + + /// Called for place-to-value conversion. + fn tag_reference( + &mut self, + ptr: Pointer, + pointee_ty: Ty<'tcx>, + size: Size, + mutability: Option, + ) -> EvalResult<'tcx, Borrow> { + let new_bor = self.tag_for_pointee(pointee_ty, mutability); trace!("tag_reference: Creating new reference ({:?}) for {:?} (pointee {}, size {}): {:?}", - borrow_kind, ptr, pointee_ty, size.bytes(), new_bor); + mutability, ptr, pointee_ty, size.bytes(), new_bor); // Make sure this reference is not dangling or so self.memory.check_bounds(ptr, size, false)?; @@ -291,14 +310,17 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' Ok(new_bor) } + /// Called for value-to-place conversion. fn tag_dereference( &self, ptr: Pointer, - ptr_ty: Ty<'tcx>, + pointee_ty: Ty<'tcx>, + size: Size, + mutability: Option, ) -> EvalResult<'tcx, Borrow> { - // If this is a raw ptr, forget about the tag. - Ok(if ptr_ty.is_unsafe_ptr() { - trace!("tag_dereference: Erasing tag for {:?} ({})", ptr, ptr_ty); + // If this is a raw situation, forget about the tag. + Ok(if mutability.is_none() { + trace!("tag_dereference: Erasing tag for {:?} (pointee {})", ptr, pointee_ty); Borrow::Mut(Mut::Raw) } else { // FIXME: Do we want to adjust the tag if it does not match the type? From dd1558f33719facb84726f9489ee9e2abb279e8b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Oct 2018 16:07:40 +0200 Subject: [PATCH 0284/5092] rustc update and be very selective about what we accept on a deref --- src/lib.rs | 36 ++-- src/stacked_borrows.rs | 204 ++++++++++++++---- .../stacked_borrows/alias_through_mutation.rs | 2 +- .../stacked_borrows/buggy_as_mut_slice.rs | 2 +- .../stacked_borrows/buggy_split_at_mut.rs | 3 +- .../stacked_borrows/illegal_write.rs | 11 - .../stacked_borrows/illegal_write2.rs | 2 +- .../stacked_borrows/pointer_smuggling.rs | 2 +- .../stacked_borrows/shared_confusion.rs | 2 +- .../static_memory_modification.rs | 3 + .../static_memory_modification2.rs | 2 +- .../static_memory_modification3.rs | 3 + tests/compile-fail/unaligned_ptr_cast.rs | 3 + tests/compile-fail/unaligned_ptr_cast2.rs | 3 + tests/compile-fail/validity/undef.rs | 2 +- tests/compile-fail/zst.rs | 2 +- 16 files changed, 207 insertions(+), 75 deletions(-) delete mode 100644 tests/compile-fail/stacked_borrows/illegal_write.rs diff --git a/src/lib.rs b/src/lib.rs index 7841a4d3a2c0..6ca64356ff9f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -434,7 +434,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn memory_deallocated( - alloc: &mut Allocation, + alloc: &mut Allocation, ptr: Pointer, ) -> EvalResult<'tcx> { alloc.extra.memory_deallocated(ptr) @@ -443,32 +443,38 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn tag_reference( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - ptr: Pointer, - pointee_ty: Ty<'tcx>, - pointee_size: Size, + place: MemPlace, + ty: Ty<'tcx>, + size: Size, mutability: Option, - ) -> EvalResult<'tcx, Borrow> { - if !ecx.machine.validate { + ) -> EvalResult<'tcx, MemPlace> { + if !ecx.machine.validate || size == Size::ZERO { // No tracking - Ok(Borrow::default()) + Ok(place) } else { - ecx.tag_reference(ptr, pointee_ty, pointee_size, mutability) + let ptr = place.ptr.to_ptr()?; + let tag = ecx.tag_reference(ptr, ty, size, mutability.into())?; + let ptr = Scalar::Ptr(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag)); + Ok(MemPlace { ptr, ..place }) } } #[inline(always)] fn tag_dereference( ecx: &EvalContext<'a, 'mir, 'tcx, Self>, - ptr: Pointer, - pointee_ty: Ty<'tcx>, - pointee_size: Size, + place: MemPlace, + ty: Ty<'tcx>, + size: Size, mutability: Option, - ) -> EvalResult<'tcx, Borrow> { - if !ecx.machine.validate { + ) -> EvalResult<'tcx, MemPlace> { + if !ecx.machine.validate || size == Size::ZERO { // No tracking - Ok(Borrow::default()) + Ok(place) } else { - ecx.tag_dereference(ptr, pointee_ty, pointee_size, mutability) + let ptr = place.ptr.to_ptr()?; + let tag = ecx.tag_dereference(ptr, ty, size, mutability.into())?; + let ptr = Scalar::Ptr(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag)); + Ok(MemPlace { ptr, ..place }) } } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 169c8abe2b08..3ed3f6d9540f 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -1,7 +1,6 @@ use std::cell::{Cell, RefCell}; -use rustc::ty::{self, Ty, layout::Size}; -use rustc::mir; +use rustc::ty::{Ty, layout::Size}; use rustc::hir; use super::{ @@ -65,6 +64,24 @@ impl Default for Borrow { } } +/// What kind of reference are we talking about? +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub enum RefKind { + Mut, + Shr, + Raw, +} + +impl From> for RefKind { + fn from(mutbl: Option) -> Self { + match mutbl { + None => RefKind::Raw, + Some(hir::MutMutable) => RefKind::Mut, + Some(hir::MutImmutable) => RefKind::Shr, + } + } +} + /// Extra global machine state #[derive(Clone, Debug)] pub struct State { @@ -101,6 +118,9 @@ pub struct Stacks { /// Core operations impl<'tcx> Stack { + /// Check if `bor` is currently active. We accept a `Raw` on a frozen location + /// because this could be a shared (re)borrow. If you want to mutate, this + /// is not the right function to call! fn check(&self, bor: Borrow) -> bool { match bor { Borrow::Frz(acc_t) => @@ -116,8 +136,33 @@ impl<'tcx> Stack { } } + /// Check if `bor` could be activated by unfreezing and popping. + /// This should be in sync with `reactivate`! + fn reactivatable(&self, bor: Borrow) -> bool { + if self.check(bor) { + return true; + } + + let acc_m = match bor { + Borrow::Frz(_) => return false, + Borrow::Mut(acc_m) => acc_m + }; + // This is where we would unfreeze. + for &itm in self.borrows.iter().rev() { + match itm { + BorStackItem::FnBarrier(_) => return false, + BorStackItem::Mut(loc_m) => { + if loc_m == acc_m { return true; } + // Go on looking. + } + } + } + // Simulate a "virtual raw" element at the bottom of the stack. + acc_m.is_raw() + } + /// Reactive `bor` for this stack. If `force_mut` is set, we want to aggressively - /// unfreeze this location (because we are about to push a `Uniq`). + /// unfreeze this location (because we are about to mutate, so a frozen `Raw` is not okay). fn reactivate(&mut self, bor: Borrow, force_mut: bool) -> EvalResult<'tcx> { // Unless mutation is bound to happen, do NOT change anything if `bor` is already active. // In particular, if it is a `Mut(Raw)` and we are frozen, this should be a NOP. @@ -126,15 +171,25 @@ impl<'tcx> Stack { } let acc_m = match bor { - Borrow::Frz(_) => + Borrow::Frz(since) => if force_mut { return err!(MachineError(format!("Using a shared borrow for mutation"))) } else { - return err!(MachineError(format!("Location should be frozen but it is not"))) + return err!(MachineError(format!( + "Location should be frozen since {} but {}", + since, + match self.frozen_since { + None => format!("it is not frozen at all"), + Some(since) => format!("it is only frozen since {}", since), + } + ))) } Borrow::Mut(acc_m) => acc_m, }; // We definitely have to unfreeze this, even if we use the topmost item. + if self.frozen_since.is_some() { + trace!("reactivate: Unfreezing"); + } self.frozen_since = None; // Pop until we see the one we are looking for. while let Some(&itm) = self.borrows.last() { @@ -157,21 +212,33 @@ impl<'tcx> Stack { } } + /// Initiate `bor`; mostly this means freezing or pushing. fn initiate(&mut self, bor: Borrow) -> EvalResult<'tcx> { match bor { Borrow::Frz(t) => { - trace!("initiate: Freezing"); match self.frozen_since { - None => self.frozen_since = Some(t), - Some(since) => assert!(since <= t), + None => { + trace!("initiate: Freezing"); + self.frozen_since = Some(t); + } + Some(since) => { + trace!("initiate: Already frozen"); + assert!(since <= t); + } } } Borrow::Mut(m) => { - trace!("initiate: Pushing {:?}", bor); match self.frozen_since { - None => self.borrows.push(BorStackItem::Mut(m)), + None => { + trace!("initiate: Pushing {:?}", bor); + self.borrows.push(BorStackItem::Mut(m)) + } + Some(_) if m.is_raw() => + // We only ever initiate right after activating the ref we come from. + // If the source ref is fine being frozen, then a raw ref we create + // from it is fine with this as well. + trace!("initiate: Initiating a raw on a frozen location, not doing a thing"), Some(_) => - // FIXME: Do we want an exception for raw borrows? return err!(MachineError(format!("Trying to mutate frozen location"))) } } @@ -223,13 +290,17 @@ impl<'tcx> Stacks { ptr: Pointer, size: Size, new_bor: Borrow, + permit_redundant: bool, ) -> EvalResult<'tcx> { let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { - if stack.check(new_bor) { + if permit_redundant && stack.check(new_bor) { // The new borrow is already active! This can happen when creating multiple // shared references from the same mutable reference. Do nothing. + trace!("reborrow: New borrow {:?} is already active, not doing a thing", new_bor); } else { + // If we are creating a uniq ref, we certainly want to unfreeze. + // Even if we are doing so from a raw. // FIXME: The blog post says we should `reset` if this is a local. stack.reactivate(ptr.tag, /*force_mut*/new_bor.is_uniq())?; stack.initiate(new_bor)?; @@ -241,39 +312,40 @@ impl<'tcx> Stacks { } pub trait EvalContextExt<'tcx> { + fn tag_for_pointee( + &self, + pointee_ty: Ty<'tcx>, + ref_kind: RefKind, + ) -> Borrow; + fn tag_reference( - &mut self, + &self, ptr: Pointer, pointee_ty: Ty<'tcx>, size: Size, - mutability: Option, + ref_kind: RefKind, ) -> EvalResult<'tcx, Borrow>; + fn tag_dereference( &self, ptr: Pointer, pointee_ty: Ty<'tcx>, size: Size, - mutability: Option, + ref_kind: RefKind, ) -> EvalResult<'tcx, Borrow>; - - fn tag_for_pointee( - &self, - pointee_ty: Ty<'tcx>, - borrow_kind: Option, - ) -> Borrow; } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { fn tag_for_pointee( &self, pointee_ty: Ty<'tcx>, - borrow_kind: Option, + ref_kind: RefKind, ) -> Borrow { let time = self.machine.stacked_borrows.increment_clock(); - match borrow_kind { - Some(hir::MutMutable) => Borrow::Mut(Mut::Uniq(time)), - Some(hir::MutImmutable) => + match ref_kind { + RefKind::Mut => Borrow::Mut(Mut::Uniq(time)), + RefKind::Shr => // FIXME This does not do enough checking when only part of the data has // interior mutability. When the type is `(i32, Cell)`, we want the // first field to be frozen but not the second. @@ -283,21 +355,21 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Shared reference with interior mutability. Borrow::Mut(Mut::Raw) }, - None => Borrow::Mut(Mut::Raw), + RefKind::Raw => Borrow::Mut(Mut::Raw), } } /// Called for place-to-value conversion. fn tag_reference( - &mut self, + &self, ptr: Pointer, pointee_ty: Ty<'tcx>, size: Size, - mutability: Option, + ref_kind: RefKind, ) -> EvalResult<'tcx, Borrow> { - let new_bor = self.tag_for_pointee(pointee_ty, mutability); + let new_bor = self.tag_for_pointee(pointee_ty, ref_kind); trace!("tag_reference: Creating new reference ({:?}) for {:?} (pointee {}, size {}): {:?}", - mutability, ptr, pointee_ty, size.bytes(), new_bor); + ref_kind, ptr, pointee_ty, size.bytes(), new_bor); // Make sure this reference is not dangling or so self.memory.check_bounds(ptr, size, false)?; @@ -305,26 +377,78 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Update the stacks. We cannot use `get_mut` becuse this might be immutable // memory. let alloc = self.memory.get(ptr.alloc_id).expect("We checked that the ptr is fine!"); - alloc.extra.reborrow(ptr, size, new_bor)?; + let permit_redundant = ref_kind == RefKind::Shr; // redundant shared refs are okay + alloc.extra.reborrow(ptr, size, new_bor, permit_redundant)?; Ok(new_bor) } /// Called for value-to-place conversion. + /// + /// Note that this does NOT mean that all this memory will actually get accessed/referenced! + /// We could be in the middle of `&(*var).1`. fn tag_dereference( &self, ptr: Pointer, pointee_ty: Ty<'tcx>, size: Size, - mutability: Option, + ref_kind: RefKind, ) -> EvalResult<'tcx, Borrow> { - // If this is a raw situation, forget about the tag. - Ok(if mutability.is_none() { - trace!("tag_dereference: Erasing tag for {:?} (pointee {})", ptr, pointee_ty); - Borrow::Mut(Mut::Raw) - } else { - // FIXME: Do we want to adjust the tag if it does not match the type? - ptr.tag - }) + // In principle we should not have to do anything here. However, with transmutes involved, + // it can happen that the tag of `ptr` does not actually match `ref_kind`, and we + // should adjust for that. + // Notably, the compiler can introduce such transmutes by optimizing away `&[mut]*`. + // That can transmute a raw ptr to a (shared/mut) ref, and a mut ref to a shared one. + match (ref_kind, ptr.tag) { + (RefKind::Raw, Borrow::Mut(Mut::Raw)) | + (RefKind::Mut, Borrow::Mut(Mut::Uniq(_))) | + (RefKind::Shr, Borrow::Frz(_)) | + (RefKind::Shr, Borrow::Mut(Mut::Raw)) => { + // Expected combinations. Nothing to do. + // FIXME: We probably shouldn't accept this if we got a raw shr without + // interior mutability. + } + (_, Borrow::Mut(Mut::Raw)) => { + // Raw transmuted to (shr/mut) ref. Keep this as raw access. + // We cannot reborrow here; there might be a raw in `&(*var).1` where + // `var` is an `&mut`. The other field of the struct might be already frozen, + // also using `var`, and that would be okay. + } + (RefKind::Raw, _) => { + // Someone transmuted a ref to a raw. Treat this like a ref, their fault. + } + (RefKind::Shr, Borrow::Mut(Mut::Uniq(_))) => { + // A mut got transmuted to shr. High time we freeze this location! + // Make this a delayed reborrow. Redundant reborows to shr are okay, + // so we do not have to be worried about doing too much. + trace!("tag_dereference: Lazy freezing of {:?}", ptr); + return self.tag_reference(ptr, pointee_ty, size, ref_kind); + } + (RefKind::Mut, Borrow::Frz(_)) => { + // This is just invalid. + // If we ever allow this, we have to consider what we do when a turn a + // `Raw`-tagged `&mut` into a raw pointer pointing to a frozen location. + // We probably do not want to allow that, but we have to allow + // turning a `Raw`-tagged `&` into a raw ptr to a frozen location. + return err!(MachineError(format!("Encountered mutable reference with frozen tag {:?}", ptr.tag))) + } + } + // Even if we don't touch the tag, this operation is only okay if we *could* + // activate it. Also it must not be dangling. + self.memory.check_bounds(ptr, size, false)?; + let alloc = self.memory.get(ptr.alloc_id).expect("We checked that the ptr is fine!"); + let mut stacks = alloc.extra.stacks.borrow_mut(); + // We need `iter_mut` because `iter` would skip gaps! + for stack in stacks.iter_mut(ptr.offset, size) { + // We accept &mut to a frozen location here, that is just normal. There might + // be shared reborrows that we are about to invalidate with this access. + // We cannot invalidate them aggressively here because the deref might also be + // to just create more shared refs. + if !stack.reactivatable(ptr.tag) { + return err!(MachineError(format!("Encountered {:?} reference with non-reactivatable tag {:?}", ref_kind, ptr.tag))) + } + } + // All is good. + Ok(ptr.tag) } } diff --git a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs index 9fa50da45bd0..3fcf20e15625 100644 --- a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs +++ b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs @@ -11,5 +11,5 @@ fn main() { retarget(&mut target_alias, target); // now `target_alias` points to the same thing as `target` *target = 13; - let _val = *target_alias; //~ ERROR should be frozen + let _val = *target_alias; //~ ERROR Shr reference with non-reactivatable tag Frz } diff --git a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs index 4857ada7fb2c..5f729af30bbe 100644 --- a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs +++ b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs @@ -14,6 +14,6 @@ fn main() { let v = vec![0,1,2]; let v1 = safe::as_mut_slice(&v); let v2 = safe::as_mut_slice(&v); - v1[1] = 5; //~ ERROR does not exist on the stack + v1[1] = 5; //~ ERROR Mut reference with non-reactivatable tag Mut(Uniq v1[1] = 6; } diff --git a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs index d7f4300f82c0..0a890b1cebaa 100644 --- a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs @@ -11,6 +11,7 @@ mod safe { assert!(mid <= len); (from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" + //~^ ERROR Mut reference with non-reactivatable tag Mut(Uniq from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) } } @@ -19,6 +20,6 @@ mod safe { fn main() { let mut array = [1,2,3,4]; let (a, b) = safe::split_at_mut(&mut array, 0); - a[1] = 5; //~ ERROR does not exist on the stack + a[1] = 5; b[1] = 6; } diff --git a/tests/compile-fail/stacked_borrows/illegal_write.rs b/tests/compile-fail/stacked_borrows/illegal_write.rs deleted file mode 100644 index 6a7ccc84012c..000000000000 --- a/tests/compile-fail/stacked_borrows/illegal_write.rs +++ /dev/null @@ -1,11 +0,0 @@ -fn evil(x: &u32) { - let x : &mut u32 = unsafe { &mut *(x as *const _ as *mut _) }; - *x = 42; // mutating shared ref without `UnsafeCell` -} - -fn main() { - let target = 42; - let ref_ = ⌖ - evil(ref_); // invalidates shared ref - let _x = *ref_; //~ ERROR should be frozen -} diff --git a/tests/compile-fail/stacked_borrows/illegal_write2.rs b/tests/compile-fail/stacked_borrows/illegal_write2.rs index 1d61b1b98896..22648ba71184 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write2.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write2.rs @@ -6,5 +6,5 @@ fn main() { drop(&mut *target); // reborrow // Now make sure our ref is still the only one unsafe { *target2 = 13; } // invalidate our ref - let _val = *target; //~ ERROR does not exist on the stack + let _val = *target; //~ ERROR Mut reference with non-reactivatable tag Mut(Uniq } diff --git a/tests/compile-fail/stacked_borrows/pointer_smuggling.rs b/tests/compile-fail/stacked_borrows/pointer_smuggling.rs index 3576aa52b753..678b9b21ba8c 100644 --- a/tests/compile-fail/stacked_borrows/pointer_smuggling.rs +++ b/tests/compile-fail/stacked_borrows/pointer_smuggling.rs @@ -18,5 +18,5 @@ fn main() { fun1(val); *val = 2; // this invalidates any raw ptrs `fun1` might have created. fun2(); // if they now use a raw ptr they break our reference - *val = 3; //~ ERROR does not exist on the stack + *val = 3; //~ ERROR Mut reference with non-reactivatable tag Mut(Uniq } diff --git a/tests/compile-fail/stacked_borrows/shared_confusion.rs b/tests/compile-fail/stacked_borrows/shared_confusion.rs index 584053f59323..5098f493ccd7 100644 --- a/tests/compile-fail/stacked_borrows/shared_confusion.rs +++ b/tests/compile-fail/stacked_borrows/shared_confusion.rs @@ -13,7 +13,7 @@ fn test(r: &mut RefCell) { } // Our old raw should be dead by now unsafe { *x_evil = 0; } // this falls back to some Raw higher up the stack - *x_inner = 12; //~ ERROR does not exist on the stack + *x_inner = 12; //~ ERROR Mut reference with non-reactivatable tag Mut(Uniq } fn main() { diff --git a/tests/compile-fail/static_memory_modification.rs b/tests/compile-fail/static_memory_modification.rs index 304ab6c6b740..c75892645865 100644 --- a/tests/compile-fail/static_memory_modification.rs +++ b/tests/compile-fail/static_memory_modification.rs @@ -1,3 +1,6 @@ +// Validation detects that we are casting & to &mut and so it changes why we fail +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation + static X: usize = 5; #[allow(mutable_transmutes)] diff --git a/tests/compile-fail/static_memory_modification2.rs b/tests/compile-fail/static_memory_modification2.rs index 01c3b9bb2d8d..c9857b20592e 100644 --- a/tests/compile-fail/static_memory_modification2.rs +++ b/tests/compile-fail/static_memory_modification2.rs @@ -1,5 +1,5 @@ // Validation detects that we are casting & to &mut and so it changes why we fail -// compile-flags: -Zmir-emit-validate=0 +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation use std::mem::transmute; diff --git a/tests/compile-fail/static_memory_modification3.rs b/tests/compile-fail/static_memory_modification3.rs index ff09aad1bd56..41a62787296f 100644 --- a/tests/compile-fail/static_memory_modification3.rs +++ b/tests/compile-fail/static_memory_modification3.rs @@ -1,3 +1,6 @@ +// Validation detects that we are casting & to &mut and so it changes why we fail +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation + use std::mem::transmute; #[allow(mutable_transmutes)] diff --git a/tests/compile-fail/unaligned_ptr_cast.rs b/tests/compile-fail/unaligned_ptr_cast.rs index 88285dc69f31..47317afd36ec 100644 --- a/tests/compile-fail/unaligned_ptr_cast.rs +++ b/tests/compile-fail/unaligned_ptr_cast.rs @@ -1,3 +1,6 @@ +// This should fail even without validation +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation + fn main() { let x = &2u16; let x = x as *const _ as *const u32; diff --git a/tests/compile-fail/unaligned_ptr_cast2.rs b/tests/compile-fail/unaligned_ptr_cast2.rs index 7541079def2c..d146f21dfe60 100644 --- a/tests/compile-fail/unaligned_ptr_cast2.rs +++ b/tests/compile-fail/unaligned_ptr_cast2.rs @@ -1,3 +1,6 @@ +// This should fail even without validation +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation + fn main() { let x = &2u16; let x = x as *const _ as *const *const u8; diff --git a/tests/compile-fail/validity/undef.rs b/tests/compile-fail/validity/undef.rs index 58d3926dadaf..f86fef9454e8 100644 --- a/tests/compile-fail/validity/undef.rs +++ b/tests/compile-fail/validity/undef.rs @@ -1,5 +1,5 @@ #![allow(unused_variables)] -// error-pattern: encountered undefined data in pointer +// error-pattern: encountered undefined address in pointer use std::mem; diff --git a/tests/compile-fail/zst.rs b/tests/compile-fail/zst.rs index 2b179dcc8a45..0f4c945c85b4 100644 --- a/tests/compile-fail/zst.rs +++ b/tests/compile-fail/zst.rs @@ -1,4 +1,4 @@ fn main() { let x = &() as *const () as *const i32; - let _ = unsafe { *x }; //~ ERROR tried to access memory with alignment 1, but alignment 4 is required + let _ = unsafe { *x }; //~ ERROR outside bounds of allocation } From fda03e9d7db66f59f4c1ae9ca752b68c53d1fe88 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Oct 2018 18:38:23 +0200 Subject: [PATCH 0285/5092] some more compile-fail tests --- tests/compile-fail-fullmir/stack_free.rs | 3 ++ .../stacked_borrows/illegal_write1.rs | 11 +++++++ .../stacked_borrows/illegal_write3.rs | 8 +++++ .../stacked_borrows/illegal_write4.rs | 31 +++++++++++++++++++ tests/compile-fail/validity/dangling_ref1.rs | 5 +++ tests/compile-fail/validity/dangling_ref2.rs | 7 +++++ 6 files changed, 65 insertions(+) create mode 100644 tests/compile-fail/stacked_borrows/illegal_write1.rs create mode 100644 tests/compile-fail/stacked_borrows/illegal_write3.rs create mode 100644 tests/compile-fail/stacked_borrows/illegal_write4.rs create mode 100644 tests/compile-fail/validity/dangling_ref1.rs create mode 100644 tests/compile-fail/validity/dangling_ref2.rs diff --git a/tests/compile-fail-fullmir/stack_free.rs b/tests/compile-fail-fullmir/stack_free.rs index 96006c884e58..6d853e75fb4a 100644 --- a/tests/compile-fail-fullmir/stack_free.rs +++ b/tests/compile-fail-fullmir/stack_free.rs @@ -1,3 +1,6 @@ +// Validation changes why we fail +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation + // error-pattern: tried to deallocate Stack memory but gave Machine(Rust) as the kind fn main() { diff --git a/tests/compile-fail/stacked_borrows/illegal_write1.rs b/tests/compile-fail/stacked_borrows/illegal_write1.rs new file mode 100644 index 000000000000..86b96e2880ec --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_write1.rs @@ -0,0 +1,11 @@ +fn evil(x: &u32) { + let x : &mut u32 = unsafe { &mut *(x as *const _ as *mut _) }; + *x = 42; // mutating shared ref without `UnsafeCell` +} + +fn main() { + let target = 42; + let ref_ = ⌖ + evil(ref_); // invalidates shared ref + let _x = *ref_; //~ ERROR Shr reference with non-reactivatable tag Frz +} diff --git a/tests/compile-fail/stacked_borrows/illegal_write3.rs b/tests/compile-fail/stacked_borrows/illegal_write3.rs new file mode 100644 index 000000000000..26c30a4122b4 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_write3.rs @@ -0,0 +1,8 @@ +fn main() { + let target = 42; + // Make sure raw ptr with raw tag cannot mutate frozen location without breaking the shared ref. + let r#ref = ⌖ // freeze + let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag + unsafe { *ptr = 42; } + let _val = *r#ref; //~ ERROR Shr reference with non-reactivatable tag Frz +} diff --git a/tests/compile-fail/stacked_borrows/illegal_write4.rs b/tests/compile-fail/stacked_borrows/illegal_write4.rs new file mode 100644 index 000000000000..b2ffac865bd4 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_write4.rs @@ -0,0 +1,31 @@ +// The compiler inserts some reborrows, enable optimizations to +// get rid of them. +// compile-flags: -Zmir-opt-level=1 + +use std::mem; + +// This is an example of a piece of code that intuitively seems like we might +// want to reject it, but that doesn't turn out to be possible. + +fn main() { + let target = 42; + // Make sure a cannot use a raw-tagged `&mut` pointing to a frozen location, not + // even to create a raw. + let r#ref = ⌖ // freeze + let ptr = r#ref as *const _ as *mut i32; // raw ptr, with raw tag + let mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag + // Now we have an &mut to a frozen location, but that is completely normal: + // We'd just unfreeze the location if we used it. + let bad_ptr = mut_ref as *mut i32; // even just creating this is like a use of `mut_ref`. + // That violates the location being frozen! However, we do not properly detect this: + // We first see a `&mut` with a `Raw` tag being deref'd for a frozen location, + // which can happen legitimately if the compiler optimized away an `&mut*` that + // turns a raw into a `&mut`. Next, we create a raw ref to a frozen location + // from a `Raw` tag, which can happen legitimately when interior mutability + // is involved. + let _val = *r#ref; // Make sure it is still frozen. + + // We only actually unfreeze once we muteate through the bad pointer. + unsafe { *bad_ptr = 42 }; + let _val = *r#ref; //~ ERROR Shr reference with non-reactivatable tag Frz +} diff --git a/tests/compile-fail/validity/dangling_ref1.rs b/tests/compile-fail/validity/dangling_ref1.rs new file mode 100644 index 000000000000..c5845cb693bb --- /dev/null +++ b/tests/compile-fail/validity/dangling_ref1.rs @@ -0,0 +1,5 @@ +use std::mem; + +fn main() { + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR tried to interpret some bytes as a pointer +} diff --git a/tests/compile-fail/validity/dangling_ref2.rs b/tests/compile-fail/validity/dangling_ref2.rs new file mode 100644 index 000000000000..21650ebf9506 --- /dev/null +++ b/tests/compile-fail/validity/dangling_ref2.rs @@ -0,0 +1,7 @@ +use std::mem; + +fn main() { + let val = 14; + let ptr = (&val as *const i32).wrapping_offset(1); + let _x: &i32 = unsafe { mem::transmute(ptr) }; //~ ERROR outside bounds of allocation +} From 01828fde5345299636f6c029b333f42e91ffd140 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Oct 2018 19:51:41 +0200 Subject: [PATCH 0286/5092] respect memory's privacy --- src/fn_call.rs | 57 +++++++++++++++++++++--------------------- src/intrinsic.rs | 10 ++++---- src/lib.rs | 4 +-- src/operator.rs | 28 ++++++++++----------- src/stacked_borrows.rs | 8 +++--- 5 files changed, 54 insertions(+), 53 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 0cbd891a34e4..04601b3cd1ff 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -125,7 +125,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo self.write_null(dest)?; } else { let align = self.tcx.data_layout.pointer_align; - let ptr = self.memory.allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into())?; + let ptr = self.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into())?; self.write_scalar(Scalar::Ptr(ptr), dest)?; } } @@ -133,7 +133,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "free" => { let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation, no tag if !ptr.is_null() { - self.memory.deallocate( + self.memory_mut().deallocate( ptr.to_ptr()?.with_default_tag(), None, MiriMemoryKind::C.into(), @@ -150,7 +150,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory.allocate(Size::from_bytes(size), + let ptr = self.memory_mut().allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), MiriMemoryKind::Rust.into())?; self.write_scalar(Scalar::Ptr(ptr), dest)?; @@ -164,10 +164,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory.allocate(Size::from_bytes(size), + let ptr = self.memory_mut().allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), MiriMemoryKind::Rust.into())?; - self.memory.write_repeat(ptr.into(), 0, Size::from_bytes(size))?; + self.memory_mut().write_repeat(ptr.into(), 0, Size::from_bytes(size))?; self.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_dealloc" => { @@ -180,7 +180,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - self.memory.deallocate( + self.memory_mut().deallocate( ptr.with_default_tag(), Some((Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap())), MiriMemoryKind::Rust.into(), @@ -197,7 +197,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let new_ptr = self.memory.reallocate( + let new_ptr = self.memory_mut().reallocate( ptr.with_default_tag(), Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap(), @@ -231,7 +231,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "dlsym" => { let _handle = self.read_scalar(args[0])?; let symbol = self.read_scalar(args[1])?.to_ptr()?.erase_tag(); - let symbol_name = self.memory.read_c_str(symbol.with_default_tag())?; + let symbol_name = self.memory().read_c_str(symbol.with_default_tag())?; let err = format!("bad c unicode symbol: {:?}", symbol_name); let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err); return err!(Unimplemented(format!( @@ -245,7 +245,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // We abort on panic, so not much is going on here, but we still have to call the closure let f = self.read_scalar(args[0])?.to_ptr()?; let data = self.read_scalar(args[1])?.not_undef()?; - let f_instance = self.memory.get_fn(f)?; + let f_instance = self.memory().get_fn(f)?; self.write_null(dest)?; trace!("__rust_maybe_catch_panic: {:?}", f_instance); @@ -289,8 +289,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let n = Size::from_bytes(self.read_scalar(args[2])?.to_usize(&self)?); let result = { - let left_bytes = self.memory.read_bytes(left.with_default_tag(), n)?; - let right_bytes = self.memory.read_bytes(right.with_default_tag(), n)?; + let left_bytes = self.memory().read_bytes(left.with_default_tag(), n)?; + let right_bytes = self.memory().read_bytes(right.with_default_tag(), n)?; use std::cmp::Ordering::*; match left_bytes.cmp(right_bytes) { @@ -311,7 +311,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let ptr = ptr.with_default_tag(); let val = self.read_scalar(args[1])?.to_bytes()? as u8; let num = self.read_scalar(args[2])?.to_usize(&self)?; - if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))? + if let Some(idx) = self.memory().read_bytes(ptr, Size::from_bytes(num))? .iter().rev().position(|&c| c == val) { let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), &self)?; @@ -326,7 +326,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let ptr = ptr.with_default_tag(); let val = self.read_scalar(args[1])?.to_bytes()? as u8; let num = self.read_scalar(args[2])?.to_usize(&self)?; - if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().position( + if let Some(idx) = self.memory().read_bytes(ptr, Size::from_bytes(num))?.iter().position( |&c| c == val, ) { @@ -340,7 +340,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "getenv" => { let result = { let name_ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation - let name = self.memory.read_c_str(name_ptr.with_default_tag())?; + let name = self.memory().read_c_str(name_ptr.with_default_tag())?; match self.machine.env_vars.get(name) { Some(&var) => Scalar::Ptr(var), None => Scalar::ptr_null(*self.tcx), @@ -354,15 +354,16 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo { let name_ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation if !name_ptr.is_null() { - let name = self.memory.read_c_str(name_ptr.to_ptr()?.with_default_tag())?; + let name = self.memory().read_c_str(name_ptr.to_ptr()? + .with_default_tag())?.to_owned(); if !name.is_empty() && !name.contains(&b'=') { - success = Some(self.machine.env_vars.remove(name)); + success = Some(self.machine.env_vars.remove(&name)); } } } if let Some(old) = success { if let Some(var) = old { - self.memory.deallocate(var, None, MiriMemoryKind::Env.into())?; + self.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; } self.write_null(dest)?; } else { @@ -375,9 +376,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo { let name_ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation let value_ptr = self.read_scalar(args[1])?.to_ptr()?.erase_tag(); // raw ptr operation - let value = self.memory.read_c_str(value_ptr.with_default_tag())?; + let value = self.memory().read_c_str(value_ptr.with_default_tag())?; if !name_ptr.is_null() { - let name = self.memory.read_c_str(name_ptr.to_ptr()?.with_default_tag())?; + let name = self.memory().read_c_str(name_ptr.to_ptr()?.with_default_tag())?; if !name.is_empty() && !name.contains(&b'=') { new = Some((name.to_owned(), value.to_owned())); } @@ -385,20 +386,20 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } if let Some((name, value)) = new { // +1 for the null terminator - let value_copy = self.memory.allocate( + let value_copy = self.memory_mut().allocate( Size::from_bytes((value.len() + 1) as u64), Align::from_bytes(1, 1).unwrap(), MiriMemoryKind::Env.into(), )?; - self.memory.write_bytes(value_copy.into(), &value)?; + self.memory_mut().write_bytes(value_copy.into(), &value)?; let trailing_zero_ptr = value_copy.offset(Size::from_bytes(value.len() as u64), &self)?.into(); - self.memory.write_bytes(trailing_zero_ptr, &[0])?; + self.memory_mut().write_bytes(trailing_zero_ptr, &[0])?; if let Some(var) = self.machine.env_vars.insert( name.to_owned(), value_copy, ) { - self.memory.deallocate(var, None, MiriMemoryKind::Env.into())?; + self.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; } self.write_null(dest)?; } else { @@ -415,7 +416,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // stdout/stderr use std::io::{self, Write}; - let buf_cont = self.memory.read_bytes(buf.with_default_tag(), Size::from_bytes(n))?; + let buf_cont = self.memory().read_bytes(buf.with_default_tag(), Size::from_bytes(n))?; let res = if fd == 1 { io::stdout().write(buf_cont) } else { @@ -437,7 +438,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "strlen" => { let ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); - let n = self.memory.read_c_str(ptr.with_default_tag())?.len(); + let n = self.memory().read_c_str(ptr.with_default_tag())?.len(); self.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; } @@ -487,9 +488,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // Extract the function type out of the signature (that seems easier than constructing it ourselves...) let dtor = match self.read_scalar(args[1])?.not_undef()? { - Scalar::Ptr(dtor_ptr) => Some(self.memory.get_fn(dtor_ptr)?), + Scalar::Ptr(dtor_ptr) => Some(self.memory().get_fn(dtor_ptr)?), Scalar::Bits { bits: 0, size } => { - assert_eq!(size as u64, self.memory.pointer_size().bytes()); + assert_eq!(size as u64, self.memory().pointer_size().bytes()); None }, Scalar::Bits { .. } => return err!(ReadBytesAsPointer), @@ -505,7 +506,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) { return err!(OutOfTls); } - self.memory.write_scalar( + self.memory_mut().write_scalar( key_ptr.with_default_tag(), key_layout.align, Scalar::from_uint(key, key_layout.size).into(), diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 5c86075883b0..98c57894a9d6 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -153,7 +153,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // erase tags: this is a raw ptr operation let src = self.read_scalar(args[0])?.not_undef()?.erase_tag(); let dest = self.read_scalar(args[1])?.not_undef()?.erase_tag(); - self.memory.copy( + self.memory_mut().copy( src.with_default_tag(), elem_align, dest.with_default_tag(), @@ -260,7 +260,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Do it in memory let mplace = self.force_allocation(dest)?; assert!(mplace.meta.is_none()); - self.memory.write_repeat(mplace.ptr, 0, dest.layout.size)?; + self.memory_mut().write_repeat(mplace.ptr, 0, dest.layout.size)?; } } } @@ -423,7 +423,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Do it in memory let mplace = self.force_allocation(dest)?; assert!(mplace.meta.is_none()); - self.memory.mark_definedness(mplace.ptr.to_ptr()?, dest.layout.size, false)?; + self.memory_mut().mark_definedness(mplace.ptr.to_ptr()?, dest.layout.size, false)?; } } } @@ -435,8 +435,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let val_byte = self.read_scalar(args[1])?.to_u8()?; let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag().with_default_tag(); let count = self.read_scalar(args[2])?.to_usize(&self)?; - self.memory.check_align(ptr, ty_layout.align)?; - self.memory.write_repeat(ptr, val_byte, ty_layout.size * count)?; + self.memory().check_align(ptr, ty_layout.align)?; + self.memory_mut().write_repeat(ptr, val_byte, ty_layout.size * count)?; } name => return err!(Unimplemented(format!("unimplemented intrinsic: {}", name))), diff --git a/src/lib.rs b/src/lib.rs index 6ca64356ff9f..8925afa5f600 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -119,12 +119,12 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // FIXME: extract main source file path // Third argument (argv): &[b"foo"] let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - let foo = ecx.memory.allocate_static_bytes(b"foo\0"); + let foo = ecx.memory_mut().allocate_static_bytes(b"foo\0"); let foo_ty = ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8); let foo_layout = ecx.layout_of(foo_ty)?; let foo_place = ecx.allocate(foo_layout, MiriMemoryKind::Env.into())?; ecx.write_scalar(Scalar::Ptr(foo), foo_place.into())?; - ecx.memory.mark_immutable(foo_place.to_ptr()?.alloc_id)?; + ecx.memory_mut().mark_immutable(foo_place.to_ptr()?.alloc_id)?; ecx.write_scalar(foo_place.ptr, dest)?; assert!(args.next().is_none(), "start lang item has more arguments than expected"); diff --git a/src/operator.rs b/src/operator.rs index a11f8f34e7e8..0eac5c11276a 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -80,8 +80,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' Ge => left.offset >= right.offset, Sub => { // subtract the offsets - let left_offset = Scalar::from_uint(left.offset.bytes(), self.memory.pointer_size()); - let right_offset = Scalar::from_uint(right.offset.bytes(), self.memory.pointer_size()); + let left_offset = Scalar::from_uint(left.offset.bytes(), self.memory().pointer_size()); + let right_offset = Scalar::from_uint(right.offset.bytes(), self.memory().pointer_size()); let layout = self.layout_of(self.tcx.types.usize)?; return self.binary_op( Sub, @@ -103,7 +103,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' self.ptr_int_arithmetic( bin_op, left.to_ptr().expect("we checked is_ptr"), - right.to_bits(self.memory.pointer_size()).expect("we checked is_bits"), + right.to_bits(self.memory().pointer_size()).expect("we checked is_bits"), right_layout.abi.is_signed(), ) } @@ -113,7 +113,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' self.ptr_int_arithmetic( bin_op, right.to_ptr().expect("we checked is_ptr"), - left.to_bits(self.memory.pointer_size()).expect("we checked is_bits"), + left.to_bits(self.memory().pointer_size()).expect("we checked is_bits"), left_layout.abi.is_signed(), ) } @@ -142,8 +142,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // allocations sit right next to each other. The C/C++ standards are // somewhat fuzzy about this case, so I think for now this check is // "good enough". - self.memory.check_bounds_ptr(left, false)?; - self.memory.check_bounds_ptr(right, false)?; + self.memory().check_bounds_ptr(left, false)?; + self.memory().check_bounds_ptr(right, false)?; // Two live in-bounds pointers, we can compare across allocations left == right } @@ -153,7 +153,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' (Scalar::Bits { bits, size }, Scalar::Ptr(ptr)) => { assert_eq!(size as u64, self.pointer_size().bytes()); let bits = bits as u64; - let (alloc_size, alloc_align) = self.memory.get_size_and_align(ptr.alloc_id); + let (alloc_size, alloc_align) = self.memory().get_size_and_align(ptr.alloc_id); // Case I: Comparing with NULL if bits == 0 { @@ -223,15 +223,15 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' map_to_primval(left.overflowing_offset(Size::from_bytes(right as u64), self)), BitAnd if !signed => { - let ptr_base_align = self.memory.get(left.alloc_id)?.align.abi(); + let ptr_base_align = self.memory().get(left.alloc_id)?.align.abi(); let base_mask = { // FIXME: Use interpret::truncate, once that takes a Size instead of a Layout - let shift = 128 - self.memory.pointer_size().bits(); + let shift = 128 - self.memory().pointer_size().bits(); let value = !(ptr_base_align as u128 - 1); // truncate (shift left to drop out leftover values, shift right to fill with zeroes) (value << shift) >> shift }; - let ptr_size = self.memory.pointer_size().bytes() as u8; + let ptr_size = self.memory().pointer_size().bytes() as u8; trace!("Ptr BitAnd, align {}, operand {:#010x}, base_mask {:#010x}", ptr_base_align, right, base_mask); if right & base_mask == base_mask { @@ -256,9 +256,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' Rem if !signed => { // Doing modulo a divisor of the alignment is allowed. // (Intuition: Modulo a divisor leaks less information.) - let ptr_base_align = self.memory.get(left.alloc_id)?.align.abi(); + let ptr_base_align = self.memory().get(left.alloc_id)?.align.abi(); let right = right as u64; - let ptr_size = self.memory.pointer_size().bytes() as u8; + let ptr_size = self.memory().pointer_size().bytes() as u8; if right == 1 { // modulo 1 is always 0 (Scalar::Bits { bits: 0, size: ptr_size }, false) @@ -295,9 +295,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' if let Scalar::Ptr(ptr) = ptr { // Both old and new pointer must be in-bounds. // (Of the same allocation, but that part is trivial with our representation.) - self.memory.check_bounds_ptr(ptr, false)?; + self.memory().check_bounds_ptr(ptr, false)?; let ptr = ptr.signed_offset(offset, self)?; - self.memory.check_bounds_ptr(ptr, false)?; + self.memory().check_bounds_ptr(ptr, false)?; Ok(Scalar::Ptr(ptr)) } else { // An integer pointer. They can only be offset by 0, and we pretend there diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 3ed3f6d9540f..993287502ae0 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -372,11 +372,11 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' ref_kind, ptr, pointee_ty, size.bytes(), new_bor); // Make sure this reference is not dangling or so - self.memory.check_bounds(ptr, size, false)?; + self.memory().check_bounds(ptr, size, false)?; // Update the stacks. We cannot use `get_mut` becuse this might be immutable // memory. - let alloc = self.memory.get(ptr.alloc_id).expect("We checked that the ptr is fine!"); + let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); let permit_redundant = ref_kind == RefKind::Shr; // redundant shared refs are okay alloc.extra.reborrow(ptr, size, new_bor, permit_redundant)?; @@ -435,8 +435,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } // Even if we don't touch the tag, this operation is only okay if we *could* // activate it. Also it must not be dangling. - self.memory.check_bounds(ptr, size, false)?; - let alloc = self.memory.get(ptr.alloc_id).expect("We checked that the ptr is fine!"); + self.memory().check_bounds(ptr, size, false)?; + let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); let mut stacks = alloc.extra.stacks.borrow_mut(); // We need `iter_mut` because `iter` would skip gaps! for stack in stacks.iter_mut(ptr.offset, size) { From 26bb4f79dc4897b3ddbae196f793c7ee3cecdeab Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Oct 2018 18:01:32 +0200 Subject: [PATCH 0287/5092] get rid of implicit Raw at bottom of stack; locals get a uniq at their bottom --- src/fn_call.rs | 16 ++-- src/lib.rs | 21 ++++- src/stacked_borrows.rs | 82 +++++++++++++++---- tests/compile-fail/copy_nonoverlapping.rs | 4 + .../stacked_borrows/illegal_write1.rs | 11 +-- .../stacked_borrows/illegal_write2.rs | 6 +- .../stacked_borrows/illegal_write3.rs | 4 +- .../stacked_borrows/illegal_write4.rs | 4 +- .../stacked_borrows/outdated_local.rs | 9 ++ .../stacked_borrows/pointer_smuggling.rs | 3 +- .../stacked_borrows/unescaped_local.rs | 10 +++ tests/compile-fail/zst.rs | 2 +- tests/run-pass/observed_local_mut.rs | 3 + tests/run-pass/ptr_arith_offset_overflow.rs | 1 + 14 files changed, 134 insertions(+), 42 deletions(-) create mode 100644 tests/compile-fail/stacked_borrows/outdated_local.rs create mode 100644 tests/compile-fail/stacked_borrows/unescaped_local.rs diff --git a/src/fn_call.rs b/src/fn_call.rs index 04601b3cd1ff..88c31f63fbb1 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -126,7 +126,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } else { let align = self.tcx.data_layout.pointer_align; let ptr = self.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into())?; - self.write_scalar(Scalar::Ptr(ptr), dest)?; + self.write_scalar(Scalar::Ptr(ptr.with_default_tag()), dest)?; } } @@ -153,7 +153,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let ptr = self.memory_mut().allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), MiriMemoryKind::Rust.into())?; - self.write_scalar(Scalar::Ptr(ptr), dest)?; + self.write_scalar(Scalar::Ptr(ptr.with_default_tag()), dest)?; } "__rust_alloc_zeroed" => { let size = self.read_scalar(args[0])?.to_usize(&self)?; @@ -164,9 +164,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory_mut().allocate(Size::from_bytes(size), - Align::from_bytes(align, align).unwrap(), - MiriMemoryKind::Rust.into())?; + let ptr = self.memory_mut().allocate( + Size::from_bytes(size), + Align::from_bytes(align, align).unwrap(), + MiriMemoryKind::Rust.into() + )?.with_default_tag(); self.memory_mut().write_repeat(ptr.into(), 0, Size::from_bytes(size))?; self.write_scalar(Scalar::Ptr(ptr), dest)?; } @@ -205,7 +207,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo Align::from_bytes(align, align).unwrap(), MiriMemoryKind::Rust.into(), )?; - self.write_scalar(Scalar::Ptr(new_ptr), dest)?; + self.write_scalar(Scalar::Ptr(new_ptr.with_default_tag()), dest)?; } "syscall" => { @@ -390,7 +392,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo Size::from_bytes((value.len() + 1) as u64), Align::from_bytes(1, 1).unwrap(), MiriMemoryKind::Env.into(), - )?; + )?.with_default_tag(); self.memory_mut().write_bytes(value_copy.into(), &value)?; let trailing_zero_ptr = value_copy.offset(Size::from_bytes(value.len() as u64), &self)?.into(); self.memory_mut().write_bytes(trailing_zero_ptr, &[0])?; diff --git a/src/lib.rs b/src/lib.rs index 8925afa5f600..128b338f943d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -108,7 +108,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let mut args = ecx.frame().mir.args_iter(); // First argument: pointer to main() - let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance); + let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance).with_default_tag(); let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?; @@ -119,7 +119,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // FIXME: extract main source file path // Third argument (argv): &[b"foo"] let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - let foo = ecx.memory_mut().allocate_static_bytes(b"foo\0"); + let foo = ecx.memory_mut().allocate_static_bytes(b"foo\0").with_default_tag(); let foo_ty = ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8); let foo_layout = ecx.layout_of(foo_ty)?; let foo_place = ecx.allocate(foo_layout, MiriMemoryKind::Env.into())?; @@ -404,7 +404,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { Ok(()) } - fn static_with_default_tag( + fn adjust_static_allocation( alloc: &'_ Allocation ) -> Cow<'_, Allocation> { let alloc: Allocation = Allocation { @@ -477,4 +477,19 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { Ok(MemPlace { ptr, ..place }) } } + + #[inline(always)] + fn tag_new_allocation( + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ptr: Pointer, + kind: MemoryKind, + ) -> EvalResult<'tcx, Pointer> { + if !ecx.machine.validate { + // No tracking + Ok(ptr.with_default_tag()) + } else { + let tag = ecx.tag_new_allocation(ptr.alloc_id, kind); + Ok(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag)) + } + } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 993287502ae0..127958476bcb 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -4,7 +4,7 @@ use rustc::ty::{Ty, layout::Size}; use rustc::hir; use super::{ - MemoryAccess, RangeMap, EvalResult, + MemoryAccess, MemoryKind, MiriMemoryKind, RangeMap, EvalResult, AllocId, Pointer, }; @@ -104,7 +104,7 @@ struct Stack { impl Default for Stack { fn default() -> Self { Stack { - borrows: Vec::new(), + borrows: vec![BorStackItem::Mut(Mut::Raw)], frozen_since: None, } } @@ -157,8 +157,8 @@ impl<'tcx> Stack { } } } - // Simulate a "virtual raw" element at the bottom of the stack. - acc_m.is_raw() + // Nothing to be found. + false } /// Reactive `bor` for this stack. If `force_mut` is set, we want to aggressively @@ -204,12 +204,8 @@ impl<'tcx> Stack { } } } - // Nothing to be found. Simulate a "virtual raw" element at the bottom of the stack. - if acc_m.is_raw() { - Ok(()) - } else { - err!(MachineError(format!("Borrow-to-reactivate does not exist on the stack"))) - } + // Nothing to be found. + err!(MachineError(format!("Borrow-to-reactivate does not exist on the stack"))) } /// Initiate `bor`; mostly this means freezing or pushing. @@ -301,7 +297,15 @@ impl<'tcx> Stacks { } else { // If we are creating a uniq ref, we certainly want to unfreeze. // Even if we are doing so from a raw. - // FIXME: The blog post says we should `reset` if this is a local. + // Notice that if this is a local, whenever we access it directly the + // tag here will be the bottommost `Uniq` for that local. That `Uniq` + // never is accessible by the program, so it will not be used by any + // other access. IOW, whenever we directly use a local this will pop + // everything else off the stack, invalidating all previous pointers + // and, in particular, *all* raw pointers. This subsumes the explicit + // `reset` which the blog post [1] says to perform when accessing a local. + // + // [1] https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html stack.reactivate(ptr.tag, /*force_mut*/new_bor.is_uniq())?; stack.initiate(new_bor)?; } @@ -309,6 +313,19 @@ impl<'tcx> Stacks { Ok(()) } + + /// Pushes the first borrow to the stacks, must be a mutable one. + pub fn first_borrow( + &mut self, + r#mut: Mut, + size: Size + ) { + for stack in self.stacks.get_mut().iter_mut(Size::ZERO, size) { + assert!(stack.borrows.len() == 1 && stack.frozen_since.is_none()); + assert_eq!(stack.borrows.pop().unwrap(), BorStackItem::Mut(Mut::Raw)); + stack.borrows.push(BorStackItem::Mut(r#mut)); + } + } } pub trait EvalContextExt<'tcx> { @@ -334,6 +351,12 @@ pub trait EvalContextExt<'tcx> { size: Size, ref_kind: RefKind, ) -> EvalResult<'tcx, Borrow>; + + fn tag_new_allocation( + &mut self, + id: AllocId, + kind: MemoryKind, + ) -> Borrow; } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { @@ -400,7 +423,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Notably, the compiler can introduce such transmutes by optimizing away `&[mut]*`. // That can transmute a raw ptr to a (shared/mut) ref, and a mut ref to a shared one. match (ref_kind, ptr.tag) { - (RefKind::Raw, Borrow::Mut(Mut::Raw)) | + (RefKind::Raw, _) => { + // Don't use the tag, this is a raw access! Even if there is a tag, + // that means transmute happened and we ignore the tag. + // Also don't do any further validation, this is raw after all. + return Ok(Borrow::Mut(Mut::Raw)); + } (RefKind::Mut, Borrow::Mut(Mut::Uniq(_))) | (RefKind::Shr, Borrow::Frz(_)) | (RefKind::Shr, Borrow::Mut(Mut::Raw)) => { @@ -408,15 +436,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // FIXME: We probably shouldn't accept this if we got a raw shr without // interior mutability. } - (_, Borrow::Mut(Mut::Raw)) => { - // Raw transmuted to (shr/mut) ref. Keep this as raw access. + (RefKind::Mut, Borrow::Mut(Mut::Raw)) => { + // Raw transmuted to mut ref. Keep this as raw access. // We cannot reborrow here; there might be a raw in `&(*var).1` where // `var` is an `&mut`. The other field of the struct might be already frozen, // also using `var`, and that would be okay. } - (RefKind::Raw, _) => { - // Someone transmuted a ref to a raw. Treat this like a ref, their fault. - } (RefKind::Shr, Borrow::Mut(Mut::Uniq(_))) => { // A mut got transmuted to shr. High time we freeze this location! // Make this a delayed reborrow. Redundant reborows to shr are okay, @@ -451,4 +476,27 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // All is good. Ok(ptr.tag) } + + fn tag_new_allocation( + &mut self, + id: AllocId, + kind: MemoryKind, + ) -> Borrow { + let r#mut = match kind { + MemoryKind::Stack => { + // New unique borrow + let time = self.machine.stacked_borrows.increment_clock(); + Mut::Uniq(time) + } + _ => { + // Raw for everything else + Mut::Raw + } + }; + // Make this the active borrow for this allocation + let alloc = self.memory_mut().get_mut(id).expect("This is a new allocation, it must still exist"); + let size = Size::from_bytes(alloc.bytes.len() as u64); + alloc.extra.first_borrow(r#mut, size); + Borrow::Mut(r#mut) + } } diff --git a/tests/compile-fail/copy_nonoverlapping.rs b/tests/compile-fail/copy_nonoverlapping.rs index 18fbc61b6d07..704711640f7d 100644 --- a/tests/compile-fail/copy_nonoverlapping.rs +++ b/tests/compile-fail/copy_nonoverlapping.rs @@ -10,6 +10,10 @@ #![feature(core_intrinsics)] +// FIXME: Validation disabled because it doesn't let us escape an entire slice +// to the raw universe. +// compile-flags: -Zmiri-disable-validation + //error-pattern: copy_nonoverlapping called on overlapping ranges fn main() { diff --git a/tests/compile-fail/stacked_borrows/illegal_write1.rs b/tests/compile-fail/stacked_borrows/illegal_write1.rs index 86b96e2880ec..ff3a3cd82245 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write1.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write1.rs @@ -1,11 +1,12 @@ fn evil(x: &u32) { - let x : &mut u32 = unsafe { &mut *(x as *const _ as *mut _) }; - *x = 42; // mutating shared ref without `UnsafeCell` + // mutating shared ref without `UnsafeCell` + let x : *mut u32 = x as *const _ as *mut _; + unsafe { *x = 42; } } fn main() { - let target = 42; - let ref_ = ⌖ - evil(ref_); // invalidates shared ref + let target = Box::new(42); // has an implicit raw + let ref_ = &*target; + evil(ref_); // invalidates shared ref, activates raw let _x = *ref_; //~ ERROR Shr reference with non-reactivatable tag Frz } diff --git a/tests/compile-fail/stacked_borrows/illegal_write2.rs b/tests/compile-fail/stacked_borrows/illegal_write2.rs index 22648ba71184..f4fefaad5e22 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write2.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write2.rs @@ -4,7 +4,7 @@ fn main() { let target = &mut 42; let target2 = target as *mut _; drop(&mut *target); // reborrow - // Now make sure our ref is still the only one - unsafe { *target2 = 13; } // invalidate our ref - let _val = *target; //~ ERROR Mut reference with non-reactivatable tag Mut(Uniq + // Now make sure our ref is still the only one. + unsafe { *target2 = 13; } //~ ERROR does not exist on the stack + let _val = *target; } diff --git a/tests/compile-fail/stacked_borrows/illegal_write3.rs b/tests/compile-fail/stacked_borrows/illegal_write3.rs index 26c30a4122b4..a653aa5003f6 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write3.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write3.rs @@ -3,6 +3,6 @@ fn main() { // Make sure raw ptr with raw tag cannot mutate frozen location without breaking the shared ref. let r#ref = ⌖ // freeze let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag - unsafe { *ptr = 42; } - let _val = *r#ref; //~ ERROR Shr reference with non-reactivatable tag Frz + unsafe { *ptr = 42; } //~ ERROR does not exist on the stack + let _val = *r#ref; } diff --git a/tests/compile-fail/stacked_borrows/illegal_write4.rs b/tests/compile-fail/stacked_borrows/illegal_write4.rs index b2ffac865bd4..2006d7262f81 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write4.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write4.rs @@ -26,6 +26,6 @@ fn main() { let _val = *r#ref; // Make sure it is still frozen. // We only actually unfreeze once we muteate through the bad pointer. - unsafe { *bad_ptr = 42 }; - let _val = *r#ref; //~ ERROR Shr reference with non-reactivatable tag Frz + unsafe { *bad_ptr = 42 }; //~ ERROR does not exist on the stack + let _val = *r#ref; } diff --git a/tests/compile-fail/stacked_borrows/outdated_local.rs b/tests/compile-fail/stacked_borrows/outdated_local.rs new file mode 100644 index 000000000000..64a8ff69108e --- /dev/null +++ b/tests/compile-fail/stacked_borrows/outdated_local.rs @@ -0,0 +1,9 @@ +fn main() { + let mut x = 0; + let y: *const i32 = &x; + x = 1; // this invalidates y by reactivating the lowermost uniq borrow for this local + + assert_eq!(unsafe { *y }, 1); //~ ERROR does not exist on the stack + + assert_eq!(x, 1); +} diff --git a/tests/compile-fail/stacked_borrows/pointer_smuggling.rs b/tests/compile-fail/stacked_borrows/pointer_smuggling.rs index 678b9b21ba8c..68f3d2923b15 100644 --- a/tests/compile-fail/stacked_borrows/pointer_smuggling.rs +++ b/tests/compile-fail/stacked_borrows/pointer_smuggling.rs @@ -10,7 +10,7 @@ fn fun1(x: &mut u8) { fn fun2() { // Now we use a pointer we are not allowed to use - let _x = unsafe { *PTR }; + let _x = unsafe { *PTR }; //~ ERROR does not exist on the stack } fn main() { @@ -18,5 +18,4 @@ fn main() { fun1(val); *val = 2; // this invalidates any raw ptrs `fun1` might have created. fun2(); // if they now use a raw ptr they break our reference - *val = 3; //~ ERROR Mut reference with non-reactivatable tag Mut(Uniq } diff --git a/tests/compile-fail/stacked_borrows/unescaped_local.rs b/tests/compile-fail/stacked_borrows/unescaped_local.rs new file mode 100644 index 000000000000..8627cc44c2e5 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/unescaped_local.rs @@ -0,0 +1,10 @@ +use std::mem; + +// Make sure we cannot use raw ptrs to access a local that +// has never been escaped to the raw world. +fn main() { + let mut x = 42; + let ptr = &mut x; + let raw: *mut i32 = unsafe { mem::transmute(ptr) }; + unsafe { *raw = 13; } //~ ERROR does not exist on the stack +} diff --git a/tests/compile-fail/zst.rs b/tests/compile-fail/zst.rs index 0f4c945c85b4..544d65a1bffa 100644 --- a/tests/compile-fail/zst.rs +++ b/tests/compile-fail/zst.rs @@ -1,4 +1,4 @@ fn main() { let x = &() as *const () as *const i32; - let _ = unsafe { *x }; //~ ERROR outside bounds of allocation + let _ = unsafe { *x }; //~ ERROR access memory with alignment 1, but alignment 4 is required } diff --git a/tests/run-pass/observed_local_mut.rs b/tests/run-pass/observed_local_mut.rs index a4ecf1e635d2..c58e8c84bb2e 100644 --- a/tests/run-pass/observed_local_mut.rs +++ b/tests/run-pass/observed_local_mut.rs @@ -1,3 +1,6 @@ +// Validation catches this (correctly) as UB. +// compile-flags: -Zmiri-disable-validation + // This test is intended to guard against the problem described in commit // 39bb1254d1eaf74f45a4e741097e33fc942168d5. // diff --git a/tests/run-pass/ptr_arith_offset_overflow.rs b/tests/run-pass/ptr_arith_offset_overflow.rs index 3383c3b80148..9eabc9142604 100644 --- a/tests/run-pass/ptr_arith_offset_overflow.rs +++ b/tests/run-pass/ptr_arith_offset_overflow.rs @@ -1,6 +1,7 @@ fn main() { let v = [1i16, 2]; let x = &v[1] as *const i16; + let _ = &v[0] as *const i16; // we need to leak the 2nd thing too or it cannot be accessed through a raw ptr // Adding 2*isize::max and then 1 is like substracting 1 let x = x.wrapping_offset(isize::max_value()); let x = x.wrapping_offset(isize::max_value()); From 44b3c38b440f9b251ad62e5bd78a0af2015d545d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Oct 2018 18:34:48 +0200 Subject: [PATCH 0288/5092] make sure raw ptrs only have to be valid as far as they are used --- tests/run-pass/deref_partially_dangling_raw.rs | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/run-pass/deref_partially_dangling_raw.rs diff --git a/tests/run-pass/deref_partially_dangling_raw.rs b/tests/run-pass/deref_partially_dangling_raw.rs new file mode 100644 index 000000000000..8639a289363b --- /dev/null +++ b/tests/run-pass/deref_partially_dangling_raw.rs @@ -0,0 +1,9 @@ +// Deref a raw ptr to access a field of a large struct, where the field +// is allocated but not the entire struct is. +// For now, we want to allow this. + +fn main() { + let x = (1, 1); + let xptr = &x as *const _ as *const (i32, i32, i32); + let _val = unsafe { (*xptr).1 }; +} From 8cd73e534f3ecc96286c626376a05c1adb48ca64 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Oct 2018 18:51:06 +0200 Subject: [PATCH 0289/5092] use as(_mut)_ptr on slices to entirely escape them to raw --- tests/compile-fail/copy_nonoverlapping.rs | 8 ++------ tests/run-pass/ptr_arith_offset_overflow.rs | 3 +-- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/tests/compile-fail/copy_nonoverlapping.rs b/tests/compile-fail/copy_nonoverlapping.rs index 704711640f7d..8e8912c81fe9 100644 --- a/tests/compile-fail/copy_nonoverlapping.rs +++ b/tests/compile-fail/copy_nonoverlapping.rs @@ -10,17 +10,13 @@ #![feature(core_intrinsics)] -// FIXME: Validation disabled because it doesn't let us escape an entire slice -// to the raw universe. -// compile-flags: -Zmiri-disable-validation - //error-pattern: copy_nonoverlapping called on overlapping ranges fn main() { let mut data = [0u8; 16]; unsafe { - let a = &data[0] as *const _; - let b = &mut data[1] as *mut _; + let a = data.as_mut_ptr(); + let b = a.wrapping_offset(1) as *mut _; std::ptr::copy_nonoverlapping(a, b, 2); } } diff --git a/tests/run-pass/ptr_arith_offset_overflow.rs b/tests/run-pass/ptr_arith_offset_overflow.rs index 9eabc9142604..6b778248be5c 100644 --- a/tests/run-pass/ptr_arith_offset_overflow.rs +++ b/tests/run-pass/ptr_arith_offset_overflow.rs @@ -1,7 +1,6 @@ fn main() { let v = [1i16, 2]; - let x = &v[1] as *const i16; - let _ = &v[0] as *const i16; // we need to leak the 2nd thing too or it cannot be accessed through a raw ptr + let x = v.as_ptr().wrapping_offset(1); // ptr to the 2nd element // Adding 2*isize::max and then 1 is like substracting 1 let x = x.wrapping_offset(isize::max_value()); let x = x.wrapping_offset(isize::max_value()); From cc328f6374263f0c4aa9f37b9965e25b25b0515f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Oct 2018 11:18:50 +0200 Subject: [PATCH 0290/5092] test passing invalid refs around --- .../compile-fail/stacked_borrows/load_invalid_mut.rs | 9 +++++++++ .../compile-fail/stacked_borrows/pass_invalid_mut.rs | 10 ++++++++++ .../stacked_borrows/return_invalid_mut.rs | 11 +++++++++++ 3 files changed, 30 insertions(+) create mode 100644 tests/compile-fail/stacked_borrows/load_invalid_mut.rs create mode 100644 tests/compile-fail/stacked_borrows/pass_invalid_mut.rs create mode 100644 tests/compile-fail/stacked_borrows/return_invalid_mut.rs diff --git a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs new file mode 100644 index 000000000000..e52b84a907e9 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs @@ -0,0 +1,9 @@ +// Make sure that we cannot load from memory a `&mut` that got already invalidated. +fn main() { + let x = &mut 42; + let xraw = x as *mut _; + let xref = unsafe { &mut *xraw }; + let xref_in_mem = Box::new(xref); + let _val = *x; // invalidate xraw + let _val = *xref_in_mem; //~ ERROR Mut reference with non-reactivatable tag Mut(Uniq +} diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs new file mode 100644 index 000000000000..f3de3f0c4ac3 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs @@ -0,0 +1,10 @@ +// Make sure that we cannot pass by argument a `&mut` that got already invalidated. +fn foo(_: &mut i32) {} + +fn main() { + let x = &mut 42; + let xraw = x as *mut _; + let xref = unsafe { &mut *xraw }; + let _val = *x; // invalidate xraw + foo(xref); //~ ERROR Mut reference with non-reactivatable tag Mut(Uniq +} diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs new file mode 100644 index 000000000000..6a4123d325b4 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs @@ -0,0 +1,11 @@ +// Make sure that we cannot return a `&mut` that got already invalidated. +fn foo(x: &mut (i32, i32)) -> &mut i32 { + let xraw = x as *mut (i32, i32); + let ret = unsafe { &mut (*xraw).1 }; + let _val = *x; // invalidate xraw and its children + ret //~ ERROR Mut reference with non-reactivatable tag Mut(Uniq +} + +fn main() { + foo(&mut (1, 2)); +} From fe83ef323cec57465948bdba654201eed22c3355 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Oct 2018 13:09:17 +0200 Subject: [PATCH 0291/5092] also run compile-fail tests with and without optimizations --- src/stacked_borrows.rs | 2 + .../stacked_borrows/alias_through_mutation.rs | 3 + .../stacked_borrows/buggy_as_mut_slice.rs | 3 + .../stacked_borrows/buggy_split_at_mut.rs | 3 + .../stacked_borrows/illegal_write2.rs | 3 + tests/compiletest.rs | 64 +++++++++++-------- tests/run-pass-fullmir/integer-ops.rs | 3 - 7 files changed, 52 insertions(+), 29 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 127958476bcb..316316351863 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -446,6 +446,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // A mut got transmuted to shr. High time we freeze this location! // Make this a delayed reborrow. Redundant reborows to shr are okay, // so we do not have to be worried about doing too much. + // FIXME: Reconsider if we really want to mutate things while doing just a deref, + // which, in particular, validation does. trace!("tag_dereference: Lazy freezing of {:?}", ptr); return self.tag_reference(ptr, pointee_ty, size, ref_kind); } diff --git a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs index 3fcf20e15625..83132195fe46 100644 --- a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs +++ b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs @@ -1,3 +1,6 @@ +// With optimizations, we just store a raw in `x`, and there is no problem. +// compile-flags: -Zmir-opt-level=0 + #![allow(unused_variables)] // This makes a ref that was passed to us via &mut alias with things it should not alias with diff --git a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs index 5f729af30bbe..9e94aa8885d2 100644 --- a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs +++ b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs @@ -1,3 +1,6 @@ +// FIXME: Without retagging, optimization kills finding this problem +// compile-flags: -Zmir-opt-level=0 + #![allow(unused_variables)] mod safe { diff --git a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs index 0a890b1cebaa..9fbcec4a8ef8 100644 --- a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs @@ -1,3 +1,6 @@ +// FIXME: Without retagging, optimization kills finding this problem +// compile-flags: -Zmir-opt-level=0 + #![allow(unused_variables)] mod safe { diff --git a/tests/compile-fail/stacked_borrows/illegal_write2.rs b/tests/compile-fail/stacked_borrows/illegal_write2.rs index f4fefaad5e22..ac9c3397f534 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write2.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write2.rs @@ -1,3 +1,6 @@ +// The reborow gets optimized away, so we can only detect this issue without optimizations +// compile-flags: -Zmir-opt-level=0 + #![allow(unused_variables)] fn main() { diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 7a7d7e49b2db..8070f817bcf6 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -37,7 +37,7 @@ fn have_fullmir() -> bool { std::env::var("MIRI_SYSROOT").is_ok() || rustc_test_suite().is_some() } -fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: bool) { +fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: bool, opt: bool) { if need_fullmir && !have_fullmir() { eprintln!("{}", format!( "## Skipping compile-fail tests in {} against miri for target {} due to missing mir", @@ -47,24 +47,34 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullm return; } + let opt_str = if opt { " with optimizations" } else { "" }; eprintln!("{}", format!( - "## Running compile-fail tests in {} against miri for target {}", + "## Running compile-fail tests in {} against miri for target {}{}", path, - target + target, + opt_str ).green().bold()); + + let mut flags = Vec::new(); + flags.push(format!("--sysroot {}", sysroot.display())); + flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs + flags.push("-Zmir-emit-validate=1".to_owned()); + if opt { + // Optimizing too aggressivley makes UB detection harder, but test at least + // the default value. + flags.push("-Zmir-opt-level=1".to_owned()); + } else { + flags.push("-Zmir-opt-level=0".to_owned()); + } + let mut config = compiletest::Config::default().tempdir(); config.mode = "compile-fail".parse().expect("Invalid mode"); config.rustc_path = miri_path(); - let mut flags = Vec::new(); if rustc_test_suite().is_some() { config.run_lib_path = rustc_lib_path(); config.compile_lib_path = rustc_lib_path(); } - flags.push(format!("--sysroot {}", sysroot.display())); - flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs config.src_base = PathBuf::from(path.to_string()); - flags.push("-Zmir-opt-level=0".to_owned()); // optimization circumvents some stacked borrow checks - flags.push("-Zmir-emit-validate=1".to_owned()); config.target_rustcflags = Some(flags.join(" ")); config.target = target.to_owned(); config.host = host.to_owned(); @@ -88,6 +98,21 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: target, opt_str ).green().bold()); + + let mut flags = Vec::new(); + flags.push(format!("--sysroot {}", sysroot.display())); + flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs + flags.push("-Zmir-emit-validate=1".to_owned()); + if opt { + // FIXME: Using level 1 (instead of 3) for now, as the optimizer is pretty broken + // and crashes... + // Level 0 and 1 are not the same, so this still gives us *some* coverage. + // See https://github.com/rust-lang/rust/issues/50411 + flags.push("-Zmir-opt-level=1".to_owned()); + } else { + flags.push("-Zmir-opt-level=0".to_owned()); + } + let mut config = compiletest::Config::default().tempdir(); config.mode = "ui".parse().expect("Invalid mode"); config.src_base = PathBuf::from(path); @@ -98,20 +123,6 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: config.run_lib_path = rustc_lib_path(); config.compile_lib_path = rustc_lib_path(); } - let mut flags = Vec::new(); - flags.push(format!("--sysroot {}", sysroot.display())); - flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs - if opt { - // FIXME: Using level 1 (instead of 3) for now, as the optimizer is pretty broken - // and crashes... - // Level 0 and 1 are not the same, so this still gives us *some* coverage. - // See https://github.com/rust-lang/rust/issues/50411 - flags.push("-Zmir-opt-level=1".to_owned()); - } else { - flags.push("-Zmir-opt-level=0".to_owned()); - // For now, only validate without optimizations. Inlining breaks validation. - flags.push("-Zmir-emit-validate=1".to_owned()); - } config.target_rustcflags = Some(flags.join(" ")); compiletest::run_tests(&config); } @@ -173,13 +184,13 @@ fn run_pass_miri(opt: bool) { miri_pass(&sysroot, "tests/run-pass-fullmir", &host, &host, true, opt); } -fn compile_fail_miri() { +fn compile_fail_miri(opt: bool) { let sysroot = get_sysroot(); let host = get_host(); // FIXME: run tests for other targets, too - compile_fail(&sysroot, "tests/compile-fail", &host, &host, false); - compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true); + compile_fail(&sysroot, "tests/compile-fail", &host, &host, false, opt); + compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true, opt); } #[test] @@ -191,5 +202,6 @@ fn test() { run_pass_miri(false); run_pass_miri(true); - compile_fail_miri(); + compile_fail_miri(false); + compile_fail_miri(true); } diff --git a/tests/run-pass-fullmir/integer-ops.rs b/tests/run-pass-fullmir/integer-ops.rs index 7a2335c829ef..0264099eb68d 100644 --- a/tests/run-pass-fullmir/integer-ops.rs +++ b/tests/run-pass-fullmir/integer-ops.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME: remove -Zmir-opt-level once https://github.com/rust-lang/rust/issues/43359 is fixed -// compile-flags: -Zmir-opt-level=0 - use std::i32; pub fn main() { From 5388037f8a16d3bf443f348e28873d255db044d0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Oct 2018 15:59:50 +0200 Subject: [PATCH 0292/5092] remove code duplication by letting reactivatable() compute what reactivate() has to do --- src/stacked_borrows.rs | 89 ++++++++----------- .../stacked_borrows/alias_through_mutation.rs | 2 +- .../stacked_borrows/buggy_as_mut_slice.rs | 2 +- .../stacked_borrows/buggy_split_at_mut.rs | 2 +- .../stacked_borrows/illegal_write1.rs | 2 +- .../stacked_borrows/load_invalid_mut.rs | 2 +- .../stacked_borrows/pass_invalid_mut.rs | 2 +- .../stacked_borrows/return_invalid_mut.rs | 2 +- .../stacked_borrows/shared_confusion.rs | 2 +- 9 files changed, 47 insertions(+), 58 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 316316351863..f634f17109c7 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -137,75 +137,64 @@ impl<'tcx> Stack { } /// Check if `bor` could be activated by unfreezing and popping. - /// This should be in sync with `reactivate`! - fn reactivatable(&self, bor: Borrow) -> bool { - if self.check(bor) { - return true; - } - - let acc_m = match bor { - Borrow::Frz(_) => return false, - Borrow::Mut(acc_m) => acc_m - }; - // This is where we would unfreeze. - for &itm in self.borrows.iter().rev() { - match itm { - BorStackItem::FnBarrier(_) => return false, - BorStackItem::Mut(loc_m) => { - if loc_m == acc_m { return true; } - // Go on looking. - } - } - } - // Nothing to be found. - false - } - - /// Reactive `bor` for this stack. If `force_mut` is set, we want to aggressively - /// unfreeze this location (because we are about to mutate, so a frozen `Raw` is not okay). - fn reactivate(&mut self, bor: Borrow, force_mut: bool) -> EvalResult<'tcx> { + /// `force_mut` indicates whether being frozen is potentially acceptable. + /// Returns `Err` if the answer is "no"; otherwise the data says + /// what needs to happen to activate this: `None` = nothing, + /// `Some(n)` = unfreeze and make item `n` the top item of the stack. + fn reactivatable(&self, bor: Borrow, force_mut: bool) -> Result, String> { // Unless mutation is bound to happen, do NOT change anything if `bor` is already active. // In particular, if it is a `Mut(Raw)` and we are frozen, this should be a NOP. if !force_mut && self.check(bor) { - return Ok(()); + return Ok(None); } let acc_m = match bor { Borrow::Frz(since) => - if force_mut { - return err!(MachineError(format!("Using a shared borrow for mutation"))) + return Err(if force_mut { + format!("Using a shared borrow for mutation") } else { - return err!(MachineError(format!( + format!( "Location should be frozen since {} but {}", since, match self.frozen_since { None => format!("it is not frozen at all"), Some(since) => format!("it is only frozen since {}", since), } - ))) - } - Borrow::Mut(acc_m) => acc_m, + ) + }), + Borrow::Mut(acc_m) => acc_m }; - // We definitely have to unfreeze this, even if we use the topmost item. - if self.frozen_since.is_some() { - trace!("reactivate: Unfreezing"); - } - self.frozen_since = None; - // Pop until we see the one we are looking for. - while let Some(&itm) = self.borrows.last() { + // This is where we would unfreeze. + for (idx, &itm) in self.borrows.iter().enumerate().rev() { match itm { - BorStackItem::FnBarrier(_) => { - return err!(MachineError(format!("Trying to reactivate a borrow that lives behind a barrier"))); - } + BorStackItem::FnBarrier(_) => + return Err(format!("Trying to reactivate a mutable borrow ({:?}) that lives behind a barrier", acc_m)), BorStackItem::Mut(loc_m) => { - if loc_m == acc_m { return Ok(()); } - trace!("reactivate: Popping {:?}", itm); - self.borrows.pop(); + if loc_m == acc_m { return Ok(Some(idx)); } } } } // Nothing to be found. - err!(MachineError(format!("Borrow-to-reactivate does not exist on the stack"))) + Err(format!("Mutable borrow-to-reactivate ({:?}) does not exist on the stack", acc_m)) + } + + /// Reactive `bor` for this stack. If `force_mut` is set, we want to aggressively + /// unfreeze this location (because we are about to mutate, so a frozen `Raw` is not okay). + fn reactivate(&mut self, bor: Borrow, force_mut: bool) -> EvalResult<'tcx> { + let action = match self.reactivatable(bor, force_mut) { + Ok(action) => action, + Err(err) => return err!(MachineError(err)), + }; + + match action { + None => {}, // nothing to do + Some(top) => { + self.frozen_since = None; + self.borrows.truncate(top+1); + } + } + + Ok(()) } /// Initiate `bor`; mostly this means freezing or pushing. @@ -471,8 +460,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // be shared reborrows that we are about to invalidate with this access. // We cannot invalidate them aggressively here because the deref might also be // to just create more shared refs. - if !stack.reactivatable(ptr.tag) { - return err!(MachineError(format!("Encountered {:?} reference with non-reactivatable tag {:?}", ref_kind, ptr.tag))) + if let Err(err) = stack.reactivatable(ptr.tag, /*force_mut*/false) { + return err!(MachineError(format!("Encountered {:?} reference with non-reactivatable tag: {}", ref_kind, err))) } } // All is good. diff --git a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs index 83132195fe46..7d56f30b3e69 100644 --- a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs +++ b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs @@ -14,5 +14,5 @@ fn main() { retarget(&mut target_alias, target); // now `target_alias` points to the same thing as `target` *target = 13; - let _val = *target_alias; //~ ERROR Shr reference with non-reactivatable tag Frz + let _val = *target_alias; //~ ERROR Shr reference with non-reactivatable tag } diff --git a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs index 9e94aa8885d2..dc1e3cc81e9e 100644 --- a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs +++ b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs @@ -17,6 +17,6 @@ fn main() { let v = vec![0,1,2]; let v1 = safe::as_mut_slice(&v); let v2 = safe::as_mut_slice(&v); - v1[1] = 5; //~ ERROR Mut reference with non-reactivatable tag Mut(Uniq + v1[1] = 5; //~ ERROR Mut reference with non-reactivatable tag v1[1] = 6; } diff --git a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs index 9fbcec4a8ef8..a697ba9167c0 100644 --- a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs @@ -14,7 +14,7 @@ mod safe { assert!(mid <= len); (from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" - //~^ ERROR Mut reference with non-reactivatable tag Mut(Uniq + //~^ ERROR Mut reference with non-reactivatable tag from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) } } diff --git a/tests/compile-fail/stacked_borrows/illegal_write1.rs b/tests/compile-fail/stacked_borrows/illegal_write1.rs index ff3a3cd82245..131e89572a50 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write1.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write1.rs @@ -8,5 +8,5 @@ fn main() { let target = Box::new(42); // has an implicit raw let ref_ = &*target; evil(ref_); // invalidates shared ref, activates raw - let _x = *ref_; //~ ERROR Shr reference with non-reactivatable tag Frz + let _x = *ref_; //~ ERROR Shr reference with non-reactivatable tag } diff --git a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs index e52b84a907e9..060cec962c47 100644 --- a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs @@ -5,5 +5,5 @@ fn main() { let xref = unsafe { &mut *xraw }; let xref_in_mem = Box::new(xref); let _val = *x; // invalidate xraw - let _val = *xref_in_mem; //~ ERROR Mut reference with non-reactivatable tag Mut(Uniq + let _val = *xref_in_mem; //~ ERROR Mut reference with non-reactivatable tag } diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs index f3de3f0c4ac3..bc950771add4 100644 --- a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs @@ -6,5 +6,5 @@ fn main() { let xraw = x as *mut _; let xref = unsafe { &mut *xraw }; let _val = *x; // invalidate xraw - foo(xref); //~ ERROR Mut reference with non-reactivatable tag Mut(Uniq + foo(xref); //~ ERROR Mut reference with non-reactivatable tag } diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs index 6a4123d325b4..c02892671e90 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> &mut i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &mut (*xraw).1 }; let _val = *x; // invalidate xraw and its children - ret //~ ERROR Mut reference with non-reactivatable tag Mut(Uniq + ret //~ ERROR Mut reference with non-reactivatable tag } fn main() { diff --git a/tests/compile-fail/stacked_borrows/shared_confusion.rs b/tests/compile-fail/stacked_borrows/shared_confusion.rs index 5098f493ccd7..e3e4c4da7765 100644 --- a/tests/compile-fail/stacked_borrows/shared_confusion.rs +++ b/tests/compile-fail/stacked_borrows/shared_confusion.rs @@ -13,7 +13,7 @@ fn test(r: &mut RefCell) { } // Our old raw should be dead by now unsafe { *x_evil = 0; } // this falls back to some Raw higher up the stack - *x_inner = 12; //~ ERROR Mut reference with non-reactivatable tag Mut(Uniq + *x_inner = 12; //~ ERROR Mut reference with non-reactivatable tag } fn main() { From 356369dd08f968b74b8bdee3a177f9919194914b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Oct 2018 16:01:22 +0200 Subject: [PATCH 0293/5092] test against passing invalid shared refs around --- .../compile-fail/stacked_borrows/load_invalid_shr.rs | 9 +++++++++ .../compile-fail/stacked_borrows/pass_invalid_shr.rs | 10 ++++++++++ .../stacked_borrows/return_invalid_shr.rs | 11 +++++++++++ 3 files changed, 30 insertions(+) create mode 100644 tests/compile-fail/stacked_borrows/load_invalid_shr.rs create mode 100644 tests/compile-fail/stacked_borrows/pass_invalid_shr.rs create mode 100644 tests/compile-fail/stacked_borrows/return_invalid_shr.rs diff --git a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs new file mode 100644 index 000000000000..785a15c4704a --- /dev/null +++ b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs @@ -0,0 +1,9 @@ +// Make sure that we cannot load from memory a `&` that got already invalidated. +fn main() { + let x = &mut 42; + let xraw = x as *mut _; + let xref = unsafe { &*xraw }; + let xref_in_mem = Box::new(xref); + let _val = *x; // invalidate xraw + let _val = *xref_in_mem; //~ ERROR Shr reference with non-reactivatable tag: Location should be frozen +} diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs b/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs new file mode 100644 index 000000000000..8b7a846d849c --- /dev/null +++ b/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs @@ -0,0 +1,10 @@ +// Make sure that we cannot pass by argument a `&` that got already invalidated. +fn foo(_: &i32) {} + +fn main() { + let x = &mut 42; + let xraw = &*x as *const _; + let xref = unsafe { &*xraw }; + let _val = *x; // invalidate xraw + foo(xref); //~ ERROR Shr reference with non-reactivatable tag: Location should be frozen +} diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr.rs b/tests/compile-fail/stacked_borrows/return_invalid_shr.rs new file mode 100644 index 000000000000..89c94127b0b7 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/return_invalid_shr.rs @@ -0,0 +1,11 @@ +// Make sure that we cannot return a `&` that got already invalidated. +fn foo(x: &mut (i32, i32)) -> &i32 { + let xraw = x as *mut (i32, i32); + let ret = unsafe { &(*xraw).1 }; + let _val = *x; // invalidate xraw and its children + ret //~ ERROR Shr reference with non-reactivatable tag: Location should be frozen +} + +fn main() { + foo(&mut (1, 2)); +} From 95f740600c530658a40687f169e2337171cbe612 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Mon, 15 Oct 2018 18:45:55 +0000 Subject: [PATCH 0294/5092] improve README instructions for using `rustup` and for compiling separate Cargo projects --- README.md | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index e59accaea1b9..9c6128643c95 100644 --- a/README.md +++ b/README.md @@ -47,13 +47,29 @@ You can also set `-Zmiri-start-fn` to make Miri start evaluation with the ## Running Miri on your own project('s test suite) -Install Miri as a cargo subcommand with `cargo install --all-features`, and install -a full libstd as described above. +Install Miri as a cargo subcommand with `cargo install --all-features --path .`. -Then, inside your own project, use `MIRI_SYSROOT=~/.xargo/HOST cargo +nightly -miri` to run your project, if it is a bin project, or run -`MIRI_SYSROOT=~/.xargo/HOST cargo +nightly miri test` to run all tests in your -project through Miri. +Compile your project and its dependencies against a MIR-enabled libstd as described +above: + +1. Run `cargo clean` to eliminate any cached dependencies that were built against +the non-MIR `libstd`. +2. For a binary project, run `MIRI_SYSROOT=~/.xargo/HOST cargo +nightly miri` to +build and run your project; for a binary or library, use `MIRI_SYSROOT=~/.xargo/HOST cargo +nightly miri test` +to run all tests in your project through Miri. + +If you forget to set `MIRI_SYSROOT`, be sure to run `cargo clean` again before +correcting it. Otherwise you are likely to get "dependency was built against possibly +newer std" errors. + +## Using Rustup To Specify a Specific Nightly + +To target a specific nightly, modify the above instructions as follows. + +1. Install Miri using `cargo +nightly-2018-10-15 install --all-features --path .`, +with the date replaced as appropriate. +2. Run `xargo/build.sh` as `rustup run nightly-2018-10-15 build.sh`. +3. When running tests, use `MIRI_SYSROOT=~/.xargo/HOST cargo +nightly-2018-10-15 miri test`. ## Miri `-Z` flags From f77b29294829564f6d95148ef1e3749587518dfa Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Fri, 19 Oct 2018 15:07:19 +0000 Subject: [PATCH 0295/5092] added line indicating that `build.sh` and `cargo miri` need the same toolchain --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 9c6128643c95..087a2a44cff7 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,10 @@ with the date replaced as appropriate. 2. Run `xargo/build.sh` as `rustup run nightly-2018-10-15 build.sh`. 3. When running tests, use `MIRI_SYSROOT=~/.xargo/HOST cargo +nightly-2018-10-15 miri test`. +You may prefer to do this rather than depending on the rustup default toolchain, +if you routinely update the default, since **it is essential that `xargo/build.sh` +is run with the same toolchain as `cargo miri`.** + ## Miri `-Z` flags Miri adds some extra `-Z` flags to control its behavior: From 3dcf655eead8aa4f041d881a91200fc9998d4405 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Sat, 20 Oct 2018 16:31:15 +0000 Subject: [PATCH 0296/5092] readme: pull "common problems" into their own section --- README.md | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 087a2a44cff7..e5c2850ef3eb 100644 --- a/README.md +++ b/README.md @@ -54,13 +54,33 @@ above: 1. Run `cargo clean` to eliminate any cached dependencies that were built against the non-MIR `libstd`. -2. For a binary project, run `MIRI_SYSROOT=~/.xargo/HOST cargo +nightly miri` to -build and run your project; for a binary or library, use `MIRI_SYSROOT=~/.xargo/HOST cargo +nightly miri test` -to run all tests in your project through Miri. +2. To run all tests in your project through, Miri, use +`MIRI_SYSROOT=~/.xargo/HOST cargo +nightly miri test`. +3. If you have a binary project, you can run it through Miri using +`MIRI_SYSROOT=~/.xargo/HOST cargo +nightly miri`. -If you forget to set `MIRI_SYSROOT`, be sure to run `cargo clean` again before -correcting it. Otherwise you are likely to get "dependency was built against possibly -newer std" errors. +### Common Problems + +When modifying the above instructions, you may encounter a number of confusing compiler +errors. + +#### "constant evaluation error: no mir for ``" + +You may have forgotten to set `MIRI_SYSROOT` when calling `cargo miri test`, and +your program called into `std` or `core`. Be sure to set `MIRI_SYSROOT=~/.xargo/HOST`. + +#### "found possibly newer version of crate `std` which `` depends on" + +Your build directory may contain artifacts from an earlier build that did/did not +have `MIRI_SYSROOT` set. Run `cargo clean` before switching from non-Miri to Miri +builds and vice-versa. + +#### "found crate `std` compiled by an incompatible version of rustc" + +You may be running `cargo miri test` with a different compiler version than the one +used to build the MIR-enabled `std`. Be sure to consistently use the same toolchain, +perhaps by following the below instructions to specify a specific nightly for use +with Miri. ## Using Rustup To Specify a Specific Nightly @@ -68,13 +88,9 @@ To target a specific nightly, modify the above instructions as follows. 1. Install Miri using `cargo +nightly-2018-10-15 install --all-features --path .`, with the date replaced as appropriate. -2. Run `xargo/build.sh` as `rustup run nightly-2018-10-15 build.sh`. +2. Run `xargo/build.sh` as `rustup run nightly-2018-10-15 xargo/build.sh`. 3. When running tests, use `MIRI_SYSROOT=~/.xargo/HOST cargo +nightly-2018-10-15 miri test`. -You may prefer to do this rather than depending on the rustup default toolchain, -if you routinely update the default, since **it is essential that `xargo/build.sh` -is run with the same toolchain as `cargo miri`.** - ## Miri `-Z` flags Miri adds some extra `-Z` flags to control its behavior: From abda1a8ebb4f38929a6f62e73b81ce6deb95ef61 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Sun, 21 Oct 2018 16:46:28 +0000 Subject: [PATCH 0297/5092] rename `rust-toolchain` to `rust-version`; add note to README about usage --- .travis.yml | 3 +-- README.md | 4 +++- appveyor.yml | 2 +- rust-toolchain => rust-version | 0 4 files changed, 5 insertions(+), 4 deletions(-) rename rust-toolchain => rust-version (100%) diff --git a/.travis.yml b/.travis.yml index d2315c7e9538..095af11627fa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,9 +18,8 @@ before_script: if [ "$TRAVIS_EVENT_TYPE" = cron ]; then RUST_TOOLCHAIN=nightly else - RUST_TOOLCHAIN=$(cat rust-toolchain) + RUST_TOOLCHAIN=$(cat rust-version) fi -- rm rust-toolchain # install Rust - curl https://build.travis-ci.org/files/rustup-init.sh -sSf | sh -s -- -y --default-toolchain "$RUST_TOOLCHAIN" - export PATH=$HOME/.cargo/bin:$PATH diff --git a/README.md b/README.md index e5c2850ef3eb..76127d8b62a9 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,9 @@ with Miri. ## Using Rustup To Specify a Specific Nightly -To target a specific nightly, modify the above instructions as follows. +To target a specific nightly, modify the above instructions as follows. It is recommended +to use the nightly specified in the `rust-version` file in this repo, since that is the +most recent nightly supported by Miri. 1. Install Miri using `cargo +nightly-2018-10-15 install --all-features --path .`, with the date replaced as appropriate. diff --git a/appveyor.yml b/appveyor.yml index 4614891a3129..cf578120c9dd 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -16,7 +16,7 @@ branches: install: # install Rust - set PATH=C:\Program Files\Git\mingw64\bin;C:\msys64\mingw%MSYS2_BITS%\bin;%PATH% - - set /p RUST_TOOLCHAIN= Date: Tue, 23 Oct 2018 15:21:19 +0000 Subject: [PATCH 0298/5092] README: remove "specific nightly" instructions and use +nightly throughout Also replace `cargo miri test` with `cargo miri` in general examples. --- README.md | 40 +++++++++++++++------------------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 76127d8b62a9..7597c9a0e11b 100644 --- a/README.md +++ b/README.md @@ -8,17 +8,19 @@ undergraduate research course at the [University of Saskatchewan][usask]. ## Building Miri I recommend that you install [rustup][rustup] to obtain Rust. Miri comes with a -`rust-toolchain` file so rustup will automatically pick a suitable nightly -version. Then all you have to do is: +`rust-version` file describing the latest supported nightly version of the Rust +compiler toolchain. Then all you have to do is: ```sh -cargo build +cargo +nightly build ``` +with `+nightly` replaced with the appropriate nightly version of Rust. + ## Running Miri ```sh -cargo run tests/run-pass/vecs.rs # Or whatever test you like. +cargo +nightly run tests/run-pass/vecs.rs # Or whatever test you like. ``` ## Running Miri with full libstd @@ -28,15 +30,15 @@ Miri hits a call to such a function, execution terminates. To fix this, it is possible to compile libstd with full MIR: ```sh -rustup component add rust-src -cargo install xargo -xargo/build.sh +rustup component add --toolchain nightly rust-src +cargo +nightly install xargo +rustup run nightly xargo/build.sh ``` Now you can run Miri against the libstd compiled by xargo: ```sh -MIRI_SYSROOT=~/.xargo/HOST cargo run tests/run-pass-fullmir/hashmap.rs +MIRI_SYSROOT=~/.xargo/HOST cargo +nightly run tests/run-pass-fullmir/hashmap.rs ``` Notice that you will have to re-run the last step of the preparations above when @@ -47,7 +49,7 @@ You can also set `-Zmiri-start-fn` to make Miri start evaluation with the ## Running Miri on your own project('s test suite) -Install Miri as a cargo subcommand with `cargo install --all-features --path .`. +Install Miri as a cargo subcommand with `cargo install +nightly --all-features --path .`. Compile your project and its dependencies against a MIR-enabled libstd as described above: @@ -61,12 +63,12 @@ the non-MIR `libstd`. ### Common Problems -When modifying the above instructions, you may encounter a number of confusing compiler +When using the above instructions, you may encounter a number of confusing compiler errors. #### "constant evaluation error: no mir for ``" -You may have forgotten to set `MIRI_SYSROOT` when calling `cargo miri test`, and +You may have forgotten to set `MIRI_SYSROOT` when calling `cargo miri`, and your program called into `std` or `core`. Be sure to set `MIRI_SYSROOT=~/.xargo/HOST`. #### "found possibly newer version of crate `std` which `` depends on" @@ -77,21 +79,9 @@ builds and vice-versa. #### "found crate `std` compiled by an incompatible version of rustc" -You may be running `cargo miri test` with a different compiler version than the one +You may be running `cargo miri` with a different compiler version than the one used to build the MIR-enabled `std`. Be sure to consistently use the same toolchain, -perhaps by following the below instructions to specify a specific nightly for use -with Miri. - -## Using Rustup To Specify a Specific Nightly - -To target a specific nightly, modify the above instructions as follows. It is recommended -to use the nightly specified in the `rust-version` file in this repo, since that is the -most recent nightly supported by Miri. - -1. Install Miri using `cargo +nightly-2018-10-15 install --all-features --path .`, -with the date replaced as appropriate. -2. Run `xargo/build.sh` as `rustup run nightly-2018-10-15 xargo/build.sh`. -3. When running tests, use `MIRI_SYSROOT=~/.xargo/HOST cargo +nightly-2018-10-15 miri test`. +which should be the toolchain specified in the `rust-version` file. ## Miri `-Z` flags From a34b9c7b70f52b10becbee7606c10afd13712f95 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Oct 2018 11:39:31 +0200 Subject: [PATCH 0299/5092] make some things public for the benefit of priroda --- src/lib.rs | 6 +++++- src/stacked_borrows.rs | 22 +++++++++++++++++++--- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 128b338f943d..50b1305e52c8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,8 +44,12 @@ use range_map::RangeMap; #[allow(unused_imports)] // FIXME rustc bug https://github.com/rust-lang/rust/issues/53682 use helpers::{ScalarExt, EvalContextExt as HelpersEvalContextExt}; use mono_hash_map::MonoHashMap; -use stacked_borrows::{EvalContextExt as StackedBorEvalContextExt, Borrow}; +use stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; +// Used by priroda +pub use stacked_borrows::{Borrow, Stacks, Mut as MutBorrow}; + +// Used by priroda pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index f634f17109c7..96ae2aa5c576 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -21,12 +21,20 @@ pub enum Mut { impl Mut { #[inline(always)] - fn is_raw(self) -> bool { + pub fn is_raw(self) -> bool { match self { Mut::Raw => true, _ => false, } } + + #[inline(always)] + pub fn is_uniq(self) -> bool { + match self { + Mut::Uniq(_) => true, + _ => false, + } + } } /// Information about any kind of borrow @@ -40,9 +48,17 @@ pub enum Borrow { impl Borrow { #[inline(always)] - fn is_uniq(self) -> bool { + pub fn is_uniq(self) -> bool { match self { - Borrow::Mut(Mut::Uniq(_)) => true, + Borrow::Mut(m) => m.is_uniq(), + _ => false, + } + } + + #[inline(always)] + pub fn is_frz(self) -> bool { + match self { + Borrow::Frz(_) => true, _ => false, } } From 86aa8352c695a59db5822f267b6c64ccf601220d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Oct 2018 15:29:48 +0200 Subject: [PATCH 0300/5092] Work on miri installation and usage instructions --- README.md | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 7597c9a0e11b..c5ac81729994 100644 --- a/README.md +++ b/README.md @@ -7,15 +7,23 @@ undergraduate research course at the [University of Saskatchewan][usask]. ## Building Miri -I recommend that you install [rustup][rustup] to obtain Rust. Miri comes with a -`rust-version` file describing the latest supported nightly version of the Rust -compiler toolchain. Then all you have to do is: +I recommend that you install [rustup][rustup] to obtain Rust. Then all you have +to do is: ```sh cargo +nightly build ``` -with `+nightly` replaced with the appropriate nightly version of Rust. +This uses the very latest Rust version. If you experience any problem, refer to +the `rust-version` file which contains a particular Rust nightly version that +has been tested against the version of miri you are using. Make sure to use +that particular `nightly-YYYY-MM-DD` whenever the instructions just say +`nightly`. + +To avoid repeating the nightly version all the time, you can use +`rustup override set nightly` (or `rustup override set nightly-YYYY-MM-DD`), +which means `nightly` Rust will automatically be used whenever you are working +in this directory. ## Running Miri @@ -41,18 +49,23 @@ Now you can run Miri against the libstd compiled by xargo: MIRI_SYSROOT=~/.xargo/HOST cargo +nightly run tests/run-pass-fullmir/hashmap.rs ``` -Notice that you will have to re-run the last step of the preparations above when -your toolchain changes (e.g., when you update the nightly). - -You can also set `-Zmiri-start-fn` to make Miri start evaluation with the -`start_fn` lang item, instead of starting at the `main` function. +Notice that you will have to re-run the last step of the preparations above +(`xargo/build.sh`) when your toolchain changes (e.g., when you update the +nightly). ## Running Miri on your own project('s test suite) -Install Miri as a cargo subcommand with `cargo install +nightly --all-features --path .`. +Install Miri as a cargo subcommand with `cargo install +nightly --all-features +--path .`. Be aware that if you used `rustup override set` to fix a particular +Rust version for the miri directory, that will *not* apply to your own project +directory! You have to use a consistent Rust version for building miri and your +project for this to work, so remember to either always specify the nightly +version manually, overriding it in your project directory as well, or use +`rustup default nightly` (or `rustup default nightly-YYYY-MM-DD`) to globally +make `nightly` the default toolchain. -Compile your project and its dependencies against a MIR-enabled libstd as described -above: +We assume that you have prepared a MIR-enabled libstd as described above. Now +compile your project and its dependencies against that libstd: 1. Run `cargo clean` to eliminate any cached dependencies that were built against the non-MIR `libstd`. From 8f9ca242fad4b17a505d26b41e8168cc051d4fe9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Oct 2018 15:32:51 +0200 Subject: [PATCH 0301/5092] expand -Z flag docs --- README.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c5ac81729994..0e88c8138a51 100644 --- a/README.md +++ b/README.md @@ -98,11 +98,17 @@ which should be the toolchain specified in the `rust-version` file. ## Miri `-Z` flags -Miri adds some extra `-Z` flags to control its behavior: +Several `-Z` flags are relevant for miri: -* `-Zmiri-start-fn`: This makes interpretation start with `lang_start` (defined - in libstd) instead of starting with `main`. Requires full MIR! -* `-Zmiri-disable-validation` disables enforcing the validity invariant. +* `-Zmir-opt-level` controls how many MIR optimizations are performed. miri + overrides the default to be `0`; be advised that using any higher level can + make miri miss bugs in your program because they got optimized away. +* `-Zalways-encode-mir` makes rustc dump MIR even for completely monomorphic + functions. This is needed so that miri can execute such functions, so miri + sets this flag per default. +* `-Zmiri-disable-validation` is a custom `-Z` flag added by miri. It disables + enforcing the validity invariant, which is enforced by default. This is + mostly useful for debugging; it means miri will miss bugs in your program. ## Development and Debugging From d890a70c39affeb9db3cfa9545905284a981114d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 25 Oct 2018 11:37:42 +0200 Subject: [PATCH 0302/5092] update for is_null removal --- src/fn_call.rs | 6 +++--- src/intrinsic.rs | 2 +- src/tls.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 0cbd891a34e4..2d142ab20dc6 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -132,7 +132,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "free" => { let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation, no tag - if !ptr.is_null() { + if !ptr.is_null_ptr(&self) { self.memory.deallocate( ptr.to_ptr()?.with_default_tag(), None, @@ -353,7 +353,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let mut success = None; { let name_ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation - if !name_ptr.is_null() { + if !name_ptr.is_null_ptr(&self) { let name = self.memory.read_c_str(name_ptr.to_ptr()?.with_default_tag())?; if !name.is_empty() && !name.contains(&b'=') { success = Some(self.machine.env_vars.remove(name)); @@ -376,7 +376,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let name_ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation let value_ptr = self.read_scalar(args[1])?.to_ptr()?.erase_tag(); // raw ptr operation let value = self.memory.read_c_str(value_ptr.with_default_tag())?; - if !name_ptr.is_null() { + if !name_ptr.is_null_ptr(&self) { let name = self.memory.read_c_str(name_ptr.to_ptr()?.with_default_tag())?; if !name.is_empty() && !name.contains(&b'=') { new = Some((name.to_owned(), value.to_owned())); diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 5c86075883b0..dceeaf89aa5d 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -231,7 +231,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let a = self.read_value(args[0])?; let b = self.read_value(args[1])?; // check x % y != 0 - if !self.binary_op_val(mir::BinOp::Rem, a, b)?.0.is_null() { + if self.binary_op_val(mir::BinOp::Rem, a, b)?.0.to_bytes()? != 0 { return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b))); } self.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; diff --git a/src/tls.rs b/src/tls.rs index 2bddc43df8c4..b315e27c45d0 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -121,7 +121,7 @@ impl<'tcx> TlsData<'tcx> { for (&key, &mut TlsEntry { ref mut data, dtor }) in thread_local.range_mut((start, Unbounded)) { - if !data.is_null() { + if !data.is_null_ptr(cx) { if let Some(dtor) = dtor { let ret = Some((dtor, *data, key)); *data = Scalar::ptr_null(cx); From 4ccdcdcace3ccea08d27e24669b8b635d1722541 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 29 Oct 2018 09:09:03 +0100 Subject: [PATCH 0303/5092] rustup --- rust-version | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index cc0787f877e6..feed920a1668 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-10-22 +nightly-2018-10-29 diff --git a/src/lib.rs b/src/lib.rs index ed23eef3f550..a93a48cb09d4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -181,7 +181,7 @@ pub fn eval_main<'a, 'tcx: 'a>( let e = e.to_string(); let msg = format!("constant evaluation error: {}", e); let mut err = struct_error(ecx.tcx.tcx.at(span), msg.as_str()); - let (frames, span) = ecx.generate_stacktrace(None); + let frames = ecx.generate_stacktrace(None); err.span_label(span, e); for FrameInfo { span, location, .. } in frames { err.span_note(span, &format!("inside call to `{}`", location)); From f7741bcfe0a6a751961a9c7a1ef01cfc439eb4eb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 29 Oct 2018 09:15:58 +0100 Subject: [PATCH 0304/5092] bump compiletest --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f79609c76394..dcf93fa14104 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,5 +45,5 @@ cargo_miri = ["cargo_metadata"] rustc_tests = [] [dev-dependencies] -compiletest_rs = { version = "0.3.12", features = ["tmp"] } +compiletest_rs = { version = "0.3.16", features = ["tmp"] } colored = "1.6" From cba30e8e8b14067750a0aec279737bcadd90cfcd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 29 Oct 2018 11:51:22 +0100 Subject: [PATCH 0305/5092] opt level 3 works again :) --- tests/compiletest.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 7a7d7e49b2db..0e6fa3d2a1fc 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -102,11 +102,7 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: flags.push(format!("--sysroot {}", sysroot.display())); flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs if opt { - // FIXME: Using level 1 (instead of 3) for now, as the optimizer is pretty broken - // and crashes... - // Level 0 and 1 are not the same, so this still gives us *some* coverage. - // See https://github.com/rust-lang/rust/issues/50411 - flags.push("-Zmir-opt-level=1".to_owned()); + flags.push("-Zmir-opt-level=3".to_owned()); } else { flags.push("-Zmir-opt-level=0".to_owned()); // For now, only validate without optimizations. Inlining breaks validation. From 942204ee321f57033c65ece3b667bf63c7c65ff0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Oct 2018 08:40:50 +0100 Subject: [PATCH 0306/5092] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index feed920a1668..d025ddacf009 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-10-29 +nightly-2018-10-30 From a48b2cc4e940d63cadccb775401618015afbe0cc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Oct 2018 09:40:01 +0100 Subject: [PATCH 0307/5092] disable validation for some tests that need further investigation --- tests/run-pass-fullmir/send-is-not-static-par-for.rs | 3 +++ tests/run-pass-fullmir/u128.rs | 3 +++ tests/run-pass-fullmir/vecdeque.rs | 3 +++ 3 files changed, 9 insertions(+) diff --git a/tests/run-pass-fullmir/send-is-not-static-par-for.rs b/tests/run-pass-fullmir/send-is-not-static-par-for.rs index 1b913aed4c89..282f7a359503 100644 --- a/tests/run-pass-fullmir/send-is-not-static-par-for.rs +++ b/tests/run-pass-fullmir/send-is-not-static-par-for.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// FIXME: Still investigating whether there is UB here +// compile-flags: -Zmiri-disable-validation + use std::sync::Mutex; fn par_for(iter: I, f: F) diff --git a/tests/run-pass-fullmir/u128.rs b/tests/run-pass-fullmir/u128.rs index ca33bd5f9e3d..0f1b6e8b5870 100644 --- a/tests/run-pass-fullmir/u128.rs +++ b/tests/run-pass-fullmir/u128.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// FIXME: Still investigating whether there is UB here +// compile-flags: -Zmiri-disable-validation + fn b(t: T) -> T { t } fn main() { diff --git a/tests/run-pass-fullmir/vecdeque.rs b/tests/run-pass-fullmir/vecdeque.rs index 381169505ec9..ffbb11668498 100644 --- a/tests/run-pass-fullmir/vecdeque.rs +++ b/tests/run-pass-fullmir/vecdeque.rs @@ -1,3 +1,6 @@ +// FIXME: Still investigating whether there is UB here +// compile-flags: -Zmiri-disable-validation + use std::collections::VecDeque; fn main() { From 9c9552260c03f72f1de840de092775fd03ed05b5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Oct 2018 10:14:09 +0100 Subject: [PATCH 0308/5092] test cargo-miri without validation, and fix how we invoke it so we see output in case of failure --- .travis.yml | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index 095af11627fa..dd7bcd49200b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,30 +36,34 @@ script: - | # Test and install plain miri cargo build --release --all-features && - cargo test --release --all-features && + #cargo test --release --all-features && cargo install --all-features --force --path . - | # get ourselves a MIR-full libstd xargo/build.sh && export MIRI_SYSROOT=~/.xargo/HOST +#- | +# # run all tests with full mir +# cargo test --release --all-features - | - # run all tests with full mir - cargo test --release --all-features -- | - # test `cargo miri` + # Test cargo integration cd cargo-miri-test && - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - cargo miri -q - else - cargo miri -q >stdout.real 2>stderr.real && - cat stdout.real stderr.real && - # Test `cargo miri` output. Not on mac because output redirecting doesn't - # work. There is no error. It just stops CI. + # Test `cargo miri` + # We ignore the exit code because we want to see the output even on failure, and + # I found no way to preserve the exit code so that we can test for it later. + # Variables set in this subshell in the parenthesis are not available + # on the outside. + # We assume that if this fails, it'll also print something about the failure on + # stdout/stderr and we'll catch that. + # FIXME: Disabling validation, still investigating whether there is UB here + (cargo miri -q >stdout.real 2>stderr.real -- -Zmiri-disable-validation || true) && + # Print file names and contents (`cat` would just print contents) + tail -n +0 stdout.real stderr.real && + # Verify output diff -u stdout.ref stdout.real && - diff -u stderr.ref stderr.real - fi && + diff -u stderr.ref stderr.real && # test `cargo miri test` - cargo miri test && + cargo miri test && cd .. notifications: From 1fa0ff88c03284421d99662909a4c24a8651d47d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Oct 2018 10:41:01 +0100 Subject: [PATCH 0309/5092] fix nits --- src/fn_call.rs | 18 ++++++++++++------ src/stacked_borrows.rs | 12 ++++++------ .../stacked_borrows/illegal_write4.rs | 8 ++++---- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index a65329a1e7bb..9e3f49ac9fd3 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -150,10 +150,14 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory_mut().allocate(Size::from_bytes(size), - Align::from_bytes(align, align).unwrap(), - MiriMemoryKind::Rust.into())?; - self.write_scalar(Scalar::Ptr(ptr.with_default_tag()), dest)?; + let ptr = self.memory_mut() + .allocate( + Size::from_bytes(size), + Align::from_bytes(align, align).unwrap(), + MiriMemoryKind::Rust.into() + )? + .with_default_tag(); + self.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_alloc_zeroed" => { let size = self.read_scalar(args[0])?.to_usize(&self)?; @@ -164,11 +168,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory_mut().allocate( + let ptr = self.memory_mut() + .allocate( Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), MiriMemoryKind::Rust.into() - )?.with_default_tag(); + )? + .with_default_tag(); self.memory_mut().write_repeat(ptr.into(), 0, Size::from_bytes(size))?; self.write_scalar(Scalar::Ptr(ptr), dest)?; } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 96ae2aa5c576..a569ed4e5551 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -251,7 +251,7 @@ impl<'tcx> Stack { impl State { fn increment_clock(&self) -> Timestamp { let val = self.clock.get(); - self.clock.set(val+1); + self.clock.set(val + 1); val } } @@ -322,13 +322,13 @@ impl<'tcx> Stacks { /// Pushes the first borrow to the stacks, must be a mutable one. pub fn first_borrow( &mut self, - r#mut: Mut, + mut_borrow: Mut, size: Size ) { for stack in self.stacks.get_mut().iter_mut(Size::ZERO, size) { assert!(stack.borrows.len() == 1 && stack.frozen_since.is_none()); assert_eq!(stack.borrows.pop().unwrap(), BorStackItem::Mut(Mut::Raw)); - stack.borrows.push(BorStackItem::Mut(r#mut)); + stack.borrows.push(BorStackItem::Mut(mut_borrow)); } } } @@ -489,7 +489,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' id: AllocId, kind: MemoryKind, ) -> Borrow { - let r#mut = match kind { + let mut_borrow = match kind { MemoryKind::Stack => { // New unique borrow let time = self.machine.stacked_borrows.increment_clock(); @@ -503,7 +503,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Make this the active borrow for this allocation let alloc = self.memory_mut().get_mut(id).expect("This is a new allocation, it must still exist"); let size = Size::from_bytes(alloc.bytes.len() as u64); - alloc.extra.first_borrow(r#mut, size); - Borrow::Mut(r#mut) + alloc.extra.first_borrow(mut_borrow, size); + Borrow::Mut(mut_borrow) } } diff --git a/tests/compile-fail/stacked_borrows/illegal_write4.rs b/tests/compile-fail/stacked_borrows/illegal_write4.rs index 2006d7262f81..094a38951974 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write4.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write4.rs @@ -11,8 +11,8 @@ fn main() { let target = 42; // Make sure a cannot use a raw-tagged `&mut` pointing to a frozen location, not // even to create a raw. - let r#ref = ⌖ // freeze - let ptr = r#ref as *const _ as *mut i32; // raw ptr, with raw tag + let reference = ⌖ // freeze + let ptr = reference as *const _ as *mut i32; // raw ptr, with raw tag let mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag // Now we have an &mut to a frozen location, but that is completely normal: // We'd just unfreeze the location if we used it. @@ -23,9 +23,9 @@ fn main() { // turns a raw into a `&mut`. Next, we create a raw ref to a frozen location // from a `Raw` tag, which can happen legitimately when interior mutability // is involved. - let _val = *r#ref; // Make sure it is still frozen. + let _val = *reference; // Make sure it is still frozen. // We only actually unfreeze once we muteate through the bad pointer. unsafe { *bad_ptr = 42 }; //~ ERROR does not exist on the stack - let _val = *r#ref; + let _val = *reference; } From f6b1f9e48756c35f2d23baedb1a111aec33bc7d2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Oct 2018 11:26:53 +0100 Subject: [PATCH 0310/5092] rewrite cargo-miri test in Python --- .travis.yml | 27 +++++------------------ cargo-miri-test/run-test.py | 43 +++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 22 deletions(-) create mode 100755 cargo-miri-test/run-test.py diff --git a/.travis.yml b/.travis.yml index dd7bcd49200b..d845eb0ec9f3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,35 +36,18 @@ script: - | # Test and install plain miri cargo build --release --all-features && - #cargo test --release --all-features && + cargo test --release --all-features && cargo install --all-features --force --path . - | # get ourselves a MIR-full libstd xargo/build.sh && export MIRI_SYSROOT=~/.xargo/HOST -#- | -# # run all tests with full mir -# cargo test --release --all-features +- | + # run all tests with full mir + cargo test --release --all-features - | # Test cargo integration - cd cargo-miri-test && - # Test `cargo miri` - # We ignore the exit code because we want to see the output even on failure, and - # I found no way to preserve the exit code so that we can test for it later. - # Variables set in this subshell in the parenthesis are not available - # on the outside. - # We assume that if this fails, it'll also print something about the failure on - # stdout/stderr and we'll catch that. - # FIXME: Disabling validation, still investigating whether there is UB here - (cargo miri -q >stdout.real 2>stderr.real -- -Zmiri-disable-validation || true) && - # Print file names and contents (`cat` would just print contents) - tail -n +0 stdout.real stderr.real && - # Verify output - diff -u stdout.ref stdout.real && - diff -u stderr.ref stderr.real && - # test `cargo miri test` - cargo miri test && - cd .. + (cd cargo-miri-test && ./run-test.py) notifications: email: diff --git a/cargo-miri-test/run-test.py b/cargo-miri-test/run-test.py new file mode 100755 index 000000000000..90f0a8ac6c88 --- /dev/null +++ b/cargo-miri-test/run-test.py @@ -0,0 +1,43 @@ +#!/usr/bin/python3 +''' +Test whether cargo-miri works properly. +Assumes the `MIRI_SYSROOT` env var to be set appropriately, +and the working directory to contain the cargo-miri-test project. +''' + +import sys, subprocess + +def test_cargo_miri(): + print("==> Testing `cargo miri` <==") + ## Call `cargo miri`, capture all output + # FIXME: Disabling validation, still investigating whether there is UB here + p = subprocess.Popen( + ["cargo", "miri", "-q", "--", "-Zmiri-disable-validation"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE + ) + (stdout, stderr) = p.communicate() + stdout = stdout.decode("UTF-8") + stderr = stderr.decode("UTF-8") + # Show output + print("=> captured stdout <=") + print(stdout, end="") + print("=> captured stderr <=") + print(stderr, end="") + # Test for failures + if p.returncode != 0: + sys.exit(1) + if stdout != open('stdout.ref').read(): + print("stdout does not match reference") + sys.exit(1) + if stderr != open('stderr.ref').read(): + print("stderr does not match reference") + sys.exit(1) + +def test_cargo_miri_test(): + print("==> Testing `cargo miri test` <==") + subprocess.check_call(["cargo", "miri", "test"]) + +test_cargo_miri() +test_cargo_miri_test() +sys.exit(0) From 8fe51ca669bd257795759816bfb29e986ca3217e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Oct 2018 15:07:40 +0100 Subject: [PATCH 0311/5092] try to find python3 on macOS --- .travis.yml | 4 ++-- cargo-miri-test/run-test.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index d845eb0ec9f3..f989c7705b19 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,8 +11,8 @@ os: - osx before_script: -# mac os weirdness (https://github.com/travis-ci/travis-ci/issues/6307) -- rvm get stable +# macOS weirdness (https://github.com/travis-ci/travis-ci/issues/6307) +- if [[ "$TRAVIS_OS_NAME" == osx ]]; then rvm get stable; fi # Compute the rust version we use. We do not use "language: rust" to have more control here. - | if [ "$TRAVIS_EVENT_TYPE" = cron ]; then diff --git a/cargo-miri-test/run-test.py b/cargo-miri-test/run-test.py index 90f0a8ac6c88..506de85ffcb2 100755 --- a/cargo-miri-test/run-test.py +++ b/cargo-miri-test/run-test.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 ''' Test whether cargo-miri works properly. Assumes the `MIRI_SYSROOT` env var to be set appropriately, From eb153810e35748d2b4556d39dd6778d35ceb1a9e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Oct 2018 10:09:55 +0100 Subject: [PATCH 0312/5092] Use MIRI_ env vars to set RUST_ ones This means we can do `MIRI_LOG=debug cargo run` and get something reasonable, even if cargo has to build some dependencies first. --- src/bin/miri.rs | 64 +++++++++++++++++++++---------------------------- src/lib.rs | 15 +++++++++++- 2 files changed, 41 insertions(+), 38 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index d4494a838852..c8103c2a1176 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -12,6 +12,9 @@ extern crate log_settings; extern crate syntax; extern crate log; +use std::path::PathBuf; +use std::env; + use rustc::session::Session; use rustc_metadata::cstore::CStore; use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls}; @@ -21,7 +24,6 @@ use rustc::hir::{self, itemlikevisit}; use rustc::ty::TyCtxt; use rustc_codegen_utils::codegen_backend::CodegenBackend; use syntax::ast; -use std::path::PathBuf; struct MiriCompilerCalls { default: Box, @@ -148,42 +150,31 @@ fn after_analysis<'a, 'tcx>( } } -fn init_logger() { - let format = |formatter: &mut env_logger::fmt::Formatter, record: &log::Record| { - use std::io::Write; - if record.level() == log::Level::Trace { - // prepend frame number - let indentation = log_settings::settings().indentation; - writeln!( - formatter, - "{indentation}:{lvl}:{module}: {text}", - lvl = record.level(), - module = record.module_path().unwrap_or(""), - indentation = indentation, - text = record.args(), - ) - } else { - writeln!( - formatter, - "{lvl}:{module}: {text}", - lvl = record.level(), - module = record.module_path().unwrap_or(""), - text = record.args(), - ) +fn init_loggers() { + // Notice that our `extern crate log` is NOT the same as rustc's! So we have to initialize + // them both. + // First, miri. + let env = env_logger::Env::new().filter("MIRI_LOG").write_style("MIRI_LOG_STYLE"); + env_logger::init_from_env(env); + // Now, change the RUST_LOG env var to control rustc's logger. + // If MIRI_LOG is set and RUST_LOG is not, set RUST_LOG. + if let Ok(var) = env::var("MIRI_LOG") { + if env::var("RUST_LOG") == Err(env::VarError::NotPresent) { + // We try to be a bit clever here: If MIRI_LOG is just a single level + // used for everything, we only apply it to the parts of rustc that are + // CTFE-related. Only if MIRI_LOG contains `module=level`, we just + // use the same value for RUST_LOG. + // This way, if you set `MIRI_LOG=trace`, you get only the right parts of + // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_mir::interpret=debug`. + if var.contains('=') { + env::set_var("RUST_LOG", &var); + } else { + env::set_var("RUST_LOG", + &format!("rustc::mir::interpret={0},rustc_mir::interpret={0}", var)); + } } - }; - - let mut builder = env_logger::Builder::new(); - builder.format(format).filter( - None, - log::LevelFilter::Info, - ); - - if std::env::var("MIRI_LOG").is_ok() { - builder.parse(&std::env::var("MIRI_LOG").unwrap()); } - - builder.init(); + rustc_driver::init_rustc_env_logger(); } fn find_sysroot() -> String { @@ -208,8 +199,7 @@ fn find_sysroot() -> String { } fn main() { - rustc_driver::init_rustc_env_logger(); - init_logger(); + init_loggers(); let mut args: Vec = std::env::args().collect(); let sysroot_flag = String::from("--sysroot"); diff --git a/src/lib.rs b/src/lib.rs index 9f4eb00877e4..fa60a0da00d5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,10 +11,12 @@ extern crate rustc; extern crate rustc_data_structures; extern crate rustc_mir; extern crate rustc_target; +extern crate rustc_driver; extern crate syntax; use std::collections::HashMap; use std::borrow::Cow; +use std::env; use rustc::ty::{self, Ty, TyCtxt, query::TyCtxtAt}; use rustc::ty::layout::{TyLayout, LayoutOf, Size}; @@ -157,11 +159,21 @@ pub fn eval_main<'a, 'tcx: 'a>( ) { let mut ecx = create_ecx(tcx, main_id, validate).expect("Couldn't create ecx"); + // If MIRI_BACKTRACE is set and RUST_CTFE_BACKTRACE is not, set RUST_CTFE_BACKTRACE. + // Do this late, so we really only apply this to miri's errors. + if let Ok(var) = env::var("MIRI_BACKTRACE") { + if env::var("RUST_CTFE_BACKTRACE") == Err(env::VarError::NotPresent) { + env::set_var("RUST_CTFE_BACKTRACE", &var); + } + } + + // Run! The main execution. let res: EvalResult = (|| { ecx.run()?; ecx.run_tls_dtors() })(); + // Process the result. match res { Ok(()) => { let leaks = ecx.memory().leak_report(); @@ -173,7 +185,8 @@ pub fn eval_main<'a, 'tcx: 'a>( tcx.sess.err("the evaluated program leaked memory"); } } - Err(e) => { + Err(mut e) => { + e.print_backtrace(); if let Some(frame) = ecx.stack().last() { let block = &frame.mir.basic_blocks()[frame.block]; let span = if frame.stmt < block.statements.len() { From cd256448d5483bb8ad6200aada68639a14ae9543 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Oct 2018 10:16:42 +0100 Subject: [PATCH 0313/5092] dumping locals with MIRI_BACKTRACE=1 is feasible now --- src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index fa60a0da00d5..ee265f8b0a89 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -208,7 +208,6 @@ pub fn eval_main<'a, 'tcx: 'a>( ecx.tcx.sess.err(&e.to_string()); } - /* Nice try, but with MIRI_BACKTRACE this shows 100s of backtraces. for (i, frame) in ecx.stack().iter().enumerate() { trace!("-------------------"); trace!("Frame {}", i); @@ -218,7 +217,7 @@ pub fn eval_main<'a, 'tcx: 'a>( trace!(" local {}: {:?}", i, local); } } - }*/ + } } } } From 8f811fe12f20e6f969490d2db9e05319d6856721 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Oct 2018 10:16:50 +0100 Subject: [PATCH 0314/5092] update README --- README.md | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 0e88c8138a51..a905c2aeffb7 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,7 @@ Several `-Z` flags are relevant for miri: Since the heart of Miri (the main interpreter engine) lives in rustc, working on Miri will often require using a locally built rustc. This includes getting a -trace of the execution, as distributed rustc has `trace!` disabled. +trace of the execution, as distributed rustc has `debug!` and `trace!` disabled. The first-time setup for a local rustc looks as follows: ``` @@ -130,14 +130,28 @@ rustup override set custom ``` The `build` step can take 30 minutes and more. -Now you can `cargo build` Miri, and you can `cargo test --tests`. (`--tests` -is needed to skip doctests because we have not built rustdoc for your custom -toolchain.) You can also set `RUST_LOG=rustc_mir::interpret=trace` as -environment variable to get a step-by-step trace. +Now you can `cargo build` Miri, and you can `cargo test` it. But the key point +is, you can now run Miri with a trace of all execution steps: + +```sh +MIRI_LOG=debug cargo run tests/run-pass/vecs.rs +``` + +Setting `MIRI_LOG` like this will configure logging for miri itself as well as +the `rustc::mir::interpret` and `rustc_mir::interpret` modules in rustc. You +can also do more targeted configuration, e.g. to debug the stacked borrows +implementation: + +```sh +MIRI_LOG=miri::stacked_borrows=trace,rustc_mir::interpret=debug cargo run tests/run-pass/vecs.rs +``` + +In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an +evaluation error was originally created. If you changed something in rustc and want to re-build, run ``` -./x.py build src/rustc --keep-stage 0 +./x.py --keep-stage 0 build src/rustc ``` This avoids rebuilding the entire stage 0, which can save a lot of time. From 7a6a68731e670aeda7cdabc1478e3fd1c34472b0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Oct 2018 10:19:20 +0100 Subject: [PATCH 0315/5092] remove unused extern crate --- src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ee265f8b0a89..650998c3e16c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,13 +6,12 @@ extern crate log; // From rustc. +extern crate syntax; #[macro_use] extern crate rustc; extern crate rustc_data_structures; extern crate rustc_mir; extern crate rustc_target; -extern crate rustc_driver; -extern crate syntax; use std::collections::HashMap; use std::borrow::Cow; From 5397f2e43647d1a78c3a4637cdcb398120b603f6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Oct 2018 10:53:37 +0100 Subject: [PATCH 0316/5092] when using MIRI_LOG, avoid logging for what rustc does before miri gets started --- src/bin/miri.rs | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index c8103c2a1176..6d0f0b5f6a23 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -107,6 +107,7 @@ fn after_analysis<'a, 'tcx>( state: &mut CompileState<'a, 'tcx>, validate: bool, ) { + init_late_loggers(); state.session.abort_if_errors(); let tcx = state.tcx.unwrap(); @@ -150,16 +151,25 @@ fn after_analysis<'a, 'tcx>( } } -fn init_loggers() { +fn init_early_loggers() { // Notice that our `extern crate log` is NOT the same as rustc's! So we have to initialize - // them both. - // First, miri. + // them both. We always initialize miri early. let env = env_logger::Env::new().filter("MIRI_LOG").write_style("MIRI_LOG_STYLE"); env_logger::init_from_env(env); - // Now, change the RUST_LOG env var to control rustc's logger. - // If MIRI_LOG is set and RUST_LOG is not, set RUST_LOG. + // We only initialize rustc if the env var is set (so the user asked for it). + // If it is not set, we avoid initializing now so that we can initialize + // later with our custom settings, and NOT log anything for what happens before + // miri gets started. + if env::var("RUST_LOG").is_ok() { + rustc_driver::init_rustc_env_logger(); + } +} + +fn init_late_loggers() { + // Initializing loggers right before we start evaluation. We overwrite the RUST_LOG + // env var if it is not set, control it based on MIRI_LOG. if let Ok(var) = env::var("MIRI_LOG") { - if env::var("RUST_LOG") == Err(env::VarError::NotPresent) { + if env::var("RUST_LOG").is_err() { // We try to be a bit clever here: If MIRI_LOG is just a single level // used for everything, we only apply it to the parts of rustc that are // CTFE-related. Only if MIRI_LOG contains `module=level`, we just @@ -172,9 +182,9 @@ fn init_loggers() { env::set_var("RUST_LOG", &format!("rustc::mir::interpret={0},rustc_mir::interpret={0}", var)); } + rustc_driver::init_rustc_env_logger(); } } - rustc_driver::init_rustc_env_logger(); } fn find_sysroot() -> String { @@ -199,7 +209,7 @@ fn find_sysroot() -> String { } fn main() { - init_loggers(); + init_early_loggers(); let mut args: Vec = std::env::args().collect(); let sysroot_flag = String::from("--sysroot"); From 016009a3016dde768806a352aaa5da9c852d9dc5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Oct 2018 10:58:19 +0100 Subject: [PATCH 0317/5092] properly recognize log levels --- src/bin/miri.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 6d0f0b5f6a23..bacea04c9768 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -13,6 +13,7 @@ extern crate syntax; extern crate log; use std::path::PathBuf; +use std::str::FromStr; use std::env; use rustc::session::Session; @@ -172,15 +173,14 @@ fn init_late_loggers() { if env::var("RUST_LOG").is_err() { // We try to be a bit clever here: If MIRI_LOG is just a single level // used for everything, we only apply it to the parts of rustc that are - // CTFE-related. Only if MIRI_LOG contains `module=level`, we just - // use the same value for RUST_LOG. + // CTFE-related. Otherwise, we use it verbatim for RUST_LOG. // This way, if you set `MIRI_LOG=trace`, you get only the right parts of // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_mir::interpret=debug`. - if var.contains('=') { - env::set_var("RUST_LOG", &var); - } else { + if log::Level::from_str(&var).is_ok() { env::set_var("RUST_LOG", &format!("rustc::mir::interpret={0},rustc_mir::interpret={0}", var)); + } else { + env::set_var("RUST_LOG", &var); } rustc_driver::init_rustc_env_logger(); } From 40b75026136eea8b7b1d4d93f7972be852d636f6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Oct 2018 11:04:35 +0100 Subject: [PATCH 0318/5092] Reject atomic arithmetic on non-integer types Fixes #181 --- src/intrinsic.rs | 3 +++ tests/compile-fail/atomic_non_integer_arithmetic.rs | 9 +++++++++ 2 files changed, 12 insertions(+) create mode 100644 tests/compile-fail/atomic_non_integer_arithmetic.rs diff --git a/src/intrinsic.rs b/src/intrinsic.rs index ee8df3e25ec1..852c93f650df 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -126,6 +126,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "atomic_xsub_acqrel" | "atomic_xsub_relaxed" => { let ptr = self.ref_to_mplace(self.read_value(args[0])?)?; + if !ptr.layout.ty.is_integral() { + return err!(Unimplemented(format!("Atomic arithmetic operations only work on integer types"))); + } let rhs = self.read_value(args[1])?; let old = self.read_value(ptr.into())?; self.write_value(*old, dest)?; // old value is returned diff --git a/tests/compile-fail/atomic_non_integer_arithmetic.rs b/tests/compile-fail/atomic_non_integer_arithmetic.rs new file mode 100644 index 000000000000..8c2ed98b7dfa --- /dev/null +++ b/tests/compile-fail/atomic_non_integer_arithmetic.rs @@ -0,0 +1,9 @@ +#![feature(core_intrinsics)] + +pub fn main() { + let mut z: f64 = 1.0; + unsafe { + ::std::intrinsics::atomic_xadd(&mut z, 2.0); + //~^ ERROR: Atomic arithmetic operations only work on integer types + } +} From 27b1f47b0a947f8867d3d0840ea40c5902b7191c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 1 Nov 2018 08:56:41 +0100 Subject: [PATCH 0319/5092] use crate:: where appropriate --- src/fn_call.rs | 2 +- src/helpers.rs | 2 +- src/intrinsic.rs | 2 +- src/lib.rs | 16 ++++++++-------- src/mono_hash_map.rs | 2 +- src/operator.rs | 2 +- src/tls.rs | 2 +- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 9e3f49ac9fd3..7e1ff3233f21 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -4,7 +4,7 @@ use rustc::hir::def_id::DefId; use rustc::mir; use syntax::attr; -use super::*; +use crate::*; pub trait EvalContextExt<'tcx, 'mir> { /// Emulate calling a foreign item, fail if the item is not supported. diff --git a/src/helpers.rs b/src/helpers.rs index c4aad2033e57..6dc5b768ea63 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -3,7 +3,7 @@ use std::mem; use rustc::ty; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; -use super::*; +use crate::*; pub trait ScalarExt { /// HACK: this function just extracts all bits if `defined != 0` diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 852c93f650df..caf5687b231c 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -4,7 +4,7 @@ use rustc::ty; use rustc::mir::interpret::{EvalResult, PointerArithmetic}; -use super::{ +use crate::{ PlaceTy, OpTy, Value, Scalar, ScalarMaybeUndef, Borrow, ScalarExt, OperatorEvalContextExt }; diff --git a/src/lib.rs b/src/lib.rs index 650998c3e16c..cb544e9bb386 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,15 +37,15 @@ mod range_map; mod mono_hash_map; mod stacked_borrows; -use fn_call::EvalContextExt as MissingFnsEvalContextExt; -use operator::EvalContextExt as OperatorEvalContextExt; -use intrinsic::EvalContextExt as IntrinsicEvalContextExt; -use tls::{EvalContextExt as TlsEvalContextExt, TlsData}; -use range_map::RangeMap; +use crate::fn_call::EvalContextExt as MissingFnsEvalContextExt; +use crate::operator::EvalContextExt as OperatorEvalContextExt; +use crate::intrinsic::EvalContextExt as IntrinsicEvalContextExt; +use crate::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; +use crate::range_map::RangeMap; #[allow(unused_imports)] // FIXME rustc bug https://github.com/rust-lang/rust/issues/53682 -use helpers::{ScalarExt, EvalContextExt as HelpersEvalContextExt}; -use mono_hash_map::MonoHashMap; -use stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; +use crate::helpers::{ScalarExt, EvalContextExt as HelpersEvalContextExt}; +use crate::mono_hash_map::MonoHashMap; +use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; // Used by priroda pub use stacked_borrows::{Borrow, Stacks, Mut as MutBorrow}; diff --git a/src/mono_hash_map.rs b/src/mono_hash_map.rs index 76ca7ac6a133..e30578a5a77b 100644 --- a/src/mono_hash_map.rs +++ b/src/mono_hash_map.rs @@ -12,7 +12,7 @@ use std::borrow::Borrow; use rustc_data_structures::fx::FxHashMap; -use super::AllocMap; +use crate::AllocMap; #[derive(Debug, Clone)] pub struct MonoHashMap(RefCell>>); diff --git a/src/operator.rs b/src/operator.rs index 0eac5c11276a..e5c695009cfa 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,7 +1,7 @@ use rustc::ty::{Ty, layout::TyLayout}; use rustc::mir; -use super::*; +use crate::*; pub trait EvalContextExt<'tcx> { fn ptr_op( diff --git a/src/tls.rs b/src/tls.rs index b315e27c45d0..001da10ddc21 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -3,7 +3,7 @@ use std::collections::BTreeMap; use rustc_target::abi::LayoutOf; use rustc::{ty, ty::layout::HasDataLayout, mir}; -use super::{ +use crate::{ EvalResult, EvalErrorKind, StackPopCleanup, MPlaceTy, Scalar, Borrow, }; From fba55ba2a9f9d906dc584e2c8dc6a97a8c137b92 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Oct 2018 17:16:41 +0200 Subject: [PATCH 0320/5092] make the -Z flags we use more consistent --- appveyor.yml | 9 +++++---- src/bin/cargo-miri.rs | 2 +- src/bin/miri-rustc-tests.rs | 4 +--- src/bin/miri.rs | 18 ++++++++++++------ src/lib.rs | 14 ++++++++++++++ xargo/build.sh | 3 ++- 6 files changed, 35 insertions(+), 15 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index cf578120c9dd..1e9ccbdf9500 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -14,19 +14,20 @@ branches: - master install: - # install Rust + # Install Rust. - set PATH=C:\Program Files\Git\mingw64\bin;C:\msys64\mingw%MSYS2_BITS%\bin;%PATH% - set /p RUST_TOOLCHAIN= = std::env::args().collect(); - let sysroot_flag = String::from("--sysroot"); - if !args.contains(&sysroot_flag) { - args.push(sysroot_flag); - args.push(find_sysroot()); - } - + // Parse our own -Z flags and remove them before rustc gets their hand on them. let mut validate = true; args.retain(|arg| { match arg.as_str() { @@ -229,7 +226,16 @@ fn main() { } }); + // Determine sysroot and let rustc know about it + let sysroot_flag = String::from("--sysroot"); + if !args.contains(&sysroot_flag) { + args.push(sysroot_flag); + args.push(find_sysroot()); + } + // Finally, add the default flags all the way in the beginning. + miri::add_miri_default_args(&mut args); + trace!("rustc arguments: {:?}", args); let result = rustc_driver::run(move || { rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls { default: Box::new(RustcDefaultCalls), diff --git a/src/lib.rs b/src/lib.rs index 650998c3e16c..2de6665186bf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,6 +50,20 @@ use stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; // Used by priroda pub use stacked_borrows::{Borrow, Stacks, Mut as MutBorrow}; +/// Insert rustc arguments at the beginning of the argument listthat miri wants to be +/// set per default, for maximal validation power. +pub fn add_miri_default_args(args: &mut Vec) { + // The flags here should be kept in sync with what bootstrap adds when `test-miri` is + // set, which happens in `bootstrap/bin/rustc.rs` in the rustc sources; and also + // kept in sync with `xargo/build.sh` in this repo and `appveyor.yml`. + + // Inserting at index 1, after the binary name + args.splice(1..1, + ["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0"] + .iter().map(|s| s.to_string()) + ); +} + // Used by priroda pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, diff --git a/xargo/build.sh b/xargo/build.sh index 15a7c770910d..25c56d31ab56 100755 --- a/xargo/build.sh +++ b/xargo/build.sh @@ -1,3 +1,4 @@ #!/bin/sh cd "$(dirname "$0")" -RUSTFLAGS='-Zalways-encode-mir -Zmir-emit-validate=1' xargo build +# The flags here should be kept in sync with `add_miri_default_args` in `src/lib.rs`. +RUSTFLAGS='-Zalways-encode-mir -Zmir-emit-retag -Zmir-opt-level=0' xargo build From 7ac0e79ad5bcd8d7e4f8317c15238d5911faf11c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Oct 2018 17:17:44 +0200 Subject: [PATCH 0321/5092] stub Retag hook; fix tests for removal of -Zmir-emit-validate --- src/lib.rs | 16 +++++++++++++++- src/stacked_borrows.rs | 17 ++++++++++++++++- tests/compile-fail-fullmir/stack_free.rs | 2 +- tests/compile-fail/cast_box_int_to_fn_ptr.rs | 2 +- tests/compile-fail/cast_int_to_fn_ptr.rs | 2 +- tests/compile-fail/execute_memory.rs | 2 +- tests/compile-fail/fn_ptr_offset.rs | 2 +- .../{invalid_bool2.rs => invalid_bool.rs} | 2 +- .../{invalid_char2.rs => invalid_char.rs} | 2 +- ...iminant2.rs => invalid_enum_discriminant.rs} | 2 +- tests/compile-fail/never_say_never.rs | 2 +- tests/compile-fail/never_transmute_humans.rs | 2 +- tests/compile-fail/never_transmute_void.rs | 2 +- tests/compile-fail/panic.rs | 2 -- tests/compile-fail/reference_to_packed.rs | 2 +- .../static_memory_modification.rs | 8 ++++++++ .../compile-fail/static_memory_modification.rs | 2 +- .../compile-fail/static_memory_modification2.rs | 2 +- .../compile-fail/static_memory_modification3.rs | 2 +- tests/compile-fail/storage_dead_dangling.rs | 2 +- tests/compile-fail/transmute_fat.rs | 2 +- tests/compile-fail/unaligned_ptr_cast.rs | 2 +- tests/compile-fail/unaligned_ptr_cast2.rs | 2 +- tests/compile-fail/undefined_byte_read.rs | 3 --- tests/compile-fail/validity/execute_memory.rs | 8 ++++++++ tests/compile-fail/validity/fn_ptr_offset.rs | 10 ++++++++++ tests/compiletest.rs | 7 +------ tests/run-pass/move-undef-primval.rs | 3 --- tests/run-pass/packed_struct.rs | 1 - tests/run-pass/recursive_static.rs | 3 --- tests/run-pass/regions-mock-trans.rs | 3 --- tests/run-pass/slice-of-zero-size-elements.rs | 2 -- 32 files changed, 77 insertions(+), 44 deletions(-) rename tests/compile-fail/{invalid_bool2.rs => invalid_bool.rs} (73%) rename tests/compile-fail/{invalid_char2.rs => invalid_char.rs} (80%) rename tests/compile-fail/{invalid_enum_discriminant2.rs => invalid_enum_discriminant.rs} (79%) create mode 100644 tests/compile-fail/stacked_borrows/static_memory_modification.rs create mode 100644 tests/compile-fail/validity/execute_memory.rs create mode 100644 tests/compile-fail/validity/fn_ptr_offset.rs diff --git a/src/lib.rs b/src/lib.rs index 2de6665186bf..5d20078082f9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,7 +26,7 @@ use syntax::attr; pub use rustc_mir::interpret::*; -pub use rustc_mir::interpret::{self, AllocMap}; // resolve ambiguity +pub use rustc_mir::interpret::{self, AllocMap, PlaceTy}; // resolve ambiguity mod fn_call; mod operator; @@ -521,4 +521,18 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { Ok(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag)) } } + + #[inline(always)] + fn retag( + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + fn_entry: bool, + place: PlaceTy<'tcx, Borrow>, + ) -> EvalResult<'tcx> { + if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !ecx.machine.validate { + // No tracking, or no retagging. This is possible because a dependency of ours might be + // called with different flags than we are, + return Ok(()) + } + ecx.retag(fn_entry, place) + } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index a569ed4e5551..22216345b65e 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -5,7 +5,7 @@ use rustc::hir; use super::{ MemoryAccess, MemoryKind, MiriMemoryKind, RangeMap, EvalResult, AllocId, - Pointer, + Pointer, PlaceTy, }; pub type Timestamp = u64; @@ -362,6 +362,12 @@ pub trait EvalContextExt<'tcx> { id: AllocId, kind: MemoryKind, ) -> Borrow; + + fn retag( + &mut self, + fn_entry: bool, + place: PlaceTy<'tcx, Borrow> + ) -> EvalResult<'tcx>; } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { @@ -506,4 +512,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' alloc.extra.first_borrow(mut_borrow, size); Borrow::Mut(mut_borrow) } + + fn retag( + &mut self, + _fn_entry: bool, + _place: PlaceTy<'tcx, Borrow> + ) -> EvalResult<'tcx> { + // TODO do something + Ok(()) + } } diff --git a/tests/compile-fail-fullmir/stack_free.rs b/tests/compile-fail-fullmir/stack_free.rs index 6d853e75fb4a..a33bca126759 100644 --- a/tests/compile-fail-fullmir/stack_free.rs +++ b/tests/compile-fail-fullmir/stack_free.rs @@ -1,5 +1,5 @@ // Validation changes why we fail -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation // error-pattern: tried to deallocate Stack memory but gave Machine(Rust) as the kind diff --git a/tests/compile-fail/cast_box_int_to_fn_ptr.rs b/tests/compile-fail/cast_box_int_to_fn_ptr.rs index c3b1fa595888..7ee3bc62767f 100644 --- a/tests/compile-fail/cast_box_int_to_fn_ptr.rs +++ b/tests/compile-fail/cast_box_int_to_fn_ptr.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation fn main() { let b = Box::new(42); diff --git a/tests/compile-fail/cast_int_to_fn_ptr.rs b/tests/compile-fail/cast_int_to_fn_ptr.rs index 1971ce1557e7..207af4ae2cef 100644 --- a/tests/compile-fail/cast_int_to_fn_ptr.rs +++ b/tests/compile-fail/cast_int_to_fn_ptr.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation fn main() { let g = unsafe { diff --git a/tests/compile-fail/execute_memory.rs b/tests/compile-fail/execute_memory.rs index d859e9072e32..295756ef0f56 100644 --- a/tests/compile-fail/execute_memory.rs +++ b/tests/compile-fail/execute_memory.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation #![feature(box_syntax)] diff --git a/tests/compile-fail/fn_ptr_offset.rs b/tests/compile-fail/fn_ptr_offset.rs index cccb21790d65..9d29316fe24f 100644 --- a/tests/compile-fail/fn_ptr_offset.rs +++ b/tests/compile-fail/fn_ptr_offset.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation use std::mem; diff --git a/tests/compile-fail/invalid_bool2.rs b/tests/compile-fail/invalid_bool.rs similarity index 73% rename from tests/compile-fail/invalid_bool2.rs rename to tests/compile-fail/invalid_bool.rs index 2348c62559b0..e80dc15efaec 100644 --- a/tests/compile-fail/invalid_bool2.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation fn main() { let b = unsafe { std::mem::transmute::(2) }; diff --git a/tests/compile-fail/invalid_char2.rs b/tests/compile-fail/invalid_char.rs similarity index 80% rename from tests/compile-fail/invalid_char2.rs rename to tests/compile-fail/invalid_char.rs index 5de2d073f323..b67ed9ba520d 100644 --- a/tests/compile-fail/invalid_char2.rs +++ b/tests/compile-fail/invalid_char.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); diff --git a/tests/compile-fail/invalid_enum_discriminant2.rs b/tests/compile-fail/invalid_enum_discriminant.rs similarity index 79% rename from tests/compile-fail/invalid_enum_discriminant2.rs rename to tests/compile-fail/invalid_enum_discriminant.rs index ea94081693e1..bd5cb55b6c92 100644 --- a/tests/compile-fail/invalid_enum_discriminant2.rs +++ b/tests/compile-fail/invalid_enum_discriminant.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation // error-pattern: invalid enum discriminant diff --git a/tests/compile-fail/never_say_never.rs b/tests/compile-fail/never_say_never.rs index 634488489b53..d7e6a8c09f64 100644 --- a/tests/compile-fail/never_say_never.rs +++ b/tests/compile-fail/never_say_never.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation #![feature(never_type)] #![allow(unreachable_code)] diff --git a/tests/compile-fail/never_transmute_humans.rs b/tests/compile-fail/never_transmute_humans.rs index c5c53d4231c7..169e861be0b1 100644 --- a/tests/compile-fail/never_transmute_humans.rs +++ b/tests/compile-fail/never_transmute_humans.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation #![feature(never_type)] #![allow(unreachable_code)] diff --git a/tests/compile-fail/never_transmute_void.rs b/tests/compile-fail/never_transmute_void.rs index 5620b6559cfd..9c0165fed222 100644 --- a/tests/compile-fail/never_transmute_void.rs +++ b/tests/compile-fail/never_transmute_void.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation #![feature(never_type)] #![allow(unreachable_code)] diff --git a/tests/compile-fail/panic.rs b/tests/compile-fail/panic.rs index 80149eeffaa6..0d594f9bd4c3 100644 --- a/tests/compile-fail/panic.rs +++ b/tests/compile-fail/panic.rs @@ -1,5 +1,3 @@ -// FIXME: Something in panic handling fails validation with full-MIR -// compile-flags: -Zmir-emit-validate=0 //error-pattern: the evaluated program panicked fn main() { diff --git a/tests/compile-fail/reference_to_packed.rs b/tests/compile-fail/reference_to_packed.rs index 14a2afc33f7f..befe96f2b35d 100644 --- a/tests/compile-fail/reference_to_packed.rs +++ b/tests/compile-fail/reference_to_packed.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation #![allow(dead_code, unused_variables)] diff --git a/tests/compile-fail/stacked_borrows/static_memory_modification.rs b/tests/compile-fail/stacked_borrows/static_memory_modification.rs new file mode 100644 index 000000000000..c092cbfe5098 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/static_memory_modification.rs @@ -0,0 +1,8 @@ +static X: usize = 5; + +#[allow(mutable_transmutes)] +fn main() { + let _x = unsafe { + std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR mutable reference with frozen tag + }; +} diff --git a/tests/compile-fail/static_memory_modification.rs b/tests/compile-fail/static_memory_modification.rs index c75892645865..07a277a16f3a 100644 --- a/tests/compile-fail/static_memory_modification.rs +++ b/tests/compile-fail/static_memory_modification.rs @@ -1,5 +1,5 @@ // Validation detects that we are casting & to &mut and so it changes why we fail -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation static X: usize = 5; diff --git a/tests/compile-fail/static_memory_modification2.rs b/tests/compile-fail/static_memory_modification2.rs index c9857b20592e..73928f533cb7 100644 --- a/tests/compile-fail/static_memory_modification2.rs +++ b/tests/compile-fail/static_memory_modification2.rs @@ -1,5 +1,5 @@ // Validation detects that we are casting & to &mut and so it changes why we fail -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation use std::mem::transmute; diff --git a/tests/compile-fail/static_memory_modification3.rs b/tests/compile-fail/static_memory_modification3.rs index 41a62787296f..280f34a5a021 100644 --- a/tests/compile-fail/static_memory_modification3.rs +++ b/tests/compile-fail/static_memory_modification3.rs @@ -1,5 +1,5 @@ // Validation detects that we are casting & to &mut and so it changes why we fail -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation use std::mem::transmute; diff --git a/tests/compile-fail/storage_dead_dangling.rs b/tests/compile-fail/storage_dead_dangling.rs index 69917dce8591..85c76f6f41f6 100644 --- a/tests/compile-fail/storage_dead_dangling.rs +++ b/tests/compile-fail/storage_dead_dangling.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation static mut LEAK: usize = 0; diff --git a/tests/compile-fail/transmute_fat.rs b/tests/compile-fail/transmute_fat.rs index e1f916910d73..ede0486be413 100644 --- a/tests/compile-fail/transmute_fat.rs +++ b/tests/compile-fail/transmute_fat.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmir-emit-validate=0 +// compile-flags: -Zmiri-disable-validation fn main() { #[cfg(target_pointer_width="64")] diff --git a/tests/compile-fail/unaligned_ptr_cast.rs b/tests/compile-fail/unaligned_ptr_cast.rs index 47317afd36ec..e64594d3e7ed 100644 --- a/tests/compile-fail/unaligned_ptr_cast.rs +++ b/tests/compile-fail/unaligned_ptr_cast.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation fn main() { let x = &2u16; diff --git a/tests/compile-fail/unaligned_ptr_cast2.rs b/tests/compile-fail/unaligned_ptr_cast2.rs index d146f21dfe60..1112f2f33c14 100644 --- a/tests/compile-fail/unaligned_ptr_cast2.rs +++ b/tests/compile-fail/unaligned_ptr_cast2.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation fn main() { let x = &2u16; diff --git a/tests/compile-fail/undefined_byte_read.rs b/tests/compile-fail/undefined_byte_read.rs index 1f092936148e..fca749ef9ccb 100644 --- a/tests/compile-fail/undefined_byte_read.rs +++ b/tests/compile-fail/undefined_byte_read.rs @@ -1,6 +1,3 @@ -// This should fail even without validation -// compile-flags: -Zmir-emit-validate=0 - fn main() { let v: Vec = Vec::with_capacity(10); let undef = unsafe { *v.get_unchecked(5) }; diff --git a/tests/compile-fail/validity/execute_memory.rs b/tests/compile-fail/validity/execute_memory.rs new file mode 100644 index 000000000000..426a51faf8a3 --- /dev/null +++ b/tests/compile-fail/validity/execute_memory.rs @@ -0,0 +1,8 @@ +#![feature(box_syntax)] + +fn main() { + let x = box 42; + unsafe { + let _f = std::mem::transmute::, fn()>(x); //~ ERROR encountered a pointer, but expected a function pointer + } +} diff --git a/tests/compile-fail/validity/fn_ptr_offset.rs b/tests/compile-fail/validity/fn_ptr_offset.rs new file mode 100644 index 000000000000..4989f4d3af7b --- /dev/null +++ b/tests/compile-fail/validity/fn_ptr_offset.rs @@ -0,0 +1,10 @@ +use std::mem; + +fn f() {} + +fn main() { + let x : fn() = f; + let y : *mut u8 = unsafe { mem::transmute(x) }; + let y = y.wrapping_offset(1); + let _x : fn() = unsafe { mem::transmute(y) }; //~ ERROR encountered a potentially NULL pointer +} diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 0b2058597e18..98e3fde54e69 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -58,13 +58,11 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullm let mut flags = Vec::new(); flags.push(format!("--sysroot {}", sysroot.display())); flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs - flags.push("-Zmir-emit-validate=1".to_owned()); if opt { // Optimizing too aggressivley makes UB detection harder, but test at least // the default value. + // FIXME: Opt level 3 ICEs during stack trace generation. flags.push("-Zmir-opt-level=1".to_owned()); - } else { - flags.push("-Zmir-opt-level=0".to_owned()); } let mut config = compiletest::Config::default().tempdir(); @@ -102,11 +100,8 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: let mut flags = Vec::new(); flags.push(format!("--sysroot {}", sysroot.display())); flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs - flags.push("-Zmir-emit-validate=1".to_owned()); if opt { flags.push("-Zmir-opt-level=3".to_owned()); - } else { - flags.push("-Zmir-opt-level=0".to_owned()); } let mut config = compiletest::Config::default().tempdir(); diff --git a/tests/run-pass/move-undef-primval.rs b/tests/run-pass/move-undef-primval.rs index 2c18c2d3687a..73c33943a63a 100644 --- a/tests/run-pass/move-undef-primval.rs +++ b/tests/run-pass/move-undef-primval.rs @@ -1,6 +1,3 @@ -// Moving around undef is not allowed by validation -// compile-flags: -Zmir-emit-validate=0 - struct Foo { _inner: i32, } diff --git a/tests/run-pass/packed_struct.rs b/tests/run-pass/packed_struct.rs index e10781e65605..303e90742fc1 100644 --- a/tests/run-pass/packed_struct.rs +++ b/tests/run-pass/packed_struct.rs @@ -1,4 +1,3 @@ -// compile-flags: -Zmir-emit-validate=0 #![allow(dead_code)] #![feature(unsize, coerce_unsized)] diff --git a/tests/run-pass/recursive_static.rs b/tests/run-pass/recursive_static.rs index d259ca6361c9..77f2902917a1 100644 --- a/tests/run-pass/recursive_static.rs +++ b/tests/run-pass/recursive_static.rs @@ -1,6 +1,3 @@ -// FIXME: Disable validation until we figure out how to handle recursive statics. -// compile-flags: -Zmir-emit-validate=0 - struct S(&'static S); static S1: S = S(&S2); static S2: S = S(&S1); diff --git a/tests/run-pass/regions-mock-trans.rs b/tests/run-pass/regions-mock-trans.rs index 039175e9acd6..130eaa288ebe 100644 --- a/tests/run-pass/regions-mock-trans.rs +++ b/tests/run-pass/regions-mock-trans.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME: We handle uninitialized storage here, which currently makes validation fail. -// compile-flags: -Zmir-emit-validate=0 - //ignore-windows: Uses POSIX APIs #![feature(libc)] diff --git a/tests/run-pass/slice-of-zero-size-elements.rs b/tests/run-pass/slice-of-zero-size-elements.rs index dbe8ec9addac..aa9d117d726f 100644 --- a/tests/run-pass/slice-of-zero-size-elements.rs +++ b/tests/run-pass/slice-of-zero-size-elements.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -C debug-assertions - use std::slice; fn foo(v: &[T]) -> Option<&[T]> { From bba3c49e844895cdc32dc6ea1acbf0c6555beefd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 26 Oct 2018 11:31:20 +0200 Subject: [PATCH 0322/5092] basic retagging (no fn_entry); this also makes us catch more bugs even with optimizations and we can finally stop mutating the state on deref --- src/lib.rs | 4 +- src/stacked_borrows.rs | 76 +++++++++---------- .../stacked_borrows/alias_through_mutation.rs | 3 - .../stacked_borrows/buggy_as_mut_slice.rs | 3 - .../stacked_borrows/buggy_split_at_mut.rs | 3 - .../stacked_borrows/illegal_write2.rs | 3 - .../stacked_borrows/illegal_write4.rs | 34 ++------- .../stacked_borrows/shared_confusion.rs | 10 ++- .../stacked_borrows/shared_confusion_opt.rs | 25 ++++++ 9 files changed, 81 insertions(+), 80 deletions(-) create mode 100644 tests/compile-fail/stacked_borrows/shared_confusion_opt.rs diff --git a/src/lib.rs b/src/lib.rs index 5d20078082f9..e1ae805fb15f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -528,9 +528,11 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn_entry: bool, place: PlaceTy<'tcx, Borrow>, ) -> EvalResult<'tcx> { - if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !ecx.machine.validate { + if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !Self::enforce_validity(ecx) { // No tracking, or no retagging. This is possible because a dependency of ours might be // called with different flags than we are, + // Also, honor the whitelist in `enforce_validity` because otherwise we might retag + // uninitialized data. return Ok(()) } ecx.retag(fn_entry, place) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 22216345b65e..cb8c2a3e5e61 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -1,6 +1,6 @@ -use std::cell::{Cell, RefCell}; +use std::cell::RefCell; -use rustc::ty::{Ty, layout::Size}; +use rustc::ty::{self, Ty, layout::Size}; use rustc::hir; use super::{ @@ -101,12 +101,12 @@ impl From> for RefKind { /// Extra global machine state #[derive(Clone, Debug)] pub struct State { - clock: Cell + clock: Timestamp } impl State { pub fn new() -> State { - State { clock: Cell::new(0) } + State { clock: 0 } } } @@ -129,6 +129,7 @@ impl Default for Stack { /// Extra per-allocation state #[derive(Clone, Debug, Default)] pub struct Stacks { + // Even reading memory can have effects on the stack, so we need a `RefCell` here. stacks: RefCell>, } @@ -249,9 +250,9 @@ impl<'tcx> Stack { } impl State { - fn increment_clock(&self) -> Timestamp { - let val = self.clock.get(); - self.clock.set(val + 1); + fn increment_clock(&mut self) -> Timestamp { + let val = self.clock; + self.clock = val + 1; val } } @@ -334,14 +335,8 @@ impl<'tcx> Stacks { } pub trait EvalContextExt<'tcx> { - fn tag_for_pointee( - &self, - pointee_ty: Ty<'tcx>, - ref_kind: RefKind, - ) -> Borrow; - fn tag_reference( - &self, + &mut self, ptr: Pointer, pointee_ty: Ty<'tcx>, size: Size, @@ -371,13 +366,16 @@ pub trait EvalContextExt<'tcx> { } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { - fn tag_for_pointee( - &self, + /// Called for place-to-value conversion. + fn tag_reference( + &mut self, + ptr: Pointer, pointee_ty: Ty<'tcx>, + size: Size, ref_kind: RefKind, - ) -> Borrow { + ) -> EvalResult<'tcx, Borrow> { let time = self.machine.stacked_borrows.increment_clock(); - match ref_kind { + let new_bor = match ref_kind { RefKind::Mut => Borrow::Mut(Mut::Uniq(time)), RefKind::Shr => // FIXME This does not do enough checking when only part of the data has @@ -390,18 +388,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' Borrow::Mut(Mut::Raw) }, RefKind::Raw => Borrow::Mut(Mut::Raw), - } - } - - /// Called for place-to-value conversion. - fn tag_reference( - &self, - ptr: Pointer, - pointee_ty: Ty<'tcx>, - size: Size, - ref_kind: RefKind, - ) -> EvalResult<'tcx, Borrow> { - let new_bor = self.tag_for_pointee(pointee_ty, ref_kind); + }; trace!("tag_reference: Creating new reference ({:?}) for {:?} (pointee {}, size {}): {:?}", ref_kind, ptr, pointee_ty, size.bytes(), new_bor); @@ -424,7 +411,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' fn tag_dereference( &self, ptr: Pointer, - pointee_ty: Ty<'tcx>, + _pointee_ty: Ty<'tcx>, size: Size, ref_kind: RefKind, ) -> EvalResult<'tcx, Borrow> { @@ -454,13 +441,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // also using `var`, and that would be okay. } (RefKind::Shr, Borrow::Mut(Mut::Uniq(_))) => { - // A mut got transmuted to shr. High time we freeze this location! - // Make this a delayed reborrow. Redundant reborows to shr are okay, - // so we do not have to be worried about doing too much. - // FIXME: Reconsider if we really want to mutate things while doing just a deref, - // which, in particular, validation does. - trace!("tag_dereference: Lazy freezing of {:?}", ptr); - return self.tag_reference(ptr, pointee_ty, size, ref_kind); + // A mut got transmuted to shr. The mut borrow must be reactivatable. } (RefKind::Mut, Borrow::Frz(_)) => { // This is just invalid. @@ -516,9 +497,24 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' fn retag( &mut self, _fn_entry: bool, - _place: PlaceTy<'tcx, Borrow> + place: PlaceTy<'tcx, Borrow> ) -> EvalResult<'tcx> { - // TODO do something + // For now, we only retag if the toplevel type is a reference. + // TODO: Recurse into structs and enums, sharing code with validation. + let mutbl = match place.layout.ty.sty { + ty::Ref(_, _, mutbl) => mutbl, // go ahead + _ => return Ok(()), // don't do a thing + }; + // We want to reborrow the reference stored there. This will call the hooks + // above. First deref. + // (This is somewhat redundant because validation already did the same thing, + // but what can you do.) + let val = self.read_value(self.place_to_op(place)?)?; + let dest = self.ref_to_mplace(val)?; + // Now put a new ref into the old place. + // FIXME: Honor `fn_entry`! + let val = self.create_ref(dest, Some(mutbl))?; + self.write_value(val, place)?; Ok(()) } } diff --git a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs index 7d56f30b3e69..eb8966f3a5c7 100644 --- a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs +++ b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs @@ -1,6 +1,3 @@ -// With optimizations, we just store a raw in `x`, and there is no problem. -// compile-flags: -Zmir-opt-level=0 - #![allow(unused_variables)] // This makes a ref that was passed to us via &mut alias with things it should not alias with diff --git a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs index dc1e3cc81e9e..e86eb9ba6de8 100644 --- a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs +++ b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs @@ -1,6 +1,3 @@ -// FIXME: Without retagging, optimization kills finding this problem -// compile-flags: -Zmir-opt-level=0 - #![allow(unused_variables)] mod safe { diff --git a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs index a697ba9167c0..a4f5f536b770 100644 --- a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs @@ -1,6 +1,3 @@ -// FIXME: Without retagging, optimization kills finding this problem -// compile-flags: -Zmir-opt-level=0 - #![allow(unused_variables)] mod safe { diff --git a/tests/compile-fail/stacked_borrows/illegal_write2.rs b/tests/compile-fail/stacked_borrows/illegal_write2.rs index ac9c3397f534..f4fefaad5e22 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write2.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write2.rs @@ -1,6 +1,3 @@ -// The reborow gets optimized away, so we can only detect this issue without optimizations -// compile-flags: -Zmir-opt-level=0 - #![allow(unused_variables)] fn main() { diff --git a/tests/compile-fail/stacked_borrows/illegal_write4.rs b/tests/compile-fail/stacked_borrows/illegal_write4.rs index 094a38951974..12deb518b4e7 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write4.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write4.rs @@ -1,31 +1,13 @@ -// The compiler inserts some reborrows, enable optimizations to -// get rid of them. -// compile-flags: -Zmir-opt-level=1 - use std::mem; -// This is an example of a piece of code that intuitively seems like we might -// want to reject it, but that doesn't turn out to be possible. - fn main() { - let target = 42; - // Make sure a cannot use a raw-tagged `&mut` pointing to a frozen location, not - // even to create a raw. - let reference = ⌖ // freeze + let mut target = 42; + // Make sure we cannot use a raw-tagged `&mut` pointing to a frozen location. + // Even just creating it unfreezes. + let raw = &mut target as *mut _; // let this leak to raw + let reference = unsafe { &*raw }; // freeze let ptr = reference as *const _ as *mut i32; // raw ptr, with raw tag - let mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag - // Now we have an &mut to a frozen location, but that is completely normal: - // We'd just unfreeze the location if we used it. - let bad_ptr = mut_ref as *mut i32; // even just creating this is like a use of `mut_ref`. - // That violates the location being frozen! However, we do not properly detect this: - // We first see a `&mut` with a `Raw` tag being deref'd for a frozen location, - // which can happen legitimately if the compiler optimized away an `&mut*` that - // turns a raw into a `&mut`. Next, we create a raw ref to a frozen location - // from a `Raw` tag, which can happen legitimately when interior mutability - // is involved. - let _val = *reference; // Make sure it is still frozen. - - // We only actually unfreeze once we muteate through the bad pointer. - unsafe { *bad_ptr = 42 }; //~ ERROR does not exist on the stack - let _val = *reference; + let _mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag + // Now we retag, making our ref top-of-stack -- and, in particular, unfreezing. + let _val = *reference; //~ ERROR Location should be frozen } diff --git a/tests/compile-fail/stacked_borrows/shared_confusion.rs b/tests/compile-fail/stacked_borrows/shared_confusion.rs index e3e4c4da7765..c02822ed4d3d 100644 --- a/tests/compile-fail/stacked_borrows/shared_confusion.rs +++ b/tests/compile-fail/stacked_borrows/shared_confusion.rs @@ -1,3 +1,11 @@ +// Optimization kills all the reborrows, enough to make this error go away. There are +// no retags either because we don't retag immediately after a `&[mut]`; we rely on +// that creating a fresh reference. +// See `shared_confusion_opt.rs` for a variant that is caught even with optimizations. +// Keep this test to make sure that without optimizations, we do not have to actually +// use the `x_inner_shr`. +// compile-flags: -Zmir-opt-level=0 + #![allow(unused_variables)] use std::cell::RefCell; @@ -9,7 +17,7 @@ fn test(r: &mut RefCell) { { let x_inner_shr = &*x_inner; // frozen let y = &*r; // outer ref, not freezing - let x_inner_shr2 = &*x_inner; // freezing again + let x_inner_shr = &*x_inner; // freezing again } // Our old raw should be dead by now unsafe { *x_evil = 0; } // this falls back to some Raw higher up the stack diff --git a/tests/compile-fail/stacked_borrows/shared_confusion_opt.rs b/tests/compile-fail/stacked_borrows/shared_confusion_opt.rs new file mode 100644 index 000000000000..4a88d4d64133 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/shared_confusion_opt.rs @@ -0,0 +1,25 @@ +// A variant of `shared_confusion.rs` that gets flagged even with optimizations. + +#![allow(unused_variables)] +use std::cell::RefCell; + +fn test(r: &mut RefCell) { + let x = &*r; // not freezing because interior mutability + let mut x_ref = x.borrow_mut(); + let x_inner : &mut i32 = &mut *x_ref; // Uniq reference + let x_evil = x_inner as *mut _; + { + let x_inner_shr = &*x_inner; // frozen + let _val = *x_inner_shr; + let y = &*r; // outer ref, not freezing + let x_inner_shr = &*x_inner; // freezing again + let _val = *x_inner_shr; + } + // Our old raw should be dead by now + unsafe { *x_evil = 0; } // this falls back to some Raw higher up the stack + *x_inner = 12; //~ ERROR Mut reference with non-reactivatable tag +} + +fn main() { + test(&mut RefCell::new(0)); +} From 85f821d7e9c1f920e6584821ffa0dbccded8f657 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 29 Oct 2018 19:48:43 +0100 Subject: [PATCH 0323/5092] unify checks on memory access and reborrowing, and update for Machine trait change --- src/lib.rs | 17 ++- src/stacked_borrows.rs | 121 +++++++++++------- .../stacked_borrows/illegal_read1.rs | 15 +++ .../stacked_borrows/illegal_read2.rs | 18 +++ .../stacked_borrows/illegal_write5.rs | 15 +++ .../stacked_borrows/load_invalid_shr.rs | 2 +- .../stacked_borrows/pass_invalid_shr.rs | 2 +- .../stacked_borrows/return_invalid_shr.rs | 2 +- 8 files changed, 137 insertions(+), 55 deletions(-) create mode 100644 tests/compile-fail/stacked_borrows/illegal_read1.rs create mode 100644 tests/compile-fail/stacked_borrows/illegal_read2.rs create mode 100644 tests/compile-fail/stacked_borrows/illegal_write5.rs diff --git a/src/lib.rs b/src/lib.rs index e1ae805fb15f..b397e9a6d224 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -452,21 +452,30 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { } #[inline(always)] - fn memory_accessed( + fn memory_read( alloc: &Allocation, ptr: Pointer, size: Size, - access: MemoryAccess, ) -> EvalResult<'tcx> { - alloc.extra.memory_accessed(ptr, size, access) + alloc.extra.memory_read(ptr, size) + } + + #[inline(always)] + fn memory_written( + alloc: &mut Allocation, + ptr: Pointer, + size: Size, + ) -> EvalResult<'tcx> { + alloc.extra.memory_written(ptr, size) } #[inline(always)] fn memory_deallocated( alloc: &mut Allocation, ptr: Pointer, + size: Size, ) -> EvalResult<'tcx> { - alloc.extra.memory_deallocated(ptr) + alloc.extra.memory_deallocated(ptr, size) } #[inline(always)] diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index cb8c2a3e5e61..baeb04b44ea7 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -4,7 +4,7 @@ use rustc::ty::{self, Ty, layout::Size}; use rustc::hir; use super::{ - MemoryAccess, MemoryKind, MiriMemoryKind, RangeMap, EvalResult, AllocId, + MemoryKind, MiriMemoryKind, RangeMap, EvalResult, AllocId, Pointer, PlaceTy, }; @@ -126,6 +126,13 @@ impl Default for Stack { } } +impl Stack { + #[inline(always)] + fn is_frozen(&self) -> bool { + self.frozen_since.is_some() + } +} + /// Extra per-allocation state #[derive(Clone, Debug, Default)] pub struct Stacks { @@ -206,8 +213,13 @@ impl<'tcx> Stack { match action { None => {}, // nothing to do Some(top) => { + if self.frozen_since.is_some() { + trace!("reactivate: Unfreezing"); + } self.frozen_since = None; - self.borrows.truncate(top+1); + for itm in self.borrows.drain(top+1..).rev() { + trace!("reactivate: Popping {:?}", itm); + } } } @@ -215,7 +227,9 @@ impl<'tcx> Stack { } /// Initiate `bor`; mostly this means freezing or pushing. - fn initiate(&mut self, bor: Borrow) -> EvalResult<'tcx> { + /// This operation cannot fail; it is up to the caller to ensure that the precondition + /// is met: We cannot push onto frozen stacks. + fn initiate(&mut self, bor: Borrow) { match bor { Borrow::Frz(t) => { match self.frozen_since { @@ -241,11 +255,10 @@ impl<'tcx> Stack { // from it is fine with this as well. trace!("initiate: Initiating a raw on a frozen location, not doing a thing"), Some(_) => - return err!(MachineError(format!("Trying to mutate frozen location"))) + bug!("Trying to mutate frozen location") } } } - Ok(()) } } @@ -259,49 +272,27 @@ impl State { /// Higher-level operations impl<'tcx> Stacks { - pub fn memory_accessed( + /// The single most operation: Make sure that using `ptr` as `ref_kind` is okay, + /// and if `new_bor` is present then make that the new current borrow. + fn use_and_maybe_re_borrow( &self, ptr: Pointer, size: Size, - access: MemoryAccess, + ref_kind: RefKind, + new_bor: Option, ) -> EvalResult<'tcx> { - trace!("memory_accessed({:?}) with tag {:?}: {:?}, size {}", access, ptr.tag, ptr, size.bytes()); + trace!("use_and_maybe_re_borrow of tag {:?} as {:?}, new {:?}: {:?}, size {}", + ptr.tag, ref_kind, new_bor, ptr, size.bytes()); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { - // FIXME: Compare this with what the blog post says. - stack.reactivate(ptr.tag, /*force_mut*/access == MemoryAccess::Write)?; - } - Ok(()) - } - - pub fn memory_deallocated( - &mut self, - ptr: Pointer, - ) -> EvalResult<'tcx> { - trace!("memory_deallocated with tag {:?}: {:?}", ptr.tag, ptr); - let stacks = self.stacks.get_mut(); - for stack in stacks.iter_mut_all() { - // This is like mutating. - stack.reactivate(ptr.tag, /*force_mut*/true)?; - } - Ok(()) - } - - fn reborrow( - &self, - ptr: Pointer, - size: Size, - new_bor: Borrow, - permit_redundant: bool, - ) -> EvalResult<'tcx> { - let mut stacks = self.stacks.borrow_mut(); - for stack in stacks.iter_mut(ptr.offset, size) { - if permit_redundant && stack.check(new_bor) { - // The new borrow is already active! This can happen when creating multiple - // shared references from the same mutable reference. Do nothing. - trace!("reborrow: New borrow {:?} is already active, not doing a thing", new_bor); + if ref_kind == RefKind::Shr && stack.is_frozen() { + // Location already frozen. We don't want to unfreeze, but make sure + // the ref makes some sense. + if let Err(err) = stack.reactivatable(ptr.tag, /*force_mut*/false) { + return err!(MachineError(err)); + } } else { - // If we are creating a uniq ref, we certainly want to unfreeze. + // If we are creating a mutable ref, we certainly want to unfreeze. // Even if we are doing so from a raw. // Notice that if this is a local, whenever we access it directly the // tag here will be the bottommost `Uniq` for that local. That `Uniq` @@ -312,14 +303,47 @@ impl<'tcx> Stacks { // `reset` which the blog post [1] says to perform when accessing a local. // // [1] https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html - stack.reactivate(ptr.tag, /*force_mut*/new_bor.is_uniq())?; - stack.initiate(new_bor)?; + let force_mut = ref_kind == RefKind::Mut; + stack.reactivate(ptr.tag, force_mut)?; + } + if let Some(new_bor) = new_bor { + stack.initiate(new_bor); } } Ok(()) } + #[inline(always)] + pub fn memory_read( + &self, + ptr: Pointer, + size: Size, + ) -> EvalResult<'tcx> { + // Reads behave exactly like the first half of a reborrow-to-shr + self.use_and_maybe_re_borrow(ptr, size, RefKind::Shr, None) + } + + #[inline(always)] + pub fn memory_written( + &mut self, + ptr: Pointer, + size: Size, + ) -> EvalResult<'tcx> { + // Writes behave exactly like the first half of a reborrow-to-mut + self.use_and_maybe_re_borrow(ptr, size, RefKind::Mut, None) + } + + pub fn memory_deallocated( + &mut self, + ptr: Pointer, + size: Size, + ) -> EvalResult<'tcx> { + // This is like mutating + self.use_and_maybe_re_borrow(ptr, size, RefKind::Mut, None) + // FIXME: Error out of there are any barriers? + } + /// Pushes the first borrow to the stacks, must be a mutable one. pub fn first_borrow( &mut self, @@ -398,8 +422,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Update the stacks. We cannot use `get_mut` becuse this might be immutable // memory. let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); - let permit_redundant = ref_kind == RefKind::Shr; // redundant shared refs are okay - alloc.extra.reborrow(ptr, size, new_bor, permit_redundant)?; + alloc.extra.use_and_maybe_re_borrow(ptr, size, ref_kind, Some(new_bor))?; Ok(new_bor) } @@ -411,10 +434,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' fn tag_dereference( &self, ptr: Pointer, - _pointee_ty: Ty<'tcx>, + pointee_ty: Ty<'tcx>, size: Size, ref_kind: RefKind, ) -> EvalResult<'tcx, Borrow> { + trace!("tag_reference: Accessing reference ({:?}) for {:?} (pointee {}, size {})", + ref_kind, ptr, pointee_ty, size.bytes()); // In principle we should not have to do anything here. However, with transmutes involved, // it can happen that the tag of `ptr` does not actually match `ref_kind`, and we // should adjust for that. @@ -506,12 +531,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' _ => return Ok(()), // don't do a thing }; // We want to reborrow the reference stored there. This will call the hooks - // above. First deref. + // above. First deref, which will call `tag_dereference`. // (This is somewhat redundant because validation already did the same thing, // but what can you do.) let val = self.read_value(self.place_to_op(place)?)?; let dest = self.ref_to_mplace(val)?; - // Now put a new ref into the old place. + // Now put a new ref into the old place, which will call `tag_reference`. // FIXME: Honor `fn_entry`! let val = self.create_ref(dest, Some(mutbl))?; self.write_value(val, place)?; diff --git a/tests/compile-fail/stacked_borrows/illegal_read1.rs b/tests/compile-fail/stacked_borrows/illegal_read1.rs new file mode 100644 index 000000000000..f0e696c457cb --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read1.rs @@ -0,0 +1,15 @@ +// A callee may not read the destination of our `&mut` without +// us noticing. + +fn main() { + let mut x = 15; + let xraw = &mut x as *mut _; + let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... + callee(xraw); + let _val = *xref; // ...but any use of raw will invalidate our ref. + //~^ ERROR: Mut reference with non-reactivatable tag +} + +fn callee(xraw: *mut i32) { + let _val = unsafe { *xraw }; +} diff --git a/tests/compile-fail/stacked_borrows/illegal_read2.rs b/tests/compile-fail/stacked_borrows/illegal_read2.rs new file mode 100644 index 000000000000..ec59c57d31b7 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read2.rs @@ -0,0 +1,18 @@ +// A callee may not read the destination of our `&mut` without +// us noticing. + +fn main() { + let mut x = 15; + let xraw = &mut x as *mut _; + let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... + callee(xraw); + let _val = *xref; // ...but any use of raw will invalidate our ref. + //~^ ERROR: Mut reference with non-reactivatable tag +} + +fn callee(xraw: *mut i32) { + // We are a bit sneaky: We first create a shared ref, exploiting the reborrowing rules, + // and then we read through that. + let shr = unsafe { &*xraw }; + let _val = *shr; +} diff --git a/tests/compile-fail/stacked_borrows/illegal_write5.rs b/tests/compile-fail/stacked_borrows/illegal_write5.rs new file mode 100644 index 000000000000..4b5d08c03a47 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_write5.rs @@ -0,0 +1,15 @@ +// A callee may not write to the destination of our `&mut` without +// us noticing. + +fn main() { + let mut x = 15; + let xraw = &mut x as *mut _; + let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... + callee(xraw); + let _val = *xref; // ...but any use of raw will invalidate our ref. + //~^ ERROR: Mut reference with non-reactivatable tag +} + +fn callee(xraw: *mut i32) { + unsafe { *xraw = 15 }; +} diff --git a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs index 785a15c4704a..b4b180e350f1 100644 --- a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs @@ -4,6 +4,6 @@ fn main() { let xraw = x as *mut _; let xref = unsafe { &*xraw }; let xref_in_mem = Box::new(xref); - let _val = *x; // invalidate xraw + *x = 42; // invalidate xraw let _val = *xref_in_mem; //~ ERROR Shr reference with non-reactivatable tag: Location should be frozen } diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs b/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs index 8b7a846d849c..477c86f6060d 100644 --- a/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs @@ -5,6 +5,6 @@ fn main() { let x = &mut 42; let xraw = &*x as *const _; let xref = unsafe { &*xraw }; - let _val = *x; // invalidate xraw + *x = 42; // invalidate xraw foo(xref); //~ ERROR Shr reference with non-reactivatable tag: Location should be frozen } diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr.rs b/tests/compile-fail/stacked_borrows/return_invalid_shr.rs index 89c94127b0b7..954b5ec8e592 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_shr.rs @@ -2,7 +2,7 @@ fn foo(x: &mut (i32, i32)) -> &i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &(*xraw).1 }; - let _val = *x; // invalidate xraw and its children + x.1 = 42; // invalidate xraw on the 2nd field ret //~ ERROR Shr reference with non-reactivatable tag: Location should be frozen } From 430e047a6f2364f9c6d7d950816eef09f3db0428 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 29 Oct 2018 21:04:56 +0100 Subject: [PATCH 0324/5092] start collecting some things ALLOWED by stacked borrows in a run-pass test --- .../run-pass/deref_partially_dangling_raw.rs | 9 ------- tests/run-pass/stacked-borrows.rs | 27 +++++++++++++++++++ 2 files changed, 27 insertions(+), 9 deletions(-) delete mode 100644 tests/run-pass/deref_partially_dangling_raw.rs create mode 100644 tests/run-pass/stacked-borrows.rs diff --git a/tests/run-pass/deref_partially_dangling_raw.rs b/tests/run-pass/deref_partially_dangling_raw.rs deleted file mode 100644 index 8639a289363b..000000000000 --- a/tests/run-pass/deref_partially_dangling_raw.rs +++ /dev/null @@ -1,9 +0,0 @@ -// Deref a raw ptr to access a field of a large struct, where the field -// is allocated but not the entire struct is. -// For now, we want to allow this. - -fn main() { - let x = (1, 1); - let xptr = &x as *const _ as *const (i32, i32, i32); - let _val = unsafe { (*xptr).1 }; -} diff --git a/tests/run-pass/stacked-borrows.rs b/tests/run-pass/stacked-borrows.rs new file mode 100644 index 000000000000..cde6968a2641 --- /dev/null +++ b/tests/run-pass/stacked-borrows.rs @@ -0,0 +1,27 @@ +// Test various stacked-borrows-related things. +fn main() { + deref_partially_dangling_raw(); + read_does_not_invalidate(); +} + +// Deref a raw ptr to access a field of a large struct, where the field +// is allocated but not the entire struct is. +// For now, we want to allow this. +fn deref_partially_dangling_raw() { + let x = (1, 1); + let xptr = &x as *const _ as *const (i32, i32, i32); + let _val = unsafe { (*xptr).1 }; +} + +// Make sure that reading from an `&mut` does, like reborrowing to `&`, +// NOT invalidate other reborrows. +fn read_does_not_invalidate() { + fn foo(x: &mut (i32, i32)) -> &i32 { + let xraw = x as *mut (i32, i32); + let ret = unsafe { &(*xraw).1 }; + let _val = x.1; // we just read, this does NOT invalidate the reborrows. + ret + } + + foo(&mut (1, 2)); +} From 3302656247438d89936bbbfd55fe696c82fa98e4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Oct 2018 13:56:19 +0100 Subject: [PATCH 0325/5092] More extensive slice and vec tests Not all of them pass validation... --- tests/run-pass/slice-of-zero-size-elements.rs | 56 ------ tests/run-pass/slices.rs | 178 ++++++++++++++++++ tests/run-pass/vecs.rs | 38 ++++ 3 files changed, 216 insertions(+), 56 deletions(-) delete mode 100644 tests/run-pass/slice-of-zero-size-elements.rs create mode 100644 tests/run-pass/slices.rs diff --git a/tests/run-pass/slice-of-zero-size-elements.rs b/tests/run-pass/slice-of-zero-size-elements.rs deleted file mode 100644 index aa9d117d726f..000000000000 --- a/tests/run-pass/slice-of-zero-size-elements.rs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::slice; - -fn foo(v: &[T]) -> Option<&[T]> { - let mut it = v.iter(); - for _ in 0..5 { - let _ = it.next(); - } - Some(it.as_slice()) -} - -fn foo_mut(v: &mut [T]) -> Option<&mut [T]> { - let mut it = v.iter_mut(); - for _ in 0..5 { - let _ = it.next(); - } - Some(it.into_slice()) -} - -pub fn main() { - // In a slice of zero-size elements the pointer is meaningless. - // Ensure iteration still works even if the pointer is at the end of the address space. - let slice: &[()] = unsafe { slice::from_raw_parts(-5isize as *const (), 10) }; - assert_eq!(slice.len(), 10); - assert_eq!(slice.iter().count(), 10); - - // .nth() on the iterator should also behave correctly - let mut it = slice.iter(); - assert!(it.nth(5).is_some()); - assert_eq!(it.count(), 4); - - // Converting Iter to a slice should never have a null pointer - assert!(foo(slice).is_some()); - - // Test mutable iterators as well - let slice: &mut [()] = unsafe { slice::from_raw_parts_mut(-5isize as *mut (), 10) }; - assert_eq!(slice.len(), 10); - assert_eq!(slice.iter_mut().count(), 10); - - { - let mut it = slice.iter_mut(); - assert!(it.nth(5).is_some()); - assert_eq!(it.count(), 4); - } - - assert!(foo_mut(slice).is_some()) -} diff --git a/tests/run-pass/slices.rs b/tests/run-pass/slices.rs new file mode 100644 index 000000000000..119c9b90a05c --- /dev/null +++ b/tests/run-pass/slices.rs @@ -0,0 +1,178 @@ +// FIXME: Still investigating whether there is UB here +// compile-flags: -Zmiri-disable-validation + +use std::slice; + +fn slice_of_zst() { + fn foo(v: &[T]) -> Option<&[T]> { + let mut it = v.iter(); + for _ in 0..5 { + let _ = it.next(); + } + Some(it.as_slice()) + } + + fn foo_mut(v: &mut [T]) -> Option<&mut [T]> { + let mut it = v.iter_mut(); + for _ in 0..5 { + let _ = it.next(); + } + Some(it.into_slice()) + } + + // In a slice of zero-size elements the pointer is meaningless. + // Ensure iteration still works even if the pointer is at the end of the address space. + let slice: &[()] = unsafe { slice::from_raw_parts(-5isize as *const (), 10) }; + assert_eq!(slice.len(), 10); + assert_eq!(slice.iter().count(), 10); + + // .nth() on the iterator should also behave correctly + let mut it = slice.iter(); + assert!(it.nth(5).is_some()); + assert_eq!(it.count(), 4); + + // Converting Iter to a slice should never have a null pointer + assert!(foo(slice).is_some()); + + // Test mutable iterators as well + let slice: &mut [()] = unsafe { slice::from_raw_parts_mut(-5isize as *mut (), 10) }; + assert_eq!(slice.len(), 10); + assert_eq!(slice.iter_mut().count(), 10); + + { + let mut it = slice.iter_mut(); + assert!(it.nth(5).is_some()); + assert_eq!(it.count(), 4); + } + + assert!(foo_mut(slice).is_some()) +} + +fn test_iter_ref_consistency() { + use std::fmt::Debug; + + fn test(x : T) { + let v : &[T] = &[x, x, x]; + let v_ptrs : [*const T; 3] = match v { + [ref v1, ref v2, ref v3] => [v1 as *const _, v2 as *const _, v3 as *const _], + _ => unreachable!() + }; + let len = v.len(); + + // nth(i) + for i in 0..len { + assert_eq!(&v[i] as *const _, v_ptrs[i]); // check the v_ptrs array, just to be sure + let nth = v.iter().nth(i).unwrap(); + assert_eq!(nth as *const _, v_ptrs[i]); + } + assert_eq!(v.iter().nth(len), None, "nth(len) should return None"); + + // stepping through with nth(0) + { + let mut it = v.iter(); + for i in 0..len { + let next = it.nth(0).unwrap(); + assert_eq!(next as *const _, v_ptrs[i]); + } + assert_eq!(it.nth(0), None); + } + + // next() + { + let mut it = v.iter(); + for i in 0..len { + let remaining = len - i; + assert_eq!(it.size_hint(), (remaining, Some(remaining))); + + let next = it.next().unwrap(); + assert_eq!(next as *const _, v_ptrs[i]); + } + assert_eq!(it.size_hint(), (0, Some(0))); + assert_eq!(it.next(), None, "The final call to next() should return None"); + } + + // next_back() + { + let mut it = v.iter(); + for i in 0..len { + let remaining = len - i; + assert_eq!(it.size_hint(), (remaining, Some(remaining))); + + let prev = it.next_back().unwrap(); + assert_eq!(prev as *const _, v_ptrs[remaining-1]); + } + assert_eq!(it.size_hint(), (0, Some(0))); + assert_eq!(it.next_back(), None, "The final call to next_back() should return None"); + } + } + + fn test_mut(x : T) { + let v : &mut [T] = &mut [x, x, x]; + let v_ptrs : [*mut T; 3] = match v { + [ref v1, ref v2, ref v3] => + [v1 as *const _ as *mut _, v2 as *const _ as *mut _, v3 as *const _ as *mut _], + _ => unreachable!() + }; + let len = v.len(); + + // nth(i) + for i in 0..len { + assert_eq!(&mut v[i] as *mut _, v_ptrs[i]); // check the v_ptrs array, just to be sure + let nth = v.iter_mut().nth(i).unwrap(); + assert_eq!(nth as *mut _, v_ptrs[i]); + } + assert_eq!(v.iter().nth(len), None, "nth(len) should return None"); + + // stepping through with nth(0) + { + let mut it = v.iter(); + for i in 0..len { + let next = it.nth(0).unwrap(); + assert_eq!(next as *const _, v_ptrs[i]); + } + assert_eq!(it.nth(0), None); + } + + // next() + { + let mut it = v.iter_mut(); + for i in 0..len { + let remaining = len - i; + assert_eq!(it.size_hint(), (remaining, Some(remaining))); + + let next = it.next().unwrap(); + assert_eq!(next as *mut _, v_ptrs[i]); + } + assert_eq!(it.size_hint(), (0, Some(0))); + assert_eq!(it.next(), None, "The final call to next() should return None"); + } + + // next_back() + { + let mut it = v.iter_mut(); + for i in 0..len { + let remaining = len - i; + assert_eq!(it.size_hint(), (remaining, Some(remaining))); + + let prev = it.next_back().unwrap(); + assert_eq!(prev as *mut _, v_ptrs[remaining-1]); + } + assert_eq!(it.size_hint(), (0, Some(0))); + assert_eq!(it.next_back(), None, "The final call to next_back() should return None"); + } + } + + // Make sure iterators and slice patterns yield consistent addresses for various types, + // including ZSTs. + test(0u32); + test(()); + test([0u32; 0]); // ZST with alignment > 0 + test_mut(0u32); + test_mut(()); + test_mut([0u32; 0]); // ZST with alignment > 0 +} + +fn main() { + slice_of_zst(); + test_iter_ref_consistency(); +} diff --git a/tests/run-pass/vecs.rs b/tests/run-pass/vecs.rs index 776791bbc9b9..bb9e5068f91e 100644 --- a/tests/run-pass/vecs.rs +++ b/tests/run-pass/vecs.rs @@ -24,13 +24,45 @@ fn vec_into_iter() -> u8 { .fold(0, |x, y| x + y) } +fn vec_into_iter_rev() -> u8 { + vec![1, 2, 3, 4] + .into_iter() + .map(|x| x * x) + .fold(0, |x, y| x + y) +} + fn vec_into_iter_zst() -> usize { vec![[0u64; 0], [0u64; 0]] .into_iter() + .rev() .map(|x| x.len()) .sum() } +fn vec_into_iter_rev_zst() -> usize { + vec![[0u64; 0], [0u64; 0]] + .into_iter() + .rev() + .map(|x| x.len()) + .sum() +} + +fn vec_iter_and_mut() { + let mut v = vec![1,2,3,4]; + for i in v.iter_mut() { + *i += 1; + } + assert_eq!(v.iter().sum::(), 2+3+4+5); +} + +fn vec_iter_and_mut_rev() { + let mut v = vec![1,2,3,4]; + for i in v.iter_mut().rev() { + *i += 1; + } + assert_eq!(v.iter().sum::(), 2+3+4+5); +} + fn vec_reallocate() -> Vec { let mut v = vec![1, 2]; v.push(3); @@ -41,8 +73,14 @@ fn vec_reallocate() -> Vec { fn main() { assert_eq!(vec_reallocate().len(), 5); + assert_eq!(vec_into_iter(), 30); + assert_eq!(vec_into_iter_rev(), 30); + vec_iter_and_mut(); assert_eq!(vec_into_iter_zst(), 0); + assert_eq!(vec_into_iter_rev_zst(), 0); + vec_iter_and_mut_rev(); + assert_eq!(make_vec().capacity(), 4); assert_eq!(make_vec_macro(), [1, 2]); assert_eq!(make_vec_macro_repeat(), [42; 5]); From 478f137c39b827e6de39056b5c27a8e5d797aa4d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Oct 2018 15:08:18 +0100 Subject: [PATCH 0326/5092] put all the logic into reactivatable() --- src/stacked_borrows.rs | 140 +++++++++++++++++++---------------------- 1 file changed, 63 insertions(+), 77 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index baeb04b44ea7..dcb284b1bc3f 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -142,74 +142,76 @@ pub struct Stacks { /// Core operations impl<'tcx> Stack { - /// Check if `bor` is currently active. We accept a `Raw` on a frozen location - /// because this could be a shared (re)borrow. If you want to mutate, this - /// is not the right function to call! - fn check(&self, bor: Borrow) -> bool { - match bor { - Borrow::Frz(acc_t) => - // Must be frozen at least as long as the `acc_t` says. - self.frozen_since.map_or(false, |loc_t| loc_t <= acc_t), - Borrow::Mut(acc_m) => - // Raw pointers are fine with frozen locations. This is important because &Cell is raw! - if self.frozen_since.is_some() { - acc_m.is_raw() - } else { - self.borrows.last().map_or(false, |&loc_itm| loc_itm == BorStackItem::Mut(acc_m)) - } - } - } - /// Check if `bor` could be activated by unfreezing and popping. - /// `force_mut` indicates whether being frozen is potentially acceptable. + /// `ref_kind` indicates whether this is being used to read/write (or, equivalently, to + /// borrow as &/&mut), or to borrow as raw. /// Returns `Err` if the answer is "no"; otherwise the data says /// what needs to happen to activate this: `None` = nothing, /// `Some(n)` = unfreeze and make item `n` the top item of the stack. - fn reactivatable(&self, bor: Borrow, force_mut: bool) -> Result, String> { - // Unless mutation is bound to happen, do NOT change anything if `bor` is already active. - // In particular, if it is a `Mut(Raw)` and we are frozen, this should be a NOP. - if !force_mut && self.check(bor) { - return Ok(None); - } - - let acc_m = match bor { + fn reactivatable(&self, bor: Borrow, ref_kind: RefKind) -> Result, String> { + let mut_borrow = match bor { Borrow::Frz(since) => - return Err(if force_mut { - format!("Using a shared borrow for mutation") - } else { - format!( - "Location should be frozen since {} but {}", - since, - match self.frozen_since { - None => format!("it is not frozen at all"), - Some(since) => format!("it is only frozen since {}", since), - } - ) - }), - Borrow::Mut(acc_m) => acc_m + // The only way to reactivate a `Frz` is if this is already frozen. + return match self.frozen_since { + _ if ref_kind == RefKind::Mut => + Err(format!("Using a shared borrow for mutation")), + None => + Err(format!("Location should be frozen but it is not")), + Some(loc) if loc <= since => + Ok(None), + Some(loc) => + Err(format!("Location should be frozen since {} but it is only frozen \ + since {}", since, loc)), + }, + Borrow::Mut(Mut::Raw) if self.is_frozen() && ref_kind != RefKind::Mut => + // Non-mutating access with a raw from a frozen location is a special case: The + // shared refs do not mind raw reads, and the raw itself does not assume any + // exclusivity. So we do not even require there to be a raw on the stack. + // This does not break the assumption that an `&mut` we own is + // exclusive for reads, because there we have the invariant that + // the location is *not* frozen. + return Ok(None), + Borrow::Mut(mut_borrow) => mut_borrow }; - // This is where we would unfreeze. + // See if we can get there via popping. for (idx, &itm) in self.borrows.iter().enumerate().rev() { match itm { BorStackItem::FnBarrier(_) => - return Err(format!("Trying to reactivate a mutable borrow ({:?}) that lives behind a barrier", acc_m)), - BorStackItem::Mut(loc_m) => { - if loc_m == acc_m { return Ok(Some(idx)); } + return Err(format!("Trying to reactivate a mutable borrow ({:?}) that lives \ + behind a barrier", mut_borrow)), + BorStackItem::Mut(loc) => { + if loc == mut_borrow { + // We found it! This is good to know. + // Yet, maybe we do not really want to pop? + if ref_kind == RefKind::Shr && self.is_frozen() { + // Whoever had exclusive access to this location allowed it + // to become frozen. That can only happen if they reborrowed + // to a shared ref, at which point they gave up on exclusive access. + // Hence we allow more reads, entirely ignoring everything above + // on the stack (but still making sure it is on the stack). + // This does not break the assumption that an `&mut` we own is + // exclusive for reads, because there we have the invariant that + // the location is *not* frozen. + return Ok(None); + } else { + return Ok(Some(idx)); + } + } } } } // Nothing to be found. - Err(format!("Mutable borrow-to-reactivate ({:?}) does not exist on the stack", acc_m)) + Err(format!("Mutable borrow-to-reactivate ({:?}) does not exist on the stack", mut_borrow)) } - /// Reactive `bor` for this stack. If `force_mut` is set, we want to aggressively - /// unfreeze this location (because we are about to mutate, so a frozen `Raw` is not okay). - fn reactivate(&mut self, bor: Borrow, force_mut: bool) -> EvalResult<'tcx> { - let action = match self.reactivatable(bor, force_mut) { + /// Reactive `bor` for this stack. `ref_kind` indicates whether this is being + /// used to read/write (or, equivalently, to borrow as &/&mut), or to borrow as raw. + fn reactivate(&mut self, bor: Borrow, ref_kind: RefKind) -> EvalResult<'tcx> { + let action = match self.reactivatable(bor, ref_kind) { Ok(action) => action, Err(err) => return err!(MachineError(err)), }; - + // Execute what `reactivatable` told us to do. match action { None => {}, // nothing to do Some(top) => { @@ -285,27 +287,7 @@ impl<'tcx> Stacks { ptr.tag, ref_kind, new_bor, ptr, size.bytes()); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { - if ref_kind == RefKind::Shr && stack.is_frozen() { - // Location already frozen. We don't want to unfreeze, but make sure - // the ref makes some sense. - if let Err(err) = stack.reactivatable(ptr.tag, /*force_mut*/false) { - return err!(MachineError(err)); - } - } else { - // If we are creating a mutable ref, we certainly want to unfreeze. - // Even if we are doing so from a raw. - // Notice that if this is a local, whenever we access it directly the - // tag here will be the bottommost `Uniq` for that local. That `Uniq` - // never is accessible by the program, so it will not be used by any - // other access. IOW, whenever we directly use a local this will pop - // everything else off the stack, invalidating all previous pointers - // and, in particular, *all* raw pointers. This subsumes the explicit - // `reset` which the blog post [1] says to perform when accessing a local. - // - // [1] https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html - let force_mut = ref_kind == RefKind::Mut; - stack.reactivate(ptr.tag, force_mut)?; - } + stack.reactivate(ptr.tag, ref_kind)?; if let Some(new_bor) = new_bor { stack.initiate(new_bor); } @@ -484,11 +466,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let mut stacks = alloc.extra.stacks.borrow_mut(); // We need `iter_mut` because `iter` would skip gaps! for stack in stacks.iter_mut(ptr.offset, size) { - // We accept &mut to a frozen location here, that is just normal. There might - // be shared reborrows that we are about to invalidate with this access. - // We cannot invalidate them aggressively here because the deref might also be - // to just create more shared refs. - if let Err(err) = stack.reactivatable(ptr.tag, /*force_mut*/false) { + // Conservatively assume that we will only read. + if let Err(err) = stack.reactivatable(ptr.tag, RefKind::Shr) { return err!(MachineError(format!("Encountered {:?} reference with non-reactivatable tag: {}", ref_kind, err))) } } @@ -503,7 +482,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' ) -> Borrow { let mut_borrow = match kind { MemoryKind::Stack => { - // New unique borrow + // New unique borrow. This `Uniq` is not accessible by the program, + // so it will only ever be used when using the local directly (i.e., + // not through a pointer). IOW, whenever we directly use a local this will pop + // everything else off the stack, invalidating all previous pointers + // and, in particular, *all* raw pointers. This subsumes the explicit + // `reset` which the blog post [1] says to perform when accessing a local. + // + // [1] https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html let time = self.machine.stacked_borrows.increment_clock(); Mut::Uniq(time) } From 81534496dc3356d5794300d513be200f939350c7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Oct 2018 16:46:28 +0100 Subject: [PATCH 0327/5092] rename RefKind to UsageKind, because it not only used for references now --- src/lib.rs | 2 +- src/stacked_borrows.rs | 118 ++++++++++-------- .../stacked_borrows/alias_through_mutation.rs | 2 +- .../stacked_borrows/buggy_as_mut_slice.rs | 2 +- .../stacked_borrows/buggy_split_at_mut.rs | 2 +- .../stacked_borrows/illegal_read1.rs | 2 +- .../stacked_borrows/illegal_read2.rs | 2 +- .../stacked_borrows/illegal_write1.rs | 2 +- .../stacked_borrows/illegal_write5.rs | 2 +- .../stacked_borrows/load_invalid_mut.rs | 2 +- .../stacked_borrows/load_invalid_shr.rs | 2 +- .../stacked_borrows/pass_invalid_mut.rs | 2 +- .../stacked_borrows/pass_invalid_shr.rs | 2 +- .../stacked_borrows/return_invalid_mut.rs | 2 +- .../stacked_borrows/return_invalid_shr.rs | 2 +- .../stacked_borrows/shared_confusion.rs | 2 +- .../stacked_borrows/shared_confusion_opt.rs | 2 +- 17 files changed, 84 insertions(+), 66 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b397e9a6d224..5a3e1c7cab05 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,7 +48,7 @@ use mono_hash_map::MonoHashMap; use stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; // Used by priroda -pub use stacked_borrows::{Borrow, Stacks, Mut as MutBorrow}; +pub use stacked_borrows::{Borrow, Stack, Stacks, Mut as MutBorrow, BorStackItem}; /// Insert rustc arguments at the beginning of the argument listthat miri wants to be /// set per default, for maximal validation power. diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index dcb284b1bc3f..d520c6ff5d47 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -64,6 +64,12 @@ impl Borrow { } } +impl Default for Borrow { + fn default() -> Self { + Borrow::Mut(Mut::Raw) + } +} + /// An item in the borrow stack #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum BorStackItem { @@ -74,26 +80,33 @@ pub enum BorStackItem { FnBarrier(usize) } -impl Default for Borrow { - fn default() -> Self { - Borrow::Mut(Mut::Raw) +impl BorStackItem { + #[inline(always)] + pub fn is_fn_barrier(self) -> bool { + match self { + BorStackItem::FnBarrier(_) => true, + _ => false, + } } } -/// What kind of reference are we talking about? +/// What kind of usage of the pointer are we talking about? #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -pub enum RefKind { - Mut, - Shr, +pub enum UsageKind { + /// Write, or create &mut + Write, + /// Read, or create & + Read, + /// Create * Raw, } -impl From> for RefKind { +impl From> for UsageKind { fn from(mutbl: Option) -> Self { match mutbl { - None => RefKind::Raw, - Some(hir::MutMutable) => RefKind::Mut, - Some(hir::MutImmutable) => RefKind::Shr, + None => UsageKind::Raw, + Some(hir::MutMutable) => UsageKind::Write, + Some(hir::MutImmutable) => UsageKind::Read, } } } @@ -112,7 +125,7 @@ impl State { /// Extra per-location state #[derive(Clone, Debug)] -struct Stack { +pub struct Stack { borrows: Vec, // used as a stack frozen_since: Option, } @@ -143,17 +156,17 @@ pub struct Stacks { /// Core operations impl<'tcx> Stack { /// Check if `bor` could be activated by unfreezing and popping. - /// `ref_kind` indicates whether this is being used to read/write (or, equivalently, to + /// `usage` indicates whether this is being used to read/write (or, equivalently, to /// borrow as &/&mut), or to borrow as raw. /// Returns `Err` if the answer is "no"; otherwise the data says /// what needs to happen to activate this: `None` = nothing, /// `Some(n)` = unfreeze and make item `n` the top item of the stack. - fn reactivatable(&self, bor: Borrow, ref_kind: RefKind) -> Result, String> { + fn reactivatable(&self, bor: Borrow, usage: UsageKind) -> Result, String> { let mut_borrow = match bor { Borrow::Frz(since) => // The only way to reactivate a `Frz` is if this is already frozen. return match self.frozen_since { - _ if ref_kind == RefKind::Mut => + _ if usage == UsageKind::Write => Err(format!("Using a shared borrow for mutation")), None => Err(format!("Location should be frozen but it is not")), @@ -163,10 +176,11 @@ impl<'tcx> Stack { Err(format!("Location should be frozen since {} but it is only frozen \ since {}", since, loc)), }, - Borrow::Mut(Mut::Raw) if self.is_frozen() && ref_kind != RefKind::Mut => + Borrow::Mut(Mut::Raw) if self.is_frozen() && usage != UsageKind::Write => // Non-mutating access with a raw from a frozen location is a special case: The // shared refs do not mind raw reads, and the raw itself does not assume any - // exclusivity. So we do not even require there to be a raw on the stack. + // exclusivity. So we do not even require there to be a raw on the stack, + // the raw is instead "matched" by the fact that this location is frozen. // This does not break the assumption that an `&mut` we own is // exclusive for reads, because there we have the invariant that // the location is *not* frozen. @@ -183,7 +197,7 @@ impl<'tcx> Stack { if loc == mut_borrow { // We found it! This is good to know. // Yet, maybe we do not really want to pop? - if ref_kind == RefKind::Shr && self.is_frozen() { + if usage == UsageKind::Read && self.is_frozen() { // Whoever had exclusive access to this location allowed it // to become frozen. That can only happen if they reborrowed // to a shared ref, at which point they gave up on exclusive access. @@ -204,10 +218,10 @@ impl<'tcx> Stack { Err(format!("Mutable borrow-to-reactivate ({:?}) does not exist on the stack", mut_borrow)) } - /// Reactive `bor` for this stack. `ref_kind` indicates whether this is being + /// Reactive `bor` for this stack. `usage` indicates whether this is being /// used to read/write (or, equivalently, to borrow as &/&mut), or to borrow as raw. - fn reactivate(&mut self, bor: Borrow, ref_kind: RefKind) -> EvalResult<'tcx> { - let action = match self.reactivatable(bor, ref_kind) { + fn reactivate(&mut self, bor: Borrow, usage: UsageKind) -> EvalResult<'tcx> { + let action = match self.reactivatable(bor, usage) { Ok(action) => action, Err(err) => return err!(MachineError(err)), }; @@ -274,20 +288,20 @@ impl State { /// Higher-level operations impl<'tcx> Stacks { - /// The single most operation: Make sure that using `ptr` as `ref_kind` is okay, + /// The single most operation: Make sure that using `ptr` as `usage` is okay, /// and if `new_bor` is present then make that the new current borrow. fn use_and_maybe_re_borrow( &self, ptr: Pointer, size: Size, - ref_kind: RefKind, + usage: UsageKind, new_bor: Option, ) -> EvalResult<'tcx> { trace!("use_and_maybe_re_borrow of tag {:?} as {:?}, new {:?}: {:?}, size {}", - ptr.tag, ref_kind, new_bor, ptr, size.bytes()); + ptr.tag, usage, new_bor, ptr, size.bytes()); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { - stack.reactivate(ptr.tag, ref_kind)?; + stack.reactivate(ptr.tag, usage)?; if let Some(new_bor) = new_bor { stack.initiate(new_bor); } @@ -303,7 +317,7 @@ impl<'tcx> Stacks { size: Size, ) -> EvalResult<'tcx> { // Reads behave exactly like the first half of a reborrow-to-shr - self.use_and_maybe_re_borrow(ptr, size, RefKind::Shr, None) + self.use_and_maybe_re_borrow(ptr, size, UsageKind::Read, None) } #[inline(always)] @@ -313,7 +327,7 @@ impl<'tcx> Stacks { size: Size, ) -> EvalResult<'tcx> { // Writes behave exactly like the first half of a reborrow-to-mut - self.use_and_maybe_re_borrow(ptr, size, RefKind::Mut, None) + self.use_and_maybe_re_borrow(ptr, size, UsageKind::Write, None) } pub fn memory_deallocated( @@ -322,7 +336,7 @@ impl<'tcx> Stacks { size: Size, ) -> EvalResult<'tcx> { // This is like mutating - self.use_and_maybe_re_borrow(ptr, size, RefKind::Mut, None) + self.use_and_maybe_re_borrow(ptr, size, UsageKind::Write, None) // FIXME: Error out of there are any barriers? } @@ -346,7 +360,7 @@ pub trait EvalContextExt<'tcx> { ptr: Pointer, pointee_ty: Ty<'tcx>, size: Size, - ref_kind: RefKind, + usage: UsageKind, ) -> EvalResult<'tcx, Borrow>; @@ -355,7 +369,7 @@ pub trait EvalContextExt<'tcx> { ptr: Pointer, pointee_ty: Ty<'tcx>, size: Size, - ref_kind: RefKind, + usage: UsageKind, ) -> EvalResult<'tcx, Borrow>; fn tag_new_allocation( @@ -378,12 +392,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' ptr: Pointer, pointee_ty: Ty<'tcx>, size: Size, - ref_kind: RefKind, + usage: UsageKind, ) -> EvalResult<'tcx, Borrow> { let time = self.machine.stacked_borrows.increment_clock(); - let new_bor = match ref_kind { - RefKind::Mut => Borrow::Mut(Mut::Uniq(time)), - RefKind::Shr => + let new_bor = match usage { + UsageKind::Write => Borrow::Mut(Mut::Uniq(time)), + UsageKind::Read => // FIXME This does not do enough checking when only part of the data has // interior mutability. When the type is `(i32, Cell)`, we want the // first field to be frozen but not the second. @@ -393,10 +407,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Shared reference with interior mutability. Borrow::Mut(Mut::Raw) }, - RefKind::Raw => Borrow::Mut(Mut::Raw), + UsageKind::Raw => Borrow::Mut(Mut::Raw), }; trace!("tag_reference: Creating new reference ({:?}) for {:?} (pointee {}, size {}): {:?}", - ref_kind, ptr, pointee_ty, size.bytes(), new_bor); + usage, ptr, pointee_ty, size.bytes(), new_bor); // Make sure this reference is not dangling or so self.memory().check_bounds(ptr, size, false)?; @@ -404,7 +418,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Update the stacks. We cannot use `get_mut` becuse this might be immutable // memory. let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); - alloc.extra.use_and_maybe_re_borrow(ptr, size, ref_kind, Some(new_bor))?; + alloc.extra.use_and_maybe_re_borrow(ptr, size, usage, Some(new_bor))?; Ok(new_bor) } @@ -418,39 +432,39 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' ptr: Pointer, pointee_ty: Ty<'tcx>, size: Size, - ref_kind: RefKind, + usage: UsageKind, ) -> EvalResult<'tcx, Borrow> { trace!("tag_reference: Accessing reference ({:?}) for {:?} (pointee {}, size {})", - ref_kind, ptr, pointee_ty, size.bytes()); + usage, ptr, pointee_ty, size.bytes()); // In principle we should not have to do anything here. However, with transmutes involved, - // it can happen that the tag of `ptr` does not actually match `ref_kind`, and we + // it can happen that the tag of `ptr` does not actually match `usage`, and we // should adjust for that. // Notably, the compiler can introduce such transmutes by optimizing away `&[mut]*`. // That can transmute a raw ptr to a (shared/mut) ref, and a mut ref to a shared one. - match (ref_kind, ptr.tag) { - (RefKind::Raw, _) => { + match (usage, ptr.tag) { + (UsageKind::Raw, _) => { // Don't use the tag, this is a raw access! Even if there is a tag, // that means transmute happened and we ignore the tag. // Also don't do any further validation, this is raw after all. return Ok(Borrow::Mut(Mut::Raw)); } - (RefKind::Mut, Borrow::Mut(Mut::Uniq(_))) | - (RefKind::Shr, Borrow::Frz(_)) | - (RefKind::Shr, Borrow::Mut(Mut::Raw)) => { + (UsageKind::Write, Borrow::Mut(Mut::Uniq(_))) | + (UsageKind::Read, Borrow::Frz(_)) | + (UsageKind::Read, Borrow::Mut(Mut::Raw)) => { // Expected combinations. Nothing to do. // FIXME: We probably shouldn't accept this if we got a raw shr without // interior mutability. } - (RefKind::Mut, Borrow::Mut(Mut::Raw)) => { + (UsageKind::Write, Borrow::Mut(Mut::Raw)) => { // Raw transmuted to mut ref. Keep this as raw access. // We cannot reborrow here; there might be a raw in `&(*var).1` where // `var` is an `&mut`. The other field of the struct might be already frozen, // also using `var`, and that would be okay. } - (RefKind::Shr, Borrow::Mut(Mut::Uniq(_))) => { + (UsageKind::Read, Borrow::Mut(Mut::Uniq(_))) => { // A mut got transmuted to shr. The mut borrow must be reactivatable. } - (RefKind::Mut, Borrow::Frz(_)) => { + (UsageKind::Write, Borrow::Frz(_)) => { // This is just invalid. // If we ever allow this, we have to consider what we do when a turn a // `Raw`-tagged `&mut` into a raw pointer pointing to a frozen location. @@ -467,8 +481,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // We need `iter_mut` because `iter` would skip gaps! for stack in stacks.iter_mut(ptr.offset, size) { // Conservatively assume that we will only read. - if let Err(err) = stack.reactivatable(ptr.tag, RefKind::Shr) { - return err!(MachineError(format!("Encountered {:?} reference with non-reactivatable tag: {}", ref_kind, err))) + if let Err(err) = stack.reactivatable(ptr.tag, UsageKind::Read) { + return err!(MachineError(format!( + "Encountered {} reference with non-reactivatable tag: {}", + if usage == UsageKind::Write { "mutable" } else { "shared" }, + err + ))) } } // All is good. diff --git a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs index eb8966f3a5c7..0b2d459366ce 100644 --- a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs +++ b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs @@ -11,5 +11,5 @@ fn main() { retarget(&mut target_alias, target); // now `target_alias` points to the same thing as `target` *target = 13; - let _val = *target_alias; //~ ERROR Shr reference with non-reactivatable tag + let _val = *target_alias; //~ ERROR reference with non-reactivatable tag } diff --git a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs index e86eb9ba6de8..2c48404ddf36 100644 --- a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs +++ b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs @@ -14,6 +14,6 @@ fn main() { let v = vec![0,1,2]; let v1 = safe::as_mut_slice(&v); let v2 = safe::as_mut_slice(&v); - v1[1] = 5; //~ ERROR Mut reference with non-reactivatable tag + v1[1] = 5; //~ ERROR reference with non-reactivatable tag v1[1] = 6; } diff --git a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs index a4f5f536b770..d8a241cab5d4 100644 --- a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs @@ -11,7 +11,7 @@ mod safe { assert!(mid <= len); (from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" - //~^ ERROR Mut reference with non-reactivatable tag + //~^ ERROR reference with non-reactivatable tag from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) } } diff --git a/tests/compile-fail/stacked_borrows/illegal_read1.rs b/tests/compile-fail/stacked_borrows/illegal_read1.rs index f0e696c457cb..59190a15db44 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read1.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read1.rs @@ -7,7 +7,7 @@ fn main() { let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. - //~^ ERROR: Mut reference with non-reactivatable tag + //~^ ERROR: mutable reference with non-reactivatable tag } fn callee(xraw: *mut i32) { diff --git a/tests/compile-fail/stacked_borrows/illegal_read2.rs b/tests/compile-fail/stacked_borrows/illegal_read2.rs index ec59c57d31b7..594117d28ab8 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read2.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read2.rs @@ -7,7 +7,7 @@ fn main() { let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. - //~^ ERROR: Mut reference with non-reactivatable tag + //~^ ERROR: mutable reference with non-reactivatable tag } fn callee(xraw: *mut i32) { diff --git a/tests/compile-fail/stacked_borrows/illegal_write1.rs b/tests/compile-fail/stacked_borrows/illegal_write1.rs index 131e89572a50..ab951be5ec91 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write1.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write1.rs @@ -8,5 +8,5 @@ fn main() { let target = Box::new(42); // has an implicit raw let ref_ = &*target; evil(ref_); // invalidates shared ref, activates raw - let _x = *ref_; //~ ERROR Shr reference with non-reactivatable tag + let _x = *ref_; //~ ERROR reference with non-reactivatable tag } diff --git a/tests/compile-fail/stacked_borrows/illegal_write5.rs b/tests/compile-fail/stacked_borrows/illegal_write5.rs index 4b5d08c03a47..f4704ad57161 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write5.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write5.rs @@ -7,7 +7,7 @@ fn main() { let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. - //~^ ERROR: Mut reference with non-reactivatable tag + //~^ ERROR: reference with non-reactivatable tag } fn callee(xraw: *mut i32) { diff --git a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs index 060cec962c47..4ea61cd606ff 100644 --- a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs @@ -5,5 +5,5 @@ fn main() { let xref = unsafe { &mut *xraw }; let xref_in_mem = Box::new(xref); let _val = *x; // invalidate xraw - let _val = *xref_in_mem; //~ ERROR Mut reference with non-reactivatable tag + let _val = *xref_in_mem; //~ ERROR mutable reference with non-reactivatable tag } diff --git a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs index b4b180e350f1..53179c954dea 100644 --- a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs @@ -5,5 +5,5 @@ fn main() { let xref = unsafe { &*xraw }; let xref_in_mem = Box::new(xref); *x = 42; // invalidate xraw - let _val = *xref_in_mem; //~ ERROR Shr reference with non-reactivatable tag: Location should be frozen + let _val = *xref_in_mem; //~ ERROR shared reference with non-reactivatable tag: Location should be frozen } diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs index bc950771add4..5e1118160a32 100644 --- a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs @@ -6,5 +6,5 @@ fn main() { let xraw = x as *mut _; let xref = unsafe { &mut *xraw }; let _val = *x; // invalidate xraw - foo(xref); //~ ERROR Mut reference with non-reactivatable tag + foo(xref); //~ ERROR mutable reference with non-reactivatable tag } diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs b/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs index 477c86f6060d..e4b26cfff6da 100644 --- a/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs @@ -6,5 +6,5 @@ fn main() { let xraw = &*x as *const _; let xref = unsafe { &*xraw }; *x = 42; // invalidate xraw - foo(xref); //~ ERROR Shr reference with non-reactivatable tag: Location should be frozen + foo(xref); //~ ERROR shared reference with non-reactivatable tag: Location should be frozen } diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs index c02892671e90..949b3829ff8f 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> &mut i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &mut (*xraw).1 }; let _val = *x; // invalidate xraw and its children - ret //~ ERROR Mut reference with non-reactivatable tag + ret //~ ERROR mutable reference with non-reactivatable tag } fn main() { diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr.rs b/tests/compile-fail/stacked_borrows/return_invalid_shr.rs index 954b5ec8e592..2d34350359d1 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_shr.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> &i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &(*xraw).1 }; x.1 = 42; // invalidate xraw on the 2nd field - ret //~ ERROR Shr reference with non-reactivatable tag: Location should be frozen + ret //~ ERROR shared reference with non-reactivatable tag: Location should be frozen } fn main() { diff --git a/tests/compile-fail/stacked_borrows/shared_confusion.rs b/tests/compile-fail/stacked_borrows/shared_confusion.rs index c02822ed4d3d..624587932cb8 100644 --- a/tests/compile-fail/stacked_borrows/shared_confusion.rs +++ b/tests/compile-fail/stacked_borrows/shared_confusion.rs @@ -21,7 +21,7 @@ fn test(r: &mut RefCell) { } // Our old raw should be dead by now unsafe { *x_evil = 0; } // this falls back to some Raw higher up the stack - *x_inner = 12; //~ ERROR Mut reference with non-reactivatable tag + *x_inner = 12; //~ ERROR reference with non-reactivatable tag } fn main() { diff --git a/tests/compile-fail/stacked_borrows/shared_confusion_opt.rs b/tests/compile-fail/stacked_borrows/shared_confusion_opt.rs index 4a88d4d64133..3030f5dd4001 100644 --- a/tests/compile-fail/stacked_borrows/shared_confusion_opt.rs +++ b/tests/compile-fail/stacked_borrows/shared_confusion_opt.rs @@ -17,7 +17,7 @@ fn test(r: &mut RefCell) { } // Our old raw should be dead by now unsafe { *x_evil = 0; } // this falls back to some Raw higher up the stack - *x_inner = 12; //~ ERROR Mut reference with non-reactivatable tag + *x_inner = 12; //~ ERROR reference with non-reactivatable tag } fn main() { From a68779fd16a851fbdb0e25297044da7f5a410845 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 1 Nov 2018 08:55:03 +0100 Subject: [PATCH 0328/5092] use crate:: import to make edition port easier later --- src/lib.rs | 2 +- src/stacked_borrows.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 5a3e1c7cab05..82ffb5e454d5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,7 +48,7 @@ use mono_hash_map::MonoHashMap; use stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; // Used by priroda -pub use stacked_borrows::{Borrow, Stack, Stacks, Mut as MutBorrow, BorStackItem}; +pub use crate::stacked_borrows::{Borrow, Stack, Stacks, Mut as MutBorrow, BorStackItem}; /// Insert rustc arguments at the beginning of the argument listthat miri wants to be /// set per default, for maximal validation power. diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index d520c6ff5d47..4d78519be61d 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -3,7 +3,7 @@ use std::cell::RefCell; use rustc::ty::{self, Ty, layout::Size}; use rustc::hir; -use super::{ +use crate::{ MemoryKind, MiriMemoryKind, RangeMap, EvalResult, AllocId, Pointer, PlaceTy, }; From e9f79f5f6f73d933d3cabbda9ae8058d54bb9f9a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Nov 2018 09:11:37 +0100 Subject: [PATCH 0329/5092] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index d025ddacf009..6b277cc26bc9 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-10-30 +nightly-2018-11-03 From 5f42aa61d578c8bb2f41ea6e5baf29565d8ee32a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Nov 2018 10:23:41 +0100 Subject: [PATCH 0330/5092] illegal_write2 does not work with optimizations --- tests/compile-fail/stacked_borrows/illegal_write2.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/compile-fail/stacked_borrows/illegal_write2.rs b/tests/compile-fail/stacked_borrows/illegal_write2.rs index f4fefaad5e22..b53655c82147 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write2.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write2.rs @@ -1,3 +1,7 @@ +// We fail to detect this when neither this nor libstd are optimized/have retagging. +// FIXME: Investigate that. +// compile-flags: -Zmir-opt-level=0 + #![allow(unused_variables)] fn main() { From 8da2c9e34e836e12bfa9912c5df4e62afc21b634 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Nov 2018 11:03:53 +0100 Subject: [PATCH 0331/5092] fix adding default arguments --- src/bin/cargo-miri.rs | 2 +- src/bin/miri-rustc-tests.rs | 3 +-- src/bin/miri.rs | 4 ++-- src/lib.rs | 9 ++------- 4 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 20fb0fa35319..69c4f122544a 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -173,6 +173,7 @@ fn main() { .chain(Some(sys_root)) .collect() }; + args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string)); // this check ensures that dependencies are built but not interpreted and the final crate is // interpreted but not built @@ -186,7 +187,6 @@ fn main() { Command::new("rustc") }; - miri::add_miri_default_args(&mut args); args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-miri""#.to_owned()]); match command.args(&args).status() { diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index d14d7a2e4bd1..6fa9b817ffee 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -156,6 +156,7 @@ fn main() { true } }).collect(); + args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string)); // file to process args.push(path.display().to_string()); @@ -165,8 +166,6 @@ fn main() { args.push(Path::new(&std::env::var("HOME").unwrap()).join(".xargo").join("HOST").display().to_string()); } - miri::add_miri_default_args(&mut args); - // A threadsafe buffer for writing. #[derive(Default, Clone)] struct BufWriter(Arc>>); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 686f685b831c..1bbf3c8c4a4a 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -232,8 +232,8 @@ fn main() { args.push(sysroot_flag); args.push(find_sysroot()); } - // Finally, add the default flags all the way in the beginning. - miri::add_miri_default_args(&mut args); + // Finally, add the default flags all the way in the beginning, but after the binary name. + args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string)); trace!("rustc arguments: {:?}", args); let result = rustc_driver::run(move || { diff --git a/src/lib.rs b/src/lib.rs index 88a2689ba9dc..6445dca1e80a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,16 +52,11 @@ pub use crate::stacked_borrows::{Borrow, Stack, Stacks, Mut as MutBorrow, BorSta /// Insert rustc arguments at the beginning of the argument listthat miri wants to be /// set per default, for maximal validation power. -pub fn add_miri_default_args(args: &mut Vec) { +pub fn miri_default_args() -> &'static [&'static str] { // The flags here should be kept in sync with what bootstrap adds when `test-miri` is // set, which happens in `bootstrap/bin/rustc.rs` in the rustc sources; and also // kept in sync with `xargo/build.sh` in this repo and `appveyor.yml`. - - // Inserting at index 1, after the binary name - args.splice(1..1, - ["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0"] - .iter().map(|s| s.to_string()) - ); + &["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0"] } // Used by priroda From 8ac5d988e237570e24208a05f65bf0b06137d101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20S=CC=B6c=CC=B6h=CC=B6n=CC=B6e=CC=B6i=CC=B6d=CC=B6?= =?UTF-8?q?e=CC=B6r=20Scherer?= Date: Sat, 3 Nov 2018 11:39:50 +0100 Subject: [PATCH 0332/5092] typo Co-Authored-By: RalfJung --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 6445dca1e80a..a2271a5898b7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,7 +50,7 @@ use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; // Used by priroda pub use crate::stacked_borrows::{Borrow, Stack, Stacks, Mut as MutBorrow, BorStackItem}; -/// Insert rustc arguments at the beginning of the argument listthat miri wants to be +/// Insert rustc arguments at the beginning of the argument list that miri wants to be /// set per default, for maximal validation power. pub fn miri_default_args() -> &'static [&'static str] { // The flags here should be kept in sync with what bootstrap adds when `test-miri` is From cb691b7ed9f0b6c37828d85126b2aaed4c2b57af Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Nov 2018 11:42:38 +0100 Subject: [PATCH 0333/5092] comment on mut-to-shr transmutes --- src/stacked_borrows.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 4d78519be61d..afc76fa375bc 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -462,7 +462,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // also using `var`, and that would be okay. } (UsageKind::Read, Borrow::Mut(Mut::Uniq(_))) => { - // A mut got transmuted to shr. The mut borrow must be reactivatable. + // A mut got transmuted to shr. Can happen even from compiler transformations: + // `&*x` gets optimized to `x` even when `x` is a `&mut`. } (UsageKind::Write, Borrow::Frz(_)) => { // This is just invalid. From e68687b8402720001a25bc45677b747690aefd3a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Nov 2018 12:07:16 +0100 Subject: [PATCH 0334/5092] test that we check the layout constraints as early as we can --- tests/compile-fail/nonzero.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/compile-fail/nonzero.rs diff --git a/tests/compile-fail/nonzero.rs b/tests/compile-fail/nonzero.rs new file mode 100644 index 000000000000..d1de0f8095e3 --- /dev/null +++ b/tests/compile-fail/nonzero.rs @@ -0,0 +1,11 @@ +#![feature(rustc_attrs)] +#![allow(unused_attributes)] + +#[rustc_layout_scalar_valid_range_start(1)] +#[repr(transparent)] +pub(crate) struct NonZero(pub(crate) T); + +fn main() { + // Make sure that we detect this even when no function call is happening along the way + let _x = Some(NonZero(0)); //~ ERROR encountered 0, but expected something greater or equal to 1 +} From efd2f0e0e49d19f322b28f49291bb60b972b8f65 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Nov 2018 12:33:14 +0100 Subject: [PATCH 0335/5092] move new test to correct dir --- tests/compile-fail/{ => validity}/nonzero.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/compile-fail/{ => validity}/nonzero.rs (100%) diff --git a/tests/compile-fail/nonzero.rs b/tests/compile-fail/validity/nonzero.rs similarity index 100% rename from tests/compile-fail/nonzero.rs rename to tests/compile-fail/validity/nonzero.rs From a8af5ae139b61a6a2b2b04718e0943476259c7ec Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Nov 2018 10:21:22 +0100 Subject: [PATCH 0336/5092] fix for latest nightly --- rust-version | 2 +- src/lib.rs | 2 +- xargo/Xargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 6b277cc26bc9..f5e9fdb9f6af 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-03 +nightly-2018-11-04 diff --git a/src/lib.rs b/src/lib.rs index a2271a5898b7..2fdd27b842e4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -89,7 +89,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( if libstd_has_mir { let start_id = tcx.lang_items().start_fn().unwrap(); let main_ret_ty = tcx.fn_sig(main_id).output(); - let main_ret_ty = main_ret_ty.no_late_bound_regions().unwrap(); + let main_ret_ty = main_ret_ty.no_bound_vars().unwrap(); let start_instance = ty::Instance::resolve( ecx.tcx.tcx, ty::ParamEnv::reveal_all(), diff --git a/xargo/Xargo.toml b/xargo/Xargo.toml index c022837a5e61..e49b0dbe743b 100644 --- a/xargo/Xargo.toml +++ b/xargo/Xargo.toml @@ -1,5 +1,5 @@ [dependencies.std] -features = ["panic_unwind", "jemalloc", "backtrace"] +features = ["panic_unwind", "backtrace"] [dependencies.test] stage = 1 From 9edac3189a12772c5dde55c52c8eb5a8292d1274 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Nov 2018 08:51:55 +0100 Subject: [PATCH 0337/5092] rustup --- rust-version | 2 +- src/fn_call.rs | 50 +++++++++++++-------------- src/intrinsic.rs | 78 +++++++++++++++++++++--------------------- src/stacked_borrows.rs | 4 +-- src/tls.rs | 12 +++---- 5 files changed, 73 insertions(+), 73 deletions(-) diff --git a/rust-version b/rust-version index f5e9fdb9f6af..734df301d8e0 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-04 +nightly-2018-11-05 diff --git a/src/fn_call.rs b/src/fn_call.rs index 7e1ff3233f21..d9bf049df704 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -120,7 +120,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo match &link_name[..] { "malloc" => { - let size = self.read_scalar(args[0])?.to_usize(&self)?; + let size = self.read_scalar(args[0])?.to_usize(self)?; if size == 0 { self.write_null(dest)?; } else { @@ -132,7 +132,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "free" => { let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation, no tag - if !ptr.is_null_ptr(&self) { + if !ptr.is_null_ptr(self) { self.memory_mut().deallocate( ptr.to_ptr()?.with_default_tag(), None, @@ -142,8 +142,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "__rust_alloc" => { - let size = self.read_scalar(args[0])?.to_usize(&self)?; - let align = self.read_scalar(args[1])?.to_usize(&self)?; + let size = self.read_scalar(args[0])?.to_usize(self)?; + let align = self.read_scalar(args[1])?.to_usize(self)?; if size == 0 { return err!(HeapAllocZeroBytes); } @@ -160,8 +160,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo self.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_alloc_zeroed" => { - let size = self.read_scalar(args[0])?.to_usize(&self)?; - let align = self.read_scalar(args[1])?.to_usize(&self)?; + let size = self.read_scalar(args[0])?.to_usize(self)?; + let align = self.read_scalar(args[1])?.to_usize(self)?; if size == 0 { return err!(HeapAllocZeroBytes); } @@ -180,8 +180,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "__rust_dealloc" => { let ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation, no tag - let old_size = self.read_scalar(args[1])?.to_usize(&self)?; - let align = self.read_scalar(args[2])?.to_usize(&self)?; + let old_size = self.read_scalar(args[1])?.to_usize(self)?; + let align = self.read_scalar(args[2])?.to_usize(self)?; if old_size == 0 { return err!(HeapAllocZeroBytes); } @@ -196,9 +196,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "__rust_realloc" => { let ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation, no tag - let old_size = self.read_scalar(args[1])?.to_usize(&self)?; - let align = self.read_scalar(args[2])?.to_usize(&self)?; - let new_size = self.read_scalar(args[3])?.to_usize(&self)?; + let old_size = self.read_scalar(args[1])?.to_usize(self)?; + let align = self.read_scalar(args[2])?.to_usize(self)?; + let new_size = self.read_scalar(args[3])?.to_usize(self)?; if old_size == 0 || new_size == 0 { return err!(HeapAllocZeroBytes); } @@ -222,7 +222,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // // libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK) // is called if a `HashMap` is created the regular way. - match self.read_scalar(args[0])?.to_usize(&self)? { + match self.read_scalar(args[0])?.to_usize(self)? { 318 | 511 => { return err!(Unimplemented( "miri does not support random number generators".to_owned(), @@ -260,7 +260,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // Now we make a function call. TODO: Consider making this re-usable? EvalContext::step does sth. similar for the TLS dtors, // and of course eval_main. let mir = self.load_mir(f_instance.def)?; - let ret_place = MPlaceTy::dangling(self.layout_of(self.tcx.mk_unit())?, &self).into(); + let ret_place = MPlaceTy::dangling(self.layout_of(self.tcx.mk_unit())?, self).into(); self.push_stack_frame( f_instance, mir.span, @@ -294,7 +294,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "memcmp" => { let left = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation let right = self.read_scalar(args[1])?.not_undef()?.erase_tag(); // raw ptr operation - let n = Size::from_bytes(self.read_scalar(args[2])?.to_usize(&self)?); + let n = Size::from_bytes(self.read_scalar(args[2])?.to_usize(self)?); let result = { let left_bytes = self.memory().read_bytes(left.with_default_tag(), n)?; @@ -318,11 +318,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation let ptr = ptr.with_default_tag(); let val = self.read_scalar(args[1])?.to_bytes()? as u8; - let num = self.read_scalar(args[2])?.to_usize(&self)?; + let num = self.read_scalar(args[2])?.to_usize(self)?; if let Some(idx) = self.memory().read_bytes(ptr, Size::from_bytes(num))? .iter().rev().position(|&c| c == val) { - let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), &self)?; + let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), self)?; self.write_scalar(new_ptr, dest)?; } else { self.write_null(dest)?; @@ -333,12 +333,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation let ptr = ptr.with_default_tag(); let val = self.read_scalar(args[1])?.to_bytes()? as u8; - let num = self.read_scalar(args[2])?.to_usize(&self)?; + let num = self.read_scalar(args[2])?.to_usize(self)?; if let Some(idx) = self.memory().read_bytes(ptr, Size::from_bytes(num))?.iter().position( |&c| c == val, ) { - let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), &self)?; + let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), self)?; self.write_scalar(new_ptr, dest)?; } else { self.write_null(dest)?; @@ -351,7 +351,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let name = self.memory().read_c_str(name_ptr.with_default_tag())?; match self.machine.env_vars.get(name) { Some(&var) => Scalar::Ptr(var), - None => Scalar::ptr_null(*self.tcx), + None => Scalar::ptr_null(&*self.tcx), } }; self.write_scalar(result, dest)?; @@ -361,7 +361,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let mut success = None; { let name_ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation - if !name_ptr.is_null_ptr(&self) { + if !name_ptr.is_null_ptr(self) { let name = self.memory().read_c_str(name_ptr.to_ptr()? .with_default_tag())?.to_owned(); if !name.is_empty() && !name.contains(&b'=') { @@ -385,7 +385,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let name_ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation let value_ptr = self.read_scalar(args[1])?.to_ptr()?.erase_tag(); // raw ptr operation let value = self.memory().read_c_str(value_ptr.with_default_tag())?; - if !name_ptr.is_null_ptr(&self) { + if !name_ptr.is_null_ptr(self) { let name = self.memory().read_c_str(name_ptr.to_ptr()?.with_default_tag())?; if !name.is_empty() && !name.contains(&b'=') { new = Some((name.to_owned(), value.to_owned())); @@ -400,7 +400,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo MiriMemoryKind::Env.into(), )?.with_default_tag(); self.memory_mut().write_bytes(value_copy.into(), &value)?; - let trailing_zero_ptr = value_copy.offset(Size::from_bytes(value.len() as u64), &self)?.into(); + let trailing_zero_ptr = value_copy.offset(Size::from_bytes(value.len() as u64), self)?.into(); self.memory_mut().write_bytes(trailing_zero_ptr, &[0])?; if let Some(var) = self.machine.env_vars.insert( name.to_owned(), @@ -510,7 +510,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let key_layout = self.layout_of(key_type)?; // Create key and write it into the memory where key_ptr wants it - let key = self.machine.tls.create_tls_key(dtor, *self.tcx) as u128; + let key = self.machine.tls.create_tls_key(dtor, &*self.tcx) as u128; if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) { return err!(OutOfTls); } @@ -555,7 +555,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "pthread_attr_getstack" => { // second argument is where we are supposed to write the stack size - let ptr = self.ref_to_mplace(self.read_value(args[1])?)?; + let ptr = self.ref_to_mplace(self.read_immediate(args[1])?)?; let stackaddr = Scalar::from_int(0x80000, args[1].layout.size); // just any address self.write_scalar(stackaddr, ptr.into())?; // return 0 @@ -613,7 +613,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // This just creates a key; Windows does not natively support TLS dtors. // Create key and return it - let key = self.machine.tls.create_tls_key(None, *self.tcx) as u128; + let key = self.machine.tls.create_tls_key(None, &*self.tcx) as u128; // Figure out how large a TLS key actually is. This is c::DWORD. if dest.layout.size.bits() < 128 && key >= (1u128 << dest.layout.size.bits() as u128) { diff --git a/src/intrinsic.rs b/src/intrinsic.rs index caf5687b231c..9aad6f95f316 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -5,7 +5,7 @@ use rustc::ty; use rustc::mir::interpret::{EvalResult, PointerArithmetic}; use crate::{ - PlaceTy, OpTy, Value, Scalar, ScalarMaybeUndef, Borrow, + PlaceTy, OpTy, Immediate, Scalar, ScalarMaybeUndef, Borrow, ScalarExt, OperatorEvalContextExt }; @@ -38,13 +38,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..]; match intrinsic_name { "arith_offset" => { - let offset = self.read_scalar(args[1])?.to_isize(&self)?; + let offset = self.read_scalar(args[1])?.to_isize(self)?; let ptr = self.read_scalar(args[0])?.not_undef()?; let pointee_ty = substs.type_at(0); let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; let offset = offset.overflowing_mul(pointee_size).0; - let result_ptr = ptr.ptr_wrapping_signed_offset(offset, &self); + let result_ptr = ptr.ptr_wrapping_signed_offset(offset, self); self.write_scalar(result_ptr, dest)?; } @@ -59,7 +59,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "atomic_load_relaxed" | "atomic_load_acq" | "volatile_load" => { - let ptr = self.ref_to_mplace(self.read_value(args[0])?)?; + let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?; let val = self.read_scalar(ptr.into())?; // make sure it fits into a scalar; otherwise it cannot be atomic self.write_scalar(val, dest)?; } @@ -68,7 +68,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "atomic_store_relaxed" | "atomic_store_rel" | "volatile_store" => { - let ptr = self.ref_to_mplace(self.read_value(args[0])?)?; + let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?; let val = self.read_scalar(args[1])?; // make sure it fits into a scalar; otherwise it cannot be atomic self.write_scalar(val, ptr.into())?; } @@ -78,7 +78,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } _ if intrinsic_name.starts_with("atomic_xchg") => { - let ptr = self.ref_to_mplace(self.read_value(args[0])?)?; + let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?; let new = self.read_scalar(args[1])?; let old = self.read_scalar(ptr.into())?; self.write_scalar(old, dest)?; // old value is returned @@ -86,14 +86,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } _ if intrinsic_name.starts_with("atomic_cxchg") => { - let ptr = self.ref_to_mplace(self.read_value(args[0])?)?; - let expect_old = self.read_value(args[1])?; // read as value for the sake of `binary_op_val()` + let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?; + let expect_old = self.read_immediate(args[1])?; // read as value for the sake of `binary_op_val()` let new = self.read_scalar(args[2])?; - let old = self.read_value(ptr.into())?; // read as value for the sake of `binary_op_val()` + let old = self.read_immediate(ptr.into())?; // read as value for the sake of `binary_op_val()` // binary_op_val will bail if either of them is not a scalar let (eq, _) = self.binary_op_val(mir::BinOp::Eq, old, expect_old)?; - let res = Value::ScalarPair(old.to_scalar_or_undef(), eq.into()); - self.write_value(res, dest)?; // old value is returned + let res = Immediate::ScalarPair(old.to_scalar_or_undef(), eq.into()); + self.write_immediate(res, dest)?; // old value is returned // update ptr depending on comparison if eq.to_bool()? { self.write_scalar(new, ptr.into())?; @@ -125,13 +125,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "atomic_xsub_rel" | "atomic_xsub_acqrel" | "atomic_xsub_relaxed" => { - let ptr = self.ref_to_mplace(self.read_value(args[0])?)?; + let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?; if !ptr.layout.ty.is_integral() { return err!(Unimplemented(format!("Atomic arithmetic operations only work on integer types"))); } - let rhs = self.read_value(args[1])?; - let old = self.read_value(ptr.into())?; - self.write_value(*old, dest)?; // old value is returned + let rhs = self.read_immediate(args[1])?; + let old = self.read_immediate(ptr.into())?; + self.write_immediate(*old, dest)?; // old value is returned let op = match intrinsic_name.split('_').nth(1).unwrap() { "or" => mir::BinOp::BitOr, "xor" => mir::BinOp::BitXor, @@ -151,7 +151,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let elem_ty = substs.type_at(0); let elem_layout = self.layout_of(elem_ty)?; let elem_size = elem_layout.size.bytes(); - let count = self.read_scalar(args[2])?.to_usize(&self)?; + let count = self.read_scalar(args[2])?.to_usize(self)?; let elem_align = elem_layout.align; // erase tags: this is a raw ptr operation let src = self.read_scalar(args[0])?.not_undef()?.erase_tag(); @@ -167,7 +167,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } "discriminant_value" => { - let place = self.ref_to_mplace(self.read_value(args[0])?)?; + let place = self.ref_to_mplace(self.read_immediate(args[0])?)?; let discr_val = self.read_discriminant(place.into())?.0; self.write_scalar(Scalar::from_uint(discr_val, dest.layout.size), dest)?; } @@ -215,8 +215,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { - let a = self.read_value(args[0])?; - let b = self.read_value(args[1])?; + let a = self.read_immediate(args[0])?; + let b = self.read_immediate(args[1])?; let op = match intrinsic_name { "fadd_fast" => mir::BinOp::Add, "fsub_fast" => mir::BinOp::Sub, @@ -231,8 +231,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "exact_div" => { // Performs an exact division, resulting in undefined behavior where // `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1` - let a = self.read_value(args[0])?; - let b = self.read_value(args[1])?; + let a = self.read_immediate(args[0])?; + let b = self.read_immediate(args[1])?; // check x % y != 0 if self.binary_op_val(mir::BinOp::Rem, a, b)?.0.to_bytes()? != 0 { return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b))); @@ -251,13 +251,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' if !dest.layout.is_zst() { // nothing to do for ZST match dest.layout.abi { layout::Abi::Scalar(ref s) => { - let x = Scalar::from_int(0, s.value.size(&self)); - self.write_value(Value::Scalar(x.into()), dest)?; + let x = Scalar::from_int(0, s.value.size(self)); + self.write_immediate(Immediate::Scalar(x.into()), dest)?; } layout::Abi::ScalarPair(ref s1, ref s2) => { - let x = Scalar::from_int(0, s1.value.size(&self)); - let y = Scalar::from_int(0, s2.value.size(&self)); - self.write_value(Value::ScalarPair(x.into(), y.into()), dest)?; + let x = Scalar::from_int(0, s1.value.size(self)); + let y = Scalar::from_int(0, s2.value.size(self)); + self.write_immediate(Immediate::ScalarPair(x.into(), y.into()), dest)?; } _ => { // Do it in memory @@ -279,12 +279,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } "move_val_init" => { - let ptr = self.ref_to_mplace(self.read_value(args[0])?)?; + let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?; self.copy_op(args[1], ptr.into())?; } "offset" => { - let offset = self.read_scalar(args[1])?.to_isize(&self)?; + let offset = self.read_scalar(args[1])?.to_isize(self)?; let ptr = self.read_scalar(args[0])?.not_undef()?; let result_ptr = self.pointer_offset_inbounds(ptr, substs.type_at(0), offset)?; self.write_scalar(result_ptr, dest)?; @@ -347,7 +347,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } "size_of_val" => { - let mplace = self.ref_to_mplace(self.read_value(args[0])?)?; + let mplace = self.ref_to_mplace(self.read_immediate(args[0])?)?; let (size, _) = self.size_and_align_of_mplace(mplace)? .expect("size_of_val called on extern type"); let ptr_size = self.pointer_size(); @@ -359,7 +359,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "min_align_of_val" | "align_of_val" => { - let mplace = self.ref_to_mplace(self.read_value(args[0])?)?; + let mplace = self.ref_to_mplace(self.read_immediate(args[0])?)?; let (_, align) = self.size_and_align_of_mplace(mplace)? .expect("size_of_val called on extern type"); let ptr_size = self.pointer_size(); @@ -372,13 +372,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "type_name" => { let ty = substs.type_at(0); let ty_name = ty.to_string(); - let value = self.str_to_value(&ty_name)?; - self.write_value(value, dest)?; + let value = self.str_to_immediate(&ty_name)?; + self.write_immediate(value, dest)?; } "unchecked_div" => { - let l = self.read_value(args[0])?; - let r = self.read_value(args[1])?; + let l = self.read_immediate(args[0])?; + let r = self.read_immediate(args[1])?; let rval = r.to_scalar()?.to_bytes()?; if rval == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_div"))); @@ -392,8 +392,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } "unchecked_rem" => { - let l = self.read_value(args[0])?; - let r = self.read_value(args[1])?; + let l = self.read_immediate(args[0])?; + let r = self.read_immediate(args[1])?; let rval = r.to_scalar()?.to_bytes()?; if rval == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_rem"))); @@ -416,11 +416,11 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' match dest.layout.abi { layout::Abi::Scalar(..) => { let x = ScalarMaybeUndef::Undef; - self.write_value(Value::Scalar(x), dest)?; + self.write_immediate(Immediate::Scalar(x), dest)?; } layout::Abi::ScalarPair(..) => { let x = ScalarMaybeUndef::Undef; - self.write_value(Value::ScalarPair(x, x), dest)?; + self.write_immediate(Immediate::ScalarPair(x, x), dest)?; } _ => { // Do it in memory @@ -437,7 +437,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let ty_layout = self.layout_of(ty)?; let val_byte = self.read_scalar(args[1])?.to_u8()?; let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag().with_default_tag(); - let count = self.read_scalar(args[2])?.to_usize(&self)?; + let count = self.read_scalar(args[2])?.to_usize(self)?; self.memory().check_align(ptr, ty_layout.align)?; self.memory_mut().write_repeat(ptr, val_byte, ty_layout.size * count)?; } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index afc76fa375bc..6d3abbcc3152 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -539,12 +539,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // above. First deref, which will call `tag_dereference`. // (This is somewhat redundant because validation already did the same thing, // but what can you do.) - let val = self.read_value(self.place_to_op(place)?)?; + let val = self.read_immediate(self.place_to_op(place)?)?; let dest = self.ref_to_mplace(val)?; // Now put a new ref into the old place, which will call `tag_reference`. // FIXME: Honor `fn_entry`! let val = self.create_ref(dest, Some(mutbl))?; - self.write_value(val, place)?; + self.write_immediate(val, place)?; Ok(()) } } diff --git a/src/tls.rs b/src/tls.rs index 001da10ddc21..1aacc67f5cca 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -42,7 +42,7 @@ impl<'tcx> TlsData<'tcx> { pub fn create_tls_key( &mut self, dtor: Option>, - cx: impl HasDataLayout, + cx: &impl HasDataLayout, ) -> TlsKey { let new_key = self.next_key; self.next_key += 1; @@ -109,7 +109,7 @@ impl<'tcx> TlsData<'tcx> { fn fetch_tls_dtor( &mut self, key: Option, - cx: impl HasDataLayout, + cx: &impl HasDataLayout, ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { use std::collections::Bound::*; @@ -135,14 +135,14 @@ impl<'tcx> TlsData<'tcx> { impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { fn run_tls_dtors(&mut self) -> EvalResult<'tcx> { - let mut dtor = self.machine.tls.fetch_tls_dtor(None, *self.tcx); + let mut dtor = self.machine.tls.fetch_tls_dtor(None, &*self.tcx); // FIXME: replace loop by some structure that works with stepping while let Some((instance, ptr, key)) = dtor { trace!("Running TLS dtor {:?} on {:?}", instance, ptr); // TODO: Potentially, this has to support all the other possible instances? // See eval_fn_call in interpret/terminator/mod.rs let mir = self.load_mir(instance.def)?; - let ret_place = MPlaceTy::dangling(self.layout_of(self.tcx.mk_unit())?, &self).into(); + let ret_place = MPlaceTy::dangling(self.layout_of(self.tcx.mk_unit())?, self).into(); self.push_stack_frame( instance, mir.span, @@ -159,9 +159,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for super::MiriEvalContext< // step until out of stackframes self.run()?; - dtor = match self.machine.tls.fetch_tls_dtor(Some(key), *self.tcx) { + dtor = match self.machine.tls.fetch_tls_dtor(Some(key), &*self.tcx) { dtor @ Some(_) => dtor, - None => self.machine.tls.fetch_tls_dtor(None, *self.tcx), + None => self.machine.tls.fetch_tls_dtor(None, &*self.tcx), }; } // FIXME: On a windows target, call `unsafe extern "system" fn on_tls_callback`. From f6d6470bc4e332eadaba27d9c494f79aafd75a66 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Nov 2018 15:45:24 +0100 Subject: [PATCH 0338/5092] move to 2018 edition I want NLL :D --- Cargo.toml | 1 + src/bin/miri-rustc-tests.rs | 2 +- src/bin/miri.rs | 2 +- src/lib.rs | 4 ++-- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dcf93fa14104..390efe0a073a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ repository = "https://github.com/solson/miri" version = "0.1.0" build = "build.rs" default-run = "miri" +edition = "2018" [lib] test = true # we have unit tests diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 6fa9b817ffee..c9ec1011ddbb 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -1,4 +1,4 @@ -#![feature(rustc_private)] +#![feature(rustc_private, extern_crate_item_prelude)] extern crate miri; extern crate getopts; extern crate rustc; diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 1bbf3c8c4a4a..bfe631b51f0f 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -1,4 +1,4 @@ -#![feature(rustc_private)] +#![feature(rustc_private, extern_crate_item_prelude)] extern crate getopts; extern crate miri; diff --git a/src/lib.rs b/src/lib.rs index 2fdd27b842e4..b4b7a310ca9d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(rustc_private)] +#![feature(rustc_private, extern_crate_item_prelude)] #![cfg_attr(feature = "cargo-clippy", allow(cast_lossless))] @@ -253,7 +253,7 @@ impl Into> for MiriMemoryKind { impl MayLeak for MiriMemoryKind { #[inline(always)] fn may_leak(self) -> bool { - use MiriMemoryKind::*; + use self::MiriMemoryKind::*; match self { Rust | C => false, Env | MutStatic => true, From 2ff1f24f2b95604b43518f334c445b9a5ab47c21 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Nov 2018 10:11:16 +0100 Subject: [PATCH 0339/5092] bump rust --- rust-version | 2 +- src/intrinsic.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index 734df301d8e0..48887947cdf7 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-05 +nightly-2018-11-07 diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 9aad6f95f316..20402f4a2329 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -87,11 +87,11 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' _ if intrinsic_name.starts_with("atomic_cxchg") => { let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?; - let expect_old = self.read_immediate(args[1])?; // read as value for the sake of `binary_op_val()` + let expect_old = self.read_immediate(args[1])?; // read as value for the sake of `binary_op_imm()` let new = self.read_scalar(args[2])?; - let old = self.read_immediate(ptr.into())?; // read as value for the sake of `binary_op_val()` - // binary_op_val will bail if either of them is not a scalar - let (eq, _) = self.binary_op_val(mir::BinOp::Eq, old, expect_old)?; + let old = self.read_immediate(ptr.into())?; // read as value for the sake of `binary_op_imm()` + // binary_op_imm will bail if either of them is not a scalar + let (eq, _) = self.binary_op_imm(mir::BinOp::Eq, old, expect_old)?; let res = Immediate::ScalarPair(old.to_scalar_or_undef(), eq.into()); self.write_immediate(res, dest)?; // old value is returned // update ptr depending on comparison @@ -234,7 +234,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let a = self.read_immediate(args[0])?; let b = self.read_immediate(args[1])?; // check x % y != 0 - if self.binary_op_val(mir::BinOp::Rem, a, b)?.0.to_bytes()? != 0 { + if self.binary_op_imm(mir::BinOp::Rem, a, b)?.0.to_bytes()? != 0 { return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b))); } self.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; From a05ba90300743f4035a5b8df0d65b916e2c7f11d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Nov 2018 14:24:11 +0100 Subject: [PATCH 0340/5092] disable Rc test for now, it ain't working --- tests/run-pass/rc.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index 4d89066035ce..f4a8855bea2f 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -1,5 +1,5 @@ -// FIXME: Validation disabled due to https://github.com/rust-lang/rust/issues/54908 -// compile-flags: -Zmiri-disable-validation +// FIXME: Disabled due to https://github.com/rust-lang/rust/issues/55747 +// ignore-test use std::cell::RefCell; use std::rc::Rc; From 74635a57e2c0d8791a49170bb8c06042a9b3a62e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Nov 2018 16:05:17 +0100 Subject: [PATCH 0341/5092] re-do large parts of stacked borrows, now with proper support for partiall frozen data --- cargo-miri-test/run-test.py | 3 +- src/helpers.rs | 131 +++++ src/lib.rs | 36 +- src/stacked_borrows.rs | 484 +++++++++--------- src/tls.rs | 2 +- .../stacked_borrows/buggy_as_mut_slice.rs | 2 +- .../stacked_borrows/buggy_split_at_mut.rs | 2 +- .../stacked_borrows/illegal_read1.rs | 2 +- .../stacked_borrows/illegal_read2.rs | 2 +- .../stacked_borrows/illegal_write1.rs | 2 +- .../stacked_borrows/illegal_write3.rs | 4 +- .../stacked_borrows/illegal_write4.rs | 2 +- .../stacked_borrows/load_invalid_mut.rs | 2 +- .../stacked_borrows/load_invalid_shr.rs | 2 +- .../stacked_borrows/pass_invalid_mut.rs | 2 +- .../stacked_borrows/pass_invalid_shr.rs | 2 +- .../stacked_borrows/return_invalid_mut.rs | 2 +- .../stacked_borrows/return_invalid_shr.rs | 2 +- .../stacked_borrows/shared_confusion.rs | 29 -- .../stacked_borrows/shared_confusion_opt.rs | 25 - .../validity/invalid_enum_discriminant.rs | 2 +- .../validity/transmute_through_ptr.rs | 2 +- .../send-is-not-static-par-for.rs | 3 - tests/run-pass-fullmir/u128.rs | 3 - tests/run-pass-fullmir/vecdeque.rs | 3 - tests/run-pass/slices.rs | 3 - tests/run-pass/stacked-borrows.rs | 17 +- 27 files changed, 435 insertions(+), 336 deletions(-) delete mode 100644 tests/compile-fail/stacked_borrows/shared_confusion.rs delete mode 100644 tests/compile-fail/stacked_borrows/shared_confusion_opt.rs diff --git a/cargo-miri-test/run-test.py b/cargo-miri-test/run-test.py index 506de85ffcb2..f686cc47449d 100755 --- a/cargo-miri-test/run-test.py +++ b/cargo-miri-test/run-test.py @@ -10,9 +10,8 @@ import sys, subprocess def test_cargo_miri(): print("==> Testing `cargo miri` <==") ## Call `cargo miri`, capture all output - # FIXME: Disabling validation, still investigating whether there is UB here p = subprocess.Popen( - ["cargo", "miri", "-q", "--", "-Zmiri-disable-validation"], + ["cargo", "miri", "-q"], stdout=subprocess.PIPE, stderr=subprocess.PIPE ) diff --git a/src/helpers.rs b/src/helpers.rs index 6dc5b768ea63..52d3db8ac46f 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -32,6 +32,15 @@ impl ScalarExt for ScalarMaybeUndef { pub trait EvalContextExt<'tcx> { fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>>; + + /// Visit the memory covered by `place` that is frozen -- i.e., NOT + /// what is inside an `UnsafeCell`. + fn visit_frozen( + &self, + place: MPlaceTy<'tcx, Borrow>, + size: Size, + action: impl FnMut(Pointer, Size) -> EvalResult<'tcx>, + ) -> EvalResult<'tcx>; } @@ -69,4 +78,126 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: EvalErrorKind::PathNotFound(path).into() }) } + + /// Visit the memory covered by `place` that is frozen -- i.e., NOT + /// what is inside an `UnsafeCell`. + fn visit_frozen( + &self, + place: MPlaceTy<'tcx, Borrow>, + size: Size, + mut frozen_action: impl FnMut(Pointer, Size) -> EvalResult<'tcx>, + ) -> EvalResult<'tcx> { + trace!("visit_frozen(place={:?}, size={:?})", *place, size); + debug_assert_eq!(size, + self.size_and_align_of_mplace(place)? + .map(|(size, _)| size) + .unwrap_or_else(|| place.layout.size) + ); + // Store how far we proceeded into the place so far. Everything to the left of + // this offset has already been handled, in the sense that the frozen parts + // have had `action` called on them. + let mut end_ptr = place.ptr; + // Called when we detected an `UnsafeCell` at the given offset and size. + // Calls `action` and advances `end_ptr`. + let mut unsafe_cell_action = |unsafe_cell_offset, unsafe_cell_size| { + // We assume that we are given the fields in increasing offset order, + // and nothing else changes. + let end_offset = end_ptr.get_ptr_offset(self); + assert!(unsafe_cell_offset >= end_offset); + let frozen_size = unsafe_cell_offset - end_offset; + // Everything between the end_ptr and this `UnsafeCell` is frozen. + if frozen_size != Size::ZERO { + frozen_action(end_ptr.to_ptr()?, frozen_size)?; + } + // Update end end_ptr. + end_ptr = end_ptr.ptr_wrapping_offset(frozen_size+unsafe_cell_size, self); + // Done + Ok(()) + }; + // Run a visitor + { + let mut visitor = UnsafeCellVisitor { + ecx: self, + unsafe_cell_action: |place| { + trace!("unsafe_cell_action on {:?}", place.ptr); + // We need a size to go on. + let (unsafe_cell_size, _) = self.size_and_align_of_mplace(place)? + // for extern types, just cover what we can + .unwrap_or_else(|| place.layout.size_and_align()); + // Now handle this `UnsafeCell`. + unsafe_cell_action(place.ptr.get_ptr_offset(self), unsafe_cell_size) + }, + }; + visitor.visit_value(place)?; + } + // The part between the end_ptr and the end of the place is also frozen. + // So pretend there is a 0-sized `UnsafeCell` at the end. + unsafe_cell_action(place.ptr.get_ptr_offset(self) + size, Size::ZERO)?; + // Done! + return Ok(()); + + /// Visiting the memory covered by a `MemPlace`, being aware of + /// whether we are inside an `UnsafeCell` or not. + struct UnsafeCellVisitor<'ecx, 'a, 'mir, 'tcx, F> + where F: FnMut(MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> + { + ecx: &'ecx MiriEvalContext<'a, 'mir, 'tcx>, + unsafe_cell_action: F, + } + + impl<'ecx, 'a, 'mir, 'tcx, F> ValueVisitor<'a, 'mir, 'tcx, Evaluator<'tcx>> + for UnsafeCellVisitor<'ecx, 'a, 'mir, 'tcx, F> + where + F: FnMut(MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> + { + type V = MPlaceTy<'tcx, Borrow>; + + const WANT_FIELDS_SORTED: bool = true; // sorted? yes please! + + #[inline(always)] + fn ecx(&self) -> &MiriEvalContext<'a, 'mir, 'tcx> { + &self.ecx + } + + // Hook to detect `UnsafeCell` + fn visit_value(&mut self, v: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> + { + trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty); + let is_unsafe_cell = match v.layout.ty.sty { + ty::Adt(adt, _) => Some(adt.did) == self.ecx.tcx.lang_items().unsafe_cell_type(), + _ => false, + }; + if is_unsafe_cell { + // We do not have to recurse further, this is an `UnsafeCell`. + (self.unsafe_cell_action)(v) + } else if self.ecx.type_is_freeze(v.layout.ty) { + // This is `Freeze`, there cannot be an `UnsafeCell` + Ok(()) + } else { + // Proceed further + self.walk_value(v) + } + } + + // We have to do *something* for unions + fn visit_union(&mut self, v: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> + { + // With unions, we fall back to whatever the type says, to hopefully be consistent + // with LLVM IR. + // FIXME Are we consistent? And is this really the behavior we want? + let frozen = self.ecx.type_is_freeze(v.layout.ty); + if frozen { + Ok(()) + } else { + (self.unsafe_cell_action)(v) + } + } + + // We should never get to a primitive, but always short-circuit somewhere above + fn visit_primitive(&mut self, _val: ImmTy<'tcx, Borrow>) -> EvalResult<'tcx> + { + bug!("We should always short-circit before coming to a primitive") + } + } + } } diff --git a/src/lib.rs b/src/lib.rs index b4b7a310ca9d..134986c814de 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,7 +17,7 @@ use std::collections::HashMap; use std::borrow::Cow; use std::env; -use rustc::ty::{self, Ty, TyCtxt, query::TyCtxtAt}; +use rustc::ty::{self, TyCtxt, query::TyCtxtAt}; use rustc::ty::layout::{TyLayout, LayoutOf, Size}; use rustc::hir::{self, def_id::DefId}; use rustc::mir; @@ -48,7 +48,7 @@ use crate::mono_hash_map::MonoHashMap; use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; // Used by priroda -pub use crate::stacked_borrows::{Borrow, Stack, Stacks, Mut as MutBorrow, BorStackItem}; +pub use crate::stacked_borrows::{Borrow, Stack, Stacks, BorStackItem}; /// Insert rustc arguments at the beginning of the argument list that miri wants to be /// set per default, for maximal validation power. @@ -476,38 +476,38 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn tag_reference( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - place: MemPlace, - ty: Ty<'tcx>, - size: Size, + place: MPlaceTy<'tcx, Borrow>, mutability: Option, - ) -> EvalResult<'tcx, MemPlace> { + ) -> EvalResult<'tcx, Scalar> { + let (size, _) = ecx.size_and_align_of_mplace(place)? + // for extern types, just cover what we can + .unwrap_or_else(|| place.layout.size_and_align()); if !ecx.machine.validate || size == Size::ZERO { // No tracking - Ok(place) + Ok(place.ptr) } else { let ptr = place.ptr.to_ptr()?; - let tag = ecx.tag_reference(ptr, ty, size, mutability.into())?; - let ptr = Scalar::Ptr(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag)); - Ok(MemPlace { ptr, ..place }) + let tag = ecx.tag_reference(place, size, mutability.into())?; + Ok(Scalar::Ptr(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag))) } } #[inline(always)] fn tag_dereference( ecx: &EvalContext<'a, 'mir, 'tcx, Self>, - place: MemPlace, - ty: Ty<'tcx>, - size: Size, + place: MPlaceTy<'tcx, Borrow>, mutability: Option, - ) -> EvalResult<'tcx, MemPlace> { + ) -> EvalResult<'tcx, Scalar> { + let (size, _) = ecx.size_and_align_of_mplace(place)? + // for extern types, just cover what we can + .unwrap_or_else(|| place.layout.size_and_align()); if !ecx.machine.validate || size == Size::ZERO { // No tracking - Ok(place) + Ok(place.ptr) } else { let ptr = place.ptr.to_ptr()?; - let tag = ecx.tag_dereference(ptr, ty, size, mutability.into())?; - let ptr = Scalar::Ptr(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag)); - Ok(MemPlace { ptr, ..place }) + let tag = ecx.tag_dereference(place, size, mutability.into())?; + Ok(Scalar::Ptr(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag))) } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 6d3abbcc3152..1ab6edcf398c 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -1,64 +1,43 @@ use std::cell::RefCell; -use rustc::ty::{self, Ty, layout::Size}; +use rustc::ty::{self, layout::Size}; use rustc::hir; use crate::{ - MemoryKind, MiriMemoryKind, RangeMap, EvalResult, AllocId, - Pointer, PlaceTy, + EvalResult, MiriEvalContext, HelpersEvalContextExt, + MemoryKind, MiriMemoryKind, RangeMap, AllocId, + Pointer, PlaceTy, MPlaceTy, }; pub type Timestamp = u64; -/// Information about a potentially mutable borrow -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -pub enum Mut { - /// A unique, mutable reference - Uniq(Timestamp), - /// Any raw pointer, or a shared borrow with interior mutability - Raw, -} - -impl Mut { - #[inline(always)] - pub fn is_raw(self) -> bool { - match self { - Mut::Raw => true, - _ => false, - } - } - - #[inline(always)] - pub fn is_uniq(self) -> bool { - match self { - Mut::Uniq(_) => true, - _ => false, - } - } -} - -/// Information about any kind of borrow +/// Information about which kind of borrow was used to create the reference this is tagged +/// with. #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum Borrow { - /// A mutable borrow, a raw pointer, or a shared borrow with interior mutability - Mut(Mut), - /// A shared borrow without interior mutability - Frz(Timestamp) + /// A unique (mutable) reference. + Uniq(Timestamp), + /// A shared reference. This is also used by raw pointers, which do not track details + /// of how or when they were created, hence the timestamp is optional. + /// Shr(Some(_)) does NOT mean that the destination of this reference is frozen; + /// that depends on the type! Only those parts outside of an `UnsafeCell` are actually + /// frozen. + Shr(Option), } impl Borrow { #[inline(always)] - pub fn is_uniq(self) -> bool { + pub fn is_shr(self) -> bool { match self { - Borrow::Mut(m) => m.is_uniq(), + Borrow::Shr(_) => true, _ => false, } } #[inline(always)] - pub fn is_frz(self) -> bool { + pub fn is_uniq(self) -> bool { match self { - Borrow::Frz(_) => true, + Borrow::Uniq(_) => true, _ => false, } } @@ -66,15 +45,19 @@ impl Borrow { impl Default for Borrow { fn default() -> Self { - Borrow::Mut(Mut::Raw) + Borrow::Shr(None) } } -/// An item in the borrow stack +/// An item in the per-location borrow stack #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum BorStackItem { - /// Defines which references are permitted to mutate *if* the location is not frozen - Mut(Mut), + /// Indicates the unique reference that may mutate. + Uniq(Timestamp), + /// Indicates that the location has been shared. Used for raw pointers, but + /// also for shared references. The latter *additionally* get frozen + /// when there is no `UnsafeCell`. + Shr, /// A barrier, tracking the function it belongs to by its index on the call stack #[allow(dead_code)] // for future use FnBarrier(usize) @@ -90,6 +73,29 @@ impl BorStackItem { } } +/// Extra per-location state +#[derive(Clone, Debug)] +pub struct Stack { + borrows: Vec, // used as a stack; never empty + frozen_since: Option, // virtual frozen "item" on top of the stack +} + +impl Default for Stack { + fn default() -> Self { + Stack { + borrows: vec![BorStackItem::Shr], + frozen_since: None, + } + } +} + +impl Stack { + #[inline(always)] + pub fn is_frozen(&self) -> bool { + self.frozen_since.is_some() + } +} + /// What kind of usage of the pointer are we talking about? #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum UsageKind { @@ -97,7 +103,7 @@ pub enum UsageKind { Write, /// Read, or create & Read, - /// Create * + /// Create * (raw ptr) Raw, } @@ -123,29 +129,6 @@ impl State { } } -/// Extra per-location state -#[derive(Clone, Debug)] -pub struct Stack { - borrows: Vec, // used as a stack - frozen_since: Option, -} - -impl Default for Stack { - fn default() -> Self { - Stack { - borrows: vec![BorStackItem::Mut(Mut::Raw)], - frozen_since: None, - } - } -} - -impl Stack { - #[inline(always)] - fn is_frozen(&self) -> bool { - self.frozen_since.is_some() - } -} - /// Extra per-allocation state #[derive(Clone, Debug, Default)] pub struct Stacks { @@ -158,122 +141,123 @@ impl<'tcx> Stack { /// Check if `bor` could be activated by unfreezing and popping. /// `usage` indicates whether this is being used to read/write (or, equivalently, to /// borrow as &/&mut), or to borrow as raw. - /// Returns `Err` if the answer is "no"; otherwise the data says - /// what needs to happen to activate this: `None` = nothing, - /// `Some(n)` = unfreeze and make item `n` the top item of the stack. + /// Returns `Err` if the answer is "no"; otherwise the return value indicates what to + /// do: With `Some(n)` you need to unfreeze, and then additionally pop `n` items. fn reactivatable(&self, bor: Borrow, usage: UsageKind) -> Result, String> { - let mut_borrow = match bor { - Borrow::Frz(since) => - // The only way to reactivate a `Frz` is if this is already frozen. - return match self.frozen_since { - _ if usage == UsageKind::Write => - Err(format!("Using a shared borrow for mutation")), - None => - Err(format!("Location should be frozen but it is not")), - Some(loc) if loc <= since => - Ok(None), - Some(loc) => - Err(format!("Location should be frozen since {} but it is only frozen \ - since {}", since, loc)), - }, - Borrow::Mut(Mut::Raw) if self.is_frozen() && usage != UsageKind::Write => - // Non-mutating access with a raw from a frozen location is a special case: The - // shared refs do not mind raw reads, and the raw itself does not assume any - // exclusivity. So we do not even require there to be a raw on the stack, - // the raw is instead "matched" by the fact that this location is frozen. - // This does not break the assumption that an `&mut` we own is - // exclusive for reads, because there we have the invariant that - // the location is *not* frozen. - return Ok(None), - Borrow::Mut(mut_borrow) => mut_borrow - }; - // See if we can get there via popping. - for (idx, &itm) in self.borrows.iter().enumerate().rev() { - match itm { - BorStackItem::FnBarrier(_) => - return Err(format!("Trying to reactivate a mutable borrow ({:?}) that lives \ - behind a barrier", mut_borrow)), - BorStackItem::Mut(loc) => { - if loc == mut_borrow { - // We found it! This is good to know. - // Yet, maybe we do not really want to pop? - if usage == UsageKind::Read && self.is_frozen() { - // Whoever had exclusive access to this location allowed it - // to become frozen. That can only happen if they reborrowed - // to a shared ref, at which point they gave up on exclusive access. - // Hence we allow more reads, entirely ignoring everything above - // on the stack (but still making sure it is on the stack). - // This does not break the assumption that an `&mut` we own is - // exclusive for reads, because there we have the invariant that - // the location is *not* frozen. - return Ok(None); - } else { - return Ok(Some(idx)); + // Check if we can match the frozen "item". Not possible on writes! + if usage != UsageKind::Write { + // For now, we do NOT check the timestamp. That might be surprising, but + // we cannot even notice when a location should be frozen but is not! + // Those checks are both done in `tag_dereference`, where we have type information. + // Either way, it is crucial that the frozen "item" matches raw pointers: + // Reading through a raw should not unfreeze. + match (self.frozen_since, bor) { + (Some(_), Borrow::Shr(_)) => { + return Ok(None) + } + _ => {}, + } + } + // See if we can find this borrow. + for (idx, &itm) in self.borrows.iter().rev().enumerate() { + // Check borrow and stack item for compatibility. + match (itm, bor) { + (BorStackItem::FnBarrier(_), _) => { + return Err(format!("Trying to reactivate a borrow ({:?}) that lives \ + behind a barrier", bor)) + } + (BorStackItem::Uniq(itm_t), Borrow::Uniq(bor_t)) if itm_t == bor_t => { + // Found matching unique item. + if usage == UsageKind::Read { + // As a special case, if we are reading and since we *did* find the `Uniq`, + // we try to pop less: We are happy with making a `Shr` or `Frz` active; + // that one will not mind concurrent reads. + match self.reactivatable(Borrow::default(), usage) { + // If we got something better that `idx`, use that + Ok(None) => return Ok(None), + Ok(Some(shr_idx)) if shr_idx <= idx => return Ok(Some(shr_idx)), + // Otherwise just go on. + _ => {}, } } + return Ok(Some(idx)) } + (BorStackItem::Shr, Borrow::Shr(_)) => { + // Found matching shared/raw item. + return Ok(Some(idx)) + } + // Go on looking. + _ => {} } } // Nothing to be found. - Err(format!("Mutable borrow-to-reactivate ({:?}) does not exist on the stack", mut_borrow)) + Err(format!("Borrow-to-reactivate {:?} does not exist on the stack", bor)) } /// Reactive `bor` for this stack. `usage` indicates whether this is being /// used to read/write (or, equivalently, to borrow as &/&mut), or to borrow as raw. fn reactivate(&mut self, bor: Borrow, usage: UsageKind) -> EvalResult<'tcx> { - let action = match self.reactivatable(bor, usage) { - Ok(action) => action, + let mut pop = match self.reactivatable(bor, usage) { + Ok(None) => return Ok(()), + Ok(Some(pop)) => pop, Err(err) => return err!(MachineError(err)), }; - // Execute what `reactivatable` told us to do. - match action { - None => {}, // nothing to do - Some(top) => { - if self.frozen_since.is_some() { - trace!("reactivate: Unfreezing"); - } - self.frozen_since = None; - for itm in self.borrows.drain(top+1..).rev() { - trace!("reactivate: Popping {:?}", itm); - } - } + // Pop what `reactivatable` told us to pop. Always unfreeze. + if self.is_frozen() { + trace!("reactivate: Unfreezing"); + } + self.frozen_since = None; + while pop > 0 { + let itm = self.borrows.pop().unwrap(); + trace!("reactivate: Popping {:?}", itm); + pop -= 1; } - Ok(()) } - /// Initiate `bor`; mostly this means freezing or pushing. + /// Initiate `bor`; mostly this means pushing. /// This operation cannot fail; it is up to the caller to ensure that the precondition /// is met: We cannot push onto frozen stacks. fn initiate(&mut self, bor: Borrow) { - match bor { - Borrow::Frz(t) => { - match self.frozen_since { - None => { - trace!("initiate: Freezing"); - self.frozen_since = Some(t); - } - Some(since) => { - trace!("initiate: Already frozen"); - assert!(since <= t); - } - } - } - Borrow::Mut(m) => { - match self.frozen_since { - None => { - trace!("initiate: Pushing {:?}", bor); - self.borrows.push(BorStackItem::Mut(m)) - } - Some(_) if m.is_raw() => - // We only ever initiate right after activating the ref we come from. - // If the source ref is fine being frozen, then a raw ref we create - // from it is fine with this as well. - trace!("initiate: Initiating a raw on a frozen location, not doing a thing"), - Some(_) => - bug!("Trying to mutate frozen location") - } + if let Some(_) = self.frozen_since { + // "Pushing" a Shr or Frz on top is redundant. + match bor { + Borrow::Uniq(_) => bug!("Trying to create unique ref to frozen location"), + Borrow::Shr(_) => trace!("initiate: New shared ref to frozen location is a NOP"), } + } else { + // Just push. + let itm = match bor { + Borrow::Uniq(t) => BorStackItem::Uniq(t), + Borrow::Shr(_) if *self.borrows.last().unwrap() == BorStackItem::Shr => { + // Optimization: Don't push a Shr onto a Shr. + trace!("initiate: New shared ref to already shared location is a NOP"); + return + }, + Borrow::Shr(_) => BorStackItem::Shr, + }; + trace!("initiate: Pushing {:?}", itm); + self.borrows.push(itm) + } + } + + /// Check if this location is "frozen enough". + fn check_frozen(&self, bor_t: Timestamp) -> EvalResult<'tcx> { + let frozen = self.frozen_since.map_or(false, |itm_t| itm_t <= bor_t); + if !frozen { + err!(MachineError(format!("Location is not frozen long enough"))) + } else { + Ok(()) + } + } + + /// Freeze this location, since `bor_t`. + fn freeze(&mut self, bor_t: Timestamp) { + if let Some(itm_t) = self.frozen_since { + assert!(itm_t <= bor_t, "Trying to freeze shorter than it was frozen?"); + } else { + trace!("Freezing"); + self.frozen_since = Some(bor_t); } } } @@ -288,7 +272,7 @@ impl State { /// Higher-level operations impl<'tcx> Stacks { - /// The single most operation: Make sure that using `ptr` as `usage` is okay, + /// The single most important operation: Make sure that using `ptr` as `usage` is okay, /// and if `new_bor` is present then make that the new current borrow. fn use_and_maybe_re_borrow( &self, @@ -306,10 +290,60 @@ impl<'tcx> Stacks { stack.initiate(new_bor); } } - Ok(()) } + /// Freeze the given memory range. + fn freeze( + &self, + ptr: Pointer, + size: Size, + bor_t: Timestamp + ) -> EvalResult<'tcx> { + let mut stacks = self.stacks.borrow_mut(); + for stack in stacks.iter_mut(ptr.offset, size) { + stack.freeze(bor_t); + } + Ok(()) + } + + /// Check that this stack is fine with being dereferenced + fn check_deref( + &self, + ptr: Pointer, + size: Size, + ) -> EvalResult<'tcx> { + let mut stacks = self.stacks.borrow_mut(); + // We need `iter_mut` because `iter` would skip gaps! + for stack in stacks.iter_mut(ptr.offset, size) { + // Conservatively assume we will just read + if let Err(err) = stack.reactivatable(ptr.tag, UsageKind::Read) { + return err!(MachineError(format!( + "Encountered reference with non-reactivatable tag: {}", + err + ))) + } + } + Ok(()) + } + + /// Check that this stack is appropriately frozen + fn check_frozen( + &self, + ptr: Pointer, + size: Size, + bor_t: Timestamp + ) -> EvalResult<'tcx> { + let mut stacks = self.stacks.borrow_mut(); + for stack in stacks.iter_mut(ptr.offset, size) { + stack.check_frozen(bor_t)?; + } + Ok(()) + } +} + +/// Hooks and glue +impl<'tcx> Stacks { #[inline(always)] pub fn memory_read( &self, @@ -340,34 +374,34 @@ impl<'tcx> Stacks { // FIXME: Error out of there are any barriers? } - /// Pushes the first borrow to the stacks, must be a mutable one. - pub fn first_borrow( + /// Pushes the first item to the stacks. + pub fn first_item( &mut self, - mut_borrow: Mut, + itm: BorStackItem, size: Size ) { + assert!(!itm.is_fn_barrier()); for stack in self.stacks.get_mut().iter_mut(Size::ZERO, size) { - assert!(stack.borrows.len() == 1 && stack.frozen_since.is_none()); - assert_eq!(stack.borrows.pop().unwrap(), BorStackItem::Mut(Mut::Raw)); - stack.borrows.push(BorStackItem::Mut(mut_borrow)); + assert!(stack.borrows.len() == 1); + assert_eq!(stack.borrows.pop().unwrap(), BorStackItem::Shr); + stack.borrows.push(itm); } } } + + pub trait EvalContextExt<'tcx> { fn tag_reference( &mut self, - ptr: Pointer, - pointee_ty: Ty<'tcx>, + place: MPlaceTy<'tcx, Borrow>, size: Size, usage: UsageKind, ) -> EvalResult<'tcx, Borrow>; - fn tag_dereference( &self, - ptr: Pointer, - pointee_ty: Ty<'tcx>, + place: MPlaceTy<'tcx, Borrow>, size: Size, usage: UsageKind, ) -> EvalResult<'tcx, Borrow>; @@ -385,40 +419,36 @@ pub trait EvalContextExt<'tcx> { ) -> EvalResult<'tcx>; } -impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { +impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { /// Called for place-to-value conversion. fn tag_reference( &mut self, - ptr: Pointer, - pointee_ty: Ty<'tcx>, + place: MPlaceTy<'tcx, Borrow>, size: Size, usage: UsageKind, ) -> EvalResult<'tcx, Borrow> { + let ptr = place.ptr.to_ptr()?; let time = self.machine.stacked_borrows.increment_clock(); let new_bor = match usage { - UsageKind::Write => Borrow::Mut(Mut::Uniq(time)), - UsageKind::Read => - // FIXME This does not do enough checking when only part of the data has - // interior mutability. When the type is `(i32, Cell)`, we want the - // first field to be frozen but not the second. - if self.type_is_freeze(pointee_ty) { - Borrow::Frz(time) - } else { - // Shared reference with interior mutability. - Borrow::Mut(Mut::Raw) - }, - UsageKind::Raw => Borrow::Mut(Mut::Raw), + UsageKind::Write => Borrow::Uniq(time), + UsageKind::Read => Borrow::Shr(Some(time)), + UsageKind::Raw => Borrow::Shr(None), }; - trace!("tag_reference: Creating new reference ({:?}) for {:?} (pointee {}, size {}): {:?}", - usage, ptr, pointee_ty, size.bytes(), new_bor); + trace!("tag_reference: Creating new reference ({:?}) for {:?} (pointee {}): {:?}", + usage, ptr, place.layout.ty, new_bor); - // Make sure this reference is not dangling or so + // Update the stacks. First create the new ref as usual, then maybe freeze stuff. self.memory().check_bounds(ptr, size, false)?; - - // Update the stacks. We cannot use `get_mut` becuse this might be immutable - // memory. let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); alloc.extra.use_and_maybe_re_borrow(ptr, size, usage, Some(new_bor))?; + // Maybe freeze stuff + if let Borrow::Shr(Some(bor_t)) = new_bor { + self.visit_frozen(place, size, |frz_ptr, size| { + debug_assert_eq!(frz_ptr.alloc_id, ptr.alloc_id); + // Be frozen! + alloc.extra.freeze(frz_ptr, size, bor_t) + })?; + } Ok(new_bor) } @@ -429,13 +459,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' /// We could be in the middle of `&(*var).1`. fn tag_dereference( &self, - ptr: Pointer, - pointee_ty: Ty<'tcx>, + place: MPlaceTy<'tcx, Borrow>, size: Size, usage: UsageKind, ) -> EvalResult<'tcx, Borrow> { - trace!("tag_reference: Accessing reference ({:?}) for {:?} (pointee {}, size {})", - usage, ptr, pointee_ty, size.bytes()); + let ptr = place.ptr.to_ptr()?; + trace!("tag_dereference: Accessing reference ({:?}) for {:?} (pointee {})", + usage, ptr, place.layout.ty); // In principle we should not have to do anything here. However, with transmutes involved, // it can happen that the tag of `ptr` does not actually match `usage`, and we // should adjust for that. @@ -446,27 +476,24 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Don't use the tag, this is a raw access! Even if there is a tag, // that means transmute happened and we ignore the tag. // Also don't do any further validation, this is raw after all. - return Ok(Borrow::Mut(Mut::Raw)); + return Ok(Borrow::default()); } - (UsageKind::Write, Borrow::Mut(Mut::Uniq(_))) | - (UsageKind::Read, Borrow::Frz(_)) | - (UsageKind::Read, Borrow::Mut(Mut::Raw)) => { + (UsageKind::Write, Borrow::Uniq(_)) | + (UsageKind::Read, Borrow::Shr(_)) => { // Expected combinations. Nothing to do. - // FIXME: We probably shouldn't accept this if we got a raw shr without - // interior mutability. } - (UsageKind::Write, Borrow::Mut(Mut::Raw)) => { + (UsageKind::Write, Borrow::Shr(None)) => { // Raw transmuted to mut ref. Keep this as raw access. // We cannot reborrow here; there might be a raw in `&(*var).1` where // `var` is an `&mut`. The other field of the struct might be already frozen, // also using `var`, and that would be okay. } - (UsageKind::Read, Borrow::Mut(Mut::Uniq(_))) => { + (UsageKind::Read, Borrow::Uniq(_)) => { // A mut got transmuted to shr. Can happen even from compiler transformations: // `&*x` gets optimized to `x` even when `x` is a `&mut`. } - (UsageKind::Write, Borrow::Frz(_)) => { - // This is just invalid. + (UsageKind::Write, Borrow::Shr(Some(_))) => { + // This is just invalid: A shr got transmuted to a mut. // If we ever allow this, we have to consider what we do when a turn a // `Raw`-tagged `&mut` into a raw pointer pointing to a frozen location. // We probably do not want to allow that, but we have to allow @@ -474,23 +501,21 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' return err!(MachineError(format!("Encountered mutable reference with frozen tag {:?}", ptr.tag))) } } - // Even if we don't touch the tag, this operation is only okay if we *could* - // activate it. Also it must not be dangling. + + // If we got here, we do some checking, *but* we leave the tag unchanged. self.memory().check_bounds(ptr, size, false)?; let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); - let mut stacks = alloc.extra.stacks.borrow_mut(); - // We need `iter_mut` because `iter` would skip gaps! - for stack in stacks.iter_mut(ptr.offset, size) { - // Conservatively assume that we will only read. - if let Err(err) = stack.reactivatable(ptr.tag, UsageKind::Read) { - return err!(MachineError(format!( - "Encountered {} reference with non-reactivatable tag: {}", - if usage == UsageKind::Write { "mutable" } else { "shared" }, - err - ))) - } + alloc.extra.check_deref(ptr, size)?; + // Maybe check frozen stuff + if let Borrow::Shr(Some(bor_t)) = ptr.tag { + self.visit_frozen(place, size, |frz_ptr, size| { + debug_assert_eq!(frz_ptr.alloc_id, ptr.alloc_id); + // Are you frozen? + alloc.extra.check_frozen(frz_ptr, size, bor_t) + })?; } - // All is good. + + // All is good, and do not change the tag Ok(ptr.tag) } @@ -499,7 +524,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' id: AllocId, kind: MemoryKind, ) -> Borrow { - let mut_borrow = match kind { + let time = match kind { MemoryKind::Stack => { // New unique borrow. This `Uniq` is not accessible by the program, // so it will only ever be used when using the local directly (i.e., @@ -509,19 +534,18 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // `reset` which the blog post [1] says to perform when accessing a local. // // [1] https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html - let time = self.machine.stacked_borrows.increment_clock(); - Mut::Uniq(time) + self.machine.stacked_borrows.increment_clock() } _ => { - // Raw for everything else - Mut::Raw + // Nothing to do for everything else + return Borrow::default() } }; // Make this the active borrow for this allocation let alloc = self.memory_mut().get_mut(id).expect("This is a new allocation, it must still exist"); let size = Size::from_bytes(alloc.bytes.len() as u64); - alloc.extra.first_borrow(mut_borrow, size); - Borrow::Mut(mut_borrow) + alloc.extra.first_item(BorStackItem::Uniq(time), size); + Borrow::Uniq(time) } fn retag( diff --git a/src/tls.rs b/src/tls.rs index 1aacc67f5cca..af1d7b138b85 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -133,7 +133,7 @@ impl<'tcx> TlsData<'tcx> { } } -impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { +impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { fn run_tls_dtors(&mut self) -> EvalResult<'tcx> { let mut dtor = self.machine.tls.fetch_tls_dtor(None, &*self.tcx); // FIXME: replace loop by some structure that works with stepping diff --git a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs index 2c48404ddf36..4857ada7fb2c 100644 --- a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs +++ b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs @@ -14,6 +14,6 @@ fn main() { let v = vec![0,1,2]; let v1 = safe::as_mut_slice(&v); let v2 = safe::as_mut_slice(&v); - v1[1] = 5; //~ ERROR reference with non-reactivatable tag + v1[1] = 5; //~ ERROR does not exist on the stack v1[1] = 6; } diff --git a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs index d8a241cab5d4..a6daa5d93d77 100644 --- a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs @@ -11,7 +11,7 @@ mod safe { assert!(mid <= len); (from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" - //~^ ERROR reference with non-reactivatable tag + //~^ ERROR does not exist on the stack from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) } } diff --git a/tests/compile-fail/stacked_borrows/illegal_read1.rs b/tests/compile-fail/stacked_borrows/illegal_read1.rs index 59190a15db44..dbaccae88272 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read1.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read1.rs @@ -7,7 +7,7 @@ fn main() { let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. - //~^ ERROR: mutable reference with non-reactivatable tag + //~^ ERROR: does not exist on the stack } fn callee(xraw: *mut i32) { diff --git a/tests/compile-fail/stacked_borrows/illegal_read2.rs b/tests/compile-fail/stacked_borrows/illegal_read2.rs index 594117d28ab8..2da755d9aabc 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read2.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read2.rs @@ -7,7 +7,7 @@ fn main() { let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. - //~^ ERROR: mutable reference with non-reactivatable tag + //~^ ERROR: does not exist on the stack } fn callee(xraw: *mut i32) { diff --git a/tests/compile-fail/stacked_borrows/illegal_write1.rs b/tests/compile-fail/stacked_borrows/illegal_write1.rs index ab951be5ec91..7378907fa745 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write1.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write1.rs @@ -8,5 +8,5 @@ fn main() { let target = Box::new(42); // has an implicit raw let ref_ = &*target; evil(ref_); // invalidates shared ref, activates raw - let _x = *ref_; //~ ERROR reference with non-reactivatable tag + let _x = *ref_; //~ ERROR is not frozen long enough } diff --git a/tests/compile-fail/stacked_borrows/illegal_write3.rs b/tests/compile-fail/stacked_borrows/illegal_write3.rs index a653aa5003f6..c82da1e9c467 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write3.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write3.rs @@ -3,6 +3,6 @@ fn main() { // Make sure raw ptr with raw tag cannot mutate frozen location without breaking the shared ref. let r#ref = ⌖ // freeze let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag - unsafe { *ptr = 42; } //~ ERROR does not exist on the stack - let _val = *r#ref; + unsafe { *ptr = 42; } + let _val = *r#ref; //~ ERROR is not frozen long enough } diff --git a/tests/compile-fail/stacked_borrows/illegal_write4.rs b/tests/compile-fail/stacked_borrows/illegal_write4.rs index 12deb518b4e7..49bf9279faa2 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write4.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write4.rs @@ -9,5 +9,5 @@ fn main() { let ptr = reference as *const _ as *mut i32; // raw ptr, with raw tag let _mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag // Now we retag, making our ref top-of-stack -- and, in particular, unfreezing. - let _val = *reference; //~ ERROR Location should be frozen + let _val = *reference; //~ ERROR is not frozen long enough } diff --git a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs index 4ea61cd606ff..d3db462343e8 100644 --- a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs @@ -5,5 +5,5 @@ fn main() { let xref = unsafe { &mut *xraw }; let xref_in_mem = Box::new(xref); let _val = *x; // invalidate xraw - let _val = *xref_in_mem; //~ ERROR mutable reference with non-reactivatable tag + let _val = *xref_in_mem; //~ ERROR does not exist on the stack } diff --git a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs index 53179c954dea..71b578817a77 100644 --- a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs @@ -5,5 +5,5 @@ fn main() { let xref = unsafe { &*xraw }; let xref_in_mem = Box::new(xref); *x = 42; // invalidate xraw - let _val = *xref_in_mem; //~ ERROR shared reference with non-reactivatable tag: Location should be frozen + let _val = *xref_in_mem; //~ ERROR does not exist on the stack } diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs index 5e1118160a32..41cf89d874d7 100644 --- a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs @@ -6,5 +6,5 @@ fn main() { let xraw = x as *mut _; let xref = unsafe { &mut *xraw }; let _val = *x; // invalidate xraw - foo(xref); //~ ERROR mutable reference with non-reactivatable tag + foo(xref); //~ ERROR does not exist on the stack } diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs b/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs index e4b26cfff6da..0bdb1b4a41e5 100644 --- a/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs @@ -6,5 +6,5 @@ fn main() { let xraw = &*x as *const _; let xref = unsafe { &*xraw }; *x = 42; // invalidate xraw - foo(xref); //~ ERROR shared reference with non-reactivatable tag: Location should be frozen + foo(xref); //~ ERROR does not exist on the stack } diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs index 949b3829ff8f..aef8fafdf5d5 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> &mut i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &mut (*xraw).1 }; let _val = *x; // invalidate xraw and its children - ret //~ ERROR mutable reference with non-reactivatable tag + ret //~ ERROR does not exist on the stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr.rs b/tests/compile-fail/stacked_borrows/return_invalid_shr.rs index 2d34350359d1..074942eb95bc 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_shr.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> &i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &(*xraw).1 }; x.1 = 42; // invalidate xraw on the 2nd field - ret //~ ERROR shared reference with non-reactivatable tag: Location should be frozen + ret //~ ERROR does not exist on the stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/shared_confusion.rs b/tests/compile-fail/stacked_borrows/shared_confusion.rs deleted file mode 100644 index 624587932cb8..000000000000 --- a/tests/compile-fail/stacked_borrows/shared_confusion.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Optimization kills all the reborrows, enough to make this error go away. There are -// no retags either because we don't retag immediately after a `&[mut]`; we rely on -// that creating a fresh reference. -// See `shared_confusion_opt.rs` for a variant that is caught even with optimizations. -// Keep this test to make sure that without optimizations, we do not have to actually -// use the `x_inner_shr`. -// compile-flags: -Zmir-opt-level=0 - -#![allow(unused_variables)] -use std::cell::RefCell; - -fn test(r: &mut RefCell) { - let x = &*r; // not freezing because interior mutability - let mut x_ref = x.borrow_mut(); - let x_inner : &mut i32 = &mut *x_ref; // Uniq reference - let x_evil = x_inner as *mut _; - { - let x_inner_shr = &*x_inner; // frozen - let y = &*r; // outer ref, not freezing - let x_inner_shr = &*x_inner; // freezing again - } - // Our old raw should be dead by now - unsafe { *x_evil = 0; } // this falls back to some Raw higher up the stack - *x_inner = 12; //~ ERROR reference with non-reactivatable tag -} - -fn main() { - test(&mut RefCell::new(0)); -} diff --git a/tests/compile-fail/stacked_borrows/shared_confusion_opt.rs b/tests/compile-fail/stacked_borrows/shared_confusion_opt.rs deleted file mode 100644 index 3030f5dd4001..000000000000 --- a/tests/compile-fail/stacked_borrows/shared_confusion_opt.rs +++ /dev/null @@ -1,25 +0,0 @@ -// A variant of `shared_confusion.rs` that gets flagged even with optimizations. - -#![allow(unused_variables)] -use std::cell::RefCell; - -fn test(r: &mut RefCell) { - let x = &*r; // not freezing because interior mutability - let mut x_ref = x.borrow_mut(); - let x_inner : &mut i32 = &mut *x_ref; // Uniq reference - let x_evil = x_inner as *mut _; - { - let x_inner_shr = &*x_inner; // frozen - let _val = *x_inner_shr; - let y = &*r; // outer ref, not freezing - let x_inner_shr = &*x_inner; // freezing again - let _val = *x_inner_shr; - } - // Our old raw should be dead by now - unsafe { *x_evil = 0; } // this falls back to some Raw higher up the stack - *x_inner = 12; //~ ERROR reference with non-reactivatable tag -} - -fn main() { - test(&mut RefCell::new(0)); -} diff --git a/tests/compile-fail/validity/invalid_enum_discriminant.rs b/tests/compile-fail/validity/invalid_enum_discriminant.rs index 543a797d44f2..13be4e7dcea8 100644 --- a/tests/compile-fail/validity/invalid_enum_discriminant.rs +++ b/tests/compile-fail/validity/invalid_enum_discriminant.rs @@ -4,5 +4,5 @@ pub enum Foo { } fn main() { - let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR encountered invalid enum discriminant 42 + let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR encountered 42, but expected a valid enum discriminant } diff --git a/tests/compile-fail/validity/transmute_through_ptr.rs b/tests/compile-fail/validity/transmute_through_ptr.rs index 0a4c64bb9bb1..d6bc0305e69d 100644 --- a/tests/compile-fail/validity/transmute_through_ptr.rs +++ b/tests/compile-fail/validity/transmute_through_ptr.rs @@ -12,5 +12,5 @@ fn main() { let mut x = Bool::True; evil(&mut x); let _y = x; // reading this ought to be enough to trigger validation - //~^ ERROR invalid enum discriminant 44 + //~^ ERROR encountered 44, but expected a valid enum discriminant } diff --git a/tests/run-pass-fullmir/send-is-not-static-par-for.rs b/tests/run-pass-fullmir/send-is-not-static-par-for.rs index 282f7a359503..1b913aed4c89 100644 --- a/tests/run-pass-fullmir/send-is-not-static-par-for.rs +++ b/tests/run-pass-fullmir/send-is-not-static-par-for.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME: Still investigating whether there is UB here -// compile-flags: -Zmiri-disable-validation - use std::sync::Mutex; fn par_for(iter: I, f: F) diff --git a/tests/run-pass-fullmir/u128.rs b/tests/run-pass-fullmir/u128.rs index 0f1b6e8b5870..ca33bd5f9e3d 100644 --- a/tests/run-pass-fullmir/u128.rs +++ b/tests/run-pass-fullmir/u128.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME: Still investigating whether there is UB here -// compile-flags: -Zmiri-disable-validation - fn b(t: T) -> T { t } fn main() { diff --git a/tests/run-pass-fullmir/vecdeque.rs b/tests/run-pass-fullmir/vecdeque.rs index ffbb11668498..381169505ec9 100644 --- a/tests/run-pass-fullmir/vecdeque.rs +++ b/tests/run-pass-fullmir/vecdeque.rs @@ -1,6 +1,3 @@ -// FIXME: Still investigating whether there is UB here -// compile-flags: -Zmiri-disable-validation - use std::collections::VecDeque; fn main() { diff --git a/tests/run-pass/slices.rs b/tests/run-pass/slices.rs index 119c9b90a05c..45a2a74db08d 100644 --- a/tests/run-pass/slices.rs +++ b/tests/run-pass/slices.rs @@ -1,6 +1,3 @@ -// FIXME: Still investigating whether there is UB here -// compile-flags: -Zmiri-disable-validation - use std::slice; fn slice_of_zst() { diff --git a/tests/run-pass/stacked-borrows.rs b/tests/run-pass/stacked-borrows.rs index cde6968a2641..8faa4d659115 100644 --- a/tests/run-pass/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows.rs @@ -1,7 +1,8 @@ // Test various stacked-borrows-related things. fn main() { deref_partially_dangling_raw(); - read_does_not_invalidate(); + read_does_not_invalidate1(); + read_does_not_invalidate2(); } // Deref a raw ptr to access a field of a large struct, where the field @@ -15,13 +16,23 @@ fn deref_partially_dangling_raw() { // Make sure that reading from an `&mut` does, like reborrowing to `&`, // NOT invalidate other reborrows. -fn read_does_not_invalidate() { +fn read_does_not_invalidate1() { fn foo(x: &mut (i32, i32)) -> &i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &(*xraw).1 }; let _val = x.1; // we just read, this does NOT invalidate the reborrows. ret } - + foo(&mut (1, 2)); +} +// Same as above, but this time we first create a raw, then read from `&mut` +// and then freeze from the raw. +fn read_does_not_invalidate2() { + fn foo(x: &mut (i32, i32)) -> &i32 { + let xraw = x as *mut (i32, i32); + let _val = x.1; // we just read, this does NOT invalidate the raw reborrow. + let ret = unsafe { &(*xraw).1 }; + ret + } foo(&mut (1, 2)); } From 00936316d18b3c1cfa7924f119bbe6061c8cb9f6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Nov 2018 16:23:22 +0100 Subject: [PATCH 0342/5092] treat shared and raw borrows alike --- src/stacked_borrows.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 1ab6edcf398c..e1abcb20af75 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -139,13 +139,13 @@ pub struct Stacks { /// Core operations impl<'tcx> Stack { /// Check if `bor` could be activated by unfreezing and popping. - /// `usage` indicates whether this is being used to read/write (or, equivalently, to - /// borrow as &/&mut), or to borrow as raw. + /// `is_write` indicates whether this is being used to write (or, equivalently, to + /// borrow as &mut). /// Returns `Err` if the answer is "no"; otherwise the return value indicates what to /// do: With `Some(n)` you need to unfreeze, and then additionally pop `n` items. - fn reactivatable(&self, bor: Borrow, usage: UsageKind) -> Result, String> { + fn reactivatable(&self, bor: Borrow, is_write: bool) -> Result, String> { // Check if we can match the frozen "item". Not possible on writes! - if usage != UsageKind::Write { + if !is_write { // For now, we do NOT check the timestamp. That might be surprising, but // we cannot even notice when a location should be frozen but is not! // Those checks are both done in `tag_dereference`, where we have type information. @@ -168,11 +168,11 @@ impl<'tcx> Stack { } (BorStackItem::Uniq(itm_t), Borrow::Uniq(bor_t)) if itm_t == bor_t => { // Found matching unique item. - if usage == UsageKind::Read { + if !is_write { // As a special case, if we are reading and since we *did* find the `Uniq`, // we try to pop less: We are happy with making a `Shr` or `Frz` active; // that one will not mind concurrent reads. - match self.reactivatable(Borrow::default(), usage) { + match self.reactivatable(Borrow::default(), is_write) { // If we got something better that `idx`, use that Ok(None) => return Ok(None), Ok(Some(shr_idx)) if shr_idx <= idx => return Ok(Some(shr_idx)), @@ -194,10 +194,10 @@ impl<'tcx> Stack { Err(format!("Borrow-to-reactivate {:?} does not exist on the stack", bor)) } - /// Reactive `bor` for this stack. `usage` indicates whether this is being - /// used to read/write (or, equivalently, to borrow as &/&mut), or to borrow as raw. - fn reactivate(&mut self, bor: Borrow, usage: UsageKind) -> EvalResult<'tcx> { - let mut pop = match self.reactivatable(bor, usage) { + /// Reactive `bor` for this stack. `is_write` indicates whether this is being + /// used to write (or, equivalently, to borrow as &mut). + fn reactivate(&mut self, bor: Borrow, is_write: bool) -> EvalResult<'tcx> { + let mut pop = match self.reactivatable(bor, is_write) { Ok(None) => return Ok(()), Ok(Some(pop)) => pop, Err(err) => return err!(MachineError(err)), @@ -272,7 +272,7 @@ impl State { /// Higher-level operations impl<'tcx> Stacks { - /// The single most important operation: Make sure that using `ptr` as `usage` is okay, + /// The single most important operation: Make sure that using `ptr` is okay, /// and if `new_bor` is present then make that the new current borrow. fn use_and_maybe_re_borrow( &self, @@ -285,7 +285,7 @@ impl<'tcx> Stacks { ptr.tag, usage, new_bor, ptr, size.bytes()); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { - stack.reactivate(ptr.tag, usage)?; + stack.reactivate(ptr.tag, usage == UsageKind::Write)?; if let Some(new_bor) = new_bor { stack.initiate(new_bor); } @@ -317,7 +317,7 @@ impl<'tcx> Stacks { // We need `iter_mut` because `iter` would skip gaps! for stack in stacks.iter_mut(ptr.offset, size) { // Conservatively assume we will just read - if let Err(err) = stack.reactivatable(ptr.tag, UsageKind::Read) { + if let Err(err) = stack.reactivatable(ptr.tag, /*is_write*/false) { return err!(MachineError(format!( "Encountered reference with non-reactivatable tag: {}", err From f4e45ff2b7fc60152ba5bbc595c4ba602dfe7680 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 6 Nov 2018 17:46:54 +0100 Subject: [PATCH 0343/5092] sort the fields ourselves --- src/helpers.rs | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 52d3db8ac46f..880b18c7d542 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,6 +1,6 @@ use std::mem; -use rustc::ty; +use rustc::ty::{self, layout}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use crate::*; @@ -124,8 +124,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let (unsafe_cell_size, _) = self.size_and_align_of_mplace(place)? // for extern types, just cover what we can .unwrap_or_else(|| place.layout.size_and_align()); - // Now handle this `UnsafeCell`. - unsafe_cell_action(place.ptr.get_ptr_offset(self), unsafe_cell_size) + // Now handle this `UnsafeCell`, unless it is empty. + if unsafe_cell_size != Size::ZERO { + unsafe_cell_action(place.ptr.get_ptr_offset(self), unsafe_cell_size) + } else { + Ok(()) + } }, }; visitor.visit_value(place)?; @@ -152,8 +156,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: { type V = MPlaceTy<'tcx, Borrow>; - const WANT_FIELDS_SORTED: bool = true; // sorted? yes please! - #[inline(always)] fn ecx(&self) -> &MiriEvalContext<'a, 'mir, 'tcx> { &self.ecx @@ -179,6 +181,31 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } } + // Make sure we visit aggregrates in increasing offset order + fn visit_aggregate( + &mut self, + place: MPlaceTy<'tcx, Borrow>, + fields: impl Iterator>>, + ) -> EvalResult<'tcx> { + match place.layout.fields { + layout::FieldPlacement::Array { .. } => { + // For the array layout, we know the iterator will yield sorted elements so + // we can avoid the allocation. + self.walk_aggregate(place, fields) + } + layout::FieldPlacement::Arbitrary { .. } => { + // Gather the subplaces and sort them before visiting. + let mut places = fields.collect::>>>()?; + places[..].sort_by_key(|place| place.ptr.get_ptr_offset(self.ecx())); + self.walk_aggregate(place, places.into_iter().map(Ok)) + } + layout::FieldPlacement::Union { .. } => { + // Uh, what? + bug!("A union is not an aggregate we should ever visit") + } + } + } + // We have to do *something* for unions fn visit_union(&mut self, v: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> { From d694dc43f4e4c459f908b8ded939fa1fc359ad9a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 8 Nov 2018 08:29:55 +0100 Subject: [PATCH 0344/5092] bump Rust version --- rust-version | 2 +- tests/compile-fail/validity/invalid_bool.rs | 2 +- tests/compile-fail/validity/invalid_char.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 48887947cdf7..0ad815872411 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-07 +nightly-2018-11-08 diff --git a/tests/compile-fail/validity/invalid_bool.rs b/tests/compile-fail/validity/invalid_bool.rs index af4ad67a4f09..ce464616195d 100644 --- a/tests/compile-fail/validity/invalid_bool.rs +++ b/tests/compile-fail/validity/invalid_bool.rs @@ -1,3 +1,3 @@ fn main() { - let _b = unsafe { std::mem::transmute::(2) }; //~ ERROR encountered 2, but expected something in the range 0..=1 + let _b = unsafe { std::mem::transmute::(2) }; //~ ERROR encountered 2, but expected something less or equal to 1 } diff --git a/tests/compile-fail/validity/invalid_char.rs b/tests/compile-fail/validity/invalid_char.rs index 3ff0ed60f664..0d75ad9d2890 100644 --- a/tests/compile-fail/validity/invalid_char.rs +++ b/tests/compile-fail/validity/invalid_char.rs @@ -1,6 +1,6 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); - let _ = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered 4294967295, but expected something in the range 0..=1114111 + let _ = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered 4294967295, but expected something less or equal to 1114111 'a' => {true}, 'b' => {false}, _ => {true}, From 45e14f8dc59310c8d647f7c76736650dfc8a3fb5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Nov 2018 11:48:10 +0100 Subject: [PATCH 0345/5092] use custom test runner so that we can get proper test filtering --- README.md | 25 +++++++++++++----- tests/compiletest.rs | 61 +++++++++++++++++++------------------------- 2 files changed, 44 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index a905c2aeffb7..94b5f8fea79d 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ undergraduate research course at the [University of Saskatchewan][usask]. ## Building Miri -I recommend that you install [rustup][rustup] to obtain Rust. Then all you have +We recommend that you install [rustup][rustup] to obtain Rust. Then all you have to do is: ```sh @@ -117,11 +117,12 @@ Miri will often require using a locally built rustc. This includes getting a trace of the execution, as distributed rustc has `debug!` and `trace!` disabled. The first-time setup for a local rustc looks as follows: -``` +```sh git clone https://github.com/rust-lang/rust/ rustc cd rustc cp config.toml.example config.toml -# Now edit `config.toml` and set `debug-assertions = true` +# Now edit `config.toml` and set `debug-assertions = true` and `test-miri = true`. +# The latter is important to build libstd with the right flags for miri. ./x.py build src/rustc # You may have to change the architecture in the next command rustup toolchain link custom build/x86_64-unknown-linux-gnu/stage2 @@ -130,9 +131,20 @@ rustup override set custom ``` The `build` step can take 30 minutes and more. -Now you can `cargo build` Miri, and you can `cargo test` it. But the key point -is, you can now run Miri with a trace of all execution steps: +Now you can `cargo build` Miri, and you can `cargo test --release` it. `cargo +test --release FILTER` only runs those tests that contain `FILTER` in their +filename (including the base directory, e.g. `cargo test --release fail` will +run all compile-fail tests). We recommend using `--release` to make test +running take less time. +Notice that the "fullmir" tests only run if you have `MIRI_SYSROOT` set, the +test runner does not realized that your libstd comes with full MIR. The +following will set it correctly: +```sh +MIRI_SYSROOT=$(rustc --print sysroot) cargo test --release +``` + +Moreover, you can now run Miri with a trace of all execution steps: ```sh MIRI_LOG=debug cargo run tests/run-pass/vecs.rs ``` @@ -141,9 +153,8 @@ Setting `MIRI_LOG` like this will configure logging for miri itself as well as the `rustc::mir::interpret` and `rustc_mir::interpret` modules in rustc. You can also do more targeted configuration, e.g. to debug the stacked borrows implementation: - ```sh -MIRI_LOG=miri::stacked_borrows=trace,rustc_mir::interpret=debug cargo run tests/run-pass/vecs.rs +MIRI_LOG=rustc_mir::interpret=debug,miri::stacked_borrows cargo run tests/run-pass/vecs.rs ``` In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 98e3fde54e69..5771478cb557 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -1,20 +1,13 @@ -#![feature(slice_concat_ext)] - -extern crate compiletest_rs as compiletest; -extern crate colored; - -use colored::*; +#![feature(slice_concat_ext, custom_test_frameworks)] +#![test_runner(test_runner)] use std::slice::SliceConcatExt; use std::path::{PathBuf, Path}; use std::io::Write; +use std::env; -macro_rules! eprintln { - ($($arg:tt)*) => { - let stderr = std::io::stderr(); - writeln!(stderr.lock(), $($arg)*).unwrap(); - } -} +use compiletest_rs as compiletest; +use colored::*; fn miri_path() -> PathBuf { if rustc_test_suite().is_some() { @@ -37,9 +30,21 @@ fn have_fullmir() -> bool { std::env::var("MIRI_SYSROOT").is_ok() || rustc_test_suite().is_some() } +fn mk_config(mode: &str) -> compiletest::Config { + let mut config = compiletest::Config::default(); + config.mode = mode.parse().expect("Invalid mode"); + config.rustc_path = miri_path(); + if rustc_test_suite().is_some() { + config.run_lib_path = rustc_lib_path(); + config.compile_lib_path = rustc_lib_path(); + } + config.filter = env::args().nth(1); + config +} + fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: bool, opt: bool) { if need_fullmir && !have_fullmir() { - eprintln!("{}", format!( + eprintln!("{}\n", format!( "## Skipping compile-fail tests in {} against miri for target {} due to missing mir", path, target @@ -65,23 +70,17 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullm flags.push("-Zmir-opt-level=1".to_owned()); } - let mut config = compiletest::Config::default().tempdir(); - config.mode = "compile-fail".parse().expect("Invalid mode"); - config.rustc_path = miri_path(); - if rustc_test_suite().is_some() { - config.run_lib_path = rustc_lib_path(); - config.compile_lib_path = rustc_lib_path(); - } - config.src_base = PathBuf::from(path.to_string()); - config.target_rustcflags = Some(flags.join(" ")); + let mut config = mk_config("compile-fail"); + config.src_base = PathBuf::from(path); config.target = target.to_owned(); config.host = host.to_owned(); - compiletest::run_tests(&config); + config.target_rustcflags = Some(flags.join(" ")); + compiletest::run_tests(&config.tempdir()); // FIXME: `tempdir` can be done by `mk_config` once `ConfigWithTemp` is exposed as type from compiletest } fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: bool, opt: bool) { if need_fullmir && !have_fullmir() { - eprintln!("{}", format!( + eprintln!("{}\n", format!( "## Skipping run-pass tests in {} against miri for target {} due to missing mir", path, target @@ -104,18 +103,12 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: flags.push("-Zmir-opt-level=3".to_owned()); } - let mut config = compiletest::Config::default().tempdir(); - config.mode = "ui".parse().expect("Invalid mode"); + let mut config = mk_config("ui"); config.src_base = PathBuf::from(path); config.target = target.to_owned(); config.host = host.to_owned(); - config.rustc_path = miri_path(); - if rustc_test_suite().is_some() { - config.run_lib_path = rustc_lib_path(); - config.compile_lib_path = rustc_lib_path(); - } config.target_rustcflags = Some(flags.join(" ")); - compiletest::run_tests(&config); + compiletest::run_tests(&config.tempdir()); // FIXME: `tempdir` can be done by `mk_config` once `ConfigWithTemp` is exposed as type from compiletest } fn is_target_dir>(path: P) -> bool { @@ -151,7 +144,6 @@ fn get_sysroot() -> PathBuf { fn get_host() -> String { let rustc = rustc_test_suite().unwrap_or(PathBuf::from("rustc")); - println!("using rustc at {}", rustc.display()); let host = std::process::Command::new(rustc) .arg("-vV") .output() @@ -184,8 +176,7 @@ fn compile_fail_miri(opt: bool) { compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true, opt); } -#[test] -fn test() { +fn test_runner(_tests: &[&()]) { // We put everything into a single test to avoid the parallelism `cargo test` // introduces. We still get parallelism within our tests because `compiletest` // uses `libtest` which runs jobs in parallel. From 97302e86c29cea97863cb1c977366c696d681755 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Nov 2018 11:51:39 +0100 Subject: [PATCH 0346/5092] remove unused import --- tests/compiletest.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 5771478cb557..7644ab1dd723 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -3,7 +3,6 @@ use std::slice::SliceConcatExt; use std::path::{PathBuf, Path}; -use std::io::Write; use std::env; use compiletest_rs as compiletest; From 54307cd88847e099b021cad788b51013d1453820 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Nov 2018 14:04:22 +0100 Subject: [PATCH 0347/5092] bump compiletest so that we can share the tempdir() call --- Cargo.toml | 2 +- tests/compiletest.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 390efe0a073a..94d13a83fafd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,5 +46,5 @@ cargo_miri = ["cargo_metadata"] rustc_tests = [] [dev-dependencies] -compiletest_rs = { version = "0.3.16", features = ["tmp"] } +compiletest_rs = { version = "0.3.17", features = ["tmp"] } colored = "1.6" diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 7644ab1dd723..55eaa7bfbab6 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -29,8 +29,8 @@ fn have_fullmir() -> bool { std::env::var("MIRI_SYSROOT").is_ok() || rustc_test_suite().is_some() } -fn mk_config(mode: &str) -> compiletest::Config { - let mut config = compiletest::Config::default(); +fn mk_config(mode: &str) -> compiletest::common::ConfigWithTemp { + let mut config = compiletest::Config::default().tempdir(); config.mode = mode.parse().expect("Invalid mode"); config.rustc_path = miri_path(); if rustc_test_suite().is_some() { @@ -74,7 +74,7 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullm config.target = target.to_owned(); config.host = host.to_owned(); config.target_rustcflags = Some(flags.join(" ")); - compiletest::run_tests(&config.tempdir()); // FIXME: `tempdir` can be done by `mk_config` once `ConfigWithTemp` is exposed as type from compiletest + compiletest::run_tests(&config); } fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: bool, opt: bool) { @@ -107,7 +107,7 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: config.target = target.to_owned(); config.host = host.to_owned(); config.target_rustcflags = Some(flags.join(" ")); - compiletest::run_tests(&config.tempdir()); // FIXME: `tempdir` can be done by `mk_config` once `ConfigWithTemp` is exposed as type from compiletest + compiletest::run_tests(&config); } fn is_target_dir>(path: P) -> bool { From f233dc0687143025d375fbc3d3ea64f17ecd7d99 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 11 Nov 2018 10:12:44 +0100 Subject: [PATCH 0348/5092] Rc should be fixed --- tests/run-pass/rc.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index f4a8855bea2f..0bf707503112 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -1,6 +1,3 @@ -// FIXME: Disabled due to https://github.com/rust-lang/rust/issues/55747 -// ignore-test - use std::cell::RefCell; use std::rc::Rc; From e7aa5c68ffc221ee07d37ee1d29b96282729b7fe Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Nov 2018 08:54:12 +0100 Subject: [PATCH 0349/5092] Update rustc for AllocationExtra trait Based on https://github.com/solson/miri/pull/493 but there were more conflicts than code so I opted not to cherry-pick. --- rust-version | 2 +- src/lib.rs | 18 ------------------ src/stacked_borrows.rs | 19 +++++++++++-------- 3 files changed, 12 insertions(+), 27 deletions(-) diff --git a/rust-version b/rust-version index 0ad815872411..fb6d167ec642 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-08 +nightly-2018-11-12 diff --git a/src/lib.rs b/src/lib.rs index 134986c814de..ab34841df89e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -446,24 +446,6 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { Cow::Owned(alloc) } - #[inline(always)] - fn memory_read( - alloc: &Allocation, - ptr: Pointer, - size: Size, - ) -> EvalResult<'tcx> { - alloc.extra.memory_read(ptr, size) - } - - #[inline(always)] - fn memory_written( - alloc: &mut Allocation, - ptr: Pointer, - size: Size, - ) -> EvalResult<'tcx> { - alloc.extra.memory_written(ptr, size) - } - #[inline(always)] fn memory_deallocated( alloc: &mut Allocation, diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index e1abcb20af75..475033d74c66 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -5,7 +5,7 @@ use rustc::hir; use crate::{ EvalResult, MiriEvalContext, HelpersEvalContextExt, - MemoryKind, MiriMemoryKind, RangeMap, AllocId, + MemoryKind, MiriMemoryKind, RangeMap, AllocId, Allocation, AllocationExtra, Pointer, PlaceTy, MPlaceTy, }; @@ -343,27 +343,30 @@ impl<'tcx> Stacks { } /// Hooks and glue -impl<'tcx> Stacks { +impl AllocationExtra for Stacks { #[inline(always)] - pub fn memory_read( - &self, + fn memory_read<'tcx>( + alloc: &Allocation, ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { // Reads behave exactly like the first half of a reborrow-to-shr - self.use_and_maybe_re_borrow(ptr, size, UsageKind::Read, None) + alloc.extra.use_and_maybe_re_borrow(ptr, size, UsageKind::Read, None) } #[inline(always)] - pub fn memory_written( - &mut self, + fn memory_written<'tcx>( + alloc: &mut Allocation, ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { // Writes behave exactly like the first half of a reborrow-to-mut - self.use_and_maybe_re_borrow(ptr, size, UsageKind::Write, None) + alloc.extra.use_and_maybe_re_borrow(ptr, size, UsageKind::Write, None) } +} +impl<'tcx> Stacks { + #[inline(always)] pub fn memory_deallocated( &mut self, ptr: Pointer, From f37fc5eb7a527124dedb29d75e4f85eb0335c44a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Nov 2018 20:20:35 +0100 Subject: [PATCH 0350/5092] cargo miri test currently does not work --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 94b5f8fea79d..3c695fbc676a 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,9 @@ compile your project and its dependencies against that libstd: 1. Run `cargo clean` to eliminate any cached dependencies that were built against the non-MIR `libstd`. 2. To run all tests in your project through, Miri, use -`MIRI_SYSROOT=~/.xargo/HOST cargo +nightly miri test`. +`MIRI_SYSROOT=~/.xargo/HOST cargo +nightly miri test`. **NOTE**: This is +currently broken, see the discussion in +[#479](https://github.com/solson/miri/issues/479). 3. If you have a binary project, you can run it through Miri using `MIRI_SYSROOT=~/.xargo/HOST cargo +nightly miri`. From c81e45f73afaccca991de35e14c8e2ae77b98a9b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 13 Nov 2018 13:28:09 +0100 Subject: [PATCH 0351/5092] add a description of what miri can do for you --- README.md | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 3c695fbc676a..919c31177f58 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,33 @@ # Miri [[slides](https://solson.me/miri-slides.pdf)] [[report](https://solson.me/miri-report.pdf)] [![Build Status](https://travis-ci.org/solson/miri.svg?branch=master)](https://travis-ci.org/solson/miri) [![Windows build status](https://ci.appveyor.com/api/projects/status/github/solson/miri?svg=true)](https://ci.appveyor.com/project/solson63299/miri) -An experimental interpreter for [Rust][rust]'s [mid-level intermediate -representation][mir] (MIR). This project began as part of my work for the -undergraduate research course at the [University of Saskatchewan][usask]. +An experimental interpreter for [Rust][rust]'s +[mid-level intermediate representation][mir] (MIR). It can run binaries and +test suites of cargo projects and detect certain classes of undefined behavior, +for example: + +* Out-of-bounds memory accesses and use-after-free +* Invalid use of uninitialized data +* Violation of intrinsic preconditions (an [`unreachable_unchecked`] being + reached, calling [`copy_nonoverlapping`] with overlapping ranges, ...) +* Not sufficiently aligned memory accesses and references +* Violation of basic type invariants (a `bool` that is not 0 or 1, for example, + or an invalid enum discriminant) +* WIP: Violations of the rules governing aliasing for reference types + +This project began as part of an undergraduate research course at the +[University of Saskatchewan][usask]. + + +[rust]: https://www.rust-lang.org/ +[mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md +[usask]: https://www.usask.ca/ +[`unreachable_unchecked`]: https://doc.rust-lang.org/stable/std/hint/fn.unreachable_unchecked.html +[`copy_nonoverlapping`]: https://doc.rust-lang.org/stable/std/ptr/fn.copy_nonoverlapping.html ## Building Miri -We recommend that you install [rustup][rustup] to obtain Rust. Then all you have +We recommend that you install [rustup] to obtain Rust. Then all you have to do is: ```sh @@ -25,6 +45,8 @@ To avoid repeating the nightly version all the time, you can use which means `nightly` Rust will automatically be used whenever you are working in this directory. +[rustup]: https://www.rustup.rs + ## Running Miri ```sh @@ -188,8 +210,3 @@ Licensed under either of Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be dual licensed as above, without any additional terms or conditions. - -[rust]: https://www.rust-lang.org/ -[mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md -[usask]: https://www.usask.ca/ -[rustup]: https://www.rustup.rs From 8368fe89bc9c9bc15b11050b99408e36c2b7e55e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 13 Nov 2018 14:16:08 +0100 Subject: [PATCH 0352/5092] miri history --- README.md | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 919c31177f58..dece1c8f72fe 100644 --- a/README.md +++ b/README.md @@ -15,13 +15,8 @@ for example: or an invalid enum discriminant) * WIP: Violations of the rules governing aliasing for reference types -This project began as part of an undergraduate research course at the -[University of Saskatchewan][usask]. - - [rust]: https://www.rust-lang.org/ [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md -[usask]: https://www.usask.ca/ [`unreachable_unchecked`]: https://doc.rust-lang.org/stable/std/hint/fn.unreachable_unchecked.html [`copy_nonoverlapping`]: https://doc.rust-lang.org/stable/std/ptr/fn.copy_nonoverlapping.html @@ -197,6 +192,23 @@ needs to be done that I haven't documented in the issues yet, however. For more ideas or help with running or hacking on Miri, you can contact me (`scott`) on Mozilla IRC in any of the Rust IRC channels (`#rust`, `#rust-offtopic`, etc). +## History + +This project began as part of an undergraduate research course in 2015 by +@solson at the [University of Saskatchewan][usask]. In 2016, @oli-obk joined to +prepare miri for eventually being used as const evaluator in the Rust compiler +itself (basically, for `const` and `static` stuff), replacing the old evaluator +that worked directly on the AST. In 2017, @RalfJung did an internship with +Mozilla and began developing miri towards a tool for detecting undefined +behavior, and also using miri as a way to explore the consequences of various +possible definitions for undefined behavior in Rust. @oli-obk's move of the +miri engine into the compiler finally came to completion in early 2018. +Meanwhile, later that year, @RalfJung did a second internship, developing miri +further with support for checking basic type invariants and verifying that +references are used according to their aliasing restrictions. + +[usask]: https://www.usask.ca/ + ## License Licensed under either of From bf3e376049d122ca47d692cca8cff7134a9746f4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 14 Nov 2018 08:23:43 +0100 Subject: [PATCH 0353/5092] move slide and report links to history --- README.md | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index dece1c8f72fe..04a263597c0b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Miri [[slides](https://solson.me/miri-slides.pdf)] [[report](https://solson.me/miri-report.pdf)] [![Build Status](https://travis-ci.org/solson/miri.svg?branch=master)](https://travis-ci.org/solson/miri) [![Windows build status](https://ci.appveyor.com/api/projects/status/github/solson/miri?svg=true)](https://ci.appveyor.com/project/solson63299/miri) +# Miri [![Build Status](https://travis-ci.org/solson/miri.svg?branch=master)](https://travis-ci.org/solson/miri) [![Windows build status](https://ci.appveyor.com/api/projects/status/github/solson/miri?svg=true)](https://ci.appveyor.com/project/solson63299/miri) An experimental interpreter for [Rust][rust]'s @@ -195,19 +195,22 @@ Mozilla IRC in any of the Rust IRC channels (`#rust`, `#rust-offtopic`, etc). ## History This project began as part of an undergraduate research course in 2015 by -@solson at the [University of Saskatchewan][usask]. In 2016, @oli-obk joined to -prepare miri for eventually being used as const evaluator in the Rust compiler -itself (basically, for `const` and `static` stuff), replacing the old evaluator -that worked directly on the AST. In 2017, @RalfJung did an internship with -Mozilla and began developing miri towards a tool for detecting undefined -behavior, and also using miri as a way to explore the consequences of various -possible definitions for undefined behavior in Rust. @oli-obk's move of the -miri engine into the compiler finally came to completion in early 2018. -Meanwhile, later that year, @RalfJung did a second internship, developing miri -further with support for checking basic type invariants and verifying that -references are used according to their aliasing restrictions. +@solson at the [University of Saskatchewan][usask]. There are [slides] and a +[report] available from that project. In 2016, @oli-obk joined to prepare miri +for eventually being used as const evaluator in the Rust compiler itself +(basically, for `const` and `static` stuff), replacing the old evaluator that +worked directly on the AST. In 2017, @RalfJung did an internship with Mozilla +and began developing miri towards a tool for detecting undefined behavior, and +also using miri as a way to explore the consequences of various possible +definitions for undefined behavior in Rust. @oli-obk's move of the miri engine +into the compiler finally came to completion in early 2018. Meanwhile, later +that year, @RalfJung did a second internship, developing miri further with +support for checking basic type invariants and verifying that references are +used according to their aliasing restrictions. [usask]: https://www.usask.ca/ +[slides]: https://solson.me/miri-slides.pdf +[report]: https://solson.me/miri-report.pdf ## License From f5bd85d009536dfb587991e611ab5211f2bb3f10 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 14 Nov 2018 16:03:38 +0100 Subject: [PATCH 0354/5092] update for memory_deallocated moving to AllocExtra --- src/lib.rs | 9 --------- src/stacked_borrows.rs | 10 +++++----- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ab34841df89e..b7deb8ee1160 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -446,15 +446,6 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { Cow::Owned(alloc) } - #[inline(always)] - fn memory_deallocated( - alloc: &mut Allocation, - ptr: Pointer, - size: Size, - ) -> EvalResult<'tcx> { - alloc.extra.memory_deallocated(ptr, size) - } - #[inline(always)] fn tag_reference( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 475033d74c66..c6cd7f5005d2 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -363,20 +363,20 @@ impl AllocationExtra for Stacks { // Writes behave exactly like the first half of a reborrow-to-mut alloc.extra.use_and_maybe_re_borrow(ptr, size, UsageKind::Write, None) } -} -impl<'tcx> Stacks { #[inline(always)] - pub fn memory_deallocated( - &mut self, + fn memory_deallocated<'tcx>( + alloc: &mut Allocation, ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { // This is like mutating - self.use_and_maybe_re_borrow(ptr, size, UsageKind::Write, None) + alloc.extra.use_and_maybe_re_borrow(ptr, size, UsageKind::Write, None) // FIXME: Error out of there are any barriers? } +} +impl<'tcx> Stacks { /// Pushes the first item to the stacks. pub fn first_item( &mut self, From 5120abc0c65540b25a0d69768a462e269fc402a8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 15 Nov 2018 08:49:51 +0100 Subject: [PATCH 0355/5092] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index fb6d167ec642..a829ec0f5a0a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-12 +nightly-2018-11-15 From 1e51a382edcebf72ef50995cf2450b05f9f0270b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 15 Nov 2018 09:09:48 +0100 Subject: [PATCH 0356/5092] update for changed FrameInfo, do not print span for all frames --- src/lib.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b7deb8ee1160..f0b59d03945b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,7 +23,7 @@ use rustc::hir::{self, def_id::DefId}; use rustc::mir; use syntax::attr; - +use syntax::source_map::DUMMY_SP; pub use rustc_mir::interpret::*; pub use rustc_mir::interpret::{self, AllocMap, PlaceTy}; // resolve ambiguity @@ -113,7 +113,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // Push our stack frame ecx.push_stack_frame( start_instance, - start_mir.span, + DUMMY_SP, // there is no call site, we want no span start_mir, Some(ret_ptr.into()), StackPopCleanup::None { cleanup: true }, @@ -146,7 +146,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let ret_place = MPlaceTy::dangling(ecx.layout_of(tcx.mk_unit())?, &ecx).into(); ecx.push_stack_frame( main_instance, - main_mir.span, + DUMMY_SP, // there is no call site, we want no span main_mir, Some(ret_place), StackPopCleanup::None { cleanup: true }, @@ -185,7 +185,7 @@ pub fn eval_main<'a, 'tcx: 'a>( match res { Ok(()) => { let leaks = ecx.memory().leak_report(); - // Disable the leak test on some platforms where we likely do not + // Disable the leak test on some platforms where we do not // correctly implement TLS destructors. let target_os = ecx.tcx.tcx.sess.target.target.target_os.to_lowercase(); let ignore_leaks = target_os == "windows" || target_os == "macos"; @@ -208,8 +208,16 @@ pub fn eval_main<'a, 'tcx: 'a>( let mut err = struct_error(ecx.tcx.tcx.at(span), msg.as_str()); let frames = ecx.generate_stacktrace(None); err.span_label(span, e); - for FrameInfo { span, location, .. } in frames { - err.span_note(span, &format!("inside call to `{}`", location)); + // we iterate with indices because we need to look at the next frame (the caller) + for idx in 0..frames.len() { + let frame_info = &frames[idx]; + let call_site_is_local = frames.get(idx+1).map_or(false, + |caller_info| caller_info.instance.def_id().is_local()); + if call_site_is_local { + err.span_note(frame_info.call_site, &frame_info.to_string()); + } else { + err.note(&frame_info.to_string()); + } } err.emit(); } else { From 09919c2b596b19ad36850b77d8f6ea00b3b60612 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Nov 2018 14:56:25 +0100 Subject: [PATCH 0357/5092] Retag is the only operation that generates new tags --- .gitignore | 1 - src/fn_call.rs | 2 +- src/intrinsic.rs | 22 +-- src/lib.rs | 58 ++++---- src/stacked_borrows.rs | 127 +++++++++++------- .../stacked_borrows/buggy_as_mut_slice.rs | 8 +- .../stacked_borrows/buggy_split_at_mut.rs | 2 +- .../static_memory_modification.rs | 3 + .../stacked_borrows/transmute-is-no-escape.rs | 12 ++ .../stacked_borrows/unescaped_local.rs | 8 +- tests/run-pass/stacked-borrows.rs | 20 ++- 11 files changed, 161 insertions(+), 102 deletions(-) create mode 100644 tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs diff --git a/.gitignore b/.gitignore index dcca7ec10a30..ca23de420882 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,5 @@ target /doc tex/*/out *.dot -*.mir *.rs.bk Cargo.lock diff --git a/src/fn_call.rs b/src/fn_call.rs index d9bf049df704..150cf7402a6d 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -555,7 +555,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "pthread_attr_getstack" => { // second argument is where we are supposed to write the stack size - let ptr = self.ref_to_mplace(self.read_immediate(args[1])?)?; + let ptr = self.deref_operand(args[1])?; let stackaddr = Scalar::from_int(0x80000, args[1].layout.size); // just any address self.write_scalar(stackaddr, ptr.into())?; // return 0 diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 20402f4a2329..e23cadfcaf0b 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -59,7 +59,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "atomic_load_relaxed" | "atomic_load_acq" | "volatile_load" => { - let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?; + let ptr = self.deref_operand(args[0])?; let val = self.read_scalar(ptr.into())?; // make sure it fits into a scalar; otherwise it cannot be atomic self.write_scalar(val, dest)?; } @@ -68,7 +68,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "atomic_store_relaxed" | "atomic_store_rel" | "volatile_store" => { - let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?; + let ptr = self.deref_operand(args[0])?; let val = self.read_scalar(args[1])?; // make sure it fits into a scalar; otherwise it cannot be atomic self.write_scalar(val, ptr.into())?; } @@ -78,7 +78,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } _ if intrinsic_name.starts_with("atomic_xchg") => { - let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?; + let ptr = self.deref_operand(args[0])?; let new = self.read_scalar(args[1])?; let old = self.read_scalar(ptr.into())?; self.write_scalar(old, dest)?; // old value is returned @@ -86,10 +86,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } _ if intrinsic_name.starts_with("atomic_cxchg") => { - let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?; - let expect_old = self.read_immediate(args[1])?; // read as value for the sake of `binary_op_imm()` + let ptr = self.deref_operand(args[0])?; + let expect_old = self.read_immediate(args[1])?; // read as immediate for the sake of `binary_op_imm()` let new = self.read_scalar(args[2])?; - let old = self.read_immediate(ptr.into())?; // read as value for the sake of `binary_op_imm()` + let old = self.read_immediate(ptr.into())?; // read as immediate for the sake of `binary_op_imm()` // binary_op_imm will bail if either of them is not a scalar let (eq, _) = self.binary_op_imm(mir::BinOp::Eq, old, expect_old)?; let res = Immediate::ScalarPair(old.to_scalar_or_undef(), eq.into()); @@ -125,7 +125,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "atomic_xsub_rel" | "atomic_xsub_acqrel" | "atomic_xsub_relaxed" => { - let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?; + let ptr = self.deref_operand(args[0])?; if !ptr.layout.ty.is_integral() { return err!(Unimplemented(format!("Atomic arithmetic operations only work on integer types"))); } @@ -167,7 +167,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } "discriminant_value" => { - let place = self.ref_to_mplace(self.read_immediate(args[0])?)?; + let place = self.deref_operand(args[0])?; let discr_val = self.read_discriminant(place.into())?.0; self.write_scalar(Scalar::from_uint(discr_val, dest.layout.size), dest)?; } @@ -279,7 +279,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } "move_val_init" => { - let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?; + let ptr = self.deref_operand(args[0])?; self.copy_op(args[1], ptr.into())?; } @@ -347,7 +347,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } "size_of_val" => { - let mplace = self.ref_to_mplace(self.read_immediate(args[0])?)?; + let mplace = self.deref_operand(args[0])?; let (size, _) = self.size_and_align_of_mplace(mplace)? .expect("size_of_val called on extern type"); let ptr_size = self.pointer_size(); @@ -359,7 +359,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "min_align_of_val" | "align_of_val" => { - let mplace = self.ref_to_mplace(self.read_immediate(args[0])?)?; + let mplace = self.deref_operand(args[0])?; let (_, align) = self.size_and_align_of_mplace(mplace)? .expect("size_of_val called on extern type"); let ptr_size = self.pointer_size(); diff --git a/src/lib.rs b/src/lib.rs index b7deb8ee1160..e8691409b1ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -296,7 +296,6 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { type AllocExtra = stacked_borrows::Stacks; type PointerTag = Borrow; - const ENABLE_PTR_TRACKING_HOOKS: bool = true; type MemoryMap = MonoHashMap, Allocation)>; @@ -446,26 +445,6 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { Cow::Owned(alloc) } - #[inline(always)] - fn tag_reference( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - place: MPlaceTy<'tcx, Borrow>, - mutability: Option, - ) -> EvalResult<'tcx, Scalar> { - let (size, _) = ecx.size_and_align_of_mplace(place)? - // for extern types, just cover what we can - .unwrap_or_else(|| place.layout.size_and_align()); - if !ecx.machine.validate || size == Size::ZERO { - // No tracking - Ok(place.ptr) - } else { - let ptr = place.ptr.to_ptr()?; - let tag = ecx.tag_reference(place, size, mutability.into())?; - Ok(Scalar::Ptr(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag))) - } - } - - #[inline(always)] fn tag_dereference( ecx: &EvalContext<'a, 'mir, 'tcx, Self>, place: MPlaceTy<'tcx, Borrow>, @@ -478,7 +457,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { // No tracking Ok(place.ptr) } else { - let ptr = place.ptr.to_ptr()?; + let ptr = place.ptr.to_ptr()?; // assert this is not a scalar let tag = ecx.tag_dereference(place, size, mutability.into())?; Ok(Scalar::Ptr(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag))) } @@ -499,6 +478,31 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { } } + #[inline] + fn escape_to_raw( + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ptr: OpTy<'tcx, Self::PointerTag>, + ) -> EvalResult<'tcx> { + // It is tempting to check the type here, but drop glue does EscapeToRaw + // on a raw pointer. + // This is deliberately NOT `deref_operand` as we do not want `tag_dereference` + // to be called! That would kill the original tag if we got a raw ptr. + let place = ecx.ref_to_mplace(ecx.read_immediate(ptr)?)?; + let (size, _) = ecx.size_and_align_of_mplace(place)? + // for extern types, just cover what we can + .unwrap_or_else(|| place.layout.size_and_align()); + if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || + !ecx.machine.validate || size == Size::ZERO + { + // No tracking, or no retagging. The latter is possible because a dependency of ours + // might be called with different flags than we are, so there are `Retag` + // statements but we do not want to execute them. + Ok(()) + } else { + ecx.escape_to_raw(place, size) + } + } + #[inline(always)] fn retag( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, @@ -506,12 +510,14 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { place: PlaceTy<'tcx, Borrow>, ) -> EvalResult<'tcx> { if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !Self::enforce_validity(ecx) { - // No tracking, or no retagging. This is possible because a dependency of ours might be - // called with different flags than we are, + // No tracking, or no retagging. The latter is possible because a dependency of ours + // might be called with different flags than we are, so there are `Retag` + // statements but we do not want to execute them. // Also, honor the whitelist in `enforce_validity` because otherwise we might retag // uninitialized data. - return Ok(()) + Ok(()) + } else { + ecx.retag(fn_entry, place) } - ecx.retag(fn_entry, place) } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index c6cd7f5005d2..e7c595f1c6cc 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -6,7 +6,7 @@ use rustc::hir; use crate::{ EvalResult, MiriEvalContext, HelpersEvalContextExt, MemoryKind, MiriMemoryKind, RangeMap, AllocId, Allocation, AllocationExtra, - Pointer, PlaceTy, MPlaceTy, + Pointer, MemPlace, Scalar, Immediate, ImmTy, PlaceTy, MPlaceTy, }; pub type Timestamp = u64; @@ -395,13 +395,6 @@ impl<'tcx> Stacks { pub trait EvalContextExt<'tcx> { - fn tag_reference( - &mut self, - place: MPlaceTy<'tcx, Borrow>, - size: Size, - usage: UsageKind, - ) -> EvalResult<'tcx, Borrow>; - fn tag_dereference( &self, place: MPlaceTy<'tcx, Borrow>, @@ -415,47 +408,27 @@ pub trait EvalContextExt<'tcx> { kind: MemoryKind, ) -> Borrow; + /// Retag an indidual pointer, returning the retagged version. + fn retag_ptr( + &mut self, + ptr: ImmTy<'tcx, Borrow>, + mutbl: hir::Mutability, + ) -> EvalResult<'tcx, Immediate>; + fn retag( &mut self, fn_entry: bool, place: PlaceTy<'tcx, Borrow> ) -> EvalResult<'tcx>; -} -impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { - /// Called for place-to-value conversion. - fn tag_reference( + fn escape_to_raw( &mut self, place: MPlaceTy<'tcx, Borrow>, size: Size, - usage: UsageKind, - ) -> EvalResult<'tcx, Borrow> { - let ptr = place.ptr.to_ptr()?; - let time = self.machine.stacked_borrows.increment_clock(); - let new_bor = match usage { - UsageKind::Write => Borrow::Uniq(time), - UsageKind::Read => Borrow::Shr(Some(time)), - UsageKind::Raw => Borrow::Shr(None), - }; - trace!("tag_reference: Creating new reference ({:?}) for {:?} (pointee {}): {:?}", - usage, ptr, place.layout.ty, new_bor); - - // Update the stacks. First create the new ref as usual, then maybe freeze stuff. - self.memory().check_bounds(ptr, size, false)?; - let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); - alloc.extra.use_and_maybe_re_borrow(ptr, size, usage, Some(new_bor))?; - // Maybe freeze stuff - if let Borrow::Shr(Some(bor_t)) = new_bor { - self.visit_frozen(place, size, |frz_ptr, size| { - debug_assert_eq!(frz_ptr.alloc_id, ptr.alloc_id); - // Be frozen! - alloc.extra.freeze(frz_ptr, size, bor_t) - })?; - } - - Ok(new_bor) - } + ) -> EvalResult<'tcx>; +} +impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { /// Called for value-to-place conversion. /// /// Note that this does NOT mean that all this memory will actually get accessed/referenced! @@ -466,9 +439,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { size: Size, usage: UsageKind, ) -> EvalResult<'tcx, Borrow> { - let ptr = place.ptr.to_ptr()?; trace!("tag_dereference: Accessing reference ({:?}) for {:?} (pointee {})", - usage, ptr, place.layout.ty); + usage, place.ptr, place.layout.ty); + let ptr = place.ptr.to_ptr()?; // In principle we should not have to do anything here. However, with transmutes involved, // it can happen that the tag of `ptr` does not actually match `usage`, and we // should adjust for that. @@ -551,6 +524,50 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { Borrow::Uniq(time) } + fn retag_ptr( + &mut self, + val: ImmTy<'tcx, Borrow>, + mutbl: hir::Mutability, + ) -> EvalResult<'tcx, Immediate> { + // We want a place for where the ptr *points to*, so we get one. + let place = self.ref_to_mplace(val)?; + let size = self.size_and_align_of_mplace(place)? + .map(|(size, _)| size) + .unwrap_or_else(|| place.layout.size); + if size == Size::ZERO { + // Nothing to do for ZSTs. + return Ok(*val); + } + + // Prepare to re-borrow this place. + let ptr = place.ptr.to_ptr()?; + let time = self.machine.stacked_borrows.increment_clock(); + let new_bor = match mutbl { + hir::MutMutable => Borrow::Uniq(time), + hir::MutImmutable => Borrow::Shr(Some(time)), + }; + trace!("retag: Creating new reference ({:?}) for {:?} (pointee {}): {:?}", + mutbl, ptr, place.layout.ty, new_bor); + + // Update the stacks. First create a new borrow, then maybe freeze stuff. + self.memory().check_bounds(ptr, size, false)?; // `ptr_dereference` wouldn't do any checks if this is a raw ptr + let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); + alloc.extra.use_and_maybe_re_borrow(ptr, size, Some(mutbl).into(), Some(new_bor))?; + // Maybe freeze stuff + if let Borrow::Shr(Some(bor_t)) = new_bor { + self.visit_frozen(place, size, |frz_ptr, size| { + debug_assert_eq!(frz_ptr.alloc_id, ptr.alloc_id); + // Be frozen! + alloc.extra.freeze(frz_ptr, size, bor_t) + })?; + } + + // Compute the new value and return that + let new_ptr = Scalar::Ptr(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, new_bor)); + let new_place = MemPlace { ptr: new_ptr, ..*place }; + Ok(new_place.to_ref()) + } + fn retag( &mut self, _fn_entry: bool, @@ -558,20 +575,30 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { ) -> EvalResult<'tcx> { // For now, we only retag if the toplevel type is a reference. // TODO: Recurse into structs and enums, sharing code with validation. + // TODO: Honor `fn_entry`. let mutbl = match place.layout.ty.sty { ty::Ref(_, _, mutbl) => mutbl, // go ahead - _ => return Ok(()), // don't do a thing + _ => return Ok(()), // do nothing, for now }; - // We want to reborrow the reference stored there. This will call the hooks - // above. First deref, which will call `tag_dereference`. - // (This is somewhat redundant because validation already did the same thing, - // but what can you do.) + // Retag the pointer and write it back. let val = self.read_immediate(self.place_to_op(place)?)?; - let dest = self.ref_to_mplace(val)?; - // Now put a new ref into the old place, which will call `tag_reference`. - // FIXME: Honor `fn_entry`! - let val = self.create_ref(dest, Some(mutbl))?; + let val = self.retag_ptr(val, mutbl)?; self.write_immediate(val, place)?; Ok(()) } + + fn escape_to_raw( + &mut self, + place: MPlaceTy<'tcx, Borrow>, + size: Size, + ) -> EvalResult<'tcx> { + trace!("self: {:?} is now accessible by raw pointers", *place); + // Re-borrow to raw. This is a NOP for shared borrows, but we do not know the borrow + // type here and that's also okay. + let ptr = place.ptr.to_ptr()?; + self.memory().check_bounds(ptr, size, false)?; // `ptr_dereference` wouldn't do any checks if this is a raw ptr + let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); + alloc.extra.use_and_maybe_re_borrow(ptr, size, UsageKind::Raw, Some(Borrow::default()))?; + Ok(()) + } } diff --git a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs index 4857ada7fb2c..2f3d0793f63e 100644 --- a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs +++ b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs @@ -1,4 +1,4 @@ -#![allow(unused_variables)] +// error-pattern: mutable reference with frozen tag mod safe { use std::slice::from_raw_parts_mut; @@ -12,8 +12,10 @@ mod safe { fn main() { let v = vec![0,1,2]; - let v1 = safe::as_mut_slice(&v); + let _v1 = safe::as_mut_slice(&v); +/* let v2 = safe::as_mut_slice(&v); - v1[1] = 5; //~ ERROR does not exist on the stack + v1[1] = 5; v1[1] = 6; +*/ } diff --git a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs index a6daa5d93d77..711544f80149 100644 --- a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs @@ -11,7 +11,6 @@ mod safe { assert!(mid <= len); (from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" - //~^ ERROR does not exist on the stack from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) } } @@ -20,6 +19,7 @@ mod safe { fn main() { let mut array = [1,2,3,4]; let (a, b) = safe::split_at_mut(&mut array, 0); + //~^ ERROR does not exist on the stack a[1] = 5; b[1] = 6; } diff --git a/tests/compile-fail/stacked_borrows/static_memory_modification.rs b/tests/compile-fail/stacked_borrows/static_memory_modification.rs index c092cbfe5098..5c605eff6784 100644 --- a/tests/compile-fail/stacked_borrows/static_memory_modification.rs +++ b/tests/compile-fail/stacked_borrows/static_memory_modification.rs @@ -1,3 +1,6 @@ +// FIXME still considering whether we are okay with this not being an error +// ignore-test + static X: usize = 5; #[allow(mutable_transmutes)] diff --git a/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs b/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs new file mode 100644 index 000000000000..1ab005e3fa17 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs @@ -0,0 +1,12 @@ +// Make sure we cannot use raw ptrs that got transmuted from mutable references +// (i.e, no EscapeToRaw happened). +// We could, in principle, to EscapeToRaw lazily to allow this code, but that +// would no alleviate the need for EscapeToRaw (see `ref_raw_int_raw` in +// `run-pass/stacked-borrows.rs`), and thus increase overall complexity. +use std::mem; + +fn main() { + let mut x: i32 = 42; + let raw: *mut i32 = unsafe { mem::transmute(&mut x) }; + unsafe { *raw = 13; } //~ ERROR does not exist on the stack +} diff --git a/tests/compile-fail/stacked_borrows/unescaped_local.rs b/tests/compile-fail/stacked_borrows/unescaped_local.rs index 8627cc44c2e5..054697b04a09 100644 --- a/tests/compile-fail/stacked_borrows/unescaped_local.rs +++ b/tests/compile-fail/stacked_borrows/unescaped_local.rs @@ -1,10 +1,8 @@ -use std::mem; - // Make sure we cannot use raw ptrs to access a local that -// has never been escaped to the raw world. +// we took the direct address of. fn main() { let mut x = 42; - let ptr = &mut x; - let raw: *mut i32 = unsafe { mem::transmute(ptr) }; + let raw = &mut x as *mut i32 as usize as *mut i32; + let _ptr = &mut x; unsafe { *raw = 13; } //~ ERROR does not exist on the stack } diff --git a/tests/run-pass/stacked-borrows.rs b/tests/run-pass/stacked-borrows.rs index 8faa4d659115..adab2b5a5683 100644 --- a/tests/run-pass/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows.rs @@ -3,15 +3,17 @@ fn main() { deref_partially_dangling_raw(); read_does_not_invalidate1(); read_does_not_invalidate2(); + ref_raw_int_raw(); } // Deref a raw ptr to access a field of a large struct, where the field // is allocated but not the entire struct is. // For now, we want to allow this. fn deref_partially_dangling_raw() { - let x = (1, 1); + let x = (1, 13); let xptr = &x as *const _ as *const (i32, i32, i32); - let _val = unsafe { (*xptr).1 }; + let val = unsafe { (*xptr).1 }; + assert_eq!(val, 13); } // Make sure that reading from an `&mut` does, like reborrowing to `&`, @@ -23,7 +25,7 @@ fn read_does_not_invalidate1() { let _val = x.1; // we just read, this does NOT invalidate the reborrows. ret } - foo(&mut (1, 2)); + assert_eq!(*foo(&mut (1, 2)), 2); } // Same as above, but this time we first create a raw, then read from `&mut` // and then freeze from the raw. @@ -34,5 +36,15 @@ fn read_does_not_invalidate2() { let ret = unsafe { &(*xraw).1 }; ret } - foo(&mut (1, 2)); + assert_eq!(*foo(&mut (1, 2)), 2); +} + +// Just to make sure that casting a ref to raw, to int and back to raw +// and only then using it works. This rules out ideas like "do escape-to-raw lazily": +// After casting to int and back, we lost the tag that could have let us do that. +fn ref_raw_int_raw() { + let mut x = 3; + let xref = &mut x; + let xraw = xref as *mut i32 as usize as *mut i32; + assert_eq!(unsafe { *xraw }, 3); } From 020313dd8506d3704a71d2ec1499f0e7ee93f3dd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Nov 2018 16:56:25 +0100 Subject: [PATCH 0358/5092] make freezing inherently part of the high-level reactivate/initiate operations --- src/helpers.rs | 35 +++--- src/stacked_borrows.rs | 259 +++++++++++++++++++++-------------------- 2 files changed, 155 insertions(+), 139 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 880b18c7d542..31e297295703 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -33,13 +33,13 @@ impl ScalarExt for ScalarMaybeUndef { pub trait EvalContextExt<'tcx> { fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>>; - /// Visit the memory covered by `place` that is frozen -- i.e., NOT - /// what is inside an `UnsafeCell`. - fn visit_frozen( + /// Visit the memory covered by `place`, sensitive to freezing: The 3rd parameter + /// will be true if this is frozen, false if this is in an `UnsafeCell`. + fn visit_freeze_sensitive( &self, place: MPlaceTy<'tcx, Borrow>, size: Size, - action: impl FnMut(Pointer, Size) -> EvalResult<'tcx>, + action: impl FnMut(Pointer, Size, bool) -> EvalResult<'tcx>, ) -> EvalResult<'tcx>; } @@ -79,13 +79,11 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: }) } - /// Visit the memory covered by `place` that is frozen -- i.e., NOT - /// what is inside an `UnsafeCell`. - fn visit_frozen( + fn visit_freeze_sensitive( &self, place: MPlaceTy<'tcx, Borrow>, size: Size, - mut frozen_action: impl FnMut(Pointer, Size) -> EvalResult<'tcx>, + mut action: impl FnMut(Pointer, Size, bool) -> EvalResult<'tcx>, ) -> EvalResult<'tcx> { trace!("visit_frozen(place={:?}, size={:?})", *place, size); debug_assert_eq!(size, @@ -99,18 +97,29 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let mut end_ptr = place.ptr; // Called when we detected an `UnsafeCell` at the given offset and size. // Calls `action` and advances `end_ptr`. - let mut unsafe_cell_action = |unsafe_cell_offset, unsafe_cell_size| { + let mut unsafe_cell_action = |unsafe_cell_ptr: Scalar, unsafe_cell_size: Size| { + if unsafe_cell_size != Size::ZERO { + debug_assert_eq!(unsafe_cell_ptr.to_ptr().unwrap().alloc_id, + end_ptr.to_ptr().unwrap().alloc_id); + debug_assert_eq!(unsafe_cell_ptr.to_ptr().unwrap().tag, + end_ptr.to_ptr().unwrap().tag); + } // We assume that we are given the fields in increasing offset order, // and nothing else changes. + let unsafe_cell_offset = unsafe_cell_ptr.get_ptr_offset(self); let end_offset = end_ptr.get_ptr_offset(self); assert!(unsafe_cell_offset >= end_offset); let frozen_size = unsafe_cell_offset - end_offset; // Everything between the end_ptr and this `UnsafeCell` is frozen. if frozen_size != Size::ZERO { - frozen_action(end_ptr.to_ptr()?, frozen_size)?; + action(end_ptr.to_ptr()?, frozen_size, /*frozen*/true)?; + } + // This `UnsafeCell` is NOT frozen. + if unsafe_cell_size != Size::ZERO { + action(unsafe_cell_ptr.to_ptr()?, unsafe_cell_size, /*frozen*/false)?; } // Update end end_ptr. - end_ptr = end_ptr.ptr_wrapping_offset(frozen_size+unsafe_cell_size, self); + end_ptr = unsafe_cell_ptr.ptr_wrapping_offset(unsafe_cell_size, self); // Done Ok(()) }; @@ -126,7 +135,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: .unwrap_or_else(|| place.layout.size_and_align()); // Now handle this `UnsafeCell`, unless it is empty. if unsafe_cell_size != Size::ZERO { - unsafe_cell_action(place.ptr.get_ptr_offset(self), unsafe_cell_size) + unsafe_cell_action(place.ptr, unsafe_cell_size) } else { Ok(()) } @@ -136,7 +145,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } // The part between the end_ptr and the end of the place is also frozen. // So pretend there is a 0-sized `UnsafeCell` at the end. - unsafe_cell_action(place.ptr.get_ptr_offset(self) + size, Size::ZERO)?; + unsafe_cell_action(place.ptr.ptr_wrapping_offset(size, self), Size::ZERO)?; // Done! return Ok(()); diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index e7c595f1c6cc..ab0c3f8994c5 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -217,10 +217,12 @@ impl<'tcx> Stack { /// Initiate `bor`; mostly this means pushing. /// This operation cannot fail; it is up to the caller to ensure that the precondition - /// is met: We cannot push onto frozen stacks. + /// is met: We cannot push `Uniq` onto frozen stacks. + /// Crucially, this makes pushing a `Shr` onto a frozen location a NOP. We do not want + /// such a location to get mutably shared this way! fn initiate(&mut self, bor: Borrow) { if let Some(_) = self.frozen_since { - // "Pushing" a Shr or Frz on top is redundant. + // A frozen location, we won't change anything here! match bor { Borrow::Uniq(_) => bug!("Trying to create unique ref to frozen location"), Borrow::Shr(_) => trace!("initiate: New shared ref to frozen location is a NOP"), @@ -272,39 +274,41 @@ impl State { /// Higher-level operations impl<'tcx> Stacks { - /// The single most important operation: Make sure that using `ptr` is okay, - /// and if `new_bor` is present then make that the new current borrow. - fn use_and_maybe_re_borrow( + /// `ptr` got used, reflect that in the stack. + fn reactivate( &self, ptr: Pointer, size: Size, usage: UsageKind, - new_bor: Option, ) -> EvalResult<'tcx> { - trace!("use_and_maybe_re_borrow of tag {:?} as {:?}, new {:?}: {:?}, size {}", - ptr.tag, usage, new_bor, ptr, size.bytes()); + trace!("use_borrow of tag {:?} as {:?}: {:?}, size {}", + ptr.tag, usage, ptr, size.bytes()); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { stack.reactivate(ptr.tag, usage == UsageKind::Write)?; - if let Some(new_bor) = new_bor { - stack.initiate(new_bor); - } } Ok(()) } - /// Freeze the given memory range. - fn freeze( + /// Create a new borrow, the ptr must already have the new tag. + /// Also freezes the location if `freeze` is set and the tag is a timestamped `Shr`. + fn initiate( &self, ptr: Pointer, size: Size, - bor_t: Timestamp - ) -> EvalResult<'tcx> { + freeze: bool, + ) { + trace!("reborrow for tag {:?}: {:?}, size {}", + ptr.tag, ptr, size.bytes()); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { - stack.freeze(bor_t); + stack.initiate(ptr.tag); + if freeze { + if let Borrow::Shr(Some(bor_t)) = ptr.tag { + stack.freeze(bor_t); + } + } } - Ok(()) } /// Check that this stack is fine with being dereferenced @@ -312,6 +316,7 @@ impl<'tcx> Stacks { &self, ptr: Pointer, size: Size, + frozen: bool, ) -> EvalResult<'tcx> { let mut stacks = self.stacks.borrow_mut(); // We need `iter_mut` because `iter` would skip gaps! @@ -323,20 +328,14 @@ impl<'tcx> Stacks { err ))) } - } - Ok(()) - } - - /// Check that this stack is appropriately frozen - fn check_frozen( - &self, - ptr: Pointer, - size: Size, - bor_t: Timestamp - ) -> EvalResult<'tcx> { - let mut stacks = self.stacks.borrow_mut(); - for stack in stacks.iter_mut(ptr.offset, size) { - stack.check_frozen(bor_t)?; + // Sometimes we also need to be frozen. + if frozen { + // Even shared refs can have uniq tags (after transmute). That's not an error + // but they do not get any freezing benefits. + if let Borrow::Shr(Some(bor_t)) = ptr.tag { + stack.check_frozen(bor_t)?; + } + } } Ok(()) } @@ -351,7 +350,7 @@ impl AllocationExtra for Stacks { size: Size, ) -> EvalResult<'tcx> { // Reads behave exactly like the first half of a reborrow-to-shr - alloc.extra.use_and_maybe_re_borrow(ptr, size, UsageKind::Read, None) + alloc.extra.reactivate(ptr, size, UsageKind::Read) } #[inline(always)] @@ -361,7 +360,7 @@ impl AllocationExtra for Stacks { size: Size, ) -> EvalResult<'tcx> { // Writes behave exactly like the first half of a reborrow-to-mut - alloc.extra.use_and_maybe_re_borrow(ptr, size, UsageKind::Write, None) + alloc.extra.reactivate(ptr, size, UsageKind::Read) } #[inline(always)] @@ -371,7 +370,7 @@ impl AllocationExtra for Stacks { size: Size, ) -> EvalResult<'tcx> { // This is like mutating - alloc.extra.use_and_maybe_re_borrow(ptr, size, UsageKind::Write, None) + alloc.extra.reactivate(ptr, size, UsageKind::Write) // FIXME: Error out of there are any barriers? } } @@ -429,72 +428,6 @@ pub trait EvalContextExt<'tcx> { } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { - /// Called for value-to-place conversion. - /// - /// Note that this does NOT mean that all this memory will actually get accessed/referenced! - /// We could be in the middle of `&(*var).1`. - fn tag_dereference( - &self, - place: MPlaceTy<'tcx, Borrow>, - size: Size, - usage: UsageKind, - ) -> EvalResult<'tcx, Borrow> { - trace!("tag_dereference: Accessing reference ({:?}) for {:?} (pointee {})", - usage, place.ptr, place.layout.ty); - let ptr = place.ptr.to_ptr()?; - // In principle we should not have to do anything here. However, with transmutes involved, - // it can happen that the tag of `ptr` does not actually match `usage`, and we - // should adjust for that. - // Notably, the compiler can introduce such transmutes by optimizing away `&[mut]*`. - // That can transmute a raw ptr to a (shared/mut) ref, and a mut ref to a shared one. - match (usage, ptr.tag) { - (UsageKind::Raw, _) => { - // Don't use the tag, this is a raw access! Even if there is a tag, - // that means transmute happened and we ignore the tag. - // Also don't do any further validation, this is raw after all. - return Ok(Borrow::default()); - } - (UsageKind::Write, Borrow::Uniq(_)) | - (UsageKind::Read, Borrow::Shr(_)) => { - // Expected combinations. Nothing to do. - } - (UsageKind::Write, Borrow::Shr(None)) => { - // Raw transmuted to mut ref. Keep this as raw access. - // We cannot reborrow here; there might be a raw in `&(*var).1` where - // `var` is an `&mut`. The other field of the struct might be already frozen, - // also using `var`, and that would be okay. - } - (UsageKind::Read, Borrow::Uniq(_)) => { - // A mut got transmuted to shr. Can happen even from compiler transformations: - // `&*x` gets optimized to `x` even when `x` is a `&mut`. - } - (UsageKind::Write, Borrow::Shr(Some(_))) => { - // This is just invalid: A shr got transmuted to a mut. - // If we ever allow this, we have to consider what we do when a turn a - // `Raw`-tagged `&mut` into a raw pointer pointing to a frozen location. - // We probably do not want to allow that, but we have to allow - // turning a `Raw`-tagged `&` into a raw ptr to a frozen location. - return err!(MachineError(format!("Encountered mutable reference with frozen tag {:?}", ptr.tag))) - } - } - - // If we got here, we do some checking, *but* we leave the tag unchanged. - self.memory().check_bounds(ptr, size, false)?; - let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); - alloc.extra.check_deref(ptr, size)?; - // Maybe check frozen stuff - if let Borrow::Shr(Some(bor_t)) = ptr.tag { - self.visit_frozen(place, size, |frz_ptr, size| { - debug_assert_eq!(frz_ptr.alloc_id, ptr.alloc_id); - // Are you frozen? - alloc.extra.check_frozen(frz_ptr, size, bor_t) - })?; - } - - // All is good, and do not change the tag - Ok(ptr.tag) - } - fn tag_new_allocation( &mut self, id: AllocId, @@ -524,6 +457,92 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { Borrow::Uniq(time) } + /// Called for value-to-place conversion. + /// + /// Note that this does NOT mean that all this memory will actually get accessed/referenced! + /// We could be in the middle of `&(*var).1`. + fn tag_dereference( + &self, + place: MPlaceTy<'tcx, Borrow>, + size: Size, + usage: UsageKind, + ) -> EvalResult<'tcx, Borrow> { + trace!("tag_dereference: Accessing reference ({:?}) for {:?} (pointee {})", + usage, place.ptr, place.layout.ty); + let ptr = place.ptr.to_ptr()?; + // In principle we should not have to do anything here. However, with transmutes involved, + // it can happen that the tag of `ptr` does not actually match `usage`, and we + // should adjust for that. + // Notably, the compiler can introduce such transmutes by optimizing away `&[mut]*`. + // That can transmute a raw ptr to a (shared/mut) ref, and a mut ref to a shared one. + match (usage, ptr.tag) { + (UsageKind::Raw, _) => { + // Don't use the tag, this is a raw access! They should happen tagless. + // This does mean, however, that `&*foo` is *not* a NOP *if* `foo` is a raw ptr. + // Also don't do any further validation, this is raw after all. + return Ok(Borrow::default()); + } + (UsageKind::Write, Borrow::Uniq(_)) | + (UsageKind::Read, Borrow::Shr(_)) => { + // Expected combinations. Nothing to do. + } + (UsageKind::Write, Borrow::Shr(None)) => { + // Raw transmuted to mut ref. Keep this as raw access. + // We cannot reborrow here; there might be a raw in `&(*var).1` where + // `var` is an `&mut`. The other field of the struct might be already frozen, + // also using `var`, and that would be okay. + } + (UsageKind::Read, Borrow::Uniq(_)) => { + // A mut got transmuted to shr. Can happen even from compiler transformations: + // `&*x` gets optimized to `x` even when `x` is a `&mut`. + } + (UsageKind::Write, Borrow::Shr(Some(_))) => { + // This is just invalid: A shr got transmuted to a mut. + // If we ever allow this, we have to consider what we do when a turn a + // `Raw`-tagged `&mut` into a raw pointer pointing to a frozen location. + // We probably do not want to allow that, but we have to allow + // turning a `Raw`-tagged `&` into a raw ptr to a frozen location. + return err!(MachineError(format!("Encountered mutable reference with frozen tag {:?}", ptr.tag))) + } + } + + // Get the allocation + self.memory().check_bounds(ptr, size, false)?; + let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); + // If we got here, we do some checking, *but* we leave the tag unchanged. + if let Borrow::Shr(Some(_)) = ptr.tag { + // We need a frozen-sensitive check + self.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { + alloc.extra.check_deref(cur_ptr, size, frozen) + })?; + } else { + // Just treat this as one big chunk + alloc.extra.check_deref(ptr, size, /*frozen*/false)?; + } + + // All is good, and do not change the tag + Ok(ptr.tag) + } + + /// The given place may henceforth be accessed through raw pointers. + fn escape_to_raw( + &mut self, + place: MPlaceTy<'tcx, Borrow>, + size: Size, + ) -> EvalResult<'tcx> { + trace!("self: {:?} is now accessible by raw pointers", *place); + // Get the allocation + let mut ptr = place.ptr.to_ptr()?; + self.memory().check_bounds(ptr, size, false)?; // `ptr_dereference` wouldn't do any checks if this is a raw ptr + let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); + // Re-borrow to raw. This is a NOP for shared borrows, but we do not know the borrow + // type here and that's also okay. Freezing does not matter here. + alloc.extra.reactivate(ptr, size, UsageKind::Raw)?; + ptr.tag = Borrow::default(); + alloc.extra.initiate(ptr, size, /*freeze*/false); + Ok(()) + } + fn retag_ptr( &mut self, val: ImmTy<'tcx, Borrow>, @@ -546,25 +565,28 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { hir::MutMutable => Borrow::Uniq(time), hir::MutImmutable => Borrow::Shr(Some(time)), }; + let new_ptr = Pointer::new_with_tag(ptr.alloc_id, ptr.offset, new_bor); trace!("retag: Creating new reference ({:?}) for {:?} (pointee {}): {:?}", mutbl, ptr, place.layout.ty, new_bor); - // Update the stacks. First create a new borrow, then maybe freeze stuff. + // Get the allocation self.memory().check_bounds(ptr, size, false)?; // `ptr_dereference` wouldn't do any checks if this is a raw ptr let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); - alloc.extra.use_and_maybe_re_borrow(ptr, size, Some(mutbl).into(), Some(new_bor))?; - // Maybe freeze stuff - if let Borrow::Shr(Some(bor_t)) = new_bor { - self.visit_frozen(place, size, |frz_ptr, size| { - debug_assert_eq!(frz_ptr.alloc_id, ptr.alloc_id); - // Be frozen! - alloc.extra.freeze(frz_ptr, size, bor_t) + // Update the stacks. First use old borrow, then initiate new one. + alloc.extra.reactivate(ptr, size, Some(mutbl).into())?; + if mutbl == hir::MutImmutable { + // We need a frozen-sensitive initiate + self.visit_freeze_sensitive(place, size, |mut cur_ptr, size, frozen| { + cur_ptr.tag = new_bor; + Ok(alloc.extra.initiate(cur_ptr, size, frozen)) })?; + } else { + // Just treat this as one big chunk + alloc.extra.initiate(new_ptr, size, /*frozen*/false); } - // Compute the new value and return that - let new_ptr = Scalar::Ptr(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, new_bor)); - let new_place = MemPlace { ptr: new_ptr, ..*place }; + // Return new ptr + let new_place = MemPlace { ptr: Scalar::Ptr(new_ptr), ..*place }; Ok(new_place.to_ref()) } @@ -586,19 +608,4 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { self.write_immediate(val, place)?; Ok(()) } - - fn escape_to_raw( - &mut self, - place: MPlaceTy<'tcx, Borrow>, - size: Size, - ) -> EvalResult<'tcx> { - trace!("self: {:?} is now accessible by raw pointers", *place); - // Re-borrow to raw. This is a NOP for shared borrows, but we do not know the borrow - // type here and that's also okay. - let ptr = place.ptr.to_ptr()?; - self.memory().check_bounds(ptr, size, false)?; // `ptr_dereference` wouldn't do any checks if this is a raw ptr - let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); - alloc.extra.use_and_maybe_re_borrow(ptr, size, UsageKind::Raw, Some(Borrow::default()))?; - Ok(()) - } } From 94e751267c881bc26219853733222e4fe8fdc87a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Nov 2018 17:33:41 +0100 Subject: [PATCH 0359/5092] add another mean test case --- .../stacked_borrows/illegal_read3.rs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 tests/compile-fail/stacked_borrows/illegal_read3.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read3.rs b/tests/compile-fail/stacked_borrows/illegal_read3.rs new file mode 100644 index 000000000000..b0da0511dee3 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read3.rs @@ -0,0 +1,29 @@ +#![feature(untagged_unions)] +// A callee may not read the destination of our `&mut` without +// us noticing. +// Thise code got carefully checked to not introduce any reborrows +// that are not explicit in the source. Let's hope the compiler does not break this later! + +use std::mem; + +fn main() { + let mut x: i32 = 15; + let xref1 = &mut x; + let xref1_sneaky: usize = unsafe { mem::transmute_copy(&xref1) }; + let xref2 = &mut *xref1; // derived from xref1, so using raw is still okay... + callee(xref1_sneaky); + let _val = *xref2; // ...but any use of it will invalidate our ref. + //~^ ERROR: does not exist on the stack +} + +fn callee(xref1: usize) { + // Transmuting through a union to avoid retagging + union UsizeToRef { + from: usize, + to: &'static mut i32, + } + let xref1 = UsizeToRef { from: xref1 }; + // Doing the deref and the transmute (through the union) in the same place expression + // should avoid retagging. + let _val = unsafe { *xref1.to }; +} From aa8f523df6447a32c15d2620a52a55761f94da97 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Nov 2018 21:08:34 +0100 Subject: [PATCH 0360/5092] test for special things that are now possible --- tests/run-pass/stacked-borrows.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/run-pass/stacked-borrows.rs b/tests/run-pass/stacked-borrows.rs index adab2b5a5683..00b21c746c26 100644 --- a/tests/run-pass/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows.rs @@ -4,6 +4,8 @@ fn main() { read_does_not_invalidate1(); read_does_not_invalidate2(); ref_raw_int_raw(); + mut_shr_raw(); + mut_raw_then_mut_shr(); } // Deref a raw ptr to access a field of a large struct, where the field @@ -48,3 +50,29 @@ fn ref_raw_int_raw() { let xraw = xref as *mut i32 as usize as *mut i32; assert_eq!(unsafe { *xraw }, 3); } + +// Creating a raw from a `&mut` through an `&` works, even if we +// write through that raw. +fn mut_shr_raw() { + let mut x = 2; + { + let xref = &mut x; + let xraw = &*xref as *const i32 as *mut i32; + unsafe { *xraw = 4; } + } + assert_eq!(x, 4); +} + +// Escape a mut to raw, then share the same mut and use the share, then the raw. +// That should work. +fn mut_raw_then_mut_shr() { + let mut x = 2; + { + let xref = &mut x; + let xraw = &mut *xref as *mut _; + let xshr = &*xref; + assert_eq!(*xshr, 2); + unsafe { *xraw = 4; } + } + assert_eq!(x, 4); +} From a94e197105a0ce67cba816299cdd59efdb6df7a4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Nov 2018 21:08:20 +0100 Subject: [PATCH 0361/5092] better test the special exception for reading through unique when things are shared --- src/stacked_borrows.rs | 14 +++++++---- .../stacked_borrows/illegal_read4.rs | 9 ++++++++ tests/run-pass/stacked-borrows.rs | 23 +++++++++++++++++++ 3 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 tests/compile-fail/stacked_borrows/illegal_read4.rs diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index ab0c3f8994c5..56688ca10f49 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -167,13 +167,15 @@ impl<'tcx> Stack { behind a barrier", bor)) } (BorStackItem::Uniq(itm_t), Borrow::Uniq(bor_t)) if itm_t == bor_t => { - // Found matching unique item. + // Found matching unique item. This is *always* required to use a `Uniq`: + // The item must still be on the stack. if !is_write { - // As a special case, if we are reading and since we *did* find the `Uniq`, - // we try to pop less: We are happy with making a `Shr` or `Frz` active; - // that one will not mind concurrent reads. + // As a special case, if we are reading, let us see if it would be + // beneficial to pretend we are a raw pointer instead. If + // raw pointers are allowed to read while popping *less* than we + // would have to pop, there is no reason not to let them do this. match self.reactivatable(Borrow::default(), is_write) { - // If we got something better that `idx`, use that + // If we got something better (popping less) that `idx`, use that Ok(None) => return Ok(None), Ok(Some(shr_idx)) if shr_idx <= idx => return Ok(Some(shr_idx)), // Otherwise just go on. @@ -329,6 +331,8 @@ impl<'tcx> Stacks { ))) } // Sometimes we also need to be frozen. + // In this case we *both* push `Shr` and then freeze. This means that a `&mut` + // to `*const` to `*mut` cast through `&` actually works. if frozen { // Even shared refs can have uniq tags (after transmute). That's not an error // but they do not get any freezing benefits. diff --git a/tests/compile-fail/stacked_borrows/illegal_read4.rs b/tests/compile-fail/stacked_borrows/illegal_read4.rs new file mode 100644 index 000000000000..c86ec1286daa --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read4.rs @@ -0,0 +1,9 @@ +// Using a raw invalidates derived `&mut` even for reading. +fn main() { + let mut x = 2; + let xref1 = &mut x; + let xraw = xref1 as *mut _; + let xref2 = unsafe { &mut *xraw }; + let _val = unsafe { *xraw }; // use the raw again, this invalidates xref2 *even* with the special read except for uniq refs + let _illegal = *xref2; //~ ERROR does not exist on the stack +} diff --git a/tests/run-pass/stacked-borrows.rs b/tests/run-pass/stacked-borrows.rs index 00b21c746c26..7b7a7c9be203 100644 --- a/tests/run-pass/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows.rs @@ -6,6 +6,7 @@ fn main() { ref_raw_int_raw(); mut_shr_raw(); mut_raw_then_mut_shr(); + mut_raw_mut(); } // Deref a raw ptr to access a field of a large struct, where the field @@ -76,3 +77,25 @@ fn mut_raw_then_mut_shr() { } assert_eq!(x, 4); } + +// Ensure that if we derive from a mut a raw, and then from that a mut, +// and then read through the original mut, that does not invalidate the raw. +// This shows that the read-exception for `&mut` applies even if the `Shr` item +// on the stack is not at the top. +fn mut_raw_mut() { + let mut x = 2; + { + let xref1 = &mut x; + let xraw = xref1 as *mut _; + let _xref2 = unsafe { &mut *xraw }; + let _val = *xref1; + unsafe { *xraw = 4; } + // we can now use both xraw and xref1, for reading + assert_eq!(*xref1, 4); + assert_eq!(unsafe { *xraw }, 4); + assert_eq!(*xref1, 4); + assert_eq!(unsafe { *xraw }, 4); + // we cannot use xref2; see `compile-fail/stacked-borows/illegal_read4.rs` + } + assert_eq!(x, 4); +} From 224d03dbdc642a60a3326c7bb9b9206082d4cda4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 8 Nov 2018 08:58:03 +0100 Subject: [PATCH 0362/5092] organize std tests a bit better --- tests/run-pass/rc.rs | 35 +++++++++++++++++++++++++++++++++-- tests/run-pass/refcell.rs | 6 +++++- tests/run-pass/std.rs | 34 ---------------------------------- 3 files changed, 38 insertions(+), 37 deletions(-) delete mode 100644 tests/run-pass/std.rs diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index 0bf707503112..bc89d752e0b6 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -1,13 +1,33 @@ -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; use std::rc::Rc; +use std::sync::Arc; fn rc_refcell() { let r = Rc::new(RefCell::new(42)); + let r2 = r.clone(); *r.borrow_mut() += 10; - let x = *r.borrow(); + let x = *r2.borrow(); assert_eq!(x, 52); } +fn rc_cell() { + let r = Rc::new(Cell::new(42)); + let r2 = r.clone(); + let x = r.get(); + r2.set(x + x); + assert_eq!(r.get(), 84); +} + +fn rc_refcell2() { + let r = Rc::new(RefCell::new(42)); + let r2 = r.clone(); + *r.borrow_mut() += 10; + let x = r2.borrow(); + let r3 = r.clone(); + let y = r3.borrow(); + assert_eq!((*x + *y)/2, 52); +} + fn rc_raw() { let r = Rc::new(0); let r2 = Rc::into_raw(r.clone()); @@ -17,6 +37,14 @@ fn rc_raw() { assert!(Rc::try_unwrap(r2).is_ok()); } +fn arc() { + fn test() -> Arc { + let a = Arc::new(42); + a + } + assert_eq!(*test(), 42); +} + // Make sure this Rc doesn't fall apart when touched fn check_unique_rc(mut r: Rc) { let r2 = r.clone(); @@ -34,6 +62,9 @@ fn rc_from() { fn main() { rc_refcell(); + rc_refcell2(); + rc_cell(); rc_raw(); rc_from(); + arc(); } diff --git a/tests/run-pass/refcell.rs b/tests/run-pass/refcell.rs index 93cef1572a3e..52dcdbd36d0f 100644 --- a/tests/run-pass/refcell.rs +++ b/tests/run-pass/refcell.rs @@ -1,6 +1,6 @@ use std::cell::RefCell; -fn main() { +fn lots_of_funny_borrows() { let c = RefCell::new(42); { let s1 = c.borrow(); @@ -31,3 +31,7 @@ fn main() { let _y: i32 = *s2; } } + +fn main() { + lots_of_funny_borrows(); +} diff --git a/tests/run-pass/std.rs b/tests/run-pass/std.rs deleted file mode 100644 index 7ff967b29f34..000000000000 --- a/tests/run-pass/std.rs +++ /dev/null @@ -1,34 +0,0 @@ -use std::cell::{Cell, RefCell}; -use std::rc::Rc; -use std::sync::Arc; - -fn rc_cell() -> Rc> { - let r = Rc::new(Cell::new(42)); - let x = r.get(); - r.set(x + x); - r -} - -fn rc_refcell() -> i32 { - let r = Rc::new(RefCell::new(42)); - *r.borrow_mut() += 10; - let x = r.borrow(); - let y = r.borrow(); - (*x + *y)/2 -} - -fn arc() -> Arc { - let a = Arc::new(42); - a -} - -fn true_assert() { - assert_eq!(1, 1); -} - -fn main() { - assert_eq!(*arc(), 42); - assert_eq!(rc_cell().get(), 84); - assert_eq!(rc_refcell(), 52); - true_assert(); -} From a87e9521029fdc319b5c86680d6645f411751943 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Nov 2018 10:53:28 +0100 Subject: [PATCH 0363/5092] Separate deref and access into different operations; add special exception for creating raw references --- src/lib.rs | 14 +- src/stacked_borrows.rs | 423 +++++++++--------- .../stacked_borrows/alias_through_mutation.rs | 2 +- .../stacked_borrows/illegal_read5.rs | 16 + .../stacked_borrows/illegal_write1.rs | 2 +- .../stacked_borrows/illegal_write3.rs | 2 +- .../stacked_borrows/illegal_write4.rs | 2 +- .../stacked_borrows/illegal_write5.rs | 2 +- .../stacked_borrows/load_invalid_mut.rs | 2 +- .../stacked_borrows/load_invalid_shr.rs | 4 +- .../stacked_borrows/pass_invalid_mut.rs | 2 +- .../stacked_borrows/pass_invalid_shr.rs | 6 +- .../stacked_borrows/return_invalid_mut.rs | 2 +- .../stacked_borrows/return_invalid_shr.rs | 4 +- tests/compiletest.rs | 4 +- tests/run-pass/refcell.rs | 17 + 16 files changed, 280 insertions(+), 224 deletions(-) create mode 100644 tests/compile-fail/stacked_borrows/illegal_read5.rs diff --git a/src/lib.rs b/src/lib.rs index e8691409b1ab..a0ed7c8e4fdb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -308,16 +308,18 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { // Some functions are whitelisted until we figure out how to fix them. // We walk up the stack a few frames to also cover their callees. - const WHITELIST: &[&str] = &[ + const WHITELIST: &[(&str, &str)] = &[ // Uses mem::uninitialized - "std::ptr::read", - "std::sys::windows::mutex::Mutex::", + ("std::ptr::read", ""), + ("std::sys::windows::mutex::Mutex::", ""), + // Should directly take a raw reference + (">", "::get"), ]; for frame in ecx.stack().iter() .rev().take(3) { let name = frame.instance.to_string(); - if WHITELIST.iter().any(|white| name.starts_with(white)) { + if WHITELIST.iter().any(|(prefix, suffix)| name.starts_with(prefix) && name.ends_with(suffix)) { return false; } } @@ -453,7 +455,9 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { let (size, _) = ecx.size_and_align_of_mplace(place)? // for extern types, just cover what we can .unwrap_or_else(|| place.layout.size_and_align()); - if !ecx.machine.validate || size == Size::ZERO { + if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || + !Self::enforce_validity(ecx) || size == Size::ZERO + { // No tracking Ok(place.ptr) } else { diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 56688ca10f49..ab536b5785c9 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -1,10 +1,10 @@ use std::cell::RefCell; use rustc::ty::{self, layout::Size}; -use rustc::hir; +use rustc::hir::{Mutability, MutMutable, MutImmutable}; use crate::{ - EvalResult, MiriEvalContext, HelpersEvalContextExt, + EvalResult, EvalErrorKind, MiriEvalContext, HelpersEvalContextExt, MemoryKind, MiriMemoryKind, RangeMap, AllocId, Allocation, AllocationExtra, Pointer, MemPlace, Scalar, Immediate, ImmTy, PlaceTy, MPlaceTy, }; @@ -27,7 +27,7 @@ pub enum Borrow { impl Borrow { #[inline(always)] - pub fn is_shr(self) -> bool { + pub fn is_shared(self) -> bool { match self { Borrow::Shr(_) => true, _ => false, @@ -35,7 +35,7 @@ impl Borrow { } #[inline(always)] - pub fn is_uniq(self) -> bool { + pub fn is_unique(self) -> bool { match self { Borrow::Uniq(_) => true, _ => false, @@ -96,27 +96,17 @@ impl Stack { } } -/// What kind of usage of the pointer are we talking about? +/// What kind of reference is being used? #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -pub enum UsageKind { - /// Write, or create &mut - Write, - /// Read, or create & - Read, - /// Create * (raw ptr) +pub enum RefKind { + /// &mut + Unique, + /// & without interior mutability + Frozen, + /// * (raw pointer) or & to `UnsafeCell` Raw, } -impl From> for UsageKind { - fn from(mutbl: Option) -> Self { - match mutbl { - None => UsageKind::Raw, - Some(hir::MutMutable) => UsageKind::Write, - Some(hir::MutImmutable) => UsageKind::Read, - } - } -} - /// Extra global machine state #[derive(Clone, Debug)] pub struct State { @@ -127,6 +117,12 @@ impl State { pub fn new() -> State { State { clock: 0 } } + + fn increment_clock(&mut self) -> Timestamp { + let val = self.clock; + self.clock = val + 1; + val + } } /// Extra per-allocation state @@ -136,52 +132,45 @@ pub struct Stacks { stacks: RefCell>, } -/// Core operations +/// Core per-location operations: deref, access, create. +/// We need to make at least the following things true: +/// +/// U1: After creating a Uniq, it is at the top (+unfrozen). +/// U2: If the top is Uniq (+unfrozen), accesses must be through that Uniq or pop it. +/// U3: If an access (deref sufficient?) happens with a Uniq, it requires the Uniq to be in the stack. +/// +/// F1: After creating a &, the parts outside `UnsafeCell` are frozen. +/// F2: If a write access happens, it unfreezes. +/// F3: If an access (well, a deref) happens with an & outside `UnsafeCell`, it requires the location to still be frozen. impl<'tcx> Stack { - /// Check if `bor` could be activated by unfreezing and popping. - /// `is_write` indicates whether this is being used to write (or, equivalently, to - /// borrow as &mut). - /// Returns `Err` if the answer is "no"; otherwise the return value indicates what to - /// do: With `Some(n)` you need to unfreeze, and then additionally pop `n` items. - fn reactivatable(&self, bor: Borrow, is_write: bool) -> Result, String> { - // Check if we can match the frozen "item". Not possible on writes! - if !is_write { - // For now, we do NOT check the timestamp. That might be surprising, but - // we cannot even notice when a location should be frozen but is not! - // Those checks are both done in `tag_dereference`, where we have type information. - // Either way, it is crucial that the frozen "item" matches raw pointers: - // Reading through a raw should not unfreeze. - match (self.frozen_since, bor) { - (Some(_), Borrow::Shr(_)) => { - return Ok(None) + /// Deref `bor`: Check if the location is frozen and the tag in the stack. + /// This dos *not* constitute an access! "Deref" refers to the `*` operator + /// in Rust, and includs cases like `&*x` or `(*x).foo` where no or only part + /// of the memory actually gets accessed. Also we cannot know if we are + /// going to read or write. + /// Returns the index of the item we matched, `None` if it was the frozen one. + /// `kind` indicates which kind of reference is being dereferenced. + fn deref(&self, bor: Borrow, kind: RefKind) -> Result, String> { + // Checks related to freezing + match bor { + Borrow::Shr(Some(bor_t)) if kind == RefKind::Frozen => { + // We need the location to be frozen. This ensures F3. + let frozen = self.frozen_since.map_or(false, |itm_t| itm_t <= bor_t); + return if frozen { Ok(None) } else { + Err(format!("Location is not frozen long enough")) } - _ => {}, } + Borrow::Shr(_) if self.frozen_since.is_some() => { + return Ok(None) // Shared deref to frozen location, looking good + } + _ => {} // Not sufficient, go on looking. } - // See if we can find this borrow. - for (idx, &itm) in self.borrows.iter().rev().enumerate() { - // Check borrow and stack item for compatibility. + // If we got here, we have to look for our item in the stack. + for (idx, &itm) in self.borrows.iter().enumerate().rev() { match (itm, bor) { - (BorStackItem::FnBarrier(_), _) => { - return Err(format!("Trying to reactivate a borrow ({:?}) that lives \ - behind a barrier", bor)) - } + (BorStackItem::FnBarrier(_), _) => break, (BorStackItem::Uniq(itm_t), Borrow::Uniq(bor_t)) if itm_t == bor_t => { - // Found matching unique item. This is *always* required to use a `Uniq`: - // The item must still be on the stack. - if !is_write { - // As a special case, if we are reading, let us see if it would be - // beneficial to pretend we are a raw pointer instead. If - // raw pointers are allowed to read while popping *less* than we - // would have to pop, there is no reason not to let them do this. - match self.reactivatable(Borrow::default(), is_write) { - // If we got something better (popping less) that `idx`, use that - Ok(None) => return Ok(None), - Ok(Some(shr_idx)) if shr_idx <= idx => return Ok(Some(shr_idx)), - // Otherwise just go on. - _ => {}, - } - } + // Found matching unique item. This satisfies U3. return Ok(Some(idx)) } (BorStackItem::Shr, Borrow::Shr(_)) => { @@ -192,154 +181,182 @@ impl<'tcx> Stack { _ => {} } } - // Nothing to be found. - Err(format!("Borrow-to-reactivate {:?} does not exist on the stack", bor)) + // If we got here, we did not find our item. We have to error to satisfy U3. + Err(format!( + "Borrow being dereferenced ({:?}) does not exist on the stack, or is guarded by a barrier", + bor + )) } - /// Reactive `bor` for this stack. `is_write` indicates whether this is being - /// used to write (or, equivalently, to borrow as &mut). - fn reactivate(&mut self, bor: Borrow, is_write: bool) -> EvalResult<'tcx> { - let mut pop = match self.reactivatable(bor, is_write) { - Ok(None) => return Ok(()), - Ok(Some(pop)) => pop, - Err(err) => return err!(MachineError(err)), - }; - // Pop what `reactivatable` told us to pop. Always unfreeze. + /// Perform an actual memory access using `bor`. We do not know any types here + /// or whether things should be frozen, but we *do* know if this is reading + /// or writing. + fn access(&mut self, bor: Borrow, is_write: bool) -> EvalResult<'tcx> { + // Check if we can match the frozen "item". + // Not possible on writes! if self.is_frozen() { - trace!("reactivate: Unfreezing"); + if !is_write { + // When we are frozen, we just accept all reads. No harm in this. + // The deref already checked that `Uniq` items are in the stack, and that + // the location is frozen if it should be. + return Ok(()); + } + trace!("access: Unfreezing"); } + // Unfreeze on writes. This ensures F2. self.frozen_since = None; - while pop > 0 { - let itm = self.borrows.pop().unwrap(); - trace!("reactivate: Popping {:?}", itm); - pop -= 1; + // Pop the stack until we have something matching. + while let Some(&itm) = self.borrows.last() { + match (itm, bor) { + (BorStackItem::FnBarrier(_), _) => break, + (BorStackItem::Uniq(itm_t), Borrow::Uniq(bor_t)) if itm_t == bor_t => { + // Found matching unique item. + return Ok(()) + } + (BorStackItem::Shr, _) if !is_write => { + // When reading, everything can use a shared item! + // We do not want to do this when writing: Writing to an `&mut` + // should reaffirm its exclusivity (i.e., make sure it is + // on top of the stack). + return Ok(()) + } + (BorStackItem::Shr, Borrow::Shr(_)) => { + // Found matching shared item. + return Ok(()) + } + _ => { + // Pop this. This ensures U2. + let itm = self.borrows.pop().unwrap(); + trace!("access: Popping {:?}", itm); + } + } } - Ok(()) + // If we got here, we did not find our item. + err!(MachineError(format!( + "Borrow being accessed ({:?}) does not exist on the stack, or is guarded by a barrier", + bor + ))) } /// Initiate `bor`; mostly this means pushing. /// This operation cannot fail; it is up to the caller to ensure that the precondition /// is met: We cannot push `Uniq` onto frozen stacks. - /// Crucially, this makes pushing a `Shr` onto a frozen location a NOP. We do not want - /// such a location to get mutably shared this way! - fn initiate(&mut self, bor: Borrow) { - if let Some(_) = self.frozen_since { + /// `kind` indicates which kind of reference is being created. + fn create(&mut self, bor: Borrow, kind: RefKind) { + // First, push the item. We do this even if we will later freeze, because we + // will allow mutation of shared data at the expense of unfreezing. + if let Some(itm_t) = self.frozen_since { // A frozen location, we won't change anything here! match bor { Borrow::Uniq(_) => bug!("Trying to create unique ref to frozen location"), - Borrow::Shr(_) => trace!("initiate: New shared ref to frozen location is a NOP"), + Borrow::Shr(Some(bor_t)) if kind == RefKind::Frozen => { + // Make sure we are frozen long enough. This is part 1 of ensuring F1. + assert!(itm_t <= bor_t, "Trying to freeze shorter than it was frozen?"); + trace!("create: Freezing a frozen location is a NOP"); + } + Borrow::Shr(_) => trace!("create: Sharing a frozen location is a NOP"), } } else { - // Just push. + // First push. let itm = match bor { Borrow::Uniq(t) => BorStackItem::Uniq(t), - Borrow::Shr(_) if *self.borrows.last().unwrap() == BorStackItem::Shr => { - // Optimization: Don't push a Shr onto a Shr. - trace!("initiate: New shared ref to already shared location is a NOP"); - return - }, Borrow::Shr(_) => BorStackItem::Shr, }; - trace!("initiate: Pushing {:?}", itm); - self.borrows.push(itm) - } - } - - /// Check if this location is "frozen enough". - fn check_frozen(&self, bor_t: Timestamp) -> EvalResult<'tcx> { - let frozen = self.frozen_since.map_or(false, |itm_t| itm_t <= bor_t); - if !frozen { - err!(MachineError(format!("Location is not frozen long enough"))) - } else { - Ok(()) - } - } - - /// Freeze this location, since `bor_t`. - fn freeze(&mut self, bor_t: Timestamp) { - if let Some(itm_t) = self.frozen_since { - assert!(itm_t <= bor_t, "Trying to freeze shorter than it was frozen?"); - } else { - trace!("Freezing"); - self.frozen_since = Some(bor_t); + if *self.borrows.last().unwrap() == itm { + assert!(bor.is_shared()); + trace!("create: Sharing a shared location is a NOP"); + } else { + // This ensures U1. + trace!("create: Pushing {:?}", itm); + self.borrows.push(itm); + } + // Now, maybe freeze. This is part 2 of ensuring F1. + if kind == RefKind::Frozen { + let bor_t = match bor { + Borrow::Shr(Some(t)) => t, + _ => bug!("Creating illegal borrow {:?} for frozen ref", bor), + }; + trace!("create: Freezing"); + self.frozen_since = Some(bor_t); + } } } } -impl State { - fn increment_clock(&mut self) -> Timestamp { - let val = self.clock; - self.clock = val + 1; - val - } -} - -/// Higher-level operations +/// Higher-level per-location operations: deref, access, reborrow. impl<'tcx> Stacks { - /// `ptr` got used, reflect that in the stack. - fn reactivate( + /// Check that this stack is fine with being dereferenced + fn deref( &self, ptr: Pointer, size: Size, - usage: UsageKind, + kind: RefKind, ) -> EvalResult<'tcx> { - trace!("use_borrow of tag {:?} as {:?}: {:?}, size {}", - ptr.tag, usage, ptr, size.bytes()); + trace!("deref for tag {:?} as {:?}: {:?}, size {}", + ptr.tag, kind, ptr, size.bytes()); let mut stacks = self.stacks.borrow_mut(); + // We need `iter_mut` because `iter` would skip gaps! for stack in stacks.iter_mut(ptr.offset, size) { - stack.reactivate(ptr.tag, usage == UsageKind::Write)?; + stack.deref(ptr.tag, kind).map_err(EvalErrorKind::MachineError)?; } Ok(()) } - /// Create a new borrow, the ptr must already have the new tag. - /// Also freezes the location if `freeze` is set and the tag is a timestamped `Shr`. - fn initiate( + /// `ptr` got used, reflect that in the stack. + fn access( &self, ptr: Pointer, size: Size, - freeze: bool, - ) { - trace!("reborrow for tag {:?}: {:?}, size {}", + is_write: bool, + ) -> EvalResult<'tcx> { + trace!("{} access of tag {:?}: {:?}, size {}", + if is_write { "read" } else { "write" }, ptr.tag, ptr, size.bytes()); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { - stack.initiate(ptr.tag); - if freeze { - if let Borrow::Shr(Some(bor_t)) = ptr.tag { - stack.freeze(bor_t); - } - } + stack.access(ptr.tag, is_write)?; } + Ok(()) } - /// Check that this stack is fine with being dereferenced - fn check_deref( + /// Reborrow the given pointer to the new tag for the given kind of reference. + fn reborrow( &self, ptr: Pointer, size: Size, - frozen: bool, + new_bor: Borrow, + new_kind: RefKind, ) -> EvalResult<'tcx> { + trace!("reborrow for tag {:?} to {:?} as {:?}: {:?}, size {}", + ptr.tag, new_bor, new_kind, ptr, size.bytes()); let mut stacks = self.stacks.borrow_mut(); - // We need `iter_mut` because `iter` would skip gaps! for stack in stacks.iter_mut(ptr.offset, size) { - // Conservatively assume we will just read - if let Err(err) = stack.reactivatable(ptr.tag, /*is_write*/false) { - return err!(MachineError(format!( - "Encountered reference with non-reactivatable tag: {}", - err - ))) - } - // Sometimes we also need to be frozen. - // In this case we *both* push `Shr` and then freeze. This means that a `&mut` - // to `*const` to `*mut` cast through `&` actually works. - if frozen { - // Even shared refs can have uniq tags (after transmute). That's not an error - // but they do not get any freezing benefits. - if let Borrow::Shr(Some(bor_t)) = ptr.tag { - stack.check_frozen(bor_t)?; + // Access source `ptr`, create new ref. + let ptr_idx = stack.deref(ptr.tag, new_kind).map_err(EvalErrorKind::MachineError)?; + if new_kind == RefKind::Raw { + assert!(new_bor.is_shared()); + // Raw references do not get quite as many guarantees as the other kinds: + // If we can deref the new tag already, and if that tag lives higher on + // the stack than the one we come from, just use that. + // IOW, we check if `new_bor` *already* is "derived from" `ptr.tag`. + match (ptr_idx, stack.deref(new_bor, new_kind)) { + // If the new borrow works with the forzen item, or else if it lives + // above the old one in the stack, our job here is done. + (_, Ok(None)) => { + trace!("reborrow-to-raw on a frozen location is a NOP"); + continue + }, + (Some(ptr_idx), Ok(Some(new_idx))) if new_idx >= ptr_idx => { + trace!("reborrow-to-raw is a NOP because the src ptr already got reborrowed-to-raw"); + continue + }, + _ => {}, } } + // Non-raw reborrows should behave exactly as if we also did a + // read/write to the given location. + stack.access(ptr.tag, new_kind == RefKind::Unique)?; + stack.create(new_bor, new_kind); } Ok(()) } @@ -353,8 +370,7 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - // Reads behave exactly like the first half of a reborrow-to-shr - alloc.extra.reactivate(ptr, size, UsageKind::Read) + alloc.extra.access(ptr, size, /*is_write*/false) } #[inline(always)] @@ -363,8 +379,7 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - // Writes behave exactly like the first half of a reborrow-to-mut - alloc.extra.reactivate(ptr, size, UsageKind::Read) + alloc.extra.access(ptr, size, /*is_write*/true) } #[inline(always)] @@ -374,7 +389,7 @@ impl AllocationExtra for Stacks { size: Size, ) -> EvalResult<'tcx> { // This is like mutating - alloc.extra.reactivate(ptr, size, UsageKind::Write) + alloc.extra.access(ptr, size, /*is_write*/true) // FIXME: Error out of there are any barriers? } } @@ -402,7 +417,7 @@ pub trait EvalContextExt<'tcx> { &self, place: MPlaceTy<'tcx, Borrow>, size: Size, - usage: UsageKind, + mutability: Option, ) -> EvalResult<'tcx, Borrow>; fn tag_new_allocation( @@ -412,10 +427,10 @@ pub trait EvalContextExt<'tcx> { ) -> Borrow; /// Retag an indidual pointer, returning the retagged version. - fn retag_ptr( + fn reborrow( &mut self, ptr: ImmTy<'tcx, Borrow>, - mutbl: hir::Mutability, + mutbl: Mutability, ) -> EvalResult<'tcx, Immediate>; fn retag( @@ -461,7 +476,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { Borrow::Uniq(time) } - /// Called for value-to-place conversion. + /// Called for value-to-place conversion. `mutability` is `None` for raw pointers. /// /// Note that this does NOT mean that all this memory will actually get accessed/referenced! /// We could be in the middle of `&(*var).1`. @@ -469,38 +484,41 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { &self, place: MPlaceTy<'tcx, Borrow>, size: Size, - usage: UsageKind, + mutability: Option, ) -> EvalResult<'tcx, Borrow> { - trace!("tag_dereference: Accessing reference ({:?}) for {:?} (pointee {})", - usage, place.ptr, place.layout.ty); + trace!("tag_dereference: Accessing {} reference for {:?} (pointee {})", + if let Some(mutability) = mutability { format!("{:?}", mutability) } else { format!("raw") }, + place.ptr, place.layout.ty); let ptr = place.ptr.to_ptr()?; // In principle we should not have to do anything here. However, with transmutes involved, - // it can happen that the tag of `ptr` does not actually match `usage`, and we + // it can happen that the tag of `ptr` does not actually match `mutability`, and we // should adjust for that. // Notably, the compiler can introduce such transmutes by optimizing away `&[mut]*`. // That can transmute a raw ptr to a (shared/mut) ref, and a mut ref to a shared one. - match (usage, ptr.tag) { - (UsageKind::Raw, _) => { + match (mutability, ptr.tag) { + (None, _) => { // Don't use the tag, this is a raw access! They should happen tagless. + // This is needed for `*mut` to make any sense: Writes *do* enforce the + // `Uniq` tag to be up top, but we must make sure raw writes do not do that. // This does mean, however, that `&*foo` is *not* a NOP *if* `foo` is a raw ptr. // Also don't do any further validation, this is raw after all. return Ok(Borrow::default()); } - (UsageKind::Write, Borrow::Uniq(_)) | - (UsageKind::Read, Borrow::Shr(_)) => { + (Some(MutMutable), Borrow::Uniq(_)) | + (Some(MutImmutable), Borrow::Shr(_)) => { // Expected combinations. Nothing to do. } - (UsageKind::Write, Borrow::Shr(None)) => { + (Some(MutMutable), Borrow::Shr(None)) => { // Raw transmuted to mut ref. Keep this as raw access. // We cannot reborrow here; there might be a raw in `&(*var).1` where // `var` is an `&mut`. The other field of the struct might be already frozen, // also using `var`, and that would be okay. } - (UsageKind::Read, Borrow::Uniq(_)) => { + (Some(MutImmutable), Borrow::Uniq(_)) => { // A mut got transmuted to shr. Can happen even from compiler transformations: // `&*x` gets optimized to `x` even when `x` is a `&mut`. } - (UsageKind::Write, Borrow::Shr(Some(_))) => { + (Some(MutMutable), Borrow::Shr(Some(_))) => { // This is just invalid: A shr got transmuted to a mut. // If we ever allow this, we have to consider what we do when a turn a // `Raw`-tagged `&mut` into a raw pointer pointing to a frozen location. @@ -515,13 +533,16 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); // If we got here, we do some checking, *but* we leave the tag unchanged. if let Borrow::Shr(Some(_)) = ptr.tag { + assert_eq!(mutability, Some(MutImmutable)); // We need a frozen-sensitive check self.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { - alloc.extra.check_deref(cur_ptr, size, frozen) + let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; + alloc.extra.deref(cur_ptr, size, kind) })?; } else { // Just treat this as one big chunk - alloc.extra.check_deref(ptr, size, /*frozen*/false)?; + let kind = if mutability == Some(MutMutable) { RefKind::Unique } else { RefKind::Raw }; + alloc.extra.deref(ptr, size, kind)?; } // All is good, and do not change the tag @@ -534,23 +555,20 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { place: MPlaceTy<'tcx, Borrow>, size: Size, ) -> EvalResult<'tcx> { - trace!("self: {:?} is now accessible by raw pointers", *place); + trace!("escape_to_raw: {:?} is now accessible by raw pointers", *place); // Get the allocation - let mut ptr = place.ptr.to_ptr()?; + let ptr = place.ptr.to_ptr()?; self.memory().check_bounds(ptr, size, false)?; // `ptr_dereference` wouldn't do any checks if this is a raw ptr let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); // Re-borrow to raw. This is a NOP for shared borrows, but we do not know the borrow // type here and that's also okay. Freezing does not matter here. - alloc.extra.reactivate(ptr, size, UsageKind::Raw)?; - ptr.tag = Borrow::default(); - alloc.extra.initiate(ptr, size, /*freeze*/false); - Ok(()) + alloc.extra.reborrow(ptr, size, Borrow::default(), RefKind::Raw) } - fn retag_ptr( + fn reborrow( &mut self, val: ImmTy<'tcx, Borrow>, - mutbl: hir::Mutability, + mutbl: Mutability, ) -> EvalResult<'tcx, Immediate> { // We want a place for where the ptr *points to*, so we get one. let place = self.ref_to_mplace(val)?; @@ -566,30 +584,29 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { let ptr = place.ptr.to_ptr()?; let time = self.machine.stacked_borrows.increment_clock(); let new_bor = match mutbl { - hir::MutMutable => Borrow::Uniq(time), - hir::MutImmutable => Borrow::Shr(Some(time)), + MutMutable => Borrow::Uniq(time), + MutImmutable => Borrow::Shr(Some(time)), }; - let new_ptr = Pointer::new_with_tag(ptr.alloc_id, ptr.offset, new_bor); - trace!("retag: Creating new reference ({:?}) for {:?} (pointee {}): {:?}", + trace!("reborrow: Creating new {:?} reference for {:?} (pointee {}): {:?}", mutbl, ptr, place.layout.ty, new_bor); - // Get the allocation - self.memory().check_bounds(ptr, size, false)?; // `ptr_dereference` wouldn't do any checks if this is a raw ptr + // Get the allocation. It might not be mutable, so we cannot use `get_mut`. + self.memory().check_bounds(ptr, size, false)?; let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); - // Update the stacks. First use old borrow, then initiate new one. - alloc.extra.reactivate(ptr, size, Some(mutbl).into())?; - if mutbl == hir::MutImmutable { - // We need a frozen-sensitive initiate - self.visit_freeze_sensitive(place, size, |mut cur_ptr, size, frozen| { - cur_ptr.tag = new_bor; - Ok(alloc.extra.initiate(cur_ptr, size, frozen)) + // Update the stacks. + if mutbl == MutImmutable { + // Shared reference. We need a frozen-sensitive reborrow. + self.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { + let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; + alloc.extra.reborrow(cur_ptr, size, new_bor, kind) })?; } else { - // Just treat this as one big chunk - alloc.extra.initiate(new_ptr, size, /*frozen*/false); + // Mutable reference. Just treat this as one big chunk. + alloc.extra.reborrow(ptr, size, new_bor, RefKind::Unique)?; } // Return new ptr + let new_ptr = Pointer::new_with_tag(ptr.alloc_id, ptr.offset, new_bor); let new_place = MemPlace { ptr: Scalar::Ptr(new_ptr), ..*place }; Ok(new_place.to_ref()) } @@ -608,7 +625,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { }; // Retag the pointer and write it back. let val = self.read_immediate(self.place_to_op(place)?)?; - let val = self.retag_ptr(val, mutbl)?; + let val = self.reborrow(val, mutbl)?; self.write_immediate(val, place)?; Ok(()) } diff --git a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs index 0b2d459366ce..092f3f09ed19 100644 --- a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs +++ b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs @@ -11,5 +11,5 @@ fn main() { retarget(&mut target_alias, target); // now `target_alias` points to the same thing as `target` *target = 13; - let _val = *target_alias; //~ ERROR reference with non-reactivatable tag + let _val = *target_alias; //~ ERROR does not exist on the stack } diff --git a/tests/compile-fail/stacked_borrows/illegal_read5.rs b/tests/compile-fail/stacked_borrows/illegal_read5.rs new file mode 100644 index 000000000000..863649a47b5e --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read5.rs @@ -0,0 +1,16 @@ +// We *can* have aliasing &RefCell and &mut T, but we cannot read through the former. +// Else we couldn't optimize based on the assumption that `xref` below is truly unique. + +use std::cell::RefCell; +use std::{mem, ptr}; + +fn main() { + let rc = RefCell::new(0); + let mut refmut = rc.borrow_mut(); + let xref: &mut i32 = &mut *refmut; + let xshr = &rc; // creating this is okay + let _val = *xref; // we can even still use our mutable reference + mem::forget(unsafe { ptr::read(xshr) }); // but after reading through the shared ref + let _val = *xref; // the mutable one is dead and gone + //~^ ERROR does not exist on the stack +} diff --git a/tests/compile-fail/stacked_borrows/illegal_write1.rs b/tests/compile-fail/stacked_borrows/illegal_write1.rs index 7378907fa745..b106cc8dc403 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write1.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write1.rs @@ -8,5 +8,5 @@ fn main() { let target = Box::new(42); // has an implicit raw let ref_ = &*target; evil(ref_); // invalidates shared ref, activates raw - let _x = *ref_; //~ ERROR is not frozen long enough + let _x = *ref_; //~ ERROR is not frozen } diff --git a/tests/compile-fail/stacked_borrows/illegal_write3.rs b/tests/compile-fail/stacked_borrows/illegal_write3.rs index c82da1e9c467..01559af21e7c 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write3.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write3.rs @@ -4,5 +4,5 @@ fn main() { let r#ref = ⌖ // freeze let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag unsafe { *ptr = 42; } - let _val = *r#ref; //~ ERROR is not frozen long enough + let _val = *r#ref; //~ ERROR is not frozen } diff --git a/tests/compile-fail/stacked_borrows/illegal_write4.rs b/tests/compile-fail/stacked_borrows/illegal_write4.rs index 49bf9279faa2..37ae0f055f0e 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write4.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write4.rs @@ -9,5 +9,5 @@ fn main() { let ptr = reference as *const _ as *mut i32; // raw ptr, with raw tag let _mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag // Now we retag, making our ref top-of-stack -- and, in particular, unfreezing. - let _val = *reference; //~ ERROR is not frozen long enough + let _val = *reference; //~ ERROR is not frozen } diff --git a/tests/compile-fail/stacked_borrows/illegal_write5.rs b/tests/compile-fail/stacked_borrows/illegal_write5.rs index f4704ad57161..57b2ca87d810 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write5.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write5.rs @@ -7,7 +7,7 @@ fn main() { let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. - //~^ ERROR: reference with non-reactivatable tag + //~^ ERROR: does not exist on the stack } fn callee(xraw: *mut i32) { diff --git a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs index d3db462343e8..98b9451eda87 100644 --- a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs @@ -4,6 +4,6 @@ fn main() { let xraw = x as *mut _; let xref = unsafe { &mut *xraw }; let xref_in_mem = Box::new(xref); - let _val = *x; // invalidate xraw + let _val = unsafe { *xraw }; // invalidate xref let _val = *xref_in_mem; //~ ERROR does not exist on the stack } diff --git a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs index 71b578817a77..6599924f0f4c 100644 --- a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs @@ -4,6 +4,6 @@ fn main() { let xraw = x as *mut _; let xref = unsafe { &*xraw }; let xref_in_mem = Box::new(xref); - *x = 42; // invalidate xraw - let _val = *xref_in_mem; //~ ERROR does not exist on the stack + unsafe { *xraw = 42 }; // unfreeze + let _val = *xref_in_mem; //~ ERROR is not frozen } diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs index 41cf89d874d7..28288c6c6362 100644 --- a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs @@ -5,6 +5,6 @@ fn main() { let x = &mut 42; let xraw = x as *mut _; let xref = unsafe { &mut *xraw }; - let _val = *x; // invalidate xraw + let _val = unsafe { *xraw }; // invalidate xref foo(xref); //~ ERROR does not exist on the stack } diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs b/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs index 0bdb1b4a41e5..67bbc88e40fb 100644 --- a/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs @@ -3,8 +3,8 @@ fn foo(_: &i32) {} fn main() { let x = &mut 42; - let xraw = &*x as *const _; + let xraw = &*x as *const _ as *mut _; let xref = unsafe { &*xraw }; - *x = 42; // invalidate xraw - foo(xref); //~ ERROR does not exist on the stack + unsafe { *xraw = 42 }; // unfreeze + foo(xref); //~ ERROR is not frozen } diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs index aef8fafdf5d5..e7f0b9bc9ddd 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs @@ -2,7 +2,7 @@ fn foo(x: &mut (i32, i32)) -> &mut i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &mut (*xraw).1 }; - let _val = *x; // invalidate xraw and its children + let _val = unsafe { *xraw }; // invalidate xref ret //~ ERROR does not exist on the stack } diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr.rs b/tests/compile-fail/stacked_borrows/return_invalid_shr.rs index 074942eb95bc..986dd18b2e0b 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_shr.rs @@ -2,8 +2,8 @@ fn foo(x: &mut (i32, i32)) -> &i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &(*xraw).1 }; - x.1 = 42; // invalidate xraw on the 2nd field - ret //~ ERROR does not exist on the stack + unsafe { *xraw = (42, 23) }; // unfreeze + ret //~ ERROR is not frozen } fn main() { diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 55eaa7bfbab6..f393fcb2c226 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -99,7 +99,9 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: flags.push(format!("--sysroot {}", sysroot.display())); flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs if opt { - flags.push("-Zmir-opt-level=3".to_owned()); + // FIXME: We use opt level 1 because MIR inlining defeats the validation + // whitelist. + flags.push("-Zmir-opt-level=1".to_owned()); } let mut config = mk_config("ui"); diff --git a/tests/run-pass/refcell.rs b/tests/run-pass/refcell.rs index 52dcdbd36d0f..5f2f3523b96b 100644 --- a/tests/run-pass/refcell.rs +++ b/tests/run-pass/refcell.rs @@ -32,6 +32,23 @@ fn lots_of_funny_borrows() { } } +fn aliasing_mut_and_shr() { + fn inner(rc: &RefCell, aliasing: &mut i32) { + *aliasing += 4; + let _escape_to_raw = rc as *const _; + *aliasing += 4; + let _shr = &*rc; + *aliasing += 4; + } + + let rc = RefCell::new(23); + let mut bmut = rc.borrow_mut(); + inner(&rc, &mut *bmut); + drop(bmut); + assert_eq!(*rc.borrow(), 23+12); +} + fn main() { lots_of_funny_borrows(); + aliasing_mut_and_shr(); } From 5a801c0dc1620948108e23ab9c75b75137eb7691 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Nov 2018 16:18:02 +0100 Subject: [PATCH 0364/5092] adjust comment --- src/stacked_borrows.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index ab536b5785c9..f5ae7cb933f9 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -509,10 +509,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { // Expected combinations. Nothing to do. } (Some(MutMutable), Borrow::Shr(None)) => { - // Raw transmuted to mut ref. Keep this as raw access. - // We cannot reborrow here; there might be a raw in `&(*var).1` where - // `var` is an `&mut`. The other field of the struct might be already frozen, - // also using `var`, and that would be okay. + // Raw transmuted to mut ref. This is something real unsafe code does. + // We cannot reborrow here because we do not want to mutate state on a deref. } (Some(MutImmutable), Borrow::Uniq(_)) => { // A mut got transmuted to shr. Can happen even from compiler transformations: From ba8eb7608ea6520238a1d587197a795e9dc7147a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Nov 2018 19:30:35 +0100 Subject: [PATCH 0365/5092] add an interesting demo for &mut being unique --- .../mut_exclusive_violation1.rs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 tests/compile-fail/stacked_borrows/mut_exclusive_violation1.rs diff --git a/tests/compile-fail/stacked_borrows/mut_exclusive_violation1.rs b/tests/compile-fail/stacked_borrows/mut_exclusive_violation1.rs new file mode 100644 index 000000000000..255e35b14558 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/mut_exclusive_violation1.rs @@ -0,0 +1,29 @@ +fn demo_mut_advanced_unique(our: &mut i32) -> i32 { + unknown_code_1(&*our); + + // This "re-asserts" uniqueness of the reference: After writing, we know + // our tag is at the top of the stack. + *our = 5; + + unknown_code_2(); + + // We know this will return 5 + *our +} + +// Now comes the evil context +use std::ptr; + +static mut LEAK: *mut i32 = ptr::null_mut(); + +fn unknown_code_1(x: &i32) { unsafe { + LEAK = x as *const _ as *mut _; +} } + +fn unknown_code_2() { unsafe { + *LEAK = 7; //~ ERROR does not exist on the stack +} } + +fn main() { + assert_eq!(demo_mut_advanced_unique(&mut 0), 5); +} From c234009fddf3a58c486a06f1c40980149df114f7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 13 Nov 2018 13:39:03 +0100 Subject: [PATCH 0366/5092] generalize reborrow-to-raw exception to a general redundancy check --- src/stacked_borrows.rs | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index f5ae7cb933f9..d2abfbc9dfcb 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -333,28 +333,24 @@ impl<'tcx> Stacks { for stack in stacks.iter_mut(ptr.offset, size) { // Access source `ptr`, create new ref. let ptr_idx = stack.deref(ptr.tag, new_kind).map_err(EvalErrorKind::MachineError)?; - if new_kind == RefKind::Raw { - assert!(new_bor.is_shared()); - // Raw references do not get quite as many guarantees as the other kinds: - // If we can deref the new tag already, and if that tag lives higher on - // the stack than the one we come from, just use that. - // IOW, we check if `new_bor` *already* is "derived from" `ptr.tag`. - match (ptr_idx, stack.deref(new_bor, new_kind)) { - // If the new borrow works with the forzen item, or else if it lives - // above the old one in the stack, our job here is done. - (_, Ok(None)) => { - trace!("reborrow-to-raw on a frozen location is a NOP"); - continue - }, - (Some(ptr_idx), Ok(Some(new_idx))) if new_idx >= ptr_idx => { - trace!("reborrow-to-raw is a NOP because the src ptr already got reborrowed-to-raw"); - continue - }, - _ => {}, - } + // If we can deref the new tag already, and if that tag lives higher on + // the stack than the one we come from, just use that. + // IOW, we check if `new_bor` *already* is "derived from" `ptr.tag`. + // This also checks frozenness, if required. + let bor_already_happened = match (ptr_idx, stack.deref(new_bor, new_kind)) { + // If the new borrow works with the frozen item, or else if it lives + // above the old one in the stack, our job here is done. + (_, Ok(None)) => true, + (Some(ptr_idx), Ok(Some(new_idx))) if new_idx >= ptr_idx => true, + // Otherwise we need to create a new borrow. + _ => false, + }; + if bor_already_happened { + assert!(new_bor.is_shared(), "A unique reborrow can never be redundant"); + trace!("Reborrow is a NOP"); + continue; } - // Non-raw reborrows should behave exactly as if we also did a - // read/write to the given location. + // We need to do some actual work. stack.access(ptr.tag, new_kind == RefKind::Unique)?; stack.create(new_bor, new_kind); } From f521fd5e0fbaa54d5a07f61a794a91a0576ff557 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 13 Nov 2018 14:49:04 +0100 Subject: [PATCH 0367/5092] let's call this a redundant reborrow --- src/stacked_borrows.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index d2abfbc9dfcb..8c409030164d 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -337,7 +337,7 @@ impl<'tcx> Stacks { // the stack than the one we come from, just use that. // IOW, we check if `new_bor` *already* is "derived from" `ptr.tag`. // This also checks frozenness, if required. - let bor_already_happened = match (ptr_idx, stack.deref(new_bor, new_kind)) { + let bor_redundant = match (ptr_idx, stack.deref(new_bor, new_kind)) { // If the new borrow works with the frozen item, or else if it lives // above the old one in the stack, our job here is done. (_, Ok(None)) => true, @@ -345,9 +345,9 @@ impl<'tcx> Stacks { // Otherwise we need to create a new borrow. _ => false, }; - if bor_already_happened { + if bor_redundant { assert!(new_bor.is_shared(), "A unique reborrow can never be redundant"); - trace!("Reborrow is a NOP"); + trace!("reborrow is redundant"); continue; } // We need to do some actual work. From cf1746222ee01eefb8c076fd48f05755b4cdc81a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 13 Nov 2018 17:05:47 +0100 Subject: [PATCH 0368/5092] we no longer even try pushing to a frozen location --- src/stacked_borrows.rs | 55 ++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 8c409030164d..3790b5d13fed 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -245,40 +245,31 @@ impl<'tcx> Stack { fn create(&mut self, bor: Borrow, kind: RefKind) { // First, push the item. We do this even if we will later freeze, because we // will allow mutation of shared data at the expense of unfreezing. - if let Some(itm_t) = self.frozen_since { - // A frozen location, we won't change anything here! - match bor { - Borrow::Uniq(_) => bug!("Trying to create unique ref to frozen location"), - Borrow::Shr(Some(bor_t)) if kind == RefKind::Frozen => { - // Make sure we are frozen long enough. This is part 1 of ensuring F1. - assert!(itm_t <= bor_t, "Trying to freeze shorter than it was frozen?"); - trace!("create: Freezing a frozen location is a NOP"); - } - Borrow::Shr(_) => trace!("create: Sharing a frozen location is a NOP"), - } + if self.frozen_since.is_some() { + // A frozen location, this should be impossible! + bug!("We should never try pushing to a frozen stack"); + } + // First, push. + let itm = match bor { + Borrow::Uniq(t) => BorStackItem::Uniq(t), + Borrow::Shr(_) => BorStackItem::Shr, + }; + if *self.borrows.last().unwrap() == itm { + assert!(bor.is_shared()); + trace!("create: Sharing a shared location is a NOP"); } else { - // First push. - let itm = match bor { - Borrow::Uniq(t) => BorStackItem::Uniq(t), - Borrow::Shr(_) => BorStackItem::Shr, + // This ensures U1. + trace!("create: Pushing {:?}", itm); + self.borrows.push(itm); + } + // Then, maybe freeze. This is part 2 of ensuring F1. + if kind == RefKind::Frozen { + let bor_t = match bor { + Borrow::Shr(Some(t)) => t, + _ => bug!("Creating illegal borrow {:?} for frozen ref", bor), }; - if *self.borrows.last().unwrap() == itm { - assert!(bor.is_shared()); - trace!("create: Sharing a shared location is a NOP"); - } else { - // This ensures U1. - trace!("create: Pushing {:?}", itm); - self.borrows.push(itm); - } - // Now, maybe freeze. This is part 2 of ensuring F1. - if kind == RefKind::Frozen { - let bor_t = match bor { - Borrow::Shr(Some(t)) => t, - _ => bug!("Creating illegal borrow {:?} for frozen ref", bor), - }; - trace!("create: Freezing"); - self.frozen_since = Some(bor_t); - } + trace!("create: Freezing"); + self.frozen_since = Some(bor_t); } } } From 60e26af3236480a73c7116a20fce49e4e8f74b5e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 16 Nov 2018 08:40:00 +0100 Subject: [PATCH 0369/5092] add a sanity assertion --- src/stacked_borrows.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 3790b5d13fed..f564bf9ab761 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -318,6 +318,7 @@ impl<'tcx> Stacks { new_bor: Borrow, new_kind: RefKind, ) -> EvalResult<'tcx> { + assert_eq!(new_bor.is_unique(), new_kind == RefKind::Unique); trace!("reborrow for tag {:?} to {:?} as {:?}: {:?}, size {}", ptr.tag, new_bor, new_kind, ptr, size.bytes()); let mut stacks = self.stacks.borrow_mut(); From 4e34457715cd06eee13b49806e1d157e1add9a66 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 16 Nov 2018 08:40:08 +0100 Subject: [PATCH 0370/5092] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index a829ec0f5a0a..6c3858ccc9cd 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-15 +nightly-2018-11-16 From ca7b088aba92efb6643cbb1b69303db35bc1c631 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 16 Nov 2018 08:50:44 +0100 Subject: [PATCH 0371/5092] remove type system tests --- tests/compile-fail/cast_fn_ptr_unsafe.rs | 10 ---------- tests/compile-fail/cast_fn_ptr_unsafe2.rs | 10 ---------- 2 files changed, 20 deletions(-) delete mode 100644 tests/compile-fail/cast_fn_ptr_unsafe.rs delete mode 100644 tests/compile-fail/cast_fn_ptr_unsafe2.rs diff --git a/tests/compile-fail/cast_fn_ptr_unsafe.rs b/tests/compile-fail/cast_fn_ptr_unsafe.rs deleted file mode 100644 index 568681da3c5d..000000000000 --- a/tests/compile-fail/cast_fn_ptr_unsafe.rs +++ /dev/null @@ -1,10 +0,0 @@ -// just making sure that fn -> unsafe fn casts are handled by rustc so miri doesn't have to -fn main() { - fn f() {} - - let g = f as fn() as unsafe fn(i32); //~ERROR: non-primitive cast: `fn()` as `unsafe fn(i32)` - - unsafe { - g(42); - } -} diff --git a/tests/compile-fail/cast_fn_ptr_unsafe2.rs b/tests/compile-fail/cast_fn_ptr_unsafe2.rs deleted file mode 100644 index 314365939fe8..000000000000 --- a/tests/compile-fail/cast_fn_ptr_unsafe2.rs +++ /dev/null @@ -1,10 +0,0 @@ -// just making sure that fn -> unsafe fn casts are handled by rustc so miri doesn't have to -fn main() { - fn f() {} - - let g = f as fn() as fn(i32) as unsafe fn(i32); //~ERROR: non-primitive cast: `fn()` as `fn(i32)` - - unsafe { - g(42); - } -} From 70738bf8cc6b5399f2810d0a2a846fddb877f511 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 16 Nov 2018 08:53:43 +0100 Subject: [PATCH 0372/5092] where there is 2, there should be 1 --- tests/compile-fail/{cast_fn_ptr.rs => cast_fn_ptr1.rs} | 0 tests/compile-fail/{div-by-zero.rs => div-by-zero-1.rs} | 0 .../{out_of_bounds_read.rs => out_of_bounds_read1.rs} | 0 tests/compile-fail/{overflowing-rsh.rs => overflowing-rsh-1.rs} | 0 tests/compile-fail/{ptr_bitops.rs => ptr_bitops1.rs} | 0 ...atic_memory_modification.rs => static_memory_modification1.rs} | 0 tests/compile-fail/{transmute_fat.rs => transmute_fat1.rs} | 0 .../{unaligned_ptr_cast.rs => unaligned_ptr_cast1.rs} | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename tests/compile-fail/{cast_fn_ptr.rs => cast_fn_ptr1.rs} (100%) rename tests/compile-fail/{div-by-zero.rs => div-by-zero-1.rs} (100%) rename tests/compile-fail/{out_of_bounds_read.rs => out_of_bounds_read1.rs} (100%) rename tests/compile-fail/{overflowing-rsh.rs => overflowing-rsh-1.rs} (100%) rename tests/compile-fail/{ptr_bitops.rs => ptr_bitops1.rs} (100%) rename tests/compile-fail/{static_memory_modification.rs => static_memory_modification1.rs} (100%) rename tests/compile-fail/{transmute_fat.rs => transmute_fat1.rs} (100%) rename tests/compile-fail/{unaligned_ptr_cast.rs => unaligned_ptr_cast1.rs} (100%) diff --git a/tests/compile-fail/cast_fn_ptr.rs b/tests/compile-fail/cast_fn_ptr1.rs similarity index 100% rename from tests/compile-fail/cast_fn_ptr.rs rename to tests/compile-fail/cast_fn_ptr1.rs diff --git a/tests/compile-fail/div-by-zero.rs b/tests/compile-fail/div-by-zero-1.rs similarity index 100% rename from tests/compile-fail/div-by-zero.rs rename to tests/compile-fail/div-by-zero-1.rs diff --git a/tests/compile-fail/out_of_bounds_read.rs b/tests/compile-fail/out_of_bounds_read1.rs similarity index 100% rename from tests/compile-fail/out_of_bounds_read.rs rename to tests/compile-fail/out_of_bounds_read1.rs diff --git a/tests/compile-fail/overflowing-rsh.rs b/tests/compile-fail/overflowing-rsh-1.rs similarity index 100% rename from tests/compile-fail/overflowing-rsh.rs rename to tests/compile-fail/overflowing-rsh-1.rs diff --git a/tests/compile-fail/ptr_bitops.rs b/tests/compile-fail/ptr_bitops1.rs similarity index 100% rename from tests/compile-fail/ptr_bitops.rs rename to tests/compile-fail/ptr_bitops1.rs diff --git a/tests/compile-fail/static_memory_modification.rs b/tests/compile-fail/static_memory_modification1.rs similarity index 100% rename from tests/compile-fail/static_memory_modification.rs rename to tests/compile-fail/static_memory_modification1.rs diff --git a/tests/compile-fail/transmute_fat.rs b/tests/compile-fail/transmute_fat1.rs similarity index 100% rename from tests/compile-fail/transmute_fat.rs rename to tests/compile-fail/transmute_fat1.rs diff --git a/tests/compile-fail/unaligned_ptr_cast.rs b/tests/compile-fail/unaligned_ptr_cast1.rs similarity index 100% rename from tests/compile-fail/unaligned_ptr_cast.rs rename to tests/compile-fail/unaligned_ptr_cast1.rs From 827e5180f20ebeec990ab8f92a4196ad8c5feb19 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 16 Nov 2018 10:01:54 +0100 Subject: [PATCH 0373/5092] stacked borrows is broken without full MIR --- README.md | 13 +++++++++---- .../copy_nonoverlapping.rs | 0 .../memleak_rc.rs | 0 .../stacked_borrows/alias_through_mutation.rs | 0 .../stacked_borrows/aliasing_mut1.rs | 0 .../stacked_borrows/aliasing_mut2.rs | 0 .../stacked_borrows/aliasing_mut3.rs | 0 .../stacked_borrows/aliasing_mut4.rs | 0 .../stacked_borrows/buggy_as_mut_slice.rs | 0 .../stacked_borrows/buggy_split_at_mut.rs | 0 .../stacked_borrows/illegal_read1.rs | 0 .../stacked_borrows/illegal_read2.rs | 0 .../stacked_borrows/illegal_read3.rs | 0 .../stacked_borrows/illegal_read4.rs | 0 .../stacked_borrows/illegal_read5.rs | 0 .../stacked_borrows/illegal_write1.rs | 0 .../stacked_borrows/illegal_write2.rs | 0 .../stacked_borrows/illegal_write3.rs | 0 .../stacked_borrows/illegal_write4.rs | 0 .../stacked_borrows/illegal_write5.rs | 0 .../stacked_borrows/load_invalid_mut.rs | 0 .../stacked_borrows/load_invalid_shr.rs | 0 .../stacked_borrows/mut_exclusive_violation1.rs | 0 .../stacked_borrows/outdated_local.rs | 0 .../stacked_borrows/pass_invalid_mut.rs | 0 .../stacked_borrows/pass_invalid_shr.rs | 0 .../stacked_borrows/pointer_smuggling.rs | 0 .../stacked_borrows/return_invalid_mut.rs | 0 .../stacked_borrows/return_invalid_shr.rs | 0 .../stacked_borrows/static_memory_modification.rs | 0 .../stacked_borrows/transmute-is-no-escape.rs | 0 .../stacked_borrows/unescaped_local.rs | 0 .../transmute-pair-undef.rs | 0 tests/compiletest.rs | 4 ++++ 34 files changed, 13 insertions(+), 4 deletions(-) rename tests/{compile-fail => compile-fail-fullmir}/copy_nonoverlapping.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/memleak_rc.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/alias_through_mutation.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/aliasing_mut1.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/aliasing_mut2.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/aliasing_mut3.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/aliasing_mut4.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/buggy_as_mut_slice.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/buggy_split_at_mut.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/illegal_read1.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/illegal_read2.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/illegal_read3.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/illegal_read4.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/illegal_read5.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/illegal_write1.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/illegal_write2.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/illegal_write3.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/illegal_write4.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/illegal_write5.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/load_invalid_mut.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/load_invalid_shr.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/mut_exclusive_violation1.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/outdated_local.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/pass_invalid_mut.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/pass_invalid_shr.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/pointer_smuggling.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/return_invalid_mut.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/return_invalid_shr.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/static_memory_modification.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/transmute-is-no-escape.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/unescaped_local.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/transmute-pair-undef.rs (100%) diff --git a/README.md b/README.md index 04a263597c0b..5eb7b34425e6 100644 --- a/README.md +++ b/README.md @@ -45,14 +45,19 @@ in this directory. ## Running Miri ```sh -cargo +nightly run tests/run-pass/vecs.rs # Or whatever test you like. +cargo +nightly run -- -Zmiri-disable-validation tests/run-pass/vecs.rs # Or whatever test you like. ``` +We have to disable validation because that can lead to errors when libstd is not +compiled the right way. + ## Running Miri with full libstd -Per default libstd does not contain the MIR of non-polymorphic functions. When -Miri hits a call to such a function, execution terminates. To fix this, it is -possible to compile libstd with full MIR: +Per default libstd does not contain the MIR of non-polymorphic functions, and +also does not contain some extra MIR statements that miri needs for validation. +When Miri hits a call to such a function, execution terminates, and even when +the MIR is present, validation can fail. To fix this, it is possible to compile +libstd with full MIR: ```sh rustup component add --toolchain nightly rust-src diff --git a/tests/compile-fail/copy_nonoverlapping.rs b/tests/compile-fail-fullmir/copy_nonoverlapping.rs similarity index 100% rename from tests/compile-fail/copy_nonoverlapping.rs rename to tests/compile-fail-fullmir/copy_nonoverlapping.rs diff --git a/tests/compile-fail/memleak_rc.rs b/tests/compile-fail-fullmir/memleak_rc.rs similarity index 100% rename from tests/compile-fail/memleak_rc.rs rename to tests/compile-fail-fullmir/memleak_rc.rs diff --git a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs b/tests/compile-fail-fullmir/stacked_borrows/alias_through_mutation.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/alias_through_mutation.rs rename to tests/compile-fail-fullmir/stacked_borrows/alias_through_mutation.rs diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut1.rs b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/aliasing_mut1.rs rename to tests/compile-fail-fullmir/stacked_borrows/aliasing_mut1.rs diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut2.rs b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut2.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/aliasing_mut2.rs rename to tests/compile-fail-fullmir/stacked_borrows/aliasing_mut2.rs diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut3.rs b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut3.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/aliasing_mut3.rs rename to tests/compile-fail-fullmir/stacked_borrows/aliasing_mut3.rs diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut4.rs b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut4.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/aliasing_mut4.rs rename to tests/compile-fail-fullmir/stacked_borrows/aliasing_mut4.rs diff --git a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/compile-fail-fullmir/stacked_borrows/buggy_as_mut_slice.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs rename to tests/compile-fail-fullmir/stacked_borrows/buggy_as_mut_slice.rs diff --git a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs b/tests/compile-fail-fullmir/stacked_borrows/buggy_split_at_mut.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs rename to tests/compile-fail-fullmir/stacked_borrows/buggy_split_at_mut.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read1.rs b/tests/compile-fail-fullmir/stacked_borrows/illegal_read1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read1.rs rename to tests/compile-fail-fullmir/stacked_borrows/illegal_read1.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read2.rs b/tests/compile-fail-fullmir/stacked_borrows/illegal_read2.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read2.rs rename to tests/compile-fail-fullmir/stacked_borrows/illegal_read2.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read3.rs b/tests/compile-fail-fullmir/stacked_borrows/illegal_read3.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read3.rs rename to tests/compile-fail-fullmir/stacked_borrows/illegal_read3.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read4.rs b/tests/compile-fail-fullmir/stacked_borrows/illegal_read4.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read4.rs rename to tests/compile-fail-fullmir/stacked_borrows/illegal_read4.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read5.rs b/tests/compile-fail-fullmir/stacked_borrows/illegal_read5.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read5.rs rename to tests/compile-fail-fullmir/stacked_borrows/illegal_read5.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_write1.rs b/tests/compile-fail-fullmir/stacked_borrows/illegal_write1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write1.rs rename to tests/compile-fail-fullmir/stacked_borrows/illegal_write1.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_write2.rs b/tests/compile-fail-fullmir/stacked_borrows/illegal_write2.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write2.rs rename to tests/compile-fail-fullmir/stacked_borrows/illegal_write2.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_write3.rs b/tests/compile-fail-fullmir/stacked_borrows/illegal_write3.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write3.rs rename to tests/compile-fail-fullmir/stacked_borrows/illegal_write3.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_write4.rs b/tests/compile-fail-fullmir/stacked_borrows/illegal_write4.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write4.rs rename to tests/compile-fail-fullmir/stacked_borrows/illegal_write4.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_write5.rs b/tests/compile-fail-fullmir/stacked_borrows/illegal_write5.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write5.rs rename to tests/compile-fail-fullmir/stacked_borrows/illegal_write5.rs diff --git a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs b/tests/compile-fail-fullmir/stacked_borrows/load_invalid_mut.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/load_invalid_mut.rs rename to tests/compile-fail-fullmir/stacked_borrows/load_invalid_mut.rs diff --git a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs b/tests/compile-fail-fullmir/stacked_borrows/load_invalid_shr.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/load_invalid_shr.rs rename to tests/compile-fail-fullmir/stacked_borrows/load_invalid_shr.rs diff --git a/tests/compile-fail/stacked_borrows/mut_exclusive_violation1.rs b/tests/compile-fail-fullmir/stacked_borrows/mut_exclusive_violation1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/mut_exclusive_violation1.rs rename to tests/compile-fail-fullmir/stacked_borrows/mut_exclusive_violation1.rs diff --git a/tests/compile-fail/stacked_borrows/outdated_local.rs b/tests/compile-fail-fullmir/stacked_borrows/outdated_local.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/outdated_local.rs rename to tests/compile-fail-fullmir/stacked_borrows/outdated_local.rs diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs b/tests/compile-fail-fullmir/stacked_borrows/pass_invalid_mut.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/pass_invalid_mut.rs rename to tests/compile-fail-fullmir/stacked_borrows/pass_invalid_mut.rs diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs b/tests/compile-fail-fullmir/stacked_borrows/pass_invalid_shr.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/pass_invalid_shr.rs rename to tests/compile-fail-fullmir/stacked_borrows/pass_invalid_shr.rs diff --git a/tests/compile-fail/stacked_borrows/pointer_smuggling.rs b/tests/compile-fail-fullmir/stacked_borrows/pointer_smuggling.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/pointer_smuggling.rs rename to tests/compile-fail-fullmir/stacked_borrows/pointer_smuggling.rs diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs b/tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/return_invalid_mut.rs rename to tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut.rs diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr.rs b/tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/return_invalid_shr.rs rename to tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr.rs diff --git a/tests/compile-fail/stacked_borrows/static_memory_modification.rs b/tests/compile-fail-fullmir/stacked_borrows/static_memory_modification.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/static_memory_modification.rs rename to tests/compile-fail-fullmir/stacked_borrows/static_memory_modification.rs diff --git a/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs b/tests/compile-fail-fullmir/stacked_borrows/transmute-is-no-escape.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs rename to tests/compile-fail-fullmir/stacked_borrows/transmute-is-no-escape.rs diff --git a/tests/compile-fail/stacked_borrows/unescaped_local.rs b/tests/compile-fail-fullmir/stacked_borrows/unescaped_local.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/unescaped_local.rs rename to tests/compile-fail-fullmir/stacked_borrows/unescaped_local.rs diff --git a/tests/compile-fail/transmute-pair-undef.rs b/tests/compile-fail-fullmir/transmute-pair-undef.rs similarity index 100% rename from tests/compile-fail/transmute-pair-undef.rs rename to tests/compile-fail-fullmir/transmute-pair-undef.rs diff --git a/tests/compiletest.rs b/tests/compiletest.rs index f393fcb2c226..7ecf64590b61 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -103,6 +103,10 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: // whitelist. flags.push("-Zmir-opt-level=1".to_owned()); } + if !have_fullmir() { + // Validation relies on the EscapeToRaw statements being emitted + flags.push("-Zmiri-disable-validation".to_owned()); + } let mut config = mk_config("ui"); config.src_base = PathBuf::from(path); From a1f895d6f2cc9090623652fbbe9029becb102189 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 13 Nov 2018 12:48:20 +0100 Subject: [PATCH 0374/5092] retagging: descent into values, type-driven --- src/helpers.rs | 8 ++- src/stacked_borrows.rs | 59 +++++++++++++++---- .../stacked_borrows/buggy_split_at_mut.rs | 2 +- 3 files changed, 55 insertions(+), 14 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 31e297295703..85329ddcf17f 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -158,8 +158,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: unsafe_cell_action: F, } - impl<'ecx, 'a, 'mir, 'tcx, F> ValueVisitor<'a, 'mir, 'tcx, Evaluator<'tcx>> - for UnsafeCellVisitor<'ecx, 'a, 'mir, 'tcx, F> + impl<'ecx, 'a, 'mir, 'tcx, F> + ValueVisitor<'a, 'mir, 'tcx, Evaluator<'tcx>> + for + UnsafeCellVisitor<'ecx, 'a, 'mir, 'tcx, F> where F: FnMut(MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> { @@ -230,7 +232,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } // We should never get to a primitive, but always short-circuit somewhere above - fn visit_primitive(&mut self, _val: ImmTy<'tcx, Borrow>) -> EvalResult<'tcx> + fn visit_primitive(&mut self, _v: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> { bug!("We should always short-circit before coming to a primitive") } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index f564bf9ab761..44fa605fd6a2 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -4,7 +4,7 @@ use rustc::ty::{self, layout::Size}; use rustc::hir::{Mutability, MutMutable, MutImmutable}; use crate::{ - EvalResult, EvalErrorKind, MiriEvalContext, HelpersEvalContextExt, + EvalResult, EvalErrorKind, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, MemoryKind, MiriMemoryKind, RangeMap, AllocId, Allocation, AllocationExtra, Pointer, MemPlace, Scalar, Immediate, ImmTy, PlaceTy, MPlaceTy, }; @@ -602,17 +602,56 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { _fn_entry: bool, place: PlaceTy<'tcx, Borrow> ) -> EvalResult<'tcx> { - // For now, we only retag if the toplevel type is a reference. - // TODO: Recurse into structs and enums, sharing code with validation. // TODO: Honor `fn_entry`. - let mutbl = match place.layout.ty.sty { - ty::Ref(_, _, mutbl) => mutbl, // go ahead - _ => return Ok(()), // do nothing, for now + + // We need a visitor to visit all references. However, that requires + // a `MemPlace`, so we have a fast path for reference types that + // avoids allocating. + match place.layout.ty.sty { + ty::Ref(_, _, mutbl) => { + // fast path + let val = self.read_immediate(self.place_to_op(place)?)?; + let val = self.reborrow(val, mutbl)?; + self.write_immediate(val, place)?; + } + _ => {}, // handled with the general case below }; - // Retag the pointer and write it back. - let val = self.read_immediate(self.place_to_op(place)?)?; - let val = self.reborrow(val, mutbl)?; - self.write_immediate(val, place)?; + let place = self.force_allocation(place)?; + + let mut visitor = RetagVisitor { ecx: self }; + visitor.visit_value(place)?; + + // The actual visitor + struct RetagVisitor<'ecx, 'a, 'mir, 'tcx> { + ecx: &'ecx mut MiriEvalContext<'a, 'mir, 'tcx>, + } + impl<'ecx, 'a, 'mir, 'tcx> + MutValueVisitor<'a, 'mir, 'tcx, Evaluator<'tcx>> + for + RetagVisitor<'ecx, 'a, 'mir, 'tcx> + { + type V = MPlaceTy<'tcx, Borrow>; + + #[inline(always)] + fn ecx(&mut self) -> &mut MiriEvalContext<'a, 'mir, 'tcx> { + &mut self.ecx + } + + // Primitives of reference type, that is the one thing we are interested in. + fn visit_primitive(&mut self, place: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> + { + match place.layout.ty.sty { + ty::Ref(_, _, mutbl) => { + let val = self.ecx.read_immediate(place.into())?; + let val = self.ecx.reborrow(val, mutbl)?; + self.ecx.write_immediate(val, place.into())?; + } + _ => {}, // nothing to do + } + Ok(()) + } + } + Ok(()) } } diff --git a/tests/compile-fail-fullmir/stacked_borrows/buggy_split_at_mut.rs b/tests/compile-fail-fullmir/stacked_borrows/buggy_split_at_mut.rs index 711544f80149..a6daa5d93d77 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/buggy_split_at_mut.rs @@ -11,6 +11,7 @@ mod safe { assert!(mid <= len); (from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" + //~^ ERROR does not exist on the stack from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) } } @@ -19,7 +20,6 @@ mod safe { fn main() { let mut array = [1,2,3,4]; let (a, b) = safe::split_at_mut(&mut array, 0); - //~^ ERROR does not exist on the stack a[1] = 5; b[1] = 6; } From c54dcf59aed7f44260df41a800e7855436a205eb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 13 Nov 2018 13:03:01 +0100 Subject: [PATCH 0375/5092] add some tests for retagging inside tuples and options --- .../stacked_borrows/return_invalid_mut_option.rs | 11 +++++++++++ .../stacked_borrows/return_invalid_mut_tuple.rs | 11 +++++++++++ .../stacked_borrows/return_invalid_shr_option.rs | 11 +++++++++++ .../stacked_borrows/return_invalid_shr_tuple.rs | 11 +++++++++++ 4 files changed, 44 insertions(+) create mode 100644 tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut_option.rs create mode 100644 tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut_tuple.rs create mode 100644 tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr_option.rs create mode 100644 tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr_tuple.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut_option.rs b/tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut_option.rs new file mode 100644 index 000000000000..28a1f74c6ac2 --- /dev/null +++ b/tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut_option.rs @@ -0,0 +1,11 @@ +// Make sure that we cannot return a `&mut` that got already invalidated, not even in an `Option`. +fn foo(x: &mut (i32, i32)) -> Option<&mut i32> { + let xraw = x as *mut (i32, i32); + let ret = Some(unsafe { &mut (*xraw).1 }); + let _val = unsafe { *xraw }; // invalidate xref + ret //~ ERROR does not exist on the stack +} + +fn main() { + foo(&mut (1, 2)); +} diff --git a/tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut_tuple.rs b/tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut_tuple.rs new file mode 100644 index 000000000000..3357af68a841 --- /dev/null +++ b/tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut_tuple.rs @@ -0,0 +1,11 @@ +// Make sure that we cannot return a `&mut` that got already invalidated, not even in a tuple. +fn foo(x: &mut (i32, i32)) -> (&mut i32,) { + let xraw = x as *mut (i32, i32); + let ret = (unsafe { &mut (*xraw).1 },); + let _val = unsafe { *xraw }; // invalidate xref + ret //~ ERROR does not exist on the stack +} + +fn main() { + foo(&mut (1, 2)); +} diff --git a/tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr_option.rs b/tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr_option.rs new file mode 100644 index 000000000000..9d220991c330 --- /dev/null +++ b/tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr_option.rs @@ -0,0 +1,11 @@ +// Make sure that we cannot return a `&` that got already invalidated, not even in an `Option`. +fn foo(x: &mut (i32, i32)) -> Option<&i32> { + let xraw = x as *mut (i32, i32); + let ret = Some(unsafe { &(*xraw).1 }); + unsafe { *xraw = (42, 23) }; // unfreeze + ret //~ ERROR is not frozen +} + +fn main() { + foo(&mut (1, 2)); +} diff --git a/tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr_tuple.rs b/tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr_tuple.rs new file mode 100644 index 000000000000..060fa25c2307 --- /dev/null +++ b/tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr_tuple.rs @@ -0,0 +1,11 @@ +// Make sure that we cannot return a `&` that got already invalidated, not even in a tuple. +fn foo(x: &mut (i32, i32)) -> (&i32,) { + let xraw = x as *mut (i32, i32); + let ret = (unsafe { &(*xraw).1 },); + unsafe { *xraw = (42, 23) }; // unfreeze + ret //~ ERROR is not frozen +} + +fn main() { + foo(&mut (1, 2)); +} From 36b97cd76c478d56820e1e18647841e1d144d852 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 15 Nov 2018 14:25:23 +0100 Subject: [PATCH 0376/5092] Factor out common top-level code from escape-to-raw and retag --- src/stacked_borrows.rs | 81 ++++++++++++++++++++++++++---------------- 1 file changed, 51 insertions(+), 30 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 44fa605fd6a2..b088a6e845f5 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -303,6 +303,9 @@ impl<'tcx> Stacks { trace!("{} access of tag {:?}: {:?}, size {}", if is_write { "read" } else { "write" }, ptr.tag, ptr, size.bytes()); + // Even reads can have a side-effect, by invalidating other references. + // This is fundamentally necessary since `&mut` asserts that there + // are no accesses through other references, not even reads. let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { stack.access(ptr.tag, is_write)?; @@ -311,6 +314,7 @@ impl<'tcx> Stacks { } /// Reborrow the given pointer to the new tag for the given kind of reference. + /// This works on `&self` because we might encounter references to constant memory. fn reborrow( &self, ptr: Pointer, @@ -414,8 +418,16 @@ pub trait EvalContextExt<'tcx> { kind: MemoryKind, ) -> Borrow; - /// Retag an indidual pointer, returning the retagged version. + /// Reborrow the given place, returning the newly tagged ptr to it. fn reborrow( + &mut self, + place: MPlaceTy<'tcx, Borrow>, + size: Size, + new_bor: Borrow + ) -> EvalResult<'tcx, Pointer>; + + /// Retag an indidual pointer, returning the retagged version. + fn retag_reference( &mut self, ptr: ImmTy<'tcx, Borrow>, mutbl: Mutability, @@ -536,22 +548,46 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { } /// The given place may henceforth be accessed through raw pointers. + #[inline(always)] fn escape_to_raw( &mut self, place: MPlaceTy<'tcx, Borrow>, size: Size, ) -> EvalResult<'tcx> { - trace!("escape_to_raw: {:?} is now accessible by raw pointers", *place); - // Get the allocation - let ptr = place.ptr.to_ptr()?; - self.memory().check_bounds(ptr, size, false)?; // `ptr_dereference` wouldn't do any checks if this is a raw ptr - let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); - // Re-borrow to raw. This is a NOP for shared borrows, but we do not know the borrow - // type here and that's also okay. Freezing does not matter here. - alloc.extra.reborrow(ptr, size, Borrow::default(), RefKind::Raw) + self.reborrow(place, size, Borrow::default())?; + Ok(()) } fn reborrow( + &mut self, + place: MPlaceTy<'tcx, Borrow>, + size: Size, + new_bor: Borrow + ) -> EvalResult<'tcx, Pointer> { + let ptr = place.ptr.to_ptr()?; + let new_ptr = Pointer::new_with_tag(ptr.alloc_id, ptr.offset, new_bor); + trace!("reborrow: Creating new reference for {:?} (pointee {}): {:?}", + ptr, place.layout.ty, new_bor); + + // Get the allocation. It might not be mutable, so we cannot use `get_mut`. + self.memory().check_bounds(ptr, size, false)?; + let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); + // Update the stacks. + if let Borrow::Shr(Some(_)) = new_bor { + // Reference that cares about freezing. We need a frozen-sensitive reborrow. + self.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { + let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; + alloc.extra.reborrow(cur_ptr, size, new_bor, kind) + })?; + } else { + // Just treat this as one big chunk. + let kind = if new_bor.is_unique() { RefKind::Unique } else { RefKind::Raw }; + alloc.extra.reborrow(ptr, size, new_bor, kind)?; + } + Ok(new_ptr) + } + + fn retag_reference( &mut self, val: ImmTy<'tcx, Borrow>, mutbl: Mutability, @@ -566,33 +602,17 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { return Ok(*val); } - // Prepare to re-borrow this place. - let ptr = place.ptr.to_ptr()?; + // Compute new borrow. let time = self.machine.stacked_borrows.increment_clock(); let new_bor = match mutbl { MutMutable => Borrow::Uniq(time), MutImmutable => Borrow::Shr(Some(time)), }; - trace!("reborrow: Creating new {:?} reference for {:?} (pointee {}): {:?}", - mutbl, ptr, place.layout.ty, new_bor); - // Get the allocation. It might not be mutable, so we cannot use `get_mut`. - self.memory().check_bounds(ptr, size, false)?; - let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); - // Update the stacks. - if mutbl == MutImmutable { - // Shared reference. We need a frozen-sensitive reborrow. - self.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { - let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; - alloc.extra.reborrow(cur_ptr, size, new_bor, kind) - })?; - } else { - // Mutable reference. Just treat this as one big chunk. - alloc.extra.reborrow(ptr, size, new_bor, RefKind::Unique)?; - } + // Reborrow. + let new_ptr = self.reborrow(place, size, new_bor)?; // Return new ptr - let new_ptr = Pointer::new_with_tag(ptr.alloc_id, ptr.offset, new_bor); let new_place = MemPlace { ptr: Scalar::Ptr(new_ptr), ..*place }; Ok(new_place.to_ref()) } @@ -611,8 +631,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { ty::Ref(_, _, mutbl) => { // fast path let val = self.read_immediate(self.place_to_op(place)?)?; - let val = self.reborrow(val, mutbl)?; + let val = self.retag_reference(val, mutbl)?; self.write_immediate(val, place)?; + return Ok(()); } _ => {}, // handled with the general case below }; @@ -643,7 +664,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { match place.layout.ty.sty { ty::Ref(_, _, mutbl) => { let val = self.ecx.read_immediate(place.into())?; - let val = self.ecx.reborrow(val, mutbl)?; + let val = self.ecx.retag_reference(val, mutbl)?; self.ecx.write_immediate(val, place.into())?; } _ => {}, // nothing to do From 733f675bccbd23a38d89e66a7ae4d9e5afcdf8bd Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Fri, 16 Nov 2018 15:14:44 -0500 Subject: [PATCH 0377/5092] fix cargo invocation in the readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5eb7b34425e6..5e5a7a23c6af 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ nightly). ## Running Miri on your own project('s test suite) -Install Miri as a cargo subcommand with `cargo install +nightly --all-features +Install Miri as a cargo subcommand with `cargo +nightly install --all-features --path .`. Be aware that if you used `rustup override set` to fix a particular Rust version for the miri directory, that will *not* apply to your own project directory! You have to use a consistent Rust version for building miri and your From b7dbb5e2a71e222b984c2ef062deccb1d9dd7c17 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Nov 2018 10:05:30 +0100 Subject: [PATCH 0378/5092] also consider boxes like unique references --- src/stacked_borrows.rs | 16 +++++----- .../box_exclusive_violation1.rs | 29 +++++++++++++++++++ 2 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index b088a6e845f5..3cf4365e35aa 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -661,14 +661,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { // Primitives of reference type, that is the one thing we are interested in. fn visit_primitive(&mut self, place: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> { - match place.layout.ty.sty { - ty::Ref(_, _, mutbl) => { - let val = self.ecx.read_immediate(place.into())?; - let val = self.ecx.retag_reference(val, mutbl)?; - self.ecx.write_immediate(val, place.into())?; - } - _ => {}, // nothing to do - } + let mutbl = match place.layout.ty.sty { + ty::Ref(_, _, mutbl) => mutbl, + ty::Adt(..) if place.layout.ty.is_box() => MutMutable, + _ => return Ok(()), // nothing to do + }; + let val = self.ecx.read_immediate(place.into())?; + let val = self.ecx.retag_reference(val, mutbl)?; + self.ecx.write_immediate(val, place.into())?; Ok(()) } } diff --git a/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs b/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs new file mode 100644 index 000000000000..73631173b932 --- /dev/null +++ b/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs @@ -0,0 +1,29 @@ +fn demo_mut_advanced_unique(mut our: Box) -> i32 { + unknown_code_1(&*our); + + // This "re-asserts" uniqueness of the reference: After writing, we know + // our tag is at the top of the stack. + *our = 5; + + unknown_code_2(); + + // We know this will return 5 + *our //~ ERROR does not exist on the stack +} + +// Now comes the evil context +use std::ptr; + +static mut LEAK: *mut i32 = ptr::null_mut(); + +fn unknown_code_1(x: &i32) { unsafe { + LEAK = x as *const _ as *mut _; +} } + +fn unknown_code_2() { unsafe { + *LEAK = 7; +} } + +fn main() { + assert_eq!(demo_mut_advanced_unique(Box::new(0)), 5); +} From 880229d4c3c4032cb3e1c2b4c599af8a0ad0d1dc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Nov 2018 09:54:58 +0100 Subject: [PATCH 0379/5092] escape-on-cast, now ptr-deref does not change the tag at all, ever --- src/lib.rs | 6 ++--- src/stacked_borrows.rs | 22 ++++++++----------- .../stacked_borrows/buggy_as_mut_slice.rs | 10 +++------ .../stacked_borrows/transmute-is-no-escape.rs | 1 + 4 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a0ed7c8e4fdb..a5de02f6421b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -461,9 +461,9 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { // No tracking Ok(place.ptr) } else { - let ptr = place.ptr.to_ptr()?; // assert this is not a scalar - let tag = ecx.tag_dereference(place, size, mutability.into())?; - Ok(Scalar::Ptr(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag))) + ecx.ptr_dereference(place, size, mutability.into())?; + // We never change the pointer + Ok(place.ptr) } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 3cf4365e35aa..2726c7dccb4f 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -405,12 +405,12 @@ impl<'tcx> Stacks { pub trait EvalContextExt<'tcx> { - fn tag_dereference( + fn ptr_dereference( &self, place: MPlaceTy<'tcx, Borrow>, size: Size, mutability: Option, - ) -> EvalResult<'tcx, Borrow>; + ) -> EvalResult<'tcx>; fn tag_new_allocation( &mut self, @@ -480,13 +480,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { /// /// Note that this does NOT mean that all this memory will actually get accessed/referenced! /// We could be in the middle of `&(*var).1`. - fn tag_dereference( + fn ptr_dereference( &self, place: MPlaceTy<'tcx, Borrow>, size: Size, mutability: Option, - ) -> EvalResult<'tcx, Borrow> { - trace!("tag_dereference: Accessing {} reference for {:?} (pointee {})", + ) -> EvalResult<'tcx> { + trace!("ptr_dereference: Accessing {} reference for {:?} (pointee {})", if let Some(mutability) = mutability { format!("{:?}", mutability) } else { format!("raw") }, place.ptr, place.layout.ty); let ptr = place.ptr.to_ptr()?; @@ -497,12 +497,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { // That can transmute a raw ptr to a (shared/mut) ref, and a mut ref to a shared one. match (mutability, ptr.tag) { (None, _) => { - // Don't use the tag, this is a raw access! They should happen tagless. - // This is needed for `*mut` to make any sense: Writes *do* enforce the - // `Uniq` tag to be up top, but we must make sure raw writes do not do that. - // This does mean, however, that `&*foo` is *not* a NOP *if* `foo` is a raw ptr. - // Also don't do any further validation, this is raw after all. - return Ok(Borrow::default()); + // No further validation on raw accesses. + return Ok(()); } (Some(MutMutable), Borrow::Uniq(_)) | (Some(MutImmutable), Borrow::Shr(_)) => { @@ -543,8 +539,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { alloc.extra.deref(ptr, size, kind)?; } - // All is good, and do not change the tag - Ok(ptr.tag) + // All is good + Ok(()) } /// The given place may henceforth be accessed through raw pointers. diff --git a/tests/compile-fail-fullmir/stacked_borrows/buggy_as_mut_slice.rs b/tests/compile-fail-fullmir/stacked_borrows/buggy_as_mut_slice.rs index 2f3d0793f63e..e08e3bba6840 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/buggy_as_mut_slice.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/buggy_as_mut_slice.rs @@ -1,5 +1,3 @@ -// error-pattern: mutable reference with frozen tag - mod safe { use std::slice::from_raw_parts_mut; @@ -12,10 +10,8 @@ mod safe { fn main() { let v = vec![0,1,2]; - let _v1 = safe::as_mut_slice(&v); -/* - let v2 = safe::as_mut_slice(&v); + let v1 = safe::as_mut_slice(&v); + let _v2 = safe::as_mut_slice(&v); v1[1] = 5; - v1[1] = 6; -*/ + //~^ ERROR does not exist on the stack } diff --git a/tests/compile-fail-fullmir/stacked_borrows/transmute-is-no-escape.rs b/tests/compile-fail-fullmir/stacked_borrows/transmute-is-no-escape.rs index 1ab005e3fa17..75abce3111f8 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/transmute-is-no-escape.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/transmute-is-no-escape.rs @@ -8,5 +8,6 @@ use std::mem; fn main() { let mut x: i32 = 42; let raw: *mut i32 = unsafe { mem::transmute(&mut x) }; + let raw = raw as usize as *mut i32; // make sure we killed the tag unsafe { *raw = 13; } //~ ERROR does not exist on the stack } From 662821f7f732f85e05b85e59ee45747dc52fc2c8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Nov 2018 10:11:21 +0100 Subject: [PATCH 0380/5092] raw ptr deref no longer erases the tag --- src/fn_call.rs | 60 ++++++++++++++++++++++++------------------------ src/intrinsic.rs | 10 ++++---- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 150cf7402a6d..41b3c1f7e660 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -131,10 +131,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "free" => { - let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation, no tag + let ptr = self.read_scalar(args[0])?.not_undef()?; if !ptr.is_null_ptr(self) { self.memory_mut().deallocate( - ptr.to_ptr()?.with_default_tag(), + ptr.to_ptr()?, None, MiriMemoryKind::C.into(), )?; @@ -179,7 +179,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo self.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_dealloc" => { - let ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation, no tag + let ptr = self.read_scalar(args[0])?.to_ptr()?; let old_size = self.read_scalar(args[1])?.to_usize(self)?; let align = self.read_scalar(args[2])?.to_usize(self)?; if old_size == 0 { @@ -189,13 +189,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo return err!(HeapAllocNonPowerOfTwoAlignment(align)); } self.memory_mut().deallocate( - ptr.with_default_tag(), + ptr, Some((Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap())), MiriMemoryKind::Rust.into(), )?; } "__rust_realloc" => { - let ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation, no tag + let ptr = self.read_scalar(args[0])?.to_ptr()?; let old_size = self.read_scalar(args[1])?.to_usize(self)?; let align = self.read_scalar(args[2])?.to_usize(self)?; let new_size = self.read_scalar(args[3])?.to_usize(self)?; @@ -206,7 +206,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo return err!(HeapAllocNonPowerOfTwoAlignment(align)); } let new_ptr = self.memory_mut().reallocate( - ptr.with_default_tag(), + ptr, Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap(), Size::from_bytes(new_size), @@ -238,8 +238,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "dlsym" => { let _handle = self.read_scalar(args[0])?; - let symbol = self.read_scalar(args[1])?.to_ptr()?.erase_tag(); - let symbol_name = self.memory().read_c_str(symbol.with_default_tag())?; + let symbol = self.read_scalar(args[1])?.to_ptr()?; + let symbol_name = self.memory().read_c_str(symbol)?; let err = format!("bad c unicode symbol: {:?}", symbol_name); let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err); return err!(Unimplemented(format!( @@ -292,13 +292,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo return err!(MachineError("the evaluated program panicked".to_string())), "memcmp" => { - let left = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation - let right = self.read_scalar(args[1])?.not_undef()?.erase_tag(); // raw ptr operation + let left = self.read_scalar(args[0])?.not_undef()?; + let right = self.read_scalar(args[1])?.not_undef()?; let n = Size::from_bytes(self.read_scalar(args[2])?.to_usize(self)?); let result = { - let left_bytes = self.memory().read_bytes(left.with_default_tag(), n)?; - let right_bytes = self.memory().read_bytes(right.with_default_tag(), n)?; + let left_bytes = self.memory().read_bytes(left, n)?; + let right_bytes = self.memory().read_bytes(right, n)?; use std::cmp::Ordering::*; match left_bytes.cmp(right_bytes) { @@ -315,8 +315,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "memrchr" => { - let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation - let ptr = ptr.with_default_tag(); + let ptr = self.read_scalar(args[0])?.not_undef()?; + let ptr = ptr; let val = self.read_scalar(args[1])?.to_bytes()? as u8; let num = self.read_scalar(args[2])?.to_usize(self)?; if let Some(idx) = self.memory().read_bytes(ptr, Size::from_bytes(num))? @@ -330,8 +330,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "memchr" => { - let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation - let ptr = ptr.with_default_tag(); + let ptr = self.read_scalar(args[0])?.not_undef()?; + let ptr = ptr; let val = self.read_scalar(args[1])?.to_bytes()? as u8; let num = self.read_scalar(args[2])?.to_usize(self)?; if let Some(idx) = self.memory().read_bytes(ptr, Size::from_bytes(num))?.iter().position( @@ -347,8 +347,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "getenv" => { let result = { - let name_ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation - let name = self.memory().read_c_str(name_ptr.with_default_tag())?; + let name_ptr = self.read_scalar(args[0])?.to_ptr()?; + let name = self.memory().read_c_str(name_ptr)?; match self.machine.env_vars.get(name) { Some(&var) => Scalar::Ptr(var), None => Scalar::ptr_null(&*self.tcx), @@ -360,10 +360,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "unsetenv" => { let mut success = None; { - let name_ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation + let name_ptr = self.read_scalar(args[0])?.not_undef()?; if !name_ptr.is_null_ptr(self) { let name = self.memory().read_c_str(name_ptr.to_ptr()? - .with_default_tag())?.to_owned(); + )?.to_owned(); if !name.is_empty() && !name.contains(&b'=') { success = Some(self.machine.env_vars.remove(&name)); } @@ -382,11 +382,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "setenv" => { let mut new = None; { - let name_ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation - let value_ptr = self.read_scalar(args[1])?.to_ptr()?.erase_tag(); // raw ptr operation - let value = self.memory().read_c_str(value_ptr.with_default_tag())?; + let name_ptr = self.read_scalar(args[0])?.not_undef()?; + let value_ptr = self.read_scalar(args[1])?.to_ptr()?; + let value = self.memory().read_c_str(value_ptr)?; if !name_ptr.is_null_ptr(self) { - let name = self.memory().read_c_str(name_ptr.to_ptr()?.with_default_tag())?; + let name = self.memory().read_c_str(name_ptr.to_ptr()?)?; if !name.is_empty() && !name.contains(&b'=') { new = Some((name.to_owned(), value.to_owned())); } @@ -417,14 +417,14 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "write" => { let fd = self.read_scalar(args[0])?.to_bytes()?; - let buf = self.read_scalar(args[1])?.not_undef()?.erase_tag(); + let buf = self.read_scalar(args[1])?.not_undef()?; let n = self.read_scalar(args[2])?.to_bytes()? as u64; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { // stdout/stderr use std::io::{self, Write}; - let buf_cont = self.memory().read_bytes(buf.with_default_tag(), Size::from_bytes(n))?; + let buf_cont = self.memory().read_bytes(buf, Size::from_bytes(n))?; let res = if fd == 1 { io::stdout().write(buf_cont) } else { @@ -445,8 +445,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "strlen" => { - let ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); - let n = self.memory().read_c_str(ptr.with_default_tag())?.len(); + let ptr = self.read_scalar(args[0])?.to_ptr()?; + let n = self.memory().read_c_str(ptr)?.len(); self.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; } @@ -492,7 +492,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // Hook pthread calls that go to the thread-local storage memory subsystem "pthread_key_create" => { - let key_ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation + let key_ptr = self.read_scalar(args[0])?.to_ptr()?; // Extract the function type out of the signature (that seems easier than constructing it ourselves...) let dtor = match self.read_scalar(args[1])?.not_undef()? { @@ -515,7 +515,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo return err!(OutOfTls); } self.memory_mut().write_scalar( - key_ptr.with_default_tag(), + key_ptr, key_layout.align, Scalar::from_uint(key, key_layout.size).into(), key_layout.size, diff --git a/src/intrinsic.rs b/src/intrinsic.rs index e23cadfcaf0b..6d5ac8d88bae 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -154,12 +154,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let count = self.read_scalar(args[2])?.to_usize(self)?; let elem_align = elem_layout.align; // erase tags: this is a raw ptr operation - let src = self.read_scalar(args[0])?.not_undef()?.erase_tag(); - let dest = self.read_scalar(args[1])?.not_undef()?.erase_tag(); + let src = self.read_scalar(args[0])?.not_undef()?; + let dest = self.read_scalar(args[1])?.not_undef()?; self.memory_mut().copy( - src.with_default_tag(), + src, elem_align, - dest.with_default_tag(), + dest, elem_align, Size::from_bytes(count * elem_size), intrinsic_name.ends_with("_nonoverlapping"), @@ -436,7 +436,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let ty = substs.type_at(0); let ty_layout = self.layout_of(ty)?; let val_byte = self.read_scalar(args[1])?.to_u8()?; - let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag().with_default_tag(); + let ptr = self.read_scalar(args[0])?.not_undef()?; let count = self.read_scalar(args[2])?.to_usize(self)?; self.memory().check_align(ptr, ty_layout.align)?; self.memory_mut().write_repeat(ptr, val_byte, ty_layout.size * count)?; From 56f1ef325a193c366f327d7ec1d6633b36331242 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Nov 2018 10:29:16 +0100 Subject: [PATCH 0381/5092] remove spurious assignments --- src/fn_call.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 41b3c1f7e660..509db0355e2b 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -316,7 +316,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "memrchr" => { let ptr = self.read_scalar(args[0])?.not_undef()?; - let ptr = ptr; let val = self.read_scalar(args[1])?.to_bytes()? as u8; let num = self.read_scalar(args[2])?.to_usize(self)?; if let Some(idx) = self.memory().read_bytes(ptr, Size::from_bytes(num))? @@ -331,7 +330,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "memchr" => { let ptr = self.read_scalar(args[0])?.not_undef()?; - let ptr = ptr; let val = self.read_scalar(args[1])?.to_bytes()? as u8; let num = self.read_scalar(args[2])?.to_usize(self)?; if let Some(idx) = self.memory().read_bytes(ptr, Size::from_bytes(num))?.iter().position( From 731f35154376e01180d2c238920033ced2a9ae34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 17 Nov 2018 12:24:27 +0100 Subject: [PATCH 0382/5092] benchmarks: make them build again --- benches/fibonacci.rs | 4 ++-- benches/helpers/miri_helper.rs | 4 ++-- benches/repeat.rs | 4 ++-- benches/smoke.rs | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/benches/fibonacci.rs b/benches/fibonacci.rs index 90b231a32bfb..10c119d9017a 100644 --- a/benches/fibonacci.rs +++ b/benches/fibonacci.rs @@ -1,9 +1,9 @@ #![feature(test, rustc_private)] extern crate test; -use test::Bencher; +use crate::test::Bencher; mod helpers; -use helpers::*; +use crate::helpers::*; #[bench] fn fib(bencher: &mut Bencher) { diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 0fbb46246aea..015e36c4f5ad 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -8,7 +8,7 @@ use self::miri::eval_main; use self::rustc_driver::{driver, Compilation}; use std::cell::RefCell; use std::rc::Rc; -use test::Bencher; +use crate::test::Bencher; pub struct MiriCompilerCalls<'a>(Rc>); @@ -50,7 +50,7 @@ pub fn run(filename: &str, bencher: &mut Bencher) { let entry_def_id = tcx.hir.local_def_id(entry_node_id); bencher.borrow_mut().iter(|| { - eval_main(tcx, entry_def_id, None); + eval_main(tcx, entry_def_id, false); }); state.session.abort_if_errors(); diff --git a/benches/repeat.rs b/benches/repeat.rs index f5920e83d9b0..0369b1f74cf5 100644 --- a/benches/repeat.rs +++ b/benches/repeat.rs @@ -1,9 +1,9 @@ #![feature(test, rustc_private)] extern crate test; -use test::Bencher; +use crate::test::Bencher; mod helpers; -use helpers::*; +use crate::helpers::*; #[bench] fn repeat(bencher: &mut Bencher) { diff --git a/benches/smoke.rs b/benches/smoke.rs index 1dbc4fed82f1..7d614e268298 100644 --- a/benches/smoke.rs +++ b/benches/smoke.rs @@ -1,9 +1,9 @@ #![feature(test, rustc_private)] extern crate test; -use test::Bencher; +use crate::test::Bencher; mod helpers; -use helpers::*; +use crate::helpers::*; #[bench] fn noop(bencher: &mut Bencher) { From c847071355eef7c8a1555d9c25d95e8fa9eccabf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Nov 2018 12:33:44 +0100 Subject: [PATCH 0383/5092] add comment about not using builtin_deref --- src/stacked_borrows.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 2726c7dccb4f..c437eaf3fc70 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -624,6 +624,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { // a `MemPlace`, so we have a fast path for reference types that // avoids allocating. match place.layout.ty.sty { + // Cannot use `builtin_deref` because that reports *immutable* for `Box`, + // making it useless. ty::Ref(_, _, mutbl) => { // fast path let val = self.read_immediate(self.place_to_op(place)?)?; @@ -657,6 +659,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { // Primitives of reference type, that is the one thing we are interested in. fn visit_primitive(&mut self, place: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> { + // Cannot use `builtin_deref` because that reports *immutable* for `Box`, + // making it useless. let mutbl = match place.layout.ty.sty { ty::Ref(_, _, mutbl) => mutbl, ty::Adt(..) if place.layout.ty.is_box() => MutMutable, From 19f8a9db7d2eca9f693827b1437108e9cc830a6b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Nov 2018 12:35:43 +0100 Subject: [PATCH 0384/5092] Boxes can also use the fast path --- src/stacked_borrows.rs | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index c437eaf3fc70..0da130260df2 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -623,18 +623,19 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { // We need a visitor to visit all references. However, that requires // a `MemPlace`, so we have a fast path for reference types that // avoids allocating. - match place.layout.ty.sty { - // Cannot use `builtin_deref` because that reports *immutable* for `Box`, - // making it useless. - ty::Ref(_, _, mutbl) => { - // fast path - let val = self.read_immediate(self.place_to_op(place)?)?; - let val = self.retag_reference(val, mutbl)?; - self.write_immediate(val, place)?; - return Ok(()); - } - _ => {}, // handled with the general case below - }; + // Cannot use `builtin_deref` because that reports *immutable* for `Box`, + // making it useless. + if let Some(mutbl) = match place.layout.ty.sty { + ty::Ref(_, _, mutbl) => Some(mutbl), + ty::Adt(..) if place.layout.ty.is_box() => Some(MutMutable), + _ => None, // handled with the general case below + } { + // fast path + let val = self.read_immediate(self.place_to_op(place)?)?; + let val = self.retag_reference(val, mutbl)?; + self.write_immediate(val, place)?; + return Ok(()); + } let place = self.force_allocation(place)?; let mut visitor = RetagVisitor { ecx: self }; From 3102b1346808b48419d037aba0dc18f36dd22ce8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 17 Nov 2018 13:57:45 +0100 Subject: [PATCH 0385/5092] travis: build benchmarks as well --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index f989c7705b19..85dd50cb5e3c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,7 +35,7 @@ script: - set -e - | # Test and install plain miri - cargo build --release --all-features && + cargo build --release --all-features --all-targets && cargo test --release --all-features && cargo install --all-features --force --path . - | diff --git a/appveyor.yml b/appveyor.yml index 1e9ccbdf9500..f03251e669e6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -37,7 +37,7 @@ build: false test_script: - set RUSTFLAGS=-g - set RUST_BACKTRACE=1 - - cargo build --release + - cargo build --release --all-targets --all-features - cargo test --release - set MIRI_SYSROOT=%USERPROFILE%\.xargo\HOST - cargo test --release From 18b2426b1b55cd9262a60626d0622bee57fe9396 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Nov 2018 14:49:24 +0100 Subject: [PATCH 0386/5092] AppVeyor: consistently use --all-features --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index f03251e669e6..dddf8913149b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -38,9 +38,9 @@ test_script: - set RUSTFLAGS=-g - set RUST_BACKTRACE=1 - cargo build --release --all-targets --all-features - - cargo test --release + - cargo test --release --all-features - set MIRI_SYSROOT=%USERPROFILE%\.xargo\HOST - - cargo test --release + - cargo test --release --all-features notifications: - provider: Email From 06d77730dea354d3fe11920276eb13d7f1cca1f8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 19 Nov 2018 09:42:03 +0100 Subject: [PATCH 0387/5092] reorder cargo flags for consistency --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index dddf8913149b..3dc47f1c67b6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -37,7 +37,7 @@ build: false test_script: - set RUSTFLAGS=-g - set RUST_BACKTRACE=1 - - cargo build --release --all-targets --all-features + - cargo build --release --all-features --all-targets - cargo test --release --all-features - set MIRI_SYSROOT=%USERPROFILE%\.xargo\HOST - cargo test --release --all-features From a806805f2373a41f0c23604fc3bc6f9b07f6895a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 19 Nov 2018 10:26:40 +0100 Subject: [PATCH 0388/5092] add an interesting testcase --- tests/run-pass-fullmir/box-pair-to-vec.rs | 28 +++++++++++++++++++ tests/run-pass-fullmir/box-pair-to-vec.stdout | 3 ++ 2 files changed, 31 insertions(+) create mode 100644 tests/run-pass-fullmir/box-pair-to-vec.rs create mode 100644 tests/run-pass-fullmir/box-pair-to-vec.stdout diff --git a/tests/run-pass-fullmir/box-pair-to-vec.rs b/tests/run-pass-fullmir/box-pair-to-vec.rs new file mode 100644 index 000000000000..353afb9d3210 --- /dev/null +++ b/tests/run-pass-fullmir/box-pair-to-vec.rs @@ -0,0 +1,28 @@ +#[repr(C)] +#[derive(Debug)] +struct PairFoo { + fst: Foo, + snd: Foo, +} + +#[derive(Debug)] +struct Foo(u64); +fn reinterstruct(box_pair: Box) -> Vec { + let ref_pair = Box::leak(box_pair) as *mut PairFoo; + let ptr_foo = unsafe { &mut (*ref_pair).fst as *mut Foo }; + unsafe { + Vec::from_raw_parts(ptr_foo, 2, 2) + } +} + +fn main() { + let pair_foo = Box::new(PairFoo { + fst: Foo(42), + snd: Foo(1337), + }); + println!("pair_foo = {:?}", pair_foo); + for (n, foo) in reinterstruct(pair_foo).into_iter().enumerate() { + println!("foo #{} = {:?}", n, foo); + } +} + diff --git a/tests/run-pass-fullmir/box-pair-to-vec.stdout b/tests/run-pass-fullmir/box-pair-to-vec.stdout new file mode 100644 index 000000000000..230ef368da64 --- /dev/null +++ b/tests/run-pass-fullmir/box-pair-to-vec.stdout @@ -0,0 +1,3 @@ +pair_foo = PairFoo { fst: Foo(42), snd: Foo(1337) } +foo #0 = Foo(42) +foo #1 = Foo(1337) From ef2ffed93fcfa6f1731621919a1b29f8783a8fe9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 19 Nov 2018 22:59:41 +0100 Subject: [PATCH 0389/5092] port cargo-miri-test to 2018 edition, mostly to test that that works with cargo miri --- cargo-miri-test/Cargo.toml | 3 ++- cargo-miri-test/src/main.rs | 2 -- src/bin/cargo-miri.rs | 12 ++++++++++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/cargo-miri-test/Cargo.toml b/cargo-miri-test/Cargo.toml index 5fbe923f23d3..4fe009e025e1 100644 --- a/cargo-miri-test/Cargo.toml +++ b/cargo-miri-test/Cargo.toml @@ -2,6 +2,7 @@ name = "cargo-miri-test" version = "0.1.0" authors = ["Oliver Schneider "] +edition = "2018" [dependencies] -byteorder = "1.0" \ No newline at end of file +byteorder = "1.0" diff --git a/cargo-miri-test/src/main.rs b/cargo-miri-test/src/main.rs index 4e1501dd57f2..1ae88a7db594 100644 --- a/cargo-miri-test/src/main.rs +++ b/cargo-miri-test/src/main.rs @@ -1,5 +1,3 @@ -extern crate byteorder; - use byteorder::{BigEndian, ByteOrder}; fn main() { diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 69c4f122544a..da4a351368d3 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -46,11 +46,15 @@ fn main() { } if let Some("miri") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { - // this arm is when `cargo miri` is called + // this arm is when `cargo miri` is called. We call `cargo rustc` for + // each applicable target, but with the RUSTC env var set to the `cargo-miri` + // binary so that we come back in the other branch, and dispatch + // the invocations to rustc and miri, respectively. let test = std::env::args().nth(2).map_or(false, |text| text == "test"); let skip = if test { 3 } else { 2 }; + // We need to get the manifest, and then the metadata, to enumerate targets. let manifest_path_arg = std::env::args().skip(skip).find(|val| { val.starts_with("--manifest-path=") }); @@ -92,6 +96,9 @@ fn main() { }) .expect("could not find matching package"); let package = metadata.packages.remove(package_index); + + // Finally we got the metadata, iterate all targets and see for which ones + // we do anything. for target in package.targets { let args = std::env::args().skip(skip); let kind = target.kind.get(0).expect( @@ -139,7 +146,8 @@ fn main() { } } } else { - // this arm is executed when cargo-miri runs `cargo rustc` with the `RUSTC` env var set to itself + // This arm is executed when cargo-miri runs `cargo rustc` with the `RUSTC` env var set to itself: + // Dependencies get dispatched to rustc, the final test/binary to miri. let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); From b8486ce9d693aa2aa987409690bf146cef20fe41 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 Nov 2018 08:30:18 +0100 Subject: [PATCH 0390/5092] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 6c3858ccc9cd..dcd90feeda81 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-16 +nightly-2018-11-20 From 6085865975ee48283ddc7604c7be5caafabd3ccb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 Nov 2018 08:42:51 +0100 Subject: [PATCH 0391/5092] adjust for InboundsCheck parameter of memory bounds check --- src/operator.rs | 17 ++++++++++------- src/stacked_borrows.rs | 6 +++--- .../compile-fail-fullmir/out_of_bounds_ptr_1.rs | 2 +- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index e5c695009cfa..be05c2259957 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -142,8 +142,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // allocations sit right next to each other. The C/C++ standards are // somewhat fuzzy about this case, so I think for now this check is // "good enough". - self.memory().check_bounds_ptr(left, false)?; - self.memory().check_bounds_ptr(right, false)?; + // We require liveness, as dead allocations can of course overlap. + self.memory().check_bounds_ptr(left, InboundsCheck::Live)?; + self.memory().check_bounds_ptr(right, InboundsCheck::Live)?; // Two live in-bounds pointers, we can compare across allocations left == right } @@ -153,15 +154,17 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' (Scalar::Bits { bits, size }, Scalar::Ptr(ptr)) => { assert_eq!(size as u64, self.pointer_size().bytes()); let bits = bits as u64; - let (alloc_size, alloc_align) = self.memory().get_size_and_align(ptr.alloc_id); // Case I: Comparing with NULL if bits == 0 { // Test if the ptr is in-bounds. Then it cannot be NULL. - if ptr.offset <= alloc_size { + if self.memory().check_bounds_ptr(ptr, InboundsCheck::MaybeDead).is_ok() { return Ok(false); } } + + let (alloc_size, alloc_align) = self.memory().get_size_and_align(ptr.alloc_id); + // Case II: Alignment gives it away if ptr.offset.bytes() % alloc_align.abi() == 0 { // The offset maintains the allocation alignment, so we know `base+offset` @@ -293,11 +296,11 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let offset = offset.checked_mul(pointee_size).ok_or_else(|| EvalErrorKind::Overflow(mir::BinOp::Mul))?; // Now let's see what kind of pointer this is if let Scalar::Ptr(ptr) = ptr { - // Both old and new pointer must be in-bounds. + // Both old and new pointer must be in-bounds of a *live* allocation. // (Of the same allocation, but that part is trivial with our representation.) - self.memory().check_bounds_ptr(ptr, false)?; + self.memory().check_bounds_ptr(ptr, InboundsCheck::Live)?; let ptr = ptr.signed_offset(offset, self)?; - self.memory().check_bounds_ptr(ptr, false)?; + self.memory().check_bounds_ptr(ptr, InboundsCheck::Live)?; Ok(Scalar::Ptr(ptr)) } else { // An integer pointer. They can only be offset by 0, and we pretend there diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 0da130260df2..063a544baa65 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -5,7 +5,7 @@ use rustc::hir::{Mutability, MutMutable, MutImmutable}; use crate::{ EvalResult, EvalErrorKind, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, - MemoryKind, MiriMemoryKind, RangeMap, AllocId, Allocation, AllocationExtra, + MemoryKind, MiriMemoryKind, RangeMap, AllocId, Allocation, AllocationExtra, InboundsCheck, Pointer, MemPlace, Scalar, Immediate, ImmTy, PlaceTy, MPlaceTy, }; @@ -523,7 +523,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { } // Get the allocation - self.memory().check_bounds(ptr, size, false)?; + self.memory().check_bounds(ptr, size, InboundsCheck::Live)?; let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); // If we got here, we do some checking, *but* we leave the tag unchanged. if let Borrow::Shr(Some(_)) = ptr.tag { @@ -566,7 +566,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { ptr, place.layout.ty, new_bor); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. - self.memory().check_bounds(ptr, size, false)?; + self.memory().check_bounds(ptr, size, InboundsCheck::Live)?; let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); // Update the stacks. if let Borrow::Shr(Some(_)) = new_bor { diff --git a/tests/compile-fail-fullmir/out_of_bounds_ptr_1.rs b/tests/compile-fail-fullmir/out_of_bounds_ptr_1.rs index 8dce7e578626..ce1c89a2a008 100644 --- a/tests/compile-fail-fullmir/out_of_bounds_ptr_1.rs +++ b/tests/compile-fail-fullmir/out_of_bounds_ptr_1.rs @@ -1,4 +1,4 @@ -// error-pattern: pointer computed at offset 5, outside bounds of allocation +// error-pattern: must be in-bounds and live at offset 5, but is outside bounds of allocation fn main() { let v = [0i8; 4]; let x = &v as *const i8; From cfa6397ad0b26c75fd7fbb5d6f89860d1662b14d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 Nov 2018 08:50:08 +0100 Subject: [PATCH 0392/5092] UnsafeCell no longer needs to be on the whitelist --- src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d4dd198323ec..418f8f60cecd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -320,8 +320,6 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { // Uses mem::uninitialized ("std::ptr::read", ""), ("std::sys::windows::mutex::Mutex::", ""), - // Should directly take a raw reference - (">", "::get"), ]; for frame in ecx.stack().iter() .rev().take(3) From 5b095e16520e28ed2333879798f666c2a3d6c8f9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 Nov 2018 09:12:29 +0100 Subject: [PATCH 0393/5092] stdout not implemented on windows --- tests/run-pass-fullmir/box-pair-to-vec.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/run-pass-fullmir/box-pair-to-vec.rs b/tests/run-pass-fullmir/box-pair-to-vec.rs index 353afb9d3210..3b829d0f1294 100644 --- a/tests/run-pass-fullmir/box-pair-to-vec.rs +++ b/tests/run-pass-fullmir/box-pair-to-vec.rs @@ -1,3 +1,5 @@ +//ignore-msvc: Stdout not implemented on Windows + #[repr(C)] #[derive(Debug)] struct PairFoo { From 1ae536b03e90f3f2d9ef7bc0420deaf8362a85ff Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 Nov 2018 12:41:34 +0100 Subject: [PATCH 0394/5092] use 2018 edition for tests --- tests/compiletest.rs | 2 ++ tests/run-pass/stacked-borrows.rs | 12 +++++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 7ecf64590b61..7aa55ef66340 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -62,6 +62,7 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullm let mut flags = Vec::new(); flags.push(format!("--sysroot {}", sysroot.display())); flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs + flags.push("--edition 2018".to_owned()); if opt { // Optimizing too aggressivley makes UB detection harder, but test at least // the default value. @@ -98,6 +99,7 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: let mut flags = Vec::new(); flags.push(format!("--sysroot {}", sysroot.display())); flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs + flags.push("--edition 2018".to_owned()); if opt { // FIXME: We use opt level 1 because MIR inlining defeats the validation // whitelist. diff --git a/tests/run-pass/stacked-borrows.rs b/tests/run-pass/stacked-borrows.rs index 7b7a7c9be203..72f26763be14 100644 --- a/tests/run-pass/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows.rs @@ -68,13 +68,11 @@ fn mut_shr_raw() { // That should work. fn mut_raw_then_mut_shr() { let mut x = 2; - { - let xref = &mut x; - let xraw = &mut *xref as *mut _; - let xshr = &*xref; - assert_eq!(*xshr, 2); - unsafe { *xraw = 4; } - } + let xref = &mut x; + let xraw = &mut *xref as *mut _; + let xshr = &*xref; + assert_eq!(*xshr, 2); + unsafe { *xraw = 4; } assert_eq!(x, 4); } From 22f11b8eec844624a0285d2d6c6ee47880542636 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 Nov 2018 14:11:27 +0100 Subject: [PATCH 0395/5092] make tests compatible with 2018 edition --- tests/compile-fail/ctlz_nonzero.rs | 2 +- tests/compile-fail/cttz_nonzero.rs | 2 +- tests/run-pass-fullmir/foreign-fn-linkname.rs | 6 ++++-- tests/run-pass-fullmir/memchr.rs | 1 - tests/run-pass/intrinsics-integer.rs | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/compile-fail/ctlz_nonzero.rs b/tests/compile-fail/ctlz_nonzero.rs index 4e2ccd0ac508..86fd5ec46c20 100644 --- a/tests/compile-fail/ctlz_nonzero.rs +++ b/tests/compile-fail/ctlz_nonzero.rs @@ -8,7 +8,7 @@ mod rusti { pub fn main() { unsafe { - use rusti::*; + use crate::rusti::*; ctlz_nonzero(0u8); //~ ERROR constant evaluation error: ctlz_nonzero called on 0 } diff --git a/tests/compile-fail/cttz_nonzero.rs b/tests/compile-fail/cttz_nonzero.rs index 50b8df619982..a6c3b03cfb5c 100644 --- a/tests/compile-fail/cttz_nonzero.rs +++ b/tests/compile-fail/cttz_nonzero.rs @@ -8,7 +8,7 @@ mod rusti { pub fn main() { unsafe { - use rusti::*; + use crate::rusti::*; cttz_nonzero(0u8); //~ ERROR constant evaluation error: cttz_nonzero called on 0 } diff --git a/tests/run-pass-fullmir/foreign-fn-linkname.rs b/tests/run-pass-fullmir/foreign-fn-linkname.rs index 789e3eccceb7..b61cfa84ef75 100644 --- a/tests/run-pass-fullmir/foreign-fn-linkname.rs +++ b/tests/run-pass-fullmir/foreign-fn-linkname.rs @@ -9,14 +9,16 @@ // except according to those terms. //ignore-windows: Uses POSIX APIs -#![feature(libc)] + +#![feature(libc, extern_crate_item_prelude)] +#![allow(unused_extern_crates)] // rustc bug https://github.com/rust-lang/rust/issues/56098 extern crate libc; + use std::ffi::CString; mod mlibc { use libc::{c_char, size_t}; - extern { #[link_name = "strlen"] pub fn my_strlen(str: *const c_char) -> size_t; diff --git a/tests/run-pass-fullmir/memchr.rs b/tests/run-pass-fullmir/memchr.rs index 36eb85dcf7e8..2f5e2c4bb739 100644 --- a/tests/run-pass-fullmir/memchr.rs +++ b/tests/run-pass-fullmir/memchr.rs @@ -1,6 +1,5 @@ #![feature(slice_internals)] -extern crate core; use core::slice::memchr::{memchr, memrchr}; // test fallback implementations on all platforms diff --git a/tests/run-pass/intrinsics-integer.rs b/tests/run-pass/intrinsics-integer.rs index 4896f02da20b..de59314eff5a 100644 --- a/tests/run-pass/intrinsics-integer.rs +++ b/tests/run-pass/intrinsics-integer.rs @@ -23,7 +23,7 @@ mod rusti { pub fn main() { unsafe { - use rusti::*; + use crate::rusti::*; assert_eq!(ctpop(0u8), 0); assert_eq!(ctpop(0i8), 0); assert_eq!(ctpop(0u16), 0); assert_eq!(ctpop(0i16), 0); From 8d6472a76c6615ad56c693b706e1232e07537b71 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 Nov 2018 12:51:55 +0100 Subject: [PATCH 0396/5092] test self-referential generator --- ...generator_control_flow.rs => generator.rs} | 40 ++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) rename tests/run-pass/{generator_control_flow.rs => generator.rs} (65%) diff --git a/tests/run-pass/generator_control_flow.rs b/tests/run-pass/generator.rs similarity index 65% rename from tests/run-pass/generator_control_flow.rs rename to tests/run-pass/generator.rs index 900ff0e34904..603093a037c7 100644 --- a/tests/run-pass/generator_control_flow.rs +++ b/tests/run-pass/generator.rs @@ -13,11 +13,11 @@ use std::ops::{GeneratorState, Generator}; fn finish(mut amt: usize, mut t: T) -> T::Return - where T: Generator + where T: Generator { loop { match unsafe { t.resume() } { - GeneratorState::Yielded(()) => amt -= 1, + GeneratorState::Yielded(y) => amt -= y, GeneratorState::Complete(ret) => { assert_eq!(amt, 0); return ret @@ -28,38 +28,50 @@ fn finish(mut amt: usize, mut t: T) -> T::Return } fn main() { - finish(1, || yield); + finish(1, || yield 1); finish(3, || { let mut x = 0; - yield; + yield 1; x += 1; - yield; + yield 1; x += 1; - yield; + yield 1; assert_eq!(x, 2); }); - finish(8, || { - for _ in 0..8 { - yield; + finish(7*8/2, || { + for i in 0..8 { + yield i; } }); finish(1, || { if true { - yield; + yield 1; } else { } }); finish(1, || { if false { } else { - yield; + yield 1; } }); finish(2, || { - if { yield; false } { - yield; + if { yield 1; false } { + yield 1; panic!() } - yield + yield 1; }); + // also test a self-referential generator + assert_eq!( + finish(5, || { + let mut x = Box::new(5); + let y = &mut *x; + *y = 5; + yield *y; + *y = 10; + *x + }), + 10 + ); } From 7fe24a2b86bd355b20bc772e4613554ea5105ec0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 Nov 2018 16:09:06 +0100 Subject: [PATCH 0397/5092] also add an async fn test --- tests/run-pass-fullmir/async-fn.rs | 35 ++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 tests/run-pass-fullmir/async-fn.rs diff --git a/tests/run-pass-fullmir/async-fn.rs b/tests/run-pass-fullmir/async-fn.rs new file mode 100644 index 000000000000..7c32b026df67 --- /dev/null +++ b/tests/run-pass-fullmir/async-fn.rs @@ -0,0 +1,35 @@ +#![feature( + async_await, + await_macro, + futures_api, + pin, +)] + +use std::{future::Future, pin::Pin, task::Poll}; + +// See if we can run a basic `async fn` +pub async fn foo(x: &u32, y: u32) -> u32 { + let y = &y; + let z = 9; + let z = &z; + let y = await!(async { *y + *z }); + let a = 10; + let a = &a; + *x + y + *a +} + +fn main() { + use std::{sync::Arc, task::{Wake, local_waker}}; + + struct NoWake; + impl Wake for NoWake { + fn wake(_arc_self: &Arc) { + panic!(); + } + } + + let lw = unsafe { local_waker(Arc::new(NoWake)) }; + let x = 5; + let mut fut = foo(&x, 7); + assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&lw), Poll::Ready(31)); +} From 6181b29f5d9e81eb16826825da4a679e5da3f57a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 Nov 2018 09:52:31 +0100 Subject: [PATCH 0398/5092] bump Rust --- rust-version | 2 +- src/fn_call.rs | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index dcd90feeda81..a3718d44da91 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-20 +nightly-2018-11-21 diff --git a/src/fn_call.rs b/src/fn_call.rs index 509db0355e2b..5fc706c04d80 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -469,10 +469,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo instance, promoted: None, }; - let const_val = self.const_eval(cid)?; - let value = const_val.unwrap_bits( - self.tcx.tcx, - ty::ParamEnv::empty().and(self.tcx.types.i32)) as i32; + let const_val = self.const_eval_raw(cid)?; + let const_val = self.read_scalar(const_val.into())?; + let value = const_val.to_i32()?; if value == name { result = Some(path_value); break; From 0b7625a0794b9997cdd60dcc5957d8991212b86b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 Nov 2018 10:19:00 +0100 Subject: [PATCH 0399/5092] make sure compile-fail tests would compile if we screw up --- .../stacked_borrows/box_exclusive_violation1.rs | 2 +- .../stacked_borrows/mut_exclusive_violation1.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs b/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs index 73631173b932..bd0fec859d8f 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs @@ -25,5 +25,5 @@ fn unknown_code_2() { unsafe { } } fn main() { - assert_eq!(demo_mut_advanced_unique(Box::new(0)), 5); + demo_mut_advanced_unique(Box::new(0)); } diff --git a/tests/compile-fail-fullmir/stacked_borrows/mut_exclusive_violation1.rs b/tests/compile-fail-fullmir/stacked_borrows/mut_exclusive_violation1.rs index 255e35b14558..fec699e35bcf 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/mut_exclusive_violation1.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/mut_exclusive_violation1.rs @@ -25,5 +25,5 @@ fn unknown_code_2() { unsafe { } } fn main() { - assert_eq!(demo_mut_advanced_unique(&mut 0), 5); + demo_mut_advanced_unique(&mut 0); } From 984c3368a9d362eb1523d47c9efce20c793cd825 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 Nov 2018 13:40:25 +0100 Subject: [PATCH 0400/5092] remove stabilized feature flag --- src/bin/miri-rustc-tests.rs | 2 +- src/bin/miri.rs | 2 +- src/lib.rs | 2 +- tests/run-pass-fullmir/foreign-fn-linkname.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index c9ec1011ddbb..6fa9b817ffee 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -1,4 +1,4 @@ -#![feature(rustc_private, extern_crate_item_prelude)] +#![feature(rustc_private)] extern crate miri; extern crate getopts; extern crate rustc; diff --git a/src/bin/miri.rs b/src/bin/miri.rs index bfe631b51f0f..1bbf3c8c4a4a 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -1,4 +1,4 @@ -#![feature(rustc_private, extern_crate_item_prelude)] +#![feature(rustc_private)] extern crate getopts; extern crate miri; diff --git a/src/lib.rs b/src/lib.rs index 418f8f60cecd..8eae6418fa7c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(rustc_private, extern_crate_item_prelude)] +#![feature(rustc_private)] #![cfg_attr(feature = "cargo-clippy", allow(cast_lossless))] diff --git a/tests/run-pass-fullmir/foreign-fn-linkname.rs b/tests/run-pass-fullmir/foreign-fn-linkname.rs index b61cfa84ef75..3dd30fd676fd 100644 --- a/tests/run-pass-fullmir/foreign-fn-linkname.rs +++ b/tests/run-pass-fullmir/foreign-fn-linkname.rs @@ -10,7 +10,7 @@ //ignore-windows: Uses POSIX APIs -#![feature(libc, extern_crate_item_prelude)] +#![feature(libc)] #![allow(unused_extern_crates)] // rustc bug https://github.com/rust-lang/rust/issues/56098 extern crate libc; From ec8cc029c1904bcbbb6ede8fba0251c2aaaf70f8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 Nov 2018 15:44:47 +0100 Subject: [PATCH 0401/5092] on a deref, check that we are not using a mutable ref with a frozen tag --- src/stacked_borrows.rs | 39 +++++-------------- .../static_memory_modification.rs | 3 -- 2 files changed, 9 insertions(+), 33 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 063a544baa65..16cd3e916434 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -151,6 +151,12 @@ impl<'tcx> Stack { /// Returns the index of the item we matched, `None` if it was the frozen one. /// `kind` indicates which kind of reference is being dereferenced. fn deref(&self, bor: Borrow, kind: RefKind) -> Result, String> { + // Exclude unique ref and frozen tag. + match (kind, bor) { + (RefKind::Unique, Borrow::Shr(Some(_))) => + return Err(format!("Encountered mutable reference with frozen tag")), + _ => {} + } // Checks related to freezing match bor { Borrow::Shr(Some(bor_t)) if kind == RefKind::Frozen => { @@ -490,36 +496,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { if let Some(mutability) = mutability { format!("{:?}", mutability) } else { format!("raw") }, place.ptr, place.layout.ty); let ptr = place.ptr.to_ptr()?; - // In principle we should not have to do anything here. However, with transmutes involved, - // it can happen that the tag of `ptr` does not actually match `mutability`, and we - // should adjust for that. - // Notably, the compiler can introduce such transmutes by optimizing away `&[mut]*`. - // That can transmute a raw ptr to a (shared/mut) ref, and a mut ref to a shared one. - match (mutability, ptr.tag) { - (None, _) => { - // No further validation on raw accesses. - return Ok(()); - } - (Some(MutMutable), Borrow::Uniq(_)) | - (Some(MutImmutable), Borrow::Shr(_)) => { - // Expected combinations. Nothing to do. - } - (Some(MutMutable), Borrow::Shr(None)) => { - // Raw transmuted to mut ref. This is something real unsafe code does. - // We cannot reborrow here because we do not want to mutate state on a deref. - } - (Some(MutImmutable), Borrow::Uniq(_)) => { - // A mut got transmuted to shr. Can happen even from compiler transformations: - // `&*x` gets optimized to `x` even when `x` is a `&mut`. - } - (Some(MutMutable), Borrow::Shr(Some(_))) => { - // This is just invalid: A shr got transmuted to a mut. - // If we ever allow this, we have to consider what we do when a turn a - // `Raw`-tagged `&mut` into a raw pointer pointing to a frozen location. - // We probably do not want to allow that, but we have to allow - // turning a `Raw`-tagged `&` into a raw ptr to a frozen location. - return err!(MachineError(format!("Encountered mutable reference with frozen tag {:?}", ptr.tag))) - } + if mutability.is_none() { + // No further checks on raw derefs -- only the access itself will be checked. + return Ok(()); } // Get the allocation diff --git a/tests/compile-fail-fullmir/stacked_borrows/static_memory_modification.rs b/tests/compile-fail-fullmir/stacked_borrows/static_memory_modification.rs index 5c605eff6784..c092cbfe5098 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/static_memory_modification.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/static_memory_modification.rs @@ -1,6 +1,3 @@ -// FIXME still considering whether we are okay with this not being an error -// ignore-test - static X: usize = 5; #[allow(mutable_transmutes)] From 41f89beb3f03cb7cdbfbd754ac2eee9e1f153f18 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 Nov 2018 16:01:39 +0100 Subject: [PATCH 0402/5092] if let --- src/stacked_borrows.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 16cd3e916434..21addbfbf789 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -151,11 +151,9 @@ impl<'tcx> Stack { /// Returns the index of the item we matched, `None` if it was the frozen one. /// `kind` indicates which kind of reference is being dereferenced. fn deref(&self, bor: Borrow, kind: RefKind) -> Result, String> { - // Exclude unique ref and frozen tag. - match (kind, bor) { - (RefKind::Unique, Borrow::Shr(Some(_))) => - return Err(format!("Encountered mutable reference with frozen tag")), - _ => {} + // Exclude unique ref with frozen tag. + if let (RefKind::Unique, Borrow::Shr(Some(_))) = (kind, bor) { + return Err(format!("Encountered mutable reference with frozen tag")); } // Checks related to freezing match bor { From 694d2490f1f10cc46aff0452874ade547e4936b9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 Nov 2018 16:02:38 +0100 Subject: [PATCH 0403/5092] slightly more verbose error msg --- src/stacked_borrows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 21addbfbf789..f26ef40ea9f8 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -153,7 +153,7 @@ impl<'tcx> Stack { fn deref(&self, bor: Borrow, kind: RefKind) -> Result, String> { // Exclude unique ref with frozen tag. if let (RefKind::Unique, Borrow::Shr(Some(_))) = (kind, bor) { - return Err(format!("Encountered mutable reference with frozen tag")); + return Err(format!("Encountered mutable reference with frozen tag ({:?})", bor)); } // Checks related to freezing match bor { From 04794c4c2ac20e66043c235b45c19f6759f48dc9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 Nov 2018 16:08:46 +0100 Subject: [PATCH 0404/5092] test that we support partial invalidation of mutable references --- tests/run-pass/stacked-borrows.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/run-pass/stacked-borrows.rs b/tests/run-pass/stacked-borrows.rs index 72f26763be14..93bdf5ffbf32 100644 --- a/tests/run-pass/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows.rs @@ -7,6 +7,7 @@ fn main() { mut_shr_raw(); mut_raw_then_mut_shr(); mut_raw_mut(); + partially_invalidate_mut(); } // Deref a raw ptr to access a field of a large struct, where the field @@ -97,3 +98,12 @@ fn mut_raw_mut() { } assert_eq!(x, 4); } + +fn partially_invalidate_mut() { + let data = &mut (0u8, 0u8); + let reborrow = &mut *data as *mut (u8, u8); + let shard = unsafe { &mut (*reborrow).0 }; + data.1 += 1; // the deref overlaps with `shard`, but that is okay; the access does not overlap. + *shard += 1; // so we can still use `shard`. + assert_eq!(*data, (1, 1)); +} From 1703d31eacccc80beedc8bc4b393df0027531e60 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 22 Nov 2018 08:21:26 +0100 Subject: [PATCH 0405/5092] bump rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index a3718d44da91..23a0fa102b00 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-21 +nightly-2018-11-22 From 68ba6cdbaa758484f56d8c7f5628ccfcb772756e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 23 Nov 2018 09:46:51 +0100 Subject: [PATCH 0406/5092] fix for new Align type --- src/fn_call.rs | 16 ++++++++-------- src/helpers.rs | 5 +++-- src/intrinsic.rs | 8 ++++---- src/lib.rs | 12 ++++++------ src/operator.rs | 8 ++++---- 5 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 5fc706c04d80..e64d4f695487 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -124,7 +124,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo if size == 0 { self.write_null(dest)?; } else { - let align = self.tcx.data_layout.pointer_align; + let align = self.tcx.data_layout.pointer_align.abi; let ptr = self.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into())?; self.write_scalar(Scalar::Ptr(ptr.with_default_tag()), dest)?; } @@ -153,7 +153,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let ptr = self.memory_mut() .allocate( Size::from_bytes(size), - Align::from_bytes(align, align).unwrap(), + Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into() )? .with_default_tag(); @@ -171,7 +171,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let ptr = self.memory_mut() .allocate( Size::from_bytes(size), - Align::from_bytes(align, align).unwrap(), + Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into() )? .with_default_tag(); @@ -190,7 +190,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } self.memory_mut().deallocate( ptr, - Some((Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap())), + Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())), MiriMemoryKind::Rust.into(), )?; } @@ -208,9 +208,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let new_ptr = self.memory_mut().reallocate( ptr, Size::from_bytes(old_size), - Align::from_bytes(align, align).unwrap(), + Align::from_bytes(align).unwrap(), Size::from_bytes(new_size), - Align::from_bytes(align, align).unwrap(), + Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into(), )?; self.write_scalar(Scalar::Ptr(new_ptr.with_default_tag()), dest)?; @@ -394,7 +394,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // +1 for the null terminator let value_copy = self.memory_mut().allocate( Size::from_bytes((value.len() + 1) as u64), - Align::from_bytes(1, 1).unwrap(), + Align::from_bytes(1).unwrap(), MiriMemoryKind::Env.into(), )?.with_default_tag(); self.memory_mut().write_bytes(value_copy.into(), &value)?; @@ -513,7 +513,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } self.memory_mut().write_scalar( key_ptr, - key_layout.align, + key_layout.align.abi, Scalar::from_uint(key, key_layout.size).into(), key_layout.size, )?; diff --git a/src/helpers.rs b/src/helpers.rs index 85329ddcf17f..2b1a28fe9e0d 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -130,9 +130,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: unsafe_cell_action: |place| { trace!("unsafe_cell_action on {:?}", place.ptr); // We need a size to go on. - let (unsafe_cell_size, _) = self.size_and_align_of_mplace(place)? + let unsafe_cell_size = self.size_and_align_of_mplace(place)? + .map(|(size, _)| size) // for extern types, just cover what we can - .unwrap_or_else(|| place.layout.size_and_align()); + .unwrap_or_else(|| place.layout.size); // Now handle this `UnsafeCell`, unless it is empty. if unsafe_cell_size != Size::ZERO { unsafe_cell_action(place.ptr, unsafe_cell_size) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 6d5ac8d88bae..66dab00e0975 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -152,7 +152,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let elem_layout = self.layout_of(elem_ty)?; let elem_size = elem_layout.size.bytes(); let count = self.read_scalar(args[2])?.to_usize(self)?; - let elem_align = elem_layout.align; + let elem_align = elem_layout.align.abi; // erase tags: this is a raw ptr operation let src = self.read_scalar(args[0])?.not_undef()?; let dest = self.read_scalar(args[1])?.not_undef()?; @@ -272,7 +272,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "pref_align_of" => { let ty = substs.type_at(0); let layout = self.layout_of(ty)?; - let align = layout.align.pref(); + let align = layout.align.pref.bytes(); let ptr_size = self.pointer_size(); let align_val = Scalar::from_uint(align as u128, ptr_size); self.write_scalar(align_val, dest)?; @@ -364,7 +364,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' .expect("size_of_val called on extern type"); let ptr_size = self.pointer_size(); self.write_scalar( - Scalar::from_uint(align.abi(), ptr_size), + Scalar::from_uint(align.bytes(), ptr_size), dest, )?; } @@ -438,7 +438,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let val_byte = self.read_scalar(args[1])?.to_u8()?; let ptr = self.read_scalar(args[0])?.not_undef()?; let count = self.read_scalar(args[2])?.to_usize(self)?; - self.memory().check_align(ptr, ty_layout.align)?; + self.memory().check_align(ptr, ty_layout.align.abi)?; self.memory_mut().write_repeat(ptr, val_byte, ty_layout.size * count)?; } diff --git a/src/lib.rs b/src/lib.rs index 8eae6418fa7c..10a1405b2a62 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -397,7 +397,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { // Second argument: align let arg = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - let align = layout.align.abi(); + let align = layout.align.abi.bytes(); ecx.write_scalar(Scalar::from_uint(align, arg.layout.size), arg)?; // No more arguments @@ -419,7 +419,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { "__cxa_thread_atexit_impl" => { // This should be all-zero, pointer-sized let data = vec![0; tcx.data_layout.pointer_size.bytes() as usize]; - Allocation::from_bytes(&data[..], tcx.data_layout.pointer_align) + Allocation::from_bytes(&data[..], tcx.data_layout.pointer_align.abi) } _ => return err!(Unimplemented( format!("can't access foreign static: {}", link_name), @@ -458,9 +458,9 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { place: MPlaceTy<'tcx, Borrow>, mutability: Option, ) -> EvalResult<'tcx, Scalar> { - let (size, _) = ecx.size_and_align_of_mplace(place)? + let size = ecx.size_and_align_of_mplace(place)?.map(|(size, _)| size) // for extern types, just cover what we can - .unwrap_or_else(|| place.layout.size_and_align()); + .unwrap_or_else(|| place.layout.size); if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !Self::enforce_validity(ecx) || size == Size::ZERO { @@ -498,9 +498,9 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { // This is deliberately NOT `deref_operand` as we do not want `tag_dereference` // to be called! That would kill the original tag if we got a raw ptr. let place = ecx.ref_to_mplace(ecx.read_immediate(ptr)?)?; - let (size, _) = ecx.size_and_align_of_mplace(place)? + let size = ecx.size_and_align_of_mplace(place)?.map(|(size, _)| size) // for extern types, just cover what we can - .unwrap_or_else(|| place.layout.size_and_align()); + .unwrap_or_else(|| place.layout.size); if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !ecx.machine.validate || size == Size::ZERO { diff --git a/src/operator.rs b/src/operator.rs index be05c2259957..2f3a0de999ad 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -166,12 +166,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let (alloc_size, alloc_align) = self.memory().get_size_and_align(ptr.alloc_id); // Case II: Alignment gives it away - if ptr.offset.bytes() % alloc_align.abi() == 0 { + if ptr.offset.bytes() % alloc_align.bytes() == 0 { // The offset maintains the allocation alignment, so we know `base+offset` // is aligned by `alloc_align`. // FIXME: We could be even more general, e.g. offset 2 into a 4-aligned // allocation cannot equal 3. - if bits % alloc_align.abi() != 0 { + if bits % alloc_align.bytes() != 0 { // The integer is *not* aligned. So they cannot be equal. return Ok(false); } @@ -226,7 +226,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' map_to_primval(left.overflowing_offset(Size::from_bytes(right as u64), self)), BitAnd if !signed => { - let ptr_base_align = self.memory().get(left.alloc_id)?.align.abi(); + let ptr_base_align = self.memory().get(left.alloc_id)?.align.bytes(); let base_mask = { // FIXME: Use interpret::truncate, once that takes a Size instead of a Layout let shift = 128 - self.memory().pointer_size().bits(); @@ -259,7 +259,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' Rem if !signed => { // Doing modulo a divisor of the alignment is allowed. // (Intuition: Modulo a divisor leaks less information.) - let ptr_base_align = self.memory().get(left.alloc_id)?.align.abi(); + let ptr_base_align = self.memory().get(left.alloc_id)?.align.bytes(); let right = right as u64; let ptr_size = self.memory().pointer_size().bytes() as u8; if right == 1 { From 32e93ed7762e5aa1a721636096848fc3c7bc7218 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 13 Nov 2018 17:19:42 +0100 Subject: [PATCH 0407/5092] Update to Memory -> Allocation method move --- src/fn_call.rs | 40 +++++++++++++++++++++++++--------------- src/intrinsic.rs | 21 +++++++++++++++++---- src/operator.rs | 18 +++++++++++------- src/stacked_borrows.rs | 10 +++++----- 4 files changed, 58 insertions(+), 31 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index e64d4f695487..e9d3255a5b32 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -114,6 +114,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo None => self.tcx.item_name(def_id).as_str(), }; + let tcx = &{self.tcx.tcx}; + // All these functions take raw pointers, so if we access memory directly // (as opposed to through a place), we have to remember to erase any tag // that might still hang around! @@ -175,7 +177,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo MiriMemoryKind::Rust.into() )? .with_default_tag(); - self.memory_mut().write_repeat(ptr.into(), 0, Size::from_bytes(size))?; + self.memory_mut() + .get_mut(ptr.alloc_id)? + .write_repeat(tcx, ptr, 0, Size::from_bytes(size))?; self.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_dealloc" => { @@ -239,7 +243,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "dlsym" => { let _handle = self.read_scalar(args[0])?; let symbol = self.read_scalar(args[1])?.to_ptr()?; - let symbol_name = self.memory().read_c_str(symbol)?; + let symbol_name = self.memory().get(symbol.alloc_id)?.read_c_str(tcx, symbol)?; let err = format!("bad c unicode symbol: {:?}", symbol_name); let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err); return err!(Unimplemented(format!( @@ -346,7 +350,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "getenv" => { let result = { let name_ptr = self.read_scalar(args[0])?.to_ptr()?; - let name = self.memory().read_c_str(name_ptr)?; + let name = self.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?; match self.machine.env_vars.get(name) { Some(&var) => Scalar::Ptr(var), None => Scalar::ptr_null(&*self.tcx), @@ -360,8 +364,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo { let name_ptr = self.read_scalar(args[0])?.not_undef()?; if !name_ptr.is_null_ptr(self) { - let name = self.memory().read_c_str(name_ptr.to_ptr()? - )?.to_owned(); + let name_ptr = name_ptr.to_ptr()?; + let name = self.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?.to_owned(); if !name.is_empty() && !name.contains(&b'=') { success = Some(self.machine.env_vars.remove(&name)); } @@ -382,9 +386,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo { let name_ptr = self.read_scalar(args[0])?.not_undef()?; let value_ptr = self.read_scalar(args[1])?.to_ptr()?; - let value = self.memory().read_c_str(value_ptr)?; + let value = self.memory().get(value_ptr.alloc_id)?.read_c_str(tcx, value_ptr)?; if !name_ptr.is_null_ptr(self) { - let name = self.memory().read_c_str(name_ptr.to_ptr()?)?; + let name_ptr = name_ptr.to_ptr()?; + let name = self.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?; if !name.is_empty() && !name.contains(&b'=') { new = Some((name.to_owned(), value.to_owned())); } @@ -397,9 +402,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo Align::from_bytes(1).unwrap(), MiriMemoryKind::Env.into(), )?.with_default_tag(); - self.memory_mut().write_bytes(value_copy.into(), &value)?; - let trailing_zero_ptr = value_copy.offset(Size::from_bytes(value.len() as u64), self)?.into(); - self.memory_mut().write_bytes(trailing_zero_ptr, &[0])?; + { + let alloc = self.memory_mut().get_mut(value_copy.alloc_id)?; + alloc.write_bytes(tcx, value_copy, &value)?; + let trailing_zero_ptr = value_copy.offset(Size::from_bytes(value.len() as u64), tcx)?; + alloc.write_bytes(tcx, trailing_zero_ptr, &[0])?; + } if let Some(var) = self.machine.env_vars.insert( name.to_owned(), value_copy, @@ -444,7 +452,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "strlen" => { let ptr = self.read_scalar(args[0])?.to_ptr()?; - let n = self.memory().read_c_str(ptr)?.len(); + let n = self.memory().get(ptr.alloc_id)?.read_c_str(tcx, ptr)?.len(); self.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; } @@ -507,13 +515,15 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let key_layout = self.layout_of(key_type)?; // Create key and write it into the memory where key_ptr wants it - let key = self.machine.tls.create_tls_key(dtor, &*self.tcx) as u128; + let key = self.machine.tls.create_tls_key(dtor, tcx) as u128; if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) { return err!(OutOfTls); } - self.memory_mut().write_scalar( + + self.memory().check_align(key_ptr.into(), key_layout.align.abi)?; + self.memory_mut().get_mut(key_ptr.alloc_id)?.write_scalar( + tcx, key_ptr, - key_layout.align.abi, Scalar::from_uint(key, key_layout.size).into(), key_layout.size, )?; @@ -610,7 +620,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // This just creates a key; Windows does not natively support TLS dtors. // Create key and return it - let key = self.machine.tls.create_tls_key(None, &*self.tcx) as u128; + let key = self.machine.tls.create_tls_key(None, tcx) as u128; // Figure out how large a TLS key actually is. This is c::DWORD. if dest.layout.size.bits() < 128 && key >= (1u128 << dest.layout.size.bits() as u128) { diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 66dab00e0975..c9b16525e566 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -28,7 +28,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' if self.emulate_intrinsic(instance, args, dest)? { return Ok(()); } - + let tcx = &{self.tcx.tcx}; let substs = instance.substs; // All these intrinsics take raw pointers, so if we access memory directly @@ -248,6 +248,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // FIXME: We do not properly validate in case of ZSTs and when doing it in memory! // However, this only affects direct calls of the intrinsic; calls to the stable // functions wrapping them do get their validation. + // FIXME: should we check that the destination pointer is aligned even for ZSTs? if !dest.layout.is_zst() { // nothing to do for ZST match dest.layout.abi { layout::Abi::Scalar(ref s) => { @@ -263,7 +264,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Do it in memory let mplace = self.force_allocation(dest)?; assert!(mplace.meta.is_none()); - self.memory_mut().write_repeat(mplace.ptr, 0, dest.layout.size)?; + // not a zst, must be valid pointer + let ptr = mplace.ptr.to_ptr()?; + self.memory_mut().get_mut(ptr.alloc_id)?.write_repeat(tcx, ptr, 0, dest.layout.size)?; } } } @@ -412,6 +415,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // FIXME: We do not properly validate in case of ZSTs and when doing it in memory! // However, this only affects direct calls of the intrinsic; calls to the stable // functions wrapping them do get their validation. + // FIXME: should we check alignment for ZSTs? if !dest.layout.is_zst() { // nothing to do for ZST match dest.layout.abi { layout::Abi::Scalar(..) => { @@ -426,7 +430,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Do it in memory let mplace = self.force_allocation(dest)?; assert!(mplace.meta.is_none()); - self.memory_mut().mark_definedness(mplace.ptr.to_ptr()?, dest.layout.size, false)?; + let ptr = mplace.ptr.to_ptr()?; + self.memory_mut() + .get_mut(ptr.alloc_id)? + .mark_definedness(ptr, dest.layout.size, false)?; } } } @@ -439,7 +446,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let ptr = self.read_scalar(args[0])?.not_undef()?; let count = self.read_scalar(args[2])?.to_usize(self)?; self.memory().check_align(ptr, ty_layout.align.abi)?; - self.memory_mut().write_repeat(ptr, val_byte, ty_layout.size * count)?; + let byte_count = ty_layout.size * count; + if byte_count.bytes() != 0 { + let ptr = ptr.to_ptr()?; + self.memory_mut() + .get_mut(ptr.alloc_id)? + .write_repeat(tcx, ptr, val_byte, byte_count)?; + } } name => return err!(Unimplemented(format!("unimplemented intrinsic: {}", name))), diff --git a/src/operator.rs b/src/operator.rs index 2f3a0de999ad..e1ccdf91995e 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -142,10 +142,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // allocations sit right next to each other. The C/C++ standards are // somewhat fuzzy about this case, so I think for now this check is // "good enough". - // We require liveness, as dead allocations can of course overlap. - self.memory().check_bounds_ptr(left, InboundsCheck::Live)?; - self.memory().check_bounds_ptr(right, InboundsCheck::Live)?; - // Two live in-bounds pointers, we can compare across allocations + // Dead allocations in miri cannot overlap with live allocations, but + // on read hardware this can easily happen. Thus for comparisons we require + // both pointers to be live. + self.memory().get(left.alloc_id)?.check_bounds_ptr(left)?; + self.memory().get(right.alloc_id)?.check_bounds_ptr(right)?; + // Two in-bounds pointers, we can compare across allocations left == right } } @@ -158,7 +160,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Case I: Comparing with NULL if bits == 0 { // Test if the ptr is in-bounds. Then it cannot be NULL. - if self.memory().check_bounds_ptr(ptr, InboundsCheck::MaybeDead).is_ok() { + // Even dangling pointers cannot be NULL. + if self.memory().check_bounds_ptr_maybe_dead(ptr).is_ok() { return Ok(false); } } @@ -298,9 +301,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' if let Scalar::Ptr(ptr) = ptr { // Both old and new pointer must be in-bounds of a *live* allocation. // (Of the same allocation, but that part is trivial with our representation.) - self.memory().check_bounds_ptr(ptr, InboundsCheck::Live)?; + let alloc = self.memory().get(ptr.alloc_id)?; + alloc.check_bounds_ptr(ptr)?; let ptr = ptr.signed_offset(offset, self)?; - self.memory().check_bounds_ptr(ptr, InboundsCheck::Live)?; + alloc.check_bounds_ptr(ptr)?; Ok(Scalar::Ptr(ptr)) } else { // An integer pointer. They can only be offset by 0, and we pretend there diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index f26ef40ea9f8..f292d083637a 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -5,7 +5,7 @@ use rustc::hir::{Mutability, MutMutable, MutImmutable}; use crate::{ EvalResult, EvalErrorKind, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, - MemoryKind, MiriMemoryKind, RangeMap, AllocId, Allocation, AllocationExtra, InboundsCheck, + MemoryKind, MiriMemoryKind, RangeMap, AllocId, Allocation, AllocationExtra, Pointer, MemPlace, Scalar, Immediate, ImmTy, PlaceTy, MPlaceTy, }; @@ -500,8 +500,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { } // Get the allocation - self.memory().check_bounds(ptr, size, InboundsCheck::Live)?; - let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); + let alloc = self.memory().get(ptr.alloc_id)?; + alloc.check_bounds(self, ptr, size)?; // If we got here, we do some checking, *but* we leave the tag unchanged. if let Borrow::Shr(Some(_)) = ptr.tag { assert_eq!(mutability, Some(MutImmutable)); @@ -543,8 +543,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { ptr, place.layout.ty, new_bor); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. - self.memory().check_bounds(ptr, size, InboundsCheck::Live)?; - let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); + let alloc = self.memory().get(ptr.alloc_id)?; + alloc.check_bounds(self, ptr, size)?; // Update the stacks. if let Borrow::Shr(Some(_)) = new_bor { // Reference that cares about freezing. We need a frozen-sensitive reborrow. From 82d4146a6c3fec5d0f87e3df6423f123dec784f6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 24 Nov 2018 11:58:28 +0100 Subject: [PATCH 0408/5092] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 23a0fa102b00..5bdac314d169 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-22 +nightly-2018-11-24 From ac9649b7c0fc0f106d4dc93ab3c4d9ff25228f32 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 26 Nov 2018 08:54:24 +0100 Subject: [PATCH 0409/5092] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 5bdac314d169..0268b07ac411 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-24 +nightly-2018-11-26 From 7d623f73cc5c592c703f68d8079f78055841e113 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 26 Nov 2018 15:31:53 +0100 Subject: [PATCH 0410/5092] do not use 'let _', it is strange --- tests/compile-fail-fullmir/ptr_offset_overflow.rs | 2 +- tests/compile-fail/invalid_enum_discriminant.rs | 2 +- tests/compile-fail/pointer_byte_read_1.rs | 2 +- tests/compile-fail/pointer_byte_read_2.rs | 2 +- tests/compile-fail/ptr_bitops2.rs | 2 +- tests/compile-fail/ptr_int_cast.rs | 2 +- tests/compile-fail/ptr_offset_int_plus_int.rs | 2 +- tests/compile-fail/ptr_offset_int_plus_ptr.rs | 2 +- tests/compile-fail/ptr_rem.rs | 2 +- tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs | 2 +- tests/compile-fail/transmute_fat1.rs | 2 +- tests/compile-fail/validity/invalid_char.rs | 2 +- tests/compile-fail/zst.rs | 2 +- tests/run-pass-fullmir/catch.rs | 2 +- tests/run-pass-fullmir/from_utf8.rs | 2 +- tests/run-pass-fullmir/threads.rs | 6 +++--- tests/run-pass/closure-drop.rs | 2 +- tests/run-pass/drop_empty_slice.rs | 2 +- tests/run-pass/issue-20575.rs | 2 +- tests/run-pass/issue-26709.rs | 2 +- tests/run-pass/issue-33387.rs | 2 +- tests/run-pass/issue-miri-184.rs | 2 +- tests/run-pass/sendable-class.rs | 4 ++-- tests/run-pass/slices.rs | 4 ++-- 24 files changed, 28 insertions(+), 28 deletions(-) diff --git a/tests/compile-fail-fullmir/ptr_offset_overflow.rs b/tests/compile-fail-fullmir/ptr_offset_overflow.rs index 32ab2daebf0d..babd0246e7e1 100644 --- a/tests/compile-fail-fullmir/ptr_offset_overflow.rs +++ b/tests/compile-fail-fullmir/ptr_offset_overflow.rs @@ -2,5 +2,5 @@ fn main() { let v = [1i8, 2]; let x = &v[1] as *const i8; - let _ = unsafe { x.offset(isize::min_value()) }; + let _val = unsafe { x.offset(isize::min_value()) }; } diff --git a/tests/compile-fail/invalid_enum_discriminant.rs b/tests/compile-fail/invalid_enum_discriminant.rs index bd5cb55b6c92..c1b8727c129b 100644 --- a/tests/compile-fail/invalid_enum_discriminant.rs +++ b/tests/compile-fail/invalid_enum_discriminant.rs @@ -12,5 +12,5 @@ pub enum Foo { fn main() { let f = unsafe { std::mem::transmute::(42) }; - let _ = mem::discriminant(&f); + let _val = mem::discriminant(&f); } diff --git a/tests/compile-fail/pointer_byte_read_1.rs b/tests/compile-fail/pointer_byte_read_1.rs index b25f09d485fb..a584863654ce 100644 --- a/tests/compile-fail/pointer_byte_read_1.rs +++ b/tests/compile-fail/pointer_byte_read_1.rs @@ -3,5 +3,5 @@ fn main() { let y = &x; let z = &y as *const &i32 as *const usize; let ptr_bytes = unsafe { *z }; // the actual deref is fine, because we read the entire pointer at once - let _ = ptr_bytes / 432; //~ ERROR invalid arithmetic on pointers that would leak base addresses + let _val = ptr_bytes / 432; //~ ERROR invalid arithmetic on pointers that would leak base addresses } diff --git a/tests/compile-fail/pointer_byte_read_2.rs b/tests/compile-fail/pointer_byte_read_2.rs index 5df8c4782c7f..ddb9bc1f995f 100644 --- a/tests/compile-fail/pointer_byte_read_2.rs +++ b/tests/compile-fail/pointer_byte_read_2.rs @@ -3,5 +3,5 @@ fn main() { let y = &x; let z = &y as *const &i32 as *const u8; // the deref fails, because we are reading only a part of the pointer - let _ = unsafe { *z }; //~ ERROR tried to access part of a pointer value as raw bytes + let _val = unsafe { *z }; //~ ERROR tried to access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/ptr_bitops2.rs b/tests/compile-fail/ptr_bitops2.rs index 233c9a733c99..5d5eab155083 100644 --- a/tests/compile-fail/ptr_bitops2.rs +++ b/tests/compile-fail/ptr_bitops2.rs @@ -1,5 +1,5 @@ fn main() { let val = 13usize; let addr = &val as *const _ as usize; - let _ = addr & 13; //~ ERROR access part of a pointer value as raw bytes + let _val = addr & 13; //~ ERROR access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/ptr_int_cast.rs b/tests/compile-fail/ptr_int_cast.rs index 576f0c333d18..a823a0f49b63 100644 --- a/tests/compile-fail/ptr_int_cast.rs +++ b/tests/compile-fail/ptr_int_cast.rs @@ -4,5 +4,5 @@ fn main() { let x = x as *const i32; let x = x as u8; //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes let x = x as *const i32; - let _ = unsafe { *x }; + let _val = unsafe { *x }; } diff --git a/tests/compile-fail/ptr_offset_int_plus_int.rs b/tests/compile-fail/ptr_offset_int_plus_int.rs index fa4efa323654..d02739610814 100644 --- a/tests/compile-fail/ptr_offset_int_plus_int.rs +++ b/tests/compile-fail/ptr_offset_int_plus_int.rs @@ -3,6 +3,6 @@ fn main() { // Can't offset an integer pointer by non-zero offset. unsafe { - let _ = (1 as *mut u8).offset(1); + let _val = (1 as *mut u8).offset(1); } } diff --git a/tests/compile-fail/ptr_offset_int_plus_ptr.rs b/tests/compile-fail/ptr_offset_int_plus_ptr.rs index b45548935807..b49c758c72f7 100644 --- a/tests/compile-fail/ptr_offset_int_plus_ptr.rs +++ b/tests/compile-fail/ptr_offset_int_plus_ptr.rs @@ -4,6 +4,6 @@ fn main() { let ptr = Box::into_raw(Box::new(0u32)); // Can't start with an integer pointer and get to something usable unsafe { - let _ = (1 as *mut u8).offset(ptr as isize); + let _val = (1 as *mut u8).offset(ptr as isize); } } diff --git a/tests/compile-fail/ptr_rem.rs b/tests/compile-fail/ptr_rem.rs index 8a3665872f7c..dfc91e9dc1b1 100644 --- a/tests/compile-fail/ptr_rem.rs +++ b/tests/compile-fail/ptr_rem.rs @@ -1,5 +1,5 @@ fn main() { let val = 13usize; let addr = &val as *const _ as usize; - let _ = addr % 16; //~ ERROR access part of a pointer value as raw bytes + let _val = addr % 16; //~ ERROR access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs b/tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs index b3dda27fad1e..eacb9f07fffd 100644 --- a/tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs +++ b/tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs @@ -4,5 +4,5 @@ fn main() { let ptr = Box::into_raw(Box::new(0u32)); // Can't start with an integer pointer and get to something usable let ptr = (1 as *mut u8).wrapping_offset(ptr as isize); - let _ = unsafe { *ptr }; + let _val = unsafe { *ptr }; } diff --git a/tests/compile-fail/transmute_fat1.rs b/tests/compile-fail/transmute_fat1.rs index ede0486be413..ddc78c8bf1d4 100644 --- a/tests/compile-fail/transmute_fat1.rs +++ b/tests/compile-fail/transmute_fat1.rs @@ -10,5 +10,5 @@ fn main() { let bad = unsafe { std::mem::transmute::<&[u8], [u8; 8]>(&[1u8]) }; - let _ = bad[0] + bad[bad.len()-1]; //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes + let _val = bad[0] + bad[bad.len()-1]; //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/validity/invalid_char.rs b/tests/compile-fail/validity/invalid_char.rs index 0d75ad9d2890..a3f907036349 100644 --- a/tests/compile-fail/validity/invalid_char.rs +++ b/tests/compile-fail/validity/invalid_char.rs @@ -1,6 +1,6 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); - let _ = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered 4294967295, but expected something less or equal to 1114111 + let _val = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered 4294967295, but expected something less or equal to 1114111 'a' => {true}, 'b' => {false}, _ => {true}, diff --git a/tests/compile-fail/zst.rs b/tests/compile-fail/zst.rs index 544d65a1bffa..0488926870a2 100644 --- a/tests/compile-fail/zst.rs +++ b/tests/compile-fail/zst.rs @@ -1,4 +1,4 @@ fn main() { let x = &() as *const () as *const i32; - let _ = unsafe { *x }; //~ ERROR access memory with alignment 1, but alignment 4 is required + let _val = unsafe { *x }; //~ ERROR access memory with alignment 1, but alignment 4 is required } diff --git a/tests/run-pass-fullmir/catch.rs b/tests/run-pass-fullmir/catch.rs index 960297daa7ef..aa7bccaa5ff3 100644 --- a/tests/run-pass-fullmir/catch.rs +++ b/tests/run-pass-fullmir/catch.rs @@ -3,6 +3,6 @@ use std::panic::{catch_unwind, AssertUnwindSafe}; fn main() { let mut i = 3; - let _ = catch_unwind(AssertUnwindSafe(|| {i -= 2;} )); + let _val = catch_unwind(AssertUnwindSafe(|| {i -= 2;} )); println!("{}", i); } diff --git a/tests/run-pass-fullmir/from_utf8.rs b/tests/run-pass-fullmir/from_utf8.rs index 69e6c521af6e..ce59e60a932d 100644 --- a/tests/run-pass-fullmir/from_utf8.rs +++ b/tests/run-pass-fullmir/from_utf8.rs @@ -1,3 +1,3 @@ fn main() { - let _ = ::std::str::from_utf8(b"a"); + let _val = ::std::str::from_utf8(b"a"); } diff --git a/tests/run-pass-fullmir/threads.rs b/tests/run-pass-fullmir/threads.rs index f920bc52edde..dad47d85a246 100644 --- a/tests/run-pass-fullmir/threads.rs +++ b/tests/run-pass-fullmir/threads.rs @@ -5,15 +5,15 @@ use std::sync; fn main() { let m = sync::Mutex::new(0); - let _ = m.lock(); + drop(m.lock()); drop(m); // We don't provide RwLock on Windows #[cfg(not(target_os = "windows"))] { let rw = sync::RwLock::new(0); - let _ = rw.read(); - let _ = rw.write(); + drop(rw.read()); + drop(rw.write()); drop(rw); } } diff --git a/tests/run-pass/closure-drop.rs b/tests/run-pass/closure-drop.rs index f1bdafaeb135..374efb6032bf 100644 --- a/tests/run-pass/closure-drop.rs +++ b/tests/run-pass/closure-drop.rs @@ -17,7 +17,7 @@ fn main() { // this closure never by val uses its captures // so it's basically a fn(&self) // the shim used to not drop the `x` - let x = move || { let _ = x; }; + let x = move || { let _val = x; }; f(x); } assert!(ran_drop); diff --git a/tests/run-pass/drop_empty_slice.rs b/tests/run-pass/drop_empty_slice.rs index b21c8a612c57..8b481a0a2dd8 100644 --- a/tests/run-pass/drop_empty_slice.rs +++ b/tests/run-pass/drop_empty_slice.rs @@ -3,5 +3,5 @@ fn main() { // With the nested Vec, this is calling Offset(Unique::empty(), 0) on drop. let args : Vec> = Vec::new(); - let _ = box args; + let _val = box args; } diff --git a/tests/run-pass/issue-20575.rs b/tests/run-pass/issue-20575.rs index 137d84c256be..01371f5bec68 100644 --- a/tests/run-pass/issue-20575.rs +++ b/tests/run-pass/issue-20575.rs @@ -13,5 +13,5 @@ fn main() { let functions: [Box Option<()>>; 1] = [Box::new(|| None)]; - let _: Option> = functions.iter().map(|f| (*f)()).collect(); + let _val: Option> = functions.iter().map(|f| (*f)()).collect(); } diff --git a/tests/run-pass/issue-26709.rs b/tests/run-pass/issue-26709.rs index 62626d75865c..e29e5fbcc408 100644 --- a/tests/run-pass/issue-26709.rs +++ b/tests/run-pass/issue-26709.rs @@ -20,7 +20,7 @@ fn main() { let mut x = 0; { let wrapper = Box::new(Wrapper(&mut x, 123)); - let _: Box> = wrapper; + let _val: Box> = wrapper; } assert_eq!(432, x) } diff --git a/tests/run-pass/issue-33387.rs b/tests/run-pass/issue-33387.rs index edbf2b81ce94..62a4263c1069 100644 --- a/tests/run-pass/issue-33387.rs +++ b/tests/run-pass/issue-33387.rs @@ -15,5 +15,5 @@ trait Foo {} impl Foo for [u8; 2] {} fn main() { - let _: Arc = Arc::new([3, 4]); + let _val: Arc = Arc::new([3, 4]); } diff --git a/tests/run-pass/issue-miri-184.rs b/tests/run-pass/issue-miri-184.rs index 24775fe8a2d9..39c841403ef0 100644 --- a/tests/run-pass/issue-miri-184.rs +++ b/tests/run-pass/issue-miri-184.rs @@ -1,4 +1,4 @@ pub fn main() { let bytes: [u8; 8] = unsafe { ::std::mem::transmute(0u64) }; - let _: &[u8] = &bytes; + let _val: &[u8] = &bytes; } diff --git a/tests/run-pass/sendable-class.rs b/tests/run-pass/sendable-class.rs index 66f0c84e23c1..3280c36e0a72 100644 --- a/tests/run-pass/sendable-class.rs +++ b/tests/run-pass/sendable-class.rs @@ -27,6 +27,6 @@ fn foo(i:isize, j: char) -> Foo { pub fn main() { let (tx, rx) = channel(); - let _ = tx.send(foo(42, 'c')); - let _ = rx; + tx.send(foo(42, 'c')).unwrap(); + let _val = rx; } diff --git a/tests/run-pass/slices.rs b/tests/run-pass/slices.rs index 45a2a74db08d..4506a72e8dd0 100644 --- a/tests/run-pass/slices.rs +++ b/tests/run-pass/slices.rs @@ -4,7 +4,7 @@ fn slice_of_zst() { fn foo(v: &[T]) -> Option<&[T]> { let mut it = v.iter(); for _ in 0..5 { - let _ = it.next(); + it.next(); } Some(it.as_slice()) } @@ -12,7 +12,7 @@ fn slice_of_zst() { fn foo_mut(v: &mut [T]) -> Option<&mut [T]> { let mut it = v.iter_mut(); for _ in 0..5 { - let _ = it.next(); + it.next(); } Some(it.into_slice()) } From 14d58ca8a90677e76908bcaa0df22e1ccbd5909f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Nov 2018 15:44:28 +0100 Subject: [PATCH 0411/5092] fix clippy lint whitelisting --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 10a1405b2a62..78481979479a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ #![feature(rustc_private)] -#![cfg_attr(feature = "cargo-clippy", allow(cast_lossless))] +#![allow(clippy::cast_lossless)] #[macro_use] extern crate log; From 6bd76c7ee1d81f97a797022c0f3cee01769d7178 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Nov 2018 16:08:24 +0100 Subject: [PATCH 0412/5092] cargo miri: factor package manifest logic into separate function --- Cargo.toml | 1 + src/bin/cargo-miri.rs | 125 +++++++++++++++++++++++++----------------- 2 files changed, 75 insertions(+), 51 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 94d13a83fafd..840805380522 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ log = "0.4" vergen = "3" [features] +default = ["cargo_miri"] cargo_miri = ["cargo_metadata"] rustc_tests = [] diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index da4a351368d3..19296238e2b2 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -1,3 +1,5 @@ +#![feature(inner_deref)] + extern crate cargo_metadata; use std::path::{PathBuf, Path}; @@ -25,6 +27,13 @@ it to configure the resource limits available resource limits are `memory_size`, `step_limit`, `stack_limit` "#; +#[derive(Copy, Clone, Debug)] +enum MiriCommand { + Run, + Test, + Setup, +} + fn show_help() { println!("{}", CARGO_MIRI_HELP); } @@ -34,6 +43,54 @@ fn show_version() { env!("CARGO_PKG_VERSION"), env!("VERGEN_SHA_SHORT"), env!("VERGEN_COMMIT_DATE")); } +fn list_targets(mut args: impl Iterator) -> impl Iterator { + // We need to get the manifest, and then the metadata, to enumerate targets. + let manifest_path_arg = args.find(|val| { + val.starts_with("--manifest-path=") + }); + + let mut metadata = if let Ok(metadata) = cargo_metadata::metadata( + manifest_path_arg.as_ref().map(AsRef::as_ref), + ) + { + metadata + } else { + let _ = std::io::stderr().write_fmt(format_args!( + "error: Could not obtain cargo metadata." + )); + std::process::exit(101); + }; + + let manifest_path = manifest_path_arg.map(|arg| { + PathBuf::from(Path::new(&arg["--manifest-path=".len()..])) + }); + + let current_dir = std::env::current_dir(); + + let package_index = metadata + .packages + .iter() + .position(|package| { + let package_manifest_path = Path::new(&package.manifest_path); + if let Some(ref manifest_path) = manifest_path { + package_manifest_path == manifest_path + } else { + let current_dir = current_dir.as_ref().expect( + "could not read current directory", + ); + let package_manifest_directory = package_manifest_path.parent().expect( + "could not find parent directory of package manifest", + ); + package_manifest_directory == current_dir + } + }) + .expect("could not find matching package"); + let package = metadata.packages.remove(package_index); + + // Finally we got the list of targets to build + package.targets.into_iter() +} + fn main() { // Check for version and help flags even when invoked as 'cargo-miri' if std::env::args().any(|a| a == "--help" || a == "-h") { @@ -51,61 +108,27 @@ fn main() { // binary so that we come back in the other branch, and dispatch // the invocations to rustc and miri, respectively. - let test = std::env::args().nth(2).map_or(false, |text| text == "test"); - let skip = if test { 3 } else { 2 }; - - // We need to get the manifest, and then the metadata, to enumerate targets. - let manifest_path_arg = std::env::args().skip(skip).find(|val| { - val.starts_with("--manifest-path=") - }); - - let mut metadata = if let Ok(metadata) = cargo_metadata::metadata( - manifest_path_arg.as_ref().map(AsRef::as_ref), - ) - { - metadata - } else { - let _ = std::io::stderr().write_fmt(format_args!( - "error: Could not obtain cargo metadata." - )); - std::process::exit(101); + let (subcommand, skip) = match std::env::args().nth(2).deref() { + Some("test") => (MiriCommand::Test, 3), + Some("run") => (MiriCommand::Run, 3), + Some("setup") => (MiriCommand::Setup, 3), + // Default command, if there is an option or nothing + Some(s) if s.starts_with("-") => (MiriCommand::Run, 2), + None => (MiriCommand::Run, 2), + // Unvalid command + Some(s) => { + eprintln!("Unknown command `{}`", s); + std::process::exit(1) + } }; - let manifest_path = manifest_path_arg.map(|arg| { - PathBuf::from(Path::new(&arg["--manifest-path=".len()..])) - }); - - let current_dir = std::env::current_dir(); - - let package_index = metadata - .packages - .iter() - .position(|package| { - let package_manifest_path = Path::new(&package.manifest_path); - if let Some(ref manifest_path) = manifest_path { - package_manifest_path == manifest_path - } else { - let current_dir = current_dir.as_ref().expect( - "could not read current directory", - ); - let package_manifest_directory = package_manifest_path.parent().expect( - "could not find parent directory of package manifest", - ); - package_manifest_directory == current_dir - } - }) - .expect("could not find matching package"); - let package = metadata.packages.remove(package_index); - - // Finally we got the metadata, iterate all targets and see for which ones - // we do anything. - for target in package.targets { + for target in list_targets(std::env::args().skip(skip)) { let args = std::env::args().skip(skip); let kind = target.kind.get(0).expect( "badly formatted cargo metadata: target::kind is an empty array", ); - match (test, &kind[..]) { - (true, "test") => { + match (subcommand, &kind[..]) { + (MiriCommand::Test, "test") => { // For test binaries we call `cargo rustc --test target -- ` if let Err(code) = process( vec!["--test".to_string(), target.name].into_iter().chain( @@ -116,7 +139,7 @@ fn main() { std::process::exit(code); } } - (true, "lib") => { + (MiriCommand::Test, "lib") => { // For libraries we call `cargo rustc -- --test ` // Notice now that `--test` is a rustc arg rather than a cargo arg. This tells // rustc to build a test harness which calls all #[test] functions. We don't @@ -131,7 +154,7 @@ fn main() { std::process::exit(code); } } - (false, "bin") => { + (MiriCommand::Run, "bin") => { // For ordinary binaries we call `cargo rustc --bin target -- ` if let Err(code) = process( vec!["--bin".to_string(), target.name].into_iter().chain( From c945e30d100a79a2d2c73358d54d7545d03093ac Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Nov 2018 16:30:11 +0100 Subject: [PATCH 0413/5092] setup routine to install xargo when missing --- src/bin/cargo-miri.rs | 58 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 19296238e2b2..e39011db5ca7 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -3,14 +3,19 @@ extern crate cargo_metadata; use std::path::{PathBuf, Path}; -use std::io::Write; +use std::io::{self, Write}; use std::process::Command; const CARGO_MIRI_HELP: &str = r#"Interprets bin crates Usage: - cargo miri [options] [--] [...] + cargo miri [subcommand] [options] [--] [...] + +Subcommands: + run Run binaries (default) + test Run tests + setup Only perform automatic setup, but without asking questions (for getting a proper libstd) Common options: -h, --help Print this message @@ -27,7 +32,7 @@ it to configure the resource limits available resource limits are `memory_size`, `step_limit`, `stack_limit` "#; -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] enum MiriCommand { Run, Test, @@ -43,6 +48,11 @@ fn show_version() { env!("CARGO_PKG_VERSION"), env!("VERGEN_SHA_SHORT"), env!("VERGEN_COMMIT_DATE")); } +fn show_error(msg: String) -> ! { + eprintln!("fatal error: {}", msg); + std::process::exit(1) +} + fn list_targets(mut args: impl Iterator) -> impl Iterator { // We need to get the manifest, and then the metadata, to enumerate targets. let manifest_path_arg = args.find(|val| { @@ -91,6 +101,40 @@ fn list_targets(mut args: impl Iterator) -> impl Iterator true, + "n" | "no" => false, + a => show_error(format!("I do not understand `{}`", a)) + }; + if !answer { + show_error(format!("Aborting as per your request")) + } +} + +/// Perform the setup requires to make `cargo miri` work: Getting a custom-built libstd. Then sets MIRI_SYSROOT. +/// Skipped if MIRI_SYSROOT is already set, in that case we expect the user has done all this already. +fn setup(ask_user: bool) { + if std::env::var("MIRI_SYSROOT").is_ok() { + return; + } + + // First, we need xargo + if Command::new("xargo").arg("--version").output().is_err() + { + if ask_user { + ask("It seems you do not have xargo installed. I will run `cargo install xargo`. Proceed?"); + } + if !Command::new("cargo").args(&["install", "xargo"]).status().unwrap().success() { + show_error(format!("Failed to install xargo")); + } + } +} + fn main() { // Check for version and help flags even when invoked as 'cargo-miri' if std::env::args().any(|a| a == "--help" || a == "-h") { @@ -117,11 +161,15 @@ fn main() { None => (MiriCommand::Run, 2), // Unvalid command Some(s) => { - eprintln!("Unknown command `{}`", s); - std::process::exit(1) + show_error(format!("Unknown command `{}`", s)) } }; + // We always setup + let ask = subcommand != MiriCommand::Setup; + setup(ask); + + // Now run the command. for target in list_targets(std::env::args().skip(skip)) { let args = std::env::args().skip(skip); let kind = target.kind.get(0).expect( From 738133b379b172a37f8699085daff62b5a7d16a5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Nov 2018 17:09:49 +0100 Subject: [PATCH 0414/5092] complete setup routine: instal rust-src, build libstd, use it --- Cargo.toml | 3 ++- src/bin/cargo-miri.rs | 55 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 840805380522..111b47a551a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,7 @@ required-features = ["rustc_tests"] [dependencies] byteorder = { version = "1.1", features = ["i128"]} cargo_metadata = { version = "0.6", optional = true } +dirs = { version = "1.0.4", optional = true } env_logger = "0.5" log = "0.4" @@ -43,7 +44,7 @@ vergen = "3" [features] default = ["cargo_miri"] -cargo_miri = ["cargo_metadata"] +cargo_miri = ["cargo_metadata", "dirs"] rustc_tests = [] [dev-dependencies] diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index e39011db5ca7..1a5553ca1094 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -5,7 +5,7 @@ extern crate cargo_metadata; use std::path::{PathBuf, Path}; use std::io::{self, Write}; use std::process::Command; - +use std::fs::{self, File}; const CARGO_MIRI_HELP: &str = r#"Interprets bin crates @@ -133,6 +133,59 @@ fn setup(ask_user: bool) { show_error(format!("Failed to install xargo")); } } + + // Then, we also need rust-src. Let's see if it is already installed. + let sysroot = Command::new("rustc").args(&["--print", "sysroot"]).output().unwrap().stdout; + let sysroot = std::str::from_utf8(&sysroot[..]).unwrap(); + let src = Path::new(sysroot.trim_end_matches('\n')).join("lib/rustlib/src"); + if !src.exists() { + println!("Could not find {:?}", src); + if ask_user { + ask("It seems you do not have the rust-src component installed. I will run `rustup component add rust-src`. Proceed?"); + } + if !Command::new("rustup").args(&["component", "add", "rust-src"]).status().unwrap().success() { + show_error(format!("Failed to install rust-src component")); + } + } + + // Next, we need our own libstd. We will do this work in ~/.miri. + let dir = dirs::home_dir().unwrap().join(".miri"); + if !dir.exists() { + fs::create_dir(&dir).unwrap(); + } + // The interesting bit: Xargo.toml + File::create(dir.join("Xargo.toml")).unwrap() + .write_all(br#" +[dependencies.std] +features = ["panic_unwind", "backtrace"] + +[dependencies.test] +stage = 1 + "#).unwrap(); + // The boring bits: A dummy project for xargo + File::create(dir.join("Cargo.toml")).unwrap() + .write_all(br#" +[package] +name = "miri-xargo" +description = "A dummy project for building libstd with xargo." +version = "0.0.0" + +[lib] +path = "lib.rs" + "#).unwrap(); + File::create(dir.join("lib.rs")).unwrap(); + // Run xargo + if !Command::new("xargo").arg("build") + .current_dir(&dir) + .env("RUSTFLAGS", miri::miri_default_args().join(" ")) + .env("XARGO_HOME", dir.to_str().unwrap()) + .status().unwrap().success() + { + show_error(format!("Failed to run xargo")); + } + + // That should be it! + std::env::set_var("MIRI_SYSROOT", dir.join("HOST")); } fn main() { From bb47df94ddf8620b10f18b528cb21b1b785f4226 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Nov 2018 17:17:21 +0100 Subject: [PATCH 0415/5092] use cargo miri setup for CI --- .travis.yml | 8 +++----- appveyor.yml | 13 ++----------- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 85dd50cb5e3c..e5a47a40a9be 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,8 +28,6 @@ before_script: - rustup target add i686-unknown-linux-gnu - rustup target add i686-pc-windows-gnu - rustup target add i686-pc-windows-msvc -- rustup component add rust-src -- cargo install xargo || echo "Skipping xargo install" script: - set -e @@ -39,9 +37,9 @@ script: cargo test --release --all-features && cargo install --all-features --force --path . - | - # get ourselves a MIR-full libstd - xargo/build.sh && - export MIRI_SYSROOT=~/.xargo/HOST + # starting here, use MIR-full libstd + cargo miri setup && + export MIRI_SYSROOT=~/.miri/HOST - | # run all tests with full mir cargo test --release --all-features diff --git a/appveyor.yml b/appveyor.yml index 3dc47f1c67b6..5757d1d27967 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -21,16 +21,6 @@ install: - rustup-init.exe -y --default-host %TARGET% --default-toolchain %RUST_TOOLCHAIN% - set PATH=%USERPROFILE%\.cargo\bin;%PATH% - rustc --version - # Customize installation. - - rustup component add rust-src - - cargo install xargo - # Prepare a libstd with MIR (cannot use bash script, obviously). - # The flags here should be kept in sync with `add_miri_default_args` in `src/lib.rs`. - - cd xargo - - set RUSTFLAGS=-Zalways-encode-mir -Zmir-emit-retag -Zmir-opt-level=0 - - xargo build - - set RUSTFLAGS= - - cd .. build: false @@ -39,7 +29,8 @@ test_script: - set RUST_BACKTRACE=1 - cargo build --release --all-features --all-targets - cargo test --release --all-features - - set MIRI_SYSROOT=%USERPROFILE%\.xargo\HOST + - cargo run --release --all-features --bin cargo-miri -- miri setup + - set MIRI_SYSROOT=%USERPROFILE%\.miri\HOST - cargo test --release --all-features notifications: From 16ac7ec1b1a7d07a1806d42e0f350580d537c121 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Nov 2018 17:30:50 +0100 Subject: [PATCH 0416/5092] tweak comments, remove debug output --- .travis.yml | 6 +++--- appveyor.yml | 3 +++ src/bin/cargo-miri.rs | 3 +-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index e5a47a40a9be..9a8b80689000 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ os: - osx before_script: -# macOS weirdness (https://github.com/travis-ci/travis-ci/issues/6307) +# macOS weirdness (https://github.com/travis-ci/travis-ci/issues/6307, https://github.com/travis-ci/travis-ci/issues/10165) - if [[ "$TRAVIS_OS_NAME" == osx ]]; then rvm get stable; fi # Compute the rust version we use. We do not use "language: rust" to have more control here. - | @@ -37,11 +37,11 @@ script: cargo test --release --all-features && cargo install --all-features --force --path . - | - # starting here, use MIR-full libstd + # Get ourselves a MIR-full libstd cargo miri setup && export MIRI_SYSROOT=~/.miri/HOST - | - # run all tests with full mir + # Test miri with full MIR cargo test --release --all-features - | # Test cargo integration diff --git a/appveyor.yml b/appveyor.yml index 5757d1d27967..4287a08613f1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -27,10 +27,13 @@ build: false test_script: - set RUSTFLAGS=-g - set RUST_BACKTRACE=1 + # Test plain miri - cargo build --release --all-features --all-targets - cargo test --release --all-features + # Get ourselves a MIR-full libstd - cargo run --release --all-features --bin cargo-miri -- miri setup - set MIRI_SYSROOT=%USERPROFILE%\.miri\HOST + # Test miri with full MIR - cargo test --release --all-features notifications: diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 1a5553ca1094..20d9e9ba71e4 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -137,9 +137,8 @@ fn setup(ask_user: bool) { // Then, we also need rust-src. Let's see if it is already installed. let sysroot = Command::new("rustc").args(&["--print", "sysroot"]).output().unwrap().stdout; let sysroot = std::str::from_utf8(&sysroot[..]).unwrap(); - let src = Path::new(sysroot.trim_end_matches('\n')).join("lib/rustlib/src"); + let src = Path::new(sysroot.trim_end_matches('\n')).join("lib").join("rustlib").join("src"); if !src.exists() { - println!("Could not find {:?}", src); if ask_user { ask("It seems you do not have the rust-src component installed. I will run `rustup component add rust-src`. Proceed?"); } From cc4dd29f547ae96d6b6eb76441f166d7b3f734b7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Nov 2018 18:27:24 +0100 Subject: [PATCH 0417/5092] kill xargo dir and update docs --- README.md | 76 +++++++++++-------------------------- cargo-miri-test/run-test.py | 4 +- src/bin/cargo-miri.rs | 2 +- xargo/Cargo.lock | 4 -- xargo/Cargo.toml | 6 --- xargo/Xargo.toml | 5 --- xargo/build.sh | 4 -- xargo/src/lib.rs | 0 8 files changed, 25 insertions(+), 76 deletions(-) delete mode 100644 xargo/Cargo.lock delete mode 100644 xargo/Cargo.toml delete mode 100644 xargo/Xargo.toml delete mode 100755 xargo/build.sh delete mode 100644 xargo/src/lib.rs diff --git a/README.md b/README.md index 5e5a7a23c6af..5dced653bb00 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ in this directory. [rustup]: https://www.rustup.rs -## Running Miri +## Running Miri on tiny examples ```sh cargo +nightly run -- -Zmiri-disable-validation tests/run-pass/vecs.rs # Or whatever test you like. @@ -51,74 +51,42 @@ cargo +nightly run -- -Zmiri-disable-validation tests/run-pass/vecs.rs # Or what We have to disable validation because that can lead to errors when libstd is not compiled the right way. -## Running Miri with full libstd - -Per default libstd does not contain the MIR of non-polymorphic functions, and -also does not contain some extra MIR statements that miri needs for validation. -When Miri hits a call to such a function, execution terminates, and even when -the MIR is present, validation can fail. To fix this, it is possible to compile -libstd with full MIR: - -```sh -rustup component add --toolchain nightly rust-src -cargo +nightly install xargo -rustup run nightly xargo/build.sh -``` - -Now you can run Miri against the libstd compiled by xargo: - -```sh -MIRI_SYSROOT=~/.xargo/HOST cargo +nightly run tests/run-pass-fullmir/hashmap.rs -``` - -Notice that you will have to re-run the last step of the preparations above -(`xargo/build.sh`) when your toolchain changes (e.g., when you update the -nightly). - ## Running Miri on your own project('s test suite) -Install Miri as a cargo subcommand with `cargo +nightly install --all-features ---path .`. Be aware that if you used `rustup override set` to fix a particular -Rust version for the miri directory, that will *not* apply to your own project -directory! You have to use a consistent Rust version for building miri and your -project for this to work, so remember to either always specify the nightly -version manually, overriding it in your project directory as well, or use -`rustup default nightly` (or `rustup default nightly-YYYY-MM-DD`) to globally -make `nightly` the default toolchain. +Install Miri as a cargo subcommand with `cargo +nightly install --path .`. Be +aware that if you used `rustup override set` to fix a particular Rust version +for the miri directory, that will *not* apply to your own project directory! +You have to use a consistent Rust version for building miri and your project for +this to work, so remember to either always specify the nightly version manually, +overriding it in your project directory as well, or use `rustup default nightly` +(or `rustup default nightly-YYYY-MM-DD`) to globally make `nightly` the default +toolchain. -We assume that you have prepared a MIR-enabled libstd as described above. Now -compile your project and its dependencies against that libstd: - -1. Run `cargo clean` to eliminate any cached dependencies that were built against -the non-MIR `libstd`. -2. To run all tests in your project through, Miri, use -`MIRI_SYSROOT=~/.xargo/HOST cargo +nightly miri test`. **NOTE**: This is -currently broken, see the discussion in -[#479](https://github.com/solson/miri/issues/479). -3. If you have a binary project, you can run it through Miri using -`MIRI_SYSROOT=~/.xargo/HOST cargo +nightly miri`. +1. Run `cargo clean` to eliminate any cached dependencies. Miri needs your + dependencies to be compiled the right way, that would not happen if they have + previously already been compiled. +2. To run all tests in your project through Miri, use `cargo +nightly miri test`. + **NOTE**: This is currently broken, see the discussion in + [#479](https://github.com/solson/miri/issues/479). +3. If you have a binary project, you can run it through Miri using `cargo + +nightly miri run`. ### Common Problems When using the above instructions, you may encounter a number of confusing compiler errors. -#### "constant evaluation error: no mir for ``" - -You may have forgotten to set `MIRI_SYSROOT` when calling `cargo miri`, and -your program called into `std` or `core`. Be sure to set `MIRI_SYSROOT=~/.xargo/HOST`. - #### "found possibly newer version of crate `std` which `` depends on" -Your build directory may contain artifacts from an earlier build that did/did not -have `MIRI_SYSROOT` set. Run `cargo clean` before switching from non-Miri to Miri -builds and vice-versa. +Your build directory may contain artifacts from an earlier build that have/have +not been built for Miri. Run `cargo clean` before switching from non-Miri to +Miri builds and vice-versa. #### "found crate `std` compiled by an incompatible version of rustc" You may be running `cargo miri` with a different compiler version than the one -used to build the MIR-enabled `std`. Be sure to consistently use the same toolchain, -which should be the toolchain specified in the `rust-version` file. +used to build the custom libstd that Miri uses, and Miri failed to detect that. +Try deleting `~/.miri`. ## Miri `-Z` flags diff --git a/cargo-miri-test/run-test.py b/cargo-miri-test/run-test.py index f686cc47449d..42745535e0ef 100755 --- a/cargo-miri-test/run-test.py +++ b/cargo-miri-test/run-test.py @@ -8,10 +8,10 @@ and the working directory to contain the cargo-miri-test project. import sys, subprocess def test_cargo_miri(): - print("==> Testing `cargo miri` <==") + print("==> Testing `cargo miri run` <==") ## Call `cargo miri`, capture all output p = subprocess.Popen( - ["cargo", "miri", "-q"], + ["cargo", "miri", "run", "-q"], stdout=subprocess.PIPE, stderr=subprocess.PIPE ) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 20d9e9ba71e4..5b6ff084024d 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -174,7 +174,7 @@ path = "lib.rs" "#).unwrap(); File::create(dir.join("lib.rs")).unwrap(); // Run xargo - if !Command::new("xargo").arg("build") + if !Command::new("xargo").arg("build").arg("-q") .current_dir(&dir) .env("RUSTFLAGS", miri::miri_default_args().join(" ")) .env("XARGO_HOME", dir.to_str().unwrap()) diff --git a/xargo/Cargo.lock b/xargo/Cargo.lock deleted file mode 100644 index c85820b708b6..000000000000 --- a/xargo/Cargo.lock +++ /dev/null @@ -1,4 +0,0 @@ -[[package]] -name = "miri-xargo" -version = "0.0.0" - diff --git a/xargo/Cargo.toml b/xargo/Cargo.toml deleted file mode 100644 index 9129c105b112..000000000000 --- a/xargo/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "miri-xargo" -description = "A dummy project for building libstd with xargo." -version = "0.0.0" - -[dependencies] diff --git a/xargo/Xargo.toml b/xargo/Xargo.toml deleted file mode 100644 index e49b0dbe743b..000000000000 --- a/xargo/Xargo.toml +++ /dev/null @@ -1,5 +0,0 @@ -[dependencies.std] -features = ["panic_unwind", "backtrace"] - -[dependencies.test] -stage = 1 diff --git a/xargo/build.sh b/xargo/build.sh deleted file mode 100755 index 25c56d31ab56..000000000000 --- a/xargo/build.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -cd "$(dirname "$0")" -# The flags here should be kept in sync with `add_miri_default_args` in `src/lib.rs`. -RUSTFLAGS='-Zalways-encode-mir -Zmir-emit-retag -Zmir-opt-level=0' xargo build diff --git a/xargo/src/lib.rs b/xargo/src/lib.rs deleted file mode 100644 index e69de29bb2d1..000000000000 From 9dd0048e665710fb29e967b3a96c7fbd9d66ee76 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Nov 2018 22:17:48 +0100 Subject: [PATCH 0418/5092] install directly from git repo --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5dced653bb00..d33b92f6de40 100644 --- a/README.md +++ b/README.md @@ -53,8 +53,13 @@ compiled the right way. ## Running Miri on your own project('s test suite) -Install Miri as a cargo subcommand with `cargo +nightly install --path .`. Be -aware that if you used `rustup override set` to fix a particular Rust version +Install Miri as a cargo subcommand: + +```sh +cargo +nightly install --git https://github.com/solson/miri/ +``` + +Be aware that if you used `rustup override set` to fix a particular Rust version for the miri directory, that will *not* apply to your own project directory! You have to use a consistent Rust version for building miri and your project for this to work, so remember to either always specify the nightly version manually, From b09dfc14a0e9dc4ace798dbcf9d381159808406b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Nov 2018 22:23:54 +0100 Subject: [PATCH 0419/5092] there are less places now to keep the flags in sync --- src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 78481979479a..d2ead2493c04 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -54,8 +54,7 @@ pub use crate::stacked_borrows::{Borrow, Stack, Stacks, BorStackItem}; /// set per default, for maximal validation power. pub fn miri_default_args() -> &'static [&'static str] { // The flags here should be kept in sync with what bootstrap adds when `test-miri` is - // set, which happens in `bootstrap/bin/rustc.rs` in the rustc sources; and also - // kept in sync with `xargo/build.sh` in this repo and `appveyor.yml`. + // set, which happens in `bootstrap/bin/rustc.rs` in the rustc sources. &["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0"] } From 82caed1a483f3e02f9e92987b88a87751bde4552 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Nov 2018 22:29:25 +0100 Subject: [PATCH 0420/5092] cargo miri setup: print when we are executing commands --- src/bin/cargo-miri.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 5b6ff084024d..edc0d35fa8dd 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -128,6 +128,8 @@ fn setup(ask_user: bool) { { if ask_user { ask("It seems you do not have xargo installed. I will run `cargo install xargo`. Proceed?"); + } else { + println!("Installing xargo: `cargo install xargo`"); } if !Command::new("cargo").args(&["install", "xargo"]).status().unwrap().success() { show_error(format!("Failed to install xargo")); @@ -141,6 +143,8 @@ fn setup(ask_user: bool) { if !src.exists() { if ask_user { ask("It seems you do not have the rust-src component installed. I will run `rustup component add rust-src`. Proceed?"); + } else { + println!("Installing rust-src component: `rustup component add rust-src`"); } if !Command::new("rustup").args(&["component", "add", "rust-src"]).status().unwrap().success() { show_error(format!("Failed to install rust-src component")); From 58982d655a3544486e8d827035e6acc4da1f0ccd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 26 Nov 2018 08:37:31 +0100 Subject: [PATCH 0421/5092] remove unneeded backtrace feature --- src/bin/cargo-miri.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index edc0d35fa8dd..28cc9f930840 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -160,7 +160,7 @@ fn setup(ask_user: bool) { File::create(dir.join("Xargo.toml")).unwrap() .write_all(br#" [dependencies.std] -features = ["panic_unwind", "backtrace"] +features = ["panic_unwind"] [dependencies.test] stage = 1 From 07f78a37d4e8d7c55330e90e0a36815bf615a8d9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Nov 2018 08:16:52 +0100 Subject: [PATCH 0422/5092] tweaks --- Cargo.toml | 4 ++-- src/bin/cargo-miri.rs | 16 +++++----------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 111b47a551a8..becb5c69e561 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,7 @@ required-features = ["rustc_tests"] [dependencies] byteorder = { version = "1.1", features = ["i128"]} cargo_metadata = { version = "0.6", optional = true } -dirs = { version = "1.0.4", optional = true } +directories = { version = "1.0", optional = true } env_logger = "0.5" log = "0.4" @@ -44,7 +44,7 @@ vergen = "3" [features] default = ["cargo_miri"] -cargo_miri = ["cargo_metadata", "dirs"] +cargo_miri = ["cargo_metadata", "directories"] rustc_tests = [] [dev-dependencies] diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 28cc9f930840..05d1bf322081 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -65,10 +65,7 @@ fn list_targets(mut args: impl Iterator) -> impl Iterator true, - "n" | "no" => false, + match buf.trim().to_lowercase().as_ref() { + "" | "y" | "yes" => {}, // proceed + "n" | "no" => show_error(format!("Aborting as per your request")), a => show_error(format!("I do not understand `{}`", a)) }; - if !answer { - show_error(format!("Aborting as per your request")) - } } /// Perform the setup requires to make `cargo miri` work: Getting a custom-built libstd. Then sets MIRI_SYSROOT. @@ -152,7 +146,7 @@ fn setup(ask_user: bool) { } // Next, we need our own libstd. We will do this work in ~/.miri. - let dir = dirs::home_dir().unwrap().join(".miri"); + let dir = directories::UserDirs::new().unwrap().home_dir().join(".miri"); if !dir.exists() { fs::create_dir(&dir).unwrap(); } From 464dee8edf786117f9806ed88d7b238cd4b8abf5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Nov 2018 09:23:22 +0100 Subject: [PATCH 0423/5092] std::ptr no longer needs whitelisting --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 10a1405b2a62..47f00658e5cb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -318,7 +318,6 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { // We walk up the stack a few frames to also cover their callees. const WHITELIST: &[(&str, &str)] = &[ // Uses mem::uninitialized - ("std::ptr::read", ""), ("std::sys::windows::mutex::Mutex::", ""), ]; for frame in ecx.stack().iter() From b91679539e7fbbd4ee4bccbdb5de5589c77cc322 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Nov 2018 11:26:53 +0100 Subject: [PATCH 0424/5092] use proper platform cache dir --- src/bin/cargo-miri.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 05d1bf322081..f06bb2d37235 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -145,8 +145,9 @@ fn setup(ask_user: bool) { } } - // Next, we need our own libstd. We will do this work in ~/.miri. - let dir = directories::UserDirs::new().unwrap().home_dir().join(".miri"); + // Next, we need our own libstd. We will do this work in whatever is a good cache dir for this platform. + let dirs = directories::ProjectDirs::from("miri", "miri", "miri").unwrap(); + let dir = dirs.cache_dir(); if !dir.exists() { fs::create_dir(&dir).unwrap(); } From bd7f4076cdac11fb87629cc5aab1ba0fd77a806a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Nov 2018 11:43:02 +0100 Subject: [PATCH 0425/5092] we need to recursively create the dir --- src/bin/cargo-miri.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index f06bb2d37235..fb1b97269aa7 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -149,7 +149,7 @@ fn setup(ask_user: bool) { let dirs = directories::ProjectDirs::from("miri", "miri", "miri").unwrap(); let dir = dirs.cache_dir(); if !dir.exists() { - fs::create_dir(&dir).unwrap(); + fs::create_dir_all(&dir).unwrap(); } // The interesting bit: Xargo.toml File::create(dir.join("Xargo.toml")).unwrap() From 53196554ec5c96f067611b96ffd3e1409274e4d0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Nov 2018 12:08:46 +0100 Subject: [PATCH 0426/5092] inform the user when and where we are creating a cache dir --- src/bin/cargo-miri.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index fb1b97269aa7..ed4ffa43dbce 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -149,6 +149,7 @@ fn setup(ask_user: bool) { let dirs = directories::ProjectDirs::from("miri", "miri", "miri").unwrap(); let dir = dirs.cache_dir(); if !dir.exists() { + println!("Creating `{}` and using it for miri's build of libstd", dir.display()); fs::create_dir_all(&dir).unwrap(); } // The interesting bit: Xargo.toml From fbd7d119aecca4019467b2b191fcb1d88af2ed81 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Nov 2018 11:46:09 +0100 Subject: [PATCH 0427/5092] use new dir for CI and docs --- .travis.yml | 8 ++++++-- README.md | 2 +- appveyor.yml | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9a8b80689000..ba3b8d363991 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,9 +37,13 @@ script: cargo test --release --all-features && cargo install --all-features --force --path . - | - # Get ourselves a MIR-full libstd + # Get ourselves a MIR-full libstd, and use it henceforth cargo miri setup && - export MIRI_SYSROOT=~/.miri/HOST + if [ "$TRAVIS_OS_NAME" == osx ]; then + export MIRI_SYSROOT=~/Library/Caches/miri.miri.miri/HOST + else + export MIRI_SYSROOT=~/.cache/miri/HOST + fi - | # Test miri with full MIR cargo test --release --all-features diff --git a/README.md b/README.md index d33b92f6de40..d6e0be40cacf 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ Miri builds and vice-versa. You may be running `cargo miri` with a different compiler version than the one used to build the custom libstd that Miri uses, and Miri failed to detect that. -Try deleting `~/.miri`. +Try deleting `~/.cache/miri`. ## Miri `-Z` flags diff --git a/appveyor.yml b/appveyor.yml index 4287a08613f1..1f38b848c005 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -30,9 +30,9 @@ test_script: # Test plain miri - cargo build --release --all-features --all-targets - cargo test --release --all-features - # Get ourselves a MIR-full libstd + # Get ourselves a MIR-full libstd, and use it henceforth - cargo run --release --all-features --bin cargo-miri -- miri setup - - set MIRI_SYSROOT=%USERPROFILE%\.miri\HOST + - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\miri\miri\cache\HOST # Test miri with full MIR - cargo test --release --all-features From e9370d2b74d38720fed7887fc708b8fa67fe7adb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 15 Nov 2018 13:29:55 +0100 Subject: [PATCH 0428/5092] adjust for memory_allocated hook, make RangeMap preallocated with a fixed size --- src/lib.rs | 23 ++++++--- src/range_map.rs | 108 +++++++++++------------------------------ src/stacked_borrows.rs | 16 ++++-- 3 files changed, 56 insertions(+), 91 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d2ead2493c04..591cf5766234 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -301,6 +301,7 @@ type MiriEvalContext<'a, 'mir, 'tcx> = EvalContext<'a, 'mir, 'tcx, Evaluator<'tc impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { type MemoryKinds = MiriMemoryKind; + type MemoryExtra = (); type AllocExtra = stacked_borrows::Stacks; type PointerTag = Borrow; @@ -405,8 +406,9 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { } fn find_foreign_static( - tcx: TyCtxtAt<'a, 'tcx, 'tcx>, def_id: DefId, + tcx: TyCtxtAt<'a, 'tcx, 'tcx>, + memory_extra: &Self::MemoryExtra, ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> { let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { @@ -417,8 +419,10 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { let alloc = match &link_name[..] { "__cxa_thread_atexit_impl" => { // This should be all-zero, pointer-sized - let data = vec![0; tcx.data_layout.pointer_size.bytes() as usize]; - Allocation::from_bytes(&data[..], tcx.data_layout.pointer_align.abi) + let size = tcx.data_layout.pointer_size; + let data = vec![0; size.bytes() as usize]; + let extra = AllocationExtra::memory_allocated(size, memory_extra); + Allocation::from_bytes(&data[..], tcx.data_layout.pointer_align.abi, extra) } _ => return err!(Unimplemented( format!("can't access foreign static: {}", link_name), @@ -434,9 +438,14 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { Ok(()) } - fn adjust_static_allocation( - alloc: &'_ Allocation - ) -> Cow<'_, Allocation> { + fn adjust_static_allocation<'b>( + alloc: &'b Allocation, + memory_extra: &Self::MemoryExtra, + ) -> Cow<'b, Allocation> { + let extra = AllocationExtra::memory_allocated( + Size::from_bytes(alloc.bytes.len() as u64), + memory_extra, + ); let alloc: Allocation = Allocation { bytes: alloc.bytes.clone(), relocations: Relocations::from_presorted( @@ -447,7 +456,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { undef_mask: alloc.undef_mask.clone(), align: alloc.align, mutability: alloc.mutability, - extra: Self::AllocExtra::default(), + extra, }; Cow::Owned(alloc) } diff --git a/src/range_map.rs b/src/range_map.rs index 74a49bf83b81..762b17b1ae33 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -16,13 +16,6 @@ pub struct RangeMap { map: BTreeMap, } -impl Default for RangeMap { - #[inline(always)] - fn default() -> Self { - RangeMap::new() - } -} - // The derived `Ord` impl sorts first by the first field, then, if the fields are the same, // by the second field. // This is exactly what we need for our purposes, since a range query on a BTReeSet/BTreeMap will give us all @@ -73,9 +66,15 @@ impl Range { } impl RangeMap { + /// Create a new RangeMap for the given size, and with the given initial value used for + /// the entire range. #[inline(always)] - pub fn new() -> RangeMap { - RangeMap { map: BTreeMap::new() } + pub fn new(size: Size, init: T) -> RangeMap { + let mut map = RangeMap { map: BTreeMap::new() }; + if size.bytes() > 0 { + map.map.insert(Range { start: 0, end: size.bytes() }, init); + } + map } fn iter_with_range<'a>( @@ -95,6 +94,9 @@ impl RangeMap { ) } + /// Provide read-only iteration over everything in the given range. This does + /// *not* split items if they overlap with the edges. Do not use this to mutate + /// through interior mutability. pub fn iter<'a>(&'a self, offset: Size, len: Size) -> impl Iterator + 'a { self.iter_with_range(offset.bytes(), len.bytes()).map(|(_, data)| data) } @@ -140,8 +142,7 @@ impl RangeMap { /// Provide mutable iteration over everything in the given range. As a side-effect, /// this will split entries in the map that are only partially hit by the given range, /// to make sure that when they are mutated, the effect is constrained to the given range. - /// If there are gaps, leave them be. - pub fn iter_mut_with_gaps<'a>( + pub fn iter_mut<'a>( &'a mut self, offset: Size, len: Size, @@ -174,64 +175,6 @@ impl RangeMap { }, ) } - - /// Provide a mutable iterator over everything in the given range, with the same side-effects as - /// iter_mut_with_gaps. Furthermore, if there are gaps between ranges, fill them with the given default - /// before yielding them in the iterator. - /// This is also how you insert. - pub fn iter_mut<'a>(&'a mut self, offset: Size, len: Size) -> impl Iterator + 'a - where - T: Clone + Default, - { - if len.bytes() > 0 { - let offset = offset.bytes(); - let len = len.bytes(); - - // Do a first iteration to collect the gaps - let mut gaps = Vec::new(); - let mut last_end = offset; - for (range, _) in self.iter_with_range(offset, len) { - if last_end < range.start { - gaps.push(Range { - start: last_end, - end: range.start, - }); - } - last_end = range.end; - } - if last_end < offset + len { - gaps.push(Range { - start: last_end, - end: offset + len, - }); - } - - // Add default for all gaps - for gap in gaps { - let old = self.map.insert(gap, Default::default()); - assert!(old.is_none()); - } - } - - // Now provide mutable iteration - self.iter_mut_with_gaps(offset, len) - } - - pub fn retain(&mut self, mut f: F) - where - F: FnMut(&T) -> bool, - { - let mut remove = Vec::new(); - for (range, data) in &self.map { - if !f(data) { - remove.push(*range); - } - } - - for range in remove { - self.map.remove(&range); - } - } } #[cfg(test)] @@ -239,14 +182,13 @@ mod tests { use super::*; /// Query the map at every offset in the range and collect the results. - fn to_vec(map: &RangeMap, offset: u64, len: u64, default: Option) -> Vec { + fn to_vec(map: &RangeMap, offset: u64, len: u64) -> Vec { (offset..offset + len) .into_iter() .map(|i| map .iter(Size::from_bytes(i), Size::from_bytes(1)) .next() .map(|&t| t) - .or(default) .unwrap() ) .collect() @@ -254,13 +196,13 @@ mod tests { #[test] fn basic_insert() { - let mut map = RangeMap::::new(); + let mut map = RangeMap::::new(Size::from_bytes(20), -1); // Insert for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(1)) { *x = 42; } // Check - assert_eq!(to_vec(&map, 10, 1, None), vec![42]); + assert_eq!(to_vec(&map, 10, 1), vec![42]); // Insert with size 0 for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(0)) { @@ -269,12 +211,12 @@ mod tests { for x in map.iter_mut(Size::from_bytes(11), Size::from_bytes(0)) { *x = 19; } - assert_eq!(to_vec(&map, 10, 2, Some(-1)), vec![42, -1]); + assert_eq!(to_vec(&map, 10, 2), vec![42, -1]); } #[test] fn gaps() { - let mut map = RangeMap::::new(); + let mut map = RangeMap::::new(Size::from_bytes(20), -1); for x in map.iter_mut(Size::from_bytes(11), Size::from_bytes(1)) { *x = 42; } @@ -282,11 +224,10 @@ mod tests { *x = 43; } assert_eq!( - to_vec(&map, 10, 10, Some(-1)), + to_vec(&map, 10, 10), vec![-1, 42, -1, -1, -1, 43, -1, -1, -1, -1] ); - // Now request a range that needs three gaps filled for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(10)) { if *x < 42 { *x = 23; @@ -294,9 +235,18 @@ mod tests { } assert_eq!( - to_vec(&map, 10, 10, None), + to_vec(&map, 10, 10), vec![23, 42, 23, 23, 23, 43, 23, 23, 23, 23] ); - assert_eq!(to_vec(&map, 13, 5, None), vec![23, 23, 43, 23, 23]); + assert_eq!(to_vec(&map, 13, 5), vec![23, 23, 43, 23, 23]); + + // Now request a range that goes beyond the initial size + for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(10)) { + *x = 19; + } + assert_eq!(map.iter(Size::from_bytes(19), Size::from_bytes(1)) + .map(|&t| t).collect::>(), vec![19]); + assert_eq!(map.iter(Size::from_bytes(20), Size::from_bytes(1)) + .map(|&t| t).collect::>(), vec![]); } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index f292d083637a..22ec6ffe6f50 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -126,7 +126,7 @@ impl State { } /// Extra per-allocation state -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct Stacks { // Even reading memory can have effects on the stack, so we need a `RefCell` here. stacks: RefCell>, @@ -289,9 +289,8 @@ impl<'tcx> Stacks { ) -> EvalResult<'tcx> { trace!("deref for tag {:?} as {:?}: {:?}, size {}", ptr.tag, kind, ptr, size.bytes()); - let mut stacks = self.stacks.borrow_mut(); - // We need `iter_mut` because `iter` would skip gaps! - for stack in stacks.iter_mut(ptr.offset, size) { + let stacks = self.stacks.borrow(); + for stack in stacks.iter(ptr.offset, size) { stack.deref(ptr.tag, kind).map_err(EvalErrorKind::MachineError)?; } Ok(()) @@ -359,7 +358,14 @@ impl<'tcx> Stacks { } /// Hooks and glue -impl AllocationExtra for Stacks { +impl AllocationExtra for Stacks { + #[inline(always)] + fn memory_allocated<'tcx>(size: Size, _extra: &()) -> Self { + Stacks { + stacks: RefCell::new(RangeMap::new(size, Stack::default())) + } + } + #[inline(always)] fn memory_read<'tcx>( alloc: &Allocation, From 215ec38624818c4df9889c702fecb10c33b646ee Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 15 Nov 2018 18:15:05 +0100 Subject: [PATCH 0429/5092] track call IDs --- src/lib.rs | 20 ++++++++++++-- src/stacked_borrows.rs | 61 ++++++++++++++++++++++++++++++++---------- 2 files changed, 65 insertions(+), 16 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 591cf5766234..3211f9c5bd95 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -289,7 +289,7 @@ impl<'tcx> Evaluator<'tcx> { env_vars: HashMap::default(), tls: TlsData::default(), validate, - stacked_borrows: stacked_borrows::State::new(), + stacked_borrows: stacked_borrows::State::default(), } } } @@ -301,7 +301,8 @@ type MiriEvalContext<'a, 'mir, 'tcx> = EvalContext<'a, 'mir, 'tcx, Evaluator<'tc impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { type MemoryKinds = MiriMemoryKind; - type MemoryExtra = (); + type FrameExtra = stacked_borrows::CallId; + type MemoryExtra = stacked_borrows::MemoryState; type AllocExtra = stacked_borrows::Stacks; type PointerTag = Borrow; @@ -538,4 +539,19 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { ecx.retag(fn_entry, place) } } + + #[inline(always)] + fn stack_push( + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ) -> EvalResult<'tcx, stacked_borrows::CallId> { + Ok(ecx.memory().extra.borrow_mut().new_call()) + } + + #[inline(always)] + fn stack_pop( + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + extra: stacked_borrows::CallId, + ) -> EvalResult<'tcx> { + Ok(ecx.memory().extra.borrow_mut().end_call(extra)) + } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 22ec6ffe6f50..067e3bb8445f 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -1,4 +1,6 @@ use std::cell::RefCell; +use std::collections::HashSet; +use std::rc::Rc; use rustc::ty::{self, layout::Size}; use rustc::hir::{Mutability, MutMutable, MutImmutable}; @@ -10,6 +12,7 @@ use crate::{ }; pub type Timestamp = u64; +pub type CallId = u64; /// Information about which kind of borrow was used to create the reference this is tagged /// with. @@ -80,15 +83,6 @@ pub struct Stack { frozen_since: Option, // virtual frozen "item" on top of the stack } -impl Default for Stack { - fn default() -> Self { - Stack { - borrows: vec![BorStackItem::Shr], - frozen_since: None, - } - } -} - impl Stack { #[inline(always)] pub fn is_frozen(&self) -> bool { @@ -107,17 +101,50 @@ pub enum RefKind { Raw, } +/// Extra global state in the memory, available to the memory access hooks +#[derive(Debug)] +pub struct BarrierTracking { + next_id: CallId, + active_calls: HashSet, +} +pub type MemoryState = Rc>; + +impl Default for BarrierTracking { + fn default() -> Self { + BarrierTracking { + next_id: 0, + active_calls: HashSet::default(), + } + } +} + +impl BarrierTracking { + pub fn new_call(&mut self) -> CallId { + let id = self.next_id; + trace!("new_call: Assigning ID {}", id); + self.active_calls.insert(id); + self.next_id += 1; + id + } + + pub fn end_call(&mut self, id: CallId) { + assert!(self.active_calls.remove(&id)); + } +} + /// Extra global machine state #[derive(Clone, Debug)] pub struct State { clock: Timestamp } -impl State { - pub fn new() -> State { +impl Default for State { + fn default() -> Self { State { clock: 0 } } +} +impl State { fn increment_clock(&mut self) -> Timestamp { let val = self.clock; self.clock = val + 1; @@ -130,6 +157,7 @@ impl State { pub struct Stacks { // Even reading memory can have effects on the stack, so we need a `RefCell` here. stacks: RefCell>, + barrier_tracking: MemoryState, } /// Core per-location operations: deref, access, create. @@ -358,11 +386,16 @@ impl<'tcx> Stacks { } /// Hooks and glue -impl AllocationExtra for Stacks { +impl AllocationExtra for Stacks { #[inline(always)] - fn memory_allocated<'tcx>(size: Size, _extra: &()) -> Self { + fn memory_allocated<'tcx>(size: Size, extra: &MemoryState) -> Self { + let stack = Stack { + borrows: vec![BorStackItem::Shr], + frozen_since: None, + }; Stacks { - stacks: RefCell::new(RangeMap::new(size, Stack::default())) + stacks: RefCell::new(RangeMap::new(size, stack)), + barrier_tracking: Rc::clone(extra), } } From dd94930ee3d928c4029b4d118befdd620eaf0919 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 15 Nov 2018 19:49:00 +0100 Subject: [PATCH 0430/5092] implement function barriers --- src/stacked_borrows.rs | 142 +++++++++++------- .../stacked_borrows/aliasing_mut1.rs | 19 ++- .../stacked_borrows/aliasing_mut2.rs | 19 ++- .../stacked_borrows/aliasing_mut3.rs | 19 ++- .../stacked_borrows/aliasing_mut4.rs | 22 +-- .../box_exclusive_violation1.rs | 4 +- .../stacked_borrows/illegal_write1.rs | 15 +- .../invalidate_against_barrier1.rs | 13 ++ .../invalidate_against_barrier2.rs | 13 ++ .../mut_exclusive_violation1.rs | 2 +- 10 files changed, 174 insertions(+), 94 deletions(-) create mode 100644 tests/compile-fail-fullmir/stacked_borrows/invalidate_against_barrier1.rs create mode 100644 tests/compile-fail-fullmir/stacked_borrows/invalidate_against_barrier2.rs diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 067e3bb8445f..6b851cd65b5e 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -62,18 +62,7 @@ pub enum BorStackItem { /// when there is no `UnsafeCell`. Shr, /// A barrier, tracking the function it belongs to by its index on the call stack - #[allow(dead_code)] // for future use - FnBarrier(usize) -} - -impl BorStackItem { - #[inline(always)] - pub fn is_fn_barrier(self) -> bool { - match self { - BorStackItem::FnBarrier(_) => true, - _ => false, - } - } + FnBarrier(CallId) } /// Extra per-location state @@ -130,6 +119,10 @@ impl BarrierTracking { pub fn end_call(&mut self, id: CallId) { assert!(self.active_calls.remove(&id)); } + + fn is_active(&self, id: CallId) -> bool { + self.active_calls.contains(&id) + } } /// Extra global machine state @@ -178,7 +171,11 @@ impl<'tcx> Stack { /// going to read or write. /// Returns the index of the item we matched, `None` if it was the frozen one. /// `kind` indicates which kind of reference is being dereferenced. - fn deref(&self, bor: Borrow, kind: RefKind) -> Result, String> { + fn deref( + &self, + bor: Borrow, + kind: RefKind, + ) -> Result, String> { // Exclude unique ref with frozen tag. if let (RefKind::Unique, Borrow::Shr(Some(_))) = (kind, bor) { return Err(format!("Encountered mutable reference with frozen tag ({:?})", bor)); @@ -200,7 +197,6 @@ impl<'tcx> Stack { // If we got here, we have to look for our item in the stack. for (idx, &itm) in self.borrows.iter().enumerate().rev() { match (itm, bor) { - (BorStackItem::FnBarrier(_), _) => break, (BorStackItem::Uniq(itm_t), Borrow::Uniq(bor_t)) if itm_t == bor_t => { // Found matching unique item. This satisfies U3. return Ok(Some(idx)) @@ -209,21 +205,25 @@ impl<'tcx> Stack { // Found matching shared/raw item. return Ok(Some(idx)) } - // Go on looking. + // Go on looking. We ignore barriers! When an `&mut` and an `&` alias, + // dereferencing the `&` is still possible (to reborrow), but doing + // an access is not. _ => {} } } // If we got here, we did not find our item. We have to error to satisfy U3. - Err(format!( - "Borrow being dereferenced ({:?}) does not exist on the stack, or is guarded by a barrier", - bor - )) + Err(format!("Borrow being dereferenced ({:?}) does not exist on the stack", bor)) } /// Perform an actual memory access using `bor`. We do not know any types here /// or whether things should be frozen, but we *do* know if this is reading /// or writing. - fn access(&mut self, bor: Borrow, is_write: bool) -> EvalResult<'tcx> { + fn access( + &mut self, + bor: Borrow, + is_write: bool, + barrier_tracking: &BarrierTracking, + ) -> EvalResult<'tcx> { // Check if we can match the frozen "item". // Not possible on writes! if self.is_frozen() { @@ -240,7 +240,12 @@ impl<'tcx> Stack { // Pop the stack until we have something matching. while let Some(&itm) = self.borrows.last() { match (itm, bor) { - (BorStackItem::FnBarrier(_), _) => break, + (BorStackItem::FnBarrier(call), _) if barrier_tracking.is_active(call) => { + return err!(MachineError(format!( + "Stopping looking for borrow being accessed ({:?}) because of barrier ({})", + bor, call + ))) + } (BorStackItem::Uniq(itm_t), Borrow::Uniq(bor_t)) if itm_t == bor_t => { // Found matching unique item. return Ok(()) @@ -265,7 +270,7 @@ impl<'tcx> Stack { } // If we got here, we did not find our item. err!(MachineError(format!( - "Borrow being accessed ({:?}) does not exist on the stack, or is guarded by a barrier", + "Borrow being accessed ({:?}) does not exist on the stack", bor ))) } @@ -275,18 +280,21 @@ impl<'tcx> Stack { /// is met: We cannot push `Uniq` onto frozen stacks. /// `kind` indicates which kind of reference is being created. fn create(&mut self, bor: Borrow, kind: RefKind) { - // First, push the item. We do this even if we will later freeze, because we - // will allow mutation of shared data at the expense of unfreezing. if self.frozen_since.is_some() { - // A frozen location, this should be impossible! - bug!("We should never try pushing to a frozen stack"); + // A frozen location? Possible if we create a barrier, then push again. + assert!(bor.is_shared(), "We should never try creating a unique borrow for a frozen stack"); + trace!("create: Not doing anything on frozen location"); + return; } - // First, push. + // First, push. We do this even if we will later freeze, because we + // will allow mutation of shared data at the expense of unfreezing. let itm = match bor { Borrow::Uniq(t) => BorStackItem::Uniq(t), Borrow::Shr(_) => BorStackItem::Shr, }; if *self.borrows.last().unwrap() == itm { + // This is just an optimization, no functional change: Avoid stacking + // multiple `Shr` on top of each other. assert!(bor.is_shared()); trace!("create: Sharing a shared location is a NOP"); } else { @@ -304,6 +312,21 @@ impl<'tcx> Stack { self.frozen_since = Some(bor_t); } } + + /// Add a barrier + fn barrier(&mut self, call: CallId) { + let itm = BorStackItem::FnBarrier(call); + if *self.borrows.last().unwrap() == itm { + // This is just an optimization, no functional change: Avoid stacking + // multiple identical barriers on top of each other. + // This can happen when a function receives several shared references + // that overlap. + trace!("barrier: Avoiding redundant extra barrier"); + } else { + trace!("barrier: Pushing barrier for call {}", call); + self.borrows.push(itm); + } + } } /// Higher-level per-location operations: deref, access, reborrow. @@ -330,6 +353,7 @@ impl<'tcx> Stacks { ptr: Pointer, size: Size, is_write: bool, + barrier_tracking: &BarrierTracking, ) -> EvalResult<'tcx> { trace!("{} access of tag {:?}: {:?}, size {}", if is_write { "read" } else { "write" }, @@ -339,7 +363,7 @@ impl<'tcx> Stacks { // are no accesses through other references, not even reads. let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { - stack.access(ptr.tag, is_write)?; + stack.access(ptr.tag, is_write, barrier_tracking)?; } Ok(()) } @@ -350,12 +374,19 @@ impl<'tcx> Stacks { &self, ptr: Pointer, size: Size, + mut barrier: Option, new_bor: Borrow, new_kind: RefKind, + barrier_tracking: &BarrierTracking, ) -> EvalResult<'tcx> { assert_eq!(new_bor.is_unique(), new_kind == RefKind::Unique); trace!("reborrow for tag {:?} to {:?} as {:?}: {:?}, size {}", ptr.tag, new_bor, new_kind, ptr, size.bytes()); + if new_kind == RefKind::Raw { + // No barrier for raw, including `&UnsafeCell`. They can rightfully + // alias with `&mut`. + barrier = None; + } let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { // Access source `ptr`, create new ref. @@ -364,21 +395,25 @@ impl<'tcx> Stacks { // the stack than the one we come from, just use that. // IOW, we check if `new_bor` *already* is "derived from" `ptr.tag`. // This also checks frozenness, if required. - let bor_redundant = match (ptr_idx, stack.deref(new_bor, new_kind)) { - // If the new borrow works with the frozen item, or else if it lives - // above the old one in the stack, our job here is done. - (_, Ok(None)) => true, - (Some(ptr_idx), Ok(Some(new_idx))) if new_idx >= ptr_idx => true, - // Otherwise we need to create a new borrow. - _ => false, - }; + let bor_redundant = barrier.is_none() && + match (ptr_idx, stack.deref(new_bor, new_kind)) { + // If the new borrow works with the frozen item, or else if it lives + // above the old one in the stack, our job here is done. + (_, Ok(None)) => true, + (Some(ptr_idx), Ok(Some(new_idx))) if new_idx >= ptr_idx => true, + // Otherwise we need to create a new borrow. + _ => false, + }; if bor_redundant { assert!(new_bor.is_shared(), "A unique reborrow can never be redundant"); trace!("reborrow is redundant"); continue; } // We need to do some actual work. - stack.access(ptr.tag, new_kind == RefKind::Unique)?; + stack.access(ptr.tag, new_kind == RefKind::Unique, barrier_tracking)?; + if let Some(call) = barrier { + stack.barrier(call); + } stack.create(new_bor, new_kind); } Ok(()) @@ -405,7 +440,7 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - alloc.extra.access(ptr, size, /*is_write*/false) + alloc.extra.access(ptr, size, /*is_write*/false, &*alloc.extra.barrier_tracking.borrow()) } #[inline(always)] @@ -414,7 +449,7 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - alloc.extra.access(ptr, size, /*is_write*/true) + alloc.extra.access(ptr, size, /*is_write*/true, &*alloc.extra.barrier_tracking.borrow()) } #[inline(always)] @@ -424,19 +459,18 @@ impl AllocationExtra for Stacks { size: Size, ) -> EvalResult<'tcx> { // This is like mutating - alloc.extra.access(ptr, size, /*is_write*/true) + alloc.extra.access(ptr, size, /*is_write*/true, &*alloc.extra.barrier_tracking.borrow()) // FIXME: Error out of there are any barriers? } } impl<'tcx> Stacks { /// Pushes the first item to the stacks. - pub fn first_item( + pub(crate) fn first_item( &mut self, itm: BorStackItem, size: Size ) { - assert!(!itm.is_fn_barrier()); for stack in self.stacks.get_mut().iter_mut(Size::ZERO, size) { assert!(stack.borrows.len() == 1); assert_eq!(stack.borrows.pop().unwrap(), BorStackItem::Shr); @@ -466,6 +500,7 @@ pub trait EvalContextExt<'tcx> { &mut self, place: MPlaceTy<'tcx, Borrow>, size: Size, + fn_barrier: bool, new_bor: Borrow ) -> EvalResult<'tcx, Pointer>; @@ -474,6 +509,7 @@ pub trait EvalContextExt<'tcx> { &mut self, ptr: ImmTy<'tcx, Borrow>, mutbl: Mutability, + fn_barrier: bool, ) -> EvalResult<'tcx, Immediate>; fn retag( @@ -566,7 +602,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { place: MPlaceTy<'tcx, Borrow>, size: Size, ) -> EvalResult<'tcx> { - self.reborrow(place, size, Borrow::default())?; + self.reborrow(place, size, /*fn_barrier*/ false, Borrow::default())?; Ok(()) } @@ -574,10 +610,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { &mut self, place: MPlaceTy<'tcx, Borrow>, size: Size, + fn_barrier: bool, new_bor: Borrow ) -> EvalResult<'tcx, Pointer> { let ptr = place.ptr.to_ptr()?; let new_ptr = Pointer::new_with_tag(ptr.alloc_id, ptr.offset, new_bor); + let barrier = if fn_barrier { Some(self.frame().extra) } else { None }; trace!("reborrow: Creating new reference for {:?} (pointee {}): {:?}", ptr, place.layout.ty, new_bor); @@ -589,12 +627,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { // Reference that cares about freezing. We need a frozen-sensitive reborrow. self.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; - alloc.extra.reborrow(cur_ptr, size, new_bor, kind) + alloc.extra.reborrow(cur_ptr, size, barrier, new_bor, kind, &*self.memory().extra.borrow()) })?; } else { // Just treat this as one big chunk. let kind = if new_bor.is_unique() { RefKind::Unique } else { RefKind::Raw }; - alloc.extra.reborrow(ptr, size, new_bor, kind)?; + alloc.extra.reborrow(ptr, size, barrier, new_bor, kind, &*self.memory().extra.borrow())?; } Ok(new_ptr) } @@ -603,6 +641,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { &mut self, val: ImmTy<'tcx, Borrow>, mutbl: Mutability, + fn_barrier: bool, ) -> EvalResult<'tcx, Immediate> { // We want a place for where the ptr *points to*, so we get one. let place = self.ref_to_mplace(val)?; @@ -622,7 +661,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { }; // Reborrow. - let new_ptr = self.reborrow(place, size, new_bor)?; + let new_ptr = self.reborrow(place, size, fn_barrier, new_bor)?; // Return new ptr let new_place = MemPlace { ptr: Scalar::Ptr(new_ptr), ..*place }; @@ -631,11 +670,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { fn retag( &mut self, - _fn_entry: bool, + fn_entry: bool, place: PlaceTy<'tcx, Borrow> ) -> EvalResult<'tcx> { - // TODO: Honor `fn_entry`. - // We need a visitor to visit all references. However, that requires // a `MemPlace`, so we have a fast path for reference types that // avoids allocating. @@ -648,18 +685,19 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { } { // fast path let val = self.read_immediate(self.place_to_op(place)?)?; - let val = self.retag_reference(val, mutbl)?; + let val = self.retag_reference(val, mutbl, fn_entry)?; self.write_immediate(val, place)?; return Ok(()); } let place = self.force_allocation(place)?; - let mut visitor = RetagVisitor { ecx: self }; + let mut visitor = RetagVisitor { ecx: self, fn_entry }; visitor.visit_value(place)?; // The actual visitor struct RetagVisitor<'ecx, 'a, 'mir, 'tcx> { ecx: &'ecx mut MiriEvalContext<'a, 'mir, 'tcx>, + fn_entry: bool, } impl<'ecx, 'a, 'mir, 'tcx> MutValueVisitor<'a, 'mir, 'tcx, Evaluator<'tcx>> @@ -684,7 +722,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { _ => return Ok(()), // nothing to do }; let val = self.ecx.read_immediate(place.into())?; - let val = self.ecx.retag_reference(val, mutbl)?; + let val = self.ecx.retag_reference(val, mutbl, self.fn_entry)?; self.ecx.write_immediate(val, place.into())?; Ok(()) } diff --git a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut1.rs b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut1.rs index e812e13e702c..b82901985b78 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut1.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut1.rs @@ -1,12 +1,17 @@ -// ignore-test validation_op is disabled - #![allow(unused_variables)] -mod safe { - pub fn safe(x: &mut i32, y: &mut i32) {} //~ ERROR: in conflict with lock WriteLock -} +use std::mem; + +pub fn safe(x: &mut i32, y: &mut i32) {} //~ ERROR barrier fn main() { - let x = &mut 0 as *mut _; - unsafe { safe::safe(&mut *x, &mut *x) }; + let mut x = 0; + let xraw: *mut i32 = unsafe { mem::transmute(&mut x) }; + // We need to apply some tricky to be able to call `safe` with two mutable references + // with the same tag: We transmute both the fn ptr (to take raw ptrs) and the argument + // (to be raw, but still have the unique tag). + let safe_raw: fn(x: *mut i32, y: *mut i32) = unsafe { + mem::transmute::(safe) + }; + safe_raw(xraw, xraw); } diff --git a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut2.rs b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut2.rs index 36ebcc2b4ac6..69caddfa8c38 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut2.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut2.rs @@ -1,12 +1,17 @@ -// ignore-test validation_op is disabled - #![allow(unused_variables)] -mod safe { - pub fn safe(x: &i32, y: &mut i32) {} //~ ERROR: in conflict with lock ReadLock -} +use std::mem; + +pub fn safe(x: &i32, y: &mut i32) {} //~ ERROR barrier fn main() { - let x = &mut 0 as *mut _; - unsafe { safe::safe(&*x, &mut *x) }; + let mut x = 0; + let xref = &mut x; + let xraw: *mut i32 = unsafe { mem::transmute_copy(&xref) }; + let xshr = &*xref; + // transmute fn ptr around so that we can avoid retagging + let safe_raw: fn(x: *const i32, y: *mut i32) = unsafe { + mem::transmute::(safe) + }; + safe_raw(xshr, xraw); } diff --git a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut3.rs b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut3.rs index ad50fbd61b45..d37f9e63f60d 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut3.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut3.rs @@ -1,12 +1,17 @@ -// ignore-test validation_op is disabled - #![allow(unused_variables)] -mod safe { - pub fn safe(x: &mut i32, y: &i32) {} //~ ERROR: in conflict with lock WriteLock -} +use std::mem; + +pub fn safe(x: &mut i32, y: &i32) {} //~ ERROR does not exist on the stack fn main() { - let x = &mut 0 as *mut _; - unsafe { safe::safe(&mut *x, &*x) }; + let mut x = 0; + let xref = &mut x; + let xraw: *mut i32 = unsafe { mem::transmute_copy(&xref) }; + let xshr = &*xref; + // transmute fn ptr around so that we can avoid retagging + let safe_raw: fn(x: *mut i32, y: *const i32) = unsafe { + mem::transmute::(safe) + }; + safe_raw(xraw, xshr); } diff --git a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut4.rs b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut4.rs index a0f0a3cf9753..bf65d6e23035 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut4.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut4.rs @@ -1,15 +1,19 @@ -// ignore-test validation_op is disabled - #![allow(unused_variables)] -mod safe { - use std::cell::Cell; +use std::mem; +use std::cell::Cell; - // Make sure &mut UnsafeCell also has a lock to it - pub fn safe(x: &mut Cell, y: &i32) {} //~ ERROR: in conflict with lock WriteLock -} +// Make sure &mut UnsafeCell also is exclusive +pub fn safe(x: &i32, y: &mut Cell) {} //~ ERROR barrier fn main() { - let x = &mut 0 as *mut _; - unsafe { safe::safe(&mut *(x as *mut _), &*x) }; + let mut x = 0; + let xref = &mut x; + let xraw: *mut i32 = unsafe { mem::transmute_copy(&xref) }; + let xshr = &*xref; + // transmute fn ptr around so that we can avoid retagging + let safe_raw: fn(x: *const i32, y: *mut Cell) = unsafe { + mem::transmute::), _>(safe) + }; + safe_raw(xshr, xraw as *mut _); } diff --git a/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs b/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs index bd0fec859d8f..e8a182779ade 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs @@ -8,7 +8,7 @@ fn demo_mut_advanced_unique(mut our: Box) -> i32 { unknown_code_2(); // We know this will return 5 - *our //~ ERROR does not exist on the stack + *our } // Now comes the evil context @@ -21,7 +21,7 @@ fn unknown_code_1(x: &i32) { unsafe { } } fn unknown_code_2() { unsafe { - *LEAK = 7; + *LEAK = 7; //~ ERROR barrier } } fn main() { diff --git a/tests/compile-fail-fullmir/stacked_borrows/illegal_write1.rs b/tests/compile-fail-fullmir/stacked_borrows/illegal_write1.rs index b106cc8dc403..d0a23cb44489 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/illegal_write1.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/illegal_write1.rs @@ -1,12 +1,9 @@ -fn evil(x: &u32) { - // mutating shared ref without `UnsafeCell` - let x : *mut u32 = x as *const _ as *mut _; - unsafe { *x = 42; } -} - fn main() { let target = Box::new(42); // has an implicit raw - let ref_ = &*target; - evil(ref_); // invalidates shared ref, activates raw - let _x = *ref_; //~ ERROR is not frozen + let xref = &*target; + { + let x : *mut u32 = xref as *const _ as *mut _; + unsafe { *x = 42; } // invalidates shared ref, activates raw + } + let _x = *xref; //~ ERROR is not frozen } diff --git a/tests/compile-fail-fullmir/stacked_borrows/invalidate_against_barrier1.rs b/tests/compile-fail-fullmir/stacked_borrows/invalidate_against_barrier1.rs new file mode 100644 index 000000000000..fc0dbb9e1313 --- /dev/null +++ b/tests/compile-fail-fullmir/stacked_borrows/invalidate_against_barrier1.rs @@ -0,0 +1,13 @@ +fn inner(x: *mut i32, _y: &mut i32) { + // If `x` and `y` alias, retagging is fine with this... but we really + // shouldn't be allowed to use `x` at all because `y` was assumed to be + // unique for the duration of this call. + let _val = unsafe { *x }; //~ ERROR barrier +} + +fn main() { + let mut x = 0; + let xraw = &mut x as *mut _; + let xref = unsafe { &mut *xraw }; + inner(xraw, xref); +} diff --git a/tests/compile-fail-fullmir/stacked_borrows/invalidate_against_barrier2.rs b/tests/compile-fail-fullmir/stacked_borrows/invalidate_against_barrier2.rs new file mode 100644 index 000000000000..a080c0958e40 --- /dev/null +++ b/tests/compile-fail-fullmir/stacked_borrows/invalidate_against_barrier2.rs @@ -0,0 +1,13 @@ +fn inner(x: *mut i32, _y: &i32) { + // If `x` and `y` alias, retagging is fine with this... but we really + // shouldn't be allowed to write to `x` at all because `y` was assumed to be + // immutable for the duration of this call. + unsafe { *x = 0 }; //~ ERROR barrier +} + +fn main() { + let mut x = 0; + let xraw = &mut x as *mut _; + let xref = unsafe { &*xraw }; + inner(xraw, xref); +} diff --git a/tests/compile-fail-fullmir/stacked_borrows/mut_exclusive_violation1.rs b/tests/compile-fail-fullmir/stacked_borrows/mut_exclusive_violation1.rs index fec699e35bcf..3fe6b6567423 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/mut_exclusive_violation1.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/mut_exclusive_violation1.rs @@ -21,7 +21,7 @@ fn unknown_code_1(x: &i32) { unsafe { } } fn unknown_code_2() { unsafe { - *LEAK = 7; //~ ERROR does not exist on the stack + *LEAK = 7; //~ ERROR barrier } } fn main() { From 58309956c10914d55171666abd1782063e921d18 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 Nov 2018 13:43:55 +0100 Subject: [PATCH 0431/5092] for now, we allow Undef in raw pointers as we do in integers --- tests/compile-fail/validity/undef.rs | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 tests/compile-fail/validity/undef.rs diff --git a/tests/compile-fail/validity/undef.rs b/tests/compile-fail/validity/undef.rs deleted file mode 100644 index f86fef9454e8..000000000000 --- a/tests/compile-fail/validity/undef.rs +++ /dev/null @@ -1,12 +0,0 @@ -#![allow(unused_variables)] -// error-pattern: encountered undefined address in pointer - -use std::mem; - -fn make_raw() -> *const f32 { - unsafe { mem::uninitialized() } -} - -fn main() { - let _x = make_raw(); -} From 194710e112ef5cc7bd9f8a7f5924c4574eca0406 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 Nov 2018 15:21:41 +0100 Subject: [PATCH 0432/5092] no barriers for boxes --- src/stacked_borrows.rs | 37 +++++++++++-------- .../box_exclusive_violation1.rs | 4 +- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 6b851cd65b5e..a31fd462e526 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -673,19 +673,27 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { fn_entry: bool, place: PlaceTy<'tcx, Borrow> ) -> EvalResult<'tcx> { + // Determine mutability and whether to add a barrier. + // Cannot use `builtin_deref` because that reports *immutable* for `Box`, + // making it useless. + fn qualify(ty: ty::Ty<'_>, fn_entry: bool) -> Option<(Mutability, bool)> { + match ty.sty { + // References are simple + ty::Ref(_, _, mutbl) => Some((mutbl, fn_entry)), + // Boxes do not get a barrier: Barriers reflect that references outlive the call + // they were passed in to; that's just not the case for boxes. + ty::Adt(..) if ty.is_box() => Some((MutMutable, false)), + _ => None, + } + } + // We need a visitor to visit all references. However, that requires // a `MemPlace`, so we have a fast path for reference types that // avoids allocating. - // Cannot use `builtin_deref` because that reports *immutable* for `Box`, - // making it useless. - if let Some(mutbl) = match place.layout.ty.sty { - ty::Ref(_, _, mutbl) => Some(mutbl), - ty::Adt(..) if place.layout.ty.is_box() => Some(MutMutable), - _ => None, // handled with the general case below - } { + if let Some((mutbl, barrier)) = qualify(place.layout.ty, fn_entry) { // fast path let val = self.read_immediate(self.place_to_op(place)?)?; - let val = self.retag_reference(val, mutbl, fn_entry)?; + let val = self.retag_reference(val, mutbl, barrier)?; self.write_immediate(val, place)?; return Ok(()); } @@ -716,14 +724,11 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { { // Cannot use `builtin_deref` because that reports *immutable* for `Box`, // making it useless. - let mutbl = match place.layout.ty.sty { - ty::Ref(_, _, mutbl) => mutbl, - ty::Adt(..) if place.layout.ty.is_box() => MutMutable, - _ => return Ok(()), // nothing to do - }; - let val = self.ecx.read_immediate(place.into())?; - let val = self.ecx.retag_reference(val, mutbl, self.fn_entry)?; - self.ecx.write_immediate(val, place.into())?; + if let Some((mutbl, barrier)) = qualify(place.layout.ty, self.fn_entry) { + let val = self.ecx.read_immediate(place.into())?; + let val = self.ecx.retag_reference(val, mutbl, barrier)?; + self.ecx.write_immediate(val, place.into())?; + } Ok(()) } } diff --git a/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs b/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs index e8a182779ade..bd0fec859d8f 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs @@ -8,7 +8,7 @@ fn demo_mut_advanced_unique(mut our: Box) -> i32 { unknown_code_2(); // We know this will return 5 - *our + *our //~ ERROR does not exist on the stack } // Now comes the evil context @@ -21,7 +21,7 @@ fn unknown_code_1(x: &i32) { unsafe { } } fn unknown_code_2() { unsafe { - *LEAK = 7; //~ ERROR barrier + *LEAK = 7; } } fn main() { From 97e010f5b97f767f4eceadd3d4ea9556052e8393 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 Nov 2018 15:25:47 +0100 Subject: [PATCH 0433/5092] barriers prevent deallocation --- src/stacked_borrows.rs | 82 +++++++++++++------ .../deallocate_against_barrier.rs | 13 +++ 2 files changed, 70 insertions(+), 25 deletions(-) create mode 100644 tests/compile-fail-fullmir/stacked_borrows/deallocate_against_barrier.rs diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index a31fd462e526..e06943f2ba06 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -90,6 +90,14 @@ pub enum RefKind { Raw, } +/// What kind of access is being performed? +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub enum AccessKind { + Read, + Write, + Dealloc, +} + /// Extra global state in the memory, available to the memory access hooks #[derive(Debug)] pub struct BarrierTracking { @@ -221,13 +229,13 @@ impl<'tcx> Stack { fn access( &mut self, bor: Borrow, - is_write: bool, + kind: AccessKind, barrier_tracking: &BarrierTracking, ) -> EvalResult<'tcx> { // Check if we can match the frozen "item". // Not possible on writes! if self.is_frozen() { - if !is_write { + if kind == AccessKind::Read { // When we are frozen, we just accept all reads. No harm in this. // The deref already checked that `Uniq` items are in the stack, and that // the location is frozen if it should be. @@ -247,26 +255,41 @@ impl<'tcx> Stack { ))) } (BorStackItem::Uniq(itm_t), Borrow::Uniq(bor_t)) if itm_t == bor_t => { - // Found matching unique item. - return Ok(()) + // Found matching unique item. Continue after the match. } - (BorStackItem::Shr, _) if !is_write => { + (BorStackItem::Shr, _) if kind == AccessKind::Read => { // When reading, everything can use a shared item! // We do not want to do this when writing: Writing to an `&mut` // should reaffirm its exclusivity (i.e., make sure it is - // on top of the stack). - return Ok(()) + // on top of the stack). Continue after the match. } (BorStackItem::Shr, Borrow::Shr(_)) => { - // Found matching shared item. - return Ok(()) + // Found matching shared item. Continue after the match. } _ => { - // Pop this. This ensures U2. + // Pop this, go on. This ensures U2. let itm = self.borrows.pop().unwrap(); trace!("access: Popping {:?}", itm); + continue } } + // If we got here, we found a matching item. Congratulations! + // However, we are not done yet: If this access is deallocating, we must make sure + // there are no active barriers remaining on the stack. + if kind == AccessKind::Dealloc { + for &itm in self.borrows.iter().rev() { + match itm { + BorStackItem::FnBarrier(call) if barrier_tracking.is_active(call) => { + return err!(MachineError(format!( + "Deallocating with active barrier ({})", call + ))) + } + _ => {}, + } + } + } + // NOW we are done. + return Ok(()) } // If we got here, we did not find our item. err!(MachineError(format!( @@ -352,18 +375,16 @@ impl<'tcx> Stacks { &self, ptr: Pointer, size: Size, - is_write: bool, - barrier_tracking: &BarrierTracking, + kind: AccessKind, ) -> EvalResult<'tcx> { - trace!("{} access of tag {:?}: {:?}, size {}", - if is_write { "read" } else { "write" }, - ptr.tag, ptr, size.bytes()); + trace!("{:?} access of tag {:?}: {:?}, size {}", kind, ptr.tag, ptr, size.bytes()); // Even reads can have a side-effect, by invalidating other references. // This is fundamentally necessary since `&mut` asserts that there // are no accesses through other references, not even reads. + let barrier_tracking = self.barrier_tracking.borrow(); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { - stack.access(ptr.tag, is_write, barrier_tracking)?; + stack.access(ptr.tag, kind, &*barrier_tracking)?; } Ok(()) } @@ -377,7 +398,6 @@ impl<'tcx> Stacks { mut barrier: Option, new_bor: Borrow, new_kind: RefKind, - barrier_tracking: &BarrierTracking, ) -> EvalResult<'tcx> { assert_eq!(new_bor.is_unique(), new_kind == RefKind::Unique); trace!("reborrow for tag {:?} to {:?} as {:?}: {:?}, size {}", @@ -385,8 +405,17 @@ impl<'tcx> Stacks { if new_kind == RefKind::Raw { // No barrier for raw, including `&UnsafeCell`. They can rightfully // alias with `&mut`. + // FIXME: This means that the `dereferencable` attribute on non-frozen shared + // references is incorrect! They are dereferencable when the function is + // called, but might become non-dereferencable during the coruse of execution. + // Also see [1], [2]. + // + // [1]: , + // [2]: barrier = None; } + let barrier_tracking = self.barrier_tracking.borrow(); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { // Access source `ptr`, create new ref. @@ -410,7 +439,12 @@ impl<'tcx> Stacks { continue; } // We need to do some actual work. - stack.access(ptr.tag, new_kind == RefKind::Unique, barrier_tracking)?; + let access_kind = if new_kind == RefKind::Unique { + AccessKind::Write + } else { + AccessKind::Read + }; + stack.access(ptr.tag, access_kind, &*barrier_tracking)?; if let Some(call) = barrier { stack.barrier(call); } @@ -440,7 +474,7 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - alloc.extra.access(ptr, size, /*is_write*/false, &*alloc.extra.barrier_tracking.borrow()) + alloc.extra.access(ptr, size, AccessKind::Read) } #[inline(always)] @@ -449,7 +483,7 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - alloc.extra.access(ptr, size, /*is_write*/true, &*alloc.extra.barrier_tracking.borrow()) + alloc.extra.access(ptr, size, AccessKind::Write) } #[inline(always)] @@ -458,9 +492,7 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - // This is like mutating - alloc.extra.access(ptr, size, /*is_write*/true, &*alloc.extra.barrier_tracking.borrow()) - // FIXME: Error out of there are any barriers? + alloc.extra.access(ptr, size, AccessKind::Dealloc) } } @@ -627,12 +659,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { // Reference that cares about freezing. We need a frozen-sensitive reborrow. self.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; - alloc.extra.reborrow(cur_ptr, size, barrier, new_bor, kind, &*self.memory().extra.borrow()) + alloc.extra.reborrow(cur_ptr, size, barrier, new_bor, kind) })?; } else { // Just treat this as one big chunk. let kind = if new_bor.is_unique() { RefKind::Unique } else { RefKind::Raw }; - alloc.extra.reborrow(ptr, size, barrier, new_bor, kind, &*self.memory().extra.borrow())?; + alloc.extra.reborrow(ptr, size, barrier, new_bor, kind)?; } Ok(new_ptr) } diff --git a/tests/compile-fail-fullmir/stacked_borrows/deallocate_against_barrier.rs b/tests/compile-fail-fullmir/stacked_borrows/deallocate_against_barrier.rs new file mode 100644 index 000000000000..eb988a589959 --- /dev/null +++ b/tests/compile-fail-fullmir/stacked_borrows/deallocate_against_barrier.rs @@ -0,0 +1,13 @@ +// error-pattern: Deallocating with active barrier + +fn inner(x: &mut i32, f: fn(&mut i32)) { + // `f` may mutate, but it may not deallocate! + f(x) +} + +fn main() { + inner(Box::leak(Box::new(0)), |x| { + let raw = x as *mut _; + drop(unsafe { Box::from_raw(raw) }); + }); +} From edc2fb5f60232ddd629986accc553acf75ab78de Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 27 Nov 2018 14:41:53 +0100 Subject: [PATCH 0434/5092] Expose some internals for priroda --- src/lib.rs | 12 ++++++------ src/mono_hash_map.rs | 6 ++++++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 10a1405b2a62..1625223ecd45 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,15 +37,15 @@ mod range_map; mod mono_hash_map; mod stacked_borrows; -use crate::fn_call::EvalContextExt as MissingFnsEvalContextExt; -use crate::operator::EvalContextExt as OperatorEvalContextExt; -use crate::intrinsic::EvalContextExt as IntrinsicEvalContextExt; -use crate::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; +pub use crate::fn_call::EvalContextExt as MissingFnsEvalContextExt; +pub use crate::operator::EvalContextExt as OperatorEvalContextExt; +pub use crate::intrinsic::EvalContextExt as IntrinsicEvalContextExt; +pub use crate::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; use crate::range_map::RangeMap; #[allow(unused_imports)] // FIXME rustc bug https://github.com/rust-lang/rust/issues/53682 -use crate::helpers::{ScalarExt, EvalContextExt as HelpersEvalContextExt}; +pub use crate::helpers::{ScalarExt, EvalContextExt as HelpersEvalContextExt}; use crate::mono_hash_map::MonoHashMap; -use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; +pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; // Used by priroda pub use crate::stacked_borrows::{Borrow, Stack, Stacks, BorStackItem}; diff --git a/src/mono_hash_map.rs b/src/mono_hash_map.rs index e30578a5a77b..42ac42544f00 100644 --- a/src/mono_hash_map.rs +++ b/src/mono_hash_map.rs @@ -17,6 +17,12 @@ use crate::AllocMap; #[derive(Debug, Clone)] pub struct MonoHashMap(RefCell>>); +impl MonoHashMap { + pub fn values(&self, f: impl FnOnce(&mut Iterator) -> T) -> T { + f(&mut self.0.borrow().values().map(|v| &**v)) + } +} + impl Default for MonoHashMap { fn default() -> Self { MonoHashMap(RefCell::new(Default::default())) From b72398de74161c0228d61501680ab653b9019b55 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Nov 2018 14:48:46 +0100 Subject: [PATCH 0435/5092] fix README install instructions --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d6e0be40cacf..dcf13a8af4a2 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ compiled the right way. Install Miri as a cargo subcommand: ```sh -cargo +nightly install --git https://github.com/solson/miri/ +cargo +nightly install --git https://github.com/solson/miri/ miri ``` Be aware that if you used `rustup override set` to fix a particular Rust version From 5958fa6a7049cd003e87d6d8502ae1237262c378 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 27 Nov 2018 16:20:15 +0100 Subject: [PATCH 0436/5092] Use explicit `dyn` trait object --- src/mono_hash_map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono_hash_map.rs b/src/mono_hash_map.rs index 42ac42544f00..278bbd9cf2b1 100644 --- a/src/mono_hash_map.rs +++ b/src/mono_hash_map.rs @@ -18,7 +18,7 @@ use crate::AllocMap; pub struct MonoHashMap(RefCell>>); impl MonoHashMap { - pub fn values(&self, f: impl FnOnce(&mut Iterator) -> T) -> T { + pub fn values(&self, f: impl FnOnce(&mut dyn Iterator) -> T) -> T { f(&mut self.0.borrow().values().map(|v| &**v)) } } From 26fe778c55ef562e88bb59fd4d43adc1b7885e24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20S=CC=B6c=CC=B6h=CC=B6n=CC=B6e=CC=B6i=CC=B6d=CC=B6?= =?UTF-8?q?e=CC=B6r=20Scherer?= Date: Wed, 28 Nov 2018 09:58:23 +0100 Subject: [PATCH 0437/5092] Typo Co-Authored-By: RalfJung --- src/stacked_borrows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index e06943f2ba06..31f80fe2f6c6 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -407,7 +407,7 @@ impl<'tcx> Stacks { // alias with `&mut`. // FIXME: This means that the `dereferencable` attribute on non-frozen shared // references is incorrect! They are dereferencable when the function is - // called, but might become non-dereferencable during the coruse of execution. + // called, but might become non-dereferencable during the course of execution. // Also see [1], [2]. // // [1]: Date: Wed, 28 Nov 2018 16:14:41 +0100 Subject: [PATCH 0438/5092] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 0268b07ac411..826965c66dea 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-26 +nightly-2018-11-28 From fb72348e5f4bd396d91c808b1e404f233908fb05 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Nov 2018 19:02:56 +0100 Subject: [PATCH 0439/5092] disable async-fn, for now --- tests/run-pass-fullmir/async-fn.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/run-pass-fullmir/async-fn.rs b/tests/run-pass-fullmir/async-fn.rs index 7c32b026df67..56e6031ceb5a 100644 --- a/tests/run-pass-fullmir/async-fn.rs +++ b/tests/run-pass-fullmir/async-fn.rs @@ -1,3 +1,6 @@ +// FIXME: investigate why this fails since barriers have been added +// compile-flags: -Zmiri-disable-validation + #![feature( async_await, await_macro, From 42e73b5536ff01c4ba846197fc18b5e051ba8515 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 29 Nov 2018 17:29:00 +0100 Subject: [PATCH 0440/5092] async fn got fixed --- tests/run-pass-fullmir/async-fn.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/run-pass-fullmir/async-fn.rs b/tests/run-pass-fullmir/async-fn.rs index 56e6031ceb5a..7c32b026df67 100644 --- a/tests/run-pass-fullmir/async-fn.rs +++ b/tests/run-pass-fullmir/async-fn.rs @@ -1,6 +1,3 @@ -// FIXME: investigate why this fails since barriers have been added -// compile-flags: -Zmiri-disable-validation - #![feature( async_await, await_macro, From 3999db1159f06672c25ba661b3a5e4de26f5b58e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 30 Nov 2018 07:26:20 +0100 Subject: [PATCH 0441/5092] new nightly, new luck --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 826965c66dea..6fd720c5c785 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-28 +nightly-2018-11-30 From 86e6470a12cc4afc00d2446a6ba0270de95f120c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 30 Nov 2018 09:23:44 +0100 Subject: [PATCH 0442/5092] update README to first describe the usual user setup, and to always set up a proper libstd --- README.md | 156 ++++++++++++++++++++++-------------------- src/bin/cargo-miri.rs | 7 +- 2 files changed, 87 insertions(+), 76 deletions(-) diff --git a/README.md b/README.md index dcf13a8af4a2..f232cf25f9fe 100644 --- a/README.md +++ b/README.md @@ -20,36 +20,6 @@ for example: [`unreachable_unchecked`]: https://doc.rust-lang.org/stable/std/hint/fn.unreachable_unchecked.html [`copy_nonoverlapping`]: https://doc.rust-lang.org/stable/std/ptr/fn.copy_nonoverlapping.html -## Building Miri - -We recommend that you install [rustup] to obtain Rust. Then all you have -to do is: - -```sh -cargo +nightly build -``` - -This uses the very latest Rust version. If you experience any problem, refer to -the `rust-version` file which contains a particular Rust nightly version that -has been tested against the version of miri you are using. Make sure to use -that particular `nightly-YYYY-MM-DD` whenever the instructions just say -`nightly`. - -To avoid repeating the nightly version all the time, you can use -`rustup override set nightly` (or `rustup override set nightly-YYYY-MM-DD`), -which means `nightly` Rust will automatically be used whenever you are working -in this directory. - -[rustup]: https://www.rustup.rs - -## Running Miri on tiny examples - -```sh -cargo +nightly run -- -Zmiri-disable-validation tests/run-pass/vecs.rs # Or whatever test you like. -``` - -We have to disable validation because that can lead to errors when libstd is not -compiled the right way. ## Running Miri on your own project('s test suite) @@ -59,13 +29,17 @@ Install Miri as a cargo subcommand: cargo +nightly install --git https://github.com/solson/miri/ miri ``` -Be aware that if you used `rustup override set` to fix a particular Rust version -for the miri directory, that will *not* apply to your own project directory! -You have to use a consistent Rust version for building miri and your project for -this to work, so remember to either always specify the nightly version manually, -overriding it in your project directory as well, or use `rustup default nightly` -(or `rustup default nightly-YYYY-MM-DD`) to globally make `nightly` the default -toolchain. +If this does not work, try using the nightly version given in +[this file](https://raw.githubusercontent.com/solson/miri/master/rust-version). CI +should ensure that this nightly always works. + +You have to use a consistent Rust version for building miri and your project, so +remember to either always specify the nightly version manually (like in the +example above), overriding it in your project directory as well, or use `rustup +default nightly` (or `rustup default nightly-YYYY-MM-DD`) to globally make +`nightly` the default toolchain. + +Now you can run your project in miri: 1. Run `cargo clean` to eliminate any cached dependencies. Miri needs your dependencies to be compiled the right way, that would not happen if they have @@ -93,53 +67,79 @@ You may be running `cargo miri` with a different compiler version than the one used to build the custom libstd that Miri uses, and Miri failed to detect that. Try deleting `~/.cache/miri`. -## Miri `-Z` flags - -Several `-Z` flags are relevant for miri: - -* `-Zmir-opt-level` controls how many MIR optimizations are performed. miri - overrides the default to be `0`; be advised that using any higher level can - make miri miss bugs in your program because they got optimized away. -* `-Zalways-encode-mir` makes rustc dump MIR even for completely monomorphic - functions. This is needed so that miri can execute such functions, so miri - sets this flag per default. -* `-Zmiri-disable-validation` is a custom `-Z` flag added by miri. It disables - enforcing the validity invariant, which is enforced by default. This is - mostly useful for debugging; it means miri will miss bugs in your program. - ## Development and Debugging -Since the heart of Miri (the main interpreter engine) lives in rustc, working on -Miri will often require using a locally built rustc. This includes getting a -trace of the execution, as distributed rustc has `debug!` and `trace!` disabled. +If you want to hack on miri yourself, great! Here are some resources you might +find useful. -The first-time setup for a local rustc looks as follows: +### Using a nightly rustc + +miri heavily relies on internal rustc interfaces to execute MIR. Still, some +things (like adding support for a new intrinsic) can be done by working just on +the miri side. + +To prepare, make sure you are using a nightly Rust compiler. You also need to +set up a libstd that enables execution with miri: + +```sh +rustup override set nightly # or the nightly in `rust-version` +cargo run --bin cargo-miri -- miri setup +``` + +The last command should end in printing the directory where the libstd was +built. Set that as your MIRI_SYSROOT environment variable: + +```sh +export MIRI_SYSROOT=~/.cache/miri/HOST # or whatever the previous command said +``` + +### Testing Miri + +Now you can run Miri directly, without going through `cargo miri`: + +```sh +cargo run tests/run-pass-fullmir/format.rs # or whatever test you like +``` + +You can also run the test suite with `cargo test --release`. `cargo test +--release FILTER` only runs those tests that contain `FILTER` in their filename +(including the base directory, e.g. `cargo test --release fail` will run all +compile-fail tests). We recommend using `--release` to make test running take +less time. + +Now you are set up! You can write a failing test case, and tweak miri until it +fails no more. + +### Using a locally built rustc + +Since the heart of Miri (the main interpreter engine) lives in rustc, working on +Miri will often require using a locally built rustc. The bug you want to fix +may actually be on the rustc side, or you just need to get more detailed trace +of the execution -- in both cases, you should develop miri against a rustc you +compiled yourself, with debug assertions (and hence tracing) enabled. + +The setup for a local rustc works as follows: ```sh git clone https://github.com/rust-lang/rust/ rustc cd rustc cp config.toml.example config.toml # Now edit `config.toml` and set `debug-assertions = true` and `test-miri = true`. # The latter is important to build libstd with the right flags for miri. +# This step can take 30 minutes and more. ./x.py build src/rustc +# If you change something, you can get a faster rebuild by doing +./x.py --keep-stage 0 build src/rustc # You may have to change the architecture in the next command rustup toolchain link custom build/x86_64-unknown-linux-gnu/stage2 -# Now cd to your Miri directory +# Now cd to your Miri directory, then configure rustup rustup override set custom +# We also need to tell Miri where to find its sysroot. Since we set +# `test-miri` above, we can just use rustc' sysroot. +export MIRI_SYSROOT=$(rustc --print sysroot) ``` -The `build` step can take 30 minutes and more. -Now you can `cargo build` Miri, and you can `cargo test --release` it. `cargo -test --release FILTER` only runs those tests that contain `FILTER` in their -filename (including the base directory, e.g. `cargo test --release fail` will -run all compile-fail tests). We recommend using `--release` to make test -running take less time. - -Notice that the "fullmir" tests only run if you have `MIRI_SYSROOT` set, the -test runner does not realized that your libstd comes with full MIR. The -following will set it correctly: -```sh -MIRI_SYSROOT=$(rustc --print sysroot) cargo test --release -``` +With this, you should now have a working development setup! See "Testing Miri" +above for how to proceed. Moreover, you can now run Miri with a trace of all execution steps: ```sh @@ -157,11 +157,19 @@ MIRI_LOG=rustc_mir::interpret=debug,miri::stacked_borrows cargo run tests/run-pa In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an evaluation error was originally created. -If you changed something in rustc and want to re-build, run -``` -./x.py --keep-stage 0 build src/rustc -``` -This avoids rebuilding the entire stage 0, which can save a lot of time. +### Miri `-Z` flags + +Several `-Z` flags are relevant for miri: + +* `-Zmir-opt-level` controls how many MIR optimizations are performed. miri + overrides the default to be `0`; be advised that using any higher level can + make miri miss bugs in your program because they got optimized away. +* `-Zalways-encode-mir` makes rustc dump MIR even for completely monomorphic + functions. This is needed so that miri can execute such functions, so miri + sets this flag per default. +* `-Zmiri-disable-validation` is a custom `-Z` flag added by miri. It disables + enforcing the validity invariant, which is enforced by default. This is + mostly useful for debugging; it means miri will miss bugs in your program. ## Contributing and getting help diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index ed4ffa43dbce..70e75eec649c 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -149,7 +149,6 @@ fn setup(ask_user: bool) { let dirs = directories::ProjectDirs::from("miri", "miri", "miri").unwrap(); let dir = dirs.cache_dir(); if !dir.exists() { - println!("Creating `{}` and using it for miri's build of libstd", dir.display()); fs::create_dir_all(&dir).unwrap(); } // The interesting bit: Xargo.toml @@ -184,7 +183,11 @@ path = "lib.rs" } // That should be it! - std::env::set_var("MIRI_SYSROOT", dir.join("HOST")); + let sysroot = dir.join("HOST"); + std::env::set_var("MIRI_SYSROOT", &sysroot); + if !ask_user { + println!("A libstd for miri is now available in `{}`", sysroot.display()); + } } fn main() { From 5032560eaa68b5e6a16c67e42d8b22b10612bc22 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 30 Nov 2018 09:31:09 +0100 Subject: [PATCH 0443/5092] add link within document --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f232cf25f9fe..c300c72628dd 100644 --- a/README.md +++ b/README.md @@ -138,8 +138,8 @@ rustup override set custom export MIRI_SYSROOT=$(rustc --print sysroot) ``` -With this, you should now have a working development setup! See "Testing Miri" -above for how to proceed. +With this, you should now have a working development setup! See +["Testing Miri"](#testing-miri) above for how to proceed. Moreover, you can now run Miri with a trace of all execution steps: ```sh From 3478c0c1e6883c2a9385f410d01bfa2203135ca3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 30 Nov 2018 22:23:20 +0100 Subject: [PATCH 0444/5092] update contact channels --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c300c72628dd..5f8f8fb8502f 100644 --- a/README.md +++ b/README.md @@ -175,8 +175,10 @@ Several `-Z` flags are relevant for miri: Check out the issues on this GitHub repository for some ideas. There's lots that needs to be done that I haven't documented in the issues yet, however. For more -ideas or help with running or hacking on Miri, you can contact me (`scott`) on -Mozilla IRC in any of the Rust IRC channels (`#rust`, `#rust-offtopic`, etc). +ideas or help with running or hacking on Miri, you can open an issue here on +GitHub or contact us (`oli-obk` and `RalfJ`) on the [Rust Zulip]. + +[Rust Zulip]: https://rust-lang.zulipchat.com ## History From dcfc2f207e40da620557ab31e0e71589a0e26552 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 2 Dec 2018 10:29:57 +0100 Subject: [PATCH 0445/5092] do not even look for cargo metadata in 'cargo miri setup' --- src/bin/cargo-miri.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 70e75eec649c..4c83c5bd3dc0 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -223,6 +223,10 @@ fn main() { // We always setup let ask = subcommand != MiriCommand::Setup; setup(ask); + if subcommand == MiriCommand::Setup { + // Stop here. + return; + } // Now run the command. for target in list_targets(std::env::args().skip(skip)) { From 429d84f0681f048661a7377b7acb57eeee77baef Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 2 Dec 2018 11:14:24 +0100 Subject: [PATCH 0446/5092] remove/fix outdated FIXMEs in tests --- tests/compile-fail-fullmir/stacked_borrows/illegal_write2.rs | 4 ---- .../stacked_borrows/pointer_smuggling.rs | 5 ++--- tests/compiletest.rs | 2 +- tests/run-pass/dst-struct.rs | 3 ++- tests/run-pass/sums.rs | 3 --- tests/run-pass/vec-matching-fold.rs | 2 -- 6 files changed, 5 insertions(+), 14 deletions(-) diff --git a/tests/compile-fail-fullmir/stacked_borrows/illegal_write2.rs b/tests/compile-fail-fullmir/stacked_borrows/illegal_write2.rs index b53655c82147..f4fefaad5e22 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/illegal_write2.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/illegal_write2.rs @@ -1,7 +1,3 @@ -// We fail to detect this when neither this nor libstd are optimized/have retagging. -// FIXME: Investigate that. -// compile-flags: -Zmir-opt-level=0 - #![allow(unused_variables)] fn main() { diff --git a/tests/compile-fail-fullmir/stacked_borrows/pointer_smuggling.rs b/tests/compile-fail-fullmir/stacked_borrows/pointer_smuggling.rs index 68f3d2923b15..bd5e28b47e86 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/pointer_smuggling.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/pointer_smuggling.rs @@ -1,5 +1,3 @@ -#![allow(unused_variables)] - static mut PTR: *mut u8 = 0 as *mut _; fn fun1(x: &mut u8) { @@ -14,7 +12,8 @@ fn fun2() { } fn main() { - let val = &mut 0; // FIXME: This should also work with a local variable, but currently it does not. + let mut val = 0; + let val = &mut val; fun1(val); *val = 2; // this invalidates any raw ptrs `fun1` might have created. fun2(); // if they now use a raw ptr they break our reference diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 7aa55ef66340..de693bd46320 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -106,7 +106,7 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: flags.push("-Zmir-opt-level=1".to_owned()); } if !have_fullmir() { - // Validation relies on the EscapeToRaw statements being emitted + // FIXME: Validation relies on the EscapeToRaw statements being emitted flags.push("-Zmiri-disable-validation".to_owned()); } diff --git a/tests/run-pass/dst-struct.rs b/tests/run-pass/dst-struct.rs index 0820614ab5c8..6ef0a6330f73 100644 --- a/tests/run-pass/dst-struct.rs +++ b/tests/run-pass/dst-struct.rs @@ -127,8 +127,9 @@ pub fn main() { let f2 : Box> = f1; foo(&*f2); - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let f3 : Box> = Box::>::new(Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }); foo(&*f3); + let f4 : Box> = box Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + foo(&*f4); } diff --git a/tests/run-pass/sums.rs b/tests/run-pass/sums.rs index a8dfd5ed66ae..daeba060a78b 100644 --- a/tests/run-pass/sums.rs +++ b/tests/run-pass/sums.rs @@ -1,6 +1,3 @@ -// FIXME(solson): 32-bit mode doesn't test anything currently. -#![cfg_attr(target_pointer_width = "32", allow(dead_code))] - #[derive(Debug, PartialEq)] enum Unit { Unit(()) } // Force non-C-enum representation. diff --git a/tests/run-pass/vec-matching-fold.rs b/tests/run-pass/vec-matching-fold.rs index 1a30f875580c..396846b23236 100644 --- a/tests/run-pass/vec-matching-fold.rs +++ b/tests/run-pass/vec-matching-fold.rs @@ -22,7 +22,6 @@ fn foldl(values: &[T], &[ref head, ref tail..] => foldl(tail, function(initial, head), function), &[] => { - // FIXME: call guards let res = initial.clone(); res } } @@ -39,7 +38,6 @@ fn foldr(values: &[T], &[ref head.., ref tail] => foldr(head, function(tail, initial), function), &[] => { - // FIXME: call guards let res = initial.clone(); res } } From 36a2b8952283e1cb86f4133ebd6ea778da1a5b50 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 2 Dec 2018 11:26:09 +0100 Subject: [PATCH 0447/5092] remove a whole lot of unnecessary attributes --- .../stacked_borrows/alias_through_mutation.rs | 2 -- .../compile-fail-fullmir/stacked_borrows/aliasing_mut1.rs | 4 +--- .../compile-fail-fullmir/stacked_borrows/aliasing_mut2.rs | 4 +--- .../compile-fail-fullmir/stacked_borrows/aliasing_mut3.rs | 4 +--- .../compile-fail-fullmir/stacked_borrows/aliasing_mut4.rs | 4 +--- .../stacked_borrows/buggy_split_at_mut.rs | 2 -- .../compile-fail-fullmir/stacked_borrows/illegal_write2.rs | 2 -- tests/compile-fail/never_transmute_humans.rs | 7 +------ tests/compile-fail/never_transmute_void.rs | 2 -- tests/compile-fail/validity/transmute_through_ptr.rs | 2 -- tests/run-pass/dst-struct.rs | 2 -- tests/run-pass/issue-31267-additional.rs | 4 +--- tests/run-pass/many_shr_bor.rs | 7 +++---- tests/run-pass/move-arg-2-unique.rs | 1 - tests/run-pass/move-arg-3-unique.rs | 1 - tests/run-pass/regions-lifetime-nonfree-late-bound.rs | 1 - 16 files changed, 9 insertions(+), 40 deletions(-) diff --git a/tests/compile-fail-fullmir/stacked_borrows/alias_through_mutation.rs b/tests/compile-fail-fullmir/stacked_borrows/alias_through_mutation.rs index 092f3f09ed19..db9ac93279f1 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/alias_through_mutation.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/alias_through_mutation.rs @@ -1,5 +1,3 @@ -#![allow(unused_variables)] - // This makes a ref that was passed to us via &mut alias with things it should not alias with fn retarget(x: &mut &u32, target: &mut u32) { unsafe { *x = &mut *(target as *mut _); } diff --git a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut1.rs b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut1.rs index b82901985b78..9bced43f6e85 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut1.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut1.rs @@ -1,8 +1,6 @@ -#![allow(unused_variables)] - use std::mem; -pub fn safe(x: &mut i32, y: &mut i32) {} //~ ERROR barrier +pub fn safe(_x: &mut i32, _y: &mut i32) {} //~ ERROR barrier fn main() { let mut x = 0; diff --git a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut2.rs b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut2.rs index 69caddfa8c38..ea24f1bd2748 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut2.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut2.rs @@ -1,8 +1,6 @@ -#![allow(unused_variables)] - use std::mem; -pub fn safe(x: &i32, y: &mut i32) {} //~ ERROR barrier +pub fn safe(_x: &i32, _y: &mut i32) {} //~ ERROR barrier fn main() { let mut x = 0; diff --git a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut3.rs b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut3.rs index d37f9e63f60d..e564e878ddb1 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut3.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut3.rs @@ -1,8 +1,6 @@ -#![allow(unused_variables)] - use std::mem; -pub fn safe(x: &mut i32, y: &i32) {} //~ ERROR does not exist on the stack +pub fn safe(_x: &mut i32, _y: &i32) {} //~ ERROR does not exist on the stack fn main() { let mut x = 0; diff --git a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut4.rs b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut4.rs index bf65d6e23035..15f67d0f8728 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut4.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut4.rs @@ -1,10 +1,8 @@ -#![allow(unused_variables)] - use std::mem; use std::cell::Cell; // Make sure &mut UnsafeCell also is exclusive -pub fn safe(x: &i32, y: &mut Cell) {} //~ ERROR barrier +pub fn safe(_x: &i32, _y: &mut Cell) {} //~ ERROR barrier fn main() { let mut x = 0; diff --git a/tests/compile-fail-fullmir/stacked_borrows/buggy_split_at_mut.rs b/tests/compile-fail-fullmir/stacked_borrows/buggy_split_at_mut.rs index a6daa5d93d77..959c6314690d 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/buggy_split_at_mut.rs @@ -1,5 +1,3 @@ -#![allow(unused_variables)] - mod safe { use std::slice::from_raw_parts_mut; diff --git a/tests/compile-fail-fullmir/stacked_borrows/illegal_write2.rs b/tests/compile-fail-fullmir/stacked_borrows/illegal_write2.rs index f4fefaad5e22..ba3b6686b84c 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/illegal_write2.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/illegal_write2.rs @@ -1,5 +1,3 @@ -#![allow(unused_variables)] - fn main() { let target = &mut 42; let target2 = target as *mut _; diff --git a/tests/compile-fail/never_transmute_humans.rs b/tests/compile-fail/never_transmute_humans.rs index 169e861be0b1..34203338696c 100644 --- a/tests/compile-fail/never_transmute_humans.rs +++ b/tests/compile-fail/never_transmute_humans.rs @@ -2,17 +2,12 @@ // compile-flags: -Zmiri-disable-validation #![feature(never_type)] -#![allow(unreachable_code)] -#![allow(unused_variables)] struct Human; fn main() { - let x: ! = unsafe { + let _x: ! = unsafe { std::mem::transmute::(Human) //~ ERROR constant evaluation error //^~ NOTE entered unreachable code }; - f(x) } - -fn f(x: !) -> ! { x } diff --git a/tests/compile-fail/never_transmute_void.rs b/tests/compile-fail/never_transmute_void.rs index 9c0165fed222..fab4981047f8 100644 --- a/tests/compile-fail/never_transmute_void.rs +++ b/tests/compile-fail/never_transmute_void.rs @@ -2,8 +2,6 @@ // compile-flags: -Zmiri-disable-validation #![feature(never_type)] -#![allow(unreachable_code)] -#![allow(unused_variables)] enum Void {} diff --git a/tests/compile-fail/validity/transmute_through_ptr.rs b/tests/compile-fail/validity/transmute_through_ptr.rs index d6bc0305e69d..4b6a3c95928a 100644 --- a/tests/compile-fail/validity/transmute_through_ptr.rs +++ b/tests/compile-fail/validity/transmute_through_ptr.rs @@ -1,5 +1,3 @@ -#![allow(unused_variables)] - #[repr(u32)] enum Bool { True } diff --git a/tests/run-pass/dst-struct.rs b/tests/run-pass/dst-struct.rs index 6ef0a6330f73..4c9e598e6ba3 100644 --- a/tests/run-pass/dst-struct.rs +++ b/tests/run-pass/dst-struct.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -#![allow(unused_features)] #![feature(box_syntax)] struct Fat { diff --git a/tests/run-pass/issue-31267-additional.rs b/tests/run-pass/issue-31267-additional.rs index 14e38f43c527..aaeeef8bf98b 100644 --- a/tests/run-pass/issue-31267-additional.rs +++ b/tests/run-pass/issue-31267-additional.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(unused_variables)] - #[derive(Clone, Copy, Debug)] struct Bar; @@ -25,5 +23,5 @@ impl Biz { } fn main() { - let foo = Biz::BAZ; + let _foo = Biz::BAZ; } diff --git a/tests/run-pass/many_shr_bor.rs b/tests/run-pass/many_shr_bor.rs index 393bafebfe4d..d4901abb808f 100644 --- a/tests/run-pass/many_shr_bor.rs +++ b/tests/run-pass/many_shr_bor.rs @@ -1,5 +1,4 @@ // Make sure validation can handle many overlapping shared borrows for different parts of a data structure -#![allow(unused_variables)] use std::cell::RefCell; struct Test { @@ -25,9 +24,9 @@ fn test2(r: &mut RefCell) { let x = &*r; // releasing write lock, first suspension recorded let mut x_ref = x.borrow_mut(); let x_inner : &mut i32 = &mut *x_ref; // new inner write lock, with same lifetime as outer lock - let x_inner_shr = &*x_inner; // releasing inner write lock, recording suspension - let y = &*r; // second suspension for the outer write lock - let x_inner_shr2 = &*x_inner; // 2nd suspension for inner write lock + let _x_inner_shr = &*x_inner; // releasing inner write lock, recording suspension + let _y = &*r; // second suspension for the outer write lock + let _x_inner_shr2 = &*x_inner; // 2nd suspension for inner write lock } fn main() { diff --git a/tests/run-pass/move-arg-2-unique.rs b/tests/run-pass/move-arg-2-unique.rs index d44c83763b7c..77f763888eae 100644 --- a/tests/run-pass/move-arg-2-unique.rs +++ b/tests/run-pass/move-arg-2-unique.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(unused_features, unused_variables)] #![feature(box_syntax)] fn test(foo: Box> ) { assert_eq!((*foo)[0], 10); } diff --git a/tests/run-pass/move-arg-3-unique.rs b/tests/run-pass/move-arg-3-unique.rs index 2e6320eb8025..0754a3f60d36 100644 --- a/tests/run-pass/move-arg-3-unique.rs +++ b/tests/run-pass/move-arg-3-unique.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(unused_features, unused_variables)] #![feature(box_syntax)] pub fn main() { diff --git a/tests/run-pass/regions-lifetime-nonfree-late-bound.rs b/tests/run-pass/regions-lifetime-nonfree-late-bound.rs index 96f1217a254e..dfdf89c9c1cd 100644 --- a/tests/run-pass/regions-lifetime-nonfree-late-bound.rs +++ b/tests/run-pass/regions-lifetime-nonfree-late-bound.rs @@ -22,7 +22,6 @@ // doing region-folding, when really all clients of the region-folding // case only want to see FREE lifetime variables, not bound ones. -#![allow(unused_features)] #![feature(box_syntax)] pub fn main() { From 91f0b28ecc780f291ed716c9126719b0f3110f92 Mon Sep 17 00:00:00 2001 From: Wim Looman Date: Fri, 30 Nov 2018 17:05:37 +0100 Subject: [PATCH 0448/5092] Skip testing targets that don't ship libstd --- tests/compiletest.rs | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 7aa55ef66340..859890aba9f2 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -124,16 +124,33 @@ fn is_target_dir>(path: P) -> bool { path.metadata().map(|m| m.is_dir()).unwrap_or(false) } -fn for_all_targets(sysroot: &Path, mut f: F) { +fn target_has_std>(path: P) -> bool { + let mut path = path.into(); + path.push("lib"); + std::fs::read_dir(path) + .expect("invalid target") + .map(|entry| entry.unwrap()) + .filter(|entry| entry.file_type().unwrap().is_file()) + .filter_map(|entry| entry.file_name().into_string().ok()) + .any(|file_name| file_name.starts_with("libstd") && file_name.ends_with(".rlib")) +} + + +fn for_all_targets(sysroot: &Path, f: F) { let target_dir = sysroot.join("lib").join("rustlib"); - for entry in std::fs::read_dir(target_dir).expect("invalid sysroot") { - let entry = entry.unwrap(); - if !is_target_dir(entry.path()) { - continue; - } - let target = entry.file_name().into_string().unwrap(); - f(target); + let mut targets = std::fs::read_dir(target_dir) + .expect("invalid sysroot") + .map(|entry| entry.unwrap()) + .filter(|entry| is_target_dir(entry.path())) + .filter(|entry| target_has_std(entry.path())) + .map(|entry| entry.file_name().into_string().unwrap()) + .peekable(); + + if targets.peek().is_none() { + panic!("No valid targets found"); } + + targets.for_each(f); } fn get_sysroot() -> PathBuf { From 479eb3bd2b538c9108880d1b6cafef648a2c8b12 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Nov 2018 09:33:33 +0100 Subject: [PATCH 0449/5092] support for basic (non-overlapping) 2-phase borrows --- src/lib.rs | 3 +- src/stacked_borrows.rs | 33 ++++++++++++------- tests/run-pass/2phase.rs | 69 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+), 12 deletions(-) create mode 100644 tests/run-pass/2phase.rs diff --git a/src/lib.rs b/src/lib.rs index 9739a7a95b6d..165b15290031 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -525,6 +525,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn retag( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, fn_entry: bool, + two_phase: bool, place: PlaceTy<'tcx, Borrow>, ) -> EvalResult<'tcx> { if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !Self::enforce_validity(ecx) { @@ -535,7 +536,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { // uninitialized data. Ok(()) } else { - ecx.retag(fn_entry, place) + ecx.retag(fn_entry, two_phase, place) } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 31f80fe2f6c6..3ea434f00f79 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -8,7 +8,7 @@ use rustc::hir::{Mutability, MutMutable, MutImmutable}; use crate::{ EvalResult, EvalErrorKind, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, MemoryKind, MiriMemoryKind, RangeMap, AllocId, Allocation, AllocationExtra, - Pointer, MemPlace, Scalar, Immediate, ImmTy, PlaceTy, MPlaceTy, + Pointer, Immediate, ImmTy, PlaceTy, MPlaceTy, }; pub type Timestamp = u64; @@ -534,7 +534,7 @@ pub trait EvalContextExt<'tcx> { size: Size, fn_barrier: bool, new_bor: Borrow - ) -> EvalResult<'tcx, Pointer>; + ) -> EvalResult<'tcx>; /// Retag an indidual pointer, returning the retagged version. fn retag_reference( @@ -542,11 +542,13 @@ pub trait EvalContextExt<'tcx> { ptr: ImmTy<'tcx, Borrow>, mutbl: Mutability, fn_barrier: bool, + two_phase: bool, ) -> EvalResult<'tcx, Immediate>; fn retag( &mut self, fn_entry: bool, + two_phase: bool, place: PlaceTy<'tcx, Borrow> ) -> EvalResult<'tcx>; @@ -644,9 +646,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { size: Size, fn_barrier: bool, new_bor: Borrow - ) -> EvalResult<'tcx, Pointer> { + ) -> EvalResult<'tcx> { let ptr = place.ptr.to_ptr()?; - let new_ptr = Pointer::new_with_tag(ptr.alloc_id, ptr.offset, new_bor); let barrier = if fn_barrier { Some(self.frame().extra) } else { None }; trace!("reborrow: Creating new reference for {:?} (pointee {}): {:?}", ptr, place.layout.ty, new_bor); @@ -666,7 +667,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { let kind = if new_bor.is_unique() { RefKind::Unique } else { RefKind::Raw }; alloc.extra.reborrow(ptr, size, barrier, new_bor, kind)?; } - Ok(new_ptr) + Ok(()) } fn retag_reference( @@ -674,6 +675,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { val: ImmTy<'tcx, Borrow>, mutbl: Mutability, fn_barrier: bool, + two_phase: bool, ) -> EvalResult<'tcx, Immediate> { // We want a place for where the ptr *points to*, so we get one. let place = self.ref_to_mplace(val)?; @@ -693,16 +695,24 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { }; // Reborrow. - let new_ptr = self.reborrow(place, size, fn_barrier, new_bor)?; + self.reborrow(place, size, fn_barrier, new_bor)?; + let new_place = place.with_tag(new_bor); + // Handle two-phase borrows. + if two_phase { + // We immediately share it, to allow read accesses + let two_phase_time = self.machine.stacked_borrows.increment_clock(); + let two_phase_bor = Borrow::Shr(Some(two_phase_time)); + self.reborrow(new_place, size, /*fn_barrier*/false, two_phase_bor)?; + } - // Return new ptr - let new_place = MemPlace { ptr: Scalar::Ptr(new_ptr), ..*place }; + // Return new ptr. Ok(new_place.to_ref()) } fn retag( &mut self, fn_entry: bool, + two_phase: bool, place: PlaceTy<'tcx, Borrow> ) -> EvalResult<'tcx> { // Determine mutability and whether to add a barrier. @@ -725,19 +735,20 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { if let Some((mutbl, barrier)) = qualify(place.layout.ty, fn_entry) { // fast path let val = self.read_immediate(self.place_to_op(place)?)?; - let val = self.retag_reference(val, mutbl, barrier)?; + let val = self.retag_reference(val, mutbl, barrier, two_phase)?; self.write_immediate(val, place)?; return Ok(()); } let place = self.force_allocation(place)?; - let mut visitor = RetagVisitor { ecx: self, fn_entry }; + let mut visitor = RetagVisitor { ecx: self, fn_entry, two_phase }; visitor.visit_value(place)?; // The actual visitor struct RetagVisitor<'ecx, 'a, 'mir, 'tcx> { ecx: &'ecx mut MiriEvalContext<'a, 'mir, 'tcx>, fn_entry: bool, + two_phase: bool, } impl<'ecx, 'a, 'mir, 'tcx> MutValueVisitor<'a, 'mir, 'tcx, Evaluator<'tcx>> @@ -758,7 +769,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { // making it useless. if let Some((mutbl, barrier)) = qualify(place.layout.ty, self.fn_entry) { let val = self.ecx.read_immediate(place.into())?; - let val = self.ecx.retag_reference(val, mutbl, barrier)?; + let val = self.ecx.retag_reference(val, mutbl, barrier, self.two_phase)?; self.ecx.write_immediate(val, place.into())?; } Ok(()) diff --git a/tests/run-pass/2phase.rs b/tests/run-pass/2phase.rs new file mode 100644 index 000000000000..0b2a7d53c855 --- /dev/null +++ b/tests/run-pass/2phase.rs @@ -0,0 +1,69 @@ +#![feature(nll)] + +trait S: Sized { + fn tpb(&mut self, _s: Self) {} +} + +impl S for i32 {} + +fn two_phase1() { + let mut x = 3; + x.tpb(x); +} + +fn two_phase2() { + let mut v = vec![]; + v.push(v.len()); +} + +/* +fn two_phase_overlapping1() { + let mut x = vec![]; + let p = &x; + x.push(p.len()); +} + +fn two_phase_overlapping2() { + use std::ops::AddAssign; + let mut x = 1; + let l = &x; + x.add_assign(x + *l); +} +*/ + +fn match_two_phase() { + let mut x = 3; + match x { + ref mut y if { let _val = x; let _val = *y; true } => {}, + _ => (), + } +} + +fn with_interior_mutability() { + use std::cell::Cell; + + trait Thing: Sized { + fn do_the_thing(&mut self, _s: i32) {} + } + + impl Thing for Cell {} + + let mut x = Cell::new(1); + let l = &x; + x + .do_the_thing({ + x.set(3); + l.set(4); + x.get() + l.get() + }) + ; +} + +fn main() { + two_phase1(); + two_phase2(); + //two_phase_overlapping1(); + //two_phase_overlapping2(); + match_two_phase(); + with_interior_mutability(); +} From b2305da8d0f4932cad3cea444d598a6e4054f804 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Nov 2018 10:35:10 +0100 Subject: [PATCH 0450/5092] assert some sense --- src/stacked_borrows.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 3ea434f00f79..1c8224ef1784 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -699,6 +699,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { let new_place = place.with_tag(new_bor); // Handle two-phase borrows. if two_phase { + assert!(mutbl == MutMutable, "two-phase shared borrows make no sense"); // We immediately share it, to allow read accesses let two_phase_time = self.machine.stacked_borrows.increment_clock(); let two_phase_bor = Borrow::Shr(Some(two_phase_time)); From e12d4bc70c018e366e0ac896f60b456019e63986 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 2 Dec 2018 14:03:29 +0100 Subject: [PATCH 0451/5092] build libstd with minimal features --- src/bin/cargo-miri.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 4c83c5bd3dc0..2dc6eee5de9d 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -155,6 +155,9 @@ fn setup(ask_user: bool) { File::create(dir.join("Xargo.toml")).unwrap() .write_all(br#" [dependencies.std] +default_features = false +# We need the `panic_unwind` feature because we use the `unwind` panic strategy. +# Using `abort` works for libstd, but then libtest will not compile. features = ["panic_unwind"] [dependencies.test] From 6df89de68a21f538173fa833f5965ac4d5da7f23 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 2 Dec 2018 17:18:25 +0100 Subject: [PATCH 0452/5092] we don't need no whitelist --- src/lib.rs | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 9739a7a95b6d..ec4e621a24a9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -310,26 +310,9 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { const STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); + #[inline(always)] fn enforce_validity(ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool { - if !ecx.machine.validate { - return false; - } - - // Some functions are whitelisted until we figure out how to fix them. - // We walk up the stack a few frames to also cover their callees. - const WHITELIST: &[(&str, &str)] = &[ - // Uses mem::uninitialized - ("std::sys::windows::mutex::Mutex::", ""), - ]; - for frame in ecx.stack().iter() - .rev().take(3) - { - let name = frame.instance.to_string(); - if WHITELIST.iter().any(|(prefix, suffix)| name.starts_with(prefix) && name.ends_with(suffix)) { - return false; - } - } - true + ecx.machine.validate } /// Returns Ok() when the function was handled, fail otherwise From 0e44876a2d37dda4dc57a6eb20588654e5e92562 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 22 Nov 2018 16:26:06 +0100 Subject: [PATCH 0453/5092] fix mutability gap: do not allow shared mutation when creating frozen reference --- src/stacked_borrows.rs | 37 +++++++++++-------- .../stacked_borrows/illegal_write3.rs | 4 +- .../stacked_borrows/pass_invalid_shr.rs | 2 +- .../stacked_borrows/shr_frozen_violation1.rs | 16 ++++++++ tests/run-pass/refcell.rs | 23 ++++++++++++ tests/run-pass/stacked-borrows.rs | 31 +++++++++------- 6 files changed, 82 insertions(+), 31 deletions(-) create mode 100644 tests/compile-fail-fullmir/stacked_borrows/shr_frozen_violation1.rs diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 31f80fe2f6c6..a90be317705a 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -303,14 +303,30 @@ impl<'tcx> Stack { /// is met: We cannot push `Uniq` onto frozen stacks. /// `kind` indicates which kind of reference is being created. fn create(&mut self, bor: Borrow, kind: RefKind) { - if self.frozen_since.is_some() { - // A frozen location? Possible if we create a barrier, then push again. - assert!(bor.is_shared(), "We should never try creating a unique borrow for a frozen stack"); - trace!("create: Not doing anything on frozen location"); + // When creating a frozen reference, freeze. This ensures F1. + // We also do *not* push anything else to the stack, making sure that no nother kind + // of access (like writing through raw pointers) is permitted. + if kind == RefKind::Frozen { + let bor_t = match bor { + Borrow::Shr(Some(t)) => t, + _ => bug!("Creating illegal borrow {:?} for frozen ref", bor), + }; + // It is possible that we already are frozen (e.g. if we just pushed a barrier, + // the redundancy check would not have kicked in). + match self.frozen_since { + Some(loc_t) => assert!(loc_t <= bor_t, "Trying to freeze location for longer than it was already frozen"), + None => { + trace!("create: Freezing"); + self.frozen_since = Some(bor_t); + } + } return; } - // First, push. We do this even if we will later freeze, because we - // will allow mutation of shared data at the expense of unfreezing. + if self.frozen_since.is_some() { + bug!("Trying to create non-frozen reference to frozen location"); + } + + // Push new item to the stack. let itm = match bor { Borrow::Uniq(t) => BorStackItem::Uniq(t), Borrow::Shr(_) => BorStackItem::Shr, @@ -325,15 +341,6 @@ impl<'tcx> Stack { trace!("create: Pushing {:?}", itm); self.borrows.push(itm); } - // Then, maybe freeze. This is part 2 of ensuring F1. - if kind == RefKind::Frozen { - let bor_t = match bor { - Borrow::Shr(Some(t)) => t, - _ => bug!("Creating illegal borrow {:?} for frozen ref", bor), - }; - trace!("create: Freezing"); - self.frozen_since = Some(bor_t); - } } /// Add a barrier diff --git a/tests/compile-fail-fullmir/stacked_borrows/illegal_write3.rs b/tests/compile-fail-fullmir/stacked_borrows/illegal_write3.rs index 01559af21e7c..a653aa5003f6 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/illegal_write3.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/illegal_write3.rs @@ -3,6 +3,6 @@ fn main() { // Make sure raw ptr with raw tag cannot mutate frozen location without breaking the shared ref. let r#ref = ⌖ // freeze let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag - unsafe { *ptr = 42; } - let _val = *r#ref; //~ ERROR is not frozen + unsafe { *ptr = 42; } //~ ERROR does not exist on the stack + let _val = *r#ref; } diff --git a/tests/compile-fail-fullmir/stacked_borrows/pass_invalid_shr.rs b/tests/compile-fail-fullmir/stacked_borrows/pass_invalid_shr.rs index 67bbc88e40fb..22a80e27103e 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/pass_invalid_shr.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/pass_invalid_shr.rs @@ -3,7 +3,7 @@ fn foo(_: &i32) {} fn main() { let x = &mut 42; - let xraw = &*x as *const _ as *mut _; + let xraw = x as *mut _; let xref = unsafe { &*xraw }; unsafe { *xraw = 42 }; // unfreeze foo(xref); //~ ERROR is not frozen diff --git a/tests/compile-fail-fullmir/stacked_borrows/shr_frozen_violation1.rs b/tests/compile-fail-fullmir/stacked_borrows/shr_frozen_violation1.rs new file mode 100644 index 000000000000..560c9dfb665d --- /dev/null +++ b/tests/compile-fail-fullmir/stacked_borrows/shr_frozen_violation1.rs @@ -0,0 +1,16 @@ +fn foo(x: &mut i32) -> i32 { + *x = 5; + unknown_code(&*x); + *x // must return 5 +} + +fn main() { + println!("{}", foo(&mut 0)); +} + +// If we replace the `*const` by `&`, my current dev version of miri +// *does* find the problem, but not for a good reason: It finds it because +// of barriers, and we shouldn't rely on unknown code using barriers. +fn unknown_code(x: *const i32) { + unsafe { *(x as *mut i32) = 7; } //~ ERROR barrier +} diff --git a/tests/run-pass/refcell.rs b/tests/run-pass/refcell.rs index 5f2f3523b96b..0bc8b15c5f24 100644 --- a/tests/run-pass/refcell.rs +++ b/tests/run-pass/refcell.rs @@ -39,6 +39,13 @@ fn aliasing_mut_and_shr() { *aliasing += 4; let _shr = &*rc; *aliasing += 4; + // also turning this into a frozen ref now must work + let aliasing = &*aliasing; + let _val = *aliasing; + let _escape_to_raw = rc as *const _; // this must NOT unfreeze + let _val = *aliasing; + let _shr = &*rc; // this must NOT unfreeze + let _val = *aliasing; } let rc = RefCell::new(23); @@ -48,7 +55,23 @@ fn aliasing_mut_and_shr() { assert_eq!(*rc.borrow(), 23+12); } +fn aliasing_frz_and_shr() { + fn inner(rc: &RefCell, aliasing: &i32) { + let _val = *aliasing; + let _escape_to_raw = rc as *const _; // this must NOT unfreeze + let _val = *aliasing; + let _shr = &*rc; // this must NOT unfreeze + let _val = *aliasing; + } + + let rc = RefCell::new(23); + let bshr = rc.borrow(); + inner(&rc, &*bshr); + assert_eq!(*rc.borrow(), 23); +} + fn main() { lots_of_funny_borrows(); aliasing_mut_and_shr(); + aliasing_frz_and_shr(); } diff --git a/tests/run-pass/stacked-borrows.rs b/tests/run-pass/stacked-borrows.rs index 93bdf5ffbf32..388765c29eab 100644 --- a/tests/run-pass/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows.rs @@ -4,10 +4,11 @@ fn main() { read_does_not_invalidate1(); read_does_not_invalidate2(); ref_raw_int_raw(); - mut_shr_raw(); mut_raw_then_mut_shr(); + mut_shr_then_mut_raw(); mut_raw_mut(); partially_invalidate_mut(); + drop_after_sharing(); } // Deref a raw ptr to access a field of a large struct, where the field @@ -53,18 +54,6 @@ fn ref_raw_int_raw() { assert_eq!(unsafe { *xraw }, 3); } -// Creating a raw from a `&mut` through an `&` works, even if we -// write through that raw. -fn mut_shr_raw() { - let mut x = 2; - { - let xref = &mut x; - let xraw = &*xref as *const i32 as *mut i32; - unsafe { *xraw = 4; } - } - assert_eq!(x, 4); -} - // Escape a mut to raw, then share the same mut and use the share, then the raw. // That should work. fn mut_raw_then_mut_shr() { @@ -77,6 +66,16 @@ fn mut_raw_then_mut_shr() { assert_eq!(x, 4); } +// Create first a shared reference and then a raw pointer from a `&mut` +// should permit mutation through that raw pointer. +fn mut_shr_then_mut_raw() { + let xref = &mut 2; + let _xshr = &*xref; + let xraw = xref as *mut _; + unsafe { *xraw = 3; } + assert_eq!(*xref, 3); +} + // Ensure that if we derive from a mut a raw, and then from that a mut, // and then read through the original mut, that does not invalidate the raw. // This shows that the read-exception for `&mut` applies even if the `Shr` item @@ -107,3 +106,9 @@ fn partially_invalidate_mut() { *shard += 1; // so we can still use `shard`. assert_eq!(*data, (1, 1)); } + +// Make sure that we can handle the situation where a loaction is frozen when being dropped. +fn drop_after_sharing() { + let x = String::from("hello!"); + let _len = x.len(); +} From 9d0c1dd676ee542af15bff3c4cd34c5c8cacaad0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 2 Dec 2018 23:24:08 +0100 Subject: [PATCH 0454/5092] disable VecDeque test until the fix lands in rustc --- tests/run-pass-fullmir/vecdeque.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/run-pass-fullmir/vecdeque.rs b/tests/run-pass-fullmir/vecdeque.rs index 381169505ec9..d92cff0b084e 100644 --- a/tests/run-pass-fullmir/vecdeque.rs +++ b/tests/run-pass-fullmir/vecdeque.rs @@ -1,3 +1,6 @@ +// FIXME: Validation disabled until https://github.com/rust-lang/rust/pull/56161 lands +// compile-flags: -Zmiri-disable-validation + use std::collections::VecDeque; fn main() { From 04057432c1045564bf8b917cacde931df4894d41 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 3 Dec 2018 09:15:00 +0100 Subject: [PATCH 0455/5092] bump nightly --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 6fd720c5c785..087b7c664272 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-30 +nightly-2018-12-03 From d11a6766ad388c97e3a95b26a9350ff4ddefd004 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 3 Dec 2018 10:26:39 +0100 Subject: [PATCH 0456/5092] use assert --- src/stacked_borrows.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index a90be317705a..41b5cc2a239d 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -322,9 +322,7 @@ impl<'tcx> Stack { } return; } - if self.frozen_since.is_some() { - bug!("Trying to create non-frozen reference to frozen location"); - } + assert!(self.frozen_since.is_none(), "Trying to create non-frozen reference to frozen location"); // Push new item to the stack. let itm = match bor { From b6e5822601beb443faed97d7d7333ba543ea119d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 3 Dec 2018 10:28:32 +0100 Subject: [PATCH 0457/5092] add FIXME --- tests/run-pass/2phase.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/2phase.rs b/tests/run-pass/2phase.rs index 0b2a7d53c855..5b9e5d3ea5ff 100644 --- a/tests/run-pass/2phase.rs +++ b/tests/run-pass/2phase.rs @@ -62,8 +62,9 @@ fn with_interior_mutability() { fn main() { two_phase1(); two_phase2(); - //two_phase_overlapping1(); - //two_phase_overlapping2(); match_two_phase(); with_interior_mutability(); + //FIXME: enable these, or remove them, depending on how https://github.com/rust-lang/rust/issues/56254 gets resolved + //two_phase_overlapping1(); + //two_phase_overlapping2(); } From bbdc3380d57fafbe66d2f6422df35d542331555f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 7 Dec 2018 10:15:25 +0100 Subject: [PATCH 0458/5092] fix tests --- tests/compile-fail/validity/nonzero.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile-fail/validity/nonzero.rs b/tests/compile-fail/validity/nonzero.rs index d1de0f8095e3..f820b0e810b8 100644 --- a/tests/compile-fail/validity/nonzero.rs +++ b/tests/compile-fail/validity/nonzero.rs @@ -7,5 +7,5 @@ pub(crate) struct NonZero(pub(crate) T); fn main() { // Make sure that we detect this even when no function call is happening along the way - let _x = Some(NonZero(0)); //~ ERROR encountered 0, but expected something greater or equal to 1 + let _x = Some(unsafe { NonZero(0) }); //~ ERROR encountered 0, but expected something greater or equal to 1 } From d5d1b1e4f3df26b70c77b9c21437db2127b8e2b8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 7 Dec 2018 18:01:23 +0100 Subject: [PATCH 0459/5092] add FIXME test for coercing &mut to *const --- tests/run-pass/stacked-borrows.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/run-pass/stacked-borrows.rs b/tests/run-pass/stacked-borrows.rs index 388765c29eab..223c69a9a3ad 100644 --- a/tests/run-pass/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows.rs @@ -9,6 +9,7 @@ fn main() { mut_raw_mut(); partially_invalidate_mut(); drop_after_sharing(); + direct_mut_to_const_raw(); } // Deref a raw ptr to access a field of a large struct, where the field @@ -112,3 +113,13 @@ fn drop_after_sharing() { let x = String::from("hello!"); let _len = x.len(); } + +// Make sure that coercing &mut T to *const T produces a writeable pointer. +fn direct_mut_to_const_raw() { + // FIXME: This is currently disabled, waiting on a fix for + /*let x = &mut 0; + let y: *const i32 = x; + unsafe { *(y as *mut i32) = 1; } + assert_eq!(*x, 1); + */ +} From f06e25f9b201dafe5f402e116b0ab7ec16727093 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 8 Dec 2018 10:33:29 +0100 Subject: [PATCH 0460/5092] bump Rust version, fix build --- rust-version | 2 +- src/bin/miri-rustc-tests.rs | 4 ++-- src/bin/miri.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 087b7c664272..69d072f1bfa0 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-12-03 +nightly-2018-12-08 diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 6fa9b817ffee..92d4237146dc 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -93,7 +93,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.node { if i.attrs.iter().any(|attr| attr.name() == "test") { - let did = self.0.hir.body_owner_def_id(body_id); + let did = self.0.hir().body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); miri::eval_main(self.0, did, /*validate*/true); self.1.session.abort_if_errors(); @@ -105,7 +105,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { } state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(tcx, state)); } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { - let entry_def_id = tcx.hir.local_def_id(entry_node_id); + let entry_def_id = tcx.hir().local_def_id(entry_node_id); miri::eval_main(tcx, entry_def_id, /*validate*/true); state.session.abort_if_errors(); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 1bbf3c8c4a4a..e88c13305d15 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -128,7 +128,7 @@ fn after_analysis<'a, 'tcx>( attr.name() == "test" }) { - let did = self.tcx.hir.body_owner_def_id(body_id); + let did = self.tcx.hir().body_owner_def_id(body_id); println!( "running test: {}", self.tcx.def_path_debug_str(did), @@ -145,7 +145,7 @@ fn after_analysis<'a, 'tcx>( &mut Visitor { tcx, state, validate } ); } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { - let entry_def_id = tcx.hir.local_def_id(entry_node_id); + let entry_def_id = tcx.hir().local_def_id(entry_node_id); miri::eval_main(tcx, entry_def_id, validate); state.session.abort_if_errors(); From 8d1e1179a17bc2aba017a5a16f0b42772032e00d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 8 Dec 2018 10:47:50 +0100 Subject: [PATCH 0461/5092] fix benches --- benches/helpers/miri_helper.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 015e36c4f5ad..c7df34eaf706 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -47,7 +47,7 @@ pub fn run(filename: &str, bencher: &mut Bencher) { let (entry_node_id, _, _) = state.session.entry_fn.borrow().expect( "no main or start function found", ); - let entry_def_id = tcx.hir.local_def_id(entry_node_id); + let entry_def_id = tcx.hir().local_def_id(entry_node_id); bencher.borrow_mut().iter(|| { eval_main(tcx, entry_def_id, false); From c84c1527e2d486437efa5e3851a2b4b421c99133 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 10 Dec 2018 09:23:27 +0100 Subject: [PATCH 0462/5092] factor grabbing of cargo options into separate function and make it better --- src/bin/cargo-miri.rs | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 2dc6eee5de9d..436b6a9430bf 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -53,14 +53,32 @@ fn show_error(msg: String) -> ! { std::process::exit(1) } -fn list_targets(mut args: impl Iterator) -> impl Iterator { +fn get_arg_flag_value(name: &str) -> Option { + // stop searching at `--` + let mut args = std::env::args().skip_while(|val| !(val.starts_with(name) || val == "--")); + + match args.next() { + Some(ref p) if p == "--" => None, + Some(ref p) if p == name => args.next(), + Some(p) => { + // Make sure this really starts with `$name=`, we didn't test for the `=` yet. + let v = &p[name.len()..]; // strip leading `$name` + if v.starts_with('=') { + Some(v[1..].to_owned()) // strip leading `=` + } else { + None + } + }, + None => None, + } +} + +fn list_targets() -> impl Iterator { // We need to get the manifest, and then the metadata, to enumerate targets. - let manifest_path_arg = args.find(|val| { - val.starts_with("--manifest-path=") - }); + let manifest_path = get_arg_flag_value("--manifest-path").map(PathBuf::from); let mut metadata = if let Ok(metadata) = cargo_metadata::metadata( - manifest_path_arg.as_ref().map(AsRef::as_ref), + manifest_path.as_ref().map(AsRef::as_ref), ) { metadata @@ -68,10 +86,6 @@ fn list_targets(mut args: impl Iterator) -> impl Iterator Date: Mon, 10 Dec 2018 09:32:54 +0100 Subject: [PATCH 0463/5092] cargo miri: support foreign targets --- Cargo.toml | 3 ++- src/bin/cargo-miri.rs | 21 ++++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index becb5c69e561..ca670df0f203 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,7 @@ required-features = ["rustc_tests"] byteorder = { version = "1.1", features = ["i128"]} cargo_metadata = { version = "0.6", optional = true } directories = { version = "1.0", optional = true } +rustc_version = { version = "0.2.3", optional = true } env_logger = "0.5" log = "0.4" @@ -44,7 +45,7 @@ vergen = "3" [features] default = ["cargo_miri"] -cargo_miri = ["cargo_metadata", "directories"] +cargo_miri = ["cargo_metadata", "directories", "rustc_version"] rustc_tests = [] [dev-dependencies] diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 436b6a9430bf..68da028a81c6 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -190,17 +190,28 @@ path = "lib.rs" "#).unwrap(); File::create(dir.join("lib.rs")).unwrap(); // Run xargo - if !Command::new("xargo").arg("build").arg("-q") + let target = get_arg_flag_value("--target"); + let mut command = Command::new("xargo"); + command.arg("build").arg("-q") .current_dir(&dir) .env("RUSTFLAGS", miri::miri_default_args().join(" ")) - .env("XARGO_HOME", dir.to_str().unwrap()) - .status().unwrap().success() + .env("XARGO_HOME", dir.to_str().unwrap()); + if let Some(ref target) = target { + command.arg("--target").arg(&target); + } + if !command.status().unwrap().success() { show_error(format!("Failed to run xargo")); } - // That should be it! - let sysroot = dir.join("HOST"); + // That should be it! But we need to figure out where xargo built stuff. + // Unfortunately, it puts things into a different directory when the + // architecture matches the host. + let is_host = match target { + None => true, + Some(target) => target == rustc_version::version_meta().unwrap().host, + }; + let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; std::env::set_var("MIRI_SYSROOT", &sysroot); if !ask_user { println!("A libstd for miri is now available in `{}`", sysroot.display()); From f044205b5fab8b48a583f613f995519d6895e8ea Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 10 Dec 2018 10:04:55 +0100 Subject: [PATCH 0464/5092] the test suite assumes a libstd with full MIR; run test suite on xargo-built foreign libstds --- .travis.yml | 29 ++++++------- .../.gitignore | 0 .../Cargo.lock | 0 .../Cargo.toml | 0 .../run-test.py | 0 .../src/main.rs | 0 .../stderr.ref | 0 .../stdout.ref | 0 .../tests/foo.rs | 0 .../copy_nonoverlapping.rs | 0 .../deallocate-bad-alignment.rs | 0 .../deallocate-bad-size.rs | 0 .../deallocate-twice.rs | 0 .../memleak_rc.rs | 0 .../out_of_bounds_ptr_1.rs | 0 .../out_of_bounds_ptr_2.rs | 0 .../ptr_offset_overflow.rs | 0 .../reallocate-bad-size.rs | 0 .../reallocate-change-alloc.rs | 0 .../reallocate-dangling.rs | 0 .../stack_free.rs | 0 .../stacked_borrows/alias_through_mutation.rs | 0 .../stacked_borrows/aliasing_mut1.rs | 0 .../stacked_borrows/aliasing_mut2.rs | 0 .../stacked_borrows/aliasing_mut3.rs | 0 .../stacked_borrows/aliasing_mut4.rs | 0 .../box_exclusive_violation1.rs | 0 .../stacked_borrows/buggy_as_mut_slice.rs | 0 .../stacked_borrows/buggy_split_at_mut.rs | 0 .../deallocate_against_barrier.rs | 0 .../stacked_borrows/illegal_read1.rs | 0 .../stacked_borrows/illegal_read2.rs | 0 .../stacked_borrows/illegal_read3.rs | 0 .../stacked_borrows/illegal_read4.rs | 0 .../stacked_borrows/illegal_read5.rs | 0 .../stacked_borrows/illegal_write1.rs | 0 .../stacked_borrows/illegal_write2.rs | 0 .../stacked_borrows/illegal_write3.rs | 0 .../stacked_borrows/illegal_write4.rs | 0 .../stacked_borrows/illegal_write5.rs | 0 .../invalidate_against_barrier1.rs | 0 .../invalidate_against_barrier2.rs | 0 .../stacked_borrows/load_invalid_mut.rs | 0 .../stacked_borrows/load_invalid_shr.rs | 0 .../mut_exclusive_violation1.rs | 0 .../stacked_borrows/outdated_local.rs | 0 .../stacked_borrows/pass_invalid_mut.rs | 0 .../stacked_borrows/pass_invalid_shr.rs | 0 .../stacked_borrows/pointer_smuggling.rs | 0 .../stacked_borrows/return_invalid_mut.rs | 0 .../return_invalid_mut_option.rs | 0 .../return_invalid_mut_tuple.rs | 0 .../stacked_borrows/return_invalid_shr.rs | 0 .../return_invalid_shr_option.rs | 0 .../return_invalid_shr_tuple.rs | 0 .../stacked_borrows/shr_frozen_violation1.rs | 0 .../static_memory_modification.rs | 0 .../stacked_borrows/transmute-is-no-escape.rs | 0 .../stacked_borrows/unescaped_local.rs | 0 .../transmute-pair-undef.rs | 0 tests/compiletest.rs | 43 ++++--------------- .../async-fn.rs | 0 .../box-pair-to-vec.rs | 0 .../box-pair-to-vec.stdout | 0 tests/{run-pass-fullmir => run-pass}/catch.rs | 0 .../catch.stdout | 0 tests/{run-pass-fullmir => run-pass}/env.rs | 0 .../foreign-fn-linkname.rs | 0 .../{run-pass-fullmir => run-pass}/format.rs | 0 .../format.stdout | 0 .../from_utf8.rs | 0 .../{run-pass-fullmir => run-pass}/hashmap.rs | 0 tests/{run-pass-fullmir => run-pass}/hello.rs | 0 .../hello.stdout | 0 .../integer-ops.rs | 0 .../issue-3794.rs | 0 .../issue-3794.stdout | 0 .../loop-break-value.rs | 0 .../{run-pass-fullmir => run-pass}/memchr.rs | 0 .../send-is-not-static-par-for.rs | 0 .../{run-pass-fullmir => run-pass}/threads.rs | 0 tests/{run-pass-fullmir => run-pass}/u128.rs | 0 .../unsized-tuple-impls.rs | 0 .../vecdeque.rs | 0 84 files changed, 22 insertions(+), 50 deletions(-) rename {cargo-miri-test => test-cargo-miri}/.gitignore (100%) rename {cargo-miri-test => test-cargo-miri}/Cargo.lock (100%) rename {cargo-miri-test => test-cargo-miri}/Cargo.toml (100%) rename {cargo-miri-test => test-cargo-miri}/run-test.py (100%) rename {cargo-miri-test => test-cargo-miri}/src/main.rs (100%) rename {cargo-miri-test => test-cargo-miri}/stderr.ref (100%) rename {cargo-miri-test => test-cargo-miri}/stdout.ref (100%) rename {cargo-miri-test => test-cargo-miri}/tests/foo.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/copy_nonoverlapping.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/deallocate-bad-alignment.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/deallocate-bad-size.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/deallocate-twice.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/memleak_rc.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/out_of_bounds_ptr_1.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/out_of_bounds_ptr_2.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/ptr_offset_overflow.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/reallocate-bad-size.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/reallocate-change-alloc.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/reallocate-dangling.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stack_free.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/alias_through_mutation.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/aliasing_mut1.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/aliasing_mut2.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/aliasing_mut3.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/aliasing_mut4.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/box_exclusive_violation1.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/buggy_as_mut_slice.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/buggy_split_at_mut.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/deallocate_against_barrier.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/illegal_read1.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/illegal_read2.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/illegal_read3.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/illegal_read4.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/illegal_read5.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/illegal_write1.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/illegal_write2.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/illegal_write3.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/illegal_write4.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/illegal_write5.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/invalidate_against_barrier1.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/invalidate_against_barrier2.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/load_invalid_mut.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/load_invalid_shr.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/mut_exclusive_violation1.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/outdated_local.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/pass_invalid_mut.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/pass_invalid_shr.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/pointer_smuggling.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/return_invalid_mut.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/return_invalid_mut_option.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/return_invalid_mut_tuple.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/return_invalid_shr.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/return_invalid_shr_option.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/return_invalid_shr_tuple.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/shr_frozen_violation1.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/static_memory_modification.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/transmute-is-no-escape.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/unescaped_local.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/transmute-pair-undef.rs (100%) rename tests/{run-pass-fullmir => run-pass}/async-fn.rs (100%) rename tests/{run-pass-fullmir => run-pass}/box-pair-to-vec.rs (100%) rename tests/{run-pass-fullmir => run-pass}/box-pair-to-vec.stdout (100%) rename tests/{run-pass-fullmir => run-pass}/catch.rs (100%) rename tests/{run-pass-fullmir => run-pass}/catch.stdout (100%) rename tests/{run-pass-fullmir => run-pass}/env.rs (100%) rename tests/{run-pass-fullmir => run-pass}/foreign-fn-linkname.rs (100%) rename tests/{run-pass-fullmir => run-pass}/format.rs (100%) rename tests/{run-pass-fullmir => run-pass}/format.stdout (100%) rename tests/{run-pass-fullmir => run-pass}/from_utf8.rs (100%) rename tests/{run-pass-fullmir => run-pass}/hashmap.rs (100%) rename tests/{run-pass-fullmir => run-pass}/hello.rs (100%) rename tests/{run-pass-fullmir => run-pass}/hello.stdout (100%) rename tests/{run-pass-fullmir => run-pass}/integer-ops.rs (100%) rename tests/{run-pass-fullmir => run-pass}/issue-3794.rs (100%) rename tests/{run-pass-fullmir => run-pass}/issue-3794.stdout (100%) rename tests/{run-pass-fullmir => run-pass}/loop-break-value.rs (100%) rename tests/{run-pass-fullmir => run-pass}/memchr.rs (100%) rename tests/{run-pass-fullmir => run-pass}/send-is-not-static-par-for.rs (100%) rename tests/{run-pass-fullmir => run-pass}/threads.rs (100%) rename tests/{run-pass-fullmir => run-pass}/u128.rs (100%) rename tests/{run-pass-fullmir => run-pass}/unsized-tuple-impls.rs (100%) rename tests/{run-pass-fullmir => run-pass}/vecdeque.rs (100%) diff --git a/.travis.yml b/.travis.yml index ba3b8d363991..ac3f16ce1353 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,36 +20,35 @@ before_script: else RUST_TOOLCHAIN=$(cat rust-version) fi +- | + if [ "$TRAVIS_OS_NAME" == osx ]; then + export MIRI_SYSROOT_BASE=~/Library/Caches/miri.miri.miri/ + else + export MIRI_SYSROOT_BASE=~/.cache/miri/HOST + fi # install Rust - curl https://build.travis-ci.org/files/rustup-init.sh -sSf | sh -s -- -y --default-toolchain "$RUST_TOOLCHAIN" - export PATH=$HOME/.cargo/bin:$PATH - rustc --version -# customize installation -- rustup target add i686-unknown-linux-gnu -- rustup target add i686-pc-windows-gnu -- rustup target add i686-pc-windows-msvc script: - set -e - | - # Test and install plain miri + # Build and install miri cargo build --release --all-features --all-targets && - cargo test --release --all-features && cargo install --all-features --force --path . - | - # Get ourselves a MIR-full libstd, and use it henceforth + # Get ourselves a MIR-full libstd cargo miri setup && - if [ "$TRAVIS_OS_NAME" == osx ]; then - export MIRI_SYSROOT=~/Library/Caches/miri.miri.miri/HOST - else - export MIRI_SYSROOT=~/.cache/miri/HOST - fi + cargo miri setup --target i686-unknown-linux-gnu && + cargo miri setup --target i686-apple-darwin - | - # Test miri with full MIR - cargo test --release --all-features + # Test miri with full MIR, on the host and other architectures + MIRI_SYSROOT=$MIRI_SYSROOT_BASE/HOST cargo test --release --all-features && + MIRI_SYSROOT=$MIRI_SYSROOT_BASE cargo test --release --all-features - | # Test cargo integration - (cd cargo-miri-test && ./run-test.py) + (cd test-cargo-miri && MIRI_SYSROOT=$MIRI_SYSROOT_BASE/HOST ./run-test.py) notifications: email: diff --git a/cargo-miri-test/.gitignore b/test-cargo-miri/.gitignore similarity index 100% rename from cargo-miri-test/.gitignore rename to test-cargo-miri/.gitignore diff --git a/cargo-miri-test/Cargo.lock b/test-cargo-miri/Cargo.lock similarity index 100% rename from cargo-miri-test/Cargo.lock rename to test-cargo-miri/Cargo.lock diff --git a/cargo-miri-test/Cargo.toml b/test-cargo-miri/Cargo.toml similarity index 100% rename from cargo-miri-test/Cargo.toml rename to test-cargo-miri/Cargo.toml diff --git a/cargo-miri-test/run-test.py b/test-cargo-miri/run-test.py similarity index 100% rename from cargo-miri-test/run-test.py rename to test-cargo-miri/run-test.py diff --git a/cargo-miri-test/src/main.rs b/test-cargo-miri/src/main.rs similarity index 100% rename from cargo-miri-test/src/main.rs rename to test-cargo-miri/src/main.rs diff --git a/cargo-miri-test/stderr.ref b/test-cargo-miri/stderr.ref similarity index 100% rename from cargo-miri-test/stderr.ref rename to test-cargo-miri/stderr.ref diff --git a/cargo-miri-test/stdout.ref b/test-cargo-miri/stdout.ref similarity index 100% rename from cargo-miri-test/stdout.ref rename to test-cargo-miri/stdout.ref diff --git a/cargo-miri-test/tests/foo.rs b/test-cargo-miri/tests/foo.rs similarity index 100% rename from cargo-miri-test/tests/foo.rs rename to test-cargo-miri/tests/foo.rs diff --git a/tests/compile-fail-fullmir/copy_nonoverlapping.rs b/tests/compile-fail/copy_nonoverlapping.rs similarity index 100% rename from tests/compile-fail-fullmir/copy_nonoverlapping.rs rename to tests/compile-fail/copy_nonoverlapping.rs diff --git a/tests/compile-fail-fullmir/deallocate-bad-alignment.rs b/tests/compile-fail/deallocate-bad-alignment.rs similarity index 100% rename from tests/compile-fail-fullmir/deallocate-bad-alignment.rs rename to tests/compile-fail/deallocate-bad-alignment.rs diff --git a/tests/compile-fail-fullmir/deallocate-bad-size.rs b/tests/compile-fail/deallocate-bad-size.rs similarity index 100% rename from tests/compile-fail-fullmir/deallocate-bad-size.rs rename to tests/compile-fail/deallocate-bad-size.rs diff --git a/tests/compile-fail-fullmir/deallocate-twice.rs b/tests/compile-fail/deallocate-twice.rs similarity index 100% rename from tests/compile-fail-fullmir/deallocate-twice.rs rename to tests/compile-fail/deallocate-twice.rs diff --git a/tests/compile-fail-fullmir/memleak_rc.rs b/tests/compile-fail/memleak_rc.rs similarity index 100% rename from tests/compile-fail-fullmir/memleak_rc.rs rename to tests/compile-fail/memleak_rc.rs diff --git a/tests/compile-fail-fullmir/out_of_bounds_ptr_1.rs b/tests/compile-fail/out_of_bounds_ptr_1.rs similarity index 100% rename from tests/compile-fail-fullmir/out_of_bounds_ptr_1.rs rename to tests/compile-fail/out_of_bounds_ptr_1.rs diff --git a/tests/compile-fail-fullmir/out_of_bounds_ptr_2.rs b/tests/compile-fail/out_of_bounds_ptr_2.rs similarity index 100% rename from tests/compile-fail-fullmir/out_of_bounds_ptr_2.rs rename to tests/compile-fail/out_of_bounds_ptr_2.rs diff --git a/tests/compile-fail-fullmir/ptr_offset_overflow.rs b/tests/compile-fail/ptr_offset_overflow.rs similarity index 100% rename from tests/compile-fail-fullmir/ptr_offset_overflow.rs rename to tests/compile-fail/ptr_offset_overflow.rs diff --git a/tests/compile-fail-fullmir/reallocate-bad-size.rs b/tests/compile-fail/reallocate-bad-size.rs similarity index 100% rename from tests/compile-fail-fullmir/reallocate-bad-size.rs rename to tests/compile-fail/reallocate-bad-size.rs diff --git a/tests/compile-fail-fullmir/reallocate-change-alloc.rs b/tests/compile-fail/reallocate-change-alloc.rs similarity index 100% rename from tests/compile-fail-fullmir/reallocate-change-alloc.rs rename to tests/compile-fail/reallocate-change-alloc.rs diff --git a/tests/compile-fail-fullmir/reallocate-dangling.rs b/tests/compile-fail/reallocate-dangling.rs similarity index 100% rename from tests/compile-fail-fullmir/reallocate-dangling.rs rename to tests/compile-fail/reallocate-dangling.rs diff --git a/tests/compile-fail-fullmir/stack_free.rs b/tests/compile-fail/stack_free.rs similarity index 100% rename from tests/compile-fail-fullmir/stack_free.rs rename to tests/compile-fail/stack_free.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/alias_through_mutation.rs b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/alias_through_mutation.rs rename to tests/compile-fail/stacked_borrows/alias_through_mutation.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut1.rs b/tests/compile-fail/stacked_borrows/aliasing_mut1.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/aliasing_mut1.rs rename to tests/compile-fail/stacked_borrows/aliasing_mut1.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut2.rs b/tests/compile-fail/stacked_borrows/aliasing_mut2.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/aliasing_mut2.rs rename to tests/compile-fail/stacked_borrows/aliasing_mut2.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut3.rs b/tests/compile-fail/stacked_borrows/aliasing_mut3.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/aliasing_mut3.rs rename to tests/compile-fail/stacked_borrows/aliasing_mut3.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut4.rs b/tests/compile-fail/stacked_borrows/aliasing_mut4.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/aliasing_mut4.rs rename to tests/compile-fail/stacked_borrows/aliasing_mut4.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs b/tests/compile-fail/stacked_borrows/box_exclusive_violation1.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs rename to tests/compile-fail/stacked_borrows/box_exclusive_violation1.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/buggy_as_mut_slice.rs b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/buggy_as_mut_slice.rs rename to tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/buggy_split_at_mut.rs b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/buggy_split_at_mut.rs rename to tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/deallocate_against_barrier.rs b/tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/deallocate_against_barrier.rs rename to tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/illegal_read1.rs b/tests/compile-fail/stacked_borrows/illegal_read1.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/illegal_read1.rs rename to tests/compile-fail/stacked_borrows/illegal_read1.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/illegal_read2.rs b/tests/compile-fail/stacked_borrows/illegal_read2.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/illegal_read2.rs rename to tests/compile-fail/stacked_borrows/illegal_read2.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/illegal_read3.rs b/tests/compile-fail/stacked_borrows/illegal_read3.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/illegal_read3.rs rename to tests/compile-fail/stacked_borrows/illegal_read3.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/illegal_read4.rs b/tests/compile-fail/stacked_borrows/illegal_read4.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/illegal_read4.rs rename to tests/compile-fail/stacked_borrows/illegal_read4.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/illegal_read5.rs b/tests/compile-fail/stacked_borrows/illegal_read5.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/illegal_read5.rs rename to tests/compile-fail/stacked_borrows/illegal_read5.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/illegal_write1.rs b/tests/compile-fail/stacked_borrows/illegal_write1.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/illegal_write1.rs rename to tests/compile-fail/stacked_borrows/illegal_write1.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/illegal_write2.rs b/tests/compile-fail/stacked_borrows/illegal_write2.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/illegal_write2.rs rename to tests/compile-fail/stacked_borrows/illegal_write2.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/illegal_write3.rs b/tests/compile-fail/stacked_borrows/illegal_write3.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/illegal_write3.rs rename to tests/compile-fail/stacked_borrows/illegal_write3.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/illegal_write4.rs b/tests/compile-fail/stacked_borrows/illegal_write4.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/illegal_write4.rs rename to tests/compile-fail/stacked_borrows/illegal_write4.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/illegal_write5.rs b/tests/compile-fail/stacked_borrows/illegal_write5.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/illegal_write5.rs rename to tests/compile-fail/stacked_borrows/illegal_write5.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/invalidate_against_barrier1.rs b/tests/compile-fail/stacked_borrows/invalidate_against_barrier1.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/invalidate_against_barrier1.rs rename to tests/compile-fail/stacked_borrows/invalidate_against_barrier1.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/invalidate_against_barrier2.rs b/tests/compile-fail/stacked_borrows/invalidate_against_barrier2.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/invalidate_against_barrier2.rs rename to tests/compile-fail/stacked_borrows/invalidate_against_barrier2.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/load_invalid_mut.rs b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/load_invalid_mut.rs rename to tests/compile-fail/stacked_borrows/load_invalid_mut.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/load_invalid_shr.rs b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/load_invalid_shr.rs rename to tests/compile-fail/stacked_borrows/load_invalid_shr.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/mut_exclusive_violation1.rs b/tests/compile-fail/stacked_borrows/mut_exclusive_violation1.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/mut_exclusive_violation1.rs rename to tests/compile-fail/stacked_borrows/mut_exclusive_violation1.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/outdated_local.rs b/tests/compile-fail/stacked_borrows/outdated_local.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/outdated_local.rs rename to tests/compile-fail/stacked_borrows/outdated_local.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/pass_invalid_mut.rs b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/pass_invalid_mut.rs rename to tests/compile-fail/stacked_borrows/pass_invalid_mut.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/pass_invalid_shr.rs b/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/pass_invalid_shr.rs rename to tests/compile-fail/stacked_borrows/pass_invalid_shr.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/pointer_smuggling.rs b/tests/compile-fail/stacked_borrows/pointer_smuggling.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/pointer_smuggling.rs rename to tests/compile-fail/stacked_borrows/pointer_smuggling.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut.rs rename to tests/compile-fail/stacked_borrows/return_invalid_mut.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut_option.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut_option.rs rename to tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut_tuple.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut_tuple.rs rename to tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr.rs b/tests/compile-fail/stacked_borrows/return_invalid_shr.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr.rs rename to tests/compile-fail/stacked_borrows/return_invalid_shr.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr_option.rs b/tests/compile-fail/stacked_borrows/return_invalid_shr_option.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr_option.rs rename to tests/compile-fail/stacked_borrows/return_invalid_shr_option.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr_tuple.rs b/tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr_tuple.rs rename to tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/shr_frozen_violation1.rs b/tests/compile-fail/stacked_borrows/shr_frozen_violation1.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/shr_frozen_violation1.rs rename to tests/compile-fail/stacked_borrows/shr_frozen_violation1.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/static_memory_modification.rs b/tests/compile-fail/stacked_borrows/static_memory_modification.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/static_memory_modification.rs rename to tests/compile-fail/stacked_borrows/static_memory_modification.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/transmute-is-no-escape.rs b/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/transmute-is-no-escape.rs rename to tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/unescaped_local.rs b/tests/compile-fail/stacked_borrows/unescaped_local.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/unescaped_local.rs rename to tests/compile-fail/stacked_borrows/unescaped_local.rs diff --git a/tests/compile-fail-fullmir/transmute-pair-undef.rs b/tests/compile-fail/transmute-pair-undef.rs similarity index 100% rename from tests/compile-fail-fullmir/transmute-pair-undef.rs rename to tests/compile-fail/transmute-pair-undef.rs diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 1c11d07c1bcc..f0ebbf6b071b 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -1,4 +1,5 @@ #![feature(slice_concat_ext, custom_test_frameworks)] +// Custom test runner, to avoid libtest being wrapped around compiletest which wraps libtest. #![test_runner(test_runner)] use std::slice::SliceConcatExt; @@ -24,11 +25,6 @@ fn rustc_lib_path() -> PathBuf { option_env!("RUSTC_LIB_PATH").unwrap().into() } -fn have_fullmir() -> bool { - // We assume we have full MIR when MIRI_SYSROOT is set or when we are in rustc - std::env::var("MIRI_SYSROOT").is_ok() || rustc_test_suite().is_some() -} - fn mk_config(mode: &str) -> compiletest::common::ConfigWithTemp { let mut config = compiletest::Config::default().tempdir(); config.mode = mode.parse().expect("Invalid mode"); @@ -41,16 +37,7 @@ fn mk_config(mode: &str) -> compiletest::common::ConfigWithTemp { config } -fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: bool, opt: bool) { - if need_fullmir && !have_fullmir() { - eprintln!("{}\n", format!( - "## Skipping compile-fail tests in {} against miri for target {} due to missing mir", - path, - target - ).yellow().bold()); - return; - } - +fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, opt: bool) { let opt_str = if opt { " with optimizations" } else { "" }; eprintln!("{}", format!( "## Running compile-fail tests in {} against miri for target {}{}", @@ -78,16 +65,7 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullm compiletest::run_tests(&config); } -fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: bool, opt: bool) { - if need_fullmir && !have_fullmir() { - eprintln!("{}\n", format!( - "## Skipping run-pass tests in {} against miri for target {} due to missing mir", - path, - target - ).yellow().bold()); - return; - } - +fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, opt: bool) { let opt_str = if opt { " with optimizations" } else { "" }; eprintln!("{}", format!( "## Running run-pass tests in {} against miri for target {}{}", @@ -105,10 +83,6 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: // whitelist. flags.push("-Zmir-opt-level=1".to_owned()); } - if !have_fullmir() { - // FIXME: Validation relies on the EscapeToRaw statements being emitted - flags.push("-Zmiri-disable-validation".to_owned()); - } let mut config = mk_config("ui"); config.src_base = PathBuf::from(path); @@ -132,7 +106,7 @@ fn target_has_std>(path: P) -> bool { .map(|entry| entry.unwrap()) .filter(|entry| entry.file_type().unwrap().is_file()) .filter_map(|entry| entry.file_name().into_string().ok()) - .any(|file_name| file_name.starts_with("libstd") && file_name.ends_with(".rlib")) + .any(|file_name| file_name == "libstd.rlib") } @@ -186,18 +160,17 @@ fn run_pass_miri(opt: bool) { let host = get_host(); for_all_targets(&sysroot, |target| { - miri_pass(&sysroot, "tests/run-pass", &target, &host, false, opt); + miri_pass(&sysroot, "tests/run-pass", &target, &host, opt); }); - miri_pass(&sysroot, "tests/run-pass-fullmir", &host, &host, true, opt); } fn compile_fail_miri(opt: bool) { let sysroot = get_sysroot(); let host = get_host(); - // FIXME: run tests for other targets, too - compile_fail(&sysroot, "tests/compile-fail", &host, &host, false, opt); - compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true, opt); + for_all_targets(&sysroot, |target| { + compile_fail(&sysroot, "tests/compile-fail", &target, &host, opt); + }); } fn test_runner(_tests: &[&()]) { diff --git a/tests/run-pass-fullmir/async-fn.rs b/tests/run-pass/async-fn.rs similarity index 100% rename from tests/run-pass-fullmir/async-fn.rs rename to tests/run-pass/async-fn.rs diff --git a/tests/run-pass-fullmir/box-pair-to-vec.rs b/tests/run-pass/box-pair-to-vec.rs similarity index 100% rename from tests/run-pass-fullmir/box-pair-to-vec.rs rename to tests/run-pass/box-pair-to-vec.rs diff --git a/tests/run-pass-fullmir/box-pair-to-vec.stdout b/tests/run-pass/box-pair-to-vec.stdout similarity index 100% rename from tests/run-pass-fullmir/box-pair-to-vec.stdout rename to tests/run-pass/box-pair-to-vec.stdout diff --git a/tests/run-pass-fullmir/catch.rs b/tests/run-pass/catch.rs similarity index 100% rename from tests/run-pass-fullmir/catch.rs rename to tests/run-pass/catch.rs diff --git a/tests/run-pass-fullmir/catch.stdout b/tests/run-pass/catch.stdout similarity index 100% rename from tests/run-pass-fullmir/catch.stdout rename to tests/run-pass/catch.stdout diff --git a/tests/run-pass-fullmir/env.rs b/tests/run-pass/env.rs similarity index 100% rename from tests/run-pass-fullmir/env.rs rename to tests/run-pass/env.rs diff --git a/tests/run-pass-fullmir/foreign-fn-linkname.rs b/tests/run-pass/foreign-fn-linkname.rs similarity index 100% rename from tests/run-pass-fullmir/foreign-fn-linkname.rs rename to tests/run-pass/foreign-fn-linkname.rs diff --git a/tests/run-pass-fullmir/format.rs b/tests/run-pass/format.rs similarity index 100% rename from tests/run-pass-fullmir/format.rs rename to tests/run-pass/format.rs diff --git a/tests/run-pass-fullmir/format.stdout b/tests/run-pass/format.stdout similarity index 100% rename from tests/run-pass-fullmir/format.stdout rename to tests/run-pass/format.stdout diff --git a/tests/run-pass-fullmir/from_utf8.rs b/tests/run-pass/from_utf8.rs similarity index 100% rename from tests/run-pass-fullmir/from_utf8.rs rename to tests/run-pass/from_utf8.rs diff --git a/tests/run-pass-fullmir/hashmap.rs b/tests/run-pass/hashmap.rs similarity index 100% rename from tests/run-pass-fullmir/hashmap.rs rename to tests/run-pass/hashmap.rs diff --git a/tests/run-pass-fullmir/hello.rs b/tests/run-pass/hello.rs similarity index 100% rename from tests/run-pass-fullmir/hello.rs rename to tests/run-pass/hello.rs diff --git a/tests/run-pass-fullmir/hello.stdout b/tests/run-pass/hello.stdout similarity index 100% rename from tests/run-pass-fullmir/hello.stdout rename to tests/run-pass/hello.stdout diff --git a/tests/run-pass-fullmir/integer-ops.rs b/tests/run-pass/integer-ops.rs similarity index 100% rename from tests/run-pass-fullmir/integer-ops.rs rename to tests/run-pass/integer-ops.rs diff --git a/tests/run-pass-fullmir/issue-3794.rs b/tests/run-pass/issue-3794.rs similarity index 100% rename from tests/run-pass-fullmir/issue-3794.rs rename to tests/run-pass/issue-3794.rs diff --git a/tests/run-pass-fullmir/issue-3794.stdout b/tests/run-pass/issue-3794.stdout similarity index 100% rename from tests/run-pass-fullmir/issue-3794.stdout rename to tests/run-pass/issue-3794.stdout diff --git a/tests/run-pass-fullmir/loop-break-value.rs b/tests/run-pass/loop-break-value.rs similarity index 100% rename from tests/run-pass-fullmir/loop-break-value.rs rename to tests/run-pass/loop-break-value.rs diff --git a/tests/run-pass-fullmir/memchr.rs b/tests/run-pass/memchr.rs similarity index 100% rename from tests/run-pass-fullmir/memchr.rs rename to tests/run-pass/memchr.rs diff --git a/tests/run-pass-fullmir/send-is-not-static-par-for.rs b/tests/run-pass/send-is-not-static-par-for.rs similarity index 100% rename from tests/run-pass-fullmir/send-is-not-static-par-for.rs rename to tests/run-pass/send-is-not-static-par-for.rs diff --git a/tests/run-pass-fullmir/threads.rs b/tests/run-pass/threads.rs similarity index 100% rename from tests/run-pass-fullmir/threads.rs rename to tests/run-pass/threads.rs diff --git a/tests/run-pass-fullmir/u128.rs b/tests/run-pass/u128.rs similarity index 100% rename from tests/run-pass-fullmir/u128.rs rename to tests/run-pass/u128.rs diff --git a/tests/run-pass-fullmir/unsized-tuple-impls.rs b/tests/run-pass/unsized-tuple-impls.rs similarity index 100% rename from tests/run-pass-fullmir/unsized-tuple-impls.rs rename to tests/run-pass/unsized-tuple-impls.rs diff --git a/tests/run-pass-fullmir/vecdeque.rs b/tests/run-pass/vecdeque.rs similarity index 100% rename from tests/run-pass-fullmir/vecdeque.rs rename to tests/run-pass/vecdeque.rs From 4d767e1f415967a4ff58a2e88905d5c9f9c98453 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 10 Dec 2018 10:10:03 +0100 Subject: [PATCH 0465/5092] MIRI_SYSROOT is no longer needed for development agains a locally built rustc --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 5f8f8fb8502f..1b9e5304bd03 100644 --- a/README.md +++ b/README.md @@ -133,9 +133,6 @@ cp config.toml.example config.toml rustup toolchain link custom build/x86_64-unknown-linux-gnu/stage2 # Now cd to your Miri directory, then configure rustup rustup override set custom -# We also need to tell Miri where to find its sysroot. Since we set -# `test-miri` above, we can just use rustc' sysroot. -export MIRI_SYSROOT=$(rustc --print sysroot) ``` With this, you should now have a working development setup! See From b8e6af49d946b123181a15f34a7c0dad24a48d5e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 10 Dec 2018 10:52:59 +0100 Subject: [PATCH 0466/5092] fix setting the manifest path manually when using cargo miri --- src/bin/cargo-miri.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 68da028a81c6..8a1a9d0554ab 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -75,7 +75,9 @@ fn get_arg_flag_value(name: &str) -> Option { fn list_targets() -> impl Iterator { // We need to get the manifest, and then the metadata, to enumerate targets. - let manifest_path = get_arg_flag_value("--manifest-path").map(PathBuf::from); + let manifest_path = get_arg_flag_value("--manifest-path").map(|m| + Path::new(&m).canonicalize().unwrap() + ); let mut metadata = if let Ok(metadata) = cargo_metadata::metadata( manifest_path.as_ref().map(AsRef::as_ref), From b50662d68c886de44628e7ce55e331515df6c5e0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 10 Dec 2018 10:19:44 +0100 Subject: [PATCH 0467/5092] fix CI --- .travis.yml | 16 +++++++++++----- appveyor.yml | 5 ++--- src/bin/cargo-miri.rs | 9 ++++----- src/fn_call.rs | 2 ++ 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index ac3f16ce1353..1d49394e29b8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,13 +9,16 @@ cache: os: - linux - osx +dist: xenial before_script: +# install extra stuff for cross-compilation +- if [[ "$TRAVIS_OS_NAME" == linux ]]; then sudo apt update && sudo apt install gcc-multilib; fi # macOS weirdness (https://github.com/travis-ci/travis-ci/issues/6307, https://github.com/travis-ci/travis-ci/issues/10165) - if [[ "$TRAVIS_OS_NAME" == osx ]]; then rvm get stable; fi # Compute the rust version we use. We do not use "language: rust" to have more control here. - | - if [ "$TRAVIS_EVENT_TYPE" = cron ]; then + if [[ "$TRAVIS_EVENT_TYPE" == cron ]]; then RUST_TOOLCHAIN=nightly else RUST_TOOLCHAIN=$(cat rust-version) @@ -24,7 +27,7 @@ before_script: if [ "$TRAVIS_OS_NAME" == osx ]; then export MIRI_SYSROOT_BASE=~/Library/Caches/miri.miri.miri/ else - export MIRI_SYSROOT_BASE=~/.cache/miri/HOST + export MIRI_SYSROOT_BASE=~/.cache/miri/ fi # install Rust - curl https://build.travis-ci.org/files/rustup-init.sh -sSf | sh -s -- -y --default-toolchain "$RUST_TOOLCHAIN" @@ -38,10 +41,13 @@ script: cargo build --release --all-features --all-targets && cargo install --all-features --force --path . - | - # Get ourselves a MIR-full libstd + # Get ourselves a MIR-full libstd for the host and a foreign architecture cargo miri setup && - cargo miri setup --target i686-unknown-linux-gnu && - cargo miri setup --target i686-apple-darwin + if [[ "$TRAVIS_OS_NAME" == osx ]]; then + cargo miri setup --target i686-apple-darwin + else + cargo miri setup --target i686-unknown-linux-gnu + fi - | # Test miri with full MIR, on the host and other architectures MIRI_SYSROOT=$MIRI_SYSROOT_BASE/HOST cargo test --release --all-features && diff --git a/appveyor.yml b/appveyor.yml index 1f38b848c005..4f4aebd80791 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -27,13 +27,12 @@ build: false test_script: - set RUSTFLAGS=-g - set RUST_BACKTRACE=1 - # Test plain miri + # Build miri - cargo build --release --all-features --all-targets - - cargo test --release --all-features # Get ourselves a MIR-full libstd, and use it henceforth - cargo run --release --all-features --bin cargo-miri -- miri setup - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\miri\miri\cache\HOST - # Test miri with full MIR + # Test miri - cargo test --release --all-features notifications: diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 8a1a9d0554ab..7e1785fd3b93 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -342,11 +342,11 @@ fn main() { .collect() }; args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string)); + args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-miri""#.to_owned()]); // this check ensures that dependencies are built but not interpreted and the final crate is // interpreted but not built let miri_enabled = std::env::args().any(|s| s == "--emit=dep-info,metadata"); - let mut command = if miri_enabled { let mut path = std::env::current_exe().expect("current executable path invalid"); path.set_file_name("miri"); @@ -354,10 +354,9 @@ fn main() { } else { Command::new("rustc") }; + command.args(&args); - args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-miri""#.to_owned()]); - - match command.args(&args).status() { + match command.status() { Ok(exit) => { if !exit.success() { std::process::exit(exit.code().unwrap_or(42)); @@ -388,7 +387,7 @@ where args.push(r#"feature="cargo-miri""#.to_owned()); let path = std::env::current_exe().expect("current executable path invalid"); - let exit_status = std::process::Command::new("cargo") + let exit_status = Command::new("cargo") .args(&args) .env("RUSTC", path) .spawn() diff --git a/src/fn_call.rs b/src/fn_call.rs index e9d3255a5b32..701dc8ca92ca 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -113,6 +113,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo Some(name) => name.as_str(), None => self.tcx.item_name(def_id).as_str(), }; + // Strip linker suffixes (seen on 32bit macOS) + let link_name = link_name.trim_end_matches("$UNIX2003"); let tcx = &{self.tcx.tcx}; From 05f2b2ed3da6f504ac31d61e8bffb9a989780847 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 10 Dec 2018 12:26:20 +0100 Subject: [PATCH 0468/5092] remove support for not having libstd MIR --- src/fn_call.rs | 84 +-------------------------------- src/lib.rs | 126 +++++++++++++++++++++---------------------------- 2 files changed, 55 insertions(+), 155 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 701dc8ca92ca..e28497aa256f 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -17,18 +17,6 @@ pub trait EvalContextExt<'tcx, 'mir> { ret: mir::BasicBlock, ) -> EvalResult<'tcx>; - /// Emulate a function that should have MIR but does not. - /// This is solely to support execution without full MIR. - /// Fail if emulating this function is not supported. - /// This function will handle `goto_block` if needed. - fn emulate_missing_fn( - &mut self, - path: String, - args: &[OpTy<'tcx, Borrow>], - dest: Option>, - ret: Option, - ) -> EvalResult<'tcx>; - fn find_fn( &mut self, instance: ty::Instance<'tcx>, @@ -81,24 +69,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo return Ok(None); } - // Otherwise we really want to see the MIR -- but if we do not have it, maybe we can - // emulate something. This is a HACK to support running without a full-MIR libstd. - let mir = match self.load_mir(instance.def) { - Ok(mir) => mir, - Err(EvalError { kind: EvalErrorKind::NoMirFor(path), .. }) => { - self.emulate_missing_fn( - path, - args, - dest, - ret, - )?; - // `goto_block` already handled - return Ok(None); - } - Err(other) => return Err(other), - }; - - Ok(Some(mir)) + // Otherwise, load the MIR + Ok(Some(self.load_mir(instance.def)?)) } fn emulate_foreign_item( @@ -657,58 +629,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo Ok(()) } - fn emulate_missing_fn( - &mut self, - path: String, - _args: &[OpTy<'tcx, Borrow>], - dest: Option>, - ret: Option, - ) -> EvalResult<'tcx> { - // In some cases in non-MIR libstd-mode, not having a destination is legit. Handle these early. - match &path[..] { - "std::panicking::rust_panic_with_hook" | - "core::panicking::panic_fmt::::panic_impl" | - "std::rt::begin_panic_fmt" => - return err!(MachineError("the evaluated program panicked".to_string())), - _ => {} - } - - let dest = dest.ok_or_else( - // Must be some function we do not support - || EvalErrorKind::NoMirFor(path.clone()), - )?; - - match &path[..] { - // A Rust function is missing, which means we are running with MIR missing for libstd (or other dependencies). - // Still, we can make many things mostly work by "emulating" or ignoring some functions. - "std::io::_print" | - "std::io::_eprint" => { - warn!( - "Ignoring output. To run programs that prints, make sure you have a libstd with full MIR." - ); - } - "std::thread::Builder::new" => { - return err!(Unimplemented("miri does not support threading".to_owned())) - } - "std::env::args" => { - return err!(Unimplemented( - "miri does not support program arguments".to_owned(), - )) - } - "std::panicking::panicking" | - "std::rt::panicking" => { - // we abort on panic -> `std::rt::panicking` always returns false - self.write_scalar(Scalar::from_bool(false), dest)?; - } - - _ => return err!(NoMirFor(path)), - } - - self.goto_block(ret)?; - self.dump_place(*dest); - Ok(()) - } - fn write_null(&mut self, dest: PlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> { self.write_scalar(Scalar::from_int(0, dest.layout.size), dest) } diff --git a/src/lib.rs b/src/lib.rs index 71abff2675e3..9641670a2edf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,82 +80,62 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( )); } - let libstd_has_mir = { - let rustc_panic = ecx.resolve_path(&["std", "panicking", "rust_panic"])?; - ecx.load_mir(rustc_panic.def).is_ok() - }; + let start_id = tcx.lang_items().start_fn().unwrap(); + let main_ret_ty = tcx.fn_sig(main_id).output(); + let main_ret_ty = main_ret_ty.no_bound_vars().unwrap(); + let start_instance = ty::Instance::resolve( + ecx.tcx.tcx, + ty::ParamEnv::reveal_all(), + start_id, + ecx.tcx.mk_substs( + ::std::iter::once(ty::subst::Kind::from(main_ret_ty))) + ).unwrap(); + let start_mir = ecx.load_mir(start_instance.def)?; - if libstd_has_mir { - let start_id = tcx.lang_items().start_fn().unwrap(); - let main_ret_ty = tcx.fn_sig(main_id).output(); - let main_ret_ty = main_ret_ty.no_bound_vars().unwrap(); - let start_instance = ty::Instance::resolve( - ecx.tcx.tcx, - ty::ParamEnv::reveal_all(), - start_id, - ecx.tcx.mk_substs( - ::std::iter::once(ty::subst::Kind::from(main_ret_ty))) - ).unwrap(); - let start_mir = ecx.load_mir(start_instance.def)?; - - if start_mir.arg_count != 3 { - return err!(AbiViolation(format!( - "'start' lang item should have three arguments, but has {}", - start_mir.arg_count - ))); - } - - // Return value (in static memory so that it does not count as leak) - let ret = ecx.layout_of(start_mir.return_ty())?; - let ret_ptr = ecx.allocate(ret, MiriMemoryKind::MutStatic.into())?; - - // Push our stack frame - ecx.push_stack_frame( - start_instance, - DUMMY_SP, // there is no call site, we want no span - start_mir, - Some(ret_ptr.into()), - StackPopCleanup::None { cleanup: true }, - )?; - - let mut args = ecx.frame().mir.args_iter(); - - // First argument: pointer to main() - let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance).with_default_tag(); - let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?; - - // Second argument (argc): 1 - let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - ecx.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; - - // FIXME: extract main source file path - // Third argument (argv): &[b"foo"] - let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - let foo = ecx.memory_mut().allocate_static_bytes(b"foo\0").with_default_tag(); - let foo_ty = ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8); - let foo_layout = ecx.layout_of(foo_ty)?; - let foo_place = ecx.allocate(foo_layout, MiriMemoryKind::Env.into())?; - ecx.write_scalar(Scalar::Ptr(foo), foo_place.into())?; - ecx.memory_mut().mark_immutable(foo_place.to_ptr()?.alloc_id)?; - ecx.write_scalar(foo_place.ptr, dest)?; - - assert!(args.next().is_none(), "start lang item has more arguments than expected"); - } else { - let ret_place = MPlaceTy::dangling(ecx.layout_of(tcx.mk_unit())?, &ecx).into(); - ecx.push_stack_frame( - main_instance, - DUMMY_SP, // there is no call site, we want no span - main_mir, - Some(ret_place), - StackPopCleanup::None { cleanup: true }, - )?; - - // No arguments - let mut args = ecx.frame().mir.args_iter(); - assert!(args.next().is_none(), "main function must not have arguments"); + if start_mir.arg_count != 3 { + return err!(AbiViolation(format!( + "'start' lang item should have three arguments, but has {}", + start_mir.arg_count + ))); } + // Return value (in static memory so that it does not count as leak) + let ret = ecx.layout_of(start_mir.return_ty())?; + let ret_ptr = ecx.allocate(ret, MiriMemoryKind::MutStatic.into())?; + + // Push our stack frame + ecx.push_stack_frame( + start_instance, + DUMMY_SP, // there is no call site, we want no span + start_mir, + Some(ret_ptr.into()), + StackPopCleanup::None { cleanup: true }, + )?; + + let mut args = ecx.frame().mir.args_iter(); + + // First argument: pointer to main() + let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance).with_default_tag(); + let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; + ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?; + + // Second argument (argc): 1 + let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; + ecx.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; + + // FIXME: extract main source file path + // Third argument (argv): &[b"foo"] + let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; + let foo = ecx.memory_mut().allocate_static_bytes(b"foo\0").with_default_tag(); + let foo_ty = ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8); + let foo_layout = ecx.layout_of(foo_ty)?; + let foo_place = ecx.allocate(foo_layout, MiriMemoryKind::Env.into())?; + ecx.write_scalar(Scalar::Ptr(foo), foo_place.into())?; + ecx.memory_mut().mark_immutable(foo_place.to_ptr()?.alloc_id)?; + ecx.write_scalar(foo_place.ptr, dest)?; + + assert!(args.next().is_none(), "start lang item has more arguments than expected"); + Ok(ecx) } From 5689366a0d47ced0e7ed85abed168493d82555c5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 10 Dec 2018 13:14:46 +0100 Subject: [PATCH 0469/5092] use rustc_version also to parse host in compiletest --- tests/compiletest.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index f0ebbf6b071b..7187a3caee25 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -142,17 +142,15 @@ fn get_sysroot() -> PathBuf { fn get_host() -> String { let rustc = rustc_test_suite().unwrap_or(PathBuf::from("rustc")); - let host = std::process::Command::new(rustc) + let rustc_version = std::process::Command::new(rustc) .arg("-vV") .output() .expect("rustc not found for -vV") .stdout; - let host = std::str::from_utf8(&host).expect("sysroot is not utf8"); - let host = host.split("\nhost: ").nth(1).expect( - "no host: part in rustc -vV", - ); - let host = host.split('\n').next().expect("no \n after host"); - String::from(host) + let rustc_version = std::str::from_utf8(&rustc_version).expect("rustc -vV is not utf8"); + let version_meta = rustc_version::version_meta_for(&rustc_version) + .expect("failed to parse rustc version info"); + version_meta.host } fn run_pass_miri(opt: bool) { From 9de605b32f830ece9abaf3476bba418ab3b3d213 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 11 Dec 2018 14:16:58 +0100 Subject: [PATCH 0470/5092] avoid repeating signatures in EvalContext extension traits --- src/fn_call.rs | 337 +++++++++++++++++++---------------------- src/helpers.rs | 45 +++--- src/intrinsic.rs | 239 ++++++++++++++--------------- src/lib.rs | 15 ++ src/stacked_borrows.rs | 100 ++++-------- src/tls.rs | 28 ++-- 6 files changed, 352 insertions(+), 412 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index e28497aa256f..ea913417a56e 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -6,29 +6,8 @@ use syntax::attr; use crate::*; -pub trait EvalContextExt<'tcx, 'mir> { - /// Emulate calling a foreign item, fail if the item is not supported. - /// This function will handle `goto_block` if needed. - fn emulate_foreign_item( - &mut self, - def_id: DefId, - args: &[OpTy<'tcx, Borrow>], - dest: PlaceTy<'tcx, Borrow>, - ret: mir::BasicBlock, - ) -> EvalResult<'tcx>; - - fn find_fn( - &mut self, - instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Borrow>], - dest: Option>, - ret: Option, - ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>>; - - fn write_null(&mut self, dest: PlaceTy<'tcx, Borrow>) -> EvalResult<'tcx>; -} - -impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalContext<'a, 'mir, 'tcx> { +impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} +pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { fn find_fn( &mut self, instance: ty::Instance<'tcx>, @@ -36,30 +15,31 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo dest: Option>, ret: Option, ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> { + let this = self.eval_context_mut(); trace!("eval_fn_call: {:#?}, {:?}", instance, dest.map(|place| *place)); // first run the common hooks also supported by CTFE - if self.hook_fn(instance, args, dest)? { - self.goto_block(ret)?; + if this.hook_fn(instance, args, dest)? { + this.goto_block(ret)?; return Ok(None); } // there are some more lang items we want to hook that CTFE does not hook (yet) - if self.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { + if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { // FIXME: return a real value in case the target allocation has an // alignment bigger than the one requested let n = u128::max_value(); let dest = dest.unwrap(); - let n = self.truncate(n, dest.layout); - self.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; - self.goto_block(ret)?; + let n = this.truncate(n, dest.layout); + this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; + this.goto_block(ret)?; return Ok(None); } // Try to see if we can do something about foreign items - if self.tcx.is_foreign_item(instance.def_id()) { + if this.tcx.is_foreign_item(instance.def_id()) { // An external function that we cannot find MIR for, but we can still run enough // of them to make miri viable. - self.emulate_foreign_item( + this.emulate_foreign_item( instance.def_id(), args, dest.unwrap(), @@ -70,9 +50,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } // Otherwise, load the MIR - Ok(Some(self.load_mir(instance.def)?)) + Ok(Some(this.load_mir(instance.def)?)) } + /// Emulate calling a foreign item, fail if the item is not supported. + /// This function will handle `goto_block` if needed. fn emulate_foreign_item( &mut self, def_id: DefId, @@ -80,15 +62,16 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo dest: PlaceTy<'tcx, Borrow>, ret: mir::BasicBlock, ) -> EvalResult<'tcx> { - let attrs = self.tcx.get_attrs(def_id); + let this = self.eval_context_mut(); + let attrs = this.tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { Some(name) => name.as_str(), - None => self.tcx.item_name(def_id).as_str(), + None => this.tcx.item_name(def_id).as_str(), }; // Strip linker suffixes (seen on 32bit macOS) let link_name = link_name.trim_end_matches("$UNIX2003"); - let tcx = &{self.tcx.tcx}; + let tcx = &{this.tcx.tcx}; // All these functions take raw pointers, so if we access memory directly // (as opposed to through a place), we have to remember to erase any tag @@ -96,20 +79,20 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo match &link_name[..] { "malloc" => { - let size = self.read_scalar(args[0])?.to_usize(self)?; + let size = this.read_scalar(args[0])?.to_usize(this)?; if size == 0 { - self.write_null(dest)?; + this.write_null(dest)?; } else { - let align = self.tcx.data_layout.pointer_align.abi; - let ptr = self.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into())?; - self.write_scalar(Scalar::Ptr(ptr.with_default_tag()), dest)?; + let align = this.tcx.data_layout.pointer_align.abi; + let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into())?; + this.write_scalar(Scalar::Ptr(ptr.with_default_tag()), dest)?; } } "free" => { - let ptr = self.read_scalar(args[0])?.not_undef()?; - if !ptr.is_null_ptr(self) { - self.memory_mut().deallocate( + let ptr = this.read_scalar(args[0])?.not_undef()?; + if !ptr.is_null_ptr(this) { + this.memory_mut().deallocate( ptr.to_ptr()?, None, MiriMemoryKind::C.into(), @@ -118,72 +101,72 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "__rust_alloc" => { - let size = self.read_scalar(args[0])?.to_usize(self)?; - let align = self.read_scalar(args[1])?.to_usize(self)?; + let size = this.read_scalar(args[0])?.to_usize(this)?; + let align = this.read_scalar(args[1])?.to_usize(this)?; if size == 0 { return err!(HeapAllocZeroBytes); } if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory_mut() + let ptr = this.memory_mut() .allocate( Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into() )? .with_default_tag(); - self.write_scalar(Scalar::Ptr(ptr), dest)?; + this.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_alloc_zeroed" => { - let size = self.read_scalar(args[0])?.to_usize(self)?; - let align = self.read_scalar(args[1])?.to_usize(self)?; + let size = this.read_scalar(args[0])?.to_usize(this)?; + let align = this.read_scalar(args[1])?.to_usize(this)?; if size == 0 { return err!(HeapAllocZeroBytes); } if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory_mut() + let ptr = this.memory_mut() .allocate( Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into() )? .with_default_tag(); - self.memory_mut() + this.memory_mut() .get_mut(ptr.alloc_id)? .write_repeat(tcx, ptr, 0, Size::from_bytes(size))?; - self.write_scalar(Scalar::Ptr(ptr), dest)?; + this.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_dealloc" => { - let ptr = self.read_scalar(args[0])?.to_ptr()?; - let old_size = self.read_scalar(args[1])?.to_usize(self)?; - let align = self.read_scalar(args[2])?.to_usize(self)?; + let ptr = this.read_scalar(args[0])?.to_ptr()?; + let old_size = this.read_scalar(args[1])?.to_usize(this)?; + let align = this.read_scalar(args[2])?.to_usize(this)?; if old_size == 0 { return err!(HeapAllocZeroBytes); } if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - self.memory_mut().deallocate( + this.memory_mut().deallocate( ptr, Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())), MiriMemoryKind::Rust.into(), )?; } "__rust_realloc" => { - let ptr = self.read_scalar(args[0])?.to_ptr()?; - let old_size = self.read_scalar(args[1])?.to_usize(self)?; - let align = self.read_scalar(args[2])?.to_usize(self)?; - let new_size = self.read_scalar(args[3])?.to_usize(self)?; + let ptr = this.read_scalar(args[0])?.to_ptr()?; + let old_size = this.read_scalar(args[1])?.to_usize(this)?; + let align = this.read_scalar(args[2])?.to_usize(this)?; + let new_size = this.read_scalar(args[3])?.to_usize(this)?; if old_size == 0 || new_size == 0 { return err!(HeapAllocZeroBytes); } if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let new_ptr = self.memory_mut().reallocate( + let new_ptr = this.memory_mut().reallocate( ptr, Size::from_bytes(old_size), Align::from_bytes(align).unwrap(), @@ -191,7 +174,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into(), )?; - self.write_scalar(Scalar::Ptr(new_ptr.with_default_tag()), dest)?; + this.write_scalar(Scalar::Ptr(new_ptr.with_default_tag()), dest)?; } "syscall" => { @@ -200,7 +183,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // // libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK) // is called if a `HashMap` is created the regular way. - match self.read_scalar(args[0])?.to_usize(self)? { + match this.read_scalar(args[0])?.to_usize(this)? { 318 | 511 => { return err!(Unimplemented( "miri does not support random number generators".to_owned(), @@ -215,9 +198,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "dlsym" => { - let _handle = self.read_scalar(args[0])?; - let symbol = self.read_scalar(args[1])?.to_ptr()?; - let symbol_name = self.memory().get(symbol.alloc_id)?.read_c_str(tcx, symbol)?; + let _handle = this.read_scalar(args[0])?; + let symbol = this.read_scalar(args[1])?.to_ptr()?; + let symbol_name = this.memory().get(symbol.alloc_id)?.read_c_str(tcx, symbol)?; let err = format!("bad c unicode symbol: {:?}", symbol_name); let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err); return err!(Unimplemented(format!( @@ -229,24 +212,24 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "__rust_maybe_catch_panic" => { // fn __rust_maybe_catch_panic(f: fn(*mut u8), data: *mut u8, data_ptr: *mut usize, vtable_ptr: *mut usize) -> u32 // We abort on panic, so not much is going on here, but we still have to call the closure - let f = self.read_scalar(args[0])?.to_ptr()?; - let data = self.read_scalar(args[1])?.not_undef()?; - let f_instance = self.memory().get_fn(f)?; - self.write_null(dest)?; + let f = this.read_scalar(args[0])?.to_ptr()?; + let data = this.read_scalar(args[1])?.not_undef()?; + let f_instance = this.memory().get_fn(f)?; + this.write_null(dest)?; trace!("__rust_maybe_catch_panic: {:?}", f_instance); // Now we make a function call. TODO: Consider making this re-usable? EvalContext::step does sth. similar for the TLS dtors, // and of course eval_main. - let mir = self.load_mir(f_instance.def)?; - let ret_place = MPlaceTy::dangling(self.layout_of(self.tcx.mk_unit())?, self).into(); - self.push_stack_frame( + let mir = this.load_mir(f_instance.def)?; + let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); + this.push_stack_frame( f_instance, mir.span, mir, Some(ret_place), StackPopCleanup::Goto(Some(ret)), // directly return to caller )?; - let mut args = self.frame().mir.args_iter(); + let mut args = this.frame().mir.args_iter(); let arg_local = args.next().ok_or_else(|| EvalErrorKind::AbiViolation( @@ -254,13 +237,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo .to_owned(), ), )?; - let arg_dest = self.eval_place(&mir::Place::Local(arg_local))?; - self.write_scalar(data, arg_dest)?; + let arg_dest = this.eval_place(&mir::Place::Local(arg_local))?; + this.write_scalar(data, arg_dest)?; assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected"); // We ourselves will return 0, eventually (because we will not return if we paniced) - self.write_null(dest)?; + this.write_null(dest)?; // Don't fall through, we do NOT want to `goto_block`! return Ok(()); @@ -270,13 +253,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo return err!(MachineError("the evaluated program panicked".to_string())), "memcmp" => { - let left = self.read_scalar(args[0])?.not_undef()?; - let right = self.read_scalar(args[1])?.not_undef()?; - let n = Size::from_bytes(self.read_scalar(args[2])?.to_usize(self)?); + let left = this.read_scalar(args[0])?.not_undef()?; + let right = this.read_scalar(args[1])?.not_undef()?; + let n = Size::from_bytes(this.read_scalar(args[2])?.to_usize(this)?); let result = { - let left_bytes = self.memory().read_bytes(left, n)?; - let right_bytes = self.memory().read_bytes(right, n)?; + let left_bytes = this.memory().read_bytes(left, n)?; + let right_bytes = this.memory().read_bytes(right, n)?; use std::cmp::Ordering::*; match left_bytes.cmp(right_bytes) { @@ -286,84 +269,84 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } }; - self.write_scalar( + this.write_scalar( Scalar::from_int(result, Size::from_bits(32)), dest, )?; } "memrchr" => { - let ptr = self.read_scalar(args[0])?.not_undef()?; - let val = self.read_scalar(args[1])?.to_bytes()? as u8; - let num = self.read_scalar(args[2])?.to_usize(self)?; - if let Some(idx) = self.memory().read_bytes(ptr, Size::from_bytes(num))? + let ptr = this.read_scalar(args[0])?.not_undef()?; + let val = this.read_scalar(args[1])?.to_bytes()? as u8; + let num = this.read_scalar(args[2])?.to_usize(this)?; + if let Some(idx) = this.memory().read_bytes(ptr, Size::from_bytes(num))? .iter().rev().position(|&c| c == val) { - let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), self)?; - self.write_scalar(new_ptr, dest)?; + let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), this)?; + this.write_scalar(new_ptr, dest)?; } else { - self.write_null(dest)?; + this.write_null(dest)?; } } "memchr" => { - let ptr = self.read_scalar(args[0])?.not_undef()?; - let val = self.read_scalar(args[1])?.to_bytes()? as u8; - let num = self.read_scalar(args[2])?.to_usize(self)?; - if let Some(idx) = self.memory().read_bytes(ptr, Size::from_bytes(num))?.iter().position( + let ptr = this.read_scalar(args[0])?.not_undef()?; + let val = this.read_scalar(args[1])?.to_bytes()? as u8; + let num = this.read_scalar(args[2])?.to_usize(this)?; + if let Some(idx) = this.memory().read_bytes(ptr, Size::from_bytes(num))?.iter().position( |&c| c == val, ) { - let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), self)?; - self.write_scalar(new_ptr, dest)?; + let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), this)?; + this.write_scalar(new_ptr, dest)?; } else { - self.write_null(dest)?; + this.write_null(dest)?; } } "getenv" => { let result = { - let name_ptr = self.read_scalar(args[0])?.to_ptr()?; - let name = self.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?; - match self.machine.env_vars.get(name) { + let name_ptr = this.read_scalar(args[0])?.to_ptr()?; + let name = this.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?; + match this.machine.env_vars.get(name) { Some(&var) => Scalar::Ptr(var), - None => Scalar::ptr_null(&*self.tcx), + None => Scalar::ptr_null(&*this.tcx), } }; - self.write_scalar(result, dest)?; + this.write_scalar(result, dest)?; } "unsetenv" => { let mut success = None; { - let name_ptr = self.read_scalar(args[0])?.not_undef()?; - if !name_ptr.is_null_ptr(self) { + let name_ptr = this.read_scalar(args[0])?.not_undef()?; + if !name_ptr.is_null_ptr(this) { let name_ptr = name_ptr.to_ptr()?; - let name = self.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?.to_owned(); + let name = this.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?.to_owned(); if !name.is_empty() && !name.contains(&b'=') { - success = Some(self.machine.env_vars.remove(&name)); + success = Some(this.machine.env_vars.remove(&name)); } } } if let Some(old) = success { if let Some(var) = old { - self.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; + this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; } - self.write_null(dest)?; + this.write_null(dest)?; } else { - self.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; } } "setenv" => { let mut new = None; { - let name_ptr = self.read_scalar(args[0])?.not_undef()?; - let value_ptr = self.read_scalar(args[1])?.to_ptr()?; - let value = self.memory().get(value_ptr.alloc_id)?.read_c_str(tcx, value_ptr)?; - if !name_ptr.is_null_ptr(self) { + let name_ptr = this.read_scalar(args[0])?.not_undef()?; + let value_ptr = this.read_scalar(args[1])?.to_ptr()?; + let value = this.memory().get(value_ptr.alloc_id)?.read_c_str(tcx, value_ptr)?; + if !name_ptr.is_null_ptr(this) { let name_ptr = name_ptr.to_ptr()?; - let name = self.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?; + let name = this.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?; if !name.is_empty() && !name.contains(&b'=') { new = Some((name.to_owned(), value.to_owned())); } @@ -371,40 +354,40 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } if let Some((name, value)) = new { // +1 for the null terminator - let value_copy = self.memory_mut().allocate( + let value_copy = this.memory_mut().allocate( Size::from_bytes((value.len() + 1) as u64), Align::from_bytes(1).unwrap(), MiriMemoryKind::Env.into(), )?.with_default_tag(); { - let alloc = self.memory_mut().get_mut(value_copy.alloc_id)?; + let alloc = this.memory_mut().get_mut(value_copy.alloc_id)?; alloc.write_bytes(tcx, value_copy, &value)?; let trailing_zero_ptr = value_copy.offset(Size::from_bytes(value.len() as u64), tcx)?; alloc.write_bytes(tcx, trailing_zero_ptr, &[0])?; } - if let Some(var) = self.machine.env_vars.insert( + if let Some(var) = this.machine.env_vars.insert( name.to_owned(), value_copy, ) { - self.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; + this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; } - self.write_null(dest)?; + this.write_null(dest)?; } else { - self.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; } } "write" => { - let fd = self.read_scalar(args[0])?.to_bytes()?; - let buf = self.read_scalar(args[1])?.not_undef()?; - let n = self.read_scalar(args[2])?.to_bytes()? as u64; + let fd = this.read_scalar(args[0])?.to_bytes()?; + let buf = this.read_scalar(args[1])?.not_undef()?; + let n = this.read_scalar(args[2])?.to_bytes()? as u64; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { // stdout/stderr use std::io::{self, Write}; - let buf_cont = self.memory().read_bytes(buf, Size::from_bytes(n))?; + let buf_cont = this.memory().read_bytes(buf, Size::from_bytes(n))?; let res = if fd == 1 { io::stdout().write(buf_cont) } else { @@ -418,25 +401,25 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo warn!("Ignored output to FD {}", fd); n as i64 // pretend it all went well }; // now result is the value we return back to the program - self.write_scalar( + this.write_scalar( Scalar::from_int(result, dest.layout.size), dest, )?; } "strlen" => { - let ptr = self.read_scalar(args[0])?.to_ptr()?; - let n = self.memory().get(ptr.alloc_id)?.read_c_str(tcx, ptr)?.len(); - self.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; + let ptr = this.read_scalar(args[0])?.to_ptr()?; + let n = this.memory().get(ptr.alloc_id)?.read_c_str(tcx, ptr)?.len(); + this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; } // Some things needed for sys::thread initialization to go through "signal" | "sigaction" | "sigaltstack" => { - self.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?; } "sysconf" => { - let name = self.read_scalar(args[0])?.to_i32()?; + let name = this.read_scalar(args[0])?.to_i32()?; trace!("sysconf() called with name {}", name); // cache the sysconf integers via miri's global cache @@ -446,13 +429,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo ]; let mut result = None; for &(path, path_value) in paths { - if let Ok(instance) = self.resolve_path(path) { + if let Ok(instance) = this.resolve_path(path) { let cid = GlobalId { instance, promoted: None, }; - let const_val = self.const_eval_raw(cid)?; - let const_val = self.read_scalar(const_val.into())?; + let const_val = this.const_eval_raw(cid)?; + let const_val = this.read_scalar(const_val.into())?; let value = const_val.to_i32()?; if value == name { result = Some(path_value); @@ -461,7 +444,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } } if let Some(result) = result { - self.write_scalar(result, dest)?; + this.write_scalar(result, dest)?; } else { return err!(Unimplemented( format!("Unimplemented sysconf name: {}", name), @@ -471,13 +454,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // Hook pthread calls that go to the thread-local storage memory subsystem "pthread_key_create" => { - let key_ptr = self.read_scalar(args[0])?.to_ptr()?; + let key_ptr = this.read_scalar(args[0])?.to_ptr()?; // Extract the function type out of the signature (that seems easier than constructing it ourselves...) - let dtor = match self.read_scalar(args[1])?.not_undef()? { - Scalar::Ptr(dtor_ptr) => Some(self.memory().get_fn(dtor_ptr)?), + let dtor = match this.read_scalar(args[1])?.not_undef()? { + Scalar::Ptr(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr)?), Scalar::Bits { bits: 0, size } => { - assert_eq!(size as u64, self.memory().pointer_size().bytes()); + assert_eq!(size as u64, this.memory().pointer_size().bytes()); None }, Scalar::Bits { .. } => return err!(ReadBytesAsPointer), @@ -486,16 +469,16 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // Figure out how large a pthread TLS key actually is. This is libc::pthread_key_t. let key_type = args[0].layout.ty.builtin_deref(true) .ok_or_else(|| EvalErrorKind::AbiViolation("Wrong signature used for pthread_key_create: First argument must be a raw pointer.".to_owned()))?.ty; - let key_layout = self.layout_of(key_type)?; + let key_layout = this.layout_of(key_type)?; // Create key and write it into the memory where key_ptr wants it - let key = self.machine.tls.create_tls_key(dtor, tcx) as u128; + let key = this.machine.tls.create_tls_key(dtor, tcx) as u128; if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) { return err!(OutOfTls); } - self.memory().check_align(key_ptr.into(), key_layout.align.abi)?; - self.memory_mut().get_mut(key_ptr.alloc_id)?.write_scalar( + this.memory().check_align(key_ptr.into(), key_layout.align.abi)?; + this.memory_mut().get_mut(key_ptr.alloc_id)?.write_scalar( tcx, key_ptr, Scalar::from_uint(key, key_layout.size).into(), @@ -503,26 +486,26 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo )?; // Return success (0) - self.write_null(dest)?; + this.write_null(dest)?; } "pthread_key_delete" => { - let key = self.read_scalar(args[0])?.to_bytes()?; - self.machine.tls.delete_tls_key(key)?; + let key = this.read_scalar(args[0])?.to_bytes()?; + this.machine.tls.delete_tls_key(key)?; // Return success (0) - self.write_null(dest)?; + this.write_null(dest)?; } "pthread_getspecific" => { - let key = self.read_scalar(args[0])?.to_bytes()?; - let ptr = self.machine.tls.load_tls(key)?; - self.write_scalar(ptr, dest)?; + let key = this.read_scalar(args[0])?.to_bytes()?; + let ptr = this.machine.tls.load_tls(key)?; + this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { - let key = self.read_scalar(args[0])?.to_bytes()?; - let new_ptr = self.read_scalar(args[1])?.not_undef()?; - self.machine.tls.store_tls(key, new_ptr)?; + let key = this.read_scalar(args[0])?.to_bytes()?; + let new_ptr = this.read_scalar(args[1])?.not_undef()?; + this.machine.tls.store_tls(key, new_ptr)?; // Return success (0) - self.write_null(dest)?; + this.write_null(dest)?; } "_tlv_atexit" => { @@ -532,19 +515,19 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // Determining stack base address "pthread_attr_init" | "pthread_attr_destroy" | "pthread_attr_get_np" | "pthread_getattr_np" | "pthread_self" | "pthread_get_stacksize_np" => { - self.write_null(dest)?; + this.write_null(dest)?; } "pthread_attr_getstack" => { // second argument is where we are supposed to write the stack size - let ptr = self.deref_operand(args[1])?; + let ptr = this.deref_operand(args[1])?; let stackaddr = Scalar::from_int(0x80000, args[1].layout.size); // just any address - self.write_scalar(stackaddr, ptr.into())?; + this.write_scalar(stackaddr, ptr.into())?; // return 0 - self.write_null(dest)?; + this.write_null(dest)?; } "pthread_get_stackaddr_np" => { let stackaddr = Scalar::from_int(0x80000, dest.layout.size); // just any address - self.write_scalar(stackaddr, dest)?; + this.write_scalar(stackaddr, dest)?; } // Stub out calls for condvar, mutex and rwlock to just return 0 @@ -554,22 +537,22 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "pthread_rwlock_wrlock" | "pthread_rwlock_destroy" | "pthread_condattr_init" | "pthread_condattr_setclock" | "pthread_cond_init" | "pthread_condattr_destroy" | "pthread_cond_destroy" => { - self.write_null(dest)?; + this.write_null(dest)?; } "mmap" => { // This is a horrible hack, but well... the guard page mechanism calls mmap and expects a particular return value, so we give it that value - let addr = self.read_scalar(args[0])?.not_undef()?; - self.write_scalar(addr, dest)?; + let addr = this.read_scalar(args[0])?.not_undef()?; + this.write_scalar(addr, dest)?; } "mprotect" => { - self.write_null(dest)?; + this.write_null(dest)?; } // Windows API subs "AddVectoredExceptionHandler" => { // any non zero value works for the stdlib. This is just used for stackoverflows anyway - self.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; }, "InitializeCriticalSection" | "EnterCriticalSection" | @@ -582,11 +565,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "GetProcAddress" | "TryEnterCriticalSection" => { // pretend these do not exist/nothing happened, by returning zero - self.write_null(dest)?; + this.write_null(dest)?; }, "GetLastError" => { // this is c::ERROR_CALL_NOT_IMPLEMENTED - self.write_scalar(Scalar::from_int(120, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_int(120, dest.layout.size), dest)?; }, // Windows TLS @@ -594,26 +577,26 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // This just creates a key; Windows does not natively support TLS dtors. // Create key and return it - let key = self.machine.tls.create_tls_key(None, tcx) as u128; + let key = this.machine.tls.create_tls_key(None, tcx) as u128; // Figure out how large a TLS key actually is. This is c::DWORD. if dest.layout.size.bits() < 128 && key >= (1u128 << dest.layout.size.bits() as u128) { return err!(OutOfTls); } - self.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { - let key = self.read_scalar(args[0])?.to_bytes()?; - let ptr = self.machine.tls.load_tls(key)?; - self.write_scalar(ptr, dest)?; + let key = this.read_scalar(args[0])?.to_bytes()?; + let ptr = this.machine.tls.load_tls(key)?; + this.write_scalar(ptr, dest)?; } "TlsSetValue" => { - let key = self.read_scalar(args[0])?.to_bytes()?; - let new_ptr = self.read_scalar(args[1])?.not_undef()?; - self.machine.tls.store_tls(key, new_ptr)?; + let key = this.read_scalar(args[0])?.to_bytes()?; + let new_ptr = this.read_scalar(args[1])?.not_undef()?; + this.machine.tls.store_tls(key, new_ptr)?; // Return success (1) - self.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; } // We can't execute anything else @@ -624,12 +607,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } } - self.goto_block(Some(ret))?; - self.dump_place(*dest); + this.goto_block(Some(ret))?; + this.dump_place(*dest); Ok(()) } fn write_null(&mut self, dest: PlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> { - self.write_scalar(Scalar::from_int(0, dest.layout.size), dest) + self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest) } } diff --git a/src/helpers.rs b/src/helpers.rs index 2b1a28fe9e0d..7be156760508 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -30,43 +30,31 @@ impl ScalarExt for ScalarMaybeUndef { } } -pub trait EvalContextExt<'tcx> { - fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>>; - - /// Visit the memory covered by `place`, sensitive to freezing: The 3rd parameter - /// will be true if this is frozen, false if this is in an `UnsafeCell`. - fn visit_freeze_sensitive( - &self, - place: MPlaceTy<'tcx, Borrow>, - size: Size, - action: impl FnMut(Pointer, Size, bool) -> EvalResult<'tcx>, - ) -> EvalResult<'tcx>; -} - - -impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { +impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} +pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { /// Get an instance for a path. fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>> { - self.tcx + let this = self.eval_context_ref(); + this.tcx .crates() .iter() - .find(|&&krate| self.tcx.original_crate_name(krate) == path[0]) + .find(|&&krate| this.tcx.original_crate_name(krate) == path[0]) .and_then(|krate| { let krate = DefId { krate: *krate, index: CRATE_DEF_INDEX, }; - let mut items = self.tcx.item_children(krate); + let mut items = this.tcx.item_children(krate); let mut path_it = path.iter().skip(1).peekable(); while let Some(segment) = path_it.next() { for item in mem::replace(&mut items, Default::default()).iter() { if item.ident.name == *segment { if path_it.peek().is_none() { - return Some(ty::Instance::mono(self.tcx.tcx, item.def.def_id())); + return Some(ty::Instance::mono(this.tcx.tcx, item.def.def_id())); } - items = self.tcx.item_children(item.def.def_id()); + items = this.tcx.item_children(item.def.def_id()); break; } } @@ -79,15 +67,18 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: }) } + /// Visit the memory covered by `place`, sensitive to freezing: The 3rd parameter + /// will be true if this is frozen, false if this is in an `UnsafeCell`. fn visit_freeze_sensitive( &self, place: MPlaceTy<'tcx, Borrow>, size: Size, mut action: impl FnMut(Pointer, Size, bool) -> EvalResult<'tcx>, ) -> EvalResult<'tcx> { + let this = self.eval_context_ref(); trace!("visit_frozen(place={:?}, size={:?})", *place, size); debug_assert_eq!(size, - self.size_and_align_of_mplace(place)? + this.size_and_align_of_mplace(place)? .map(|(size, _)| size) .unwrap_or_else(|| place.layout.size) ); @@ -106,8 +97,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } // We assume that we are given the fields in increasing offset order, // and nothing else changes. - let unsafe_cell_offset = unsafe_cell_ptr.get_ptr_offset(self); - let end_offset = end_ptr.get_ptr_offset(self); + let unsafe_cell_offset = unsafe_cell_ptr.get_ptr_offset(this); + let end_offset = end_ptr.get_ptr_offset(this); assert!(unsafe_cell_offset >= end_offset); let frozen_size = unsafe_cell_offset - end_offset; // Everything between the end_ptr and this `UnsafeCell` is frozen. @@ -119,18 +110,18 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: action(unsafe_cell_ptr.to_ptr()?, unsafe_cell_size, /*frozen*/false)?; } // Update end end_ptr. - end_ptr = unsafe_cell_ptr.ptr_wrapping_offset(unsafe_cell_size, self); + end_ptr = unsafe_cell_ptr.ptr_wrapping_offset(unsafe_cell_size, this); // Done Ok(()) }; // Run a visitor { let mut visitor = UnsafeCellVisitor { - ecx: self, + ecx: this, unsafe_cell_action: |place| { trace!("unsafe_cell_action on {:?}", place.ptr); // We need a size to go on. - let unsafe_cell_size = self.size_and_align_of_mplace(place)? + let unsafe_cell_size = this.size_and_align_of_mplace(place)? .map(|(size, _)| size) // for extern types, just cover what we can .unwrap_or_else(|| place.layout.size); @@ -146,7 +137,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } // The part between the end_ptr and the end of the place is also frozen. // So pretend there is a 0-sized `UnsafeCell` at the end. - unsafe_cell_action(place.ptr.ptr_wrapping_offset(size, self), Size::ZERO)?; + unsafe_cell_action(place.ptr.ptr_wrapping_offset(size, this), Size::ZERO)?; // Done! return Ok(()); diff --git a/src/intrinsic.rs b/src/intrinsic.rs index c9b16525e566..35182ba5137a 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -9,47 +9,40 @@ use crate::{ ScalarExt, OperatorEvalContextExt }; -pub trait EvalContextExt<'tcx> { - fn call_intrinsic( - &mut self, - instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Borrow>], - dest: PlaceTy<'tcx, Borrow>, - ) -> EvalResult<'tcx>; -} - -impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { +impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} +pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { fn call_intrinsic( &mut self, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Borrow>], dest: PlaceTy<'tcx, Borrow>, ) -> EvalResult<'tcx> { - if self.emulate_intrinsic(instance, args, dest)? { + let this = self.eval_context_mut(); + if this.emulate_intrinsic(instance, args, dest)? { return Ok(()); } - let tcx = &{self.tcx.tcx}; + let tcx = &{this.tcx.tcx}; let substs = instance.substs; // All these intrinsics take raw pointers, so if we access memory directly // (as opposed to through a place), we have to remember to erase any tag // that might still hang around! - let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..]; + let intrinsic_name = &this.tcx.item_name(instance.def_id()).as_str()[..]; match intrinsic_name { "arith_offset" => { - let offset = self.read_scalar(args[1])?.to_isize(self)?; - let ptr = self.read_scalar(args[0])?.not_undef()?; + let offset = this.read_scalar(args[1])?.to_isize(this)?; + let ptr = this.read_scalar(args[0])?.not_undef()?; let pointee_ty = substs.type_at(0); - let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; + let pointee_size = this.layout_of(pointee_ty)?.size.bytes() as i64; let offset = offset.overflowing_mul(pointee_size).0; - let result_ptr = ptr.ptr_wrapping_signed_offset(offset, self); - self.write_scalar(result_ptr, dest)?; + let result_ptr = ptr.ptr_wrapping_signed_offset(offset, this); + this.write_scalar(result_ptr, dest)?; } "assume" => { - let cond = self.read_scalar(args[0])?.to_bool()?; + let cond = this.read_scalar(args[0])?.to_bool()?; if !cond { return err!(AssumptionNotHeld); } @@ -59,18 +52,18 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "atomic_load_relaxed" | "atomic_load_acq" | "volatile_load" => { - let ptr = self.deref_operand(args[0])?; - let val = self.read_scalar(ptr.into())?; // make sure it fits into a scalar; otherwise it cannot be atomic - self.write_scalar(val, dest)?; + let ptr = this.deref_operand(args[0])?; + let val = this.read_scalar(ptr.into())?; // make sure it fits into a scalar; otherwise it cannot be atomic + this.write_scalar(val, dest)?; } "atomic_store" | "atomic_store_relaxed" | "atomic_store_rel" | "volatile_store" => { - let ptr = self.deref_operand(args[0])?; - let val = self.read_scalar(args[1])?; // make sure it fits into a scalar; otherwise it cannot be atomic - self.write_scalar(val, ptr.into())?; + let ptr = this.deref_operand(args[0])?; + let val = this.read_scalar(args[1])?; // make sure it fits into a scalar; otherwise it cannot be atomic + this.write_scalar(val, ptr.into())?; } "atomic_fence_acq" => { @@ -78,25 +71,25 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } _ if intrinsic_name.starts_with("atomic_xchg") => { - let ptr = self.deref_operand(args[0])?; - let new = self.read_scalar(args[1])?; - let old = self.read_scalar(ptr.into())?; - self.write_scalar(old, dest)?; // old value is returned - self.write_scalar(new, ptr.into())?; + let ptr = this.deref_operand(args[0])?; + let new = this.read_scalar(args[1])?; + let old = this.read_scalar(ptr.into())?; + this.write_scalar(old, dest)?; // old value is returned + this.write_scalar(new, ptr.into())?; } _ if intrinsic_name.starts_with("atomic_cxchg") => { - let ptr = self.deref_operand(args[0])?; - let expect_old = self.read_immediate(args[1])?; // read as immediate for the sake of `binary_op_imm()` - let new = self.read_scalar(args[2])?; - let old = self.read_immediate(ptr.into())?; // read as immediate for the sake of `binary_op_imm()` + let ptr = this.deref_operand(args[0])?; + let expect_old = this.read_immediate(args[1])?; // read as immediate for the sake of `binary_op_imm()` + let new = this.read_scalar(args[2])?; + let old = this.read_immediate(ptr.into())?; // read as immediate for the sake of `binary_op_imm()` // binary_op_imm will bail if either of them is not a scalar - let (eq, _) = self.binary_op_imm(mir::BinOp::Eq, old, expect_old)?; + let (eq, _) = this.binary_op_imm(mir::BinOp::Eq, old, expect_old)?; let res = Immediate::ScalarPair(old.to_scalar_or_undef(), eq.into()); - self.write_immediate(res, dest)?; // old value is returned + this.write_immediate(res, dest)?; // old value is returned // update ptr depending on comparison if eq.to_bool()? { - self.write_scalar(new, ptr.into())?; + this.write_scalar(new, ptr.into())?; } } @@ -125,13 +118,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "atomic_xsub_rel" | "atomic_xsub_acqrel" | "atomic_xsub_relaxed" => { - let ptr = self.deref_operand(args[0])?; + let ptr = this.deref_operand(args[0])?; if !ptr.layout.ty.is_integral() { return err!(Unimplemented(format!("Atomic arithmetic operations only work on integer types"))); } - let rhs = self.read_immediate(args[1])?; - let old = self.read_immediate(ptr.into())?; - self.write_immediate(*old, dest)?; // old value is returned + let rhs = this.read_immediate(args[1])?; + let old = this.read_immediate(ptr.into())?; + this.write_immediate(*old, dest)?; // old value is returned let op = match intrinsic_name.split('_').nth(1).unwrap() { "or" => mir::BinOp::BitOr, "xor" => mir::BinOp::BitXor, @@ -141,7 +134,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' _ => bug!(), }; // Atomics wrap around on overflow. - self.binop_ignore_overflow(op, old, rhs, ptr.into())?; + this.binop_ignore_overflow(op, old, rhs, ptr.into())?; } "breakpoint" => unimplemented!(), // halt miri @@ -149,14 +142,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "copy" | "copy_nonoverlapping" => { let elem_ty = substs.type_at(0); - let elem_layout = self.layout_of(elem_ty)?; + let elem_layout = this.layout_of(elem_ty)?; let elem_size = elem_layout.size.bytes(); - let count = self.read_scalar(args[2])?.to_usize(self)?; + let count = this.read_scalar(args[2])?.to_usize(this)?; let elem_align = elem_layout.align.abi; // erase tags: this is a raw ptr operation - let src = self.read_scalar(args[0])?.not_undef()?; - let dest = self.read_scalar(args[1])?.not_undef()?; - self.memory_mut().copy( + let src = this.read_scalar(args[0])?.not_undef()?; + let dest = this.read_scalar(args[1])?.not_undef()?; + this.memory_mut().copy( src, elem_align, dest, @@ -167,14 +160,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } "discriminant_value" => { - let place = self.deref_operand(args[0])?; - let discr_val = self.read_discriminant(place.into())?.0; - self.write_scalar(Scalar::from_uint(discr_val, dest.layout.size), dest)?; + let place = this.deref_operand(args[0])?; + let discr_val = this.read_discriminant(place.into())?.0; + this.write_scalar(Scalar::from_uint(discr_val, dest.layout.size), dest)?; } "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" => { - let f = self.read_scalar(args[0])?.to_f32()?; + let f = this.read_scalar(args[0])?.to_f32()?; let f = match intrinsic_name { "sinf32" => f.sin(), "fabsf32" => f.abs(), @@ -190,12 +183,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "truncf32" => f.trunc(), _ => bug!(), }; - self.write_scalar(Scalar::from_f32(f), dest)?; + this.write_scalar(Scalar::from_f32(f), dest)?; } "sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" | "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" => { - let f = self.read_scalar(args[0])?.to_f64()?; + let f = this.read_scalar(args[0])?.to_f64()?; let f = match intrinsic_name { "sinf64" => f.sin(), "fabsf64" => f.abs(), @@ -211,12 +204,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "truncf64" => f.trunc(), _ => bug!(), }; - self.write_scalar(Scalar::from_f64(f), dest)?; + this.write_scalar(Scalar::from_f64(f), dest)?; } "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { - let a = self.read_immediate(args[0])?; - let b = self.read_immediate(args[1])?; + let a = this.read_immediate(args[0])?; + let b = this.read_immediate(args[1])?; let op = match intrinsic_name { "fadd_fast" => mir::BinOp::Add, "fsub_fast" => mir::BinOp::Sub, @@ -225,19 +218,19 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "frem_fast" => mir::BinOp::Rem, _ => bug!(), }; - self.binop_ignore_overflow(op, a, b, dest)?; + this.binop_ignore_overflow(op, a, b, dest)?; } "exact_div" => { // Performs an exact division, resulting in undefined behavior where // `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1` - let a = self.read_immediate(args[0])?; - let b = self.read_immediate(args[1])?; + let a = this.read_immediate(args[0])?; + let b = this.read_immediate(args[1])?; // check x % y != 0 - if self.binary_op_imm(mir::BinOp::Rem, a, b)?.0.to_bytes()? != 0 { + if this.binary_op_imm(mir::BinOp::Rem, a, b)?.0.to_bytes()? != 0 { return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b))); } - self.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; + this.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; }, "likely" | "unlikely" | "forget" => {} @@ -252,21 +245,21 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' if !dest.layout.is_zst() { // nothing to do for ZST match dest.layout.abi { layout::Abi::Scalar(ref s) => { - let x = Scalar::from_int(0, s.value.size(self)); - self.write_immediate(Immediate::Scalar(x.into()), dest)?; + let x = Scalar::from_int(0, s.value.size(this)); + this.write_immediate(Immediate::Scalar(x.into()), dest)?; } layout::Abi::ScalarPair(ref s1, ref s2) => { - let x = Scalar::from_int(0, s1.value.size(self)); - let y = Scalar::from_int(0, s2.value.size(self)); - self.write_immediate(Immediate::ScalarPair(x.into(), y.into()), dest)?; + let x = Scalar::from_int(0, s1.value.size(this)); + let y = Scalar::from_int(0, s2.value.size(this)); + this.write_immediate(Immediate::ScalarPair(x.into(), y.into()), dest)?; } _ => { // Do it in memory - let mplace = self.force_allocation(dest)?; + let mplace = this.force_allocation(dest)?; assert!(mplace.meta.is_none()); // not a zst, must be valid pointer let ptr = mplace.ptr.to_ptr()?; - self.memory_mut().get_mut(ptr.alloc_id)?.write_repeat(tcx, ptr, 0, dest.layout.size)?; + this.memory_mut().get_mut(ptr.alloc_id)?.write_repeat(tcx, ptr, 0, dest.layout.size)?; } } } @@ -274,87 +267,87 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "pref_align_of" => { let ty = substs.type_at(0); - let layout = self.layout_of(ty)?; + let layout = this.layout_of(ty)?; let align = layout.align.pref.bytes(); - let ptr_size = self.pointer_size(); + let ptr_size = this.pointer_size(); let align_val = Scalar::from_uint(align as u128, ptr_size); - self.write_scalar(align_val, dest)?; + this.write_scalar(align_val, dest)?; } "move_val_init" => { - let ptr = self.deref_operand(args[0])?; - self.copy_op(args[1], ptr.into())?; + let ptr = this.deref_operand(args[0])?; + this.copy_op(args[1], ptr.into())?; } "offset" => { - let offset = self.read_scalar(args[1])?.to_isize(self)?; - let ptr = self.read_scalar(args[0])?.not_undef()?; - let result_ptr = self.pointer_offset_inbounds(ptr, substs.type_at(0), offset)?; - self.write_scalar(result_ptr, dest)?; + let offset = this.read_scalar(args[1])?.to_isize(this)?; + let ptr = this.read_scalar(args[0])?.not_undef()?; + let result_ptr = this.pointer_offset_inbounds(ptr, substs.type_at(0), offset)?; + this.write_scalar(result_ptr, dest)?; } "powf32" => { - let f = self.read_scalar(args[0])?.to_f32()?; - let f2 = self.read_scalar(args[1])?.to_f32()?; - self.write_scalar( + let f = this.read_scalar(args[0])?.to_f32()?; + let f2 = this.read_scalar(args[1])?.to_f32()?; + this.write_scalar( Scalar::from_f32(f.powf(f2)), dest, )?; } "powf64" => { - let f = self.read_scalar(args[0])?.to_f64()?; - let f2 = self.read_scalar(args[1])?.to_f64()?; - self.write_scalar( + let f = this.read_scalar(args[0])?.to_f64()?; + let f2 = this.read_scalar(args[1])?.to_f64()?; + this.write_scalar( Scalar::from_f64(f.powf(f2)), dest, )?; } "fmaf32" => { - let a = self.read_scalar(args[0])?.to_f32()?; - let b = self.read_scalar(args[1])?.to_f32()?; - let c = self.read_scalar(args[2])?.to_f32()?; - self.write_scalar( + let a = this.read_scalar(args[0])?.to_f32()?; + let b = this.read_scalar(args[1])?.to_f32()?; + let c = this.read_scalar(args[2])?.to_f32()?; + this.write_scalar( Scalar::from_f32(a * b + c), dest, )?; } "fmaf64" => { - let a = self.read_scalar(args[0])?.to_f64()?; - let b = self.read_scalar(args[1])?.to_f64()?; - let c = self.read_scalar(args[2])?.to_f64()?; - self.write_scalar( + let a = this.read_scalar(args[0])?.to_f64()?; + let b = this.read_scalar(args[1])?.to_f64()?; + let c = this.read_scalar(args[2])?.to_f64()?; + this.write_scalar( Scalar::from_f64(a * b + c), dest, )?; } "powif32" => { - let f = self.read_scalar(args[0])?.to_f32()?; - let i = self.read_scalar(args[1])?.to_i32()?; - self.write_scalar( + let f = this.read_scalar(args[0])?.to_f32()?; + let i = this.read_scalar(args[1])?.to_i32()?; + this.write_scalar( Scalar::from_f32(f.powi(i)), dest, )?; } "powif64" => { - let f = self.read_scalar(args[0])?.to_f64()?; - let i = self.read_scalar(args[1])?.to_i32()?; - self.write_scalar( + let f = this.read_scalar(args[0])?.to_f64()?; + let i = this.read_scalar(args[1])?.to_i32()?; + this.write_scalar( Scalar::from_f64(f.powi(i)), dest, )?; } "size_of_val" => { - let mplace = self.deref_operand(args[0])?; - let (size, _) = self.size_and_align_of_mplace(mplace)? + let mplace = this.deref_operand(args[0])?; + let (size, _) = this.size_and_align_of_mplace(mplace)? .expect("size_of_val called on extern type"); - let ptr_size = self.pointer_size(); - self.write_scalar( + let ptr_size = this.pointer_size(); + this.write_scalar( Scalar::from_uint(size.bytes() as u128, ptr_size), dest, )?; @@ -362,11 +355,11 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "min_align_of_val" | "align_of_val" => { - let mplace = self.deref_operand(args[0])?; - let (_, align) = self.size_and_align_of_mplace(mplace)? + let mplace = this.deref_operand(args[0])?; + let (_, align) = this.size_and_align_of_mplace(mplace)? .expect("size_of_val called on extern type"); - let ptr_size = self.pointer_size(); - self.write_scalar( + let ptr_size = this.pointer_size(); + this.write_scalar( Scalar::from_uint(align.bytes(), ptr_size), dest, )?; @@ -375,18 +368,18 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "type_name" => { let ty = substs.type_at(0); let ty_name = ty.to_string(); - let value = self.str_to_immediate(&ty_name)?; - self.write_immediate(value, dest)?; + let value = this.str_to_immediate(&ty_name)?; + this.write_immediate(value, dest)?; } "unchecked_div" => { - let l = self.read_immediate(args[0])?; - let r = self.read_immediate(args[1])?; + let l = this.read_immediate(args[0])?; + let r = this.read_immediate(args[1])?; let rval = r.to_scalar()?.to_bytes()?; if rval == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_div"))); } - self.binop_ignore_overflow( + this.binop_ignore_overflow( mir::BinOp::Div, l, r, @@ -395,13 +388,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } "unchecked_rem" => { - let l = self.read_immediate(args[0])?; - let r = self.read_immediate(args[1])?; + let l = this.read_immediate(args[0])?; + let r = this.read_immediate(args[1])?; let rval = r.to_scalar()?.to_bytes()?; if rval == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_rem"))); } - self.binop_ignore_overflow( + this.binop_ignore_overflow( mir::BinOp::Rem, l, r, @@ -420,18 +413,18 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' match dest.layout.abi { layout::Abi::Scalar(..) => { let x = ScalarMaybeUndef::Undef; - self.write_immediate(Immediate::Scalar(x), dest)?; + this.write_immediate(Immediate::Scalar(x), dest)?; } layout::Abi::ScalarPair(..) => { let x = ScalarMaybeUndef::Undef; - self.write_immediate(Immediate::ScalarPair(x, x), dest)?; + this.write_immediate(Immediate::ScalarPair(x, x), dest)?; } _ => { // Do it in memory - let mplace = self.force_allocation(dest)?; + let mplace = this.force_allocation(dest)?; assert!(mplace.meta.is_none()); let ptr = mplace.ptr.to_ptr()?; - self.memory_mut() + this.memory_mut() .get_mut(ptr.alloc_id)? .mark_definedness(ptr, dest.layout.size, false)?; } @@ -441,15 +434,15 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "write_bytes" => { let ty = substs.type_at(0); - let ty_layout = self.layout_of(ty)?; - let val_byte = self.read_scalar(args[1])?.to_u8()?; - let ptr = self.read_scalar(args[0])?.not_undef()?; - let count = self.read_scalar(args[2])?.to_usize(self)?; - self.memory().check_align(ptr, ty_layout.align.abi)?; + let ty_layout = this.layout_of(ty)?; + let val_byte = this.read_scalar(args[1])?.to_u8()?; + let ptr = this.read_scalar(args[0])?.not_undef()?; + let count = this.read_scalar(args[2])?.to_usize(this)?; + this.memory().check_align(ptr, ty_layout.align.abi)?; let byte_count = ty_layout.size * count; if byte_count.bytes() != 0 { let ptr = ptr.to_ptr()?; - self.memory_mut() + this.memory_mut() .get_mut(ptr.alloc_id)? .write_repeat(tcx, ptr, val_byte, byte_count)?; } diff --git a/src/lib.rs b/src/lib.rs index 9641670a2edf..aabfa36a4b5b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -277,6 +277,21 @@ impl<'tcx> Evaluator<'tcx> { #[allow(dead_code)] // FIXME https://github.com/rust-lang/rust/issues/47131 type MiriEvalContext<'a, 'mir, 'tcx> = EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>; +// A little trait that's useful to be inherited by extension traits +pub trait MiriEvalContextExt<'a, 'mir, 'tcx> { + fn eval_context_ref(&self) -> &MiriEvalContext<'a, 'mir, 'tcx>; + fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'a, 'mir, 'tcx>; +} +impl<'a, 'mir, 'tcx> MiriEvalContextExt<'a, 'mir, 'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { + #[inline(always)] + fn eval_context_ref(&self) -> &MiriEvalContext<'a, 'mir, 'tcx> { + self + } + #[inline(always)] + fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'a, 'mir, 'tcx> { + self + } +} impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { type MemoryKinds = MiriMemoryKind; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index e9fb0aa77797..17da5c152692 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -516,60 +516,14 @@ impl<'tcx> Stacks { } } - - -pub trait EvalContextExt<'tcx> { - fn ptr_dereference( - &self, - place: MPlaceTy<'tcx, Borrow>, - size: Size, - mutability: Option, - ) -> EvalResult<'tcx>; - - fn tag_new_allocation( - &mut self, - id: AllocId, - kind: MemoryKind, - ) -> Borrow; - - /// Reborrow the given place, returning the newly tagged ptr to it. - fn reborrow( - &mut self, - place: MPlaceTy<'tcx, Borrow>, - size: Size, - fn_barrier: bool, - new_bor: Borrow - ) -> EvalResult<'tcx>; - - /// Retag an indidual pointer, returning the retagged version. - fn retag_reference( - &mut self, - ptr: ImmTy<'tcx, Borrow>, - mutbl: Mutability, - fn_barrier: bool, - two_phase: bool, - ) -> EvalResult<'tcx, Immediate>; - - fn retag( - &mut self, - fn_entry: bool, - two_phase: bool, - place: PlaceTy<'tcx, Borrow> - ) -> EvalResult<'tcx>; - - fn escape_to_raw( - &mut self, - place: MPlaceTy<'tcx, Borrow>, - size: Size, - ) -> EvalResult<'tcx>; -} - -impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { +impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} +pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { fn tag_new_allocation( &mut self, id: AllocId, kind: MemoryKind, ) -> Borrow { + let this = self.eval_context_mut(); let time = match kind { MemoryKind::Stack => { // New unique borrow. This `Uniq` is not accessible by the program, @@ -580,7 +534,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { // `reset` which the blog post [1] says to perform when accessing a local. // // [1] https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html - self.machine.stacked_borrows.increment_clock() + this.machine.stacked_borrows.increment_clock() } _ => { // Nothing to do for everything else @@ -588,7 +542,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { } }; // Make this the active borrow for this allocation - let alloc = self.memory_mut().get_mut(id).expect("This is a new allocation, it must still exist"); + let alloc = this.memory_mut().get_mut(id).expect("This is a new allocation, it must still exist"); let size = Size::from_bytes(alloc.bytes.len() as u64); alloc.extra.first_item(BorStackItem::Uniq(time), size); Borrow::Uniq(time) @@ -604,6 +558,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { size: Size, mutability: Option, ) -> EvalResult<'tcx> { + let this = self.eval_context_ref(); trace!("ptr_dereference: Accessing {} reference for {:?} (pointee {})", if let Some(mutability) = mutability { format!("{:?}", mutability) } else { format!("raw") }, place.ptr, place.layout.ty); @@ -614,13 +569,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { } // Get the allocation - let alloc = self.memory().get(ptr.alloc_id)?; - alloc.check_bounds(self, ptr, size)?; + let alloc = this.memory().get(ptr.alloc_id)?; + alloc.check_bounds(this, ptr, size)?; // If we got here, we do some checking, *but* we leave the tag unchanged. if let Borrow::Shr(Some(_)) = ptr.tag { assert_eq!(mutability, Some(MutImmutable)); // We need a frozen-sensitive check - self.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { + this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; alloc.extra.deref(cur_ptr, size, kind) })?; @@ -641,7 +596,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { place: MPlaceTy<'tcx, Borrow>, size: Size, ) -> EvalResult<'tcx> { - self.reborrow(place, size, /*fn_barrier*/ false, Borrow::default())?; + let this = self.eval_context_mut(); + this.reborrow(place, size, /*fn_barrier*/ false, Borrow::default())?; Ok(()) } @@ -652,18 +608,19 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { fn_barrier: bool, new_bor: Borrow ) -> EvalResult<'tcx> { + let this = self.eval_context_mut(); let ptr = place.ptr.to_ptr()?; - let barrier = if fn_barrier { Some(self.frame().extra) } else { None }; + let barrier = if fn_barrier { Some(this.frame().extra) } else { None }; trace!("reborrow: Creating new reference for {:?} (pointee {}): {:?}", ptr, place.layout.ty, new_bor); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. - let alloc = self.memory().get(ptr.alloc_id)?; - alloc.check_bounds(self, ptr, size)?; + let alloc = this.memory().get(ptr.alloc_id)?; + alloc.check_bounds(this, ptr, size)?; // Update the stacks. if let Borrow::Shr(Some(_)) = new_bor { // Reference that cares about freezing. We need a frozen-sensitive reborrow. - self.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { + this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; alloc.extra.reborrow(cur_ptr, size, barrier, new_bor, kind) })?; @@ -675,6 +632,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { Ok(()) } + /// Retag an indidual pointer, returning the retagged version. fn retag_reference( &mut self, val: ImmTy<'tcx, Borrow>, @@ -682,9 +640,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { fn_barrier: bool, two_phase: bool, ) -> EvalResult<'tcx, Immediate> { + let this = self.eval_context_mut(); // We want a place for where the ptr *points to*, so we get one. - let place = self.ref_to_mplace(val)?; - let size = self.size_and_align_of_mplace(place)? + let place = this.ref_to_mplace(val)?; + let size = this.size_and_align_of_mplace(place)? .map(|(size, _)| size) .unwrap_or_else(|| place.layout.size); if size == Size::ZERO { @@ -693,22 +652,22 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { } // Compute new borrow. - let time = self.machine.stacked_borrows.increment_clock(); + let time = this.machine.stacked_borrows.increment_clock(); let new_bor = match mutbl { MutMutable => Borrow::Uniq(time), MutImmutable => Borrow::Shr(Some(time)), }; // Reborrow. - self.reborrow(place, size, fn_barrier, new_bor)?; + this.reborrow(place, size, fn_barrier, new_bor)?; let new_place = place.with_tag(new_bor); // Handle two-phase borrows. if two_phase { assert!(mutbl == MutMutable, "two-phase shared borrows make no sense"); // We immediately share it, to allow read accesses - let two_phase_time = self.machine.stacked_borrows.increment_clock(); + let two_phase_time = this.machine.stacked_borrows.increment_clock(); let two_phase_bor = Borrow::Shr(Some(two_phase_time)); - self.reborrow(new_place, size, /*fn_barrier*/false, two_phase_bor)?; + this.reborrow(new_place, size, /*fn_barrier*/false, two_phase_bor)?; } // Return new ptr. @@ -721,6 +680,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { two_phase: bool, place: PlaceTy<'tcx, Borrow> ) -> EvalResult<'tcx> { + let this = self.eval_context_mut(); // Determine mutability and whether to add a barrier. // Cannot use `builtin_deref` because that reports *immutable* for `Box`, // making it useless. @@ -740,14 +700,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { // avoids allocating. if let Some((mutbl, barrier)) = qualify(place.layout.ty, fn_entry) { // fast path - let val = self.read_immediate(self.place_to_op(place)?)?; - let val = self.retag_reference(val, mutbl, barrier, two_phase)?; - self.write_immediate(val, place)?; + let val = this.read_immediate(this.place_to_op(place)?)?; + let val = this.retag_reference(val, mutbl, barrier, two_phase)?; + this.write_immediate(val, place)?; return Ok(()); } - let place = self.force_allocation(place)?; + let place = this.force_allocation(place)?; - let mut visitor = RetagVisitor { ecx: self, fn_entry, two_phase }; + let mut visitor = RetagVisitor { ecx: this, fn_entry, two_phase }; visitor.visit_value(place)?; // The actual visitor diff --git a/src/tls.rs b/src/tls.rs index af1d7b138b85..5411e021619c 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -34,10 +34,6 @@ impl<'tcx> Default for TlsData<'tcx> { } } -pub trait EvalContextExt<'tcx> { - fn run_tls_dtors(&mut self) -> EvalResult<'tcx>; -} - impl<'tcx> TlsData<'tcx> { pub fn create_tls_key( &mut self, @@ -133,35 +129,37 @@ impl<'tcx> TlsData<'tcx> { } } -impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { +impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} +pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { fn run_tls_dtors(&mut self) -> EvalResult<'tcx> { - let mut dtor = self.machine.tls.fetch_tls_dtor(None, &*self.tcx); + let this = self.eval_context_mut(); + let mut dtor = this.machine.tls.fetch_tls_dtor(None, &*this.tcx); // FIXME: replace loop by some structure that works with stepping while let Some((instance, ptr, key)) = dtor { trace!("Running TLS dtor {:?} on {:?}", instance, ptr); // TODO: Potentially, this has to support all the other possible instances? // See eval_fn_call in interpret/terminator/mod.rs - let mir = self.load_mir(instance.def)?; - let ret_place = MPlaceTy::dangling(self.layout_of(self.tcx.mk_unit())?, self).into(); - self.push_stack_frame( + let mir = this.load_mir(instance.def)?; + let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); + this.push_stack_frame( instance, mir.span, mir, Some(ret_place), StackPopCleanup::None { cleanup: true }, )?; - let arg_local = self.frame().mir.args_iter().next().ok_or_else( + let arg_local = this.frame().mir.args_iter().next().ok_or_else( || EvalErrorKind::AbiViolation("TLS dtor does not take enough arguments.".to_owned()), )?; - let dest = self.eval_place(&mir::Place::Local(arg_local))?; - self.write_scalar(ptr, dest)?; + let dest = this.eval_place(&mir::Place::Local(arg_local))?; + this.write_scalar(ptr, dest)?; // step until out of stackframes - self.run()?; + this.run()?; - dtor = match self.machine.tls.fetch_tls_dtor(Some(key), &*self.tcx) { + dtor = match this.machine.tls.fetch_tls_dtor(Some(key), &*this.tcx) { dtor @ Some(_) => dtor, - None => self.machine.tls.fetch_tls_dtor(None, &*self.tcx), + None => this.machine.tls.fetch_tls_dtor(None, &*this.tcx), }; } // FIXME: On a windows target, call `unsafe extern "system" fn on_tls_callback`. From 383d215386f7b9cb4b08bde9b7fd0db4c3f8112a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 11 Dec 2018 14:18:51 +0100 Subject: [PATCH 0471/5092] make some functions private to StackedBorrows --- src/stacked_borrows.rs | 149 +++++++++++++++++++++-------------------- 1 file changed, 76 insertions(+), 73 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 17da5c152692..748ac020d6a8 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -516,6 +516,82 @@ impl<'tcx> Stacks { } } +impl<'a, 'mir, 'tcx> EvalContextPrivExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} +trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { + fn reborrow( + &mut self, + place: MPlaceTy<'tcx, Borrow>, + size: Size, + fn_barrier: bool, + new_bor: Borrow + ) -> EvalResult<'tcx> { + let this = self.eval_context_mut(); + let ptr = place.ptr.to_ptr()?; + let barrier = if fn_barrier { Some(this.frame().extra) } else { None }; + trace!("reborrow: Creating new reference for {:?} (pointee {}): {:?}", + ptr, place.layout.ty, new_bor); + + // Get the allocation. It might not be mutable, so we cannot use `get_mut`. + let alloc = this.memory().get(ptr.alloc_id)?; + alloc.check_bounds(this, ptr, size)?; + // Update the stacks. + if let Borrow::Shr(Some(_)) = new_bor { + // Reference that cares about freezing. We need a frozen-sensitive reborrow. + this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { + let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; + alloc.extra.reborrow(cur_ptr, size, barrier, new_bor, kind) + })?; + } else { + // Just treat this as one big chunk. + let kind = if new_bor.is_unique() { RefKind::Unique } else { RefKind::Raw }; + alloc.extra.reborrow(ptr, size, barrier, new_bor, kind)?; + } + Ok(()) + } + + /// Retag an indidual pointer, returning the retagged version. + fn retag_reference( + &mut self, + val: ImmTy<'tcx, Borrow>, + mutbl: Mutability, + fn_barrier: bool, + two_phase: bool, + ) -> EvalResult<'tcx, Immediate> { + let this = self.eval_context_mut(); + // We want a place for where the ptr *points to*, so we get one. + let place = this.ref_to_mplace(val)?; + let size = this.size_and_align_of_mplace(place)? + .map(|(size, _)| size) + .unwrap_or_else(|| place.layout.size); + if size == Size::ZERO { + // Nothing to do for ZSTs. + return Ok(*val); + } + + // Compute new borrow. + let time = this.machine.stacked_borrows.increment_clock(); + let new_bor = match mutbl { + MutMutable => Borrow::Uniq(time), + MutImmutable => Borrow::Shr(Some(time)), + }; + + // Reborrow. + this.reborrow(place, size, fn_barrier, new_bor)?; + let new_place = place.with_tag(new_bor); + // Handle two-phase borrows. + if two_phase { + assert!(mutbl == MutMutable, "two-phase shared borrows make no sense"); + // We immediately share it, to allow read accesses + let two_phase_time = this.machine.stacked_borrows.increment_clock(); + let two_phase_bor = Borrow::Shr(Some(two_phase_time)); + this.reborrow(new_place, size, /*fn_barrier*/false, two_phase_bor)?; + } + + // Return new ptr. + Ok(new_place.to_ref()) + } +} + impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { fn tag_new_allocation( @@ -601,79 +677,6 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, Ok(()) } - fn reborrow( - &mut self, - place: MPlaceTy<'tcx, Borrow>, - size: Size, - fn_barrier: bool, - new_bor: Borrow - ) -> EvalResult<'tcx> { - let this = self.eval_context_mut(); - let ptr = place.ptr.to_ptr()?; - let barrier = if fn_barrier { Some(this.frame().extra) } else { None }; - trace!("reborrow: Creating new reference for {:?} (pointee {}): {:?}", - ptr, place.layout.ty, new_bor); - - // Get the allocation. It might not be mutable, so we cannot use `get_mut`. - let alloc = this.memory().get(ptr.alloc_id)?; - alloc.check_bounds(this, ptr, size)?; - // Update the stacks. - if let Borrow::Shr(Some(_)) = new_bor { - // Reference that cares about freezing. We need a frozen-sensitive reborrow. - this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { - let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; - alloc.extra.reborrow(cur_ptr, size, barrier, new_bor, kind) - })?; - } else { - // Just treat this as one big chunk. - let kind = if new_bor.is_unique() { RefKind::Unique } else { RefKind::Raw }; - alloc.extra.reborrow(ptr, size, barrier, new_bor, kind)?; - } - Ok(()) - } - - /// Retag an indidual pointer, returning the retagged version. - fn retag_reference( - &mut self, - val: ImmTy<'tcx, Borrow>, - mutbl: Mutability, - fn_barrier: bool, - two_phase: bool, - ) -> EvalResult<'tcx, Immediate> { - let this = self.eval_context_mut(); - // We want a place for where the ptr *points to*, so we get one. - let place = this.ref_to_mplace(val)?; - let size = this.size_and_align_of_mplace(place)? - .map(|(size, _)| size) - .unwrap_or_else(|| place.layout.size); - if size == Size::ZERO { - // Nothing to do for ZSTs. - return Ok(*val); - } - - // Compute new borrow. - let time = this.machine.stacked_borrows.increment_clock(); - let new_bor = match mutbl { - MutMutable => Borrow::Uniq(time), - MutImmutable => Borrow::Shr(Some(time)), - }; - - // Reborrow. - this.reborrow(place, size, fn_barrier, new_bor)?; - let new_place = place.with_tag(new_bor); - // Handle two-phase borrows. - if two_phase { - assert!(mutbl == MutMutable, "two-phase shared borrows make no sense"); - // We immediately share it, to allow read accesses - let two_phase_time = this.machine.stacked_borrows.increment_clock(); - let two_phase_bor = Borrow::Shr(Some(two_phase_time)); - this.reborrow(new_place, size, /*fn_barrier*/false, two_phase_bor)?; - } - - // Return new ptr. - Ok(new_place.to_ref()) - } - fn retag( &mut self, fn_entry: bool, From 6b376dc3940513b5f7414333a42ce28b47268965 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 11 Dec 2018 14:32:59 +0100 Subject: [PATCH 0472/5092] get rid of to_bytes hack --- src/fn_call.rs | 18 +++++++++--------- src/helpers.rs | 25 ------------------------- src/intrinsic.rs | 8 ++++---- src/lib.rs | 2 +- 4 files changed, 14 insertions(+), 39 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index ea913417a56e..5d41848b643e 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -277,7 +277,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "memrchr" => { let ptr = this.read_scalar(args[0])?.not_undef()?; - let val = this.read_scalar(args[1])?.to_bytes()? as u8; + let val = this.read_scalar(args[1])?.to_i32()? as u8; let num = this.read_scalar(args[2])?.to_usize(this)?; if let Some(idx) = this.memory().read_bytes(ptr, Size::from_bytes(num))? .iter().rev().position(|&c| c == val) @@ -291,7 +291,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "memchr" => { let ptr = this.read_scalar(args[0])?.not_undef()?; - let val = this.read_scalar(args[1])?.to_bytes()? as u8; + let val = this.read_scalar(args[1])?.to_i32()? as u8; let num = this.read_scalar(args[2])?.to_usize(this)?; if let Some(idx) = this.memory().read_bytes(ptr, Size::from_bytes(num))?.iter().position( |&c| c == val, @@ -379,9 +379,9 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } "write" => { - let fd = this.read_scalar(args[0])?.to_bytes()?; + let fd = this.read_scalar(args[0])?.to_i32()?; let buf = this.read_scalar(args[1])?.not_undef()?; - let n = this.read_scalar(args[2])?.to_bytes()? as u64; + let n = this.read_scalar(args[2])?.to_usize(&*this.tcx)?; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { // stdout/stderr @@ -489,18 +489,18 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_null(dest)?; } "pthread_key_delete" => { - let key = this.read_scalar(args[0])?.to_bytes()?; + let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; this.machine.tls.delete_tls_key(key)?; // Return success (0) this.write_null(dest)?; } "pthread_getspecific" => { - let key = this.read_scalar(args[0])?.to_bytes()?; + let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; let ptr = this.machine.tls.load_tls(key)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { - let key = this.read_scalar(args[0])?.to_bytes()?; + let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; let new_ptr = this.read_scalar(args[1])?.not_undef()?; this.machine.tls.store_tls(key, new_ptr)?; @@ -586,12 +586,12 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { - let key = this.read_scalar(args[0])?.to_bytes()?; + let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; let ptr = this.machine.tls.load_tls(key)?; this.write_scalar(ptr, dest)?; } "TlsSetValue" => { - let key = this.read_scalar(args[0])?.to_bytes()?; + let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; let new_ptr = this.read_scalar(args[1])?.not_undef()?; this.machine.tls.store_tls(key, new_ptr)?; diff --git a/src/helpers.rs b/src/helpers.rs index 7be156760508..fab0c67d0aa4 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -5,31 +5,6 @@ use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use crate::*; -pub trait ScalarExt { - /// HACK: this function just extracts all bits if `defined != 0` - /// Mainly used for args of C-functions and we should totally correctly fetch the size - /// of their arguments - fn to_bytes(self) -> EvalResult<'static, u128>; -} - -impl ScalarExt for Scalar { - fn to_bytes(self) -> EvalResult<'static, u128> { - match self { - Scalar::Bits { bits, size } => { - assert_ne!(size, 0); - Ok(bits) - }, - Scalar::Ptr(_) => err!(ReadPointerAsBytes), - } - } -} - -impl ScalarExt for ScalarMaybeUndef { - fn to_bytes(self) -> EvalResult<'static, u128> { - self.not_undef()?.to_bytes() - } -} - impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { /// Get an instance for a path. diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 35182ba5137a..0f7382b61b72 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -6,7 +6,7 @@ use rustc::mir::interpret::{EvalResult, PointerArithmetic}; use crate::{ PlaceTy, OpTy, Immediate, Scalar, ScalarMaybeUndef, Borrow, - ScalarExt, OperatorEvalContextExt + OperatorEvalContextExt }; impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} @@ -227,7 +227,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let a = this.read_immediate(args[0])?; let b = this.read_immediate(args[1])?; // check x % y != 0 - if this.binary_op_imm(mir::BinOp::Rem, a, b)?.0.to_bytes()? != 0 { + if this.binary_op_imm(mir::BinOp::Rem, a, b)?.0.to_bits(dest.layout.size)? != 0 { return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b))); } this.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; @@ -375,7 +375,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "unchecked_div" => { let l = this.read_immediate(args[0])?; let r = this.read_immediate(args[1])?; - let rval = r.to_scalar()?.to_bytes()?; + let rval = r.to_scalar()?.to_bits(args[1].layout.size)?; if rval == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_div"))); } @@ -390,7 +390,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "unchecked_rem" => { let l = this.read_immediate(args[0])?; let r = this.read_immediate(args[1])?; - let rval = r.to_scalar()?.to_bytes()?; + let rval = r.to_scalar()?.to_bits(args[1].layout.size)?; if rval == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_rem"))); } diff --git a/src/lib.rs b/src/lib.rs index aabfa36a4b5b..28639976aa03 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,7 +43,7 @@ pub use crate::intrinsic::EvalContextExt as IntrinsicEvalContextExt; pub use crate::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; use crate::range_map::RangeMap; #[allow(unused_imports)] // FIXME rustc bug https://github.com/rust-lang/rust/issues/53682 -pub use crate::helpers::{ScalarExt, EvalContextExt as HelpersEvalContextExt}; +pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; use crate::mono_hash_map::MonoHashMap; pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; From f31bb43804fd70452eb8e20f83065aad186f8ec5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Nov 2018 15:06:08 +0100 Subject: [PATCH 0473/5092] implement some libc hooks needed by libtest --- src/fn_call.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/fn_call.rs b/src/fn_call.rs index 5d41848b643e..8909223a31d7 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -426,6 +426,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let paths = &[ (&["libc", "_SC_PAGESIZE"], Scalar::from_int(4096, dest.layout.size)), (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)), + (&["libc", "_SC_NPROCESSORS_ONLN"], Scalar::from_int(1, dest.layout.size)), ]; let mut result = None; for &(path, path_value) in paths { @@ -452,6 +453,10 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } } + "isatty" => { + self.write_null(dest)?; + } + // Hook pthread calls that go to the thread-local storage memory subsystem "pthread_key_create" => { let key_ptr = this.read_scalar(args[0])?.to_ptr()?; From 9417b28de55888d99aeefcd03243294b658b4d97 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Nov 2018 15:06:23 +0100 Subject: [PATCH 0474/5092] treat test binaries like all others --- src/bin/cargo-miri.rs | 5 ++--- src/bin/miri.rs | 43 +++++-------------------------------------- 2 files changed, 7 insertions(+), 41 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 7e1785fd3b93..179f11dd56a3 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -279,9 +279,8 @@ fn main() { (MiriCommand::Test, "lib") => { // For libraries we call `cargo rustc -- --test ` // Notice now that `--test` is a rustc arg rather than a cargo arg. This tells - // rustc to build a test harness which calls all #[test] functions. We don't - // use the harness since we execute each #[test] function's MIR ourselves before - // compilation even completes, but this option is necessary to build the library. + // rustc to build a test harness which calls all #[test] functions. + // We then execute that harness just like any other binary. if let Err(code) = process( vec!["--".to_string(), "--test".to_string()].into_iter().chain( args, diff --git a/src/bin/miri.rs b/src/bin/miri.rs index e88c13305d15..c2255d706339 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -23,8 +23,6 @@ use rustc_metadata::cstore::CStore; use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls}; use rustc_driver::driver::{CompileState, CompileController}; use rustc::session::config::{self, Input, ErrorOutputType}; -use rustc::hir::{self, itemlikevisit}; -use rustc::ty::TyCtxt; use rustc_codegen_utils::codegen_backend::CodegenBackend; use syntax::ast; @@ -115,43 +113,12 @@ fn after_analysis<'a, 'tcx>( let tcx = state.tcx.unwrap(); - if std::env::args().any(|arg| arg == "--test") { - struct Visitor<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - state: &'a CompileState<'a, 'tcx>, - validate: bool, - }; - impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> { - fn visit_item(&mut self, i: &'hir hir::Item) { - if let hir::ItemKind::Fn(.., body_id) = i.node { - if i.attrs.iter().any(|attr| { - attr.name() == "test" - }) - { - let did = self.tcx.hir().body_owner_def_id(body_id); - println!( - "running test: {}", - self.tcx.def_path_debug_str(did), - ); - miri::eval_main(self.tcx, did, self.validate); - self.state.session.abort_if_errors(); - } - } - } - fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {} - fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {} - } - state.hir_crate.unwrap().visit_all_item_likes( - &mut Visitor { tcx, state, validate } - ); - } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { - let entry_def_id = tcx.hir().local_def_id(entry_node_id); - miri::eval_main(tcx, entry_def_id, validate); + let (entry_node_id, _, _) = state.session.entry_fn.borrow().expect("no main function found!"); + let entry_def_id = tcx.hir().local_def_id(entry_node_id); - state.session.abort_if_errors(); - } else { - println!("no main function found, assuming auxiliary build"); - } + miri::eval_main(tcx, entry_def_id, validate); + + state.session.abort_if_errors(); } fn init_early_loggers() { From 3fda8294bdc8dedfc299cd15d0d40c19d7da598f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Nov 2018 15:06:51 +0100 Subject: [PATCH 0475/5092] test cargo miri test output when testing cargo miri --- test-cargo-miri/run-test.py | 21 ++++++++++++--------- test-cargo-miri/test.stderr.ref | 0 test-cargo-miri/test.stdout.ref | 7 +++++++ test-cargo-miri/tests/foo.rs | 7 +++++++ 4 files changed, 26 insertions(+), 9 deletions(-) create mode 100644 test-cargo-miri/test.stderr.ref create mode 100644 test-cargo-miri/test.stdout.ref diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 42745535e0ef..c7ab8f14df88 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -7,11 +7,11 @@ and the working directory to contain the cargo-miri-test project. import sys, subprocess -def test_cargo_miri(): - print("==> Testing `cargo miri run` <==") +def test(name, cmd, stdout_ref, stderr_ref): + print("==> Testing `{}` <==".format(name)) ## Call `cargo miri`, capture all output p = subprocess.Popen( - ["cargo", "miri", "run", "-q"], + cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) @@ -26,17 +26,20 @@ def test_cargo_miri(): # Test for failures if p.returncode != 0: sys.exit(1) - if stdout != open('stdout.ref').read(): + if stdout != open(stdout_ref).read(): print("stdout does not match reference") sys.exit(1) - if stderr != open('stderr.ref').read(): + if stderr != open(stderr_ref).read(): print("stderr does not match reference") sys.exit(1) -def test_cargo_miri_test(): - print("==> Testing `cargo miri test` <==") - subprocess.check_call(["cargo", "miri", "test"]) +def test_cargo_miri_run(): + test("cargo miri run", ["cargo", "miri", "run", "-q"], "stout.ref", "stderr.ref") -test_cargo_miri() +def test_cargo_miri_test(): + # FIXME: validation disabled for now because of https://github.com/rust-lang/rust/issues/54957 + test("cargo miri test", ["cargo", "miri", "test", "-q", "--", "-Zmiri-disable-validation"], "stout.ref", "stderr.ref") + +test_cargo_miri_run() test_cargo_miri_test() sys.exit(0) diff --git a/test-cargo-miri/test.stderr.ref b/test-cargo-miri/test.stderr.ref new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/test-cargo-miri/test.stdout.ref b/test-cargo-miri/test.stdout.ref new file mode 100644 index 000000000000..94fd56b0cd6f --- /dev/null +++ b/test-cargo-miri/test.stdout.ref @@ -0,0 +1,7 @@ + +running 2 tests +test bar ... ok +test baz ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out + diff --git a/test-cargo-miri/tests/foo.rs b/test-cargo-miri/tests/foo.rs index fb7fad21c9db..9827ae82d6cf 100644 --- a/test-cargo-miri/tests/foo.rs +++ b/test-cargo-miri/tests/foo.rs @@ -2,3 +2,10 @@ fn bar() { assert_eq!(4, 4); } + +// Having more than 1 test does seem to make a difference +// (i.e., this calls ptr::swap which having just one test does not). +#[test] +fn baz() { + assert_eq!(5, 5); +} From ce5089c3905f7051a9bcdc92ef24ba934dc75098 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 11 Dec 2018 17:54:39 +0100 Subject: [PATCH 0476/5092] rebase fallout --- src/fn_call.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 8909223a31d7..d11364ce0d18 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -454,7 +454,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } "isatty" => { - self.write_null(dest)?; + this.write_null(dest)?; } // Hook pthread calls that go to the thread-local storage memory subsystem From 8ec371747a742d8f96effe80b9bfcfa53ff6fa62 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Dec 2018 11:03:42 +0100 Subject: [PATCH 0477/5092] do not auto-detect the targets in the sysroot, instead specify target manually through env var --- .travis.yml | 14 ++++--- README.md | 12 +++++- tests/compiletest.rs | 89 ++++++++++++-------------------------------- 3 files changed, 41 insertions(+), 74 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1d49394e29b8..a58ff4f67d8d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,6 +29,12 @@ before_script: else export MIRI_SYSROOT_BASE=~/.cache/miri/ fi +- | + if [[ "$TRAVIS_OS_NAME" == osx ]]; then + FOREIGN_TARGET=i686-apple-darwin + else + FOREIGN_TARGET=i686-unknown-linux-gnu + fi # install Rust - curl https://build.travis-ci.org/files/rustup-init.sh -sSf | sh -s -- -y --default-toolchain "$RUST_TOOLCHAIN" - export PATH=$HOME/.cargo/bin:$PATH @@ -43,15 +49,11 @@ script: - | # Get ourselves a MIR-full libstd for the host and a foreign architecture cargo miri setup && - if [[ "$TRAVIS_OS_NAME" == osx ]]; then - cargo miri setup --target i686-apple-darwin - else - cargo miri setup --target i686-unknown-linux-gnu - fi + cargo miri setup --target "$FOREIGN_TARGET" - | # Test miri with full MIR, on the host and other architectures MIRI_SYSROOT=$MIRI_SYSROOT_BASE/HOST cargo test --release --all-features && - MIRI_SYSROOT=$MIRI_SYSROOT_BASE cargo test --release --all-features + MIRI_SYSROOT=$MIRI_SYSROOT_BASE MIRI_TARGET=$FOREIGN_TARGET cargo test --release --all-features - | # Test cargo integration (cd test-cargo-miri && MIRI_SYSROOT=$MIRI_SYSROOT_BASE/HOST ./run-test.py) diff --git a/README.md b/README.md index 1b9e5304bd03..b6e1c20076de 100644 --- a/README.md +++ b/README.md @@ -154,9 +154,9 @@ MIRI_LOG=rustc_mir::interpret=debug,miri::stacked_borrows cargo run tests/run-pa In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an evaluation error was originally created. -### Miri `-Z` flags +### Miri `-Z` flags and environment variables -Several `-Z` flags are relevant for miri: +Several `-Z` flags are relevant for Miri: * `-Zmir-opt-level` controls how many MIR optimizations are performed. miri overrides the default to be `0`; be advised that using any higher level can @@ -168,6 +168,14 @@ Several `-Z` flags are relevant for miri: enforcing the validity invariant, which is enforced by default. This is mostly useful for debugging; it means miri will miss bugs in your program. +Moreover, Miri recognizes some environment variables: + +* `MIRI_SYSROOT` (recognized by `miri`, `cargo miri` and the test suite) + indicates the sysroot to use. +* `MIRI_TARGET` (recognized by the test suite) indicates which target + architecture to test against. `miri` and `cargo miri` accept the `--target` + flag for the same purpose. + ## Contributing and getting help Check out the issues on this GitHub repository for some ideas. There's lots that diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 7187a3caee25..a0862d00326c 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -34,10 +34,11 @@ fn mk_config(mode: &str) -> compiletest::common::ConfigWithTemp { config.compile_lib_path = rustc_lib_path(); } config.filter = env::args().nth(1); + config.host = get_host(); config } -fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, opt: bool) { +fn compile_fail(path: &str, target: &str, opt: bool) { let opt_str = if opt { " with optimizations" } else { "" }; eprintln!("{}", format!( "## Running compile-fail tests in {} against miri for target {}{}", @@ -47,7 +48,6 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, opt: bool) ).green().bold()); let mut flags = Vec::new(); - flags.push(format!("--sysroot {}", sysroot.display())); flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs flags.push("--edition 2018".to_owned()); if opt { @@ -60,12 +60,11 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, opt: bool) let mut config = mk_config("compile-fail"); config.src_base = PathBuf::from(path); config.target = target.to_owned(); - config.host = host.to_owned(); config.target_rustcflags = Some(flags.join(" ")); compiletest::run_tests(&config); } -fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, opt: bool) { +fn miri_pass(path: &str, target: &str, opt: bool) { let opt_str = if opt { " with optimizations" } else { "" }; eprintln!("{}", format!( "## Running run-pass tests in {} against miri for target {}{}", @@ -75,7 +74,6 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, opt: bool) { ).green().bold()); let mut flags = Vec::new(); - flags.push(format!("--sysroot {}", sysroot.display())); flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs flags.push("--edition 2018".to_owned()); if opt { @@ -87,57 +85,24 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, opt: bool) { let mut config = mk_config("ui"); config.src_base = PathBuf::from(path); config.target = target.to_owned(); - config.host = host.to_owned(); config.target_rustcflags = Some(flags.join(" ")); compiletest::run_tests(&config); } -fn is_target_dir>(path: P) -> bool { - let mut path = path.into(); - path.push("lib"); - path.metadata().map(|m| m.is_dir()).unwrap_or(false) -} - -fn target_has_std>(path: P) -> bool { - let mut path = path.into(); - path.push("lib"); - std::fs::read_dir(path) - .expect("invalid target") - .map(|entry| entry.unwrap()) - .filter(|entry| entry.file_type().unwrap().is_file()) - .filter_map(|entry| entry.file_name().into_string().ok()) - .any(|file_name| file_name == "libstd.rlib") -} - - -fn for_all_targets(sysroot: &Path, f: F) { - let target_dir = sysroot.join("lib").join("rustlib"); - let mut targets = std::fs::read_dir(target_dir) - .expect("invalid sysroot") - .map(|entry| entry.unwrap()) - .filter(|entry| is_target_dir(entry.path())) - .filter(|entry| target_has_std(entry.path())) - .map(|entry| entry.file_name().into_string().unwrap()) - .peekable(); - - if targets.peek().is_none() { - panic!("No valid targets found"); +/// Make sure the MIRI_SYSROOT env var is set +fn set_sysroot() { + if std::env::var("MIRI_SYSROOT").is_ok() { + // Nothing to do + return; } - - targets.for_each(f); -} - -fn get_sysroot() -> PathBuf { - let sysroot = std::env::var("MIRI_SYSROOT").unwrap_or_else(|_| { - let sysroot = std::process::Command::new("rustc") - .arg("--print") - .arg("sysroot") - .output() - .expect("rustc not found") - .stdout; - String::from_utf8(sysroot).expect("sysroot is not utf8") - }); - PathBuf::from(sysroot.trim()) + let sysroot = std::process::Command::new("rustc") + .arg("--print") + .arg("sysroot") + .output() + .expect("rustc not found") + .stdout; + let sysroot = String::from_utf8(sysroot).expect("sysroot is not utf8"); + std::env::set_var("MIRI_SYSROOT", sysroot.trim()); } fn get_host() -> String { @@ -153,28 +118,20 @@ fn get_host() -> String { version_meta.host } -fn run_pass_miri(opt: bool) { - let sysroot = get_sysroot(); - let host = get_host(); +fn get_target() -> String { + std::env::var("MIRI_TARGET").unwrap_or_else(|_| get_host()) +} - for_all_targets(&sysroot, |target| { - miri_pass(&sysroot, "tests/run-pass", &target, &host, opt); - }); +fn run_pass_miri(opt: bool) { + miri_pass("tests/run-pass", &get_target(), opt); } fn compile_fail_miri(opt: bool) { - let sysroot = get_sysroot(); - let host = get_host(); - - for_all_targets(&sysroot, |target| { - compile_fail(&sysroot, "tests/compile-fail", &target, &host, opt); - }); + compile_fail("tests/compile-fail", &get_target(), opt); } fn test_runner(_tests: &[&()]) { - // We put everything into a single test to avoid the parallelism `cargo test` - // introduces. We still get parallelism within our tests because `compiletest` - // uses `libtest` which runs jobs in parallel. + set_sysroot(); run_pass_miri(false); run_pass_miri(true); From 7e9098ff692eccd07c509f1a6bee1328e8882d34 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Dec 2018 11:11:20 +0100 Subject: [PATCH 0478/5092] treat ref-to-raw cast like a reborrow: do a special kind of retag --- src/lib.rs | 30 +---------- src/stacked_borrows.rs | 52 +++++++++---------- .../stacked_borrows/transmute-is-no-escape.rs | 9 ++-- 3 files changed, 31 insertions(+), 60 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 28639976aa03..e821b4f76a34 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -474,36 +474,10 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { } } - #[inline] - fn escape_to_raw( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - ptr: OpTy<'tcx, Self::PointerTag>, - ) -> EvalResult<'tcx> { - // It is tempting to check the type here, but drop glue does EscapeToRaw - // on a raw pointer. - // This is deliberately NOT `deref_operand` as we do not want `tag_dereference` - // to be called! That would kill the original tag if we got a raw ptr. - let place = ecx.ref_to_mplace(ecx.read_immediate(ptr)?)?; - let size = ecx.size_and_align_of_mplace(place)?.map(|(size, _)| size) - // for extern types, just cover what we can - .unwrap_or_else(|| place.layout.size); - if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || - !ecx.machine.validate || size == Size::ZERO - { - // No tracking, or no retagging. The latter is possible because a dependency of ours - // might be called with different flags than we are, so there are `Retag` - // statements but we do not want to execute them. - Ok(()) - } else { - ecx.escape_to_raw(place, size) - } - } - #[inline(always)] fn retag( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - fn_entry: bool, - two_phase: bool, + kind: mir::RetagKind, place: PlaceTy<'tcx, Borrow>, ) -> EvalResult<'tcx> { if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !Self::enforce_validity(ecx) { @@ -514,7 +488,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { // uninitialized data. Ok(()) } else { - ecx.retag(fn_entry, two_phase, place) + ecx.retag(kind, place) } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 748ac020d6a8..27d4a4f7f7b5 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -4,6 +4,7 @@ use std::rc::Rc; use rustc::ty::{self, layout::Size}; use rustc::hir::{Mutability, MutMutable, MutImmutable}; +use rustc::mir::RetagKind; use crate::{ EvalResult, EvalErrorKind, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, @@ -550,10 +551,11 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } /// Retag an indidual pointer, returning the retagged version. + /// `mutbl` can be `None` to make this a raw pointer. fn retag_reference( &mut self, val: ImmTy<'tcx, Borrow>, - mutbl: Mutability, + mutbl: Option, fn_barrier: bool, two_phase: bool, ) -> EvalResult<'tcx, Immediate> { @@ -571,8 +573,9 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // Compute new borrow. let time = this.machine.stacked_borrows.increment_clock(); let new_bor = match mutbl { - MutMutable => Borrow::Uniq(time), - MutImmutable => Borrow::Shr(Some(time)), + Some(MutMutable) => Borrow::Uniq(time), + Some(MutImmutable) => Borrow::Shr(Some(time)), + None => Borrow::default(), }; // Reborrow. @@ -580,7 +583,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let new_place = place.with_tag(new_bor); // Handle two-phase borrows. if two_phase { - assert!(mutbl == MutMutable, "two-phase shared borrows make no sense"); + assert!(mutbl == Some(MutMutable), "two-phase shared borrows make no sense"); // We immediately share it, to allow read accesses let two_phase_time = this.machine.stacked_borrows.increment_clock(); let two_phase_bor = Borrow::Shr(Some(two_phase_time)); @@ -665,35 +668,24 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, Ok(()) } - /// The given place may henceforth be accessed through raw pointers. - #[inline(always)] - fn escape_to_raw( - &mut self, - place: MPlaceTy<'tcx, Borrow>, - size: Size, - ) -> EvalResult<'tcx> { - let this = self.eval_context_mut(); - this.reborrow(place, size, /*fn_barrier*/ false, Borrow::default())?; - Ok(()) - } - fn retag( &mut self, - fn_entry: bool, - two_phase: bool, + kind: RetagKind, place: PlaceTy<'tcx, Borrow> ) -> EvalResult<'tcx> { let this = self.eval_context_mut(); // Determine mutability and whether to add a barrier. // Cannot use `builtin_deref` because that reports *immutable* for `Box`, // making it useless. - fn qualify(ty: ty::Ty<'_>, fn_entry: bool) -> Option<(Mutability, bool)> { + fn qualify(ty: ty::Ty<'_>, kind: RetagKind) -> Option<(Option, bool)> { match ty.sty { // References are simple - ty::Ref(_, _, mutbl) => Some((mutbl, fn_entry)), + ty::Ref(_, _, mutbl) => Some((Some(mutbl), kind == RetagKind::FnEntry)), + // Raw pointers need to be enabled + ty::RawPtr(..) if kind == RetagKind::Raw => Some((None, false)), // Boxes do not get a barrier: Barriers reflect that references outlive the call // they were passed in to; that's just not the case for boxes. - ty::Adt(..) if ty.is_box() => Some((MutMutable, false)), + ty::Adt(..) if ty.is_box() => Some((Some(MutMutable), false)), _ => None, } } @@ -701,23 +693,22 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // We need a visitor to visit all references. However, that requires // a `MemPlace`, so we have a fast path for reference types that // avoids allocating. - if let Some((mutbl, barrier)) = qualify(place.layout.ty, fn_entry) { + if let Some((mutbl, barrier)) = qualify(place.layout.ty, kind) { // fast path let val = this.read_immediate(this.place_to_op(place)?)?; - let val = this.retag_reference(val, mutbl, barrier, two_phase)?; + let val = this.retag_reference(val, mutbl, barrier, kind == RetagKind::TwoPhase)?; this.write_immediate(val, place)?; return Ok(()); } let place = this.force_allocation(place)?; - let mut visitor = RetagVisitor { ecx: this, fn_entry, two_phase }; + let mut visitor = RetagVisitor { ecx: this, kind }; visitor.visit_value(place)?; // The actual visitor struct RetagVisitor<'ecx, 'a, 'mir, 'tcx> { ecx: &'ecx mut MiriEvalContext<'a, 'mir, 'tcx>, - fn_entry: bool, - two_phase: bool, + kind: RetagKind, } impl<'ecx, 'a, 'mir, 'tcx> MutValueVisitor<'a, 'mir, 'tcx, Evaluator<'tcx>> @@ -736,9 +727,14 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, { // Cannot use `builtin_deref` because that reports *immutable* for `Box`, // making it useless. - if let Some((mutbl, barrier)) = qualify(place.layout.ty, self.fn_entry) { + if let Some((mutbl, barrier)) = qualify(place.layout.ty, self.kind) { let val = self.ecx.read_immediate(place.into())?; - let val = self.ecx.retag_reference(val, mutbl, barrier, self.two_phase)?; + let val = self.ecx.retag_reference( + val, + mutbl, + barrier, + self.kind == RetagKind::TwoPhase + )?; self.ecx.write_immediate(val, place.into())?; } Ok(()) diff --git a/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs b/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs index 75abce3111f8..197c11197efa 100644 --- a/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs +++ b/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs @@ -1,13 +1,14 @@ // Make sure we cannot use raw ptrs that got transmuted from mutable references // (i.e, no EscapeToRaw happened). -// We could, in principle, to EscapeToRaw lazily to allow this code, but that +// We could, in principle, do EscapeToRaw lazily to allow this code, but that // would no alleviate the need for EscapeToRaw (see `ref_raw_int_raw` in // `run-pass/stacked-borrows.rs`), and thus increase overall complexity. use std::mem; fn main() { - let mut x: i32 = 42; - let raw: *mut i32 = unsafe { mem::transmute(&mut x) }; - let raw = raw as usize as *mut i32; // make sure we killed the tag + let mut x: [i32; 2] = [42, 43]; + let _raw: *mut i32 = unsafe { mem::transmute(&mut x[0]) }; + // `raw` still carries a tag, so we get another pointer to the same location that does not carry a tag + let raw = (&mut x[1] as *mut i32).wrapping_offset(-1); unsafe { *raw = 13; } //~ ERROR does not exist on the stack } From ed83cc2600049adaf7d142ff7f5defb3c691d6b2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Dec 2018 17:03:40 +0100 Subject: [PATCH 0479/5092] use RUSTC_WRAPPER for the cargo hook --- src/bin/cargo-miri.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 7e1785fd3b93..f428062b3fc4 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -305,8 +305,8 @@ fn main() { _ => {} } } - } else { - // This arm is executed when cargo-miri runs `cargo rustc` with the `RUSTC` env var set to itself: + } else if let Some("rustc") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { + // This arm is executed when cargo-miri runs `cargo rustc` with the `RUSTC_WRAPPER` env var set to itself: // Dependencies get dispatched to rustc, the final test/binary to miri. let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); @@ -332,11 +332,11 @@ fn main() { // this conditional check for the --sysroot flag is there so users can call `cargo-miri` directly // without having to pass --sysroot or anything + let rustc_args = std::env::args().skip(2); let mut args: Vec = if std::env::args().any(|s| s == "--sysroot") { - std::env::args().skip(1).collect() + rustc_args.collect() } else { - std::env::args() - .skip(1) + rustc_args .chain(Some("--sysroot".to_owned())) .chain(Some(sys_root)) .collect() @@ -365,6 +365,8 @@ fn main() { Err(ref e) if miri_enabled => panic!("error during miri run: {:?}", e), Err(ref e) => panic!("error during rustc call: {:?}", e), } + } else { + eprintln!("Unexpected call: Must be called with either `miri` or `rustc` as first argument.") } } @@ -389,7 +391,7 @@ where let path = std::env::current_exe().expect("current executable path invalid"); let exit_status = Command::new("cargo") .args(&args) - .env("RUSTC", path) + .env("RUSTC_WRAPPER", path) .spawn() .expect("could not run cargo") .wait() From b6a4556cb9d6458bb97c8e8ff91e71b7c13d094b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Dec 2018 17:05:23 +0100 Subject: [PATCH 0480/5092] use show_error to terminate --- src/bin/cargo-miri.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index f428062b3fc4..71cd46314b5a 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -366,7 +366,7 @@ fn main() { Err(ref e) => panic!("error during rustc call: {:?}", e), } } else { - eprintln!("Unexpected call: Must be called with either `miri` or `rustc` as first argument.") + show_error!("Must be called with either `miri` or `rustc` as first argument.") } } From e6147ae67eaad7ba2de11ae8e4a57c5cc022dd29 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Dec 2018 17:30:20 +0100 Subject: [PATCH 0481/5092] *oops* --- src/bin/cargo-miri.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 71cd46314b5a..6d2dc1dd2f1a 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -366,7 +366,7 @@ fn main() { Err(ref e) => panic!("error during rustc call: {:?}", e), } } else { - show_error!("Must be called with either `miri` or `rustc` as first argument.") + show_error(format!("Must be called with either `miri` or `rustc` as first argument.")) } } From 74e9ed998b68de78c6bde206537cdb05b6cd2a6a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Dec 2018 19:15:57 +0100 Subject: [PATCH 0482/5092] move travis commands to script file, maybe that fixes the macOS weirdness --- .travis.yml | 33 ++------------------------------- travis.sh | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 31 deletions(-) create mode 100755 travis.sh diff --git a/.travis.yml b/.travis.yml index a58ff4f67d8d..dfc4238a6c03 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,10 +12,8 @@ os: dist: xenial before_script: -# install extra stuff for cross-compilation +# Linux: install extra stuff for cross-compilation - if [[ "$TRAVIS_OS_NAME" == linux ]]; then sudo apt update && sudo apt install gcc-multilib; fi -# macOS weirdness (https://github.com/travis-ci/travis-ci/issues/6307, https://github.com/travis-ci/travis-ci/issues/10165) -- if [[ "$TRAVIS_OS_NAME" == osx ]]; then rvm get stable; fi # Compute the rust version we use. We do not use "language: rust" to have more control here. - | if [[ "$TRAVIS_EVENT_TYPE" == cron ]]; then @@ -23,40 +21,13 @@ before_script: else RUST_TOOLCHAIN=$(cat rust-version) fi -- | - if [ "$TRAVIS_OS_NAME" == osx ]; then - export MIRI_SYSROOT_BASE=~/Library/Caches/miri.miri.miri/ - else - export MIRI_SYSROOT_BASE=~/.cache/miri/ - fi -- | - if [[ "$TRAVIS_OS_NAME" == osx ]]; then - FOREIGN_TARGET=i686-apple-darwin - else - FOREIGN_TARGET=i686-unknown-linux-gnu - fi # install Rust - curl https://build.travis-ci.org/files/rustup-init.sh -sSf | sh -s -- -y --default-toolchain "$RUST_TOOLCHAIN" - export PATH=$HOME/.cargo/bin:$PATH - rustc --version script: -- set -e -- | - # Build and install miri - cargo build --release --all-features --all-targets && - cargo install --all-features --force --path . -- | - # Get ourselves a MIR-full libstd for the host and a foreign architecture - cargo miri setup && - cargo miri setup --target "$FOREIGN_TARGET" -- | - # Test miri with full MIR, on the host and other architectures - MIRI_SYSROOT=$MIRI_SYSROOT_BASE/HOST cargo test --release --all-features && - MIRI_SYSROOT=$MIRI_SYSROOT_BASE MIRI_TARGET=$FOREIGN_TARGET cargo test --release --all-features -- | - # Test cargo integration - (cd test-cargo-miri && MIRI_SYSROOT=$MIRI_SYSROOT_BASE/HOST ./run-test.py) +- ./travis.sh notifications: email: diff --git a/travis.sh b/travis.sh new file mode 100755 index 000000000000..4dc368155cb9 --- /dev/null +++ b/travis.sh @@ -0,0 +1,26 @@ +#!/bin/bash +set -e + +# Determine configuration +if [ "$TRAVIS_OS_NAME" == osx ]; then + export MIRI_SYSROOT_BASE=~/Library/Caches/miri.miri.miri/ + FOREIGN_TARGET=i686-apple-darwin +else + export MIRI_SYSROOT_BASE=~/.cache/miri/ + FOREIGN_TARGET=i686-unknown-linux-gnu +fi + +# Build and install miri +cargo build --release --all-features --all-targets && +cargo install --all-features --force --path . + +# Get ourselves a MIR-full libstd for the host and a foreign architecture +cargo miri setup && +cargo miri setup --target "$FOREIGN_TARGET" + +# Test miri with full MIR, on the host and other architectures +MIRI_SYSROOT=$MIRI_SYSROOT_BASE/HOST cargo test --release --all-features && +MIRI_SYSROOT=$MIRI_SYSROOT_BASE MIRI_TARGET=$FOREIGN_TARGET cargo test --release --all-features + +# Test cargo integration +(cd test-cargo-miri && MIRI_SYSROOT=$MIRI_SYSROOT_BASE/HOST ./run-test.py) From 5ff67363cbb6a0818c53b5cfa6a985a24614722f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Dec 2018 19:51:52 +0100 Subject: [PATCH 0483/5092] fix warning --- tests/compiletest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index a0862d00326c..31f0eb0c1386 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -3,7 +3,7 @@ #![test_runner(test_runner)] use std::slice::SliceConcatExt; -use std::path::{PathBuf, Path}; +use std::path::PathBuf; use std::env; use compiletest_rs as compiletest; From ee2b5bb6bbd8867bc964a25a464278d61e5ff112 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Dec 2018 19:52:49 +0100 Subject: [PATCH 0484/5092] travis: explain what we are doing --- travis.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/travis.sh b/travis.sh index 4dc368155cb9..e11d3e17c023 100755 --- a/travis.sh +++ b/travis.sh @@ -10,17 +10,21 @@ else FOREIGN_TARGET=i686-unknown-linux-gnu fi -# Build and install miri +echo "Build and install miri" cargo build --release --all-features --all-targets && cargo install --all-features --force --path . +echo -# Get ourselves a MIR-full libstd for the host and a foreign architecture +echo "Get ourselves a MIR-full libstd for the host and a foreign architecture" cargo miri setup && cargo miri setup --target "$FOREIGN_TARGET" +echo -# Test miri with full MIR, on the host and other architectures +echo "Test miri with full MIR, on the host and other architectures" MIRI_SYSROOT=$MIRI_SYSROOT_BASE/HOST cargo test --release --all-features && MIRI_SYSROOT=$MIRI_SYSROOT_BASE MIRI_TARGET=$FOREIGN_TARGET cargo test --release --all-features +echo -# Test cargo integration +echo "Test cargo integration" (cd test-cargo-miri && MIRI_SYSROOT=$MIRI_SYSROOT_BASE/HOST ./run-test.py) +echo From 8bd1f78563b33bfc8664289ca3dad88cf4da613e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 13 Dec 2018 20:25:24 +0100 Subject: [PATCH 0485/5092] fix libc feature gate --- tests/run-pass/foreign-fn-linkname.rs | 2 +- tests/run-pass/regions-mock-trans.rs | 2 +- tests/run-pass/thread-local.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/run-pass/foreign-fn-linkname.rs b/tests/run-pass/foreign-fn-linkname.rs index 3dd30fd676fd..f2ed67385cdc 100644 --- a/tests/run-pass/foreign-fn-linkname.rs +++ b/tests/run-pass/foreign-fn-linkname.rs @@ -10,7 +10,7 @@ //ignore-windows: Uses POSIX APIs -#![feature(libc)] +#![feature(rustc_private)] #![allow(unused_extern_crates)] // rustc bug https://github.com/rust-lang/rust/issues/56098 extern crate libc; diff --git a/tests/run-pass/regions-mock-trans.rs b/tests/run-pass/regions-mock-trans.rs index 130eaa288ebe..62931493aa00 100644 --- a/tests/run-pass/regions-mock-trans.rs +++ b/tests/run-pass/regions-mock-trans.rs @@ -10,7 +10,7 @@ //ignore-windows: Uses POSIX APIs -#![feature(libc)] +#![feature(rustc_private)] #![allow(dead_code)] diff --git a/tests/run-pass/thread-local.rs b/tests/run-pass/thread-local.rs index 8c20e89ab52d..aeedb7034ce5 100644 --- a/tests/run-pass/thread-local.rs +++ b/tests/run-pass/thread-local.rs @@ -1,6 +1,6 @@ //ignore-windows: Uses POSIX APIs -#![feature(libc)] +#![feature(rustc_private)] extern crate libc; use std::mem; From b0581caeef3278d020aee44c7f5a7736504df401 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 13 Dec 2018 22:05:46 +0100 Subject: [PATCH 0486/5092] VecDeque got fixed --- tests/run-pass/vecdeque.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/run-pass/vecdeque.rs b/tests/run-pass/vecdeque.rs index d92cff0b084e..381169505ec9 100644 --- a/tests/run-pass/vecdeque.rs +++ b/tests/run-pass/vecdeque.rs @@ -1,6 +1,3 @@ -// FIXME: Validation disabled until https://github.com/rust-lang/rust/pull/56161 lands -// compile-flags: -Zmiri-disable-validation - use std::collections::VecDeque; fn main() { From e2505dd945923fa5ed057a2ee3080154fa356e0a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 13 Dec 2018 22:07:57 +0100 Subject: [PATCH 0487/5092] we have no whitelist any more, go back to opt-level 3 --- tests/compiletest.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 31f0eb0c1386..f125100f8343 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -77,9 +77,7 @@ fn miri_pass(path: &str, target: &str, opt: bool) { flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs flags.push("--edition 2018".to_owned()); if opt { - // FIXME: We use opt level 1 because MIR inlining defeats the validation - // whitelist. - flags.push("-Zmir-opt-level=1".to_owned()); + flags.push("-Zmir-opt-level=3".to_owned()); } let mut config = mk_config("ui"); From fbad6c031083d6c30b6e3dd7d685f9c0c688b716 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 14 Dec 2018 08:12:39 +0100 Subject: [PATCH 0488/5092] bump Rust nightly --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 69d072f1bfa0..2ad896fe0519 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-12-08 +nightly-2018-12-14 From 6bc3a488025b5525173b64fc691785aa67fced47 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 15 Dec 2018 14:13:46 +0100 Subject: [PATCH 0489/5092] tweak travis.sh --- travis.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/travis.sh b/travis.sh index e11d3e17c023..aded53b1579d 100755 --- a/travis.sh +++ b/travis.sh @@ -11,20 +11,20 @@ else fi echo "Build and install miri" -cargo build --release --all-features --all-targets && +cargo build --release --all-features --all-targets cargo install --all-features --force --path . echo echo "Get ourselves a MIR-full libstd for the host and a foreign architecture" -cargo miri setup && +cargo miri setup cargo miri setup --target "$FOREIGN_TARGET" echo echo "Test miri with full MIR, on the host and other architectures" -MIRI_SYSROOT=$MIRI_SYSROOT_BASE/HOST cargo test --release --all-features && -MIRI_SYSROOT=$MIRI_SYSROOT_BASE MIRI_TARGET=$FOREIGN_TARGET cargo test --release --all-features +MIRI_SYSROOT="$MIRI_SYSROOT_BASE"/HOST cargo test --release --all-features +MIRI_SYSROOT="$MIRI_SYSROOT_BASE" MIRI_TARGET="$FOREIGN_TARGET" cargo test --release --all-features echo echo "Test cargo integration" -(cd test-cargo-miri && MIRI_SYSROOT=$MIRI_SYSROOT_BASE/HOST ./run-test.py) +(cd test-cargo-miri && MIRI_SYSROOT="$MIRI_SYSROOT_BASE"/HOST ./run-test.py) echo From 6a37e723c4af5760cec21d6a1684ed6d7f344a93 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 15 Dec 2018 15:08:03 +0100 Subject: [PATCH 0490/5092] detect outdated xargo version --- src/bin/cargo-miri.rs | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 6d2dc1dd2f1a..310bf4f583ea 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -3,7 +3,7 @@ extern crate cargo_metadata; use std::path::{PathBuf, Path}; -use std::io::{self, Write}; +use std::io::{self, Write, BufRead}; use std::process::Command; use std::fs::{self, File}; @@ -114,6 +114,36 @@ fn list_targets() -> impl Iterator { package.targets.into_iter() } +fn xargo_version() -> Option<(u32, u32, u32)> { + let out = Command::new("xargo").arg("--version").output().ok()?; + if !out.status.success() { + return None; + } + // Parse output. The first line looks like "xargo 0.3.12 (b004f1c 2018-12-13)". + let line = out.stderr.lines().nth(0) + .expect("malformed `xargo --version` output: not at least one line") + .expect("malformed `xargo --version` output: error reading first line"); + let version = line.split(' ').nth(1) + .expect("malformed `xargo --version` output: not at least two words"); + let mut version_pieces = version.split('.'); + let major = version_pieces.next() + .expect("malformed `xargo --version` output: not a major version piece") + .parse() + .expect("malformed `xargo --version` output: major version is not an integer"); + let minor = version_pieces.next() + .expect("malformed `xargo --version` output: not a minor version piece") + .parse() + .expect("malformed `xargo --version` output: minor version is not an integer"); + let patch = version_pieces.next() + .expect("malformed `xargo --version` output: not a patch version piece") + .parse() + .expect("malformed `xargo --version` output: patch version is not an integer"); + if !version_pieces.next().is_none() { + panic!("malformed `xargo --version` output: more than three pieces in version"); + } + Some((major, minor, patch)) +} + fn ask(question: &str) { let mut buf = String::new(); print!("{} [Y/n] ", question); @@ -134,14 +164,14 @@ fn setup(ask_user: bool) { } // First, we need xargo - if Command::new("xargo").arg("--version").output().is_err() - { + let xargo = xargo_version(); + if xargo.map_or(true, |v| v < (0, 3, 13)) { if ask_user { - ask("It seems you do not have xargo installed. I will run `cargo install xargo`. Proceed?"); + ask("It seems you do not have a recent enough xargo installed. I will run `cargo install xargo -f`. Proceed?"); } else { - println!("Installing xargo: `cargo install xargo`"); + println!("Installing xargo: `cargo install xargo -f`"); } - if !Command::new("cargo").args(&["install", "xargo"]).status().unwrap().success() { + if !Command::new("cargo").args(&["install", "xargo", "-f"]).status().unwrap().success() { show_error(format!("Failed to install xargo")); } } From 96b2c347d74cef4b93ddb681fb3244b98ab883f1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 15 Dec 2018 18:39:42 +0100 Subject: [PATCH 0491/5092] temporarily use git version of xargo --- src/bin/cargo-miri.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 310bf4f583ea..5b1b720da749 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -171,7 +171,8 @@ fn setup(ask_user: bool) { } else { println!("Installing xargo: `cargo install xargo -f`"); } - if !Command::new("cargo").args(&["install", "xargo", "-f"]).status().unwrap().success() { + // FIXME: Go back to using releases, once a 0.3.13 got released. + if !Command::new("cargo").args(&["install", "xargo", "-f", "--git", "https://github.com/japaric/xargo"]).status().unwrap().success() { show_error(format!("Failed to install xargo")); } } From d801daf3e589da9726eec2d8f07c611ca7b9f3c6 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 16 Dec 2018 19:34:00 -0800 Subject: [PATCH 0492/5092] Add rustc-workspace-hack. --- Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index ca670df0f203..6fd45b0c7417 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,10 @@ directories = { version = "1.0", optional = true } rustc_version = { version = "0.2.3", optional = true } env_logger = "0.5" log = "0.4" +# A noop dependency that changes in the Rust repository, it's a bit of a hack. +# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` +# for more information. +rustc-workspace-hack = "1.0.0" [build-dependencies] vergen = "3" From 77ef84e1e8a48ffa1a7d63e858e3d158bc1a8ecb Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 17 Dec 2018 10:12:04 +0100 Subject: [PATCH 0493/5092] Adjust tests for funciton pointer changes --- tests/run-pass/function_pointers.rs | 9 +++++---- tests/run-pass/mir_coercions.rs | 5 ++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/tests/run-pass/function_pointers.rs b/tests/run-pass/function_pointers.rs index 4f597d4a2e94..6819a2af3ed8 100644 --- a/tests/run-pass/function_pointers.rs +++ b/tests/run-pass/function_pointers.rs @@ -10,12 +10,12 @@ fn h(i: i32, j: i32) -> i32 { j * i * 7 } -fn return_fn_ptr() -> fn() -> i32 { +fn return_fn_ptr(f: fn() -> i32) -> fn() -> i32 { f } fn call_fn_ptr() -> i32 { - return_fn_ptr()() + return_fn_ptr(f)() } fn indirect i32>(f: F) -> i32 { f() } @@ -41,6 +41,7 @@ fn main() { assert_eq!(indirect3(h), 210); assert_eq!(indirect_mut3(h), 210); assert_eq!(indirect_once3(h), 210); - assert!(return_fn_ptr() == f); - assert!(return_fn_ptr() as unsafe fn() -> i32 == f as fn() -> i32 as unsafe fn() -> i32); + let g = f as fn() -> i32; + assert!(return_fn_ptr(g) == g); + assert!(return_fn_ptr(g) as unsafe fn() -> i32 == g as fn() -> i32 as unsafe fn() -> i32); } diff --git a/tests/run-pass/mir_coercions.rs b/tests/run-pass/mir_coercions.rs index 36155297e32f..1dab492f9da3 100644 --- a/tests/run-pass/mir_coercions.rs +++ b/tests/run-pass/mir_coercions.rs @@ -60,7 +60,10 @@ fn main() { let a = [0,1,2]; let square_local : fn(u32) -> u32 = square; let (f,g) = fn_coercions(&square_local); - assert_eq!(f as *const (), square as *const()); + // cannot use `square as *const ()` because we can't know whether the compiler duplicates + // functions, so two function pointers are only equal if they result from the same function + // to function pointer cast + assert_eq!(f as *const (), square_local as *const()); assert_eq!(g(4), 16); assert_eq!(identity_coercion(g)(5), 25); From 3e603c38d74935689d7454ec961c49ab2470bf46 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Dec 2018 18:40:06 +0100 Subject: [PATCH 0494/5092] bump Rust version, fix test-cargo-miri and it no longer needs to disable validation --- rust-version | 2 +- test-cargo-miri/run-test.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index 2ad896fe0519..d1ff80dec08a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-12-14 +nightly-2018-12-18 diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index c7ab8f14df88..19e0a147408f 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -34,11 +34,10 @@ def test(name, cmd, stdout_ref, stderr_ref): sys.exit(1) def test_cargo_miri_run(): - test("cargo miri run", ["cargo", "miri", "run", "-q"], "stout.ref", "stderr.ref") + test("cargo miri run", ["cargo", "miri", "run", "-q"], "stdout.ref", "stderr.ref") def test_cargo_miri_test(): - # FIXME: validation disabled for now because of https://github.com/rust-lang/rust/issues/54957 - test("cargo miri test", ["cargo", "miri", "test", "-q", "--", "-Zmiri-disable-validation"], "stout.ref", "stderr.ref") + test("cargo miri test", ["cargo", "miri", "test", "-q"], "test.stdout.ref", "test.stderr.ref") test_cargo_miri_run() test_cargo_miri_test() From b3f799136778a1d034bc621bc41ed42a68d1cc48 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Dec 2018 18:41:52 +0100 Subject: [PATCH 0495/5092] btree is fixed --- tests/run-pass/btreemap.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/run-pass/btreemap.rs b/tests/run-pass/btreemap.rs index dc0fa0987aeb..b7140d72ac3a 100644 --- a/tests/run-pass/btreemap.rs +++ b/tests/run-pass/btreemap.rs @@ -1,6 +1,3 @@ -// FIXME: Validation disabled due to https://github.com/rust-lang/rust/issues/54957 -// compile-flags: -Zmiri-disable-validation - #[derive(PartialEq, Eq, PartialOrd, Ord)] pub enum Foo { A(&'static str), From e8c53e81f8ec8de08cc1f2a1c026c9055fc37445 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Dec 2018 19:26:57 +0100 Subject: [PATCH 0496/5092] implement macOS functions for argc, argv --- src/fn_call.rs | 19 ++++++++++++------- src/lib.rs | 19 +++++++++++++++++-- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index d11364ce0d18..ab82223f234d 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -513,10 +513,6 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_null(dest)?; } - "_tlv_atexit" => { - // FIXME: Register the dtor - }, - // Determining stack base address "pthread_attr_init" | "pthread_attr_destroy" | "pthread_attr_get_np" | "pthread_getattr_np" | "pthread_self" | "pthread_get_stacksize_np" => { @@ -554,7 +550,18 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_null(dest)?; } - // Windows API subs + // macOS API stubs + "_tlv_atexit" => { + // FIXME: Register the dtor + }, + "_NSGetArgc" => { + this.write_scalar(Scalar::Ptr(this.machine.argc.unwrap()), dest)?; + }, + "_NSGetArgv" => { + this.write_scalar(Scalar::Ptr(this.machine.argv.unwrap()), dest)?; + }, + + // Windows API stubs "AddVectoredExceptionHandler" => { // any non zero value works for the stdlib. This is just used for stackoverflows anyway this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; @@ -576,8 +583,6 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // this is c::ERROR_CALL_NOT_IMPLEMENTED this.write_scalar(Scalar::from_int(120, dest.layout.size), dest)?; }, - - // Windows TLS "TlsAlloc" => { // This just creates a key; Windows does not natively support TLS dtors. diff --git a/src/lib.rs b/src/lib.rs index 28639976aa03..e6e1a338c9d1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -121,7 +121,11 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // Second argument (argc): 1 let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - ecx.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; + let argc = Scalar::from_int(1, dest.layout.size); + ecx.write_scalar(argc, dest)?; + let argc_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into())?; + ecx.write_scalar(argc, argc_place.into())?; + ecx.machine.argc = Some(argc_place.ptr.to_ptr()?); // FIXME: extract main source file path // Third argument (argv): &[b"foo"] @@ -132,7 +136,11 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let foo_place = ecx.allocate(foo_layout, MiriMemoryKind::Env.into())?; ecx.write_scalar(Scalar::Ptr(foo), foo_place.into())?; ecx.memory_mut().mark_immutable(foo_place.to_ptr()?.alloc_id)?; - ecx.write_scalar(foo_place.ptr, dest)?; + let argv = foo_place.ptr; + ecx.write_scalar(argv, dest)?; + let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into())?; + ecx.write_scalar(argv, argv_place.into())?; + ecx.machine.argc = Some(argv_place.ptr.to_ptr()?); assert!(args.next().is_none(), "start lang item has more arguments than expected"); @@ -253,6 +261,11 @@ pub struct Evaluator<'tcx> { /// Miri does not expose env vars from the host to the emulated program pub(crate) env_vars: HashMap, Pointer>, + /// Program arguments (`Option` because we can only initialize them after creating the ecx). + /// These are *pointers* to argc/argv because macOS. + pub(crate) argc: Option>, + pub(crate) argv: Option>, + /// TLS state pub(crate) tls: TlsData<'tcx>, @@ -267,6 +280,8 @@ impl<'tcx> Evaluator<'tcx> { fn new(validate: bool) -> Self { Evaluator { env_vars: HashMap::default(), + argc: None, + argv: None, tls: TlsData::default(), validate, stacked_borrows: stacked_borrows::State::default(), From e4fd710606c346cad3e64dc7edc18201699560c7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Dec 2018 19:41:32 +0100 Subject: [PATCH 0497/5092] there is a new xargo released, use that --- src/bin/cargo-miri.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 2a2cbdb8155d..0a8ddd95a76e 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -171,8 +171,7 @@ fn setup(ask_user: bool) { } else { println!("Installing xargo: `cargo install xargo -f`"); } - // FIXME: Go back to using releases, once a 0.3.13 got released. - if !Command::new("cargo").args(&["install", "xargo", "-f", "--git", "https://github.com/japaric/xargo"]).status().unwrap().success() { + if !Command::new("cargo").args(&["install", "xargo", "-f"]).status().unwrap().success() { show_error(format!("Failed to install xargo")); } } From 4e0fe62bd90bffcec376e7b0877e87ebfece3cfb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Dec 2018 19:45:10 +0100 Subject: [PATCH 0498/5092] typo --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index e6e1a338c9d1..e41a92e55f72 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -140,7 +140,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( ecx.write_scalar(argv, dest)?; let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into())?; ecx.write_scalar(argv, argv_place.into())?; - ecx.machine.argc = Some(argv_place.ptr.to_ptr()?); + ecx.machine.argv = Some(argv_place.ptr.to_ptr()?); assert!(args.next().is_none(), "start lang item has more arguments than expected"); From 61c0df793060e60e5bd106dec82fd0951decd63b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Dec 2018 21:49:21 +0100 Subject: [PATCH 0499/5092] remove outdated README comment --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index b6e1c20076de..02e13ad56a7e 100644 --- a/README.md +++ b/README.md @@ -45,8 +45,6 @@ Now you can run your project in miri: dependencies to be compiled the right way, that would not happen if they have previously already been compiled. 2. To run all tests in your project through Miri, use `cargo +nightly miri test`. - **NOTE**: This is currently broken, see the discussion in - [#479](https://github.com/solson/miri/issues/479). 3. If you have a binary project, you can run it through Miri using `cargo +nightly miri run`. From bf846a637c6755bd4fe215b6103d7aba28a282a5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Dec 2018 21:49:38 +0100 Subject: [PATCH 0500/5092] test-cargo-miri: be more clear that and why the test failed --- test-cargo-miri/run-test.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 19e0a147408f..7f7f2660c062 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -7,6 +7,10 @@ and the working directory to contain the cargo-miri-test project. import sys, subprocess +def fail(msg): + print("TEST FAIL: {}".format(msg)) + sys.exit(1) + def test(name, cmd, stdout_ref, stderr_ref): print("==> Testing `{}` <==".format(name)) ## Call `cargo miri`, capture all output @@ -25,13 +29,11 @@ def test(name, cmd, stdout_ref, stderr_ref): print(stderr, end="") # Test for failures if p.returncode != 0: - sys.exit(1) + fail("Non-zero exit status") if stdout != open(stdout_ref).read(): - print("stdout does not match reference") - sys.exit(1) + fail("stdout does not match reference") if stderr != open(stderr_ref).read(): - print("stderr does not match reference") - sys.exit(1) + fail("stderr does not match reference") def test_cargo_miri_run(): test("cargo miri run", ["cargo", "miri", "run", "-q"], "stdout.ref", "stderr.ref") From 133e012cec90e220f5c7f50d454e8d93b0f79332 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 Dec 2018 11:06:35 +0100 Subject: [PATCH 0501/5092] sync env vars between appveyor and travis --- .travis.yml | 1 + appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index dfc4238a6c03..51b14a1b345b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,3 +38,4 @@ branches: env: global: - RUST_TEST_NOCAPTURE=1 + - RUST_BACKTRACE=1 diff --git a/appveyor.yml b/appveyor.yml index 4f4aebd80791..09040ed42a58 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -25,7 +25,7 @@ install: build: false test_script: - - set RUSTFLAGS=-g + - set RUST_TEST_NOCAPTURE=1 - set RUST_BACKTRACE=1 # Build miri - cargo build --release --all-features --all-targets From ecf659905145ba9430b54f72c2328edd74462117 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 Dec 2018 08:41:31 +0100 Subject: [PATCH 0502/5092] xargo version check: also check application name, just to be sure --- src/bin/cargo-miri.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 0a8ddd95a76e..4ac1d1a3b475 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -123,8 +123,14 @@ fn xargo_version() -> Option<(u32, u32, u32)> { let line = out.stderr.lines().nth(0) .expect("malformed `xargo --version` output: not at least one line") .expect("malformed `xargo --version` output: error reading first line"); - let version = line.split(' ').nth(1) - .expect("malformed `xargo --version` output: not at least two words"); + let (name, version) = { + let mut split = line.split(' '); + (split.next().expect("malformed `xargo --version` output: empty"), + split.next().expect("malformed `xargo --version` output: not at least two words")) + }; + if name != "xargo" { + panic!("malformed `xargo --version` output: application name is not `xargo`"); + } let mut version_pieces = version.split('.'); let major = version_pieces.next() .expect("malformed `xargo --version` output: not a major version piece") From 11433bf38e586ae517d5caa3ddb82c283cb8a1b3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 Dec 2018 09:03:10 +0100 Subject: [PATCH 0503/5092] actually show warnings about suppressed output --- src/fn_call.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index ab82223f234d..ab38270724f4 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -398,7 +398,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, Err(_) => -1, } } else { - warn!("Ignored output to FD {}", fd); + eprintln!("Miri: Ignored output to FD {}", fd); n as i64 // pretend it all went well }; // now result is the value we return back to the program this.write_scalar( From e10a26fd3cdcb9a8442fb21b1e13e8425d3e29d7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 Dec 2018 11:11:01 +0100 Subject: [PATCH 0504/5092] add a test for excluding tests on miri --- test-cargo-miri/tests/foo.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test-cargo-miri/tests/foo.rs b/test-cargo-miri/tests/foo.rs index 9827ae82d6cf..bd7b2c569a19 100644 --- a/test-cargo-miri/tests/foo.rs +++ b/test-cargo-miri/tests/foo.rs @@ -9,3 +9,11 @@ fn bar() { fn baz() { assert_eq!(5, 5); } + +// A test that won't work on miri +#[cfg(not(feature = "cargo-miri"))] +#[test] +fn does_not_work_on_miri() { + let x = 0u8; + assert!(&x as *const _ as usize % 4 < 4); +} From d67da9f04bf2acf7ecec1438c28015cd75d01c83 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 Dec 2018 11:12:56 +0100 Subject: [PATCH 0505/5092] no need to set the cargo-miri feature twice --- src/bin/cargo-miri.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 4ac1d1a3b475..21cc7ee0e398 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -420,8 +420,6 @@ where args.push("--".to_owned()); } args.push("--emit=dep-info,metadata".to_owned()); - args.push("--cfg".to_owned()); - args.push(r#"feature="cargo-miri""#.to_owned()); let path = std::env::current_exe().expect("current executable path invalid"); let exit_status = Command::new("cargo") From adba97e4b24aa5ec920330a549690f664a3e1ab6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 Dec 2018 11:16:19 +0100 Subject: [PATCH 0506/5092] document the cargo-miri feature --- README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 02e13ad56a7e..5a615e656d74 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ example above), overriding it in your project directory as well, or use `rustup default nightly` (or `rustup default nightly-YYYY-MM-DD`) to globally make `nightly` the default toolchain. -Now you can run your project in miri: +Now you can run your project in Miri: 1. Run `cargo clean` to eliminate any cached dependencies. Miri needs your dependencies to be compiled the right way, that would not happen if they have @@ -48,6 +48,19 @@ Now you can run your project in miri: 3. If you have a binary project, you can run it through Miri using `cargo +nightly miri run`. +When running code via `cargo miri`, the `cargo-miri` feature is set. You can +use this to exclude test cases that will fail under Miri because they do things +Miri does not support: + +```rust +#[cfg(not(feature = "cargo-miri"))] +#[test] +fn does_not_work_on_miri() { + let x = 0u8; + assert!(&x as *const _ as usize % 4 < 4); +} +``` + ### Common Problems When using the above instructions, you may encounter a number of confusing compiler From 51ed485ba4eb19083f7da719c55edb8a11f7f28e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Dec 2018 21:49:01 +0100 Subject: [PATCH 0507/5092] implement stdout/stderr on Windows --- src/fn_call.rs | 45 +++++++++++++++++++++++++++++-- tests/run-pass/box-pair-to-vec.rs | 2 -- tests/run-pass/catch.rs | 1 - tests/run-pass/format.rs | 1 - tests/run-pass/hello.rs | 1 - tests/run-pass/issue-17877.rs | 2 +- tests/run-pass/issue-3794.rs | 1 - 7 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index ab38270724f4..7815c1ce40e1 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -596,18 +596,59 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { - let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; + let key = this.read_scalar(args[0])?.to_u32()? as u128; let ptr = this.machine.tls.load_tls(key)?; this.write_scalar(ptr, dest)?; } "TlsSetValue" => { - let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; + let key = this.read_scalar(args[0])?.to_u32()? as u128; let new_ptr = this.read_scalar(args[1])?.not_undef()?; this.machine.tls.store_tls(key, new_ptr)?; // Return success (1) this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; } + "GetStdHandle" => { + let which = this.read_scalar(args[0])?.to_i32()?; + // We just make this the identity function, so we know later in "WriteFile" + // which one it is. + this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?; + } + "WriteFile" => { + let handle = this.read_scalar(args[0])?.to_isize(this)?; + let buf = this.read_scalar(args[1])?.not_undef()?; + let n = this.read_scalar(args[2])?.to_u32()?; + let written_place = this.deref_operand(args[3])?; + this.write_null(written_place.into())?; // spec says we always write 0 first + let written = if handle == -11 || handle == -12 { + // stdout/stderr + use std::io::{self, Write}; + + let buf_cont = this.memory().read_bytes(buf, Size::from_bytes(u64::from(n)))?; + let res = if handle == -11 { + io::stdout().write(buf_cont) + } else { + io::stderr().write(buf_cont) + }; + res.ok().map(|n| n as u32) + } else { + eprintln!("Miri: Ignored output to handle {}", handle); + Some(n) // pretend it all went well + }; + // If there was no error, write back how much was written + if let Some(n) = written { + this.write_scalar(Scalar::from_uint(n, Size::from_bits(32)), written_place.into())?; + } + // Return whether this was a success + this.write_scalar( + Scalar::from_int(if written.is_some() { 1 } else { 0 }, dest.layout.size), + dest, + )?; + } + "GetConsoleMode" => { + // Everything is a pipe + this.write_null(dest)?; + } // We can't execute anything else _ => { diff --git a/tests/run-pass/box-pair-to-vec.rs b/tests/run-pass/box-pair-to-vec.rs index 3b829d0f1294..353afb9d3210 100644 --- a/tests/run-pass/box-pair-to-vec.rs +++ b/tests/run-pass/box-pair-to-vec.rs @@ -1,5 +1,3 @@ -//ignore-msvc: Stdout not implemented on Windows - #[repr(C)] #[derive(Debug)] struct PairFoo { diff --git a/tests/run-pass/catch.rs b/tests/run-pass/catch.rs index aa7bccaa5ff3..5fd65f138aaf 100644 --- a/tests/run-pass/catch.rs +++ b/tests/run-pass/catch.rs @@ -1,4 +1,3 @@ -//ignore-msvc: Stdout not implemented on Windows use std::panic::{catch_unwind, AssertUnwindSafe}; fn main() { diff --git a/tests/run-pass/format.rs b/tests/run-pass/format.rs index b1b05abd2965..78729b915613 100644 --- a/tests/run-pass/format.rs +++ b/tests/run-pass/format.rs @@ -1,4 +1,3 @@ -//ignore-msvc: Stdout not implemented on Windows fn main() { println!("Hello {}", 13); } diff --git a/tests/run-pass/hello.rs b/tests/run-pass/hello.rs index c92c1567f5ae..e7a11a969c03 100644 --- a/tests/run-pass/hello.rs +++ b/tests/run-pass/hello.rs @@ -1,4 +1,3 @@ -//ignore-msvc: Stdout not implemented on Windows fn main() { println!("Hello, world!"); } diff --git a/tests/run-pass/issue-17877.rs b/tests/run-pass/issue-17877.rs index 762bacbe0e6f..91d17683e39e 100644 --- a/tests/run-pass/issue-17877.rs +++ b/tests/run-pass/issue-17877.rs @@ -9,7 +9,7 @@ // except according to those terms. //ignore-windows: Causes a stack overflow?!? Likely a rustc bug: https://github.com/rust-lang/rust/issues/53820 -//Once that bug is fixed, increase the size to 16*1024 and enable on all platforms. +//FIXME: Once that bug is fixed, increase the size to 16*1024 and enable on all platforms. #![feature(slice_patterns)] diff --git a/tests/run-pass/issue-3794.rs b/tests/run-pass/issue-3794.rs index 32b4d27f11f5..badb833ee800 100644 --- a/tests/run-pass/issue-3794.rs +++ b/tests/run-pass/issue-3794.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//ignore-msvc: Stdout not implemented on Windows #![feature(box_syntax)] trait T { From e7c523f72ee0850972cc8a37b6780d2fe1666b0c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Dec 2018 19:52:30 +0100 Subject: [PATCH 0508/5092] run test-cargo-miri on Windows --- appveyor.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 09040ed42a58..a46214a3c45c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -27,13 +27,17 @@ build: false test_script: - set RUST_TEST_NOCAPTURE=1 - set RUST_BACKTRACE=1 - # Build miri + # Build and install miri - cargo build --release --all-features --all-targets + - cargo install --all-features --force --path . # Get ourselves a MIR-full libstd, and use it henceforth - - cargo run --release --all-features --bin cargo-miri -- miri setup + - cargo miri setup - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\miri\miri\cache\HOST # Test miri - cargo test --release --all-features + # Test cargo integration + - cd test-cargo-miri + - python3 run-test.py notifications: - provider: Email From af4fb6655e9a09d4154250bcff99fc80eb2c402f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 Dec 2018 15:25:25 +0100 Subject: [PATCH 0509/5092] implement GetCommandLineW, GetEnvironmentVariableW, GetConsoleScreenBufferInfo, SetConsoleTextAttribute, GetSystemInfo --- src/fn_call.rs | 47 ++++++++++++++++++++++++++++------ src/lib.rs | 69 +++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 93 insertions(+), 23 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 7815c1ce40e1..16d18dbfe6dc 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -562,6 +562,14 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, }, // Windows API stubs + "SetLastError" => { + let err = this.read_scalar(args[0])?.to_u32()?; + this.machine.last_error = err; + } + "GetLastError" => { + this.write_scalar(Scalar::from_uint(this.machine.last_error, Size::from_bits(32)), dest)?; + } + "AddVectoredExceptionHandler" => { // any non zero value works for the stdlib. This is just used for stackoverflows anyway this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; @@ -569,20 +577,35 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "InitializeCriticalSection" | "EnterCriticalSection" | "LeaveCriticalSection" | - "DeleteCriticalSection" | - "SetLastError" => { - // Function does not return anything, nothing to do + "DeleteCriticalSection" => { + // Nothing to do, not even a return value }, "GetModuleHandleW" | "GetProcAddress" | - "TryEnterCriticalSection" => { + "TryEnterCriticalSection" | + "GetConsoleScreenBufferInfo" | + "SetConsoleTextAttribute" => { // pretend these do not exist/nothing happened, by returning zero this.write_null(dest)?; }, - "GetLastError" => { - // this is c::ERROR_CALL_NOT_IMPLEMENTED - this.write_scalar(Scalar::from_int(120, dest.layout.size), dest)?; - }, + "GetSystemInfo" => { + let system_info = this.deref_operand(args[0])?; + let system_info_ptr = system_info.ptr.to_ptr()?; + // initialize with 0 + this.memory_mut().get_mut(system_info_ptr.alloc_id)? + .write_repeat(tcx, system_info_ptr, 0, system_info.layout.size)?; + // set number of processors to 1 + let dword_size = Size::from_bytes(4); + let offset = 2*dword_size + 3*tcx.pointer_size(); + this.memory_mut().get_mut(system_info_ptr.alloc_id)? + .write_scalar( + tcx, + system_info_ptr.offset(offset, tcx)?, + Scalar::from_int(1, dword_size).into(), + dword_size, + )?; + } + "TlsAlloc" => { // This just creates a key; Windows does not natively support TLS dtors. @@ -649,6 +672,14 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // Everything is a pipe this.write_null(dest)?; } + "GetEnvironmentVariableW" => { + // This is not the env var you are looking for + this.machine.last_error = 203; // ERROR_ENVVAR_NOT_FOUND + this.write_null(dest)?; + } + "GetCommandLineW" => { + this.write_scalar(Scalar::Ptr(this.machine.cmd_line.unwrap()), dest)?; + } // We can't execute anything else _ => { diff --git a/src/lib.rs b/src/lib.rs index e41a92e55f72..bc5e8363e89e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,7 @@ use std::borrow::Cow; use std::env; use rustc::ty::{self, TyCtxt, query::TyCtxtAt}; -use rustc::ty::layout::{TyLayout, LayoutOf, Size}; +use rustc::ty::layout::{TyLayout, LayoutOf, Size, Align}; use rustc::hir::{self, def_id::DefId}; use rustc::mir; @@ -123,24 +123,56 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let argc = Scalar::from_int(1, dest.layout.size); ecx.write_scalar(argc, dest)?; - let argc_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into())?; - ecx.write_scalar(argc, argc_place.into())?; - ecx.machine.argc = Some(argc_place.ptr.to_ptr()?); + // Store argc for macOS _NSGetArgc + { + let argc_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into())?; + ecx.write_scalar(argc, argc_place.into())?; + ecx.machine.argc = Some(argc_place.ptr.to_ptr()?); + } // FIXME: extract main source file path // Third argument (argv): &[b"foo"] + const CMD: &str = "running-in-miri"; let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - let foo = ecx.memory_mut().allocate_static_bytes(b"foo\0").with_default_tag(); - let foo_ty = ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8); - let foo_layout = ecx.layout_of(foo_ty)?; - let foo_place = ecx.allocate(foo_layout, MiriMemoryKind::Env.into())?; - ecx.write_scalar(Scalar::Ptr(foo), foo_place.into())?; - ecx.memory_mut().mark_immutable(foo_place.to_ptr()?.alloc_id)?; - let argv = foo_place.ptr; - ecx.write_scalar(argv, dest)?; - let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into())?; - ecx.write_scalar(argv, argv_place.into())?; - ecx.machine.argv = Some(argv_place.ptr.to_ptr()?); + let cmd = ecx.memory_mut().allocate_static_bytes(CMD.as_bytes()).with_default_tag(); + let raw_str_layout = ecx.layout_of(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8))?; + let cmd_place = ecx.allocate(raw_str_layout, MiriMemoryKind::Env.into())?; + ecx.write_scalar(Scalar::Ptr(cmd), cmd_place.into())?; + ecx.memory_mut().mark_immutable(cmd_place.to_ptr()?.alloc_id)?; + // Store argv for macOS _NSGetArgv + { + let argv = cmd_place.ptr; + ecx.write_scalar(argv, dest)?; + let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into())?; + ecx.write_scalar(argv, argv_place.into())?; + ecx.machine.argv = Some(argv_place.ptr.to_ptr()?); + } + // Store cmdline as UTF-16 for Windows GetCommandLineW + { + let tcx = &{ecx.tcx.tcx}; + let cmd_utf16: Vec = CMD.encode_utf16() + .chain(Some(0)) // add 0-terminator + .collect(); + let cmd_ptr = ecx.memory_mut().allocate( + Size::from_bytes(cmd_utf16.len() as u64 * 2), + Align::from_bytes(2).unwrap(), + MiriMemoryKind::Env.into(), + )?.with_default_tag(); + ecx.machine.cmd_line = Some(cmd_ptr); + // store the UTF-16 string + let char_size = Size::from_bytes(2); + let cmd_alloc = ecx.memory_mut().get_mut(cmd_ptr.alloc_id)?; + let mut cur_ptr = cmd_ptr; + for &c in cmd_utf16.iter() { + cmd_alloc.write_scalar( + tcx, + cur_ptr, + Scalar::from_uint(c, char_size).into(), + char_size, + )?; + cur_ptr = cur_ptr.offset(char_size, tcx)?; + } + } assert!(args.next().is_none(), "start lang item has more arguments than expected"); @@ -263,8 +295,13 @@ pub struct Evaluator<'tcx> { /// Program arguments (`Option` because we can only initialize them after creating the ecx). /// These are *pointers* to argc/argv because macOS. + /// We also need the full cmdline as one string because Window. pub(crate) argc: Option>, pub(crate) argv: Option>, + pub(crate) cmd_line: Option>, + + /// Last OS error + pub(crate) last_error: u32, /// TLS state pub(crate) tls: TlsData<'tcx>, @@ -282,6 +319,8 @@ impl<'tcx> Evaluator<'tcx> { env_vars: HashMap::default(), argc: None, argv: None, + cmd_line: None, + last_error: 0, tls: TlsData::default(), validate, stacked_borrows: stacked_borrows::State::default(), From 750cd442beb0009df6ee3dc80b88582f3b8730d9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 Dec 2018 15:45:23 +0100 Subject: [PATCH 0510/5092] fix argv null terminator --- src/lib.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index bc5e8363e89e..cf2c39f61ef8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -132,7 +132,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // FIXME: extract main source file path // Third argument (argv): &[b"foo"] - const CMD: &str = "running-in-miri"; + const CMD: &str = "running-in-miri\0"; let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let cmd = ecx.memory_mut().allocate_static_bytes(CMD.as_bytes()).with_default_tag(); let raw_str_layout = ecx.layout_of(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8))?; @@ -150,9 +150,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // Store cmdline as UTF-16 for Windows GetCommandLineW { let tcx = &{ecx.tcx.tcx}; - let cmd_utf16: Vec = CMD.encode_utf16() - .chain(Some(0)) // add 0-terminator - .collect(); + let cmd_utf16: Vec = CMD.encode_utf16().collect(); let cmd_ptr = ecx.memory_mut().allocate( Size::from_bytes(cmd_utf16.len() as u64 * 2), Align::from_bytes(2).unwrap(), From 2c2587bc8d18f9fea886b9a852218fe8c89d6f73 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 21 Dec 2018 09:29:42 +0100 Subject: [PATCH 0511/5092] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index d1ff80dec08a..7a16560006d5 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-12-18 +nightly-2018-12-21 From 79bdec8a9cb18ce8ba9c93183bbefbf680241bec Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 22 Dec 2018 16:07:40 +0100 Subject: [PATCH 0512/5092] fix test for latest nightly --- rust-version | 2 +- tests/compile-fail/never_transmute_void.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 7a16560006d5..0c2bc318c67f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-12-21 +nightly-2018-12-22 diff --git a/tests/compile-fail/never_transmute_void.rs b/tests/compile-fail/never_transmute_void.rs index fab4981047f8..5993cfad8699 100644 --- a/tests/compile-fail/never_transmute_void.rs +++ b/tests/compile-fail/never_transmute_void.rs @@ -2,6 +2,7 @@ // compile-flags: -Zmiri-disable-validation #![feature(never_type)] +#![allow(unused)] enum Void {} From 4f659ed507761563748e1ee286adc2aea685923c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Dec 2018 14:13:16 +0100 Subject: [PATCH 0513/5092] fix for infallible allocation --- src/fn_call.rs | 8 ++++---- src/lib.rs | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 16d18dbfe6dc..0f5429518239 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -84,7 +84,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_null(dest)?; } else { let align = this.tcx.data_layout.pointer_align.abi; - let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into())?; + let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into()); this.write_scalar(Scalar::Ptr(ptr.with_default_tag()), dest)?; } } @@ -114,7 +114,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into() - )? + ) .with_default_tag(); this.write_scalar(Scalar::Ptr(ptr), dest)?; } @@ -132,7 +132,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into() - )? + ) .with_default_tag(); this.memory_mut() .get_mut(ptr.alloc_id)? @@ -358,7 +358,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, Size::from_bytes((value.len() + 1) as u64), Align::from_bytes(1).unwrap(), MiriMemoryKind::Env.into(), - )?.with_default_tag(); + ).with_default_tag(); { let alloc = this.memory_mut().get_mut(value_copy.alloc_id)?; alloc.write_bytes(tcx, value_copy, &value)?; diff --git a/src/lib.rs b/src/lib.rs index aa6522030550..7643f93fdc2c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -101,7 +101,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // Return value (in static memory so that it does not count as leak) let ret = ecx.layout_of(start_mir.return_ty())?; - let ret_ptr = ecx.allocate(ret, MiriMemoryKind::MutStatic.into())?; + let ret_ptr = ecx.allocate(ret, MiriMemoryKind::MutStatic.into()); // Push our stack frame ecx.push_stack_frame( @@ -125,7 +125,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( ecx.write_scalar(argc, dest)?; // Store argc for macOS _NSGetArgc { - let argc_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into())?; + let argc_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into()); ecx.write_scalar(argc, argc_place.into())?; ecx.machine.argc = Some(argc_place.ptr.to_ptr()?); } @@ -136,14 +136,14 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let cmd = ecx.memory_mut().allocate_static_bytes(CMD.as_bytes()).with_default_tag(); let raw_str_layout = ecx.layout_of(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8))?; - let cmd_place = ecx.allocate(raw_str_layout, MiriMemoryKind::Env.into())?; + let cmd_place = ecx.allocate(raw_str_layout, MiriMemoryKind::Env.into()); ecx.write_scalar(Scalar::Ptr(cmd), cmd_place.into())?; ecx.memory_mut().mark_immutable(cmd_place.to_ptr()?.alloc_id)?; // Store argv for macOS _NSGetArgv { let argv = cmd_place.ptr; ecx.write_scalar(argv, dest)?; - let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into())?; + let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into()); ecx.write_scalar(argv, argv_place.into())?; ecx.machine.argv = Some(argv_place.ptr.to_ptr()?); } @@ -155,7 +155,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( Size::from_bytes(cmd_utf16.len() as u64 * 2), Align::from_bytes(2).unwrap(), MiriMemoryKind::Env.into(), - )?.with_default_tag(); + ).with_default_tag(); ecx.machine.cmd_line = Some(cmd_ptr); // store the UTF-16 string let char_size = Size::from_bytes(2); @@ -516,13 +516,13 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, ptr: Pointer, kind: MemoryKind, - ) -> EvalResult<'tcx, Pointer> { + ) -> Pointer { if !ecx.machine.validate { // No tracking - Ok(ptr.with_default_tag()) + ptr.with_default_tag() } else { let tag = ecx.tag_new_allocation(ptr.alloc_id, kind); - Ok(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag)) + Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag) } } From d8c9c9dd4f49fbb78f82c7407daff5e403b6f274 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Dec 2018 14:21:15 +0100 Subject: [PATCH 0514/5092] update README for some tracing being available on nightlies --- README.md | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 5a615e656d74..879d27dc97e0 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ things (like adding support for a new intrinsic) can be done by working just on the miri side. To prepare, make sure you are using a nightly Rust compiler. You also need to -set up a libstd that enables execution with miri: +set up a libstd that enables execution with Miri: ```sh rustup override set nightly # or the nightly in `rust-version` @@ -98,7 +98,7 @@ cargo run --bin cargo-miri -- miri setup ``` The last command should end in printing the directory where the libstd was -built. Set that as your MIRI_SYSROOT environment variable: +built. Set that as your `MIRI_SYSROOT` environment variable: ```sh export MIRI_SYSROOT=~/.cache/miri/HOST # or whatever the previous command said @@ -109,7 +109,7 @@ export MIRI_SYSROOT=~/.cache/miri/HOST # or whatever the previous command said Now you can run Miri directly, without going through `cargo miri`: ```sh -cargo run tests/run-pass-fullmir/format.rs # or whatever test you like +cargo run tests/run-pass/format.rs # or whatever test you like ``` You can also run the test suite with `cargo test --release`. `cargo test @@ -120,14 +120,33 @@ less time. Now you are set up! You can write a failing test case, and tweak miri until it fails no more. +You can get a trace of which MIR statements are being executed by setting the +`MIRI_LOG` environment variable. For example: + +```sh +MIRI_LOG=info cargo run tests/run-pass/vecs.rs +``` + +Setting `MIRI_LOG` like this will configure logging for miri itself as well as +the `rustc::mir::interpret` and `rustc_mir::interpret` modules in rustc. You +can also do more targeted configuration, e.g. to debug the stacked borrows +implementation: +```sh +MIRI_LOG=rustc_mir::interpret=info,miri::stacked_borrows cargo run tests/run-pass/vecs.rs +``` + +In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an +evaluation error was originally created. + ### Using a locally built rustc Since the heart of Miri (the main interpreter engine) lives in rustc, working on Miri will often require using a locally built rustc. The bug you want to fix may actually be on the rustc side, or you just need to get more detailed trace -of the execution -- in both cases, you should develop miri against a rustc you -compiled yourself, with debug assertions (and hence tracing) enabled. +of the execution than what is possible with release builds -- in both cases, you +should develop miri against a rustc you compiled yourself, with debug assertions +(and hence tracing) enabled. The setup for a local rustc works as follows: ```sh @@ -149,22 +168,6 @@ rustup override set custom With this, you should now have a working development setup! See ["Testing Miri"](#testing-miri) above for how to proceed. -Moreover, you can now run Miri with a trace of all execution steps: -```sh -MIRI_LOG=debug cargo run tests/run-pass/vecs.rs -``` - -Setting `MIRI_LOG` like this will configure logging for miri itself as well as -the `rustc::mir::interpret` and `rustc_mir::interpret` modules in rustc. You -can also do more targeted configuration, e.g. to debug the stacked borrows -implementation: -```sh -MIRI_LOG=rustc_mir::interpret=debug,miri::stacked_borrows cargo run tests/run-pass/vecs.rs -``` - -In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an -evaluation error was originally created. - ### Miri `-Z` flags and environment variables Several `-Z` flags are relevant for Miri: From d0f06a5f0daa73731f2ebe7763f2c48192220392 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Dec 2018 14:30:29 +0100 Subject: [PATCH 0515/5092] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 0c2bc318c67f..ea30c4512ee7 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-12-22 +nightly-2018-12-24 From 4e4569cf4b5f044b030f9a3de61e4167395c5145 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 25 Dec 2018 13:26:40 +0100 Subject: [PATCH 0516/5092] fix build and tests with latest nightly --- src/operator.rs | 6 ++++-- tests/run-pass/async-fn.rs | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index e1ccdf91995e..abc1c98a1ded 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -161,12 +161,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' if bits == 0 { // Test if the ptr is in-bounds. Then it cannot be NULL. // Even dangling pointers cannot be NULL. - if self.memory().check_bounds_ptr_maybe_dead(ptr).is_ok() { + if self.memory().check_bounds_ptr(ptr, InboundsCheck::MaybeDead).is_ok() { return Ok(false); } } - let (alloc_size, alloc_align) = self.memory().get_size_and_align(ptr.alloc_id); + let (alloc_size, alloc_align) = self.memory() + .get_size_and_align(ptr.alloc_id, InboundsCheck::MaybeDead) + .expect("determining size+align of dead ptr cannot fail"); // Case II: Alignment gives it away if ptr.offset.bytes() % alloc_align.bytes() == 0 { diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 7c32b026df67..9094a9fd3a68 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -2,7 +2,6 @@ async_await, await_macro, futures_api, - pin, )] use std::{future::Future, pin::Pin, task::Poll}; From 5a8f9e58f72a8b8ad284475c8992c664c548f776 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 25 Dec 2018 13:29:38 +0100 Subject: [PATCH 0517/5092] properly compare unequal function pointers --- src/operator.rs | 4 ++-- tests/run-pass/function_pointers.rs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index abc1c98a1ded..cc803c4ea954 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -145,8 +145,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Dead allocations in miri cannot overlap with live allocations, but // on read hardware this can easily happen. Thus for comparisons we require // both pointers to be live. - self.memory().get(left.alloc_id)?.check_bounds_ptr(left)?; - self.memory().get(right.alloc_id)?.check_bounds_ptr(right)?; + self.memory().check_bounds_ptr(left, InboundsCheck::Live)?; + self.memory().check_bounds_ptr(right, InboundsCheck::Live)?; // Two in-bounds pointers, we can compare across allocations left == right } diff --git a/tests/run-pass/function_pointers.rs b/tests/run-pass/function_pointers.rs index 6819a2af3ed8..cc888630d3ee 100644 --- a/tests/run-pass/function_pointers.rs +++ b/tests/run-pass/function_pointers.rs @@ -44,4 +44,5 @@ fn main() { let g = f as fn() -> i32; assert!(return_fn_ptr(g) == g); assert!(return_fn_ptr(g) as unsafe fn() -> i32 == g as fn() -> i32 as unsafe fn() -> i32); + assert!(return_fn_ptr(f) != f); } From 55107d5dd34d73af891f117ace2c25bb8ac33680 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 26 Dec 2018 11:01:22 +0100 Subject: [PATCH 0518/5092] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index ea30c4512ee7..a2909dd32898 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-12-24 +nightly-2018-12-26 From e759da6b4b7d64d9561fa988765acbc6215aecbb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 26 Dec 2018 11:25:20 +0100 Subject: [PATCH 0519/5092] bump env_logger --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 6fd45b0c7417..5e78661c2196 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,7 @@ byteorder = { version = "1.1", features = ["i128"]} cargo_metadata = { version = "0.6", optional = true } directories = { version = "1.0", optional = true } rustc_version = { version = "0.2.3", optional = true } -env_logger = "0.5" +env_logger = "0.6" log = "0.4" # A noop dependency that changes in the Rust repository, it's a bit of a hack. # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` From f2e14d931417f5037aea6212a5294a641caf5512 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 26 Dec 2018 13:16:47 +0100 Subject: [PATCH 0520/5092] use memory::check_bounds_ptr for offset check --- src/operator.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index cc803c4ea954..4b110224a0a2 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -303,10 +303,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' if let Scalar::Ptr(ptr) = ptr { // Both old and new pointer must be in-bounds of a *live* allocation. // (Of the same allocation, but that part is trivial with our representation.) - let alloc = self.memory().get(ptr.alloc_id)?; - alloc.check_bounds_ptr(ptr)?; + self.memory().check_bounds_ptr(ptr, InboundsCheck::Live)?; let ptr = ptr.signed_offset(offset, self)?; - alloc.check_bounds_ptr(ptr)?; + self.memory().check_bounds_ptr(ptr, InboundsCheck::Live)?; Ok(Scalar::Ptr(ptr)) } else { // An integer pointer. They can only be offset by 0, and we pretend there From 3715245a3688de8f82ffbb127b09a0dd517458c3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 26 Dec 2018 16:23:04 +0100 Subject: [PATCH 0521/5092] add test for offseting fn ptr --- tests/run-pass/ptr_offset.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/run-pass/ptr_offset.rs b/tests/run-pass/ptr_offset.rs index 6add5212db9f..9e2e26fad365 100644 --- a/tests/run-pass/ptr_offset.rs +++ b/tests/run-pass/ptr_offset.rs @@ -1,6 +1,16 @@ +fn f() -> i32 { 42 } + fn main() { let v = [1i16, 2]; let x = &v as *const i16; let x = unsafe { x.offset(1) }; assert_eq!(unsafe { *x }, 2); + + // fn ptr offset + unsafe { + let p = f as fn() -> i32 as usize; + let x = (p as *mut u32).offset(0) as usize; + let f: fn() -> i32 = std::mem::transmute(x); + assert_eq!(f(), 42); + } } From 1cda220b4b2403774feae5e37b8e8517875762b6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 28 Dec 2018 18:16:55 +0100 Subject: [PATCH 0522/5092] fix install command --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 879d27dc97e0..c6dd0d8b06c6 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ for example: Install Miri as a cargo subcommand: ```sh -cargo +nightly install --git https://github.com/solson/miri/ miri +cargo +nightly install --force --git https://github.com/solson/miri miri ``` If this does not work, try using the nightly version given in From b344f0fd43d6042d540ad209309fd859d595180c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 4 Jan 2019 10:15:53 +0100 Subject: [PATCH 0523/5092] test some more 2PB stuff --- tests/run-pass/2phase.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/run-pass/2phase.rs b/tests/run-pass/2phase.rs index 5b9e5d3ea5ff..987adca477a6 100644 --- a/tests/run-pass/2phase.rs +++ b/tests/run-pass/2phase.rs @@ -16,6 +16,18 @@ fn two_phase2() { v.push(v.len()); } +fn two_phase3(b: bool) { + let mut x = &mut vec![]; + let mut y = vec![]; + x.push(( + { + if b { x = &mut y }; + 22 + }, + x.len(), + )); +} + /* fn two_phase_overlapping1() { let mut x = vec![]; @@ -62,6 +74,8 @@ fn with_interior_mutability() { fn main() { two_phase1(); two_phase2(); + two_phase3(false); + two_phase3(true); match_two_phase(); with_interior_mutability(); //FIXME: enable these, or remove them, depending on how https://github.com/rust-lang/rust/issues/56254 gets resolved From fced2ac8653bd7adb7edb81d312b09352ab572f0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 4 Jan 2019 15:37:51 +0100 Subject: [PATCH 0524/5092] move env var stuff out of the miri lib --- src/bin/miri.rs | 8 ++++++++ src/lib.rs | 9 --------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index c2255d706339..d8d7cfe0702e 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -154,6 +154,14 @@ fn init_late_loggers() { rustc_driver::init_rustc_env_logger(); } } + + // If MIRI_BACKTRACE is set and RUST_CTFE_BACKTRACE is not, set RUST_CTFE_BACKTRACE. + // Do this late, so we really only apply this to miri's errors. + if let Ok(var) = env::var("MIRI_BACKTRACE") { + if env::var("RUST_CTFE_BACKTRACE") == Err(env::VarError::NotPresent) { + env::set_var("RUST_CTFE_BACKTRACE", &var); + } + } } fn find_sysroot() -> String { diff --git a/src/lib.rs b/src/lib.rs index 7643f93fdc2c..bb6c9e3ca503 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,6 @@ extern crate rustc_target; use std::collections::HashMap; use std::borrow::Cow; -use std::env; use rustc::ty::{self, TyCtxt, query::TyCtxtAt}; use rustc::ty::layout::{TyLayout, LayoutOf, Size, Align}; @@ -184,14 +183,6 @@ pub fn eval_main<'a, 'tcx: 'a>( ) { let mut ecx = create_ecx(tcx, main_id, validate).expect("Couldn't create ecx"); - // If MIRI_BACKTRACE is set and RUST_CTFE_BACKTRACE is not, set RUST_CTFE_BACKTRACE. - // Do this late, so we really only apply this to miri's errors. - if let Ok(var) = env::var("MIRI_BACKTRACE") { - if env::var("RUST_CTFE_BACKTRACE") == Err(env::VarError::NotPresent) { - env::set_var("RUST_CTFE_BACKTRACE", &var); - } - } - // Run! The main execution. let res: EvalResult = (|| { ecx.run()?; From e81d81e5af07f65a51e8496fda524b4cfbc09677 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Jan 2019 11:23:08 +0100 Subject: [PATCH 0525/5092] implement panic_if_uninhabited intrinsic --- src/intrinsic.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 0f7382b61b72..0ef847236418 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -286,6 +286,14 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_scalar(result_ptr, dest)?; } + "panic_if_uninhabited" => { + let ty = substs.type_at(0); + let layout = this.layout_of(ty)?; + if layout.abi.is_uninhabited() { + return err!(Intrinsic(format!("Trying to instantiate uninhabited type {}", ty))) + } + } + "powf32" => { let f = this.read_scalar(args[0])?.to_f32()?; let f2 = this.read_scalar(args[1])?.to_f32()?; From 6c9e702d9bdcef31a73949617cf5cb53c94c5dcb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 4 Jan 2019 16:03:39 +0100 Subject: [PATCH 0526/5092] range_map: also test size of the internal representation --- src/range_map.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/range_map.rs b/src/range_map.rs index 762b17b1ae33..84965fd4cf73 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -203,6 +203,7 @@ mod tests { } // Check assert_eq!(to_vec(&map, 10, 1), vec![42]); + assert_eq!(map.map.len(), 3); // Insert with size 0 for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(0)) { @@ -212,6 +213,7 @@ mod tests { *x = 19; } assert_eq!(to_vec(&map, 10, 2), vec![42, -1]); + assert_eq!(map.map.len(), 3); } #[test] @@ -223,6 +225,7 @@ mod tests { for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(1)) { *x = 43; } + assert_eq!(map.map.len(), 5); assert_eq!( to_vec(&map, 10, 10), vec![-1, 42, -1, -1, -1, 43, -1, -1, -1, -1] @@ -233,6 +236,7 @@ mod tests { *x = 23; } } + assert_eq!(map.map.len(), 6); assert_eq!( to_vec(&map, 10, 10), @@ -244,6 +248,7 @@ mod tests { for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(10)) { *x = 19; } + assert_eq!(map.map.len(), 6); assert_eq!(map.iter(Size::from_bytes(19), Size::from_bytes(1)) .map(|&t| t).collect::>(), vec![19]); assert_eq!(map.iter(Size::from_bytes(20), Size::from_bytes(1)) From f24d0354f95615731d49a993adf2ea2983b661c1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Jan 2019 12:59:33 +0100 Subject: [PATCH 0527/5092] rewrite RangeMap to use a sorted Vec instead of a RangeMap This gives us a 20% perf improve for the benchmark from https://github.com/solson/miri/issues/593 --- src/range_map.rs | 253 ++++++++++++++++++++++++----------------------- 1 file changed, 127 insertions(+), 126 deletions(-) diff --git a/src/range_map.rs b/src/range_map.rs index 84965fd4cf73..5b7a940329b0 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -6,62 +6,29 @@ //! necessary (e.g. when [0,5) is first associated with X, and then [1,2) is mutated). //! Users must not depend on whether a range is coalesced or not, even though this is observable //! via the iteration APIs. -use std::collections::BTreeMap; + use std::ops; +use std::num::NonZeroU64; use rustc::ty::layout::Size; -#[derive(Clone, Debug, PartialEq, Eq)] +// Representation: offset-length-data tuples, sorted by offset. +#[derive(Clone, Debug)] +struct Elem { + offset: u64, + len: NonZeroU64, + data: T, +} +// Length is always > 0. +#[derive(Clone, Debug)] pub struct RangeMap { - map: BTreeMap, + v: Vec>, } -// The derived `Ord` impl sorts first by the first field, then, if the fields are the same, -// by the second field. -// This is exactly what we need for our purposes, since a range query on a BTReeSet/BTreeMap will give us all -// `MemoryRange`s whose `start` is <= than the one we're looking for, but not > the end of the range we're checking. -// At the same time the `end` is irrelevant for the sorting and range searching, but used for the check. -// This kind of search breaks, if `end < start`, so don't do that! -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] -struct Range { - start: u64, - end: u64, // Invariant: end > start -} - -impl Range { - /// Compute a range of ranges that contains all ranges overlaping with [offset, offset+len) - fn range(offset: u64, len: u64) -> ops::Range { - if len == 0 { - // We can produce an empty range, nothing overlaps with this. - let r = Range { start: 0, end: 1 }; - return r..r; - } - // We select all elements that are within - // the range given by the offset into the allocation and the length. - // This is sound if all ranges that intersect with the argument range, are in the - // resulting range of ranges. - let left = Range { - // lowest range to include `offset` - start: 0, - end: offset + 1, - }; - let right = Range { - // lowest (valid) range not to include `offset+len` - start: offset + len, - end: offset + len + 1, - }; - left..right - } - - /// Tests if any element of [offset, offset+len) is contained in this range. +impl Elem { #[inline(always)] - fn overlaps(&self, offset: u64, len: u64) -> bool { - if len == 0 { - // `offset` totally does not matter, we cannot overlap with an empty interval - false - } else { - offset < self.end && offset.checked_add(len).unwrap() >= self.start - } + fn contains(&self, offset: u64) -> bool { + offset >= self.offset && offset < self.offset + self.len.get() } } @@ -70,73 +37,95 @@ impl RangeMap { /// the entire range. #[inline(always)] pub fn new(size: Size, init: T) -> RangeMap { - let mut map = RangeMap { map: BTreeMap::new() }; - if size.bytes() > 0 { - map.map.insert(Range { start: 0, end: size.bytes() }, init); + let size = size.bytes(); + let mut map = RangeMap { v: Vec::new() }; + if size > 0 { + map.v.push(Elem { + offset: 0, + len: NonZeroU64::new(size).unwrap(), + data: init + }); } map } - fn iter_with_range<'a>( - &'a self, - offset: u64, - len: u64, - ) -> impl Iterator + 'a { - self.map.range(Range::range(offset, len)).filter_map( - move |(range, data)| { - debug_assert!(len > 0); - if range.overlaps(offset, len) { - Some((range, data)) - } else { - None - } - }, - ) + /// Find the index containing the given offset. + fn find_offset(&self, offset: u64) -> usize { + debug_assert!(self.v.len() > 0); + let mut left = 0usize; // inclusive + let mut right = self.v.len(); // exclusive + loop { + let candidate = left.checked_add(right).unwrap() / 2; + let elem = &self.v[candidate]; + if elem.offset > offset { + // we are too far right (offset is further left) + debug_assert!(candidate < right); // we are making progress + right = candidate; + } else if offset >= elem.offset + elem.len.get() { + // we are too far left (offset is further right) + debug_assert!(candidate >= left); // we are making progress + left = candidate+1; + debug_assert!(left < right, "find_offset: offset {} is out-of-bounds", offset); + } else { + // This is it! + return candidate; + } + } } /// Provide read-only iteration over everything in the given range. This does /// *not* split items if they overlap with the edges. Do not use this to mutate /// through interior mutability. pub fn iter<'a>(&'a self, offset: Size, len: Size) -> impl Iterator + 'a { - self.iter_with_range(offset.bytes(), len.bytes()).map(|(_, data)| data) + let offset = offset.bytes(); + let len = len.bytes(); + // Compute a slice starting with the elements we care about + let slice: &[Elem] = if len == 0 { + // We just need any empty iterator. We don't even want to + // yield the element that surrounds this position. + &[] + } else { + let first = self.find_offset(offset); + &self.v[first..] + }; + let end = offset + len; // the first offset that is not included any more + slice.iter() + .take_while(move |elem| elem.offset < end) + .map(|elem| &elem.data) } pub fn iter_mut_all<'a>(&'a mut self) -> impl Iterator + 'a { - self.map.values_mut() + self.v.iter_mut().map(|elem| &mut elem.data) } - fn split_entry_at(&mut self, offset: u64) + // Split the element situated at the given `index`, such that the 2nd one starts at offset `split_offset`. + // Do nothing if the element already starts there. + // Return whether a split was necessary. + fn split_index(&mut self, index: usize, split_offset: u64) -> bool where T: Clone, { - let range = match self.iter_with_range(offset, 1).next() { - Some((&range, _)) => range, - None => return, - }; - assert!( - range.start <= offset && range.end > offset, - "We got a range that doesn't even contain what we asked for." - ); - // There is an entry overlapping this position, see if we have to split it - if range.start < offset { - let data = self.map.remove(&range).unwrap(); - let old = self.map.insert( - Range { - start: range.start, - end: offset, - }, - data.clone(), - ); - assert!(old.is_none()); - let old = self.map.insert( - Range { - start: offset, - end: range.end, - }, - data, - ); - assert!(old.is_none()); + let elem = &mut self.v[index]; + let first_len = split_offset.checked_sub(elem.offset) + .expect("The split_offset is before the element to be split"); + assert!(first_len <= elem.len.get(), + "The split_offset is after the element to be split"); + if first_len == 0 || first_len == elem.len.get() { + // Nothing to do + return false; } + + // Now we really have to split. Reduce length of first element. + let second_len = elem.len.get() - first_len; + elem.len = NonZeroU64::new(first_len).unwrap(); + // Copy the data, and insert 2nd element + let second = Elem { + offset: split_offset, + len: NonZeroU64::new(second_len).unwrap(), + data: elem.data.clone(), + }; + self.v.insert(index+1, second); + return true; } /// Provide mutable iteration over everything in the given range. As a side-effect, @@ -152,28 +141,43 @@ impl RangeMap { { let offset = offset.bytes(); let len = len.bytes(); - - if len > 0 { - // Preparation: Split first and last entry as needed. - self.split_entry_at(offset); - self.split_entry_at(offset + len); - } - // Now we can provide a mutable iterator - self.map.range_mut(Range::range(offset, len)).filter_map( - move |(&range, data)| { - debug_assert!(len > 0); - if range.overlaps(offset, len) { - assert!( - offset <= range.start && offset + len >= range.end, - "The splitting went wrong" - ); - Some(data) - } else { - // Skip this one - None + // Compute a slice containing exactly the elements we care about + let slice: &mut [Elem] = if len == 0 { + // We just need any empty iterator. We don't even want to + // yield the element that surrounds this position, nor do + // any splitting. + &mut [] + } else { + // Make sure we got a clear beginning + let mut first = self.find_offset(offset); + if self.split_index(first, offset) { + // The newly created 2nd element is ours + first += 1; } - }, - ) + let first = first; // no more mutation + // Find our end. Linear scan, but that's okay because the iteration + // is doing the same linear scan anyway -- no increase in complexity. + let mut end = first; // the last element to be included + loop { + let elem = &self.v[end]; + if elem.offset+elem.len.get() < offset+len { + // We need to scan further. + end += 1; + debug_assert!(end < self.v.len(), "iter_mut: end-offset {} is out-of-bounds", offset+len); + } else { + // `elem` is the last included element. Stop search. + break; + } + } + let end = end; // no more mutation + // We need to split the end as well. Even if this performs a + // split, we don't have to adjust our index as we only care about + // the first part of the split. + self.split_index(end, offset+len); + // Now we yield the slice. `end` is inclusive. + &mut self.v[first..=end] + }; + slice.iter_mut().map(|elem| &mut elem.data) } } @@ -203,7 +207,7 @@ mod tests { } // Check assert_eq!(to_vec(&map, 10, 1), vec![42]); - assert_eq!(map.map.len(), 3); + assert_eq!(map.v.len(), 3); // Insert with size 0 for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(0)) { @@ -213,7 +217,7 @@ mod tests { *x = 19; } assert_eq!(to_vec(&map, 10, 2), vec![42, -1]); - assert_eq!(map.map.len(), 3); + assert_eq!(map.v.len(), 3); } #[test] @@ -225,7 +229,7 @@ mod tests { for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(1)) { *x = 43; } - assert_eq!(map.map.len(), 5); + assert_eq!(map.v.len(), 5); assert_eq!( to_vec(&map, 10, 10), vec![-1, 42, -1, -1, -1, 43, -1, -1, -1, -1] @@ -236,7 +240,7 @@ mod tests { *x = 23; } } - assert_eq!(map.map.len(), 6); + assert_eq!(map.v.len(), 6); assert_eq!( to_vec(&map, 10, 10), @@ -244,14 +248,11 @@ mod tests { ); assert_eq!(to_vec(&map, 13, 5), vec![23, 23, 43, 23, 23]); - // Now request a range that goes beyond the initial size - for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(10)) { + for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(5)) { *x = 19; } - assert_eq!(map.map.len(), 6); + assert_eq!(map.v.len(), 6); assert_eq!(map.iter(Size::from_bytes(19), Size::from_bytes(1)) .map(|&t| t).collect::>(), vec![19]); - assert_eq!(map.iter(Size::from_bytes(20), Size::from_bytes(1)) - .map(|&t| t).collect::>(), vec![]); } } From 4f9c14c256b08458c873290a5e34eb493156532e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Jan 2019 15:26:16 +0100 Subject: [PATCH 0528/5092] deduplicate RangeMap elements in iter_mut This cuts down execution time of the benchmark in the OP of https://github.com/solson/miri/issues/593 by another 25%, and it cuts max-RSS by 90% (!) --- src/lib.rs | 2 +- src/range_map.rs | 111 ++++++++++++++++++++++++----------------- src/stacked_borrows.rs | 2 +- 3 files changed, 67 insertions(+), 48 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index bb6c9e3ca503..a8fd432282a1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(rustc_private)] +#![feature(rustc_private, range_contains)] #![allow(clippy::cast_lossless)] diff --git a/src/range_map.rs b/src/range_map.rs index 5b7a940329b0..d157cbf0549f 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -12,26 +12,16 @@ use std::num::NonZeroU64; use rustc::ty::layout::Size; -// Representation: offset-length-data tuples, sorted by offset. #[derive(Clone, Debug)] struct Elem { - offset: u64, - len: NonZeroU64, + range: ops::Range, // the range covered by this element, never empty data: T, } -// Length is always > 0. #[derive(Clone, Debug)] pub struct RangeMap { v: Vec>, } -impl Elem { - #[inline(always)] - fn contains(&self, offset: u64) -> bool { - offset >= self.offset && offset < self.offset + self.len.get() - } -} - impl RangeMap { /// Create a new RangeMap for the given size, and with the given initial value used for /// the entire range. @@ -41,8 +31,7 @@ impl RangeMap { let mut map = RangeMap { v: Vec::new() }; if size > 0 { map.v.push(Elem { - offset: 0, - len: NonZeroU64::new(size).unwrap(), + range: 0..size, data: init }); } @@ -57,11 +46,11 @@ impl RangeMap { loop { let candidate = left.checked_add(right).unwrap() / 2; let elem = &self.v[candidate]; - if elem.offset > offset { + if offset < elem.range.start { // we are too far right (offset is further left) debug_assert!(candidate < right); // we are making progress right = candidate; - } else if offset >= elem.offset + elem.len.get() { + } else if offset >= elem.range.end { // we are too far left (offset is further right) debug_assert!(candidate >= left); // we are making progress left = candidate+1; @@ -85,12 +74,12 @@ impl RangeMap { // yield the element that surrounds this position. &[] } else { - let first = self.find_offset(offset); - &self.v[first..] + let first_idx = self.find_offset(offset); + &self.v[first_idx..] }; let end = offset + len; // the first offset that is not included any more slice.iter() - .take_while(move |elem| elem.offset < end) + .take_while(move |elem| elem.range.start < end) .map(|elem| &elem.data) } @@ -106,22 +95,19 @@ impl RangeMap { T: Clone, { let elem = &mut self.v[index]; - let first_len = split_offset.checked_sub(elem.offset) - .expect("The split_offset is before the element to be split"); - assert!(first_len <= elem.len.get(), - "The split_offset is after the element to be split"); - if first_len == 0 || first_len == elem.len.get() { + if split_offset == elem.range.start || split_offset == elem.range.end { // Nothing to do return false; } + debug_assert!(elem.range.contains(&split_offset), + "The split_offset is not in the element to be split"); // Now we really have to split. Reduce length of first element. - let second_len = elem.len.get() - first_len; - elem.len = NonZeroU64::new(first_len).unwrap(); + let second_range = split_offset..elem.range.end; + elem.range.end = split_offset; // Copy the data, and insert 2nd element let second = Elem { - offset: split_offset, - len: NonZeroU64::new(second_len).unwrap(), + range: second_range, data: elem.data.clone(), }; self.v.insert(index+1, second); @@ -137,7 +123,7 @@ impl RangeMap { len: Size, ) -> impl Iterator + 'a where - T: Clone, + T: Clone + PartialEq, { let offset = offset.bytes(); let len = len.bytes(); @@ -149,33 +135,53 @@ impl RangeMap { &mut [] } else { // Make sure we got a clear beginning - let mut first = self.find_offset(offset); - if self.split_index(first, offset) { + let mut first_idx = self.find_offset(offset); + if self.split_index(first_idx, offset) { // The newly created 2nd element is ours - first += 1; + first_idx += 1; } - let first = first; // no more mutation + let first_idx = first_idx; // no more mutation // Find our end. Linear scan, but that's okay because the iteration // is doing the same linear scan anyway -- no increase in complexity. - let mut end = first; // the last element to be included + // We combine this scan with a scan for duplicates that we can merge, to reduce + // the number of elements. + let mut equal_since_idx = first_idx; + let mut end_idx = first_idx; // when the loop is done, this is the first excluded element. loop { - let elem = &self.v[end]; - if elem.offset+elem.len.get() < offset+len { - // We need to scan further. - end += 1; - debug_assert!(end < self.v.len(), "iter_mut: end-offset {} is out-of-bounds", offset+len); - } else { - // `elem` is the last included element. Stop search. + // Compute if `end` is the last element we need to look at. + let done = (self.v[end_idx].range.end >= offset+len); + // We definitely need to include `end`, so move the index. + end_idx += 1; + debug_assert!(done || end_idx < self.v.len(), "iter_mut: end-offset {} is out-of-bounds", offset+len); + // see if we want to merge everything in `equal_since..end` (exclusive at the end!) + if done || self.v[end_idx].data != self.v[equal_since_idx].data { + // Everything in `equal_since..end` was equal. Make them just one element covering + // the entire range. + let equal_elems = end_idx - equal_since_idx; // number of equal elements + if equal_elems > 1 { + // Adjust the range of the first element to cover all of them. + let equal_until = self.v[end_idx - 1].range.end; // end of range of last of the equal elements + self.v[equal_since_idx].range.end = equal_until; + // Delete the rest of them. + self.v.splice(equal_since_idx+1..end_idx, std::iter::empty()); + // Adjust `end_idx` because we made the list shorter. + end_idx -= (equal_elems - 1); + } + // Go on scanning. + equal_since_idx = end_idx; + } + // Leave loop if this is the last element. + if done { break; } } - let end = end; // no more mutation + let end_idx = end_idx-1; // Move to last included instead of first excluded index. // We need to split the end as well. Even if this performs a // split, we don't have to adjust our index as we only care about // the first part of the split. - self.split_index(end, offset+len); + self.split_index(end_idx, offset+len); // Now we yield the slice. `end` is inclusive. - &mut self.v[first..=end] + &mut self.v[first_idx..=end_idx] }; slice.iter_mut().map(|elem| &mut elem.data) } @@ -241,18 +247,31 @@ mod tests { } } assert_eq!(map.v.len(), 6); - assert_eq!( to_vec(&map, 10, 10), vec![23, 42, 23, 23, 23, 43, 23, 23, 23, 23] ); assert_eq!(to_vec(&map, 13, 5), vec![23, 23, 43, 23, 23]); + for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(5)) { *x = 19; } assert_eq!(map.v.len(), 6); - assert_eq!(map.iter(Size::from_bytes(19), Size::from_bytes(1)) - .map(|&t| t).collect::>(), vec![19]); + assert_eq!( + to_vec(&map, 10, 10), + vec![23, 42, 23, 23, 23, 19, 19, 19, 19, 19] + ); + // Should be seeing two blocks with 19 + assert_eq!(map.iter(Size::from_bytes(15), Size::from_bytes(2)) + .map(|&t| t).collect::>(), vec![19, 19]); + + // a NOP iter_mut should trigger merging + for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(5)) { } + assert_eq!(map.v.len(), 5); + assert_eq!( + to_vec(&map, 10, 10), + vec![23, 42, 23, 23, 23, 19, 19, 19, 19, 19] + ); } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 27d4a4f7f7b5..1fc705c03bb5 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -67,7 +67,7 @@ pub enum BorStackItem { } /// Extra per-location state -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct Stack { borrows: Vec, // used as a stack; never empty frozen_since: Option, // virtual frozen "item" on top of the stack From 17d11ebe6e9599d804c0378900b92a5a8054aec3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Jan 2019 16:16:08 +0100 Subject: [PATCH 0529/5092] be explicit about doing a binary search; fix out-of-bounds check --- src/range_map.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/range_map.rs b/src/range_map.rs index d157cbf0549f..d21f1ed8964d 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -40,10 +40,11 @@ impl RangeMap { /// Find the index containing the given offset. fn find_offset(&self, offset: u64) -> usize { - debug_assert!(self.v.len() > 0); + // We do a binary search let mut left = 0usize; // inclusive let mut right = self.v.len(); // exclusive loop { + debug_assert!(left < right, "find_offset: offset {} is out-of-bounds", offset); let candidate = left.checked_add(right).unwrap() / 2; let elem = &self.v[candidate]; if offset < elem.range.start { @@ -54,7 +55,6 @@ impl RangeMap { // we are too far left (offset is further right) debug_assert!(candidate >= left); // we are making progress left = candidate+1; - debug_assert!(left < right, "find_offset: offset {} is out-of-bounds", offset); } else { // This is it! return candidate; From a957a36ddcb1a735719a96f1fb35c9ac0d604bf3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Jan 2019 19:36:25 +0100 Subject: [PATCH 0530/5092] tweak merging to give up if we don't make any progress --- src/range_map.rs | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/range_map.rs b/src/range_map.rs index d21f1ed8964d..48cbc57f0ebc 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -145,7 +145,12 @@ impl RangeMap { // is doing the same linear scan anyway -- no increase in complexity. // We combine this scan with a scan for duplicates that we can merge, to reduce // the number of elements. + // We stop searching after the first "block" of size 1, to avoid spending excessive + // amounts of time on the merging. let mut equal_since_idx = first_idx; + // Once we see too many non-mergeable blocks, we stop. + // The initial value is chosen via... magic. Benchmarking and magic. + let mut successful_merge_count = 3usize; let mut end_idx = first_idx; // when the loop is done, this is the first excluded element. loop { // Compute if `end` is the last element we need to look at. @@ -154,21 +159,28 @@ impl RangeMap { end_idx += 1; debug_assert!(done || end_idx < self.v.len(), "iter_mut: end-offset {} is out-of-bounds", offset+len); // see if we want to merge everything in `equal_since..end` (exclusive at the end!) - if done || self.v[end_idx].data != self.v[equal_since_idx].data { - // Everything in `equal_since..end` was equal. Make them just one element covering - // the entire range. - let equal_elems = end_idx - equal_since_idx; // number of equal elements - if equal_elems > 1 { - // Adjust the range of the first element to cover all of them. - let equal_until = self.v[end_idx - 1].range.end; // end of range of last of the equal elements - self.v[equal_since_idx].range.end = equal_until; - // Delete the rest of them. - self.v.splice(equal_since_idx+1..end_idx, std::iter::empty()); - // Adjust `end_idx` because we made the list shorter. - end_idx -= (equal_elems - 1); + if successful_merge_count > 0 { + if done || self.v[end_idx].data != self.v[equal_since_idx].data { + // Everything in `equal_since..end` was equal. Make them just one element covering + // the entire range. + let removed_elems = end_idx - equal_since_idx - 1; // number of elements that we would remove + if removed_elems > 0 { + // Adjust the range of the first element to cover all of them. + let equal_until = self.v[end_idx - 1].range.end; // end of range of last of the equal elements + self.v[equal_since_idx].range.end = equal_until; + // Delete the rest of them. + self.v.splice(equal_since_idx+1..end_idx, std::iter::empty()); + // Adjust `end_idx` because we made the list shorter. + end_idx -= removed_elems; + // adjust the count for the cutoff + successful_merge_count += removed_elems; + } else { + // adjust the count for the cutoff + successful_merge_count -= 1; + } + // Go on scanning for the next block starting here. + equal_since_idx = end_idx; } - // Go on scanning. - equal_since_idx = end_idx; } // Leave loop if this is the last element. if done { From 44612aa8348fd204b0678b385e285271874ebc26 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Jan 2019 19:39:49 +0100 Subject: [PATCH 0531/5092] add the benchmarks I used --- bench-cargo-miri/mse/Cargo.toml | 7 +++++++ bench-cargo-miri/mse/src/main.rs | 26 ++++++++++++++++++++++++++ bench-cargo-miri/serde1/Cargo.toml | 9 +++++++++ bench-cargo-miri/serde1/src/main.rs | 13 +++++++++++++ 4 files changed, 55 insertions(+) create mode 100644 bench-cargo-miri/mse/Cargo.toml create mode 100644 bench-cargo-miri/mse/src/main.rs create mode 100644 bench-cargo-miri/serde1/Cargo.toml create mode 100644 bench-cargo-miri/serde1/src/main.rs diff --git a/bench-cargo-miri/mse/Cargo.toml b/bench-cargo-miri/mse/Cargo.toml new file mode 100644 index 000000000000..7b4c2dc758fa --- /dev/null +++ b/bench-cargo-miri/mse/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "mse" +version = "0.1.0" +authors = ["Ralf Jung "] +edition = "2018" + +[dependencies] diff --git a/bench-cargo-miri/mse/src/main.rs b/bench-cargo-miri/mse/src/main.rs new file mode 100644 index 000000000000..7d00a623468e --- /dev/null +++ b/bench-cargo-miri/mse/src/main.rs @@ -0,0 +1,26 @@ +static EXPECTED: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 254, 255, 0, 0, 254, 255, 0, 0, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 255, 255, 1, 0, 255, 255, 1, 0, 0, 0, 1, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 0, 0, 254, 255, 0, 0, 254, 255, 0, 0, 254, 255, 255, 255, 254, 255, 254, 255, 254, 255, 253, 255, 253, 255, 253, 255, 253, 255, 252, 255, 254, 255, 251, 255, 254, 255, 251, 255, 254, 255, 252, 255, 255, 255, 252, 255, 0, 0, 252, 255, 0, 0, 252, 255, 1, 0, 252, 255, 1, 0, 252, 255, 2, 0, 252, 255, 2, 0, 252, 255, 2, 0, 252, 255, 2, 0, 252, 255, 2, 0, 253, 255, 1, 0, 252, 255, 0, 0, 252, 255, 255, 255, 251, 255, 0, 0, 251, 255, 0, 0, 251, 255, 0, 0, 252, 255, 2, 0, 252, 255, 3, 0, 252, 255, 4, 0, 253, 255, 5, 0, 254, 255, 5, 0, 253, 255, 6, 0, 253, 255, 6, 0, 253, 255, 5, 0, 253, 255, 5, 0, 254, 255, 4, 0, 254, 255, 3, 0, 251, 255, 0, 0, 250, 255, 255, 255, 253, 255, 254, 255, 252, 255, 252, 255, 247, 255, 251, 255, 247, 255, 252, 255, 252, 255, 254, 255, 252, 255, 254, 255, 252, 255, 255, 255, 254, 255, 1, 0, 1, 0, 1, 0, 4, 0, 2, 0, 8, 0, 2, 0, 12, 0, 1, 0, 13, 0, 0, 0, 12, 0, 0, 0, 11, 0, 255, 255, 8, 0, 254, 255, 7, 0, 0, 0, 7, 0, 253, 255, 11, 0, 248, 255, 15, 0, 247, 255, 17, 0, 250, 255, 17, 0, 251, 255, 13, 0, 253, 255, 7, 0, 255, 255, 3, 0, 255, 255, 254, 255, 255, 255, 252, 255, 255, 255, 252, 255, 254, 255, 250, 255, 255, 255, 242, 255, 254, 255, 239, 255, 252, 255, 248, 255, 255, 255, 249, 255, 5, 0, 239, 255, 7, 0, 238, 255, 10, 0, 249, 255, 18, 0, 254, 255, 25, 0, 253, 255, 27, 0, 0, 0, 31, 0, 4, 0, 34, 0, 4, 0, 34, 0, 8, 0, 36, 0, 8, 0, 37, 0, 2, 0, 36, 0, 4, 0, 34, 0, 8, 0, 28, 0, 3, 0, 15, 0, 255, 255, 11, 0, 0, 0, 12, 0, 251, 255, 8, 0, 252, 255, 10, 0, 0, 0, 23, 0, 252, 255, 31, 0, 248, 255, 30, 0, 254, 255, 30, 0, 255, 255, 26, 0, 250, 255, 22, 0, 250, 255, 20, 0, 244, 255, 15, 0, 237, 255, 10, 0, 246, 255, 13, 0, 242, 255, 6, 0, 213, 255, 243, 255, 213, 255, 240, 255, 247, 255, 244, 255, 246, 255, 227, 255, 214, 255, 216, 255, 219, 255, 228, 255, 251, 255, 235, 255, 1, 0, 232, 255, 248, 255, 236, 255, 4, 0, 238, 255, 26, 0, 232, 255, 44, 0, 230, 255, 66, 0, 226, 255, 86, 0, 219, 255, 88, 0, 215, 255, 72, 0, 210, 255, 50, 0, 225, 255, 28, 0, 23, 0, 14, 0, 64, 0, 16, 0, 51, 0, 26, 0, 32, 0, 34, 0, 39, 0, 42, 0, 48, 0, 35, 0, 58, 0, 255, 255, 72, 0, 220, 255, 69, 0, 197, 255, 58, 0, 158, 255, 54, 0, 132, 255, 36, 0, 153, 255, 12, 0, 146, 255, 5, 0, 83, 255, 237, 255, 110, 255, 197, 255, 252, 255, 214, 255, 51, 0, 1, 0, 233, 255, 250, 255, 226, 255, 250, 255, 45, 0, 46, 0, 47, 0, 70, 0, 6, 0, 55, 0, 19, 0, 60, 0, 38, 0, 62, 0, 42, 0, 47, 0, 61, 0, 46, 0, 40, 0, 42, 0, 237, 255, 22, 0, 222, 255, 6, 0, 221, 255, 206, 255, 195, 255, 115, 255, 219, 255, 85, 255, 17, 0, 93, 255, 26, 0, 76, 255, 46, 0, 102, 255, 80, 0, 193, 255, 48, 0, 252, 255, 18, 0, 20, 0, 50, 0, 47, 0, 58, 0, 53, 0, 44, 0, 61, 0, 57, 0, 85, 0, 37, 0, 80, 0, 0, 0, 86, 0, 248, 255, 106, 0, 161, 255, 49, 0, 43, 255, 248, 255, 125, 255, 47, 0, 49, 0, 63, 0, 40, 0, 217, 255, 187, 255, 182, 255, 219, 255, 236, 255, 63, 0, 244, 255, 58, 0, 242, 255, 244, 255, 25, 0, 225, 255, 41, 0, 11, 0, 45, 0, 76, 0, 47, 0, 167, 0, 5, 0, 5, 1, 219, 255, 21, 1, 173, 255, 183, 0, 84, 255, 35, 0, 134, 255, 177, 255, 138, 0, 186, 255, 10, 1, 69, 0, 124, 0, 228, 0, 0, 0, 135, 1, 227, 255, 82, 2, 172, 255, 190, 2, 178, 255, 115, 2, 248, 255, 39, 2, 243, 255, 253, 1, 13, 0, 116, 1, 120, 0, 96, 1, 125, 0, 110, 2, 127, 0, 179, 2, 223, 0, 106, 1, 126, 0, 130, 1, 223, 255, 147, 3, 198, 0, 190, 3, 201, 1, 200, 1, 42, 1, 244, 1, 233, 0, 3, 4, 213, 1, 72, 4, 170, 1, 150, 3, 160, 0, 43, 4, 141, 0, 196, 4, 189, 0, 221, 4, 164, 0, 95, 5, 41, 1, 98, 5, 247, 1, 19, 5, 190, 2, 14, 6, 161, 3, 7, 7, 87, 3, 216, 6, 35, 2, 38, 7, 90, 2, 136, 7, 64, 3, 200, 6, 28, 3, 199, 6, 165, 3, 169, 7, 105, 5, 143, 7, 26, 6, 57, 8, 205, 5, 156, 10, 169, 5, 132, 11, 25, 5, 208, 10, 181, 4, 156, 10, 66, 5, 227, 9, 170, 5, 166, 9, 117, 6, 45, 12, 63, 8, 42, 13, 128, 8, 136, 10, 155, 7, 109, 11, 1, 9, 6, 15, 98, 10, 121, 9, 136, 8, 147, 252, 189, 7, 43, 247, 63, 10, 147, 249, 92, 11, 172, 248, 172, 10, 112, 245, 137, 11, 76, 246, 44, 12, 184, 247, 138, 11, 118, 246, 144, 12, 94, 246, 171, 13, 112, 247, 162, 12, 168, 246, 33, 13, 63, 246, 29, 15, 226, 247, 188, 14, 190, 248, 75, 15, 238, 247, 86, 17, 19, 247, 118, 11, 10, 247, 232, 254, 238, 247, 30, 249, 56, 248, 124, 250, 6, 247, 1, 250, 161, 246, 3, 249, 81, 247, 117, 250, 60, 247, 202, 250, 212, 247, 60, 250, 15, 249, 140, 250, 34, 248, 221, 249, 105, 247, 218, 249, 205, 248, 113, 251, 138, 248, 90, 250, 41, 248, 230, 248]; +static PCM: &[i16] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1, 0, 1, 0, 0, -2, 0, -2, 0, -2, 0, -2, -2, -2, -3, -3, -3, -3, -4, -2, -5, -2, -5, -2, -4, 0, -4, 0, -4, 0, -4, 1, -4, 1, -4, 2, -4, 2, -4, 2, -4, 2, -4, 2, -3, 1, -4, 0, -4, 0, -5, 0, -5, 0, -5, 0, -4, 2, -4, 3, -4, 4, -3, 5, -2, 5, -3, 6, -3, 6, -3, 5, -3, 5, -2, 4, -2, 3, -5, 0, -6, 0, -3, -2, -4, -4, -9, -5, -9, -4, -4, -2, -4, -2, -4, 0, -2, 1, 1, 1, 4, 2, 8, 2, 12, 1, 13, 0, 12, 0, 11, 0, 8, -2, 7, 0, 7, -3, 11, -8, 15, -9, 17, -6, 17, -5, 13, -3, 7, 0, 3, 0, -2, 0, -4, 0, -4, -2, -6, 0, -14, -2, -17, -4, -8, 0, -7, 5, -17, 7, -18, 10, -7, 18, -2, 25, -3, 27, 0, 31, 4, 34, 4, 34, 8, 36, 8, 37, 2, 36, 4, 34, 8, 28, 3, 15, 0, 11, 0, 12, -5, 8, -4, 10, 0, 23, -4, 31, -8, 30, -2, 30, 0, 26, -6, 22, -6, 20, -12, 15, -19, 10, -10, 13, -14, 6, -43, -13, -43, -16, -9, -12, -10, -29, -42, -40, -37, -28, -5, -21, 1, -24, -8, -20, 4, -18, 26, -24, 44, -26, 66, -30, 86, -37, 88, -41, 72, -46, 50, -31, 28, 23, 14, 64, 16, 51, 26, 32, 34, 39, 42, 48, 35, 58, 0, 72, -36, 69, -59, 58, -98, 54, -124, 36, -103, 12, -110, 5, -173, -19, -146, -59, -4, -42, 51, 1, -23, -6, -30, -6, 45, 46, 47, 70, 6, 55, 19, 60, 38, 62, 42, 47, 61, 46, 40, 42, -19, 22, -34, 6, -35, -50, -61, -141, -37, -171, 17, -163, 26, -180, 46, -154, 80, -63, 48, -4, 18, 20, 50, 47, 58, 53, 44, 61, 57, 85, 37, 80, 0, 86, -8, 106, -95, 49, -213, -8, -131, 47, 49, 63, 40, -39, -69, -74, -37, -20, 63, -12, 58, -14, -12, 25, -31, 41, 11, 45, 76, 47, 167, 5, 261, -37, 277, -83, 183, -172, 35, -122, -79, 138, -70, 266, 69, 124, 228, 0, 391, -29, 594, -84, 702, -78, 627, -8, 551, -13, 509, 13, 372, 120, 352, 125, 622, 127, 691, 223, 362, 126, 386, -33, 915, 198, 958, 457, 456, 298, 500, 233, 1027, 469, 1096, 426, 918, 160, 1067, 141, 1220, 189, 1245, 164, 1375, 297, 1378, 503, 1299, 702, 1550, 929, 1799, 855, 1752, 547, 1830, 602, 1928, 832, 1736, 796, 1735, 933, 1961, 1385, 1935, 1562, 2105, 1485, 2716, 1449, 2948, 1305, 2768, 1205, 2716, 1346, 2531, 1450, 2470, 1653, 3117, 2111, 3370, 2176, 2696, 1947, 2925, 2305, 3846, 2658, 2425, 2184, -877, 1981, -2261, 2623, -1645, 2908, -1876, 2732, -2704, 2953, -2484, 3116, -2120, 2954, -2442, 3216, -2466, 3499, -2192, 3234, -2392, 3361, -2497, 3869, -2078, 3772, -1858, 3915, -2066, 4438, -2285, 2934, -2294, -280, -2066, -1762, -1992, -1412, -2298, -1535, -2399, -1789, -2223, -1419, -2244, -1334, -2092, -1476, -1777, -1396, -2014, -1571, -2199, -1574, -1843, -1167, -1910, -1446, -2007, -1818]; + +fn main() { + mse(PCM.len(), PCM, EXPECTED); +} + +fn read_i16(buffer: &[u8], index: usize) -> i16 { + const SIZE: usize = std::mem::size_of::(); + let mut bytes: [u8; SIZE] = [0u8; SIZE]; + bytes.copy_from_slice(&buffer[(index * SIZE)..(index * SIZE + SIZE)]); + unsafe { std::mem::transmute(bytes) } +} + +fn mse(samples: usize, frame_buf: &[i16], buf_ref: &[u8]) -> f64 { + let mut mse = 0.0; + let max_samples = std::cmp::min(buf_ref.len() / 2, samples as usize); + for i in 0..max_samples { + let ref_res = read_i16(buf_ref, i); + let info_res = frame_buf[i as usize]; + let diff = (ref_res - info_res).abs(); + mse += f64::from(diff.pow(2)); + } + mse / max_samples as f64 +} + diff --git a/bench-cargo-miri/serde1/Cargo.toml b/bench-cargo-miri/serde1/Cargo.toml new file mode 100644 index 000000000000..29f0abff5d73 --- /dev/null +++ b/bench-cargo-miri/serde1/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "cargo-miri-test" +version = "0.1.0" +authors = ["Oliver Schneider "] +edition = "2018" + +[dependencies] +serde = { version = "*", features = ["derive"] } +serde_json = "*" diff --git a/bench-cargo-miri/serde1/src/main.rs b/bench-cargo-miri/serde1/src/main.rs new file mode 100644 index 000000000000..2712156d61b4 --- /dev/null +++ b/bench-cargo-miri/serde1/src/main.rs @@ -0,0 +1,13 @@ +static JSON: &str = r#"{"buffer":[-29,-42,-40,-37,-28,-5,-21,1,-24,-8,-20,4,-18,26,-24,44,-26,66,-30,86,-37,88,-41,72,-46,50,-31,28,23,14,64,16,51,26,32,34,39,42,48,35,58,0,72,-36,69,-59,58,-98,54,-124,36,-103,12,-110,5,-173,-19,-146,-59,-4,-42,51,1,-23,-6,-30,-6,45,46,47,70,6,55,19,60,38,62,42,47,61,46,40,42,-19,22,-34,6,-35,-50,-61,-141,-37,-171,17,-163,26,-180,46,-154,80,-63,48,-4,18,20,50,47,58,53,44,61,57,85,37,80,0,86,-8,106,-95,49,-213,-8,-131,47,49,63,40,-39,-69,-74,-37,-20,63,-12,58,-14,-12,25,-31,41,11,45,76,47,167,5,261,-37,277,-83,183,-172,35,-122,-79,138,-70,266,69,124,228,0,391,-29,594,-84,702,-78,627,-8,551,-13,509,13,372,120,352,125,622,127,691,223,362,126,386,-33,915,198,958,457,456,298,500,233,1027,469,1096,426,918,160,1067,141,1220,189,1245,164,1375,297,1378,503,1299,702,1550,929,1799,855,1752,547,1830,602,1928,832,1736,796,1735,933,1961,1385,1935,1562,2105,1485,2716,1449,2948,1305,2768,1205,2716,1346,2531,1450,2470,1653,3117,2111,3370,2176,2696,1947,2925,2305,3846,2658,2425,2184,-877,1981,-2261,2623,-1645,2908,-1876,2732,-2704,2953,-2484,3116,-2120,2954,-2442,3216,-2466,3499,-2192,3234,-2392,3361,-2497,3869,-2078,3772,-1858,3915,-2066,4438,-2285,2934,-2294,-280,-2066,-1762,-1992,-1412,-2298,-1535,-2399,-1789,-2223,-1419,-2244,-1334,-2092,-1476,-1777,-1396,-2014,-1571,-2199,-1574,-1843,-1167,-1910,-1446,-2007,-1818,-1506,-1331,-2526,-2048,-5535,-4573,-7148,-5828,-6422,-5327,-5840,-5488,-5992,-6144,-6014,-6164,-6109,-6234,-6271,-6388,-6288,-6156,-6517,-6249,-6794,-6602,-6822,-6418,-6788,-6245,-6490,-6560,-6394,-6794,-7920,-6937,-10397,-7140,-11428,-6972,-11019,-6610,-11141,-6665,-11913,-7046,-11979,-7235,-11599,-7015,-11854,-6912,-12161,-7441,-12136,-7761,-12861,-7292,-13390,-7254,-12345,-7809,-12490,-7463,-13983,-6969,-10489,-8465,-2382,-11054,1272,-12247,-270,-12060,-323,-12113,502,-12486,-697,-12251,-1086,-12141,-181,-13116,-670,-13509,-1173,-12592,-443,-12811,-449,-13698,-934,-12850,-747,-13083,-873,-15036,-1161,-11478,-1047,-2669,-1407,1006,-1658,-1146,-1195,-1297,-1421,-73,-1946,-977,-1590,-1499,-1577,-1010,-1862,-1256,-1389,-962,-1692,-509,-2613,-1317,-2087,-1359,-1997,-1034,-2891,-2024,-119,-84,5651,5723,8074,8306,7156,6870,6985,7106,7312,8403,7114,8096,7173,7848,7082,7827,6761,7189,6985,7368,7076,7835,6992,7297,7453,7260,7016,7755,6025,7429,8533,7352,14150,7628,17142,7077,16399,6947,15939,7475,16564,7069,16463,6882,16400,7602,17031,7233,16543,6517,15395,7018,15985,7104,16689,6869,15655,7622,16155,7198,17884,6022,14056,8856,5665,14484,1815,16782,3034,15786,3107,15664,2312,16517,2965,16443,3036,16120,2287,16584,2479,16720,2693,16073,2535,16159,2958,16609,3067,16086,2716,16579,3035,17752,3092,13704,2499,5265,2620,1452,2808,3024,2444,3275,2839,2267,3340,2857,2968,3232,3066,2867,3152,3072,2248,2961,2413,2807,3238,3237,2368,2699,2262,2392,3537,3339,827,823,-5020,-5359,-7095,-7857,-5973,-6274,-6208,-6279,-6934,-7181,-6893,-6647,-7146,-6687,-7026,-7328,-6451,-6924,-6763,-6535,-7109,-6639,-6926,-6559,-7188,-6799,-6727,-6955,-5786,-6554,-8543,-6796,-14465,-7190,-17356,-6641,-16372,-6529,-15941,-6898,-16526,-6434,-16219,-6520,-16222,-7449,-17077,-7097,-16665,-6476,-15675,-7026,-16498,-6848,-17147,-6271,-15894,-7069,-16266,-7032,-17817,-5991,-13796,-8594,-5421,-14349,-1649,-17288,-2847,-16525,-2974,-15945,-2324,-16482,-3022,-16593,-3097,-16451,-2420,-16780,-2649,-16641,-2836,-15900,-2660,-16214,-3050,-16827,-3111,-15993,-2741,-16151,-2994,-17537,-2933,-13812,-2314,-5216,-2475,-1125,-2648,-2801,-2290,-3285,-2796,-2243,-3415,-2642,-3109,-3000,-3271,-2839,-3408,-3161,-2497,-2876,-2603,-2570,-3351,-3173,-2416,-2832,-2235,-2408,-3405,-3186,-613,-768,5271,5201,7376,7644,6241,6176,6366,6275,6964,7124,6831,6508,6998,6566,6836,7230,6277,6777,6589,6376,6934,6536,6819,6494,7160,6749,6736,6900,5822,6476,8593,6747,14520,7204,17448,6637,16490,6483,16033,6906,16600,6511,16304,6568,16279,7438,17079,7072,16624,6463,15577,7028,16343,6877,16990,6331,15760,7121,16140,7023,17719,5944,13748,8575,5401,14336,1645,17210,2880,16419,3036,15896,2382,16483,3074,16584,3143,16425,2443,16782,2650,16695,2825,15978,2632,16272,3015,16880,3084,16096,2709,16289,2965,17641,2932,13887,2323,5330,2474,1286,2656,2954,2309,3410,2803,2373,3414,2795,3106,3151,3263,2952,3403,3241,2483,2969,2568,2681,3316,3245,2383,2837,2199,2390,3396,3165,641,706,-5230,-5323,-7307,-7790,-6136,-6317,-6268,-6419,-6884,-7278,-6766,-6666,-6976,-6731,-6853,-7406,-6308,-6958,-6636,-6553,-6978,-6703,-6829,-6647,-7156,-6883,-6737,-7017,-5814,-6581,-8575,-6833,-14490,-7270,-17411,-6699,-16466,-6539,-16016,-6931,-16571,-6504,-16257,-6551,-16202,-7408,-16983,-7021,-16545,-6410,-15512,-6976,-16305,-6803,-17017,-6243,-15820,-7037,-16197,-6923,-17802,-5820,-13840,-8455,-5475,-14227,-1724,-17099,-2923,-16314,-3008,-15801,-2362,-16392,-3088,-16506,-3163,-16356,-2503,-16700,-2717,-16605,-2855,-15904,-2710,-16226,-3108,-16870,-3089,-16101,-2747,-16257,-3087,-17584,-2975,-13868,-2324,-5343,-2548,-1275,-2673,-2917,-2213,-3363,-2694,-2311,-3251,-2744,-2867,-3129,-3034,-2939,-3190,-3234,-2346,-2964,-2639,-2658,-3558,-3241,-2670,-2892,-2453,-2437,-3564,-3175,-771,-779,5105,5171,7308,7655,6265,6204,6397,6288,7024,7172,6903,6586,7002,6627,6777,7308,6190,6889,6537,6465,7011,6613,6985,6631,7393,6934,7073,7072,6112,6615,8751,6859,14672,7282,17448,6652,16146,6448,15565,6899,16151,6547,15860,6591,16048,7446,17065,7064,16661,6368,15774,6857,16524,6677,16825,6071,15577,6900,16119,7040,17490,6118,13495,8696,5432,14446,1678,17366,3036,16488,3624,15834,3012,16382,3575,16465,3685,16301,2815,16708,2982,16679,3356,15952,2934,16049,3290,16352,3964,15605,3612,16222,3647,17764,4272,13865,3977,5384,3592,1580,3794,3243,3627,3670,3622,2758,4007,3130,3835,3294,3964,3065,4468,3408,3933,3234,3789,3118,4634,3643,4211,3174,4155,3176,5512,4400,2792,1730,-3702,-4499,-5940,-6691,-4265,-5094,-4381,-5215,-4918,-5746,-4217,-4871,-4402,-4981,-4479,-5525,-3732,-4968,-4118,-4924,-4300,-5349,-3422,-5021,-3876,-4886,-4087,-4860,-2790,-4254,-5025,-4196,-10898,-4415,-13419,-4007,-12198,-4121,-11995,-4413,-12471,-3808,-11937,-3920,-11792,-4583,-12284,-3776,-12085,-3107,-11421,-3583,-11226,-3081,-11157,-2768,-10580,-3914,-10424,-3197,-11040,-1715,-9822,-5144,-6189,-11154,-4236,-13029,-5134,-11598,-5507,-10949,-4921,-11142,-4999,-11180,-4883,-11184,-4366,-11090,-4548,-10887,-4818,-10708,-4866,-10534,-5253,-10272,-5179,-9894,-4633,-10029,-4773,-10382,-4977,-8674,-4668,-5292,-4651,-3928,-4629,-4465,-4312,-3994,-4459,-3528,-4570,-4400,-4272,-4601,-4482,-4035,-4627,-4334,-4080,-4498,-4045,-3835,-4204,-3526,-3695,-3646,-4045,-4101,-4856,-4628,-3338,-3235,-673,-508,28,147,-453,-639,11,0,8,-2,7,0,7,-3,11,-8,15,-9,17,-6,17,-5,13,-3,7,0,3,0,-2,0,-4,0,-4,-2,-6,0,-14,-2,-17,-4,-8,0,-7,5,-17,7,-18,10,-7,18,-2,25,-3,27,0,31,4,34,4,34,8,36,8,37,2,36,4,34,8,28,3,15,0,11,0,12,-5,8,-4,10,0,23,-4,31,-8,30,-2,30,0,26,-6,22,-6,20,-12,15,-19,10,-10,13,-14,6,-43,-13,-43,-16,-9,-12,-10,-29,-42,-40,-37,-28,-5,-21,1,-24,-8,-20,4,-18,26,-24,44,-26,66,-30,86,-37,88,-41,72,-46,50,-31,28,23,14,64,16,51,26,32,34,39,42,48,35,58,0,72,-36,69,-59,58,-98,54,-124,36,-103,12,-110,5,-173,-19,-146,-59,-4,-42,51,1,-23,-6,-30,-6,45,46,47,70,6,55,19,60,38,62,42,47,61,46,40,42,-19,22,-34,6,-35,-50,-61,-141,-37,-171,17,-163,26,-180,46,-154,80,-63,48,-4,18,20,50,47,58,53,44,61,57,85,37,80,0,86,-8,106,-95,49,-213,-8,-131,47,49,63,40,-39,-69,-74,-37,-20,63,-12,58,-14,-12,25,-31,41,11,45,76,47,167,5,261,-37,277,-83,183,-172,35,-122,-79,138,-70,266,69,124,228,0,391,-29,594,-84,702,-78,627,-8,551,-13,509,13,372,120,352,125,622,127,691,223,362,126,386,-33,915,198,958,457,456,298,500,233,1027,469,1096,426,918,160,1067,141,1220,189,1245,164,1375,297,1378,503,1299,702,1550,929,1799,855,1752,547,1830,602,1928,832,1736,796,1735,933,1961,1385,1935,1562,2105,1485,2716,1449,2948,1305,2768,1205,2716,1346,2531,1450,2470,1653,3117,2111,3370,2176,2696,1947,2925,2305,3846,2658,2425,2184,-877,1981,-2261,2623,-1645,2908,-1876,2732,-2704,2953,-2484,3116,-2120,2954,-2442,3216,-2466,3499,-2192,3234,-2392,3361,-2497,3869,-2078,3772,-1858,3915,-2066,4438,-2285,2934,-2294,-280,-2066,-1762,-1992,-1412,-2298,-1535,-2399,-1789,-2223,-1419,-2244,-1334,-2092,-1476,-1777,-1396,-2014,-1571,-2199,-1574,-1843,-1167,-1910,-1446,-2007,-1818,-1506,-1331,-2526,-2048,-5535,-4573,-7148,-5828,-6422,-5327,-5840,-5488,-5992,-6144,-6014,-6164,-6109,-6234,-6271,-6388,-6288,-6156,-6517,-6249,-6794,-6602,-6822,-6418,-6788,-6245,-6490,-6560,-6394,-6794,-7920,-6937,-10397,-7140,-11428,-6972,-11019,-6610,-11141,-6665,-11913,-7046,-11979,-7235,-11599,-7015,-11854,-6912,-12161,-7441,-12136,-7761,-12861,-7292,-13390,-7254,-12345,-7809,-12490,-7463,-13983,-6969,-10489,-8465,-2382,-11054,1272,-12247,-270,-12060,-323,-12113,502,-12486,-697,-12251,-1086,-12141,-181,-13116,-670,-13509,-1173,-12592,-443,-12811,-449,-13698,-934,-12850,-747,-13083,-873,-15036,-1161,-11478,-1047,-2669,-1407,1006,-1658,-1146,-1195,-1297,-1421,-73,-1946,-977,-1590,-1499,-1577,-1010,-1862,-1256,-1389,-962,-1692,-509,-2613,-1317,-2087,-1359,-1997,-1034,-2891,-2024,-119,-84,5651,5723,8074,8306,7156,6870,6985,7106,7312,8403,7114,8096,7173,7848,7082,7827,6761,7189,6985,7368]}"#; + +use serde::Deserialize; + +#[derive(Deserialize)] +struct DeriveStruct { + buffer: Vec, +} + +fn main() { + let info: DeriveStruct = serde_json::from_str(JSON).unwrap(); + println!("{}", info.buffer.len()); +} From c54d7eef07f91d64665c1ed673ce5c535ce023d9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Jan 2019 19:41:18 +0100 Subject: [PATCH 0532/5092] expand docs --- src/range_map.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/range_map.rs b/src/range_map.rs index 48cbc57f0ebc..80fc98a86965 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -117,6 +117,7 @@ impl RangeMap { /// Provide mutable iteration over everything in the given range. As a side-effect, /// this will split entries in the map that are only partially hit by the given range, /// to make sure that when they are mutated, the effect is constrained to the given range. + /// Moreover, this will opportunistically merge neighbouring equal blocks. pub fn iter_mut<'a>( &'a mut self, offset: Size, From a13b6f183b519025fe181fd4d1230287d34b1f3e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Jan 2019 22:57:05 +0100 Subject: [PATCH 0533/5092] make MSE bench run a bit longer (less noise) --- bench-cargo-miri/mse/src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bench-cargo-miri/mse/src/main.rs b/bench-cargo-miri/mse/src/main.rs index 7d00a623468e..696de93442ed 100644 --- a/bench-cargo-miri/mse/src/main.rs +++ b/bench-cargo-miri/mse/src/main.rs @@ -2,7 +2,9 @@ static EXPECTED: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, static PCM: &[i16] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1, 0, 1, 0, 0, -2, 0, -2, 0, -2, 0, -2, -2, -2, -3, -3, -3, -3, -4, -2, -5, -2, -5, -2, -4, 0, -4, 0, -4, 0, -4, 1, -4, 1, -4, 2, -4, 2, -4, 2, -4, 2, -4, 2, -3, 1, -4, 0, -4, 0, -5, 0, -5, 0, -5, 0, -4, 2, -4, 3, -4, 4, -3, 5, -2, 5, -3, 6, -3, 6, -3, 5, -3, 5, -2, 4, -2, 3, -5, 0, -6, 0, -3, -2, -4, -4, -9, -5, -9, -4, -4, -2, -4, -2, -4, 0, -2, 1, 1, 1, 4, 2, 8, 2, 12, 1, 13, 0, 12, 0, 11, 0, 8, -2, 7, 0, 7, -3, 11, -8, 15, -9, 17, -6, 17, -5, 13, -3, 7, 0, 3, 0, -2, 0, -4, 0, -4, -2, -6, 0, -14, -2, -17, -4, -8, 0, -7, 5, -17, 7, -18, 10, -7, 18, -2, 25, -3, 27, 0, 31, 4, 34, 4, 34, 8, 36, 8, 37, 2, 36, 4, 34, 8, 28, 3, 15, 0, 11, 0, 12, -5, 8, -4, 10, 0, 23, -4, 31, -8, 30, -2, 30, 0, 26, -6, 22, -6, 20, -12, 15, -19, 10, -10, 13, -14, 6, -43, -13, -43, -16, -9, -12, -10, -29, -42, -40, -37, -28, -5, -21, 1, -24, -8, -20, 4, -18, 26, -24, 44, -26, 66, -30, 86, -37, 88, -41, 72, -46, 50, -31, 28, 23, 14, 64, 16, 51, 26, 32, 34, 39, 42, 48, 35, 58, 0, 72, -36, 69, -59, 58, -98, 54, -124, 36, -103, 12, -110, 5, -173, -19, -146, -59, -4, -42, 51, 1, -23, -6, -30, -6, 45, 46, 47, 70, 6, 55, 19, 60, 38, 62, 42, 47, 61, 46, 40, 42, -19, 22, -34, 6, -35, -50, -61, -141, -37, -171, 17, -163, 26, -180, 46, -154, 80, -63, 48, -4, 18, 20, 50, 47, 58, 53, 44, 61, 57, 85, 37, 80, 0, 86, -8, 106, -95, 49, -213, -8, -131, 47, 49, 63, 40, -39, -69, -74, -37, -20, 63, -12, 58, -14, -12, 25, -31, 41, 11, 45, 76, 47, 167, 5, 261, -37, 277, -83, 183, -172, 35, -122, -79, 138, -70, 266, 69, 124, 228, 0, 391, -29, 594, -84, 702, -78, 627, -8, 551, -13, 509, 13, 372, 120, 352, 125, 622, 127, 691, 223, 362, 126, 386, -33, 915, 198, 958, 457, 456, 298, 500, 233, 1027, 469, 1096, 426, 918, 160, 1067, 141, 1220, 189, 1245, 164, 1375, 297, 1378, 503, 1299, 702, 1550, 929, 1799, 855, 1752, 547, 1830, 602, 1928, 832, 1736, 796, 1735, 933, 1961, 1385, 1935, 1562, 2105, 1485, 2716, 1449, 2948, 1305, 2768, 1205, 2716, 1346, 2531, 1450, 2470, 1653, 3117, 2111, 3370, 2176, 2696, 1947, 2925, 2305, 3846, 2658, 2425, 2184, -877, 1981, -2261, 2623, -1645, 2908, -1876, 2732, -2704, 2953, -2484, 3116, -2120, 2954, -2442, 3216, -2466, 3499, -2192, 3234, -2392, 3361, -2497, 3869, -2078, 3772, -1858, 3915, -2066, 4438, -2285, 2934, -2294, -280, -2066, -1762, -1992, -1412, -2298, -1535, -2399, -1789, -2223, -1419, -2244, -1334, -2092, -1476, -1777, -1396, -2014, -1571, -2199, -1574, -1843, -1167, -1910, -1446, -2007, -1818]; fn main() { + for i in 0..5 { mse(PCM.len(), PCM, EXPECTED); + } } fn read_i16(buffer: &[u8], index: usize) -> i16 { From 9c1c407a02b6d465f3b583760657d355f75b2b94 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 21 Jan 2019 17:29:09 +0100 Subject: [PATCH 0534/5092] Update to latest rustc master --- benches/helpers/miri_helper.rs | 4 ++-- src/bin/miri-rustc-tests.rs | 4 ++-- src/bin/miri.rs | 5 +++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index c7df34eaf706..a34e137694cb 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -6,6 +6,7 @@ extern crate test; use self::miri::eval_main; use self::rustc_driver::{driver, Compilation}; +use rustc::hir::def_id::LOCAL_CRATE; use std::cell::RefCell; use std::rc::Rc; use crate::test::Bencher; @@ -44,10 +45,9 @@ pub fn run(filename: &str, bencher: &mut Bencher) { state.session.abort_if_errors(); let tcx = state.tcx.unwrap(); - let (entry_node_id, _, _) = state.session.entry_fn.borrow().expect( + let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect( "no main or start function found", ); - let entry_def_id = tcx.hir().local_def_id(entry_node_id); bencher.borrow_mut().iter(|| { eval_main(tcx, entry_def_id, false); diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 92d4237146dc..45902dc6722f 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -23,6 +23,7 @@ use rustc::hir::{self, itemlikevisit}; use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc::ty::TyCtxt; use syntax::ast; +use rustc::hir::def_id::LOCAL_CRATE; struct MiriCompilerCalls { default: Box, @@ -104,8 +105,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {} } state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(tcx, state)); - } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { - let entry_def_id = tcx.hir().local_def_id(entry_node_id); + } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { miri::eval_main(tcx, entry_def_id, /*validate*/true); state.session.abort_if_errors(); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index d8d7cfe0702e..acfc429ed805 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -24,6 +24,7 @@ use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls}; use rustc_driver::driver::{CompileState, CompileController}; use rustc::session::config::{self, Input, ErrorOutputType}; use rustc_codegen_utils::codegen_backend::CodegenBackend; +use rustc::hir::def_id::LOCAL_CRATE; use syntax::ast; struct MiriCompilerCalls { @@ -113,8 +114,8 @@ fn after_analysis<'a, 'tcx>( let tcx = state.tcx.unwrap(); - let (entry_node_id, _, _) = state.session.entry_fn.borrow().expect("no main function found!"); - let entry_def_id = tcx.hir().local_def_id(entry_node_id); + + let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!"); miri::eval_main(tcx, entry_def_id, validate); From 6943ba8a633d0437a3e60c3d4dcdc07ab218c18d Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 21 Jan 2019 17:43:11 +0100 Subject: [PATCH 0535/5092] Bump version file --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index a2909dd32898..a34ac2b25216 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-12-26 +nightly-2019-01-21 From 7269a884c91d539c6e6ec275a6d9ef6d6bd5f142 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 22 Jan 2019 16:46:05 +0100 Subject: [PATCH 0536/5092] Expose `AllocId`s for priroda --- src/mono_hash_map.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/mono_hash_map.rs b/src/mono_hash_map.rs index 278bbd9cf2b1..56d6e1400f3e 100644 --- a/src/mono_hash_map.rs +++ b/src/mono_hash_map.rs @@ -18,8 +18,11 @@ use crate::AllocMap; pub struct MonoHashMap(RefCell>>); impl MonoHashMap { - pub fn values(&self, f: impl FnOnce(&mut dyn Iterator) -> T) -> T { - f(&mut self.0.borrow().values().map(|v| &**v)) + /// This function exists for priroda to be able to iterate over all evaluator memory + /// + /// The memory of constants does not show up in this list. + pub fn iter(&self, f: impl FnOnce(&mut dyn Iterator) -> T) -> T { + f(&mut self.0.borrow().iter().map(|(k, v)| (k, &**v))) } } From 9f06cdc87a450b486a5bfea209acf958de92dfc8 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 22 Jan 2019 17:19:19 +0100 Subject: [PATCH 0537/5092] Explain Ref problems --- src/mono_hash_map.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/mono_hash_map.rs b/src/mono_hash_map.rs index 56d6e1400f3e..ec1a5fdb4288 100644 --- a/src/mono_hash_map.rs +++ b/src/mono_hash_map.rs @@ -20,7 +20,12 @@ pub struct MonoHashMap(RefCell>>); impl MonoHashMap { /// This function exists for priroda to be able to iterate over all evaluator memory /// - /// The memory of constants does not show up in this list. + /// The function is somewhat roundabout with the closure argument because internally the + /// `MonoHashMap` uses a `RefCell`. When iterating over the `HashMap` inside the `RefCell`, + /// we need to keep a borrow to the `HashMap` inside the iterator. The borrow is only alive + /// as long as the `Ref` returned by `RefCell::borrow()` is alive. So we can't return the + /// iterator, as that would drop the `Ref`. We can't return both, as it's not possible in Rust + /// to have a struct/tuple with a field that refers to another field. pub fn iter(&self, f: impl FnOnce(&mut dyn Iterator) -> T) -> T { f(&mut self.0.borrow().iter().map(|(k, v)| (k, &**v))) } From 76985f1e2d56fda022edee360b0deb5fdb7fb9f7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 25 Jan 2019 08:59:12 +0100 Subject: [PATCH 0538/5092] remove outdated comment --- src/fn_call.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 0f5429518239..720737b53965 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -73,10 +73,6 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let tcx = &{this.tcx.tcx}; - // All these functions take raw pointers, so if we access memory directly - // (as opposed to through a place), we have to remember to erase any tag - // that might still hang around! - match &link_name[..] { "malloc" => { let size = this.read_scalar(args[0])?.to_usize(this)?; From f7519f36e67b6a9547670d6635a754465ad3c09f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 28 Jan 2019 09:19:56 +0100 Subject: [PATCH 0539/5092] fix tests to avoid deprecated constants --- tests/run-pass/atomic-access-bool.rs | 5 ++--- tests/run-pass/atomic-compare_exchange.rs | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/run-pass/atomic-access-bool.rs b/tests/run-pass/atomic-access-bool.rs index ada584705401..8a3db796a087 100644 --- a/tests/run-pass/atomic-access-bool.rs +++ b/tests/run-pass/atomic-access-bool.rs @@ -8,10 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT}; -use std::sync::atomic::Ordering::*; +use std::sync::atomic::{AtomicBool, Ordering::*}; -static mut ATOMIC: AtomicBool = ATOMIC_BOOL_INIT; +static mut ATOMIC: AtomicBool = AtomicBool::new(false); fn main() { unsafe { diff --git a/tests/run-pass/atomic-compare_exchange.rs b/tests/run-pass/atomic-compare_exchange.rs index ec8e16d33e42..67280096073d 100644 --- a/tests/run-pass/atomic-compare_exchange.rs +++ b/tests/run-pass/atomic-compare_exchange.rs @@ -8,10 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::sync::atomic::{AtomicIsize, ATOMIC_ISIZE_INIT}; -use std::sync::atomic::Ordering::*; +use std::sync::atomic::{AtomicIsize, Ordering::*}; -static ATOMIC: AtomicIsize = ATOMIC_ISIZE_INIT; +static ATOMIC: AtomicIsize = AtomicIsize::new(0); fn main() { // Make sure trans can emit all the intrinsics correctly From ce8cf6425e85b58840686cd1556f4ea537fc2bca Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 28 Jan 2019 09:20:06 +0100 Subject: [PATCH 0540/5092] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index a34ac2b25216..452bb5c2b97f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2019-01-21 +nightly-2019-01-28 From 6b855573bd488cc11efb1f8cf1eeaf0f51327776 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 30 Jan 2019 11:51:06 +0100 Subject: [PATCH 0541/5092] fix generator test case --- tests/run-pass/generator.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/generator.rs b/tests/run-pass/generator.rs index 603093a037c7..c9c114aaccca 100644 --- a/tests/run-pass/generator.rs +++ b/tests/run-pass/generator.rs @@ -11,12 +11,15 @@ #![feature(generators, generator_trait)] use std::ops::{GeneratorState, Generator}; +use std::pin::Pin; fn finish(mut amt: usize, mut t: T) -> T::Return where T: Generator { + // We are not moving the `t` around until it gets dropped, so this is okay. + let mut t = unsafe { Pin::new_unchecked(&mut t) }; loop { - match unsafe { t.resume() } { + match t.as_mut().resume() { GeneratorState::Yielded(y) => amt -= y, GeneratorState::Complete(ret) => { assert_eq!(amt, 0); From e827f7b2383adddaced2a9af404455224d7be6c0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 30 Jan 2019 11:51:17 +0100 Subject: [PATCH 0542/5092] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 452bb5c2b97f..0c7f46922122 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2019-01-28 +nightly-2019-01-30 From 35809441cd9fba2797982906b657a16b63e5aa29 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 30 Jan 2019 13:21:43 +0100 Subject: [PATCH 0543/5092] Try out more email notifications --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 51b14a1b345b..ee58f73c3643 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,6 +32,9 @@ script: notifications: email: on_success: never + recipients: + - post+travis@ralfj.de + - travis-miri@oli-obk.de branches: only: - master From 7dbd23626e2df2b129a31bc341d029bbf4439a70 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 Feb 2019 15:03:11 +0100 Subject: [PATCH 0544/5092] update development instructions in README --- README.md | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index c6dd0d8b06c6..c7e7cb8c4a55 100644 --- a/README.md +++ b/README.md @@ -85,27 +85,45 @@ find useful. ### Using a nightly rustc -miri heavily relies on internal rustc interfaces to execute MIR. Still, some +Miri heavily relies on internal rustc interfaces to execute MIR. Still, some things (like adding support for a new intrinsic) can be done by working just on -the miri side. +the Miri side. -To prepare, make sure you are using a nightly Rust compiler. You also need to -set up a libstd that enables execution with Miri: +To prepare, make sure you are using a nightly Rust compiler. The most +convenient way is to install Miri using cargo, then you can easily run it on +other projects: ```sh -rustup override set nightly # or the nightly in `rust-version` -cargo run --bin cargo-miri -- miri setup +cargo +nightly install --path "$DIR" --force # or the nightly in `rust-version` +cargo +nightly miri setup ``` -The last command should end in printing the directory where the libstd was +If you want to use a different libstd (not the one that comes with the +nightly), you can do that by running + +```sh +XARGO_RUST_SRC=~/src/rust/rustc/src/ cargo +nightly miri setup +``` + +Either way, you can now do `cargo +nightly miri run` to run Miri with your +local changes on whatever project you are debugging. + +(We are giving `+nightly` explicitly here all the time because it is important +that all of these commands get executed with the same toolchain.) + +### Testing Miri + +Instead of running an entire project using `cargo miri`, you can also use the +Miri "driver" directly to run just a single file. That can be easier during +debugging. + +`cargo miri setup` should end in printing the directory where the libstd was built. Set that as your `MIRI_SYSROOT` environment variable: ```sh export MIRI_SYSROOT=~/.cache/miri/HOST # or whatever the previous command said ``` -### Testing Miri - Now you can run Miri directly, without going through `cargo miri`: ```sh From f3becd810eead697d31c5d73624d16996160efa6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 Feb 2019 21:35:15 +0100 Subject: [PATCH 0545/5092] explain how to run cargo miri with a locally compiled rustc --- README.md | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index c7e7cb8c4a55..46a46b3e7a80 100644 --- a/README.md +++ b/README.md @@ -111,20 +111,19 @@ local changes on whatever project you are debugging. (We are giving `+nightly` explicitly here all the time because it is important that all of these commands get executed with the same toolchain.) -### Testing Miri - -Instead of running an entire project using `cargo miri`, you can also use the -Miri "driver" directly to run just a single file. That can be easier during -debugging. - `cargo miri setup` should end in printing the directory where the libstd was -built. Set that as your `MIRI_SYSROOT` environment variable: +built. For the next step to work, set that as your `MIRI_SYSROOT` environment +variable: ```sh export MIRI_SYSROOT=~/.cache/miri/HOST # or whatever the previous command said ``` -Now you can run Miri directly, without going through `cargo miri`: +### Testing Miri + +Instead of running an entire project using `cargo miri`, you can also use the +Miri "driver" directly to run just a single file. That can be easier during +debugging. ```sh cargo run tests/run-pass/format.rs # or whatever test you like @@ -186,6 +185,15 @@ rustup override set custom With this, you should now have a working development setup! See ["Testing Miri"](#testing-miri) above for how to proceed. +Running `cargo miri` in this setup is a bit more complicated, because the Miri +binary you just created does not actually run without some enviroment variables. +But you can contort cargo into calling `cargo miri` the right way for you: + +```sh +# in some other project's directory, to run `cargo miri test`: +MIRI_SYSROOT=$(rustc +custom --print sysroot) cargo +custom run --manifest-path /path/to/miri/Cargo.toml --bin cargo-miri --release -- miri test +``` + ### Miri `-Z` flags and environment variables Several `-Z` flags are relevant for Miri: From 661ed7b82dc7b9ab597a274f10055f58f9db6f4b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Feb 2019 11:38:40 +0100 Subject: [PATCH 0546/5092] implement atomic_nand --- src/intrinsic.rs | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 0ef847236418..b7c5d8d07c25 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -108,6 +108,11 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "atomic_and_rel" | "atomic_and_acqrel" | "atomic_and_relaxed" | + "atomic_nand" | + "atomic_nand_acq" | + "atomic_nand_rel" | + "atomic_nand_acqrel" | + "atomic_nand_relaxed" | "atomic_xadd" | "atomic_xadd_acq" | "atomic_xadd_rel" | @@ -125,16 +130,23 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let rhs = this.read_immediate(args[1])?; let old = this.read_immediate(ptr.into())?; this.write_immediate(*old, dest)?; // old value is returned - let op = match intrinsic_name.split('_').nth(1).unwrap() { - "or" => mir::BinOp::BitOr, - "xor" => mir::BinOp::BitXor, - "and" => mir::BinOp::BitAnd, - "xadd" => mir::BinOp::Add, - "xsub" => mir::BinOp::Sub, + let (op, neg) = match intrinsic_name.split('_').nth(1).unwrap() { + "or" => (mir::BinOp::BitOr, false), + "xor" => (mir::BinOp::BitXor, false), + "and" => (mir::BinOp::BitAnd, false), + "xadd" => (mir::BinOp::Add, false), + "xsub" => (mir::BinOp::Sub, false), + "nand" => (mir::BinOp::BitAnd, true), _ => bug!(), }; // Atomics wrap around on overflow. - this.binop_ignore_overflow(op, old, rhs, ptr.into())?; + let (val, _overflowed) = this.binary_op_imm(op, old, rhs)?; + let val = if neg { + this.unary_op(mir::UnOp::Not, val, old.layout)? + } else { + val + }; + this.write_scalar(val, ptr.into())?; } "breakpoint" => unimplemented!(), // halt miri From 48ac35f0727e1c660fa95012a941cf65de8b9443 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Feb 2019 11:39:16 +0100 Subject: [PATCH 0547/5092] panic_impl is another way to panic --- src/fn_call.rs | 30 +++++++++++++--------- tests/compile-fail/{panic.rs => panic1.rs} | 2 +- tests/compile-fail/panic2.rs | 5 ++++ tests/compile-fail/panic3.rs | 5 ++++ tests/compile-fail/panic4.rs | 5 ++++ 5 files changed, 34 insertions(+), 13 deletions(-) rename tests/compile-fail/{panic.rs => panic1.rs} (60%) create mode 100644 tests/compile-fail/panic2.rs create mode 100644 tests/compile-fail/panic3.rs create mode 100644 tests/compile-fail/panic4.rs diff --git a/src/fn_call.rs b/src/fn_call.rs index 720737b53965..abb239ad7d62 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -39,12 +39,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, if this.tcx.is_foreign_item(instance.def_id()) { // An external function that we cannot find MIR for, but we can still run enough // of them to make miri viable. - this.emulate_foreign_item( - instance.def_id(), - args, - dest.unwrap(), - ret.unwrap(), - )?; + this.emulate_foreign_item(instance.def_id(), args, dest, ret)?; // `goto_block` already handled return Ok(None); } @@ -59,8 +54,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, &mut self, def_id: DefId, args: &[OpTy<'tcx, Borrow>], - dest: PlaceTy<'tcx, Borrow>, - ret: mir::BasicBlock, + dest: Option>, + ret: Option, ) -> EvalResult<'tcx> { let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); @@ -70,9 +65,23 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, }; // Strip linker suffixes (seen on 32bit macOS) let link_name = link_name.trim_end_matches("$UNIX2003"); - let tcx = &{this.tcx.tcx}; + // first: functions that could diverge + match &link_name[..] { + "__rust_start_panic" | "panic_impl" => { + return err!(MachineError("the evaluated program panicked".to_string())); + } + _ => if dest.is_none() { + return err!(Unimplemented( + format!("can't call diverging foreign function: {}", link_name), + )); + } + } + + // now: functions that assume a ret and dest + let dest = dest.expect("we already checked for a dest"); + let ret = ret.expect("dest is Some but ret is None"); match &link_name[..] { "malloc" => { let size = this.read_scalar(args[0])?.to_usize(this)?; @@ -245,9 +254,6 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, return Ok(()); } - "__rust_start_panic" => - return err!(MachineError("the evaluated program panicked".to_string())), - "memcmp" => { let left = this.read_scalar(args[0])?.not_undef()?; let right = this.read_scalar(args[1])?.not_undef()?; diff --git a/tests/compile-fail/panic.rs b/tests/compile-fail/panic1.rs similarity index 60% rename from tests/compile-fail/panic.rs rename to tests/compile-fail/panic1.rs index 0d594f9bd4c3..1163c8708287 100644 --- a/tests/compile-fail/panic.rs +++ b/tests/compile-fail/panic1.rs @@ -1,5 +1,5 @@ //error-pattern: the evaluated program panicked fn main() { - assert_eq!(5, 6); + std::panic!("panicking from libstd"); } diff --git a/tests/compile-fail/panic2.rs b/tests/compile-fail/panic2.rs new file mode 100644 index 000000000000..e643e6922413 --- /dev/null +++ b/tests/compile-fail/panic2.rs @@ -0,0 +1,5 @@ +//error-pattern: the evaluated program panicked + +fn main() { + std::panic!("{}-panicking from libstd", 42); +} diff --git a/tests/compile-fail/panic3.rs b/tests/compile-fail/panic3.rs new file mode 100644 index 000000000000..b22f95d9c69d --- /dev/null +++ b/tests/compile-fail/panic3.rs @@ -0,0 +1,5 @@ +//error-pattern: the evaluated program panicked + +fn main() { + core::panic!("panicking from libcore"); +} diff --git a/tests/compile-fail/panic4.rs b/tests/compile-fail/panic4.rs new file mode 100644 index 000000000000..449e716e161c --- /dev/null +++ b/tests/compile-fail/panic4.rs @@ -0,0 +1,5 @@ +//error-pattern: the evaluated program panicked + +fn main() { + core::panic!("{}-panicking from libcore", 42); +} From e5972c38a3322e8ab98aead64d75f63fe4c7c75d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Feb 2019 11:47:32 +0100 Subject: [PATCH 0548/5092] test mutable string slice indexing --- tests/run-pass/strings.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/run-pass/strings.rs b/tests/run-pass/strings.rs index d5fc80b41f01..fa692ba3de1b 100644 --- a/tests/run-pass/strings.rs +++ b/tests/run-pass/strings.rs @@ -18,10 +18,17 @@ fn fat_pointer_on_32_bit() { Some(5).expect("foo"); } +fn str_indexing() { + let mut x = "Hello".to_string(); + let _v = &mut x[..3]; // Test IndexMut on String. +} + fn main() { assert_eq!(empty(), ""); assert_eq!(hello(), "Hello, world!"); assert_eq!(hello_bytes(), b"Hello, world!"); assert_eq!(hello_bytes_fat(), b"Hello, world!"); + fat_pointer_on_32_bit(); // Should run without crashing. + str_indexing(); } From e36a90de98b77bc3dccaa2910206ab15581c1755 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Feb 2019 12:59:35 +0100 Subject: [PATCH 0549/5092] make release builds have debug info --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 5e78661c2196..16b5b2361bd4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,3 +55,6 @@ rustc_tests = [] [dev-dependencies] compiletest_rs = { version = "0.3.17", features = ["tmp"] } colored = "1.6" + +[profile.release] +debug = true From 4309539efe85b03ae34076372327ae80c9b81552 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Feb 2019 13:00:27 +0100 Subject: [PATCH 0550/5092] cargo miri: refactor how we detect what to interpret and how we run cargo rustc, fix running unit tests --- src/bin/cargo-miri.rs | 346 +++++++++++++++++++++--------------------- src/lib.rs | 2 +- 2 files changed, 177 insertions(+), 171 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 21cc7ee0e398..b952aeea2f7f 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -7,10 +7,10 @@ use std::io::{self, Write, BufRead}; use std::process::Command; use std::fs::{self, File}; -const CARGO_MIRI_HELP: &str = r#"Interprets bin crates +const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and runs test suites Usage: - cargo miri [subcommand] [options] [--] [...] + cargo miri [subcommand] [options] [--] [...] Subcommands: run Run binaries (default) @@ -22,12 +22,13 @@ Common options: --features Features to compile for the package -V, --version Print version info and exit -Other options are the same as `cargo rustc`. +Other [options] are the same as `cargo rustc`. Everything after the "--" is +passed verbatim to Miri. -The feature `cargo-miri` is automatically defined for convenience. You can use +The config flag `miri` is automatically defined for convenience. You can use it to configure the resource limits - #![cfg_attr(feature = "cargo-miri", memory_size = 42)] + #![cfg_attr(miri, memory_size = 42)] available resource limits are `memory_size`, `step_limit`, `stack_limit` "#; @@ -53,23 +54,32 @@ fn show_error(msg: String) -> ! { std::process::exit(1) } +// Determines whether a --flag is present +fn has_arg_flag(name: &str) -> bool { + let mut args = std::env::args().take_while(|val| val != "--"); + args.any(|val| val == name) +} + +/// Gets the value of a --flag fn get_arg_flag_value(name: &str) -> Option { // stop searching at `--` - let mut args = std::env::args().skip_while(|val| !(val.starts_with(name) || val == "--")); - - match args.next() { - Some(ref p) if p == "--" => None, - Some(ref p) if p == name => args.next(), - Some(p) => { - // Make sure this really starts with `$name=`, we didn't test for the `=` yet. - let v = &p[name.len()..]; // strip leading `$name` - if v.starts_with('=') { - Some(v[1..].to_owned()) // strip leading `=` - } else { - None - } - }, - None => None, + let mut args = std::env::args().take_while(|val| val != "--"); + loop { + let arg = match args.next() { + Some(arg) => arg, + None => return None, + }; + if !arg.starts_with(name) { + continue; + } + let suffix = &arg[name.len()..]; // strip leading `name` + if suffix.is_empty() { + // This argument is exactly `name`, the next one is the value + return args.next(); + } else if suffix.starts_with('=') { + // This argument is `name=value`, get the value + return Some(suffix[1..].to_owned()); // strip leading `=` + } } } @@ -272,167 +282,163 @@ fn main() { // each applicable target, but with the RUSTC env var set to the `cargo-miri` // binary so that we come back in the other branch, and dispatch // the invocations to rustc and miri, respectively. - - let (subcommand, skip) = match std::env::args().nth(2).deref() { - Some("test") => (MiriCommand::Test, 3), - Some("run") => (MiriCommand::Run, 3), - Some("setup") => (MiriCommand::Setup, 3), - // Default command, if there is an option or nothing - Some(s) if s.starts_with("-") => (MiriCommand::Run, 2), - None => (MiriCommand::Run, 2), - // Unvalid command - Some(s) => { - show_error(format!("Unknown command `{}`", s)) - } - }; - - // We always setup - let ask = subcommand != MiriCommand::Setup; - setup(ask); - if subcommand == MiriCommand::Setup { - // Stop here. - return; - } - - // Now run the command. - for target in list_targets() { - let args = std::env::args().skip(skip); - let kind = target.kind.get(0).expect( - "badly formatted cargo metadata: target::kind is an empty array", - ); - match (subcommand, &kind[..]) { - (MiriCommand::Test, "test") => { - // For test binaries we call `cargo rustc --test target -- ` - if let Err(code) = process( - vec!["--test".to_string(), target.name].into_iter().chain( - args, - ), - ) - { - std::process::exit(code); - } - } - (MiriCommand::Test, "lib") => { - // For libraries we call `cargo rustc -- --test ` - // Notice now that `--test` is a rustc arg rather than a cargo arg. This tells - // rustc to build a test harness which calls all #[test] functions. - // We then execute that harness just like any other binary. - if let Err(code) = process( - vec!["--".to_string(), "--test".to_string()].into_iter().chain( - args, - ), - ) - { - std::process::exit(code); - } - } - (MiriCommand::Run, "bin") => { - // For ordinary binaries we call `cargo rustc --bin target -- ` - if let Err(code) = process( - vec!["--bin".to_string(), target.name].into_iter().chain( - args, - ), - ) - { - std::process::exit(code); - } - } - _ => {} - } - } + in_cargo_miri(); } else if let Some("rustc") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { // This arm is executed when cargo-miri runs `cargo rustc` with the `RUSTC_WRAPPER` env var set to itself: // Dependencies get dispatched to rustc, the final test/binary to miri. - - let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); - let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); - let sys_root = if let Ok(sysroot) = ::std::env::var("MIRI_SYSROOT") { - sysroot - } else if let (Some(home), Some(toolchain)) = (home, toolchain) { - format!("{}/toolchains/{}", home, toolchain) - } else { - option_env!("RUST_SYSROOT") - .map(|s| s.to_owned()) - .or_else(|| { - Command::new("rustc") - .arg("--print") - .arg("sysroot") - .output() - .ok() - .and_then(|out| String::from_utf8(out.stdout).ok()) - .map(|s| s.trim().to_owned()) - }) - .expect("need to specify RUST_SYSROOT env var during miri compilation, or use rustup or multirust") - }; - - // this conditional check for the --sysroot flag is there so users can call `cargo-miri` directly - // without having to pass --sysroot or anything - let rustc_args = std::env::args().skip(2); - let mut args: Vec = if std::env::args().any(|s| s == "--sysroot") { - rustc_args.collect() - } else { - rustc_args - .chain(Some("--sysroot".to_owned())) - .chain(Some(sys_root)) - .collect() - }; - args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string)); - args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-miri""#.to_owned()]); - - // this check ensures that dependencies are built but not interpreted and the final crate is - // interpreted but not built - let miri_enabled = std::env::args().any(|s| s == "--emit=dep-info,metadata"); - let mut command = if miri_enabled { - let mut path = std::env::current_exe().expect("current executable path invalid"); - path.set_file_name("miri"); - Command::new(path) - } else { - Command::new("rustc") - }; - command.args(&args); - - match command.status() { - Ok(exit) => { - if !exit.success() { - std::process::exit(exit.code().unwrap_or(42)); - } - } - Err(ref e) if miri_enabled => panic!("error during miri run: {:?}", e), - Err(ref e) => panic!("error during rustc call: {:?}", e), - } + inside_cargo_rustc(); } else { show_error(format!("Must be called with either `miri` or `rustc` as first argument.")) } } -fn process(old_args: I) -> Result<(), i32> -where - I: Iterator, -{ - let mut args = vec!["rustc".to_owned()]; +fn in_cargo_miri() { + let (subcommand, skip) = match std::env::args().nth(2).deref() { + Some("test") => (MiriCommand::Test, 3), + Some("run") => (MiriCommand::Run, 3), + Some("setup") => (MiriCommand::Setup, 3), + // Default command, if there is an option or nothing + Some(s) if s.starts_with("-") => (MiriCommand::Run, 2), + None => (MiriCommand::Run, 2), + // Unvalid command + Some(s) => { + show_error(format!("Unknown command `{}`", s)) + } + }; + let verbose = has_arg_flag("-v"); - let mut found_dashes = false; - for arg in old_args { - found_dashes |= arg == "--"; - args.push(arg); + // We always setup + let ask = subcommand != MiriCommand::Setup; + setup(ask); + if subcommand == MiriCommand::Setup { + // Stop here. + return; } - if !found_dashes { - args.push("--".to_owned()); - } - args.push("--emit=dep-info,metadata".to_owned()); - let path = std::env::current_exe().expect("current executable path invalid"); - let exit_status = Command::new("cargo") - .args(&args) - .env("RUSTC_WRAPPER", path) - .spawn() - .expect("could not run cargo") - .wait() - .expect("failed to wait for cargo?"); + // Now run the command. + for target in list_targets() { + let mut args = std::env::args().skip(skip); + let kind = target.kind.get(0).expect( + "badly formatted cargo metadata: target::kind is an empty array", + ); + // Now we run `cargo rustc $FLAGS $ARGS`, giving the user the + // change to add additional flags. "FLAGS" is set to identify + // this target. The user gets to control what gets actually passed to Miri. + // However, we need to add a flag to what gets passed to rustc for the finaly + // binary, so that we know to interpret that with Miri. + // So after the first "--", we add "-Zcargo-miri-marker". + let mut cmd = Command::new("cargo"); + cmd.arg("rustc"); + match (subcommand, &kind[..]) { + (MiriCommand::Run, "bin") => { + // FIXME: We just run all the binaries here. + // We should instead support `cargo miri --bin foo`. + cmd.arg("--bin").arg(target.name); + } + (MiriCommand::Test, "test") => { + cmd.arg("--test").arg(target.name); + } + (MiriCommand::Test, "lib") | + (MiriCommand::Test, "bin") => { + cmd.arg(format!("--{}", kind)).arg(target.name).arg("--profile").arg("test"); + } + // The remaining targets we do not even want to build + _ => continue, + } + // add user-defined args until first "--" + while let Some(arg) = args.next() { + if arg == "--" { + break; + } + cmd.arg(arg); + } + // add "--" "-Zcargo-miri-marker" and the remaining user flags + cmd + .arg("--") + .arg("cargo-miri-marker") + .args(args); + let path = std::env::current_exe().expect("current executable path invalid"); + cmd.env("RUSTC_WRAPPER", path); + if verbose { + eprintln!("+ {:?}", cmd); + } - if exit_status.success() { - Ok(()) - } else { - Err(exit_status.code().unwrap_or(-1)) + let exit_status = cmd + .spawn() + .expect("could not run cargo") + .wait() + .expect("failed to wait for cargo?"); + + if !exit_status.success() { + std::process::exit(exit_status.code().unwrap_or(-1)) + } + } +} + +fn inside_cargo_rustc() { + let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); + let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); + let sys_root = if let Ok(sysroot) = ::std::env::var("MIRI_SYSROOT") { + sysroot + } else if let (Some(home), Some(toolchain)) = (home, toolchain) { + format!("{}/toolchains/{}", home, toolchain) + } else { + option_env!("RUST_SYSROOT") + .map(|s| s.to_owned()) + .or_else(|| { + Command::new("rustc") + .arg("--print") + .arg("sysroot") + .output() + .ok() + .and_then(|out| String::from_utf8(out.stdout).ok()) + .map(|s| s.trim().to_owned()) + }) + .expect("need to specify RUST_SYSROOT env var during miri compilation, or use rustup or multirust") + }; + + // this conditional check for the --sysroot flag is there so users can call `cargo-miri` directly + // without having to pass --sysroot or anything + let rustc_args = std::env::args().skip(2); + let mut args: Vec = if std::env::args().any(|s| s == "--sysroot") { + rustc_args.collect() + } else { + rustc_args + .chain(Some("--sysroot".to_owned())) + .chain(Some(sys_root)) + .collect() + }; + args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string)); + + // see if we have cargo-miri-marker, which means we want to interpret this crate in Miri + // (and remove the marker). + let needs_miri = if let Some(pos) = args.iter().position(|arg| arg == "cargo-miri-marker") { + args.remove(pos); + true + } else { + false + }; + + + let mut command = if needs_miri { + let mut path = std::env::current_exe().expect("current executable path invalid"); + path.set_file_name("miri"); + Command::new(path) + } else { + Command::new("rustc") + }; + command.args(&args); + if has_arg_flag("-v") { + eprintln!("+ {:?}", command); + } + + match command.status() { + Ok(exit) => { + if !exit.success() { + std::process::exit(exit.code().unwrap_or(42)); + } + } + Err(ref e) if needs_miri => panic!("error during miri run: {:?}", e), + Err(ref e) => panic!("error during rustc call: {:?}", e), } } diff --git a/src/lib.rs b/src/lib.rs index a8fd432282a1..4ff3e011c6ae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -54,7 +54,7 @@ pub use crate::stacked_borrows::{Borrow, Stack, Stacks, BorStackItem}; pub fn miri_default_args() -> &'static [&'static str] { // The flags here should be kept in sync with what bootstrap adds when `test-miri` is // set, which happens in `bootstrap/bin/rustc.rs` in the rustc sources. - &["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0"] + &["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0", "--cfg=miri"] } // Used by priroda From 5766b328713410dc0bc8e2d349b569937fb79e50 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Feb 2019 13:00:42 +0100 Subject: [PATCH 0551/5092] update test for cargo-miri --- src/bin/cargo-miri.rs | 2 +- test-cargo-miri/Cargo.lock | 197 ++++++++++++++++++++++ test-cargo-miri/Cargo.toml | 3 + test-cargo-miri/src/main.rs | 18 ++ test-cargo-miri/test.stdout.ref | 10 +- test-cargo-miri/tests/{foo.rs => test.rs} | 15 +- 6 files changed, 238 insertions(+), 7 deletions(-) rename test-cargo-miri/tests/{foo.rs => test.rs} (56%) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index b952aeea2f7f..677c38d7c295 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -7,7 +7,7 @@ use std::io::{self, Write, BufRead}; use std::process::Command; use std::fs::{self, File}; -const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and runs test suites +const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and tests in Miri Usage: cargo miri [subcommand] [options] [--] [...] diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 85c3c08dba01..76fb04c6672a 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -1,3 +1,15 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "autocfg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bitflags" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "byteorder" version = "1.0.0" @@ -8,7 +20,192 @@ name = "cargo-miri-test" version = "0.1.0" dependencies = [ "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.48" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_jitter 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_jitter" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_os" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_pcg" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [metadata] +"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" +"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c40977b0ee6b9885c9013cd41d9feffdd22deb3bb4dc3a71d901cc7a77de18c8" +"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +"checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047" +"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" +"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +"checksum rand_jitter 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "080723c6145e37503a2224f801f252e14ac5531cb450f4502698542d188cb3c0" +"checksum rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b7c690732391ae0abafced5015ffb53656abfaec61b342290e5eb56b286a679d" +"checksum rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05" +"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 4fe009e025e1..04f259a0aedb 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -6,3 +6,6 @@ edition = "2018" [dependencies] byteorder = "1.0" + +[dev-dependencies] +rand = "0.6.5" diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index 1ae88a7db594..25e2cfdfa036 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -1,3 +1,7 @@ +extern crate byteorder; +#[cfg(test)] +extern crate rand; + use byteorder::{BigEndian, ByteOrder}; fn main() { @@ -7,3 +11,17 @@ fn main() { println!("{:#010x}", n); eprintln!("standard error"); } + +#[cfg(test)] +mod test { + use rand::{Rng, SeedableRng}; + + // Make sure in-crate tests with dev-dependencies work + #[test] + fn rng() { + let mut rng = rand::rngs::StdRng::seed_from_u64(0xcafebeef); + let x: u32 = rng.gen(); + let y: u32 = rng.gen(); + assert_ne!(x, y); + } +} diff --git a/test-cargo-miri/test.stdout.ref b/test-cargo-miri/test.stdout.ref index 94fd56b0cd6f..9c3621f21535 100644 --- a/test-cargo-miri/test.stdout.ref +++ b/test-cargo-miri/test.stdout.ref @@ -1,7 +1,13 @@ +running 1 test +test test::rng ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out + + running 2 tests -test bar ... ok -test baz ... ok +test rng ... ok +test simple ... ok test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/tests/foo.rs b/test-cargo-miri/tests/test.rs similarity index 56% rename from test-cargo-miri/tests/foo.rs rename to test-cargo-miri/tests/test.rs index bd7b2c569a19..e9faaf2fb2f1 100644 --- a/test-cargo-miri/tests/foo.rs +++ b/test-cargo-miri/tests/test.rs @@ -1,17 +1,24 @@ +extern crate rand; + +use rand::{Rng, SeedableRng}; + #[test] -fn bar() { +fn simple() { assert_eq!(4, 4); } // Having more than 1 test does seem to make a difference // (i.e., this calls ptr::swap which having just one test does not). #[test] -fn baz() { - assert_eq!(5, 5); +fn rng() { + let mut rng = rand::rngs::StdRng::seed_from_u64(0xdeadcafe); + let x: u32 = rng.gen(); + let y: u32 = rng.gen(); + assert_ne!(x, y); } // A test that won't work on miri -#[cfg(not(feature = "cargo-miri"))] +#[cfg(not(miri))] #[test] fn does_not_work_on_miri() { let x = 0u8; From 08180f07baca0ea1fdc7672eca7dfdee9f860851 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Feb 2019 13:07:47 +0100 Subject: [PATCH 0552/5092] update docs --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 46a46b3e7a80..1d97b61f43d5 100644 --- a/README.md +++ b/README.md @@ -48,12 +48,12 @@ Now you can run your project in Miri: 3. If you have a binary project, you can run it through Miri using `cargo +nightly miri run`. -When running code via `cargo miri`, the `cargo-miri` feature is set. You can +When running code via `cargo miri`, the `miri` config flag is set. You can use this to exclude test cases that will fail under Miri because they do things Miri does not support: ```rust -#[cfg(not(feature = "cargo-miri"))] +#[cfg(not(miri))] #[test] fn does_not_work_on_miri() { let x = 0u8; From e0891bd619deaa7a7d91766710703f9fa631c059 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Feb 2019 16:33:46 +0100 Subject: [PATCH 0553/5092] Fix cargo miri test on lib crates --- src/bin/cargo-miri.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 677c38d7c295..9b97822b4754 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -338,9 +338,12 @@ fn in_cargo_miri() { (MiriCommand::Test, "test") => { cmd.arg("--test").arg(target.name); } - (MiriCommand::Test, "lib") | + (MiriCommand::Test, "lib") => { + // There can be only one lib + cmd.arg("--lib").arg("--profile").arg("test"); + } (MiriCommand::Test, "bin") => { - cmd.arg(format!("--{}", kind)).arg(target.name).arg("--profile").arg("test"); + cmd.arg("--bin").arg(target.name).arg("--profile").arg("test"); } // The remaining targets we do not even want to build _ => continue, From 68e8ff1a097fa561a19eeb5d1f0328b8ef20cef4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Feb 2019 18:04:54 +0100 Subject: [PATCH 0554/5092] flush stdout/stderr to make sure it appears on the screen --- src/fn_call.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index abb239ad7d62..56cb38645090 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -390,10 +390,15 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, use std::io::{self, Write}; let buf_cont = this.memory().read_bytes(buf, Size::from_bytes(n))?; + // We need to flush to make sure this actually appears on the screen let res = if fd == 1 { - io::stdout().write(buf_cont) + let res = io::stdout().write(buf_cont); + io::stdout().flush().unwrap(); + res } else { - io::stderr().write(buf_cont) + let res = io::stderr().write(buf_cont); + io::stderr().flush().unwrap(); + res }; match res { Ok(n) => n as i64, From 7af75abdd79c4c72f7eea5d136b95dc882c705f1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Feb 2019 10:28:43 +0100 Subject: [PATCH 0555/5092] we don't need to flush stderr --- src/fn_call.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 56cb38645090..a5708305a976 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -392,13 +392,16 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let buf_cont = this.memory().read_bytes(buf, Size::from_bytes(n))?; // We need to flush to make sure this actually appears on the screen let res = if fd == 1 { + // Stdout is buffered, flush to make sure it appears on the screen. + // This is the write() syscall of the interpreted program, we want it + // to correspond to a write() syscall on the host -- there is no good + // in adding extra buffering here. let res = io::stdout().write(buf_cont); io::stdout().flush().unwrap(); res } else { - let res = io::stderr().write(buf_cont); - io::stderr().flush().unwrap(); - res + // No need to flush, stderr is not buffered. + io::stderr().write(buf_cont) }; match res { Ok(n) => n as i64, From e747c65f8dbb898f4fad2e500cd2fe01d87fac1c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Feb 2019 12:13:07 +0100 Subject: [PATCH 0556/5092] make bash more strict --- travis.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/travis.sh b/travis.sh index aded53b1579d..8ec1d56ab770 100755 --- a/travis.sh +++ b/travis.sh @@ -1,5 +1,5 @@ #!/bin/bash -set -e +set -euo pipefail # Determine configuration if [ "$TRAVIS_OS_NAME" == osx ]; then From 0f6e82db361b58d8332a1f793232cbe396d526c5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Feb 2019 13:07:55 +0100 Subject: [PATCH 0557/5092] fix (un)likely intrinsics --- src/intrinsic.rs | 8 +++++++- tests/run-pass/iter.rs | 40 ++++++++++++++++++++++++++++++++++++ tests/run-pass/iter_any.rs | 12 ----------- tests/run-pass/iter_slice.rs | 12 ----------- 4 files changed, 47 insertions(+), 25 deletions(-) create mode 100644 tests/run-pass/iter.rs delete mode 100644 tests/run-pass/iter_any.rs delete mode 100644 tests/run-pass/iter_slice.rs diff --git a/src/intrinsic.rs b/src/intrinsic.rs index b7c5d8d07c25..09df91b3ab38 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -245,7 +245,13 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; }, - "likely" | "unlikely" | "forget" => {} + "forget" => {} + + "likely" | "unlikely" => { + // These just return their argument + let b = this.read_immediate(args[0])?; + this.write_immediate(*b, dest)?; + } "init" => { // Check fast path: we don't want to force an allocation in case the destination is a simple value, diff --git a/tests/run-pass/iter.rs b/tests/run-pass/iter.rs new file mode 100644 index 000000000000..1bef21d83bda --- /dev/null +++ b/tests/run-pass/iter.rs @@ -0,0 +1,40 @@ +fn iter_empty_and_zst() { + for _ in Vec::::new().iter() { // this iterates over a Unique::empty() + panic!("We should never be here."); + } + + // Iterate over a ZST (uses arith_offset internally) + let mut count = 0; + for _ in &[(), (), ()] { + count += 1; + } + assert_eq!(count, 3); +} + +fn test_iterator_step_by_nth() { + let mut it = (0..16).step_by(5); + assert_eq!(it.nth(0), Some(0)); + assert_eq!(it.nth(0), Some(5)); + assert_eq!(it.nth(0), Some(10)); + assert_eq!(it.nth(0), Some(15)); + assert_eq!(it.nth(0), None); +} + +fn iter_any() { + let f = |x: &u8| { 10u8 == *x }; + f(&1u8); + + let g = |(), x: &u8| { 10u8 == *x }; + g((), &1u8); + + let h = |(), (), x: &u8| { 10u8 == *x }; + h((), (), &1u8); + + [1, 2, 3u8].into_iter().any(|elt| 10 == *elt); +} + +fn main() { + test_iterator_step_by_nth(); + iter_any(); + iter_empty_and_zst(); +} diff --git a/tests/run-pass/iter_any.rs b/tests/run-pass/iter_any.rs deleted file mode 100644 index b14eb074488b..000000000000 --- a/tests/run-pass/iter_any.rs +++ /dev/null @@ -1,12 +0,0 @@ -pub fn main() { - let f = |x: &u8| { 10u8 == *x }; - f(&1u8); - - let g = |(), x: &u8| { 10u8 == *x }; - g((), &1u8); - - let h = |(), (), x: &u8| { 10u8 == *x }; - h((), (), &1u8); - - [1, 2, 3u8].into_iter().any(|elt| 10 == *elt); -} diff --git a/tests/run-pass/iter_slice.rs b/tests/run-pass/iter_slice.rs deleted file mode 100644 index fd7229c3455e..000000000000 --- a/tests/run-pass/iter_slice.rs +++ /dev/null @@ -1,12 +0,0 @@ -fn main() { - for _ in Vec::::new().iter() { // this iterates over a Unique::empty() - panic!("We should never be here."); - } - - // Iterate over a ZST (uses arith_offset internally) - let mut count = 0; - for _ in &[(), (), ()] { - count += 1; - } - assert_eq!(count, 3); -} From 7827924bfc920bc171f3c68e25dc47065f5ae6e4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Feb 2019 15:52:59 +0100 Subject: [PATCH 0558/5092] test padding in format strings --- tests/run-pass/format.rs | 1 + tests/run-pass/format.stdout | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/run-pass/format.rs b/tests/run-pass/format.rs index 78729b915613..053cce36130c 100644 --- a/tests/run-pass/format.rs +++ b/tests/run-pass/format.rs @@ -1,3 +1,4 @@ fn main() { println!("Hello {}", 13); + println!("{:0 Date: Fri, 8 Feb 2019 19:21:44 +0100 Subject: [PATCH 0559/5092] implement passing arguments to the interpreted program --- src/bin/miri.rs | 67 ++++++++++++++++++++++++------------- src/lib.rs | 46 +++++++++++++++++-------- test-cargo-miri/src/main.rs | 4 ++- test-cargo-miri/stderr.ref | 2 +- tests/run-pass/args.rs | 5 +++ tests/run-pass/args.stdout | 1 + 6 files changed, 85 insertions(+), 40 deletions(-) create mode 100644 tests/run-pass/args.rs create mode 100644 tests/run-pass/args.stdout diff --git a/src/bin/miri.rs b/src/bin/miri.rs index acfc429ed805..31bd1deb10f5 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -27,11 +27,11 @@ use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc::hir::def_id::LOCAL_CRATE; use syntax::ast; +use miri::MiriConfig; + struct MiriCompilerCalls { default: Box, - - /// Whether to enforce the validity invariant. - validate: bool, + miri_config: MiriConfig, } impl<'a> CompilerCalls<'a> for MiriCompilerCalls { @@ -79,6 +79,8 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { odir: &Option, ofile: &Option, ) -> Compilation { + // Called *before* build_controller. Add filename to miri arguments. + self.miri_config.args.insert(0, input.filestem().to_string()); self.default.late_callback(codegen_backend, matches, sess, cstore, input, odir, ofile) } fn build_controller( @@ -89,9 +91,9 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { let this = *self; let mut control = this.default.build_controller(sess, matches); control.after_hir_lowering.callback = Box::new(after_hir_lowering); - let validate = this.validate; + let miri_config = this.miri_config; control.after_analysis.callback = - Box::new(move |state| after_analysis(state, validate)); + Box::new(move |state| after_analysis(state, miri_config.clone())); control.after_analysis.stop = Compilation::Stop; control } @@ -107,7 +109,7 @@ fn after_hir_lowering(state: &mut CompileState) { fn after_analysis<'a, 'tcx>( state: &mut CompileState<'a, 'tcx>, - validate: bool, + miri_config: MiriConfig, ) { init_late_loggers(); state.session.abort_if_errors(); @@ -117,7 +119,7 @@ fn after_analysis<'a, 'tcx>( let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!"); - miri::eval_main(tcx, entry_def_id, validate); + miri::eval_main(tcx, entry_def_id, miri_config); state.session.abort_if_errors(); } @@ -188,34 +190,51 @@ fn find_sysroot() -> String { fn main() { init_early_loggers(); - let mut args: Vec = std::env::args().collect(); - // Parse our own -Z flags and remove them before rustc gets their hand on them. + // Parse our arguments and split them across rustc and miri let mut validate = true; - args.retain(|arg| { - match arg.as_str() { - "-Zmiri-disable-validation" => { - validate = false; - false - }, - _ => true + let mut rustc_args = vec![]; + let mut miri_args = vec![]; + let mut after_dashdash = false; + for arg in std::env::args() { + if rustc_args.is_empty() { + // Very first arg: for rustc + rustc_args.push(arg); } - }); + else if after_dashdash { + // Everything that comes is Miri args + miri_args.push(arg); + } else { + match arg.as_str() { + "-Zmiri-disable-validation" => { + validate = false; + }, + "--" => { + after_dashdash = true; + } + _ => { + rustc_args.push(arg); + } + } + } + } // Determine sysroot and let rustc know about it let sysroot_flag = String::from("--sysroot"); - if !args.contains(&sysroot_flag) { - args.push(sysroot_flag); - args.push(find_sysroot()); + if !rustc_args.contains(&sysroot_flag) { + rustc_args.push(sysroot_flag); + rustc_args.push(find_sysroot()); } // Finally, add the default flags all the way in the beginning, but after the binary name. - args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string)); + rustc_args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string)); - trace!("rustc arguments: {:?}", args); + debug!("rustc arguments: {:?}", rustc_args); + debug!("miri arguments: {:?}", miri_args); + let miri_config = MiriConfig { validate, args: miri_args }; let result = rustc_driver::run(move || { - rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls { + rustc_driver::run_compiler(&rustc_args, Box::new(MiriCompilerCalls { default: Box::new(RustcDefaultCalls), - validate, + miri_config, }), None, None) }); std::process::exit(result as i32); diff --git a/src/lib.rs b/src/lib.rs index 4ff3e011c6ae..49c39201d006 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,16 +57,23 @@ pub fn miri_default_args() -> &'static [&'static str] { &["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0", "--cfg=miri"] } +/// Configuration needed to spawn a Miri instance +#[derive(Clone)] +pub struct MiriConfig { + pub validate: bool, + pub args: Vec, +} + // Used by priroda pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, - validate: bool, + config: MiriConfig, ) -> EvalResult<'tcx, EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>> { let mut ecx = EvalContext::new( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), - Evaluator::new(validate), + Evaluator::new(config.validate), ); let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); @@ -120,7 +127,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // Second argument (argc): 1 let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - let argc = Scalar::from_int(1, dest.layout.size); + let argc = Scalar::from_uint(config.args.len() as u128, dest.layout.size); ecx.write_scalar(argc, dest)?; // Store argc for macOS _NSGetArgc { @@ -130,24 +137,35 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( } // FIXME: extract main source file path - // Third argument (argv): &[b"foo"] - const CMD: &str = "running-in-miri\0"; + // Third argument (argv): Created from config.args let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - let cmd = ecx.memory_mut().allocate_static_bytes(CMD.as_bytes()).with_default_tag(); - let raw_str_layout = ecx.layout_of(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8))?; - let cmd_place = ecx.allocate(raw_str_layout, MiriMemoryKind::Env.into()); - ecx.write_scalar(Scalar::Ptr(cmd), cmd_place.into())?; - ecx.memory_mut().mark_immutable(cmd_place.to_ptr()?.alloc_id)?; + // Collect the pointers to the individual strings. + let mut argvs = Vec::>::new(); + for arg in config.args { + let mut arg = arg.into_bytes(); + arg.push(0); + argvs.push(ecx.memory_mut().allocate_static_bytes(arg.as_slice()).with_default_tag()); + } + // Make an array with all these pointers, in the Miri memory. + let argvs_layout = ecx.layout_of(ecx.tcx.mk_array(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8), argvs.len() as u64))?; + let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into()); + for (idx, arg) in argvs.into_iter().enumerate() { + let place = ecx.mplace_field(argvs_place, idx as u64)?; + ecx.write_scalar(Scalar::Ptr(arg), place.into())?; + } + ecx.memory_mut().mark_immutable(argvs_place.to_ptr()?.alloc_id)?; + // Write a pointe to that place as the argument. + let argv = argvs_place.ptr; + ecx.write_scalar(argv, dest)?; // Store argv for macOS _NSGetArgv { - let argv = cmd_place.ptr; - ecx.write_scalar(argv, dest)?; let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into()); ecx.write_scalar(argv, argv_place.into())?; ecx.machine.argv = Some(argv_place.ptr.to_ptr()?); } // Store cmdline as UTF-16 for Windows GetCommandLineW { + const CMD: &str = "running-in-miri\0"; let tcx = &{ecx.tcx.tcx}; let cmd_utf16: Vec = CMD.encode_utf16().collect(); let cmd_ptr = ecx.memory_mut().allocate( @@ -179,9 +197,9 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( pub fn eval_main<'a, 'tcx: 'a>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, - validate: bool, + config: MiriConfig, ) { - let mut ecx = create_ecx(tcx, main_id, validate).expect("Couldn't create ecx"); + let mut ecx = create_ecx(tcx, main_id, config).expect("Couldn't create ecx"); // Run! The main execution. let res: EvalResult = (|| { diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index 25e2cfdfa036..32f1bac57d20 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -9,7 +9,9 @@ fn main() { let n = ::read_u32(buf); assert_eq!(n, 0x01020304); println!("{:#010x}", n); - eprintln!("standard error"); + for arg in std::env::args() { + eprintln!("{}", arg); + } } #[cfg(test)] diff --git a/test-cargo-miri/stderr.ref b/test-cargo-miri/stderr.ref index aa7d1a2bdec7..ba2906d0666c 100644 --- a/test-cargo-miri/stderr.ref +++ b/test-cargo-miri/stderr.ref @@ -1 +1 @@ -standard error +main diff --git a/tests/run-pass/args.rs b/tests/run-pass/args.rs new file mode 100644 index 000000000000..0116dce4992d --- /dev/null +++ b/tests/run-pass/args.rs @@ -0,0 +1,5 @@ +fn main() { + for arg in std::env::args() { + println!("{}", arg); + } +} diff --git a/tests/run-pass/args.stdout b/tests/run-pass/args.stdout new file mode 100644 index 000000000000..9564f5a1aa05 --- /dev/null +++ b/tests/run-pass/args.stdout @@ -0,0 +1 @@ +args From e400b42c216cc88ba1689fb72a704ee4aacbb2b3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Feb 2019 20:07:49 +0100 Subject: [PATCH 0560/5092] fix build --- benches/helpers/miri_helper.rs | 9 ++++++--- src/bin/miri-rustc-tests.rs | 8 ++++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index a34e137694cb..404fe7ae9150 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -4,11 +4,13 @@ extern crate rustc; extern crate rustc_driver; extern crate test; -use self::miri::eval_main; -use self::rustc_driver::{driver, Compilation}; +use rustc_driver::{driver, Compilation}; use rustc::hir::def_id::LOCAL_CRATE; use std::cell::RefCell; use std::rc::Rc; + +use miri::{MiriConfig, eval_main}; + use crate::test::Bencher; pub struct MiriCompilerCalls<'a>(Rc>); @@ -50,7 +52,8 @@ pub fn run(filename: &str, bencher: &mut Bencher) { ); bencher.borrow_mut().iter(|| { - eval_main(tcx, entry_def_id, false); + let config = MiriConfig { validate: true, args: vec![] }; + eval_main(tcx, entry_def_id, config); }); state.session.abort_if_errors(); diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 45902dc6722f..3a70577cb7f2 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -25,6 +25,8 @@ use rustc::ty::TyCtxt; use syntax::ast; use rustc::hir::def_id::LOCAL_CRATE; +use miri::MiriConfig; + struct MiriCompilerCalls { default: Box, /// whether we are building for the host @@ -94,9 +96,10 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.node { if i.attrs.iter().any(|attr| attr.name() == "test") { + let config = MiriConfig { validate: true, args: vec![] }; let did = self.0.hir().body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); - miri::eval_main(self.0, did, /*validate*/true); + miri::eval_main(self.0, did, config); self.1.session.abort_if_errors(); } } @@ -106,7 +109,8 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { } state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(tcx, state)); } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { - miri::eval_main(tcx, entry_def_id, /*validate*/true); + let config = MiriConfig { validate: true, args: vec![] }; + miri::eval_main(tcx, entry_def_id, config); state.session.abort_if_errors(); } else { From 5e468766b79d3efb0b46f0cd2cefb451ac0a710b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Feb 2019 20:37:07 +0100 Subject: [PATCH 0561/5092] also pass actual arguments to Windows --- Cargo.toml | 1 + src/lib.rs | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 16b5b2361bd4..721ebe5cfd46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,7 @@ directories = { version = "1.0", optional = true } rustc_version = { version = "0.2.3", optional = true } env_logger = "0.6" log = "0.4" +shell-escape = "0.1.4" # A noop dependency that changes in the Rust repository, it's a bit of a hack. # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` # for more information. diff --git a/src/lib.rs b/src/lib.rs index 49c39201d006..f59a476ed94e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -139,9 +139,19 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // FIXME: extract main source file path // Third argument (argv): Created from config.args let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; + // For Windows, construct a command string with all the aguments + let mut cmd = String::new(); + for arg in config.args.iter() { + if !cmd.is_empty() { + cmd.push(' '); + } + cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into())); + } + cmd.push(std::char::from_u32(0).unwrap()); // don't forget 0 terminator // Collect the pointers to the individual strings. let mut argvs = Vec::>::new(); for arg in config.args { + // Add 0 terminator let mut arg = arg.into_bytes(); arg.push(0); argvs.push(ecx.memory_mut().allocate_static_bytes(arg.as_slice()).with_default_tag()); @@ -165,9 +175,8 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( } // Store cmdline as UTF-16 for Windows GetCommandLineW { - const CMD: &str = "running-in-miri\0"; let tcx = &{ecx.tcx.tcx}; - let cmd_utf16: Vec = CMD.encode_utf16().collect(); + let cmd_utf16: Vec = cmd.encode_utf16().collect(); let cmd_ptr = ecx.memory_mut().allocate( Size::from_bytes(cmd_utf16.len() as u64 * 2), Align::from_bytes(2).unwrap(), From 35ed590075bc1018bb5863f8f7d3d4ae079aea73 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Feb 2019 12:42:16 +0100 Subject: [PATCH 0562/5092] also enable passing arguments through from cargo-miri --- src/bin/cargo-miri.rs | 32 ++++++++++++++++++++++---------- test-cargo-miri/run-test.py | 9 +++++++++ test-cargo-miri/stderr.ref2 | 3 +++ test-cargo-miri/test.stdout.ref2 | 11 +++++++++++ 4 files changed, 45 insertions(+), 10 deletions(-) create mode 100644 test-cargo-miri/stderr.ref2 create mode 100644 test-cargo-miri/test.stdout.ref2 diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 9b97822b4754..93200f33a260 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -10,7 +10,7 @@ use std::fs::{self, File}; const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and tests in Miri Usage: - cargo miri [subcommand] [options] [--] [...] + cargo miri [subcommand] [options] [--] [...] [--] [...] Subcommands: run Run binaries (default) @@ -22,8 +22,9 @@ Common options: --features Features to compile for the package -V, --version Print version info and exit -Other [options] are the same as `cargo rustc`. Everything after the "--" is -passed verbatim to Miri. +Other [options] are the same as `cargo rustc`. Everything after the first "--" is +passed verbatim to Miri, which will pass everything after the second "--" verbatim +to the interpreted program. The config flag `miri` is automatically defined for convenience. You can use it to configure the resource limits @@ -355,11 +356,13 @@ fn in_cargo_miri() { } cmd.arg(arg); } - // add "--" "-Zcargo-miri-marker" and the remaining user flags + // Add "--" (to end the cargo flags), and then the user flags. We add markers around the user flags + // to be able to identify them later. cmd .arg("--") - .arg("cargo-miri-marker") - .args(args); + .arg("cargo-miri-marker-begin") + .args(args) + .arg("cargo-miri-marker-end"); let path = std::env::current_exe().expect("current executable path invalid"); cmd.env("RUSTC_WRAPPER", path); if verbose { @@ -413,10 +416,19 @@ fn inside_cargo_rustc() { }; args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string)); - // see if we have cargo-miri-marker, which means we want to interpret this crate in Miri - // (and remove the marker). - let needs_miri = if let Some(pos) = args.iter().position(|arg| arg == "cargo-miri-marker") { - args.remove(pos); + // See if we can find the cargo-miri markers. Those only get added to the binary we want to + // run. They also serve to mark the user-defined arguments, which we have to move all the way to the + // end (they get added somewhere in the middle). + let needs_miri = if let Some(begin) = args.iter().position(|arg| arg == "cargo-miri-marker-begin") { + let end = args.iter().position(|arg| arg == "cargo-miri-marker-end").expect("Cannot find end marker"); + // These mark the user arguments. We remove the first and last as they are the markers. + let mut user_args = args.drain(begin..=end); + assert_eq!(user_args.next().unwrap(), "cargo-miri-marker-begin"); + assert_eq!(user_args.next_back().unwrap(), "cargo-miri-marker-end"); + // Collect the rest and add it back at the end + let mut user_args = user_args.collect::>(); + args.append(&mut user_args); + // Run this in Miri true } else { false diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 7f7f2660c062..8c59b6bcdead 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -37,10 +37,19 @@ def test(name, cmd, stdout_ref, stderr_ref): def test_cargo_miri_run(): test("cargo miri run", ["cargo", "miri", "run", "-q"], "stdout.ref", "stderr.ref") + test("cargo miri run (with arguments)", + ["cargo", "miri", "run", "-q", "--", "--", "hello world", '"hello world"'], + "stdout.ref", "stderr.ref2" + ) def test_cargo_miri_test(): test("cargo miri test", ["cargo", "miri", "test", "-q"], "test.stdout.ref", "test.stderr.ref") + test("cargo miri test (with filter)", + ["cargo", "miri", "test", "-q", "--", "--", "impl"], + "test.stdout.ref2", "test.stderr.ref" + ) test_cargo_miri_run() test_cargo_miri_test() +print("TEST SUCCESSFUL!") sys.exit(0) diff --git a/test-cargo-miri/stderr.ref2 b/test-cargo-miri/stderr.ref2 new file mode 100644 index 000000000000..8226b1b7cdec --- /dev/null +++ b/test-cargo-miri/stderr.ref2 @@ -0,0 +1,3 @@ +main +hello world +"hello world" diff --git a/test-cargo-miri/test.stdout.ref2 b/test-cargo-miri/test.stdout.ref2 new file mode 100644 index 000000000000..ce3506709d5a --- /dev/null +++ b/test-cargo-miri/test.stdout.ref2 @@ -0,0 +1,11 @@ + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out + + +running 1 test +test simple ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out + From 866aeaecfc35cc54f03ab6bf777c39587dd4b042 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Feb 2019 12:44:56 +0100 Subject: [PATCH 0563/5092] explain arument passing in the docs --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 1d97b61f43d5..21e9fa43a8f8 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,13 @@ Now you can run your project in Miri: 3. If you have a binary project, you can run it through Miri using `cargo +nightly miri run`. +You can pass arguments to Miri after the first `--`, and pass arguments to the +interpreted program or test suite after the second `--`. For example, `cargo ++nightly miri run -- -Zmiri-disable-validation` runs the program without +validation of basic type invariants and references. `cargo +nightly miri test +-- -- filter` passes `filter` to the test suite the same way `cargo test filter` +would. + When running code via `cargo miri`, the `miri` config flag is set. You can use this to exclude test cases that will fail under Miri because they do things Miri does not support: From 88bb7a1525fa03173c5f04b3dcdac34ca2bce082 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 11 Feb 2019 10:02:59 +0100 Subject: [PATCH 0564/5092] TIL that you can also use .appveyor.yml --- appveyor.yml => .appveyor.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename appveyor.yml => .appveyor.yml (100%) diff --git a/appveyor.yml b/.appveyor.yml similarity index 100% rename from appveyor.yml rename to .appveyor.yml From 3c652032c0223de205c28e6e0ded117ca4e46e61 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 12 Feb 2019 10:51:03 +0100 Subject: [PATCH 0565/5092] be more clear which stack we are talking about --- src/stacked_borrows.rs | 4 ++-- tests/compile-fail/stacked_borrows/alias_through_mutation.rs | 2 +- tests/compile-fail/stacked_borrows/aliasing_mut3.rs | 2 +- .../compile-fail/stacked_borrows/box_exclusive_violation1.rs | 2 +- tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs | 2 +- tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_read1.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_read2.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_read3.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_read4.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_read5.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_write2.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_write3.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_write5.rs | 2 +- tests/compile-fail/stacked_borrows/load_invalid_mut.rs | 2 +- tests/compile-fail/stacked_borrows/outdated_local.rs | 2 +- tests/compile-fail/stacked_borrows/pass_invalid_mut.rs | 2 +- tests/compile-fail/stacked_borrows/pointer_smuggling.rs | 2 +- tests/compile-fail/stacked_borrows/return_invalid_mut.rs | 2 +- .../compile-fail/stacked_borrows/return_invalid_mut_option.rs | 2 +- .../compile-fail/stacked_borrows/return_invalid_mut_tuple.rs | 2 +- tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs | 2 +- tests/compile-fail/stacked_borrows/unescaped_local.rs | 2 +- 23 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 1fc705c03bb5..be4a607961f3 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -221,7 +221,7 @@ impl<'tcx> Stack { } } // If we got here, we did not find our item. We have to error to satisfy U3. - Err(format!("Borrow being dereferenced ({:?}) does not exist on the stack", bor)) + Err(format!("Borrow being dereferenced ({:?}) does not exist on the borrow stack", bor)) } /// Perform an actual memory access using `bor`. We do not know any types here @@ -294,7 +294,7 @@ impl<'tcx> Stack { } // If we got here, we did not find our item. err!(MachineError(format!( - "Borrow being accessed ({:?}) does not exist on the stack", + "Borrow being accessed ({:?}) does not exist on the borrow stack", bor ))) } diff --git a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs index db9ac93279f1..30f5921202c3 100644 --- a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs +++ b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs @@ -9,5 +9,5 @@ fn main() { retarget(&mut target_alias, target); // now `target_alias` points to the same thing as `target` *target = 13; - let _val = *target_alias; //~ ERROR does not exist on the stack + let _val = *target_alias; //~ ERROR does not exist on the borrow stack } diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut3.rs b/tests/compile-fail/stacked_borrows/aliasing_mut3.rs index e564e878ddb1..e3c59d156614 100644 --- a/tests/compile-fail/stacked_borrows/aliasing_mut3.rs +++ b/tests/compile-fail/stacked_borrows/aliasing_mut3.rs @@ -1,6 +1,6 @@ use std::mem; -pub fn safe(_x: &mut i32, _y: &i32) {} //~ ERROR does not exist on the stack +pub fn safe(_x: &mut i32, _y: &i32) {} //~ ERROR does not exist on the borrow stack fn main() { let mut x = 0; diff --git a/tests/compile-fail/stacked_borrows/box_exclusive_violation1.rs b/tests/compile-fail/stacked_borrows/box_exclusive_violation1.rs index bd0fec859d8f..481915faed04 100644 --- a/tests/compile-fail/stacked_borrows/box_exclusive_violation1.rs +++ b/tests/compile-fail/stacked_borrows/box_exclusive_violation1.rs @@ -8,7 +8,7 @@ fn demo_mut_advanced_unique(mut our: Box) -> i32 { unknown_code_2(); // We know this will return 5 - *our //~ ERROR does not exist on the stack + *our //~ ERROR does not exist on the borrow stack } // Now comes the evil context diff --git a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs index e08e3bba6840..98d4e6f22965 100644 --- a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs +++ b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs @@ -13,5 +13,5 @@ fn main() { let v1 = safe::as_mut_slice(&v); let _v2 = safe::as_mut_slice(&v); v1[1] = 5; - //~^ ERROR does not exist on the stack + //~^ ERROR does not exist on the borrow stack } diff --git a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs index 959c6314690d..42f345f55144 100644 --- a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs @@ -9,7 +9,7 @@ mod safe { assert!(mid <= len); (from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" - //~^ ERROR does not exist on the stack + //~^ ERROR does not exist on the borrow stack from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) } } diff --git a/tests/compile-fail/stacked_borrows/illegal_read1.rs b/tests/compile-fail/stacked_borrows/illegal_read1.rs index dbaccae88272..0181f739a899 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read1.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read1.rs @@ -7,7 +7,7 @@ fn main() { let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. - //~^ ERROR: does not exist on the stack + //~^ ERROR: does not exist on the borrow stack } fn callee(xraw: *mut i32) { diff --git a/tests/compile-fail/stacked_borrows/illegal_read2.rs b/tests/compile-fail/stacked_borrows/illegal_read2.rs index 2da755d9aabc..b55fe1c6c88a 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read2.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read2.rs @@ -7,7 +7,7 @@ fn main() { let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. - //~^ ERROR: does not exist on the stack + //~^ ERROR: does not exist on the borrow stack } fn callee(xraw: *mut i32) { diff --git a/tests/compile-fail/stacked_borrows/illegal_read3.rs b/tests/compile-fail/stacked_borrows/illegal_read3.rs index b0da0511dee3..9da4ca09606e 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read3.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read3.rs @@ -13,7 +13,7 @@ fn main() { let xref2 = &mut *xref1; // derived from xref1, so using raw is still okay... callee(xref1_sneaky); let _val = *xref2; // ...but any use of it will invalidate our ref. - //~^ ERROR: does not exist on the stack + //~^ ERROR: does not exist on the borrow stack } fn callee(xref1: usize) { diff --git a/tests/compile-fail/stacked_borrows/illegal_read4.rs b/tests/compile-fail/stacked_borrows/illegal_read4.rs index c86ec1286daa..bb889de8f839 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read4.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read4.rs @@ -5,5 +5,5 @@ fn main() { let xraw = xref1 as *mut _; let xref2 = unsafe { &mut *xraw }; let _val = unsafe { *xraw }; // use the raw again, this invalidates xref2 *even* with the special read except for uniq refs - let _illegal = *xref2; //~ ERROR does not exist on the stack + let _illegal = *xref2; //~ ERROR does not exist on the borrow stack } diff --git a/tests/compile-fail/stacked_borrows/illegal_read5.rs b/tests/compile-fail/stacked_borrows/illegal_read5.rs index 863649a47b5e..5f800e754a5d 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read5.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read5.rs @@ -12,5 +12,5 @@ fn main() { let _val = *xref; // we can even still use our mutable reference mem::forget(unsafe { ptr::read(xshr) }); // but after reading through the shared ref let _val = *xref; // the mutable one is dead and gone - //~^ ERROR does not exist on the stack + //~^ ERROR does not exist on the borrow stack } diff --git a/tests/compile-fail/stacked_borrows/illegal_write2.rs b/tests/compile-fail/stacked_borrows/illegal_write2.rs index ba3b6686b84c..affa21c7625e 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write2.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write2.rs @@ -3,6 +3,6 @@ fn main() { let target2 = target as *mut _; drop(&mut *target); // reborrow // Now make sure our ref is still the only one. - unsafe { *target2 = 13; } //~ ERROR does not exist on the stack + unsafe { *target2 = 13; } //~ ERROR does not exist on the borrow stack let _val = *target; } diff --git a/tests/compile-fail/stacked_borrows/illegal_write3.rs b/tests/compile-fail/stacked_borrows/illegal_write3.rs index a653aa5003f6..dc4edcc3a5b4 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write3.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write3.rs @@ -3,6 +3,6 @@ fn main() { // Make sure raw ptr with raw tag cannot mutate frozen location without breaking the shared ref. let r#ref = ⌖ // freeze let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag - unsafe { *ptr = 42; } //~ ERROR does not exist on the stack + unsafe { *ptr = 42; } //~ ERROR does not exist on the borrow stack let _val = *r#ref; } diff --git a/tests/compile-fail/stacked_borrows/illegal_write5.rs b/tests/compile-fail/stacked_borrows/illegal_write5.rs index 57b2ca87d810..af57221260ce 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write5.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write5.rs @@ -7,7 +7,7 @@ fn main() { let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. - //~^ ERROR: does not exist on the stack + //~^ ERROR: does not exist on the borrow stack } fn callee(xraw: *mut i32) { diff --git a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs index 98b9451eda87..f2e4b36f85cc 100644 --- a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs @@ -5,5 +5,5 @@ fn main() { let xref = unsafe { &mut *xraw }; let xref_in_mem = Box::new(xref); let _val = unsafe { *xraw }; // invalidate xref - let _val = *xref_in_mem; //~ ERROR does not exist on the stack + let _val = *xref_in_mem; //~ ERROR does not exist on the borrow stack } diff --git a/tests/compile-fail/stacked_borrows/outdated_local.rs b/tests/compile-fail/stacked_borrows/outdated_local.rs index 64a8ff69108e..ba36e43e0c5d 100644 --- a/tests/compile-fail/stacked_borrows/outdated_local.rs +++ b/tests/compile-fail/stacked_borrows/outdated_local.rs @@ -3,7 +3,7 @@ fn main() { let y: *const i32 = &x; x = 1; // this invalidates y by reactivating the lowermost uniq borrow for this local - assert_eq!(unsafe { *y }, 1); //~ ERROR does not exist on the stack + assert_eq!(unsafe { *y }, 1); //~ ERROR does not exist on the borrow stack assert_eq!(x, 1); } diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs index 28288c6c6362..b239237f0199 100644 --- a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs @@ -6,5 +6,5 @@ fn main() { let xraw = x as *mut _; let xref = unsafe { &mut *xraw }; let _val = unsafe { *xraw }; // invalidate xref - foo(xref); //~ ERROR does not exist on the stack + foo(xref); //~ ERROR does not exist on the borrow stack } diff --git a/tests/compile-fail/stacked_borrows/pointer_smuggling.rs b/tests/compile-fail/stacked_borrows/pointer_smuggling.rs index bd5e28b47e86..a8207d58e99b 100644 --- a/tests/compile-fail/stacked_borrows/pointer_smuggling.rs +++ b/tests/compile-fail/stacked_borrows/pointer_smuggling.rs @@ -8,7 +8,7 @@ fn fun1(x: &mut u8) { fn fun2() { // Now we use a pointer we are not allowed to use - let _x = unsafe { *PTR }; //~ ERROR does not exist on the stack + let _x = unsafe { *PTR }; //~ ERROR does not exist on the borrow stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs index e7f0b9bc9ddd..31f8a4e33afd 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> &mut i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &mut (*xraw).1 }; let _val = unsafe { *xraw }; // invalidate xref - ret //~ ERROR does not exist on the stack + ret //~ ERROR does not exist on the borrow stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs index 28a1f74c6ac2..750d507d6f66 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> Option<&mut i32> { let xraw = x as *mut (i32, i32); let ret = Some(unsafe { &mut (*xraw).1 }); let _val = unsafe { *xraw }; // invalidate xref - ret //~ ERROR does not exist on the stack + ret //~ ERROR does not exist on the borrow stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs index 3357af68a841..bb712e9e486c 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> (&mut i32,) { let xraw = x as *mut (i32, i32); let ret = (unsafe { &mut (*xraw).1 },); let _val = unsafe { *xraw }; // invalidate xref - ret //~ ERROR does not exist on the stack + ret //~ ERROR does not exist on the borrow stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs b/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs index 197c11197efa..45ada8897778 100644 --- a/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs +++ b/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs @@ -10,5 +10,5 @@ fn main() { let _raw: *mut i32 = unsafe { mem::transmute(&mut x[0]) }; // `raw` still carries a tag, so we get another pointer to the same location that does not carry a tag let raw = (&mut x[1] as *mut i32).wrapping_offset(-1); - unsafe { *raw = 13; } //~ ERROR does not exist on the stack + unsafe { *raw = 13; } //~ ERROR does not exist on the borrow stack } diff --git a/tests/compile-fail/stacked_borrows/unescaped_local.rs b/tests/compile-fail/stacked_borrows/unescaped_local.rs index 054697b04a09..1db14ea7eda5 100644 --- a/tests/compile-fail/stacked_borrows/unescaped_local.rs +++ b/tests/compile-fail/stacked_borrows/unescaped_local.rs @@ -4,5 +4,5 @@ fn main() { let mut x = 42; let raw = &mut x as *mut i32 as usize as *mut i32; let _ptr = &mut x; - unsafe { *raw = 13; } //~ ERROR does not exist on the stack + unsafe { *raw = 13; } //~ ERROR does not exist on the borrow stack } From fd6bd5ba4b55da0c7056d91ed3cae85bb2029b95 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 12 Feb 2019 10:56:27 +0100 Subject: [PATCH 0566/5092] rename things away from 'Shr' that are used for much more than just shared references --- src/stacked_borrows.rs | 58 +++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index be4a607961f3..a52e115323c6 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -21,19 +21,19 @@ pub type CallId = u64; pub enum Borrow { /// A unique (mutable) reference. Uniq(Timestamp), - /// A shared reference. This is also used by raw pointers, which do not track details + /// An aliasing reference. This is also used by raw pointers, which do not track details /// of how or when they were created, hence the timestamp is optional. /// Shr(Some(_)) does NOT mean that the destination of this reference is frozen; /// that depends on the type! Only those parts outside of an `UnsafeCell` are actually /// frozen. - Shr(Option), + Alias(Option), } impl Borrow { #[inline(always)] - pub fn is_shared(self) -> bool { + pub fn is_aliasing(self) -> bool { match self { - Borrow::Shr(_) => true, + Borrow::Alias(_) => true, _ => false, } } @@ -49,7 +49,7 @@ impl Borrow { impl Default for Borrow { fn default() -> Self { - Borrow::Shr(None) + Borrow::Alias(None) } } @@ -58,10 +58,9 @@ impl Default for Borrow { pub enum BorStackItem { /// Indicates the unique reference that may mutate. Uniq(Timestamp), - /// Indicates that the location has been shared. Used for raw pointers, but - /// also for shared references. The latter *additionally* get frozen - /// when there is no `UnsafeCell`. - Shr, + /// Indicates that the location has been mutably shared. Used for raw pointers as + /// well as for unfrozen shared references. + Raw, /// A barrier, tracking the function it belongs to by its index on the call stack FnBarrier(CallId) } @@ -186,19 +185,19 @@ impl<'tcx> Stack { kind: RefKind, ) -> Result, String> { // Exclude unique ref with frozen tag. - if let (RefKind::Unique, Borrow::Shr(Some(_))) = (kind, bor) { + if let (RefKind::Unique, Borrow::Alias(Some(_))) = (kind, bor) { return Err(format!("Encountered mutable reference with frozen tag ({:?})", bor)); } // Checks related to freezing match bor { - Borrow::Shr(Some(bor_t)) if kind == RefKind::Frozen => { + Borrow::Alias(Some(bor_t)) if kind == RefKind::Frozen => { // We need the location to be frozen. This ensures F3. let frozen = self.frozen_since.map_or(false, |itm_t| itm_t <= bor_t); return if frozen { Ok(None) } else { Err(format!("Location is not frozen long enough")) } } - Borrow::Shr(_) if self.frozen_since.is_some() => { + Borrow::Alias(_) if self.frozen_since.is_some() => { return Ok(None) // Shared deref to frozen location, looking good } _ => {} // Not sufficient, go on looking. @@ -210,8 +209,8 @@ impl<'tcx> Stack { // Found matching unique item. This satisfies U3. return Ok(Some(idx)) } - (BorStackItem::Shr, Borrow::Shr(_)) => { - // Found matching shared/raw item. + (BorStackItem::Raw, Borrow::Alias(_)) => { + // Found matching aliasing/raw item. return Ok(Some(idx)) } // Go on looking. We ignore barriers! When an `&mut` and an `&` alias, @@ -258,14 +257,15 @@ impl<'tcx> Stack { (BorStackItem::Uniq(itm_t), Borrow::Uniq(bor_t)) if itm_t == bor_t => { // Found matching unique item. Continue after the match. } - (BorStackItem::Shr, _) if kind == AccessKind::Read => { - // When reading, everything can use a shared item! + (BorStackItem::Raw, _) if kind == AccessKind::Read => { + // When reading, everything can use a raw item! // We do not want to do this when writing: Writing to an `&mut` // should reaffirm its exclusivity (i.e., make sure it is - // on top of the stack). Continue after the match. + // on top of the stack). + // Continue after the match. } - (BorStackItem::Shr, Borrow::Shr(_)) => { - // Found matching shared item. Continue after the match. + (BorStackItem::Raw, Borrow::Alias(_)) => { + // Found matching raw item. Continue after the match. } _ => { // Pop this, go on. This ensures U2. @@ -309,7 +309,7 @@ impl<'tcx> Stack { // of access (like writing through raw pointers) is permitted. if kind == RefKind::Frozen { let bor_t = match bor { - Borrow::Shr(Some(t)) => t, + Borrow::Alias(Some(t)) => t, _ => bug!("Creating illegal borrow {:?} for frozen ref", bor), }; // It is possible that we already are frozen (e.g. if we just pushed a barrier, @@ -328,12 +328,12 @@ impl<'tcx> Stack { // Push new item to the stack. let itm = match bor { Borrow::Uniq(t) => BorStackItem::Uniq(t), - Borrow::Shr(_) => BorStackItem::Shr, + Borrow::Alias(_) => BorStackItem::Raw, }; if *self.borrows.last().unwrap() == itm { // This is just an optimization, no functional change: Avoid stacking // multiple `Shr` on top of each other. - assert!(bor.is_shared()); + assert!(bor.is_aliasing()); trace!("create: Sharing a shared location is a NOP"); } else { // This ensures U1. @@ -440,7 +440,7 @@ impl<'tcx> Stacks { _ => false, }; if bor_redundant { - assert!(new_bor.is_shared(), "A unique reborrow can never be redundant"); + assert!(new_bor.is_aliasing(), "A unique reborrow can never be redundant"); trace!("reborrow is redundant"); continue; } @@ -465,7 +465,7 @@ impl AllocationExtra for Stacks { #[inline(always)] fn memory_allocated<'tcx>(size: Size, extra: &MemoryState) -> Self { let stack = Stack { - borrows: vec![BorStackItem::Shr], + borrows: vec![BorStackItem::Raw], frozen_since: None, }; Stacks { @@ -511,7 +511,7 @@ impl<'tcx> Stacks { ) { for stack in self.stacks.get_mut().iter_mut(Size::ZERO, size) { assert!(stack.borrows.len() == 1); - assert_eq!(stack.borrows.pop().unwrap(), BorStackItem::Shr); + assert_eq!(stack.borrows.pop().unwrap(), BorStackItem::Raw); stack.borrows.push(itm); } } @@ -536,7 +536,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let alloc = this.memory().get(ptr.alloc_id)?; alloc.check_bounds(this, ptr, size)?; // Update the stacks. - if let Borrow::Shr(Some(_)) = new_bor { + if let Borrow::Alias(Some(_)) = new_bor { // Reference that cares about freezing. We need a frozen-sensitive reborrow. this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; @@ -574,7 +574,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let time = this.machine.stacked_borrows.increment_clock(); let new_bor = match mutbl { Some(MutMutable) => Borrow::Uniq(time), - Some(MutImmutable) => Borrow::Shr(Some(time)), + Some(MutImmutable) => Borrow::Alias(Some(time)), None => Borrow::default(), }; @@ -586,7 +586,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, assert!(mutbl == Some(MutMutable), "two-phase shared borrows make no sense"); // We immediately share it, to allow read accesses let two_phase_time = this.machine.stacked_borrows.increment_clock(); - let two_phase_bor = Borrow::Shr(Some(two_phase_time)); + let two_phase_bor = Borrow::Alias(Some(two_phase_time)); this.reborrow(new_place, size, /*fn_barrier*/false, two_phase_bor)?; } @@ -651,7 +651,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let alloc = this.memory().get(ptr.alloc_id)?; alloc.check_bounds(this, ptr, size)?; // If we got here, we do some checking, *but* we leave the tag unchanged. - if let Borrow::Shr(Some(_)) = ptr.tag { + if let Borrow::Alias(Some(_)) = ptr.tag { assert_eq!(mutability, Some(MutImmutable)); // We need a frozen-sensitive check this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { From 93cf2e5491acc90ae6a08a9acbb55be512124071 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Feb 2019 08:13:07 +0100 Subject: [PATCH 0567/5092] update Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 0c7f46922122..b265e000950e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2019-01-30 +nightly-2019-02-13 From d91ab9a7a63d3e4a6bd1071f32aada6e0194ef11 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Feb 2019 10:07:31 +0100 Subject: [PATCH 0568/5092] fix ptr comparison test --- tests/run-pass/function_pointers.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/function_pointers.rs b/tests/run-pass/function_pointers.rs index cc888630d3ee..26a2d5a6c2a9 100644 --- a/tests/run-pass/function_pointers.rs +++ b/tests/run-pass/function_pointers.rs @@ -1,5 +1,16 @@ -fn f() -> i32 { - 42 +trait Answer { + fn answer() -> Self; +} + +impl Answer for i32 { + fn answer() -> i32 { + 42 + } +} + +// A generic function, to make its address unstable +fn f() -> T { + Answer::answer() } fn g(i: i32) -> i32 { From 2d892c160b3aaaf3ec0a002eb38a4b50379cb759 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Feb 2019 12:09:53 +0100 Subject: [PATCH 0569/5092] skip installing rust-src if XARGO_RUST_SRC is set --- src/bin/cargo-miri.rs | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 93200f33a260..bca2b6df1b40 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -193,18 +193,21 @@ fn setup(ask_user: bool) { } } - // Then, we also need rust-src. Let's see if it is already installed. - let sysroot = Command::new("rustc").args(&["--print", "sysroot"]).output().unwrap().stdout; - let sysroot = std::str::from_utf8(&sysroot[..]).unwrap(); - let src = Path::new(sysroot.trim_end_matches('\n')).join("lib").join("rustlib").join("src"); - if !src.exists() { - if ask_user { - ask("It seems you do not have the rust-src component installed. I will run `rustup component add rust-src`. Proceed?"); - } else { - println!("Installing rust-src component: `rustup component add rust-src`"); - } - if !Command::new("rustup").args(&["component", "add", "rust-src"]).status().unwrap().success() { - show_error(format!("Failed to install rust-src component")); + // Then, unless XARGO_RUST_SRC is set, we also need rust-src. + // Let's see if it is already installed. + if std::env::var("XARGO_RUST_SRC").is_err() { + let sysroot = Command::new("rustc").args(&["--print", "sysroot"]).output().unwrap().stdout; + let sysroot = std::str::from_utf8(&sysroot[..]).unwrap(); + let src = Path::new(sysroot.trim_end_matches('\n')).join("lib").join("rustlib").join("src"); + if !src.exists() { + if ask_user { + ask("It seems you do not have the rust-src component installed. I will run `rustup component add rust-src`. Proceed?"); + } else { + println!("Installing rust-src component: `rustup component add rust-src`"); + } + if !Command::new("rustup").args(&["component", "add", "rust-src"]).status().unwrap().success() { + show_error(format!("Failed to install rust-src component")); + } } } From 2d323857e91f3f73bd9d15a83af079a3f6d9ff43 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Feb 2019 17:47:47 +0100 Subject: [PATCH 0570/5092] implement and test posix_memalign --- src/fn_call.rs | 26 ++++++++++++++++++++++++++ tests/run-pass/heap.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/src/fn_call.rs b/src/fn_call.rs index a5708305a976..fa68f1d0d703 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -93,6 +93,32 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_scalar(Scalar::Ptr(ptr.with_default_tag()), dest)?; } } + "posix_memalign" => { + let ret = this.deref_operand(args[0])?; + let align = this.read_scalar(args[1])?.to_usize(this)?; + let size = this.read_scalar(args[2])?.to_usize(this)?; + // align must be a power of 2, and also at least ptr-sized (wtf, POSIX) + if !align.is_power_of_two() { + return err!(HeapAllocNonPowerOfTwoAlignment(align)); + } + if align < this.pointer_size().bytes() { + return err!(MachineError(format!( + "posix_memalign: alignment must be at least the size of a pointer, but is {}", + align, + ))); + } + if size == 0 { + this.write_null(ret.into())?; + } else { + let ptr = this.memory_mut().allocate( + Size::from_bytes(size), + Align::from_bytes(align).unwrap(), + MiriMemoryKind::C.into() + ); + this.write_scalar(Scalar::Ptr(ptr.with_default_tag()), ret.into())?; + } + this.write_null(dest)?; + } "free" => { let ptr = this.read_scalar(args[0])?.not_undef()?; diff --git a/tests/run-pass/heap.rs b/tests/run-pass/heap.rs index b533f9164698..8421dce9c21b 100644 --- a/tests/run-pass/heap.rs +++ b/tests/run-pass/heap.rs @@ -1,4 +1,7 @@ #![feature(box_syntax)] +#![feature(allocator_api)] + +use std::alloc::{Global, Alloc, Layout, System}; fn make_box() -> Box<(i16, i16)> { Box::new((1, 2)) @@ -27,8 +30,31 @@ fn allocate_reallocate() { assert_eq!(s.capacity(), 9); } +fn check_overalign_requests(mut allocator: T) { + let size = 8; + let align = 16; // greater than size + let iterations = 1; // Miri is deterministic, no need to try many times + unsafe { + let pointers: Vec<_> = (0..iterations).map(|_| { + allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap() + }).collect(); + for &ptr in &pointers { + assert_eq!((ptr.as_ptr() as usize) % align, 0, + "Got a pointer less aligned than requested") + } + + // Clean up + for &ptr in &pointers { + allocator.dealloc(ptr, Layout::from_size_align(size, align).unwrap()) + } + } +} + fn main() { assert_eq!(*make_box(), (1, 2)); assert_eq!(*make_box_syntax(), (1, 2)); allocate_reallocate(); + + check_overalign_requests(System); + check_overalign_requests(Global); } From 8466f78e83799ddee5f9bfd19f883c627036d096 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Feb 2019 19:47:51 +0100 Subject: [PATCH 0571/5092] ignore overaligned tests on Windows (because, of course, Windows' API is broken here) --- tests/run-pass/heap.rs | 26 -------------------------- tests/run-pass/heap_system.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 26 deletions(-) create mode 100644 tests/run-pass/heap_system.rs diff --git a/tests/run-pass/heap.rs b/tests/run-pass/heap.rs index 8421dce9c21b..b533f9164698 100644 --- a/tests/run-pass/heap.rs +++ b/tests/run-pass/heap.rs @@ -1,7 +1,4 @@ #![feature(box_syntax)] -#![feature(allocator_api)] - -use std::alloc::{Global, Alloc, Layout, System}; fn make_box() -> Box<(i16, i16)> { Box::new((1, 2)) @@ -30,31 +27,8 @@ fn allocate_reallocate() { assert_eq!(s.capacity(), 9); } -fn check_overalign_requests(mut allocator: T) { - let size = 8; - let align = 16; // greater than size - let iterations = 1; // Miri is deterministic, no need to try many times - unsafe { - let pointers: Vec<_> = (0..iterations).map(|_| { - allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap() - }).collect(); - for &ptr in &pointers { - assert_eq!((ptr.as_ptr() as usize) % align, 0, - "Got a pointer less aligned than requested") - } - - // Clean up - for &ptr in &pointers { - allocator.dealloc(ptr, Layout::from_size_align(size, align).unwrap()) - } - } -} - fn main() { assert_eq!(*make_box(), (1, 2)); assert_eq!(*make_box_syntax(), (1, 2)); allocate_reallocate(); - - check_overalign_requests(System); - check_overalign_requests(Global); } diff --git a/tests/run-pass/heap_system.rs b/tests/run-pass/heap_system.rs new file mode 100644 index 000000000000..0eb209704713 --- /dev/null +++ b/tests/run-pass/heap_system.rs @@ -0,0 +1,29 @@ +//ignore-windows: Inspects allocation base address on Windows +#![feature(allocator_api)] + +use std::alloc::{Global, Alloc, Layout, System}; + +fn check_overalign_requests(mut allocator: T) { + let size = 8; + let align = 16; // greater than size + let iterations = 1; // Miri is deterministic, no need to try many times + unsafe { + let pointers: Vec<_> = (0..iterations).map(|_| { + allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap() + }).collect(); + for &ptr in &pointers { + assert_eq!((ptr.as_ptr() as usize) % align, 0, + "Got a pointer less aligned than requested") + } + + // Clean up + for &ptr in &pointers { + allocator.dealloc(ptr, Layout::from_size_align(size, align).unwrap()) + } + } +} + +fn main() { + check_overalign_requests(System); + check_overalign_requests(Global); +} From ad8a5d965bab87d662b3e9297e062e48e3ff3718 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Feb 2019 08:33:48 +0100 Subject: [PATCH 0572/5092] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index b265e000950e..edd1c533d983 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2019-02-13 +nightly-2019-02-14 From 457741d6d2eb6c869fb95ba76dae55daa44b5a3f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Feb 2019 14:01:40 +0100 Subject: [PATCH 0573/5092] update for new bin_op APIs --- src/intrinsic.rs | 16 ++++++++-------- src/lib.rs | 8 +++----- src/operator.rs | 21 +++++++++++---------- 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 09df91b3ab38..5a9939db2e7d 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -5,7 +5,7 @@ use rustc::ty; use rustc::mir::interpret::{EvalResult, PointerArithmetic}; use crate::{ - PlaceTy, OpTy, Immediate, Scalar, ScalarMaybeUndef, Borrow, + PlaceTy, OpTy, ImmTy, Immediate, Scalar, ScalarMaybeUndef, Borrow, OperatorEvalContextExt }; @@ -80,11 +80,11 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, _ if intrinsic_name.starts_with("atomic_cxchg") => { let ptr = this.deref_operand(args[0])?; - let expect_old = this.read_immediate(args[1])?; // read as immediate for the sake of `binary_op_imm()` + let expect_old = this.read_immediate(args[1])?; // read as immediate for the sake of `binary_op()` let new = this.read_scalar(args[2])?; - let old = this.read_immediate(ptr.into())?; // read as immediate for the sake of `binary_op_imm()` - // binary_op_imm will bail if either of them is not a scalar - let (eq, _) = this.binary_op_imm(mir::BinOp::Eq, old, expect_old)?; + let old = this.read_immediate(ptr.into())?; // read as immediate for the sake of `binary_op()` + // binary_op will bail if either of them is not a scalar + let (eq, _) = this.binary_op(mir::BinOp::Eq, old, expect_old)?; let res = Immediate::ScalarPair(old.to_scalar_or_undef(), eq.into()); this.write_immediate(res, dest)?; // old value is returned // update ptr depending on comparison @@ -140,9 +140,9 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, _ => bug!(), }; // Atomics wrap around on overflow. - let (val, _overflowed) = this.binary_op_imm(op, old, rhs)?; + let (val, _overflowed) = this.binary_op(op, old, rhs)?; let val = if neg { - this.unary_op(mir::UnOp::Not, val, old.layout)? + this.unary_op(mir::UnOp::Not, ImmTy::from_scalar(val, old.layout))? } else { val }; @@ -239,7 +239,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let a = this.read_immediate(args[0])?; let b = this.read_immediate(args[1])?; // check x % y != 0 - if this.binary_op_imm(mir::BinOp::Rem, a, b)?.0.to_bits(dest.layout.size)? != 0 { + if this.binary_op(mir::BinOp::Rem, a, b)?.0.to_bits(dest.layout.size)? != 0 { return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b))); } this.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; diff --git a/src/lib.rs b/src/lib.rs index f59a476ed94e..67bd54872f82 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -406,12 +406,10 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn ptr_op( ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, bin_op: mir::BinOp, - left: Scalar, - left_layout: TyLayout<'tcx>, - right: Scalar, - right_layout: TyLayout<'tcx>, + left: ImmTy<'tcx, Borrow>, + right: ImmTy<'tcx, Borrow>, ) -> EvalResult<'tcx, (Scalar, bool)> { - ecx.ptr_op(bin_op, left, left_layout, right, right_layout) + ecx.ptr_op(bin_op, left, right) } fn box_alloc( diff --git a/src/operator.rs b/src/operator.rs index 4b110224a0a2..0bdec0349778 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -7,10 +7,8 @@ pub trait EvalContextExt<'tcx> { fn ptr_op( &self, bin_op: mir::BinOp, - left: Scalar, - left_layout: TyLayout<'tcx>, - right: Scalar, - right_layout: TyLayout<'tcx>, + left: ImmTy<'tcx, Borrow>, + right: ImmTy<'tcx, Borrow>, ) -> EvalResult<'tcx, (Scalar, bool)>; fn ptr_int_arithmetic( @@ -40,13 +38,16 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' fn ptr_op( &self, bin_op: mir::BinOp, - left: Scalar, - left_layout: TyLayout<'tcx>, - right: Scalar, - right_layout: TyLayout<'tcx>, + left: ImmTy<'tcx, Borrow>, + right: ImmTy<'tcx, Borrow>, ) -> EvalResult<'tcx, (Scalar, bool)> { use rustc::mir::BinOp::*; + let left_layout = left.layout; + let left = left.to_scalar()?; + let right_layout = right.layout; + let right = right.to_scalar()?; + trace!("ptr_op: {:?} {:?} {:?}", left, bin_op, right); debug_assert!(left.is_ptr() || right.is_ptr() || bin_op == Offset); @@ -85,8 +86,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let layout = self.layout_of(self.tcx.types.usize)?; return self.binary_op( Sub, - left_offset, layout, - right_offset, layout, + ImmTy::from_scalar(left_offset, layout), + ImmTy::from_scalar(right_offset, layout), ) } _ => bug!("We already established it has to be one of these operators."), From 2c3ee678b127629396908199d298f66edb0b0b2d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Feb 2019 16:27:00 +0100 Subject: [PATCH 0574/5092] Fix comparing fat pointers --- src/lib.rs | 2 +- src/operator.rs | 31 +++++++++++++++++++++---------- tests/run-pass/rc.rs | 10 ++++++++++ 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 67bd54872f82..1608bc1f3028 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,7 +17,7 @@ use std::collections::HashMap; use std::borrow::Cow; use rustc::ty::{self, TyCtxt, query::TyCtxtAt}; -use rustc::ty::layout::{TyLayout, LayoutOf, Size, Align}; +use rustc::ty::layout::{LayoutOf, Size, Align}; use rustc::hir::{self, def_id::DefId}; use rustc::mir; diff --git a/src/operator.rs b/src/operator.rs index 0bdec0349778..b64ccf5462d6 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,4 +1,4 @@ -use rustc::ty::{Ty, layout::TyLayout}; +use rustc::ty::Ty; use rustc::mir; use crate::*; @@ -23,7 +23,6 @@ pub trait EvalContextExt<'tcx> { &self, left: Scalar, right: Scalar, - size: Size, ) -> EvalResult<'tcx, bool>; fn pointer_offset_inbounds( @@ -43,12 +42,29 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' ) -> EvalResult<'tcx, (Scalar, bool)> { use rustc::mir::BinOp::*; + trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); + + // Operations that support fat pointers + match bin_op { + Eq | Ne => { + let eq = match (*left, *right) { + (Immediate::Scalar(left), Immediate::Scalar(right)) => + self.ptr_eq(left.not_undef()?, right.not_undef()?)?, + (Immediate::ScalarPair(left1, left2), Immediate::ScalarPair(right1, right2)) => + self.ptr_eq(left1.not_undef()?, right1.not_undef()?)? && + self.ptr_eq(left2.not_undef()?, right2.not_undef()?)?, + _ => bug!("Type system should not allow comparing Scalar with ScalarPair"), + }; + return Ok((Scalar::from_bool(if bin_op == Eq { eq } else { !eq }), false)); + } + _ => {}, + } + + // Now we expect no more fat pointers let left_layout = left.layout; let left = left.to_scalar()?; let right_layout = right.layout; let right = right.to_scalar()?; - - trace!("ptr_op: {:?} {:?} {:?}", left, bin_op, right); debug_assert!(left.is_ptr() || right.is_ptr() || bin_op == Offset); match bin_op { @@ -64,11 +80,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' )?; Ok((ptr, false)) } - // These work on anything - Eq => - Ok((Scalar::from_bool(self.ptr_eq(left, right, left_layout.size)?), false)), - Ne => - Ok((Scalar::from_bool(!self.ptr_eq(left, right, left_layout.size)?), false)), // These need both to be pointer, and fail if they are not in the same location Lt | Le | Gt | Ge | Sub if left.is_ptr() && right.is_ptr() => { let left = left.to_ptr().expect("we checked is_ptr"); @@ -127,8 +138,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' &self, left: Scalar, right: Scalar, - size: Size, ) -> EvalResult<'tcx, bool> { + let size = self.pointer_size(); Ok(match (left, right) { (Scalar::Bits { .. }, Scalar::Bits { .. }) => left.to_bits(size)? == right.to_bits(size)?, diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index bc89d752e0b6..af68e5cfd1fa 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -1,6 +1,7 @@ use std::cell::{Cell, RefCell}; use std::rc::Rc; use std::sync::Arc; +use std::fmt::Debug; fn rc_refcell() { let r = Rc::new(RefCell::new(42)); @@ -60,7 +61,16 @@ fn rc_from() { check_unique_rc::(Rc::from("Hello, World!")); } +fn rc_fat_ptr_eq() { + let p = Rc::new(1) as Rc; + let a: *const Debug = &*p; + let r = Rc::into_raw(p); + let _b = a == r; + drop(unsafe { Rc::from_raw(r) }); +} + fn main() { + rc_fat_ptr_eq(); rc_refcell(); rc_refcell2(); rc_cell(); From 1921fa5766292a8b4ddd6c44deaedccfb2f85b7e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Feb 2019 23:48:37 +0100 Subject: [PATCH 0575/5092] actually they should be equal --- tests/run-pass/rc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index af68e5cfd1fa..164842ab4d97 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -65,7 +65,7 @@ fn rc_fat_ptr_eq() { let p = Rc::new(1) as Rc; let a: *const Debug = &*p; let r = Rc::into_raw(p); - let _b = a == r; + assert!(a == r); drop(unsafe { Rc::from_raw(r) }); } From 9397b36ab813376d5af354c25f8d875b281802c9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Feb 2019 17:21:46 +0100 Subject: [PATCH 0576/5092] typo and comments --- src/bin/cargo-miri.rs | 2 +- tests/run-pass/hashmap.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index bca2b6df1b40..0de835f45d0a 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -266,7 +266,7 @@ path = "lib.rs" let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; std::env::set_var("MIRI_SYSROOT", &sysroot); if !ask_user { - println!("A libstd for miri is now available in `{}`", sysroot.display()); + println!("A libstd for Miri is now available in `{}`", sysroot.display()); } } diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass/hashmap.rs index f4a358174f55..d89a5ab535f6 100644 --- a/tests/run-pass/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -21,5 +21,5 @@ fn main() { } assert_eq!(map.values().fold(0, |x, y| x+y), num*(num-1)/2); - // TODO: Test Entry API + // TODO: Test Entry API, Iterators, ... } From 15722fab51fadd484694dd01498f35ebba2b1999 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 15 Feb 2019 08:28:02 +0100 Subject: [PATCH 0577/5092] update Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index edd1c533d983..cb6d9f177dde 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2019-02-14 +nightly-2019-02-15 From e630175867b00a81e4125ece04e5f14cc88d9970 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 15 Feb 2019 09:32:54 +0100 Subject: [PATCH 0578/5092] fix async-fn test --- tests/run-pass/async-fn.rs | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 9094a9fd3a68..48f8fc1223c9 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -4,7 +4,8 @@ futures_api, )] -use std::{future::Future, pin::Pin, task::Poll}; +use std::{future::Future, pin::Pin, task::Poll, ptr}; +use std::task::{Waker, RawWaker, RawWakerVTable}; // See if we can run a basic `async fn` pub async fn foo(x: &u32, y: u32) -> u32 { @@ -17,18 +18,23 @@ pub async fn foo(x: &u32, y: u32) -> u32 { *x + y + *a } +fn raw_waker_clone(_this: *const ()) -> RawWaker { + panic!("unimplemented"); +} +fn raw_waker_wake(_this: *const ()) { + panic!("unimplemented"); +} +fn raw_waker_drop(_this: *const ()) {} + +static RAW_WAKER: RawWakerVTable = RawWakerVTable { + clone: raw_waker_clone, + wake: raw_waker_wake, + drop: raw_waker_drop, +}; + fn main() { - use std::{sync::Arc, task::{Wake, local_waker}}; - - struct NoWake; - impl Wake for NoWake { - fn wake(_arc_self: &Arc) { - panic!(); - } - } - - let lw = unsafe { local_waker(Arc::new(NoWake)) }; let x = 5; let mut fut = foo(&x, 7); - assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&lw), Poll::Ready(31)); + let waker = unsafe { Waker::new_unchecked(RawWaker::new(ptr::null(), &RAW_WAKER)) }; + assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&waker), Poll::Ready(31)); } From 5190b5b1e817977994ddb7afd2c27a1a9818236a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 15 Feb 2019 10:41:12 +0100 Subject: [PATCH 0579/5092] test VecDeque debug printing --- tests/run-pass/vecdeque.rs | 8 ++++++++ tests/run-pass/vecdeque.stdout | 2 ++ 2 files changed, 10 insertions(+) create mode 100644 tests/run-pass/vecdeque.stdout diff --git a/tests/run-pass/vecdeque.rs b/tests/run-pass/vecdeque.rs index 381169505ec9..9c9909802e20 100644 --- a/tests/run-pass/vecdeque.rs +++ b/tests/run-pass/vecdeque.rs @@ -9,6 +9,14 @@ fn main() { let mut src = VecDeque::new(); src.push_front(Box::new(2)); dst.append(&mut src); + for a in dst.iter() { + assert_eq!(**a, 2); + } + + // Regression test for Debug and Diaplay impl's + println!("{:?} {:?}", dst, dst.iter()); + println!("{:?}", VecDeque::::new().iter()); + for a in dst { assert_eq!(*a, 2); } diff --git a/tests/run-pass/vecdeque.stdout b/tests/run-pass/vecdeque.stdout new file mode 100644 index 000000000000..63de960ee2bd --- /dev/null +++ b/tests/run-pass/vecdeque.stdout @@ -0,0 +1,2 @@ +[2, 2] Iter([2, 2], []) +Iter([], []) From a3eae6c8ab0ac190066c8ebefb0ef0314aa1e7ef Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 15 Feb 2019 10:41:25 +0100 Subject: [PATCH 0580/5092] collect some bugs that we found --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 21e9fa43a8f8..a9e9ee0a1e3c 100644 --- a/README.md +++ b/README.md @@ -252,6 +252,18 @@ used according to their aliasing restrictions. [slides]: https://solson.me/miri-slides.pdf [report]: https://solson.me/miri-report.pdf +## Bugs found by Miri + +Miri has already found a number of bugs in the Rust standard library, which we collect here. + +* [`vec_deque::Iter` having an unsound `Debug` implementation](https://github.com/rust-lang/rust/issues/53566) +* [`From<&[T]> for Rc` creating a not sufficiently aligned reference](https://github.com/rust-lang/rust/issues/54908) +* [`BTreeMap` creating a shared reference pointing to a too small allocation](https://github.com/rust-lang/rust/issues/54957) +* [`VecDeque` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/56161) +* [Futures turning a shared reference into a mutable one](https://github.com/rust-lang/rust/pull/56319) +* [`str` turning a shared reference into a mutable one](https://github.com/rust-lang/rust/pull/58200) +* [`BTreeMap` creating mutable references that overlap with shared references](https://github.com/rust-lang/rust/pull/58431) + ## License Licensed under either of From a4c852ddfe95b8726ca4e23f49290f2a561dbd40 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 15 Feb 2019 10:43:27 +0100 Subject: [PATCH 0581/5092] link to bug list from intro --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a9e9ee0a1e3c..897bf0b66e7e 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ for example: or an invalid enum discriminant) * WIP: Violations of the rules governing aliasing for reference types +Miri has already discovered some [real-world bugs](#bugs-found-by-miri). + [rust]: https://www.rust-lang.org/ [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md [`unreachable_unchecked`]: https://doc.rust-lang.org/stable/std/hint/fn.unreachable_unchecked.html @@ -256,7 +258,7 @@ used according to their aliasing restrictions. Miri has already found a number of bugs in the Rust standard library, which we collect here. -* [`vec_deque::Iter` having an unsound `Debug` implementation](https://github.com/rust-lang/rust/issues/53566) +* [`Debug for vec_deque::Iter` accessing uninitialized memory](https://github.com/rust-lang/rust/issues/53566) * [`From<&[T]> for Rc` creating a not sufficiently aligned reference](https://github.com/rust-lang/rust/issues/54908) * [`BTreeMap` creating a shared reference pointing to a too small allocation](https://github.com/rust-lang/rust/issues/54957) * [`VecDeque` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/56161) From 17e05540adadd4643aab3098cc594801c9532d77 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Feb 2019 12:09:38 +0100 Subject: [PATCH 0582/5092] we can't have profiles because we are also in the rustc worksapce --- Cargo.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 721ebe5cfd46..da876423ce9b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,6 +56,3 @@ rustc_tests = [] [dev-dependencies] compiletest_rs = { version = "0.3.17", features = ["tmp"] } colored = "1.6" - -[profile.release] -debug = true From edd9e5b7b12ed1093a87ba51e25443f7e1098c4f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Feb 2019 17:22:06 +0100 Subject: [PATCH 0583/5092] test BTree a bit more --- tests/run-pass/btreemap.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/btreemap.rs b/tests/run-pass/btreemap.rs index b7140d72ac3a..e2049d948032 100644 --- a/tests/run-pass/btreemap.rs +++ b/tests/run-pass/btreemap.rs @@ -1,3 +1,5 @@ +use std::collections::{BTreeMap, BTreeSet}; + #[derive(PartialEq, Eq, PartialOrd, Ord)] pub enum Foo { A(&'static str), @@ -6,11 +8,22 @@ pub enum Foo { } pub fn main() { - let mut b = std::collections::BTreeSet::new(); + let mut b = BTreeSet::new(); b.insert(Foo::A("\'")); b.insert(Foo::A("/=")); b.insert(Foo::A("#")); b.insert(Foo::A("0o")); assert!(b.remove(&Foo::A("/="))); assert!(!b.remove(&Foo::A("/="))); + + // Also test a lower-alignment type, where the NodeHeader overlaps with + // the keys. + let mut b = BTreeSet::new(); + b.insert(1024); + b.insert(7); + + let mut b = BTreeMap::new(); + b.insert("bar", 1024); + b.insert("baz", 7); + for _val in b.iter_mut() {} } From 441442e07113ae9cad93243fb6e178b1b6b1665e Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sat, 23 Feb 2019 19:56:29 +0900 Subject: [PATCH 0584/5092] Update some links --- Cargo.toml | 2 +- README.md | 6 +++--- tests/run-pass/validation_lifetime_resolution.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index da876423ce9b..1a1a1fa2330a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Scott Olson "] description = "An experimental interpreter for Rust MIR." license = "MIT/Apache-2.0" name = "miri" -repository = "https://github.com/solson/miri" +repository = "https://github.com/rust-lang/miri" version = "0.1.0" build = "build.rs" default-run = "miri" diff --git a/README.md b/README.md index 897bf0b66e7e..856e1273131a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Miri [![Build Status](https://travis-ci.org/solson/miri.svg?branch=master)](https://travis-ci.org/solson/miri) [![Windows build status](https://ci.appveyor.com/api/projects/status/github/solson/miri?svg=true)](https://ci.appveyor.com/project/solson63299/miri) +# Miri [![Build Status](https://travis-ci.com/rust-lang/miri.svg?branch=master)](https://travis-ci.com/rust-lang/miri) [![Windows build status](https://ci.appveyor.com/api/projects/status/github/rust-lang/miri?svg=true)](https://ci.appveyor.com/project/rust-lang-libs/miri) An experimental interpreter for [Rust][rust]'s @@ -28,11 +28,11 @@ Miri has already discovered some [real-world bugs](#bugs-found-by-miri). Install Miri as a cargo subcommand: ```sh -cargo +nightly install --force --git https://github.com/solson/miri miri +cargo +nightly install --force --git https://github.com/rust-lang/miri miri ``` If this does not work, try using the nightly version given in -[this file](https://raw.githubusercontent.com/solson/miri/master/rust-version). CI +[this file](https://raw.githubusercontent.com/rust-lang/miri/master/rust-version). CI should ensure that this nightly always works. You have to use a consistent Rust version for building miri and your project, so diff --git a/tests/run-pass/validation_lifetime_resolution.rs b/tests/run-pass/validation_lifetime_resolution.rs index 4d919f735255..3375632c9d70 100644 --- a/tests/run-pass/validation_lifetime_resolution.rs +++ b/tests/run-pass/validation_lifetime_resolution.rs @@ -22,7 +22,7 @@ fn foo(mut x: T) where for<'a> &'a mut T: Id let _y = x.id(); // Inspecting the trace should show that _y has a type involving a local lifetime, when it gets validated. // Unfortunately, there doesn't seem to be a way to actually have a test fail if it does not have the right - // type. Currently, this is NOT working correctly; see . + // type. Currently, this is NOT working correctly; see . } fn main() { From acc304c0bd3f5459c104be99a3270d7909988b55 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 24 Feb 2019 08:16:21 +0000 Subject: [PATCH 0585/5092] Remove test of two-phase borrows in match --- tests/run-pass/2phase.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tests/run-pass/2phase.rs b/tests/run-pass/2phase.rs index 987adca477a6..5ca0ff5d8df8 100644 --- a/tests/run-pass/2phase.rs +++ b/tests/run-pass/2phase.rs @@ -43,14 +43,6 @@ fn two_phase_overlapping2() { } */ -fn match_two_phase() { - let mut x = 3; - match x { - ref mut y if { let _val = x; let _val = *y; true } => {}, - _ => (), - } -} - fn with_interior_mutability() { use std::cell::Cell; @@ -76,7 +68,6 @@ fn main() { two_phase2(); two_phase3(false); two_phase3(true); - match_two_phase(); with_interior_mutability(); //FIXME: enable these, or remove them, depending on how https://github.com/rust-lang/rust/issues/56254 gets resolved //two_phase_overlapping1(); From 8a779bc260646f7fb16ab24a463ad977a9e05c90 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 Feb 2019 12:22:53 +0100 Subject: [PATCH 0586/5092] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index cb6d9f177dde..091e10fde3c2 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2019-02-15 +nightly-2019-02-24 From ac23bcd2980c98cf6145524f31c63320431d5d4a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 Feb 2019 09:47:34 +0100 Subject: [PATCH 0587/5092] test using the Global allocator trait to alloc/free a Box --- .../{heap_system.rs => heap_allocator.rs} | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) rename tests/run-pass/{heap_system.rs => heap_allocator.rs} (57%) diff --git a/tests/run-pass/heap_system.rs b/tests/run-pass/heap_allocator.rs similarity index 57% rename from tests/run-pass/heap_system.rs rename to tests/run-pass/heap_allocator.rs index 0eb209704713..e1aace8cecaf 100644 --- a/tests/run-pass/heap_system.rs +++ b/tests/run-pass/heap_allocator.rs @@ -1,6 +1,7 @@ //ignore-windows: Inspects allocation base address on Windows #![feature(allocator_api)] +use std::ptr::NonNull; use std::alloc::{Global, Alloc, Layout, System}; fn check_overalign_requests(mut allocator: T) { @@ -23,7 +24,31 @@ fn check_overalign_requests(mut allocator: T) { } } +fn global_to_box() { + type T = [i32; 4]; + let l = Layout::new::(); + // allocate manually with global allocator, then turn into Box and free there + unsafe { + let ptr = Global.alloc(l).unwrap().as_ptr() as *mut T; + let b = Box::from_raw(ptr); + drop(b); + } +} + +fn box_to_global() { + type T = [i32; 4]; + let l = Layout::new::(); + // allocate with the Box, then deallocate manually with global allocator + unsafe { + let b = Box::new(T::default()); + let ptr = Box::into_raw(b); + Global.dealloc(NonNull::new(ptr as *mut u8).unwrap(), l); + } +} + fn main() { check_overalign_requests(System); check_overalign_requests(Global); + global_to_box(); + box_to_global(); } From b1c0cf2ef94eec6a8e84e1a1d91fb561a1f50519 Mon Sep 17 00:00:00 2001 From: rchaser53 Date: Mon, 25 Feb 2019 00:08:38 +0900 Subject: [PATCH 0588/5092] use copy_op directly insteadof write_scalar - fix volatile_store logic - rename test to be able to read back from later - expand test to use assert_eq! and confirm to fix volatile_store - expand test to use assert_eq! and confirm normal load --- src/intrinsic.rs | 16 ++++++++++++---- tests/run-pass/volatile.rs | 12 ++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 tests/run-pass/volatile.rs diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 5a9939db2e7d..6f9dfb397167 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -50,22 +50,30 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "atomic_load" | "atomic_load_relaxed" | - "atomic_load_acq" | - "volatile_load" => { + "atomic_load_acq" => { let ptr = this.deref_operand(args[0])?; let val = this.read_scalar(ptr.into())?; // make sure it fits into a scalar; otherwise it cannot be atomic this.write_scalar(val, dest)?; } + "volatile_load" => { + let ptr = this.deref_operand(args[0])?; + this.copy_op(ptr.into(), dest)?; + } + "atomic_store" | "atomic_store_relaxed" | - "atomic_store_rel" | - "volatile_store" => { + "atomic_store_rel" => { let ptr = this.deref_operand(args[0])?; let val = this.read_scalar(args[1])?; // make sure it fits into a scalar; otherwise it cannot be atomic this.write_scalar(val, ptr.into())?; } + "volatile_store" => { + let ptr = this.deref_operand(args[0])?; + this.copy_op(args[1], ptr.into())?; + } + "atomic_fence_acq" => { // we are inherently singlethreaded and singlecored, this is a nop } diff --git a/tests/run-pass/volatile.rs b/tests/run-pass/volatile.rs new file mode 100644 index 000000000000..c9799801455c --- /dev/null +++ b/tests/run-pass/volatile.rs @@ -0,0 +1,12 @@ +// related: #58645 +#![feature(core_intrinsics)] +use std::intrinsics::{volatile_load, volatile_store}; + +pub fn main() { + unsafe { + let i: &mut (isize, isize) = &mut (0, 0); + volatile_store(i, (1, 2)); + assert_eq!(volatile_load(i), (1, 2)); + assert_eq!(i, &mut (1, 2)); + } +} From a478bfebd2aef26287268fd0c0e255184a24a7a1 Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Sat, 16 Feb 2019 01:43:56 +0000 Subject: [PATCH 0589/5092] Removed copyright notices. --- tests/compile-fail/copy_nonoverlapping.rs | 10 ---------- tests/compile-fail/copy_null.rs | 12 +----------- tests/compile-fail/copy_unaligned.rs | 10 ---------- tests/compile-fail/div-by-zero-1.rs | 10 ---------- tests/compile-fail/div-by-zero-2.rs | 10 ---------- tests/compile-fail/overflowing-lsh-neg.rs | 10 ---------- tests/compile-fail/overflowing-rsh-1.rs | 10 ---------- tests/compile-fail/overflowing-rsh-2.rs | 10 ---------- tests/compile-fail/overflowing-unchecked-rsh.rs | 10 ---------- tests/compile-fail/ptr_offset_ptr_plus_0.rs | 2 +- tests/compile-fail/reading_half_a_pointer.rs | 2 +- .../stacked_borrows/illegal_read1.rs | 2 +- .../stacked_borrows/illegal_read2.rs | 2 +- .../stacked_borrows/illegal_read3.rs | 16 +++++++++------- .../stacked_borrows/illegal_read5.rs | 2 +- .../stacked_borrows/illegal_write5.rs | 9 +++++---- tests/compile-fail/transmute-pair-undef.rs | 6 ++++-- tests/compile-fail/unaligned_ptr_cast2.rs | 9 +++++---- tests/compile-fail/unaligned_ptr_cast_zst.rs | 5 +++-- tests/compile-fail/validity/cast_fn_ptr1.rs | 5 +++-- tests/compile-fail/validity/cast_fn_ptr2.rs | 5 +++-- tests/compiletest.rs | 4 ++-- tests/run-pass/associated-const.rs | 10 ---------- tests/run-pass/atomic-access-bool.rs | 10 ---------- tests/run-pass/atomic-compare_exchange.rs | 10 ---------- tests/run-pass/binops.rs | 10 ---------- tests/run-pass/cast-rfc0401-vtable-kinds.rs | 10 ---------- tests/run-pass/deriving-associated-types.rs | 10 ---------- tests/run-pass/dst-field-align.rs | 10 ---------- tests/run-pass/dst-irrefutable-bind.rs | 10 ---------- tests/run-pass/dst-raw.rs | 10 ---------- tests/run-pass/dst-struct-sole.rs | 10 ---------- tests/run-pass/dst-struct.rs | 10 ---------- .../enum-nullable-const-null-with-fields.rs | 10 ---------- tests/run-pass/float_fast_math.rs | 10 ---------- tests/run-pass/foreign-fn-linkname.rs | 10 ---------- tests/run-pass/generator.rs | 10 ---------- tests/run-pass/issue-15063.rs | 10 ---------- tests/run-pass/issue-15080.rs | 10 ---------- tests/run-pass/issue-15523-big.rs | 10 ---------- tests/run-pass/issue-17877.rs | 10 ---------- tests/run-pass/issue-20575.rs | 10 ---------- tests/run-pass/issue-23261.rs | 10 ---------- tests/run-pass/issue-26709.rs | 10 ---------- tests/run-pass/issue-27901.rs | 10 ---------- tests/run-pass/issue-29746.rs | 10 ---------- tests/run-pass/issue-31267-additional.rs | 10 ---------- tests/run-pass/issue-33387.rs | 10 ---------- tests/run-pass/issue-34571.rs | 10 ---------- tests/run-pass/issue-35815.rs | 10 ---------- tests/run-pass/issue-36278-prefix-nesting.rs | 10 ---------- tests/run-pass/issue-3794.rs | 10 ---------- tests/run-pass/issue-5917.rs | 10 ---------- tests/run-pass/last-use-in-cap-clause.rs | 10 ---------- tests/run-pass/loop-break-value.rs | 10 ---------- tests/run-pass/mir_coercions.rs | 10 ---------- tests/run-pass/mir_fat_ptr.rs | 10 ---------- tests/run-pass/move-arg-2-unique.rs | 10 ---------- tests/run-pass/move-arg-3-unique.rs | 10 ---------- tests/run-pass/overloaded-calls-simple.rs | 10 ---------- tests/run-pass/ref-invalid-ptr.rs | 6 +++--- .../regions-lifetime-nonfree-late-bound.rs | 14 ++------------ tests/run-pass/regions-mock-trans.rs | 10 ---------- tests/run-pass/rfc1623.rs | 10 ---------- tests/run-pass/send-is-not-static-par-for.rs | 10 ---------- tests/run-pass/sendable-class.rs | 10 ---------- .../run-pass/simd-intrinsic-generic-elements.rs | 10 ---------- tests/run-pass/stacked-borrows.rs | 6 +++--- tests/run-pass/try-operator-custom.rs | 10 ---------- tests/run-pass/u128.rs | 10 ---------- tests/run-pass/union-overwrite.rs | 10 ---------- tests/run-pass/unique-send.rs | 10 ---------- tests/run-pass/unsized-tuple-impls.rs | 10 ---------- tests/run-pass/validation_lifetime_resolution.rs | 4 ++-- tests/run-pass/vec-matching-fold.rs | 10 ---------- tests/run-pass/zero-sized-binary-heap-push.rs | 10 ---------- tests/run-pass/zst.rs | 6 +++--- 77 files changed, 53 insertions(+), 644 deletions(-) diff --git a/tests/compile-fail/copy_nonoverlapping.rs b/tests/compile-fail/copy_nonoverlapping.rs index 8e8912c81fe9..748bccff5d3a 100644 --- a/tests/compile-fail/copy_nonoverlapping.rs +++ b/tests/compile-fail/copy_nonoverlapping.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(core_intrinsics)] //error-pattern: copy_nonoverlapping called on overlapping ranges diff --git a/tests/compile-fail/copy_null.rs b/tests/compile-fail/copy_null.rs index e46e327e6111..08391b12ae1b 100644 --- a/tests/compile-fail/copy_null.rs +++ b/tests/compile-fail/copy_null.rs @@ -1,18 +1,8 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //error-pattern: invalid use of NULL pointer fn main() { let mut data = [0u16; 4]; let ptr = &mut data[0] as *mut u16; - // Even copying 0 elements from NULL should error + // Even copying 0 elements from NULL should error. unsafe { ptr.copy_from(std::ptr::null(), 0); } } diff --git a/tests/compile-fail/copy_unaligned.rs b/tests/compile-fail/copy_unaligned.rs index 0f04dc68db90..e1f243210ade 100644 --- a/tests/compile-fail/copy_unaligned.rs +++ b/tests/compile-fail/copy_unaligned.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //error-pattern: tried to access memory with alignment 1, but alignment 2 is required fn main() { diff --git a/tests/compile-fail/div-by-zero-1.rs b/tests/compile-fail/div-by-zero-1.rs index 4ac6214d88ab..987c18e4c492 100644 --- a/tests/compile-fail/div-by-zero-1.rs +++ b/tests/compile-fail/div-by-zero-1.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(core_intrinsics)] use std::intrinsics::*; diff --git a/tests/compile-fail/div-by-zero-2.rs b/tests/compile-fail/div-by-zero-2.rs index 181a41ce3b23..302d26a41f36 100644 --- a/tests/compile-fail/div-by-zero-2.rs +++ b/tests/compile-fail/div-by-zero-2.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(const_err)] fn main() { diff --git a/tests/compile-fail/overflowing-lsh-neg.rs b/tests/compile-fail/overflowing-lsh-neg.rs index 8c70c9c7df7d..253294d1f53b 100644 --- a/tests/compile-fail/overflowing-lsh-neg.rs +++ b/tests/compile-fail/overflowing-lsh-neg.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(exceeding_bitshifts)] #![allow(const_err)] diff --git a/tests/compile-fail/overflowing-rsh-1.rs b/tests/compile-fail/overflowing-rsh-1.rs index 355cbd869888..7a4646a0ebf3 100644 --- a/tests/compile-fail/overflowing-rsh-1.rs +++ b/tests/compile-fail/overflowing-rsh-1.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(exceeding_bitshifts)] fn main() { diff --git a/tests/compile-fail/overflowing-rsh-2.rs b/tests/compile-fail/overflowing-rsh-2.rs index 7b7486343c33..3f7f31f4c235 100644 --- a/tests/compile-fail/overflowing-rsh-2.rs +++ b/tests/compile-fail/overflowing-rsh-2.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(exceeding_bitshifts, const_err)] fn main() { diff --git a/tests/compile-fail/overflowing-unchecked-rsh.rs b/tests/compile-fail/overflowing-unchecked-rsh.rs index b8291e1300ed..0d67aef43088 100644 --- a/tests/compile-fail/overflowing-unchecked-rsh.rs +++ b/tests/compile-fail/overflowing-unchecked-rsh.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(core_intrinsics)] use std::intrinsics::*; diff --git a/tests/compile-fail/ptr_offset_ptr_plus_0.rs b/tests/compile-fail/ptr_offset_ptr_plus_0.rs index 46937b1c8ce4..a089a8b82131 100644 --- a/tests/compile-fail/ptr_offset_ptr_plus_0.rs +++ b/tests/compile-fail/ptr_offset_ptr_plus_0.rs @@ -2,6 +2,6 @@ fn main() { let x = Box::into_raw(Box::new(0u32)); - let x = x.wrapping_offset(8); // okay, this has no inbounds tag + let x = x.wrapping_offset(8); // ok, this has no inbounds tag let _x = unsafe { x.offset(0) }; // UB despite offset 0, the pointer is not inbounds of the only object it can point to } diff --git a/tests/compile-fail/reading_half_a_pointer.rs b/tests/compile-fail/reading_half_a_pointer.rs index 049dfca340ed..f8e9e5781e39 100644 --- a/tests/compile-fail/reading_half_a_pointer.rs +++ b/tests/compile-fail/reading_half_a_pointer.rs @@ -20,7 +20,7 @@ fn main() { // Get a pointer to the beginning of the Data struct (one u8 byte, then the pointer bytes). // Thanks to the wrapper, we know this is aligned-enough to perform a load at ptr size. - // We load at pointer type, so having a relocation is okay -- but here, the relocation + // We load at pointer type, so having a relocation is ok -- but here, the relocation // starts 1 byte to the right, so using it would actually be wrong! let d_alias = &mut w.data as *mut _ as *mut *const u8; unsafe { diff --git a/tests/compile-fail/stacked_borrows/illegal_read1.rs b/tests/compile-fail/stacked_borrows/illegal_read1.rs index 0181f739a899..3fb38abefdae 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read1.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read1.rs @@ -4,7 +4,7 @@ fn main() { let mut x = 15; let xraw = &mut x as *mut _; - let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... + let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. //~^ ERROR: does not exist on the borrow stack diff --git a/tests/compile-fail/stacked_borrows/illegal_read2.rs b/tests/compile-fail/stacked_borrows/illegal_read2.rs index b55fe1c6c88a..e43340f0b8ee 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read2.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read2.rs @@ -4,7 +4,7 @@ fn main() { let mut x = 15; let xraw = &mut x as *mut _; - let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... + let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. //~^ ERROR: does not exist on the borrow stack diff --git a/tests/compile-fail/stacked_borrows/illegal_read3.rs b/tests/compile-fail/stacked_borrows/illegal_read3.rs index 9da4ca09606e..b4abbb4a1aed 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read3.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read3.rs @@ -1,8 +1,8 @@ -#![feature(untagged_unions)] -// A callee may not read the destination of our `&mut` without -// us noticing. +// A callee may not read the destination of our `&mut` without us noticing. // Thise code got carefully checked to not introduce any reborrows -// that are not explicit in the source. Let's hope the compiler does not break this later! +// that are not explicit in the source. Let's hope the compiler does not break this later! + +#![feature(untagged_unions)] use std::mem; @@ -10,14 +10,16 @@ fn main() { let mut x: i32 = 15; let xref1 = &mut x; let xref1_sneaky: usize = unsafe { mem::transmute_copy(&xref1) }; - let xref2 = &mut *xref1; // derived from xref1, so using raw is still okay... + // Derived from `xref1`, so using raw value is still ok, ... + let xref2 = &mut *xref1; callee(xref1_sneaky); - let _val = *xref2; // ...but any use of it will invalidate our ref. + // ... though any use of it will invalidate our ref. + let _val = *xref2; //~^ ERROR: does not exist on the borrow stack } fn callee(xref1: usize) { - // Transmuting through a union to avoid retagging + // Transmuting through a union to avoid retagging. union UsizeToRef { from: usize, to: &'static mut i32, diff --git a/tests/compile-fail/stacked_borrows/illegal_read5.rs b/tests/compile-fail/stacked_borrows/illegal_read5.rs index 5f800e754a5d..0f4737f16e63 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read5.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read5.rs @@ -8,7 +8,7 @@ fn main() { let rc = RefCell::new(0); let mut refmut = rc.borrow_mut(); let xref: &mut i32 = &mut *refmut; - let xshr = &rc; // creating this is okay + let xshr = &rc; // creating this is ok let _val = *xref; // we can even still use our mutable reference mem::forget(unsafe { ptr::read(xshr) }); // but after reading through the shared ref let _val = *xref; // the mutable one is dead and gone diff --git a/tests/compile-fail/stacked_borrows/illegal_write5.rs b/tests/compile-fail/stacked_borrows/illegal_write5.rs index af57221260ce..3a0738bfd0b8 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write5.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write5.rs @@ -1,12 +1,13 @@ -// A callee may not write to the destination of our `&mut` without -// us noticing. +// A callee may not write to the destination of our `&mut` without us noticing. fn main() { let mut x = 15; let xraw = &mut x as *mut _; - let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... + // Derived from raw value, so using raw value is still ok ... + let xref = unsafe { &mut *xraw }; callee(xraw); - let _val = *xref; // ...but any use of raw will invalidate our ref. + // ... though any use of raw value will invalidate our ref. + let _val = *xref; //~^ ERROR: does not exist on the borrow stack } diff --git a/tests/compile-fail/transmute-pair-undef.rs b/tests/compile-fail/transmute-pair-undef.rs index acc6098af7ee..43f1eed42d07 100644 --- a/tests/compile-fail/transmute-pair-undef.rs +++ b/tests/compile-fail/transmute-pair-undef.rs @@ -8,7 +8,8 @@ fn main() { std::mem::transmute::<(usize, bool), Option>>(z) }; let y = &x; - // Now read this bytewise. There should be (ptr_size+1) def bytes followed by (ptr_size-1) undef bytes (the padding after the bool) in there. + // Now read this bytewise. There should be (`ptr_size + 1`) def bytes followed by + // (`ptr_size - 1`) undef bytes (the padding after the bool) in there. let z : *const u8 = y as *const _ as *const _; let first_undef = mem::size_of::() as isize + 1; for i in 0..first_undef { @@ -16,5 +17,6 @@ fn main() { assert_eq!(byte, 0); } let v = unsafe { *z.offset(first_undef) }; - if v == 0 {} //~ ERROR attempted to read undefined bytes + if v == 0 {} + //~^ ERROR attempted to read undefined bytes } diff --git a/tests/compile-fail/unaligned_ptr_cast2.rs b/tests/compile-fail/unaligned_ptr_cast2.rs index 1112f2f33c14..9fb138e353fe 100644 --- a/tests/compile-fail/unaligned_ptr_cast2.rs +++ b/tests/compile-fail/unaligned_ptr_cast2.rs @@ -1,10 +1,11 @@ -// This should fail even without validation +// This should fail even without validation. // compile-flags: -Zmiri-disable-validation fn main() { let x = &2u16; let x = x as *const _ as *const *const u8; - // This must fail because alignment is violated. Test specifically for loading pointers, which have special code - // in miri's memory. - let _x = unsafe { *x }; //~ ERROR tried to access memory with alignment 2, but alignment + // This must fail because alignment is violated. Test specifically for loading pointers, + // which have special code in miri's memory. + let _x = unsafe { *x }; + //~^ ERROR tried to access memory with alignment 2, but alignment } diff --git a/tests/compile-fail/unaligned_ptr_cast_zst.rs b/tests/compile-fail/unaligned_ptr_cast_zst.rs index 1b9b55c6be1f..d52b569175c1 100644 --- a/tests/compile-fail/unaligned_ptr_cast_zst.rs +++ b/tests/compile-fail/unaligned_ptr_cast_zst.rs @@ -1,6 +1,7 @@ fn main() { let x = &2u16; let x = x as *const _ as *const [u32; 0]; - // This must fail because alignment is violated. Test specifically for loading ZST. - let _x = unsafe { *x }; //~ ERROR tried to access memory with alignment 2, but alignment 4 is required + // This must fail because alignment is violated. Test specifically for loading ZST. + let _x = unsafe { *x }; + //~^ ERROR tried to access memory with alignment 2, but alignment 4 is required } diff --git a/tests/compile-fail/validity/cast_fn_ptr1.rs b/tests/compile-fail/validity/cast_fn_ptr1.rs index 82f2d10ee4bb..d1f6e33e4598 100644 --- a/tests/compile-fail/validity/cast_fn_ptr1.rs +++ b/tests/compile-fail/validity/cast_fn_ptr1.rs @@ -1,10 +1,11 @@ fn main() { // Cast a function pointer such that on a call, the argument gets transmuted - // from raw ptr to reference. This is ABI-compatible, so it's not the call that + // from raw ptr to reference. This is ABI-compatible, so it's not the call that // should fail, but validation should. fn f(_x: &i32) { } let g: fn(*const i32) = unsafe { std::mem::transmute(f as fn(&i32)) }; - g(0usize as *const i32) //~ ERROR encountered 0, but expected something greater or equal to 1 + g(0usize as *const i32) + //~^ ERROR encountered 0, but expected something greater or equal to 1 } diff --git a/tests/compile-fail/validity/cast_fn_ptr2.rs b/tests/compile-fail/validity/cast_fn_ptr2.rs index 2f3b91a53e62..809f118c1df1 100644 --- a/tests/compile-fail/validity/cast_fn_ptr2.rs +++ b/tests/compile-fail/validity/cast_fn_ptr2.rs @@ -1,10 +1,11 @@ fn main() { // Cast a function pointer such that when returning, the return value gets transmuted - // from raw ptr to reference. This is ABI-compatible, so it's not the call that + // from raw ptr to reference. This is ABI-compatible, so it's not the call that // should fail, but validation should. fn f() -> *const i32 { 0usize as *const i32 } let g: fn() -> &'static i32 = unsafe { std::mem::transmute(f as fn() -> *const i32) }; - let _x = g(); //~ ERROR encountered 0, but expected something greater or equal to 1 + let _x = g(); + //~^ ERROR encountered 0, but expected something greater or equal to 1 } diff --git a/tests/compiletest.rs b/tests/compiletest.rs index f125100f8343..38a9d31d6e89 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -87,10 +87,10 @@ fn miri_pass(path: &str, target: &str, opt: bool) { compiletest::run_tests(&config); } -/// Make sure the MIRI_SYSROOT env var is set +/// Ensures that the `MIRI_SYSROOT` env var is set. fn set_sysroot() { if std::env::var("MIRI_SYSROOT").is_ok() { - // Nothing to do + // Nothing to do. return; } let sysroot = std::process::Command::new("rustc") diff --git a/tests/run-pass/associated-const.rs b/tests/run-pass/associated-const.rs index fe5da49f807d..2ff08ffc4bf6 100644 --- a/tests/run-pass/associated-const.rs +++ b/tests/run-pass/associated-const.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - trait Foo { const ID: i32; } diff --git a/tests/run-pass/atomic-access-bool.rs b/tests/run-pass/atomic-access-bool.rs index 8a3db796a087..68a5d7295f17 100644 --- a/tests/run-pass/atomic-access-bool.rs +++ b/tests/run-pass/atomic-access-bool.rs @@ -1,13 +1,3 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use std::sync::atomic::{AtomicBool, Ordering::*}; static mut ATOMIC: AtomicBool = AtomicBool::new(false); diff --git a/tests/run-pass/atomic-compare_exchange.rs b/tests/run-pass/atomic-compare_exchange.rs index 67280096073d..575b53fb44b0 100644 --- a/tests/run-pass/atomic-compare_exchange.rs +++ b/tests/run-pass/atomic-compare_exchange.rs @@ -1,13 +1,3 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use std::sync::atomic::{AtomicIsize, Ordering::*}; static ATOMIC: AtomicIsize = AtomicIsize::new(0); diff --git a/tests/run-pass/binops.rs b/tests/run-pass/binops.rs index a03b96fa499f..1d03c8b3d0aa 100644 --- a/tests/run-pass/binops.rs +++ b/tests/run-pass/binops.rs @@ -1,13 +1,3 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // Binop corner cases fn test_nil() { diff --git a/tests/run-pass/cast-rfc0401-vtable-kinds.rs b/tests/run-pass/cast-rfc0401-vtable-kinds.rs index ebae26996b7b..6442eab30a13 100644 --- a/tests/run-pass/cast-rfc0401-vtable-kinds.rs +++ b/tests/run-pass/cast-rfc0401-vtable-kinds.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // Check that you can cast between different pointers to trait objects // whose vtable have the same kind (both lengths, or both trait pointers). diff --git a/tests/run-pass/deriving-associated-types.rs b/tests/run-pass/deriving-associated-types.rs index b67ef85acf62..52104d8486b0 100644 --- a/tests/run-pass/deriving-associated-types.rs +++ b/tests/run-pass/deriving-associated-types.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - pub trait DeclaredTrait { type Type; } diff --git a/tests/run-pass/dst-field-align.rs b/tests/run-pass/dst-field-align.rs index 5631b65ed9d8..b8e9815640c2 100644 --- a/tests/run-pass/dst-field-align.rs +++ b/tests/run-pass/dst-field-align.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(dead_code)] struct Foo { diff --git a/tests/run-pass/dst-irrefutable-bind.rs b/tests/run-pass/dst-irrefutable-bind.rs index 9f8067f372ae..eeddfce75fd9 100644 --- a/tests/run-pass/dst-irrefutable-bind.rs +++ b/tests/run-pass/dst-irrefutable-bind.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - struct Test(T); fn main() { diff --git a/tests/run-pass/dst-raw.rs b/tests/run-pass/dst-raw.rs index 3a74626b0299..a3ee982d19aa 100644 --- a/tests/run-pass/dst-raw.rs +++ b/tests/run-pass/dst-raw.rs @@ -1,13 +1,3 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // Test DST raw pointers diff --git a/tests/run-pass/dst-struct-sole.rs b/tests/run-pass/dst-struct-sole.rs index 58d7b35a5275..770af864a44c 100644 --- a/tests/run-pass/dst-struct-sole.rs +++ b/tests/run-pass/dst-struct-sole.rs @@ -1,13 +1,3 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // As dst-struct.rs, but the unsized field is the only field in the struct. diff --git a/tests/run-pass/dst-struct.rs b/tests/run-pass/dst-struct.rs index 4c9e598e6ba3..bd6517bd1fd7 100644 --- a/tests/run-pass/dst-struct.rs +++ b/tests/run-pass/dst-struct.rs @@ -1,13 +1,3 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(box_syntax)] struct Fat { diff --git a/tests/run-pass/enum-nullable-const-null-with-fields.rs b/tests/run-pass/enum-nullable-const-null-with-fields.rs index 1342c4e104de..87389c9c3a81 100644 --- a/tests/run-pass/enum-nullable-const-null-with-fields.rs +++ b/tests/run-pass/enum-nullable-const-null-with-fields.rs @@ -1,13 +1,3 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use std::result::Result; use std::result::Result::Ok; diff --git a/tests/run-pass/float_fast_math.rs b/tests/run-pass/float_fast_math.rs index c1b4b55bd372..ba7e6ac3ec06 100644 --- a/tests/run-pass/float_fast_math.rs +++ b/tests/run-pass/float_fast_math.rs @@ -1,13 +1,3 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(core_intrinsics)] use std::intrinsics::{fadd_fast, fsub_fast, fmul_fast, fdiv_fast, frem_fast}; diff --git a/tests/run-pass/foreign-fn-linkname.rs b/tests/run-pass/foreign-fn-linkname.rs index f2ed67385cdc..ebb0e5364b94 100644 --- a/tests/run-pass/foreign-fn-linkname.rs +++ b/tests/run-pass/foreign-fn-linkname.rs @@ -1,13 +1,3 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //ignore-windows: Uses POSIX APIs #![feature(rustc_private)] diff --git a/tests/run-pass/generator.rs b/tests/run-pass/generator.rs index c9c114aaccca..477f548a7b06 100644 --- a/tests/run-pass/generator.rs +++ b/tests/run-pass/generator.rs @@ -1,13 +1,3 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(generators, generator_trait)] use std::ops::{GeneratorState, Generator}; diff --git a/tests/run-pass/issue-15063.rs b/tests/run-pass/issue-15063.rs index 726aee283e29..8ccf87ee7079 100644 --- a/tests/run-pass/issue-15063.rs +++ b/tests/run-pass/issue-15063.rs @@ -1,13 +1,3 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(dead_code)] enum Two { A, B } diff --git a/tests/run-pass/issue-15080.rs b/tests/run-pass/issue-15080.rs index b5b1edcfddd0..3ef3718d5227 100644 --- a/tests/run-pass/issue-15080.rs +++ b/tests/run-pass/issue-15080.rs @@ -1,13 +1,3 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(slice_patterns)] fn main() { diff --git a/tests/run-pass/issue-15523-big.rs b/tests/run-pass/issue-15523-big.rs index 33c81cab3817..75fd8d8dfce8 100644 --- a/tests/run-pass/issue-15523-big.rs +++ b/tests/run-pass/issue-15523-big.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // Issue 15523: derive(PartialOrd) should use the provided // discriminant values for the derived ordering. // diff --git a/tests/run-pass/issue-17877.rs b/tests/run-pass/issue-17877.rs index 91d17683e39e..caad8b27766f 100644 --- a/tests/run-pass/issue-17877.rs +++ b/tests/run-pass/issue-17877.rs @@ -1,13 +1,3 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //ignore-windows: Causes a stack overflow?!? Likely a rustc bug: https://github.com/rust-lang/rust/issues/53820 //FIXME: Once that bug is fixed, increase the size to 16*1024 and enable on all platforms. diff --git a/tests/run-pass/issue-20575.rs b/tests/run-pass/issue-20575.rs index 01371f5bec68..1443ec78fd75 100644 --- a/tests/run-pass/issue-20575.rs +++ b/tests/run-pass/issue-20575.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // Test that overloaded calls work with zero arity closures fn main() { diff --git a/tests/run-pass/issue-23261.rs b/tests/run-pass/issue-23261.rs index fc806f5429a4..3e1aa295af1e 100644 --- a/tests/run-pass/issue-23261.rs +++ b/tests/run-pass/issue-23261.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // Matching on a DST struct should not trigger an LLVM assertion. struct Foo { diff --git a/tests/run-pass/issue-26709.rs b/tests/run-pass/issue-26709.rs index e29e5fbcc408..a283d8743ccf 100644 --- a/tests/run-pass/issue-26709.rs +++ b/tests/run-pass/issue-26709.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - struct Wrapper<'a, T: ?Sized>(&'a mut i32, T); impl<'a, T: ?Sized> Drop for Wrapper<'a, T> { diff --git a/tests/run-pass/issue-27901.rs b/tests/run-pass/issue-27901.rs index b7a9daaf8abd..b0822accb6b6 100644 --- a/tests/run-pass/issue-27901.rs +++ b/tests/run-pass/issue-27901.rs @@ -1,13 +1,3 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - trait Stream { type Item; } impl<'a> Stream for &'a str { type Item = u8; } fn f<'s>(s: &'s str) -> (&'s str, <&'s str as Stream>::Item) { diff --git a/tests/run-pass/issue-29746.rs b/tests/run-pass/issue-29746.rs index 61c601ac6a90..d04703d6877c 100644 --- a/tests/run-pass/issue-29746.rs +++ b/tests/run-pass/issue-29746.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // zip!(a1,a2,a3,a4) is equivalent to: // a1.zip(a2).zip(a3).zip(a4).map(|(((x1,x2),x3),x4)| (x1,x2,x3,x4)) macro_rules! zip { diff --git a/tests/run-pass/issue-31267-additional.rs b/tests/run-pass/issue-31267-additional.rs index aaeeef8bf98b..f6d7209369b7 100644 --- a/tests/run-pass/issue-31267-additional.rs +++ b/tests/run-pass/issue-31267-additional.rs @@ -1,13 +1,3 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[derive(Clone, Copy, Debug)] struct Bar; diff --git a/tests/run-pass/issue-33387.rs b/tests/run-pass/issue-33387.rs index 62a4263c1069..2335f9c1b941 100644 --- a/tests/run-pass/issue-33387.rs +++ b/tests/run-pass/issue-33387.rs @@ -1,13 +1,3 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use std::sync::Arc; trait Foo {} diff --git a/tests/run-pass/issue-34571.rs b/tests/run-pass/issue-34571.rs index 7d8041565765..28fe076b644d 100644 --- a/tests/run-pass/issue-34571.rs +++ b/tests/run-pass/issue-34571.rs @@ -1,13 +1,3 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[repr(u8)] enum Foo { Foo(u8), diff --git a/tests/run-pass/issue-35815.rs b/tests/run-pass/issue-35815.rs index 216e06c0732c..e17c37f92a50 100644 --- a/tests/run-pass/issue-35815.rs +++ b/tests/run-pass/issue-35815.rs @@ -1,13 +1,3 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(dead_code)] use std::mem; diff --git a/tests/run-pass/issue-36278-prefix-nesting.rs b/tests/run-pass/issue-36278-prefix-nesting.rs index dc807bfde7a3..cbffbbc0e0f8 100644 --- a/tests/run-pass/issue-36278-prefix-nesting.rs +++ b/tests/run-pass/issue-36278-prefix-nesting.rs @@ -1,13 +1,3 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // Issue 36278: On an unsized struct with >1 level of nontrivial // nesting, ensure we are computing dynamic size of prefix correctly. diff --git a/tests/run-pass/issue-3794.rs b/tests/run-pass/issue-3794.rs index badb833ee800..9161fefef30c 100644 --- a/tests/run-pass/issue-3794.rs +++ b/tests/run-pass/issue-3794.rs @@ -1,13 +1,3 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(box_syntax)] trait T { diff --git a/tests/run-pass/issue-5917.rs b/tests/run-pass/issue-5917.rs index 69b95f2cd7e1..eb506dd3a17e 100644 --- a/tests/run-pass/issue-5917.rs +++ b/tests/run-pass/issue-5917.rs @@ -1,13 +1,3 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - struct T (&'static [isize]); static STATIC : T = T (&[5, 4, 3]); diff --git a/tests/run-pass/last-use-in-cap-clause.rs b/tests/run-pass/last-use-in-cap-clause.rs index de2d815ca54e..f75f00b87fd4 100644 --- a/tests/run-pass/last-use-in-cap-clause.rs +++ b/tests/run-pass/last-use-in-cap-clause.rs @@ -1,13 +1,3 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // Make sure #1399 stays fixed #[allow(dead_code)] diff --git a/tests/run-pass/loop-break-value.rs b/tests/run-pass/loop-break-value.rs index ab79a64b56e2..bd7afa7ec1a8 100644 --- a/tests/run-pass/loop-break-value.rs +++ b/tests/run-pass/loop-break-value.rs @@ -1,13 +1,3 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(never_type)] #![allow(unreachable_code)] diff --git a/tests/run-pass/mir_coercions.rs b/tests/run-pass/mir_coercions.rs index 1dab492f9da3..f3d8e519d23e 100644 --- a/tests/run-pass/mir_coercions.rs +++ b/tests/run-pass/mir_coercions.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(coerce_unsized, unsize)] use std::ops::CoerceUnsized; diff --git a/tests/run-pass/mir_fat_ptr.rs b/tests/run-pass/mir_fat_ptr.rs index e5c9e3577d1c..55418c4802a7 100644 --- a/tests/run-pass/mir_fat_ptr.rs +++ b/tests/run-pass/mir_fat_ptr.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // test that ordinary fat pointer operations work. struct Wrapper(u32, T); diff --git a/tests/run-pass/move-arg-2-unique.rs b/tests/run-pass/move-arg-2-unique.rs index 77f763888eae..b31b868bb96d 100644 --- a/tests/run-pass/move-arg-2-unique.rs +++ b/tests/run-pass/move-arg-2-unique.rs @@ -1,13 +1,3 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(box_syntax)] fn test(foo: Box> ) { assert_eq!((*foo)[0], 10); } diff --git a/tests/run-pass/move-arg-3-unique.rs b/tests/run-pass/move-arg-3-unique.rs index 0754a3f60d36..3b5c7cbbd42c 100644 --- a/tests/run-pass/move-arg-3-unique.rs +++ b/tests/run-pass/move-arg-3-unique.rs @@ -1,13 +1,3 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(box_syntax)] pub fn main() { diff --git a/tests/run-pass/overloaded-calls-simple.rs b/tests/run-pass/overloaded-calls-simple.rs index 1eeda12ca06f..12e632c251b4 100644 --- a/tests/run-pass/overloaded-calls-simple.rs +++ b/tests/run-pass/overloaded-calls-simple.rs @@ -1,13 +1,3 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(lang_items, unboxed_closures, fn_traits)] diff --git a/tests/run-pass/ref-invalid-ptr.rs b/tests/run-pass/ref-invalid-ptr.rs index 627c821a9f30..e0e7d2afefc5 100644 --- a/tests/run-pass/ref-invalid-ptr.rs +++ b/tests/run-pass/ref-invalid-ptr.rs @@ -1,12 +1,12 @@ -// FIXME validation disabled because it checks these references too eagerly +// FIXME: validation disabled because it checks these references too eagerly. // compile-flags: -Zmiri-disable-validation fn main() { let x = 2usize as *const u32; - // this is not aligned, but we immediately cast it to a raw ptr so that must be okay + // This is not aligned, but we immediately cast it to a raw ptr so that must be ok. let _y = unsafe { &*x as *const u32 }; let x = 0usize as *const u32; - // this is NULL, but we immediately cast it to a raw ptr so that must be okay + // This is NULL, but we immediately cast it to a raw ptr so that must be ok. let _y = unsafe { &*x as *const u32 }; } diff --git a/tests/run-pass/regions-lifetime-nonfree-late-bound.rs b/tests/run-pass/regions-lifetime-nonfree-late-bound.rs index dfdf89c9c1cd..85a189007c3d 100644 --- a/tests/run-pass/regions-lifetime-nonfree-late-bound.rs +++ b/tests/run-pass/regions-lifetime-nonfree-late-bound.rs @@ -1,13 +1,3 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // This is a regression test for the ICE from issue #10846. // // The original issue causing the ICE: the LUB-computations during @@ -17,10 +7,10 @@ // // However, those encounters were occurring within the lexical scope // of the binding for the late-bound lifetime; that is, the late-bound -// lifetimes were perfectly valid. The core problem was that the type +// lifetimes were perfectly valid. The core problem was that the type // folding code was over-zealously passing back all lifetimes when // doing region-folding, when really all clients of the region-folding -// case only want to see FREE lifetime variables, not bound ones. +// case only want to see *free* lifetime variables, not bound ones. #![feature(box_syntax)] diff --git a/tests/run-pass/regions-mock-trans.rs b/tests/run-pass/regions-mock-trans.rs index 62931493aa00..ac8a1c04fbe4 100644 --- a/tests/run-pass/regions-mock-trans.rs +++ b/tests/run-pass/regions-mock-trans.rs @@ -1,13 +1,3 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //ignore-windows: Uses POSIX APIs #![feature(rustc_private)] diff --git a/tests/run-pass/rfc1623.rs b/tests/run-pass/rfc1623.rs index 0ee523a5be00..2f893d8150c9 100644 --- a/tests/run-pass/rfc1623.rs +++ b/tests/run-pass/rfc1623.rs @@ -1,13 +1,3 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(dead_code)] // very simple test for a 'static static with default lifetime diff --git a/tests/run-pass/send-is-not-static-par-for.rs b/tests/run-pass/send-is-not-static-par-for.rs index 1b913aed4c89..396a87fca060 100644 --- a/tests/run-pass/send-is-not-static-par-for.rs +++ b/tests/run-pass/send-is-not-static-par-for.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use std::sync::Mutex; fn par_for(iter: I, f: F) diff --git a/tests/run-pass/sendable-class.rs b/tests/run-pass/sendable-class.rs index 3280c36e0a72..b2feb5316f87 100644 --- a/tests/run-pass/sendable-class.rs +++ b/tests/run-pass/sendable-class.rs @@ -1,13 +1,3 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // Test that a class with only sendable fields can be sent use std::sync::mpsc::channel; diff --git a/tests/run-pass/simd-intrinsic-generic-elements.rs b/tests/run-pass/simd-intrinsic-generic-elements.rs index 36567f4c0331..e8fba6707db1 100644 --- a/tests/run-pass/simd-intrinsic-generic-elements.rs +++ b/tests/run-pass/simd-intrinsic-generic-elements.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(repr_simd, platform_intrinsics)] #[repr(simd)] diff --git a/tests/run-pass/stacked-borrows.rs b/tests/run-pass/stacked-borrows.rs index 223c69a9a3ad..711026c02dfc 100644 --- a/tests/run-pass/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows.rs @@ -46,8 +46,8 @@ fn read_does_not_invalidate2() { } // Just to make sure that casting a ref to raw, to int and back to raw -// and only then using it works. This rules out ideas like "do escape-to-raw lazily": -// After casting to int and back, we lost the tag that could have let us do that. +// and only then using it works. This rules out ideas like "do escape-to-raw lazily"; +// after casting to int and back, we lost the tag that could have let us do that. fn ref_raw_int_raw() { let mut x = 3; let xref = &mut x; @@ -103,7 +103,7 @@ fn partially_invalidate_mut() { let data = &mut (0u8, 0u8); let reborrow = &mut *data as *mut (u8, u8); let shard = unsafe { &mut (*reborrow).0 }; - data.1 += 1; // the deref overlaps with `shard`, but that is okay; the access does not overlap. + data.1 += 1; // the deref overlaps with `shard`, but that is ok; the access does not overlap. *shard += 1; // so we can still use `shard`. assert_eq!(*data, (1, 1)); } diff --git a/tests/run-pass/try-operator-custom.rs b/tests/run-pass/try-operator-custom.rs index 3b447f36ece1..ccbf63796af5 100644 --- a/tests/run-pass/try-operator-custom.rs +++ b/tests/run-pass/try-operator-custom.rs @@ -1,13 +1,3 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - fn main() { assert!(Ok::(42) == Ok(42)); } diff --git a/tests/run-pass/u128.rs b/tests/run-pass/u128.rs index ca33bd5f9e3d..5a5d7c1f9442 100644 --- a/tests/run-pass/u128.rs +++ b/tests/run-pass/u128.rs @@ -1,13 +1,3 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - fn b(t: T) -> T { t } fn main() { diff --git a/tests/run-pass/union-overwrite.rs b/tests/run-pass/union-overwrite.rs index df2ff6e51a59..5c618763c0d2 100644 --- a/tests/run-pass/union-overwrite.rs +++ b/tests/run-pass/union-overwrite.rs @@ -1,13 +1,3 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(untagged_unions)] #![allow(unions_with_drop_fields)] diff --git a/tests/run-pass/unique-send.rs b/tests/run-pass/unique-send.rs index 7644da08e4af..04dbf495f8bf 100644 --- a/tests/run-pass/unique-send.rs +++ b/tests/run-pass/unique-send.rs @@ -1,13 +1,3 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(box_syntax)] use std::sync::mpsc::channel; diff --git a/tests/run-pass/unsized-tuple-impls.rs b/tests/run-pass/unsized-tuple-impls.rs index ccb6883e8733..54bd6f5c34f8 100644 --- a/tests/run-pass/unsized-tuple-impls.rs +++ b/tests/run-pass/unsized-tuple-impls.rs @@ -1,13 +1,3 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(unsized_tuple_coercion)] use std::mem; diff --git a/tests/run-pass/validation_lifetime_resolution.rs b/tests/run-pass/validation_lifetime_resolution.rs index 3375632c9d70..a0eea517095b 100644 --- a/tests/run-pass/validation_lifetime_resolution.rs +++ b/tests/run-pass/validation_lifetime_resolution.rs @@ -20,9 +20,9 @@ fn foo(mut x: T) where for<'a> &'a mut T: Id { let x = &mut x; let _y = x.id(); - // Inspecting the trace should show that _y has a type involving a local lifetime, when it gets validated. + // Inspecting the trace should show that `_y` has a type involving a local lifetime, when it gets validated. // Unfortunately, there doesn't seem to be a way to actually have a test fail if it does not have the right - // type. Currently, this is NOT working correctly; see . + // type. Currently, this is *not* working correctly; see . } fn main() { diff --git a/tests/run-pass/vec-matching-fold.rs b/tests/run-pass/vec-matching-fold.rs index 396846b23236..f953e0474705 100644 --- a/tests/run-pass/vec-matching-fold.rs +++ b/tests/run-pass/vec-matching-fold.rs @@ -1,13 +1,3 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(slice_patterns)] use std::fmt::Debug; diff --git a/tests/run-pass/zero-sized-binary-heap-push.rs b/tests/run-pass/zero-sized-binary-heap-push.rs index 63a0d65f017d..c9312d79bfda 100644 --- a/tests/run-pass/zero-sized-binary-heap-push.rs +++ b/tests/run-pass/zero-sized-binary-heap-push.rs @@ -1,13 +1,3 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use std::collections::BinaryHeap; use std::iter::Iterator; diff --git a/tests/run-pass/zst.rs b/tests/run-pass/zst.rs index c3bae4062fc2..9d97210b73db 100644 --- a/tests/run-pass/zst.rs +++ b/tests/run-pass/zst.rs @@ -18,16 +18,16 @@ fn main() { assert_eq!(zst_ret(), A); assert_eq!(use_zst(), A); let x = 42 as *mut [u8; 0]; - // reading and writing is okay + // Reading and writing is ok. unsafe { *x = zst_val; } unsafe { let _y = *x; } // We should even be able to use "true" pointers for ZST when the allocation has been - // removed already. The box is for a non-ZST to make sure there actually is an allocation. + // removed already. The box is for a non-ZST to make sure there actually is an allocation. let mut x_box = Box::new(((), 1u8)); let x = &mut x_box.0 as *mut _ as *mut [u8; 0]; drop(x_box); - // reading and writing is okay + // Reading and writing is ok. unsafe { *x = zst_val; } unsafe { let _y = *x; } } From 12d3ecbaff9e7b627e79404fa21e2a52278e1368 Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Sat, 16 Feb 2019 01:29:38 +0000 Subject: [PATCH 0590/5092] Various cosmetic improvements. --- README.md | 2 +- src/bin/cargo-miri.rs | 103 +++++---- src/bin/miri.rs | 48 ++-- src/fn_call.rs | 172 ++++++++------ src/helpers.rs | 23 +- src/intrinsic.rs | 7 +- src/lib.rs | 138 ++++++------ src/mono_hash_map.rs | 8 +- src/operator.rs | 71 +++--- src/range_map.rs | 65 +++--- src/stacked_borrows.rs | 211 ++++++++++-------- .../deallocate_against_barrier.rs | 2 +- tests/run-pass/const-vec-of-fns.rs | 10 - tests/run-pass/heap_allocator.rs | 11 +- .../too-large-primval-write-problem.rs | 2 +- 15 files changed, 468 insertions(+), 405 deletions(-) diff --git a/README.md b/README.md index 856e1273131a..c11cb46b31df 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Miri has already discovered some [real-world bugs](#bugs-found-by-miri). [`copy_nonoverlapping`]: https://doc.rust-lang.org/stable/std/ptr/fn.copy_nonoverlapping.html -## Running Miri on your own project('s test suite) +## Running Miri on your own project (and its test suite) Install Miri as a cargo subcommand: diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 0de835f45d0a..c88912c83d78 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -2,10 +2,10 @@ extern crate cargo_metadata; -use std::path::{PathBuf, Path}; -use std::io::{self, Write, BufRead}; -use std::process::Command; use std::fs::{self, File}; +use std::io::{self, Write, BufRead}; +use std::path::{PathBuf, Path}; +use std::process::Command; const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and tests in Miri @@ -55,15 +55,15 @@ fn show_error(msg: String) -> ! { std::process::exit(1) } -// Determines whether a --flag is present +// Determines whether a `--flag` is present. fn has_arg_flag(name: &str) -> bool { let mut args = std::env::args().take_while(|val| val != "--"); args.any(|val| val == name) } -/// Gets the value of a --flag +/// Gets the value of a `--flag`. fn get_arg_flag_value(name: &str) -> Option { - // stop searching at `--` + // Stop searching at `--`. let mut args = std::env::args().take_while(|val| val != "--"); loop { let arg = match args.next() { @@ -73,13 +73,15 @@ fn get_arg_flag_value(name: &str) -> Option { if !arg.starts_with(name) { continue; } - let suffix = &arg[name.len()..]; // strip leading `name` + // Strip leading `name`. + let suffix = &arg[name.len()..]; if suffix.is_empty() { - // This argument is exactly `name`, the next one is the value + // This argument is exactly `name`; the next one is the value. return args.next(); } else if suffix.starts_with('=') { - // This argument is `name=value`, get the value - return Some(suffix[1..].to_owned()); // strip leading `=` + // This argument is `name=value`; get the value. + // Strip leading `=`. + return Some(suffix[1..].to_owned()); } } } @@ -96,7 +98,7 @@ fn list_targets() -> impl Iterator { { metadata } else { - show_error(format!("error: Could not obtain cargo metadata.")); + show_error(format!("Could not obtain Cargo metadata")); }; let current_dir = std::env::current_dir(); @@ -167,20 +169,22 @@ fn ask(question: &str) { io::stdout().flush().unwrap(); io::stdin().read_line(&mut buf).unwrap(); match buf.trim().to_lowercase().as_ref() { - "" | "y" | "yes" => {}, // proceed + // Proceed. + "" | "y" | "yes" => {}, "n" | "no" => show_error(format!("Aborting as per your request")), a => show_error(format!("I do not understand `{}`", a)) }; } -/// Perform the setup requires to make `cargo miri` work: Getting a custom-built libstd. Then sets MIRI_SYSROOT. -/// Skipped if MIRI_SYSROOT is already set, in that case we expect the user has done all this already. +/// Performs the setup required to make `cargo miri` work: Getting a custom-built libstd. Then sets +/// `MIRI_SYSROOT`. Skipped if `MIRI_SYSROOT` is already set, in which case we expect the user has +/// done all this already. fn setup(ask_user: bool) { if std::env::var("MIRI_SYSROOT").is_ok() { return; } - // First, we need xargo + // First, we need xargo. let xargo = xargo_version(); if xargo.map_or(true, |v| v < (0, 3, 13)) { if ask_user { @@ -193,7 +197,7 @@ fn setup(ask_user: bool) { } } - // Then, unless XARGO_RUST_SRC is set, we also need rust-src. + // Then, unless `XARGO_RUST_SRC` is set, we also need rust-src. // Let's see if it is already installed. if std::env::var("XARGO_RUST_SRC").is_err() { let sysroot = Command::new("rustc").args(&["--print", "sysroot"]).output().unwrap().stdout; @@ -229,7 +233,7 @@ features = ["panic_unwind"] [dependencies.test] stage = 1 "#).unwrap(); - // The boring bits: A dummy project for xargo + // The boring bits: a dummy project for xargo. File::create(dir.join("Cargo.toml")).unwrap() .write_all(br#" [package] @@ -241,7 +245,7 @@ version = "0.0.0" path = "lib.rs" "#).unwrap(); File::create(dir.join("lib.rs")).unwrap(); - // Run xargo + // Run xargo. let target = get_arg_flag_value("--target"); let mut command = Command::new("xargo"); command.arg("build").arg("-q") @@ -256,7 +260,7 @@ path = "lib.rs" show_error(format!("Failed to run xargo")); } - // That should be it! But we need to figure out where xargo built stuff. + // That should be it! But we need to figure out where xargo built stuff. // Unfortunately, it puts things into a different directory when the // architecture matches the host. let is_host = match target { @@ -271,7 +275,7 @@ path = "lib.rs" } fn main() { - // Check for version and help flags even when invoked as 'cargo-miri' + // Check for version and help flags even when invoked as `cargo-miri`. if std::env::args().any(|a| a == "--help" || a == "-h") { show_help(); return; @@ -282,17 +286,16 @@ fn main() { } if let Some("miri") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { - // this arm is when `cargo miri` is called. We call `cargo rustc` for - // each applicable target, but with the RUSTC env var set to the `cargo-miri` - // binary so that we come back in the other branch, and dispatch - // the invocations to rustc and miri, respectively. + // This arm is for when `cargo miri` is called. We call `cargo rustc` for each applicable target, + // but with the `RUSTC` env var set to the `cargo-miri` binary so that we come back in the other branch, + // and dispatch the invocations to `rustc` and `miri`, respectively. in_cargo_miri(); } else if let Some("rustc") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { - // This arm is executed when cargo-miri runs `cargo rustc` with the `RUSTC_WRAPPER` env var set to itself: - // Dependencies get dispatched to rustc, the final test/binary to miri. + // This arm is executed when `cargo-miri` runs `cargo rustc` with the `RUSTC_WRAPPER` env var set to itself: + // dependencies get dispatched to `rustc`, the final test/binary to `miri`. inside_cargo_rustc(); } else { - show_error(format!("Must be called with either `miri` or `rustc` as first argument.")) + show_error(format!("must be called with either `miri` or `rustc` as first argument.")) } } @@ -301,17 +304,17 @@ fn in_cargo_miri() { Some("test") => (MiriCommand::Test, 3), Some("run") => (MiriCommand::Run, 3), Some("setup") => (MiriCommand::Setup, 3), - // Default command, if there is an option or nothing + // Default command, if there is an option or nothing. Some(s) if s.starts_with("-") => (MiriCommand::Run, 2), None => (MiriCommand::Run, 2), - // Unvalid command + // Invalid command. Some(s) => { show_error(format!("Unknown command `{}`", s)) } }; let verbose = has_arg_flag("-v"); - // We always setup + // We always setup. let ask = subcommand != MiriCommand::Setup; setup(ask); if subcommand == MiriCommand::Setup { @@ -326,16 +329,16 @@ fn in_cargo_miri() { "badly formatted cargo metadata: target::kind is an empty array", ); // Now we run `cargo rustc $FLAGS $ARGS`, giving the user the - // change to add additional flags. "FLAGS" is set to identify + // change to add additional flags. `FLAGS` is set to identify // this target. The user gets to control what gets actually passed to Miri. // However, we need to add a flag to what gets passed to rustc for the finaly // binary, so that we know to interpret that with Miri. - // So after the first "--", we add "-Zcargo-miri-marker". + // So after the first `--`, we add `-Zcargo-miri-marker`. let mut cmd = Command::new("cargo"); cmd.arg("rustc"); match (subcommand, &kind[..]) { (MiriCommand::Run, "bin") => { - // FIXME: We just run all the binaries here. + // FIXME: we just run all the binaries here. // We should instead support `cargo miri --bin foo`. cmd.arg("--bin").arg(target.name); } @@ -343,24 +346,24 @@ fn in_cargo_miri() { cmd.arg("--test").arg(target.name); } (MiriCommand::Test, "lib") => { - // There can be only one lib + // There can be only one lib. cmd.arg("--lib").arg("--profile").arg("test"); } (MiriCommand::Test, "bin") => { cmd.arg("--bin").arg(target.name).arg("--profile").arg("test"); } - // The remaining targets we do not even want to build + // The remaining targets we do not even want to build. _ => continue, } - // add user-defined args until first "--" + // Add user-defined args until first `--`. while let Some(arg) = args.next() { if arg == "--" { break; } cmd.arg(arg); } - // Add "--" (to end the cargo flags), and then the user flags. We add markers around the user flags - // to be able to identify them later. + // Add `--` (to end the `cargo` flags), and then the user flags. We add markers around the + // user flags to be able to identify them later. cmd .arg("--") .arg("cargo-miri-marker-begin") @@ -403,11 +406,11 @@ fn inside_cargo_rustc() { .and_then(|out| String::from_utf8(out.stdout).ok()) .map(|s| s.trim().to_owned()) }) - .expect("need to specify RUST_SYSROOT env var during miri compilation, or use rustup or multirust") + .expect("need to specify `RUST_SYSROOT` env var during miri compilation, or use rustup or multirust") }; - // this conditional check for the --sysroot flag is there so users can call `cargo-miri` directly - // without having to pass --sysroot or anything + // This conditional check for the `--sysroot` flag is there so that users can call `cargo-miri` + // directly without having to pass `--sysroot` or anything. let rustc_args = std::env::args().skip(2); let mut args: Vec = if std::env::args().any(|s| s == "--sysroot") { rustc_args.collect() @@ -419,25 +422,27 @@ fn inside_cargo_rustc() { }; args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string)); - // See if we can find the cargo-miri markers. Those only get added to the binary we want to - // run. They also serve to mark the user-defined arguments, which we have to move all the way to the - // end (they get added somewhere in the middle). + // See if we can find the `cargo-miri` markers. Those only get added to the binary we want to + // run. They also serve to mark the user-defined arguments, which we have to move all the way + // to the end (they get added somewhere in the middle). let needs_miri = if let Some(begin) = args.iter().position(|arg| arg == "cargo-miri-marker-begin") { - let end = args.iter().position(|arg| arg == "cargo-miri-marker-end").expect("Cannot find end marker"); - // These mark the user arguments. We remove the first and last as they are the markers. + let end = args + .iter() + .position(|arg| arg == "cargo-miri-marker-end") + .expect("cannot find end marker"); + // These mark the user arguments. We remove the first and last as they are the markers. let mut user_args = args.drain(begin..=end); assert_eq!(user_args.next().unwrap(), "cargo-miri-marker-begin"); assert_eq!(user_args.next_back().unwrap(), "cargo-miri-marker-end"); - // Collect the rest and add it back at the end + // Collect the rest and add it back at the end. let mut user_args = user_args.collect::>(); args.append(&mut user_args); - // Run this in Miri + // Run this in Miri. true } else { false }; - let mut command = if needs_miri { let mut path = std::env::current_exe().expect("current executable path invalid"); path.set_file_name("miri"); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 31bd1deb10f5..0f1501d5913b 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -1,23 +1,23 @@ #![feature(rustc_private)] +extern crate env_logger; extern crate getopts; +#[macro_use] +extern crate log; +extern crate log_settings; extern crate miri; extern crate rustc; extern crate rustc_metadata; extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_codegen_utils; -extern crate env_logger; -extern crate log_settings; extern crate syntax; -#[macro_use] -extern crate log; - use std::path::PathBuf; use std::str::FromStr; use std::env; +use miri::MiriConfig; use rustc::session::Session; use rustc_metadata::cstore::CStore; use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls}; @@ -27,8 +27,6 @@ use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc::hir::def_id::LOCAL_CRATE; use syntax::ast; -use miri::MiriConfig; - struct MiriCompilerCalls { default: Box, miri_config: MiriConfig, @@ -79,7 +77,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { odir: &Option, ofile: &Option, ) -> Compilation { - // Called *before* build_controller. Add filename to miri arguments. + // Called *before* `build_controller`. Add filename to `miri` arguments. self.miri_config.args.insert(0, input.filestem().to_string()); self.default.late_callback(codegen_backend, matches, sess, cstore, input, odir, ofile) } @@ -125,27 +123,27 @@ fn after_analysis<'a, 'tcx>( } fn init_early_loggers() { - // Notice that our `extern crate log` is NOT the same as rustc's! So we have to initialize - // them both. We always initialize miri early. + // Note that our `extern crate log` is *not* the same as rustc's; as a result, we have to + // initialize them both, and we always initialize `miri`'s first. let env = env_logger::Env::new().filter("MIRI_LOG").write_style("MIRI_LOG_STYLE"); env_logger::init_from_env(env); - // We only initialize rustc if the env var is set (so the user asked for it). + // We only initialize `rustc` if the env var is set (so the user asked for it). // If it is not set, we avoid initializing now so that we can initialize - // later with our custom settings, and NOT log anything for what happens before - // miri gets started. + // later with our custom settings, and *not* log anything for what happens before + // `miri` gets started. if env::var("RUST_LOG").is_ok() { rustc_driver::init_rustc_env_logger(); } } fn init_late_loggers() { - // Initializing loggers right before we start evaluation. We overwrite the RUST_LOG - // env var if it is not set, control it based on MIRI_LOG. + // We initialize loggers right before we start evaluation. We overwrite the `RUST_LOG` + // env var if it is not set, control it based on `MIRI_LOG`. if let Ok(var) = env::var("MIRI_LOG") { if env::var("RUST_LOG").is_err() { - // We try to be a bit clever here: If MIRI_LOG is just a single level + // We try to be a bit clever here: if `MIRI_LOG` is just a single level // used for everything, we only apply it to the parts of rustc that are - // CTFE-related. Otherwise, we use it verbatim for RUST_LOG. + // CTFE-related. Otherwise, we use it verbatim for `RUST_LOG`. // This way, if you set `MIRI_LOG=trace`, you get only the right parts of // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_mir::interpret=debug`. if log::Level::from_str(&var).is_ok() { @@ -158,7 +156,7 @@ fn init_late_loggers() { } } - // If MIRI_BACKTRACE is set and RUST_CTFE_BACKTRACE is not, set RUST_CTFE_BACKTRACE. + // If `MIRI_BACKTRACE` is set and `RUST_CTFE_BACKTRACE` is not, set `RUST_CTFE_BACKTRACE`. // Do this late, so we really only apply this to miri's errors. if let Ok(var) = env::var("MIRI_BACKTRACE") { if env::var("RUST_CTFE_BACKTRACE") == Err(env::VarError::NotPresent) { @@ -172,7 +170,7 @@ fn find_sysroot() -> String { return sysroot; } - // Taken from https://github.com/Manishearth/rust-clippy/pull/911. + // Taken from PR . let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); match (home, toolchain) { @@ -180,8 +178,8 @@ fn find_sysroot() -> String { _ => { option_env!("RUST_SYSROOT") .expect( - "Could not find sysroot. Either set MIRI_SYSROOT at run-time, or at \ - build-time specify RUST_SYSROOT env var or use rustup or multirust", + "could not find sysroot. either set `MIRI_SYSROOT` at run-time, or at \ + build-time specify `RUST_SYSROOT` env var or use rustup or multirust", ) .to_owned() } @@ -191,18 +189,18 @@ fn find_sysroot() -> String { fn main() { init_early_loggers(); - // Parse our arguments and split them across rustc and miri + // Parse our arguments and split them across `rustc` and `miri`. let mut validate = true; let mut rustc_args = vec![]; let mut miri_args = vec![]; let mut after_dashdash = false; for arg in std::env::args() { if rustc_args.is_empty() { - // Very first arg: for rustc + // Very first arg: for `rustc`. rustc_args.push(arg); } else if after_dashdash { - // Everything that comes is Miri args + // Everything that comes after are `miri` args. miri_args.push(arg); } else { match arg.as_str() { @@ -219,7 +217,7 @@ fn main() { } } - // Determine sysroot and let rustc know about it + // Determine sysroot and let rustc know about it. let sysroot_flag = String::from("--sysroot"); if !rustc_args.contains(&sysroot_flag) { rustc_args.push(sysroot_flag); diff --git a/src/fn_call.rs b/src/fn_call.rs index fa68f1d0d703..fa8c61e678be 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -7,7 +7,7 @@ use syntax::attr; use crate::*; impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} -pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { +pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { fn find_fn( &mut self, instance: ty::Instance<'tcx>, @@ -18,15 +18,15 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let this = self.eval_context_mut(); trace!("eval_fn_call: {:#?}, {:?}", instance, dest.map(|place| *place)); - // first run the common hooks also supported by CTFE + // First, run the common hooks also supported by CTFE. if this.hook_fn(instance, args, dest)? { this.goto_block(ret)?; return Ok(None); } - // there are some more lang items we want to hook that CTFE does not hook (yet) + // There are some more lang items we want to hook that CTFE does not hook (yet). if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { // FIXME: return a real value in case the target allocation has an - // alignment bigger than the one requested + // alignment bigger than the one requested. let n = u128::max_value(); let dest = dest.unwrap(); let n = this.truncate(n, dest.layout); @@ -35,20 +35,20 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, return Ok(None); } - // Try to see if we can do something about foreign items + // Try to see if we can do something about foreign items. if this.tcx.is_foreign_item(instance.def_id()) { // An external function that we cannot find MIR for, but we can still run enough // of them to make miri viable. this.emulate_foreign_item(instance.def_id(), args, dest, ret)?; - // `goto_block` already handled + // `goto_block` already handled. return Ok(None); } - // Otherwise, load the MIR + // Otherwise, load the MIR. Ok(Some(this.load_mir(instance.def)?)) } - /// Emulate calling a foreign item, fail if the item is not supported. + /// Emulates calling a foreign item, failing if the item is not supported. /// This function will handle `goto_block` if needed. fn emulate_foreign_item( &mut self, @@ -63,11 +63,11 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, Some(name) => name.as_str(), None => this.tcx.item_name(def_id).as_str(), }; - // Strip linker suffixes (seen on 32bit macOS) + // Strip linker suffixes (seen on 32-bit macOS). let link_name = link_name.trim_end_matches("$UNIX2003"); let tcx = &{this.tcx.tcx}; - // first: functions that could diverge + // First: functions that could diverge. match &link_name[..] { "__rust_start_panic" | "panic_impl" => { return err!(MachineError("the evaluated program panicked".to_string())); @@ -79,9 +79,9 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } } - // now: functions that assume a ret and dest + // Next: functions that assume a ret and dest. let dest = dest.expect("we already checked for a dest"); - let ret = ret.expect("dest is Some but ret is None"); + let ret = ret.expect("dest is `Some` but ret is `None`"); match &link_name[..] { "malloc" => { let size = this.read_scalar(args[0])?.to_usize(this)?; @@ -97,7 +97,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let ret = this.deref_operand(args[0])?; let align = this.read_scalar(args[1])?.to_usize(this)?; let size = this.read_scalar(args[2])?.to_usize(this)?; - // align must be a power of 2, and also at least ptr-sized (wtf, POSIX) + // Align must be power of 2, and also at least ptr-sized (POSIX rules). if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } @@ -209,10 +209,10 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } "syscall" => { - // TODO: read `syscall` ids like `sysconf` ids and - // figure out some way to actually process some of them + // TODO: read `syscall` IDs like `sysconf` IDs and + // figure out some way to actually process some of them. // - // libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK) + // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` // is called if a `HashMap` is created the regular way. match this.read_scalar(args[0])?.to_usize(this)? { 318 | 511 => { @@ -222,7 +222,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } id => { return err!(Unimplemented( - format!("miri does not support syscall id {}", id), + format!("miri does not support syscall ID {}", id), )) } } @@ -241,16 +241,22 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } "__rust_maybe_catch_panic" => { - // fn __rust_maybe_catch_panic(f: fn(*mut u8), data: *mut u8, data_ptr: *mut usize, vtable_ptr: *mut usize) -> u32 - // We abort on panic, so not much is going on here, but we still have to call the closure + // fn __rust_maybe_catch_panic( + // f: fn(*mut u8), + // data: *mut u8, + // data_ptr: *mut usize, + // vtable_ptr: *mut usize, + // ) -> u32 + // We abort on panic, so not much is going on here, but we still have to call the closure. let f = this.read_scalar(args[0])?.to_ptr()?; let data = this.read_scalar(args[1])?.not_undef()?; let f_instance = this.memory().get_fn(f)?; this.write_null(dest)?; trace!("__rust_maybe_catch_panic: {:?}", f_instance); - // Now we make a function call. TODO: Consider making this re-usable? EvalContext::step does sth. similar for the TLS dtors, - // and of course eval_main. + // Now we make a function call. + // TODO: consider making this reusable? `EvalContext::step` does something similar + // for the TLS destructors, and of course `eval_main`. let mir = this.load_mir(f_instance.def)?; let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); this.push_stack_frame( @@ -258,7 +264,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, mir.span, mir, Some(ret_place), - StackPopCleanup::Goto(Some(ret)), // directly return to caller + // Directly return to caller. + StackPopCleanup::Goto(Some(ret)), )?; let mut args = this.frame().mir.args_iter(); @@ -273,10 +280,10 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected"); - // We ourselves will return 0, eventually (because we will not return if we paniced) + // We ourselves will return `0`, eventually (because we will not return if we paniced). this.write_null(dest)?; - // Don't fall through, we do NOT want to `goto_block`! + // Don't fall through, we do *not* want to `goto_block`! return Ok(()); } @@ -321,10 +328,12 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let ptr = this.read_scalar(args[0])?.not_undef()?; let val = this.read_scalar(args[1])?.to_i32()? as u8; let num = this.read_scalar(args[2])?.to_usize(this)?; - if let Some(idx) = this.memory().read_bytes(ptr, Size::from_bytes(num))?.iter().position( - |&c| c == val, - ) - { + let idx = this + .memory() + .read_bytes(ptr, Size::from_bytes(num))? + .iter() + .position(|&c| c == val); + if let Some(idx) = idx { let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), this)?; this.write_scalar(new_ptr, dest)?; } else { @@ -350,7 +359,11 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let name_ptr = this.read_scalar(args[0])?.not_undef()?; if !name_ptr.is_null_ptr(this) { let name_ptr = name_ptr.to_ptr()?; - let name = this.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?.to_owned(); + let name = this + .memory() + .get(name_ptr.alloc_id)? + .read_c_str(tcx, name_ptr)? + .to_owned(); if !name.is_empty() && !name.contains(&b'=') { success = Some(this.machine.env_vars.remove(&name)); } @@ -381,7 +394,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } } if let Some((name, value)) = new { - // +1 for the null terminator + // `+1` for the null terminator. let value_copy = this.memory_mut().allocate( Size::from_bytes((value.len() + 1) as u64), Align::from_bytes(1).unwrap(), @@ -390,7 +403,10 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, { let alloc = this.memory_mut().get_mut(value_copy.alloc_id)?; alloc.write_bytes(tcx, value_copy, &value)?; - let trailing_zero_ptr = value_copy.offset(Size::from_bytes(value.len() as u64), tcx)?; + let trailing_zero_ptr = value_copy.offset( + Size::from_bytes(value.len() as u64), + tcx, + )?; alloc.write_bytes(tcx, trailing_zero_ptr, &[0])?; } if let Some(var) = this.machine.env_vars.insert( @@ -435,8 +451,10 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } } else { eprintln!("Miri: Ignored output to FD {}", fd); - n as i64 // pretend it all went well - }; // now result is the value we return back to the program + // Pretend it all went well. + n as i64 + }; + // Now, `result` is the value we return back to the program. this.write_scalar( Scalar::from_int(result, dest.layout.size), dest, @@ -449,7 +467,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; } - // Some things needed for sys::thread initialization to go through + // Some things needed for `sys::thread` initialization to go through. "signal" | "sigaction" | "sigaltstack" => { this.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?; } @@ -458,7 +476,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let name = this.read_scalar(args[0])?.to_i32()?; trace!("sysconf() called with name {}", name); - // cache the sysconf integers via miri's global cache + // Cache the sysconf integers via Miri's global cache. let paths = &[ (&["libc", "_SC_PAGESIZE"], Scalar::from_int(4096, dest.layout.size)), (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)), @@ -493,11 +511,11 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_null(dest)?; } - // Hook pthread calls that go to the thread-local storage memory subsystem + // Hook pthread calls that go to the thread-local storage memory subsystem. "pthread_key_create" => { let key_ptr = this.read_scalar(args[0])?.to_ptr()?; - // Extract the function type out of the signature (that seems easier than constructing it ourselves...) + // Extract the function type out of the signature (that seems easier than constructing it ourselves). let dtor = match this.read_scalar(args[1])?.not_undef()? { Scalar::Ptr(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr)?), Scalar::Bits { bits: 0, size } => { @@ -507,12 +525,15 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, Scalar::Bits { .. } => return err!(ReadBytesAsPointer), }; - // Figure out how large a pthread TLS key actually is. This is libc::pthread_key_t. - let key_type = args[0].layout.ty.builtin_deref(true) - .ok_or_else(|| EvalErrorKind::AbiViolation("Wrong signature used for pthread_key_create: First argument must be a raw pointer.".to_owned()))?.ty; + // Figure out how large a pthread TLS key actually is. + // This is `libc::pthread_key_t`. + let key_type = args[0].layout.ty + .builtin_deref(true) + .ok_or_else(|| EvalErrorKind::AbiViolation("wrong signature used for `pthread_key_create`: first argument must be a raw pointer.".to_owned()))? + .ty; let key_layout = this.layout_of(key_type)?; - // Create key and write it into the memory where key_ptr wants it + // Create key and write it into the memory where `key_ptr` wants it. let key = this.machine.tls.create_tls_key(dtor, tcx) as u128; if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) { return err!(OutOfTls); @@ -526,7 +547,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, key_layout.size, )?; - // Return success (0) + // Return success (`0`). this.write_null(dest)?; } "pthread_key_delete" => { @@ -545,29 +566,31 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let new_ptr = this.read_scalar(args[1])?.not_undef()?; this.machine.tls.store_tls(key, new_ptr)?; - // Return success (0) + // Return success (`0`). this.write_null(dest)?; } - // Determining stack base address + // Determine stack base address. "pthread_attr_init" | "pthread_attr_destroy" | "pthread_attr_get_np" | "pthread_getattr_np" | "pthread_self" | "pthread_get_stacksize_np" => { this.write_null(dest)?; } "pthread_attr_getstack" => { - // second argument is where we are supposed to write the stack size + // Second argument is where we are supposed to write the stack size. let ptr = this.deref_operand(args[1])?; - let stackaddr = Scalar::from_int(0x80000, args[1].layout.size); // just any address - this.write_scalar(stackaddr, ptr.into())?; - // return 0 + // Just any address. + let stack_addr = Scalar::from_int(0x80000, args[1].layout.size); + this.write_scalar(stack_addr, ptr.into())?; + // Return success (`0`). this.write_null(dest)?; } "pthread_get_stackaddr_np" => { - let stackaddr = Scalar::from_int(0x80000, dest.layout.size); // just any address - this.write_scalar(stackaddr, dest)?; + // Just any address. + let stack_addr = Scalar::from_int(0x80000, dest.layout.size); + this.write_scalar(stack_addr, dest)?; } - // Stub out calls for condvar, mutex and rwlock to just return 0 + // Stub out calls for condvar, mutex and rwlock, to just return `0`. "pthread_mutexattr_init" | "pthread_mutexattr_settype" | "pthread_mutex_init" | "pthread_mutexattr_destroy" | "pthread_mutex_lock" | "pthread_mutex_unlock" | "pthread_mutex_destroy" | "pthread_rwlock_rdlock" | "pthread_rwlock_unlock" | @@ -578,7 +601,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } "mmap" => { - // This is a horrible hack, but well... the guard page mechanism calls mmap and expects a particular return value, so we give it that value + // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. let addr = this.read_scalar(args[0])?.not_undef()?; this.write_scalar(addr, dest)?; } @@ -586,9 +609,9 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_null(dest)?; } - // macOS API stubs + // macOS API stubs. "_tlv_atexit" => { - // FIXME: Register the dtor + // FIXME: register the destructor. }, "_NSGetArgc" => { this.write_scalar(Scalar::Ptr(this.machine.argc.unwrap()), dest)?; @@ -597,7 +620,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_scalar(Scalar::Ptr(this.machine.argv.unwrap()), dest)?; }, - // Windows API stubs + // Windows API stubs. "SetLastError" => { let err = this.read_scalar(args[0])?.to_u32()?; this.machine.last_error = err; @@ -607,30 +630,30 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } "AddVectoredExceptionHandler" => { - // any non zero value works for the stdlib. This is just used for stackoverflows anyway + // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; }, "InitializeCriticalSection" | "EnterCriticalSection" | "LeaveCriticalSection" | "DeleteCriticalSection" => { - // Nothing to do, not even a return value + // Nothing to do, not even a return value. }, "GetModuleHandleW" | "GetProcAddress" | "TryEnterCriticalSection" | "GetConsoleScreenBufferInfo" | "SetConsoleTextAttribute" => { - // pretend these do not exist/nothing happened, by returning zero + // Pretend these do not exist / nothing happened, by returning zero. this.write_null(dest)?; }, "GetSystemInfo" => { let system_info = this.deref_operand(args[0])?; let system_info_ptr = system_info.ptr.to_ptr()?; - // initialize with 0 + // Initialize with `0`. this.memory_mut().get_mut(system_info_ptr.alloc_id)? .write_repeat(tcx, system_info_ptr, 0, system_info.layout.size)?; - // set number of processors to 1 + // Set number of processors to `1`. let dword_size = Size::from_bytes(4); let offset = 2*dword_size + 3*tcx.pointer_size(); this.memory_mut().get_mut(system_info_ptr.alloc_id)? @@ -643,13 +666,14 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } "TlsAlloc" => { - // This just creates a key; Windows does not natively support TLS dtors. + // This just creates a key; Windows does not natively support TLS destructors. - // Create key and return it + // Create key and return it. let key = this.machine.tls.create_tls_key(None, tcx) as u128; - // Figure out how large a TLS key actually is. This is c::DWORD. - if dest.layout.size.bits() < 128 && key >= (1u128 << dest.layout.size.bits() as u128) { + // Figure out how large a TLS key actually is. This is `c::DWORD`. + if dest.layout.size.bits() < 128 + && key >= (1u128 << dest.layout.size.bits() as u128) { return err!(OutOfTls); } this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; @@ -664,12 +688,12 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let new_ptr = this.read_scalar(args[1])?.not_undef()?; this.machine.tls.store_tls(key, new_ptr)?; - // Return success (1) + // Return success (`1`). this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; } "GetStdHandle" => { let which = this.read_scalar(args[0])?.to_i32()?; - // We just make this the identity function, so we know later in "WriteFile" + // We just make this the identity function, so we know later in `WriteFile` // which one it is. this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?; } @@ -678,7 +702,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let buf = this.read_scalar(args[1])?.not_undef()?; let n = this.read_scalar(args[2])?.to_u32()?; let written_place = this.deref_operand(args[3])?; - this.write_null(written_place.into())?; // spec says we always write 0 first + // Spec says to always write `0` first. + this.write_null(written_place.into())?; let written = if handle == -11 || handle == -12 { // stdout/stderr use std::io::{self, Write}; @@ -692,24 +717,25 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, res.ok().map(|n| n as u32) } else { eprintln!("Miri: Ignored output to handle {}", handle); - Some(n) // pretend it all went well + // Pretend it all went well. + Some(n) }; - // If there was no error, write back how much was written + // If there was no error, write back how much was written. if let Some(n) = written { this.write_scalar(Scalar::from_uint(n, Size::from_bits(32)), written_place.into())?; } - // Return whether this was a success + // Return whether this was a success. this.write_scalar( Scalar::from_int(if written.is_some() { 1 } else { 0 }, dest.layout.size), dest, )?; } "GetConsoleMode" => { - // Everything is a pipe + // Everything is a pipe. this.write_null(dest)?; } "GetEnvironmentVariableW" => { - // This is not the env var you are looking for + // This is not the env var you are looking for. this.machine.last_error = 203; // ERROR_ENVVAR_NOT_FOUND this.write_null(dest)?; } @@ -717,7 +743,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_scalar(Scalar::Ptr(this.machine.cmd_line.unwrap()), dest)?; } - // We can't execute anything else + // We can't execute anything else. _ => { return err!(Unimplemented( format!("can't call foreign function: {}", link_name), diff --git a/src/helpers.rs b/src/helpers.rs index fab0c67d0aa4..cdef224b3e99 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -6,8 +6,9 @@ use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use crate::*; impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} -pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { - /// Get an instance for a path. + +pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { + /// Gets an instance for a path. fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>> { let this = self.eval_context_ref(); this.tcx @@ -42,7 +43,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, }) } - /// Visit the memory covered by `place`, sensitive to freezing: The 3rd parameter + /// Visits the memory covered by `place`, sensitive to freezing: the 3rd parameter /// will be true if this is frozen, false if this is in an `UnsafeCell`. fn visit_freeze_sensitive( &self, @@ -57,7 +58,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, .map(|(size, _)| size) .unwrap_or_else(|| place.layout.size) ); - // Store how far we proceeded into the place so far. Everything to the left of + // Store how far we proceeded into the place so far. Everything to the left of // this offset has already been handled, in the sense that the frozen parts // have had `action` called on them. let mut end_ptr = place.ptr; @@ -139,7 +140,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, &self.ecx } - // Hook to detect `UnsafeCell` + // Hook to detect `UnsafeCell`. fn visit_value(&mut self, v: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> { trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty); @@ -159,7 +160,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } } - // Make sure we visit aggregrates in increasing offset order + // Make sure we visit aggregrates in increasing offset order. fn visit_aggregate( &mut self, place: MPlaceTy<'tcx, Borrow>, @@ -179,17 +180,17 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } layout::FieldPlacement::Union { .. } => { // Uh, what? - bug!("A union is not an aggregate we should ever visit") + bug!("a union is not an aggregate we should ever visit") } } } - // We have to do *something* for unions + // We have to do *something* for unions. fn visit_union(&mut self, v: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> { // With unions, we fall back to whatever the type says, to hopefully be consistent // with LLVM IR. - // FIXME Are we consistent? And is this really the behavior we want? + // FIXME: are we consistent, and is this really the behavior we want? let frozen = self.ecx.type_is_freeze(v.layout.ty); if frozen { Ok(()) @@ -198,10 +199,10 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } } - // We should never get to a primitive, but always short-circuit somewhere above + // We should never get to a primitive, but always short-circuit somewhere above. fn visit_primitive(&mut self, _v: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> { - bug!("We should always short-circit before coming to a primitive") + bug!("we should always short-circuit before coming to a primitive") } } } diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 6f9dfb397167..70880c4f7da8 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -1,9 +1,8 @@ use rustc::mir; +use rustc::mir::interpret::{EvalResult, PointerArithmetic}; use rustc::ty::layout::{self, LayoutOf, Size}; use rustc::ty; -use rustc::mir::interpret::{EvalResult, PointerArithmetic}; - use crate::{ PlaceTy, OpTy, ImmTy, Immediate, Scalar, ScalarMaybeUndef, Borrow, OperatorEvalContextExt @@ -268,7 +267,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // However, this only affects direct calls of the intrinsic; calls to the stable // functions wrapping them do get their validation. // FIXME: should we check that the destination pointer is aligned even for ZSTs? - if !dest.layout.is_zst() { // nothing to do for ZST + if !dest.layout.is_zst() { match dest.layout.abi { layout::Abi::Scalar(ref s) => { let x = Scalar::from_int(0, s.value.size(this)); @@ -443,7 +442,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // However, this only affects direct calls of the intrinsic; calls to the stable // functions wrapping them do get their validation. // FIXME: should we check alignment for ZSTs? - if !dest.layout.is_zst() { // nothing to do for ZST + if !dest.layout.is_zst() { match dest.layout.abi { layout::Abi::Scalar(..) => { let x = ScalarMaybeUndef::Undef; diff --git a/src/lib.rs b/src/lib.rs index 1608bc1f3028..df118ea09828 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,6 @@ #[macro_use] extern crate log; - // From rustc. extern crate syntax; #[macro_use] @@ -13,20 +12,6 @@ extern crate rustc_data_structures; extern crate rustc_mir; extern crate rustc_target; -use std::collections::HashMap; -use std::borrow::Cow; - -use rustc::ty::{self, TyCtxt, query::TyCtxtAt}; -use rustc::ty::layout::{LayoutOf, Size, Align}; -use rustc::hir::{self, def_id::DefId}; -use rustc::mir; - -use syntax::attr; -use syntax::source_map::DUMMY_SP; - -pub use rustc_mir::interpret::*; -pub use rustc_mir::interpret::{self, AllocMap, PlaceTy}; // resolve ambiguity - mod fn_call; mod operator; mod intrinsic; @@ -36,20 +21,34 @@ mod range_map; mod mono_hash_map; mod stacked_borrows; +use std::collections::HashMap; +use std::borrow::Cow; + +use rustc::ty::{self, TyCtxt, query::TyCtxtAt}; +use rustc::ty::layout::{LayoutOf, Size, Align}; +use rustc::hir::{self, def_id::DefId}; +use rustc::mir; +pub use rustc_mir::interpret::*; +// Resolve ambiguity. +pub use rustc_mir::interpret::{self, AllocMap, PlaceTy}; +use syntax::attr; +use syntax::source_map::DUMMY_SP; + pub use crate::fn_call::EvalContextExt as MissingFnsEvalContextExt; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::intrinsic::EvalContextExt as IntrinsicEvalContextExt; pub use crate::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; use crate::range_map::RangeMap; -#[allow(unused_imports)] // FIXME rustc bug https://github.com/rust-lang/rust/issues/53682 +// FIXME: rustc bug, issue . +#[allow(unused_imports)] pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; use crate::mono_hash_map::MonoHashMap; pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; -// Used by priroda +// Used by priroda. pub use crate::stacked_borrows::{Borrow, Stack, Stacks, BorStackItem}; -/// Insert rustc arguments at the beginning of the argument list that miri wants to be +/// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. pub fn miri_default_args() -> &'static [&'static str] { // The flags here should be kept in sync with what bootstrap adds when `test-miri` is @@ -57,14 +56,14 @@ pub fn miri_default_args() -> &'static [&'static str] { &["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0", "--cfg=miri"] } -/// Configuration needed to spawn a Miri instance +/// Configuration needed to spawn a Miri instance. #[derive(Clone)] pub struct MiriConfig { pub validate: bool, pub args: Vec, } -// Used by priroda +// Used by priroda. pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, @@ -105,14 +104,15 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( ))); } - // Return value (in static memory so that it does not count as leak) + // Return value (in static memory so that it does not count as leak). let ret = ecx.layout_of(start_mir.return_ty())?; let ret_ptr = ecx.allocate(ret, MiriMemoryKind::MutStatic.into()); - // Push our stack frame + // Push our stack frame. ecx.push_stack_frame( start_instance, - DUMMY_SP, // there is no call site, we want no span + // There is no call site. + DUMMY_SP, start_mir, Some(ret_ptr.into()), StackPopCleanup::None { cleanup: true }, @@ -120,26 +120,26 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let mut args = ecx.frame().mir.args_iter(); - // First argument: pointer to main() + // First argument: pointer to `main()`. let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance).with_default_tag(); let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?; - // Second argument (argc): 1 + // Second argument (argc): `1`. let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let argc = Scalar::from_uint(config.args.len() as u128, dest.layout.size); ecx.write_scalar(argc, dest)?; - // Store argc for macOS _NSGetArgc + // Store argc for macOS: `_NSGetArgc`. { let argc_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into()); ecx.write_scalar(argc, argc_place.into())?; ecx.machine.argc = Some(argc_place.ptr.to_ptr()?); } - // FIXME: extract main source file path - // Third argument (argv): Created from config.args + // FIXME: extract main source file path. + // Third argument (`argv`): created from `config.args`. let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - // For Windows, construct a command string with all the aguments + // For Windows, construct a command string with all the aguments. let mut cmd = String::new(); for arg in config.args.iter() { if !cmd.is_empty() { @@ -147,11 +147,12 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( } cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into())); } - cmd.push(std::char::from_u32(0).unwrap()); // don't forget 0 terminator + // Don't forget `0` terminator. + cmd.push(std::char::from_u32(0).unwrap()); // Collect the pointers to the individual strings. let mut argvs = Vec::>::new(); for arg in config.args { - // Add 0 terminator + // Add `0` terminator. let mut arg = arg.into_bytes(); arg.push(0); argvs.push(ecx.memory_mut().allocate_static_bytes(arg.as_slice()).with_default_tag()); @@ -164,16 +165,16 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( ecx.write_scalar(Scalar::Ptr(arg), place.into())?; } ecx.memory_mut().mark_immutable(argvs_place.to_ptr()?.alloc_id)?; - // Write a pointe to that place as the argument. + // Write a pointer to that place as the argument. let argv = argvs_place.ptr; ecx.write_scalar(argv, dest)?; - // Store argv for macOS _NSGetArgv + // Store `argv` for macOS `_NSGetArgv`. { let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into()); ecx.write_scalar(argv, argv_place.into())?; ecx.machine.argv = Some(argv_place.ptr.to_ptr()?); } - // Store cmdline as UTF-16 for Windows GetCommandLineW + // Store command line as UTF-16 for Windows `GetCommandLineW`. { let tcx = &{ecx.tcx.tcx}; let cmd_utf16: Vec = cmd.encode_utf16().collect(); @@ -183,7 +184,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( MiriMemoryKind::Env.into(), ).with_default_tag(); ecx.machine.cmd_line = Some(cmd_ptr); - // store the UTF-16 string + // Store the UTF-16 string. let char_size = Size::from_bytes(2); let cmd_alloc = ecx.memory_mut().get_mut(cmd_ptr.alloc_id)?; let mut cur_ptr = cmd_ptr; @@ -208,9 +209,9 @@ pub fn eval_main<'a, 'tcx: 'a>( main_id: DefId, config: MiriConfig, ) { - let mut ecx = create_ecx(tcx, main_id, config).expect("Couldn't create ecx"); + let mut ecx = create_ecx(tcx, main_id, config).expect("couldn't create ecx"); - // Run! The main execution. + // Perform the main execution. let res: EvalResult = (|| { ecx.run()?; ecx.run_tls_dtors() @@ -243,7 +244,7 @@ pub fn eval_main<'a, 'tcx: 'a>( let mut err = struct_error(ecx.tcx.tcx.at(span), msg.as_str()); let frames = ecx.generate_stacktrace(None); err.span_label(span, e); - // we iterate with indices because we need to look at the next frame (the caller) + // We iterate with indices because we need to look at the next frame (the caller). for idx in 0..frames.len() { let frame_info = &frames[idx]; let call_site_is_local = frames.get(idx+1).map_or(false, @@ -273,16 +274,15 @@ pub fn eval_main<'a, 'tcx: 'a>( } } - #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum MiriMemoryKind { - /// `__rust_alloc` memory + /// `__rust_alloc` memory. Rust, - /// `malloc` memory + /// `malloc` memory. C, - /// Part of env var emulation + /// Part of env var emulation. Env, - /// mutable statics + /// Mutable statics. MutStatic, } @@ -305,27 +305,27 @@ impl MayLeak for MiriMemoryKind { } pub struct Evaluator<'tcx> { - /// Environment variables set by `setenv` - /// Miri does not expose env vars from the host to the emulated program + /// Environment variables set by `setenv`. + /// Miri does not expose env vars from the host to the emulated program. pub(crate) env_vars: HashMap, Pointer>, /// Program arguments (`Option` because we can only initialize them after creating the ecx). /// These are *pointers* to argc/argv because macOS. - /// We also need the full cmdline as one string because Window. + /// We also need the full command line as one string because of Windows. pub(crate) argc: Option>, pub(crate) argv: Option>, pub(crate) cmd_line: Option>, - /// Last OS error + /// Last OS error. pub(crate) last_error: u32, - /// TLS state + /// TLS state. pub(crate) tls: TlsData<'tcx>, - /// Whether to enforce the validity invariant + /// Whether to enforce the validity invariant. pub(crate) validate: bool, - /// Stacked Borrows state + /// Stacked Borrows state. pub(crate) stacked_borrows: stacked_borrows::State, } @@ -344,10 +344,11 @@ impl<'tcx> Evaluator<'tcx> { } } -#[allow(dead_code)] // FIXME https://github.com/rust-lang/rust/issues/47131 +// FIXME: rustc issue . +#[allow(dead_code)] type MiriEvalContext<'a, 'mir, 'tcx> = EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>; -// A little trait that's useful to be inherited by extension traits +// A little trait that's useful to be inherited by extension traits. pub trait MiriEvalContextExt<'a, 'mir, 'tcx> { fn eval_context_ref(&self) -> &MiriEvalContext<'a, 'mir, 'tcx>; fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'a, 'mir, 'tcx>; @@ -380,7 +381,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { ecx.machine.validate } - /// Returns Ok() when the function was handled, fail otherwise + /// Returns `Ok()` when the function was handled; fail otherwise. #[inline(always)] fn find_fn( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, @@ -417,7 +418,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { dest: PlaceTy<'tcx, Borrow>, ) -> EvalResult<'tcx> { trace!("box_alloc for {:?}", dest.layout.ty); - // Call the `exchange_malloc` lang item + // Call the `exchange_malloc` lang item. let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap(); let malloc = ty::Instance::mono(ecx.tcx.tcx, malloc); let malloc_mir = ecx.load_mir(malloc.def)?; @@ -426,28 +427,31 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { malloc_mir.span, malloc_mir, Some(dest), - // Don't do anything when we are done. The statement() function will increment + // Don't do anything when we are done. The `statement()` function will increment // the old stack frame's stmt counter to the next statement, which means that when - // exchange_malloc returns, we go on evaluating exactly where we want to be. + // `exchange_malloc` returns, we go on evaluating exactly where we want to be. StackPopCleanup::None { cleanup: true }, )?; let mut args = ecx.frame().mir.args_iter(); let layout = ecx.layout_of(dest.layout.ty.builtin_deref(false).unwrap().ty)?; - // First argument: size - // (0 is allowed here, this is expected to be handled by the lang item) + // First argument: `size`. + // (`0` is allowed here -- this is expected to be handled by the lang item). let arg = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let size = layout.size.bytes(); ecx.write_scalar(Scalar::from_uint(size, arg.layout.size), arg)?; - // Second argument: align + // Second argument: `align`. let arg = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let align = layout.align.abi.bytes(); ecx.write_scalar(Scalar::from_uint(align, arg.layout.size), arg)?; - // No more arguments - assert!(args.next().is_none(), "exchange_malloc lang item has more arguments than expected"); + // No more arguments. + assert!( + args.next().is_none(), + "`exchange_malloc` lang item has more arguments than expected" + ); Ok(()) } @@ -464,7 +468,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { let alloc = match &link_name[..] { "__cxa_thread_atexit_impl" => { - // This should be all-zero, pointer-sized + // This should be all-zero, pointer-sized. let size = tcx.data_layout.pointer_size; let data = vec![0; size.bytes() as usize]; let extra = AllocationExtra::memory_allocated(size, memory_extra); @@ -480,7 +484,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn before_terminator(_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> { - // We are not interested in detecting loops + // We are not interested in detecting loops. Ok(()) } @@ -513,16 +517,16 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { mutability: Option, ) -> EvalResult<'tcx, Scalar> { let size = ecx.size_and_align_of_mplace(place)?.map(|(size, _)| size) - // for extern types, just cover what we can + // For extern types, just cover what we can. .unwrap_or_else(|| place.layout.size); if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !Self::enforce_validity(ecx) || size == Size::ZERO { - // No tracking + // No tracking. Ok(place.ptr) } else { ecx.ptr_dereference(place, size, mutability.into())?; - // We never change the pointer + // We never change the pointer. Ok(place.ptr) } } @@ -534,7 +538,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { kind: MemoryKind, ) -> Pointer { if !ecx.machine.validate { - // No tracking + // No tracking. ptr.with_default_tag() } else { let tag = ecx.tag_new_allocation(ptr.alloc_id, kind); diff --git a/src/mono_hash_map.rs b/src/mono_hash_map.rs index ec1a5fdb4288..f2abe4217306 100644 --- a/src/mono_hash_map.rs +++ b/src/mono_hash_map.rs @@ -1,6 +1,6 @@ -//! This is a "monotonic HashMap": A HashMap that, when shared, can be pushed to but not -//! otherwise mutated. We also Box items in the map. This means we can safely provide -//! shared references into existing items in the HashMap, because they will not be dropped +//! This is a "monotonic `HashMap`": A `HashMap` that, when shared, can be pushed to but not +//! otherwise mutated. We also box items in the map. This means we can safely provide +//! shared references into existing items in the `HashMap`, because they will not be dropped //! (from being removed) or moved (because they are boxed). //! The API is is completely tailored to what `memory.rs` needs. It is still in //! a separate file to minimize the amount of code that has to care about the unsafety. @@ -18,7 +18,7 @@ use crate::AllocMap; pub struct MonoHashMap(RefCell>>); impl MonoHashMap { - /// This function exists for priroda to be able to iterate over all evaluator memory + /// This function exists for priroda to be able to iterate over all evaluator memory. /// /// The function is somewhat roundabout with the closure argument because internally the /// `MonoHashMap` uses a `RefCell`. When iterating over the `HashMap` inside the `RefCell`, diff --git a/src/operator.rs b/src/operator.rs index b64ccf5462d6..0cba240a7d0f 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -60,7 +60,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' _ => {}, } - // Now we expect no more fat pointers + // Now we expect no more fat pointers. let left_layout = left.layout; let left = left.to_scalar()?; let right_layout = right.layout; @@ -149,9 +149,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' if left.alloc_id == right.alloc_id { left.offset == right.offset } else { - // This accepts one-past-the end. So technically there is still + // This accepts one-past-the end. Thus, there is still technically // some non-determinism that we do not fully rule out when two - // allocations sit right next to each other. The C/C++ standards are + // allocations sit right next to each other. The C/C++ standards are // somewhat fuzzy about this case, so I think for now this check is // "good enough". // Dead allocations in miri cannot overlap with live allocations, but @@ -159,17 +159,17 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // both pointers to be live. self.memory().check_bounds_ptr(left, InboundsCheck::Live)?; self.memory().check_bounds_ptr(right, InboundsCheck::Live)?; - // Two in-bounds pointers, we can compare across allocations + // Two in-bounds pointers, we can compare across allocations. left == right } } - // Comparing ptr and integer + // Comparing ptr and integer. (Scalar::Ptr(ptr), Scalar::Bits { bits, size }) | (Scalar::Bits { bits, size }, Scalar::Ptr(ptr)) => { assert_eq!(size as u64, self.pointer_size().bytes()); let bits = bits as u64; - // Case I: Comparing with NULL + // Case I: Comparing with NULL. if bits == 0 { // Test if the ptr is in-bounds. Then it cannot be NULL. // Even dangling pointers cannot be NULL. @@ -186,7 +186,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' if ptr.offset.bytes() % alloc_align.bytes() == 0 { // The offset maintains the allocation alignment, so we know `base+offset` // is aligned by `alloc_align`. - // FIXME: We could be even more general, e.g. offset 2 into a 4-aligned + // FIXME: We could be even more general, e.g., offset 2 into a 4-aligned // allocation cannot equal 3. if bits % alloc_align.bytes() != 0 { // The integer is *not* aligned. So they cannot be equal. @@ -198,7 +198,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' { // Compute the highest address at which this allocation could live. // Substract one more, because it must be possible to add the size - // to the base address without overflowing -- IOW, the very last address + // to the base address without overflowing; that is, the very last address // of the address space is never dereferencable (but it can be in-bounds, i.e., // one-past-the-end). let max_base_addr = @@ -208,7 +208,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' ) as u64; if let Some(max_addr) = max_base_addr.checked_add(ptr.offset.bytes()) { if bits > max_addr { - // The integer is too big, this cannot possibly be equal + // The integer is too big, this cannot possibly be equal. return Ok(false) } } @@ -235,7 +235,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' Ok(match bin_op { Sub => - // The only way this can overflow is by underflowing, so signdeness of the right operands does not matter + // The only way this can overflow is by underflowing, so signdeness of the right + // operands does not matter. map_to_primval(left.overflowing_signed_offset(-(right as i128), self)), Add if signed => map_to_primval(left.overflowing_signed_offset(right as i128, self)), @@ -245,17 +246,17 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' BitAnd if !signed => { let ptr_base_align = self.memory().get(left.alloc_id)?.align.bytes(); let base_mask = { - // FIXME: Use interpret::truncate, once that takes a Size instead of a Layout + // FIXME: use `interpret::truncate`, once that takes a `Size` instead of a `Layout`. let shift = 128 - self.memory().pointer_size().bits(); let value = !(ptr_base_align as u128 - 1); - // truncate (shift left to drop out leftover values, shift right to fill with zeroes) + // Truncate (shift left to drop out leftover values, shift right to fill with zeroes). (value << shift) >> shift }; let ptr_size = self.memory().pointer_size().bytes() as u8; - trace!("Ptr BitAnd, align {}, operand {:#010x}, base_mask {:#010x}", + trace!("ptr BitAnd, align {}, operand {:#010x}, base_mask {:#010x}", ptr_base_align, right, base_mask); if right & base_mask == base_mask { - // Case 1: The base address bits are all preserved, i.e., right is all-1 there + // Case 1: the base address bits are all preserved, i.e., right is all-1 there. let offset = (left.offset.bytes() as u128 & right) as u64; ( Scalar::Ptr(Pointer::new_with_tag( @@ -266,7 +267,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' false, ) } else if right & base_mask == 0 { - // Case 2: The base address bits are all taken away, i.e., right is all-0 there + // Case 2: the base address bits are all taken away, i.e., right is all-0 there. (Scalar::Bits { bits: (left.offset.bytes() as u128) & right, size: ptr_size }, false) } else { return err!(ReadPointerAsBytes); @@ -275,43 +276,57 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' Rem if !signed => { // Doing modulo a divisor of the alignment is allowed. - // (Intuition: Modulo a divisor leaks less information.) + // (Intuition: modulo a divisor leaks less information.) let ptr_base_align = self.memory().get(left.alloc_id)?.align.bytes(); let right = right as u64; let ptr_size = self.memory().pointer_size().bytes() as u8; if right == 1 { - // modulo 1 is always 0 + // Modulo 1 is always 0. (Scalar::Bits { bits: 0, size: ptr_size }, false) } else if ptr_base_align % right == 0 { - // the base address would be cancelled out by the modulo operation, so we can - // just take the modulo of the offset - (Scalar::Bits { bits: (left.offset.bytes() % right) as u128, size: ptr_size }, false) + // The base address would be cancelled out by the modulo operation, so we can + // just take the modulo of the offset. + ( + Scalar::Bits { + bits: (left.offset.bytes() % right) as u128, + size: ptr_size + }, + false, + ) } else { return err!(ReadPointerAsBytes); } } _ => { - let msg = format!("unimplemented binary op on pointer {:?}: {:?}, {:?} ({})", bin_op, left, right, if signed { "signed" } else { "unsigned" }); + let msg = format!( + "unimplemented binary op on pointer {:?}: {:?}, {:?} ({})", + bin_op, + left, + right, + if signed { "signed" } else { "unsigned" } + ); return err!(Unimplemented(msg)); } }) } - /// This function raises an error if the offset moves the pointer outside of its allocation. We consider - /// ZSTs their own huge allocation that doesn't overlap with anything (and nothing moves in there because the size is 0). - /// We also consider the NULL pointer its own separate allocation, and all the remaining integers pointers their own - /// allocation. + /// Raises an error if the offset moves the pointer outside of its allocation. + /// We consider ZSTs their own huge allocation that doesn't overlap with anything (and nothing + /// moves in there because the size is 0). We also consider the NULL pointer its own separate + /// allocation, and all the remaining integers pointers their own allocation. fn pointer_offset_inbounds( &self, ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, ) -> EvalResult<'tcx, Scalar> { - // FIXME: assuming here that type size is < i64::max_value() + // FIXME: assuming here that type size is less than `i64::max_value()`. let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; - let offset = offset.checked_mul(pointee_size).ok_or_else(|| EvalErrorKind::Overflow(mir::BinOp::Mul))?; - // Now let's see what kind of pointer this is + let offset = offset + .checked_mul(pointee_size) + .ok_or_else(|| EvalErrorKind::Overflow(mir::BinOp::Mul))?; + // Now let's see what kind of pointer this is. if let Scalar::Ptr(ptr) = ptr { // Both old and new pointer must be in-bounds of a *live* allocation. // (Of the same allocation, but that part is trivial with our representation.) diff --git a/src/range_map.rs b/src/range_map.rs index 80fc98a86965..f94917e612a8 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -3,7 +3,7 @@ //! Implements a map from integer indices to data. //! Rather than storing data for every index, internally, this maps entire ranges to the data. //! To this end, the APIs all work on ranges, not on individual integers. Ranges are split as -//! necessary (e.g. when [0,5) is first associated with X, and then [1,2) is mutated). +//! necessary (e.g., when [0,5) is first associated with X, and then [1,2) is mutated). //! Users must not depend on whether a range is coalesced or not, even though this is observable //! via the iteration APIs. @@ -14,7 +14,8 @@ use rustc::ty::layout::Size; #[derive(Clone, Debug)] struct Elem { - range: ops::Range, // the range covered by this element, never empty + /// The range covered by this element, never empty. + range: ops::Range, data: T, } #[derive(Clone, Debug)] @@ -23,7 +24,7 @@ pub struct RangeMap { } impl RangeMap { - /// Create a new RangeMap for the given size, and with the given initial value used for + /// Creates a new `RangeMap` for the given size, and with the given initial value used for /// the entire range. #[inline(always)] pub fn new(size: Size, init: T) -> RangeMap { @@ -38,9 +39,9 @@ impl RangeMap { map } - /// Find the index containing the given offset. + /// Finds the index containing the given offset. fn find_offset(&self, offset: u64) -> usize { - // We do a binary search + // We do a binary search. let mut left = 0usize; // inclusive let mut right = self.v.len(); // exclusive loop { @@ -62,22 +63,23 @@ impl RangeMap { } } - /// Provide read-only iteration over everything in the given range. This does - /// *not* split items if they overlap with the edges. Do not use this to mutate + /// Provides read-only iteration over everything in the given range. This does + /// *not* split items if they overlap with the edges. Do not use this to mutate /// through interior mutability. pub fn iter<'a>(&'a self, offset: Size, len: Size) -> impl Iterator + 'a { let offset = offset.bytes(); let len = len.bytes(); - // Compute a slice starting with the elements we care about + // Compute a slice starting with the elements we care about. let slice: &[Elem] = if len == 0 { - // We just need any empty iterator. We don't even want to + // We just need any empty iterator. We don't even want to // yield the element that surrounds this position. &[] } else { let first_idx = self.find_offset(offset); &self.v[first_idx..] }; - let end = offset + len; // the first offset that is not included any more + // The first offset that is not included any more. + let end = offset + len; slice.iter() .take_while(move |elem| elem.range.start < end) .map(|elem| &elem.data) @@ -87,25 +89,25 @@ impl RangeMap { self.v.iter_mut().map(|elem| &mut elem.data) } - // Split the element situated at the given `index`, such that the 2nd one starts at offset `split_offset`. - // Do nothing if the element already starts there. - // Return whether a split was necessary. + // Splits the element situated at the given `index`, such that the 2nd one starts at offset + // `split_offset`. Do nothing if the element already starts there. + // Returns whether a split was necessary. fn split_index(&mut self, index: usize, split_offset: u64) -> bool where T: Clone, { let elem = &mut self.v[index]; if split_offset == elem.range.start || split_offset == elem.range.end { - // Nothing to do + // Nothing to do. return false; } debug_assert!(elem.range.contains(&split_offset), - "The split_offset is not in the element to be split"); + "the `split_offset` is not in the element to be split"); - // Now we really have to split. Reduce length of first element. + // Now we really have to split. Reduce length of first element. let second_range = split_offset..elem.range.end; elem.range.end = split_offset; - // Copy the data, and insert 2nd element + // Copy the data, and insert second element. let second = Elem { range: second_range, data: elem.data.clone(), @@ -114,7 +116,7 @@ impl RangeMap { return true; } - /// Provide mutable iteration over everything in the given range. As a side-effect, + /// Provides mutable iteration over everything in the given range. As a side-effect, /// this will split entries in the map that are only partially hit by the given range, /// to make sure that when they are mutated, the effect is constrained to the given range. /// Moreover, this will opportunistically merge neighbouring equal blocks. @@ -130,7 +132,7 @@ impl RangeMap { let len = len.bytes(); // Compute a slice containing exactly the elements we care about let slice: &mut [Elem] = if len == 0 { - // We just need any empty iterator. We don't even want to + // We just need any empty iterator. We don't even want to // yield the element that surrounds this position, nor do // any splitting. &mut [] @@ -142,7 +144,7 @@ impl RangeMap { first_idx += 1; } let first_idx = first_idx; // no more mutation - // Find our end. Linear scan, but that's okay because the iteration + // Find our end. Linear scan, but that's ok because the iteration // is doing the same linear scan anyway -- no increase in complexity. // We combine this scan with a scan for duplicates that we can merge, to reduce // the number of elements. @@ -150,7 +152,7 @@ impl RangeMap { // amounts of time on the merging. let mut equal_since_idx = first_idx; // Once we see too many non-mergeable blocks, we stop. - // The initial value is chosen via... magic. Benchmarking and magic. + // The initial value is chosen via... magic. Benchmarking and magic. let mut successful_merge_count = 3usize; let mut end_idx = first_idx; // when the loop is done, this is the first excluded element. loop { @@ -162,7 +164,7 @@ impl RangeMap { // see if we want to merge everything in `equal_since..end` (exclusive at the end!) if successful_merge_count > 0 { if done || self.v[end_idx].data != self.v[equal_since_idx].data { - // Everything in `equal_since..end` was equal. Make them just one element covering + // Everything in `equal_since..end` was equal. Make them just one element covering // the entire range. let removed_elems = end_idx - equal_since_idx - 1; // number of elements that we would remove if removed_elems > 0 { @@ -173,10 +175,10 @@ impl RangeMap { self.v.splice(equal_since_idx+1..end_idx, std::iter::empty()); // Adjust `end_idx` because we made the list shorter. end_idx -= removed_elems; - // adjust the count for the cutoff + // Adjust the count for the cutoff. successful_merge_count += removed_elems; } else { - // adjust the count for the cutoff + // Adjust the count for the cutoff. successful_merge_count -= 1; } // Go on scanning for the next block starting here. @@ -188,8 +190,9 @@ impl RangeMap { break; } } - let end_idx = end_idx-1; // Move to last included instead of first excluded index. - // We need to split the end as well. Even if this performs a + // Move to last included instead of first excluded index. + let end_idx = end_idx-1; + // We need to split the end as well. Even if this performs a // split, we don't have to adjust our index as we only care about // the first part of the split. self.split_index(end_idx, offset+len); @@ -220,15 +223,15 @@ mod tests { #[test] fn basic_insert() { let mut map = RangeMap::::new(Size::from_bytes(20), -1); - // Insert + // Insert. for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(1)) { *x = 42; } - // Check + // Check. assert_eq!(to_vec(&map, 10, 1), vec![42]); assert_eq!(map.v.len(), 3); - // Insert with size 0 + // Insert with size 0. for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(0)) { *x = 19; } @@ -275,11 +278,11 @@ mod tests { to_vec(&map, 10, 10), vec![23, 42, 23, 23, 23, 19, 19, 19, 19, 19] ); - // Should be seeing two blocks with 19 + // Should be seeing two blocks with 19. assert_eq!(map.iter(Size::from_bytes(15), Size::from_bytes(2)) .map(|&t| t).collect::>(), vec![19, 19]); - // a NOP iter_mut should trigger merging + // A NOP `iter_mut` should trigger merging. for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(5)) { } assert_eq!(map.v.len(), 5); assert_eq!( diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index a52e115323c6..c9ca1c84e0f7 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -15,16 +15,15 @@ use crate::{ pub type Timestamp = u64; pub type CallId = u64; -/// Information about which kind of borrow was used to create the reference this is tagged -/// with. +/// Information about which kind of borrow was used to create the reference this is tagged with. #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum Borrow { /// A unique (mutable) reference. Uniq(Timestamp), - /// An aliasing reference. This is also used by raw pointers, which do not track details + /// An aliasing reference. This is also used by raw pointers, which do not track details /// of how or when they were created, hence the timestamp is optional. - /// Shr(Some(_)) does NOT mean that the destination of this reference is frozen; - /// that depends on the type! Only those parts outside of an `UnsafeCell` are actually + /// `Shr(Some(_))` does *not* mean that the destination of this reference is frozen; + /// that depends on the type! Only those parts outside of an `UnsafeCell` are actually /// frozen. Alias(Option), } @@ -53,23 +52,25 @@ impl Default for Borrow { } } -/// An item in the per-location borrow stack +/// An item in the per-location borrow stack. #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum BorStackItem { /// Indicates the unique reference that may mutate. Uniq(Timestamp), - /// Indicates that the location has been mutably shared. Used for raw pointers as + /// Indicates that the location has been mutably shared. Used for raw pointers as /// well as for unfrozen shared references. Raw, - /// A barrier, tracking the function it belongs to by its index on the call stack + /// A barrier, tracking the function it belongs to by its index on the call stack. FnBarrier(CallId) } -/// Extra per-location state +/// Extra per-location state. #[derive(Clone, Debug, PartialEq, Eq)] pub struct Stack { - borrows: Vec, // used as a stack; never empty - frozen_since: Option, // virtual frozen "item" on top of the stack + /// Used as the stack; never empty. + borrows: Vec, + /// A virtual frozen "item" on top of the stack. + frozen_since: Option, } impl Stack { @@ -79,18 +80,18 @@ impl Stack { } } -/// What kind of reference is being used? +/// Indicates which kind of reference is being used. #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum RefKind { - /// &mut + /// `&mut`. Unique, - /// & without interior mutability + /// `&` without interior mutability. Frozen, - /// * (raw pointer) or & to `UnsafeCell` + /// `*` (raw pointer) or `&` to `UnsafeCell`. Raw, } -/// What kind of access is being performed? +/// Indicates which kind of access is being performed. #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum AccessKind { Read, @@ -98,7 +99,7 @@ pub enum AccessKind { Dealloc, } -/// Extra global state in the memory, available to the memory access hooks +/// Extra global state in the memory, available to the memory access hooks. #[derive(Debug)] pub struct BarrierTracking { next_id: CallId, @@ -133,7 +134,7 @@ impl BarrierTracking { } } -/// Extra global machine state +/// Extra global machine state. #[derive(Clone, Debug)] pub struct State { clock: Timestamp @@ -153,7 +154,7 @@ impl State { } } -/// Extra per-allocation state +/// Extra per-allocation state. #[derive(Clone, Debug)] pub struct Stacks { // Even reading memory can have effects on the stack, so we need a `RefCell` here. @@ -164,18 +165,19 @@ pub struct Stacks { /// Core per-location operations: deref, access, create. /// We need to make at least the following things true: /// -/// U1: After creating a Uniq, it is at the top (+unfrozen). -/// U2: If the top is Uniq (+unfrozen), accesses must be through that Uniq or pop it. -/// U3: If an access (deref sufficient?) happens with a Uniq, it requires the Uniq to be in the stack. +/// U1: After creating a `Uniq`, it is at the top (and unfrozen). +/// U2: If the top is `Uniq` (and unfrozen), accesses must be through that `Uniq` or pop it. +/// U3: If an access (deref sufficient?) happens with a `Uniq`, it requires the `Uniq` to be in the stack. /// -/// F1: After creating a &, the parts outside `UnsafeCell` are frozen. +/// F1: After creating a `&`, the parts outside `UnsafeCell` are frozen. /// F2: If a write access happens, it unfreezes. -/// F3: If an access (well, a deref) happens with an & outside `UnsafeCell`, it requires the location to still be frozen. +/// F3: If an access (well, a deref) happens with an `&` outside `UnsafeCell`, +/// it requires the location to still be frozen. impl<'tcx> Stack { - /// Deref `bor`: Check if the location is frozen and the tag in the stack. - /// This dos *not* constitute an access! "Deref" refers to the `*` operator + /// Deref `bor`: check if the location is frozen and the tag in the stack. + /// This dos *not* constitute an access! "Deref" refers to the `*` operator /// in Rust, and includs cases like `&*x` or `(*x).foo` where no or only part - /// of the memory actually gets accessed. Also we cannot know if we are + /// of the memory actually gets accessed. Also we cannot know if we are /// going to read or write. /// Returns the index of the item we matched, `None` if it was the frozen one. /// `kind` indicates which kind of reference is being dereferenced. @@ -186,44 +188,46 @@ impl<'tcx> Stack { ) -> Result, String> { // Exclude unique ref with frozen tag. if let (RefKind::Unique, Borrow::Alias(Some(_))) = (kind, bor) { - return Err(format!("Encountered mutable reference with frozen tag ({:?})", bor)); + return Err(format!("encountered mutable reference with frozen tag ({:?})", bor)); } - // Checks related to freezing + // Checks related to freezing. match bor { Borrow::Alias(Some(bor_t)) if kind == RefKind::Frozen => { // We need the location to be frozen. This ensures F3. let frozen = self.frozen_since.map_or(false, |itm_t| itm_t <= bor_t); return if frozen { Ok(None) } else { - Err(format!("Location is not frozen long enough")) + Err(format!("location is not frozen long enough")) } } Borrow::Alias(_) if self.frozen_since.is_some() => { - return Ok(None) // Shared deref to frozen location, looking good + // Shared deref to frozen location; looking good. + return Ok(None) } - _ => {} // Not sufficient, go on looking. + // Not sufficient; go on looking. + _ => {} } // If we got here, we have to look for our item in the stack. for (idx, &itm) in self.borrows.iter().enumerate().rev() { match (itm, bor) { (BorStackItem::Uniq(itm_t), Borrow::Uniq(bor_t)) if itm_t == bor_t => { - // Found matching unique item. This satisfies U3. + // Found matching unique item. This satisfies U3. return Ok(Some(idx)) } (BorStackItem::Raw, Borrow::Alias(_)) => { // Found matching aliasing/raw item. return Ok(Some(idx)) } - // Go on looking. We ignore barriers! When an `&mut` and an `&` alias, + // Go on looking. We ignore barriers! When an `&mut` and an `&` alias, // dereferencing the `&` is still possible (to reborrow), but doing // an access is not. _ => {} } } - // If we got here, we did not find our item. We have to error to satisfy U3. + // If we got here, we did not find our item. We have to error to satisfy U3. Err(format!("Borrow being dereferenced ({:?}) does not exist on the borrow stack", bor)) } - /// Perform an actual memory access using `bor`. We do not know any types here + /// Performs an actual memory access using `bor`. We do not know any types here /// or whether things should be frozen, but we *do* know if this is reading /// or writing. fn access( @@ -236,45 +240,44 @@ impl<'tcx> Stack { // Not possible on writes! if self.is_frozen() { if kind == AccessKind::Read { - // When we are frozen, we just accept all reads. No harm in this. + // When we are frozen, we just accept all reads. No harm in this. // The deref already checked that `Uniq` items are in the stack, and that // the location is frozen if it should be. return Ok(()); } - trace!("access: Unfreezing"); + trace!("access: unfreezing"); } - // Unfreeze on writes. This ensures F2. + // Unfreeze on writes. This ensures F2. self.frozen_since = None; // Pop the stack until we have something matching. while let Some(&itm) = self.borrows.last() { match (itm, bor) { (BorStackItem::FnBarrier(call), _) if barrier_tracking.is_active(call) => { return err!(MachineError(format!( - "Stopping looking for borrow being accessed ({:?}) because of barrier ({})", + "stopping looking for borrow being accessed ({:?}) because of barrier ({})", bor, call ))) } (BorStackItem::Uniq(itm_t), Borrow::Uniq(bor_t)) if itm_t == bor_t => { - // Found matching unique item. Continue after the match. + // Found matching unique item. Continue after the match. } (BorStackItem::Raw, _) if kind == AccessKind::Read => { // When reading, everything can use a raw item! // We do not want to do this when writing: Writing to an `&mut` // should reaffirm its exclusivity (i.e., make sure it is - // on top of the stack). - // Continue after the match. + // on top of the stack). Continue after the match. } (BorStackItem::Raw, Borrow::Alias(_)) => { - // Found matching raw item. Continue after the match. + // Found matching raw item. Continue after the match. } _ => { - // Pop this, go on. This ensures U2. + // Pop this, go on. This ensures U2. let itm = self.borrows.pop().unwrap(); trace!("access: Popping {:?}", itm); continue } } - // If we got here, we found a matching item. Congratulations! + // If we got here, we found a matching item. Congratulations! // However, we are not done yet: If this access is deallocating, we must make sure // there are no active barriers remaining on the stack. if kind == AccessKind::Dealloc { @@ -282,19 +285,19 @@ impl<'tcx> Stack { match itm { BorStackItem::FnBarrier(call) if barrier_tracking.is_active(call) => { return err!(MachineError(format!( - "Deallocating with active barrier ({})", call + "deallocating with active barrier ({})", call ))) } _ => {}, } } } - // NOW we are done. + // Now we are done. return Ok(()) } // If we got here, we did not find our item. err!(MachineError(format!( - "Borrow being accessed ({:?}) does not exist on the borrow stack", + "borrow being accessed ({:?}) does not exist on the borrow stack", bor ))) } @@ -304,7 +307,7 @@ impl<'tcx> Stack { /// is met: We cannot push `Uniq` onto frozen stacks. /// `kind` indicates which kind of reference is being created. fn create(&mut self, bor: Borrow, kind: RefKind) { - // When creating a frozen reference, freeze. This ensures F1. + // When creating a frozen reference, freeze. This ensures F1. // We also do *not* push anything else to the stack, making sure that no nother kind // of access (like writing through raw pointers) is permitted. if kind == RefKind::Frozen { @@ -312,10 +315,13 @@ impl<'tcx> Stack { Borrow::Alias(Some(t)) => t, _ => bug!("Creating illegal borrow {:?} for frozen ref", bor), }; - // It is possible that we already are frozen (e.g. if we just pushed a barrier, + // It is possible that we already are frozen (e.g., if we just pushed a barrier, // the redundancy check would not have kicked in). match self.frozen_since { - Some(loc_t) => assert!(loc_t <= bor_t, "Trying to freeze location for longer than it was already frozen"), + Some(loc_t) => assert!( + loc_t <= bor_t, + "trying to freeze location for longer than it was already frozen" + ), None => { trace!("create: Freezing"); self.frozen_since = Some(bor_t); @@ -323,7 +329,10 @@ impl<'tcx> Stack { } return; } - assert!(self.frozen_since.is_none(), "Trying to create non-frozen reference to frozen location"); + assert!( + self.frozen_since.is_none(), + "trying to create non-frozen reference to frozen location" + ); // Push new item to the stack. let itm = match bor { @@ -334,15 +343,15 @@ impl<'tcx> Stack { // This is just an optimization, no functional change: Avoid stacking // multiple `Shr` on top of each other. assert!(bor.is_aliasing()); - trace!("create: Sharing a shared location is a NOP"); + trace!("create: sharing a shared location is a NOP"); } else { // This ensures U1. - trace!("create: Pushing {:?}", itm); + trace!("create: pushing {:?}", itm); self.borrows.push(itm); } } - /// Add a barrier + /// Adds a barrier. fn barrier(&mut self, call: CallId) { let itm = BorStackItem::FnBarrier(call); if *self.borrows.last().unwrap() == itm { @@ -350,9 +359,9 @@ impl<'tcx> Stack { // multiple identical barriers on top of each other. // This can happen when a function receives several shared references // that overlap. - trace!("barrier: Avoiding redundant extra barrier"); + trace!("barrier: avoiding redundant extra barrier"); } else { - trace!("barrier: Pushing barrier for call {}", call); + trace!("barrier: pushing barrier for call {}", call); self.borrows.push(itm); } } @@ -360,7 +369,7 @@ impl<'tcx> Stack { /// Higher-level per-location operations: deref, access, reborrow. impl<'tcx> Stacks { - /// Check that this stack is fine with being dereferenced + /// Checks that this stack is fine with being dereferenced. fn deref( &self, ptr: Pointer, @@ -406,14 +415,15 @@ impl<'tcx> Stacks { new_kind: RefKind, ) -> EvalResult<'tcx> { assert_eq!(new_bor.is_unique(), new_kind == RefKind::Unique); - trace!("reborrow for tag {:?} to {:?} as {:?}: {:?}, size {}", - ptr.tag, new_bor, new_kind, ptr, size.bytes()); + trace!( + "reborrow for tag {:?} to {:?} as {:?}: {:?}, size {}", + ptr.tag, new_bor, new_kind, ptr, size.bytes(), + ); if new_kind == RefKind::Raw { - // No barrier for raw, including `&UnsafeCell`. They can rightfully - // alias with `&mut`. - // FIXME: This means that the `dereferencable` attribute on non-frozen shared - // references is incorrect! They are dereferencable when the function is - // called, but might become non-dereferencable during the course of execution. + // No barrier for raw, including `&UnsafeCell`. They can rightfully alias with `&mut`. + // FIXME: This means that the `dereferencable` attribute on non-frozen shared references + // is incorrect! They are dereferencable when the function is called, but might become + // non-dereferencable during the course of execution. // Also see [1], [2]. // // [1]: Stacks { let ptr_idx = stack.deref(ptr.tag, new_kind).map_err(EvalErrorKind::MachineError)?; // If we can deref the new tag already, and if that tag lives higher on // the stack than the one we come from, just use that. - // IOW, we check if `new_bor` *already* is "derived from" `ptr.tag`. + // That is, we check if `new_bor` *already* is "derived from" `ptr.tag`. // This also checks frozenness, if required. let bor_redundant = barrier.is_none() && match (ptr_idx, stack.deref(new_bor, new_kind)) { @@ -436,11 +446,11 @@ impl<'tcx> Stacks { // above the old one in the stack, our job here is done. (_, Ok(None)) => true, (Some(ptr_idx), Ok(Some(new_idx))) if new_idx >= ptr_idx => true, - // Otherwise we need to create a new borrow. + // Otherwise, we need to create a new borrow. _ => false, }; if bor_redundant { - assert!(new_bor.is_aliasing(), "A unique reborrow can never be redundant"); + assert!(new_bor.is_aliasing(), "a unique reborrow can never be redundant"); trace!("reborrow is redundant"); continue; } @@ -460,7 +470,7 @@ impl<'tcx> Stacks { } } -/// Hooks and glue +/// Hooks and glue. impl AllocationExtra for Stacks { #[inline(always)] fn memory_allocated<'tcx>(size: Size, extra: &MemoryState) -> Self { @@ -529,10 +539,10 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let this = self.eval_context_mut(); let ptr = place.ptr.to_ptr()?; let barrier = if fn_barrier { Some(this.frame().extra) } else { None }; - trace!("reborrow: Creating new reference for {:?} (pointee {}): {:?}", + trace!("reborrow: creating new reference for {:?} (pointee {}): {:?}", ptr, place.layout.ty, new_bor); - // Get the allocation. It might not be mutable, so we cannot use `get_mut`. + // Get the allocation. It might not be mutable, so we cannot use `get_mut`. let alloc = this.memory().get(ptr.alloc_id)?; alloc.check_bounds(this, ptr, size)?; // Update the stacks. @@ -550,7 +560,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, Ok(()) } - /// Retag an indidual pointer, returning the retagged version. + /// Retags an indidual pointer, returning the retagged version. /// `mutbl` can be `None` to make this a raw pointer. fn retag_reference( &mut self, @@ -587,10 +597,10 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // We immediately share it, to allow read accesses let two_phase_time = this.machine.stacked_borrows.increment_clock(); let two_phase_bor = Borrow::Alias(Some(two_phase_time)); - this.reborrow(new_place, size, /*fn_barrier*/false, two_phase_bor)?; + this.reborrow(new_place, size, false /* fn_barrier */, two_phase_bor)?; } - // Return new ptr. + // Return new pointer. Ok(new_place.to_ref()) } } @@ -607,29 +617,32 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, MemoryKind::Stack => { // New unique borrow. This `Uniq` is not accessible by the program, // so it will only ever be used when using the local directly (i.e., - // not through a pointer). IOW, whenever we directly use a local this will pop - // everything else off the stack, invalidating all previous pointers - // and, in particular, *all* raw pointers. This subsumes the explicit + // not through a pointer). That is, whenever we directly use a local, this will pop + // everything else off the stack, invalidating all previous pointers, + // and in particular, *all* raw pointers. This subsumes the explicit // `reset` which the blog post [1] says to perform when accessing a local. // - // [1] https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html + // [1]: this.machine.stacked_borrows.increment_clock() } _ => { - // Nothing to do for everything else + // Nothing to do for everything else. return Borrow::default() } }; - // Make this the active borrow for this allocation - let alloc = this.memory_mut().get_mut(id).expect("This is a new allocation, it must still exist"); + // Make this the active borrow for this allocation. + let alloc = this + .memory_mut() + .get_mut(id) + .expect("this is a new allocation; it must still exist"); let size = Size::from_bytes(alloc.bytes.len() as u64); alloc.extra.first_item(BorStackItem::Uniq(time), size); Borrow::Uniq(time) } - /// Called for value-to-place conversion. `mutability` is `None` for raw pointers. + /// Called for value-to-place conversion. `mutability` is `None` for raw pointers. /// - /// Note that this does NOT mean that all this memory will actually get accessed/referenced! + /// Note that this does *not* mean that all this memory will actually get accessed/referenced! /// We could be in the middle of `&(*var).1`. fn ptr_dereference( &self, @@ -638,9 +651,15 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, mutability: Option, ) -> EvalResult<'tcx> { let this = self.eval_context_ref(); - trace!("ptr_dereference: Accessing {} reference for {:?} (pointee {})", - if let Some(mutability) = mutability { format!("{:?}", mutability) } else { format!("raw") }, - place.ptr, place.layout.ty); + trace!( + "ptr_dereference: Accessing {} reference for {:?} (pointee {})", + if let Some(mutability) = mutability { + format!("{:?}", mutability) + } else { + format!("raw") + }, + place.ptr, place.layout.ty + ); let ptr = place.ptr.to_ptr()?; if mutability.is_none() { // No further checks on raw derefs -- only the access itself will be checked. @@ -653,18 +672,18 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // If we got here, we do some checking, *but* we leave the tag unchanged. if let Borrow::Alias(Some(_)) = ptr.tag { assert_eq!(mutability, Some(MutImmutable)); - // We need a frozen-sensitive check + // We need a frozen-sensitive check. this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; alloc.extra.deref(cur_ptr, size, kind) })?; } else { - // Just treat this as one big chunk + // Just treat this as one big chunk. let kind = if mutability == Some(MutMutable) { RefKind::Unique } else { RefKind::Raw }; alloc.extra.deref(ptr, size, kind)?; } - // All is good + // All is good. Ok(()) } @@ -679,22 +698,22 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // making it useless. fn qualify(ty: ty::Ty<'_>, kind: RetagKind) -> Option<(Option, bool)> { match ty.sty { - // References are simple + // References are simple. ty::Ref(_, _, mutbl) => Some((Some(mutbl), kind == RetagKind::FnEntry)), - // Raw pointers need to be enabled + // Raw pointers need to be enabled. ty::RawPtr(..) if kind == RetagKind::Raw => Some((None, false)), - // Boxes do not get a barrier: Barriers reflect that references outlive the call + // Boxes do not get a barrier: barriers reflect that references outlive the call // they were passed in to; that's just not the case for boxes. ty::Adt(..) if ty.is_box() => Some((Some(MutMutable), false)), _ => None, } } - // We need a visitor to visit all references. However, that requires + // We need a visitor to visit all references. However, that requires // a `MemPlace`, so we have a fast path for reference types that // avoids allocating. if let Some((mutbl, barrier)) = qualify(place.layout.ty, kind) { - // fast path + // Fast path. let val = this.read_immediate(this.place_to_op(place)?)?; let val = this.retag_reference(val, mutbl, barrier, kind == RetagKind::TwoPhase)?; this.write_immediate(val, place)?; @@ -705,7 +724,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let mut visitor = RetagVisitor { ecx: this, kind }; visitor.visit_value(place)?; - // The actual visitor + // The actual visitor. struct RetagVisitor<'ecx, 'a, 'mir, 'tcx> { ecx: &'ecx mut MiriEvalContext<'a, 'mir, 'tcx>, kind: RetagKind, diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs b/tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs index eb988a589959..b2f1c824f1b4 100644 --- a/tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs +++ b/tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs @@ -1,4 +1,4 @@ -// error-pattern: Deallocating with active barrier +// error-pattern: deallocating with active barrier fn inner(x: &mut i32, f: fn(&mut i32)) { // `f` may mutate, but it may not deallocate! diff --git a/tests/run-pass/const-vec-of-fns.rs b/tests/run-pass/const-vec-of-fns.rs index e100ad5f4692..9b6c6fcc32ef 100644 --- a/tests/run-pass/const-vec-of-fns.rs +++ b/tests/run-pass/const-vec-of-fns.rs @@ -1,13 +1,3 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - /*! * Try to double-check that static fns have the right size (with or * without dummy env ptr, as appropriate) by iterating a size-2 array. diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index e1aace8cecaf..bfed725a497c 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -1,4 +1,5 @@ -//ignore-windows: Inspects allocation base address on Windows +//ignore-windows: inspects allocation base address on Windows + #![feature(allocator_api)] use std::ptr::NonNull; @@ -6,8 +7,10 @@ use std::alloc::{Global, Alloc, Layout, System}; fn check_overalign_requests(mut allocator: T) { let size = 8; - let align = 16; // greater than size - let iterations = 1; // Miri is deterministic, no need to try many times + // Greater than `size`. + let align = 16; + // Miri is deterministic; no need to try many times. + let iterations = 1; unsafe { let pointers: Vec<_> = (0..iterations).map(|_| { allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap() @@ -17,7 +20,7 @@ fn check_overalign_requests(mut allocator: T) { "Got a pointer less aligned than requested") } - // Clean up + // Clean up. for &ptr in &pointers { allocator.dealloc(ptr, Layout::from_size_align(size, align).unwrap()) } diff --git a/tests/run-pass/too-large-primval-write-problem.rs b/tests/run-pass/too-large-primval-write-problem.rs index 1bbe45277c43..ebd6dbb61ee4 100644 --- a/tests/run-pass/too-large-primval-write-problem.rs +++ b/tests/run-pass/too-large-primval-write-problem.rs @@ -1,4 +1,4 @@ -// PrimVals in Miri are represented with 8 bytes (u64) and at the time of writing, the `-x` +// `PrimVal`s in Miri are represented with 8 bytes (u64) and at the time of writing, the `-x` // will sign extend into the entire 8 bytes. Then, if you tried to write the `-x` into // something smaller than 8 bytes, like a 4 byte pointer, it would crash in byteorder crate // code that assumed only the low 4 bytes would be set. Actually, we were masking properly for From 205490b85c5024006e89c6443a1ba6f21bda4b89 Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Tue, 26 Feb 2019 18:37:05 +0000 Subject: [PATCH 0591/5092] Fixed nits raised in review. --- src/bin/miri.rs | 2 +- src/lib.rs | 5 ++--- src/range_map.rs | 7 ++++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 0f1501d5913b..c1cad6edc0ab 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -178,7 +178,7 @@ fn find_sysroot() -> String { _ => { option_env!("RUST_SYSROOT") .expect( - "could not find sysroot. either set `MIRI_SYSROOT` at run-time, or at \ + "could not find sysroot. Either set `MIRI_SYSROOT` at run-time, or at \ build-time specify `RUST_SYSROOT` env var or use rustup or multirust", ) .to_owned() diff --git a/src/lib.rs b/src/lib.rs index df118ea09828..31a02a7466e3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,8 +39,7 @@ pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::intrinsic::EvalContextExt as IntrinsicEvalContextExt; pub use crate::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; use crate::range_map::RangeMap; -// FIXME: rustc bug, issue . -#[allow(unused_imports)] +#[allow(unused_imports)] // FIXME: rustc bug, issue . pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; use crate::mono_hash_map::MonoHashMap; pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; @@ -129,7 +128,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let argc = Scalar::from_uint(config.args.len() as u128, dest.layout.size); ecx.write_scalar(argc, dest)?; - // Store argc for macOS: `_NSGetArgc`. + // Store argc for macOS's `_NSGetArgc`. { let argc_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into()); ecx.write_scalar(argc, argc_place.into())?; diff --git a/src/range_map.rs b/src/range_map.rs index f94917e612a8..16e7e2724179 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -14,8 +14,9 @@ use rustc::ty::layout::Size; #[derive(Clone, Debug)] struct Elem { - /// The range covered by this element, never empty. + /// The range covered by this element; never empty. range: ops::Range, + /// The data stored for this element. data: T, } #[derive(Clone, Debug)] @@ -49,11 +50,11 @@ impl RangeMap { let candidate = left.checked_add(right).unwrap() / 2; let elem = &self.v[candidate]; if offset < elem.range.start { - // we are too far right (offset is further left) + // We are too far right (offset is further left). debug_assert!(candidate < right); // we are making progress right = candidate; } else if offset >= elem.range.end { - // we are too far left (offset is further right) + // We are too far left (offset is further right). debug_assert!(candidate >= left); // we are making progress left = candidate+1; } else { From a9b03f94110a7ab9a8185acd06eed5aa56e0c56d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 27 Feb 2019 11:38:43 +0100 Subject: [PATCH 0592/5092] avoid [..] --- src/bin/cargo-miri.rs | 4 ++-- src/fn_call.rs | 8 ++++---- src/helpers.rs | 2 +- src/intrinsic.rs | 2 +- src/lib.rs | 8 ++++---- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index c88912c83d78..0c90e8ade0d2 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -201,7 +201,7 @@ fn setup(ask_user: bool) { // Let's see if it is already installed. if std::env::var("XARGO_RUST_SRC").is_err() { let sysroot = Command::new("rustc").args(&["--print", "sysroot"]).output().unwrap().stdout; - let sysroot = std::str::from_utf8(&sysroot[..]).unwrap(); + let sysroot = std::str::from_utf8(&sysroot).unwrap(); let src = Path::new(sysroot.trim_end_matches('\n')).join("lib").join("rustlib").join("src"); if !src.exists() { if ask_user { @@ -336,7 +336,7 @@ fn in_cargo_miri() { // So after the first `--`, we add `-Zcargo-miri-marker`. let mut cmd = Command::new("cargo"); cmd.arg("rustc"); - match (subcommand, &kind[..]) { + match (subcommand, kind.as_str()) { (MiriCommand::Run, "bin") => { // FIXME: we just run all the binaries here. // We should instead support `cargo miri --bin foo`. diff --git a/src/fn_call.rs b/src/fn_call.rs index fa8c61e678be..ce07b04c29c3 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -60,15 +60,15 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { - Some(name) => name.as_str(), - None => this.tcx.item_name(def_id).as_str(), + Some(name) => name.as_str().get(), + None => this.tcx.item_name(def_id).as_str().get(), }; // Strip linker suffixes (seen on 32-bit macOS). let link_name = link_name.trim_end_matches("$UNIX2003"); let tcx = &{this.tcx.tcx}; // First: functions that could diverge. - match &link_name[..] { + match link_name { "__rust_start_panic" | "panic_impl" => { return err!(MachineError("the evaluated program panicked".to_string())); } @@ -82,7 +82,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' // Next: functions that assume a ret and dest. let dest = dest.expect("we already checked for a dest"); let ret = ret.expect("dest is `Some` but ret is `None`"); - match &link_name[..] { + match link_name { "malloc" => { let size = this.read_scalar(args[0])?.to_usize(this)?; if size == 0 { diff --git a/src/helpers.rs b/src/helpers.rs index cdef224b3e99..2e4c955413ab 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -175,7 +175,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' layout::FieldPlacement::Arbitrary { .. } => { // Gather the subplaces and sort them before visiting. let mut places = fields.collect::>>>()?; - places[..].sort_by_key(|place| place.ptr.get_ptr_offset(self.ecx())); + places.sort_by_key(|place| place.ptr.get_ptr_offset(self.ecx())); self.walk_aggregate(place, places.into_iter().map(Ok)) } layout::FieldPlacement::Union { .. } => { diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 70880c4f7da8..5b0f0e99ad84 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -27,7 +27,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // (as opposed to through a place), we have to remember to erase any tag // that might still hang around! - let intrinsic_name = &this.tcx.item_name(instance.def_id()).as_str()[..]; + let intrinsic_name = this.tcx.item_name(instance.def_id()).as_str().get(); match intrinsic_name { "arith_offset" => { let offset = this.read_scalar(args[1])?.to_isize(this)?; diff --git a/src/lib.rs b/src/lib.rs index 31a02a7466e3..8fc3efd7c23b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -461,17 +461,17 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> { let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { - Some(name) => name.as_str(), - None => tcx.item_name(def_id).as_str(), + Some(name) => name.as_str().get(), + None => tcx.item_name(def_id).as_str().get(), }; - let alloc = match &link_name[..] { + let alloc = match link_name { "__cxa_thread_atexit_impl" => { // This should be all-zero, pointer-sized. let size = tcx.data_layout.pointer_size; let data = vec![0; size.bytes() as usize]; let extra = AllocationExtra::memory_allocated(size, memory_extra); - Allocation::from_bytes(&data[..], tcx.data_layout.pointer_align.abi, extra) + Allocation::from_bytes(&data, tcx.data_layout.pointer_align.abi, extra) } _ => return err!(Unimplemented( format!("can't access foreign static: {}", link_name), From 6265f6658ee56e5493339249f6b1f6a83bee865e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Mar 2019 09:16:14 +0100 Subject: [PATCH 0593/5092] the stable part of compiletest_rs is enough --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 1a1a1fa2330a..a68c04092f66 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,5 +54,5 @@ cargo_miri = ["cargo_metadata", "directories", "rustc_version"] rustc_tests = [] [dev-dependencies] -compiletest_rs = { version = "0.3.17", features = ["tmp"] } +compiletest_rs = { version = "0.3.17", features = ["tmp", "stable"] } colored = "1.6" From 0bb6ae8f62d3239a1c666c566693dfedc8652ad3 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 26 Feb 2019 14:58:13 -0300 Subject: [PATCH 0594/5092] Place::Local(x) is now Place::Base(PlaceBase::Local(x)) --- src/fn_call.rs | 2 +- src/lib.rs | 10 +++++----- src/tls.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index ce07b04c29c3..b496a9b7d41d 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -275,7 +275,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' .to_owned(), ), )?; - let arg_dest = this.eval_place(&mir::Place::Local(arg_local))?; + let arg_dest = this.eval_place(&mir::Place::Base(mir::PlaceBase::Local(arg_local)))?; this.write_scalar(data, arg_dest)?; assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected"); diff --git a/src/lib.rs b/src/lib.rs index 8fc3efd7c23b..cf6a885c605c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -121,11 +121,11 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // First argument: pointer to `main()`. let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance).with_default_tag(); - let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; + let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?; // Second argument (argc): `1`. - let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; + let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; let argc = Scalar::from_uint(config.args.len() as u128, dest.layout.size); ecx.write_scalar(argc, dest)?; // Store argc for macOS's `_NSGetArgc`. @@ -137,7 +137,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // FIXME: extract main source file path. // Third argument (`argv`): created from `config.args`. - let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; + let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; // For Windows, construct a command string with all the aguments. let mut cmd = String::new(); for arg in config.args.iter() { @@ -437,12 +437,12 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { // First argument: `size`. // (`0` is allowed here -- this is expected to be handled by the lang item). - let arg = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; + let arg = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; let size = layout.size.bytes(); ecx.write_scalar(Scalar::from_uint(size, arg.layout.size), arg)?; // Second argument: `align`. - let arg = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; + let arg = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; let align = layout.align.abi.bytes(); ecx.write_scalar(Scalar::from_uint(align, arg.layout.size), arg)?; diff --git a/src/tls.rs b/src/tls.rs index 5411e021619c..796c2e5f9827 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -151,7 +151,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let arg_local = this.frame().mir.args_iter().next().ok_or_else( || EvalErrorKind::AbiViolation("TLS dtor does not take enough arguments.".to_owned()), )?; - let dest = this.eval_place(&mir::Place::Local(arg_local))?; + let dest = this.eval_place(&mir::Place::Base(mir::PlaceBase::Local(arg_local)))?; this.write_scalar(ptr, dest)?; // step until out of stackframes From 355135bb895c16e9011d6b83ad13663de47d2c64 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Mar 2019 09:01:03 +0100 Subject: [PATCH 0595/5092] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 091e10fde3c2..bf8995fe8a3e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2019-02-24 +nightly-2019-03-02 From 2ef399979b5801efb64c68b57ccb34007ad9b012 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Mar 2019 10:50:31 +0100 Subject: [PATCH 0596/5092] README --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c11cb46b31df..aef74d6a5fe6 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,9 @@ for example: or an invalid enum discriminant) * WIP: Violations of the rules governing aliasing for reference types -Miri has already discovered some [real-world bugs](#bugs-found-by-miri). +Miri has already discovered some [real-world bugs](#bugs-found-by-miri). If you +found a bug with Miri, we'd appreciate if you tell us and we'll add it to the +list! [rust]: https://www.rust-lang.org/ [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md @@ -50,6 +52,11 @@ Now you can run your project in Miri: 3. If you have a binary project, you can run it through Miri using `cargo +nightly miri run`. +The first time you run Miri, it will perform some extra setup and install some +dependencies. It will ask you for confirmation before installing anything. If +you run Miri on CI, run `cargo +nightly miri setup` to avoid getting interactive +questions. + You can pass arguments to Miri after the first `--`, and pass arguments to the interpreted program or test suite after the second `--`. For example, `cargo +nightly miri run -- -Zmiri-disable-validation` runs the program without From 8c74325441c3d571f0439a772f9287ac94975f54 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 Mar 2019 17:53:30 +0100 Subject: [PATCH 0597/5092] mention --exclude-should-panic --- README.md | 4 ++-- src/bin/cargo-miri.rs | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index aef74d6a5fe6..184e37a894a9 100644 --- a/README.md +++ b/README.md @@ -61,8 +61,8 @@ You can pass arguments to Miri after the first `--`, and pass arguments to the interpreted program or test suite after the second `--`. For example, `cargo +nightly miri run -- -Zmiri-disable-validation` runs the program without validation of basic type invariants and references. `cargo +nightly miri test --- -- filter` passes `filter` to the test suite the same way `cargo test filter` -would. +-- -- -Zunstable-options --exclude-should-panic` skips `#[should_panic]` tests, +which is a good idea because Miri does not support unwinding or catching panics. When running code via `cargo miri`, the `miri` config flag is set. You can use this to exclude test cases that will fail under Miri because they do things diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 0c90e8ade0d2..50570554f450 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -329,11 +329,8 @@ fn in_cargo_miri() { "badly formatted cargo metadata: target::kind is an empty array", ); // Now we run `cargo rustc $FLAGS $ARGS`, giving the user the - // change to add additional flags. `FLAGS` is set to identify + // change to add additional arguments. `FLAGS` is set to identify // this target. The user gets to control what gets actually passed to Miri. - // However, we need to add a flag to what gets passed to rustc for the finaly - // binary, so that we know to interpret that with Miri. - // So after the first `--`, we add `-Zcargo-miri-marker`. let mut cmd = Command::new("cargo"); cmd.arg("rustc"); match (subcommand, kind.as_str()) { @@ -363,7 +360,8 @@ fn in_cargo_miri() { cmd.arg(arg); } // Add `--` (to end the `cargo` flags), and then the user flags. We add markers around the - // user flags to be able to identify them later. + // user flags to be able to identify them later. "cargo rustc" adds more stuff after this, + // so we have to mark both the beginning and the end. cmd .arg("--") .arg("cargo-miri-marker-begin") From 7d142ecf75cc347213502311253cd41f5d87dfaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 1 Feb 2019 23:26:42 +0100 Subject: [PATCH 0598/5092] Use the new rustc interface --- benches/helpers/miri_helper.rs | 58 +++++++------- src/bin/miri-rustc-tests.rs | 128 ++++++++++-------------------- src/bin/miri.rs | 138 ++++++++------------------------- 3 files changed, 105 insertions(+), 219 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 404fe7ae9150..3e3c3a53f754 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -2,18 +2,39 @@ extern crate getopts; extern crate miri; extern crate rustc; extern crate rustc_driver; +extern crate rustc_interface; extern crate test; -use rustc_driver::{driver, Compilation}; +use self::miri::eval_main; use rustc::hir::def_id::LOCAL_CRATE; -use std::cell::RefCell; -use std::rc::Rc; - -use miri::{MiriConfig, eval_main}; - +use rustc_interface::interface; use crate::test::Bencher; -pub struct MiriCompilerCalls<'a>(Rc>); +struct MiriCompilerCalls<'a> { + bencher: &'a mut Bencher, +} + +impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { + fn after_analysis(&mut self, compiler: &interface::Compiler<'_>) -> bool { + compiler.session().abort_if_errors(); + + compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| { + let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect( + "no main or start function found", + ); + + self.bencher.iter(|| { + let config = MiriConfig { validate: true, args: vec![] }; + eval_main(tcx, entry_def_id, config); + }); + }); + + compiler.session().abort_if_errors(); + + // Don't continue execution + false + } +} fn find_sysroot() -> String { // Taken from https://github.com/Manishearth/rust-clippy/pull/911. @@ -38,26 +59,5 @@ pub fn run(filename: &str, bencher: &mut Bencher) { "--sysroot".to_string(), find_sysroot(), ]; - let bencher = RefCell::new(bencher); - - let mut control = driver::CompileController::basic(); - - control.after_analysis.stop = Compilation::Stop; - control.after_analysis.callback = Box::new(move |state| { - state.session.abort_if_errors(); - - let tcx = state.tcx.unwrap(); - let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect( - "no main or start function found", - ); - - bencher.borrow_mut().iter(|| { - let config = MiriConfig { validate: true, args: vec![] }; - eval_main(tcx, entry_def_id, config); - }); - - state.session.abort_if_errors(); - }); - - rustc_driver::run_compiler(args, Box::new(control), None, None); + rustc_driver::run_compiler(args, &mut MiriCompilerCalls { bencher }, None, None); } diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 3a70577cb7f2..cab8d845fc0d 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -6,6 +6,7 @@ extern crate rustc_metadata; extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_codegen_utils; +extern crate rustc_interface; extern crate syntax; use std::path::{PathBuf, Path}; @@ -15,12 +16,10 @@ use std::io; use rustc::session::Session; +use rustc_interface::interface; use rustc_metadata::cstore::CStore; -use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls}; -use rustc_driver::driver::{CompileState, CompileController}; use rustc::session::config::{self, Input, ErrorOutputType}; use rustc::hir::{self, itemlikevisit}; -use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc::ty::TyCtxt; use syntax::ast; use rustc::hir::def_id::LOCAL_CRATE; @@ -28,93 +27,55 @@ use rustc::hir::def_id::LOCAL_CRATE; use miri::MiriConfig; struct MiriCompilerCalls { - default: Box, /// whether we are building for the host host_target: bool, } -impl<'a> CompilerCalls<'a> for MiriCompilerCalls { - fn early_callback( - &mut self, - matches: &getopts::Matches, - sopts: &config::Options, - cfg: &ast::CrateConfig, - descriptions: &rustc_errors::registry::Registry, - output: ErrorOutputType - ) -> Compilation { - self.default.early_callback(matches, sopts, cfg, descriptions, output) - } - fn no_input( - &mut self, - matches: &getopts::Matches, - sopts: &config::Options, - cfg: &ast::CrateConfig, - odir: &Option, - ofile: &Option, - descriptions: &rustc_errors::registry::Registry - ) -> Option<(Input, Option)> { - self.default.no_input(matches, sopts, cfg, odir, ofile, descriptions) - } - fn late_callback( - &mut self, - trans: &CodegenBackend, - matches: &getopts::Matches, - sess: &Session, - cstore: &CStore, - input: &Input, - odir: &Option, - ofile: &Option, - ) -> Compilation { - self.default.late_callback(trans, matches, sess, cstore, input, odir, ofile) - } - fn build_controller(self: Box, sess: &Session, matches: &getopts::Matches) -> CompileController<'a> { - let this = *self; - let mut control = this.default.build_controller(sess, matches); - control.after_hir_lowering.callback = Box::new(after_hir_lowering); - control.after_analysis.callback = Box::new(after_analysis); - if !this.host_target { - // only fully compile targets on the host - control.after_analysis.stop = Compilation::Stop; - } - control - } -} +impl rustc_driver::Callbacks for MiriCompilerCalls { + fn after_parsing(&mut self, compiler: &interface::Compiler<'_>) -> bool { + let attr = ( + String::from("miri"), + syntax::feature_gate::AttributeType::Whitelisted, + ); + compiler.session().plugin_attributes.borrow_mut().push(attr); -fn after_hir_lowering(state: &mut CompileState) { - let attr = (String::from("miri"), syntax::feature_gate::AttributeType::Whitelisted); - state.session.plugin_attributes.borrow_mut().push(attr); -} + // Continue execution + true + } -fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { - state.session.abort_if_errors(); - - let tcx = state.tcx.unwrap(); - - if std::env::args().any(|arg| arg == "--test") { - struct Visitor<'a, 'tcx: 'a>(TyCtxt<'a, 'tcx, 'tcx>, &'a CompileState<'a, 'tcx>); - impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> { - fn visit_item(&mut self, i: &'hir hir::Item) { - if let hir::ItemKind::Fn(.., body_id) = i.node { - if i.attrs.iter().any(|attr| attr.name() == "test") { - let config = MiriConfig { validate: true, args: vec![] }; - let did = self.0.hir().body_owner_def_id(body_id); - println!("running test: {}", self.0.def_path_debug_str(did)); - miri::eval_main(self.0, did, config); - self.1.session.abort_if_errors(); + fn after_analysis(&mut self, compiler: &interface::Compiler<'_>) -> bool { + compiler.session().abort_if_errors(); + compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| { + if std::env::args().any(|arg| arg == "--test") { + struct Visitor<'a, 'tcx: 'a>(TyCtxt<'a, 'tcx, 'tcx>); + impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> { + fn visit_item(&mut self, i: &'hir hir::Item) { + if let hir::ItemKind::Fn(.., body_id) = i.node { + if i.attrs.iter().any(|attr| attr.name() == "test") { + let config = MiriConfig { validate: true, args: vec![] }; + let did = self.0.hir().body_owner_def_id(body_id); + println!("running test: {}", self.0.def_path_debug_str(did)); + miri::eval_main(self.0, did, config); + self.0.sess.abort_if_errors(); + } + } } + fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {} + fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {} } - } - fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {} - fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {} - } - state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(tcx, state)); - } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { - let config = MiriConfig { validate: true, args: vec![] }; - miri::eval_main(tcx, entry_def_id, config); + tcx.hir().krate().visit_all_item_likes(&mut Visitor(tcx)); + } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { + let config = MiriConfig { validate: true, args: vec![] }; + miri::eval_main(tcx, entry_def_id, config); - state.session.abort_if_errors(); - } else { - println!("no main function found, assuming auxiliary build"); + compiler.session().abort_if_errors(); + } else { + println!("no main function found, assuming auxiliary build"); + } + }); + + // Continue execution on host target + self.host_target } } @@ -185,10 +146,7 @@ fn main() { let buf = BufWriter::default(); let output = buf.clone(); let result = std::panic::catch_unwind(|| { - rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls { - default: Box::new(RustcDefaultCalls), - host_target, - }), None, Some(Box::new(buf))); + rustc_driver::run_compiler(&args, &mut MiriCompilerCalls { host_target }, None, Some(Box::new(buf))); }); match result { diff --git a/src/bin/miri.rs b/src/bin/miri.rs index c1cad6edc0ab..27e52d5f1a06 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -11,115 +11,46 @@ extern crate rustc_metadata; extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_codegen_utils; +extern crate rustc_interface; extern crate syntax; -use std::path::PathBuf; use std::str::FromStr; use std::env; -use miri::MiriConfig; -use rustc::session::Session; -use rustc_metadata::cstore::CStore; -use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls}; -use rustc_driver::driver::{CompileState, CompileController}; -use rustc::session::config::{self, Input, ErrorOutputType}; -use rustc_codegen_utils::codegen_backend::CodegenBackend; +use rustc_interface::interface; use rustc::hir::def_id::LOCAL_CRATE; -use syntax::ast; struct MiriCompilerCalls { - default: Box, - miri_config: MiriConfig, + miri_config: miri::MiriConfig, } -impl<'a> CompilerCalls<'a> for MiriCompilerCalls { - fn early_callback( - &mut self, - matches: &getopts::Matches, - sopts: &config::Options, - cfg: &ast::CrateConfig, - descriptions: &rustc_errors::registry::Registry, - output: ErrorOutputType, - ) -> Compilation { - self.default.early_callback( - matches, - sopts, - cfg, - descriptions, - output, - ) +impl rustc_driver::Callbacks for MiriCompilerCalls { + fn after_parsing(&mut self, compiler: &interface::Compiler) -> bool { + let attr = ( + String::from("miri"), + syntax::feature_gate::AttributeType::Whitelisted, + ); + compiler.session().plugin_attributes.borrow_mut().push(attr); + + // Continue execution + true } - fn no_input( - &mut self, - matches: &getopts::Matches, - sopts: &config::Options, - cfg: &ast::CrateConfig, - odir: &Option, - ofile: &Option, - descriptions: &rustc_errors::registry::Registry, - ) -> Option<(Input, Option)> { - self.default.no_input( - matches, - sopts, - cfg, - odir, - ofile, - descriptions, - ) + + fn after_analysis(&mut self, compiler: &interface::Compiler) -> bool { + init_late_loggers(); + compiler.session().abort_if_errors(); + + compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| { + let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!"); + + miri::eval_main(tcx, entry_def_id, self.miri_config.clone()); + }); + + compiler.session().abort_if_errors(); + + // Don't continue execution + false } - fn late_callback( - &mut self, - codegen_backend: &CodegenBackend, - matches: &getopts::Matches, - sess: &Session, - cstore: &CStore, - input: &Input, - odir: &Option, - ofile: &Option, - ) -> Compilation { - // Called *before* `build_controller`. Add filename to `miri` arguments. - self.miri_config.args.insert(0, input.filestem().to_string()); - self.default.late_callback(codegen_backend, matches, sess, cstore, input, odir, ofile) - } - fn build_controller( - self: Box, - sess: &Session, - matches: &getopts::Matches, - ) -> CompileController<'a> { - let this = *self; - let mut control = this.default.build_controller(sess, matches); - control.after_hir_lowering.callback = Box::new(after_hir_lowering); - let miri_config = this.miri_config; - control.after_analysis.callback = - Box::new(move |state| after_analysis(state, miri_config.clone())); - control.after_analysis.stop = Compilation::Stop; - control - } -} - -fn after_hir_lowering(state: &mut CompileState) { - let attr = ( - String::from("miri"), - syntax::feature_gate::AttributeType::Whitelisted, - ); - state.session.plugin_attributes.borrow_mut().push(attr); -} - -fn after_analysis<'a, 'tcx>( - state: &mut CompileState<'a, 'tcx>, - miri_config: MiriConfig, -) { - init_late_loggers(); - state.session.abort_if_errors(); - - let tcx = state.tcx.unwrap(); - - - let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!"); - - miri::eval_main(tcx, entry_def_id, miri_config); - - state.session.abort_if_errors(); } fn init_early_loggers() { @@ -228,12 +159,9 @@ fn main() { debug!("rustc arguments: {:?}", rustc_args); debug!("miri arguments: {:?}", miri_args); - let miri_config = MiriConfig { validate, args: miri_args }; - let result = rustc_driver::run(move || { - rustc_driver::run_compiler(&rustc_args, Box::new(MiriCompilerCalls { - default: Box::new(RustcDefaultCalls), - miri_config, - }), None, None) - }); - std::process::exit(result as i32); + let miri_config = miri::MiriConfig { validate, args: miri_args }; + let result = rustc_driver::report_ices_to_stderr_if_any(move || { + rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None) + }).and_then(|result| result); + std::process::exit(result.is_err() as i32); } From ecae3751b4016a76346d5495282111e7d36a013a Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 10 Mar 2019 12:03:51 +0100 Subject: [PATCH 0599/5092] Reintroduce prepending the input file name to the miri arguments --- src/bin/miri.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 27e52d5f1a06..4cc0d955d3c2 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -42,8 +42,12 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| { let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!"); + let mut config = self.miri_config.clone(); - miri::eval_main(tcx, entry_def_id, self.miri_config.clone()); + // Add filename to `miri` arguments. + config.args.insert(0, compiler.input().filestem().to_string()); + + miri::eval_main(tcx, entry_def_id, config); }); compiler.session().abort_if_errors(); From 2c7357dc54f7f7b201074d35614bb7d9559a61e1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 11 Mar 2019 10:09:08 +0100 Subject: [PATCH 0600/5092] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index bf8995fe8a3e..7abca8ef4694 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2019-03-02 +nightly-2019-03-11 From a672abddfa4fa544dc5f4e1fd5fe22244bd8b718 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 11 Mar 2019 10:25:21 +0100 Subject: [PATCH 0601/5092] Make the rustc test runner build again --- src/bin/miri-rustc-tests.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index cab8d845fc0d..43bf466c70ee 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -9,19 +9,15 @@ extern crate rustc_codegen_utils; extern crate rustc_interface; extern crate syntax; -use std::path::{PathBuf, Path}; +use std::path::Path; use std::io::Write; use std::sync::{Mutex, Arc}; use std::io; -use rustc::session::Session; use rustc_interface::interface; -use rustc_metadata::cstore::CStore; -use rustc::session::config::{self, Input, ErrorOutputType}; use rustc::hir::{self, itemlikevisit}; use rustc::ty::TyCtxt; -use syntax::ast; use rustc::hir::def_id::LOCAL_CRATE; use miri::MiriConfig; @@ -32,7 +28,7 @@ struct MiriCompilerCalls { } impl rustc_driver::Callbacks for MiriCompilerCalls { - fn after_parsing(&mut self, compiler: &interface::Compiler<'_>) -> bool { + fn after_parsing(&mut self, compiler: &interface::Compiler) -> bool { let attr = ( String::from("miri"), syntax::feature_gate::AttributeType::Whitelisted, @@ -43,7 +39,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { true } - fn after_analysis(&mut self, compiler: &interface::Compiler<'_>) -> bool { + fn after_analysis(&mut self, compiler: &interface::Compiler) -> bool { compiler.session().abort_if_errors(); compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| { if std::env::args().any(|arg| arg == "--test") { @@ -146,7 +142,7 @@ fn main() { let buf = BufWriter::default(); let output = buf.clone(); let result = std::panic::catch_unwind(|| { - rustc_driver::run_compiler(&args, &mut MiriCompilerCalls { host_target }, None, Some(Box::new(buf))); + let _ = rustc_driver::run_compiler(&args, &mut MiriCompilerCalls { host_target }, None, Some(Box::new(buf))); }); match result { From 56c7656568911bbe2e438d18348af67a6935573f Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 11 Mar 2019 10:28:03 +0100 Subject: [PATCH 0602/5092] Remove dead code and docs --- src/bin/cargo-miri.rs | 7 ------- tests/compile-fail/stack_limit.rs | 20 -------------------- 2 files changed, 27 deletions(-) delete mode 100644 tests/compile-fail/stack_limit.rs diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 50570554f450..8984a0bc4f91 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -25,13 +25,6 @@ Common options: Other [options] are the same as `cargo rustc`. Everything after the first "--" is passed verbatim to Miri, which will pass everything after the second "--" verbatim to the interpreted program. - -The config flag `miri` is automatically defined for convenience. You can use -it to configure the resource limits - - #![cfg_attr(miri, memory_size = 42)] - -available resource limits are `memory_size`, `step_limit`, `stack_limit` "#; #[derive(Copy, Clone, Debug, PartialEq, Eq)] diff --git a/tests/compile-fail/stack_limit.rs b/tests/compile-fail/stack_limit.rs deleted file mode 100644 index 5645217fe1ff..000000000000 --- a/tests/compile-fail/stack_limit.rs +++ /dev/null @@ -1,20 +0,0 @@ -#![feature(custom_attribute)] -#![miri(stack_limit=16)] - -//error-pattern: reached the configured maximum number of stack frames - -fn bar() { - foo(); -} - -fn foo() { - cake(); -} - -fn cake() { - bar(); -} - -fn main() { - bar(); -} From 40ce1fcf267e8819c1e0699833beed087671e473 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 11 Mar 2019 11:28:56 +0100 Subject: [PATCH 0603/5092] Update bencher API --- benches/helpers/miri_helper.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 3e3c3a53f754..d82f9f8b9289 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -15,7 +15,7 @@ struct MiriCompilerCalls<'a> { } impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { - fn after_analysis(&mut self, compiler: &interface::Compiler<'_>) -> bool { + fn after_analysis(&mut self, compiler: &interface::Compiler) -> bool { compiler.session().abort_if_errors(); compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| { @@ -24,7 +24,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { ); self.bencher.iter(|| { - let config = MiriConfig { validate: true, args: vec![] }; + let config = miri::MiriConfig { validate: true, args: vec![] }; eval_main(tcx, entry_def_id, config); }); }); From 8568c20f4de4b52d3cc625c9f9c5052ee0e74d67 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 11 Mar 2019 12:41:11 +0100 Subject: [PATCH 0604/5092] Silence some warnings --- benches/helpers/miri_helper.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index d82f9f8b9289..01fef16e4a97 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -59,5 +59,5 @@ pub fn run(filename: &str, bencher: &mut Bencher) { "--sysroot".to_string(), find_sysroot(), ]; - rustc_driver::run_compiler(args, &mut MiriCompilerCalls { bencher }, None, None); + rustc_driver::run_compiler(args, &mut MiriCompilerCalls { bencher }, None, None).unwrap() } From 687c5d13ea09aceaa79b4eb1b854791ad0f27b89 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Mar 2019 13:30:57 +0100 Subject: [PATCH 0605/5092] bump Rust; remove stabilized feature --- rust-version | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 7abca8ef4694..0979a384dd32 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2019-03-11 +nightly-2019-03-18 diff --git a/src/lib.rs b/src/lib.rs index cf6a885c605c..ee739a5435ac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(rustc_private, range_contains)] +#![feature(rustc_private)] #![allow(clippy::cast_lossless)] From 8ee67994cc2ef98efb3f820a8f7012d24812cc06 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Mar 2019 13:48:37 +0100 Subject: [PATCH 0606/5092] fix for rustc change --- src/bin/miri-rustc-tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 43bf466c70ee..f1f1e1a7c6be 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -47,7 +47,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.node { - if i.attrs.iter().any(|attr| attr.name() == "test") { + if i.attrs.iter().any(|attr| attr.ident_str() == Some("test")) { let config = MiriConfig { validate: true, args: vec![] }; let did = self.0.hir().body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); From 5d3825fc4800a04ded444ba442d5080abe7c4c38 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 18 Mar 2019 15:08:36 +0100 Subject: [PATCH 0607/5092] Update src/bin/miri-rustc-tests.rs Co-Authored-By: RalfJung --- src/bin/miri-rustc-tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index f1f1e1a7c6be..e54be4644f25 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -47,7 +47,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.node { - if i.attrs.iter().any(|attr| attr.ident_str() == Some("test")) { + if i.attrs.iter().any(|attr| attr.check_name("test")) { let config = MiriConfig { validate: true, args: vec![] }; let did = self.0.hir().body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); From d96ece3806d0ac4c670dc7ed1cda07e1339a450b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Mar 2019 10:09:49 +0100 Subject: [PATCH 0608/5092] move back to unstable compiletest; the stable one broke --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a68c04092f66..1a1a1fa2330a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,5 +54,5 @@ cargo_miri = ["cargo_metadata", "directories", "rustc_version"] rustc_tests = [] [dev-dependencies] -compiletest_rs = { version = "0.3.17", features = ["tmp", "stable"] } +compiletest_rs = { version = "0.3.17", features = ["tmp"] } colored = "1.6" From d0d7f221637951587d647b4d37f89955db9ce43b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Mar 2019 10:20:29 +0100 Subject: [PATCH 0609/5092] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 0979a384dd32..04dab0fba1af 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2019-03-18 +nightly-2019-03-20 From 133f2ce4e511f555486d63f35c56d3e0b863126f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Mar 2019 10:24:22 +0100 Subject: [PATCH 0610/5092] pin old compiletest, for now --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 1a1a1fa2330a..bc0109a2ffbb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,5 +54,5 @@ cargo_miri = ["cargo_metadata", "directories", "rustc_version"] rustc_tests = [] [dev-dependencies] -compiletest_rs = { version = "0.3.17", features = ["tmp"] } +compiletest_rs = { version = "=0.3.19", features = ["tmp", "stable"] } colored = "1.6" From 90dac3d4bd861c9b46aab646cc1abe90dcc3f4a1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 Mar 2019 22:47:31 +0100 Subject: [PATCH 0611/5092] update README to suggest installing Miri as a component --- README.md | 36 +++++++++++++----------------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 184e37a894a9..09fa329dc4ec 100644 --- a/README.md +++ b/README.md @@ -27,42 +27,31 @@ list! ## Running Miri on your own project (and its test suite) -Install Miri as a cargo subcommand: +Install Miri via `rustup`: ```sh -cargo +nightly install --force --git https://github.com/rust-lang/miri miri +rustup component add miri ``` -If this does not work, try using the nightly version given in -[this file](https://raw.githubusercontent.com/rust-lang/miri/master/rust-version). CI -should ensure that this nightly always works. - -You have to use a consistent Rust version for building miri and your project, so -remember to either always specify the nightly version manually (like in the -example above), overriding it in your project directory as well, or use `rustup -default nightly` (or `rustup default nightly-YYYY-MM-DD`) to globally make -`nightly` the default toolchain. - Now you can run your project in Miri: 1. Run `cargo clean` to eliminate any cached dependencies. Miri needs your dependencies to be compiled the right way, that would not happen if they have previously already been compiled. -2. To run all tests in your project through Miri, use `cargo +nightly miri test`. -3. If you have a binary project, you can run it through Miri using `cargo - +nightly miri run`. +2. To run all tests in your project through Miri, use `cargo miri test`. +3. If you have a binary project, you can run it through Miri using `cargo miri run`. The first time you run Miri, it will perform some extra setup and install some dependencies. It will ask you for confirmation before installing anything. If -you run Miri on CI, run `cargo +nightly miri setup` to avoid getting interactive +you run Miri on CI, run `cargo miri setup` to avoid getting interactive questions. You can pass arguments to Miri after the first `--`, and pass arguments to the interpreted program or test suite after the second `--`. For example, `cargo -+nightly miri run -- -Zmiri-disable-validation` runs the program without -validation of basic type invariants and references. `cargo +nightly miri test --- -- -Zunstable-options --exclude-should-panic` skips `#[should_panic]` tests, -which is a good idea because Miri does not support unwinding or catching panics. +miri run -- -Zmiri-disable-validation` runs the program without validation of +basic type invariants and references. `cargo miri test -- -- -Zunstable-options +--exclude-should-panic` skips `#[should_panic]` tests, which is a good idea +because Miri does not support unwinding or catching panics. When running code via `cargo miri`, the `miri` config flag is set. You can use this to exclude test cases that will fail under Miri because they do things @@ -110,10 +99,14 @@ convenient way is to install Miri using cargo, then you can easily run it on other projects: ```sh +rustup component remove miri # avoid having Miri installed twice cargo +nightly install --path "$DIR" --force # or the nightly in `rust-version` cargo +nightly miri setup ``` +(We are giving `+nightly` explicitly here all the time because it is important +that all of these commands get executed with the same toolchain.) + If you want to use a different libstd (not the one that comes with the nightly), you can do that by running @@ -124,9 +117,6 @@ XARGO_RUST_SRC=~/src/rust/rustc/src/ cargo +nightly miri setup Either way, you can now do `cargo +nightly miri run` to run Miri with your local changes on whatever project you are debugging. -(We are giving `+nightly` explicitly here all the time because it is important -that all of these commands get executed with the same toolchain.) - `cargo miri setup` should end in printing the directory where the libstd was built. For the next step to work, set that as your `MIRI_SYSROOT` environment variable: From 63b4a7661d620e804f5fc682c05aec3c499fe88a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 26 Mar 2019 10:07:22 +0100 Subject: [PATCH 0612/5092] explain Miri limitations --- README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/README.md b/README.md index 09fa329dc4ec..81a1220ae295 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,26 @@ Miri has already discovered some [real-world bugs](#bugs-found-by-miri). If you found a bug with Miri, we'd appreciate if you tell us and we'll add it to the list! +Be aware that Miri will not catch all possible errors in your program, and +cannot run all programs: + +* There are still plenty of open questions around the basic invariants for some + types and when these invariants even have to hold, so if you program runs fine + in Miri right now that is by no means a guarantee that it is UB-free when + these questions get answered. +* If the program relies on unspecified details of how data is laid out, it will + still run fine in Miri -- but might break (including causing UB) on different + compiler versions or different platforms. +* Miri is fully deterministic and does not actually pick a base address in + virtual memory for the program's allocations. If program behavior depends on + the base address of an allocation, Miri will stop execution (with a few + exceptions to make some common pointer comparisons work). +* Miri runs the program as a platform-independent interpreter, so the program + has no access to any platform-specific APIs or FFI. A few APIs have been + implemented (such as printing to stdout) but most have not: for example, Miri + currently does not support concurrency, or networking, or file system access, + or gathering entropy from the system. + [rust]: https://www.rust-lang.org/ [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md [`unreachable_unchecked`]: https://doc.rust-lang.org/stable/std/hint/fn.unreachable_unchecked.html From 1100b4819c64d2554e2bff0ac3bd505ff44809bb Mon Sep 17 00:00:00 2001 From: 0xflotus <0xflotus@gmail.com> Date: Thu, 28 Mar 2019 11:47:51 +0100 Subject: [PATCH 0613/5092] fixed environment --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 81a1220ae295..cf7bc9e32d0b 100644 --- a/README.md +++ b/README.md @@ -212,7 +212,7 @@ With this, you should now have a working development setup! See ["Testing Miri"](#testing-miri) above for how to proceed. Running `cargo miri` in this setup is a bit more complicated, because the Miri -binary you just created does not actually run without some enviroment variables. +binary you just created does not actually run without some environment variables. But you can contort cargo into calling `cargo miri` the right way for you: ```sh From d9178b9300d884b54ea9892bfa3b6892148bee9d Mon Sep 17 00:00:00 2001 From: kenta7777 Date: Wed, 27 Mar 2019 17:58:11 +0900 Subject: [PATCH 0614/5092] renames EvalContext to InterpretCx --- src/fn_call.rs | 2 +- src/lib.rs | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index b496a9b7d41d..3c6384e1a79e 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -255,7 +255,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' trace!("__rust_maybe_catch_panic: {:?}", f_instance); // Now we make a function call. - // TODO: consider making this reusable? `EvalContext::step` does something similar + // TODO: consider making this reusable? `InterpretCx::step` does something similar // for the TLS destructors, and of course `eval_main`. let mir = this.load_mir(f_instance.def)?; let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); diff --git a/src/lib.rs b/src/lib.rs index ee739a5435ac..be58c6a6a464 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,8 +67,8 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, config: MiriConfig, -) -> EvalResult<'tcx, EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>> { - let mut ecx = EvalContext::new( +) -> EvalResult<'tcx, InterpretCx<'a, 'mir, 'tcx, Evaluator<'tcx>>> { + let mut ecx = InterpretCx::new( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), Evaluator::new(config.validate), @@ -345,7 +345,7 @@ impl<'tcx> Evaluator<'tcx> { // FIXME: rustc issue . #[allow(dead_code)] -type MiriEvalContext<'a, 'mir, 'tcx> = EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>; +type MiriEvalContext<'a, 'mir, 'tcx> = InterpretCx<'a, 'mir, 'tcx, Evaluator<'tcx>>; // A little trait that's useful to be inherited by extension traits. pub trait MiriEvalContextExt<'a, 'mir, 'tcx> { @@ -376,14 +376,14 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { const STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); #[inline(always)] - fn enforce_validity(ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool { + fn enforce_validity(ecx: &InterpretCx<'a, 'mir, 'tcx, Self>) -> bool { ecx.machine.validate } /// Returns `Ok()` when the function was handled; fail otherwise. #[inline(always)] fn find_fn( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Borrow>], dest: Option>, @@ -394,7 +394,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn call_intrinsic( - ecx: &mut rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &mut rustc_mir::interpret::InterpretCx<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Borrow>], dest: PlaceTy<'tcx, Borrow>, @@ -404,7 +404,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn ptr_op( - ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &rustc_mir::interpret::InterpretCx<'a, 'mir, 'tcx, Self>, bin_op: mir::BinOp, left: ImmTy<'tcx, Borrow>, right: ImmTy<'tcx, Borrow>, @@ -413,7 +413,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { } fn box_alloc( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, dest: PlaceTy<'tcx, Borrow>, ) -> EvalResult<'tcx> { trace!("box_alloc for {:?}", dest.layout.ty); @@ -481,7 +481,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { } #[inline(always)] - fn before_terminator(_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> + fn before_terminator(_ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> { // We are not interested in detecting loops. Ok(()) @@ -511,7 +511,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { } fn tag_dereference( - ecx: &EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &InterpretCx<'a, 'mir, 'tcx, Self>, place: MPlaceTy<'tcx, Borrow>, mutability: Option, ) -> EvalResult<'tcx, Scalar> { @@ -532,7 +532,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn tag_new_allocation( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, ptr: Pointer, kind: MemoryKind, ) -> Pointer { @@ -547,7 +547,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn retag( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, kind: mir::RetagKind, place: PlaceTy<'tcx, Borrow>, ) -> EvalResult<'tcx> { @@ -565,14 +565,14 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn stack_push( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, ) -> EvalResult<'tcx, stacked_borrows::CallId> { Ok(ecx.memory().extra.borrow_mut().new_call()) } #[inline(always)] fn stack_pop( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, extra: stacked_borrows::CallId, ) -> EvalResult<'tcx> { Ok(ecx.memory().extra.borrow_mut().end_call(extra)) From 83b7f2edc90028fa8dafa696a45da6d0d44c5c70 Mon Sep 17 00:00:00 2001 From: 0xflotus <0xflotus@gmail.com> Date: Thu, 28 Mar 2019 11:47:51 +0100 Subject: [PATCH 0615/5092] fixed environment --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 81a1220ae295..cf7bc9e32d0b 100644 --- a/README.md +++ b/README.md @@ -212,7 +212,7 @@ With this, you should now have a working development setup! See ["Testing Miri"](#testing-miri) above for how to proceed. Running `cargo miri` in this setup is a bit more complicated, because the Miri -binary you just created does not actually run without some enviroment variables. +binary you just created does not actually run without some environment variables. But you can contort cargo into calling `cargo miri` the right way for you: ```sh From adbda8ca24f044506684bbe3d48f5c096f6b02e3 Mon Sep 17 00:00:00 2001 From: kenta7777 Date: Sat, 30 Mar 2019 11:01:44 +0900 Subject: [PATCH 0616/5092] adjust rust-version to the latest nightly --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 04dab0fba1af..eadee7c5f5de 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2019-03-20 +nightly-2019-03-29 From d5cdba5ee6025374be0942cf103740603216604e Mon Sep 17 00:00:00 2001 From: Timo Date: Sat, 30 Mar 2019 17:53:15 -0400 Subject: [PATCH 0617/5092] Add alternative for how to install if rustup fails As is the case now: https://rust-lang-nursery.github.io/rust-toolstate/ --- README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cf7bc9e32d0b..115f29f09abe 100644 --- a/README.md +++ b/README.md @@ -88,9 +88,19 @@ fn does_not_work_on_miri() { ### Common Problems -When using the above instructions, you may encounter a number of confusing compiler +When using the above instructions, you may encounter a number of confusing errors. +#### "component 'miri' for target '\' is unavailable for download for channel 'nightly'" + +The latest nightly may have broken Miri. If [this is the case][rust-toolstate], instead try to install Miri the old way with + +```sh +cargo +nightly install --force --git https://github.com/rust-lang/miri miri +``` + +[rust-toolstate]: + #### "found possibly newer version of crate `std` which `` depends on" Your build directory may contain artifacts from an earlier build that have/have From 67e123502c50dd2c24c34ff6886233d6721cfb5a Mon Sep 17 00:00:00 2001 From: Timo Date: Sun, 31 Mar 2019 10:03:03 -0400 Subject: [PATCH 0618/5092] README: Suggest using a previous nightly, revert other approach --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 115f29f09abe..e64f4a6cb3b5 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,16 @@ Install Miri via `rustup`: rustup component add miri ``` +### error: component 'miri' is unavailable for download (nightly) + +The development of rustc's internals is quite fast paced. Downstream projects that rely on nightly internals, particularly clippy, can break fairly often because of this. + +When such breakages occur the nightly release will be missing Miri. This is a trade-off compared with the other option of just not publishing the night's release, but does avoid blocking the rust nightly releases for people that don't need clippy/Miri. + +To mitigate the issues we have: +* rustup will warn if the update is missing any components you currently have. This means you can no longer accidentally update to a no-Miri release. Once Miri is available again it'll update. +* However, if you need latest nightly Miri you can use to find and install a dated nightly release e.g. `rustup install nightly-2018-12-06`. + Now you can run your project in Miri: 1. Run `cargo clean` to eliminate any cached dependencies. Miri needs your @@ -88,19 +98,9 @@ fn does_not_work_on_miri() { ### Common Problems -When using the above instructions, you may encounter a number of confusing +When using the above instructions, you may encounter a number of confusing compiler errors. -#### "component 'miri' for target '\' is unavailable for download for channel 'nightly'" - -The latest nightly may have broken Miri. If [this is the case][rust-toolstate], instead try to install Miri the old way with - -```sh -cargo +nightly install --force --git https://github.com/rust-lang/miri miri -``` - -[rust-toolstate]: - #### "found possibly newer version of crate `std` which `` depends on" Your build directory may contain artifacts from an earlier build that have/have From d54f9dc75cf3e9405ff56240c685eb7cf994c26e Mon Sep 17 00:00:00 2001 From: Timo Date: Sun, 31 Mar 2019 11:05:14 -0400 Subject: [PATCH 0619/5092] README: Update to RalfJung's suggestion... ...verbatim. Thanks :) --- README.md | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/README.md b/README.md index e64f4a6cb3b5..a366e433b0f3 100644 --- a/README.md +++ b/README.md @@ -53,15 +53,7 @@ Install Miri via `rustup`: rustup component add miri ``` -### error: component 'miri' is unavailable for download (nightly) - -The development of rustc's internals is quite fast paced. Downstream projects that rely on nightly internals, particularly clippy, can break fairly often because of this. - -When such breakages occur the nightly release will be missing Miri. This is a trade-off compared with the other option of just not publishing the night's release, but does avoid blocking the rust nightly releases for people that don't need clippy/Miri. - -To mitigate the issues we have: -* rustup will warn if the update is missing any components you currently have. This means you can no longer accidentally update to a no-Miri release. Once Miri is available again it'll update. -* However, if you need latest nightly Miri you can use to find and install a dated nightly release e.g. `rustup install nightly-2018-12-06`. +If `rustup` says the `miri` component is unavailable, that's because not all nightly releases come with all tools. Check out this website to determine a nightly version that comes with Miri and install that, e.g. using `rustup install nightly-2019-03-28`. Now you can run your project in Miri: From 7d6c8ad24b490c633b608849af504dcb3a71fa5e Mon Sep 17 00:00:00 2001 From: Timo Date: Sun, 31 Mar 2019 14:52:57 -0400 Subject: [PATCH 0620/5092] README: Fix missing link Thanks for your patience :man_facepalming: --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a366e433b0f3..495d74dcc41a 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ Install Miri via `rustup`: rustup component add miri ``` -If `rustup` says the `miri` component is unavailable, that's because not all nightly releases come with all tools. Check out this website to determine a nightly version that comes with Miri and install that, e.g. using `rustup install nightly-2019-03-28`. +If `rustup` says the `miri` component is unavailable, that's because not all nightly releases come with all tools. Check out [this website](https://rust-lang.github.io/rustup-components-history) to determine a nightly version that comes with Miri and install that, e.g. using `rustup install nightly-2019-03-28`. Now you can run your project in Miri: From 9a0eaf6ebd6165a071ce3cf6d30921e02a115660 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 3 Apr 2019 10:48:11 +0200 Subject: [PATCH 0621/5092] Update to rustc nightly --- rust-version | 2 +- src/fn_call.rs | 4 ++-- src/helpers.rs | 2 +- src/operator.rs | 2 +- src/stacked_borrows.rs | 6 +++--- src/tls.rs | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/rust-version b/rust-version index eadee7c5f5de..b62147121802 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2019-03-29 +nightly-2019-04-03 diff --git a/src/fn_call.rs b/src/fn_call.rs index 3c6384e1a79e..038f5ed8a047 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -270,7 +270,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' let mut args = this.frame().mir.args_iter(); let arg_local = args.next().ok_or_else(|| - EvalErrorKind::AbiViolation( + InterpError::AbiViolation( "Argument to __rust_maybe_catch_panic does not take enough arguments." .to_owned(), ), @@ -529,7 +529,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' // This is `libc::pthread_key_t`. let key_type = args[0].layout.ty .builtin_deref(true) - .ok_or_else(|| EvalErrorKind::AbiViolation("wrong signature used for `pthread_key_create`: first argument must be a raw pointer.".to_owned()))? + .ok_or_else(|| InterpError::AbiViolation("wrong signature used for `pthread_key_create`: first argument must be a raw pointer.".to_owned()))? .ty; let key_layout = this.layout_of(key_type)?; diff --git a/src/helpers.rs b/src/helpers.rs index 2e4c955413ab..8a4cccc743e6 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -39,7 +39,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' }) .ok_or_else(|| { let path = path.iter().map(|&s| s.to_owned()).collect(); - EvalErrorKind::PathNotFound(path).into() + InterpError::PathNotFound(path).into() }) } diff --git a/src/operator.rs b/src/operator.rs index 0cba240a7d0f..a30b11aeb27d 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -325,7 +325,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; let offset = offset .checked_mul(pointee_size) - .ok_or_else(|| EvalErrorKind::Overflow(mir::BinOp::Mul))?; + .ok_or_else(|| InterpError::Overflow(mir::BinOp::Mul))?; // Now let's see what kind of pointer this is. if let Scalar::Ptr(ptr) = ptr { // Both old and new pointer must be in-bounds of a *live* allocation. diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index c9ca1c84e0f7..bea6aaf9cf89 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -7,7 +7,7 @@ use rustc::hir::{Mutability, MutMutable, MutImmutable}; use rustc::mir::RetagKind; use crate::{ - EvalResult, EvalErrorKind, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, + EvalResult, InterpError, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, MemoryKind, MiriMemoryKind, RangeMap, AllocId, Allocation, AllocationExtra, Pointer, Immediate, ImmTy, PlaceTy, MPlaceTy, }; @@ -380,7 +380,7 @@ impl<'tcx> Stacks { ptr.tag, kind, ptr, size.bytes()); let stacks = self.stacks.borrow(); for stack in stacks.iter(ptr.offset, size) { - stack.deref(ptr.tag, kind).map_err(EvalErrorKind::MachineError)?; + stack.deref(ptr.tag, kind).map_err(InterpError::MachineError)?; } Ok(()) } @@ -435,7 +435,7 @@ impl<'tcx> Stacks { let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { // Access source `ptr`, create new ref. - let ptr_idx = stack.deref(ptr.tag, new_kind).map_err(EvalErrorKind::MachineError)?; + let ptr_idx = stack.deref(ptr.tag, new_kind).map_err(InterpError::MachineError)?; // If we can deref the new tag already, and if that tag lives higher on // the stack than the one we come from, just use that. // That is, we check if `new_bor` *already* is "derived from" `ptr.tag`. diff --git a/src/tls.rs b/src/tls.rs index 796c2e5f9827..992e4fd05619 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -4,7 +4,7 @@ use rustc_target::abi::LayoutOf; use rustc::{ty, ty::layout::HasDataLayout, mir}; use crate::{ - EvalResult, EvalErrorKind, StackPopCleanup, + EvalResult, InterpError, StackPopCleanup, MPlaceTy, Scalar, Borrow, }; @@ -149,7 +149,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, StackPopCleanup::None { cleanup: true }, )?; let arg_local = this.frame().mir.args_iter().next().ok_or_else( - || EvalErrorKind::AbiViolation("TLS dtor does not take enough arguments.".to_owned()), + || InterpError::AbiViolation("TLS dtor does not take enough arguments.".to_owned()), )?; let dest = this.eval_place(&mir::Place::Base(mir::PlaceBase::Local(arg_local)))?; this.write_scalar(ptr, dest)?; From bebb5bfa38bdfe80970a105a758474bbb29bb95b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 4 Apr 2019 10:19:18 +0100 Subject: [PATCH 0622/5092] use rustup-toolchain-install-master for CI --- .travis.yml | 14 +++++++++++--- rust-version | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index ee58f73c3643..29e680cbae52 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ cache: # over time). directories: - /home/travis/.cargo + - /home/travis/.rustup os: - linux @@ -17,18 +18,25 @@ before_script: # Compute the rust version we use. We do not use "language: rust" to have more control here. - | if [[ "$TRAVIS_EVENT_TYPE" == cron ]]; then - RUST_TOOLCHAIN=nightly + RUSTC_HASH=$(git ls-remote https://github.com/rust-lang/rust.git master | awk '{print $1}') else - RUST_TOOLCHAIN=$(cat rust-version) + RUSTC_HASH=$(cat rust-version) fi # install Rust -- curl https://build.travis-ci.org/files/rustup-init.sh -sSf | sh -s -- -y --default-toolchain "$RUST_TOOLCHAIN" +- curl https://build.travis-ci.org/files/rustup-init.sh -sSf | sh -s -- -y --default-toolchain stable - export PATH=$HOME/.cargo/bin:$PATH +- cargo install rustup-toolchain-install-master || echo "rustup-toolchain-install-master already installed" +- rustup-toolchain-install-master -f -n master $RUSTC_HASH +- rustup default master - rustc --version script: - ./travis.sh +after_script: +# Don't cache this, it's a waste +- rustup toolchain uninstall master + notifications: email: on_success: never diff --git a/rust-version b/rust-version index b62147121802..a2b3daad97ec 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2019-04-03 +f717b58dd70829f105960a071c7992b440720482 From 31bc4355aaa27627d96696c03faa61ec35c5b7b4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 4 Apr 2019 10:21:32 +0100 Subject: [PATCH 0623/5092] adjust README --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cf7bc9e32d0b..54d8411b2fe7 100644 --- a/README.md +++ b/README.md @@ -120,13 +120,18 @@ other projects: ```sh rustup component remove miri # avoid having Miri installed twice -cargo +nightly install --path "$DIR" --force # or the nightly in `rust-version` +cargo +nightly install --path "$DIR" --force cargo +nightly miri setup ``` (We are giving `+nightly` explicitly here all the time because it is important that all of these commands get executed with the same toolchain.) +In case this fails, your nightly might be incompatible with Miri master. The +`rust-version` file contains the commit hash of rustc that Miri is currently +tested against; you can use that to find a nightly that works or you might have +to wait for the next nightly to get released. + If you want to use a different libstd (not the one that comes with the nightly), you can do that by running From 081837eff0c6f8dde9c6d87b8b9ddab1d2ecfd60 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 4 Apr 2019 10:38:49 +0100 Subject: [PATCH 0624/5092] fix Travis and adjust AppVeyor --- .appveyor.yml | 30 ++++++++++++++++++++---------- .travis.yml | 14 ++++++++------ 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index a46214a3c45c..e99b0cc33c9b 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -3,9 +3,7 @@ environment: PROJECT_NAME: miri matrix: - TARGET: x86_64-pc-windows-msvc - MSYS2_BITS: 64 - - TARGET: i686-pc-windows-msvc - MSYS2_BITS: 32 + #- TARGET: i686-pc-windows-msvc # branches to build branches: @@ -13,18 +11,23 @@ branches: only: - master +cache: + - '%USERPROFILE%\.cargo' + - '%USERPROFILE%\.rustup' + install: - # Install Rust. - - set PATH=C:\Program Files\Git\mingw64\bin;C:\msys64\mingw%MSYS2_BITS%\bin;%PATH% - - set /p RUST_TOOLCHAIN= Date: Thu, 4 Apr 2019 16:49:16 +0100 Subject: [PATCH 0625/5092] fix AppVeyor --- .appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index e99b0cc33c9b..e97380cb932f 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -3,7 +3,7 @@ environment: PROJECT_NAME: miri matrix: - TARGET: x86_64-pc-windows-msvc - #- TARGET: i686-pc-windows-msvc + - TARGET: i686-pc-windows-msvc # branches to build branches: @@ -42,7 +42,7 @@ test_script: - cargo test --release --all-features # Test cargo integration - cd test-cargo-miri - - python3 run-test.py + - '"C:\msys64\mingw64\bin\python3.exe" run-test.py' after_test: # Don't cache "master" toolchain, it's a waste From 7213b91cd4870ad878eb486e176346e832b5ed0b Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 5 Apr 2019 10:00:44 +0100 Subject: [PATCH 0626/5092] Use edition flag for 2phase test The compiler now rejects one of the examples with #![feature(nll)] --- tests/run-pass/2phase.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/2phase.rs b/tests/run-pass/2phase.rs index 5ca0ff5d8df8..9e50829fade8 100644 --- a/tests/run-pass/2phase.rs +++ b/tests/run-pass/2phase.rs @@ -1,4 +1,4 @@ -#![feature(nll)] +// edition:2018 trait S: Sized { fn tpb(&mut self, _s: Self) {} @@ -54,6 +54,8 @@ fn with_interior_mutability() { let mut x = Cell::new(1); let l = &x; + + #[allow(unknown_lints, mutable_borrow_reservation_conflict)] x .do_the_thing({ x.set(3); From 3d491884c5487487c002b5d6669a5992796ff328 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Apr 2019 11:29:35 +0200 Subject: [PATCH 0627/5092] AppVeyor: ignore already existing rustup-toolchain-install-master (WTF windows batch makes no sense) --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index e97380cb932f..7db60514ada7 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -21,7 +21,7 @@ install: - rustup-init.exe -y --default-host %TARGET% --default-toolchain stable - set PATH=%USERPROFILE%\.cargo\bin;%PATH% # Install "master" toolchain - - cargo install rustup-toolchain-install-master + - cargo install rustup-toolchain-install-master & exit 0 - set /p RUSTC_HASH= Date: Sat, 6 Apr 2019 16:17:33 +0100 Subject: [PATCH 0628/5092] Remove unnecessary test directive --- tests/run-pass/2phase.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/run-pass/2phase.rs b/tests/run-pass/2phase.rs index 9e50829fade8..57f363114370 100644 --- a/tests/run-pass/2phase.rs +++ b/tests/run-pass/2phase.rs @@ -1,5 +1,3 @@ -// edition:2018 - trait S: Sized { fn tpb(&mut self, _s: Self) {} } From ddb04966422eaba33328416806f45370a0a95711 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Apr 2019 22:11:59 +0200 Subject: [PATCH 0629/5092] temporarily ignore async fn test --- tests/run-pass/async-fn.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 48f8fc1223c9..79fcb59011f6 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -1,3 +1,4 @@ +// ignore-test FIXME ignored to let https://github.com/rust-lang/rust/pull/59119 land #![feature( async_await, await_macro, From 72cd133d1babc088661d52525e4f3a8a4e5d2d2d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 7 Apr 2019 10:55:34 +0200 Subject: [PATCH 0630/5092] compiletest can just propagate MIRI_SYSROOT from the outside --- tests/compiletest.rs | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 38a9d31d6e89..0ee8ca130ae0 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -87,22 +87,6 @@ fn miri_pass(path: &str, target: &str, opt: bool) { compiletest::run_tests(&config); } -/// Ensures that the `MIRI_SYSROOT` env var is set. -fn set_sysroot() { - if std::env::var("MIRI_SYSROOT").is_ok() { - // Nothing to do. - return; - } - let sysroot = std::process::Command::new("rustc") - .arg("--print") - .arg("sysroot") - .output() - .expect("rustc not found") - .stdout; - let sysroot = String::from_utf8(sysroot).expect("sysroot is not utf8"); - std::env::set_var("MIRI_SYSROOT", sysroot.trim()); -} - fn get_host() -> String { let rustc = rustc_test_suite().unwrap_or(PathBuf::from("rustc")); let rustc_version = std::process::Command::new(rustc) @@ -129,8 +113,6 @@ fn compile_fail_miri(opt: bool) { } fn test_runner(_tests: &[&()]) { - set_sysroot(); - run_pass_miri(false); run_pass_miri(true); From 336a59d2640377af3a51c1133c0394d99cbd5ef5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 7 Apr 2019 10:57:25 +0200 Subject: [PATCH 0631/5092] rename MIRI_TARGET -> MIRI_COMPILETEST_TARGET to clarify that this affects compiletest only --- tests/compiletest.rs | 2 +- travis.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 0ee8ca130ae0..ff83eca1c9f0 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -101,7 +101,7 @@ fn get_host() -> String { } fn get_target() -> String { - std::env::var("MIRI_TARGET").unwrap_or_else(|_| get_host()) + std::env::var("MIRI_COMPILETEST_TARGET").unwrap_or_else(|_| get_host()) } fn run_pass_miri(opt: bool) { diff --git a/travis.sh b/travis.sh index 8ec1d56ab770..8951cdc89644 100755 --- a/travis.sh +++ b/travis.sh @@ -22,7 +22,7 @@ echo echo "Test miri with full MIR, on the host and other architectures" MIRI_SYSROOT="$MIRI_SYSROOT_BASE"/HOST cargo test --release --all-features -MIRI_SYSROOT="$MIRI_SYSROOT_BASE" MIRI_TARGET="$FOREIGN_TARGET" cargo test --release --all-features +MIRI_SYSROOT="$MIRI_SYSROOT_BASE" MIRI_COMPILETEST_TARGET="$FOREIGN_TARGET" cargo test --release --all-features echo echo "Test cargo integration" From 3f552fea269850a16b3e5f9743f0ab783c668787 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 7 Apr 2019 20:05:57 +0200 Subject: [PATCH 0632/5092] test calling Box --- tests/run-pass/closures.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/run-pass/closures.rs b/tests/run-pass/closures.rs index 9b379051eb77..141e6cd6d08a 100644 --- a/tests/run-pass/closures.rs +++ b/tests/run-pass/closures.rs @@ -40,9 +40,14 @@ fn fn_once_closure_with_multiple_args() -> i64 { } } +fn boxed(f: Box i32>) -> i32 { + f() +} + fn main() { assert_eq!(simple(), 12); assert_eq!(crazy_closure(), (84, 10, 10)); assert_eq!(closure_arg_adjustment_problem(), 3); assert_eq!(fn_once_closure_with_multiple_args(), 6); + assert_eq!(boxed(Box::new({let x = 13; move || x})), 13); } From 6e4264bf27882dfee5276e18834ceb9edb040c23 Mon Sep 17 00:00:00 2001 From: Tim Diekmann <21277928+TimDiekmann@users.noreply.github.com> Date: Sun, 7 Apr 2019 20:52:12 +0200 Subject: [PATCH 0633/5092] Add `calloc` --- src/fn_call.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/fn_call.rs b/src/fn_call.rs index 038f5ed8a047..911f76929d5a 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -93,6 +93,28 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' this.write_scalar(Scalar::Ptr(ptr.with_default_tag()), dest)?; } } + "calloc" => { + let items = this.read_scalar(args[0])?.to_usize(this)?; + let count = this.read_scalar(args[1])?.to_usize(this)?; + let size = if let Some(size) = items.checked_add(count) { + size + } else { + return err!(MachineError(format!( + "calloc: overflow of items * size: {} * {}", + items, size, + ))); + }; + if size == 0 { + this.write_null(dest)?; + } else { + let align = this.tcx.data_layout.pointer_align.abi; + let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into()); + this.memory_mut() + .get_mut(ptr.alloc_id)? + .write_repeat(tcx, ptr, 0, Size::from_bytes(size))?; + this.write_scalar(Scalar::Ptr(ptr.with_default_tag()), dest)?; + } + } "posix_memalign" => { let ret = this.deref_operand(args[0])?; let align = this.read_scalar(args[1])?.to_usize(this)?; From d1d05c8b4127295717b6f893e22cf657b4dbf1db Mon Sep 17 00:00:00 2001 From: Tim Diekmann Date: Sun, 7 Apr 2019 21:09:21 +0200 Subject: [PATCH 0634/5092] Fix tagging order --- src/fn_call.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 911f76929d5a..062cc900e176 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -100,19 +100,21 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' size } else { return err!(MachineError(format!( - "calloc: overflow of items * size: {} * {}", - items, size, + "calloc: overflow of items * count: {} * {}", + items, count, ))); }; if size == 0 { this.write_null(dest)?; } else { let align = this.tcx.data_layout.pointer_align.abi; - let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into()); + let ptr = this.memory_mut() + .allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into()) + .with_default_tag(); this.memory_mut() .get_mut(ptr.alloc_id)? .write_repeat(tcx, ptr, 0, Size::from_bytes(size))?; - this.write_scalar(Scalar::Ptr(ptr.with_default_tag()), dest)?; + this.write_scalar(Scalar::Ptr(ptr), dest)?; } } "posix_memalign" => { From 3002bbd4ac9e4b64ed546550b54d3511395dd1ff Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sun, 7 Apr 2019 14:33:28 -0700 Subject: [PATCH 0635/5092] Update compiletest --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index bc0109a2ffbb..d580d4b8ec17 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,5 +54,5 @@ cargo_miri = ["cargo_metadata", "directories", "rustc_version"] rustc_tests = [] [dev-dependencies] -compiletest_rs = { version = "=0.3.19", features = ["tmp", "stable"] } +compiletest_rs = { version = "0.3.21", features = ["tmp", "stable"] } colored = "1.6" From a59e155206ca596722a67e967848fa2d3e516e8c Mon Sep 17 00:00:00 2001 From: Tim Diekmann Date: Mon, 8 Apr 2019 01:12:44 +0200 Subject: [PATCH 0636/5092] Tidy up calloc code --- src/fn_call.rs | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 062cc900e176..2db23bd48c54 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -95,25 +95,16 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } "calloc" => { let items = this.read_scalar(args[0])?.to_usize(this)?; - let count = this.read_scalar(args[1])?.to_usize(this)?; - let size = if let Some(size) = items.checked_add(count) { - size - } else { - return err!(MachineError(format!( - "calloc: overflow of items * count: {} * {}", - items, count, - ))); - }; - if size == 0 { + let len = this.read_scalar(args[1])?.to_usize(this)?; + let bytes = items.checked_mul(len).ok_or_else(|| InterpError::Overflow(mir::BinOp::Mul))?; + + if bytes== 0 { this.write_null(dest)?; } else { + let size = Size::from_bytes(bytes); let align = this.tcx.data_layout.pointer_align.abi; - let ptr = this.memory_mut() - .allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into()) - .with_default_tag(); - this.memory_mut() - .get_mut(ptr.alloc_id)? - .write_repeat(tcx, ptr, 0, Size::from_bytes(size))?; + let ptr = this.memory_mut().allocate(size, align, MiriMemoryKind::C.into()).with_default_tag(); + this.memory_mut().get_mut(ptr.alloc_id)?.write_repeat(tcx, ptr, 0, size)?; this.write_scalar(Scalar::Ptr(ptr), dest)?; } } From fa0755c9fd9f7c43fbd313db32935ff37e588ee2 Mon Sep 17 00:00:00 2001 From: Tim Diekmann Date: Mon, 8 Apr 2019 01:12:50 +0200 Subject: [PATCH 0637/5092] Add calloc test --- tests/run-pass/calloc.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 tests/run-pass/calloc.rs diff --git a/tests/run-pass/calloc.rs b/tests/run-pass/calloc.rs new file mode 100644 index 000000000000..8e8e2e5f10f4 --- /dev/null +++ b/tests/run-pass/calloc.rs @@ -0,0 +1,26 @@ +//ignore-windows: Uses POSIX APIs + +#![feature(rustc_private)] + +use core::slice; + +extern crate libc; + +fn main() { + unsafe { + let p1 = libc::calloc(0, 0); + assert!(p1.is_null()); + + let p2 = libc::calloc(20, 0); + assert!(p2.is_null()); + + let p3 = libc::calloc(0, 20); + assert!(p3.is_null()); + + let p4 = libc::calloc(4, 8) as *const u8; + assert!(!p4.is_null()); + + let slice = slice::from_raw_parts(p4, 4 * 8); + assert_eq!(&slice, &[0_u8; 4 * 8]); + } +} From 73239573c9290346dd31c50cd3565cb754d86c80 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 7 Apr 2019 18:17:43 -0400 Subject: [PATCH 0638/5092] Implement non-deterministc mode Part of #653 This allows us to properly implement getrandom(), which unlocks the default HashMap type (e.g. HashMap) with RandomState) This commit adds a new '-Zmiri-seed=' option. When present, this option takes a 64-bit hex value, which is used as the seed to an internal PRNG. This PRNG is used to implement the 'getrandom()' syscall. When '-Zmiri-seed' is not passed, 'getrandom()' will be disabled. --- Cargo.toml | 2 ++ src/bin/miri-rustc-tests.rs | 4 ++-- src/bin/miri.rs | 20 ++++++++++++++++++-- src/fn_call.rs | 31 ++++++++++++++++++++++++++++--- src/lib.rs | 16 ++++++++++++++-- tests/compile-fail/getrandom.rs | 10 ++++++++++ tests/run-pass/hashmap.rs | 18 ++++++++++++++---- 7 files changed, 88 insertions(+), 13 deletions(-) create mode 100644 tests/compile-fail/getrandom.rs diff --git a/Cargo.toml b/Cargo.toml index d580d4b8ec17..6c77315bea48 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,8 @@ shell-escape = "0.1.4" # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` # for more information. rustc-workspace-hack = "1.0.0" +hex = "0.3.2" +rand = "0.6.5" [build-dependencies] vergen = "3" diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index e54be4644f25..ce2ad1a2715d 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -48,7 +48,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.node { if i.attrs.iter().any(|attr| attr.check_name("test")) { - let config = MiriConfig { validate: true, args: vec![] }; + let config = MiriConfig { validate: true, args: vec![], seed: None }; let did = self.0.hir().body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); miri::eval_main(self.0, did, config); @@ -61,7 +61,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { } tcx.hir().krate().visit_all_item_likes(&mut Visitor(tcx)); } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { - let config = MiriConfig { validate: true, args: vec![] }; + let config = MiriConfig { validate: true, args: vec![], seed: None }; miri::eval_main(tcx, entry_def_id, config); compiler.session().abort_if_errors(); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 4cc0d955d3c2..7f15d00e2c8a 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -126,6 +126,7 @@ fn main() { // Parse our arguments and split them across `rustc` and `miri`. let mut validate = true; + let mut seed: Option = None; let mut rustc_args = vec![]; let mut miri_args = vec![]; let mut after_dashdash = false; @@ -146,7 +147,22 @@ fn main() { after_dashdash = true; } _ => { - rustc_args.push(arg); + let split: Vec = arg.split("-Zmiri-seed=").map(|s| s.to_owned()).collect(); + if split.len() == 2 { + if seed.is_some() { + panic!("Cannot specify -Zmiri-seed multiple times!"); + } + let seed_raw = hex::decode(&split[1]).unwrap(); + if seed_raw.len() > 8 { + panic!(format!("-Zmiri-seed must be at most 8 bytes, was {}", seed_raw.len())); + } + + let mut bytes = [0; 8]; + bytes[..seed_raw.len()].copy_from_slice(&hex::decode(&split[1]).unwrap()); + seed = Some(u64::from_be_bytes(bytes)); + } else { + rustc_args.push(arg); + } } } } @@ -163,7 +179,7 @@ fn main() { debug!("rustc arguments: {:?}", rustc_args); debug!("miri arguments: {:?}", miri_args); - let miri_config = miri::MiriConfig { validate, args: miri_args }; + let miri_config = miri::MiriConfig { validate, args: miri_args, seed }; let result = rustc_driver::report_ices_to_stderr_if_any(move || { rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None) }).and_then(|result| result); diff --git a/src/fn_call.rs b/src/fn_call.rs index 038f5ed8a047..ba610e8b230c 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -4,6 +4,8 @@ use rustc::hir::def_id::DefId; use rustc::mir; use syntax::attr; +use rand::RngCore; + use crate::*; impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} @@ -216,9 +218,32 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' // is called if a `HashMap` is created the regular way. match this.read_scalar(args[0])?.to_usize(this)? { 318 | 511 => { - return err!(Unimplemented( - "miri does not support random number generators".to_owned(), - )) + match this.machine.rng.as_ref() { + Some(rng) => { + let ptr = this.read_scalar(args[1])?.to_ptr()?; + let len = this.read_scalar(args[2])?.to_usize(this)?; + + // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, + // neither of which have any effect on our current PRNG + let _flags = this.read_scalar(args[3])?.to_i32()?; + + let mut data = vec![0; len as usize]; + rng.borrow_mut().fill_bytes(&mut data); + + this.memory_mut().get_mut(ptr.alloc_id)? + .write_bytes(tcx, ptr, &data)?; + + this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; + + }, + None => { + return err!(Unimplemented( + "miri does not support random number generators in deterministic mode! + Use '-Zmiri-seed=' to enable random number generation".to_owned(), + )) + } + } + } id => { return err!(Unimplemented( diff --git a/src/lib.rs b/src/lib.rs index be58c6a6a464..9b4b69b6d707 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,6 +23,10 @@ mod stacked_borrows; use std::collections::HashMap; use std::borrow::Cow; +use std::cell::RefCell; + +use rand::rngs::StdRng; +use rand::SeedableRng; use rustc::ty::{self, TyCtxt, query::TyCtxtAt}; use rustc::ty::layout::{LayoutOf, Size, Align}; @@ -60,6 +64,9 @@ pub fn miri_default_args() -> &'static [&'static str] { pub struct MiriConfig { pub validate: bool, pub args: Vec, + + // The seed to use when non-determinism is required (e.g. getrandom()) + pub seed: Option } // Used by priroda. @@ -71,7 +78,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let mut ecx = InterpretCx::new( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), - Evaluator::new(config.validate), + Evaluator::new(config.validate, config.seed), ); let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); @@ -326,10 +333,14 @@ pub struct Evaluator<'tcx> { /// Stacked Borrows state. pub(crate) stacked_borrows: stacked_borrows::State, + + /// The random number generator to use if Miri + /// is running in non-deterministic mode + pub(crate) rng: Option> } impl<'tcx> Evaluator<'tcx> { - fn new(validate: bool) -> Self { + fn new(validate: bool, seed: Option) -> Self { Evaluator { env_vars: HashMap::default(), argc: None, @@ -339,6 +350,7 @@ impl<'tcx> Evaluator<'tcx> { tls: TlsData::default(), validate, stacked_borrows: stacked_borrows::State::default(), + rng: seed.map(|s| RefCell::new(StdRng::seed_from_u64(s))) } } } diff --git a/tests/compile-fail/getrandom.rs b/tests/compile-fail/getrandom.rs new file mode 100644 index 000000000000..85148a724ebc --- /dev/null +++ b/tests/compile-fail/getrandom.rs @@ -0,0 +1,10 @@ +#![feature(rustc_private)] +extern crate libc; + +fn main() { + let mut buf = [0u8; 5]; + unsafe { + libc::syscall(libc::SYS_getrandom, &mut buf as &mut [u8] as *mut [u8] as *mut u8 as *mut libc::c_void, 5, 0); + //~^ ERROR constant evaluation error: miri does not support random number generators in deterministic mode! + } +} diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass/hashmap.rs index d89a5ab535f6..a663c9659524 100644 --- a/tests/run-pass/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -1,8 +1,9 @@ -use std::collections::{self, HashMap}; -use std::hash::BuildHasherDefault; +// compile-flags: -Zmiri-seed=0000000000000000 -fn main() { - let mut map : HashMap> = Default::default(); +use std::collections::{self, HashMap}; +use std::hash::{BuildHasherDefault, BuildHasher}; + +fn test_map(mut map: HashMap) { map.insert(0, 0); assert_eq!(map.values().fold(0, |x, y| x+y), 0); @@ -22,4 +23,13 @@ fn main() { assert_eq!(map.values().fold(0, |x, y| x+y), num*(num-1)/2); // TODO: Test Entry API, Iterators, ... + +} + +fn main() { + let map : HashMap> = Default::default(); + let map_normal: HashMap = HashMap::new(); + + test_map(map); + test_map(map_normal); } From fdefac8599a385a87de02f06d5a77f726a524904 Mon Sep 17 00:00:00 2001 From: Tim Diekmann Date: Mon, 8 Apr 2019 01:26:52 +0200 Subject: [PATCH 0639/5092] Fix calloc test Forgot to free the memory. Miri found the bug :) --- tests/run-pass/calloc.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/run-pass/calloc.rs b/tests/run-pass/calloc.rs index 8e8e2e5f10f4..4c520da85e87 100644 --- a/tests/run-pass/calloc.rs +++ b/tests/run-pass/calloc.rs @@ -17,10 +17,10 @@ fn main() { let p3 = libc::calloc(0, 20); assert!(p3.is_null()); - let p4 = libc::calloc(4, 8) as *const u8; + let p4 = libc::calloc(4, 8); assert!(!p4.is_null()); - - let slice = slice::from_raw_parts(p4, 4 * 8); + let slice = slice::from_raw_parts(p4 as *const u8, 4 * 8); assert_eq!(&slice, &[0_u8; 4 * 8]); + libc::free(p4); } } From 312f938e791178eccca51ee22126d1ef06f50f9b Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 7 Apr 2019 19:30:37 -0400 Subject: [PATCH 0640/5092] Fix benchmark --- benches/helpers/miri_helper.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 01fef16e4a97..44a94cd61a0b 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -24,7 +24,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { ); self.bencher.iter(|| { - let config = miri::MiriConfig { validate: true, args: vec![] }; + let config = miri::MiriConfig { validate: true, args: vec![], seed: None }; eval_main(tcx, entry_def_id, config); }); }); From dddeda7f7d14ef410bf938e3197587cc8d5ac7da Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 7 Apr 2019 19:57:14 -0400 Subject: [PATCH 0641/5092] Use getrandom() syscall number from libc --- Cargo.toml | 1 + src/fn_call.rs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6c77315bea48..b0e278c1b54c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,7 @@ shell-escape = "0.1.4" rustc-workspace-hack = "1.0.0" hex = "0.3.2" rand = "0.6.5" +libc = "0.2.51" [build-dependencies] vergen = "3" diff --git a/src/fn_call.rs b/src/fn_call.rs index ba610e8b230c..74352302f36e 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -216,8 +216,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' // // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` // is called if a `HashMap` is created the regular way. - match this.read_scalar(args[0])?.to_usize(this)? { - 318 | 511 => { + match this.read_scalar(args[0])?.to_usize(this)? as i64 { + libc::SYS_getrandom => { match this.machine.rng.as_ref() { Some(rng) => { let ptr = this.read_scalar(args[1])?.to_ptr()?; From 808b1496710b369ceeddc0ef833af12c663ef6e4 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 7 Apr 2019 20:08:15 -0400 Subject: [PATCH 0642/5092] Use raw syscall numbers --- Cargo.toml | 1 - src/fn_call.rs | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b0e278c1b54c..6c77315bea48 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,7 +46,6 @@ shell-escape = "0.1.4" rustc-workspace-hack = "1.0.0" hex = "0.3.2" rand = "0.6.5" -libc = "0.2.51" [build-dependencies] vergen = "3" diff --git a/src/fn_call.rs b/src/fn_call.rs index 74352302f36e..52f252da5cfa 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -217,7 +217,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` // is called if a `HashMap` is created the regular way. match this.read_scalar(args[0])?.to_usize(this)? as i64 { - libc::SYS_getrandom => { + // SYS_getrandom on x86_64 and x86 respectively + 318 | 355 => { match this.machine.rng.as_ref() { Some(rng) => { let ptr = this.read_scalar(args[1])?.to_ptr()?; From 32d01263a96d1dfca9b484aba74f97a887c4a24a Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Mon, 8 Apr 2019 10:44:02 +0200 Subject: [PATCH 0643/5092] Update src/fn_call.rs Co-Authored-By: TimDiekmann <21277928+TimDiekmann@users.noreply.github.com> --- src/fn_call.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 2db23bd48c54..83eb37708e8e 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -98,7 +98,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' let len = this.read_scalar(args[1])?.to_usize(this)?; let bytes = items.checked_mul(len).ok_or_else(|| InterpError::Overflow(mir::BinOp::Mul))?; - if bytes== 0 { + if bytes == 0 { this.write_null(dest)?; } else { let size = Size::from_bytes(bytes); From 06af617b92680b791875a2b0d88700ac9253b8f0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 8 Apr 2019 13:40:11 +0200 Subject: [PATCH 0644/5092] fix dumping uninitialized locals --- src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index be58c6a6a464..728d32f969d3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -264,9 +264,7 @@ pub fn eval_main<'a, 'tcx: 'a>( trace!("Frame {}", i); trace!(" return: {:#?}", frame.return_place); for (i, local) in frame.locals.iter().enumerate() { - if let Ok(local) = local.access() { - trace!(" local {}: {:?}", i, local); - } + trace!(" local {}: {:?}", i, local.value); } } } From 5530d295ad2c4900c3c8ab80abb5b5258b99446b Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 8 Apr 2019 21:36:35 -0400 Subject: [PATCH 0645/5092] Simplify cast using as_mut_ptr() --- tests/compile-fail/getrandom.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile-fail/getrandom.rs b/tests/compile-fail/getrandom.rs index 85148a724ebc..58a39ea3156d 100644 --- a/tests/compile-fail/getrandom.rs +++ b/tests/compile-fail/getrandom.rs @@ -4,7 +4,7 @@ extern crate libc; fn main() { let mut buf = [0u8; 5]; unsafe { - libc::syscall(libc::SYS_getrandom, &mut buf as &mut [u8] as *mut [u8] as *mut u8 as *mut libc::c_void, 5, 0); + libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr() as *mut libc::c_void, 5, 0); //~^ ERROR constant evaluation error: miri does not support random number generators in deterministic mode! } } From 6b0440e26d3e51aef9841ac47914b729416b25c9 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 8 Apr 2019 21:40:52 -0400 Subject: [PATCH 0646/5092] Cleanup argument parsing --- src/bin/miri.rs | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 7f15d00e2c8a..6e68f803f858 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -146,23 +146,22 @@ fn main() { "--" => { after_dashdash = true; } - _ => { - let split: Vec = arg.split("-Zmiri-seed=").map(|s| s.to_owned()).collect(); - if split.len() == 2 { - if seed.is_some() { - panic!("Cannot specify -Zmiri-seed multiple times!"); - } - let seed_raw = hex::decode(&split[1]).unwrap(); - if seed_raw.len() > 8 { - panic!(format!("-Zmiri-seed must be at most 8 bytes, was {}", seed_raw.len())); - } - - let mut bytes = [0; 8]; - bytes[..seed_raw.len()].copy_from_slice(&hex::decode(&split[1]).unwrap()); - seed = Some(u64::from_be_bytes(bytes)); - } else { - rustc_args.push(arg); + arg if arg.starts_with("-Zmiri-seed=") => { + if seed.is_some() { + panic!("Cannot specify -Zmiri-seed multiple times!"); } + let seed_raw = hex::decode(arg.trim_start_matches("-Zmiri-seed=")).unwrap(); + if seed_raw.len() > 8 { + panic!(format!("-Zmiri-seed must be at most 8 bytes, was {}", seed_raw.len())); + } + + let mut bytes = [0; 8]; + bytes[..seed_raw.len()].copy_from_slice(&seed_raw); + seed = Some(u64::from_be_bytes(bytes)); + + }, + _ => { + rustc_args.push(arg); } } } From b120e8bb88271bc7fbe68651f230ead35de098a1 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 8 Apr 2019 21:42:12 -0400 Subject: [PATCH 0647/5092] Only run test with default hasher --- tests/run-pass/hashmap.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass/hashmap.rs index a663c9659524..94add0078f7c 100644 --- a/tests/run-pass/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -27,9 +27,8 @@ fn test_map(mut map: HashMap) { } fn main() { - let map : HashMap> = Default::default(); + let _map : HashMap> = Default::default(); let map_normal: HashMap = HashMap::new(); - test_map(map); test_map(map_normal); } From 6d3e93c2815c61e3293c85189dce1424c842bfc5 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 8 Apr 2019 22:22:41 -0400 Subject: [PATCH 0648/5092] Refactor random number generation --- src/fn_call.rs | 61 ++++++++++++++++++++------------- tests/compile-fail/getrandom.rs | 2 +- 2 files changed, 39 insertions(+), 24 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 52f252da5cfa..0f1814a0c42c 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -215,36 +215,22 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' // figure out some way to actually process some of them. // // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` - // is called if a `HashMap` is created the regular way. + // is called if a `HashMap` is created the regular way (e.g. HashMap). match this.read_scalar(args[0])?.to_usize(this)? as i64 { // SYS_getrandom on x86_64 and x86 respectively 318 | 355 => { - match this.machine.rng.as_ref() { - Some(rng) => { - let ptr = this.read_scalar(args[1])?.to_ptr()?; - let len = this.read_scalar(args[2])?.to_usize(this)?; + let ptr = this.read_scalar(args[1])?.to_ptr()?; + let len = this.read_scalar(args[2])?.to_usize(this)?; - // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, - // neither of which have any effect on our current PRNG - let _flags = this.read_scalar(args[3])?.to_i32()?; + // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, + // neither of which have any effect on our current PRNG + let _flags = this.read_scalar(args[3])?.to_i32()?; - let mut data = vec![0; len as usize]; - rng.borrow_mut().fill_bytes(&mut data); - - this.memory_mut().get_mut(ptr.alloc_id)? + let data = gen_random(this, len as usize)?; + this.memory_mut().get_mut(ptr.alloc_id)? .write_bytes(tcx, ptr, &data)?; - this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; - - }, - None => { - return err!(Unimplemented( - "miri does not support random number generators in deterministic mode! - Use '-Zmiri-seed=' to enable random number generation".to_owned(), - )) - } - } - + this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; } id => { return err!(Unimplemented( @@ -768,6 +754,17 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' "GetCommandLineW" => { this.write_scalar(Scalar::Ptr(this.machine.cmd_line.unwrap()), dest)?; } + // The actual name of 'RtlGenRandom' + "SystemFunction036" => { + let ptr = this.read_scalar(args[1])?.to_ptr()?; + let len = this.read_scalar(args[2])?.to_usize(this)?; + + let data = gen_random(this, len as usize)?; + this.memory_mut().get_mut(ptr.alloc_id)? + .write_bytes(tcx, ptr, &data)?; + + this.write_scalar(Scalar::from_bool(true), dest)?; + } // We can't execute anything else. _ => { @@ -786,3 +783,21 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest) } } + +fn gen_random<'a, 'mir, 'tcx>(this: &mut MiriEvalContext<'a, 'mir, 'tcx>, + len: usize) -> Result, EvalError<'tcx>> { + + match this.machine.rng.as_ref() { + Some(rng) => { + let mut data = vec![0; len]; + rng.borrow_mut().fill_bytes(&mut data); + Ok(data) + } + None => { + err!(Unimplemented( + "miri does not support random number generators in deterministic mode! + Use '-Zmiri-seed=' to enable random number generation".to_owned(), + )) + } + } +} diff --git a/tests/compile-fail/getrandom.rs b/tests/compile-fail/getrandom.rs index 58a39ea3156d..efa7a86fee08 100644 --- a/tests/compile-fail/getrandom.rs +++ b/tests/compile-fail/getrandom.rs @@ -4,7 +4,7 @@ extern crate libc; fn main() { let mut buf = [0u8; 5]; unsafe { - libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr() as *mut libc::c_void, 5, 0); + libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, 0 as libc::c_uint); //~^ ERROR constant evaluation error: miri does not support random number generators in deterministic mode! } } From 858e82bc6f56114545f2be472210ebef84d2e4b2 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 8 Apr 2019 22:29:40 -0400 Subject: [PATCH 0649/5092] Disable normal HashMap test on OS X Implementing random number generation on OS X will require special-casing the 'openat' system call to special-case reading from /dev/urandom --- tests/run-pass/hashmap.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass/hashmap.rs index 94add0078f7c..d0de8b448b09 100644 --- a/tests/run-pass/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -28,7 +28,12 @@ fn test_map(mut map: HashMap) { fn main() { let _map : HashMap> = Default::default(); - let map_normal: HashMap = HashMap::new(); - test_map(map_normal); + // TODO: Implement random number generation on OS X + if cfg!(not(target_os = "darwin")) { + let map_normal: HashMap = HashMap::new(); + test_map(map_normal); + } else { + test_map(_map); + } } From 5f997645bccb5776d17deafb8101c7575b41c08f Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 8 Apr 2019 22:37:58 -0400 Subject: [PATCH 0650/5092] Interpret system call numbers relative to target architecture --- src/fn_call.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 0f1814a0c42c..94e1f11ccf79 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -216,9 +216,9 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' // // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` // is called if a `HashMap` is created the regular way (e.g. HashMap). - match this.read_scalar(args[0])?.to_usize(this)? as i64 { + match (this.read_scalar(args[0])?.to_usize(this)? as i64, tcx.data_layout.pointer_size.bits()) { // SYS_getrandom on x86_64 and x86 respectively - 318 | 355 => { + (318, 64) | (355, 32) => { let ptr = this.read_scalar(args[1])?.to_ptr()?; let len = this.read_scalar(args[2])?.to_usize(this)?; @@ -232,7 +232,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; } - id => { + (id, _size) => { return err!(Unimplemented( format!("miri does not support syscall ID {}", id), )) From 174874420b09082d4feef0fe25a6cdf14fca3309 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 8 Apr 2019 22:48:57 -0400 Subject: [PATCH 0651/5092] OS X is "macos", not "darwin" --- tests/run-pass/hashmap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass/hashmap.rs index d0de8b448b09..a95f7170aa1b 100644 --- a/tests/run-pass/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -30,7 +30,7 @@ fn main() { let _map : HashMap> = Default::default(); // TODO: Implement random number generation on OS X - if cfg!(not(target_os = "darwin")) { + if cfg!(not(target_os = "macos")) { let map_normal: HashMap = HashMap::new(); test_map(map_normal); } else { From 5e07ff6b1f1f5e8906a571a59855013ee49bdd30 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 8 Apr 2019 23:16:13 -0400 Subject: [PATCH 0652/5092] Only run 'getrandom' test on Linux --- tests/compile-fail/getrandom.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/compile-fail/getrandom.rs b/tests/compile-fail/getrandom.rs index efa7a86fee08..dcd3869c1445 100644 --- a/tests/compile-fail/getrandom.rs +++ b/tests/compile-fail/getrandom.rs @@ -1,3 +1,5 @@ +// only-linux + #![feature(rustc_private)] extern crate libc; From 6b4c5b81da314ff29adcf341ba80faff00fa1bb0 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 8 Apr 2019 23:18:10 -0400 Subject: [PATCH 0653/5092] Fix 'RtlGenRandom' argument slots --- src/fn_call.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 94e1f11ccf79..8a586c7705b3 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -756,8 +756,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } // The actual name of 'RtlGenRandom' "SystemFunction036" => { - let ptr = this.read_scalar(args[1])?.to_ptr()?; - let len = this.read_scalar(args[2])?.to_usize(this)?; + let ptr = this.read_scalar(args[0])?.to_ptr()?; + let len = this.read_scalar(args[1])?.to_usize(this)?; let data = gen_random(this, len as usize)?; this.memory_mut().get_mut(ptr.alloc_id)? From 92436805885c28cfee7cb52d2b2fe742e4c3cb4f Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 8 Apr 2019 23:52:33 -0400 Subject: [PATCH 0654/5092] Use 'ignore-' instead of 'only-' Apparently 'ignore-' doesn't work with compiletest_rs --- tests/compile-fail/getrandom.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/compile-fail/getrandom.rs b/tests/compile-fail/getrandom.rs index dcd3869c1445..7f2087a320a4 100644 --- a/tests/compile-fail/getrandom.rs +++ b/tests/compile-fail/getrandom.rs @@ -1,4 +1,5 @@ -// only-linux +// ignore-macos +// ignore-windows #![feature(rustc_private)] extern crate libc; From 22044c878d2a29902d05a4d66604f797207570d7 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 9 Apr 2019 10:16:32 -0400 Subject: [PATCH 0655/5092] Improve deterministic mode error message --- src/fn_call.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 8a586c7705b3..b97c23741281 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -795,8 +795,10 @@ fn gen_random<'a, 'mir, 'tcx>(this: &mut MiriEvalContext<'a, 'mir, 'tcx>, } None => { err!(Unimplemented( - "miri does not support random number generators in deterministic mode! - Use '-Zmiri-seed=' to enable random number generation".to_owned(), + "miri does not support gathering system entropy in deterministic mode! + Use '-Zmiri-seed=' to enable random number generation. + WARNING: Miri does *not* generate cryptographically secure entropy - + do not use Miri to run any program that need secure random number generation".to_owned(), )) } } From ae8e7f654a002d182fe66cdbd3ebfe0ee1e74ae2 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 9 Apr 2019 10:19:29 -0400 Subject: [PATCH 0656/5092] Fix compile-fail error message --- tests/compile-fail/getrandom.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile-fail/getrandom.rs b/tests/compile-fail/getrandom.rs index 7f2087a320a4..4dc3e863aaae 100644 --- a/tests/compile-fail/getrandom.rs +++ b/tests/compile-fail/getrandom.rs @@ -8,6 +8,6 @@ fn main() { let mut buf = [0u8; 5]; unsafe { libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, 0 as libc::c_uint); - //~^ ERROR constant evaluation error: miri does not support random number generators in deterministic mode! + //~^ ERROR constant evaluation error: miri does not support gathering system entropy in deterministic mode! } } From c6e0d097143a90ec8512a087b6cd3a475d2aeff1 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 9 Apr 2019 11:04:30 -0400 Subject: [PATCH 0657/5092] Retrieve SYS_getrandom from libc using const-eval --- src/fn_call.rs | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index b97c23741281..3eacaaa74e65 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -211,14 +211,14 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } "syscall" => { - // TODO: read `syscall` IDs like `sysconf` IDs and - // figure out some way to actually process some of them. - // + let sys_getrandom = this.eval_path_scalar(&["libc", "SYS_getrandom"])? + .expect("Failed to get libc::SYS_getrandom") + .to_usize(this)? as i64; + // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` // is called if a `HashMap` is created the regular way (e.g. HashMap). - match (this.read_scalar(args[0])?.to_usize(this)? as i64, tcx.data_layout.pointer_size.bits()) { - // SYS_getrandom on x86_64 and x86 respectively - (318, 64) | (355, 32) => { + match this.read_scalar(args[0])?.to_usize(this)? as i64 { + id if id == sys_getrandom => { let ptr = this.read_scalar(args[1])?.to_ptr()?; let len = this.read_scalar(args[2])?.to_usize(this)?; @@ -232,7 +232,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; } - (id, _size) => { + id => { return err!(Unimplemented( format!("miri does not support syscall ID {}", id), )) @@ -496,18 +496,13 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' ]; let mut result = None; for &(path, path_value) in paths { - if let Ok(instance) = this.resolve_path(path) { - let cid = GlobalId { - instance, - promoted: None, - }; - let const_val = this.const_eval_raw(cid)?; - let const_val = this.read_scalar(const_val.into())?; - let value = const_val.to_i32()?; - if value == name { + if let Some(val) = this.eval_path_scalar(path)? { + let val = val.to_i32()?; + if val == name { result = Some(path_value); break; } + } } if let Some(result) = result { @@ -782,6 +777,22 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' fn write_null(&mut self, dest: PlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> { self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest) } + + /// Evaluates the scalar at the specified path. Returns Some(val) + /// if the path could be resolved, and None otherwise + fn eval_path_scalar(&mut self, path: &[&str]) -> EvalResult<'tcx, Option>> { + let this = self.eval_context_mut(); + if let Ok(instance) = this.resolve_path(path) { + let cid = GlobalId { + instance, + promoted: None, + }; + let const_val = this.const_eval_raw(cid)?; + let const_val = this.read_scalar(const_val.into())?; + return Ok(Some(const_val)); + } + return Ok(None); + } } fn gen_random<'a, 'mir, 'tcx>(this: &mut MiriEvalContext<'a, 'mir, 'tcx>, From 0837d630f7becb8259074a2adc35e77476e5083e Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 9 Apr 2019 15:49:34 -0400 Subject: [PATCH 0658/5092] Some final cleanup --- src/fn_call.rs | 14 ++++++++------ src/lib.rs | 5 ++--- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 3eacaaa74e65..50351e2c7045 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -213,11 +213,11 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' "syscall" => { let sys_getrandom = this.eval_path_scalar(&["libc", "SYS_getrandom"])? .expect("Failed to get libc::SYS_getrandom") - .to_usize(this)? as i64; + .to_usize(this)?; // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` // is called if a `HashMap` is created the regular way (e.g. HashMap). - match this.read_scalar(args[0])?.to_usize(this)? as i64 { + match this.read_scalar(args[0])?.to_usize(this)? { id if id == sys_getrandom => { let ptr = this.read_scalar(args[1])?.to_ptr()?; let len = this.read_scalar(args[2])?.to_usize(this)?; @@ -795,13 +795,15 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } } -fn gen_random<'a, 'mir, 'tcx>(this: &mut MiriEvalContext<'a, 'mir, 'tcx>, - len: usize) -> Result, EvalError<'tcx>> { +fn gen_random<'a, 'mir, 'tcx>( + this: &mut MiriEvalContext<'a, 'mir, 'tcx>, + len: usize, +) -> Result, EvalError<'tcx>> { - match this.machine.rng.as_ref() { + match &mut this.machine.rng { Some(rng) => { let mut data = vec![0; len]; - rng.borrow_mut().fill_bytes(&mut data); + rng.fill_bytes(&mut data); Ok(data) } None => { diff --git a/src/lib.rs b/src/lib.rs index 9b4b69b6d707..d185ec610c9a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,7 +23,6 @@ mod stacked_borrows; use std::collections::HashMap; use std::borrow::Cow; -use std::cell::RefCell; use rand::rngs::StdRng; use rand::SeedableRng; @@ -336,7 +335,7 @@ pub struct Evaluator<'tcx> { /// The random number generator to use if Miri /// is running in non-deterministic mode - pub(crate) rng: Option> + pub(crate) rng: Option } impl<'tcx> Evaluator<'tcx> { @@ -350,7 +349,7 @@ impl<'tcx> Evaluator<'tcx> { tls: TlsData::default(), validate, stacked_borrows: stacked_borrows::State::default(), - rng: seed.map(|s| RefCell::new(StdRng::seed_from_u64(s))) + rng: seed.map(|s| StdRng::seed_from_u64(s)) } } } From 48b22b80c5e4977fd638d67e9494d85df5cb912e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 9 Apr 2019 23:33:13 -0400 Subject: [PATCH 0659/5092] Fix typo Co-Authored-By: Aaron1011 --- src/fn_call.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index a0ff614de20a..3e12c1dd1c6d 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -826,7 +826,7 @@ fn gen_random<'a, 'mir, 'tcx>( "miri does not support gathering system entropy in deterministic mode! Use '-Zmiri-seed=' to enable random number generation. WARNING: Miri does *not* generate cryptographically secure entropy - - do not use Miri to run any program that need secure random number generation".to_owned(), + do not use Miri to run any program that needs secure random number generation".to_owned(), )) } } From a8763f3d8d8e362f49090e8d99a86920f2e55fef Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 9 Apr 2019 23:36:27 -0400 Subject: [PATCH 0660/5092] Don't create HashMap when not needed --- tests/run-pass/hashmap.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass/hashmap.rs index a95f7170aa1b..b29b68193979 100644 --- a/tests/run-pass/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -27,13 +27,12 @@ fn test_map(mut map: HashMap) { } fn main() { - let _map : HashMap> = Default::default(); - // TODO: Implement random number generation on OS X if cfg!(not(target_os = "macos")) { let map_normal: HashMap = HashMap::new(); test_map(map_normal); } else { - test_map(_map); + let map : HashMap> = Default::default(); + test_map(map); } } From 83d199eb86c107087ad40fab1c98ceb1d799b2de Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 10 Apr 2019 17:20:54 +0200 Subject: [PATCH 0661/5092] fix async-fn test --- tests/run-pass/async-fn.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 79fcb59011f6..7af2304cb400 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -1,4 +1,3 @@ -// ignore-test FIXME ignored to let https://github.com/rust-lang/rust/pull/59119 land #![feature( async_await, await_macro, @@ -6,7 +5,7 @@ )] use std::{future::Future, pin::Pin, task::Poll, ptr}; -use std::task::{Waker, RawWaker, RawWakerVTable}; +use std::task::{Waker, RawWaker, RawWakerVTable, Context}; // See if we can run a basic `async fn` pub async fn foo(x: &u32, y: u32) -> u32 { @@ -27,15 +26,16 @@ fn raw_waker_wake(_this: *const ()) { } fn raw_waker_drop(_this: *const ()) {} -static RAW_WAKER: RawWakerVTable = RawWakerVTable { - clone: raw_waker_clone, - wake: raw_waker_wake, - drop: raw_waker_drop, -}; +static RAW_WAKER: RawWakerVTable = RawWakerVTable::new( + raw_waker_clone, + raw_waker_wake, + raw_waker_drop, +); fn main() { let x = 5; let mut fut = foo(&x, 7); let waker = unsafe { Waker::new_unchecked(RawWaker::new(ptr::null(), &RAW_WAKER)) }; - assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&waker), Poll::Ready(31)); + let mut context = Context::from_waker(&waker); + assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(31)); } From 8235f5694cccdb131f1a26f94eb7a9bc8f9e3117 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Apr 2019 22:09:27 +0200 Subject: [PATCH 0662/5092] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index a2b3daad97ec..69a46de1d45d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -f717b58dd70829f105960a071c7992b440720482 +3de0106789468b211bcc3a25c09c0cf07119186d From 5f29a539921298fd4d36b1574c01de35e8f6e7a3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 12 Apr 2019 12:32:14 +0200 Subject: [PATCH 0663/5092] rustup --- rust-version | 2 +- src/fn_call.rs | 6 +++--- src/intrinsic.rs | 10 +++++----- src/lib.rs | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/rust-version b/rust-version index 69a46de1d45d..9e2c1a36bb4f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -3de0106789468b211bcc3a25c09c0cf07119186d +2226c09699a96520238e162777f44504f4a0a1a7 diff --git a/src/fn_call.rs b/src/fn_call.rs index 3e12c1dd1c6d..bb6d6aed4905 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -62,11 +62,11 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { - Some(name) => name.as_str().get(), - None => this.tcx.item_name(def_id).as_str().get(), + Some(name) => name.as_str(), + None => this.tcx.item_name(def_id).as_str(), }; // Strip linker suffixes (seen on 32-bit macOS). - let link_name = link_name.trim_end_matches("$UNIX2003"); + let link_name = link_name.get().trim_end_matches("$UNIX2003"); let tcx = &{this.tcx.tcx}; // First: functions that could diverge. diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 5b0f0e99ad84..bb156c95dfea 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -27,8 +27,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // (as opposed to through a place), we have to remember to erase any tag // that might still hang around! - let intrinsic_name = this.tcx.item_name(instance.def_id()).as_str().get(); - match intrinsic_name { + let intrinsic_name = this.tcx.item_name(instance.def_id()).as_str(); + match intrinsic_name.get() { "arith_offset" => { let offset = this.read_scalar(args[1])?.to_isize(this)?; let ptr = this.read_scalar(args[0])?.not_undef()?; @@ -187,7 +187,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" => { let f = this.read_scalar(args[0])?.to_f32()?; - let f = match intrinsic_name { + let f = match intrinsic_name.get() { "sinf32" => f.sin(), "fabsf32" => f.abs(), "cosf32" => f.cos(), @@ -208,7 +208,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" | "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" => { let f = this.read_scalar(args[0])?.to_f64()?; - let f = match intrinsic_name { + let f = match intrinsic_name.get() { "sinf64" => f.sin(), "fabsf64" => f.abs(), "cosf64" => f.cos(), @@ -229,7 +229,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { let a = this.read_immediate(args[0])?; let b = this.read_immediate(args[1])?; - let op = match intrinsic_name { + let op = match intrinsic_name.get() { "fadd_fast" => mir::BinOp::Add, "fsub_fast" => mir::BinOp::Sub, "fmul_fast" => mir::BinOp::Mul, diff --git a/src/lib.rs b/src/lib.rs index ba9b69703a41..541986de5517 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -470,11 +470,11 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> { let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { - Some(name) => name.as_str().get(), - None => tcx.item_name(def_id).as_str().get(), + Some(name) => name.as_str(), + None => tcx.item_name(def_id).as_str(), }; - let alloc = match link_name { + let alloc = match link_name.get() { "__cxa_thread_atexit_impl" => { // This should be all-zero, pointer-sized. let size = tcx.data_layout.pointer_size; From aa79244b62c7a4506213829629f4993daa6f0cf5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 12 Apr 2019 22:15:55 +0200 Subject: [PATCH 0664/5092] rustup --- rust-version | 2 +- tests/run-pass/async-fn.rs | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 9e2c1a36bb4f..29649e957f2c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -2226c09699a96520238e162777f44504f4a0a1a7 +df25d79a33b0c82b716699a75a41bfdc6089850a diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 7af2304cb400..1608ea188894 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -24,18 +24,22 @@ fn raw_waker_clone(_this: *const ()) -> RawWaker { fn raw_waker_wake(_this: *const ()) { panic!("unimplemented"); } +fn raw_waker_wake_by_ref(_this: *const ()) { + panic!("unimplemented"); +} fn raw_waker_drop(_this: *const ()) {} static RAW_WAKER: RawWakerVTable = RawWakerVTable::new( raw_waker_clone, raw_waker_wake, + raw_waker_wake_by_ref, raw_waker_drop, ); fn main() { let x = 5; let mut fut = foo(&x, 7); - let waker = unsafe { Waker::new_unchecked(RawWaker::new(ptr::null(), &RAW_WAKER)) }; + let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &RAW_WAKER)) }; let mut context = Context::from_waker(&waker); assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(31)); } From 98296d60e7d5db8296748e263eca2c55026ef056 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 12 Apr 2019 23:17:58 +0200 Subject: [PATCH 0665/5092] lower rand version requirement --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 6c77315bea48..bb86795270fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,7 +45,7 @@ shell-escape = "0.1.4" # for more information. rustc-workspace-hack = "1.0.0" hex = "0.3.2" -rand = "0.6.5" +rand = "0.6" [build-dependencies] vergen = "3" From a246116bdc6bc42fed360a1267de4f99492be791 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Apr 2019 10:30:00 +0200 Subject: [PATCH 0666/5092] rustup --- rust-version | 2 +- tests/compile-fail/deallocate-bad-alignment.rs | 2 +- tests/compile-fail/deallocate-bad-size.rs | 2 +- tests/compile-fail/deallocate-twice.rs | 2 +- tests/compile-fail/reallocate-bad-size.rs | 2 +- tests/compile-fail/reallocate-change-alloc.rs | 2 +- tests/compile-fail/reallocate-dangling.rs | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rust-version b/rust-version index 29649e957f2c..dcee3ec5daa7 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -df25d79a33b0c82b716699a75a41bfdc6089850a +ee621f42329069c296b4c2066b3743cc4ff0f369 diff --git a/tests/compile-fail/deallocate-bad-alignment.rs b/tests/compile-fail/deallocate-bad-alignment.rs index 4b89f0ac70c7..d124136a9653 100644 --- a/tests/compile-fail/deallocate-bad-alignment.rs +++ b/tests/compile-fail/deallocate-bad-alignment.rs @@ -1,4 +1,4 @@ -#![feature(alloc, allocator_api)] +#![feature(allocator_api)] extern crate alloc; diff --git a/tests/compile-fail/deallocate-bad-size.rs b/tests/compile-fail/deallocate-bad-size.rs index 3a74245816c4..7a95b0ac7e90 100644 --- a/tests/compile-fail/deallocate-bad-size.rs +++ b/tests/compile-fail/deallocate-bad-size.rs @@ -1,4 +1,4 @@ -#![feature(alloc, allocator_api)] +#![feature(allocator_api)] extern crate alloc; diff --git a/tests/compile-fail/deallocate-twice.rs b/tests/compile-fail/deallocate-twice.rs index 613edf3c6af9..03fab76d601b 100644 --- a/tests/compile-fail/deallocate-twice.rs +++ b/tests/compile-fail/deallocate-twice.rs @@ -1,4 +1,4 @@ -#![feature(alloc, allocator_api)] +#![feature(allocator_api)] extern crate alloc; diff --git a/tests/compile-fail/reallocate-bad-size.rs b/tests/compile-fail/reallocate-bad-size.rs index 489b7bebcdc8..24d913205447 100644 --- a/tests/compile-fail/reallocate-bad-size.rs +++ b/tests/compile-fail/reallocate-bad-size.rs @@ -1,4 +1,4 @@ -#![feature(alloc, allocator_api)] +#![feature(allocator_api)] extern crate alloc; diff --git a/tests/compile-fail/reallocate-change-alloc.rs b/tests/compile-fail/reallocate-change-alloc.rs index 1e2178811ea3..312edfd52b27 100644 --- a/tests/compile-fail/reallocate-change-alloc.rs +++ b/tests/compile-fail/reallocate-change-alloc.rs @@ -1,4 +1,4 @@ -#![feature(alloc, allocator_api)] +#![feature(allocator_api)] extern crate alloc; diff --git a/tests/compile-fail/reallocate-dangling.rs b/tests/compile-fail/reallocate-dangling.rs index 6dfb7fe2b966..450f63cc40d3 100644 --- a/tests/compile-fail/reallocate-dangling.rs +++ b/tests/compile-fail/reallocate-dangling.rs @@ -1,4 +1,4 @@ -#![feature(alloc, allocator_api)] +#![feature(allocator_api)] extern crate alloc; From 378d9d41720fe2a8a2aec1b39551d11fac6d8ec6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 17:47:37 +0200 Subject: [PATCH 0667/5092] be pragmatic about ptr-int comparisons, for now --- src/operator.rs | 18 ++++++++++++++---- tests/run-pass/vecs.rs | 4 ++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index a30b11aeb27d..45c0e63542dc 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -152,8 +152,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // This accepts one-past-the end. Thus, there is still technically // some non-determinism that we do not fully rule out when two // allocations sit right next to each other. The C/C++ standards are - // somewhat fuzzy about this case, so I think for now this check is - // "good enough". + // somewhat fuzzy about this case, so pragmatically speaking I think + // for now this check is "good enough". + // FIXME: Once we support intptrcast, we could try to fix these holes. // Dead allocations in miri cannot overlap with live allocations, but // on read hardware this can easily happen. Thus for comparisons we require // both pointers to be live. @@ -169,8 +170,17 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' assert_eq!(size as u64, self.pointer_size().bytes()); let bits = bits as u64; - // Case I: Comparing with NULL. - if bits == 0 { + // Case I: Comparing real pointers with "small" integers. + // Really we should only do this for NULL, but pragmatically speaking on non-bare-metal systems, + // an allocation will never be at the very bottom of the address space. + // Such comparisons can arise when comparing empty slices, which sometimes are "fake" + // integer pointers (okay because the slice is empty) and sometimes point into a + // real allocation. + // The most common source of such integer pointers is `NonNull::dangling()`, which + // equals the type's alignment. i128 might have an alignment of 16 bytes, but few types have + // alignment 32 or higher, hence the limit of 32. + // FIXME: Once we support intptrcast, we could try to fix these holes. + if bits < 32 { // Test if the ptr is in-bounds. Then it cannot be NULL. // Even dangling pointers cannot be NULL. if self.memory().check_bounds_ptr(ptr, InboundsCheck::MaybeDead).is_ok() { diff --git a/tests/run-pass/vecs.rs b/tests/run-pass/vecs.rs index bb9e5068f91e..739def804975 100644 --- a/tests/run-pass/vecs.rs +++ b/tests/run-pass/vecs.rs @@ -85,4 +85,8 @@ fn main() { assert_eq!(make_vec_macro(), [1, 2]); assert_eq!(make_vec_macro_repeat(), [42; 5]); assert_eq!(make_vec_macro_repeat_zeroed(), [0; 7]); + + // Test interesting empty slice comparison + // (one is a real pointer, one an integer pointer). + assert_eq!((200..-5).step_by(1).collect::>(), []); } From ceca7c502057fedee2e77329df4ec23b1bebaa03 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 19:06:08 +0200 Subject: [PATCH 0668/5092] tweak entropy tests a bit --- tests/compile-fail/getrandom.rs | 4 ++-- tests/run-pass/hashmap.rs | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/compile-fail/getrandom.rs b/tests/compile-fail/getrandom.rs index 4dc3e863aaae..d54c95c82385 100644 --- a/tests/compile-fail/getrandom.rs +++ b/tests/compile-fail/getrandom.rs @@ -1,5 +1,5 @@ -// ignore-macos -// ignore-windows +// ignore-macos: Uses Linux-only APIs +// ignore-windows: Uses Linux-only APIs #![feature(rustc_private)] extern crate libc; diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass/hashmap.rs index b29b68193979..796e63c81a41 100644 --- a/tests/run-pass/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -27,12 +27,13 @@ fn test_map(mut map: HashMap) { } fn main() { - // TODO: Implement random number generation on OS X if cfg!(not(target_os = "macos")) { - let map_normal: HashMap = HashMap::new(); - test_map(map_normal); + let map: HashMap = HashMap::default(); + test_map(map); } else { - let map : HashMap> = Default::default(); + // TODO: Implement random number generation on OS X. + // Until then, use a deterministic map. + let map : HashMap> = HashMap::default(); test_map(map); } } From af2b42de0a43c0bf656e290e73a431acd033e79d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 19:09:37 +0200 Subject: [PATCH 0669/5092] fix compile-fail test --- tests/compile-fail/ptr_eq_integer.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/compile-fail/ptr_eq_integer.rs b/tests/compile-fail/ptr_eq_integer.rs index 10d5fbd517a3..396abaf4493b 100644 --- a/tests/compile-fail/ptr_eq_integer.rs +++ b/tests/compile-fail/ptr_eq_integer.rs @@ -1,8 +1,6 @@ -use std::mem; - fn main() { let b = Box::new(0); let x = &*b as *const i32; // We cannot compare this with a non-NULL integer. After all, these *could* be equal (with the right base address). - assert!(x != mem::align_of::() as *const i32); //~ ERROR invalid arithmetic on pointers + assert!(x != 64 as *const i32); //~ ERROR invalid arithmetic on pointers } From bd4a772e1a87180f31da81f7d11ef07cff042bbf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 19:12:56 +0200 Subject: [PATCH 0670/5092] update cargo miri test to test rng crate a bit; this currently fails --- test-cargo-miri/run-test.py | 2 +- test-cargo-miri/test.stdout.ref | 5 +++-- test-cargo-miri/tests/test.rs | 10 +++++++++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 8c59b6bcdead..f1412dbf3969 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -43,7 +43,7 @@ def test_cargo_miri_run(): ) def test_cargo_miri_test(): - test("cargo miri test", ["cargo", "miri", "test", "-q"], "test.stdout.ref", "test.stderr.ref") + test("cargo miri test", ["cargo", "miri", "test", "-q", "--", "-Zmiri-seed=feed"], "test.stdout.ref", "test.stderr.ref") test("cargo miri test (with filter)", ["cargo", "miri", "test", "-q", "--", "--", "impl"], "test.stdout.ref2", "test.stderr.ref" diff --git a/test-cargo-miri/test.stdout.ref b/test-cargo-miri/test.stdout.ref index 9c3621f21535..318057a7d9e6 100644 --- a/test-cargo-miri/test.stdout.ref +++ b/test-cargo-miri/test.stdout.ref @@ -5,9 +5,10 @@ test test::rng ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out -running 2 tests +running 3 tests test rng ... ok +test seeded_rng ... ok test simple ... ok -test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index e9faaf2fb2f1..6f7876d679b6 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -1,6 +1,6 @@ extern crate rand; -use rand::{Rng, SeedableRng}; +use rand::{SeedableRng, FromEntropy, Rng, rngs::SmallRng}; #[test] fn simple() { @@ -17,6 +17,14 @@ fn rng() { assert_ne!(x, y); } +#[test] +#[cfg(not(target_os="macos"))] // FIXME entropy does not work on macOS +fn seeded_rng() { + // Use this opportunity to test querying the RNG (needs an external crate, hence tested here and not in the compiletest suite) + let mut rng = SmallRng::from_entropy(); + let _val = rng.gen::(); +} + // A test that won't work on miri #[cfg(not(miri))] #[test] From 9c8ad5f9e199d45b7c2425389ef718ce65071be2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 19:26:02 +0200 Subject: [PATCH 0671/5092] fix 0-sized getrandom --- src/fn_call.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index bb6d6aed4905..718f1c24ac79 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -241,9 +241,11 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' // neither of which have any effect on our current PRNG let _flags = this.read_scalar(args[3])?.to_i32()?; - let data = gen_random(this, len as usize)?; - this.memory_mut().get_mut(ptr.alloc_id)? - .write_bytes(tcx, ptr, &data)?; + if len > 0 { + let data = gen_random(this, len as usize)?; + this.memory_mut().get_mut(ptr.alloc_id)? + .write_bytes(tcx, ptr, &data)?; + } this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; } @@ -769,9 +771,11 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' let ptr = this.read_scalar(args[0])?.to_ptr()?; let len = this.read_scalar(args[1])?.to_usize(this)?; - let data = gen_random(this, len as usize)?; - this.memory_mut().get_mut(ptr.alloc_id)? - .write_bytes(tcx, ptr, &data)?; + if len > 0 { + let data = gen_random(this, len as usize)?; + this.memory_mut().get_mut(ptr.alloc_id)? + .write_bytes(tcx, ptr, &data)?; + } this.write_scalar(Scalar::from_bool(true), dest)?; } From ba567d19f09f105d7ed03808d2220b27fc0b8893 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 19:49:36 +0200 Subject: [PATCH 0672/5092] stub out pthread_atfork to that we support thread_rng() --- src/fn_call.rs | 5 +++++ test-cargo-miri/tests/test.rs | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/src/fn_call.rs b/src/fn_call.rs index 718f1c24ac79..bb9eef0c8721 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -624,6 +624,11 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' this.write_null(dest)?; } + // We don't support fork so we don't have to do anything for atfork. + "pthread_atfork" => { + this.write_null(dest)?; + } + "mmap" => { // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. let addr = this.read_scalar(args[0])?.not_undef()?; diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 6f7876d679b6..1812ca59c417 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -23,6 +23,10 @@ fn seeded_rng() { // Use this opportunity to test querying the RNG (needs an external crate, hence tested here and not in the compiletest suite) let mut rng = SmallRng::from_entropy(); let _val = rng.gen::(); + + // Also try per-thread RNG. + let mut rng = rand::thread_rng(); + let _val = rng.gen::(); } // A test that won't work on miri From 5761a0bf61fe932699c0547849da792f4fb2c4fa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 19:55:22 +0200 Subject: [PATCH 0673/5092] fix ref file --- test-cargo-miri/test.stdout.ref2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-cargo-miri/test.stdout.ref2 b/test-cargo-miri/test.stdout.ref2 index ce3506709d5a..32d943623a91 100644 --- a/test-cargo-miri/test.stdout.ref2 +++ b/test-cargo-miri/test.stdout.ref2 @@ -7,5 +7,5 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out running 1 test test simple ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out From 59541d446aabc3b0a15bc1ba2a3f28eeb7608285 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 20:12:55 +0200 Subject: [PATCH 0674/5092] pick better test names --- test-cargo-miri/test.stdout.ref | 4 ++-- test-cargo-miri/tests/test.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test-cargo-miri/test.stdout.ref b/test-cargo-miri/test.stdout.ref index 318057a7d9e6..97589e9a1635 100644 --- a/test-cargo-miri/test.stdout.ref +++ b/test-cargo-miri/test.stdout.ref @@ -6,8 +6,8 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out running 3 tests -test rng ... ok -test seeded_rng ... ok +test entropy_rng ... ok +test fixed_rng ... ok test simple ... ok test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 1812ca59c417..cea14d0d1ca2 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -10,7 +10,7 @@ fn simple() { // Having more than 1 test does seem to make a difference // (i.e., this calls ptr::swap which having just one test does not). #[test] -fn rng() { +fn fixed_rng() { let mut rng = rand::rngs::StdRng::seed_from_u64(0xdeadcafe); let x: u32 = rng.gen(); let y: u32 = rng.gen(); @@ -19,7 +19,7 @@ fn rng() { #[test] #[cfg(not(target_os="macos"))] // FIXME entropy does not work on macOS -fn seeded_rng() { +fn entropy_rng() { // Use this opportunity to test querying the RNG (needs an external crate, hence tested here and not in the compiletest suite) let mut rng = SmallRng::from_entropy(); let _val = rng.gen::(); From 341798f09da757d18aa6e139748134561b610d00 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 20:14:23 +0200 Subject: [PATCH 0675/5092] fix tests on macOS --- test-cargo-miri/tests/test.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index cea14d0d1ca2..7b6aaf934ec7 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -1,3 +1,5 @@ +#![allow(unused_imports)] // FIXME for macOS + extern crate rand; use rand::{SeedableRng, FromEntropy, Rng, rngs::SmallRng}; From 54039cafa83e58f271261d730dd9bf6bf78fffba Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 20:36:33 +0200 Subject: [PATCH 0676/5092] try to really fix tests on macOS --- test-cargo-miri/tests/test.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 7b6aaf934ec7..69a31c42a75c 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -20,15 +20,18 @@ fn fixed_rng() { } #[test] -#[cfg(not(target_os="macos"))] // FIXME entropy does not work on macOS fn entropy_rng() { - // Use this opportunity to test querying the RNG (needs an external crate, hence tested here and not in the compiletest suite) - let mut rng = SmallRng::from_entropy(); - let _val = rng.gen::(); + #[cfg(not(target_os="macos"))] // FIXME entropy does not work on macOS + // (Not disabling the entire test as that would change the output.) + { + // Use this opportunity to test querying the RNG (needs an external crate, hence tested here and not in the compiletest suite) + let mut rng = SmallRng::from_entropy(); + let _val = rng.gen::(); - // Also try per-thread RNG. - let mut rng = rand::thread_rng(); - let _val = rng.gen::(); + // Also try per-thread RNG. + let mut rng = rand::thread_rng(); + let _val = rng.gen::(); + } } // A test that won't work on miri From a50512f75134d13a71c0cd99d698f21f17523f7f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 21:04:44 +0200 Subject: [PATCH 0677/5092] fix RtlGenRandom argument size --- src/fn_call.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index bb9eef0c8721..64dcce161dd7 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -774,7 +774,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' // The actual name of 'RtlGenRandom' "SystemFunction036" => { let ptr = this.read_scalar(args[0])?.to_ptr()?; - let len = this.read_scalar(args[1])?.to_usize(this)?; + let len = this.read_scalar(args[1])?.to_u32()?; if len > 0 { let data = gen_random(this, len as usize)?; From d7bcaab7375120da4a08e295f0b8bd7109987998 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Apr 2019 08:20:02 +0200 Subject: [PATCH 0678/5092] document -Zmiri-seed --- README.md | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 75ad2b81bf4b..716c26c03a73 100644 --- a/README.md +++ b/README.md @@ -231,15 +231,23 @@ MIRI_SYSROOT=$(rustc +custom --print sysroot) cargo +custom run --manifest-path Several `-Z` flags are relevant for Miri: -* `-Zmir-opt-level` controls how many MIR optimizations are performed. miri +* `-Zmiri-seed=` is a custom `-Z` flag added by Miri. It enables the + interpreted program to seed an RNG with system entropy. Miri will keep an RNG + on its own that is seeded with the given seed, and use that to generate the + "system entropy" that seeds the RNG(s) in the interpreted program. + **NOTE**: This entropy is not good enough for cryptographic use! Do not + generate secret keys in Miri or perform other kinds of cryptographic + operations that rely on proper random numbers. +* `-Zmiri-disable-validation` disables enforcing the validity invariant, which + is enforced by default. This is mostly useful for debugging; it means Miri + will miss bugs in your program. However, this can also help to make Miri run + faster. +* `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri overrides the default to be `0`; be advised that using any higher level can - make miri miss bugs in your program because they got optimized away. + make Miri miss bugs in your program because they got optimized away. * `-Zalways-encode-mir` makes rustc dump MIR even for completely monomorphic - functions. This is needed so that miri can execute such functions, so miri + functions. This is needed so that Miri can execute such functions, so Miri sets this flag per default. -* `-Zmiri-disable-validation` is a custom `-Z` flag added by miri. It disables - enforcing the validity invariant, which is enforced by default. This is - mostly useful for debugging; it means miri will miss bugs in your program. Moreover, Miri recognizes some environment variables: From 3f0a2a29414a67d9c52241a94ce373546ca2ddcf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 15 Apr 2019 15:36:09 +0200 Subject: [PATCH 0679/5092] rewrite Stacked Borrows Core. this passes stacked-borrows.rs! --- src/fn_call.rs | 28 +- src/helpers.rs | 24 +- src/intrinsic.rs | 6 +- src/lib.rs | 108 ++--- src/operator.rs | 38 +- src/stacked_borrows.rs | 979 +++++++++++++++++++++-------------------- src/tls.rs | 10 +- 7 files changed, 594 insertions(+), 599 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 64dcce161dd7..d8794fed4694 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -13,8 +13,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' fn find_fn( &mut self, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Borrow>], - dest: Option>, + args: &[OpTy<'tcx, Tag>], + dest: Option>, ret: Option, ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> { let this = self.eval_context_mut(); @@ -55,8 +55,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' fn emulate_foreign_item( &mut self, def_id: DefId, - args: &[OpTy<'tcx, Borrow>], - dest: Option>, + args: &[OpTy<'tcx, Tag>], + dest: Option>, ret: Option, ) -> EvalResult<'tcx> { let this = self.eval_context_mut(); @@ -92,7 +92,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } else { let align = this.tcx.data_layout.pointer_align.abi; let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into()); - this.write_scalar(Scalar::Ptr(ptr.with_default_tag()), dest)?; + this.write_scalar(Scalar::Ptr(ptr), dest)?; } } "calloc" => { @@ -105,7 +105,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } else { let size = Size::from_bytes(bytes); let align = this.tcx.data_layout.pointer_align.abi; - let ptr = this.memory_mut().allocate(size, align, MiriMemoryKind::C.into()).with_default_tag(); + let ptr = this.memory_mut().allocate(size, align, MiriMemoryKind::C.into()); this.memory_mut().get_mut(ptr.alloc_id)?.write_repeat(tcx, ptr, 0, size)?; this.write_scalar(Scalar::Ptr(ptr), dest)?; } @@ -132,7 +132,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' Align::from_bytes(align).unwrap(), MiriMemoryKind::C.into() ); - this.write_scalar(Scalar::Ptr(ptr.with_default_tag()), ret.into())?; + this.write_scalar(Scalar::Ptr(ptr), ret.into())?; } this.write_null(dest)?; } @@ -162,8 +162,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into() - ) - .with_default_tag(); + ); this.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_alloc_zeroed" => { @@ -180,8 +179,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into() - ) - .with_default_tag(); + ); this.memory_mut() .get_mut(ptr.alloc_id)? .write_repeat(tcx, ptr, 0, Size::from_bytes(size))?; @@ -222,7 +220,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into(), )?; - this.write_scalar(Scalar::Ptr(new_ptr.with_default_tag()), dest)?; + this.write_scalar(Scalar::Ptr(new_ptr), dest)?; } "syscall" => { @@ -428,7 +426,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' Size::from_bytes((value.len() + 1) as u64), Align::from_bytes(1).unwrap(), MiriMemoryKind::Env.into(), - ).with_default_tag(); + ); { let alloc = this.memory_mut().get_mut(value_copy.alloc_id)?; alloc.write_bytes(tcx, value_copy, &value)?; @@ -798,13 +796,13 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' Ok(()) } - fn write_null(&mut self, dest: PlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> { + fn write_null(&mut self, dest: PlaceTy<'tcx, Tag>) -> EvalResult<'tcx> { self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest) } /// Evaluates the scalar at the specified path. Returns Some(val) /// if the path could be resolved, and None otherwise - fn eval_path_scalar(&mut self, path: &[&str]) -> EvalResult<'tcx, Option>> { + fn eval_path_scalar(&mut self, path: &[&str]) -> EvalResult<'tcx, Option>> { let this = self.eval_context_mut(); if let Ok(instance) = this.resolve_path(path) { let cid = GlobalId { diff --git a/src/helpers.rs b/src/helpers.rs index 8a4cccc743e6..f468d256031c 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -47,9 +47,9 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' /// will be true if this is frozen, false if this is in an `UnsafeCell`. fn visit_freeze_sensitive( &self, - place: MPlaceTy<'tcx, Borrow>, + place: MPlaceTy<'tcx, Tag>, size: Size, - mut action: impl FnMut(Pointer, Size, bool) -> EvalResult<'tcx>, + mut action: impl FnMut(Pointer, Size, bool) -> EvalResult<'tcx>, ) -> EvalResult<'tcx> { let this = self.eval_context_ref(); trace!("visit_frozen(place={:?}, size={:?})", *place, size); @@ -64,7 +64,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' let mut end_ptr = place.ptr; // Called when we detected an `UnsafeCell` at the given offset and size. // Calls `action` and advances `end_ptr`. - let mut unsafe_cell_action = |unsafe_cell_ptr: Scalar, unsafe_cell_size: Size| { + let mut unsafe_cell_action = |unsafe_cell_ptr: Scalar, unsafe_cell_size: Size| { if unsafe_cell_size != Size::ZERO { debug_assert_eq!(unsafe_cell_ptr.to_ptr().unwrap().alloc_id, end_ptr.to_ptr().unwrap().alloc_id); @@ -120,7 +120,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' /// Visiting the memory covered by a `MemPlace`, being aware of /// whether we are inside an `UnsafeCell` or not. struct UnsafeCellVisitor<'ecx, 'a, 'mir, 'tcx, F> - where F: FnMut(MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> + where F: FnMut(MPlaceTy<'tcx, Tag>) -> EvalResult<'tcx> { ecx: &'ecx MiriEvalContext<'a, 'mir, 'tcx>, unsafe_cell_action: F, @@ -131,9 +131,9 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' for UnsafeCellVisitor<'ecx, 'a, 'mir, 'tcx, F> where - F: FnMut(MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> + F: FnMut(MPlaceTy<'tcx, Tag>) -> EvalResult<'tcx> { - type V = MPlaceTy<'tcx, Borrow>; + type V = MPlaceTy<'tcx, Tag>; #[inline(always)] fn ecx(&self) -> &MiriEvalContext<'a, 'mir, 'tcx> { @@ -141,7 +141,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } // Hook to detect `UnsafeCell`. - fn visit_value(&mut self, v: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> + fn visit_value(&mut self, v: MPlaceTy<'tcx, Tag>) -> EvalResult<'tcx> { trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty); let is_unsafe_cell = match v.layout.ty.sty { @@ -163,8 +163,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' // Make sure we visit aggregrates in increasing offset order. fn visit_aggregate( &mut self, - place: MPlaceTy<'tcx, Borrow>, - fields: impl Iterator>>, + place: MPlaceTy<'tcx, Tag>, + fields: impl Iterator>>, ) -> EvalResult<'tcx> { match place.layout.fields { layout::FieldPlacement::Array { .. } => { @@ -174,7 +174,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } layout::FieldPlacement::Arbitrary { .. } => { // Gather the subplaces and sort them before visiting. - let mut places = fields.collect::>>>()?; + let mut places = fields.collect::>>>()?; places.sort_by_key(|place| place.ptr.get_ptr_offset(self.ecx())); self.walk_aggregate(place, places.into_iter().map(Ok)) } @@ -186,7 +186,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } // We have to do *something* for unions. - fn visit_union(&mut self, v: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> + fn visit_union(&mut self, v: MPlaceTy<'tcx, Tag>) -> EvalResult<'tcx> { // With unions, we fall back to whatever the type says, to hopefully be consistent // with LLVM IR. @@ -200,7 +200,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } // We should never get to a primitive, but always short-circuit somewhere above. - fn visit_primitive(&mut self, _v: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> + fn visit_primitive(&mut self, _v: MPlaceTy<'tcx, Tag>) -> EvalResult<'tcx> { bug!("we should always short-circuit before coming to a primitive") } diff --git a/src/intrinsic.rs b/src/intrinsic.rs index bb156c95dfea..a17f576b43b7 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -4,7 +4,7 @@ use rustc::ty::layout::{self, LayoutOf, Size}; use rustc::ty; use crate::{ - PlaceTy, OpTy, ImmTy, Immediate, Scalar, ScalarMaybeUndef, Borrow, + PlaceTy, OpTy, ImmTy, Immediate, Scalar, ScalarMaybeUndef, Tag, OperatorEvalContextExt }; @@ -13,8 +13,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, fn call_intrinsic( &mut self, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Borrow>], - dest: PlaceTy<'tcx, Borrow>, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag>, ) -> EvalResult<'tcx> { let this = self.eval_context_mut(); if this.emulate_intrinsic(instance, args, dest)? { diff --git a/src/lib.rs b/src/lib.rs index 541986de5517..3dbe922999da 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,6 +23,7 @@ mod stacked_borrows; use std::collections::HashMap; use std::borrow::Cow; +use std::rc::Rc; use rand::rngs::StdRng; use rand::SeedableRng; @@ -48,7 +49,7 @@ use crate::mono_hash_map::MonoHashMap; pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; // Used by priroda. -pub use crate::stacked_borrows::{Borrow, Stack, Stacks, BorStackItem}; +pub use crate::stacked_borrows::{Tag, Permission, Stack, Stacks, Item}; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. @@ -155,7 +156,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // Don't forget `0` terminator. cmd.push(std::char::from_u32(0).unwrap()); // Collect the pointers to the individual strings. - let mut argvs = Vec::>::new(); + let mut argvs = Vec::>::new(); for arg in config.args { // Add `0` terminator. let mut arg = arg.into_bytes(); @@ -187,7 +188,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( Size::from_bytes(cmd_utf16.len() as u64 * 2), Align::from_bytes(2).unwrap(), MiriMemoryKind::Env.into(), - ).with_default_tag(); + ); ecx.machine.cmd_line = Some(cmd_ptr); // Store the UTF-16 string. let char_size = Size::from_bytes(2); @@ -214,7 +215,13 @@ pub fn eval_main<'a, 'tcx: 'a>( main_id: DefId, config: MiriConfig, ) { - let mut ecx = create_ecx(tcx, main_id, config).expect("couldn't create ecx"); + let mut ecx = match create_ecx(tcx, main_id, config) { + Ok(ecx) => ecx, + Err(mut err) => { + err.print_backtrace(); + panic!("Miri initialziation error: {}", err.kind) + } + }; // Perform the main execution. let res: EvalResult = (|| { @@ -310,14 +317,14 @@ impl MayLeak for MiriMemoryKind { pub struct Evaluator<'tcx> { /// Environment variables set by `setenv`. /// Miri does not expose env vars from the host to the emulated program. - pub(crate) env_vars: HashMap, Pointer>, + pub(crate) env_vars: HashMap, Pointer>, /// Program arguments (`Option` because we can only initialize them after creating the ecx). /// These are *pointers* to argc/argv because macOS. /// We also need the full command line as one string because of Windows. - pub(crate) argc: Option>, - pub(crate) argv: Option>, - pub(crate) cmd_line: Option>, + pub(crate) argc: Option>, + pub(crate) argv: Option>, + pub(crate) cmd_line: Option>, /// Last OS error. pub(crate) last_error: u32, @@ -328,9 +335,6 @@ pub struct Evaluator<'tcx> { /// Whether to enforce the validity invariant. pub(crate) validate: bool, - /// Stacked Borrows state. - pub(crate) stacked_borrows: stacked_borrows::State, - /// The random number generator to use if Miri /// is running in non-deterministic mode pub(crate) rng: Option @@ -346,7 +350,6 @@ impl<'tcx> Evaluator<'tcx> { last_error: 0, tls: TlsData::default(), validate, - stacked_borrows: stacked_borrows::State::default(), rng: seed.map(|s| StdRng::seed_from_u64(s)) } } @@ -378,9 +381,9 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { type FrameExtra = stacked_borrows::CallId; type MemoryExtra = stacked_borrows::MemoryState; type AllocExtra = stacked_borrows::Stacks; - type PointerTag = Borrow; + type PointerTag = Tag; - type MemoryMap = MonoHashMap, Allocation)>; + type MemoryMap = MonoHashMap, Allocation)>; const STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); @@ -394,8 +397,8 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn find_fn( ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Borrow>], - dest: Option>, + args: &[OpTy<'tcx, Tag>], + dest: Option>, ret: Option, ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> { ecx.find_fn(instance, args, dest, ret) @@ -405,8 +408,8 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn call_intrinsic( ecx: &mut rustc_mir::interpret::InterpretCx<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Borrow>], - dest: PlaceTy<'tcx, Borrow>, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag>, ) -> EvalResult<'tcx> { ecx.call_intrinsic(instance, args, dest) } @@ -415,15 +418,15 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn ptr_op( ecx: &rustc_mir::interpret::InterpretCx<'a, 'mir, 'tcx, Self>, bin_op: mir::BinOp, - left: ImmTy<'tcx, Borrow>, - right: ImmTy<'tcx, Borrow>, - ) -> EvalResult<'tcx, (Scalar, bool)> { + left: ImmTy<'tcx, Tag>, + right: ImmTy<'tcx, Tag>, + ) -> EvalResult<'tcx, (Scalar, bool)> { ecx.ptr_op(bin_op, left, right) } fn box_alloc( ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, - dest: PlaceTy<'tcx, Borrow>, + dest: PlaceTy<'tcx, Tag>, ) -> EvalResult<'tcx> { trace!("box_alloc for {:?}", dest.layout.ty); // Call the `exchange_malloc` lang item. @@ -467,7 +470,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { def_id: DefId, tcx: TyCtxtAt<'a, 'tcx, 'tcx>, memory_extra: &Self::MemoryExtra, - ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> { + ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> { let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { Some(name) => name.as_str(), @@ -479,7 +482,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { // This should be all-zero, pointer-sized. let size = tcx.data_layout.pointer_size; let data = vec![0; size.bytes() as usize]; - let extra = AllocationExtra::memory_allocated(size, memory_extra); + let extra = Stacks::new(size, Tag::default(), Rc::clone(memory_extra)); Allocation::from_bytes(&data, tcx.data_layout.pointer_align.abi, extra) } _ => return err!(Unimplemented( @@ -499,16 +502,17 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn adjust_static_allocation<'b>( alloc: &'b Allocation, memory_extra: &Self::MemoryExtra, - ) -> Cow<'b, Allocation> { - let extra = AllocationExtra::memory_allocated( + ) -> Cow<'b, Allocation> { + let extra = Stacks::new( Size::from_bytes(alloc.bytes.len() as u64), - memory_extra, + Tag::default(), + Rc::clone(memory_extra), ); - let alloc: Allocation = Allocation { + let alloc: Allocation = Allocation { bytes: alloc.bytes.clone(), relocations: Relocations::from_presorted( alloc.relocations.iter() - .map(|&(offset, ((), alloc))| (offset, (Borrow::default(), alloc))) + .map(|&(offset, ((), alloc))| (offset, (Tag::default(), alloc))) .collect() ), undef_mask: alloc.undef_mask.clone(), @@ -519,46 +523,30 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { Cow::Owned(alloc) } - fn tag_dereference( - ecx: &InterpretCx<'a, 'mir, 'tcx, Self>, - place: MPlaceTy<'tcx, Borrow>, - mutability: Option, - ) -> EvalResult<'tcx, Scalar> { - let size = ecx.size_and_align_of_mplace(place)?.map(|(size, _)| size) - // For extern types, just cover what we can. - .unwrap_or_else(|| place.layout.size); - if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || - !Self::enforce_validity(ecx) || size == Size::ZERO - { - // No tracking. - Ok(place.ptr) - } else { - ecx.ptr_dereference(place, size, mutability.into())?; - // We never change the pointer. - Ok(place.ptr) - } + #[inline(always)] + fn new_allocation( + size: Size, + extra: &Self::MemoryExtra, + kind: MemoryKind, + ) -> (Self::AllocExtra, Self::PointerTag) { + Stacks::new_allocation(size, extra, kind) } #[inline(always)] - fn tag_new_allocation( - ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, - ptr: Pointer, - kind: MemoryKind, - ) -> Pointer { - if !ecx.machine.validate { - // No tracking. - ptr.with_default_tag() - } else { - let tag = ecx.tag_new_allocation(ptr.alloc_id, kind); - Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag) - } + fn tag_dereference( + _ecx: &InterpretCx<'a, 'mir, 'tcx, Self>, + place: MPlaceTy<'tcx, Tag>, + _mutability: Option, + ) -> EvalResult<'tcx, Scalar> { + // Nothing happens. + Ok(place.ptr) } #[inline(always)] fn retag( ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, kind: mir::RetagKind, - place: PlaceTy<'tcx, Borrow>, + place: PlaceTy<'tcx, Tag>, ) -> EvalResult<'tcx> { if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !Self::enforce_validity(ecx) { // No tracking, or no retagging. The latter is possible because a dependency of ours diff --git a/src/operator.rs b/src/operator.rs index 45c0e63542dc..386fc4307b87 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -7,39 +7,39 @@ pub trait EvalContextExt<'tcx> { fn ptr_op( &self, bin_op: mir::BinOp, - left: ImmTy<'tcx, Borrow>, - right: ImmTy<'tcx, Borrow>, - ) -> EvalResult<'tcx, (Scalar, bool)>; + left: ImmTy<'tcx, Tag>, + right: ImmTy<'tcx, Tag>, + ) -> EvalResult<'tcx, (Scalar, bool)>; fn ptr_int_arithmetic( &self, bin_op: mir::BinOp, - left: Pointer, + left: Pointer, right: u128, signed: bool, - ) -> EvalResult<'tcx, (Scalar, bool)>; + ) -> EvalResult<'tcx, (Scalar, bool)>; fn ptr_eq( &self, - left: Scalar, - right: Scalar, + left: Scalar, + right: Scalar, ) -> EvalResult<'tcx, bool>; fn pointer_offset_inbounds( &self, - ptr: Scalar, + ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Scalar>; + ) -> EvalResult<'tcx, Scalar>; } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { fn ptr_op( &self, bin_op: mir::BinOp, - left: ImmTy<'tcx, Borrow>, - right: ImmTy<'tcx, Borrow>, - ) -> EvalResult<'tcx, (Scalar, bool)> { + left: ImmTy<'tcx, Tag>, + right: ImmTy<'tcx, Tag>, + ) -> EvalResult<'tcx, (Scalar, bool)> { use rustc::mir::BinOp::*; trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); @@ -136,8 +136,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' fn ptr_eq( &self, - left: Scalar, - right: Scalar, + left: Scalar, + right: Scalar, ) -> EvalResult<'tcx, bool> { let size = self.pointer_size(); Ok(match (left, right) { @@ -233,13 +233,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' fn ptr_int_arithmetic( &self, bin_op: mir::BinOp, - left: Pointer, + left: Pointer, right: u128, signed: bool, - ) -> EvalResult<'tcx, (Scalar, bool)> { + ) -> EvalResult<'tcx, (Scalar, bool)> { use rustc::mir::BinOp::*; - fn map_to_primval((res, over): (Pointer, bool)) -> (Scalar, bool) { + fn map_to_primval((res, over): (Pointer, bool)) -> (Scalar, bool) { (Scalar::Ptr(res), over) } @@ -327,10 +327,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' /// allocation, and all the remaining integers pointers their own allocation. fn pointer_offset_inbounds( &self, - ptr: Scalar, + ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Scalar> { + ) -> EvalResult<'tcx, Scalar> { // FIXME: assuming here that type size is less than `i64::max_value()`. let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; let offset = offset diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index bea6aaf9cf89..080200b12a4e 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -1,6 +1,8 @@ use std::cell::RefCell; use std::collections::HashSet; use std::rc::Rc; +use std::fmt; +use std::num::NonZeroU64; use rustc::ty::{self, layout::Size}; use rustc::hir::{Mutability, MutMutable, MutImmutable}; @@ -8,120 +10,163 @@ use rustc::mir::RetagKind; use crate::{ EvalResult, InterpError, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, - MemoryKind, MiriMemoryKind, RangeMap, AllocId, Allocation, AllocationExtra, + MemoryKind, MiriMemoryKind, RangeMap, Allocation, AllocationExtra, Pointer, Immediate, ImmTy, PlaceTy, MPlaceTy, }; -pub type Timestamp = u64; +pub type PtrId = NonZeroU64; pub type CallId = u64; -/// Information about which kind of borrow was used to create the reference this is tagged with. +/// Tracking pointer provenance #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -pub enum Borrow { - /// A unique (mutable) reference. - Uniq(Timestamp), - /// An aliasing reference. This is also used by raw pointers, which do not track details - /// of how or when they were created, hence the timestamp is optional. - /// `Shr(Some(_))` does *not* mean that the destination of this reference is frozen; - /// that depends on the type! Only those parts outside of an `UnsafeCell` are actually - /// frozen. - Alias(Option), +pub enum Tag { + Tagged(PtrId), + Untagged, } -impl Borrow { - #[inline(always)] - pub fn is_aliasing(self) -> bool { +impl fmt::Display for Tag { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - Borrow::Alias(_) => true, - _ => false, - } - } - - #[inline(always)] - pub fn is_unique(self) -> bool { - match self { - Borrow::Uniq(_) => true, - _ => false, + Tag::Tagged(id) => write!(f, "{}", id), + Tag::Untagged => write!(f, ""), } } } -impl Default for Borrow { - fn default() -> Self { - Borrow::Alias(None) - } +/// Indicates which permission is granted (by this item to some pointers) +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub enum Permission { + /// Grants unique mutable access. + Unique, + /// Grants shared mutable access. + SharedReadWrite, + /// Greants shared read-only access. + SharedReadOnly, } /// An item in the per-location borrow stack. #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -pub enum BorStackItem { - /// Indicates the unique reference that may mutate. - Uniq(Timestamp), - /// Indicates that the location has been mutably shared. Used for raw pointers as - /// well as for unfrozen shared references. - Raw, +pub enum Item { + /// Grants the given permission for pointers with this tag. + Permission(Permission, Tag), /// A barrier, tracking the function it belongs to by its index on the call stack. - FnBarrier(CallId) + FnBarrier(CallId), +} + +impl fmt::Display for Item { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Item::Permission(perm, tag) => write!(f, "[{:?} for {}]", perm, tag), + Item::FnBarrier(call) => write!(f, "[barrier {}]", call), + } + } } /// Extra per-location state. #[derive(Clone, Debug, PartialEq, Eq)] pub struct Stack { - /// Used as the stack; never empty. - borrows: Vec, - /// A virtual frozen "item" on top of the stack. - frozen_since: Option, + /// Used *mostly* as a stack; never empty. + /// We sometimes push into the middle but never remove from the middle. + /// The same tag may occur multiple times, e.g. from a two-phase borrow. + /// Invariants: + /// * Above a `SharedReadOnly` there can only be barriers and more `SharedReadOnly`. + borrows: Vec, } -impl Stack { - #[inline(always)] - pub fn is_frozen(&self) -> bool { - self.frozen_since.is_some() - } + +/// Extra per-allocation state. +#[derive(Clone, Debug)] +pub struct Stacks { + // Even reading memory can have effects on the stack, so we need a `RefCell` here. + stacks: RefCell>, + // Pointer to global state + global: MemoryState, } -/// Indicates which kind of reference is being used. -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -pub enum RefKind { - /// `&mut`. - Unique, - /// `&` without interior mutability. - Frozen, - /// `*` (raw pointer) or `&` to `UnsafeCell`. - Raw, +/// Extra global state, available to the memory access hooks. +#[derive(Debug)] +pub struct GlobalState { + next_ptr_id: PtrId, + next_call_id: CallId, + active_calls: HashSet, } +pub type MemoryState = Rc>; /// Indicates which kind of access is being performed. #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum AccessKind { Read, - Write, - Dealloc, + Write { dealloc: bool }, } -/// Extra global state in the memory, available to the memory access hooks. -#[derive(Debug)] -pub struct BarrierTracking { - next_id: CallId, - active_calls: HashSet, -} -pub type MemoryState = Rc>; +// "Fake" constructors +impl AccessKind { + fn write() -> AccessKind { + AccessKind::Write { dealloc: false } + } -impl Default for BarrierTracking { + fn dealloc() -> AccessKind { + AccessKind::Write { dealloc: true } + } +} + +impl fmt::Display for AccessKind { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + AccessKind::Read => write!(f, "read"), + AccessKind::Write { dealloc: false } => write!(f, "write"), + AccessKind::Write { dealloc: true } => write!(f, "deallocation"), + } + } +} + +/// Indicates which kind of reference is being created. +/// Used by `reborrow` to compute which permissions to grant to the +/// new pointer. +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub enum RefKind { + /// `&mut`. + Mutable, + /// `&` with or without interior mutability. + Shared { frozen: bool }, + /// `*` (raw pointer). + Raw, +} + +impl fmt::Display for RefKind { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + RefKind::Mutable => write!(f, "mutable"), + RefKind::Shared { frozen: true } => write!(f, "shared (frozen)"), + RefKind::Shared { frozen: false } => write!(f, "shared (mutable)"), + RefKind::Raw => write!(f, "raw"), + } + } +} + +/// Utilities for initialization and ID generation +impl Default for GlobalState { fn default() -> Self { - BarrierTracking { - next_id: 0, + GlobalState { + next_ptr_id: NonZeroU64::new(1).unwrap(), + next_call_id: 0, active_calls: HashSet::default(), } } } -impl BarrierTracking { +impl GlobalState { + pub fn new_ptr(&mut self) -> PtrId { + let id = self.next_ptr_id; + self.next_ptr_id = NonZeroU64::new(id.get() + 1).unwrap(); + id + } + pub fn new_call(&mut self) -> CallId { - let id = self.next_id; + let id = self.next_call_id; trace!("new_call: Assigning ID {}", id); self.active_calls.insert(id); - self.next_id += 1; + self.next_call_id = id+1; id } @@ -134,293 +179,286 @@ impl BarrierTracking { } } -/// Extra global machine state. -#[derive(Clone, Debug)] -pub struct State { - clock: Timestamp -} +// # Stacked Borrows Core Begin -impl Default for State { - fn default() -> Self { - State { clock: 0 } - } -} - -impl State { - fn increment_clock(&mut self) -> Timestamp { - let val = self.clock; - self.clock = val + 1; - val - } -} - -/// Extra per-allocation state. -#[derive(Clone, Debug)] -pub struct Stacks { - // Even reading memory can have effects on the stack, so we need a `RefCell` here. - stacks: RefCell>, - barrier_tracking: MemoryState, -} - -/// Core per-location operations: deref, access, create. /// We need to make at least the following things true: /// /// U1: After creating a `Uniq`, it is at the top (and unfrozen). /// U2: If the top is `Uniq` (and unfrozen), accesses must be through that `Uniq` or pop it. -/// U3: If an access (deref sufficient?) happens with a `Uniq`, it requires the `Uniq` to be in the stack. +/// U3: If an access happens with a `Uniq`, it requires the `Uniq` to be in the stack. /// /// F1: After creating a `&`, the parts outside `UnsafeCell` are frozen. /// F2: If a write access happens, it unfreezes. -/// F3: If an access (well, a deref) happens with an `&` outside `UnsafeCell`, +/// F3: If an access happens with an `&` outside `UnsafeCell`, /// it requires the location to still be frozen. -impl<'tcx> Stack { - /// Deref `bor`: check if the location is frozen and the tag in the stack. - /// This dos *not* constitute an access! "Deref" refers to the `*` operator - /// in Rust, and includs cases like `&*x` or `(*x).foo` where no or only part - /// of the memory actually gets accessed. Also we cannot know if we are - /// going to read or write. - /// Returns the index of the item we matched, `None` if it was the frozen one. - /// `kind` indicates which kind of reference is being dereferenced. - fn deref( - &self, - bor: Borrow, - kind: RefKind, - ) -> Result, String> { - // Exclude unique ref with frozen tag. - if let (RefKind::Unique, Borrow::Alias(Some(_))) = (kind, bor) { - return Err(format!("encountered mutable reference with frozen tag ({:?})", bor)); + +impl Default for Tag { + #[inline(always)] + fn default() -> Tag { + Tag::Untagged + } +} + +/// Core relations on `Permission` define which accesses are allowed: +/// On every access, we try to find a *granting* item, and then we remove all +/// *incompatible* items above it. +impl Permission { + /// This defines for a given permission, whether it permits the given kind of access. + fn grants(self, access: AccessKind) -> bool { + match (self, access) { + // Unique and SharedReadWrite allow any kind of access. + (Permission::Unique, _) | + (Permission::SharedReadWrite, _) => + true, + // SharedReadOnly only permits read access. + (Permission::SharedReadOnly, AccessKind::Read) => + true, + (Permission::SharedReadOnly, AccessKind::Write { .. }) => + false, } - // Checks related to freezing. - match bor { - Borrow::Alias(Some(bor_t)) if kind == RefKind::Frozen => { - // We need the location to be frozen. This ensures F3. - let frozen = self.frozen_since.map_or(false, |itm_t| itm_t <= bor_t); - return if frozen { Ok(None) } else { - Err(format!("location is not frozen long enough")) - } - } - Borrow::Alias(_) if self.frozen_since.is_some() => { - // Shared deref to frozen location; looking good. - return Ok(None) - } - // Not sufficient; go on looking. - _ => {} - } - // If we got here, we have to look for our item in the stack. - for (idx, &itm) in self.borrows.iter().enumerate().rev() { - match (itm, bor) { - (BorStackItem::Uniq(itm_t), Borrow::Uniq(bor_t)) if itm_t == bor_t => { - // Found matching unique item. This satisfies U3. - return Ok(Some(idx)) - } - (BorStackItem::Raw, Borrow::Alias(_)) => { - // Found matching aliasing/raw item. - return Ok(Some(idx)) - } - // Go on looking. We ignore barriers! When an `&mut` and an `&` alias, - // dereferencing the `&` is still possible (to reborrow), but doing - // an access is not. - _ => {} - } - } - // If we got here, we did not find our item. We have to error to satisfy U3. - Err(format!("Borrow being dereferenced ({:?}) does not exist on the borrow stack", bor)) } - /// Performs an actual memory access using `bor`. We do not know any types here - /// or whether things should be frozen, but we *do* know if this is reading - /// or writing. + /// This defines for a given permission, which other items it can tolerate "above" itself + /// for which kinds of accesses. + /// If true, then `other` is allowed to remain on top of `self` when `access` happens. + fn compatible_with(self, access: AccessKind, other: Item) -> bool { + use self::Permission::*; + + let other = match other { + Item::Permission(perm, _) => perm, + Item::FnBarrier(_) => return false, // Remove all barriers -- if they are active, cause UB. + }; + + match (self, access, other) { + // Some cases are impossible. + (SharedReadOnly, _, SharedReadWrite) | + (SharedReadOnly, _, Unique) => + bug!("There can never be a SharedReadWrite or a Unique on top of a SharedReadOnly"), + // When `other` is `SharedReadOnly`, that is NEVER compatible with + // write accesses. + // This makes sure read-only pointers become invalid on write accesses. + (_, AccessKind::Write { .. }, SharedReadOnly) => + false, + // When `other` is `Unique`, that is compatible with nothing. + // This makes sure unique pointers become invalid on incompatible accesses (ensures U2). + (_, _, Unique) => + false, + // When we are unique and this is a write/dealloc, we tolerate nothing. + // This makes sure we re-assert uniqueness on write accesses. + // (This is particularily important such that when a new mutable ref gets created, it gets + // pushed into the right item -- this behaves like a write and we assert uniqueness of the + // pointer from which this comes, *if* it was a unique pointer.) + (Unique, AccessKind::Write { .. }, _) => + false, + // `SharedReadWrite` items can tolerate any other akin items for any kind of access. + (SharedReadWrite, _, SharedReadWrite) => + true, + // Any item can tolerate read accesses for shared items. + // This includes unique items! Reads from unique pointers do not invalidate + // other pointers. + (_, AccessKind::Read, SharedReadWrite) | + (_, AccessKind::Read, SharedReadOnly) => + true, + // That's it. + } + } +} + +impl<'tcx> RefKind { + /// Defines which kind of access the "parent" must grant to create this reference. + fn access(self) -> AccessKind { + match self { + RefKind::Mutable | RefKind::Shared { frozen: false } => AccessKind::write(), + RefKind::Raw | RefKind::Shared { frozen: true } => AccessKind::Read, + // FIXME: Just requiring read-only access for raw means that a raw ptr might not be writeable + // even when we think it should be! Think about this some more. + } + } + + /// This defines the new permission used when a pointer gets created: For raw pointers, whether these are read-only + /// or read-write depends on the permission from which they derive. + fn new_perm(self, derived_from: Permission) -> EvalResult<'tcx, Permission> { + Ok(match (self, derived_from) { + // Do not derive writable safe pointer from read-only pointer! + (RefKind::Mutable, Permission::SharedReadOnly) => + return err!(MachineError(format!( + "deriving mutable reference from read-only pointer" + ))), + (RefKind::Shared { frozen: false }, Permission::SharedReadOnly) => + return err!(MachineError(format!( + "deriving shared reference with interior mutability from read-only pointer" + ))), + // Safe pointer cases. + (RefKind::Mutable, _) => Permission::Unique, + (RefKind::Shared { frozen: true }, _) => Permission::SharedReadOnly, + (RefKind::Shared { frozen: false }, _) => Permission::SharedReadWrite, + // Raw pointer cases. + (RefKind::Raw, Permission::SharedReadOnly) => Permission::SharedReadOnly, + (RefKind::Raw, _) => Permission::SharedReadWrite, + }) + } +} + +/// Core per-location operations: access, create. +impl<'tcx> Stack { + /// Find the item granting the given kind of access to the given tag, and where that item is in the stack. + fn find_granting(&self, access: AccessKind, tag: Tag) -> Option<(usize, Permission)> { + self.borrows.iter() + .enumerate() // we also need to know *where* in the stack + .rev() // search top-to-bottom + // Return permission of first item that grants access. + .filter_map(|(idx, item)| match item { + &Item::Permission(perm, item_tag) if perm.grants(access) && tag == item_tag => + Some((idx, perm)), + _ => None, + }) + .next() + } + + /// Test if a memory `access` using pointer tagged `tag` is granted. + /// If yes, return the index of the item that granted it. fn access( &mut self, - bor: Borrow, - kind: AccessKind, - barrier_tracking: &BarrierTracking, - ) -> EvalResult<'tcx> { - // Check if we can match the frozen "item". - // Not possible on writes! - if self.is_frozen() { - if kind == AccessKind::Read { - // When we are frozen, we just accept all reads. No harm in this. - // The deref already checked that `Uniq` items are in the stack, and that - // the location is frozen if it should be. - return Ok(()); - } - trace!("access: unfreezing"); - } - // Unfreeze on writes. This ensures F2. - self.frozen_since = None; - // Pop the stack until we have something matching. - while let Some(&itm) = self.borrows.last() { - match (itm, bor) { - (BorStackItem::FnBarrier(call), _) if barrier_tracking.is_active(call) => { - return err!(MachineError(format!( - "stopping looking for borrow being accessed ({:?}) because of barrier ({})", - bor, call - ))) - } - (BorStackItem::Uniq(itm_t), Borrow::Uniq(bor_t)) if itm_t == bor_t => { - // Found matching unique item. Continue after the match. - } - (BorStackItem::Raw, _) if kind == AccessKind::Read => { - // When reading, everything can use a raw item! - // We do not want to do this when writing: Writing to an `&mut` - // should reaffirm its exclusivity (i.e., make sure it is - // on top of the stack). Continue after the match. - } - (BorStackItem::Raw, Borrow::Alias(_)) => { - // Found matching raw item. Continue after the match. - } - _ => { - // Pop this, go on. This ensures U2. - let itm = self.borrows.pop().unwrap(); - trace!("access: Popping {:?}", itm); - continue - } - } - // If we got here, we found a matching item. Congratulations! - // However, we are not done yet: If this access is deallocating, we must make sure - // there are no active barriers remaining on the stack. - if kind == AccessKind::Dealloc { - for &itm in self.borrows.iter().rev() { - match itm { - BorStackItem::FnBarrier(call) if barrier_tracking.is_active(call) => { + access: AccessKind, + tag: Tag, + global: &GlobalState, + ) -> EvalResult<'tcx, usize> { + // Two main steps: Find granting item, remove all incompatible items above. + // Afterwards we just do some post-processing for deallocation accesses. + + // Step 1: Find granting item. + let (granting_idx, granting_perm) = self.find_granting(access, tag) + .ok_or_else(|| InterpError::MachineError(format!( + "no item granting {} access to tag {} found in borrow stack", + access, tag, + )))?; + + // Step 2: Remove everything incompatible above them. + // Implemented with indices because there does not seem to be a nice iterator and range-based + // API for this. + { + let mut cur = granting_idx + 1; + while let Some(item) = self.borrows.get(cur) { + if granting_perm.compatible_with(access, *item) { + // Keep this, check next. + cur += 1; + } else { + // Aha! This is a bad one, remove it, and if it is an *active* barrier + // we have a problem. + match self.borrows.remove(cur) { + Item::FnBarrier(call) if global.is_active(call) => { return err!(MachineError(format!( - "deallocating with active barrier ({})", call - ))) + "not granting access because of barrier ({})", call + ))); } - _ => {}, + _ => {} } } } - // Now we are done. - return Ok(()) } - // If we got here, we did not find our item. - err!(MachineError(format!( - "borrow being accessed ({:?}) does not exist on the borrow stack", - bor - ))) - } - /// Initiate `bor`; mostly this means pushing. - /// This operation cannot fail; it is up to the caller to ensure that the precondition - /// is met: We cannot push `Uniq` onto frozen stacks. - /// `kind` indicates which kind of reference is being created. - fn create(&mut self, bor: Borrow, kind: RefKind) { - // When creating a frozen reference, freeze. This ensures F1. - // We also do *not* push anything else to the stack, making sure that no nother kind - // of access (like writing through raw pointers) is permitted. - if kind == RefKind::Frozen { - let bor_t = match bor { - Borrow::Alias(Some(t)) => t, - _ => bug!("Creating illegal borrow {:?} for frozen ref", bor), - }; - // It is possible that we already are frozen (e.g., if we just pushed a barrier, - // the redundancy check would not have kicked in). - match self.frozen_since { - Some(loc_t) => assert!( - loc_t <= bor_t, - "trying to freeze location for longer than it was already frozen" - ), - None => { - trace!("create: Freezing"); - self.frozen_since = Some(bor_t); + // Post-processing. + // If we got here, we found a matching item. Congratulations! + // However, we are not done yet: If this access is deallocating, we must make sure + // there are no active barriers remaining on the stack. + if access == AccessKind::dealloc() { + for &itm in self.borrows.iter().rev() { + match itm { + Item::FnBarrier(call) if global.is_active(call) => { + return err!(MachineError(format!( + "deallocating with active barrier ({})", call + ))) + } + _ => {}, } } - return; } - assert!( - self.frozen_since.is_none(), - "trying to create non-frozen reference to frozen location" - ); - // Push new item to the stack. - let itm = match bor { - Borrow::Uniq(t) => BorStackItem::Uniq(t), - Borrow::Alias(_) => BorStackItem::Raw, - }; - if *self.borrows.last().unwrap() == itm { - // This is just an optimization, no functional change: Avoid stacking - // multiple `Shr` on top of each other. - assert!(bor.is_aliasing()); - trace!("create: sharing a shared location is a NOP"); - } else { - // This ensures U1. - trace!("create: pushing {:?}", itm); - self.borrows.push(itm); - } + // Done. + return Ok(granting_idx); } + /// `reborrow` helper function. + /// Grant `permisson` to new pointer tagged `tag`, added at `position` in the stack. + fn grant(&mut self, perm: Permission, tag: Tag, position: usize) { + // Simply add it to the "stack" -- this might add in the middle. + // As an optimization, do nothing if the new item is identical to one of its neighbors. + let item = Item::Permission(perm, tag); + if self.borrows[position-1] == item || self.borrows.get(position) == Some(&item) { + // Optimization applies, done. + trace!("reborrow: avoiding redundant item {}", item); + return; + } + trace!("reborrow: pushing item {}", item); + self.borrows.insert(position, item); + } + + /// `reborrow` helper function. /// Adds a barrier. fn barrier(&mut self, call: CallId) { - let itm = BorStackItem::FnBarrier(call); + let itm = Item::FnBarrier(call); if *self.borrows.last().unwrap() == itm { // This is just an optimization, no functional change: Avoid stacking // multiple identical barriers on top of each other. // This can happen when a function receives several shared references // that overlap. - trace!("barrier: avoiding redundant extra barrier"); + trace!("reborrow: avoiding redundant extra barrier"); } else { - trace!("barrier: pushing barrier for call {}", call); + trace!("reborrow: pushing barrier for call {}", call); self.borrows.push(itm); } } -} -/// Higher-level per-location operations: deref, access, reborrow. -impl<'tcx> Stacks { - /// Checks that this stack is fine with being dereferenced. - fn deref( - &self, - ptr: Pointer, - size: Size, - kind: RefKind, - ) -> EvalResult<'tcx> { - trace!("deref for tag {:?} as {:?}: {:?}, size {}", - ptr.tag, kind, ptr, size.bytes()); - let stacks = self.stacks.borrow(); - for stack in stacks.iter(ptr.offset, size) { - stack.deref(ptr.tag, kind).map_err(InterpError::MachineError)?; + /// `reborrow` helper function: test that the stack invariants are still maintained. + fn test_invariants(&self) { + let mut saw_shared_read_only = false; + for item in self.borrows.iter() { + match item { + Item::Permission(Permission::SharedReadOnly, _) => { + saw_shared_read_only = true; + } + Item::Permission(perm, _) if saw_shared_read_only => { + panic!("Found {:?} on top of a SharedReadOnly!", perm); + } + _ => {} + } } - Ok(()) } - /// `ptr` got used, reflect that in the stack. - fn access( - &self, - ptr: Pointer, - size: Size, - kind: AccessKind, - ) -> EvalResult<'tcx> { - trace!("{:?} access of tag {:?}: {:?}, size {}", kind, ptr.tag, ptr, size.bytes()); - // Even reads can have a side-effect, by invalidating other references. - // This is fundamentally necessary since `&mut` asserts that there - // are no accesses through other references, not even reads. - let barrier_tracking = self.barrier_tracking.borrow(); - let mut stacks = self.stacks.borrow_mut(); - for stack in stacks.iter_mut(ptr.offset, size) { - stack.access(ptr.tag, kind, &*barrier_tracking)?; - } - Ok(()) - } - - /// Reborrow the given pointer to the new tag for the given kind of reference. - /// This works on `&self` because we might encounter references to constant memory. + /// Derived a new pointer from one with the given tag . fn reborrow( - &self, - ptr: Pointer, - size: Size, - mut barrier: Option, - new_bor: Borrow, + &mut self, + derived_from: Tag, + barrier: Option, new_kind: RefKind, + new_tag: Tag, + global: &GlobalState, ) -> EvalResult<'tcx> { - assert_eq!(new_bor.is_unique(), new_kind == RefKind::Unique); - trace!( - "reborrow for tag {:?} to {:?} as {:?}: {:?}, size {}", - ptr.tag, new_bor, new_kind, ptr, size.bytes(), - ); - if new_kind == RefKind::Raw { - // No barrier for raw, including `&UnsafeCell`. They can rightfully alias with `&mut`. + // Find the permission "from which we derive". To this end we first have to decide + // if we derive from a permission that grants writes or just reads. + let access = new_kind.access(); + let (derived_from_idx, derived_from_perm) = self.find_granting(access, derived_from) + .ok_or_else(|| InterpError::MachineError(format!( + "no item to reborrow as {} from tag {} found in borrow stack", new_kind, derived_from, + )))?; + // With this we can compute the permission for the new pointer. + let new_perm = new_kind.new_perm(derived_from_perm)?; + + // We behave very differently for the "unsafe" case of a shared-read-write pointer + // ("unsafe" because this also applies to shared references with interior mutability). + // This is because such pointers may be reborrowed to unique pointers that actually + // remain valid when their "parents" get further reborrows! + if new_perm == Permission::SharedReadWrite { + // A very liberal reborrow because the new pointer does not expect any kind of aliasing guarantee. + // Just insert new permission as child of old permission, and maintain everything else. + // This inserts "as far down as possible", which is good because it makes this pointer as + // long-lived as possible *and* we want all the items that are incompatible with this + // to actually get removed from the stack. If we pushed a `SharedReadWrite` on top of + // a `SharedReadOnly`, we'd violate the invariant that `SaredReadOnly` are at the top + // and we'd allow write access without invalidating frozen shared references! + self.grant(new_perm, new_tag, derived_from_idx+1); + + // No barrier. They can rightfully alias with `&mut`. // FIXME: This means that the `dereferencable` attribute on non-frozen shared references // is incorrect! They are dereferencable when the function is called, but might become // non-dereferencable during the course of execution. @@ -429,65 +467,129 @@ impl<'tcx> Stacks { // [1]: , // [2]: - barrier = None; + } else { + // A "safe" reborrow for a pointer that actually expects some aliasing guarantees. + // Here, creating a reference actually counts as an access, and pops incompatible + // stuff off the stack. + let check_idx = self.access(access, derived_from, global)?; + assert_eq!(check_idx, derived_from_idx, "somehow we saw different items??"); + + // Now is a good time to add the barrier. + if let Some(call) = barrier { + self.barrier(call); + } + + // We insert "as far up as possible": We know only compatible items are remaining + // on top of `derived_from`, and we want the new item at the top so that we + // get the strongest possible guarantees. + self.grant(new_perm, new_tag, self.borrows.len()); } - let barrier_tracking = self.barrier_tracking.borrow(); + + // Make sure that after all this, the stack's invariant is still maintained. + if cfg!(debug_assertions) { + self.test_invariants(); + } + + Ok(()) + } +} + +/// Higher-level per-location operations: deref, access, reborrow. +impl<'tcx> Stacks { + /// Creates new stack with initial tag. + pub(crate) fn new( + size: Size, + tag: Tag, + extra: MemoryState, + ) -> Self { + let item = Item::Permission(Permission::Unique, tag); + let stack = Stack { + borrows: vec![item], + }; + Stacks { + stacks: RefCell::new(RangeMap::new(size, stack)), + global: extra, + } + } + + /// `ptr` got used, reflect that in the stack. + fn access( + &self, + ptr: Pointer, + size: Size, + kind: AccessKind, + ) -> EvalResult<'tcx> { + trace!("{} access of tag {}: {:?}, size {}", kind, ptr.tag, ptr, size.bytes()); + // Even reads can have a side-effect, by invalidating other references. + // This is fundamentally necessary since `&mut` asserts that there + // are no accesses through other references, not even reads. + let global = self.global.borrow(); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { - // Access source `ptr`, create new ref. - let ptr_idx = stack.deref(ptr.tag, new_kind).map_err(InterpError::MachineError)?; - // If we can deref the new tag already, and if that tag lives higher on - // the stack than the one we come from, just use that. - // That is, we check if `new_bor` *already* is "derived from" `ptr.tag`. - // This also checks frozenness, if required. - let bor_redundant = barrier.is_none() && - match (ptr_idx, stack.deref(new_bor, new_kind)) { - // If the new borrow works with the frozen item, or else if it lives - // above the old one in the stack, our job here is done. - (_, Ok(None)) => true, - (Some(ptr_idx), Ok(Some(new_idx))) if new_idx >= ptr_idx => true, - // Otherwise, we need to create a new borrow. - _ => false, - }; - if bor_redundant { - assert!(new_bor.is_aliasing(), "a unique reborrow can never be redundant"); - trace!("reborrow is redundant"); - continue; - } - // We need to do some actual work. - let access_kind = if new_kind == RefKind::Unique { - AccessKind::Write - } else { - AccessKind::Read - }; - stack.access(ptr.tag, access_kind, &*barrier_tracking)?; - if let Some(call) = barrier { - stack.barrier(call); - } - stack.create(new_bor, new_kind); + stack.access(kind, ptr.tag, &*global)?; + } + Ok(()) + } + + /// Reborrow the given pointer to the new tag for the given kind of reference. + /// This works on `&self` because we might encounter references to constant memory. + fn reborrow( + &self, + ptr: Pointer, + size: Size, + barrier: Option, + new_kind: RefKind, + new_tag: Tag, + ) -> EvalResult<'tcx> { + trace!( + "{} reborrow for tag {} to {}: {:?}, size {}", + new_kind, ptr.tag, new_tag, ptr, size.bytes(), + ); + let global = self.global.borrow(); + let mut stacks = self.stacks.borrow_mut(); + for stack in stacks.iter_mut(ptr.offset, size) { + stack.reborrow(ptr.tag, barrier, new_kind, new_tag, &*global)?; } Ok(()) } } -/// Hooks and glue. -impl AllocationExtra for Stacks { - #[inline(always)] - fn memory_allocated<'tcx>(size: Size, extra: &MemoryState) -> Self { - let stack = Stack { - borrows: vec![BorStackItem::Raw], - frozen_since: None, - }; - Stacks { - stacks: RefCell::new(RangeMap::new(size, stack)), - barrier_tracking: Rc::clone(extra), - } - } +// # Stacked Borrows Core End +// Glue code to connect with Miri Machine Hooks + +impl Stacks { + pub fn new_allocation( + size: Size, + extra: &MemoryState, + kind: MemoryKind, + ) -> (Self, Tag) { + let tag = match kind { + MemoryKind::Stack => { + // New unique borrow. This `Uniq` is not accessible by the program, + // so it will only ever be used when using the local directly (i.e., + // not through a pointer). That is, whenever we directly use a local, this will pop + // everything else off the stack, invalidating all previous pointers, + // and in particular, *all* raw pointers. This subsumes the explicit + // `reset` which the blog post [1] says to perform when accessing a local. + // + // [1]: + Tag::Tagged(extra.borrow_mut().new_ptr()) + } + _ => { + Tag::Untagged + } + }; + let stack = Stacks::new(size, tag, Rc::clone(extra)); + (stack, tag) + } +} + +impl AllocationExtra for Stacks { #[inline(always)] fn memory_read<'tcx>( - alloc: &Allocation, - ptr: Pointer, + alloc: &Allocation, + ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { alloc.extra.access(ptr, size, AccessKind::Read) @@ -495,35 +597,20 @@ impl AllocationExtra for Stacks { #[inline(always)] fn memory_written<'tcx>( - alloc: &mut Allocation, - ptr: Pointer, + alloc: &mut Allocation, + ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - alloc.extra.access(ptr, size, AccessKind::Write) + alloc.extra.access(ptr, size, AccessKind::write()) } #[inline(always)] fn memory_deallocated<'tcx>( - alloc: &mut Allocation, - ptr: Pointer, + alloc: &mut Allocation, + ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - alloc.extra.access(ptr, size, AccessKind::Dealloc) - } -} - -impl<'tcx> Stacks { - /// Pushes the first item to the stacks. - pub(crate) fn first_item( - &mut self, - itm: BorStackItem, - size: Size - ) { - for stack in self.stacks.get_mut().iter_mut(Size::ZERO, size) { - assert!(stack.borrows.len() == 1); - assert_eq!(stack.borrows.pop().unwrap(), BorStackItem::Raw); - stack.borrows.push(itm); - } + alloc.extra.access(ptr, size, AccessKind::dealloc()) } } @@ -531,31 +618,32 @@ impl<'a, 'mir, 'tcx> EvalContextPrivExt<'a, 'mir, 'tcx> for crate::MiriEvalConte trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { fn reborrow( &mut self, - place: MPlaceTy<'tcx, Borrow>, + place: MPlaceTy<'tcx, Tag>, size: Size, + mutbl: Option, + new_tag: Tag, fn_barrier: bool, - new_bor: Borrow ) -> EvalResult<'tcx> { let this = self.eval_context_mut(); - let ptr = place.ptr.to_ptr()?; let barrier = if fn_barrier { Some(this.frame().extra) } else { None }; + let ptr = place.ptr.to_ptr()?; trace!("reborrow: creating new reference for {:?} (pointee {}): {:?}", - ptr, place.layout.ty, new_bor); + ptr, place.layout.ty, new_tag); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. let alloc = this.memory().get(ptr.alloc_id)?; alloc.check_bounds(this, ptr, size)?; // Update the stacks. - if let Borrow::Alias(Some(_)) = new_bor { + if mutbl == Some(MutImmutable) { // Reference that cares about freezing. We need a frozen-sensitive reborrow. this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { - let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; - alloc.extra.reborrow(cur_ptr, size, barrier, new_bor, kind) + let new_kind = RefKind::Shared { frozen }; + alloc.extra.reborrow(cur_ptr, size, barrier, new_kind, new_tag) })?; } else { // Just treat this as one big chunk. - let kind = if new_bor.is_unique() { RefKind::Unique } else { RefKind::Raw }; - alloc.extra.reborrow(ptr, size, barrier, new_bor, kind)?; + let new_kind = if mutbl == Some(MutMutable) { RefKind::Mutable } else { RefKind::Raw }; + alloc.extra.reborrow(ptr, size, barrier, new_kind, new_tag)?; } Ok(()) } @@ -564,11 +652,11 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, /// `mutbl` can be `None` to make this a raw pointer. fn retag_reference( &mut self, - val: ImmTy<'tcx, Borrow>, + val: ImmTy<'tcx, Tag>, mutbl: Option, fn_barrier: bool, two_phase: bool, - ) -> EvalResult<'tcx, Immediate> { + ) -> EvalResult<'tcx, Immediate> { let this = self.eval_context_mut(); // We want a place for where the ptr *points to*, so we get one. let place = this.ref_to_mplace(val)?; @@ -581,23 +669,24 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } // Compute new borrow. - let time = this.machine.stacked_borrows.increment_clock(); - let new_bor = match mutbl { - Some(MutMutable) => Borrow::Uniq(time), - Some(MutImmutable) => Borrow::Alias(Some(time)), - None => Borrow::default(), + let new_tag = match mutbl { + Some(_) => Tag::Tagged(this.memory().extra.borrow_mut().new_ptr()), + None => Tag::Untagged, }; // Reborrow. - this.reborrow(place, size, fn_barrier, new_bor)?; - let new_place = place.with_tag(new_bor); + this.reborrow(place, size, mutbl, new_tag, fn_barrier)?; + let new_place = place.replace_tag(new_tag); // Handle two-phase borrows. if two_phase { assert!(mutbl == Some(MutMutable), "two-phase shared borrows make no sense"); - // We immediately share it, to allow read accesses - let two_phase_time = this.machine.stacked_borrows.increment_clock(); - let two_phase_bor = Borrow::Alias(Some(two_phase_time)); - this.reborrow(new_place, size, false /* fn_barrier */, two_phase_bor)?; + // Grant read access *to the parent pointer* with the old tag. This means the same pointer + // has multiple items in the stack now! + // FIXME: Think about this some more, in particular about the interaction with cast-to-raw. + // Maybe find a better way to express 2-phase, now that we have a "more expressive language" + // in the stack. + let old_tag = place.ptr.to_ptr().unwrap().tag; + this.reborrow(new_place, size, Some(MutImmutable), old_tag, /* fn_barrier: */ false)?; } // Return new pointer. @@ -607,90 +696,10 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { - fn tag_new_allocation( - &mut self, - id: AllocId, - kind: MemoryKind, - ) -> Borrow { - let this = self.eval_context_mut(); - let time = match kind { - MemoryKind::Stack => { - // New unique borrow. This `Uniq` is not accessible by the program, - // so it will only ever be used when using the local directly (i.e., - // not through a pointer). That is, whenever we directly use a local, this will pop - // everything else off the stack, invalidating all previous pointers, - // and in particular, *all* raw pointers. This subsumes the explicit - // `reset` which the blog post [1] says to perform when accessing a local. - // - // [1]: - this.machine.stacked_borrows.increment_clock() - } - _ => { - // Nothing to do for everything else. - return Borrow::default() - } - }; - // Make this the active borrow for this allocation. - let alloc = this - .memory_mut() - .get_mut(id) - .expect("this is a new allocation; it must still exist"); - let size = Size::from_bytes(alloc.bytes.len() as u64); - alloc.extra.first_item(BorStackItem::Uniq(time), size); - Borrow::Uniq(time) - } - - /// Called for value-to-place conversion. `mutability` is `None` for raw pointers. - /// - /// Note that this does *not* mean that all this memory will actually get accessed/referenced! - /// We could be in the middle of `&(*var).1`. - fn ptr_dereference( - &self, - place: MPlaceTy<'tcx, Borrow>, - size: Size, - mutability: Option, - ) -> EvalResult<'tcx> { - let this = self.eval_context_ref(); - trace!( - "ptr_dereference: Accessing {} reference for {:?} (pointee {})", - if let Some(mutability) = mutability { - format!("{:?}", mutability) - } else { - format!("raw") - }, - place.ptr, place.layout.ty - ); - let ptr = place.ptr.to_ptr()?; - if mutability.is_none() { - // No further checks on raw derefs -- only the access itself will be checked. - return Ok(()); - } - - // Get the allocation - let alloc = this.memory().get(ptr.alloc_id)?; - alloc.check_bounds(this, ptr, size)?; - // If we got here, we do some checking, *but* we leave the tag unchanged. - if let Borrow::Alias(Some(_)) = ptr.tag { - assert_eq!(mutability, Some(MutImmutable)); - // We need a frozen-sensitive check. - this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { - let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; - alloc.extra.deref(cur_ptr, size, kind) - })?; - } else { - // Just treat this as one big chunk. - let kind = if mutability == Some(MutMutable) { RefKind::Unique } else { RefKind::Raw }; - alloc.extra.deref(ptr, size, kind)?; - } - - // All is good. - Ok(()) - } - fn retag( &mut self, kind: RetagKind, - place: PlaceTy<'tcx, Borrow> + place: PlaceTy<'tcx, Tag> ) -> EvalResult<'tcx> { let this = self.eval_context_mut(); // Determine mutability and whether to add a barrier. @@ -734,7 +743,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, for RetagVisitor<'ecx, 'a, 'mir, 'tcx> { - type V = MPlaceTy<'tcx, Borrow>; + type V = MPlaceTy<'tcx, Tag>; #[inline(always)] fn ecx(&mut self) -> &mut MiriEvalContext<'a, 'mir, 'tcx> { @@ -742,7 +751,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } // Primitives of reference type, that is the one thing we are interested in. - fn visit_primitive(&mut self, place: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> + fn visit_primitive(&mut self, place: MPlaceTy<'tcx, Tag>) -> EvalResult<'tcx> { // Cannot use `builtin_deref` because that reports *immutable* for `Box`, // making it useless. diff --git a/src/tls.rs b/src/tls.rs index 992e4fd05619..9346fba0dcc4 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -5,14 +5,14 @@ use rustc::{ty, ty::layout::HasDataLayout, mir}; use crate::{ EvalResult, InterpError, StackPopCleanup, - MPlaceTy, Scalar, Borrow, + MPlaceTy, Scalar, Tag, }; pub type TlsKey = u128; #[derive(Copy, Clone, Debug)] pub struct TlsEntry<'tcx> { - pub(crate) data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. + pub(crate) data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. pub(crate) dtor: Option>, } @@ -63,7 +63,7 @@ impl<'tcx> TlsData<'tcx> { } } - pub fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar> { + pub fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar> { match self.keys.get(&key) { Some(&TlsEntry { data, .. }) => { trace!("TLS key {} loaded: {:?}", key, data); @@ -73,7 +73,7 @@ impl<'tcx> TlsData<'tcx> { } } - pub fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx> { + pub fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx> { match self.keys.get_mut(&key) { Some(&mut TlsEntry { ref mut data, .. }) => { trace!("TLS key {} stored: {:?}", key, new_data); @@ -106,7 +106,7 @@ impl<'tcx> TlsData<'tcx> { &mut self, key: Option, cx: &impl HasDataLayout, - ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { + ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { use std::collections::Bound::*; let thread_local = &mut self.keys; From 966d638760d391db49e691479cb06062a19add0e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 15 Apr 2019 17:06:42 +0200 Subject: [PATCH 0680/5092] make run-pass tests pass. tweak how we remove barriers. --- src/stacked_borrows.rs | 87 ++++++++++++++++++---------- tests/run-pass/2phase.rs | 7 +-- tests/run-pass/ptr_arith_offset.rs | 2 +- tests/run-pass/ptr_offset.rs | 2 +- tests/run-pass/regions-mock-trans.rs | 4 +- 5 files changed, 62 insertions(+), 40 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 080200b12a4e..c55ebecea71d 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -183,14 +183,17 @@ impl GlobalState { /// We need to make at least the following things true: /// -/// U1: After creating a `Uniq`, it is at the top (and unfrozen). -/// U2: If the top is `Uniq` (and unfrozen), accesses must be through that `Uniq` or pop it. +/// U1: After creating a `Uniq`, it is at the top. +/// U2: If the top is `Uniq`, accesses must be through that `Uniq` or remove it it. /// U3: If an access happens with a `Uniq`, it requires the `Uniq` to be in the stack. /// -/// F1: After creating a `&`, the parts outside `UnsafeCell` are frozen. -/// F2: If a write access happens, it unfreezes. +/// F1: After creating a `&`, the parts outside `UnsafeCell` have our `SharedReadOnly` on top. +/// F2: If a write access happens, it pops the `SharedReadOnly`. This has three pieces: +/// F2a: If a write happens granted by an item below our `SharedReadOnly`, the `SharedReadOnly` +/// gets popped. +/// F2b: No `SharedReadWrite` or `Unique` will ever be added on top of our `SharedReadOnly`. /// F3: If an access happens with an `&` outside `UnsafeCell`, -/// it requires the location to still be frozen. +/// it requires the `SharedReadOnly` to still be in the stack. impl Default for Tag { #[inline(always)] @@ -218,17 +221,12 @@ impl Permission { } } - /// This defines for a given permission, which other items it can tolerate "above" itself + /// This defines for a given permission, which other permissions it can tolerate "above" itself /// for which kinds of accesses. /// If true, then `other` is allowed to remain on top of `self` when `access` happens. - fn compatible_with(self, access: AccessKind, other: Item) -> bool { + fn compatible_with(self, access: AccessKind, other: Permission) -> bool { use self::Permission::*; - let other = match other { - Item::Permission(perm, _) => perm, - Item::FnBarrier(_) => return false, // Remove all barriers -- if they are active, cause UB. - }; - match (self, access, other) { // Some cases are impossible. (SharedReadOnly, _, SharedReadWrite) | @@ -236,7 +234,7 @@ impl Permission { bug!("There can never be a SharedReadWrite or a Unique on top of a SharedReadOnly"), // When `other` is `SharedReadOnly`, that is NEVER compatible with // write accesses. - // This makes sure read-only pointers become invalid on write accesses. + // This makes sure read-only pointers become invalid on write accesses (ensures F2a). (_, AccessKind::Write { .. }, SharedReadOnly) => false, // When `other` is `Unique`, that is compatible with nothing. @@ -244,7 +242,7 @@ impl Permission { (_, _, Unique) => false, // When we are unique and this is a write/dealloc, we tolerate nothing. - // This makes sure we re-assert uniqueness on write accesses. + // This makes sure we re-assert uniqueness ("being on top") on write accesses. // (This is particularily important such that when a new mutable ref gets created, it gets // pushed into the right item -- this behaves like a write and we assert uniqueness of the // pointer from which this comes, *if* it was a unique pointer.) @@ -307,6 +305,7 @@ impl<'tcx> Stack { .enumerate() // we also need to know *where* in the stack .rev() // search top-to-bottom // Return permission of first item that grants access. + // We require a permission with the right tag, ensuring U3 and F3. .filter_map(|(idx, item)| match item { &Item::Permission(perm, item_tag) if perm.grants(access) && tag == item_tag => Some((idx, perm)), @@ -324,6 +323,9 @@ impl<'tcx> Stack { global: &GlobalState, ) -> EvalResult<'tcx, usize> { // Two main steps: Find granting item, remove all incompatible items above. + // The second step is where barriers get implemented: they "protect" the items + // below them, meaning that if we remove an item and then further up encounter a barrier, + // we raise an error. // Afterwards we just do some post-processing for deallocation accesses. // Step 1: Find granting item. @@ -338,20 +340,35 @@ impl<'tcx> Stack { // API for this. { let mut cur = granting_idx + 1; + let mut removed_item = None; while let Some(item) = self.borrows.get(cur) { - if granting_perm.compatible_with(access, *item) { - // Keep this, check next. - cur += 1; - } else { - // Aha! This is a bad one, remove it, and if it is an *active* barrier - // we have a problem. - match self.borrows.remove(cur) { - Item::FnBarrier(call) if global.is_active(call) => { - return err!(MachineError(format!( - "not granting access because of barrier ({})", call - ))); + match *item { + Item::Permission(perm, _) => { + if granting_perm.compatible_with(access, perm) { + // Keep this, check next. + cur += 1; + } else { + // Aha! This is a bad one, remove it. + let item = self.borrows.remove(cur); + trace!("access: popping item {}", item); + removed_item = Some(item); } - _ => {} + } + Item::FnBarrier(call) if !global.is_active(call) => { + // An inactive barrier, just get rid of it. (Housekeeping.) + self.borrows.remove(cur); + } + Item::FnBarrier(call) => { + // We hit an active barrier! If we have already removed an item, + // we got a problem! The barrier was supposed to protect this item. + if let Some(removed_item) = removed_item { + return err!(MachineError(format!( + "not granting {} access to tag {} because barrier ({}) protects incompatible item {}", + access, tag, call, removed_item + ))); + } + // Keep this, check next. + cur += 1; } } } @@ -425,7 +442,7 @@ impl<'tcx> Stack { } } - /// Derived a new pointer from one with the given tag . + /// Derived a new pointer from one with the given tag. fn reborrow( &mut self, derived_from: Tag, @@ -448,6 +465,8 @@ impl<'tcx> Stack { // ("unsafe" because this also applies to shared references with interior mutability). // This is because such pointers may be reborrowed to unique pointers that actually // remain valid when their "parents" get further reborrows! + // However, either way, we ensure that we insert the new item in a way that between + // `derived_from` and the new one, there are only items *compatible with* `derived_from`. if new_perm == Permission::SharedReadWrite { // A very liberal reborrow because the new pointer does not expect any kind of aliasing guarantee. // Just insert new permission as child of old permission, and maintain everything else. @@ -456,6 +475,8 @@ impl<'tcx> Stack { // to actually get removed from the stack. If we pushed a `SharedReadWrite` on top of // a `SharedReadOnly`, we'd violate the invariant that `SaredReadOnly` are at the top // and we'd allow write access without invalidating frozen shared references! + // This ensures F2b for `SharedReadWrite` by adding the new item below any + // potentially existing `SharedReadOnly`. self.grant(new_perm, new_tag, derived_from_idx+1); // No barrier. They can rightfully alias with `&mut`. @@ -471,18 +492,20 @@ impl<'tcx> Stack { // A "safe" reborrow for a pointer that actually expects some aliasing guarantees. // Here, creating a reference actually counts as an access, and pops incompatible // stuff off the stack. + // This ensures F2b for `Unique`, by removing offending `SharedReadOnly`. let check_idx = self.access(access, derived_from, global)?; assert_eq!(check_idx, derived_from_idx, "somehow we saw different items??"); - // Now is a good time to add the barrier. - if let Some(call) = barrier { - self.barrier(call); - } - // We insert "as far up as possible": We know only compatible items are remaining // on top of `derived_from`, and we want the new item at the top so that we // get the strongest possible guarantees. + // This ensures U1 and F1. self.grant(new_perm, new_tag, self.borrows.len()); + + // Now is a good time to add the barrier, protecting the item we just added. + if let Some(call) = barrier { + self.barrier(call); + } } // Make sure that after all this, the stack's invariant is still maintained. diff --git a/tests/run-pass/2phase.rs b/tests/run-pass/2phase.rs index 57f363114370..78ddf566a9d3 100644 --- a/tests/run-pass/2phase.rs +++ b/tests/run-pass/2phase.rs @@ -51,14 +51,13 @@ fn with_interior_mutability() { impl Thing for Cell {} let mut x = Cell::new(1); - let l = &x; + //let l = &x; - #[allow(unknown_lints, mutable_borrow_reservation_conflict)] x .do_the_thing({ x.set(3); - l.set(4); - x.get() + l.get() + // l.set(4); // FIXME: Enable this as an example of overlapping 2PB! + x.get() // FIXME same: + l.get() }) ; } diff --git a/tests/run-pass/ptr_arith_offset.rs b/tests/run-pass/ptr_arith_offset.rs index 7912da9fd437..a6ee151e3e13 100644 --- a/tests/run-pass/ptr_arith_offset.rs +++ b/tests/run-pass/ptr_arith_offset.rs @@ -1,6 +1,6 @@ fn main() { let v = [1i16, 2]; - let x = &v as *const i16; + let x = &v as *const [i16] as *const i16; let x = x.wrapping_offset(1); assert_eq!(unsafe { *x }, 2); } diff --git a/tests/run-pass/ptr_offset.rs b/tests/run-pass/ptr_offset.rs index 9e2e26fad365..1c7f0eb71797 100644 --- a/tests/run-pass/ptr_offset.rs +++ b/tests/run-pass/ptr_offset.rs @@ -2,7 +2,7 @@ fn f() -> i32 { 42 } fn main() { let v = [1i16, 2]; - let x = &v as *const i16; + let x = &v as *const [i16; 2] as *const i16; let x = unsafe { x.offset(1) }; assert_eq!(unsafe { *x }, 2); diff --git a/tests/run-pass/regions-mock-trans.rs b/tests/run-pass/regions-mock-trans.rs index ac8a1c04fbe4..020ed4927a88 100644 --- a/tests/run-pass/regions-mock-trans.rs +++ b/tests/run-pass/regions-mock-trans.rs @@ -22,14 +22,14 @@ struct Ccx { x: isize } -fn alloc<'a>(_bcx : &'a Arena) -> &'a Bcx<'a> { +fn alloc<'a>(_bcx : &'a Arena) -> &'a mut Bcx<'a> { unsafe { mem::transmute(libc::malloc(mem::size_of::>() as libc::size_t)) } } -fn h<'a>(bcx : &'a Bcx<'a>) -> &'a Bcx<'a> { +fn h<'a>(bcx : &'a Bcx<'a>) -> &'a mut Bcx<'a> { return alloc(bcx.fcx.arena); } From a6d377ca0b883355b40a2aff9d29fde195dd0a20 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 15:26:21 +0200 Subject: [PATCH 0681/5092] more comments --- src/stacked_borrows.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index c55ebecea71d..40cbf92e9655 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -334,11 +334,17 @@ impl<'tcx> Stack { "no item granting {} access to tag {} found in borrow stack", access, tag, )))?; - + // Step 2: Remove everything incompatible above them. - // Implemented with indices because there does not seem to be a nice iterator and range-based - // API for this. + // Items below an active barrier however may not be removed, so we check that as well. + // We do *not* maintain a stack discipline here. We could, in principle, decide to only + // keep the items immediately above `granting_idx` that are compatible, and then pop the rest. + // However, that kills off entire "branches" of pointer derivation too easily: + // in `let raw = &mut *x as *mut _; let _val = *x;`, the second statement would pop the `Unique` + // from the reborrow of the first statement, and subequently also pop the `SharedReadWrite` for `raw`. { + // Implemented with indices because there does not seem to be a nice iterator and range-based + // API for this. let mut cur = granting_idx + 1; let mut removed_item = None; while let Some(item) = self.borrows.get(cur) { @@ -454,6 +460,14 @@ impl<'tcx> Stack { // Find the permission "from which we derive". To this end we first have to decide // if we derive from a permission that grants writes or just reads. let access = new_kind.access(); + // Now we figure out which item grants our parent (`derived_from`) permission. + // We use that to determine (a) where to put the new item, and for raw pointers + // (b) whether to given read-only or read-write access. + // FIXME: This handling of raw pointers is fragile, very fragile. What if we do + // not get "the right one", like when there are multiple items granting `derived_from` + // and we accidentally create a read-only pointer? This can happen for two-phase borrows + // (then there's a `Unique` and a `SharedReadOnly` for the same tag), and for raw pointers + // (which currently all are `Untagged`). let (derived_from_idx, derived_from_perm) = self.find_granting(access, derived_from) .ok_or_else(|| InterpError::MachineError(format!( "no item to reborrow as {} from tag {} found in borrow stack", new_kind, derived_from, From ef52be031ca7a75863b937e68799de66557563ce Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 17:17:28 +0200 Subject: [PATCH 0682/5092] adjust compile-fail error messages This also passes miri-test-libstd! --- .../compile-fail/stacked_borrows/alias_through_mutation.rs | 2 +- tests/compile-fail/stacked_borrows/aliasing_mut3.rs | 2 +- .../stacked_borrows/box_exclusive_violation1.rs | 2 +- tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs | 2 +- tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_read1.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_read2.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_read3.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_read4.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_read5.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_write1.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_write2.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_write3.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_write4.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_write5.rs | 2 +- tests/compile-fail/stacked_borrows/load_invalid_mut.rs | 2 +- tests/compile-fail/stacked_borrows/load_invalid_shr.rs | 2 +- .../stacked_borrows/mut_exclusive_violation1.rs | 2 +- tests/compile-fail/stacked_borrows/outdated_local.rs | 2 +- tests/compile-fail/stacked_borrows/pass_invalid_mut.rs | 2 +- tests/compile-fail/stacked_borrows/pass_invalid_shr.rs | 2 +- tests/compile-fail/stacked_borrows/pointer_smuggling.rs | 2 +- tests/compile-fail/stacked_borrows/return_invalid_mut.rs | 2 +- .../stacked_borrows/return_invalid_mut_option.rs | 2 +- .../stacked_borrows/return_invalid_mut_tuple.rs | 2 +- tests/compile-fail/stacked_borrows/return_invalid_shr.rs | 2 +- .../stacked_borrows/return_invalid_shr_option.rs | 2 +- .../stacked_borrows/return_invalid_shr_tuple.rs | 2 +- .../compile-fail/stacked_borrows/shr_frozen_violation1.rs | 7 ++----- .../stacked_borrows/static_memory_modification.rs | 2 +- .../compile-fail/stacked_borrows/transmute-is-no-escape.rs | 2 +- tests/compile-fail/stacked_borrows/unescaped_local.rs | 2 +- 32 files changed, 33 insertions(+), 36 deletions(-) diff --git a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs index 30f5921202c3..4a153d74ffb0 100644 --- a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs +++ b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs @@ -9,5 +9,5 @@ fn main() { retarget(&mut target_alias, target); // now `target_alias` points to the same thing as `target` *target = 13; - let _val = *target_alias; //~ ERROR does not exist on the borrow stack + let _val = *target_alias; //~ ERROR borrow stack } diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut3.rs b/tests/compile-fail/stacked_borrows/aliasing_mut3.rs index e3c59d156614..3943e9576158 100644 --- a/tests/compile-fail/stacked_borrows/aliasing_mut3.rs +++ b/tests/compile-fail/stacked_borrows/aliasing_mut3.rs @@ -1,6 +1,6 @@ use std::mem; -pub fn safe(_x: &mut i32, _y: &i32) {} //~ ERROR does not exist on the borrow stack +pub fn safe(_x: &mut i32, _y: &i32) {} //~ ERROR borrow stack fn main() { let mut x = 0; diff --git a/tests/compile-fail/stacked_borrows/box_exclusive_violation1.rs b/tests/compile-fail/stacked_borrows/box_exclusive_violation1.rs index 481915faed04..7d7f5e24e2b0 100644 --- a/tests/compile-fail/stacked_borrows/box_exclusive_violation1.rs +++ b/tests/compile-fail/stacked_borrows/box_exclusive_violation1.rs @@ -8,7 +8,7 @@ fn demo_mut_advanced_unique(mut our: Box) -> i32 { unknown_code_2(); // We know this will return 5 - *our //~ ERROR does not exist on the borrow stack + *our //~ ERROR borrow stack } // Now comes the evil context diff --git a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs index 98d4e6f22965..9ff67ae35422 100644 --- a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs +++ b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs @@ -13,5 +13,5 @@ fn main() { let v1 = safe::as_mut_slice(&v); let _v2 = safe::as_mut_slice(&v); v1[1] = 5; - //~^ ERROR does not exist on the borrow stack + //~^ ERROR borrow stack } diff --git a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs index 42f345f55144..812dd47ef1d9 100644 --- a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs @@ -9,7 +9,7 @@ mod safe { assert!(mid <= len); (from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" - //~^ ERROR does not exist on the borrow stack + //~^ ERROR borrow stack from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) } } diff --git a/tests/compile-fail/stacked_borrows/illegal_read1.rs b/tests/compile-fail/stacked_borrows/illegal_read1.rs index 3fb38abefdae..d942d2b27b99 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read1.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read1.rs @@ -7,7 +7,7 @@ fn main() { let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. - //~^ ERROR: does not exist on the borrow stack + //~^ ERROR: borrow stack } fn callee(xraw: *mut i32) { diff --git a/tests/compile-fail/stacked_borrows/illegal_read2.rs b/tests/compile-fail/stacked_borrows/illegal_read2.rs index e43340f0b8ee..c50c88d48f8c 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read2.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read2.rs @@ -7,7 +7,7 @@ fn main() { let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. - //~^ ERROR: does not exist on the borrow stack + //~^ ERROR: borrow stack } fn callee(xraw: *mut i32) { diff --git a/tests/compile-fail/stacked_borrows/illegal_read3.rs b/tests/compile-fail/stacked_borrows/illegal_read3.rs index b4abbb4a1aed..09fd5d534cf7 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read3.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read3.rs @@ -15,7 +15,7 @@ fn main() { callee(xref1_sneaky); // ... though any use of it will invalidate our ref. let _val = *xref2; - //~^ ERROR: does not exist on the borrow stack + //~^ ERROR: borrow stack } fn callee(xref1: usize) { diff --git a/tests/compile-fail/stacked_borrows/illegal_read4.rs b/tests/compile-fail/stacked_borrows/illegal_read4.rs index bb889de8f839..d7e281e3ffe5 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read4.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read4.rs @@ -5,5 +5,5 @@ fn main() { let xraw = xref1 as *mut _; let xref2 = unsafe { &mut *xraw }; let _val = unsafe { *xraw }; // use the raw again, this invalidates xref2 *even* with the special read except for uniq refs - let _illegal = *xref2; //~ ERROR does not exist on the borrow stack + let _illegal = *xref2; //~ ERROR borrow stack } diff --git a/tests/compile-fail/stacked_borrows/illegal_read5.rs b/tests/compile-fail/stacked_borrows/illegal_read5.rs index 0f4737f16e63..d6120cd64ad0 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read5.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read5.rs @@ -12,5 +12,5 @@ fn main() { let _val = *xref; // we can even still use our mutable reference mem::forget(unsafe { ptr::read(xshr) }); // but after reading through the shared ref let _val = *xref; // the mutable one is dead and gone - //~^ ERROR does not exist on the borrow stack + //~^ ERROR borrow stack } diff --git a/tests/compile-fail/stacked_borrows/illegal_write1.rs b/tests/compile-fail/stacked_borrows/illegal_write1.rs index d0a23cb44489..dd262a341ed2 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write1.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write1.rs @@ -5,5 +5,5 @@ fn main() { let x : *mut u32 = xref as *const _ as *mut _; unsafe { *x = 42; } // invalidates shared ref, activates raw } - let _x = *xref; //~ ERROR is not frozen + let _x = *xref; //~ ERROR borrow stack } diff --git a/tests/compile-fail/stacked_borrows/illegal_write2.rs b/tests/compile-fail/stacked_borrows/illegal_write2.rs index affa21c7625e..62ea05e1811e 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write2.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write2.rs @@ -3,6 +3,6 @@ fn main() { let target2 = target as *mut _; drop(&mut *target); // reborrow // Now make sure our ref is still the only one. - unsafe { *target2 = 13; } //~ ERROR does not exist on the borrow stack + unsafe { *target2 = 13; } //~ ERROR borrow stack let _val = *target; } diff --git a/tests/compile-fail/stacked_borrows/illegal_write3.rs b/tests/compile-fail/stacked_borrows/illegal_write3.rs index dc4edcc3a5b4..d2d8528d9078 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write3.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write3.rs @@ -3,6 +3,6 @@ fn main() { // Make sure raw ptr with raw tag cannot mutate frozen location without breaking the shared ref. let r#ref = ⌖ // freeze let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag - unsafe { *ptr = 42; } //~ ERROR does not exist on the borrow stack + unsafe { *ptr = 42; } //~ ERROR borrow stack let _val = *r#ref; } diff --git a/tests/compile-fail/stacked_borrows/illegal_write4.rs b/tests/compile-fail/stacked_borrows/illegal_write4.rs index 37ae0f055f0e..be4f89ba289a 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write4.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write4.rs @@ -9,5 +9,5 @@ fn main() { let ptr = reference as *const _ as *mut i32; // raw ptr, with raw tag let _mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag // Now we retag, making our ref top-of-stack -- and, in particular, unfreezing. - let _val = *reference; //~ ERROR is not frozen + let _val = *reference; //~ ERROR borrow stack } diff --git a/tests/compile-fail/stacked_borrows/illegal_write5.rs b/tests/compile-fail/stacked_borrows/illegal_write5.rs index 3a0738bfd0b8..c60fe90fe05c 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write5.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write5.rs @@ -8,7 +8,7 @@ fn main() { callee(xraw); // ... though any use of raw value will invalidate our ref. let _val = *xref; - //~^ ERROR: does not exist on the borrow stack + //~^ ERROR: borrow stack } fn callee(xraw: *mut i32) { diff --git a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs index f2e4b36f85cc..1704b7fe19b2 100644 --- a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs @@ -5,5 +5,5 @@ fn main() { let xref = unsafe { &mut *xraw }; let xref_in_mem = Box::new(xref); let _val = unsafe { *xraw }; // invalidate xref - let _val = *xref_in_mem; //~ ERROR does not exist on the borrow stack + let _val = *xref_in_mem; //~ ERROR borrow stack } diff --git a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs index 6599924f0f4c..4757a2c1e589 100644 --- a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs @@ -5,5 +5,5 @@ fn main() { let xref = unsafe { &*xraw }; let xref_in_mem = Box::new(xref); unsafe { *xraw = 42 }; // unfreeze - let _val = *xref_in_mem; //~ ERROR is not frozen + let _val = *xref_in_mem; //~ ERROR borrow stack } diff --git a/tests/compile-fail/stacked_borrows/mut_exclusive_violation1.rs b/tests/compile-fail/stacked_borrows/mut_exclusive_violation1.rs index 3fe6b6567423..03343b985a02 100644 --- a/tests/compile-fail/stacked_borrows/mut_exclusive_violation1.rs +++ b/tests/compile-fail/stacked_borrows/mut_exclusive_violation1.rs @@ -21,7 +21,7 @@ fn unknown_code_1(x: &i32) { unsafe { } } fn unknown_code_2() { unsafe { - *LEAK = 7; //~ ERROR barrier + *LEAK = 7; //~ ERROR borrow stack } } fn main() { diff --git a/tests/compile-fail/stacked_borrows/outdated_local.rs b/tests/compile-fail/stacked_borrows/outdated_local.rs index ba36e43e0c5d..4cb655366ef1 100644 --- a/tests/compile-fail/stacked_borrows/outdated_local.rs +++ b/tests/compile-fail/stacked_borrows/outdated_local.rs @@ -3,7 +3,7 @@ fn main() { let y: *const i32 = &x; x = 1; // this invalidates y by reactivating the lowermost uniq borrow for this local - assert_eq!(unsafe { *y }, 1); //~ ERROR does not exist on the borrow stack + assert_eq!(unsafe { *y }, 1); //~ ERROR borrow stack assert_eq!(x, 1); } diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs index b239237f0199..d8a53b7a9630 100644 --- a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs @@ -6,5 +6,5 @@ fn main() { let xraw = x as *mut _; let xref = unsafe { &mut *xraw }; let _val = unsafe { *xraw }; // invalidate xref - foo(xref); //~ ERROR does not exist on the borrow stack + foo(xref); //~ ERROR borrow stack } diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs b/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs index 22a80e27103e..091604a283b9 100644 --- a/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs @@ -6,5 +6,5 @@ fn main() { let xraw = x as *mut _; let xref = unsafe { &*xraw }; unsafe { *xraw = 42 }; // unfreeze - foo(xref); //~ ERROR is not frozen + foo(xref); //~ ERROR borrow stack } diff --git a/tests/compile-fail/stacked_borrows/pointer_smuggling.rs b/tests/compile-fail/stacked_borrows/pointer_smuggling.rs index a8207d58e99b..f724cdd2a769 100644 --- a/tests/compile-fail/stacked_borrows/pointer_smuggling.rs +++ b/tests/compile-fail/stacked_borrows/pointer_smuggling.rs @@ -8,7 +8,7 @@ fn fun1(x: &mut u8) { fn fun2() { // Now we use a pointer we are not allowed to use - let _x = unsafe { *PTR }; //~ ERROR does not exist on the borrow stack + let _x = unsafe { *PTR }; //~ ERROR borrow stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs index 31f8a4e33afd..54004ec43882 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> &mut i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &mut (*xraw).1 }; let _val = unsafe { *xraw }; // invalidate xref - ret //~ ERROR does not exist on the borrow stack + ret //~ ERROR borrow stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs index 750d507d6f66..2eb2df81f5f1 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> Option<&mut i32> { let xraw = x as *mut (i32, i32); let ret = Some(unsafe { &mut (*xraw).1 }); let _val = unsafe { *xraw }; // invalidate xref - ret //~ ERROR does not exist on the borrow stack + ret //~ ERROR borrow stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs index bb712e9e486c..8b73df4bd1ac 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> (&mut i32,) { let xraw = x as *mut (i32, i32); let ret = (unsafe { &mut (*xraw).1 },); let _val = unsafe { *xraw }; // invalidate xref - ret //~ ERROR does not exist on the borrow stack + ret //~ ERROR borrow stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr.rs b/tests/compile-fail/stacked_borrows/return_invalid_shr.rs index 986dd18b2e0b..eab026f9a47c 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_shr.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> &i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &(*xraw).1 }; unsafe { *xraw = (42, 23) }; // unfreeze - ret //~ ERROR is not frozen + ret //~ ERROR borrow stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr_option.rs b/tests/compile-fail/stacked_borrows/return_invalid_shr_option.rs index 9d220991c330..f3a35ca266c6 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_shr_option.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_shr_option.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> Option<&i32> { let xraw = x as *mut (i32, i32); let ret = Some(unsafe { &(*xraw).1 }); unsafe { *xraw = (42, 23) }; // unfreeze - ret //~ ERROR is not frozen + ret //~ ERROR borrow stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.rs b/tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.rs index 060fa25c2307..82723bade27d 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> (&i32,) { let xraw = x as *mut (i32, i32); let ret = (unsafe { &(*xraw).1 },); unsafe { *xraw = (42, 23) }; // unfreeze - ret //~ ERROR is not frozen + ret //~ ERROR borrow stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/shr_frozen_violation1.rs b/tests/compile-fail/stacked_borrows/shr_frozen_violation1.rs index 560c9dfb665d..5031210c547b 100644 --- a/tests/compile-fail/stacked_borrows/shr_frozen_violation1.rs +++ b/tests/compile-fail/stacked_borrows/shr_frozen_violation1.rs @@ -8,9 +8,6 @@ fn main() { println!("{}", foo(&mut 0)); } -// If we replace the `*const` by `&`, my current dev version of miri -// *does* find the problem, but not for a good reason: It finds it because -// of barriers, and we shouldn't rely on unknown code using barriers. -fn unknown_code(x: *const i32) { - unsafe { *(x as *mut i32) = 7; } //~ ERROR barrier +fn unknown_code(x: &i32) { + unsafe { *(x as *const i32 as *mut i32) = 7; } //~ ERROR borrow stack } diff --git a/tests/compile-fail/stacked_borrows/static_memory_modification.rs b/tests/compile-fail/stacked_borrows/static_memory_modification.rs index c092cbfe5098..88ac16494766 100644 --- a/tests/compile-fail/stacked_borrows/static_memory_modification.rs +++ b/tests/compile-fail/stacked_borrows/static_memory_modification.rs @@ -3,6 +3,6 @@ static X: usize = 5; #[allow(mutable_transmutes)] fn main() { let _x = unsafe { - std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR mutable reference with frozen tag + std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR borrow stack }; } diff --git a/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs b/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs index 45ada8897778..e9282c5ba8f2 100644 --- a/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs +++ b/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs @@ -10,5 +10,5 @@ fn main() { let _raw: *mut i32 = unsafe { mem::transmute(&mut x[0]) }; // `raw` still carries a tag, so we get another pointer to the same location that does not carry a tag let raw = (&mut x[1] as *mut i32).wrapping_offset(-1); - unsafe { *raw = 13; } //~ ERROR does not exist on the borrow stack + unsafe { *raw = 13; } //~ ERROR borrow stack } diff --git a/tests/compile-fail/stacked_borrows/unescaped_local.rs b/tests/compile-fail/stacked_borrows/unescaped_local.rs index 1db14ea7eda5..b49e6cce63bc 100644 --- a/tests/compile-fail/stacked_borrows/unescaped_local.rs +++ b/tests/compile-fail/stacked_borrows/unescaped_local.rs @@ -4,5 +4,5 @@ fn main() { let mut x = 42; let raw = &mut x as *mut i32 as usize as *mut i32; let _ptr = &mut x; - unsafe { *raw = 13; } //~ ERROR does not exist on the borrow stack + unsafe { *raw = 13; } //~ ERROR borrow stack } From 924624f810bd70078074c62ea94061927d2516bd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 23:37:37 +0200 Subject: [PATCH 0683/5092] some failures are impossible --- src/stacked_borrows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 40cbf92e9655..152171aed066 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -473,7 +473,7 @@ impl<'tcx> Stack { "no item to reborrow as {} from tag {} found in borrow stack", new_kind, derived_from, )))?; // With this we can compute the permission for the new pointer. - let new_perm = new_kind.new_perm(derived_from_perm)?; + let new_perm = new_kind.new_perm(derived_from_perm).expect("this should never fail"); // We behave very differently for the "unsafe" case of a shared-read-write pointer // ("unsafe" because this also applies to shared references with interior mutability). From 97c34c266f492ff548ca1584ccb7f1c3c49dcf82 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Apr 2019 08:25:21 +0200 Subject: [PATCH 0684/5092] try to test the problematic cast-to-raw case... unfortunately with the implicit reborrow that's not currently possible --- tests/run-pass/2phase.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/run-pass/2phase.rs b/tests/run-pass/2phase.rs index 78ddf566a9d3..87ecb4aef065 100644 --- a/tests/run-pass/2phase.rs +++ b/tests/run-pass/2phase.rs @@ -26,6 +26,21 @@ fn two_phase3(b: bool) { )); } +#[allow(unreachable_code)] +fn two_phase_raw() { + let x: &mut Vec = &mut vec![]; + x.push( + { + // Unfortunately this does not trigger the problem of creating a + // raw ponter from a pointer that had a two-phase borrow derived from + // it because of the implicit &mut reborrow. + let raw = x as *mut _; + unsafe { *raw = vec![1]; } + return + } + ); +} + /* fn two_phase_overlapping1() { let mut x = vec![]; @@ -67,6 +82,7 @@ fn main() { two_phase2(); two_phase3(false); two_phase3(true); + two_phase_raw(); with_interior_mutability(); //FIXME: enable these, or remove them, depending on how https://github.com/rust-lang/rust/issues/56254 gets resolved //two_phase_overlapping1(); From a503259d8b6437550fd1563368cfae618f8ab426 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Apr 2019 08:35:06 +0200 Subject: [PATCH 0685/5092] organize stacked borrows run-pass tests --- tests/run-pass/refcell.rs | 46 +------------------ .../run-pass/{ => stacked-borrows}/2phase.rs | 0 tests/run-pass/stacked-borrows/refcell.rs | 44 ++++++++++++++++++ .../{ => stacked-borrows}/stacked-borrows.rs | 0 4 files changed, 45 insertions(+), 45 deletions(-) rename tests/run-pass/{ => stacked-borrows}/2phase.rs (100%) create mode 100644 tests/run-pass/stacked-borrows/refcell.rs rename tests/run-pass/{ => stacked-borrows}/stacked-borrows.rs (100%) diff --git a/tests/run-pass/refcell.rs b/tests/run-pass/refcell.rs index 0bc8b15c5f24..93cef1572a3e 100644 --- a/tests/run-pass/refcell.rs +++ b/tests/run-pass/refcell.rs @@ -1,6 +1,6 @@ use std::cell::RefCell; -fn lots_of_funny_borrows() { +fn main() { let c = RefCell::new(42); { let s1 = c.borrow(); @@ -31,47 +31,3 @@ fn lots_of_funny_borrows() { let _y: i32 = *s2; } } - -fn aliasing_mut_and_shr() { - fn inner(rc: &RefCell, aliasing: &mut i32) { - *aliasing += 4; - let _escape_to_raw = rc as *const _; - *aliasing += 4; - let _shr = &*rc; - *aliasing += 4; - // also turning this into a frozen ref now must work - let aliasing = &*aliasing; - let _val = *aliasing; - let _escape_to_raw = rc as *const _; // this must NOT unfreeze - let _val = *aliasing; - let _shr = &*rc; // this must NOT unfreeze - let _val = *aliasing; - } - - let rc = RefCell::new(23); - let mut bmut = rc.borrow_mut(); - inner(&rc, &mut *bmut); - drop(bmut); - assert_eq!(*rc.borrow(), 23+12); -} - -fn aliasing_frz_and_shr() { - fn inner(rc: &RefCell, aliasing: &i32) { - let _val = *aliasing; - let _escape_to_raw = rc as *const _; // this must NOT unfreeze - let _val = *aliasing; - let _shr = &*rc; // this must NOT unfreeze - let _val = *aliasing; - } - - let rc = RefCell::new(23); - let bshr = rc.borrow(); - inner(&rc, &*bshr); - assert_eq!(*rc.borrow(), 23); -} - -fn main() { - lots_of_funny_borrows(); - aliasing_mut_and_shr(); - aliasing_frz_and_shr(); -} diff --git a/tests/run-pass/2phase.rs b/tests/run-pass/stacked-borrows/2phase.rs similarity index 100% rename from tests/run-pass/2phase.rs rename to tests/run-pass/stacked-borrows/2phase.rs diff --git a/tests/run-pass/stacked-borrows/refcell.rs b/tests/run-pass/stacked-borrows/refcell.rs new file mode 100644 index 000000000000..dddc7089d02d --- /dev/null +++ b/tests/run-pass/stacked-borrows/refcell.rs @@ -0,0 +1,44 @@ +use std::cell::RefCell; + +fn main() { + aliasing_mut_and_shr(); + aliasing_frz_and_shr(); +} + +fn aliasing_mut_and_shr() { + fn inner(rc: &RefCell, aliasing: &mut i32) { + *aliasing += 4; + let _escape_to_raw = rc as *const _; + *aliasing += 4; + let _shr = &*rc; + *aliasing += 4; + // also turning this into a frozen ref now must work + let aliasing = &*aliasing; + let _val = *aliasing; + let _escape_to_raw = rc as *const _; // this must NOT unfreeze + let _val = *aliasing; + let _shr = &*rc; // this must NOT unfreeze + let _val = *aliasing; + } + + let rc = RefCell::new(23); + let mut bmut = rc.borrow_mut(); + inner(&rc, &mut *bmut); + drop(bmut); + assert_eq!(*rc.borrow(), 23+12); +} + +fn aliasing_frz_and_shr() { + fn inner(rc: &RefCell, aliasing: &i32) { + let _val = *aliasing; + let _escape_to_raw = rc as *const _; // this must NOT unfreeze + let _val = *aliasing; + let _shr = &*rc; // this must NOT unfreeze + let _val = *aliasing; + } + + let rc = RefCell::new(23); + let bshr = rc.borrow(); + inner(&rc, &*bshr); + assert_eq!(*rc.borrow(), 23); +} diff --git a/tests/run-pass/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs similarity index 100% rename from tests/run-pass/stacked-borrows.rs rename to tests/run-pass/stacked-borrows/stacked-borrows.rs From 7b7fef1b53dab72a6a61951e166851ffc7d4bc82 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Apr 2019 08:42:41 +0200 Subject: [PATCH 0686/5092] let the permission of a new pointer depend on the type only --- src/stacked_borrows.rs | 264 +++++++++++++++++++---------------------- 1 file changed, 125 insertions(+), 139 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 152171aed066..ca257aaf1feb 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -5,7 +5,7 @@ use std::fmt; use std::num::NonZeroU64; use rustc::ty::{self, layout::Size}; -use rustc::hir::{Mutability, MutMutable, MutImmutable}; +use rustc::hir::{MutMutable, MutImmutable}; use rustc::mir::RetagKind; use crate::{ @@ -96,50 +96,38 @@ pub type MemoryState = Rc>; #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum AccessKind { Read, - Write { dealloc: bool }, -} - -// "Fake" constructors -impl AccessKind { - fn write() -> AccessKind { - AccessKind::Write { dealloc: false } - } - - fn dealloc() -> AccessKind { - AccessKind::Write { dealloc: true } - } + Write, } impl fmt::Display for AccessKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { AccessKind::Read => write!(f, "read"), - AccessKind::Write { dealloc: false } => write!(f, "write"), - AccessKind::Write { dealloc: true } => write!(f, "deallocation"), + AccessKind::Write => write!(f, "write"), } } } /// Indicates which kind of reference is being created. -/// Used by `reborrow` to compute which permissions to grant to the +/// Used by high-level `reborrow` to compute which permissions to grant to the /// new pointer. #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum RefKind { - /// `&mut`. - Mutable, + /// `&mut` and `Box`. + Unique, /// `&` with or without interior mutability. - Shared { frozen: bool }, - /// `*` (raw pointer). - Raw, + Shared, + /// `*mut`/`*const` (raw pointers). + Raw { mutable: bool }, } impl fmt::Display for RefKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - RefKind::Mutable => write!(f, "mutable"), - RefKind::Shared { frozen: true } => write!(f, "shared (frozen)"), - RefKind::Shared { frozen: false } => write!(f, "shared (mutable)"), - RefKind::Raw => write!(f, "raw"), + RefKind::Unique => write!(f, "unique"), + RefKind::Shared => write!(f, "shared"), + RefKind::Raw { mutable: true } => write!(f, "raw (mutable)"), + RefKind::Raw { mutable: false } => write!(f, "raw (constant)"), } } } @@ -216,7 +204,7 @@ impl Permission { // SharedReadOnly only permits read access. (Permission::SharedReadOnly, AccessKind::Read) => true, - (Permission::SharedReadOnly, AccessKind::Write { .. }) => + (Permission::SharedReadOnly, AccessKind::Write) => false, } } @@ -235,7 +223,7 @@ impl Permission { // When `other` is `SharedReadOnly`, that is NEVER compatible with // write accesses. // This makes sure read-only pointers become invalid on write accesses (ensures F2a). - (_, AccessKind::Write { .. }, SharedReadOnly) => + (_, AccessKind::Write, SharedReadOnly) => false, // When `other` is `Unique`, that is compatible with nothing. // This makes sure unique pointers become invalid on incompatible accesses (ensures U2). @@ -246,7 +234,7 @@ impl Permission { // (This is particularily important such that when a new mutable ref gets created, it gets // pushed into the right item -- this behaves like a write and we assert uniqueness of the // pointer from which this comes, *if* it was a unique pointer.) - (Unique, AccessKind::Write { .. }, _) => + (Unique, AccessKind::Write, _) => false, // `SharedReadWrite` items can tolerate any other akin items for any kind of access. (SharedReadWrite, _, SharedReadWrite) => @@ -262,42 +250,7 @@ impl Permission { } } -impl<'tcx> RefKind { - /// Defines which kind of access the "parent" must grant to create this reference. - fn access(self) -> AccessKind { - match self { - RefKind::Mutable | RefKind::Shared { frozen: false } => AccessKind::write(), - RefKind::Raw | RefKind::Shared { frozen: true } => AccessKind::Read, - // FIXME: Just requiring read-only access for raw means that a raw ptr might not be writeable - // even when we think it should be! Think about this some more. - } - } - - /// This defines the new permission used when a pointer gets created: For raw pointers, whether these are read-only - /// or read-write depends on the permission from which they derive. - fn new_perm(self, derived_from: Permission) -> EvalResult<'tcx, Permission> { - Ok(match (self, derived_from) { - // Do not derive writable safe pointer from read-only pointer! - (RefKind::Mutable, Permission::SharedReadOnly) => - return err!(MachineError(format!( - "deriving mutable reference from read-only pointer" - ))), - (RefKind::Shared { frozen: false }, Permission::SharedReadOnly) => - return err!(MachineError(format!( - "deriving shared reference with interior mutability from read-only pointer" - ))), - // Safe pointer cases. - (RefKind::Mutable, _) => Permission::Unique, - (RefKind::Shared { frozen: true }, _) => Permission::SharedReadOnly, - (RefKind::Shared { frozen: false }, _) => Permission::SharedReadWrite, - // Raw pointer cases. - (RefKind::Raw, Permission::SharedReadOnly) => Permission::SharedReadOnly, - (RefKind::Raw, _) => Permission::SharedReadWrite, - }) - } -} - -/// Core per-location operations: access, create. +/// Core per-location operations: access, dealloc, reborrow. impl<'tcx> Stack { /// Find the item granting the given kind of access to the given tag, and where that item is in the stack. fn find_granting(&self, access: AccessKind, tag: Tag) -> Option<(usize, Permission)> { @@ -326,7 +279,6 @@ impl<'tcx> Stack { // The second step is where barriers get implemented: they "protect" the items // below them, meaning that if we remove an item and then further up encounter a barrier, // we raise an error. - // Afterwards we just do some post-processing for deallocation accesses. // Step 1: Find granting item. let (granting_idx, granting_perm) = self.find_granting(access, tag) @@ -356,7 +308,7 @@ impl<'tcx> Stack { } else { // Aha! This is a bad one, remove it. let item = self.borrows.remove(cur); - trace!("access: popping item {}", item); + trace!("access: removing item {}", item); removed_item = Some(item); } } @@ -380,25 +332,38 @@ impl<'tcx> Stack { } } - // Post-processing. - // If we got here, we found a matching item. Congratulations! - // However, we are not done yet: If this access is deallocating, we must make sure - // there are no active barriers remaining on the stack. - if access == AccessKind::dealloc() { - for &itm in self.borrows.iter().rev() { - match itm { - Item::FnBarrier(call) if global.is_active(call) => { - return err!(MachineError(format!( - "deallocating with active barrier ({})", call - ))) - } - _ => {}, + // Done. + return Ok(granting_idx); + } + + /// Deallocate a location: Like a write access, but also there must be no + /// barriers at all. + fn dealloc( + &mut self, + tag: Tag, + global: &GlobalState, + ) -> EvalResult<'tcx> { + // Step 1: Find granting item. + self.find_granting(AccessKind::Write, tag) + .ok_or_else(|| InterpError::MachineError(format!( + "no item granting write access for deallocation to tag {} found in borrow stack", + tag, + )))?; + + // We must make sure there are no active barriers remaining on the stack. + // Also clear the stack, no more accesses are possible. + while let Some(itm) = self.borrows.pop() { + match itm { + Item::FnBarrier(call) if global.is_active(call) => { + return err!(MachineError(format!( + "deallocating with active barrier ({})", call + ))) } + _ => {}, } } - // Done. - return Ok(granting_idx); + Ok(()) } /// `reborrow` helper function. @@ -412,7 +377,7 @@ impl<'tcx> Stack { trace!("reborrow: avoiding redundant item {}", item); return; } - trace!("reborrow: pushing item {}", item); + trace!("reborrow: adding item {}", item); self.borrows.insert(position, item); } @@ -427,7 +392,7 @@ impl<'tcx> Stack { // that overlap. trace!("reborrow: avoiding redundant extra barrier"); } else { - trace!("reborrow: pushing barrier for call {}", call); + trace!("reborrow: adding barrier for call {}", call); self.borrows.push(itm); } } @@ -453,27 +418,22 @@ impl<'tcx> Stack { &mut self, derived_from: Tag, barrier: Option, - new_kind: RefKind, + new_perm: Permission, new_tag: Tag, global: &GlobalState, ) -> EvalResult<'tcx> { - // Find the permission "from which we derive". To this end we first have to decide - // if we derive from a permission that grants writes or just reads. - let access = new_kind.access(); - // Now we figure out which item grants our parent (`derived_from`) permission. - // We use that to determine (a) where to put the new item, and for raw pointers - // (b) whether to given read-only or read-write access. - // FIXME: This handling of raw pointers is fragile, very fragile. What if we do - // not get "the right one", like when there are multiple items granting `derived_from` - // and we accidentally create a read-only pointer? This can happen for two-phase borrows - // (then there's a `Unique` and a `SharedReadOnly` for the same tag), and for raw pointers - // (which currently all are `Untagged`). - let (derived_from_idx, derived_from_perm) = self.find_granting(access, derived_from) + // Figure out which access `perm` corresponds to. + let access = if new_perm.grants(AccessKind::Write) { + AccessKind::Write + } else { + AccessKind::Read + }; + // Now we figure out which item grants our parent (`derived_from`) this kind of access. + // We use that to determine where to put the new item. + let (derived_from_idx, _) = self.find_granting(access, derived_from) .ok_or_else(|| InterpError::MachineError(format!( - "no item to reborrow as {} from tag {} found in borrow stack", new_kind, derived_from, + "no item to reborrow for {:?} from tag {} found in borrow stack", new_perm, derived_from, )))?; - // With this we can compute the permission for the new pointer. - let new_perm = new_kind.new_perm(derived_from_perm).expect("this should never fail"); // We behave very differently for the "unsafe" case of a shared-read-write pointer // ("unsafe" because this also applies to shared references with interior mutability). @@ -530,8 +490,9 @@ impl<'tcx> Stack { Ok(()) } } +// # Stacked Borrows Core End -/// Higher-level per-location operations: deref, access, reborrow. +/// Higher-level per-location operations: deref, access, dealloc, reborrow. impl<'tcx> Stacks { /// Creates new stack with initial tag. pub(crate) fn new( @@ -554,16 +515,34 @@ impl<'tcx> Stacks { &self, ptr: Pointer, size: Size, - kind: AccessKind, + access: AccessKind, ) -> EvalResult<'tcx> { - trace!("{} access of tag {}: {:?}, size {}", kind, ptr.tag, ptr, size.bytes()); + trace!("{} access of tag {}: {:?}, size {}", access, ptr.tag, ptr, size.bytes()); // Even reads can have a side-effect, by invalidating other references. // This is fundamentally necessary since `&mut` asserts that there // are no accesses through other references, not even reads. let global = self.global.borrow(); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { - stack.access(kind, ptr.tag, &*global)?; + stack.access(access, ptr.tag, &*global)?; + } + Ok(()) + } + + /// `ptr` is used to deallocate. + fn dealloc( + &self, + ptr: Pointer, + size: Size, + ) -> EvalResult<'tcx> { + trace!("deallocation with tag {}: {:?}, size {}", ptr.tag, ptr, size.bytes()); + // Even reads can have a side-effect, by invalidating other references. + // This is fundamentally necessary since `&mut` asserts that there + // are no accesses through other references, not even reads. + let global = self.global.borrow(); + let mut stacks = self.stacks.borrow_mut(); + for stack in stacks.iter_mut(ptr.offset, size) { + stack.dealloc(ptr.tag, &*global)?; } Ok(()) } @@ -575,26 +554,23 @@ impl<'tcx> Stacks { ptr: Pointer, size: Size, barrier: Option, - new_kind: RefKind, + new_perm: Permission, new_tag: Tag, ) -> EvalResult<'tcx> { trace!( - "{} reborrow for tag {} to {}: {:?}, size {}", - new_kind, ptr.tag, new_tag, ptr, size.bytes(), + "reborrow tag {} as {:?} {}: {:?}, size {}", + ptr.tag, new_perm, new_tag, ptr, size.bytes(), ); let global = self.global.borrow(); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { - stack.reborrow(ptr.tag, barrier, new_kind, new_tag, &*global)?; + stack.reborrow(ptr.tag, barrier, new_perm, new_tag, &*global)?; } Ok(()) } } -// # Stacked Borrows Core End - -// Glue code to connect with Miri Machine Hooks - +/// Glue code to connect with Miri Machine Hooks impl Stacks { pub fn new_allocation( size: Size, @@ -638,7 +614,7 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - alloc.extra.access(ptr, size, AccessKind::write()) + alloc.extra.access(ptr, size, AccessKind::Write) } #[inline(always)] @@ -647,42 +623,48 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - alloc.extra.access(ptr, size, AccessKind::dealloc()) + alloc.extra.dealloc(ptr, size) } } impl<'a, 'mir, 'tcx> EvalContextPrivExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { + /// High-level `reborrow` operation. This decides which reference gets which kind + /// of permission! fn reborrow( &mut self, place: MPlaceTy<'tcx, Tag>, size: Size, - mutbl: Option, + kind: RefKind, new_tag: Tag, fn_barrier: bool, ) -> EvalResult<'tcx> { let this = self.eval_context_mut(); let barrier = if fn_barrier { Some(this.frame().extra) } else { None }; let ptr = place.ptr.to_ptr()?; - trace!("reborrow: creating new reference for {:?} (pointee {}): {:?}", - ptr, place.layout.ty, new_tag); + trace!("reborrow: creating new reference for {:?} (pointee {}): {}, {:?}", + ptr, place.layout.ty, kind, new_tag); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. let alloc = this.memory().get(ptr.alloc_id)?; alloc.check_bounds(this, ptr, size)?; // Update the stacks. - if mutbl == Some(MutImmutable) { - // Reference that cares about freezing. We need a frozen-sensitive reborrow. - this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { - let new_kind = RefKind::Shared { frozen }; - alloc.extra.reborrow(cur_ptr, size, barrier, new_kind, new_tag) - })?; - } else { - // Just treat this as one big chunk. - let new_kind = if mutbl == Some(MutMutable) { RefKind::Mutable } else { RefKind::Raw }; - alloc.extra.reborrow(ptr, size, barrier, new_kind, new_tag)?; - } - Ok(()) + let perm = match kind { + RefKind::Unique => Permission::Unique, + RefKind::Raw { mutable: true } => Permission::SharedReadWrite, + RefKind::Shared | RefKind::Raw { mutable: false } => { + // Shared references and *const are a whole different kind of game, the + // permission is not uniform across the entire range! + // We need a frozen-sensitive reborrow. + return this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { + // We are only ever `SharedReadOnly` inside the frozen bits. + let perm = if frozen { Permission::SharedReadOnly } else { Permission::SharedReadWrite }; + alloc.extra.reborrow(cur_ptr, size, barrier, perm, new_tag) + }); + } + }; + debug_assert_ne!(perm, Permission::SharedReadOnly, "SharedReadOnly must be used frozen-sensitive"); + return alloc.extra.reborrow(ptr, size, barrier, perm, new_tag); } /// Retags an indidual pointer, returning the retagged version. @@ -690,7 +672,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, fn retag_reference( &mut self, val: ImmTy<'tcx, Tag>, - mutbl: Option, + kind: RefKind, fn_barrier: bool, two_phase: bool, ) -> EvalResult<'tcx, Immediate> { @@ -706,24 +688,24 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } // Compute new borrow. - let new_tag = match mutbl { - Some(_) => Tag::Tagged(this.memory().extra.borrow_mut().new_ptr()), - None => Tag::Untagged, + let new_tag = match kind { + RefKind::Raw { .. } => Tag::Untagged, + _ => Tag::Tagged(this.memory().extra.borrow_mut().new_ptr()), }; // Reborrow. - this.reborrow(place, size, mutbl, new_tag, fn_barrier)?; + this.reborrow(place, size, kind, new_tag, fn_barrier)?; let new_place = place.replace_tag(new_tag); // Handle two-phase borrows. if two_phase { - assert!(mutbl == Some(MutMutable), "two-phase shared borrows make no sense"); + assert!(kind == RefKind::Unique, "two-phase shared borrows make no sense"); // Grant read access *to the parent pointer* with the old tag. This means the same pointer // has multiple items in the stack now! // FIXME: Think about this some more, in particular about the interaction with cast-to-raw. // Maybe find a better way to express 2-phase, now that we have a "more expressive language" // in the stack. let old_tag = place.ptr.to_ptr().unwrap().tag; - this.reborrow(new_place, size, Some(MutImmutable), old_tag, /* fn_barrier: */ false)?; + this.reborrow(new_place, size, RefKind::Shared, old_tag, /* fn_barrier: */ false)?; } // Return new pointer. @@ -742,15 +724,19 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // Determine mutability and whether to add a barrier. // Cannot use `builtin_deref` because that reports *immutable* for `Box`, // making it useless. - fn qualify(ty: ty::Ty<'_>, kind: RetagKind) -> Option<(Option, bool)> { + fn qualify(ty: ty::Ty<'_>, kind: RetagKind) -> Option<(RefKind, bool)> { match ty.sty { // References are simple. - ty::Ref(_, _, mutbl) => Some((Some(mutbl), kind == RetagKind::FnEntry)), + ty::Ref(_, _, MutMutable) => + Some((RefKind::Unique, kind == RetagKind::FnEntry)), + ty::Ref(_, _, MutImmutable) => + Some((RefKind::Shared, kind == RetagKind::FnEntry)), // Raw pointers need to be enabled. - ty::RawPtr(..) if kind == RetagKind::Raw => Some((None, false)), + ty::RawPtr(tym) if kind == RetagKind::Raw => + Some((RefKind::Raw { mutable: tym.mutbl == MutMutable }, false)), // Boxes do not get a barrier: barriers reflect that references outlive the call // they were passed in to; that's just not the case for boxes. - ty::Adt(..) if ty.is_box() => Some((Some(MutMutable), false)), + ty::Adt(..) if ty.is_box() => Some((RefKind::Unique, false)), _ => None, } } From 14e701f7d8008656327094056e800af506b0f6a4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Apr 2019 14:23:21 +0200 Subject: [PATCH 0687/5092] abstract mapping over all the stacks in some memory range --- src/stacked_borrows.rs | 83 ++++++++++++++---------------------------- 1 file changed, 27 insertions(+), 56 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index ca257aaf1feb..7c0a72cde3c0 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -492,7 +492,7 @@ impl<'tcx> Stack { } // # Stacked Borrows Core End -/// Higher-level per-location operations: deref, access, dealloc, reborrow. +/// Map per-stack operations to higher-level per-location-range operations. impl<'tcx> Stacks { /// Creates new stack with initial tag. pub(crate) fn new( @@ -510,61 +510,17 @@ impl<'tcx> Stacks { } } - /// `ptr` got used, reflect that in the stack. - fn access( + /// Call `f` on every stack in the range. + fn for_each( &self, ptr: Pointer, size: Size, - access: AccessKind, + f: impl Fn(&mut Stack, Tag, &GlobalState) -> EvalResult<'tcx>, ) -> EvalResult<'tcx> { - trace!("{} access of tag {}: {:?}, size {}", access, ptr.tag, ptr, size.bytes()); - // Even reads can have a side-effect, by invalidating other references. - // This is fundamentally necessary since `&mut` asserts that there - // are no accesses through other references, not even reads. let global = self.global.borrow(); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { - stack.access(access, ptr.tag, &*global)?; - } - Ok(()) - } - - /// `ptr` is used to deallocate. - fn dealloc( - &self, - ptr: Pointer, - size: Size, - ) -> EvalResult<'tcx> { - trace!("deallocation with tag {}: {:?}, size {}", ptr.tag, ptr, size.bytes()); - // Even reads can have a side-effect, by invalidating other references. - // This is fundamentally necessary since `&mut` asserts that there - // are no accesses through other references, not even reads. - let global = self.global.borrow(); - let mut stacks = self.stacks.borrow_mut(); - for stack in stacks.iter_mut(ptr.offset, size) { - stack.dealloc(ptr.tag, &*global)?; - } - Ok(()) - } - - /// Reborrow the given pointer to the new tag for the given kind of reference. - /// This works on `&self` because we might encounter references to constant memory. - fn reborrow( - &self, - ptr: Pointer, - size: Size, - barrier: Option, - new_perm: Permission, - new_tag: Tag, - ) -> EvalResult<'tcx> { - trace!( - "reborrow tag {} as {:?} {}: {:?}, size {}", - ptr.tag, new_perm, new_tag, ptr, size.bytes(), - ); - let global = self.global.borrow(); - let mut stacks = self.stacks.borrow_mut(); - for stack in stacks.iter_mut(ptr.offset, size) { - stack.reborrow(ptr.tag, barrier, new_perm, new_tag, &*global)?; + f(stack, ptr.tag, &*global)?; } Ok(()) } @@ -605,7 +561,11 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - alloc.extra.access(ptr, size, AccessKind::Read) + trace!("read access with tag {}: {:?}, size {}", ptr.tag, ptr, size.bytes()); + alloc.extra.for_each(ptr, size, |stack, tag, global| { + stack.access(AccessKind::Read, tag, global)?; + Ok(()) + }) } #[inline(always)] @@ -614,7 +574,11 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - alloc.extra.access(ptr, size, AccessKind::Write) + trace!("write access with tag {}: {:?}, size {}", ptr.tag, ptr, size.bytes()); + alloc.extra.for_each(ptr, size, |stack, tag, global| { + stack.access(AccessKind::Write, tag, global)?; + Ok(()) + }) } #[inline(always)] @@ -623,7 +587,10 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - alloc.extra.dealloc(ptr, size) + trace!("deallocation with tag {}: {:?}, size {}", ptr.tag, ptr, size.bytes()); + alloc.extra.for_each(ptr, size, |stack, tag, global| { + stack.dealloc(tag, global) + }) } } @@ -642,8 +609,8 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let this = self.eval_context_mut(); let barrier = if fn_barrier { Some(this.frame().extra) } else { None }; let ptr = place.ptr.to_ptr()?; - trace!("reborrow: creating new reference for {:?} (pointee {}): {}, {:?}", - ptr, place.layout.ty, kind, new_tag); + trace!("reborrow: {:?} reference {} derived from {} (pointee {}): {:?}, size {}", + kind, new_tag, ptr.tag, place.layout.ty, ptr, size.bytes()); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. let alloc = this.memory().get(ptr.alloc_id)?; @@ -659,12 +626,16 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, return this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { // We are only ever `SharedReadOnly` inside the frozen bits. let perm = if frozen { Permission::SharedReadOnly } else { Permission::SharedReadWrite }; - alloc.extra.reborrow(cur_ptr, size, barrier, perm, new_tag) + alloc.extra.for_each(cur_ptr, size, |stack, tag, global| { + stack.reborrow(tag, barrier, perm, new_tag, global) + }) }); } }; debug_assert_ne!(perm, Permission::SharedReadOnly, "SharedReadOnly must be used frozen-sensitive"); - return alloc.extra.reborrow(ptr, size, barrier, perm, new_tag); + alloc.extra.for_each(ptr, size, |stack, tag, global| { + stack.reborrow(tag, barrier, perm, new_tag, global) + }) } /// Retags an indidual pointer, returning the retagged version. From e7a500b7e112be64e90517316a527e3a4a239437 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Apr 2019 14:28:45 +0200 Subject: [PATCH 0688/5092] test creating two raw pointers from the same mutable ref --- tests/run-pass/stacked-borrows/stacked-borrows.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index 711026c02dfc..791e97f0eb1e 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -10,6 +10,7 @@ fn main() { partially_invalidate_mut(); drop_after_sharing(); direct_mut_to_const_raw(); + two_raw(); } // Deref a raw ptr to access a field of a large struct, where the field @@ -123,3 +124,15 @@ fn direct_mut_to_const_raw() { assert_eq!(*x, 1); */ } + +// Make sure that we can create two raw pointers from a mutable reference and use them both. +fn two_raw() { unsafe { + let x = &mut 0; + // Given the implicit reborrows, the only reason this currently works is that we + // do not track raw pointers: The creation of `y2` reborrows `x` and thus pops + // `y1` off the stack. + let y1 = x as *mut _; + let y2 = x as *mut _; + *y1 += 2; + *y2 += 1; +} } From 46d5fd848773dcb3699344a8927a21e285d9207a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Apr 2019 14:57:13 +0200 Subject: [PATCH 0689/5092] barriers are dead, long live protectors -- this enables overlapping two-phase borrows! --- src/stacked_borrows.rs | 255 ++++++++---------- .../stacked_borrows/aliasing_mut1.rs | 2 +- .../stacked_borrows/aliasing_mut2.rs | 2 +- .../stacked_borrows/aliasing_mut4.rs | 2 +- .../deallocate_against_barrier.rs | 2 +- .../invalidate_against_barrier1.rs | 2 +- .../invalidate_against_barrier2.rs | 2 +- tests/run-pass/stacked-borrows/2phase.rs | 15 +- 8 files changed, 120 insertions(+), 162 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 7c0a72cde3c0..98b6ca6543f2 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -15,7 +15,7 @@ use crate::{ }; pub type PtrId = NonZeroU64; -pub type CallId = u64; +pub type CallId = NonZeroU64; /// Tracking pointer provenance #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] @@ -46,19 +46,23 @@ pub enum Permission { /// An item in the per-location borrow stack. #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -pub enum Item { - /// Grants the given permission for pointers with this tag. - Permission(Permission, Tag), - /// A barrier, tracking the function it belongs to by its index on the call stack. - FnBarrier(CallId), +pub struct Item { + /// The permission this item grants. + perm: Permission, + /// The pointers the permission is granted to. + tag: Tag, + /// An optional protector, ensuring the item cannot get popped until `CallId` is over. + protector: Option, } impl fmt::Display for Item { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Item::Permission(perm, tag) => write!(f, "[{:?} for {}]", perm, tag), - Item::FnBarrier(call) => write!(f, "[barrier {}]", call), + write!(f, "[{:?} for {}", self.perm, self.tag)?; + if let Some(call) = self.protector { + write!(f, " (call {})", call)?; } + write!(f, "]")?; + Ok(()) } } @@ -69,7 +73,7 @@ pub struct Stack { /// We sometimes push into the middle but never remove from the middle. /// The same tag may occur multiple times, e.g. from a two-phase borrow. /// Invariants: - /// * Above a `SharedReadOnly` there can only be barriers and more `SharedReadOnly`. + /// * Above a `SharedReadOnly` there can only be more `SharedReadOnly`. borrows: Vec, } @@ -137,7 +141,7 @@ impl Default for GlobalState { fn default() -> Self { GlobalState { next_ptr_id: NonZeroU64::new(1).unwrap(), - next_call_id: 0, + next_call_id: NonZeroU64::new(1).unwrap(), active_calls: HashSet::default(), } } @@ -154,7 +158,7 @@ impl GlobalState { let id = self.next_call_id; trace!("new_call: Assigning ID {}", id); self.active_calls.insert(id); - self.next_call_id = id+1; + self.next_call_id = NonZeroU64::new(id.get() + 1).unwrap(); id } @@ -232,7 +236,7 @@ impl Permission { // When we are unique and this is a write/dealloc, we tolerate nothing. // This makes sure we re-assert uniqueness ("being on top") on write accesses. // (This is particularily important such that when a new mutable ref gets created, it gets - // pushed into the right item -- this behaves like a write and we assert uniqueness of the + // pushed onto the right item -- this behaves like a write and we assert uniqueness of the // pointer from which this comes, *if* it was a unique pointer.) (Unique, AccessKind::Write, _) => false, @@ -259,11 +263,13 @@ impl<'tcx> Stack { .rev() // search top-to-bottom // Return permission of first item that grants access. // We require a permission with the right tag, ensuring U3 and F3. - .filter_map(|(idx, item)| match item { - &Item::Permission(perm, item_tag) if perm.grants(access) && tag == item_tag => - Some((idx, perm)), - _ => None, - }) + .filter_map(|(idx, item)| + if item.perm.grants(access) && tag == item.tag { + Some((idx, item.perm)) + } else { + None + } + ) .next() } @@ -276,9 +282,6 @@ impl<'tcx> Stack { global: &GlobalState, ) -> EvalResult<'tcx, usize> { // Two main steps: Find granting item, remove all incompatible items above. - // The second step is where barriers get implemented: they "protect" the items - // below them, meaning that if we remove an item and then further up encounter a barrier, - // we raise an error. // Step 1: Find granting item. let (granting_idx, granting_perm) = self.find_granting(access, tag) @@ -287,47 +290,35 @@ impl<'tcx> Stack { access, tag, )))?; - // Step 2: Remove everything incompatible above them. - // Items below an active barrier however may not be removed, so we check that as well. + // Step 2: Remove everything incompatible above them. Make sure we do not remove protected + // items. // We do *not* maintain a stack discipline here. We could, in principle, decide to only // keep the items immediately above `granting_idx` that are compatible, and then pop the rest. // However, that kills off entire "branches" of pointer derivation too easily: // in `let raw = &mut *x as *mut _; let _val = *x;`, the second statement would pop the `Unique` // from the reborrow of the first statement, and subequently also pop the `SharedReadWrite` for `raw`. + // This pattern occurs a lot in the standard library: create a raw pointer, then also create a shared + // reference and use that. { // Implemented with indices because there does not seem to be a nice iterator and range-based // API for this. let mut cur = granting_idx + 1; - let mut removed_item = None; while let Some(item) = self.borrows.get(cur) { - match *item { - Item::Permission(perm, _) => { - if granting_perm.compatible_with(access, perm) { - // Keep this, check next. - cur += 1; - } else { - // Aha! This is a bad one, remove it. - let item = self.borrows.remove(cur); - trace!("access: removing item {}", item); - removed_item = Some(item); - } - } - Item::FnBarrier(call) if !global.is_active(call) => { - // An inactive barrier, just get rid of it. (Housekeeping.) - self.borrows.remove(cur); - } - Item::FnBarrier(call) => { - // We hit an active barrier! If we have already removed an item, - // we got a problem! The barrier was supposed to protect this item. - if let Some(removed_item) = removed_item { + if granting_perm.compatible_with(access, item.perm) { + // Keep this, check next. + cur += 1; + } else { + // Aha! This is a bad one, remove it, and make sure it is not protected. + let item = self.borrows.remove(cur); + if let Some(call) = item.protector { + if global.is_active(call) { return err!(MachineError(format!( - "not granting {} access to tag {} because barrier ({}) protects incompatible item {}", - access, tag, call, removed_item + "not granting {} access to tag {} because incompatible item {} is protected", + access, tag, item ))); } - // Keep this, check next. - cur += 1; } + trace!("access: removing item {}", item); } } } @@ -337,7 +328,7 @@ impl<'tcx> Stack { } /// Deallocate a location: Like a write access, but also there must be no - /// barriers at all. + /// active protectors at all. fn dealloc( &mut self, tag: Tag, @@ -350,63 +341,32 @@ impl<'tcx> Stack { tag, )))?; - // We must make sure there are no active barriers remaining on the stack. + // We must make sure there are no protected items remaining on the stack. // Also clear the stack, no more accesses are possible. - while let Some(itm) = self.borrows.pop() { - match itm { - Item::FnBarrier(call) if global.is_active(call) => { + while let Some(item) = self.borrows.pop() { + if let Some(call) = item.protector { + if global.is_active(call) { return err!(MachineError(format!( - "deallocating with active barrier ({})", call + "deallocating with active protector ({})", call ))) } - _ => {}, } } Ok(()) } - /// `reborrow` helper function. - /// Grant `permisson` to new pointer tagged `tag`, added at `position` in the stack. - fn grant(&mut self, perm: Permission, tag: Tag, position: usize) { - // Simply add it to the "stack" -- this might add in the middle. - // As an optimization, do nothing if the new item is identical to one of its neighbors. - let item = Item::Permission(perm, tag); - if self.borrows[position-1] == item || self.borrows.get(position) == Some(&item) { - // Optimization applies, done. - trace!("reborrow: avoiding redundant item {}", item); - return; - } - trace!("reborrow: adding item {}", item); - self.borrows.insert(position, item); - } - - /// `reborrow` helper function. - /// Adds a barrier. - fn barrier(&mut self, call: CallId) { - let itm = Item::FnBarrier(call); - if *self.borrows.last().unwrap() == itm { - // This is just an optimization, no functional change: Avoid stacking - // multiple identical barriers on top of each other. - // This can happen when a function receives several shared references - // that overlap. - trace!("reborrow: avoiding redundant extra barrier"); - } else { - trace!("reborrow: adding barrier for call {}", call); - self.borrows.push(itm); - } - } - /// `reborrow` helper function: test that the stack invariants are still maintained. fn test_invariants(&self) { let mut saw_shared_read_only = false; for item in self.borrows.iter() { - match item { - Item::Permission(Permission::SharedReadOnly, _) => { + match item.perm { + Permission::SharedReadOnly => { saw_shared_read_only = true; } - Item::Permission(perm, _) if saw_shared_read_only => { - panic!("Found {:?} on top of a SharedReadOnly!", perm); + // Otherwise, if we saw one before, that's a bug. + perm if saw_shared_read_only => { + bug!("Found {:?} on top of a SharedReadOnly!", perm); } _ => {} } @@ -414,16 +374,18 @@ impl<'tcx> Stack { } /// Derived a new pointer from one with the given tag. + /// `weak` controls whether this is a weak reborrow: weak reborrows do not act as + /// accesses, and they add the new item directly on top of the one it is derived + /// from instead of all the way at the top of the stack. fn reborrow( &mut self, derived_from: Tag, - barrier: Option, - new_perm: Permission, - new_tag: Tag, + weak: bool, + new: Item, global: &GlobalState, ) -> EvalResult<'tcx> { // Figure out which access `perm` corresponds to. - let access = if new_perm.grants(AccessKind::Write) { + let access = if new.perm.grants(AccessKind::Write) { AccessKind::Write } else { AccessKind::Read @@ -432,16 +394,13 @@ impl<'tcx> Stack { // We use that to determine where to put the new item. let (derived_from_idx, _) = self.find_granting(access, derived_from) .ok_or_else(|| InterpError::MachineError(format!( - "no item to reborrow for {:?} from tag {} found in borrow stack", new_perm, derived_from, + "no item to reborrow for {:?} from tag {} found in borrow stack", new.perm, derived_from, )))?; - // We behave very differently for the "unsafe" case of a shared-read-write pointer - // ("unsafe" because this also applies to shared references with interior mutability). - // This is because such pointers may be reborrowed to unique pointers that actually - // remain valid when their "parents" get further reborrows! - // However, either way, we ensure that we insert the new item in a way that between + // Compute where to put the new item. + // Either way, we ensure that we insert the new item in a way that between // `derived_from` and the new one, there are only items *compatible with* `derived_from`. - if new_perm == Permission::SharedReadWrite { + let new_idx = if weak { // A very liberal reborrow because the new pointer does not expect any kind of aliasing guarantee. // Just insert new permission as child of old permission, and maintain everything else. // This inserts "as far down as possible", which is good because it makes this pointer as @@ -451,17 +410,7 @@ impl<'tcx> Stack { // and we'd allow write access without invalidating frozen shared references! // This ensures F2b for `SharedReadWrite` by adding the new item below any // potentially existing `SharedReadOnly`. - self.grant(new_perm, new_tag, derived_from_idx+1); - - // No barrier. They can rightfully alias with `&mut`. - // FIXME: This means that the `dereferencable` attribute on non-frozen shared references - // is incorrect! They are dereferencable when the function is called, but might become - // non-dereferencable during the course of execution. - // Also see [1], [2]. - // - // [1]: , - // [2]: + derived_from_idx+1 } else { // A "safe" reborrow for a pointer that actually expects some aliasing guarantees. // Here, creating a reference actually counts as an access, and pops incompatible @@ -474,12 +423,16 @@ impl<'tcx> Stack { // on top of `derived_from`, and we want the new item at the top so that we // get the strongest possible guarantees. // This ensures U1 and F1. - self.grant(new_perm, new_tag, self.borrows.len()); + self.borrows.len() + }; - // Now is a good time to add the barrier, protecting the item we just added. - if let Some(call) = barrier { - self.barrier(call); - } + // Put the new item there. As an optimization, deduplicate if it is equal to one of its new neighbors. + if self.borrows[new_idx-1] == new || self.borrows.get(new_idx) == Some(&new) { + // Optimization applies, done. + trace!("reborrow: avoiding adding redundant item {}", new); + } else { + trace!("reborrow: adding item {}", new); + self.borrows.insert(new_idx, new); } // Make sure that after all this, the stack's invariant is still maintained. @@ -500,7 +453,7 @@ impl<'tcx> Stacks { tag: Tag, extra: MemoryState, ) -> Self { - let item = Item::Permission(Permission::Unique, tag); + let item = Item { perm: Permission::Unique, tag, protector: None }; let stack = Stack { borrows: vec![item], }; @@ -515,12 +468,12 @@ impl<'tcx> Stacks { &self, ptr: Pointer, size: Size, - f: impl Fn(&mut Stack, Tag, &GlobalState) -> EvalResult<'tcx>, + f: impl Fn(&mut Stack, &GlobalState) -> EvalResult<'tcx>, ) -> EvalResult<'tcx> { let global = self.global.borrow(); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { - f(stack, ptr.tag, &*global)?; + f(stack, &*global)?; } Ok(()) } @@ -562,8 +515,8 @@ impl AllocationExtra for Stacks { size: Size, ) -> EvalResult<'tcx> { trace!("read access with tag {}: {:?}, size {}", ptr.tag, ptr, size.bytes()); - alloc.extra.for_each(ptr, size, |stack, tag, global| { - stack.access(AccessKind::Read, tag, global)?; + alloc.extra.for_each(ptr, size, |stack, global| { + stack.access(AccessKind::Read, ptr.tag, global)?; Ok(()) }) } @@ -575,8 +528,8 @@ impl AllocationExtra for Stacks { size: Size, ) -> EvalResult<'tcx> { trace!("write access with tag {}: {:?}, size {}", ptr.tag, ptr, size.bytes()); - alloc.extra.for_each(ptr, size, |stack, tag, global| { - stack.access(AccessKind::Write, tag, global)?; + alloc.extra.for_each(ptr, size, |stack, global| { + stack.access(AccessKind::Write, ptr.tag, global)?; Ok(()) }) } @@ -588,26 +541,28 @@ impl AllocationExtra for Stacks { size: Size, ) -> EvalResult<'tcx> { trace!("deallocation with tag {}: {:?}, size {}", ptr.tag, ptr, size.bytes()); - alloc.extra.for_each(ptr, size, |stack, tag, global| { - stack.dealloc(tag, global) + alloc.extra.for_each(ptr, size, |stack, global| { + stack.dealloc(ptr.tag, global) }) } } +/// Retagging/reborrowing. There is some policy in here, such as which permissions +/// to grant for which references, when to add protectors, and how to realize two-phase +/// borrows in terms of the primitives above. impl<'a, 'mir, 'tcx> EvalContextPrivExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { - /// High-level `reborrow` operation. This decides which reference gets which kind - /// of permission! fn reborrow( &mut self, place: MPlaceTy<'tcx, Tag>, size: Size, kind: RefKind, new_tag: Tag, - fn_barrier: bool, + force_weak: bool, + protect: bool, ) -> EvalResult<'tcx> { let this = self.eval_context_mut(); - let barrier = if fn_barrier { Some(this.frame().extra) } else { None }; + let protector = if protect { Some(this.frame().extra) } else { None }; let ptr = place.ptr.to_ptr()?; trace!("reborrow: {:?} reference {} derived from {} (pointee {}): {:?}, size {}", kind, new_tag, ptr.tag, place.layout.ty, ptr, size.bytes()); @@ -616,6 +571,8 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let alloc = this.memory().get(ptr.alloc_id)?; alloc.check_bounds(this, ptr, size)?; // Update the stacks. + // Make sure that raw pointers and mutable shared references are reborrowed "weak": + // There could be existing unique pointers reborrowed from them that should remain valid! let perm = match kind { RefKind::Unique => Permission::Unique, RefKind::Raw { mutable: true } => Permission::SharedReadWrite, @@ -625,16 +582,20 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // We need a frozen-sensitive reborrow. return this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { // We are only ever `SharedReadOnly` inside the frozen bits. + let weak = !frozen || kind != RefKind::Shared; // `RefKind::Raw` is always weak, as is `SharedReadWrite`. let perm = if frozen { Permission::SharedReadOnly } else { Permission::SharedReadWrite }; - alloc.extra.for_each(cur_ptr, size, |stack, tag, global| { - stack.reborrow(tag, barrier, perm, new_tag, global) + let item = Item { perm, tag: new_tag, protector }; + alloc.extra.for_each(cur_ptr, size, |stack, global| { + stack.reborrow(cur_ptr.tag, force_weak || weak, item, global) }) }); } }; debug_assert_ne!(perm, Permission::SharedReadOnly, "SharedReadOnly must be used frozen-sensitive"); - alloc.extra.for_each(ptr, size, |stack, tag, global| { - stack.reborrow(tag, barrier, perm, new_tag, global) + let weak = perm == Permission::SharedReadWrite; + let item = Item { perm, tag: new_tag, protector }; + alloc.extra.for_each(ptr, size, |stack, global| { + stack.reborrow(ptr.tag, force_weak || weak, item, global) }) } @@ -644,7 +605,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, &mut self, val: ImmTy<'tcx, Tag>, kind: RefKind, - fn_barrier: bool, + protect: bool, two_phase: bool, ) -> EvalResult<'tcx, Immediate> { let this = self.eval_context_mut(); @@ -665,18 +626,16 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, }; // Reborrow. - this.reborrow(place, size, kind, new_tag, fn_barrier)?; + this.reborrow(place, size, kind, new_tag, /*force_weak:*/ two_phase, protect)?; let new_place = place.replace_tag(new_tag); // Handle two-phase borrows. if two_phase { assert!(kind == RefKind::Unique, "two-phase shared borrows make no sense"); - // Grant read access *to the parent pointer* with the old tag. This means the same pointer - // has multiple items in the stack now! - // FIXME: Think about this some more, in particular about the interaction with cast-to-raw. - // Maybe find a better way to express 2-phase, now that we have a "more expressive language" - // in the stack. + // Grant read access *to the parent pointer* with the old tag *derived from the new tag* (`new_place`). + // This means the old pointer has multiple items in the stack now, which otherwise cannot happen + // for unique references -- but in this case it precisely expresses the semantics we want. let old_tag = place.ptr.to_ptr().unwrap().tag; - this.reborrow(new_place, size, RefKind::Shared, old_tag, /* fn_barrier: */ false)?; + this.reborrow(new_place, size, RefKind::Shared, old_tag, /*force_weak:*/ false, /*protect:*/ false)?; } // Return new pointer. @@ -692,7 +651,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, place: PlaceTy<'tcx, Tag> ) -> EvalResult<'tcx> { let this = self.eval_context_mut(); - // Determine mutability and whether to add a barrier. + // Determine mutability and whether to add a protector. // Cannot use `builtin_deref` because that reports *immutable* for `Box`, // making it useless. fn qualify(ty: ty::Ty<'_>, kind: RetagKind) -> Option<(RefKind, bool)> { @@ -705,7 +664,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // Raw pointers need to be enabled. ty::RawPtr(tym) if kind == RetagKind::Raw => Some((RefKind::Raw { mutable: tym.mutbl == MutMutable }, false)), - // Boxes do not get a barrier: barriers reflect that references outlive the call + // Boxes do not get a protector: protectors reflect that references outlive the call // they were passed in to; that's just not the case for boxes. ty::Adt(..) if ty.is_box() => Some((RefKind::Unique, false)), _ => None, @@ -715,10 +674,10 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // We need a visitor to visit all references. However, that requires // a `MemPlace`, so we have a fast path for reference types that // avoids allocating. - if let Some((mutbl, barrier)) = qualify(place.layout.ty, kind) { + if let Some((mutbl, protector)) = qualify(place.layout.ty, kind) { // Fast path. let val = this.read_immediate(this.place_to_op(place)?)?; - let val = this.retag_reference(val, mutbl, barrier, kind == RetagKind::TwoPhase)?; + let val = this.retag_reference(val, mutbl, protector, kind == RetagKind::TwoPhase)?; this.write_immediate(val, place)?; return Ok(()); } @@ -749,12 +708,12 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, { // Cannot use `builtin_deref` because that reports *immutable* for `Box`, // making it useless. - if let Some((mutbl, barrier)) = qualify(place.layout.ty, self.kind) { + if let Some((mutbl, protector)) = qualify(place.layout.ty, self.kind) { let val = self.ecx.read_immediate(place.into())?; let val = self.ecx.retag_reference( val, mutbl, - barrier, + protector, self.kind == RetagKind::TwoPhase )?; self.ecx.write_immediate(val, place.into())?; diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut1.rs b/tests/compile-fail/stacked_borrows/aliasing_mut1.rs index 9bced43f6e85..d047925163bd 100644 --- a/tests/compile-fail/stacked_borrows/aliasing_mut1.rs +++ b/tests/compile-fail/stacked_borrows/aliasing_mut1.rs @@ -1,6 +1,6 @@ use std::mem; -pub fn safe(_x: &mut i32, _y: &mut i32) {} //~ ERROR barrier +pub fn safe(_x: &mut i32, _y: &mut i32) {} //~ ERROR protect fn main() { let mut x = 0; diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut2.rs b/tests/compile-fail/stacked_borrows/aliasing_mut2.rs index ea24f1bd2748..c679e01677eb 100644 --- a/tests/compile-fail/stacked_borrows/aliasing_mut2.rs +++ b/tests/compile-fail/stacked_borrows/aliasing_mut2.rs @@ -1,6 +1,6 @@ use std::mem; -pub fn safe(_x: &i32, _y: &mut i32) {} //~ ERROR barrier +pub fn safe(_x: &i32, _y: &mut i32) {} //~ ERROR protect fn main() { let mut x = 0; diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut4.rs b/tests/compile-fail/stacked_borrows/aliasing_mut4.rs index 15f67d0f8728..778935a6d0b0 100644 --- a/tests/compile-fail/stacked_borrows/aliasing_mut4.rs +++ b/tests/compile-fail/stacked_borrows/aliasing_mut4.rs @@ -2,7 +2,7 @@ use std::mem; use std::cell::Cell; // Make sure &mut UnsafeCell also is exclusive -pub fn safe(_x: &i32, _y: &mut Cell) {} //~ ERROR barrier +pub fn safe(_x: &i32, _y: &mut Cell) {} //~ ERROR protect fn main() { let mut x = 0; diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs b/tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs index b2f1c824f1b4..49e376c0287e 100644 --- a/tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs +++ b/tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs @@ -1,4 +1,4 @@ -// error-pattern: deallocating with active barrier +// error-pattern: deallocating with active protect fn inner(x: &mut i32, f: fn(&mut i32)) { // `f` may mutate, but it may not deallocate! diff --git a/tests/compile-fail/stacked_borrows/invalidate_against_barrier1.rs b/tests/compile-fail/stacked_borrows/invalidate_against_barrier1.rs index fc0dbb9e1313..3a214a75b505 100644 --- a/tests/compile-fail/stacked_borrows/invalidate_against_barrier1.rs +++ b/tests/compile-fail/stacked_borrows/invalidate_against_barrier1.rs @@ -2,7 +2,7 @@ fn inner(x: *mut i32, _y: &mut i32) { // If `x` and `y` alias, retagging is fine with this... but we really // shouldn't be allowed to use `x` at all because `y` was assumed to be // unique for the duration of this call. - let _val = unsafe { *x }; //~ ERROR barrier + let _val = unsafe { *x }; //~ ERROR protect } fn main() { diff --git a/tests/compile-fail/stacked_borrows/invalidate_against_barrier2.rs b/tests/compile-fail/stacked_borrows/invalidate_against_barrier2.rs index a080c0958e40..86e4a84287ec 100644 --- a/tests/compile-fail/stacked_borrows/invalidate_against_barrier2.rs +++ b/tests/compile-fail/stacked_borrows/invalidate_against_barrier2.rs @@ -2,7 +2,7 @@ fn inner(x: *mut i32, _y: &i32) { // If `x` and `y` alias, retagging is fine with this... but we really // shouldn't be allowed to write to `x` at all because `y` was assumed to be // immutable for the duration of this call. - unsafe { *x = 0 }; //~ ERROR barrier + unsafe { *x = 0 }; //~ ERROR protect } fn main() { diff --git a/tests/run-pass/stacked-borrows/2phase.rs b/tests/run-pass/stacked-borrows/2phase.rs index 87ecb4aef065..97f435472e30 100644 --- a/tests/run-pass/stacked-borrows/2phase.rs +++ b/tests/run-pass/stacked-borrows/2phase.rs @@ -1,3 +1,5 @@ +#![allow(mutable_borrow_reservation_conflict)] + trait S: Sized { fn tpb(&mut self, _s: Self) {} } @@ -41,7 +43,6 @@ fn two_phase_raw() { ); } -/* fn two_phase_overlapping1() { let mut x = vec![]; let p = &x; @@ -54,7 +55,6 @@ fn two_phase_overlapping2() { let l = &x; x.add_assign(x + *l); } -*/ fn with_interior_mutability() { use std::cell::Cell; @@ -66,13 +66,13 @@ fn with_interior_mutability() { impl Thing for Cell {} let mut x = Cell::new(1); - //let l = &x; + let l = &x; x .do_the_thing({ x.set(3); - // l.set(4); // FIXME: Enable this as an example of overlapping 2PB! - x.get() // FIXME same: + l.get() + l.set(4); + x.get() + l.get() }) ; } @@ -84,7 +84,6 @@ fn main() { two_phase3(true); two_phase_raw(); with_interior_mutability(); - //FIXME: enable these, or remove them, depending on how https://github.com/rust-lang/rust/issues/56254 gets resolved - //two_phase_overlapping1(); - //two_phase_overlapping2(); + two_phase_overlapping1(); + two_phase_overlapping2(); } From 72cec0562cf3ff5a50f4318e316e188325cda54c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Apr 2019 15:20:33 +0200 Subject: [PATCH 0690/5092] add tests for fixes: sharing no longer leaks, and we can handle entering interior mutability --- .../compile-fail/stacked_borrows/illegal_read6.rs | 8 ++++++++ .../{refcell.rs => interior_mutability.rs} | 15 +++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 tests/compile-fail/stacked_borrows/illegal_read6.rs rename tests/run-pass/stacked-borrows/{refcell.rs => interior_mutability.rs} (70%) diff --git a/tests/compile-fail/stacked_borrows/illegal_read6.rs b/tests/compile-fail/stacked_borrows/illegal_read6.rs new file mode 100644 index 000000000000..dc3781472900 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read6.rs @@ -0,0 +1,8 @@ +// Creating a shared reference does not leak the data to raw pointers. +fn main() { unsafe { + let x = &mut 0; + let raw = x as *mut _; + let x = &mut *x; // kill `raw` + let _y = &*x; // this should not activate `raw` again + let _val = *raw; //~ ERROR borrow stack +} } diff --git a/tests/run-pass/stacked-borrows/refcell.rs b/tests/run-pass/stacked-borrows/interior_mutability.rs similarity index 70% rename from tests/run-pass/stacked-borrows/refcell.rs rename to tests/run-pass/stacked-borrows/interior_mutability.rs index dddc7089d02d..33f44d0093ed 100644 --- a/tests/run-pass/stacked-borrows/refcell.rs +++ b/tests/run-pass/stacked-borrows/interior_mutability.rs @@ -1,8 +1,12 @@ +#![feature(maybe_uninit, maybe_uninit_ref)] +use std::mem::MaybeUninit; +use std::cell::Cell; use std::cell::RefCell; fn main() { aliasing_mut_and_shr(); aliasing_frz_and_shr(); + into_interior_mutability(); } fn aliasing_mut_and_shr() { @@ -42,3 +46,14 @@ fn aliasing_frz_and_shr() { inner(&rc, &*bshr); assert_eq!(*rc.borrow(), 23); } + +// Getting a pointer into a union with interior mutability used to be tricky +// business (https://github.com/rust-lang/miri/issues/615), but it should work +// now. +fn into_interior_mutability() { + let mut x: MaybeUninit<(Cell, u32)> = MaybeUninit::uninit(); + x.as_ptr(); + x.write((Cell::new(0), 1)); + let ptr = unsafe { x.get_ref() }; + assert_eq!(ptr.1, 1); +} From 0a313183b1bfe6f2324ae2dc30673e1649cf3859 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Apr 2019 15:23:20 +0200 Subject: [PATCH 0691/5092] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index dcee3ec5daa7..40e42e688647 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -ee621f42329069c296b4c2066b3743cc4ff0f369 +efe2f32a6b8217425f361ec7c206910c611c03ee From e1ed855a441dc6f7234104b4c3a6751b23ae588d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Apr 2019 16:02:42 +0200 Subject: [PATCH 0692/5092] more tests -- also one showing why we are not done yet --- .../stacked_borrows/shared_rw_borrows_are_weak1.rs | 14 ++++++++++++++ .../stacked_borrows/shared_rw_borrows_are_weak2.rs | 14 ++++++++++++++ tests/run-pass/stacked-borrows/stacked-borrows.rs | 13 +++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak1.rs create mode 100644 tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.rs diff --git a/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak1.rs b/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak1.rs new file mode 100644 index 000000000000..d734caf1d97a --- /dev/null +++ b/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak1.rs @@ -0,0 +1,14 @@ +// We want to test that granting a SharedReadWrite will be added +// *below* an already granted Unique -- so writing to +// the SharedReadWrite will invalidate the Unique. + +use std::mem; +use std::cell::Cell; + +fn main() { unsafe { + let x = &mut Cell::new(0); + let y: &mut Cell = mem::transmute(&mut *x); // launder lifetime + let shr_rw = &*x; // thanks to interior mutability this will be a SharedReadWrite + shr_rw.set(1); + y.get_mut(); //~ ERROR borrow stack +} } diff --git a/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.rs b/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.rs new file mode 100644 index 000000000000..942bb503db02 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.rs @@ -0,0 +1,14 @@ +// We want to test that granting a SharedReadWrite will be added +// *below* an already granted SharedReadWrite -- so writing to +// the SharedReadWrite will invalidate the SharedReadWrite. + +use std::mem; +use std::cell::RefCell; + +fn main() { unsafe { + let x = &mut RefCell::new(0); + let y: &i32 = mem::transmute(&*x.borrow()); // launder lifetime + let shr_rw = &*x; // thanks to interior mutability this will be a SharedReadWrite + shr_rw.replace(1); + let _val = *y; //~ ERROR borrow stack +} } diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index 791e97f0eb1e..7d84e33b3d6b 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -11,6 +11,7 @@ fn main() { drop_after_sharing(); direct_mut_to_const_raw(); two_raw(); + shr_and_raw(); } // Deref a raw ptr to access a field of a large struct, where the field @@ -136,3 +137,15 @@ fn two_raw() { unsafe { *y1 += 2; *y2 += 1; } } + +// Make sure that creating a *mut does not invalidate existing shared references. +fn shr_and_raw() { /* unsafe { + use std::mem; + // FIXME: This is currently disabled because "as *mut _" incurs a reborrow. + let x = &mut 0; + let y1: &i32 = mem::transmute(&*x); // launder lifetimes + let y2 = x as *mut _; + let _val = *y1; + *y2 += 1; + // TODO: Once this works, add compile-fail test that tries to read from y1 again. +} */ } From abe8959339c7fafbc4cba85bda1f64a59f88a88e Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 17 Apr 2019 16:22:33 +0200 Subject: [PATCH 0693/5092] Apply suggestions from code review Co-Authored-By: RalfJung --- src/stacked_borrows.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 98b6ca6543f2..dc2a78d2960c 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -296,7 +296,7 @@ impl<'tcx> Stack { // keep the items immediately above `granting_idx` that are compatible, and then pop the rest. // However, that kills off entire "branches" of pointer derivation too easily: // in `let raw = &mut *x as *mut _; let _val = *x;`, the second statement would pop the `Unique` - // from the reborrow of the first statement, and subequently also pop the `SharedReadWrite` for `raw`. + // from the reborrow of the first statement, and subsequently also pop the `SharedReadWrite` for `raw`. // This pattern occurs a lot in the standard library: create a raw pointer, then also create a shared // reference and use that. { @@ -343,7 +343,7 @@ impl<'tcx> Stack { // We must make sure there are no protected items remaining on the stack. // Also clear the stack, no more accesses are possible. - while let Some(item) = self.borrows.pop() { + for item in self.borrows.drain(..) { if let Some(call) = item.protector { if global.is_active(call) { return err!(MachineError(format!( @@ -394,7 +394,7 @@ impl<'tcx> Stack { // We use that to determine where to put the new item. let (derived_from_idx, _) = self.find_granting(access, derived_from) .ok_or_else(|| InterpError::MachineError(format!( - "no item to reborrow for {:?} from tag {} found in borrow stack", new.perm, derived_from, + "no item to reborrow for {:?} from tag {} found in borrow stack", new.perm, derived_from, )))?; // Compute where to put the new item. @@ -410,7 +410,7 @@ impl<'tcx> Stack { // and we'd allow write access without invalidating frozen shared references! // This ensures F2b for `SharedReadWrite` by adding the new item below any // potentially existing `SharedReadOnly`. - derived_from_idx+1 + derived_from_idx + 1 } else { // A "safe" reborrow for a pointer that actually expects some aliasing guarantees. // Here, creating a reference actually counts as an access, and pops incompatible From 39ecd05c46e96e606561d22163ea05be5b1fa6e2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Apr 2019 16:25:38 +0200 Subject: [PATCH 0694/5092] embrace find_map and some whitespace changes --- src/stacked_borrows.rs | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index dc2a78d2960c..250def0c7ce6 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -263,14 +263,13 @@ impl<'tcx> Stack { .rev() // search top-to-bottom // Return permission of first item that grants access. // We require a permission with the right tag, ensuring U3 and F3. - .filter_map(|(idx, item)| + .find_map(|(idx, item)| if item.perm.grants(access) && tag == item.tag { Some((idx, item.perm)) } else { None } ) - .next() } /// Test if a memory `access` using pointer tagged `tag` is granted. @@ -286,8 +285,8 @@ impl<'tcx> Stack { // Step 1: Find granting item. let (granting_idx, granting_perm) = self.find_granting(access, tag) .ok_or_else(|| InterpError::MachineError(format!( - "no item granting {} access to tag {} found in borrow stack", - access, tag, + "no item granting {} access to tag {} found in borrow stack", + access, tag, )))?; // Step 2: Remove everything incompatible above them. Make sure we do not remove protected @@ -313,9 +312,9 @@ impl<'tcx> Stack { if let Some(call) = item.protector { if global.is_active(call) { return err!(MachineError(format!( - "not granting {} access to tag {} because incompatible item {} is protected", - access, tag, item - ))); + "not granting {} access to tag {} because incompatible item {} is protected", + access, tag, item + ))); } } trace!("access: removing item {}", item); @@ -337,8 +336,8 @@ impl<'tcx> Stack { // Step 1: Find granting item. self.find_granting(AccessKind::Write, tag) .ok_or_else(|| InterpError::MachineError(format!( - "no item granting write access for deallocation to tag {} found in borrow stack", - tag, + "no item granting write access for deallocation to tag {} found in borrow stack", + tag, )))?; // We must make sure there are no protected items remaining on the stack. @@ -386,10 +385,10 @@ impl<'tcx> Stack { ) -> EvalResult<'tcx> { // Figure out which access `perm` corresponds to. let access = if new.perm.grants(AccessKind::Write) { - AccessKind::Write - } else { - AccessKind::Read - }; + AccessKind::Write + } else { + AccessKind::Read + }; // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. let (derived_from_idx, _) = self.find_granting(access, derived_from) From 0e6deee76ef49e44d1089d6f2b8f9966a1c2db0a Mon Sep 17 00:00:00 2001 From: Tim Diekmann Date: Thu, 18 Apr 2019 01:17:19 +0200 Subject: [PATCH 0695/5092] Add `realloc` --- src/fn_call.rs | 17 +++++++++++++++++ tests/run-pass/realloc.rs | 31 +++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 tests/run-pass/realloc.rs diff --git a/src/fn_call.rs b/src/fn_call.rs index 64dcce161dd7..6706cc1fbc3c 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -148,6 +148,23 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } } + "realloc" => { + let ptr = this.read_scalar(args[0])?.to_ptr()?; + let new_size = this.read_scalar(args[1])?.to_usize(this)?; + let align = this.tcx.data_layout.pointer_align.abi; + let memory = this.memory_mut(); + let old_size = memory.get(ptr.alloc_id)?.bytes.len(); + let new_ptr = memory.reallocate( + ptr, + Size::from_bytes(old_size as u64), + align, + Size::from_bytes(new_size), + align, + MiriMemoryKind::C.into(), + )?; + this.write_scalar(Scalar::Ptr(new_ptr.with_default_tag()), dest)?; + } + "__rust_alloc" => { let size = this.read_scalar(args[0])?.to_usize(this)?; let align = this.read_scalar(args[1])?.to_usize(this)?; diff --git a/tests/run-pass/realloc.rs b/tests/run-pass/realloc.rs new file mode 100644 index 000000000000..594fec717e97 --- /dev/null +++ b/tests/run-pass/realloc.rs @@ -0,0 +1,31 @@ +//ignore-windows: Uses POSIX APIs + +#![feature(rustc_private)] + +use core::slice; + +extern crate libc; + +fn main() { + unsafe { + // Use calloc for initialized memory + let p1 = libc::calloc(20, 1); + + // old size < new size + let p2 = libc::realloc(p1, 40); + let slice = slice::from_raw_parts(p2 as *const u8, 20); + assert_eq!(&slice, &[0_u8; 20]); + + // old size == new size + let p3 = libc::realloc(p2, 40); + let slice = slice::from_raw_parts(p3 as *const u8, 20); + assert_eq!(&slice, &[0_u8; 20]); + + // old size > new size + let p4 = libc::realloc(p3, 10); + let slice = slice::from_raw_parts(p4 as *const u8, 10); + assert_eq!(&slice, &[0_u8; 10]); + + libc::free(p4); + } +} From afb64232dbc30047e001c1a24abc9de485b78d04 Mon Sep 17 00:00:00 2001 From: Tim Diekmann Date: Thu, 18 Apr 2019 12:39:18 +0200 Subject: [PATCH 0696/5092] Fix for latest upstream update --- src/fn_call.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 7b1ea73eb80f..310b57641904 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -162,7 +162,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' align, MiriMemoryKind::C.into(), )?; - this.write_scalar(Scalar::Ptr(new_ptr.with_default_tag()), dest)?; + this.write_scalar(Scalar::Ptr(new_ptr), dest)?; } "__rust_alloc" => { From 7d9dc6e698b5bddc5e63f11fc6d6f60bb1cd4359 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Apr 2019 13:20:01 +0200 Subject: [PATCH 0697/5092] test that creating a 2nd mutable ref from a NonNull invalidates the first --- .../stacked_borrows/mut_exclusive_violation2.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 tests/compile-fail/stacked_borrows/mut_exclusive_violation2.rs diff --git a/tests/compile-fail/stacked_borrows/mut_exclusive_violation2.rs b/tests/compile-fail/stacked_borrows/mut_exclusive_violation2.rs new file mode 100644 index 000000000000..c6802c5ec94e --- /dev/null +++ b/tests/compile-fail/stacked_borrows/mut_exclusive_violation2.rs @@ -0,0 +1,10 @@ +use std::ptr::NonNull; + +fn main() { unsafe { + let x = &mut 0; + let mut ptr1 = NonNull::from(x); + let mut ptr2 = ptr1.clone(); + let raw1 = ptr1.as_mut(); + let _raw2 = ptr2.as_mut(); + let _val = *raw1; //~ ERROR borrow stack +} } From 78e11058d32fbea1dee2645a9060813dd8be17de Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Apr 2019 14:58:30 +0200 Subject: [PATCH 0698/5092] CI: build with debug assertions --- .appveyor.yml | 1 + .travis.yml | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 7db60514ada7..5b77b1895a63 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -30,6 +30,7 @@ install: build_script: - set RUST_TEST_NOCAPTURE=1 - set RUST_BACKTRACE=1 + - set RUSTFLAGS="-C debug-assertions" # Build and install miri - cargo build --release --all-features --all-targets - cargo install --all-features --force --path . diff --git a/.travis.yml b/.travis.yml index 883404fb4a08..fd8c1260215d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,12 @@ os: - osx dist: xenial +env: + global: + - RUST_TEST_NOCAPTURE=1 + - RUST_BACKTRACE=1 + - RUSTFLAGS="-C debug-assertions" + before_script: # Linux: install extra stuff for cross-compilation - if [[ "$TRAVIS_OS_NAME" == linux ]]; then sudo apt update && sudo apt install gcc-multilib; fi @@ -48,7 +54,3 @@ notifications: branches: only: - master -env: - global: - - RUST_TEST_NOCAPTURE=1 - - RUST_BACKTRACE=1 From 9ecc07c9b2df3cf88223d97ddea95a61a548e09e Mon Sep 17 00:00:00 2001 From: Tim Diekmann Date: Thu, 18 Apr 2019 15:20:32 +0200 Subject: [PATCH 0699/5092] Add handling for `nullptr` and `size == 0` --- src/fn_call.rs | 48 ++++++++++++++++++++++++++++----------- tests/run-pass/realloc.rs | 16 ++++++++++++- 2 files changed, 50 insertions(+), 14 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 310b57641904..ae6aff10ac20 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -147,22 +147,44 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' )?; } } - "realloc" => { - let ptr = this.read_scalar(args[0])?.to_ptr()?; + let old_ptr = this.read_scalar(args[0])?.not_undef()?; let new_size = this.read_scalar(args[1])?.to_usize(this)?; let align = this.tcx.data_layout.pointer_align.abi; - let memory = this.memory_mut(); - let old_size = memory.get(ptr.alloc_id)?.bytes.len(); - let new_ptr = memory.reallocate( - ptr, - Size::from_bytes(old_size as u64), - align, - Size::from_bytes(new_size), - align, - MiriMemoryKind::C.into(), - )?; - this.write_scalar(Scalar::Ptr(new_ptr), dest)?; + if old_ptr.is_null_ptr(this) { + if new_size == 0 { + this.write_null(dest)?; + } else { + let new_ptr = this.memory_mut().allocate( + Size::from_bytes(new_size), + align, + MiriMemoryKind::C.into() + ); + this.write_scalar(Scalar::Ptr(new_ptr), dest)?; + } + } else { + let old_ptr = old_ptr.to_ptr()?; + let memory = this.memory_mut(); + let old_size = Size::from_bytes(memory.get(old_ptr.alloc_id)?.bytes.len() as u64); + if new_size == 0 { + memory.deallocate( + old_ptr, + Some((old_size, align)), + MiriMemoryKind::C.into(), + )?; + this.write_null(dest)?; + } else { + let new_ptr = memory.reallocate( + old_ptr, + old_size, + align, + Size::from_bytes(new_size), + align, + MiriMemoryKind::C.into(), + )?; + this.write_scalar(Scalar::Ptr(new_ptr), dest)?; + } + } } "__rust_alloc" => { diff --git a/tests/run-pass/realloc.rs b/tests/run-pass/realloc.rs index 594fec717e97..c23b3e645c70 100644 --- a/tests/run-pass/realloc.rs +++ b/tests/run-pass/realloc.rs @@ -2,7 +2,7 @@ #![feature(rustc_private)] -use core::slice; +use core::{slice, ptr}; extern crate libc; @@ -28,4 +28,18 @@ fn main() { libc::free(p4); } + + unsafe { + let p1 = libc::malloc(20); + + let p2 = libc::realloc(p1, 0); + assert!(p2.is_null()); + } + + unsafe { + let p1 = libc::realloc(ptr::null_mut(), 20); + assert!(!p1.is_null()); + + libc::free(p1); + } } From 36e99a1bdaee7ff07e03ac074a5b3f291a16e373 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Apr 2019 16:16:22 +0200 Subject: [PATCH 0700/5092] remove some unneeded 'extern crate' --- src/bin/cargo-miri.rs | 2 -- test-cargo-miri/src/main.rs | 4 ---- 2 files changed, 6 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 8984a0bc4f91..b6c448cc0457 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -1,7 +1,5 @@ #![feature(inner_deref)] -extern crate cargo_metadata; - use std::fs::{self, File}; use std::io::{self, Write, BufRead}; use std::path::{PathBuf, Path}; diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index 32f1bac57d20..9ec8e85887a7 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -1,7 +1,3 @@ -extern crate byteorder; -#[cfg(test)] -extern crate rand; - use byteorder::{BigEndian, ByteOrder}; fn main() { From 107b8b8ed920f286a21273785a1deeacf0d68799 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Apr 2019 16:44:43 +0200 Subject: [PATCH 0701/5092] try to fix Windows CI --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 5b77b1895a63..438a65880b87 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -30,7 +30,7 @@ install: build_script: - set RUST_TEST_NOCAPTURE=1 - set RUST_BACKTRACE=1 - - set RUSTFLAGS="-C debug-assertions" + - set RUSTFLAGS=-C debug-assertions # Build and install miri - cargo build --release --all-features --all-targets - cargo install --all-features --force --path . From 0a5e54127243f4ff9f847e91356c3a73f18126f2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Apr 2019 08:36:05 +0200 Subject: [PATCH 0702/5092] two-phase-borrow comment --- src/stacked_borrows.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 250def0c7ce6..bac35796ed13 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -625,6 +625,11 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, }; // Reborrow. + // TODO: With `two_phase == true`, this performs a weak reborrow for a `Unique`. That + // can lead to some possibly surprising effects, if the parent permission is + // `SharedReadWrite` then we now have a `Unique` in the middle of them, which "splits" + // them in terms of what remains valid when the `Unique` gets used. Is that really + // what we want? this.reborrow(place, size, kind, new_tag, /*force_weak:*/ two_phase, protect)?; let new_place = place.replace_tag(new_tag); // Handle two-phase borrows. From 287ffb8bba8d137c9dc04ade49c0bc65e0ab07f7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Apr 2019 08:46:09 +0200 Subject: [PATCH 0703/5092] test another version of 'creating a shared ref must not leak the Unique' --- .../stacked_borrows/illegal_read7.rs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/compile-fail/stacked_borrows/illegal_read7.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read7.rs b/tests/compile-fail/stacked_borrows/illegal_read7.rs new file mode 100644 index 000000000000..25d0878c0455 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read7.rs @@ -0,0 +1,20 @@ +// Creating a shared reference does not leak the data to raw pointers, +// not even when interior mutability is involved. + +use std::cell::Cell; +use std::ptr; + +fn main() { unsafe { + let x = &mut Cell::new(0); + let raw = x as *mut Cell; + let x = &mut *raw; + let _shr = &*x; + // The state here is interesting because the top of the stack is [Unique, SharedReadWrite], + // just like if we had done `x as *mut _`. + // If we said that reading from a lower item is fine if the top item is `SharedReadWrite` + // (one way to maybe preserve a stack discipline), then we could now read from `raw` + // without invalidating `x`. That would be bad! It would mean that creating `shr` + // leaked `x` to `raw`. + let _val = ptr::read(raw); + let _val = *x.get_mut(); //~ ERROR borrow stack +} } From e4cecb10dbfed3e66d8cb58978b26e5e464291a9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Apr 2019 18:30:53 +0200 Subject: [PATCH 0704/5092] bump compiletest --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index bb86795270fa..ce9c3cc4f29c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,5 +56,5 @@ cargo_miri = ["cargo_metadata", "directories", "rustc_version"] rustc_tests = [] [dev-dependencies] -compiletest_rs = { version = "0.3.21", features = ["tmp", "stable"] } +compiletest_rs = { version = "0.3.22", features = ["tmp", "stable"] } colored = "1.6" From 2481d6091ac59bec4e54be04b7361596c80412df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Apr 2019 19:27:19 +0200 Subject: [PATCH 0705/5092] warn when cargo miri setup does not do anything --- src/bin/cargo-miri.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index b6c448cc0457..b24bf65629b0 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -172,6 +172,9 @@ fn ask(question: &str) { /// done all this already. fn setup(ask_user: bool) { if std::env::var("MIRI_SYSROOT").is_ok() { + if !ask_user { + println!("WARNING: MIRI_SYSROOT already set, not doing anything.") + } return; } From bf6b7aa550125aa6520e261da4ddc930239fa007 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Apr 2019 19:53:42 +0200 Subject: [PATCH 0706/5092] rewirte development part of README --- README.md | 119 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 66 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 716c26c03a73..eb86d5b2ee31 100644 --- a/README.md +++ b/README.md @@ -113,63 +113,56 @@ find useful. ### Using a nightly rustc Miri heavily relies on internal rustc interfaces to execute MIR. Still, some -things (like adding support for a new intrinsic) can be done by working just on -the Miri side. +things (like adding support for a new intrinsic or a shim for an external +function being called) can be done by working just on the Miri side. -To prepare, make sure you are using a nightly Rust compiler. The most -convenient way is to install Miri using cargo, then you can easily run it on -other projects: - -```sh -rustup component remove miri # avoid having Miri installed twice -cargo +nightly install --path "$DIR" --force -cargo +nightly miri setup -``` - -(We are giving `+nightly` explicitly here all the time because it is important -that all of these commands get executed with the same toolchain.) +To prepare, make sure you are using a nightly Rust compiler. Then you should be +able to just `cargo build` Miri. In case this fails, your nightly might be incompatible with Miri master. The `rust-version` file contains the commit hash of rustc that Miri is currently tested against; you can use that to find a nightly that works or you might have to wait for the next nightly to get released. -If you want to use a different libstd (not the one that comes with the -nightly), you can do that by running +### Testing the Miri driver +[testing-miri]: #testing-the-miri-driver -```sh -XARGO_RUST_SRC=~/src/rust/rustc/src/ cargo +nightly miri setup +The Miri driver in the `miri` binary is the "heart" of Miri: it is basically a +version of `rustc` that, instead of compiling your code, runs it. It accepts +all the same flags as `rustc` (though the ones only affecting code generation +and linking obviously will have no effect) [and more][miri-flags]. + +To run the Miri driver, you need to have the `MIRI_SYSROOT` environment variable +set to an appropriate sysroot. You can generate such a sysroot with the +following incantation: + +``` +cargo run --bin cargo-miri -- miri setup ``` -Either way, you can now do `cargo +nightly miri run` to run Miri with your -local changes on whatever project you are debugging. +This basically runs the `cargo-miri` binary (which backs the `cargo miri` +subcommand) with `cargo`, and asks it to `setup`. It should in the end print +the directory where the libstd was built. In the following, we will assume it +is `~/.cache/miri/HOST`; you may have to adjust that if you are not using Linux. -`cargo miri setup` should end in printing the directory where the libstd was -built. For the next step to work, set that as your `MIRI_SYSROOT` environment -variable: +Now you can run the driver directly using ```sh -export MIRI_SYSROOT=~/.cache/miri/HOST # or whatever the previous command said +MIRI_SYSROOT=~/.cache/miri/HOST cargo run tests/run-pass/format.rs # or whatever test you like ``` -### Testing Miri +and you can run the test suite using -Instead of running an entire project using `cargo miri`, you can also use the -Miri "driver" directly to run just a single file. That can be easier during -debugging. - -```sh -cargo run tests/run-pass/format.rs # or whatever test you like +``` +cargo test ``` -You can also run the test suite with `cargo test --release`. `cargo test ---release FILTER` only runs those tests that contain `FILTER` in their filename -(including the base directory, e.g. `cargo test --release fail` will run all -compile-fail tests). We recommend using `--release` to make test running take -less time. +We recommend adding the `--release` flag to make tests run faster. + +`cargo test --release FILTER` only runs those tests that contain `FILTER` in +their filename (including the base directory, e.g. `cargo test --release fail` +will run all compile-fail tests). -Now you are set up! You can write a failing test case, and tweak miri until it -fails no more. You can get a trace of which MIR statements are being executed by setting the `MIRI_LOG` environment variable. For example: @@ -177,26 +170,43 @@ You can get a trace of which MIR statements are being executed by setting the MIRI_LOG=info cargo run tests/run-pass/vecs.rs ``` -Setting `MIRI_LOG` like this will configure logging for miri itself as well as +Setting `MIRI_LOG` like this will configure logging for Miri itself as well as the `rustc::mir::interpret` and `rustc_mir::interpret` modules in rustc. You -can also do more targeted configuration, e.g. to debug the stacked borrows -implementation: +can also do more targeted configuration, e.g. the following helps debug the +stacked borrows implementation: + ```sh MIRI_LOG=rustc_mir::interpret=info,miri::stacked_borrows cargo run tests/run-pass/vecs.rs ``` In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an -evaluation error was originally created. +evaluation error was originally raised. +### Testing `cargo miri` + +Working with the driver directly gives you full control, but you also lose all +the convenience provided by cargo. Once your test case depends on a crate, it +is probably easier to test it with the cargo wrapper. You can install your +development version of Miri using + +``` +cargo install --path . --force +``` + +and then you can use it as if it was installed by `rustup`. Make sure you use +the same toolchain when calling `cargo miri` that you used when installing Miri! + +There's a test for the cargo wrapper in the `test-cargo-miri` directory; run +`./run-test.py` in there to execute it. ### Using a locally built rustc -Since the heart of Miri (the main interpreter engine) lives in rustc, working on -Miri will often require using a locally built rustc. The bug you want to fix -may actually be on the rustc side, or you just need to get more detailed trace -of the execution than what is possible with release builds -- in both cases, you -should develop miri against a rustc you compiled yourself, with debug assertions -(and hence tracing) enabled. +A big part of the Miri driver lives in rustc, so working on Miri will sometimes +require using a locally built rustc. The bug you want to fix may actually be on +the rustc side, or you just need to get more detailed trace of the execution +than what is possible with release builds -- in both cases, you should develop +miri against a rustc you compiled yourself, with debug assertions (and hence +tracing) enabled. The setup for a local rustc works as follows: ```sh @@ -216,18 +226,21 @@ rustup override set custom ``` With this, you should now have a working development setup! See -["Testing Miri"](#testing-miri) above for how to proceed. +[above][testing-miri] for how to proceed working with the Miri driver. Notice +that rustc's sysroot is already built for Miri in this case, so you can set +`MIRI_SYSROOT=$(rustc --print sysroot)`. Running `cargo miri` in this setup is a bit more complicated, because the Miri -binary you just created does not actually run without some environment variables. -But you can contort cargo into calling `cargo miri` the right way for you: +binary you just created needs help to find the libraries it links against. On +Linux, you can set the rpath to make this "just work": ```sh -# in some other project's directory, to run `cargo miri test`: -MIRI_SYSROOT=$(rustc +custom --print sysroot) cargo +custom run --manifest-path /path/to/miri/Cargo.toml --bin cargo-miri --release -- miri test +export RUSTFLAGS="-C link-args=-Wl,-rpath,$(rustc --print sysroot)/lib/rustlib/x86_64-unknown-linux-gnu/lib" +cargo install --path . --force ``` ### Miri `-Z` flags and environment variables +[miri-flags]: #miri--z-flags-and-environment-variables Several `-Z` flags are relevant for Miri: From 677bd6f65646a6610ec2e3d11b203392477e3dd8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Apr 2019 11:54:21 +0200 Subject: [PATCH 0707/5092] add LinkedList test and mention the bug Miri found there --- README.md | 1 + tests/run-pass/linked-list.rs | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 tests/run-pass/linked-list.rs diff --git a/README.md b/README.md index 716c26c03a73..464c1c33c2d3 100644 --- a/README.md +++ b/README.md @@ -297,6 +297,7 @@ Miri has already found a number of bugs in the Rust standard library, which we c * [Futures turning a shared reference into a mutable one](https://github.com/rust-lang/rust/pull/56319) * [`str` turning a shared reference into a mutable one](https://github.com/rust-lang/rust/pull/58200) * [`BTreeMap` creating mutable references that overlap with shared references](https://github.com/rust-lang/rust/pull/58431) +* [`LinkedList` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/60072) ## License diff --git a/tests/run-pass/linked-list.rs b/tests/run-pass/linked-list.rs new file mode 100644 index 000000000000..f1d21728b2f0 --- /dev/null +++ b/tests/run-pass/linked-list.rs @@ -0,0 +1,33 @@ +#![feature(linked_list_extras)] +use std::collections::LinkedList; + +fn list_from(v: &[T]) -> LinkedList { + v.iter().cloned().collect() +} + +fn main() { + let mut m = list_from(&[0, 2, 4, 6, 8]); + let len = m.len(); + { + let mut it = m.iter_mut(); + it.insert_next(-2); + loop { + match it.next() { + None => break, + Some(elt) => { + it.insert_next(*elt + 1); + match it.peek_next() { + Some(x) => assert_eq!(*x, *elt + 2), + None => assert_eq!(8, *elt), + } + } + } + } + it.insert_next(0); + it.insert_next(1); + } + + assert_eq!(m.len(), 3 + len * 2); + assert_eq!(m.into_iter().collect::>(), + [-2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1]); +} From 791abb7a7e87c1ab20616d37184b661acc425753 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Apr 2019 23:08:35 +0200 Subject: [PATCH 0708/5092] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 40e42e688647..f0c4e551b3a5 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -efe2f32a6b8217425f361ec7c206910c611c03ee +130dc3e7dac132cf30272ccf4541b512828e2108 From a20719cec68a7c1babcbe4ccee2633c1ffc89aed Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 20 Apr 2019 18:36:43 +0200 Subject: [PATCH 0709/5092] add section on the no MIR error --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index eb86d5b2ee31..64bf361d54b3 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,13 @@ You may be running `cargo miri` with a different compiler version than the one used to build the custom libstd that Miri uses, and Miri failed to detect that. Try deleting `~/.cache/miri`. +#### "no mir for `std::rt::lang_start_internal`" + +This means the sysroot you are using was not compiled with Miri in mind. This +should never happen when you use `cargo miri` because that takes care of setting +up the sysroot. If you are using `miri` (the Miri driver) directly, see +[below][testing-miri] for how to set up the sysroot. + ## Development and Debugging If you want to hack on miri yourself, great! Here are some resources you might From 0694435650adbd5965a30a14771bc142919bbfe4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Apr 2019 17:25:27 +0200 Subject: [PATCH 0710/5092] implement exit implement exit code via new error kind --- rust-version | 2 +- src/fn_call.rs | 6 +++++- src/lib.rs | 14 ++++++++++---- tests/run-pass/exit.rs | 3 +++ 4 files changed, 19 insertions(+), 6 deletions(-) create mode 100644 tests/run-pass/exit.rs diff --git a/rust-version b/rust-version index f0c4e551b3a5..fae9b1d599a4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -130dc3e7dac132cf30272ccf4541b512828e2108 +9224be5fa39f6170f6e046342976efee5453a1ff diff --git a/src/fn_call.rs b/src/fn_call.rs index ae6aff10ac20..2f827510aa5d 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -69,11 +69,15 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' let link_name = link_name.get().trim_end_matches("$UNIX2003"); let tcx = &{this.tcx.tcx}; - // First: functions that could diverge. + // First: functions that diverge. match link_name { "__rust_start_panic" | "panic_impl" => { return err!(MachineError("the evaluated program panicked".to_string())); } + "exit" => { + let code = this.read_scalar(args[0])?.to_i32()?; + return err!(Exit(code)); + } _ => if dest.is_none() { return err!(Unimplemented( format!("can't call diverging foreign function: {}", link_name), diff --git a/src/lib.rs b/src/lib.rs index 3dbe922999da..683eee0cb7a3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -242,6 +242,13 @@ pub fn eval_main<'a, 'tcx: 'a>( } } Err(mut e) => { + // Special treatment for some error kinds + let msg = match e.kind { + InterpError::Exit(code) => std::process::exit(code), + InterpError::NoMirFor(..) => + format!("{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", e), + _ => e.to_string() + }; e.print_backtrace(); if let Some(frame) = ecx.stack().last() { let block = &frame.mir.basic_blocks()[frame.block]; @@ -251,11 +258,10 @@ pub fn eval_main<'a, 'tcx: 'a>( block.terminator().source_info.span }; - let e = e.to_string(); - let msg = format!("constant evaluation error: {}", e); + let msg = format!("Miri evaluation error: {}", msg); let mut err = struct_error(ecx.tcx.tcx.at(span), msg.as_str()); let frames = ecx.generate_stacktrace(None); - err.span_label(span, e); + err.span_label(span, msg); // We iterate with indices because we need to look at the next frame (the caller). for idx in 0..frames.len() { let frame_info = &frames[idx]; @@ -269,7 +275,7 @@ pub fn eval_main<'a, 'tcx: 'a>( } err.emit(); } else { - ecx.tcx.sess.err(&e.to_string()); + ecx.tcx.sess.err(&msg); } for (i, frame) in ecx.stack().iter().enumerate() { diff --git a/tests/run-pass/exit.rs b/tests/run-pass/exit.rs new file mode 100644 index 000000000000..d93f0045377e --- /dev/null +++ b/tests/run-pass/exit.rs @@ -0,0 +1,3 @@ +fn main() { + std::process::exit(0) +} From d410b131395ee0ba0cc02d6ca8cedc04e7c1fded Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Apr 2019 13:18:05 +0200 Subject: [PATCH 0711/5092] fix compile-fail ref files --- tests/compile-fail/ctlz_nonzero.rs | 2 +- tests/compile-fail/cttz_nonzero.rs | 2 +- tests/compile-fail/deref_fn_ptr.rs | 2 +- tests/compile-fail/getrandom.rs | 2 +- tests/compile-fail/never_transmute_humans.rs | 3 +-- tests/compile-fail/null_pointer_deref.rs | 2 +- tests/compile-fail/null_pointer_deref_zst.rs | 2 +- tests/compile-fail/null_pointer_write.rs | 2 +- tests/compile-fail/null_pointer_write_zst.rs | 2 +- 9 files changed, 9 insertions(+), 10 deletions(-) diff --git a/tests/compile-fail/ctlz_nonzero.rs b/tests/compile-fail/ctlz_nonzero.rs index 86fd5ec46c20..61f41363589c 100644 --- a/tests/compile-fail/ctlz_nonzero.rs +++ b/tests/compile-fail/ctlz_nonzero.rs @@ -10,6 +10,6 @@ pub fn main() { unsafe { use crate::rusti::*; - ctlz_nonzero(0u8); //~ ERROR constant evaluation error: ctlz_nonzero called on 0 + ctlz_nonzero(0u8); //~ ERROR ctlz_nonzero called on 0 } } diff --git a/tests/compile-fail/cttz_nonzero.rs b/tests/compile-fail/cttz_nonzero.rs index a6c3b03cfb5c..69d2874ce926 100644 --- a/tests/compile-fail/cttz_nonzero.rs +++ b/tests/compile-fail/cttz_nonzero.rs @@ -10,6 +10,6 @@ pub fn main() { unsafe { use crate::rusti::*; - cttz_nonzero(0u8); //~ ERROR constant evaluation error: cttz_nonzero called on 0 + cttz_nonzero(0u8); //~ ERROR cttz_nonzero called on 0 } } diff --git a/tests/compile-fail/deref_fn_ptr.rs b/tests/compile-fail/deref_fn_ptr.rs index 68826a6ff03d..ed2ac60f43fe 100644 --- a/tests/compile-fail/deref_fn_ptr.rs +++ b/tests/compile-fail/deref_fn_ptr.rs @@ -2,7 +2,7 @@ fn f() {} fn main() { let x: u8 = unsafe { - *std::mem::transmute::(f) //~ ERROR constant evaluation error: tried to dereference a function pointer + *std::mem::transmute::(f) //~ ERROR tried to dereference a function pointer }; panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/getrandom.rs b/tests/compile-fail/getrandom.rs index d54c95c82385..246893a5c640 100644 --- a/tests/compile-fail/getrandom.rs +++ b/tests/compile-fail/getrandom.rs @@ -8,6 +8,6 @@ fn main() { let mut buf = [0u8; 5]; unsafe { libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, 0 as libc::c_uint); - //~^ ERROR constant evaluation error: miri does not support gathering system entropy in deterministic mode! + //~^ ERROR miri does not support gathering system entropy in deterministic mode! } } diff --git a/tests/compile-fail/never_transmute_humans.rs b/tests/compile-fail/never_transmute_humans.rs index 34203338696c..ab25b1ffc746 100644 --- a/tests/compile-fail/never_transmute_humans.rs +++ b/tests/compile-fail/never_transmute_humans.rs @@ -7,7 +7,6 @@ struct Human; fn main() { let _x: ! = unsafe { - std::mem::transmute::(Human) //~ ERROR constant evaluation error - //^~ NOTE entered unreachable code + std::mem::transmute::(Human) //~ ERROR entered unreachable code }; } diff --git a/tests/compile-fail/null_pointer_deref.rs b/tests/compile-fail/null_pointer_deref.rs index 08ea63f58ff5..8bf0392b8903 100644 --- a/tests/compile-fail/null_pointer_deref.rs +++ b/tests/compile-fail/null_pointer_deref.rs @@ -1,4 +1,4 @@ fn main() { - let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR constant evaluation error: invalid use of NULL pointer + let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR invalid use of NULL pointer panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/null_pointer_deref_zst.rs b/tests/compile-fail/null_pointer_deref_zst.rs index a8b23368616e..b2800e96292d 100644 --- a/tests/compile-fail/null_pointer_deref_zst.rs +++ b/tests/compile-fail/null_pointer_deref_zst.rs @@ -1,4 +1,4 @@ fn main() { - let x: () = unsafe { *std::ptr::null() }; //~ ERROR constant evaluation error: invalid use of NULL pointer + let x: () = unsafe { *std::ptr::null() }; //~ ERROR invalid use of NULL pointer panic!("this should never print: {:?}", x); } diff --git a/tests/compile-fail/null_pointer_write.rs b/tests/compile-fail/null_pointer_write.rs index affb040bdedf..1577b2a1b13b 100644 --- a/tests/compile-fail/null_pointer_write.rs +++ b/tests/compile-fail/null_pointer_write.rs @@ -1,3 +1,3 @@ fn main() { - unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR constant evaluation error: invalid use of NULL pointer + unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR invalid use of NULL pointer } diff --git a/tests/compile-fail/null_pointer_write_zst.rs b/tests/compile-fail/null_pointer_write_zst.rs index 433c69dbb032..7e91d736bd29 100644 --- a/tests/compile-fail/null_pointer_write_zst.rs +++ b/tests/compile-fail/null_pointer_write_zst.rs @@ -2,5 +2,5 @@ fn main() { // Not using the () type here, as writes of that type do not even have MIR generated. // Also not assigning directly as that's array initialization, not assignment. let zst_val = [1u8; 0]; - unsafe { *std::ptr::null_mut() = zst_val }; //~ ERROR constant evaluation error: invalid use of NULL pointer + unsafe { *std::ptr::null_mut() = zst_val }; //~ ERROR invalid use of NULL pointer } From 6a6c0cd5f0f2e7283f2271f2188280e5ce9b9e69 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Apr 2019 13:25:24 +0200 Subject: [PATCH 0712/5092] implement ExitProcess for Windows --- src/fn_call.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/fn_call.rs b/src/fn_call.rs index 2f827510aa5d..84033e9e8307 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -78,6 +78,10 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' let code = this.read_scalar(args[0])?.to_i32()?; return err!(Exit(code)); } + "ExitProcess" => { + let code = this.read_scalar(args[0])?.to_u32()?; + return err!(Exit(code as i32)); + } _ => if dest.is_none() { return err!(Unimplemented( format!("can't call diverging foreign function: {}", link_name), From a87a7338e64001f60704a7bdd7d2ed6bfc64c397 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Apr 2019 13:43:53 +0200 Subject: [PATCH 0713/5092] test System/Global allocator API: alloc_zeroed, realloc --- tests/run-pass/env.rs | 2 +- tests/run-pass/hashmap.rs | 9 ++++----- tests/run-pass/heap_allocator.rs | 30 ++++++++++++++++++++++++++++-- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/tests/run-pass/env.rs b/tests/run-pass/env.rs index 0ca63e148fdb..91e15f249d45 100644 --- a/tests/run-pass/env.rs +++ b/tests/run-pass/env.rs @@ -1,4 +1,4 @@ -//ignore-windows: env var emulation not implemented on Windows +//ignore-windows: TODO env var emulation stubbed out on Windows use std::env; diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass/hashmap.rs index 796e63c81a41..25a816bcf245 100644 --- a/tests/run-pass/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -27,13 +27,12 @@ fn test_map(mut map: HashMap) { } fn main() { - if cfg!(not(target_os = "macos")) { - let map: HashMap = HashMap::default(); - test_map(map); - } else { - // TODO: Implement random number generation on OS X. + if cfg!(target_os = "macos") { // TODO: Implement random number generation on OS X. // Until then, use a deterministic map. let map : HashMap> = HashMap::default(); test_map(map); + } else { + let map: HashMap = HashMap::default(); + test_map(map); } } diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index bfed725a497c..b201f24e2563 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -1,9 +1,32 @@ -//ignore-windows: inspects allocation base address on Windows - #![feature(allocator_api)] use std::ptr::NonNull; use std::alloc::{Global, Alloc, Layout, System}; +use std::slice; + +fn check_alloc(mut allocator: T) { unsafe { + let layout = Layout::from_size_align(20, 4).unwrap(); + let a = allocator.alloc(layout).unwrap(); + allocator.dealloc(a, layout); + + let p1 = allocator.alloc_zeroed(layout).unwrap(); + + let p2 = allocator.realloc(p1, Layout::from_size_align(20, 4).unwrap(), 40).unwrap(); + let slice = slice::from_raw_parts(p2.as_ptr(), 20); + assert_eq!(&slice, &[0_u8; 20]); + + // old size == new size + let p3 = allocator.realloc(p2, Layout::from_size_align(40, 4).unwrap(), 40).unwrap(); + let slice = slice::from_raw_parts(p3.as_ptr(), 20); + assert_eq!(&slice, &[0_u8; 20]); + + // old size > new size + let p4 = allocator.realloc(p3, Layout::from_size_align(40, 4).unwrap(), 10).unwrap(); + let slice = slice::from_raw_parts(p4.as_ptr(), 10); + assert_eq!(&slice, &[0_u8; 10]); + + allocator.dealloc(p4, Layout::from_size_align(10, 4).unwrap()); +} } fn check_overalign_requests(mut allocator: T) { let size = 8; @@ -50,6 +73,9 @@ fn box_to_global() { } fn main() { + check_alloc(System); + check_alloc(Global); + #[cfg(not(target_os = "windows"))] // TODO: Inspects allocation base address on Windows; needs intptrcast model check_overalign_requests(System); check_overalign_requests(Global); global_to_box(); From e4970fe6ffa3052d6b1a880c934d4465bf656df9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Apr 2019 14:34:30 +0200 Subject: [PATCH 0714/5092] Windows: implement heap functions --- src/fn_call.rs | 178 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 117 insertions(+), 61 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index ae6aff10ac20..9789a76c6393 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -50,6 +50,86 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' Ok(Some(this.load_mir(instance.def)?)) } + fn malloc( + &mut self, + size: u64, + zero_init: bool, + ) -> Scalar { + let this = self.eval_context_mut(); + let tcx = &{this.tcx.tcx}; + if size == 0 { + Scalar::from_int(0, this.pointer_size()) + } else { + let align = this.tcx.data_layout.pointer_align.abi; + let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into()); + if zero_init { + // We just allocated this, the access cannot fail + this.memory_mut() + .get_mut(ptr.alloc_id).unwrap() + .write_repeat(tcx, ptr, 0, Size::from_bytes(size)).unwrap(); + } + Scalar::Ptr(ptr) + } + } + + fn free( + &mut self, + ptr: Scalar, + ) -> EvalResult<'tcx> { + let this = self.eval_context_mut(); + if !ptr.is_null_ptr(this) { + this.memory_mut().deallocate( + ptr.to_ptr()?, + None, + MiriMemoryKind::C.into(), + )?; + } + Ok(()) + } + + fn realloc( + &mut self, + old_ptr: Scalar, + new_size: u64, + ) -> EvalResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + let align = this.tcx.data_layout.pointer_align.abi; + if old_ptr.is_null_ptr(this) { + if new_size == 0 { + Ok(Scalar::from_int(0, this.pointer_size())) + } else { + let new_ptr = this.memory_mut().allocate( + Size::from_bytes(new_size), + align, + MiriMemoryKind::C.into() + ); + Ok(Scalar::Ptr(new_ptr)) + } + } else { + let old_ptr = old_ptr.to_ptr()?; + let memory = this.memory_mut(); + let old_size = Size::from_bytes(memory.get(old_ptr.alloc_id)?.bytes.len() as u64); + if new_size == 0 { + memory.deallocate( + old_ptr, + Some((old_size, align)), + MiriMemoryKind::C.into(), + )?; + Ok(Scalar::from_int(0, this.pointer_size())) + } else { + let new_ptr = memory.reallocate( + old_ptr, + old_size, + align, + Size::from_bytes(new_size), + align, + MiriMemoryKind::C.into(), + )?; + Ok(Scalar::Ptr(new_ptr)) + } + } + } + /// Emulates calling a foreign item, failing if the item is not supported. /// This function will handle `goto_block` if needed. fn emulate_foreign_item( @@ -87,28 +167,15 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' match link_name { "malloc" => { let size = this.read_scalar(args[0])?.to_usize(this)?; - if size == 0 { - this.write_null(dest)?; - } else { - let align = this.tcx.data_layout.pointer_align.abi; - let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into()); - this.write_scalar(Scalar::Ptr(ptr), dest)?; - } + let res = this.malloc(size, /*zero_init:*/ false); + this.write_scalar(res, dest)?; } "calloc" => { let items = this.read_scalar(args[0])?.to_usize(this)?; let len = this.read_scalar(args[1])?.to_usize(this)?; - let bytes = items.checked_mul(len).ok_or_else(|| InterpError::Overflow(mir::BinOp::Mul))?; - - if bytes == 0 { - this.write_null(dest)?; - } else { - let size = Size::from_bytes(bytes); - let align = this.tcx.data_layout.pointer_align.abi; - let ptr = this.memory_mut().allocate(size, align, MiriMemoryKind::C.into()); - this.memory_mut().get_mut(ptr.alloc_id)?.write_repeat(tcx, ptr, 0, size)?; - this.write_scalar(Scalar::Ptr(ptr), dest)?; - } + let size = items.checked_mul(len).ok_or_else(|| InterpError::Overflow(mir::BinOp::Mul))?; + let res = this.malloc(size, /*zero_init:*/ true); + this.write_scalar(res, dest)?; } "posix_memalign" => { let ret = this.deref_operand(args[0])?; @@ -136,55 +203,15 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } this.write_null(dest)?; } - "free" => { let ptr = this.read_scalar(args[0])?.not_undef()?; - if !ptr.is_null_ptr(this) { - this.memory_mut().deallocate( - ptr.to_ptr()?, - None, - MiriMemoryKind::C.into(), - )?; - } + this.free(ptr)?; } "realloc" => { let old_ptr = this.read_scalar(args[0])?.not_undef()?; let new_size = this.read_scalar(args[1])?.to_usize(this)?; - let align = this.tcx.data_layout.pointer_align.abi; - if old_ptr.is_null_ptr(this) { - if new_size == 0 { - this.write_null(dest)?; - } else { - let new_ptr = this.memory_mut().allocate( - Size::from_bytes(new_size), - align, - MiriMemoryKind::C.into() - ); - this.write_scalar(Scalar::Ptr(new_ptr), dest)?; - } - } else { - let old_ptr = old_ptr.to_ptr()?; - let memory = this.memory_mut(); - let old_size = Size::from_bytes(memory.get(old_ptr.alloc_id)?.bytes.len() as u64); - if new_size == 0 { - memory.deallocate( - old_ptr, - Some((old_size, align)), - MiriMemoryKind::C.into(), - )?; - this.write_null(dest)?; - } else { - let new_ptr = memory.reallocate( - old_ptr, - old_size, - align, - Size::from_bytes(new_size), - align, - MiriMemoryKind::C.into(), - )?; - this.write_scalar(Scalar::Ptr(new_ptr), dest)?; - } - } + let res = this.realloc(old_ptr, new_size)?; + this.write_scalar(res, dest)?; } "__rust_alloc" => { @@ -687,6 +714,35 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' }, // Windows API stubs. + // HANDLE = isize + // DWORD = ULONG = u32 + "GetProcessHeap" => { + // Just fake a HANDLE + this.write_scalar(Scalar::from_int(1, this.pointer_size()), dest)?; + } + "HeapAlloc" => { + let _handle = this.read_scalar(args[0])?.to_isize(this)?; + let flags = this.read_scalar(args[1])?.to_u32()?; + let size = this.read_scalar(args[2])?.to_usize(this)?; + let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY + let res = this.malloc(size, zero_init); + this.write_scalar(res, dest)?; + } + "HeapFree" => { + let _handle = this.read_scalar(args[0])?.to_isize(this)?; + let _flags = this.read_scalar(args[1])?.to_u32()?; + let ptr = this.read_scalar(args[2])?.not_undef()?; + this.free(ptr)?; + } + "HeapReAlloc" => { + let _handle = this.read_scalar(args[0])?.to_isize(this)?; + let _flags = this.read_scalar(args[1])?.to_u32()?; + let ptr = this.read_scalar(args[2])?.not_undef()?; + let size = this.read_scalar(args[3])?.to_usize(this)?; + let res = this.realloc(ptr, size)?; + this.write_scalar(res, dest)?; + } + "SetLastError" => { let err = this.read_scalar(args[0])?.to_u32()?; this.machine.last_error = err; From 7bb461362e3078f471b5d25c27c01c60c55f1318 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Apr 2019 22:35:47 +0200 Subject: [PATCH 0715/5092] Travis: test cargo miri on foreign arch --- test-cargo-miri/run-test.py | 22 +++++++++++++++++----- tests/compiletest.rs | 2 +- travis.sh | 22 +++++++++++++++------- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index f1412dbf3969..ec77875d4900 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -5,12 +5,18 @@ Assumes the `MIRI_SYSROOT` env var to be set appropriately, and the working directory to contain the cargo-miri-test project. ''' -import sys, subprocess +import sys, subprocess, os def fail(msg): print("TEST FAIL: {}".format(msg)) sys.exit(1) +def cargo_miri(cmd): + args = ["cargo", "miri", cmd, "-q"] + if 'MIRI_TEST_TARGET' in os.environ: + args += ["--target", os.environ['MIRI_TEST_TARGET']] + return args + def test(name, cmd, stdout_ref, stderr_ref): print("==> Testing `{}` <==".format(name)) ## Call `cargo miri`, capture all output @@ -36,16 +42,22 @@ def test(name, cmd, stdout_ref, stderr_ref): fail("stderr does not match reference") def test_cargo_miri_run(): - test("cargo miri run", ["cargo", "miri", "run", "-q"], "stdout.ref", "stderr.ref") + test("cargo miri run", + cargo_miri("run"), + "stdout.ref", "stderr.ref" + ) test("cargo miri run (with arguments)", - ["cargo", "miri", "run", "-q", "--", "--", "hello world", '"hello world"'], + cargo_miri("run") + ["--", "--", "hello world", '"hello world"'], "stdout.ref", "stderr.ref2" ) def test_cargo_miri_test(): - test("cargo miri test", ["cargo", "miri", "test", "-q", "--", "-Zmiri-seed=feed"], "test.stdout.ref", "test.stderr.ref") + test("cargo miri test", + cargo_miri("test") + ["--", "-Zmiri-seed=feed"], + "test.stdout.ref", "test.stderr.ref" + ) test("cargo miri test (with filter)", - ["cargo", "miri", "test", "-q", "--", "--", "impl"], + cargo_miri("test") + ["--", "--", "impl"], "test.stdout.ref2", "test.stderr.ref" ) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index ff83eca1c9f0..7f2c8966472f 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -101,7 +101,7 @@ fn get_host() -> String { } fn get_target() -> String { - std::env::var("MIRI_COMPILETEST_TARGET").unwrap_or_else(|_| get_host()) + std::env::var("MIRI_TEST_TARGET").unwrap_or_else(|_| get_host()) } fn run_pass_miri(opt: bool) { diff --git a/travis.sh b/travis.sh index 8951cdc89644..77768cf03114 100755 --- a/travis.sh +++ b/travis.sh @@ -3,13 +3,14 @@ set -euo pipefail # Determine configuration if [ "$TRAVIS_OS_NAME" == osx ]; then - export MIRI_SYSROOT_BASE=~/Library/Caches/miri.miri.miri/ + MIRI_SYSROOT_BASE=~/Library/Caches/miri.miri.miri/ FOREIGN_TARGET=i686-apple-darwin else - export MIRI_SYSROOT_BASE=~/.cache/miri/ + MIRI_SYSROOT_BASE=~/.cache/miri/ FOREIGN_TARGET=i686-unknown-linux-gnu fi +# Prepare echo "Build and install miri" cargo build --release --all-features --all-targets cargo install --all-features --force --path . @@ -20,11 +21,18 @@ cargo miri setup cargo miri setup --target "$FOREIGN_TARGET" echo -echo "Test miri with full MIR, on the host and other architectures" -MIRI_SYSROOT="$MIRI_SYSROOT_BASE"/HOST cargo test --release --all-features -MIRI_SYSROOT="$MIRI_SYSROOT_BASE" MIRI_COMPILETEST_TARGET="$FOREIGN_TARGET" cargo test --release --all-features +# Test +function run_tests { + cargo test --release --all-features + (cd test-cargo-miri && ./run-test.py) +} + +echo "Test host architecture" +export MIRI_SYSROOT="$MIRI_SYSROOT_BASE"/HOST +run_tests echo -echo "Test cargo integration" -(cd test-cargo-miri && MIRI_SYSROOT="$MIRI_SYSROOT_BASE"/HOST ./run-test.py) +echo "Test foreign architecture ($FOREIGN_TARGET)" +export MIRI_SYSROOT="$MIRI_SYSROOT_BASE" MIRI_TEST_TARGET="$FOREIGN_TARGET" +run_tests echo From 703b7f8a7e64fb2273fb516ecb8c953375d9deed Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Apr 2019 21:37:06 +0200 Subject: [PATCH 0716/5092] implement SecRandomCopyBytes for macOS RNG --- src/fn_call.rs | 12 ++++++++++++ test-cargo-miri/tests/test.rs | 16 ++++++---------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 9789a76c6393..fa0373ec54ec 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -712,6 +712,18 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' "_NSGetArgv" => { this.write_scalar(Scalar::Ptr(this.machine.argv.unwrap()), dest)?; }, + "SecRandomCopyBytes" => { + let len = this.read_scalar(args[1])?.to_usize(this)?; + let ptr = this.read_scalar(args[2])?.to_ptr()?; + + if len > 0 { + let data = gen_random(this, len as usize)?; + this.memory_mut().get_mut(ptr.alloc_id)? + .write_bytes(tcx, ptr, &data)?; + } + + this.write_null(dest)?; + } // Windows API stubs. // HANDLE = isize diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 69a31c42a75c..1f2f79214807 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -21,17 +21,13 @@ fn fixed_rng() { #[test] fn entropy_rng() { - #[cfg(not(target_os="macos"))] // FIXME entropy does not work on macOS - // (Not disabling the entire test as that would change the output.) - { - // Use this opportunity to test querying the RNG (needs an external crate, hence tested here and not in the compiletest suite) - let mut rng = SmallRng::from_entropy(); - let _val = rng.gen::(); + // Use this opportunity to test querying the RNG (needs an external crate, hence tested here and not in the compiletest suite) + let mut rng = SmallRng::from_entropy(); + let _val = rng.gen::(); - // Also try per-thread RNG. - let mut rng = rand::thread_rng(); - let _val = rng.gen::(); - } + // Also try per-thread RNG. + let mut rng = rand::thread_rng(); + let _val = rng.gen::(); } // A test that won't work on miri From 131548a748c2d508a544632697cfe9f7db5d4c6c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Apr 2019 22:57:58 +0200 Subject: [PATCH 0717/5092] gen_random: handle size 0 and writing to mem --- src/fn_call.rs | 50 +++++++++++++++++++++----------------------------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index fa0373ec54ec..7a684bdaa78f 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -298,19 +298,14 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' // is called if a `HashMap` is created the regular way (e.g. HashMap). match this.read_scalar(args[0])?.to_usize(this)? { id if id == sys_getrandom => { - let ptr = this.read_scalar(args[1])?.to_ptr()?; + let ptr = this.read_scalar(args[1])?.not_undef()?; let len = this.read_scalar(args[2])?.to_usize(this)?; // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, // neither of which have any effect on our current PRNG let _flags = this.read_scalar(args[3])?.to_i32()?; - if len > 0 { - let data = gen_random(this, len as usize)?; - this.memory_mut().get_mut(ptr.alloc_id)? - .write_bytes(tcx, ptr, &data)?; - } - + gen_random(this, len as usize, ptr)?; this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; } id => { @@ -714,14 +709,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' }, "SecRandomCopyBytes" => { let len = this.read_scalar(args[1])?.to_usize(this)?; - let ptr = this.read_scalar(args[2])?.to_ptr()?; - - if len > 0 { - let data = gen_random(this, len as usize)?; - this.memory_mut().get_mut(ptr.alloc_id)? - .write_bytes(tcx, ptr, &data)?; - } - + let ptr = this.read_scalar(args[2])?.not_undef()?; + gen_random(this, len as usize, ptr)?; this.write_null(dest)?; } @@ -878,15 +867,9 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } // The actual name of 'RtlGenRandom' "SystemFunction036" => { - let ptr = this.read_scalar(args[0])?.to_ptr()?; + let ptr = this.read_scalar(args[0])?.not_undef()?; let len = this.read_scalar(args[1])?.to_u32()?; - - if len > 0 { - let data = gen_random(this, len as usize)?; - this.memory_mut().get_mut(ptr.alloc_id)? - .write_bytes(tcx, ptr, &data)?; - } - + gen_random(this, len as usize, ptr)?; this.write_scalar(Scalar::from_bool(true), dest)?; } @@ -927,21 +910,30 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' fn gen_random<'a, 'mir, 'tcx>( this: &mut MiriEvalContext<'a, 'mir, 'tcx>, len: usize, -) -> Result, EvalError<'tcx>> { + dest: Scalar, +) -> EvalResult<'tcx> { + if len == 0 { + // Nothing to do + return Ok(()); + } + let ptr = dest.to_ptr()?; - match &mut this.machine.rng { + let data = match &mut this.machine.rng { Some(rng) => { let mut data = vec![0; len]; rng.fill_bytes(&mut data); - Ok(data) + data } None => { - err!(Unimplemented( + return err!(Unimplemented( "miri does not support gathering system entropy in deterministic mode! Use '-Zmiri-seed=' to enable random number generation. WARNING: Miri does *not* generate cryptographically secure entropy - do not use Miri to run any program that needs secure random number generation".to_owned(), - )) + )); } - } + }; + let tcx = &{this.tcx.tcx}; + this.memory_mut().get_mut(ptr.alloc_id)? + .write_bytes(tcx, ptr, &data) } From 8cb0b23c08c8463db0de2d70a8df44fd8326236e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Apr 2019 11:08:53 +0200 Subject: [PATCH 0718/5092] no need to allow any more --- test-cargo-miri/tests/test.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 1f2f79214807..ce15824f94a2 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -1,7 +1,3 @@ -#![allow(unused_imports)] // FIXME for macOS - -extern crate rand; - use rand::{SeedableRng, FromEntropy, Rng, rngs::SmallRng}; #[test] From b7314369e28560aa3358e5df221007ec304e023e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Apr 2019 11:11:06 +0200 Subject: [PATCH 0719/5092] make run-test runnable from other directories --- test-cargo-miri/run-test.py | 3 +++ travis.sh | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index ec77875d4900..33664737709c 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -61,7 +61,10 @@ def test_cargo_miri_test(): "test.stdout.ref2", "test.stderr.ref" ) +os.chdir(os.path.dirname(os.path.realpath(__file__))) + test_cargo_miri_run() test_cargo_miri_test() + print("TEST SUCCESSFUL!") sys.exit(0) diff --git a/travis.sh b/travis.sh index 77768cf03114..84f9c408dcba 100755 --- a/travis.sh +++ b/travis.sh @@ -24,7 +24,7 @@ echo # Test function run_tests { cargo test --release --all-features - (cd test-cargo-miri && ./run-test.py) + test-cargo-miri/run-test.py } echo "Test host architecture" From aaa8ee743bca78d52018a025a525183405b2a1b1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Apr 2019 13:20:51 +0200 Subject: [PATCH 0720/5092] unify code paths --- src/fn_call.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 62ad675218a4..29a34a696863 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -154,14 +154,11 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' "__rust_start_panic" | "panic_impl" => { return err!(MachineError("the evaluated program panicked".to_string())); } - "exit" => { + "exit" | "ExitProcess" => { + // it's really u32 for ExitProcess, but we have to put it into the `Exit` error variant anyway let code = this.read_scalar(args[0])?.to_i32()?; return err!(Exit(code)); } - "ExitProcess" => { - let code = this.read_scalar(args[0])?.to_u32()?; - return err!(Exit(code as i32)); - } _ => if dest.is_none() { return err!(Unimplemented( format!("can't call diverging foreign function: {}", link_name), From f9cf78d68525c37fbda04175fa9d9d9b98626ec7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 26 Apr 2019 09:08:30 +0200 Subject: [PATCH 0721/5092] trophy case: add rand; separate definite bugs from stacked-borrows-is-not-yet-official bugs --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0517092a8790..22eb41f94900 100644 --- a/README.md +++ b/README.md @@ -308,14 +308,20 @@ used according to their aliasing restrictions. ## Bugs found by Miri -Miri has already found a number of bugs in the Rust standard library, which we collect here. +Miri has already found a number of bugs in the Rust standard library and beyond, which we collect here. + +Definite bugs found: * [`Debug for vec_deque::Iter` accessing uninitialized memory](https://github.com/rust-lang/rust/issues/53566) * [`From<&[T]> for Rc` creating a not sufficiently aligned reference](https://github.com/rust-lang/rust/issues/54908) * [`BTreeMap` creating a shared reference pointing to a too small allocation](https://github.com/rust-lang/rust/issues/54957) -* [`VecDeque` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/56161) * [Futures turning a shared reference into a mutable one](https://github.com/rust-lang/rust/pull/56319) * [`str` turning a shared reference into a mutable one](https://github.com/rust-lang/rust/pull/58200) +* [`rand` performing unaligned reads](https://github.com/rust-random/rand/issues/779) + +Violations of Stacked Borrows found that are likely bugs (but Stacked Borrows is currently just an experiment): + +* [`VecDeque` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/56161) * [`BTreeMap` creating mutable references that overlap with shared references](https://github.com/rust-lang/rust/pull/58431) * [`LinkedList` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/60072) From d30141693ef9e4add781cdfa0c5b880192489f26 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Apr 2019 21:59:33 +0200 Subject: [PATCH 0722/5092] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index fae9b1d599a4..52b6685715d7 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9224be5fa39f6170f6e046342976efee5453a1ff +fe0a415b4ba3310c2263f07e0253e2434310299c From 53f59431a5f2c16b8a6dd66d91008c97a4ed8884 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Apr 2019 18:21:10 +0200 Subject: [PATCH 0723/5092] fix HeapFree return value --- src/fn_call.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/fn_call.rs b/src/fn_call.rs index 29a34a696863..1fd10ff38506 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -722,6 +722,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' // Windows API stubs. // HANDLE = isize // DWORD = ULONG = u32 + // BOOL = i32 "GetProcessHeap" => { // Just fake a HANDLE this.write_scalar(Scalar::from_int(1, this.pointer_size()), dest)?; @@ -739,6 +740,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' let _flags = this.read_scalar(args[1])?.to_u32()?; let ptr = this.read_scalar(args[2])?.not_undef()?; this.free(ptr)?; + this.write_scalar(Scalar::from_int(1, Size::from_bytes(4)), dest)?; } "HeapReAlloc" => { let _handle = this.read_scalar(args[0])?.to_isize(this)?; From 69a252c1b3492ea2902447a3331933c3fbe4d7f6 Mon Sep 17 00:00:00 2001 From: Bastien Orivel Date: Sat, 27 Apr 2019 23:31:48 +0200 Subject: [PATCH 0724/5092] Update cargo_metadata to 0.7 --- Cargo.toml | 2 +- src/bin/cargo-miri.rs | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ce9c3cc4f29c..639fd50c7503 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,7 @@ required-features = ["rustc_tests"] [dependencies] byteorder = { version = "1.1", features = ["i128"]} -cargo_metadata = { version = "0.6", optional = true } +cargo_metadata = { version = "0.7", optional = true } directories = { version = "1.0", optional = true } rustc_version = { version = "0.2.3", optional = true } env_logger = "0.6" diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index b24bf65629b0..5fc6f4af2b2d 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -83,10 +83,11 @@ fn list_targets() -> impl Iterator { Path::new(&m).canonicalize().unwrap() ); - let mut metadata = if let Ok(metadata) = cargo_metadata::metadata( - manifest_path.as_ref().map(AsRef::as_ref), - ) - { + let mut cmd = cargo_metadata::MetadataCommand::new(); + if let Some(ref manifest_path) = manifest_path { + cmd.manifest_path(manifest_path); + } + let mut metadata = if let Ok(metadata) = cmd.exec() { metadata } else { show_error(format!("Could not obtain Cargo metadata")); From 59985157d3931861a709ff610b22114442aac9ba Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Apr 2019 13:48:16 +0200 Subject: [PATCH 0725/5092] SharedReadOnly reborrows are never weak --- src/stacked_borrows.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index bac35796ed13..c2e4c72fb73d 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -400,6 +400,9 @@ impl<'tcx> Stack { // Either way, we ensure that we insert the new item in a way that between // `derived_from` and the new one, there are only items *compatible with* `derived_from`. let new_idx = if weak { + // A weak ShareadReadOnly reborrow might be added below other items, violating the + // invariant that only SharedReadOnly can sit on top of SharedReadOnly. + assert!(new.perm != Permission::SharedReadOnly, "Weak ShareadReadOnly reborrows don't work"); // A very liberal reborrow because the new pointer does not expect any kind of aliasing guarantee. // Just insert new permission as child of old permission, and maintain everything else. // This inserts "as far down as possible", which is good because it makes this pointer as @@ -581,8 +584,8 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // We need a frozen-sensitive reborrow. return this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { // We are only ever `SharedReadOnly` inside the frozen bits. - let weak = !frozen || kind != RefKind::Shared; // `RefKind::Raw` is always weak, as is `SharedReadWrite`. let perm = if frozen { Permission::SharedReadOnly } else { Permission::SharedReadWrite }; + let weak = perm == Permission::SharedReadWrite; let item = Item { perm, tag: new_tag, protector }; alloc.extra.for_each(cur_ptr, size, |stack, global| { stack.reborrow(cur_ptr.tag, force_weak || weak, item, global) From 17643af868c0310ec23c64d729e2f75ff19f21c7 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 30 Apr 2019 15:31:53 +0200 Subject: [PATCH 0726/5092] Apply suggestions from code review Co-Authored-By: RalfJung --- src/stacked_borrows.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index c2e4c72fb73d..2b4034d73137 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -400,9 +400,9 @@ impl<'tcx> Stack { // Either way, we ensure that we insert the new item in a way that between // `derived_from` and the new one, there are only items *compatible with* `derived_from`. let new_idx = if weak { - // A weak ShareadReadOnly reborrow might be added below other items, violating the + // A weak SharedReadOnly reborrow might be added below other items, violating the // invariant that only SharedReadOnly can sit on top of SharedReadOnly. - assert!(new.perm != Permission::SharedReadOnly, "Weak ShareadReadOnly reborrows don't work"); + assert!(new.perm != Permission::SharedReadOnly, "Weak SharedReadOnly reborrows don't work"); // A very liberal reborrow because the new pointer does not expect any kind of aliasing guarantee. // Just insert new permission as child of old permission, and maintain everything else. // This inserts "as far down as possible", which is good because it makes this pointer as From 617195eb12a439119d9ae8aa12eda7b5d1894e37 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Apr 2019 20:18:29 +0200 Subject: [PATCH 0727/5092] add arielby's example --- tests/compile-fail/stacked_borrows/illegal_write6.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/compile-fail/stacked_borrows/illegal_write6.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_write6.rs b/tests/compile-fail/stacked_borrows/illegal_write6.rs new file mode 100644 index 000000000000..86f2c0f350e3 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_write6.rs @@ -0,0 +1,12 @@ +fn main() { + let x = &mut 0u32; + let p = x as *mut u32; + foo(x, p); +} + +fn foo(a: &mut u32, y: *mut u32) -> u32 { + *a = 1; + let _b = &*a; + unsafe { *y = 2; } //~ ERROR: borrow stack + return *a; +} From d05159f3a981abc294358b7f1880511ac6078d8f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 May 2019 20:37:08 +0200 Subject: [PATCH 0728/5092] switch to my xargo fork, because that one works with current libstd --- src/bin/cargo-miri.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 5fc6f4af2b2d..8fb6d04aa07e 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -133,7 +133,11 @@ fn xargo_version() -> Option<(u32, u32, u32)> { (split.next().expect("malformed `xargo --version` output: empty"), split.next().expect("malformed `xargo --version` output: not at least two words")) }; - if name != "xargo" { + if name == "xargo" { + // This is the upstream version which is currently broken, we need our fork. + return None; + } + if name != "xargo-rj" { panic!("malformed `xargo --version` output: application name is not `xargo`"); } let mut version_pieces = version.split('.'); @@ -183,11 +187,11 @@ fn setup(ask_user: bool) { let xargo = xargo_version(); if xargo.map_or(true, |v| v < (0, 3, 13)) { if ask_user { - ask("It seems you do not have a recent enough xargo installed. I will run `cargo install xargo -f`. Proceed?"); + ask("It seems you do not have a recent enough xargo installed. I will run `cargo install --git https://github.com/RalfJung/xargo -f`. Proceed?"); } else { - println!("Installing xargo: `cargo install xargo -f`"); + println!("Installing xargo: `cargo install --git https://github.com/RalfJung/xargo -f`"); } - if !Command::new("cargo").args(&["install", "xargo", "-f"]).status().unwrap().success() { + if !Command::new("cargo").args(&["install", "--git", "https://github.com/RalfJung/xargo", "-f"]).status().unwrap().success() { show_error(format!("Failed to install xargo")); } } From b08bf47606bbba0a966d6a722d85c740b315fcec Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 May 2019 20:43:43 +0200 Subject: [PATCH 0729/5092] fix tests for latest Rust --- rust-version | 2 +- tests/run-pass/async-fn.rs | 1 - tests/run-pass/hashmap.rs | 5 +---- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index 52b6685715d7..49e9739a2eb1 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -fe0a415b4ba3310c2263f07e0253e2434310299c +7c71bc3208031b1307573de45a3b3e18fa45787a diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 1608ea188894..8a0ac875f54d 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -1,7 +1,6 @@ #![feature( async_await, await_macro, - futures_api, )] use std::{future::Future, pin::Pin, task::Poll, ptr}; diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass/hashmap.rs index 25a816bcf245..55037f55bf04 100644 --- a/tests/run-pass/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -7,13 +7,10 @@ fn test_map(mut map: HashMap) { map.insert(0, 0); assert_eq!(map.values().fold(0, |x, y| x+y), 0); - let table_base = map.get(&0).unwrap() as *const _; - - let num = 22; // large enough to trigger a resize + let num = 25; for i in 1..num { map.insert(i, i); } - assert!(table_base != map.get(&0).unwrap() as *const _); // make sure relocation happened assert_eq!(map.values().fold(0, |x, y| x+y), num*(num-1)/2); // check the right things are in the table now // Inserting again replaces the existing entries From 0f96676f43b111c8e448bf8c8f35cac07a79894b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 10 May 2019 08:05:34 +0200 Subject: [PATCH 0730/5092] switch back to upstream xargo --- src/bin/cargo-miri.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 8fb6d04aa07e..5dc7a75fc764 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -133,13 +133,10 @@ fn xargo_version() -> Option<(u32, u32, u32)> { (split.next().expect("malformed `xargo --version` output: empty"), split.next().expect("malformed `xargo --version` output: not at least two words")) }; - if name == "xargo" { - // This is the upstream version which is currently broken, we need our fork. + if name != "xargo" { + // This is some fork of xargo return None; } - if name != "xargo-rj" { - panic!("malformed `xargo --version` output: application name is not `xargo`"); - } let mut version_pieces = version.split('.'); let major = version_pieces.next() .expect("malformed `xargo --version` output: not a major version piece") @@ -185,13 +182,13 @@ fn setup(ask_user: bool) { // First, we need xargo. let xargo = xargo_version(); - if xargo.map_or(true, |v| v < (0, 3, 13)) { + if xargo.map_or(true, |v| v < (0, 3, 14)) { if ask_user { - ask("It seems you do not have a recent enough xargo installed. I will run `cargo install --git https://github.com/RalfJung/xargo -f`. Proceed?"); + ask("It seems you do not have a recent enough xargo installed. I will run `cargo install xargo -f`. Proceed?"); } else { - println!("Installing xargo: `cargo install --git https://github.com/RalfJung/xargo -f`"); + println!("Installing xargo: `cargo install xargo -f`"); } - if !Command::new("cargo").args(&["install", "--git", "https://github.com/RalfJung/xargo", "-f"]).status().unwrap().success() { + if !Command::new("cargo").args(&["install", "xargo", "-f"]).status().unwrap().success() { show_error(format!("Failed to install xargo")); } } From 8530080d03e852467d008ff2b4a4859f27e42daf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 May 2019 11:03:53 +0200 Subject: [PATCH 0731/5092] rename per-location part of reborowing to 'granting' --- src/stacked_borrows.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 2b4034d73137..37288afe239e 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -373,10 +373,10 @@ impl<'tcx> Stack { } /// Derived a new pointer from one with the given tag. - /// `weak` controls whether this is a weak reborrow: weak reborrows do not act as - /// accesses, and they add the new item directly on top of the one it is derived + /// `weak` controls whether this operation is weak or string: weak granting does not act as + /// an access, and they add the new item directly on top of the one it is derived /// from instead of all the way at the top of the stack. - fn reborrow( + fn grant( &mut self, derived_from: Tag, weak: bool, @@ -588,7 +588,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let weak = perm == Permission::SharedReadWrite; let item = Item { perm, tag: new_tag, protector }; alloc.extra.for_each(cur_ptr, size, |stack, global| { - stack.reborrow(cur_ptr.tag, force_weak || weak, item, global) + stack.grant(cur_ptr.tag, force_weak || weak, item, global) }) }); } @@ -597,7 +597,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let weak = perm == Permission::SharedReadWrite; let item = Item { perm, tag: new_tag, protector }; alloc.extra.for_each(ptr, size, |stack, global| { - stack.reborrow(ptr.tag, force_weak || weak, item, global) + stack.grant(ptr.tag, force_weak || weak, item, global) }) } From a9e66928d60a0d8564cc262d780f42ad0a2e900c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 May 2019 12:07:25 +0200 Subject: [PATCH 0732/5092] Update src/stacked_borrows.rs Co-Authored-By: bjorn3 --- src/stacked_borrows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 37288afe239e..910c4ce49f5a 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -373,7 +373,7 @@ impl<'tcx> Stack { } /// Derived a new pointer from one with the given tag. - /// `weak` controls whether this operation is weak or string: weak granting does not act as + /// `weak` controls whether this operation is weak or strong: weak granting does not act as /// an access, and they add the new item directly on top of the one it is derived /// from instead of all the way at the top of the stack. fn grant( From be47fae17393106c4093849a696b9adbdb23e5f6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 13 May 2019 11:37:54 +0200 Subject: [PATCH 0733/5092] build with latest version --- rust-version | 2 +- src/helpers.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 49e9739a2eb1..61205128dfe6 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7c71bc3208031b1307573de45a3b3e18fa45787a +d595b113584f8f446957469951fd5d31adc2a44e diff --git a/src/helpers.rs b/src/helpers.rs index f468d256031c..e9f7741d31b9 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -27,10 +27,10 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' for item in mem::replace(&mut items, Default::default()).iter() { if item.ident.name == *segment { if path_it.peek().is_none() { - return Some(ty::Instance::mono(this.tcx.tcx, item.def.def_id())); + return Some(ty::Instance::mono(this.tcx.tcx, item.res.def_id())); } - items = this.tcx.item_children(item.def.def_id()); + items = this.tcx.item_children(item.res.def_id()); break; } } From 7f09e61c31ffffc340495eca23e834d6159f61d6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 13 May 2019 11:45:39 +0200 Subject: [PATCH 0734/5092] make HashMap test a bit nicer --- tests/run-pass/hashmap.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass/hashmap.rs index 55037f55bf04..e249238d48cb 100644 --- a/tests/run-pass/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -24,12 +24,10 @@ fn test_map(mut map: HashMap) { } fn main() { - if cfg!(target_os = "macos") { // TODO: Implement random number generation on OS X. + if cfg!(target_os = "macos") { // TODO: Implement libstd HashMap seeding for macOS (https://github.com/rust-lang/miri/issues/686). // Until then, use a deterministic map. - let map : HashMap> = HashMap::default(); - test_map(map); + test_map::>(HashMap::default()); } else { - let map: HashMap = HashMap::default(); - test_map(map); + test_map(HashMap::new()); } } From ada5edbf966b3e968e7a20e03484217dfa2ae551 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 13 May 2019 14:10:52 +0200 Subject: [PATCH 0735/5092] RUST_LOG got renamed to RUSTC_LOG --- src/bin/miri.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 6e68f803f858..272fd17d433c 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -66,26 +66,26 @@ fn init_early_loggers() { // If it is not set, we avoid initializing now so that we can initialize // later with our custom settings, and *not* log anything for what happens before // `miri` gets started. - if env::var("RUST_LOG").is_ok() { + if env::var("RUSTC_LOG").is_ok() { rustc_driver::init_rustc_env_logger(); } } fn init_late_loggers() { - // We initialize loggers right before we start evaluation. We overwrite the `RUST_LOG` + // We initialize loggers right before we start evaluation. We overwrite the `RUSTC_LOG` // env var if it is not set, control it based on `MIRI_LOG`. if let Ok(var) = env::var("MIRI_LOG") { - if env::var("RUST_LOG").is_err() { + if env::var("RUSTC_LOG").is_err() { // We try to be a bit clever here: if `MIRI_LOG` is just a single level // used for everything, we only apply it to the parts of rustc that are - // CTFE-related. Otherwise, we use it verbatim for `RUST_LOG`. + // CTFE-related. Otherwise, we use it verbatim for `RUSTC_LOG`. // This way, if you set `MIRI_LOG=trace`, you get only the right parts of // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_mir::interpret=debug`. if log::Level::from_str(&var).is_ok() { - env::set_var("RUST_LOG", + env::set_var("RUSTC_LOG", &format!("rustc::mir::interpret={0},rustc_mir::interpret={0}", var)); } else { - env::set_var("RUST_LOG", &var); + env::set_var("RUSTC_LOG", &var); } rustc_driver::init_rustc_env_logger(); } From bc0c76d861a178911f3f506196a7404eda1e690d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 13 May 2019 21:55:58 +0200 Subject: [PATCH 0736/5092] fix for latest rustc --- rust-version | 2 +- src/bin/miri-rustc-tests.rs | 4 ++-- src/bin/miri.rs | 2 +- src/fn_call.rs | 3 ++- src/helpers.rs | 4 ++-- src/lib.rs | 3 ++- 6 files changed, 10 insertions(+), 8 deletions(-) diff --git a/rust-version b/rust-version index 61205128dfe6..1567a48efcc9 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d595b113584f8f446957469951fd5d31adc2a44e +a9ec99f4201ec33026a468ef1289f98a95b4d71a diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index ce2ad1a2715d..cf50f8125c4b 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -30,7 +30,7 @@ struct MiriCompilerCalls { impl rustc_driver::Callbacks for MiriCompilerCalls { fn after_parsing(&mut self, compiler: &interface::Compiler) -> bool { let attr = ( - String::from("miri"), + syntax::symbol::Symbol::intern("miri"), syntax::feature_gate::AttributeType::Whitelisted, ); compiler.session().plugin_attributes.borrow_mut().push(attr); @@ -47,7 +47,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.node { - if i.attrs.iter().any(|attr| attr.check_name("test")) { + if i.attrs.iter().any(|attr| attr.check_name(syntax::symbol::sym::test)) { let config = MiriConfig { validate: true, args: vec![], seed: None }; let did = self.0.hir().body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 272fd17d433c..31ed5f2ccd53 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -27,7 +27,7 @@ struct MiriCompilerCalls { impl rustc_driver::Callbacks for MiriCompilerCalls { fn after_parsing(&mut self, compiler: &interface::Compiler) -> bool { let attr = ( - String::from("miri"), + syntax::symbol::Symbol::intern("miri"), syntax::feature_gate::AttributeType::Whitelisted, ); compiler.session().plugin_attributes.borrow_mut().push(attr); diff --git a/src/fn_call.rs b/src/fn_call.rs index 1fd10ff38506..3ff0c1eb18a0 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -3,6 +3,7 @@ use rustc::ty::layout::{Align, LayoutOf, Size}; use rustc::hir::def_id::DefId; use rustc::mir; use syntax::attr; +use syntax::symbol::sym; use rand::RngCore; @@ -141,7 +142,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' ) -> EvalResult<'tcx> { let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); - let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { + let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { Some(name) => name.as_str(), None => this.tcx.item_name(def_id).as_str(), }; diff --git a/src/helpers.rs b/src/helpers.rs index e9f7741d31b9..89aba494724c 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -14,7 +14,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' this.tcx .crates() .iter() - .find(|&&krate| this.tcx.original_crate_name(krate) == path[0]) + .find(|&&krate| this.tcx.original_crate_name(krate).as_str() == path[0]) .and_then(|krate| { let krate = DefId { krate: *krate, @@ -25,7 +25,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' while let Some(segment) = path_it.next() { for item in mem::replace(&mut items, Default::default()).iter() { - if item.ident.name == *segment { + if item.ident.name.as_str() == *segment { if path_it.peek().is_none() { return Some(ty::Instance::mono(this.tcx.tcx, item.res.def_id())); } diff --git a/src/lib.rs b/src/lib.rs index 683eee0cb7a3..d3e30bbdde8f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,6 +37,7 @@ pub use rustc_mir::interpret::*; pub use rustc_mir::interpret::{self, AllocMap, PlaceTy}; use syntax::attr; use syntax::source_map::DUMMY_SP; +use syntax::symbol::sym; pub use crate::fn_call::EvalContextExt as MissingFnsEvalContextExt; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; @@ -478,7 +479,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { memory_extra: &Self::MemoryExtra, ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> { let attrs = tcx.get_attrs(def_id); - let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { + let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { Some(name) => name.as_str(), None => tcx.item_name(def_id).as_str(), }; From 7a5a0303be8a053339d9fd88b4adee9d01e6469f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 May 2019 08:58:43 +0200 Subject: [PATCH 0737/5092] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 1567a48efcc9..4cf2697aa421 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a9ec99f4201ec33026a468ef1289f98a95b4d71a +372be4f360ce42b1a10126a711189796f8440ab4 From 9b3f07b161636a4453a15d5448ed1964dd451369 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 May 2019 15:19:19 +0200 Subject: [PATCH 0738/5092] make printing return place less verbose --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index d3e30bbdde8f..a12493fbfbd6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -282,7 +282,7 @@ pub fn eval_main<'a, 'tcx: 'a>( for (i, frame) in ecx.stack().iter().enumerate() { trace!("-------------------"); trace!("Frame {}", i); - trace!(" return: {:#?}", frame.return_place); + trace!(" return: {:?}", frame.return_place.map(|p| *p)); for (i, local) in frame.locals.iter().enumerate() { trace!(" local {}: {:?}", i, local.value); } From f676f2265b6473c4e84f38c0384ed1f6e3211255 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 May 2019 17:23:26 +0200 Subject: [PATCH 0739/5092] make writes act stack-like --- src/stacked_borrows.rs | 49 ++++++++++++------- .../stacked_borrows/interior_mut1.rs | 10 ++++ 2 files changed, 42 insertions(+), 17 deletions(-) create mode 100644 tests/compile-fail/stacked_borrows/interior_mut1.rs diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 910c4ce49f5a..2f082bcc4c05 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -256,20 +256,33 @@ impl Permission { /// Core per-location operations: access, dealloc, reborrow. impl<'tcx> Stack { - /// Find the item granting the given kind of access to the given tag, and where that item is in the stack. - fn find_granting(&self, access: AccessKind, tag: Tag) -> Option<(usize, Permission)> { - self.borrows.iter() + /// Find the item granting the given kind of access to the given tag, and where + /// *the first incompatible item above it* is on the stack. + fn find_granting(&self, access: AccessKind, tag: Tag) -> Option<(Permission, usize)> { + let (perm, idx) = self.borrows.iter() .enumerate() // we also need to know *where* in the stack .rev() // search top-to-bottom // Return permission of first item that grants access. // We require a permission with the right tag, ensuring U3 and F3. .find_map(|(idx, item)| if item.perm.grants(access) && tag == item.tag { - Some((idx, item.perm)) + Some((item.perm, idx)) } else { None } - ) + )?; + + let mut first_incompatible_idx = idx+1; + while let Some(item) = self.borrows.get(first_incompatible_idx) { + if perm.compatible_with(access, item.perm) { + // Keep this, check next. + first_incompatible_idx += 1; + } else { + // Found it! + break; + } + } + return Some((perm, first_incompatible_idx)); } /// Test if a memory `access` using pointer tagged `tag` is granted. @@ -279,11 +292,11 @@ impl<'tcx> Stack { access: AccessKind, tag: Tag, global: &GlobalState, - ) -> EvalResult<'tcx, usize> { + ) -> EvalResult<'tcx> { // Two main steps: Find granting item, remove all incompatible items above. // Step 1: Find granting item. - let (granting_idx, granting_perm) = self.find_granting(access, tag) + let (granting_perm, first_incompatible_idx) = self.find_granting(access, tag) .ok_or_else(|| InterpError::MachineError(format!( "no item granting {} access to tag {} found in borrow stack", access, tag, @@ -291,9 +304,7 @@ impl<'tcx> Stack { // Step 2: Remove everything incompatible above them. Make sure we do not remove protected // items. - // We do *not* maintain a stack discipline here. We could, in principle, decide to only - // keep the items immediately above `granting_idx` that are compatible, and then pop the rest. - // However, that kills off entire "branches" of pointer derivation too easily: + // For writes, this is a simple stack. For reads, however, it is not: // in `let raw = &mut *x as *mut _; let _val = *x;`, the second statement would pop the `Unique` // from the reborrow of the first statement, and subsequently also pop the `SharedReadWrite` for `raw`. // This pattern occurs a lot in the standard library: create a raw pointer, then also create a shared @@ -301,9 +312,10 @@ impl<'tcx> Stack { { // Implemented with indices because there does not seem to be a nice iterator and range-based // API for this. - let mut cur = granting_idx + 1; + let mut cur = first_incompatible_idx; while let Some(item) = self.borrows.get(cur) { - if granting_perm.compatible_with(access, item.perm) { + // If this is a read, we double-check if we really want to kill this. + if access == AccessKind::Read && granting_perm.compatible_with(access, item.perm) { // Keep this, check next. cur += 1; } else { @@ -323,7 +335,7 @@ impl<'tcx> Stack { } // Done. - return Ok(granting_idx); + Ok(()) } /// Deallocate a location: Like a write access, but also there must be no @@ -391,7 +403,7 @@ impl<'tcx> Stack { }; // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. - let (derived_from_idx, _) = self.find_granting(access, derived_from) + let (_, first_incompatible_idx) = self.find_granting(access, derived_from) .ok_or_else(|| InterpError::MachineError(format!( "no item to reborrow for {:?} from tag {} found in borrow stack", new.perm, derived_from, )))?; @@ -412,14 +424,17 @@ impl<'tcx> Stack { // and we'd allow write access without invalidating frozen shared references! // This ensures F2b for `SharedReadWrite` by adding the new item below any // potentially existing `SharedReadOnly`. - derived_from_idx + 1 + first_incompatible_idx } else { // A "safe" reborrow for a pointer that actually expects some aliasing guarantees. // Here, creating a reference actually counts as an access, and pops incompatible // stuff off the stack. // This ensures F2b for `Unique`, by removing offending `SharedReadOnly`. - let check_idx = self.access(access, derived_from, global)?; - assert_eq!(check_idx, derived_from_idx, "somehow we saw different items??"); + self.access(access, derived_from, global)?; + if access == AccessKind::Write { + // For write accesses, the position is the same as what it would have been weakly! + assert_eq!(first_incompatible_idx, self.borrows.len()); + } // We insert "as far up as possible": We know only compatible items are remaining // on top of `derived_from`, and we want the new item at the top so that we diff --git a/tests/compile-fail/stacked_borrows/interior_mut1.rs b/tests/compile-fail/stacked_borrows/interior_mut1.rs new file mode 100644 index 000000000000..dd9fce110c2d --- /dev/null +++ b/tests/compile-fail/stacked_borrows/interior_mut1.rs @@ -0,0 +1,10 @@ +use std::cell::UnsafeCell; + +fn main() { unsafe { + let c = &UnsafeCell::new(UnsafeCell::new(0)); + let inner_uniq = &mut *c.get(); + let inner_shr = &*inner_uniq; // a SharedRW with a tag + *c.get() = UnsafeCell::new(1); // invalidates the SharedRW + let _val = *inner_shr.get(); //~ ERROR borrow stack + let _val = *inner_uniq.get(); +} } From 1447242bf98d7bf3e094d2e5d6029472cfdcc75d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 May 2019 17:50:43 +0200 Subject: [PATCH 0740/5092] refactor to simplify --- src/stacked_borrows.rs | 82 +++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 53 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 2f082bcc4c05..a3910fd0c43d 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -214,51 +214,21 @@ impl Permission { } /// This defines for a given permission, which other permissions it can tolerate "above" itself - /// for which kinds of accesses. - /// If true, then `other` is allowed to remain on top of `self` when `access` happens. - fn compatible_with(self, access: AccessKind, other: Permission) -> bool { - use self::Permission::*; - - match (self, access, other) { - // Some cases are impossible. - (SharedReadOnly, _, SharedReadWrite) | - (SharedReadOnly, _, Unique) => - bug!("There can never be a SharedReadWrite or a Unique on top of a SharedReadOnly"), - // When `other` is `SharedReadOnly`, that is NEVER compatible with - // write accesses. - // This makes sure read-only pointers become invalid on write accesses (ensures F2a). - (_, AccessKind::Write, SharedReadOnly) => - false, - // When `other` is `Unique`, that is compatible with nothing. - // This makes sure unique pointers become invalid on incompatible accesses (ensures U2). - (_, _, Unique) => - false, - // When we are unique and this is a write/dealloc, we tolerate nothing. - // This makes sure we re-assert uniqueness ("being on top") on write accesses. - // (This is particularily important such that when a new mutable ref gets created, it gets - // pushed onto the right item -- this behaves like a write and we assert uniqueness of the - // pointer from which this comes, *if* it was a unique pointer.) - (Unique, AccessKind::Write, _) => - false, - // `SharedReadWrite` items can tolerate any other akin items for any kind of access. - (SharedReadWrite, _, SharedReadWrite) => - true, - // Any item can tolerate read accesses for shared items. - // This includes unique items! Reads from unique pointers do not invalidate - // other pointers. - (_, AccessKind::Read, SharedReadWrite) | - (_, AccessKind::Read, SharedReadOnly) => - true, - // That's it. - } + /// when it is written to. + /// If true, then `other` is allowed to remain on top of `self` when a write access happens. + fn write_compatible_with(self, other: Permission) -> bool { + // Only writes to SharedRW can tolerate any other items above them, and they only + // tolerate other SharedRW. So, basically, searching the first write-incompatible item above X treats + // consecutive SharedRW as one "group", and skips to the first item outside X's group. + return self == Permission::SharedReadWrite && other == Permission::SharedReadWrite; } } /// Core per-location operations: access, dealloc, reborrow. impl<'tcx> Stack { - /// Find the item granting the given kind of access to the given tag, and where - /// *the first incompatible item above it* is on the stack. - fn find_granting(&self, access: AccessKind, tag: Tag) -> Option<(Permission, usize)> { + /// Find the item granting the given kind of access to the given tag, and return where + /// *the first write-incompatible item above it* is on the stack. + fn check_granting(&self, access: AccessKind, tag: Tag) -> Option { let (perm, idx) = self.borrows.iter() .enumerate() // we also need to know *where* in the stack .rev() // search top-to-bottom @@ -274,7 +244,7 @@ impl<'tcx> Stack { let mut first_incompatible_idx = idx+1; while let Some(item) = self.borrows.get(first_incompatible_idx) { - if perm.compatible_with(access, item.perm) { + if perm.write_compatible_with(item.perm) { // Keep this, check next. first_incompatible_idx += 1; } else { @@ -282,7 +252,7 @@ impl<'tcx> Stack { break; } } - return Some((perm, first_incompatible_idx)); + return Some(first_incompatible_idx); } /// Test if a memory `access` using pointer tagged `tag` is granted. @@ -293,20 +263,26 @@ impl<'tcx> Stack { tag: Tag, global: &GlobalState, ) -> EvalResult<'tcx> { - // Two main steps: Find granting item, remove all incompatible items above. + // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. - let (granting_perm, first_incompatible_idx) = self.find_granting(access, tag) + let first_incompatible_idx = self.check_granting(access, tag) .ok_or_else(|| InterpError::MachineError(format!( "no item granting {} access to tag {} found in borrow stack", access, tag, )))?; - // Step 2: Remove everything incompatible above them. Make sure we do not remove protected - // items. - // For writes, this is a simple stack. For reads, however, it is not: - // in `let raw = &mut *x as *mut _; let _val = *x;`, the second statement would pop the `Unique` - // from the reborrow of the first statement, and subsequently also pop the `SharedReadWrite` for `raw`. + // Step 2: Remove incompatible items above them. Make sure we do not remove protected + // items. Behavior differs for reads and writes. + // + // For writes, this is a simple stack, where everything starting with the first incompatible item + // gets removed. This makes sure read-only and unique pointers become invalid on write accesses + // (ensures F2a, and ensures U2 for write accesses). + // + // For reads, however, we just filter away the Unique items, which is sufficient to ensure U2 for read + // accesses. The reason is that in `let raw = &mut *x as *mut _; let _val = *x;`, the second statement + // would pop the `Unique` from the reborrow of the first statement, and subsequently also pop the + // `SharedReadWrite` for `raw`. // This pattern occurs a lot in the standard library: create a raw pointer, then also create a shared // reference and use that. { @@ -314,8 +290,8 @@ impl<'tcx> Stack { // API for this. let mut cur = first_incompatible_idx; while let Some(item) = self.borrows.get(cur) { - // If this is a read, we double-check if we really want to kill this. - if access == AccessKind::Read && granting_perm.compatible_with(access, item.perm) { + // If this is a read, only remove Unique items! + if access == AccessKind::Read && item.perm != Permission::Unique { // Keep this, check next. cur += 1; } else { @@ -346,7 +322,7 @@ impl<'tcx> Stack { global: &GlobalState, ) -> EvalResult<'tcx> { // Step 1: Find granting item. - self.find_granting(AccessKind::Write, tag) + self.check_granting(AccessKind::Write, tag) .ok_or_else(|| InterpError::MachineError(format!( "no item granting write access for deallocation to tag {} found in borrow stack", tag, @@ -403,7 +379,7 @@ impl<'tcx> Stack { }; // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. - let (_, first_incompatible_idx) = self.find_granting(access, derived_from) + let first_incompatible_idx = self.check_granting(access, derived_from) .ok_or_else(|| InterpError::MachineError(format!( "no item to reborrow for {:?} from tag {} found in borrow stack", new.perm, derived_from, )))?; From b9517ca9f3c1d54dba369dca811ed30b291c2e17 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 May 2019 17:52:08 +0200 Subject: [PATCH 0741/5092] this also fixed our 2-phase woes --- .../run-pass/stacked-borrows/interior_mutability.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/stacked-borrows/interior_mutability.rs b/tests/run-pass/stacked-borrows/interior_mutability.rs index 33f44d0093ed..d27519df48a7 100644 --- a/tests/run-pass/stacked-borrows/interior_mutability.rs +++ b/tests/run-pass/stacked-borrows/interior_mutability.rs @@ -1,12 +1,12 @@ #![feature(maybe_uninit, maybe_uninit_ref)] use std::mem::MaybeUninit; -use std::cell::Cell; -use std::cell::RefCell; +use std::cell::{Cell, RefCell, UnsafeCell}; fn main() { aliasing_mut_and_shr(); aliasing_frz_and_shr(); into_interior_mutability(); + unsafe_cell_2phase(); } fn aliasing_mut_and_shr() { @@ -57,3 +57,12 @@ fn into_interior_mutability() { let ptr = unsafe { x.get_ref() }; assert_eq!(ptr.1, 1); } + +// Two-phase borrows of the pointer returned by UnsafeCell::get() should not +// invalidate aliases. +fn unsafe_cell_2phase() { unsafe { + let x = &UnsafeCell::new(vec![]); + let x2 = &*x; + (*x.get()).push(0); + let _val = (*x2.get()).get(0); +} } From 3618992a39d6ef81dea38bbf9cd3d332281e55f9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 May 2019 14:45:15 +0200 Subject: [PATCH 0742/5092] deduplicate tests --- test-cargo-miri/tests/test.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index ce15824f94a2..b4f5563a3a8b 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -1,5 +1,7 @@ use rand::{SeedableRng, FromEntropy, Rng, rngs::SmallRng}; +// Having more than 1 test does seem to make a difference +// (i.e., this calls ptr::swap which having just one test does not). #[test] fn simple() { assert_eq!(4, 4); @@ -7,14 +9,6 @@ fn simple() { // Having more than 1 test does seem to make a difference // (i.e., this calls ptr::swap which having just one test does not). -#[test] -fn fixed_rng() { - let mut rng = rand::rngs::StdRng::seed_from_u64(0xdeadcafe); - let x: u32 = rng.gen(); - let y: u32 = rng.gen(); - assert_ne!(x, y); -} - #[test] fn entropy_rng() { // Use this opportunity to test querying the RNG (needs an external crate, hence tested here and not in the compiletest suite) From 4b9e1544c214133dab7af874e0452dd8ae2894cd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 17 May 2019 13:42:36 +0200 Subject: [PATCH 0743/5092] give up on two-phase borrows --- src/stacked_borrows.rs | 245 ++++++++---------- .../deallocate_against_barrier.rs | 2 +- 2 files changed, 105 insertions(+), 142 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index a3910fd0c43d..33d9509bd3f9 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -70,10 +70,9 @@ impl fmt::Display for Item { #[derive(Clone, Debug, PartialEq, Eq)] pub struct Stack { /// Used *mostly* as a stack; never empty. - /// We sometimes push into the middle but never remove from the middle. - /// The same tag may occur multiple times, e.g. from a two-phase borrow. /// Invariants: /// * Above a `SharedReadOnly` there can only be more `SharedReadOnly`. + /// * Except for `Untagged`, no tag occurs in the stack more than once. borrows: Vec, } @@ -118,7 +117,7 @@ impl fmt::Display for AccessKind { #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum RefKind { /// `&mut` and `Box`. - Unique, + Unique { two_phase: bool }, /// `&` with or without interior mutability. Shared, /// `*mut`/`*const` (raw pointers). @@ -128,7 +127,8 @@ pub enum RefKind { impl fmt::Display for RefKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - RefKind::Unique => write!(f, "unique"), + RefKind::Unique { two_phase: false } => write!(f, "unique"), + RefKind::Unique { two_phase: true } => write!(f, "unique (two-phase)"), RefKind::Shared => write!(f, "shared"), RefKind::Raw { mutable: true } => write!(f, "raw (mutable)"), RefKind::Raw { mutable: false } => write!(f, "raw (constant)"), @@ -194,65 +194,82 @@ impl Default for Tag { } } -/// Core relations on `Permission` define which accesses are allowed: -/// On every access, we try to find a *granting* item, and then we remove all -/// *incompatible* items above it. + +/// Core relation on `Permission` to define which accesses are allowed impl Permission { /// This defines for a given permission, whether it permits the given kind of access. fn grants(self, access: AccessKind) -> bool { - match (self, access) { - // Unique and SharedReadWrite allow any kind of access. - (Permission::Unique, _) | - (Permission::SharedReadWrite, _) => - true, - // SharedReadOnly only permits read access. - (Permission::SharedReadOnly, AccessKind::Read) => - true, - (Permission::SharedReadOnly, AccessKind::Write) => - false, - } - } - - /// This defines for a given permission, which other permissions it can tolerate "above" itself - /// when it is written to. - /// If true, then `other` is allowed to remain on top of `self` when a write access happens. - fn write_compatible_with(self, other: Permission) -> bool { - // Only writes to SharedRW can tolerate any other items above them, and they only - // tolerate other SharedRW. So, basically, searching the first write-incompatible item above X treats - // consecutive SharedRW as one "group", and skips to the first item outside X's group. - return self == Permission::SharedReadWrite && other == Permission::SharedReadWrite; + // All items grant read access, and except for SharedReadOnly they grant write access. + access == AccessKind::Read || self != Permission::SharedReadOnly } } /// Core per-location operations: access, dealloc, reborrow. impl<'tcx> Stack { /// Find the item granting the given kind of access to the given tag, and return where - /// *the first write-incompatible item above it* is on the stack. - fn check_granting(&self, access: AccessKind, tag: Tag) -> Option { - let (perm, idx) = self.borrows.iter() + /// it is on the stack. + fn find_granting(&self, access: AccessKind, tag: Tag) -> Option { + self.borrows.iter() .enumerate() // we also need to know *where* in the stack .rev() // search top-to-bottom // Return permission of first item that grants access. // We require a permission with the right tag, ensuring U3 and F3. .find_map(|(idx, item)| - if item.perm.grants(access) && tag == item.tag { - Some((item.perm, idx)) + if tag == item.tag && item.perm.grants(access) { + Some(idx) } else { None } - )?; + ) + } - let mut first_incompatible_idx = idx+1; - while let Some(item) = self.borrows.get(first_incompatible_idx) { - if perm.write_compatible_with(item.perm) { - // Keep this, check next. - first_incompatible_idx += 1; - } else { - // Found it! - break; + /// Find the first write-incompatible item above the given one -- + /// i.e, find the heigh to which the stack will be truncated when writing to `granting`. + fn find_first_write_incompaible(&self, granting: usize) -> usize { + let perm = self.borrows[granting].perm; + match perm { + Permission::SharedReadOnly => + bug!("Cannot use SharedReadOnly for writing"), + Permission::Unique => + // On a write, everything above us is incompatible. + granting+1, + Permission::SharedReadWrite => { + // The SharedReadWrite *just* above us are compatible, to skip those. + let mut idx = granting+1; + while let Some(item) = self.borrows.get(idx) { + if item.perm == Permission::SharedReadWrite { + // Go on. + idx += 1; + } else { + // Found first incompatible! + break; + } + } + idx } } - return Some(first_incompatible_idx); + } + + /// Remove the given item, enforcing barriers. + /// `tag` is just used for the error message. + fn remove(&mut self, idx: usize, tag: Option, global: &GlobalState) -> EvalResult<'tcx> { + let item = self.borrows.remove(idx); + if let Some(call) = item.protector { + if global.is_active(call) { + if let Some(tag) = tag { + return err!(MachineError(format!( + "not granting access to tag {} because incompatible item is protected: {}", + tag, item + ))); + } else { + return err!(MachineError(format!( + "deallocating while item is protected: {}", item + ))); + } + } + } + trace!("access: removing item {}", item); + Ok(()) } /// Test if a memory `access` using pointer tagged `tag` is granted. @@ -266,7 +283,7 @@ impl<'tcx> Stack { // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. - let first_incompatible_idx = self.check_granting(access, tag) + let granting_idx = self.find_granting(access, tag) .ok_or_else(|| InterpError::MachineError(format!( "no item granting {} access to tag {} found in borrow stack", access, tag, @@ -274,38 +291,24 @@ impl<'tcx> Stack { // Step 2: Remove incompatible items above them. Make sure we do not remove protected // items. Behavior differs for reads and writes. - // - // For writes, this is a simple stack, where everything starting with the first incompatible item - // gets removed. This makes sure read-only and unique pointers become invalid on write accesses - // (ensures F2a, and ensures U2 for write accesses). - // - // For reads, however, we just filter away the Unique items, which is sufficient to ensure U2 for read - // accesses. The reason is that in `let raw = &mut *x as *mut _; let _val = *x;`, the second statement - // would pop the `Unique` from the reborrow of the first statement, and subsequently also pop the - // `SharedReadWrite` for `raw`. - // This pattern occurs a lot in the standard library: create a raw pointer, then also create a shared - // reference and use that. - { - // Implemented with indices because there does not seem to be a nice iterator and range-based - // API for this. - let mut cur = first_incompatible_idx; - while let Some(item) = self.borrows.get(cur) { - // If this is a read, only remove Unique items! - if access == AccessKind::Read && item.perm != Permission::Unique { - // Keep this, check next. - cur += 1; - } else { - // Aha! This is a bad one, remove it, and make sure it is not protected. - let item = self.borrows.remove(cur); - if let Some(call) = item.protector { - if global.is_active(call) { - return err!(MachineError(format!( - "not granting {} access to tag {} because incompatible item {} is protected", - access, tag, item - ))); - } - } - trace!("access: removing item {}", item); + if access == AccessKind::Write { + // Remove everything above the write-compatible items, like a proper stack. This makes sure read-only and unique + // pointers become invalid on write accesses (ensures F2a, and ensures U2 for write accesses). + let first_incompatible_idx = self.find_first_write_incompaible(granting_idx); + for idx in (first_incompatible_idx..self.borrows.len()).rev() { + self.remove(idx, Some(tag), global)?; + } + } else { + // On a read, remove all `Unique` above the granting item. This ensures U2 for read accesses. + // The reason this is not following the stack discipline is that in + // `let raw = &mut *x as *mut _; let _val = *x;`, the second statement + // would pop the `Unique` from the reborrow of the first statement, and subsequently also pop the + // `SharedReadWrite` for `raw`. + // This pattern occurs a lot in the standard library: create a raw pointer, then also create a shared + // reference and use that. + for idx in (granting_idx+1 .. self.borrows.len()).rev() { + if self.borrows[idx].perm == Permission::Unique { + self.remove(idx, Some(tag), global)?; } } } @@ -315,29 +318,22 @@ impl<'tcx> Stack { } /// Deallocate a location: Like a write access, but also there must be no - /// active protectors at all. + /// active protectors at all because we will remove all items. fn dealloc( &mut self, tag: Tag, global: &GlobalState, ) -> EvalResult<'tcx> { // Step 1: Find granting item. - self.check_granting(AccessKind::Write, tag) + self.find_granting(AccessKind::Write, tag) .ok_or_else(|| InterpError::MachineError(format!( "no item granting write access for deallocation to tag {} found in borrow stack", tag, )))?; - // We must make sure there are no protected items remaining on the stack. - // Also clear the stack, no more accesses are possible. - for item in self.borrows.drain(..) { - if let Some(call) = item.protector { - if global.is_active(call) { - return err!(MachineError(format!( - "deallocating with active protector ({})", call - ))) - } - } + // Step 2: Remove all items. Also checks for protectors. + for idx in (0..self.borrows.len()).rev() { + self.remove(idx, None, global)?; } Ok(()) @@ -367,7 +363,6 @@ impl<'tcx> Stack { fn grant( &mut self, derived_from: Tag, - weak: bool, new: Item, global: &GlobalState, ) -> EvalResult<'tcx> { @@ -379,38 +374,26 @@ impl<'tcx> Stack { }; // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. - let first_incompatible_idx = self.check_granting(access, derived_from) + let granting_idx = self.find_granting(access, derived_from) .ok_or_else(|| InterpError::MachineError(format!( "no item to reborrow for {:?} from tag {} found in borrow stack", new.perm, derived_from, )))?; // Compute where to put the new item. - // Either way, we ensure that we insert the new item in a way that between + // Either way, we ensure that we insert the new item in a way such that between // `derived_from` and the new one, there are only items *compatible with* `derived_from`. - let new_idx = if weak { - // A weak SharedReadOnly reborrow might be added below other items, violating the - // invariant that only SharedReadOnly can sit on top of SharedReadOnly. - assert!(new.perm != Permission::SharedReadOnly, "Weak SharedReadOnly reborrows don't work"); - // A very liberal reborrow because the new pointer does not expect any kind of aliasing guarantee. - // Just insert new permission as child of old permission, and maintain everything else. - // This inserts "as far down as possible", which is good because it makes this pointer as - // long-lived as possible *and* we want all the items that are incompatible with this - // to actually get removed from the stack. If we pushed a `SharedReadWrite` on top of - // a `SharedReadOnly`, we'd violate the invariant that `SaredReadOnly` are at the top - // and we'd allow write access without invalidating frozen shared references! - // This ensures F2b for `SharedReadWrite` by adding the new item below any - // potentially existing `SharedReadOnly`. - first_incompatible_idx + let new_idx = if new.perm == Permission::SharedReadWrite { + assert!(access == AccessKind::Write, "this case only makes sense for stack-like accesses"); + // SharedReadWrite can coexist with "existing loans", meaning they don't act like a write + // access. Instead of popping the stack, we insert the item at the place the stack would + // be popped to (i.e., we insert it above all the write-compatible items). + // This ensures F2b by adding the new item below any potentially existing `SharedReadOnly`. + self.find_first_write_incompaible(granting_idx) } else { // A "safe" reborrow for a pointer that actually expects some aliasing guarantees. - // Here, creating a reference actually counts as an access, and pops incompatible - // stuff off the stack. + // Here, creating a reference actually counts as an access. // This ensures F2b for `Unique`, by removing offending `SharedReadOnly`. self.access(access, derived_from, global)?; - if access == AccessKind::Write { - // For write accesses, the position is the same as what it would have been weakly! - assert_eq!(first_incompatible_idx, self.borrows.len()); - } // We insert "as far up as possible": We know only compatible items are remaining // on top of `derived_from`, and we want the new item at the top so that we @@ -541,8 +524,7 @@ impl AllocationExtra for Stacks { } /// Retagging/reborrowing. There is some policy in here, such as which permissions -/// to grant for which references, when to add protectors, and how to realize two-phase -/// borrows in terms of the primitives above. +/// to grant for which references, and when to add protectors. impl<'a, 'mir, 'tcx> EvalContextPrivExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { fn reborrow( @@ -551,7 +533,6 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, size: Size, kind: RefKind, new_tag: Tag, - force_weak: bool, protect: bool, ) -> EvalResult<'tcx> { let this = self.eval_context_mut(); @@ -567,7 +548,8 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // Make sure that raw pointers and mutable shared references are reborrowed "weak": // There could be existing unique pointers reborrowed from them that should remain valid! let perm = match kind { - RefKind::Unique => Permission::Unique, + RefKind::Unique { two_phase: false } => Permission::Unique, + RefKind::Unique { two_phase: true } => Permission::SharedReadWrite, RefKind::Raw { mutable: true } => Permission::SharedReadWrite, RefKind::Shared | RefKind::Raw { mutable: false } => { // Shared references and *const are a whole different kind of game, the @@ -576,19 +558,16 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, return this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { // We are only ever `SharedReadOnly` inside the frozen bits. let perm = if frozen { Permission::SharedReadOnly } else { Permission::SharedReadWrite }; - let weak = perm == Permission::SharedReadWrite; let item = Item { perm, tag: new_tag, protector }; alloc.extra.for_each(cur_ptr, size, |stack, global| { - stack.grant(cur_ptr.tag, force_weak || weak, item, global) + stack.grant(cur_ptr.tag, item, global) }) }); } }; - debug_assert_ne!(perm, Permission::SharedReadOnly, "SharedReadOnly must be used frozen-sensitive"); - let weak = perm == Permission::SharedReadWrite; let item = Item { perm, tag: new_tag, protector }; alloc.extra.for_each(ptr, size, |stack, global| { - stack.grant(ptr.tag, force_weak || weak, item, global) + stack.grant(ptr.tag, item, global) }) } @@ -599,7 +578,6 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, val: ImmTy<'tcx, Tag>, kind: RefKind, protect: bool, - two_phase: bool, ) -> EvalResult<'tcx, Immediate> { let this = self.eval_context_mut(); // We want a place for where the ptr *points to*, so we get one. @@ -619,22 +597,8 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, }; // Reborrow. - // TODO: With `two_phase == true`, this performs a weak reborrow for a `Unique`. That - // can lead to some possibly surprising effects, if the parent permission is - // `SharedReadWrite` then we now have a `Unique` in the middle of them, which "splits" - // them in terms of what remains valid when the `Unique` gets used. Is that really - // what we want? - this.reborrow(place, size, kind, new_tag, /*force_weak:*/ two_phase, protect)?; + this.reborrow(place, size, kind, new_tag, protect)?; let new_place = place.replace_tag(new_tag); - // Handle two-phase borrows. - if two_phase { - assert!(kind == RefKind::Unique, "two-phase shared borrows make no sense"); - // Grant read access *to the parent pointer* with the old tag *derived from the new tag* (`new_place`). - // This means the old pointer has multiple items in the stack now, which otherwise cannot happen - // for unique references -- but in this case it precisely expresses the semantics we want. - let old_tag = place.ptr.to_ptr().unwrap().tag; - this.reborrow(new_place, size, RefKind::Shared, old_tag, /*force_weak:*/ false, /*protect:*/ false)?; - } // Return new pointer. Ok(new_place.to_ref()) @@ -656,7 +620,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, match ty.sty { // References are simple. ty::Ref(_, _, MutMutable) => - Some((RefKind::Unique, kind == RetagKind::FnEntry)), + Some((RefKind::Unique { two_phase: kind == RetagKind::TwoPhase}, kind == RetagKind::FnEntry)), ty::Ref(_, _, MutImmutable) => Some((RefKind::Shared, kind == RetagKind::FnEntry)), // Raw pointers need to be enabled. @@ -664,7 +628,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, Some((RefKind::Raw { mutable: tym.mutbl == MutMutable }, false)), // Boxes do not get a protector: protectors reflect that references outlive the call // they were passed in to; that's just not the case for boxes. - ty::Adt(..) if ty.is_box() => Some((RefKind::Unique, false)), + ty::Adt(..) if ty.is_box() => Some((RefKind::Unique { two_phase: false }, false)), _ => None, } } @@ -675,7 +639,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, if let Some((mutbl, protector)) = qualify(place.layout.ty, kind) { // Fast path. let val = this.read_immediate(this.place_to_op(place)?)?; - let val = this.retag_reference(val, mutbl, protector, kind == RetagKind::TwoPhase)?; + let val = this.retag_reference(val, mutbl, protector)?; this.write_immediate(val, place)?; return Ok(()); } @@ -711,8 +675,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let val = self.ecx.retag_reference( val, mutbl, - protector, - self.kind == RetagKind::TwoPhase + protector )?; self.ecx.write_immediate(val, place.into())?; } diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs b/tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs index 49e376c0287e..bf18c9a058cf 100644 --- a/tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs +++ b/tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs @@ -1,4 +1,4 @@ -// error-pattern: deallocating with active protect +// error-pattern: deallocating while item is protected fn inner(x: &mut i32, f: fn(&mut i32)) { // `f` may mutate, but it may not deallocate! From 8212314441bc2a60f4f28d097eb6125c88859a13 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 17 May 2019 15:03:28 +0200 Subject: [PATCH 0744/5092] fix tests --- test-cargo-miri/test.stdout.ref | 5 ++--- test-cargo-miri/test.stdout.ref2 | 2 +- test-cargo-miri/tests/test.rs | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/test-cargo-miri/test.stdout.ref b/test-cargo-miri/test.stdout.ref index 97589e9a1635..58b9b4794b90 100644 --- a/test-cargo-miri/test.stdout.ref +++ b/test-cargo-miri/test.stdout.ref @@ -5,10 +5,9 @@ test test::rng ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out -running 3 tests +running 2 tests test entropy_rng ... ok -test fixed_rng ... ok test simple ... ok -test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/test.stdout.ref2 b/test-cargo-miri/test.stdout.ref2 index 32d943623a91..ce3506709d5a 100644 --- a/test-cargo-miri/test.stdout.ref2 +++ b/test-cargo-miri/test.stdout.ref2 @@ -7,5 +7,5 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out running 1 test test simple ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index b4f5563a3a8b..ed9efa21e4fa 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -1,4 +1,4 @@ -use rand::{SeedableRng, FromEntropy, Rng, rngs::SmallRng}; +use rand::{FromEntropy, Rng, rngs::SmallRng}; // Having more than 1 test does seem to make a difference // (i.e., this calls ptr::swap which having just one test does not). From 9c161b80d05250a0a8f6e6f5f8d462c510aecf32 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 17 May 2019 14:22:55 +0200 Subject: [PATCH 0745/5092] reading does not remove Unique, it just invalidates them --- src/stacked_borrows.rs | 43 +++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 33d9509bd3f9..d14d00018a7a 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -42,6 +42,9 @@ pub enum Permission { SharedReadWrite, /// Greants shared read-only access. SharedReadOnly, + /// Grants no access, but separates two groups of SharedReadWrite so they are not + /// all considered mutually compatible. + Disabled, } /// An item in the per-location borrow stack. @@ -199,8 +202,8 @@ impl Default for Tag { impl Permission { /// This defines for a given permission, whether it permits the given kind of access. fn grants(self, access: AccessKind) -> bool { - // All items grant read access, and except for SharedReadOnly they grant write access. - access == AccessKind::Read || self != Permission::SharedReadOnly + // Disabled grants nother. Otherwise, all items grant read access, and except for SharedReadOnly they grant write access. + self != Permission::Disabled && (access == AccessKind::Read || self != Permission::SharedReadOnly) } } @@ -224,12 +227,14 @@ impl<'tcx> Stack { } /// Find the first write-incompatible item above the given one -- - /// i.e, find the heigh to which the stack will be truncated when writing to `granting`. + /// i.e, find the height to which the stack will be truncated when writing to `granting`. fn find_first_write_incompaible(&self, granting: usize) -> usize { let perm = self.borrows[granting].perm; match perm { Permission::SharedReadOnly => bug!("Cannot use SharedReadOnly for writing"), + Permission::Disabled => + bug!("Cannot use Disabled for anything"), Permission::Unique => // On a write, everything above us is incompatible. granting+1, @@ -250,10 +255,8 @@ impl<'tcx> Stack { } } - /// Remove the given item, enforcing barriers. - /// `tag` is just used for the error message. - fn remove(&mut self, idx: usize, tag: Option, global: &GlobalState) -> EvalResult<'tcx> { - let item = self.borrows.remove(idx); + /// Check if the given item is protected. + fn check_protector(item: &Item, tag: Option, global: &GlobalState) -> EvalResult<'tcx> { if let Some(call) = item.protector { if global.is_active(call) { if let Some(tag) = tag { @@ -268,7 +271,6 @@ impl<'tcx> Stack { } } } - trace!("access: removing item {}", item); Ok(()) } @@ -295,20 +297,26 @@ impl<'tcx> Stack { // Remove everything above the write-compatible items, like a proper stack. This makes sure read-only and unique // pointers become invalid on write accesses (ensures F2a, and ensures U2 for write accesses). let first_incompatible_idx = self.find_first_write_incompaible(granting_idx); - for idx in (first_incompatible_idx..self.borrows.len()).rev() { - self.remove(idx, Some(tag), global)?; + while self.borrows.len() > first_incompatible_idx { + let item = self.borrows.pop().unwrap(); + trace!("access: popping item {}", item); + Stack::check_protector(&item, Some(tag), global)?; } } else { - // On a read, remove all `Unique` above the granting item. This ensures U2 for read accesses. - // The reason this is not following the stack discipline is that in - // `let raw = &mut *x as *mut _; let _val = *x;`, the second statement + // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses. + // The reason this is not following the stack discipline (by removing the first Unique and + // everything on top of it) is that in `let raw = &mut *x as *mut _; let _val = *x;`, the second statement // would pop the `Unique` from the reborrow of the first statement, and subsequently also pop the // `SharedReadWrite` for `raw`. // This pattern occurs a lot in the standard library: create a raw pointer, then also create a shared // reference and use that. + // We *disable* instead of removing `Unique` to avoid "connecting" two neighbouring blocks of SRWs. for idx in (granting_idx+1 .. self.borrows.len()).rev() { - if self.borrows[idx].perm == Permission::Unique { - self.remove(idx, Some(tag), global)?; + let item = &mut self.borrows[idx]; + if item.perm == Permission::Unique { + trace!("access: disabling item {}", item); + Stack::check_protector(item, Some(tag), global)?; + item.perm = Permission::Disabled; } } } @@ -332,8 +340,9 @@ impl<'tcx> Stack { )))?; // Step 2: Remove all items. Also checks for protectors. - for idx in (0..self.borrows.len()).rev() { - self.remove(idx, None, global)?; + while self.borrows.len() > 0 { + let item = self.borrows.pop().unwrap(); + Stack::check_protector(&item, None, global)?; } Ok(()) From 6b4164e0df2a4fb14bee133a026774728ecb35d9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 17 May 2019 19:42:35 +0200 Subject: [PATCH 0746/5092] nits --- src/stacked_borrows.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index d14d00018a7a..239752ea242e 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -237,10 +237,10 @@ impl<'tcx> Stack { bug!("Cannot use Disabled for anything"), Permission::Unique => // On a write, everything above us is incompatible. - granting+1, + granting + 1, Permission::SharedReadWrite => { // The SharedReadWrite *just* above us are compatible, to skip those. - let mut idx = granting+1; + let mut idx = granting + 1; while let Some(item) = self.borrows.get(idx) { if item.perm == Permission::SharedReadWrite { // Go on. From 3fde45233bbca880e8ed0dbcb33a107bd0c07d86 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 19 May 2019 12:40:59 +0200 Subject: [PATCH 0747/5092] Prefer `drain` over manual implementation of `drain` --- src/stacked_borrows.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 239752ea242e..e0ac6bf05a74 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -226,7 +226,7 @@ impl<'tcx> Stack { ) } - /// Find the first write-incompatible item above the given one -- + /// Find the first write-incompatible item above the given one -- /// i.e, find the height to which the stack will be truncated when writing to `granting`. fn find_first_write_incompaible(&self, granting: usize) -> usize { let perm = self.borrows[granting].perm; @@ -297,8 +297,7 @@ impl<'tcx> Stack { // Remove everything above the write-compatible items, like a proper stack. This makes sure read-only and unique // pointers become invalid on write accesses (ensures F2a, and ensures U2 for write accesses). let first_incompatible_idx = self.find_first_write_incompaible(granting_idx); - while self.borrows.len() > first_incompatible_idx { - let item = self.borrows.pop().unwrap(); + for item in self.borrows.drain(first_incompatible_idx..).rev() { trace!("access: popping item {}", item); Stack::check_protector(&item, Some(tag), global)?; } @@ -340,8 +339,7 @@ impl<'tcx> Stack { )))?; // Step 2: Remove all items. Also checks for protectors. - while self.borrows.len() > 0 { - let item = self.borrows.pop().unwrap(); + for item in self.borrows.drain(..).rev() { Stack::check_protector(&item, None, global)?; } From 5c54a58c066a7cc05f1106811cd78334ccdc727a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 19 May 2019 13:59:18 +0200 Subject: [PATCH 0748/5092] typo --- src/stacked_borrows.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index e0ac6bf05a74..be6bec60cfd4 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -40,7 +40,7 @@ pub enum Permission { Unique, /// Grants shared mutable access. SharedReadWrite, - /// Greants shared read-only access. + /// Grants shared read-only access. SharedReadOnly, /// Grants no access, but separates two groups of SharedReadWrite so they are not /// all considered mutually compatible. @@ -202,7 +202,7 @@ impl Default for Tag { impl Permission { /// This defines for a given permission, whether it permits the given kind of access. fn grants(self, access: AccessKind) -> bool { - // Disabled grants nother. Otherwise, all items grant read access, and except for SharedReadOnly they grant write access. + // Disabled grants nothing. Otherwise, all items grant read access, and except for SharedReadOnly they grant write access. self != Permission::Disabled && (access == AccessKind::Read || self != Permission::SharedReadOnly) } } From df36c2bb7d6a71d3fe420e1aba9a0bd0655e9758 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 20 May 2019 09:32:01 +0200 Subject: [PATCH 0749/5092] expand explanation of how we treat validity invariants --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 22eb41f94900..ae2f5f506f16 100644 --- a/README.md +++ b/README.md @@ -23,9 +23,11 @@ Be aware that Miri will not catch all possible errors in your program, and cannot run all programs: * There are still plenty of open questions around the basic invariants for some - types and when these invariants even have to hold, so if you program runs fine - in Miri right now that is by no means a guarantee that it is UB-free when - these questions get answered. + types and when these invariants even have to hold. Miri tries to avoid false + positives here, so if you program runs fine in Miri right now that is by no + means a guarantee that it is UB-free when these questions get answered. In + particular, Miri does currently not check that integers are initialized or + that references point to valid data. * If the program relies on unspecified details of how data is laid out, it will still run fine in Miri -- but might break (including causing UB) on different compiler versions or different platforms. From 0c85dbf3df0f545133dca24eccfc9f0f6107c7f8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 20 May 2019 10:46:28 +0200 Subject: [PATCH 0750/5092] prepare for MaybeUninit stabilization --- tests/run-pass/stacked-borrows/interior_mutability.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/stacked-borrows/interior_mutability.rs b/tests/run-pass/stacked-borrows/interior_mutability.rs index d27519df48a7..bd19f153deeb 100644 --- a/tests/run-pass/stacked-borrows/interior_mutability.rs +++ b/tests/run-pass/stacked-borrows/interior_mutability.rs @@ -1,4 +1,4 @@ -#![feature(maybe_uninit, maybe_uninit_ref)] +#![feature(maybe_uninit_extra, maybe_uninit_ref)] use std::mem::MaybeUninit; use std::cell::{Cell, RefCell, UnsafeCell}; From 5a4e1cdd863d206b75e244895df6d05200b85c56 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 21 May 2019 08:54:15 +0200 Subject: [PATCH 0751/5092] update Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 4cf2697aa421..3c8fa005c32d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -372be4f360ce42b1a10126a711189796f8440ab4 +d35181ad8785fa958e43580a29a982afe02c728f From 74f98b3803404dd86d6c6365081e2276fa7a0543 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 21 May 2019 15:41:26 +0200 Subject: [PATCH 0752/5092] test for new read rules --- .../stacked_borrows/interior_mut1.rs | 11 ++++++-- .../stacked_borrows/interior_mut2.rs | 28 +++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 tests/compile-fail/stacked_borrows/interior_mut2.rs diff --git a/tests/compile-fail/stacked_borrows/interior_mut1.rs b/tests/compile-fail/stacked_borrows/interior_mut1.rs index dd9fce110c2d..e2f8233bd86b 100644 --- a/tests/compile-fail/stacked_borrows/interior_mut1.rs +++ b/tests/compile-fail/stacked_borrows/interior_mut1.rs @@ -3,8 +3,13 @@ use std::cell::UnsafeCell; fn main() { unsafe { let c = &UnsafeCell::new(UnsafeCell::new(0)); let inner_uniq = &mut *c.get(); - let inner_shr = &*inner_uniq; // a SharedRW with a tag - *c.get() = UnsafeCell::new(1); // invalidates the SharedRW + // stack: [c: SharedReadWrite, inner_uniq: Unique] + + let inner_shr = &*inner_uniq; // adds a SharedReadWrite + // stack: [c: SharedReadWrite, inner_uniq: Unique, inner_shr: SharedReadWrite] + + *c.get() = UnsafeCell::new(1); // invalidates inner_shr + // stack: [c: SharedReadWrite] + let _val = *inner_shr.get(); //~ ERROR borrow stack - let _val = *inner_uniq.get(); } } diff --git a/tests/compile-fail/stacked_borrows/interior_mut2.rs b/tests/compile-fail/stacked_borrows/interior_mut2.rs new file mode 100644 index 000000000000..45770020d33d --- /dev/null +++ b/tests/compile-fail/stacked_borrows/interior_mut2.rs @@ -0,0 +1,28 @@ +use std::cell::UnsafeCell; +use std::mem; + +// Like `&mut *x.get()`, but without intermediate raw pointers. +#[allow(mutable_transmutes)] +unsafe fn unsafe_cell_get(x: &UnsafeCell) -> &'static mut T { + mem::transmute(x) +} + +fn main() { unsafe { + let c = &UnsafeCell::new(UnsafeCell::new(0)); + let inner_uniq = &mut *c.get(); + let inner_shr = &*inner_uniq; + // stack: [c: SharedReadWrite, inner_uniq: Unique, inner_shr: SharedReadWrite] + + let _val = c.get().read(); // invalidates inner_uniq + // stack: [c: SharedReadWrite, inner_uniq: Disabled, inner_shr: SharedReadWrite] + + // We have to be careful not to add any raw pointers above inner_uniq in + // the stack, hence the use of unsafe_cell_get. + let _val = *unsafe_cell_get(inner_shr); // this still works + + *c.get() = UnsafeCell::new(0); // now inner_shr gets invalidated + // stack: [c: SharedReadWrite] + + // now this does not work any more + let _val = *inner_shr.get(); //~ ERROR borrow stack +} } From 3e33e54b5be77d03df0962291f1480cc3876544d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 May 2019 11:03:04 +0200 Subject: [PATCH 0753/5092] hopefully improve error message a bit --- src/stacked_borrows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index be6bec60cfd4..e76747ef8071 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -383,7 +383,7 @@ impl<'tcx> Stack { // We use that to determine where to put the new item. let granting_idx = self.find_granting(access, derived_from) .ok_or_else(|| InterpError::MachineError(format!( - "no item to reborrow for {:?} from tag {} found in borrow stack", new.perm, derived_from, + "trying to reborrow for {:?}, but parent tag {} does not have an appropriate item in the borrow stack", new.perm, derived_from, )))?; // Compute where to put the new item. From 1d92791965f81f44f2d961396e4eda6d43392d8d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 May 2019 15:54:50 +0200 Subject: [PATCH 0754/5092] use prettier printing --- src/stacked_borrows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index e76747ef8071..332e44e6780e 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -545,7 +545,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let this = self.eval_context_mut(); let protector = if protect { Some(this.frame().extra) } else { None }; let ptr = place.ptr.to_ptr()?; - trace!("reborrow: {:?} reference {} derived from {} (pointee {}): {:?}, size {}", + trace!("reborrow: {} reference {} derived from {} (pointee {}): {:?}, size {}", kind, new_tag, ptr.tag, place.layout.ty, ptr, size.bytes()); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. From ff6f1010747104db6af41b2a49d168af66328910 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 May 2019 16:33:44 +0200 Subject: [PATCH 0755/5092] add more bugs that Miri found --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ae2f5f506f16..d3a06dea6d27 100644 --- a/README.md +++ b/README.md @@ -317,6 +317,7 @@ Definite bugs found: * [`Debug for vec_deque::Iter` accessing uninitialized memory](https://github.com/rust-lang/rust/issues/53566) * [`From<&[T]> for Rc` creating a not sufficiently aligned reference](https://github.com/rust-lang/rust/issues/54908) * [`BTreeMap` creating a shared reference pointing to a too small allocation](https://github.com/rust-lang/rust/issues/54957) +* [`Vec::append` creating a dangling reference](https://github.com/rust-lang/rust/pull/61082) * [Futures turning a shared reference into a mutable one](https://github.com/rust-lang/rust/pull/56319) * [`str` turning a shared reference into a mutable one](https://github.com/rust-lang/rust/pull/58200) * [`rand` performing unaligned reads](https://github.com/rust-random/rand/issues/779) @@ -326,6 +327,7 @@ Violations of Stacked Borrows found that are likely bugs (but Stacked Borrows is * [`VecDeque` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/56161) * [`BTreeMap` creating mutable references that overlap with shared references](https://github.com/rust-lang/rust/pull/58431) * [`LinkedList` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/60072) +* [`Vec::push` invalidating existing references into the vector](https://github.com/rust-lang/rust/issues/60847) ## License From 5569fffe7d71ed52ce284d0ffc6691d0141874f2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 24 May 2019 10:09:18 +0200 Subject: [PATCH 0756/5092] avoid having both Debug and Display for a type and using the wrong one --- src/stacked_borrows.rs | 46 +++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 332e44e6780e..0c1e9b9c49aa 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -18,16 +18,16 @@ pub type PtrId = NonZeroU64; pub type CallId = NonZeroU64; /// Tracking pointer provenance -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Copy, Clone, Hash, PartialEq, Eq)] pub enum Tag { Tagged(PtrId), Untagged, } -impl fmt::Display for Tag { +impl fmt::Debug for Tag { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - Tag::Tagged(id) => write!(f, "{}", id), + Tag::Tagged(id) => write!(f, "<{}>", id), Tag::Untagged => write!(f, ""), } } @@ -48,7 +48,7 @@ pub enum Permission { } /// An item in the per-location borrow stack. -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Copy, Clone, Hash, PartialEq, Eq)] pub struct Item { /// The permission this item grants. perm: Permission, @@ -58,9 +58,9 @@ pub struct Item { protector: Option, } -impl fmt::Display for Item { +impl fmt::Debug for Item { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "[{:?} for {}", self.perm, self.tag)?; + write!(f, "[{:?} for {:?}", self.perm, self.tag)?; if let Some(call) = self.protector { write!(f, " (call {})", call)?; } @@ -99,7 +99,7 @@ pub struct GlobalState { pub type MemoryState = Rc>; /// Indicates which kind of access is being performed. -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Copy, Clone, Hash, PartialEq, Eq)] pub enum AccessKind { Read, Write, @@ -108,8 +108,8 @@ pub enum AccessKind { impl fmt::Display for AccessKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - AccessKind::Read => write!(f, "read"), - AccessKind::Write => write!(f, "write"), + AccessKind::Read => write!(f, "read access"), + AccessKind::Write => write!(f, "write access"), } } } @@ -117,7 +117,7 @@ impl fmt::Display for AccessKind { /// Indicates which kind of reference is being created. /// Used by high-level `reborrow` to compute which permissions to grant to the /// new pointer. -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Copy, Clone, Hash, PartialEq, Eq)] pub enum RefKind { /// `&mut` and `Box`. Unique { two_phase: bool }, @@ -261,12 +261,12 @@ impl<'tcx> Stack { if global.is_active(call) { if let Some(tag) = tag { return err!(MachineError(format!( - "not granting access to tag {} because incompatible item is protected: {}", + "not granting access to tag {:?} because incompatible item is protected: {:?}", tag, item ))); } else { return err!(MachineError(format!( - "deallocating while item is protected: {}", item + "deallocating while item is protected: {:?}", item ))); } } @@ -287,7 +287,7 @@ impl<'tcx> Stack { // Step 1: Find granting item. let granting_idx = self.find_granting(access, tag) .ok_or_else(|| InterpError::MachineError(format!( - "no item granting {} access to tag {} found in borrow stack", + "no item granting {} to tag {:?} found in borrow stack", access, tag, )))?; @@ -298,7 +298,7 @@ impl<'tcx> Stack { // pointers become invalid on write accesses (ensures F2a, and ensures U2 for write accesses). let first_incompatible_idx = self.find_first_write_incompaible(granting_idx); for item in self.borrows.drain(first_incompatible_idx..).rev() { - trace!("access: popping item {}", item); + trace!("access: popping item {:?}", item); Stack::check_protector(&item, Some(tag), global)?; } } else { @@ -313,7 +313,7 @@ impl<'tcx> Stack { for idx in (granting_idx+1 .. self.borrows.len()).rev() { let item = &mut self.borrows[idx]; if item.perm == Permission::Unique { - trace!("access: disabling item {}", item); + trace!("access: disabling item {:?}", item); Stack::check_protector(item, Some(tag), global)?; item.perm = Permission::Disabled; } @@ -334,7 +334,7 @@ impl<'tcx> Stack { // Step 1: Find granting item. self.find_granting(AccessKind::Write, tag) .ok_or_else(|| InterpError::MachineError(format!( - "no item granting write access for deallocation to tag {} found in borrow stack", + "no item granting write access for deallocation to tag {:?} found in borrow stack", tag, )))?; @@ -383,7 +383,7 @@ impl<'tcx> Stack { // We use that to determine where to put the new item. let granting_idx = self.find_granting(access, derived_from) .ok_or_else(|| InterpError::MachineError(format!( - "trying to reborrow for {:?}, but parent tag {} does not have an appropriate item in the borrow stack", new.perm, derived_from, + "trying to reborrow for {:?}, but parent tag {:?} does not have an appropriate item in the borrow stack", new.perm, derived_from, )))?; // Compute where to put the new item. @@ -412,9 +412,9 @@ impl<'tcx> Stack { // Put the new item there. As an optimization, deduplicate if it is equal to one of its new neighbors. if self.borrows[new_idx-1] == new || self.borrows.get(new_idx) == Some(&new) { // Optimization applies, done. - trace!("reborrow: avoiding adding redundant item {}", new); + trace!("reborrow: avoiding adding redundant item {:?}", new); } else { - trace!("reborrow: adding item {}", new); + trace!("reborrow: adding item {:?}", new); self.borrows.insert(new_idx, new); } @@ -497,7 +497,7 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - trace!("read access with tag {}: {:?}, size {}", ptr.tag, ptr, size.bytes()); + trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr, size.bytes()); alloc.extra.for_each(ptr, size, |stack, global| { stack.access(AccessKind::Read, ptr.tag, global)?; Ok(()) @@ -510,7 +510,7 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - trace!("write access with tag {}: {:?}, size {}", ptr.tag, ptr, size.bytes()); + trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr, size.bytes()); alloc.extra.for_each(ptr, size, |stack, global| { stack.access(AccessKind::Write, ptr.tag, global)?; Ok(()) @@ -523,7 +523,7 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - trace!("deallocation with tag {}: {:?}, size {}", ptr.tag, ptr, size.bytes()); + trace!("deallocation with tag {:?}: {:?}, size {}", ptr.tag, ptr, size.bytes()); alloc.extra.for_each(ptr, size, |stack, global| { stack.dealloc(ptr.tag, global) }) @@ -545,7 +545,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let this = self.eval_context_mut(); let protector = if protect { Some(this.frame().extra) } else { None }; let ptr = place.ptr.to_ptr()?; - trace!("reborrow: {} reference {} derived from {} (pointee {}): {:?}, size {}", + trace!("reborrow: {} reference {:?} derived from {:?} (pointee {}): {:?}, size {}", kind, new_tag, ptr.tag, place.layout.ty, ptr, size.bytes()); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. From 21fb14dba1649ef8f2be612df2943fc9313781be Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 24 May 2019 13:09:29 +0200 Subject: [PATCH 0757/5092] avoid printing the tag twice --- src/stacked_borrows.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 0c1e9b9c49aa..f997e6316435 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -497,7 +497,7 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr, size.bytes()); + trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); alloc.extra.for_each(ptr, size, |stack, global| { stack.access(AccessKind::Read, ptr.tag, global)?; Ok(()) @@ -510,7 +510,7 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr, size.bytes()); + trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); alloc.extra.for_each(ptr, size, |stack, global| { stack.access(AccessKind::Write, ptr.tag, global)?; Ok(()) @@ -523,7 +523,7 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - trace!("deallocation with tag {:?}: {:?}, size {}", ptr.tag, ptr, size.bytes()); + trace!("deallocation with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); alloc.extra.for_each(ptr, size, |stack, global| { stack.dealloc(ptr.tag, global) }) @@ -546,7 +546,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let protector = if protect { Some(this.frame().extra) } else { None }; let ptr = place.ptr.to_ptr()?; trace!("reborrow: {} reference {:?} derived from {:?} (pointee {}): {:?}, size {}", - kind, new_tag, ptr.tag, place.layout.ty, ptr, size.bytes()); + kind, new_tag, ptr.tag, place.layout.ty, ptr.erase_tag(), size.bytes()); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. let alloc = this.memory().get(ptr.alloc_id)?; From aa868a8a212656a965b25762fb3a45f0bd64666c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 May 2019 09:45:00 +0200 Subject: [PATCH 0758/5092] dependency management --- Cargo.toml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 639fd50c7503..6f7570edda5f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,12 +40,15 @@ rustc_version = { version = "0.2.3", optional = true } env_logger = "0.6" log = "0.4" shell-escape = "0.1.4" +hex = "0.3.2" +rand = "0.6" # A noop dependency that changes in the Rust repository, it's a bit of a hack. # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` # for more information. rustc-workspace-hack = "1.0.0" -hex = "0.3.2" -rand = "0.6" +# Depend on num-traits with default features to avoid having to rebuild +# between "cargo build" and "cargo intall". +num-traits = "*" [build-dependencies] vergen = "3" From c2791fc56abba235c4d0d56a746e24ac2cb778bf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 May 2019 12:51:59 +0200 Subject: [PATCH 0759/5092] add 'miri' script to help build, test and run miri --- miri | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100755 miri diff --git a/miri b/miri new file mode 100755 index 000000000000..fc8fdb7b5b25 --- /dev/null +++ b/miri @@ -0,0 +1,36 @@ +#!/bin/sh +set -e +TARGET=$(rustc --print target-spec-json -Z unstable-options | jq '.["llvm-target"]' -r) +SYSROOT=$(rustc --print sysroot) +export RUSTFLAGS="-C link-args=-Wl,-rpath,$SYSROOT/lib/rustlib/$TARGET/lib -C debug-assertions" + +COMMAND="$1" +shift + +case "$COMMAND" in +install) + exec cargo install --path "$(dirname "$0")" --force --locked --offline + ;; +build|test|run) + # Basic build + cargo build --release + + # We we want to just build, we are done. + if [ "$COMMAND" = "build" ]; then exit 0; fi + + # Get ourselves a sysroot + if [ -n "$MIRI_SYSROOT" ]; then + # sysroot already set + true + elif rustc --print sysroot | egrep -q 'build/[^/]+/stage'; then + # a local build, we have a proper libstd in $SYSROOT + true + else + # we have to build a sysroot + cargo run --release --bin cargo-miri -- miri setup + export MIRI_SYSROOT=$HOME/.cache/miri/HOST + fi + + exec cargo "$COMMAND" --release "$@" + ;; +esac From 6420293af4b87bca51c51661de1aa53d2158cdb5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 May 2019 12:59:52 +0200 Subject: [PATCH 0760/5092] adjust readme to miri build script --- README.md | 47 +++++++++++------------------------------------ 1 file changed, 11 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index d3a06dea6d27..09b23b0db12f 100644 --- a/README.md +++ b/README.md @@ -141,42 +141,28 @@ version of `rustc` that, instead of compiling your code, runs it. It accepts all the same flags as `rustc` (though the ones only affecting code generation and linking obviously will have no effect) [and more][miri-flags]. -To run the Miri driver, you need to have the `MIRI_SYSROOT` environment variable -set to an appropriate sysroot. You can generate such a sysroot with the -following incantation: - -``` -cargo run --bin cargo-miri -- miri setup -``` - -This basically runs the `cargo-miri` binary (which backs the `cargo miri` -subcommand) with `cargo`, and asks it to `setup`. It should in the end print -the directory where the libstd was built. In the following, we will assume it -is `~/.cache/miri/HOST`; you may have to adjust that if you are not using Linux. - -Now you can run the driver directly using +Running the Miri driver requires some fiddling with environment variables, so the `miri` script helps you do that. +For example, you can run the driver on a particular file by doing ```sh -MIRI_SYSROOT=~/.cache/miri/HOST cargo run tests/run-pass/format.rs # or whatever test you like +./miri run tests/run-pass/format.rs # or whatever test you like ``` and you can run the test suite using ``` -cargo test +./miri test ``` -We recommend adding the `--release` flag to make tests run faster. - -`cargo test --release FILTER` only runs those tests that contain `FILTER` in -their filename (including the base directory, e.g. `cargo test --release fail` -will run all compile-fail tests). +`./miri test FILTER` only runs those tests that contain `FILTER` in their +filename (including the base directory, e.g. `./miri test fail` will run all +compile-fail tests). You can get a trace of which MIR statements are being executed by setting the `MIRI_LOG` environment variable. For example: ```sh -MIRI_LOG=info cargo run tests/run-pass/vecs.rs +MIRI_LOG=info ./miri run tests/run-pass/vecs.rs ``` Setting `MIRI_LOG` like this will configure logging for Miri itself as well as @@ -185,7 +171,7 @@ can also do more targeted configuration, e.g. the following helps debug the stacked borrows implementation: ```sh -MIRI_LOG=rustc_mir::interpret=info,miri::stacked_borrows cargo run tests/run-pass/vecs.rs +MIRI_LOG=rustc_mir::interpret=info,miri::stacked_borrows ./miri run tests/run-pass/vecs.rs ``` In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an @@ -199,7 +185,7 @@ is probably easier to test it with the cargo wrapper. You can install your development version of Miri using ``` -cargo install --path . --force +./miri install ``` and then you can use it as if it was installed by `rustup`. Make sure you use @@ -235,18 +221,7 @@ rustup override set custom ``` With this, you should now have a working development setup! See -[above][testing-miri] for how to proceed working with the Miri driver. Notice -that rustc's sysroot is already built for Miri in this case, so you can set -`MIRI_SYSROOT=$(rustc --print sysroot)`. - -Running `cargo miri` in this setup is a bit more complicated, because the Miri -binary you just created needs help to find the libraries it links against. On -Linux, you can set the rpath to make this "just work": - -```sh -export RUSTFLAGS="-C link-args=-Wl,-rpath,$(rustc --print sysroot)/lib/rustlib/x86_64-unknown-linux-gnu/lib" -cargo install --path . --force -``` +[above][testing-miri] for how to proceed working with the Miri driver. ### Miri `-Z` flags and environment variables [miri-flags]: #miri--z-flags-and-environment-variables From ab1f60c9105f41f0ba3d6e7b87674828dcabc025 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 May 2019 13:04:18 +0200 Subject: [PATCH 0761/5092] comments --- miri | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/miri b/miri index fc8fdb7b5b25..bc8bd59e5dd5 100755 --- a/miri +++ b/miri @@ -2,6 +2,8 @@ set -e TARGET=$(rustc --print target-spec-json -Z unstable-options | jq '.["llvm-target"]' -r) SYSROOT=$(rustc --print sysroot) +# We set the rpath so that Miri finds the private rustc libraries it needs. +# We enable debug-assertions to get tracing. export RUSTFLAGS="-C link-args=-Wl,-rpath,$SYSROOT/lib/rustlib/$TARGET/lib -C debug-assertions" COMMAND="$1" @@ -22,8 +24,8 @@ build|test|run) if [ -n "$MIRI_SYSROOT" ]; then # sysroot already set true - elif rustc --print sysroot | egrep -q 'build/[^/]+/stage'; then - # a local build, we have a proper libstd in $SYSROOT + elif echo "$SYSROOT" | egrep -q 'build/[^/]+/stage'; then + # a local rustc build, assume we have a proper libstd in $SYSROOT true else # we have to build a sysroot From eb85ced8c730ad6a0f0518dfd7db3166a18e8108 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 May 2019 13:08:47 +0200 Subject: [PATCH 0762/5092] improve backtraces --- miri | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/miri b/miri index bc8bd59e5dd5..99ae7c5811ee 100755 --- a/miri +++ b/miri @@ -4,7 +4,8 @@ TARGET=$(rustc --print target-spec-json -Z unstable-options | jq '.["llvm-target SYSROOT=$(rustc --print sysroot) # We set the rpath so that Miri finds the private rustc libraries it needs. # We enable debug-assertions to get tracing. -export RUSTFLAGS="-C link-args=-Wl,-rpath,$SYSROOT/lib/rustlib/$TARGET/lib -C debug-assertions" +# We enable line-only debuginfo for backtraces. +export RUSTFLAGS="-C link-args=-Wl,-rpath,$SYSROOT/lib/rustlib/$TARGET/lib -C debug-assertions -C debuginfo=1" COMMAND="$1" shift From cf96396fccbad2cce0f4a710d26951083a9864e6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 May 2019 14:40:27 +0200 Subject: [PATCH 0763/5092] make miri script smarter: auto-determine MIRI_SYSROOT, handle MIRI_TEST_TARGET --- README.md | 10 +++--- miri | 83 ++++++++++++++++++++++++++++++++----------- src/bin/cargo-miri.rs | 5 ++- travis.sh | 19 +++------- 4 files changed, 78 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 09b23b0db12f..130072825e1c 100644 --- a/README.md +++ b/README.md @@ -141,14 +141,16 @@ version of `rustc` that, instead of compiling your code, runs it. It accepts all the same flags as `rustc` (though the ones only affecting code generation and linking obviously will have no effect) [and more][miri-flags]. -Running the Miri driver requires some fiddling with environment variables, so the `miri` script helps you do that. -For example, you can run the driver on a particular file by doing +Running the Miri driver requires some fiddling with environment variables, so +the `miri` script helps you do that. For example, you can run the driver on a +particular file by doing ```sh -./miri run tests/run-pass/format.rs # or whatever test you like +./miri run tests/run-pass/format.rs +./miri run tests/run-pass/hello.rs --target i686-unknown-linux-gnu ``` -and you can run the test suite using +and you can run the test suite using: ``` ./miri test diff --git a/miri b/miri index 99ae7c5811ee..1d090c8827fd 100755 --- a/miri +++ b/miri @@ -7,33 +7,76 @@ SYSROOT=$(rustc --print sysroot) # We enable line-only debuginfo for backtraces. export RUSTFLAGS="-C link-args=-Wl,-rpath,$SYSROOT/lib/rustlib/$TARGET/lib -C debug-assertions -C debuginfo=1" +## Helper functions + +# Build a sysroot and set MIRI_SYSROOT to use it. Arguments are passed to `cargo miri setup`. +build_sysroot() { + # Build once, for the user to see. + cargo run --release --bin cargo-miri -- miri setup "$@" + # Call again, to just set env var. + eval $(cargo run --release -q --bin cargo-miri -- miri setup --env "$@") + export MIRI_SYSROOT +} + +# Prepare and set MIRI_SYSROOT. Respects `MIRI_TEST_TARGET` and takes into account +# locally built vs. distributed rustc. +find_sysroot() { + # Get ourselves a sysroot + if [ -n "$MIRI_SYSROOT" ]; then + # Sysroot already set, use that. + true + elif echo "$SYSROOT" | egrep -q 'build/[^/]+/stage'; then + # A local rustc build. + if [ -n "$MIRI_TEST_TARGET" ]; then + # Foreign targets still need a build. Use the rustc sources. + export XARGO_RUST_SRC="$SYSROOT/../../../src" + build_sysroot --target "$MIRI_TEST_TARGET" + else + # Assume we have a proper host libstd in $SYSROOT. + true + fi + else + # We have to build a sysroot either way. + if [ -n "$MIRI_TEST_TARGET" ]; then + build_sysroot --target "$MIRI_TEST_TARGET" + else + build_sysroot + fi + fi +} + +## Main + COMMAND="$1" shift case "$COMMAND" in install) - exec cargo install --path "$(dirname "$0")" --force --locked --offline + # "--locked" to respect the Cargo.lock file if it exists, + # "--offline" to avoid querying the registry (for yanked packages). + exec cargo "$COMMAND" --path "$(dirname "$0")" --force --locked --offline "$@" ;; -build|test|run) - # Basic build - cargo build --release - - # We we want to just build, we are done. - if [ "$COMMAND" = "build" ]; then exit 0; fi - - # Get ourselves a sysroot - if [ -n "$MIRI_SYSROOT" ]; then - # sysroot already set - true - elif echo "$SYSROOT" | egrep -q 'build/[^/]+/stage'; then - # a local rustc build, assume we have a proper libstd in $SYSROOT - true - else - # we have to build a sysroot - cargo run --release --bin cargo-miri -- miri setup - export MIRI_SYSROOT=$HOME/.cache/miri/HOST +build) + # Build, and let caller control flags. + exec cargo "$COMMAND" --release "$@" + ;; +test|run) + # In "run" mode, scan for "--target" to set the "MIRI_TEST_TARGET" env var so + # that we set the MIRI_SYSROOT up the right way. + if [ "$COMMAND" = "run" ] && [ -z "$MIRI_TEST_TARGET" ]; then + for ARG in "$@"; do + if [ "$LAST_ARG" = "--target" ]; then + # Found it! + export MIRI_TEST_TARGET="$ARG" + break + fi + LAST_ARG="$ARG" + done fi - + # First build and get a sysroot. + cargo build --release + find_sysroot + # Then run the actual command. exec cargo "$COMMAND" --release "$@" ;; esac diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 5dc7a75fc764..55c53e7361a5 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -243,6 +243,7 @@ path = "lib.rs" File::create(dir.join("lib.rs")).unwrap(); // Run xargo. let target = get_arg_flag_value("--target"); + let print_env = !ask_user && has_arg_flag("--env"); // whether we just print the necessary environment variable let mut command = Command::new("xargo"); command.arg("build").arg("-q") .current_dir(&dir) @@ -265,7 +266,9 @@ path = "lib.rs" }; let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; std::env::set_var("MIRI_SYSROOT", &sysroot); - if !ask_user { + if print_env { + println!("MIRI_SYSROOT={}", sysroot.display()); + } else if !ask_user { println!("A libstd for Miri is now available in `{}`", sysroot.display()); } } diff --git a/travis.sh b/travis.sh index 84f9c408dcba..dc98ca44ae58 100755 --- a/travis.sh +++ b/travis.sh @@ -3,36 +3,27 @@ set -euo pipefail # Determine configuration if [ "$TRAVIS_OS_NAME" == osx ]; then - MIRI_SYSROOT_BASE=~/Library/Caches/miri.miri.miri/ FOREIGN_TARGET=i686-apple-darwin else - MIRI_SYSROOT_BASE=~/.cache/miri/ FOREIGN_TARGET=i686-unknown-linux-gnu fi # Prepare echo "Build and install miri" -cargo build --release --all-features --all-targets -cargo install --all-features --force --path . -echo - -echo "Get ourselves a MIR-full libstd for the host and a foreign architecture" -cargo miri setup -cargo miri setup --target "$FOREIGN_TARGET" +./miri build --all-features --all-targets +./miri install echo # Test function run_tests { - cargo test --release --all-features - test-cargo-miri/run-test.py + ./miri test + test-cargo-miri/run-test.py } echo "Test host architecture" -export MIRI_SYSROOT="$MIRI_SYSROOT_BASE"/HOST run_tests echo echo "Test foreign architecture ($FOREIGN_TARGET)" -export MIRI_SYSROOT="$MIRI_SYSROOT_BASE" MIRI_TEST_TARGET="$FOREIGN_TARGET" -run_tests +MIRI_TEST_TARGET="$FOREIGN_TARGET" run_tests echo From 7f3a298f6db4acdd33e29f5c4dc20cd91efa1859 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 May 2019 15:02:17 +0200 Subject: [PATCH 0764/5092] improve macOS-compatibility by being more awful --- miri | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/miri b/miri index 1d090c8827fd..7c88309c4472 100755 --- a/miri +++ b/miri @@ -1,6 +1,7 @@ #!/bin/sh set -e -TARGET=$(rustc --print target-spec-json -Z unstable-options | jq '.["llvm-target"]' -r) +# I'd love to use `jq` for parsing the JSON properly, but macOS is totally underequipped for this kind of work. +TARGET=$(rustc --print target-spec-json -Z unstable-options | grep llvm-target | cut -d '"' -f 4) SYSROOT=$(rustc --print sysroot) # We set the rpath so that Miri finds the private rustc libraries it needs. # We enable debug-assertions to get tracing. From a358590679df59d57ca66524f162c5b2f8f2bf18 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 May 2019 15:05:55 +0200 Subject: [PATCH 0765/5092] fix indentation --- miri | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/miri b/miri index 7c88309c4472..effbd023f198 100755 --- a/miri +++ b/miri @@ -33,8 +33,8 @@ find_sysroot() { export XARGO_RUST_SRC="$SYSROOT/../../../src" build_sysroot --target "$MIRI_TEST_TARGET" else - # Assume we have a proper host libstd in $SYSROOT. - true + # Assume we have a proper host libstd in $SYSROOT. + true fi else # We have to build a sysroot either way. From 3a837cdedd782dab48b98eb488c4c8f90c013cd2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 May 2019 15:19:53 +0200 Subject: [PATCH 0766/5092] add comment --- travis.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/travis.sh b/travis.sh index dc98ca44ae58..4df12613fb83 100755 --- a/travis.sh +++ b/travis.sh @@ -17,6 +17,8 @@ echo # Test function run_tests { ./miri test + # "miri test" has built the sysroot for us, now this should pass without + # any interactive questions. test-cargo-miri/run-test.py } From aa888c55936a473d5ff0c4f474a42bf94237a77d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 May 2019 15:24:37 +0200 Subject: [PATCH 0767/5092] remove redundant RUSTFLAGS --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fd8c1260215d..1ba55e0c724a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,6 @@ env: global: - RUST_TEST_NOCAPTURE=1 - RUST_BACKTRACE=1 - - RUSTFLAGS="-C debug-assertions" before_script: # Linux: install extra stuff for cross-compilation From 0b6b7dad8f1aaeca31a8c298fa8fcae3831a69bf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 May 2019 15:35:48 +0200 Subject: [PATCH 0768/5092] fix more indentation --- miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri b/miri index effbd023f198..a5f7271b246e 100755 --- a/miri +++ b/miri @@ -37,7 +37,7 @@ find_sysroot() { true fi else - # We have to build a sysroot either way. + # A normal toolchain. We have to build a sysroot either way. if [ -n "$MIRI_TEST_TARGET" ]; then build_sysroot --target "$MIRI_TEST_TARGET" else From 8b219a132902262db3285ed0cd57cb3bce8259a4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 May 2019 18:50:32 +0200 Subject: [PATCH 0769/5092] fix for latest rustc --- rust-version | 2 +- src/operator.rs | 10 +++++----- src/stacked_borrows.rs | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/rust-version b/rust-version index 3c8fa005c32d..41821bcd73b7 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d35181ad8785fa958e43580a29a982afe02c728f +1a56ec4dae92538ab6e0ecf993c61f3b50ed77cf diff --git a/src/operator.rs b/src/operator.rs index 386fc4307b87..528da92c20f0 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -158,8 +158,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Dead allocations in miri cannot overlap with live allocations, but // on read hardware this can easily happen. Thus for comparisons we require // both pointers to be live. - self.memory().check_bounds_ptr(left, InboundsCheck::Live)?; - self.memory().check_bounds_ptr(right, InboundsCheck::Live)?; + self.memory().check_bounds_ptr(left, InboundsCheck::Live, CheckInAllocMsg::InboundsTest)?; + self.memory().check_bounds_ptr(right, InboundsCheck::Live, CheckInAllocMsg::InboundsTest)?; // Two in-bounds pointers, we can compare across allocations. left == right } @@ -183,7 +183,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' if bits < 32 { // Test if the ptr is in-bounds. Then it cannot be NULL. // Even dangling pointers cannot be NULL. - if self.memory().check_bounds_ptr(ptr, InboundsCheck::MaybeDead).is_ok() { + if self.memory().check_bounds_ptr(ptr, InboundsCheck::MaybeDead, CheckInAllocMsg::NullPointerTest).is_ok() { return Ok(false); } } @@ -340,9 +340,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' if let Scalar::Ptr(ptr) = ptr { // Both old and new pointer must be in-bounds of a *live* allocation. // (Of the same allocation, but that part is trivial with our representation.) - self.memory().check_bounds_ptr(ptr, InboundsCheck::Live)?; + self.memory().check_bounds_ptr(ptr, InboundsCheck::Live, CheckInAllocMsg::InboundsTest)?; let ptr = ptr.signed_offset(offset, self)?; - self.memory().check_bounds_ptr(ptr, InboundsCheck::Live)?; + self.memory().check_bounds_ptr(ptr, InboundsCheck::Live, CheckInAllocMsg::InboundsTest)?; Ok(Scalar::Ptr(ptr)) } else { // An integer pointer. They can only be offset by 0, and we pretend there diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index f997e6316435..8c46f7e1b2e9 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -10,7 +10,7 @@ use rustc::mir::RetagKind; use crate::{ EvalResult, InterpError, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, - MemoryKind, MiriMemoryKind, RangeMap, Allocation, AllocationExtra, + MemoryKind, MiriMemoryKind, RangeMap, Allocation, AllocationExtra, CheckInAllocMsg, Pointer, Immediate, ImmTy, PlaceTy, MPlaceTy, }; @@ -550,7 +550,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // Get the allocation. It might not be mutable, so we cannot use `get_mut`. let alloc = this.memory().get(ptr.alloc_id)?; - alloc.check_bounds(this, ptr, size)?; + alloc.check_bounds(this, ptr, size, CheckInAllocMsg::InboundsTest)?; // Update the stacks. // Make sure that raw pointers and mutable shared references are reborrowed "weak": // There could be existing unique pointers reborrowed from them that should remain valid! From f10ab1991cc550dc0c5b5f636db535a0e4d1e21f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 May 2019 19:37:31 +0200 Subject: [PATCH 0770/5092] fix error pattern --- tests/compile-fail/out_of_bounds_ptr_1.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile-fail/out_of_bounds_ptr_1.rs b/tests/compile-fail/out_of_bounds_ptr_1.rs index ce1c89a2a008..b46609305368 100644 --- a/tests/compile-fail/out_of_bounds_ptr_1.rs +++ b/tests/compile-fail/out_of_bounds_ptr_1.rs @@ -1,4 +1,4 @@ -// error-pattern: must be in-bounds and live at offset 5, but is outside bounds of allocation +// error-pattern: must be in-bounds at offset 5, but is outside bounds of allocation fn main() { let v = [0i8; 4]; let x = &v as *const i8; From ed0c6e833604364c8c7d454bdb66ed6a9c620ee6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 28 May 2019 19:01:43 +0200 Subject: [PATCH 0771/5092] miri build script: support building miri in debug mode --- miri | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 11 deletions(-) diff --git a/miri b/miri index a5f7271b246e..f12a49afe474 100755 --- a/miri +++ b/miri @@ -1,4 +1,36 @@ #!/bin/sh +## Usage +# +# COMMANDS +# +# ./miri install : +# Installs the miri driver and cargo-miri. are passed to `cargo +# install`. Sets up the rpath such that the installed binary should work in any +# working directory. +# +# ./miri build : +# Just build miri. are passed to `cargo build`. +# +# ./miri test : +# Build miri, set up a sysroot and then run the test suite. are passed +# to the final `cargo test` invocation. +# +# ./miri run : +# Build miri, set up a sysroot and then run the driver with the given . +# +# All commands also exist in a "-debug" variant (e.g. "./miri run-debug +# ") which uses debug builds instead of release builds, for faster build +# times and slower execution times. +# +# ENVIRONMENT VARIABLES +# +# MIRI_SYSROOT: +# If already set, the "sysroot setup" step is skipped. +# +# CARGO_EXTRA_FLAGS: +# Pass extra flags to all cargo invocations. + +## Preparation set -e # I'd love to use `jq` for parsing the JSON properly, but macOS is totally underequipped for this kind of work. TARGET=$(rustc --print target-spec-json -Z unstable-options | grep llvm-target | cut -d '"' -f 4) @@ -13,9 +45,9 @@ export RUSTFLAGS="-C link-args=-Wl,-rpath,$SYSROOT/lib/rustlib/$TARGET/lib -C de # Build a sysroot and set MIRI_SYSROOT to use it. Arguments are passed to `cargo miri setup`. build_sysroot() { # Build once, for the user to see. - cargo run --release --bin cargo-miri -- miri setup "$@" + cargo run $CARGO_BUILD_FLAGS --bin cargo-miri -- miri setup "$@" # Call again, to just set env var. - eval $(cargo run --release -q --bin cargo-miri -- miri setup --env "$@") + eval $(cargo run $CARGO_BUILD_FLAGS -q --bin cargo-miri -- miri setup --env "$@") export MIRI_SYSROOT } @@ -48,23 +80,44 @@ find_sysroot() { ## Main +# Determine command. COMMAND="$1" shift +# Determine flags passed to all cargo invocations. case "$COMMAND" in -install) +*-debug) + CARGO_INSTALL_FLAGS="--debug $CARGO_EXTRA_FLAGS" + CARGO_BUILD_FLAGS="$CARGO_EXTRA_FLAGS" + ;; +*) + CARGO_INSTALL_FLAGS="$CARGO_EXTRA_FLAGS" + CARGO_BUILD_FLAGS="--release $CARGO_EXTRA_FLAGS" + ;; +esac + +# Run command. +case "$COMMAND" in +install|install-debug) # "--locked" to respect the Cargo.lock file if it exists, # "--offline" to avoid querying the registry (for yanked packages). - exec cargo "$COMMAND" --path "$(dirname "$0")" --force --locked --offline "$@" + exec cargo install --path "$(dirname "$0")" --force --locked --offline "$@" ;; -build) +build|build-debug) # Build, and let caller control flags. - exec cargo "$COMMAND" --release "$@" + exec cargo build $CARGO_BUILD_FLAGS "$@" ;; -test|run) - # In "run" mode, scan for "--target" to set the "MIRI_TEST_TARGET" env var so +test|test-debug) + # First build and get a sysroot. + cargo build $CARGO_BUILD_FLAGS + find_sysroot + # Then test, and let caller control flags. + exec cargo test $CARGO_BUILD_FLAGS "$@" + ;; +run|run-debug) + # Scan for "--target" to set the "MIRI_TEST_TARGET" env var so # that we set the MIRI_SYSROOT up the right way. - if [ "$COMMAND" = "run" ] && [ -z "$MIRI_TEST_TARGET" ]; then + if [ -z "$MIRI_TEST_TARGET" ]; then for ARG in "$@"; do if [ "$LAST_ARG" = "--target" ]; then # Found it! @@ -75,9 +128,9 @@ test|run) done fi # First build and get a sysroot. - cargo build --release + cargo build $CARGO_BUILD_FLAGS find_sysroot # Then run the actual command. - exec cargo "$COMMAND" --release "$@" + exec cargo run $CARGO_BUILD_FLAGS "$@" ;; esac From 328ecd1abf4ca75499d2ed6b450c4ebf1535a6da Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 28 May 2019 19:02:54 +0200 Subject: [PATCH 0772/5092] avoid rebuilding Miri on CI --- travis.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/travis.sh b/travis.sh index 4df12613fb83..c06dbaee3638 100755 --- a/travis.sh +++ b/travis.sh @@ -7,10 +7,11 @@ if [ "$TRAVIS_OS_NAME" == osx ]; then else FOREIGN_TARGET=i686-unknown-linux-gnu fi +export CARGO_EXTRA_FLAGS="--all-features" # Prepare echo "Build and install miri" -./miri build --all-features --all-targets +./miri build --all-targets ./miri install echo From d55d04780cbf966537c3f1d6e33b133a5319eeb8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 28 May 2019 19:04:31 +0200 Subject: [PATCH 0773/5092] reference cargo issue --- miri | 2 ++ 1 file changed, 2 insertions(+) diff --git a/miri b/miri index f12a49afe474..99b64b62028a 100755 --- a/miri +++ b/miri @@ -85,6 +85,8 @@ COMMAND="$1" shift # Determine flags passed to all cargo invocations. +# This is a bit more annoying that one would hope due to +# . case "$COMMAND" in *-debug) CARGO_INSTALL_FLAGS="--debug $CARGO_EXTRA_FLAGS" From bf9f26401f8a41880203918ffbbfcac4ae5f16ac Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 28 May 2019 19:20:01 +0200 Subject: [PATCH 0774/5092] also pass flags to install --- miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri b/miri index 99b64b62028a..64466951e982 100755 --- a/miri +++ b/miri @@ -103,7 +103,7 @@ case "$COMMAND" in install|install-debug) # "--locked" to respect the Cargo.lock file if it exists, # "--offline" to avoid querying the registry (for yanked packages). - exec cargo install --path "$(dirname "$0")" --force --locked --offline "$@" + exec cargo install $CARGO_INSTALL_FLAGS --path "$(dirname "$0")" --force --locked --offline "$@" ;; build|build-debug) # Build, and let caller control flags. From 7a7b853120f84c90702802b96cfdb243a08d4cc0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 May 2019 14:43:34 +0200 Subject: [PATCH 0775/5092] adjust for rustc changes --- src/fn_call.rs | 5 +++-- src/operator.rs | 22 ++++++++++------------ 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 3ff0c1eb18a0..dc43c6524096 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -607,11 +607,12 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' // Extract the function type out of the signature (that seems easier than constructing it ourselves). let dtor = match this.read_scalar(args[1])?.not_undef()? { Scalar::Ptr(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr)?), - Scalar::Bits { bits: 0, size } => { + Scalar::Raw { data: 0, size } => { + // NULL pointer assert_eq!(size as u64, this.memory().pointer_size().bytes()); None }, - Scalar::Bits { .. } => return err!(ReadBytesAsPointer), + Scalar::Raw { .. } => return err!(ReadBytesAsPointer), }; // Figure out how large a pthread TLS key actually is. diff --git a/src/operator.rs b/src/operator.rs index 528da92c20f0..28d0d7c96095 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -141,7 +141,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' ) -> EvalResult<'tcx, bool> { let size = self.pointer_size(); Ok(match (left, right) { - (Scalar::Bits { .. }, Scalar::Bits { .. }) => + (Scalar::Raw { .. }, Scalar::Raw { .. }) => left.to_bits(size)? == right.to_bits(size)?, (Scalar::Ptr(left), Scalar::Ptr(right)) => { // Comparison illegal if one of them is out-of-bounds, *unless* they @@ -165,10 +165,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } } // Comparing ptr and integer. - (Scalar::Ptr(ptr), Scalar::Bits { bits, size }) | - (Scalar::Bits { bits, size }, Scalar::Ptr(ptr)) => { + (Scalar::Ptr(ptr), Scalar::Raw { data, size }) | + (Scalar::Raw { data, size }, Scalar::Ptr(ptr)) => { assert_eq!(size as u64, self.pointer_size().bytes()); - let bits = bits as u64; + let bits = data as u64; // Case I: Comparing real pointers with "small" integers. // Really we should only do this for NULL, but pragmatically speaking on non-bare-metal systems, @@ -262,7 +262,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Truncate (shift left to drop out leftover values, shift right to fill with zeroes). (value << shift) >> shift }; - let ptr_size = self.memory().pointer_size().bytes() as u8; + let ptr_size = self.memory().pointer_size(); trace!("ptr BitAnd, align {}, operand {:#010x}, base_mask {:#010x}", ptr_base_align, right, base_mask); if right & base_mask == base_mask { @@ -278,7 +278,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' ) } else if right & base_mask == 0 { // Case 2: the base address bits are all taken away, i.e., right is all-0 there. - (Scalar::Bits { bits: (left.offset.bytes() as u128) & right, size: ptr_size }, false) + let v = Scalar::from_uint((left.offset.bytes() as u128) & right, ptr_size); + (v, false) } else { return err!(ReadPointerAsBytes); } @@ -289,18 +290,15 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // (Intuition: modulo a divisor leaks less information.) let ptr_base_align = self.memory().get(left.alloc_id)?.align.bytes(); let right = right as u64; - let ptr_size = self.memory().pointer_size().bytes() as u8; + let ptr_size = self.memory().pointer_size(); if right == 1 { // Modulo 1 is always 0. - (Scalar::Bits { bits: 0, size: ptr_size }, false) + (Scalar::from_uint(0u32, ptr_size), false) } else if ptr_base_align % right == 0 { // The base address would be cancelled out by the modulo operation, so we can // just take the modulo of the offset. ( - Scalar::Bits { - bits: (left.offset.bytes() % right) as u128, - size: ptr_size - }, + Scalar::from_uint((left.offset.bytes() % right) as u128, ptr_size), false, ) } else { From 381c2897b065472d0a0fe7ee9f200e38fc2ca3ec Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 May 2019 14:47:37 +0200 Subject: [PATCH 0776/5092] test for pointer wrapping ICE --- tests/run-pass/ptr_arith_offset_overflow.rs | 13 ++++++++----- tests/run-pass/ptr_int_casts.rs | 7 +++++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/tests/run-pass/ptr_arith_offset_overflow.rs b/tests/run-pass/ptr_arith_offset_overflow.rs index 6b778248be5c..56fd448b0cc2 100644 --- a/tests/run-pass/ptr_arith_offset_overflow.rs +++ b/tests/run-pass/ptr_arith_offset_overflow.rs @@ -1,9 +1,12 @@ +use std::ptr; + fn main() { let v = [1i16, 2]; - let x = v.as_ptr().wrapping_offset(1); // ptr to the 2nd element + let x = &mut ptr::null(); // going through memory as there are more sanity checks along that path + *x = v.as_ptr().wrapping_offset(1); // ptr to the 2nd element // Adding 2*isize::max and then 1 is like substracting 1 - let x = x.wrapping_offset(isize::max_value()); - let x = x.wrapping_offset(isize::max_value()); - let x = x.wrapping_offset(1); - assert_eq!(unsafe { *x }, 1); + *x = x.wrapping_offset(isize::max_value()); + *x = x.wrapping_offset(isize::max_value()); + *x = x.wrapping_offset(1); + assert_eq!(unsafe { **x }, 1); } diff --git a/tests/run-pass/ptr_int_casts.rs b/tests/run-pass/ptr_int_casts.rs index b1b06263056d..c279024f35ea 100644 --- a/tests/run-pass/ptr_int_casts.rs +++ b/tests/run-pass/ptr_int_casts.rs @@ -1,4 +1,5 @@ use std::mem; +use std::ptr; fn eq_ref(x: &T, y: &T) -> bool { x as *const _ == y as *const _ @@ -11,6 +12,12 @@ fn main() { assert_eq!(1 as *const i32 as usize, 1); assert_eq!((1 as *const i32).wrapping_offset(4) as usize, 1 + 4*4); + // negative overflowing wrapping_offset (going through memory because + // this used to trigger an ICE on 32bit) + let val = &mut ptr::null(); + *val = (1 as *const u8).wrapping_offset(-4); + assert_eq!(*val as usize, usize::max_value() - 2); + { // ptr-int-ptr let x = 13; let mut y = &x as &_ as *const _ as usize; From b62ddc2cff25d9ca29ee5dd5776b89413ee580eb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 28 May 2019 22:47:22 +0200 Subject: [PATCH 0777/5092] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 41821bcd73b7..0af97e2a284c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1a56ec4dae92538ab6e0ecf993c61f3b50ed77cf +721268583759224d0f6476e0b8b196cc8afbdea0 From e4cee77121d8ad3c547a67b6c8cff88e38183ec1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 May 2019 09:30:36 +0200 Subject: [PATCH 0778/5092] fix for rustc changes --- rust-version | 2 +- src/fn_call.rs | 2 +- src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 0af97e2a284c..7695b069436f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -721268583759224d0f6476e0b8b196cc8afbdea0 +4b9d80325a65b0375eea526409a0f3aaf1cbc23c diff --git a/src/fn_call.rs b/src/fn_call.rs index dc43c6524096..17679e26790c 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -17,7 +17,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' args: &[OpTy<'tcx, Tag>], dest: Option>, ret: Option, - ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> { + ) -> EvalResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); trace!("eval_fn_call: {:#?}, {:?}", instance, dest.map(|place| *place)); diff --git a/src/lib.rs b/src/lib.rs index a12493fbfbd6..89d7964913ae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -407,7 +407,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { args: &[OpTy<'tcx, Tag>], dest: Option>, ret: Option, - ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> { + ) -> EvalResult<'tcx, Option<&'mir mir::Body<'tcx>>> { ecx.find_fn(instance, args, dest, ret) } From 35b4d9fd8ac260bdfee5204ec2590420ca0782b2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 May 2019 09:36:59 +0200 Subject: [PATCH 0779/5092] print usage information on invalid command --- miri | 68 +++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/miri b/miri index 64466951e982..d683a0853008 100755 --- a/miri +++ b/miri @@ -1,37 +1,38 @@ #!/bin/sh -## Usage -# -# COMMANDS -# -# ./miri install : -# Installs the miri driver and cargo-miri. are passed to `cargo -# install`. Sets up the rpath such that the installed binary should work in any -# working directory. -# -# ./miri build : -# Just build miri. are passed to `cargo build`. -# -# ./miri test : -# Build miri, set up a sysroot and then run the test suite. are passed -# to the final `cargo test` invocation. -# -# ./miri run : -# Build miri, set up a sysroot and then run the driver with the given . -# -# All commands also exist in a "-debug" variant (e.g. "./miri run-debug -# ") which uses debug builds instead of release builds, for faster build -# times and slower execution times. -# -# ENVIRONMENT VARIABLES -# -# MIRI_SYSROOT: -# If already set, the "sysroot setup" step is skipped. -# -# CARGO_EXTRA_FLAGS: -# Pass extra flags to all cargo invocations. +set -e +USAGE=$(cat <<"EOF" + COMMANDS + +./miri install : +Installs the miri driver and cargo-miri. are passed to `cargo +install`. Sets up the rpath such that the installed binary should work in any +working directory. + +./miri build : +Just build miri. are passed to `cargo build`. + +./miri test : +Build miri, set up a sysroot and then run the test suite. are passed +to the final `cargo test` invocation. + +./miri run : +Build miri, set up a sysroot and then run the driver with the given . + +All commands also exist in a "-debug" variant (e.g. "./miri run-debug +") which uses debug builds instead of release builds, for faster build +times and slower execution times. + + ENVIRONMENT VARIABLES + +MIRI_SYSROOT: +If already set, the "sysroot setup" step is skipped. + +CARGO_EXTRA_FLAGS: +Pass extra flags to all cargo invocations. +EOF +) ## Preparation -set -e # I'd love to use `jq` for parsing the JSON properly, but macOS is totally underequipped for this kind of work. TARGET=$(rustc --print target-spec-json -Z unstable-options | grep llvm-target | cut -d '"' -f 4) SYSROOT=$(rustc --print sysroot) @@ -135,4 +136,9 @@ run|run-debug) # Then run the actual command. exec cargo run $CARGO_BUILD_FLAGS "$@" ;; +*) + echo "Unknown command: $COMMAND" + echo + echo "$USAGE" + exit 1 esac From 16cc5ddacbde23a71d05535f6b51298d295535df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 May 2019 09:39:49 +0200 Subject: [PATCH 0780/5092] tweak logic for determining rustc default target --- miri | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/miri b/miri index d683a0853008..2181403b7bde 100755 --- a/miri +++ b/miri @@ -33,13 +33,19 @@ EOF ) ## Preparation -# I'd love to use `jq` for parsing the JSON properly, but macOS is totally underequipped for this kind of work. -TARGET=$(rustc --print target-spec-json -Z unstable-options | grep llvm-target | cut -d '"' -f 4) +TARGET=$(rustc --version --verbose | grep "^host:" | cut -d ' ' -f 2) SYSROOT=$(rustc --print sysroot) +LIBDIR=$SYSROOT/lib/rustlib/$TARGET/lib +if ! test -d "$LIBDIR"; then + echo "Something went wrong determining the library dir." + echo "I got $LIBDIR but that does not exist." + echo "Please report a bug at https://github.com/rust-lang/miri/issues." + exit 2 +fi # We set the rpath so that Miri finds the private rustc libraries it needs. # We enable debug-assertions to get tracing. # We enable line-only debuginfo for backtraces. -export RUSTFLAGS="-C link-args=-Wl,-rpath,$SYSROOT/lib/rustlib/$TARGET/lib -C debug-assertions -C debuginfo=1" +export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR -C debug-assertions -C debuginfo=1" ## Helper functions From 65a93eb3ee0ad5ded12666370029dbaca7c5e1ad Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 May 2019 12:54:19 +0200 Subject: [PATCH 0781/5092] try to make the Windows CI not rebuild Miri --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 438a65880b87..d13ce2b3974d 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -33,7 +33,7 @@ build_script: - set RUSTFLAGS=-C debug-assertions # Build and install miri - cargo build --release --all-features --all-targets - - cargo install --all-features --force --path . + - cargo install --all-features --force --path . --locked --offline # Get ourselves a MIR-full libstd, and use it henceforth - cargo miri setup - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\miri\miri\cache\HOST From 0dfc1c97c59361be750b0e15a181cd4d06712dd8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 May 2019 19:35:47 +0200 Subject: [PATCH 0782/5092] test weak_into_raw --- rust-version | 2 +- tests/compile-fail/rc_as_raw.rs | 19 +++++++++++++++++ tests/run-pass/rc.rs | 38 ++++++++++++++++++++++++++++++++- 3 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 tests/compile-fail/rc_as_raw.rs diff --git a/rust-version b/rust-version index 7695b069436f..d93fb8b6950e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4b9d80325a65b0375eea526409a0f3aaf1cbc23c +81970852e172c04322cbf8ba23effabeb491c83c diff --git a/tests/compile-fail/rc_as_raw.rs b/tests/compile-fail/rc_as_raw.rs new file mode 100644 index 000000000000..3e6e96456fca --- /dev/null +++ b/tests/compile-fail/rc_as_raw.rs @@ -0,0 +1,19 @@ +#![feature(weak_into_raw)] + +use std::rc::{Rc, Weak}; +use std::ptr; + +/// Taken from the `Weak::as_raw` doctest. +fn main() { + let strong = Rc::new(Box::new(42)); + let weak = Rc::downgrade(&strong); + // Both point to the same object + assert!(ptr::eq(&*strong, Weak::as_raw(&weak))); + // The strong here keeps it alive, so we can still access the object. + assert_eq!(42, **unsafe { &*Weak::as_raw(&weak) }); + + drop(strong); + // But not any more. We can do Weak::as_raw(&weak), but accessing the pointer would lead to + // undefined behaviour. + assert_eq!(42, **unsafe { &*Weak::as_raw(&weak) }); //~ ERROR dangling pointer +} diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index 164842ab4d97..9b4d51ed376a 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -1,5 +1,7 @@ +#![feature(weak_into_raw)] + use std::cell::{Cell, RefCell}; -use std::rc::Rc; +use std::rc::{Rc, Weak}; use std::sync::Arc; use std::fmt::Debug; @@ -69,6 +71,37 @@ fn rc_fat_ptr_eq() { drop(unsafe { Rc::from_raw(r) }); } +/// Taken from the `Weak::into_raw` doctest. +fn weak_into_raw() { + let strong = Rc::new(42); + let weak = Rc::downgrade(&strong); + let raw = Weak::into_raw(weak); + + assert_eq!(1, Rc::weak_count(&strong)); + assert_eq!(42, unsafe { *raw }); + + drop(unsafe { Weak::from_raw(raw) }); + assert_eq!(0, Rc::weak_count(&strong)); +} + +/// Taken from the `Weak::from_raw` doctest. +fn weak_from_raw() { + let strong = Rc::new(42); + + let raw_1 = Weak::into_raw(Rc::downgrade(&strong)); + let raw_2 = Weak::into_raw(Rc::downgrade(&strong)); + + assert_eq!(2, Rc::weak_count(&strong)); + + assert_eq!(42, *Weak::upgrade(&unsafe { Weak::from_raw(raw_1) }).unwrap()); + assert_eq!(1, Rc::weak_count(&strong)); + + drop(strong); + + // Decrement the last weak count. + assert!(Weak::upgrade(&unsafe { Weak::from_raw(raw_2) }).is_none()); +} + fn main() { rc_fat_ptr_eq(); rc_refcell(); @@ -76,5 +109,8 @@ fn main() { rc_cell(); rc_raw(); rc_from(); + weak_into_raw(); + weak_from_raw(); + arc(); } From badbd57cee570f25ebf6b31ea4d596a162a87188 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 May 2019 10:58:30 +0200 Subject: [PATCH 0783/5092] update for rustc warning about missing dyn --- rust-version | 2 +- tests/run-pass/box_box_trait.rs | 6 +++--- tests/run-pass/call_drop_on_fat_ptr_array_elements.rs | 2 +- tests/run-pass/call_drop_through_trait_object.rs | 2 +- tests/run-pass/call_drop_through_trait_object_rc.rs | 2 +- tests/run-pass/cast-rfc0401-vtable-kinds.rs | 10 +++++----- tests/run-pass/dst-field-align.rs | 8 ++++---- tests/run-pass/dst-raw.rs | 8 ++++---- tests/run-pass/fn_item_as_closure_trait_object.rs | 2 +- .../fn_item_with_args_as_closure_trait_object.rs | 2 +- ..._item_with_multiple_args_as_closure_trait_object.rs | 4 ++-- tests/run-pass/fn_ptr_as_closure_trait_object.rs | 6 +++--- tests/run-pass/issue-20575.rs | 2 +- tests/run-pass/issue-23261.rs | 4 ++-- tests/run-pass/issue-26709.rs | 2 +- tests/run-pass/issue-30530.rs | 4 ++-- tests/run-pass/issue-33387.rs | 2 +- tests/run-pass/issue-35815.rs | 2 +- tests/run-pass/issue-3794.rs | 4 ++-- tests/run-pass/last-use-in-cap-clause.rs | 2 +- tests/run-pass/mir_coercions.rs | 10 +++++----- tests/run-pass/multi_arg_closure.rs | 2 +- tests/run-pass/non_capture_closure_to_fn_ptr.rs | 2 +- tests/run-pass/rc.rs | 4 ++-- tests/run-pass/regions-lifetime-nonfree-late-bound.rs | 8 ++++---- tests/run-pass/traits.rs | 8 ++++---- 26 files changed, 55 insertions(+), 55 deletions(-) diff --git a/rust-version b/rust-version index d93fb8b6950e..5504e77097b7 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -81970852e172c04322cbf8ba23effabeb491c83c +c28084ac16af4ab594b6860958df140e7c876a13 diff --git a/tests/run-pass/box_box_trait.rs b/tests/run-pass/box_box_trait.rs index 7fe568522d53..e7620cd42f70 100644 --- a/tests/run-pass/box_box_trait.rs +++ b/tests/run-pass/box_box_trait.rs @@ -14,10 +14,10 @@ trait MyTrait { fn dummy(&self) { } } impl MyTrait for Box {} #[allow(dead_code)] -struct Whatever { w: Box } +struct Whatever { w: Box } impl Whatever { - fn new(w: Box) -> Whatever { + fn new(w: Box) -> Whatever { Whatever { w: w } } } @@ -25,7 +25,7 @@ impl Whatever { fn main() { { let f: Box<_> = box DroppableStruct; - let _a = Whatever::new(box f as Box); + let _a = Whatever::new(box f as Box); } assert!(unsafe { DROPPED }); } diff --git a/tests/run-pass/call_drop_on_fat_ptr_array_elements.rs b/tests/run-pass/call_drop_on_fat_ptr_array_elements.rs index a1ab5c45e358..36162d320212 100644 --- a/tests/run-pass/call_drop_on_fat_ptr_array_elements.rs +++ b/tests/run-pass/call_drop_on_fat_ptr_array_elements.rs @@ -13,7 +13,7 @@ impl Drop for Bar { } fn main() { - let b: [Box; 4] = [Box::new(Bar), Box::new(Bar), Box::new(Bar), Box::new(Bar)]; + let b: [Box; 4] = [Box::new(Bar), Box::new(Bar), Box::new(Bar), Box::new(Bar)]; assert_eq!(unsafe { DROP_COUNT }, 0); drop(b); assert_eq!(unsafe { DROP_COUNT }, 4); diff --git a/tests/run-pass/call_drop_through_trait_object.rs b/tests/run-pass/call_drop_through_trait_object.rs index 9b6acf0b1474..97ba69c9fe28 100644 --- a/tests/run-pass/call_drop_through_trait_object.rs +++ b/tests/run-pass/call_drop_through_trait_object.rs @@ -13,7 +13,7 @@ impl Drop for Bar { impl Foo for Bar {} fn main() { - let b: Box = Box::new(Bar); + let b: Box = Box::new(Bar); assert!(unsafe { !DROP_CALLED }); drop(b); assert!(unsafe { DROP_CALLED }); diff --git a/tests/run-pass/call_drop_through_trait_object_rc.rs b/tests/run-pass/call_drop_through_trait_object_rc.rs index ce56ca6a1caf..172a4580dc10 100644 --- a/tests/run-pass/call_drop_through_trait_object_rc.rs +++ b/tests/run-pass/call_drop_through_trait_object_rc.rs @@ -15,7 +15,7 @@ impl Foo for Bar {} use std::rc::Rc; fn main() { - let b: Rc = Rc::new(Bar); + let b: Rc = Rc::new(Bar); assert!(unsafe { !DROP_CALLED }); drop(b); assert!(unsafe { DROP_CALLED }); diff --git a/tests/run-pass/cast-rfc0401-vtable-kinds.rs b/tests/run-pass/cast-rfc0401-vtable-kinds.rs index 6442eab30a13..544510be9bb0 100644 --- a/tests/run-pass/cast-rfc0401-vtable-kinds.rs +++ b/tests/run-pass/cast-rfc0401-vtable-kinds.rs @@ -13,9 +13,9 @@ impl Foo for () {} impl Foo for u32 { fn foo(&self, _: u32) -> u32 { self+43 } } impl Bar for () {} -unsafe fn round_trip_and_call<'a>(t: *const (Foo+'a)) -> u32 { - let foo_e : *const Foo = t as *const _; - let r_1 = foo_e as *mut Foo; +unsafe fn round_trip_and_call<'a>(t: *const (dyn Foo+'a)) -> u32 { + let foo_e : *const dyn Foo = t as *const _; + let r_1 = foo_e as *mut dyn Foo; (&*r_1).foo(0) } @@ -31,8 +31,8 @@ fn foo_to_bar(u: *const FooS) -> *const BarS { fn main() { let x = 4u32; - let y : &Foo = &x; - let fl = unsafe { round_trip_and_call(y as *const Foo) }; + let y : &dyn Foo = &x; + let fl = unsafe { round_trip_and_call(y as *const dyn Foo) }; assert_eq!(fl, (43+4)); let s = FooS([0,1,2]); diff --git a/tests/run-pass/dst-field-align.rs b/tests/run-pass/dst-field-align.rs index b8e9815640c2..7cd0c851b638 100644 --- a/tests/run-pass/dst-field-align.rs +++ b/tests/run-pass/dst-field-align.rs @@ -26,7 +26,7 @@ fn main() { // Test that zero-offset works properly let b : Baz = Baz { a: 7 }; assert_eq!(b.a.get(), 7); - let b : &Baz = &b; + let b : &Baz = &b; assert_eq!(b.a.get(), 7); // Test that the field is aligned properly @@ -34,7 +34,7 @@ fn main() { assert_eq!(f.b.get(), 11); let ptr1 : *const u8 = &f.b as *const _ as *const u8; - let f : &Foo = &f; + let f : &Foo = &f; let ptr2 : *const u8 = &f.b as *const _ as *const u8; assert_eq!(f.b.get(), 11); @@ -44,13 +44,13 @@ fn main() { // Test that nested DSTs work properly let f : Foo> = Foo { a: 0, b: Foo { a: 1, b: 17 }}; assert_eq!(f.b.b.get(), 17); - let f : &Foo> = &f; + let f : &Foo> = &f; assert_eq!(f.b.b.get(), 17); // Test that get the pointer via destructuring works let f : Foo = Foo { a: 0, b: 11 }; - let f : &Foo = &f; + let f : &Foo = &f; let &Foo { a: _, b: ref bar } = f; assert_eq!(bar.get(), 11); diff --git a/tests/run-pass/dst-raw.rs b/tests/run-pass/dst-raw.rs index a3ee982d19aa..0fe2b72b8c6a 100644 --- a/tests/run-pass/dst-raw.rs +++ b/tests/run-pass/dst-raw.rs @@ -21,7 +21,7 @@ struct Foo { pub fn main() { // raw trait object let x = A { f: 42 }; - let z: *const Trait = &x; + let z: *const dyn Trait = &x; let r = unsafe { (&*z).foo() }; @@ -29,7 +29,7 @@ pub fn main() { // raw DST struct let p = Foo {f: A { f: 42 }}; - let o: *const Foo = &p; + let o: *const Foo = &p; let r = unsafe { (&*o).f.foo() }; @@ -64,14 +64,14 @@ pub fn main() { // all of the above with *mut let mut x = A { f: 42 }; - let z: *mut Trait = &mut x; + let z: *mut dyn Trait = &mut x; let r = unsafe { (&*z).foo() }; assert_eq!(r, 42); let mut p = Foo {f: A { f: 42 }}; - let o: *mut Foo = &mut p; + let o: *mut Foo = &mut p; let r = unsafe { (&*o).f.foo() }; diff --git a/tests/run-pass/fn_item_as_closure_trait_object.rs b/tests/run-pass/fn_item_as_closure_trait_object.rs index 799f97a4f6fd..dcbbb5cb6a2c 100644 --- a/tests/run-pass/fn_item_as_closure_trait_object.rs +++ b/tests/run-pass/fn_item_as_closure_trait_object.rs @@ -1,6 +1,6 @@ fn foo() {} fn main() { - let f: &Fn() = &foo; + let f: &dyn Fn() = &foo; f(); } diff --git a/tests/run-pass/fn_item_with_args_as_closure_trait_object.rs b/tests/run-pass/fn_item_with_args_as_closure_trait_object.rs index 79ece75c773b..257028c4f0d8 100644 --- a/tests/run-pass/fn_item_with_args_as_closure_trait_object.rs +++ b/tests/run-pass/fn_item_with_args_as_closure_trait_object.rs @@ -3,6 +3,6 @@ fn foo(i: i32) { } fn main() { - let f: &Fn(i32) = &foo; + let f: &dyn Fn(i32) = &foo; f(42); } diff --git a/tests/run-pass/fn_item_with_multiple_args_as_closure_trait_object.rs b/tests/run-pass/fn_item_with_multiple_args_as_closure_trait_object.rs index f4b5b449aa58..98111f304c89 100644 --- a/tests/run-pass/fn_item_with_multiple_args_as_closure_trait_object.rs +++ b/tests/run-pass/fn_item_with_multiple_args_as_closure_trait_object.rs @@ -11,8 +11,8 @@ fn bar(i: i32, j: i32, k: f32) { fn main() { - let f: &Fn(i32, i32) = &foo; + let f: &dyn Fn(i32, i32) = &foo; f(42, 55); - let f: &Fn(i32, i32, f32) = &bar; + let f: &dyn Fn(i32, i32, f32) = &bar; f(42, 55, 3.14159); } diff --git a/tests/run-pass/fn_ptr_as_closure_trait_object.rs b/tests/run-pass/fn_ptr_as_closure_trait_object.rs index 24ae1f35bb60..89daed81507f 100644 --- a/tests/run-pass/fn_ptr_as_closure_trait_object.rs +++ b/tests/run-pass/fn_ptr_as_closure_trait_object.rs @@ -6,10 +6,10 @@ fn baa(u: u32, f: f32) { } fn main() { - let f: &Fn() = &(foo as fn()); + let f: &dyn Fn() = &(foo as fn()); f(); - let f: &Fn(u32) = &(bar as fn(u32)); + let f: &dyn Fn(u32) = &(bar as fn(u32)); f(42); - let f: &Fn(u32, f32) = &(baa as fn(u32, f32)); + let f: &dyn Fn(u32, f32) = &(baa as fn(u32, f32)); f(42, 3.141); } diff --git a/tests/run-pass/issue-20575.rs b/tests/run-pass/issue-20575.rs index 1443ec78fd75..19049b9add5c 100644 --- a/tests/run-pass/issue-20575.rs +++ b/tests/run-pass/issue-20575.rs @@ -1,7 +1,7 @@ // Test that overloaded calls work with zero arity closures fn main() { - let functions: [Box Option<()>>; 1] = [Box::new(|| None)]; + let functions: [Box Option<()>>; 1] = [Box::new(|| None)]; let _val: Option> = functions.iter().map(|f| (*f)()).collect(); } diff --git a/tests/run-pass/issue-23261.rs b/tests/run-pass/issue-23261.rs index 3e1aa295af1e..f3c2f58ddbca 100644 --- a/tests/run-pass/issue-23261.rs +++ b/tests/run-pass/issue-23261.rs @@ -40,7 +40,7 @@ fn check_both(val: &Foo<[u8]>) { } } -fn check_trait_obj(val: &Foo) { +fn check_trait_obj(val: &Foo) { match *val { Foo { a, ref inner } => { assert_eq!(a, 32); @@ -55,6 +55,6 @@ fn main() { check_dst_val(foo); check_both(foo); - let foo: &Foo = &Foo { a: 32, inner: 32 }; + let foo: &Foo = &Foo { a: 32, inner: 32 }; check_trait_obj(foo); } diff --git a/tests/run-pass/issue-26709.rs b/tests/run-pass/issue-26709.rs index a283d8743ccf..78f30e78db76 100644 --- a/tests/run-pass/issue-26709.rs +++ b/tests/run-pass/issue-26709.rs @@ -10,7 +10,7 @@ fn main() { let mut x = 0; { let wrapper = Box::new(Wrapper(&mut x, 123)); - let _val: Box> = wrapper; + let _val: Box> = wrapper; } assert_eq!(432, x) } diff --git a/tests/run-pass/issue-30530.rs b/tests/run-pass/issue-30530.rs index d5139c908bda..10dec30c64ca 100644 --- a/tests/run-pass/issue-30530.rs +++ b/tests/run-pass/issue-30530.rs @@ -17,7 +17,7 @@ pub enum Handler { Default, #[allow(dead_code)] - Custom(*mut Box), + Custom(*mut Box), } fn main() { @@ -25,7 +25,7 @@ fn main() { } #[inline(never)] -pub fn take(h: Handler, f: Box) -> Box { +pub fn take(h: Handler, f: Box) -> Box { unsafe { match h { Handler::Custom(ptr) => *Box::from_raw(ptr), diff --git a/tests/run-pass/issue-33387.rs b/tests/run-pass/issue-33387.rs index 2335f9c1b941..36b58c642d7d 100644 --- a/tests/run-pass/issue-33387.rs +++ b/tests/run-pass/issue-33387.rs @@ -5,5 +5,5 @@ trait Foo {} impl Foo for [u8; 2] {} fn main() { - let _val: Arc = Arc::new([3, 4]); + let _val: Arc = Arc::new([3, 4]); } diff --git a/tests/run-pass/issue-35815.rs b/tests/run-pass/issue-35815.rs index e17c37f92a50..fb0bd8e202ff 100644 --- a/tests/run-pass/issue-35815.rs +++ b/tests/run-pass/issue-35815.rs @@ -10,6 +10,6 @@ struct Foo { fn main() { let foo: &Foo = &Foo { a: 1, b: false, c: 2i32 }; - let foo_unsized: &Foo = foo; + let foo_unsized: &Foo = foo; assert_eq!(mem::size_of_val(foo), mem::size_of_val(foo_unsized)); } diff --git a/tests/run-pass/issue-3794.rs b/tests/run-pass/issue-3794.rs index 9161fefef30c..fb1c19b04e99 100644 --- a/tests/run-pass/issue-3794.rs +++ b/tests/run-pass/issue-3794.rs @@ -15,7 +15,7 @@ impl T for S { } } -fn print_t(t: &T) { +fn print_t(t: &dyn T) { t.print(); } @@ -26,6 +26,6 @@ fn print_s(s: &S) { pub fn main() { let s: Box = box S { s: 5 }; print_s(&*s); - let t: Box = s as Box; + let t: Box = s as Box; print_t(&*t); } diff --git a/tests/run-pass/last-use-in-cap-clause.rs b/tests/run-pass/last-use-in-cap-clause.rs index f75f00b87fd4..9d137f706bd3 100644 --- a/tests/run-pass/last-use-in-cap-clause.rs +++ b/tests/run-pass/last-use-in-cap-clause.rs @@ -3,7 +3,7 @@ #[allow(dead_code)] struct A { a: Box } -fn foo() -> Box isize + 'static> { +fn foo() -> Box isize + 'static> { let k: Box<_> = Box::new(22); let _u = A {a: k.clone()}; let result = || 22; diff --git a/tests/run-pass/mir_coercions.rs b/tests/run-pass/mir_coercions.rs index f3d8e519d23e..bfc821f799ee 100644 --- a/tests/run-pass/mir_coercions.rs +++ b/tests/run-pass/mir_coercions.rs @@ -3,12 +3,12 @@ use std::ops::CoerceUnsized; use std::marker::Unsize; -fn identity_coercion(x: &(Fn(u32)->u32 + Send)) -> &Fn(u32)->u32 { +fn identity_coercion(x: &(dyn Fn(u32)->u32 + Send)) -> &dyn Fn(u32)->u32 { x } fn fn_coercions(f: &fn(u32) -> u32) -> (unsafe fn(u32) -> u32, - &(Fn(u32) -> u32+Send)) + &(dyn Fn(u32) -> u32 + Send)) { (*f, f) } @@ -34,8 +34,8 @@ fn coerce_triv_ptr_wrapper(p: TrivPtrWrapper<[u8; 3]>) -> TrivPtrWrapper<[u8]> { p } -fn coerce_fat_ptr_wrapper(p: PtrWrapper u32+Send>) - -> PtrWrapper u32> { +fn coerce_fat_ptr_wrapper(p: PtrWrapper u32 + Send>) + -> PtrWrapper u32> { p } @@ -67,7 +67,7 @@ fn main() { let z = coerce_fat_ptr_wrapper(PtrWrapper(2,3,(),&square_local)); assert_eq!((z.3)(6), 36); - let z: PtrWrapper u32> = + let z: PtrWrapper u32> = coerce_ptr_wrapper_poly(PtrWrapper(2,3,(),&square_local)); assert_eq!((z.3)(6), 36); } diff --git a/tests/run-pass/multi_arg_closure.rs b/tests/run-pass/multi_arg_closure.rs index 30cfb5b685b2..02d53540b83c 100644 --- a/tests/run-pass/multi_arg_closure.rs +++ b/tests/run-pass/multi_arg_closure.rs @@ -1,4 +1,4 @@ -fn foo(f: &mut FnMut(isize, isize) -> isize) -> isize { +fn foo(f: &mut dyn FnMut(isize, isize) -> isize) -> isize { f(1, 2) } diff --git a/tests/run-pass/non_capture_closure_to_fn_ptr.rs b/tests/run-pass/non_capture_closure_to_fn_ptr.rs index d48c4df45944..e6a5017847d4 100644 --- a/tests/run-pass/non_capture_closure_to_fn_ptr.rs +++ b/tests/run-pass/non_capture_closure_to_fn_ptr.rs @@ -12,7 +12,7 @@ fn main() { BAR(44, 45); let bar: unsafe fn(i32, i32) = BAR; unsafe { bar(46, 47) }; - let boo: &Fn(i32, i32) = &BAR; + let boo: &dyn Fn(i32, i32) = &BAR; boo(48, 49); let f = magic(||{}) as fn(); diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index 9b4d51ed376a..d731fe8fd4c3 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -64,8 +64,8 @@ fn rc_from() { } fn rc_fat_ptr_eq() { - let p = Rc::new(1) as Rc; - let a: *const Debug = &*p; + let p = Rc::new(1) as Rc; + let a: *const dyn Debug = &*p; let r = Rc::into_raw(p); assert!(a == r); drop(unsafe { Rc::from_raw(r) }); diff --git a/tests/run-pass/regions-lifetime-nonfree-late-bound.rs b/tests/run-pass/regions-lifetime-nonfree-late-bound.rs index 85a189007c3d..78aeea64814a 100644 --- a/tests/run-pass/regions-lifetime-nonfree-late-bound.rs +++ b/tests/run-pass/regions-lifetime-nonfree-late-bound.rs @@ -16,15 +16,15 @@ pub fn main() { fn explicit() { - fn test(_x: Option>) where F: FnMut(Box FnMut(&'a isize)>) {} - test(Some(box |_f: Box FnMut(&'a isize)>| {})); + fn test(_x: Option>) where F: FnMut(Box FnMut(&'a isize)>) {} + test(Some(box |_f: Box FnMut(&'a isize)>| {})); } // The code below is shorthand for the code above (and more likely // to represent what one encounters in practice). fn implicit() { - fn test(_x: Option>) where F: FnMut(Box< FnMut(& isize)>) {} - test(Some(box |_f: Box< FnMut(& isize)>| {})); + fn test(_x: Option>) where F: FnMut(Box) {} + test(Some(box |_f: Box| {})); } explicit(); diff --git a/tests/run-pass/traits.rs b/tests/run-pass/traits.rs index b2eae5d04f41..03d2db400f01 100644 --- a/tests/run-pass/traits.rs +++ b/tests/run-pass/traits.rs @@ -13,17 +13,17 @@ impl Trait for Struct { struct Foo(T); fn main() { - let y: &Trait = &Struct(42); + let y: &dyn Trait = &Struct(42); y.method(); let x: Foo = Foo(Struct(42)); - let y: &Foo = &x; + let y: &Foo = &x; y.0.method(); - let x: Box i32> = Box::new(|x| x * 2); + let x: Box i32> = Box::new(|x| x * 2); assert_eq!(x(21), 42); let mut i = 5; { - let mut x: Box = Box::new(|| i *= 2); + let mut x: Box = Box::new(|| i *= 2); x(); x(); } assert_eq!(i, 20); From c748323eb39ea10d63368a37a4f72260b9703702 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 May 2019 11:01:22 +0200 Subject: [PATCH 0784/5092] move fn_item/ptr tests to closures file --- tests/run-pass/closures.rs | 52 +++++++++++++++++++ .../fn_item_as_closure_trait_object.rs | 6 --- ..._item_with_args_as_closure_trait_object.rs | 8 --- ...h_multiple_args_as_closure_trait_object.rs | 18 ------- .../fn_ptr_as_closure_trait_object.rs | 15 ------ 5 files changed, 52 insertions(+), 47 deletions(-) delete mode 100644 tests/run-pass/fn_item_as_closure_trait_object.rs delete mode 100644 tests/run-pass/fn_item_with_args_as_closure_trait_object.rs delete mode 100644 tests/run-pass/fn_item_with_multiple_args_as_closure_trait_object.rs delete mode 100644 tests/run-pass/fn_ptr_as_closure_trait_object.rs diff --git a/tests/run-pass/closures.rs b/tests/run-pass/closures.rs index 141e6cd6d08a..eb8d8f0d5b98 100644 --- a/tests/run-pass/closures.rs +++ b/tests/run-pass/closures.rs @@ -44,10 +44,62 @@ fn boxed(f: Box i32>) -> i32 { f() } +fn fn_item_as_closure_trait_object() { + fn foo() {} + let f: &dyn Fn() = &foo; + f(); +} + +fn fn_item_with_args_as_closure_trait_object() { + fn foo(i: i32) { + assert_eq!(i, 42); + } + let f: &dyn Fn(i32) = &foo; + f(42); +} + +fn fn_item_with_multiple_args_as_closure_trait_object() { + fn foo(i: i32, j: i32) { + assert_eq!(i, 42); + assert_eq!(j, 55); + } + + fn bar(i: i32, j: i32, k: f32) { + assert_eq!(i, 42); + assert_eq!(j, 55); + assert_eq!(k, 3.14159) + } + let f: &dyn Fn(i32, i32) = &foo; + f(42, 55); + let f: &dyn Fn(i32, i32, f32) = &bar; + f(42, 55, 3.14159); +} + +fn fn_ptr_as_closure_trait_object() { + fn foo() {} + fn bar(u: u32) { assert_eq!(u, 42); } + fn baa(u: u32, f: f32) { + assert_eq!(u, 42); + assert_eq!(f, 3.141); + } + let f: &dyn Fn() = &(foo as fn()); + f(); + let f: &dyn Fn(u32) = &(bar as fn(u32)); + f(42); + let f: &dyn Fn(u32, f32) = &(baa as fn(u32, f32)); + f(42, 3.141); +} + + fn main() { assert_eq!(simple(), 12); assert_eq!(crazy_closure(), (84, 10, 10)); assert_eq!(closure_arg_adjustment_problem(), 3); assert_eq!(fn_once_closure_with_multiple_args(), 6); assert_eq!(boxed(Box::new({let x = 13; move || x})), 13); + + fn_item_as_closure_trait_object(); + fn_item_with_args_as_closure_trait_object(); + fn_item_with_multiple_args_as_closure_trait_object(); + fn_ptr_as_closure_trait_object(); } diff --git a/tests/run-pass/fn_item_as_closure_trait_object.rs b/tests/run-pass/fn_item_as_closure_trait_object.rs deleted file mode 100644 index dcbbb5cb6a2c..000000000000 --- a/tests/run-pass/fn_item_as_closure_trait_object.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn foo() {} - -fn main() { - let f: &dyn Fn() = &foo; - f(); -} diff --git a/tests/run-pass/fn_item_with_args_as_closure_trait_object.rs b/tests/run-pass/fn_item_with_args_as_closure_trait_object.rs deleted file mode 100644 index 257028c4f0d8..000000000000 --- a/tests/run-pass/fn_item_with_args_as_closure_trait_object.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn foo(i: i32) { - assert_eq!(i, 42); -} - -fn main() { - let f: &dyn Fn(i32) = &foo; - f(42); -} diff --git a/tests/run-pass/fn_item_with_multiple_args_as_closure_trait_object.rs b/tests/run-pass/fn_item_with_multiple_args_as_closure_trait_object.rs deleted file mode 100644 index 98111f304c89..000000000000 --- a/tests/run-pass/fn_item_with_multiple_args_as_closure_trait_object.rs +++ /dev/null @@ -1,18 +0,0 @@ -fn foo(i: i32, j: i32) { - assert_eq!(i, 42); - assert_eq!(j, 55); -} - -fn bar(i: i32, j: i32, k: f32) { - assert_eq!(i, 42); - assert_eq!(j, 55); - assert_eq!(k, 3.14159) -} - - -fn main() { - let f: &dyn Fn(i32, i32) = &foo; - f(42, 55); - let f: &dyn Fn(i32, i32, f32) = &bar; - f(42, 55, 3.14159); -} diff --git a/tests/run-pass/fn_ptr_as_closure_trait_object.rs b/tests/run-pass/fn_ptr_as_closure_trait_object.rs deleted file mode 100644 index 89daed81507f..000000000000 --- a/tests/run-pass/fn_ptr_as_closure_trait_object.rs +++ /dev/null @@ -1,15 +0,0 @@ -fn foo() {} -fn bar(u: u32) { assert_eq!(u, 42); } -fn baa(u: u32, f: f32) { - assert_eq!(u, 42); - assert_eq!(f, 3.141); -} - -fn main() { - let f: &dyn Fn() = &(foo as fn()); - f(); - let f: &dyn Fn(u32) = &(bar as fn(u32)); - f(42); - let f: &dyn Fn(u32, f32) = &(baa as fn(u32, f32)); - f(42, 3.141); -} From 96444c11eee3a6d29d22056eee7e1d2ea73ebb19 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 31 May 2019 16:34:22 +0200 Subject: [PATCH 0785/5092] remove too expensive debug assertion --- src/stacked_borrows.rs | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 8c46f7e1b2e9..289fab99ad64 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -346,23 +346,6 @@ impl<'tcx> Stack { Ok(()) } - /// `reborrow` helper function: test that the stack invariants are still maintained. - fn test_invariants(&self) { - let mut saw_shared_read_only = false; - for item in self.borrows.iter() { - match item.perm { - Permission::SharedReadOnly => { - saw_shared_read_only = true; - } - // Otherwise, if we saw one before, that's a bug. - perm if saw_shared_read_only => { - bug!("Found {:?} on top of a SharedReadOnly!", perm); - } - _ => {} - } - } - } - /// Derived a new pointer from one with the given tag. /// `weak` controls whether this operation is weak or strong: weak granting does not act as /// an access, and they add the new item directly on top of the one it is derived @@ -418,11 +401,6 @@ impl<'tcx> Stack { self.borrows.insert(new_idx, new); } - // Make sure that after all this, the stack's invariant is still maintained. - if cfg!(debug_assertions) { - self.test_invariants(); - } - Ok(()) } } From dafd2e7202dbdc167b573e07f13a7ca1fd37e42f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 1 Jun 2019 10:04:49 +0200 Subject: [PATCH 0786/5092] rustup for ... deprecation --- rust-version | 2 +- tests/run-pass/ints.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index 5504e77097b7..60d0ba51f794 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c28084ac16af4ab594b6860958df140e7c876a13 +8b40a188cee5bef97526dfc271afbd2a98008183 diff --git a/tests/run-pass/ints.rs b/tests/run-pass/ints.rs index 4f23b5ec9c38..00ca2aa41dd3 100644 --- a/tests/run-pass/ints.rs +++ b/tests/run-pass/ints.rs @@ -34,11 +34,11 @@ fn match_int() -> i16 { fn match_int_range() -> i64 { let n = 42; match n { - 0...9 => 0, - 10...19 => 1, - 20...29 => 2, - 30...39 => 3, - 40...49 => 4, + 0..=9 => 0, + 10..=19 => 1, + 20..=29 => 2, + 30..=39 => 3, + 40..=42 => 4, _ => 5, } } From 0c704151f7c365ab8cd84e994b54b1bb424647cd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 May 2019 20:04:37 +0200 Subject: [PATCH 0787/5092] use new rustc infrastructure to tag the base pointer of static allocations --- src/intrinsic.rs | 5 +-- src/lib.rs | 73 +++++++++++++++++++++--------------------- src/stacked_borrows.rs | 65 +++++++++++++++++++++---------------- 3 files changed, 76 insertions(+), 67 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index a17f576b43b7..d46d185c5f48 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -5,7 +5,7 @@ use rustc::ty; use crate::{ PlaceTy, OpTy, ImmTy, Immediate, Scalar, ScalarMaybeUndef, Tag, - OperatorEvalContextExt + OperatorEvalContextExt, MiriMemoryKind, }; impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} @@ -401,7 +401,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "type_name" => { let ty = substs.type_at(0); let ty_name = ty.to_string(); - let value = this.str_to_immediate(&ty_name)?; + let ptr = this.memory_mut().allocate_static_bytes(ty_name.as_bytes(), MiriMemoryKind::Static.into()); + let value = Immediate::new_slice(Scalar::Ptr(ptr), ty_name.len() as u64, this); this.write_immediate(value, dest)?; } diff --git a/src/lib.rs b/src/lib.rs index 89d7964913ae..bf0c6cd38787 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,7 +30,7 @@ use rand::SeedableRng; use rustc::ty::{self, TyCtxt, query::TyCtxtAt}; use rustc::ty::layout::{LayoutOf, Size, Align}; -use rustc::hir::{self, def_id::DefId}; +use rustc::hir::def_id::DefId; use rustc::mir; pub use rustc_mir::interpret::*; // Resolve ambiguity. @@ -113,7 +113,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // Return value (in static memory so that it does not count as leak). let ret = ecx.layout_of(start_mir.return_ty())?; - let ret_ptr = ecx.allocate(ret, MiriMemoryKind::MutStatic.into()); + let ret_ptr = ecx.allocate(ret, MiriMemoryKind::Static.into()); // Push our stack frame. ecx.push_stack_frame( @@ -128,7 +128,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let mut args = ecx.frame().mir.args_iter(); // First argument: pointer to `main()`. - let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance).with_default_tag(); + let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance); let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?; @@ -162,7 +162,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // Add `0` terminator. let mut arg = arg.into_bytes(); arg.push(0); - argvs.push(ecx.memory_mut().allocate_static_bytes(arg.as_slice()).with_default_tag()); + argvs.push(ecx.memory_mut().allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Static.into())); } // Make an array with all these pointers, in the Miri memory. let argvs_layout = ecx.layout_of(ecx.tcx.mk_array(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8), argvs.len() as u64))?; @@ -299,8 +299,8 @@ pub enum MiriMemoryKind { C, /// Part of env var emulation. Env, - /// Mutable statics. - MutStatic, + /// Statics. + Static, } impl Into> for MiriMemoryKind { @@ -316,7 +316,7 @@ impl MayLeak for MiriMemoryKind { use self::MiriMemoryKind::*; match self { Rust | C => false, - Env | MutStatic => true, + Env | Static => true, } } } @@ -392,7 +392,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { type MemoryMap = MonoHashMap, Allocation)>; - const STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); + const STATIC_KIND: Option = Some(MiriMemoryKind::Static); #[inline(always)] fn enforce_validity(ecx: &InterpretCx<'a, 'mir, 'tcx, Self>) -> bool { @@ -476,8 +476,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn find_foreign_static( def_id: DefId, tcx: TyCtxtAt<'a, 'tcx, 'tcx>, - memory_extra: &Self::MemoryExtra, - ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> { + ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> { let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { Some(name) => name.as_str(), @@ -489,8 +488,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { // This should be all-zero, pointer-sized. let size = tcx.data_layout.pointer_size; let data = vec![0; size.bytes() as usize]; - let extra = Stacks::new(size, Tag::default(), Rc::clone(memory_extra)); - Allocation::from_bytes(&data, tcx.data_layout.pointer_align.abi, extra) + Allocation::from_bytes(&data, tcx.data_layout.pointer_align.abi) } _ => return err!(Unimplemented( format!("can't access foreign static: {}", link_name), @@ -506,47 +504,48 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { Ok(()) } - fn adjust_static_allocation<'b>( - alloc: &'b Allocation, + fn tag_allocation<'b>( + id: AllocId, + alloc: Cow<'b, Allocation>, + kind: Option>, memory_extra: &Self::MemoryExtra, - ) -> Cow<'b, Allocation> { - let extra = Stacks::new( + ) -> (Cow<'b, Allocation>, Self::PointerTag) { + let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); + let alloc = alloc.into_owned(); + let (extra, base_tag) = Stacks::new_allocation( + id, Size::from_bytes(alloc.bytes.len() as u64), - Tag::default(), Rc::clone(memory_extra), + kind, ); + if kind != MiriMemoryKind::Static.into() { + assert!(alloc.relocations.is_empty(), "Only statics can come initialized with inner pointers"); + // Now we can rely on the inner pointers being static, too. + } + let mut memory_extra = memory_extra.borrow_mut(); let alloc: Allocation = Allocation { - bytes: alloc.bytes.clone(), + bytes: alloc.bytes, relocations: Relocations::from_presorted( alloc.relocations.iter() - .map(|&(offset, ((), alloc))| (offset, (Tag::default(), alloc))) + // The allocations in the relocations (pointers stored *inside* this allocation) + // all get the base pointer tag. + .map(|&(offset, ((), alloc))| (offset, (memory_extra.static_base_ptr(alloc), alloc))) .collect() ), - undef_mask: alloc.undef_mask.clone(), + undef_mask: alloc.undef_mask, align: alloc.align, mutability: alloc.mutability, extra, }; - Cow::Owned(alloc) + (Cow::Owned(alloc), base_tag) } #[inline(always)] - fn new_allocation( - size: Size, - extra: &Self::MemoryExtra, - kind: MemoryKind, - ) -> (Self::AllocExtra, Self::PointerTag) { - Stacks::new_allocation(size, extra, kind) - } - - #[inline(always)] - fn tag_dereference( - _ecx: &InterpretCx<'a, 'mir, 'tcx, Self>, - place: MPlaceTy<'tcx, Tag>, - _mutability: Option, - ) -> EvalResult<'tcx, Scalar> { - // Nothing happens. - Ok(place.ptr) + fn tag_static_base_pointer( + id: AllocId, + memory_extra: &Self::MemoryExtra, + ) -> Self::PointerTag { + memory_extra.borrow_mut().static_base_ptr(id) } #[inline(always)] diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 8c46f7e1b2e9..71779a6132d9 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -1,5 +1,5 @@ use std::cell::RefCell; -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; use std::rc::Rc; use std::fmt; use std::num::NonZeroU64; @@ -10,7 +10,7 @@ use rustc::mir::RetagKind; use crate::{ EvalResult, InterpError, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, - MemoryKind, MiriMemoryKind, RangeMap, Allocation, AllocationExtra, CheckInAllocMsg, + MemoryKind, MiriMemoryKind, RangeMap, Allocation, AllocationExtra, AllocId, CheckInAllocMsg, Pointer, Immediate, ImmTy, PlaceTy, MPlaceTy, }; @@ -92,10 +92,18 @@ pub struct Stacks { /// Extra global state, available to the memory access hooks. #[derive(Debug)] pub struct GlobalState { + /// Next unused pointer ID (tag). next_ptr_id: PtrId, + /// Table storing the "base" tag for each allocation. + /// The base tag is the one used for the initial pointer. + /// We need this in a separate table to handle cyclic statics. + base_ptr_ids: HashMap, + /// Next unused call ID (for protectors). next_call_id: CallId, + /// Those call IDs corresponding to functions that are still running. active_calls: HashSet, } +/// Memory extra state gives us interior mutable access to the global state. pub type MemoryState = Rc>; /// Indicates which kind of access is being performed. @@ -144,6 +152,7 @@ impl Default for GlobalState { fn default() -> Self { GlobalState { next_ptr_id: NonZeroU64::new(1).unwrap(), + base_ptr_ids: HashMap::default(), next_call_id: NonZeroU64::new(1).unwrap(), active_calls: HashSet::default(), } @@ -151,7 +160,7 @@ impl Default for GlobalState { } impl GlobalState { - pub fn new_ptr(&mut self) -> PtrId { + fn new_ptr(&mut self) -> PtrId { let id = self.next_ptr_id; self.next_ptr_id = NonZeroU64::new(id.get() + 1).unwrap(); id @@ -172,6 +181,15 @@ impl GlobalState { fn is_active(&self, id: CallId) -> bool { self.active_calls.contains(&id) } + + pub fn static_base_ptr(&mut self, id: AllocId) -> Tag { + self.base_ptr_ids.get(&id).copied().unwrap_or_else(|| { + let tag = Tag::Tagged(self.new_ptr()); + trace!("New allocation {:?} has base tag {:?}", id, tag); + self.base_ptr_ids.insert(id, tag); + tag + }) + } } // # Stacked Borrows Core Begin @@ -190,14 +208,6 @@ impl GlobalState { /// F3: If an access happens with an `&` outside `UnsafeCell`, /// it requires the `SharedReadOnly` to still be in the stack. -impl Default for Tag { - #[inline(always)] - fn default() -> Tag { - Tag::Untagged - } -} - - /// Core relation on `Permission` to define which accesses are allowed impl Permission { /// This defines for a given permission, whether it permits the given kind of access. @@ -431,12 +441,13 @@ impl<'tcx> Stack { /// Map per-stack operations to higher-level per-location-range operations. impl<'tcx> Stacks { /// Creates new stack with initial tag. - pub(crate) fn new( + fn new( size: Size, + perm: Permission, tag: Tag, extra: MemoryState, ) -> Self { - let item = Item { perm: Permission::Unique, tag, protector: None }; + let item = Item { perm, tag, protector: None }; let stack = Stack { borrows: vec![item], }; @@ -465,27 +476,25 @@ impl<'tcx> Stacks { /// Glue code to connect with Miri Machine Hooks impl Stacks { pub fn new_allocation( + id: AllocId, size: Size, - extra: &MemoryState, + extra: MemoryState, kind: MemoryKind, ) -> (Self, Tag) { - let tag = match kind { - MemoryKind::Stack => { - // New unique borrow. This `Uniq` is not accessible by the program, + let (tag, perm) = match kind { + MemoryKind::Stack => + // New unique borrow. This tag is not accessible by the program, // so it will only ever be used when using the local directly (i.e., - // not through a pointer). That is, whenever we directly use a local, this will pop + // not through a pointer). That is, whenever we directly write to a local, this will pop // everything else off the stack, invalidating all previous pointers, - // and in particular, *all* raw pointers. This subsumes the explicit - // `reset` which the blog post [1] says to perform when accessing a local. - // - // [1]: - Tag::Tagged(extra.borrow_mut().new_ptr()) - } - _ => { - Tag::Untagged - } + // and in particular, *all* raw pointers. + (Tag::Tagged(extra.borrow_mut().new_ptr()), Permission::Unique), + MemoryKind::Machine(MiriMemoryKind::Static) => + (extra.borrow_mut().static_base_ptr(id), Permission::SharedReadWrite), + _ => + (Tag::Untagged, Permission::SharedReadWrite), }; - let stack = Stacks::new(size, tag, Rc::clone(extra)); + let stack = Stacks::new(size, perm, tag, extra); (stack, tag) } } From e03255d62554424805a1959a0cfdad13171429a1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 28 May 2019 18:28:15 +0200 Subject: [PATCH 0788/5092] fix existing tests fix thread-local example to no longer write to pointers derived from a shared ref; fix compile-fail test --- tests/compile-fail/modifying_constants.rs | 2 ++ tests/run-pass/thread-local.rs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/compile-fail/modifying_constants.rs b/tests/compile-fail/modifying_constants.rs index 27c74e8dc87e..4546e8a4d7c9 100644 --- a/tests/compile-fail/modifying_constants.rs +++ b/tests/compile-fail/modifying_constants.rs @@ -1,3 +1,5 @@ +// This should fail even without validation +// compile-flags: -Zmiri-disable-validation fn main() { let x = &1; // the `&1` is promoted to a constant, but it used to be that only the pointer is marked static, not the pointee diff --git a/tests/run-pass/thread-local.rs b/tests/run-pass/thread-local.rs index aeedb7034ce5..8de45811be44 100644 --- a/tests/run-pass/thread-local.rs +++ b/tests/run-pass/thread-local.rs @@ -56,7 +56,7 @@ fn main() { create(None); // check that the no-dtor case works // Initialize the keys we use to check destructor ordering - for (key, global) in KEYS.iter_mut().zip(GLOBALS.iter()) { + for (key, global) in KEYS.iter_mut().zip(GLOBALS.iter_mut()) { *key = create(Some(mem::transmute(dtor as unsafe extern fn(*mut u64)))); set(*key, global as *const _ as *mut _); } From 9f48b3029ca51997945ae4170f1e2b0ebb23a7a2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 28 May 2019 19:26:50 +0200 Subject: [PATCH 0789/5092] test that we cannot access unescaped static memory with a raw ptr --- tests/compile-fail/stacked_borrows/unescaped_static.rs | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/compile-fail/stacked_borrows/unescaped_static.rs diff --git a/tests/compile-fail/stacked_borrows/unescaped_static.rs b/tests/compile-fail/stacked_borrows/unescaped_static.rs new file mode 100644 index 000000000000..0f0467fc5cb9 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/unescaped_static.rs @@ -0,0 +1,7 @@ +static ARRAY: [u8; 2] = [0, 1]; + +fn main() { + let ptr_to_first = &ARRAY[0] as *const u8; + // Illegally use this to access the 2nd element. + let _val = unsafe { *ptr_to_first.add(1) }; //~ ERROR borrow stack +} From b231a7ec9efa58496786c4eed623e150659f370d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 2 Jun 2019 22:16:18 +0200 Subject: [PATCH 0790/5092] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 60d0ba51f794..7604934a98b3 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8b40a188cee5bef97526dfc271afbd2a98008183 +627486af15d222bcba336b12ea92a05237cc9ab1 From e4317e9e082b0b7b3c3162e4ad725194f09dd7e7 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Mon, 3 Jun 2019 09:52:19 +0700 Subject: [PATCH 0791/5092] Bump cargo_metadata to 0.8 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 6f7570edda5f..e60205fc4208 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,7 @@ required-features = ["rustc_tests"] [dependencies] byteorder = { version = "1.1", features = ["i128"]} -cargo_metadata = { version = "0.7", optional = true } +cargo_metadata = { version = "0.8", optional = true } directories = { version = "1.0", optional = true } rustc_version = { version = "0.2.3", optional = true } env_logger = "0.6" From 724a9276b1f382a000ceed27ba52bcb04ed436f4 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Mon, 3 Jun 2019 09:55:02 +0700 Subject: [PATCH 0792/5092] Bump directories to 2.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e60205fc4208..0627c9986fb4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,7 @@ required-features = ["rustc_tests"] [dependencies] byteorder = { version = "1.1", features = ["i128"]} cargo_metadata = { version = "0.8", optional = true } -directories = { version = "1.0", optional = true } +directories = { version = "2.0", optional = true } rustc_version = { version = "0.2.3", optional = true } env_logger = "0.6" log = "0.4" From 27a66a1e4220afc859d3ee93a208a7f19b1c693f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 31 May 2019 19:05:31 +0200 Subject: [PATCH 0793/5092] test for no-validation-only failure --- tests/run-pass/without-validation.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 tests/run-pass/without-validation.rs diff --git a/tests/run-pass/without-validation.rs b/tests/run-pass/without-validation.rs new file mode 100644 index 000000000000..8cff3a5c4b2e --- /dev/null +++ b/tests/run-pass/without-validation.rs @@ -0,0 +1,24 @@ +// When we notice something breaks only without validation, we add a test here. +// compile-flags: -Zmiri-disable-validation +use std::cell::*; + +fn refcell_unsize() { + let cell: RefCell<[i32; 3]> = RefCell::new([1, 2, 3]); + { + let mut cellref: RefMut<'_, [i32; 3]> = cell.borrow_mut(); + cellref[0] = 4; + let mut coerced: RefMut<'_, [i32]> = cellref; + coerced[2] = 5; + } + { + let comp: &mut [i32] = &mut [4, 2, 5]; + let cellref: Ref<'_, [i32; 3]> = cell.borrow(); + assert_eq!(&*cellref, comp); + let coerced: Ref<'_, [i32]> = cellref; + assert_eq!(&*coerced, comp); + } +} + +fn main() { + refcell_unsize(); +} From c06134c4afdc82c298e424e8f3e43c7e5379197c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 4 Jun 2019 13:22:27 +0200 Subject: [PATCH 0794/5092] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 7604934a98b3..930c6c17ac6c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -627486af15d222bcba336b12ea92a05237cc9ab1 +021a5033098ff0e3f7126acc7ac35149d325f16d From 1ceb81b34552c0ff466f4ffaa00fe2f87cb5e16c Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sun, 2 Jun 2019 21:20:13 -0700 Subject: [PATCH 0795/5092] Use in-core implementation of `type_name`. We bump `rust-version` to pick up the new impl from https://github.com/rust-lang/rust/pull/61498 and add a test. --- rust-version | 2 +- src/intrinsic.rs | 10 +--------- tests/run-pass/intrinsics.rs | 5 +++++ 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/rust-version b/rust-version index 930c6c17ac6c..b2c0aca42bdf 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -021a5033098ff0e3f7126acc7ac35149d325f16d +7cdaffd7962c4aae0cadd82baa241901b03f9458 diff --git a/src/intrinsic.rs b/src/intrinsic.rs index d46d185c5f48..8d564456f4ed 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -5,7 +5,7 @@ use rustc::ty; use crate::{ PlaceTy, OpTy, ImmTy, Immediate, Scalar, ScalarMaybeUndef, Tag, - OperatorEvalContextExt, MiriMemoryKind, + OperatorEvalContextExt }; impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} @@ -398,14 +398,6 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, )?; } - "type_name" => { - let ty = substs.type_at(0); - let ty_name = ty.to_string(); - let ptr = this.memory_mut().allocate_static_bytes(ty_name.as_bytes(), MiriMemoryKind::Static.into()); - let value = Immediate::new_slice(Scalar::Ptr(ptr), ty_name.len() as u64, this); - this.write_immediate(value, dest)?; - } - "unchecked_div" => { let l = this.read_immediate(args[0])?; let r = this.read_immediate(args[1])?; diff --git a/tests/run-pass/intrinsics.rs b/tests/run-pass/intrinsics.rs index 3152737a601c..963265749d13 100644 --- a/tests/run-pass/intrinsics.rs +++ b/tests/run-pass/intrinsics.rs @@ -1,3 +1,6 @@ +#![feature(core_intrinsics)] + +use std::intrinsics::type_name; use std::mem::{size_of, size_of_val}; fn main() { @@ -7,4 +10,6 @@ fn main() { assert_eq!(size_of_val(&[] as &[i32]), 0); assert_eq!(size_of_val(&[1, 2, 3] as &[i32]), 12); assert_eq!(size_of_val("foobar"), 6); + + assert_eq!(unsafe { type_name::>() }, "core::option::Option"); } From d6bcfc58e3afe292cce167e8a419cf412c25e4cd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 8 Jun 2019 22:14:47 +0200 Subject: [PATCH 0796/5092] rustup for EvalResult rename --- rust-version | 2 +- src/fn_call.rs | 14 +++++++------- src/helpers.rs | 22 +++++++++++----------- src/intrinsic.rs | 4 ++-- src/lib.rs | 22 +++++++++++----------- src/operator.rs | 16 ++++++++-------- src/stacked_borrows.rs | 28 ++++++++++++++-------------- src/tls.rs | 10 +++++----- 8 files changed, 59 insertions(+), 59 deletions(-) diff --git a/rust-version b/rust-version index b2c0aca42bdf..3e7048ac72cc 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7cdaffd7962c4aae0cadd82baa241901b03f9458 +5c45343f11fbf93cf4e15568aee3ff3f2f287466 diff --git a/src/fn_call.rs b/src/fn_call.rs index 17679e26790c..5397c048f9f4 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -17,7 +17,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' args: &[OpTy<'tcx, Tag>], dest: Option>, ret: Option, - ) -> EvalResult<'tcx, Option<&'mir mir::Body<'tcx>>> { + ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); trace!("eval_fn_call: {:#?}, {:?}", instance, dest.map(|place| *place)); @@ -76,7 +76,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' fn free( &mut self, ptr: Scalar, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if !ptr.is_null_ptr(this) { this.memory_mut().deallocate( @@ -92,7 +92,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' &mut self, old_ptr: Scalar, new_size: u64, - ) -> EvalResult<'tcx, Scalar> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let align = this.tcx.data_layout.pointer_align.abi; if old_ptr.is_null_ptr(this) { @@ -139,7 +139,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' args: &[OpTy<'tcx, Tag>], dest: Option>, ret: Option, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { @@ -895,13 +895,13 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' Ok(()) } - fn write_null(&mut self, dest: PlaceTy<'tcx, Tag>) -> EvalResult<'tcx> { + fn write_null(&mut self, dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest) } /// Evaluates the scalar at the specified path. Returns Some(val) /// if the path could be resolved, and None otherwise - fn eval_path_scalar(&mut self, path: &[&str]) -> EvalResult<'tcx, Option>> { + fn eval_path_scalar(&mut self, path: &[&str]) -> InterpResult<'tcx, Option>> { let this = self.eval_context_mut(); if let Ok(instance) = this.resolve_path(path) { let cid = GlobalId { @@ -920,7 +920,7 @@ fn gen_random<'a, 'mir, 'tcx>( this: &mut MiriEvalContext<'a, 'mir, 'tcx>, len: usize, dest: Scalar, -) -> EvalResult<'tcx> { +) -> InterpResult<'tcx> { if len == 0 { // Nothing to do return Ok(()); diff --git a/src/helpers.rs b/src/helpers.rs index 89aba494724c..29bc1def9fda 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -9,7 +9,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<' pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { /// Gets an instance for a path. - fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>> { + fn resolve_path(&self, path: &[&str]) -> InterpResult<'tcx, ty::Instance<'tcx>> { let this = self.eval_context_ref(); this.tcx .crates() @@ -49,8 +49,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' &self, place: MPlaceTy<'tcx, Tag>, size: Size, - mut action: impl FnMut(Pointer, Size, bool) -> EvalResult<'tcx>, - ) -> EvalResult<'tcx> { + mut action: impl FnMut(Pointer, Size, bool) -> InterpResult<'tcx>, + ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); trace!("visit_frozen(place={:?}, size={:?})", *place, size); debug_assert_eq!(size, @@ -120,7 +120,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' /// Visiting the memory covered by a `MemPlace`, being aware of /// whether we are inside an `UnsafeCell` or not. struct UnsafeCellVisitor<'ecx, 'a, 'mir, 'tcx, F> - where F: FnMut(MPlaceTy<'tcx, Tag>) -> EvalResult<'tcx> + where F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { ecx: &'ecx MiriEvalContext<'a, 'mir, 'tcx>, unsafe_cell_action: F, @@ -131,7 +131,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' for UnsafeCellVisitor<'ecx, 'a, 'mir, 'tcx, F> where - F: FnMut(MPlaceTy<'tcx, Tag>) -> EvalResult<'tcx> + F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { type V = MPlaceTy<'tcx, Tag>; @@ -141,7 +141,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } // Hook to detect `UnsafeCell`. - fn visit_value(&mut self, v: MPlaceTy<'tcx, Tag>) -> EvalResult<'tcx> + fn visit_value(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty); let is_unsafe_cell = match v.layout.ty.sty { @@ -164,8 +164,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' fn visit_aggregate( &mut self, place: MPlaceTy<'tcx, Tag>, - fields: impl Iterator>>, - ) -> EvalResult<'tcx> { + fields: impl Iterator>>, + ) -> InterpResult<'tcx> { match place.layout.fields { layout::FieldPlacement::Array { .. } => { // For the array layout, we know the iterator will yield sorted elements so @@ -174,7 +174,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } layout::FieldPlacement::Arbitrary { .. } => { // Gather the subplaces and sort them before visiting. - let mut places = fields.collect::>>>()?; + let mut places = fields.collect::>>>()?; places.sort_by_key(|place| place.ptr.get_ptr_offset(self.ecx())); self.walk_aggregate(place, places.into_iter().map(Ok)) } @@ -186,7 +186,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } // We have to do *something* for unions. - fn visit_union(&mut self, v: MPlaceTy<'tcx, Tag>) -> EvalResult<'tcx> + fn visit_union(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { // With unions, we fall back to whatever the type says, to hopefully be consistent // with LLVM IR. @@ -200,7 +200,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } // We should never get to a primitive, but always short-circuit somewhere above. - fn visit_primitive(&mut self, _v: MPlaceTy<'tcx, Tag>) -> EvalResult<'tcx> + fn visit_primitive(&mut self, _v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { bug!("we should always short-circuit before coming to a primitive") } diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 8d564456f4ed..822265bc2112 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -1,5 +1,5 @@ use rustc::mir; -use rustc::mir::interpret::{EvalResult, PointerArithmetic}; +use rustc::mir::interpret::{InterpResult, PointerArithmetic}; use rustc::ty::layout::{self, LayoutOf, Size}; use rustc::ty; @@ -15,7 +15,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if this.emulate_intrinsic(instance, args, dest)? { return Ok(()); diff --git a/src/lib.rs b/src/lib.rs index bf0c6cd38787..8577bc4714e5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,7 +75,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, config: MiriConfig, -) -> EvalResult<'tcx, InterpretCx<'a, 'mir, 'tcx, Evaluator<'tcx>>> { +) -> InterpResult<'tcx, InterpretCx<'a, 'mir, 'tcx, Evaluator<'tcx>>> { let mut ecx = InterpretCx::new( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), @@ -225,7 +225,7 @@ pub fn eval_main<'a, 'tcx: 'a>( }; // Perform the main execution. - let res: EvalResult = (|| { + let res: InterpResult = (|| { ecx.run()?; ecx.run_tls_dtors() })(); @@ -407,7 +407,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { args: &[OpTy<'tcx, Tag>], dest: Option>, ret: Option, - ) -> EvalResult<'tcx, Option<&'mir mir::Body<'tcx>>> { + ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { ecx.find_fn(instance, args, dest, ret) } @@ -417,7 +417,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { ecx.call_intrinsic(instance, args, dest) } @@ -427,14 +427,14 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { bin_op: mir::BinOp, left: ImmTy<'tcx, Tag>, right: ImmTy<'tcx, Tag>, - ) -> EvalResult<'tcx, (Scalar, bool)> { + ) -> InterpResult<'tcx, (Scalar, bool)> { ecx.ptr_op(bin_op, left, right) } fn box_alloc( ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, dest: PlaceTy<'tcx, Tag>, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { trace!("box_alloc for {:?}", dest.layout.ty); // Call the `exchange_malloc` lang item. let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap(); @@ -476,7 +476,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn find_foreign_static( def_id: DefId, tcx: TyCtxtAt<'a, 'tcx, 'tcx>, - ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> { + ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { Some(name) => name.as_str(), @@ -498,7 +498,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { } #[inline(always)] - fn before_terminator(_ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> + fn before_terminator(_ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>) -> InterpResult<'tcx> { // We are not interested in detecting loops. Ok(()) @@ -553,7 +553,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, kind: mir::RetagKind, place: PlaceTy<'tcx, Tag>, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !Self::enforce_validity(ecx) { // No tracking, or no retagging. The latter is possible because a dependency of ours // might be called with different flags than we are, so there are `Retag` @@ -569,7 +569,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn stack_push( ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, - ) -> EvalResult<'tcx, stacked_borrows::CallId> { + ) -> InterpResult<'tcx, stacked_borrows::CallId> { Ok(ecx.memory().extra.borrow_mut().new_call()) } @@ -577,7 +577,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn stack_pop( ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, extra: stacked_borrows::CallId, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { Ok(ecx.memory().extra.borrow_mut().end_call(extra)) } } diff --git a/src/operator.rs b/src/operator.rs index 28d0d7c96095..411df2155de0 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -9,7 +9,7 @@ pub trait EvalContextExt<'tcx> { bin_op: mir::BinOp, left: ImmTy<'tcx, Tag>, right: ImmTy<'tcx, Tag>, - ) -> EvalResult<'tcx, (Scalar, bool)>; + ) -> InterpResult<'tcx, (Scalar, bool)>; fn ptr_int_arithmetic( &self, @@ -17,20 +17,20 @@ pub trait EvalContextExt<'tcx> { left: Pointer, right: u128, signed: bool, - ) -> EvalResult<'tcx, (Scalar, bool)>; + ) -> InterpResult<'tcx, (Scalar, bool)>; fn ptr_eq( &self, left: Scalar, right: Scalar, - ) -> EvalResult<'tcx, bool>; + ) -> InterpResult<'tcx, bool>; fn pointer_offset_inbounds( &self, ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Scalar>; + ) -> InterpResult<'tcx, Scalar>; } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { @@ -39,7 +39,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' bin_op: mir::BinOp, left: ImmTy<'tcx, Tag>, right: ImmTy<'tcx, Tag>, - ) -> EvalResult<'tcx, (Scalar, bool)> { + ) -> InterpResult<'tcx, (Scalar, bool)> { use rustc::mir::BinOp::*; trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); @@ -138,7 +138,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' &self, left: Scalar, right: Scalar, - ) -> EvalResult<'tcx, bool> { + ) -> InterpResult<'tcx, bool> { let size = self.pointer_size(); Ok(match (left, right) { (Scalar::Raw { .. }, Scalar::Raw { .. }) => @@ -236,7 +236,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' left: Pointer, right: u128, signed: bool, - ) -> EvalResult<'tcx, (Scalar, bool)> { + ) -> InterpResult<'tcx, (Scalar, bool)> { use rustc::mir::BinOp::*; fn map_to_primval((res, over): (Pointer, bool)) -> (Scalar, bool) { @@ -328,7 +328,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Scalar> { + ) -> InterpResult<'tcx, Scalar> { // FIXME: assuming here that type size is less than `i64::max_value()`. let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; let offset = offset diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index dee4ca33c25d..bd8158479019 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -9,7 +9,7 @@ use rustc::hir::{MutMutable, MutImmutable}; use rustc::mir::RetagKind; use crate::{ - EvalResult, InterpError, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, + InterpResult, InterpError, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, MemoryKind, MiriMemoryKind, RangeMap, Allocation, AllocationExtra, AllocId, CheckInAllocMsg, Pointer, Immediate, ImmTy, PlaceTy, MPlaceTy, }; @@ -266,7 +266,7 @@ impl<'tcx> Stack { } /// Check if the given item is protected. - fn check_protector(item: &Item, tag: Option, global: &GlobalState) -> EvalResult<'tcx> { + fn check_protector(item: &Item, tag: Option, global: &GlobalState) -> InterpResult<'tcx> { if let Some(call) = item.protector { if global.is_active(call) { if let Some(tag) = tag { @@ -291,7 +291,7 @@ impl<'tcx> Stack { access: AccessKind, tag: Tag, global: &GlobalState, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. @@ -340,7 +340,7 @@ impl<'tcx> Stack { &mut self, tag: Tag, global: &GlobalState, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { // Step 1: Find granting item. self.find_granting(AccessKind::Write, tag) .ok_or_else(|| InterpError::MachineError(format!( @@ -365,7 +365,7 @@ impl<'tcx> Stack { derived_from: Tag, new: Item, global: &GlobalState, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { // Figure out which access `perm` corresponds to. let access = if new.perm.grants(AccessKind::Write) { AccessKind::Write @@ -440,8 +440,8 @@ impl<'tcx> Stacks { &self, ptr: Pointer, size: Size, - f: impl Fn(&mut Stack, &GlobalState) -> EvalResult<'tcx>, - ) -> EvalResult<'tcx> { + f: impl Fn(&mut Stack, &GlobalState) -> InterpResult<'tcx>, + ) -> InterpResult<'tcx> { let global = self.global.borrow(); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { @@ -483,7 +483,7 @@ impl AllocationExtra for Stacks { alloc: &Allocation, ptr: Pointer, size: Size, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); alloc.extra.for_each(ptr, size, |stack, global| { stack.access(AccessKind::Read, ptr.tag, global)?; @@ -496,7 +496,7 @@ impl AllocationExtra for Stacks { alloc: &mut Allocation, ptr: Pointer, size: Size, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); alloc.extra.for_each(ptr, size, |stack, global| { stack.access(AccessKind::Write, ptr.tag, global)?; @@ -509,7 +509,7 @@ impl AllocationExtra for Stacks { alloc: &mut Allocation, ptr: Pointer, size: Size, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); alloc.extra.for_each(ptr, size, |stack, global| { stack.dealloc(ptr.tag, global) @@ -528,7 +528,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, kind: RefKind, new_tag: Tag, protect: bool, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let protector = if protect { Some(this.frame().extra) } else { None }; let ptr = place.ptr.to_ptr()?; @@ -572,7 +572,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, val: ImmTy<'tcx, Tag>, kind: RefKind, protect: bool, - ) -> EvalResult<'tcx, Immediate> { + ) -> InterpResult<'tcx, Immediate> { let this = self.eval_context_mut(); // We want a place for where the ptr *points to*, so we get one. let place = this.ref_to_mplace(val)?; @@ -605,7 +605,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, &mut self, kind: RetagKind, place: PlaceTy<'tcx, Tag> - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); // Determine mutability and whether to add a protector. // Cannot use `builtin_deref` because that reports *immutable* for `Box`, @@ -660,7 +660,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } // Primitives of reference type, that is the one thing we are interested in. - fn visit_primitive(&mut self, place: MPlaceTy<'tcx, Tag>) -> EvalResult<'tcx> + fn visit_primitive(&mut self, place: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { // Cannot use `builtin_deref` because that reports *immutable* for `Box`, // making it useless. diff --git a/src/tls.rs b/src/tls.rs index 9346fba0dcc4..b38b15c3e18e 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -4,7 +4,7 @@ use rustc_target::abi::LayoutOf; use rustc::{ty, ty::layout::HasDataLayout, mir}; use crate::{ - EvalResult, InterpError, StackPopCleanup, + InterpResult, InterpError, StackPopCleanup, MPlaceTy, Scalar, Tag, }; @@ -53,7 +53,7 @@ impl<'tcx> TlsData<'tcx> { new_key } - pub fn delete_tls_key(&mut self, key: TlsKey) -> EvalResult<'tcx> { + pub fn delete_tls_key(&mut self, key: TlsKey) -> InterpResult<'tcx> { match self.keys.remove(&key) { Some(_) => { trace!("TLS key {} removed", key); @@ -63,7 +63,7 @@ impl<'tcx> TlsData<'tcx> { } } - pub fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar> { + pub fn load_tls(&mut self, key: TlsKey) -> InterpResult<'tcx, Scalar> { match self.keys.get(&key) { Some(&TlsEntry { data, .. }) => { trace!("TLS key {} loaded: {:?}", key, data); @@ -73,7 +73,7 @@ impl<'tcx> TlsData<'tcx> { } } - pub fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx> { + pub fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> InterpResult<'tcx> { match self.keys.get_mut(&key) { Some(&mut TlsEntry { ref mut data, .. }) => { trace!("TLS key {} stored: {:?}", key, new_data); @@ -131,7 +131,7 @@ impl<'tcx> TlsData<'tcx> { impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { - fn run_tls_dtors(&mut self) -> EvalResult<'tcx> { + fn run_tls_dtors(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let mut dtor = this.machine.tls.fetch_tls_dtor(None, &*this.tcx); // FIXME: replace loop by some structure that works with stepping From 09f30cabf0bb01131080032ae9858c065b64ac8b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Jun 2019 13:48:18 +0200 Subject: [PATCH 0797/5092] cargo miri: make sure we see the same sysroot for rustc and miri --- src/bin/cargo-miri.rs | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 55c53e7361a5..5e3a35917b24 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -119,6 +119,39 @@ fn list_targets() -> impl Iterator { package.targets.into_iter() } +/// Make sure that the `miri` and `rustc` binary are from the same sysroot. +/// This can be violated e.g. when miri is locally built and installed with a different +/// toolchain than what is used when `cargo miri` is run. +fn test_sysroot_consistency() { + fn get_sysroot(mut cmd: Command) -> PathBuf { + let out = cmd.arg("--print").arg("sysroot") + .env_remove("MIRI_SYSROOT") // We want to test their "native" sysroot, not the manually set one + .output().expect("Failed to run rustc to get sysroot info"); + assert!(out.status.success(), "Bad statuc code when getting sysroot info"); + let sysroot = out.stdout.lines().nth(0) + .expect("didn't get at least one line for the sysroot").unwrap(); + PathBuf::from(sysroot).canonicalize() + .expect("Failed to canonicalize sysroot") + } + + let rustc_sysroot = get_sysroot(Command::new("rustc")); + let miri_sysroot = { + let mut path = std::env::current_exe().expect("current executable path invalid"); + path.set_file_name("miri"); + get_sysroot(Command::new(path)) + }; + + if rustc_sysroot != miri_sysroot { + show_error(format!( + "miri was built for a different sysroot than the rustc in your current toolchain.\n\ + Make sure you use the same toolchain to run miri that you used to build it!\n\ + rustc sysroot: `{}`\n\ + miri sysroot: `{}`", + rustc_sysroot.display(), miri_sysroot.display() + )); + } +} + fn xargo_version() -> Option<(u32, u32, u32)> { let out = Command::new("xargo").arg("--version").output().ok()?; if !out.status.success() { @@ -269,7 +302,7 @@ path = "lib.rs" if print_env { println!("MIRI_SYSROOT={}", sysroot.display()); } else if !ask_user { - println!("A libstd for Miri is now available in `{}`", sysroot.display()); + println!("A libstd for Miri is now available in `{}`.", sysroot.display()); } } @@ -313,6 +346,9 @@ fn in_cargo_miri() { }; let verbose = has_arg_flag("-v"); + // Some basic sanity checks + test_sysroot_consistency(); + // We always setup. let ask = subcommand != MiriCommand::Setup; setup(ask); From 05b7e61977a0f7cc1b4bddab0275b5cc7deae660 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Jun 2019 14:10:42 +0200 Subject: [PATCH 0798/5092] remove outdated sysroot management --- src/bin/cargo-miri.rs | 35 +++++------------------------------ 1 file changed, 5 insertions(+), 30 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 5e3a35917b24..ae9b2efa6750 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -421,38 +421,13 @@ fn in_cargo_miri() { } fn inside_cargo_rustc() { - let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); - let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); - let sys_root = if let Ok(sysroot) = ::std::env::var("MIRI_SYSROOT") { - sysroot - } else if let (Some(home), Some(toolchain)) = (home, toolchain) { - format!("{}/toolchains/{}", home, toolchain) - } else { - option_env!("RUST_SYSROOT") - .map(|s| s.to_owned()) - .or_else(|| { - Command::new("rustc") - .arg("--print") - .arg("sysroot") - .output() - .ok() - .and_then(|out| String::from_utf8(out.stdout).ok()) - .map(|s| s.trim().to_owned()) - }) - .expect("need to specify `RUST_SYSROOT` env var during miri compilation, or use rustup or multirust") - }; + let sysroot = std::env::var("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); - // This conditional check for the `--sysroot` flag is there so that users can call `cargo-miri` - // directly without having to pass `--sysroot` or anything. - let rustc_args = std::env::args().skip(2); - let mut args: Vec = if std::env::args().any(|s| s == "--sysroot") { - rustc_args.collect() - } else { - rustc_args + let rustc_args = std::env::args().skip(2); // skip `cargo rustc` + let mut args: Vec = rustc_args .chain(Some("--sysroot".to_owned())) - .chain(Some(sys_root)) - .collect() - }; + .chain(Some(sysroot)) + .collect(); args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string)); // See if we can find the `cargo-miri` markers. Those only get added to the binary we want to From 619f29646379dd9d3001804f4d73993f7099ab91 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Jun 2019 14:31:05 +0200 Subject: [PATCH 0799/5092] explain why we always set a sysroot; make sure we error if both MIRI_SYSROOT and --sysroot are set --- src/bin/miri.rs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 31ed5f2ccd53..660f1bec2d62 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -100,11 +100,7 @@ fn init_late_loggers() { } } -fn find_sysroot() -> String { - if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") { - return sysroot; - } - +fn compile_time_sysroot() -> String { // Taken from PR . let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); @@ -167,12 +163,22 @@ fn main() { } } - // Determine sysroot and let rustc know about it. - let sysroot_flag = String::from("--sysroot"); - if !rustc_args.contains(&sysroot_flag) { + // Determine sysroot. + let sysroot_flag = "--sysroot".to_string(); + if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") { + // MIRI_SYSROOT takes priority. rustc will ensure for us that this errors if there + // already is a "--sysroot" flag (because now there would be two). rustc_args.push(sysroot_flag); - rustc_args.push(find_sysroot()); + rustc_args.push(sysroot); + } else if !rustc_args.contains(&sysroot_flag) { + // We need to *always* set a --sysroot, as the "default" rustc uses is + // somewhere in the directory miri was built in. + // If neither MIRI_SYSROOT nor --sysroot are given, fall back to env + // vars that are read at *compile-time*. + rustc_args.push(sysroot_flag); + rustc_args.push(compile_time_sysroot()); } + // Finally, add the default flags all the way in the beginning, but after the binary name. rustc_args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string)); From 244011a47f1f6318d120035c1a3b6eb121bd95f1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Jun 2019 15:43:22 +0200 Subject: [PATCH 0800/5092] don't have both MIRI_SYSROOT and --sysroot --- src/bin/cargo-miri.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index ae9b2efa6750..53b849a1a70c 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -458,6 +458,7 @@ fn inside_cargo_rustc() { } else { Command::new("rustc") }; + command.env_remove("MIRI_SYSROOT"); // we already set the --sysroot flag command.args(&args); if has_arg_flag("-v") { eprintln!("+ {:?}", command); From b0b082d4d896348bf6cee0df70ff933f7619c0e9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Jun 2019 17:10:04 +0200 Subject: [PATCH 0801/5092] do not handle MIRI_SYSROOT in the driver at all, rely fully on the --sysroot flag --- README.md | 9 ++++++--- miri | 2 +- src/bin/cargo-miri.rs | 10 ++++------ src/bin/miri.rs | 7 +------ tests/compiletest.rs | 31 +++++++++++++++---------------- 5 files changed, 27 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 130072825e1c..090694128e3a 100644 --- a/README.md +++ b/README.md @@ -250,9 +250,12 @@ Several `-Z` flags are relevant for Miri: Moreover, Miri recognizes some environment variables: -* `MIRI_SYSROOT` (recognized by `miri`, `cargo miri` and the test suite) - indicates the sysroot to use. -* `MIRI_TARGET` (recognized by the test suite) indicates which target +* `MIRI_LOG`, `MIRI_BACKTRACE` control logging and backtrace printing during + Miri executions, also [see above][testing-miri]. +* `MIRI_SYSROOT` (recognized by `cargo miri` and the test suite) + indicates the sysroot to use. To do the same thing with `miri` + directly, use the `--sysroot` flag. +* `MIRI_TEST_TARGET` (recognized by the test suite) indicates which target architecture to test against. `miri` and `cargo miri` accept the `--target` flag for the same purpose. diff --git a/miri b/miri index 2181403b7bde..bb6441bd97f9 100755 --- a/miri +++ b/miri @@ -140,7 +140,7 @@ run|run-debug) cargo build $CARGO_BUILD_FLAGS find_sysroot # Then run the actual command. - exec cargo run $CARGO_BUILD_FLAGS "$@" + exec cargo run $CARGO_BUILD_FLAGS -- --sysroot "$MIRI_SYSROOT" "$@" ;; *) echo "Unknown command: $COMMAND" diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 53b849a1a70c..db53ca6ce7c1 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -125,7 +125,6 @@ fn list_targets() -> impl Iterator { fn test_sysroot_consistency() { fn get_sysroot(mut cmd: Command) -> PathBuf { let out = cmd.arg("--print").arg("sysroot") - .env_remove("MIRI_SYSROOT") // We want to test their "native" sysroot, not the manually set one .output().expect("Failed to run rustc to get sysroot info"); assert!(out.status.success(), "Bad statuc code when getting sysroot info"); let sysroot = out.stdout.lines().nth(0) @@ -298,7 +297,7 @@ path = "lib.rs" Some(target) => target == rustc_version::version_meta().unwrap().host, }; let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; - std::env::set_var("MIRI_SYSROOT", &sysroot); + std::env::set_var("MIRI_SYSROOT", &sysroot); // pass the env var to the processes we spawn, which will turn it into "--sysroot" flags if print_env { println!("MIRI_SYSROOT={}", sysroot.display()); } else if !ask_user { @@ -425,9 +424,9 @@ fn inside_cargo_rustc() { let rustc_args = std::env::args().skip(2); // skip `cargo rustc` let mut args: Vec = rustc_args - .chain(Some("--sysroot".to_owned())) - .chain(Some(sysroot)) - .collect(); + .chain(Some("--sysroot".to_owned())) + .chain(Some(sysroot)) + .collect(); args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string)); // See if we can find the `cargo-miri` markers. Those only get added to the binary we want to @@ -458,7 +457,6 @@ fn inside_cargo_rustc() { } else { Command::new("rustc") }; - command.env_remove("MIRI_SYSROOT"); // we already set the --sysroot flag command.args(&args); if has_arg_flag("-v") { eprintln!("+ {:?}", command); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 660f1bec2d62..60f4751db8d2 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -165,12 +165,7 @@ fn main() { // Determine sysroot. let sysroot_flag = "--sysroot".to_string(); - if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") { - // MIRI_SYSROOT takes priority. rustc will ensure for us that this errors if there - // already is a "--sysroot" flag (because now there would be two). - rustc_args.push(sysroot_flag); - rustc_args.push(sysroot); - } else if !rustc_args.contains(&sysroot_flag) { + if !rustc_args.contains(&sysroot_flag) { // We need to *always* set a --sysroot, as the "default" rustc uses is // somewhere in the directory miri was built in. // If neither MIRI_SYSROOT nor --sysroot are given, fall back to env diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 7f2c8966472f..d59be08c8e00 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -25,7 +25,15 @@ fn rustc_lib_path() -> PathBuf { option_env!("RUSTC_LIB_PATH").unwrap().into() } -fn mk_config(mode: &str) -> compiletest::common::ConfigWithTemp { +fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec) { + // Some flags we always want. + flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs + flags.push("--edition 2018".to_owned()); + if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") { + flags.push(format!("--sysroot {}", sysroot)); + } + + // The rest of the configuration. let mut config = compiletest::Config::default().tempdir(); config.mode = mode.parse().expect("Invalid mode"); config.rustc_path = miri_path(); @@ -35,7 +43,10 @@ fn mk_config(mode: &str) -> compiletest::common::ConfigWithTemp { } config.filter = env::args().nth(1); config.host = get_host(); - config + config.src_base = PathBuf::from(path); + config.target = target.to_owned(); + config.target_rustcflags = Some(flags.join(" ")); + compiletest::run_tests(&config); } fn compile_fail(path: &str, target: &str, opt: bool) { @@ -48,8 +59,6 @@ fn compile_fail(path: &str, target: &str, opt: bool) { ).green().bold()); let mut flags = Vec::new(); - flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs - flags.push("--edition 2018".to_owned()); if opt { // Optimizing too aggressivley makes UB detection harder, but test at least // the default value. @@ -57,11 +66,7 @@ fn compile_fail(path: &str, target: &str, opt: bool) { flags.push("-Zmir-opt-level=1".to_owned()); } - let mut config = mk_config("compile-fail"); - config.src_base = PathBuf::from(path); - config.target = target.to_owned(); - config.target_rustcflags = Some(flags.join(" ")); - compiletest::run_tests(&config); + run_tests("compile-fail", path, target, flags); } fn miri_pass(path: &str, target: &str, opt: bool) { @@ -74,17 +79,11 @@ fn miri_pass(path: &str, target: &str, opt: bool) { ).green().bold()); let mut flags = Vec::new(); - flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs - flags.push("--edition 2018".to_owned()); if opt { flags.push("-Zmir-opt-level=3".to_owned()); } - let mut config = mk_config("ui"); - config.src_base = PathBuf::from(path); - config.target = target.to_owned(); - config.target_rustcflags = Some(flags.join(" ")); - compiletest::run_tests(&config); + run_tests("ui", path, target, flags); } fn get_host() -> String { From 5b91ecc066726527f439a983a4a75c852c631737 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Jun 2019 17:12:41 +0200 Subject: [PATCH 0802/5092] fix comments --- src/bin/miri.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 60f4751db8d2..6346b2340b08 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -100,6 +100,8 @@ fn init_late_loggers() { } } +/// Returns the "default sysroot" that Miri will use if no `--sysroot` flag is set. +/// Should be a compile-time constant. fn compile_time_sysroot() -> String { // Taken from PR . let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); @@ -168,8 +170,7 @@ fn main() { if !rustc_args.contains(&sysroot_flag) { // We need to *always* set a --sysroot, as the "default" rustc uses is // somewhere in the directory miri was built in. - // If neither MIRI_SYSROOT nor --sysroot are given, fall back to env - // vars that are read at *compile-time*. + // If no --sysroot is given, fall back to env vars that are read at *compile-time*. rustc_args.push(sysroot_flag); rustc_args.push(compile_time_sysroot()); } From 3b7ae049eeb559b372ff16f0b4213ac21f72309e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Jun 2019 19:41:58 +0200 Subject: [PATCH 0803/5092] make sure that find_sysroot always sets MIRI_SYSROOT --- miri | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/miri b/miri index bb6441bd97f9..89df4f205447 100755 --- a/miri +++ b/miri @@ -55,7 +55,6 @@ build_sysroot() { cargo run $CARGO_BUILD_FLAGS --bin cargo-miri -- miri setup "$@" # Call again, to just set env var. eval $(cargo run $CARGO_BUILD_FLAGS -q --bin cargo-miri -- miri setup --env "$@") - export MIRI_SYSROOT } # Prepare and set MIRI_SYSROOT. Respects `MIRI_TEST_TARGET` and takes into account @@ -73,7 +72,7 @@ find_sysroot() { build_sysroot --target "$MIRI_TEST_TARGET" else # Assume we have a proper host libstd in $SYSROOT. - true + MIRI_SYSROOT="$SYSROOT" fi else # A normal toolchain. We have to build a sysroot either way. @@ -83,6 +82,7 @@ find_sysroot() { build_sysroot fi fi + export MIRI_SYSROOT } ## Main From 0a9f9e0a0bc4d2aab22c3d40309208b233bef1ed Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Jun 2019 19:47:09 +0200 Subject: [PATCH 0804/5092] factor out common code to determine miri binary --- src/bin/cargo-miri.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index db53ca6ce7c1..121930bccce6 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -119,6 +119,13 @@ fn list_targets() -> impl Iterator { package.targets.into_iter() } +/// Returns the path to the `miri` binary +fn find_miri() -> PathBuf { + let mut path = std::env::current_exe().expect("current executable path invalid"); + path.set_file_name("miri"); + path +} + /// Make sure that the `miri` and `rustc` binary are from the same sysroot. /// This can be violated e.g. when miri is locally built and installed with a different /// toolchain than what is used when `cargo miri` is run. @@ -126,7 +133,7 @@ fn test_sysroot_consistency() { fn get_sysroot(mut cmd: Command) -> PathBuf { let out = cmd.arg("--print").arg("sysroot") .output().expect("Failed to run rustc to get sysroot info"); - assert!(out.status.success(), "Bad statuc code when getting sysroot info"); + assert!(out.status.success(), "Bad status code when getting sysroot info"); let sysroot = out.stdout.lines().nth(0) .expect("didn't get at least one line for the sysroot").unwrap(); PathBuf::from(sysroot).canonicalize() @@ -134,11 +141,7 @@ fn test_sysroot_consistency() { } let rustc_sysroot = get_sysroot(Command::new("rustc")); - let miri_sysroot = { - let mut path = std::env::current_exe().expect("current executable path invalid"); - path.set_file_name("miri"); - get_sysroot(Command::new(path)) - }; + let miri_sysroot = get_sysroot(Command::new(find_miri())); if rustc_sysroot != miri_sysroot { show_error(format!( @@ -451,9 +454,7 @@ fn inside_cargo_rustc() { }; let mut command = if needs_miri { - let mut path = std::env::current_exe().expect("current executable path invalid"); - path.set_file_name("miri"); - Command::new(path) + Command::new(find_miri()) } else { Command::new("rustc") }; From 446478cce2219b48114f54ca424321f67cdd428e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 10 Jun 2019 13:01:55 +0200 Subject: [PATCH 0805/5092] fix for rustc rename mir -> body --- rust-version | 2 +- src/fn_call.rs | 2 +- src/lib.rs | 6 +++--- src/tls.rs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index 3e7048ac72cc..b72e1f53ef1f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -5c45343f11fbf93cf4e15568aee3ff3f2f287466 +1cbd8a4d686d1411105f26cddf876c5994e69593 diff --git a/src/fn_call.rs b/src/fn_call.rs index 5397c048f9f4..e9377d89bcac 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -361,7 +361,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' // Directly return to caller. StackPopCleanup::Goto(Some(ret)), )?; - let mut args = this.frame().mir.args_iter(); + let mut args = this.frame().body.args_iter(); let arg_local = args.next().ok_or_else(|| InterpError::AbiViolation( diff --git a/src/lib.rs b/src/lib.rs index 8577bc4714e5..d0b7111bb069 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -125,7 +125,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( StackPopCleanup::None { cleanup: true }, )?; - let mut args = ecx.frame().mir.args_iter(); + let mut args = ecx.frame().body.args_iter(); // First argument: pointer to `main()`. let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance); @@ -252,7 +252,7 @@ pub fn eval_main<'a, 'tcx: 'a>( }; e.print_backtrace(); if let Some(frame) = ecx.stack().last() { - let block = &frame.mir.basic_blocks()[frame.block]; + let block = &frame.body.basic_blocks()[frame.block]; let span = if frame.stmt < block.statements.len() { block.statements[frame.stmt].source_info.span } else { @@ -451,7 +451,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { StackPopCleanup::None { cleanup: true }, )?; - let mut args = ecx.frame().mir.args_iter(); + let mut args = ecx.frame().body.args_iter(); let layout = ecx.layout_of(dest.layout.ty.builtin_deref(false).unwrap().ty)?; // First argument: `size`. diff --git a/src/tls.rs b/src/tls.rs index b38b15c3e18e..4101a3ab39b7 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -148,7 +148,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, Some(ret_place), StackPopCleanup::None { cleanup: true }, )?; - let arg_local = this.frame().mir.args_iter().next().ok_or_else( + let arg_local = this.frame().body.args_iter().next().ok_or_else( || InterpError::AbiViolation("TLS dtor does not take enough arguments.".to_owned()), )?; let dest = this.eval_place(&mir::Place::Base(mir::PlaceBase::Local(arg_local)))?; From 6eab94a459a16a4da0c6e18583bf70ee8c42cb1f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Jun 2019 00:12:57 +0200 Subject: [PATCH 0806/5092] fix from to/from f32/f64 changes --- src/fn_call.rs | 4 ++-- src/intrinsic.rs | 40 ++++++++++++++++++++++++---------------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index e9377d89bcac..3d2c523bf705 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -758,7 +758,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' this.machine.last_error = err; } "GetLastError" => { - this.write_scalar(Scalar::from_uint(this.machine.last_error, Size::from_bits(32)), dest)?; + this.write_scalar(Scalar::from_u32(this.machine.last_error), dest)?; } "AddVectoredExceptionHandler" => { @@ -854,7 +854,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' }; // If there was no error, write back how much was written. if let Some(n) = written { - this.write_scalar(Scalar::from_uint(n, Size::from_bits(32)), written_place.into())?; + this.write_scalar(Scalar::from_u32(n), written_place.into())?; } // Return whether this was a success. this.write_scalar( diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 822265bc2112..faaa15d3ba96 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -186,7 +186,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" => { - let f = this.read_scalar(args[0])?.to_f32()?; + // FIXME: Using host floats. + let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); let f = match intrinsic_name.get() { "sinf32" => f.sin(), "fabsf32" => f.abs(), @@ -202,12 +203,13 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "truncf32" => f.trunc(), _ => bug!(), }; - this.write_scalar(Scalar::from_f32(f), dest)?; + this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?; } "sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" | "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" => { - let f = this.read_scalar(args[0])?.to_f64()?; + // FIXME: Using host floats. + let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); let f = match intrinsic_name.get() { "sinf64" => f.sin(), "fabsf64" => f.abs(), @@ -223,7 +225,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "truncf64" => f.trunc(), _ => bug!(), }; - this.write_scalar(Scalar::from_f64(f), dest)?; + this.write_scalar(Scalar::from_u64(f.to_bits()), dest)?; } "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { @@ -320,19 +322,21 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } "powf32" => { - let f = this.read_scalar(args[0])?.to_f32()?; - let f2 = this.read_scalar(args[1])?.to_f32()?; + // FIXME: Using host floats. + let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); + let f2 = f32::from_bits(this.read_scalar(args[1])?.to_u32()?); this.write_scalar( - Scalar::from_f32(f.powf(f2)), + Scalar::from_u32(f.powf(f2).to_bits()), dest, )?; } "powf64" => { - let f = this.read_scalar(args[0])?.to_f64()?; - let f2 = this.read_scalar(args[1])?.to_f64()?; + // FIXME: Using host floats. + let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); + let f2 = f64::from_bits(this.read_scalar(args[1])?.to_u64()?); this.write_scalar( - Scalar::from_f64(f.powf(f2)), + Scalar::from_u64(f.powf(f2).to_bits()), dest, )?; } @@ -341,8 +345,9 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let a = this.read_scalar(args[0])?.to_f32()?; let b = this.read_scalar(args[1])?.to_f32()?; let c = this.read_scalar(args[2])?.to_f32()?; + let res = (a*b).value + c; this.write_scalar( - Scalar::from_f32(a * b + c), + Scalar::from_f32(res.value), dest, )?; } @@ -351,26 +356,29 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let a = this.read_scalar(args[0])?.to_f64()?; let b = this.read_scalar(args[1])?.to_f64()?; let c = this.read_scalar(args[2])?.to_f64()?; + let res = (a*b).value + c; this.write_scalar( - Scalar::from_f64(a * b + c), + Scalar::from_f64(res.value), dest, )?; } "powif32" => { - let f = this.read_scalar(args[0])?.to_f32()?; + // FIXME: Using host floats. + let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); let i = this.read_scalar(args[1])?.to_i32()?; this.write_scalar( - Scalar::from_f32(f.powi(i)), + Scalar::from_u32(f.powi(i).to_bits()), dest, )?; } "powif64" => { - let f = this.read_scalar(args[0])?.to_f64()?; + // FIXME: Using host floats. + let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); let i = this.read_scalar(args[1])?.to_i32()?; this.write_scalar( - Scalar::from_f64(f.powi(i)), + Scalar::from_u64(f.powi(i).to_bits()), dest, )?; } From 5e07ac335fe75aafd34394ff95bb2f153c11c967 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Jun 2019 00:19:05 +0200 Subject: [PATCH 0807/5092] implement min and max floating point intrinsics --- src/intrinsic.rs | 23 +++++++++++++++++++++++ src/lib.rs | 4 ++-- tests/run-pass/floats.rs | 15 ++++++++++++++- 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index faaa15d3ba96..a28c99db6bfa 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -1,3 +1,4 @@ +use rustc_apfloat::Float; use rustc::mir; use rustc::mir::interpret::{InterpResult, PointerArithmetic}; use rustc::ty::layout::{self, LayoutOf, Size}; @@ -242,6 +243,28 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.binop_ignore_overflow(op, a, b, dest)?; } + "minnumf32" | "maxnumf32" => { + let a = this.read_scalar(args[0])?.to_f32()?; + let b = this.read_scalar(args[1])?.to_f32()?; + let res = if intrinsic_name.get().starts_with("min") { + a.min(b) + } else { + a.max(b) + }; + this.write_scalar(Scalar::from_f32(res), dest)?; + } + + "minnumf64" | "maxnumf64" => { + let a = this.read_scalar(args[0])?.to_f64()?; + let b = this.read_scalar(args[1])?.to_f64()?; + let res = if intrinsic_name.get().starts_with("min") { + a.min(b) + } else { + a.max(b) + }; + this.write_scalar(Scalar::from_f64(res), dest)?; + } + "exact_div" => { // Performs an exact division, resulting in undefined behavior where // `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1` diff --git a/src/lib.rs b/src/lib.rs index d0b7111bb069..d2b20db06d3c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,8 +6,8 @@ extern crate log; // From rustc. extern crate syntax; -#[macro_use] -extern crate rustc; +extern crate rustc_apfloat; +#[macro_use] extern crate rustc; extern crate rustc_data_structures; extern crate rustc_mir; extern crate rustc_target; diff --git a/tests/run-pass/floats.rs b/tests/run-pass/floats.rs index 39fdbce49202..c1588dae249a 100644 --- a/tests/run-pass/floats.rs +++ b/tests/run-pass/floats.rs @@ -1,4 +1,3 @@ - fn main() { assert_eq!(6.0_f32*6.0_f32, 36.0_f32); assert_eq!(6.0_f64*6.0_f64, 36.0_f64); @@ -12,4 +11,18 @@ fn main() { assert_eq!(5.0f32 as u32, 5); assert_eq!(5.0f32 as i32, 5); assert_eq!(-5.0f32 as i32, -5); + + assert_eq!((1.0 as f32).max(-1.0), 1.0); + assert_eq!((1.0 as f32).min(-1.0), -1.0); + assert_eq!(std::f32::NAN.min(9.0), 9.0); + assert_eq!(std::f32::NAN.max(-9.0), -9.0); + assert_eq!((9.0 as f32).min(std::f32::NAN), 9.0); + assert_eq!((-9.0 as f32).max(std::f32::NAN), -9.0); + + assert_eq!((1.0 as f64).max(-1.0), 1.0); + assert_eq!((1.0 as f64).min(-1.0), -1.0); + assert_eq!(std::f64::NAN.min(9.0), 9.0); + assert_eq!(std::f64::NAN.max(-9.0), -9.0); + assert_eq!((9.0 as f64).min(std::f64::NAN), 9.0); + assert_eq!((-9.0 as f64).max(std::f64::NAN), -9.0); } From a37953752d325e3a08ee7db27709a9d9c170b0ff Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 10 Jun 2019 09:49:06 +0200 Subject: [PATCH 0808/5092] use apfloat's FMA primitive --- src/intrinsic.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index a28c99db6bfa..451a97eeed72 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -368,9 +368,9 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let a = this.read_scalar(args[0])?.to_f32()?; let b = this.read_scalar(args[1])?.to_f32()?; let c = this.read_scalar(args[2])?.to_f32()?; - let res = (a*b).value + c; + let res = a.mul_add(b, c).value; this.write_scalar( - Scalar::from_f32(res.value), + Scalar::from_f32(res), dest, )?; } @@ -379,9 +379,9 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let a = this.read_scalar(args[0])?.to_f64()?; let b = this.read_scalar(args[1])?.to_f64()?; let c = this.read_scalar(args[2])?.to_f64()?; - let res = (a*b).value + c; + let res = a.mul_add(b, c).value; this.write_scalar( - Scalar::from_f64(res.value), + Scalar::from_f64(res), dest, )?; } From 9c9a947bf4b90623a9db50c9349808b45ca2fc11 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 10 Jun 2019 09:50:47 +0200 Subject: [PATCH 0809/5092] test more enum-int-cast code paths --- tests/run-pass/c_enums.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/c_enums.rs b/tests/run-pass/c_enums.rs index 11897b73eb2a..16b795342eab 100644 --- a/tests/run-pass/c_enums.rs +++ b/tests/run-pass/c_enums.rs @@ -11,11 +11,13 @@ enum Signed { } fn foo() -> [u8; 3] { - [Foo::Bar as u8, Foo::Baz as u8, Foo::Quux as u8] + let baz = Foo::Baz; // let-expansion changes the MIR significantly + [Foo::Bar as u8, baz as u8, Foo::Quux as u8] } fn signed() -> [i8; 3] { - [Signed::Bar as i8, Signed::Baz as i8, Signed::Quux as i8] + let baz = Signed::Baz; // let-expansion changes the MIR significantly + [Signed::Bar as i8, baz as i8, Signed::Quux as i8] } fn unsafe_match() -> bool { From e2f114a5e071a1785024fdaf6260b656b226a696 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 10 Jun 2019 09:57:01 +0200 Subject: [PATCH 0810/5092] test FMA a bit more --- tests/run-pass/intrinsics-math.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/intrinsics-math.rs b/tests/run-pass/intrinsics-math.rs index a2c55634749c..6b3d15a5091f 100644 --- a/tests/run-pass/intrinsics-math.rs +++ b/tests/run-pass/intrinsics-math.rs @@ -50,8 +50,10 @@ pub fn main() { assert_approx_eq!(8f32.log2(), 3f32); assert_approx_eq!(f64::consts::E.log2(), f64::consts::LOG2_E); - assert_approx_eq!(1.0f32.mul_add(2.0f32, 5.0f32), 7.0f32); - assert_approx_eq!(0.0f64.mul_add(-2.0f64, f64::consts::E), f64::consts::E); + assert_approx_eq!(3.0f32.mul_add(2.0f32, 5.0f32), 11.0); + assert_eq!(0.0f32.mul_add(-2.0, f32::consts::E), f32::consts::E); + assert_approx_eq!(3.0f64.mul_add(2.0, 5.0), 11.0); + assert_eq!(0.0f64.mul_add(-2.0f64, f64::consts::E), f64::consts::E); assert_approx_eq!((-1.0f32).abs(), 1.0f32); assert_approx_eq!(34.2f64.abs(), 34.2f64); From 6a0d092eaf3150a4ae2e509744c49d5cadc60efc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 11 Jun 2019 19:42:01 +0200 Subject: [PATCH 0811/5092] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index b72e1f53ef1f..8ef35afca054 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1cbd8a4d686d1411105f26cddf876c5994e69593 +8e948df707ea8a3c88c65bf2ffdcb2f1cf5491be From 8f670e6b8bb343268c87143ecc8faa19bca7dd31 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Jun 2019 18:19:50 +0200 Subject: [PATCH 0812/5092] test rand a bit more --- test-cargo-miri/src/main.rs | 6 ++++-- test-cargo-miri/tests/test.rs | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index 9ec8e85887a7..c21547c29ff9 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -19,7 +19,9 @@ mod test { fn rng() { let mut rng = rand::rngs::StdRng::seed_from_u64(0xcafebeef); let x: u32 = rng.gen(); - let y: u32 = rng.gen(); - assert_ne!(x, y); + let y: usize = rng.gen(); + let z: u128 = rng.gen(); + assert_ne!(x as usize, y); + assert_ne!(y as u128, z); } } diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index ed9efa21e4fa..31425d5ad973 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -7,17 +7,19 @@ fn simple() { assert_eq!(4, 4); } -// Having more than 1 test does seem to make a difference -// (i.e., this calls ptr::swap which having just one test does not). #[test] fn entropy_rng() { // Use this opportunity to test querying the RNG (needs an external crate, hence tested here and not in the compiletest suite) let mut rng = SmallRng::from_entropy(); let _val = rng.gen::(); + let _val = rng.gen::(); + let _val = rng.gen::(); // Also try per-thread RNG. let mut rng = rand::thread_rng(); let _val = rng.gen::(); + let _val = rng.gen::(); + let _val = rng.gen::(); } // A test that won't work on miri From f72f53c3adfbcfb5977429a4b81d08c9cd327cc1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Jun 2019 18:30:05 +0200 Subject: [PATCH 0813/5092] bump rand so that the test passes --- test-cargo-miri/Cargo.lock | 235 +++++++++++++--------------------- test-cargo-miri/Cargo.toml | 2 +- test-cargo-miri/tests/test.rs | 2 +- 3 files changed, 94 insertions(+), 145 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 76fb04c6672a..972b6bf074de 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -2,25 +2,34 @@ # It is not intended for manual editing. [[package]] name = "autocfg" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bitflags" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "byteorder" -version = "1.0.0" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "c2-chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cargo-miri-test" version = "0.1.0" dependencies = [ - "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -28,7 +37,7 @@ name = "cloudabi" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -37,138 +46,83 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "libc" -version = "0.2.48" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_jitter 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_chacha" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rand_hc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_jitter" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_os" -version = "0.1.2" +name = "getrandom" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lazy_static" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.58" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "ppv-lite86" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand" +version = "0.7.0-pre.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_pcg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_chacha" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_pcg" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "winapi" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -186,26 +140,21 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] -"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" -"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" -"checksum byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c40977b0ee6b9885c9013cd41d9feffdd22deb3bb4dc3a71d901cc7a77de18c8" +"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" +"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" +"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" +"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047" -"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" -"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -"checksum rand_jitter 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "080723c6145e37503a2224f801f252e14ac5531cb450f4502698542d188cb3c0" -"checksum rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b7c690732391ae0abafced5015ffb53656abfaec61b342290e5eb56b286a679d" -"checksum rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05" -"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" +"checksum getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8d1dffef07351aafe6ef177e4dd2b8dcf503e6bc765dea3b0de9ed149a3db1ec" +"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" +"checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319" +"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" +"checksum rand 0.7.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)" = "866531c9bb6613da04a1e6ad99d27a7c8acd488020d7a8b177b058a10c900eec" +"checksum rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e193067942ef6f485a349a113329140d0ab9e2168ce92274499bb0e9a4190d9d" +"checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" +"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +"checksum rand_pcg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e196346cbbc5c70c77e7b4926147ee8e383a38ee4d15d58a08098b169e492b6" +"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 04f259a0aedb..607514b995f6 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -8,4 +8,4 @@ edition = "2018" byteorder = "1.0" [dev-dependencies] -rand = "0.6.5" +rand = { version = "0.7.0-pre.0", features = ["small_rng"] } diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 31425d5ad973..ac0db2778cae 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -1,4 +1,4 @@ -use rand::{FromEntropy, Rng, rngs::SmallRng}; +use rand::{SeedableRng, Rng, rngs::SmallRng}; // Having more than 1 test does seem to make a difference // (i.e., this calls ptr::swap which having just one test does not). From 535914e3dcd65fd2bb2cbb02f505ef200169a547 Mon Sep 17 00:00:00 2001 From: Kenny Goodin Date: Wed, 5 Jun 2019 01:26:46 -0400 Subject: [PATCH 0814/5092] Implement cbrt and hypot function calls Test cases are added to `tests/run-pass/intrinsics-math.rs` --- src/fn_call.rs | 14 ++++++++++++++ tests/run-pass/intrinsics-math.rs | 3 +++ 2 files changed, 17 insertions(+) diff --git a/src/fn_call.rs b/src/fn_call.rs index 3d2c523bf705..b6b35bfc005e 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -560,6 +560,20 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' let n = this.memory().get(ptr.alloc_id)?.read_c_str(tcx, ptr)?.len(); this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; } + "cbrt" => { + // FIXME: Using host floats. + let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); + let n = f.cbrt(); + this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?; + } + // underscore case for windows + "_hypot" | "hypot" => { + // FIXME: Using host floats. + let f1 = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); + let f2 = f64::from_bits(this.read_scalar(args[1])?.to_u64()?); + let n = f1.hypot(f2); + this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?; + } // Some things needed for `sys::thread` initialization to go through. "signal" | "sigaction" | "sigaltstack" => { diff --git a/tests/run-pass/intrinsics-math.rs b/tests/run-pass/intrinsics-math.rs index 6b3d15a5091f..504ef4789795 100644 --- a/tests/run-pass/intrinsics-math.rs +++ b/tests/run-pass/intrinsics-math.rs @@ -66,4 +66,7 @@ pub fn main() { assert_approx_eq!(0.1f32.trunc(), 0.0f32); assert_approx_eq!((-0.1f64).trunc(), 0.0f64); + + assert_approx_eq!(27f64.cbrt(), 3.0f64); + assert_approx_eq!(3f64.hypot(4f64), 5.0f64); } From 118274f300d60d8a450cdbc16a72101efde23b12 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 13 Jun 2019 08:43:35 +0200 Subject: [PATCH 0815/5092] README: mention to cargo update, mention rustup-toolchain-install-master --- README.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 090694128e3a..82fe738e0310 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,11 @@ Install Miri via `rustup`: rustup component add miri ``` -If `rustup` says the `miri` component is unavailable, that's because not all nightly releases come with all tools. Check out [this website](https://rust-lang.github.io/rustup-components-history) to determine a nightly version that comes with Miri and install that, e.g. using `rustup install nightly-2019-03-28`. +If `rustup` says the `miri` component is unavailable, that's because not all +nightly releases come with all tools. Check out +[this website](https://rust-lang.github.io/rustup-components-history) to +determine a nightly version that comes with Miri and install that, e.g. using +`rustup install nightly-2019-03-28`. Now you can run your project in Miri: @@ -131,7 +135,17 @@ able to just `cargo build` Miri. In case this fails, your nightly might be incompatible with Miri master. The `rust-version` file contains the commit hash of rustc that Miri is currently tested against; you can use that to find a nightly that works or you might have -to wait for the next nightly to get released. +to wait for the next nightly to get released. You can also use +[`rustup-toolchain-install-master`](https://github.com/kennytm/rustup-toolchain-install-master) +to install that exact version of rustc as a toolchain: +``` +rustup-toolchain-install-master $(cat rust-version) -c rust-src +``` + +Another common problem is outdated dependencies: Miri does not come with a +lockfile (it cannot, due to how it gets embedded into the rustc build). So you +have to run `cargo update` every now and then yourself to make sure you are +using the latest versions of everything (which is what gets tested on CI). ### Testing the Miri driver [testing-miri]: #testing-the-miri-driver From ad0c941547e36a9f2eb4c5ef254ba0e87817b0b6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 13 Jun 2019 08:52:04 +0200 Subject: [PATCH 0816/5092] rustup for lifetime refactorings --- rust-version | 2 +- src/bin/miri-rustc-tests.rs | 4 ++-- src/fn_call.rs | 8 +++---- src/helpers.rs | 16 ++++++------- src/intrinsic.rs | 4 ++-- src/lib.rs | 46 ++++++++++++++++++------------------- src/operator.rs | 2 +- src/stacked_borrows.rs | 20 ++++++++-------- src/tls.rs | 4 ++-- 9 files changed, 53 insertions(+), 53 deletions(-) diff --git a/rust-version b/rust-version index 8ef35afca054..b945d0b3a265 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8e948df707ea8a3c88c65bf2ffdcb2f1cf5491be +d8f50ab0ea6c529c24e575279acc72093caeb679 diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index cf50f8125c4b..e8714123ceb0 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -43,8 +43,8 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { compiler.session().abort_if_errors(); compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| { if std::env::args().any(|arg| arg == "--test") { - struct Visitor<'a, 'tcx: 'a>(TyCtxt<'a, 'tcx, 'tcx>); - impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> { + struct Visitor<'tcx>(TyCtxt<'tcx, 'tcx>); + impl<'tcx, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.node { if i.attrs.iter().any(|attr| attr.check_name(syntax::symbol::sym::test)) { diff --git a/src/fn_call.rs b/src/fn_call.rs index b6b35bfc005e..4c40d24f7ff5 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -9,8 +9,8 @@ use rand::RngCore; use crate::*; -impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} -pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn find_fn( &mut self, instance: ty::Instance<'tcx>, @@ -930,8 +930,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } } -fn gen_random<'a, 'mir, 'tcx>( - this: &mut MiriEvalContext<'a, 'mir, 'tcx>, +fn gen_random<'mir, 'tcx>( + this: &mut MiriEvalContext<'mir, 'tcx>, len: usize, dest: Scalar, ) -> InterpResult<'tcx> { diff --git a/src/helpers.rs b/src/helpers.rs index 29bc1def9fda..62a546767e89 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -5,9 +5,9 @@ use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use crate::*; -impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} -pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Gets an instance for a path. fn resolve_path(&self, path: &[&str]) -> InterpResult<'tcx, ty::Instance<'tcx>> { let this = self.eval_context_ref(); @@ -119,24 +119,24 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' /// Visiting the memory covered by a `MemPlace`, being aware of /// whether we are inside an `UnsafeCell` or not. - struct UnsafeCellVisitor<'ecx, 'a, 'mir, 'tcx, F> + struct UnsafeCellVisitor<'ecx, 'mir, 'tcx, F> where F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { - ecx: &'ecx MiriEvalContext<'a, 'mir, 'tcx>, + ecx: &'ecx MiriEvalContext<'mir, 'tcx>, unsafe_cell_action: F, } - impl<'ecx, 'a, 'mir, 'tcx, F> - ValueVisitor<'a, 'mir, 'tcx, Evaluator<'tcx>> + impl<'ecx, 'mir, 'tcx, F> + ValueVisitor<'mir, 'tcx, Evaluator<'tcx>> for - UnsafeCellVisitor<'ecx, 'a, 'mir, 'tcx, F> + UnsafeCellVisitor<'ecx, 'mir, 'tcx, F> where F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { type V = MPlaceTy<'tcx, Tag>; #[inline(always)] - fn ecx(&self) -> &MiriEvalContext<'a, 'mir, 'tcx> { + fn ecx(&self) -> &MiriEvalContext<'mir, 'tcx> { &self.ecx } diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 451a97eeed72..cd89055b467a 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -9,8 +9,8 @@ use crate::{ OperatorEvalContextExt }; -impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} -pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn call_intrinsic( &mut self, instance: ty::Instance<'tcx>, diff --git a/src/lib.rs b/src/lib.rs index d2b20db06d3c..822b173e34a0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -71,11 +71,11 @@ pub struct MiriConfig { } // Used by priroda. -pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub fn create_ecx<'mir, 'tcx: 'mir>( + tcx: TyCtxt<'tcx, 'tcx>, main_id: DefId, config: MiriConfig, -) -> InterpResult<'tcx, InterpretCx<'a, 'mir, 'tcx, Evaluator<'tcx>>> { +) -> InterpResult<'tcx, InterpretCx<'mir, 'tcx, Evaluator<'tcx>>> { let mut ecx = InterpretCx::new( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), @@ -211,8 +211,8 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( Ok(ecx) } -pub fn eval_main<'a, 'tcx: 'a>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub fn eval_main<'tcx>( + tcx: TyCtxt<'tcx, 'tcx>, main_id: DefId, config: MiriConfig, ) { @@ -364,25 +364,25 @@ impl<'tcx> Evaluator<'tcx> { // FIXME: rustc issue . #[allow(dead_code)] -type MiriEvalContext<'a, 'mir, 'tcx> = InterpretCx<'a, 'mir, 'tcx, Evaluator<'tcx>>; +type MiriEvalContext<'mir, 'tcx> = InterpretCx<'mir, 'tcx, Evaluator<'tcx>>; // A little trait that's useful to be inherited by extension traits. -pub trait MiriEvalContextExt<'a, 'mir, 'tcx> { - fn eval_context_ref(&self) -> &MiriEvalContext<'a, 'mir, 'tcx>; - fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'a, 'mir, 'tcx>; +pub trait MiriEvalContextExt<'mir, 'tcx> { + fn eval_context_ref(&self) -> &MiriEvalContext<'mir, 'tcx>; + fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'mir, 'tcx>; } -impl<'a, 'mir, 'tcx> MiriEvalContextExt<'a, 'mir, 'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { +impl<'mir, 'tcx> MiriEvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> { #[inline(always)] - fn eval_context_ref(&self) -> &MiriEvalContext<'a, 'mir, 'tcx> { + fn eval_context_ref(&self) -> &MiriEvalContext<'mir, 'tcx> { self } #[inline(always)] - fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'a, 'mir, 'tcx> { + fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'mir, 'tcx> { self } } -impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { +impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryKinds = MiriMemoryKind; type FrameExtra = stacked_borrows::CallId; @@ -395,14 +395,14 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { const STATIC_KIND: Option = Some(MiriMemoryKind::Static); #[inline(always)] - fn enforce_validity(ecx: &InterpretCx<'a, 'mir, 'tcx, Self>) -> bool { + fn enforce_validity(ecx: &InterpretCx<'mir, 'tcx, Self>) -> bool { ecx.machine.validate } /// Returns `Ok()` when the function was handled; fail otherwise. #[inline(always)] fn find_fn( - ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], dest: Option>, @@ -413,7 +413,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn call_intrinsic( - ecx: &mut rustc_mir::interpret::InterpretCx<'a, 'mir, 'tcx, Self>, + ecx: &mut rustc_mir::interpret::InterpretCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, @@ -423,7 +423,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn ptr_op( - ecx: &rustc_mir::interpret::InterpretCx<'a, 'mir, 'tcx, Self>, + ecx: &rustc_mir::interpret::InterpretCx<'mir, 'tcx, Self>, bin_op: mir::BinOp, left: ImmTy<'tcx, Tag>, right: ImmTy<'tcx, Tag>, @@ -432,7 +432,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { } fn box_alloc( - ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'mir, 'tcx, Self>, dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { trace!("box_alloc for {:?}", dest.layout.ty); @@ -475,7 +475,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn find_foreign_static( def_id: DefId, - tcx: TyCtxtAt<'a, 'tcx, 'tcx>, + tcx: TyCtxtAt<'tcx, 'tcx>, ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { @@ -498,7 +498,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { } #[inline(always)] - fn before_terminator(_ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>) -> InterpResult<'tcx> + fn before_terminator(_ecx: &mut InterpretCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { // We are not interested in detecting loops. Ok(()) @@ -550,7 +550,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn retag( - ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'mir, 'tcx, Self>, kind: mir::RetagKind, place: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { @@ -568,14 +568,14 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn stack_push( - ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'mir, 'tcx, Self>, ) -> InterpResult<'tcx, stacked_borrows::CallId> { Ok(ecx.memory().extra.borrow_mut().new_call()) } #[inline(always)] fn stack_pop( - ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'mir, 'tcx, Self>, extra: stacked_borrows::CallId, ) -> InterpResult<'tcx> { Ok(ecx.memory().extra.borrow_mut().end_call(extra)) diff --git a/src/operator.rs b/src/operator.rs index 411df2155de0..336f945c7847 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -33,7 +33,7 @@ pub trait EvalContextExt<'tcx> { ) -> InterpResult<'tcx, Scalar>; } -impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { +impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { fn ptr_op( &self, bin_op: mir::BinOp, diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index bd8158479019..f7617676701c 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -519,8 +519,8 @@ impl AllocationExtra for Stacks { /// Retagging/reborrowing. There is some policy in here, such as which permissions /// to grant for which references, and when to add protectors. -impl<'a, 'mir, 'tcx> EvalContextPrivExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} -trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { +impl<'mir, 'tcx> EvalContextPrivExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn reborrow( &mut self, place: MPlaceTy<'tcx, Tag>, @@ -599,8 +599,8 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } } -impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} -pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn retag( &mut self, kind: RetagKind, @@ -643,19 +643,19 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, visitor.visit_value(place)?; // The actual visitor. - struct RetagVisitor<'ecx, 'a, 'mir, 'tcx> { - ecx: &'ecx mut MiriEvalContext<'a, 'mir, 'tcx>, + struct RetagVisitor<'ecx, 'mir, 'tcx> { + ecx: &'ecx mut MiriEvalContext<'mir, 'tcx>, kind: RetagKind, } - impl<'ecx, 'a, 'mir, 'tcx> - MutValueVisitor<'a, 'mir, 'tcx, Evaluator<'tcx>> + impl<'ecx, 'mir, 'tcx> + MutValueVisitor<'mir, 'tcx, Evaluator<'tcx>> for - RetagVisitor<'ecx, 'a, 'mir, 'tcx> + RetagVisitor<'ecx, 'mir, 'tcx> { type V = MPlaceTy<'tcx, Tag>; #[inline(always)] - fn ecx(&mut self) -> &mut MiriEvalContext<'a, 'mir, 'tcx> { + fn ecx(&mut self) -> &mut MiriEvalContext<'mir, 'tcx> { &mut self.ecx } diff --git a/src/tls.rs b/src/tls.rs index 4101a3ab39b7..ddc301447c7e 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -129,8 +129,8 @@ impl<'tcx> TlsData<'tcx> { } } -impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} -pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn run_tls_dtors(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let mut dtor = this.machine.tls.fetch_tls_dtor(None, &*this.tcx); From 46b6a3fb7fbe10af1d5e8b2c527500130a4e317a Mon Sep 17 00:00:00 2001 From: Kenny Goodin Date: Thu, 13 Jun 2019 14:11:35 -0400 Subject: [PATCH 0817/5092] Add more missing math functions Add missing functions for atan2, cosh, sinh, and tan. Also add f32 calls and tests for cbrt and hypot. --- src/fn_call.rs | 50 +++++++++++++++++++++++++++---- tests/run-pass/intrinsics-math.rs | 20 +++++++++++-- 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 4c40d24f7ff5..d7e52b483032 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -560,18 +560,56 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let n = this.memory().get(ptr.alloc_id)?.read_c_str(tcx, ptr)?.len(); this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; } - "cbrt" => { + + // math functions + + "cbrtf" | "coshf" | "sinhf" |"tanf" => { // FIXME: Using host floats. - let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); - let n = f.cbrt(); - this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?; + let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); + let f = match link_name { + "cbrtf" => f.cbrt(), + "coshf" => f.cosh(), + "sinhf" => f.sinh(), + "tanf" => f.tan(), + _ => bug!(), + }; + this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?; } // underscore case for windows - "_hypot" | "hypot" => { + "_hypotf" | "hypotf" | "atan2f" => { + // FIXME: Using host floats. + let f1 = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); + let f2 = f32::from_bits(this.read_scalar(args[1])?.to_u32()?); + let n = match link_name { + "_hypotf" | "hypotf" => f1.hypot(f2), + "atan2f" => f1.atan2(f2), + _ => bug!(), + }; + this.write_scalar(Scalar::from_u32(n.to_bits()), dest)?; + } + + "cbrt" | "cosh" | "sinh" | "tan" => { + // FIXME: Using host floats. + let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); + let f = match link_name { + "cbrt" => f.cbrt(), + "cosh" => f.cosh(), + "sinh" => f.sinh(), + "tan" => f.tan(), + _ => bug!(), + }; + this.write_scalar(Scalar::from_u64(f.to_bits()), dest)?; + } + // underscore case for windows + "_hypot" | "hypot" | "atan2" => { // FIXME: Using host floats. let f1 = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); let f2 = f64::from_bits(this.read_scalar(args[1])?.to_u64()?); - let n = f1.hypot(f2); + let n = match link_name { + "_hypot" | "hypot" => f1.hypot(f2), + "atan2" => f1.atan2(f2), + _ => bug!(), + }; this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?; } diff --git a/tests/run-pass/intrinsics-math.rs b/tests/run-pass/intrinsics-math.rs index 504ef4789795..20c0f6749488 100644 --- a/tests/run-pass/intrinsics-math.rs +++ b/tests/run-pass/intrinsics-math.rs @@ -67,6 +67,22 @@ pub fn main() { assert_approx_eq!(0.1f32.trunc(), 0.0f32); assert_approx_eq!((-0.1f64).trunc(), 0.0f64); - assert_approx_eq!(27f64.cbrt(), 3.0f64); - assert_approx_eq!(3f64.hypot(4f64), 5.0f64); + assert_approx_eq!(27.0f32.cbrt(), 3.0f32); + assert_approx_eq!(27.0f64.cbrt(), 3.0f64); + + assert_approx_eq!(3.0f32.hypot(4.0f32), 5.0f32); + assert_approx_eq!(3.0f64.hypot(4.0f64), 5.0f64); + + assert_approx_eq!(1.0f32.atan2(2.0f32), 0.46364761f32); + assert_approx_eq!(1.0f32.atan2(2.0f32), 0.46364761f32); + + assert_approx_eq!(1.0f32.cosh(), 1.54308f32); + assert_approx_eq!(1.0f64.cosh(), 1.54308f64); + + assert_approx_eq!(1.0f32.sinh(), 1.1752012f32); + assert_approx_eq!(1.0f64.sinh(), 1.1752012f64); + + assert_approx_eq!(1.0f32.tan(), 1.557408f32); + assert_approx_eq!(1.0f64.tan(), 1.557408f64); + } From 4db0eea010e7f490935b01e04feeedd4dc7dadf2 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 14 Jun 2019 10:44:08 +0200 Subject: [PATCH 0818/5092] Fix indentation --- src/fn_call.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index d7e52b483032..eca1d9144ec4 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -570,7 +570,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "cbrtf" => f.cbrt(), "coshf" => f.cosh(), "sinhf" => f.sinh(), - "tanf" => f.tan(), + "tanf" => f.tan(), _ => bug!(), }; this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?; From ac2f6cbcde00eebcb696143e76177c1600f63410 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 14 Jun 2019 11:15:09 +0200 Subject: [PATCH 0819/5092] change sysroot check to print the output in case of an error --- src/bin/cargo-miri.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 121930bccce6..3b7af9324194 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -133,11 +133,12 @@ fn test_sysroot_consistency() { fn get_sysroot(mut cmd: Command) -> PathBuf { let out = cmd.arg("--print").arg("sysroot") .output().expect("Failed to run rustc to get sysroot info"); - assert!(out.status.success(), "Bad status code when getting sysroot info"); - let sysroot = out.stdout.lines().nth(0) - .expect("didn't get at least one line for the sysroot").unwrap(); - PathBuf::from(sysroot).canonicalize() - .expect("Failed to canonicalize sysroot") + let stdout = String::from_utf8(out.stdout).expect("stdout is not valid UTF-8"); + let stderr = String::from_utf8(out.stderr).expect("stderr is not valid UTF-8"); + let stdout = stdout.trim(); + assert!(out.status.success(), "Bad status code when getting sysroot info.\nstdout:\n{}\nstderr:\n{}", stdout, stderr); + PathBuf::from(stdout).canonicalize() + .unwrap_or_else(|_| panic!("Failed to canonicalize sysroot: {}", stdout)) } let rustc_sysroot = get_sysroot(Command::new("rustc")); From 34b0922cec2eac41c7c204ca234fcd4a85b08615 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 14 Jun 2019 12:09:43 +0200 Subject: [PATCH 0820/5092] fix running a Miri that was built in bootstrap --- src/bin/miri.rs | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 6346b2340b08..5a425baf0f61 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -102,21 +102,26 @@ fn init_late_loggers() { /// Returns the "default sysroot" that Miri will use if no `--sysroot` flag is set. /// Should be a compile-time constant. -fn compile_time_sysroot() -> String { +fn compile_time_sysroot() -> Option { + if option_env!("RUSTC_STAGE").is_some() { + // This is being built as part of rustc, and gets shipped with rustup. + // We can rely on the sysroot computation in librustc. + return None; + } + // For builds outside rustc, we need to ensure that we got a sysroot + // that gets used as a default. The sysroot computation in librustc would + // end up somewhere in the build dir. // Taken from PR . let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); - match (home, toolchain) { + Some(match (home, toolchain) { (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain), _ => { option_env!("RUST_SYSROOT") - .expect( - "could not find sysroot. Either set `MIRI_SYSROOT` at run-time, or at \ - build-time specify `RUST_SYSROOT` env var or use rustup or multirust", - ) + .expect("To build Miri without rustup, set the `RUST_SYSROOT` env var at build time") .to_owned() } - } + }) } fn main() { @@ -165,14 +170,17 @@ fn main() { } } - // Determine sysroot. - let sysroot_flag = "--sysroot".to_string(); - if !rustc_args.contains(&sysroot_flag) { - // We need to *always* set a --sysroot, as the "default" rustc uses is - // somewhere in the directory miri was built in. - // If no --sysroot is given, fall back to env vars that are read at *compile-time*. - rustc_args.push(sysroot_flag); - rustc_args.push(compile_time_sysroot()); + // Determine sysroot if needed. Make sure we always call `compile_time_sysroot` + // as that also does some sanity-checks of the environment we were built in. + // FIXME: Ideally we'd turn a bad build env into a compile-time error, but + // CTFE does not seem powerful enough for that yet. + if let Some(sysroot) = compile_time_sysroot() { + let sysroot_flag = "--sysroot".to_string(); + if !rustc_args.contains(&sysroot_flag) { + // We need to overwrite the default that librustc would compute. + rustc_args.push(sysroot_flag); + rustc_args.push(sysroot); + } } // Finally, add the default flags all the way in the beginning, but after the binary name. From fd0dccd4b12169e0aac42aff8addbb26b6d72197 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sat, 15 Jun 2019 02:34:11 +0700 Subject: [PATCH 0821/5092] Fix wrong lifetime of TyCtxt Rustup rust-lang/rust#61817 --- rust-version | 2 +- src/bin/miri-rustc-tests.rs | 2 +- src/lib.rs | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index b945d0b3a265..e60eb6c94954 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d8f50ab0ea6c529c24e575279acc72093caeb679 +9606f6fa64926a84d82e3c62dbdc57f5c10f756d diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index e8714123ceb0..9b0d02f4b7e2 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -43,7 +43,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { compiler.session().abort_if_errors(); compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| { if std::env::args().any(|arg| arg == "--test") { - struct Visitor<'tcx>(TyCtxt<'tcx, 'tcx>); + struct Visitor<'tcx>(TyCtxt<'tcx>); impl<'tcx, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.node { diff --git a/src/lib.rs b/src/lib.rs index 822b173e34a0..061b07478a28 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -72,7 +72,7 @@ pub struct MiriConfig { // Used by priroda. pub fn create_ecx<'mir, 'tcx: 'mir>( - tcx: TyCtxt<'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig, ) -> InterpResult<'tcx, InterpretCx<'mir, 'tcx, Evaluator<'tcx>>> { @@ -212,7 +212,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } pub fn eval_main<'tcx>( - tcx: TyCtxt<'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig, ) { @@ -475,7 +475,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn find_foreign_static( def_id: DefId, - tcx: TyCtxtAt<'tcx, 'tcx>, + tcx: TyCtxtAt<'tcx>, ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { From a561f949ad214080054295035e5453c23c5a6ca5 Mon Sep 17 00:00:00 2001 From: soc Date: Fri, 14 Jun 2019 23:17:27 +0200 Subject: [PATCH 0822/5092] Fix project dirs path ProjectDirs::from("miri", "miri", "miri") would get you `miri\miri` on Windows and `miri.miri.miri` on macOS. I'm assuming here that your intention was to have only a `miri` directory on every OS. --- .appveyor.yml | 2 +- src/bin/cargo-miri.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index d13ce2b3974d..fe450922e044 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -36,7 +36,7 @@ build_script: - cargo install --all-features --force --path . --locked --offline # Get ourselves a MIR-full libstd, and use it henceforth - cargo miri setup - - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\miri\miri\cache\HOST + - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\miri\cache\HOST test_script: # Test miri diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 3b7af9324194..0b2662fe3fb0 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -248,7 +248,7 @@ fn setup(ask_user: bool) { } // Next, we need our own libstd. We will do this work in whatever is a good cache dir for this platform. - let dirs = directories::ProjectDirs::from("miri", "miri", "miri").unwrap(); + let dirs = directories::ProjectDirs::from("", "", "miri").unwrap(); let dir = dirs.cache_dir(); if !dir.exists() { fs::create_dir_all(&dir).unwrap(); From d210ed7e122632b0904f8c077b94459fda92012f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Jun 2019 09:49:27 +0200 Subject: [PATCH 0823/5092] bump rustc yet again --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index e60eb6c94954..9d2a8772234b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9606f6fa64926a84d82e3c62dbdc57f5c10f756d +374c63e0fc356eb61b1966cb6026a2a49fe9226d From fc901244890cf2c0218027189d9d2311026dabbd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Jun 2019 10:51:08 +0200 Subject: [PATCH 0824/5092] test exact_div UB detection --- src/intrinsic.rs | 8 +++++++- tests/compile-fail/exact_div1.rs | 5 +++++ tests/compile-fail/exact_div2.rs | 5 +++++ tests/compile-fail/exact_div3.rs | 5 +++++ tests/compile-fail/exact_div4.rs | 5 +++++ 5 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/exact_div1.rs create mode 100644 tests/compile-fail/exact_div2.rs create mode 100644 tests/compile-fail/exact_div3.rs create mode 100644 tests/compile-fail/exact_div4.rs diff --git a/src/intrinsic.rs b/src/intrinsic.rs index cd89055b467a..cf2afe0a811a 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -272,7 +272,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let b = this.read_immediate(args[1])?; // check x % y != 0 if this.binary_op(mir::BinOp::Rem, a, b)?.0.to_bits(dest.layout.size)? != 0 { - return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b))); + // Check if `b` is -1, which is the "min_value / -1" case. + let minus1 = Scalar::from_int(-1, dest.layout.size); + return if b.to_scalar().unwrap() == minus1 { + err!(Intrinsic(format!("exact_div: result of dividing MIN by -1 cannot be represented"))) + } else { + err!(Intrinsic(format!("exact_div: {:?} cannot be divided by {:?} without remainder", *a, *b))) + }; } this.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; }, diff --git a/tests/compile-fail/exact_div1.rs b/tests/compile-fail/exact_div1.rs new file mode 100644 index 000000000000..171bedeadc67 --- /dev/null +++ b/tests/compile-fail/exact_div1.rs @@ -0,0 +1,5 @@ +#![feature(core_intrinsics)] +fn main() { + // divison by 0 + unsafe { std::intrinsics::exact_div(2, 0); } //~ ERROR divisor of zero +} diff --git a/tests/compile-fail/exact_div2.rs b/tests/compile-fail/exact_div2.rs new file mode 100644 index 000000000000..22bcf027dd05 --- /dev/null +++ b/tests/compile-fail/exact_div2.rs @@ -0,0 +1,5 @@ +#![feature(core_intrinsics)] +fn main() { + // divison with a remainder + unsafe { std::intrinsics::exact_div(2u16, 3); } //~ ERROR Scalar(0x0002) cannot be divided by Scalar(0x0003) without remainder +} diff --git a/tests/compile-fail/exact_div3.rs b/tests/compile-fail/exact_div3.rs new file mode 100644 index 000000000000..2db62e0092d5 --- /dev/null +++ b/tests/compile-fail/exact_div3.rs @@ -0,0 +1,5 @@ +#![feature(core_intrinsics)] +fn main() { + // signed divison with a remainder + unsafe { std::intrinsics::exact_div(-19i8, 2); } //~ ERROR Scalar(0xed) cannot be divided by Scalar(0x02) without remainder +} diff --git a/tests/compile-fail/exact_div4.rs b/tests/compile-fail/exact_div4.rs new file mode 100644 index 000000000000..736d4f2516d2 --- /dev/null +++ b/tests/compile-fail/exact_div4.rs @@ -0,0 +1,5 @@ +#![feature(core_intrinsics)] +fn main() { + // divison of min_value by -1 + unsafe { std::intrinsics::exact_div(i64::min_value(), -1); } //~ ERROR result of dividing MIN by -1 cannot be represented +} From cf748149ce6e4a8af1dcb387b6f5a19a856a6579 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Jun 2019 10:53:49 +0200 Subject: [PATCH 0825/5092] test unchecked_rem --- tests/compile-fail/div-by-zero-3.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/compile-fail/div-by-zero-3.rs diff --git a/tests/compile-fail/div-by-zero-3.rs b/tests/compile-fail/div-by-zero-3.rs new file mode 100644 index 000000000000..3200504ddb6e --- /dev/null +++ b/tests/compile-fail/div-by-zero-3.rs @@ -0,0 +1,11 @@ +#![feature(core_intrinsics)] + +use std::intrinsics::*; + +//error-pattern: Division by 0 in unchecked_rem + +fn main() { + unsafe { + let _n = unchecked_rem(3u32, 0); + } +} From 7ce36226e6156e7aaf6da77833fd80cd83d8d623 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Jun 2019 11:10:14 +0200 Subject: [PATCH 0826/5092] implement and test unchecked_{add,sub,mul} intrinsics --- src/intrinsic.rs | 16 +++++++++++ tests/compile-fail/unchecked_add1.rs | 5 ++++ tests/compile-fail/unchecked_add2.rs | 5 ++++ tests/compile-fail/unchecked_mul1.rs | 5 ++++ tests/compile-fail/unchecked_mul2.rs | 5 ++++ tests/compile-fail/unchecked_sub1.rs | 5 ++++ tests/compile-fail/unchecked_sub2.rs | 5 ++++ tests/run-pass/intrinsics-integer.rs | 40 ++++++++++++++++++---------- 8 files changed, 72 insertions(+), 14 deletions(-) create mode 100644 tests/compile-fail/unchecked_add1.rs create mode 100644 tests/compile-fail/unchecked_add2.rs create mode 100644 tests/compile-fail/unchecked_mul1.rs create mode 100644 tests/compile-fail/unchecked_mul2.rs create mode 100644 tests/compile-fail/unchecked_sub1.rs create mode 100644 tests/compile-fail/unchecked_sub2.rs diff --git a/src/intrinsic.rs b/src/intrinsic.rs index cf2afe0a811a..0ecccd02d7e1 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -465,6 +465,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; } + "unchecked_add" | "unchecked_sub" | "unchecked_mul" => { + let l = this.read_immediate(args[0])?; + let r = this.read_immediate(args[1])?; + let op = match intrinsic_name.get() { + "unchecked_add" => mir::BinOp::Add, + "unchecked_sub" => mir::BinOp::Sub, + "unchecked_mul" => mir::BinOp::Mul, + _ => bug!(), + }; + let (res, overflowed) = this.binary_op(op, l, r)?; + if overflowed { + return err!(Intrinsic(format!("Overflowing arithmetic in {}", intrinsic_name.get()))); + } + this.write_scalar(res, dest)?; + } + "uninit" => { // Check fast path: we don't want to force an allocation in case the destination is a simple value, // but we also do not want to create a new allocation with 0s and then copy that over. diff --git a/tests/compile-fail/unchecked_add1.rs b/tests/compile-fail/unchecked_add1.rs new file mode 100644 index 000000000000..2447c8ba4a81 --- /dev/null +++ b/tests/compile-fail/unchecked_add1.rs @@ -0,0 +1,5 @@ +#![feature(core_intrinsics)] +fn main() { + // MAX overflow + unsafe { std::intrinsics::unchecked_add(40000u16, 30000); } //~ ERROR Overflowing arithmetic in unchecked_add +} diff --git a/tests/compile-fail/unchecked_add2.rs b/tests/compile-fail/unchecked_add2.rs new file mode 100644 index 000000000000..e292cdf6d961 --- /dev/null +++ b/tests/compile-fail/unchecked_add2.rs @@ -0,0 +1,5 @@ +#![feature(core_intrinsics)] +fn main() { + // MIN overflow + unsafe { std::intrinsics::unchecked_add(-30000i16, -8000); } //~ ERROR Overflowing arithmetic in unchecked_add +} diff --git a/tests/compile-fail/unchecked_mul1.rs b/tests/compile-fail/unchecked_mul1.rs new file mode 100644 index 000000000000..57bfaf124c24 --- /dev/null +++ b/tests/compile-fail/unchecked_mul1.rs @@ -0,0 +1,5 @@ +#![feature(core_intrinsics)] +fn main() { + // MAX overflow + unsafe { std::intrinsics::unchecked_mul(300u16, 250u16); } //~ ERROR Overflowing arithmetic in unchecked_mul +} diff --git a/tests/compile-fail/unchecked_mul2.rs b/tests/compile-fail/unchecked_mul2.rs new file mode 100644 index 000000000000..690f2dc76284 --- /dev/null +++ b/tests/compile-fail/unchecked_mul2.rs @@ -0,0 +1,5 @@ +#![feature(core_intrinsics)] +fn main() { + // MIN overflow + unsafe { std::intrinsics::unchecked_mul(1_000_000_000i32, -4); } //~ ERROR Overflowing arithmetic in unchecked_mul +} diff --git a/tests/compile-fail/unchecked_sub1.rs b/tests/compile-fail/unchecked_sub1.rs new file mode 100644 index 000000000000..0be8afa2c34c --- /dev/null +++ b/tests/compile-fail/unchecked_sub1.rs @@ -0,0 +1,5 @@ +#![feature(core_intrinsics)] +fn main() { + // MIN overflow + unsafe { std::intrinsics::unchecked_sub(14u32, 22); } //~ ERROR Overflowing arithmetic in unchecked_sub +} diff --git a/tests/compile-fail/unchecked_sub2.rs b/tests/compile-fail/unchecked_sub2.rs new file mode 100644 index 000000000000..bc23fa37c367 --- /dev/null +++ b/tests/compile-fail/unchecked_sub2.rs @@ -0,0 +1,5 @@ +#![feature(core_intrinsics)] +fn main() { + // MAX overflow + unsafe { std::intrinsics::unchecked_sub(30000i16, -7000); } //~ ERROR Overflowing arithmetic in unchecked_sub +} diff --git a/tests/run-pass/intrinsics-integer.rs b/tests/run-pass/intrinsics-integer.rs index de59314eff5a..af3517af6f7a 100644 --- a/tests/run-pass/intrinsics-integer.rs +++ b/tests/run-pass/intrinsics-integer.rs @@ -8,23 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(intrinsics)] - -mod rusti { - extern "rust-intrinsic" { - pub fn ctpop(x: T) -> T; - pub fn ctlz(x: T) -> T; - pub fn ctlz_nonzero(x: T) -> T; - pub fn cttz(x: T) -> T; - pub fn cttz_nonzero(x: T) -> T; - pub fn bswap(x: T) -> T; - } -} +#![feature(core_intrinsics)] +use std::intrinsics::*; pub fn main() { unsafe { - use crate::rusti::*; - assert_eq!(ctpop(0u8), 0); assert_eq!(ctpop(0i8), 0); assert_eq!(ctpop(0u16), 0); assert_eq!(ctpop(0i16), 0); assert_eq!(ctpop(0u32), 0); assert_eq!(ctpop(0i32), 0); @@ -138,5 +126,29 @@ pub fn main() { assert_eq!(bswap(0x0ABBCC0Di32), 0x0DCCBB0A); assert_eq!(bswap(0x0122334455667708u64), 0x0877665544332201); assert_eq!(bswap(0x0122334455667708i64), 0x0877665544332201); + + assert_eq!(exact_div(9*9u32, 3), 27); + assert_eq!(exact_div(-9*9i32, 3), -27); + assert_eq!(exact_div(9*9i8, -3), -27); + assert_eq!(exact_div(-9*9i64, -3), 27); + + assert_eq!(unchecked_div(9*9u32, 2), 40); + assert_eq!(unchecked_div(-9*9i32, 2), -40); + assert_eq!(unchecked_div(9*9i8, -2), -40); + assert_eq!(unchecked_div(-9*9i64, -2), 40); + + assert_eq!(unchecked_rem(9*9u32, 2), 1); + assert_eq!(unchecked_rem(-9*9i32, 2), -1); + assert_eq!(unchecked_rem(9*9i8, -2), 1); + assert_eq!(unchecked_rem(-9*9i64, -2), -1); + + assert_eq!(unchecked_add(23u8, 19), 42); + assert_eq!(unchecked_add(5, -10), -5); + + assert_eq!(unchecked_sub(23u8, 19), 4); + assert_eq!(unchecked_sub(-17, -27), 10); + + assert_eq!(unchecked_mul(6u8, 7), 42); + assert_eq!(unchecked_mul(13, -5), -65); } } From 850a0d725fe4593645642b142e79037420030c4a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 20 Jun 2019 15:35:06 +0200 Subject: [PATCH 0827/5092] bump Rust, no changes needed --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 9d2a8772234b..1999b58c89cb 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -374c63e0fc356eb61b1966cb6026a2a49fe9226d +4fb77a0398d0339f35f1b18595b375428babd431 From 04fa38dd1bd52c098a731893bbf5b274a4911d0c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 20 Jun 2019 16:38:55 +0200 Subject: [PATCH 0828/5092] allow some inequality comparisons between pointers and integers --- src/operator.rs | 21 +++++++++++++++++++++ tests/compile-fail/ptr_ge_integer.rs | 7 +++++++ tests/run-pass/pointers.rs | 7 +++++++ 3 files changed, 35 insertions(+) create mode 100644 tests/compile-fail/ptr_ge_integer.rs diff --git a/src/operator.rs b/src/operator.rs index 336f945c7847..b05d435ef644 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -109,6 +109,27 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { err!(InvalidPointerMath) } } + Gt | Ge if left.is_ptr() && right.is_bits() => { + // "ptr >[=] integer" can be tested if the integer is small enough. + let left = left.to_ptr().expect("we checked is_ptr"); + let right = right.to_bits(self.memory().pointer_size()).expect("we checked is_bits"); + let (_alloc_size, alloc_align) = self.memory() + .get_size_and_align(left.alloc_id, InboundsCheck::MaybeDead) + .expect("determining size+align of dead ptr cannot fail"); + let min_ptr_val = u128::from(alloc_align.bytes()) + u128::from(left.offset.bytes()); + let result = match bin_op { + Gt => min_ptr_val > right, + Ge => min_ptr_val >= right, + _ => bug!(), + }; + if result { + // Definitely true! + Ok((Scalar::from_bool(true), false)) + } else { + // Sorry, can't tell. + err!(InvalidPointerMath) + } + } // These work if the left operand is a pointer, and the right an integer Add | BitAnd | Sub | Rem if left.is_ptr() && right.is_bits() => { // Cast to i128 is fine as we checked the kind to be ptr-sized diff --git a/tests/compile-fail/ptr_ge_integer.rs b/tests/compile-fail/ptr_ge_integer.rs new file mode 100644 index 000000000000..43160249c363 --- /dev/null +++ b/tests/compile-fail/ptr_ge_integer.rs @@ -0,0 +1,7 @@ +fn main() { + let b = Box::new(0); + let x = &*b as *const i32; + // We cannot test if this is >= 64. After all, depending on the base address, that + // might or might not be the case. + assert!(x >= 64 as *const i32); //~ ERROR invalid arithmetic on pointers +} diff --git a/tests/run-pass/pointers.rs b/tests/run-pass/pointers.rs index 2b26791328df..e0847de97ba9 100644 --- a/tests/run-pass/pointers.rs +++ b/tests/run-pass/pointers.rs @@ -83,4 +83,11 @@ fn main() { assert!(dangling != 5usize); assert!(dangling != 6usize); assert!(dangling != 7usize); + + // Using inequality to do the comparison. + assert!(dangling > 0); + assert!(dangling > 1); + assert!(dangling > 2); + assert!(dangling > 3); + assert!(dangling >= 4); } From 03eff5981b05ab20461e745a031bd6599a41af7d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 20 Jun 2019 19:45:39 +0200 Subject: [PATCH 0829/5092] use org.rust-lang.miri folder on macOS --- .appveyor.yml | 2 +- src/bin/cargo-miri.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index fe450922e044..5080a22aded9 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -36,7 +36,7 @@ build_script: - cargo install --all-features --force --path . --locked --offline # Get ourselves a MIR-full libstd, and use it henceforth - cargo miri setup - - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\miri\cache\HOST + - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\rust-lang\miri\cache\HOST test_script: # Test miri diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 0b2662fe3fb0..cc95eeb7f3a0 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -248,7 +248,7 @@ fn setup(ask_user: bool) { } // Next, we need our own libstd. We will do this work in whatever is a good cache dir for this platform. - let dirs = directories::ProjectDirs::from("", "", "miri").unwrap(); + let dirs = directories::ProjectDirs::from("org", "rust-lang", "miri").unwrap(); let dir = dirs.cache_dir(); if !dir.exists() { fs::create_dir_all(&dir).unwrap(); From 4211d7e1a0083456dfdb9ad466907ed17ed23cd4 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 20 Jun 2019 16:58:57 -0500 Subject: [PATCH 0830/5092] Update tag methods to match Machine changes --- src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 061b07478a28..9072f141f89d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -508,21 +508,21 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { id: AllocId, alloc: Cow<'b, Allocation>, kind: Option>, - memory_extra: &Self::MemoryExtra, + memory: &Memory<'mir, 'tcx, Self>, ) -> (Cow<'b, Allocation>, Self::PointerTag) { let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); let (extra, base_tag) = Stacks::new_allocation( id, Size::from_bytes(alloc.bytes.len() as u64), - Rc::clone(memory_extra), + Rc::clone(&memory.extra), kind, ); if kind != MiriMemoryKind::Static.into() { assert!(alloc.relocations.is_empty(), "Only statics can come initialized with inner pointers"); // Now we can rely on the inner pointers being static, too. } - let mut memory_extra = memory_extra.borrow_mut(); + let mut memory_extra = memory.extra.borrow_mut(); let alloc: Allocation = Allocation { bytes: alloc.bytes, relocations: Relocations::from_presorted( @@ -543,9 +543,9 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn tag_static_base_pointer( id: AllocId, - memory_extra: &Self::MemoryExtra, + memory: &Memory<'mir, 'tcx, Self>, ) -> Self::PointerTag { - memory_extra.borrow_mut().static_base_ptr(id) + memory.extra.borrow_mut().static_base_ptr(id) } #[inline(always)] From ef59fc420fad34801871e538e5e54c8ba8056c61 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 21 Jun 2019 12:36:19 +0200 Subject: [PATCH 0831/5092] Update rust-version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 9d2a8772234b..f09338fca150 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -374c63e0fc356eb61b1966cb6026a2a49fe9226d +56a12b2ad058f22f1ef090713df15598525ba4a4 From 1a784ea21b5652ea4cbedca06fcb8c7249df7ce8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 21 Jun 2019 20:51:05 +0200 Subject: [PATCH 0832/5092] Travis: also run on bors branches, and not on master --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index 1ba55e0c724a..4b56ea9aa648 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,9 @@ os: - osx dist: xenial +# Run in PRs and for bors, but not on master. +if: branch = staging OR branch = trying OR type = pull_request + env: global: - RUST_TEST_NOCAPTURE=1 @@ -53,3 +56,5 @@ notifications: branches: only: - master + - auto + - try From 38d19199c3945f1ae5f086bc4b8ab74e55a62bca Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 21 Jun 2019 20:55:24 +0200 Subject: [PATCH 0833/5092] AppVeyor: only run on bors branches --- .appveyor.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 5080a22aded9..f7d3f990ac99 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -9,7 +9,8 @@ environment: branches: # whitelist only: - - master + - auto + - try cache: - '%USERPROFILE%\.cargo' From ab473bcda5a96cf83bca8cad6f35bd3068c19e60 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 21 Jun 2019 21:02:30 +0200 Subject: [PATCH 0834/5092] fix Travis bors branch names --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4b56ea9aa648..e78c4b9b8b4f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ os: dist: xenial # Run in PRs and for bors, but not on master. -if: branch = staging OR branch = trying OR type = pull_request +if: branch = auto OR branch = try OR type = pull_request env: global: From 5472755f1654f210d61c4f5003ff8e733b54f9a4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 21 Jun 2019 21:48:27 +0200 Subject: [PATCH 0835/5092] add a failing test where an immovable generator gets moved --- tests/compile-fail/generator-pinned-moved.rs | 44 ++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 tests/compile-fail/generator-pinned-moved.rs diff --git a/tests/compile-fail/generator-pinned-moved.rs b/tests/compile-fail/generator-pinned-moved.rs new file mode 100644 index 000000000000..2ae98adad773 --- /dev/null +++ b/tests/compile-fail/generator-pinned-moved.rs @@ -0,0 +1,44 @@ +#![feature(generators, generator_trait)] + +use std::{ + ops::{Generator, GeneratorState}, + pin::Pin, +}; + +fn firstn() -> impl Generator { + static move || { + let mut num = 0; + let num = &mut num; + + yield *num; + *num += 1; //~ ERROR dangling pointer was dereferenced + } +} + +struct GeneratorIteratorAdapter(G); + +impl Iterator for GeneratorIteratorAdapter +where + G: Generator, +{ + type Item = G::Yield; + + fn next(&mut self) -> Option { + let me = unsafe { Pin::new_unchecked(&mut self.0) }; + match me.resume() { + GeneratorState::Yielded(x) => Some(x), + GeneratorState::Complete(_) => None, + } + } +} + +fn main() { + let mut generator_iterator_2 = { + let mut generator_iterator = GeneratorIteratorAdapter(firstn()); + generator_iterator.next(); // pin it + + generator_iterator // move it + }; // *deallocate* generator_iterator + + generator_iterator_2.next(); // and use moved value +} From fd3a291db49fbb6a0198f8bb05990f9163cc1f66 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 20 Jun 2019 14:21:47 -0500 Subject: [PATCH 0836/5092] Implement intptrcast methods --- src/intptrcast.rs | 20 +++++++++ src/lib.rs | 95 ++++++++++++++++++++++++++++++++++++++---- src/memory.rs | 60 ++++++++++++++++++++++++++ src/stacked_borrows.rs | 63 ++++++---------------------- 4 files changed, 179 insertions(+), 59 deletions(-) create mode 100644 src/intptrcast.rs create mode 100644 src/memory.rs diff --git a/src/intptrcast.rs b/src/intptrcast.rs new file mode 100644 index 000000000000..3e07f54fbd3e --- /dev/null +++ b/src/intptrcast.rs @@ -0,0 +1,20 @@ +use std::cell::RefCell; + +use rustc::mir::interpret::AllocId; + +pub type MemoryState = RefCell; + +#[derive(Clone, Debug)] +pub struct GlobalState { + pub vec: Vec<(u64, AllocId)>, + pub addr: u64, +} + +impl Default for GlobalState { + fn default() -> Self { + GlobalState { + vec: Vec::default(), + addr: 2u64.pow(16) + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 9072f141f89d..f61abea62e0b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,9 +20,12 @@ mod tls; mod range_map; mod mono_hash_map; mod stacked_borrows; +mod intptrcast; +mod memory; use std::collections::HashMap; use std::borrow::Cow; +use std::cell::RefCell; use std::rc::Rc; use rand::rngs::StdRng; @@ -48,6 +51,7 @@ use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; use crate::mono_hash_map::MonoHashMap; pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; +use crate::memory::AllocExtra; // Used by priroda. pub use crate::stacked_borrows::{Tag, Permission, Stack, Stacks, Item}; @@ -206,6 +210,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } } + ecx.memory_mut().extra.seed = config.seed.clone(); + assert!(args.next().is_none(), "start lang item has more arguments than expected"); Ok(ecx) @@ -386,8 +392,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryKinds = MiriMemoryKind; type FrameExtra = stacked_borrows::CallId; - type MemoryExtra = stacked_borrows::MemoryState; - type AllocExtra = stacked_borrows::Stacks; + type MemoryExtra = memory::MemoryState; + type AllocExtra = memory::AllocExtra; type PointerTag = Tag; type MemoryMap = MonoHashMap, Allocation)>; @@ -515,14 +521,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { let (extra, base_tag) = Stacks::new_allocation( id, Size::from_bytes(alloc.bytes.len() as u64), - Rc::clone(&memory.extra), + Rc::clone(&memory.extra.stacked), kind, ); if kind != MiriMemoryKind::Static.into() { assert!(alloc.relocations.is_empty(), "Only statics can come initialized with inner pointers"); // Now we can rely on the inner pointers being static, too. } - let mut memory_extra = memory.extra.borrow_mut(); + let mut memory_extra = memory.extra.stacked.borrow_mut(); let alloc: Allocation = Allocation { bytes: alloc.bytes, relocations: Relocations::from_presorted( @@ -535,7 +541,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { undef_mask: alloc.undef_mask, align: alloc.align, mutability: alloc.mutability, - extra, + extra: AllocExtra { + stacks: extra, + base_addr: RefCell::new(None), + }, }; (Cow::Owned(alloc), base_tag) } @@ -545,7 +554,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { id: AllocId, memory: &Memory<'mir, 'tcx, Self>, ) -> Self::PointerTag { - memory.extra.borrow_mut().static_base_ptr(id) + memory.extra.stacked.borrow_mut().static_base_ptr(id) } #[inline(always)] @@ -570,7 +579,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn stack_push( ecx: &mut InterpretCx<'mir, 'tcx, Self>, ) -> InterpResult<'tcx, stacked_borrows::CallId> { - Ok(ecx.memory().extra.borrow_mut().new_call()) + Ok(ecx.memory().extra.stacked.borrow_mut().new_call()) } #[inline(always)] @@ -578,6 +587,76 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx: &mut InterpretCx<'mir, 'tcx, Self>, extra: stacked_borrows::CallId, ) -> InterpResult<'tcx> { - Ok(ecx.memory().extra.borrow_mut().end_call(extra)) + Ok(ecx.memory().extra.stacked.borrow_mut().end_call(extra)) + } + + fn int_to_ptr( + int: u64, + memory: &Memory<'mir, 'tcx, Self>, + ) -> InterpResult<'tcx, Pointer> { + if int == 0 { + return err!(InvalidNullPointerUsage); + } + + if memory.extra.seed.is_none() { + return err!(ReadBytesAsPointer); + } + + let extra = memory.extra.intptrcast.borrow(); + + match extra.vec.binary_search_by_key(&int, |(int, _)| *int) { + Ok(pos) => { + let (_, alloc_id) = extra.vec[pos]; + Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged)) + } + Err(pos) => { + if pos > 0 { + let (glb, alloc_id) = extra.vec[pos - 1]; + let offset = int - glb; + if offset <= memory.get(alloc_id)?.bytes.len() as u64 { + Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged)) + } else { + return err!(DanglingPointerDeref); + } + } else { + return err!(DanglingPointerDeref); + } + } + } + } + + fn ptr_to_int( + ptr: Pointer, + memory: &Memory<'mir, 'tcx, Self>, + ) -> InterpResult<'tcx, u64> { + if memory.extra.seed.is_none() { + return err!(ReadPointerAsBytes); + } + + let mut extra = memory.extra.intptrcast.borrow_mut(); + + let alloc = memory.get(ptr.alloc_id)?; + + let base_addr = match alloc.extra.base_addr.borrow().clone() { + Some(base_addr) => base_addr, + None => { + let base_addr = extra.addr; + extra.addr += alloc.bytes.len() as u64; + + *alloc.extra.base_addr.borrow_mut() = Some(base_addr); + + let elem = (base_addr, ptr.alloc_id); + + if let Err(pos) = extra.vec.binary_search(&elem) { + extra.vec.insert(pos, elem); + } else { + return err!(Unreachable); + } + + base_addr + } + }; + + Ok(base_addr + ptr.offset.bytes()) } } diff --git a/src/memory.rs b/src/memory.rs new file mode 100644 index 000000000000..13ffd859adef --- /dev/null +++ b/src/memory.rs @@ -0,0 +1,60 @@ +use std::cell::RefCell; + +use rustc_mir::interpret::{Pointer, Allocation, AllocationExtra, InterpResult}; +use rustc_target::abi::Size; + +use crate::{stacked_borrows, intptrcast}; +use crate::stacked_borrows::{Tag, AccessKind}; + +#[derive(Default, Clone, Debug)] +pub struct MemoryState { + pub stacked: stacked_borrows::MemoryState, + pub intptrcast: intptrcast::MemoryState, + pub seed: Option, +} + +#[derive(Debug, Clone,)] +pub struct AllocExtra { + pub stacks: stacked_borrows::Stacks, + pub base_addr: RefCell>, +} + +impl AllocationExtra for AllocExtra { + #[inline(always)] + fn memory_read<'tcx>( + alloc: &Allocation, + ptr: Pointer, + size: Size, + ) -> InterpResult<'tcx> { + trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); + alloc.extra.stacks.for_each(ptr, size, |stack, global| { + stack.access(AccessKind::Read, ptr.tag, global)?; + Ok(()) + }) + } + + #[inline(always)] + fn memory_written<'tcx>( + alloc: &mut Allocation, + ptr: Pointer, + size: Size, + ) -> InterpResult<'tcx> { + trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); + alloc.extra.stacks.for_each(ptr, size, |stack, global| { + stack.access(AccessKind::Write, ptr.tag, global)?; + Ok(()) + }) + } + + #[inline(always)] + fn memory_deallocated<'tcx>( + alloc: &mut Allocation, + ptr: Pointer, + size: Size, + ) -> InterpResult<'tcx> { + trace!("deallocation with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); + alloc.extra.stacks.for_each(ptr, size, |stack, global| { + stack.dealloc(ptr.tag, global) + }) + } +} diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index f7617676701c..ea70c28709ce 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -10,8 +10,8 @@ use rustc::mir::RetagKind; use crate::{ InterpResult, InterpError, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, - MemoryKind, MiriMemoryKind, RangeMap, Allocation, AllocationExtra, AllocId, CheckInAllocMsg, - Pointer, Immediate, ImmTy, PlaceTy, MPlaceTy, + MemoryKind, MiriMemoryKind, RangeMap, AllocId, CheckInAllocMsg, Pointer, Immediate, ImmTy, + PlaceTy, MPlaceTy, }; pub type PtrId = NonZeroU64; @@ -286,7 +286,7 @@ impl<'tcx> Stack { /// Test if a memory `access` using pointer tagged `tag` is granted. /// If yes, return the index of the item that granted it. - fn access( + pub(crate) fn access( &mut self, access: AccessKind, tag: Tag, @@ -336,7 +336,7 @@ impl<'tcx> Stack { /// Deallocate a location: Like a write access, but also there must be no /// active protectors at all because we will remove all items. - fn dealloc( + pub(crate) fn dealloc( &mut self, tag: Tag, global: &GlobalState, @@ -429,14 +429,15 @@ impl<'tcx> Stacks { let stack = Stack { borrows: vec![item], }; + Stacks { stacks: RefCell::new(RangeMap::new(size, stack)), - global: extra, + global: extra, } } /// Call `f` on every stack in the range. - fn for_each( + pub(crate) fn for_each( &self, ptr: Pointer, size: Size, @@ -456,7 +457,7 @@ impl Stacks { pub fn new_allocation( id: AllocId, size: Size, - extra: MemoryState, + extra: MemoryState, kind: MemoryKind, ) -> (Self, Tag) { let (tag, perm) = match kind { @@ -477,46 +478,6 @@ impl Stacks { } } -impl AllocationExtra for Stacks { - #[inline(always)] - fn memory_read<'tcx>( - alloc: &Allocation, - ptr: Pointer, - size: Size, - ) -> InterpResult<'tcx> { - trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - alloc.extra.for_each(ptr, size, |stack, global| { - stack.access(AccessKind::Read, ptr.tag, global)?; - Ok(()) - }) - } - - #[inline(always)] - fn memory_written<'tcx>( - alloc: &mut Allocation, - ptr: Pointer, - size: Size, - ) -> InterpResult<'tcx> { - trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - alloc.extra.for_each(ptr, size, |stack, global| { - stack.access(AccessKind::Write, ptr.tag, global)?; - Ok(()) - }) - } - - #[inline(always)] - fn memory_deallocated<'tcx>( - alloc: &mut Allocation, - ptr: Pointer, - size: Size, - ) -> InterpResult<'tcx> { - trace!("deallocation with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - alloc.extra.for_each(ptr, size, |stack, global| { - stack.dealloc(ptr.tag, global) - }) - } -} - /// Retagging/reborrowing. There is some policy in here, such as which permissions /// to grant for which references, and when to add protectors. impl<'mir, 'tcx> EvalContextPrivExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -553,14 +514,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We are only ever `SharedReadOnly` inside the frozen bits. let perm = if frozen { Permission::SharedReadOnly } else { Permission::SharedReadWrite }; let item = Item { perm, tag: new_tag, protector }; - alloc.extra.for_each(cur_ptr, size, |stack, global| { + alloc.extra.stacks.for_each(cur_ptr, size, |stack, global| { stack.grant(cur_ptr.tag, item, global) }) }); } }; let item = Item { perm, tag: new_tag, protector }; - alloc.extra.for_each(ptr, size, |stack, global| { + alloc.extra.stacks.for_each(ptr, size, |stack, global| { stack.grant(ptr.tag, item, global) }) } @@ -587,7 +548,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Compute new borrow. let new_tag = match kind { RefKind::Raw { .. } => Tag::Untagged, - _ => Tag::Tagged(this.memory().extra.borrow_mut().new_ptr()), + _ => Tag::Tagged(this.memory().extra.stacked.borrow_mut().new_ptr()), }; // Reborrow. @@ -621,7 +582,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ty::RawPtr(tym) if kind == RetagKind::Raw => Some((RefKind::Raw { mutable: tym.mutbl == MutMutable }, false)), // Boxes do not get a protector: protectors reflect that references outlive the call - // they were passed in to; that's just not the case for boxes. + // they were passed in to; that's just not the case for boxes. ty::Adt(..) if ty.is_box() => Some((RefKind::Unique { two_phase: false }, false)), _ => None, } From e57447014d0cc8ab9ec86c30bc94e48c588d4526 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 21 Jun 2019 16:32:54 -0500 Subject: [PATCH 0837/5092] Duplicate compile-fail tests for intptrcast --- tests/compile-fail/intptrcast_cast_int_to_fn_ptr.rs | 10 ++++++++++ tests/compile-fail/intptrcast_null_pointer_deref.rs | 6 ++++++ tests/compile-fail/intptrcast_wild_pointer_deref.rs | 7 +++++++ 3 files changed, 23 insertions(+) create mode 100644 tests/compile-fail/intptrcast_cast_int_to_fn_ptr.rs create mode 100644 tests/compile-fail/intptrcast_null_pointer_deref.rs create mode 100644 tests/compile-fail/intptrcast_wild_pointer_deref.rs diff --git a/tests/compile-fail/intptrcast_cast_int_to_fn_ptr.rs b/tests/compile-fail/intptrcast_cast_int_to_fn_ptr.rs new file mode 100644 index 000000000000..f4064cf92e2c --- /dev/null +++ b/tests/compile-fail/intptrcast_cast_int_to_fn_ptr.rs @@ -0,0 +1,10 @@ +// Validation makes this fail in the wrong place +// compile-flags: -Zmiri-disable-validation -Zmiri-seed=0000000000000000 + +fn main() { + let g = unsafe { + std::mem::transmute::(42) + }; + + g(42) //~ ERROR dangling pointer was dereferenced +} diff --git a/tests/compile-fail/intptrcast_null_pointer_deref.rs b/tests/compile-fail/intptrcast_null_pointer_deref.rs new file mode 100644 index 000000000000..0c5d46609cf8 --- /dev/null +++ b/tests/compile-fail/intptrcast_null_pointer_deref.rs @@ -0,0 +1,6 @@ +// compile-flags: -Zmiri-seed=0000000000000000 + +fn main() { + let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR invalid use of NULL pointer + panic!("this should never print: {}", x); +} diff --git a/tests/compile-fail/intptrcast_wild_pointer_deref.rs b/tests/compile-fail/intptrcast_wild_pointer_deref.rs new file mode 100644 index 000000000000..2ee664eb68bd --- /dev/null +++ b/tests/compile-fail/intptrcast_wild_pointer_deref.rs @@ -0,0 +1,7 @@ +// compile-flags: -Zmiri-seed=0000000000000000 + +fn main() { + let p = 44 as *const i32; + let x = unsafe { *p }; //~ ERROR dangling pointer was dereferenced + panic!("this should never print: {}", x); +} From 72c269eebe15141a570ad72a0e6bb87cc59fdc5e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 22 Jun 2019 11:05:12 +0200 Subject: [PATCH 0838/5092] fix compilation with latest rustc --- rust-version | 2 +- src/intrinsic.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index f09338fca150..5422121beb5f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -56a12b2ad058f22f1ef090713df15598525ba4a4 +305930cffeac1da0fd73a08d9f5680e4a49bfb9f diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 0ecccd02d7e1..33bab4642a90 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -505,7 +505,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = mplace.ptr.to_ptr()?; this.memory_mut() .get_mut(ptr.alloc_id)? - .mark_definedness(ptr, dest.layout.size, false)?; + .mark_definedness(ptr, dest.layout.size, false); } } } From 2b1eeb39286c8f504c16e6d92da5d8dd1eac1845 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 22 Jun 2019 11:13:35 +0200 Subject: [PATCH 0839/5092] also run tests for cron jobs --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e78c4b9b8b4f..7db62bc74bd4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ os: dist: xenial # Run in PRs and for bors, but not on master. -if: branch = auto OR branch = try OR type = pull_request +if: branch = auto OR branch = try OR type = pull_request OR type = cron env: global: From dd732e5862ba4601959bbae7993eb4924ddf8ee6 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 22 Jun 2019 09:25:16 -0500 Subject: [PATCH 0840/5092] Force intptrcast for binary operations --- src/lib.rs | 16 +++++++++------- src/operator.rs | 10 ++++++++++ tests/run-pass/intptrcast-truncate.rs | 8 ++++++++ 3 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 tests/run-pass/intptrcast-truncate.rs diff --git a/src/lib.rs b/src/lib.rs index f61abea62e0b..17b20d003e93 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -637,15 +637,17 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { let alloc = memory.get(ptr.alloc_id)?; - let base_addr = match alloc.extra.base_addr.borrow().clone() { - Some(base_addr) => base_addr, + let mut base_addr = alloc.extra.base_addr.borrow_mut(); + + let addr = match *base_addr { + Some(addr) => addr, None => { - let base_addr = extra.addr; + let addr = extra.addr; extra.addr += alloc.bytes.len() as u64; - *alloc.extra.base_addr.borrow_mut() = Some(base_addr); + *base_addr = Some(addr); - let elem = (base_addr, ptr.alloc_id); + let elem = (addr, ptr.alloc_id); if let Err(pos) = extra.vec.binary_search(&elem) { extra.vec.insert(pos, elem); @@ -653,10 +655,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { return err!(Unreachable); } - base_addr + addr } }; - Ok(base_addr + ptr.offset.bytes()) + Ok(addr + ptr.offset.bytes()) } } diff --git a/src/operator.rs b/src/operator.rs index b05d435ef644..7dd3b3526cdc 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -44,6 +44,16 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); + if self.memory().extra.seed.is_some() && bin_op != Offset { + let l_bits = self.force_bits(left.imm.to_scalar()?, left.layout.size)?; + let r_bits = self.force_bits(right.imm.to_scalar()?, right.layout.size)?; + + let left = ImmTy::from_scalar(Scalar::from_uint(l_bits, left.layout.size), left.layout); + let right = ImmTy::from_scalar(Scalar::from_uint(r_bits, left.layout.size), right.layout); + + return self.binary_op(bin_op, left, right); + } + // Operations that support fat pointers match bin_op { Eq | Ne => { diff --git a/tests/run-pass/intptrcast-truncate.rs b/tests/run-pass/intptrcast-truncate.rs new file mode 100644 index 000000000000..7c49af87f886 --- /dev/null +++ b/tests/run-pass/intptrcast-truncate.rs @@ -0,0 +1,8 @@ +// compile-flags: -Zmiri-seed=0000000000000000 + +fn main() { + let x = &42 as *const i32 as usize; + let y = x * 2; + let z = y as u8 as usize; + assert_eq!(z, y % 256); +} From 4dc188a60eb19dc770db071a5e368e90b5a1fab3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Jun 2019 17:26:12 +0200 Subject: [PATCH 0841/5092] adjust for refactored memory pointer checks --- src/fn_call.rs | 5 ++- src/intrinsic.rs | 15 ++++--- src/operator.rs | 41 +++++++++++++------- src/stacked_borrows.rs | 7 ++-- tests/compile-fail/ptr_eq_dangling.rs | 2 +- tests/compile-fail/ptr_eq_out_of_bounds.rs | 2 +- tests/compile-fail/rc_as_raw.rs | 2 + tests/compile-fail/unaligned_ptr_cast1.rs | 4 +- tests/compile-fail/unaligned_ptr_cast2.rs | 4 +- tests/compile-fail/validity/dangling_ref1.rs | 2 +- tests/compile-fail/validity/dangling_ref2.rs | 2 +- tests/compile-fail/zst.rs | 4 -- tests/compile-fail/zst1.rs | 5 +++ tests/compile-fail/zst2.rs | 12 ++++++ tests/compile-fail/zst3.rs | 15 +++++++ tests/run-pass/zst.rs | 9 ----- 16 files changed, 86 insertions(+), 45 deletions(-) delete mode 100644 tests/compile-fail/zst.rs create mode 100644 tests/compile-fail/zst1.rs create mode 100644 tests/compile-fail/zst2.rs create mode 100644 tests/compile-fail/zst3.rs diff --git a/src/fn_call.rs b/src/fn_call.rs index eca1d9144ec4..b053d8c51e70 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -654,7 +654,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Hook pthread calls that go to the thread-local storage memory subsystem. "pthread_key_create" => { - let key_ptr = this.read_scalar(args[0])?.to_ptr()?; + let key_ptr = this.read_scalar(args[0])?.not_undef()?; // Extract the function type out of the signature (that seems easier than constructing it ourselves). let dtor = match this.read_scalar(args[1])?.not_undef()? { @@ -681,7 +681,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return err!(OutOfTls); } - this.memory().check_align(key_ptr.into(), key_layout.align.abi)?; + let key_ptr = this.memory().check_ptr_access(key_ptr, key_layout.size, key_layout.align.abi)? + .expect("cannot be a ZST"); this.memory_mut().get_mut(key_ptr.alloc_id)?.write_scalar( tcx, key_ptr, diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 33bab4642a90..3f9c4e53f09d 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -517,13 +517,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val_byte = this.read_scalar(args[1])?.to_u8()?; let ptr = this.read_scalar(args[0])?.not_undef()?; let count = this.read_scalar(args[2])?.to_usize(this)?; - this.memory().check_align(ptr, ty_layout.align.abi)?; let byte_count = ty_layout.size * count; - if byte_count.bytes() != 0 { - let ptr = ptr.to_ptr()?; - this.memory_mut() - .get_mut(ptr.alloc_id)? - .write_repeat(tcx, ptr, val_byte, byte_count)?; + match this.memory().check_ptr_access(ptr, byte_count, ty_layout.align.abi)? { + Some(ptr) => { + this.memory_mut() + .get_mut(ptr.alloc_id)? + .write_repeat(tcx, ptr, val_byte, byte_count)?; + } + None => { + // Size is 0, nothing to do. + } } } diff --git a/src/operator.rs b/src/operator.rs index b05d435ef644..b735cbcba4ec 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -4,6 +4,11 @@ use rustc::mir; use crate::*; pub trait EvalContextExt<'tcx> { + fn pointer_inbounds( + &self, + ptr: Pointer + ) -> InterpResult<'tcx>; + fn ptr_op( &self, bin_op: mir::BinOp, @@ -34,6 +39,13 @@ pub trait EvalContextExt<'tcx> { } impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { + /// Test if the pointer is in-bounds of a live allocation. + #[inline] + fn pointer_inbounds(&self, ptr: Pointer) -> InterpResult<'tcx> { + let (size, _align) = self.memory().get_size_and_align(ptr.alloc_id, AllocCheck::Live)?; + ptr.check_in_alloc(size, CheckInAllocMsg::InboundsTest) + } + fn ptr_op( &self, bin_op: mir::BinOp, @@ -114,8 +126,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { let left = left.to_ptr().expect("we checked is_ptr"); let right = right.to_bits(self.memory().pointer_size()).expect("we checked is_bits"); let (_alloc_size, alloc_align) = self.memory() - .get_size_and_align(left.alloc_id, InboundsCheck::MaybeDead) - .expect("determining size+align of dead ptr cannot fail"); + .get_size_and_align(left.alloc_id, AllocCheck::MaybeDead) + .expect("alloc info with MaybeDead cannot fail"); let min_ptr_val = u128::from(alloc_align.bytes()) + u128::from(left.offset.bytes()); let result = match bin_op { Gt => min_ptr_val > right, @@ -170,6 +182,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { if left.alloc_id == right.alloc_id { left.offset == right.offset } else { + // Make sure both pointers are in-bounds. // This accepts one-past-the end. Thus, there is still technically // some non-determinism that we do not fully rule out when two // allocations sit right next to each other. The C/C++ standards are @@ -179,10 +192,12 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { // Dead allocations in miri cannot overlap with live allocations, but // on read hardware this can easily happen. Thus for comparisons we require // both pointers to be live. - self.memory().check_bounds_ptr(left, InboundsCheck::Live, CheckInAllocMsg::InboundsTest)?; - self.memory().check_bounds_ptr(right, InboundsCheck::Live, CheckInAllocMsg::InboundsTest)?; - // Two in-bounds pointers, we can compare across allocations. - left == right + if self.pointer_inbounds(left).is_ok() && self.pointer_inbounds(right).is_ok() { + // Two in-bounds pointers, we can compare across allocations. + left == right + } else { + return err!(InvalidPointerMath); + } } } // Comparing ptr and integer. @@ -202,16 +217,16 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { // alignment 32 or higher, hence the limit of 32. // FIXME: Once we support intptrcast, we could try to fix these holes. if bits < 32 { - // Test if the ptr is in-bounds. Then it cannot be NULL. - // Even dangling pointers cannot be NULL. - if self.memory().check_bounds_ptr(ptr, InboundsCheck::MaybeDead, CheckInAllocMsg::NullPointerTest).is_ok() { + // Test if the pointer can be different from NULL or not. + // We assume that pointers that are not NULL are also not "small". + if !self.memory().ptr_may_be_null(ptr) { return Ok(false); } } let (alloc_size, alloc_align) = self.memory() - .get_size_and_align(ptr.alloc_id, InboundsCheck::MaybeDead) - .expect("determining size+align of dead ptr cannot fail"); + .get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead) + .expect("alloc info with MaybeDead cannot fail"); // Case II: Alignment gives it away if ptr.offset.bytes() % alloc_align.bytes() == 0 { @@ -359,9 +374,9 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { if let Scalar::Ptr(ptr) = ptr { // Both old and new pointer must be in-bounds of a *live* allocation. // (Of the same allocation, but that part is trivial with our representation.) - self.memory().check_bounds_ptr(ptr, InboundsCheck::Live, CheckInAllocMsg::InboundsTest)?; + self.pointer_inbounds(ptr)?; let ptr = ptr.signed_offset(offset, self)?; - self.memory().check_bounds_ptr(ptr, InboundsCheck::Live, CheckInAllocMsg::InboundsTest)?; + self.pointer_inbounds(ptr)?; Ok(Scalar::Ptr(ptr)) } else { // An integer pointer. They can only be offset by 0, and we pretend there diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index f7617676701c..3a0c257428e1 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -10,7 +10,7 @@ use rustc::mir::RetagKind; use crate::{ InterpResult, InterpError, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, - MemoryKind, MiriMemoryKind, RangeMap, Allocation, AllocationExtra, AllocId, CheckInAllocMsg, + MemoryKind, MiriMemoryKind, RangeMap, Allocation, AllocationExtra, AllocId, Pointer, Immediate, ImmTy, PlaceTy, MPlaceTy, }; @@ -531,13 +531,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let protector = if protect { Some(this.frame().extra) } else { None }; - let ptr = place.ptr.to_ptr()?; + let ptr = this.memory().check_ptr_access(place.ptr, size, place.align) + .expect("validity checks should have excluded dangling/unaligned pointer") + .expect("we shouldn't get here for ZST"); trace!("reborrow: {} reference {:?} derived from {:?} (pointee {}): {:?}, size {}", kind, new_tag, ptr.tag, place.layout.ty, ptr.erase_tag(), size.bytes()); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. let alloc = this.memory().get(ptr.alloc_id)?; - alloc.check_bounds(this, ptr, size, CheckInAllocMsg::InboundsTest)?; // Update the stacks. // Make sure that raw pointers and mutable shared references are reborrowed "weak": // There could be existing unique pointers reborrowed from them that should remain valid! diff --git a/tests/compile-fail/ptr_eq_dangling.rs b/tests/compile-fail/ptr_eq_dangling.rs index d05996a13d56..5badf099e439 100644 --- a/tests/compile-fail/ptr_eq_dangling.rs +++ b/tests/compile-fail/ptr_eq_dangling.rs @@ -6,5 +6,5 @@ fn main() { let y = &*b as *const i32; // different allocation // We cannot compare these even though both are inbounds -- they *could* be // equal if memory was reused. - assert!(x != y); //~ ERROR dangling pointer + assert!(x != y); //~ ERROR invalid arithmetic on pointers } diff --git a/tests/compile-fail/ptr_eq_out_of_bounds.rs b/tests/compile-fail/ptr_eq_out_of_bounds.rs index af4eed8d4e32..7efa446d7fca 100644 --- a/tests/compile-fail/ptr_eq_out_of_bounds.rs +++ b/tests/compile-fail/ptr_eq_out_of_bounds.rs @@ -5,5 +5,5 @@ fn main() { let y = &*b as *const i32; // different allocation // We cannot compare these even though both allocations are live -- they *could* be // equal (with the right base addresses). - assert!(x != y); //~ ERROR outside bounds + assert!(x != y); //~ ERROR invalid arithmetic on pointers } diff --git a/tests/compile-fail/rc_as_raw.rs b/tests/compile-fail/rc_as_raw.rs index 3e6e96456fca..086467eea311 100644 --- a/tests/compile-fail/rc_as_raw.rs +++ b/tests/compile-fail/rc_as_raw.rs @@ -1,3 +1,5 @@ +// This should fail even without validation +// compile-flags: -Zmiri-disable-validation #![feature(weak_into_raw)] use std::rc::{Rc, Weak}; diff --git a/tests/compile-fail/unaligned_ptr_cast1.rs b/tests/compile-fail/unaligned_ptr_cast1.rs index e64594d3e7ed..92e1fae75a04 100644 --- a/tests/compile-fail/unaligned_ptr_cast1.rs +++ b/tests/compile-fail/unaligned_ptr_cast1.rs @@ -2,8 +2,8 @@ // compile-flags: -Zmiri-disable-validation fn main() { - let x = &2u16; - let x = x as *const _ as *const u32; + let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. + let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated let _x = unsafe { *x }; //~ ERROR tried to access memory with alignment 2, but alignment 4 is required } diff --git a/tests/compile-fail/unaligned_ptr_cast2.rs b/tests/compile-fail/unaligned_ptr_cast2.rs index 9fb138e353fe..783661c55710 100644 --- a/tests/compile-fail/unaligned_ptr_cast2.rs +++ b/tests/compile-fail/unaligned_ptr_cast2.rs @@ -2,8 +2,8 @@ // compile-flags: -Zmiri-disable-validation fn main() { - let x = &2u16; - let x = x as *const _ as *const *const u8; + let x = [2u16, 3, 4, 5]; // Make it big enough so we don't get an out-of-bounds error. + let x = &x[0] as *const _ as *const *const u8; // This must fail because alignment is violated. Test specifically for loading pointers, // which have special code in miri's memory. let _x = unsafe { *x }; diff --git a/tests/compile-fail/validity/dangling_ref1.rs b/tests/compile-fail/validity/dangling_ref1.rs index c5845cb693bb..4318c7c90271 100644 --- a/tests/compile-fail/validity/dangling_ref1.rs +++ b/tests/compile-fail/validity/dangling_ref1.rs @@ -1,5 +1,5 @@ use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR tried to interpret some bytes as a pointer + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR integer pointer in non-ZST reference } diff --git a/tests/compile-fail/validity/dangling_ref2.rs b/tests/compile-fail/validity/dangling_ref2.rs index 21650ebf9506..ef76b93d11e2 100644 --- a/tests/compile-fail/validity/dangling_ref2.rs +++ b/tests/compile-fail/validity/dangling_ref2.rs @@ -3,5 +3,5 @@ use std::mem; fn main() { let val = 14; let ptr = (&val as *const i32).wrapping_offset(1); - let _x: &i32 = unsafe { mem::transmute(ptr) }; //~ ERROR outside bounds of allocation + let _x: &i32 = unsafe { mem::transmute(ptr) }; //~ ERROR encountered dangling (not entirely in bounds) reference } diff --git a/tests/compile-fail/zst.rs b/tests/compile-fail/zst.rs deleted file mode 100644 index 0488926870a2..000000000000 --- a/tests/compile-fail/zst.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn main() { - let x = &() as *const () as *const i32; - let _val = unsafe { *x }; //~ ERROR access memory with alignment 1, but alignment 4 is required -} diff --git a/tests/compile-fail/zst1.rs b/tests/compile-fail/zst1.rs new file mode 100644 index 000000000000..e4ce7b8ecdf8 --- /dev/null +++ b/tests/compile-fail/zst1.rs @@ -0,0 +1,5 @@ +fn main() { + // make sure ZST locals cannot be accessed + let x = &() as *const () as *const i8; + let _val = unsafe { *x }; //~ ERROR pointer must be in-bounds +} diff --git a/tests/compile-fail/zst2.rs b/tests/compile-fail/zst2.rs new file mode 100644 index 000000000000..950f7b3d60e6 --- /dev/null +++ b/tests/compile-fail/zst2.rs @@ -0,0 +1,12 @@ +fn main() { + // Not using the () type here, as writes of that type do not even have MIR generated. + // Also not assigning directly as that's array initialization, not assignment. + let zst_val = [1u8; 0]; + + // make sure ZST accesses are checked against being "truly" dangling pointers + // (into deallocated allocations). + let mut x_box = Box::new(1u8); + let x = &mut *x_box as *mut _ as *mut [u8; 0]; + drop(x_box); + unsafe { *x = zst_val; } //~ ERROR dangling pointer was dereferenced +} diff --git a/tests/compile-fail/zst3.rs b/tests/compile-fail/zst3.rs new file mode 100644 index 000000000000..a16ec0186d77 --- /dev/null +++ b/tests/compile-fail/zst3.rs @@ -0,0 +1,15 @@ +fn main() { + // Not using the () type here, as writes of that type do not even have MIR generated. + // Also not assigning directly as that's array initialization, not assignment. + let zst_val = [1u8; 0]; + + // make sure ZST accesses are checked against being "truly" dangling pointers + // (that are out-of-bounds). + let mut x_box = Box::new(1u8); + let x = (&mut *x_box as *mut u8).wrapping_offset(1); + // This one is just "at the egde", but still okay + unsafe { *(x as *mut [u8; 0]) = zst_val; } + // One byte further is OOB. + let x = x.wrapping_offset(1); + unsafe { *(x as *mut [u8; 0]) = zst_val; } //~ ERROR pointer must be in-bounds +} diff --git a/tests/run-pass/zst.rs b/tests/run-pass/zst.rs index 9d97210b73db..988473570913 100644 --- a/tests/run-pass/zst.rs +++ b/tests/run-pass/zst.rs @@ -21,13 +21,4 @@ fn main() { // Reading and writing is ok. unsafe { *x = zst_val; } unsafe { let _y = *x; } - - // We should even be able to use "true" pointers for ZST when the allocation has been - // removed already. The box is for a non-ZST to make sure there actually is an allocation. - let mut x_box = Box::new(((), 1u8)); - let x = &mut x_box.0 as *mut _ as *mut [u8; 0]; - drop(x_box); - // Reading and writing is ok. - unsafe { *x = zst_val; } - unsafe { let _y = *x; } } From 69e8318b602d0b6bab2dee9bc3476e831b6ea5a6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Jun 2019 20:30:33 +0200 Subject: [PATCH 0842/5092] de-obfuscate ptr comparison a bit --- src/operator.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index b735cbcba4ec..5d1f33a57093 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -193,8 +193,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { // on read hardware this can easily happen. Thus for comparisons we require // both pointers to be live. if self.pointer_inbounds(left).is_ok() && self.pointer_inbounds(right).is_ok() { - // Two in-bounds pointers, we can compare across allocations. - left == right + // Two in-bounds pointers in different allocatons are different. + false } else { return err!(InvalidPointerMath); } From 4d65aa8f20ac80f7517af15f2dec8936325119c6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Jun 2019 08:40:45 +0200 Subject: [PATCH 0843/5092] expand and better explain alignment check tests --- .../{unaligned_ptr_cast1.rs => unaligned_ptr1.rs} | 2 +- tests/compile-fail/unaligned_ptr2.rs | 10 ++++++++++ .../{unaligned_ptr_cast2.rs => unaligned_ptr3.rs} | 2 +- ...{unaligned_ptr_cast_zst.rs => unaligned_ptr_zst.rs} | 3 +++ 4 files changed, 15 insertions(+), 2 deletions(-) rename tests/compile-fail/{unaligned_ptr_cast1.rs => unaligned_ptr1.rs} (76%) create mode 100644 tests/compile-fail/unaligned_ptr2.rs rename tests/compile-fail/{unaligned_ptr_cast2.rs => unaligned_ptr3.rs} (81%) rename tests/compile-fail/{unaligned_ptr_cast_zst.rs => unaligned_ptr_zst.rs} (75%) diff --git a/tests/compile-fail/unaligned_ptr_cast1.rs b/tests/compile-fail/unaligned_ptr1.rs similarity index 76% rename from tests/compile-fail/unaligned_ptr_cast1.rs rename to tests/compile-fail/unaligned_ptr1.rs index 92e1fae75a04..bcc4192d7d2a 100644 --- a/tests/compile-fail/unaligned_ptr_cast1.rs +++ b/tests/compile-fail/unaligned_ptr1.rs @@ -4,6 +4,6 @@ fn main() { let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. let x = &x[0] as *const _ as *const u32; - // This must fail because alignment is violated + // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. let _x = unsafe { *x }; //~ ERROR tried to access memory with alignment 2, but alignment 4 is required } diff --git a/tests/compile-fail/unaligned_ptr2.rs b/tests/compile-fail/unaligned_ptr2.rs new file mode 100644 index 000000000000..225bd14ade61 --- /dev/null +++ b/tests/compile-fail/unaligned_ptr2.rs @@ -0,0 +1,10 @@ +// This should fail even without validation. +// compile-flags: -Zmiri-disable-validation + +fn main() { + let x = [2u32, 3]; // Make it big enough so we don't get an out-of-bounds error. + let x = (x.as_ptr() as *const u8).wrapping_offset(3) as *const u32; + // This must fail because alignment is violated: the offset is not sufficiently aligned. + // Also make the offset not a power of 2, that used to ICE. + let _x = unsafe { *x }; //~ ERROR tried to access memory with alignment 1, but alignment 4 is required +} diff --git a/tests/compile-fail/unaligned_ptr_cast2.rs b/tests/compile-fail/unaligned_ptr3.rs similarity index 81% rename from tests/compile-fail/unaligned_ptr_cast2.rs rename to tests/compile-fail/unaligned_ptr3.rs index 783661c55710..f33a80d4588b 100644 --- a/tests/compile-fail/unaligned_ptr_cast2.rs +++ b/tests/compile-fail/unaligned_ptr3.rs @@ -3,7 +3,7 @@ fn main() { let x = [2u16, 3, 4, 5]; // Make it big enough so we don't get an out-of-bounds error. - let x = &x[0] as *const _ as *const *const u8; + let x = &x[0] as *const _ as *const *const u8; // cast to ptr-to-ptr, so that we load a ptr // This must fail because alignment is violated. Test specifically for loading pointers, // which have special code in miri's memory. let _x = unsafe { *x }; diff --git a/tests/compile-fail/unaligned_ptr_cast_zst.rs b/tests/compile-fail/unaligned_ptr_zst.rs similarity index 75% rename from tests/compile-fail/unaligned_ptr_cast_zst.rs rename to tests/compile-fail/unaligned_ptr_zst.rs index d52b569175c1..127ec04027d1 100644 --- a/tests/compile-fail/unaligned_ptr_cast_zst.rs +++ b/tests/compile-fail/unaligned_ptr_zst.rs @@ -1,3 +1,6 @@ +// This should fail even without validation +// compile-flags: -Zmiri-disable-validation + fn main() { let x = &2u16; let x = x as *const _ as *const [u32; 0]; From 7e7b5d42ba321aa4cc3da5e1da222344597b0c1d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Jun 2019 14:50:27 +0200 Subject: [PATCH 0844/5092] Apply suggestions from code review Co-Authored-By: Oliver Scherer --- src/operator.rs | 2 +- tests/compile-fail/zst3.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index 5d1f33a57093..cb258cf150d7 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -193,7 +193,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { // on read hardware this can easily happen. Thus for comparisons we require // both pointers to be live. if self.pointer_inbounds(left).is_ok() && self.pointer_inbounds(right).is_ok() { - // Two in-bounds pointers in different allocatons are different. + // Two in-bounds pointers in different allocations are different. false } else { return err!(InvalidPointerMath); diff --git a/tests/compile-fail/zst3.rs b/tests/compile-fail/zst3.rs index a16ec0186d77..c94591174ec5 100644 --- a/tests/compile-fail/zst3.rs +++ b/tests/compile-fail/zst3.rs @@ -7,7 +7,7 @@ fn main() { // (that are out-of-bounds). let mut x_box = Box::new(1u8); let x = (&mut *x_box as *mut u8).wrapping_offset(1); - // This one is just "at the egde", but still okay + // This one is just "at the edge", but still okay unsafe { *(x as *mut [u8; 0]) = zst_val; } // One byte further is OOB. let x = x.wrapping_offset(1); From 2861ceb2fa1acc2c642abd4f2efb96c713a47e29 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 24 Jun 2019 10:03:16 -0500 Subject: [PATCH 0845/5092] Rename new fields and move rng to MemoryExtra --- src/fn_call.rs | 2 +- src/intptrcast.rs | 10 +++++---- src/lib.rs | 55 ++++++++++++++++++++--------------------------- src/memory.rs | 9 +++++--- src/operator.rs | 2 +- 5 files changed, 37 insertions(+), 41 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index eca1d9144ec4..e47e21691211 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -979,7 +979,7 @@ fn gen_random<'mir, 'tcx>( } let ptr = dest.to_ptr()?; - let data = match &mut this.machine.rng { + let data = match &mut this.memory_mut().extra.rng { Some(rng) => { let mut data = vec![0; len]; rng.fill_bytes(&mut data); diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 3e07f54fbd3e..f95cf0fda46b 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -6,15 +6,17 @@ pub type MemoryState = RefCell; #[derive(Clone, Debug)] pub struct GlobalState { - pub vec: Vec<(u64, AllocId)>, - pub addr: u64, + /// This field is used as a map between the address of each allocation and its `AllocId` + pub int_to_ptr_map: Vec<(u64, AllocId)>, + pub next_base_addr: u64, } impl Default for GlobalState { + // FIXME: Query the page size in the future fn default() -> Self { GlobalState { - vec: Vec::default(), - addr: 2u64.pow(16) + int_to_ptr_map: Vec::default(), + next_base_addr: 2u64.pow(16) } } } diff --git a/src/lib.rs b/src/lib.rs index 17b20d003e93..5288537f20ee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,7 @@ mod memory; use std::collections::HashMap; use std::borrow::Cow; -use std::cell::RefCell; +use std::cell::Cell; use std::rc::Rc; use rand::rngs::StdRng; @@ -83,9 +83,11 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let mut ecx = InterpretCx::new( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), - Evaluator::new(config.validate, config.seed), + Evaluator::new(config.validate), ); + ecx.memory_mut().extra.rng = config.seed.map(StdRng::seed_from_u64); + let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; @@ -209,9 +211,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( cur_ptr = cur_ptr.offset(char_size, tcx)?; } } - - ecx.memory_mut().extra.seed = config.seed.clone(); - + assert!(args.next().is_none(), "start lang item has more arguments than expected"); Ok(ecx) @@ -347,14 +347,10 @@ pub struct Evaluator<'tcx> { /// Whether to enforce the validity invariant. pub(crate) validate: bool, - - /// The random number generator to use if Miri - /// is running in non-deterministic mode - pub(crate) rng: Option } impl<'tcx> Evaluator<'tcx> { - fn new(validate: bool, seed: Option) -> Self { + fn new(validate: bool) -> Self { Evaluator { env_vars: HashMap::default(), argc: None, @@ -363,7 +359,6 @@ impl<'tcx> Evaluator<'tcx> { last_error: 0, tls: TlsData::default(), validate, - rng: seed.map(|s| StdRng::seed_from_u64(s)) } } } @@ -543,7 +538,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { mutability: alloc.mutability, extra: AllocExtra { stacks: extra, - base_addr: RefCell::new(None), + base_addr: Cell::new(None), }, }; (Cow::Owned(alloc), base_tag) @@ -598,20 +593,20 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { return err!(InvalidNullPointerUsage); } - if memory.extra.seed.is_none() { + if memory.extra.rng.is_none() { return err!(ReadBytesAsPointer); } let extra = memory.extra.intptrcast.borrow(); - match extra.vec.binary_search_by_key(&int, |(int, _)| *int) { + match extra.int_to_ptr_map.binary_search_by_key(&int, |(int, _)| *int) { Ok(pos) => { - let (_, alloc_id) = extra.vec[pos]; + let (_, alloc_id) = extra.int_to_ptr_map[pos]; Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged)) } Err(pos) => { if pos > 0 { - let (glb, alloc_id) = extra.vec[pos - 1]; + let (glb, alloc_id) = extra.int_to_ptr_map[pos - 1]; let offset = int - glb; if offset <= memory.get(alloc_id)?.bytes.len() as u64 { Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged)) @@ -629,7 +624,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ptr: Pointer, memory: &Memory<'mir, 'tcx, Self>, ) -> InterpResult<'tcx, u64> { - if memory.extra.seed.is_none() { + if memory.extra.rng.is_none() { return err!(ReadPointerAsBytes); } @@ -637,28 +632,24 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { let alloc = memory.get(ptr.alloc_id)?; - let mut base_addr = alloc.extra.base_addr.borrow_mut(); - - let addr = match *base_addr { - Some(addr) => addr, + let base_addr = match alloc.extra.base_addr.get() { + Some(base_addr) => base_addr, None => { - let addr = extra.addr; - extra.addr += alloc.bytes.len() as u64; + let base_addr = extra.next_base_addr; + extra.next_base_addr += alloc.bytes.len() as u64; - *base_addr = Some(addr); + alloc.extra.base_addr.set(Some(base_addr)); - let elem = (addr, ptr.alloc_id); + let elem = (base_addr, ptr.alloc_id); - if let Err(pos) = extra.vec.binary_search(&elem) { - extra.vec.insert(pos, elem); - } else { - return err!(Unreachable); - } + // Given that `next_base_addr` increases in each allocation, pushing the + // corresponding tuple keeps `int_to_ptr_map` sorted + extra.int_to_ptr_map.push(elem); - addr + base_addr } }; - Ok(addr + ptr.offset.bytes()) + Ok(base_addr + ptr.offset.bytes()) } } diff --git a/src/memory.rs b/src/memory.rs index 13ffd859adef..fafa9272bacd 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -1,4 +1,5 @@ -use std::cell::RefCell; +use std::cell::Cell; +use rand::rngs::StdRng; use rustc_mir::interpret::{Pointer, Allocation, AllocationExtra, InterpResult}; use rustc_target::abi::Size; @@ -10,13 +11,15 @@ use crate::stacked_borrows::{Tag, AccessKind}; pub struct MemoryState { pub stacked: stacked_borrows::MemoryState, pub intptrcast: intptrcast::MemoryState, - pub seed: Option, + /// The random number generator to use if Miri + /// is running in non-deterministic mode + pub(crate) rng: Option } #[derive(Debug, Clone,)] pub struct AllocExtra { pub stacks: stacked_borrows::Stacks, - pub base_addr: RefCell>, + pub base_addr: Cell>, } impl AllocationExtra for AllocExtra { diff --git a/src/operator.rs b/src/operator.rs index 7dd3b3526cdc..0ebb1e71610a 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -44,7 +44,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); - if self.memory().extra.seed.is_some() && bin_op != Offset { + if self.memory().extra.rng.is_some() && bin_op != Offset { let l_bits = self.force_bits(left.imm.to_scalar()?, left.layout.size)?; let r_bits = self.force_bits(right.imm.to_scalar()?, right.layout.size)?; From b66cf703684b3678aae162ced43c6846f105a681 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Jun 2019 23:58:12 +0200 Subject: [PATCH 0846/5092] bump Rust commit --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 5422121beb5f..17338728254a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -305930cffeac1da0fd73a08d9f5680e4a49bfb9f +7e08576e4276a97b523c25bfd196d419c39c7b87 From 84cfbb01b7ad4c4ba3f3b987ef8c3f562c9e57cb Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 24 Jun 2019 16:34:38 -0500 Subject: [PATCH 0847/5092] Reorganize MemoryExtra and AllocExtra structures --- src/intptrcast.rs | 83 ++++++++++++++++++++++++++++++++++++++++-- src/lib.rs | 79 +++++++++------------------------------- src/memory.rs | 36 ++++++------------ src/operator.rs | 3 ++ src/stacked_borrows.rs | 61 +++++++++++++++++++++++++------ 5 files changed, 161 insertions(+), 101 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index f95cf0fda46b..c48e7b7772b1 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -1,13 +1,26 @@ -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; -use rustc::mir::interpret::AllocId; +use rustc::mir::interpret::{AllocId, Pointer, InterpResult}; +use rustc_mir::interpret::Memory; +use rustc_target::abi::Size; -pub type MemoryState = RefCell; +use crate::stacked_borrows::Tag; +use crate::Evaluator; + +pub type MemoryExtra = RefCell; + +#[derive(Clone, Debug, Default)] +pub struct AllocExtra { + base_addr: Cell> +} #[derive(Clone, Debug)] pub struct GlobalState { - /// This field is used as a map between the address of each allocation and its `AllocId` + /// This is used as a map between the address of each allocation and its `AllocId`. + /// It is always sorted pub int_to_ptr_map: Vec<(u64, AllocId)>, + /// This is used as a memory address when a new pointer is casted to an integer. It + /// is always larger than any address that was previously made part of a block. pub next_base_addr: u64, } @@ -20,3 +33,65 @@ impl Default for GlobalState { } } } + +impl<'mir, 'tcx> GlobalState { + pub fn int_to_ptr( + base_addr: u64, + memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>, + ) -> InterpResult<'tcx, Pointer> { + let global_state = memory.extra.intptrcast.borrow(); + + match global_state.int_to_ptr_map.binary_search_by_key(&base_addr, |(addr, _)| *addr) { + Ok(pos) => { + let (_, alloc_id) = global_state.int_to_ptr_map[pos]; + // `base_addr` is the starting address for an allocation, the offset should be + // zero. The pointer is untagged because it was created from a cast + Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged)) + }, + Err(0) => err!(DanglingPointerDeref), + Err(pos) => { + // This is the gargest of the adresses smaller than `base_addr`, + // i.e. the greatest lower bound (glb) + let (glb, alloc_id) = global_state.int_to_ptr_map[pos - 1]; + // This never overflows because `base_addr >= glb` + let offset = base_addr - glb; + // If the offset exceeds the size of the allocation, this access is illegal + if offset <= memory.get(alloc_id)?.bytes.len() as u64 { + // This pointer is untagged because it was created from a cast + Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged)) + } else { + err!(DanglingPointerDeref) + } + } + } + } + + pub fn ptr_to_int( + ptr: Pointer, + memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>, + ) -> InterpResult<'tcx, u64> { + let mut global_state = memory.extra.intptrcast.borrow_mut(); + + let alloc = memory.get(ptr.alloc_id)?; + + let base_addr = match alloc.extra.intptrcast.base_addr.get() { + Some(base_addr) => base_addr, + None => { + let base_addr = global_state.next_base_addr; + global_state.next_base_addr += alloc.bytes.len() as u64; + + alloc.extra.intptrcast.base_addr.set(Some(base_addr)); + + let elem = (base_addr, ptr.alloc_id); + + // Given that `next_base_addr` increases in each allocation, pushing the + // corresponding tuple keeps `int_to_ptr_map` sorted + global_state.int_to_ptr_map.push(elem); + + base_addr + } + }; + + Ok(base_addr + ptr.offset.bytes()) + } +} diff --git a/src/lib.rs b/src/lib.rs index 5288537f20ee..77acd3045da5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,6 @@ mod memory; use std::collections::HashMap; use std::borrow::Cow; -use std::cell::Cell; use std::rc::Rc; use rand::rngs::StdRng; @@ -387,7 +386,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryKinds = MiriMemoryKind; type FrameExtra = stacked_borrows::CallId; - type MemoryExtra = memory::MemoryState; + type MemoryExtra = memory::MemoryExtra; type AllocExtra = memory::AllocExtra; type PointerTag = Tag; @@ -513,17 +512,17 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ) -> (Cow<'b, Allocation>, Self::PointerTag) { let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); - let (extra, base_tag) = Stacks::new_allocation( + let (stacks, base_tag) = Stacks::new_allocation( id, Size::from_bytes(alloc.bytes.len() as u64), - Rc::clone(&memory.extra.stacked), + Rc::clone(&memory.extra.stacked_borrows), kind, ); if kind != MiriMemoryKind::Static.into() { assert!(alloc.relocations.is_empty(), "Only statics can come initialized with inner pointers"); // Now we can rely on the inner pointers being static, too. } - let mut memory_extra = memory.extra.stacked.borrow_mut(); + let mut memory_extra = memory.extra.stacked_borrows.borrow_mut(); let alloc: Allocation = Allocation { bytes: alloc.bytes, relocations: Relocations::from_presorted( @@ -537,8 +536,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { align: alloc.align, mutability: alloc.mutability, extra: AllocExtra { - stacks: extra, - base_addr: Cell::new(None), + stacked_borrows: stacks, + intptrcast: Default::default(), }, }; (Cow::Owned(alloc), base_tag) @@ -549,7 +548,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { id: AllocId, memory: &Memory<'mir, 'tcx, Self>, ) -> Self::PointerTag { - memory.extra.stacked.borrow_mut().static_base_ptr(id) + memory.extra.stacked_borrows.borrow_mut().static_base_ptr(id) } #[inline(always)] @@ -574,7 +573,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn stack_push( ecx: &mut InterpretCx<'mir, 'tcx, Self>, ) -> InterpResult<'tcx, stacked_borrows::CallId> { - Ok(ecx.memory().extra.stacked.borrow_mut().new_call()) + Ok(ecx.memory().extra.stacked_borrows.borrow_mut().new_call()) } #[inline(always)] @@ -582,7 +581,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx: &mut InterpretCx<'mir, 'tcx, Self>, extra: stacked_borrows::CallId, ) -> InterpResult<'tcx> { - Ok(ecx.memory().extra.stacked.borrow_mut().end_call(extra)) + Ok(ecx.memory().extra.stacked_borrows.borrow_mut().end_call(extra)) } fn int_to_ptr( @@ -590,33 +589,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { memory: &Memory<'mir, 'tcx, Self>, ) -> InterpResult<'tcx, Pointer> { if int == 0 { - return err!(InvalidNullPointerUsage); - } - - if memory.extra.rng.is_none() { - return err!(ReadBytesAsPointer); - } - - let extra = memory.extra.intptrcast.borrow(); - - match extra.int_to_ptr_map.binary_search_by_key(&int, |(int, _)| *int) { - Ok(pos) => { - let (_, alloc_id) = extra.int_to_ptr_map[pos]; - Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged)) - } - Err(pos) => { - if pos > 0 { - let (glb, alloc_id) = extra.int_to_ptr_map[pos - 1]; - let offset = int - glb; - if offset <= memory.get(alloc_id)?.bytes.len() as u64 { - Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged)) - } else { - return err!(DanglingPointerDeref); - } - } else { - return err!(DanglingPointerDeref); - } - } + err!(InvalidNullPointerUsage) + } else if memory.extra.rng.is_none() { + err!(ReadBytesAsPointer) + } else { + intptrcast::GlobalState::int_to_ptr(int, memory) } } @@ -625,31 +602,9 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { memory: &Memory<'mir, 'tcx, Self>, ) -> InterpResult<'tcx, u64> { if memory.extra.rng.is_none() { - return err!(ReadPointerAsBytes); + err!(ReadPointerAsBytes) + } else { + intptrcast::GlobalState::ptr_to_int(ptr, memory) } - - let mut extra = memory.extra.intptrcast.borrow_mut(); - - let alloc = memory.get(ptr.alloc_id)?; - - let base_addr = match alloc.extra.base_addr.get() { - Some(base_addr) => base_addr, - None => { - let base_addr = extra.next_base_addr; - extra.next_base_addr += alloc.bytes.len() as u64; - - alloc.extra.base_addr.set(Some(base_addr)); - - let elem = (base_addr, ptr.alloc_id); - - // Given that `next_base_addr` increases in each allocation, pushing the - // corresponding tuple keeps `int_to_ptr_map` sorted - extra.int_to_ptr_map.push(elem); - - base_addr - } - }; - - Ok(base_addr + ptr.offset.bytes()) } } diff --git a/src/memory.rs b/src/memory.rs index fafa9272bacd..ea8f01a808c0 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -1,25 +1,24 @@ -use std::cell::Cell; use rand::rngs::StdRng; use rustc_mir::interpret::{Pointer, Allocation, AllocationExtra, InterpResult}; use rustc_target::abi::Size; use crate::{stacked_borrows, intptrcast}; -use crate::stacked_borrows::{Tag, AccessKind}; +use crate::stacked_borrows::Tag; #[derive(Default, Clone, Debug)] -pub struct MemoryState { - pub stacked: stacked_borrows::MemoryState, - pub intptrcast: intptrcast::MemoryState, - /// The random number generator to use if Miri - /// is running in non-deterministic mode +pub struct MemoryExtra { + pub stacked_borrows: stacked_borrows::MemoryExtra, + pub intptrcast: intptrcast::MemoryExtra, + /// The random number generator to use if Miri is running in non-deterministic mode and to + /// enable intptrcast pub(crate) rng: Option } -#[derive(Debug, Clone,)] +#[derive(Debug, Clone)] pub struct AllocExtra { - pub stacks: stacked_borrows::Stacks, - pub base_addr: Cell>, + pub stacked_borrows: stacked_borrows::AllocExtra, + pub intptrcast: intptrcast::AllocExtra, } impl AllocationExtra for AllocExtra { @@ -29,11 +28,7 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - alloc.extra.stacks.for_each(ptr, size, |stack, global| { - stack.access(AccessKind::Read, ptr.tag, global)?; - Ok(()) - }) + alloc.extra.stacked_borrows.memory_read(ptr, size) } #[inline(always)] @@ -42,11 +37,7 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - alloc.extra.stacks.for_each(ptr, size, |stack, global| { - stack.access(AccessKind::Write, ptr.tag, global)?; - Ok(()) - }) + alloc.extra.stacked_borrows.memory_written(ptr, size) } #[inline(always)] @@ -55,9 +46,6 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - trace!("deallocation with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - alloc.extra.stacks.for_each(ptr, size, |stack, global| { - stack.dealloc(ptr.tag, global) - }) + alloc.extra.stacked_borrows.memory_deallocated(ptr, size) } } diff --git a/src/operator.rs b/src/operator.rs index 0ebb1e71610a..8f2b75d6043a 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -44,6 +44,9 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); + // If intptrcast is enabled and the operation is not an offset + // we can force the cast from pointers to integer addresses and + // then dispatch to rustc binary operation method if self.memory().extra.rng.is_some() && bin_op != Offset { let l_bits = self.force_bits(left.imm.to_scalar()?, left.layout.size)?; let r_bits = self.force_bits(right.imm.to_scalar()?, right.layout.size)?; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index ea70c28709ce..c47ad95c04b3 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -16,6 +16,7 @@ use crate::{ pub type PtrId = NonZeroU64; pub type CallId = NonZeroU64; +pub type AllocExtra = Stacks; /// Tracking pointer provenance #[derive(Copy, Clone, Hash, PartialEq, Eq)] @@ -86,7 +87,7 @@ pub struct Stacks { // Even reading memory can have effects on the stack, so we need a `RefCell` here. stacks: RefCell>, // Pointer to global state - global: MemoryState, + global: MemoryExtra, } /// Extra global state, available to the memory access hooks. @@ -104,7 +105,7 @@ pub struct GlobalState { active_calls: HashSet, } /// Memory extra state gives us interior mutable access to the global state. -pub type MemoryState = Rc>; +pub type MemoryExtra = Rc>; /// Indicates which kind of access is being performed. #[derive(Copy, Clone, Hash, PartialEq, Eq)] @@ -286,7 +287,7 @@ impl<'tcx> Stack { /// Test if a memory `access` using pointer tagged `tag` is granted. /// If yes, return the index of the item that granted it. - pub(crate) fn access( + fn access( &mut self, access: AccessKind, tag: Tag, @@ -336,7 +337,7 @@ impl<'tcx> Stack { /// Deallocate a location: Like a write access, but also there must be no /// active protectors at all because we will remove all items. - pub(crate) fn dealloc( + fn dealloc( &mut self, tag: Tag, global: &GlobalState, @@ -423,7 +424,7 @@ impl<'tcx> Stacks { size: Size, perm: Permission, tag: Tag, - extra: MemoryState, + extra: MemoryExtra, ) -> Self { let item = Item { perm, tag, protector: None }; let stack = Stack { @@ -437,7 +438,7 @@ impl<'tcx> Stacks { } /// Call `f` on every stack in the range. - pub(crate) fn for_each( + fn for_each( &self, ptr: Pointer, size: Size, @@ -457,7 +458,7 @@ impl Stacks { pub fn new_allocation( id: AllocId, size: Size, - extra: MemoryState, + extra: MemoryExtra, kind: MemoryKind, ) -> (Self, Tag) { let (tag, perm) = match kind { @@ -476,6 +477,44 @@ impl Stacks { let stack = Stacks::new(size, perm, tag, extra); (stack, tag) } + + #[inline(always)] + pub fn memory_read<'tcx>( + &self, + ptr: Pointer, + size: Size, + ) -> InterpResult<'tcx> { + trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); + self.for_each(ptr, size, |stack, global| { + stack.access(AccessKind::Read, ptr.tag, global)?; + Ok(()) + }) + } + + #[inline(always)] + pub fn memory_written<'tcx>( + &mut self, + ptr: Pointer, + size: Size, + ) -> InterpResult<'tcx> { + trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); + self.for_each(ptr, size, |stack, global| { + stack.access(AccessKind::Write, ptr.tag, global)?; + Ok(()) + }) + } + + #[inline(always)] + pub fn memory_deallocated<'tcx>( + &mut self, + ptr: Pointer, + size: Size, + ) -> InterpResult<'tcx> { + trace!("deallocation with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); + self.for_each(ptr, size, |stack, global| { + stack.dealloc(ptr.tag, global) + }) + } } /// Retagging/reborrowing. There is some policy in here, such as which permissions @@ -514,14 +553,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We are only ever `SharedReadOnly` inside the frozen bits. let perm = if frozen { Permission::SharedReadOnly } else { Permission::SharedReadWrite }; let item = Item { perm, tag: new_tag, protector }; - alloc.extra.stacks.for_each(cur_ptr, size, |stack, global| { + alloc.extra.stacked_borrows.for_each(cur_ptr, size, |stack, global| { stack.grant(cur_ptr.tag, item, global) }) }); } }; let item = Item { perm, tag: new_tag, protector }; - alloc.extra.stacks.for_each(ptr, size, |stack, global| { + alloc.extra.stacked_borrows.for_each(ptr, size, |stack, global| { stack.grant(ptr.tag, item, global) }) } @@ -548,7 +587,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Compute new borrow. let new_tag = match kind { RefKind::Raw { .. } => Tag::Untagged, - _ => Tag::Tagged(this.memory().extra.stacked.borrow_mut().new_ptr()), + _ => Tag::Tagged(this.memory().extra.stacked_borrows.borrow_mut().new_ptr()), }; // Reborrow. @@ -582,7 +621,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ty::RawPtr(tym) if kind == RetagKind::Raw => Some((RefKind::Raw { mutable: tym.mutbl == MutMutable }, false)), // Boxes do not get a protector: protectors reflect that references outlive the call - // they were passed in to; that's just not the case for boxes. + // they were passed in to; that's just not the case for boxes. ty::Adt(..) if ty.is_box() => Some((RefKind::Unique { two_phase: false }, false)), _ => None, } From 7a6438ada68b30f194985da5586b640138d768dc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 25 Jun 2019 10:05:34 +0200 Subject: [PATCH 0848/5092] add snippet for running Miri on CI --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index 82fe738e0310..91dcfd7cf83b 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,24 @@ fn does_not_work_on_miri() { } ``` +### Running Miri on CI + +To run Miri on CI, make sure that you handle the case where the latest nightly +does not ship the Miri component because it currently does not build. For +example, you can use the following snippet to always test with the latest +nightly that *does* come with Miri: + +```sh +MIRI_NIGHTLY=nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/miri) +echo "Installing latest nightly with Miri: $MIRI_NIGHTLY" +rustup default "$MIRI_NIGHTLY" + +rustup component add miri +cargo miri setup + +cargo miri test -- -- -Zunstable-options --exclude-should-panic +``` + ### Common Problems When using the above instructions, you may encounter a number of confusing compiler From 7fbf8e53a22925a5ff865b3546f881f7542c4f9e Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 25 Jun 2019 14:07:23 -0500 Subject: [PATCH 0849/5092] Fix alignment of base addresses --- src/intptrcast.rs | 29 ++++++++++--------- src/lib.rs | 1 + .../{intptrcast-truncate.rs => intptrcast.rs} | 0 3 files changed, 17 insertions(+), 13 deletions(-) rename tests/run-pass/{intptrcast-truncate.rs => intptrcast.rs} (100%) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index c48e7b7772b1..ad0489fa7de8 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -36,25 +36,25 @@ impl Default for GlobalState { impl<'mir, 'tcx> GlobalState { pub fn int_to_ptr( - base_addr: u64, + int: u64, memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>, ) -> InterpResult<'tcx, Pointer> { let global_state = memory.extra.intptrcast.borrow(); - match global_state.int_to_ptr_map.binary_search_by_key(&base_addr, |(addr, _)| *addr) { + match global_state.int_to_ptr_map.binary_search_by_key(&int, |(addr, _)| *addr) { Ok(pos) => { let (_, alloc_id) = global_state.int_to_ptr_map[pos]; - // `base_addr` is the starting address for an allocation, the offset should be + // `int` is equal to the starting address for an allocation, the offset should be // zero. The pointer is untagged because it was created from a cast Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged)) }, Err(0) => err!(DanglingPointerDeref), Err(pos) => { - // This is the gargest of the adresses smaller than `base_addr`, + // This is the largest of the adresses smaller than `int`, // i.e. the greatest lower bound (glb) let (glb, alloc_id) = global_state.int_to_ptr_map[pos - 1]; - // This never overflows because `base_addr >= glb` - let offset = base_addr - glb; + // This never overflows because `int >= glb` + let offset = int - glb; // If the offset exceeds the size of the allocation, this access is illegal if offset <= memory.get(alloc_id)?.bytes.len() as u64 { // This pointer is untagged because it was created from a cast @@ -77,16 +77,13 @@ impl<'mir, 'tcx> GlobalState { let base_addr = match alloc.extra.intptrcast.base_addr.get() { Some(base_addr) => base_addr, None => { - let base_addr = global_state.next_base_addr; - global_state.next_base_addr += alloc.bytes.len() as u64; - + // This allocation does not have a base address yet, pick one. + let base_addr = Self::align_addr(global_state.next_base_addr, alloc.align.bytes()); + global_state.next_base_addr = base_addr + alloc.bytes.len() as u64; alloc.extra.intptrcast.base_addr.set(Some(base_addr)); - - let elem = (base_addr, ptr.alloc_id); - // Given that `next_base_addr` increases in each allocation, pushing the // corresponding tuple keeps `int_to_ptr_map` sorted - global_state.int_to_ptr_map.push(elem); + global_state.int_to_ptr_map.push((base_addr, ptr.alloc_id)); base_addr } @@ -94,4 +91,10 @@ impl<'mir, 'tcx> GlobalState { Ok(base_addr + ptr.offset.bytes()) } + + /// Shifts `addr` to make it aligned with `align` by rounding `addr` to the smallest multiple + /// of `align` that is strictly larger to `addr` + fn align_addr(addr: u64, align: u64) -> u64 { + addr + align - addr % align + } } diff --git a/src/lib.rs b/src/lib.rs index 77acd3045da5..6b1ada69d397 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -85,6 +85,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( Evaluator::new(config.validate), ); + // FIXME: InterpretCx::new should take an initial MemoryExtra ecx.memory_mut().extra.rng = config.seed.map(StdRng::seed_from_u64); let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); diff --git a/tests/run-pass/intptrcast-truncate.rs b/tests/run-pass/intptrcast.rs similarity index 100% rename from tests/run-pass/intptrcast-truncate.rs rename to tests/run-pass/intptrcast.rs From 413a3515525829e1ddd93dbb391da0fe45e16ff8 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 26 Jun 2019 13:09:50 -0500 Subject: [PATCH 0850/5092] Initialize MemoryExtra with StdRng --- src/lib.rs | 6 ++---- src/memory.rs | 10 ++++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6b1ada69d397..7bab1762bdd6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,7 +50,7 @@ use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; use crate::mono_hash_map::MonoHashMap; pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; -use crate::memory::AllocExtra; +use crate::memory::{MemoryExtra, AllocExtra}; // Used by priroda. pub use crate::stacked_borrows::{Tag, Permission, Stack, Stacks, Item}; @@ -83,10 +83,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), Evaluator::new(config.validate), + MemoryExtra::with_rng(config.seed.map(StdRng::seed_from_u64)), ); - - // FIXME: InterpretCx::new should take an initial MemoryExtra - ecx.memory_mut().extra.rng = config.seed.map(StdRng::seed_from_u64); let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; diff --git a/src/memory.rs b/src/memory.rs index ea8f01a808c0..252e1cc08ae5 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -15,6 +15,16 @@ pub struct MemoryExtra { pub(crate) rng: Option } +impl MemoryExtra { + pub fn with_rng(rng: Option) -> Self { + MemoryExtra { + stacked_borrows: Default::default(), + intptrcast: Default::default(), + rng, + } + } +} + #[derive(Debug, Clone)] pub struct AllocExtra { pub stacked_borrows: stacked_borrows::AllocExtra, From 373a4ee1e99661dd9d708626b41d0ed0e9fbe254 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 26 Jun 2019 13:55:56 -0500 Subject: [PATCH 0851/5092] Remove default derive for MemoryExtra --- src/memory.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/memory.rs b/src/memory.rs index 252e1cc08ae5..e1ccafaae282 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -6,7 +6,7 @@ use rustc_target::abi::Size; use crate::{stacked_borrows, intptrcast}; use crate::stacked_borrows::Tag; -#[derive(Default, Clone, Debug)] +#[derive(Clone, Debug)] pub struct MemoryExtra { pub stacked_borrows: stacked_borrows::MemoryExtra, pub intptrcast: intptrcast::MemoryExtra, From 38b947b9535838d7e62aad684edc69f94b1f97f5 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Thu, 27 Jun 2019 21:46:24 -0400 Subject: [PATCH 0852/5092] Show usage if run without arguments Before, running `./miri` without arguments gave './miri: 92: shift: can't shift that many' if run with /bin/sh, or no output at all when run with bash. Although that gives some indication of the error, it's not as helpful as showing the usage. --- miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri b/miri index 89df4f205447..15bfeed4da06 100755 --- a/miri +++ b/miri @@ -89,7 +89,7 @@ find_sysroot() { # Determine command. COMMAND="$1" -shift +[ $# -gt 0 ] && shift # Determine flags passed to all cargo invocations. # This is a bit more annoying that one would hope due to From 6886864862b6a66a5e9807e98300e6e3254d27bf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 28 Jun 2019 09:12:11 +0200 Subject: [PATCH 0853/5092] ptr-to-int alignment sanity check --- src/intptrcast.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index ad0489fa7de8..176e1bc591c2 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -89,6 +89,7 @@ impl<'mir, 'tcx> GlobalState { } }; + debug_assert_eq!(base_addr % alloc.align.bytes(), 0); // sanity check Ok(base_addr + ptr.offset.bytes()) } From 4df5c6ac831c71f0c2b1dc2b6c0748798b42df4e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 28 Jun 2019 11:29:24 +0200 Subject: [PATCH 0854/5092] bump rand to released 0.7 --- test-cargo-miri/Cargo.lock | 7 +++---- test-cargo-miri/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 972b6bf074de..d404872f9db6 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -29,7 +29,7 @@ name = "cargo-miri-test" version = "0.1.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -73,10 +73,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rand" -version = "0.7.0-pre.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -150,7 +149,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319" "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" -"checksum rand 0.7.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)" = "866531c9bb6613da04a1e6ad99d27a7c8acd488020d7a8b177b058a10c900eec" +"checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" "checksum rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e193067942ef6f485a349a113329140d0ab9e2168ce92274499bb0e9a4190d9d" "checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 607514b995f6..c7fc62b79e84 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -8,4 +8,4 @@ edition = "2018" byteorder = "1.0" [dev-dependencies] -rand = { version = "0.7.0-pre.0", features = ["small_rng"] } +rand = { version = "0.7", features = ["small_rng"] } From afe42625e51c9b102895af86118354ada7ad8e26 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 28 Jun 2019 20:42:00 +0200 Subject: [PATCH 0855/5092] test pointer string formatting --- tests/run-pass/intptrcast.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/run-pass/intptrcast.rs b/tests/run-pass/intptrcast.rs index 4ff57caf95c2..40b21f9a4729 100644 --- a/tests/run-pass/intptrcast.rs +++ b/tests/run-pass/intptrcast.rs @@ -1,9 +1,14 @@ // compile-flags: -Zmiri-seed=0000000000000000 fn main() { + // Some casting-to-int with arithmetic. let x = &42 as *const i32 as usize; let y = x * 2; assert_eq!(y, x + x); let z = y as u8 as usize; assert_eq!(z, y % 256); + + // Pointer string formatting! We can't check the output as it changes when libstd changes, + // but we can make sure Miri does not error. + format!("{:?}", &mut 13 as *mut _); } From 67d3779b0ce5a1f2e735e4497af5321a9000105a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 27 Jun 2019 23:59:00 +0200 Subject: [PATCH 0856/5092] move most of the stuff from lib.rs into machine.rs, and initialization + main loop into eval.rs --- src/eval.rs | 248 +++++++++++++++++++++ src/helpers.rs | 2 +- src/lib.rs | 578 +----------------------------------------------- src/machine.rs | 384 ++++++++++++++++++++++++++++++++ src/memory.rs | 51 ----- src/operator.rs | 2 +- 6 files changed, 642 insertions(+), 623 deletions(-) create mode 100644 src/eval.rs create mode 100644 src/machine.rs delete mode 100644 src/memory.rs diff --git a/src/eval.rs b/src/eval.rs new file mode 100644 index 000000000000..5f7d85b7445f --- /dev/null +++ b/src/eval.rs @@ -0,0 +1,248 @@ +use rand::rngs::StdRng; +use rand::SeedableRng; + +use syntax::source_map::DUMMY_SP; +use rustc::ty::{self, TyCtxt}; +use rustc::ty::layout::{LayoutOf, Size, Align}; +use rustc::hir::def_id::DefId; +use rustc::mir; + +use crate::{ + InterpResult, InterpError, InterpretCx, StackPopCleanup, struct_error, + Scalar, Tag, Pointer, + MiriMemoryKind, Evaluator, TlsEvalContextExt, +}; + +/// Configuration needed to spawn a Miri instance. +#[derive(Clone)] +pub struct MiriConfig { + pub validate: bool, + pub args: Vec, + + // The seed to use when non-determinism is required (e.g. getrandom()) + pub seed: Option +} + +// Used by priroda. +pub fn create_ecx<'mir, 'tcx: 'mir>( + tcx: TyCtxt<'tcx>, + main_id: DefId, + config: MiriConfig, +) -> InterpResult<'tcx, InterpretCx<'mir, 'tcx, Evaluator<'tcx>>> { + let mut ecx = InterpretCx::new( + tcx.at(syntax::source_map::DUMMY_SP), + ty::ParamEnv::reveal_all(), + Evaluator::new(config.validate), + ); + + // FIXME: InterpretCx::new should take an initial MemoryExtra + ecx.memory_mut().extra.rng = config.seed.map(StdRng::seed_from_u64); + + let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); + let main_mir = ecx.load_mir(main_instance.def)?; + + if !main_mir.return_ty().is_unit() || main_mir.arg_count != 0 { + return err!(Unimplemented( + "miri does not support main functions without `fn()` type signatures" + .to_owned(), + )); + } + + let start_id = tcx.lang_items().start_fn().unwrap(); + let main_ret_ty = tcx.fn_sig(main_id).output(); + let main_ret_ty = main_ret_ty.no_bound_vars().unwrap(); + let start_instance = ty::Instance::resolve( + ecx.tcx.tcx, + ty::ParamEnv::reveal_all(), + start_id, + ecx.tcx.mk_substs( + ::std::iter::once(ty::subst::Kind::from(main_ret_ty))) + ).unwrap(); + let start_mir = ecx.load_mir(start_instance.def)?; + + if start_mir.arg_count != 3 { + return err!(AbiViolation(format!( + "'start' lang item should have three arguments, but has {}", + start_mir.arg_count + ))); + } + + // Return value (in static memory so that it does not count as leak). + let ret = ecx.layout_of(start_mir.return_ty())?; + let ret_ptr = ecx.allocate(ret, MiriMemoryKind::Static.into()); + + // Push our stack frame. + ecx.push_stack_frame( + start_instance, + // There is no call site. + DUMMY_SP, + start_mir, + Some(ret_ptr.into()), + StackPopCleanup::None { cleanup: true }, + )?; + + let mut args = ecx.frame().body.args_iter(); + + // First argument: pointer to `main()`. + let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance); + let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; + ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?; + + // Second argument (argc): `1`. + let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; + let argc = Scalar::from_uint(config.args.len() as u128, dest.layout.size); + ecx.write_scalar(argc, dest)?; + // Store argc for macOS's `_NSGetArgc`. + { + let argc_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into()); + ecx.write_scalar(argc, argc_place.into())?; + ecx.machine.argc = Some(argc_place.ptr.to_ptr()?); + } + + // FIXME: extract main source file path. + // Third argument (`argv`): created from `config.args`. + let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; + // For Windows, construct a command string with all the aguments. + let mut cmd = String::new(); + for arg in config.args.iter() { + if !cmd.is_empty() { + cmd.push(' '); + } + cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into())); + } + // Don't forget `0` terminator. + cmd.push(std::char::from_u32(0).unwrap()); + // Collect the pointers to the individual strings. + let mut argvs = Vec::>::new(); + for arg in config.args { + // Add `0` terminator. + let mut arg = arg.into_bytes(); + arg.push(0); + argvs.push(ecx.memory_mut().allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Static.into())); + } + // Make an array with all these pointers, in the Miri memory. + let argvs_layout = ecx.layout_of(ecx.tcx.mk_array(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8), argvs.len() as u64))?; + let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into()); + for (idx, arg) in argvs.into_iter().enumerate() { + let place = ecx.mplace_field(argvs_place, idx as u64)?; + ecx.write_scalar(Scalar::Ptr(arg), place.into())?; + } + ecx.memory_mut().mark_immutable(argvs_place.to_ptr()?.alloc_id)?; + // Write a pointer to that place as the argument. + let argv = argvs_place.ptr; + ecx.write_scalar(argv, dest)?; + // Store `argv` for macOS `_NSGetArgv`. + { + let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into()); + ecx.write_scalar(argv, argv_place.into())?; + ecx.machine.argv = Some(argv_place.ptr.to_ptr()?); + } + // Store command line as UTF-16 for Windows `GetCommandLineW`. + { + let tcx = &{ecx.tcx.tcx}; + let cmd_utf16: Vec = cmd.encode_utf16().collect(); + let cmd_ptr = ecx.memory_mut().allocate( + Size::from_bytes(cmd_utf16.len() as u64 * 2), + Align::from_bytes(2).unwrap(), + MiriMemoryKind::Env.into(), + ); + ecx.machine.cmd_line = Some(cmd_ptr); + // Store the UTF-16 string. + let char_size = Size::from_bytes(2); + let cmd_alloc = ecx.memory_mut().get_mut(cmd_ptr.alloc_id)?; + let mut cur_ptr = cmd_ptr; + for &c in cmd_utf16.iter() { + cmd_alloc.write_scalar( + tcx, + cur_ptr, + Scalar::from_uint(c, char_size).into(), + char_size, + )?; + cur_ptr = cur_ptr.offset(char_size, tcx)?; + } + } + + assert!(args.next().is_none(), "start lang item has more arguments than expected"); + + Ok(ecx) +} + +pub fn eval_main<'tcx>( + tcx: TyCtxt<'tcx>, + main_id: DefId, + config: MiriConfig, +) { + let mut ecx = match create_ecx(tcx, main_id, config) { + Ok(ecx) => ecx, + Err(mut err) => { + err.print_backtrace(); + panic!("Miri initialziation error: {}", err.kind) + } + }; + + // Perform the main execution. + let res: InterpResult = (|| { + ecx.run()?; + ecx.run_tls_dtors() + })(); + + // Process the result. + match res { + Ok(()) => { + let leaks = ecx.memory().leak_report(); + // Disable the leak test on some platforms where we do not + // correctly implement TLS destructors. + let target_os = ecx.tcx.tcx.sess.target.target.target_os.to_lowercase(); + let ignore_leaks = target_os == "windows" || target_os == "macos"; + if !ignore_leaks && leaks != 0 { + tcx.sess.err("the evaluated program leaked memory"); + } + } + Err(mut e) => { + // Special treatment for some error kinds + let msg = match e.kind { + InterpError::Exit(code) => std::process::exit(code), + InterpError::NoMirFor(..) => + format!("{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", e), + _ => e.to_string() + }; + e.print_backtrace(); + if let Some(frame) = ecx.stack().last() { + let block = &frame.body.basic_blocks()[frame.block]; + let span = if frame.stmt < block.statements.len() { + block.statements[frame.stmt].source_info.span + } else { + block.terminator().source_info.span + }; + + let msg = format!("Miri evaluation error: {}", msg); + let mut err = struct_error(ecx.tcx.tcx.at(span), msg.as_str()); + let frames = ecx.generate_stacktrace(None); + err.span_label(span, msg); + // We iterate with indices because we need to look at the next frame (the caller). + for idx in 0..frames.len() { + let frame_info = &frames[idx]; + let call_site_is_local = frames.get(idx+1).map_or(false, + |caller_info| caller_info.instance.def_id().is_local()); + if call_site_is_local { + err.span_note(frame_info.call_site, &frame_info.to_string()); + } else { + err.note(&frame_info.to_string()); + } + } + err.emit(); + } else { + ecx.tcx.sess.err(&msg); + } + + for (i, frame) in ecx.stack().iter().enumerate() { + trace!("-------------------"); + trace!("Frame {}", i); + trace!(" return: {:?}", frame.return_place.map(|p| *p)); + for (i, local) in frame.locals.iter().enumerate() { + trace!(" local {}: {:?}", i, local.value); + } + } + } + } +} diff --git a/src/helpers.rs b/src/helpers.rs index 62a546767e89..f65eef557c96 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,6 +1,6 @@ use std::mem; -use rustc::ty::{self, layout}; +use rustc::ty::{self, layout::{self, Size}}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use crate::*; diff --git a/src/lib.rs b/src/lib.rs index 6b1ada69d397..ab9e9854c34c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,39 +21,24 @@ mod range_map; mod mono_hash_map; mod stacked_borrows; mod intptrcast; -mod memory; +mod machine; +mod eval; -use std::collections::HashMap; -use std::borrow::Cow; -use std::rc::Rc; - -use rand::rngs::StdRng; -use rand::SeedableRng; - -use rustc::ty::{self, TyCtxt, query::TyCtxtAt}; -use rustc::ty::layout::{LayoutOf, Size, Align}; -use rustc::hir::def_id::DefId; -use rustc::mir; +// Make all those symbols available in the same place as our own. pub use rustc_mir::interpret::*; // Resolve ambiguity. pub use rustc_mir::interpret::{self, AllocMap, PlaceTy}; -use syntax::attr; -use syntax::source_map::DUMMY_SP; -use syntax::symbol::sym; pub use crate::fn_call::EvalContextExt as MissingFnsEvalContextExt; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::intrinsic::EvalContextExt as IntrinsicEvalContextExt; pub use crate::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; -use crate::range_map::RangeMap; -#[allow(unused_imports)] // FIXME: rustc bug, issue . +pub use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; -use crate::mono_hash_map::MonoHashMap; -pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; -use crate::memory::AllocExtra; - -// Used by priroda. -pub use crate::stacked_borrows::{Tag, Permission, Stack, Stacks, Item}; +pub use crate::mono_hash_map::MonoHashMap; +pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt, Tag, Permission, Stack, Stacks, Item}; +pub use crate::machine::{MemoryExtra, AllocExtra, MiriMemoryKind, Evaluator, MiriEvalContext, MiriEvalContextExt}; +pub use crate::eval::{eval_main, create_ecx, MiriConfig}; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. @@ -62,550 +47,3 @@ pub fn miri_default_args() -> &'static [&'static str] { // set, which happens in `bootstrap/bin/rustc.rs` in the rustc sources. &["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0", "--cfg=miri"] } - -/// Configuration needed to spawn a Miri instance. -#[derive(Clone)] -pub struct MiriConfig { - pub validate: bool, - pub args: Vec, - - // The seed to use when non-determinism is required (e.g. getrandom()) - pub seed: Option -} - -// Used by priroda. -pub fn create_ecx<'mir, 'tcx: 'mir>( - tcx: TyCtxt<'tcx>, - main_id: DefId, - config: MiriConfig, -) -> InterpResult<'tcx, InterpretCx<'mir, 'tcx, Evaluator<'tcx>>> { - let mut ecx = InterpretCx::new( - tcx.at(syntax::source_map::DUMMY_SP), - ty::ParamEnv::reveal_all(), - Evaluator::new(config.validate), - ); - - // FIXME: InterpretCx::new should take an initial MemoryExtra - ecx.memory_mut().extra.rng = config.seed.map(StdRng::seed_from_u64); - - let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); - let main_mir = ecx.load_mir(main_instance.def)?; - - if !main_mir.return_ty().is_unit() || main_mir.arg_count != 0 { - return err!(Unimplemented( - "miri does not support main functions without `fn()` type signatures" - .to_owned(), - )); - } - - let start_id = tcx.lang_items().start_fn().unwrap(); - let main_ret_ty = tcx.fn_sig(main_id).output(); - let main_ret_ty = main_ret_ty.no_bound_vars().unwrap(); - let start_instance = ty::Instance::resolve( - ecx.tcx.tcx, - ty::ParamEnv::reveal_all(), - start_id, - ecx.tcx.mk_substs( - ::std::iter::once(ty::subst::Kind::from(main_ret_ty))) - ).unwrap(); - let start_mir = ecx.load_mir(start_instance.def)?; - - if start_mir.arg_count != 3 { - return err!(AbiViolation(format!( - "'start' lang item should have three arguments, but has {}", - start_mir.arg_count - ))); - } - - // Return value (in static memory so that it does not count as leak). - let ret = ecx.layout_of(start_mir.return_ty())?; - let ret_ptr = ecx.allocate(ret, MiriMemoryKind::Static.into()); - - // Push our stack frame. - ecx.push_stack_frame( - start_instance, - // There is no call site. - DUMMY_SP, - start_mir, - Some(ret_ptr.into()), - StackPopCleanup::None { cleanup: true }, - )?; - - let mut args = ecx.frame().body.args_iter(); - - // First argument: pointer to `main()`. - let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance); - let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; - ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?; - - // Second argument (argc): `1`. - let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; - let argc = Scalar::from_uint(config.args.len() as u128, dest.layout.size); - ecx.write_scalar(argc, dest)?; - // Store argc for macOS's `_NSGetArgc`. - { - let argc_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into()); - ecx.write_scalar(argc, argc_place.into())?; - ecx.machine.argc = Some(argc_place.ptr.to_ptr()?); - } - - // FIXME: extract main source file path. - // Third argument (`argv`): created from `config.args`. - let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; - // For Windows, construct a command string with all the aguments. - let mut cmd = String::new(); - for arg in config.args.iter() { - if !cmd.is_empty() { - cmd.push(' '); - } - cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into())); - } - // Don't forget `0` terminator. - cmd.push(std::char::from_u32(0).unwrap()); - // Collect the pointers to the individual strings. - let mut argvs = Vec::>::new(); - for arg in config.args { - // Add `0` terminator. - let mut arg = arg.into_bytes(); - arg.push(0); - argvs.push(ecx.memory_mut().allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Static.into())); - } - // Make an array with all these pointers, in the Miri memory. - let argvs_layout = ecx.layout_of(ecx.tcx.mk_array(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8), argvs.len() as u64))?; - let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into()); - for (idx, arg) in argvs.into_iter().enumerate() { - let place = ecx.mplace_field(argvs_place, idx as u64)?; - ecx.write_scalar(Scalar::Ptr(arg), place.into())?; - } - ecx.memory_mut().mark_immutable(argvs_place.to_ptr()?.alloc_id)?; - // Write a pointer to that place as the argument. - let argv = argvs_place.ptr; - ecx.write_scalar(argv, dest)?; - // Store `argv` for macOS `_NSGetArgv`. - { - let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into()); - ecx.write_scalar(argv, argv_place.into())?; - ecx.machine.argv = Some(argv_place.ptr.to_ptr()?); - } - // Store command line as UTF-16 for Windows `GetCommandLineW`. - { - let tcx = &{ecx.tcx.tcx}; - let cmd_utf16: Vec = cmd.encode_utf16().collect(); - let cmd_ptr = ecx.memory_mut().allocate( - Size::from_bytes(cmd_utf16.len() as u64 * 2), - Align::from_bytes(2).unwrap(), - MiriMemoryKind::Env.into(), - ); - ecx.machine.cmd_line = Some(cmd_ptr); - // Store the UTF-16 string. - let char_size = Size::from_bytes(2); - let cmd_alloc = ecx.memory_mut().get_mut(cmd_ptr.alloc_id)?; - let mut cur_ptr = cmd_ptr; - for &c in cmd_utf16.iter() { - cmd_alloc.write_scalar( - tcx, - cur_ptr, - Scalar::from_uint(c, char_size).into(), - char_size, - )?; - cur_ptr = cur_ptr.offset(char_size, tcx)?; - } - } - - assert!(args.next().is_none(), "start lang item has more arguments than expected"); - - Ok(ecx) -} - -pub fn eval_main<'tcx>( - tcx: TyCtxt<'tcx>, - main_id: DefId, - config: MiriConfig, -) { - let mut ecx = match create_ecx(tcx, main_id, config) { - Ok(ecx) => ecx, - Err(mut err) => { - err.print_backtrace(); - panic!("Miri initialziation error: {}", err.kind) - } - }; - - // Perform the main execution. - let res: InterpResult = (|| { - ecx.run()?; - ecx.run_tls_dtors() - })(); - - // Process the result. - match res { - Ok(()) => { - let leaks = ecx.memory().leak_report(); - // Disable the leak test on some platforms where we do not - // correctly implement TLS destructors. - let target_os = ecx.tcx.tcx.sess.target.target.target_os.to_lowercase(); - let ignore_leaks = target_os == "windows" || target_os == "macos"; - if !ignore_leaks && leaks != 0 { - tcx.sess.err("the evaluated program leaked memory"); - } - } - Err(mut e) => { - // Special treatment for some error kinds - let msg = match e.kind { - InterpError::Exit(code) => std::process::exit(code), - InterpError::NoMirFor(..) => - format!("{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", e), - _ => e.to_string() - }; - e.print_backtrace(); - if let Some(frame) = ecx.stack().last() { - let block = &frame.body.basic_blocks()[frame.block]; - let span = if frame.stmt < block.statements.len() { - block.statements[frame.stmt].source_info.span - } else { - block.terminator().source_info.span - }; - - let msg = format!("Miri evaluation error: {}", msg); - let mut err = struct_error(ecx.tcx.tcx.at(span), msg.as_str()); - let frames = ecx.generate_stacktrace(None); - err.span_label(span, msg); - // We iterate with indices because we need to look at the next frame (the caller). - for idx in 0..frames.len() { - let frame_info = &frames[idx]; - let call_site_is_local = frames.get(idx+1).map_or(false, - |caller_info| caller_info.instance.def_id().is_local()); - if call_site_is_local { - err.span_note(frame_info.call_site, &frame_info.to_string()); - } else { - err.note(&frame_info.to_string()); - } - } - err.emit(); - } else { - ecx.tcx.sess.err(&msg); - } - - for (i, frame) in ecx.stack().iter().enumerate() { - trace!("-------------------"); - trace!("Frame {}", i); - trace!(" return: {:?}", frame.return_place.map(|p| *p)); - for (i, local) in frame.locals.iter().enumerate() { - trace!(" local {}: {:?}", i, local.value); - } - } - } - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum MiriMemoryKind { - /// `__rust_alloc` memory. - Rust, - /// `malloc` memory. - C, - /// Part of env var emulation. - Env, - /// Statics. - Static, -} - -impl Into> for MiriMemoryKind { - #[inline(always)] - fn into(self) -> MemoryKind { - MemoryKind::Machine(self) - } -} - -impl MayLeak for MiriMemoryKind { - #[inline(always)] - fn may_leak(self) -> bool { - use self::MiriMemoryKind::*; - match self { - Rust | C => false, - Env | Static => true, - } - } -} - -pub struct Evaluator<'tcx> { - /// Environment variables set by `setenv`. - /// Miri does not expose env vars from the host to the emulated program. - pub(crate) env_vars: HashMap, Pointer>, - - /// Program arguments (`Option` because we can only initialize them after creating the ecx). - /// These are *pointers* to argc/argv because macOS. - /// We also need the full command line as one string because of Windows. - pub(crate) argc: Option>, - pub(crate) argv: Option>, - pub(crate) cmd_line: Option>, - - /// Last OS error. - pub(crate) last_error: u32, - - /// TLS state. - pub(crate) tls: TlsData<'tcx>, - - /// Whether to enforce the validity invariant. - pub(crate) validate: bool, -} - -impl<'tcx> Evaluator<'tcx> { - fn new(validate: bool) -> Self { - Evaluator { - env_vars: HashMap::default(), - argc: None, - argv: None, - cmd_line: None, - last_error: 0, - tls: TlsData::default(), - validate, - } - } -} - -// FIXME: rustc issue . -#[allow(dead_code)] -type MiriEvalContext<'mir, 'tcx> = InterpretCx<'mir, 'tcx, Evaluator<'tcx>>; - -// A little trait that's useful to be inherited by extension traits. -pub trait MiriEvalContextExt<'mir, 'tcx> { - fn eval_context_ref(&self) -> &MiriEvalContext<'mir, 'tcx>; - fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'mir, 'tcx>; -} -impl<'mir, 'tcx> MiriEvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> { - #[inline(always)] - fn eval_context_ref(&self) -> &MiriEvalContext<'mir, 'tcx> { - self - } - #[inline(always)] - fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'mir, 'tcx> { - self - } -} - -impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { - type MemoryKinds = MiriMemoryKind; - - type FrameExtra = stacked_borrows::CallId; - type MemoryExtra = memory::MemoryExtra; - type AllocExtra = memory::AllocExtra; - type PointerTag = Tag; - - type MemoryMap = MonoHashMap, Allocation)>; - - const STATIC_KIND: Option = Some(MiriMemoryKind::Static); - - #[inline(always)] - fn enforce_validity(ecx: &InterpretCx<'mir, 'tcx, Self>) -> bool { - ecx.machine.validate - } - - /// Returns `Ok()` when the function was handled; fail otherwise. - #[inline(always)] - fn find_fn( - ecx: &mut InterpretCx<'mir, 'tcx, Self>, - instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Tag>], - dest: Option>, - ret: Option, - ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { - ecx.find_fn(instance, args, dest, ret) - } - - #[inline(always)] - fn call_intrinsic( - ecx: &mut rustc_mir::interpret::InterpretCx<'mir, 'tcx, Self>, - instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { - ecx.call_intrinsic(instance, args, dest) - } - - #[inline(always)] - fn ptr_op( - ecx: &rustc_mir::interpret::InterpretCx<'mir, 'tcx, Self>, - bin_op: mir::BinOp, - left: ImmTy<'tcx, Tag>, - right: ImmTy<'tcx, Tag>, - ) -> InterpResult<'tcx, (Scalar, bool)> { - ecx.ptr_op(bin_op, left, right) - } - - fn box_alloc( - ecx: &mut InterpretCx<'mir, 'tcx, Self>, - dest: PlaceTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { - trace!("box_alloc for {:?}", dest.layout.ty); - // Call the `exchange_malloc` lang item. - let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap(); - let malloc = ty::Instance::mono(ecx.tcx.tcx, malloc); - let malloc_mir = ecx.load_mir(malloc.def)?; - ecx.push_stack_frame( - malloc, - malloc_mir.span, - malloc_mir, - Some(dest), - // Don't do anything when we are done. The `statement()` function will increment - // the old stack frame's stmt counter to the next statement, which means that when - // `exchange_malloc` returns, we go on evaluating exactly where we want to be. - StackPopCleanup::None { cleanup: true }, - )?; - - let mut args = ecx.frame().body.args_iter(); - let layout = ecx.layout_of(dest.layout.ty.builtin_deref(false).unwrap().ty)?; - - // First argument: `size`. - // (`0` is allowed here -- this is expected to be handled by the lang item). - let arg = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; - let size = layout.size.bytes(); - ecx.write_scalar(Scalar::from_uint(size, arg.layout.size), arg)?; - - // Second argument: `align`. - let arg = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; - let align = layout.align.abi.bytes(); - ecx.write_scalar(Scalar::from_uint(align, arg.layout.size), arg)?; - - // No more arguments. - assert!( - args.next().is_none(), - "`exchange_malloc` lang item has more arguments than expected" - ); - Ok(()) - } - - fn find_foreign_static( - def_id: DefId, - tcx: TyCtxtAt<'tcx>, - ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { - let attrs = tcx.get_attrs(def_id); - let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { - Some(name) => name.as_str(), - None => tcx.item_name(def_id).as_str(), - }; - - let alloc = match link_name.get() { - "__cxa_thread_atexit_impl" => { - // This should be all-zero, pointer-sized. - let size = tcx.data_layout.pointer_size; - let data = vec![0; size.bytes() as usize]; - Allocation::from_bytes(&data, tcx.data_layout.pointer_align.abi) - } - _ => return err!(Unimplemented( - format!("can't access foreign static: {}", link_name), - )), - }; - Ok(Cow::Owned(alloc)) - } - - #[inline(always)] - fn before_terminator(_ecx: &mut InterpretCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> - { - // We are not interested in detecting loops. - Ok(()) - } - - fn tag_allocation<'b>( - id: AllocId, - alloc: Cow<'b, Allocation>, - kind: Option>, - memory: &Memory<'mir, 'tcx, Self>, - ) -> (Cow<'b, Allocation>, Self::PointerTag) { - let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); - let alloc = alloc.into_owned(); - let (stacks, base_tag) = Stacks::new_allocation( - id, - Size::from_bytes(alloc.bytes.len() as u64), - Rc::clone(&memory.extra.stacked_borrows), - kind, - ); - if kind != MiriMemoryKind::Static.into() { - assert!(alloc.relocations.is_empty(), "Only statics can come initialized with inner pointers"); - // Now we can rely on the inner pointers being static, too. - } - let mut memory_extra = memory.extra.stacked_borrows.borrow_mut(); - let alloc: Allocation = Allocation { - bytes: alloc.bytes, - relocations: Relocations::from_presorted( - alloc.relocations.iter() - // The allocations in the relocations (pointers stored *inside* this allocation) - // all get the base pointer tag. - .map(|&(offset, ((), alloc))| (offset, (memory_extra.static_base_ptr(alloc), alloc))) - .collect() - ), - undef_mask: alloc.undef_mask, - align: alloc.align, - mutability: alloc.mutability, - extra: AllocExtra { - stacked_borrows: stacks, - intptrcast: Default::default(), - }, - }; - (Cow::Owned(alloc), base_tag) - } - - #[inline(always)] - fn tag_static_base_pointer( - id: AllocId, - memory: &Memory<'mir, 'tcx, Self>, - ) -> Self::PointerTag { - memory.extra.stacked_borrows.borrow_mut().static_base_ptr(id) - } - - #[inline(always)] - fn retag( - ecx: &mut InterpretCx<'mir, 'tcx, Self>, - kind: mir::RetagKind, - place: PlaceTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { - if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !Self::enforce_validity(ecx) { - // No tracking, or no retagging. The latter is possible because a dependency of ours - // might be called with different flags than we are, so there are `Retag` - // statements but we do not want to execute them. - // Also, honor the whitelist in `enforce_validity` because otherwise we might retag - // uninitialized data. - Ok(()) - } else { - ecx.retag(kind, place) - } - } - - #[inline(always)] - fn stack_push( - ecx: &mut InterpretCx<'mir, 'tcx, Self>, - ) -> InterpResult<'tcx, stacked_borrows::CallId> { - Ok(ecx.memory().extra.stacked_borrows.borrow_mut().new_call()) - } - - #[inline(always)] - fn stack_pop( - ecx: &mut InterpretCx<'mir, 'tcx, Self>, - extra: stacked_borrows::CallId, - ) -> InterpResult<'tcx> { - Ok(ecx.memory().extra.stacked_borrows.borrow_mut().end_call(extra)) - } - - fn int_to_ptr( - int: u64, - memory: &Memory<'mir, 'tcx, Self>, - ) -> InterpResult<'tcx, Pointer> { - if int == 0 { - err!(InvalidNullPointerUsage) - } else if memory.extra.rng.is_none() { - err!(ReadBytesAsPointer) - } else { - intptrcast::GlobalState::int_to_ptr(int, memory) - } - } - - fn ptr_to_int( - ptr: Pointer, - memory: &Memory<'mir, 'tcx, Self>, - ) -> InterpResult<'tcx, u64> { - if memory.extra.rng.is_none() { - err!(ReadPointerAsBytes) - } else { - intptrcast::GlobalState::ptr_to_int(ptr, memory) - } - } -} diff --git a/src/machine.rs b/src/machine.rs new file mode 100644 index 000000000000..eb177fa2a185 --- /dev/null +++ b/src/machine.rs @@ -0,0 +1,384 @@ +use std::rc::Rc; +use std::borrow::Cow; +use std::collections::HashMap; + +use rand::rngs::StdRng; + +use syntax::attr; +use syntax::symbol::sym; +use rustc::hir::def_id::DefId; +use rustc::ty::{self, layout::{Size, LayoutOf}, query::TyCtxtAt}; +use rustc::mir; + +use crate::*; + +/// Extra memory kinds +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum MiriMemoryKind { + /// `__rust_alloc` memory. + Rust, + /// `malloc` memory. + C, + /// Part of env var emulation. + Env, + /// Statics. + Static, +} + +impl Into> for MiriMemoryKind { + #[inline(always)] + fn into(self) -> MemoryKind { + MemoryKind::Machine(self) + } +} + +/// Extra per-allocation data +#[derive(Debug, Clone)] +pub struct AllocExtra { + pub stacked_borrows: stacked_borrows::AllocExtra, + pub intptrcast: intptrcast::AllocExtra, +} + +/// Extra global memory data +#[derive(Default, Clone, Debug)] +pub struct MemoryExtra { + pub stacked_borrows: stacked_borrows::MemoryExtra, + pub intptrcast: intptrcast::MemoryExtra, + /// The random number generator to use if Miri is running in non-deterministic mode and to + /// enable intptrcast + pub(crate) rng: Option +} + +impl MemoryExtra { + pub fn with_rng(rng: Option) -> Self { + MemoryExtra { + stacked_borrows: Default::default(), + intptrcast: Default::default(), + rng, + } + } +} + +/// The machine itself. +pub struct Evaluator<'tcx> { + /// Environment variables set by `setenv`. + /// Miri does not expose env vars from the host to the emulated program. + pub(crate) env_vars: HashMap, Pointer>, + + /// Program arguments (`Option` because we can only initialize them after creating the ecx). + /// These are *pointers* to argc/argv because macOS. + /// We also need the full command line as one string because of Windows. + pub(crate) argc: Option>, + pub(crate) argv: Option>, + pub(crate) cmd_line: Option>, + + /// Last OS error. + pub(crate) last_error: u32, + + /// TLS state. + pub(crate) tls: TlsData<'tcx>, + + /// Whether to enforce the validity invariant. + pub(crate) validate: bool, +} + +impl<'tcx> Evaluator<'tcx> { + pub(crate) fn new(validate: bool) -> Self { + Evaluator { + env_vars: HashMap::default(), + argc: None, + argv: None, + cmd_line: None, + last_error: 0, + tls: TlsData::default(), + validate, + } + } +} + +/// A rustc InterpretCx for Miri. +pub type MiriEvalContext<'mir, 'tcx> = InterpretCx<'mir, 'tcx, Evaluator<'tcx>>; + +/// A little trait that's useful to be inherited by extension traits. +pub trait MiriEvalContextExt<'mir, 'tcx> { + fn eval_context_ref(&self) -> &MiriEvalContext<'mir, 'tcx>; + fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'mir, 'tcx>; +} +impl<'mir, 'tcx> MiriEvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> { + #[inline(always)] + fn eval_context_ref(&self) -> &MiriEvalContext<'mir, 'tcx> { + self + } + #[inline(always)] + fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'mir, 'tcx> { + self + } +} + +/// Machine hook implementations. +impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { + type MemoryKinds = MiriMemoryKind; + + type FrameExtra = stacked_borrows::CallId; + type MemoryExtra = MemoryExtra; + type AllocExtra = AllocExtra; + type PointerTag = Tag; + + type MemoryMap = MonoHashMap, Allocation)>; + + const STATIC_KIND: Option = Some(MiriMemoryKind::Static); + + #[inline(always)] + fn enforce_validity(ecx: &InterpretCx<'mir, 'tcx, Self>) -> bool { + ecx.machine.validate + } + + /// Returns `Ok()` when the function was handled; fail otherwise. + #[inline(always)] + fn find_fn( + ecx: &mut InterpretCx<'mir, 'tcx, Self>, + instance: ty::Instance<'tcx>, + args: &[OpTy<'tcx, Tag>], + dest: Option>, + ret: Option, + ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { + ecx.find_fn(instance, args, dest, ret) + } + + #[inline(always)] + fn call_intrinsic( + ecx: &mut rustc_mir::interpret::InterpretCx<'mir, 'tcx, Self>, + instance: ty::Instance<'tcx>, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + ecx.call_intrinsic(instance, args, dest) + } + + #[inline(always)] + fn ptr_op( + ecx: &rustc_mir::interpret::InterpretCx<'mir, 'tcx, Self>, + bin_op: mir::BinOp, + left: ImmTy<'tcx, Tag>, + right: ImmTy<'tcx, Tag>, + ) -> InterpResult<'tcx, (Scalar, bool)> { + ecx.ptr_op(bin_op, left, right) + } + + fn box_alloc( + ecx: &mut InterpretCx<'mir, 'tcx, Self>, + dest: PlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + trace!("box_alloc for {:?}", dest.layout.ty); + // Call the `exchange_malloc` lang item. + let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap(); + let malloc = ty::Instance::mono(ecx.tcx.tcx, malloc); + let malloc_mir = ecx.load_mir(malloc.def)?; + ecx.push_stack_frame( + malloc, + malloc_mir.span, + malloc_mir, + Some(dest), + // Don't do anything when we are done. The `statement()` function will increment + // the old stack frame's stmt counter to the next statement, which means that when + // `exchange_malloc` returns, we go on evaluating exactly where we want to be. + StackPopCleanup::None { cleanup: true }, + )?; + + let mut args = ecx.frame().body.args_iter(); + let layout = ecx.layout_of(dest.layout.ty.builtin_deref(false).unwrap().ty)?; + + // First argument: `size`. + // (`0` is allowed here -- this is expected to be handled by the lang item). + let arg = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; + let size = layout.size.bytes(); + ecx.write_scalar(Scalar::from_uint(size, arg.layout.size), arg)?; + + // Second argument: `align`. + let arg = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; + let align = layout.align.abi.bytes(); + ecx.write_scalar(Scalar::from_uint(align, arg.layout.size), arg)?; + + // No more arguments. + assert!( + args.next().is_none(), + "`exchange_malloc` lang item has more arguments than expected" + ); + Ok(()) + } + + fn find_foreign_static( + def_id: DefId, + tcx: TyCtxtAt<'tcx>, + ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { + let attrs = tcx.get_attrs(def_id); + let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { + Some(name) => name.as_str(), + None => tcx.item_name(def_id).as_str(), + }; + + let alloc = match link_name.get() { + "__cxa_thread_atexit_impl" => { + // This should be all-zero, pointer-sized. + let size = tcx.data_layout.pointer_size; + let data = vec![0; size.bytes() as usize]; + Allocation::from_bytes(&data, tcx.data_layout.pointer_align.abi) + } + _ => return err!(Unimplemented( + format!("can't access foreign static: {}", link_name), + )), + }; + Ok(Cow::Owned(alloc)) + } + + #[inline(always)] + fn before_terminator(_ecx: &mut InterpretCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> + { + // We are not interested in detecting loops. + Ok(()) + } + + fn tag_allocation<'b>( + id: AllocId, + alloc: Cow<'b, Allocation>, + kind: Option>, + memory: &Memory<'mir, 'tcx, Self>, + ) -> (Cow<'b, Allocation>, Self::PointerTag) { + let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); + let alloc = alloc.into_owned(); + let (stacks, base_tag) = Stacks::new_allocation( + id, + Size::from_bytes(alloc.bytes.len() as u64), + Rc::clone(&memory.extra.stacked_borrows), + kind, + ); + if kind != MiriMemoryKind::Static.into() { + assert!(alloc.relocations.is_empty(), "Only statics can come initialized with inner pointers"); + // Now we can rely on the inner pointers being static, too. + } + let mut memory_extra = memory.extra.stacked_borrows.borrow_mut(); + let alloc: Allocation = Allocation { + bytes: alloc.bytes, + relocations: Relocations::from_presorted( + alloc.relocations.iter() + // The allocations in the relocations (pointers stored *inside* this allocation) + // all get the base pointer tag. + .map(|&(offset, ((), alloc))| (offset, (memory_extra.static_base_ptr(alloc), alloc))) + .collect() + ), + undef_mask: alloc.undef_mask, + align: alloc.align, + mutability: alloc.mutability, + extra: AllocExtra { + stacked_borrows: stacks, + intptrcast: Default::default(), + }, + }; + (Cow::Owned(alloc), base_tag) + } + + #[inline(always)] + fn tag_static_base_pointer( + id: AllocId, + memory: &Memory<'mir, 'tcx, Self>, + ) -> Self::PointerTag { + memory.extra.stacked_borrows.borrow_mut().static_base_ptr(id) + } + + #[inline(always)] + fn retag( + ecx: &mut InterpretCx<'mir, 'tcx, Self>, + kind: mir::RetagKind, + place: PlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !Self::enforce_validity(ecx) { + // No tracking, or no retagging. The latter is possible because a dependency of ours + // might be called with different flags than we are, so there are `Retag` + // statements but we do not want to execute them. + // Also, honor the whitelist in `enforce_validity` because otherwise we might retag + // uninitialized data. + Ok(()) + } else { + ecx.retag(kind, place) + } + } + + #[inline(always)] + fn stack_push( + ecx: &mut InterpretCx<'mir, 'tcx, Self>, + ) -> InterpResult<'tcx, stacked_borrows::CallId> { + Ok(ecx.memory().extra.stacked_borrows.borrow_mut().new_call()) + } + + #[inline(always)] + fn stack_pop( + ecx: &mut InterpretCx<'mir, 'tcx, Self>, + extra: stacked_borrows::CallId, + ) -> InterpResult<'tcx> { + Ok(ecx.memory().extra.stacked_borrows.borrow_mut().end_call(extra)) + } + + fn int_to_ptr( + int: u64, + memory: &Memory<'mir, 'tcx, Self>, + ) -> InterpResult<'tcx, Pointer> { + if int == 0 { + err!(InvalidNullPointerUsage) + } else if memory.extra.rng.is_none() { + err!(ReadBytesAsPointer) + } else { + intptrcast::GlobalState::int_to_ptr(int, memory) + } + } + + fn ptr_to_int( + ptr: Pointer, + memory: &Memory<'mir, 'tcx, Self>, + ) -> InterpResult<'tcx, u64> { + if memory.extra.rng.is_none() { + err!(ReadPointerAsBytes) + } else { + intptrcast::GlobalState::ptr_to_int(ptr, memory) + } + } +} + +impl AllocationExtra for AllocExtra { + #[inline(always)] + fn memory_read<'tcx>( + alloc: &Allocation, + ptr: Pointer, + size: Size, + ) -> InterpResult<'tcx> { + alloc.extra.stacked_borrows.memory_read(ptr, size) + } + + #[inline(always)] + fn memory_written<'tcx>( + alloc: &mut Allocation, + ptr: Pointer, + size: Size, + ) -> InterpResult<'tcx> { + alloc.extra.stacked_borrows.memory_written(ptr, size) + } + + #[inline(always)] + fn memory_deallocated<'tcx>( + alloc: &mut Allocation, + ptr: Pointer, + size: Size, + ) -> InterpResult<'tcx> { + alloc.extra.stacked_borrows.memory_deallocated(ptr, size) + } +} + +impl MayLeak for MiriMemoryKind { + #[inline(always)] + fn may_leak(self) -> bool { + use self::MiriMemoryKind::*; + match self { + Rust | C => false, + Env | Static => true, + } + } +} diff --git a/src/memory.rs b/src/memory.rs deleted file mode 100644 index ea8f01a808c0..000000000000 --- a/src/memory.rs +++ /dev/null @@ -1,51 +0,0 @@ -use rand::rngs::StdRng; - -use rustc_mir::interpret::{Pointer, Allocation, AllocationExtra, InterpResult}; -use rustc_target::abi::Size; - -use crate::{stacked_borrows, intptrcast}; -use crate::stacked_borrows::Tag; - -#[derive(Default, Clone, Debug)] -pub struct MemoryExtra { - pub stacked_borrows: stacked_borrows::MemoryExtra, - pub intptrcast: intptrcast::MemoryExtra, - /// The random number generator to use if Miri is running in non-deterministic mode and to - /// enable intptrcast - pub(crate) rng: Option -} - -#[derive(Debug, Clone)] -pub struct AllocExtra { - pub stacked_borrows: stacked_borrows::AllocExtra, - pub intptrcast: intptrcast::AllocExtra, -} - -impl AllocationExtra for AllocExtra { - #[inline(always)] - fn memory_read<'tcx>( - alloc: &Allocation, - ptr: Pointer, - size: Size, - ) -> InterpResult<'tcx> { - alloc.extra.stacked_borrows.memory_read(ptr, size) - } - - #[inline(always)] - fn memory_written<'tcx>( - alloc: &mut Allocation, - ptr: Pointer, - size: Size, - ) -> InterpResult<'tcx> { - alloc.extra.stacked_borrows.memory_written(ptr, size) - } - - #[inline(always)] - fn memory_deallocated<'tcx>( - alloc: &mut Allocation, - ptr: Pointer, - size: Size, - ) -> InterpResult<'tcx> { - alloc.extra.stacked_borrows.memory_deallocated(ptr, size) - } -} diff --git a/src/operator.rs b/src/operator.rs index 572794a44add..0e25de7da5a9 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,4 +1,4 @@ -use rustc::ty::Ty; +use rustc::ty::{Ty, layout::{Size, LayoutOf}}; use rustc::mir; use crate::*; From aa5a9bc15233960b8c375e1fa45fd11e5ae5b6cb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 29 Jun 2019 14:15:05 +0200 Subject: [PATCH 0857/5092] some module comments --- src/eval.rs | 2 ++ src/machine.rs | 3 +++ src/range_map.rs | 5 +---- src/stacked_borrows.rs | 3 +++ src/tls.rs | 2 ++ 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index fd5404a981d2..616e11a51561 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -1,3 +1,5 @@ +//! Main evaluator loop and setting up the initial stack frame. + use rand::rngs::StdRng; use rand::SeedableRng; diff --git a/src/machine.rs b/src/machine.rs index 8ef5410f395f..9785d6a45560 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -1,3 +1,6 @@ +//! Global machine state as well as implementation of the interpreter engine +//! `Machine` trait. + use std::rc::Rc; use std::borrow::Cow; use std::collections::HashMap; diff --git a/src/range_map.rs b/src/range_map.rs index 16e7e2724179..f2cbd89f64da 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -1,5 +1,3 @@ -#![allow(unused)] - //! Implements a map from integer indices to data. //! Rather than storing data for every index, internally, this maps entire ranges to the data. //! To this end, the APIs all work on ranges, not on individual integers. Ranges are split as @@ -8,7 +6,6 @@ //! via the iteration APIs. use std::ops; -use std::num::NonZeroU64; use rustc::ty::layout::Size; @@ -158,7 +155,7 @@ impl RangeMap { let mut end_idx = first_idx; // when the loop is done, this is the first excluded element. loop { // Compute if `end` is the last element we need to look at. - let done = (self.v[end_idx].range.end >= offset+len); + let done = self.v[end_idx].range.end >= offset+len; // We definitely need to include `end`, so move the index. end_idx += 1; debug_assert!(done || end_idx < self.v.len(), "iter_mut: end-offset {} is out-of-bounds", offset+len); diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 524ad2b47af0..6e5bbf50941b 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -1,3 +1,6 @@ +//! Implements "Stacked Borrows". See +//! for further information. + use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::rc::Rc; diff --git a/src/tls.rs b/src/tls.rs index ddc301447c7e..73c778f66d25 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -1,3 +1,5 @@ +//! Implement thread-local storage. + use std::collections::BTreeMap; use rustc_target::abi::LayoutOf; From c0b44ca98cab26289e3e6c435bab5574f30f0a09 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 28 Jun 2019 10:16:10 +0200 Subject: [PATCH 0858/5092] tweak inttoptr allocation behavior - Make `align_addr` not offset by `align` for no reason. - Add some random slack between allocations to give them the chance to not be aligned. --- src/eval.rs | 4 ++-- src/fn_call.rs | 1 + src/intptrcast.rs | 36 +++++++++++++++++++++++++++++++----- src/machine.rs | 5 +++-- 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 5f7d85b7445f..ec97a77357cf 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -10,7 +10,7 @@ use rustc::mir; use crate::{ InterpResult, InterpError, InterpretCx, StackPopCleanup, struct_error, Scalar, Tag, Pointer, - MiriMemoryKind, Evaluator, TlsEvalContextExt, + MemoryExtra, MiriMemoryKind, Evaluator, TlsEvalContextExt, }; /// Configuration needed to spawn a Miri instance. @@ -36,7 +36,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ); // FIXME: InterpretCx::new should take an initial MemoryExtra - ecx.memory_mut().extra.rng = config.seed.map(StdRng::seed_from_u64); + ecx.memory_mut().extra = MemoryExtra::with_rng(config.seed.map(StdRng::seed_from_u64)); let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; diff --git a/src/fn_call.rs b/src/fn_call.rs index e2a4daa6f385..66783f3200e0 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -982,6 +982,7 @@ fn gen_random<'mir, 'tcx>( let data = match &mut this.memory_mut().extra.rng { Some(rng) => { + let mut rng = rng.borrow_mut(); let mut data = vec![0; len]; rng.fill_bytes(&mut data); data diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 176e1bc591c2..aa2e11ac68db 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -1,5 +1,7 @@ use std::cell::{Cell, RefCell}; +use rand::Rng; + use rustc::mir::interpret::{AllocId, Pointer, InterpResult}; use rustc_mir::interpret::Memory; use rustc_target::abi::Size; @@ -73,14 +75,23 @@ impl<'mir, 'tcx> GlobalState { let mut global_state = memory.extra.intptrcast.borrow_mut(); let alloc = memory.get(ptr.alloc_id)?; + let align = alloc.align.bytes(); let base_addr = match alloc.extra.intptrcast.base_addr.get() { Some(base_addr) => base_addr, None => { // This allocation does not have a base address yet, pick one. - let base_addr = Self::align_addr(global_state.next_base_addr, alloc.align.bytes()); - global_state.next_base_addr = base_addr + alloc.bytes.len() as u64; + // Leave some space to the previous allocation, to give it some chance to be less aligned. + let slack = { + let mut rng = memory.extra.rng.as_ref().unwrap().borrow_mut(); + rng.gen_range(0, align) + }; + // From next_base_addr + slack, round up to adjust for alignment. + let base_addr = Self::align_addr(global_state.next_base_addr + slack, align); alloc.extra.intptrcast.base_addr.set(Some(base_addr)); + + // Remember next base address. + global_state.next_base_addr = base_addr + alloc.bytes.len() as u64; // Given that `next_base_addr` increases in each allocation, pushing the // corresponding tuple keeps `int_to_ptr_map` sorted global_state.int_to_ptr_map.push((base_addr, ptr.alloc_id)); @@ -89,13 +100,28 @@ impl<'mir, 'tcx> GlobalState { } }; - debug_assert_eq!(base_addr % alloc.align.bytes(), 0); // sanity check + debug_assert_eq!(base_addr % align, 0); // sanity check Ok(base_addr + ptr.offset.bytes()) } /// Shifts `addr` to make it aligned with `align` by rounding `addr` to the smallest multiple - /// of `align` that is strictly larger to `addr` + /// of `align` that is larger or equal to `addr` fn align_addr(addr: u64, align: u64) -> u64 { - addr + align - addr % align + if addr % align == 0 { + addr + } else { + addr + align - addr % align + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_align_addr() { + assert_eq!(GlobalState::align_addr(37, 4), 40); + assert_eq!(GlobalState::align_addr(44, 4), 44); } } diff --git a/src/machine.rs b/src/machine.rs index eb177fa2a185..c956fd0f33a9 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -1,6 +1,7 @@ use std::rc::Rc; use std::borrow::Cow; use std::collections::HashMap; +use std::cell::RefCell; use rand::rngs::StdRng; @@ -46,7 +47,7 @@ pub struct MemoryExtra { pub intptrcast: intptrcast::MemoryExtra, /// The random number generator to use if Miri is running in non-deterministic mode and to /// enable intptrcast - pub(crate) rng: Option + pub(crate) rng: Option> } impl MemoryExtra { @@ -54,7 +55,7 @@ impl MemoryExtra { MemoryExtra { stacked_borrows: Default::default(), intptrcast: Default::default(), - rng, + rng: rng.map(RefCell::new), } } } From 9b66527075fafba9c058137a6943cf2e0d312000 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 28 Jun 2019 10:23:29 +0200 Subject: [PATCH 0859/5092] more sensible slack --- src/intptrcast.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index aa2e11ac68db..df7217965c81 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -84,7 +84,8 @@ impl<'mir, 'tcx> GlobalState { // Leave some space to the previous allocation, to give it some chance to be less aligned. let slack = { let mut rng = memory.extra.rng.as_ref().unwrap().borrow_mut(); - rng.gen_range(0, align) + // This means that `(global_state.next_base_addr + slack) % 16` is uniformly distributed. + rng.gen_range(0, 16) }; // From next_base_addr + slack, round up to adjust for alignment. let base_addr = Self::align_addr(global_state.next_base_addr + slack, align); From c1645f6c6582f6017cd8e330372bbaa21d95e3f3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 28 Jun 2019 10:24:16 +0200 Subject: [PATCH 0860/5092] don't compute residue twice --- src/intptrcast.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index df7217965c81..a41a139062d8 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -108,10 +108,9 @@ impl<'mir, 'tcx> GlobalState { /// Shifts `addr` to make it aligned with `align` by rounding `addr` to the smallest multiple /// of `align` that is larger or equal to `addr` fn align_addr(addr: u64, align: u64) -> u64 { - if addr % align == 0 { - addr - } else { - addr + align - addr % align + match addr % align { + 0 => addr, + rem => addr + align - rem } } } From 0bb50ada34b3d4fe0ad6be0041f6bd68bacb1cb0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 28 Jun 2019 10:27:19 +0200 Subject: [PATCH 0861/5092] make sure we catch alignment problems even with intrptrcast --- .../compile-fail/intptrcast_alignment_check.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tests/compile-fail/intptrcast_alignment_check.rs diff --git a/tests/compile-fail/intptrcast_alignment_check.rs b/tests/compile-fail/intptrcast_alignment_check.rs new file mode 100644 index 000000000000..5a35844d1256 --- /dev/null +++ b/tests/compile-fail/intptrcast_alignment_check.rs @@ -0,0 +1,18 @@ +// Validation makes this fail in the wrong place +// compile-flags: -Zmiri-disable-validation -Zmiri-seed=0000000000000000 + +// Even with intptrcast and without validation, we want to be *sure* to catch bugs +// that arise from pointers being insufficiently aligned. The only way to achieve +// that is not not let programs exploit integer information for alignment, so here +// we test that this is indeed the case. +fn main() { + let x = &mut [0u8; 3]; + let base_addr = x as *mut _ as usize; + let u16_ref = unsafe { if base_addr % 2 == 0 { + &mut *(base_addr as *mut u16) + } else { + &mut *((base_addr+1) as *mut u16) + } }; + *u16_ref = 2; //~ ERROR tried to access memory with alignment 1, but alignment 2 is required + println!("{:?}", x); +} From 0fac868685020a78b056facee7fa321a02457d5f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 29 Jun 2019 13:33:47 +0200 Subject: [PATCH 0862/5092] support num_cpus and test that --- src/fn_call.rs | 19 ++++++++++++------- src/intptrcast.rs | 6 ++---- src/lib.rs | 5 +++++ test-cargo-miri/Cargo.lock | 10 ++++++++++ test-cargo-miri/Cargo.toml | 1 + test-cargo-miri/run-test.py | 6 +++--- test-cargo-miri/src/main.rs | 3 +++ test-cargo-miri/test.stdout.ref | 8 +++++--- test-cargo-miri/test.stdout.ref2 | 4 ++-- test-cargo-miri/tests/test.rs | 26 +++++++++++++++++++------- 10 files changed, 62 insertions(+), 26 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index e2a4daa6f385..559524b2fe0b 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -622,11 +622,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name = this.read_scalar(args[0])?.to_i32()?; trace!("sysconf() called with name {}", name); - // Cache the sysconf integers via Miri's global cache. + // TODO: Cache the sysconf integers via Miri's global cache. let paths = &[ - (&["libc", "_SC_PAGESIZE"], Scalar::from_int(4096, dest.layout.size)), + (&["libc", "_SC_PAGESIZE"], Scalar::from_int(PAGE_SIZE, dest.layout.size)), (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)), - (&["libc", "_SC_NPROCESSORS_ONLN"], Scalar::from_int(1, dest.layout.size)), + (&["libc", "_SC_NPROCESSORS_ONLN"], Scalar::from_int(NUM_CPUS, dest.layout.size)), ]; let mut result = None; for &(path, path_value) in paths { @@ -648,6 +648,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + "sched_getaffinity" => { + // Return an error; `num_cpus` then falls back to `sysconf`. + this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; + } + "isatty" => { this.write_null(dest)?; } @@ -722,14 +727,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Second argument is where we are supposed to write the stack size. let ptr = this.deref_operand(args[1])?; // Just any address. - let stack_addr = Scalar::from_int(0x80000, args[1].layout.size); + let stack_addr = Scalar::from_uint(STACK_ADDR, args[1].layout.size); this.write_scalar(stack_addr, ptr.into())?; // Return success (`0`). this.write_null(dest)?; } "pthread_get_stackaddr_np" => { // Just any address. - let stack_addr = Scalar::from_int(0x80000, dest.layout.size); + let stack_addr = Scalar::from_uint(STACK_ADDR, dest.layout.size); this.write_scalar(stack_addr, dest)?; } @@ -838,14 +843,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Initialize with `0`. this.memory_mut().get_mut(system_info_ptr.alloc_id)? .write_repeat(tcx, system_info_ptr, 0, system_info.layout.size)?; - // Set number of processors to `1`. + // Set number of processors. let dword_size = Size::from_bytes(4); let offset = 2*dword_size + 3*tcx.pointer_size(); this.memory_mut().get_mut(system_info_ptr.alloc_id)? .write_scalar( tcx, system_info_ptr.offset(offset, tcx)?, - Scalar::from_int(1, dword_size).into(), + Scalar::from_int(NUM_CPUS, dword_size).into(), dword_size, )?; } diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 176e1bc591c2..83e500ea32dd 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -4,8 +4,7 @@ use rustc::mir::interpret::{AllocId, Pointer, InterpResult}; use rustc_mir::interpret::Memory; use rustc_target::abi::Size; -use crate::stacked_borrows::Tag; -use crate::Evaluator; +use crate::{Evaluator, Tag, STACK_ADDR}; pub type MemoryExtra = RefCell; @@ -25,11 +24,10 @@ pub struct GlobalState { } impl Default for GlobalState { - // FIXME: Query the page size in the future fn default() -> Self { GlobalState { int_to_ptr_map: Vec::default(), - next_base_addr: 2u64.pow(16) + next_base_addr: STACK_ADDR, } } } diff --git a/src/lib.rs b/src/lib.rs index ab9e9854c34c..567fdae53b43 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,6 +40,11 @@ pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt, Tag pub use crate::machine::{MemoryExtra, AllocExtra, MiriMemoryKind, Evaluator, MiriEvalContext, MiriEvalContextExt}; pub use crate::eval::{eval_main, create_ecx, MiriConfig}; +// Some global facts about the emulated machine. +pub const PAGE_SIZE: u64 = 4*1024; +pub const STACK_ADDR: u64 = 16*PAGE_SIZE; +pub const NUM_CPUS: u64 = 1; + /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. pub fn miri_default_args() -> &'static [&'static str] { diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index d404872f9db6..8343832886a6 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -29,6 +29,7 @@ name = "cargo-miri-test" version = "0.1.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -66,6 +67,14 @@ name = "libc" version = "0.2.58" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "num_cpus" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ppv-lite86" version = "0.2.5" @@ -148,6 +157,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8d1dffef07351aafe6ef177e4dd2b8dcf503e6bc765dea3b0de9ed149a3db1ec" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319" +"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" "checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" "checksum rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e193067942ef6f485a349a113329140d0ab9e2168ce92274499bb0e9a4190d9d" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index c7fc62b79e84..3abb437049f0 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -9,3 +9,4 @@ byteorder = "1.0" [dev-dependencies] rand = { version = "0.7", features = ["small_rng"] } +num_cpus = "1.10.1" diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 33664737709c..73515c74e401 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -8,7 +8,7 @@ and the working directory to contain the cargo-miri-test project. import sys, subprocess, os def fail(msg): - print("TEST FAIL: {}".format(msg)) + print("\nTEST FAIL: {}".format(msg)) sys.exit(1) def cargo_miri(cmd): @@ -57,7 +57,7 @@ def test_cargo_miri_test(): "test.stdout.ref", "test.stderr.ref" ) test("cargo miri test (with filter)", - cargo_miri("test") + ["--", "--", "impl"], + cargo_miri("test") + ["--", "--", "le1"], "test.stdout.ref2", "test.stderr.ref" ) @@ -66,5 +66,5 @@ os.chdir(os.path.dirname(os.path.realpath(__file__))) test_cargo_miri_run() test_cargo_miri_test() -print("TEST SUCCESSFUL!") +print("\nTEST SUCCESSFUL!") sys.exit(0) diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index c21547c29ff9..d3663ec849d3 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -1,10 +1,13 @@ use byteorder::{BigEndian, ByteOrder}; fn main() { + // Exercise external crate, printing to stdout. let buf = &[1,2,3,4]; let n = ::read_u32(buf); assert_eq!(n, 0x01020304); println!("{:#010x}", n); + + // Access program arguments, printing to stderr. for arg in std::env::args() { eprintln!("{}", arg); } diff --git a/test-cargo-miri/test.stdout.ref b/test-cargo-miri/test.stdout.ref index 58b9b4794b90..c2257e68e256 100644 --- a/test-cargo-miri/test.stdout.ref +++ b/test-cargo-miri/test.stdout.ref @@ -5,9 +5,11 @@ test test::rng ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out -running 2 tests +running 4 tests test entropy_rng ... ok -test simple ... ok +test num_cpus ... ok +test simple1 ... ok +test simple2 ... ok -test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/test.stdout.ref2 b/test-cargo-miri/test.stdout.ref2 index ce3506709d5a..a6f6e915e0e8 100644 --- a/test-cargo-miri/test.stdout.ref2 +++ b/test-cargo-miri/test.stdout.ref2 @@ -5,7 +5,7 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out running 1 test -test simple ... ok +test simple1 ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 3 filtered out diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index ac0db2778cae..cfbe3f6d7fb6 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -3,13 +3,28 @@ use rand::{SeedableRng, Rng, rngs::SmallRng}; // Having more than 1 test does seem to make a difference // (i.e., this calls ptr::swap which having just one test does not). #[test] -fn simple() { +fn simple1() { assert_eq!(4, 4); } +#[test] +fn simple2() { + assert_ne!(42, 24); +} + +// A test that won't work on miri (tests disabling tests) +#[cfg(not(miri))] +#[test] +fn does_not_work_on_miri() { + let x = 0u8; + assert!(&x as *const _ as usize % 4 < 4); +} + +// We also use this to test some external crates, that we cannot depend on in the compiletest suite. + #[test] fn entropy_rng() { - // Use this opportunity to test querying the RNG (needs an external crate, hence tested here and not in the compiletest suite) + // Try seeding with "real" entropy. let mut rng = SmallRng::from_entropy(); let _val = rng.gen::(); let _val = rng.gen::(); @@ -22,10 +37,7 @@ fn entropy_rng() { let _val = rng.gen::(); } -// A test that won't work on miri -#[cfg(not(miri))] #[test] -fn does_not_work_on_miri() { - let x = 0u8; - assert!(&x as *const _ as usize % 4 < 4); +fn num_cpus() { + assert_eq!(num_cpus::get(), 1); } From c7bf9064f7028a9e43feaf699e23f1443704e448 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 29 Jun 2019 13:37:38 +0200 Subject: [PATCH 0863/5092] comment on STACK_ADDR --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 567fdae53b43..66b6afde3317 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,7 +42,7 @@ pub use crate::eval::{eval_main, create_ecx, MiriConfig}; // Some global facts about the emulated machine. pub const PAGE_SIZE: u64 = 4*1024; -pub const STACK_ADDR: u64 = 16*PAGE_SIZE; +pub const STACK_ADDR: u64 = 16*PAGE_SIZE; // not really about the "stack", but where we start assigning integer addresses to allocations pub const NUM_CPUS: u64 = 1; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be From 019ad4bab456bf107cba54dc8c396fbdd6d2bae0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 29 Jun 2019 14:37:41 +0200 Subject: [PATCH 0864/5092] move constants to machine.rs --- src/lib.rs | 10 ++++------ src/machine.rs | 5 +++++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 66b6afde3317..0e4a9c4ccc37 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,14 +37,12 @@ pub use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; pub use crate::mono_hash_map::MonoHashMap; pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt, Tag, Permission, Stack, Stacks, Item}; -pub use crate::machine::{MemoryExtra, AllocExtra, MiriMemoryKind, Evaluator, MiriEvalContext, MiriEvalContextExt}; +pub use crate::machine::{ + PAGE_SIZE, STACK_ADDR, NUM_CPUS, + MemoryExtra, AllocExtra, MiriMemoryKind, Evaluator, MiriEvalContext, MiriEvalContextExt, +}; pub use crate::eval::{eval_main, create_ecx, MiriConfig}; -// Some global facts about the emulated machine. -pub const PAGE_SIZE: u64 = 4*1024; -pub const STACK_ADDR: u64 = 16*PAGE_SIZE; // not really about the "stack", but where we start assigning integer addresses to allocations -pub const NUM_CPUS: u64 = 1; - /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. pub fn miri_default_args() -> &'static [&'static str] { diff --git a/src/machine.rs b/src/machine.rs index eb177fa2a185..383b6aac631e 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -12,6 +12,11 @@ use rustc::mir; use crate::*; +// Some global facts about the emulated machine. +pub const PAGE_SIZE: u64 = 4*1024; // FIXME: adjust to target architecture +pub const STACK_ADDR: u64 = 16*PAGE_SIZE; // not really about the "stack", but where we start assigning integer addresses to allocations +pub const NUM_CPUS: u64 = 1; + /// Extra memory kinds #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum MiriMemoryKind { From 11457a4ad942ec35952682f474556f6eae2d4db3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 10:59:42 +0200 Subject: [PATCH 0865/5092] fix comparing function pointers with intptrcast --- src/intptrcast.rs | 39 +++++++++++++------------ src/machine.rs | 2 -- tests/run-pass/intptrcast_format.rs | 6 ++++ tests/run-pass/intptrcast_format.stdout | 2 ++ 4 files changed, 29 insertions(+), 20 deletions(-) create mode 100644 tests/run-pass/intptrcast_format.rs create mode 100644 tests/run-pass/intptrcast_format.stdout diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 7fd48defda13..f8102642bdb4 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -1,25 +1,26 @@ -use std::cell::{Cell, RefCell}; +use std::cell::RefCell; +use std::collections::{HashMap, hash_map::Entry}; +use std::cmp::max; use rand::Rng; -use rustc::mir::interpret::{AllocId, Pointer, InterpResult}; -use rustc_mir::interpret::Memory; +use rustc_mir::interpret::{AllocId, Pointer, InterpResult, Memory, AllocCheck}; use rustc_target::abi::Size; use crate::{Evaluator, Tag, STACK_ADDR}; pub type MemoryExtra = RefCell; -#[derive(Clone, Debug, Default)] -pub struct AllocExtra { - base_addr: Cell> -} - #[derive(Clone, Debug)] pub struct GlobalState { /// This is used as a map between the address of each allocation and its `AllocId`. /// It is always sorted pub int_to_ptr_map: Vec<(u64, AllocId)>, + /// The base address for each allocation. We cannot put that into + /// `AllocExtra` because function pointers also have a base address, and + /// they do not have an `AllocExtra`. + /// This is the inverse of `int_to_ptr_map`. + pub base_addr: HashMap, /// This is used as a memory address when a new pointer is casted to an integer. It /// is always larger than any address that was previously made part of a block. pub next_base_addr: u64, @@ -29,6 +30,7 @@ impl Default for GlobalState { fn default() -> Self { GlobalState { int_to_ptr_map: Vec::default(), + base_addr: HashMap::default(), next_base_addr: STACK_ADDR, } } @@ -71,13 +73,13 @@ impl<'mir, 'tcx> GlobalState { memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>, ) -> InterpResult<'tcx, u64> { let mut global_state = memory.extra.intptrcast.borrow_mut(); + let global_state = &mut *global_state; - let alloc = memory.get(ptr.alloc_id)?; - let align = alloc.align.bytes(); + let (size, align) = memory.get_size_and_align(ptr.alloc_id, AllocCheck::Live)?; - let base_addr = match alloc.extra.intptrcast.base_addr.get() { - Some(base_addr) => base_addr, - None => { + let base_addr = match global_state.base_addr.entry(ptr.alloc_id) { + Entry::Occupied(entry) => *entry.get(), + Entry::Vacant(entry) => { // This allocation does not have a base address yet, pick one. // Leave some space to the previous allocation, to give it some chance to be less aligned. let slack = { @@ -86,11 +88,12 @@ impl<'mir, 'tcx> GlobalState { rng.gen_range(0, 16) }; // From next_base_addr + slack, round up to adjust for alignment. - let base_addr = Self::align_addr(global_state.next_base_addr + slack, align); - alloc.extra.intptrcast.base_addr.set(Some(base_addr)); + let base_addr = Self::align_addr(global_state.next_base_addr + slack, align.bytes()); + entry.insert(base_addr); - // Remember next base address. - global_state.next_base_addr = base_addr + alloc.bytes.len() as u64; + // Remember next base address. If this allocation is zero-sized, leave a gap + // of at least 1 to avoid two allocations having the same base address. + global_state.next_base_addr = base_addr + max(size.bytes(), 1); // Given that `next_base_addr` increases in each allocation, pushing the // corresponding tuple keeps `int_to_ptr_map` sorted global_state.int_to_ptr_map.push((base_addr, ptr.alloc_id)); @@ -99,7 +102,7 @@ impl<'mir, 'tcx> GlobalState { } }; - debug_assert_eq!(base_addr % align, 0); // sanity check + debug_assert_eq!(base_addr % align.bytes(), 0); // sanity check Ok(base_addr + ptr.offset.bytes()) } diff --git a/src/machine.rs b/src/machine.rs index 485286ea400d..20fe2e055fb5 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -42,7 +42,6 @@ impl Into> for MiriMemoryKind { #[derive(Debug, Clone)] pub struct AllocExtra { pub stacked_borrows: stacked_borrows::AllocExtra, - pub intptrcast: intptrcast::AllocExtra, } /// Extra global memory data @@ -277,7 +276,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { mutability: alloc.mutability, extra: AllocExtra { stacked_borrows: stacks, - intptrcast: Default::default(), }, }; (Cow::Owned(alloc), base_tag) diff --git a/tests/run-pass/intptrcast_format.rs b/tests/run-pass/intptrcast_format.rs new file mode 100644 index 000000000000..c0d3e9398dc5 --- /dev/null +++ b/tests/run-pass/intptrcast_format.rs @@ -0,0 +1,6 @@ +// compile-flags: -Zmiri-seed= + +fn main() { + println!("Hello {}", 13); + println!("{:0 Date: Sun, 30 Jun 2019 15:35:28 +0200 Subject: [PATCH 0866/5092] move shims (foreign items and intrinsics) into submodule --- src/lib.rs | 7 +++---- src/{fn_call.rs => shims/foreign_items.rs} | 0 src/{intrinsic.rs => shims/intrinsics.rs} | 0 src/shims/mod.rs | 2 ++ 4 files changed, 5 insertions(+), 4 deletions(-) rename src/{fn_call.rs => shims/foreign_items.rs} (100%) rename src/{intrinsic.rs => shims/intrinsics.rs} (100%) create mode 100644 src/shims/mod.rs diff --git a/src/lib.rs b/src/lib.rs index 0e4a9c4ccc37..6b2de4ac08be 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,9 +12,8 @@ extern crate rustc_data_structures; extern crate rustc_mir; extern crate rustc_target; -mod fn_call; +mod shims; mod operator; -mod intrinsic; mod helpers; mod tls; mod range_map; @@ -29,9 +28,9 @@ pub use rustc_mir::interpret::*; // Resolve ambiguity. pub use rustc_mir::interpret::{self, AllocMap, PlaceTy}; -pub use crate::fn_call::EvalContextExt as MissingFnsEvalContextExt; +pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextExt; +pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; -pub use crate::intrinsic::EvalContextExt as IntrinsicEvalContextExt; pub use crate::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; diff --git a/src/fn_call.rs b/src/shims/foreign_items.rs similarity index 100% rename from src/fn_call.rs rename to src/shims/foreign_items.rs diff --git a/src/intrinsic.rs b/src/shims/intrinsics.rs similarity index 100% rename from src/intrinsic.rs rename to src/shims/intrinsics.rs diff --git a/src/shims/mod.rs b/src/shims/mod.rs new file mode 100644 index 000000000000..cadfc05681da --- /dev/null +++ b/src/shims/mod.rs @@ -0,0 +1,2 @@ +pub mod foreign_items; +pub mod intrinsics; From 5d4aae8c05c6389c41b0cf5585c9dd1a645bfbd3 Mon Sep 17 00:00:00 2001 From: varkor Date: Sun, 30 Jun 2019 15:31:14 +0100 Subject: [PATCH 0867/5092] Fix `unused_must_use` inside `Box` After https://github.com/rust-lang/rust/pull/62228, this will be linted against (and causes the test to fail). --- tests/run-pass/issue-30530.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/issue-30530.rs b/tests/run-pass/issue-30530.rs index 10dec30c64ca..86c2d9184e01 100644 --- a/tests/run-pass/issue-30530.rs +++ b/tests/run-pass/issue-30530.rs @@ -21,7 +21,9 @@ pub enum Handler { } fn main() { - take(Handler::Default, Box::new(main)); + #[allow(unused_must_use)] { + take(Handler::Default, Box::new(main)); + } } #[inline(never)] From db6283b88447577f11e13b6eca99dfb7d0215b1b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 16:44:25 +0200 Subject: [PATCH 0868/5092] better name for a test: threads -> sync --- tests/run-pass/{threads.rs => sync.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/run-pass/{threads.rs => sync.rs} (100%) diff --git a/tests/run-pass/threads.rs b/tests/run-pass/sync.rs similarity index 100% rename from tests/run-pass/threads.rs rename to tests/run-pass/sync.rs From e44d38e0511376b73e1a17588780b21c359789f6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 16:45:41 +0200 Subject: [PATCH 0869/5092] improve comment --- tests/run-pass/sync.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index dad47d85a246..54d79566eae4 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -8,8 +8,7 @@ fn main() { drop(m.lock()); drop(m); - // We don't provide RwLock on Windows - #[cfg(not(target_os = "windows"))] + #[cfg(not(target_os = "windows"))] // TODO: implement RwLock on Windows { let rw = sync::RwLock::new(0); drop(rw.read()); From b06731355205f0a4ffa1464137b1d55992f08b48 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 16:56:16 +0200 Subject: [PATCH 0870/5092] use intptrcast for heap_allocator test; then it should work on Windows --- tests/run-pass/heap_allocator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index b201f24e2563..457734cb602c 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -1,3 +1,4 @@ +// compile-flag: -Zmiri-seed= #![feature(allocator_api)] use std::ptr::NonNull; @@ -75,7 +76,6 @@ fn box_to_global() { fn main() { check_alloc(System); check_alloc(Global); - #[cfg(not(target_os = "windows"))] // TODO: Inspects allocation base address on Windows; needs intptrcast model check_overalign_requests(System); check_overalign_requests(Global); global_to_box(); From 0ea4b50025ea71e11aa8b326508b4d40e998727a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 17:02:20 +0200 Subject: [PATCH 0871/5092] Miri is not deterministic any more --- tests/run-pass/heap_allocator.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index 457734cb602c..3eb0f70fd662 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -33,8 +33,8 @@ fn check_overalign_requests(mut allocator: T) { let size = 8; // Greater than `size`. let align = 16; - // Miri is deterministic; no need to try many times. - let iterations = 1; + + let iterations = 5; unsafe { let pointers: Vec<_> = (0..iterations).map(|_| { allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap() From 78261b788d0107efed65b4fb24e18c1a7ff5840b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 19:10:09 +0200 Subject: [PATCH 0872/5092] fix setting rustc flags --- tests/run-pass/heap_allocator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index 3eb0f70fd662..57db5407b7af 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -1,4 +1,4 @@ -// compile-flag: -Zmiri-seed= +// compile-flags: -Zmiri-seed= #![feature(allocator_api)] use std::ptr::NonNull; From a04890795db44682f4afd276dbb7277eee3bcc11 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 21:03:52 +0200 Subject: [PATCH 0873/5092] move appveyor env var settings to more appropriate section --- .appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index f7d3f990ac99..4e8b8cd4b898 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -29,8 +29,6 @@ install: - rustc --version build_script: - - set RUST_TEST_NOCAPTURE=1 - - set RUST_BACKTRACE=1 - set RUSTFLAGS=-C debug-assertions # Build and install miri - cargo build --release --all-features --all-targets @@ -40,6 +38,8 @@ build_script: - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\rust-lang\miri\cache\HOST test_script: + - set RUST_TEST_NOCAPTURE=1 + - set RUST_BACKTRACE=1 # Test miri - cargo test --release --all-features # Test cargo integration From e960270662e74aa19beee319641e12d67e45aa07 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 21:06:32 +0200 Subject: [PATCH 0874/5092] add some tracing to intptrcast --- src/intptrcast.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index f8102642bdb4..548070000507 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -90,6 +90,10 @@ impl<'mir, 'tcx> GlobalState { // From next_base_addr + slack, round up to adjust for alignment. let base_addr = Self::align_addr(global_state.next_base_addr + slack, align.bytes()); entry.insert(base_addr); + trace!( + "Assigning base address {:#x} to allocation {:?} (slack: {}, align: {})", + base_addr, ptr.alloc_id, slack, align.bytes(), + ); // Remember next base address. If this allocation is zero-sized, leave a gap // of at least 1 to avoid two allocations having the same base address. From 709b4748599881184f4f03137d1b81ea160d5dd1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 21:08:17 +0200 Subject: [PATCH 0875/5092] fix minimal alignment for system allocation functions --- src/shims/foreign_items.rs | 16 ++++++++-- tests/run-pass/heap_allocator.rs | 50 ++++++++++++++++++++------------ 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 9c9e77abfed3..2e2a9062fba8 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -51,6 +51,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(Some(this.load_mir(instance.def)?)) } + /// Returns the minimum alignment for the target architecture. + fn min_align(&self) -> Align { + let this = self.eval_context_ref(); + // List taken from `libstd/sys_common/alloc.rs`. + let min_align = match this.tcx.tcx.sess.target.target.arch.as_str() { + "x86" | "arm" | "mips" | "powerpc" | "powerpc64" | "asmjs" | "wasm32" => 8, + "x86_64" | "aarch64" | "mips64" | "s390x" | "sparc64" => 16, + arch => bug!("Unsupported target architecture: {}", arch), + }; + Align::from_bytes(min_align).unwrap() + } + fn malloc( &mut self, size: u64, @@ -61,7 +73,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if size == 0 { Scalar::from_int(0, this.pointer_size()) } else { - let align = this.tcx.data_layout.pointer_align.abi; + let align = this.min_align(); let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into()); if zero_init { // We just allocated this, the access cannot fail @@ -94,7 +106,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx new_size: u64, ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let align = this.tcx.data_layout.pointer_align.abi; + let align = this.min_align(); if old_ptr.is_null_ptr(this) { if new_size == 0 { Ok(Scalar::from_int(0, this.pointer_size())) diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index 57db5407b7af..1ea04ec467f1 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -6,35 +6,47 @@ use std::alloc::{Global, Alloc, Layout, System}; use std::slice; fn check_alloc(mut allocator: T) { unsafe { - let layout = Layout::from_size_align(20, 4).unwrap(); - let a = allocator.alloc(layout).unwrap(); - allocator.dealloc(a, layout); + for &align in &[4, 8, 16, 32] { + let layout = Layout::from_size_align(20, align).unwrap(); - let p1 = allocator.alloc_zeroed(layout).unwrap(); + for _ in 0..32 { + let a = allocator.alloc(layout).unwrap(); + assert_eq!(a.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); + allocator.dealloc(a, layout); + } - let p2 = allocator.realloc(p1, Layout::from_size_align(20, 4).unwrap(), 40).unwrap(); - let slice = slice::from_raw_parts(p2.as_ptr(), 20); - assert_eq!(&slice, &[0_u8; 20]); + let p1 = allocator.alloc_zeroed(layout).unwrap(); + assert_eq!(p1.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); - // old size == new size - let p3 = allocator.realloc(p2, Layout::from_size_align(40, 4).unwrap(), 40).unwrap(); - let slice = slice::from_raw_parts(p3.as_ptr(), 20); - assert_eq!(&slice, &[0_u8; 20]); + let p2 = allocator.realloc(p1, layout, 40).unwrap(); + let layout = Layout::from_size_align(40, align).unwrap(); + assert_eq!(p2.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); + let slice = slice::from_raw_parts(p2.as_ptr(), 20); + assert_eq!(&slice, &[0_u8; 20]); - // old size > new size - let p4 = allocator.realloc(p3, Layout::from_size_align(40, 4).unwrap(), 10).unwrap(); - let slice = slice::from_raw_parts(p4.as_ptr(), 10); - assert_eq!(&slice, &[0_u8; 10]); + // old size == new size + let p3 = allocator.realloc(p2, layout, 40).unwrap(); + assert_eq!(p3.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); + let slice = slice::from_raw_parts(p3.as_ptr(), 20); + assert_eq!(&slice, &[0_u8; 20]); - allocator.dealloc(p4, Layout::from_size_align(10, 4).unwrap()); + // old size > new size + let p4 = allocator.realloc(p3, layout, 10).unwrap(); + let layout = Layout::from_size_align(10, align).unwrap(); + assert_eq!(p4.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); + let slice = slice::from_raw_parts(p4.as_ptr(), 10); + assert_eq!(&slice, &[0_u8; 10]); + + allocator.dealloc(p4, layout); + } } } fn check_overalign_requests(mut allocator: T) { let size = 8; - // Greater than `size`. - let align = 16; + // Greater than `size`, and also greater than `MIN_ALIGN`. + let align = 32; - let iterations = 5; + let iterations = 32; unsafe { let pointers: Vec<_> = (0..iterations).map(|_| { allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap() From cb6d4f0c9ab95125af236abea72661efd094f699 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 21:23:48 +0200 Subject: [PATCH 0876/5092] test even more size-alignment combinations. found a bug in libstd! --- README.md | 1 + src/shims/foreign_items.rs | 4 ++++ tests/run-pass/heap_allocator.rs | 32 ++++++++++++++++---------------- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 91dcfd7cf83b..be104ed0b2ba 100644 --- a/README.md +++ b/README.md @@ -333,6 +333,7 @@ Definite bugs found: * [Futures turning a shared reference into a mutable one](https://github.com/rust-lang/rust/pull/56319) * [`str` turning a shared reference into a mutable one](https://github.com/rust-lang/rust/pull/58200) * [`rand` performing unaligned reads](https://github.com/rust-random/rand/issues/779) +* [The Unix allocator calling `posix_memalign` in an invalid way](https://github.com/rust-lang/rust/issues/62251) Violations of Stacked Borrows found that are likely bugs (but Stacked Borrows is currently just an experiment): diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 2e2a9062fba8..1a39df9cce15 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -203,12 +203,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } + /* + FIXME: This check is disabled because rustc violates it. + See . if align < this.pointer_size().bytes() { return err!(MachineError(format!( "posix_memalign: alignment must be at least the size of a pointer, but is {}", align, ))); } + */ if size == 0 { this.write_null(ret.into())?; } else { diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index 1ea04ec467f1..2f3a48f535dd 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -42,23 +42,23 @@ fn check_alloc(mut allocator: T) { unsafe { } } fn check_overalign_requests(mut allocator: T) { - let size = 8; - // Greater than `size`, and also greater than `MIN_ALIGN`. - let align = 32; + for &size in &[2, 8, 64] { // size less than and bigger than alignment + for &align in &[4, 8, 16, 32] { // Be sure to cover less than and bigger than `MIN_ALIGN` for all architectures + let iterations = 32; + unsafe { + let pointers: Vec<_> = (0..iterations).map(|_| { + allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap() + }).collect(); + for &ptr in &pointers { + assert_eq!((ptr.as_ptr() as usize) % align, 0, + "Got a pointer less aligned than requested") + } - let iterations = 32; - unsafe { - let pointers: Vec<_> = (0..iterations).map(|_| { - allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap() - }).collect(); - for &ptr in &pointers { - assert_eq!((ptr.as_ptr() as usize) % align, 0, - "Got a pointer less aligned than requested") - } - - // Clean up. - for &ptr in &pointers { - allocator.dealloc(ptr, Layout::from_size_align(size, align).unwrap()) + // Clean up. + for &ptr in &pointers { + allocator.dealloc(ptr, Layout::from_size_align(size, align).unwrap()) + } + } } } } From 4135441137ca02168522c24c0f5a3fbbf3af8741 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 1 Jul 2019 00:12:45 +0200 Subject: [PATCH 0877/5092] don't call Memory::get without checking the pointer first; avoid Memory::get if we just need to know align/size --- src/operator.rs | 10 +++++++--- src/shims/foreign_items.rs | 32 ++++++++++++++++++++------------ 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index 0e25de7da5a9..d3af1f0db0e0 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -206,7 +206,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { // on read hardware this can easily happen. Thus for comparisons we require // both pointers to be live. if self.pointer_inbounds(left).is_ok() && self.pointer_inbounds(right).is_ok() { - // Two in-bounds pointers in different allocations are different. + // Two in-bounds (and hence live) pointers in different allocations are different. false } else { return err!(InvalidPointerMath); @@ -303,7 +303,9 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { map_to_primval(left.overflowing_offset(Size::from_bytes(right as u64), self)), BitAnd if !signed => { - let ptr_base_align = self.memory().get(left.alloc_id)?.align.bytes(); + let ptr_base_align = self.memory().get_size_and_align(left.alloc_id, AllocCheck::MaybeDead) + .expect("alloc info with MaybeDead cannot fail") + .1.bytes(); let base_mask = { // FIXME: use `interpret::truncate`, once that takes a `Size` instead of a `Layout`. let shift = 128 - self.memory().pointer_size().bits(); @@ -337,7 +339,9 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { Rem if !signed => { // Doing modulo a divisor of the alignment is allowed. // (Intuition: modulo a divisor leaks less information.) - let ptr_base_align = self.memory().get(left.alloc_id)?.align.bytes(); + let ptr_base_align = self.memory().get_size_and_align(left.alloc_id, AllocCheck::MaybeDead) + .expect("alloc info with MaybeDead cannot fail") + .1.bytes(); let right = right as u64; let ptr_size = self.memory().pointer_size(); if right == 1 { diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 9c9e77abfed3..0fa857eff757 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -252,9 +252,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into() ); + // We just allocated this, the access cannot fail this.memory_mut() - .get_mut(ptr.alloc_id)? - .write_repeat(tcx, ptr, 0, Size::from_bytes(size))?; + .get_mut(ptr.alloc_id).unwrap() + .write_repeat(tcx, ptr, 0, Size::from_bytes(size)).unwrap(); this.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_dealloc" => { @@ -494,15 +495,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Align::from_bytes(1).unwrap(), MiriMemoryKind::Env.into(), ); - { - let alloc = this.memory_mut().get_mut(value_copy.alloc_id)?; - alloc.write_bytes(tcx, value_copy, &value)?; - let trailing_zero_ptr = value_copy.offset( - Size::from_bytes(value.len() as u64), - tcx, - )?; - alloc.write_bytes(tcx, trailing_zero_ptr, &[0])?; - } + // We just allocated these, so the write cannot fail. + let alloc = this.memory_mut().get_mut(value_copy.alloc_id).unwrap(); + alloc.write_bytes(tcx, value_copy, &value).unwrap(); + let trailing_zero_ptr = value_copy.offset( + Size::from_bytes(value.len() as u64), + tcx, + ).unwrap(); + alloc.write_bytes(tcx, trailing_zero_ptr, &[0]).unwrap(); + if let Some(var) = this.machine.env_vars.insert( name.to_owned(), value_copy, @@ -839,7 +840,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }, "GetSystemInfo" => { let system_info = this.deref_operand(args[0])?; - let system_info_ptr = system_info.ptr.to_ptr()?; + let (system_info_ptr, align) = system_info.to_scalar_ptr_align(); + let system_info_ptr = this.memory() + .check_ptr_access( + system_info_ptr, + system_info.layout.size, + align, + )? + .expect("cannot be a ZST"); // Initialize with `0`. this.memory_mut().get_mut(system_info_ptr.alloc_id)? .write_repeat(tcx, system_info_ptr, 0, system_info.layout.size)?; From 7b702b92588316adda4992e0ef247176b91a2f07 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 23:24:08 +0200 Subject: [PATCH 0878/5092] move find_fn (which is not specific to foreign items) out of foreign_items --- src/lib.rs | 1 + src/shims/foreign_items.rs | 41 --------------------------------- src/shims/mod.rs | 47 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 41 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6b2de4ac08be..50cf32f85204 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,6 +28,7 @@ pub use rustc_mir::interpret::*; // Resolve ambiguity. pub use rustc_mir::interpret::{self, AllocMap, PlaceTy}; +pub use crate::shims::{EvalContextExt as ShimsEvalContextExt}; pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextExt; pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 1a39df9cce15..aece4d3e1aef 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -1,4 +1,3 @@ -use rustc::ty; use rustc::ty::layout::{Align, LayoutOf, Size}; use rustc::hir::def_id::DefId; use rustc::mir; @@ -11,46 +10,6 @@ use crate::*; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn find_fn( - &mut self, - instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Tag>], - dest: Option>, - ret: Option, - ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { - let this = self.eval_context_mut(); - trace!("eval_fn_call: {:#?}, {:?}", instance, dest.map(|place| *place)); - - // First, run the common hooks also supported by CTFE. - if this.hook_fn(instance, args, dest)? { - this.goto_block(ret)?; - return Ok(None); - } - // There are some more lang items we want to hook that CTFE does not hook (yet). - if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { - // FIXME: return a real value in case the target allocation has an - // alignment bigger than the one requested. - let n = u128::max_value(); - let dest = dest.unwrap(); - let n = this.truncate(n, dest.layout); - this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; - this.goto_block(ret)?; - return Ok(None); - } - - // Try to see if we can do something about foreign items. - if this.tcx.is_foreign_item(instance.def_id()) { - // An external function that we cannot find MIR for, but we can still run enough - // of them to make miri viable. - this.emulate_foreign_item(instance.def_id(), args, dest, ret)?; - // `goto_block` already handled. - return Ok(None); - } - - // Otherwise, load the MIR. - Ok(Some(this.load_mir(instance.def)?)) - } - /// Returns the minimum alignment for the target architecture. fn min_align(&self) -> Align { let this = self.eval_context_ref(); diff --git a/src/shims/mod.rs b/src/shims/mod.rs index cadfc05681da..0fc23e811937 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -1,2 +1,49 @@ pub mod foreign_items; pub mod intrinsics; + +use rustc::{ty, mir}; + +use crate::*; + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn find_fn( + &mut self, + instance: ty::Instance<'tcx>, + args: &[OpTy<'tcx, Tag>], + dest: Option>, + ret: Option, + ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { + let this = self.eval_context_mut(); + trace!("eval_fn_call: {:#?}, {:?}", instance, dest.map(|place| *place)); + + // First, run the common hooks also supported by CTFE. + if this.hook_fn(instance, args, dest)? { + this.goto_block(ret)?; + return Ok(None); + } + // There are some more lang items we want to hook that CTFE does not hook (yet). + if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { + // FIXME: return a real value in case the target allocation has an + // alignment bigger than the one requested. + let n = u128::max_value(); + let dest = dest.unwrap(); + let n = this.truncate(n, dest.layout); + this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; + this.goto_block(ret)?; + return Ok(None); + } + + // Try to see if we can do something about foreign items. + if this.tcx.is_foreign_item(instance.def_id()) { + // An external function that we cannot find MIR for, but we can still run enough + // of them to make miri viable. + this.emulate_foreign_item(instance.def_id(), args, dest, ret)?; + // `goto_block` already handled. + return Ok(None); + } + + // Otherwise, load the MIR. + Ok(Some(this.load_mir(instance.def)?)) + } +} From b04452223a8b4256e32306eab2f1bcb578c09c16 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 1 Jul 2019 11:05:57 +0200 Subject: [PATCH 0879/5092] be explicit about our line endings --- .gitattributes | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000000..6313b56c5784 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf From e8e42ab5ecead88c23dec9eab9a23019e45410fd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Jul 2019 09:51:16 +0200 Subject: [PATCH 0880/5092] add another bug we found to the list --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index be104ed0b2ba..8c0c87ab9ebb 100644 --- a/README.md +++ b/README.md @@ -327,6 +327,7 @@ Miri has already found a number of bugs in the Rust standard library and beyond, Definite bugs found: * [`Debug for vec_deque::Iter` accessing uninitialized memory](https://github.com/rust-lang/rust/issues/53566) +* [`Vec::into_iter` doing an unaligned ZST read](https://github.com/rust-lang/rust/pull/53804) * [`From<&[T]> for Rc` creating a not sufficiently aligned reference](https://github.com/rust-lang/rust/issues/54908) * [`BTreeMap` creating a shared reference pointing to a too small allocation](https://github.com/rust-lang/rust/issues/54957) * [`Vec::append` creating a dangling reference](https://github.com/rust-lang/rust/pull/61082) From 8d8481fed5c0417e01bfa4726e16e0181213e93f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Jul 2019 13:02:48 +0200 Subject: [PATCH 0881/5092] fix outdated test name: overalign -> align --- tests/run-pass/heap_allocator.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index 2f3a48f535dd..e7a609a7d98e 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -41,7 +41,7 @@ fn check_alloc(mut allocator: T) { unsafe { } } } -fn check_overalign_requests(mut allocator: T) { +fn check_align_requests(mut allocator: T) { for &size in &[2, 8, 64] { // size less than and bigger than alignment for &align in &[4, 8, 16, 32] { // Be sure to cover less than and bigger than `MIN_ALIGN` for all architectures let iterations = 32; @@ -88,8 +88,8 @@ fn box_to_global() { fn main() { check_alloc(System); check_alloc(Global); - check_overalign_requests(System); - check_overalign_requests(Global); + check_align_requests(System); + check_align_requests(Global); global_to_box(); box_to_global(); } From ccbc035f6a57dd6315114e4de3ee89513c355bb2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Jul 2019 22:20:37 +0200 Subject: [PATCH 0882/5092] run all run-pass tests with intrptrcast. makes many of them fail! --- tests/compiletest.rs | 3 +++ tests/run-pass/intptrcast_format.rs | 6 ------ tests/run-pass/intptrcast_format.stdout | 2 -- 3 files changed, 3 insertions(+), 8 deletions(-) delete mode 100644 tests/run-pass/intptrcast_format.rs delete mode 100644 tests/run-pass/intptrcast_format.stdout diff --git a/tests/compiletest.rs b/tests/compiletest.rs index d59be08c8e00..cb61c1c01b32 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -81,6 +81,9 @@ fn miri_pass(path: &str, target: &str, opt: bool) { let mut flags = Vec::new(); if opt { flags.push("-Zmir-opt-level=3".to_owned()); + } else { + // Run with intptrcast. Avoid test matrix explosion by doing either this or opt-level=3. + flags.push("-Zmiri-seed=".to_owned()); } run_tests("ui", path, target, flags); diff --git a/tests/run-pass/intptrcast_format.rs b/tests/run-pass/intptrcast_format.rs deleted file mode 100644 index c0d3e9398dc5..000000000000 --- a/tests/run-pass/intptrcast_format.rs +++ /dev/null @@ -1,6 +0,0 @@ -// compile-flags: -Zmiri-seed= - -fn main() { - println!("Hello {}", 13); - println!("{:0 Date: Wed, 3 Jul 2019 09:06:35 +0200 Subject: [PATCH 0883/5092] dont add the -Zmiri-seed flag twice --- tests/compiletest.rs | 7 ++++--- tests/{run-pass => run-pass-noseed}/hashmap.rs | 0 tests/{run-pass => run-pass-noseed}/heap_allocator.rs | 0 tests/{run-pass => run-pass-noseed}/intptrcast.rs | 0 4 files changed, 4 insertions(+), 3 deletions(-) rename tests/{run-pass => run-pass-noseed}/hashmap.rs (100%) rename tests/{run-pass => run-pass-noseed}/heap_allocator.rs (100%) rename tests/{run-pass => run-pass-noseed}/intptrcast.rs (100%) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index cb61c1c01b32..1d32d3a73244 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -69,7 +69,7 @@ fn compile_fail(path: &str, target: &str, opt: bool) { run_tests("compile-fail", path, target, flags); } -fn miri_pass(path: &str, target: &str, opt: bool) { +fn miri_pass(path: &str, target: &str, opt: bool, noseed: bool) { let opt_str = if opt { " with optimizations" } else { "" }; eprintln!("{}", format!( "## Running run-pass tests in {} against miri for target {}{}", @@ -81,7 +81,7 @@ fn miri_pass(path: &str, target: &str, opt: bool) { let mut flags = Vec::new(); if opt { flags.push("-Zmir-opt-level=3".to_owned()); - } else { + } else if !noseed { // Run with intptrcast. Avoid test matrix explosion by doing either this or opt-level=3. flags.push("-Zmiri-seed=".to_owned()); } @@ -107,7 +107,8 @@ fn get_target() -> String { } fn run_pass_miri(opt: bool) { - miri_pass("tests/run-pass", &get_target(), opt); + miri_pass("tests/run-pass", &get_target(), opt, false); + miri_pass("tests/run-pass-noseed", &get_target(), opt, true); } fn compile_fail_miri(opt: bool) { diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass-noseed/hashmap.rs similarity index 100% rename from tests/run-pass/hashmap.rs rename to tests/run-pass-noseed/hashmap.rs diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass-noseed/heap_allocator.rs similarity index 100% rename from tests/run-pass/heap_allocator.rs rename to tests/run-pass-noseed/heap_allocator.rs diff --git a/tests/run-pass/intptrcast.rs b/tests/run-pass-noseed/intptrcast.rs similarity index 100% rename from tests/run-pass/intptrcast.rs rename to tests/run-pass-noseed/intptrcast.rs From 457c8237652e123010555b5ecc795a5a4fd6111f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Jul 2019 09:06:48 +0200 Subject: [PATCH 0884/5092] only treat integer operations as such --- src/operator.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index d3af1f0db0e0..31def2fec0e0 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -56,10 +56,10 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); - // If intptrcast is enabled and the operation is not an offset - // we can force the cast from pointers to integer addresses and - // then dispatch to rustc binary operation method - if self.memory().extra.rng.is_some() && bin_op != Offset { + // If intptrcast is enabled, treat everything of integer *type* at integer *value*. + if self.memory().extra.rng.is_some() && left.layout.ty.is_integral() { + // This is actually an integer operation, so dispatch back to the core engine. + assert!(right.layout.ty.is_integral()); let l_bits = self.force_bits(left.imm.to_scalar()?, left.layout.size)?; let r_bits = self.force_bits(right.imm.to_scalar()?, right.layout.size)?; From c6e4f760a21f0d25215a9b5b6b01798e5d08c5ca Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Jul 2019 09:23:31 +0200 Subject: [PATCH 0885/5092] allow dangling ptr-to-int casts; use force_bits for ptr comparison --- src/intptrcast.rs | 4 +++- src/operator.rs | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 548070000507..805cc2ad2a50 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -75,7 +75,9 @@ impl<'mir, 'tcx> GlobalState { let mut global_state = memory.extra.intptrcast.borrow_mut(); let global_state = &mut *global_state; - let (size, align) = memory.get_size_and_align(ptr.alloc_id, AllocCheck::Live)?; + // There is nothing wrong with a raw pointer being cast to an integer only after + // it became dangling. Hence `MaybeDead`. + let (size, align) = memory.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead)?; let base_addr = match global_state.base_addr.entry(ptr.alloc_id) { Entry::Occupied(entry) => *entry.get(), diff --git a/src/operator.rs b/src/operator.rs index 31def2fec0e0..219448431683 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -59,6 +59,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { // If intptrcast is enabled, treat everything of integer *type* at integer *value*. if self.memory().extra.rng.is_some() && left.layout.ty.is_integral() { // This is actually an integer operation, so dispatch back to the core engine. + // TODO: Once intptrcast is the default, librustc_mir should never even call us + // for integer types. assert!(right.layout.ty.is_integral()); let l_bits = self.force_bits(left.imm.to_scalar()?, left.layout.size)?; let r_bits = self.force_bits(right.imm.to_scalar()?, right.layout.size)?; @@ -186,6 +188,13 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { right: Scalar, ) -> InterpResult<'tcx, bool> { let size = self.pointer_size(); + if self.memory().extra.rng.is_some() { + // Just compare the integers. + // TODO: Do we really want to *always* do that, even when comparing two live in-bounds pointers? + let left = self.force_bits(left, size)?; + let right = self.force_bits(right, size)?; + return Ok(left == right); + } Ok(match (left, right) { (Scalar::Raw { .. }, Scalar::Raw { .. }) => left.to_bits(size)? == right.to_bits(size)?, From 12b8d4366cc48ed93441f4b039bc18e30b0f0baa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Jul 2019 09:32:21 +0200 Subject: [PATCH 0886/5092] avoid integer overflow in ptr-to-int cast --- src/intptrcast.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 805cc2ad2a50..5797895c54f8 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -4,7 +4,8 @@ use std::cmp::max; use rand::Rng; -use rustc_mir::interpret::{AllocId, Pointer, InterpResult, Memory, AllocCheck}; +use rustc::ty::layout::HasDataLayout; +use rustc_mir::interpret::{AllocId, Pointer, InterpResult, Memory, AllocCheck, PointerArithmetic}; use rustc_target::abi::Size; use crate::{Evaluator, Tag, STACK_ADDR}; @@ -109,7 +110,9 @@ impl<'mir, 'tcx> GlobalState { }; debug_assert_eq!(base_addr % align.bytes(), 0); // sanity check - Ok(base_addr + ptr.offset.bytes()) + // Add offset with the right kind of pointer-overflowing arithmetic. + let dl = memory.data_layout(); + Ok(dl.overflowing_offset(base_addr, ptr.offset.bytes()).0) } /// Shifts `addr` to make it aligned with `align` by rounding `addr` to the smallest multiple From c3da843ca02dab7b5f6563ffeb0d654bbe70e1f8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Jul 2019 09:42:07 +0200 Subject: [PATCH 0887/5092] we don't need zero-sized freeze-sensitive visiting --- src/helpers.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/helpers.rs b/src/helpers.rs index f65eef557c96..16451fb8726a 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -58,6 +58,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .map(|(size, _)| size) .unwrap_or_else(|| place.layout.size) ); + assert!(size.bytes() > 0); // Store how far we proceeded into the place so far. Everything to the left of // this offset has already been handled, in the sense that the frozen parts // have had `action` called on them. From c8450bda4fc3ed70aa019f83c58ff8ee8f9fcb09 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Jul 2019 09:56:35 +0200 Subject: [PATCH 0888/5092] support integers that can be cast to pointers in in-bounds offset operation --- src/operator.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index 219448431683..2e9b8238479f 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -397,7 +397,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { .checked_mul(pointee_size) .ok_or_else(|| InterpError::Overflow(mir::BinOp::Mul))?; // Now let's see what kind of pointer this is. - if let Scalar::Ptr(ptr) = ptr { + if let Ok(ptr) = self.force_ptr(ptr) { // Both old and new pointer must be in-bounds of a *live* allocation. // (Of the same allocation, but that part is trivial with our representation.) self.pointer_inbounds(ptr)?; @@ -405,7 +405,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { self.pointer_inbounds(ptr)?; Ok(Scalar::Ptr(ptr)) } else { - // An integer pointer. They can only be offset by 0, and we pretend there + // A "true" integer pointer. They can only be offset by 0, and we pretend there // is a little zero-sized allocation here. if offset == 0 { Ok(ptr) From eb4128fb4203f926370fdf17d6961940986728cd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Jul 2019 10:19:55 +0200 Subject: [PATCH 0889/5092] don't call Stacked Borrows hooks at all when validation is disabled --- README.md | 2 + src/eval.rs | 4 +- src/machine.rs | 78 ++++++++++++++++++++++----------- src/stacked_borrows.rs | 5 ++- tests/run-pass/transmute_fat.rs | 3 ++ 5 files changed, 62 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 8c0c87ab9ebb..69c66db52147 100644 --- a/README.md +++ b/README.md @@ -279,6 +279,8 @@ Several `-Z` flags are relevant for Miri: * `-Zalways-encode-mir` makes rustc dump MIR even for completely monomorphic functions. This is needed so that Miri can execute such functions, so Miri sets this flag per default. +* `-Zmir-emit-retag` controls whether `Retag` statements are emitted. Miri + enables this per default because it is needed for validation. Moreover, Miri recognizes some environment variables: diff --git a/src/eval.rs b/src/eval.rs index ec97a77357cf..a1157af0e39b 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -32,11 +32,11 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let mut ecx = InterpretCx::new( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), - Evaluator::new(config.validate), + Evaluator::new(), ); // FIXME: InterpretCx::new should take an initial MemoryExtra - ecx.memory_mut().extra = MemoryExtra::with_rng(config.seed.map(StdRng::seed_from_u64)); + ecx.memory_mut().extra = MemoryExtra::new(config.seed.map(StdRng::seed_from_u64), config.validate); let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; diff --git a/src/machine.rs b/src/machine.rs index 20fe2e055fb5..0ddb2d40b8e8 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -41,7 +41,8 @@ impl Into> for MiriMemoryKind { /// Extra per-allocation data #[derive(Debug, Clone)] pub struct AllocExtra { - pub stacked_borrows: stacked_borrows::AllocExtra, + /// Stacked Borrows state is only added if validation is enabled. + pub stacked_borrows: Option, } /// Extra global memory data @@ -49,17 +50,22 @@ pub struct AllocExtra { pub struct MemoryExtra { pub stacked_borrows: stacked_borrows::MemoryExtra, pub intptrcast: intptrcast::MemoryExtra, + /// The random number generator to use if Miri is running in non-deterministic mode and to /// enable intptrcast - pub(crate) rng: Option> + pub(crate) rng: Option>, + + /// Whether to enforce the validity invariant. + pub(crate) validate: bool, } impl MemoryExtra { - pub fn with_rng(rng: Option) -> Self { + pub fn new(rng: Option, validate: bool) -> Self { MemoryExtra { stacked_borrows: Default::default(), intptrcast: Default::default(), rng: rng.map(RefCell::new), + validate, } } } @@ -82,13 +88,10 @@ pub struct Evaluator<'tcx> { /// TLS state. pub(crate) tls: TlsData<'tcx>, - - /// Whether to enforce the validity invariant. - pub(crate) validate: bool, } impl<'tcx> Evaluator<'tcx> { - pub(crate) fn new(validate: bool) -> Self { + pub(crate) fn new() -> Self { Evaluator { env_vars: HashMap::default(), argc: None, @@ -96,7 +99,6 @@ impl<'tcx> Evaluator<'tcx> { cmd_line: None, last_error: 0, tls: TlsData::default(), - validate, } } } @@ -135,7 +137,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn enforce_validity(ecx: &InterpretCx<'mir, 'tcx, Self>) -> bool { - ecx.machine.validate + ecx.memory().extra.validate } /// Returns `Ok()` when the function was handled; fail otherwise. @@ -251,12 +253,17 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ) -> (Cow<'b, Allocation>, Self::PointerTag) { let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); - let (stacks, base_tag) = Stacks::new_allocation( - id, - Size::from_bytes(alloc.bytes.len() as u64), - Rc::clone(&memory.extra.stacked_borrows), - kind, - ); + let (stacks, base_tag) = if !memory.extra.validate { + (None, Tag::Untagged) + } else { + let (stacks, base_tag) = Stacks::new_allocation( + id, + Size::from_bytes(alloc.bytes.len() as u64), + Rc::clone(&memory.extra.stacked_borrows), + kind, + ); + (Some(stacks), base_tag) + }; if kind != MiriMemoryKind::Static.into() { assert!(alloc.relocations.is_empty(), "Only statics can come initialized with inner pointers"); // Now we can rely on the inner pointers being static, too. @@ -268,7 +275,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { alloc.relocations.iter() // The allocations in the relocations (pointers stored *inside* this allocation) // all get the base pointer tag. - .map(|&(offset, ((), alloc))| (offset, (memory_extra.static_base_ptr(alloc), alloc))) + .map(|&(offset, ((), alloc))| { + let tag = if !memory.extra.validate { + Tag::Untagged + } else { + memory_extra.static_base_ptr(alloc) + }; + (offset, (tag, alloc)) + }) .collect() ), undef_mask: alloc.undef_mask, @@ -286,7 +300,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { id: AllocId, memory: &Memory<'mir, 'tcx, Self>, ) -> Self::PointerTag { - memory.extra.stacked_borrows.borrow_mut().static_base_ptr(id) + if !memory.extra.validate { + Tag::Untagged + } else { + memory.extra.stacked_borrows.borrow_mut().static_base_ptr(id) + } } #[inline(always)] @@ -295,12 +313,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { kind: mir::RetagKind, place: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { - if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !Self::enforce_validity(ecx) { - // No tracking, or no retagging. The latter is possible because a dependency of ours - // might be called with different flags than we are, so there are `Retag` - // statements but we do not want to execute them. - // Also, honor the whitelist in `enforce_validity` because otherwise we might retag - // uninitialized data. + if !Self::enforce_validity(ecx) { + // No tracking. Ok(()) } else { ecx.retag(kind, place) @@ -354,7 +368,11 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - alloc.extra.stacked_borrows.memory_read(ptr, size) + if let Some(ref stacked_borrows) = alloc.extra.stacked_borrows { + stacked_borrows.memory_read(ptr, size) + } else { + Ok(()) + } } #[inline(always)] @@ -363,7 +381,11 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - alloc.extra.stacked_borrows.memory_written(ptr, size) + if let Some(ref mut stacked_borrows) = alloc.extra.stacked_borrows { + stacked_borrows.memory_written(ptr, size) + } else { + Ok(()) + } } #[inline(always)] @@ -372,7 +394,11 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - alloc.extra.stacked_borrows.memory_deallocated(ptr, size) + if let Some(ref mut stacked_borrows) = alloc.extra.stacked_borrows { + stacked_borrows.memory_deallocated(ptr, size) + } else { + Ok(()) + } } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 524ad2b47af0..5c59066c475d 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -538,6 +538,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Get the allocation. It might not be mutable, so we cannot use `get_mut`. let alloc = this.memory().get(ptr.alloc_id)?; + let stacked_borrows = alloc.extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); // Update the stacks. // Make sure that raw pointers and mutable shared references are reborrowed "weak": // There could be existing unique pointers reborrowed from them that should remain valid! @@ -553,14 +554,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We are only ever `SharedReadOnly` inside the frozen bits. let perm = if frozen { Permission::SharedReadOnly } else { Permission::SharedReadWrite }; let item = Item { perm, tag: new_tag, protector }; - alloc.extra.stacked_borrows.for_each(cur_ptr, size, |stack, global| { + stacked_borrows.for_each(cur_ptr, size, |stack, global| { stack.grant(cur_ptr.tag, item, global) }) }); } }; let item = Item { perm, tag: new_tag, protector }; - alloc.extra.stacked_borrows.for_each(ptr, size, |stack, global| { + stacked_borrows.for_each(ptr, size, |stack, global| { stack.grant(ptr.tag, item, global) }) } diff --git a/tests/run-pass/transmute_fat.rs b/tests/run-pass/transmute_fat.rs index ec887902d054..27da44935b10 100644 --- a/tests/run-pass/transmute_fat.rs +++ b/tests/run-pass/transmute_fat.rs @@ -1,3 +1,6 @@ +// Validation disallows this becuase the reference is never cast to a raw pointer. +// compile-flags: -Zmiri-disable-validation + fn main() { // If we are careful, we can exploit data layout... let raw = unsafe { From 8ec25066e741fd0e4a87f2eed53a777dbc64b802 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Jul 2019 10:46:51 +0200 Subject: [PATCH 0890/5092] make a test noseed for now that does not work with intptrcast yet --- tests/{run-pass => run-pass-noseed}/ptr_int_casts.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/{run-pass => run-pass-noseed}/ptr_int_casts.rs (100%) diff --git a/tests/run-pass/ptr_int_casts.rs b/tests/run-pass-noseed/ptr_int_casts.rs similarity index 100% rename from tests/run-pass/ptr_int_casts.rs rename to tests/run-pass-noseed/ptr_int_casts.rs From b29cb7d551cece20ec0fe0b378edaeb1318d702d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Jul 2019 10:54:16 +0200 Subject: [PATCH 0891/5092] avoid catching errors --- src/operator.rs | 33 ++++++++++--------- tests/compile-fail/ptr_offset_int_plus_int.rs | 2 +- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index 2e9b8238479f..df60acc661ed 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -397,21 +397,24 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { .checked_mul(pointee_size) .ok_or_else(|| InterpError::Overflow(mir::BinOp::Mul))?; // Now let's see what kind of pointer this is. - if let Ok(ptr) = self.force_ptr(ptr) { - // Both old and new pointer must be in-bounds of a *live* allocation. - // (Of the same allocation, but that part is trivial with our representation.) - self.pointer_inbounds(ptr)?; - let ptr = ptr.signed_offset(offset, self)?; - self.pointer_inbounds(ptr)?; - Ok(Scalar::Ptr(ptr)) - } else { - // A "true" integer pointer. They can only be offset by 0, and we pretend there - // is a little zero-sized allocation here. - if offset == 0 { - Ok(ptr) - } else { - err!(InvalidPointerMath) + let ptr = if offset == 0 { + match ptr { + Scalar::Ptr(ptr) => ptr, + Scalar::Raw { .. } => { + // Offset 0 on an integer. We accept that, pretending there is + // a little zero-sized allocation here. + return Ok(ptr); + } } - } + } else { + // Offset > 0. We *require* a pointer. + self.force_ptr(ptr)? + }; + // Both old and new pointer must be in-bounds of a *live* allocation. + // (Of the same allocation, but that part is trivial with our representation.) + self.pointer_inbounds(ptr)?; + let ptr = ptr.signed_offset(offset, self)?; + self.pointer_inbounds(ptr)?; + Ok(Scalar::Ptr(ptr)) } } diff --git a/tests/compile-fail/ptr_offset_int_plus_int.rs b/tests/compile-fail/ptr_offset_int_plus_int.rs index d02739610814..2d3282a0a97a 100644 --- a/tests/compile-fail/ptr_offset_int_plus_int.rs +++ b/tests/compile-fail/ptr_offset_int_plus_int.rs @@ -1,4 +1,4 @@ -// error-pattern: invalid arithmetic on pointers +// error-pattern: tried to interpret some bytes as a pointer fn main() { // Can't offset an integer pointer by non-zero offset. From 074e20eb7b3f36846c6c3a182060a5b82da46498 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 29 Jun 2019 13:17:15 -0500 Subject: [PATCH 0892/5092] Add intptrcast test for explicit casts --- tests/run-pass-noseed/intptrcast.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/run-pass-noseed/intptrcast.rs b/tests/run-pass-noseed/intptrcast.rs index 40b21f9a4729..919083f98d3d 100644 --- a/tests/run-pass-noseed/intptrcast.rs +++ b/tests/run-pass-noseed/intptrcast.rs @@ -1,4 +1,7 @@ // compile-flags: -Zmiri-seed=0000000000000000 +fn transmute_ptr_to_int(x: *const T) -> usize { + unsafe { std::mem::transmute::<*const T, usize>(x) * 1 } +} fn main() { // Some casting-to-int with arithmetic. @@ -11,4 +14,11 @@ fn main() { // Pointer string formatting! We can't check the output as it changes when libstd changes, // but we can make sure Miri does not error. format!("{:?}", &mut 13 as *mut _); + + // Check that intptrcast is triggered for explicit casts and that it is consistent with + // transmuting. + let a: *const i32 = &42; + let b = transmute_ptr_to_int(a) as u8; + let c = a as usize as u8; + assert_eq!(b, c); } From 39d383d9e729965b406009033977cb942dc899b3 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 3 Jul 2019 13:28:30 -0500 Subject: [PATCH 0893/5092] Update rust-version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 17338728254a..9e4ddf2acaaa 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7e08576e4276a97b523c25bfd196d419c39c7b87 +088b987307b91612ab164026e1dcdd0129fdb62b From 8dfb278ac5ad47f7fac3d161ebb30d9efb9246a3 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 3 Jul 2019 13:42:01 -0500 Subject: [PATCH 0894/5092] Fix explicit cast test --- tests/run-pass-noseed/intptrcast.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/run-pass-noseed/intptrcast.rs b/tests/run-pass-noseed/intptrcast.rs index 919083f98d3d..1b5251c91119 100644 --- a/tests/run-pass-noseed/intptrcast.rs +++ b/tests/run-pass-noseed/intptrcast.rs @@ -1,11 +1,13 @@ // compile-flags: -Zmiri-seed=0000000000000000 -fn transmute_ptr_to_int(x: *const T) -> usize { - unsafe { std::mem::transmute::<*const T, usize>(x) * 1 } + +// This returns a miri pointer at type usize, if the argument is a proper pointer +fn transmute_ptr_to_int(x: *const T) -> usize { + unsafe { std::mem::transmute(x) } } fn main() { // Some casting-to-int with arithmetic. - let x = &42 as *const i32 as usize; + let x = &42 as *const i32 as usize; let y = x * 2; assert_eq!(y, x + x); let z = y as u8 as usize; From 93c62a4912c7350924ec942aed37ff1cc363352f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Jul 2019 23:12:44 +0200 Subject: [PATCH 0895/5092] move tls.rs into shims module --- src/lib.rs | 3 +-- src/shims/mod.rs | 1 + src/{ => shims}/tls.rs | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename src/{ => shims}/tls.rs (100%) diff --git a/src/lib.rs b/src/lib.rs index 50cf32f85204..31e707077769 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,6 @@ extern crate rustc_target; mod shims; mod operator; mod helpers; -mod tls; mod range_map; mod mono_hash_map; mod stacked_borrows; @@ -31,8 +30,8 @@ pub use rustc_mir::interpret::{self, AllocMap, PlaceTy}; pub use crate::shims::{EvalContextExt as ShimsEvalContextExt}; pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextExt; pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; +pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; -pub use crate::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; pub use crate::mono_hash_map::MonoHashMap; diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 0fc23e811937..3258cf3d9c1d 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -1,5 +1,6 @@ pub mod foreign_items; pub mod intrinsics; +pub mod tls; use rustc::{ty, mir}; diff --git a/src/tls.rs b/src/shims/tls.rs similarity index 100% rename from src/tls.rs rename to src/shims/tls.rs From 802dcb7f890cf1e05a98fd21466f74d9c9b5b748 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Jul 2019 00:06:41 +0200 Subject: [PATCH 0896/5092] temporarily disable ptr_offset, maybe that helps --- tests/run-pass-noseed/ptr_int_casts.rs | 1 + tests/{run-pass => run-pass-noseed}/ptr_offset.rs | 2 ++ 2 files changed, 3 insertions(+) rename tests/{run-pass => run-pass-noseed}/ptr_offset.rs (85%) diff --git a/tests/run-pass-noseed/ptr_int_casts.rs b/tests/run-pass-noseed/ptr_int_casts.rs index c279024f35ea..ebf65ac3fe24 100644 --- a/tests/run-pass-noseed/ptr_int_casts.rs +++ b/tests/run-pass-noseed/ptr_int_casts.rs @@ -1,3 +1,4 @@ +// FIXME move this to run-pass, it should work with intptrcast. use std::mem; use std::ptr; diff --git a/tests/run-pass/ptr_offset.rs b/tests/run-pass-noseed/ptr_offset.rs similarity index 85% rename from tests/run-pass/ptr_offset.rs rename to tests/run-pass-noseed/ptr_offset.rs index 1c7f0eb71797..a836e02812da 100644 --- a/tests/run-pass/ptr_offset.rs +++ b/tests/run-pass-noseed/ptr_offset.rs @@ -1,3 +1,5 @@ +// FIXME move this to run-pass, it should work with intptrcast. + fn f() -> i32 { 42 } fn main() { From 07d5e9917cb17d8c8aa2c132919e985841ed24bc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Jul 2019 09:56:42 +0200 Subject: [PATCH 0897/5092] avoid Scalar::is_null_ptr, it is going away --- src/helpers.rs | 22 ++++++++++++++++++++++ src/shims/foreign_items.rs | 35 +++++++++++++---------------------- src/shims/tls.rs | 20 +++++++++++++------- 3 files changed, 48 insertions(+), 29 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 16451fb8726a..3503af43690f 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -43,6 +43,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) } + /// Write a 0 of the appropriate size to `dest`. + fn write_null(&mut self, dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest) + } + + /// Test if this immediate equals 0. + fn is_null(&self, val: Scalar) -> InterpResult<'tcx, bool> { + let this = self.eval_context_ref(); + let null = Scalar::from_int(0, this.memory().pointer_size()); + this.ptr_eq(val, null) + } + + /// Turn a Scalar into an Option + fn test_null(&self, val: Scalar) -> InterpResult<'tcx, Option>> { + let this = self.eval_context_ref(); + Ok(if this.is_null(val)? { + None + } else { + Some(val) + }) + } + /// Visits the memory covered by `place`, sensitive to freezing: the 3rd parameter /// will be true if this is frozen, false if this is in an `UnsafeCell`. fn visit_freeze_sensitive( diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index c9b10e02c978..d43374f1bcf8 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -49,7 +49,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ptr: Scalar, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - if !ptr.is_null_ptr(this) { + if !this.is_null(ptr)? { this.memory_mut().deallocate( ptr.to_ptr()?, None, @@ -66,7 +66,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let align = this.min_align(); - if old_ptr.is_null_ptr(this) { + if this.is_null(old_ptr)? { if new_size == 0 { Ok(Scalar::from_int(0, this.pointer_size())) } else { @@ -427,7 +427,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut success = None; { let name_ptr = this.read_scalar(args[0])?.not_undef()?; - if !name_ptr.is_null_ptr(this) { + if !this.is_null(name_ptr)? { let name_ptr = name_ptr.to_ptr()?; let name = this .memory() @@ -455,7 +455,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_ptr = this.read_scalar(args[0])?.not_undef()?; let value_ptr = this.read_scalar(args[1])?.to_ptr()?; let value = this.memory().get(value_ptr.alloc_id)?.read_c_str(tcx, value_ptr)?; - if !name_ptr.is_null_ptr(this) { + if !this.is_null(name_ptr)? { let name_ptr = name_ptr.to_ptr()?; let name = this.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?; if !name.is_empty() && !name.contains(&b'=') { @@ -638,14 +638,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let key_ptr = this.read_scalar(args[0])?.not_undef()?; // Extract the function type out of the signature (that seems easier than constructing it ourselves). - let dtor = match this.read_scalar(args[1])?.not_undef()? { - Scalar::Ptr(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr)?), - Scalar::Raw { data: 0, size } => { - // NULL pointer - assert_eq!(size as u64, this.memory().pointer_size().bytes()); - None - }, - Scalar::Raw { .. } => return err!(ReadBytesAsPointer), + let dtor = match this.test_null(this.read_scalar(args[1])?.not_undef()?)? { + Some(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr.to_ptr()?)?), + None => None, }; // Figure out how large a pthread TLS key actually is. @@ -657,7 +652,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let key_layout = this.layout_of(key_type)?; // Create key and write it into the memory where `key_ptr` wants it. - let key = this.machine.tls.create_tls_key(dtor, tcx) as u128; + let key = this.machine.tls.create_tls_key(dtor) as u128; if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) { return err!(OutOfTls); } @@ -682,13 +677,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "pthread_getspecific" => { let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; - let ptr = this.machine.tls.load_tls(key)?; + let ptr = this.machine.tls.load_tls(key, tcx)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; let new_ptr = this.read_scalar(args[1])?.not_undef()?; - this.machine.tls.store_tls(key, new_ptr)?; + this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?; // Return success (`0`). this.write_null(dest)?; @@ -842,7 +837,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This just creates a key; Windows does not natively support TLS destructors. // Create key and return it. - let key = this.machine.tls.create_tls_key(None, tcx) as u128; + let key = this.machine.tls.create_tls_key(None) as u128; // Figure out how large a TLS key actually is. This is `c::DWORD`. if dest.layout.size.bits() < 128 @@ -853,13 +848,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "TlsGetValue" => { let key = this.read_scalar(args[0])?.to_u32()? as u128; - let ptr = this.machine.tls.load_tls(key)?; + let ptr = this.machine.tls.load_tls(key, tcx)?; this.write_scalar(ptr, dest)?; } "TlsSetValue" => { let key = this.read_scalar(args[0])?.to_u32()? as u128; let new_ptr = this.read_scalar(args[1])?.not_undef()?; - this.machine.tls.store_tls(key, new_ptr)?; + this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?; // Return success (`1`). this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; @@ -936,10 +931,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - fn write_null(&mut self, dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { - self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest) - } - /// Evaluates the scalar at the specified path. Returns Some(val) /// if the path could be resolved, and None otherwise fn eval_path_scalar(&mut self, path: &[&str]) -> InterpResult<'tcx, Option>> { diff --git a/src/shims/tls.rs b/src/shims/tls.rs index ddc301447c7e..6d6a71b8eb24 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -12,7 +12,10 @@ pub type TlsKey = u128; #[derive(Copy, Clone, Debug)] pub struct TlsEntry<'tcx> { - pub(crate) data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. + /// The data for this key. None is used to represent NULL. + /// (We normalize this early to avoid having to do a NULL-ptr-test each time we access the data.) + /// Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. + pub(crate) data: Option>, pub(crate) dtor: Option>, } @@ -38,14 +41,13 @@ impl<'tcx> TlsData<'tcx> { pub fn create_tls_key( &mut self, dtor: Option>, - cx: &impl HasDataLayout, ) -> TlsKey { let new_key = self.next_key; self.next_key += 1; self.keys.insert( new_key, TlsEntry { - data: Scalar::ptr_null(cx).into(), + data: None, dtor, }, ); @@ -63,17 +65,21 @@ impl<'tcx> TlsData<'tcx> { } } - pub fn load_tls(&mut self, key: TlsKey) -> InterpResult<'tcx, Scalar> { + pub fn load_tls( + &mut self, + key: TlsKey, + cx: &impl HasDataLayout, + ) -> InterpResult<'tcx, Scalar> { match self.keys.get(&key) { Some(&TlsEntry { data, .. }) => { trace!("TLS key {} loaded: {:?}", key, data); - Ok(data) + Ok(data.unwrap_or_else(|| Scalar::ptr_null(cx).into())) } None => err!(TlsOutOfBounds), } } - pub fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> InterpResult<'tcx> { + pub fn store_tls(&mut self, key: TlsKey, new_data: Option>) -> InterpResult<'tcx> { match self.keys.get_mut(&key) { Some(&mut TlsEntry { ref mut data, .. }) => { trace!("TLS key {} stored: {:?}", key, new_data); @@ -117,7 +123,7 @@ impl<'tcx> TlsData<'tcx> { for (&key, &mut TlsEntry { ref mut data, dtor }) in thread_local.range_mut((start, Unbounded)) { - if !data.is_null_ptr(cx) { + if let Some(ref mut data) = *data { if let Some(dtor) = dtor { let ret = Some((dtor, *data, key)); *data = Scalar::ptr_null(cx); From 698b311a596b5d141b0c42f1b5400adc1f11150f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Jul 2019 10:08:57 +0200 Subject: [PATCH 0898/5092] fix NULL in TLS dtors --- src/shims/tls.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 6d6a71b8eb24..9a22c03bf2f6 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -6,6 +6,7 @@ use rustc::{ty, ty::layout::HasDataLayout, mir}; use crate::{ InterpResult, InterpError, StackPopCleanup, MPlaceTy, Scalar, Tag, + HelpersEvalContextExt, }; pub type TlsKey = u128; @@ -111,7 +112,6 @@ impl<'tcx> TlsData<'tcx> { fn fetch_tls_dtor( &mut self, key: Option, - cx: &impl HasDataLayout, ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { use std::collections::Bound::*; @@ -123,10 +123,10 @@ impl<'tcx> TlsData<'tcx> { for (&key, &mut TlsEntry { ref mut data, dtor }) in thread_local.range_mut((start, Unbounded)) { - if let Some(ref mut data) = *data { + if let Some(data_scalar) = *data { if let Some(dtor) = dtor { - let ret = Some((dtor, *data, key)); - *data = Scalar::ptr_null(cx); + let ret = Some((dtor, data_scalar, key)); + *data = None; return ret; } } @@ -139,10 +139,11 @@ impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tc pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn run_tls_dtors(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let mut dtor = this.machine.tls.fetch_tls_dtor(None, &*this.tcx); + let mut dtor = this.machine.tls.fetch_tls_dtor(None); // FIXME: replace loop by some structure that works with stepping while let Some((instance, ptr, key)) = dtor { trace!("Running TLS dtor {:?} on {:?}", instance, ptr); + assert!(!this.is_null(ptr).unwrap(), "Data can't be NULL when dtor is called!"); // TODO: Potentially, this has to support all the other possible instances? // See eval_fn_call in interpret/terminator/mod.rs let mir = this.load_mir(instance.def)?; @@ -163,9 +164,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // step until out of stackframes this.run()?; - dtor = match this.machine.tls.fetch_tls_dtor(Some(key), &*this.tcx) { + dtor = match this.machine.tls.fetch_tls_dtor(Some(key)) { dtor @ Some(_) => dtor, - None => this.machine.tls.fetch_tls_dtor(None, &*this.tcx), + None => this.machine.tls.fetch_tls_dtor(None), }; } // FIXME: On a windows target, call `unsafe extern "system" fn on_tls_callback`. From aad5fde70316f87f023b918001f02db21d7ff0e1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Jul 2019 19:21:21 +0200 Subject: [PATCH 0899/5092] fix deallocating/reallocating with integer pointers --- src/shims/foreign_items.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index c9b10e02c978..540e3fc96406 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -50,8 +50,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if !ptr.is_null_ptr(this) { + let ptr = this.force_ptr(ptr)?; this.memory_mut().deallocate( - ptr.to_ptr()?, + ptr, None, MiriMemoryKind::C.into(), )?; @@ -78,7 +79,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(Scalar::Ptr(new_ptr)) } } else { - let old_ptr = old_ptr.to_ptr()?; + let old_ptr = this.force_ptr(old_ptr)?; let memory = this.memory_mut(); let old_size = Size::from_bytes(memory.get(old_ptr.alloc_id)?.bytes.len() as u64); if new_size == 0 { @@ -234,7 +235,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_dealloc" => { - let ptr = this.read_scalar(args[0])?.to_ptr()?; + let ptr = this.read_scalar(args[0])?.not_undef()?; let old_size = this.read_scalar(args[1])?.to_usize(this)?; let align = this.read_scalar(args[2])?.to_usize(this)?; if old_size == 0 { @@ -243,6 +244,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } + let ptr = this.force_ptr(ptr)?; this.memory_mut().deallocate( ptr, Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())), From 6c58d40a8d42650332a4c68b44ea3827263c395f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Jul 2019 19:21:42 +0200 Subject: [PATCH 0900/5092] temporarily disable validation for 'cargo miri test' testing --- test-cargo-miri/run-test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 73515c74e401..a9aba008e9a9 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -52,8 +52,9 @@ def test_cargo_miri_run(): ) def test_cargo_miri_test(): + # FIXME: enable validation again, once that no longer conflicts with intptrcast test("cargo miri test", - cargo_miri("test") + ["--", "-Zmiri-seed=feed"], + cargo_miri("test") + ["--", "-Zmiri-seed=feed", "-Zmiri-disable-validation"], "test.stdout.ref", "test.stderr.ref" ) test("cargo miri test (with filter)", From 9b58492df179be10cc2004ad0fe0616cdfd9b505 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Jul 2019 19:22:22 +0200 Subject: [PATCH 0901/5092] temporarily disable intptrcast advanced testing on Windows --- tests/compiletest.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 1d32d3a73244..b31be0a4f32d 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -83,6 +83,7 @@ fn miri_pass(path: &str, target: &str, opt: bool, noseed: bool) { flags.push("-Zmir-opt-level=3".to_owned()); } else if !noseed { // Run with intptrcast. Avoid test matrix explosion by doing either this or opt-level=3. + #[cfg(not(windows))] // FIXME re-enable on Windows flags.push("-Zmiri-seed=".to_owned()); } From 4d76dd1f09db1b5a69435d3aa85c4c2f0a5887c1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Jul 2019 21:26:58 +0200 Subject: [PATCH 0902/5092] temporarily disable validation on Windows --- src/eval.rs | 10 +++++++++- tests/compiletest.rs | 5 +++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index a1157af0e39b..91a563fa56b9 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -35,8 +35,16 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( Evaluator::new(), ); + // FIXME(https://github.com/rust-lang/miri/pull/803): no validation on Windows. + let target_os = ecx.tcx.tcx.sess.target.target.target_os.to_lowercase(); + let validate = if target_os == "windows" { + false + } else { + config.validate + }; + // FIXME: InterpretCx::new should take an initial MemoryExtra - ecx.memory_mut().extra = MemoryExtra::new(config.seed.map(StdRng::seed_from_u64), config.validate); + ecx.memory_mut().extra = MemoryExtra::new(config.seed.map(StdRng::seed_from_u64), validate); let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; diff --git a/tests/compiletest.rs b/tests/compiletest.rs index b31be0a4f32d..076deca6a318 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -83,7 +83,6 @@ fn miri_pass(path: &str, target: &str, opt: bool, noseed: bool) { flags.push("-Zmir-opt-level=3".to_owned()); } else if !noseed { // Run with intptrcast. Avoid test matrix explosion by doing either this or opt-level=3. - #[cfg(not(windows))] // FIXME re-enable on Windows flags.push("-Zmiri-seed=".to_owned()); } @@ -113,7 +112,9 @@ fn run_pass_miri(opt: bool) { } fn compile_fail_miri(opt: bool) { - compile_fail("tests/compile-fail", &get_target(), opt); + if !cfg!(windows) { // FIXME re-enable on Windows + compile_fail("tests/compile-fail", &get_target(), opt); + } } fn test_runner(_tests: &[&()]) { From f23b782101c03331413870a11a787d4b605b84df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Jul 2019 09:03:45 +0200 Subject: [PATCH 0903/5092] align small malloc-allocations even less, and test that we do --- src/machine.rs | 4 +- src/shims/foreign_items.rs | 70 +++++++++++++++--------- tests/run-pass/{realloc.rs => malloc.rs} | 11 ++++ 3 files changed, 58 insertions(+), 27 deletions(-) rename tests/run-pass/{realloc.rs => malloc.rs} (70%) diff --git a/src/machine.rs b/src/machine.rs index 0ddb2d40b8e8..a58903f6d516 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -25,6 +25,8 @@ pub enum MiriMemoryKind { Rust, /// `malloc` memory. C, + /// Windows `HeapAlloc` memory. + WinHeap, /// Part of env var emulation. Env, /// Statics. @@ -407,7 +409,7 @@ impl MayLeak for MiriMemoryKind { fn may_leak(self) -> bool { use self::MiriMemoryKind::*; match self { - Rust | C => false, + Rust | C | WinHeap => false, Env | Static => true, } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 2a3644e45cbf..38fc36609e69 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -10,8 +10,8 @@ use crate::*; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// Returns the minimum alignment for the target architecture. - fn min_align(&self) -> Align { + /// Returns the minimum alignment for the target architecture for allocations of the given size. + fn min_align(&self, size: u64, kind: MiriMemoryKind) -> Align { let this = self.eval_context_ref(); // List taken from `libstd/sys_common/alloc.rs`. let min_align = match this.tcx.tcx.sess.target.target.arch.as_str() { @@ -19,21 +19,39 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "x86_64" | "aarch64" | "mips64" | "s390x" | "sparc64" => 16, arch => bug!("Unsupported target architecture: {}", arch), }; - Align::from_bytes(min_align).unwrap() + // Windows always aligns, even small allocations. + // Source: + // But jemalloc does not, so for the C heap we only align if the allocation is sufficiently big. + if kind == MiriMemoryKind::WinHeap || size >= min_align { + return Align::from_bytes(min_align).unwrap(); + } + // We have `size < min_align`. Round `size` *down* to the next power of two and use that. + fn prev_power_of_two(x: u64) -> u64 { + let next_pow2 = x.next_power_of_two(); + if next_pow2 == x { + // x *is* a power of two, just use that. + x + } else { + // x is between two powers, so next = 2*prev. + next_pow2 / 2 + } + } + Align::from_bytes(prev_power_of_two(size)).unwrap() } fn malloc( &mut self, size: u64, zero_init: bool, + kind: MiriMemoryKind, ) -> Scalar { let this = self.eval_context_mut(); let tcx = &{this.tcx.tcx}; if size == 0 { Scalar::from_int(0, this.pointer_size()) } else { - let align = this.min_align(); - let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into()); + let align = this.min_align(size, kind); + let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, kind.into()); if zero_init { // We just allocated this, the access cannot fail this.memory_mut() @@ -47,6 +65,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn free( &mut self, ptr: Scalar, + kind: MiriMemoryKind, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if !this.is_null(ptr)? { @@ -54,7 +73,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.memory_mut().deallocate( ptr, None, - MiriMemoryKind::C.into(), + kind.into(), )?; } Ok(()) @@ -64,39 +83,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, old_ptr: Scalar, new_size: u64, + kind: MiriMemoryKind, ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let align = this.min_align(); + let new_align = this.min_align(new_size, kind); if this.is_null(old_ptr)? { if new_size == 0 { Ok(Scalar::from_int(0, this.pointer_size())) } else { let new_ptr = this.memory_mut().allocate( Size::from_bytes(new_size), - align, - MiriMemoryKind::C.into() + new_align, + kind.into() ); Ok(Scalar::Ptr(new_ptr)) } } else { let old_ptr = this.force_ptr(old_ptr)?; let memory = this.memory_mut(); - let old_size = Size::from_bytes(memory.get(old_ptr.alloc_id)?.bytes.len() as u64); if new_size == 0 { memory.deallocate( old_ptr, - Some((old_size, align)), - MiriMemoryKind::C.into(), + None, + kind.into(), )?; Ok(Scalar::from_int(0, this.pointer_size())) } else { let new_ptr = memory.reallocate( old_ptr, - old_size, - align, + None, Size::from_bytes(new_size), - align, - MiriMemoryKind::C.into(), + new_align, + kind.into(), )?; Ok(Scalar::Ptr(new_ptr)) } @@ -145,14 +163,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { "malloc" => { let size = this.read_scalar(args[0])?.to_usize(this)?; - let res = this.malloc(size, /*zero_init:*/ false); + let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C); this.write_scalar(res, dest)?; } "calloc" => { let items = this.read_scalar(args[0])?.to_usize(this)?; let len = this.read_scalar(args[1])?.to_usize(this)?; let size = items.checked_mul(len).ok_or_else(|| InterpError::Overflow(mir::BinOp::Mul))?; - let res = this.malloc(size, /*zero_init:*/ true); + let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C); this.write_scalar(res, dest)?; } "posix_memalign" => { @@ -187,12 +205,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "free" => { let ptr = this.read_scalar(args[0])?.not_undef()?; - this.free(ptr)?; + this.free(ptr, MiriMemoryKind::C)?; } "realloc" => { let old_ptr = this.read_scalar(args[0])?.not_undef()?; let new_size = this.read_scalar(args[1])?.to_usize(this)?; - let res = this.realloc(old_ptr, new_size)?; + let res = this.realloc(old_ptr, new_size, MiriMemoryKind::C)?; this.write_scalar(res, dest)?; } @@ -262,12 +280,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } + let align = Align::from_bytes(align).unwrap(); let new_ptr = this.memory_mut().reallocate( ptr, - Size::from_bytes(old_size), - Align::from_bytes(align).unwrap(), + Some((Size::from_bytes(old_size), align)), Size::from_bytes(new_size), - Align::from_bytes(align).unwrap(), + align, MiriMemoryKind::Rust.into(), )?; this.write_scalar(Scalar::Ptr(new_ptr), dest)?; @@ -765,14 +783,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let flags = this.read_scalar(args[1])?.to_u32()?; let size = this.read_scalar(args[2])?.to_usize(this)?; let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY - let res = this.malloc(size, zero_init); + let res = this.malloc(size, zero_init, MiriMemoryKind::WinHeap); this.write_scalar(res, dest)?; } "HeapFree" => { let _handle = this.read_scalar(args[0])?.to_isize(this)?; let _flags = this.read_scalar(args[1])?.to_u32()?; let ptr = this.read_scalar(args[2])?.not_undef()?; - this.free(ptr)?; + this.free(ptr, MiriMemoryKind::WinHeap)?; this.write_scalar(Scalar::from_int(1, Size::from_bytes(4)), dest)?; } "HeapReAlloc" => { @@ -780,7 +798,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let _flags = this.read_scalar(args[1])?.to_u32()?; let ptr = this.read_scalar(args[2])?.not_undef()?; let size = this.read_scalar(args[3])?.to_usize(this)?; - let res = this.realloc(ptr, size)?; + let res = this.realloc(ptr, size, MiriMemoryKind::WinHeap)?; this.write_scalar(res, dest)?; } diff --git a/tests/run-pass/realloc.rs b/tests/run-pass/malloc.rs similarity index 70% rename from tests/run-pass/realloc.rs rename to tests/run-pass/malloc.rs index c23b3e645c70..a50b3f3606de 100644 --- a/tests/run-pass/realloc.rs +++ b/tests/run-pass/malloc.rs @@ -1,4 +1,5 @@ //ignore-windows: Uses POSIX APIs +//compile-flags: -Zmiri-seed= #![feature(rustc_private)] @@ -7,6 +8,16 @@ use core::{slice, ptr}; extern crate libc; fn main() { + // Test that small allocations sometimes *are* not very aligned. + let saw_unaligned = (0..64).any(|_| unsafe { + let p = libc::malloc(3); + let addr = p as usize; + let unaligned = addr % 4 != 0; // test that this is not 4-aligned + libc::free(p); // FIXME have to free *after* test; should allow ptr-to-int of dangling ptr. + unaligned + }); + assert!(saw_unaligned); + unsafe { // Use calloc for initialized memory let p1 = libc::calloc(20, 1); From 1729965808dec239aa46f2eafaa39261f491a0b4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Jul 2019 23:47:10 +0200 Subject: [PATCH 0904/5092] rename InterpretCx -> InterpCx --- src/eval.rs | 8 ++++---- src/machine.rs | 22 +++++++++++----------- src/shims/foreign_items.rs | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 91a563fa56b9..b29ce3537706 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -8,7 +8,7 @@ use rustc::hir::def_id::DefId; use rustc::mir; use crate::{ - InterpResult, InterpError, InterpretCx, StackPopCleanup, struct_error, + InterpResult, InterpError, InterpCx, StackPopCleanup, struct_error, Scalar, Tag, Pointer, MemoryExtra, MiriMemoryKind, Evaluator, TlsEvalContextExt, }; @@ -28,8 +28,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig, -) -> InterpResult<'tcx, InterpretCx<'mir, 'tcx, Evaluator<'tcx>>> { - let mut ecx = InterpretCx::new( +) -> InterpResult<'tcx, InterpCx<'mir, 'tcx, Evaluator<'tcx>>> { + let mut ecx = InterpCx::new( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), Evaluator::new(), @@ -43,7 +43,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( config.validate }; - // FIXME: InterpretCx::new should take an initial MemoryExtra + // FIXME: InterpCx::new should take an initial MemoryExtra ecx.memory_mut().extra = MemoryExtra::new(config.seed.map(StdRng::seed_from_u64), validate); let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); diff --git a/src/machine.rs b/src/machine.rs index a58903f6d516..930eeee96b59 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -105,8 +105,8 @@ impl<'tcx> Evaluator<'tcx> { } } -/// A rustc InterpretCx for Miri. -pub type MiriEvalContext<'mir, 'tcx> = InterpretCx<'mir, 'tcx, Evaluator<'tcx>>; +/// A rustc InterpCx for Miri. +pub type MiriEvalContext<'mir, 'tcx> = InterpCx<'mir, 'tcx, Evaluator<'tcx>>; /// A little trait that's useful to be inherited by extension traits. pub trait MiriEvalContextExt<'mir, 'tcx> { @@ -138,14 +138,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { const STATIC_KIND: Option = Some(MiriMemoryKind::Static); #[inline(always)] - fn enforce_validity(ecx: &InterpretCx<'mir, 'tcx, Self>) -> bool { + fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { ecx.memory().extra.validate } /// Returns `Ok()` when the function was handled; fail otherwise. #[inline(always)] fn find_fn( - ecx: &mut InterpretCx<'mir, 'tcx, Self>, + ecx: &mut InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], dest: Option>, @@ -156,7 +156,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn call_intrinsic( - ecx: &mut rustc_mir::interpret::InterpretCx<'mir, 'tcx, Self>, + ecx: &mut rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, @@ -166,7 +166,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn ptr_op( - ecx: &rustc_mir::interpret::InterpretCx<'mir, 'tcx, Self>, + ecx: &rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>, bin_op: mir::BinOp, left: ImmTy<'tcx, Tag>, right: ImmTy<'tcx, Tag>, @@ -175,7 +175,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } fn box_alloc( - ecx: &mut InterpretCx<'mir, 'tcx, Self>, + ecx: &mut InterpCx<'mir, 'tcx, Self>, dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { trace!("box_alloc for {:?}", dest.layout.ty); @@ -241,7 +241,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } #[inline(always)] - fn before_terminator(_ecx: &mut InterpretCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> + fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { // We are not interested in detecting loops. Ok(()) @@ -311,7 +311,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn retag( - ecx: &mut InterpretCx<'mir, 'tcx, Self>, + ecx: &mut InterpCx<'mir, 'tcx, Self>, kind: mir::RetagKind, place: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { @@ -325,14 +325,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn stack_push( - ecx: &mut InterpretCx<'mir, 'tcx, Self>, + ecx: &mut InterpCx<'mir, 'tcx, Self>, ) -> InterpResult<'tcx, stacked_borrows::CallId> { Ok(ecx.memory().extra.stacked_borrows.borrow_mut().new_call()) } #[inline(always)] fn stack_pop( - ecx: &mut InterpretCx<'mir, 'tcx, Self>, + ecx: &mut InterpCx<'mir, 'tcx, Self>, extra: stacked_borrows::CallId, ) -> InterpResult<'tcx> { Ok(ecx.memory().extra.stacked_borrows.borrow_mut().end_call(extra)) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 38fc36609e69..2fe2ecc19581 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -345,7 +345,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("__rust_maybe_catch_panic: {:?}", f_instance); // Now we make a function call. - // TODO: consider making this reusable? `InterpretCx::step` does something similar + // TODO: consider making this reusable? `InterpCx::step` does something similar // for the TLS destructors, and of course `eval_main`. let mir = this.load_mir(f_instance.def)?; let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); From b75e9179bf21254a198e5b7359589cd0502d135c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Jul 2019 23:49:30 +0200 Subject: [PATCH 0905/5092] bump rustc --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 9e4ddf2acaaa..cbd8e335771e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -088b987307b91612ab164026e1dcdd0129fdb62b +24a9bcbb7cb0d8bdc11b8252a9c13f7562c7e4ca From 029a29407acd30454fb41f340a8d108a47bef349 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Jul 2019 23:51:11 +0200 Subject: [PATCH 0906/5092] dangling-ptr-to-int should work now; move to noseed --- tests/{run-pass => run-pass-noseed}/malloc.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) rename tests/{run-pass => run-pass-noseed}/malloc.rs (84%) diff --git a/tests/run-pass/malloc.rs b/tests/run-pass-noseed/malloc.rs similarity index 84% rename from tests/run-pass/malloc.rs rename to tests/run-pass-noseed/malloc.rs index a50b3f3606de..bf51baacd35a 100644 --- a/tests/run-pass/malloc.rs +++ b/tests/run-pass-noseed/malloc.rs @@ -11,10 +11,8 @@ fn main() { // Test that small allocations sometimes *are* not very aligned. let saw_unaligned = (0..64).any(|_| unsafe { let p = libc::malloc(3); - let addr = p as usize; - let unaligned = addr % 4 != 0; // test that this is not 4-aligned - libc::free(p); // FIXME have to free *after* test; should allow ptr-to-int of dangling ptr. - unaligned + libc::free(p); + (p as usize) % 4 != 0 // find any that this is *not* 4-aligned }); assert!(saw_unaligned); From 67882459f3ce77199f1a74180c3bccf730b5d5cb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Jul 2019 09:29:58 +0200 Subject: [PATCH 0907/5092] bump rustc --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index cbd8e335771e..e278a8063370 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -24a9bcbb7cb0d8bdc11b8252a9c13f7562c7e4ca +481068a707679257e2a738b40987246e0420e787 From 5e022773f3e5b6a8218e94d08566a931d713bb0e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Jul 2019 09:32:35 +0200 Subject: [PATCH 0908/5092] fix unused variable warning --- src/range_map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/range_map.rs b/src/range_map.rs index f2cbd89f64da..aa9a87887d37 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -281,7 +281,7 @@ mod tests { .map(|&t| t).collect::>(), vec![19, 19]); // A NOP `iter_mut` should trigger merging. - for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(5)) { } + for _ in map.iter_mut(Size::from_bytes(15), Size::from_bytes(5)) { } assert_eq!(map.v.len(), 5); assert_eq!( to_vec(&map, 10, 10), From ba8728cd8bbb9852d8884b7444a8b049a432dcd1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Jul 2019 09:33:22 +0200 Subject: [PATCH 0909/5092] fix test using mem::uninitialized --- tests/run-pass/move-undef-primval.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/run-pass/move-undef-primval.rs b/tests/run-pass/move-undef-primval.rs index 73c33943a63a..b8bd869b48c9 100644 --- a/tests/run-pass/move-undef-primval.rs +++ b/tests/run-pass/move-undef-primval.rs @@ -1,3 +1,5 @@ +#![allow(deprecated)] + struct Foo { _inner: i32, } From fa290f1a481b0f98ed1de06206e643af8e04acd5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Jul 2019 18:44:58 +0200 Subject: [PATCH 0910/5092] uninit intrinsic is gone --- src/shims/intrinsics.rs | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 3f9c4e53f09d..d62e92169590 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -481,36 +481,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } - "uninit" => { - // Check fast path: we don't want to force an allocation in case the destination is a simple value, - // but we also do not want to create a new allocation with 0s and then copy that over. - // FIXME: We do not properly validate in case of ZSTs and when doing it in memory! - // However, this only affects direct calls of the intrinsic; calls to the stable - // functions wrapping them do get their validation. - // FIXME: should we check alignment for ZSTs? - if !dest.layout.is_zst() { - match dest.layout.abi { - layout::Abi::Scalar(..) => { - let x = ScalarMaybeUndef::Undef; - this.write_immediate(Immediate::Scalar(x), dest)?; - } - layout::Abi::ScalarPair(..) => { - let x = ScalarMaybeUndef::Undef; - this.write_immediate(Immediate::ScalarPair(x, x), dest)?; - } - _ => { - // Do it in memory - let mplace = this.force_allocation(dest)?; - assert!(mplace.meta.is_none()); - let ptr = mplace.ptr.to_ptr()?; - this.memory_mut() - .get_mut(ptr.alloc_id)? - .mark_definedness(ptr, dest.layout.size, false); - } - } - } - } - "write_bytes" => { let ty = substs.type_at(0); let ty_layout = this.layout_of(ty)?; From 2ca1b94e6d7e1a078b7fcef9a10e2ed07145e1bd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 16:03:13 +0200 Subject: [PATCH 0911/5092] update to FnVal changes; implement basic Dlsym support and use it for getentropy --- src/eval.rs | 4 +- src/lib.rs | 1 + src/machine.rs | 13 +++++- src/shims/dlsym.rs | 49 ++++++++++++++++++++++ src/shims/foreign_items.rs | 85 ++++++++++++++++++++------------------ src/shims/mod.rs | 1 + 6 files changed, 110 insertions(+), 43 deletions(-) create mode 100644 src/shims/dlsym.rs diff --git a/src/eval.rs b/src/eval.rs index 6132c502531f..bf99d3e61166 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -11,7 +11,7 @@ use rustc::mir; use crate::{ InterpResult, InterpError, InterpCx, StackPopCleanup, struct_error, - Scalar, Tag, Pointer, + Scalar, Tag, Pointer, FnVal, MemoryExtra, MiriMemoryKind, Evaluator, TlsEvalContextExt, }; @@ -93,7 +93,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let mut args = ecx.frame().body.args_iter(); // First argument: pointer to `main()`. - let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance); + let main_ptr = ecx.memory_mut().create_fn_alloc(FnVal::Instance(main_instance)); let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?; diff --git a/src/lib.rs b/src/lib.rs index 31e707077769..295c8e519e13 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,6 +31,7 @@ pub use crate::shims::{EvalContextExt as ShimsEvalContextExt}; pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextExt; pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; +pub use crate::shims::dlsym::{Dlsym, EvalContextExt as DlsymEvalContextExt}; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; diff --git a/src/machine.rs b/src/machine.rs index 0875331131bd..77e02dba266a 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -135,6 +135,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryExtra = MemoryExtra; type AllocExtra = AllocExtra; type PointerTag = Tag; + type ExtraFnVal = Dlsym; type MemoryMap = MonoHashMap, Allocation)>; @@ -145,7 +146,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx.memory().extra.validate } - /// Returns `Ok()` when the function was handled; fail otherwise. #[inline(always)] fn find_fn( ecx: &mut InterpCx<'mir, 'tcx, Self>, @@ -157,6 +157,17 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx.find_fn(instance, args, dest, ret) } + #[inline(always)] + fn call_extra_fn( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + fn_val: Dlsym, + args: &[OpTy<'tcx, Tag>], + dest: Option>, + ret: Option, + ) -> InterpResult<'tcx> { + ecx.call_dlsym(fn_val, args, dest, ret) + } + #[inline(always)] fn call_intrinsic( ecx: &mut rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>, diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs new file mode 100644 index 000000000000..1c2567b951ca --- /dev/null +++ b/src/shims/dlsym.rs @@ -0,0 +1,49 @@ +use rustc::mir; + +use crate::*; + +#[derive(Debug, Copy, Clone)] +pub enum Dlsym { + GetEntropy, +} + +impl Dlsym { + pub fn from_str(name: &str) -> Option { + use self::Dlsym::*; + Some(match name { + "getentropy" => GetEntropy, + _ => return None, + }) + } +} + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn call_dlsym( + &mut self, + dlsym: Dlsym, + args: &[OpTy<'tcx, Tag>], + dest: Option>, + ret: Option, + ) -> InterpResult<'tcx> { + use self::Dlsym::*; + + let this = self.eval_context_mut(); + + let dest = dest.expect("we don't support any diverging dlsym"); + let ret = ret.expect("dest is `Some` but ret is `None`"); + + match dlsym { + GetEntropy => { + let ptr = this.read_scalar(args[0])?.not_undef()?; + let len = this.read_scalar(args[1])?.to_usize(this)?; + this.gen_random(len as usize, ptr)?; + this.write_null(dest)?; + } + } + + this.goto_block(Some(ret))?; + this.dump_place(*dest); + Ok(()) + } +} diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 2fe2ecc19581..fb1d08d0bc20 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -307,7 +307,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // neither of which have any effect on our current PRNG let _flags = this.read_scalar(args[3])?.to_i32()?; - gen_random(this, len as usize, ptr)?; + this.gen_random(len as usize, ptr)?; this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; } id => { @@ -324,10 +324,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let symbol_name = this.memory().get(symbol.alloc_id)?.read_c_str(tcx, symbol)?; let err = format!("bad c unicode symbol: {:?}", symbol_name); let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err); - return err!(Unimplemented(format!( - "miri does not support dynamically loading libraries (requested symbol: {})", - symbol_name - ))); + if let Some(dlsym) = Dlsym::from_str(symbol_name) { + let ptr = this.memory_mut().create_fn_alloc(FnVal::Other(dlsym)); + this.write_scalar(Scalar::from(ptr), dest)?; + } else { + return err!(Unimplemented(format!( + "Unsupported dlsym: {}", symbol_name + ))); + } } "__rust_maybe_catch_panic" => { @@ -340,7 +344,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We abort on panic, so not much is going on here, but we still have to call the closure. let f = this.read_scalar(args[0])?.to_ptr()?; let data = this.read_scalar(args[1])?.not_undef()?; - let f_instance = this.memory().get_fn(f)?; + let f_instance = this.memory().get_fn(f)?.as_instance()?; this.write_null(dest)?; trace!("__rust_maybe_catch_panic: {:?}", f_instance); @@ -659,7 +663,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Extract the function type out of the signature (that seems easier than constructing it ourselves). let dtor = match this.test_null(this.read_scalar(args[1])?.not_undef()?)? { - Some(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr.to_ptr()?)?), + Some(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr)?.as_instance()?), None => None, }; @@ -766,7 +770,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "SecRandomCopyBytes" => { let len = this.read_scalar(args[1])?.to_usize(this)?; let ptr = this.read_scalar(args[2])?.not_undef()?; - gen_random(this, len as usize, ptr)?; + this.gen_random(len as usize, ptr)?; this.write_null(dest)?; } @@ -934,7 +938,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "SystemFunction036" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let len = this.read_scalar(args[1])?.to_u32()?; - gen_random(this, len as usize, ptr)?; + this.gen_random(len as usize, ptr)?; this.write_scalar(Scalar::from_bool(true), dest)?; } @@ -966,36 +970,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } return Ok(None); } -} -fn gen_random<'mir, 'tcx>( - this: &mut MiriEvalContext<'mir, 'tcx>, - len: usize, - dest: Scalar, -) -> InterpResult<'tcx> { - if len == 0 { - // Nothing to do - return Ok(()); + fn gen_random( + &mut self, + len: usize, + dest: Scalar, + ) -> InterpResult<'tcx> { + if len == 0 { + // Nothing to do + return Ok(()); + } + let this = self.eval_context_mut(); + let ptr = dest.to_ptr()?; + + let data = match &mut this.memory_mut().extra.rng { + Some(rng) => { + let mut rng = rng.borrow_mut(); + let mut data = vec![0; len]; + rng.fill_bytes(&mut data); + data + } + None => { + return err!(Unimplemented( + "miri does not support gathering system entropy in deterministic mode! + Use '-Zmiri-seed=' to enable random number generation. + WARNING: Miri does *not* generate cryptographically secure entropy - + do not use Miri to run any program that needs secure random number generation".to_owned(), + )); + } + }; + let tcx = &{this.tcx.tcx}; + this.memory_mut().get_mut(ptr.alloc_id)? + .write_bytes(tcx, ptr, &data) } - let ptr = dest.to_ptr()?; - - let data = match &mut this.memory_mut().extra.rng { - Some(rng) => { - let mut rng = rng.borrow_mut(); - let mut data = vec![0; len]; - rng.fill_bytes(&mut data); - data - } - None => { - return err!(Unimplemented( - "miri does not support gathering system entropy in deterministic mode! - Use '-Zmiri-seed=' to enable random number generation. - WARNING: Miri does *not* generate cryptographically secure entropy - - do not use Miri to run any program that needs secure random number generation".to_owned(), - )); - } - }; - let tcx = &{this.tcx.tcx}; - this.memory_mut().get_mut(ptr.alloc_id)? - .write_bytes(tcx, ptr, &data) -} +} \ No newline at end of file diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 3258cf3d9c1d..c06373005ff9 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -1,6 +1,7 @@ pub mod foreign_items; pub mod intrinsics; pub mod tls; +pub mod dlsym; use rustc::{ty, mir}; From 4f6a56f54fabf86f530527dadce624854ee4c39b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 16:43:05 +0200 Subject: [PATCH 0912/5092] better error message when the program tries to spawn a thread --- src/lib.rs | 2 +- src/machine.rs | 3 +- src/shims/dlsym.rs | 16 ++++++---- src/shims/foreign_items.rs | 48 ++++++++++++++++++++---------- tests/compile-fail/thread-spawn.rs | 7 +++++ 5 files changed, 53 insertions(+), 23 deletions(-) create mode 100644 tests/compile-fail/thread-spawn.rs diff --git a/src/lib.rs b/src/lib.rs index 295c8e519e13..20c24ad54fe8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,7 +38,7 @@ pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; pub use crate::mono_hash_map::MonoHashMap; pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt, Tag, Permission, Stack, Stacks, Item}; pub use crate::machine::{ - PAGE_SIZE, STACK_ADDR, NUM_CPUS, + PAGE_SIZE, STACK_ADDR, STACK_SIZE, NUM_CPUS, MemoryExtra, AllocExtra, MiriMemoryKind, Evaluator, MiriEvalContext, MiriEvalContextExt, }; pub use crate::eval::{eval_main, create_ecx, MiriConfig}; diff --git a/src/machine.rs b/src/machine.rs index 77e02dba266a..58c1cb51ca52 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -18,7 +18,8 @@ use crate::*; // Some global facts about the emulated machine. pub const PAGE_SIZE: u64 = 4*1024; // FIXME: adjust to target architecture -pub const STACK_ADDR: u64 = 16*PAGE_SIZE; // not really about the "stack", but where we start assigning integer addresses to allocations +pub const STACK_ADDR: u64 = 32*PAGE_SIZE; // not really about the "stack", but where we start assigning integer addresses to allocations +pub const STACK_SIZE: u64 = 16*PAGE_SIZE; // whatever pub const NUM_CPUS: u64 = 1; /// Extra memory kinds diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 1c2567b951ca..602d8064e82e 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -8,11 +8,17 @@ pub enum Dlsym { } impl Dlsym { - pub fn from_str(name: &str) -> Option { + // Returns an error for unsupported symbols, and None if this symbol + // should become a NULL pointer (pretend it does not exist). + pub fn from_str(name: &str) -> InterpResult<'static, Option> { use self::Dlsym::*; - Some(match name { - "getentropy" => GetEntropy, - _ => return None, + Ok(match name { + "getentropy" => Some(GetEntropy), + "__pthread_get_minstack" => None, + _ => + return err!(Unimplemented(format!( + "Unsupported dlsym: {}", name + ))), }) } } @@ -32,7 +38,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dest = dest.expect("we don't support any diverging dlsym"); let ret = ret.expect("dest is `Some` but ret is `None`"); - + match dlsym { GetEntropy => { let ptr = this.read_scalar(args[0])?.not_undef()?; diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index fb1d08d0bc20..e31a34a60158 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -324,13 +324,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let symbol_name = this.memory().get(symbol.alloc_id)?.read_c_str(tcx, symbol)?; let err = format!("bad c unicode symbol: {:?}", symbol_name); let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err); - if let Some(dlsym) = Dlsym::from_str(symbol_name) { + if let Some(dlsym) = Dlsym::from_str(symbol_name)? { let ptr = this.memory_mut().create_fn_alloc(FnVal::Other(dlsym)); this.write_scalar(Scalar::from(ptr), dest)?; } else { - return err!(Unimplemented(format!( - "Unsupported dlsym: {}", symbol_name - ))); + this.write_null(dest)?; } } @@ -713,24 +711,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - // Determine stack base address. - "pthread_attr_init" | "pthread_attr_destroy" | "pthread_attr_get_np" | - "pthread_getattr_np" | "pthread_self" | "pthread_get_stacksize_np" => { + // Stack size/address stuff. + "pthread_attr_init" | "pthread_attr_destroy" | "pthread_self" | + "pthread_attr_setstacksize" => { this.write_null(dest)?; } "pthread_attr_getstack" => { - // Second argument is where we are supposed to write the stack size. - let ptr = this.deref_operand(args[1])?; - // Just any address. - let stack_addr = Scalar::from_uint(STACK_ADDR, args[1].layout.size); - this.write_scalar(stack_addr, ptr.into())?; + let addr_place = this.deref_operand(args[1])?; + let size_place = this.deref_operand(args[2])?; + + this.write_scalar( + Scalar::from_uint(STACK_ADDR, addr_place.layout.size), + addr_place.into(), + )?; + this.write_scalar( + Scalar::from_uint(STACK_SIZE, size_place.layout.size), + size_place.into(), + )?; + // Return success (`0`). this.write_null(dest)?; } - "pthread_get_stackaddr_np" => { - // Just any address. - let stack_addr = Scalar::from_uint(STACK_ADDR, dest.layout.size); - this.write_scalar(stack_addr, dest)?; + + // We don't support threading. + "pthread_create" => { + return err!(Unimplemented(format!("Miri does not support threading"))); } // Stub out calls for condvar, mutex and rwlock, to just return `0`. @@ -758,6 +763,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // macOS API stubs. + "pthread_attr_get_np" | "pthread_getattr_np" => { + this.write_null(dest)?; + } + "pthread_get_stackaddr_np" => { + let stack_addr = Scalar::from_uint(STACK_ADDR, dest.layout.size); + this.write_scalar(stack_addr, dest)?; + } + "pthread_get_stacksize_np" => { + let stack_size = Scalar::from_uint(STACK_SIZE, dest.layout.size); + this.write_scalar(stack_size, dest)?; + } "_tlv_atexit" => { // FIXME: register the destructor. }, diff --git a/tests/compile-fail/thread-spawn.rs b/tests/compile-fail/thread-spawn.rs new file mode 100644 index 000000000000..450dea99f552 --- /dev/null +++ b/tests/compile-fail/thread-spawn.rs @@ -0,0 +1,7 @@ +use std::thread; + +// error-pattern: Miri does not support threading + +fn main() { + thread::spawn(|| {}); +} From b3c3c33ebf1f2e340e992c2f23ceaa39fc4bb365 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 16:52:12 +0200 Subject: [PATCH 0913/5092] bump the version of getrandom that we test --- test-cargo-miri/Cargo.lock | 58 ++++++++------------------------------ 1 file changed, 11 insertions(+), 47 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 8343832886a6..55e5a3dfc185 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -5,11 +5,6 @@ name = "autocfg" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "bitflags" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "byteorder" version = "1.3.2" @@ -33,34 +28,22 @@ dependencies = [ "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "getrandom" -version = "0.1.3" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lazy_static" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "libc" @@ -85,7 +68,7 @@ name = "rand" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -108,7 +91,7 @@ name = "rand_core" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -129,32 +112,15 @@ dependencies = [ ] [[package]] -name = "winapi" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "spin" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" -"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8d1dffef07351aafe6ef177e4dd2b8dcf503e6bc765dea3b0de9ed149a3db1ec" +"checksum getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e65cce4e5084b14874c4e7097f38cab54f47ee554f9194673456ea379dcc4c55" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319" "checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" @@ -164,6 +130,4 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum rand_pcg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e196346cbbc5c70c77e7b4926147ee8e383a38ee4d15d58a08098b169e492b6" -"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" From 8093a59ffb0318ab315a6386cfe76e6a595a313e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 23:28:24 +0200 Subject: [PATCH 0914/5092] move gen_random to helpers --- src/helpers.rs | 36 ++++++++++++++++++++++++++++++++++++ src/shims/foreign_items.rs | 35 ----------------------------------- 2 files changed, 36 insertions(+), 35 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 3503af43690f..b2be90ca999e 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -3,6 +3,8 @@ use std::mem; use rustc::ty::{self, layout::{self, Size}}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; +use rand::RngCore; + use crate::*; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -65,6 +67,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) } + /// Generate some random bytes, and write them to `dest`. + fn gen_random( + &mut self, + len: usize, + dest: Scalar, + ) -> InterpResult<'tcx> { + if len == 0 { + // Nothing to do + return Ok(()); + } + let this = self.eval_context_mut(); + let ptr = dest.to_ptr()?; + + let data = match &mut this.memory_mut().extra.rng { + Some(rng) => { + let mut rng = rng.borrow_mut(); + let mut data = vec![0; len]; + rng.fill_bytes(&mut data); + data + } + None => { + return err!(Unimplemented( + "miri does not support gathering system entropy in deterministic mode! + Use '-Zmiri-seed=' to enable random number generation. + WARNING: Miri does *not* generate cryptographically secure entropy - + do not use Miri to run any program that needs secure random number generation".to_owned(), + )); + } + }; + let tcx = &{this.tcx.tcx}; + this.memory_mut().get_mut(ptr.alloc_id)? + .write_bytes(tcx, ptr, &data) + } + /// Visits the memory covered by `place`, sensitive to freezing: the 3rd parameter /// will be true if this is frozen, false if this is in an `UnsafeCell`. fn visit_freeze_sensitive( diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index e31a34a60158..7ab97c87e305 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -4,8 +4,6 @@ use rustc::mir; use syntax::attr; use syntax::symbol::sym; -use rand::RngCore; - use crate::*; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -986,37 +984,4 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } return Ok(None); } - - fn gen_random( - &mut self, - len: usize, - dest: Scalar, - ) -> InterpResult<'tcx> { - if len == 0 { - // Nothing to do - return Ok(()); - } - let this = self.eval_context_mut(); - let ptr = dest.to_ptr()?; - - let data = match &mut this.memory_mut().extra.rng { - Some(rng) => { - let mut rng = rng.borrow_mut(); - let mut data = vec![0; len]; - rng.fill_bytes(&mut data); - data - } - None => { - return err!(Unimplemented( - "miri does not support gathering system entropy in deterministic mode! - Use '-Zmiri-seed=' to enable random number generation. - WARNING: Miri does *not* generate cryptographically secure entropy - - do not use Miri to run any program that needs secure random number generation".to_owned(), - )); - } - }; - let tcx = &{this.tcx.tcx}; - this.memory_mut().get_mut(ptr.alloc_id)? - .write_bytes(tcx, ptr, &data) - } } \ No newline at end of file From 3ca934f07d2f0fcf7f5aec5f5493cdbd3dfa7480 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 23:32:25 +0200 Subject: [PATCH 0915/5092] gen_random: use check_ptr_access --- src/helpers.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index b2be90ca999e..b9fa7bc2a77a 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,6 +1,6 @@ use std::mem; -use rustc::ty::{self, layout::{self, Size}}; +use rustc::ty::{self, layout::{self, Size, Align}}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rand::RngCore; @@ -71,14 +71,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn gen_random( &mut self, len: usize, - dest: Scalar, + ptr: Scalar, ) -> InterpResult<'tcx> { - if len == 0 { - // Nothing to do - return Ok(()); - } let this = self.eval_context_mut(); - let ptr = dest.to_ptr()?; + + let ptr = match this.memory().check_ptr_access(ptr, Size::from_bytes(len as u64), Align::from_bytes(1).unwrap())? { + Some(ptr) => ptr, + None => return Ok(()), // zero-sized access + }; let data = match &mut this.memory_mut().extra.rng { Some(rng) => { From 4fa243be78e4be2ca8d5e79fea26fe87deb720ae Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 1 Jul 2019 23:07:40 +0200 Subject: [PATCH 0916/5092] adjust for get_fn signature change --- src/shims/foreign_items.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 7ab97c87e305..9dbb55668ef3 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -338,7 +338,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // vtable_ptr: *mut usize, // ) -> u32 // We abort on panic, so not much is going on here, but we still have to call the closure. - let f = this.read_scalar(args[0])?.to_ptr()?; + let f = this.read_scalar(args[0])?.not_undef()?; let data = this.read_scalar(args[1])?.not_undef()?; let f_instance = this.memory().get_fn(f)?.as_instance()?; this.write_null(dest)?; From 9e130c6c6f46532af4d210ba5e58322cd5c5cd3d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Jul 2019 09:51:20 +0200 Subject: [PATCH 0917/5092] fix for changd machine trait signatures --- src/machine.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 58c1cb51ca52..d1cf913a75bf 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -11,7 +11,7 @@ use rand::rngs::StdRng; use syntax::attr; use syntax::symbol::sym; use rustc::hir::def_id::DefId; -use rustc::ty::{self, layout::{Size, LayoutOf}, query::TyCtxtAt}; +use rustc::ty::{self, layout::{Size, LayoutOf}, TyCtxt}; use rustc::mir; use crate::*; @@ -232,8 +232,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } fn find_foreign_static( + tcx: TyCtxt<'tcx>, def_id: DefId, - tcx: TyCtxtAt<'tcx>, ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { @@ -263,20 +263,20 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } fn tag_allocation<'b>( + memory_extra: &MemoryExtra, id: AllocId, alloc: Cow<'b, Allocation>, kind: Option>, - memory: &Memory<'mir, 'tcx, Self>, ) -> (Cow<'b, Allocation>, Self::PointerTag) { let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); - let (stacks, base_tag) = if !memory.extra.validate { + let (stacks, base_tag) = if !memory_extra.validate { (None, Tag::Untagged) } else { let (stacks, base_tag) = Stacks::new_allocation( id, Size::from_bytes(alloc.bytes.len() as u64), - Rc::clone(&memory.extra.stacked_borrows), + Rc::clone(&memory_extra.stacked_borrows), kind, ); (Some(stacks), base_tag) @@ -285,7 +285,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { assert!(alloc.relocations.is_empty(), "Only statics can come initialized with inner pointers"); // Now we can rely on the inner pointers being static, too. } - let mut memory_extra = memory.extra.stacked_borrows.borrow_mut(); + let mut stacked_borrows = memory_extra.stacked_borrows.borrow_mut(); let alloc: Allocation = Allocation { bytes: alloc.bytes, relocations: Relocations::from_presorted( @@ -293,10 +293,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { // The allocations in the relocations (pointers stored *inside* this allocation) // all get the base pointer tag. .map(|&(offset, ((), alloc))| { - let tag = if !memory.extra.validate { + let tag = if !memory_extra.validate { Tag::Untagged } else { - memory_extra.static_base_ptr(alloc) + stacked_borrows.static_base_ptr(alloc) }; (offset, (tag, alloc)) }) @@ -314,13 +314,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn tag_static_base_pointer( + memory_extra: &MemoryExtra, id: AllocId, - memory: &Memory<'mir, 'tcx, Self>, ) -> Self::PointerTag { - if !memory.extra.validate { + if !memory_extra.validate { Tag::Untagged } else { - memory.extra.stacked_borrows.borrow_mut().static_base_ptr(id) + memory_extra.stacked_borrows.borrow_mut().static_base_ptr(id) } } @@ -354,8 +354,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } fn int_to_ptr( - int: u64, memory: &Memory<'mir, 'tcx, Self>, + int: u64, ) -> InterpResult<'tcx, Pointer> { if int == 0 { err!(InvalidNullPointerUsage) @@ -367,8 +367,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } fn ptr_to_int( - ptr: Pointer, memory: &Memory<'mir, 'tcx, Self>, + ptr: Pointer, ) -> InterpResult<'tcx, u64> { if memory.extra.rng.is_none() { err!(ReadPointerAsBytes) From fbf3f5e0c97f1cf6fffeabb824327ab8cc9030d6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Jul 2019 09:52:28 +0200 Subject: [PATCH 0918/5092] bump rustc --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index e278a8063370..e70f05a0090d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -481068a707679257e2a738b40987246e0420e787 +b820c761744db080ff7a4ba3ac88d259065cb836 From 47bfc62b5be28d1861a15099787be20f83163dbc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Jul 2019 08:37:19 +0200 Subject: [PATCH 0919/5092] use Memory::read_c_str, avoid a few to_ptr --- src/shims/foreign_items.rs | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 9dbb55668ef3..41966c5f0d9c 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -318,8 +318,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "dlsym" => { let _handle = this.read_scalar(args[0])?; - let symbol = this.read_scalar(args[1])?.to_ptr()?; - let symbol_name = this.memory().get(symbol.alloc_id)?.read_c_str(tcx, symbol)?; + let symbol = this.read_scalar(args[1])?.not_undef()?; + let symbol_name = this.memory().read_c_str(symbol)?; let err = format!("bad c unicode symbol: {:?}", symbol_name); let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err); if let Some(dlsym) = Dlsym::from_str(symbol_name)? { @@ -433,8 +433,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "getenv" => { let result = { - let name_ptr = this.read_scalar(args[0])?.to_ptr()?; - let name = this.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?; + let name_ptr = this.read_scalar(args[0])?.not_undef()?; + let name = this.memory().read_c_str(name_ptr)?; match this.machine.env_vars.get(name) { Some(&var) => Scalar::Ptr(var), None => Scalar::ptr_null(&*this.tcx), @@ -448,12 +448,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx { let name_ptr = this.read_scalar(args[0])?.not_undef()?; if !this.is_null(name_ptr)? { - let name_ptr = name_ptr.to_ptr()?; - let name = this - .memory() - .get(name_ptr.alloc_id)? - .read_c_str(tcx, name_ptr)? - .to_owned(); + let name = this.memory().read_c_str(name_ptr)?.to_owned(); if !name.is_empty() && !name.contains(&b'=') { success = Some(this.machine.env_vars.remove(&name)); } @@ -473,11 +468,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut new = None; { let name_ptr = this.read_scalar(args[0])?.not_undef()?; - let value_ptr = this.read_scalar(args[1])?.to_ptr()?; - let value = this.memory().get(value_ptr.alloc_id)?.read_c_str(tcx, value_ptr)?; + let value_ptr = this.read_scalar(args[1])?.not_undef()?; + let value = this.memory().read_c_str(value_ptr)?; if !this.is_null(name_ptr)? { - let name_ptr = name_ptr.to_ptr()?; - let name = this.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?; + let name = this.memory().read_c_str(name_ptr)?; if !name.is_empty() && !name.contains(&b'=') { new = Some((name.to_owned(), value.to_owned())); } @@ -552,8 +546,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "strlen" => { - let ptr = this.read_scalar(args[0])?.to_ptr()?; - let n = this.memory().get(ptr.alloc_id)?.read_c_str(tcx, ptr)?.len(); + let ptr = this.read_scalar(args[0])?.not_undef()?; + let n = this.memory().read_c_str(ptr)?.len(); this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; } From 8f114e87b8ceebd034540137e57912530239e61c Mon Sep 17 00:00:00 2001 From: lzutao Date: Sat, 6 Jul 2019 16:16:34 +0700 Subject: [PATCH 0920/5092] Remove stable cargo feature `default-run` At least on beta. --- .appveyor.yml | 7 ++++--- .travis.yml | 6 +++--- Cargo.toml | 2 -- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 4e8b8cd4b898..2cba0b55885e 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -19,12 +19,13 @@ cache: install: # Install Rust - curl -sSf -o rustup-init.exe https://win.rustup.rs/ - - rustup-init.exe -y --default-host %TARGET% --default-toolchain stable + - rustup-init.exe -y --default-host %TARGET% --default-toolchain beta - set PATH=%USERPROFILE%\.cargo\bin;%PATH% + - rustup update beta # Install "master" toolchain - cargo install rustup-toolchain-install-master & exit 0 - set /p RUSTC_HASH="] description = "An experimental interpreter for Rust MIR." From 96be92401e828d52756a58fbb0579fe27dc9e616 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sat, 6 Jul 2019 16:35:57 +0700 Subject: [PATCH 0921/5092] build: Revert update beta toolchain --- .appveyor.yml | 7 +++---- .travis.yml | 6 +++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 2cba0b55885e..4e8b8cd4b898 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -19,13 +19,12 @@ cache: install: # Install Rust - curl -sSf -o rustup-init.exe https://win.rustup.rs/ - - rustup-init.exe -y --default-host %TARGET% --default-toolchain beta + - rustup-init.exe -y --default-host %TARGET% --default-toolchain stable - set PATH=%USERPROFILE%\.cargo\bin;%PATH% - - rustup update beta # Install "master" toolchain - cargo install rustup-toolchain-install-master & exit 0 - set /p RUSTC_HASH= Date: Wed, 10 Jul 2019 09:55:04 +0700 Subject: [PATCH 0922/5092] Remove SliceConcatExt import --- src/shims/intrinsics.rs | 2 +- tests/compiletest.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index d62e92169590..54f826db1fa8 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -5,7 +5,7 @@ use rustc::ty::layout::{self, LayoutOf, Size}; use rustc::ty; use crate::{ - PlaceTy, OpTy, ImmTy, Immediate, Scalar, ScalarMaybeUndef, Tag, + PlaceTy, OpTy, ImmTy, Immediate, Scalar, Tag, OperatorEvalContextExt }; diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 076deca6a318..4d799cdb542d 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -1,8 +1,7 @@ -#![feature(slice_concat_ext, custom_test_frameworks)] +#![feature(custom_test_frameworks)] // Custom test runner, to avoid libtest being wrapped around compiletest which wraps libtest. #![test_runner(test_runner)] -use std::slice::SliceConcatExt; use std::path::PathBuf; use std::env; From e414a5ac0e25fdd36fde06c72d1aa9f2bf983c08 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 10 Jul 2019 09:31:31 +0200 Subject: [PATCH 0923/5092] bump rustc --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index e70f05a0090d..0a162e1928f4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -b820c761744db080ff7a4ba3ac88d259065cb836 +0b680cfce544ff9a59d720020e397c4bf3346650 From dd6cf30f6001339aa3d8fb1657521b772e06986a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Jul 2019 11:05:51 +0200 Subject: [PATCH 0924/5092] ptr_offset works fine with intptrcast now --- tests/{run-pass-noseed => run-pass}/ptr_offset.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/{run-pass-noseed => run-pass}/ptr_offset.rs (100%) diff --git a/tests/run-pass-noseed/ptr_offset.rs b/tests/run-pass/ptr_offset.rs similarity index 100% rename from tests/run-pass-noseed/ptr_offset.rs rename to tests/run-pass/ptr_offset.rs From f79f31dfa18c234a3cc12c1c77fd00b045b4cd1a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Jul 2019 13:14:06 +0200 Subject: [PATCH 0925/5092] adjust for rustc changes; normalize mplace before doing freeze-sensitive visit --- src/eval.rs | 2 +- src/helpers.rs | 25 +++++++++++-------------- src/shims/foreign_items.rs | 8 +------- src/shims/intrinsics.rs | 22 +++++++++++++--------- 4 files changed, 26 insertions(+), 31 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index bf99d3e61166..d40f4b3e59f6 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -136,7 +136,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let place = ecx.mplace_field(argvs_place, idx as u64)?; ecx.write_scalar(Scalar::Ptr(arg), place.into())?; } - ecx.memory_mut().mark_immutable(argvs_place.to_ptr()?.alloc_id)?; + ecx.memory_mut().mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?; // Write a pointer to that place as the argument. let argv = argvs_place.ptr; ecx.write_scalar(argv, dest)?; diff --git a/src/helpers.rs b/src/helpers.rs index b9fa7bc2a77a..fb4106e5db5c 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -116,36 +116,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .map(|(size, _)| size) .unwrap_or_else(|| place.layout.size) ); - assert!(size.bytes() > 0); + let place = this.normalize_mplace_ptr(place)?; // Store how far we proceeded into the place so far. Everything to the left of // this offset has already been handled, in the sense that the frozen parts // have had `action` called on them. - let mut end_ptr = place.ptr; + let mut end_ptr = place.ptr.assert_ptr(); // Called when we detected an `UnsafeCell` at the given offset and size. // Calls `action` and advances `end_ptr`. let mut unsafe_cell_action = |unsafe_cell_ptr: Scalar, unsafe_cell_size: Size| { - if unsafe_cell_size != Size::ZERO { - debug_assert_eq!(unsafe_cell_ptr.to_ptr().unwrap().alloc_id, - end_ptr.to_ptr().unwrap().alloc_id); - debug_assert_eq!(unsafe_cell_ptr.to_ptr().unwrap().tag, - end_ptr.to_ptr().unwrap().tag); - } + let unsafe_cell_ptr = unsafe_cell_ptr.assert_ptr(); + debug_assert_eq!(unsafe_cell_ptr.alloc_id, end_ptr.alloc_id); + debug_assert_eq!(unsafe_cell_ptr.tag, end_ptr.tag); // We assume that we are given the fields in increasing offset order, // and nothing else changes. - let unsafe_cell_offset = unsafe_cell_ptr.get_ptr_offset(this); - let end_offset = end_ptr.get_ptr_offset(this); + let unsafe_cell_offset = unsafe_cell_ptr.offset; + let end_offset = end_ptr.offset; assert!(unsafe_cell_offset >= end_offset); let frozen_size = unsafe_cell_offset - end_offset; // Everything between the end_ptr and this `UnsafeCell` is frozen. if frozen_size != Size::ZERO { - action(end_ptr.to_ptr()?, frozen_size, /*frozen*/true)?; + action(end_ptr, frozen_size, /*frozen*/true)?; } // This `UnsafeCell` is NOT frozen. if unsafe_cell_size != Size::ZERO { - action(unsafe_cell_ptr.to_ptr()?, unsafe_cell_size, /*frozen*/false)?; + action(unsafe_cell_ptr, unsafe_cell_size, /*frozen*/false)?; } // Update end end_ptr. - end_ptr = unsafe_cell_ptr.ptr_wrapping_offset(unsafe_cell_size, this); + end_ptr = unsafe_cell_ptr.wrapping_offset(unsafe_cell_size, this); // Done Ok(()) }; @@ -234,7 +231,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx layout::FieldPlacement::Arbitrary { .. } => { // Gather the subplaces and sort them before visiting. let mut places = fields.collect::>>>()?; - places.sort_by_key(|place| place.ptr.get_ptr_offset(self.ecx())); + places.sort_by_key(|place| place.ptr.assert_ptr().offset); self.walk_aggregate(place, places.into_iter().map(Ok)) } layout::FieldPlacement::Union { .. } => { diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 41966c5f0d9c..fd46eaea9dab 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -842,13 +842,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }, "GetSystemInfo" => { let system_info = this.deref_operand(args[0])?; - let (system_info_ptr, align) = system_info.to_scalar_ptr_align(); - let system_info_ptr = this.memory() - .check_ptr_access( - system_info_ptr, - system_info.layout.size, - align, - )? + let system_info_ptr = this.check_mplace_access(system_info, None)? .expect("cannot be a ZST"); // Initialize with `0`. this.memory_mut().get_mut(system_info_ptr.alloc_id)? diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 54f826db1fa8..6038950bad9f 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -166,17 +166,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let elem_size = elem_layout.size.bytes(); let count = this.read_scalar(args[2])?.to_usize(this)?; let elem_align = elem_layout.align.abi; - // erase tags: this is a raw ptr operation + + let size = Size::from_bytes(count * elem_size); let src = this.read_scalar(args[0])?.not_undef()?; + let src = this.memory().check_ptr_access(src, size, elem_align)?; let dest = this.read_scalar(args[1])?.not_undef()?; - this.memory_mut().copy( - src, - elem_align, - dest, - elem_align, - Size::from_bytes(count * elem_size), - intrinsic_name.ends_with("_nonoverlapping"), - )?; + let dest = this.memory().check_ptr_access(dest, size, elem_align)?; + + if let (Some(src), Some(dest)) = (src, dest) { + this.memory_mut().copy( + src, + dest, + size, + intrinsic_name.ends_with("_nonoverlapping"), + )?; + } } "discriminant_value" => { From a6f9bbc9e22be612849508552271e98bb0ae62bf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Jul 2019 13:16:54 +0200 Subject: [PATCH 0926/5092] now we can also enable the ptr_int_cast test again --- tests/{run-pass-noseed => run-pass}/ptr_int_casts.rs | 1 - tests/run-pass/ptr_offset.rs | 2 -- 2 files changed, 3 deletions(-) rename tests/{run-pass-noseed => run-pass}/ptr_int_casts.rs (94%) diff --git a/tests/run-pass-noseed/ptr_int_casts.rs b/tests/run-pass/ptr_int_casts.rs similarity index 94% rename from tests/run-pass-noseed/ptr_int_casts.rs rename to tests/run-pass/ptr_int_casts.rs index ebf65ac3fe24..c279024f35ea 100644 --- a/tests/run-pass-noseed/ptr_int_casts.rs +++ b/tests/run-pass/ptr_int_casts.rs @@ -1,4 +1,3 @@ -// FIXME move this to run-pass, it should work with intptrcast. use std::mem; use std::ptr; diff --git a/tests/run-pass/ptr_offset.rs b/tests/run-pass/ptr_offset.rs index a836e02812da..1c7f0eb71797 100644 --- a/tests/run-pass/ptr_offset.rs +++ b/tests/run-pass/ptr_offset.rs @@ -1,5 +1,3 @@ -// FIXME move this to run-pass, it should work with intptrcast. - fn f() -> i32 { 42 } fn main() { From 70a5bb7dbbba69d9e2e813693063f8c2b651f66f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Jul 2019 14:08:37 +0200 Subject: [PATCH 0927/5092] force pointers before reborrowing; fixes cargo miri test suite --- src/helpers.rs | 1 - src/stacked_borrows.rs | 1 + test-cargo-miri/run-test.py | 3 +-- tests/run-pass/{unique-send.rs => mpsc.rs} | 5 +++++ 4 files changed, 7 insertions(+), 3 deletions(-) rename tests/run-pass/{unique-send.rs => mpsc.rs} (57%) diff --git a/src/helpers.rs b/src/helpers.rs index fb4106e5db5c..351a6e7e54a6 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -116,7 +116,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .map(|(size, _)| size) .unwrap_or_else(|| place.layout.size) ); - let place = this.normalize_mplace_ptr(place)?; // Store how far we proceeded into the place so far. Everything to the left of // this offset has already been handled, in the sense that the frozen parts // have had `action` called on them. diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index acd1aec5b770..90656180150f 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -587,6 +587,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Nothing to do for ZSTs. return Ok(*val); } + let place = this.force_mplace_ptr(place)?; // Compute new borrow. let new_tag = match kind { diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index a9aba008e9a9..73515c74e401 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -52,9 +52,8 @@ def test_cargo_miri_run(): ) def test_cargo_miri_test(): - # FIXME: enable validation again, once that no longer conflicts with intptrcast test("cargo miri test", - cargo_miri("test") + ["--", "-Zmiri-seed=feed", "-Zmiri-disable-validation"], + cargo_miri("test") + ["--", "-Zmiri-seed=feed"], "test.stdout.ref", "test.stderr.ref" ) test("cargo miri test (with filter)", diff --git a/tests/run-pass/unique-send.rs b/tests/run-pass/mpsc.rs similarity index 57% rename from tests/run-pass/unique-send.rs rename to tests/run-pass/mpsc.rs index 04dbf495f8bf..6e3c6e771ccb 100644 --- a/tests/run-pass/unique-send.rs +++ b/tests/run-pass/mpsc.rs @@ -7,4 +7,9 @@ pub fn main() { tx.send(box 100).unwrap(); let v = rx.recv().unwrap(); assert_eq!(v, box 100); + + tx.send(box 101).unwrap(); + tx.send(box 102).unwrap(); + assert_eq!(rx.recv().unwrap(), box 101); + assert_eq!(rx.recv().unwrap(), box 102); } From 743299e7a04ee69ab00f8e92ff1c8dfec31ef1b8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 10 Jul 2019 14:37:52 +0200 Subject: [PATCH 0928/5092] bump rustc --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 0a162e1928f4..507fda7ac851 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0b680cfce544ff9a59d720020e397c4bf3346650 +d4e15655092d1bdae79619eb0ff2c3cb5468fc36 From 11686f4be23d4ee7a0490ab4d1fc593b46b1910a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 10 Jul 2019 14:38:49 +0200 Subject: [PATCH 0929/5092] we do this these days --- src/eval.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/eval.rs b/src/eval.rs index d40f4b3e59f6..dbc3282a306f 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -108,7 +108,6 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ecx.machine.argc = Some(argc_place.ptr.to_ptr()?); } - // FIXME: extract main source file path. // Third argument (`argv`): created from `config.args`. let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; // For Windows, construct a command string with all the aguments. From 7dd0dd35691e0528a6f46013e61c8da4c5013cf5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Jul 2019 17:13:28 +0200 Subject: [PATCH 0930/5092] bump rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 507fda7ac851..8650ea737fbe 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d4e15655092d1bdae79619eb0ff2c3cb5468fc36 +97b1128589fdaa786a7cf65c5a6ff7ed37a1d2f3 From e7b39e382a71882546528693ea8ed8125580fcde Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Jul 2019 18:41:53 +0200 Subject: [PATCH 0931/5092] reenable all tests on Windows --- src/eval.rs | 11 +---------- tests/compiletest.rs | 4 +--- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index dbc3282a306f..faa50f914916 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -31,20 +31,11 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( main_id: DefId, config: MiriConfig, ) -> InterpResult<'tcx, InterpCx<'mir, 'tcx, Evaluator<'tcx>>> { - - // FIXME(https://github.com/rust-lang/miri/pull/803): no validation on Windows. - let target_os = tcx.sess.target.target.target_os.to_lowercase(); - let validate = if target_os == "windows" { - false - } else { - config.validate - }; - let mut ecx = InterpCx::new( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), Evaluator::new(), - MemoryExtra::new(config.seed.map(StdRng::seed_from_u64), validate), + MemoryExtra::new(config.seed.map(StdRng::seed_from_u64), config.validate), ); let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 4d799cdb542d..302c080a52eb 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -111,9 +111,7 @@ fn run_pass_miri(opt: bool) { } fn compile_fail_miri(opt: bool) { - if !cfg!(windows) { // FIXME re-enable on Windows - compile_fail("tests/compile-fail", &get_target(), opt); - } + compile_fail("tests/compile-fail", &get_target(), opt); } fn test_runner(_tests: &[&()]) { From f8c6eb5e8c98d1ff623361d287c6e5af1943ba65 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Jul 2019 18:59:11 +0200 Subject: [PATCH 0932/5092] thread creation error for Windows --- src/shims/foreign_items.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index fd46eaea9dab..f7c6465a6363 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -725,8 +725,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - // We don't support threading. - "pthread_create" => { + // We don't support threading. (Also for Windows.) + "pthread_create" | "CreateThread" => { return err!(Unimplemented(format!("Miri does not support threading"))); } From f1b623c31353818f8bf0abbab48249a2168e60c0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 13 Jul 2019 10:23:40 +0200 Subject: [PATCH 0933/5092] test some const-generic-using methods --- tests/run-pass/arrays.rs | 17 +++++++++++++++++ tests/run-pass/arrays.stdout | 1 + 2 files changed, 18 insertions(+) create mode 100644 tests/run-pass/arrays.stdout diff --git a/tests/run-pass/arrays.rs b/tests/run-pass/arrays.rs index 469dde3091eb..d374ccf25354 100644 --- a/tests/run-pass/arrays.rs +++ b/tests/run-pass/arrays.rs @@ -33,6 +33,21 @@ fn slice_index() -> u8 { arr[5] } +fn eq() { + const N: usize = 16; + type Array = [u8; N]; + let array1: Array = [0; N]; + let array2: Array = [0; N]; + let array3: Array = [1; N]; + assert_eq!(array1, array2); + assert_ne!(array1, array3); +} + +fn debug() { + let array = [0u8, 42, 13, 71]; + println!("{:?}", array); +} + fn main() { assert_eq!(empty_array(), []); assert_eq!(index_unsafe(), 20); @@ -42,4 +57,6 @@ fn main() { assert_eq!(array_array(), [[5, 4], [3, 2], [1, 0]]); assert_eq!(array_repeat(), [42; 8]); assert_eq!(mini_array(), [42]); + eq(); + debug(); } diff --git a/tests/run-pass/arrays.stdout b/tests/run-pass/arrays.stdout new file mode 100644 index 000000000000..6c3cefadf803 --- /dev/null +++ b/tests/run-pass/arrays.stdout @@ -0,0 +1 @@ +[0, 42, 13, 71] From ebf65cbdab2f3d93e73f49cb0a8035d421b5c646 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 13 Jul 2019 08:28:33 -0400 Subject: [PATCH 0934/5092] Give a useful error message if user gives invalid random seed --- src/bin/miri.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 5a425baf0f61..0f28a0c5d8dc 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -17,6 +17,8 @@ extern crate syntax; use std::str::FromStr; use std::env; +use hex::FromHexError; + use rustc_interface::interface; use rustc::hir::def_id::LOCAL_CRATE; @@ -153,7 +155,14 @@ fn main() { if seed.is_some() { panic!("Cannot specify -Zmiri-seed multiple times!"); } - let seed_raw = hex::decode(arg.trim_start_matches("-Zmiri-seed=")).unwrap(); + let seed_raw = hex::decode(arg.trim_start_matches("-Zmiri-seed=")) + .unwrap_or_else(|err| match err { + FromHexError::InvalidHexCharacter { .. } => panic!( + "-Zmiri-seed should only contain valid hex digits [0-9a-fA-F]" + ), + FromHexError::OddLength => panic!("-Zmiri-seed should have an even number of digits"), + err => panic!("Unknown error decoding -Zmiri-seed as hex: {:?}", err), + }); if seed_raw.len() > 8 { panic!(format!("-Zmiri-seed must be at most 8 bytes, was {}", seed_raw.len())); } From a11d1f55ff14d7a1708f51e21771c8eb7bf44102 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 13 Jul 2019 15:18:15 +0200 Subject: [PATCH 0935/5092] avoid unnecessary allocation --- src/bin/miri.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 0f28a0c5d8dc..6e67246d2ca1 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -184,10 +184,10 @@ fn main() { // FIXME: Ideally we'd turn a bad build env into a compile-time error, but // CTFE does not seem powerful enough for that yet. if let Some(sysroot) = compile_time_sysroot() { - let sysroot_flag = "--sysroot".to_string(); - if !rustc_args.contains(&sysroot_flag) { + let sysroot_flag = "--sysroot"; + if !rustc_args.iter().any(|e| e == sysroot_flag) { // We need to overwrite the default that librustc would compute. - rustc_args.push(sysroot_flag); + rustc_args.push(sysroot_flag.to_owned()); rustc_args.push(sysroot); } } From 4cbd31220bf710ecc917941fa7d836cad8d6eef0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Jul 2019 09:34:08 +0200 Subject: [PATCH 0936/5092] update README about what we do not support --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 69c66db52147..9baaae568a29 100644 --- a/README.md +++ b/README.md @@ -38,8 +38,8 @@ cannot run all programs: * Miri runs the program as a platform-independent interpreter, so the program has no access to any platform-specific APIs or FFI. A few APIs have been implemented (such as printing to stdout) but most have not: for example, Miri - currently does not support concurrency, or networking, or file system access, - or gathering entropy from the system. + currently does not support concurrency, or SIMD, or networking, or file system + access. [rust]: https://www.rust-lang.org/ [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md From 95e6e671bf2993ec51b778a0531bf393c575a7e0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Jul 2019 18:39:18 +0200 Subject: [PATCH 0937/5092] fix compile-fail tests for latest rustc --- rust-version | 2 +- tests/compile-fail/validity/dangling_ref1.rs | 2 +- tests/compile-fail/validity/dangling_ref2.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 8650ea737fbe..570ef6376272 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -97b1128589fdaa786a7cf65c5a6ff7ed37a1d2f3 +d36b7f69448f7390fa9dfde75d58b914365acdab diff --git a/tests/compile-fail/validity/dangling_ref1.rs b/tests/compile-fail/validity/dangling_ref1.rs index 4318c7c90271..2c1984b7159c 100644 --- a/tests/compile-fail/validity/dangling_ref1.rs +++ b/tests/compile-fail/validity/dangling_ref1.rs @@ -1,5 +1,5 @@ use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR integer pointer in non-ZST reference + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR dangling reference (created from integer) } diff --git a/tests/compile-fail/validity/dangling_ref2.rs b/tests/compile-fail/validity/dangling_ref2.rs index ef76b93d11e2..0dc9c3a1826c 100644 --- a/tests/compile-fail/validity/dangling_ref2.rs +++ b/tests/compile-fail/validity/dangling_ref2.rs @@ -3,5 +3,5 @@ use std::mem; fn main() { let val = 14; let ptr = (&val as *const i32).wrapping_offset(1); - let _x: &i32 = unsafe { mem::transmute(ptr) }; //~ ERROR encountered dangling (not entirely in bounds) reference + let _x: &i32 = unsafe { mem::transmute(ptr) }; //~ ERROR dangling reference (not entirely in bounds) } From 66ca0f2cc214368c1b4364a4dc941ec95a7b2d03 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Jul 2019 17:36:25 +0200 Subject: [PATCH 0938/5092] fix for rustc_driver change --- benches/helpers/miri_helper.rs | 6 +++--- rust-version | 2 +- src/bin/miri.rs | 11 +++++------ 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 44a94cd61a0b..203a8b1133a5 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -8,6 +8,7 @@ extern crate test; use self::miri::eval_main; use rustc::hir::def_id::LOCAL_CRATE; use rustc_interface::interface; +use rustc_driver::Compilation; use crate::test::Bencher; struct MiriCompilerCalls<'a> { @@ -15,7 +16,7 @@ struct MiriCompilerCalls<'a> { } impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { - fn after_analysis(&mut self, compiler: &interface::Compiler) -> bool { + fn after_analysis(&mut self, compiler: &interface::Compiler) -> Compilation { compiler.session().abort_if_errors(); compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| { @@ -31,8 +32,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { compiler.session().abort_if_errors(); - // Don't continue execution - false + Compilation::Stop } } diff --git a/rust-version b/rust-version index 570ef6376272..9ee662c00cb3 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d36b7f69448f7390fa9dfde75d58b914365acdab +527dce7137f7a3c7bf47d9a503abf25f88ea22de diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 6e67246d2ca1..43cb19b2658e 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -21,24 +21,24 @@ use hex::FromHexError; use rustc_interface::interface; use rustc::hir::def_id::LOCAL_CRATE; +use rustc_driver::Compilation; struct MiriCompilerCalls { miri_config: miri::MiriConfig, } impl rustc_driver::Callbacks for MiriCompilerCalls { - fn after_parsing(&mut self, compiler: &interface::Compiler) -> bool { + fn after_parsing(&mut self, compiler: &interface::Compiler) -> Compilation { let attr = ( syntax::symbol::Symbol::intern("miri"), syntax::feature_gate::AttributeType::Whitelisted, ); compiler.session().plugin_attributes.borrow_mut().push(attr); - // Continue execution - true + Compilation::Continue } - fn after_analysis(&mut self, compiler: &interface::Compiler) -> bool { + fn after_analysis(&mut self, compiler: &interface::Compiler) -> Compilation { init_late_loggers(); compiler.session().abort_if_errors(); @@ -54,8 +54,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { compiler.session().abort_if_errors(); - // Don't continue execution - false + Compilation::Stop } } From 11d71195dd73f779cd020dd4811f1ed348f55988 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Jul 2019 18:03:55 +0200 Subject: [PATCH 0939/5092] fix miri-rustc-tests --- src/bin/miri-rustc-tests.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 9b0d02f4b7e2..dae5189937a3 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -19,6 +19,7 @@ use rustc_interface::interface; use rustc::hir::{self, itemlikevisit}; use rustc::ty::TyCtxt; use rustc::hir::def_id::LOCAL_CRATE; +use rustc_driver::Compilation; use miri::MiriConfig; @@ -28,18 +29,17 @@ struct MiriCompilerCalls { } impl rustc_driver::Callbacks for MiriCompilerCalls { - fn after_parsing(&mut self, compiler: &interface::Compiler) -> bool { + fn after_parsing(&mut self, compiler: &interface::Compiler) -> Compilation { let attr = ( syntax::symbol::Symbol::intern("miri"), syntax::feature_gate::AttributeType::Whitelisted, ); compiler.session().plugin_attributes.borrow_mut().push(attr); - // Continue execution - true + Compilation::Continue } - fn after_analysis(&mut self, compiler: &interface::Compiler) -> bool { + fn after_analysis(&mut self, compiler: &interface::Compiler) -> Compilation { compiler.session().abort_if_errors(); compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| { if std::env::args().any(|arg| arg == "--test") { @@ -71,7 +71,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { }); // Continue execution on host target - self.host_target + if self.host_target { Compilation::Continue } else { Compilation::Stop } } } From 59190e85429a18a88d8155eb0e3f8c1ff1d5a123 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 20 Jul 2019 22:38:41 +0200 Subject: [PATCH 0940/5092] disable some compile-fail tests for rustc --- .../copy_nonoverlapping.rs | 0 tests/{compile-fail => compile-fail-norustc}/copy_null.rs | 0 .../copy_unaligned.rs | 0 tests/compiletest.rs | 7 +++++++ 4 files changed, 7 insertions(+) rename tests/{compile-fail => compile-fail-norustc}/copy_nonoverlapping.rs (100%) rename tests/{compile-fail => compile-fail-norustc}/copy_null.rs (100%) rename tests/{compile-fail => compile-fail-norustc}/copy_unaligned.rs (100%) diff --git a/tests/compile-fail/copy_nonoverlapping.rs b/tests/compile-fail-norustc/copy_nonoverlapping.rs similarity index 100% rename from tests/compile-fail/copy_nonoverlapping.rs rename to tests/compile-fail-norustc/copy_nonoverlapping.rs diff --git a/tests/compile-fail/copy_null.rs b/tests/compile-fail-norustc/copy_null.rs similarity index 100% rename from tests/compile-fail/copy_null.rs rename to tests/compile-fail-norustc/copy_null.rs diff --git a/tests/compile-fail/copy_unaligned.rs b/tests/compile-fail-norustc/copy_unaligned.rs similarity index 100% rename from tests/compile-fail/copy_unaligned.rs rename to tests/compile-fail-norustc/copy_unaligned.rs diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 302c080a52eb..16311d0749b3 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -112,6 +112,13 @@ fn run_pass_miri(opt: bool) { fn compile_fail_miri(opt: bool) { compile_fail("tests/compile-fail", &get_target(), opt); + if rustc_test_suite().is_none() { + // FIXME: Some tests disabled in rustc test suite because + // they run with a debug-assertion libstd which changes the errors. + // We should build our own libstd for testing, see + // . + compile_fail("tests/compile-fail-norustc", &get_target(), opt); + } } fn test_runner(_tests: &[&()]) { From a2541aacd6b44ae2bd90cbaa0a0c4f4bcd4a62d1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Jul 2019 11:56:10 +0200 Subject: [PATCH 0941/5092] bump rust --- rust-version | 2 +- src/eval.rs | 9 ++++----- src/helpers.rs | 8 ++++++++ src/machine.rs | 4 ++-- src/shims/foreign_items.rs | 2 +- src/shims/tls.rs | 4 ++-- 6 files changed, 18 insertions(+), 11 deletions(-) diff --git a/rust-version b/rust-version index 9ee662c00cb3..b247139d09b3 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -527dce7137f7a3c7bf47d9a503abf25f88ea22de +1301422a6c2e8916560b8cc2f0564f38d8858a75 diff --git a/src/eval.rs b/src/eval.rs index faa50f914916..cde4da833e6c 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -7,12 +7,11 @@ use syntax::source_map::DUMMY_SP; use rustc::ty::{self, TyCtxt}; use rustc::ty::layout::{LayoutOf, Size, Align}; use rustc::hir::def_id::DefId; -use rustc::mir; use crate::{ InterpResult, InterpError, InterpCx, StackPopCleanup, struct_error, Scalar, Tag, Pointer, FnVal, - MemoryExtra, MiriMemoryKind, Evaluator, TlsEvalContextExt, + MemoryExtra, MiriMemoryKind, Evaluator, TlsEvalContextExt, HelpersEvalContextExt, }; /// Configuration needed to spawn a Miri instance. @@ -85,11 +84,11 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // First argument: pointer to `main()`. let main_ptr = ecx.memory_mut().create_fn_alloc(FnVal::Instance(main_instance)); - let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; + let dest = ecx.local_place(args.next().unwrap())?; ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?; // Second argument (argc): `1`. - let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; + let dest = ecx.local_place(args.next().unwrap())?; let argc = Scalar::from_uint(config.args.len() as u128, dest.layout.size); ecx.write_scalar(argc, dest)?; // Store argc for macOS's `_NSGetArgc`. @@ -100,7 +99,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } // Third argument (`argv`): created from `config.args`. - let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; + let dest = ecx.local_place(args.next().unwrap())?; // For Windows, construct a command string with all the aguments. let mut cmd = String::new(); for arg in config.args.iter() { diff --git a/src/helpers.rs b/src/helpers.rs index 351a6e7e54a6..19abbd6b8193 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -2,6 +2,7 @@ use std::mem; use rustc::ty::{self, layout::{self, Size, Align}}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; +use rustc::mir; use rand::RngCore; @@ -67,6 +68,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) } + /// Get the `Place` for a local + fn local_place(&mut self, local: mir::Local) -> InterpResult<'tcx, PlaceTy<'tcx, Tag>> { + let this = self.eval_context_mut(); + let place = mir::Place { base: mir::PlaceBase::Local(local), projection: None }; + this.eval_place(&place) + } + /// Generate some random bytes, and write them to `dest`. fn gen_random( &mut self, diff --git a/src/machine.rs b/src/machine.rs index d1cf913a75bf..c2e78024105d 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -214,12 +214,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { // First argument: `size`. // (`0` is allowed here -- this is expected to be handled by the lang item). - let arg = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; + let arg = ecx.local_place(args.next().unwrap())?; let size = layout.size.bytes(); ecx.write_scalar(Scalar::from_uint(size, arg.layout.size), arg)?; // Second argument: `align`. - let arg = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; + let arg = ecx.local_place(args.next().unwrap())?; let align = layout.align.abi.bytes(); ecx.write_scalar(Scalar::from_uint(align, arg.layout.size), arg)?; diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index f7c6465a6363..1deaf521ca66 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -365,7 +365,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .to_owned(), ), )?; - let arg_dest = this.eval_place(&mir::Place::Base(mir::PlaceBase::Local(arg_local)))?; + let arg_dest = this.local_place(arg_local)?; this.write_scalar(data, arg_dest)?; assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected"); diff --git a/src/shims/tls.rs b/src/shims/tls.rs index e2f2dab51805..abe6dd958693 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -3,7 +3,7 @@ use std::collections::BTreeMap; use rustc_target::abi::LayoutOf; -use rustc::{ty, ty::layout::HasDataLayout, mir}; +use rustc::{ty, ty::layout::HasDataLayout}; use crate::{ InterpResult, InterpError, StackPopCleanup, @@ -160,7 +160,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let arg_local = this.frame().body.args_iter().next().ok_or_else( || InterpError::AbiViolation("TLS dtor does not take enough arguments.".to_owned()), )?; - let dest = this.eval_place(&mir::Place::Base(mir::PlaceBase::Local(arg_local)))?; + let dest = this.local_place(arg_local)?; this.write_scalar(ptr, dest)?; // step until out of stackframes From 068517ae66a41052dea2c86c88fc10794304622d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Jul 2019 21:38:53 +0200 Subject: [PATCH 0942/5092] make sure we always have an RNG --- README.md | 8 ++-- src/eval.rs | 2 +- src/helpers.rs | 23 +++------- src/intptrcast.rs | 6 ++- src/machine.rs | 25 ++++------- src/operator.rs | 107 +++------------------------------------------- 6 files changed, 30 insertions(+), 141 deletions(-) diff --git a/README.md b/README.md index 9baaae568a29..fbd1f51c9e69 100644 --- a/README.md +++ b/README.md @@ -262,10 +262,10 @@ With this, you should now have a working development setup! See Several `-Z` flags are relevant for Miri: -* `-Zmiri-seed=` is a custom `-Z` flag added by Miri. It enables the - interpreted program to seed an RNG with system entropy. Miri will keep an RNG - on its own that is seeded with the given seed, and use that to generate the - "system entropy" that seeds the RNG(s) in the interpreted program. +* `-Zmiri-seed=` is a custom `-Z` flag added by Miri. It configures the + seed of the RNG that Miri uses to resolve non-determinism. This RNG is used + to pick base addresses for allocations, and when the interpreted program + requests system entropy. The default seed is 0. **NOTE**: This entropy is not good enough for cryptographic use! Do not generate secret keys in Miri or perform other kinds of cryptographic operations that rely on proper random numbers. diff --git a/src/eval.rs b/src/eval.rs index cde4da833e6c..83307c99f9c5 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -34,7 +34,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), Evaluator::new(), - MemoryExtra::new(config.seed.map(StdRng::seed_from_u64), config.validate), + MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate), ); let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); diff --git a/src/helpers.rs b/src/helpers.rs index 19abbd6b8193..3857020a71f8 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -88,25 +88,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx None => return Ok(()), // zero-sized access }; - let data = match &mut this.memory_mut().extra.rng { - Some(rng) => { - let mut rng = rng.borrow_mut(); - let mut data = vec![0; len]; - rng.fill_bytes(&mut data); - data - } - None => { - return err!(Unimplemented( - "miri does not support gathering system entropy in deterministic mode! - Use '-Zmiri-seed=' to enable random number generation. - WARNING: Miri does *not* generate cryptographically secure entropy - - do not use Miri to run any program that needs secure random number generation".to_owned(), - )); - } - }; + let rng = this.memory_mut().extra.rng.get_mut(); + let mut data = vec![0; len]; + rng.fill_bytes(&mut data); + let tcx = &{this.tcx.tcx}; - this.memory_mut().get_mut(ptr.alloc_id)? - .write_bytes(tcx, ptr, &data) + this.memory_mut().get_mut(ptr.alloc_id)?.write_bytes(tcx, ptr, &data) } /// Visits the memory covered by `place`, sensitive to freezing: the 3rd parameter diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 5797895c54f8..8fbf7ed76427 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -42,6 +42,10 @@ impl<'mir, 'tcx> GlobalState { int: u64, memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>, ) -> InterpResult<'tcx, Pointer> { + if int == 0 { + return err!(InvalidNullPointerUsage); + } + let global_state = memory.extra.intptrcast.borrow(); match global_state.int_to_ptr_map.binary_search_by_key(&int, |(addr, _)| *addr) { @@ -86,7 +90,7 @@ impl<'mir, 'tcx> GlobalState { // This allocation does not have a base address yet, pick one. // Leave some space to the previous allocation, to give it some chance to be less aligned. let slack = { - let mut rng = memory.extra.rng.as_ref().unwrap().borrow_mut(); + let mut rng = memory.extra.rng.borrow_mut(); // This means that `(global_state.next_base_addr + slack) % 16` is uniformly distributed. rng.gen_range(0, 16) }; diff --git a/src/machine.rs b/src/machine.rs index c2e78024105d..d50afec253e8 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -57,20 +57,19 @@ pub struct MemoryExtra { pub stacked_borrows: stacked_borrows::MemoryExtra, pub intptrcast: intptrcast::MemoryExtra, - /// The random number generator to use if Miri is running in non-deterministic mode and to - /// enable intptrcast - pub(crate) rng: Option>, + /// The random number generator used for resolving non-determinism. + pub(crate) rng: RefCell, /// Whether to enforce the validity invariant. pub(crate) validate: bool, } impl MemoryExtra { - pub fn new(rng: Option, validate: bool) -> Self { + pub fn new(rng: StdRng, validate: bool) -> Self { MemoryExtra { stacked_borrows: Default::default(), intptrcast: Default::default(), - rng: rng.map(RefCell::new), + rng: RefCell::new(rng), validate, } } @@ -353,28 +352,20 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { Ok(ecx.memory().extra.stacked_borrows.borrow_mut().end_call(extra)) } + #[inline(always)] fn int_to_ptr( memory: &Memory<'mir, 'tcx, Self>, int: u64, ) -> InterpResult<'tcx, Pointer> { - if int == 0 { - err!(InvalidNullPointerUsage) - } else if memory.extra.rng.is_none() { - err!(ReadBytesAsPointer) - } else { - intptrcast::GlobalState::int_to_ptr(int, memory) - } + intptrcast::GlobalState::int_to_ptr(int, memory) } + #[inline(always)] fn ptr_to_int( memory: &Memory<'mir, 'tcx, Self>, ptr: Pointer, ) -> InterpResult<'tcx, u64> { - if memory.extra.rng.is_none() { - err!(ReadPointerAsBytes) - } else { - intptrcast::GlobalState::ptr_to_int(ptr, memory) - } + intptrcast::GlobalState::ptr_to_int(ptr, memory) } } diff --git a/src/operator.rs b/src/operator.rs index df60acc661ed..5eeed5eac635 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -56,8 +56,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); - // If intptrcast is enabled, treat everything of integer *type* at integer *value*. - if self.memory().extra.rng.is_some() && left.layout.ty.is_integral() { + // Treat everything of integer *type* at integer *value*. + if left.layout.ty.is_integral() { // This is actually an integer operation, so dispatch back to the core engine. // TODO: Once intptrcast is the default, librustc_mir should never even call us // for integer types. @@ -188,104 +188,11 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { right: Scalar, ) -> InterpResult<'tcx, bool> { let size = self.pointer_size(); - if self.memory().extra.rng.is_some() { - // Just compare the integers. - // TODO: Do we really want to *always* do that, even when comparing two live in-bounds pointers? - let left = self.force_bits(left, size)?; - let right = self.force_bits(right, size)?; - return Ok(left == right); - } - Ok(match (left, right) { - (Scalar::Raw { .. }, Scalar::Raw { .. }) => - left.to_bits(size)? == right.to_bits(size)?, - (Scalar::Ptr(left), Scalar::Ptr(right)) => { - // Comparison illegal if one of them is out-of-bounds, *unless* they - // are in the same allocation. - if left.alloc_id == right.alloc_id { - left.offset == right.offset - } else { - // Make sure both pointers are in-bounds. - // This accepts one-past-the end. Thus, there is still technically - // some non-determinism that we do not fully rule out when two - // allocations sit right next to each other. The C/C++ standards are - // somewhat fuzzy about this case, so pragmatically speaking I think - // for now this check is "good enough". - // FIXME: Once we support intptrcast, we could try to fix these holes. - // Dead allocations in miri cannot overlap with live allocations, but - // on read hardware this can easily happen. Thus for comparisons we require - // both pointers to be live. - if self.pointer_inbounds(left).is_ok() && self.pointer_inbounds(right).is_ok() { - // Two in-bounds (and hence live) pointers in different allocations are different. - false - } else { - return err!(InvalidPointerMath); - } - } - } - // Comparing ptr and integer. - (Scalar::Ptr(ptr), Scalar::Raw { data, size }) | - (Scalar::Raw { data, size }, Scalar::Ptr(ptr)) => { - assert_eq!(size as u64, self.pointer_size().bytes()); - let bits = data as u64; - - // Case I: Comparing real pointers with "small" integers. - // Really we should only do this for NULL, but pragmatically speaking on non-bare-metal systems, - // an allocation will never be at the very bottom of the address space. - // Such comparisons can arise when comparing empty slices, which sometimes are "fake" - // integer pointers (okay because the slice is empty) and sometimes point into a - // real allocation. - // The most common source of such integer pointers is `NonNull::dangling()`, which - // equals the type's alignment. i128 might have an alignment of 16 bytes, but few types have - // alignment 32 or higher, hence the limit of 32. - // FIXME: Once we support intptrcast, we could try to fix these holes. - if bits < 32 { - // Test if the pointer can be different from NULL or not. - // We assume that pointers that are not NULL are also not "small". - if !self.memory().ptr_may_be_null(ptr) { - return Ok(false); - } - } - - let (alloc_size, alloc_align) = self.memory() - .get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead) - .expect("alloc info with MaybeDead cannot fail"); - - // Case II: Alignment gives it away - if ptr.offset.bytes() % alloc_align.bytes() == 0 { - // The offset maintains the allocation alignment, so we know `base+offset` - // is aligned by `alloc_align`. - // FIXME: We could be even more general, e.g., offset 2 into a 4-aligned - // allocation cannot equal 3. - if bits % alloc_align.bytes() != 0 { - // The integer is *not* aligned. So they cannot be equal. - return Ok(false); - } - } - // Case III: The integer is too big, and the allocation goes on a bit - // without wrapping around the address space. - { - // Compute the highest address at which this allocation could live. - // Substract one more, because it must be possible to add the size - // to the base address without overflowing; that is, the very last address - // of the address space is never dereferencable (but it can be in-bounds, i.e., - // one-past-the-end). - let max_base_addr = - ((1u128 << self.pointer_size().bits()) - - u128::from(alloc_size.bytes()) - - 1 - ) as u64; - if let Some(max_addr) = max_base_addr.checked_add(ptr.offset.bytes()) { - if bits > max_addr { - // The integer is too big, this cannot possibly be equal. - return Ok(false) - } - } - } - - // None of the supported cases. - return err!(InvalidPointerMath); - } - }) + // Just compare the integers. + // TODO: Do we really want to *always* do that, even when comparing two live in-bounds pointers? + let left = self.force_bits(left, size)?; + let right = self.force_bits(right, size)?; + Ok(left == right) } fn ptr_int_arithmetic( From c094d42504c41ebd4e452542f3fa2cbc303fc975 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Jul 2019 21:53:47 +0200 Subject: [PATCH 0943/5092] update miri-seed handling for run-pass test suite --- tests/compiletest.rs | 8 ++------ tests/{run-pass-noseed => run-pass}/hashmap.rs | 2 -- tests/{run-pass-noseed => run-pass}/heap_allocator.rs | 1 - tests/{run-pass-noseed => run-pass}/intptrcast.rs | 2 -- tests/{run-pass-noseed => run-pass}/malloc.rs | 1 - 5 files changed, 2 insertions(+), 12 deletions(-) rename tests/{run-pass-noseed => run-pass}/hashmap.rs (95%) rename tests/{run-pass-noseed => run-pass}/heap_allocator.rs (99%) rename tests/{run-pass-noseed => run-pass}/intptrcast.rs (94%) rename tests/{run-pass-noseed => run-pass}/malloc.rs (97%) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 16311d0749b3..9394084ad34d 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -68,7 +68,7 @@ fn compile_fail(path: &str, target: &str, opt: bool) { run_tests("compile-fail", path, target, flags); } -fn miri_pass(path: &str, target: &str, opt: bool, noseed: bool) { +fn miri_pass(path: &str, target: &str, opt: bool) { let opt_str = if opt { " with optimizations" } else { "" }; eprintln!("{}", format!( "## Running run-pass tests in {} against miri for target {}{}", @@ -80,9 +80,6 @@ fn miri_pass(path: &str, target: &str, opt: bool, noseed: bool) { let mut flags = Vec::new(); if opt { flags.push("-Zmir-opt-level=3".to_owned()); - } else if !noseed { - // Run with intptrcast. Avoid test matrix explosion by doing either this or opt-level=3. - flags.push("-Zmiri-seed=".to_owned()); } run_tests("ui", path, target, flags); @@ -106,8 +103,7 @@ fn get_target() -> String { } fn run_pass_miri(opt: bool) { - miri_pass("tests/run-pass", &get_target(), opt, false); - miri_pass("tests/run-pass-noseed", &get_target(), opt, true); + miri_pass("tests/run-pass", &get_target(), opt); } fn compile_fail_miri(opt: bool) { diff --git a/tests/run-pass-noseed/hashmap.rs b/tests/run-pass/hashmap.rs similarity index 95% rename from tests/run-pass-noseed/hashmap.rs rename to tests/run-pass/hashmap.rs index e249238d48cb..1ff9c26ba18c 100644 --- a/tests/run-pass-noseed/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -1,5 +1,3 @@ -// compile-flags: -Zmiri-seed=0000000000000000 - use std::collections::{self, HashMap}; use std::hash::{BuildHasherDefault, BuildHasher}; diff --git a/tests/run-pass-noseed/heap_allocator.rs b/tests/run-pass/heap_allocator.rs similarity index 99% rename from tests/run-pass-noseed/heap_allocator.rs rename to tests/run-pass/heap_allocator.rs index e7a609a7d98e..7bcb08058c36 100644 --- a/tests/run-pass-noseed/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -1,4 +1,3 @@ -// compile-flags: -Zmiri-seed= #![feature(allocator_api)] use std::ptr::NonNull; diff --git a/tests/run-pass-noseed/intptrcast.rs b/tests/run-pass/intptrcast.rs similarity index 94% rename from tests/run-pass-noseed/intptrcast.rs rename to tests/run-pass/intptrcast.rs index 1b5251c91119..c28958b872de 100644 --- a/tests/run-pass-noseed/intptrcast.rs +++ b/tests/run-pass/intptrcast.rs @@ -1,5 +1,3 @@ -// compile-flags: -Zmiri-seed=0000000000000000 - // This returns a miri pointer at type usize, if the argument is a proper pointer fn transmute_ptr_to_int(x: *const T) -> usize { unsafe { std::mem::transmute(x) } diff --git a/tests/run-pass-noseed/malloc.rs b/tests/run-pass/malloc.rs similarity index 97% rename from tests/run-pass-noseed/malloc.rs rename to tests/run-pass/malloc.rs index bf51baacd35a..f66263425ee8 100644 --- a/tests/run-pass-noseed/malloc.rs +++ b/tests/run-pass/malloc.rs @@ -1,5 +1,4 @@ //ignore-windows: Uses POSIX APIs -//compile-flags: -Zmiri-seed= #![feature(rustc_private)] From 3c1ab7819698b374d833e8818e39ef011a48eb83 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Jul 2019 23:25:06 +0200 Subject: [PATCH 0944/5092] review failing compile-fail tests --- tests/compile-fail/cast_box_int_to_fn_ptr.rs | 4 +- tests/compile-fail/cast_int_to_fn_ptr.rs | 2 +- tests/compile-fail/getrandom.rs | 13 ---- ...er_byte_read_2.rs => pointer_byte_read.rs} | 0 tests/compile-fail/pointer_byte_read_1.rs | 7 -- tests/compile-fail/ptr_bitops1.rs | 7 -- tests/compile-fail/ptr_bitops2.rs | 5 -- tests/compile-fail/ptr_eq_dangling.rs | 10 --- tests/compile-fail/ptr_eq_integer.rs | 6 -- tests/compile-fail/ptr_eq_out_of_bounds.rs | 9 --- .../compile-fail/ptr_eq_out_of_bounds_null.rs | 6 -- tests/compile-fail/ptr_int_cast.rs | 8 --- tests/compile-fail/ptr_offset_int_plus_int.rs | 2 +- tests/compile-fail/ptr_offset_int_plus_ptr.rs | 2 +- tests/compile-fail/ptr_rem.rs | 5 -- .../ptr_wrapping_offset_int_plus_ptr.rs | 8 --- tests/compile-fail/validity/dangling_ref1.rs | 2 +- tests/compile-fail/wild_pointer_deref.rs | 2 +- .../bitop-beyond-alignment.rs | 2 +- tests/run-pass/intptrcast.rs | 67 ++++++++++++++++++- 20 files changed, 74 insertions(+), 93 deletions(-) delete mode 100644 tests/compile-fail/getrandom.rs rename tests/compile-fail/{pointer_byte_read_2.rs => pointer_byte_read.rs} (100%) delete mode 100644 tests/compile-fail/pointer_byte_read_1.rs delete mode 100644 tests/compile-fail/ptr_bitops1.rs delete mode 100644 tests/compile-fail/ptr_bitops2.rs delete mode 100644 tests/compile-fail/ptr_eq_dangling.rs delete mode 100644 tests/compile-fail/ptr_eq_integer.rs delete mode 100644 tests/compile-fail/ptr_eq_out_of_bounds.rs delete mode 100644 tests/compile-fail/ptr_eq_out_of_bounds_null.rs delete mode 100644 tests/compile-fail/ptr_int_cast.rs delete mode 100644 tests/compile-fail/ptr_rem.rs delete mode 100644 tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs rename tests/{compile-fail => run-pass}/bitop-beyond-alignment.rs (87%) diff --git a/tests/compile-fail/cast_box_int_to_fn_ptr.rs b/tests/compile-fail/cast_box_int_to_fn_ptr.rs index 7ee3bc62767f..6dad2a472730 100644 --- a/tests/compile-fail/cast_box_int_to_fn_ptr.rs +++ b/tests/compile-fail/cast_box_int_to_fn_ptr.rs @@ -4,8 +4,8 @@ fn main() { let b = Box::new(42); let g = unsafe { - std::mem::transmute::<&usize, &fn(i32)>(&b) + std::mem::transmute::<&Box, &fn(i32)>(&b) }; - (*g)(42) //~ ERROR a memory access tried to interpret some bytes as a pointer + (*g)(42) //~ ERROR tried to treat a memory pointer as a function pointer } diff --git a/tests/compile-fail/cast_int_to_fn_ptr.rs b/tests/compile-fail/cast_int_to_fn_ptr.rs index 207af4ae2cef..4fd14751a279 100644 --- a/tests/compile-fail/cast_int_to_fn_ptr.rs +++ b/tests/compile-fail/cast_int_to_fn_ptr.rs @@ -6,5 +6,5 @@ fn main() { std::mem::transmute::(42) }; - g(42) //~ ERROR a memory access tried to interpret some bytes as a pointer + g(42) //~ ERROR dangling pointer was dereferenced } diff --git a/tests/compile-fail/getrandom.rs b/tests/compile-fail/getrandom.rs deleted file mode 100644 index 246893a5c640..000000000000 --- a/tests/compile-fail/getrandom.rs +++ /dev/null @@ -1,13 +0,0 @@ -// ignore-macos: Uses Linux-only APIs -// ignore-windows: Uses Linux-only APIs - -#![feature(rustc_private)] -extern crate libc; - -fn main() { - let mut buf = [0u8; 5]; - unsafe { - libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, 0 as libc::c_uint); - //~^ ERROR miri does not support gathering system entropy in deterministic mode! - } -} diff --git a/tests/compile-fail/pointer_byte_read_2.rs b/tests/compile-fail/pointer_byte_read.rs similarity index 100% rename from tests/compile-fail/pointer_byte_read_2.rs rename to tests/compile-fail/pointer_byte_read.rs diff --git a/tests/compile-fail/pointer_byte_read_1.rs b/tests/compile-fail/pointer_byte_read_1.rs deleted file mode 100644 index a584863654ce..000000000000 --- a/tests/compile-fail/pointer_byte_read_1.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn main() { - let x = 13; - let y = &x; - let z = &y as *const &i32 as *const usize; - let ptr_bytes = unsafe { *z }; // the actual deref is fine, because we read the entire pointer at once - let _val = ptr_bytes / 432; //~ ERROR invalid arithmetic on pointers that would leak base addresses -} diff --git a/tests/compile-fail/ptr_bitops1.rs b/tests/compile-fail/ptr_bitops1.rs deleted file mode 100644 index 2706b0970d7d..000000000000 --- a/tests/compile-fail/ptr_bitops1.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn main() { - let bytes = [0i8, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - let one = bytes.as_ptr().wrapping_offset(1); - let three = bytes.as_ptr().wrapping_offset(3); - let res = (one as usize) | (three as usize); //~ ERROR invalid arithmetic on pointers that would leak base addresses - println!("{}", res); -} diff --git a/tests/compile-fail/ptr_bitops2.rs b/tests/compile-fail/ptr_bitops2.rs deleted file mode 100644 index 5d5eab155083..000000000000 --- a/tests/compile-fail/ptr_bitops2.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn main() { - let val = 13usize; - let addr = &val as *const _ as usize; - let _val = addr & 13; //~ ERROR access part of a pointer value as raw bytes -} diff --git a/tests/compile-fail/ptr_eq_dangling.rs b/tests/compile-fail/ptr_eq_dangling.rs deleted file mode 100644 index 5badf099e439..000000000000 --- a/tests/compile-fail/ptr_eq_dangling.rs +++ /dev/null @@ -1,10 +0,0 @@ -fn main() { - let b = Box::new(0); - let x = &*b as *const i32; // soon-to-be dangling - drop(b); - let b = Box::new(0); - let y = &*b as *const i32; // different allocation - // We cannot compare these even though both are inbounds -- they *could* be - // equal if memory was reused. - assert!(x != y); //~ ERROR invalid arithmetic on pointers -} diff --git a/tests/compile-fail/ptr_eq_integer.rs b/tests/compile-fail/ptr_eq_integer.rs deleted file mode 100644 index 396abaf4493b..000000000000 --- a/tests/compile-fail/ptr_eq_integer.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn main() { - let b = Box::new(0); - let x = &*b as *const i32; - // We cannot compare this with a non-NULL integer. After all, these *could* be equal (with the right base address). - assert!(x != 64 as *const i32); //~ ERROR invalid arithmetic on pointers -} diff --git a/tests/compile-fail/ptr_eq_out_of_bounds.rs b/tests/compile-fail/ptr_eq_out_of_bounds.rs deleted file mode 100644 index 7efa446d7fca..000000000000 --- a/tests/compile-fail/ptr_eq_out_of_bounds.rs +++ /dev/null @@ -1,9 +0,0 @@ -fn main() { - let b = Box::new(0); - let x = (&*b as *const i32).wrapping_sub(0x800); // out-of-bounds - let b = Box::new(0); - let y = &*b as *const i32; // different allocation - // We cannot compare these even though both allocations are live -- they *could* be - // equal (with the right base addresses). - assert!(x != y); //~ ERROR invalid arithmetic on pointers -} diff --git a/tests/compile-fail/ptr_eq_out_of_bounds_null.rs b/tests/compile-fail/ptr_eq_out_of_bounds_null.rs deleted file mode 100644 index 3b7b51fc1995..000000000000 --- a/tests/compile-fail/ptr_eq_out_of_bounds_null.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn main() { - let b = Box::new(0); - let x = (&*b as *const i32).wrapping_sub(0x800); // out-of-bounds - // We cannot compare this with NULL. After all, this *could* be NULL (with the right base address). - assert!(x != std::ptr::null()); //~ ERROR invalid arithmetic on pointers -} diff --git a/tests/compile-fail/ptr_int_cast.rs b/tests/compile-fail/ptr_int_cast.rs deleted file mode 100644 index a823a0f49b63..000000000000 --- a/tests/compile-fail/ptr_int_cast.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - let x = &1; - // Casting down to u8 and back up to a pointer loses too much precision; this must not work. - let x = x as *const i32; - let x = x as u8; //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes - let x = x as *const i32; - let _val = unsafe { *x }; -} diff --git a/tests/compile-fail/ptr_offset_int_plus_int.rs b/tests/compile-fail/ptr_offset_int_plus_int.rs index 2d3282a0a97a..051874696b11 100644 --- a/tests/compile-fail/ptr_offset_int_plus_int.rs +++ b/tests/compile-fail/ptr_offset_int_plus_int.rs @@ -1,4 +1,4 @@ -// error-pattern: tried to interpret some bytes as a pointer +// error-pattern: dangling pointer was dereferenced fn main() { // Can't offset an integer pointer by non-zero offset. diff --git a/tests/compile-fail/ptr_offset_int_plus_ptr.rs b/tests/compile-fail/ptr_offset_int_plus_ptr.rs index b49c758c72f7..bd90d0690917 100644 --- a/tests/compile-fail/ptr_offset_int_plus_ptr.rs +++ b/tests/compile-fail/ptr_offset_int_plus_ptr.rs @@ -1,4 +1,4 @@ -// error-pattern: pointer value as raw bytes +// error-pattern: dangling pointer was dereferenced fn main() { let ptr = Box::into_raw(Box::new(0u32)); diff --git a/tests/compile-fail/ptr_rem.rs b/tests/compile-fail/ptr_rem.rs deleted file mode 100644 index dfc91e9dc1b1..000000000000 --- a/tests/compile-fail/ptr_rem.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn main() { - let val = 13usize; - let addr = &val as *const _ as usize; - let _val = addr % 16; //~ ERROR access part of a pointer value as raw bytes -} diff --git a/tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs b/tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs deleted file mode 100644 index eacb9f07fffd..000000000000 --- a/tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs +++ /dev/null @@ -1,8 +0,0 @@ -// error-pattern: pointer value as raw bytes - -fn main() { - let ptr = Box::into_raw(Box::new(0u32)); - // Can't start with an integer pointer and get to something usable - let ptr = (1 as *mut u8).wrapping_offset(ptr as isize); - let _val = unsafe { *ptr }; -} diff --git a/tests/compile-fail/validity/dangling_ref1.rs b/tests/compile-fail/validity/dangling_ref1.rs index 2c1984b7159c..194445b1ad7e 100644 --- a/tests/compile-fail/validity/dangling_ref1.rs +++ b/tests/compile-fail/validity/dangling_ref1.rs @@ -1,5 +1,5 @@ use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR dangling reference (created from integer) + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR dangling reference (not entirely in bounds) } diff --git a/tests/compile-fail/wild_pointer_deref.rs b/tests/compile-fail/wild_pointer_deref.rs index 8eec9737546b..ae32f7d5562b 100644 --- a/tests/compile-fail/wild_pointer_deref.rs +++ b/tests/compile-fail/wild_pointer_deref.rs @@ -1,5 +1,5 @@ fn main() { let p = 44 as *const i32; - let x = unsafe { *p }; //~ ERROR a memory access tried to interpret some bytes as a pointer + let x = unsafe { *p }; //~ ERROR dangling pointer was dereferenced panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/bitop-beyond-alignment.rs b/tests/run-pass/bitop-beyond-alignment.rs similarity index 87% rename from tests/compile-fail/bitop-beyond-alignment.rs rename to tests/run-pass/bitop-beyond-alignment.rs index a30c054ab5d0..f7bf7f9ff58b 100644 --- a/tests/compile-fail/bitop-beyond-alignment.rs +++ b/tests/run-pass/bitop-beyond-alignment.rs @@ -28,7 +28,7 @@ fn mk_rec() -> Rec { fn is_u64_aligned(u: &Tag) -> bool { let p: usize = unsafe { mem::transmute(u) }; let u64_align = std::mem::align_of::(); - return (p & (u64_align + 1)) == 0; //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes + return (p & (u64_align + 1)) == 0; } pub fn main() { diff --git a/tests/run-pass/intptrcast.rs b/tests/run-pass/intptrcast.rs index c28958b872de..c2711f9845d0 100644 --- a/tests/run-pass/intptrcast.rs +++ b/tests/run-pass/intptrcast.rs @@ -3,18 +3,22 @@ fn transmute_ptr_to_int(x: *const T) -> usize { unsafe { std::mem::transmute(x) } } -fn main() { +fn cast() { // Some casting-to-int with arithmetic. let x = &42 as *const i32 as usize; let y = x * 2; assert_eq!(y, x + x); let z = y as u8 as usize; assert_eq!(z, y % 256); +} +fn format() { // Pointer string formatting! We can't check the output as it changes when libstd changes, // but we can make sure Miri does not error. format!("{:?}", &mut 13 as *mut _); +} +fn transmute() { // Check that intptrcast is triggered for explicit casts and that it is consistent with // transmuting. let a: *const i32 = &42; @@ -22,3 +26,64 @@ fn main() { let c = a as usize as u8; assert_eq!(b, c); } + +fn ptr_bitops1() { + let bytes = [0i8, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + let one = bytes.as_ptr().wrapping_offset(1); + let three = bytes.as_ptr().wrapping_offset(3); + let res = (one as usize) | (three as usize); + format!("{}", res); +} + +fn ptr_bitops2() { + let val = 13usize; + let addr = &val as *const _ as usize; + let _val = addr & 13; +} + +fn ptr_eq_dangling() { + let b = Box::new(0); + let x = &*b as *const i32; // soon-to-be dangling + drop(b); + let b = Box::new(0); + let y = &*b as *const i32; // different allocation + // We cannot compare these even though both are inbounds -- they *could* be + // equal if memory was reused. + assert!(x != y); +} + +fn ptr_eq_out_of_bounds() { + let b = Box::new(0); + let x = (&*b as *const i32).wrapping_sub(0x800); // out-of-bounds + let b = Box::new(0); + let y = &*b as *const i32; // different allocation + // We cannot compare these even though both allocations are live -- they *could* be + // equal (with the right base addresses). + assert!(x != y); +} + +fn ptr_eq_out_of_bounds_null() { + let b = Box::new(0); + let x = (&*b as *const i32).wrapping_sub(0x800); // out-of-bounds + // We cannot compare this with NULL. After all, this *could* be NULL (with the right base address). + assert!(x != std::ptr::null()); +} + +fn ptr_eq_integer() { + let b = Box::new(0); + let x = &*b as *const i32; + // We cannot compare this with a non-NULL integer. After all, these *could* be equal (with the right base address). + assert!(x != 64 as *const i32); +} + +fn main() { + cast(); + format(); + transmute(); + ptr_bitops1(); + ptr_bitops2(); + ptr_eq_dangling(); + ptr_eq_out_of_bounds(); + ptr_eq_out_of_bounds_null(); + ptr_eq_integer(); +} From d5ca345c36b037c4cdfe1a9f165464e7f815e2c1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Jul 2019 23:26:25 +0200 Subject: [PATCH 0945/5092] remove redundant tests / flags --- tests/compile-fail/intptrcast_alignment_check.rs | 2 +- tests/compile-fail/intptrcast_cast_int_to_fn_ptr.rs | 10 ---------- tests/compile-fail/intptrcast_null_pointer_deref.rs | 6 ------ tests/compile-fail/intptrcast_wild_pointer_deref.rs | 7 ------- 4 files changed, 1 insertion(+), 24 deletions(-) delete mode 100644 tests/compile-fail/intptrcast_cast_int_to_fn_ptr.rs delete mode 100644 tests/compile-fail/intptrcast_null_pointer_deref.rs delete mode 100644 tests/compile-fail/intptrcast_wild_pointer_deref.rs diff --git a/tests/compile-fail/intptrcast_alignment_check.rs b/tests/compile-fail/intptrcast_alignment_check.rs index 5a35844d1256..4e12a8a9e25e 100644 --- a/tests/compile-fail/intptrcast_alignment_check.rs +++ b/tests/compile-fail/intptrcast_alignment_check.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmiri-disable-validation -Zmiri-seed=0000000000000000 +// compile-flags: -Zmiri-disable-validation // Even with intptrcast and without validation, we want to be *sure* to catch bugs // that arise from pointers being insufficiently aligned. The only way to achieve diff --git a/tests/compile-fail/intptrcast_cast_int_to_fn_ptr.rs b/tests/compile-fail/intptrcast_cast_int_to_fn_ptr.rs deleted file mode 100644 index f4064cf92e2c..000000000000 --- a/tests/compile-fail/intptrcast_cast_int_to_fn_ptr.rs +++ /dev/null @@ -1,10 +0,0 @@ -// Validation makes this fail in the wrong place -// compile-flags: -Zmiri-disable-validation -Zmiri-seed=0000000000000000 - -fn main() { - let g = unsafe { - std::mem::transmute::(42) - }; - - g(42) //~ ERROR dangling pointer was dereferenced -} diff --git a/tests/compile-fail/intptrcast_null_pointer_deref.rs b/tests/compile-fail/intptrcast_null_pointer_deref.rs deleted file mode 100644 index 0c5d46609cf8..000000000000 --- a/tests/compile-fail/intptrcast_null_pointer_deref.rs +++ /dev/null @@ -1,6 +0,0 @@ -// compile-flags: -Zmiri-seed=0000000000000000 - -fn main() { - let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR invalid use of NULL pointer - panic!("this should never print: {}", x); -} diff --git a/tests/compile-fail/intptrcast_wild_pointer_deref.rs b/tests/compile-fail/intptrcast_wild_pointer_deref.rs deleted file mode 100644 index 2ee664eb68bd..000000000000 --- a/tests/compile-fail/intptrcast_wild_pointer_deref.rs +++ /dev/null @@ -1,7 +0,0 @@ -// compile-flags: -Zmiri-seed=0000000000000000 - -fn main() { - let p = 44 as *const i32; - let x = unsafe { *p }; //~ ERROR dangling pointer was dereferenced - panic!("this should never print: {}", x); -} From 724cf41eb1a4fa529a5b1fe629d077dbb217019f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Jul 2019 23:43:37 +0200 Subject: [PATCH 0946/5092] use checked arithmetic in intrptrcast --- src/intptrcast.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 8fbf7ed76427..1247150cc119 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -95,7 +95,8 @@ impl<'mir, 'tcx> GlobalState { rng.gen_range(0, 16) }; // From next_base_addr + slack, round up to adjust for alignment. - let base_addr = Self::align_addr(global_state.next_base_addr + slack, align.bytes()); + let base_addr = global_state.next_base_addr.checked_add(slack).unwrap(); + let base_addr = Self::align_addr(base_addr, align.bytes()); entry.insert(base_addr); trace!( "Assigning base address {:#x} to allocation {:?} (slack: {}, align: {})", @@ -104,7 +105,7 @@ impl<'mir, 'tcx> GlobalState { // Remember next base address. If this allocation is zero-sized, leave a gap // of at least 1 to avoid two allocations having the same base address. - global_state.next_base_addr = base_addr + max(size.bytes(), 1); + global_state.next_base_addr = base_addr.checked_add(max(size.bytes(), 1)).unwrap(); // Given that `next_base_addr` increases in each allocation, pushing the // corresponding tuple keeps `int_to_ptr_map` sorted global_state.int_to_ptr_map.push((base_addr, ptr.alloc_id)); @@ -124,7 +125,7 @@ impl<'mir, 'tcx> GlobalState { fn align_addr(addr: u64, align: u64) -> u64 { match addr % align { 0 => addr, - rem => addr + align - rem + rem => addr.checked_add(align).unwrap() - rem } } } From 85be8ab8ebaf5487ef7e852db809751d97a36605 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Jul 2019 23:48:28 +0200 Subject: [PATCH 0947/5092] fix non-deterministic test --- tests/run-pass/bitop-beyond-alignment.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/bitop-beyond-alignment.rs b/tests/run-pass/bitop-beyond-alignment.rs index f7bf7f9ff58b..f60982246427 100644 --- a/tests/run-pass/bitop-beyond-alignment.rs +++ b/tests/run-pass/bitop-beyond-alignment.rs @@ -33,5 +33,5 @@ fn is_u64_aligned(u: &Tag) -> bool { pub fn main() { let x = mk_rec(); - assert!(is_u64_aligned(&x.t)); + is_u64_aligned(&x.t); // the result of this is non-deterministic } From fd71fbea0f5e9f13bf33b0b1a78f3e6d5897b542 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Wed, 24 Jul 2019 07:30:41 +0700 Subject: [PATCH 0948/5092] build: Fix build after rust-lang/rust#60951 --- rust-version | 2 +- src/operator.rs | 7 ++++--- src/shims/foreign_items.rs | 3 ++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index b247139d09b3..973a5105980c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1301422a6c2e8916560b8cc2f0564f38d8858a75 +a7f28678bbf4e16893bb6a718e427504167a9494 diff --git a/src/operator.rs b/src/operator.rs index df60acc661ed..977d6dd56e46 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -64,12 +64,12 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { assert!(right.layout.ty.is_integral()); let l_bits = self.force_bits(left.imm.to_scalar()?, left.layout.size)?; let r_bits = self.force_bits(right.imm.to_scalar()?, right.layout.size)?; - + let left = ImmTy::from_scalar(Scalar::from_uint(l_bits, left.layout.size), left.layout); let right = ImmTy::from_scalar(Scalar::from_uint(r_bits, left.layout.size), right.layout); return self.binary_op(bin_op, left, right); - } + } // Operations that support fat pointers match bin_op { @@ -391,11 +391,12 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { pointee_ty: Ty<'tcx>, offset: i64, ) -> InterpResult<'tcx, Scalar> { + use rustc::mir::interpret::InterpError::Panic; // FIXME: assuming here that type size is less than `i64::max_value()`. let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; let offset = offset .checked_mul(pointee_size) - .ok_or_else(|| InterpError::Overflow(mir::BinOp::Mul))?; + .ok_or_else(|| Panic(PanicMessage::Overflow(mir::BinOp::Mul)))?; // Now let's see what kind of pointer this is. let ptr = if offset == 0 { match ptr { diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 1deaf521ca66..bcfcda2fd01c 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -128,6 +128,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest: Option>, ret: Option, ) -> InterpResult<'tcx> { + use rustc::mir::interpret::InterpError::Panic; let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { @@ -167,7 +168,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "calloc" => { let items = this.read_scalar(args[0])?.to_usize(this)?; let len = this.read_scalar(args[1])?.to_usize(this)?; - let size = items.checked_mul(len).ok_or_else(|| InterpError::Overflow(mir::BinOp::Mul))?; + let size = items.checked_mul(len).ok_or_else(|| Panic(PanicMessage::Overflow(mir::BinOp::Mul)))?; let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C); this.write_scalar(res, dest)?; } From 758d88bbf96c726ca8c620068bb20f552b8bd35a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Jul 2019 08:57:05 +0200 Subject: [PATCH 0949/5092] explain better what is non-deterministic here --- tests/run-pass/bitop-beyond-alignment.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/bitop-beyond-alignment.rs b/tests/run-pass/bitop-beyond-alignment.rs index f60982246427..a30f0fb61314 100644 --- a/tests/run-pass/bitop-beyond-alignment.rs +++ b/tests/run-pass/bitop-beyond-alignment.rs @@ -33,5 +33,5 @@ fn is_u64_aligned(u: &Tag) -> bool { pub fn main() { let x = mk_rec(); - is_u64_aligned(&x.t); // the result of this is non-deterministic + is_u64_aligned(&x.t); // the result of this is non-deterministic (even with a fixed seed, results vary between platforms) } From 59fa7c2cf5ed072e7d9f8bc1ae2307b67dacfbdb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Jul 2019 14:18:42 +0200 Subject: [PATCH 0950/5092] readme: move flags and env vars up above dev --- README.md | 73 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index fbd1f51c9e69..6b6a274f3fba 100644 --- a/README.md +++ b/README.md @@ -136,6 +136,43 @@ should never happen when you use `cargo miri` because that takes care of setting up the sysroot. If you are using `miri` (the Miri driver) directly, see [below][testing-miri] for how to set up the sysroot. + +## Miri `-Z` flags and environment variables +[miri-flags]: #miri--z-flags-and-environment-variables + +Several `-Z` flags are relevant for Miri: + +* `-Zmiri-seed=` is a custom `-Z` flag added by Miri. It configures the + seed of the RNG that Miri uses to resolve non-determinism. This RNG is used + to pick base addresses for allocations, and when the interpreted program + requests system entropy. The default seed is 0. + **NOTE**: This entropy is not good enough for cryptographic use! Do not + generate secret keys in Miri or perform other kinds of cryptographic + operations that rely on proper random numbers. +* `-Zmiri-disable-validation` disables enforcing the validity invariant, which + is enforced by default. This is mostly useful for debugging; it means Miri + will miss bugs in your program. However, this can also help to make Miri run + faster. +* `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri + overrides the default to be `0`; be advised that using any higher level can + make Miri miss bugs in your program because they got optimized away. +* `-Zalways-encode-mir` makes rustc dump MIR even for completely monomorphic + functions. This is needed so that Miri can execute such functions, so Miri + sets this flag per default. +* `-Zmir-emit-retag` controls whether `Retag` statements are emitted. Miri + enables this per default because it is needed for validation. + +Moreover, Miri recognizes some environment variables: + +* `MIRI_LOG`, `MIRI_BACKTRACE` control logging and backtrace printing during + Miri executions, also [see above][testing-miri]. +* `MIRI_SYSROOT` (recognized by `cargo miri` and the test suite) + indicates the sysroot to use. To do the same thing with `miri` + directly, use the `--sysroot` flag. +* `MIRI_TEST_TARGET` (recognized by the test suite) indicates which target + architecture to test against. `miri` and `cargo miri` accept the `--target` + flag for the same purpose. + ## Development and Debugging If you want to hack on miri yourself, great! Here are some resources you might @@ -257,42 +294,6 @@ rustup override set custom With this, you should now have a working development setup! See [above][testing-miri] for how to proceed working with the Miri driver. -### Miri `-Z` flags and environment variables -[miri-flags]: #miri--z-flags-and-environment-variables - -Several `-Z` flags are relevant for Miri: - -* `-Zmiri-seed=` is a custom `-Z` flag added by Miri. It configures the - seed of the RNG that Miri uses to resolve non-determinism. This RNG is used - to pick base addresses for allocations, and when the interpreted program - requests system entropy. The default seed is 0. - **NOTE**: This entropy is not good enough for cryptographic use! Do not - generate secret keys in Miri or perform other kinds of cryptographic - operations that rely on proper random numbers. -* `-Zmiri-disable-validation` disables enforcing the validity invariant, which - is enforced by default. This is mostly useful for debugging; it means Miri - will miss bugs in your program. However, this can also help to make Miri run - faster. -* `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri - overrides the default to be `0`; be advised that using any higher level can - make Miri miss bugs in your program because they got optimized away. -* `-Zalways-encode-mir` makes rustc dump MIR even for completely monomorphic - functions. This is needed so that Miri can execute such functions, so Miri - sets this flag per default. -* `-Zmir-emit-retag` controls whether `Retag` statements are emitted. Miri - enables this per default because it is needed for validation. - -Moreover, Miri recognizes some environment variables: - -* `MIRI_LOG`, `MIRI_BACKTRACE` control logging and backtrace printing during - Miri executions, also [see above][testing-miri]. -* `MIRI_SYSROOT` (recognized by `cargo miri` and the test suite) - indicates the sysroot to use. To do the same thing with `miri` - directly, use the `--sysroot` flag. -* `MIRI_TEST_TARGET` (recognized by the test suite) indicates which target - architecture to test against. `miri` and `cargo miri` accept the `--target` - flag for the same purpose. - ## Contributing and getting help Check out the issues on this GitHub repository for some ideas. There's lots that From e6a677fe63286dac484714282da7bb873dd2dbd3 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Wed, 24 Jul 2019 21:24:26 +0700 Subject: [PATCH 0951/5092] build: Warn if not use 2018 idioms --- src/eval.rs | 2 +- src/lib.rs | 1 + src/stacked_borrows.rs | 8 ++++---- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 83307c99f9c5..e688d3594718 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -179,7 +179,7 @@ pub fn eval_main<'tcx>( }; // Perform the main execution. - let res: InterpResult = (|| { + let res: InterpResult<'_> = (|| { ecx.run()?; ecx.run_tls_dtors() })(); diff --git a/src/lib.rs b/src/lib.rs index 20c24ad54fe8..0265fbf15cc5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ #![feature(rustc_private)] +#![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] #[macro_use] diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 90656180150f..0fe42f7974fb 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -28,7 +28,7 @@ pub enum Tag { } impl fmt::Debug for Tag { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Tag::Tagged(id) => write!(f, "<{}>", id), Tag::Untagged => write!(f, ""), @@ -62,7 +62,7 @@ pub struct Item { } impl fmt::Debug for Item { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "[{:?} for {:?}", self.perm, self.tag)?; if let Some(call) = self.protector { write!(f, " (call {})", call)?; @@ -117,7 +117,7 @@ pub enum AccessKind { } impl fmt::Display for AccessKind { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { AccessKind::Read => write!(f, "read access"), AccessKind::Write => write!(f, "write access"), @@ -139,7 +139,7 @@ pub enum RefKind { } impl fmt::Display for RefKind { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { RefKind::Unique { two_phase: false } => write!(f, "unique"), RefKind::Unique { two_phase: true } => write!(f, "unique (two-phase)"), From e843077d1d673019518055c47dc39c7098993b0c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 25 Jul 2019 19:38:55 +0200 Subject: [PATCH 0952/5092] link to UB definition --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6b6a274f3fba..6934c453de4d 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,8 @@ An experimental interpreter for [Rust][rust]'s [mid-level intermediate representation][mir] (MIR). It can run binaries and -test suites of cargo projects and detect certain classes of undefined behavior, +test suites of cargo projects and detect certain classes of +[undefined behavior](https://doc.rust-lang.org/reference/behavior-considered-undefined.html), for example: * Out-of-bounds memory accesses and use-after-free From 8bec925e049b74134713f4c860d1c46acc84214d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 26 Jul 2019 10:14:44 +0200 Subject: [PATCH 0953/5092] bump Rust --- rust-version | 2 +- tests/run-pass/intrinsics.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 973a5105980c..b8ae5e6cbd56 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a7f28678bbf4e16893bb6a718e427504167a9494 +4268e7ee22935f086b856ef0063a9e22b49aeddb diff --git a/tests/run-pass/intrinsics.rs b/tests/run-pass/intrinsics.rs index 963265749d13..754a38f63535 100644 --- a/tests/run-pass/intrinsics.rs +++ b/tests/run-pass/intrinsics.rs @@ -11,5 +11,5 @@ fn main() { assert_eq!(size_of_val(&[1, 2, 3] as &[i32]), 12); assert_eq!(size_of_val("foobar"), 6); - assert_eq!(unsafe { type_name::>() }, "core::option::Option"); + assert_eq!(type_name::>(), "core::option::Option"); } From faadb86159bf3c65a1e69db0432ba52c980b6324 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 26 Jul 2019 22:50:01 +0200 Subject: [PATCH 0954/5092] bump Rust --- rust-version | 2 +- src/bin/cargo-miri.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index b8ae5e6cbd56..a3ec4b911c40 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4268e7ee22935f086b856ef0063a9e22b49aeddb +c43753f910aae000f8bcb0a502407ea332afc74b diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index cc95eeb7f3a0..fe30e7d010bd 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -335,7 +335,7 @@ fn main() { } fn in_cargo_miri() { - let (subcommand, skip) = match std::env::args().nth(2).deref() { + let (subcommand, skip) = match std::env::args().nth(2).as_deref() { Some("test") => (MiriCommand::Test, 3), Some("run") => (MiriCommand::Run, 3), Some("setup") => (MiriCommand::Setup, 3), From 070d1cd08d0bf7c994cc842b60d883c9f9e8ce2c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 28 Jul 2019 10:14:36 +0200 Subject: [PATCH 0955/5092] bump Rust (no changes needed) --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index a3ec4b911c40..2dc0d2bbccb6 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c43753f910aae000f8bcb0a502407ea332afc74b +0e9b465d729d07101b29b4d096d83edf9be82df0 From 784ad6953edf5a82382e74223225382cb9ed12c4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 29 Jul 2019 10:07:29 +0200 Subject: [PATCH 0956/5092] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 2dc0d2bbccb6..5178503f1041 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0e9b465d729d07101b29b4d096d83edf9be82df0 +8b94e9e9188b65df38a5f1ae723617dc2dfb3155 From 87f20fede528a2a99c06e6aae480adac91f5ecc2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 29 Jul 2019 10:21:59 +0200 Subject: [PATCH 0957/5092] adjust for slice pattern changes --- tests/run-pass/issue-15080.rs | 4 ++-- tests/run-pass/issue-17877.rs | 4 ++-- tests/run-pass/subslice_array.rs | 2 +- tests/run-pass/vec-matching-fold.rs | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/run-pass/issue-15080.rs b/tests/run-pass/issue-15080.rs index 3ef3718d5227..7f19759b910a 100644 --- a/tests/run-pass/issue-15080.rs +++ b/tests/run-pass/issue-15080.rs @@ -6,11 +6,11 @@ fn main() { let mut result = vec!(); loop { x = match *x { - [1, n, 3, ref rest..] => { + [1, n, 3, ref rest @ ..] => { result.push(n); rest } - [n, ref rest..] => { + [n, ref rest @ ..] => { result.push(n); rest } diff --git a/tests/run-pass/issue-17877.rs b/tests/run-pass/issue-17877.rs index caad8b27766f..9cbc459ad038 100644 --- a/tests/run-pass/issue-17877.rs +++ b/tests/run-pass/issue-17877.rs @@ -9,8 +9,8 @@ fn main() { }, 42_usize); assert_eq!(match [0u8; 1024] { - [1, _..] => 0_usize, - [0, _..] => 1_usize, + [1, ..] => 0_usize, + [0, ..] => 1_usize, _ => 2_usize }, 1_usize); } diff --git a/tests/run-pass/subslice_array.rs b/tests/run-pass/subslice_array.rs index 5bbbffe4e60e..df3631c647fb 100644 --- a/tests/run-pass/subslice_array.rs +++ b/tests/run-pass/subslice_array.rs @@ -6,7 +6,7 @@ fn bar(a: &'static str, b: &'static str) -> [&'static str; 4] { fn main() { let out = bar("baz", "foo"); - let [a, xs.., d] = out; + let [a, xs @ .., d] = out; assert_eq!(a, "baz"); assert_eq!(xs, ["foo", "foo"]); assert_eq!(d, "baz"); diff --git a/tests/run-pass/vec-matching-fold.rs b/tests/run-pass/vec-matching-fold.rs index f953e0474705..54fbb702924f 100644 --- a/tests/run-pass/vec-matching-fold.rs +++ b/tests/run-pass/vec-matching-fold.rs @@ -9,7 +9,7 @@ fn foldl(values: &[T], U: Clone+Debug, T:Debug, F: FnMut(U, &T) -> U, { match values { - &[ref head, ref tail..] => + &[ref head, ref tail @ ..] => foldl(tail, function(initial, head), function), &[] => { let res = initial.clone(); res @@ -25,7 +25,7 @@ fn foldr(values: &[T], F: FnMut(&T, U) -> U, { match values { - &[ref head.., ref tail] => + &[ref head @ .., ref tail] => foldr(head, function(tail, initial), function), &[] => { let res = initial.clone(); res From b1ba07b0ca440329068ca2fd308ccb24c31a2697 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Jul 2019 11:23:56 +0200 Subject: [PATCH 0958/5092] call out more clearly what we do not test; update paragraph on intptrcast --- README.md | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 6934c453de4d..e21ee987125e 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ for example: * Violation of intrinsic preconditions (an [`unreachable_unchecked`] being reached, calling [`copy_nonoverlapping`] with overlapping ranges, ...) * Not sufficiently aligned memory accesses and references -* Violation of basic type invariants (a `bool` that is not 0 or 1, for example, +* Violation of *some* basic type invariants (a `bool` that is not 0 or 1, for example, or an invalid enum discriminant) * WIP: Violations of the rules governing aliasing for reference types @@ -20,22 +20,24 @@ Miri has already discovered some [real-world bugs](#bugs-found-by-miri). If you found a bug with Miri, we'd appreciate if you tell us and we'll add it to the list! -Be aware that Miri will not catch all possible errors in your program, and -cannot run all programs: +Be aware that Miri will not catch all cases of undefined behavior in your +program, and cannot run all programs: * There are still plenty of open questions around the basic invariants for some types and when these invariants even have to hold. Miri tries to avoid false positives here, so if you program runs fine in Miri right now that is by no - means a guarantee that it is UB-free when these questions get answered. In - particular, Miri does currently not check that integers are initialized or - that references point to valid data. + means a guarantee that it is UB-free when these questions get answered. + + In particular, Miri does currently not check that integers are initialized + or that references point to valid data. * If the program relies on unspecified details of how data is laid out, it will still run fine in Miri -- but might break (including causing UB) on different compiler versions or different platforms. -* Miri is fully deterministic and does not actually pick a base address in - virtual memory for the program's allocations. If program behavior depends on - the base address of an allocation, Miri will stop execution (with a few - exceptions to make some common pointer comparisons work). +* Program execution is non-deterministic when it depends, for example, on where + exactly in memory allocations end up. Miri tests one of many possible + executions of your program. If your code is sensitive to allocation base + addresses or other non-deterministic data, try running Miri with different + values for `-Zmiri-seed` to test different executions. * Miri runs the program as a platform-independent interpreter, so the program has no access to any platform-specific APIs or FFI. A few APIs have been implemented (such as printing to stdout) but most have not: for example, Miri From fcbdd2c86469b0be514b1c08075fec57e71e20a1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Jul 2019 17:04:57 +0200 Subject: [PATCH 0959/5092] move CI remark down to CI section --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e21ee987125e..91fc72cb427b 100644 --- a/README.md +++ b/README.md @@ -73,9 +73,7 @@ Now you can run your project in Miri: 3. If you have a binary project, you can run it through Miri using `cargo miri run`. The first time you run Miri, it will perform some extra setup and install some -dependencies. It will ask you for confirmation before installing anything. If -you run Miri on CI, run `cargo miri setup` to avoid getting interactive -questions. +dependencies. It will ask you for confirmation before installing anything. You can pass arguments to Miri after the first `--`, and pass arguments to the interpreted program or test suite after the second `--`. For example, `cargo @@ -115,6 +113,9 @@ cargo miri setup cargo miri test -- -- -Zunstable-options --exclude-should-panic ``` +We use `cargo miri setup` to avoid getting interactive questions about the extra +setup needed for Miri. + ### Common Problems When using the above instructions, you may encounter a number of confusing compiler From 6902461226ae7508e58689e80280da223462f3d0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Jul 2019 23:17:13 +0200 Subject: [PATCH 0960/5092] AppVeyor: retry download --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 4e8b8cd4b898..391ff042daf4 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -18,7 +18,7 @@ cache: install: # Install Rust - - curl -sSf -o rustup-init.exe https://win.rustup.rs/ + - curl -sSf --retry 3 -o rustup-init.exe https://win.rustup.rs/ - rustup-init.exe -y --default-host %TARGET% --default-toolchain stable - set PATH=%USERPROFILE%\.cargo\bin;%PATH% # Install "master" toolchain From af7570fced59a775da78492cb20a6f22982a1268 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Wed, 31 Jul 2019 16:42:38 +0900 Subject: [PATCH 0961/5092] Remove await_macro --- tests/run-pass/async-fn.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 8a0ac875f54d..5c916473b580 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -1,7 +1,4 @@ -#![feature( - async_await, - await_macro, -)] +#![feature(async_await)] use std::{future::Future, pin::Pin, task::Poll, ptr}; use std::task::{Waker, RawWaker, RawWakerVTable, Context}; @@ -11,7 +8,7 @@ pub async fn foo(x: &u32, y: u32) -> u32 { let y = &y; let z = 9; let z = &z; - let y = await!(async { *y + *z }); + let y = async { *y + *z }.await; let a = 10; let a = &a; *x + y + *a From 6dadb941013e901dd8167ee50642d6eba0c08aff Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Jul 2019 13:44:55 +0200 Subject: [PATCH 0962/5092] test suite: be fine with warnings when running on rustc CI --- tests/compiletest.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 9394084ad34d..f88fb0b6b981 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -26,7 +26,11 @@ fn rustc_lib_path() -> PathBuf { fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec) { // Some flags we always want. - flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs + if rustc_test_suite().is_none() { + // Only `-Dwarnings` on the Miri side to make the rustc toolstate management less painful. + // (We often get warnings when e.g. a feature gets stabilized or some lint gets added/improved.) + flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs + } flags.push("--edition 2018".to_owned()); if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") { flags.push(format!("--sysroot {}", sysroot)); From edf7d1c30c9b53da5f9cd0fa9597d999f0aa1752 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Jul 2019 13:48:15 +0200 Subject: [PATCH 0963/5092] dedup code a bit --- tests/compiletest.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index f88fb0b6b981..21366c3dbf50 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -25,8 +25,9 @@ fn rustc_lib_path() -> PathBuf { } fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec) { - // Some flags we always want. - if rustc_test_suite().is_none() { + let in_rustc_test_suite = rustc_test_suite().is_some(); + // Add some flags we always want. + if !in_rustc_test_suite { // Only `-Dwarnings` on the Miri side to make the rustc toolstate management less painful. // (We often get warnings when e.g. a feature gets stabilized or some lint gets added/improved.) flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs @@ -40,7 +41,7 @@ fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec) { let mut config = compiletest::Config::default().tempdir(); config.mode = mode.parse().expect("Invalid mode"); config.rustc_path = miri_path(); - if rustc_test_suite().is_some() { + if in_rustc_test_suite { config.run_lib_path = rustc_lib_path(); config.compile_lib_path = rustc_lib_path(); } From a414492cc736111446a11925aadba5605496624c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Jul 2019 13:48:49 +0200 Subject: [PATCH 0964/5092] reorder for clarity --- tests/compiletest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 21366c3dbf50..eaf7f8531b8f 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -27,12 +27,12 @@ fn rustc_lib_path() -> PathBuf { fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec) { let in_rustc_test_suite = rustc_test_suite().is_some(); // Add some flags we always want. + flags.push("--edition 2018".to_owned()); if !in_rustc_test_suite { // Only `-Dwarnings` on the Miri side to make the rustc toolstate management less painful. // (We often get warnings when e.g. a feature gets stabilized or some lint gets added/improved.) flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs } - flags.push("--edition 2018".to_owned()); if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") { flags.push(format!("--sysroot {}", sysroot)); } From d213c64d8569a7422eed517b9f4a5ea867c76866 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Jul 2019 15:15:14 +0200 Subject: [PATCH 0965/5092] let the user skip the sysroot consistency check --- src/bin/cargo-miri.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index fe30e7d010bd..b46742efe72a 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -141,6 +141,13 @@ fn test_sysroot_consistency() { .unwrap_or_else(|_| panic!("Failed to canonicalize sysroot: {}", stdout)) } + // We let the user skip this check if they really want to. + // (`bootstrap` needs this because Miri gets built by the stage1 compiler + // but run with the stage2 sysroot.) + if std::env::var("MIRI_SKIP_SYSROOT_CHECK").is_ok() { + return; + } + let rustc_sysroot = get_sysroot(Command::new("rustc")); let miri_sysroot = get_sysroot(Command::new(find_miri())); From 56630e0ff06c9f9690c4497f95a88fc64b1e5c8a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Jul 2019 15:15:31 +0200 Subject: [PATCH 0966/5092] bootstrap no longer carries a copy of these flags --- src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0265fbf15cc5..58f572bf7011 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,7 +47,5 @@ pub use crate::eval::{eval_main, create_ecx, MiriConfig}; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. pub fn miri_default_args() -> &'static [&'static str] { - // The flags here should be kept in sync with what bootstrap adds when `test-miri` is - // set, which happens in `bootstrap/bin/rustc.rs` in the rustc sources. &["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0", "--cfg=miri"] } From 6c545ba340fb50e33bf4b71672e3919a84ba4f3c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Jul 2019 15:15:55 +0200 Subject: [PATCH 0967/5092] the compile-fail-norustc hack is no longer needed --- .../copy_nonoverlapping.rs | 0 tests/{compile-fail-norustc => compile-fail}/copy_null.rs | 0 .../copy_unaligned.rs | 0 tests/compiletest.rs | 7 ------- 4 files changed, 7 deletions(-) rename tests/{compile-fail-norustc => compile-fail}/copy_nonoverlapping.rs (100%) rename tests/{compile-fail-norustc => compile-fail}/copy_null.rs (100%) rename tests/{compile-fail-norustc => compile-fail}/copy_unaligned.rs (100%) diff --git a/tests/compile-fail-norustc/copy_nonoverlapping.rs b/tests/compile-fail/copy_nonoverlapping.rs similarity index 100% rename from tests/compile-fail-norustc/copy_nonoverlapping.rs rename to tests/compile-fail/copy_nonoverlapping.rs diff --git a/tests/compile-fail-norustc/copy_null.rs b/tests/compile-fail/copy_null.rs similarity index 100% rename from tests/compile-fail-norustc/copy_null.rs rename to tests/compile-fail/copy_null.rs diff --git a/tests/compile-fail-norustc/copy_unaligned.rs b/tests/compile-fail/copy_unaligned.rs similarity index 100% rename from tests/compile-fail-norustc/copy_unaligned.rs rename to tests/compile-fail/copy_unaligned.rs diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 9394084ad34d..757e8c1a6472 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -108,13 +108,6 @@ fn run_pass_miri(opt: bool) { fn compile_fail_miri(opt: bool) { compile_fail("tests/compile-fail", &get_target(), opt); - if rustc_test_suite().is_none() { - // FIXME: Some tests disabled in rustc test suite because - // they run with a debug-assertion libstd which changes the errors. - // We should build our own libstd for testing, see - // . - compile_fail("tests/compile-fail-norustc", &get_target(), opt); - } } fn test_runner(_tests: &[&()]) { From 40d647a060d4da5a3d28d92c9a782b370ab3a4f0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Jul 2019 15:28:31 +0200 Subject: [PATCH 0968/5092] test-miri is no longer a thing --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index e21ee987125e..2eae254802c8 100644 --- a/README.md +++ b/README.md @@ -282,8 +282,7 @@ The setup for a local rustc works as follows: git clone https://github.com/rust-lang/rust/ rustc cd rustc cp config.toml.example config.toml -# Now edit `config.toml` and set `debug-assertions = true` and `test-miri = true`. -# The latter is important to build libstd with the right flags for miri. +# Now edit `config.toml` and set `debug-assertions = true`. # This step can take 30 minutes and more. ./x.py build src/rustc # If you change something, you can get a faster rebuild by doing From c4c2716f4e92550d20f6bec1c21f7ee90ddb5848 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 2 Aug 2019 08:09:22 +0200 Subject: [PATCH 0969/5092] make reborrow shallow, and fix tests for that --- src/stacked_borrows.rs | 46 +------------------ .../stacked_borrows/buggy_split_at_mut.rs | 2 +- .../return_invalid_mut_option.rs | 11 +++-- .../return_invalid_mut_tuple.rs | 5 +- .../return_invalid_shr_option.rs | 8 +++- .../return_invalid_shr_tuple.rs | 5 +- 6 files changed, 23 insertions(+), 54 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 0fe42f7974fb..4e2198a8cea0 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -12,7 +12,7 @@ use rustc::hir::{MutMutable, MutImmutable}; use rustc::mir::RetagKind; use crate::{ - InterpResult, InterpError, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, + InterpResult, InterpError, HelpersEvalContextExt, MemoryKind, MiriMemoryKind, RangeMap, AllocId, Pointer, Immediate, ImmTy, PlaceTy, MPlaceTy, }; @@ -632,54 +632,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - // We need a visitor to visit all references. However, that requires - // a `MemPlace`, so we have a fast path for reference types that - // avoids allocating. + // We only reborrow "bare" references/boxes. if let Some((mutbl, protector)) = qualify(place.layout.ty, kind) { // Fast path. let val = this.read_immediate(this.place_to_op(place)?)?; let val = this.retag_reference(val, mutbl, protector)?; this.write_immediate(val, place)?; - return Ok(()); - } - let place = this.force_allocation(place)?; - - let mut visitor = RetagVisitor { ecx: this, kind }; - visitor.visit_value(place)?; - - // The actual visitor. - struct RetagVisitor<'ecx, 'mir, 'tcx> { - ecx: &'ecx mut MiriEvalContext<'mir, 'tcx>, - kind: RetagKind, - } - impl<'ecx, 'mir, 'tcx> - MutValueVisitor<'mir, 'tcx, Evaluator<'tcx>> - for - RetagVisitor<'ecx, 'mir, 'tcx> - { - type V = MPlaceTy<'tcx, Tag>; - - #[inline(always)] - fn ecx(&mut self) -> &mut MiriEvalContext<'mir, 'tcx> { - &mut self.ecx - } - - // Primitives of reference type, that is the one thing we are interested in. - fn visit_primitive(&mut self, place: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> - { - // Cannot use `builtin_deref` because that reports *immutable* for `Box`, - // making it useless. - if let Some((mutbl, protector)) = qualify(place.layout.ty, self.kind) { - let val = self.ecx.read_immediate(place.into())?; - let val = self.ecx.retag_reference( - val, - mutbl, - protector - )?; - self.ecx.write_immediate(val, place.into())?; - } - Ok(()) - } } Ok(()) diff --git a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs index 812dd47ef1d9..798f68fa13cc 100644 --- a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs @@ -9,7 +9,6 @@ mod safe { assert!(mid <= len); (from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" - //~^ ERROR borrow stack from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) } } @@ -18,6 +17,7 @@ mod safe { fn main() { let mut array = [1,2,3,4]; let (a, b) = safe::split_at_mut(&mut array, 0); + //~^ ERROR borrow stack a[1] = 5; b[1] = 6; } diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs index 2eb2df81f5f1..1cb3f3f92026 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs @@ -1,11 +1,16 @@ // Make sure that we cannot return a `&mut` that got already invalidated, not even in an `Option`. +// Due to shallow reborrowing, the error only surfaces when we look into the `Option`. fn foo(x: &mut (i32, i32)) -> Option<&mut i32> { let xraw = x as *mut (i32, i32); - let ret = Some(unsafe { &mut (*xraw).1 }); + let ret = unsafe { &mut (*xraw).1 }; // let-bind to avoid 2phase + let ret = Some(ret); let _val = unsafe { *xraw }; // invalidate xref - ret //~ ERROR borrow stack + ret } fn main() { - foo(&mut (1, 2)); + match foo(&mut (1, 2)) { + Some(_x) => {}, //~ ERROR borrow stack + None => {}, + } } diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs index 8b73df4bd1ac..fbd9a6e5d269 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs @@ -1,11 +1,12 @@ // Make sure that we cannot return a `&mut` that got already invalidated, not even in a tuple. +// Due to shallow reborrowing, the error only surfaces when we look into the tuple. fn foo(x: &mut (i32, i32)) -> (&mut i32,) { let xraw = x as *mut (i32, i32); let ret = (unsafe { &mut (*xraw).1 },); let _val = unsafe { *xraw }; // invalidate xref - ret //~ ERROR borrow stack + ret } fn main() { - foo(&mut (1, 2)); + foo(&mut (1, 2)).0; //~ ERROR: borrow stack } diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr_option.rs b/tests/compile-fail/stacked_borrows/return_invalid_shr_option.rs index f3a35ca266c6..2d8527fa3fb4 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_shr_option.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_shr_option.rs @@ -1,11 +1,15 @@ // Make sure that we cannot return a `&` that got already invalidated, not even in an `Option`. +// Due to shallow reborrowing, the error only surfaces when we look into the `Option`. fn foo(x: &mut (i32, i32)) -> Option<&i32> { let xraw = x as *mut (i32, i32); let ret = Some(unsafe { &(*xraw).1 }); unsafe { *xraw = (42, 23) }; // unfreeze - ret //~ ERROR borrow stack + ret } fn main() { - foo(&mut (1, 2)); + match foo(&mut (1, 2)) { + Some(_x) => {}, //~ ERROR borrow stack + None => {}, + } } diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.rs b/tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.rs index 82723bade27d..d7494d6ee653 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.rs @@ -1,11 +1,12 @@ // Make sure that we cannot return a `&` that got already invalidated, not even in a tuple. +// Due to shallow reborrowing, the error only surfaces when we look into the tuple. fn foo(x: &mut (i32, i32)) -> (&i32,) { let xraw = x as *mut (i32, i32); let ret = (unsafe { &(*xraw).1 },); unsafe { *xraw = (42, 23) }; // unfreeze - ret //~ ERROR borrow stack + ret } fn main() { - foo(&mut (1, 2)); + foo(&mut (1, 2)).0; //~ ERROR borrow stack } From 3318657eaf0b8403317883a8cd68689d8a5c7d9a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 2 Aug 2019 08:15:52 +0200 Subject: [PATCH 0970/5092] test Ref/RefMut protector interactions --- tests/run-pass/refcell.rs | 33 ----------- tests/run-pass/stacked-borrows/refcell.rs | 68 +++++++++++++++++++++++ 2 files changed, 68 insertions(+), 33 deletions(-) delete mode 100644 tests/run-pass/refcell.rs create mode 100644 tests/run-pass/stacked-borrows/refcell.rs diff --git a/tests/run-pass/refcell.rs b/tests/run-pass/refcell.rs deleted file mode 100644 index 93cef1572a3e..000000000000 --- a/tests/run-pass/refcell.rs +++ /dev/null @@ -1,33 +0,0 @@ -use std::cell::RefCell; - -fn main() { - let c = RefCell::new(42); - { - let s1 = c.borrow(); - let _x: i32 = *s1; - let s2 = c.borrow(); - let _x: i32 = *s1; - let _y: i32 = *s2; - let _x: i32 = *s1; - let _y: i32 = *s2; - } - { - let mut m = c.borrow_mut(); - let _z: i32 = *m; - { - let s: &i32 = &*m; - let _x = *s; - } - *m = 23; - let _z: i32 = *m; - } - { - let s1 = c.borrow(); - let _x: i32 = *s1; - let s2 = c.borrow(); - let _x: i32 = *s1; - let _y: i32 = *s2; - let _x: i32 = *s1; - let _y: i32 = *s2; - } -} diff --git a/tests/run-pass/stacked-borrows/refcell.rs b/tests/run-pass/stacked-borrows/refcell.rs new file mode 100644 index 000000000000..0939a666193e --- /dev/null +++ b/tests/run-pass/stacked-borrows/refcell.rs @@ -0,0 +1,68 @@ +use std::cell::{RefCell, Ref, RefMut}; + +fn main() { + basic(); + ref_protector(); + ref_mut_protector(); +} + +fn basic() { + let c = RefCell::new(42); + { + let s1 = c.borrow(); + let _x: i32 = *s1; + let s2 = c.borrow(); + let _x: i32 = *s1; + let _y: i32 = *s2; + let _x: i32 = *s1; + let _y: i32 = *s2; + } + { + let mut m = c.borrow_mut(); + let _z: i32 = *m; + { + let s: &i32 = &*m; + let _x = *s; + } + *m = 23; + let _z: i32 = *m; + } + { + let s1 = c.borrow(); + let _x: i32 = *s1; + let s2 = c.borrow(); + let _x: i32 = *s1; + let _y: i32 = *s2; + let _x: i32 = *s1; + let _y: i32 = *s2; + } +} + +// Adding a Stacked Borrows protector for `Ref` would break this +fn ref_protector() { + fn break_it(rc: &RefCell, r: Ref<'_, i32>) { + // `r` has a shared reference, it is passed in as argument and hence + // a protector is added that marks this memory as read-only for the entire + // duration of this function. + drop(r); + // *oops* here we can mutate that memory. + *rc.borrow_mut() = 2; + } + + let rc = RefCell::new(0); + break_it(&rc, rc.borrow()) +} + +fn ref_mut_protector() { + fn break_it(rc: &RefCell, r: RefMut<'_, i32>) { + // `r` has a shared reference, it is passed in as argument and hence + // a protector is added that marks this memory as inaccessible for the entire + // duration of this function + drop(r); + // *oops* here we can mutate that memory. + *rc.borrow_mut() = 2; + } + + let rc = RefCell::new(0); + break_it(&rc, rc.borrow_mut()) +} From 30fb027f33e3c97489a7d7049d70ee876ac38c73 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 2 Aug 2019 08:38:22 +0200 Subject: [PATCH 0971/5092] comment --- src/stacked_borrows.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 4e2198a8cea0..c276f83de660 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -633,6 +633,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // We only reborrow "bare" references/boxes. + // Not traversing into fields helps with , + // but might also cost us optimization and analyses. We will have to experiment more with this. if let Some((mutbl, protector)) = qualify(place.layout.ty, kind) { // Fast path. let val = this.read_immediate(this.place_to_op(place)?)?; From 2973063fa32155873aaeb37a7399d3c592afda5c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 2 Aug 2019 14:26:15 +0200 Subject: [PATCH 0972/5092] test dangling ZST deref --- tests/compile-fail/dangling_zst_deref.rs | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/compile-fail/dangling_zst_deref.rs diff --git a/tests/compile-fail/dangling_zst_deref.rs b/tests/compile-fail/dangling_zst_deref.rs new file mode 100644 index 000000000000..0a8480675f3d --- /dev/null +++ b/tests/compile-fail/dangling_zst_deref.rs @@ -0,0 +1,7 @@ +fn main() { + let p = { + let b = Box::new(42); + &*b as *const i32 as *const () + }; + let _x = unsafe { *p }; //~ ERROR dangling pointer was dereferenced +} From 0dab3d5ee167aadaebe4b32b035f6b3dc581538d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 2 Aug 2019 18:02:54 +0200 Subject: [PATCH 0973/5092] honor CARGO env var (for rustc bootstrap) --- src/bin/cargo-miri.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index b46742efe72a..8dbb7573ba91 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -231,7 +231,14 @@ fn setup(ask_user: bool) { } else { println!("Installing xargo: `cargo install xargo -f`"); } - if !Command::new("cargo").args(&["install", "xargo", "-f"]).status().unwrap().success() { + + let mut cargo = if let Ok(val) = std::env::var("CARGO") { + // In rustc bootstrap, an env var tells us where to find cargo. + Command::new(val) + } else { + Command::new("cargo") + }; + if !cargo.args(&["install", "xargo", "-f"]).status().unwrap().success() { show_error(format!("Failed to install xargo")); } } From ff2001040f06bda894fb512684e34ea12deade6e Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 2 Aug 2019 13:42:10 -0500 Subject: [PATCH 0974/5092] Add shim for ldexp --- src/shims/foreign_items.rs | 12 ++++++++++-- tests/run-pass/intrinsics-math.rs | 4 ++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index bcfcda2fd01c..332132947823 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -603,7 +603,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?; } - + // underscore case for windows + "_ldexp" | "ldexp" => { + // FIXME: Using host floats. + let x = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); + let exp = this.read_scalar(args[1])?.to_i32()?; + // FIXME: We should use cmath if there are any imprecisions. + let n = x * 2.0f64.powi(exp); + this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?; + } // Some things needed for `sys::thread` initialization to go through. "signal" | "sigaction" | "sigaltstack" => { this.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?; @@ -973,4 +981,4 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } return Ok(None); } -} \ No newline at end of file +} diff --git a/tests/run-pass/intrinsics-math.rs b/tests/run-pass/intrinsics-math.rs index 20c0f6749488..9a7a70bd0092 100644 --- a/tests/run-pass/intrinsics-math.rs +++ b/tests/run-pass/intrinsics-math.rs @@ -85,4 +85,8 @@ pub fn main() { assert_approx_eq!(1.0f32.tan(), 1.557408f32); assert_approx_eq!(1.0f64.tan(), 1.557408f64); + extern { + fn ldexp(x: f64, n: i32) -> f64; + } + unsafe { assert_approx_eq!(ldexp(0.65f64, 3i32), 5.2f64); } } From 8071034b93ab1c363e45b72a5d3e53432c52f2b0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Aug 2019 10:25:55 +0200 Subject: [PATCH 0975/5092] fix for error refactoring --- src/eval.rs | 6 ++--- src/helpers.rs | 2 +- src/intptrcast.rs | 14 +++++------ src/machine.rs | 2 +- src/operator.rs | 29 +++++++++++----------- src/shims/dlsym.rs | 2 +- src/shims/foreign_items.rs | 49 +++++++++++++++++++------------------- src/shims/intrinsics.rs | 22 ++++++++--------- src/shims/tls.rs | 10 ++++---- src/stacked_borrows.rs | 18 +++++++------- 10 files changed, 77 insertions(+), 77 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index e688d3594718..837757c1ad3b 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -41,7 +41,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let main_mir = ecx.load_mir(main_instance.def)?; if !main_mir.return_ty().is_unit() || main_mir.arg_count != 0 { - return err!(Unimplemented( + throw_unsup!(Unimplemented( "miri does not support main functions without `fn()` type signatures" .to_owned(), )); @@ -60,7 +60,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let start_mir = ecx.load_mir(start_instance.def)?; if start_mir.arg_count != 3 { - return err!(AbiViolation(format!( + throw_unsup!(AbiViolation(format!( "'start' lang item should have three arguments, but has {}", start_mir.arg_count ))); @@ -200,7 +200,7 @@ pub fn eval_main<'tcx>( // Special treatment for some error kinds let msg = match e.kind { InterpError::Exit(code) => std::process::exit(code), - InterpError::NoMirFor(..) => + err_unsup!(NoMirFor(..)) => format!("{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", e), _ => e.to_string() }; diff --git a/src/helpers.rs b/src/helpers.rs index 3857020a71f8..d29cc021a1b0 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -42,7 +42,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) .ok_or_else(|| { let path = path.iter().map(|&s| s.to_owned()).collect(); - InterpError::PathNotFound(path).into() + err_unsup!(PathNotFound(path)).into() }) } diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 1247150cc119..b1e89f3819ae 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -43,19 +43,19 @@ impl<'mir, 'tcx> GlobalState { memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>, ) -> InterpResult<'tcx, Pointer> { if int == 0 { - return err!(InvalidNullPointerUsage); + throw_unsup!(InvalidNullPointerUsage); } let global_state = memory.extra.intptrcast.borrow(); - match global_state.int_to_ptr_map.binary_search_by_key(&int, |(addr, _)| *addr) { + Ok(match global_state.int_to_ptr_map.binary_search_by_key(&int, |(addr, _)| *addr) { Ok(pos) => { let (_, alloc_id) = global_state.int_to_ptr_map[pos]; // `int` is equal to the starting address for an allocation, the offset should be // zero. The pointer is untagged because it was created from a cast - Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged)) + Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged) }, - Err(0) => err!(DanglingPointerDeref), + Err(0) => throw_unsup!(DanglingPointerDeref), Err(pos) => { // This is the largest of the adresses smaller than `int`, // i.e. the greatest lower bound (glb) @@ -65,12 +65,12 @@ impl<'mir, 'tcx> GlobalState { // If the offset exceeds the size of the allocation, this access is illegal if offset <= memory.get(alloc_id)?.bytes.len() as u64 { // This pointer is untagged because it was created from a cast - Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged)) + Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged) } else { - err!(DanglingPointerDeref) + throw_unsup!(DanglingPointerDeref) } } - } + }) } pub fn ptr_to_int( diff --git a/src/machine.rs b/src/machine.rs index d50afec253e8..cdac9fb815cc 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -247,7 +247,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { let data = vec![0; size.bytes() as usize]; Allocation::from_bytes(&data, tcx.data_layout.pointer_align.abi) } - _ => return err!(Unimplemented( + _ => throw_unsup!(Unimplemented( format!("can't access foreign static: {}", link_name), )), }; diff --git a/src/operator.rs b/src/operator.rs index 1ce485682c77..dfe58037789c 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -94,7 +94,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { let right = right.to_scalar()?; debug_assert!(left.is_ptr() || right.is_ptr() || bin_op == Offset); - match bin_op { + Ok(match bin_op { Offset => { let pointee_ty = left_layout.ty .builtin_deref(true) @@ -105,7 +105,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { pointee_ty, right.to_isize(self)?, )?; - Ok((ptr, false)) + (ptr, false) } // These need both to be pointer, and fail if they are not in the same location Lt | Le | Gt | Ge | Sub if left.is_ptr() && right.is_ptr() => { @@ -130,10 +130,10 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { } _ => bug!("We already established it has to be one of these operators."), }; - Ok((Scalar::from_bool(res), false)) + (Scalar::from_bool(res), false) } else { // Both are pointers, but from different allocations. - err!(InvalidPointerMath) + throw_unsup!(InvalidPointerMath) } } Gt | Ge if left.is_ptr() && right.is_bits() => { @@ -151,10 +151,10 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { }; if result { // Definitely true! - Ok((Scalar::from_bool(true), false)) + (Scalar::from_bool(true), false) } else { // Sorry, can't tell. - err!(InvalidPointerMath) + throw_unsup!(InvalidPointerMath) } } // These work if the left operand is a pointer, and the right an integer @@ -165,7 +165,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { left.to_ptr().expect("we checked is_ptr"), right.to_bits(self.memory().pointer_size()).expect("we checked is_bits"), right_layout.abi.is_signed(), - ) + )? } // Commutative operators also work if the integer is on the left Add | BitAnd if left.is_bits() && right.is_ptr() => { @@ -175,11 +175,11 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { right.to_ptr().expect("we checked is_ptr"), left.to_bits(self.memory().pointer_size()).expect("we checked is_bits"), left_layout.abi.is_signed(), - ) + )? } // Nothing else works - _ => err!(InvalidPointerMath), - } + _ => throw_unsup!(InvalidPointerMath), + }) } fn ptr_eq( @@ -248,7 +248,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { let v = Scalar::from_uint((left.offset.bytes() as u128) & right, ptr_size); (v, false) } else { - return err!(ReadPointerAsBytes); + throw_unsup!(ReadPointerAsBytes); } } @@ -271,7 +271,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { false, ) } else { - return err!(ReadPointerAsBytes); + throw_unsup!(ReadPointerAsBytes); } } @@ -283,7 +283,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { right, if signed { "signed" } else { "unsigned" } ); - return err!(Unimplemented(msg)); + throw_unsup!(Unimplemented(msg)); } }) } @@ -298,12 +298,11 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { pointee_ty: Ty<'tcx>, offset: i64, ) -> InterpResult<'tcx, Scalar> { - use rustc::mir::interpret::InterpError::Panic; // FIXME: assuming here that type size is less than `i64::max_value()`. let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; let offset = offset .checked_mul(pointee_size) - .ok_or_else(|| Panic(PanicMessage::Overflow(mir::BinOp::Mul)))?; + .ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?; // Now let's see what kind of pointer this is. let ptr = if offset == 0 { match ptr { diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 602d8064e82e..005493096248 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -16,7 +16,7 @@ impl Dlsym { "getentropy" => Some(GetEntropy), "__pthread_get_minstack" => None, _ => - return err!(Unimplemented(format!( + throw_unsup!(Unimplemented(format!( "Unsupported dlsym: {}", name ))), }) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index bcfcda2fd01c..12baa79916ab 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -128,7 +128,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest: Option>, ret: Option, ) -> InterpResult<'tcx> { - use rustc::mir::interpret::InterpError::Panic; let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { @@ -142,15 +141,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // First: functions that diverge. match link_name { "__rust_start_panic" | "panic_impl" => { - return err!(MachineError("the evaluated program panicked".to_string())); + throw_unsup!(MachineError("the evaluated program panicked".to_string())); } "exit" | "ExitProcess" => { // it's really u32 for ExitProcess, but we have to put it into the `Exit` error variant anyway let code = this.read_scalar(args[0])?.to_i32()?; - return err!(Exit(code)); + return Err(InterpError::Exit(code).into()); } _ => if dest.is_none() { - return err!(Unimplemented( + throw_unsup!(Unimplemented( format!("can't call diverging foreign function: {}", link_name), )); } @@ -168,7 +167,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "calloc" => { let items = this.read_scalar(args[0])?.to_usize(this)?; let len = this.read_scalar(args[1])?.to_usize(this)?; - let size = items.checked_mul(len).ok_or_else(|| Panic(PanicMessage::Overflow(mir::BinOp::Mul)))?; + let size = items.checked_mul(len).ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?; let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C); this.write_scalar(res, dest)?; } @@ -178,13 +177,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let size = this.read_scalar(args[2])?.to_usize(this)?; // Align must be power of 2, and also at least ptr-sized (POSIX rules). if !align.is_power_of_two() { - return err!(HeapAllocNonPowerOfTwoAlignment(align)); + throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); } /* FIXME: This check is disabled because rustc violates it. See . if align < this.pointer_size().bytes() { - return err!(MachineError(format!( + throw_unsup!(MachineError(format!( "posix_memalign: alignment must be at least the size of a pointer, but is {}", align, ))); @@ -217,10 +216,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let size = this.read_scalar(args[0])?.to_usize(this)?; let align = this.read_scalar(args[1])?.to_usize(this)?; if size == 0 { - return err!(HeapAllocZeroBytes); + throw_unsup!(HeapAllocZeroBytes); } if !align.is_power_of_two() { - return err!(HeapAllocNonPowerOfTwoAlignment(align)); + throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); } let ptr = this.memory_mut() .allocate( @@ -234,10 +233,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let size = this.read_scalar(args[0])?.to_usize(this)?; let align = this.read_scalar(args[1])?.to_usize(this)?; if size == 0 { - return err!(HeapAllocZeroBytes); + throw_unsup!(HeapAllocZeroBytes); } if !align.is_power_of_two() { - return err!(HeapAllocNonPowerOfTwoAlignment(align)); + throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); } let ptr = this.memory_mut() .allocate( @@ -256,10 +255,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let old_size = this.read_scalar(args[1])?.to_usize(this)?; let align = this.read_scalar(args[2])?.to_usize(this)?; if old_size == 0 { - return err!(HeapAllocZeroBytes); + throw_unsup!(HeapAllocZeroBytes); } if !align.is_power_of_two() { - return err!(HeapAllocNonPowerOfTwoAlignment(align)); + throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); } let ptr = this.force_ptr(ptr)?; this.memory_mut().deallocate( @@ -274,10 +273,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let align = this.read_scalar(args[2])?.to_usize(this)?; let new_size = this.read_scalar(args[3])?.to_usize(this)?; if old_size == 0 || new_size == 0 { - return err!(HeapAllocZeroBytes); + throw_unsup!(HeapAllocZeroBytes); } if !align.is_power_of_two() { - return err!(HeapAllocNonPowerOfTwoAlignment(align)); + throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); } let align = Align::from_bytes(align).unwrap(); let new_ptr = this.memory_mut().reallocate( @@ -310,7 +309,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; } id => { - return err!(Unimplemented( + throw_unsup!(Unimplemented( format!("miri does not support syscall ID {}", id), )) } @@ -361,10 +360,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut args = this.frame().body.args_iter(); let arg_local = args.next().ok_or_else(|| - InterpError::AbiViolation( + err_unsup!(AbiViolation( "Argument to __rust_maybe_catch_panic does not take enough arguments." .to_owned(), - ), + )), )?; let arg_dest = this.local_place(arg_local)?; this.write_scalar(data, arg_dest)?; @@ -633,7 +632,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(result) = result { this.write_scalar(result, dest)?; } else { - return err!(Unimplemented( + throw_unsup!(Unimplemented( format!("Unimplemented sysconf name: {}", name), )); } @@ -662,14 +661,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This is `libc::pthread_key_t`. let key_type = args[0].layout.ty .builtin_deref(true) - .ok_or_else(|| InterpError::AbiViolation("wrong signature used for `pthread_key_create`: first argument must be a raw pointer.".to_owned()))? + .ok_or_else(|| err_unsup!( + AbiViolation("wrong signature used for `pthread_key_create`: first argument must be a raw pointer.".to_owned()) + ))? .ty; let key_layout = this.layout_of(key_type)?; // Create key and write it into the memory where `key_ptr` wants it. let key = this.machine.tls.create_tls_key(dtor) as u128; if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) { - return err!(OutOfTls); + throw_unsup!(OutOfTls); } let key_ptr = this.memory().check_ptr_access(key_ptr, key_layout.size, key_layout.align.abi)? @@ -728,7 +729,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We don't support threading. (Also for Windows.) "pthread_create" | "CreateThread" => { - return err!(Unimplemented(format!("Miri does not support threading"))); + throw_unsup!(Unimplemented(format!("Miri does not support threading"))); } // Stub out calls for condvar, mutex and rwlock, to just return `0`. @@ -869,7 +870,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Figure out how large a TLS key actually is. This is `c::DWORD`. if dest.layout.size.bits() < 128 && key >= (1u128 << dest.layout.size.bits() as u128) { - return err!(OutOfTls); + throw_unsup!(OutOfTls); } this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } @@ -947,7 +948,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We can't execute anything else. _ => { - return err!(Unimplemented( + throw_unsup!(Unimplemented( format!("can't call foreign function: {}", link_name), )); } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 6038950bad9f..71027a65b054 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -44,7 +44,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "assume" => { let cond = this.read_scalar(args[0])?.to_bool()?; if !cond { - return err!(AssumptionNotHeld); + throw_unsup!(AssumptionNotHeld); } } @@ -133,7 +133,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_xsub_relaxed" => { let ptr = this.deref_operand(args[0])?; if !ptr.layout.ty.is_integral() { - return err!(Unimplemented(format!("Atomic arithmetic operations only work on integer types"))); + throw_unsup!(Unimplemented(format!("Atomic arithmetic operations only work on integer types"))); } let rhs = this.read_immediate(args[1])?; let old = this.read_immediate(ptr.into())?; @@ -278,11 +278,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.binary_op(mir::BinOp::Rem, a, b)?.0.to_bits(dest.layout.size)? != 0 { // Check if `b` is -1, which is the "min_value / -1" case. let minus1 = Scalar::from_int(-1, dest.layout.size); - return if b.to_scalar().unwrap() == minus1 { - err!(Intrinsic(format!("exact_div: result of dividing MIN by -1 cannot be represented"))) + return Err(if b.to_scalar().unwrap() == minus1 { + err_unsup!(Intrinsic(format!("exact_div: result of dividing MIN by -1 cannot be represented"))) } else { - err!(Intrinsic(format!("exact_div: {:?} cannot be divided by {:?} without remainder", *a, *b))) - }; + err_unsup!(Intrinsic(format!("exact_div: {:?} cannot be divided by {:?} without remainder", *a, *b))) + }.into()); } this.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; }, @@ -350,7 +350,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ty = substs.type_at(0); let layout = this.layout_of(ty)?; if layout.abi.is_uninhabited() { - return err!(Intrinsic(format!("Trying to instantiate uninhabited type {}", ty))) + throw_unsup!(Intrinsic(format!("Trying to instantiate uninhabited type {}", ty))) } } @@ -444,7 +444,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let r = this.read_immediate(args[1])?; let rval = r.to_scalar()?.to_bits(args[1].layout.size)?; if rval == 0 { - return err!(Intrinsic(format!("Division by 0 in unchecked_div"))); + throw_unsup!(Intrinsic(format!("Division by 0 in unchecked_div"))); } this.binop_ignore_overflow( mir::BinOp::Div, @@ -459,7 +459,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let r = this.read_immediate(args[1])?; let rval = r.to_scalar()?.to_bits(args[1].layout.size)?; if rval == 0 { - return err!(Intrinsic(format!("Division by 0 in unchecked_rem"))); + throw_unsup!(Intrinsic(format!("Division by 0 in unchecked_rem"))); } this.binop_ignore_overflow( mir::BinOp::Rem, @@ -480,7 +480,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; let (res, overflowed) = this.binary_op(op, l, r)?; if overflowed { - return err!(Intrinsic(format!("Overflowing arithmetic in {}", intrinsic_name.get()))); + throw_unsup!(Intrinsic(format!("Overflowing arithmetic in {}", intrinsic_name.get()))); } this.write_scalar(res, dest)?; } @@ -504,7 +504,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - name => return err!(Unimplemented(format!("unimplemented intrinsic: {}", name))), + name => throw_unsup!(Unimplemented(format!("unimplemented intrinsic: {}", name))), } Ok(()) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index abe6dd958693..145d2b3e7891 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -6,7 +6,7 @@ use rustc_target::abi::LayoutOf; use rustc::{ty, ty::layout::HasDataLayout}; use crate::{ - InterpResult, InterpError, StackPopCleanup, + InterpResult, StackPopCleanup, MPlaceTy, Scalar, Tag, HelpersEvalContextExt, }; @@ -64,7 +64,7 @@ impl<'tcx> TlsData<'tcx> { trace!("TLS key {} removed", key); Ok(()) } - None => err!(TlsOutOfBounds), + None => throw_unsup!(TlsOutOfBounds), } } @@ -78,7 +78,7 @@ impl<'tcx> TlsData<'tcx> { trace!("TLS key {} loaded: {:?}", key, data); Ok(data.unwrap_or_else(|| Scalar::ptr_null(cx).into())) } - None => err!(TlsOutOfBounds), + None => throw_unsup!(TlsOutOfBounds), } } @@ -89,7 +89,7 @@ impl<'tcx> TlsData<'tcx> { *data = new_data; Ok(()) } - None => err!(TlsOutOfBounds), + None => throw_unsup!(TlsOutOfBounds), } } @@ -158,7 +158,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx StackPopCleanup::None { cleanup: true }, )?; let arg_local = this.frame().body.args_iter().next().ok_or_else( - || InterpError::AbiViolation("TLS dtor does not take enough arguments.".to_owned()), + || err_unsup!(AbiViolation("TLS dtor does not take enough arguments.".to_owned())), )?; let dest = this.local_place(arg_local)?; this.write_scalar(ptr, dest)?; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index c276f83de660..5ef934b9922b 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -12,7 +12,7 @@ use rustc::hir::{MutMutable, MutImmutable}; use rustc::mir::RetagKind; use crate::{ - InterpResult, InterpError, HelpersEvalContextExt, + InterpResult, HelpersEvalContextExt, MemoryKind, MiriMemoryKind, RangeMap, AllocId, Pointer, Immediate, ImmTy, PlaceTy, MPlaceTy, }; @@ -273,12 +273,12 @@ impl<'tcx> Stack { if let Some(call) = item.protector { if global.is_active(call) { if let Some(tag) = tag { - return err!(MachineError(format!( + throw_unsup!(MachineError(format!( "not granting access to tag {:?} because incompatible item is protected: {:?}", tag, item ))); } else { - return err!(MachineError(format!( + throw_unsup!(MachineError(format!( "deallocating while item is protected: {:?}", item ))); } @@ -299,10 +299,10 @@ impl<'tcx> Stack { // Step 1: Find granting item. let granting_idx = self.find_granting(access, tag) - .ok_or_else(|| InterpError::MachineError(format!( + .ok_or_else(|| err_unsup!(MachineError(format!( "no item granting {} to tag {:?} found in borrow stack", access, tag, - )))?; + ))))?; // Step 2: Remove incompatible items above them. Make sure we do not remove protected // items. Behavior differs for reads and writes. @@ -346,10 +346,10 @@ impl<'tcx> Stack { ) -> InterpResult<'tcx> { // Step 1: Find granting item. self.find_granting(AccessKind::Write, tag) - .ok_or_else(|| InterpError::MachineError(format!( + .ok_or_else(|| err_unsup!(MachineError(format!( "no item granting write access for deallocation to tag {:?} found in borrow stack", tag, - )))?; + ))))?; // Step 2: Remove all items. Also checks for protectors. for item in self.borrows.drain(..).rev() { @@ -378,9 +378,9 @@ impl<'tcx> Stack { // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. let granting_idx = self.find_granting(access, derived_from) - .ok_or_else(|| InterpError::MachineError(format!( + .ok_or_else(|| err_unsup!(MachineError(format!( "trying to reborrow for {:?}, but parent tag {:?} does not have an appropriate item in the borrow stack", new.perm, derived_from, - )))?; + ))))?; // Compute where to put the new item. // Either way, we ensure that we insert the new item in a way such that between From 312b546026c59549e860cf939bc20f1117f5c93f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Aug 2019 10:26:15 +0200 Subject: [PATCH 0976/5092] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 5178503f1041..8fbf6d7425bb 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8b94e9e9188b65df38a5f1ae723617dc2dfb3155 +d7270712cb446aad0817040bbca73a8d024f67b0 From e71ca965b9bfda52f6720e718a631c324c35b196 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Aug 2019 13:53:02 +0200 Subject: [PATCH 0977/5092] also let bootstrap tell us where to find xargo --- src/bin/cargo-miri.rs | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 8dbb7573ba91..351da554b7bf 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -162,8 +162,26 @@ fn test_sysroot_consistency() { } } +fn cargo() -> Command { + if let Ok(val) = std::env::var("CARGO") { + // Bootstrap tells us where to find cargo + Command::new(val) + } else { + Command::new("cargo") + } +} + +fn xargo() -> Command { + if let Ok(val) = std::env::var("XARGO") { + // Bootstrap tells us where to find xargo + Command::new(val) + } else { + Command::new("xargo") + } +} + fn xargo_version() -> Option<(u32, u32, u32)> { - let out = Command::new("xargo").arg("--version").output().ok()?; + let out = xargo().arg("--version").output().ok()?; if !out.status.success() { return None; } @@ -224,21 +242,14 @@ fn setup(ask_user: bool) { } // First, we need xargo. - let xargo = xargo_version(); - if xargo.map_or(true, |v| v < (0, 3, 14)) { + if xargo_version().map_or(true, |v| v < (0, 3, 14)) { if ask_user { ask("It seems you do not have a recent enough xargo installed. I will run `cargo install xargo -f`. Proceed?"); } else { println!("Installing xargo: `cargo install xargo -f`"); } - let mut cargo = if let Ok(val) = std::env::var("CARGO") { - // In rustc bootstrap, an env var tells us where to find cargo. - Command::new(val) - } else { - Command::new("cargo") - }; - if !cargo.args(&["install", "xargo", "-f"]).status().unwrap().success() { + if !cargo().args(&["install", "xargo", "-f"]).status().unwrap().success() { show_error(format!("Failed to install xargo")); } } @@ -294,7 +305,7 @@ path = "lib.rs" // Run xargo. let target = get_arg_flag_value("--target"); let print_env = !ask_user && has_arg_flag("--env"); // whether we just print the necessary environment variable - let mut command = Command::new("xargo"); + let mut command = xargo(); command.arg("build").arg("-q") .current_dir(&dir) .env("RUSTFLAGS", miri::miri_default_args().join(" ")) @@ -383,7 +394,7 @@ fn in_cargo_miri() { // Now we run `cargo rustc $FLAGS $ARGS`, giving the user the // change to add additional arguments. `FLAGS` is set to identify // this target. The user gets to control what gets actually passed to Miri. - let mut cmd = Command::new("cargo"); + let mut cmd = cargo(); cmd.arg("rustc"); match (subcommand, kind.as_str()) { (MiriCommand::Run, "bin") => { From bb6a91dc949218c4cc4990cc6f50bbdd58df7648 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Jul 2019 16:17:49 +0200 Subject: [PATCH 0978/5092] adjust for ptr_op now being called type-based --- src/machine.rs | 4 ++-- src/operator.rs | 48 ++++++++++++++++++++++-------------------------- 2 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index cdac9fb815cc..7fa79d822c35 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -179,13 +179,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } #[inline(always)] - fn ptr_op( + fn binary_ptr_op( ecx: &rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>, bin_op: mir::BinOp, left: ImmTy<'tcx, Tag>, right: ImmTy<'tcx, Tag>, ) -> InterpResult<'tcx, (Scalar, bool)> { - ecx.ptr_op(bin_op, left, right) + ecx.binary_ptr_op(bin_op, left, right) } fn box_alloc( diff --git a/src/operator.rs b/src/operator.rs index dfe58037789c..d564b5f19f95 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -9,7 +9,7 @@ pub trait EvalContextExt<'tcx> { ptr: Pointer ) -> InterpResult<'tcx>; - fn ptr_op( + fn binary_ptr_op( &self, bin_op: mir::BinOp, left: ImmTy<'tcx, Tag>, @@ -46,7 +46,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { ptr.check_in_alloc(size, CheckInAllocMsg::InboundsTest) } - fn ptr_op( + fn binary_ptr_op( &self, bin_op: mir::BinOp, left: ImmTy<'tcx, Tag>, @@ -56,21 +56,6 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); - // Treat everything of integer *type* at integer *value*. - if left.layout.ty.is_integral() { - // This is actually an integer operation, so dispatch back to the core engine. - // TODO: Once intptrcast is the default, librustc_mir should never even call us - // for integer types. - assert!(right.layout.ty.is_integral()); - let l_bits = self.force_bits(left.imm.to_scalar()?, left.layout.size)?; - let r_bits = self.force_bits(right.imm.to_scalar()?, right.layout.size)?; - - let left = ImmTy::from_scalar(Scalar::from_uint(l_bits, left.layout.size), left.layout); - let right = ImmTy::from_scalar(Scalar::from_uint(r_bits, left.layout.size), right.layout); - - return self.binary_op(bin_op, left, right); - } - // Operations that support fat pointers match bin_op { Eq | Ne => { @@ -92,7 +77,6 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { let left = left.to_scalar()?; let right_layout = right.layout; let right = right.to_scalar()?; - debug_assert!(left.is_ptr() || right.is_ptr() || bin_op == Offset); Ok(match bin_op { Offset => { @@ -109,8 +93,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { } // These need both to be pointer, and fail if they are not in the same location Lt | Le | Gt | Ge | Sub if left.is_ptr() && right.is_ptr() => { - let left = left.to_ptr().expect("we checked is_ptr"); - let right = right.to_ptr().expect("we checked is_ptr"); + let left = left.assert_ptr(); + let right = right.assert_ptr(); if left.alloc_id == right.alloc_id { let res = match bin_op { Lt => left.offset < right.offset, @@ -136,10 +120,22 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { throw_unsup!(InvalidPointerMath) } } + Lt | Le | Gt | Ge if left.is_bits() && right.is_bits() => { + let left = left.assert_bits(self.memory().pointer_size()); + let right = right.assert_bits(self.memory().pointer_size()); + let res = match bin_op { + Lt => left < right, + Le => left <= right, + Gt => left > right, + Ge => left >= right, + _ => bug!("We already established it has to be one of these operators."), + }; + Ok((Scalar::from_bool(res), false)) + } Gt | Ge if left.is_ptr() && right.is_bits() => { // "ptr >[=] integer" can be tested if the integer is small enough. - let left = left.to_ptr().expect("we checked is_ptr"); - let right = right.to_bits(self.memory().pointer_size()).expect("we checked is_bits"); + let left = left.assert_ptr(); + let right = right.assert_bits(self.memory().pointer_size()); let (_alloc_size, alloc_align) = self.memory() .get_size_and_align(left.alloc_id, AllocCheck::MaybeDead) .expect("alloc info with MaybeDead cannot fail"); @@ -162,8 +158,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { // Cast to i128 is fine as we checked the kind to be ptr-sized self.ptr_int_arithmetic( bin_op, - left.to_ptr().expect("we checked is_ptr"), - right.to_bits(self.memory().pointer_size()).expect("we checked is_bits"), + left.assert_ptr(), + right.assert_bits(self.memory().pointer_size()), right_layout.abi.is_signed(), )? } @@ -172,8 +168,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { // This is a commutative operation, just swap the operands self.ptr_int_arithmetic( bin_op, - right.to_ptr().expect("we checked is_ptr"), - left.to_bits(self.memory().pointer_size()).expect("we checked is_bits"), + right.assert_ptr(), + left.assert_bits(self.memory().pointer_size()), left_layout.abi.is_signed(), )? } From 82da68c5caca6b534d77c01cbcf9d1ed0a6ef496 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Jul 2019 16:22:48 +0200 Subject: [PATCH 0979/5092] implement all ptr comparisons through integer casts --- src/operator.rs | 225 ++++++------------------------------------------ 1 file changed, 24 insertions(+), 201 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index d564b5f19f95..f047f4f4fad0 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,4 +1,4 @@ -use rustc::ty::{Ty, layout::{Size, LayoutOf}}; +use rustc::ty::{Ty, layout::LayoutOf}; use rustc::mir; use crate::*; @@ -16,14 +16,6 @@ pub trait EvalContextExt<'tcx> { right: ImmTy<'tcx, Tag>, ) -> InterpResult<'tcx, (Scalar, bool)>; - fn ptr_int_arithmetic( - &self, - bin_op: mir::BinOp, - left: Pointer, - right: u128, - signed: bool, - ) -> InterpResult<'tcx, (Scalar, bool)>; - fn ptr_eq( &self, left: Scalar, @@ -56,9 +48,9 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); - // Operations that support fat pointers - match bin_op { + Ok(match bin_op { Eq | Ne => { + // This supports fat pointers. let eq = match (*left, *right) { (Immediate::Scalar(left), Immediate::Scalar(right)) => self.ptr_eq(left.not_undef()?, right.not_undef()?)?, @@ -67,62 +59,14 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { self.ptr_eq(left2.not_undef()?, right2.not_undef()?)?, _ => bug!("Type system should not allow comparing Scalar with ScalarPair"), }; - return Ok((Scalar::from_bool(if bin_op == Eq { eq } else { !eq }), false)); + (Scalar::from_bool(if bin_op == Eq { eq } else { !eq }), false) } - _ => {}, - } - // Now we expect no more fat pointers. - let left_layout = left.layout; - let left = left.to_scalar()?; - let right_layout = right.layout; - let right = right.to_scalar()?; - - Ok(match bin_op { - Offset => { - let pointee_ty = left_layout.ty - .builtin_deref(true) - .expect("Offset called on non-ptr type") - .ty; - let ptr = self.pointer_offset_inbounds( - left, - pointee_ty, - right.to_isize(self)?, - )?; - (ptr, false) - } - // These need both to be pointer, and fail if they are not in the same location - Lt | Le | Gt | Ge | Sub if left.is_ptr() && right.is_ptr() => { - let left = left.assert_ptr(); - let right = right.assert_ptr(); - if left.alloc_id == right.alloc_id { - let res = match bin_op { - Lt => left.offset < right.offset, - Le => left.offset <= right.offset, - Gt => left.offset > right.offset, - Ge => left.offset >= right.offset, - Sub => { - // subtract the offsets - let left_offset = Scalar::from_uint(left.offset.bytes(), self.memory().pointer_size()); - let right_offset = Scalar::from_uint(right.offset.bytes(), self.memory().pointer_size()); - let layout = self.layout_of(self.tcx.types.usize)?; - return self.binary_op( - Sub, - ImmTy::from_scalar(left_offset, layout), - ImmTy::from_scalar(right_offset, layout), - ) - } - _ => bug!("We already established it has to be one of these operators."), - }; - (Scalar::from_bool(res), false) - } else { - // Both are pointers, but from different allocations. - throw_unsup!(InvalidPointerMath) - } - } - Lt | Le | Gt | Ge if left.is_bits() && right.is_bits() => { - let left = left.assert_bits(self.memory().pointer_size()); - let right = right.assert_bits(self.memory().pointer_size()); + Lt | Le | Gt | Ge => { + // Just compare the integers. + // TODO: Do we really want to *always* do that, even when comparing two live in-bounds pointers? + let left = self.force_bits(left.to_scalar()?, left.layout.size)?; + let right = self.force_bits(right.to_scalar()?, right.layout.size)?; let res = match bin_op { Lt => left < right, Le => left <= right, @@ -130,51 +74,23 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { Ge => left >= right, _ => bug!("We already established it has to be one of these operators."), }; - Ok((Scalar::from_bool(res), false)) + (Scalar::from_bool(res), false) } - Gt | Ge if left.is_ptr() && right.is_bits() => { - // "ptr >[=] integer" can be tested if the integer is small enough. - let left = left.assert_ptr(); - let right = right.assert_bits(self.memory().pointer_size()); - let (_alloc_size, alloc_align) = self.memory() - .get_size_and_align(left.alloc_id, AllocCheck::MaybeDead) - .expect("alloc info with MaybeDead cannot fail"); - let min_ptr_val = u128::from(alloc_align.bytes()) + u128::from(left.offset.bytes()); - let result = match bin_op { - Gt => min_ptr_val > right, - Ge => min_ptr_val >= right, - _ => bug!(), - }; - if result { - // Definitely true! - (Scalar::from_bool(true), false) - } else { - // Sorry, can't tell. - throw_unsup!(InvalidPointerMath) - } + + Offset => { + let pointee_ty = left.layout.ty + .builtin_deref(true) + .expect("Offset called on non-ptr type") + .ty; + let ptr = self.pointer_offset_inbounds( + left.to_scalar()?, + pointee_ty, + right.to_scalar()?.to_isize(self)?, + )?; + (ptr, false) } - // These work if the left operand is a pointer, and the right an integer - Add | BitAnd | Sub | Rem if left.is_ptr() && right.is_bits() => { - // Cast to i128 is fine as we checked the kind to be ptr-sized - self.ptr_int_arithmetic( - bin_op, - left.assert_ptr(), - right.assert_bits(self.memory().pointer_size()), - right_layout.abi.is_signed(), - )? - } - // Commutative operators also work if the integer is on the left - Add | BitAnd if left.is_bits() && right.is_ptr() => { - // This is a commutative operation, just swap the operands - self.ptr_int_arithmetic( - bin_op, - right.assert_ptr(), - left.assert_bits(self.memory().pointer_size()), - left_layout.abi.is_signed(), - )? - } - // Nothing else works - _ => throw_unsup!(InvalidPointerMath), + + _ => bug!("Invalid operator on pointers: {:?}", bin_op) }) } @@ -191,99 +107,6 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { Ok(left == right) } - fn ptr_int_arithmetic( - &self, - bin_op: mir::BinOp, - left: Pointer, - right: u128, - signed: bool, - ) -> InterpResult<'tcx, (Scalar, bool)> { - use rustc::mir::BinOp::*; - - fn map_to_primval((res, over): (Pointer, bool)) -> (Scalar, bool) { - (Scalar::Ptr(res), over) - } - - Ok(match bin_op { - Sub => - // The only way this can overflow is by underflowing, so signdeness of the right - // operands does not matter. - map_to_primval(left.overflowing_signed_offset(-(right as i128), self)), - Add if signed => - map_to_primval(left.overflowing_signed_offset(right as i128, self)), - Add if !signed => - map_to_primval(left.overflowing_offset(Size::from_bytes(right as u64), self)), - - BitAnd if !signed => { - let ptr_base_align = self.memory().get_size_and_align(left.alloc_id, AllocCheck::MaybeDead) - .expect("alloc info with MaybeDead cannot fail") - .1.bytes(); - let base_mask = { - // FIXME: use `interpret::truncate`, once that takes a `Size` instead of a `Layout`. - let shift = 128 - self.memory().pointer_size().bits(); - let value = !(ptr_base_align as u128 - 1); - // Truncate (shift left to drop out leftover values, shift right to fill with zeroes). - (value << shift) >> shift - }; - let ptr_size = self.memory().pointer_size(); - trace!("ptr BitAnd, align {}, operand {:#010x}, base_mask {:#010x}", - ptr_base_align, right, base_mask); - if right & base_mask == base_mask { - // Case 1: the base address bits are all preserved, i.e., right is all-1 there. - let offset = (left.offset.bytes() as u128 & right) as u64; - ( - Scalar::Ptr(Pointer::new_with_tag( - left.alloc_id, - Size::from_bytes(offset), - left.tag, - )), - false, - ) - } else if right & base_mask == 0 { - // Case 2: the base address bits are all taken away, i.e., right is all-0 there. - let v = Scalar::from_uint((left.offset.bytes() as u128) & right, ptr_size); - (v, false) - } else { - throw_unsup!(ReadPointerAsBytes); - } - } - - Rem if !signed => { - // Doing modulo a divisor of the alignment is allowed. - // (Intuition: modulo a divisor leaks less information.) - let ptr_base_align = self.memory().get_size_and_align(left.alloc_id, AllocCheck::MaybeDead) - .expect("alloc info with MaybeDead cannot fail") - .1.bytes(); - let right = right as u64; - let ptr_size = self.memory().pointer_size(); - if right == 1 { - // Modulo 1 is always 0. - (Scalar::from_uint(0u32, ptr_size), false) - } else if ptr_base_align % right == 0 { - // The base address would be cancelled out by the modulo operation, so we can - // just take the modulo of the offset. - ( - Scalar::from_uint((left.offset.bytes() % right) as u128, ptr_size), - false, - ) - } else { - throw_unsup!(ReadPointerAsBytes); - } - } - - _ => { - let msg = format!( - "unimplemented binary op on pointer {:?}: {:?}, {:?} ({})", - bin_op, - left, - right, - if signed { "signed" } else { "unsigned" } - ); - throw_unsup!(Unimplemented(msg)); - } - }) - } - /// Raises an error if the offset moves the pointer outside of its allocation. /// We consider ZSTs their own huge allocation that doesn't overlap with anything (and nothing /// moves in there because the size is 0). We also consider the NULL pointer its own separate From 773f6aeb4ca07711330c5ab2cdec1c50cba4b9c8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Jul 2019 16:25:12 +0200 Subject: [PATCH 0980/5092] remove some compile-fail tests that now work --- .../pointers_to_different_allocations_are_unorderable.rs | 7 ------- tests/compile-fail/ptr_ge_integer.rs | 7 ------- 2 files changed, 14 deletions(-) delete mode 100644 tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs delete mode 100644 tests/compile-fail/ptr_ge_integer.rs diff --git a/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs b/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs deleted file mode 100644 index 124f84de5bf4..000000000000 --- a/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn main() { - let x: *const u8 = &1; - let y: *const u8 = &2; - if x < y { //~ ERROR attempted to do invalid arithmetic on pointers - unreachable!() - } -} diff --git a/tests/compile-fail/ptr_ge_integer.rs b/tests/compile-fail/ptr_ge_integer.rs deleted file mode 100644 index 43160249c363..000000000000 --- a/tests/compile-fail/ptr_ge_integer.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn main() { - let b = Box::new(0); - let x = &*b as *const i32; - // We cannot test if this is >= 64. After all, depending on the base address, that - // might or might not be the case. - assert!(x >= 64 as *const i32); //~ ERROR invalid arithmetic on pointers -} From 61d8a4e101ba7822d4b86bdb548adb5bbc96e461 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Jul 2019 20:42:53 +0200 Subject: [PATCH 0981/5092] simplify code --- src/shims/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 71027a65b054..7a213a805996 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -306,7 +306,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match dest.layout.abi { layout::Abi::Scalar(ref s) => { let x = Scalar::from_int(0, s.value.size(this)); - this.write_immediate(Immediate::Scalar(x.into()), dest)?; + this.write_scalar(x, dest)?; } layout::Abi::ScalarPair(ref s1, ref s2) => { let x = Scalar::from_int(0, s1.value.size(this)); From 5efacf636baba76bec2255e3d3312f5d5c81018f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Aug 2019 15:15:28 +0200 Subject: [PATCH 0982/5092] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 8fbf6d7425bb..f54537d33b93 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d7270712cb446aad0817040bbca73a8d024f67b0 +8e917f48382c6afaf50568263b89d35fba5d98e4 From ab22da8ce8b08f06e01e325c277f19072717fe9c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Aug 2019 16:59:30 +0200 Subject: [PATCH 0983/5092] annotate some unwraps with better messages --- src/bin/cargo-miri.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 351da554b7bf..72bc630e7fa5 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -249,7 +249,10 @@ fn setup(ask_user: bool) { println!("Installing xargo: `cargo install xargo -f`"); } - if !cargo().args(&["install", "xargo", "-f"]).status().unwrap().success() { + if !cargo().args(&["install", "xargo", "-f"]).status() + .expect("failed to install xargo") + .success() + { show_error(format!("Failed to install xargo")); } } @@ -257,7 +260,9 @@ fn setup(ask_user: bool) { // Then, unless `XARGO_RUST_SRC` is set, we also need rust-src. // Let's see if it is already installed. if std::env::var("XARGO_RUST_SRC").is_err() { - let sysroot = Command::new("rustc").args(&["--print", "sysroot"]).output().unwrap().stdout; + let sysroot = Command::new("rustc").args(&["--print", "sysroot"]).output() + .expect("failed to get rustc sysroot") + .stdout; let sysroot = std::str::from_utf8(&sysroot).unwrap(); let src = Path::new(sysroot.trim_end_matches('\n')).join("lib").join("rustlib").join("src"); if !src.exists() { @@ -266,7 +271,10 @@ fn setup(ask_user: bool) { } else { println!("Installing rust-src component: `rustup component add rust-src`"); } - if !Command::new("rustup").args(&["component", "add", "rust-src"]).status().unwrap().success() { + if !Command::new("rustup").args(&["component", "add", "rust-src"]).status() + .expect("failed to install rust-src component") + .success() + { show_error(format!("Failed to install rust-src component")); } } @@ -313,7 +321,9 @@ path = "lib.rs" if let Some(ref target) = target { command.arg("--target").arg(&target); } - if !command.status().unwrap().success() + if !command.status() + .expect("failed to run xargo") + .success() { show_error(format!("Failed to run xargo")); } From 10f46336af2dea648c3b2ecf999d789d33bbfdd0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Aug 2019 17:20:16 +0200 Subject: [PATCH 0984/5092] set RUSTC_DEBUG_ASSERTIONS for when we are in bootstrap --- src/bin/cargo-miri.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 72bc630e7fa5..1c0d23336e61 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -310,17 +310,21 @@ version = "0.0.0" path = "lib.rs" "#).unwrap(); File::create(dir.join("lib.rs")).unwrap(); - // Run xargo. + // Prepare xargo invocation. let target = get_arg_flag_value("--target"); let print_env = !ask_user && has_arg_flag("--env"); // whether we just print the necessary environment variable let mut command = xargo(); - command.arg("build").arg("-q") - .current_dir(&dir) - .env("RUSTFLAGS", miri::miri_default_args().join(" ")) - .env("XARGO_HOME", dir.to_str().unwrap()); + command.arg("build").arg("-q"); + command.current_dir(&dir); + command.env("RUSTFLAGS", miri::miri_default_args().join(" ")); + command.env("XARGO_HOME", dir.to_str().unwrap()); + // In bootstrap, make sure we don't get debug assertons into our libstd. + command.env("RUSTC_DEBUG_ASSERTIONS", "false"); + // Handle target flag. if let Some(ref target) = target { command.arg("--target").arg(&target); } + // Finally run it! if !command.status() .expect("failed to run xargo") .success() From bff6b05424e9cf1a9b9afc9f5d6953ba4f1c0ea6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Aug 2019 17:27:50 +0200 Subject: [PATCH 0985/5092] more consistent test name --- .../compile-fail/{copy_nonoverlapping.rs => copy_overlapping.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/compile-fail/{copy_nonoverlapping.rs => copy_overlapping.rs} (100%) diff --git a/tests/compile-fail/copy_nonoverlapping.rs b/tests/compile-fail/copy_overlapping.rs similarity index 100% rename from tests/compile-fail/copy_nonoverlapping.rs rename to tests/compile-fail/copy_overlapping.rs From c4cea035e670eddc1afb0b78a6cdd37cb58c8fb7 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 3 Aug 2019 10:51:23 -0500 Subject: [PATCH 0986/5092] Formatting --- src/shims/foreign_items.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 332132947823..3e3266b74a07 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -612,6 +612,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let n = x * 2.0f64.powi(exp); this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?; } + // Some things needed for `sys::thread` initialization to go through. "signal" | "sigaction" | "sigaltstack" => { this.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?; From f65e7cd2d1a99618c3225f1a6deb424e5bba7dfa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Aug 2019 20:31:33 +0200 Subject: [PATCH 0987/5092] adjust for rustc changes --- rust-version | 2 +- src/eval.rs | 9 ++++----- src/machine.rs | 4 +--- src/shims/dlsym.rs | 4 +--- src/shims/foreign_items.rs | 38 +++++++++++++------------------------- src/shims/intrinsics.rs | 16 ++++++++-------- src/shims/tls.rs | 2 +- src/stacked_borrows.rs | 14 +++++++------- 8 files changed, 36 insertions(+), 53 deletions(-) diff --git a/rust-version b/rust-version index f54537d33b93..94c6f5e4b8c9 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8e917f48382c6afaf50568263b89d35fba5d98e4 +a45743345659c775b01484574af2818c46a2cb03 diff --git a/src/eval.rs b/src/eval.rs index 837757c1ad3b..bc9d97b0280f 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -41,10 +41,9 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let main_mir = ecx.load_mir(main_instance.def)?; if !main_mir.return_ty().is_unit() || main_mir.arg_count != 0 { - throw_unsup!(Unimplemented( + throw_unsup_format!( "miri does not support main functions without `fn()` type signatures" - .to_owned(), - )); + ); } let start_id = tcx.lang_items().start_fn().unwrap(); @@ -60,10 +59,10 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let start_mir = ecx.load_mir(start_instance.def)?; if start_mir.arg_count != 3 { - throw_unsup!(AbiViolation(format!( + bug!( "'start' lang item should have three arguments, but has {}", start_mir.arg_count - ))); + ); } // Return value (in static memory so that it does not count as leak). diff --git a/src/machine.rs b/src/machine.rs index 7fa79d822c35..30f3231308a4 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -247,9 +247,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { let data = vec![0; size.bytes() as usize]; Allocation::from_bytes(&data, tcx.data_layout.pointer_align.abi) } - _ => throw_unsup!(Unimplemented( - format!("can't access foreign static: {}", link_name), - )), + _ => throw_unsup_format!("can't access foreign static: {}", link_name), }; Ok(Cow::Owned(alloc)) } diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 005493096248..b859a8019024 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -16,9 +16,7 @@ impl Dlsym { "getentropy" => Some(GetEntropy), "__pthread_get_minstack" => None, _ => - throw_unsup!(Unimplemented(format!( - "Unsupported dlsym: {}", name - ))), + throw_unsup_format!("Unsupported dlsym: {}", name), }) } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 12baa79916ab..5561231edf04 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -141,7 +141,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // First: functions that diverge. match link_name { "__rust_start_panic" | "panic_impl" => { - throw_unsup!(MachineError("the evaluated program panicked".to_string())); + throw_unsup_format!("the evaluated program panicked"); } "exit" | "ExitProcess" => { // it's really u32 for ExitProcess, but we have to put it into the `Exit` error variant anyway @@ -149,9 +149,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Err(InterpError::Exit(code).into()); } _ => if dest.is_none() { - throw_unsup!(Unimplemented( - format!("can't call diverging foreign function: {}", link_name), - )); + throw_unsup_format!("can't call (diverging) foreign function: {}", link_name); } } @@ -183,10 +181,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx FIXME: This check is disabled because rustc violates it. See . if align < this.pointer_size().bytes() { - throw_unsup!(MachineError(format!( + throw_ub_format!( "posix_memalign: alignment must be at least the size of a pointer, but is {}", align, - ))); + ); } */ if size == 0 { @@ -309,9 +307,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; } id => { - throw_unsup!(Unimplemented( - format!("miri does not support syscall ID {}", id), - )) + throw_unsup_format!("miri does not support syscall ID {}", id) } } } @@ -359,12 +355,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; let mut args = this.frame().body.args_iter(); - let arg_local = args.next().ok_or_else(|| - err_unsup!(AbiViolation( - "Argument to __rust_maybe_catch_panic does not take enough arguments." - .to_owned(), - )), - )?; + let arg_local = args.next() + .expect("Argument to __rust_maybe_catch_panic does not take enough arguments."); let arg_dest = this.local_place(arg_local)?; this.write_scalar(data, arg_dest)?; @@ -632,9 +624,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(result) = result { this.write_scalar(result, dest)?; } else { - throw_unsup!(Unimplemented( - format!("Unimplemented sysconf name: {}", name), - )); + throw_unsup_format!("Unimplemented sysconf name: {}", name) } } @@ -661,9 +651,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This is `libc::pthread_key_t`. let key_type = args[0].layout.ty .builtin_deref(true) - .ok_or_else(|| err_unsup!( - AbiViolation("wrong signature used for `pthread_key_create`: first argument must be a raw pointer.".to_owned()) - ))? + .ok_or_else(|| err_ub!(Ub(format!( + "wrong signature used for `pthread_key_create`: first argument must be a raw pointer." + ))))? .ty; let key_layout = this.layout_of(key_type)?; @@ -729,7 +719,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We don't support threading. (Also for Windows.) "pthread_create" | "CreateThread" => { - throw_unsup!(Unimplemented(format!("Miri does not support threading"))); + throw_unsup_format!("Miri does not support threading"); } // Stub out calls for condvar, mutex and rwlock, to just return `0`. @@ -948,9 +938,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We can't execute anything else. _ => { - throw_unsup!(Unimplemented( - format!("can't call foreign function: {}", link_name), - )); + throw_unsup_format!("can't call foreign function: {}", link_name) } } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 7a213a805996..5c3ff139c026 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -133,7 +133,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_xsub_relaxed" => { let ptr = this.deref_operand(args[0])?; if !ptr.layout.ty.is_integral() { - throw_unsup!(Unimplemented(format!("Atomic arithmetic operations only work on integer types"))); + bug!("Atomic arithmetic operations only work on integer types"); } let rhs = this.read_immediate(args[1])?; let old = this.read_immediate(ptr.into())?; @@ -279,9 +279,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Check if `b` is -1, which is the "min_value / -1" case. let minus1 = Scalar::from_int(-1, dest.layout.size); return Err(if b.to_scalar().unwrap() == minus1 { - err_unsup!(Intrinsic(format!("exact_div: result of dividing MIN by -1 cannot be represented"))) + err_ub!(Ub(format!("exact_div: result of dividing MIN by -1 cannot be represented"))) } else { - err_unsup!(Intrinsic(format!("exact_div: {:?} cannot be divided by {:?} without remainder", *a, *b))) + err_ub!(Ub(format!("exact_div: {:?} cannot be divided by {:?} without remainder", *a, *b))) }.into()); } this.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; @@ -350,7 +350,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ty = substs.type_at(0); let layout = this.layout_of(ty)?; if layout.abi.is_uninhabited() { - throw_unsup!(Intrinsic(format!("Trying to instantiate uninhabited type {}", ty))) + throw_ub_format!("Trying to instantiate uninhabited type {}", ty) } } @@ -444,7 +444,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let r = this.read_immediate(args[1])?; let rval = r.to_scalar()?.to_bits(args[1].layout.size)?; if rval == 0 { - throw_unsup!(Intrinsic(format!("Division by 0 in unchecked_div"))); + throw_ub_format!("Division by 0 in unchecked_div"); } this.binop_ignore_overflow( mir::BinOp::Div, @@ -459,7 +459,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let r = this.read_immediate(args[1])?; let rval = r.to_scalar()?.to_bits(args[1].layout.size)?; if rval == 0 { - throw_unsup!(Intrinsic(format!("Division by 0 in unchecked_rem"))); + throw_ub_format!("Division by 0 in unchecked_rem"); } this.binop_ignore_overflow( mir::BinOp::Rem, @@ -480,7 +480,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; let (res, overflowed) = this.binary_op(op, l, r)?; if overflowed { - throw_unsup!(Intrinsic(format!("Overflowing arithmetic in {}", intrinsic_name.get()))); + throw_ub_format!("Overflowing arithmetic in {}", intrinsic_name.get()); } this.write_scalar(res, dest)?; } @@ -504,7 +504,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - name => throw_unsup!(Unimplemented(format!("unimplemented intrinsic: {}", name))), + name => throw_unsup_format!("unimplemented intrinsic: {}", name), } Ok(()) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 145d2b3e7891..05b8dc15da66 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -158,7 +158,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx StackPopCleanup::None { cleanup: true }, )?; let arg_local = this.frame().body.args_iter().next().ok_or_else( - || err_unsup!(AbiViolation("TLS dtor does not take enough arguments.".to_owned())), + || err_ub!(Ub(format!("TLS dtor does not take enough arguments."))), )?; let dest = this.local_place(arg_local)?; this.write_scalar(ptr, dest)?; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 5ef934b9922b..0fbc3e1ac281 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -273,14 +273,14 @@ impl<'tcx> Stack { if let Some(call) = item.protector { if global.is_active(call) { if let Some(tag) = tag { - throw_unsup!(MachineError(format!( + throw_ub_format!( "not granting access to tag {:?} because incompatible item is protected: {:?}", tag, item - ))); + ); } else { - throw_unsup!(MachineError(format!( + throw_ub_format!( "deallocating while item is protected: {:?}", item - ))); + ); } } } @@ -299,7 +299,7 @@ impl<'tcx> Stack { // Step 1: Find granting item. let granting_idx = self.find_granting(access, tag) - .ok_or_else(|| err_unsup!(MachineError(format!( + .ok_or_else(|| err_ub!(Ub(format!( "no item granting {} to tag {:?} found in borrow stack", access, tag, ))))?; @@ -346,7 +346,7 @@ impl<'tcx> Stack { ) -> InterpResult<'tcx> { // Step 1: Find granting item. self.find_granting(AccessKind::Write, tag) - .ok_or_else(|| err_unsup!(MachineError(format!( + .ok_or_else(|| err_ub!(Ub(format!( "no item granting write access for deallocation to tag {:?} found in borrow stack", tag, ))))?; @@ -378,7 +378,7 @@ impl<'tcx> Stack { // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. let granting_idx = self.find_granting(access, derived_from) - .ok_or_else(|| err_unsup!(MachineError(format!( + .ok_or_else(|| err_ub!(Ub(format!( "trying to reborrow for {:?}, but parent tag {:?} does not have an appropriate item in the borrow stack", new.perm, derived_from, ))))?; From 8d99e42f47e4fa0d79bc544c098e7287866c9a29 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Aug 2019 20:53:42 +0200 Subject: [PATCH 0988/5092] test memalign contract (rustc is fixed) --- src/shims/foreign_items.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 5561231edf04..76ee875d026b 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -177,16 +177,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if !align.is_power_of_two() { throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); } - /* - FIXME: This check is disabled because rustc violates it. - See . if align < this.pointer_size().bytes() { throw_ub_format!( "posix_memalign: alignment must be at least the size of a pointer, but is {}", align, ); } - */ + if size == 0 { this.write_null(ret.into())?; } else { From a41ec9aacbdc4798f9efeb8b24fc12d26e04bf7d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Aug 2019 20:54:57 +0200 Subject: [PATCH 0989/5092] adjust error messages in tests --- tests/compile-fail/atomic_non_integer_arithmetic.rs | 9 --------- tests/compile-fail/ctlz_nonzero.rs | 2 +- tests/compile-fail/cttz_nonzero.rs | 2 +- tests/compile-fail/overflowing-unchecked-rsh.rs | 2 +- 4 files changed, 3 insertions(+), 12 deletions(-) delete mode 100644 tests/compile-fail/atomic_non_integer_arithmetic.rs diff --git a/tests/compile-fail/atomic_non_integer_arithmetic.rs b/tests/compile-fail/atomic_non_integer_arithmetic.rs deleted file mode 100644 index 8c2ed98b7dfa..000000000000 --- a/tests/compile-fail/atomic_non_integer_arithmetic.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![feature(core_intrinsics)] - -pub fn main() { - let mut z: f64 = 1.0; - unsafe { - ::std::intrinsics::atomic_xadd(&mut z, 2.0); - //~^ ERROR: Atomic arithmetic operations only work on integer types - } -} diff --git a/tests/compile-fail/ctlz_nonzero.rs b/tests/compile-fail/ctlz_nonzero.rs index 61f41363589c..e82ed89da18a 100644 --- a/tests/compile-fail/ctlz_nonzero.rs +++ b/tests/compile-fail/ctlz_nonzero.rs @@ -10,6 +10,6 @@ pub fn main() { unsafe { use crate::rusti::*; - ctlz_nonzero(0u8); //~ ERROR ctlz_nonzero called on 0 + ctlz_nonzero(0u8); //~ ERROR `ctlz_nonzero` called on 0 } } diff --git a/tests/compile-fail/cttz_nonzero.rs b/tests/compile-fail/cttz_nonzero.rs index 69d2874ce926..205b55208114 100644 --- a/tests/compile-fail/cttz_nonzero.rs +++ b/tests/compile-fail/cttz_nonzero.rs @@ -10,6 +10,6 @@ pub fn main() { unsafe { use crate::rusti::*; - cttz_nonzero(0u8); //~ ERROR cttz_nonzero called on 0 + cttz_nonzero(0u8); //~ ERROR `cttz_nonzero` called on 0 } } diff --git a/tests/compile-fail/overflowing-unchecked-rsh.rs b/tests/compile-fail/overflowing-unchecked-rsh.rs index 0d67aef43088..f59773f7e366 100644 --- a/tests/compile-fail/overflowing-unchecked-rsh.rs +++ b/tests/compile-fail/overflowing-unchecked-rsh.rs @@ -2,7 +2,7 @@ use std::intrinsics::*; -//error-pattern: Overflowing shift by 64 in unchecked_shr +//error-pattern: Overflowing shift by 64 in `unchecked_shr` fn main() { unsafe { From 874437d717154072a3fe6ff04887fdf42988dffc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Aug 2019 10:09:58 +0200 Subject: [PATCH 0990/5092] install xargo from git temporarily --- src/bin/cargo-miri.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 1c0d23336e61..6baa882519b7 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -249,7 +249,8 @@ fn setup(ask_user: bool) { println!("Installing xargo: `cargo install xargo -f`"); } - if !cargo().args(&["install", "xargo", "-f"]).status() + // FIXME: Install from crates.io again once a new xargo got released. + if !cargo().args(&["install", "xargo", "-f", "--git", "https://github.com/japaric/xargo"]).status() .expect("failed to install xargo") .success() { From 162c0ffb1fc6547557f94fa0c9b316e4a785bd8a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Aug 2019 10:14:51 +0200 Subject: [PATCH 0991/5092] use postfix negation instead of prefix --- src/bin/cargo-miri.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 6baa882519b7..8d7bbace0edd 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -4,6 +4,7 @@ use std::fs::{self, File}; use std::io::{self, Write, BufRead}; use std::path::{PathBuf, Path}; use std::process::Command; +use std::ops::Not; const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and tests in Miri @@ -250,9 +251,9 @@ fn setup(ask_user: bool) { } // FIXME: Install from crates.io again once a new xargo got released. - if !cargo().args(&["install", "xargo", "-f", "--git", "https://github.com/japaric/xargo"]).status() + if cargo().args(&["install", "xargo", "-f", "--git", "https://github.com/japaric/xargo"]).status() .expect("failed to install xargo") - .success() + .success().not() { show_error(format!("Failed to install xargo")); } @@ -326,9 +327,9 @@ path = "lib.rs" command.arg("--target").arg(&target); } // Finally run it! - if !command.status() + if command.status() .expect("failed to run xargo") - .success() + .success().not() { show_error(format!("Failed to run xargo")); } From ca4969d4da07faab68ab8be893602a41fca63724 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 2 Aug 2019 19:50:54 +0200 Subject: [PATCH 0992/5092] consolidate atomic tests --- tests/run-pass/atomic-access-bool.rs | 19 ------------ .../{atomic-compare_exchange.rs => atomic.rs} | 29 +++++++++++++++++-- 2 files changed, 26 insertions(+), 22 deletions(-) delete mode 100644 tests/run-pass/atomic-access-bool.rs rename tests/run-pass/{atomic-compare_exchange.rs => atomic.rs} (64%) diff --git a/tests/run-pass/atomic-access-bool.rs b/tests/run-pass/atomic-access-bool.rs deleted file mode 100644 index 68a5d7295f17..000000000000 --- a/tests/run-pass/atomic-access-bool.rs +++ /dev/null @@ -1,19 +0,0 @@ -use std::sync::atomic::{AtomicBool, Ordering::*}; - -static mut ATOMIC: AtomicBool = AtomicBool::new(false); - -fn main() { - unsafe { - assert_eq!(*ATOMIC.get_mut(), false); - ATOMIC.store(true, SeqCst); - assert_eq!(*ATOMIC.get_mut(), true); - ATOMIC.fetch_or(false, SeqCst); - assert_eq!(*ATOMIC.get_mut(), true); - ATOMIC.fetch_and(false, SeqCst); - assert_eq!(*ATOMIC.get_mut(), false); - ATOMIC.fetch_nand(true, SeqCst); - assert_eq!(*ATOMIC.get_mut(), true); - ATOMIC.fetch_xor(true, SeqCst); - assert_eq!(*ATOMIC.get_mut(), false); - } -} diff --git a/tests/run-pass/atomic-compare_exchange.rs b/tests/run-pass/atomic.rs similarity index 64% rename from tests/run-pass/atomic-compare_exchange.rs rename to tests/run-pass/atomic.rs index 575b53fb44b0..ed9a9f453490 100644 --- a/tests/run-pass/atomic-compare_exchange.rs +++ b/tests/run-pass/atomic.rs @@ -1,8 +1,31 @@ -use std::sync::atomic::{AtomicIsize, Ordering::*}; - -static ATOMIC: AtomicIsize = AtomicIsize::new(0); +use std::sync::atomic::{AtomicBool, AtomicIsize, Ordering::*}; fn main() { + atomic_bool(); + atomic_isize(); +} + +fn atomic_bool() { + static mut ATOMIC: AtomicBool = AtomicBool::new(false); + + unsafe { + assert_eq!(*ATOMIC.get_mut(), false); + ATOMIC.store(true, SeqCst); + assert_eq!(*ATOMIC.get_mut(), true); + ATOMIC.fetch_or(false, SeqCst); + assert_eq!(*ATOMIC.get_mut(), true); + ATOMIC.fetch_and(false, SeqCst); + assert_eq!(*ATOMIC.get_mut(), false); + ATOMIC.fetch_nand(true, SeqCst); + assert_eq!(*ATOMIC.get_mut(), true); + ATOMIC.fetch_xor(true, SeqCst); + assert_eq!(*ATOMIC.get_mut(), false); + } +} + +fn atomic_isize() { + static ATOMIC: AtomicIsize = AtomicIsize::new(0); + // Make sure trans can emit all the intrinsics correctly assert_eq!(ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed), Ok(0)); assert_eq!(ATOMIC.compare_exchange(0, 2, Acquire, Relaxed), Err(1)); From 702f63e427a17081db942ff7f964b682b2e2b663 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 2 Aug 2019 20:08:04 +0200 Subject: [PATCH 0993/5092] test AtomicU64 --- tests/run-pass/atomic.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/atomic.rs b/tests/run-pass/atomic.rs index ed9a9f453490..f0b8ec06b905 100644 --- a/tests/run-pass/atomic.rs +++ b/tests/run-pass/atomic.rs @@ -1,8 +1,9 @@ -use std::sync::atomic::{AtomicBool, AtomicIsize, Ordering::*}; +use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicU64, Ordering::*}; fn main() { atomic_bool(); atomic_isize(); + atomic_u64(); } fn atomic_bool() { @@ -50,3 +51,12 @@ fn atomic_isize() { ATOMIC.compare_exchange_weak(0, 1, SeqCst, Acquire).ok(); ATOMIC.compare_exchange_weak(0, 1, SeqCst, SeqCst).ok(); } + +fn atomic_u64() { + static ATOMIC: AtomicU64 = AtomicU64::new(0); + + ATOMIC.store(1, SeqCst); + assert_eq!(ATOMIC.compare_exchange(0, 0x100, AcqRel, Acquire), Err(1)); + assert_eq!(ATOMIC.compare_exchange_weak(1, 0x100, AcqRel, Acquire), Ok(1)); + assert_eq!(ATOMIC.load(Relaxed), 0x100); +} From f47e58950bc8541a887d9e1720a5ecc9b9c346d5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 2 Aug 2019 20:20:56 +0200 Subject: [PATCH 0994/5092] check that atomics are sufficiently aligned, and add test --- src/shims/intrinsics.rs | 57 +++++++++++++++++++++----- tests/compile-fail/atomic_unaligned.rs | 12 ++++++ 2 files changed, 58 insertions(+), 11 deletions(-) create mode 100644 tests/compile-fail/atomic_unaligned.rs diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 5c3ff139c026..d442fcedbdb1 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -1,7 +1,7 @@ use rustc_apfloat::Float; use rustc::mir; use rustc::mir::interpret::{InterpResult, PointerArithmetic}; -use rustc::ty::layout::{self, LayoutOf, Size}; +use rustc::ty::layout::{self, LayoutOf, Size, Align}; use rustc::ty; use crate::{ @@ -48,17 +48,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + "volatile_load" => { + let ptr = this.deref_operand(args[0])?; + this.copy_op(ptr.into(), dest)?; + } + + "volatile_store" => { + let ptr = this.deref_operand(args[0])?; + this.copy_op(args[1], ptr.into())?; + } + "atomic_load" | "atomic_load_relaxed" | "atomic_load_acq" => { let ptr = this.deref_operand(args[0])?; let val = this.read_scalar(ptr.into())?; // make sure it fits into a scalar; otherwise it cannot be atomic - this.write_scalar(val, dest)?; - } - "volatile_load" => { - let ptr = this.deref_operand(args[0])?; - this.copy_op(ptr.into(), dest)?; + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(ptr.layout.size.bytes()).unwrap(); + this.memory().check_ptr_access(ptr.ptr, ptr.layout.size, align)?; + + this.write_scalar(val, dest)?; } "atomic_store" | @@ -66,12 +78,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_store_rel" => { let ptr = this.deref_operand(args[0])?; let val = this.read_scalar(args[1])?; // make sure it fits into a scalar; otherwise it cannot be atomic - this.write_scalar(val, ptr.into())?; - } - "volatile_store" => { - let ptr = this.deref_operand(args[0])?; - this.copy_op(args[1], ptr.into())?; + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(ptr.layout.size.bytes()).unwrap(); + this.memory().check_ptr_access(ptr.ptr, ptr.layout.size, align)?; + + this.write_scalar(val, ptr.into())?; } "atomic_fence_acq" => { @@ -82,6 +96,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.deref_operand(args[0])?; let new = this.read_scalar(args[1])?; let old = this.read_scalar(ptr.into())?; + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(ptr.layout.size.bytes()).unwrap(); + this.memory().check_ptr_access(ptr.ptr, ptr.layout.size, align)?; + this.write_scalar(old, dest)?; // old value is returned this.write_scalar(new, ptr.into())?; } @@ -91,6 +112,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let expect_old = this.read_immediate(args[1])?; // read as immediate for the sake of `binary_op()` let new = this.read_scalar(args[2])?; let old = this.read_immediate(ptr.into())?; // read as immediate for the sake of `binary_op()` + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(ptr.layout.size.bytes()).unwrap(); + this.memory().check_ptr_access(ptr.ptr, ptr.layout.size, align)?; + // binary_op will bail if either of them is not a scalar let (eq, _) = this.binary_op(mir::BinOp::Eq, old, expect_old)?; let res = Immediate::ScalarPair(old.to_scalar_or_undef(), eq.into()); @@ -137,6 +165,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let rhs = this.read_immediate(args[1])?; let old = this.read_immediate(ptr.into())?; + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(ptr.layout.size.bytes()).unwrap(); + this.memory().check_ptr_access(ptr.ptr, ptr.layout.size, align)?; + this.write_immediate(*old, dest)?; // old value is returned let (op, neg) = match intrinsic_name.split('_').nth(1).unwrap() { "or" => (mir::BinOp::BitOr, false), diff --git a/tests/compile-fail/atomic_unaligned.rs b/tests/compile-fail/atomic_unaligned.rs new file mode 100644 index 000000000000..5d2347c03ffe --- /dev/null +++ b/tests/compile-fail/atomic_unaligned.rs @@ -0,0 +1,12 @@ +#![feature(core_intrinsics)] + +fn main() { + // Do a 4-aligned u64 atomic access. That should be UB on all platforms, + // even if u64 only has alignment 4. + let z = [0u32; 2]; + let zptr = &z as *const _ as *const u64; + unsafe { + ::std::intrinsics::atomic_load(zptr); + //~^ ERROR tried to access memory with alignment 4, but alignment 8 is required + } +} From 19add0bb751000dc94c28a603600f82b6e14d887 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Aug 2019 10:52:09 +0200 Subject: [PATCH 0995/5092] places and pointers are not the same thing; this is a place --- src/shims/intrinsics.rs | 56 ++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index d442fcedbdb1..b7a1761167d5 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -49,26 +49,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "volatile_load" => { - let ptr = this.deref_operand(args[0])?; - this.copy_op(ptr.into(), dest)?; + let place = this.deref_operand(args[0])?; + this.copy_op(place.into(), dest)?; } "volatile_store" => { - let ptr = this.deref_operand(args[0])?; - this.copy_op(args[1], ptr.into())?; + let place = this.deref_operand(args[0])?; + this.copy_op(args[1], place.into())?; } "atomic_load" | "atomic_load_relaxed" | "atomic_load_acq" => { - let ptr = this.deref_operand(args[0])?; - let val = this.read_scalar(ptr.into())?; // make sure it fits into a scalar; otherwise it cannot be atomic + let place = this.deref_operand(args[0])?; + let val = this.read_scalar(place.into())?; // make sure it fits into a scalar; otherwise it cannot be atomic // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). - let align = Align::from_bytes(ptr.layout.size.bytes()).unwrap(); - this.memory().check_ptr_access(ptr.ptr, ptr.layout.size, align)?; + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.memory().check_ptr_access(place.ptr, place.layout.size, align)?; this.write_scalar(val, dest)?; } @@ -76,16 +76,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_store" | "atomic_store_relaxed" | "atomic_store_rel" => { - let ptr = this.deref_operand(args[0])?; + let place = this.deref_operand(args[0])?; let val = this.read_scalar(args[1])?; // make sure it fits into a scalar; otherwise it cannot be atomic // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). - let align = Align::from_bytes(ptr.layout.size.bytes()).unwrap(); - this.memory().check_ptr_access(ptr.ptr, ptr.layout.size, align)?; + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.memory().check_ptr_access(place.ptr, place.layout.size, align)?; - this.write_scalar(val, ptr.into())?; + this.write_scalar(val, place.into())?; } "atomic_fence_acq" => { @@ -93,31 +93,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } _ if intrinsic_name.starts_with("atomic_xchg") => { - let ptr = this.deref_operand(args[0])?; + let place = this.deref_operand(args[0])?; let new = this.read_scalar(args[1])?; - let old = this.read_scalar(ptr.into())?; + let old = this.read_scalar(place.into())?; // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). - let align = Align::from_bytes(ptr.layout.size.bytes()).unwrap(); - this.memory().check_ptr_access(ptr.ptr, ptr.layout.size, align)?; + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.memory().check_ptr_access(place.ptr, place.layout.size, align)?; this.write_scalar(old, dest)?; // old value is returned - this.write_scalar(new, ptr.into())?; + this.write_scalar(new, place.into())?; } _ if intrinsic_name.starts_with("atomic_cxchg") => { - let ptr = this.deref_operand(args[0])?; + let place = this.deref_operand(args[0])?; let expect_old = this.read_immediate(args[1])?; // read as immediate for the sake of `binary_op()` let new = this.read_scalar(args[2])?; - let old = this.read_immediate(ptr.into())?; // read as immediate for the sake of `binary_op()` + let old = this.read_immediate(place.into())?; // read as immediate for the sake of `binary_op()` // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). - let align = Align::from_bytes(ptr.layout.size.bytes()).unwrap(); - this.memory().check_ptr_access(ptr.ptr, ptr.layout.size, align)?; + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.memory().check_ptr_access(place.ptr, place.layout.size, align)?; // binary_op will bail if either of them is not a scalar let (eq, _) = this.binary_op(mir::BinOp::Eq, old, expect_old)?; @@ -125,7 +125,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_immediate(res, dest)?; // old value is returned // update ptr depending on comparison if eq.to_bool()? { - this.write_scalar(new, ptr.into())?; + this.write_scalar(new, place.into())?; } } @@ -159,18 +159,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_xsub_rel" | "atomic_xsub_acqrel" | "atomic_xsub_relaxed" => { - let ptr = this.deref_operand(args[0])?; - if !ptr.layout.ty.is_integral() { + let place = this.deref_operand(args[0])?; + if !place.layout.ty.is_integral() { bug!("Atomic arithmetic operations only work on integer types"); } let rhs = this.read_immediate(args[1])?; - let old = this.read_immediate(ptr.into())?; + let old = this.read_immediate(place.into())?; // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). - let align = Align::from_bytes(ptr.layout.size.bytes()).unwrap(); - this.memory().check_ptr_access(ptr.ptr, ptr.layout.size, align)?; + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.memory().check_ptr_access(place.ptr, place.layout.size, align)?; this.write_immediate(*old, dest)?; // old value is returned let (op, neg) = match intrinsic_name.split('_').nth(1).unwrap() { @@ -189,7 +189,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { val }; - this.write_scalar(val, ptr.into())?; + this.write_scalar(val, place.into())?; } "breakpoint" => unimplemented!(), // halt miri From a4cc58efc6db1c8c478954ea5116e15a7add479c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Aug 2019 10:54:07 +0200 Subject: [PATCH 0996/5092] one more place -> ptr rename --- src/shims/intrinsics.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index b7a1761167d5..920dc564e154 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -370,8 +370,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "move_val_init" => { - let ptr = this.deref_operand(args[0])?; - this.copy_op(args[1], ptr.into())?; + let place = this.deref_operand(args[0])?; + this.copy_op(args[1], place.into())?; } "offset" => { From 0096a0df2a34b5818976ff40b6ec5b1a54ebf92f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Aug 2019 14:49:10 +0200 Subject: [PATCH 0997/5092] gen_random helper: move ptr argument to front --- src/helpers.rs | 2 +- src/shims/dlsym.rs | 2 +- src/shims/foreign_items.rs | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index d29cc021a1b0..e9b09d816056 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -78,8 +78,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Generate some random bytes, and write them to `dest`. fn gen_random( &mut self, - len: usize, ptr: Scalar, + len: usize, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index b859a8019024..307de29f2203 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -41,7 +41,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx GetEntropy => { let ptr = this.read_scalar(args[0])?.not_undef()?; let len = this.read_scalar(args[1])?.to_usize(this)?; - this.gen_random(len as usize, ptr)?; + this.gen_random(ptr, len as usize)?; this.write_null(dest)?; } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 96bc747d3efb..4fc8b1d54cfc 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -300,7 +300,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // neither of which have any effect on our current PRNG let _flags = this.read_scalar(args[3])?.to_i32()?; - this.gen_random(len as usize, ptr)?; + this.gen_random(ptr, len as usize)?; this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; } id => { @@ -776,7 +776,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "SecRandomCopyBytes" => { let len = this.read_scalar(args[1])?.to_usize(this)?; let ptr = this.read_scalar(args[2])?.not_undef()?; - this.gen_random(len as usize, ptr)?; + this.gen_random(ptr, len as usize)?; this.write_null(dest)?; } @@ -938,7 +938,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "SystemFunction036" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let len = this.read_scalar(args[1])?.to_u32()?; - this.gen_random(len as usize, ptr)?; + this.gen_random(ptr, len as usize)?; this.write_scalar(Scalar::from_bool(true), dest)?; } From e8d956c4fa320675f245788701193dabd730f5a9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Aug 2019 15:09:13 +0200 Subject: [PATCH 0998/5092] add getrandom bug --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 91fc72cb427b..8c5a29880c7c 100644 --- a/README.md +++ b/README.md @@ -342,6 +342,7 @@ Definite bugs found: * [`str` turning a shared reference into a mutable one](https://github.com/rust-lang/rust/pull/58200) * [`rand` performing unaligned reads](https://github.com/rust-random/rand/issues/779) * [The Unix allocator calling `posix_memalign` in an invalid way](https://github.com/rust-lang/rust/issues/62251) +* [`getrandom` calling the `getrandom` syscall in an invalid way](https://github.com/rust-random/getrandom/pull/73) Violations of Stacked Borrows found that are likely bugs (but Stacked Borrows is currently just an experiment): From 0505868d18ff946da58028de20bf2d5a19bb7f40 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Aug 2019 09:21:17 -0400 Subject: [PATCH 0999/5092] Do nothing when we try to generate random data of length 0 This preserves compatibility with programs that pass a null pointer and a length of zero to getrandom(), or their platform's equivalent. --- src/helpers.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/helpers.rs b/src/helpers.rs index e9b09d816056..c543240442ec 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -81,6 +81,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ptr: Scalar, len: usize, ) -> InterpResult<'tcx> { + // Some programs pass in a null pointer and a length of 0 + // to their platform's random-generation function (e.g. getrandom()) + // on Linux. For compatibility with these programs, we don't perform + // any additional checks - it's okay if the pointer is invalid, + // since we wouldn't actually be writing to it. + if len == 0 { + return Ok(()) + } let this = self.eval_context_mut(); let ptr = match this.memory().check_ptr_access(ptr, Size::from_bytes(len as u64), Align::from_bytes(1).unwrap())? { From c2f681f005a036568dcfe2beb171b9ab635fa486 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Aug 2019 10:13:29 -0400 Subject: [PATCH 1000/5092] Add semicolon Co-Authored-By: Ralf Jung --- src/helpers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers.rs b/src/helpers.rs index c543240442ec..569c1dbfb07e 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -87,7 +87,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // any additional checks - it's okay if the pointer is invalid, // since we wouldn't actually be writing to it. if len == 0 { - return Ok(()) + return Ok(()); } let this = self.eval_context_mut(); From 3118b9fe4288c21dc0b81c90178cea092d0edfaf Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Aug 2019 10:25:10 -0400 Subject: [PATCH 1001/5092] Add misssing 'roundf32' and 'roundf64' intrinsics --- src/shims/intrinsics.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 920dc564e154..52a17a92c2ed 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -225,7 +225,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | - "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" => { + "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" | "roundf32" => { // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); let f = match intrinsic_name.get() { @@ -241,13 +241,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "floorf32" => f.floor(), "ceilf32" => f.ceil(), "truncf32" => f.trunc(), + "roundf32" => f.round(), _ => bug!(), }; this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?; } "sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" | - "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" => { + "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" | "roundf64" => { // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); let f = match intrinsic_name.get() { @@ -263,6 +264,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "floorf64" => f.floor(), "ceilf64" => f.ceil(), "truncf64" => f.trunc(), + "roundf64" => f.round(), _ => bug!(), }; this.write_scalar(Scalar::from_u64(f.to_bits()), dest)?; From 4d3398fc6262a0159af7311524ade980637121ae Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Aug 2019 10:17:39 -0400 Subject: [PATCH 1002/5092] Replace match with expect() --- src/helpers.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 569c1dbfb07e..c0e1ec2cd75b 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -91,10 +91,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let this = self.eval_context_mut(); - let ptr = match this.memory().check_ptr_access(ptr, Size::from_bytes(len as u64), Align::from_bytes(1).unwrap())? { - Some(ptr) => ptr, - None => return Ok(()), // zero-sized access - }; + let ptr = this.memory().check_ptr_access( + ptr, + Size::from_bytes(len as u64), + Align::from_bytes(1).unwrap() + )?.expect("we already checked for size 0"); let rng = this.memory_mut().extra.rng.get_mut(); let mut data = vec![0; len]; From 4c11c6b73729f7b573eab102efb9856b37951532 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Aug 2019 15:57:00 -0400 Subject: [PATCH 1003/5092] Add test for f32::round and f64::round --- tests/run-pass/intrinsics-math.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/run-pass/intrinsics-math.rs b/tests/run-pass/intrinsics-math.rs index 9a7a70bd0092..63098f5fd3f7 100644 --- a/tests/run-pass/intrinsics-math.rs +++ b/tests/run-pass/intrinsics-math.rs @@ -85,6 +85,9 @@ pub fn main() { assert_approx_eq!(1.0f32.tan(), 1.557408f32); assert_approx_eq!(1.0f64.tan(), 1.557408f64); + assert_eq!(3.3_f32.round(), 3.0); + assert_eq!(3.3_f64.round(), 3.0); + extern { fn ldexp(x: f64, n: i32) -> f64; } From a2bdb3bb94936c45b68f91b4ffd938dd3df5f8c1 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Aug 2019 10:50:38 -0400 Subject: [PATCH 1004/5092] Shim 'libc::getrandom' in addition to 'libc::syscall(libc::SYS_getrandom)' --- src/shims/foreign_items.rs | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 4fc8b1d54cfc..6ae99c9bc15c 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -293,15 +293,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // is called if a `HashMap` is created the regular way (e.g. HashMap). match this.read_scalar(args[0])?.to_usize(this)? { id if id == sys_getrandom => { - let ptr = this.read_scalar(args[1])?.not_undef()?; - let len = this.read_scalar(args[2])?.to_usize(this)?; - - // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, - // neither of which have any effect on our current PRNG - let _flags = this.read_scalar(args[3])?.to_i32()?; - - this.gen_random(ptr, len as usize)?; - this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; + // The first argument is the syscall id, + // so skip over it + linux_getrandom(this, &args[1..], dest)?; } id => { throw_unsup_format!("miri does not support syscall ID {}", id) @@ -309,6 +303,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + "getrandom" => { + linux_getrandom(this, args, dest)?; + } + "dlsym" => { let _handle = this.read_scalar(args[0])?; let symbol = this.read_scalar(args[1])?.not_undef()?; @@ -969,3 +967,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(None); } } + +// Shims the linux 'getrandom()' syscall +fn linux_getrandom<'mir, 'tcx>(this: &mut MiriEvalContext<'mir, 'tcx>, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + let ptr = this.read_scalar(args[0])?.not_undef()?; + let len = this.read_scalar(args[1])?.to_usize(this)?; + + + // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, + // neither of which have any effect on our current PRNG + let _flags = this.read_scalar(args[2])?.to_i32()?; + + this.gen_random(ptr, len as usize)?; + this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; + Ok(()) +} From 56a9a283e74078a3a48974a5e294bcb8f8e025c1 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Aug 2019 15:53:38 -0400 Subject: [PATCH 1005/5092] Cleanup formatting --- src/shims/foreign_items.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 6ae99c9bc15c..24bdc98fe8eb 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -969,13 +969,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Shims the linux 'getrandom()' syscall -fn linux_getrandom<'mir, 'tcx>(this: &mut MiriEvalContext<'mir, 'tcx>, - args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { +fn linux_getrandom<'tcx>( + this: &mut MiriEvalContext<'_, 'tcx>, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag> +) -> InterpResult<'tcx> { let ptr = this.read_scalar(args[0])?.not_undef()?; let len = this.read_scalar(args[1])?.to_usize(this)?; - // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, // neither of which have any effect on our current PRNG let _flags = this.read_scalar(args[2])?.to_i32()?; From 6b087d25362a3461f76cdee5a62fb76d2d8023fd Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Aug 2019 15:53:49 -0400 Subject: [PATCH 1006/5092] Add test --- tests/run-pass/linux-getrandom.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/run-pass/linux-getrandom.rs diff --git a/tests/run-pass/linux-getrandom.rs b/tests/run-pass/linux-getrandom.rs new file mode 100644 index 000000000000..ded5596d8072 --- /dev/null +++ b/tests/run-pass/linux-getrandom.rs @@ -0,0 +1,12 @@ +// only-linux: Uses Linux-only APIs + +#![feature(rustc_private)] +extern crate libc; + +fn main() { + let mut buf = [0u8; 5]; + unsafe { + assert_eq!(libc::syscall(libc::SYS_getrandom, 0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), 0); + assert_eq!(libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, 0 as libc::c_uint), 5); + } +} From 8650f02bc983a34b3c7923850fca07c2ddf2d544 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Aug 2019 15:59:20 -0400 Subject: [PATCH 1007/5092] Add trailing comma --- src/shims/foreign_items.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 24bdc98fe8eb..887fb8e5d80a 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -972,7 +972,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn linux_getrandom<'tcx>( this: &mut MiriEvalContext<'_, 'tcx>, args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag> + dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let ptr = this.read_scalar(args[0])?.not_undef()?; let len = this.read_scalar(args[1])?.to_usize(this)?; From a74a04f35676f9061691844b2852c499d953a731 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Aug 2019 16:11:52 -0400 Subject: [PATCH 1008/5092] Test 'libc::getrandom' as well --- tests/run-pass/linux-getrandom.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/run-pass/linux-getrandom.rs b/tests/run-pass/linux-getrandom.rs index ded5596d8072..b698b54a3c0e 100644 --- a/tests/run-pass/linux-getrandom.rs +++ b/tests/run-pass/linux-getrandom.rs @@ -8,5 +8,8 @@ fn main() { unsafe { assert_eq!(libc::syscall(libc::SYS_getrandom, 0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), 0); assert_eq!(libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, 0 as libc::c_uint), 5); + + assert_eq!(libc::getrandom(0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), 0); + assert_eq!(libc::getrandom(buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, 0 as libc::c_uint), 5); } } From 8a758177073229df9c0bdcd69f3bcd7bbe5601c9 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Aug 2019 16:30:33 -0400 Subject: [PATCH 1009/5092] Fix identation --- tests/run-pass/linux-getrandom.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/linux-getrandom.rs b/tests/run-pass/linux-getrandom.rs index b698b54a3c0e..d9d588221c97 100644 --- a/tests/run-pass/linux-getrandom.rs +++ b/tests/run-pass/linux-getrandom.rs @@ -6,7 +6,7 @@ extern crate libc; fn main() { let mut buf = [0u8; 5]; unsafe { - assert_eq!(libc::syscall(libc::SYS_getrandom, 0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), 0); + assert_eq!(libc::syscall(libc::SYS_getrandom, 0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), 0); assert_eq!(libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, 0 as libc::c_uint), 5); assert_eq!(libc::getrandom(0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), 0); From 66d10c877d4b68d730e6aa4759a36a68dfe97152 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Aug 2019 16:40:30 -0400 Subject: [PATCH 1010/5092] Ignore other platforms instead of using only-linux --- tests/run-pass/linux-getrandom.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/linux-getrandom.rs b/tests/run-pass/linux-getrandom.rs index d9d588221c97..8da2ce46fe7d 100644 --- a/tests/run-pass/linux-getrandom.rs +++ b/tests/run-pass/linux-getrandom.rs @@ -1,5 +1,7 @@ -// only-linux: Uses Linux-only APIs - +// Unfortunately, compiletest_rs does not support 'only-linux', +// so we need to ignore Windows and OS X instead +// ignore-macos: Uses Linux-only APIs +// ignore-windows: Uses Linux-only APIs #![feature(rustc_private)] extern crate libc; From a208f2fccf30329f148fbc1f742e4c0af2417059 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Aug 2019 16:44:32 -0400 Subject: [PATCH 1011/5092] Improve formatting Co-Authored-By: Ralf Jung --- tests/run-pass/linux-getrandom.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/linux-getrandom.rs b/tests/run-pass/linux-getrandom.rs index 8da2ce46fe7d..f582a282c59b 100644 --- a/tests/run-pass/linux-getrandom.rs +++ b/tests/run-pass/linux-getrandom.rs @@ -1,5 +1,5 @@ // Unfortunately, compiletest_rs does not support 'only-linux', -// so we need to ignore Windows and OS X instead +// so we need to ignore Windows and macOS instead. // ignore-macos: Uses Linux-only APIs // ignore-windows: Uses Linux-only APIs #![feature(rustc_private)] From f830a6c69ecef2e87a24be1dca68537411b04f84 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Aug 2019 16:57:17 -0400 Subject: [PATCH 1012/5092] Apply more formatting fixes Co-Authored-By: Ralf Jung --- src/shims/foreign_items.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 887fb8e5d80a..538109eceae7 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -294,7 +294,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match this.read_scalar(args[0])?.to_usize(this)? { id if id == sys_getrandom => { // The first argument is the syscall id, - // so skip over it + // so skip over it. linux_getrandom(this, &args[1..], dest)?; } id => { @@ -968,7 +968,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } -// Shims the linux 'getrandom()' syscall +// Shims the linux 'getrandom()' syscall. fn linux_getrandom<'tcx>( this: &mut MiriEvalContext<'_, 'tcx>, args: &[OpTy<'tcx, Tag>], @@ -978,7 +978,7 @@ fn linux_getrandom<'tcx>( let len = this.read_scalar(args[1])?.to_usize(this)?; // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, - // neither of which have any effect on our current PRNG + // neither of which have any effect on our current PRNG. let _flags = this.read_scalar(args[2])?.to_i32()?; this.gen_random(ptr, len as usize)?; From d26917a9d6d6eebb37b16d896cdef9953ce34e2f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Aug 2019 10:45:48 +0200 Subject: [PATCH 1013/5092] fix for latest rustc --- rust-version | 2 +- src/shims/foreign_items.rs | 4 ++-- src/shims/intrinsics.rs | 6 +++--- src/shims/tls.rs | 2 +- src/stacked_borrows.rs | 14 +++++++------- tests/compile-fail/assume.rs | 2 +- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/rust-version b/rust-version index 94c6f5e4b8c9..0680001291b7 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a45743345659c775b01484574af2818c46a2cb03 +11a51488f03405ea539a9fe84973ee972eaa7b96 diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 538109eceae7..37e5fe42c3de 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -655,9 +655,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This is `libc::pthread_key_t`. let key_type = args[0].layout.ty .builtin_deref(true) - .ok_or_else(|| err_ub!(Ub(format!( + .ok_or_else(|| err_ub_format!( "wrong signature used for `pthread_key_create`: first argument must be a raw pointer." - ))))? + ))? .ty; let key_layout = this.layout_of(key_type)?; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 52a17a92c2ed..c96869c80cee 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -44,7 +44,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "assume" => { let cond = this.read_scalar(args[0])?.to_bool()?; if !cond { - throw_unsup!(AssumptionNotHeld); + throw_ub_format!("`assume` intrinsic called with `false`"); } } @@ -316,9 +316,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Check if `b` is -1, which is the "min_value / -1" case. let minus1 = Scalar::from_int(-1, dest.layout.size); return Err(if b.to_scalar().unwrap() == minus1 { - err_ub!(Ub(format!("exact_div: result of dividing MIN by -1 cannot be represented"))) + err_ub_format!("exact_div: result of dividing MIN by -1 cannot be represented") } else { - err_ub!(Ub(format!("exact_div: {:?} cannot be divided by {:?} without remainder", *a, *b))) + err_ub_format!("exact_div: {:?} cannot be divided by {:?} without remainder", *a, *b) }.into()); } this.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 05b8dc15da66..d2190bd969e3 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -158,7 +158,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx StackPopCleanup::None { cleanup: true }, )?; let arg_local = this.frame().body.args_iter().next().ok_or_else( - || err_ub!(Ub(format!("TLS dtor does not take enough arguments."))), + || err_ub_format!("TLS dtor does not take enough arguments."), )?; let dest = this.local_place(arg_local)?; this.write_scalar(ptr, dest)?; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 0fbc3e1ac281..01ed6ec225d2 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -273,14 +273,14 @@ impl<'tcx> Stack { if let Some(call) = item.protector { if global.is_active(call) { if let Some(tag) = tag { - throw_ub_format!( + throw_ub!(UbExperimental(format!( "not granting access to tag {:?} because incompatible item is protected: {:?}", tag, item - ); + ))); } else { - throw_ub_format!( + throw_ub!(UbExperimental(format!( "deallocating while item is protected: {:?}", item - ); + ))); } } } @@ -299,7 +299,7 @@ impl<'tcx> Stack { // Step 1: Find granting item. let granting_idx = self.find_granting(access, tag) - .ok_or_else(|| err_ub!(Ub(format!( + .ok_or_else(|| err_ub!(UbExperimental(format!( "no item granting {} to tag {:?} found in borrow stack", access, tag, ))))?; @@ -346,7 +346,7 @@ impl<'tcx> Stack { ) -> InterpResult<'tcx> { // Step 1: Find granting item. self.find_granting(AccessKind::Write, tag) - .ok_or_else(|| err_ub!(Ub(format!( + .ok_or_else(|| err_ub!(UbExperimental(format!( "no item granting write access for deallocation to tag {:?} found in borrow stack", tag, ))))?; @@ -378,7 +378,7 @@ impl<'tcx> Stack { // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. let granting_idx = self.find_granting(access, derived_from) - .ok_or_else(|| err_ub!(Ub(format!( + .ok_or_else(|| err_ub!(UbExperimental(format!( "trying to reborrow for {:?}, but parent tag {:?} does not have an appropriate item in the borrow stack", new.perm, derived_from, ))))?; diff --git a/tests/compile-fail/assume.rs b/tests/compile-fail/assume.rs index 3026124e1f9a..7b18cab79805 100644 --- a/tests/compile-fail/assume.rs +++ b/tests/compile-fail/assume.rs @@ -5,6 +5,6 @@ fn main() { unsafe { std::intrinsics::assume(x < 10); std::intrinsics::assume(x > 1); - std::intrinsics::assume(x > 42); //~ `assume` argument was false + std::intrinsics::assume(x > 42); //~ `assume` intrinsic called with `false` } } From b0cb603e3afa8761fcfbaaa196e1f5ff9448357b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Aug 2019 15:49:19 +0200 Subject: [PATCH 1014/5092] rustup --- rust-version | 2 +- src/machine.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 0680001291b7..e09b2fc7e55f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -11a51488f03405ea539a9fe84973ee972eaa7b96 +4be067558962c004b638e4c6f162d50f7c0c98b6 diff --git a/src/machine.rs b/src/machine.rs index 30f3231308a4..f2c81c92d3d0 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -141,6 +141,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { const STATIC_KIND: Option = Some(MiriMemoryKind::Static); + const CHECK_ALIGN: bool = true; + #[inline(always)] fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { ecx.memory().extra.validate From cc8d9956054246ef78c27e58eb0a1ef1df8c1fd2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 6 Aug 2019 08:05:32 +0200 Subject: [PATCH 1015/5092] go back to released xargo (the experiment is done) --- src/bin/cargo-miri.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 8d7bbace0edd..2202465709d5 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -250,8 +250,7 @@ fn setup(ask_user: bool) { println!("Installing xargo: `cargo install xargo -f`"); } - // FIXME: Install from crates.io again once a new xargo got released. - if cargo().args(&["install", "xargo", "-f", "--git", "https://github.com/japaric/xargo"]).status() + if cargo().args(&["install", "xargo", "-f"]).status() .expect("failed to install xargo") .success().not() { From c73b13fc5847f60f51a3f060fde2242bfb5cbeba Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 6 Aug 2019 12:50:22 +0200 Subject: [PATCH 1016/5092] test-cargo-miri: cargo update --- test-cargo-miri/Cargo.lock | 48 +++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 55e5a3dfc185..3b4dbdcf1d2e 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -2,7 +2,7 @@ # It is not intended for manual editing. [[package]] name = "autocfg" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -28,26 +28,28 @@ dependencies = [ "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cfg-if" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "getrandom" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lazy_static" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "libc" -version = "0.2.58" +version = "0.2.60" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -55,7 +57,7 @@ name = "num_cpus" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -68,9 +70,9 @@ name = "rand" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_pcg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -78,10 +80,9 @@ dependencies = [ [[package]] name = "rand_chacha" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -91,7 +92,7 @@ name = "rand_core" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -107,27 +108,22 @@ name = "rand_pcg" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "spin" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [metadata] -"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" +"checksum autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "22130e92352b948e7e82a49cdb0aa94f2211761117f29e052dd397c1ac33542b" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" -"checksum getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e65cce4e5084b14874c4e7097f38cab54f47ee554f9194673456ea379dcc4c55" +"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" +"checksum getrandom 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "34f33de6f0ae7c9cb5e574502a562e2b512799e32abb801cd1e79ad952b62b49" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" -"checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319" +"checksum libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "d44e80633f007889c7eff624b709ab43c92d708caad982295768a7b13ca3b5eb" "checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" "checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" -"checksum rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e193067942ef6f485a349a113329140d0ab9e2168ce92274499bb0e9a4190d9d" +"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum rand_pcg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e196346cbbc5c70c77e7b4926147ee8e383a38ee4d15d58a08098b169e492b6" -"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" From 3fe4eec37a7fce551b6f3c96e67b70151bc468e2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 6 Aug 2019 20:52:09 +0200 Subject: [PATCH 1017/5092] mention that we get the toolchain right --- src/bin/cargo-miri.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 2202465709d5..4da039a42d9e 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -268,7 +268,7 @@ fn setup(ask_user: bool) { let src = Path::new(sysroot.trim_end_matches('\n')).join("lib").join("rustlib").join("src"); if !src.exists() { if ask_user { - ask("It seems you do not have the rust-src component installed. I will run `rustup component add rust-src`. Proceed?"); + ask("It seems you do not have the rust-src component installed. I will run `rustup component add rust-src` for the selected toolchain. Proceed?"); } else { println!("Installing rust-src component: `rustup component add rust-src`"); } From 655f9af7fe315a9f8e881d94b7c221c965a7caae Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 6 Aug 2019 10:28:50 -0500 Subject: [PATCH 1018/5092] Add flag to enable communication --- benches/helpers/miri_helper.rs | 2 +- src/bin/miri-rustc-tests.rs | 5 +++-- src/bin/miri.rs | 6 +++++- src/eval.rs | 5 +++-- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 203a8b1133a5..003c93f7464d 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -25,7 +25,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { ); self.bencher.iter(|| { - let config = miri::MiriConfig { validate: true, args: vec![], seed: None }; + let config = miri::MiriConfig { validate: true, communicate: false, args: vec![], seed: None }; eval_main(tcx, entry_def_id, config); }); }); diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index dae5189937a3..a1bc53f69b80 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -48,7 +48,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.node { if i.attrs.iter().any(|attr| attr.check_name(syntax::symbol::sym::test)) { - let config = MiriConfig { validate: true, args: vec![], seed: None }; + let config = MiriConfig { validate: true, communicate: false, args: vec![], seed: None }; let did = self.0.hir().body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); miri::eval_main(self.0, did, config); @@ -61,7 +61,8 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { } tcx.hir().krate().visit_all_item_likes(&mut Visitor(tcx)); } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { - let config = MiriConfig { validate: true, args: vec![], seed: None }; + + let config = MiriConfig { validate: true, communicate: false, args: vec![], seed: None }; miri::eval_main(tcx, entry_def_id, config); compiler.session().abort_if_errors(); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 43cb19b2658e..875afd42af44 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -130,6 +130,7 @@ fn main() { // Parse our arguments and split them across `rustc` and `miri`. let mut validate = true; + let mut communicate = false; let mut seed: Option = None; let mut rustc_args = vec![]; let mut miri_args = vec![]; @@ -147,6 +148,9 @@ fn main() { "-Zmiri-disable-validation" => { validate = false; }, + "-Zmiri-enable-communication" => { + communicate = true; + }, "--" => { after_dashdash = true; } @@ -196,7 +200,7 @@ fn main() { debug!("rustc arguments: {:?}", rustc_args); debug!("miri arguments: {:?}", miri_args); - let miri_config = miri::MiriConfig { validate, args: miri_args, seed }; + let miri_config = miri::MiriConfig { validate, communicate, args: miri_args, seed }; let result = rustc_driver::report_ices_to_stderr_if_any(move || { rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None) }).and_then(|result| result); diff --git a/src/eval.rs b/src/eval.rs index bc9d97b0280f..681bad01d23c 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -18,10 +18,11 @@ use crate::{ #[derive(Clone)] pub struct MiriConfig { pub validate: bool, + pub communicate: bool, pub args: Vec, // The seed to use when non-determinism is required (e.g. getrandom()) - pub seed: Option + pub seed: Option, } // Used by priroda. @@ -158,7 +159,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( cur_ptr = cur_ptr.offset(char_size, tcx)?; } } - + assert!(args.next().is_none(), "start lang item has more arguments than expected"); Ok(ecx) From 068c448832c466e3eb6297125a12e5a83a450e2d Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 6 Aug 2019 15:32:57 -0500 Subject: [PATCH 1019/5092] Add communicate field to evaluator and fix formatting --- benches/helpers/miri_helper.rs | 7 ++++++- src/bin/miri-rustc-tests.rs | 14 ++++++++++++-- src/eval.rs | 5 +++-- src/machine.rs | 6 +++++- 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 003c93f7464d..5cb938659a6c 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -25,7 +25,12 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { ); self.bencher.iter(|| { - let config = miri::MiriConfig { validate: true, communicate: false, args: vec![], seed: None }; + let config = miri::MiriConfig { + validate: true, + communicate: false, + args: vec![], + seed: None, + }; eval_main(tcx, entry_def_id, config); }); }); diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index a1bc53f69b80..0cf171f52e7e 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -48,7 +48,12 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.node { if i.attrs.iter().any(|attr| attr.check_name(syntax::symbol::sym::test)) { - let config = MiriConfig { validate: true, communicate: false, args: vec![], seed: None }; + let config = MiriConfig { + validate: true, + communicate: false, + args: vec![], + seed: None, + }; let did = self.0.hir().body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); miri::eval_main(self.0, did, config); @@ -62,7 +67,12 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { tcx.hir().krate().visit_all_item_likes(&mut Visitor(tcx)); } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { - let config = MiriConfig { validate: true, communicate: false, args: vec![], seed: None }; + let config = MiriConfig { + validate: true, + communicate: false, + args: vec![], + seed: None + }; miri::eval_main(tcx, entry_def_id, config); compiler.session().abort_if_errors(); diff --git a/src/eval.rs b/src/eval.rs index 681bad01d23c..e80162ec1796 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -18,10 +18,11 @@ use crate::{ #[derive(Clone)] pub struct MiriConfig { pub validate: bool, + /// Determines if communication with the host environment is enabled. pub communicate: bool, pub args: Vec, - // The seed to use when non-determinism is required (e.g. getrandom()) + /// The seed to use when non-determinism is required (e.g. getrandom()) pub seed: Option, } @@ -34,7 +35,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let mut ecx = InterpCx::new( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), - Evaluator::new(), + Evaluator::new(config.communicate), MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate), ); diff --git a/src/machine.rs b/src/machine.rs index f2c81c92d3d0..ed9a8a1c4634 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -93,10 +93,13 @@ pub struct Evaluator<'tcx> { /// TLS state. pub(crate) tls: TlsData<'tcx>, + + /// If enabled, the `env_vars` field is populated with the host env vars during initialization. + pub(crate) communicate: bool, } impl<'tcx> Evaluator<'tcx> { - pub(crate) fn new() -> Self { + pub(crate) fn new(communicate: bool) -> Self { Evaluator { env_vars: HashMap::default(), argc: None, @@ -104,6 +107,7 @@ impl<'tcx> Evaluator<'tcx> { cmd_line: None, last_error: 0, tls: TlsData::default(), + communicate, } } } From 0df7a728c684606a3ee275ca32d3d56c17902c76 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 6 Aug 2019 15:47:57 -0500 Subject: [PATCH 1020/5092] Update readme --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 8c5a29880c7c..a9cd9ee938c5 100644 --- a/README.md +++ b/README.md @@ -157,6 +157,9 @@ Several `-Z` flags are relevant for Miri: is enforced by default. This is mostly useful for debugging; it means Miri will miss bugs in your program. However, this can also help to make Miri run faster. +* `-Zmiri-enable-communication` enables communication between the host + environment and Miri, i.e., all the host environment variables are available + during Miri runtime. * `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri overrides the default to be `0`; be advised that using any higher level can make Miri miss bugs in your program because they got optimized away. From b731a6a15f3ac426ca29f5bdbe4e3d7bd68d9685 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 6 Aug 2019 17:40:07 -0500 Subject: [PATCH 1021/5092] Add support for env communication --- src/eval.rs | 8 ++++++++ src/shims/env.rs | 23 +++++++++++++++++++++++ src/shims/foreign_items.rs | 23 +++-------------------- src/shims/mod.rs | 1 + tests/run-pass/communication.rs | 6 ++++++ 5 files changed, 41 insertions(+), 20 deletions(-) create mode 100644 src/shims/env.rs create mode 100644 tests/run-pass/communication.rs diff --git a/src/eval.rs b/src/eval.rs index e80162ec1796..b171b38a6cbd 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -13,6 +13,7 @@ use crate::{ Scalar, Tag, Pointer, FnVal, MemoryExtra, MiriMemoryKind, Evaluator, TlsEvalContextExt, HelpersEvalContextExt, }; +use crate::shims::env::alloc_env_value; /// Configuration needed to spawn a Miri instance. #[derive(Clone)] @@ -163,6 +164,13 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( assert!(args.next().is_none(), "start lang item has more arguments than expected"); + if config.communicate { + for (name, value) in std::env::vars() { + let value = alloc_env_value(value.as_bytes(), ecx.memory_mut(), &tcx); + ecx.machine.env_vars.insert(name.into_bytes(), value); + } + } + Ok(ecx) } diff --git a/src/shims/env.rs b/src/shims/env.rs new file mode 100644 index 000000000000..0cb8c9c370c3 --- /dev/null +++ b/src/shims/env.rs @@ -0,0 +1,23 @@ +use rustc::ty::{layout::{Size, Align}, TyCtxt}; +use rustc_mir::interpret::Memory; + +use crate::*; + +pub(crate) fn alloc_env_value<'mir, 'tcx>(bytes: &[u8], memory: &mut Memory<'mir, 'tcx, Evaluator<'tcx>>, tcx: &TyCtxt<'tcx>) -> Pointer { + let length = bytes.len() as u64; + // `+1` for the null terminator. + let ptr = memory.allocate( + Size::from_bytes(length + 1), + Align::from_bytes(1).unwrap(), + MiriMemoryKind::Env.into(), + ); + // We just allocated these, so the write cannot fail. + let alloc = memory.get_mut(ptr.alloc_id).unwrap(); + alloc.write_bytes(tcx, ptr, &bytes).unwrap(); + let trailing_zero_ptr = ptr.offset( + Size::from_bytes(length), + tcx, + ).unwrap(); + alloc.write_bytes(tcx, trailing_zero_ptr, &[0]).unwrap(); + ptr +} diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 37e5fe42c3de..b1554395b692 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -5,6 +5,7 @@ use syntax::attr; use syntax::symbol::sym; use crate::*; +use crate::shims::env::alloc_env_value; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -465,26 +466,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } if let Some((name, value)) = new { - // `+1` for the null terminator. - let value_copy = this.memory_mut().allocate( - Size::from_bytes((value.len() + 1) as u64), - Align::from_bytes(1).unwrap(), - MiriMemoryKind::Env.into(), - ); - // We just allocated these, so the write cannot fail. - let alloc = this.memory_mut().get_mut(value_copy.alloc_id).unwrap(); - alloc.write_bytes(tcx, value_copy, &value).unwrap(); - let trailing_zero_ptr = value_copy.offset( - Size::from_bytes(value.len() as u64), - tcx, - ).unwrap(); - alloc.write_bytes(tcx, trailing_zero_ptr, &[0]).unwrap(); - - if let Some(var) = this.machine.env_vars.insert( - name.to_owned(), - value_copy, - ) - { + let value_copy = alloc_env_value(&value, this.memory_mut(), tcx); + if let Some(var) = this.machine.env_vars.insert(name.to_owned(), value_copy) { this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; } this.write_null(dest)?; diff --git a/src/shims/mod.rs b/src/shims/mod.rs index c06373005ff9..96a1f34152b3 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -2,6 +2,7 @@ pub mod foreign_items; pub mod intrinsics; pub mod tls; pub mod dlsym; +pub mod env; use rustc::{ty, mir}; diff --git a/tests/run-pass/communication.rs b/tests/run-pass/communication.rs new file mode 100644 index 000000000000..08c6bd88fd68 --- /dev/null +++ b/tests/run-pass/communication.rs @@ -0,0 +1,6 @@ +// ignore-windows: TODO env var emulation stubbed out on Windows +// compile-flags: -Zmiri-enable-communication + +fn main() { + assert!(std::env::var("PWD").is_ok()); +} From 455531c564b7c849eb505876a9810f98e2f9fca2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Aug 2019 10:24:27 +0200 Subject: [PATCH 1022/5092] Revert "uninit intrinsic is gone" This reverts commit fa290f1a481b0f98ed1de06206e643af8e04acd5. Uninit is being reinstated because it breaks some broken code. --- src/shims/intrinsics.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index c96869c80cee..4e957f792b75 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -522,6 +522,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } + "uninit" => { + // Check fast path: we don't want to force an allocation in case the destination is a simple value, + // but we also do not want to create a new allocation with 0s and then copy that over. + // FIXME: We do not properly validate in case of ZSTs and when doing it in memory! + // However, this only affects direct calls of the intrinsic; calls to the stable + // functions wrapping them do get their validation. + // FIXME: should we check alignment for ZSTs? + use crate::ScalarMaybeUndef; + if !dest.layout.is_zst() { + match dest.layout.abi { + layout::Abi::Scalar(..) => { + let x = ScalarMaybeUndef::Undef; + this.write_immediate(Immediate::Scalar(x), dest)?; + } + layout::Abi::ScalarPair(..) => { + let x = ScalarMaybeUndef::Undef; + this.write_immediate(Immediate::ScalarPair(x, x), dest)?; + } + _ => { + // Do it in memory + let mplace = this.force_allocation(dest)?; + assert!(mplace.meta.is_none()); + let ptr = mplace.ptr.to_ptr()?; + this.memory_mut() + .get_mut(ptr.alloc_id)? + .mark_definedness(ptr, dest.layout.size, false); + } + } + } + } + "write_bytes" => { let ty = substs.type_at(0); let ty_layout = this.layout_of(ty)?; From af623dede2437244eabe7a6833b28ec2535de82a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 7 Aug 2019 09:09:13 -0500 Subject: [PATCH 1023/5092] Add env var test variable in compiletest --- tests/compiletest.rs | 3 +++ tests/run-pass/communication.rs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index eaf7f8531b8f..c5fba3d46e2f 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -37,6 +37,9 @@ fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec) { flags.push(format!("--sysroot {}", sysroot)); } + // Add a test env var to do evironment communication tests + std::env::set_var("MIRI_ENV_VAR_TEST", "0"); + // The rest of the configuration. let mut config = compiletest::Config::default().tempdir(); config.mode = mode.parse().expect("Invalid mode"); diff --git a/tests/run-pass/communication.rs b/tests/run-pass/communication.rs index 08c6bd88fd68..e3fb0c5bd5e0 100644 --- a/tests/run-pass/communication.rs +++ b/tests/run-pass/communication.rs @@ -2,5 +2,5 @@ // compile-flags: -Zmiri-enable-communication fn main() { - assert!(std::env::var("PWD").is_ok()); + assert_eq!(std::env::var("MIRI_ENV_VAR_TEST"), Ok("0".to_owned())); } From 253af9692afebc1a4b460fd2ac2cc842d007d573 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 7 Aug 2019 09:10:39 -0500 Subject: [PATCH 1024/5092] Fix formatting --- src/shims/env.rs | 6 +++++- tests/compiletest.rs | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 0cb8c9c370c3..56d2bd4b3d3e 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -3,7 +3,11 @@ use rustc_mir::interpret::Memory; use crate::*; -pub(crate) fn alloc_env_value<'mir, 'tcx>(bytes: &[u8], memory: &mut Memory<'mir, 'tcx, Evaluator<'tcx>>, tcx: &TyCtxt<'tcx>) -> Pointer { +pub(crate) fn alloc_env_value<'mir, 'tcx>( + bytes: &[u8], + memory: &mut Memory<'mir, 'tcx, Evaluator<'tcx>>, + tcx: &TyCtxt<'tcx>, +) -> Pointer { let length = bytes.len() as u64; // `+1` for the null terminator. let ptr = memory.allocate( diff --git a/tests/compiletest.rs b/tests/compiletest.rs index c5fba3d46e2f..f61faa9fcc61 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -37,7 +37,7 @@ fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec) { flags.push(format!("--sysroot {}", sysroot)); } - // Add a test env var to do evironment communication tests + // Add a test env var to do environment communication tests std::env::set_var("MIRI_ENV_VAR_TEST", "0"); // The rest of the configuration. From f544721de41b6b5e7b93dbc85840431abe195614 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Wed, 7 Aug 2019 16:39:54 -0700 Subject: [PATCH 1025/5092] Add generator, async tests with uninhabited saved local --- tests/run-pass/async-fn.rs | 36 ++++++++++++++++++++++++++++++++++++ tests/run-pass/generator.rs | 13 +++++++++++++ 2 files changed, 49 insertions(+) diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 5c916473b580..25b9b9ac5ba4 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -14,6 +14,32 @@ pub async fn foo(x: &u32, y: u32) -> u32 { *x + y + *a } +async fn add(x: u32, y: u32) -> u32 { + async { x + y }.await +} + +async fn build_aggregate(a: u32, b: u32, c: u32, d: u32) -> u32 { + let x = (add(a, b).await, add(c, d).await); + x.0 + x.1 +} + +enum Never {} +fn never() -> Never { + panic!() +} + +async fn includes_never(crash: bool, x: u32) -> u32 { + let mut result = async { x * x }.await; + if !crash { + return result; + } + #[allow(unused)] + let bad = never(); + result *= async { x + x }.await; + drop(bad); + result +} + fn raw_waker_clone(_this: *const ()) -> RawWaker { panic!("unimplemented"); } @@ -38,4 +64,14 @@ fn main() { let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &RAW_WAKER)) }; let mut context = Context::from_waker(&waker); assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(31)); + + let mut fut = build_aggregate(1, 2, 3, 4); + let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &RAW_WAKER)) }; + let mut context = Context::from_waker(&waker); + assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(10)); + + let mut fut = includes_never(false, 4); + let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &RAW_WAKER)) }; + let mut context = Context::from_waker(&waker); + assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(16)); } diff --git a/tests/run-pass/generator.rs b/tests/run-pass/generator.rs index 477f548a7b06..5064d8daf0f3 100644 --- a/tests/run-pass/generator.rs +++ b/tests/run-pass/generator.rs @@ -17,7 +17,11 @@ fn finish(mut amt: usize, mut t: T) -> T::Return } } } +} +enum Never {} +fn never() -> Never { + panic!() } fn main() { @@ -67,4 +71,13 @@ fn main() { }), 10 ); + let b = true; + finish(1, || { + yield 1; + if b { return; } + #[allow(unused)] + let x = never(); + yield 2; + drop(x); + }); } From 19367fd8de5449900d9c059d84f48e8499e59b5d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 8 Aug 2019 19:34:23 +0200 Subject: [PATCH 1026/5092] bump xargo version --- src/bin/cargo-miri.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 4da039a42d9e..b1dc306bcb1d 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -243,7 +243,7 @@ fn setup(ask_user: bool) { } // First, we need xargo. - if xargo_version().map_or(true, |v| v < (0, 3, 14)) { + if xargo_version().map_or(true, |v| v < (0, 3, 15)) { if ask_user { ask("It seems you do not have a recent enough xargo installed. I will run `cargo install xargo -f`. Proceed?"); } else { From e1d1cd191f6601b0ed2219beb7a4fb00f25b6667 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 8 Aug 2019 15:22:34 -0500 Subject: [PATCH 1027/5092] Use ldexp from cmath instead --- src/shims/foreign_items.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 37e5fe42c3de..ba9b7ca27eb0 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -594,8 +594,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: Using host floats. let x = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); let exp = this.read_scalar(args[1])?.to_i32()?; - // FIXME: We should use cmath if there are any imprecisions. - let n = x * 2.0f64.powi(exp); + extern { + fn ldexp(x: f64, n: i32) -> f64; + } + let n = unsafe { ldexp(x, exp) }; this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?; } From d5294a5bf3457c7565f1fce4ce804682a2f8fa10 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Aug 2019 10:32:53 +0200 Subject: [PATCH 1028/5092] test generator that yields during initialization of struct with uninhabited field --- tests/run-pass/generator.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/generator.rs b/tests/run-pass/generator.rs index 5064d8daf0f3..c31b5b9ed3bb 100644 --- a/tests/run-pass/generator.rs +++ b/tests/run-pass/generator.rs @@ -1,4 +1,4 @@ -#![feature(generators, generator_trait)] +#![feature(generators, generator_trait, never_type)] use std::ops::{GeneratorState, Generator}; use std::pin::Pin; @@ -26,6 +26,7 @@ fn never() -> Never { fn main() { finish(1, || yield 1); + finish(3, || { let mut x = 0; yield 1; @@ -35,23 +36,27 @@ fn main() { yield 1; assert_eq!(x, 2); }); + finish(7*8/2, || { for i in 0..8 { yield i; } }); + finish(1, || { if true { yield 1; } else { } }); + finish(1, || { if false { } else { yield 1; } }); + finish(2, || { if { yield 1; false } { yield 1; @@ -59,6 +64,7 @@ fn main() { } yield 1; }); + // also test a self-referential generator assert_eq!( finish(5, || { @@ -71,6 +77,7 @@ fn main() { }), 10 ); + let b = true; finish(1, || { yield 1; @@ -80,4 +87,10 @@ fn main() { yield 2; drop(x); }); + + finish(3, || { + yield 1; + #[allow(unreachable_code)] + let _x: (String, !) = (String::new(), { yield 2; return }); + }); } From fc06cb71bfa606ed602969868abd9623c27464e9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Aug 2019 10:26:48 +0200 Subject: [PATCH 1029/5092] simplify async-fn tests --- tests/run-pass/async-fn.rs | 53 ++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 25b9b9ac5ba4..3f3729d70834 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -40,38 +40,35 @@ async fn includes_never(crash: bool, x: u32) -> u32 { result } -fn raw_waker_clone(_this: *const ()) -> RawWaker { - panic!("unimplemented"); -} -fn raw_waker_wake(_this: *const ()) { - panic!("unimplemented"); -} -fn raw_waker_wake_by_ref(_this: *const ()) { - panic!("unimplemented"); -} -fn raw_waker_drop(_this: *const ()) {} +fn run_fut(mut fut: impl Future, output: u32) { + fn raw_waker_clone(_this: *const ()) -> RawWaker { + panic!("unimplemented"); + } + fn raw_waker_wake(_this: *const ()) { + panic!("unimplemented"); + } + fn raw_waker_wake_by_ref(_this: *const ()) { + panic!("unimplemented"); + } + fn raw_waker_drop(_this: *const ()) {} -static RAW_WAKER: RawWakerVTable = RawWakerVTable::new( - raw_waker_clone, - raw_waker_wake, - raw_waker_wake_by_ref, - raw_waker_drop, -); + static RAW_WAKER: RawWakerVTable = RawWakerVTable::new( + raw_waker_clone, + raw_waker_wake, + raw_waker_wake_by_ref, + raw_waker_drop, + ); + + let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &RAW_WAKER)) }; + let mut context = Context::from_waker(&waker); + assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(output)); +} fn main() { let x = 5; - let mut fut = foo(&x, 7); - let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &RAW_WAKER)) }; - let mut context = Context::from_waker(&waker); - assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(31)); + run_fut(foo(&x, 7), 31); - let mut fut = build_aggregate(1, 2, 3, 4); - let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &RAW_WAKER)) }; - let mut context = Context::from_waker(&waker); - assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(10)); + run_fut(build_aggregate(1, 2, 3, 4), 10); - let mut fut = includes_never(false, 4); - let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &RAW_WAKER)) }; - let mut context = Context::from_waker(&waker); - assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(16)); + run_fut(includes_never(false, 4), 16); } From abcd2449273ebced7df695be2249f56ed4c8f331 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Aug 2019 11:01:11 +0200 Subject: [PATCH 1030/5092] add async fn with partial initialization --- tests/run-pass/async-fn.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 3f3729d70834..91266f67aa8e 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -1,4 +1,4 @@ -#![feature(async_await)] +#![feature(async_await, never_type)] use std::{future::Future, pin::Pin, task::Poll, ptr}; use std::task::{Waker, RawWaker, RawWakerVTable, Context}; @@ -40,6 +40,11 @@ async fn includes_never(crash: bool, x: u32) -> u32 { result } +async fn partial_init(x: u32) -> u32 { + #[allow(unreachable_code)] + let _x: (String, !) = (String::new(), return async { x + x }.await); +} + fn run_fut(mut fut: impl Future, output: u32) { fn raw_waker_clone(_this: *const ()) -> RawWaker { panic!("unimplemented"); @@ -71,4 +76,6 @@ fn main() { run_fut(build_aggregate(1, 2, 3, 4), 10); run_fut(includes_never(false, 4), 16); + + run_fut(partial_init(4), 8); } From b5ce8f410bd04b97f25b5903ca014eaf99d4dc46 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Aug 2019 11:03:45 +0200 Subject: [PATCH 1031/5092] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index e09b2fc7e55f..d2d7536dcae9 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4be067558962c004b638e4c6f162d50f7c0c98b6 +5aa3d9a7b5d3a46a7f158e8881146331a6bc9243 From 68d7e4ebb045ecd1d4ff14847d0c2cd577b0bf60 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Aug 2019 11:29:10 +0200 Subject: [PATCH 1032/5092] local rustc builds now also need a sysroot built With the test-miri flag gone, the libstd of local builds isn't good enough for Miri any more. --- miri | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/miri b/miri index 15bfeed4da06..1f46f04c13e8 100755 --- a/miri +++ b/miri @@ -60,27 +60,19 @@ build_sysroot() { # Prepare and set MIRI_SYSROOT. Respects `MIRI_TEST_TARGET` and takes into account # locally built vs. distributed rustc. find_sysroot() { - # Get ourselves a sysroot if [ -n "$MIRI_SYSROOT" ]; then # Sysroot already set, use that. - true - elif echo "$SYSROOT" | egrep -q 'build/[^/]+/stage'; then - # A local rustc build. - if [ -n "$MIRI_TEST_TARGET" ]; then - # Foreign targets still need a build. Use the rustc sources. - export XARGO_RUST_SRC="$SYSROOT/../../../src" - build_sysroot --target "$MIRI_TEST_TARGET" - else - # Assume we have a proper host libstd in $SYSROOT. - MIRI_SYSROOT="$SYSROOT" - fi + return 0 + fi + # We need to build a sysroot. + if echo "$SYSROOT" | egrep -q 'build/[^/]+/stage'; then + # A local rustc build. Use its source dir. + export XARGO_RUST_SRC="$SYSROOT/../../../src" + fi + if [ -n "$MIRI_TEST_TARGET" ]; then + build_sysroot --target "$MIRI_TEST_TARGET" else - # A normal toolchain. We have to build a sysroot either way. - if [ -n "$MIRI_TEST_TARGET" ]; then - build_sysroot --target "$MIRI_TEST_TARGET" - else - build_sysroot - fi + build_sysroot fi export MIRI_SYSROOT } From b93629262dc66361387fd045e53bd01e9e45311b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Aug 2019 19:21:41 +0200 Subject: [PATCH 1033/5092] test that even &Cell must be dereferencable --- ...arrier.rs => deallocate_against_barrier1.rs} | 0 .../deallocate_against_barrier2.rs | 17 +++++++++++++++++ 2 files changed, 17 insertions(+) rename tests/compile-fail/stacked_borrows/{deallocate_against_barrier.rs => deallocate_against_barrier1.rs} (100%) create mode 100644 tests/compile-fail/stacked_borrows/deallocate_against_barrier2.rs diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs b/tests/compile-fail/stacked_borrows/deallocate_against_barrier1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs rename to tests/compile-fail/stacked_borrows/deallocate_against_barrier1.rs diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.rs b/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.rs new file mode 100644 index 000000000000..db4d2d998dbd --- /dev/null +++ b/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.rs @@ -0,0 +1,17 @@ +// error-pattern: deallocating while item is protected + +use std::cell::Cell; + +// Check that even `&Cell` are dereferencable. +// Also see . +fn inner(x: &Cell, f: fn(&Cell)) { + // `f` may mutate, but it may not deallocate! + f(x) +} + +fn main() { + inner(Box::leak(Box::new(Cell::new(0))), |x| { + let raw = x as *const _ as *mut Cell; + drop(unsafe { Box::from_raw(raw) }); + }); +} From 5e3035b6cbf02d29157ab5633142cf741e7b2361 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Aug 2019 19:53:42 +0200 Subject: [PATCH 1034/5092] use apfloat for ldexp --- src/shims/foreign_items.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index ba9b7ca27eb0..d7c2b86c2c2d 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -1,3 +1,6 @@ +use std::convert::TryInto; + +use rustc_apfloat::Float; use rustc::ty::layout::{Align, LayoutOf, Size}; use rustc::hir::def_id::DefId; use rustc::mir; @@ -591,14 +594,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // underscore case for windows "_ldexp" | "ldexp" => { - // FIXME: Using host floats. - let x = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); + let x = this.read_scalar(args[0])?.to_f64()?; let exp = this.read_scalar(args[1])?.to_i32()?; - extern { - fn ldexp(x: f64, n: i32) -> f64; - } - let n = unsafe { ldexp(x, exp) }; - this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?; + // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. + let res = x.scalbn(exp.try_into().unwrap()); + this.write_scalar(Scalar::from_f64(res), dest)?; } // Some things needed for `sys::thread` initialization to go through. From 3ae01a64bcc649942cee70f6cba7e765b0850942 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 Aug 2019 11:22:32 +0200 Subject: [PATCH 1035/5092] also support scalbn itself --- src/shims/foreign_items.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index d7c2b86c2c2d..add6bd5bbefd 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -580,7 +580,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; this.write_scalar(Scalar::from_u64(f.to_bits()), dest)?; } - // underscore case for windows + // underscore case for windows, here and below + // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) "_hypot" | "hypot" | "atan2" => { // FIXME: Using host floats. let f1 = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); @@ -592,11 +593,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?; } - // underscore case for windows - "_ldexp" | "ldexp" => { + // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. + "_ldexp" | "ldexp" | "scalbn" => { let x = this.read_scalar(args[0])?.to_f64()?; let exp = this.read_scalar(args[1])?.to_i32()?; - // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. let res = x.scalbn(exp.try_into().unwrap()); this.write_scalar(Scalar::from_f64(res), dest)?; } From 0743ed631efe63ae2de96847df7b7fce629127b6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 Aug 2019 11:27:27 +0200 Subject: [PATCH 1036/5092] clamp ldexp exponent to i16 --- src/shims/foreign_items.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index add6bd5bbefd..4cca6b9efdd1 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -597,7 +597,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "_ldexp" | "ldexp" | "scalbn" => { let x = this.read_scalar(args[0])?.to_f64()?; let exp = this.read_scalar(args[1])?.to_i32()?; - let res = x.scalbn(exp.try_into().unwrap()); + // Saturating cast to i16. Even those are outside the valid exponent range to + // `scalbn` below will to its over/underflow handling. + let exp = if exp > i16::max_value() as i32 { + i16::max_value() + } else if exp < i16::min_value() as i32 { + i16::min_value() + } else { + exp.try_into().unwrap() + }; + let res = x.scalbn(exp); this.write_scalar(Scalar::from_f64(res), dest)?; } From 33eb5657d6b3677b000680e9fd349550143d3693 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 Aug 2019 11:31:20 +0200 Subject: [PATCH 1037/5092] ldexp: test overflow behavior --- tests/run-pass/intrinsics-math.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/run-pass/intrinsics-math.rs b/tests/run-pass/intrinsics-math.rs index 63098f5fd3f7..f435611b2b69 100644 --- a/tests/run-pass/intrinsics-math.rs +++ b/tests/run-pass/intrinsics-math.rs @@ -16,6 +16,13 @@ macro_rules! assert_approx_eq { }) } +fn ldexp(a: f64, b: i32) -> f64 { + extern { + fn ldexp(x: f64, n: i32) -> f64; + } + unsafe { ldexp(a, b) } +} + pub fn main() { use std::f32; use std::f64; @@ -88,8 +95,7 @@ pub fn main() { assert_eq!(3.3_f32.round(), 3.0); assert_eq!(3.3_f64.round(), 3.0); - extern { - fn ldexp(x: f64, n: i32) -> f64; - } - unsafe { assert_approx_eq!(ldexp(0.65f64, 3i32), 5.2f64); } + assert_eq!(ldexp(0.65f64, 3i32), 5.2f64); + assert_eq!(ldexp(1.42, 0xFFFF), f64::INFINITY); + assert_eq!(ldexp(1.42, -0xFFFF), 0f64); } From 04892d915512abe85d7a663b68dc62ef802eef30 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 Aug 2019 11:33:33 +0200 Subject: [PATCH 1038/5092] typo --- src/shims/foreign_items.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 4cca6b9efdd1..0288773044ac 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -597,8 +597,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "_ldexp" | "ldexp" | "scalbn" => { let x = this.read_scalar(args[0])?.to_f64()?; let exp = this.read_scalar(args[1])?.to_i32()?; + // Saturating cast to i16. Even those are outside the valid exponent range to - // `scalbn` below will to its over/underflow handling. + // `scalbn` below will do its over/underflow handling. let exp = if exp > i16::max_value() as i32 { i16::max_value() } else if exp < i16::min_value() as i32 { @@ -606,6 +607,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { exp.try_into().unwrap() }; + let res = x.scalbn(exp); this.write_scalar(Scalar::from_f64(res), dest)?; } From 7a9733929b8e56d2def8bfeb8ce0dfef9e402949 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Aug 2019 08:25:31 +0200 Subject: [PATCH 1039/5092] it's called RUSTC_CTFE_BACKTRACE now --- rust-version | 2 +- src/bin/miri.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index d2d7536dcae9..6a1f1c81bdfa 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -5aa3d9a7b5d3a46a7f158e8881146331a6bc9243 +00ee1b47f42129a0a6e33510578fbcf07c1e5382 diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 43cb19b2658e..29076828d814 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -92,11 +92,11 @@ fn init_late_loggers() { } } - // If `MIRI_BACKTRACE` is set and `RUST_CTFE_BACKTRACE` is not, set `RUST_CTFE_BACKTRACE`. - // Do this late, so we really only apply this to miri's errors. + // If `MIRI_BACKTRACE` is set and `RUSTC_CTFE_BACKTRACE` is not, set `RUSTC_CTFE_BACKTRACE`. + // Do this late, so we ideally only apply this to Miri's errors. if let Ok(var) = env::var("MIRI_BACKTRACE") { - if env::var("RUST_CTFE_BACKTRACE") == Err(env::VarError::NotPresent) { - env::set_var("RUST_CTFE_BACKTRACE", &var); + if env::var("RUSTC_CTFE_BACKTRACE") == Err(env::VarError::NotPresent) { + env::set_var("RUSTC_CTFE_BACKTRACE", &var); } } } From 95fb11d51fdd3523f96dca81835681274086e656 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 13 Aug 2019 09:29:01 +0200 Subject: [PATCH 1040/5092] make TLS state private to TLS module --- src/shims/tls.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index d2190bd969e3..e90ace948b7a 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -18,17 +18,17 @@ pub struct TlsEntry<'tcx> { /// The data for this key. None is used to represent NULL. /// (We normalize this early to avoid having to do a NULL-ptr-test each time we access the data.) /// Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. - pub(crate) data: Option>, - pub(crate) dtor: Option>, + data: Option>, + dtor: Option>, } #[derive(Debug)] pub struct TlsData<'tcx> { /// The Key to use for the next thread-local allocation. - pub(crate) next_key: TlsKey, + next_key: TlsKey, /// pthreads-style thread-local storage. - pub(crate) keys: BTreeMap>, + keys: BTreeMap>, } impl<'tcx> Default for TlsData<'tcx> { From 666cd22fa64ee318edc3b6292efa507442eb2554 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 13 Aug 2019 11:34:43 -0500 Subject: [PATCH 1041/5092] Wrap hashmap for env vars in its own type --- src/eval.rs | 11 ++++------- src/machine.rs | 6 +++--- src/shims/env.rs | 35 +++++++++++++++++++++++++++++++++-- src/shims/foreign_items.rs | 4 ++-- 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index b171b38a6cbd..5e6c8129fb31 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -13,17 +13,17 @@ use crate::{ Scalar, Tag, Pointer, FnVal, MemoryExtra, MiriMemoryKind, Evaluator, TlsEvalContextExt, HelpersEvalContextExt, }; -use crate::shims::env::alloc_env_value; +use crate::shims::env::EnvVars; /// Configuration needed to spawn a Miri instance. #[derive(Clone)] pub struct MiriConfig { + /// Determine if validity checking and Stacked Borrows are enabled. pub validate: bool, /// Determines if communication with the host environment is enabled. pub communicate: bool, pub args: Vec, - - /// The seed to use when non-determinism is required (e.g. getrandom()) + /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`). pub seed: Option, } @@ -165,10 +165,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( assert!(args.next().is_none(), "start lang item has more arguments than expected"); if config.communicate { - for (name, value) in std::env::vars() { - let value = alloc_env_value(value.as_bytes(), ecx.memory_mut(), &tcx); - ecx.machine.env_vars.insert(name.into_bytes(), value); - } + EnvVars::init(&mut ecx, &tcx); } Ok(ecx) diff --git a/src/machine.rs b/src/machine.rs index ed9a8a1c4634..cc0c85d6603d 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -3,7 +3,6 @@ use std::rc::Rc; use std::borrow::Cow; -use std::collections::HashMap; use std::cell::RefCell; use rand::rngs::StdRng; @@ -15,6 +14,7 @@ use rustc::ty::{self, layout::{Size, LayoutOf}, TyCtxt}; use rustc::mir; use crate::*; +use crate::shims::env::EnvVars; // Some global facts about the emulated machine. pub const PAGE_SIZE: u64 = 4*1024; // FIXME: adjust to target architecture @@ -79,7 +79,7 @@ impl MemoryExtra { pub struct Evaluator<'tcx> { /// Environment variables set by `setenv`. /// Miri does not expose env vars from the host to the emulated program. - pub(crate) env_vars: HashMap, Pointer>, + pub(crate) env_vars: EnvVars, /// Program arguments (`Option` because we can only initialize them after creating the ecx). /// These are *pointers* to argc/argv because macOS. @@ -101,7 +101,7 @@ pub struct Evaluator<'tcx> { impl<'tcx> Evaluator<'tcx> { pub(crate) fn new(communicate: bool) -> Self { Evaluator { - env_vars: HashMap::default(), + env_vars: EnvVars::default(), argc: None, argv: None, cmd_line: None, diff --git a/src/shims/env.rs b/src/shims/env.rs index 56d2bd4b3d3e..09d87d27ebc2 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,8 +1,39 @@ -use rustc::ty::{layout::{Size, Align}, TyCtxt}; -use rustc_mir::interpret::Memory; +use std::collections::HashMap; +use rustc::ty::{layout::{Size, Align}, TyCtxt}; +use rustc_mir::interpret::{Pointer, Memory}; +use crate::stacked_borrows::Tag; use crate::*; +#[derive(Default)] +pub struct EnvVars { + map: HashMap, Pointer>, +} + +impl EnvVars { + pub(crate) fn init<'mir, 'tcx>( + ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, + tcx: &TyCtxt<'tcx>, + ) { + for (name, value) in std::env::vars() { + let value = alloc_env_value(value.as_bytes(), ecx.memory_mut(), tcx); + ecx.machine.env_vars.map.insert(name.into_bytes(), value); + } + } + + pub(crate) fn get(&self, name: &[u8]) -> Option<&Pointer> { + self.map.get(name) + } + + pub(crate) fn unset(&mut self, name: &[u8]) -> Option> { + self.map.remove(name) + } + + pub(crate) fn set(&mut self, name: Vec, ptr: Pointer) -> Option>{ + self.map.insert(name, ptr) + } +} + pub(crate) fn alloc_env_value<'mir, 'tcx>( bytes: &[u8], memory: &mut Memory<'mir, 'tcx, Evaluator<'tcx>>, diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index b1554395b692..6705183da47f 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -438,7 +438,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if !this.is_null(name_ptr)? { let name = this.memory().read_c_str(name_ptr)?.to_owned(); if !name.is_empty() && !name.contains(&b'=') { - success = Some(this.machine.env_vars.remove(&name)); + success = Some(this.machine.env_vars.unset(&name)); } } } @@ -467,7 +467,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } if let Some((name, value)) = new { let value_copy = alloc_env_value(&value, this.memory_mut(), tcx); - if let Some(var) = this.machine.env_vars.insert(name.to_owned(), value_copy) { + if let Some(var) = this.machine.env_vars.set(name.to_owned(), value_copy) { this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; } this.write_null(dest)?; From 67d13577aac2e47a0f40292c5c966469cbc610d7 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 13 Aug 2019 12:10:24 -0500 Subject: [PATCH 1042/5092] Move test env var to test_runner --- src/bin/miri-rustc-tests.rs | 1 - tests/compiletest.rs | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 0cf171f52e7e..9ef64c38638b 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -66,7 +66,6 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { } tcx.hir().krate().visit_all_item_likes(&mut Visitor(tcx)); } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { - let config = MiriConfig { validate: true, communicate: false, diff --git a/tests/compiletest.rs b/tests/compiletest.rs index f61faa9fcc61..702c6026eced 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -37,9 +37,6 @@ fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec) { flags.push(format!("--sysroot {}", sysroot)); } - // Add a test env var to do environment communication tests - std::env::set_var("MIRI_ENV_VAR_TEST", "0"); - // The rest of the configuration. let mut config = compiletest::Config::default().tempdir(); config.mode = mode.parse().expect("Invalid mode"); @@ -126,6 +123,9 @@ fn compile_fail_miri(opt: bool) { } fn test_runner(_tests: &[&()]) { + // Add a test env var to do environment communication tests + std::env::set_var("MIRI_ENV_VAR_TEST", "0"); + run_pass_miri(false); run_pass_miri(true); From afc6713e4178fc4c375e7acea8898534f2e6fba3 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 13 Aug 2019 16:17:41 -0500 Subject: [PATCH 1043/5092] Reorganize shims::env::EnvVars --- src/eval.rs | 8 +++----- src/lib.rs | 1 + src/machine.rs | 7 ++++--- src/shims/env.rs | 9 ++++++--- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 5e6c8129fb31..936ae5b89532 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -12,8 +12,8 @@ use crate::{ InterpResult, InterpError, InterpCx, StackPopCleanup, struct_error, Scalar, Tag, Pointer, FnVal, MemoryExtra, MiriMemoryKind, Evaluator, TlsEvalContextExt, HelpersEvalContextExt, + ShimsEnvVars, }; -use crate::shims::env::EnvVars; /// Configuration needed to spawn a Miri instance. #[derive(Clone)] @@ -40,6 +40,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate), ); + ShimsEnvVars::init(config.communicate, &mut ecx, &tcx); + let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; @@ -164,10 +166,6 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( assert!(args.next().is_none(), "start lang item has more arguments than expected"); - if config.communicate { - EnvVars::init(&mut ecx, &tcx); - } - Ok(ecx) } diff --git a/src/lib.rs b/src/lib.rs index 58f572bf7011..216e41d4f838 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,6 +33,7 @@ pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextEx pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::dlsym::{Dlsym, EvalContextExt as DlsymEvalContextExt}; +pub use crate::shims::env::{EnvVars as ShimsEnvVars}; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; diff --git a/src/machine.rs b/src/machine.rs index cc0c85d6603d..635b46bcdb04 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -14,7 +14,6 @@ use rustc::ty::{self, layout::{Size, LayoutOf}, TyCtxt}; use rustc::mir; use crate::*; -use crate::shims::env::EnvVars; // Some global facts about the emulated machine. pub const PAGE_SIZE: u64 = 4*1024; // FIXME: adjust to target architecture @@ -79,7 +78,7 @@ impl MemoryExtra { pub struct Evaluator<'tcx> { /// Environment variables set by `setenv`. /// Miri does not expose env vars from the host to the emulated program. - pub(crate) env_vars: EnvVars, + pub(crate) env_vars: ShimsEnvVars, /// Program arguments (`Option` because we can only initialize them after creating the ecx). /// These are *pointers* to argc/argv because macOS. @@ -101,7 +100,9 @@ pub struct Evaluator<'tcx> { impl<'tcx> Evaluator<'tcx> { pub(crate) fn new(communicate: bool) -> Self { Evaluator { - env_vars: EnvVars::default(), + // `env_vars` could be initialized properly here if `Memory` were available before + // calling this method. + env_vars: ShimsEnvVars::default(), argc: None, argv: None, cmd_line: None, diff --git a/src/shims/env.rs b/src/shims/env.rs index 09d87d27ebc2..4a15eb4cfb48 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -12,12 +12,15 @@ pub struct EnvVars { impl EnvVars { pub(crate) fn init<'mir, 'tcx>( + communicate: bool, ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, tcx: &TyCtxt<'tcx>, ) { - for (name, value) in std::env::vars() { - let value = alloc_env_value(value.as_bytes(), ecx.memory_mut(), tcx); - ecx.machine.env_vars.map.insert(name.into_bytes(), value); + if communicate { + for (name, value) in std::env::vars() { + let value = alloc_env_value(value.as_bytes(), ecx.memory_mut(), tcx); + ecx.machine.env_vars.map.insert(name.into_bytes(), value); + } } } From f451fe21bdae10709b98406544c61689e1691163 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 13 Aug 2019 16:17:53 -0500 Subject: [PATCH 1044/5092] Test env isolation --- tests/run-pass/env.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/run-pass/env.rs b/tests/run-pass/env.rs index 91e15f249d45..faf947420347 100644 --- a/tests/run-pass/env.rs +++ b/tests/run-pass/env.rs @@ -6,4 +6,6 @@ fn main() { assert_eq!(env::var("MIRI_TEST"), Err(env::VarError::NotPresent)); env::set_var("MIRI_TEST", "the answer"); assert_eq!(env::var("MIRI_TEST"), Ok("the answer".to_owned())); + // Test that miri environment is isolated when communication is disabled. + assert!(env::var("MIRI_ENV_VAR_TEST").is_err()); } From 46f902b67dfeaeab45424dd7e24771676ef30b58 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 14 Aug 2019 10:24:35 -0500 Subject: [PATCH 1045/5092] Rename export for shims::env::EnvVars --- src/eval.rs | 8 ++++---- src/lib.rs | 2 +- src/machine.rs | 4 ++-- src/shims/env.rs | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 936ae5b89532..496bcf990adc 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -12,7 +12,7 @@ use crate::{ InterpResult, InterpError, InterpCx, StackPopCleanup, struct_error, Scalar, Tag, Pointer, FnVal, MemoryExtra, MiriMemoryKind, Evaluator, TlsEvalContextExt, HelpersEvalContextExt, - ShimsEnvVars, + EnvVars, }; /// Configuration needed to spawn a Miri instance. @@ -39,9 +39,9 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( Evaluator::new(config.communicate), MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate), ); - - ShimsEnvVars::init(config.communicate, &mut ecx, &tcx); - + // Complete initialization. + EnvVars::init(&mut ecx, &tcx, config.communicate); + // Setup first stack-frame let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; diff --git a/src/lib.rs b/src/lib.rs index 216e41d4f838..738419c2498b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,7 +33,7 @@ pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextEx pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::dlsym::{Dlsym, EvalContextExt as DlsymEvalContextExt}; -pub use crate::shims::env::{EnvVars as ShimsEnvVars}; +pub use crate::shims::env::EnvVars; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; diff --git a/src/machine.rs b/src/machine.rs index 635b46bcdb04..b4aac147f94f 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -78,7 +78,7 @@ impl MemoryExtra { pub struct Evaluator<'tcx> { /// Environment variables set by `setenv`. /// Miri does not expose env vars from the host to the emulated program. - pub(crate) env_vars: ShimsEnvVars, + pub(crate) env_vars: EnvVars, /// Program arguments (`Option` because we can only initialize them after creating the ecx). /// These are *pointers* to argc/argv because macOS. @@ -102,7 +102,7 @@ impl<'tcx> Evaluator<'tcx> { Evaluator { // `env_vars` could be initialized properly here if `Memory` were available before // calling this method. - env_vars: ShimsEnvVars::default(), + env_vars: EnvVars::default(), argc: None, argv: None, cmd_line: None, diff --git a/src/shims/env.rs b/src/shims/env.rs index 4a15eb4cfb48..d283cde8e3e9 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -12,9 +12,9 @@ pub struct EnvVars { impl EnvVars { pub(crate) fn init<'mir, 'tcx>( - communicate: bool, ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, tcx: &TyCtxt<'tcx>, + communicate: bool, ) { if communicate { for (name, value) in std::env::vars() { From 451a09a6857f7e7dabc918f09c78932b3de2e8f4 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 14 Aug 2019 11:22:47 -0500 Subject: [PATCH 1046/5092] Remove tcx parameter for EnvVars::alloc_env_value --- src/eval.rs | 4 +++- src/shims/env.rs | 13 ++++++------- src/shims/foreign_items.rs | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 496bcf990adc..0970edb2b75f 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -39,8 +39,10 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( Evaluator::new(config.communicate), MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate), ); + // Complete initialization. - EnvVars::init(&mut ecx, &tcx, config.communicate); + EnvVars::init(&mut ecx, config.communicate); + // Setup first stack-frame let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; diff --git a/src/shims/env.rs b/src/shims/env.rs index d283cde8e3e9..05c5fbb04309 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use rustc::ty::{layout::{Size, Align}, TyCtxt}; +use rustc::ty::layout::{Size, Align}; use rustc_mir::interpret::{Pointer, Memory}; use crate::stacked_borrows::Tag; use crate::*; @@ -13,12 +13,11 @@ pub struct EnvVars { impl EnvVars { pub(crate) fn init<'mir, 'tcx>( ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, - tcx: &TyCtxt<'tcx>, communicate: bool, ) { if communicate { for (name, value) in std::env::vars() { - let value = alloc_env_value(value.as_bytes(), ecx.memory_mut(), tcx); + let value = alloc_env_value(value.as_bytes(), ecx.memory_mut()); ecx.machine.env_vars.map.insert(name.into_bytes(), value); } } @@ -40,8 +39,8 @@ impl EnvVars { pub(crate) fn alloc_env_value<'mir, 'tcx>( bytes: &[u8], memory: &mut Memory<'mir, 'tcx, Evaluator<'tcx>>, - tcx: &TyCtxt<'tcx>, ) -> Pointer { + let tcx = {memory.tcx.tcx}; let length = bytes.len() as u64; // `+1` for the null terminator. let ptr = memory.allocate( @@ -51,11 +50,11 @@ pub(crate) fn alloc_env_value<'mir, 'tcx>( ); // We just allocated these, so the write cannot fail. let alloc = memory.get_mut(ptr.alloc_id).unwrap(); - alloc.write_bytes(tcx, ptr, &bytes).unwrap(); + alloc.write_bytes(&tcx, ptr, &bytes).unwrap(); let trailing_zero_ptr = ptr.offset( Size::from_bytes(length), - tcx, + &tcx, ).unwrap(); - alloc.write_bytes(tcx, trailing_zero_ptr, &[0]).unwrap(); + alloc.write_bytes(&tcx, trailing_zero_ptr, &[0]).unwrap(); ptr } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 6705183da47f..088077d5dfa2 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -466,7 +466,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } if let Some((name, value)) = new { - let value_copy = alloc_env_value(&value, this.memory_mut(), tcx); + let value_copy = alloc_env_value(&value, this.memory_mut()); if let Some(var) = this.machine.env_vars.set(name.to_owned(), value_copy) { this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; } From 41f8cfa30edc92c3c42a08059d0737d5ee4b87ac Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 14 Aug 2019 15:44:37 -0500 Subject: [PATCH 1047/5092] Move env shims to its own module --- src/eval.rs | 1 - src/lib.rs | 2 +- src/shims/env.rs | 92 ++++++++++++++++++++++++++++++++------ src/shims/foreign_items.rs | 60 ++----------------------- 4 files changed, 83 insertions(+), 72 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 0970edb2b75f..ae57bcf98b96 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -39,7 +39,6 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( Evaluator::new(config.communicate), MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate), ); - // Complete initialization. EnvVars::init(&mut ecx, config.communicate); diff --git a/src/lib.rs b/src/lib.rs index 738419c2498b..cea99d86eaa8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,7 +33,7 @@ pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextEx pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::dlsym::{Dlsym, EvalContextExt as DlsymEvalContextExt}; -pub use crate::shims::env::EnvVars; +pub use crate::shims::env::{EnvVars, EvalContextExt as EnvEvalContextExt}; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; diff --git a/src/shims/env.rs b/src/shims/env.rs index 05c5fbb04309..8362a02c7e80 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -22,21 +22,9 @@ impl EnvVars { } } } - - pub(crate) fn get(&self, name: &[u8]) -> Option<&Pointer> { - self.map.get(name) - } - - pub(crate) fn unset(&mut self, name: &[u8]) -> Option> { - self.map.remove(name) - } - - pub(crate) fn set(&mut self, name: Vec, ptr: Pointer) -> Option>{ - self.map.insert(name, ptr) - } } -pub(crate) fn alloc_env_value<'mir, 'tcx>( +fn alloc_env_value<'mir, 'tcx>( bytes: &[u8], memory: &mut Memory<'mir, 'tcx, Evaluator<'tcx>>, ) -> Pointer { @@ -58,3 +46,81 @@ pub(crate) fn alloc_env_value<'mir, 'tcx>( alloc.write_bytes(&tcx, trailing_zero_ptr, &[0]).unwrap(); ptr } + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn getenv( + &mut self, + name_op: OpTy<'tcx, Tag>, + dest: PlaceTy<'tcx, Tag> + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let result = { + let name_ptr = this.read_scalar(name_op)?.not_undef()?; + let name = this.memory().read_c_str(name_ptr)?; + match this.machine.env_vars.map.get(name) { + Some(&var) => Scalar::Ptr(var), + None => Scalar::ptr_null(&*this.tcx), + } + }; + this.write_scalar(result, dest)?; + Ok(()) + } + + fn setenv( + &mut self, + name_op: OpTy<'tcx, Tag>, + value_op: OpTy<'tcx, Tag>, + dest: PlaceTy<'tcx, Tag> + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let mut new = None; + let name_ptr = this.read_scalar(name_op)?.not_undef()?; + let value_ptr = this.read_scalar(value_op)?.not_undef()?; + let value = this.memory().read_c_str(value_ptr)?; + if !this.is_null(name_ptr)? { + let name = this.memory().read_c_str(name_ptr)?; + if !name.is_empty() && !name.contains(&b'=') { + new = Some((name.to_owned(), value.to_owned())); + } + } + if let Some((name, value)) = new { + let value_copy = alloc_env_value(&value, this.memory_mut()); + if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), value_copy) { + this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; + } + this.write_null(dest)?; + } else { + this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; + } + Ok(()) + } + + fn unsetenv( + &mut self, + name_op: OpTy<'tcx, Tag>, + dest: PlaceTy<'tcx, Tag> + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let mut success = None; + let name_ptr = this.read_scalar(name_op)?.not_undef()?; + if !this.is_null(name_ptr)? { + let name = this.memory().read_c_str(name_ptr)?.to_owned(); + if !name.is_empty() && !name.contains(&b'=') { + success = Some(this.machine.env_vars.map.remove(&name)); + } + } + if let Some(old) = success { + if let Some(var) = old { + this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; + } + this.write_null(dest)?; + } else { + this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; + } + Ok(()) + } +} diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 2d2b917eb275..34b54f329024 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -8,7 +8,6 @@ use syntax::attr; use syntax::symbol::sym; use crate::*; -use crate::shims::env::alloc_env_value; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -422,62 +421,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - "getenv" => { - let result = { - let name_ptr = this.read_scalar(args[0])?.not_undef()?; - let name = this.memory().read_c_str(name_ptr)?; - match this.machine.env_vars.get(name) { - Some(&var) => Scalar::Ptr(var), - None => Scalar::ptr_null(&*this.tcx), - } - }; - this.write_scalar(result, dest)?; - } - - "unsetenv" => { - let mut success = None; - { - let name_ptr = this.read_scalar(args[0])?.not_undef()?; - if !this.is_null(name_ptr)? { - let name = this.memory().read_c_str(name_ptr)?.to_owned(); - if !name.is_empty() && !name.contains(&b'=') { - success = Some(this.machine.env_vars.unset(&name)); - } - } - } - if let Some(old) = success { - if let Some(var) = old { - this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; - } - this.write_null(dest)?; - } else { - this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; - } - } - - "setenv" => { - let mut new = None; - { - let name_ptr = this.read_scalar(args[0])?.not_undef()?; - let value_ptr = this.read_scalar(args[1])?.not_undef()?; - let value = this.memory().read_c_str(value_ptr)?; - if !this.is_null(name_ptr)? { - let name = this.memory().read_c_str(name_ptr)?; - if !name.is_empty() && !name.contains(&b'=') { - new = Some((name.to_owned(), value.to_owned())); - } - } - } - if let Some((name, value)) = new { - let value_copy = alloc_env_value(&value, this.memory_mut()); - if let Some(var) = this.machine.env_vars.set(name.to_owned(), value_copy) { - this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; - } - this.write_null(dest)?; - } else { - this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; - } - } + "getenv" => this.getenv(args[0], dest)?, + "unsetenv" => this.unsetenv(args[0], dest)?, + "setenv" => this.setenv(args[0], args[1], dest)?, "write" => { let fd = this.read_scalar(args[0])?.to_i32()?; From aee8f173ec46d4b98cc562c6e7cad54bef764298 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 14 Aug 2019 16:48:36 -0500 Subject: [PATCH 1048/5092] Delegate writing to emulate_foreign_item --- src/shims/env.rs | 39 +++++++++++++++----------------------- src/shims/foreign_items.rs | 17 ++++++++++++++--- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 8362a02c7e80..c941bf4f50e3 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -52,34 +52,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn getenv( &mut self, name_op: OpTy<'tcx, Tag>, - dest: PlaceTy<'tcx, Tag> - ) -> InterpResult<'tcx> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let result = { - let name_ptr = this.read_scalar(name_op)?.not_undef()?; - let name = this.memory().read_c_str(name_ptr)?; - match this.machine.env_vars.map.get(name) { - Some(&var) => Scalar::Ptr(var), - None => Scalar::ptr_null(&*this.tcx), - } - }; - this.write_scalar(result, dest)?; - Ok(()) + let name_ptr = this.read_scalar(name_op)?.not_undef()?; + let name = this.memory().read_c_str(name_ptr)?; + Ok(match this.machine.env_vars.map.get(name) { + Some(&var) => Scalar::Ptr(var), + None => Scalar::ptr_null(&*this.tcx), + }) } fn setenv( &mut self, name_op: OpTy<'tcx, Tag>, value_op: OpTy<'tcx, Tag>, - dest: PlaceTy<'tcx, Tag> - ) -> InterpResult<'tcx> { + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let mut new = None; let name_ptr = this.read_scalar(name_op)?.not_undef()?; let value_ptr = this.read_scalar(value_op)?.not_undef()?; let value = this.memory().read_c_str(value_ptr)?; + let mut new = None; if !this.is_null(name_ptr)? { let name = this.memory().read_c_str(name_ptr)?; if !name.is_empty() && !name.contains(&b'=') { @@ -91,22 +85,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), value_copy) { this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; } - this.write_null(dest)?; + Ok(0) } else { - this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; + Ok(-1) } - Ok(()) } fn unsetenv( &mut self, name_op: OpTy<'tcx, Tag>, - dest: PlaceTy<'tcx, Tag> - ) -> InterpResult<'tcx> { + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let mut success = None; let name_ptr = this.read_scalar(name_op)?.not_undef()?; + let mut success = None; if !this.is_null(name_ptr)? { let name = this.memory().read_c_str(name_ptr)?.to_owned(); if !name.is_empty() && !name.contains(&b'=') { @@ -117,10 +109,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(var) = old { this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; } - this.write_null(dest)?; + Ok(0) } else { - this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; + Ok(-1) } - Ok(()) } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 34b54f329024..59e7673dcab5 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -421,9 +421,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - "getenv" => this.getenv(args[0], dest)?, - "unsetenv" => this.unsetenv(args[0], dest)?, - "setenv" => this.setenv(args[0], args[1], dest)?, + "getenv" => { + let result = this.getenv(args[0])?; + this.write_scalar(result, dest)?; + } + + "unsetenv" => { + let result = this.unsetenv(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "setenv" => { + let result = this.setenv(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } "write" => { let fd = this.read_scalar(args[0])?.to_i32()?; From 60a0688185b1412147a5b5f235597bc7618b104a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Jul 2019 11:03:12 +0200 Subject: [PATCH 1049/5092] adjust tests for eager pointer checks on deref --- tests/compile-fail/deref-invalid-ptr.rs | 7 +++++++ tests/compile-fail/deref-partially-dangling.rs | 8 ++++++++ tests/compile-fail/intptrcast_alignment_check.rs | 12 +++--------- tests/compile-fail/storage_dead_dangling.rs | 4 ++-- tests/run-pass/ref-invalid-ptr.rs | 12 ------------ tests/run-pass/stacked-borrows/stacked-borrows.rs | 11 ----------- 6 files changed, 20 insertions(+), 34 deletions(-) create mode 100644 tests/compile-fail/deref-invalid-ptr.rs create mode 100644 tests/compile-fail/deref-partially-dangling.rs delete mode 100644 tests/run-pass/ref-invalid-ptr.rs diff --git a/tests/compile-fail/deref-invalid-ptr.rs b/tests/compile-fail/deref-invalid-ptr.rs new file mode 100644 index 000000000000..2a8be87e1251 --- /dev/null +++ b/tests/compile-fail/deref-invalid-ptr.rs @@ -0,0 +1,7 @@ +// This should fail even without validation. +// compile-flags: -Zmiri-disable-validation + +fn main() { + let x = 2usize as *const u32; + let _y = unsafe { &*x as *const u32 }; //~ ERROR dangling pointer was dereferenced +} diff --git a/tests/compile-fail/deref-partially-dangling.rs b/tests/compile-fail/deref-partially-dangling.rs new file mode 100644 index 000000000000..221e585c5ff3 --- /dev/null +++ b/tests/compile-fail/deref-partially-dangling.rs @@ -0,0 +1,8 @@ +// Deref a raw ptr to access a field of a large struct, where the field +// is allocated but not the entire struct is. +fn main() { + let x = (1, 13); + let xptr = &x as *const _ as *const (i32, i32, i32); + let val = unsafe { (*xptr).1 }; //~ ERROR pointer must be in-bounds at offset 12, but is outside bounds of allocation + assert_eq!(val, 13); +} diff --git a/tests/compile-fail/intptrcast_alignment_check.rs b/tests/compile-fail/intptrcast_alignment_check.rs index 4e12a8a9e25e..fcf613ace462 100644 --- a/tests/compile-fail/intptrcast_alignment_check.rs +++ b/tests/compile-fail/intptrcast_alignment_check.rs @@ -1,6 +1,3 @@ -// Validation makes this fail in the wrong place -// compile-flags: -Zmiri-disable-validation - // Even with intptrcast and without validation, we want to be *sure* to catch bugs // that arise from pointers being insufficiently aligned. The only way to achieve // that is not not let programs exploit integer information for alignment, so here @@ -8,11 +5,8 @@ fn main() { let x = &mut [0u8; 3]; let base_addr = x as *mut _ as usize; - let u16_ref = unsafe { if base_addr % 2 == 0 { - &mut *(base_addr as *mut u16) - } else { - &mut *((base_addr+1) as *mut u16) - } }; - *u16_ref = 2; //~ ERROR tried to access memory with alignment 1, but alignment 2 is required + let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr+1 }; + let u16_ptr = base_addr_aligned as *mut u16; + unsafe { *u16_ptr = 2; } //~ ERROR tried to access memory with alignment 1, but alignment 2 is required println!("{:?}", x); } diff --git a/tests/compile-fail/storage_dead_dangling.rs b/tests/compile-fail/storage_dead_dangling.rs index 85c76f6f41f6..5a5d79f1582e 100644 --- a/tests/compile-fail/storage_dead_dangling.rs +++ b/tests/compile-fail/storage_dead_dangling.rs @@ -8,8 +8,8 @@ fn fill(v: &mut i32) { } fn evil() { - let v = unsafe { &mut *(LEAK as *mut i32) }; - let _x = *v; //~ ERROR dangling pointer was dereferenced + let v = unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR dangling pointer was dereferenced + let _x = *v; } fn main() { diff --git a/tests/run-pass/ref-invalid-ptr.rs b/tests/run-pass/ref-invalid-ptr.rs deleted file mode 100644 index e0e7d2afefc5..000000000000 --- a/tests/run-pass/ref-invalid-ptr.rs +++ /dev/null @@ -1,12 +0,0 @@ -// FIXME: validation disabled because it checks these references too eagerly. -// compile-flags: -Zmiri-disable-validation - -fn main() { - let x = 2usize as *const u32; - // This is not aligned, but we immediately cast it to a raw ptr so that must be ok. - let _y = unsafe { &*x as *const u32 }; - - let x = 0usize as *const u32; - // This is NULL, but we immediately cast it to a raw ptr so that must be ok. - let _y = unsafe { &*x as *const u32 }; -} diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index 7d84e33b3d6b..afa364e85643 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -1,6 +1,5 @@ // Test various stacked-borrows-related things. fn main() { - deref_partially_dangling_raw(); read_does_not_invalidate1(); read_does_not_invalidate2(); ref_raw_int_raw(); @@ -14,16 +13,6 @@ fn main() { shr_and_raw(); } -// Deref a raw ptr to access a field of a large struct, where the field -// is allocated but not the entire struct is. -// For now, we want to allow this. -fn deref_partially_dangling_raw() { - let x = (1, 13); - let xptr = &x as *const _ as *const (i32, i32, i32); - let val = unsafe { (*xptr).1 }; - assert_eq!(val, 13); -} - // Make sure that reading from an `&mut` does, like reborrowing to `&`, // NOT invalidate other reborrows. fn read_does_not_invalidate1() { From a801b0ba3f8f16aa9ded9d28af4279b4b0b4509b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 28 Jul 2019 14:55:55 +0200 Subject: [PATCH 1050/5092] adjust for fn rename --- src/operator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/operator.rs b/src/operator.rs index f047f4f4fad0..acf1db2977b7 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -35,7 +35,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { #[inline] fn pointer_inbounds(&self, ptr: Pointer) -> InterpResult<'tcx> { let (size, _align) = self.memory().get_size_and_align(ptr.alloc_id, AllocCheck::Live)?; - ptr.check_in_alloc(size, CheckInAllocMsg::InboundsTest) + ptr.check_inbounds_alloc(size, CheckInAllocMsg::InboundsTest) } fn binary_ptr_op( From 2f95d4d50cbf28de90d01a01e36197872f3a55f6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 28 Jul 2019 18:08:39 +0200 Subject: [PATCH 1051/5092] remove dead code --- tests/compile-fail/storage_dead_dangling.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/compile-fail/storage_dead_dangling.rs b/tests/compile-fail/storage_dead_dangling.rs index 5a5d79f1582e..3047f086bdf3 100644 --- a/tests/compile-fail/storage_dead_dangling.rs +++ b/tests/compile-fail/storage_dead_dangling.rs @@ -8,8 +8,7 @@ fn fill(v: &mut i32) { } fn evil() { - let v = unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR dangling pointer was dereferenced - let _x = *v; + unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR dangling pointer was dereferenced } fn main() { From 8a103cfdd99b258560c1c3c88c1e49108fb87c7d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 15 Aug 2019 11:06:27 +0200 Subject: [PATCH 1052/5092] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 6a1f1c81bdfa..f7f2a4e20f25 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -00ee1b47f42129a0a6e33510578fbcf07c1e5382 +1cdcea920e56a5d0587307a4c9cf8fff5c77c4bc From 6ef7c0886c0e8113b038306878dbbb43a3b49535 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 15 Aug 2019 11:14:45 +0200 Subject: [PATCH 1053/5092] deny warnings on CI --- miri | 2 +- travis.sh | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/miri b/miri index 1f46f04c13e8..6de2391137ac 100755 --- a/miri +++ b/miri @@ -45,7 +45,7 @@ fi # We set the rpath so that Miri finds the private rustc libraries it needs. # We enable debug-assertions to get tracing. # We enable line-only debuginfo for backtraces. -export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR -C debug-assertions -C debuginfo=1" +export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR -C debug-assertions -C debuginfo=1 $RUSTC_EXTRA_FLAGS" ## Helper functions diff --git a/travis.sh b/travis.sh index c06dbaee3638..6f14be44ef0a 100755 --- a/travis.sh +++ b/travis.sh @@ -8,6 +8,7 @@ else FOREIGN_TARGET=i686-unknown-linux-gnu fi export CARGO_EXTRA_FLAGS="--all-features" +export RUSTC_EXTRA_FLAGS="-D warnings" # Prepare echo "Build and install miri" From f9241be73493f9f1e26631a5389b599557ef4f2f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 15 Aug 2019 11:24:04 +0200 Subject: [PATCH 1054/5092] fix warning --- src/eval.rs | 2 +- src/shims/env.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index ae57bcf98b96..39da414de14a 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -40,7 +40,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate), ); // Complete initialization. - EnvVars::init(&mut ecx, config.communicate); + EnvVars::init(&mut ecx); // Setup first stack-frame let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); diff --git a/src/shims/env.rs b/src/shims/env.rs index c941bf4f50e3..eb5722a5a3d8 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -13,9 +13,8 @@ pub struct EnvVars { impl EnvVars { pub(crate) fn init<'mir, 'tcx>( ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, - communicate: bool, ) { - if communicate { + if ecx.machine.communicate { for (name, value) in std::env::vars() { let value = alloc_env_value(value.as_bytes(), ecx.memory_mut()); ecx.machine.env_vars.map.insert(name.into_bytes(), value); From 5aa60571fcbb6d44ca32c3d4b5ca3cd2f69787ac Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 26 Jul 2019 10:21:31 +0200 Subject: [PATCH 1055/5092] travis: do not install cargo from master --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7db62bc74bd4..26645c307951 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,7 +35,7 @@ before_script: - export PATH=$HOME/.cargo/bin:$PATH # Install "master" toolchain - cargo install rustup-toolchain-install-master || echo "rustup-toolchain-install-master already installed" -- travis_retry rustup-toolchain-install-master -f -n master $RUSTC_HASH -c cargo -c rust-src +- travis_retry rustup-toolchain-install-master -f -n master $RUSTC_HASH -c rust-src - rustup default master - rustc --version From 65541d9021904feb21a11f0a5b3fb3f7c9320a82 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 15 Aug 2019 22:30:38 +0200 Subject: [PATCH 1056/5092] rustup update --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 26645c307951..269dc28ca021 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,6 +33,7 @@ before_script: # Install Rust ("stable" toolchain for better caching, it is just used to build rustup-toolchain-install-master) - curl https://build.travis-ci.org/files/rustup-init.sh -sSf | sh -s -- -y --default-toolchain stable - export PATH=$HOME/.cargo/bin:$PATH +- rustup update # Install "master" toolchain - cargo install rustup-toolchain-install-master || echo "rustup-toolchain-install-master already installed" - travis_retry rustup-toolchain-install-master -f -n master $RUSTC_HASH -c rust-src From 4f1c9bb607637cd8d6926e1b7875fb048e8a9139 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 Aug 2019 21:19:25 +0200 Subject: [PATCH 1057/5092] adjust for typed binary/unary_op --- src/machine.rs | 4 ++-- src/operator.rs | 10 +++++----- src/shims/intrinsics.rs | 14 +++++++------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index b4aac147f94f..9d50c77c7c4c 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -10,7 +10,7 @@ use rand::rngs::StdRng; use syntax::attr; use syntax::symbol::sym; use rustc::hir::def_id::DefId; -use rustc::ty::{self, layout::{Size, LayoutOf}, TyCtxt}; +use rustc::ty::{self, Ty, TyCtxt, layout::{Size, LayoutOf}}; use rustc::mir; use crate::*; @@ -191,7 +191,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { bin_op: mir::BinOp, left: ImmTy<'tcx, Tag>, right: ImmTy<'tcx, Tag>, - ) -> InterpResult<'tcx, (Scalar, bool)> { + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { ecx.binary_ptr_op(bin_op, left, right) } diff --git a/src/operator.rs b/src/operator.rs index acf1db2977b7..45bf1e453744 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -14,7 +14,7 @@ pub trait EvalContextExt<'tcx> { bin_op: mir::BinOp, left: ImmTy<'tcx, Tag>, right: ImmTy<'tcx, Tag>, - ) -> InterpResult<'tcx, (Scalar, bool)>; + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)>; fn ptr_eq( &self, @@ -43,7 +43,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { bin_op: mir::BinOp, left: ImmTy<'tcx, Tag>, right: ImmTy<'tcx, Tag>, - ) -> InterpResult<'tcx, (Scalar, bool)> { + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { use rustc::mir::BinOp::*; trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); @@ -59,7 +59,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { self.ptr_eq(left2.not_undef()?, right2.not_undef()?)?, _ => bug!("Type system should not allow comparing Scalar with ScalarPair"), }; - (Scalar::from_bool(if bin_op == Eq { eq } else { !eq }), false) + (Scalar::from_bool(if bin_op == Eq { eq } else { !eq }), false, self.tcx.types.bool) } Lt | Le | Gt | Ge => { @@ -74,7 +74,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { Ge => left >= right, _ => bug!("We already established it has to be one of these operators."), }; - (Scalar::from_bool(res), false) + (Scalar::from_bool(res), false, self.tcx.types.bool) } Offset => { @@ -87,7 +87,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { pointee_ty, right.to_scalar()?.to_isize(self)?, )?; - (ptr, false) + (ptr, false, left.layout.ty) } _ => bug!("Invalid operator on pointers: {:?}", bin_op) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 4e957f792b75..865696276171 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -5,7 +5,7 @@ use rustc::ty::layout::{self, LayoutOf, Size, Align}; use rustc::ty; use crate::{ - PlaceTy, OpTy, ImmTy, Immediate, Scalar, Tag, + PlaceTy, OpTy, Immediate, Scalar, Tag, OperatorEvalContextExt }; @@ -120,7 +120,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.memory().check_ptr_access(place.ptr, place.layout.size, align)?; // binary_op will bail if either of them is not a scalar - let (eq, _) = this.binary_op(mir::BinOp::Eq, old, expect_old)?; + let eq = this.overflowing_binary_op(mir::BinOp::Eq, old, expect_old)?.0; let res = Immediate::ScalarPair(old.to_scalar_or_undef(), eq.into()); this.write_immediate(res, dest)?; // old value is returned // update ptr depending on comparison @@ -183,13 +183,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => bug!(), }; // Atomics wrap around on overflow. - let (val, _overflowed) = this.binary_op(op, old, rhs)?; + let val = this.binary_op(op, old, rhs)?; let val = if neg { - this.unary_op(mir::UnOp::Not, ImmTy::from_scalar(val, old.layout))? + this.unary_op(mir::UnOp::Not, val)? } else { val }; - this.write_scalar(val, place.into())?; + this.write_immediate(*val, place.into())?; } "breakpoint" => unimplemented!(), // halt miri @@ -312,7 +312,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let a = this.read_immediate(args[0])?; let b = this.read_immediate(args[1])?; // check x % y != 0 - if this.binary_op(mir::BinOp::Rem, a, b)?.0.to_bits(dest.layout.size)? != 0 { + if this.overflowing_binary_op(mir::BinOp::Rem, a, b)?.0.to_bits(dest.layout.size)? != 0 { // Check if `b` is -1, which is the "min_value / -1" case. let minus1 = Scalar::from_int(-1, dest.layout.size); return Err(if b.to_scalar().unwrap() == minus1 { @@ -515,7 +515,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "unchecked_mul" => mir::BinOp::Mul, _ => bug!(), }; - let (res, overflowed) = this.binary_op(op, l, r)?; + let (res, overflowed, _ty) = this.overflowing_binary_op(op, l, r)?; if overflowed { throw_ub_format!("Overflowing arithmetic in {}", intrinsic_name.get()); } From d7ff7ccbad89c4fe9eb84b3b22f4b994f7f169a0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 Aug 2019 07:43:18 +0200 Subject: [PATCH 1058/5092] update Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index f7f2a4e20f25..f90b8945180f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1cdcea920e56a5d0587307a4c9cf8fff5c77c4bc +2111aed0a38c819acb140c7153e9366964a37f2f From 94cd0ce734db8f760b5a8de877684f917d0a9d90 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 Aug 2019 11:16:02 +0200 Subject: [PATCH 1059/5092] fix test failure due to my own lint --- rust-version | 2 +- tests/compile-fail/never_transmute_void.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index f90b8945180f..07d9d2955478 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -2111aed0a38c819acb140c7153e9366964a37f2f +ef1ecbefb8719e408150738664d443a73f757ffd diff --git a/tests/compile-fail/never_transmute_void.rs b/tests/compile-fail/never_transmute_void.rs index 5993cfad8699..a5d6795d71e7 100644 --- a/tests/compile-fail/never_transmute_void.rs +++ b/tests/compile-fail/never_transmute_void.rs @@ -2,7 +2,7 @@ // compile-flags: -Zmiri-disable-validation #![feature(never_type)] -#![allow(unused)] +#![allow(unused, invalid_value)] enum Void {} From be4108e27cf4ff452d3b667097c9e7c893063892 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 Aug 2019 11:31:18 +0200 Subject: [PATCH 1060/5092] test some new uninit APIs --- tests/run-pass/rc.rs | 31 +++++++++++++++++++++++++++++++ tests/run-pass/slices.rs | 18 ++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index d731fe8fd4c3..9ab460c96165 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -1,4 +1,6 @@ #![feature(weak_into_raw)] +#![feature(new_uninit)] +#![feature(get_mut_unchecked)] use std::cell::{Cell, RefCell}; use std::rc::{Rc, Weak}; @@ -102,6 +104,33 @@ fn weak_from_raw() { assert!(Weak::upgrade(&unsafe { Weak::from_raw(raw_2) }).is_none()); } +fn rc_uninit() { + let mut five = Rc::>::new_uninit(); + let five = unsafe { + // Deferred initialization: + Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(Box::new(5)); + five.assume_init() + }; + assert_eq!(**five, 5) +} + +fn rc_uninit_slice() { + let mut values = Rc::<[Box]>::new_uninit_slice(3); + + let values = unsafe { + // Deferred initialization: + Rc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(Box::new(0)); + Rc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(Box::new(1)); + Rc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(Box::new(2)); + + values.assume_init() + }; + + for (idx, i) in values.iter().enumerate() { + assert_eq!(idx, **i); + } +} + fn main() { rc_fat_ptr_eq(); rc_refcell(); @@ -111,6 +140,8 @@ fn main() { rc_from(); weak_into_raw(); weak_from_raw(); + rc_uninit(); + rc_uninit_slice(); arc(); } diff --git a/tests/run-pass/slices.rs b/tests/run-pass/slices.rs index 4506a72e8dd0..41e7b2d36c7c 100644 --- a/tests/run-pass/slices.rs +++ b/tests/run-pass/slices.rs @@ -1,3 +1,5 @@ +#![feature(new_uninit)] + use std::slice; fn slice_of_zst() { @@ -169,7 +171,23 @@ fn test_iter_ref_consistency() { test_mut([0u32; 0]); // ZST with alignment > 0 } +fn uninit_slice() { + let mut values = Box::<[Box]>::new_uninit_slice(3); + + let values = unsafe { + // Deferred initialization: + values[0].as_mut_ptr().write(Box::new(1)); + values[1].as_mut_ptr().write(Box::new(2)); + values[2].as_mut_ptr().write(Box::new(3)); + + values.assume_init() + }; + + assert_eq!(values.iter().map(|x| **x).collect::>(), vec![1, 2, 3]) +} + fn main() { slice_of_zst(); test_iter_ref_consistency(); + uninit_slice(); } From b44fd97af6999e032f71e9e7c265b43163cb4052 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 19 Aug 2019 10:43:09 -0500 Subject: [PATCH 1061/5092] Use host's rng when communication is enabled --- Cargo.toml | 1 + src/helpers.rs | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 644a3476a6dd..1ab0580cc631 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,7 @@ byteorder = { version = "1.1", features = ["i128"]} cargo_metadata = { version = "0.8", optional = true } directories = { version = "2.0", optional = true } rustc_version = { version = "0.2.3", optional = true } +getrandom = "0.1.10" env_logger = "0.6" log = "0.4" shell-escape = "0.1.4" diff --git a/src/helpers.rs b/src/helpers.rs index c0e1ec2cd75b..d134a19f4c23 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -97,9 +97,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Align::from_bytes(1).unwrap() )?.expect("we already checked for size 0"); - let rng = this.memory_mut().extra.rng.get_mut(); let mut data = vec![0; len]; - rng.fill_bytes(&mut data); + + if this.machine.communicate { + // Fill the buffer using the host's rng. + getrandom::getrandom(&mut data).map_err(|err| { + InterpError::Unsupported(UnsupportedOpInfo::Unsupported(err.to_string())) + })?; + } + else { + let rng = this.memory_mut().extra.rng.get_mut(); + rng.fill_bytes(&mut data); + } let tcx = &{this.tcx.tcx}; this.memory_mut().get_mut(ptr.alloc_id)?.write_bytes(tcx, ptr, &data) From a76bc3fb87b4bf470330ab2f41d0ffc6f75676e5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 13 Jul 2019 10:27:50 +0200 Subject: [PATCH 1062/5092] test arrray try_from (interesting const generic usage) --- tests/run-pass/arrays.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/run-pass/arrays.rs b/tests/run-pass/arrays.rs index d374ccf25354..b760d515395c 100644 --- a/tests/run-pass/arrays.rs +++ b/tests/run-pass/arrays.rs @@ -1,3 +1,5 @@ +use std::convert::TryFrom; + fn empty_array() -> [u16; 0] { [] } @@ -33,6 +35,16 @@ fn slice_index() -> u8 { arr[5] } +fn try_from() { + const N: usize = 16; + type Array = [u8; N]; + let array: Array = [0; N]; + let slice: &[u8] = &array[..]; + + let result = <&Array>::try_from(slice); + assert_eq!(&array, result.unwrap()); +} + fn eq() { const N: usize = 16; type Array = [u8; N]; @@ -57,6 +69,7 @@ fn main() { assert_eq!(array_array(), [[5, 4], [3, 2], [1, 0]]); assert_eq!(array_repeat(), [42; 8]); assert_eq!(mini_array(), [42]); + try_from(); eq(); debug(); } From 3b14567e36d4353bfa715d11387eb2e1cd1f2ae9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 Aug 2019 16:11:11 +0200 Subject: [PATCH 1063/5092] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 07d9d2955478..853bf9bd52ee 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -ef1ecbefb8719e408150738664d443a73f757ffd +14890954ce17c44d944eda988c5a64bb4c5ec9eb From 98129631b5a71c9a43724903499b11170b518e7a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 20 Aug 2019 10:47:38 -0500 Subject: [PATCH 1064/5092] Use err_unsup_format instead --- src/helpers.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index d134a19f4c23..330d6bc996b7 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -101,9 +101,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.machine.communicate { // Fill the buffer using the host's rng. - getrandom::getrandom(&mut data).map_err(|err| { - InterpError::Unsupported(UnsupportedOpInfo::Unsupported(err.to_string())) - })?; + getrandom::getrandom(&mut data) + .map_err(|err| err_unsup_format!("getrandom failed: {}", err))?; } else { let rng = this.memory_mut().extra.rng.get_mut(); From f53b5b0fb4cc9a716eb27929c3829f096e90b6eb Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 20 Aug 2019 10:47:57 -0500 Subject: [PATCH 1065/5092] Update -Zmiri-enable-communication docs --- README.md | 4 ++-- src/machine.rs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f34569d865a8..502c562d1357 100644 --- a/README.md +++ b/README.md @@ -158,8 +158,8 @@ Several `-Z` flags are relevant for Miri: will miss bugs in your program. However, this can also help to make Miri run faster. * `-Zmiri-enable-communication` enables communication between the host - environment and Miri, i.e., all the host environment variables are available - during Miri runtime. + environment and Miri, i.e., Miri uses the host's random number generator and + all the host environment variables are available during runtime. * `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri overrides the default to be `0`; be advised that using any higher level can make Miri miss bugs in your program because they got optimized away. diff --git a/src/machine.rs b/src/machine.rs index b4aac147f94f..b11ecfa44135 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -93,7 +93,8 @@ pub struct Evaluator<'tcx> { /// TLS state. pub(crate) tls: TlsData<'tcx>, - /// If enabled, the `env_vars` field is populated with the host env vars during initialization. + /// If enabled, the `env_vars` field is populated with the host env vars during initialization + /// and random number generation is delegated to the host. pub(crate) communicate: bool, } From 1be4e2ff589e14148dc71a0f4d71ff2923876415 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 Aug 2019 09:07:27 +0200 Subject: [PATCH 1066/5092] bump Rust --- rust-version | 2 +- tests/compiletest.rs | 10 ++++++---- tests/run-pass/async-fn.rs | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index 853bf9bd52ee..012763c00023 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -14890954ce17c44d944eda988c5a64bb4c5ec9eb +bea0372a1a7a31b81f28cc4d9a83a2dc9a79d008 diff --git a/tests/compiletest.rs b/tests/compiletest.rs index d0705b26b7a9..00fd039ad7e8 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -28,10 +28,12 @@ fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec) { let in_rustc_test_suite = rustc_test_suite().is_some(); // Add some flags we always want. flags.push("--edition 2018".to_owned()); - if !in_rustc_test_suite { - // Only `-Dwarnings` on the Miri side to make the rustc toolstate management less painful. - // (We often get warnings when e.g. a feature gets stabilized or some lint gets added/improved.) - flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs + if in_rustc_test_suite { + // Less aggressive warnings to make the rustc toolstate management less painful. + // (We often get warnings when e.g. a feature gets stabilized or some lint gets added/improved.) + flags.push("-Astable-features".to_owned()); + } else { + flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs } if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") { flags.push(format!("--sysroot {}", sysroot)); diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 91266f67aa8e..dd31d901062f 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -1,4 +1,4 @@ -#![feature(async_await, never_type)] +#![feature(never_type)] use std::{future::Future, pin::Pin, task::Poll, ptr}; use std::task::{Waker, RawWaker, RawWakerVTable, Context}; From 97f9fb1284c526f62286d3334b42481a2efe43a7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 23 Aug 2019 23:29:11 +0200 Subject: [PATCH 1067/5092] change flag name: enable-communication -> disable-isolation --- README.md | 6 +++--- src/bin/miri.rs | 2 +- tests/run-pass/communication.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 502c562d1357..d3e4adfa1785 100644 --- a/README.md +++ b/README.md @@ -157,9 +157,9 @@ Several `-Z` flags are relevant for Miri: is enforced by default. This is mostly useful for debugging; it means Miri will miss bugs in your program. However, this can also help to make Miri run faster. -* `-Zmiri-enable-communication` enables communication between the host - environment and Miri, i.e., Miri uses the host's random number generator and - all the host environment variables are available during runtime. +* `-Zmiri-disable-isolation` disables host host isolation. As a consequence, + the program has access to host resources such as environment variables and + randomness (and, eventually, file systems and more). * `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri overrides the default to be `0`; be advised that using any higher level can make Miri miss bugs in your program because they got optimized away. diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 1aa89fc5a610..55522a52e012 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -148,7 +148,7 @@ fn main() { "-Zmiri-disable-validation" => { validate = false; }, - "-Zmiri-enable-communication" => { + "-Zmiri-disable-isolation" => { communicate = true; }, "--" => { diff --git a/tests/run-pass/communication.rs b/tests/run-pass/communication.rs index e3fb0c5bd5e0..537e0923d20b 100644 --- a/tests/run-pass/communication.rs +++ b/tests/run-pass/communication.rs @@ -1,5 +1,5 @@ // ignore-windows: TODO env var emulation stubbed out on Windows -// compile-flags: -Zmiri-enable-communication +// compile-flags: -Zmiri-disable-isolation fn main() { assert_eq!(std::env::var("MIRI_ENV_VAR_TEST"), Ok("0".to_owned())); From 55efee91406f17beab46273210318b7259632345 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 23 Aug 2019 23:30:23 +0200 Subject: [PATCH 1068/5092] test host randomness access --- ...mmunication.rs => env-without-isolation.rs} | 0 .../linux-getrandom-without-isolation.rs | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+) rename tests/run-pass/{communication.rs => env-without-isolation.rs} (100%) create mode 100644 tests/run-pass/linux-getrandom-without-isolation.rs diff --git a/tests/run-pass/communication.rs b/tests/run-pass/env-without-isolation.rs similarity index 100% rename from tests/run-pass/communication.rs rename to tests/run-pass/env-without-isolation.rs diff --git a/tests/run-pass/linux-getrandom-without-isolation.rs b/tests/run-pass/linux-getrandom-without-isolation.rs new file mode 100644 index 000000000000..ce9ff8b6c3f9 --- /dev/null +++ b/tests/run-pass/linux-getrandom-without-isolation.rs @@ -0,0 +1,18 @@ +// Unfortunately, compiletest_rs does not support 'only-linux', +// so we need to ignore Windows and macOS instead. +// ignore-macos: Uses Linux-only APIs +// ignore-windows: Uses Linux-only APIs +// compile-flags: -Zmiri-disable-isolation +#![feature(rustc_private)] +extern crate libc; + +fn main() { + let mut buf = [0u8; 5]; + unsafe { + assert_eq!(libc::syscall(libc::SYS_getrandom, 0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), 0); + assert_eq!(libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, 0 as libc::c_uint), 5); + + assert_eq!(libc::getrandom(0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), 0); + assert_eq!(libc::getrandom(buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, 0 as libc::c_uint), 5); + } +} From 03408061270b5985d245b334fee6e5cac8c7121a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 26 Aug 2019 19:38:47 +0200 Subject: [PATCH 1069/5092] cargo update --- test-cargo-miri/Cargo.lock | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 3b4dbdcf1d2e..2a6a32a18f04 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -2,7 +2,7 @@ # It is not intended for manual editing. [[package]] name = "autocfg" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -15,7 +15,7 @@ name = "c2-chacha" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -35,21 +35,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "getrandom" -version = "0.1.8" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lazy_static" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.60" +version = "0.2.62" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -57,7 +58,7 @@ name = "num_cpus" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -70,8 +71,8 @@ name = "rand" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -92,7 +93,7 @@ name = "rand_core" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -108,18 +109,23 @@ name = "rand_pcg" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "wasi" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [metadata] -"checksum autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "22130e92352b948e7e82a49cdb0aa94f2211761117f29e052dd397c1ac33542b" +"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" -"checksum getrandom 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "34f33de6f0ae7c9cb5e574502a562e2b512799e32abb801cd1e79ad952b62b49" -"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" -"checksum libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "d44e80633f007889c7eff624b709ab43c92d708caad982295768a7b13ca3b5eb" +"checksum getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "fc344b02d3868feb131e8b5fe2b9b0a1cc42942679af493061fc13b853243872" +"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" "checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" "checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" @@ -127,3 +133,4 @@ dependencies = [ "checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum rand_pcg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e196346cbbc5c70c77e7b4926147ee8e383a38ee4d15d58a08098b169e492b6" +"checksum wasi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd5442abcac6525a045cc8c795aedb60da7a2e5e89c7bf18a0d5357849bb23c7" From c6c9276d6122e4302ee42389eaf29e51ef795a57 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 26 Aug 2019 19:44:27 +0200 Subject: [PATCH 1070/5092] bump Rust and xargo --- rust-version | 2 +- src/bin/cargo-miri.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 012763c00023..70f10366b993 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -bea0372a1a7a31b81f28cc4d9a83a2dc9a79d008 +521d78407471cb78e9bbf47160f6aa23047ac499 diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index b1dc306bcb1d..8749e5b7eed9 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -243,7 +243,7 @@ fn setup(ask_user: bool) { } // First, we need xargo. - if xargo_version().map_or(true, |v| v < (0, 3, 15)) { + if xargo_version().map_or(true, |v| v < (0, 3, 16)) { if ask_user { ask("It seems you do not have a recent enough xargo installed. I will run `cargo install xargo -f`. Proceed?"); } else { @@ -297,7 +297,6 @@ default_features = false features = ["panic_unwind"] [dependencies.test] -stage = 1 "#).unwrap(); // The boring bits: a dummy project for xargo. File::create(dir.join("Cargo.toml")).unwrap() From 63ec6e6467a504e9445b9c69450a80a4dc5e6a88 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 26 Aug 2019 20:53:33 +0200 Subject: [PATCH 1071/5092] decrease getrandom version so that we dont have to bump Cargo.toml in rustc --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 1ab0580cc631..6f45cc7a06db 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,7 @@ byteorder = { version = "1.1", features = ["i128"]} cargo_metadata = { version = "0.8", optional = true } directories = { version = "2.0", optional = true } rustc_version = { version = "0.2.3", optional = true } -getrandom = "0.1.10" +getrandom = "0.1.8" env_logger = "0.6" log = "0.4" shell-escape = "0.1.4" From ace3416cf25d4214e1ebdac55459abd8edee4999 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 26 Aug 2019 15:18:11 -0500 Subject: [PATCH 1072/5092] Write name and value for each env var --- src/shims/env.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index eb5722a5a3d8..988ee61a0e35 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -16,17 +16,19 @@ impl EnvVars { ) { if ecx.machine.communicate { for (name, value) in std::env::vars() { - let value = alloc_env_value(value.as_bytes(), ecx.memory_mut()); - ecx.machine.env_vars.map.insert(name.into_bytes(), value); + let var_ptr = alloc_env_var(name.as_bytes(), value.as_bytes(), ecx.memory_mut()); + ecx.machine.env_vars.map.insert(name.into_bytes(), var_ptr); } } } } -fn alloc_env_value<'mir, 'tcx>( - bytes: &[u8], +fn alloc_env_var<'mir, 'tcx>( + name: &[u8], + value: &[u8], memory: &mut Memory<'mir, 'tcx, Evaluator<'tcx>>, ) -> Pointer { + let bytes = [name, b"=", value].concat(); let tcx = {memory.tcx.tcx}; let length = bytes.len() as u64; // `+1` for the null terminator. @@ -57,7 +59,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_ptr = this.read_scalar(name_op)?.not_undef()?; let name = this.memory().read_c_str(name_ptr)?; Ok(match this.machine.env_vars.map.get(name) { - Some(&var) => Scalar::Ptr(var), + Some(var_ptr) => Scalar::Ptr(var_ptr.offset(Size::from_bytes(name.len() as u64 + 1), this)?), None => Scalar::ptr_null(&*this.tcx), }) } @@ -80,8 +82,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } if let Some((name, value)) = new { - let value_copy = alloc_env_value(&value, this.memory_mut()); - if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), value_copy) { + let var_ptr = alloc_env_var(&name, &value, this.memory_mut()); + if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), var_ptr) { this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; } Ok(0) From 3a68d943bab229271ad6d537e043d5bc3eed514d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Aug 2019 08:32:31 +0200 Subject: [PATCH 1073/5092] rustup --- rust-version | 2 +- src/eval.rs | 4 ++-- src/machine.rs | 2 +- src/shims/foreign_items.rs | 2 +- src/shims/mod.rs | 2 +- src/shims/tls.rs | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rust-version b/rust-version index 70f10366b993..8c746ad2fff8 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -521d78407471cb78e9bbf47160f6aa23047ac499 +0444b9f66acb5da23dc816e0d8eb59623ba9ea50 diff --git a/src/eval.rs b/src/eval.rs index 39da414de14a..bd4d8a0bef85 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -44,7 +44,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Setup first stack-frame let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); - let main_mir = ecx.load_mir(main_instance.def)?; + let main_mir = ecx.load_mir(main_instance.def, None)?; if !main_mir.return_ty().is_unit() || main_mir.arg_count != 0 { throw_unsup_format!( @@ -62,7 +62,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ecx.tcx.mk_substs( ::std::iter::once(ty::subst::Kind::from(main_ret_ty))) ).unwrap(); - let start_mir = ecx.load_mir(start_instance.def)?; + let start_mir = ecx.load_mir(start_instance.def, None)?; if start_mir.arg_count != 3 { bug!( diff --git a/src/machine.rs b/src/machine.rs index 8989062b513a..3853a45fd990 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -204,7 +204,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { // Call the `exchange_malloc` lang item. let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap(); let malloc = ty::Instance::mono(ecx.tcx.tcx, malloc); - let malloc_mir = ecx.load_mir(malloc.def)?; + let malloc_mir = ecx.load_mir(malloc.def, None)?; ecx.push_stack_frame( malloc, malloc_mir.span, diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 59e7673dcab5..0b2fa64996e7 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -341,7 +341,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Now we make a function call. // TODO: consider making this reusable? `InterpCx::step` does something similar // for the TLS destructors, and of course `eval_main`. - let mir = this.load_mir(f_instance.def)?; + let mir = this.load_mir(f_instance.def, None)?; let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); this.push_stack_frame( f_instance, diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 96a1f34152b3..5fbe6e379987 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -47,6 +47,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Otherwise, load the MIR. - Ok(Some(this.load_mir(instance.def)?)) + Ok(Some(this.load_mir(instance.def, None)?)) } } diff --git a/src/shims/tls.rs b/src/shims/tls.rs index e90ace948b7a..44bedbd44d2d 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -148,7 +148,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert!(!this.is_null(ptr).unwrap(), "Data can't be NULL when dtor is called!"); // TODO: Potentially, this has to support all the other possible instances? // See eval_fn_call in interpret/terminator/mod.rs - let mir = this.load_mir(instance.def)?; + let mir = this.load_mir(instance.def, None)?; let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); this.push_stack_frame( instance, From 26afb4685d460f1153313716406bfe40011c2bf3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Aug 2019 08:42:36 +0200 Subject: [PATCH 1074/5092] hashmap ICEs with optimizations, temporarily disable --- tests/compiletest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 00fd039ad7e8..aa2488b1a417 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -122,7 +122,7 @@ fn test_runner(_tests: &[&()]) { std::env::set_var("MIRI_ENV_VAR_TEST", "0"); run_pass_miri(false); - run_pass_miri(true); + // FIXME: hashmap ICEs with optimizations run_pass_miri(true); compile_fail_miri(false); compile_fail_miri(true); From 283829c5c1a13c7c1f01b4b0e0e697b967bb46f1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Aug 2019 15:12:12 +0200 Subject: [PATCH 1075/5092] explicitly enable getrandom/std feature --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6f45cc7a06db..d78ce46f0fd2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,11 +31,11 @@ doctest = false # and no doc tests required-features = ["rustc_tests"] [dependencies] -byteorder = { version = "1.1", features = ["i128"]} +byteorder = { version = "1.1", features = ["i128"] } cargo_metadata = { version = "0.8", optional = true } directories = { version = "2.0", optional = true } rustc_version = { version = "0.2.3", optional = true } -getrandom = "0.1.8" +getrandom = { version = "0.1.8", features = ["std"] } env_logger = "0.6" log = "0.4" shell-escape = "0.1.4" From 7d93cc7b5efeeec001aa8071b1bc61b8cc111c95 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 27 Aug 2019 08:45:37 -0500 Subject: [PATCH 1076/5092] Add docs --- src/shims/env.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/shims/env.rs b/src/shims/env.rs index 988ee61a0e35..8f946a2b5eb1 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -7,6 +7,8 @@ use crate::*; #[derive(Default)] pub struct EnvVars { + /// Stores pointers to the environment variables. These variables must be stored as + /// null-terminated C strings with the `"{name}={value}"` format. map: HashMap, Pointer>, } @@ -59,6 +61,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_ptr = this.read_scalar(name_op)?.not_undef()?; let name = this.memory().read_c_str(name_ptr)?; Ok(match this.machine.env_vars.map.get(name) { + // The offset is used to strip the "{name}=" part of the string. Some(var_ptr) => Scalar::Ptr(var_ptr.offset(Size::from_bytes(name.len() as u64 + 1), this)?), None => Scalar::ptr_null(&*this.tcx), }) From 71aae4ffa5a8ee36f09953d1b85c7b5c2818e0c6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Aug 2019 09:15:31 +0200 Subject: [PATCH 1077/5092] test that build scripts do not run in Miri --- test-cargo-miri/Cargo.toml | 1 + test-cargo-miri/build.rs | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 test-cargo-miri/build.rs diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 3abb437049f0..c2460014b663 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -3,6 +3,7 @@ name = "cargo-miri-test" version = "0.1.0" authors = ["Oliver Schneider "] edition = "2018" +build = "build.rs" [dependencies] byteorder = "1.0" diff --git a/test-cargo-miri/build.rs b/test-cargo-miri/build.rs new file mode 100644 index 000000000000..950fc3c82bb1 --- /dev/null +++ b/test-cargo-miri/build.rs @@ -0,0 +1,15 @@ +#![feature(asm)] + +fn not_in_miri() -> i32 { + // Inline assembly definitely does not work in Miri. + let dummy = 42; + unsafe { + asm!("" : : "r"(&dummy)); + } + return dummy; +} + +fn main() { + not_in_miri(); + println!("cargo:rerun-if-changed=build.rs"); +} From 7faa329f11d38da611e49c82c823a35758a713e5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Aug 2019 09:27:19 +0200 Subject: [PATCH 1078/5092] more implicit --- Cargo.toml | 1 - test-cargo-miri/Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d78ce46f0fd2..ecc8deedf325 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,6 @@ license = "MIT/Apache-2.0" name = "miri" repository = "https://github.com/rust-lang/miri" version = "0.1.0" -build = "build.rs" default-run = "miri" edition = "2018" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index c2460014b663..3abb437049f0 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -3,7 +3,6 @@ name = "cargo-miri-test" version = "0.1.0" authors = ["Oliver Schneider "] edition = "2018" -build = "build.rs" [dependencies] byteorder = "1.0" From 79dd70fd9bd2de5a0b2dd4697905571f39012dc7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Aug 2019 18:41:30 +0200 Subject: [PATCH 1079/5092] Stacked Borrows: don't read from memory during retagging --- src/helpers.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 330d6bc996b7..e5203becd5cf 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -222,8 +222,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This is `Freeze`, there cannot be an `UnsafeCell` Ok(()) } else { - // Proceed further - self.walk_value(v) + // We want to not actually read from memory for this visit. So, before + // walking this value, we have to make sure it is not a + // `Variants::Multiple`. + match v.layout.variants { + layout::Variants::Multiple { .. } => { + // A multi-variant enum, or generator, or so. + // Treat this like a union: without reading from memory, + // we cannot determine the variant we are in. Reading from + // memory would be subject to Stacked Borrows rules, leading + // to all sorts of "funny" recursion. + self.visit_union(v) + } + layout::Variants::Single { .. } => { + // Proceed further + self.walk_value(v) + } + } } } From f3ff10005ab1bdb7c4c0d43ee54d55563911f5ea Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Aug 2019 18:45:10 +0200 Subject: [PATCH 1080/5092] small optimization --- src/helpers.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index e5203becd5cf..3eafb28b8949 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -232,10 +232,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // we cannot determine the variant we are in. Reading from // memory would be subject to Stacked Borrows rules, leading // to all sorts of "funny" recursion. - self.visit_union(v) + // We only end up here if the type is *not* freeze, so we just call the + // `UnsafeCell` action. + (self.unsafe_cell_action)(v) } layout::Variants::Single { .. } => { - // Proceed further + // Proceed further, try to find where exactly that `UnsafeCell` + // is hiding. self.walk_value(v) } } From 1ae1d71938e2a177f3edb60fc30991ce2c8e4536 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 28 Aug 2019 17:20:50 -0500 Subject: [PATCH 1081/5092] Add -Zmiri-env-exclude flag --- README.md | 2 ++ src/bin/miri-rustc-tests.rs | 1 + src/bin/miri.rs | 12 +++++++++++- src/eval.rs | 2 ++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d3e4adfa1785..3cc4872eb7f0 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,8 @@ Several `-Z` flags are relevant for Miri: * `-Zmiri-disable-isolation` disables host host isolation. As a consequence, the program has access to host resources such as environment variables and randomness (and, eventually, file systems and more). +* `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from + the host. It can be used multiple times to exclude several variables. * `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri overrides the default to be `0`; be advised that using any higher level can make Miri miss bugs in your program because they got optimized away. diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 9ef64c38638b..f8bd92afbec7 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -51,6 +51,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { let config = MiriConfig { validate: true, communicate: false, + excluded_env_vars: vec![], args: vec![], seed: None, }; diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 55522a52e012..6e4bf4a6c269 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -135,6 +135,7 @@ fn main() { let mut rustc_args = vec![]; let mut miri_args = vec![]; let mut after_dashdash = false; + let mut excluded_env_vars = vec![]; for arg in std::env::args() { if rustc_args.is_empty() { // Very first arg: for `rustc`. @@ -175,6 +176,9 @@ fn main() { seed = Some(u64::from_be_bytes(bytes)); }, + arg if arg.starts_with("-Zmiri-env-exclude=") => { + excluded_env_vars.push(arg.trim_start_matches("-Zmiri-env-exclude=").to_owned()); + }, _ => { rustc_args.push(arg); } @@ -200,7 +204,13 @@ fn main() { debug!("rustc arguments: {:?}", rustc_args); debug!("miri arguments: {:?}", miri_args); - let miri_config = miri::MiriConfig { validate, communicate, args: miri_args, seed }; + let miri_config = miri::MiriConfig { + validate, + communicate, + excluded_env_vars, + seed, + args: miri_args, + }; let result = rustc_driver::report_ices_to_stderr_if_any(move || { rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None) }).and_then(|result| result); diff --git a/src/eval.rs b/src/eval.rs index bd4d8a0bef85..463f21d30ec7 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -22,6 +22,8 @@ pub struct MiriConfig { pub validate: bool, /// Determines if communication with the host environment is enabled. pub communicate: bool, + /// Environment variables that should always be isolated from the host. + pub excluded_env_vars: Vec, pub args: Vec, /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`). pub seed: Option, From c1cec3b247f022b9e3a88c6afe7d1fe8cc459a76 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 28 Aug 2019 17:31:57 -0500 Subject: [PATCH 1082/5092] Exclude env vars using flag --- src/eval.rs | 2 +- src/shims/env.rs | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 463f21d30ec7..e44fdfd14169 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -42,7 +42,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate), ); // Complete initialization. - EnvVars::init(&mut ecx); + EnvVars::init(&mut ecx, config.excluded_env_vars); // Setup first stack-frame let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); diff --git a/src/shims/env.rs b/src/shims/env.rs index 8f946a2b5eb1..5a5dffa1d09b 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -15,11 +15,14 @@ pub struct EnvVars { impl EnvVars { pub(crate) fn init<'mir, 'tcx>( ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, + excluded_env_vars: Vec, ) { if ecx.machine.communicate { for (name, value) in std::env::vars() { - let var_ptr = alloc_env_var(name.as_bytes(), value.as_bytes(), ecx.memory_mut()); - ecx.machine.env_vars.map.insert(name.into_bytes(), var_ptr); + if !excluded_env_vars.contains(&name) { + let var_ptr = alloc_env_var(name.as_bytes(), value.as_bytes(), ecx.memory_mut()); + ecx.machine.env_vars.map.insert(name.into_bytes(), var_ptr); + } } } } From f4a25e530a773175c19ad6c50e8ce5d0f043e9c7 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 28 Aug 2019 17:34:34 -0500 Subject: [PATCH 1083/5092] Add env exclusion test --- tests/run-pass/env-exclude.rs | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 tests/run-pass/env-exclude.rs diff --git a/tests/run-pass/env-exclude.rs b/tests/run-pass/env-exclude.rs new file mode 100644 index 000000000000..efcf7a756114 --- /dev/null +++ b/tests/run-pass/env-exclude.rs @@ -0,0 +1,6 @@ +// ignore-windows: TODO env var emulation stubbed out on Windows +// compile-flags: -Zmiri-disable-isolation -Zmiri-env-exclude=MIRI_ENV_VAR_TEST + +fn main() { + assert!(std::env::var("MIRI_ENV_VAR_TEST").is_err()); +} From abcda6dc941fb992c4293ab93d710a713ed365cc Mon Sep 17 00:00:00 2001 From: Christian Poveda <31802960+christianpoveda@users.noreply.github.com> Date: Thu, 29 Aug 2019 01:26:14 -0500 Subject: [PATCH 1084/5092] Small corrections Co-Authored-By: Ralf Jung --- README.md | 2 +- benches/helpers/miri_helper.rs | 1 + src/bin/miri-rustc-tests.rs | 1 + src/eval.rs | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3cc4872eb7f0..f5b8999d1c59 100644 --- a/README.md +++ b/README.md @@ -161,7 +161,7 @@ Several `-Z` flags are relevant for Miri: the program has access to host resources such as environment variables and randomness (and, eventually, file systems and more). * `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from - the host. It can be used multiple times to exclude several variables. + the host. Can be used multiple times to exclude several variables. * `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri overrides the default to be `0`; be advised that using any higher level can make Miri miss bugs in your program because they got optimized away. diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 5cb938659a6c..a4f559967204 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -28,6 +28,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { let config = miri::MiriConfig { validate: true, communicate: false, + excluded_env_vars: vec![], args: vec![], seed: None, }; diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index f8bd92afbec7..3b4ad8415917 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -70,6 +70,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { let config = MiriConfig { validate: true, communicate: false, + excluded_env_vars: vec![], args: vec![], seed: None }; diff --git a/src/eval.rs b/src/eval.rs index e44fdfd14169..667491f8d477 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -24,6 +24,7 @@ pub struct MiriConfig { pub communicate: bool, /// Environment variables that should always be isolated from the host. pub excluded_env_vars: Vec, + /// Command-line arguments passed to the interpreted program. pub args: Vec, /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`). pub seed: Option, From 9c54368ccaf4d8a4f67c2df0efa428a6067f0ed3 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 29 Aug 2019 04:07:20 -0500 Subject: [PATCH 1085/5092] Exclude TERM env var by default --- src/shims/env.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 5a5dffa1d09b..d0b5abbaf181 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -15,8 +15,10 @@ pub struct EnvVars { impl EnvVars { pub(crate) fn init<'mir, 'tcx>( ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, - excluded_env_vars: Vec, + mut excluded_env_vars: Vec, ) { + // Exclude TERM var to avoid calls to the file system + excluded_env_vars.push("TERM".to_owned()); if ecx.machine.communicate { for (name, value) in std::env::vars() { if !excluded_env_vars.contains(&name) { From 814fe9951637bc965f072c3d6b7d0386c33e90ae Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 29 Aug 2019 04:09:34 -0500 Subject: [PATCH 1086/5092] Add cargo-miri test for no isolation --- README.md | 3 ++- src/shims/env.rs | 3 ++- test-cargo-miri/run-test.py | 4 ++++ test-cargo-miri/test.stdout.ref3 | 11 +++++++++++ 4 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 test-cargo-miri/test.stdout.ref3 diff --git a/README.md b/README.md index f5b8999d1c59..7ae3c84517f9 100644 --- a/README.md +++ b/README.md @@ -161,7 +161,8 @@ Several `-Z` flags are relevant for Miri: the program has access to host resources such as environment variables and randomness (and, eventually, file systems and more). * `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from - the host. Can be used multiple times to exclude several variables. + the host. Can be used multiple times to exclude several variables. The `TERM` + environment variable is excluded by default. * `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri overrides the default to be `0`; be advised that using any higher level can make Miri miss bugs in your program because they got optimized away. diff --git a/src/shims/env.rs b/src/shims/env.rs index d0b5abbaf181..4b126fbfdaed 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -17,8 +17,9 @@ impl EnvVars { ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, mut excluded_env_vars: Vec, ) { - // Exclude TERM var to avoid calls to the file system + // Exclude `TERM` var to avoid terminfo trying to open the termcap file. excluded_env_vars.push("TERM".to_owned()); + if ecx.machine.communicate { for (name, value) in std::env::vars() { if !excluded_env_vars.contains(&name) { diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 73515c74e401..499c2e896f17 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -60,6 +60,10 @@ def test_cargo_miri_test(): cargo_miri("test") + ["--", "--", "le1"], "test.stdout.ref2", "test.stderr.ref" ) + test("cargo miri test (without isolation)", + cargo_miri("test") + ["--", "-Zmiri-disable-isolation", "--", "num_cpus"], + "test.stdout.ref3", "test.stderr.ref" + ) os.chdir(os.path.dirname(os.path.realpath(__file__))) diff --git a/test-cargo-miri/test.stdout.ref3 b/test-cargo-miri/test.stdout.ref3 new file mode 100644 index 000000000000..f0d8afbd0e8e --- /dev/null +++ b/test-cargo-miri/test.stdout.ref3 @@ -0,0 +1,11 @@ + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out + + +running 1 test +test num_cpus ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 3 filtered out + From cecbe1611befc6bab2fa194e5cdef88f56692193 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Aug 2019 14:56:38 +0200 Subject: [PATCH 1087/5092] test for invalid wide raw ptr --- tests/compile-fail/validity/invalid_wide_raw.rs | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 tests/compile-fail/validity/invalid_wide_raw.rs diff --git a/tests/compile-fail/validity/invalid_wide_raw.rs b/tests/compile-fail/validity/invalid_wide_raw.rs new file mode 100644 index 000000000000..ec14f6988b24 --- /dev/null +++ b/tests/compile-fail/validity/invalid_wide_raw.rs @@ -0,0 +1,8 @@ +fn main() { + trait T { } + #[derive(Debug)] + struct S { + x: * mut dyn T + } + dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); //~ ERROR: encountered dangling or unaligned vtable pointer +} From 5483531be36cc1cdc19048829c1a135ea669ab50 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 29 Aug 2019 17:20:14 +0200 Subject: [PATCH 1088/5092] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 8c746ad2fff8..3520d790eca8 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0444b9f66acb5da23dc816e0d8eb59623ba9ea50 +7445622bcb515c822a2fc6e8c57c90478c1a56bb From 4afa3bccb0a41b49037cb5b80943d58374a04cf7 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 29 Aug 2019 15:03:10 -0500 Subject: [PATCH 1089/5092] Rewrite alloc_env_var --- src/shims/env.rs | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 4b126fbfdaed..1cffc60bc40a 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use rustc::ty::layout::{Size, Align}; +use rustc::ty::layout::{Size}; use rustc_mir::interpret::{Pointer, Memory}; use crate::stacked_borrows::Tag; use crate::*; @@ -36,24 +36,11 @@ fn alloc_env_var<'mir, 'tcx>( value: &[u8], memory: &mut Memory<'mir, 'tcx, Evaluator<'tcx>>, ) -> Pointer { - let bytes = [name, b"=", value].concat(); - let tcx = {memory.tcx.tcx}; - let length = bytes.len() as u64; - // `+1` for the null terminator. - let ptr = memory.allocate( - Size::from_bytes(length + 1), - Align::from_bytes(1).unwrap(), - MiriMemoryKind::Env.into(), - ); - // We just allocated these, so the write cannot fail. - let alloc = memory.get_mut(ptr.alloc_id).unwrap(); - alloc.write_bytes(&tcx, ptr, &bytes).unwrap(); - let trailing_zero_ptr = ptr.offset( - Size::from_bytes(length), - &tcx, - ).unwrap(); - alloc.write_bytes(&tcx, trailing_zero_ptr, &[0]).unwrap(); - ptr + let mut bytes = name.to_vec(); + bytes.push(b'='); + bytes.extend_from_slice(value); + bytes.push(0); + memory.allocate_static_bytes(bytes.as_slice(), MiriMemoryKind::Env.into()) } impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} From f67af5a1c2e6e7c785b9fc1d1edcff936992382a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Aug 2019 18:36:43 +0200 Subject: [PATCH 1090/5092] test too big slice --- tests/compile-fail/slice-too-big.rs | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/compile-fail/slice-too-big.rs diff --git a/tests/compile-fail/slice-too-big.rs b/tests/compile-fail/slice-too-big.rs new file mode 100644 index 000000000000..08ab48175aed --- /dev/null +++ b/tests/compile-fail/slice-too-big.rs @@ -0,0 +1,7 @@ +use std::mem; +use std::usize; + +fn main() { unsafe { + let ptr = Box::into_raw(Box::new(0u8)); + let _x: &[u8] = mem::transmute((ptr, usize::MAX)); //~ ERROR: invalid slice: total size is bigger than largest supported object +} } From dfca0263d0471547ccad1841076be07197c38675 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 31 Aug 2019 08:44:47 +0200 Subject: [PATCH 1091/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 3520d790eca8..af5cbdfb6ca3 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7445622bcb515c822a2fc6e8c57c90478c1a56bb +2d851b33181b1404856cb1d8b20d261adda54ffb From a37cd856adef52451f024b44c668a8021f8236e0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Sep 2019 16:13:35 +0200 Subject: [PATCH 1092/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index af5cbdfb6ca3..28dca558cf78 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -2d851b33181b1404856cb1d8b20d261adda54ffb +fdaf594bab31eec75fb6d582cd33e5a5b43de7f4 From e479ab26406ed8a473987e5f4a1f3be3e978e5d2 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 5 Sep 2019 18:17:58 +0200 Subject: [PATCH 1093/5092] Rustup --- src/intptrcast.rs | 10 +++++----- src/machine.rs | 39 ++++++++++++-------------------------- src/shims/foreign_items.rs | 2 +- src/shims/intrinsics.rs | 18 +++++++++--------- 4 files changed, 27 insertions(+), 42 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index b1e89f3819ae..e08166b8c2b2 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -47,7 +47,7 @@ impl<'mir, 'tcx> GlobalState { } let global_state = memory.extra.intptrcast.borrow(); - + Ok(match global_state.int_to_ptr_map.binary_search_by_key(&int, |(addr, _)| *addr) { Ok(pos) => { let (_, alloc_id) = global_state.int_to_ptr_map[pos]; @@ -55,7 +55,7 @@ impl<'mir, 'tcx> GlobalState { // zero. The pointer is untagged because it was created from a cast Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged) }, - Err(0) => throw_unsup!(DanglingPointerDeref), + Err(0) => throw_unsup!(DanglingPointerDeref), Err(pos) => { // This is the largest of the adresses smaller than `int`, // i.e. the greatest lower bound (glb) @@ -63,12 +63,12 @@ impl<'mir, 'tcx> GlobalState { // This never overflows because `int >= glb` let offset = int - glb; // If the offset exceeds the size of the allocation, this access is illegal - if offset <= memory.get(alloc_id)?.bytes.len() as u64 { + if offset <= memory.get(alloc_id)?.size.bytes() { // This pointer is untagged because it was created from a cast Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged) } else { throw_unsup!(DanglingPointerDeref) - } + } } }) } @@ -108,7 +108,7 @@ impl<'mir, 'tcx> GlobalState { global_state.next_base_addr = base_addr.checked_add(max(size.bytes(), 1)).unwrap(); // Given that `next_base_addr` increases in each allocation, pushing the // corresponding tuple keeps `int_to_ptr_map` sorted - global_state.int_to_ptr_map.push((base_addr, ptr.alloc_id)); + global_state.int_to_ptr_map.push((base_addr, ptr.alloc_id)); base_addr } diff --git a/src/machine.rs b/src/machine.rs index 3853a45fd990..95cb31d67b8f 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -248,7 +248,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { None => tcx.item_name(def_id).as_str(), }; - let alloc = match link_name.get() { + let alloc = match &*link_name { "__cxa_thread_atexit_impl" => { // This should be all-zero, pointer-sized. let size = tcx.data_layout.pointer_size; @@ -280,40 +280,25 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } else { let (stacks, base_tag) = Stacks::new_allocation( id, - Size::from_bytes(alloc.bytes.len() as u64), + alloc.size, Rc::clone(&memory_extra.stacked_borrows), kind, ); (Some(stacks), base_tag) }; - if kind != MiriMemoryKind::Static.into() { - assert!(alloc.relocations.is_empty(), "Only statics can come initialized with inner pointers"); - // Now we can rely on the inner pointers being static, too. - } let mut stacked_borrows = memory_extra.stacked_borrows.borrow_mut(); - let alloc: Allocation = Allocation { - bytes: alloc.bytes, - relocations: Relocations::from_presorted( - alloc.relocations.iter() - // The allocations in the relocations (pointers stored *inside* this allocation) - // all get the base pointer tag. - .map(|&(offset, ((), alloc))| { - let tag = if !memory_extra.validate { - Tag::Untagged - } else { - stacked_borrows.static_base_ptr(alloc) - }; - (offset, (tag, alloc)) - }) - .collect() - ), - undef_mask: alloc.undef_mask, - align: alloc.align, - mutability: alloc.mutability, - extra: AllocExtra { + let alloc: Allocation = alloc.retag( + |alloc| if !memory_extra.validate { + Tag::Untagged + } else { + // Only statics may already contain pointers at this point + assert_eq!(kind, MiriMemoryKind::Static.into()); + stacked_borrows.static_base_ptr(alloc) + }, + AllocExtra { stacked_borrows: stacks, }, - }; + ); (Cow::Owned(alloc), base_tag) } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 0b2fa64996e7..90c18265fcf7 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -138,7 +138,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx None => this.tcx.item_name(def_id).as_str(), }; // Strip linker suffixes (seen on 32-bit macOS). - let link_name = link_name.get().trim_end_matches("$UNIX2003"); + let link_name = link_name.trim_end_matches("$UNIX2003"); let tcx = &{this.tcx.tcx}; // First: functions that diverge. diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 865696276171..06af6db76ae6 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -28,8 +28,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // (as opposed to through a place), we have to remember to erase any tag // that might still hang around! - let intrinsic_name = this.tcx.item_name(instance.def_id()).as_str(); - match intrinsic_name.get() { + let intrinsic_name = &*this.tcx.item_name(instance.def_id()).as_str(); + match intrinsic_name { "arith_offset" => { let offset = this.read_scalar(args[1])?.to_isize(this)?; let ptr = this.read_scalar(args[0])?.not_undef()?; @@ -228,7 +228,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" | "roundf32" => { // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); - let f = match intrinsic_name.get() { + let f = match intrinsic_name { "sinf32" => f.sin(), "fabsf32" => f.abs(), "cosf32" => f.cos(), @@ -251,7 +251,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" | "roundf64" => { // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); - let f = match intrinsic_name.get() { + let f = match intrinsic_name { "sinf64" => f.sin(), "fabsf64" => f.abs(), "cosf64" => f.cos(), @@ -273,7 +273,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { let a = this.read_immediate(args[0])?; let b = this.read_immediate(args[1])?; - let op = match intrinsic_name.get() { + let op = match intrinsic_name { "fadd_fast" => mir::BinOp::Add, "fsub_fast" => mir::BinOp::Sub, "fmul_fast" => mir::BinOp::Mul, @@ -287,7 +287,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "minnumf32" | "maxnumf32" => { let a = this.read_scalar(args[0])?.to_f32()?; let b = this.read_scalar(args[1])?.to_f32()?; - let res = if intrinsic_name.get().starts_with("min") { + let res = if intrinsic_name.starts_with("min") { a.min(b) } else { a.max(b) @@ -298,7 +298,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "minnumf64" | "maxnumf64" => { let a = this.read_scalar(args[0])?.to_f64()?; let b = this.read_scalar(args[1])?.to_f64()?; - let res = if intrinsic_name.get().starts_with("min") { + let res = if intrinsic_name.starts_with("min") { a.min(b) } else { a.max(b) @@ -509,7 +509,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "unchecked_add" | "unchecked_sub" | "unchecked_mul" => { let l = this.read_immediate(args[0])?; let r = this.read_immediate(args[1])?; - let op = match intrinsic_name.get() { + let op = match intrinsic_name { "unchecked_add" => mir::BinOp::Add, "unchecked_sub" => mir::BinOp::Sub, "unchecked_mul" => mir::BinOp::Mul, @@ -517,7 +517,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; let (res, overflowed, _ty) = this.overflowing_binary_op(op, l, r)?; if overflowed { - throw_ub_format!("Overflowing arithmetic in {}", intrinsic_name.get()); + throw_ub_format!("Overflowing arithmetic in {}", intrinsic_name); } this.write_scalar(res, dest)?; } From 8349ead81db9e199fa42bc7b79a90499cb63b518 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 8 Sep 2019 12:28:31 +0200 Subject: [PATCH 1094/5092] Update latest working rust version id --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 28dca558cf78..937df9071860 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -fdaf594bab31eec75fb6d582cd33e5a5b43de7f4 +4894123d21ed4b153a2e5c32c0870cb2d97f9b46 From 636439c33f392d71fe455727dc9386d264b753d0 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Mon, 9 Sep 2019 06:32:02 -0400 Subject: [PATCH 1095/5092] Re-enable run-pass tests with optimizations enabled --- tests/compiletest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index aa2488b1a417..00fd039ad7e8 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -122,7 +122,7 @@ fn test_runner(_tests: &[&()]) { std::env::set_var("MIRI_ENV_VAR_TEST", "0"); run_pass_miri(false); - // FIXME: hashmap ICEs with optimizations run_pass_miri(true); + run_pass_miri(true); compile_fail_miri(false); compile_fail_miri(true); From b952584186bcb3035c89b8382cafe57a8bfa23ec Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 9 Sep 2019 13:00:20 +0200 Subject: [PATCH 1096/5092] Rustup to 1.39.0-nightly (1e869133b 2019-09-09) --- rust-version | 2 +- tests/compile-fail/stack_free.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 937df9071860..44e4cd9ccead 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4894123d21ed4b153a2e5c32c0870cb2d97f9b46 +1e869133b9888dc5abde54f4f31cb797ed9c7874 diff --git a/tests/compile-fail/stack_free.rs b/tests/compile-fail/stack_free.rs index a33bca126759..43cc17308c06 100644 --- a/tests/compile-fail/stack_free.rs +++ b/tests/compile-fail/stack_free.rs @@ -1,7 +1,7 @@ // Validation changes why we fail // compile-flags: -Zmiri-disable-validation -// error-pattern: tried to deallocate Stack memory but gave Machine(Rust) as the kind +// error-pattern: tried to deallocate `Stack` memory but gave `Machine(Rust)` as the kind fn main() { let x = 42; From f5c35a25842d3dcec676b7a5175c90a06184b87c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Sep 2019 17:13:32 +0200 Subject: [PATCH 1097/5092] fix async test --- rust-version | 2 +- tests/run-pass/async-fn.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 44e4cd9ccead..2e869d31de41 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1e869133b9888dc5abde54f4f31cb797ed9c7874 +74d5c70b174f06843049af2d764ff57ddc81c81c diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index dd31d901062f..90448aca1779 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -15,7 +15,8 @@ pub async fn foo(x: &u32, y: u32) -> u32 { } async fn add(x: u32, y: u32) -> u32 { - async { x + y }.await + let a = async { x + y }; + a.await } async fn build_aggregate(a: u32, b: u32, c: u32, d: u32) -> u32 { From 62280b4b1166830facf1b43d6dda13df687252c8 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 11 Sep 2019 11:09:56 -0500 Subject: [PATCH 1098/5092] Use libcore's align_offset --- src/shims/mod.rs | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 5fbe6e379987..5b67d075a5c7 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -1,3 +1,4 @@ + pub mod foreign_items; pub mod intrinsics; pub mod tls; @@ -27,9 +28,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // There are some more lang items we want to hook that CTFE does not hook (yet). if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { - // FIXME: return a real value in case the target allocation has an - // alignment bigger than the one requested. - let n = u128::max_value(); + + let n = { + let ptr = this.read_scalar(args[0])?.not_undef()?.assert_ptr(); + let align = this.force_bits( + this.read_scalar(args[1])?.not_undef()?, + this.pointer_size() + )? as usize; + + let stride = this.memory().get(ptr.alloc_id)?.align.bytes() as usize; + // if the allocation alignment is at least the required alignment, we use the + // libcore implementation + if stride >= align { + ((stride + ptr.offset.bytes() as usize) as *const ()) + .align_offset(align) as u128 + } else { + u128::max_value() + } + }; + let dest = dest.unwrap(); let n = this.truncate(n, dest.layout); this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; From 138492c30b85748c3ab9d9f040f98ad9e4343e1f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Sep 2019 18:33:48 +0200 Subject: [PATCH 1099/5092] bump rand dependency --- Cargo.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ecc8deedf325..7d6e9812aaf9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,11 +39,13 @@ env_logger = "0.6" log = "0.4" shell-escape = "0.1.4" hex = "0.3.2" -rand = "0.6" +rand = "0.7" + # A noop dependency that changes in the Rust repository, it's a bit of a hack. # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` # for more information. rustc-workspace-hack = "1.0.0" + # Depend on num-traits with default features to avoid having to rebuild # between "cargo build" and "cargo intall". num-traits = "*" From ed70617b9c78ab28c1c6616e112b4516b8d4a7de Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 11 Sep 2019 12:08:42 -0500 Subject: [PATCH 1100/5092] Add test for u8 align_offset --- tests/run-pass/aligned_utf8_check.rs | 13 +++++++++++++ tests/run-pass/aligned_utf8_check.stdout | 1 + 2 files changed, 14 insertions(+) create mode 100644 tests/run-pass/aligned_utf8_check.rs create mode 100644 tests/run-pass/aligned_utf8_check.stdout diff --git a/tests/run-pass/aligned_utf8_check.rs b/tests/run-pass/aligned_utf8_check.rs new file mode 100644 index 000000000000..0d2b2bf66a97 --- /dev/null +++ b/tests/run-pass/aligned_utf8_check.rs @@ -0,0 +1,13 @@ +fn main() { + const N: usize = 10; + + let x = vec![0x4141u16; N]; + + let mut y: Vec = unsafe { std::mem::transmute(x) }; + unsafe { y.set_len(2 * N) }; + + println!("{:?}", String::from_utf8_lossy(&y)); + + let mut x: Vec = unsafe { std::mem::transmute(y) }; + unsafe { x.set_len(N) }; +} diff --git a/tests/run-pass/aligned_utf8_check.stdout b/tests/run-pass/aligned_utf8_check.stdout new file mode 100644 index 000000000000..8d08312cac7b --- /dev/null +++ b/tests/run-pass/aligned_utf8_check.stdout @@ -0,0 +1 @@ +"AAAAAAAAAAAAAAAAAAAA" From 247ac227ef3ce3fe5c1886b6b5c96eee17e4779a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Thu, 12 Sep 2019 12:45:00 +0200 Subject: [PATCH 1101/5092] Bump byteorder and remove no-op feature --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ecc8deedf325..25506c963a7e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,11 +30,11 @@ doctest = false # and no doc tests required-features = ["rustc_tests"] [dependencies] -byteorder = { version = "1.1", features = ["i128"] } cargo_metadata = { version = "0.8", optional = true } directories = { version = "2.0", optional = true } rustc_version = { version = "0.2.3", optional = true } getrandom = { version = "0.1.8", features = ["std"] } +byteorder = "1.3" env_logger = "0.6" log = "0.4" shell-escape = "0.1.4" From fa20338c9aa4a64d984c61ae5f4332db89c78de1 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 12 Sep 2019 09:25:39 -0500 Subject: [PATCH 1102/5092] Use str::from_utf8 instead --- src/shims/mod.rs | 1 - tests/run-pass/aligned_utf8_check.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 5b67d075a5c7..728634a7f6f6 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -1,4 +1,3 @@ - pub mod foreign_items; pub mod intrinsics; pub mod tls; diff --git a/tests/run-pass/aligned_utf8_check.rs b/tests/run-pass/aligned_utf8_check.rs index 0d2b2bf66a97..202856b3bde9 100644 --- a/tests/run-pass/aligned_utf8_check.rs +++ b/tests/run-pass/aligned_utf8_check.rs @@ -6,7 +6,7 @@ fn main() { let mut y: Vec = unsafe { std::mem::transmute(x) }; unsafe { y.set_len(2 * N) }; - println!("{:?}", String::from_utf8_lossy(&y)); + println!("{:?}", std::str::from_utf8(&y).unwrap()); let mut x: Vec = unsafe { std::mem::transmute(y) }; unsafe { x.set_len(N) }; From b245cb616e7ef75b6a1381d3b432e4e856922bd8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 13 Sep 2019 10:39:36 +0200 Subject: [PATCH 1103/5092] factor ask-to-run-command into helper function --- src/bin/cargo-miri.rs | 62 +++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 8749e5b7eed9..43e8761d48c1 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -218,17 +218,28 @@ fn xargo_version() -> Option<(u32, u32, u32)> { Some((major, minor, patch)) } -fn ask(question: &str) { - let mut buf = String::new(); - print!("{} [Y/n] ", question); - io::stdout().flush().unwrap(); - io::stdin().read_line(&mut buf).unwrap(); - match buf.trim().to_lowercase().as_ref() { - // Proceed. - "" | "y" | "yes" => {}, - "n" | "no" => show_error(format!("Aborting as per your request")), - a => show_error(format!("I do not understand `{}`", a)) - }; +fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { + if ask { + let mut buf = String::new(); + print!("I will run `{:?}` to {}. Proceed? [Y/n] ", cmd, text); + io::stdout().flush().unwrap(); + io::stdin().read_line(&mut buf).unwrap(); + match buf.trim().to_lowercase().as_ref() { + // Proceed. + "" | "y" | "yes" => {}, + "n" | "no" => show_error(format!("Aborting as per your request")), + a => show_error(format!("I do not understand `{}`", a)) + }; + } else { + println!("Running `{:?}` to {}.", cmd, text); + } + + if cmd.status() + .expect(&format!("failed to execute {:?}", cmd)) + .success().not() + { + show_error(format!("Failed to {}", text)); + } } /// Performs the setup required to make `cargo miri` work: Getting a custom-built libstd. Then sets @@ -244,18 +255,9 @@ fn setup(ask_user: bool) { // First, we need xargo. if xargo_version().map_or(true, |v| v < (0, 3, 16)) { - if ask_user { - ask("It seems you do not have a recent enough xargo installed. I will run `cargo install xargo -f`. Proceed?"); - } else { - println!("Installing xargo: `cargo install xargo -f`"); - } - - if cargo().args(&["install", "xargo", "-f"]).status() - .expect("failed to install xargo") - .success().not() - { - show_error(format!("Failed to install xargo")); - } + let mut cmd = cargo(); + cmd.args(&["install", "xargo", "-f"]); + ask_to_run(cmd, ask_user, "install a recent enough xargo"); } // Then, unless `XARGO_RUST_SRC` is set, we also need rust-src. @@ -267,17 +269,9 @@ fn setup(ask_user: bool) { let sysroot = std::str::from_utf8(&sysroot).unwrap(); let src = Path::new(sysroot.trim_end_matches('\n')).join("lib").join("rustlib").join("src"); if !src.exists() { - if ask_user { - ask("It seems you do not have the rust-src component installed. I will run `rustup component add rust-src` for the selected toolchain. Proceed?"); - } else { - println!("Installing rust-src component: `rustup component add rust-src`"); - } - if !Command::new("rustup").args(&["component", "add", "rust-src"]).status() - .expect("failed to install rust-src component") - .success() - { - show_error(format!("Failed to install rust-src component")); - } + let mut cmd = Command::new("rustup"); + cmd.args(&["component", "add", "rust-src"]); + ask_to_run(cmd, ask_user, "install the rustc-src component for the selected toolchain"); } } From 78cfdcead22482c1ac5d8fa408cfc673d5735c20 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 14 Sep 2019 13:05:39 +0200 Subject: [PATCH 1104/5092] temporarily enable backtrace feature --- rust-version | 2 +- src/bin/cargo-miri.rs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 2e869d31de41..b0af10f44a94 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -74d5c70b174f06843049af2d764ff57ddc81c81c +eb48d6bdee6c655d71f26594d47d232adf3e4e93 diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 8749e5b7eed9..7e92c51f8e64 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -294,7 +294,9 @@ fn setup(ask_user: bool) { default_features = false # We need the `panic_unwind` feature because we use the `unwind` panic strategy. # Using `abort` works for libstd, but then libtest will not compile. -features = ["panic_unwind"] +# FIXME: Temporarily enabling backtrace feature to work around +# . +features = ["panic_unwind", "backtrace"] [dependencies.test] "#).unwrap(); From 1fb934b6cf7bf7a7b62ef65f728a397e27507f18 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 14 Sep 2019 13:40:37 +0200 Subject: [PATCH 1105/5092] add CONTRIBUTING guide --- CONTRIBUTING.md | 141 ++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 129 ++------------------------------------------ 2 files changed, 146 insertions(+), 124 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000000..83e2338552e9 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,141 @@ +# Contribution Guide + +If you want to hack on miri yourself, great! Here are some resources you might +find useful. + +## Getting started + +Check out the issues on this GitHub repository for some ideas. There's lots that +needs to be done that we haven't documented in the issues yet, however. For more +ideas or help with hacking on Miri, you can contact us (`oli-obk` and `RalfJ`) +on the [Rust Zulip]. + +[Rust Zulip]: https://rust-lang.zulipchat.com + +### Fixing Miri when rustc changes + +Miri is heavily tied to rustc internals, so it is very common that rustc changes +break Miri. Fixing those is a good way to get starting working on Miri. +Usually, Miri will require changes similar to the other consumers of the changed +rustc API, so reading the rustc PR diff is a good way to get an idea for what is +needed. + +When submitting a PR against Miri after fixing it for rustc changes, make sure +you update the `rust-version` file. That file always contains the exact rustc +git commit with which Miri works, and it is the version that our CI tests Miri +against. + +## Building Miri with a nightly rustc + +Miri heavily relies on internal rustc interfaces to execute MIR. Still, some +things (like adding support for a new intrinsic or a shim for an external +function being called) can be done by working just on the Miri side. + +To prepare, make sure you are using a nightly Rust compiler. Then you should be +able to just `cargo build` Miri. + +In case this fails, your nightly might be incompatible with Miri master. The +`rust-version` file contains the commit hash of rustc that Miri is currently +tested against; you can use that to find a nightly that works or you might have +to wait for the next nightly to get released. You can also use +[`rustup-toolchain-install-master`](https://github.com/kennytm/rustup-toolchain-install-master) +to install that exact version of rustc as a toolchain: +``` +rustup-toolchain-install-master $(cat rust-version) -c rust-src +``` + +Another common problem is outdated dependencies: Miri does not come with a +lockfile (it cannot, due to how it gets embedded into the rustc build). So you +have to run `cargo update` every now and then yourself to make sure you are +using the latest versions of everything (which is what gets tested on CI). + +## Testing the Miri driver +[testing-miri]: #testing-the-miri-driver + +The Miri driver in the `miri` binary is the "heart" of Miri: it is basically a +version of `rustc` that, instead of compiling your code, runs it. It accepts +all the same flags as `rustc` (though the ones only affecting code generation +and linking obviously will have no effect) [and more][miri-flags]. + +Running the Miri driver requires some fiddling with environment variables, so +the `miri` script helps you do that. For example, you can run the driver on a +particular file by doing + +```sh +./miri run tests/run-pass/format.rs +./miri run tests/run-pass/hello.rs --target i686-unknown-linux-gnu +``` + +and you can run the test suite using: + +``` +./miri test +``` + +`./miri test FILTER` only runs those tests that contain `FILTER` in their +filename (including the base directory, e.g. `./miri test fail` will run all +compile-fail tests). + +You can get a trace of which MIR statements are being executed by setting the +`MIRI_LOG` environment variable. For example: + +```sh +MIRI_LOG=info ./miri run tests/run-pass/vecs.rs +``` + +Setting `MIRI_LOG` like this will configure logging for Miri itself as well as +the `rustc::mir::interpret` and `rustc_mir::interpret` modules in rustc. You +can also do more targeted configuration, e.g. the following helps debug the +stacked borrows implementation: + +```sh +MIRI_LOG=rustc_mir::interpret=info,miri::stacked_borrows ./miri run tests/run-pass/vecs.rs +``` + +In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an +evaluation error was originally raised. + +## Testing `cargo miri` + +Working with the driver directly gives you full control, but you also lose all +the convenience provided by cargo. Once your test case depends on a crate, it +is probably easier to test it with the cargo wrapper. You can install your +development version of Miri using + +``` +./miri install +``` + +and then you can use it as if it was installed by `rustup`. Make sure you use +the same toolchain when calling `cargo miri` that you used when installing Miri! + +There's a test for the cargo wrapper in the `test-cargo-miri` directory; run +`./run-test.py` in there to execute it. + +## Building Miri with a locally built rustc + +A big part of the Miri driver lives in rustc, so working on Miri will sometimes +require using a locally built rustc. The bug you want to fix may actually be on +the rustc side, or you just need to get more detailed trace of the execution +than what is possible with release builds -- in both cases, you should develop +miri against a rustc you compiled yourself, with debug assertions (and hence +tracing) enabled. + +The setup for a local rustc works as follows: +```sh +git clone https://github.com/rust-lang/rust/ rustc +cd rustc +cp config.toml.example config.toml +# Now edit `config.toml` and set `debug-assertions = true`. +# This step can take 30 minutes and more. +./x.py build src/rustc +# If you change something, you can get a faster rebuild by doing +./x.py --keep-stage 0 build src/rustc +# You may have to change the architecture in the next command +rustup toolchain link custom build/x86_64-unknown-linux-gnu/stage2 +# Now cd to your Miri directory, then configure rustup +rustup override set custom +``` + +With this, you should now have a working development setup! See +[above][testing-miri] for how to proceed working with the Miri driver. diff --git a/README.md b/README.md index 7ae3c84517f9..0187047534d4 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ program, and cannot run all programs: [`copy_nonoverlapping`]: https://doc.rust-lang.org/stable/std/ptr/fn.copy_nonoverlapping.html -## Running Miri on your own project (and its test suite) +## Using Miri Install Miri via `rustup`: @@ -183,131 +183,12 @@ Moreover, Miri recognizes some environment variables: architecture to test against. `miri` and `cargo miri` accept the `--target` flag for the same purpose. -## Development and Debugging - -If you want to hack on miri yourself, great! Here are some resources you might -find useful. - -### Using a nightly rustc - -Miri heavily relies on internal rustc interfaces to execute MIR. Still, some -things (like adding support for a new intrinsic or a shim for an external -function being called) can be done by working just on the Miri side. - -To prepare, make sure you are using a nightly Rust compiler. Then you should be -able to just `cargo build` Miri. - -In case this fails, your nightly might be incompatible with Miri master. The -`rust-version` file contains the commit hash of rustc that Miri is currently -tested against; you can use that to find a nightly that works or you might have -to wait for the next nightly to get released. You can also use -[`rustup-toolchain-install-master`](https://github.com/kennytm/rustup-toolchain-install-master) -to install that exact version of rustc as a toolchain: -``` -rustup-toolchain-install-master $(cat rust-version) -c rust-src -``` - -Another common problem is outdated dependencies: Miri does not come with a -lockfile (it cannot, due to how it gets embedded into the rustc build). So you -have to run `cargo update` every now and then yourself to make sure you are -using the latest versions of everything (which is what gets tested on CI). - -### Testing the Miri driver -[testing-miri]: #testing-the-miri-driver - -The Miri driver in the `miri` binary is the "heart" of Miri: it is basically a -version of `rustc` that, instead of compiling your code, runs it. It accepts -all the same flags as `rustc` (though the ones only affecting code generation -and linking obviously will have no effect) [and more][miri-flags]. - -Running the Miri driver requires some fiddling with environment variables, so -the `miri` script helps you do that. For example, you can run the driver on a -particular file by doing - -```sh -./miri run tests/run-pass/format.rs -./miri run tests/run-pass/hello.rs --target i686-unknown-linux-gnu -``` - -and you can run the test suite using: - -``` -./miri test -``` - -`./miri test FILTER` only runs those tests that contain `FILTER` in their -filename (including the base directory, e.g. `./miri test fail` will run all -compile-fail tests). - -You can get a trace of which MIR statements are being executed by setting the -`MIRI_LOG` environment variable. For example: - -```sh -MIRI_LOG=info ./miri run tests/run-pass/vecs.rs -``` - -Setting `MIRI_LOG` like this will configure logging for Miri itself as well as -the `rustc::mir::interpret` and `rustc_mir::interpret` modules in rustc. You -can also do more targeted configuration, e.g. the following helps debug the -stacked borrows implementation: - -```sh -MIRI_LOG=rustc_mir::interpret=info,miri::stacked_borrows ./miri run tests/run-pass/vecs.rs -``` - -In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an -evaluation error was originally raised. - -### Testing `cargo miri` - -Working with the driver directly gives you full control, but you also lose all -the convenience provided by cargo. Once your test case depends on a crate, it -is probably easier to test it with the cargo wrapper. You can install your -development version of Miri using - -``` -./miri install -``` - -and then you can use it as if it was installed by `rustup`. Make sure you use -the same toolchain when calling `cargo miri` that you used when installing Miri! - -There's a test for the cargo wrapper in the `test-cargo-miri` directory; run -`./run-test.py` in there to execute it. - -### Using a locally built rustc - -A big part of the Miri driver lives in rustc, so working on Miri will sometimes -require using a locally built rustc. The bug you want to fix may actually be on -the rustc side, or you just need to get more detailed trace of the execution -than what is possible with release builds -- in both cases, you should develop -miri against a rustc you compiled yourself, with debug assertions (and hence -tracing) enabled. - -The setup for a local rustc works as follows: -```sh -git clone https://github.com/rust-lang/rust/ rustc -cd rustc -cp config.toml.example config.toml -# Now edit `config.toml` and set `debug-assertions = true`. -# This step can take 30 minutes and more. -./x.py build src/rustc -# If you change something, you can get a faster rebuild by doing -./x.py --keep-stage 0 build src/rustc -# You may have to change the architecture in the next command -rustup toolchain link custom build/x86_64-unknown-linux-gnu/stage2 -# Now cd to your Miri directory, then configure rustup -rustup override set custom -``` - -With this, you should now have a working development setup! See -[above][testing-miri] for how to proceed working with the Miri driver. - ## Contributing and getting help -Check out the issues on this GitHub repository for some ideas. There's lots that -needs to be done that I haven't documented in the issues yet, however. For more -ideas or help with running or hacking on Miri, you can open an issue here on +If you want to contribute to Miri, great! Please check out our +[contribution guide](CONTRIBUTING.md). + +For help with running Miri, you can open an issue here on GitHub or contact us (`oli-obk` and `RalfJ`) on the [Rust Zulip]. [Rust Zulip]: https://rust-lang.zulipchat.com From 5ecb2d93564f5674378f348635488410aba3cff5 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sat, 14 Sep 2019 01:01:37 -0300 Subject: [PATCH 1106/5092] Place projection field is now Box<[PlaceElem<'tcx>]> --- rust-version | 2 +- src/helpers.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index b0af10f44a94..60ef1e36f704 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -eb48d6bdee6c655d71f26594d47d232adf3e4e93 +b35ebac96102cd12406d9d87827b0838d129c278 diff --git a/src/helpers.rs b/src/helpers.rs index 3eafb28b8949..ad30040c2ddc 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -71,7 +71,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Get the `Place` for a local fn local_place(&mut self, local: mir::Local) -> InterpResult<'tcx, PlaceTy<'tcx, Tag>> { let this = self.eval_context_mut(); - let place = mir::Place { base: mir::PlaceBase::Local(local), projection: None }; + let place = mir::Place { base: mir::PlaceBase::Local(local), projection: Box::new([]) }; this.eval_place(&place) } From 1ef1d581d3900e34dd6db58f20322474dad71a54 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 15 Sep 2019 23:27:58 +0200 Subject: [PATCH 1107/5092] update for rustc changes --- rust-version | 2 +- src/bin/miri.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 60ef1e36f704..07e965d7c39e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -b35ebac96102cd12406d9d87827b0838d129c278 +96d07e0ac9f0c56b95a2561c6cedac0b23a5d2a3 diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 6e4bf4a6c269..7b3dbeacc48f 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -211,7 +211,7 @@ fn main() { seed, args: miri_args, }; - let result = rustc_driver::report_ices_to_stderr_if_any(move || { + let result = rustc_driver::catch_fatal_errors(move || { rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None) }).and_then(|result| result); std::process::exit(result.is_err() as i32); From 9e2107cef59e3ca2f2c2687ec85533177de0a337 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 16 Sep 2019 09:31:56 +0200 Subject: [PATCH 1108/5092] install ICE hook --- src/bin/miri.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 7b3dbeacc48f..dd56f0a6e53c 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -211,6 +211,7 @@ fn main() { seed, args: miri_args, }; + rustc_driver::install_ice_hook(); let result = rustc_driver::catch_fatal_errors(move || { rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None) }).and_then(|result| result); From 55863cb88effdaa2198a22149cfae99c2377dd76 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 16 Sep 2019 10:16:06 -0500 Subject: [PATCH 1109/5092] Use force_ptr instead of assert_ptr --- src/shims/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 728634a7f6f6..a0da364ff0b9 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -29,7 +29,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { let n = { - let ptr = this.read_scalar(args[0])?.not_undef()?.assert_ptr(); + let ptr = this.force_ptr(this.read_scalar(args[0])?.not_undef()?)?; let align = this.force_bits( this.read_scalar(args[1])?.not_undef()?, this.pointer_size() From 8cd215dc9733defd7f73c3955bc21c63d8b3ed7e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 16 Sep 2019 22:22:54 +0200 Subject: [PATCH 1110/5092] remove libstd backtrace work-around --- rust-version | 2 +- src/bin/cargo-miri.rs | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index 07e965d7c39e..464b061edbd0 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -96d07e0ac9f0c56b95a2561c6cedac0b23a5d2a3 +a44881d892fb4f4a8ed93f8f392bab942fac7a41 diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index d92fc344e8ad..43e8761d48c1 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -288,9 +288,7 @@ fn setup(ask_user: bool) { default_features = false # We need the `panic_unwind` feature because we use the `unwind` panic strategy. # Using `abort` works for libstd, but then libtest will not compile. -# FIXME: Temporarily enabling backtrace feature to work around -# . -features = ["panic_unwind", "backtrace"] +features = ["panic_unwind"] [dependencies.test] "#).unwrap(); From 130f9488d3b861e02c9282b686eec717e30912cf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 17 Sep 2019 12:30:14 +0200 Subject: [PATCH 1111/5092] rustup --- src/machine.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine.rs b/src/machine.rs index 95cb31d67b8f..340dd109e124 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -287,7 +287,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { (Some(stacks), base_tag) }; let mut stacked_borrows = memory_extra.stacked_borrows.borrow_mut(); - let alloc: Allocation = alloc.retag( + let alloc: Allocation = alloc.with_tags_and_extra( |alloc| if !memory_extra.validate { Tag::Untagged } else { From 881929f7537d6fd5b85f6c8efc1dc0f3f558591f Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 16 Sep 2019 13:46:37 -0500 Subject: [PATCH 1112/5092] Add align_offset for integers --- src/shims/mod.rs | 49 +++++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/src/shims/mod.rs b/src/shims/mod.rs index a0da364ff0b9..f9b89cf553a3 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -27,25 +27,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // There are some more lang items we want to hook that CTFE does not hook (yet). if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { - - let n = { - let ptr = this.force_ptr(this.read_scalar(args[0])?.not_undef()?)?; - let align = this.force_bits( - this.read_scalar(args[1])?.not_undef()?, - this.pointer_size() - )? as usize; - - let stride = this.memory().get(ptr.alloc_id)?.align.bytes() as usize; - // if the allocation alignment is at least the required alignment, we use the - // libcore implementation - if stride >= align { - ((stride + ptr.offset.bytes() as usize) as *const ()) - .align_offset(align) as u128 - } else { - u128::max_value() - } - }; - + let n = this.align_offset(args[0], args[1])?; let dest = dest.unwrap(); let n = this.truncate(n, dest.layout); this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; @@ -65,4 +47,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Otherwise, load the MIR. Ok(Some(this.load_mir(instance.def, None)?)) } + + fn align_offset( + &mut self, + ptr_op: OpTy<'tcx, Tag>, + align_op: OpTy<'tcx, Tag> + ) -> InterpResult<'tcx, u128> { + let this = self.eval_context_mut(); + + let req_align = this.force_bits( + this.read_scalar(align_op)?.not_undef()?, + this.pointer_size() + )? as usize; + + let ptr_scalar = this.read_scalar(ptr_op)?.not_undef()?; + + if let Scalar::Ptr(ptr) = ptr_scalar { + let cur_align = this.memory().get(ptr.alloc_id)?.align.bytes() as usize; + if cur_align < req_align { + return Ok(u128::max_value()); + } + } + + // if the allocation alignment is at least the required alignment or if the pointer is an + // integer, we use the libcore implementation + Ok( + (this.force_bits(ptr_scalar, this.pointer_size())? as *const i8) + .align_offset(req_align) as u128 + ) + } } From 497de53825728382dad498239b8dd8e871d26c45 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 17 Sep 2019 11:47:36 -0500 Subject: [PATCH 1113/5092] Update align_offset tests --- tests/run-pass/aligned_utf8_check.rs | 13 +++---------- tests/run-pass/aligned_utf8_check.stdout | 2 +- tests/run-pass/integer_align_offset.rs | 3 +++ 3 files changed, 7 insertions(+), 11 deletions(-) create mode 100644 tests/run-pass/integer_align_offset.rs diff --git a/tests/run-pass/aligned_utf8_check.rs b/tests/run-pass/aligned_utf8_check.rs index 202856b3bde9..6c6ff6b6173c 100644 --- a/tests/run-pass/aligned_utf8_check.rs +++ b/tests/run-pass/aligned_utf8_check.rs @@ -1,13 +1,6 @@ fn main() { const N: usize = 10; - - let x = vec![0x4141u16; N]; - - let mut y: Vec = unsafe { std::mem::transmute(x) }; - unsafe { y.set_len(2 * N) }; - - println!("{:?}", std::str::from_utf8(&y).unwrap()); - - let mut x: Vec = unsafe { std::mem::transmute(y) }; - unsafe { x.set_len(N) }; + let vec = vec![0x4141414141414141u64; N]; + let content = unsafe { std::slice::from_raw_parts(vec.as_ptr() as *const u8, 8 * N) }; + println!("{:?}", std::str::from_utf8(content).unwrap()); } diff --git a/tests/run-pass/aligned_utf8_check.stdout b/tests/run-pass/aligned_utf8_check.stdout index 8d08312cac7b..66d439948159 100644 --- a/tests/run-pass/aligned_utf8_check.stdout +++ b/tests/run-pass/aligned_utf8_check.stdout @@ -1 +1 @@ -"AAAAAAAAAAAAAAAAAAAA" +"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" diff --git a/tests/run-pass/integer_align_offset.rs b/tests/run-pass/integer_align_offset.rs new file mode 100644 index 000000000000..971c19b0576e --- /dev/null +++ b/tests/run-pass/integer_align_offset.rs @@ -0,0 +1,3 @@ +fn main() { + assert_eq!(2, (2 as *const i8).align_offset(4)); +} From 4a0b7446cf143f1ab4f2368623de25bc563fb2e3 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 17 Sep 2019 13:26:12 -0500 Subject: [PATCH 1114/5092] Move truncation from the main branch --- src/shims/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shims/mod.rs b/src/shims/mod.rs index f9b89cf553a3..eea23b6de4e6 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -27,9 +27,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // There are some more lang items we want to hook that CTFE does not hook (yet). if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { - let n = this.align_offset(args[0], args[1])?; let dest = dest.unwrap(); - let n = this.truncate(n, dest.layout); + let n = this.align_offset(args[0], args[1], dest.layout)?; this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; this.goto_block(ret)?; return Ok(None); @@ -51,7 +50,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn align_offset( &mut self, ptr_op: OpTy<'tcx, Tag>, - align_op: OpTy<'tcx, Tag> + align_op: OpTy<'tcx, Tag>, + layout: ty::layout::TyLayout<'tcx>, ) -> InterpResult<'tcx, u128> { let this = self.eval_context_mut(); @@ -65,7 +65,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Scalar::Ptr(ptr) = ptr_scalar { let cur_align = this.memory().get(ptr.alloc_id)?.align.bytes() as usize; if cur_align < req_align { - return Ok(u128::max_value()); + return Ok(this.truncate(u128::max_value(), layout)); } } From d610d9de9092d3607f68bb98bee671ca08edc3ca Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 18 Sep 2019 11:22:28 +0200 Subject: [PATCH 1115/5092] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 464b061edbd0..5081720aed44 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a44881d892fb4f4a8ed93f8f392bab942fac7a41 +64c09694a6ecc434cd3a61ade89beb1de17770c5 From 5cf90bc7866cd8f24178f2696e4fcbb7bfad0171 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 18 Sep 2019 16:10:13 -0500 Subject: [PATCH 1116/5092] Add getcwd shim --- src/shims/env.rs | 28 +++++++++++++++++++++++++++- src/shims/foreign_items.rs | 5 +++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 1cffc60bc40a..73627086e0b6 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::env; use rustc::ty::layout::{Size}; use rustc_mir::interpret::{Pointer, Memory}; @@ -21,7 +22,7 @@ impl EnvVars { excluded_env_vars.push("TERM".to_owned()); if ecx.machine.communicate { - for (name, value) in std::env::vars() { + for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { let var_ptr = alloc_env_var(name.as_bytes(), value.as_bytes(), ecx.memory_mut()); ecx.machine.env_vars.map.insert(name.into_bytes(), var_ptr); @@ -111,4 +112,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(-1) } } + + fn getcwd( + &mut self, + buf_op: OpTy<'tcx, Tag>, + size_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + let tcx = &{this.tcx.tcx}; + + let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; + let size = this.read_scalar(size_op)?.to_usize(&*this.tcx)?; + // If we cannot get the current directory, we return null + if let Ok(cwd) = env::current_dir() { + // It is not clear what happens with non-utf8 paths here + let mut bytes = cwd.display().to_string().into_bytes(); + // If the buffer is smaller than the path, we return null + if bytes.len() as u64 <= size { + // We need `size` bytes exactly + bytes.resize(size as usize, 0); + this.memory_mut().get_mut(buf.alloc_id)?.write_bytes(tcx, buf, &bytes)?; + return Ok(Scalar::Ptr(buf)) + } + } + Ok(Scalar::ptr_null(&*this.tcx)) + } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 90c18265fcf7..45f167bea582 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -436,6 +436,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "getcwd" => { + let result = this.getcwd(args[0], args[1])?; + this.write_scalar(result, dest)?; + } + "write" => { let fd = this.read_scalar(args[0])?.to_i32()?; let buf = this.read_scalar(args[1])?.not_undef()?; From 6593563e46d025aa0eb7a12a34085b7337b62c5b Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 18 Sep 2019 16:46:41 -0500 Subject: [PATCH 1117/5092] Check that getcwd does not error --- tests/run-pass/get_current_dir.rs | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 tests/run-pass/get_current_dir.rs diff --git a/tests/run-pass/get_current_dir.rs b/tests/run-pass/get_current_dir.rs new file mode 100644 index 000000000000..d8e6c225e965 --- /dev/null +++ b/tests/run-pass/get_current_dir.rs @@ -0,0 +1,5 @@ +// ignore-windows: TODO the windows hook is not done yet + +fn main() { + std::env::current_dir().unwrap(); +} From 133c2b39db73843e6a5ee0bce325cca034012579 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 19 Sep 2019 10:32:18 -0500 Subject: [PATCH 1118/5092] Only use getcwd without isolation --- src/shims/env.rs | 32 +++++++++++++++++-------------- tests/run-pass/get_current_dir.rs | 1 + 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 73627086e0b6..debeab894d45 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -119,22 +119,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let tcx = &{this.tcx.tcx}; - let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; - let size = this.read_scalar(size_op)?.to_usize(&*this.tcx)?; - // If we cannot get the current directory, we return null - if let Ok(cwd) = env::current_dir() { - // It is not clear what happens with non-utf8 paths here - let mut bytes = cwd.display().to_string().into_bytes(); - // If the buffer is smaller than the path, we return null - if bytes.len() as u64 <= size { - // We need `size` bytes exactly - bytes.resize(size as usize, 0); - this.memory_mut().get_mut(buf.alloc_id)?.write_bytes(tcx, buf, &bytes)?; - return Ok(Scalar::Ptr(buf)) + if this.machine.communicate { + let tcx = &{this.tcx.tcx}; + + let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; + let size = this.read_scalar(size_op)?.to_usize(&*this.tcx)?; + // If we cannot get the current directory, we return null + if let Ok(cwd) = env::current_dir() { + // It is not clear what happens with non-utf8 paths here + let mut bytes = cwd.display().to_string().into_bytes(); + // If the buffer is smaller than the path, we return null + if bytes.len() as u64 <= size { + // We need `size` bytes exactly + bytes.resize(size as usize, 0); + this.memory_mut().get_mut(buf.alloc_id)?.write_bytes(tcx, buf, &bytes)?; + return Ok(Scalar::Ptr(buf)) + } } + return Ok(Scalar::ptr_null(&*this.tcx)); } - Ok(Scalar::ptr_null(&*this.tcx)) + throw_unsup_format!("Function not available when isolation is enabled") } } diff --git a/tests/run-pass/get_current_dir.rs b/tests/run-pass/get_current_dir.rs index d8e6c225e965..45efd06d3f67 100644 --- a/tests/run-pass/get_current_dir.rs +++ b/tests/run-pass/get_current_dir.rs @@ -1,4 +1,5 @@ // ignore-windows: TODO the windows hook is not done yet +// compile-flags: -Zmiri-disable-isolation fn main() { std::env::current_dir().unwrap(); From 7e65c44714b3afe4ba2a1d70853c9cbbabbf74a0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 Aug 2019 15:10:11 +0200 Subject: [PATCH 1119/5092] test for niche enum discriminant computation that overflows --- tests/run-pass/enums.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/run-pass/enums.rs b/tests/run-pass/enums.rs index 1f27292904f4..73172d6bbd2f 100644 --- a/tests/run-pass/enums.rs +++ b/tests/run-pass/enums.rs @@ -23,6 +23,28 @@ fn test(me: MyEnum) { } } +fn discriminant_overflow() { + // Tests for https://github.com/rust-lang/rust/issues/62138. + #[repr(u8)] + #[allow(dead_code)] + enum WithWraparoundInvalidValues { + X = 1, + Y = 254, + } + + #[allow(dead_code)] + enum Foo { + A, + B, + C(WithWraparoundInvalidValues), + } + + let x = Foo::B; + if let Foo::C(_) = x { + panic!(); + } +} + fn main() { test(MyEnum::MyEmptyVariant); test(MyEnum::MyNewtypeVariant(42)); @@ -31,4 +53,6 @@ fn main() { my_first_field: 45, my_second_field: 46, }); + + discriminant_overflow(); } From d53d7f77a0edf8d74b0c2483b0aa5d65964a2889 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 Aug 2019 18:38:41 +0200 Subject: [PATCH 1120/5092] err on all-but-B, not just on C --- tests/run-pass/enums.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/enums.rs b/tests/run-pass/enums.rs index 73172d6bbd2f..dab3e873668b 100644 --- a/tests/run-pass/enums.rs +++ b/tests/run-pass/enums.rs @@ -40,8 +40,9 @@ fn discriminant_overflow() { } let x = Foo::B; - if let Foo::C(_) = x { - panic!(); + match x { + Foo::B => {}, + _ => panic!(), } } From 0ab0e40e1b15278c34b10d23603de98c3a27f1b2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 16 Sep 2019 15:04:42 +0200 Subject: [PATCH 1121/5092] add another test case --- tests/run-pass/enums.rs | 76 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/tests/run-pass/enums.rs b/tests/run-pass/enums.rs index dab3e873668b..39bf567076c4 100644 --- a/tests/run-pass/enums.rs +++ b/tests/run-pass/enums.rs @@ -46,6 +46,81 @@ fn discriminant_overflow() { } } +fn more_discriminant_overflow() { + pub enum Infallible {} + + // The check that the `bool` field of `V1` is encoding a "niche variant" + // (i.e. not `V1`, so `V3` or `V4`) used to be mathematically incorrect, + // causing valid `V1` values to be interpreted as other variants. + #[allow(dead_code)] + pub enum E1 { + V1 { f: bool }, + V2 { f: Infallible }, + V3, + V4, + } + + // Computing the discriminant used to be done using the niche type (here `u8`, + // from the `bool` field of `V1`), overflowing for variants with large enough + // indices (`V3` and `V4`), causing them to be interpreted as other variants. + #[allow(dead_code)] + pub enum E2 { + V1 { f: bool }, + + /*_00*/ _01(X), _02(X), _03(X), _04(X), _05(X), _06(X), _07(X), + _08(X), _09(X), _0A(X), _0B(X), _0C(X), _0D(X), _0E(X), _0F(X), + _10(X), _11(X), _12(X), _13(X), _14(X), _15(X), _16(X), _17(X), + _18(X), _19(X), _1A(X), _1B(X), _1C(X), _1D(X), _1E(X), _1F(X), + _20(X), _21(X), _22(X), _23(X), _24(X), _25(X), _26(X), _27(X), + _28(X), _29(X), _2A(X), _2B(X), _2C(X), _2D(X), _2E(X), _2F(X), + _30(X), _31(X), _32(X), _33(X), _34(X), _35(X), _36(X), _37(X), + _38(X), _39(X), _3A(X), _3B(X), _3C(X), _3D(X), _3E(X), _3F(X), + _40(X), _41(X), _42(X), _43(X), _44(X), _45(X), _46(X), _47(X), + _48(X), _49(X), _4A(X), _4B(X), _4C(X), _4D(X), _4E(X), _4F(X), + _50(X), _51(X), _52(X), _53(X), _54(X), _55(X), _56(X), _57(X), + _58(X), _59(X), _5A(X), _5B(X), _5C(X), _5D(X), _5E(X), _5F(X), + _60(X), _61(X), _62(X), _63(X), _64(X), _65(X), _66(X), _67(X), + _68(X), _69(X), _6A(X), _6B(X), _6C(X), _6D(X), _6E(X), _6F(X), + _70(X), _71(X), _72(X), _73(X), _74(X), _75(X), _76(X), _77(X), + _78(X), _79(X), _7A(X), _7B(X), _7C(X), _7D(X), _7E(X), _7F(X), + _80(X), _81(X), _82(X), _83(X), _84(X), _85(X), _86(X), _87(X), + _88(X), _89(X), _8A(X), _8B(X), _8C(X), _8D(X), _8E(X), _8F(X), + _90(X), _91(X), _92(X), _93(X), _94(X), _95(X), _96(X), _97(X), + _98(X), _99(X), _9A(X), _9B(X), _9C(X), _9D(X), _9E(X), _9F(X), + _A0(X), _A1(X), _A2(X), _A3(X), _A4(X), _A5(X), _A6(X), _A7(X), + _A8(X), _A9(X), _AA(X), _AB(X), _AC(X), _AD(X), _AE(X), _AF(X), + _B0(X), _B1(X), _B2(X), _B3(X), _B4(X), _B5(X), _B6(X), _B7(X), + _B8(X), _B9(X), _BA(X), _BB(X), _BC(X), _BD(X), _BE(X), _BF(X), + _C0(X), _C1(X), _C2(X), _C3(X), _C4(X), _C5(X), _C6(X), _C7(X), + _C8(X), _C9(X), _CA(X), _CB(X), _CC(X), _CD(X), _CE(X), _CF(X), + _D0(X), _D1(X), _D2(X), _D3(X), _D4(X), _D5(X), _D6(X), _D7(X), + _D8(X), _D9(X), _DA(X), _DB(X), _DC(X), _DD(X), _DE(X), _DF(X), + _E0(X), _E1(X), _E2(X), _E3(X), _E4(X), _E5(X), _E6(X), _E7(X), + _E8(X), _E9(X), _EA(X), _EB(X), _EC(X), _ED(X), _EE(X), _EF(X), + _F0(X), _F1(X), _F2(X), _F3(X), _F4(X), _F5(X), _F6(X), _F7(X), + _F8(X), _F9(X), _FA(X), _FB(X), _FC(X), _FD(X), _FE(X), _FF(X), + + V3, + V4, + } + + if let E1::V2 { .. } = (E1::V1 { f: true }) { + unreachable!() + } + if let E1::V1 { .. } = (E1::V1 { f: true }) { + } else { + unreachable!() + } + + if let E2::V1 { .. } = E2::V3:: { + unreachable!() + } + if let E2::V3 { .. } = E2::V3:: { + } else { + unreachable!() + } +} + fn main() { test(MyEnum::MyEmptyVariant); test(MyEnum::MyNewtypeVariant(42)); @@ -56,4 +131,5 @@ fn main() { }); discriminant_overflow(); + more_discriminant_overflow(); } From a86ca2452627d19289b076ea8f1762d6d7d77cd9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 20 Sep 2019 08:55:12 +0200 Subject: [PATCH 1122/5092] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 5081720aed44..60dae7291d63 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -64c09694a6ecc434cd3a61ade89beb1de17770c5 +ea3ba36f3f4b7f0168a27d23c499efeb2304e2d5 From 49275d42690318e410f65e3a38d04f2c4ccfbd0c Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 20 Sep 2019 02:13:48 -0500 Subject: [PATCH 1123/5092] Avoid writing more bytes than necessary --- src/shims/env.rs | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index debeab894d45..5e81b94e6997 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -120,25 +120,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - if this.machine.communicate { - let tcx = &{this.tcx.tcx}; - - let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; - let size = this.read_scalar(size_op)?.to_usize(&*this.tcx)?; - // If we cannot get the current directory, we return null - if let Ok(cwd) = env::current_dir() { - // It is not clear what happens with non-utf8 paths here - let mut bytes = cwd.display().to_string().into_bytes(); - // If the buffer is smaller than the path, we return null - if bytes.len() as u64 <= size { - // We need `size` bytes exactly - bytes.resize(size as usize, 0); - this.memory_mut().get_mut(buf.alloc_id)?.write_bytes(tcx, buf, &bytes)?; - return Ok(Scalar::Ptr(buf)) - } - } - return Ok(Scalar::ptr_null(&*this.tcx)); + if !this.machine.communicate { + throw_unsup_format!("Function not available when isolation is enabled") } - throw_unsup_format!("Function not available when isolation is enabled") + + let tcx = &{this.tcx.tcx}; + + let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; + let size = this.read_scalar(size_op)?.to_usize(&*this.tcx)?; + // If we cannot get the current directory, we return null + // FIXME: Technically we have to set the `errno` global too + if let Ok(cwd) = env::current_dir() { + // It is not clear what happens with non-utf8 paths here + let mut bytes = cwd.display().to_string().into_bytes(); + // If the buffer is smaller or equal than the path, we return null. + // FIXME: Technically we have to set the `errno` global too + if (bytes.len() as u64) < size { + // We add a `/0` terminator + bytes.push(0); + // This is ok because the buffer is larger than the path with the null terminator. + this.memory_mut().get_mut(buf.alloc_id)?.write_bytes(tcx, buf, &bytes)?; + return Ok(Scalar::Ptr(buf)) + } + } + Ok(Scalar::ptr_null(&*this.tcx)) } } From c0a6b5ff69580325e590d1062570be16c0a93f14 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 20 Sep 2019 03:30:55 -0500 Subject: [PATCH 1124/5092] Set errno when getcwd fails --- src/shims/env.rs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 5e81b94e6997..d766d8f0c1a6 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -130,18 +130,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let size = this.read_scalar(size_op)?.to_usize(&*this.tcx)?; // If we cannot get the current directory, we return null // FIXME: Technically we have to set the `errno` global too - if let Ok(cwd) = env::current_dir() { - // It is not clear what happens with non-utf8 paths here - let mut bytes = cwd.display().to_string().into_bytes(); - // If the buffer is smaller or equal than the path, we return null. - // FIXME: Technically we have to set the `errno` global too - if (bytes.len() as u64) < size { - // We add a `/0` terminator - bytes.push(0); - // This is ok because the buffer is larger than the path with the null terminator. - this.memory_mut().get_mut(buf.alloc_id)?.write_bytes(tcx, buf, &bytes)?; - return Ok(Scalar::Ptr(buf)) + match env::current_dir() { + Ok(cwd) =>{ + // It is not clear what happens with non-utf8 paths here + let mut bytes = cwd.display().to_string().into_bytes(); + // If the buffer is smaller or equal than the path, we return null. + if (bytes.len() as u64) < size { + // We add a `/0` terminator + bytes.push(0); + // This is ok because the buffer is larger than the path with the null terminator. + this.memory_mut().get_mut(buf.alloc_id)?.write_bytes(tcx, buf, &bytes)?; + return Ok(Scalar::Ptr(buf)) + } + this.machine.last_error = 34; // ERANGE } + Err(e) => this.machine.last_error = e.raw_os_error().unwrap() as u32, } Ok(Scalar::ptr_null(&*this.tcx)) } From 0f58289b3d799e04aa2b0027c4a7ff571c7a7511 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 20 Sep 2019 10:25:43 -0500 Subject: [PATCH 1125/5092] fetch ERANGE value from libc --- src/shims/env.rs | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index d766d8f0c1a6..784df0a50fb0 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,10 +1,10 @@ use std::collections::HashMap; use std::env; -use rustc::ty::layout::{Size}; -use rustc_mir::interpret::{Pointer, Memory}; use crate::stacked_borrows::Tag; use crate::*; +use rustc::ty::layout::Size; +use rustc_mir::interpret::{Memory, Pointer}; #[derive(Default)] pub struct EnvVars { @@ -24,7 +24,8 @@ impl EnvVars { if ecx.machine.communicate { for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { - let var_ptr = alloc_env_var(name.as_bytes(), value.as_bytes(), ecx.memory_mut()); + let var_ptr = + alloc_env_var(name.as_bytes(), value.as_bytes(), ecx.memory_mut()); ecx.machine.env_vars.map.insert(name.into_bytes(), var_ptr); } } @@ -46,17 +47,16 @@ fn alloc_env_var<'mir, 'tcx>( impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn getenv( - &mut self, - name_op: OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, Scalar> { + fn getenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let name_ptr = this.read_scalar(name_op)?.not_undef()?; let name = this.memory().read_c_str(name_ptr)?; Ok(match this.machine.env_vars.map.get(name) { // The offset is used to strip the "{name}=" part of the string. - Some(var_ptr) => Scalar::Ptr(var_ptr.offset(Size::from_bytes(name.len() as u64 + 1), this)?), + Some(var_ptr) => { + Scalar::Ptr(var_ptr.offset(Size::from_bytes(name.len() as u64 + 1), this)?) + } None => Scalar::ptr_null(&*this.tcx), }) } @@ -81,7 +81,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some((name, value)) = new { let var_ptr = alloc_env_var(&name, &value, this.memory_mut()); if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), var_ptr) { - this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; + this.memory_mut() + .deallocate(var, None, MiriMemoryKind::Env.into())?; } Ok(0) } else { @@ -89,10 +90,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn unsetenv( - &mut self, - name_op: OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, i32> { + fn unsetenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let name_ptr = this.read_scalar(name_op)?.not_undef()?; @@ -105,7 +103,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } if let Some(old) = success { if let Some(var) = old { - this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; + this.memory_mut() + .deallocate(var, None, MiriMemoryKind::Env.into())?; } Ok(0) } else { @@ -124,14 +123,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("Function not available when isolation is enabled") } - let tcx = &{this.tcx.tcx}; + let tcx = &{ this.tcx.tcx }; let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; let size = this.read_scalar(size_op)?.to_usize(&*this.tcx)?; // If we cannot get the current directory, we return null // FIXME: Technically we have to set the `errno` global too match env::current_dir() { - Ok(cwd) =>{ + Ok(cwd) => { // It is not clear what happens with non-utf8 paths here let mut bytes = cwd.display().to_string().into_bytes(); // If the buffer is smaller or equal than the path, we return null. @@ -139,10 +138,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We add a `/0` terminator bytes.push(0); // This is ok because the buffer is larger than the path with the null terminator. - this.memory_mut().get_mut(buf.alloc_id)?.write_bytes(tcx, buf, &bytes)?; - return Ok(Scalar::Ptr(buf)) + this.memory_mut() + .get_mut(buf.alloc_id)? + .write_bytes(tcx, buf, &bytes)?; + return Ok(Scalar::Ptr(buf)); } - this.machine.last_error = 34; // ERANGE + this.machine.last_error = this + .eval_path_scalar(&["libc", "ERANGE"])? + .unwrap() + .to_u32()?; } Err(e) => this.machine.last_error = e.raw_os_error().unwrap() as u32, } From f7366360383f6df430fb5dc7145f4ce8cab5f5e6 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 17 Sep 2019 13:42:04 -0500 Subject: [PATCH 1126/5092] Throw unsupported error when alignment is not a power of two --- src/shims/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/shims/mod.rs b/src/shims/mod.rs index eea23b6de4e6..0b5bd7ae5cf0 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -60,6 +60,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.pointer_size() )? as usize; + // FIXME: This should actually panic in the interpreted program + if !req_align.is_power_of_two() { + throw_unsup_format!("Required alignment should always be a power of two") + } + let ptr_scalar = this.read_scalar(ptr_op)?.not_undef()?; if let Scalar::Ptr(ptr) = ptr_scalar { From e2c54e64d141c8524ff9e4753f9b8acde3859351 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sun, 22 Sep 2019 21:39:17 -0500 Subject: [PATCH 1127/5092] Ignore integers --- src/shims/mod.rs | 42 +++++++++++++++----------- tests/run-pass/integer_align_offset.rs | 3 -- 2 files changed, 24 insertions(+), 21 deletions(-) delete mode 100644 tests/run-pass/integer_align_offset.rs diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 0b5bd7ae5cf0..4ccdbdc0d7c3 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -1,10 +1,10 @@ +pub mod dlsym; +pub mod env; pub mod foreign_items; pub mod intrinsics; pub mod tls; -pub mod dlsym; -pub mod env; -use rustc::{ty, mir}; +use rustc::{mir, ty}; use crate::*; @@ -18,7 +18,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ret: Option, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); - trace!("eval_fn_call: {:#?}, {:?}", instance, dest.map(|place| *place)); + trace!( + "eval_fn_call: {:#?}, {:?}", + instance, + dest.map(|place| *place) + ); // First, run the common hooks also supported by CTFE. if this.hook_fn(instance, args, dest)? { @@ -28,7 +32,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // There are some more lang items we want to hook that CTFE does not hook (yet). if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { let dest = dest.unwrap(); - let n = this.align_offset(args[0], args[1], dest.layout)?; + let n = this + .align_offset(args[0], args[1])? + .unwrap_or_else(|| this.truncate(u128::max_value(), dest.layout)); this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; this.goto_block(ret)?; return Ok(None); @@ -51,13 +57,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, ptr_op: OpTy<'tcx, Tag>, align_op: OpTy<'tcx, Tag>, - layout: ty::layout::TyLayout<'tcx>, - ) -> InterpResult<'tcx, u128> { + ) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); let req_align = this.force_bits( this.read_scalar(align_op)?.not_undef()?, - this.pointer_size() + this.pointer_size(), )? as usize; // FIXME: This should actually panic in the interpreted program @@ -67,18 +72,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr_scalar = this.read_scalar(ptr_op)?.not_undef()?; - if let Scalar::Ptr(ptr) = ptr_scalar { + if let Ok(ptr) = this.force_ptr(ptr_scalar) { let cur_align = this.memory().get(ptr.alloc_id)?.align.bytes() as usize; - if cur_align < req_align { - return Ok(this.truncate(u128::max_value(), layout)); + if cur_align >= req_align { + // if the allocation alignment is at least the required alignment we use the + // libcore implementation + return Ok(Some( + (this.force_bits(ptr_scalar, this.pointer_size())? as *const i8) + .align_offset(req_align) as u128, + )); } } - - // if the allocation alignment is at least the required alignment or if the pointer is an - // integer, we use the libcore implementation - Ok( - (this.force_bits(ptr_scalar, this.pointer_size())? as *const i8) - .align_offset(req_align) as u128 - ) + // If the allocation alignment is smaller than then required alignment or the pointer was + // actually an integer, we return `None` + Ok(None) } } diff --git a/tests/run-pass/integer_align_offset.rs b/tests/run-pass/integer_align_offset.rs deleted file mode 100644 index 971c19b0576e..000000000000 --- a/tests/run-pass/integer_align_offset.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - assert_eq!(2, (2 as *const i8).align_offset(4)); -} From 02261e4be2c5c8d569ac98f6d7c7623c6d26fe47 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 24 Sep 2019 09:29:16 -0500 Subject: [PATCH 1128/5092] Fix comments --- src/shims/env.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 784df0a50fb0..e2a9452045ea 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -120,7 +120,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); if !this.machine.communicate { - throw_unsup_format!("Function not available when isolation is enabled") + throw_unsup_format!("`getcwd` not available when isolation is enabled") } let tcx = &{ this.tcx.tcx }; @@ -128,7 +128,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; let size = this.read_scalar(size_op)?.to_usize(&*this.tcx)?; // If we cannot get the current directory, we return null - // FIXME: Technically we have to set the `errno` global too match env::current_dir() { Ok(cwd) => { // It is not clear what happens with non-utf8 paths here From 0eed5e64de4c7497785f5df7f2cf376d1e6afb91 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 24 Sep 2019 14:42:38 -0500 Subject: [PATCH 1129/5092] Add `chdir` shim --- src/shims/env.rs | 26 ++++++++++++++++++++++++++ src/shims/foreign_items.rs | 5 +++++ tests/run-pass/change_current_dir.rs | 14 ++++++++++++++ tests/run-pass/get_current_dir.rs | 6 ------ 4 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 tests/run-pass/change_current_dir.rs delete mode 100644 tests/run-pass/get_current_dir.rs diff --git a/src/shims/env.rs b/src/shims/env.rs index e2a9452045ea..074baa51f826 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; use std::env; +use std::path::Path; use crate::stacked_borrows::Tag; use crate::*; @@ -151,4 +152,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(Scalar::ptr_null(&*this.tcx)) } + + fn chdir(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + if !this.machine.communicate { + throw_unsup_format!("`chdir` not available when isolation is enabled") + } + + let path_bytes = this + .memory() + .read_c_str(this.read_scalar(path_op)?.not_undef()?)?; + + let path = Path::new( + std::str::from_utf8(path_bytes) + .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", path_bytes))?, + ); + + match env::set_current_dir(path) { + Ok(()) => Ok(0), + Err(e) => { + this.machine.last_error = e.raw_os_error().unwrap() as u32; + Ok(-1) + } + } + } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 45f167bea582..fedb6354b820 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -441,6 +441,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(result, dest)?; } + "chdir" => { + let result = this.chdir(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + "write" => { let fd = this.read_scalar(args[0])?.to_i32()?; let buf = this.read_scalar(args[1])?.not_undef()?; diff --git a/tests/run-pass/change_current_dir.rs b/tests/run-pass/change_current_dir.rs new file mode 100644 index 000000000000..fa8220339db0 --- /dev/null +++ b/tests/run-pass/change_current_dir.rs @@ -0,0 +1,14 @@ +// ignore-windows: TODO the windows hook is not done yet +// compile-flags: -Zmiri-disable-isolation +use std::env; +use std::path::Path; + +fn main() { + // test that `getcwd` is available + let cwd = env::current_dir().unwrap(); + let parent = cwd.parent().unwrap_or(&cwd); + // test that `chdir` is available + assert!(env::set_current_dir(&Path::new("..")).is_ok()); + // test that `..` goes to the parent directory + assert_eq!(env::current_dir().unwrap(), parent); +} diff --git a/tests/run-pass/get_current_dir.rs b/tests/run-pass/get_current_dir.rs deleted file mode 100644 index 45efd06d3f67..000000000000 --- a/tests/run-pass/get_current_dir.rs +++ /dev/null @@ -1,6 +0,0 @@ -// ignore-windows: TODO the windows hook is not done yet -// compile-flags: -Zmiri-disable-isolation - -fn main() { - std::env::current_dir().unwrap(); -} From 145a5826d5cc02b15723bb9acb6739abdac28409 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 24 Sep 2019 15:53:14 -0500 Subject: [PATCH 1130/5092] Check that `chdir` fails for non-utf8 paths --- tests/compile-fail/chdir_invalid_path.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/compile-fail/chdir_invalid_path.rs diff --git a/tests/compile-fail/chdir_invalid_path.rs b/tests/compile-fail/chdir_invalid_path.rs new file mode 100644 index 000000000000..22b0d723aad8 --- /dev/null +++ b/tests/compile-fail/chdir_invalid_path.rs @@ -0,0 +1,11 @@ +// compile-flags: -Zmiri-disable-isolation + +extern { + pub fn chdir(dir: *const u8) -> i32; +} + +fn main() { + let path = vec![0xc3u8, 0x28, 0]; + // test that `chdir` errors with invalid utf-8 path + unsafe { chdir(path.as_ptr()) }; //~ ERROR is not a valid utf-8 string +} From 79b1f91f45e3883e0946846cfd82aa4273c9809a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 24 Sep 2019 17:28:00 -0500 Subject: [PATCH 1131/5092] First version of file handling --- src/lib.rs | 1 + src/machine.rs | 3 + src/shims/foreign_items.rs | 20 ++++ src/shims/io.rs | 179 ++++++++++++++++++++++++++++++++++++ src/shims/mod.rs | 1 + tests/hello.txt | 1 + tests/run-pass/file_read.rs | 12 +++ 7 files changed, 217 insertions(+) create mode 100644 src/shims/io.rs create mode 100644 tests/hello.txt create mode 100644 tests/run-pass/file_read.rs diff --git a/src/lib.rs b/src/lib.rs index cea99d86eaa8..9f4e605b6c94 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,6 +34,7 @@ pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::dlsym::{Dlsym, EvalContextExt as DlsymEvalContextExt}; pub use crate::shims::env::{EnvVars, EvalContextExt as EnvEvalContextExt}; +pub use crate::shims::io::{FileHandler, EvalContextExt as FileEvalContextExt}; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; diff --git a/src/machine.rs b/src/machine.rs index 340dd109e124..19be5b547ba8 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -96,6 +96,8 @@ pub struct Evaluator<'tcx> { /// If enabled, the `env_vars` field is populated with the host env vars during initialization /// and random number generation is delegated to the host. pub(crate) communicate: bool, + + pub(crate) file_handler: FileHandler, } impl<'tcx> Evaluator<'tcx> { @@ -110,6 +112,7 @@ impl<'tcx> Evaluator<'tcx> { last_error: 0, tls: TlsData::default(), communicate, + file_handler: Default::default(), } } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index fedb6354b820..f717d7959f04 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -446,6 +446,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "open" | "open64" => { + let result = this.open(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "fcntl" => { + let result = this.fcntl(args[0], args[1], args.get(2).cloned())?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "close" => { + let result = this.close(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "read" => { + let result = this.read(args[0], args[1], args[2])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + "write" => { let fd = this.read_scalar(args[0])?.to_i32()?; let buf = this.read_scalar(args[1])?.not_undef()?; diff --git a/src/shims/io.rs b/src/shims/io.rs new file mode 100644 index 000000000000..02e5133c9a08 --- /dev/null +++ b/src/shims/io.rs @@ -0,0 +1,179 @@ +use std::collections::HashMap; +use std::fs::File; +use std::io::Read; + +use crate::stacked_borrows::Tag; +use crate::*; + +#[derive(Default)] +pub struct FileHandler { + files: HashMap, + flags: HashMap, + low: i32, +} + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn open( + &mut self, + path_op: OpTy<'tcx, Tag>, + flag_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + if !this.machine.communicate { + throw_unsup_format!("`open` not available when isolation is enabled") + } + + let flag = this.read_scalar(flag_op)?.to_i32()?; + + if flag + != this + .eval_path_scalar(&["libc", "O_RDONLY"])? + .unwrap() + .to_i32()? + && flag + != this + .eval_path_scalar(&["libc", "O_CLOEXEC"])? + .unwrap() + .to_i32()? + { + throw_unsup_format!("Unsupported flag {:#x}", flag); + } + + let path_bytes = this + .memory() + .read_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = std::str::from_utf8(path_bytes) + .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", path_bytes))?; + + match File::open(path) { + Ok(file) => { + let mut fh = &mut this.machine.file_handler; + fh.low += 1; + fh.files.insert(fh.low, file); + fh.flags.insert(fh.low, flag); + Ok(fh.low) + } + + Err(e) => { + this.machine.last_error = e.raw_os_error().unwrap() as u32; + Ok(-1) + } + } + } + + fn fcntl( + &mut self, + fd_op: OpTy<'tcx, Tag>, + cmd_op: OpTy<'tcx, Tag>, + arg_op: Option>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + if !this.machine.communicate { + throw_unsup_format!("`open` not available when isolation is enabled") + } + + let fd = this.read_scalar(fd_op)?.to_i32()?; + let cmd = this.read_scalar(cmd_op)?.to_i32()?; + + if cmd + == this + .eval_path_scalar(&["libc", "F_SETFD"])? + .unwrap() + .to_i32()? + { + let flag = this.read_scalar(arg_op.unwrap())?.to_i32()?; + this.machine.file_handler.flags.insert(fd, flag); + Ok(0) + } else if cmd + == this + .eval_path_scalar(&["libc", "F_GETFD"])? + .unwrap() + .to_i32()? + { + if let Some(flag) = this.machine.file_handler.flags.get(&fd) { + Ok(*flag) + } else { + this.machine.last_error = this + .eval_path_scalar(&["libc", "EBADF"])? + .unwrap() + .to_u32()?; + Ok(-1) + } + } else { + throw_unsup_format!("Unsupported command {:#x}", cmd); + } + } + + fn close(&mut self, fd_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + if !this.machine.communicate { + throw_unsup_format!("`open` not available when isolation is enabled") + } + + let fd = this.read_scalar(fd_op)?.to_i32()?; + + if let Some(file) = this.machine.file_handler.files.remove(&fd) { + match file.sync_all() { + Ok(()) => Ok(0), + Err(e) => { + this.machine.last_error = e.raw_os_error().unwrap() as u32; + Ok(-1) + } + } + } else { + this.machine.last_error = this + .eval_path_scalar(&["libc", "EBADF"])? + .unwrap() + .to_u32()?; + Ok(-1) + } + } + + fn read( + &mut self, + fd_op: OpTy<'tcx, Tag>, + buf_op: OpTy<'tcx, Tag>, + count_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i64> { + let this = self.eval_context_mut(); + + if !this.machine.communicate { + throw_unsup_format!("`open` not available when isolation is enabled") + } + + let tcx = &{ this.tcx.tcx }; + + let fd = this.read_scalar(fd_op)?.to_i32()?; + let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; + let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; + + if let Some(file) = this.machine.file_handler.files.get_mut(&fd) { + let mut bytes = vec![0; count as usize]; + match file.read(&mut bytes) { + Ok(read_bytes) => { + bytes.truncate(read_bytes); + + this.memory_mut() + .get_mut(buf.alloc_id)? + .write_bytes(tcx, buf, &bytes)?; + + Ok(read_bytes as i64) + } + Err(e) => { + this.machine.last_error = e.raw_os_error().unwrap() as u32; + Ok(-1) + } + } + } else { + this.machine.last_error = this + .eval_path_scalar(&["libc", "EBADF"])? + .unwrap() + .to_u32()?; + Ok(-1) + } + } +} diff --git a/src/shims/mod.rs b/src/shims/mod.rs index a0da364ff0b9..981185d252e7 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -3,6 +3,7 @@ pub mod intrinsics; pub mod tls; pub mod dlsym; pub mod env; +pub mod io; use rustc::{ty, mir}; diff --git a/tests/hello.txt b/tests/hello.txt new file mode 100644 index 000000000000..8ab686eafeb1 --- /dev/null +++ b/tests/hello.txt @@ -0,0 +1 @@ +Hello, World! diff --git a/tests/run-pass/file_read.rs b/tests/run-pass/file_read.rs new file mode 100644 index 000000000000..93c986393b02 --- /dev/null +++ b/tests/run-pass/file_read.rs @@ -0,0 +1,12 @@ +// ignore-windows: File handling is not implemented yet +// compile-flags: -Zmiri-disable-isolation + +use std::fs::File; +use std::io::Read; + +fn main() { + let mut file = File::open("./tests/hello.txt").unwrap(); + let mut contents = String::new(); + file.read_to_string(&mut contents).unwrap(); + assert_eq!("Hello, World!\n", contents); +} From 3726081857e3759ce7b7caeb836d6dce9f515227 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 25 Sep 2019 10:49:12 -0500 Subject: [PATCH 1132/5092] Add helper function to fetch `libc` constants --- src/shims/foreign_items.rs | 8 ++++++++ src/shims/io.rs | 41 ++++++-------------------------------- 2 files changed, 14 insertions(+), 35 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index f717d7959f04..2c0064976e3f 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -949,6 +949,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } return Ok(None); } + + fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { + self + .eval_context_mut() + .eval_path_scalar(&["libc", name])? + .ok_or_else(|| err_unsup_format!("Path libc::{} cannot be resolved.", name).into()) + .and_then(|scalar| scalar.to_i32()) + } } // Shims the linux 'getrandom()' syscall. diff --git a/src/shims/io.rs b/src/shims/io.rs index 02e5133c9a08..4b9af52962e7 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -27,17 +27,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let flag = this.read_scalar(flag_op)?.to_i32()?; - if flag - != this - .eval_path_scalar(&["libc", "O_RDONLY"])? - .unwrap() - .to_i32()? - && flag - != this - .eval_path_scalar(&["libc", "O_CLOEXEC"])? - .unwrap() - .to_i32()? - { + if flag != this.eval_libc_i32("O_RDONLY")? && flag != this.eval_libc_i32("O_CLOEXEC")? { throw_unsup_format!("Unsupported flag {:#x}", flag); } @@ -78,28 +68,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; let cmd = this.read_scalar(cmd_op)?.to_i32()?; - if cmd - == this - .eval_path_scalar(&["libc", "F_SETFD"])? - .unwrap() - .to_i32()? - { + if cmd == this.eval_libc_i32("F_SETFD")? { let flag = this.read_scalar(arg_op.unwrap())?.to_i32()?; this.machine.file_handler.flags.insert(fd, flag); Ok(0) - } else if cmd - == this - .eval_path_scalar(&["libc", "F_GETFD"])? - .unwrap() - .to_i32()? - { + } else if cmd == this.eval_libc_i32("F_GETFD")? { if let Some(flag) = this.machine.file_handler.flags.get(&fd) { Ok(*flag) } else { - this.machine.last_error = this - .eval_path_scalar(&["libc", "EBADF"])? - .unwrap() - .to_u32()?; + this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; Ok(-1) } } else { @@ -125,10 +102,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } else { - this.machine.last_error = this - .eval_path_scalar(&["libc", "EBADF"])? - .unwrap() - .to_u32()?; + this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; Ok(-1) } } @@ -169,10 +143,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } else { - this.machine.last_error = this - .eval_path_scalar(&["libc", "EBADF"])? - .unwrap() - .to_u32()?; + this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; Ok(-1) } } From 01f64616adbeb6162a6aecabbdf562810f14e20f Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 25 Sep 2019 11:11:20 -0500 Subject: [PATCH 1133/5092] Check that the only flag change is done to enable `FD_CLOEXEC` --- src/shims/io.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/shims/io.rs b/src/shims/io.rs index 4b9af52962e7..180748a07550 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -69,8 +69,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let cmd = this.read_scalar(cmd_op)?.to_i32()?; if cmd == this.eval_libc_i32("F_SETFD")? { + // This does not affect the file itself. Certain flags might require changing the file + // or the way it is accessed somehow. let flag = this.read_scalar(arg_op.unwrap())?.to_i32()?; - this.machine.file_handler.flags.insert(fd, flag); + // The only usage of this in stdlib at the moment is to enable the `FD_CLOEXEC` flag. + let fd_cloexec = this.eval_libc_i32("FD_CLOEXEC")?; + if let Some(old_flag) = this.machine.file_handler.flags.get_mut(&fd) { + if flag ^ *old_flag == fd_cloexec { + *old_flag = flag; + } else { + throw_unsup_format!("Unsupported arg {:#x} for `F_SETFD`", flag); + } + } Ok(0) } else if cmd == this.eval_libc_i32("F_GETFD")? { if let Some(flag) = this.machine.file_handler.flags.get(&fd) { From bdaa90ceb20a42405f9c7fee31133e70aab1bf7d Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 25 Sep 2019 11:12:46 -0500 Subject: [PATCH 1134/5092] Add FIXME to file reading test --- tests/run-pass/file_read.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-pass/file_read.rs b/tests/run-pass/file_read.rs index 93c986393b02..a60640d1b3c3 100644 --- a/tests/run-pass/file_read.rs +++ b/tests/run-pass/file_read.rs @@ -5,6 +5,7 @@ use std::fs::File; use std::io::Read; fn main() { + // FIXME: create the file and delete it when `rm` is implemented. let mut file = File::open("./tests/hello.txt").unwrap(); let mut contents = String::new(); file.read_to_string(&mut contents).unwrap(); From ca3a917a6fdc02caf40b5c466b8394be7f61f0d5 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 25 Sep 2019 11:16:11 -0500 Subject: [PATCH 1135/5092] Enable close call for macos --- src/shims/foreign_items.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 2c0064976e3f..b8609fd2ef09 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -456,7 +456,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "close" => { + "close" | "close$NOCANCEL" => { let result = this.close(args[0])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } From 20b10cc6d3419f50844a13fec2bc693b0194801d Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 26 Sep 2019 09:42:03 +0200 Subject: [PATCH 1136/5092] Update to latest nightly --- Cargo.toml | 2 +- rust-version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6e34d6c3d5d3..5a5c774169cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,5 +59,5 @@ cargo_miri = ["cargo_metadata", "directories", "rustc_version"] rustc_tests = [] [dev-dependencies] -compiletest_rs = { version = "0.3.22", features = ["tmp", "stable"] } +compiletest_rs = { version = "0.3.23", features = ["tmp"] } colored = "1.6" diff --git a/rust-version b/rust-version index 60dae7291d63..e4cfa76225a4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -ea3ba36f3f4b7f0168a27d23c499efeb2304e2d5 +a5bc0f0e3f0c58518c0537d82dee0fcfeb57115c From 9fdb347ad733dcd40eaab34ebb3143a1c6060206 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 26 Sep 2019 11:40:13 +0200 Subject: [PATCH 1137/5092] Rustup to `sty` -> `kind` changes --- rust-version | 2 +- src/helpers.rs | 2 +- src/stacked_borrows.rs | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index e4cfa76225a4..e8bca6ea63b5 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a5bc0f0e3f0c58518c0537d82dee0fcfeb57115c +dc45735f29788924b9fc351d100e5bf3ebdca162 diff --git a/src/helpers.rs b/src/helpers.rs index ad30040c2ddc..3bee028c5eb7 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -211,7 +211,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn visit_value(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty); - let is_unsafe_cell = match v.layout.ty.sty { + let is_unsafe_cell = match v.layout.ty.kind { ty::Adt(adt, _) => Some(adt.did) == self.ecx.tcx.lang_items().unsafe_cell_type(), _ => false, }; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 01ed6ec225d2..5258cbb5485b 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -435,7 +435,7 @@ impl<'tcx> Stacks { Stacks { stacks: RefCell::new(RangeMap::new(size, stack)), - global: extra, + global: extra, } } @@ -460,7 +460,7 @@ impl Stacks { pub fn new_allocation( id: AllocId, size: Size, - extra: MemoryExtra, + extra: MemoryExtra, kind: MemoryKind, ) -> (Self, Tag) { let (tag, perm) = match kind { @@ -616,7 +616,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Cannot use `builtin_deref` because that reports *immutable* for `Box`, // making it useless. fn qualify(ty: ty::Ty<'_>, kind: RetagKind) -> Option<(RefKind, bool)> { - match ty.sty { + match ty.kind { // References are simple. ty::Ref(_, _, MutMutable) => Some((RefKind::Unique { two_phase: kind == RetagKind::TwoPhase}, kind == RetagKind::FnEntry)), From 9f6287eb0cbb0524ce503010d50a25e1e4ecb4a3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 27 Sep 2019 10:23:26 -0400 Subject: [PATCH 1138/5092] show cargo version --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 269dc28ca021..e053c062ff99 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,6 +39,7 @@ before_script: - travis_retry rustup-toolchain-install-master -f -n master $RUSTC_HASH -c rust-src - rustup default master - rustc --version +- cargo --version script: - ./travis.sh From c424e069932d632e08856739e2811764d4d7020c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 27 Sep 2019 10:54:39 -0400 Subject: [PATCH 1139/5092] make sure we use the stable toolchain, no matter the cache --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index e053c062ff99..446fab794110 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,6 +33,8 @@ before_script: # Install Rust ("stable" toolchain for better caching, it is just used to build rustup-toolchain-install-master) - curl https://build.travis-ci.org/files/rustup-init.sh -sSf | sh -s -- -y --default-toolchain stable - export PATH=$HOME/.cargo/bin:$PATH +- rustup default stable +- rustup uninstall beta - rustup update # Install "master" toolchain - cargo install rustup-toolchain-install-master || echo "rustup-toolchain-install-master already installed" From 28e814ab537606d3d9cd2235198c2c5f658206bf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Sep 2019 10:37:48 -0400 Subject: [PATCH 1140/5092] rustup --- rust-version | 2 +- src/eval.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index e8bca6ea63b5..08d4c1dc2342 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -dc45735f29788924b9fc351d100e5bf3ebdca162 +084beb83e0e87d673d5fabc844d28e8e8ae2ab4c diff --git a/src/eval.rs b/src/eval.rs index 667491f8d477..1b7c082ec37b 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -63,7 +63,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ty::ParamEnv::reveal_all(), start_id, ecx.tcx.mk_substs( - ::std::iter::once(ty::subst::Kind::from(main_ret_ty))) + ::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))) ).unwrap(); let start_mir = ecx.load_mir(start_instance.def, None)?; From 63ea13ad0dc30769c674ea52172cafe4e0178bb1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Sep 2019 11:00:05 -0400 Subject: [PATCH 1141/5092] fix miri-rustc-tests --- src/bin/miri-rustc-tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 3b4ad8415917..5f814fd19862 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -46,7 +46,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { struct Visitor<'tcx>(TyCtxt<'tcx>); impl<'tcx, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { - if let hir::ItemKind::Fn(.., body_id) = i.node { + if let hir::ItemKind::Fn(.., body_id) = i.kind { if i.attrs.iter().any(|attr| attr.check_name(syntax::symbol::sym::test)) { let config = MiriConfig { validate: true, From 638d989629675288207fa2031a1fca531a9eaf9e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Sep 2019 11:36:20 -0400 Subject: [PATCH 1142/5092] sync AppVeyor CI script with Travis --- .appveyor.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 391ff042daf4..c3d575403cb3 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -17,16 +17,21 @@ cache: - '%USERPROFILE%\.rustup' install: + # Compute the rust version we use + - set /p RUSTC_HASH= Date: Sat, 28 Sep 2019 12:10:18 -0400 Subject: [PATCH 1143/5092] cargo update for test-cargo-miri --- test-cargo-miri/Cargo.lock | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 2a6a32a18f04..70476fbdcb06 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -25,22 +25,22 @@ version = "0.1.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cfg-if" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "getrandom" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -68,13 +68,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rand" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_pcg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -85,15 +85,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_core" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -101,7 +101,7 @@ name = "rand_hc" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -110,27 +110,27 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasi" -version = "0.5.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" -"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" -"checksum getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "fc344b02d3868feb131e8b5fe2b9b0a1cc42942679af493061fc13b853243872" +"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" "checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" -"checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" +"checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" -"checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" +"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum rand_pcg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e196346cbbc5c70c77e7b4926147ee8e383a38ee4d15d58a08098b169e492b6" -"checksum wasi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd5442abcac6525a045cc8c795aedb60da7a2e5e89c7bf18a0d5357849bb23c7" +"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" From 8ecd767791a67c15b07087b060d0387f1d36ad21 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 Sep 2019 11:30:28 -0400 Subject: [PATCH 1144/5092] fix test failure from diagnostics change --- rust-version | 2 +- tests/compile-fail/overflowing-rsh-1.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 08d4c1dc2342..77a1658e248b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -084beb83e0e87d673d5fabc844d28e8e8ae2ab4c +488381ce9ef0ceabe83b73127c659e5d38137df0 diff --git a/tests/compile-fail/overflowing-rsh-1.rs b/tests/compile-fail/overflowing-rsh-1.rs index 7a4646a0ebf3..e0d3f1904a23 100644 --- a/tests/compile-fail/overflowing-rsh-1.rs +++ b/tests/compile-fail/overflowing-rsh-1.rs @@ -1,4 +1,4 @@ -#![allow(exceeding_bitshifts)] +#![allow(exceeding_bitshifts, const_err)] fn main() { let _n = 1i64 >> 64; //~ ERROR attempt to shift right with overflow From 9650b7868e64971f6a154c87ddd13e9cc33f1589 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 Sep 2019 11:43:50 -0400 Subject: [PATCH 1145/5092] more align_offset tests --- tests/run-pass/align_offset.rs | 70 +++++++++++++++++++ ..._utf8_check.stdout => align_offset.stdout} | 0 tests/run-pass/aligned_utf8_check.rs | 6 -- 3 files changed, 70 insertions(+), 6 deletions(-) create mode 100644 tests/run-pass/align_offset.rs rename tests/run-pass/{aligned_utf8_check.stdout => align_offset.stdout} (100%) delete mode 100644 tests/run-pass/aligned_utf8_check.rs diff --git a/tests/run-pass/align_offset.rs b/tests/run-pass/align_offset.rs new file mode 100644 index 000000000000..f3464a012f02 --- /dev/null +++ b/tests/run-pass/align_offset.rs @@ -0,0 +1,70 @@ +fn test_align_offset() { + let d = Box::new([0u32; 4]); + // Get u8 pointer to base + let raw = d.as_ptr() as *const u8; + + assert_eq!(raw.align_offset(2), 0); + assert_eq!(raw.align_offset(4), 0); + assert_eq!(raw.align_offset(8), usize::max_value()); + + assert_eq!(raw.wrapping_offset(1).align_offset(2), 1); + assert_eq!(raw.wrapping_offset(1).align_offset(4), 3); + assert_eq!(raw.wrapping_offset(1).align_offset(8), usize::max_value()); + + assert_eq!(raw.wrapping_offset(2).align_offset(2), 0); + assert_eq!(raw.wrapping_offset(2).align_offset(4), 2); + assert_eq!(raw.wrapping_offset(2).align_offset(8), usize::max_value()); +} + +fn test_align_to() { + const N: usize = 4; + let d = Box::new([0u32; N]); + // Get u8 slice covering the entire thing + let s = unsafe { std::slice::from_raw_parts(d.as_ptr() as *const u8, 4 * N) }; + let raw = s.as_ptr(); + + { + let (l, m, r) = unsafe { s.align_to::() }; + assert_eq!(l.len(), 0); + assert_eq!(r.len(), 0); + assert_eq!(m.len(), N); + assert_eq!(raw, m.as_ptr() as *const u8); + } + + { + let (l, m, r) = unsafe { s[1..].align_to::() }; + assert_eq!(l.len(), 3); + assert_eq!(m.len(), N-1); + assert_eq!(r.len(), 0); + assert_eq!(raw.wrapping_offset(4), m.as_ptr() as *const u8); + } + + { + let (l, m, r) = unsafe { s[..4*N - 1].align_to::() }; + assert_eq!(l.len(), 0); + assert_eq!(m.len(), N-1); + assert_eq!(r.len(), 3); + assert_eq!(raw, m.as_ptr() as *const u8); + } + + { + let (l, m, r) = unsafe { s[1..4*N - 1].align_to::() }; + assert_eq!(l.len(), 3); + assert_eq!(m.len(), N-2); + assert_eq!(r.len(), 3); + assert_eq!(raw.wrapping_offset(4), m.as_ptr() as *const u8); + } +} + +fn test_from_utf8() { + const N: usize = 10; + let vec = vec![0x4141414141414141u64; N]; + let content = unsafe { std::slice::from_raw_parts(vec.as_ptr() as *const u8, 8 * N) }; + println!("{:?}", std::str::from_utf8(content).unwrap()); +} + +fn main() { + test_align_offset(); + test_align_to(); + test_from_utf8(); +} diff --git a/tests/run-pass/aligned_utf8_check.stdout b/tests/run-pass/align_offset.stdout similarity index 100% rename from tests/run-pass/aligned_utf8_check.stdout rename to tests/run-pass/align_offset.stdout diff --git a/tests/run-pass/aligned_utf8_check.rs b/tests/run-pass/aligned_utf8_check.rs deleted file mode 100644 index 6c6ff6b6173c..000000000000 --- a/tests/run-pass/aligned_utf8_check.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn main() { - const N: usize = 10; - let vec = vec![0x4141414141414141u64; N]; - let content = unsafe { std::slice::from_raw_parts(vec.as_ptr() as *const u8, 8 * N) }; - println!("{:?}", std::str::from_utf8(content).unwrap()); -} From b5d449949a5833d2ea3484d840b704a731bac516 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 Sep 2019 11:49:04 -0400 Subject: [PATCH 1146/5092] comments and another test --- tests/run-pass/align_offset.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tests/run-pass/align_offset.rs b/tests/run-pass/align_offset.rs index f3464a012f02..8388089b8f44 100644 --- a/tests/run-pass/align_offset.rs +++ b/tests/run-pass/align_offset.rs @@ -5,15 +5,15 @@ fn test_align_offset() { assert_eq!(raw.align_offset(2), 0); assert_eq!(raw.align_offset(4), 0); - assert_eq!(raw.align_offset(8), usize::max_value()); + assert_eq!(raw.align_offset(8), usize::max_value()); // requested alignment higher than allocation alignment assert_eq!(raw.wrapping_offset(1).align_offset(2), 1); assert_eq!(raw.wrapping_offset(1).align_offset(4), 3); - assert_eq!(raw.wrapping_offset(1).align_offset(8), usize::max_value()); + assert_eq!(raw.wrapping_offset(1).align_offset(8), usize::max_value()); // requested alignment higher than allocation alignment assert_eq!(raw.wrapping_offset(2).align_offset(2), 0); assert_eq!(raw.wrapping_offset(2).align_offset(4), 2); - assert_eq!(raw.wrapping_offset(2).align_offset(8), usize::max_value()); + assert_eq!(raw.wrapping_offset(2).align_offset(8), usize::max_value()); // requested alignment higher than allocation alignment } fn test_align_to() { @@ -54,6 +54,13 @@ fn test_align_to() { assert_eq!(r.len(), 3); assert_eq!(raw.wrapping_offset(4), m.as_ptr() as *const u8); } + + { + let (l, m, r) = unsafe { s.align_to::() }; // requested alignment higher than allocation alignment + assert_eq!(l.len(), 4*N); + assert_eq!(r.len(), 0); + assert_eq!(m.len(), 0); + } } fn test_from_utf8() { From a9c207dce22340fbf2e31399bccbbafb7bfb2358 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 Sep 2019 12:26:13 -0400 Subject: [PATCH 1147/5092] fix tests on 32bit --- tests/run-pass/align_offset.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/align_offset.rs b/tests/run-pass/align_offset.rs index 8388089b8f44..736889174839 100644 --- a/tests/run-pass/align_offset.rs +++ b/tests/run-pass/align_offset.rs @@ -56,7 +56,8 @@ fn test_align_to() { } { - let (l, m, r) = unsafe { s.align_to::() }; // requested alignment higher than allocation alignment + #[repr(align(8))] struct Align8(u64); + let (l, m, r) = unsafe { s.align_to::() }; // requested alignment higher than allocation alignment assert_eq!(l.len(), 4*N); assert_eq!(r.len(), 0); assert_eq!(m.len(), 0); From 241b418125df8dee4d1524510432eea7ff50869e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 Sep 2019 12:31:04 -0400 Subject: [PATCH 1148/5092] bump rust even more --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 77a1658e248b..2d311cc17704 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -488381ce9ef0ceabe83b73127c659e5d38137df0 +d046ffddc4bd50e04ffc3ff9f766e2ac71f74d50 From 03ed4123c0b9ee265d713ba76b1b003d02c5bf3b Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 30 Sep 2019 11:51:09 -0500 Subject: [PATCH 1149/5092] Add FileHandle struct --- src/shims/io.rs | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/shims/io.rs b/src/shims/io.rs index 6f8785891c27..44acf45c9a53 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -5,17 +5,20 @@ use std::io::Read; use crate::stacked_borrows::Tag; use crate::*; +struct FileHandle { + file: File, + flag: i32, +} + pub struct FileHandler { - files: HashMap, - flags: HashMap, + handles: HashMap, low: i32, } impl Default for FileHandler { fn default() -> Self { FileHandler { - files: Default::default(), - flags: Default::default(), + handles: Default::default(), // 0, 1 and 2 are reserved for stdin, stdout and stderr low: 3, } @@ -51,8 +54,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(file) => { let mut fh = &mut this.machine.file_handler; fh.low += 1; - fh.files.insert(fh.low, file); - fh.flags.insert(fh.low, flag); + fh.handles.insert(fh.low, FileHandle{ file, flag}); Ok(fh.low) } @@ -84,7 +86,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let flag = this.read_scalar(arg_op.unwrap())?.to_i32()?; // The only usage of this in stdlib at the moment is to enable the `FD_CLOEXEC` flag. let fd_cloexec = this.eval_libc_i32("FD_CLOEXEC")?; - if let Some(old_flag) = this.machine.file_handler.flags.get_mut(&fd) { + if let Some(FileHandle{ flag: old_flag, .. }) = this.machine.file_handler.handles.get_mut(&fd) { if flag ^ *old_flag == fd_cloexec { *old_flag = flag; } else { @@ -93,8 +95,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(0) } else if cmd == this.eval_libc_i32("F_GETFD")? { - if let Some(flag) = this.machine.file_handler.flags.get(&fd) { - Ok(*flag) + if let Some(handle) = this.machine.file_handler.handles.get(&fd) { + Ok(handle.flag) } else { this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; Ok(-1) @@ -113,8 +115,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; - if let Some(file) = this.machine.file_handler.files.remove(&fd) { - match file.sync_all() { + if let Some(handle) = this.machine.file_handler.handles.remove(&fd) { + match handle.file.sync_all() { Ok(()) => Ok(0), Err(e) => { this.machine.last_error = e.raw_os_error().unwrap() as u32; @@ -145,7 +147,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; - if let Some(file) = this.machine.file_handler.files.get_mut(&fd) { + if let Some(FileHandle { file, ..}) = this.machine.file_handler.handles.get_mut(&fd) { let mut bytes = vec![0; count as usize]; match file.read(&mut bytes) { Ok(read_bytes) => { From 775246e3297ef49ae361a43fc5ce469f1cc26c96 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 30 Sep 2019 14:07:08 -0500 Subject: [PATCH 1150/5092] Add method to consume std::io::Result --- src/shims/io.rs | 71 +++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 38 deletions(-) diff --git a/src/shims/io.rs b/src/shims/io.rs index 44acf45c9a53..c75d3d5ea223 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -48,21 +48,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .memory() .read_c_str(this.read_scalar(path_op)?.not_undef()?)?; let path = std::str::from_utf8(path_bytes) - .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", path_bytes))?; + .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", path_bytes))? + .to_owned(); + let fd = File::open(&path).map(|file| { + let mut fh = &mut this.machine.file_handler; + fh.low += 1; + fh.handles.insert(fh.low, FileHandle{ file, flag}); + fh.low + }); - match File::open(path) { - Ok(file) => { - let mut fh = &mut this.machine.file_handler; - fh.low += 1; - fh.handles.insert(fh.low, FileHandle{ file, flag}); - Ok(fh.low) - } - - Err(e) => { - this.machine.last_error = e.raw_os_error().unwrap() as u32; - Ok(-1) - } - } + this.consume_result::(fd, -1) } fn fcntl( @@ -116,13 +111,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(handle) = this.machine.file_handler.handles.remove(&fd) { - match handle.file.sync_all() { - Ok(()) => Ok(0), - Err(e) => { - this.machine.last_error = e.raw_os_error().unwrap() as u32; - Ok(-1) - } - } + this.consume_result::(handle.file.sync_all().map(|_| 0), -1) } else { this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; Ok(-1) @@ -147,26 +136,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; - if let Some(FileHandle { file, ..}) = this.machine.file_handler.handles.get_mut(&fd) { - let mut bytes = vec![0; count as usize]; - match file.read(&mut bytes) { - Ok(read_bytes) => { - bytes.truncate(read_bytes); + let mut bytes = vec![0; count as usize]; - this.memory_mut() - .get_mut(buf.alloc_id)? - .write_bytes(tcx, buf, &bytes)?; - - Ok(read_bytes as i64) - } - Err(e) => { - this.machine.last_error = e.raw_os_error().unwrap() as u32; - Ok(-1) - } - } + let read_result = if let Some(FileHandle { file, ..}) = this.machine.file_handler.handles.get_mut(&fd) { + file.read(&mut bytes).map(|bytes| bytes as i64) } else { this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; - Ok(-1) + return Ok(-1); + }; + + let read_bytes = this.consume_result::(read_result, -1)?; + if read_bytes != -1 { + bytes.truncate(read_bytes as usize); + this.memory_mut() + .get_mut(buf.alloc_id)? + .write_bytes(tcx, buf, &bytes)?; + } + Ok(read_bytes) + } + + fn consume_result(&mut self, result: std::io::Result, t: T) -> InterpResult<'tcx, T> { + match result { + Ok(ok) => Ok(ok), + Err(e) => { + self.eval_context_mut().machine.last_error = e.raw_os_error().unwrap() as u32; + Ok(t) + } } } } From efbe798e626bee92cb7b2858b26ead38746b1960 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 30 Sep 2019 14:21:45 -0500 Subject: [PATCH 1151/5092] Avoid buffer allocation to read files --- src/shims/io.rs | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/shims/io.rs b/src/shims/io.rs index c75d3d5ea223..6b1952e8d66a 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -2,6 +2,8 @@ use std::collections::HashMap; use std::fs::File; use std::io::Read; +use rustc::ty::layout::Size; + use crate::stacked_borrows::Tag; use crate::*; @@ -53,7 +55,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = File::open(&path).map(|file| { let mut fh = &mut this.machine.file_handler; fh.low += 1; - fh.handles.insert(fh.low, FileHandle{ file, flag}); + fh.handles.insert(fh.low, FileHandle { file, flag }); fh.low }); @@ -81,7 +83,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let flag = this.read_scalar(arg_op.unwrap())?.to_i32()?; // The only usage of this in stdlib at the moment is to enable the `FD_CLOEXEC` flag. let fd_cloexec = this.eval_libc_i32("FD_CLOEXEC")?; - if let Some(FileHandle{ flag: old_flag, .. }) = this.machine.file_handler.handles.get_mut(&fd) { + if let Some(FileHandle { flag: old_flag, .. }) = + this.machine.file_handler.handles.get_mut(&fd) + { if flag ^ *old_flag == fd_cloexec { *old_flag = flag; } else { @@ -136,23 +140,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; - let mut bytes = vec![0; count as usize]; - - let read_result = if let Some(FileHandle { file, ..}) = this.machine.file_handler.handles.get_mut(&fd) { - file.read(&mut bytes).map(|bytes| bytes as i64) + // Remove the file handle to avoid borrowing issues + if let Some(mut handle) = this.machine.file_handler.handles.remove(&fd) { + let bytes = handle + .file + .read(this.memory_mut().get_mut(buf.alloc_id)?.get_bytes_mut( + tcx, + buf, + Size::from_bytes(count), + )?) + .map(|bytes| bytes as i64); + // Reinsert the file handle + this.machine.file_handler.handles.insert(fd, handle); + this.consume_result::(bytes, -1) } else { this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; - return Ok(-1); - }; - - let read_bytes = this.consume_result::(read_result, -1)?; - if read_bytes != -1 { - bytes.truncate(read_bytes as usize); - this.memory_mut() - .get_mut(buf.alloc_id)? - .write_bytes(tcx, buf, &bytes)?; + Ok(-1) } - Ok(read_bytes) } fn consume_result(&mut self, result: std::io::Result, t: T) -> InterpResult<'tcx, T> { From 644467c570314097f626868320bb4a9b2f769fc7 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 30 Sep 2019 15:18:23 -0500 Subject: [PATCH 1152/5092] Add methods to handle invalid fides --- src/shims/io.rs | 73 +++++++++++++++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 26 deletions(-) diff --git a/src/shims/io.rs b/src/shims/io.rs index 6b1952e8d66a..0cb2d7eeeabd 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -7,7 +7,7 @@ use rustc::ty::layout::Size; use crate::stacked_borrows::Tag; use crate::*; -struct FileHandle { +pub struct FileHandle { file: File, flag: i32, } @@ -94,12 +94,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(0) } else if cmd == this.eval_libc_i32("F_GETFD")? { - if let Some(handle) = this.machine.file_handler.handles.get(&fd) { - Ok(handle.flag) - } else { - this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; - Ok(-1) - } + this.get_handle_and(fd, |handle| Ok(handle.flag), -1) } else { throw_unsup_format!("Unsupported command {:#x}", cmd); } @@ -114,12 +109,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; - if let Some(handle) = this.machine.file_handler.handles.remove(&fd) { - this.consume_result::(handle.file.sync_all().map(|_| 0), -1) - } else { - this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; - Ok(-1) - } + this.remove_handle_and( + fd, + |handle, this| this.consume_result::(handle.file.sync_all().map(|_| 0), -1), + -1, + ) } fn read( @@ -141,21 +135,48 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; // Remove the file handle to avoid borrowing issues - if let Some(mut handle) = this.machine.file_handler.handles.remove(&fd) { - let bytes = handle - .file - .read(this.memory_mut().get_mut(buf.alloc_id)?.get_bytes_mut( - tcx, - buf, - Size::from_bytes(count), - )?) - .map(|bytes| bytes as i64); - // Reinsert the file handle - this.machine.file_handler.handles.insert(fd, handle); - this.consume_result::(bytes, -1) + this.remove_handle_and( + fd, + |mut handle, this| { + let bytes = handle + .file + .read(this.memory_mut().get_mut(buf.alloc_id)?.get_bytes_mut( + tcx, + buf, + Size::from_bytes(count), + )?) + .map(|bytes| bytes as i64); + // Reinsert the file handle + this.machine.file_handler.handles.insert(fd, handle); + this.consume_result::(bytes, -1) + }, + -1, + ) + } + + fn get_handle_and(&mut self, fd: i32, f: F, t: T) -> InterpResult<'tcx, T> + where + F: Fn(&FileHandle) -> InterpResult<'tcx, T>, + { + let this = self.eval_context_mut(); + if let Some(handle) = this.machine.file_handler.handles.get(&fd) { + f(handle) } else { this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; - Ok(-1) + Ok(t) + } + } + + fn remove_handle_and(&mut self, fd: i32, mut f: F, t: T) -> InterpResult<'tcx, T> + where + F: FnMut(FileHandle, &mut MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx, T>, + { + let this = self.eval_context_mut(); + if let Some(handle) = this.machine.file_handler.handles.remove(&fd) { + f(handle, this) + } else { + this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; + Ok(t) } } From 50be5a83c50528cc61d2b65a73839dbb25fc9c67 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 1 Oct 2019 09:18:55 -0500 Subject: [PATCH 1153/5092] Remove return argument when fd is not found --- src/shims/io.rs | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/shims/io.rs b/src/shims/io.rs index 0cb2d7eeeabd..c91d3a07726e 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -50,16 +50,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .memory() .read_c_str(this.read_scalar(path_op)?.not_undef()?)?; let path = std::str::from_utf8(path_bytes) - .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", path_bytes))? - .to_owned(); - let fd = File::open(&path).map(|file| { + .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", path_bytes))?; + let fd = File::open(path).map(|file| { let mut fh = &mut this.machine.file_handler; fh.low += 1; fh.handles.insert(fh.low, FileHandle { file, flag }); fh.low }); - this.consume_result::(fd, -1) + this.consume_result(fd) } fn fcntl( @@ -94,7 +93,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(0) } else if cmd == this.eval_libc_i32("F_GETFD")? { - this.get_handle_and(fd, |handle| Ok(handle.flag), -1) + this.get_handle_and(fd, |handle| Ok(handle.flag)) } else { throw_unsup_format!("Unsupported command {:#x}", cmd); } @@ -111,8 +110,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.remove_handle_and( fd, - |handle, this| this.consume_result::(handle.file.sync_all().map(|_| 0), -1), - -1, + |handle, this| this.consume_result(handle.file.sync_all().map(|_| 0i32)), ) } @@ -148,13 +146,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .map(|bytes| bytes as i64); // Reinsert the file handle this.machine.file_handler.handles.insert(fd, handle); - this.consume_result::(bytes, -1) + this.consume_result(bytes) }, - -1, ) } - fn get_handle_and(&mut self, fd: i32, f: F, t: T) -> InterpResult<'tcx, T> + fn get_handle_and>(&mut self, fd: i32, f: F) -> InterpResult<'tcx, T> where F: Fn(&FileHandle) -> InterpResult<'tcx, T>, { @@ -163,11 +160,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx f(handle) } else { this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; - Ok(t) + Ok((-1).into()) } } - fn remove_handle_and(&mut self, fd: i32, mut f: F, t: T) -> InterpResult<'tcx, T> + fn remove_handle_and>(&mut self, fd: i32, mut f: F) -> InterpResult<'tcx, T> where F: FnMut(FileHandle, &mut MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx, T>, { @@ -176,16 +173,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx f(handle, this) } else { this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; - Ok(t) + Ok((-1).into()) } } - fn consume_result(&mut self, result: std::io::Result, t: T) -> InterpResult<'tcx, T> { + fn consume_result>(&mut self, result: std::io::Result) -> InterpResult<'tcx, T> { match result { Ok(ok) => Ok(ok), Err(e) => { self.eval_context_mut().machine.last_error = e.raw_os_error().unwrap() as u32; - Ok(t) + Ok((-1).into()) } } } From d0509d719c27d95b5d0f8379d66f13b99b60c42e Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 1 Oct 2019 10:31:04 -0500 Subject: [PATCH 1154/5092] Add docs for helper functions --- src/shims/io.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/shims/io.rs b/src/shims/io.rs index c91d3a07726e..0d1adcce6526 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -151,6 +151,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) } + /// Helper function that gets a `FileHandle` immutable reference and allows to manipulate it + /// using `f`. + /// + /// If the `fd` file descriptor does not corresponds to a file, this functions returns `Ok(-1)` + /// and sets `Evaluator::last_error` to `libc::EBADF` (invalid file descriptor). + /// + /// This function uses `T: From` instead of `i32` directly because some IO related + /// functions return different integer types (like `read`, that returns an `i64`) fn get_handle_and>(&mut self, fd: i32, f: F) -> InterpResult<'tcx, T> where F: Fn(&FileHandle) -> InterpResult<'tcx, T>, @@ -164,6 +172,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + /// Helper function that removes a `FileHandle` and allows to manipulate it using the `f` + /// closure. This function is quite useful when you need to modify a `FileHandle` but you need + /// to modify `MiriEvalContext` at the same time, so you can modify the handle and reinsert it + /// using `f`. + /// + /// If the `fd` file descriptor does not corresponds to a file, this functions returns `Ok(-1)` + /// and sets `Evaluator::last_error` to `libc::EBADF` (invalid file descriptor). + /// + /// This function uses `T: From` instead of `i32` directly because some IO related + /// functions return different integer types (like `read`, that returns an `i64`) fn remove_handle_and>(&mut self, fd: i32, mut f: F) -> InterpResult<'tcx, T> where F: FnMut(FileHandle, &mut MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx, T>, @@ -177,6 +195,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + /// Helper function that consumes an `std::io::Result` and returns an + /// `InterpResult<'tcx,T>::Ok` instead. It is expected that the result can be converted to an + /// OS error using `std::io::Error::raw_os_error`. + /// + /// This function uses `T: From` instead of `i32` directly because some IO related + /// functions return different integer types (like `read`, that returns an `i64`) fn consume_result>(&mut self, result: std::io::Result) -> InterpResult<'tcx, T> { match result { Ok(ok) => Ok(ok), From cd495cb04f10eb2149f3a57bc0310af4c8c3ac3b Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 30 Sep 2019 11:46:07 -0500 Subject: [PATCH 1155/5092] Add file writing capabilities --- src/shims/foreign_items.rs | 4 +-- src/shims/io.rs | 62 +++++++++++++++++++++++++++++++++---- tests/hello.txt | 1 - tests/run-pass/file_read.rs | 10 ++++-- 4 files changed, 65 insertions(+), 12 deletions(-) delete mode 100644 tests/hello.txt diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index b8609fd2ef09..847169f38dca 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -494,9 +494,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Err(_) => -1, } } else { - eprintln!("Miri: Ignored output to FD {}", fd); - // Pretend it all went well. - n as i64 + this.write(args[0], args[1], args[2])? }; // Now, `result` is the value we return back to the program. this.write_scalar( diff --git a/src/shims/io.rs b/src/shims/io.rs index 0d1adcce6526..afb6e6311e72 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use std::fs::File; -use std::io::Read; +use std::fs::{ File, OpenOptions }; +use std::io::{ Read, Write }; use rustc::ty::layout::Size; @@ -42,8 +42,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let flag = this.read_scalar(flag_op)?.to_i32()?; - if flag != this.eval_libc_i32("O_RDONLY")? && flag != this.eval_libc_i32("O_CLOEXEC")? { - throw_unsup_format!("Unsupported flag {:#x}", flag); + let mut options = OpenOptions::new(); + + // The first two bits of the flag correspond to the access mode of the file in linux. + let access_mode = flag & 0b11; + + if access_mode == this.eval_libc_i32("O_RDONLY")? { + options.read(true); + } else if access_mode == this.eval_libc_i32("O_WRONLY")? { + options.write(true); + } else if access_mode == this.eval_libc_i32("O_RDWR")? { + options.read(true).write(true); + } else { + throw_unsup_format!("Unsupported access mode {:#x}", access_mode); + } + + if flag & this.eval_libc_i32("O_APPEND")? != 0 { + options.append(true); + } + if flag & this.eval_libc_i32("O_TRUNC")? != 0 { + options.truncate(true); + } + if flag & this.eval_libc_i32("O_CREAT")? != 0 { + options.create(true); } let path_bytes = this @@ -51,7 +72,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .read_c_str(this.read_scalar(path_op)?.not_undef()?)?; let path = std::str::from_utf8(path_bytes) .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", path_bytes))?; - let fd = File::open(path).map(|file| { + + let fd = options.open(path).map(|file| { let mut fh = &mut this.machine.file_handler; fh.low += 1; fh.handles.insert(fh.low, FileHandle { file, flag }); @@ -151,8 +173,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) } + fn write( + &mut self, + fd_op: OpTy<'tcx, Tag>, + buf_op: OpTy<'tcx, Tag>, + count_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i64> { + let this = self.eval_context_mut(); + + if !this.machine.communicate { + throw_unsup_format!("`write` not available when isolation is enabled") + } + + let tcx = &{ this.tcx.tcx }; + + let fd = this.read_scalar(fd_op)?.to_i32()?; + let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; + let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; + + // `to_vec` is needed to avoid borrowing issues when writing to the file. + let bytes = this.memory().get(buf.alloc_id)?.get_bytes(tcx, buf, Size::from_bytes(count))?.to_vec(); + + this.remove_handle_and(fd, |mut handle, this| { + let bytes = handle.file.write(&bytes).map(|bytes| bytes as i64); + this.machine.file_handler.handles.insert(fd, handle); + this.consume_result(bytes) + }) + } + /// Helper function that gets a `FileHandle` immutable reference and allows to manipulate it - /// using `f`. + /// using the `f` closure. /// /// If the `fd` file descriptor does not corresponds to a file, this functions returns `Ok(-1)` /// and sets `Evaluator::last_error` to `libc::EBADF` (invalid file descriptor). diff --git a/tests/hello.txt b/tests/hello.txt deleted file mode 100644 index 8ab686eafeb1..000000000000 --- a/tests/hello.txt +++ /dev/null @@ -1 +0,0 @@ -Hello, World! diff --git a/tests/run-pass/file_read.rs b/tests/run-pass/file_read.rs index a60640d1b3c3..b0f2618920bf 100644 --- a/tests/run-pass/file_read.rs +++ b/tests/run-pass/file_read.rs @@ -2,10 +2,16 @@ // compile-flags: -Zmiri-disable-isolation use std::fs::File; -use std::io::Read; +use std::io::{ Read, Write }; fn main() { - // FIXME: create the file and delete it when `rm` is implemented. + // FIXME: remove the file and delete it when `rm` is implemented. + + // Test creating, writing and closing a file (closing is tested when `file` is dropped). + let mut file = File::create("./tests/hello.txt").unwrap(); + file.write(b"Hello, World!\n").unwrap(); + + // Test opening, reading and closing a file. let mut file = File::open("./tests/hello.txt").unwrap(); let mut contents = String::new(); file.read_to_string(&mut contents).unwrap(); From 5a05c04c857538a60cd006455686124162f736dc Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 1 Oct 2019 10:57:12 -0500 Subject: [PATCH 1156/5092] Correct name of each shim when erroring --- src/shims/io.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/shims/io.rs b/src/shims/io.rs index afb6e6311e72..9f08141eb3b0 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -92,7 +92,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); if !this.machine.communicate { - throw_unsup_format!("`open` not available when isolation is enabled") + throw_unsup_format!("`fcntl` not available when isolation is enabled") } let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -125,7 +125,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); if !this.machine.communicate { - throw_unsup_format!("`open` not available when isolation is enabled") + throw_unsup_format!("`close` not available when isolation is enabled") } let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -145,7 +145,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); if !this.machine.communicate { - throw_unsup_format!("`open` not available when isolation is enabled") + throw_unsup_format!("`read` not available when isolation is enabled") } let tcx = &{ this.tcx.tcx }; @@ -204,7 +204,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function that gets a `FileHandle` immutable reference and allows to manipulate it /// using the `f` closure. /// - /// If the `fd` file descriptor does not corresponds to a file, this functions returns `Ok(-1)` + /// If the `fd` file descriptor does not correspond to a file, this functions returns `Ok(-1)` /// and sets `Evaluator::last_error` to `libc::EBADF` (invalid file descriptor). /// /// This function uses `T: From` instead of `i32` directly because some IO related @@ -227,7 +227,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// to modify `MiriEvalContext` at the same time, so you can modify the handle and reinsert it /// using `f`. /// - /// If the `fd` file descriptor does not corresponds to a file, this functions returns `Ok(-1)` + /// If the `fd` file descriptor does not correspond to a file, this functions returns `Ok(-1)` /// and sets `Evaluator::last_error` to `libc::EBADF` (invalid file descriptor). /// /// This function uses `T: From` instead of `i32` directly because some IO related From 78e0d309efe507afab2e71a2e3a0f8bec1cd4f1a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 1 Oct 2019 13:48:59 -0500 Subject: [PATCH 1157/5092] Avoid early return after handles are removed --- src/shims/io.rs | 55 ++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/src/shims/io.rs b/src/shims/io.rs index 9f08141eb3b0..49ad06e0dffc 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use std::fs::{ File, OpenOptions }; -use std::io::{ Read, Write }; +use std::fs::{File, OpenOptions}; +use std::io::{Read, Write}; use rustc::ty::layout::Size; @@ -130,10 +130,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; - this.remove_handle_and( - fd, - |handle, this| this.consume_result(handle.file.sync_all().map(|_| 0i32)), - ) + this.remove_handle_and(fd, |handle, this| { + this.consume_result(handle.file.sync_all().map(|_| 0i32)) + }) } fn read( @@ -155,22 +154,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; // Remove the file handle to avoid borrowing issues - this.remove_handle_and( - fd, - |mut handle, this| { - let bytes = handle - .file - .read(this.memory_mut().get_mut(buf.alloc_id)?.get_bytes_mut( - tcx, - buf, - Size::from_bytes(count), - )?) - .map(|bytes| bytes as i64); - // Reinsert the file handle - this.machine.file_handler.handles.insert(fd, handle); - this.consume_result(bytes) - }, - ) + this.remove_handle_and(fd, |mut handle, this| { + // Don't use `?` to avoid returning before reinserting the handle + let bytes = this + .memory_mut() + .get_mut(buf.alloc_id).and_then(|alloc| + alloc.get_bytes_mut(tcx, buf, Size::from_bytes(count)) + .map(|buffer| handle.file.read(buffer).map(|bytes| bytes as i64)) + ); + // Reinsert the file handle + this.machine.file_handler.handles.insert(fd, handle); + this.consume_result(bytes?) + }) } fn write( @@ -191,13 +186,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; - // `to_vec` is needed to avoid borrowing issues when writing to the file. - let bytes = this.memory().get(buf.alloc_id)?.get_bytes(tcx, buf, Size::from_bytes(count))?.to_vec(); - this.remove_handle_and(fd, |mut handle, this| { - let bytes = handle.file.write(&bytes).map(|bytes| bytes as i64); + let bytes = this.memory().get(buf.alloc_id).and_then(|alloc| { + alloc + .get_bytes(tcx, buf, Size::from_bytes(count)) + .map(|bytes| handle.file.write(bytes).map(|bytes| bytes as i64)) + }); this.machine.file_handler.handles.insert(fd, handle); - this.consume_result(bytes) + this.consume_result(bytes?) }) } @@ -251,7 +247,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// /// This function uses `T: From` instead of `i32` directly because some IO related /// functions return different integer types (like `read`, that returns an `i64`) - fn consume_result>(&mut self, result: std::io::Result) -> InterpResult<'tcx, T> { + fn consume_result>( + &mut self, + result: std::io::Result, + ) -> InterpResult<'tcx, T> { match result { Ok(ok) => Ok(ok), Err(e) => { From f5022b19d38777c72a308028663c7b6994d04648 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 2 Oct 2019 08:43:23 -0500 Subject: [PATCH 1158/5092] Fix dangling pointer bug for zero-sized reads --- src/shims/io.rs | 22 ++++++++++++++-------- tests/run-pass/file_read.rs | 20 ++++++++++++-------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/shims/io.rs b/src/shims/io.rs index 49ad06e0dffc..9d3e3d261625 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -150,21 +150,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tcx = &{ this.tcx.tcx }; let fd = this.read_scalar(fd_op)?.to_i32()?; - let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; + let buf_scalar = this.read_scalar(buf_op)?.not_undef()?; let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; // Remove the file handle to avoid borrowing issues this.remove_handle_and(fd, |mut handle, this| { // Don't use `?` to avoid returning before reinserting the handle - let bytes = this - .memory_mut() - .get_mut(buf.alloc_id).and_then(|alloc| - alloc.get_bytes_mut(tcx, buf, Size::from_bytes(count)) - .map(|buffer| handle.file.read(buffer).map(|bytes| bytes as i64)) - ); + let bytes = + if count == 0 { + Ok(handle.file.read(&mut [])) + } else { + this.force_ptr(buf_scalar).and_then(|buf| this + .memory_mut() + .get_mut(buf.alloc_id).and_then(|alloc| + alloc.get_bytes_mut(tcx, buf, Size::from_bytes(count)) + .map(|buffer| handle.file.read(buffer)) + )) + + }; // Reinsert the file handle this.machine.file_handler.handles.insert(fd, handle); - this.consume_result(bytes?) + this.consume_result(bytes?.map(|bytes| bytes as i64)) }) } diff --git a/tests/run-pass/file_read.rs b/tests/run-pass/file_read.rs index b0f2618920bf..a17f948980a9 100644 --- a/tests/run-pass/file_read.rs +++ b/tests/run-pass/file_read.rs @@ -6,14 +6,18 @@ use std::io::{ Read, Write }; fn main() { // FIXME: remove the file and delete it when `rm` is implemented. - + let path = "./tests/hello.txt"; + let bytes = b"Hello, World!\n"; // Test creating, writing and closing a file (closing is tested when `file` is dropped). - let mut file = File::create("./tests/hello.txt").unwrap(); - file.write(b"Hello, World!\n").unwrap(); - + let mut file = File::create(path).unwrap(); + file.write(bytes).unwrap(); // Test opening, reading and closing a file. - let mut file = File::open("./tests/hello.txt").unwrap(); - let mut contents = String::new(); - file.read_to_string(&mut contents).unwrap(); - assert_eq!("Hello, World!\n", contents); + let mut file = File::open(path).unwrap(); + let mut contents = Vec::new(); + // Reading 0 bytes should not fill `contents`. + file.read(&mut contents).unwrap(); + assert!(contents.is_empty()); + // Reading until EOF should get the whole text. + file.read_to_end(&mut contents).unwrap(); + assert_eq!(bytes, contents.as_slice()); } From 6c36a8c949a3e506b48481d746df85e6596d097d Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 2 Oct 2019 08:50:32 -0500 Subject: [PATCH 1159/5092] Return earlier when reading/writing 0 bytes --- src/shims/io.rs | 30 ++++++++++++++++-------------- tests/run-pass/file_read.rs | 10 ++++++---- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/shims/io.rs b/src/shims/io.rs index 9d3e3d261625..74b8dde5c7fc 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -149,25 +149,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tcx = &{ this.tcx.tcx }; + let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; + // Reading zero bytes should not change `buf` + if count == 0 { + return Ok(0); + } let fd = this.read_scalar(fd_op)?.to_i32()?; let buf_scalar = this.read_scalar(buf_op)?.not_undef()?; - let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; // Remove the file handle to avoid borrowing issues this.remove_handle_and(fd, |mut handle, this| { // Don't use `?` to avoid returning before reinserting the handle - let bytes = - if count == 0 { - Ok(handle.file.read(&mut [])) - } else { - this.force_ptr(buf_scalar).and_then(|buf| this - .memory_mut() - .get_mut(buf.alloc_id).and_then(|alloc| - alloc.get_bytes_mut(tcx, buf, Size::from_bytes(count)) - .map(|buffer| handle.file.read(buffer)) - )) - - }; + let bytes = this.force_ptr(buf_scalar).and_then(|buf| { + this.memory_mut() + .get_mut(buf.alloc_id)? + .get_bytes_mut(tcx, buf, Size::from_bytes(count)) + .map(|buffer| handle.file.read(buffer)) + }); // Reinsert the file handle this.machine.file_handler.handles.insert(fd, handle); this.consume_result(bytes?.map(|bytes| bytes as i64)) @@ -188,9 +186,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tcx = &{ this.tcx.tcx }; + let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; + // Writing zero bytes should not change `buf` + if count == 0 { + return Ok(0); + } let fd = this.read_scalar(fd_op)?.to_i32()?; let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; - let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; this.remove_handle_and(fd, |mut handle, this| { let bytes = this.memory().get(buf.alloc_id).and_then(|alloc| { diff --git a/tests/run-pass/file_read.rs b/tests/run-pass/file_read.rs index a17f948980a9..666abd65c12e 100644 --- a/tests/run-pass/file_read.rs +++ b/tests/run-pass/file_read.rs @@ -2,7 +2,7 @@ // compile-flags: -Zmiri-disable-isolation use std::fs::File; -use std::io::{ Read, Write }; +use std::io::{Read, Write}; fn main() { // FIXME: remove the file and delete it when `rm` is implemented. @@ -10,13 +10,15 @@ fn main() { let bytes = b"Hello, World!\n"; // Test creating, writing and closing a file (closing is tested when `file` is dropped). let mut file = File::create(path).unwrap(); + // Writing 0 bytes should not change the file contents. + file.write(&mut []).unwrap(); + file.write(bytes).unwrap(); // Test opening, reading and closing a file. let mut file = File::open(path).unwrap(); let mut contents = Vec::new(); - // Reading 0 bytes should not fill `contents`. - file.read(&mut contents).unwrap(); - assert!(contents.is_empty()); + // Reading 0 bytes should not move the file pointer. + file.read(&mut []).unwrap(); // Reading until EOF should get the whole text. file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); From 0c4003631d011ba569e49e6d1a63b90e92db3a49 Mon Sep 17 00:00:00 2001 From: Nicolas Date: Sat, 5 Oct 2019 06:12:37 -0300 Subject: [PATCH 1160/5092] Add missing atomic_fence intrinsics as nops Fixes #972 --- src/shims/intrinsics.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 06af6db76ae6..875a344363a0 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -88,7 +88,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(val, place.into())?; } - "atomic_fence_acq" => { + "atomic_fence_acq" | + "atomic_fence_rel" | + "atomic_fence_acqrel" | + "atomic_fence" => { // we are inherently singlethreaded and singlecored, this is a nop } From bd4a2996d1ac30e49adfcb241cb8a436730c35ac Mon Sep 17 00:00:00 2001 From: Nicolas Date: Sat, 5 Oct 2019 08:09:23 -0300 Subject: [PATCH 1161/5092] Add test for atomic fences --- tests/run-pass/atomic.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/atomic.rs b/tests/run-pass/atomic.rs index f0b8ec06b905..5872a496dbfa 100644 --- a/tests/run-pass/atomic.rs +++ b/tests/run-pass/atomic.rs @@ -1,9 +1,10 @@ -use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicU64, Ordering::*}; +use std::sync::atomic::{fence, AtomicBool, AtomicIsize, AtomicU64, Ordering::*}; fn main() { atomic_bool(); atomic_isize(); atomic_u64(); + atomic_fences(); } fn atomic_bool() { @@ -57,6 +58,15 @@ fn atomic_u64() { ATOMIC.store(1, SeqCst); assert_eq!(ATOMIC.compare_exchange(0, 0x100, AcqRel, Acquire), Err(1)); - assert_eq!(ATOMIC.compare_exchange_weak(1, 0x100, AcqRel, Acquire), Ok(1)); + assert_eq!( + ATOMIC.compare_exchange_weak(1, 0x100, AcqRel, Acquire), + Ok(1) + ); assert_eq!(ATOMIC.load(Relaxed), 0x100); } + +fn atomic_fences() { + fence(SeqCst); + fence(Release); + fence(Acquire); +} From 2b3b865c285dc090eb49d8e5ed93165a69c6c498 Mon Sep 17 00:00:00 2001 From: YOUNGSUK_KIM Date: Sat, 5 Oct 2019 17:11:09 -0400 Subject: [PATCH 1162/5092] change cargo-miri.rs to fix issue #978 --- src/bin/cargo-miri.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 43e8761d48c1..1f1705a49ac9 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -333,7 +333,14 @@ path = "lib.rs" None => true, Some(target) => target == rustc_version::version_meta().unwrap().host, }; - let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; + let mut sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; + if cfg!(target_os = "windows") { + // Replace backslashes in path to slashes as they cause problems. + // Win10 Powershell can work with slashes in paths. + sysroot = PathBuf::from( + String::from(sysroot.to_str().unwrap()).replace("\\", "/") + ); + } std::env::set_var("MIRI_SYSROOT", &sysroot); // pass the env var to the processes we spawn, which will turn it into "--sysroot" flags if print_env { println!("MIRI_SYSROOT={}", sysroot.display()); From 905c70cfa55a42af4f5e90a4e5cf0bebc307150c Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 7 Oct 2019 08:39:59 -0500 Subject: [PATCH 1163/5092] Rustfmt --- src/eval.rs | 64 ++++++---- src/machine.rs | 67 ++++++---- src/shims/foreign_items.rs | 246 ++++++++++++++++++++----------------- 3 files changed, 214 insertions(+), 163 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 1b7c082ec37b..21395cb311fa 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -3,16 +3,15 @@ use rand::rngs::StdRng; use rand::SeedableRng; -use syntax::source_map::DUMMY_SP; -use rustc::ty::{self, TyCtxt}; -use rustc::ty::layout::{LayoutOf, Size, Align}; use rustc::hir::def_id::DefId; +use rustc::ty::layout::{Align, LayoutOf, Size}; +use rustc::ty::{self, TyCtxt}; +use syntax::source_map::DUMMY_SP; use crate::{ - InterpResult, InterpError, InterpCx, StackPopCleanup, struct_error, - Scalar, Tag, Pointer, FnVal, - MemoryExtra, MiriMemoryKind, Evaluator, TlsEvalContextExt, HelpersEvalContextExt, - EnvVars, + struct_error, EnvVars, Evaluator, FnVal, HelpersEvalContextExt, InterpCx, InterpError, + InterpResult, MemoryExtra, MiriMemoryKind, Pointer, Scalar, StackPopCleanup, Tag, + TlsEvalContextExt, }; /// Configuration needed to spawn a Miri instance. @@ -40,7 +39,10 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), Evaluator::new(config.communicate), - MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate), + MemoryExtra::new( + StdRng::seed_from_u64(config.seed.unwrap_or(0)), + config.validate, + ), ); // Complete initialization. EnvVars::init(&mut ecx, config.excluded_env_vars); @@ -50,9 +52,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let main_mir = ecx.load_mir(main_instance.def, None)?; if !main_mir.return_ty().is_unit() || main_mir.arg_count != 0 { - throw_unsup_format!( - "miri does not support main functions without `fn()` type signatures" - ); + throw_unsup_format!("miri does not support main functions without `fn()` type signatures"); } let start_id = tcx.lang_items().start_fn().unwrap(); @@ -62,9 +62,10 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ecx.tcx.tcx, ty::ParamEnv::reveal_all(), start_id, - ecx.tcx.mk_substs( - ::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))) - ).unwrap(); + ecx.tcx + .mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))), + ) + .unwrap(); let start_mir = ecx.load_mir(start_instance.def, None)?; if start_mir.arg_count != 3 { @@ -91,7 +92,9 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let mut args = ecx.frame().body.args_iter(); // First argument: pointer to `main()`. - let main_ptr = ecx.memory_mut().create_fn_alloc(FnVal::Instance(main_instance)); + let main_ptr = ecx + .memory_mut() + .create_fn_alloc(FnVal::Instance(main_instance)); let dest = ecx.local_place(args.next().unwrap())?; ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?; @@ -124,16 +127,23 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Add `0` terminator. let mut arg = arg.into_bytes(); arg.push(0); - argvs.push(ecx.memory_mut().allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Static.into())); + argvs.push( + ecx.memory_mut() + .allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Static.into()), + ); } // Make an array with all these pointers, in the Miri memory. - let argvs_layout = ecx.layout_of(ecx.tcx.mk_array(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8), argvs.len() as u64))?; + let argvs_layout = ecx.layout_of( + ecx.tcx + .mk_array(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8), argvs.len() as u64), + )?; let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into()); for (idx, arg) in argvs.into_iter().enumerate() { let place = ecx.mplace_field(argvs_place, idx as u64)?; ecx.write_scalar(Scalar::Ptr(arg), place.into())?; } - ecx.memory_mut().mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?; + ecx.memory_mut() + .mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?; // Write a pointer to that place as the argument. let argv = argvs_place.ptr; ecx.write_scalar(argv, dest)?; @@ -145,7 +155,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } // Store command line as UTF-16 for Windows `GetCommandLineW`. { - let tcx = &{ecx.tcx.tcx}; + let tcx = &{ ecx.tcx.tcx }; let cmd_utf16: Vec = cmd.encode_utf16().collect(); let cmd_ptr = ecx.memory_mut().allocate( Size::from_bytes(cmd_utf16.len() as u64 * 2), @@ -168,16 +178,15 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } } - assert!(args.next().is_none(), "start lang item has more arguments than expected"); + assert!( + args.next().is_none(), + "start lang item has more arguments than expected" + ); Ok(ecx) } -pub fn eval_main<'tcx>( - tcx: TyCtxt<'tcx>, - main_id: DefId, - config: MiriConfig, -) { +pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) { let mut ecx = match create_ecx(tcx, main_id, config) { Ok(ecx) => ecx, Err(mut err) => { @@ -228,8 +237,9 @@ pub fn eval_main<'tcx>( // We iterate with indices because we need to look at the next frame (the caller). for idx in 0..frames.len() { let frame_info = &frames[idx]; - let call_site_is_local = frames.get(idx+1).map_or(false, - |caller_info| caller_info.instance.def_id().is_local()); + let call_site_is_local = frames.get(idx + 1).map_or(false, |caller_info| { + caller_info.instance.def_id().is_local() + }); if call_site_is_local { err.span_note(frame_info.call_site, &frame_info.to_string()); } else { diff --git a/src/machine.rs b/src/machine.rs index 19be5b547ba8..c8962612c658 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -1,24 +1,28 @@ //! Global machine state as well as implementation of the interpreter engine //! `Machine` trait. -use std::rc::Rc; use std::borrow::Cow; use std::cell::RefCell; +use std::rc::Rc; use rand::rngs::StdRng; +use rustc::hir::def_id::DefId; +use rustc::mir; +use rustc::ty::{ + self, + layout::{LayoutOf, Size}, + Ty, TyCtxt, +}; use syntax::attr; use syntax::symbol::sym; -use rustc::hir::def_id::DefId; -use rustc::ty::{self, Ty, TyCtxt, layout::{Size, LayoutOf}}; -use rustc::mir; use crate::*; // Some global facts about the emulated machine. -pub const PAGE_SIZE: u64 = 4*1024; // FIXME: adjust to target architecture -pub const STACK_ADDR: u64 = 32*PAGE_SIZE; // not really about the "stack", but where we start assigning integer addresses to allocations -pub const STACK_SIZE: u64 = 16*PAGE_SIZE; // whatever +pub const PAGE_SIZE: u64 = 4 * 1024; // FIXME: adjust to target architecture +pub const STACK_ADDR: u64 = 32 * PAGE_SIZE; // not really about the "stack", but where we start assigning integer addresses to allocations +pub const STACK_SIZE: u64 = 16 * PAGE_SIZE; // whatever pub const NUM_CPUS: u64 = 1; /// Extra memory kinds @@ -146,7 +150,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { type PointerTag = Tag; type ExtraFnVal = Dlsym; - type MemoryMap = MonoHashMap, Allocation)>; + type MemoryMap = MonoHashMap< + AllocId, + ( + MemoryKind, + Allocation, + ), + >; const STATIC_KIND: Option = Some(MiriMemoryKind::Static); @@ -264,8 +274,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } #[inline(always)] - fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> - { + fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { // We are not interested in detecting loops. Ok(()) } @@ -275,7 +284,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { id: AllocId, alloc: Cow<'b, Allocation>, kind: Option>, - ) -> (Cow<'b, Allocation>, Self::PointerTag) { + ) -> ( + Cow<'b, Allocation>, + Self::PointerTag, + ) { let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); let (stacks, base_tag) = if !memory_extra.validate { @@ -291,12 +303,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { }; let mut stacked_borrows = memory_extra.stacked_borrows.borrow_mut(); let alloc: Allocation = alloc.with_tags_and_extra( - |alloc| if !memory_extra.validate { - Tag::Untagged - } else { - // Only statics may already contain pointers at this point - assert_eq!(kind, MiriMemoryKind::Static.into()); - stacked_borrows.static_base_ptr(alloc) + |alloc| { + if !memory_extra.validate { + Tag::Untagged + } else { + // Only statics may already contain pointers at this point + assert_eq!(kind, MiriMemoryKind::Static.into()); + stacked_borrows.static_base_ptr(alloc) + } }, AllocExtra { stacked_borrows: stacks, @@ -306,14 +320,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } #[inline(always)] - fn tag_static_base_pointer( - memory_extra: &MemoryExtra, - id: AllocId, - ) -> Self::PointerTag { + fn tag_static_base_pointer(memory_extra: &MemoryExtra, id: AllocId) -> Self::PointerTag { if !memory_extra.validate { Tag::Untagged } else { - memory_extra.stacked_borrows.borrow_mut().static_base_ptr(id) + memory_extra + .stacked_borrows + .borrow_mut() + .static_base_ptr(id) } } @@ -325,7 +339,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ) -> InterpResult<'tcx> { if !Self::enforce_validity(ecx) { // No tracking. - Ok(()) + Ok(()) } else { ecx.retag(kind, place) } @@ -343,7 +357,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx: &mut InterpCx<'mir, 'tcx, Self>, extra: stacked_borrows::CallId, ) -> InterpResult<'tcx> { - Ok(ecx.memory().extra.stacked_borrows.borrow_mut().end_call(extra)) + Ok(ecx + .memory() + .extra + .stacked_borrows + .borrow_mut() + .end_call(extra)) } #[inline(always)] diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 847169f38dca..985d75b03303 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -1,9 +1,9 @@ use std::convert::TryInto; -use rustc_apfloat::Float; -use rustc::ty::layout::{Align, LayoutOf, Size}; use rustc::hir::def_id::DefId; use rustc::mir; +use rustc::ty::layout::{Align, LayoutOf, Size}; +use rustc_apfloat::Float; use syntax::attr; use syntax::symbol::sym; @@ -40,42 +40,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Align::from_bytes(prev_power_of_two(size)).unwrap() } - fn malloc( - &mut self, - size: u64, - zero_init: bool, - kind: MiriMemoryKind, - ) -> Scalar { + fn malloc(&mut self, size: u64, zero_init: bool, kind: MiriMemoryKind) -> Scalar { let this = self.eval_context_mut(); - let tcx = &{this.tcx.tcx}; + let tcx = &{ this.tcx.tcx }; if size == 0 { Scalar::from_int(0, this.pointer_size()) } else { let align = this.min_align(size, kind); - let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, kind.into()); + let ptr = this + .memory_mut() + .allocate(Size::from_bytes(size), align, kind.into()); if zero_init { // We just allocated this, the access cannot fail this.memory_mut() - .get_mut(ptr.alloc_id).unwrap() - .write_repeat(tcx, ptr, 0, Size::from_bytes(size)).unwrap(); + .get_mut(ptr.alloc_id) + .unwrap() + .write_repeat(tcx, ptr, 0, Size::from_bytes(size)) + .unwrap(); } Scalar::Ptr(ptr) } } - fn free( - &mut self, - ptr: Scalar, - kind: MiriMemoryKind, - ) -> InterpResult<'tcx> { + fn free(&mut self, ptr: Scalar, kind: MiriMemoryKind) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if !this.is_null(ptr)? { let ptr = this.force_ptr(ptr)?; - this.memory_mut().deallocate( - ptr, - None, - kind.into(), - )?; + this.memory_mut().deallocate(ptr, None, kind.into())?; } Ok(()) } @@ -92,22 +83,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if new_size == 0 { Ok(Scalar::from_int(0, this.pointer_size())) } else { - let new_ptr = this.memory_mut().allocate( - Size::from_bytes(new_size), - new_align, - kind.into() - ); + let new_ptr = + this.memory_mut() + .allocate(Size::from_bytes(new_size), new_align, kind.into()); Ok(Scalar::Ptr(new_ptr)) } } else { let old_ptr = this.force_ptr(old_ptr)?; let memory = this.memory_mut(); if new_size == 0 { - memory.deallocate( - old_ptr, - None, - kind.into(), - )?; + memory.deallocate(old_ptr, None, kind.into())?; Ok(Scalar::from_int(0, this.pointer_size())) } else { let new_ptr = memory.reallocate( @@ -139,7 +124,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Strip linker suffixes (seen on 32-bit macOS). let link_name = link_name.trim_end_matches("$UNIX2003"); - let tcx = &{this.tcx.tcx}; + let tcx = &{ this.tcx.tcx }; // First: functions that diverge. match link_name { @@ -151,8 +136,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let code = this.read_scalar(args[0])?.to_i32()?; return Err(InterpError::Exit(code).into()); } - _ => if dest.is_none() { - throw_unsup_format!("can't call (diverging) foreign function: {}", link_name); + _ => { + if dest.is_none() { + throw_unsup_format!("can't call (diverging) foreign function: {}", link_name); + } } } @@ -168,7 +155,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "calloc" => { let items = this.read_scalar(args[0])?.to_usize(this)?; let len = this.read_scalar(args[1])?.to_usize(this)?; - let size = items.checked_mul(len).ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?; + let size = items + .checked_mul(len) + .ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?; let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C); this.write_scalar(res, dest)?; } @@ -193,7 +182,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.memory_mut().allocate( Size::from_bytes(size), Align::from_bytes(align).unwrap(), - MiriMemoryKind::C.into() + MiriMemoryKind::C.into(), ); this.write_scalar(Scalar::Ptr(ptr), ret.into())?; } @@ -219,12 +208,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if !align.is_power_of_two() { throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = this.memory_mut() - .allocate( - Size::from_bytes(size), - Align::from_bytes(align).unwrap(), - MiriMemoryKind::Rust.into() - ); + let ptr = this.memory_mut().allocate( + Size::from_bytes(size), + Align::from_bytes(align).unwrap(), + MiriMemoryKind::Rust.into(), + ); this.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_alloc_zeroed" => { @@ -236,16 +224,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if !align.is_power_of_two() { throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = this.memory_mut() - .allocate( - Size::from_bytes(size), - Align::from_bytes(align).unwrap(), - MiriMemoryKind::Rust.into() - ); + let ptr = this.memory_mut().allocate( + Size::from_bytes(size), + Align::from_bytes(align).unwrap(), + MiriMemoryKind::Rust.into(), + ); // We just allocated this, the access cannot fail this.memory_mut() - .get_mut(ptr.alloc_id).unwrap() - .write_repeat(tcx, ptr, 0, Size::from_bytes(size)).unwrap(); + .get_mut(ptr.alloc_id) + .unwrap() + .write_repeat(tcx, ptr, 0, Size::from_bytes(size)) + .unwrap(); this.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_dealloc" => { @@ -261,7 +250,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.force_ptr(ptr)?; this.memory_mut().deallocate( ptr, - Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())), + Some(( + Size::from_bytes(old_size), + Align::from_bytes(align).unwrap(), + )), MiriMemoryKind::Rust.into(), )?; } @@ -288,7 +280,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "syscall" => { - let sys_getrandom = this.eval_path_scalar(&["libc", "SYS_getrandom"])? + let sys_getrandom = this + .eval_path_scalar(&["libc", "SYS_getrandom"])? .expect("Failed to get libc::SYS_getrandom") .to_usize(this)?; @@ -300,9 +293,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // so skip over it. linux_getrandom(this, &args[1..], dest)?; } - id => { - throw_unsup_format!("miri does not support syscall ID {}", id) - } + id => throw_unsup_format!("miri does not support syscall ID {}", id), } } @@ -342,7 +333,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // TODO: consider making this reusable? `InterpCx::step` does something similar // for the TLS destructors, and of course `eval_main`. let mir = this.load_mir(f_instance.def, None)?; - let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); + let ret_place = + MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); this.push_stack_frame( f_instance, mir.span, @@ -353,12 +345,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; let mut args = this.frame().body.args_iter(); - let arg_local = args.next() + let arg_local = args + .next() .expect("Argument to __rust_maybe_catch_panic does not take enough arguments."); let arg_dest = this.local_place(arg_local)?; this.write_scalar(data, arg_dest)?; - assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected"); + assert!( + args.next().is_none(), + "__rust_maybe_catch_panic argument has more arguments than expected" + ); // We ourselves will return `0`, eventually (because we will not return if we paniced). this.write_null(dest)?; @@ -384,18 +380,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } }; - this.write_scalar( - Scalar::from_int(result, Size::from_bits(32)), - dest, - )?; + this.write_scalar(Scalar::from_int(result, Size::from_bits(32)), dest)?; } "memrchr" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let val = this.read_scalar(args[1])?.to_i32()? as u8; let num = this.read_scalar(args[2])?.to_usize(this)?; - if let Some(idx) = this.memory().read_bytes(ptr, Size::from_bytes(num))? - .iter().rev().position(|&c| c == val) + if let Some(idx) = this + .memory() + .read_bytes(ptr, Size::from_bytes(num))? + .iter() + .rev() + .position(|&c| c == val) { let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), this)?; this.write_scalar(new_ptr, dest)?; @@ -497,10 +494,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write(args[0], args[1], args[2])? }; // Now, `result` is the value we return back to the program. - this.write_scalar( - Scalar::from_int(result, dest.layout.size), - dest, - )?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } "strlen" => { @@ -510,8 +504,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // math functions - - "cbrtf" | "coshf" | "sinhf" |"tanf" => { + "cbrtf" | "coshf" | "sinhf" | "tanf" => { // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); let f = match link_name { @@ -591,9 +584,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("sysconf() called with name {}", name); // TODO: Cache the sysconf integers via Miri's global cache. let paths = &[ - (&["libc", "_SC_PAGESIZE"], Scalar::from_int(PAGE_SIZE, dest.layout.size)), - (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)), - (&["libc", "_SC_NPROCESSORS_ONLN"], Scalar::from_int(NUM_CPUS, dest.layout.size)), + ( + &["libc", "_SC_PAGESIZE"], + Scalar::from_int(PAGE_SIZE, dest.layout.size), + ), + ( + &["libc", "_SC_GETPW_R_SIZE_MAX"], + Scalar::from_int(-1, dest.layout.size), + ), + ( + &["libc", "_SC_NPROCESSORS_ONLN"], + Scalar::from_int(NUM_CPUS, dest.layout.size), + ), ]; let mut result = None; for &(path, path_value) in paths { @@ -603,7 +605,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx result = Some(path_value); break; } - } } if let Some(result) = result { @@ -644,11 +645,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Create key and write it into the memory where `key_ptr` wants it. let key = this.machine.tls.create_tls_key(dtor) as u128; - if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) { + if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) + { throw_unsup!(OutOfTls); } - let key_ptr = this.memory().check_ptr_access(key_ptr, key_layout.size, key_layout.align.abi)? + let key_ptr = this + .memory() + .check_ptr_access(key_ptr, key_layout.size, key_layout.align.abi)? .expect("cannot be a ZST"); this.memory_mut().get_mut(key_ptr.alloc_id)?.write_scalar( tcx, @@ -681,8 +685,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Stack size/address stuff. - "pthread_attr_init" | "pthread_attr_destroy" | "pthread_self" | - "pthread_attr_setstacksize" => { + "pthread_attr_init" + | "pthread_attr_destroy" + | "pthread_self" + | "pthread_attr_setstacksize" => { this.write_null(dest)?; } "pthread_attr_getstack" => { @@ -708,12 +714,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Stub out calls for condvar, mutex and rwlock, to just return `0`. - "pthread_mutexattr_init" | "pthread_mutexattr_settype" | "pthread_mutex_init" | - "pthread_mutexattr_destroy" | "pthread_mutex_lock" | "pthread_mutex_unlock" | - "pthread_mutex_destroy" | "pthread_rwlock_rdlock" | "pthread_rwlock_unlock" | - "pthread_rwlock_wrlock" | "pthread_rwlock_destroy" | "pthread_condattr_init" | - "pthread_condattr_setclock" | "pthread_cond_init" | "pthread_condattr_destroy" | - "pthread_cond_destroy" => { + "pthread_mutexattr_init" + | "pthread_mutexattr_settype" + | "pthread_mutex_init" + | "pthread_mutexattr_destroy" + | "pthread_mutex_lock" + | "pthread_mutex_unlock" + | "pthread_mutex_destroy" + | "pthread_rwlock_rdlock" + | "pthread_rwlock_unlock" + | "pthread_rwlock_wrlock" + | "pthread_rwlock_destroy" + | "pthread_condattr_init" + | "pthread_condattr_setclock" + | "pthread_cond_init" + | "pthread_condattr_destroy" + | "pthread_cond_destroy" => { this.write_null(dest)?; } @@ -745,13 +761,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "_tlv_atexit" => { // FIXME: register the destructor. - }, + } "_NSGetArgc" => { this.write_scalar(Scalar::Ptr(this.machine.argc.unwrap()), dest)?; - }, + } "_NSGetArgv" => { this.write_scalar(Scalar::Ptr(this.machine.argv.unwrap()), dest)?; - }, + } "SecRandomCopyBytes" => { let len = this.read_scalar(args[1])?.to_usize(this)?; let ptr = this.read_scalar(args[2])?.not_undef()?; @@ -802,32 +818,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "AddVectoredExceptionHandler" => { // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; - }, - "InitializeCriticalSection" | - "EnterCriticalSection" | - "LeaveCriticalSection" | - "DeleteCriticalSection" => { + } + "InitializeCriticalSection" + | "EnterCriticalSection" + | "LeaveCriticalSection" + | "DeleteCriticalSection" => { // Nothing to do, not even a return value. - }, - "GetModuleHandleW" | - "GetProcAddress" | - "TryEnterCriticalSection" | - "GetConsoleScreenBufferInfo" | - "SetConsoleTextAttribute" => { + } + "GetModuleHandleW" + | "GetProcAddress" + | "TryEnterCriticalSection" + | "GetConsoleScreenBufferInfo" + | "SetConsoleTextAttribute" => { // Pretend these do not exist / nothing happened, by returning zero. this.write_null(dest)?; - }, + } "GetSystemInfo" => { let system_info = this.deref_operand(args[0])?; - let system_info_ptr = this.check_mplace_access(system_info, None)? + let system_info_ptr = this + .check_mplace_access(system_info, None)? .expect("cannot be a ZST"); // Initialize with `0`. - this.memory_mut().get_mut(system_info_ptr.alloc_id)? + this.memory_mut() + .get_mut(system_info_ptr.alloc_id)? .write_repeat(tcx, system_info_ptr, 0, system_info.layout.size)?; // Set number of processors. let dword_size = Size::from_bytes(4); - let offset = 2*dword_size + 3*tcx.pointer_size(); - this.memory_mut().get_mut(system_info_ptr.alloc_id)? + let offset = 2 * dword_size + 3 * tcx.pointer_size(); + this.memory_mut() + .get_mut(system_info_ptr.alloc_id)? .write_scalar( tcx, system_info_ptr.offset(offset, tcx)?, @@ -844,7 +863,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Figure out how large a TLS key actually is. This is `c::DWORD`. if dest.layout.size.bits() < 128 - && key >= (1u128 << dest.layout.size.bits() as u128) { + && key >= (1u128 << dest.layout.size.bits() as u128) + { throw_unsup!(OutOfTls); } this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; @@ -879,7 +899,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // stdout/stderr use std::io::{self, Write}; - let buf_cont = this.memory().read_bytes(buf, Size::from_bytes(u64::from(n)))?; + let buf_cont = this + .memory() + .read_bytes(buf, Size::from_bytes(u64::from(n)))?; let res = if handle == -11 { io::stdout().write(buf_cont) } else { @@ -922,9 +944,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // We can't execute anything else. - _ => { - throw_unsup_format!("can't call foreign function: {}", link_name) - } + _ => throw_unsup_format!("can't call foreign function: {}", link_name), } this.goto_block(Some(ret))?; @@ -934,7 +954,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Evaluates the scalar at the specified path. Returns Some(val) /// if the path could be resolved, and None otherwise - fn eval_path_scalar(&mut self, path: &[&str]) -> InterpResult<'tcx, Option>> { + fn eval_path_scalar( + &mut self, + path: &[&str], + ) -> InterpResult<'tcx, Option>> { let this = self.eval_context_mut(); if let Ok(instance) = this.resolve_path(path) { let cid = GlobalId { @@ -949,8 +972,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { - self - .eval_context_mut() + self.eval_context_mut() .eval_path_scalar(&["libc", name])? .ok_or_else(|| err_unsup_format!("Path libc::{} cannot be resolved.", name).into()) .and_then(|scalar| scalar.to_i32()) From 11d7be9c6fc72c9337067e0713b06644d3574c45 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 3 Oct 2019 10:21:55 -0500 Subject: [PATCH 1164/5092] Move last_error into memory --- src/eval.rs | 7 +++++++ src/machine.rs | 4 ++-- src/shims/env.rs | 18 +++++++++++------- src/shims/foreign_items.rs | 38 ++++++++++++++++++++++++++++++++------ src/shims/io.rs | 11 ++++++++--- 5 files changed, 60 insertions(+), 18 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 21395cb311fa..aa876d6617ce 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -183,6 +183,13 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( "start lang item has more arguments than expected" ); + // Set the last_error to 0 + let errno_layout = ecx.layout_of(ecx.tcx.types.u32)?; + let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Static.into()); + ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?; + let errno_ptr = ecx.check_mplace_access(errno_place.into(), Some(Size::from_bits(32)))?; + ecx.machine.last_error = errno_ptr; + Ok(ecx) } diff --git a/src/machine.rs b/src/machine.rs index c8962612c658..c22b3805d46b 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -92,7 +92,7 @@ pub struct Evaluator<'tcx> { pub(crate) cmd_line: Option>, /// Last OS error. - pub(crate) last_error: u32, + pub(crate) last_error: Option>, /// TLS state. pub(crate) tls: TlsData<'tcx>, @@ -113,7 +113,7 @@ impl<'tcx> Evaluator<'tcx> { argc: None, argv: None, cmd_line: None, - last_error: 0, + last_error: None, tls: TlsData::default(), communicate, file_handler: Default::default(), diff --git a/src/shims/env.rs b/src/shims/env.rs index 074baa51f826..23ba8d96567d 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -137,18 +137,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if (bytes.len() as u64) < size { // We add a `/0` terminator bytes.push(0); - // This is ok because the buffer is larger than the path with the null terminator. + // This is ok because the buffer is larger than the path with terminatorhe null terminator. this.memory_mut() .get_mut(buf.alloc_id)? .write_bytes(tcx, buf, &bytes)?; return Ok(Scalar::Ptr(buf)); } - this.machine.last_error = this - .eval_path_scalar(&["libc", "ERANGE"])? - .unwrap() - .to_u32()?; + let erange = this.eval_libc("ERANGE")?; + this.set_last_error(erange)?; } - Err(e) => this.machine.last_error = e.raw_os_error().unwrap() as u32, + Err(e) => this.set_last_error(Scalar::from_int( + e.raw_os_error().unwrap(), + Size::from_bits(32), + ))?, } Ok(Scalar::ptr_null(&*this.tcx)) } @@ -172,7 +173,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match env::set_current_dir(path) { Ok(()) => Ok(0), Err(e) => { - this.machine.last_error = e.raw_os_error().unwrap() as u32; + this.set_last_error(Scalar::from_int( + e.raw_os_error().unwrap(), + Size::from_bits(32), + ))?; Ok(-1) } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 985d75b03303..76430260f7ec 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -808,11 +808,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "SetLastError" => { - let err = this.read_scalar(args[0])?.to_u32()?; - this.machine.last_error = err; + this.set_last_error(this.read_scalar(args[0])?.not_undef()?)?; } "GetLastError" => { - this.write_scalar(Scalar::from_u32(this.machine.last_error), dest)?; + let last_error = this.get_last_error()?; + this.write_scalar(last_error, dest)?; } "AddVectoredExceptionHandler" => { @@ -929,7 +929,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "GetEnvironmentVariableW" => { // This is not the env var you are looking for. - this.machine.last_error = 203; // ERROR_ENVVAR_NOT_FOUND + this.set_last_error(Scalar::from_u32(203))?; // ERROR_ENVVAR_NOT_FOUND this.write_null(dest)?; } "GetCommandLineW" => { @@ -971,11 +971,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(None); } - fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { + fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar> { self.eval_context_mut() .eval_path_scalar(&["libc", name])? .ok_or_else(|| err_unsup_format!("Path libc::{} cannot be resolved.", name).into()) - .and_then(|scalar| scalar.to_i32()) + .and_then(|scalar| scalar.not_undef()) + } + + fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { + self.eval_libc(name).and_then(|scalar| scalar.to_i32()) + } + + fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx, ()> { + let this = self.eval_context_mut(); + let tcx = &{ this.tcx.tcx }; + let errno_ptr = this.machine.last_error.unwrap(); + this.memory_mut().get_mut(errno_ptr.alloc_id)?.write_scalar( + tcx, + errno_ptr, + scalar.into(), + Size::from_bits(32), + ) + } + + fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + let tcx = &{ this.tcx.tcx }; + let errno_ptr = this.machine.last_error.unwrap(); + this.memory() + .get(errno_ptr.alloc_id)? + .read_scalar(tcx, errno_ptr, Size::from_bits(32))? + .not_undef() } } diff --git a/src/shims/io.rs b/src/shims/io.rs index 74b8dde5c7fc..1eaebbf0b887 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -221,7 +221,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(handle) = this.machine.file_handler.handles.get(&fd) { f(handle) } else { - this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; + let ebadf = this.eval_libc("EBADF")?; + this.set_last_error(ebadf)?; Ok((-1).into()) } } @@ -244,7 +245,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(handle) = this.machine.file_handler.handles.remove(&fd) { f(handle, this) } else { - this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; + let ebadf = this.eval_libc("EBADF")?; + this.set_last_error(ebadf)?; Ok((-1).into()) } } @@ -262,7 +264,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match result { Ok(ok) => Ok(ok), Err(e) => { - self.eval_context_mut().machine.last_error = e.raw_os_error().unwrap() as u32; + self.eval_context_mut().set_last_error(Scalar::from_int( + e.raw_os_error().unwrap(), + Size::from_bits(32), + ))?; Ok((-1).into()) } } From 887d7481148101615fc1966864a14276350dbf65 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 3 Oct 2019 10:28:38 -0500 Subject: [PATCH 1165/5092] Add __errno_location shim --- src/shims/foreign_items.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 76430260f7ec..fecd15b39283 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -418,6 +418,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + "__errno_location" => { + let errno_scalar: Scalar = this.machine.last_error.unwrap().into(); + this.write_scalar(errno_scalar, dest)?; + } + "getenv" => { let result = this.getenv(args[0])?; this.write_scalar(result, dest)?; From 459c65a4f9b2e462037e600a511b785c78dd8f0e Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 7 Oct 2019 08:38:54 -0500 Subject: [PATCH 1166/5092] Add method to consume io::Error --- src/shims/env.rs | 12 +++--------- src/shims/foreign_items.rs | 9 ++++++++- src/shims/io.rs | 5 +---- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 23ba8d96567d..f4b6a7c4dbac 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -137,7 +137,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if (bytes.len() as u64) < size { // We add a `/0` terminator bytes.push(0); - // This is ok because the buffer is larger than the path with terminatorhe null terminator. + // This is ok because the buffer is larger than the path with the null terminator. this.memory_mut() .get_mut(buf.alloc_id)? .write_bytes(tcx, buf, &bytes)?; @@ -146,10 +146,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let erange = this.eval_libc("ERANGE")?; this.set_last_error(erange)?; } - Err(e) => this.set_last_error(Scalar::from_int( - e.raw_os_error().unwrap(), - Size::from_bits(32), - ))?, + Err(e) => this.consume_io_error(e)?, } Ok(Scalar::ptr_null(&*this.tcx)) } @@ -173,10 +170,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match env::set_current_dir(path) { Ok(()) => Ok(0), Err(e) => { - this.set_last_error(Scalar::from_int( - e.raw_os_error().unwrap(), - Size::from_bits(32), - ))?; + this.consume_io_error(e)?; Ok(-1) } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index fecd15b39283..3298eef85353 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -987,7 +987,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx self.eval_libc(name).and_then(|scalar| scalar.to_i32()) } - fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx, ()> { + fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let tcx = &{ this.tcx.tcx }; let errno_ptr = this.machine.last_error.unwrap(); @@ -1008,6 +1008,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .read_scalar(tcx, errno_ptr, Size::from_bits(32))? .not_undef() } + + fn consume_io_error(&mut self, e: std::io::Error) -> InterpResult<'tcx> { + self.eval_context_mut().set_last_error(Scalar::from_int( + e.raw_os_error().unwrap(), + Size::from_bits(32), + )) + } } // Shims the linux 'getrandom()' syscall. diff --git a/src/shims/io.rs b/src/shims/io.rs index 1eaebbf0b887..ca3f500f5a47 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -264,10 +264,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match result { Ok(ok) => Ok(ok), Err(e) => { - self.eval_context_mut().set_last_error(Scalar::from_int( - e.raw_os_error().unwrap(), - Size::from_bits(32), - ))?; + self.eval_context_mut().consume_io_error(e)?; Ok((-1).into()) } } From ffc47de1b989ea4fe15162061c835ae13524d602 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 3 Oct 2019 09:33:36 -0500 Subject: [PATCH 1167/5092] Add unlink shim to delete files --- src/shims/foreign_items.rs | 5 +++++ src/shims/io.rs | 20 ++++++++++++++++++- .../{file_read.rs => file_manipulation.rs} | 5 +++-- 3 files changed, 27 insertions(+), 3 deletions(-) rename tests/run-pass/{file_read.rs => file_manipulation.rs} (89%) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 3298eef85353..a96ed35b67a6 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -502,6 +502,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "unlink" => { + let result = this.unlink(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + "strlen" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let n = this.memory().read_c_str(ptr)?.len(); diff --git a/src/shims/io.rs b/src/shims/io.rs index ca3f500f5a47..0893d0b4e0e8 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use std::fs::{File, OpenOptions}; +use std::fs::{File, OpenOptions, remove_file}; use std::io::{Read, Write}; use rustc::ty::layout::Size; @@ -205,6 +205,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) } + fn unlink( &mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + if !this.machine.communicate { + throw_unsup_format!("`write` not available when isolation is enabled") + } + + let path_bytes = this + .memory() + .read_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = std::str::from_utf8(path_bytes) + .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", path_bytes))?; + + let result = remove_file(path).map(|_| 0); + + this.consume_result(result) + } + /// Helper function that gets a `FileHandle` immutable reference and allows to manipulate it /// using the `f` closure. /// diff --git a/tests/run-pass/file_read.rs b/tests/run-pass/file_manipulation.rs similarity index 89% rename from tests/run-pass/file_read.rs rename to tests/run-pass/file_manipulation.rs index 666abd65c12e..3980cc0f74f5 100644 --- a/tests/run-pass/file_read.rs +++ b/tests/run-pass/file_manipulation.rs @@ -1,11 +1,10 @@ // ignore-windows: File handling is not implemented yet // compile-flags: -Zmiri-disable-isolation -use std::fs::File; +use std::fs::{File, remove_file}; use std::io::{Read, Write}; fn main() { - // FIXME: remove the file and delete it when `rm` is implemented. let path = "./tests/hello.txt"; let bytes = b"Hello, World!\n"; // Test creating, writing and closing a file (closing is tested when `file` is dropped). @@ -22,4 +21,6 @@ fn main() { // Reading until EOF should get the whole text. file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); + // Removing file should succeed + remove_file(path).unwrap(); } From 00792493ef65da150ce5d3e4cc7c15660ce1b54a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 8 Oct 2019 08:56:36 -0500 Subject: [PATCH 1168/5092] Add tests for non-existing files --- tests/run-pass/file_manipulation.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/run-pass/file_manipulation.rs b/tests/run-pass/file_manipulation.rs index 3980cc0f74f5..fa17efd7e179 100644 --- a/tests/run-pass/file_manipulation.rs +++ b/tests/run-pass/file_manipulation.rs @@ -23,4 +23,8 @@ fn main() { assert_eq!(bytes, contents.as_slice()); // Removing file should succeed remove_file(path).unwrap(); + // Opening non-existing file should fail + assert!(File::open(path).is_err()); + // Removing non-existing file should fail + assert!(remove_file(path).is_err()); } From 187361996f6b85edc9001cfdc0081474986ed2b1 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 8 Oct 2019 09:25:26 -0500 Subject: [PATCH 1169/5092] Add errno_location shim for MacOS --- src/shims/foreign_items.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index a96ed35b67a6..9cd84d0b887e 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -418,7 +418,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - "__errno_location" => { + "__errno_location" | "__error" => { let errno_scalar: Scalar = this.machine.last_error.unwrap().into(); this.write_scalar(errno_scalar, dest)?; } From 62f08eb41682e2cd44890377d422ce8268d10ca4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Oct 2019 10:29:08 +0200 Subject: [PATCH 1170/5092] also test AcqRel fence --- tests/run-pass/atomic.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-pass/atomic.rs b/tests/run-pass/atomic.rs index 5872a496dbfa..a9dd29bd62bf 100644 --- a/tests/run-pass/atomic.rs +++ b/tests/run-pass/atomic.rs @@ -69,4 +69,5 @@ fn atomic_fences() { fence(SeqCst); fence(Release); fence(Acquire); + fence(AcqRel); } From c2e4c877c5c47a20cc66de848d6eb51b0f478dd9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Oct 2019 11:11:56 +0200 Subject: [PATCH 1171/5092] bump to latest nightly --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 2d311cc17704..db6f5ebe88c4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d046ffddc4bd50e04ffc3ff9f766e2ac71f74d50 +2748a9fd93dd1a00a4521f4f16de5befbf77f6cd From 610dbdd562bc327f016a326c703073cee97dc645 Mon Sep 17 00:00:00 2001 From: YOUNGSUK_KIM Date: Thu, 10 Oct 2019 11:03:20 -0400 Subject: [PATCH 1172/5092] fixed cargo-miri bug for windows users --- src/bin/cargo-miri.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 1f1705a49ac9..521ac8fa065c 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -333,17 +333,11 @@ path = "lib.rs" None => true, Some(target) => target == rustc_version::version_meta().unwrap().host, }; - let mut sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; - if cfg!(target_os = "windows") { - // Replace backslashes in path to slashes as they cause problems. - // Win10 Powershell can work with slashes in paths. - sysroot = PathBuf::from( - String::from(sysroot.to_str().unwrap()).replace("\\", "/") - ); - } + let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; + std::env::set_var("MIRI_SYSROOT", &sysroot); // pass the env var to the processes we spawn, which will turn it into "--sysroot" flags if print_env { - println!("MIRI_SYSROOT={}", sysroot.display()); + println!("MIRI_SYSROOT={:?}", &sysroot); // for Windows users, prints path with backslashes escaped. } else if !ask_user { println!("A libstd for Miri is now available in `{}`.", sysroot.display()); } From 976c976f0948ebfb080f51c733c5bbe24c366554 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 01:49:28 -0500 Subject: [PATCH 1173/5092] Rename shims::io to shims::fs --- src/lib.rs | 2 +- src/shims/{io.rs => fs.rs} | 0 src/shims/mod.rs | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/shims/{io.rs => fs.rs} (100%) diff --git a/src/lib.rs b/src/lib.rs index 9f4e605b6c94..baae26d91ada 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,7 +34,7 @@ pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::dlsym::{Dlsym, EvalContextExt as DlsymEvalContextExt}; pub use crate::shims::env::{EnvVars, EvalContextExt as EnvEvalContextExt}; -pub use crate::shims::io::{FileHandler, EvalContextExt as FileEvalContextExt}; +pub use crate::shims::fs::{FileHandler, EvalContextExt as FileEvalContextExt}; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; diff --git a/src/shims/io.rs b/src/shims/fs.rs similarity index 100% rename from src/shims/io.rs rename to src/shims/fs.rs diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 3df5b839e5d7..6d80af46850c 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -3,7 +3,7 @@ pub mod env; pub mod foreign_items; pub mod intrinsics; pub mod tls; -pub mod io; +pub mod fs; use rustc::{mir, ty}; From c8df0171e84deb4563f30f9f1c3cf61e859315fb Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 01:53:31 -0500 Subject: [PATCH 1174/5092] Move functions to eval libc constants to helpers --- src/helpers.rs | 11 +++++++++++ src/shims/foreign_items.rs | 11 ----------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 3bee028c5eb7..39c7af94e0ae 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -291,4 +291,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } + /// Helper function to get a `libc` constant as a `Scalar`. + fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar> { + self.eval_context_mut() + .eval_path_scalar(&["libc", name])? + .ok_or_else(|| err_unsup_format!("Path libc::{} cannot be resolved.", name).into()) + .and_then(|scalar| scalar.not_undef()) + } + /// Helper function to get a `libc` constant as an `i32`. + fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { + self.eval_libc(name).and_then(|scalar| scalar.to_i32()) + } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 9cd84d0b887e..00160156312a 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -981,17 +981,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(None); } - fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar> { - self.eval_context_mut() - .eval_path_scalar(&["libc", name])? - .ok_or_else(|| err_unsup_format!("Path libc::{} cannot be resolved.", name).into()) - .and_then(|scalar| scalar.not_undef()) - } - - fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { - self.eval_libc(name).and_then(|scalar| scalar.to_i32()) - } - fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let tcx = &{ this.tcx.tcx }; From 8368d4f2b44ae1441390a2f7eee48af340c8d70c Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 02:35:50 -0500 Subject: [PATCH 1175/5092] Add comments to explain the chdir test --- tests/run-pass/{change_current_dir.rs => current_dir.rs} | 3 +++ 1 file changed, 3 insertions(+) rename tests/run-pass/{change_current_dir.rs => current_dir.rs} (66%) diff --git a/tests/run-pass/change_current_dir.rs b/tests/run-pass/current_dir.rs similarity index 66% rename from tests/run-pass/change_current_dir.rs rename to tests/run-pass/current_dir.rs index fa8220339db0..48045187ab15 100644 --- a/tests/run-pass/change_current_dir.rs +++ b/tests/run-pass/current_dir.rs @@ -6,6 +6,9 @@ use std::path::Path; fn main() { // test that `getcwd` is available let cwd = env::current_dir().unwrap(); + // test that changing dir to `..` actually sets the current directory to the parent of `cwd`. + // the only exception here is if `cwd` is the root directory, then changing directory must + // keep the current directory equal to `cwd`. let parent = cwd.parent().unwrap_or(&cwd); // test that `chdir` is available assert!(env::set_current_dir(&Path::new("..")).is_ok()); From 12040aae885b8df967892ea1de420b9a35b42599 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 03:36:34 -0500 Subject: [PATCH 1176/5092] Add comment explaining why buffer isn't overflowed --- src/shims/env.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index f4b6a7c4dbac..b39bde4dedc6 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -133,11 +133,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(cwd) => { // It is not clear what happens with non-utf8 paths here let mut bytes = cwd.display().to_string().into_bytes(); - // If the buffer is smaller or equal than the path, we return null. + // If `size` is smaller or equal than the `bytes.len()`, writing `bytes` using the + // `buf` pointer would cause an overflow, the desired behavior in this case is to + // return null. if (bytes.len() as u64) < size { // We add a `/0` terminator bytes.push(0); - // This is ok because the buffer is larger than the path with the null terminator. + // This is ok because the buffer was strictly larger than `bytes`, so after + // adding the null terminator, the buffer size is larger or equal to + // `bytes.len()`, meaning that `bytes` actually fit inside tbe buffer. this.memory_mut() .get_mut(buf.alloc_id)? .write_bytes(tcx, buf, &bytes)?; From 1c64f29811db779bb202c3450c60c227fb0234bb Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 03:55:18 -0500 Subject: [PATCH 1177/5092] Add comment for the flag diff check --- src/shims/fs.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 0893d0b4e0e8..7e684489b5c9 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -107,6 +107,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(FileHandle { flag: old_flag, .. }) = this.machine.file_handler.handles.get_mut(&fd) { + // Check that the only difference between the old flag and the current flag is + // exactly the `FD_CLOEXEC` value. if flag ^ *old_flag == fd_cloexec { *old_flag = flag; } else { From ae9f4e1e63c8dfd8f860d6b28c5a192bd22de316 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 03:31:11 -0500 Subject: [PATCH 1178/5092] Avoid using the tests folder for the file manipualtion test --- tests/run-pass/file_manipulation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/file_manipulation.rs b/tests/run-pass/file_manipulation.rs index fa17efd7e179..98f3c1089bb7 100644 --- a/tests/run-pass/file_manipulation.rs +++ b/tests/run-pass/file_manipulation.rs @@ -5,7 +5,7 @@ use std::fs::{File, remove_file}; use std::io::{Read, Write}; fn main() { - let path = "./tests/hello.txt"; + let path = "miri_test_fs.txt"; let bytes = b"Hello, World!\n"; // Test creating, writing and closing a file (closing is tested when `file` is dropped). let mut file = File::create(path).unwrap(); From e9138ab4d63019a514fe5d531776fc1ecd37c307 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 04:01:07 -0500 Subject: [PATCH 1179/5092] Rename file manipulation test to fs --- tests/run-pass/{file_manipulation.rs => fs.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/run-pass/{file_manipulation.rs => fs.rs} (100%) diff --git a/tests/run-pass/file_manipulation.rs b/tests/run-pass/fs.rs similarity index 100% rename from tests/run-pass/file_manipulation.rs rename to tests/run-pass/fs.rs From 67ea4546472edace0ae1d8fc97ae85bf5953e8a5 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 04:17:43 -0500 Subject: [PATCH 1180/5092] Correct style of comments --- src/helpers.rs | 2 ++ src/shims/env.rs | 6 +++--- tests/run-pass/current_dir.rs | 10 +++++----- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 39c7af94e0ae..b2a462ef9067 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -291,6 +291,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } + /// Helper function to get a `libc` constant as a `Scalar`. fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar> { self.eval_context_mut() @@ -298,6 +299,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .ok_or_else(|| err_unsup_format!("Path libc::{} cannot be resolved.", name).into()) .and_then(|scalar| scalar.not_undef()) } + /// Helper function to get a `libc` constant as an `i32`. fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { self.eval_libc(name).and_then(|scalar| scalar.to_i32()) diff --git a/src/shims/env.rs b/src/shims/env.rs index b39bde4dedc6..6f32783d7a76 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -133,9 +133,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(cwd) => { // It is not clear what happens with non-utf8 paths here let mut bytes = cwd.display().to_string().into_bytes(); - // If `size` is smaller or equal than the `bytes.len()`, writing `bytes` using the - // `buf` pointer would cause an overflow, the desired behavior in this case is to - // return null. + // If `size` is smaller or equal than the `bytes.len()`, writing `bytes` plus the + // required null terminator to memory using the `buf` pointer would cause an + // overflow, the desired behavior in this case is to return null. if (bytes.len() as u64) < size { // We add a `/0` terminator bytes.push(0); diff --git a/tests/run-pass/current_dir.rs b/tests/run-pass/current_dir.rs index 48045187ab15..5e896659c85e 100644 --- a/tests/run-pass/current_dir.rs +++ b/tests/run-pass/current_dir.rs @@ -4,14 +4,14 @@ use std::env; use std::path::Path; fn main() { - // test that `getcwd` is available + // Test that `getcwd` is available let cwd = env::current_dir().unwrap(); - // test that changing dir to `..` actually sets the current directory to the parent of `cwd`. - // the only exception here is if `cwd` is the root directory, then changing directory must + // Test that changing dir to `..` actually sets the current directory to the parent of `cwd`. + // The only exception here is if `cwd` is the root directory, then changing directory must // keep the current directory equal to `cwd`. let parent = cwd.parent().unwrap_or(&cwd); - // test that `chdir` is available + // Test that `chdir` is available assert!(env::set_current_dir(&Path::new("..")).is_ok()); - // test that `..` goes to the parent directory + // Test that `..` goes to the parent directory assert_eq!(env::current_dir().unwrap(), parent); } From 60cf06a03fa06bc1c5e2981d4ad7f5496b06c62f Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 04:20:18 -0500 Subject: [PATCH 1181/5092] Use existing tcx instead --- src/shims/env.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 6f32783d7a76..8c1645cde738 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -127,7 +127,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tcx = &{ this.tcx.tcx }; let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; - let size = this.read_scalar(size_op)?.to_usize(&*this.tcx)?; + let size = this.read_scalar(size_op)?.to_usize(&*tcx)?; // If we cannot get the current directory, we return null match env::current_dir() { Ok(cwd) => { @@ -152,7 +152,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Err(e) => this.consume_io_error(e)?, } - Ok(Scalar::ptr_null(&*this.tcx)) + Ok(Scalar::ptr_null(&*tcx)) } fn chdir(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { From 003b257f87b94921594a46b4e0ad4dc22bb4cf4d Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 08:20:32 -0500 Subject: [PATCH 1182/5092] Change error handling style for consistency --- src/helpers.rs | 6 +++--- src/shims/env.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index b2a462ef9067..c7b7853388cc 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -296,12 +296,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar> { self.eval_context_mut() .eval_path_scalar(&["libc", name])? - .ok_or_else(|| err_unsup_format!("Path libc::{} cannot be resolved.", name).into()) - .and_then(|scalar| scalar.not_undef()) + .ok_or_else(|| err_unsup_format!("Path libc::{} cannot be resolved.", name))? + .not_undef() } /// Helper function to get a `libc` constant as an `i32`. fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { - self.eval_libc(name).and_then(|scalar| scalar.to_i32()) + self.eval_libc(name)?.to_i32() } } diff --git a/src/shims/env.rs b/src/shims/env.rs index 8c1645cde738..2ccbc0238e5f 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -135,7 +135,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut bytes = cwd.display().to_string().into_bytes(); // If `size` is smaller or equal than the `bytes.len()`, writing `bytes` plus the // required null terminator to memory using the `buf` pointer would cause an - // overflow, the desired behavior in this case is to return null. + // overflow. The desired behavior in this case is to return null. if (bytes.len() as u64) < size { // We add a `/0` terminator bytes.push(0); From aa3e9703d180648af483a4d2304a9092debf365d Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 2 Oct 2019 13:17:58 -0500 Subject: [PATCH 1183/5092] Add clock_gettime shim --- src/shims/foreign_items.rs | 55 ++++++++++++++++++++++++++++++++------ tests/run-pass/clock.rs | 7 +++++ 2 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 tests/run-pass/clock.rs diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 00160156312a..8641a7cf3862 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -507,16 +507,55 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "strlen" => { - let ptr = this.read_scalar(args[0])?.not_undef()?; - let n = this.memory().read_c_str(ptr)?.len(); - this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; + "clock_gettime" => { + if !this.machine.communicate { + throw_unsup_format!("`clock_gettime` not available when isolation is enabled") + } else { + let tcx = &{ this.tcx.tcx }; + + let clk_id = this.read_scalar(args[0])?.to_i32()?; + + if clk_id != this.eval_libc_i32("CLOCK_REALTIME")? { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + this.write_scalar(Scalar::from_int(-1i32, dest.layout.size), dest)?; + } else { + let tp = this.force_ptr(this.read_scalar(args[1])?.not_undef()?)?; + + let allocation = this.memory_mut().get_mut(tp.alloc_id)?; + + let duration = std::time::SystemTime::now() + .duration_since(std::time::SystemTime::UNIX_EPOCH) + .unwrap_or_else(|_| bug!("Clock went backwards")); + + allocation.write_scalar( + tcx, + tp, + Scalar::from_u64(duration.as_secs()).into(), + Size::from_bits(64), + )?; + allocation.write_scalar( + tcx, + tp.offset(Size::from_bits(64), tcx)?, + Scalar::from_u64(duration.subsec_nanos() as u64).into(), + Size::from_bits(64), + )?; + + this.write_scalar(Scalar::from_int(0i32, dest.layout.size), dest)?; + } + } } - // math functions - "cbrtf" | "coshf" | "sinhf" | "tanf" => { - // FIXME: Using host floats. - let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); + "strlen" => { + let ptr = this.read_scalar(args[0])?.not_undef()?; + let n = this.memory().read_c_str(ptr)?.len(); + this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; + } + + // math functions + "cbrtf" | "coshf" | "sinhf" | "tanf" => { + // FIXME: Using host floats. + let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); let f = match link_name { "cbrtf" => f.cbrt(), "coshf" => f.cosh(), diff --git a/tests/run-pass/clock.rs b/tests/run-pass/clock.rs new file mode 100644 index 000000000000..987a78fe1f05 --- /dev/null +++ b/tests/run-pass/clock.rs @@ -0,0 +1,7 @@ +// compile-flags: -Zmiri-disable-isolation + +use std::time::SystemTime; + +fn main() { + let _now = SystemTime::now(); +} From fcf04b5425099738c0f26994baf29a1112997bf2 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 3 Oct 2019 11:20:06 -0500 Subject: [PATCH 1184/5092] Reduce size of nanoseconds --- src/shims/foreign_items.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 8641a7cf3862..c106a296dcde 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -537,8 +537,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx allocation.write_scalar( tcx, tp.offset(Size::from_bits(64), tcx)?, - Scalar::from_u64(duration.subsec_nanos() as u64).into(), - Size::from_bits(64), + Scalar::from_u32(duration.subsec_nanos()).into(), + Size::from_bits(32), )?; this.write_scalar(Scalar::from_int(0i32, dest.layout.size), dest)?; From adfa2eb062bf825bb100dc2cfd7ab7df075f1824 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 7 Oct 2019 16:22:53 -0500 Subject: [PATCH 1185/5092] Return negative times when the current time is before the unix epoch --- src/shims/foreign_items.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index c106a296dcde..c403afacd89b 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -524,21 +524,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let allocation = this.memory_mut().get_mut(tp.alloc_id)?; + let mut sign = 1; + let duration = std::time::SystemTime::now() .duration_since(std::time::SystemTime::UNIX_EPOCH) - .unwrap_or_else(|_| bug!("Clock went backwards")); + .unwrap_or_else(|e| { + sign = -1; + e.duration() + }); + + let tv_sec_size = Size::from_bits(64); + let tv_nsec_size = Size::from_bits(64); allocation.write_scalar( tcx, tp, - Scalar::from_u64(duration.as_secs()).into(), - Size::from_bits(64), + Scalar::from_int(sign * (duration.as_secs() as i64), tv_sec_size).into(), + tv_sec_size, )?; + allocation.write_scalar( tcx, - tp.offset(Size::from_bits(64), tcx)?, - Scalar::from_u32(duration.subsec_nanos()).into(), - Size::from_bits(32), + tp.offset(tv_sec_size, tcx)?, + Scalar::from_int(duration.subsec_nanos() as i64, tv_nsec_size).into(), + tv_nsec_size, )?; this.write_scalar(Scalar::from_int(0i32, dest.layout.size), dest)?; From 7a6df8504f477faafe1c91e0c7fa83a63e31a825 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 8 Oct 2019 13:29:39 -0500 Subject: [PATCH 1186/5092] Get size of integers using libc --- src/shims/foreign_items.rs | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index c403afacd89b..1e7c85c43521 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -522,6 +522,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { let tp = this.force_ptr(this.read_scalar(args[1])?.not_undef()?)?; + let long = this.resolve_path(&["libc", "c_long"])?.ty(*tcx); + let time_t = this.resolve_path(&["libc", "time_t"])?.ty(*tcx); + + let tv_sec_size = this.layout_of(time_t)?.size; + let tv_nsec_size = this.layout_of(long)?.size; + let allocation = this.memory_mut().get_mut(tp.alloc_id)?; let mut sign = 1; @@ -533,13 +539,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx e.duration() }); - let tv_sec_size = Size::from_bits(64); - let tv_nsec_size = Size::from_bits(64); - allocation.write_scalar( tcx, tp, - Scalar::from_int(sign * (duration.as_secs() as i64), tv_sec_size).into(), + Scalar::from_int(sign * (duration.as_secs() as i64), tv_sec_size) + .into(), tv_sec_size, )?; @@ -555,16 +559,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - "strlen" => { - let ptr = this.read_scalar(args[0])?.not_undef()?; - let n = this.memory().read_c_str(ptr)?.len(); - this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; - } + "strlen" => { + let ptr = this.read_scalar(args[0])?.not_undef()?; + let n = this.memory().read_c_str(ptr)?.len(); + this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; + } - // math functions - "cbrtf" | "coshf" | "sinhf" | "tanf" => { - // FIXME: Using host floats. - let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); + // math functions + "cbrtf" | "coshf" | "sinhf" | "tanf" => { + // FIXME: Using host floats. + let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); let f = match link_name { "cbrtf" => f.cbrt(), "coshf" => f.cosh(), From b7863f2509eed16f2ce79ffb52a21de5bd536a48 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 8 Oct 2019 14:04:23 -0500 Subject: [PATCH 1187/5092] Add gettimeofday shim for macOS --- src/shims/foreign_items.rs | 52 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 1e7c85c43521..656cb0101020 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -559,6 +559,58 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + "gettimeofday" => { + if !this.machine.communicate { + throw_unsup_format!("`gettimeofday` not available when isolation is enabled") + } else { + let tcx = &{ this.tcx.tcx }; + + let tz = this.read_scalar(args[1])?.not_undef()?; + // Using tz is obsolete and should always be null + if !this.is_null(tz)? { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + this.write_scalar(Scalar::from_int(-1i32, dest.layout.size), dest)?; + } else { + let tv = this.force_ptr(this.read_scalar(args[0])?.not_undef()?)?; + + let time_t = this.resolve_path(&["libc", "time_t"])?.ty(*tcx); + let suseconds_t = this.resolve_path(&["libc", "suseconds_t"])?.ty(*tcx); + + let tv_sec_size = this.layout_of(time_t)?.size; + let tv_usec_size = this.layout_of(suseconds_t)?.size; + + let allocation = this.memory_mut().get_mut(tv.alloc_id)?; + + let mut sign = 1; + + let duration = std::time::SystemTime::now() + .duration_since(std::time::SystemTime::UNIX_EPOCH) + .unwrap_or_else(|e| { + sign = -1; + e.duration() + }); + + allocation.write_scalar( + tcx, + tv, + Scalar::from_int(sign * (duration.as_secs() as i64), tv_sec_size) + .into(), + tv_sec_size, + )?; + + allocation.write_scalar( + tcx, + tv.offset(tv_sec_size, tcx)?, + Scalar::from_int(duration.subsec_micros() as i64, tv_usec_size).into(), + tv_usec_size, + )?; + + this.write_scalar(Scalar::from_int(0i32, dest.layout.size), dest)?; + } + } + } + "strlen" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let n = this.memory().read_c_str(ptr)?.len(); From 9f24c126249990f337f7e940b586a1424081d9c6 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 8 Oct 2019 15:06:14 -0500 Subject: [PATCH 1188/5092] Add helper function to write structs --- src/helpers.rs | 38 +++++++++++++++++++++++++++- src/shims/foreign_items.rs | 52 +++++--------------------------------- 2 files changed, 43 insertions(+), 47 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index c7b7853388cc..eeada36ca833 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,8 +1,11 @@ use std::mem; -use rustc::ty::{self, layout::{self, Size, Align}}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; +use rustc::ty::{ + self, + layout::{self, Align, Size, LayoutOf}, +}; use rand::RngCore; @@ -304,4 +307,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { self.eval_libc(name)?.to_i32() } + + fn write_c_ints( + &mut self, + ptr: &Pointer, + bits: &[i128], + ty_names: &[&str], + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let tcx = &{ this.tcx.tcx }; + + let mut sizes = Vec::new(); + + for name in ty_names { + let ty = this.resolve_path(&["libc", name])?.ty(*tcx); + sizes.push(this.layout_of(ty)?.size); + } + + let allocation = this.memory_mut().get_mut(ptr.alloc_id)?; + let mut offset = Size::from_bytes(0); + + for (value, size) in bits.iter().zip(sizes) { + allocation.write_scalar( + tcx, + ptr.offset(offset, tcx)?, + Scalar::from_int(*value, size).into(), + size, + )?; + offset += size; + } + + Ok(()) + } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 656cb0101020..edf151f44ef6 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -511,8 +511,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if !this.machine.communicate { throw_unsup_format!("`clock_gettime` not available when isolation is enabled") } else { - let tcx = &{ this.tcx.tcx }; - let clk_id = this.read_scalar(args[0])?.to_i32()?; if clk_id != this.eval_libc_i32("CLOCK_REALTIME")? { @@ -522,14 +520,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { let tp = this.force_ptr(this.read_scalar(args[1])?.not_undef()?)?; - let long = this.resolve_path(&["libc", "c_long"])?.ty(*tcx); - let time_t = this.resolve_path(&["libc", "time_t"])?.ty(*tcx); - - let tv_sec_size = this.layout_of(time_t)?.size; - let tv_nsec_size = this.layout_of(long)?.size; - - let allocation = this.memory_mut().get_mut(tp.alloc_id)?; - let mut sign = 1; let duration = std::time::SystemTime::now() @@ -539,20 +529,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx e.duration() }); - allocation.write_scalar( - tcx, - tp, - Scalar::from_int(sign * (duration.as_secs() as i64), tv_sec_size) - .into(), - tv_sec_size, - )?; + let tv_sec = sign * (duration.as_secs() as i128); + let tv_nsec = duration.subsec_nanos() as i128; - allocation.write_scalar( - tcx, - tp.offset(tv_sec_size, tcx)?, - Scalar::from_int(duration.subsec_nanos() as i64, tv_nsec_size).into(), - tv_nsec_size, - )?; + this.write_c_ints(&tp, &[tv_sec, tv_nsec], &["time_t", "c_long"])?; this.write_scalar(Scalar::from_int(0i32, dest.layout.size), dest)?; } @@ -563,8 +543,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if !this.machine.communicate { throw_unsup_format!("`gettimeofday` not available when isolation is enabled") } else { - let tcx = &{ this.tcx.tcx }; - let tz = this.read_scalar(args[1])?.not_undef()?; // Using tz is obsolete and should always be null if !this.is_null(tz)? { @@ -574,14 +552,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { let tv = this.force_ptr(this.read_scalar(args[0])?.not_undef()?)?; - let time_t = this.resolve_path(&["libc", "time_t"])?.ty(*tcx); - let suseconds_t = this.resolve_path(&["libc", "suseconds_t"])?.ty(*tcx); - - let tv_sec_size = this.layout_of(time_t)?.size; - let tv_usec_size = this.layout_of(suseconds_t)?.size; - - let allocation = this.memory_mut().get_mut(tv.alloc_id)?; - let mut sign = 1; let duration = std::time::SystemTime::now() @@ -591,20 +561,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx e.duration() }); - allocation.write_scalar( - tcx, - tv, - Scalar::from_int(sign * (duration.as_secs() as i64), tv_sec_size) - .into(), - tv_sec_size, - )?; + let tv_sec = sign * (duration.as_secs() as i128); + let tv_usec = duration.subsec_micros() as i128; - allocation.write_scalar( - tcx, - tv.offset(tv_sec_size, tcx)?, - Scalar::from_int(duration.subsec_micros() as i64, tv_usec_size).into(), - tv_usec_size, - )?; + this.write_c_ints(&tv, &[tv_sec, tv_usec], &["time_t", "suseconds_t"])?; this.write_scalar(Scalar::from_int(0i32, dest.layout.size), dest)?; } From b8ee90d22eff95f02d78f628e4f2c3b71e265f1a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 9 Oct 2019 10:56:47 -0500 Subject: [PATCH 1189/5092] Throw error instead of panicking for unfittable bits --- src/helpers.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index eeada36ca833..fea2307dcca5 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -4,7 +4,7 @@ use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc::ty::{ self, - layout::{self, Align, Size, LayoutOf}, + layout::{self, Align, LayoutOf, Size}, }; use rand::RngCore; @@ -328,11 +328,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let allocation = this.memory_mut().get_mut(ptr.alloc_id)?; let mut offset = Size::from_bytes(0); - for (value, size) in bits.iter().zip(sizes) { + for (&value, size) in bits.iter().zip(sizes) { + // If `value` does not fit in `size` bits, we error instead of letting + // `Scalar::from_int` panic. + let truncated = truncate(value as u128, size); + if sign_extend(truncated, size) as i128 != value { + throw_unsup_format!( + "Signed value {:#x} does not fit in {} bits", + value, + size.bits() + ) + } + allocation.write_scalar( tcx, ptr.offset(offset, tcx)?, - Scalar::from_int(*value, size).into(), + Scalar::from_int(value, size).into(), size, )?; offset += size; From 8f4d185d1b39b98846895b06d4a29525365eba4f Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 10 Oct 2019 15:41:32 -0500 Subject: [PATCH 1190/5092] Move time related functions to its own module --- src/lib.rs | 1 + src/shims/foreign_items.rs | 62 ++----------------------------- src/shims/mod.rs | 1 + src/shims/time.rs | 75 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 81 insertions(+), 58 deletions(-) create mode 100644 src/shims/time.rs diff --git a/src/lib.rs b/src/lib.rs index baae26d91ada..06ec33a914bf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,6 +32,7 @@ pub use crate::shims::{EvalContextExt as ShimsEvalContextExt}; pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextExt; pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; +pub use crate::shims::time::{EvalContextExt as TimeEvalContextExt}; pub use crate::shims::dlsym::{Dlsym, EvalContextExt as DlsymEvalContextExt}; pub use crate::shims::env::{EnvVars, EvalContextExt as EnvEvalContextExt}; pub use crate::shims::fs::{FileHandler, EvalContextExt as FileEvalContextExt}; diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index edf151f44ef6..f6195961ba06 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -508,67 +508,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "clock_gettime" => { - if !this.machine.communicate { - throw_unsup_format!("`clock_gettime` not available when isolation is enabled") - } else { - let clk_id = this.read_scalar(args[0])?.to_i32()?; - - if clk_id != this.eval_libc_i32("CLOCK_REALTIME")? { - let einval = this.eval_libc("EINVAL")?; - this.set_last_error(einval)?; - this.write_scalar(Scalar::from_int(-1i32, dest.layout.size), dest)?; - } else { - let tp = this.force_ptr(this.read_scalar(args[1])?.not_undef()?)?; - - let mut sign = 1; - - let duration = std::time::SystemTime::now() - .duration_since(std::time::SystemTime::UNIX_EPOCH) - .unwrap_or_else(|e| { - sign = -1; - e.duration() - }); - - let tv_sec = sign * (duration.as_secs() as i128); - let tv_nsec = duration.subsec_nanos() as i128; - - this.write_c_ints(&tp, &[tv_sec, tv_nsec], &["time_t", "c_long"])?; - - this.write_scalar(Scalar::from_int(0i32, dest.layout.size), dest)?; - } - } + let result = this.clock_gettime(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } "gettimeofday" => { - if !this.machine.communicate { - throw_unsup_format!("`gettimeofday` not available when isolation is enabled") - } else { - let tz = this.read_scalar(args[1])?.not_undef()?; - // Using tz is obsolete and should always be null - if !this.is_null(tz)? { - let einval = this.eval_libc("EINVAL")?; - this.set_last_error(einval)?; - this.write_scalar(Scalar::from_int(-1i32, dest.layout.size), dest)?; - } else { - let tv = this.force_ptr(this.read_scalar(args[0])?.not_undef()?)?; - - let mut sign = 1; - - let duration = std::time::SystemTime::now() - .duration_since(std::time::SystemTime::UNIX_EPOCH) - .unwrap_or_else(|e| { - sign = -1; - e.duration() - }); - - let tv_sec = sign * (duration.as_secs() as i128); - let tv_usec = duration.subsec_micros() as i128; - - this.write_c_ints(&tv, &[tv_sec, tv_usec], &["time_t", "suseconds_t"])?; - - this.write_scalar(Scalar::from_int(0i32, dest.layout.size), dest)?; - } - } + let result = this.gettimeofday(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } "strlen" => { diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 6d80af46850c..95bb8b70370f 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -4,6 +4,7 @@ pub mod foreign_items; pub mod intrinsics; pub mod tls; pub mod fs; +pub mod time; use rustc::{mir, ty}; diff --git a/src/shims/time.rs b/src/shims/time.rs new file mode 100644 index 000000000000..97b74542d809 --- /dev/null +++ b/src/shims/time.rs @@ -0,0 +1,75 @@ +use crate::stacked_borrows::Tag; +use crate::*; + +use std::time::{Duration, SystemTime}; + +fn get_time() -> (Duration, i128) { + let mut sign = 1; + let duration = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap_or_else(|e| { + sign = -1; + e.duration() + }); + (duration, sign) +} + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn clock_gettime( + &mut self, + clk_id_op: OpTy<'tcx, Tag>, + tp_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + if !this.machine.communicate { + throw_unsup_format!("`clock_gettime` not available when isolation is enabled") + } + + let clk_id = this.read_scalar(clk_id_op)?.to_i32()?; + if clk_id != this.eval_libc_i32("CLOCK_REALTIME")? { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + return Ok(-1); + } + + let tp = this.force_ptr(this.read_scalar(tp_op)?.not_undef()?)?; + + let (duration, sign) = get_time(); + let tv_sec = sign * (duration.as_secs() as i128); + let tv_nsec = duration.subsec_nanos() as i128; + this.write_c_ints(&tp, &[tv_sec, tv_nsec], &["time_t", "c_long"])?; + + Ok(0) + } + + fn gettimeofday( + &mut self, + tv_op: OpTy<'tcx, Tag>, + tz_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + if !this.machine.communicate { + throw_unsup_format!("`gettimeofday` not available when isolation is enabled") + } + // Using tz is obsolete and should always be null + let tz = this.read_scalar(tz_op)?.not_undef()?; + if !this.is_null(tz)? { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + return Ok(-1); + } + + let tv = this.force_ptr(this.read_scalar(tv_op)?.not_undef()?)?; + + let (duration, sign) = get_time(); + let tv_sec = sign * (duration.as_secs() as i128); + let tv_usec = duration.subsec_micros() as i128; + + this.write_c_ints(&tv, &[tv_sec, tv_usec], &["time_t", "suseconds_t"])?; + + Ok(0) + } +} From 87b210df6c4ee3cd823f3d0a4a6940084e765c82 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 00:03:54 -0500 Subject: [PATCH 1191/5092] Fix sign when number of seconds is zero --- src/shims/time.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index 97b74542d809..2995bdc43464 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -16,6 +16,7 @@ fn get_time() -> (Duration, i128) { impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + // Foreign function used by linux fn clock_gettime( &mut self, clk_id_op: OpTy<'tcx, Tag>, @@ -38,12 +39,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (duration, sign) = get_time(); let tv_sec = sign * (duration.as_secs() as i128); - let tv_nsec = duration.subsec_nanos() as i128; + let mut tv_nsec = duration.subsec_nanos() as i128; + // If the number of seconds is zero, we need to put the sign into the second's fraction. + if tv_sec == 0 && sign < 0 { + tv_nsec *= sign; + } + this.write_c_ints(&tp, &[tv_sec, tv_nsec], &["time_t", "c_long"])?; Ok(0) } - + // Foreign function used by generic unix fn gettimeofday( &mut self, tv_op: OpTy<'tcx, Tag>, @@ -66,7 +72,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (duration, sign) = get_time(); let tv_sec = sign * (duration.as_secs() as i128); - let tv_usec = duration.subsec_micros() as i128; + let mut tv_usec = duration.subsec_micros() as i128; + // If the number of seconds is zero, we need to put the sign into the second's fraction. + if tv_sec == 0 && sign < 0 { + tv_usec *= sign; + } this.write_c_ints(&tv, &[tv_sec, tv_usec], &["time_t", "suseconds_t"])?; From 2cbf4afa99a1a8953ed54abdcb292b45b79a8639 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 00:55:32 -0500 Subject: [PATCH 1192/5092] Split `write_c_ints` into less specific helper functions --- src/helpers.rs | 39 +++++++++++++++------------------------ src/shims/time.rs | 40 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 51 insertions(+), 28 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index fea2307dcca5..892ba7b2401b 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -4,7 +4,7 @@ use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc::ty::{ self, - layout::{self, Align, LayoutOf, Size}, + layout::{self, Align, LayoutOf, Size, TyLayout}, }; use rand::RngCore; @@ -308,42 +308,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx self.eval_libc(name)?.to_i32() } - fn write_c_ints( + // Writes several `ImmTy`s contiguosly into memory. This is useful when you have to pack + // different values into an struct. + fn write_immediates( &mut self, ptr: &Pointer, - bits: &[i128], - ty_names: &[&str], + imms: &[ImmTy<'tcx, Tag>], ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let tcx = &{ this.tcx.tcx }; - let mut sizes = Vec::new(); - - for name in ty_names { - let ty = this.resolve_path(&["libc", name])?.ty(*tcx); - sizes.push(this.layout_of(ty)?.size); - } - let allocation = this.memory_mut().get_mut(ptr.alloc_id)?; let mut offset = Size::from_bytes(0); - for (&value, size) in bits.iter().zip(sizes) { - // If `value` does not fit in `size` bits, we error instead of letting - // `Scalar::from_int` panic. - let truncated = truncate(value as u128, size); - if sign_extend(truncated, size) as i128 != value { - throw_unsup_format!( - "Signed value {:#x} does not fit in {} bits", - value, - size.bits() - ) - } - + for imm in imms { + let size = imm.layout.size; allocation.write_scalar( tcx, ptr.offset(offset, tcx)?, - Scalar::from_int(value, size).into(), + imm.to_scalar()?.into(), size, )?; offset += size; @@ -351,4 +335,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } + + fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyLayout<'tcx>> { + let this = self.eval_context_mut(); + let tcx = &{ this.tcx.tcx }; + let ty = this.resolve_path(&["libc", name])?.ty(*tcx); + this.layout_of(ty) + } } diff --git a/src/shims/time.rs b/src/shims/time.rs index 2995bdc43464..3acc84dbc751 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -1,8 +1,12 @@ +use std::time::{Duration, SystemTime}; + +use rustc::ty::layout::TyLayout; + use crate::stacked_borrows::Tag; use crate::*; -use std::time::{Duration, SystemTime}; - +// Returns the time elapsed between now and the unix epoch as a `Duration` and the sign of the time +// interval fn get_time() -> (Duration, i128) { let mut sign = 1; let duration = SystemTime::now() @@ -14,6 +18,24 @@ fn get_time() -> (Duration, i128) { (duration, sign) } +fn int_to_immty_checked<'tcx>( + int: i128, + layout: TyLayout<'tcx>, +) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { + // If `int` does not fit in `size` bits, we error instead of letting + // `ImmTy::from_int` panic. + let size = layout.size; + let truncated = truncate(int as u128, size); + if sign_extend(truncated, size) as i128 != int { + throw_unsup_format!( + "Signed value {:#x} does not fit in {} bits", + int, + size.bits() + ) + } + Ok(ImmTy::from_int(int, layout)) +} + impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { // Foreign function used by linux @@ -45,7 +67,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx tv_nsec *= sign; } - this.write_c_ints(&tp, &[tv_sec, tv_nsec], &["time_t", "c_long"])?; + let imms = [ + int_to_immty_checked(tv_sec, this.libc_ty_layout("time_t")?)?, + int_to_immty_checked(tv_nsec, this.libc_ty_layout("c_long")?)?, + ]; + + this.write_immediates(&tp, &imms)?; Ok(0) } @@ -78,7 +105,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx tv_usec *= sign; } - this.write_c_ints(&tv, &[tv_sec, tv_usec], &["time_t", "suseconds_t"])?; + let imms = [ + int_to_immty_checked(tv_sec, this.libc_ty_layout("time_t")?)?, + int_to_immty_checked(tv_usec, this.libc_ty_layout("suseconds_t")?)?, + ]; + + this.write_immediates(&tv, &imms)?; Ok(0) } From a1c6797c5c145f597e37dae53031babb0aaf7735 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 05:30:50 -0500 Subject: [PATCH 1193/5092] Error when there is an unsupported flag --- src/shims/fs.rs | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 7e684489b5c9..a6a1eb947b0b 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -44,7 +44,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut options = OpenOptions::new(); - // The first two bits of the flag correspond to the access mode of the file in linux. + // The first two bits of the flag correspond to the access mode of the file in linux. This + // is done this way because `O_RDONLY` is zero in several platforms. let access_mode = flag & 0b11; if access_mode == this.eval_libc_i32("O_RDONLY")? { @@ -56,15 +57,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { throw_unsup_format!("Unsupported access mode {:#x}", access_mode); } + // We need to check that there aren't unsupported options in `flag`. For this we try to + // reproduce the content of `flag` in the `mirror` variable using only the supported + // options. + let mut mirror = access_mode; - if flag & this.eval_libc_i32("O_APPEND")? != 0 { + let o_append = this.eval_libc_i32("O_APPEND")?; + if flag & o_append != 0 { options.append(true); + mirror |= o_append; } - if flag & this.eval_libc_i32("O_TRUNC")? != 0 { + let o_trunc = this.eval_libc_i32("O_TRUNC")?; + if flag & o_trunc != 0 { options.truncate(true); + mirror |= o_trunc; } - if flag & this.eval_libc_i32("O_CREAT")? != 0 { + let o_creat = this.eval_libc_i32("O_CREAT")?; + if flag & o_creat != 0 { options.create(true); + mirror |= o_creat; + } + let o_cloexec = this.eval_libc_i32("O_CLOEXEC")?; + if flag & o_cloexec != 0 { + // This flag is a noop for now because `std` already sets it. + mirror |= o_cloexec; + } + // If `flag` is not equal to `mirror`, there is an unsupported option enabled in `flag`, + // then we throw an error. + if flag != mirror { + throw_unsup_format!("unsupported flags {:#x}", flag); } let path_bytes = this From d73fae1b28b3a12a5c22df71fc7be5fdb5f66e67 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 12:17:54 -0500 Subject: [PATCH 1194/5092] Remove F_SETFD command --- src/shims/fs.rs | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index a6a1eb947b0b..443a61c46e9a 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -108,7 +108,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, fd_op: OpTy<'tcx, Tag>, cmd_op: OpTy<'tcx, Tag>, - arg_op: Option>, + _arg_op: Option>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -118,29 +118,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; let cmd = this.read_scalar(cmd_op)?.to_i32()?; - - if cmd == this.eval_libc_i32("F_SETFD")? { - // This does not affect the file itself. Certain flags might require changing the file - // or the way it is accessed somehow. - let flag = this.read_scalar(arg_op.unwrap())?.to_i32()?; - // The only usage of this in stdlib at the moment is to enable the `FD_CLOEXEC` flag. - let fd_cloexec = this.eval_libc_i32("FD_CLOEXEC")?; - if let Some(FileHandle { flag: old_flag, .. }) = - this.machine.file_handler.handles.get_mut(&fd) - { - // Check that the only difference between the old flag and the current flag is - // exactly the `FD_CLOEXEC` value. - if flag ^ *old_flag == fd_cloexec { - *old_flag = flag; - } else { - throw_unsup_format!("Unsupported arg {:#x} for `F_SETFD`", flag); - } - } - Ok(0) - } else if cmd == this.eval_libc_i32("F_GETFD")? { + // We only support getting the flags for a descriptor + if cmd == this.eval_libc_i32("F_GETFD")? { this.get_handle_and(fd, |handle| Ok(handle.flag)) } else { - throw_unsup_format!("Unsupported command {:#x}", cmd); + throw_unsup_format!("The {:#x} command is not supported for `fcntl`)", cmd); } } From 9082092a71edf130aecbde147a5b27b2a50e1fd7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 11 Oct 2019 23:02:04 +0200 Subject: [PATCH 1195/5092] use temp_dir for FS test --- tests/run-pass/fs.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 98f3c1089bb7..212e5e27d8aa 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -5,16 +5,16 @@ use std::fs::{File, remove_file}; use std::io::{Read, Write}; fn main() { - let path = "miri_test_fs.txt"; + let path = std::env::temp_dir().join("miri_test_fs.txt"); let bytes = b"Hello, World!\n"; // Test creating, writing and closing a file (closing is tested when `file` is dropped). - let mut file = File::create(path).unwrap(); + let mut file = File::create(&path).unwrap(); // Writing 0 bytes should not change the file contents. file.write(&mut []).unwrap(); file.write(bytes).unwrap(); // Test opening, reading and closing a file. - let mut file = File::open(path).unwrap(); + let mut file = File::open(&path).unwrap(); let mut contents = Vec::new(); // Reading 0 bytes should not move the file pointer. file.read(&mut []).unwrap(); @@ -22,9 +22,9 @@ fn main() { file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); // Removing file should succeed - remove_file(path).unwrap(); + remove_file(&path).unwrap(); // Opening non-existing file should fail - assert!(File::open(path).is_err()); + assert!(File::open(&path).is_err()); // Removing non-existing file should fail - assert!(remove_file(path).is_err()); + assert!(remove_file(&path).is_err()); } From 7f28d9631e01cd39ea6e687268ba87c1f77a574b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Oct 2019 17:51:10 +0200 Subject: [PATCH 1196/5092] hopefully harmless Rust bump --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index db6f5ebe88c4..fef9820f7e1a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -2748a9fd93dd1a00a4521f4f16de5befbf77f6cd +898f36c83cc28d7921a1d7b3605323dc5cfcf533 From 19fb53e8a3e72159c2105d497fd23d4d4f34ee3a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Oct 2019 18:11:44 +0200 Subject: [PATCH 1197/5092] better debugging for sysroot check --- src/bin/cargo-miri.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 43e8761d48c1..30b1d863e0ca 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -136,8 +136,12 @@ fn test_sysroot_consistency() { .output().expect("Failed to run rustc to get sysroot info"); let stdout = String::from_utf8(out.stdout).expect("stdout is not valid UTF-8"); let stderr = String::from_utf8(out.stderr).expect("stderr is not valid UTF-8"); + assert!( + out.status.success(), + "Bad status code {} when getting sysroot info via {:?}.\nstdout:\n{}\nstderr:\n{}", + out.status, cmd, stdout, stderr, + ); let stdout = stdout.trim(); - assert!(out.status.success(), "Bad status code when getting sysroot info.\nstdout:\n{}\nstderr:\n{}", stdout, stderr); PathBuf::from(stdout).canonicalize() .unwrap_or_else(|_| panic!("Failed to canonicalize sysroot: {}", stdout)) } From 508df227e5f4820f1d600b72e626a620b2c714af Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 12 Oct 2019 19:48:18 -0500 Subject: [PATCH 1198/5092] Group libc helper functions --- src/helpers.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 892ba7b2401b..3012b1a95541 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -308,8 +308,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx self.eval_libc(name)?.to_i32() } + /// Helper function to get the `TyLayout` of a `libc` type + fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyLayout<'tcx>> { + let this = self.eval_context_mut(); + let tcx = &{ this.tcx.tcx }; + let ty = this.resolve_path(&["libc", name])?.ty(*tcx); + this.layout_of(ty) + } + // Writes several `ImmTy`s contiguosly into memory. This is useful when you have to pack - // different values into an struct. + // different values into a struct. fn write_immediates( &mut self, ptr: &Pointer, @@ -335,11 +343,4 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - - fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyLayout<'tcx>> { - let this = self.eval_context_mut(); - let tcx = &{ this.tcx.tcx }; - let ty = this.resolve_path(&["libc", name])?.ty(*tcx); - this.layout_of(ty) - } } From f76f8ce63bc160b127356c01624bbc8442844c22 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 12 Oct 2019 20:12:26 -0500 Subject: [PATCH 1199/5092] Correct fcntl behavior --- src/shims/fs.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 443a61c46e9a..4d93ca4fd31b 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -9,7 +9,6 @@ use crate::*; pub struct FileHandle { file: File, - flag: i32, } pub struct FileHandler { @@ -79,13 +78,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let o_cloexec = this.eval_libc_i32("O_CLOEXEC")?; if flag & o_cloexec != 0 { - // This flag is a noop for now because `std` already sets it. + // We do not need to do anything for this flag because `std` already sets it. + // (Technically we do not support *not* setting this flag, but we ignore that.) mirror |= o_cloexec; } // If `flag` is not equal to `mirror`, there is an unsupported option enabled in `flag`, // then we throw an error. if flag != mirror { - throw_unsup_format!("unsupported flags {:#x}", flag); + throw_unsup_format!("unsupported flags {:#x}", flag & !mirror); } let path_bytes = this @@ -97,7 +97,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = options.open(path).map(|file| { let mut fh = &mut this.machine.file_handler; fh.low += 1; - fh.handles.insert(fh.low, FileHandle { file, flag }); + fh.handles.insert(fh.low, FileHandle { file }); fh.low }); @@ -108,7 +108,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, fd_op: OpTy<'tcx, Tag>, cmd_op: OpTy<'tcx, Tag>, - _arg_op: Option>, + _arg1_op: Option>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -120,7 +120,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let cmd = this.read_scalar(cmd_op)?.to_i32()?; // We only support getting the flags for a descriptor if cmd == this.eval_libc_i32("F_GETFD")? { - this.get_handle_and(fd, |handle| Ok(handle.flag)) + // Currently this is the only flag that `F_GETFD` returns. It is OK to just return the + // `FD_CLOEXEC` value without checking if the flag is set for the file because `std` + // always sets this flag when opening a file. However we still need to check that the + // file itself is open. + this.get_handle_and(fd, |_| Ok(0))?; + this.eval_libc_i32("FD_CLOEXEC") } else { throw_unsup_format!("The {:#x} command is not supported for `fcntl`)", cmd); } From 50618b55cd8c2cd8da905697fe80e5f3a519fb3b Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sun, 13 Oct 2019 16:06:37 -0500 Subject: [PATCH 1200/5092] Error on negative times --- src/shims/time.rs | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index 3acc84dbc751..1b799b1330aa 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -7,15 +7,10 @@ use crate::*; // Returns the time elapsed between now and the unix epoch as a `Duration` and the sign of the time // interval -fn get_time() -> (Duration, i128) { - let mut sign = 1; - let duration = SystemTime::now() +fn get_time<'tcx>() -> InterpResult<'tcx, Duration> { + SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH) - .unwrap_or_else(|e| { - sign = -1; - e.duration() - }); - (duration, sign) + .map_err(|_| err_unsup_format!("Time went backwards").into()) } fn int_to_immty_checked<'tcx>( @@ -59,13 +54,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tp = this.force_ptr(this.read_scalar(tp_op)?.not_undef()?)?; - let (duration, sign) = get_time(); - let tv_sec = sign * (duration.as_secs() as i128); - let mut tv_nsec = duration.subsec_nanos() as i128; - // If the number of seconds is zero, we need to put the sign into the second's fraction. - if tv_sec == 0 && sign < 0 { - tv_nsec *= sign; - } + let duration = get_time()?; + let tv_sec = duration.as_secs() as i128; + let tv_nsec = duration.subsec_nanos() as i128; let imms = [ int_to_immty_checked(tv_sec, this.libc_ty_layout("time_t")?)?, @@ -97,13 +88,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tv = this.force_ptr(this.read_scalar(tv_op)?.not_undef()?)?; - let (duration, sign) = get_time(); - let tv_sec = sign * (duration.as_secs() as i128); - let mut tv_usec = duration.subsec_micros() as i128; - // If the number of seconds is zero, we need to put the sign into the second's fraction. - if tv_sec == 0 && sign < 0 { - tv_usec *= sign; - } + let duration = get_time()?; + let tv_sec = duration.as_secs() as i128; + let tv_usec = duration.subsec_micros() as i128; let imms = [ int_to_immty_checked(tv_sec, this.libc_ty_layout("time_t")?)?, From d5003bc07de502267aa2588630c3345c6e05a136 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 14 Oct 2019 09:38:08 +0200 Subject: [PATCH 1201/5092] add lockfile --- .gitignore | 1 - Cargo.lock | 901 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 901 insertions(+), 1 deletion(-) create mode 100644 Cargo.lock diff --git a/.gitignore b/.gitignore index ca23de420882..389565791c00 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,3 @@ target tex/*/out *.dot *.rs.bk -Cargo.lock diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 000000000000..b498f9efd922 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,901 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "aho-corasick" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "approx" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "arrayref" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "arrayvec" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "atty" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "autocfg" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "backtrace" +version = "0.3.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace-sys" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "base64" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bitflags" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "blake2b_simd" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "byteorder" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "c2-chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cargo_metadata" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cc" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cgmath" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "chrono" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "colored" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winconsole 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "compiletest_rs" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustfix 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "crossbeam-utils" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "diff" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "directories" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "dirs-sys" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "env_logger" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure_derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "filetime" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "getrandom" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hex" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "humantime" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itoa" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.62" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "log" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "memchr" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "miow" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "miri" +version = "0.1.0" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo_metadata 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "compiletest_rs 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", + "directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "nodrop" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "num-integer" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro2" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quick-error" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_chacha" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand_core" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "redox_syscall" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "redox_users" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "remove_dir_all" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rgb" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rust-argon2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2b_simd 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rustc-workspace-hack" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustfix" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ryu" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_derive" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_json" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "shell-escape" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "socket2" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "synstructure" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tempfile" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "termcolor" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread_local" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "time" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-width" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "vergen" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasi" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "wincolor" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winconsole" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rgb 0.8.14 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[metadata] +"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" +"checksum approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08abcc3b4e9339e33a3d0a5ed15d84a687350c05689d825e0f6655eef9e76a94" +"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" +"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" +"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" +"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" +"checksum backtrace 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "1371048253fa3bac6704bfd6bbfc922ee9bdcee8881330d40f308b81cc5adc55" +"checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b" +"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" +"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" +"checksum blake2b_simd 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bf775a81bb2d464e20ff170ac20316c7b08a43d11dbc72f0f82e8e8d3d6d0499" +"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" +"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" +"checksum cargo_metadata 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "700b3731fd7d357223d0000f4dbf1808401b694609035c3c411fbc0cd375c426" +"checksum cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "b548a4ee81fccb95919d4e22cfea83c7693ebfd78f0495493178db20b3139da7" +"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" +"checksum cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64a4b57c8f4e3a2e9ac07e0f6abc9c24b6fc9e1b54c3478cfb598f3d0023e51c" +"checksum chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "77d81f58b7301084de3b958691458a53c3f7e0b1d702f77e550b6a88e3a88abe" +"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +"checksum colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6cdb90b60f2927f8d76139c72dbde7e10c3a2bc47c8594c9c7a66529f2687c03" +"checksum compiletest_rs 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "eb783fe7afb90ec3d3e49ccaf9196d29ab63c6ed61d4b0695839daa580ae3a3d" +"checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120" +"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" +"checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" +"checksum directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c" +"checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" +"checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" +"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" +"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" +"checksum filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6bd7380b54ced79dda72ecc35cc4fbbd1da6bba54afaa37e96fd1c2a308cd469" +"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +"checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +"checksum getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "fc344b02d3868feb131e8b5fe2b9b0a1cc42942679af493061fc13b853243872" +"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" +"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" +"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" +"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" +"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" +"checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226" +"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" +"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" +"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" +"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" +"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" +"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +"checksum proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c5c2380ae88876faae57698be9e9775e3544decad214599c3a6266cca6ac802" +"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" +"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +"checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" +"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" +"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" +"checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" +"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" +"checksum redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecedbca3bf205f8d8f5c2b44d83cd0690e39ee84b951ed649e9f1841132b66d" +"checksum regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88c3d9193984285d544df4a30c23a4e62ead42edf70a4452ceb76dac1ce05c26" +"checksum regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b143cceb2ca5e56d5671988ef8b15615733e7ee16cd348e064333b251b89343f" +"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" +"checksum rgb 0.8.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2089e4031214d129e201f8c3c8c2fe97cd7322478a0d1cdf78e7029b0042efdb" +"checksum rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf" +"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" +"checksum rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum rustfix 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7150ac777a2931a53489f5a41eb0937b84e3092a20cd0e73ad436b65b507f607" +"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "fec2851eb56d010dc9a21b89ca53ee75e6528bab60c11e89d38390904982da9f" +"checksum serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "cb4dc18c61206b08dc98216c98faa0232f4337e1e1b8574551d5bad29ea1b425" +"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" +"checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9" +"checksum socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e8b74de517221a2cb01a53349cf54182acdc31a074727d3079068448c0676d85" +"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" +"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" +"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" +"checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" +"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" +"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" +"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" +"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +"checksum vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6aba5e34f93dc7051dfad05b98a18e9156f27e7b431fe1d2398cb6061c0a1dba" +"checksum wasi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd5442abcac6525a045cc8c795aedb60da7a2e5e89c7bf18a0d5357849bb23c7" +"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9" +"checksum winconsole 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ef84b96d10db72dd980056666d7f1e7663ce93d82fa33b63e71c966f4cf5032" From 917effada1e970e964520f56431119b7f6b332c9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 14 Oct 2019 09:40:11 +0200 Subject: [PATCH 1202/5092] CI: force using locked versions --- .appveyor.yml | 4 ++-- travis.sh | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index c3d575403cb3..582b55f62dbb 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -36,7 +36,7 @@ install: build_script: - set RUSTFLAGS=-C debug-assertions # Build and install miri - - cargo build --release --all-features --all-targets + - cargo build --release --all-features --all-targets --locked - cargo install --all-features --force --path . --locked --offline # Get ourselves a MIR-full libstd, and use it henceforth - cargo miri setup @@ -46,7 +46,7 @@ test_script: - set RUST_TEST_NOCAPTURE=1 - set RUST_BACKTRACE=1 # Test miri - - cargo test --release --all-features + - cargo test --release --all-features --locked # Test cargo integration - cd test-cargo-miri - '"C:\msys64\mingw64\bin\python3.exe" run-test.py' diff --git a/travis.sh b/travis.sh index 6f14be44ef0a..af297129e821 100755 --- a/travis.sh +++ b/travis.sh @@ -12,13 +12,13 @@ export RUSTC_EXTRA_FLAGS="-D warnings" # Prepare echo "Build and install miri" -./miri build --all-targets -./miri install +./miri build --all-targets --locked +./miri install # implicitly locked echo # Test function run_tests { - ./miri test + ./miri test --locked # "miri test" has built the sysroot for us, now this should pass without # any interactive questions. test-cargo-miri/run-test.py From d4d80cbecb592750693499717f5cd2f616b9059a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 14 Oct 2019 13:15:44 +0200 Subject: [PATCH 1203/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index fef9820f7e1a..820490edd618 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -898f36c83cc28d7921a1d7b3605323dc5cfcf533 +d28a9c38fe14396e86ae274c7847e20ee0f78ca9 From d8f06523f26ffc5a12d347fb6934e8b7a28e8a2c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 14 Oct 2019 13:17:30 +0200 Subject: [PATCH 1204/5092] bump compiletest --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b498f9efd922..8d80f1f11cd1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -158,7 +158,7 @@ dependencies = [ [[package]] name = "compiletest_rs" -version = "0.3.23" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -338,7 +338,7 @@ dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "compiletest_rs 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", + "compiletest_rs 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -822,7 +822,7 @@ dependencies = [ "checksum chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "77d81f58b7301084de3b958691458a53c3f7e0b1d702f77e550b6a88e3a88abe" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6cdb90b60f2927f8d76139c72dbde7e10c3a2bc47c8594c9c7a66529f2687c03" -"checksum compiletest_rs 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "eb783fe7afb90ec3d3e49ccaf9196d29ab63c6ed61d4b0695839daa580ae3a3d" +"checksum compiletest_rs 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "676a74b493d50ac33cacd83fd536597e6b52c0b46b9856f7b9c809d82fef4ac0" "checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120" "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" "checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" diff --git a/Cargo.toml b/Cargo.toml index 5a5c774169cf..bd345ea2b7f5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,5 +59,5 @@ cargo_miri = ["cargo_metadata", "directories", "rustc_version"] rustc_tests = [] [dev-dependencies] -compiletest_rs = { version = "0.3.23", features = ["tmp"] } +compiletest_rs = { version = "0.3.24", features = ["tmp"] } colored = "1.6" From f425f445d14007d3a3dd10c7f0ca90177b9dee2e Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sun, 13 Oct 2019 14:48:07 -0500 Subject: [PATCH 1205/5092] Check that fs errors have the proper kind --- tests/run-pass/fs.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 212e5e27d8aa..7765e5b368e8 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -2,7 +2,7 @@ // compile-flags: -Zmiri-disable-isolation use std::fs::{File, remove_file}; -use std::io::{Read, Write}; +use std::io::{Read, Write, ErrorKind}; fn main() { let path = std::env::temp_dir().join("miri_test_fs.txt"); @@ -23,8 +23,10 @@ fn main() { assert_eq!(bytes, contents.as_slice()); // Removing file should succeed remove_file(&path).unwrap(); - // Opening non-existing file should fail - assert!(File::open(&path).is_err()); - // Removing non-existing file should fail - assert!(remove_file(&path).is_err()); + + // The two following tests also check that the `__errno_location()` shim is working properly. + // Opening a non-existing file should fail with a "not found" error. + assert_eq!(ErrorKind::NotFound, File::open(&path).unwrap_err().kind()); + // Removing a non-existing file should fail with a "not found" error. + assert_eq!(ErrorKind::NotFound, remove_file(&path).unwrap_err().kind()); } From f9c768864a7784c518b6ac1af6515950c6eff6ec Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 14 Oct 2019 09:08:39 -0500 Subject: [PATCH 1206/5092] Use places instead of ptrs to write packed immtys --- src/helpers.rs | 18 +++++++----------- src/shims/time.rs | 12 ++++++------ tests/run-pass/clock.rs | 1 + 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 3012b1a95541..9107958e010c 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -318,27 +318,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Writes several `ImmTy`s contiguosly into memory. This is useful when you have to pack // different values into a struct. - fn write_immediates( + fn write_packed_immediates( &mut self, - ptr: &Pointer, + place: &MPlaceTy<'tcx, Tag>, imms: &[ImmTy<'tcx, Tag>], ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let tcx = &{ this.tcx.tcx }; - let allocation = this.memory_mut().get_mut(ptr.alloc_id)?; let mut offset = Size::from_bytes(0); - for imm in imms { - let size = imm.layout.size; - allocation.write_scalar( - tcx, - ptr.offset(offset, tcx)?, - imm.to_scalar()?.into(), - size, + for &imm in imms { + this.write_immediate_to_mplace( + *imm, + place.offset(offset, None, imm.layout, tcx)?, )?; - offset += size; + offset += imm.layout.size; } Ok(()) diff --git a/src/shims/time.rs b/src/shims/time.rs index 1b799b1330aa..0153c1a912df 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -10,7 +10,7 @@ use crate::*; fn get_time<'tcx>() -> InterpResult<'tcx, Duration> { SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH) - .map_err(|_| err_unsup_format!("Time went backwards").into()) + .map_err(|_| err_unsup_format!("Times before the Unix epoch are not supported").into()) } fn int_to_immty_checked<'tcx>( @@ -52,7 +52,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } - let tp = this.force_ptr(this.read_scalar(tp_op)?.not_undef()?)?; + let tp = this.deref_operand(tp_op)?; let duration = get_time()?; let tv_sec = duration.as_secs() as i128; @@ -63,11 +63,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx int_to_immty_checked(tv_nsec, this.libc_ty_layout("c_long")?)?, ]; - this.write_immediates(&tp, &imms)?; + this.write_packed_immediates(&tp, &imms)?; Ok(0) } - // Foreign function used by generic unix + // Foreign function used by generic unix (in particular macOS) fn gettimeofday( &mut self, tv_op: OpTy<'tcx, Tag>, @@ -86,7 +86,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } - let tv = this.force_ptr(this.read_scalar(tv_op)?.not_undef()?)?; + let tv = this.deref_operand(tv_op)?; let duration = get_time()?; let tv_sec = duration.as_secs() as i128; @@ -97,7 +97,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx int_to_immty_checked(tv_usec, this.libc_ty_layout("suseconds_t")?)?, ]; - this.write_immediates(&tv, &imms)?; + this.write_packed_immediates(&tv, &imms)?; Ok(0) } diff --git a/tests/run-pass/clock.rs b/tests/run-pass/clock.rs index 987a78fe1f05..23f45f91ada1 100644 --- a/tests/run-pass/clock.rs +++ b/tests/run-pass/clock.rs @@ -1,3 +1,4 @@ +// ignore-windows: TODO clock shims are not implemented on Windows // compile-flags: -Zmiri-disable-isolation use std::time::SystemTime; From e06ce728ca49fc647ea1dfbb609116d76385446c Mon Sep 17 00:00:00 2001 From: YOUNGSUK_KIM Date: Mon, 14 Oct 2019 20:57:57 -0400 Subject: [PATCH 1207/5092] Ralf Jung's great idea! --- src/bin/cargo-miri.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 521ac8fa065c..3af5a2b35db3 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -333,11 +333,11 @@ path = "lib.rs" None => true, Some(target) => target == rustc_version::version_meta().unwrap().host, }; - let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; - + let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; + std::env::set_var("MIRI_SYSROOT", &sysroot); // pass the env var to the processes we spawn, which will turn it into "--sysroot" flags if print_env { - println!("MIRI_SYSROOT={:?}", &sysroot); // for Windows users, prints path with backslashes escaped. + println!("MIRI_SYSROOT='{}'", sysroot.display().to_string().replace('\'', r#"'"'"'"#)); } else if !ask_user { println!("A libstd for Miri is now available in `{}`.", sysroot.display()); } From 65fd00665ee246a029c9b220781098277319cd6a Mon Sep 17 00:00:00 2001 From: YOUNGSUK_KIM Date: Mon, 14 Oct 2019 22:37:54 -0400 Subject: [PATCH 1208/5092] remove unnecessary line break --- src/bin/cargo-miri.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 3af5a2b35db3..479374ee4750 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -334,7 +334,6 @@ path = "lib.rs" Some(target) => target == rustc_version::version_meta().unwrap().host, }; let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; - std::env::set_var("MIRI_SYSROOT", &sysroot); // pass the env var to the processes we spawn, which will turn it into "--sysroot" flags if print_env { println!("MIRI_SYSROOT='{}'", sysroot.display().to_string().replace('\'', r#"'"'"'"#)); From 4ba63fb0fcdc6407c284bc58935c8df7b6d79c30 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 15 Oct 2019 09:50:16 +0200 Subject: [PATCH 1209/5092] explain our shell encoding --- src/bin/cargo-miri.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 14f381a45546..15c66f8c0dba 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -340,6 +340,11 @@ path = "lib.rs" let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; std::env::set_var("MIRI_SYSROOT", &sysroot); // pass the env var to the processes we spawn, which will turn it into "--sysroot" flags if print_env { + // Escape an arbitrary string for the shell: by wrapping it in `'`, the only special + // character we have to worry about is `'` itself. Everything else is taken literally + // in these strings. `'` is encoded as `'"'"'`: the outer `'` end and being a + // `'`-quoted string, respectively; the `"'"` in the middle represents a single `'`. + // (We could use `'\''` instead of `'"'"'` if we wanted but let's avoid backslashes.) println!("MIRI_SYSROOT='{}'", sysroot.display().to_string().replace('\'', r#"'"'"'"#)); } else if !ask_user { println!("A libstd for Miri is now available in `{}`.", sysroot.display()); From 78311a713218b9923cd5ab73b62a9fe2485c7d22 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 14 Oct 2019 15:36:15 -0500 Subject: [PATCH 1210/5092] Add function to error with enabled isolation --- src/helpers.rs | 9 +++++++++ src/shims/env.rs | 8 ++------ src/shims/fs.rs | 24 ++++++------------------ src/shims/time.rs | 8 ++------ 4 files changed, 19 insertions(+), 30 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 9107958e010c..e3f818414da3 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -336,7 +336,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; offset += imm.layout.size; } + Ok(()) + } + /// Helper function used inside the shims of foreign functions to check that isolation is + /// disabled. It returns an error using the `name` of the foreign function if this is not the + /// case. + fn check_no_isolation(&mut self, name: &str) -> InterpResult<'tcx> { + if !self.eval_context_mut().machine.communicate { + throw_unsup_format!("`{}` not available when isolation is enabled. Pass the flag `-Zmiri-disable-isolation` to disable it.", name) + } Ok(()) } } diff --git a/src/shims/env.rs b/src/shims/env.rs index 2ccbc0238e5f..ae800c2315fe 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -120,9 +120,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - if !this.machine.communicate { - throw_unsup_format!("`getcwd` not available when isolation is enabled") - } + this.check_no_isolation("getcwd")?; let tcx = &{ this.tcx.tcx }; @@ -158,9 +156,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn chdir(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if !this.machine.communicate { - throw_unsup_format!("`chdir` not available when isolation is enabled") - } + this.check_no_isolation("chdir")?; let path_bytes = this .memory() diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 7e684489b5c9..414ae35e9666 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -36,9 +36,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if !this.machine.communicate { - throw_unsup_format!("`open` not available when isolation is enabled") - } + this.check_no_isolation("open")?; let flag = this.read_scalar(flag_op)?.to_i32()?; @@ -91,9 +89,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if !this.machine.communicate { - throw_unsup_format!("`fcntl` not available when isolation is enabled") - } + this.check_no_isolation("fcntl")?; let fd = this.read_scalar(fd_op)?.to_i32()?; let cmd = this.read_scalar(cmd_op)?.to_i32()?; @@ -126,9 +122,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn close(&mut self, fd_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if !this.machine.communicate { - throw_unsup_format!("`close` not available when isolation is enabled") - } + this.check_no_isolation("close")?; let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -145,9 +139,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); - if !this.machine.communicate { - throw_unsup_format!("`read` not available when isolation is enabled") - } + this.check_no_isolation("read")?; let tcx = &{ this.tcx.tcx }; @@ -182,9 +174,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); - if !this.machine.communicate { - throw_unsup_format!("`write` not available when isolation is enabled") - } + this.check_no_isolation("write")?; let tcx = &{ this.tcx.tcx }; @@ -210,9 +200,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn unlink( &mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if !this.machine.communicate { - throw_unsup_format!("`write` not available when isolation is enabled") - } + this.check_no_isolation("unlink")?; let path_bytes = this .memory() diff --git a/src/shims/time.rs b/src/shims/time.rs index 0153c1a912df..d75cb7bad384 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -41,9 +41,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if !this.machine.communicate { - throw_unsup_format!("`clock_gettime` not available when isolation is enabled") - } + this.check_no_isolation("clock_gettime")?; let clk_id = this.read_scalar(clk_id_op)?.to_i32()?; if clk_id != this.eval_libc_i32("CLOCK_REALTIME")? { @@ -75,9 +73,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if !this.machine.communicate { - throw_unsup_format!("`gettimeofday` not available when isolation is enabled") - } + this.check_no_isolation("gettimeofday")?; // Using tz is obsolete and should always be null let tz = this.read_scalar(tz_op)?.not_undef()?; if !this.is_null(tz)? { From 24872230dc25f40b5683549bdb1e288964744e77 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 14 Oct 2019 16:42:29 -0500 Subject: [PATCH 1211/5092] Check that access mode flags only use the first two bits --- src/shims/fs.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 4d93ca4fd31b..c3dc5e60f0b4 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -43,15 +43,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut options = OpenOptions::new(); - // The first two bits of the flag correspond to the access mode of the file in linux. This - // is done this way because `O_RDONLY` is zero in several platforms. + let o_rdonly = this.eval_libc_i32("O_RDONLY")?; + let o_wronly = this.eval_libc_i32("O_WRONLY")?; + let o_rdwr = this.eval_libc_i32("O_RDWR")?; + // The first two bits of the flag correspond to the access mode in linux, macOS and + // windows. We need to check that in fact the access mode flags for the current platform + // only use these two bits, otherwise we are in an unsupported platform and should error. + if (o_rdonly | o_wronly | o_rdwr) & !0b11 != 0 { + throw_unsup_format!("Access mode flags on this platform are unsupported"); + } + // Now we check the access mode let access_mode = flag & 0b11; - if access_mode == this.eval_libc_i32("O_RDONLY")? { + if access_mode == o_rdonly { options.read(true); - } else if access_mode == this.eval_libc_i32("O_WRONLY")? { + } else if access_mode == o_wronly { options.write(true); - } else if access_mode == this.eval_libc_i32("O_RDWR")? { + } else if access_mode == o_rdwr { options.read(true).write(true); } else { throw_unsup_format!("Unsupported access mode {:#x}", access_mode); @@ -124,8 +132,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `FD_CLOEXEC` value without checking if the flag is set for the file because `std` // always sets this flag when opening a file. However we still need to check that the // file itself is open. - this.get_handle_and(fd, |_| Ok(0))?; - this.eval_libc_i32("FD_CLOEXEC") + let fd_cloexec = this.eval_libc_i32("FD_CLOEXEC")?; + this.get_handle_and(fd, |_| Ok(fd_cloexec)) } else { throw_unsup_format!("The {:#x} command is not supported for `fcntl`)", cmd); } From a94d9d2c1d76f71fcf3ed5d27e5d20bec87cea62 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 16 Oct 2019 10:02:31 +0200 Subject: [PATCH 1212/5092] install minimal profile by default --- .appveyor.yml | 2 +- .travis.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 582b55f62dbb..d0668c72acdb 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -21,7 +21,7 @@ install: - set /p RUSTC_HASH= Date: Wed, 16 Oct 2019 10:41:50 +0200 Subject: [PATCH 1213/5092] cleanup: remove leftover rust-docs components --- .appveyor.yml | 1 + .travis.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.appveyor.yml b/.appveyor.yml index d0668c72acdb..60963438abff 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -25,6 +25,7 @@ install: - set PATH=%USERPROFILE%\.cargo\bin;%PATH% - rustup default stable - rustup uninstall beta + - rustup component remove rust-docs & exit 0 - rustup update # Install "master" toolchain - cargo install rustup-toolchain-install-master & exit 0 diff --git a/.travis.yml b/.travis.yml index e6d5ee08892b..51f02e76824b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,6 +35,7 @@ before_script: - export PATH=$HOME/.cargo/bin:$PATH - rustup default stable - rustup uninstall beta +- rustup component remove rust-docs || echo "rust-docs already gone" - rustup update # Install "master" toolchain - cargo install rustup-toolchain-install-master || echo "rustup-toolchain-install-master already installed" From cb913698d28b911e4ea0b5113c3f4e102ee0285c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 16 Oct 2019 10:45:48 +0200 Subject: [PATCH 1214/5092] make sure we don't install more than we have to --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0187047534d4..6d0173aaf04e 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,7 @@ nightly that *does* come with Miri: ```sh MIRI_NIGHTLY=nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/miri) echo "Installing latest nightly with Miri: $MIRI_NIGHTLY" +rustup set profile minimal rustup default "$MIRI_NIGHTLY" rustup component add miri From 2967d0d13aa9ad536ad9532ad6eb04d3ac336346 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 16 Oct 2019 21:45:17 +0200 Subject: [PATCH 1215/5092] better error when using cargo-miri in a workspace --- src/bin/cargo-miri.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 15c66f8c0dba..b189dc1f808c 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -91,7 +91,7 @@ fn list_targets() -> impl Iterator { let mut metadata = if let Ok(metadata) = cmd.exec() { metadata } else { - show_error(format!("Could not obtain Cargo metadata")); + show_error(format!("Could not obtain Cargo metadata; likely an ill-formed manifest")); }; let current_dir = std::env::current_dir(); @@ -113,7 +113,7 @@ fn list_targets() -> impl Iterator { package_manifest_directory == current_dir } }) - .expect("could not find matching package"); + .unwrap_or_else(|| show_error(format!("This seems to be a workspace, which is not supported by cargo-miri"))); let package = metadata.packages.remove(package_index); // Finally we got the list of targets to build From a353e90eedb088acf0535c62cac656c5c2621d76 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Fri, 18 Oct 2019 11:11:50 +0900 Subject: [PATCH 1216/5092] Use memory field instead of memory() --- src/eval.rs | 12 ++++---- src/helpers.rs | 8 +++--- src/machine.rs | 6 ++-- src/operator.rs | 2 +- src/shims/env.rs | 20 +++++++------- src/shims/foreign_items.rs | 56 +++++++++++++++++++------------------- src/shims/fs.rs | 8 +++--- src/shims/intrinsics.rs | 24 ++++++++-------- src/shims/mod.rs | 2 +- src/stacked_borrows.rs | 6 ++-- 10 files changed, 72 insertions(+), 72 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index aa876d6617ce..77bc096e3198 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -93,7 +93,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // First argument: pointer to `main()`. let main_ptr = ecx - .memory_mut() + .memory .create_fn_alloc(FnVal::Instance(main_instance)); let dest = ecx.local_place(args.next().unwrap())?; ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?; @@ -128,7 +128,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let mut arg = arg.into_bytes(); arg.push(0); argvs.push( - ecx.memory_mut() + ecx.memory .allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Static.into()), ); } @@ -142,7 +142,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let place = ecx.mplace_field(argvs_place, idx as u64)?; ecx.write_scalar(Scalar::Ptr(arg), place.into())?; } - ecx.memory_mut() + ecx.memory .mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?; // Write a pointer to that place as the argument. let argv = argvs_place.ptr; @@ -157,7 +157,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( { let tcx = &{ ecx.tcx.tcx }; let cmd_utf16: Vec = cmd.encode_utf16().collect(); - let cmd_ptr = ecx.memory_mut().allocate( + let cmd_ptr = ecx.memory.allocate( Size::from_bytes(cmd_utf16.len() as u64 * 2), Align::from_bytes(2).unwrap(), MiriMemoryKind::Env.into(), @@ -165,7 +165,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ecx.machine.cmd_line = Some(cmd_ptr); // Store the UTF-16 string. let char_size = Size::from_bytes(2); - let cmd_alloc = ecx.memory_mut().get_mut(cmd_ptr.alloc_id)?; + let cmd_alloc = ecx.memory.get_mut(cmd_ptr.alloc_id)?; let mut cur_ptr = cmd_ptr; for &c in cmd_utf16.iter() { cmd_alloc.write_scalar( @@ -211,7 +211,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) { // Process the result. match res { Ok(()) => { - let leaks = ecx.memory().leak_report(); + let leaks = ecx.memory.leak_report(); // Disable the leak test on some platforms where we do not // correctly implement TLS destructors. let target_os = ecx.tcx.tcx.sess.target.target.target_os.to_lowercase(); diff --git a/src/helpers.rs b/src/helpers.rs index e3f818414da3..08e28e909ab2 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -57,7 +57,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Test if this immediate equals 0. fn is_null(&self, val: Scalar) -> InterpResult<'tcx, bool> { let this = self.eval_context_ref(); - let null = Scalar::from_int(0, this.memory().pointer_size()); + let null = Scalar::from_int(0, this.memory.pointer_size()); this.ptr_eq(val, null) } @@ -94,7 +94,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let this = self.eval_context_mut(); - let ptr = this.memory().check_ptr_access( + let ptr = this.memory.check_ptr_access( ptr, Size::from_bytes(len as u64), Align::from_bytes(1).unwrap() @@ -108,12 +108,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .map_err(|err| err_unsup_format!("getrandom failed: {}", err))?; } else { - let rng = this.memory_mut().extra.rng.get_mut(); + let rng = this.memory.extra.rng.get_mut(); rng.fill_bytes(&mut data); } let tcx = &{this.tcx.tcx}; - this.memory_mut().get_mut(ptr.alloc_id)?.write_bytes(tcx, ptr, &data) + this.memory.get_mut(ptr.alloc_id)?.write_bytes(tcx, ptr, &data) } /// Visits the memory covered by `place`, sensitive to freezing: the 3rd parameter diff --git a/src/machine.rs b/src/machine.rs index c22b3805d46b..d20346ba468a 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -164,7 +164,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { - ecx.memory().extra.validate + ecx.memory.extra.validate } #[inline(always)] @@ -349,7 +349,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn stack_push( ecx: &mut InterpCx<'mir, 'tcx, Self>, ) -> InterpResult<'tcx, stacked_borrows::CallId> { - Ok(ecx.memory().extra.stacked_borrows.borrow_mut().new_call()) + Ok(ecx.memory.extra.stacked_borrows.borrow_mut().new_call()) } #[inline(always)] @@ -358,7 +358,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { extra: stacked_borrows::CallId, ) -> InterpResult<'tcx> { Ok(ecx - .memory() + .memory .extra .stacked_borrows .borrow_mut() diff --git a/src/operator.rs b/src/operator.rs index 45bf1e453744..9c02c56fd6a1 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -34,7 +34,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { /// Test if the pointer is in-bounds of a live allocation. #[inline] fn pointer_inbounds(&self, ptr: Pointer) -> InterpResult<'tcx> { - let (size, _align) = self.memory().get_size_and_align(ptr.alloc_id, AllocCheck::Live)?; + let (size, _align) = self.memory.get_size_and_align(ptr.alloc_id, AllocCheck::Live)?; ptr.check_inbounds_alloc(size, CheckInAllocMsg::InboundsTest) } diff --git a/src/shims/env.rs b/src/shims/env.rs index ae800c2315fe..bd9263d8bf2b 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -26,7 +26,7 @@ impl EnvVars { for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { let var_ptr = - alloc_env_var(name.as_bytes(), value.as_bytes(), ecx.memory_mut()); + alloc_env_var(name.as_bytes(), value.as_bytes(), &mut ecx.memory); ecx.machine.env_vars.map.insert(name.into_bytes(), var_ptr); } } @@ -52,7 +52,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let name_ptr = this.read_scalar(name_op)?.not_undef()?; - let name = this.memory().read_c_str(name_ptr)?; + let name = this.memory.read_c_str(name_ptr)?; Ok(match this.machine.env_vars.map.get(name) { // The offset is used to strip the "{name}=" part of the string. Some(var_ptr) => { @@ -71,18 +71,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_ptr = this.read_scalar(name_op)?.not_undef()?; let value_ptr = this.read_scalar(value_op)?.not_undef()?; - let value = this.memory().read_c_str(value_ptr)?; + let value = this.memory.read_c_str(value_ptr)?; let mut new = None; if !this.is_null(name_ptr)? { - let name = this.memory().read_c_str(name_ptr)?; + let name = this.memory.read_c_str(name_ptr)?; if !name.is_empty() && !name.contains(&b'=') { new = Some((name.to_owned(), value.to_owned())); } } if let Some((name, value)) = new { - let var_ptr = alloc_env_var(&name, &value, this.memory_mut()); + let var_ptr = alloc_env_var(&name, &value, &mut this.memory); if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), var_ptr) { - this.memory_mut() + this.memory .deallocate(var, None, MiriMemoryKind::Env.into())?; } Ok(0) @@ -97,14 +97,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_ptr = this.read_scalar(name_op)?.not_undef()?; let mut success = None; if !this.is_null(name_ptr)? { - let name = this.memory().read_c_str(name_ptr)?.to_owned(); + let name = this.memory.read_c_str(name_ptr)?.to_owned(); if !name.is_empty() && !name.contains(&b'=') { success = Some(this.machine.env_vars.map.remove(&name)); } } if let Some(old) = success { if let Some(var) = old { - this.memory_mut() + this.memory .deallocate(var, None, MiriMemoryKind::Env.into())?; } Ok(0) @@ -140,7 +140,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This is ok because the buffer was strictly larger than `bytes`, so after // adding the null terminator, the buffer size is larger or equal to // `bytes.len()`, meaning that `bytes` actually fit inside tbe buffer. - this.memory_mut() + this.memory .get_mut(buf.alloc_id)? .write_bytes(tcx, buf, &bytes)?; return Ok(Scalar::Ptr(buf)); @@ -159,7 +159,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("chdir")?; let path_bytes = this - .memory() + .memory .read_c_str(this.read_scalar(path_op)?.not_undef()?)?; let path = Path::new( diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index f6195961ba06..563acde00e1e 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -48,11 +48,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { let align = this.min_align(size, kind); let ptr = this - .memory_mut() + .memory .allocate(Size::from_bytes(size), align, kind.into()); if zero_init { // We just allocated this, the access cannot fail - this.memory_mut() + this.memory .get_mut(ptr.alloc_id) .unwrap() .write_repeat(tcx, ptr, 0, Size::from_bytes(size)) @@ -66,7 +66,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); if !this.is_null(ptr)? { let ptr = this.force_ptr(ptr)?; - this.memory_mut().deallocate(ptr, None, kind.into())?; + this.memory.deallocate(ptr, None, kind.into())?; } Ok(()) } @@ -84,13 +84,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(Scalar::from_int(0, this.pointer_size())) } else { let new_ptr = - this.memory_mut() + this.memory .allocate(Size::from_bytes(new_size), new_align, kind.into()); Ok(Scalar::Ptr(new_ptr)) } } else { let old_ptr = this.force_ptr(old_ptr)?; - let memory = this.memory_mut(); + let memory = &mut this.memory; if new_size == 0 { memory.deallocate(old_ptr, None, kind.into())?; Ok(Scalar::from_int(0, this.pointer_size())) @@ -179,7 +179,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if size == 0 { this.write_null(ret.into())?; } else { - let ptr = this.memory_mut().allocate( + let ptr = this.memory.allocate( Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::C.into(), @@ -208,7 +208,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if !align.is_power_of_two() { throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = this.memory_mut().allocate( + let ptr = this.memory.allocate( Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into(), @@ -224,13 +224,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if !align.is_power_of_two() { throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = this.memory_mut().allocate( + let ptr = this.memory.allocate( Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into(), ); // We just allocated this, the access cannot fail - this.memory_mut() + this.memory .get_mut(ptr.alloc_id) .unwrap() .write_repeat(tcx, ptr, 0, Size::from_bytes(size)) @@ -248,7 +248,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); } let ptr = this.force_ptr(ptr)?; - this.memory_mut().deallocate( + this.memory.deallocate( ptr, Some(( Size::from_bytes(old_size), @@ -269,7 +269,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); } let align = Align::from_bytes(align).unwrap(); - let new_ptr = this.memory_mut().reallocate( + let new_ptr = this.memory.reallocate( ptr, Some((Size::from_bytes(old_size), align)), Size::from_bytes(new_size), @@ -304,11 +304,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "dlsym" => { let _handle = this.read_scalar(args[0])?; let symbol = this.read_scalar(args[1])?.not_undef()?; - let symbol_name = this.memory().read_c_str(symbol)?; + let symbol_name = this.memory.read_c_str(symbol)?; let err = format!("bad c unicode symbol: {:?}", symbol_name); let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err); if let Some(dlsym) = Dlsym::from_str(symbol_name)? { - let ptr = this.memory_mut().create_fn_alloc(FnVal::Other(dlsym)); + let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); this.write_scalar(Scalar::from(ptr), dest)?; } else { this.write_null(dest)?; @@ -325,7 +325,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We abort on panic, so not much is going on here, but we still have to call the closure. let f = this.read_scalar(args[0])?.not_undef()?; let data = this.read_scalar(args[1])?.not_undef()?; - let f_instance = this.memory().get_fn(f)?.as_instance()?; + let f_instance = this.memory.get_fn(f)?.as_instance()?; this.write_null(dest)?; trace!("__rust_maybe_catch_panic: {:?}", f_instance); @@ -369,8 +369,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let n = Size::from_bytes(this.read_scalar(args[2])?.to_usize(this)?); let result = { - let left_bytes = this.memory().read_bytes(left, n)?; - let right_bytes = this.memory().read_bytes(right, n)?; + let left_bytes = this.memory.read_bytes(left, n)?; + let right_bytes = this.memory.read_bytes(right, n)?; use std::cmp::Ordering::*; match left_bytes.cmp(right_bytes) { @@ -388,7 +388,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val = this.read_scalar(args[1])?.to_i32()? as u8; let num = this.read_scalar(args[2])?.to_usize(this)?; if let Some(idx) = this - .memory() + .memory .read_bytes(ptr, Size::from_bytes(num))? .iter() .rev() @@ -406,7 +406,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val = this.read_scalar(args[1])?.to_i32()? as u8; let num = this.read_scalar(args[2])?.to_usize(this)?; let idx = this - .memory() + .memory .read_bytes(ptr, Size::from_bytes(num))? .iter() .position(|&c| c == val); @@ -477,7 +477,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // stdout/stderr use std::io::{self, Write}; - let buf_cont = this.memory().read_bytes(buf, Size::from_bytes(n))?; + let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(n))?; // We need to flush to make sure this actually appears on the screen let res = if fd == 1 { // Stdout is buffered, flush to make sure it appears on the screen. @@ -519,7 +519,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "strlen" => { let ptr = this.read_scalar(args[0])?.not_undef()?; - let n = this.memory().read_c_str(ptr)?.len(); + let n = this.memory.read_c_str(ptr)?.len(); this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; } @@ -649,7 +649,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Extract the function type out of the signature (that seems easier than constructing it ourselves). let dtor = match this.test_null(this.read_scalar(args[1])?.not_undef()?)? { - Some(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr)?.as_instance()?), + Some(dtor_ptr) => Some(this.memory.get_fn(dtor_ptr)?.as_instance()?), None => None, }; @@ -671,10 +671,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let key_ptr = this - .memory() + .memory .check_ptr_access(key_ptr, key_layout.size, key_layout.align.abi)? .expect("cannot be a ZST"); - this.memory_mut().get_mut(key_ptr.alloc_id)?.write_scalar( + this.memory.get_mut(key_ptr.alloc_id)?.write_scalar( tcx, key_ptr, Scalar::from_uint(key, key_layout.size).into(), @@ -859,13 +859,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .check_mplace_access(system_info, None)? .expect("cannot be a ZST"); // Initialize with `0`. - this.memory_mut() + this.memory .get_mut(system_info_ptr.alloc_id)? .write_repeat(tcx, system_info_ptr, 0, system_info.layout.size)?; // Set number of processors. let dword_size = Size::from_bytes(4); let offset = 2 * dword_size + 3 * tcx.pointer_size(); - this.memory_mut() + this.memory .get_mut(system_info_ptr.alloc_id)? .write_scalar( tcx, @@ -920,7 +920,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx use std::io::{self, Write}; let buf_cont = this - .memory() + .memory .read_bytes(buf, Size::from_bytes(u64::from(n)))?; let res = if handle == -11 { io::stdout().write(buf_cont) @@ -995,7 +995,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let tcx = &{ this.tcx.tcx }; let errno_ptr = this.machine.last_error.unwrap(); - this.memory_mut().get_mut(errno_ptr.alloc_id)?.write_scalar( + this.memory.get_mut(errno_ptr.alloc_id)?.write_scalar( tcx, errno_ptr, scalar.into(), @@ -1007,7 +1007,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let tcx = &{ this.tcx.tcx }; let errno_ptr = this.machine.last_error.unwrap(); - this.memory() + this.memory .get(errno_ptr.alloc_id)? .read_scalar(tcx, errno_ptr, Size::from_bits(32))? .not_undef() diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 445c98fd9fa4..3a16e2868958 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -95,7 +95,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let path_bytes = this - .memory() + .memory .read_c_str(this.read_scalar(path_op)?.not_undef()?)?; let path = std::str::from_utf8(path_bytes) .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", path_bytes))?; @@ -171,7 +171,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.remove_handle_and(fd, |mut handle, this| { // Don't use `?` to avoid returning before reinserting the handle let bytes = this.force_ptr(buf_scalar).and_then(|buf| { - this.memory_mut() + this.memory .get_mut(buf.alloc_id)? .get_bytes_mut(tcx, buf, Size::from_bytes(count)) .map(|buffer| handle.file.read(buffer)) @@ -203,7 +203,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; this.remove_handle_and(fd, |mut handle, this| { - let bytes = this.memory().get(buf.alloc_id).and_then(|alloc| { + let bytes = this.memory.get(buf.alloc_id).and_then(|alloc| { alloc .get_bytes(tcx, buf, Size::from_bytes(count)) .map(|bytes| handle.file.write(bytes).map(|bytes| bytes as i64)) @@ -219,7 +219,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("unlink")?; let path_bytes = this - .memory() + .memory .read_c_str(this.read_scalar(path_op)?.not_undef()?)?; let path = std::str::from_utf8(path_bytes) .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", path_bytes))?; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 875a344363a0..1fa2b5a0d01f 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -68,7 +68,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory().check_ptr_access(place.ptr, place.layout.size, align)?; + this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; this.write_scalar(val, dest)?; } @@ -83,7 +83,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory().check_ptr_access(place.ptr, place.layout.size, align)?; + this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; this.write_scalar(val, place.into())?; } @@ -104,7 +104,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory().check_ptr_access(place.ptr, place.layout.size, align)?; + this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; this.write_scalar(old, dest)?; // old value is returned this.write_scalar(new, place.into())?; @@ -120,7 +120,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory().check_ptr_access(place.ptr, place.layout.size, align)?; + this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; // binary_op will bail if either of them is not a scalar let eq = this.overflowing_binary_op(mir::BinOp::Eq, old, expect_old)?.0; @@ -173,7 +173,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory().check_ptr_access(place.ptr, place.layout.size, align)?; + this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; this.write_immediate(*old, dest)?; // old value is returned let (op, neg) = match intrinsic_name.split('_').nth(1).unwrap() { @@ -207,12 +207,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let size = Size::from_bytes(count * elem_size); let src = this.read_scalar(args[0])?.not_undef()?; - let src = this.memory().check_ptr_access(src, size, elem_align)?; + let src = this.memory.check_ptr_access(src, size, elem_align)?; let dest = this.read_scalar(args[1])?.not_undef()?; - let dest = this.memory().check_ptr_access(dest, size, elem_align)?; + let dest = this.memory.check_ptr_access(dest, size, elem_align)?; if let (Some(src), Some(dest)) = (src, dest) { - this.memory_mut().copy( + this.memory.copy( src, dest, size, @@ -359,7 +359,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert!(mplace.meta.is_none()); // not a zst, must be valid pointer let ptr = mplace.ptr.to_ptr()?; - this.memory_mut().get_mut(ptr.alloc_id)?.write_repeat(tcx, ptr, 0, dest.layout.size)?; + this.memory.get_mut(ptr.alloc_id)?.write_repeat(tcx, ptr, 0, dest.layout.size)?; } } } @@ -548,7 +548,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mplace = this.force_allocation(dest)?; assert!(mplace.meta.is_none()); let ptr = mplace.ptr.to_ptr()?; - this.memory_mut() + this.memory .get_mut(ptr.alloc_id)? .mark_definedness(ptr, dest.layout.size, false); } @@ -563,9 +563,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.read_scalar(args[0])?.not_undef()?; let count = this.read_scalar(args[2])?.to_usize(this)?; let byte_count = ty_layout.size * count; - match this.memory().check_ptr_access(ptr, byte_count, ty_layout.align.abi)? { + match this.memory.check_ptr_access(ptr, byte_count, ty_layout.align.abi)? { Some(ptr) => { - this.memory_mut() + this.memory .get_mut(ptr.alloc_id)? .write_repeat(tcx, ptr, val_byte, byte_count)?; } diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 95bb8b70370f..60974958c42a 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -75,7 +75,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr_scalar = this.read_scalar(ptr_op)?.not_undef()?; if let Ok(ptr) = this.force_ptr(ptr_scalar) { - let cur_align = this.memory().get(ptr.alloc_id)?.align.bytes() as usize; + let cur_align = this.memory.get(ptr.alloc_id)?.align.bytes() as usize; if cur_align >= req_align { // if the allocation alignment is at least the required alignment we use the // libcore implementation diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 5258cbb5485b..d219c1c75834 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -533,14 +533,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let protector = if protect { Some(this.frame().extra) } else { None }; - let ptr = this.memory().check_ptr_access(place.ptr, size, place.align) + let ptr = this.memory.check_ptr_access(place.ptr, size, place.align) .expect("validity checks should have excluded dangling/unaligned pointer") .expect("we shouldn't get here for ZST"); trace!("reborrow: {} reference {:?} derived from {:?} (pointee {}): {:?}, size {}", kind, new_tag, ptr.tag, place.layout.ty, ptr.erase_tag(), size.bytes()); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. - let alloc = this.memory().get(ptr.alloc_id)?; + let alloc = this.memory.get(ptr.alloc_id)?; let stacked_borrows = alloc.extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); // Update the stacks. // Make sure that raw pointers and mutable shared references are reborrowed "weak": @@ -592,7 +592,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Compute new borrow. let new_tag = match kind { RefKind::Raw { .. } => Tag::Untagged, - _ => Tag::Tagged(this.memory().extra.stacked_borrows.borrow_mut().new_ptr()), + _ => Tag::Tagged(this.memory.extra.stacked_borrows.borrow_mut().new_ptr()), }; // Reborrow. From 17449fbce6da59668987bc8527ea6f84f038dd0c Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Fri, 18 Oct 2019 11:21:20 +0900 Subject: [PATCH 1217/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 820490edd618..0f59c13723c7 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d28a9c38fe14396e86ae274c7847e20ee0f78ca9 +fa0f7d0080d8e7e9eb20aa9cbf8013f96c81287f From 5481afbaf64c05d5647533df0ec58492af5ef455 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 18 Oct 2019 11:33:12 +0200 Subject: [PATCH 1218/5092] cleanup now that borrow checker knows memory is a field --- src/eval.rs | 5 ++--- src/helpers.rs | 10 +++------- src/shims/env.rs | 8 +++----- src/shims/foreign_items.rs | 18 +++++++----------- src/shims/fs.rs | 8 ++------ src/shims/intrinsics.rs | 2 +- 6 files changed, 18 insertions(+), 33 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 77bc096e3198..bb0bad0ea03d 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -155,7 +155,6 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } // Store command line as UTF-16 for Windows `GetCommandLineW`. { - let tcx = &{ ecx.tcx.tcx }; let cmd_utf16: Vec = cmd.encode_utf16().collect(); let cmd_ptr = ecx.memory.allocate( Size::from_bytes(cmd_utf16.len() as u64 * 2), @@ -169,12 +168,12 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let mut cur_ptr = cmd_ptr; for &c in cmd_utf16.iter() { cmd_alloc.write_scalar( - tcx, + &*ecx.tcx, cur_ptr, Scalar::from_uint(c, char_size).into(), char_size, )?; - cur_ptr = cur_ptr.offset(char_size, tcx)?; + cur_ptr = cur_ptr.offset(char_size, &*ecx.tcx)?; } } diff --git a/src/helpers.rs b/src/helpers.rs index 08e28e909ab2..c09d5c823e1b 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -112,8 +112,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx rng.fill_bytes(&mut data); } - let tcx = &{this.tcx.tcx}; - this.memory.get_mut(ptr.alloc_id)?.write_bytes(tcx, ptr, &data) + this.memory.get_mut(ptr.alloc_id)?.write_bytes(&*this.tcx, ptr, &data) } /// Visits the memory covered by `place`, sensitive to freezing: the 3rd parameter @@ -311,8 +310,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function to get the `TyLayout` of a `libc` type fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyLayout<'tcx>> { let this = self.eval_context_mut(); - let tcx = &{ this.tcx.tcx }; - let ty = this.resolve_path(&["libc", name])?.ty(*tcx); + let ty = this.resolve_path(&["libc", name])?.ty(*this.tcx); this.layout_of(ty) } @@ -325,14 +323,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let tcx = &{ this.tcx.tcx }; - let mut offset = Size::from_bytes(0); for &imm in imms { this.write_immediate_to_mplace( *imm, - place.offset(offset, None, imm.layout, tcx)?, + place.offset(offset, None, imm.layout, &*this.tcx)?, )?; offset += imm.layout.size; } diff --git a/src/shims/env.rs b/src/shims/env.rs index bd9263d8bf2b..6078ca26e269 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -122,10 +122,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("getcwd")?; - let tcx = &{ this.tcx.tcx }; - let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; - let size = this.read_scalar(size_op)?.to_usize(&*tcx)?; + let size = this.read_scalar(size_op)?.to_usize(&*this.tcx)?; // If we cannot get the current directory, we return null match env::current_dir() { Ok(cwd) => { @@ -142,7 +140,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `bytes.len()`, meaning that `bytes` actually fit inside tbe buffer. this.memory .get_mut(buf.alloc_id)? - .write_bytes(tcx, buf, &bytes)?; + .write_bytes(&*this.tcx, buf, &bytes)?; return Ok(Scalar::Ptr(buf)); } let erange = this.eval_libc("ERANGE")?; @@ -150,7 +148,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Err(e) => this.consume_io_error(e)?, } - Ok(Scalar::ptr_null(&*tcx)) + Ok(Scalar::ptr_null(&*this.tcx)) } fn chdir(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 563acde00e1e..cfbb02f60813 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -42,7 +42,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn malloc(&mut self, size: u64, zero_init: bool, kind: MiriMemoryKind) -> Scalar { let this = self.eval_context_mut(); - let tcx = &{ this.tcx.tcx }; if size == 0 { Scalar::from_int(0, this.pointer_size()) } else { @@ -55,7 +54,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.memory .get_mut(ptr.alloc_id) .unwrap() - .write_repeat(tcx, ptr, 0, Size::from_bytes(size)) + .write_repeat(&*this.tcx, ptr, 0, Size::from_bytes(size)) .unwrap(); } Scalar::Ptr(ptr) @@ -90,12 +89,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } else { let old_ptr = this.force_ptr(old_ptr)?; - let memory = &mut this.memory; if new_size == 0 { - memory.deallocate(old_ptr, None, kind.into())?; + this.memory.deallocate(old_ptr, None, kind.into())?; Ok(Scalar::from_int(0, this.pointer_size())) } else { - let new_ptr = memory.reallocate( + let new_ptr = this.memory.reallocate( old_ptr, None, Size::from_bytes(new_size), @@ -334,7 +332,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // for the TLS destructors, and of course `eval_main`. let mir = this.load_mir(f_instance.def, None)?; let ret_place = - MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); + MPlaceTy::dangling(this.layout_of(tcx.mk_unit())?, this).into(); this.push_stack_frame( f_instance, mir.span, @@ -471,7 +469,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "write" => { let fd = this.read_scalar(args[0])?.to_i32()?; let buf = this.read_scalar(args[1])?.not_undef()?; - let n = this.read_scalar(args[2])?.to_usize(&*this.tcx)?; + let n = this.read_scalar(args[2])?.to_usize(tcx)?; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { // stdout/stderr @@ -993,10 +991,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let tcx = &{ this.tcx.tcx }; let errno_ptr = this.machine.last_error.unwrap(); this.memory.get_mut(errno_ptr.alloc_id)?.write_scalar( - tcx, + &*this.tcx, errno_ptr, scalar.into(), Size::from_bits(32), @@ -1005,11 +1002,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let tcx = &{ this.tcx.tcx }; let errno_ptr = this.machine.last_error.unwrap(); this.memory .get(errno_ptr.alloc_id)? - .read_scalar(tcx, errno_ptr, Size::from_bits(32))? + .read_scalar(&*this.tcx, errno_ptr, Size::from_bits(32))? .not_undef() } diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 3a16e2868958..891474bc3bdb 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -157,8 +157,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("read")?; - let tcx = &{ this.tcx.tcx }; - let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; // Reading zero bytes should not change `buf` if count == 0 { @@ -173,7 +171,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let bytes = this.force_ptr(buf_scalar).and_then(|buf| { this.memory .get_mut(buf.alloc_id)? - .get_bytes_mut(tcx, buf, Size::from_bytes(count)) + .get_bytes_mut(&*this.tcx, buf, Size::from_bytes(count)) .map(|buffer| handle.file.read(buffer)) }); // Reinsert the file handle @@ -192,8 +190,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("write")?; - let tcx = &{ this.tcx.tcx }; - let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; // Writing zero bytes should not change `buf` if count == 0 { @@ -205,7 +201,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.remove_handle_and(fd, |mut handle, this| { let bytes = this.memory.get(buf.alloc_id).and_then(|alloc| { alloc - .get_bytes(tcx, buf, Size::from_bytes(count)) + .get_bytes(&*this.tcx, buf, Size::from_bytes(count)) .map(|bytes| handle.file.write(bytes).map(|bytes| bytes as i64)) }); this.machine.file_handler.handles.insert(fd, handle); diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 1fa2b5a0d01f..4666557e200c 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -28,7 +28,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // (as opposed to through a place), we have to remember to erase any tag // that might still hang around! - let intrinsic_name = &*this.tcx.item_name(instance.def_id()).as_str(); + let intrinsic_name = &*tcx.item_name(instance.def_id()).as_str(); match intrinsic_name { "arith_offset" => { let offset = this.read_scalar(args[1])?.to_isize(this)?; From 61da8b84282d4b44f4dd1742328867cae9e5cefc Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sun, 13 Oct 2019 15:26:03 -0500 Subject: [PATCH 1219/5092] Add OsString from/to bytes helper functions --- src/helpers.rs | 23 +++++++++++++++++++++++ src/shims/env.rs | 16 +++++----------- src/shims/fs.rs | 5 ++--- tests/compile-fail/chdir_invalid_path.rs | 11 ----------- 4 files changed, 30 insertions(+), 25 deletions(-) delete mode 100644 tests/compile-fail/chdir_invalid_path.rs diff --git a/src/helpers.rs b/src/helpers.rs index c09d5c823e1b..c2e4131a76d1 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,4 +1,5 @@ use std::mem; +use std::ffi::OsString; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; @@ -345,3 +346,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } } + + +pub fn bytes_to_os_string<'tcx>(bytes: Vec) -> InterpResult<'tcx, OsString> { + if cfg!(unix) { + Ok(std::os::unix::ffi::OsStringExt::from_vec(bytes)) + } else { + std::str::from_utf8(&bytes) + .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes).into()) + .map(OsString::from) + } + } + +pub fn os_string_to_bytes<'tcx>(os_string: OsString) -> InterpResult<'tcx, Vec> { + if cfg!(unix) { + Ok(std::os::unix::ffi::OsStringExt::into_vec(os_string)) + } else { + os_string + .into_string() + .map_err(|os_string| err_unsup_format!("{:?} is not a valid utf-8 string", os_string).into()) + .map(|s| s.into_bytes()) + } + } diff --git a/src/shims/env.rs b/src/shims/env.rs index 6078ca26e269..1fe08aeffb7b 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,9 +1,9 @@ use std::collections::HashMap; use std::env; -use std::path::Path; use crate::stacked_borrows::Tag; use crate::*; + use rustc::ty::layout::Size; use rustc_mir::interpret::{Memory, Pointer}; @@ -128,7 +128,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match env::current_dir() { Ok(cwd) => { // It is not clear what happens with non-utf8 paths here - let mut bytes = cwd.display().to_string().into_bytes(); + let mut bytes = helpers::os_string_to_bytes(cwd.into())?; // If `size` is smaller or equal than the `bytes.len()`, writing `bytes` plus the // required null terminator to memory using the `buf` pointer would cause an // overflow. The desired behavior in this case is to return null. @@ -156,16 +156,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("chdir")?; - let path_bytes = this - .memory - .read_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let bytes = this.memory.read_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = helpers::bytes_to_os_string(bytes.to_vec()); - let path = Path::new( - std::str::from_utf8(path_bytes) - .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", path_bytes))?, - ); - - match env::set_current_dir(path) { + match env::set_current_dir(path?) { Ok(()) => Ok(0), Err(e) => { this.consume_io_error(e)?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 891474bc3bdb..cc776295bd49 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -94,11 +94,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("unsupported flags {:#x}", flag & !mirror); } - let path_bytes = this + let bytes = this .memory .read_c_str(this.read_scalar(path_op)?.not_undef()?)?; - let path = std::str::from_utf8(path_bytes) - .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", path_bytes))?; + let path: std::path::PathBuf = helpers::bytes_to_os_string(bytes.to_vec())?.into(); let fd = options.open(path).map(|file| { let mut fh = &mut this.machine.file_handler; diff --git a/tests/compile-fail/chdir_invalid_path.rs b/tests/compile-fail/chdir_invalid_path.rs deleted file mode 100644 index 22b0d723aad8..000000000000 --- a/tests/compile-fail/chdir_invalid_path.rs +++ /dev/null @@ -1,11 +0,0 @@ -// compile-flags: -Zmiri-disable-isolation - -extern { - pub fn chdir(dir: *const u8) -> i32; -} - -fn main() { - let path = vec![0xc3u8, 0x28, 0]; - // test that `chdir` errors with invalid utf-8 path - unsafe { chdir(path.as_ptr()) }; //~ ERROR is not a valid utf-8 string -} From 1241abbec473827acf8dbbfff8f79fe08117b967 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 17 Oct 2019 10:21:06 -0500 Subject: [PATCH 1220/5092] Change helper functions to read/write --- src/helpers.rs | 32 ++++++++++++++++++++++++-------- src/shims/env.rs | 20 +++----------------- src/shims/fs.rs | 5 +---- 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index c2e4131a76d1..c384b8974283 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -345,10 +345,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(()) } -} - -pub fn bytes_to_os_string<'tcx>(bytes: Vec) -> InterpResult<'tcx, OsString> { + fn read_os_string(&mut self, scalar: Scalar) -> InterpResult<'tcx, OsString> { + let bytes = self.eval_context_mut().memory.read_c_str(scalar)?.to_vec(); if cfg!(unix) { Ok(std::os::unix::ffi::OsStringExt::from_vec(bytes)) } else { @@ -358,13 +357,30 @@ pub fn bytes_to_os_string<'tcx>(bytes: Vec) -> InterpResult<'tcx, OsString> } } -pub fn os_string_to_bytes<'tcx>(os_string: OsString) -> InterpResult<'tcx, Vec> { - if cfg!(unix) { - Ok(std::os::unix::ffi::OsStringExt::into_vec(os_string)) + fn write_os_string(&mut self, os_string: OsString, ptr: Pointer, size: u64) -> InterpResult<'tcx> { + let mut bytes = if cfg!(unix) { + std::os::unix::ffi::OsStringExt::into_vec(os_string) } else { os_string .into_string() - .map_err(|os_string| err_unsup_format!("{:?} is not a valid utf-8 string", os_string).into()) - .map(|s| s.into_bytes()) + .map_err(|os_string| err_unsup_format!("{:?} is not a valid utf-8 string", os_string))? + .into_bytes() + }; + // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null + // terminator to memory using the `ptr` pointer would cause an overflow. + if (bytes.len() as u64) < size { + // We add a `/0` terminator + bytes.push(0); + let this = self.eval_context_mut(); + let tcx = &{ this.tcx.tcx }; + // This is ok because the buffer was strictly larger than `bytes`, so after adding the + // null terminator, the buffer size is larger or equal to `bytes.len()`, meaning that + // `bytes` actually fit inside tbe buffer. + this.memory + .get_mut(ptr.alloc_id)? + .write_bytes(tcx, ptr, &bytes) + } else { + throw_unsup_format!("OsString is larger than destination") } } +} diff --git a/src/shims/env.rs b/src/shims/env.rs index 1fe08aeffb7b..b344a5c54949 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -127,20 +127,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If we cannot get the current directory, we return null match env::current_dir() { Ok(cwd) => { - // It is not clear what happens with non-utf8 paths here - let mut bytes = helpers::os_string_to_bytes(cwd.into())?; - // If `size` is smaller or equal than the `bytes.len()`, writing `bytes` plus the - // required null terminator to memory using the `buf` pointer would cause an - // overflow. The desired behavior in this case is to return null. - if (bytes.len() as u64) < size { - // We add a `/0` terminator - bytes.push(0); - // This is ok because the buffer was strictly larger than `bytes`, so after - // adding the null terminator, the buffer size is larger or equal to - // `bytes.len()`, meaning that `bytes` actually fit inside tbe buffer. - this.memory - .get_mut(buf.alloc_id)? - .write_bytes(&*this.tcx, buf, &bytes)?; + if this.write_os_string(cwd.into(), buf, size).is_ok() { return Ok(Scalar::Ptr(buf)); } let erange = this.eval_libc("ERANGE")?; @@ -156,10 +143,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("chdir")?; - let bytes = this.memory.read_c_str(this.read_scalar(path_op)?.not_undef()?)?; - let path = helpers::bytes_to_os_string(bytes.to_vec()); + let path = this.read_os_string(this.read_scalar(path_op)?.not_undef()?)?; - match env::set_current_dir(path?) { + match env::set_current_dir(path) { Ok(()) => Ok(0), Err(e) => { this.consume_io_error(e)?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index cc776295bd49..d4f9fde24e1e 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -94,10 +94,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("unsupported flags {:#x}", flag & !mirror); } - let bytes = this - .memory - .read_c_str(this.read_scalar(path_op)?.not_undef()?)?; - let path: std::path::PathBuf = helpers::bytes_to_os_string(bytes.to_vec())?.into(); + let path: std::path::PathBuf = this.read_os_string(this.read_scalar(path_op)?.not_undef()?)?.into(); let fd = options.open(path).map(|file| { let mut fh = &mut this.machine.file_handler; From 68fec4b3fe3a86a01e39d31d05a8438c07845aba Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 17 Oct 2019 21:20:05 -0500 Subject: [PATCH 1221/5092] Use conditional compilation properly and work with `OsStr`s instead --- src/helpers.rs | 60 +++++++++++++++++++++++++++++++----------------- src/shims/env.rs | 3 ++- 2 files changed, 41 insertions(+), 22 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index c384b8974283..32edb107f36e 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,5 +1,5 @@ use std::mem; -use std::ffi::OsString; +use std::ffi::{OsStr, OsString}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; @@ -347,30 +347,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } fn read_os_string(&mut self, scalar: Scalar) -> InterpResult<'tcx, OsString> { - let bytes = self.eval_context_mut().memory.read_c_str(scalar)?.to_vec(); - if cfg!(unix) { - Ok(std::os::unix::ffi::OsStringExt::from_vec(bytes)) - } else { - std::str::from_utf8(&bytes) - .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes).into()) - .map(OsString::from) - } + let bytes = self.eval_context_mut().memory.read_c_str(scalar)?; + Ok(bytes_to_os_str(bytes)?.into()) } - fn write_os_string(&mut self, os_string: OsString, ptr: Pointer, size: u64) -> InterpResult<'tcx> { - let mut bytes = if cfg!(unix) { - std::os::unix::ffi::OsStringExt::into_vec(os_string) - } else { - os_string - .into_string() - .map_err(|os_string| err_unsup_format!("{:?} is not a valid utf-8 string", os_string))? - .into_bytes() - }; + fn write_os_str(&mut self, os_str: &OsStr, ptr: Pointer, size: u64) -> InterpResult<'tcx> { + let bytes = os_str_to_bytes(os_str)?; // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null // terminator to memory using the `ptr` pointer would cause an overflow. if (bytes.len() as u64) < size { - // We add a `/0` terminator - bytes.push(0); let this = self.eval_context_mut(); let tcx = &{ this.tcx.tcx }; // This is ok because the buffer was strictly larger than `bytes`, so after adding the @@ -378,9 +363,42 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `bytes` actually fit inside tbe buffer. this.memory .get_mut(ptr.alloc_id)? - .write_bytes(tcx, ptr, &bytes) + .write_bytes(tcx, ptr, &bytes)?; + // We write the `/0` terminator + let tail_ptr = ptr.offset(Size::from_bytes(bytes.len() as u64 + 1), this)?; + this.memory + .get_mut(ptr.alloc_id)? + .write_bytes(tcx, tail_ptr, b"0") } else { throw_unsup_format!("OsString is larger than destination") } } } + +#[cfg(target_os = "unix")] +fn bytes_to_os_str<'tcx, 'a>(bytes: &'a[u8]) -> InterpResult<'tcx, &'a OsStr> { + Ok(std::os::unix::ffi::OsStringExt::from_bytes(bytes)) +} + +#[cfg(target_os = "unix")] +fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + std::os::unix::ffi::OsStringExt::into_bytes(os_str) +} + +// On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the +// intermediate transformation into strings. Which invalidates non-utf8 paths that are actually +// valid. +#[cfg(not(target_os = "unix"))] +fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + os_str + .to_str() + .map(|s| s.as_bytes()) + .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) +} + +#[cfg(not(target_os = "unix"))] +fn bytes_to_os_str<'tcx, 'a>(bytes: &'a[u8]) -> InterpResult<'tcx, &'a OsStr> { + let s = std::str::from_utf8(bytes) + .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; + Ok(&OsStr::new(s)) +} diff --git a/src/shims/env.rs b/src/shims/env.rs index b344a5c54949..b2e0709557d5 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::ffi::OsString; use std::env; use crate::stacked_borrows::Tag; @@ -127,7 +128,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If we cannot get the current directory, we return null match env::current_dir() { Ok(cwd) => { - if this.write_os_string(cwd.into(), buf, size).is_ok() { + if this.write_os_str(&OsString::from(cwd), buf, size).is_ok() { return Ok(Scalar::Ptr(buf)); } let erange = this.eval_libc("ERANGE")?; From 85941c72497e69653b847744a447ae51b433d4ba Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 18 Oct 2019 09:30:12 -0500 Subject: [PATCH 1222/5092] Rename write/read os string functions --- src/helpers.rs | 4 ++-- src/shims/env.rs | 4 ++-- src/shims/fs.rs | 8 ++------ 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 32edb107f36e..454f7d2c2f80 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -346,12 +346,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - fn read_os_string(&mut self, scalar: Scalar) -> InterpResult<'tcx, OsString> { + fn read_os_string_from_c_string(&mut self, scalar: Scalar) -> InterpResult<'tcx, OsString> { let bytes = self.eval_context_mut().memory.read_c_str(scalar)?; Ok(bytes_to_os_str(bytes)?.into()) } - fn write_os_str(&mut self, os_str: &OsStr, ptr: Pointer, size: u64) -> InterpResult<'tcx> { + fn write_os_str_to_c_string(&mut self, os_str: &OsStr, ptr: Pointer, size: u64) -> InterpResult<'tcx> { let bytes = os_str_to_bytes(os_str)?; // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null // terminator to memory using the `ptr` pointer would cause an overflow. diff --git a/src/shims/env.rs b/src/shims/env.rs index b2e0709557d5..7e2df4f985d1 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -128,7 +128,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If we cannot get the current directory, we return null match env::current_dir() { Ok(cwd) => { - if this.write_os_str(&OsString::from(cwd), buf, size).is_ok() { + if this.write_os_str_to_c_string(&OsString::from(cwd), buf, size).is_ok() { return Ok(Scalar::Ptr(buf)); } let erange = this.eval_libc("ERANGE")?; @@ -144,7 +144,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("chdir")?; - let path = this.read_os_string(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_os_string_from_c_string(this.read_scalar(path_op)?.not_undef()?)?; match env::set_current_dir(path) { Ok(()) => Ok(0), diff --git a/src/shims/fs.rs b/src/shims/fs.rs index d4f9fde24e1e..7cc574f05f13 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -94,7 +94,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("unsupported flags {:#x}", flag & !mirror); } - let path: std::path::PathBuf = this.read_os_string(this.read_scalar(path_op)?.not_undef()?)?.into(); + let path: std::path::PathBuf = this.read_os_string_from_c_string(this.read_scalar(path_op)?.not_undef()?)?.into(); let fd = options.open(path).map(|file| { let mut fh = &mut this.machine.file_handler; @@ -210,11 +210,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("unlink")?; - let path_bytes = this - .memory - .read_c_str(this.read_scalar(path_op)?.not_undef()?)?; - let path = std::str::from_utf8(path_bytes) - .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", path_bytes))?; + let path = this.read_os_string_from_c_string(this.read_scalar(path_op)?.not_undef()?)?; let result = remove_file(path).map(|_| 0); From 0201cc55873dd27f0be148482ad3619083fed80b Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 18 Oct 2019 14:25:49 -0500 Subject: [PATCH 1223/5092] Fix writing errors --- src/helpers.rs | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 454f7d2c2f80..c975ad144e26 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -353,22 +353,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_os_str_to_c_string(&mut self, os_str: &OsStr, ptr: Pointer, size: u64) -> InterpResult<'tcx> { let bytes = os_str_to_bytes(os_str)?; + let len = bytes.len(); // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null // terminator to memory using the `ptr` pointer would cause an overflow. - if (bytes.len() as u64) < size { + if (len as u64) < size { let this = self.eval_context_mut(); let tcx = &{ this.tcx.tcx }; + let buffer = this.memory.get_mut(ptr.alloc_id)?.get_bytes_mut(tcx, ptr, Size::from_bytes(len as u64 + 1))?; + buffer[..len].copy_from_slice(bytes); // This is ok because the buffer was strictly larger than `bytes`, so after adding the // null terminator, the buffer size is larger or equal to `bytes.len()`, meaning that // `bytes` actually fit inside tbe buffer. - this.memory - .get_mut(ptr.alloc_id)? - .write_bytes(tcx, ptr, &bytes)?; - // We write the `/0` terminator - let tail_ptr = ptr.offset(Size::from_bytes(bytes.len() as u64 + 1), this)?; - this.memory - .get_mut(ptr.alloc_id)? - .write_bytes(tcx, tail_ptr, b"0") + buffer[len] = 0; + Ok(()) } else { throw_unsup_format!("OsString is larger than destination") } @@ -376,13 +373,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[cfg(target_os = "unix")] -fn bytes_to_os_str<'tcx, 'a>(bytes: &'a[u8]) -> InterpResult<'tcx, &'a OsStr> { - Ok(std::os::unix::ffi::OsStringExt::from_bytes(bytes)) +fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + std::os::unix::ffi::OsStringExt::into_bytes(os_str) } #[cfg(target_os = "unix")] -fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - std::os::unix::ffi::OsStringExt::into_bytes(os_str) +fn bytes_to_os_str<'tcx, 'a>(bytes: &'a[u8]) -> InterpResult<'tcx, &'a OsStr> { + Ok(std::os::unix::ffi::OsStringExt::from_bytes(bytes)) } // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the From e574c77aa2292ac2a776754a60b1320058bdb071 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 19 Oct 2019 12:28:39 +0200 Subject: [PATCH 1224/5092] audit our bounds checks --- src/eval.rs | 2 +- src/helpers.rs | 1 + src/shims/foreign_items.rs | 19 ++++++------------- src/shims/intrinsics.rs | 2 ++ 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index bb0bad0ea03d..21a7dd35212c 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -162,7 +162,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( MiriMemoryKind::Env.into(), ); ecx.machine.cmd_line = Some(cmd_ptr); - // Store the UTF-16 string. + // Store the UTF-16 string. We just allocated so we know the bounds are fine. let char_size = Size::from_bytes(2); let cmd_alloc = ecx.memory.get_mut(cmd_ptr.alloc_id)?; let mut cur_ptr = cmd_ptr; diff --git a/src/helpers.rs b/src/helpers.rs index c09d5c823e1b..0c22a0f2e065 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -94,6 +94,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let this = self.eval_context_mut(); + // Don't forget the bounds check. let ptr = this.memory.check_ptr_access( ptr, Size::from_bytes(len as u64), diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index cfbb02f60813..cfd3743089e7 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -50,7 +50,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .memory .allocate(Size::from_bytes(size), align, kind.into()); if zero_init { - // We just allocated this, the access cannot fail + // We just allocated this, the access is definitely in-bounds. this.memory .get_mut(ptr.alloc_id) .unwrap() @@ -227,7 +227,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into(), ); - // We just allocated this, the access cannot fail + // We just allocated this, the access is definitely in-bounds. this.memory .get_mut(ptr.alloc_id) .unwrap() @@ -643,7 +643,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Hook pthread calls that go to the thread-local storage memory subsystem. "pthread_key_create" => { - let key_ptr = this.read_scalar(args[0])?.not_undef()?; + let key_place = this.deref_operand(args[0])?; // Extract the function type out of the signature (that seems easier than constructing it ourselves). let dtor = match this.test_null(this.read_scalar(args[1])?.not_undef()?)? { @@ -668,16 +668,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup!(OutOfTls); } - let key_ptr = this - .memory - .check_ptr_access(key_ptr, key_layout.size, key_layout.align.abi)? - .expect("cannot be a ZST"); - this.memory.get_mut(key_ptr.alloc_id)?.write_scalar( - tcx, - key_ptr, - Scalar::from_uint(key, key_layout.size).into(), - key_layout.size, - )?; + this.write_scalar(Scalar::from_uint(key, key_layout.size), key_place.into())?; // Return success (`0`). this.write_null(dest)?; @@ -856,6 +847,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let system_info_ptr = this .check_mplace_access(system_info, None)? .expect("cannot be a ZST"); + // We rely on `deref_operand` doing bounds checks for us. // Initialize with `0`. this.memory .get_mut(system_info_ptr.alloc_id)? @@ -992,6 +984,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let errno_ptr = this.machine.last_error.unwrap(); + // We allocated this during machine initialziation so the bounds are fine. this.memory.get_mut(errno_ptr.alloc_id)?.write_scalar( &*this.tcx, errno_ptr, diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 4666557e200c..cd7db0973666 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -359,6 +359,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert!(mplace.meta.is_none()); // not a zst, must be valid pointer let ptr = mplace.ptr.to_ptr()?; + // we know the return place is in-bounds this.memory.get_mut(ptr.alloc_id)?.write_repeat(tcx, ptr, 0, dest.layout.size)?; } } @@ -548,6 +549,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mplace = this.force_allocation(dest)?; assert!(mplace.meta.is_none()); let ptr = mplace.ptr.to_ptr()?; + // We know the return place is in-bounds this.memory .get_mut(ptr.alloc_id)? .mark_definedness(ptr, dest.layout.size, false); From 324fed316f019a24b7a442a7759040fdd650b69f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 19 Oct 2019 16:36:45 +0200 Subject: [PATCH 1225/5092] print sysroot without any escaping --- miri | 2 +- src/bin/cargo-miri.rs | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/miri b/miri index 6de2391137ac..c3d7ae0280c7 100755 --- a/miri +++ b/miri @@ -54,7 +54,7 @@ build_sysroot() { # Build once, for the user to see. cargo run $CARGO_BUILD_FLAGS --bin cargo-miri -- miri setup "$@" # Call again, to just set env var. - eval $(cargo run $CARGO_BUILD_FLAGS -q --bin cargo-miri -- miri setup --env "$@") + export MIRI_SYSROOT="$(cargo run $CARGO_BUILD_FLAGS -q --bin cargo-miri -- miri setup --print-sysroot "$@")" } # Prepare and set MIRI_SYSROOT. Respects `MIRI_TEST_TARGET` and takes into account diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index b189dc1f808c..cf513bc1d269 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -310,7 +310,7 @@ path = "lib.rs" File::create(dir.join("lib.rs")).unwrap(); // Prepare xargo invocation. let target = get_arg_flag_value("--target"); - let print_env = !ask_user && has_arg_flag("--env"); // whether we just print the necessary environment variable + let print_sysroot = !ask_user && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path let mut command = xargo(); command.arg("build").arg("-q"); command.current_dir(&dir); @@ -339,13 +339,9 @@ path = "lib.rs" }; let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; std::env::set_var("MIRI_SYSROOT", &sysroot); // pass the env var to the processes we spawn, which will turn it into "--sysroot" flags - if print_env { - // Escape an arbitrary string for the shell: by wrapping it in `'`, the only special - // character we have to worry about is `'` itself. Everything else is taken literally - // in these strings. `'` is encoded as `'"'"'`: the outer `'` end and being a - // `'`-quoted string, respectively; the `"'"` in the middle represents a single `'`. - // (We could use `'\''` instead of `'"'"'` if we wanted but let's avoid backslashes.) - println!("MIRI_SYSROOT='{}'", sysroot.display().to_string().replace('\'', r#"'"'"'"#)); + if print_sysroot { + // Print just the sysroot and nothing else; this way we do not need any escaping. + println!("{}", sysroot.display()); } else if !ask_user { println!("A libstd for Miri is now available in `{}`.", sysroot.display()); } From ab059671cb78016bb039b3db07c62279d37ef42b Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 19 Oct 2019 14:13:49 -0500 Subject: [PATCH 1226/5092] Change comparison order for clarity --- src/helpers.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index c975ad144e26..ddaf8f48a5aa 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -356,19 +356,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let len = bytes.len(); // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null // terminator to memory using the `ptr` pointer would cause an overflow. - if (len as u64) < size { - let this = self.eval_context_mut(); - let tcx = &{ this.tcx.tcx }; - let buffer = this.memory.get_mut(ptr.alloc_id)?.get_bytes_mut(tcx, ptr, Size::from_bytes(len as u64 + 1))?; - buffer[..len].copy_from_slice(bytes); - // This is ok because the buffer was strictly larger than `bytes`, so after adding the - // null terminator, the buffer size is larger or equal to `bytes.len()`, meaning that - // `bytes` actually fit inside tbe buffer. - buffer[len] = 0; - Ok(()) - } else { - throw_unsup_format!("OsString is larger than destination") + if size <= bytes.len() as u64 { + throw_unsup_format!("OsString of length {} is too large for destination buffer of size {}", len, size) } + + let this = self.eval_context_mut(); + let buffer = this.memory.get_mut(ptr.alloc_id)?.get_bytes_mut(&*this.tcx, ptr, Size::from_bytes(len as u64 + 1))?; + buffer[..len].copy_from_slice(bytes); + // This is ok because the buffer was strictly larger than `bytes`, so after adding the + // null terminator, the buffer size is larger or equal to `bytes.len()`, meaning that + // `bytes` actually fit inside tbe buffer. + buffer[len] = 0; + Ok(()) } } From f7c6e0efbe11343562c713dce1d28e2d141dcb89 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 19 Oct 2019 15:49:00 -0500 Subject: [PATCH 1227/5092] Do additional bounds checks --- src/helpers.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index ddaf8f48a5aa..63380199beab 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -356,12 +356,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let len = bytes.len(); // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null // terminator to memory using the `ptr` pointer would cause an overflow. - if size <= bytes.len() as u64 { + if size <= len as u64 { throw_unsup_format!("OsString of length {} is too large for destination buffer of size {}", len, size) } - + let actual_len = (len as u64) + .checked_add(1) + .map(Size::from_bytes) + .ok_or_else(|| err_unsup_format!("OsString of length {} is too large", len))?; let this = self.eval_context_mut(); - let buffer = this.memory.get_mut(ptr.alloc_id)?.get_bytes_mut(&*this.tcx, ptr, Size::from_bytes(len as u64 + 1))?; + this.memory.check_ptr_access(ptr.into(), actual_len, Align::from_bytes(1).unwrap())?; + let buffer = this.memory.get_mut(ptr.alloc_id)?.get_bytes_mut(&*this.tcx, ptr, actual_len)?; buffer[..len].copy_from_slice(bytes); // This is ok because the buffer was strictly larger than `bytes`, so after adding the // null terminator, the buffer size is larger or equal to `bytes.len()`, meaning that From 88c88530ec5788ada08bcf23d6c7b149337f0713 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 20 Oct 2019 12:20:48 +0200 Subject: [PATCH 1228/5092] use expect_none and unwrap_none where it makes sense --- src/eval.rs | 5 +---- src/lib.rs | 1 + src/machine.rs | 5 +---- src/shims/foreign_items.rs | 5 +---- src/shims/fs.rs | 7 ++++--- src/shims/intrinsics.rs | 4 ++-- src/shims/tls.rs | 2 +- src/stacked_borrows.rs | 4 ++-- 8 files changed, 13 insertions(+), 20 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 21a7dd35212c..6fb1cd25b159 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -177,10 +177,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } } - assert!( - args.next().is_none(), - "start lang item has more arguments than expected" - ); + args.next().expect_none("start lang item has more arguments than expected"); // Set the last_error to 0 let errno_layout = ecx.layout_of(ecx.tcx.types.u32)?; diff --git a/src/lib.rs b/src/lib.rs index 06ec33a914bf..59acff358678 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ #![feature(rustc_private)] +#![feature(option_expect_none, option_unwrap_none)] #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] diff --git a/src/machine.rs b/src/machine.rs index d20346ba468a..3878a0860538 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -244,10 +244,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx.write_scalar(Scalar::from_uint(align, arg.layout.size), arg)?; // No more arguments. - assert!( - args.next().is_none(), - "`exchange_malloc` lang item has more arguments than expected" - ); + args.next().expect_none("`exchange_malloc` lang item has more arguments than expected"); Ok(()) } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index cfd3743089e7..b28e361b1377 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -349,10 +349,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let arg_dest = this.local_place(arg_local)?; this.write_scalar(data, arg_dest)?; - assert!( - args.next().is_none(), - "__rust_maybe_catch_panic argument has more arguments than expected" - ); + args.next().expect_none("__rust_maybe_catch_panic argument has more arguments than expected"); // We ourselves will return `0`, eventually (because we will not return if we paniced). this.write_null(dest)?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 891474bc3bdb..ed2465cd1f97 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -7,6 +7,7 @@ use rustc::ty::layout::Size; use crate::stacked_borrows::Tag; use crate::*; +#[derive(Debug)] pub struct FileHandle { file: File, } @@ -103,7 +104,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = options.open(path).map(|file| { let mut fh = &mut this.machine.file_handler; fh.low += 1; - fh.handles.insert(fh.low, FileHandle { file }); + fh.handles.insert(fh.low, FileHandle { file }).unwrap_none(); fh.low }); @@ -175,7 +176,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .map(|buffer| handle.file.read(buffer)) }); // Reinsert the file handle - this.machine.file_handler.handles.insert(fd, handle); + this.machine.file_handler.handles.insert(fd, handle).unwrap_none(); this.consume_result(bytes?.map(|bytes| bytes as i64)) }) } @@ -204,7 +205,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .get_bytes(&*this.tcx, buf, Size::from_bytes(count)) .map(|bytes| handle.file.write(bytes).map(|bytes| bytes as i64)) }); - this.machine.file_handler.handles.insert(fd, handle); + this.machine.file_handler.handles.insert(fd, handle).unwrap_none(); this.consume_result(bytes?) }) } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index cd7db0973666..46658760cc12 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -356,7 +356,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => { // Do it in memory let mplace = this.force_allocation(dest)?; - assert!(mplace.meta.is_none()); + mplace.meta.unwrap_none(); // not a zst, must be valid pointer let ptr = mplace.ptr.to_ptr()?; // we know the return place is in-bounds @@ -547,7 +547,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => { // Do it in memory let mplace = this.force_allocation(dest)?; - assert!(mplace.meta.is_none()); + mplace.meta.unwrap_none(); let ptr = mplace.ptr.to_ptr()?; // We know the return place is in-bounds this.memory diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 44bedbd44d2d..b6aadd31a5be 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -53,7 +53,7 @@ impl<'tcx> TlsData<'tcx> { data: None, dtor, }, - ); + ).unwrap_none(); trace!("New TLS key allocated: {} with dtor {:?}", new_key, dtor); new_key } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index d219c1c75834..2188b9d5394a 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -172,7 +172,7 @@ impl GlobalState { pub fn new_call(&mut self) -> CallId { let id = self.next_call_id; trace!("new_call: Assigning ID {}", id); - self.active_calls.insert(id); + assert!(self.active_calls.insert(id)); self.next_call_id = NonZeroU64::new(id.get() + 1).unwrap(); id } @@ -189,7 +189,7 @@ impl GlobalState { self.base_ptr_ids.get(&id).copied().unwrap_or_else(|| { let tag = Tag::Tagged(self.new_ptr()); trace!("New allocation {:?} has base tag {:?}", id, tag); - self.base_ptr_ids.insert(id, tag); + self.base_ptr_ids.insert(id, tag).unwrap_none(); tag }) } From 4232939319448244bacd8376049a17325225eadb Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 12 Oct 2019 20:44:45 -0500 Subject: [PATCH 1229/5092] Move last error functions to helpers --- src/helpers.rs | 35 +++++++++++++++++++++++++++++++++++ src/shims/env.rs | 4 ++-- src/shims/foreign_items.rs | 28 ---------------------------- src/shims/fs.rs | 2 +- 4 files changed, 38 insertions(+), 31 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 0c22a0f2e065..36091d923555 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -345,4 +345,39 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(()) } + + /// Sets the last error variable + fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let tcx = &{ this.tcx.tcx }; + let errno_ptr = this.machine.last_error.unwrap(); + this.memory.get_mut(errno_ptr.alloc_id)?.write_scalar( + tcx, + errno_ptr, + scalar.into(), + Size::from_bits(32), + ) + } + + /// Gets the last error variable + fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + let tcx = &{ this.tcx.tcx }; + let errno_ptr = this.machine.last_error.unwrap(); + this.memory + .get(errno_ptr.alloc_id)? + .read_scalar(tcx, errno_ptr, Size::from_bits(32))? + .not_undef() + } + + /// Sets the last error variable using a `std::io::Error`. It fails if the error cannot be + /// transformed to a raw os error succesfully + fn set_last_error_from_io_error(&mut self, e: std::io::Error) -> InterpResult<'tcx> { + self.eval_context_mut().set_last_error(Scalar::from_int( + e.raw_os_error().ok_or_else(|| { + err_unsup_format!("The {} error cannot be transformed into a raw os error", e) + })?, + Size::from_bits(32), + )) + } } diff --git a/src/shims/env.rs b/src/shims/env.rs index 6078ca26e269..661e8bf209b1 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -146,7 +146,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let erange = this.eval_libc("ERANGE")?; this.set_last_error(erange)?; } - Err(e) => this.consume_io_error(e)?, + Err(e) => this.set_last_error_from_io_error(e)?, } Ok(Scalar::ptr_null(&*this.tcx)) } @@ -168,7 +168,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match env::set_current_dir(path) { Ok(()) => Ok(0), Err(e) => { - this.consume_io_error(e)?; + this.set_last_error_from_io_error(e)?; Ok(-1) } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index b28e361b1377..5d2c3648b43a 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -977,34 +977,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } return Ok(None); } - - fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - let errno_ptr = this.machine.last_error.unwrap(); - // We allocated this during machine initialziation so the bounds are fine. - this.memory.get_mut(errno_ptr.alloc_id)?.write_scalar( - &*this.tcx, - errno_ptr, - scalar.into(), - Size::from_bits(32), - ) - } - - fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { - let this = self.eval_context_mut(); - let errno_ptr = this.machine.last_error.unwrap(); - this.memory - .get(errno_ptr.alloc_id)? - .read_scalar(&*this.tcx, errno_ptr, Size::from_bits(32))? - .not_undef() - } - - fn consume_io_error(&mut self, e: std::io::Error) -> InterpResult<'tcx> { - self.eval_context_mut().set_last_error(Scalar::from_int( - e.raw_os_error().unwrap(), - Size::from_bits(32), - )) - } } // Shims the linux 'getrandom()' syscall. diff --git a/src/shims/fs.rs b/src/shims/fs.rs index ed2465cd1f97..8fcd5c8b1e3e 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -285,7 +285,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match result { Ok(ok) => Ok(ok), Err(e) => { - self.eval_context_mut().consume_io_error(e)?; + self.eval_context_mut().set_last_error_from_io_error(e)?; Ok((-1).into()) } } From ed776f67ba73380926d987bb8ba6618fa0cc55f3 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 12 Oct 2019 20:58:02 -0500 Subject: [PATCH 1230/5092] Change last_error to a place --- src/eval.rs | 3 +-- src/helpers.rs | 18 ++++-------------- src/machine.rs | 4 ++-- src/shims/foreign_items.rs | 3 ++- 4 files changed, 9 insertions(+), 19 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 6fb1cd25b159..f4a8d176172d 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -183,8 +183,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let errno_layout = ecx.layout_of(ecx.tcx.types.u32)?; let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Static.into()); ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?; - let errno_ptr = ecx.check_mplace_access(errno_place.into(), Some(Size::from_bits(32)))?; - ecx.machine.last_error = errno_ptr; + ecx.machine.last_error = Some(errno_place); Ok(ecx) } diff --git a/src/helpers.rs b/src/helpers.rs index 36091d923555..1b80166b2fe7 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -349,25 +349,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Sets the last error variable fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let tcx = &{ this.tcx.tcx }; - let errno_ptr = this.machine.last_error.unwrap(); - this.memory.get_mut(errno_ptr.alloc_id)?.write_scalar( - tcx, - errno_ptr, - scalar.into(), - Size::from_bits(32), - ) + let errno_place = this.machine.last_error.unwrap(); + this.write_scalar(scalar, errno_place.into()) } /// Gets the last error variable fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let tcx = &{ this.tcx.tcx }; - let errno_ptr = this.machine.last_error.unwrap(); - this.memory - .get(errno_ptr.alloc_id)? - .read_scalar(tcx, errno_ptr, Size::from_bits(32))? - .not_undef() + let errno_place = this.machine.last_error.unwrap(); + this.read_scalar(errno_place.into())?.not_undef() } /// Sets the last error variable using a `std::io::Error`. It fails if the error cannot be diff --git a/src/machine.rs b/src/machine.rs index 3878a0860538..3714aa2d799e 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -91,8 +91,8 @@ pub struct Evaluator<'tcx> { pub(crate) argv: Option>, pub(crate) cmd_line: Option>, - /// Last OS error. - pub(crate) last_error: Option>, + /// Last OS error location in memory. It is a 32 bits integer (unsigned for Windows) + pub(crate) last_error: Option>, /// TLS state. pub(crate) tls: TlsData<'tcx>, diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 5d2c3648b43a..51be7ea5bcd3 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -414,7 +414,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "__errno_location" | "__error" => { - let errno_scalar: Scalar = this.machine.last_error.unwrap().into(); + let errno_place = this.machine.last_error.unwrap(); + let errno_scalar: Scalar = this.check_mplace_access(errno_place.into(), Some(Size::from_bits(32)))?.unwrap().into(); this.write_scalar(errno_scalar, dest)?; } From 338e51aa48fbf9d5f3407c3872e46facfab53ca3 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 16 Oct 2019 21:37:35 -0500 Subject: [PATCH 1231/5092] Rename consume_result --- src/helpers.rs | 19 +++++++++++++++++++ src/shims/fs.rs | 29 +++++------------------------ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 1b80166b2fe7..465fca554c10 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -370,4 +370,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Size::from_bits(32), )) } + + /// Helper function that consumes an `std::io::Result` and returns an + /// `InterpResult<'tcx,T>::Ok` instead. It is expected that the result can be converted to an + /// OS error using `std::io::Error::raw_os_error`. + /// + /// This function uses `T: From` instead of `i32` directly because some IO related + /// functions return different integer types (like `read`, that returns an `i64`) + fn set_last_error_from_io_result>( + &mut self, + result: std::io::Result, + ) -> InterpResult<'tcx, T> { + match result { + Ok(ok) => Ok(ok), + Err(e) => { + self.eval_context_mut().set_last_error_from_io_error(e)?; + Ok((-1).into()) + } + } + } } diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 8fcd5c8b1e3e..c8d1eb29562d 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -108,7 +108,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fh.low }); - this.consume_result(fd) + this.set_last_error_from_io_result(fd) } fn fcntl( @@ -144,7 +144,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; this.remove_handle_and(fd, |handle, this| { - this.consume_result(handle.file.sync_all().map(|_| 0i32)) + this.set_last_error_from_io_result(handle.file.sync_all().map(|_| 0i32)) }) } @@ -177,7 +177,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }); // Reinsert the file handle this.machine.file_handler.handles.insert(fd, handle).unwrap_none(); - this.consume_result(bytes?.map(|bytes| bytes as i64)) + this.set_last_error_from_io_result(bytes?.map(|bytes| bytes as i64)) }) } @@ -206,7 +206,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .map(|bytes| handle.file.write(bytes).map(|bytes| bytes as i64)) }); this.machine.file_handler.handles.insert(fd, handle).unwrap_none(); - this.consume_result(bytes?) + this.set_last_error_from_io_result(bytes?) }) } @@ -223,7 +223,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = remove_file(path).map(|_| 0); - this.consume_result(result) + this.set_last_error_from_io_result(result) } /// Helper function that gets a `FileHandle` immutable reference and allows to manipulate it @@ -271,23 +271,4 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok((-1).into()) } } - - /// Helper function that consumes an `std::io::Result` and returns an - /// `InterpResult<'tcx,T>::Ok` instead. It is expected that the result can be converted to an - /// OS error using `std::io::Error::raw_os_error`. - /// - /// This function uses `T: From` instead of `i32` directly because some IO related - /// functions return different integer types (like `read`, that returns an `i64`) - fn consume_result>( - &mut self, - result: std::io::Result, - ) -> InterpResult<'tcx, T> { - match result { - Ok(ok) => Ok(ok), - Err(e) => { - self.eval_context_mut().set_last_error_from_io_error(e)?; - Ok((-1).into()) - } - } - } } From 5c3c738c4b82a00471cffe67e44a22173404bd4f Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 17 Oct 2019 20:29:30 -0500 Subject: [PATCH 1232/5092] Make transformation to OS error explicit --- src/helpers.rs | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 465fca554c10..7d68d05cdb78 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -361,14 +361,34 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Sets the last error variable using a `std::io::Error`. It fails if the error cannot be - /// transformed to a raw os error succesfully + /// transformed to a raw os error succesfully. fn set_last_error_from_io_error(&mut self, e: std::io::Error) -> InterpResult<'tcx> { - self.eval_context_mut().set_last_error(Scalar::from_int( - e.raw_os_error().ok_or_else(|| { - err_unsup_format!("The {} error cannot be transformed into a raw os error", e) - })?, - Size::from_bits(32), - )) + use std::io::ErrorKind::*; + let this = self.eval_context_mut(); + let target = &this.tcx.tcx.sess.target.target; + let last_error = if target.options.target_family == Some("unix".to_owned()) { + this.eval_libc(match e.kind() { + ConnectionRefused => "ECONNREFUSED", + ConnectionReset => "ECONNRESET", + PermissionDenied => "EPERM", + BrokenPipe => "EPIPE", + NotConnected => "ENOTCONN", + ConnectionAborted => "ECONNABORTED", + AddrNotAvailable => "EADDRNOTAVAIL", + AddrInUse => "EADDRINUSE", + NotFound => "ENOENT", + Interrupted => "EINTR", + InvalidInput => "EINVAL", + TimedOut => "ETIMEDOUT", + AlreadyExists => "EEXIST", + WouldBlock => "EWOULDBLOCK", + _ => throw_unsup_format!("The {} error cannot be transformed into a raw os error", e) + })? + } else { + // FIXME: we have to implement the windows' equivalent of this. + throw_unsup_format!("Setting the last OS error from an io::Error is unsupported for {}.", target.target_os) + }; + this.set_last_error(last_error) } /// Helper function that consumes an `std::io::Result` and returns an From 619ccf3834d18eeef1aea4030e5c2bcf673e5688 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 18 Oct 2019 14:33:25 -0500 Subject: [PATCH 1233/5092] Rename set_last_error_from_io_result --- src/helpers.rs | 10 +++++----- src/machine.rs | 2 +- src/shims/fs.rs | 11 +++++------ 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 7d68d05cdb78..616de8378791 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -360,8 +360,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.read_scalar(errno_place.into())?.not_undef() } - /// Sets the last error variable using a `std::io::Error`. It fails if the error cannot be - /// transformed to a raw os error succesfully. + /// Sets the last OS error using a `std::io::Error`. This function tries to produce the most + /// similar OS error from the `std::io::ErrorKind` and sets it as the last OS error. fn set_last_error_from_io_error(&mut self, e: std::io::Error) -> InterpResult<'tcx> { use std::io::ErrorKind::*; let this = self.eval_context_mut(); @@ -392,12 +392,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Helper function that consumes an `std::io::Result` and returns an - /// `InterpResult<'tcx,T>::Ok` instead. It is expected that the result can be converted to an - /// OS error using `std::io::Error::raw_os_error`. + /// `InterpResult<'tcx,T>::Ok` instead. In case the result is an error, this function returns + /// `Ok(-1)` and sets the last OS error accordingly. /// /// This function uses `T: From` instead of `i32` directly because some IO related /// functions return different integer types (like `read`, that returns an `i64`) - fn set_last_error_from_io_result>( + fn try_unwrap_io_result>( &mut self, result: std::io::Result, ) -> InterpResult<'tcx, T> { diff --git a/src/machine.rs b/src/machine.rs index 3714aa2d799e..315e9c1a35a9 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -91,7 +91,7 @@ pub struct Evaluator<'tcx> { pub(crate) argv: Option>, pub(crate) cmd_line: Option>, - /// Last OS error location in memory. It is a 32 bits integer (unsigned for Windows) + /// Last OS error location in memory. It is a 32 bit integer (unsigned for Windows) pub(crate) last_error: Option>, /// TLS state. diff --git a/src/shims/fs.rs b/src/shims/fs.rs index c8d1eb29562d..ffcfab10081a 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -108,7 +108,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fh.low }); - this.set_last_error_from_io_result(fd) + this.try_unwrap_io_result(fd) } fn fcntl( @@ -144,7 +144,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; this.remove_handle_and(fd, |handle, this| { - this.set_last_error_from_io_result(handle.file.sync_all().map(|_| 0i32)) + this.try_unwrap_io_result(handle.file.sync_all().map(|_| 0i32)) }) } @@ -175,9 +175,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .get_bytes_mut(&*this.tcx, buf, Size::from_bytes(count)) .map(|buffer| handle.file.read(buffer)) }); - // Reinsert the file handle this.machine.file_handler.handles.insert(fd, handle).unwrap_none(); - this.set_last_error_from_io_result(bytes?.map(|bytes| bytes as i64)) + this.try_unwrap_io_result(bytes?.map(|bytes| bytes as i64)) }) } @@ -206,7 +205,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .map(|bytes| handle.file.write(bytes).map(|bytes| bytes as i64)) }); this.machine.file_handler.handles.insert(fd, handle).unwrap_none(); - this.set_last_error_from_io_result(bytes?) + this.try_unwrap_io_result(bytes?) }) } @@ -223,7 +222,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = remove_file(path).map(|_| 0); - this.set_last_error_from_io_result(result) + this.try_unwrap_io_result(result) } /// Helper function that gets a `FileHandle` immutable reference and allows to manipulate it From 8a8fa53a5d28fa3e849e26e907480dd28b8f2aa3 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 18 Oct 2019 14:44:48 -0500 Subject: [PATCH 1234/5092] Transform the last error place to an immediate instead --- src/shims/foreign_items.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 51be7ea5bcd3..1933aee1151d 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -415,8 +415,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "__errno_location" | "__error" => { let errno_place = this.machine.last_error.unwrap(); - let errno_scalar: Scalar = this.check_mplace_access(errno_place.into(), Some(Size::from_bits(32)))?.unwrap().into(); - this.write_scalar(errno_scalar, dest)?; + this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } "getenv" => { From 9d50c5e75806bc27fc0b144be92b895c2f2a7339 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 19 Oct 2019 14:00:44 -0500 Subject: [PATCH 1235/5092] Small corrections to docs --- src/helpers.rs | 4 ++-- src/machine.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 616de8378791..16091bb242cd 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -346,14 +346,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - /// Sets the last error variable + /// Sets the last error variable. fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let errno_place = this.machine.last_error.unwrap(); this.write_scalar(scalar, errno_place.into()) } - /// Gets the last error variable + /// Gets the last error variable. fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let errno_place = this.machine.last_error.unwrap(); diff --git a/src/machine.rs b/src/machine.rs index 315e9c1a35a9..50f0ecf59093 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -91,7 +91,7 @@ pub struct Evaluator<'tcx> { pub(crate) argv: Option>, pub(crate) cmd_line: Option>, - /// Last OS error location in memory. It is a 32 bit integer (unsigned for Windows) + /// Last OS error location in memory. It is a 32-bit integer pub(crate) last_error: Option>, /// TLS state. From 283a130ddafa01537123b0650f869abc14886911 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sun, 20 Oct 2019 17:40:21 -0500 Subject: [PATCH 1236/5092] Add docs for the new helper functions --- src/helpers.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/helpers.rs b/src/helpers.rs index 63380199beab..4d84106dbe86 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -346,11 +346,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } + /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what + /// the Unix APIs usually handle. fn read_os_string_from_c_string(&mut self, scalar: Scalar) -> InterpResult<'tcx, OsString> { let bytes = self.eval_context_mut().memory.read_c_str(scalar)?; Ok(bytes_to_os_str(bytes)?.into()) } + /// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what + /// the Unix APIs usually handle. fn write_os_str_to_c_string(&mut self, os_str: &OsStr, ptr: Pointer, size: u64) -> InterpResult<'tcx> { let bytes = os_str_to_bytes(os_str)?; let len = bytes.len(); From ebdb6d4df73c244b4b6dae761c900db896263a89 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Oct 2019 10:25:47 +0200 Subject: [PATCH 1237/5092] when xargo is manually specified, don't try to upgrade it --- src/bin/cargo-miri.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index cf513bc1d269..b889ce52f386 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -259,6 +259,10 @@ fn setup(ask_user: bool) { // First, we need xargo. if xargo_version().map_or(true, |v| v < (0, 3, 16)) { + if std::env::var("XARGO").is_ok() { + // The user manually gave us a xargo binary; don't do anything automatically. + show_error(format!("Your xargo is too old; please upgrade to the latest version")) + } let mut cmd = cargo(); cmd.args(&["install", "xargo", "-f"]); ask_to_run(cmd, ask_user, "install a recent enough xargo"); From d9aa20fb3135436706ba8b9dd387edfde9127ddb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Oct 2019 13:24:56 +0200 Subject: [PATCH 1238/5092] add some missing trailing full stops that slipped through review --- src/machine.rs | 2 +- src/shims/fs.rs | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 50f0ecf59093..7904e1cc123b 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -91,7 +91,7 @@ pub struct Evaluator<'tcx> { pub(crate) argv: Option>, pub(crate) cmd_line: Option>, - /// Last OS error location in memory. It is a 32-bit integer + /// Last OS error location in memory. It is a 32-bit integer. pub(crate) last_error: Option>, /// TLS state. diff --git a/src/shims/fs.rs b/src/shims/fs.rs index ffcfab10081a..902f5f609d18 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -21,7 +21,7 @@ impl Default for FileHandler { fn default() -> Self { FileHandler { handles: Default::default(), - // 0, 1 and 2 are reserved for stdin, stdout and stderr + // 0, 1 and 2 are reserved for stdin, stdout and stderr. low: 3, } } @@ -123,7 +123,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; let cmd = this.read_scalar(cmd_op)?.to_i32()?; - // We only support getting the flags for a descriptor + // We only support getting the flags for a descriptor. if cmd == this.eval_libc_i32("F_GETFD")? { // Currently this is the only flag that `F_GETFD` returns. It is OK to just return the // `FD_CLOEXEC` value without checking if the flag is set for the file because `std` @@ -159,16 +159,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("read")?; let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; - // Reading zero bytes should not change `buf` + // Reading zero bytes should not change `buf`. if count == 0 { return Ok(0); } let fd = this.read_scalar(fd_op)?.to_i32()?; let buf_scalar = this.read_scalar(buf_op)?.not_undef()?; - // Remove the file handle to avoid borrowing issues + // Remove the file handle to avoid borrowing issues. this.remove_handle_and(fd, |mut handle, this| { - // Don't use `?` to avoid returning before reinserting the handle + // Don't use `?` to avoid returning before reinserting the handle. let bytes = this.force_ptr(buf_scalar).and_then(|buf| { this.memory .get_mut(buf.alloc_id)? @@ -191,7 +191,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("write")?; let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; - // Writing zero bytes should not change `buf` + // Writing zero bytes should not change `buf`. if count == 0 { return Ok(0); } @@ -232,7 +232,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// and sets `Evaluator::last_error` to `libc::EBADF` (invalid file descriptor). /// /// This function uses `T: From` instead of `i32` directly because some IO related - /// functions return different integer types (like `read`, that returns an `i64`) + /// functions return different integer types (like `read`, that returns an `i64`). fn get_handle_and>(&mut self, fd: i32, f: F) -> InterpResult<'tcx, T> where F: Fn(&FileHandle) -> InterpResult<'tcx, T>, @@ -256,7 +256,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// and sets `Evaluator::last_error` to `libc::EBADF` (invalid file descriptor). /// /// This function uses `T: From` instead of `i32` directly because some IO related - /// functions return different integer types (like `read`, that returns an `i64`) + /// functions return different integer types (like `read`, that returns an `i64`). fn remove_handle_and>(&mut self, fd: i32, mut f: F) -> InterpResult<'tcx, T> where F: FnMut(FileHandle, &mut MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx, T>, From 789eeee6a5eed7926d3ced5684b624071d9bbf5d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Oct 2019 13:31:38 +0200 Subject: [PATCH 1239/5092] bump Rust (no changes needed) --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 0f59c13723c7..8e2cace33850 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -fa0f7d0080d8e7e9eb20aa9cbf8013f96c81287f +7979016aff545f7b41cc517031026020b340989d From 2690f5948ad4746655e073fc7367df95b0eb22d2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 22 Oct 2019 10:13:11 +0200 Subject: [PATCH 1240/5092] rustup: fix for write_bytes and new union rules --- Cargo.lock | 16 ++++++++++++++++ Cargo.toml | 1 + rust-version | 2 +- src/eval.rs | 5 +++-- src/helpers.rs | 11 ++--------- src/shims/env.rs | 8 +++----- src/shims/foreign_items.rs | 29 ++++++++--------------------- src/shims/intrinsics.rs | 18 +++--------------- tests/run-pass/union-overwrite.rs | 7 ++++--- 9 files changed, 41 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8d80f1f11cd1..d3b6ee0bb531 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -215,6 +215,11 @@ dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "either" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "env_logger" version = "0.6.2" @@ -294,6 +299,14 @@ dependencies = [ "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "itertools" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "itoa" version = "0.4.4" @@ -343,6 +356,7 @@ dependencies = [ "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -828,6 +842,7 @@ dependencies = [ "checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" "checksum directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c" "checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" +"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" "checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" @@ -837,6 +852,7 @@ dependencies = [ "checksum getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "fc344b02d3868feb131e8b5fe2b9b0a1cc42942679af493061fc13b853243872" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" +"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" diff --git a/Cargo.toml b/Cargo.toml index bd345ea2b7f5..91da02eac8a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,7 @@ log = "0.4" shell-escape = "0.1.4" hex = "0.3.2" rand = "0.7" +itertools = "0.8" # A noop dependency that changes in the Rust repository, it's a bit of a hack. # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` diff --git a/rust-version b/rust-version index 8e2cace33850..b2b3a89fe956 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7979016aff545f7b41cc517031026020b340989d +6576f4be5af31a5e61dfc0cf50b7130e6c6dfb35 diff --git a/src/eval.rs b/src/eval.rs index f4a8d176172d..13396e845da1 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -257,8 +257,9 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) { trace!("-------------------"); trace!("Frame {}", i); trace!(" return: {:?}", frame.return_place.map(|p| *p)); - for (i, local) in frame.locals.iter().enumerate() { - trace!(" local {}: {:?}", i, local.value); + for (_i, _local) in frame.locals.iter().enumerate() { + //trace!(" local {}: {:?}", i, local.value); + //FIXME: enable this again when the LocalValue Debug impl is back } } } diff --git a/src/helpers.rs b/src/helpers.rs index 16091bb242cd..9e1fa3437058 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -4,7 +4,7 @@ use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc::ty::{ self, - layout::{self, Align, LayoutOf, Size, TyLayout}, + layout::{self, LayoutOf, Size, TyLayout}, }; use rand::RngCore; @@ -94,13 +94,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let this = self.eval_context_mut(); - // Don't forget the bounds check. - let ptr = this.memory.check_ptr_access( - ptr, - Size::from_bytes(len as u64), - Align::from_bytes(1).unwrap() - )?.expect("we already checked for size 0"); - let mut data = vec![0; len]; if this.machine.communicate { @@ -113,7 +106,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx rng.fill_bytes(&mut data); } - this.memory.get_mut(ptr.alloc_id)?.write_bytes(&*this.tcx, ptr, &data) + this.memory.write_bytes(ptr, data.iter().copied()) } /// Visits the memory covered by `place`, sensitive to freezing: the 3rd parameter diff --git a/src/shims/env.rs b/src/shims/env.rs index 661e8bf209b1..28f1c7d2ef9e 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -122,7 +122,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("getcwd")?; - let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; + let buf = this.read_scalar(buf_op)?.not_undef()?; let size = this.read_scalar(size_op)?.to_usize(&*this.tcx)?; // If we cannot get the current directory, we return null match env::current_dir() { @@ -138,10 +138,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This is ok because the buffer was strictly larger than `bytes`, so after // adding the null terminator, the buffer size is larger or equal to // `bytes.len()`, meaning that `bytes` actually fit inside tbe buffer. - this.memory - .get_mut(buf.alloc_id)? - .write_bytes(&*this.tcx, buf, &bytes)?; - return Ok(Scalar::Ptr(buf)); + this.memory.write_bytes(buf, bytes.iter().copied())?; + return Ok(buf); } let erange = this.eval_libc("ERANGE")?; this.set_last_error(erange)?; diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 1933aee1151d..f951cf2df77c 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -52,9 +52,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if zero_init { // We just allocated this, the access is definitely in-bounds. this.memory - .get_mut(ptr.alloc_id) - .unwrap() - .write_repeat(&*this.tcx, ptr, 0, Size::from_bytes(size)) + .write_bytes(ptr.into(), itertools::repeat_n(0u8, size as usize)) .unwrap(); } Scalar::Ptr(ptr) @@ -229,9 +227,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); // We just allocated this, the access is definitely in-bounds. this.memory - .get_mut(ptr.alloc_id) - .unwrap() - .write_repeat(tcx, ptr, 0, Size::from_bytes(size)) + .write_bytes(ptr.into(), itertools::repeat_n(0u8, size as usize)) .unwrap(); this.write_scalar(Scalar::Ptr(ptr), dest)?; } @@ -841,25 +837,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "GetSystemInfo" => { let system_info = this.deref_operand(args[0])?; - let system_info_ptr = this - .check_mplace_access(system_info, None)? - .expect("cannot be a ZST"); - // We rely on `deref_operand` doing bounds checks for us. // Initialize with `0`. this.memory - .get_mut(system_info_ptr.alloc_id)? - .write_repeat(tcx, system_info_ptr, 0, system_info.layout.size)?; + .write_bytes(system_info.ptr, itertools::repeat_n(0, system_info.layout.size.bytes() as usize))?; // Set number of processors. let dword_size = Size::from_bytes(4); - let offset = 2 * dword_size + 3 * tcx.pointer_size(); - this.memory - .get_mut(system_info_ptr.alloc_id)? - .write_scalar( - tcx, - system_info_ptr.offset(offset, tcx)?, - Scalar::from_int(NUM_CPUS, dword_size).into(), - dword_size, - )?; + let num_cpus = this.mplace_field(system_info, 5)?; + this.write_scalar( + Scalar::from_int(NUM_CPUS, dword_size), + num_cpus.into(), + )?; } "TlsAlloc" => { diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 46658760cc12..d39e70d8990f 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -356,11 +356,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => { // Do it in memory let mplace = this.force_allocation(dest)?; - mplace.meta.unwrap_none(); - // not a zst, must be valid pointer - let ptr = mplace.ptr.to_ptr()?; - // we know the return place is in-bounds - this.memory.get_mut(ptr.alloc_id)?.write_repeat(tcx, ptr, 0, dest.layout.size)?; + mplace.meta.unwrap_none(); // must be sized + this.memory.write_bytes(mplace.ptr, itertools::repeat_n(0, dest.layout.size.bytes() as usize))?; } } } @@ -565,16 +562,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.read_scalar(args[0])?.not_undef()?; let count = this.read_scalar(args[2])?.to_usize(this)?; let byte_count = ty_layout.size * count; - match this.memory.check_ptr_access(ptr, byte_count, ty_layout.align.abi)? { - Some(ptr) => { - this.memory - .get_mut(ptr.alloc_id)? - .write_repeat(tcx, ptr, val_byte, byte_count)?; - } - None => { - // Size is 0, nothing to do. - } - } + this.memory.write_bytes(ptr, itertools::repeat_n(val_byte, byte_count.bytes() as usize))?; } name => throw_unsup_format!("unimplemented intrinsic: {}", name), diff --git a/tests/run-pass/union-overwrite.rs b/tests/run-pass/union-overwrite.rs index 5c618763c0d2..d3c81834bc4b 100644 --- a/tests/run-pass/union-overwrite.rs +++ b/tests/run-pass/union-overwrite.rs @@ -1,19 +1,20 @@ #![feature(untagged_unions)] -#![allow(unions_with_drop_fields)] #[repr(C)] +#[derive(Clone, Copy)] struct Pair(T, U); #[repr(C)] +#[derive(Clone, Copy)] struct Triple(T, T, T); #[repr(C)] -union U { +union U { a: Pair, b: B, } #[repr(C)] -union W { +union W { a: A, b: B, } From db949af8ed24e46f0d0bcc1fbe0517b2996b5f9e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 22 Oct 2019 10:43:16 +0200 Subject: [PATCH 1241/5092] fix field index --- src/shims/foreign_items.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index f951cf2df77c..66fb53581e68 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -842,7 +842,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .write_bytes(system_info.ptr, itertools::repeat_n(0, system_info.layout.size.bytes() as usize))?; // Set number of processors. let dword_size = Size::from_bytes(4); - let num_cpus = this.mplace_field(system_info, 5)?; + let num_cpus = this.mplace_field(system_info, 6)?; this.write_scalar( Scalar::from_int(NUM_CPUS, dword_size), num_cpus.into(), From 0ad37dd876c422829248e00e5401a9df17d7c486 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 22 Oct 2019 13:11:16 +0200 Subject: [PATCH 1242/5092] AppVeyor: abort early if a job fails --- .appveyor.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.appveyor.yml b/.appveyor.yml index 60963438abff..2ba95c228baf 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -12,6 +12,9 @@ branches: - auto - try +matrix: + fast_finish: true # set this flag to immediately finish build once one of the jobs fails. + cache: - '%USERPROFILE%\.cargo' - '%USERPROFILE%\.rustup' From fb4cb5bf4af633ca057a84b995bab3b08333df41 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 22 Oct 2019 16:57:07 -0500 Subject: [PATCH 1243/5092] Make size error distinguishable from other errors --- src/helpers.rs | 17 +++++++++++++---- src/shims/env.rs | 2 +- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index b31e0a2c2eb9..79efd95eb6d7 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -412,16 +412,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what - /// the Unix APIs usually handle. - fn write_os_str_to_c_string(&mut self, os_str: &OsStr, scalar: Scalar, size: u64) -> InterpResult<'tcx> { + /// the Unix APIs usually handle. This function returns `Ok(false)` without trying to write if + /// `size` is not large enough to fit the contents of `os_string` plus a null terminator. It + /// returns `Ok(true)` if the writing process was successful. Otherwise it returns an + /// `InterpError`. + fn write_os_str_to_c_string( + &mut self, + os_str: &OsStr, + scalar: Scalar, + size: u64 + ) -> InterpResult<'tcx, bool> { let bytes = os_str_to_bytes(os_str)?; // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null // terminator to memory using the `ptr` pointer would cause an overflow. if size <= bytes.len() as u64 { - throw_unsup_format!("OsString of length {} is too large for destination buffer of size {}", bytes.len(), size) + return Ok(false); } // FIXME: We should use `Iterator::chain` instead when rust-lang/rust#65704 lands. - self.eval_context_mut().memory.write_bytes(scalar, [bytes, &[0]].concat()) + self.eval_context_mut().memory.write_bytes(scalar, [bytes, &[0]].concat())?; + Ok(true) } } diff --git a/src/shims/env.rs b/src/shims/env.rs index f88a5bbac72e..2dc47d74ffb8 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -128,7 +128,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If we cannot get the current directory, we return null match env::current_dir() { Ok(cwd) => { - if this.write_os_str_to_c_string(&OsString::from(cwd), buf, size).is_ok() { + if this.write_os_str_to_c_string(&OsString::from(cwd), buf, size)? { return Ok(buf); } let erange = this.eval_libc("ERANGE")?; From 47eb8549eec05117a55739c9b818d1ece1df898f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 23 Oct 2019 10:25:22 +0200 Subject: [PATCH 1244/5092] rustup + cargo update --- Cargo.lock | 338 +++++++++++++++++++++++---------------------------- rust-version | 2 +- 2 files changed, 152 insertions(+), 188 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d3b6ee0bb531..18cef9461b26 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,10 +20,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "arrayvec" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -31,33 +31,33 @@ name = "atty" version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "autocfg" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "backtrace" -version = "0.3.35" +version = "0.3.40" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "backtrace-sys" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -70,16 +70,16 @@ dependencies = [ [[package]] name = "bitflags" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "blake2b_simd" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -90,11 +90,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "c2-chacha" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -103,19 +102,19 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cc" -version = "1.0.40" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cfg-if" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -130,10 +129,10 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", @@ -144,7 +143,7 @@ name = "cloudabi" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -158,22 +157,22 @@ dependencies = [ [[package]] name = "compiletest_rs" -version = "0.3.24" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustfix 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -186,7 +185,7 @@ name = "crossbeam-utils" version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -200,7 +199,7 @@ name = "directories" version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -209,10 +208,10 @@ name = "dirs-sys" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -226,30 +225,30 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "failure" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "failure_derive" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -257,10 +256,10 @@ name = "filetime" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -278,12 +277,12 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -293,7 +292,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "humantime" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -319,7 +318,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.62" +version = "0.2.65" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -327,7 +326,7 @@ name = "log" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -341,7 +340,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -351,15 +350,15 @@ dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "compiletest_rs 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "compiletest_rs 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)", "directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -368,7 +367,7 @@ dependencies = [ [[package]] name = "nodrop" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -376,7 +375,7 @@ name = "num-integer" version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -393,25 +392,17 @@ name = "num-traits" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ppv-lite86" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "proc-macro2" -version = "1.0.1" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -422,20 +413,12 @@ name = "quick-error" version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "quote" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "quote" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -444,21 +427,21 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -467,8 +450,8 @@ name = "rand_chacha" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -486,10 +469,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rand_core" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -497,7 +480,7 @@ name = "rand_hc" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -507,10 +490,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -531,7 +514,7 @@ name = "redox_users" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -539,18 +522,18 @@ dependencies = [ [[package]] name = "regex" -version = "1.2.1" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex-syntax" -version = "0.6.11" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -558,7 +541,7 @@ name = "remove_dir_all" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -572,7 +555,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2b_simd 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -599,15 +582,15 @@ name = "rustfix" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ryu" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -616,7 +599,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -626,30 +609,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.99" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.99" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -662,20 +645,10 @@ name = "socket2" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "syn" -version = "0.15.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -683,20 +656,20 @@ name = "syn" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "synstructure" -version = "0.10.2" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -704,12 +677,12 @@ name = "tempfile" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -733,9 +706,9 @@ name = "time" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -743,11 +716,6 @@ name = "unicode-width" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "unicode-xid" version = "0.2.0" @@ -758,19 +726,19 @@ name = "vergen" version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasi" -version = "0.5.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -787,7 +755,7 @@ name = "winapi-util" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -800,7 +768,7 @@ name = "wincolor" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -812,31 +780,31 @@ dependencies = [ "cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rgb 0.8.14 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [metadata] "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" "checksum approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08abcc3b4e9339e33a3d0a5ed15d84a687350c05689d825e0f6655eef9e76a94" "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" -"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" +"checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" -"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" -"checksum backtrace 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "1371048253fa3bac6704bfd6bbfc922ee9bdcee8881330d40f308b81cc5adc55" -"checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b" +"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" +"checksum backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea" +"checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" -"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" -"checksum blake2b_simd 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bf775a81bb2d464e20ff170ac20316c7b08a43d11dbc72f0f82e8e8d3d6d0499" +"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +"checksum blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "5850aeee1552f495dd0250014cf64b82b7c8879a89d83b33bbdace2cc4f63182" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" -"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" +"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" "checksum cargo_metadata 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "700b3731fd7d357223d0000f4dbf1808401b694609035c3c411fbc0cd375c426" -"checksum cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "b548a4ee81fccb95919d4e22cfea83c7693ebfd78f0495493178db20b3139da7" -"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" +"checksum cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)" = "0213d356d3c4ea2c18c40b037c3be23cd639825c18f25ee670ac7813beeef99c" +"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64a4b57c8f4e3a2e9ac07e0f6abc9c24b6fc9e1b54c3478cfb598f3d0023e51c" -"checksum chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "77d81f58b7301084de3b958691458a53c3f7e0b1d702f77e550b6a88e3a88abe" +"checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6cdb90b60f2927f8d76139c72dbde7e10c3a2bc47c8594c9c7a66529f2687c03" -"checksum compiletest_rs 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "676a74b493d50ac33cacd83fd536597e6b52c0b46b9856f7b9c809d82fef4ac0" +"checksum compiletest_rs 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f75b10a18fb53549fdd090846eb01c7f8593914494d1faabc4d3005c436e417a" "checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120" "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" "checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" @@ -844,44 +812,42 @@ dependencies = [ "checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" "checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" "checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" -"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" -"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" +"checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" +"checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" "checksum filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6bd7380b54ced79dda72ecc35cc4fbbd1da6bba54afaa37e96fd1c2a308cd469" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" -"checksum getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "fc344b02d3868feb131e8b5fe2b9b0a1cc42942679af493061fc13b853243872" +"checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" -"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" +"checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" +"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" "checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226" -"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" +"checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" "checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" "checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" -"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" -"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c5c2380ae88876faae57698be9e9775e3544decad214599c3a6266cca6ac802" +"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" +"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" -"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" -"checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" +"checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" "checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" -"checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" +"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" "checksum redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecedbca3bf205f8d8f5c2b44d83cd0690e39ee84b951ed649e9f1841132b66d" -"checksum regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88c3d9193984285d544df4a30c23a4e62ead42edf70a4452ceb76dac1ce05c26" -"checksum regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b143cceb2ca5e56d5671988ef8b15615733e7ee16cd348e064333b251b89343f" +"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" +"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" "checksum rgb 0.8.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2089e4031214d129e201f8c3c8c2fe97cd7322478a0d1cdf78e7029b0042efdb" "checksum rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf" @@ -889,27 +855,25 @@ dependencies = [ "checksum rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rustfix 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7150ac777a2931a53489f5a41eb0937b84e3092a20cd0e73ad436b65b507f607" -"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" +"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "fec2851eb56d010dc9a21b89ca53ee75e6528bab60c11e89d38390904982da9f" -"checksum serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "cb4dc18c61206b08dc98216c98faa0232f4337e1e1b8574551d5bad29ea1b425" -"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" +"checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd" +"checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e" +"checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2" "checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9" "checksum socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e8b74de517221a2cb01a53349cf54182acdc31a074727d3079068448c0676d85" -"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" "checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" -"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" +"checksum synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" -"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6aba5e34f93dc7051dfad05b98a18e9156f27e7b431fe1d2398cb6061c0a1dba" -"checksum wasi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd5442abcac6525a045cc8c795aedb60da7a2e5e89c7bf18a0d5357849bb23c7" -"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" +"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" +"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/rust-version b/rust-version index b2b3a89fe956..71068bb941a0 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6576f4be5af31a5e61dfc0cf50b7130e6c6dfb35 +57bfb8096295150c06559da10adc5629e445a4ac From 6fb5e124d9299cfd52a6726caf9bd2a5bcfaf73f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 23 Oct 2019 10:31:08 +0200 Subject: [PATCH 1245/5092] use compiletest_rs for stable compiler as nightly is broken --- Cargo.lock | 44 ++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 +- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 18cef9461b26..0f04aa04bb45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -172,6 +172,7 @@ dependencies = [ "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tester 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -311,6 +312,15 @@ name = "itoa" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -685,6 +695,15 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "term" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "termcolor" version = "1.0.5" @@ -693,6 +712,16 @@ dependencies = [ "wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tester" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "thread_local" version = "0.3.6" @@ -736,6 +765,11 @@ name = "wasi" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "winapi" version = "0.3.8" @@ -745,6 +779,11 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -822,6 +861,7 @@ dependencies = [ "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" +"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" @@ -866,14 +906,18 @@ dependencies = [ "checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" "checksum synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" +"checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" +"checksum tester 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5e812cb26c597f86a49b26dbb58b878bd2a2b4b93fc069dc39499228fe556ff6" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6aba5e34f93dc7051dfad05b98a18e9156f27e7b431fe1d2398cb6061c0a1dba" "checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" +"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index 91da02eac8a6..4c39341e10c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,5 +60,5 @@ cargo_miri = ["cargo_metadata", "directories", "rustc_version"] rustc_tests = [] [dev-dependencies] -compiletest_rs = { version = "0.3.24", features = ["tmp"] } +compiletest_rs = { version = "0.3.24", features = ["tmp", "stable"] } colored = "1.6" From 505b02fc99c49c1a3f2db4baeb989c9cb62d6605 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 23 Oct 2019 10:32:08 +0200 Subject: [PATCH 1246/5092] cargo update cargo-miri-test --- test-cargo-miri/Cargo.lock | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 70476fbdcb06..55c7c528aa9f 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -2,7 +2,7 @@ # It is not intended for manual editing. [[package]] name = "autocfg" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -12,11 +12,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "c2-chacha" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -39,18 +38,13 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "libc" -version = "0.2.62" +version = "0.2.65" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -58,12 +52,12 @@ name = "num_cpus" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ppv-lite86" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -72,7 +66,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -84,7 +78,7 @@ name = "rand_chacha" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -109,7 +103,7 @@ name = "rand_pcg" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -119,15 +113,14 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] -"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" +"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" -"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" +"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" -"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" +"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" "checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" -"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" +"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" "checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" From de12cbcb32a53a06e1f73e7d9cdfa11e41d79ded Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 23 Oct 2019 08:58:25 -0500 Subject: [PATCH 1247/5092] Fix documentation --- src/helpers.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 79efd95eb6d7..0245540debbe 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -414,8 +414,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. This function returns `Ok(false)` without trying to write if /// `size` is not large enough to fit the contents of `os_string` plus a null terminator. It - /// returns `Ok(true)` if the writing process was successful. Otherwise it returns an - /// `InterpError`. + /// returns `Ok(true)` if the writing process was successful. fn write_os_str_to_c_string( &mut self, os_str: &OsStr, From 354de02c24525ee2a0cf712e5d0f44f6228ad96c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 23 Oct 2019 16:33:54 +0200 Subject: [PATCH 1248/5092] rustup; fix debugging --- rust-version | 2 +- src/eval.rs | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index 71068bb941a0..42aa6d8d76a0 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -57bfb8096295150c06559da10adc5629e445a4ac +f466f52c1bf8f2e4454e31c683a88625ad4b4033 diff --git a/src/eval.rs b/src/eval.rs index 13396e845da1..f4a8d176172d 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -257,9 +257,8 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) { trace!("-------------------"); trace!("Frame {}", i); trace!(" return: {:?}", frame.return_place.map(|p| *p)); - for (_i, _local) in frame.locals.iter().enumerate() { - //trace!(" local {}: {:?}", i, local.value); - //FIXME: enable this again when the LocalValue Debug impl is back + for (i, local) in frame.locals.iter().enumerate() { + trace!(" local {}: {:?}", i, local.value); } } } From cf9340113efcf5c7bea4a143f42c8ea47da4550e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 24 Oct 2019 10:15:30 +0200 Subject: [PATCH 1249/5092] rustup: more flexible write_bytes avoids allocations and removes itertools dependency --- Cargo.lock | 16 ---------------- Cargo.toml | 1 - rust-version | 2 +- src/helpers.rs | 4 ++-- src/shims/foreign_items.rs | 8 ++++---- src/shims/intrinsics.rs | 6 ++++-- 6 files changed, 11 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0f04aa04bb45..1aa15f8b6846 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -215,11 +215,6 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "either" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "env_logger" version = "0.6.2" @@ -299,14 +294,6 @@ dependencies = [ "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "itertools" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "itoa" version = "0.4.4" @@ -365,7 +352,6 @@ dependencies = [ "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -849,7 +835,6 @@ dependencies = [ "checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" "checksum directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c" "checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" -"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" "checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" "checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" "checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" @@ -859,7 +844,6 @@ dependencies = [ "checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" diff --git a/Cargo.toml b/Cargo.toml index 4c39341e10c1..6e317ce94597 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,7 +40,6 @@ log = "0.4" shell-escape = "0.1.4" hex = "0.3.2" rand = "0.7" -itertools = "0.8" # A noop dependency that changes in the Rust repository, it's a bit of a hack. # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` diff --git a/rust-version b/rust-version index 42aa6d8d76a0..543d4e269d41 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -f466f52c1bf8f2e4454e31c683a88625ad4b4033 +55e00631e5bc5b16d40232914e57deeea197a8e4 diff --git a/src/helpers.rs b/src/helpers.rs index 0245540debbe..f7be3de8e481 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,4 +1,4 @@ -use std::mem; +use std::{mem, iter}; use std::ffi::{OsStr, OsString}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; @@ -428,7 +428,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(false); } // FIXME: We should use `Iterator::chain` instead when rust-lang/rust#65704 lands. - self.eval_context_mut().memory.write_bytes(scalar, [bytes, &[0]].concat())?; + self.eval_context_mut().memory.write_bytes(scalar, bytes.iter().copied().chain(iter::once(0u8)))?; Ok(true) } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 66fb53581e68..dea01c63a05b 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -1,4 +1,4 @@ -use std::convert::TryInto; +use std::{iter, convert::TryInto}; use rustc::hir::def_id::DefId; use rustc::mir; @@ -52,7 +52,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if zero_init { // We just allocated this, the access is definitely in-bounds. this.memory - .write_bytes(ptr.into(), itertools::repeat_n(0u8, size as usize)) + .write_bytes(ptr.into(), iter::repeat(0u8).take(size as usize)) .unwrap(); } Scalar::Ptr(ptr) @@ -227,7 +227,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); // We just allocated this, the access is definitely in-bounds. this.memory - .write_bytes(ptr.into(), itertools::repeat_n(0u8, size as usize)) + .write_bytes(ptr.into(), iter::repeat(0u8).take(size as usize)) .unwrap(); this.write_scalar(Scalar::Ptr(ptr), dest)?; } @@ -839,7 +839,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let system_info = this.deref_operand(args[0])?; // Initialize with `0`. this.memory - .write_bytes(system_info.ptr, itertools::repeat_n(0, system_info.layout.size.bytes() as usize))?; + .write_bytes(system_info.ptr, iter::repeat(0u8).take(system_info.layout.size.bytes() as usize))?; // Set number of processors. let dword_size = Size::from_bytes(4); let num_cpus = this.mplace_field(system_info, 6)?; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index d39e70d8990f..5ef7fba7f590 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -1,3 +1,5 @@ +use std::iter; + use rustc_apfloat::Float; use rustc::mir; use rustc::mir::interpret::{InterpResult, PointerArithmetic}; @@ -357,7 +359,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Do it in memory let mplace = this.force_allocation(dest)?; mplace.meta.unwrap_none(); // must be sized - this.memory.write_bytes(mplace.ptr, itertools::repeat_n(0, dest.layout.size.bytes() as usize))?; + this.memory.write_bytes(mplace.ptr, iter::repeat(0u8).take(dest.layout.size.bytes() as usize))?; } } } @@ -562,7 +564,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.read_scalar(args[0])?.not_undef()?; let count = this.read_scalar(args[2])?.to_usize(this)?; let byte_count = ty_layout.size * count; - this.memory.write_bytes(ptr, itertools::repeat_n(val_byte, byte_count.bytes() as usize))?; + this.memory.write_bytes(ptr, iter::repeat(val_byte).take(byte_count.bytes() as usize))?; } name => throw_unsup_format!("unimplemented intrinsic: {}", name), From c87f106cacf70611b37edd31c44fa133034b22ed Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 24 Oct 2019 10:23:44 +0200 Subject: [PATCH 1250/5092] update comments and some tweaks --- src/helpers.rs | 7 +++---- src/operator.rs | 5 +++-- src/shims/fs.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index f7be3de8e481..dd0530cf48b4 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -379,7 +379,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => throw_unsup_format!("The {} error cannot be transformed into a raw os error", e) })? } else { - // FIXME: we have to implement the windows' equivalent of this. + // FIXME: we have to implement the Windows equivalent of this. throw_unsup_format!("Setting the last OS error from an io::Error is unsupported for {}.", target.target_os) }; this.set_last_error(last_error) @@ -390,7 +390,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// `Ok(-1)` and sets the last OS error accordingly. /// /// This function uses `T: From` instead of `i32` directly because some IO related - /// functions return different integer types (like `read`, that returns an `i64`) + /// functions return different integer types (like `read`, that returns an `i64`). fn try_unwrap_io_result>( &mut self, result: std::io::Result, @@ -423,11 +423,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, bool> { let bytes = os_str_to_bytes(os_str)?; // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null - // terminator to memory using the `ptr` pointer would cause an overflow. + // terminator to memory using the `ptr` pointer would cause an out-of-bounds access. if size <= bytes.len() as u64 { return Ok(false); } - // FIXME: We should use `Iterator::chain` instead when rust-lang/rust#65704 lands. self.eval_context_mut().memory.write_bytes(scalar, bytes.iter().copied().chain(iter::once(0u8)))?; Ok(true) } diff --git a/src/operator.rs b/src/operator.rs index 9c02c56fd6a1..a60bc8c0b13d 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,3 +1,5 @@ +use std::convert::TryFrom; + use rustc::ty::{Ty, layout::LayoutOf}; use rustc::mir; @@ -117,8 +119,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { pointee_ty: Ty<'tcx>, offset: i64, ) -> InterpResult<'tcx, Scalar> { - // FIXME: assuming here that type size is less than `i64::max_value()`. - let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; + let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); let offset = offset .checked_mul(pointee_size) .ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 08c9f3ec06e7..c484795d8fec 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -95,7 +95,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("unsupported flags {:#x}", flag & !mirror); } - let path: std::path::PathBuf = this.read_os_string_from_c_string(this.read_scalar(path_op)?.not_undef()?)?.into(); + let path = this.read_os_string_from_c_string(this.read_scalar(path_op)?.not_undef()?)?; let fd = options.open(path).map(|file| { let mut fh = &mut this.machine.file_handler; From 1b96a822de09be7739c93f8409dbd7bbbfa3a340 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 24 Oct 2019 10:31:08 +0200 Subject: [PATCH 1251/5092] compiletest-nightly should work again --- Cargo.lock | 44 -------------------------------------------- Cargo.toml | 2 +- 2 files changed, 1 insertion(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0f04aa04bb45..18cef9461b26 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -172,7 +172,6 @@ dependencies = [ "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tester 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -312,15 +311,6 @@ name = "itoa" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -695,15 +685,6 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "term" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "termcolor" version = "1.0.5" @@ -712,16 +693,6 @@ dependencies = [ "wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "tester" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "thread_local" version = "0.3.6" @@ -765,11 +736,6 @@ name = "wasi" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "winapi" version = "0.3.8" @@ -779,11 +745,6 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -861,7 +822,6 @@ dependencies = [ "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" @@ -906,18 +866,14 @@ dependencies = [ "checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" "checksum synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" -"checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" -"checksum tester 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5e812cb26c597f86a49b26dbb58b878bd2a2b4b93fc069dc39499228fe556ff6" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6aba5e34f93dc7051dfad05b98a18e9156f27e7b431fe1d2398cb6061c0a1dba" "checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index 4c39341e10c1..91da02eac8a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,5 +60,5 @@ cargo_miri = ["cargo_metadata", "directories", "rustc_version"] rustc_tests = [] [dev-dependencies] -compiletest_rs = { version = "0.3.24", features = ["tmp", "stable"] } +compiletest_rs = { version = "0.3.24", features = ["tmp"] } colored = "1.6" From 930c797a83669d0a6ba7797673bdb535e2979bd6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 11 Oct 2019 10:11:01 +0200 Subject: [PATCH 1252/5092] bump rustc and adjust for rustc-dev component (also sync AppVeyor with Travis: use stable cargo) --- .appveyor.yml | 2 +- .travis.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 2ba95c228baf..2474657fd777 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -32,7 +32,7 @@ install: - rustup update # Install "master" toolchain - cargo install rustup-toolchain-install-master & exit 0 - - rustup-toolchain-install-master -f -n master %RUSTC_HASH% -c cargo -c rust-src + - rustup-toolchain-install-master -f -n master %RUSTC_HASH% -c rust-src -c rustc-dev - rustup default master - rustc --version - cargo --version diff --git a/.travis.yml b/.travis.yml index 51f02e76824b..bb38510e3934 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,7 +39,7 @@ before_script: - rustup update # Install "master" toolchain - cargo install rustup-toolchain-install-master || echo "rustup-toolchain-install-master already installed" -- travis_retry rustup-toolchain-install-master -f -n master $RUSTC_HASH -c rust-src +- travis_retry rustup-toolchain-install-master -f -n master $RUSTC_HASH -c rust-src -c rustc-dev - rustup default master - rustc --version - cargo --version From 557836b83e3511e645b3484d9d2286980319fd58 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 11 Oct 2019 10:13:26 +0200 Subject: [PATCH 1253/5092] adjust README for rustc-dev --- CONTRIBUTING.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 83e2338552e9..d6436873938e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -31,8 +31,10 @@ Miri heavily relies on internal rustc interfaces to execute MIR. Still, some things (like adding support for a new intrinsic or a shim for an external function being called) can be done by working just on the Miri side. -To prepare, make sure you are using a nightly Rust compiler. Then you should be -able to just `cargo build` Miri. +To prepare, make sure you are using a nightly Rust compiler. You also need to +have the `rust-src` and `rustc-dev` components installed, which you can add via +`rustup component add rust-src rustc-dev`. Then you should be able to just +`cargo build` Miri. In case this fails, your nightly might be incompatible with Miri master. The `rust-version` file contains the commit hash of rustc that Miri is currently @@ -41,7 +43,7 @@ to wait for the next nightly to get released. You can also use [`rustup-toolchain-install-master`](https://github.com/kennytm/rustup-toolchain-install-master) to install that exact version of rustc as a toolchain: ``` -rustup-toolchain-install-master $(cat rust-version) -c rust-src +rustup-toolchain-install-master $(cat rust-version) -c rust-src -c rustc-dev ``` Another common problem is outdated dependencies: Miri does not come with a From 4872c5cbbe9a4f59c71a9ffde4d5e521c08e8ea0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Oct 2019 17:11:29 +0200 Subject: [PATCH 1254/5092] temporarily ignore cached rustup-toolchain-install-master --- .appveyor.yml | 2 +- .travis.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 2474657fd777..3fe85fe14210 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -31,7 +31,7 @@ install: - rustup component remove rust-docs & exit 0 - rustup update # Install "master" toolchain - - cargo install rustup-toolchain-install-master & exit 0 + - cargo install rustup-toolchain-install-master -f - rustup-toolchain-install-master -f -n master %RUSTC_HASH% -c rust-src -c rustc-dev - rustup default master - rustc --version diff --git a/.travis.yml b/.travis.yml index bb38510e3934..e9df794b5940 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,7 +38,7 @@ before_script: - rustup component remove rust-docs || echo "rust-docs already gone" - rustup update # Install "master" toolchain -- cargo install rustup-toolchain-install-master || echo "rustup-toolchain-install-master already installed" +- cargo install rustup-toolchain-install-master -f - travis_retry rustup-toolchain-install-master -f -n master $RUSTC_HASH -c rust-src -c rustc-dev - rustup default master - rustc --version From 55e1251886425492edac903bcbe7f7474d3a2c55 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 24 Oct 2019 13:12:26 +0200 Subject: [PATCH 1255/5092] rustc-dev landed; adjust rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 543d4e269d41..61a6353bb4d9 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -55e00631e5bc5b16d40232914e57deeea197a8e4 +8e0007f829661e57d008d2e908c95f6e84b04b25 From 39cdc35dd7b5362001e5987df1e85f375f2187c4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 24 Oct 2019 15:44:35 +0200 Subject: [PATCH 1256/5092] add back '-c cargo' --- .appveyor.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 3fe85fe14210..c8ee04275c83 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -32,7 +32,9 @@ install: - rustup update # Install "master" toolchain - cargo install rustup-toolchain-install-master -f - - rustup-toolchain-install-master -f -n master %RUSTC_HASH% -c rust-src -c rustc-dev + # We need to install cargo here as well or else the DLL search path inside `cargo run` + # will be for the wrong toolchain. (On Unix, `./miri` takes care of this, but not here.) + - rustup-toolchain-install-master -f -n master %RUSTC_HASH% -c rust-src -c rustc-dev -c cargo - rustup default master - rustc --version - cargo --version From 260b463bb037809e9558421ad5e73bf89e9a08df Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 24 Oct 2019 08:44:13 -0500 Subject: [PATCH 1257/5092] Clean file handling functions --- src/shims/fs.rs | 116 ++++++++++++++++++------------------------------ 1 file changed, 44 insertions(+), 72 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index c484795d8fec..760fc1daff1f 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use std::fs::{File, OpenOptions, remove_file}; +use std::fs::{remove_file, File, OpenOptions}; use std::io::{Read, Write}; use rustc::ty::layout::Size; @@ -125,8 +125,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `FD_CLOEXEC` value without checking if the flag is set for the file because `std` // always sets this flag when opening a file. However we still need to check that the // file itself is open. - let fd_cloexec = this.eval_libc_i32("FD_CLOEXEC")?; - this.get_handle_and(fd, |_| Ok(fd_cloexec)) + if this.machine.file_handler.handles.contains_key(&fd) { + Ok(this.eval_libc_i32("FD_CLOEXEC")?) + } else { + this.handle_not_found() + } } else { throw_unsup_format!("The {:#x} command is not supported for `fcntl`)", cmd); } @@ -139,9 +142,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; - this.remove_handle_and(fd, |handle, this| { + if let Some(handle) = this.machine.file_handler.handles.remove(&fd) { this.try_unwrap_io_result(handle.file.sync_all().map(|_| 0i32)) - }) + } else { + this.handle_not_found() + } } fn read( @@ -160,20 +165,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(0); } let fd = this.read_scalar(fd_op)?.to_i32()?; - let buf_scalar = this.read_scalar(buf_op)?.not_undef()?; + let buf = this.read_scalar(buf_op)?.not_undef()?; - // Remove the file handle to avoid borrowing issues. - this.remove_handle_and(fd, |mut handle, this| { - // Don't use `?` to avoid returning before reinserting the handle. - let bytes = this.force_ptr(buf_scalar).and_then(|buf| { - this.memory - .get_mut(buf.alloc_id)? - .get_bytes_mut(&*this.tcx, buf, Size::from_bytes(count)) - .map(|buffer| handle.file.read(buffer)) - }); - this.machine.file_handler.handles.insert(fd, handle).unwrap_none(); - this.try_unwrap_io_result(bytes?.map(|bytes| bytes as i64)) - }) + if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { + // We want to read at most `count` bytes + let mut bytes = vec![0; count as usize]; + let result = handle.file.read(&mut bytes).map(|c| c as i64); + let written_count = this.try_unwrap_io_result(result)?; + // `try_unwrap_io_result` returns Ok(`-1`) if `result` is an error. There is no other + // way of returning `-1` because the `Ok` variant of `result` contains the number of + // written bytes, which is a possitive value. + if written_count != -1 { + // If reading to `bytes` did not fail, we write those bytes to the buffer. + this.memory.write_bytes(buf, bytes)?; + } + Ok(written_count) + } else { + this.handle_not_found() + } } fn write( @@ -192,20 +201,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(0); } let fd = this.read_scalar(fd_op)?.to_i32()?; - let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; + let buf = this.read_scalar(buf_op)?.not_undef()?; - this.remove_handle_and(fd, |mut handle, this| { - let bytes = this.memory.get(buf.alloc_id).and_then(|alloc| { - alloc - .get_bytes(&*this.tcx, buf, Size::from_bytes(count)) - .map(|bytes| handle.file.write(bytes).map(|bytes| bytes as i64)) - }); - this.machine.file_handler.handles.insert(fd, handle).unwrap_none(); - this.try_unwrap_io_result(bytes?) - }) + if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { + let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; + let result = handle.file.write(&bytes).map(|c| c as i64); + this.try_unwrap_io_result(result) + } else { + this.handle_not_found() + } } - fn unlink( &mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn unlink(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.check_no_isolation("unlink")?; @@ -217,49 +224,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.try_unwrap_io_result(result) } - /// Helper function that gets a `FileHandle` immutable reference and allows to manipulate it - /// using the `f` closure. - /// - /// If the `fd` file descriptor does not correspond to a file, this functions returns `Ok(-1)` - /// and sets `Evaluator::last_error` to `libc::EBADF` (invalid file descriptor). - /// - /// This function uses `T: From` instead of `i32` directly because some IO related - /// functions return different integer types (like `read`, that returns an `i64`). - fn get_handle_and>(&mut self, fd: i32, f: F) -> InterpResult<'tcx, T> - where - F: Fn(&FileHandle) -> InterpResult<'tcx, T>, - { + /// Function used when a handle is not found inside `FileHandler`. It returns `Ok(-1)`and sets + /// the last OS error to `libc::EBADF` (invalid file descriptor). This function uses + /// `T: From` instead of `i32` directly because some fs functions return different integer + /// types (like `read`, that returns an `i64`). + fn handle_not_found>(&mut self) -> InterpResult<'tcx, T> { let this = self.eval_context_mut(); - if let Some(handle) = this.machine.file_handler.handles.get(&fd) { - f(handle) - } else { - let ebadf = this.eval_libc("EBADF")?; - this.set_last_error(ebadf)?; - Ok((-1).into()) - } - } - - /// Helper function that removes a `FileHandle` and allows to manipulate it using the `f` - /// closure. This function is quite useful when you need to modify a `FileHandle` but you need - /// to modify `MiriEvalContext` at the same time, so you can modify the handle and reinsert it - /// using `f`. - /// - /// If the `fd` file descriptor does not correspond to a file, this functions returns `Ok(-1)` - /// and sets `Evaluator::last_error` to `libc::EBADF` (invalid file descriptor). - /// - /// This function uses `T: From` instead of `i32` directly because some IO related - /// functions return different integer types (like `read`, that returns an `i64`). - fn remove_handle_and>(&mut self, fd: i32, mut f: F) -> InterpResult<'tcx, T> - where - F: FnMut(FileHandle, &mut MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx, T>, - { - let this = self.eval_context_mut(); - if let Some(handle) = this.machine.file_handler.handles.remove(&fd) { - f(handle, this) - } else { - let ebadf = this.eval_libc("EBADF")?; - this.set_last_error(ebadf)?; - Ok((-1).into()) - } + let ebadf = this.eval_libc("EBADF")?; + this.set_last_error(ebadf)?; + Ok((-1).into()) } } From 459aea8f520ef74f81863f17c4fc68bd7ef607fb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 25 Oct 2019 20:26:01 +0200 Subject: [PATCH 1258/5092] test align_to example --- tests/run-pass/align_offset.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/run-pass/align_offset.rs b/tests/run-pass/align_offset.rs index 736889174839..1202fd00be15 100644 --- a/tests/run-pass/align_offset.rs +++ b/tests/run-pass/align_offset.rs @@ -71,8 +71,31 @@ fn test_from_utf8() { println!("{:?}", std::str::from_utf8(content).unwrap()); } +fn test_u64_array() { + #[derive(Default)] + #[repr(align(8))] + struct AlignToU64(T); + + const BYTE_LEN: usize = std::mem::size_of::<[u64; 4]>(); + type Data = AlignToU64<[u8; BYTE_LEN]>; + + fn example(data: &Data) { + let (head, u64_arrays, tail) = unsafe { data.0.align_to::<[u64; 4]>() }; + + assert!(head.is_empty(), "buffer was not aligned for 64-bit numbers"); + assert_eq!(u64_arrays.len(), 1, "buffer was not long enough"); + assert!(tail.is_empty(), "buffer was too long"); + + let u64_array = &u64_arrays[0]; + let _val = u64_array[0]; // make sure we can actually load this + } + + example(&Data::default()); +} + fn main() { test_align_offset(); test_align_to(); test_from_utf8(); + test_u64_array(); } From d8a3a1f09c7d32ad4122932bf95ab5b4249eecda Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 26 Oct 2019 09:33:24 +0200 Subject: [PATCH 1259/5092] rustup for projection interning --- rust-version | 2 +- src/helpers.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 61a6353bb4d9..f7618eadd9f0 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8e0007f829661e57d008d2e908c95f6e84b04b25 +084edc426f2e7e4bbedb5c6afa7fc422a52ee379 diff --git a/src/helpers.rs b/src/helpers.rs index dd0530cf48b4..ae117d5fb352 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -5,6 +5,7 @@ use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc::ty::{ self, + List, layout::{self, LayoutOf, Size, TyLayout}, }; @@ -75,7 +76,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Get the `Place` for a local fn local_place(&mut self, local: mir::Local) -> InterpResult<'tcx, PlaceTy<'tcx, Tag>> { let this = self.eval_context_mut(); - let place = mir::Place { base: mir::PlaceBase::Local(local), projection: Box::new([]) }; + let place = mir::Place { base: mir::PlaceBase::Local(local), projection: List::empty() }; this.eval_place(&place) } From d7967f6b058b3dbf8608a76b0fbe165585a2b77c Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 26 Oct 2019 08:54:02 -0500 Subject: [PATCH 1260/5092] Drop files explicitly when closing them --- src/shims/fs.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 760fc1daff1f..c57ec1a1f916 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -143,7 +143,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(handle) = this.machine.file_handler.handles.remove(&fd) { - this.try_unwrap_io_result(handle.file.sync_all().map(|_| 0i32)) + // `File::sync_all` does the checks that are done when closing a file. We do this to + // to handle possible errors correctly. + let result = this.try_unwrap_io_result(handle.file.sync_all().map(|_| 0i32)); + // Now we actually drop the handle. + drop(handle); + // And return the result. + result } else { this.handle_not_found() } From 122549fd0959634d0255ba40be6c994e9e60d791 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 26 Oct 2019 09:03:45 -0500 Subject: [PATCH 1261/5092] Simplify `read` logic --- src/shims/fs.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index c57ec1a1f916..e8c42eb9a301 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -177,15 +177,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We want to read at most `count` bytes let mut bytes = vec![0; count as usize]; let result = handle.file.read(&mut bytes).map(|c| c as i64); - let written_count = this.try_unwrap_io_result(result)?; - // `try_unwrap_io_result` returns Ok(`-1`) if `result` is an error. There is no other - // way of returning `-1` because the `Ok` variant of `result` contains the number of - // written bytes, which is a possitive value. - if written_count != -1 { - // If reading to `bytes` did not fail, we write those bytes to the buffer. + // If reading to `bytes` did not fail, we write those bytes to the buffer. + if result.is_ok() { this.memory.write_bytes(buf, bytes)?; } - Ok(written_count) + this.try_unwrap_io_result(result) } else { this.handle_not_found() } From b40351c53a2047114705b2efa3161687dc111c0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Sun, 27 Oct 2019 23:01:01 +0100 Subject: [PATCH 1262/5092] Bump dependencies --- Cargo.lock | 18 +++++++++--------- Cargo.toml | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e1444252a817..fb7ab619281f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -98,7 +98,7 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.8.2" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -216,7 +216,7 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.6.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -282,7 +282,7 @@ dependencies = [ [[package]] name = "hex" -version = "0.3.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -335,13 +335,13 @@ name = "miri" version = "0.1.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cargo_metadata 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo_metadata 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "compiletest_rs 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)", "directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -783,7 +783,7 @@ dependencies = [ "checksum blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "5850aeee1552f495dd0250014cf64b82b7c8879a89d83b33bbdace2cc4f63182" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" -"checksum cargo_metadata 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "700b3731fd7d357223d0000f4dbf1808401b694609035c3c411fbc0cd375c426" +"checksum cargo_metadata 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8d2d1617e838936c0d2323a65cc151e03ae19a7678dd24f72bccf27119b90a5d" "checksum cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)" = "0213d356d3c4ea2c18c40b037c3be23cd639825c18f25ee670ac7813beeef99c" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64a4b57c8f4e3a2e9ac07e0f6abc9c24b6fc9e1b54c3478cfb598f3d0023e51c" @@ -796,14 +796,14 @@ dependencies = [ "checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" "checksum directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c" "checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" -"checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" +"checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" "checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" "checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" "checksum filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6bd7380b54ced79dda72ecc35cc4fbbd1da6bba54afaa37e96fd1c2a308cd469" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" "checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" -"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" +"checksum hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "023b39be39e3a2da62a94feb433e91e8bcd37676fbc8bea371daf52b7a769a3e" "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" diff --git a/Cargo.toml b/Cargo.toml index bd345ea2b7f5..ba31dd848ab4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,15 +30,15 @@ doctest = false # and no doc tests required-features = ["rustc_tests"] [dependencies] -cargo_metadata = { version = "0.8", optional = true } +cargo_metadata = { version = "0.9.0", optional = true } directories = { version = "2.0", optional = true } rustc_version = { version = "0.2.3", optional = true } getrandom = { version = "0.1.8", features = ["std"] } byteorder = "1.3" -env_logger = "0.6" +env_logger = "0.7.1" log = "0.4" shell-escape = "0.1.4" -hex = "0.3.2" +hex = "0.4.0" rand = "0.7" # A noop dependency that changes in the Rust repository, it's a bit of a hack. From 06ef77bfef45b3eb01ab4c3ceb0fa30186de4ea0 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 28 Oct 2019 16:44:18 -0500 Subject: [PATCH 1263/5092] Check for usize to i64 overflows --- src/shims/fs.rs | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index e8c42eb9a301..2710cbacb021 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -176,12 +176,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { // We want to read at most `count` bytes let mut bytes = vec![0; count as usize]; - let result = handle.file.read(&mut bytes).map(|c| c as i64); - // If reading to `bytes` did not fail, we write those bytes to the buffer. - if result.is_ok() { - this.memory.write_bytes(buf, bytes)?; + let result = handle.file.read(&mut bytes); + + if let Ok(c) = result { + // Check that we read less than `i64::MAX` bytes. + if c > (i64::max_value() as usize) { + throw_unsup_format!("Number of read bytes {} is larger than the maximum value", c); + } + // If reading to `bytes` did not fail, we write those bytes to the buffer. + this.memory.write_bytes(buf, bytes)? } - this.try_unwrap_io_result(result) + + this.try_unwrap_io_result(result.map(|c| c as i64)) } else { this.handle_not_found() } @@ -207,8 +213,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; - let result = handle.file.write(&bytes).map(|c| c as i64); - this.try_unwrap_io_result(result) + let result = handle.file.write(&bytes); + + if let Ok(c) = result { + // Check that we wrote less than `i64::MAX` bytes. + if c > (i64::max_value() as usize) { + throw_unsup_format!("Number of written bytes {} is larger than the maximum value", c); + } + } + + this.try_unwrap_io_result(result.map(|c| c as i64)) } else { this.handle_not_found() } From 15ae234a42bf45efeb8fae3d1c7a080a10c465cd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 30 Oct 2019 10:16:58 +0100 Subject: [PATCH 1264/5092] rustup for span in intrinsic emulation --- rust-version | 2 +- src/machine.rs | 6 +++--- src/shims/intrinsics.rs | 4 +++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index f7618eadd9f0..8fb4c0987318 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -084edc426f2e7e4bbedb5c6afa7fc422a52ee379 +aa69777ea2902208b24b3fd77767d577ceaf6386 diff --git a/src/machine.rs b/src/machine.rs index 7904e1cc123b..c07fca68199c 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -14,8 +14,7 @@ use rustc::ty::{ layout::{LayoutOf, Size}, Ty, TyCtxt, }; -use syntax::attr; -use syntax::symbol::sym; +use syntax::{attr, source_map::Span, symbol::sym}; use crate::*; @@ -192,11 +191,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn call_intrinsic( ecx: &mut rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>, + span: Span, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { - ecx.call_intrinsic(instance, args, dest) + ecx.call_intrinsic(span, instance, args, dest) } #[inline(always)] diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 5ef7fba7f590..9e47c095d6d3 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -5,6 +5,7 @@ use rustc::mir; use rustc::mir::interpret::{InterpResult, PointerArithmetic}; use rustc::ty::layout::{self, LayoutOf, Size, Align}; use rustc::ty; +use syntax::source_map::Span; use crate::{ PlaceTy, OpTy, Immediate, Scalar, Tag, @@ -15,12 +16,13 @@ impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tc pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn call_intrinsic( &mut self, + span: Span, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - if this.emulate_intrinsic(instance, args, dest)? { + if this.emulate_intrinsic(span, instance, args, dest)? { return Ok(()); } let tcx = &{this.tcx.tcx}; From 90634121b39ca2e15abc40ee2622b3d7e42d823c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 30 Oct 2019 15:05:44 +0100 Subject: [PATCH 1265/5092] fix typo --- src/stacked_borrows.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 2188b9d5394a..6e63bb073c8c 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -241,7 +241,7 @@ impl<'tcx> Stack { /// Find the first write-incompatible item above the given one -- /// i.e, find the height to which the stack will be truncated when writing to `granting`. - fn find_first_write_incompaible(&self, granting: usize) -> usize { + fn find_first_write_incompatible(&self, granting: usize) -> usize { let perm = self.borrows[granting].perm; match perm { Permission::SharedReadOnly => @@ -309,7 +309,7 @@ impl<'tcx> Stack { if access == AccessKind::Write { // Remove everything above the write-compatible items, like a proper stack. This makes sure read-only and unique // pointers become invalid on write accesses (ensures F2a, and ensures U2 for write accesses). - let first_incompatible_idx = self.find_first_write_incompaible(granting_idx); + let first_incompatible_idx = self.find_first_write_incompatible(granting_idx); for item in self.borrows.drain(first_incompatible_idx..).rev() { trace!("access: popping item {:?}", item); Stack::check_protector(&item, Some(tag), global)?; @@ -391,7 +391,7 @@ impl<'tcx> Stack { // access. Instead of popping the stack, we insert the item at the place the stack would // be popped to (i.e., we insert it above all the write-compatible items). // This ensures F2b by adding the new item below any potentially existing `SharedReadOnly`. - self.find_first_write_incompaible(granting_idx) + self.find_first_write_incompatible(granting_idx) } else { // A "safe" reborrow for a pointer that actually expects some aliasing guarantees. // Here, creating a reference actually counts as an access. From 1e0b398cb6fbfe6b2c0c029fac08f64a7e96d322 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Nov 2019 11:48:28 +0100 Subject: [PATCH 1266/5092] Windows cmdline: avoid accessing allocations directly --- src/eval.rs | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index f4a8d176172d..2f998408b8cc 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -4,7 +4,7 @@ use rand::rngs::StdRng; use rand::SeedableRng; use rustc::hir::def_id::DefId; -use rustc::ty::layout::{Align, LayoutOf, Size}; +use rustc::ty::layout::{LayoutOf, Size}; use rustc::ty::{self, TyCtxt}; use syntax::source_map::DUMMY_SP; @@ -48,7 +48,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( EnvVars::init(&mut ecx, config.excluded_env_vars); // Setup first stack-frame - let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); + let main_instance = ty::Instance::mono(tcx, main_id); let main_mir = ecx.load_mir(main_instance.def, None)?; if !main_mir.return_ty().is_unit() || main_mir.arg_count != 0 { @@ -59,11 +59,10 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let main_ret_ty = tcx.fn_sig(main_id).output(); let main_ret_ty = main_ret_ty.no_bound_vars().unwrap(); let start_instance = ty::Instance::resolve( - ecx.tcx.tcx, + tcx, ty::ParamEnv::reveal_all(), start_id, - ecx.tcx - .mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))), + tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))), ) .unwrap(); let start_mir = ecx.load_mir(start_instance.def, None)?; @@ -134,8 +133,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } // Make an array with all these pointers, in the Miri memory. let argvs_layout = ecx.layout_of( - ecx.tcx - .mk_array(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8), argvs.len() as u64), + tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), argvs.len() as u64), )?; let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into()); for (idx, arg) in argvs.into_iter().enumerate() { @@ -156,31 +154,21 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Store command line as UTF-16 for Windows `GetCommandLineW`. { let cmd_utf16: Vec = cmd.encode_utf16().collect(); - let cmd_ptr = ecx.memory.allocate( - Size::from_bytes(cmd_utf16.len() as u64 * 2), - Align::from_bytes(2).unwrap(), - MiriMemoryKind::Env.into(), - ); - ecx.machine.cmd_line = Some(cmd_ptr); + let cmd_type = tcx.mk_array(tcx.types.u16, cmd_utf16.len() as u64); + let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Env.into()); + ecx.machine.cmd_line = Some(cmd_place.ptr.to_ptr()?); // Store the UTF-16 string. We just allocated so we know the bounds are fine. let char_size = Size::from_bytes(2); - let cmd_alloc = ecx.memory.get_mut(cmd_ptr.alloc_id)?; - let mut cur_ptr = cmd_ptr; - for &c in cmd_utf16.iter() { - cmd_alloc.write_scalar( - &*ecx.tcx, - cur_ptr, - Scalar::from_uint(c, char_size).into(), - char_size, - )?; - cur_ptr = cur_ptr.offset(char_size, &*ecx.tcx)?; + for (idx, &c) in cmd_utf16.iter().enumerate() { + let place = ecx.mplace_field(cmd_place, idx as u64)?; + ecx.write_scalar(Scalar::from_uint(c, char_size), place.into())?; } } args.next().expect_none("start lang item has more arguments than expected"); // Set the last_error to 0 - let errno_layout = ecx.layout_of(ecx.tcx.types.u32)?; + let errno_layout = ecx.layout_of(tcx.types.u32)?; let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Static.into()); ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?; ecx.machine.last_error = Some(errno_place); From ddb1fc9205586ccd4f71bb7de583769f9fd3fa77 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Nov 2019 11:50:21 +0100 Subject: [PATCH 1267/5092] store scalars where appropriate --- src/eval.rs | 6 +++--- src/machine.rs | 6 +++--- src/shims/foreign_items.rs | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 2f998408b8cc..b87d735ce525 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -105,7 +105,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( { let argc_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into()); ecx.write_scalar(argc, argc_place.into())?; - ecx.machine.argc = Some(argc_place.ptr.to_ptr()?); + ecx.machine.argc = Some(argc_place.ptr); } // Third argument (`argv`): created from `config.args`. @@ -149,14 +149,14 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( { let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into()); ecx.write_scalar(argv, argv_place.into())?; - ecx.machine.argv = Some(argv_place.ptr.to_ptr()?); + ecx.machine.argv = Some(argv_place.ptr); } // Store command line as UTF-16 for Windows `GetCommandLineW`. { let cmd_utf16: Vec = cmd.encode_utf16().collect(); let cmd_type = tcx.mk_array(tcx.types.u16, cmd_utf16.len() as u64); let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Env.into()); - ecx.machine.cmd_line = Some(cmd_place.ptr.to_ptr()?); + ecx.machine.cmd_line = Some(cmd_place.ptr); // Store the UTF-16 string. We just allocated so we know the bounds are fine. let char_size = Size::from_bytes(2); for (idx, &c) in cmd_utf16.iter().enumerate() { diff --git a/src/machine.rs b/src/machine.rs index c07fca68199c..c76cc2e568f4 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -86,9 +86,9 @@ pub struct Evaluator<'tcx> { /// Program arguments (`Option` because we can only initialize them after creating the ecx). /// These are *pointers* to argc/argv because macOS. /// We also need the full command line as one string because of Windows. - pub(crate) argc: Option>, - pub(crate) argv: Option>, - pub(crate) cmd_line: Option>, + pub(crate) argc: Option>, + pub(crate) argv: Option>, + pub(crate) cmd_line: Option>, /// Last OS error location in memory. It is a 32-bit integer. pub(crate) last_error: Option>, diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index dea01c63a05b..74ce477b8e35 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -765,10 +765,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: register the destructor. } "_NSGetArgc" => { - this.write_scalar(Scalar::Ptr(this.machine.argc.unwrap()), dest)?; + this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?; } "_NSGetArgv" => { - this.write_scalar(Scalar::Ptr(this.machine.argv.unwrap()), dest)?; + this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; } "SecRandomCopyBytes" => { let len = this.read_scalar(args[1])?.to_usize(this)?; @@ -927,7 +927,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "GetCommandLineW" => { - this.write_scalar(Scalar::Ptr(this.machine.cmd_line.unwrap()), dest)?; + this.write_scalar(this.machine.cmd_line.expect("machine must be initialized"), dest)?; } // The actual name of 'RtlGenRandom' "SystemFunction036" => { From 7a39460e2488fe654b0b6f370e652a42c600e53e Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 25 Sep 2019 01:19:41 +0200 Subject: [PATCH 1268/5092] Use the upstream `exact_div` implementation --- src/shims/intrinsics.rs | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 9e47c095d6d3..0c6e5f0af69d 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -313,23 +313,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_f64(res), dest)?; } - "exact_div" => { - // Performs an exact division, resulting in undefined behavior where - // `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1` - let a = this.read_immediate(args[0])?; - let b = this.read_immediate(args[1])?; - // check x % y != 0 - if this.overflowing_binary_op(mir::BinOp::Rem, a, b)?.0.to_bits(dest.layout.size)? != 0 { - // Check if `b` is -1, which is the "min_value / -1" case. - let minus1 = Scalar::from_int(-1, dest.layout.size); - return Err(if b.to_scalar().unwrap() == minus1 { - err_ub_format!("exact_div: result of dividing MIN by -1 cannot be represented") - } else { - err_ub_format!("exact_div: {:?} cannot be divided by {:?} without remainder", *a, *b) - }.into()); - } - this.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; - }, + "exact_div" => this.exact_div( + this.read_immediate(args[0])?, + this.read_immediate(args[1])?, + dest, + )?, "forget" => {} From 47bfd84c982b43a3e7458a38bd1c432c195f352f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Nov 2019 10:02:32 +0100 Subject: [PATCH 1269/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 8fb4c0987318..1a58c80128a5 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -aa69777ea2902208b24b3fd77767d577ceaf6386 +6c1b220fd747bf244f04b380e4d4ae005068f706 From 5a5fa1538229b0304b74ae961af157a7d4aed7d3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Nov 2019 10:03:30 +0100 Subject: [PATCH 1270/5092] style --- src/shims/intrinsics.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 0c6e5f0af69d..cdd31c9298c4 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -313,11 +313,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_f64(res), dest)?; } - "exact_div" => this.exact_div( - this.read_immediate(args[0])?, - this.read_immediate(args[1])?, - dest, - )?, + "exact_div" => + this.exact_div( + this.read_immediate(args[0])?, + this.read_immediate(args[1])?, + dest, + )?, "forget" => {} From fcf0f886d46050ecbb64c068d62725b1b4ef1aca Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Nov 2019 10:15:55 +0100 Subject: [PATCH 1271/5092] adjust tests --- tests/compile-fail/exact_div2.rs | 2 +- tests/compile-fail/exact_div3.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/compile-fail/exact_div2.rs b/tests/compile-fail/exact_div2.rs index 22bcf027dd05..f4400d0d8ae2 100644 --- a/tests/compile-fail/exact_div2.rs +++ b/tests/compile-fail/exact_div2.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // divison with a remainder - unsafe { std::intrinsics::exact_div(2u16, 3); } //~ ERROR Scalar(0x0002) cannot be divided by Scalar(0x0003) without remainder + unsafe { std::intrinsics::exact_div(2u16, 3); } //~ ERROR 2 cannot be divided by 3 without remainder } diff --git a/tests/compile-fail/exact_div3.rs b/tests/compile-fail/exact_div3.rs index 2db62e0092d5..0460e412e45e 100644 --- a/tests/compile-fail/exact_div3.rs +++ b/tests/compile-fail/exact_div3.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // signed divison with a remainder - unsafe { std::intrinsics::exact_div(-19i8, 2); } //~ ERROR Scalar(0xed) cannot be divided by Scalar(0x02) without remainder + unsafe { std::intrinsics::exact_div(-19i8, 2); } //~ ERROR 237 cannot be divided by 2 without remainder } From 955a26fb0803fa1fb46d21abcb89f3a05e5cadda Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Nov 2019 15:39:03 +0100 Subject: [PATCH 1272/5092] calling panic_if_uninhabited is not actually UB --- src/shims/intrinsics.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index cdd31c9298c4..7c8c06cbbfd5 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -381,7 +381,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ty = substs.type_at(0); let layout = this.layout_of(ty)?; if layout.abi.is_uninhabited() { - throw_ub_format!("Trying to instantiate uninhabited type {}", ty) + // FIXME: This should throw a panic in the interpreted program instead. + throw_unsup_format!("Trying to instantiate uninhabited type {}", ty) } } From d0b4407b258acdf87a2b44b687564468b115071a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sun, 3 Nov 2019 10:04:00 -0600 Subject: [PATCH 1273/5092] Fix casts for `count` check --- src/shims/fs.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 2710cbacb021..66e24eb8b092 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -146,7 +146,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `File::sync_all` does the checks that are done when closing a file. We do this to // to handle possible errors correctly. let result = this.try_unwrap_io_result(handle.file.sync_all().map(|_| 0i32)); - // Now we actually drop the handle. + // Now we actually close the file. drop(handle); // And return the result. result @@ -180,7 +180,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Ok(c) = result { // Check that we read less than `i64::MAX` bytes. - if c > (i64::max_value() as usize) { + if (c as u64) > (i64::max_value() as u64) { throw_unsup_format!("Number of read bytes {} is larger than the maximum value", c); } // If reading to `bytes` did not fail, we write those bytes to the buffer. @@ -217,7 +217,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Ok(c) = result { // Check that we wrote less than `i64::MAX` bytes. - if c > (i64::max_value() as usize) { + if (c as u64) > (i64::max_value() as u64) { throw_unsup_format!("Number of written bytes {} is larger than the maximum value", c); } } From 9b4ceec60e039433a4409ca2f89af97e1c3b581d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Nov 2019 11:17:40 +0100 Subject: [PATCH 1274/5092] update comment re: not using higher mir-opt-level --- tests/compiletest.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 00fd039ad7e8..bc1ba2eda568 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -66,9 +66,8 @@ fn compile_fail(path: &str, target: &str, opt: bool) { let mut flags = Vec::new(); if opt { - // Optimizing too aggressivley makes UB detection harder, but test at least - // the default value. - // FIXME: Opt level 3 ICEs during stack trace generation. + // FIXME: Opt level 2 ICEs during stack trace generation. + // See https://github.com/rust-lang/rust/issues/66077. flags.push("-Zmir-opt-level=1".to_owned()); } From 56c5e53553859d153009f76d2da15bf2d0e3d037 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 4 Nov 2019 09:38:21 -0500 Subject: [PATCH 1275/5092] Handle host's `usize` correctly --- src/helpers.rs | 14 ++++++++++++++ src/shims/fs.rs | 38 ++++++++++++++++++++++++-------------- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index dd0530cf48b4..c02ba3f1fab3 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,5 +1,6 @@ use std::{mem, iter}; use std::ffi::{OsStr, OsString}; +use std::convert::TryFrom; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; @@ -459,3 +460,16 @@ fn bytes_to_os_str<'tcx, 'a>(bytes: &'a[u8]) -> InterpResult<'tcx, &'a OsStr> { .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; Ok(&OsStr::new(s)) } + +pub fn try_into_host_usize(i: impl Into) -> Option { + let i: u128 = i.into(); + if i > usize::max_value() as u128 { + None + } else { + Some(i as usize) + } +} + +pub fn try_from_host_usize>(i: usize) -> Option { + T::try_from(i as u128).ok() +} diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 66e24eb8b092..910e3907695c 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -178,16 +178,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut bytes = vec![0; count as usize]; let result = handle.file.read(&mut bytes); - if let Ok(c) = result { - // Check that we read less than `i64::MAX` bytes. - if (c as u64) > (i64::max_value() as u64) { - throw_unsup_format!("Number of read bytes {} is larger than the maximum value", c); + match result { + Ok(c) => { + if let Some(read_bytes) = helpers::try_from_host_usize::(c) { + // If reading to `bytes` did not fail, we write those bytes to the buffer. + this.memory.write_bytes(buf, bytes)?; + Ok(read_bytes) + } else { + throw_unsup_format!("Number of read bytes {} cannot be transformed to i64", c); + } + }, + Err(e) => { + this.set_last_error_from_io_error(e)?; + Ok(-1) } - // If reading to `bytes` did not fail, we write those bytes to the buffer. - this.memory.write_bytes(buf, bytes)? } - - this.try_unwrap_io_result(result.map(|c| c as i64)) } else { this.handle_not_found() } @@ -215,14 +220,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; let result = handle.file.write(&bytes); - if let Ok(c) = result { - // Check that we wrote less than `i64::MAX` bytes. - if (c as u64) > (i64::max_value() as u64) { - throw_unsup_format!("Number of written bytes {} is larger than the maximum value", c); + match result { + Ok(c) => { + if let Some(written_bytes) = helpers::try_from_host_usize::(c) { + Ok(written_bytes) + } else { + throw_unsup_format!("Number of written bytes {} cannot be transformed to i64", c); + } + }, + Err(e) => { + this.set_last_error_from_io_error(e)?; + Ok(-1) } } - - this.try_unwrap_io_result(result.map(|c| c as i64)) } else { this.handle_not_found() } From 99282efc86974f32dd93e6504b49ed9b717caea4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 Nov 2019 11:05:02 +0100 Subject: [PATCH 1276/5092] add an interesting run-pass stacked borrows example --- .../stacked-borrows/stacked-borrows.rs | 29 +++++++++++++++++++ .../stacked-borrows/stacked-borrows.stderr | 7 +++++ 2 files changed, 36 insertions(+) create mode 100644 tests/run-pass/stacked-borrows/stacked-borrows.stderr diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index afa364e85643..fe6a9a54d4f3 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -11,6 +11,7 @@ fn main() { direct_mut_to_const_raw(); two_raw(); shr_and_raw(); + disjoint_mutable_subborrows(); } // Make sure that reading from an `&mut` does, like reborrowing to `&`, @@ -138,3 +139,31 @@ fn shr_and_raw() { /* unsafe { *y2 += 1; // TODO: Once this works, add compile-fail test that tries to read from y1 again. } */ } + +fn disjoint_mutable_subborrows() { + struct Foo { + a: String, + b: Vec, + } + + unsafe fn borrow_field_a<'a>(this:*mut Foo) -> &'a mut String { + &mut (*this).a + } + + unsafe fn borrow_field_b<'a>(this:*mut Foo) -> &'a mut Vec { + &mut (*this).b + } + + let mut foo = Foo { + a: "hello".into(), + b: vec![0,1,2], + }; + + let ptr = &mut foo as *mut Foo; + + let a = unsafe{ borrow_field_a(ptr) }; + let b = unsafe{ borrow_field_b(ptr) }; + b.push(4); + a.push_str(" world"); + dbg!(a,b); +} diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.stderr b/tests/run-pass/stacked-borrows/stacked-borrows.stderr new file mode 100644 index 000000000000..4493d45ae157 --- /dev/null +++ b/tests/run-pass/stacked-borrows/stacked-borrows.stderr @@ -0,0 +1,7 @@ +[$DIR/stacked-borrows.rs:168] a = "hello world" +[$DIR/stacked-borrows.rs:168] b = [ + 0, + 1, + 2, + 4, +] From f4fb330c67f41af06ae275aafeba2a9bb69d1660 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Nov 2019 13:28:18 +0100 Subject: [PATCH 1277/5092] test offset_from --- tests/run-pass/ptr_offset_from.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 tests/run-pass/ptr_offset_from.rs diff --git a/tests/run-pass/ptr_offset_from.rs b/tests/run-pass/ptr_offset_from.rs new file mode 100644 index 000000000000..92eb3f6e46e3 --- /dev/null +++ b/tests/run-pass/ptr_offset_from.rs @@ -0,0 +1,29 @@ +#![feature(ptr_offset_from)] + +fn test_raw() { unsafe { + let buf = [0u32; 4]; + + let x = buf.as_ptr() as *const u8; + let y = x.offset(12); + + assert_eq!(y.offset_from(x), 12); + assert_eq!(x.offset_from(y), -12); + assert_eq!((y as *const u32).offset_from(x as *const u32), 12/4); + assert_eq!((x as *const u32).offset_from(y as *const u32), -12/4); + + let x = (((x as usize) * 2) / 2) as *const u8; + assert_eq!(y.offset_from(x), 12); + assert_eq!(x.offset_from(y), -12); +} } + +// This also internally uses offset_from. +fn test_vec_into_iter() { + let v = Vec::::new(); + let i = v.into_iter(); + i.size_hint(); +} + +fn main() { + test_raw(); + test_vec_into_iter(); +} From 3847334e725aec9f963afa20520631bf6566a244 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 Nov 2019 20:17:45 +0100 Subject: [PATCH 1278/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 1a58c80128a5..5511ef0ad62f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6c1b220fd747bf244f04b380e4d4ae005068f706 +3a1b3b30c6cdd674049b144a3ced7b711de962b2 From f910ea135c0cbfec4dd10adf2a79163e1b8935f3 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 5 Nov 2019 16:47:24 -0500 Subject: [PATCH 1279/5092] Avoid using `as` cast --- src/shims/fs.rs | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 910e3907695c..3fccbaa33f05 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -174,19 +174,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.read_scalar(buf_op)?.not_undef()?; if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { + let count = helpers::try_into_host_usize(count) + .ok_or_else(|| err_unsup_format!("Program tries to read into buffer too big for this host platform"))?; // We want to read at most `count` bytes - let mut bytes = vec![0; count as usize]; + let mut bytes = vec![0; count]; let result = handle.file.read(&mut bytes); match result { Ok(c) => { - if let Some(read_bytes) = helpers::try_from_host_usize::(c) { - // If reading to `bytes` did not fail, we write those bytes to the buffer. - this.memory.write_bytes(buf, bytes)?; - Ok(read_bytes) - } else { - throw_unsup_format!("Number of read bytes {} cannot be transformed to i64", c); - } + let read_bytes = helpers::try_from_host_usize::(c) + .ok_or_else(|| err_unsup_format!("Number of read bytes {} cannot be transformed to i64", c))?; + // If reading to `bytes` did not fail, we write those bytes to the buffer. + this.memory.write_bytes(buf, bytes)?; + Ok(read_bytes) }, Err(e) => { this.set_last_error_from_io_error(e)?; @@ -221,13 +221,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = handle.file.write(&bytes); match result { - Ok(c) => { - if let Some(written_bytes) = helpers::try_from_host_usize::(c) { - Ok(written_bytes) - } else { - throw_unsup_format!("Number of written bytes {} cannot be transformed to i64", c); - } - }, + Ok(c) => helpers::try_from_host_usize::(c) + .ok_or_else(|| err_unsup_format!("Number of written bytes {} cannot be transformed to i64", c).into()), Err(e) => { this.set_last_error_from_io_error(e)?; Ok(-1) From 2661295cdffdf36f6f8593a249ed5733472391d2 Mon Sep 17 00:00:00 2001 From: YOUNGSUK KIM Date: Tue, 5 Nov 2019 21:56:18 -0500 Subject: [PATCH 1280/5092] error code E0080 is no longer printed with MIRI error message --- src/eval.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index b87d735ce525..cfe856ec3a4d 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -9,7 +9,7 @@ use rustc::ty::{self, TyCtxt}; use syntax::source_map::DUMMY_SP; use crate::{ - struct_error, EnvVars, Evaluator, FnVal, HelpersEvalContextExt, InterpCx, InterpError, + EnvVars, Evaluator, FnVal, HelpersEvalContextExt, InterpCx, InterpError, InterpResult, MemoryExtra, MiriMemoryKind, Pointer, Scalar, StackPopCleanup, Tag, TlsEvalContextExt, }; @@ -221,7 +221,10 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) { }; let msg = format!("Miri evaluation error: {}", msg); - let mut err = struct_error(ecx.tcx.tcx.at(span), msg.as_str()); + let mut err = { + let new_tcx = ecx.tcx.tcx.at(span); + new_tcx.sess.struct_span_err(new_tcx.span, msg.as_str()) + }; let frames = ecx.generate_stacktrace(None); err.span_label(span, msg); // We iterate with indices because we need to look at the next frame (the caller). From c4f1d3f4886d1bcb144aa5b929ca76e5d2804435 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Nov 2019 12:11:31 +0100 Subject: [PATCH 1281/5092] test that 0 cannot be offset-inbounds by 0 --- tests/compile-fail/ptr_offset_0_plus_0.rs | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/compile-fail/ptr_offset_0_plus_0.rs diff --git a/tests/compile-fail/ptr_offset_0_plus_0.rs b/tests/compile-fail/ptr_offset_0_plus_0.rs new file mode 100644 index 000000000000..4abcc5c1b809 --- /dev/null +++ b/tests/compile-fail/ptr_offset_0_plus_0.rs @@ -0,0 +1,7 @@ +// error-pattern: outside bounds of allocation + +fn main() { + let x = 0 as *mut i32; + let _x = x.wrapping_offset(8); // ok, this has no inbounds tag + let _x = unsafe { x.offset(0) }; // UB despite offset 0, NULL is never inbounds +} From 9eb4e00f6fe0f720d9bc7116bf89c20acd35f00b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Nov 2019 12:13:51 +0100 Subject: [PATCH 1282/5092] refactor ptr_offset_inbounds: it can be reduced to check_ptr_access, after all! --- src/operator.rs | 50 ++++++++++++++----------------------------------- 1 file changed, 14 insertions(+), 36 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index a60bc8c0b13d..0c83b5bed93b 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,16 +1,11 @@ use std::convert::TryFrom; -use rustc::ty::{Ty, layout::LayoutOf}; +use rustc::ty::{Ty, layout::{Size, Align, LayoutOf}}; use rustc::mir; use crate::*; pub trait EvalContextExt<'tcx> { - fn pointer_inbounds( - &self, - ptr: Pointer - ) -> InterpResult<'tcx>; - fn binary_ptr_op( &self, bin_op: mir::BinOp, @@ -33,13 +28,6 @@ pub trait EvalContextExt<'tcx> { } impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { - /// Test if the pointer is in-bounds of a live allocation. - #[inline] - fn pointer_inbounds(&self, ptr: Pointer) -> InterpResult<'tcx> { - let (size, _align) = self.memory.get_size_and_align(ptr.alloc_id, AllocCheck::Live)?; - ptr.check_inbounds_alloc(size, CheckInAllocMsg::InboundsTest) - } - fn binary_ptr_op( &self, bin_op: mir::BinOp, @@ -110,9 +98,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { } /// Raises an error if the offset moves the pointer outside of its allocation. - /// We consider ZSTs their own huge allocation that doesn't overlap with anything (and nothing - /// moves in there because the size is 0). We also consider the NULL pointer its own separate - /// allocation, and all the remaining integers pointers their own allocation. + /// For integers, we consider each of them their own tiny allocation of size 0, + /// so offset-by-0 is okay for them -- except for NULL, which we rule out entirely. fn pointer_offset_inbounds( &self, ptr: Scalar, @@ -123,25 +110,16 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { let offset = offset .checked_mul(pointee_size) .ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?; - // Now let's see what kind of pointer this is. - let ptr = if offset == 0 { - match ptr { - Scalar::Ptr(ptr) => ptr, - Scalar::Raw { .. } => { - // Offset 0 on an integer. We accept that, pretending there is - // a little zero-sized allocation here. - return Ok(ptr); - } - } - } else { - // Offset > 0. We *require* a pointer. - self.force_ptr(ptr)? - }; - // Both old and new pointer must be in-bounds of a *live* allocation. - // (Of the same allocation, but that part is trivial with our representation.) - self.pointer_inbounds(ptr)?; - let ptr = ptr.signed_offset(offset, self)?; - self.pointer_inbounds(ptr)?; - Ok(Scalar::Ptr(ptr)) + // We do this forst, to rule out overflows. + let offset_ptr = ptr.ptr_signed_offset(offset, self)?; + // What we need to check is that starting at `ptr`, + // we could do an access of size `offset`. Alignment does not matter. + self.memory.check_ptr_access( + ptr, + Size::from_bytes(u64::try_from(offset).unwrap()), + Align::from_bytes(1).unwrap(), + )?; + // That's it! + Ok(offset_ptr) } } From 1f8cb476eabe3b809907890e69fbf3003a8bb8dc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Nov 2019 12:17:25 +0100 Subject: [PATCH 1283/5092] fix test erorr msg --- tests/compile-fail/ptr_offset_0_plus_0.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile-fail/ptr_offset_0_plus_0.rs b/tests/compile-fail/ptr_offset_0_plus_0.rs index 4abcc5c1b809..96a9fb8402f6 100644 --- a/tests/compile-fail/ptr_offset_0_plus_0.rs +++ b/tests/compile-fail/ptr_offset_0_plus_0.rs @@ -1,4 +1,4 @@ -// error-pattern: outside bounds of allocation +// error-pattern: invalid use of NULL pointer fn main() { let x = 0 as *mut i32; From 4b9a7d8cffc3aefff5d660f07c90fc6f183c4357 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Nov 2019 12:29:15 +0100 Subject: [PATCH 1284/5092] fix error message details --- src/operator.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index 0c83b5bed93b..dea5f1539b3e 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,6 +1,6 @@ use std::convert::TryFrom; -use rustc::ty::{Ty, layout::{Size, Align, LayoutOf}}; +use rustc::ty::{Ty, layout::{Size, LayoutOf}}; use rustc::mir; use crate::*; @@ -110,14 +110,15 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { let offset = offset .checked_mul(pointee_size) .ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?; - // We do this forst, to rule out overflows. + // We do this first, to rule out overflows. let offset_ptr = ptr.ptr_signed_offset(offset, self)?; // What we need to check is that starting at `ptr`, // we could do an access of size `offset`. Alignment does not matter. - self.memory.check_ptr_access( + self.memory.check_ptr_access_align( ptr, Size::from_bytes(u64::try_from(offset).unwrap()), - Align::from_bytes(1).unwrap(), + None, + CheckInAllocMsg::InboundsTest, )?; // That's it! Ok(offset_ptr) From b2a2f4dd152787cf506e75ec936c42b0b84a599f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Nov 2019 09:25:02 +0100 Subject: [PATCH 1285/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 5511ef0ad62f..6b17a5dbeb5e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -3a1b3b30c6cdd674049b144a3ced7b711de962b2 +e4931eaaa3d95189b30e90d3af9f0db17c41bbb0 From 8b0c14f9f6ada1f042b3a734308bb60bdf4ac65e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Nov 2019 10:51:06 +0100 Subject: [PATCH 1286/5092] ptr_offset: handle negative offsets --- src/operator.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index dea5f1539b3e..2a90d3e12f4c 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -112,11 +112,18 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { .ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?; // We do this first, to rule out overflows. let offset_ptr = ptr.ptr_signed_offset(offset, self)?; - // What we need to check is that starting at `ptr`, - // we could do an access of size `offset`. Alignment does not matter. + // What we need to check is that starting at `min(ptr, offset_ptr)`, + // we could do an access of size `abs(offset)`. Alignment does not matter. + let (min_ptr, abs_offset) = if offset >= 0 { + (ptr, u64::try_from(offset).unwrap()) + } else { + // Negative offset. + // If the negation overflows, the result will be negative so the try_from will fail. + (offset_ptr, u64::try_from(-offset).unwrap()) + }; self.memory.check_ptr_access_align( - ptr, - Size::from_bytes(u64::try_from(offset).unwrap()), + min_ptr, + Size::from_bytes(abs_offset), None, CheckInAllocMsg::InboundsTest, )?; From e5675ab0fc03d6f2960b0ec1a8b18bdc1d42b283 Mon Sep 17 00:00:00 2001 From: YOUNGSUK KIM Date: Wed, 6 Nov 2019 08:25:00 -0500 Subject: [PATCH 1287/5092] follow-up to review --- src/eval.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index cfe856ec3a4d..b09fb5918c87 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -221,10 +221,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) { }; let msg = format!("Miri evaluation error: {}", msg); - let mut err = { - let new_tcx = ecx.tcx.tcx.at(span); - new_tcx.sess.struct_span_err(new_tcx.span, msg.as_str()) - }; + let mut err = ecx.tcx.sess.struct_span_err(span, msg.as_str()); let frames = ecx.generate_stacktrace(None); err.span_label(span, msg); // We iterate with indices because we need to look at the next frame (the caller). From 8b1630cb3b06d4d2d2a8a38d08afa368dcefa0c4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Nov 2019 08:55:59 +0100 Subject: [PATCH 1288/5092] tweak and slightly extend box-box-trait test --- tests/run-pass/box_box_trait.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/run-pass/box_box_trait.rs b/tests/run-pass/box_box_trait.rs index e7620cd42f70..5ce0e8f5957b 100644 --- a/tests/run-pass/box_box_trait.rs +++ b/tests/run-pass/box_box_trait.rs @@ -1,5 +1,3 @@ -#![feature(box_syntax)] - struct DroppableStruct; static mut DROPPED: bool = false; @@ -13,7 +11,6 @@ impl Drop for DroppableStruct { trait MyTrait { fn dummy(&self) { } } impl MyTrait for Box {} -#[allow(dead_code)] struct Whatever { w: Box } impl Whatever { @@ -24,8 +21,9 @@ impl Whatever { fn main() { { - let f: Box<_> = box DroppableStruct; - let _a = Whatever::new(box f as Box); + let f = Box::new(DroppableStruct); + let a = Whatever::new(Box::new(f) as Box); + a.w.dummy(); } assert!(unsafe { DROPPED }); } From c77b2826953b126f3dfe752ef461f85d5a24d5a3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Nov 2019 08:56:11 +0100 Subject: [PATCH 1289/5092] rename call_drop_ tests to drop_ --- .../{call_drop_on_array_elements.rs => drop_on_array_elements.rs} | 0 ...at_ptr_array_elements.rs => drop_on_fat_ptr_array_elements.rs} | 0 ...rop_on_zst_array_elements.rs => drop_on_zst_array_elements.rs} | 0 ...ll_drop_through_owned_slice.rs => drop_through_owned_slice.rs} | 0 ..._drop_through_trait_object.rs => drop_through_trait_object.rs} | 0 ...through_trait_object_rc.rs => drop_through_trait_object_rc.rs} | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename tests/run-pass/{call_drop_on_array_elements.rs => drop_on_array_elements.rs} (100%) rename tests/run-pass/{call_drop_on_fat_ptr_array_elements.rs => drop_on_fat_ptr_array_elements.rs} (100%) rename tests/run-pass/{call_drop_on_zst_array_elements.rs => drop_on_zst_array_elements.rs} (100%) rename tests/run-pass/{call_drop_through_owned_slice.rs => drop_through_owned_slice.rs} (100%) rename tests/run-pass/{call_drop_through_trait_object.rs => drop_through_trait_object.rs} (100%) rename tests/run-pass/{call_drop_through_trait_object_rc.rs => drop_through_trait_object_rc.rs} (100%) diff --git a/tests/run-pass/call_drop_on_array_elements.rs b/tests/run-pass/drop_on_array_elements.rs similarity index 100% rename from tests/run-pass/call_drop_on_array_elements.rs rename to tests/run-pass/drop_on_array_elements.rs diff --git a/tests/run-pass/call_drop_on_fat_ptr_array_elements.rs b/tests/run-pass/drop_on_fat_ptr_array_elements.rs similarity index 100% rename from tests/run-pass/call_drop_on_fat_ptr_array_elements.rs rename to tests/run-pass/drop_on_fat_ptr_array_elements.rs diff --git a/tests/run-pass/call_drop_on_zst_array_elements.rs b/tests/run-pass/drop_on_zst_array_elements.rs similarity index 100% rename from tests/run-pass/call_drop_on_zst_array_elements.rs rename to tests/run-pass/drop_on_zst_array_elements.rs diff --git a/tests/run-pass/call_drop_through_owned_slice.rs b/tests/run-pass/drop_through_owned_slice.rs similarity index 100% rename from tests/run-pass/call_drop_through_owned_slice.rs rename to tests/run-pass/drop_through_owned_slice.rs diff --git a/tests/run-pass/call_drop_through_trait_object.rs b/tests/run-pass/drop_through_trait_object.rs similarity index 100% rename from tests/run-pass/call_drop_through_trait_object.rs rename to tests/run-pass/drop_through_trait_object.rs diff --git a/tests/run-pass/call_drop_through_trait_object_rc.rs b/tests/run-pass/drop_through_trait_object_rc.rs similarity index 100% rename from tests/run-pass/call_drop_through_trait_object_rc.rs rename to tests/run-pass/drop_through_trait_object_rc.rs From 04c12952ca11b286536ac2826446f5f686b4af73 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Nov 2019 09:05:11 +0100 Subject: [PATCH 1290/5092] centralize and expand dyn-trait (method receiver) tests --- tests/run-pass/box_box_trait.rs | 29 ------- tests/run-pass/dyn-traits.rs | 140 ++++++++++++++++++++++++++++++++ tests/run-pass/traits.rs | 30 ------- 3 files changed, 140 insertions(+), 59 deletions(-) delete mode 100644 tests/run-pass/box_box_trait.rs create mode 100644 tests/run-pass/dyn-traits.rs delete mode 100644 tests/run-pass/traits.rs diff --git a/tests/run-pass/box_box_trait.rs b/tests/run-pass/box_box_trait.rs deleted file mode 100644 index 5ce0e8f5957b..000000000000 --- a/tests/run-pass/box_box_trait.rs +++ /dev/null @@ -1,29 +0,0 @@ -struct DroppableStruct; - -static mut DROPPED: bool = false; - -impl Drop for DroppableStruct { - fn drop(&mut self) { - unsafe { DROPPED = true; } - } -} - -trait MyTrait { fn dummy(&self) { } } -impl MyTrait for Box {} - -struct Whatever { w: Box } - -impl Whatever { - fn new(w: Box) -> Whatever { - Whatever { w: w } - } -} - -fn main() { - { - let f = Box::new(DroppableStruct); - let a = Whatever::new(Box::new(f) as Box); - a.w.dummy(); - } - assert!(unsafe { DROPPED }); -} diff --git a/tests/run-pass/dyn-traits.rs b/tests/run-pass/dyn-traits.rs new file mode 100644 index 000000000000..bcff3e0b76dc --- /dev/null +++ b/tests/run-pass/dyn-traits.rs @@ -0,0 +1,140 @@ +#![feature(unsized_locals)] + +fn ref_dyn() { + struct Struct(i32); + + trait Trait { + fn method(&self); + } + + impl Trait for Struct { + fn method(&self) { + assert_eq!(self.0, 42); + } + } + + struct Foo(T); + + let y: &dyn Trait = &Struct(42); + y.method(); + let x: Foo = Foo(Struct(42)); + let y: &Foo = &x; + y.0.method(); +} + +fn box_dyn() { + let x: Box i32> = Box::new(|x| x * 2); + assert_eq!(x(21), 42); + let mut i = 5; + { + let mut x: Box = Box::new(|| i *= 2); + x(); x(); + } + assert_eq!(i, 20); +} + +fn box_box_trait() { + struct DroppableStruct; + + static mut DROPPED: bool = false; + + impl Drop for DroppableStruct { + fn drop(&mut self) { + unsafe { DROPPED = true; } + } + } + + trait MyTrait { fn dummy(&self) { } } + impl MyTrait for Box {} + + struct Whatever { w: Box } + + impl Whatever { + fn new(w: Box) -> Whatever { + Whatever { w: w } + } + } + + { + let f = Box::new(DroppableStruct); + let a = Whatever::new(Box::new(f) as Box); + a.w.dummy(); + } + assert!(unsafe { DROPPED }); +} + +fn unsized_dyn() { + pub trait Foo { + fn foo(self) -> String; + } + + struct A; + + impl Foo for A { + fn foo(self) -> String { + format!("hello") + } + } + + let x = *(Box::new(A) as Box); + assert_eq!(x.foo(), format!("hello")); + + // I'm not sure whether we want this to work + let x = Box::new(A) as Box; + assert_eq!(x.foo(), format!("hello")); +} + +fn unsized_dyn_autoderef() { + pub trait Foo { + fn foo(self) -> String; + } + + impl Foo for [char] { + fn foo(self) -> String { + self.iter().collect() + } + } + + impl Foo for str { + fn foo(self) -> String { + self.to_owned() + } + } + + impl Foo for dyn FnMut() -> String { + fn foo(mut self) -> String { + self() + } + } + + let x = *(Box::new(['h', 'e', 'l', 'l', 'o']) as Box<[char]>); + assert_eq!(&x.foo() as &str, "hello"); + + let x = Box::new(['h', 'e', 'l', 'l', 'o']) as Box<[char]>; + assert_eq!(&x.foo() as &str, "hello"); + + let x = "hello".to_owned().into_boxed_str(); + assert_eq!(&x.foo() as &str, "hello"); + + let x = *("hello".to_owned().into_boxed_str()); + assert_eq!(&x.foo() as &str, "hello"); + + let x = "hello".to_owned().into_boxed_str(); + assert_eq!(&x.foo() as &str, "hello"); + + let x = *(Box::new(|| "hello".to_owned()) as Box String>); + assert_eq!(&x.foo() as &str, "hello"); + + let x = Box::new(|| "hello".to_owned()) as Box String>; + assert_eq!(&x.foo() as &str, "hello"); +} + +fn main() { + ref_dyn(); + box_dyn(); + box_box_trait(); + + // "exotic" receivers + unsized_dyn(); + unsized_dyn_autoderef(); +} diff --git a/tests/run-pass/traits.rs b/tests/run-pass/traits.rs deleted file mode 100644 index 03d2db400f01..000000000000 --- a/tests/run-pass/traits.rs +++ /dev/null @@ -1,30 +0,0 @@ -struct Struct(i32); - -trait Trait { - fn method(&self); -} - -impl Trait for Struct { - fn method(&self) { - assert_eq!(self.0, 42); - } -} - -struct Foo(T); - -fn main() { - let y: &dyn Trait = &Struct(42); - y.method(); - let x: Foo = Foo(Struct(42)); - let y: &Foo = &x; - y.0.method(); - - let x: Box i32> = Box::new(|x| x * 2); - assert_eq!(x(21), 42); - let mut i = 5; - { - let mut x: Box = Box::new(|| i *= 2); - x(); x(); - } - assert_eq!(i, 20); -} From b7a8ce1be070c095fafc881e6deb2c1ed87943dd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Nov 2019 09:14:23 +0100 Subject: [PATCH 1291/5092] move blosure tests to closures file; test Box a bit more --- tests/run-pass/closures.rs | 16 ++++++++++++++-- tests/run-pass/dyn-traits.rs | 22 +++++++++------------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/tests/run-pass/closures.rs b/tests/run-pass/closures.rs index eb8d8f0d5b98..5e2e0f87bdaf 100644 --- a/tests/run-pass/closures.rs +++ b/tests/run-pass/closures.rs @@ -40,10 +40,21 @@ fn fn_once_closure_with_multiple_args() -> i64 { } } -fn boxed(f: Box i32>) -> i32 { +fn boxed_fn_once(f: Box i32>) -> i32 { f() } +fn box_dyn() { + let x: Box i32> = Box::new(|x| x * 2); + assert_eq!(x(21), 42); + let mut i = 5; + { + let mut x: Box = Box::new(|| i *= 2); + x(); x(); + } + assert_eq!(i, 20); +} + fn fn_item_as_closure_trait_object() { fn foo() {} let f: &dyn Fn() = &foo; @@ -96,8 +107,9 @@ fn main() { assert_eq!(crazy_closure(), (84, 10, 10)); assert_eq!(closure_arg_adjustment_problem(), 3); assert_eq!(fn_once_closure_with_multiple_args(), 6); - assert_eq!(boxed(Box::new({let x = 13; move || x})), 13); + assert_eq!(boxed_fn_once(Box::new({let x = 13; move || x})), 13); + box_dyn(); fn_item_as_closure_trait_object(); fn_item_with_args_as_closure_trait_object(); fn_item_with_multiple_args_as_closure_trait_object(); diff --git a/tests/run-pass/dyn-traits.rs b/tests/run-pass/dyn-traits.rs index bcff3e0b76dc..f732c7bfaf1c 100644 --- a/tests/run-pass/dyn-traits.rs +++ b/tests/run-pass/dyn-traits.rs @@ -1,6 +1,6 @@ #![feature(unsized_locals)] -fn ref_dyn() { +fn ref_box_dyn() { struct Struct(i32); trait Trait { @@ -17,21 +17,18 @@ fn ref_dyn() { let y: &dyn Trait = &Struct(42); y.method(); + let x: Foo = Foo(Struct(42)); let y: &Foo = &x; y.0.method(); + + let y: Box = Box::new(Struct(42)); + y.method(); + + let y = &y; + y.method(); } -fn box_dyn() { - let x: Box i32> = Box::new(|x| x * 2); - assert_eq!(x(21), 42); - let mut i = 5; - { - let mut x: Box = Box::new(|| i *= 2); - x(); x(); - } - assert_eq!(i, 20); -} fn box_box_trait() { struct DroppableStruct; @@ -130,8 +127,7 @@ fn unsized_dyn_autoderef() { } fn main() { - ref_dyn(); - box_dyn(); + ref_box_dyn(); box_box_trait(); // "exotic" receivers From 57dec5c79158a494905bfd5e6e2473783da177c8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Nov 2019 09:17:40 +0100 Subject: [PATCH 1292/5092] also test Box receiver --- tests/run-pass/dyn-traits.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/run-pass/dyn-traits.rs b/tests/run-pass/dyn-traits.rs index f732c7bfaf1c..33d1f4fc1cf0 100644 --- a/tests/run-pass/dyn-traits.rs +++ b/tests/run-pass/dyn-traits.rs @@ -5,12 +5,18 @@ fn ref_box_dyn() { trait Trait { fn method(&self); + + fn box_method(self: Box); } impl Trait for Struct { fn method(&self) { assert_eq!(self.0, 42); } + + fn box_method(self: Box) { + assert_eq!(self.0, 7); + } } struct Foo(T); @@ -27,6 +33,9 @@ fn ref_box_dyn() { let y = &y; y.method(); + + let y: Box = Box::new(Struct(7)); + y.box_method(); } From 428fc531d857937bd32e7d86757f5f033915d7b0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Nov 2019 09:44:00 +0100 Subject: [PATCH 1293/5092] silence a lint that catches the bug statically --- rust-version | 2 +- tests/compile-fail/validity/invalid_wide_raw.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 6b17a5dbeb5e..41001febbff4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e4931eaaa3d95189b30e90d3af9f0db17c41bbb0 +7a76fe76f756895b8cda1e10398f2268656a2e0f diff --git a/tests/compile-fail/validity/invalid_wide_raw.rs b/tests/compile-fail/validity/invalid_wide_raw.rs index ec14f6988b24..8f1e184ed22e 100644 --- a/tests/compile-fail/validity/invalid_wide_raw.rs +++ b/tests/compile-fail/validity/invalid_wide_raw.rs @@ -1,3 +1,5 @@ +#![allow(invalid_value)] + fn main() { trait T { } #[derive(Debug)] From 4bbaa72dc92ca385b2595f6a072b96f36fa4a1ef Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 7 Nov 2019 20:50:16 +0100 Subject: [PATCH 1294/5092] Use TryFrom instead --- src/helpers.rs | 14 -------------- src/shims/fs.rs | 19 +++++++++++-------- 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index c02ba3f1fab3..dd0530cf48b4 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,6 +1,5 @@ use std::{mem, iter}; use std::ffi::{OsStr, OsString}; -use std::convert::TryFrom; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; @@ -460,16 +459,3 @@ fn bytes_to_os_str<'tcx, 'a>(bytes: &'a[u8]) -> InterpResult<'tcx, &'a OsStr> { .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; Ok(&OsStr::new(s)) } - -pub fn try_into_host_usize(i: impl Into) -> Option { - let i: u128 = i.into(); - if i > usize::max_value() as u128 { - None - } else { - Some(i as usize) - } -} - -pub fn try_from_host_usize>(i: usize) -> Option { - T::try_from(i as u128).ok() -} diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 3fccbaa33f05..8b2452d33d47 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use std::fs::{remove_file, File, OpenOptions}; use std::io::{Read, Write}; +use std::convert::TryFrom; use rustc::ty::layout::Size; @@ -174,16 +175,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.read_scalar(buf_op)?.not_undef()?; if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { - let count = helpers::try_into_host_usize(count) - .ok_or_else(|| err_unsup_format!("Program tries to read into buffer too big for this host platform"))?; - // We want to read at most `count` bytes - let mut bytes = vec![0; count]; + let count = isize::try_from(count) + .map_err(|_| err_unsup_format!("Program tries to read into buffer too big for this host platform"))?; + // We want to read at most `count` bytes. We are sure that `count` is not negative + // because it was a target's `usize`. Also we are sure that its smaller than + // `usize::max_value()` because it is a host's `isize`. + let mut bytes = vec![0; count as usize]; let result = handle.file.read(&mut bytes); match result { Ok(c) => { - let read_bytes = helpers::try_from_host_usize::(c) - .ok_or_else(|| err_unsup_format!("Number of read bytes {} cannot be transformed to i64", c))?; + let read_bytes = i64::try_from(c) + .map_err(|_| err_unsup_format!("Number of read bytes {} cannot be transformed to i64", c))?; // If reading to `bytes` did not fail, we write those bytes to the buffer. this.memory.write_bytes(buf, bytes)?; Ok(read_bytes) @@ -221,8 +224,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = handle.file.write(&bytes); match result { - Ok(c) => helpers::try_from_host_usize::(c) - .ok_or_else(|| err_unsup_format!("Number of written bytes {} cannot be transformed to i64", c).into()), + Ok(c) => i64::try_from(c) + .map_err(|_| err_unsup_format!("Number of written bytes {} cannot be transformed to i64", c).into()), Err(e) => { this.set_last_error_from_io_error(e)?; Ok(-1) From a90ac3b0ecc1ca315512568d2e88191e8b468b2b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Nov 2019 09:16:44 +0100 Subject: [PATCH 1295/5092] disable num_cpus on Windows for now --- test-cargo-miri/tests/test.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index cfbe3f6d7fb6..904bbbc6cd46 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -39,5 +39,6 @@ fn entropy_rng() { #[test] fn num_cpus() { + #[cfg(not(windows))] // FIXME: enable on Windows again once https://github.com/seanmonstar/num_cpus/pull/90 gets released. assert_eq!(num_cpus::get(), 1); } From bcbc6664932437184bd33ba8cf29491bec463f34 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Nov 2019 10:08:57 +0100 Subject: [PATCH 1296/5092] let's see if newer rustc helps --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 41001febbff4..1377ee94dfc3 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7a76fe76f756895b8cda1e10398f2268656a2e0f +c34472b77084c9f76f872871aeab121daf81fb99 From 4c25cf0a87ed605c2cc23ac74dccc56b7ea21f6b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Nov 2019 12:43:26 +0100 Subject: [PATCH 1297/5092] fix into_iter usage --- tests/run-pass/iter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/iter.rs b/tests/run-pass/iter.rs index 1bef21d83bda..6192dd0d37e8 100644 --- a/tests/run-pass/iter.rs +++ b/tests/run-pass/iter.rs @@ -30,7 +30,7 @@ fn iter_any() { let h = |(), (), x: &u8| { 10u8 == *x }; h((), (), &1u8); - [1, 2, 3u8].into_iter().any(|elt| 10 == *elt); + [1, 2, 3u8].iter().any(|elt| 10 == *elt); } fn main() { From 1aeecb553a79d7bf425a19f74a8b213be63773cb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Nov 2019 14:12:54 +0100 Subject: [PATCH 1298/5092] Revert "temporarily ignore cached rustup-toolchain-install-master" This reverts commit 4872c5cbbe9a4f59c71a9ffde4d5e521c08e8ea0. --- .appveyor.yml | 2 +- .travis.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index c8ee04275c83..2106ef365503 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -31,7 +31,7 @@ install: - rustup component remove rust-docs & exit 0 - rustup update # Install "master" toolchain - - cargo install rustup-toolchain-install-master -f + - cargo install rustup-toolchain-install-master & exit 0 # We need to install cargo here as well or else the DLL search path inside `cargo run` # will be for the wrong toolchain. (On Unix, `./miri` takes care of this, but not here.) - rustup-toolchain-install-master -f -n master %RUSTC_HASH% -c rust-src -c rustc-dev -c cargo diff --git a/.travis.yml b/.travis.yml index e9df794b5940..bb38510e3934 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,7 +38,7 @@ before_script: - rustup component remove rust-docs || echo "rust-docs already gone" - rustup update # Install "master" toolchain -- cargo install rustup-toolchain-install-master -f +- cargo install rustup-toolchain-install-master || echo "rustup-toolchain-install-master already installed" - travis_retry rustup-toolchain-install-master -f -n master $RUSTC_HASH -c rust-src -c rustc-dev - rustup default master - rustc --version From d518c38219b9316d4eae2c817ec4fe3b69d4cc29 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Nov 2019 14:13:23 +0100 Subject: [PATCH 1299/5092] rust-docs should be gone from all caches now --- .appveyor.yml | 1 - .travis.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 2106ef365503..b9e112aa0860 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -28,7 +28,6 @@ install: - set PATH=%USERPROFILE%\.cargo\bin;%PATH% - rustup default stable - rustup uninstall beta - - rustup component remove rust-docs & exit 0 - rustup update # Install "master" toolchain - cargo install rustup-toolchain-install-master & exit 0 diff --git a/.travis.yml b/.travis.yml index bb38510e3934..a080ab55b94f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,7 +35,6 @@ before_script: - export PATH=$HOME/.cargo/bin:$PATH - rustup default stable - rustup uninstall beta -- rustup component remove rust-docs || echo "rust-docs already gone" - rustup update # Install "master" toolchain - cargo install rustup-toolchain-install-master || echo "rustup-toolchain-install-master already installed" From 9ca277f2e9cface924a5afa8ccfb9c77747956d0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Nov 2019 16:36:57 +0100 Subject: [PATCH 1300/5092] bump minimal xargo version so that it honors the lockfile --- src/bin/cargo-miri.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index b889ce52f386..36545766d101 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -6,6 +6,8 @@ use std::path::{PathBuf, Path}; use std::process::Command; use std::ops::Not; +const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 17); + const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and tests in Miri Usage: @@ -258,7 +260,7 @@ fn setup(ask_user: bool) { } // First, we need xargo. - if xargo_version().map_or(true, |v| v < (0, 3, 16)) { + if xargo_version().map_or(true, |v| v < XARGO_MIN_VERSION) { if std::env::var("XARGO").is_ok() { // The user manually gave us a xargo binary; don't do anything automatically. show_error(format!("Your xargo is too old; please upgrade to the latest version")) From 37b1190defc78a8d2d4139bfcb4816a1a7faf253 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Nov 2019 22:07:52 +0100 Subject: [PATCH 1301/5092] rustup --- rust-version | 2 +- src/intptrcast.rs | 2 +- src/operator.rs | 2 +- src/shims/dlsym.rs | 2 +- src/shims/env.rs | 2 +- src/shims/foreign_items.rs | 58 +++++++++++++++++++------------------- src/shims/fs.rs | 10 ++++--- src/shims/intrinsics.rs | 10 +++---- src/shims/mod.rs | 2 +- src/stacked_borrows.rs | 4 +-- 10 files changed, 48 insertions(+), 46 deletions(-) diff --git a/rust-version b/rust-version index 1377ee94dfc3..ec45e1f97307 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c34472b77084c9f76f872871aeab121daf81fb99 +9e346646e93cc243567e27bb0f4e8716d56ad1f1 diff --git a/src/intptrcast.rs b/src/intptrcast.rs index e08166b8c2b2..a55c58c13add 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -63,7 +63,7 @@ impl<'mir, 'tcx> GlobalState { // This never overflows because `int >= glb` let offset = int - glb; // If the offset exceeds the size of the allocation, this access is illegal - if offset <= memory.get(alloc_id)?.size.bytes() { + if offset <= memory.get_size_and_align(alloc_id, AllocCheck::MaybeDead)?.0.bytes() { // This pointer is untagged because it was created from a cast Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged) } else { diff --git a/src/operator.rs b/src/operator.rs index 2a90d3e12f4c..6b2c12e6b0b0 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -75,7 +75,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { let ptr = self.pointer_offset_inbounds( left.to_scalar()?, pointee_ty, - right.to_scalar()?.to_isize(self)?, + right.to_scalar()?.to_machine_isize(self)?, )?; (ptr, false, left.layout.ty) } diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 307de29f2203..ca53f5d23015 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -40,7 +40,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match dlsym { GetEntropy => { let ptr = this.read_scalar(args[0])?.not_undef()?; - let len = this.read_scalar(args[1])?.to_usize(this)?; + let len = this.read_scalar(args[1])?.to_machine_usize(this)?; this.gen_random(ptr, len as usize)?; this.write_null(dest)?; } diff --git a/src/shims/env.rs b/src/shims/env.rs index 2dc47d74ffb8..44896fd9bbd5 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -124,7 +124,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("getcwd")?; let buf = this.read_scalar(buf_op)?.not_undef()?; - let size = this.read_scalar(size_op)?.to_usize(&*this.tcx)?; + let size = this.read_scalar(size_op)?.to_machine_usize(&*this.tcx)?; // If we cannot get the current directory, we return null match env::current_dir() { Ok(cwd) => { diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 74ce477b8e35..1f43a83576f6 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -144,13 +144,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ret = ret.expect("dest is `Some` but ret is `None`"); match link_name { "malloc" => { - let size = this.read_scalar(args[0])?.to_usize(this)?; + let size = this.read_scalar(args[0])?.to_machine_usize(this)?; let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C); this.write_scalar(res, dest)?; } "calloc" => { - let items = this.read_scalar(args[0])?.to_usize(this)?; - let len = this.read_scalar(args[1])?.to_usize(this)?; + let items = this.read_scalar(args[0])?.to_machine_usize(this)?; + let len = this.read_scalar(args[1])?.to_machine_usize(this)?; let size = items .checked_mul(len) .ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?; @@ -159,8 +159,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "posix_memalign" => { let ret = this.deref_operand(args[0])?; - let align = this.read_scalar(args[1])?.to_usize(this)?; - let size = this.read_scalar(args[2])?.to_usize(this)?; + let align = this.read_scalar(args[1])?.to_machine_usize(this)?; + let size = this.read_scalar(args[2])?.to_machine_usize(this)?; // Align must be power of 2, and also at least ptr-sized (POSIX rules). if !align.is_power_of_two() { throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); @@ -190,14 +190,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "realloc" => { let old_ptr = this.read_scalar(args[0])?.not_undef()?; - let new_size = this.read_scalar(args[1])?.to_usize(this)?; + let new_size = this.read_scalar(args[1])?.to_machine_usize(this)?; let res = this.realloc(old_ptr, new_size, MiriMemoryKind::C)?; this.write_scalar(res, dest)?; } "__rust_alloc" => { - let size = this.read_scalar(args[0])?.to_usize(this)?; - let align = this.read_scalar(args[1])?.to_usize(this)?; + let size = this.read_scalar(args[0])?.to_machine_usize(this)?; + let align = this.read_scalar(args[1])?.to_machine_usize(this)?; if size == 0 { throw_unsup!(HeapAllocZeroBytes); } @@ -212,8 +212,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_alloc_zeroed" => { - let size = this.read_scalar(args[0])?.to_usize(this)?; - let align = this.read_scalar(args[1])?.to_usize(this)?; + let size = this.read_scalar(args[0])?.to_machine_usize(this)?; + let align = this.read_scalar(args[1])?.to_machine_usize(this)?; if size == 0 { throw_unsup!(HeapAllocZeroBytes); } @@ -233,8 +233,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "__rust_dealloc" => { let ptr = this.read_scalar(args[0])?.not_undef()?; - let old_size = this.read_scalar(args[1])?.to_usize(this)?; - let align = this.read_scalar(args[2])?.to_usize(this)?; + let old_size = this.read_scalar(args[1])?.to_machine_usize(this)?; + let align = this.read_scalar(args[2])?.to_machine_usize(this)?; if old_size == 0 { throw_unsup!(HeapAllocZeroBytes); } @@ -253,9 +253,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "__rust_realloc" => { let ptr = this.read_scalar(args[0])?.to_ptr()?; - let old_size = this.read_scalar(args[1])?.to_usize(this)?; - let align = this.read_scalar(args[2])?.to_usize(this)?; - let new_size = this.read_scalar(args[3])?.to_usize(this)?; + let old_size = this.read_scalar(args[1])?.to_machine_usize(this)?; + let align = this.read_scalar(args[2])?.to_machine_usize(this)?; + let new_size = this.read_scalar(args[3])?.to_machine_usize(this)?; if old_size == 0 || new_size == 0 { throw_unsup!(HeapAllocZeroBytes); } @@ -277,11 +277,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let sys_getrandom = this .eval_path_scalar(&["libc", "SYS_getrandom"])? .expect("Failed to get libc::SYS_getrandom") - .to_usize(this)?; + .to_machine_usize(this)?; // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` // is called if a `HashMap` is created the regular way (e.g. HashMap). - match this.read_scalar(args[0])?.to_usize(this)? { + match this.read_scalar(args[0])?.to_machine_usize(this)? { id if id == sys_getrandom => { // The first argument is the syscall id, // so skip over it. @@ -357,7 +357,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "memcmp" => { let left = this.read_scalar(args[0])?.not_undef()?; let right = this.read_scalar(args[1])?.not_undef()?; - let n = Size::from_bytes(this.read_scalar(args[2])?.to_usize(this)?); + let n = Size::from_bytes(this.read_scalar(args[2])?.to_machine_usize(this)?); let result = { let left_bytes = this.memory.read_bytes(left, n)?; @@ -377,7 +377,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "memrchr" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let val = this.read_scalar(args[1])?.to_i32()? as u8; - let num = this.read_scalar(args[2])?.to_usize(this)?; + let num = this.read_scalar(args[2])?.to_machine_usize(this)?; if let Some(idx) = this .memory .read_bytes(ptr, Size::from_bytes(num))? @@ -395,7 +395,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "memchr" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let val = this.read_scalar(args[1])?.to_i32()? as u8; - let num = this.read_scalar(args[2])?.to_usize(this)?; + let num = this.read_scalar(args[2])?.to_machine_usize(this)?; let idx = this .memory .read_bytes(ptr, Size::from_bytes(num))? @@ -462,7 +462,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "write" => { let fd = this.read_scalar(args[0])?.to_i32()?; let buf = this.read_scalar(args[1])?.not_undef()?; - let n = this.read_scalar(args[2])?.to_usize(tcx)?; + let n = this.read_scalar(args[2])?.to_machine_usize(tcx)?; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { // stdout/stderr @@ -771,7 +771,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; } "SecRandomCopyBytes" => { - let len = this.read_scalar(args[1])?.to_usize(this)?; + let len = this.read_scalar(args[1])?.to_machine_usize(this)?; let ptr = this.read_scalar(args[2])?.not_undef()?; this.gen_random(ptr, len as usize)?; this.write_null(dest)?; @@ -786,25 +786,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(1, this.pointer_size()), dest)?; } "HeapAlloc" => { - let _handle = this.read_scalar(args[0])?.to_isize(this)?; + let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?; let flags = this.read_scalar(args[1])?.to_u32()?; - let size = this.read_scalar(args[2])?.to_usize(this)?; + let size = this.read_scalar(args[2])?.to_machine_usize(this)?; let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY let res = this.malloc(size, zero_init, MiriMemoryKind::WinHeap); this.write_scalar(res, dest)?; } "HeapFree" => { - let _handle = this.read_scalar(args[0])?.to_isize(this)?; + let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?; let _flags = this.read_scalar(args[1])?.to_u32()?; let ptr = this.read_scalar(args[2])?.not_undef()?; this.free(ptr, MiriMemoryKind::WinHeap)?; this.write_scalar(Scalar::from_int(1, Size::from_bytes(4)), dest)?; } "HeapReAlloc" => { - let _handle = this.read_scalar(args[0])?.to_isize(this)?; + let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?; let _flags = this.read_scalar(args[1])?.to_u32()?; let ptr = this.read_scalar(args[2])?.not_undef()?; - let size = this.read_scalar(args[3])?.to_usize(this)?; + let size = this.read_scalar(args[3])?.to_machine_usize(this)?; let res = this.realloc(ptr, size, MiriMemoryKind::WinHeap)?; this.write_scalar(res, dest)?; } @@ -883,7 +883,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?; } "WriteFile" => { - let handle = this.read_scalar(args[0])?.to_isize(this)?; + let handle = this.read_scalar(args[0])?.to_machine_isize(this)?; let buf = this.read_scalar(args[1])?.not_undef()?; let n = this.read_scalar(args[2])?.to_u32()?; let written_place = this.deref_operand(args[3])?; @@ -973,7 +973,7 @@ fn linux_getrandom<'tcx>( dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let ptr = this.read_scalar(args[0])?.not_undef()?; - let len = this.read_scalar(args[1])?.to_usize(this)?; + let len = this.read_scalar(args[1])?.to_machine_usize(this)?; // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, // neither of which have any effect on our current PRNG. diff --git a/src/shims/fs.rs b/src/shims/fs.rs index c484795d8fec..764f345904fa 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -154,7 +154,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("read")?; - let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; + let count = this.read_scalar(count_op)?.to_machine_usize(&*this.tcx)?; // Reading zero bytes should not change `buf`. if count == 0 { return Ok(0); @@ -166,8 +166,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.remove_handle_and(fd, |mut handle, this| { // Don't use `?` to avoid returning before reinserting the handle. let bytes = this.force_ptr(buf_scalar).and_then(|buf| { + // FIXME: Don't use raw methods this.memory - .get_mut(buf.alloc_id)? + .get_raw_mut(buf.alloc_id)? .get_bytes_mut(&*this.tcx, buf, Size::from_bytes(count)) .map(|buffer| handle.file.read(buffer)) }); @@ -186,7 +187,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("write")?; - let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; + let count = this.read_scalar(count_op)?.to_machine_usize(&*this.tcx)?; // Writing zero bytes should not change `buf`. if count == 0 { return Ok(0); @@ -195,7 +196,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; this.remove_handle_and(fd, |mut handle, this| { - let bytes = this.memory.get(buf.alloc_id).and_then(|alloc| { + // FIXME: Don't use raw methods + let bytes = this.memory.get_raw(buf.alloc_id).and_then(|alloc| { alloc .get_bytes(&*this.tcx, buf, Size::from_bytes(count)) .map(|bytes| handle.file.write(bytes).map(|bytes| bytes as i64)) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 7c8c06cbbfd5..7470090f5208 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -35,7 +35,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let intrinsic_name = &*tcx.item_name(instance.def_id()).as_str(); match intrinsic_name { "arith_offset" => { - let offset = this.read_scalar(args[1])?.to_isize(this)?; + let offset = this.read_scalar(args[1])?.to_machine_isize(this)?; let ptr = this.read_scalar(args[0])?.not_undef()?; let pointee_ty = substs.type_at(0); @@ -206,7 +206,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let elem_ty = substs.type_at(0); let elem_layout = this.layout_of(elem_ty)?; let elem_size = elem_layout.size.bytes(); - let count = this.read_scalar(args[2])?.to_usize(this)?; + let count = this.read_scalar(args[2])?.to_machine_usize(this)?; let elem_align = elem_layout.align.abi; let size = Size::from_bytes(count * elem_size); @@ -371,7 +371,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "offset" => { - let offset = this.read_scalar(args[1])?.to_isize(this)?; + let offset = this.read_scalar(args[1])?.to_machine_isize(this)?; let ptr = this.read_scalar(args[0])?.not_undef()?; let result_ptr = this.pointer_offset_inbounds(ptr, substs.type_at(0), offset)?; this.write_scalar(result_ptr, dest)?; @@ -542,7 +542,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = mplace.ptr.to_ptr()?; // We know the return place is in-bounds this.memory - .get_mut(ptr.alloc_id)? + .get_raw_mut(ptr.alloc_id)? .mark_definedness(ptr, dest.layout.size, false); } } @@ -554,7 +554,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ty_layout = this.layout_of(ty)?; let val_byte = this.read_scalar(args[1])?.to_u8()?; let ptr = this.read_scalar(args[0])?.not_undef()?; - let count = this.read_scalar(args[2])?.to_usize(this)?; + let count = this.read_scalar(args[2])?.to_machine_usize(this)?; let byte_count = ty_layout.size * count; this.memory.write_bytes(ptr, iter::repeat(val_byte).take(byte_count.bytes() as usize))?; } diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 60974958c42a..3302143f48cb 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -75,7 +75,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr_scalar = this.read_scalar(ptr_op)?.not_undef()?; if let Ok(ptr) = this.force_ptr(ptr_scalar) { - let cur_align = this.memory.get(ptr.alloc_id)?.align.bytes() as usize; + let cur_align = this.memory.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead)?.1.bytes() as usize; if cur_align >= req_align { // if the allocation alignment is at least the required alignment we use the // libcore implementation diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 6e63bb073c8c..94e69203437b 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -540,8 +540,8 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx kind, new_tag, ptr.tag, place.layout.ty, ptr.erase_tag(), size.bytes()); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. - let alloc = this.memory.get(ptr.alloc_id)?; - let stacked_borrows = alloc.extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); + let extra = &this.memory.get_raw(ptr.alloc_id)?.extra; + let stacked_borrows = extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); // Update the stacks. // Make sure that raw pointers and mutable shared references are reborrowed "weak": // There could be existing unique pointers reborrowed from them that should remain valid! From 6e37f2f3e158c98d094b7f3c9f681ed8e5b8c4c2 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 9 Nov 2019 15:15:52 +0100 Subject: [PATCH 1302/5092] Cap `count` --- src/shims/fs.rs | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 4d1b7fdf06c9..5e84cdee5cc4 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; +use std::convert::TryFrom; use std::fs::{remove_file, File, OpenOptions}; use std::io::{Read, Write}; -use std::convert::TryFrom; use rustc::ty::layout::Size; @@ -166,7 +166,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("read")?; - let count = this.read_scalar(count_op)?.to_machine_usize(&*this.tcx)?; + let ptr_size = this.pointer_size().bits(); + + let count = this + .read_scalar(count_op)? + .to_machine_usize(&*this.tcx)? + .min(1 << (ptr_size - 1)); // Reading zero bytes should not change `buf`. if count == 0 { return Ok(0); @@ -175,22 +180,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.read_scalar(buf_op)?.not_undef()?; if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { - let count = isize::try_from(count) - .map_err(|_| err_unsup_format!("Program tries to read into buffer too big for this host platform"))?; + let count = isize::try_from(count).unwrap(); // We want to read at most `count` bytes. We are sure that `count` is not negative // because it was a target's `usize`. Also we are sure that its smaller than // `usize::max_value()` because it is a host's `isize`. let mut bytes = vec![0; count as usize]; - let result = handle.file.read(&mut bytes); + let result = handle + .file + .read(&mut bytes) + .map(|c| i64::try_from(c).unwrap()); match result { - Ok(c) => { - let read_bytes = i64::try_from(c) - .map_err(|_| err_unsup_format!("Number of read bytes {} cannot be transformed to i64", c))?; + Ok(read_bytes) => { // If reading to `bytes` did not fail, we write those bytes to the buffer. this.memory.write_bytes(buf, bytes)?; Ok(read_bytes) - }, + } Err(e) => { this.set_last_error_from_io_error(e)?; Ok(-1) @@ -211,7 +216,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("write")?; - let count = this.read_scalar(count_op)?.to_machine_usize(&*this.tcx)?; + let ptr_size = this.pointer_size().bits(); + + let count = this + .read_scalar(count_op)? + .to_machine_usize(&*this.tcx)? + .min(1 << (ptr_size - 1)); // Writing zero bytes should not change `buf`. if count == 0 { return Ok(0); @@ -221,16 +231,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; - let result = handle.file.write(&bytes); - - match result { - Ok(c) => i64::try_from(c) - .map_err(|_| err_unsup_format!("Number of written bytes {} cannot be transformed to i64", c).into()), - Err(e) => { - this.set_last_error_from_io_error(e)?; - Ok(-1) - } - } + let result = handle.file.write(&bytes).map(|c| i64::try_from(c).unwrap()); + this.try_unwrap_io_result(result) } else { this.handle_not_found() } From 2c55a508e94c4390d94a843fd52114aa7a7940a7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 11 Nov 2019 21:25:57 +0100 Subject: [PATCH 1303/5092] rustup --- rust-version | 2 +- src/stacked_borrows.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index ec45e1f97307..e6d05f2ed0e2 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9e346646e93cc243567e27bb0f4e8716d56ad1f1 +56237d75b4271a8a2e0f47d86ea76ebf6d966152 diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 94e69203437b..32715157a771 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -8,7 +8,7 @@ use std::fmt; use std::num::NonZeroU64; use rustc::ty::{self, layout::Size}; -use rustc::hir::{MutMutable, MutImmutable}; +use rustc::hir::Mutability::{Mutable, Immutable}; use rustc::mir::RetagKind; use crate::{ @@ -618,13 +618,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn qualify(ty: ty::Ty<'_>, kind: RetagKind) -> Option<(RefKind, bool)> { match ty.kind { // References are simple. - ty::Ref(_, _, MutMutable) => + ty::Ref(_, _, Mutable) => Some((RefKind::Unique { two_phase: kind == RetagKind::TwoPhase}, kind == RetagKind::FnEntry)), - ty::Ref(_, _, MutImmutable) => + ty::Ref(_, _, Immutable) => Some((RefKind::Shared, kind == RetagKind::FnEntry)), // Raw pointers need to be enabled. ty::RawPtr(tym) if kind == RetagKind::Raw => - Some((RefKind::Raw { mutable: tym.mutbl == MutMutable }, false)), + Some((RefKind::Raw { mutable: tym.mutbl == Mutable }, false)), // Boxes do not get a protector: protectors reflect that references outlive the call // they were passed in to; that's just not the case for boxes. ty::Adt(..) if ty.is_box() => Some((RefKind::Unique { two_phase: false }, false)), From cf5b53e52fc0267aa9be95a6a2544eeb9761cd7f Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 12 Nov 2019 10:19:13 -0500 Subject: [PATCH 1304/5092] Rustup for panic changes This gets Miri working again, but doesn't actually implement unwinding --- src/eval.rs | 2 +- src/machine.rs | 17 +++++++++++++---- src/shims/foreign_items.rs | 2 +- src/shims/intrinsics.rs | 2 +- src/shims/mod.rs | 2 +- 5 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index b09fb5918c87..65f6d5dd0271 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -213,7 +213,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) { }; e.print_backtrace(); if let Some(frame) = ecx.stack().last() { - let block = &frame.body.basic_blocks()[frame.block]; + let block = &frame.body.basic_blocks()[frame.block.unwrap()]; let span = if frame.stmt < block.statements.len() { block.statements[frame.stmt].source_info.span } else { diff --git a/src/machine.rs b/src/machine.rs index c76cc2e568f4..20abfdcf54bb 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -173,6 +173,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { args: &[OpTy<'tcx, Tag>], dest: Option>, ret: Option, + _unwind: Option, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { ecx.find_fn(instance, args, dest, ret) } @@ -194,8 +195,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { span: Span, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag>, + dest: Option>, + _ret: Option, + _unwind: Option ) -> InterpResult<'tcx> { + let dest = match dest { + Some(dest) => dest, + None => throw_ub!(Unreachable) + }; ecx.call_intrinsic(span, instance, args, dest) } @@ -353,13 +360,15 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn stack_pop( ecx: &mut InterpCx<'mir, 'tcx, Self>, extra: stacked_borrows::CallId, - ) -> InterpResult<'tcx> { - Ok(ecx + _unwinding: bool + ) -> InterpResult<'tcx, StackPopInfo> { + ecx .memory .extra .stacked_borrows .borrow_mut() - .end_call(extra)) + .end_call(extra); + Ok(StackPopInfo::Normal) } #[inline(always)] diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 1f43a83576f6..55ec36387f2e 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -335,7 +335,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mir, Some(ret_place), // Directly return to caller. - StackPopCleanup::Goto(Some(ret)), + StackPopCleanup::Goto { ret: Some(ret), unwind: None }, )?; let mut args = this.frame().body.args_iter(); diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 7470090f5208..2e41ab1ca670 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -22,7 +22,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - if this.emulate_intrinsic(span, instance, args, dest)? { + if this.emulate_intrinsic(span, instance, args, Some(dest))? { return Ok(()); } let tcx = &{this.tcx.tcx}; diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 3302143f48cb..d9de27596cd0 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -27,7 +27,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); // First, run the common hooks also supported by CTFE. - if this.hook_fn(instance, args, dest)? { + if this.hook_panic_fn(instance, args, dest)? { this.goto_block(ret)?; return Ok(None); } From ca983f5f80c2e3c5cc54349276ccc8845063bf84 Mon Sep 17 00:00:00 2001 From: Steven Gu Date: Wed, 13 Nov 2019 10:14:13 +0800 Subject: [PATCH 1305/5092] Implments `intrinsics::copysignf32` and `intrinsics::copysignf64`. --- src/shims/intrinsics.rs | 22 ++++++++++++---------- tests/run-pass/floats.rs | 12 ++++++++++++ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 7470090f5208..34b8c483225b 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -291,24 +291,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.binop_ignore_overflow(op, a, b, dest)?; } - "minnumf32" | "maxnumf32" => { + "minnumf32" | "maxnumf32" | "copysignf32" => { let a = this.read_scalar(args[0])?.to_f32()?; let b = this.read_scalar(args[1])?.to_f32()?; - let res = if intrinsic_name.starts_with("min") { - a.min(b) - } else { - a.max(b) + let res = match intrinsic_name { + "minnumf32" => a.min(b), + "maxnumf32" => a.max(b), + "copysignf32" => a.copy_sign(b), + _ => bug!(), }; this.write_scalar(Scalar::from_f32(res), dest)?; } - "minnumf64" | "maxnumf64" => { + "minnumf64" | "maxnumf64" | "copysignf64" => { let a = this.read_scalar(args[0])?.to_f64()?; let b = this.read_scalar(args[1])?.to_f64()?; - let res = if intrinsic_name.starts_with("min") { - a.min(b) - } else { - a.max(b) + let res = match intrinsic_name { + "minnumf64" => a.min(b), + "maxnumf64" => a.max(b), + "copysignf64" => a.copy_sign(b), + _ => bug!(), }; this.write_scalar(Scalar::from_f64(res), dest)?; } diff --git a/tests/run-pass/floats.rs b/tests/run-pass/floats.rs index c1588dae249a..7577c48c5ae3 100644 --- a/tests/run-pass/floats.rs +++ b/tests/run-pass/floats.rs @@ -25,4 +25,16 @@ fn main() { assert_eq!(std::f64::NAN.max(-9.0), -9.0); assert_eq!((9.0 as f64).min(std::f64::NAN), 9.0); assert_eq!((-9.0 as f64).max(std::f64::NAN), -9.0); + + assert_eq!(3.5_f32.copysign(0.42), 3.5_f32); + assert_eq!(3.5_f32.copysign(-0.42), -3.5_f32); + assert_eq!((-3.5_f32).copysign(0.42), 3.5_f32); + assert_eq!((-3.5_f32).copysign(-0.42), -3.5_f32); + assert!(std::f32::NAN.copysign(1.0).is_nan()); + + assert_eq!(3.5_f64.copysign(0.42), 3.5_f64); + assert_eq!(3.5_f64.copysign(-0.42), -3.5_f64); + assert_eq!((-3.5_f64).copysign(0.42), 3.5_f64); + assert_eq!((-3.5_f64).copysign(-0.42), -3.5_f64); + assert!(std::f64::NAN.copysign(1.0).is_nan()); } From edd0157069b09e3fceb8036cabbdba96972cb2f7 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 13 Nov 2019 11:57:20 -0500 Subject: [PATCH 1306/5092] Cap `count` twice --- src/shims/fs.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 5e84cdee5cc4..9a819cd9db4b 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -168,10 +168,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr_size = this.pointer_size().bits(); + // We cap the number of read bytes to the largest value that we are able to fit in both the + // host's and target's `isize`. let count = this .read_scalar(count_op)? .to_machine_usize(&*this.tcx)? - .min(1 << (ptr_size - 1)); + .min(1 << (ptr_size - 1)) + .min(isize::max_value() as u64); // Reading zero bytes should not change `buf`. if count == 0 { return Ok(0); @@ -180,6 +183,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.read_scalar(buf_op)?.not_undef()?; if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { + // This can never fail because `count` was capped to be smaller than + // `isize::max_value()`. let count = isize::try_from(count).unwrap(); // We want to read at most `count` bytes. We are sure that `count` is not negative // because it was a target's `usize`. Also we are sure that its smaller than @@ -188,6 +193,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = handle .file .read(&mut bytes) + // `File::read` never returns a value larger than `i64::max_value()`, so this + // unwrap cannot fail. .map(|c| i64::try_from(c).unwrap()); match result { @@ -218,10 +225,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr_size = this.pointer_size().bits(); + // We cap the number of read bytes to the largest value that we are able to fit in both the + // host's and target's `isize`. let count = this .read_scalar(count_op)? .to_machine_usize(&*this.tcx)? - .min(1 << (ptr_size - 1)); + .min(1 << (ptr_size - 1)) + .min(isize::max_value() as u64); // Writing zero bytes should not change `buf`. if count == 0 { return Ok(0); From 4baef7120a934b79f87dbe5d09591d781c1c81f7 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 13 Nov 2019 14:45:00 -0500 Subject: [PATCH 1307/5092] Fix maximum `isize` value for target --- src/shims/fs.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 9a819cd9db4b..4de59ad32ff5 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -173,7 +173,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let count = this .read_scalar(count_op)? .to_machine_usize(&*this.tcx)? - .min(1 << (ptr_size - 1)) + .min((1 << (ptr_size - 1)) - 1) // max value of target `isize` .min(isize::max_value() as u64); // Reading zero bytes should not change `buf`. if count == 0 { @@ -193,8 +193,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = handle .file .read(&mut bytes) - // `File::read` never returns a value larger than `i64::max_value()`, so this - // unwrap cannot fail. + // `File::read` never returns a value larger than `count`, so this cannot fail. .map(|c| i64::try_from(c).unwrap()); match result { @@ -230,7 +229,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let count = this .read_scalar(count_op)? .to_machine_usize(&*this.tcx)? - .min(1 << (ptr_size - 1)) + .min((1 << (ptr_size - 1)) - 1) // max value of target `isize` .min(isize::max_value() as u64); // Writing zero bytes should not change `buf`. if count == 0 { From 82ef2bb0e28884207a2c59d42d6fbf2918153ec4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Nov 2019 10:16:44 +0100 Subject: [PATCH 1308/5092] rename miri-issue to issue-miri for grouping --- tests/run-pass/{miri-issue-133.rs => issue-miri-133.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/run-pass/{miri-issue-133.rs => issue-miri-133.rs} (100%) diff --git a/tests/run-pass/miri-issue-133.rs b/tests/run-pass/issue-miri-133.rs similarity index 100% rename from tests/run-pass/miri-issue-133.rs rename to tests/run-pass/issue-miri-133.rs From 64244e9a18a0b6a328f8dcfe0741a160d219b429 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Nov 2019 10:23:29 +0100 Subject: [PATCH 1309/5092] do full deref-check before reborrowing --- src/stacked_borrows.rs | 8 ++++---- tests/compile-fail/stacked_borrows/issue-miri-1050-1.rs | 6 ++++++ tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs | 7 +++++++ 3 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 tests/compile-fail/stacked_borrows/issue-miri-1050-1.rs create mode 100644 tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 32715157a771..0ab9dabab9b7 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -533,9 +533,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let protector = if protect { Some(this.frame().extra) } else { None }; - let ptr = this.memory.check_ptr_access(place.ptr, size, place.align) - .expect("validity checks should have excluded dangling/unaligned pointer") - .expect("we shouldn't get here for ZST"); + let ptr = place.ptr.to_ptr().expect("we should have a proper pointer"); trace!("reborrow: {} reference {:?} derived from {:?} (pointee {}): {:?}, size {}", kind, new_tag, ptr.tag, place.layout.ty, ptr.erase_tag(), size.bytes()); @@ -583,11 +581,13 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let size = this.size_and_align_of_mplace(place)? .map(|(size, _)| size) .unwrap_or_else(|| place.layout.size); + // We can see dangling ptrs in here e.g. after a Box's `Unique` was + // updated using "self.0 = ..." (can happen in Box::from_raw); see miri#1050. + let place = this.mplace_access_checked(place)?; if size == Size::ZERO { // Nothing to do for ZSTs. return Ok(*val); } - let place = this.force_mplace_ptr(place)?; // Compute new borrow. let new_tag = match kind { diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-1.rs b/tests/compile-fail/stacked_borrows/issue-miri-1050-1.rs new file mode 100644 index 000000000000..24df70a8179f --- /dev/null +++ b/tests/compile-fail/stacked_borrows/issue-miri-1050-1.rs @@ -0,0 +1,6 @@ +// error-pattern: pointer must be in-bounds + +fn main() { unsafe { + let ptr = Box::into_raw(Box::new(0u16)); + Box::from_raw(ptr as *mut u32); +} } diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs b/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs new file mode 100644 index 000000000000..74aab153ea90 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs @@ -0,0 +1,7 @@ +// error-pattern: dangling pointer was dereferenced +use std::ptr::NonNull; + +fn main() { unsafe { + let ptr = NonNull::::dangling(); + Box::from_raw(ptr.as_ptr()); +} } From c790317eb95c78af1e63dc0efcd4d447aa83ffc8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Nov 2019 10:29:43 +0100 Subject: [PATCH 1310/5092] remove no-longer-needed zero checks --- src/shims/fs.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 4de59ad32ff5..79e57cf2c8f5 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -175,10 +175,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .to_machine_usize(&*this.tcx)? .min((1 << (ptr_size - 1)) - 1) // max value of target `isize` .min(isize::max_value() as u64); - // Reading zero bytes should not change `buf`. - if count == 0 { - return Ok(0); - } + let fd = this.read_scalar(fd_op)?.to_i32()?; let buf = this.read_scalar(buf_op)?.not_undef()?; @@ -231,10 +228,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .to_machine_usize(&*this.tcx)? .min((1 << (ptr_size - 1)) - 1) // max value of target `isize` .min(isize::max_value() as u64); - // Writing zero bytes should not change `buf`. - if count == 0 { - return Ok(0); - } + let fd = this.read_scalar(fd_op)?.to_i32()?; let buf = this.read_scalar(buf_op)?.not_undef()?; From 524624297d37f87d3bceb28cddbde82eb2e789f8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 15 Nov 2019 15:59:19 +0100 Subject: [PATCH 1311/5092] test-cargo-miri: cargo update, re-enable windows num_cpus test --- test-cargo-miri/Cargo.lock | 37 +++++++++++++++++++---------------- test-cargo-miri/tests/test.rs | 1 - 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 55c7c528aa9f..118afff39bd6 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -1,10 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -[[package]] -name = "autocfg" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "byteorder" version = "1.3.2" @@ -23,7 +18,7 @@ name = "cargo-miri-test" version = "0.1.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -34,7 +29,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "getrandom" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -42,6 +37,14 @@ dependencies = [ "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "hermit-abi" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "libc" version = "0.2.65" @@ -49,9 +52,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num_cpus" -version = "1.10.1" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -65,12 +69,12 @@ name = "rand" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_pcg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -87,7 +91,7 @@ name = "rand_core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -100,10 +104,9 @@ dependencies = [ [[package]] name = "rand_pcg" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -113,17 +116,17 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] -"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" +"checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407" +"checksum hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "307c3c9f937f38e3534b1d6447ecf090cafcc9744e4a6360e8b037b2cf5af120" "checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" -"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" +"checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72" "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" "checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -"checksum rand_pcg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e196346cbbc5c70c77e7b4926147ee8e383a38ee4d15d58a08098b169e492b6" +"checksum rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" "checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 904bbbc6cd46..cfbe3f6d7fb6 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -39,6 +39,5 @@ fn entropy_rng() { #[test] fn num_cpus() { - #[cfg(not(windows))] // FIXME: enable on Windows again once https://github.com/seanmonstar/num_cpus/pull/90 gets released. assert_eq!(num_cpus::get(), 1); } From 68bc7e077b213bc92d8511e0236d2272743aa619 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 16 Nov 2019 09:00:05 +0100 Subject: [PATCH 1312/5092] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index e6d05f2ed0e2..0ddadf64c9d4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -56237d75b4271a8a2e0f47d86ea76ebf6d966152 +1d8b6ce89e0874b5e93c9e41bfdd565c56372bb0 From 08fe5ee78c181b4b7216d4a0cdacc4a29f1ae8b6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 16 Nov 2019 09:07:35 +0100 Subject: [PATCH 1313/5092] try the stable feature of compiletest --- Cargo.lock | 32 ++++++++++++++++++++++++++++++++ Cargo.toml | 2 +- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index fb7ab619281f..c930566c86a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -172,6 +172,7 @@ dependencies = [ "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tester 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -203,6 +204,15 @@ dependencies = [ "dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "dirs" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "dirs-sys" version = "0.3.4" @@ -671,6 +681,15 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "term" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "termcolor" version = "1.0.5" @@ -679,6 +698,16 @@ dependencies = [ "wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tester" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "thread_local" version = "0.3.6" @@ -795,6 +824,7 @@ dependencies = [ "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" "checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" "checksum directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c" +"checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" "checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" "checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" "checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" @@ -850,7 +880,9 @@ dependencies = [ "checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" "checksum synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" +"checksum term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" +"checksum tester 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cd0d1044cb5ca390e9c93f8c35abd2c55484397dfd786f189321aa34605ee6ab" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" diff --git a/Cargo.toml b/Cargo.toml index ba31dd848ab4..8a09bb7ac178 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,5 +59,5 @@ cargo_miri = ["cargo_metadata", "directories", "rustc_version"] rustc_tests = [] [dev-dependencies] -compiletest_rs = { version = "0.3.24", features = ["tmp"] } +compiletest_rs = { version = "0.3.24", features = ["tmp", "stable"] } colored = "1.6" From 4712ed3ff50db58e823758daca68ef33700aec00 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Nov 2019 09:03:16 +0100 Subject: [PATCH 1314/5092] rustup again --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 0ddadf64c9d4..0d6f14df928c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1d8b6ce89e0874b5e93c9e41bfdd565c56372bb0 +8831d766ace89bc74714918a7d9fbd3ca5ec946a From f2c0c44a098e9afda322fd9b378add202b49b637 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Nov 2019 09:20:50 +0100 Subject: [PATCH 1315/5092] remove some leftovers from the miri-control-attribute days --- src/bin/miri-rustc-tests.rs | 10 ---------- src/bin/miri.rs | 10 ---------- 2 files changed, 20 deletions(-) diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 5f814fd19862..920c92544300 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -29,16 +29,6 @@ struct MiriCompilerCalls { } impl rustc_driver::Callbacks for MiriCompilerCalls { - fn after_parsing(&mut self, compiler: &interface::Compiler) -> Compilation { - let attr = ( - syntax::symbol::Symbol::intern("miri"), - syntax::feature_gate::AttributeType::Whitelisted, - ); - compiler.session().plugin_attributes.borrow_mut().push(attr); - - Compilation::Continue - } - fn after_analysis(&mut self, compiler: &interface::Compiler) -> Compilation { compiler.session().abort_if_errors(); compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| { diff --git a/src/bin/miri.rs b/src/bin/miri.rs index dd56f0a6e53c..481491ea722f 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -28,16 +28,6 @@ struct MiriCompilerCalls { } impl rustc_driver::Callbacks for MiriCompilerCalls { - fn after_parsing(&mut self, compiler: &interface::Compiler) -> Compilation { - let attr = ( - syntax::symbol::Symbol::intern("miri"), - syntax::feature_gate::AttributeType::Whitelisted, - ); - compiler.session().plugin_attributes.borrow_mut().push(attr); - - Compilation::Continue - } - fn after_analysis(&mut self, compiler: &interface::Compiler) -> Compilation { init_late_loggers(); compiler.session().abort_if_errors(); From 5345636f37a2934ea4c183baa2069fa50c6793cc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Nov 2019 09:30:32 +0100 Subject: [PATCH 1316/5092] use new isize_max method in FS accesses; also check full buffers for validity --- src/shims/fs.rs | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 79e57cf2c8f5..9291f3a6e3b2 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -3,7 +3,7 @@ use std::convert::TryFrom; use std::fs::{remove_file, File, OpenOptions}; use std::io::{Read, Write}; -use rustc::ty::layout::Size; +use rustc::ty::layout::{Size, Align}; use crate::stacked_borrows::Tag; use crate::*; @@ -166,18 +166,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("read")?; - let ptr_size = this.pointer_size().bits(); - - // We cap the number of read bytes to the largest value that we are able to fit in both the - // host's and target's `isize`. - let count = this - .read_scalar(count_op)? - .to_machine_usize(&*this.tcx)? - .min((1 << (ptr_size - 1)) - 1) // max value of target `isize` - .min(isize::max_value() as u64); - let fd = this.read_scalar(fd_op)?.to_i32()?; let buf = this.read_scalar(buf_op)?.not_undef()?; + let count = this + .read_scalar(count_op)? + .to_machine_usize(&*this.tcx)?; + + // Check that the *entire* buffer is actually valid memory. + this.memory.check_ptr_access(buf, Size::from_bytes(count), Align::from_bytes(1).unwrap())?; + + // We cap the number of read bytes to the largest value that we are able to fit in both the + // host's and target's `isize`. This saves us from having to handle overflows later. + let count = count + .min(this.isize_max() as u64) + .min(isize::max_value() as u64); if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { // This can never fail because `count` was capped to be smaller than @@ -219,18 +221,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("write")?; - let ptr_size = this.pointer_size().bits(); - - // We cap the number of read bytes to the largest value that we are able to fit in both the - // host's and target's `isize`. - let count = this - .read_scalar(count_op)? - .to_machine_usize(&*this.tcx)? - .min((1 << (ptr_size - 1)) - 1) // max value of target `isize` - .min(isize::max_value() as u64); - let fd = this.read_scalar(fd_op)?.to_i32()?; let buf = this.read_scalar(buf_op)?.not_undef()?; + let count = this + .read_scalar(count_op)? + .to_machine_usize(&*this.tcx)?; + + // Check that the *entire* buffer is actually valid memory. + this.memory.check_ptr_access(buf, Size::from_bytes(count), Align::from_bytes(1).unwrap())?; + + // We cap the number of written bytes to the largest value that we are able to fit in both the + // host's and target's `isize`. This saves us from having to handle overflows later. + let count = count + .min(this.isize_max() as u64) + .min(isize::max_value() as u64); if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; From 08d3fbc76b72fd06cade88b2afe21b70978e8797 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 14 Apr 2019 21:02:55 -0400 Subject: [PATCH 1317/5092] Support unwinding after a panic Fixes #658 This commit adds support for unwinding after a panic. It requires a companion rustc PR to be merged, in order for the necessary hooks to work properly. Currently implemented: * Selecting between unwind/abort mode based on the rustc Session * Properly popping off stack frames, unwinding back the caller * Running 'unwind' blocks in Mir terminators Not yet implemented: * 'Abort' terminators This PR was getting fairly large, so I decided to open it for review without implementing 'Abort' terminator support. This could either be added on to this PR, or merged separately. --- src/eval.rs | 5 +- src/helpers.rs | 66 ++++++----- src/lib.rs | 1 + src/machine.rs | 59 +++++----- src/shims/foreign_items.rs | 78 +++++-------- src/shims/intrinsics.rs | 33 ++++-- src/shims/mod.rs | 20 ++-- src/shims/panic.rs | 179 +++++++++++++++++++++++++++++ src/stacked_borrows.rs | 2 +- tests/compile-fail/double_panic.rs | 11 ++ tests/compile-fail/panic1.rs | 4 +- tests/compile-fail/panic2.rs | 3 +- tests/compile-fail/panic3.rs | 1 + tests/compile-fail/panic4.rs | 1 + tests/run-pass/catch_panic.rs | 61 ++++++++++ tests/run-pass/panic1.rs | 3 + tests/run-pass/panic1.stderr | 1 + tests/run-pass/panic2.rs | 4 + tests/run-pass/panic2.stderr | 1 + 19 files changed, 403 insertions(+), 130 deletions(-) create mode 100644 src/shims/panic.rs create mode 100644 tests/compile-fail/double_panic.rs create mode 100644 tests/run-pass/catch_panic.rs create mode 100644 tests/run-pass/panic1.rs create mode 100644 tests/run-pass/panic1.stderr create mode 100644 tests/run-pass/panic2.rs create mode 100644 tests/run-pass/panic2.stderr diff --git a/src/eval.rs b/src/eval.rs index 65f6d5dd0271..7203ba6bf1db 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -39,10 +39,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), Evaluator::new(config.communicate), - MemoryExtra::new( - StdRng::seed_from_u64(config.seed.unwrap_or(0)), - config.validate, - ), + MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate), ); // Complete initialization. EnvVars::init(&mut ecx, config.excluded_env_vars); diff --git a/src/helpers.rs b/src/helpers.rs index ae117d5fb352..cff78859df8d 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -6,6 +6,7 @@ use rustc::mir; use rustc::ty::{ self, List, + TyCtxt, layout::{self, LayoutOf, Size, TyLayout}, }; @@ -15,40 +16,45 @@ use crate::*; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} -pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// Gets an instance for a path. - fn resolve_path(&self, path: &[&str]) -> InterpResult<'tcx, ty::Instance<'tcx>> { - let this = self.eval_context_ref(); - this.tcx - .crates() - .iter() - .find(|&&krate| this.tcx.original_crate_name(krate).as_str() == path[0]) - .and_then(|krate| { - let krate = DefId { - krate: *krate, - index: CRATE_DEF_INDEX, - }; - let mut items = this.tcx.item_children(krate); - let mut path_it = path.iter().skip(1).peekable(); +/// Gets an instance for a path. +fn resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> InterpResult<'tcx, DefId> { + tcx + .crates() + .iter() + .find(|&&krate| tcx.original_crate_name(krate).as_str() == path[0]) + .and_then(|krate| { + let krate = DefId { + krate: *krate, + index: CRATE_DEF_INDEX, + }; + let mut items = tcx.item_children(krate); + let mut path_it = path.iter().skip(1).peekable(); - while let Some(segment) = path_it.next() { - for item in mem::replace(&mut items, Default::default()).iter() { - if item.ident.name.as_str() == *segment { - if path_it.peek().is_none() { - return Some(ty::Instance::mono(this.tcx.tcx, item.res.def_id())); - } - - items = this.tcx.item_children(item.res.def_id()); - break; + while let Some(segment) = path_it.next() { + for item in mem::replace(&mut items, Default::default()).iter() { + if item.ident.name.as_str() == *segment { + if path_it.peek().is_none() { + return Some(item.res.def_id()) } + + items = tcx.item_children(item.res.def_id()); + break; } } - None - }) - .ok_or_else(|| { - let path = path.iter().map(|&s| s.to_owned()).collect(); - err_unsup!(PathNotFound(path)).into() - }) + } + None + }) + .ok_or_else(|| { + let path = path.iter().map(|&s| s.to_owned()).collect(); + err_unsup!(PathNotFound(path)).into() + }) +} + + +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + + fn resolve_path(&self, path: &[&str]) -> InterpResult<'tcx, ty::Instance<'tcx>> { + Ok(ty::Instance::mono(self.eval_context_ref().tcx.tcx, resolve_did(self.eval_context_ref().tcx.tcx, path)?)) } /// Write a 0 of the appropriate size to `dest`. diff --git a/src/lib.rs b/src/lib.rs index 59acff358678..f29ec8f22bba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,6 +37,7 @@ pub use crate::shims::time::{EvalContextExt as TimeEvalContextExt}; pub use crate::shims::dlsym::{Dlsym, EvalContextExt as DlsymEvalContextExt}; pub use crate::shims::env::{EnvVars, EvalContextExt as EnvEvalContextExt}; pub use crate::shims::fs::{FileHandler, EvalContextExt as FileEvalContextExt}; +pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as PanicEvalContextExt}; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; diff --git a/src/machine.rs b/src/machine.rs index 20abfdcf54bb..8910c589ee70 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -8,12 +8,8 @@ use std::rc::Rc; use rand::rngs::StdRng; use rustc::hir::def_id::DefId; +use rustc::ty::{self, layout::{Size, LayoutOf}, Ty, TyCtxt}; use rustc::mir; -use rustc::ty::{ - self, - layout::{LayoutOf, Size}, - Ty, TyCtxt, -}; use syntax::{attr, source_map::Span, symbol::sym}; use crate::*; @@ -24,6 +20,19 @@ pub const STACK_ADDR: u64 = 32 * PAGE_SIZE; // not really about the "stack", but pub const STACK_SIZE: u64 = 16 * PAGE_SIZE; // whatever pub const NUM_CPUS: u64 = 1; +/// Extra data stored with each stack frame +#[derive(Debug)] +pub struct FrameData<'tcx> { + /// Extra data for Stacked Borrows. + pub call_id: stacked_borrows::CallId, + /// If this is Some(), then this is a special 'catch unwind' + /// frame. When this frame is popped during unwinding a panic, + /// we stop unwinding, and use the `CatchUnwindData` to + /// store the panic payload and continue execution in the parent frame. + pub catch_panic: Option>, +} + + /// Extra memory kinds #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum MiriMemoryKind { @@ -101,6 +110,10 @@ pub struct Evaluator<'tcx> { pub(crate) communicate: bool, pub(crate) file_handler: FileHandler, + + /// The temporary used for storing the argument of + /// the call to `miri_start_panic` (the panic payload) when unwinding. + pub(crate) panic_payload: Option> } impl<'tcx> Evaluator<'tcx> { @@ -116,6 +129,7 @@ impl<'tcx> Evaluator<'tcx> { tls: TlsData::default(), communicate, file_handler: Default::default(), + panic_payload: None } } } @@ -143,7 +157,7 @@ impl<'mir, 'tcx> MiriEvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryKinds = MiriMemoryKind; - type FrameExtra = stacked_borrows::CallId; + type FrameExtra = FrameData<'tcx>; type MemoryExtra = MemoryExtra; type AllocExtra = AllocExtra; type PointerTag = Tag; @@ -173,9 +187,9 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { args: &[OpTy<'tcx, Tag>], dest: Option>, ret: Option, - _unwind: Option, + unwind: Option, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { - ecx.find_fn(instance, args, dest, ret) + ecx.find_fn(instance, args, dest, ret, unwind) } #[inline(always)] @@ -196,14 +210,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], dest: Option>, - _ret: Option, - _unwind: Option + ret: Option, + unwind: Option, ) -> InterpResult<'tcx> { - let dest = match dest { - Some(dest) => dest, - None => throw_ub!(Unreachable) - }; - ecx.call_intrinsic(span, instance, args, dest) + ecx.call_intrinsic(span, instance, args, dest, ret, unwind) } #[inline(always)] @@ -352,23 +362,20 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn stack_push( ecx: &mut InterpCx<'mir, 'tcx, Self>, - ) -> InterpResult<'tcx, stacked_borrows::CallId> { - Ok(ecx.memory.extra.stacked_borrows.borrow_mut().new_call()) + ) -> InterpResult<'tcx, FrameData<'tcx>> { + Ok(FrameData { + call_id: ecx.memory.extra.stacked_borrows.borrow_mut().new_call(), + catch_panic: None, + }) } #[inline(always)] fn stack_pop( ecx: &mut InterpCx<'mir, 'tcx, Self>, - extra: stacked_borrows::CallId, - _unwinding: bool + extra: FrameData<'tcx>, + unwinding: bool ) -> InterpResult<'tcx, StackPopInfo> { - ecx - .memory - .extra - .stacked_borrows - .borrow_mut() - .end_call(extra); - Ok(StackPopInfo::Normal) + ecx.handle_stack_pop(extra, unwinding) } #[inline(always)] diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 55ec36387f2e..781c5ad40f93 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -1,9 +1,10 @@ use std::{iter, convert::TryInto}; -use rustc::hir::def_id::DefId; use rustc::mir; use rustc::ty::layout::{Align, LayoutOf, Size}; +use rustc::hir::def_id::DefId; use rustc_apfloat::Float; +use rustc::ty; use syntax::attr; use syntax::symbol::sym; @@ -105,13 +106,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Emulates calling a foreign item, failing if the item is not supported. /// This function will handle `goto_block` if needed. + /// Returns Ok(None) if the foreign item was completely handled + /// by this function. + /// Returns Ok(Some(body)) if processing the foreign item + /// is delegated to another function. fn emulate_foreign_item( &mut self, def_id: DefId, args: &[OpTy<'tcx, Tag>], dest: Option>, ret: Option, - ) -> InterpResult<'tcx> { + _unwind: Option + ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { @@ -124,8 +130,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // First: functions that diverge. match link_name { - "__rust_start_panic" | "panic_impl" => { - throw_unsup_format!("the evaluated program panicked"); + // Note that this matches calls to the *foreign* item "__rust_start_panic" - + // that is, calls `extern "Rust" { fn __rust_start_panic(...) }` + // We forward this to the underlying *implementation* in "libpanic_unwind" + "__rust_start_panic" => { + let start_panic_instance = this.resolve_path(&["panic_unwind", "__rust_start_panic"])?; + return Ok(Some(this.load_mir(start_panic_instance.def, None)?)); + } + + // During a normal (non-Miri) compilation, + // this gets resolved to the '#[panic_handler]` function at link time, + // which corresponds to the function with the `#[panic_handler]` attribute. + // + // Since we're interpreting mir, we forward it to the implementation of `panic_impl` + // + // This is used by libcore to forward panics to the actual + // panic impl + "panic_impl" => { + let panic_impl_id = this.tcx.lang_items().panic_impl().unwrap(); + let panic_impl_instance = ty::Instance::mono(*this.tcx, panic_impl_id); + return Ok(Some(this.load_mir(panic_impl_instance.def, None)?)); } "exit" | "ExitProcess" => { // it's really u32 for ExitProcess, but we have to put it into the `Exit` error variant anyway @@ -310,48 +334,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "__rust_maybe_catch_panic" => { - // fn __rust_maybe_catch_panic( - // f: fn(*mut u8), - // data: *mut u8, - // data_ptr: *mut usize, - // vtable_ptr: *mut usize, - // ) -> u32 - // We abort on panic, so not much is going on here, but we still have to call the closure. - let f = this.read_scalar(args[0])?.not_undef()?; - let data = this.read_scalar(args[1])?.not_undef()?; - let f_instance = this.memory.get_fn(f)?.as_instance()?; - this.write_null(dest)?; - trace!("__rust_maybe_catch_panic: {:?}", f_instance); - - // Now we make a function call. - // TODO: consider making this reusable? `InterpCx::step` does something similar - // for the TLS destructors, and of course `eval_main`. - let mir = this.load_mir(f_instance.def, None)?; - let ret_place = - MPlaceTy::dangling(this.layout_of(tcx.mk_unit())?, this).into(); - this.push_stack_frame( - f_instance, - mir.span, - mir, - Some(ret_place), - // Directly return to caller. - StackPopCleanup::Goto { ret: Some(ret), unwind: None }, - )?; - let mut args = this.frame().body.args_iter(); - - let arg_local = args - .next() - .expect("Argument to __rust_maybe_catch_panic does not take enough arguments."); - let arg_dest = this.local_place(arg_local)?; - this.write_scalar(data, arg_dest)?; - - args.next().expect_none("__rust_maybe_catch_panic argument has more arguments than expected"); - - // We ourselves will return `0`, eventually (because we will not return if we paniced). - this.write_null(dest)?; - - // Don't fall through, we do *not* want to `goto_block`! - return Ok(()); + this.handle_catch_panic(args, dest, ret)?; + return Ok(None) } "memcmp" => { @@ -943,7 +927,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.goto_block(Some(ret))?; this.dump_place(*dest); - Ok(()) + Ok(None) } /// Evaluates the scalar at the specified path. Returns Some(val) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 20031f837bc3..0e7314c1809f 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -7,10 +7,7 @@ use rustc::ty::layout::{self, LayoutOf, Size, Align}; use rustc::ty; use syntax::source_map::Span; -use crate::{ - PlaceTy, OpTy, Immediate, Scalar, Tag, - OperatorEvalContextExt -}; +use crate::*; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -19,10 +16,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx span: Span, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag>, + dest: Option>, + _ret: Option, + unwind: Option ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - if this.emulate_intrinsic(span, instance, args, Some(dest))? { + if this.emulate_intrinsic(span, instance, args, dest)? { return Ok(()); } let tcx = &{this.tcx.tcx}; @@ -31,8 +30,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // All these intrinsics take raw pointers, so if we access memory directly // (as opposed to through a place), we have to remember to erase any tag // that might still hang around! - let intrinsic_name = &*tcx.item_name(instance.def_id()).as_str(); + + // Handle diverging intrinsics + match intrinsic_name { + "abort" => { + // FIXME: Add a better way of indicating 'abnormal' termination, + // since this is not really an 'unsupported' behavior + throw_unsup_format!("the evaluated program aborted!"); + } + "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), + _ => {} + } + + // Handle non-diverging intrinsics + // The intrinsic itself cannot diverge (otherwise, we would have handled it above), + // so if we got here without a return place... (can happen e.g., for transmute returning `!`) + let dest = match dest { + Some(dest) => dest, + None => throw_ub!(Unreachable) + }; + match intrinsic_name { "arith_offset" => { let offset = this.read_scalar(args[1])?.to_machine_isize(this)?; @@ -526,7 +544,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // However, this only affects direct calls of the intrinsic; calls to the stable // functions wrapping them do get their validation. // FIXME: should we check alignment for ZSTs? - use crate::ScalarMaybeUndef; if !dest.layout.is_zst() { match dest.layout.abi { layout::Abi::Scalar(..) => { diff --git a/src/shims/mod.rs b/src/shims/mod.rs index d9de27596cd0..f554c19f11c2 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -5,9 +5,9 @@ pub mod intrinsics; pub mod tls; pub mod fs; pub mod time; +pub mod panic; use rustc::{mir, ty}; - use crate::*; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -18,6 +18,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], dest: Option>, ret: Option, + unwind: Option ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); trace!( @@ -26,11 +27,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest.map(|place| *place) ); - // First, run the common hooks also supported by CTFE. - if this.hook_panic_fn(instance, args, dest)? { - this.goto_block(ret)?; - return Ok(None); - } // There are some more lang items we want to hook that CTFE does not hook (yet). if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { let dest = dest.unwrap(); @@ -44,11 +40,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Try to see if we can do something about foreign items. if this.tcx.is_foreign_item(instance.def_id()) { - // An external function that we cannot find MIR for, but we can still run enough - // of them to make miri viable. - this.emulate_foreign_item(instance.def_id(), args, dest, ret)?; - // `goto_block` already handled. - return Ok(None); + // An external function call that does not have a MIR body. We either find MIR elsewhere + // or emulate its effect. + // This will be Ok(None) if we're emulating the intrinsic entirely within Miri (no need + // to run extra MIR), and Ok(Some(body)) if we found MIR to run for the + // foreign function + // Any needed call to `goto_block` will be performed by `emulate_foreign_item`. + return this.emulate_foreign_item(instance.def_id(), args, dest, ret, unwind); } // Otherwise, load the MIR. diff --git a/src/shims/panic.rs b/src/shims/panic.rs new file mode 100644 index 000000000000..3e0dd767d823 --- /dev/null +++ b/src/shims/panic.rs @@ -0,0 +1,179 @@ +use rustc::mir; +use crate::*; +use super::machine::FrameData; +use rustc_target::spec::PanicStrategy; +use crate::rustc_target::abi::LayoutOf; + +/// Holds all of the relevant data for a call to +/// __rust_maybe_catch_panic +/// +/// If a panic occurs, we update this data with +/// the information from the panic site +#[derive(Debug)] +pub struct CatchUnwindData<'tcx> { + /// The 'data' argument passed to `__rust_maybe_catch_panic` + pub data: Pointer, + /// The `data_ptr` argument passed to `__rust_maybe_catch_panic` + pub data_place: MPlaceTy<'tcx, Tag>, + /// The `vtable_ptr` argument passed to `__rust_maybe_catch_panic` + pub vtable_place: MPlaceTy<'tcx, Tag>, + /// The `dest` from the original call to `__rust_maybe_catch_panic` + pub dest: PlaceTy<'tcx, Tag>, + /// The `ret` from the original call to `__rust_maybe_catch_panic` + pub ret: mir::BasicBlock, +} + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + + /// Handles the special "miri_start_panic" intrinsic, which is called + /// by libpanic_unwind to delegate the actual unwinding process to Miri + #[inline(always)] + fn handle_miri_start_panic( + &mut self, + args: &[OpTy<'tcx, Tag>], + unwind: Option + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + trace!("miri_start_panic: {:?}", this.frame().span); + + if this.tcx.tcx.sess.panic_strategy() == PanicStrategy::Abort { + // FIXME: Add a better way of indicating 'abnormal' termination, + // since this is not really an 'unsupported' behavior + throw_unsup_format!("the evaluated program panicked"); + } + + // Get the raw pointer stored in arg[0] + let scalar = this.read_immediate(args[0])?; + this.machine.panic_payload = Some(scalar); + + // Jump to the unwind block to begin unwinding + // We don't use 'goto_block' - if `unwind` is None, + // we'll end up immediately returning out of the + // function during the next step() call + let next_frame = this.frame_mut(); + next_frame.block = unwind; + next_frame.stmt = 0; + return Ok(()) + } + + #[inline(always)] + fn handle_catch_panic( + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag>, + ret: mir::BasicBlock, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let tcx = &{this.tcx.tcx}; + + // fn __rust_maybe_catch_panic( + // f: fn(*mut u8), + // data: *mut u8, + // data_ptr: *mut usize, + // vtable_ptr: *mut usize, + // ) -> u32 + let f = this.read_scalar(args[0])?.not_undef()?; + let data = this.read_scalar(args[1])?.not_undef()?; + let data_place = this.deref_operand(args[2])?; + let vtable_place = this.deref_operand(args[3])?; + let f_instance = this.memory.get_fn(f)?.as_instance()?; + this.write_null(dest)?; + trace!("__rust_maybe_catch_panic: {:?}", f_instance); + + + // Now we make a function call. + // TODO: consider making this reusable? `InterpCx::step` does something similar + // for the TLS destructors, and of course `eval_main`. + let mir = this.load_mir(f_instance.def, None)?; + let ret_place = + MPlaceTy::dangling(this.layout_of(tcx.mk_unit())?, this).into(); + this.push_stack_frame( + f_instance, + mir.span, + mir, + Some(ret_place), + // Directly return to caller. + StackPopCleanup::Goto { ret: Some(ret), unwind: None }, + )?; + + // In unwind mode, we tag this frame with some extra data. + // This lets `handle_stack_pop` (below) know that we should stop unwinding + // when we pop this frame. + if this.tcx.tcx.sess.panic_strategy() == PanicStrategy::Unwind { + this.frame_mut().extra.catch_panic = Some(CatchUnwindData { + data: data.to_ptr()?, + data_place, + vtable_place, + dest, + ret, + }) + } + + let mut args = this.frame().body.args_iter(); + + let arg_local = args + .next() + .expect("Argument to __rust_maybe_catch_panic does not take enough arguments."); + let arg_dest = this.local_place(arg_local)?; + this.write_scalar(data, arg_dest)?; + + args.next().expect_none("__rust_maybe_catch_panic argument has more arguments than expected"); + + // We ourselves will return `0`, eventually (because we will not return if we paniced). + this.write_null(dest)?; + + return Ok(()); + } + + #[inline(always)] + fn handle_stack_pop( + &mut self, + mut extra: FrameData<'tcx>, + unwinding: bool + ) -> InterpResult<'tcx, StackPopInfo> { + let this = self.eval_context_mut(); + + trace!("handle_stack_pop(extra = {:?}, unwinding = {})", extra, unwinding); + + // We only care about `catch_panic` if we're unwinding - if we're doing a normal + // return, then we don't need to do anything special. + let res = if let (true, Some(unwind_data)) = (unwinding, extra.catch_panic.take()) { + // We've just popped the frame that was immediately above + // the frame which originally called `__rust_maybe_catch_panic` + trace!("unwinding: found catch_panic frame: {:?}", this.frame().span); + + // `panic_payload` now holds a '*mut (dyn Any + Send)', + // provided by the `miri_start_panic` intrinsic. + // We want to split this into its consituient parts - + // the data and vtable pointers - and store them back + // into the panic handler frame + let real_ret = this.machine.panic_payload.take().unwrap(); + + let payload = this.ref_to_mplace(real_ret)?; + let payload_data_place = payload.ptr; + let payload_vtable_place = payload.meta.expect("Expected fat pointer"); + + + let data_place = unwind_data.data_place; + let vtable_place = unwind_data.vtable_place; + let dest = unwind_data.dest; + + // Here, we write to the pointers provided to the call + // to '__rust_maybe_catch_panic`. + this.write_scalar(payload_data_place, data_place.into())?; + this.write_scalar(payload_vtable_place, vtable_place.into())?; + + // We set the return value of `__rust_maybe_catch_panic` to 1, + // since there was a panic. + this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; + + StackPopInfo::StopUnwinding + } else { + StackPopInfo::Normal + }; + this.memory.extra.stacked_borrows.borrow_mut().end_call(extra.call_id); + Ok(res) + } +} diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 0ab9dabab9b7..3b821c7155a6 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -532,7 +532,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx protect: bool, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let protector = if protect { Some(this.frame().extra) } else { None }; + let protector = if protect { Some(this.frame().extra.call_id) } else { None }; let ptr = place.ptr.to_ptr().expect("we should have a proper pointer"); trace!("reborrow: {} reference {:?} derived from {:?} (pointee {}): {:?}, size {}", kind, new_tag, ptr.tag, place.layout.ty, ptr.erase_tag(), size.bytes()); diff --git a/tests/compile-fail/double_panic.rs b/tests/compile-fail/double_panic.rs new file mode 100644 index 000000000000..950d865c2a56 --- /dev/null +++ b/tests/compile-fail/double_panic.rs @@ -0,0 +1,11 @@ + //error-pattern: the evaluated program aborted +struct Foo; +impl Drop for Foo { + fn drop(&mut self) { + panic!("second"); + } +} +fn main() { + let _foo = Foo; + panic!("first"); +} diff --git a/tests/compile-fail/panic1.rs b/tests/compile-fail/panic1.rs index 1163c8708287..ff499316920f 100644 --- a/tests/compile-fail/panic1.rs +++ b/tests/compile-fail/panic1.rs @@ -1,5 +1,5 @@ -//error-pattern: the evaluated program panicked - +// error-pattern: the evaluated program panicked +// compile-flags: -C panic=abort fn main() { std::panic!("panicking from libstd"); } diff --git a/tests/compile-fail/panic2.rs b/tests/compile-fail/panic2.rs index e643e6922413..3b36db2d2d81 100644 --- a/tests/compile-fail/panic2.rs +++ b/tests/compile-fail/panic2.rs @@ -1,4 +1,5 @@ -//error-pattern: the evaluated program panicked +// error-pattern: the evaluated program panicked +// compile-flags: -C panic=abort fn main() { std::panic!("{}-panicking from libstd", 42); diff --git a/tests/compile-fail/panic3.rs b/tests/compile-fail/panic3.rs index b22f95d9c69d..6f5d6c3e1ce3 100644 --- a/tests/compile-fail/panic3.rs +++ b/tests/compile-fail/panic3.rs @@ -1,4 +1,5 @@ //error-pattern: the evaluated program panicked +// compile-flags: -C panic=abort fn main() { core::panic!("panicking from libcore"); diff --git a/tests/compile-fail/panic4.rs b/tests/compile-fail/panic4.rs index 449e716e161c..22d675375ac4 100644 --- a/tests/compile-fail/panic4.rs +++ b/tests/compile-fail/panic4.rs @@ -1,4 +1,5 @@ //error-pattern: the evaluated program panicked +// compile-flags: -C panic=abort fn main() { core::panic!("{}-panicking from libcore", 42); diff --git a/tests/run-pass/catch_panic.rs b/tests/run-pass/catch_panic.rs new file mode 100644 index 000000000000..8e254385d474 --- /dev/null +++ b/tests/run-pass/catch_panic.rs @@ -0,0 +1,61 @@ +use std::panic::catch_unwind; +use std::cell::Cell; + +thread_local! { + static MY_COUNTER: Cell = Cell::new(0); + static DROPPED: Cell = Cell::new(false); + static HOOK_CALLED: Cell = Cell::new(false); +} + +struct DropTester; + +impl Drop for DropTester { + fn drop(&mut self) { + DROPPED.with(|c| { + c.set(true); + }); + } +} + +fn do_panic_counter() { + // If this gets leaked, it will be easy to spot + // in Miri's leak report + let _string = "LEAKED FROM do_panic_counter".to_string(); + + // When we panic, this should get dropped during unwinding + let _drop_tester = DropTester; + + // Check for bugs in Miri's panic implementation. + // If do_panic_counter() somehow gets called more than once, + // we'll generate a different panic message + let old_val = MY_COUNTER.with(|c| { + let val = c.get(); + c.set(val + 1); + val + }); + panic!(format!("Hello from panic: {:?}", old_val)); +} + +fn main() { + std::panic::set_hook(Box::new(|_panic_info| { + HOOK_CALLED.with(|h| h.set(true)); + })); + let res = catch_unwind(|| { + let _string = "LEAKED FROM CLOSURE".to_string(); + do_panic_counter() + }); + let expected: Box = Box::new("Hello from panic: 0".to_string()); + let actual = res.expect_err("do_panic() did not panic!") + .downcast::().expect("Failed to cast to string!"); + + assert_eq!(expected, actual); + DROPPED.with(|c| { + // This should have been set to 'true' by DropTester + assert!(c.get()); + }); + + HOOK_CALLED.with(|h| { + assert!(h.get()); + }); +} + diff --git a/tests/run-pass/panic1.rs b/tests/run-pass/panic1.rs new file mode 100644 index 000000000000..b9bb52b95b13 --- /dev/null +++ b/tests/run-pass/panic1.rs @@ -0,0 +1,3 @@ +fn main() { + panic!("Miri panic!"); +} diff --git a/tests/run-pass/panic1.stderr b/tests/run-pass/panic1.stderr new file mode 100644 index 000000000000..a29ba479825a --- /dev/null +++ b/tests/run-pass/panic1.stderr @@ -0,0 +1 @@ +thread 'main' panicked at 'Miri panic!', $DIR/panic1.rs:2:5 diff --git a/tests/run-pass/panic2.rs b/tests/run-pass/panic2.rs new file mode 100644 index 000000000000..9a1da6656c26 --- /dev/null +++ b/tests/run-pass/panic2.rs @@ -0,0 +1,4 @@ +fn main() { + let val = "Value".to_string(); + panic!("Miri panic with value: {}", val); +} diff --git a/tests/run-pass/panic2.stderr b/tests/run-pass/panic2.stderr new file mode 100644 index 000000000000..de70fd4d583e --- /dev/null +++ b/tests/run-pass/panic2.stderr @@ -0,0 +1 @@ +thread 'main' panicked at 'Miri panic with value: Value', $DIR/panic2.rs:3:5 From b06d99b8a00a2b1433b0ccaabe4b4b86bdd786b2 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 17 Nov 2019 08:40:34 -0500 Subject: [PATCH 1318/5092] Ignore '-C panic=abort' tests for now We are currently building `libpanic_abort` with the wrong panic strategy, due to Xargo missing a hack used by `bootstrap`. --- tests/compile-fail/panic1.rs | 1 + tests/compile-fail/panic2.rs | 1 + tests/compile-fail/panic3.rs | 1 + tests/compile-fail/panic4.rs | 1 + 4 files changed, 4 insertions(+) diff --git a/tests/compile-fail/panic1.rs b/tests/compile-fail/panic1.rs index ff499316920f..4a1bb11483ca 100644 --- a/tests/compile-fail/panic1.rs +++ b/tests/compile-fail/panic1.rs @@ -1,3 +1,4 @@ +// ignore-test: Abort panics are not yet supported // error-pattern: the evaluated program panicked // compile-flags: -C panic=abort fn main() { diff --git a/tests/compile-fail/panic2.rs b/tests/compile-fail/panic2.rs index 3b36db2d2d81..ce4471c0effc 100644 --- a/tests/compile-fail/panic2.rs +++ b/tests/compile-fail/panic2.rs @@ -1,3 +1,4 @@ +// ignore-test: Abort panics are not yet supported // error-pattern: the evaluated program panicked // compile-flags: -C panic=abort diff --git a/tests/compile-fail/panic3.rs b/tests/compile-fail/panic3.rs index 6f5d6c3e1ce3..842a0f5435b7 100644 --- a/tests/compile-fail/panic3.rs +++ b/tests/compile-fail/panic3.rs @@ -1,3 +1,4 @@ +// ignore-test: Abort panics are not yet supported //error-pattern: the evaluated program panicked // compile-flags: -C panic=abort diff --git a/tests/compile-fail/panic4.rs b/tests/compile-fail/panic4.rs index 22d675375ac4..816cc90cfabd 100644 --- a/tests/compile-fail/panic4.rs +++ b/tests/compile-fail/panic4.rs @@ -1,3 +1,4 @@ +// ignore-test: Abort panics are not yet supported //error-pattern: the evaluated program panicked // compile-flags: -C panic=abort From b5235dea7f3252087569361f07ae0bab71e5ae8d Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 17 Nov 2019 11:09:16 -0500 Subject: [PATCH 1319/5092] Add #[should_panic] test --- test-cargo-miri/tests/test.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index cfbe3f6d7fb6..bc00cb6a765c 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -41,3 +41,9 @@ fn entropy_rng() { fn num_cpus() { assert_eq!(num_cpus::get(), 1); } + +#[test] +#[should_panic] +fn do_panic() { // In large, friendly letters :) + panic!("Explicit panic from test!"); +} From 660cd55cc74a6c391cf817d771181eeaa736967b Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 17 Nov 2019 11:49:31 -0500 Subject: [PATCH 1320/5092] Update captured test output --- test-cargo-miri/test.stdout.ref | 5 +++-- test-cargo-miri/test.stdout.ref2 | 2 +- test-cargo-miri/test.stdout.ref3 | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/test-cargo-miri/test.stdout.ref b/test-cargo-miri/test.stdout.ref index c2257e68e256..827e2f93237b 100644 --- a/test-cargo-miri/test.stdout.ref +++ b/test-cargo-miri/test.stdout.ref @@ -5,11 +5,12 @@ test test::rng ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out -running 4 tests +running 5 tests +test do_panic ... ok test entropy_rng ... ok test num_cpus ... ok test simple1 ... ok test simple2 ... ok -test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/test.stdout.ref2 b/test-cargo-miri/test.stdout.ref2 index a6f6e915e0e8..e070941c36ec 100644 --- a/test-cargo-miri/test.stdout.ref2 +++ b/test-cargo-miri/test.stdout.ref2 @@ -7,5 +7,5 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out running 1 test test simple1 ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 3 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 4 filtered out diff --git a/test-cargo-miri/test.stdout.ref3 b/test-cargo-miri/test.stdout.ref3 index f0d8afbd0e8e..a4a1a7812aea 100644 --- a/test-cargo-miri/test.stdout.ref3 +++ b/test-cargo-miri/test.stdout.ref3 @@ -7,5 +7,5 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out running 1 test test num_cpus ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 3 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 4 filtered out From 80f9484c8680e54a31916d6410a5eea2ddb1e237 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 17 Nov 2019 13:47:06 -0500 Subject: [PATCH 1321/5092] Disable panic tests on Windows Miri currently does not support `GetProcAddress` and `GetModuleHandleW`, both of which end up getting invoked by the libstd panic hook. --- tests/run-pass/catch_panic.rs | 1 + tests/run-pass/panic1.rs | 1 + tests/run-pass/panic1.stderr | 2 +- tests/run-pass/panic2.rs | 1 + tests/run-pass/panic2.stderr | 2 +- 5 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/catch_panic.rs b/tests/run-pass/catch_panic.rs index 8e254385d474..228317e89369 100644 --- a/tests/run-pass/catch_panic.rs +++ b/tests/run-pass/catch_panic.rs @@ -1,3 +1,4 @@ +// ignore-windows: Unwind panicking does not currently work on Windows use std::panic::catch_unwind; use std::cell::Cell; diff --git a/tests/run-pass/panic1.rs b/tests/run-pass/panic1.rs index b9bb52b95b13..261db018d6da 100644 --- a/tests/run-pass/panic1.rs +++ b/tests/run-pass/panic1.rs @@ -1,3 +1,4 @@ +// ignore-windows: Unwind panicking does not currently work on Windows fn main() { panic!("Miri panic!"); } diff --git a/tests/run-pass/panic1.stderr b/tests/run-pass/panic1.stderr index a29ba479825a..b1607dd864fb 100644 --- a/tests/run-pass/panic1.stderr +++ b/tests/run-pass/panic1.stderr @@ -1 +1 @@ -thread 'main' panicked at 'Miri panic!', $DIR/panic1.rs:2:5 +thread 'main' panicked at 'Miri panic!', $DIR/panic1.rs:3:5 diff --git a/tests/run-pass/panic2.rs b/tests/run-pass/panic2.rs index 9a1da6656c26..deaf606d9a2e 100644 --- a/tests/run-pass/panic2.rs +++ b/tests/run-pass/panic2.rs @@ -1,3 +1,4 @@ +// ignore-windows: Unwind panicking does not currently work on Windows fn main() { let val = "Value".to_string(); panic!("Miri panic with value: {}", val); diff --git a/tests/run-pass/panic2.stderr b/tests/run-pass/panic2.stderr index de70fd4d583e..bc5df83ec0f0 100644 --- a/tests/run-pass/panic2.stderr +++ b/tests/run-pass/panic2.stderr @@ -1 +1 @@ -thread 'main' panicked at 'Miri panic with value: Value', $DIR/panic2.rs:3:5 +thread 'main' panicked at 'Miri panic with value: Value', $DIR/panic2.rs:4:5 From 52b18b44f9032d0e311ca09a84956734a76ae53d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Nov 2019 15:10:17 +0100 Subject: [PATCH 1322/5092] bump compiletest; remove unused feature --- Cargo.lock | 12 ++++++------ Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c930566c86a5..bc122e3debd7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -157,7 +157,7 @@ dependencies = [ [[package]] name = "compiletest_rs" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -172,7 +172,7 @@ dependencies = [ "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tester 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tester 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -347,7 +347,7 @@ dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "compiletest_rs 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)", + "compiletest_rs 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", "directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -700,7 +700,7 @@ dependencies = [ [[package]] name = "tester" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -819,7 +819,7 @@ dependencies = [ "checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6cdb90b60f2927f8d76139c72dbde7e10c3a2bc47c8594c9c7a66529f2687c03" -"checksum compiletest_rs 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f75b10a18fb53549fdd090846eb01c7f8593914494d1faabc4d3005c436e417a" +"checksum compiletest_rs 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)" = "d7d8975604ebad8b6660796802377eb6495045c5606168fc1b8d19a4dd9bfa46" "checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120" "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" "checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" @@ -882,7 +882,7 @@ dependencies = [ "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" -"checksum tester 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cd0d1044cb5ca390e9c93f8c35abd2c55484397dfd786f189321aa34605ee6ab" +"checksum tester 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7647e6d732eb84375d8e7abda37818f81861ddbfc7235e33f4983cb254b71e4f" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" diff --git a/Cargo.toml b/Cargo.toml index 8a09bb7ac178..01516d358913 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,5 +59,5 @@ cargo_miri = ["cargo_metadata", "directories", "rustc_version"] rustc_tests = [] [dev-dependencies] -compiletest_rs = { version = "0.3.24", features = ["tmp", "stable"] } +compiletest_rs = { version = "0.3.26", features = ["tmp"] } colored = "1.6" From 82374ad9bd73178947348206bc7ed463b5a8a982 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Nov 2019 14:51:08 +0100 Subject: [PATCH 1323/5092] comments and slight refactoring --- rust-version | 2 +- src/helpers.rs | 1 + src/machine.rs | 9 ++-- src/shims/foreign_items.rs | 18 +++---- src/shims/intrinsics.rs | 2 +- src/shims/panic.rs | 106 ++++++++++++++++++------------------- 6 files changed, 67 insertions(+), 71 deletions(-) diff --git a/rust-version b/rust-version index 0d6f14df928c..093065aab2c0 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8831d766ace89bc74714918a7d9fbd3ca5ec946a +3e525e3f6d9e85d54fa4c49b52df85aa0c990100 diff --git a/src/helpers.rs b/src/helpers.rs index cff78859df8d..20f21cfc255c 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -53,6 +53,7 @@ fn resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> InterpResult<'tc pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + /// Gets an instance for a path. fn resolve_path(&self, path: &[&str]) -> InterpResult<'tcx, ty::Instance<'tcx>> { Ok(ty::Instance::mono(self.eval_context_ref().tcx.tcx, resolve_did(self.eval_context_ref().tcx.tcx, path)?)) } diff --git a/src/machine.rs b/src/machine.rs index 8910c589ee70..cb6581703571 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -25,10 +25,11 @@ pub const NUM_CPUS: u64 = 1; pub struct FrameData<'tcx> { /// Extra data for Stacked Borrows. pub call_id: stacked_borrows::CallId, - /// If this is Some(), then this is a special 'catch unwind' - /// frame. When this frame is popped during unwinding a panic, - /// we stop unwinding, and use the `CatchUnwindData` to - /// store the panic payload and continue execution in the parent frame. + + /// If this is Some(), then this is a special "catch unwind" frame (the frame of the closure + /// called by `__rustc_maybe_catch_panic`). When this frame is popped during unwinding a panic, + /// we stop unwinding, use the `CatchUnwindData` to + /// store the panic payload, and continue execution in the parent frame. pub catch_panic: Option>, } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 781c5ad40f93..3a95ffd78e31 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -130,27 +130,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // First: functions that diverge. match link_name { - // Note that this matches calls to the *foreign* item "__rust_start_panic" - - // that is, calls `extern "Rust" { fn __rust_start_panic(...) }` - // We forward this to the underlying *implementation* in "libpanic_unwind" + // Note that this matches calls to the *foreign* item `__rust_start_panic* - + // that is, calls to `extern "Rust" { fn __rust_start_panic(...) }`. + // We forward this to the underlying *implementation* in "libpanic_unwind". "__rust_start_panic" => { let start_panic_instance = this.resolve_path(&["panic_unwind", "__rust_start_panic"])?; return Ok(Some(this.load_mir(start_panic_instance.def, None)?)); } - - // During a normal (non-Miri) compilation, - // this gets resolved to the '#[panic_handler]` function at link time, - // which corresponds to the function with the `#[panic_handler]` attribute. - // - // Since we're interpreting mir, we forward it to the implementation of `panic_impl` - // - // This is used by libcore to forward panics to the actual - // panic impl + // Similarly, we forward calls to the `panic_impl` foreign item to its implementation. + // The implementation is provided by the function with the `#[panic_handler]` attribute. "panic_impl" => { let panic_impl_id = this.tcx.lang_items().panic_impl().unwrap(); let panic_impl_instance = ty::Instance::mono(*this.tcx, panic_impl_id); return Ok(Some(this.load_mir(panic_impl_instance.def, None)?)); } + "exit" | "ExitProcess" => { // it's really u32 for ExitProcess, but we have to put it into the `Exit` error variant anyway let code = this.read_scalar(args[0])?.to_i32()?; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 0e7314c1809f..5e1f3cff1c77 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -45,7 +45,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Handle non-diverging intrinsics // The intrinsic itself cannot diverge (otherwise, we would have handled it above), - // so if we got here without a return place... (can happen e.g., for transmute returning `!`) + // so if we got here without a return place that's UB (can happen e.g., for transmute returning `!`). let dest = match dest { Some(dest) => dest, None => throw_ub!(Unreachable) diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 3e0dd767d823..9c5c32491915 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -1,3 +1,16 @@ +//! Panic runtime for Miri. +//! +//! The core pieces of the runtime are: +//! - An implementation of `__rust_maybe_catch_panic` that pushes the invoked stack frame with +//! some extra metadata derived from the panic-catching arguments of `__rust_maybe_catch_panic`. +//! - A hack in `libpanic_unwind` that calls the `miri_start_panic` intrinsic instead of the +//! target-native panic runtime. (This lives in the rustc repo.) +//! - An implementation of `miri_start_panic` that stores its argument (the panic payload), and then +//! immediately returns, but on the *unwind* edge (not the normal return edge), thus initiating unwinding. +//! - A hook executed each time a frame is popped, such that if the frame pushed by `__rust_maybe_catch_panic` +//! gets popped *during unwinding*, we take the panic payload and store it according to the extra +//! metadata we remembered when pushing said frame. + use rustc::mir; use crate::*; use super::machine::FrameData; @@ -5,29 +18,25 @@ use rustc_target::spec::PanicStrategy; use crate::rustc_target::abi::LayoutOf; /// Holds all of the relevant data for a call to -/// __rust_maybe_catch_panic +/// `__rust_maybe_catch_panic`. /// /// If a panic occurs, we update this data with -/// the information from the panic site +/// the information from the panic site. #[derive(Debug)] pub struct CatchUnwindData<'tcx> { - /// The 'data' argument passed to `__rust_maybe_catch_panic` - pub data: Pointer, - /// The `data_ptr` argument passed to `__rust_maybe_catch_panic` + /// The dereferenced `data_ptr` argument passed to `__rust_maybe_catch_panic`. pub data_place: MPlaceTy<'tcx, Tag>, - /// The `vtable_ptr` argument passed to `__rust_maybe_catch_panic` + /// The dereferenced `vtable_ptr` argument passed to `__rust_maybe_catch_panic`. pub vtable_place: MPlaceTy<'tcx, Tag>, - /// The `dest` from the original call to `__rust_maybe_catch_panic` + /// The `dest` from the original call to `__rust_maybe_catch_panic`. pub dest: PlaceTy<'tcx, Tag>, - /// The `ret` from the original call to `__rust_maybe_catch_panic` - pub ret: mir::BasicBlock, } impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Handles the special "miri_start_panic" intrinsic, which is called - /// by libpanic_unwind to delegate the actual unwinding process to Miri + /// by libpanic_unwind to delegate the actual unwinding process to Miri. #[inline(always)] fn handle_miri_start_panic( &mut self, @@ -44,14 +53,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("the evaluated program panicked"); } - // Get the raw pointer stored in arg[0] + // Get the raw pointer stored in arg[0] (the panic payload). let scalar = this.read_immediate(args[0])?; + assert!(this.machine.panic_payload.is_none(), "the panic runtime should avoid double-panics"); this.machine.panic_payload = Some(scalar); - // Jump to the unwind block to begin unwinding - // We don't use 'goto_block' - if `unwind` is None, - // we'll end up immediately returning out of the - // function during the next step() call + // Jump to the unwind block to begin unwinding. + // We don't use `goto_block` as that is just meant for normal returns. let next_frame = this.frame_mut(); next_frame.block = unwind; next_frame.stmt = 0; @@ -74,16 +82,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // data_ptr: *mut usize, // vtable_ptr: *mut usize, // ) -> u32 + + // Get all the arguments. let f = this.read_scalar(args[0])?.not_undef()?; - let data = this.read_scalar(args[1])?.not_undef()?; + let f_arg = this.read_scalar(args[1])?.not_undef()?; let data_place = this.deref_operand(args[2])?; let vtable_place = this.deref_operand(args[3])?; + + // Now we make a function call, and pass `f_arg` as first and only argument. let f_instance = this.memory.get_fn(f)?.as_instance()?; - this.write_null(dest)?; trace!("__rust_maybe_catch_panic: {:?}", f_instance); - - - // Now we make a function call. // TODO: consider making this reusable? `InterpCx::step` does something similar // for the TLS destructors, and of course `eval_main`. let mir = this.load_mir(f_instance.def, None)?; @@ -98,32 +106,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx StackPopCleanup::Goto { ret: Some(ret), unwind: None }, )?; + let mut args = this.frame().body.args_iter(); + // First argument. + let arg_local = args + .next() + .expect("Argument to __rust_maybe_catch_panic does not take enough arguments."); + let arg_dest = this.local_place(arg_local)?; + this.write_scalar(f_arg, arg_dest)?; + // No more arguments. + args.next().expect_none("__rust_maybe_catch_panic argument has more arguments than expected"); + + // We ourselves will return `0`, eventually (will be overwritten if we catch a panic). + this.write_null(dest)?; + // In unwind mode, we tag this frame with some extra data. // This lets `handle_stack_pop` (below) know that we should stop unwinding // when we pop this frame. if this.tcx.tcx.sess.panic_strategy() == PanicStrategy::Unwind { this.frame_mut().extra.catch_panic = Some(CatchUnwindData { - data: data.to_ptr()?, data_place, vtable_place, dest, - ret, }) } - let mut args = this.frame().body.args_iter(); - - let arg_local = args - .next() - .expect("Argument to __rust_maybe_catch_panic does not take enough arguments."); - let arg_dest = this.local_place(arg_local)?; - this.write_scalar(data, arg_dest)?; - - args.next().expect_none("__rust_maybe_catch_panic argument has more arguments than expected"); - - // We ourselves will return `0`, eventually (because we will not return if we paniced). - this.write_null(dest)?; - return Ok(()); } @@ -140,33 +146,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We only care about `catch_panic` if we're unwinding - if we're doing a normal // return, then we don't need to do anything special. let res = if let (true, Some(unwind_data)) = (unwinding, extra.catch_panic.take()) { - // We've just popped the frame that was immediately above - // the frame which originally called `__rust_maybe_catch_panic` - trace!("unwinding: found catch_panic frame: {:?}", this.frame().span); + // We've just popped a frame that was pushed by `__rust_maybe_catch_panic`, + // and we are unwinding, so we should catch that. + trace!("unwinding: found catch_panic frame during unwinding: {:?}", this.frame().span); - // `panic_payload` now holds a '*mut (dyn Any + Send)', + // `panic_payload` now holds a `*mut (dyn Any + Send)`, // provided by the `miri_start_panic` intrinsic. // We want to split this into its consituient parts - - // the data and vtable pointers - and store them back - // into the panic handler frame - let real_ret = this.machine.panic_payload.take().unwrap(); - - let payload = this.ref_to_mplace(real_ret)?; + // the data and vtable pointers - and store them according to + // `unwind_data`, i.e., we store them where `__rust_maybe_catch_panic` + // was told to put them. + let payload = this.machine.panic_payload.take().unwrap(); + let payload = this.ref_to_mplace(payload)?; let payload_data_place = payload.ptr; let payload_vtable_place = payload.meta.expect("Expected fat pointer"); - - let data_place = unwind_data.data_place; - let vtable_place = unwind_data.vtable_place; - let dest = unwind_data.dest; - - // Here, we write to the pointers provided to the call - // to '__rust_maybe_catch_panic`. - this.write_scalar(payload_data_place, data_place.into())?; - this.write_scalar(payload_vtable_place, vtable_place.into())?; + this.write_scalar(payload_data_place, unwind_data.data_place.into())?; + this.write_scalar(payload_vtable_place, unwind_data.vtable_place.into())?; // We set the return value of `__rust_maybe_catch_panic` to 1, // since there was a panic. + let dest = unwind_data.dest; this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; StackPopInfo::StopUnwinding From 8936d67e7f7a6ab1318e6179ac3b839ffb47b430 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 19 Nov 2019 10:11:25 -0500 Subject: [PATCH 1324/5092] Delegate to the actual panic runtime crate --- src/shims/foreign_items.rs | 3 ++- src/shims/panic.rs | 7 ------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 3a95ffd78e31..130c5d28fff3 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -134,7 +134,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // that is, calls to `extern "Rust" { fn __rust_start_panic(...) }`. // We forward this to the underlying *implementation* in "libpanic_unwind". "__rust_start_panic" => { - let start_panic_instance = this.resolve_path(&["panic_unwind", "__rust_start_panic"])?; + let panic_runtime = tcx.crate_name(tcx.injected_panic_runtime().expect("No panic runtime found!")); + let start_panic_instance = this.resolve_path(&[&*panic_runtime.as_str(), "__rust_start_panic"])?; return Ok(Some(this.load_mir(start_panic_instance.def, None)?)); } // Similarly, we forward calls to the `panic_impl` foreign item to its implementation. diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 9c5c32491915..ef9843056a08 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -47,13 +47,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("miri_start_panic: {:?}", this.frame().span); - if this.tcx.tcx.sess.panic_strategy() == PanicStrategy::Abort { - // FIXME: Add a better way of indicating 'abnormal' termination, - // since this is not really an 'unsupported' behavior - throw_unsup_format!("the evaluated program panicked"); - } - - // Get the raw pointer stored in arg[0] (the panic payload). let scalar = this.read_immediate(args[0])?; assert!(this.machine.panic_payload.is_none(), "the panic runtime should avoid double-panics"); this.machine.panic_payload = Some(scalar); From a4eb34b3e1e93df4a5ab7645a480bbcffd8b71ef Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Nov 2019 20:40:06 +0100 Subject: [PATCH 1325/5092] generalize readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6d0173aaf04e..5a85b6d47855 100644 --- a/README.md +++ b/README.md @@ -61,8 +61,8 @@ rustup component add miri If `rustup` says the `miri` component is unavailable, that's because not all nightly releases come with all tools. Check out [this website](https://rust-lang.github.io/rustup-components-history) to -determine a nightly version that comes with Miri and install that, e.g. using -`rustup install nightly-2019-03-28`. +determine a nightly version that comes with Miri and install that using +`rustup install nightly-YYYY-MM-DD`. Now you can run your project in Miri: From e02dc4af4bf3104574f5fe96f1b51cb27f65c508 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 19 Nov 2019 15:31:37 -0500 Subject: [PATCH 1326/5092] Re-add comment --- src/shims/panic.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shims/panic.rs b/src/shims/panic.rs index ef9843056a08..59ff1a870d10 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -47,6 +47,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("miri_start_panic: {:?}", this.frame().span); + // Get the raw pointer stored in arg[0] (the panic payload). let scalar = this.read_immediate(args[0])?; assert!(this.machine.panic_payload.is_none(), "the panic runtime should avoid double-panics"); this.machine.panic_payload = Some(scalar); From 2750f60d4f4c8090bd0d0230c074fc7d1e2b5a6e Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 19 Nov 2019 15:33:14 -0500 Subject: [PATCH 1327/5092] Update panic runtime comment --- src/shims/foreign_items.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 130c5d28fff3..48d98141b8ad 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -132,7 +132,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Note that this matches calls to the *foreign* item `__rust_start_panic* - // that is, calls to `extern "Rust" { fn __rust_start_panic(...) }`. - // We forward this to the underlying *implementation* in "libpanic_unwind". + // We forward this to the underlying *implementation* in the panic runtime crate. + // Normally, this will be either `libpanic_unwind` or `libpanic_abort`, but it could + // also be a custom user-provided implementation via `#![feature(panic_runtime)]` "__rust_start_panic" => { let panic_runtime = tcx.crate_name(tcx.injected_panic_runtime().expect("No panic runtime found!")); let start_panic_instance = this.resolve_path(&[&*panic_runtime.as_str(), "__rust_start_panic"])?; From 6fe89e45f44df216911de48958aed38965b0de1c Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 19 Nov 2019 15:55:12 -0500 Subject: [PATCH 1328/5092] Disable #[should_panic] test on Windows We should re-enable this once https://github.com/rust-lang/miri/issues/1059 is fixed --- test-cargo-miri/tests/test.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index bc00cb6a765c..5d1beaec9806 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -42,8 +42,13 @@ fn num_cpus() { assert_eq!(num_cpus::get(), 1); } + +// FIXME: Remove this `cfg` once we fix https://github.com/rust-lang/miri/issues/1059 +// We cfg-gate the `should_panic` attribute and the `panic!` itself, so that the test +// stdout does not depend on the platform #[test] -#[should_panic] +#[cfg_attr(not(windows), should_panic)] fn do_panic() { // In large, friendly letters :) + #[cfg(not(windows))] panic!("Explicit panic from test!"); } From 5cef4666e6bd1e2c447fb262c5a6830147a73491 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Nov 2019 22:44:07 +0100 Subject: [PATCH 1329/5092] rename panic=abort tests to panic_abort --- tests/compile-fail/{panic1.rs => panic_abort1.rs} | 0 tests/compile-fail/{panic2.rs => panic_abort2.rs} | 0 tests/compile-fail/{panic3.rs => panic_abort3.rs} | 0 tests/compile-fail/{panic4.rs => panic_abort4.rs} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename tests/compile-fail/{panic1.rs => panic_abort1.rs} (100%) rename tests/compile-fail/{panic2.rs => panic_abort2.rs} (100%) rename tests/compile-fail/{panic3.rs => panic_abort3.rs} (100%) rename tests/compile-fail/{panic4.rs => panic_abort4.rs} (100%) diff --git a/tests/compile-fail/panic1.rs b/tests/compile-fail/panic_abort1.rs similarity index 100% rename from tests/compile-fail/panic1.rs rename to tests/compile-fail/panic_abort1.rs diff --git a/tests/compile-fail/panic2.rs b/tests/compile-fail/panic_abort2.rs similarity index 100% rename from tests/compile-fail/panic2.rs rename to tests/compile-fail/panic_abort2.rs diff --git a/tests/compile-fail/panic3.rs b/tests/compile-fail/panic_abort3.rs similarity index 100% rename from tests/compile-fail/panic3.rs rename to tests/compile-fail/panic_abort3.rs diff --git a/tests/compile-fail/panic4.rs b/tests/compile-fail/panic_abort4.rs similarity index 100% rename from tests/compile-fail/panic4.rs rename to tests/compile-fail/panic_abort4.rs From 2532b86a3b89acaff5c7793d69bc159de8ddd214 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 19 Nov 2019 17:25:09 -0500 Subject: [PATCH 1330/5092] Propagate the return code from the `start` lang item Fixes #1064 This ensures that we set the error code properly when a panic unwinds past `main`. I'm not sure what the best way to write a test for this is --- src/eval.rs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 7203ba6bf1db..3dad5a0d8c73 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -11,7 +11,7 @@ use syntax::source_map::DUMMY_SP; use crate::{ EnvVars, Evaluator, FnVal, HelpersEvalContextExt, InterpCx, InterpError, InterpResult, MemoryExtra, MiriMemoryKind, Pointer, Scalar, StackPopCleanup, Tag, - TlsEvalContextExt, + TlsEvalContextExt, MPlaceTy }; /// Configuration needed to spawn a Miri instance. @@ -34,7 +34,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig, -) -> InterpResult<'tcx, InterpCx<'mir, 'tcx, Evaluator<'tcx>>> { +) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'tcx>>, MPlaceTy<'tcx, Tag>)> { let mut ecx = InterpCx::new( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), @@ -170,12 +170,12 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?; ecx.machine.last_error = Some(errno_place); - Ok(ecx) + Ok((ecx, ret_ptr)) } pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) { - let mut ecx = match create_ecx(tcx, main_id, config) { - Ok(ecx) => ecx, + let (mut ecx, ret_ptr) = match create_ecx(tcx, main_id, config) { + Ok(v) => v, Err(mut err) => { err.print_backtrace(); panic!("Miri initialziation error: {}", err.kind) @@ -183,14 +183,18 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) { }; // Perform the main execution. - let res: InterpResult<'_> = (|| { + let res: InterpResult<'_, i64> = (|| { ecx.run()?; - ecx.run_tls_dtors() + // Read the return code pointer *before* we run TLS destructors, to assert + // that it was written to by the time that `start` lang item returned. + let return_code = ecx.read_scalar(ret_ptr.into())?.not_undef()?.to_machine_isize(&ecx)?; + ecx.run_tls_dtors()?; + Ok(return_code) })(); // Process the result. match res { - Ok(()) => { + Ok(return_code) => { let leaks = ecx.memory.leak_report(); // Disable the leak test on some platforms where we do not // correctly implement TLS destructors. @@ -199,6 +203,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) { if !ignore_leaks && leaks != 0 { tcx.sess.err("the evaluated program leaked memory"); } + std::process::exit(return_code as i32); } Err(mut e) => { // Special treatment for some error kinds From 310212931666421636286d223ca88841b26011c2 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 20 Nov 2019 12:43:10 -0500 Subject: [PATCH 1331/5092] Improve return code propagation. Don't explicitly exit if we reported an evaluation error --- src/bin/miri.rs | 5 ++++- src/eval.rs | 19 +++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 481491ea722f..9e95e4b0a466 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -15,6 +15,7 @@ extern crate rustc_interface; extern crate syntax; use std::str::FromStr; +use std::convert::TryFrom; use std::env; use hex::FromHexError; @@ -39,7 +40,9 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { // Add filename to `miri` arguments. config.args.insert(0, compiler.input().filestem().to_string()); - miri::eval_main(tcx, entry_def_id, config); + if let Some(return_code) = miri::eval_main(tcx, entry_def_id, config) { + std::process::exit(i32::try_from(return_code).expect("Return value was too large!")); + } }); compiler.session().abort_if_errors(); diff --git a/src/eval.rs b/src/eval.rs index 3dad5a0d8c73..603c30feb9f4 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -29,7 +29,10 @@ pub struct MiriConfig { pub seed: Option, } -// Used by priroda. +/// Returns a freshly created `InterpCx`, along with an `MPlaceTy` representing +/// the location where the return value of the `start` lang item will be +/// written to. +/// Used by `priroda` and `miri pub fn create_ecx<'mir, 'tcx: 'mir>( tcx: TyCtxt<'tcx>, main_id: DefId, @@ -173,7 +176,10 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( Ok((ecx, ret_ptr)) } -pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) { +/// Evaluates the main function specified by `main_id`. +/// Returns `Some(return_code)` if program executed completed. +/// Returns `None` if an evaluation error occured +pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option { let (mut ecx, ret_ptr) = match create_ecx(tcx, main_id, config) { Ok(v) => v, Err(mut err) => { @@ -202,13 +208,16 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) { let ignore_leaks = target_os == "windows" || target_os == "macos"; if !ignore_leaks && leaks != 0 { tcx.sess.err("the evaluated program leaked memory"); + // Ignore the provided return code - let the reported error + // determine the return code + return None; } - std::process::exit(return_code as i32); + return Some(return_code) } Err(mut e) => { // Special treatment for some error kinds let msg = match e.kind { - InterpError::Exit(code) => std::process::exit(code), + InterpError::Exit(code) => return Some(code.into()), err_unsup!(NoMirFor(..)) => format!("{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", e), _ => e.to_string() @@ -251,6 +260,8 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) { trace!(" local {}: {:?}", i, local.value); } } + // Let the reported error determine the return code + return None; } } } From f16f891191b3d61df3d23c49b122e12cad7e09d9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Nov 2019 19:38:41 +0100 Subject: [PATCH 1332/5092] slice matching overflow got fixed --- rust-version | 2 +- tests/run-pass/issue-17877.rs | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index 093065aab2c0..cb6136f40fb6 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -3e525e3f6d9e85d54fa4c49b52df85aa0c990100 +b9cf5417892ef242c783ef963deff5436205b0f6 diff --git a/tests/run-pass/issue-17877.rs b/tests/run-pass/issue-17877.rs index 9cbc459ad038..d2806e5ed350 100644 --- a/tests/run-pass/issue-17877.rs +++ b/tests/run-pass/issue-17877.rs @@ -1,14 +1,11 @@ -//ignore-windows: Causes a stack overflow?!? Likely a rustc bug: https://github.com/rust-lang/rust/issues/53820 -//FIXME: Once that bug is fixed, increase the size to 16*1024 and enable on all platforms. - #![feature(slice_patterns)] fn main() { - assert_eq!(match [0u8; 1024] { + assert_eq!(match [0u8; 16*1024] { _ => 42_usize, }, 42_usize); - assert_eq!(match [0u8; 1024] { + assert_eq!(match [0u8; 16*1024] { [1, ..] => 0_usize, [0, ..] => 1_usize, _ => 2_usize From 2176bf6cf04bea76d9a1c85a8418fb9b91d17dfa Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 20 Nov 2019 13:52:04 -0500 Subject: [PATCH 1333/5092] Fix nits Co-Authored-By: Ralf Jung --- src/eval.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 603c30feb9f4..237ef99d1fe6 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -32,7 +32,7 @@ pub struct MiriConfig { /// Returns a freshly created `InterpCx`, along with an `MPlaceTy` representing /// the location where the return value of the `start` lang item will be /// written to. -/// Used by `priroda` and `miri +/// Public because this is also used by `priroda`. pub fn create_ecx<'mir, 'tcx: 'mir>( tcx: TyCtxt<'tcx>, main_id: DefId, @@ -178,7 +178,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( /// Evaluates the main function specified by `main_id`. /// Returns `Some(return_code)` if program executed completed. -/// Returns `None` if an evaluation error occured +/// Returns `None` if an evaluation error occured. pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option { let (mut ecx, ret_ptr) = match create_ecx(tcx, main_id, config) { Ok(v) => v, @@ -209,7 +209,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> if !ignore_leaks && leaks != 0 { tcx.sess.err("the evaluated program leaked memory"); // Ignore the provided return code - let the reported error - // determine the return code + // determine the return code. return None; } return Some(return_code) @@ -260,7 +260,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> trace!(" local {}: {:?}", i, local.value); } } - // Let the reported error determine the return code + // Let the reported error determine the return code. return None; } } From a328683c4ae15137235f0b48a5d803a76343e810 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 21 Nov 2019 17:33:30 -0500 Subject: [PATCH 1334/5092] Add acos, asin, and atan foreign functions I copied the tests from the docs pages --- src/shims/foreign_items.rs | 10 ++++++++-- tests/run-pass/intrinsics-math.rs | 9 +++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 48d98141b8ad..5edabf215667 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -496,7 +496,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // math functions - "cbrtf" | "coshf" | "sinhf" | "tanf" => { + "cbrtf" | "coshf" | "sinhf" | "tanf" | "acosf" | "asinf" | "atanf" => { // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); let f = match link_name { @@ -504,6 +504,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "coshf" => f.cosh(), "sinhf" => f.sinh(), "tanf" => f.tan(), + "acosf" => f.acos(), + "asinf" => f.asin(), + "atanf" => f.atan(), _ => bug!(), }; this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?; @@ -521,7 +524,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_u32(n.to_bits()), dest)?; } - "cbrt" | "cosh" | "sinh" | "tan" => { + "cbrt" | "cosh" | "sinh" | "tan" | "acos" | "asin" | "atan" => { // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); let f = match link_name { @@ -529,6 +532,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "cosh" => f.cosh(), "sinh" => f.sinh(), "tan" => f.tan(), + "acos" => f.acos(), + "asin" => f.asin(), + "atan" => f.atan(), _ => bug!(), }; this.write_scalar(Scalar::from_u64(f.to_bits()), dest)?; diff --git a/tests/run-pass/intrinsics-math.rs b/tests/run-pass/intrinsics-math.rs index f435611b2b69..98cb87ee9342 100644 --- a/tests/run-pass/intrinsics-math.rs +++ b/tests/run-pass/intrinsics-math.rs @@ -92,6 +92,15 @@ pub fn main() { assert_approx_eq!(1.0f32.tan(), 1.557408f32); assert_approx_eq!(1.0f64.tan(), 1.557408f64); + assert_approx_eq!(f32::consts::FRAC_PI_4.cos().acos(), f32::consts::FRAC_PI_4); + assert_approx_eq!(f64::consts::FRAC_PI_4.cos().acos(), f64::consts::FRAC_PI_4); + + assert_approx_eq!(f32::consts::FRAC_PI_4.sin().asin(), f32::consts::FRAC_PI_4); + assert_approx_eq!(f64::consts::FRAC_PI_4.sin().asin(), f64::consts::FRAC_PI_4); + + assert_approx_eq!(1.0_f32, 1.0_f32.tan().atan()); + assert_approx_eq!(1.0_f64, 1.0_f64.tan().atan()); + assert_eq!(3.3_f32.round(), 3.0); assert_eq!(3.3_f64.round(), 3.0); From 6888555ca91f8e729b84da13da20d886919489b3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 22 Nov 2019 09:50:22 +0100 Subject: [PATCH 1335/5092] rustup for never stabilization --- rust-version | 2 +- tests/compile-fail/never_say_never.rs | 1 - tests/compile-fail/never_transmute_humans.rs | 2 -- tests/compile-fail/never_transmute_void.rs | 1 - tests/run-pass/async-fn.rs | 2 -- tests/run-pass/generator.rs | 2 +- tests/run-pass/loop-break-value.rs | 1 - 7 files changed, 2 insertions(+), 9 deletions(-) diff --git a/rust-version b/rust-version index cb6136f40fb6..09cac5bb059f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -b9cf5417892ef242c783ef963deff5436205b0f6 +bd816fd76f4f7a040ca7ac8ca5bc556d761f96fa diff --git a/tests/compile-fail/never_say_never.rs b/tests/compile-fail/never_say_never.rs index d7e6a8c09f64..199ceb70fb6b 100644 --- a/tests/compile-fail/never_say_never.rs +++ b/tests/compile-fail/never_say_never.rs @@ -1,7 +1,6 @@ // This should fail even without validation // compile-flags: -Zmiri-disable-validation -#![feature(never_type)] #![allow(unreachable_code)] fn main() { diff --git a/tests/compile-fail/never_transmute_humans.rs b/tests/compile-fail/never_transmute_humans.rs index ab25b1ffc746..f662fdcd9872 100644 --- a/tests/compile-fail/never_transmute_humans.rs +++ b/tests/compile-fail/never_transmute_humans.rs @@ -1,8 +1,6 @@ // This should fail even without validation // compile-flags: -Zmiri-disable-validation -#![feature(never_type)] - struct Human; fn main() { diff --git a/tests/compile-fail/never_transmute_void.rs b/tests/compile-fail/never_transmute_void.rs index a5d6795d71e7..933e05211956 100644 --- a/tests/compile-fail/never_transmute_void.rs +++ b/tests/compile-fail/never_transmute_void.rs @@ -1,7 +1,6 @@ // This should fail even without validation // compile-flags: -Zmiri-disable-validation -#![feature(never_type)] #![allow(unused, invalid_value)] enum Void {} diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 90448aca1779..a4c176ad8f12 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -1,5 +1,3 @@ -#![feature(never_type)] - use std::{future::Future, pin::Pin, task::Poll, ptr}; use std::task::{Waker, RawWaker, RawWakerVTable, Context}; diff --git a/tests/run-pass/generator.rs b/tests/run-pass/generator.rs index c31b5b9ed3bb..00ebba6344e2 100644 --- a/tests/run-pass/generator.rs +++ b/tests/run-pass/generator.rs @@ -1,4 +1,4 @@ -#![feature(generators, generator_trait, never_type)] +#![feature(generators, generator_trait)] use std::ops::{GeneratorState, Generator}; use std::pin::Pin; diff --git a/tests/run-pass/loop-break-value.rs b/tests/run-pass/loop-break-value.rs index bd7afa7ec1a8..43acdc228202 100644 --- a/tests/run-pass/loop-break-value.rs +++ b/tests/run-pass/loop-break-value.rs @@ -1,4 +1,3 @@ -#![feature(never_type)] #![allow(unreachable_code)] #[allow(unused)] From 6941caf1df5e38d47bfec16353c0ef6eeceb9aa8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 22 Nov 2019 18:12:10 +0100 Subject: [PATCH 1336/5092] typo --- .../compile-fail/stacked_borrows/deallocate_against_barrier2.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.rs b/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.rs index db4d2d998dbd..9c0c59d364f2 100644 --- a/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.rs +++ b/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.rs @@ -2,7 +2,7 @@ use std::cell::Cell; -// Check that even `&Cell` are dereferencable. +// Check that even `&Cell` are dereferenceable. // Also see . fn inner(x: &Cell, f: fn(&Cell)) { // `f` may mutate, but it may not deallocate! From 5339d541efa7245a17fabe8992065ff9d444f5a4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Nov 2019 10:33:49 +0100 Subject: [PATCH 1337/5092] cargo-miri: also find Rust sources when being run in a locally built, linked toolchain --- src/bin/cargo-miri.rs | 52 ++++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 36545766d101..f4fb13518e30 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -270,19 +270,44 @@ fn setup(ask_user: bool) { ask_to_run(cmd, ask_user, "install a recent enough xargo"); } - // Then, unless `XARGO_RUST_SRC` is set, we also need rust-src. - // Let's see if it is already installed. - if std::env::var("XARGO_RUST_SRC").is_err() { - let sysroot = Command::new("rustc").args(&["--print", "sysroot"]).output() - .expect("failed to get rustc sysroot") - .stdout; - let sysroot = std::str::from_utf8(&sysroot).unwrap(); - let src = Path::new(sysroot.trim_end_matches('\n')).join("lib").join("rustlib").join("src"); - if !src.exists() { - let mut cmd = Command::new("rustup"); - cmd.args(&["component", "add", "rust-src"]); - ask_to_run(cmd, ask_user, "install the rustc-src component for the selected toolchain"); + // Determine where the rust sources are located. `XARGO_RUST_SRC` env var trumps everything. + let rust_src = match std::env::var("XARGO_RUST_SRC") { + Ok(val) => PathBuf::from(val), + Err(_) => { + // Check for `rust-src` rustup component. + let sysroot = Command::new("rustc").args(&["--print", "sysroot"]).output() + .expect("failed to get rustc sysroot") + .stdout; + let sysroot = std::str::from_utf8(&sysroot).unwrap(); + let sysroot = Path::new(sysroot.trim_end_matches('\n')); + // First try: `$SYSROOT/lib/rustlib/src/rust`; test if that contains `Cargo.lock`. + let rustup_src = sysroot.join("lib").join("rustlib").join("src").join("rust"); + let base_dir = if rustup_src.join("Cargo.lock").exists() { + // Just use this. + rustup_src + } else { + // Maybe this is a local toolchain built with `x.py` and linked into `rustup`? + // Second try: `$SYSROOT/../../..`; test if that contains `x.py`. + let local_src = sysroot.parent().and_then(Path::parent).and_then(Path::parent); + match local_src { + Some(local_src) if local_src.join("x.py").exists() => { + // Use this. + PathBuf::from(local_src) + } + _ => { + // Fallback: Ask the user to install the `rust-src` component, and use that. + let mut cmd = Command::new("rustup"); + cmd.args(&["component", "add", "rust-src"]); + ask_to_run(cmd, ask_user, "install the rustc-src component for the selected toolchain"); + rustup_src + } + } + }; + base_dir.join("src") // Xargo wants the src-subdir } + }; + if !rust_src.exists() { + show_error(format!("Given Rust source directory `{}` does not exist.", rust_src.display())); } // Next, we need our own libstd. We will do this work in whatever is a good cache dir for this platform. @@ -321,7 +346,8 @@ path = "lib.rs" command.arg("build").arg("-q"); command.current_dir(&dir); command.env("RUSTFLAGS", miri::miri_default_args().join(" ")); - command.env("XARGO_HOME", dir.to_str().unwrap()); + command.env("XARGO_HOME", &dir); + command.env("XARGO_RUST_SRC", &rust_src); // In bootstrap, make sure we don't get debug assertons into our libstd. command.env("RUSTC_DEBUG_ASSERTIONS", "false"); // Handle target flag. From 274e72996eb36f815f34cf5593eaed4f314a1b2a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Nov 2019 10:36:23 +0100 Subject: [PATCH 1338/5092] miri script does not need to handle locally built rustc any more --- miri | 5 ----- 1 file changed, 5 deletions(-) diff --git a/miri b/miri index c3d7ae0280c7..f1eae220e0de 100755 --- a/miri +++ b/miri @@ -65,16 +65,11 @@ find_sysroot() { return 0 fi # We need to build a sysroot. - if echo "$SYSROOT" | egrep -q 'build/[^/]+/stage'; then - # A local rustc build. Use its source dir. - export XARGO_RUST_SRC="$SYSROOT/../../../src" - fi if [ -n "$MIRI_TEST_TARGET" ]; then build_sysroot --target "$MIRI_TEST_TARGET" else build_sysroot fi - export MIRI_SYSROOT } ## Main From ee411c2a74c9d9876c1ac5e03a300456e3caa6bb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 Nov 2019 10:24:41 +0100 Subject: [PATCH 1339/5092] beef up catch_panic test --- tests/run-pass/catch_panic.rs | 69 +++++++++++++++++++++---------- tests/run-pass/catch_panic.stderr | 7 ++++ tests/run-pass/panic1.rs | 4 -- tests/run-pass/panic1.stderr | 1 - tests/run-pass/panic2.rs | 5 --- tests/run-pass/panic2.stderr | 1 - 6 files changed, 55 insertions(+), 32 deletions(-) create mode 100644 tests/run-pass/catch_panic.stderr delete mode 100644 tests/run-pass/panic1.rs delete mode 100644 tests/run-pass/panic1.stderr delete mode 100644 tests/run-pass/panic2.rs delete mode 100644 tests/run-pass/panic2.stderr diff --git a/tests/run-pass/catch_panic.rs b/tests/run-pass/catch_panic.rs index 228317e89369..4d1f9a850489 100644 --- a/tests/run-pass/catch_panic.rs +++ b/tests/run-pass/catch_panic.rs @@ -1,5 +1,5 @@ // ignore-windows: Unwind panicking does not currently work on Windows -use std::panic::catch_unwind; +use std::panic::{catch_unwind, AssertUnwindSafe}; use std::cell::Cell; thread_local! { @@ -18,7 +18,7 @@ impl Drop for DropTester { } } -fn do_panic_counter() { +fn do_panic_counter(do_panic: impl FnOnce(usize) -> !) { // If this gets leaked, it will be easy to spot // in Miri's leak report let _string = "LEAKED FROM do_panic_counter".to_string(); @@ -28,35 +28,62 @@ fn do_panic_counter() { // Check for bugs in Miri's panic implementation. // If do_panic_counter() somehow gets called more than once, - // we'll generate a different panic message + // we'll generate a different panic message and stderr will differ. let old_val = MY_COUNTER.with(|c| { let val = c.get(); c.set(val + 1); val }); - panic!(format!("Hello from panic: {:?}", old_val)); + do_panic(old_val); } fn main() { - std::panic::set_hook(Box::new(|_panic_info| { + let prev = std::panic::take_hook(); + std::panic::set_hook(Box::new(move |panic_info| { HOOK_CALLED.with(|h| h.set(true)); + prev(panic_info) })); - let res = catch_unwind(|| { - let _string = "LEAKED FROM CLOSURE".to_string(); - do_panic_counter() - }); - let expected: Box = Box::new("Hello from panic: 0".to_string()); - let actual = res.expect_err("do_panic() did not panic!") - .downcast::().expect("Failed to cast to string!"); - - assert_eq!(expected, actual); - DROPPED.with(|c| { - // This should have been set to 'true' by DropTester - assert!(c.get()); - }); - HOOK_CALLED.with(|h| { - assert!(h.get()); - }); + test(|_old_val| panic!("Hello from panic: std")); + test(|old_val| panic!(format!("Hello from panic: {:?}", old_val))); + test(|old_val| panic!("Hello from panic: {:?}", old_val)); + // FIXME https://github.com/rust-lang/miri/issues/1071 + //test(|_old_val| core::panic!("Hello from panic: core")); + //test(|old_val| core::panic!(&format!("Hello from panic: {:?}", old_val))); + //test(|old_val| core::panic!("Hello from panic: {:?}", old_val)); + + // Cleanup: reset to default hook. + drop(std::panic::take_hook()); + + eprintln!("Success!"); // Make sure we get this in stderr +} + +fn test(do_panic: impl FnOnce(usize) -> !) { + // Reset test flags. + DROPPED.with(|c| c.set(false)); + HOOK_CALLED.with(|c| c.set(false)); + + // Cause and catch a panic. + let res = catch_unwind(AssertUnwindSafe(|| { + let _string = "LEAKED FROM CLOSURE".to_string(); + do_panic_counter(do_panic) + })).expect_err("do_panic() did not panic!"); + + // See if we can extract panic message. + match res.downcast::() { + Ok(s) => { + eprintln!("Caught panic message (String): {}", s); + } + Err(res) => + if let Ok(s) = res.downcast::<&str>() { + eprintln!("Caught panic message (&str): {}", s); + } else { + eprintln!("Failed get caught panic message."); + } + } + + // Test flags. + assert!(DROPPED.with(|c| c.get())); + assert!(HOOK_CALLED.with(|c| c.get())); } diff --git a/tests/run-pass/catch_panic.stderr b/tests/run-pass/catch_panic.stderr new file mode 100644 index 000000000000..f6e545655907 --- /dev/null +++ b/tests/run-pass/catch_panic.stderr @@ -0,0 +1,7 @@ +thread 'main' panicked at 'Hello from panic: std', $DIR/catch_panic.rs:47:21 +Caught panic message (&str): Hello from panic: std +thread 'main' panicked at 'Hello from panic: 1', $DIR/catch_panic.rs:48:20 +Caught panic message (String): Hello from panic: 1 +thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:49:20 +Caught panic message (String): Hello from panic: 2 +Success! diff --git a/tests/run-pass/panic1.rs b/tests/run-pass/panic1.rs deleted file mode 100644 index 261db018d6da..000000000000 --- a/tests/run-pass/panic1.rs +++ /dev/null @@ -1,4 +0,0 @@ -// ignore-windows: Unwind panicking does not currently work on Windows -fn main() { - panic!("Miri panic!"); -} diff --git a/tests/run-pass/panic1.stderr b/tests/run-pass/panic1.stderr deleted file mode 100644 index b1607dd864fb..000000000000 --- a/tests/run-pass/panic1.stderr +++ /dev/null @@ -1 +0,0 @@ -thread 'main' panicked at 'Miri panic!', $DIR/panic1.rs:3:5 diff --git a/tests/run-pass/panic2.rs b/tests/run-pass/panic2.rs deleted file mode 100644 index deaf606d9a2e..000000000000 --- a/tests/run-pass/panic2.rs +++ /dev/null @@ -1,5 +0,0 @@ -// ignore-windows: Unwind panicking does not currently work on Windows -fn main() { - let val = "Value".to_string(); - panic!("Miri panic with value: {}", val); -} diff --git a/tests/run-pass/panic2.stderr b/tests/run-pass/panic2.stderr deleted file mode 100644 index bc5df83ec0f0..000000000000 --- a/tests/run-pass/panic2.stderr +++ /dev/null @@ -1 +0,0 @@ -thread 'main' panicked at 'Miri panic with value: Value', $DIR/panic2.rs:4:5 From 35e1fe16652c7e7490d54fbf7f764b0676378456 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 Nov 2019 10:51:48 +0100 Subject: [PATCH 1340/5092] also test non-string panic payload --- tests/run-pass/catch_panic.rs | 1 + tests/run-pass/catch_panic.stderr | 2 ++ 2 files changed, 3 insertions(+) diff --git a/tests/run-pass/catch_panic.rs b/tests/run-pass/catch_panic.rs index 4d1f9a850489..c504956db35a 100644 --- a/tests/run-pass/catch_panic.rs +++ b/tests/run-pass/catch_panic.rs @@ -47,6 +47,7 @@ fn main() { test(|_old_val| panic!("Hello from panic: std")); test(|old_val| panic!(format!("Hello from panic: {:?}", old_val))); test(|old_val| panic!("Hello from panic: {:?}", old_val)); + test(|_old_val| panic!(1337)); // FIXME https://github.com/rust-lang/miri/issues/1071 //test(|_old_val| core::panic!("Hello from panic: core")); //test(|old_val| core::panic!(&format!("Hello from panic: {:?}", old_val))); diff --git a/tests/run-pass/catch_panic.stderr b/tests/run-pass/catch_panic.stderr index f6e545655907..6d905da7febe 100644 --- a/tests/run-pass/catch_panic.stderr +++ b/tests/run-pass/catch_panic.stderr @@ -4,4 +4,6 @@ thread 'main' panicked at 'Hello from panic: 1', $DIR/catch_panic.rs:48:20 Caught panic message (String): Hello from panic: 1 thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:49:20 Caught panic message (String): Hello from panic: 2 +thread 'main' panicked at 'Box', $DIR/catch_panic.rs:50:21 +Failed get caught panic message. Success! From 51d47e8dc5a94d60ea0ef321cf81544d2908a216 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 Nov 2019 15:01:05 +0100 Subject: [PATCH 1341/5092] test closure-to-fn-ptr coercions a bit more --- .../run-pass/non_capture_closure_to_fn_ptr.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/non_capture_closure_to_fn_ptr.rs b/tests/run-pass/non_capture_closure_to_fn_ptr.rs index e6a5017847d4..d404daef2c7c 100644 --- a/tests/run-pass/non_capture_closure_to_fn_ptr.rs +++ b/tests/run-pass/non_capture_closure_to_fn_ptr.rs @@ -5,7 +5,8 @@ static FOO: fn() = || { assert_ne!(42, 43) }; static BAR: fn(i32, i32) = |a, b| { assert_ne!(a, b) }; // use to first make the closure FnOnce() before making it fn() -fn magic(f: F) -> F { f } +fn magic0 R>(f: F) -> F { f } +fn magic1 R>(f: F) -> F { f } fn main() { FOO(); @@ -15,6 +16,20 @@ fn main() { let boo: &dyn Fn(i32, i32) = &BAR; boo(48, 49); - let f = magic(||{}) as fn(); + let f: fn() = ||{}; f(); + let f = magic0(||{}) as fn(); + f(); + + let g: fn(i32) = |i| assert_eq!(i, 2); + g(2); + let g = magic1(|i| assert_eq!(i, 2)) as fn(i32); + g(2); + + // FIXME: This fails with "invalid use of NULL pointer" + //let h: fn() -> ! = || std::process::exit(0); + //h(); + // FIXME: This does not even compile?!? + //let h = magic0(|| std::process::exit(0)) as fn() -> !; + //h(); } From d16e12b0a4b3b525c2aaac7af05a1494f4d3a7bc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 Nov 2019 15:08:24 +0100 Subject: [PATCH 1342/5092] rename test and add some references --- ...re_to_fn_ptr.rs => coerce_non_capture_closure_to_fn_ptr.rs} | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) rename tests/run-pass/{non_capture_closure_to_fn_ptr.rs => coerce_non_capture_closure_to_fn_ptr.rs} (83%) diff --git a/tests/run-pass/non_capture_closure_to_fn_ptr.rs b/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs similarity index 83% rename from tests/run-pass/non_capture_closure_to_fn_ptr.rs rename to tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs index d404daef2c7c..30e1768837eb 100644 --- a/tests/run-pass/non_capture_closure_to_fn_ptr.rs +++ b/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs @@ -29,7 +29,8 @@ fn main() { // FIXME: This fails with "invalid use of NULL pointer" //let h: fn() -> ! = || std::process::exit(0); //h(); - // FIXME: This does not even compile?!? + // FIXME: This does not even compile?!? //let h = magic0(|| std::process::exit(0)) as fn() -> !; //h(); + // Once these tests pass, they should be in separate files as they terminate the process. } From 66dc939787d7b5df2bc4866ab69fe7cc4d980307 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 Nov 2019 15:08:47 +0100 Subject: [PATCH 1343/5092] rename some more tests --- tests/run-pass/{mir_coercions.rs => coercions.rs} | 0 tests/run-pass/{mir_fat_ptr.rs => fat_ptr.rs} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename tests/run-pass/{mir_coercions.rs => coercions.rs} (100%) rename tests/run-pass/{mir_fat_ptr.rs => fat_ptr.rs} (100%) diff --git a/tests/run-pass/mir_coercions.rs b/tests/run-pass/coercions.rs similarity index 100% rename from tests/run-pass/mir_coercions.rs rename to tests/run-pass/coercions.rs diff --git a/tests/run-pass/mir_fat_ptr.rs b/tests/run-pass/fat_ptr.rs similarity index 100% rename from tests/run-pass/mir_fat_ptr.rs rename to tests/run-pass/fat_ptr.rs From 2152258b04ba3eb2f7f560ff7b793fb277d29077 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 Nov 2019 15:10:39 +0100 Subject: [PATCH 1344/5092] and another reference --- tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs b/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs index 30e1768837eb..4da2c0c61b4a 100644 --- a/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs +++ b/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs @@ -26,7 +26,7 @@ fn main() { let g = magic1(|i| assert_eq!(i, 2)) as fn(i32); g(2); - // FIXME: This fails with "invalid use of NULL pointer" + // FIXME: This fails with "invalid use of NULL pointer" //let h: fn() -> ! = || std::process::exit(0); //h(); // FIXME: This does not even compile?!? From e2fd9d83e202cbf54c48ab97713d8d797065f188 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 26 Nov 2019 14:28:56 +0100 Subject: [PATCH 1345/5092] cargo update --- Cargo.lock | 188 +++++++++++++++++------------------------------------ Cargo.toml | 2 +- 2 files changed, 62 insertions(+), 128 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bc122e3debd7..0ccbaaaabec2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,11 +8,6 @@ dependencies = [ "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "approx" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "arrayref" version = "0.3.5" @@ -20,11 +15,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "arrayvec" -version = "0.4.12" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "atty" @@ -56,7 +48,7 @@ name = "backtrace-sys" version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -75,11 +67,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "blake2b_simd" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -102,14 +94,14 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cc" -version = "1.0.46" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -117,24 +109,13 @@ name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "cgmath" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "chrono" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -148,31 +129,32 @@ dependencies = [ [[package]] name = "colored" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winconsole 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "compiletest_rs" -version = "0.3.26" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustfix 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tester 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tester 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -252,13 +234,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "filetime" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -282,7 +264,7 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -346,14 +328,14 @@ version = "0.1.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "compiletest_rs 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", + "colored 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "compiletest_rs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -361,31 +343,18 @@ dependencies = [ "vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "num-integer" version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-traits" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -417,24 +386,12 @@ dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rand" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rand" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -468,7 +425,7 @@ name = "rand_core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -540,18 +497,13 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rgb" -version = "0.8.14" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "rust-argon2" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2b_simd 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -580,8 +532,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -595,7 +547,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -605,30 +557,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.41" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -649,7 +601,7 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.5" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -659,12 +611,12 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -700,7 +652,7 @@ dependencies = [ [[package]] name = "tester" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -742,7 +694,7 @@ version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -787,39 +739,26 @@ dependencies = [ "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "winconsole" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rgb 0.8.14 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [metadata] "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" -"checksum approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08abcc3b4e9339e33a3d0a5ed15d84a687350c05689d825e0f6655eef9e76a94" "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" -"checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" +"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" "checksum backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea" "checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -"checksum blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "5850aeee1552f495dd0250014cf64b82b7c8879a89d83b33bbdace2cc4f63182" +"checksum blake2b_simd 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b83b7baab1e671718d78204225800d6b170e648188ac7dc992e9d6bddf87d0c0" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" "checksum cargo_metadata 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8d2d1617e838936c0d2323a65cc151e03ae19a7678dd24f72bccf27119b90a5d" -"checksum cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)" = "0213d356d3c4ea2c18c40b037c3be23cd639825c18f25ee670ac7813beeef99c" +"checksum cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)" = "aa87058dce70a3ff5621797f1506cb837edd02ac4c0ae642b4542dce802908b8" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64a4b57c8f4e3a2e9ac07e0f6abc9c24b6fc9e1b54c3478cfb598f3d0023e51c" -"checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68" +"checksum chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "31850b4a4d6bae316f7a09e691c944c28299298837edc0a03f755618c23cbc01" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6cdb90b60f2927f8d76139c72dbde7e10c3a2bc47c8594c9c7a66529f2687c03" -"checksum compiletest_rs 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)" = "d7d8975604ebad8b6660796802377eb6495045c5606168fc1b8d19a4dd9bfa46" +"checksum colored 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "433e7ac7d511768127ed85b0c4947f47a254131e37864b2dc13f52aa32cd37e5" +"checksum compiletest_rs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d7b678957210a00ba0fbeacc23d38cbfbf29895564da1616564634351e1dac5e" "checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120" "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" "checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" @@ -829,10 +768,10 @@ dependencies = [ "checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" "checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" "checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" -"checksum filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6bd7380b54ced79dda72ecc35cc4fbbd1da6bba54afaa37e96fd1c2a308cd469" +"checksum filetime 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1ff6d4dab0aa0c8e6346d46052e93b13a16cf847b54ed357087c35011048cc7d" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" -"checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" +"checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407" "checksum hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "023b39be39e3a2da62a94feb433e91e8bcd37676fbc8bea371daf52b7a769a3e" "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" @@ -841,15 +780,12 @@ dependencies = [ "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" "checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226" -"checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" "checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" -"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" -"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" +"checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4" "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" "checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" -"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" "checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" @@ -863,7 +799,6 @@ dependencies = [ "checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" "checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" -"checksum rgb 0.8.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2089e4031214d129e201f8c3c8c2fe97cd7322478a0d1cdf78e7029b0042efdb" "checksum rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf" "checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" "checksum rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" @@ -872,17 +807,17 @@ dependencies = [ "checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd" -"checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e" -"checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2" +"checksum serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "1217f97ab8e8904b57dd22eb61cde455fa7446a9c1cf43966066da047c1f3702" +"checksum serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "a8c6faef9a2e64b0064f48570289b4bf8823b7581f1d6157c1b52152306651d0" +"checksum serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)" = "1a3351dcbc1f067e2c92ab7c3c1f288ad1a4cffc470b5aaddb4c2e0a3ae80043" "checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9" "checksum socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e8b74de517221a2cb01a53349cf54182acdc31a074727d3079068448c0676d85" -"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" -"checksum synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203" +"checksum syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "661641ea2aa15845cddeb97dad000d22070bb5c1fb456b96c1cba883ec691e92" +"checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" -"checksum tester 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7647e6d732eb84375d8e7abda37818f81861ddbfc7235e33f4983cb254b71e4f" +"checksum tester 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee72ec31009a42b53de9a6b7d8f462b493ab3b1e4767bda1fcdbb52127f13b6c" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" @@ -894,4 +829,3 @@ dependencies = [ "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9" -"checksum winconsole 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ef84b96d10db72dd980056666d7f1e7663ce93d82fa33b63e71c966f4cf5032" diff --git a/Cargo.toml b/Cargo.toml index 01516d358913..ac62d29eb8fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,5 +59,5 @@ cargo_miri = ["cargo_metadata", "directories", "rustc_version"] rustc_tests = [] [dev-dependencies] -compiletest_rs = { version = "0.3.26", features = ["tmp"] } +compiletest_rs = { version = "0.4", features = ["tmp"] } colored = "1.6" From 824328c6d5d76d3db86045da7ca606789696d4f9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 Nov 2019 22:48:31 +0100 Subject: [PATCH 1346/5092] adjust for goto_block refactoring --- src/machine.rs | 16 +++++++--------- src/shims/dlsym.rs | 9 +++------ src/shims/foreign_items.rs | 17 ++++++++--------- src/shims/intrinsics.rs | 27 +++++++++++++-------------- src/shims/mod.rs | 11 +++++------ src/shims/panic.rs | 5 +---- 6 files changed, 37 insertions(+), 48 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index cb6581703571..c40532914198 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -186,11 +186,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx: &mut InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], - dest: Option>, - ret: Option, + ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { - ecx.find_fn(instance, args, dest, ret, unwind) + ecx.find_fn(instance, args, ret, unwind) } #[inline(always)] @@ -198,10 +197,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx: &mut InterpCx<'mir, 'tcx, Self>, fn_val: Dlsym, args: &[OpTy<'tcx, Tag>], - dest: Option>, - ret: Option, + ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + _unwind: Option, ) -> InterpResult<'tcx> { - ecx.call_dlsym(fn_val, args, dest, ret) + ecx.call_dlsym(fn_val, args, ret) } #[inline(always)] @@ -210,11 +209,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { span: Span, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], - dest: Option>, - ret: Option, + ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, ) -> InterpResult<'tcx> { - ecx.call_intrinsic(span, instance, args, dest, ret, unwind) + ecx.call_intrinsic(span, instance, args, ret, unwind) } #[inline(always)] diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index ca53f5d23015..dfee4066da1b 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -27,15 +27,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, dlsym: Dlsym, args: &[OpTy<'tcx, Tag>], - dest: Option>, - ret: Option, + ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, ) -> InterpResult<'tcx> { use self::Dlsym::*; let this = self.eval_context_mut(); - - let dest = dest.expect("we don't support any diverging dlsym"); - let ret = ret.expect("dest is `Some` but ret is `None`"); + let (dest, ret) = ret.expect("we don't support any diverging dlsym"); match dlsym { GetEntropy => { @@ -46,8 +43,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - this.goto_block(Some(ret))?; this.dump_place(*dest); + this.go_to_block(ret); Ok(()) } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 5edabf215667..b136260f751e 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -114,8 +114,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, def_id: DefId, args: &[OpTy<'tcx, Tag>], - dest: Option>, - ret: Option, + ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, _unwind: Option ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); @@ -129,7 +128,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tcx = &{ this.tcx.tcx }; // First: functions that diverge. - match link_name { + let (dest, ret) = match link_name { // Note that this matches calls to the *foreign* item `__rust_start_panic* - // that is, calls to `extern "Rust" { fn __rust_start_panic(...) }`. // We forward this to the underlying *implementation* in the panic runtime crate. @@ -154,15 +153,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Err(InterpError::Exit(code).into()); } _ => { - if dest.is_none() { + if let Some(p) = ret { + p + } else { throw_unsup_format!("can't call (diverging) foreign function: {}", link_name); } } - } + }; - // Next: functions that assume a ret and dest. - let dest = dest.expect("we already checked for a dest"); - let ret = ret.expect("dest is `Some` but ret is `None`"); + // Next: functions that return. match link_name { "malloc" => { let size = this.read_scalar(args[0])?.to_machine_usize(this)?; @@ -928,8 +927,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => throw_unsup_format!("can't call foreign function: {}", link_name), } - this.goto_block(Some(ret))?; this.dump_place(*dest); + this.go_to_block(ret); Ok(None) } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 5e1f3cff1c77..00886328030b 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -16,12 +16,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx span: Span, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], - dest: Option>, - _ret: Option, + ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - if this.emulate_intrinsic(span, instance, args, dest)? { + if this.emulate_intrinsic(span, instance, args, ret)? { return Ok(()); } let tcx = &{this.tcx.tcx}; @@ -32,23 +31,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // that might still hang around! let intrinsic_name = &*tcx.item_name(instance.def_id()).as_str(); - // Handle diverging intrinsics - match intrinsic_name { + // Handle diverging intrinsics. + let (dest, ret) = match intrinsic_name { "abort" => { // FIXME: Add a better way of indicating 'abnormal' termination, // since this is not really an 'unsupported' behavior throw_unsup_format!("the evaluated program aborted!"); } "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), - _ => {} - } - - // Handle non-diverging intrinsics - // The intrinsic itself cannot diverge (otherwise, we would have handled it above), - // so if we got here without a return place that's UB (can happen e.g., for transmute returning `!`). - let dest = match dest { - Some(dest) => dest, - None => throw_ub!(Unreachable) + _ => { + if let Some(p) = ret { + p + } else { + throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name); + } + } }; match intrinsic_name { @@ -581,6 +578,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name => throw_unsup_format!("unimplemented intrinsic: {}", name), } + this.dump_place(*dest); + this.go_to_block(ret); Ok(()) } } diff --git a/src/shims/mod.rs b/src/shims/mod.rs index f554c19f11c2..2e8aea3f86e0 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -16,25 +16,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], - dest: Option>, - ret: Option, + ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); trace!( "eval_fn_call: {:#?}, {:?}", instance, - dest.map(|place| *place) + ret.map(|p| *p.0) ); // There are some more lang items we want to hook that CTFE does not hook (yet). if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { - let dest = dest.unwrap(); + let (dest, ret) = ret.unwrap(); let n = this .align_offset(args[0], args[1])? .unwrap_or_else(|| this.truncate(u128::max_value(), dest.layout)); this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; - this.goto_block(ret)?; + this.go_to_block(ret); return Ok(None); } @@ -46,7 +45,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // to run extra MIR), and Ok(Some(body)) if we found MIR to run for the // foreign function // Any needed call to `goto_block` will be performed by `emulate_foreign_item`. - return this.emulate_foreign_item(instance.def_id(), args, dest, ret, unwind); + return this.emulate_foreign_item(instance.def_id(), args, ret, unwind); } // Otherwise, load the MIR. diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 59ff1a870d10..42028738822a 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -53,10 +53,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.panic_payload = Some(scalar); // Jump to the unwind block to begin unwinding. - // We don't use `goto_block` as that is just meant for normal returns. - let next_frame = this.frame_mut(); - next_frame.block = unwind; - next_frame.stmt = 0; + this.unwind_to_block(unwind); return Ok(()) } From fbc1fb20ac606dfcb6f91fb7823272760e583f85 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 27 Nov 2019 08:45:24 +0100 Subject: [PATCH 1347/5092] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 09cac5bb059f..b5ab3053c5cf 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -bd816fd76f4f7a040ca7ac8ca5bc556d761f96fa +809e180a76ce97340bf4354ff357bc59e3ca40b2 From a04620eb697eb064902d5c1b5f7584fa68a1bcfd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 27 Nov 2019 09:13:37 +0100 Subject: [PATCH 1348/5092] only run leak test on clean platforms --- src/eval.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 237ef99d1fe6..3524029475a9 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -201,16 +201,18 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> // Process the result. match res { Ok(return_code) => { - let leaks = ecx.memory.leak_report(); // Disable the leak test on some platforms where we do not // correctly implement TLS destructors. let target_os = ecx.tcx.tcx.sess.target.target.target_os.to_lowercase(); let ignore_leaks = target_os == "windows" || target_os == "macos"; - if !ignore_leaks && leaks != 0 { - tcx.sess.err("the evaluated program leaked memory"); - // Ignore the provided return code - let the reported error - // determine the return code. - return None; + if !ignore_leaks { + let leaks = ecx.memory.leak_report(); + if leaks != 0 { + tcx.sess.err("the evaluated program leaked memory"); + // Ignore the provided return code - let the reported error + // determine the return code. + return None; + } } return Some(return_code) } From fe76d33506f61695b54213b423efa14bbb280531 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 28 Nov 2019 23:42:10 +0100 Subject: [PATCH 1349/5092] Add and use helper function for calling a machine function and passing it some arguments --- src/eval.rs | 181 ++++++++++++++++++++------------------------- src/helpers.rs | 35 +++++++++ src/machine.rs | 31 +++----- src/shims/panic.rs | 21 +----- src/shims/tls.rs | 14 +--- 5 files changed, 131 insertions(+), 151 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 3524029475a9..488fdc3b37b1 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -6,13 +6,8 @@ use rand::SeedableRng; use rustc::hir::def_id::DefId; use rustc::ty::layout::{LayoutOf, Size}; use rustc::ty::{self, TyCtxt}; -use syntax::source_map::DUMMY_SP; -use crate::{ - EnvVars, Evaluator, FnVal, HelpersEvalContextExt, InterpCx, InterpError, - InterpResult, MemoryExtra, MiriMemoryKind, Pointer, Scalar, StackPopCleanup, Tag, - TlsEvalContextExt, MPlaceTy -}; +use crate::*; /// Configuration needed to spawn a Miri instance. #[derive(Clone)] @@ -65,107 +60,93 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))), ) .unwrap(); - let start_mir = ecx.load_mir(start_instance.def, None)?; - - if start_mir.arg_count != 3 { - bug!( - "'start' lang item should have three arguments, but has {}", - start_mir.arg_count - ); - } - - // Return value (in static memory so that it does not count as leak). - let ret = ecx.layout_of(start_mir.return_ty())?; - let ret_ptr = ecx.allocate(ret, MiriMemoryKind::Static.into()); - - // Push our stack frame. - ecx.push_stack_frame( - start_instance, - // There is no call site. - DUMMY_SP, - start_mir, - Some(ret_ptr.into()), - StackPopCleanup::None { cleanup: true }, - )?; - - let mut args = ecx.frame().body.args_iter(); // First argument: pointer to `main()`. let main_ptr = ecx .memory .create_fn_alloc(FnVal::Instance(main_instance)); - let dest = ecx.local_place(args.next().unwrap())?; - ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?; - // Second argument (argc): `1`. - let dest = ecx.local_place(args.next().unwrap())?; - let argc = Scalar::from_uint(config.args.len() as u128, dest.layout.size); - ecx.write_scalar(argc, dest)?; - // Store argc for macOS's `_NSGetArgc`. - { - let argc_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into()); - ecx.write_scalar(argc, argc_place.into())?; - ecx.machine.argc = Some(argc_place.ptr); - } - + let argc = Scalar::from_uint(config.args.len() as u128, ecx.pointer_size()); // Third argument (`argv`): created from `config.args`. - let dest = ecx.local_place(args.next().unwrap())?; - // For Windows, construct a command string with all the aguments. - let mut cmd = String::new(); - for arg in config.args.iter() { - if !cmd.is_empty() { - cmd.push(' '); + let argv = { + // For Windows, construct a command string with all the aguments (before we take apart `config.args`). + let mut cmd = String::new(); + for arg in config.args.iter() { + if !cmd.is_empty() { + cmd.push(' '); + } + cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into())); } - cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into())); - } - // Don't forget `0` terminator. - cmd.push(std::char::from_u32(0).unwrap()); - // Collect the pointers to the individual strings. - let mut argvs = Vec::>::new(); - for arg in config.args { - // Add `0` terminator. - let mut arg = arg.into_bytes(); - arg.push(0); - argvs.push( - ecx.memory - .allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Static.into()), - ); - } - // Make an array with all these pointers, in the Miri memory. - let argvs_layout = ecx.layout_of( - tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), argvs.len() as u64), - )?; - let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into()); - for (idx, arg) in argvs.into_iter().enumerate() { - let place = ecx.mplace_field(argvs_place, idx as u64)?; - ecx.write_scalar(Scalar::Ptr(arg), place.into())?; - } - ecx.memory - .mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?; - // Write a pointer to that place as the argument. - let argv = argvs_place.ptr; - ecx.write_scalar(argv, dest)?; - // Store `argv` for macOS `_NSGetArgv`. - { - let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into()); - ecx.write_scalar(argv, argv_place.into())?; - ecx.machine.argv = Some(argv_place.ptr); - } - // Store command line as UTF-16 for Windows `GetCommandLineW`. - { - let cmd_utf16: Vec = cmd.encode_utf16().collect(); - let cmd_type = tcx.mk_array(tcx.types.u16, cmd_utf16.len() as u64); - let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Env.into()); - ecx.machine.cmd_line = Some(cmd_place.ptr); - // Store the UTF-16 string. We just allocated so we know the bounds are fine. - let char_size = Size::from_bytes(2); - for (idx, &c) in cmd_utf16.iter().enumerate() { - let place = ecx.mplace_field(cmd_place, idx as u64)?; - ecx.write_scalar(Scalar::from_uint(c, char_size), place.into())?; + // Don't forget `0` terminator. + cmd.push(std::char::from_u32(0).unwrap()); + // Collect the pointers to the individual strings. + let mut argvs = Vec::>::new(); + for arg in config.args { + // Add `0` terminator. + let mut arg = arg.into_bytes(); + arg.push(0); + argvs.push( + ecx.memory + .allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Static.into()), + ); } - } + // Make an array with all these pointers, in the Miri memory. + let argvs_layout = ecx.layout_of( + tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), argvs.len() as u64), + )?; + let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into()); + for (idx, arg) in argvs.into_iter().enumerate() { + let place = ecx.mplace_field(argvs_place, idx as u64)?; + ecx.write_scalar(Scalar::Ptr(arg), place.into())?; + } + ecx.memory + .mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?; + // A pointer to that place is the argument. + let argv = argvs_place.ptr; + // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`. + { + let argc_place = ecx.allocate( + ecx.layout_of(tcx.types.isize)?, + MiriMemoryKind::Env.into(), + ); + ecx.write_scalar(argc, argc_place.into())?; + ecx.machine.argc = Some(argc_place.ptr); - args.next().expect_none("start lang item has more arguments than expected"); + let argv_place = ecx.allocate( + ecx.layout_of(tcx.mk_imm_ptr(tcx.types.unit))?, + MiriMemoryKind::Env.into(), + ); + ecx.write_scalar(argv, argv_place.into())?; + ecx.machine.argv = Some(argv_place.ptr); + } + // Store command line as UTF-16 for Windows `GetCommandLineW`. + { + let cmd_utf16: Vec = cmd.encode_utf16().collect(); + let cmd_type = tcx.mk_array(tcx.types.u16, cmd_utf16.len() as u64); + let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Env.into()); + ecx.machine.cmd_line = Some(cmd_place.ptr); + // Store the UTF-16 string. We just allocated so we know the bounds are fine. + let char_size = Size::from_bytes(2); + for (idx, &c) in cmd_utf16.iter().enumerate() { + let place = ecx.mplace_field(cmd_place, idx as u64)?; + ecx.write_scalar(Scalar::from_uint(c, char_size), place.into())?; + } + } + argv + }; + + // Return place (in static memory so that it does not count as leak). + let ret_place = ecx.allocate( + ecx.layout_of(tcx.types.isize)?, + MiriMemoryKind::Static.into(), + ); + // Call start function. + ecx.call_function( + start_instance, + &[main_ptr.into(), argc, argv], + Some(ret_place.into()), + StackPopCleanup::None { cleanup: true }, + )?; // Set the last_error to 0 let errno_layout = ecx.layout_of(tcx.types.u32)?; @@ -173,14 +154,14 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?; ecx.machine.last_error = Some(errno_place); - Ok((ecx, ret_ptr)) + Ok((ecx, ret_place)) } /// Evaluates the main function specified by `main_id`. /// Returns `Some(return_code)` if program executed completed. /// Returns `None` if an evaluation error occured. pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option { - let (mut ecx, ret_ptr) = match create_ecx(tcx, main_id, config) { + let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) { Ok(v) => v, Err(mut err) => { err.print_backtrace(); @@ -193,7 +174,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> ecx.run()?; // Read the return code pointer *before* we run TLS destructors, to assert // that it was written to by the time that `start` lang item returned. - let return_code = ecx.read_scalar(ret_ptr.into())?.not_undef()?.to_machine_isize(&ecx)?; + let return_code = ecx.read_scalar(ret_place.into())?.not_undef()?.to_machine_isize(&ecx)?; ecx.run_tls_dtors()?; Ok(return_code) })(); diff --git a/src/helpers.rs b/src/helpers.rs index 20f21cfc255c..28c31a07ef57 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,6 +1,7 @@ use std::{mem, iter}; use std::ffi::{OsStr, OsString}; +use syntax::source_map::DUMMY_SP; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc::ty::{ @@ -118,6 +119,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.memory.write_bytes(ptr, data.iter().copied()) } + /// Call a function: Push the stack frame and pass the arguments. + /// For now, arguments must be scalars (so that the caller does not have to know the layout). + fn call_function( + &mut self, + f: ty::Instance<'tcx>, + args: &[Scalar], + dest: Option>, + stack_pop: StackPopCleanup, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + // Push frame. + let mir = this.load_mir(f.def, None)?; + this.push_stack_frame( + f, + DUMMY_SP, // There is no call site. + mir, + dest, + stack_pop, + )?; + + // Initialize arguments. + let mut callee_args = this.frame().body.args_iter(); + for arg in args { + let callee_arg = this.local_place( + callee_args.next().expect("callee has fewer arguments than expected") + )?; + this.write_scalar(*arg, callee_arg)?; + } + callee_args.next().expect_none("callee has more arguments than expected"); + + Ok(()) + } + /// Visits the memory covered by `place`, sensitive to freezing: the 3rd parameter /// will be true if this is frozen, false if this is in an `UnsafeCell`. fn visit_freeze_sensitive( diff --git a/src/machine.rs b/src/machine.rs index c40532914198..94ddee6fc092 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -230,37 +230,26 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { trace!("box_alloc for {:?}", dest.layout.ty); + let layout = ecx.layout_of(dest.layout.ty.builtin_deref(false).unwrap().ty)?; + // First argument: `size`. + // (`0` is allowed here -- this is expected to be handled by the lang item). + let size = Scalar::from_uint(layout.size.bytes(), ecx.pointer_size()); + + // Second argument: `align`. + let align = Scalar::from_uint(layout.align.abi.bytes(), ecx.pointer_size()); + // Call the `exchange_malloc` lang item. let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap(); let malloc = ty::Instance::mono(ecx.tcx.tcx, malloc); - let malloc_mir = ecx.load_mir(malloc.def, None)?; - ecx.push_stack_frame( + ecx.call_function( malloc, - malloc_mir.span, - malloc_mir, + &[size, align], Some(dest), // Don't do anything when we are done. The `statement()` function will increment // the old stack frame's stmt counter to the next statement, which means that when // `exchange_malloc` returns, we go on evaluating exactly where we want to be. StackPopCleanup::None { cleanup: true }, )?; - - let mut args = ecx.frame().body.args_iter(); - let layout = ecx.layout_of(dest.layout.ty.builtin_deref(false).unwrap().ty)?; - - // First argument: `size`. - // (`0` is allowed here -- this is expected to be handled by the lang item). - let arg = ecx.local_place(args.next().unwrap())?; - let size = layout.size.bytes(); - ecx.write_scalar(Scalar::from_uint(size, arg.layout.size), arg)?; - - // Second argument: `align`. - let arg = ecx.local_place(args.next().unwrap())?; - let align = layout.align.abi.bytes(); - ecx.write_scalar(Scalar::from_uint(align, arg.layout.size), arg)?; - - // No more arguments. - args.next().expect_none("`exchange_malloc` lang item has more arguments than expected"); Ok(()) } diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 42028738822a..6cc9f176c8fa 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -37,7 +37,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Handles the special "miri_start_panic" intrinsic, which is called /// by libpanic_unwind to delegate the actual unwinding process to Miri. - #[inline(always)] fn handle_miri_start_panic( &mut self, args: &[OpTy<'tcx, Tag>], @@ -57,7 +56,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(()) } - #[inline(always)] fn handle_catch_panic( &mut self, args: &[OpTy<'tcx, Tag>], @@ -83,30 +81,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Now we make a function call, and pass `f_arg` as first and only argument. let f_instance = this.memory.get_fn(f)?.as_instance()?; trace!("__rust_maybe_catch_panic: {:?}", f_instance); - // TODO: consider making this reusable? `InterpCx::step` does something similar - // for the TLS destructors, and of course `eval_main`. - let mir = this.load_mir(f_instance.def, None)?; let ret_place = MPlaceTy::dangling(this.layout_of(tcx.mk_unit())?, this).into(); - this.push_stack_frame( + this.call_function( f_instance, - mir.span, - mir, + &[f_arg], Some(ret_place), // Directly return to caller. StackPopCleanup::Goto { ret: Some(ret), unwind: None }, )?; - let mut args = this.frame().body.args_iter(); - // First argument. - let arg_local = args - .next() - .expect("Argument to __rust_maybe_catch_panic does not take enough arguments."); - let arg_dest = this.local_place(arg_local)?; - this.write_scalar(f_arg, arg_dest)?; - // No more arguments. - args.next().expect_none("__rust_maybe_catch_panic argument has more arguments than expected"); - // We ourselves will return `0`, eventually (will be overwritten if we catch a panic). this.write_null(dest)?; @@ -124,7 +108,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(()); } - #[inline(always)] fn handle_stack_pop( &mut self, mut extra: FrameData<'tcx>, diff --git a/src/shims/tls.rs b/src/shims/tls.rs index b6aadd31a5be..ea8b0df230f2 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -146,22 +146,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx while let Some((instance, ptr, key)) = dtor { trace!("Running TLS dtor {:?} on {:?}", instance, ptr); assert!(!this.is_null(ptr).unwrap(), "Data can't be NULL when dtor is called!"); - // TODO: Potentially, this has to support all the other possible instances? - // See eval_fn_call in interpret/terminator/mod.rs - let mir = this.load_mir(instance.def, None)?; + let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); - this.push_stack_frame( + this.call_function( instance, - mir.span, - mir, + &[ptr], Some(ret_place), StackPopCleanup::None { cleanup: true }, )?; - let arg_local = this.frame().body.args_iter().next().ok_or_else( - || err_ub_format!("TLS dtor does not take enough arguments."), - )?; - let dest = this.local_place(arg_local)?; - this.write_scalar(ptr, dest)?; // step until out of stackframes this.run()?; From e5a81c6a2da299d13ab513d6328677caffc72cc4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 29 Nov 2019 11:08:27 +0100 Subject: [PATCH 1350/5092] fix comment --- src/eval.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/eval.rs b/src/eval.rs index 488fdc3b37b1..986c6143ab4d 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -65,7 +65,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let main_ptr = ecx .memory .create_fn_alloc(FnVal::Instance(main_instance)); - // Second argument (argc): `1`. + // Second argument (argc): length of `config.args`. let argc = Scalar::from_uint(config.args.len() as u128, ecx.pointer_size()); // Third argument (`argv`): created from `config.args`. let argv = { From 4a4886c0f07054e0367d90b461c11b1211b874ca Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 29 Nov 2019 21:37:59 +0100 Subject: [PATCH 1351/5092] avoid injected_panic_runtime which is going away --- src/shims/foreign_items.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index b136260f751e..b9e6734613c0 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -135,7 +135,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Normally, this will be either `libpanic_unwind` or `libpanic_abort`, but it could // also be a custom user-provided implementation via `#![feature(panic_runtime)]` "__rust_start_panic" => { - let panic_runtime = tcx.crate_name(tcx.injected_panic_runtime().expect("No panic runtime found!")); + // FIXME we might want to cache this... but it's not really performance-critical. + let panic_runtime = tcx.crates().iter() + .find(|cnum| tcx.is_panic_runtime(**cnum)) + .expect("No panic runtime found!"); + let panic_runtime = tcx.crate_name(*panic_runtime); let start_panic_instance = this.resolve_path(&[&*panic_runtime.as_str(), "__rust_start_panic"])?; return Ok(Some(this.load_mir(start_panic_instance.def, None)?)); } From c9b3b688d5121d155cb29df78d83ce1b9cc19a98 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 Nov 2019 10:06:12 +0100 Subject: [PATCH 1352/5092] add toolchain mgmt script --- CONTRIBUTING.md | 46 +++++++++++++++++++--------------------------- toolchain | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 27 deletions(-) create mode 100755 toolchain diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d6436873938e..9338f0b8dd73 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,6 +12,22 @@ on the [Rust Zulip]. [Rust Zulip]: https://rust-lang.zulipchat.com +## Building Miri with a pre-built rustc + +Miri heavily relies on internal rustc interfaces to execute MIR. Still, some +things (like adding support for a new intrinsic or a shim for an external +function being called) can be done by working just on the Miri side. + +The `rust-version` file contains the commit hash of rustc that Miri is currently +tested against. Other versions will likely not work. After installing +[`rustup-toolchain-install-master`], you can run the following command to +install that exact version of rustc as a toolchain: +``` +./toolchain +``` + +[`rustup-toolchain-install-master`]: https://github.com/kennytm/rustup-toolchain-install-master + ### Fixing Miri when rustc changes Miri is heavily tied to rustc internals, so it is very common that rustc changes @@ -20,36 +36,12 @@ Usually, Miri will require changes similar to the other consumers of the changed rustc API, so reading the rustc PR diff is a good way to get an idea for what is needed. -When submitting a PR against Miri after fixing it for rustc changes, make sure -you update the `rust-version` file. That file always contains the exact rustc -git commit with which Miri works, and it is the version that our CI tests Miri -against. - -## Building Miri with a nightly rustc - -Miri heavily relies on internal rustc interfaces to execute MIR. Still, some -things (like adding support for a new intrinsic or a shim for an external -function being called) can be done by working just on the Miri side. - -To prepare, make sure you are using a nightly Rust compiler. You also need to -have the `rust-src` and `rustc-dev` components installed, which you can add via -`rustup component add rust-src rustc-dev`. Then you should be able to just -`cargo build` Miri. - -In case this fails, your nightly might be incompatible with Miri master. The -`rust-version` file contains the commit hash of rustc that Miri is currently -tested against; you can use that to find a nightly that works or you might have -to wait for the next nightly to get released. You can also use -[`rustup-toolchain-install-master`](https://github.com/kennytm/rustup-toolchain-install-master) -to install that exact version of rustc as a toolchain: +To update the `rustc-version` file and install the latest rustc, you can run: ``` -rustup-toolchain-install-master $(cat rust-version) -c rust-src -c rustc-dev +./toolchain HEAD ``` -Another common problem is outdated dependencies: Miri does not come with a -lockfile (it cannot, due to how it gets embedded into the rustc build). So you -have to run `cargo update` every now and then yourself to make sure you are -using the latest versions of everything (which is what gets tested on CI). +Now try `./miri test`, and submit a PR once that works again. ## Testing the Miri driver [testing-miri]: #testing-the-miri-driver diff --git a/toolchain b/toolchain new file mode 100755 index 000000000000..043b2ee2edd7 --- /dev/null +++ b/toolchain @@ -0,0 +1,40 @@ +#!/bin/bash +set -e +# Manages a rustup toolchain called "miri". +# +# All commands set "miri" as the override toolchain for the current directory, +# and make the `rust-version` file match that toolchain. +# +# USAGE: +# +# ./toolchain: Update "miri" toolchain to match `rust-version` (the known-good version for this commit). +# +# ./toolchain HEAD: Update "miri" toolchain and `rust-version` file to latest rustc HEAD. +# +# ./toolchain $COMMIT: Update "miri" toolchain and `rust-version` file to match that commit. + +# Determine new commit. +if [[ "$1" == "" ]]; then + NEW_COMMIT=$(cat rust-version) +elif [[ "$1" == "HEAD" ]]; then + NEW_COMMIT=$(git ls-remote https://github.com/rust-lang/rust/ HEAD | cut -f 1) +else + NEW_COMMIT="$1" +fi +echo "$NEW_COMMIT" > rust-version + +# Check if we already are at that commit. +CUR_COMMIT=$(rustc +miri --version -v | egrep "^commit-hash: " | cut -d " " -f 2) +if [[ "$CUR_COMMIT" == "$NEW_COMMIT" ]]; then + echo "miri toolchain is already at commit $CUR_COMMIT." + rustup override set miri + exit 0 +fi + +# Cleanup. +cargo +nightly clean # Use nightly cargo as miri toolchain might be broken. +rustup toolchain uninstall miri + +# Install and setup new toolchain. +rustup-toolchain-install-master -n miri -c rust-src -c rustc-dev -- "$NEW_COMMIT" +rustup override set miri From 6363bc497529dbce3000ec213a8023112eebd512 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 Nov 2019 10:31:53 +0100 Subject: [PATCH 1353/5092] test should_panic checking the panic string --- test-cargo-miri/tests/test.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 5d1beaec9806..ce85f929049b 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -12,7 +12,7 @@ fn simple2() { assert_ne!(42, 24); } -// A test that won't work on miri (tests disabling tests) +// A test that won't work on miri (tests disabling tests). #[cfg(not(miri))] #[test] fn does_not_work_on_miri() { @@ -45,9 +45,9 @@ fn num_cpus() { // FIXME: Remove this `cfg` once we fix https://github.com/rust-lang/miri/issues/1059 // We cfg-gate the `should_panic` attribute and the `panic!` itself, so that the test -// stdout does not depend on the platform +// stdout does not depend on the platform. #[test] -#[cfg_attr(not(windows), should_panic)] +#[cfg_attr(not(windows), should_panic(expected="Explicit panic"))] fn do_panic() { // In large, friendly letters :) #[cfg(not(windows))] panic!("Explicit panic from test!"); From a971b8a2aec8cab720c51ef31f92b2246d83edd8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 Nov 2019 10:19:00 +0100 Subject: [PATCH 1354/5092] fix for GlobalCtxt changes --- benches/helpers/miri_helper.rs | 6 +++--- src/bin/miri-rustc-tests.rs | 6 +++--- src/bin/miri.rs | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index a4f559967204..95146513509b 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -7,7 +7,7 @@ extern crate test; use self::miri::eval_main; use rustc::hir::def_id::LOCAL_CRATE; -use rustc_interface::interface; +use rustc_interface::{interface, Queries}; use rustc_driver::Compilation; use crate::test::Bencher; @@ -16,10 +16,10 @@ struct MiriCompilerCalls<'a> { } impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { - fn after_analysis(&mut self, compiler: &interface::Compiler) -> Compilation { + fn after_analysis<'tcx>(&mut self, compiler: &interface::Compiler, queries: &'tcx Queries<'tcx>) -> Compilation { compiler.session().abort_if_errors(); - compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| { + queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect( "no main or start function found", ); diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 920c92544300..5e3f663de2e5 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -15,7 +15,7 @@ use std::sync::{Mutex, Arc}; use std::io; -use rustc_interface::interface; +use rustc_interface::{interface, Queries}; use rustc::hir::{self, itemlikevisit}; use rustc::ty::TyCtxt; use rustc::hir::def_id::LOCAL_CRATE; @@ -29,9 +29,9 @@ struct MiriCompilerCalls { } impl rustc_driver::Callbacks for MiriCompilerCalls { - fn after_analysis(&mut self, compiler: &interface::Compiler) -> Compilation { + fn after_analysis<'tcx>(&mut self, compiler: &interface::Compiler, queries: &'tcx Queries<'tcx>) -> Compilation { compiler.session().abort_if_errors(); - compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| { + queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { if std::env::args().any(|arg| arg == "--test") { struct Visitor<'tcx>(TyCtxt<'tcx>); impl<'tcx, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'tcx> { diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 9e95e4b0a466..59cb19476ac5 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -20,7 +20,7 @@ use std::env; use hex::FromHexError; -use rustc_interface::interface; +use rustc_interface::{interface, Queries}; use rustc::hir::def_id::LOCAL_CRATE; use rustc_driver::Compilation; @@ -29,11 +29,11 @@ struct MiriCompilerCalls { } impl rustc_driver::Callbacks for MiriCompilerCalls { - fn after_analysis(&mut self, compiler: &interface::Compiler) -> Compilation { + fn after_analysis<'tcx>(&mut self, compiler: &interface::Compiler, queries: &'tcx Queries<'tcx>) -> Compilation { init_late_loggers(); compiler.session().abort_if_errors(); - compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| { + queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!"); let mut config = self.miri_config.clone(); From f838410f492690e09626e9ae95f110f948235dce Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Dec 2019 10:20:16 +0100 Subject: [PATCH 1355/5092] toolchain -> rustup-toolchain --- CONTRIBUTING.md | 4 ++-- toolchain => rustup-toolchain | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) rename toolchain => rustup-toolchain (76%) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9338f0b8dd73..c673e107d55d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -23,7 +23,7 @@ tested against. Other versions will likely not work. After installing [`rustup-toolchain-install-master`], you can run the following command to install that exact version of rustc as a toolchain: ``` -./toolchain +./rustup-toolchain ``` [`rustup-toolchain-install-master`]: https://github.com/kennytm/rustup-toolchain-install-master @@ -38,7 +38,7 @@ needed. To update the `rustc-version` file and install the latest rustc, you can run: ``` -./toolchain HEAD +./rustup-toolchain HEAD ``` Now try `./miri test`, and submit a PR once that works again. diff --git a/toolchain b/rustup-toolchain similarity index 76% rename from toolchain rename to rustup-toolchain index 043b2ee2edd7..a981ec76548a 100755 --- a/toolchain +++ b/rustup-toolchain @@ -7,11 +7,11 @@ set -e # # USAGE: # -# ./toolchain: Update "miri" toolchain to match `rust-version` (the known-good version for this commit). +# ./rustup-toolchain: Update "miri" toolchain to match `rust-version` (the known-good version for this commit). # -# ./toolchain HEAD: Update "miri" toolchain and `rust-version` file to latest rustc HEAD. +# ./rustup-toolchain HEAD: Update "miri" toolchain and `rust-version` file to latest rustc HEAD. # -# ./toolchain $COMMIT: Update "miri" toolchain and `rust-version` file to match that commit. +# ./rustup-toolchain $COMMIT: Update "miri" toolchain and `rust-version` file to match that commit. # Determine new commit. if [[ "$1" == "" ]]; then From 0a4ec5d34e542ff00ff41110b0fc42072bd1b4aa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Dec 2019 10:22:16 +0100 Subject: [PATCH 1356/5092] test for rustup-toolchain-install-master --- rustup-toolchain | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/rustup-toolchain b/rustup-toolchain index a981ec76548a..096fa8857bab 100755 --- a/rustup-toolchain +++ b/rustup-toolchain @@ -13,6 +13,12 @@ set -e # # ./rustup-toolchain $COMMIT: Update "miri" toolchain and `rust-version` file to match that commit. +# Make sure rustup-toolchain-install-master is installed. +if ! which rustup-toolchain-install-master >/dev/null; then + echo "Please install rustup-toolchain-install-master by running 'cargo install rustup-toolchain-install-master'" + exit 1 +fi + # Determine new commit. if [[ "$1" == "" ]]; then NEW_COMMIT=$(cat rust-version) From c39482b20341abe2b22834f2ec6b04199e4a3383 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Dec 2019 10:29:19 +0100 Subject: [PATCH 1357/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index b5ab3053c5cf..43425c9afc58 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -809e180a76ce97340bf4354ff357bc59e3ca40b2 +4007d4ef26eab44bdabc2b7574d032152264d3ad From 2789e72e18938b4c676551d9b3d8f7ee955e5bbc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 28 Nov 2019 19:17:43 +0100 Subject: [PATCH 1358/5092] test more panics --- tests/run-pass/catch_panic.rs | 16 ++++++++-------- tests/run-pass/catch_panic.stderr | 6 ++++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/tests/run-pass/catch_panic.rs b/tests/run-pass/catch_panic.rs index c504956db35a..88fc35067d01 100644 --- a/tests/run-pass/catch_panic.rs +++ b/tests/run-pass/catch_panic.rs @@ -44,14 +44,14 @@ fn main() { prev(panic_info) })); - test(|_old_val| panic!("Hello from panic: std")); - test(|old_val| panic!(format!("Hello from panic: {:?}", old_val))); - test(|old_val| panic!("Hello from panic: {:?}", old_val)); - test(|_old_val| panic!(1337)); - // FIXME https://github.com/rust-lang/miri/issues/1071 - //test(|_old_val| core::panic!("Hello from panic: core")); - //test(|old_val| core::panic!(&format!("Hello from panic: {:?}", old_val))); - //test(|old_val| core::panic!("Hello from panic: {:?}", old_val)); + test(|_old_val| std::panic!("Hello from panic: std")); + test(|old_val| std::panic!(format!("Hello from panic: {:?}", old_val))); + test(|old_val| std::panic!("Hello from panic: {:?}", old_val)); + test(|_old_val| std::panic!(1337)); + + test(|_old_val| core::panic!("Hello from panic: core")); + test(|old_val| core::panic!(&format!("Hello from panic: {:?}", old_val))); + test(|old_val| core::panic!("Hello from panic: {:?}", old_val)); // Cleanup: reset to default hook. drop(std::panic::take_hook()); diff --git a/tests/run-pass/catch_panic.stderr b/tests/run-pass/catch_panic.stderr index 6d905da7febe..51814c7cde6e 100644 --- a/tests/run-pass/catch_panic.stderr +++ b/tests/run-pass/catch_panic.stderr @@ -6,4 +6,10 @@ thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:49:20 Caught panic message (String): Hello from panic: 2 thread 'main' panicked at 'Box', $DIR/catch_panic.rs:50:21 Failed get caught panic message. +thread 'main' panicked at 'Hello from panic: core', tests/run-pass/catch_panic.rs:52:21 +Caught panic message (String): Hello from panic: core +thread 'main' panicked at 'Hello from panic: 5', tests/run-pass/catch_panic.rs:53:20 +Caught panic message (String): Hello from panic: 5 +thread 'main' panicked at 'Hello from panic: 6', tests/run-pass/catch_panic.rs:54:20 +Caught panic message (String): Hello from panic: 6 Success! From f7efe238f3c999b815da3e7b736136360c973c59 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Dec 2019 11:04:51 +0100 Subject: [PATCH 1359/5092] fix catch_panic.stderr --- tests/run-pass/catch_panic.stderr | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/run-pass/catch_panic.stderr b/tests/run-pass/catch_panic.stderr index 51814c7cde6e..be729005dd56 100644 --- a/tests/run-pass/catch_panic.stderr +++ b/tests/run-pass/catch_panic.stderr @@ -6,10 +6,10 @@ thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:49:20 Caught panic message (String): Hello from panic: 2 thread 'main' panicked at 'Box', $DIR/catch_panic.rs:50:21 Failed get caught panic message. -thread 'main' panicked at 'Hello from panic: core', tests/run-pass/catch_panic.rs:52:21 +thread 'main' panicked at 'Hello from panic: core', $DIR/catch_panic.rs:52:21 Caught panic message (String): Hello from panic: core -thread 'main' panicked at 'Hello from panic: 5', tests/run-pass/catch_panic.rs:53:20 +thread 'main' panicked at 'Hello from panic: 5', $DIR/catch_panic.rs:53:20 Caught panic message (String): Hello from panic: 5 -thread 'main' panicked at 'Hello from panic: 6', tests/run-pass/catch_panic.rs:54:20 +thread 'main' panicked at 'Hello from panic: 6', $DIR/catch_panic.rs:54:20 Caught panic message (String): Hello from panic: 6 Success! From 3de5bd7decec2440a7696fdad72bf6f7698afa61 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Dec 2019 12:57:09 +0100 Subject: [PATCH 1360/5092] run-test: make sure the sysroot building output does not distort our tests --- test-cargo-miri/run-test.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 499c2e896f17..a4086bcc8c99 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -67,6 +67,10 @@ def test_cargo_miri_test(): os.chdir(os.path.dirname(os.path.realpath(__file__))) +if not 'MIRI_SYSROOT' in os.environ: + # Make sure we got a working sysroot. + # (If the sysroot gets built later when output is compared, that leads to test failures.) + subprocess.run(cargo_miri("setup"), check=True) test_cargo_miri_run() test_cargo_miri_test() From 9501d044c1afcd2c7921e48ef17930977d156dec Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Dec 2019 15:16:55 +0100 Subject: [PATCH 1361/5092] don't assume a nightly toolchain is installed --- rustup-toolchain | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/rustup-toolchain b/rustup-toolchain index 096fa8857bab..4e8e0b01ebc4 100755 --- a/rustup-toolchain +++ b/rustup-toolchain @@ -30,17 +30,17 @@ fi echo "$NEW_COMMIT" > rust-version # Check if we already are at that commit. -CUR_COMMIT=$(rustc +miri --version -v | egrep "^commit-hash: " | cut -d " " -f 2) +CUR_COMMIT=$(rustc +miri --version -v 2>/dev/null | egrep "^commit-hash: " | cut -d " " -f 2) if [[ "$CUR_COMMIT" == "$NEW_COMMIT" ]]; then echo "miri toolchain is already at commit $CUR_COMMIT." rustup override set miri exit 0 fi -# Cleanup. -cargo +nightly clean # Use nightly cargo as miri toolchain might be broken. -rustup toolchain uninstall miri - # Install and setup new toolchain. +rustup toolchain uninstall miri rustup-toolchain-install-master -n miri -c rust-src -c rustc-dev -- "$NEW_COMMIT" rustup override set miri + +# Cleanup. +cargo clean From f3c00a447c4d67053746bbfc40b41c0225f4b5dd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Dec 2019 09:05:35 +0100 Subject: [PATCH 1362/5092] use new MachineStop error variant --- rust-version | 2 +- src/eval.rs | 16 +++++++++++++++- src/lib.rs | 2 +- src/shims/foreign_items.rs | 5 +++-- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 43425c9afc58..3a0cf96e1327 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4007d4ef26eab44bdabc2b7574d032152264d3ad +f5c81e0a986e4285d3d0fd781a1bd475753eb12c diff --git a/src/eval.rs b/src/eval.rs index 986c6143ab4d..2c165760418f 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -24,6 +24,12 @@ pub struct MiriConfig { pub seed: Option, } +/// Details of premature program termination. +pub enum TerminationInfo { + Exit(i64), + Abort, +} + /// Returns a freshly created `InterpCx`, along with an `MPlaceTy` representing /// the location where the return value of the `start` lang item will be /// written to. @@ -200,7 +206,15 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Err(mut e) => { // Special treatment for some error kinds let msg = match e.kind { - InterpError::Exit(code) => return Some(code.into()), + InterpError::MachineStop(ref info) => { + let info = info.downcast_ref::() + .expect("invalid MachineStop payload"); + match info { + TerminationInfo::Exit(code) => return Some(*code), + TerminationInfo::Abort => + format!("The program aborted execution") + } + } err_unsup!(NoMirFor(..)) => format!("{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", e), _ => e.to_string() diff --git a/src/lib.rs b/src/lib.rs index f29ec8f22bba..05234e880f58 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,7 +47,7 @@ pub use crate::machine::{ PAGE_SIZE, STACK_ADDR, STACK_SIZE, NUM_CPUS, MemoryExtra, AllocExtra, MiriMemoryKind, Evaluator, MiriEvalContext, MiriEvalContextExt, }; -pub use crate::eval::{eval_main, create_ecx, MiriConfig}; +pub use crate::eval::{eval_main, create_ecx, MiriConfig, TerminationInfo}; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index b9e6734613c0..114931e435a4 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -152,9 +152,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "exit" | "ExitProcess" => { - // it's really u32 for ExitProcess, but we have to put it into the `Exit` error variant anyway + // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway let code = this.read_scalar(args[0])?.to_i32()?; - return Err(InterpError::Exit(code).into()); + let ti = Box::new(TerminationInfo::Exit(code.into())); + return Err(InterpError::MachineStop(ti).into()); } _ => { if let Some(p) = ret { From 1c420b0b5538a9bd1d81b02e7d3d775e85fe0a4d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Dec 2019 09:11:33 +0100 Subject: [PATCH 1363/5092] improve style in catch_panic test --- tests/run-pass/catch_panic.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/tests/run-pass/catch_panic.rs b/tests/run-pass/catch_panic.rs index 88fc35067d01..4c8b4cba9005 100644 --- a/tests/run-pass/catch_panic.rs +++ b/tests/run-pass/catch_panic.rs @@ -70,17 +70,13 @@ fn test(do_panic: impl FnOnce(usize) -> !) { do_panic_counter(do_panic) })).expect_err("do_panic() did not panic!"); - // See if we can extract panic message. - match res.downcast::() { - Ok(s) => { - eprintln!("Caught panic message (String): {}", s); - } - Err(res) => - if let Ok(s) = res.downcast::<&str>() { - eprintln!("Caught panic message (&str): {}", s); - } else { - eprintln!("Failed get caught panic message."); - } + // See if we can extract the panic message. + if let Some(s) = res.downcast_ref::() { + eprintln!("Caught panic message (String): {}", s); + } else if let Some(s) = res.downcast_ref::<&str>() { + eprintln!("Caught panic message (&str): {}", s); + } else { + eprintln!("Failed get caught panic message."); } // Test flags. From dcdd68b9364fb5410fccd5f66d334f6436273c4c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Dec 2019 09:13:58 +0100 Subject: [PATCH 1364/5092] also indicate abort via new MachineStop variant --- src/eval.rs | 2 +- src/shims/intrinsics.rs | 5 ++--- tests/compile-fail/double_panic.rs | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 2c165760418f..dbb14b7bb189 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -212,7 +212,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> match info { TerminationInfo::Exit(code) => return Some(*code), TerminationInfo::Abort => - format!("The program aborted execution") + format!("the evaluated program aborted execution") } } err_unsup!(NoMirFor(..)) => diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 00886328030b..0cb51d593199 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -34,9 +34,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Handle diverging intrinsics. let (dest, ret) = match intrinsic_name { "abort" => { - // FIXME: Add a better way of indicating 'abnormal' termination, - // since this is not really an 'unsupported' behavior - throw_unsup_format!("the evaluated program aborted!"); + let ti = Box::new(TerminationInfo::Abort); + return Err(InterpError::MachineStop(ti).into()); } "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), _ => { diff --git a/tests/compile-fail/double_panic.rs b/tests/compile-fail/double_panic.rs index 950d865c2a56..759762196b75 100644 --- a/tests/compile-fail/double_panic.rs +++ b/tests/compile-fail/double_panic.rs @@ -1,4 +1,4 @@ - //error-pattern: the evaluated program aborted + // error-pattern: the evaluated program aborted struct Foo; impl Drop for Foo { fn drop(&mut self) { From bba9359256d5b5ffa4caef5c60237ca2b325c7f7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 27 Nov 2019 21:50:20 +0100 Subject: [PATCH 1365/5092] expand coerce fn test --- .../coerce_non_capture_closure_to_fn_ptr.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs b/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs index 4da2c0c61b4a..71f244b2bc27 100644 --- a/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs +++ b/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs @@ -5,8 +5,10 @@ static FOO: fn() = || { assert_ne!(42, 43) }; static BAR: fn(i32, i32) = |a, b| { assert_ne!(a, b) }; // use to first make the closure FnOnce() before making it fn() -fn magic0 R>(f: F) -> F { f } -fn magic1 R>(f: F) -> F { f } +fn force_once0 R>(f: F) -> F { f } +fn force_once1 R>(f: F) -> F { f } +fn force_mut0 R>(f: F) -> F { f } +fn force_mut1 R>(f: F) -> F { f } fn main() { FOO(); @@ -18,12 +20,16 @@ fn main() { let f: fn() = ||{}; f(); - let f = magic0(||{}) as fn(); + let f = force_once0(||{}) as fn(); + f(); + let f = force_mut0(||{}) as fn(); f(); let g: fn(i32) = |i| assert_eq!(i, 2); g(2); - let g = magic1(|i| assert_eq!(i, 2)) as fn(i32); + let g = force_once1(|i| assert_eq!(i, 2)) as fn(i32); + g(2); + let g = force_mut1(|i| assert_eq!(i, 2)) as fn(i32); g(2); // FIXME: This fails with "invalid use of NULL pointer" From 9f9e547d791c5031f2dde9fa5424903d52934cc1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 27 Nov 2019 23:28:59 +0100 Subject: [PATCH 1366/5092] test diverging closure fn ptr coercion --- tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs | 8 -------- tests/run-pass/issue-miri-1075.rs | 6 ++++++ 2 files changed, 6 insertions(+), 8 deletions(-) create mode 100644 tests/run-pass/issue-miri-1075.rs diff --git a/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs b/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs index 71f244b2bc27..32393a37d2ec 100644 --- a/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs +++ b/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs @@ -31,12 +31,4 @@ fn main() { g(2); let g = force_mut1(|i| assert_eq!(i, 2)) as fn(i32); g(2); - - // FIXME: This fails with "invalid use of NULL pointer" - //let h: fn() -> ! = || std::process::exit(0); - //h(); - // FIXME: This does not even compile?!? - //let h = magic0(|| std::process::exit(0)) as fn() -> !; - //h(); - // Once these tests pass, they should be in separate files as they terminate the process. } diff --git a/tests/run-pass/issue-miri-1075.rs b/tests/run-pass/issue-miri-1075.rs new file mode 100644 index 000000000000..8bacaca9c2ac --- /dev/null +++ b/tests/run-pass/issue-miri-1075.rs @@ -0,0 +1,6 @@ +fn main() { + let f: fn() -> ! = || std::process::exit(0); + f(); + + // FIXME: Also add a test for , once that is fixed. +} From 42732cc9bb6cec922b9cc0ef723e97dd0b83bc52 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Dec 2019 15:42:38 +0100 Subject: [PATCH 1367/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 3a0cf96e1327..b2b29eb52795 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -f5c81e0a986e4285d3d0fd781a1bd475753eb12c +4af3ee8ee2a2bc1286b021db7600ba990359cf3f From 8a36d12d3664ab0e882ce98bacd6f7f95000f6a2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 29 Nov 2019 10:16:03 +0100 Subject: [PATCH 1368/5092] implement proper panicking for failed index check --- src/lib.rs | 3 ++- src/machine.rs | 10 ++++++++++ src/shims/panic.rs | 40 +++++++++++++++++++++++++++++++++++++--- 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 05234e880f58..abed7ab9dfeb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,6 +38,7 @@ pub use crate::shims::dlsym::{Dlsym, EvalContextExt as DlsymEvalContextExt}; pub use crate::shims::env::{EnvVars, EvalContextExt as EnvEvalContextExt}; pub use crate::shims::fs::{FileHandler, EvalContextExt as FileEvalContextExt}; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as PanicEvalContextExt}; + pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; @@ -45,7 +46,7 @@ pub use crate::mono_hash_map::MonoHashMap; pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt, Tag, Permission, Stack, Stacks, Item}; pub use crate::machine::{ PAGE_SIZE, STACK_ADDR, STACK_SIZE, NUM_CPUS, - MemoryExtra, AllocExtra, MiriMemoryKind, Evaluator, MiriEvalContext, MiriEvalContextExt, + MemoryExtra, AllocExtra, FrameData, MiriMemoryKind, Evaluator, MiriEvalContext, MiriEvalContextExt, }; pub use crate::eval::{eval_main, create_ecx, MiriConfig, TerminationInfo}; diff --git a/src/machine.rs b/src/machine.rs index 94ddee6fc092..07864ac4ee46 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -215,6 +215,16 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx.call_intrinsic(span, instance, args, ret, unwind) } + #[inline(always)] + fn assert_panic( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + span: Span, + msg: &AssertMessage<'tcx>, + unwind: Option, + ) -> InterpResult<'tcx> { + ecx.assert_panic(span, msg, unwind) + } + #[inline(always)] fn binary_ptr_op( ecx: &rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>, diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 6cc9f176c8fa..4b9cb6b41955 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -11,11 +11,12 @@ //! gets popped *during unwinding*, we take the panic payload and store it according to the extra //! metadata we remembered when pushing said frame. +use syntax::source_map::Span; use rustc::mir; -use crate::*; -use super::machine::FrameData; +use rustc::ty::{self, layout::LayoutOf}; use rustc_target::spec::PanicStrategy; -use crate::rustc_target::abi::LayoutOf; + +use crate::*; /// Holds all of the relevant data for a call to /// `__rust_maybe_catch_panic`. @@ -150,4 +151,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.memory.extra.stacked_borrows.borrow_mut().end_call(extra.call_id); Ok(res) } + + fn assert_panic( + &mut self, + span: Span, + msg: &AssertMessage<'tcx>, + unwind: Option, + ) -> InterpResult<'tcx> { + use rustc::mir::interpret::PanicInfo::*; + let this = self.eval_context_mut(); + + match msg { + BoundsCheck { ref index, ref len } => { + // First arg: Caller location. + let location = this.alloc_caller_location_for_span(span)?; + // Second arg: index. + let index = this.read_scalar(this.eval_operand(index, None)?)?; + // Third arg: len. + let len = this.read_scalar(this.eval_operand(len, None)?)?; + + // Call the lang item. + let panic_bounds_check = this.tcx.lang_items().panic_bounds_check_fn().unwrap(); + let panic_bounds_check = ty::Instance::mono(this.tcx.tcx, panic_bounds_check); + this.call_function( + panic_bounds_check, + &[location.ptr, index.not_undef()?, len.not_undef()?], + None, + StackPopCleanup::Goto { ret: None, unwind }, + )?; + } + _ => unimplemented!() + } + Ok(()) + } } From b91383b068dcd8c7cb287858e781c80323601fa5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 29 Nov 2019 11:17:44 +0100 Subject: [PATCH 1369/5092] implement proper panicking for other MIR assertions Requires generalizing the call_function helper to arbitrary Immediate arguments --- src/eval.rs | 4 ++-- src/helpers.rs | 4 ++-- src/machine.rs | 2 +- src/shims/env.rs | 2 +- src/shims/foreign_items.rs | 8 ++++---- src/shims/panic.rs | 27 ++++++++++++++++++++++++--- src/shims/tls.rs | 2 +- 7 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index dbb14b7bb189..f13ef89ff7fe 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -103,7 +103,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into()); for (idx, arg) in argvs.into_iter().enumerate() { let place = ecx.mplace_field(argvs_place, idx as u64)?; - ecx.write_scalar(Scalar::Ptr(arg), place.into())?; + ecx.write_scalar(arg, place.into())?; } ecx.memory .mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?; @@ -149,7 +149,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Call start function. ecx.call_function( start_instance, - &[main_ptr.into(), argc, argv], + &[main_ptr.into(), argc.into(), argv.into()], Some(ret_place.into()), StackPopCleanup::None { cleanup: true }, )?; diff --git a/src/helpers.rs b/src/helpers.rs index 28c31a07ef57..68ce014c3068 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -124,7 +124,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn call_function( &mut self, f: ty::Instance<'tcx>, - args: &[Scalar], + args: &[Immediate], dest: Option>, stack_pop: StackPopCleanup, ) -> InterpResult<'tcx> { @@ -146,7 +146,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let callee_arg = this.local_place( callee_args.next().expect("callee has fewer arguments than expected") )?; - this.write_scalar(*arg, callee_arg)?; + this.write_immediate(*arg, callee_arg)?; } callee_args.next().expect_none("callee has more arguments than expected"); diff --git a/src/machine.rs b/src/machine.rs index 07864ac4ee46..980c6115e91c 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -253,7 +253,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { let malloc = ty::Instance::mono(ecx.tcx.tcx, malloc); ecx.call_function( malloc, - &[size, align], + &[size.into(), align.into()], Some(dest), // Don't do anything when we are done. The `statement()` function will increment // the old stack frame's stmt counter to the next statement, which means that when diff --git a/src/shims/env.rs b/src/shims/env.rs index 44896fd9bbd5..ae8dae0313f1 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -57,7 +57,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(match this.machine.env_vars.map.get(name) { // The offset is used to strip the "{name}=" part of the string. Some(var_ptr) => { - Scalar::Ptr(var_ptr.offset(Size::from_bytes(name.len() as u64 + 1), this)?) + Scalar::from(var_ptr.offset(Size::from_bytes(name.len() as u64 + 1), this)?) } None => Scalar::ptr_null(&*this.tcx), }) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 114931e435a4..f27b4fb33352 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -205,7 +205,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Align::from_bytes(align).unwrap(), MiriMemoryKind::C.into(), ); - this.write_scalar(Scalar::Ptr(ptr), ret.into())?; + this.write_scalar(ptr, ret.into())?; } this.write_null(dest)?; } @@ -234,7 +234,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into(), ); - this.write_scalar(Scalar::Ptr(ptr), dest)?; + this.write_scalar(ptr, dest)?; } "__rust_alloc_zeroed" => { let size = this.read_scalar(args[0])?.to_machine_usize(this)?; @@ -254,7 +254,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.memory .write_bytes(ptr.into(), iter::repeat(0u8).take(size as usize)) .unwrap(); - this.write_scalar(Scalar::Ptr(ptr), dest)?; + this.write_scalar(ptr, dest)?; } "__rust_dealloc" => { let ptr = this.read_scalar(args[0])?.not_undef()?; @@ -295,7 +295,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx align, MiriMemoryKind::Rust.into(), )?; - this.write_scalar(Scalar::Ptr(new_ptr), dest)?; + this.write_scalar(new_ptr, dest)?; } "syscall" => { diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 4b9cb6b41955..7cdd81d935c2 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -86,7 +86,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx MPlaceTy::dangling(this.layout_of(tcx.mk_unit())?, this).into(); this.call_function( f_instance, - &[f_arg], + &[f_arg.into()], Some(ret_place), // Directly return to caller. StackPopCleanup::Goto { ret: Some(ret), unwind: None }, @@ -163,6 +163,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match msg { BoundsCheck { ref index, ref len } => { + // Forward to `panic_bounds_check` lang item. + // First arg: Caller location. let location = this.alloc_caller_location_for_span(span)?; // Second arg: index. @@ -175,12 +177,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let panic_bounds_check = ty::Instance::mono(this.tcx.tcx, panic_bounds_check); this.call_function( panic_bounds_check, - &[location.ptr, index.not_undef()?, len.not_undef()?], + &[location.ptr.into(), index.into(), len.into()], + None, + StackPopCleanup::Goto { ret: None, unwind }, + )?; + } + _ => { + // Forward everything else to `panic` lang item. + + // First arg: Message. + let msg = msg.description(); + let msg = this.allocate_str(msg, MiriMemoryKind::Static.into()); + + // Second arg: Caller location. + let location = this.alloc_caller_location_for_span(span)?; + + // Call the lang item. + let panic = this.tcx.lang_items().panic_fn().unwrap(); + let panic = ty::Instance::mono(this.tcx.tcx, panic); + this.call_function( + panic, + &[msg.to_ref(), location.ptr.into()], None, StackPopCleanup::Goto { ret: None, unwind }, )?; } - _ => unimplemented!() } Ok(()) } diff --git a/src/shims/tls.rs b/src/shims/tls.rs index ea8b0df230f2..420fd63a6181 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -150,7 +150,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); this.call_function( instance, - &[ptr], + &[ptr.into()], Some(ret_place), StackPopCleanup::None { cleanup: true }, )?; From 4cf83433b1fb17e3d08fe68a12ee58c7960330cc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 29 Nov 2019 11:19:15 +0100 Subject: [PATCH 1370/5092] test built-in panic catching --- tests/run-pass/catch_panic.rs | 8 ++++++++ tests/run-pass/catch_panic.stderr | 18 +++++++++++------- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/tests/run-pass/catch_panic.rs b/tests/run-pass/catch_panic.rs index 4c8b4cba9005..a14dd411c1c6 100644 --- a/tests/run-pass/catch_panic.rs +++ b/tests/run-pass/catch_panic.rs @@ -1,4 +1,6 @@ // ignore-windows: Unwind panicking does not currently work on Windows +#![allow(const_err)] + use std::panic::{catch_unwind, AssertUnwindSafe}; use std::cell::Cell; @@ -44,15 +46,21 @@ fn main() { prev(panic_info) })); + // Std panics test(|_old_val| std::panic!("Hello from panic: std")); test(|old_val| std::panic!(format!("Hello from panic: {:?}", old_val))); test(|old_val| std::panic!("Hello from panic: {:?}", old_val)); test(|_old_val| std::panic!(1337)); + // Core panics test(|_old_val| core::panic!("Hello from panic: core")); test(|old_val| core::panic!(&format!("Hello from panic: {:?}", old_val))); test(|old_val| core::panic!("Hello from panic: {:?}", old_val)); + // Built-in panics + test(|_old_val| { let _val = [0, 1, 2][4]; loop {} }); + test(|_old_val| { let _val = 1/0; loop {} }); + // Cleanup: reset to default hook. drop(std::panic::take_hook()); diff --git a/tests/run-pass/catch_panic.stderr b/tests/run-pass/catch_panic.stderr index be729005dd56..fd9a2f14ec3b 100644 --- a/tests/run-pass/catch_panic.stderr +++ b/tests/run-pass/catch_panic.stderr @@ -1,15 +1,19 @@ -thread 'main' panicked at 'Hello from panic: std', $DIR/catch_panic.rs:47:21 +thread 'main' panicked at 'Hello from panic: std', $DIR/catch_panic.rs:50:21 Caught panic message (&str): Hello from panic: std -thread 'main' panicked at 'Hello from panic: 1', $DIR/catch_panic.rs:48:20 +thread 'main' panicked at 'Hello from panic: 1', $DIR/catch_panic.rs:51:20 Caught panic message (String): Hello from panic: 1 -thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:49:20 +thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:52:20 Caught panic message (String): Hello from panic: 2 -thread 'main' panicked at 'Box', $DIR/catch_panic.rs:50:21 +thread 'main' panicked at 'Box', $DIR/catch_panic.rs:53:21 Failed get caught panic message. -thread 'main' panicked at 'Hello from panic: core', $DIR/catch_panic.rs:52:21 +thread 'main' panicked at 'Hello from panic: core', $DIR/catch_panic.rs:56:21 Caught panic message (String): Hello from panic: core -thread 'main' panicked at 'Hello from panic: 5', $DIR/catch_panic.rs:53:20 +thread 'main' panicked at 'Hello from panic: 5', $DIR/catch_panic.rs:57:20 Caught panic message (String): Hello from panic: 5 -thread 'main' panicked at 'Hello from panic: 6', $DIR/catch_panic.rs:54:20 +thread 'main' panicked at 'Hello from panic: 6', $DIR/catch_panic.rs:58:20 Caught panic message (String): Hello from panic: 6 +thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4', $DIR/catch_panic.rs:61:34 +Caught panic message (String): index out of bounds: the len is 3 but the index is 4 +thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:62:34 +Caught panic message (String): attempt to divide by zero Success! From b2cddd27bd1ba25f20cb5608d73053170f2ed83b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 29 Nov 2019 11:52:53 +0100 Subject: [PATCH 1371/5092] better span for functions whose frame we push 'manually' --- src/eval.rs | 7 +------ src/helpers.rs | 6 +++++- src/shims/panic.rs | 4 ++-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index f13ef89ff7fe..33bcfcc7380e 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -221,12 +221,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> }; e.print_backtrace(); if let Some(frame) = ecx.stack().last() { - let block = &frame.body.basic_blocks()[frame.block.unwrap()]; - let span = if frame.stmt < block.statements.len() { - block.statements[frame.stmt].source_info.span - } else { - block.terminator().source_info.span - }; + let span = frame.current_source_info().unwrap().span; let msg = format!("Miri evaluation error: {}", msg); let mut err = ecx.tcx.sess.struct_span_err(span, msg.as_str()); diff --git a/src/helpers.rs b/src/helpers.rs index 68ce014c3068..7bd29e174194 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -132,9 +132,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Push frame. let mir = this.load_mir(f.def, None)?; + let span = this.stack().last() + .and_then(Frame::current_source_info) + .map(|si| si.span) + .unwrap_or(DUMMY_SP); this.push_stack_frame( f, - DUMMY_SP, // There is no call site. + span, mir, dest, stack_pop, diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 7cdd81d935c2..3e82519f86b1 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -166,7 +166,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Forward to `panic_bounds_check` lang item. // First arg: Caller location. - let location = this.alloc_caller_location_for_span(span)?; + let location = this.alloc_caller_location_for_span(span); // Second arg: index. let index = this.read_scalar(this.eval_operand(index, None)?)?; // Third arg: len. @@ -190,7 +190,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let msg = this.allocate_str(msg, MiriMemoryKind::Static.into()); // Second arg: Caller location. - let location = this.alloc_caller_location_for_span(span)?; + let location = this.alloc_caller_location_for_span(span); // Call the lang item. let panic = this.tcx.lang_items().panic_fn().unwrap(); From ae53b1222a1cbb21b057e294ea93f1283210fb1a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 29 Nov 2019 13:18:54 +0100 Subject: [PATCH 1372/5092] fix and expand panic tests --- tests/compile-fail/div-by-zero-2.rs | 5 ----- tests/compile-fail/overflowing-lsh-neg.rs | 6 ------ tests/compile-fail/overflowing-rsh-1.rs | 5 ----- tests/compile-fail/{ => panic}/panic_abort1.rs | 0 tests/compile-fail/{ => panic}/panic_abort2.rs | 0 tests/compile-fail/{ => panic}/panic_abort3.rs | 0 tests/compile-fail/{ => panic}/panic_abort4.rs | 0 tests/run-pass/{ => panic}/catch_panic.rs | 0 tests/run-pass/{ => panic}/catch_panic.stderr | 0 tests/run-pass/panic/div-by-zero-2.rs | 6 ++++++ tests/run-pass/panic/div-by-zero-2.stderr | 1 + tests/run-pass/panic/overflowing-lsh-neg.rs | 7 +++++++ tests/run-pass/panic/overflowing-lsh-neg.stderr | 1 + tests/run-pass/panic/overflowing-rsh-1.rs | 6 ++++++ tests/run-pass/panic/overflowing-rsh-1.stderr | 1 + .../{compile-fail => run-pass/panic}/overflowing-rsh-2.rs | 3 ++- tests/run-pass/panic/overflowing-rsh-2.stderr | 1 + tests/run-pass/panic/panic1.rs | 4 ++++ tests/run-pass/panic/panic1.stderr | 1 + tests/run-pass/panic/panic2.rs | 4 ++++ tests/run-pass/panic/panic2.stderr | 1 + tests/run-pass/panic/panic3.rs | 4 ++++ tests/run-pass/panic/panic3.stderr | 1 + tests/run-pass/panic/panic4.rs | 4 ++++ tests/run-pass/panic/panic4.stderr | 1 + tests/{compile-fail => run-pass/panic}/transmute_fat2.rs | 2 +- tests/run-pass/panic/transmute_fat2.stderr | 1 + 27 files changed, 47 insertions(+), 18 deletions(-) delete mode 100644 tests/compile-fail/div-by-zero-2.rs delete mode 100644 tests/compile-fail/overflowing-lsh-neg.rs delete mode 100644 tests/compile-fail/overflowing-rsh-1.rs rename tests/compile-fail/{ => panic}/panic_abort1.rs (100%) rename tests/compile-fail/{ => panic}/panic_abort2.rs (100%) rename tests/compile-fail/{ => panic}/panic_abort3.rs (100%) rename tests/compile-fail/{ => panic}/panic_abort4.rs (100%) rename tests/run-pass/{ => panic}/catch_panic.rs (100%) rename tests/run-pass/{ => panic}/catch_panic.stderr (100%) create mode 100644 tests/run-pass/panic/div-by-zero-2.rs create mode 100644 tests/run-pass/panic/div-by-zero-2.stderr create mode 100644 tests/run-pass/panic/overflowing-lsh-neg.rs create mode 100644 tests/run-pass/panic/overflowing-lsh-neg.stderr create mode 100644 tests/run-pass/panic/overflowing-rsh-1.rs create mode 100644 tests/run-pass/panic/overflowing-rsh-1.stderr rename tests/{compile-fail => run-pass/panic}/overflowing-rsh-2.rs (54%) create mode 100644 tests/run-pass/panic/overflowing-rsh-2.stderr create mode 100644 tests/run-pass/panic/panic1.rs create mode 100644 tests/run-pass/panic/panic1.stderr create mode 100644 tests/run-pass/panic/panic2.rs create mode 100644 tests/run-pass/panic/panic2.stderr create mode 100644 tests/run-pass/panic/panic3.rs create mode 100644 tests/run-pass/panic/panic3.stderr create mode 100644 tests/run-pass/panic/panic4.rs create mode 100644 tests/run-pass/panic/panic4.stderr rename tests/{compile-fail => run-pass/panic}/transmute_fat2.rs (76%) create mode 100644 tests/run-pass/panic/transmute_fat2.stderr diff --git a/tests/compile-fail/div-by-zero-2.rs b/tests/compile-fail/div-by-zero-2.rs deleted file mode 100644 index 302d26a41f36..000000000000 --- a/tests/compile-fail/div-by-zero-2.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![allow(const_err)] - -fn main() { - let _n = 1 / 0; //~ ERROR attempt to divide by zero -} diff --git a/tests/compile-fail/overflowing-lsh-neg.rs b/tests/compile-fail/overflowing-lsh-neg.rs deleted file mode 100644 index 253294d1f53b..000000000000 --- a/tests/compile-fail/overflowing-lsh-neg.rs +++ /dev/null @@ -1,6 +0,0 @@ -#![allow(exceeding_bitshifts)] -#![allow(const_err)] - -fn main() { - let _n = 2i64 << -1; //~ ERROR attempt to shift left with overflow -} diff --git a/tests/compile-fail/overflowing-rsh-1.rs b/tests/compile-fail/overflowing-rsh-1.rs deleted file mode 100644 index e0d3f1904a23..000000000000 --- a/tests/compile-fail/overflowing-rsh-1.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![allow(exceeding_bitshifts, const_err)] - -fn main() { - let _n = 1i64 >> 64; //~ ERROR attempt to shift right with overflow -} diff --git a/tests/compile-fail/panic_abort1.rs b/tests/compile-fail/panic/panic_abort1.rs similarity index 100% rename from tests/compile-fail/panic_abort1.rs rename to tests/compile-fail/panic/panic_abort1.rs diff --git a/tests/compile-fail/panic_abort2.rs b/tests/compile-fail/panic/panic_abort2.rs similarity index 100% rename from tests/compile-fail/panic_abort2.rs rename to tests/compile-fail/panic/panic_abort2.rs diff --git a/tests/compile-fail/panic_abort3.rs b/tests/compile-fail/panic/panic_abort3.rs similarity index 100% rename from tests/compile-fail/panic_abort3.rs rename to tests/compile-fail/panic/panic_abort3.rs diff --git a/tests/compile-fail/panic_abort4.rs b/tests/compile-fail/panic/panic_abort4.rs similarity index 100% rename from tests/compile-fail/panic_abort4.rs rename to tests/compile-fail/panic/panic_abort4.rs diff --git a/tests/run-pass/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs similarity index 100% rename from tests/run-pass/catch_panic.rs rename to tests/run-pass/panic/catch_panic.rs diff --git a/tests/run-pass/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr similarity index 100% rename from tests/run-pass/catch_panic.stderr rename to tests/run-pass/panic/catch_panic.stderr diff --git a/tests/run-pass/panic/div-by-zero-2.rs b/tests/run-pass/panic/div-by-zero-2.rs new file mode 100644 index 000000000000..6cc319bf0bc4 --- /dev/null +++ b/tests/run-pass/panic/div-by-zero-2.rs @@ -0,0 +1,6 @@ +// ignore-windows: Unwind panicking does not currently work on Windows +#![allow(const_err)] + +fn main() { + let _n = 1 / 0; +} diff --git a/tests/run-pass/panic/div-by-zero-2.stderr b/tests/run-pass/panic/div-by-zero-2.stderr new file mode 100644 index 000000000000..77dca2aac1e2 --- /dev/null +++ b/tests/run-pass/panic/div-by-zero-2.stderr @@ -0,0 +1 @@ +thread 'main' panicked at 'attempt to divide by zero', $DIR/div-by-zero-2.rs:5:14 diff --git a/tests/run-pass/panic/overflowing-lsh-neg.rs b/tests/run-pass/panic/overflowing-lsh-neg.rs new file mode 100644 index 000000000000..b214243c88f8 --- /dev/null +++ b/tests/run-pass/panic/overflowing-lsh-neg.rs @@ -0,0 +1,7 @@ +// ignore-windows: Unwind panicking does not currently work on Windows +#![allow(exceeding_bitshifts)] +#![allow(const_err)] + +fn main() { + let _n = 2i64 << -1; +} diff --git a/tests/run-pass/panic/overflowing-lsh-neg.stderr b/tests/run-pass/panic/overflowing-lsh-neg.stderr new file mode 100644 index 000000000000..fe5a35e6b381 --- /dev/null +++ b/tests/run-pass/panic/overflowing-lsh-neg.stderr @@ -0,0 +1 @@ +thread 'main' panicked at 'attempt to shift left with overflow', $DIR/overflowing-lsh-neg.rs:6:14 diff --git a/tests/run-pass/panic/overflowing-rsh-1.rs b/tests/run-pass/panic/overflowing-rsh-1.rs new file mode 100644 index 000000000000..68ea51d16731 --- /dev/null +++ b/tests/run-pass/panic/overflowing-rsh-1.rs @@ -0,0 +1,6 @@ +// ignore-windows: Unwind panicking does not currently work on Windows +#![allow(exceeding_bitshifts, const_err)] + +fn main() { + let _n = 1i64 >> 64; +} diff --git a/tests/run-pass/panic/overflowing-rsh-1.stderr b/tests/run-pass/panic/overflowing-rsh-1.stderr new file mode 100644 index 000000000000..20a45739ae2e --- /dev/null +++ b/tests/run-pass/panic/overflowing-rsh-1.stderr @@ -0,0 +1 @@ +thread 'main' panicked at 'attempt to shift right with overflow', $DIR/overflowing-rsh-1.rs:5:14 diff --git a/tests/compile-fail/overflowing-rsh-2.rs b/tests/run-pass/panic/overflowing-rsh-2.rs similarity index 54% rename from tests/compile-fail/overflowing-rsh-2.rs rename to tests/run-pass/panic/overflowing-rsh-2.rs index 3f7f31f4c235..4e287f20adf8 100644 --- a/tests/compile-fail/overflowing-rsh-2.rs +++ b/tests/run-pass/panic/overflowing-rsh-2.rs @@ -1,6 +1,7 @@ +// ignore-windows: Unwind panicking does not currently work on Windows #![allow(exceeding_bitshifts, const_err)] fn main() { // Make sure we catch overflows that would be hidden by first casting the RHS to u32 - let _n = 1i64 >> (u32::max_value() as i64 + 1); //~ ERROR attempt to shift right with overflow + let _n = 1i64 >> (u32::max_value() as i64 + 1); } diff --git a/tests/run-pass/panic/overflowing-rsh-2.stderr b/tests/run-pass/panic/overflowing-rsh-2.stderr new file mode 100644 index 000000000000..3381116ae6c8 --- /dev/null +++ b/tests/run-pass/panic/overflowing-rsh-2.stderr @@ -0,0 +1 @@ +thread 'main' panicked at 'attempt to shift right with overflow', $DIR/overflowing-rsh-2.rs:6:14 diff --git a/tests/run-pass/panic/panic1.rs b/tests/run-pass/panic/panic1.rs new file mode 100644 index 000000000000..61321c658166 --- /dev/null +++ b/tests/run-pass/panic/panic1.rs @@ -0,0 +1,4 @@ +// ignore-windows: Unwind panicking does not currently work on Windows +fn main() { + std::panic!("panicking from libstd"); +} diff --git a/tests/run-pass/panic/panic1.stderr b/tests/run-pass/panic/panic1.stderr new file mode 100644 index 000000000000..305fc1a1a6e6 --- /dev/null +++ b/tests/run-pass/panic/panic1.stderr @@ -0,0 +1 @@ +thread 'main' panicked at 'panicking from libstd', $DIR/panic1.rs:3:5 diff --git a/tests/run-pass/panic/panic2.rs b/tests/run-pass/panic/panic2.rs new file mode 100644 index 000000000000..d6ab864795ea --- /dev/null +++ b/tests/run-pass/panic/panic2.rs @@ -0,0 +1,4 @@ +// ignore-windows: Unwind panicking does not currently work on Windows +fn main() { + std::panic!("{}-panicking from libstd", 42); +} diff --git a/tests/run-pass/panic/panic2.stderr b/tests/run-pass/panic/panic2.stderr new file mode 100644 index 000000000000..cd40559c81ef --- /dev/null +++ b/tests/run-pass/panic/panic2.stderr @@ -0,0 +1 @@ +thread 'main' panicked at '42-panicking from libstd', $DIR/panic2.rs:3:5 diff --git a/tests/run-pass/panic/panic3.rs b/tests/run-pass/panic/panic3.rs new file mode 100644 index 000000000000..10a42c7e6c00 --- /dev/null +++ b/tests/run-pass/panic/panic3.rs @@ -0,0 +1,4 @@ +// ignore-windows: Unwind panicking does not currently work on Windows +fn main() { + core::panic!("panicking from libcore"); +} diff --git a/tests/run-pass/panic/panic3.stderr b/tests/run-pass/panic/panic3.stderr new file mode 100644 index 000000000000..e3aa902f0cbc --- /dev/null +++ b/tests/run-pass/panic/panic3.stderr @@ -0,0 +1 @@ +thread 'main' panicked at 'panicking from libcore', $DIR/panic3.rs:3:5 diff --git a/tests/run-pass/panic/panic4.rs b/tests/run-pass/panic/panic4.rs new file mode 100644 index 000000000000..06e2dd008fff --- /dev/null +++ b/tests/run-pass/panic/panic4.rs @@ -0,0 +1,4 @@ +// ignore-windows: Unwind panicking does not currently work on Windows +fn main() { + core::panic!("{}-panicking from libcore", 42); +} diff --git a/tests/run-pass/panic/panic4.stderr b/tests/run-pass/panic/panic4.stderr new file mode 100644 index 000000000000..1a242a868cae --- /dev/null +++ b/tests/run-pass/panic/panic4.stderr @@ -0,0 +1 @@ +thread 'main' panicked at '42-panicking from libcore', $DIR/panic4.rs:3:5 diff --git a/tests/compile-fail/transmute_fat2.rs b/tests/run-pass/panic/transmute_fat2.rs similarity index 76% rename from tests/compile-fail/transmute_fat2.rs rename to tests/run-pass/panic/transmute_fat2.rs index 3121a139d920..40b3bd9d1051 100644 --- a/tests/compile-fail/transmute_fat2.rs +++ b/tests/run-pass/panic/transmute_fat2.rs @@ -7,5 +7,5 @@ fn main() { let bad = unsafe { std::mem::transmute::(42) }; - bad[0]; //~ ERROR index out of bounds: the len is 0 but the index is 0 + bad[0]; } diff --git a/tests/run-pass/panic/transmute_fat2.stderr b/tests/run-pass/panic/transmute_fat2.stderr new file mode 100644 index 000000000000..62f37877230a --- /dev/null +++ b/tests/run-pass/panic/transmute_fat2.stderr @@ -0,0 +1 @@ +thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', $DIR/transmute_fat2.rs:10:5 From 1b3434c67d27da6cf4c758b517fe132d5295bf02 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 29 Nov 2019 19:50:37 +0100 Subject: [PATCH 1373/5092] adjust for init_allocation_extra --- src/machine.rs | 21 +++++++++------------ src/stacked_borrows.rs | 14 +++++++++++--- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 980c6115e91c..b974c956c2e9 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -291,27 +291,24 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { Ok(()) } - fn tag_allocation<'b>( + fn init_allocation_extra<'b>( memory_extra: &MemoryExtra, id: AllocId, alloc: Cow<'b, Allocation>, kind: Option>, - ) -> ( - Cow<'b, Allocation>, - Self::PointerTag, - ) { + ) -> Cow<'b, Allocation> { let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); - let (stacks, base_tag) = if !memory_extra.validate { - (None, Tag::Untagged) - } else { - let (stacks, base_tag) = Stacks::new_allocation( + let stacks = if memory_extra.validate { + Some(Stacks::new_allocation( id, alloc.size, Rc::clone(&memory_extra.stacked_borrows), kind, - ); - (Some(stacks), base_tag) + )) + } else { + // No stacks. + None }; let mut stacked_borrows = memory_extra.stacked_borrows.borrow_mut(); let alloc: Allocation = alloc.with_tags_and_extra( @@ -328,7 +325,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { stacked_borrows: stacks, }, ); - (Cow::Owned(alloc), base_tag) + Cow::Owned(alloc) } #[inline(always)] diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 3b821c7155a6..dc06f12ffeb4 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -462,7 +462,7 @@ impl Stacks { size: Size, extra: MemoryExtra, kind: MemoryKind, - ) -> (Self, Tag) { + ) -> Self { let (tag, perm) = match kind { MemoryKind::Stack => // New unique borrow. This tag is not accessible by the program, @@ -472,12 +472,15 @@ impl Stacks { // and in particular, *all* raw pointers. (Tag::Tagged(extra.borrow_mut().new_ptr()), Permission::Unique), MemoryKind::Machine(MiriMemoryKind::Static) => + // Statics are inherently shared, so we do not derive any uniqueness assumptions + // from direct accesses to a static. Thus, the base permission is `SharedReadWrite`. (extra.borrow_mut().static_base_ptr(id), Permission::SharedReadWrite), _ => + // Everything else we handle entirely untagged for now. + // FIXME: experiment with more precise tracking. (Tag::Untagged, Permission::SharedReadWrite), }; - let stack = Stacks::new(size, perm, tag, extra); - (stack, tag) + Stacks::new(size, perm, tag, extra) } #[inline(always)] @@ -591,7 +594,12 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Compute new borrow. let new_tag = match kind { + // Give up tracking for raw pointers. + // FIXME: Experiment with more precise tracking. Blocked on `&raw` + // because `Rc::into_raw` currently creates intermediate references, + // breaking `Rc::from_raw`. RefKind::Raw { .. } => Tag::Untagged, + // All other pointesr are properly tracked. _ => Tag::Tagged(this.memory.extra.stacked_borrows.borrow_mut().new_ptr()), }; From f1cde6d80b9bef9808832b5b7ea322925c04fe5b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 Nov 2019 10:37:14 +0100 Subject: [PATCH 1374/5092] also test built-in panics via should_panic --- test-cargo-miri/test.stdout.ref | 5 +++-- test-cargo-miri/test.stdout.ref2 | 2 +- test-cargo-miri/test.stdout.ref3 | 2 +- test-cargo-miri/tests/test.rs | 11 ++++++++++- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/test-cargo-miri/test.stdout.ref b/test-cargo-miri/test.stdout.ref index 827e2f93237b..0ab948893b49 100644 --- a/test-cargo-miri/test.stdout.ref +++ b/test-cargo-miri/test.stdout.ref @@ -5,12 +5,13 @@ test test::rng ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out -running 5 tests +running 6 tests test do_panic ... ok test entropy_rng ... ok +test fail_index_check ... ok test num_cpus ... ok test simple1 ... ok test simple2 ... ok -test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/test.stdout.ref2 b/test-cargo-miri/test.stdout.ref2 index e070941c36ec..1dd4f70658d5 100644 --- a/test-cargo-miri/test.stdout.ref2 +++ b/test-cargo-miri/test.stdout.ref2 @@ -7,5 +7,5 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out running 1 test test simple1 ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 4 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 5 filtered out diff --git a/test-cargo-miri/test.stdout.ref3 b/test-cargo-miri/test.stdout.ref3 index a4a1a7812aea..af94192a12ca 100644 --- a/test-cargo-miri/test.stdout.ref3 +++ b/test-cargo-miri/test.stdout.ref3 @@ -7,5 +7,5 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out running 1 test test num_cpus ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 4 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 5 filtered out diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index ce85f929049b..76d3eeece5eb 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -43,7 +43,7 @@ fn num_cpus() { } -// FIXME: Remove this `cfg` once we fix https://github.com/rust-lang/miri/issues/1059 +// FIXME: Remove this `cfg` once we fix https://github.com/rust-lang/miri/issues/1059. // We cfg-gate the `should_panic` attribute and the `panic!` itself, so that the test // stdout does not depend on the platform. #[test] @@ -52,3 +52,12 @@ fn do_panic() { // In large, friendly letters :) #[cfg(not(windows))] panic!("Explicit panic from test!"); } + +// FIXME: see above +#[test] +#[allow(const_err)] +#[cfg_attr(not(windows), should_panic(expected="the len is 0 but the index is 42"))] +fn fail_index_check() { + #[cfg(not(windows))] + [][42] +} From e77258322c71091afe23ecb64461243174e7fd49 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 Nov 2019 11:48:34 +0100 Subject: [PATCH 1375/5092] some error classes should be impossible --- src/eval.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/eval.rs b/src/eval.rs index 33bcfcc7380e..17c0d52b00b9 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -217,6 +217,8 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> } err_unsup!(NoMirFor(..)) => format!("{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", e), + InterpError::Panic(_) | InterpError::InvalidProgram(_) => + bug!("This error should be impossible in Miri: {}", e), _ => e.to_string() }; e.print_backtrace(); From d43e394c4691f6ae9173001a27943d74ef6c5f97 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Dec 2019 10:18:41 +0100 Subject: [PATCH 1376/5092] fix init_allocation_extra --- src/eval.rs | 6 +++--- src/machine.rs | 19 ++++++++++--------- src/shims/panic.rs | 2 +- src/stacked_borrows.rs | 10 ++++++---- 4 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 17c0d52b00b9..2796dbd0b9b1 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -93,7 +93,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( arg.push(0); argvs.push( ecx.memory - .allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Static.into()), + .allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Env.into()), ); } // Make an array with all these pointers, in the Miri memory. @@ -144,7 +144,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Return place (in static memory so that it does not count as leak). let ret_place = ecx.allocate( ecx.layout_of(tcx.types.isize)?, - MiriMemoryKind::Static.into(), + MiriMemoryKind::Env.into(), ); // Call start function. ecx.call_function( @@ -156,7 +156,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Set the last_error to 0 let errno_layout = ecx.layout_of(tcx.types.u32)?; - let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Static.into()); + let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Env.into()); ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?; ecx.machine.last_error = Some(errno_place); diff --git a/src/machine.rs b/src/machine.rs index b974c956c2e9..edabc3bccbcc 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -43,9 +43,9 @@ pub enum MiriMemoryKind { C, /// Windows `HeapAlloc` memory. WinHeap, - /// Part of env var emulation. + /// Memory for env vars and args, errno and other parts of the machine-managed environment. Env, - /// Statics. + /// Rust statics. Static, } @@ -296,19 +296,20 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { id: AllocId, alloc: Cow<'b, Allocation>, kind: Option>, - ) -> Cow<'b, Allocation> { + ) -> (Cow<'b, Allocation>, Self::PointerTag) { let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); - let stacks = if memory_extra.validate { - Some(Stacks::new_allocation( + let (stacks, base_tag) = if memory_extra.validate { + let (stacks, base_tag) = Stacks::new_allocation( id, alloc.size, Rc::clone(&memory_extra.stacked_borrows), kind, - )) + ); + (Some(stacks), base_tag) } else { - // No stacks. - None + // No stacks, no tag. + (None, Tag::Untagged) }; let mut stacked_borrows = memory_extra.stacked_borrows.borrow_mut(); let alloc: Allocation = alloc.with_tags_and_extra( @@ -325,7 +326,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { stacked_borrows: stacks, }, ); - Cow::Owned(alloc) + (Cow::Owned(alloc), base_tag) } #[inline(always)] diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 3e82519f86b1..fc3339352a98 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -187,7 +187,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // First arg: Message. let msg = msg.description(); - let msg = this.allocate_str(msg, MiriMemoryKind::Static.into()); + let msg = this.allocate_str(msg, MiriMemoryKind::Env.into()); // Second arg: Caller location. let location = this.alloc_caller_location_for_span(span); diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index dc06f12ffeb4..23a32fc2ac5c 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -462,7 +462,7 @@ impl Stacks { size: Size, extra: MemoryExtra, kind: MemoryKind, - ) -> Self { + ) -> (Self, Tag) { let (tag, perm) = match kind { MemoryKind::Stack => // New unique borrow. This tag is not accessible by the program, @@ -472,15 +472,17 @@ impl Stacks { // and in particular, *all* raw pointers. (Tag::Tagged(extra.borrow_mut().new_ptr()), Permission::Unique), MemoryKind::Machine(MiriMemoryKind::Static) => - // Statics are inherently shared, so we do not derive any uniqueness assumptions - // from direct accesses to a static. Thus, the base permission is `SharedReadWrite`. + // Static memory can be referenced by "global" pointers from `tcx`. + // Thus we call `static_base_ptr` such that the global pointers get the same tag + // as what we use here. + // The base pointer is not unique, so the base permission is `SharedReadWrite`. (extra.borrow_mut().static_base_ptr(id), Permission::SharedReadWrite), _ => // Everything else we handle entirely untagged for now. // FIXME: experiment with more precise tracking. (Tag::Untagged, Permission::SharedReadWrite), }; - Stacks::new(size, perm, tag, extra) + (Stacks::new(size, perm, tag, extra), tag) } #[inline(always)] From 8e3c3eccc46a839e81ad2806d9507ab555260556 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Dec 2019 10:19:01 +0100 Subject: [PATCH 1377/5092] panic errors are actually still possible --- src/eval.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/eval.rs b/src/eval.rs index 2796dbd0b9b1..197cf87ba549 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -217,7 +217,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> } err_unsup!(NoMirFor(..)) => format!("{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", e), - InterpError::Panic(_) | InterpError::InvalidProgram(_) => + InterpError::InvalidProgram(_) => bug!("This error should be impossible in Miri: {}", e), _ => e.to_string() }; From 2ef5ac17cc1a6a3d2263d3a3382eba37e5252325 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Dec 2019 16:04:51 +0100 Subject: [PATCH 1378/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index b2b29eb52795..ebf6e5a2aca8 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4af3ee8ee2a2bc1286b021db7600ba990359cf3f +2da942f32802c8233a09744024dfbc34431adf65 From ce7b44b048820edc6b29873a708ec12c760db64b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Dec 2019 16:48:18 +0100 Subject: [PATCH 1379/5092] ignore another panicking test on Windows --- tests/run-pass/panic/transmute_fat2.rs | 1 + tests/run-pass/panic/transmute_fat2.stderr | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/panic/transmute_fat2.rs b/tests/run-pass/panic/transmute_fat2.rs index 40b3bd9d1051..8cbe9a099bb6 100644 --- a/tests/run-pass/panic/transmute_fat2.rs +++ b/tests/run-pass/panic/transmute_fat2.rs @@ -1,3 +1,4 @@ +// ignore-windows: Unwind panicking does not currently work on Windows fn main() { #[cfg(target_pointer_width="64")] let bad = unsafe { diff --git a/tests/run-pass/panic/transmute_fat2.stderr b/tests/run-pass/panic/transmute_fat2.stderr index 62f37877230a..08849a5b517a 100644 --- a/tests/run-pass/panic/transmute_fat2.stderr +++ b/tests/run-pass/panic/transmute_fat2.stderr @@ -1 +1 @@ -thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', $DIR/transmute_fat2.rs:10:5 +thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', $DIR/transmute_fat2.rs:11:5 From a418fe9826b4b2aa0a2f9d6c26d82673262a757a Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 2 Dec 2019 20:20:11 -0500 Subject: [PATCH 1380/5092] Rustup for `BodyCache` changes --- rust-version | 2 +- src/helpers.rs | 2 +- src/shims/foreign_items.rs | 4 ++-- src/shims/mod.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index ebf6e5a2aca8..08289d4459e7 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -2da942f32802c8233a09744024dfbc34431adf65 +fdc0011561c6365c596dfd8fa1ef388162bc89c7 diff --git a/src/helpers.rs b/src/helpers.rs index 7bd29e174194..e7da88f2bbfe 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -131,7 +131,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); // Push frame. - let mir = this.load_mir(f.def, None)?; + let mir = this.load_mir(f.def, None)?.body(); let span = this.stack().last() .and_then(Frame::current_source_info) .map(|si| si.span) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index f27b4fb33352..52e04aea3045 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -141,14 +141,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .expect("No panic runtime found!"); let panic_runtime = tcx.crate_name(*panic_runtime); let start_panic_instance = this.resolve_path(&[&*panic_runtime.as_str(), "__rust_start_panic"])?; - return Ok(Some(this.load_mir(start_panic_instance.def, None)?)); + return Ok(Some(this.load_mir(start_panic_instance.def, None)?.body())); } // Similarly, we forward calls to the `panic_impl` foreign item to its implementation. // The implementation is provided by the function with the `#[panic_handler]` attribute. "panic_impl" => { let panic_impl_id = this.tcx.lang_items().panic_impl().unwrap(); let panic_impl_instance = ty::Instance::mono(*this.tcx, panic_impl_id); - return Ok(Some(this.load_mir(panic_impl_instance.def, None)?)); + return Ok(Some(this.load_mir(panic_impl_instance.def, None)?.body())); } "exit" | "ExitProcess" => { diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 2e8aea3f86e0..d7842dbcba25 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -49,7 +49,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Otherwise, load the MIR. - Ok(Some(this.load_mir(instance.def, None)?)) + Ok(Some(this.load_mir(instance.def, None)?.body())) } fn align_offset( From ebe5a51336a2b948d100863c8bd8d813a86cce0b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 3 Dec 2019 08:21:52 +0100 Subject: [PATCH 1381/5092] bump Rust to HEAD --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 08289d4459e7..e81e0579a386 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -fdc0011561c6365c596dfd8fa1ef388162bc89c7 +4787e97475de6be9487e3d9255a9c2d3c0bf9252 From 6d8e87111ba4430ee7679232b7578257ffa015a1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 3 Dec 2019 17:37:42 +0100 Subject: [PATCH 1382/5092] bump Rust for exact_div fix --- rust-version | 2 +- tests/compile-fail/exact_div3.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index e81e0579a386..e1047d816e22 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4787e97475de6be9487e3d9255a9c2d3c0bf9252 +f577b0ef6e637ab7a6095cdfe0b51fa3faf97050 diff --git a/tests/compile-fail/exact_div3.rs b/tests/compile-fail/exact_div3.rs index 0460e412e45e..0d5097a87a20 100644 --- a/tests/compile-fail/exact_div3.rs +++ b/tests/compile-fail/exact_div3.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // signed divison with a remainder - unsafe { std::intrinsics::exact_div(-19i8, 2); } //~ ERROR 237 cannot be divided by 2 without remainder + unsafe { std::intrinsics::exact_div(-19i8, 2); } //~ ERROR -19 cannot be divided by 2 without remainder } From ab000997dbc597416c151e7879bb113c56146228 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Dec 2019 11:02:11 +0100 Subject: [PATCH 1383/5092] use throw_machine_stop macro --- src/shims/foreign_items.rs | 3 +-- src/shims/intrinsics.rs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 52e04aea3045..316cc686ad77 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -154,8 +154,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "exit" | "ExitProcess" => { // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway let code = this.read_scalar(args[0])?.to_i32()?; - let ti = Box::new(TerminationInfo::Exit(code.into())); - return Err(InterpError::MachineStop(ti).into()); + throw_machine_stop!(TerminationInfo::Exit(code.into())); } _ => { if let Some(p) = ret { diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 0cb51d593199..57b77a8b7490 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -34,8 +34,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Handle diverging intrinsics. let (dest, ret) = match intrinsic_name { "abort" => { - let ti = Box::new(TerminationInfo::Abort); - return Err(InterpError::MachineStop(ti).into()); + throw_machine_stop!(TerminationInfo::Abort); } "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), _ => { From 07af5c9ffc458f34eb31fc338a3785a1c81fa04c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 3 Dec 2019 23:38:41 +0100 Subject: [PATCH 1384/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index e1047d816e22..644ec5ed8072 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -f577b0ef6e637ab7a6095cdfe0b51fa3faf97050 +7afe6d9d1f48b998cc88fe6f01ba0082788ba4b9 From 808ac8f4b949d6ad4f4efc6e591e94f1321c03a3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 4 Dec 2019 09:55:36 +0100 Subject: [PATCH 1385/5092] use write_os_str_to_c_string for unix arg passing --- src/eval.rs | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 197cf87ba549..6f7f0ba329ce 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -1,5 +1,7 @@ //! Main evaluator loop and setting up the initial stack frame. +use std::ffi::OsStr; + use rand::rngs::StdRng; use rand::SeedableRng; @@ -75,26 +77,15 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let argc = Scalar::from_uint(config.args.len() as u128, ecx.pointer_size()); // Third argument (`argv`): created from `config.args`. let argv = { - // For Windows, construct a command string with all the aguments (before we take apart `config.args`). - let mut cmd = String::new(); + // Put each argument in memory, collect pointers. + let mut argvs = Vec::>::new(); for arg in config.args.iter() { - if !cmd.is_empty() { - cmd.push(' '); - } - cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into())); - } - // Don't forget `0` terminator. - cmd.push(std::char::from_u32(0).unwrap()); - // Collect the pointers to the individual strings. - let mut argvs = Vec::>::new(); - for arg in config.args { - // Add `0` terminator. - let mut arg = arg.into_bytes(); - arg.push(0); - argvs.push( - ecx.memory - .allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Env.into()), - ); + // Make space for `0` terminator. + let size = arg.len() as u64 + 1; + let arg_type = tcx.mk_array(tcx.types.u8, size); + let arg_place = ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Env.into()); + ecx.write_os_str_to_c_string(OsStr::new(arg), arg_place.ptr, size)?; + argvs.push(arg_place.ptr); } // Make an array with all these pointers, in the Miri memory. let argvs_layout = ecx.layout_of( @@ -107,7 +98,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } ecx.memory .mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?; - // A pointer to that place is the argument. + // A pointer to that place is the 3rd argument for main. let argv = argvs_place.ptr; // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`. { @@ -127,6 +118,17 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } // Store command line as UTF-16 for Windows `GetCommandLineW`. { + // Construct a command string with all the aguments. + let mut cmd = String::new(); + for arg in config.args.iter() { + if !cmd.is_empty() { + cmd.push(' '); + } + cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into())); + } + // Don't forget `0` terminator. + cmd.push(std::char::from_u32(0).unwrap()); + let cmd_utf16: Vec = cmd.encode_utf16().collect(); let cmd_type = tcx.mk_array(tcx.types.u16, cmd_utf16.len() as u64); let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Env.into()); From 01f060b6da675d800d9874e5256f4a069e58d442 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 4 Dec 2019 10:16:08 +0100 Subject: [PATCH 1386/5092] avoid allocation in read_os_string_from_c_string --- src/helpers.rs | 13 ++++++++----- src/machine.rs | 4 ++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index e7da88f2bbfe..9f75c9b7fbe1 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,5 +1,5 @@ use std::{mem, iter}; -use std::ffi::{OsStr, OsString}; +use std::ffi::OsStr; use syntax::source_map::DUMMY_SP; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; @@ -453,9 +453,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. - fn read_os_string_from_c_string(&mut self, scalar: Scalar) -> InterpResult<'tcx, OsString> { - let bytes = self.eval_context_mut().memory.read_c_str(scalar)?; - Ok(bytes_to_os_str(bytes)?.into()) + fn read_os_string_from_c_string<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, &'a OsStr> + where 'tcx: 'a, 'mir: 'a + { + let this = self.eval_context_ref(); + let bytes = this.memory.read_c_str(scalar)?; + bytes_to_os_str(bytes) } /// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what @@ -501,7 +504,7 @@ fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> } #[cfg(not(target_os = "unix"))] -fn bytes_to_os_str<'tcx, 'a>(bytes: &'a[u8]) -> InterpResult<'tcx, &'a OsStr> { +fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { let s = std::str::from_utf8(bytes) .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; Ok(&OsStr::new(s)) diff --git a/src/machine.rs b/src/machine.rs index edabc3bccbcc..55ac7f780fae 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -140,8 +140,8 @@ pub type MiriEvalContext<'mir, 'tcx> = InterpCx<'mir, 'tcx, Evaluator<'tcx>>; /// A little trait that's useful to be inherited by extension traits. pub trait MiriEvalContextExt<'mir, 'tcx> { - fn eval_context_ref(&self) -> &MiriEvalContext<'mir, 'tcx>; - fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'mir, 'tcx>; + fn eval_context_ref<'a>(&'a self) -> &'a MiriEvalContext<'mir, 'tcx>; + fn eval_context_mut<'a>(&'a mut self) -> &'a mut MiriEvalContext<'mir, 'tcx>; } impl<'mir, 'tcx> MiriEvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> { #[inline(always)] From 94732aaf7bf79fd01a4a48d11155c6586b937514 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 4 Dec 2019 10:43:36 +0100 Subject: [PATCH 1387/5092] rename helper methods a bit --- src/eval.rs | 2 +- src/helpers.rs | 4 ++-- src/shims/env.rs | 4 ++-- src/shims/fs.rs | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 6f7f0ba329ce..897d39567494 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -84,7 +84,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let size = arg.len() as u64 + 1; let arg_type = tcx.mk_array(tcx.types.u8, size); let arg_place = ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Env.into()); - ecx.write_os_str_to_c_string(OsStr::new(arg), arg_place.ptr, size)?; + ecx.write_os_str_to_c_str(OsStr::new(arg), arg_place.ptr, size)?; argvs.push(arg_place.ptr); } // Make an array with all these pointers, in the Miri memory. diff --git a/src/helpers.rs b/src/helpers.rs index 9f75c9b7fbe1..05a92164f27d 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -453,7 +453,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. - fn read_os_string_from_c_string<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, &'a OsStr> + fn read_os_str_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, &'a OsStr> where 'tcx: 'a, 'mir: 'a { let this = self.eval_context_ref(); @@ -465,7 +465,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// the Unix APIs usually handle. This function returns `Ok(false)` without trying to write if /// `size` is not large enough to fit the contents of `os_string` plus a null terminator. It /// returns `Ok(true)` if the writing process was successful. - fn write_os_str_to_c_string( + fn write_os_str_to_c_str( &mut self, os_str: &OsStr, scalar: Scalar, diff --git a/src/shims/env.rs b/src/shims/env.rs index ae8dae0313f1..8c431fd2016d 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -128,7 +128,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If we cannot get the current directory, we return null match env::current_dir() { Ok(cwd) => { - if this.write_os_str_to_c_string(&OsString::from(cwd), buf, size)? { + if this.write_os_str_to_c_str(&OsString::from(cwd), buf, size)? { return Ok(buf); } let erange = this.eval_libc("ERANGE")?; @@ -144,7 +144,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("chdir")?; - let path = this.read_os_string_from_c_string(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; match env::set_current_dir(path) { Ok(()) => Ok(0), diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 9291f3a6e3b2..4d10be626460 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -96,7 +96,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("unsupported flags {:#x}", flag & !mirror); } - let path = this.read_os_string_from_c_string(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; let fd = options.open(path).map(|file| { let mut fh = &mut this.machine.file_handler; @@ -250,7 +250,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("unlink")?; - let path = this.read_os_string_from_c_string(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; let result = remove_file(path).map(|_| 0); From edac086f1c9b324f97a9e0aab4c2f46b317d64e1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 4 Dec 2019 23:31:39 +0100 Subject: [PATCH 1388/5092] rustup for find_fn rename --- rust-version | 2 +- src/machine.rs | 4 ++-- src/shims/mod.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index 644ec5ed8072..83d06b2f7d2e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7afe6d9d1f48b998cc88fe6f01ba0082788ba4b9 +6d77e45f01079fe3d40180b3e256e414ab379f63 diff --git a/src/machine.rs b/src/machine.rs index 55ac7f780fae..65b6bcfb2ab7 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -182,14 +182,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } #[inline(always)] - fn find_fn( + fn find_mir_or_eval_fn( ecx: &mut InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { - ecx.find_fn(instance, args, ret, unwind) + ecx.find_mir_or_eval_fn(instance, args, ret, unwind) } #[inline(always)] diff --git a/src/shims/mod.rs b/src/shims/mod.rs index d7842dbcba25..21e69dc1f0fc 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -12,7 +12,7 @@ use crate::*; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn find_fn( + fn find_mir_or_eval_fn( &mut self, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], From 87fb5db526e8602c1a34d6cb42b3a31daa83888c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 6 Dec 2019 08:25:50 +0100 Subject: [PATCH 1389/5092] avoid recompiling Miri on install --- Cargo.lock | 1 + Cargo.toml | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 0ccbaaaabec2..9550b2bfdfe3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -339,6 +339,7 @@ dependencies = [ "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/Cargo.toml b/Cargo.toml index ac62d29eb8fc..da9481cce526 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,9 +46,10 @@ rand = "0.7" # for more information. rustc-workspace-hack = "1.0.0" -# Depend on num-traits with default features to avoid having to rebuild +# Some extra dependency for better feature control to avoid having to rebuild # between "cargo build" and "cargo intall". num-traits = "*" +serde = { version = "*", features = ["derive"] } [build-dependencies] vergen = "3" From f02643001f84f72962c01a924dd72fe5f2b00cfd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 6 Dec 2019 09:28:46 +0100 Subject: [PATCH 1390/5092] README: Miri now supports panics and FS access --- README.md | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 5a85b6d47855..7fd94a2811a9 100644 --- a/README.md +++ b/README.md @@ -39,10 +39,9 @@ program, and cannot run all programs: addresses or other non-deterministic data, try running Miri with different values for `-Zmiri-seed` to test different executions. * Miri runs the program as a platform-independent interpreter, so the program - has no access to any platform-specific APIs or FFI. A few APIs have been + has no access to most platform-specific APIs or FFI. A few APIs have been implemented (such as printing to stdout) but most have not: for example, Miri - currently does not support concurrency, or SIMD, or networking, or file system - access. + currently does not support concurrency, or SIMD, or networking. [rust]: https://www.rust-lang.org/ [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md @@ -78,9 +77,7 @@ dependencies. It will ask you for confirmation before installing anything. You can pass arguments to Miri after the first `--`, and pass arguments to the interpreted program or test suite after the second `--`. For example, `cargo miri run -- -Zmiri-disable-validation` runs the program without validation of -basic type invariants and references. `cargo miri test -- -- -Zunstable-options ---exclude-should-panic` skips `#[should_panic]` tests, which is a good idea -because Miri does not support unwinding or catching panics. +basic type invariants and references. When running code via `cargo miri`, the `miri` config flag is set. You can use this to exclude test cases that will fail under Miri because they do things @@ -90,8 +87,9 @@ Miri does not support: #[cfg(not(miri))] #[test] fn does_not_work_on_miri() { - let x = 0u8; - assert!(&x as *const _ as usize % 4 < 4); + std::thread::spawn(|| println!("Hello Thread!")) + .join() + .unwrap(); } ``` @@ -111,7 +109,7 @@ rustup default "$MIRI_NIGHTLY" rustup component add miri cargo miri setup -cargo miri test -- -- -Zunstable-options --exclude-should-panic +cargo miri test ``` We use `cargo miri setup` to avoid getting interactive questions about the extra From e0619b717ce2957dda6040b6996ceebb9539f30b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 6 Dec 2019 09:30:44 +0100 Subject: [PATCH 1391/5092] wording --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 7fd94a2811a9..92423c73c9ca 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ dependencies. It will ask you for confirmation before installing anything. You can pass arguments to Miri after the first `--`, and pass arguments to the interpreted program or test suite after the second `--`. For example, `cargo miri run -- -Zmiri-disable-validation` runs the program without validation of -basic type invariants and references. +basic type invariants and without checking the aliasing of references. When running code via `cargo miri`, the `miri` config flag is set. You can use this to exclude test cases that will fail under Miri because they do things @@ -152,10 +152,10 @@ Several `-Z` flags are relevant for Miri: **NOTE**: This entropy is not good enough for cryptographic use! Do not generate secret keys in Miri or perform other kinds of cryptographic operations that rely on proper random numbers. -* `-Zmiri-disable-validation` disables enforcing the validity invariant, which - is enforced by default. This is mostly useful for debugging; it means Miri - will miss bugs in your program. However, this can also help to make Miri run - faster. +* `-Zmiri-disable-validation` disables enforcing validity invariants and + reference aliasing rules, which are enforced by default. This is mostly + useful for debugging. It means Miri will miss bugs in your program. However, + this can also help to make Miri run faster. * `-Zmiri-disable-isolation` disables host host isolation. As a consequence, the program has access to host resources such as environment variables and randomness (and, eventually, file systems and more). From 1a8755384e20e5b90e591f665f7b4849941ed58e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 7 Dec 2019 11:43:24 +0100 Subject: [PATCH 1392/5092] better way to ignore tests in Miri --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 92423c73c9ca..3156b4fa2418 100644 --- a/README.md +++ b/README.md @@ -79,13 +79,13 @@ interpreted program or test suite after the second `--`. For example, `cargo miri run -- -Zmiri-disable-validation` runs the program without validation of basic type invariants and without checking the aliasing of references. -When running code via `cargo miri`, the `miri` config flag is set. You can -use this to exclude test cases that will fail under Miri because they do things +When compiling code via `cargo miri`, the `miri` config flag is set. You can +use this to ignore test cases that will fail under Miri because they do things Miri does not support: ```rust -#[cfg(not(miri))] #[test] +#[cfg_attr(miri, ignore)] fn does_not_work_on_miri() { std::thread::spawn(|| println!("Hello Thread!")) .join() From b883c11caa4aa3dabd245b9a91168af1d44d236e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 7 Dec 2019 11:55:19 +0100 Subject: [PATCH 1393/5092] use recommended test exclusion technique in test --- test-cargo-miri/test.stdout.ref | 5 +++-- test-cargo-miri/test.stdout.ref2 | 2 +- test-cargo-miri/test.stdout.ref3 | 2 +- test-cargo-miri/tests/test.rs | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/test-cargo-miri/test.stdout.ref b/test-cargo-miri/test.stdout.ref index 0ab948893b49..4260f5b3cb78 100644 --- a/test-cargo-miri/test.stdout.ref +++ b/test-cargo-miri/test.stdout.ref @@ -5,13 +5,14 @@ test test::rng ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out -running 6 tests +running 7 tests test do_panic ... ok +test does_not_work_on_miri ... ignored test entropy_rng ... ok test fail_index_check ... ok test num_cpus ... ok test simple1 ... ok test simple2 ... ok -test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/test.stdout.ref2 b/test-cargo-miri/test.stdout.ref2 index 1dd4f70658d5..37efb8c3ee89 100644 --- a/test-cargo-miri/test.stdout.ref2 +++ b/test-cargo-miri/test.stdout.ref2 @@ -7,5 +7,5 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out running 1 test test simple1 ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 5 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out diff --git a/test-cargo-miri/test.stdout.ref3 b/test-cargo-miri/test.stdout.ref3 index af94192a12ca..c5c39de109d2 100644 --- a/test-cargo-miri/test.stdout.ref3 +++ b/test-cargo-miri/test.stdout.ref3 @@ -7,5 +7,5 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out running 1 test test num_cpus ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 5 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 76d3eeece5eb..4c196ef5e0f5 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -13,8 +13,8 @@ fn simple2() { } // A test that won't work on miri (tests disabling tests). -#[cfg(not(miri))] #[test] +#[cfg_attr(miri, ignore)] fn does_not_work_on_miri() { let x = 0u8; assert!(&x as *const _ as usize % 4 < 4); From e92d16d9cd32fdaaf218c09e198b93c1f7c7914d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 7 Dec 2019 13:44:48 +0100 Subject: [PATCH 1394/5092] add flag to ignore memory leaks --- README.md | 1 + src/bin/miri.rs | 5 +++++ src/eval.rs | 11 +++++++---- tests/run-pass/memleak_ignored.rs | 5 +++++ 4 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 tests/run-pass/memleak_ignored.rs diff --git a/README.md b/README.md index 92423c73c9ca..01d0935be21a 100644 --- a/README.md +++ b/README.md @@ -159,6 +159,7 @@ Several `-Z` flags are relevant for Miri: * `-Zmiri-disable-isolation` disables host host isolation. As a consequence, the program has access to host resources such as environment variables and randomness (and, eventually, file systems and more). +* `-Zmiri-ignore-leaks` disables the memory leak checker. * `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from the host. Can be used multiple times to exclude several variables. The `TERM` environment variable is excluded by default. diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 59cb19476ac5..e255afc3463d 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -124,6 +124,7 @@ fn main() { // Parse our arguments and split them across `rustc` and `miri`. let mut validate = true; let mut communicate = false; + let mut ignore_leaks = false; let mut seed: Option = None; let mut rustc_args = vec![]; let mut miri_args = vec![]; @@ -145,6 +146,9 @@ fn main() { "-Zmiri-disable-isolation" => { communicate = true; }, + "-Zmiri-ignore-leaks" => { + ignore_leaks = true; + }, "--" => { after_dashdash = true; } @@ -200,6 +204,7 @@ fn main() { let miri_config = miri::MiriConfig { validate, communicate, + ignore_leaks, excluded_env_vars, seed, args: miri_args, diff --git a/src/eval.rs b/src/eval.rs index 897d39567494..8be42226b5ec 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -18,6 +18,8 @@ pub struct MiriConfig { pub validate: bool, /// Determines if communication with the host environment is enabled. pub communicate: bool, + /// Determines if memory leaks should be ignored. + pub ignore_leaks: bool, /// Environment variables that should always be isolated from the host. pub excluded_env_vars: Vec, /// Command-line arguments passed to the interpreted program. @@ -169,6 +171,11 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( /// Returns `Some(return_code)` if program executed completed. /// Returns `None` if an evaluation error occured. pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option { + // FIXME: We always ignore leaks on some platforms where we do not + // correctly implement TLS destructors. + let target_os = tcx.sess.target.target.target_os.to_lowercase(); + let ignore_leaks = config.ignore_leaks || target_os == "windows" || target_os == "macos"; + let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) { Ok(v) => v, Err(mut err) => { @@ -190,10 +197,6 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> // Process the result. match res { Ok(return_code) => { - // Disable the leak test on some platforms where we do not - // correctly implement TLS destructors. - let target_os = ecx.tcx.tcx.sess.target.target.target_os.to_lowercase(); - let ignore_leaks = target_os == "windows" || target_os == "macos"; if !ignore_leaks { let leaks = ecx.memory.leak_report(); if leaks != 0 { diff --git a/tests/run-pass/memleak_ignored.rs b/tests/run-pass/memleak_ignored.rs new file mode 100644 index 000000000000..fddf14121ef3 --- /dev/null +++ b/tests/run-pass/memleak_ignored.rs @@ -0,0 +1,5 @@ +// compile-flags: -Zmiri-ignore-leaks + +fn main() { + std::mem::forget(Box::new(42)); +} From 0a63637e6640cdb9ef9e0afeb4d3408cd553093f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 7 Dec 2019 18:50:07 +0100 Subject: [PATCH 1395/5092] fix all-targets build --- benches/helpers/miri_helper.rs | 1 + src/bin/miri-rustc-tests.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 95146513509b..aa0f3d995925 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -28,6 +28,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { let config = miri::MiriConfig { validate: true, communicate: false, + ignore_leaks: false, excluded_env_vars: vec![], args: vec![], seed: None, diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 5e3f663de2e5..df8bb583f8e3 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -41,6 +41,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { let config = MiriConfig { validate: true, communicate: false, + ignore_leaks: false, excluded_env_vars: vec![], args: vec![], seed: None, @@ -60,6 +61,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { let config = MiriConfig { validate: true, communicate: false, + ignore_leaks: false, excluded_env_vars: vec![], args: vec![], seed: None From cefc592273fbf708378273317a1485a32bbc7318 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 8 Dec 2019 01:45:41 +0100 Subject: [PATCH 1396/5092] bump Rust, fix error messages --- rust-version | 2 +- tests/compile-fail/never_say_never.rs | 2 +- tests/compile-fail/never_transmute_humans.rs | 2 +- tests/compile-fail/never_transmute_void.rs | 2 +- tests/compile-fail/out_of_bounds_ptr_2.rs | 2 +- tests/compile-fail/ptr_offset_overflow.rs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index 83d06b2f7d2e..7266b1bd0ab0 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6d77e45f01079fe3d40180b3e256e414ab379f63 +5c5c8eb864e56ce905742b8e97df5506bba6aeef diff --git a/tests/compile-fail/never_say_never.rs b/tests/compile-fail/never_say_never.rs index 199ceb70fb6b..21fc16751c25 100644 --- a/tests/compile-fail/never_say_never.rs +++ b/tests/compile-fail/never_say_never.rs @@ -6,7 +6,7 @@ fn main() { let y = &5; let x: ! = unsafe { - *(y as *const _ as *const !) //~ ERROR entered unreachable code + *(y as *const _ as *const !) //~ ERROR entering unreachable code }; f(x) } diff --git a/tests/compile-fail/never_transmute_humans.rs b/tests/compile-fail/never_transmute_humans.rs index f662fdcd9872..5053be24ebf0 100644 --- a/tests/compile-fail/never_transmute_humans.rs +++ b/tests/compile-fail/never_transmute_humans.rs @@ -5,6 +5,6 @@ struct Human; fn main() { let _x: ! = unsafe { - std::mem::transmute::(Human) //~ ERROR entered unreachable code + std::mem::transmute::(Human) //~ ERROR entering unreachable code }; } diff --git a/tests/compile-fail/never_transmute_void.rs b/tests/compile-fail/never_transmute_void.rs index 933e05211956..a9cbac528d7a 100644 --- a/tests/compile-fail/never_transmute_void.rs +++ b/tests/compile-fail/never_transmute_void.rs @@ -6,7 +6,7 @@ enum Void {} fn f(v: Void) -> ! { - match v {} //~ ERROR entered unreachable code + match v {} //~ ERROR entering unreachable code } fn main() { diff --git a/tests/compile-fail/out_of_bounds_ptr_2.rs b/tests/compile-fail/out_of_bounds_ptr_2.rs index e19a616a1916..1e4759ddc46d 100644 --- a/tests/compile-fail/out_of_bounds_ptr_2.rs +++ b/tests/compile-fail/out_of_bounds_ptr_2.rs @@ -1,4 +1,4 @@ -// error-pattern: attempt to add with overflow +// error-pattern: overflowing in-bounds pointer arithmetic fn main() { let v = [0i8; 4]; let x = &v as *const i8; diff --git a/tests/compile-fail/ptr_offset_overflow.rs b/tests/compile-fail/ptr_offset_overflow.rs index babd0246e7e1..e52384e91967 100644 --- a/tests/compile-fail/ptr_offset_overflow.rs +++ b/tests/compile-fail/ptr_offset_overflow.rs @@ -1,4 +1,4 @@ -//error-pattern: attempt to add with overflow +//error-pattern: overflowing in-bounds pointer arithmetic fn main() { let v = [1i8, 2]; let x = &v[1] as *const i8; From 67151a712d4e894f145454de78dcd04aa16d204a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 8 Dec 2019 10:32:50 +0100 Subject: [PATCH 1397/5092] rustup --- rust-version | 2 +- src/helpers.rs | 2 +- src/shims/foreign_items.rs | 4 ++-- src/shims/mod.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 7266b1bd0ab0..bc65b5b6751b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -5c5c8eb864e56ce905742b8e97df5506bba6aeef +e862c01aadb2d029864f7bb256cf6c85bbb5d7e4 diff --git a/src/helpers.rs b/src/helpers.rs index 05a92164f27d..763ab403f192 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -131,7 +131,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); // Push frame. - let mir = this.load_mir(f.def, None)?.body(); + let mir = &*this.load_mir(f.def, None)?; let span = this.stack().last() .and_then(Frame::current_source_info) .map(|si| si.span) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 316cc686ad77..a983c0b11fa2 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -141,14 +141,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .expect("No panic runtime found!"); let panic_runtime = tcx.crate_name(*panic_runtime); let start_panic_instance = this.resolve_path(&[&*panic_runtime.as_str(), "__rust_start_panic"])?; - return Ok(Some(this.load_mir(start_panic_instance.def, None)?.body())); + return Ok(Some(&*this.load_mir(start_panic_instance.def, None)?)); } // Similarly, we forward calls to the `panic_impl` foreign item to its implementation. // The implementation is provided by the function with the `#[panic_handler]` attribute. "panic_impl" => { let panic_impl_id = this.tcx.lang_items().panic_impl().unwrap(); let panic_impl_instance = ty::Instance::mono(*this.tcx, panic_impl_id); - return Ok(Some(this.load_mir(panic_impl_instance.def, None)?.body())); + return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); } "exit" | "ExitProcess" => { diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 21e69dc1f0fc..06ef58eaf526 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -49,7 +49,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Otherwise, load the MIR. - Ok(Some(this.load_mir(instance.def, None)?.body())) + Ok(Some(&*this.load_mir(instance.def, None)?)) } fn align_offset( From b0a205ce6ffbe5618bc280d82f261320c8421790 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 8 Dec 2019 11:06:35 +0100 Subject: [PATCH 1398/5092] add caller_location tests to Miri --- tests/run-pass/track-caller-attribute.rs | 54 ++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 tests/run-pass/track-caller-attribute.rs diff --git a/tests/run-pass/track-caller-attribute.rs b/tests/run-pass/track-caller-attribute.rs new file mode 100644 index 000000000000..68a0c95b44db --- /dev/null +++ b/tests/run-pass/track-caller-attribute.rs @@ -0,0 +1,54 @@ +#![feature(track_caller, core_intrinsics)] + +use std::panic::Location; + +#[track_caller] +fn tracked() -> &'static Location<'static> { + Location::caller() // most importantly, we never get line 7 +} + +fn nested_intrinsic() -> &'static Location<'static> { + Location::caller() +} + +fn nested_tracked() -> &'static Location<'static> { + tracked() +} + +macro_rules! caller_location_from_macro { + () => (core::panic::Location::caller()); +} + +fn main() { + let location = Location::caller(); + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), 23); + assert_eq!(location.column(), 20); + + let tracked = tracked(); + assert_eq!(tracked.file(), file!()); + assert_eq!(tracked.line(), 28); + assert_eq!(tracked.column(), 19); + + let nested = nested_intrinsic(); + assert_eq!(nested.file(), file!()); + assert_eq!(nested.line(), 11); + assert_eq!(nested.column(), 5); + + let contained = nested_tracked(); + assert_eq!(contained.file(), file!()); + assert_eq!(contained.line(), 15); + assert_eq!(contained.column(), 5); + + // `Location::caller()` in a macro should behave similarly to `file!` and `line!`, + // i.e. point to where the macro was invoked, instead of the macro itself. + let inmacro = caller_location_from_macro!(); + assert_eq!(inmacro.file(), file!()); + assert_eq!(inmacro.line(), 45); + assert_eq!(inmacro.column(), 19); + + let intrinsic = core::intrinsics::caller_location(); + assert_eq!(intrinsic.file(), file!()); + assert_eq!(intrinsic.line(), 50); + assert_eq!(intrinsic.column(), 21); +} From ef37a4c158375a29f7b4035cd3aab144fff0bb8c Mon Sep 17 00:00:00 2001 From: Markus Pettersson Date: Sun, 8 Dec 2019 11:12:25 +0100 Subject: [PATCH 1399/5092] Updated README to reflect deprecation of rustup install --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 16eae05973b2..e505496a69a8 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ If `rustup` says the `miri` component is unavailable, that's because not all nightly releases come with all tools. Check out [this website](https://rust-lang.github.io/rustup-components-history) to determine a nightly version that comes with Miri and install that using -`rustup install nightly-YYYY-MM-DD`. +`rustup toolchain install nightly-YYYY-MM-DD`. Now you can run your project in Miri: From c9e7fe8b8cdc1b1397b8f7bcaf5b2a1aff8b830c Mon Sep 17 00:00:00 2001 From: Markus Pettersson Date: Sun, 8 Dec 2019 11:22:02 +0100 Subject: [PATCH 1400/5092] Updated CI config to reflect deprecation of rustup uninstall --- .appveyor.yml | 2 +- .travis.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index b9e112aa0860..16fd20c9da61 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -27,7 +27,7 @@ install: - rustup-init.exe -y --default-host %TARGET% --default-toolchain stable --profile minimal - set PATH=%USERPROFILE%\.cargo\bin;%PATH% - rustup default stable - - rustup uninstall beta + - rustup toolchain uninstall beta - rustup update # Install "master" toolchain - cargo install rustup-toolchain-install-master & exit 0 diff --git a/.travis.yml b/.travis.yml index a080ab55b94f..cbb7c69db1cd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,7 +34,7 @@ before_script: - curl https://build.travis-ci.org/files/rustup-init.sh -sSf | sh -s -- -y --default-toolchain stable --profile minimal - export PATH=$HOME/.cargo/bin:$PATH - rustup default stable -- rustup uninstall beta +- rustup toolchain uninstall beta - rustup update # Install "master" toolchain - cargo install rustup-toolchain-install-master || echo "rustup-toolchain-install-master already installed" From d363a47fcbbdcef228acef6f8625fc09ce168c55 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 28 Nov 2019 10:36:37 +0100 Subject: [PATCH 1401/5092] Add a scheme to find the place where an id was destroyed --- benches/helpers/miri_helper.rs | 1 + src/bin/miri-rustc-tests.rs | 4 +++- src/bin/miri.rs | 13 +++++++++++++ src/eval.rs | 4 +++- src/lib.rs | 5 ++++- src/machine.rs | 4 ++-- src/stacked_borrows.rs | 14 ++++++++++---- .../compile-fail/stacked_borrows/track_id.rs | 19 +++++++++++++++++++ 8 files changed, 55 insertions(+), 9 deletions(-) create mode 100644 tests/compile-fail/stacked_borrows/track_id.rs diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index aa0f3d995925..40683f8d7475 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -32,6 +32,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { excluded_env_vars: vec![], args: vec![], seed: None, + tracked_id: None, }; eval_main(tcx, entry_def_id, config); }); diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index df8bb583f8e3..8b1739f3443b 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -45,6 +45,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { excluded_env_vars: vec![], args: vec![], seed: None, + tracked_id: None, }; let did = self.0.hir().body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); @@ -64,7 +65,8 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { ignore_leaks: false, excluded_env_vars: vec![], args: vec![], - seed: None + seed: None, + tracked_id: None, }; miri::eval_main(tcx, entry_def_id, config); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index e255afc3463d..e3aa75b9e880 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -126,6 +126,7 @@ fn main() { let mut communicate = false; let mut ignore_leaks = false; let mut seed: Option = None; + let mut tracked_id: Option = None; let mut rustc_args = vec![]; let mut miri_args = vec![]; let mut after_dashdash = false; @@ -176,6 +177,17 @@ fn main() { arg if arg.starts_with("-Zmiri-env-exclude=") => { excluded_env_vars.push(arg.trim_start_matches("-Zmiri-env-exclude=").to_owned()); }, + arg if arg.starts_with("-Zmiri-track-id=") => { + let id: u64 = match arg.trim_start_matches("-Zmiri-track-id=").parse() { + Ok(id) => id, + Err(err) => panic!("-Zmiri-track-id requires a valid `u64` as the argument: {}", err), + }; + if let Some(id) = miri::PtrId::new(id) { + tracked_id = Some(id); + } else { + panic!("-Zmiri-track-id must be a nonzero id"); + } + }, _ => { rustc_args.push(arg); } @@ -208,6 +220,7 @@ fn main() { excluded_env_vars, seed, args: miri_args, + tracked_id, }; rustc_driver::install_ice_hook(); let result = rustc_driver::catch_fatal_errors(move || { diff --git a/src/eval.rs b/src/eval.rs index 8be42226b5ec..fb82679523e3 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -26,6 +26,8 @@ pub struct MiriConfig { pub args: Vec, /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`). pub seed: Option, + /// The stacked borrow id to report about + pub tracked_id: Option, } /// Details of premature program termination. @@ -47,7 +49,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), Evaluator::new(config.communicate), - MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate), + MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate, config.tracked_id), ); // Complete initialization. EnvVars::init(&mut ecx, config.excluded_env_vars); diff --git a/src/lib.rs b/src/lib.rs index abed7ab9dfeb..ee13631727d2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,7 +43,10 @@ pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; pub use crate::mono_hash_map::MonoHashMap; -pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt, Tag, Permission, Stack, Stacks, Item}; +pub use crate::stacked_borrows::{ + EvalContextExt as StackedBorEvalContextExt, Tag, Permission, Stack, Stacks, Item, PtrId, + GlobalState, +}; pub use crate::machine::{ PAGE_SIZE, STACK_ADDR, STACK_SIZE, NUM_CPUS, MemoryExtra, AllocExtra, FrameData, MiriMemoryKind, Evaluator, MiriEvalContext, MiriEvalContextExt, diff --git a/src/machine.rs b/src/machine.rs index 65b6bcfb2ab7..3d8e724c57c3 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -77,9 +77,9 @@ pub struct MemoryExtra { } impl MemoryExtra { - pub fn new(rng: StdRng, validate: bool) -> Self { + pub fn new(rng: StdRng, validate: bool, tracked_id: Option) -> Self { MemoryExtra { - stacked_borrows: Default::default(), + stacked_borrows: Rc::new(RefCell::new(GlobalState::new(tracked_id))), intptrcast: Default::default(), rng: RefCell::new(rng), validate, diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 23a32fc2ac5c..bd42191821b7 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -105,6 +105,8 @@ pub struct GlobalState { next_call_id: CallId, /// Those call IDs corresponding to functions that are still running. active_calls: HashSet, + /// The id to trace in this execution run + tracked_id: Option, } /// Memory extra state gives us interior mutable access to the global state. pub type MemoryExtra = Rc>; @@ -151,18 +153,17 @@ impl fmt::Display for RefKind { } /// Utilities for initialization and ID generation -impl Default for GlobalState { - fn default() -> Self { +impl GlobalState { + pub fn new(tracked_id: Option) -> Self { GlobalState { next_ptr_id: NonZeroU64::new(1).unwrap(), base_ptr_ids: HashMap::default(), next_call_id: NonZeroU64::new(1).unwrap(), active_calls: HashSet::default(), + tracked_id, } } -} -impl GlobalState { fn new_ptr(&mut self) -> PtrId { let id = self.next_ptr_id; self.next_ptr_id = NonZeroU64::new(id.get() + 1).unwrap(); @@ -312,6 +313,11 @@ impl<'tcx> Stack { let first_incompatible_idx = self.find_first_write_incompatible(granting_idx); for item in self.borrows.drain(first_incompatible_idx..).rev() { trace!("access: popping item {:?}", item); + if let Tag::Tagged(id) = item.tag { + if Some(id) == global.tracked_id { + throw_unsup!(Unsupported(format!("popped id {}", id))); + } + } Stack::check_protector(&item, Some(tag), global)?; } } else { diff --git a/tests/compile-fail/stacked_borrows/track_id.rs b/tests/compile-fail/stacked_borrows/track_id.rs new file mode 100644 index 000000000000..67d38b119412 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/track_id.rs @@ -0,0 +1,19 @@ +// compile-flags: -Zmiri-track-id=1372 +// do not run on anything but x86_64 linux, because minute changes can change the borrow stack ids +// only-x86_64 +// only-linux + +use std::mem; + +fn main() { + let mut target = 42; + // Make sure we cannot use a raw-tagged `&mut` pointing to a frozen location. + // Even just creating it unfreezes. + let raw = &mut target as *mut _; // let this leak to raw + let reference = unsafe { &*raw }; // freeze + let ptr = reference as *const _ as *mut i32; // raw ptr, with raw tag + let _mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag + //~^ ERROR popped id 1372 + // Now we retag, making our ref top-of-stack -- and, in particular, unfreezing. + let _val = *reference; +} From a0de213e421fa64f293d4247a2e7225104d8b6d9 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 28 Nov 2019 11:14:16 +0100 Subject: [PATCH 1402/5092] Vocabulary fix --- tests/compile-fail/stacked_borrows/track_id.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile-fail/stacked_borrows/track_id.rs b/tests/compile-fail/stacked_borrows/track_id.rs index 67d38b119412..04f4f251fbaf 100644 --- a/tests/compile-fail/stacked_borrows/track_id.rs +++ b/tests/compile-fail/stacked_borrows/track_id.rs @@ -1,5 +1,5 @@ // compile-flags: -Zmiri-track-id=1372 -// do not run on anything but x86_64 linux, because minute changes can change the borrow stack ids +// do not run on anything but x86_64 linux, because minor libstd changes can change the borrow stack ids // only-x86_64 // only-linux From 67417945d4925e0c74277df2ba38d968791aba6d Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 28 Nov 2019 14:33:35 +0100 Subject: [PATCH 1403/5092] Detect all variants of stack removals --- src/stacked_borrows.rs | 10 +++++----- tests/compile-fail/stacked_borrows/track_id.rs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index bd42191821b7..be54b7f5abab 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -271,6 +271,11 @@ impl<'tcx> Stack { /// Check if the given item is protected. fn check_protector(item: &Item, tag: Option, global: &GlobalState) -> InterpResult<'tcx> { + if let Tag::Tagged(id) = item.tag { + if Some(id) == global.tracked_id { + throw_unsup!(Unsupported(format!("disabling item {:?} for tag {:?}", item, tag))); + } + } if let Some(call) = item.protector { if global.is_active(call) { if let Some(tag) = tag { @@ -313,11 +318,6 @@ impl<'tcx> Stack { let first_incompatible_idx = self.find_first_write_incompatible(granting_idx); for item in self.borrows.drain(first_incompatible_idx..).rev() { trace!("access: popping item {:?}", item); - if let Tag::Tagged(id) = item.tag { - if Some(id) == global.tracked_id { - throw_unsup!(Unsupported(format!("popped id {}", id))); - } - } Stack::check_protector(&item, Some(tag), global)?; } } else { diff --git a/tests/compile-fail/stacked_borrows/track_id.rs b/tests/compile-fail/stacked_borrows/track_id.rs index 04f4f251fbaf..e691603b5341 100644 --- a/tests/compile-fail/stacked_borrows/track_id.rs +++ b/tests/compile-fail/stacked_borrows/track_id.rs @@ -13,7 +13,7 @@ fn main() { let reference = unsafe { &*raw }; // freeze let ptr = reference as *const _ as *mut i32; // raw ptr, with raw tag let _mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag - //~^ ERROR popped id 1372 + //~^ ERROR disabling item [SharedReadOnly for <1372>] for tag Some() // Now we retag, making our ref top-of-stack -- and, in particular, unfreezing. let _val = *reference; } From eab25383174ec70b76395d079ad6e85dfd15f2ff Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 1 Dec 2019 00:02:58 +0100 Subject: [PATCH 1404/5092] Rename track-id to track-pointer-tag --- benches/helpers/miri_helper.rs | 2 +- src/bin/miri-rustc-tests.rs | 4 ++-- src/bin/miri.rs | 14 +++++++------- src/eval.rs | 4 ++-- src/machine.rs | 4 ++-- src/stacked_borrows.rs | 8 ++++---- tests/compile-fail/stacked_borrows/track_id.rs | 2 +- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 40683f8d7475..e2951110acdf 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -32,7 +32,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { excluded_env_vars: vec![], args: vec![], seed: None, - tracked_id: None, + tracked_pointer_tag: None, }; eval_main(tcx, entry_def_id, config); }); diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 8b1739f3443b..370d2a206178 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -45,7 +45,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { excluded_env_vars: vec![], args: vec![], seed: None, - tracked_id: None, + tracked_pointer_tag: None, }; let did = self.0.hir().body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); @@ -66,7 +66,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { excluded_env_vars: vec![], args: vec![], seed: None, - tracked_id: None, + tracked_pointer_tag: None, }; miri::eval_main(tcx, entry_def_id, config); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index e3aa75b9e880..48af81296257 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -126,7 +126,7 @@ fn main() { let mut communicate = false; let mut ignore_leaks = false; let mut seed: Option = None; - let mut tracked_id: Option = None; + let mut tracked_pointer_tag: Option = None; let mut rustc_args = vec![]; let mut miri_args = vec![]; let mut after_dashdash = false; @@ -177,15 +177,15 @@ fn main() { arg if arg.starts_with("-Zmiri-env-exclude=") => { excluded_env_vars.push(arg.trim_start_matches("-Zmiri-env-exclude=").to_owned()); }, - arg if arg.starts_with("-Zmiri-track-id=") => { - let id: u64 = match arg.trim_start_matches("-Zmiri-track-id=").parse() { + arg if arg.starts_with("-Zmiri-track-pointer-tag=") => { + let id: u64 = match arg.trim_start_matches("-Zmiri-track-pointer-tag=").parse() { Ok(id) => id, - Err(err) => panic!("-Zmiri-track-id requires a valid `u64` as the argument: {}", err), + Err(err) => panic!("-Zmiri-track-pointer-tag requires a valid `u64` as the argument: {}", err), }; if let Some(id) = miri::PtrId::new(id) { - tracked_id = Some(id); + tracked_pointer_tag = Some(id); } else { - panic!("-Zmiri-track-id must be a nonzero id"); + panic!("-Zmiri-track-pointer-tag must be a nonzero id"); } }, _ => { @@ -220,7 +220,7 @@ fn main() { excluded_env_vars, seed, args: miri_args, - tracked_id, + tracked_pointer_tag, }; rustc_driver::install_ice_hook(); let result = rustc_driver::catch_fatal_errors(move || { diff --git a/src/eval.rs b/src/eval.rs index fb82679523e3..81de2fa882c5 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -27,7 +27,7 @@ pub struct MiriConfig { /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`). pub seed: Option, /// The stacked borrow id to report about - pub tracked_id: Option, + pub tracked_pointer_tag: Option, } /// Details of premature program termination. @@ -49,7 +49,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), Evaluator::new(config.communicate), - MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate, config.tracked_id), + MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate, config.tracked_pointer_tag), ); // Complete initialization. EnvVars::init(&mut ecx, config.excluded_env_vars); diff --git a/src/machine.rs b/src/machine.rs index 3d8e724c57c3..d5cd86d97878 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -77,9 +77,9 @@ pub struct MemoryExtra { } impl MemoryExtra { - pub fn new(rng: StdRng, validate: bool, tracked_id: Option) -> Self { + pub fn new(rng: StdRng, validate: bool, tracked_pointer_tag: Option) -> Self { MemoryExtra { - stacked_borrows: Rc::new(RefCell::new(GlobalState::new(tracked_id))), + stacked_borrows: Rc::new(RefCell::new(GlobalState::new(tracked_pointer_tag))), intptrcast: Default::default(), rng: RefCell::new(rng), validate, diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index be54b7f5abab..ad70b05d8abd 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -106,7 +106,7 @@ pub struct GlobalState { /// Those call IDs corresponding to functions that are still running. active_calls: HashSet, /// The id to trace in this execution run - tracked_id: Option, + tracked_pointer_tag: Option, } /// Memory extra state gives us interior mutable access to the global state. pub type MemoryExtra = Rc>; @@ -154,13 +154,13 @@ impl fmt::Display for RefKind { /// Utilities for initialization and ID generation impl GlobalState { - pub fn new(tracked_id: Option) -> Self { + pub fn new(tracked_pointer_tag: Option) -> Self { GlobalState { next_ptr_id: NonZeroU64::new(1).unwrap(), base_ptr_ids: HashMap::default(), next_call_id: NonZeroU64::new(1).unwrap(), active_calls: HashSet::default(), - tracked_id, + tracked_pointer_tag, } } @@ -272,7 +272,7 @@ impl<'tcx> Stack { /// Check if the given item is protected. fn check_protector(item: &Item, tag: Option, global: &GlobalState) -> InterpResult<'tcx> { if let Tag::Tagged(id) = item.tag { - if Some(id) == global.tracked_id { + if Some(id) == global.tracked_pointer_tag { throw_unsup!(Unsupported(format!("disabling item {:?} for tag {:?}", item, tag))); } } diff --git a/tests/compile-fail/stacked_borrows/track_id.rs b/tests/compile-fail/stacked_borrows/track_id.rs index e691603b5341..35a0f04ee6f1 100644 --- a/tests/compile-fail/stacked_borrows/track_id.rs +++ b/tests/compile-fail/stacked_borrows/track_id.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-track-id=1372 +// compile-flags: -Zmiri-track-pointer-tag=1372 // do not run on anything but x86_64 linux, because minor libstd changes can change the borrow stack ids // only-x86_64 // only-linux From acb43f80fdd2fb8c81192a030d9c847d27fa502d Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 1 Dec 2019 00:03:06 +0100 Subject: [PATCH 1405/5092] Document the new flag --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 16eae05973b2..176b4c4c342d 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ Several `-Z` flags are relevant for Miri: the program has access to host resources such as environment variables and randomness (and, eventually, file systems and more). * `-Zmiri-ignore-leaks` disables the memory leak checker. -* `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from +* `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from the host. Can be used multiple times to exclude several variables. The `TERM` environment variable is excluded by default. * `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri @@ -171,6 +171,11 @@ Several `-Z` flags are relevant for Miri: sets this flag per default. * `-Zmir-emit-retag` controls whether `Retag` statements are emitted. Miri enables this per default because it is needed for validation. +* `-Zmiri-track-pointer-tag` aborts interpretation with a backtrace when the + given pointer tag is popped from a borrow stack (which is where the tag + becomes invalid and any future use of it will error anyway). This helps you + in finding out why UB is happening and where in your code would be a good + place to look for it. Moreover, Miri recognizes some environment variables: From 7cd0d7f15266eeebada17e51881b470561c3e697 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 1 Dec 2019 00:04:24 +0100 Subject: [PATCH 1406/5092] Remove a flaky test --- .../compile-fail/stacked_borrows/track_id.rs | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 tests/compile-fail/stacked_borrows/track_id.rs diff --git a/tests/compile-fail/stacked_borrows/track_id.rs b/tests/compile-fail/stacked_borrows/track_id.rs deleted file mode 100644 index 35a0f04ee6f1..000000000000 --- a/tests/compile-fail/stacked_borrows/track_id.rs +++ /dev/null @@ -1,19 +0,0 @@ -// compile-flags: -Zmiri-track-pointer-tag=1372 -// do not run on anything but x86_64 linux, because minor libstd changes can change the borrow stack ids -// only-x86_64 -// only-linux - -use std::mem; - -fn main() { - let mut target = 42; - // Make sure we cannot use a raw-tagged `&mut` pointing to a frozen location. - // Even just creating it unfreezes. - let raw = &mut target as *mut _; // let this leak to raw - let reference = unsafe { &*raw }; // freeze - let ptr = reference as *const _ as *mut i32; // raw ptr, with raw tag - let _mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag - //~^ ERROR disabling item [SharedReadOnly for <1372>] for tag Some() - // Now we retag, making our ref top-of-stack -- and, in particular, unfreezing. - let _val = *reference; -} From 817f4159a2146b95fd29fb5ea1725463e8f2dfd3 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 9 Dec 2019 14:29:28 +0100 Subject: [PATCH 1407/5092] Use the machine stop error instead of abusing other error kinds --- src/eval.rs | 3 +++ src/stacked_borrows.rs | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 81de2fa882c5..9a70663716d6 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -33,6 +33,7 @@ pub struct MiriConfig { /// Details of premature program termination. pub enum TerminationInfo { Exit(i64), + PoppedTrackedPointerTag(Item), Abort, } @@ -218,6 +219,8 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> .expect("invalid MachineStop payload"); match info { TerminationInfo::Exit(code) => return Some(*code), + TerminationInfo::PoppedTrackedPointerTag(item) => + format!("popped tracked tag for item {:?}", item), TerminationInfo::Abort => format!("the evaluated program aborted execution") } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index ad70b05d8abd..8782eb83d183 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -12,7 +12,7 @@ use rustc::hir::Mutability::{Mutable, Immutable}; use rustc::mir::RetagKind; use crate::{ - InterpResult, HelpersEvalContextExt, + InterpResult, HelpersEvalContextExt, TerminationInfo, MemoryKind, MiriMemoryKind, RangeMap, AllocId, Pointer, Immediate, ImmTy, PlaceTy, MPlaceTy, }; @@ -273,7 +273,7 @@ impl<'tcx> Stack { fn check_protector(item: &Item, tag: Option, global: &GlobalState) -> InterpResult<'tcx> { if let Tag::Tagged(id) = item.tag { if Some(id) == global.tracked_pointer_tag { - throw_unsup!(Unsupported(format!("disabling item {:?} for tag {:?}", item, tag))); + throw_machine_stop!(TerminationInfo::PoppedTrackedPointerTag(item.clone())); } } if let Some(call) = item.protector { From 8d409a7b593b32b6b1fa1914ce352efea1bb8095 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 10 Dec 2019 14:47:28 +0100 Subject: [PATCH 1408/5092] Update README.md Co-Authored-By: Ralf Jung --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 176b4c4c342d..5be16899a5ef 100644 --- a/README.md +++ b/README.md @@ -171,7 +171,7 @@ Several `-Z` flags are relevant for Miri: sets this flag per default. * `-Zmir-emit-retag` controls whether `Retag` statements are emitted. Miri enables this per default because it is needed for validation. -* `-Zmiri-track-pointer-tag` aborts interpretation with a backtrace when the +* `-Zmiri-track-pointer-tag=` aborts interpretation with a backtrace when the given pointer tag is popped from a borrow stack (which is where the tag becomes invalid and any future use of it will error anyway). This helps you in finding out why UB is happening and where in your code would be a good From f0d43872ad61b392d229319ae1a1478e8a558b11 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 13 Dec 2019 13:19:46 +0100 Subject: [PATCH 1409/5092] add test for sketchy vtable --- tests/compile-fail/issue-miri-1112.rs | 46 +++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 tests/compile-fail/issue-miri-1112.rs diff --git a/tests/compile-fail/issue-miri-1112.rs b/tests/compile-fail/issue-miri-1112.rs new file mode 100644 index 000000000000..29cc5c781200 --- /dev/null +++ b/tests/compile-fail/issue-miri-1112.rs @@ -0,0 +1,46 @@ +trait Empty {} + +#[repr(transparent)] +pub struct FunnyPointer(dyn Empty); + +#[repr(C)] +pub struct Meta { + drop_fn: fn(&mut ()), + size: usize, + align: usize, +} + +impl Meta { + pub fn new() -> Self { + Meta { + drop_fn: |_| {}, + size: 0, + align: 1, + } + } +} + +#[repr(C)] +pub struct FatPointer { + pub data: *const (), + pub vtable: *const (), +} + +impl FunnyPointer { + pub unsafe fn from_data_ptr(data: &String, ptr: *const Meta) -> &Self { + let obj = FatPointer { + data: data as *const _ as *const (), + vtable: ptr as *const _ as *const (), + }; + let obj = std::mem::transmute::(obj); //~ ERROR invalid drop fn in vtable + &*obj + } +} + +fn main() { + unsafe { + let meta = Meta::new(); + let hello = "hello".to_string(); + let _raw: &FunnyPointer = FunnyPointer::from_data_ptr(&hello, &meta as *const _); + } +} From bbd512d52f5203672452a8c476775bf27fe4b110 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 14 Dec 2019 12:06:01 +0100 Subject: [PATCH 1410/5092] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index bc65b5b6751b..afa5b6ae4861 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e862c01aadb2d029864f7bb256cf6c85bbb5d7e4 +12307b3b08edee543a78fb9d4a837fbd6d6ac0fa From 74ef63ff0aeeffc87b8d53f5fe3aadbe7cc00d3e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 15 Dec 2019 12:22:09 +0100 Subject: [PATCH 1411/5092] the never type got de-stabilized again; adjust tests --- rust-version | 2 +- tests/compile-fail/never_say_never.rs | 1 + tests/compile-fail/never_transmute_humans.rs | 2 ++ tests/compile-fail/never_transmute_void.rs | 1 + tests/run-pass/async-fn.rs | 2 ++ tests/run-pass/generator.rs | 2 +- tests/run-pass/loop-break-value.rs | 1 + tests/run-pass/panic/catch_panic.rs | 2 +- 8 files changed, 10 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index afa5b6ae4861..584f9f86b985 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -12307b3b08edee543a78fb9d4a837fbd6d6ac0fa +a605441e049f0b6d5f7715b94b8ac4662fd7fcf6 diff --git a/tests/compile-fail/never_say_never.rs b/tests/compile-fail/never_say_never.rs index 21fc16751c25..37dfe827d997 100644 --- a/tests/compile-fail/never_say_never.rs +++ b/tests/compile-fail/never_say_never.rs @@ -1,6 +1,7 @@ // This should fail even without validation // compile-flags: -Zmiri-disable-validation +#![feature(never_type)] #![allow(unreachable_code)] fn main() { diff --git a/tests/compile-fail/never_transmute_humans.rs b/tests/compile-fail/never_transmute_humans.rs index 5053be24ebf0..2e0d4e9bdf33 100644 --- a/tests/compile-fail/never_transmute_humans.rs +++ b/tests/compile-fail/never_transmute_humans.rs @@ -1,6 +1,8 @@ // This should fail even without validation // compile-flags: -Zmiri-disable-validation +#![feature(never_type)] + struct Human; fn main() { diff --git a/tests/compile-fail/never_transmute_void.rs b/tests/compile-fail/never_transmute_void.rs index a9cbac528d7a..2a822ab1b515 100644 --- a/tests/compile-fail/never_transmute_void.rs +++ b/tests/compile-fail/never_transmute_void.rs @@ -1,6 +1,7 @@ // This should fail even without validation // compile-flags: -Zmiri-disable-validation +#![feature(never_type)] #![allow(unused, invalid_value)] enum Void {} diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index a4c176ad8f12..90448aca1779 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -1,3 +1,5 @@ +#![feature(never_type)] + use std::{future::Future, pin::Pin, task::Poll, ptr}; use std::task::{Waker, RawWaker, RawWakerVTable, Context}; diff --git a/tests/run-pass/generator.rs b/tests/run-pass/generator.rs index 00ebba6344e2..c31b5b9ed3bb 100644 --- a/tests/run-pass/generator.rs +++ b/tests/run-pass/generator.rs @@ -1,4 +1,4 @@ -#![feature(generators, generator_trait)] +#![feature(generators, generator_trait, never_type)] use std::ops::{GeneratorState, Generator}; use std::pin::Pin; diff --git a/tests/run-pass/loop-break-value.rs b/tests/run-pass/loop-break-value.rs index 43acdc228202..bd7afa7ec1a8 100644 --- a/tests/run-pass/loop-break-value.rs +++ b/tests/run-pass/loop-break-value.rs @@ -1,3 +1,4 @@ +#![feature(never_type)] #![allow(unreachable_code)] #[allow(unused)] diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index a14dd411c1c6..722da68b70b2 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -1,6 +1,6 @@ // ignore-windows: Unwind panicking does not currently work on Windows +#![feature(never_type)] #![allow(const_err)] - use std::panic::{catch_unwind, AssertUnwindSafe}; use std::cell::Cell; From d9859c83fc416880f31f3fb8409ddb21673435f7 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 21 Dec 2019 11:45:09 +0100 Subject: [PATCH 1412/5092] Rustup to rustc 1.42.0-nightly (9ff30a781 2019-12-21) --- rust-version | 2 +- tests/compile-fail/stacked_borrows/illegal_write6.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 584f9f86b985..f3c0b833d1a1 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a605441e049f0b6d5f7715b94b8ac4662fd7fcf6 +9ff30a7810c586819a78188c173a7b74adbb9730 diff --git a/tests/compile-fail/stacked_borrows/illegal_write6.rs b/tests/compile-fail/stacked_borrows/illegal_write6.rs index 86f2c0f350e3..6985e7f0ead3 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write6.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write6.rs @@ -7,6 +7,6 @@ fn main() { fn foo(a: &mut u32, y: *mut u32) -> u32 { *a = 1; let _b = &*a; - unsafe { *y = 2; } //~ ERROR: borrow stack + unsafe { *y = 2; } //~ ERROR: not granting access to tag return *a; } From b0c7625dd109197cc38710da64e5eeb401f97379 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 30 Nov 2019 15:09:52 -0500 Subject: [PATCH 1413/5092] add `statx` shim for linux --- src/helpers.rs | 42 ++++++++ src/shims/env.rs | 8 +- src/shims/foreign_items.rs | 15 ++- src/shims/fs.rs | 198 ++++++++++++++++++++++++++++++++++++- src/shims/time.rs | 39 +++----- tests/run-pass/fs.rs | 38 ++++++- 6 files changed, 303 insertions(+), 37 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 05a92164f27d..ac63a3a9b3a4 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -509,3 +509,45 @@ fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; Ok(&OsStr::new(s)) } + +// FIXME: change `ImmTy::from_int` so it returns an `InterpResult` instead and remove this +// function. +pub fn immty_from_int_checked<'tcx>( + int: impl Into, + layout: TyLayout<'tcx>, +) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { + let int = int.into(); + // If `int` does not fit in `size` bits, we error instead of letting + // `ImmTy::from_int` panic. + let size = layout.size; + let truncated = truncate(int as u128, size); + if sign_extend(truncated, size) as i128 != int { + throw_unsup_format!( + "Signed value {:#x} does not fit in {} bits", + int, + size.bits() + ) + } + Ok(ImmTy::from_int(int, layout)) +} + +// FIXME: change `ImmTy::from_uint` so it returns an `InterpResult` instead and remove this +// function. +pub fn immty_from_uint_checked<'tcx>( + int: impl Into, + layout: TyLayout<'tcx>, +) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { + let int = int.into(); + // If `int` does not fit in `size` bits, we error instead of letting + // `ImmTy::from_int` panic. + let size = layout.size; + if truncate(int, size) != int { + throw_unsup_format!( + "Unsigned value {:#x} does not fit in {} bits", + int, + size.bits() + ) + } + Ok(ImmTy::from_uint(int, layout)) +} + diff --git a/src/shims/env.rs b/src/shims/env.rs index 8c431fd2016d..3994cf78780a 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -20,8 +20,12 @@ impl EnvVars { ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, mut excluded_env_vars: Vec, ) { - // Exclude `TERM` var to avoid terminfo trying to open the termcap file. - excluded_env_vars.push("TERM".to_owned()); + + // FIXME: this can be removed when we have the `stat64` shim for macos. + if ecx.tcx.sess.target.target.target_os.to_lowercase() != "linux" { + // Exclude `TERM` var to avoid terminfo trying to open the termcap file. + excluded_env_vars.push("TERM".to_owned()); + } if ecx.machine.communicate { for (name, value) in env::vars() { diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 316cc686ad77..3989f7f48a0b 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -303,14 +303,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .expect("Failed to get libc::SYS_getrandom") .to_machine_usize(this)?; - // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` - // is called if a `HashMap` is created the regular way (e.g. HashMap). + let sys_statx = this + .eval_path_scalar(&["libc", "SYS_statx"])? + .expect("Failed to get libc::SYS_statx") + .to_machine_usize(this)?; + match this.read_scalar(args[0])?.to_machine_usize(this)? { + // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` + // is called if a `HashMap` is created the regular way (e.g. HashMap). id if id == sys_getrandom => { // The first argument is the syscall id, // so skip over it. linux_getrandom(this, &args[1..], dest)?; } + id if id == sys_statx => { + // The first argument is the syscall id, + // so skip over it. + let result = this.statx(args[1], args[2], args[3], args[4], args[5])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } id => throw_unsup_format!("miri does not support syscall ID {}", id), } } diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 4d10be626460..47f3f50b76af 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1,12 +1,16 @@ use std::collections::HashMap; -use std::convert::TryFrom; +use std::convert::{TryInto, TryFrom}; use std::fs::{remove_file, File, OpenOptions}; use std::io::{Read, Write}; +use std::path::PathBuf; +use std::time::SystemTime; -use rustc::ty::layout::{Size, Align}; +use rustc::ty::layout::{Size, Align, LayoutOf}; use crate::stacked_borrows::Tag; use crate::*; +use helpers::immty_from_uint_checked; +use shims::time::system_time_to_duration; #[derive(Debug)] pub struct FileHandle { @@ -98,7 +102,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; - let fd = options.open(path).map(|file| { + let fd = options.open(&path).map(|file| { let mut fh = &mut this.machine.file_handler; fh.low += 1; fh.handles.insert(fh.low, FileHandle { file }).unwrap_none(); @@ -257,6 +261,181 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.try_unwrap_io_result(result) } + fn statx( + &mut self, + dirfd_op: OpTy<'tcx, Tag>, // Should be an `int` + pathname_op: OpTy<'tcx, Tag>, // Should be a `const char *` + flags_op: OpTy<'tcx, Tag>, // Should be an `int` + _mask_op: OpTy<'tcx, Tag>, // Should be an `unsigned int` + statxbuf_op: OpTy<'tcx, Tag> // Should be a `struct statx *` + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.check_no_isolation("statx")?; + + let statxbuf_scalar = this.read_scalar(statxbuf_op)?.not_undef()?; + let pathname_scalar = this.read_scalar(pathname_op)?.not_undef()?; + + // If the statxbuf or pathname pointers are null, the function fails with `EFAULT`. + if this.is_null(statxbuf_scalar)? || this.is_null(pathname_scalar)? { + let efault = this.eval_libc("EFAULT")?; + this.set_last_error(efault)?; + return Ok(-1); + } + + // Under normal circumstances, we would use `deref_operand(statxbuf_op)` to produce a + // proper `MemPlace` and then write the results of this function to it. However, the + // `syscall` function is untyped. This means that all the `statx` parameters are provided + // 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_place = { + // 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); + let statxbuf_ty = this.tcx.mk_mut_ptr(statx_ty); + let statxbuf_layout = this.layout_of(statxbuf_ty)?; + let statxbuf_imm = ImmTy::from_scalar(statxbuf_scalar, statxbuf_layout); + this.ref_to_mplace(statxbuf_imm)? + }; + + let path: PathBuf = this.read_os_str_from_c_str(pathname_scalar)?.into(); + // `flags` should be a `c_int` but the `syscall` function provides an `isize`. + let flags: i32 = this + .read_scalar(flags_op)? + .to_machine_isize(&*this.tcx)? + .try_into() + .map_err(|e| err_unsup_format!( + "Failed to convert pointer sized operand to integer: {}", + e + ))?; + // `dirfd` should be a `c_int` but the `syscall` function provides an `isize`. + let dirfd: i32 = this + .read_scalar(dirfd_op)? + .to_machine_isize(&*this.tcx)? + .try_into() + .map_err(|e| err_unsup_format!( + "Failed to convert pointer sized operand to integer: {}", + e + ))?; + // we only support interpreting `path` as an absolute directory or as a directory relative + // to `dirfd` when the latter is `AT_FDCWD`. The behavior of `statx` with a relative path + // and a directory file descriptor other than `AT_FDCWD` is specified but it cannot be + // tested from `libstd`. If you found this error, please open an issue reporting it. + if !(path.is_absolute() || dirfd == this.eval_libc_i32("AT_FDCWD")?) + { + throw_unsup_format!( + "Using statx with a relative path and a file descriptor different from `AT_FDCWD` is not supported" + ) + } + + // the `_mask_op` paramter specifies the file information that the caller requested. + // However `statx` is allowed to return information that was not requested or to not + // return information that was requested. This `mask` represents the information we can + // actually provide in any host platform. + let mut mask = + this.eval_libc("STATX_TYPE")?.to_u32()? | this.eval_libc("STATX_SIZE")?.to_u32()?; + + // If the `AT_SYMLINK_NOFOLLOW` flag is set, we query the file's metadata without following + // symbolic links. + let metadata = if flags & this.eval_libc("AT_SYMLINK_NOFOLLOW")?.to_i32()? != 0 { + // FIXME: metadata for symlinks need testing. + std::fs::symlink_metadata(path) + } else { + std::fs::metadata(path) + }; + + let metadata = match metadata { + Ok(metadata) => metadata, + Err(e) => { + this.set_last_error_from_io_error(e)?; + return Ok(-1); + } + }; + + let file_type = metadata.file_type(); + + let mode_name = if file_type.is_file() { + "S_IFREG" + } else if file_type.is_dir() { + "S_IFDIR" + } else { + "S_IFLNK" + }; + + // The `mode` field specifies the type of the file and the permissions over the file for + // the owner, its group and other users. Given that we can only provide the file type + // without using platform specific methods, we only set the bits corresponding to the file + // type. This should be an `__u16` but `libc` provides its values as `u32`. + let mode: u16 = this.eval_libc(mode_name)? + .to_u32()? + .try_into() + .unwrap_or_else(|_| bug!("libc contains bad value for `{}` constant", mode_name)); + + let size = metadata.len(); + + let (access_sec, access_nsec) = extract_sec_and_nsec( + metadata.accessed(), + &mut mask, + this.eval_libc("STATX_ATIME")?.to_u32()? + )?; + + let (created_sec, created_nsec) = extract_sec_and_nsec( + metadata.created(), + &mut mask, + this.eval_libc("STATX_BTIME")?.to_u32()? + )?; + + let (modified_sec, modified_nsec) = extract_sec_and_nsec( + metadata.modified(), + &mut mask, + this.eval_libc("STATX_MTIME")?.to_u32()? + )?; + + let __u32_layout = this.libc_ty_layout("__u32")?; + let __u64_layout = this.libc_ty_layout("__u64")?; + let __u16_layout = this.libc_ty_layout("__u16")?; + + // Now we transform all this fields into `ImmTy`s and write them to `statxbuf`. We write a + // zero for the unavailable fields. + // FIXME: Provide more fields using platform specific methods. + let imms = [ + immty_from_uint_checked(mask, __u32_layout)?, // stx_mask + immty_from_uint_checked(0u128, __u32_layout)?, // stx_blksize + immty_from_uint_checked(0u128, __u64_layout)?, // stx_attributes + immty_from_uint_checked(0u128, __u32_layout)?, // stx_nlink + immty_from_uint_checked(0u128, __u32_layout)?, // stx_uid + immty_from_uint_checked(0u128, __u32_layout)?, // stx_gid + immty_from_uint_checked(mode, __u16_layout)?, // stx_mode + immty_from_uint_checked(0u128, __u16_layout)?, // statx padding + immty_from_uint_checked(0u128, __u64_layout)?, // stx_ino + immty_from_uint_checked(size, __u64_layout)?, // stx_size + immty_from_uint_checked(0u128, __u64_layout)?, // stx_blocks + immty_from_uint_checked(0u128, __u64_layout)?, // stx_attributes + immty_from_uint_checked(access_sec, __u64_layout)?, // stx_atime.tv_sec + immty_from_uint_checked(access_nsec, __u32_layout)?, // stx_atime.tv_nsec + immty_from_uint_checked(0u128, __u32_layout)?, // statx_timestamp padding + immty_from_uint_checked(created_sec, __u64_layout)?, // stx_btime.tv_sec + immty_from_uint_checked(created_nsec, __u32_layout)?, // stx_btime.tv_nsec + immty_from_uint_checked(0u128, __u32_layout)?, // statx_timestamp padding + immty_from_uint_checked(0u128, __u64_layout)?, // stx_ctime.tv_sec + immty_from_uint_checked(0u128, __u32_layout)?, // stx_ctime.tv_nsec + immty_from_uint_checked(0u128, __u32_layout)?, // statx_timestamp padding + immty_from_uint_checked(modified_sec, __u64_layout)?, // stx_mtime.tv_sec + immty_from_uint_checked(modified_nsec, __u32_layout)?, // stx_mtime.tv_nsec + immty_from_uint_checked(0u128, __u32_layout)?, // statx_timestamp padding + immty_from_uint_checked(0u128, __u64_layout)?, // stx_rdev_major + immty_from_uint_checked(0u128, __u64_layout)?, // stx_rdev_minor + immty_from_uint_checked(0u128, __u64_layout)?, // stx_dev_major + immty_from_uint_checked(0u128, __u64_layout)?, // stx_dev_minor + ]; + + this.write_packed_immediates(&statxbuf_place, &imms)?; + + Ok(0) + } + /// Function used when a handle is not found inside `FileHandler`. It returns `Ok(-1)`and sets /// the last OS error to `libc::EBADF` (invalid file descriptor). This function uses /// `T: From` instead of `i32` directly because some fs functions return different integer @@ -268,3 +447,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok((-1).into()) } } + +// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch, and +// then sets the `mask` bits determined by `flag` when `time` is Ok. If `time` is an error, it +// returns `(0, 0)` without setting any bits. +fn extract_sec_and_nsec<'tcx>(time: std::io::Result, mask: &mut u32, flag: u32) -> InterpResult<'tcx, (u64, u32)> { + if let Ok(time) = time { + let duration = system_time_to_duration(&time)?; + *mask |= flag; + Ok((duration.as_secs(), duration.subsec_nanos())) + } else { + Ok((0, 0)) + } +} diff --git a/src/shims/time.rs b/src/shims/time.rs index d75cb7bad384..da9ea07c4f25 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -1,34 +1,19 @@ use std::time::{Duration, SystemTime}; -use rustc::ty::layout::TyLayout; - use crate::stacked_borrows::Tag; use crate::*; +use helpers::immty_from_int_checked; -// Returns the time elapsed between now and the unix epoch as a `Duration` and the sign of the time -// interval +// Returns the time elapsed between now and the unix epoch as a `Duration`. fn get_time<'tcx>() -> InterpResult<'tcx, Duration> { - SystemTime::now() - .duration_since(SystemTime::UNIX_EPOCH) - .map_err(|_| err_unsup_format!("Times before the Unix epoch are not supported").into()) + system_time_to_duration(&SystemTime::now()) } -fn int_to_immty_checked<'tcx>( - int: i128, - layout: TyLayout<'tcx>, -) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { - // If `int` does not fit in `size` bits, we error instead of letting - // `ImmTy::from_int` panic. - let size = layout.size; - let truncated = truncate(int as u128, size); - if sign_extend(truncated, size) as i128 != int { - throw_unsup_format!( - "Signed value {:#x} does not fit in {} bits", - int, - size.bits() - ) - } - Ok(ImmTy::from_int(int, layout)) +// Returns the time elapsed between the provided time and the unix epoch as a `Duration`. +pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Duration> { + time + .duration_since(SystemTime::UNIX_EPOCH) + .map_err(|_| err_unsup_format!("Times before the Unix epoch are not supported").into()) } impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -57,8 +42,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tv_nsec = duration.subsec_nanos() as i128; let imms = [ - int_to_immty_checked(tv_sec, this.libc_ty_layout("time_t")?)?, - int_to_immty_checked(tv_nsec, this.libc_ty_layout("c_long")?)?, + immty_from_int_checked(tv_sec, this.libc_ty_layout("time_t")?)?, + immty_from_int_checked(tv_nsec, this.libc_ty_layout("c_long")?)?, ]; this.write_packed_immediates(&tp, &imms)?; @@ -89,8 +74,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tv_usec = duration.subsec_micros() as i128; let imms = [ - int_to_immty_checked(tv_sec, this.libc_ty_layout("time_t")?)?, - int_to_immty_checked(tv_usec, this.libc_ty_layout("suseconds_t")?)?, + immty_from_int_checked(tv_sec, this.libc_ty_layout("time_t")?)?, + immty_from_int_checked(tv_usec, this.libc_ty_layout("suseconds_t")?)?, ]; this.write_packed_immediates(&tv, &imms)?; diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 7765e5b368e8..b8f9e3229af6 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -2,11 +2,32 @@ // compile-flags: -Zmiri-disable-isolation use std::fs::{File, remove_file}; -use std::io::{Read, Write, ErrorKind}; +use std::io::{Read, Write, ErrorKind, Result}; +use std::path::{PathBuf, Path}; + +#[cfg(target_os = "linux")] +fn test_metadata(bytes: &[u8], path: &Path) -> Result<()> { + // Test that the file metadata is correct. + let metadata = path.metadata()?; + // `path` should point to a file. + assert!(metadata.is_file()); + // The size of the file must be equal to the number of written bytes. + assert_eq!(bytes.len() as u64, metadata.len()); + Ok(()) +} + +// FIXME: Implement stat64 for macos. +#[cfg(not(target_os = "linux"))] +fn test_metadata(_bytes: &[u8], _path: &Path) -> Result<()> { + Ok(()) +} fn main() { - let path = std::env::temp_dir().join("miri_test_fs.txt"); + let tmp = std::env::temp_dir(); + let filename = PathBuf::from("miri_test_fs.txt"); + let path = tmp.join(&filename); let bytes = b"Hello, World!\n"; + // Test creating, writing and closing a file (closing is tested when `file` is dropped). let mut file = File::create(&path).unwrap(); // Writing 0 bytes should not change the file contents. @@ -21,7 +42,14 @@ fn main() { // Reading until EOF should get the whole text. file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); - // Removing file should succeed + + // Test that metadata of an absolute path is correct. + test_metadata(bytes, &path).unwrap(); + // Test that metadata of a relative path is correct. + std::env::set_current_dir(tmp).unwrap(); + test_metadata(bytes, &filename).unwrap(); + + // Removing file should succeed. remove_file(&path).unwrap(); // The two following tests also check that the `__errno_location()` shim is working properly. @@ -29,4 +57,8 @@ fn main() { assert_eq!(ErrorKind::NotFound, File::open(&path).unwrap_err().kind()); // Removing a non-existing file should fail with a "not found" error. assert_eq!(ErrorKind::NotFound, remove_file(&path).unwrap_err().kind()); + // Reading the metadata of a non-existing file should fail with a "not found" error. + if cfg!(target_os = "linux") { // FIXME: Implement stat64 for macos. + assert_eq!(ErrorKind::NotFound, test_metadata(bytes, &path).unwrap_err().kind()); + } } From bc715cb6469015012a3d77dbd84a648c9380873e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Dec 2019 18:13:13 +0100 Subject: [PATCH 1414/5092] disable sysroot checks for distributed binaries --- src/bin/cargo-miri.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index f4fb13518e30..e5c722860091 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -148,10 +148,11 @@ fn test_sysroot_consistency() { .unwrap_or_else(|_| panic!("Failed to canonicalize sysroot: {}", stdout)) } - // We let the user skip this check if they really want to. - // (`bootstrap` needs this because Miri gets built by the stage1 compiler - // but run with the stage2 sysroot.) - if std::env::var("MIRI_SKIP_SYSROOT_CHECK").is_ok() { + // Do not check sysroots if we got built as part of a Rust distribution. + // During `bootstrap`, the sysroot does not match anyway, and then some distros + // play symlink tricks so the sysroots may be different even for the final stage + // (see ). + if option_env!("RUSTC_STAGE").is_some() { return; } From 7ead530841a7c16d2228504978a7ab34e08d0b40 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 23 Dec 2019 12:56:23 +0100 Subject: [PATCH 1415/5092] Rustfmt all the things --- benches/fibonacci.rs | 4 +- benches/helpers/miri_helper.rs | 27 ++-- benches/smoke.rs | 2 +- rustfmt.toml | 3 + src/bin/cargo-miri.rs | 195 ++++++++++++----------- src/bin/miri-rustc-tests.rs | 91 +++++++---- src/bin/miri.rs | 70 +++++---- src/eval.rs | 50 +++--- src/helpers.rs | 140 ++++++++--------- src/intptrcast.rs | 19 ++- src/lib.rs | 48 +++--- src/machine.rs | 35 ++--- src/mono_hash_map.rs | 35 ++--- src/operator.rs | 38 ++--- src/range_map.rs | 208 ++++++++++++------------- src/shims/dlsym.rs | 3 +- src/shims/foreign_items.rs | 162 +++++++++++-------- src/shims/fs.rs | 94 ++++++------ src/shims/intrinsics.rs | 273 ++++++++++++++++++--------------- src/shims/mod.rs | 27 ++-- src/shims/panic.rs | 26 ++-- src/shims/time.rs | 5 +- src/shims/tls.rs | 21 +-- src/stacked_borrows.rs | 193 ++++++++++------------- tests/compiletest.rs | 34 ++-- 25 files changed, 905 insertions(+), 898 deletions(-) create mode 100644 rustfmt.toml diff --git a/benches/fibonacci.rs b/benches/fibonacci.rs index 10c119d9017a..ebb1b5fd0b18 100644 --- a/benches/fibonacci.rs +++ b/benches/fibonacci.rs @@ -7,7 +7,7 @@ use crate::helpers::*; #[bench] fn fib(bencher: &mut Bencher) { - bencher.iter(|| { fibonacci_helper::main(); }) + bencher.iter(|| fibonacci_helper::main()) } #[bench] @@ -17,7 +17,7 @@ fn fib_miri(bencher: &mut Bencher) { #[bench] fn fib_iter(bencher: &mut Bencher) { - bencher.iter(|| { fibonacci_helper_iterative::main(); }) + bencher.iter(|| fibonacci_helper_iterative::main()) } #[bench] diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index e2951110acdf..92aedcc4244a 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -6,23 +6,26 @@ extern crate rustc_interface; extern crate test; use self::miri::eval_main; -use rustc::hir::def_id::LOCAL_CRATE; -use rustc_interface::{interface, Queries}; -use rustc_driver::Compilation; use crate::test::Bencher; +use rustc::hir::def_id::LOCAL_CRATE; +use rustc_driver::Compilation; +use rustc_interface::{interface, Queries}; struct MiriCompilerCalls<'a> { bencher: &'a mut Bencher, } impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { - fn after_analysis<'tcx>(&mut self, compiler: &interface::Compiler, queries: &'tcx Queries<'tcx>) -> Compilation { + fn after_analysis<'tcx>( + &mut self, + compiler: &interface::Compiler, + queries: &'tcx Queries<'tcx>, + ) -> Compilation { compiler.session().abort_if_errors(); queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { - let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect( - "no main or start function found", - ); + let (entry_def_id, _) = + tcx.entry_fn(LOCAL_CRATE).expect("no main or start function found"); self.bencher.iter(|| { let config = miri::MiriConfig { @@ -50,13 +53,9 @@ fn find_sysroot() -> String { let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); match (home, toolchain) { (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain), - _ => { - option_env!("RUST_SYSROOT") - .expect( - "need to specify RUST_SYSROOT env var or use rustup or multirust", - ) - .to_owned() - } + _ => option_env!("RUST_SYSROOT") + .expect("need to specify RUST_SYSROOT env var or use rustup or multirust") + .to_owned(), } } diff --git a/benches/smoke.rs b/benches/smoke.rs index 7d614e268298..9229e972d7f3 100644 --- a/benches/smoke.rs +++ b/benches/smoke.rs @@ -7,7 +7,7 @@ use crate::helpers::*; #[bench] fn noop(bencher: &mut Bencher) { - bencher.iter(|| { smoke_helper::main(); }) + bencher.iter(|| smoke_helper::main()) } /* diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 000000000000..a0d494b335a8 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,3 @@ +use_small_heuristics = "Max" +version = "Two" +match_arm_blocks = false diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index f4fb13518e30..955167bc425d 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -1,10 +1,10 @@ #![feature(inner_deref)] use std::fs::{self, File}; -use std::io::{self, Write, BufRead}; -use std::path::{PathBuf, Path}; -use std::process::Command; +use std::io::{self, BufRead, Write}; use std::ops::Not; +use std::path::{Path, PathBuf}; +use std::process::Command; const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 17); @@ -40,8 +40,12 @@ fn show_help() { } fn show_version() { - println!("miri {} ({} {})", - env!("CARGO_PKG_VERSION"), env!("VERGEN_SHA_SHORT"), env!("VERGEN_COMMIT_DATE")); + println!( + "miri {} ({} {})", + env!("CARGO_PKG_VERSION"), + env!("VERGEN_SHA_SHORT"), + env!("VERGEN_COMMIT_DATE") + ); } fn show_error(msg: String) -> ! { @@ -80,11 +84,10 @@ fn get_arg_flag_value(name: &str) -> Option { } } -fn list_targets() -> impl Iterator { +fn list_targets() -> impl Iterator { // We need to get the manifest, and then the metadata, to enumerate targets. - let manifest_path = get_arg_flag_value("--manifest-path").map(|m| - Path::new(&m).canonicalize().unwrap() - ); + let manifest_path = + get_arg_flag_value("--manifest-path").map(|m| Path::new(&m).canonicalize().unwrap()); let mut cmd = cargo_metadata::MetadataCommand::new(); if let Some(ref manifest_path) = manifest_path { @@ -106,16 +109,18 @@ fn list_targets() -> impl Iterator { if let Some(ref manifest_path) = manifest_path { package_manifest_path == manifest_path } else { - let current_dir = current_dir.as_ref().expect( - "could not read current directory", - ); - let package_manifest_directory = package_manifest_path.parent().expect( - "could not find parent directory of package manifest", - ); + let current_dir = current_dir.as_ref().expect("could not read current directory"); + let package_manifest_directory = package_manifest_path + .parent() + .expect("could not find parent directory of package manifest"); package_manifest_directory == current_dir } }) - .unwrap_or_else(|| show_error(format!("This seems to be a workspace, which is not supported by cargo-miri"))); + .unwrap_or_else(|| { + show_error(format!( + "This seems to be a workspace, which is not supported by cargo-miri" + )) + }); let package = metadata.packages.remove(package_index); // Finally we got the list of targets to build @@ -134,17 +139,24 @@ fn find_miri() -> PathBuf { /// toolchain than what is used when `cargo miri` is run. fn test_sysroot_consistency() { fn get_sysroot(mut cmd: Command) -> PathBuf { - let out = cmd.arg("--print").arg("sysroot") - .output().expect("Failed to run rustc to get sysroot info"); + let out = cmd + .arg("--print") + .arg("sysroot") + .output() + .expect("Failed to run rustc to get sysroot info"); let stdout = String::from_utf8(out.stdout).expect("stdout is not valid UTF-8"); let stderr = String::from_utf8(out.stderr).expect("stderr is not valid UTF-8"); assert!( out.status.success(), "Bad status code {} when getting sysroot info via {:?}.\nstdout:\n{}\nstderr:\n{}", - out.status, cmd, stdout, stderr, + out.status, + cmd, + stdout, + stderr, ); let stdout = stdout.trim(); - PathBuf::from(stdout).canonicalize() + PathBuf::from(stdout) + .canonicalize() .unwrap_or_else(|_| panic!("Failed to canonicalize sysroot: {}", stdout)) } @@ -164,7 +176,8 @@ fn test_sysroot_consistency() { Make sure you use the same toolchain to run miri that you used to build it!\n\ rustc sysroot: `{}`\n\ miri sysroot: `{}`", - rustc_sysroot.display(), miri_sysroot.display() + rustc_sysroot.display(), + miri_sysroot.display() )); } } @@ -193,28 +206,36 @@ fn xargo_version() -> Option<(u32, u32, u32)> { return None; } // Parse output. The first line looks like "xargo 0.3.12 (b004f1c 2018-12-13)". - let line = out.stderr.lines().nth(0) + let line = out + .stderr + .lines() + .nth(0) .expect("malformed `xargo --version` output: not at least one line") .expect("malformed `xargo --version` output: error reading first line"); let (name, version) = { let mut split = line.split(' '); - (split.next().expect("malformed `xargo --version` output: empty"), - split.next().expect("malformed `xargo --version` output: not at least two words")) + ( + split.next().expect("malformed `xargo --version` output: empty"), + split.next().expect("malformed `xargo --version` output: not at least two words"), + ) }; if name != "xargo" { // This is some fork of xargo return None; } let mut version_pieces = version.split('.'); - let major = version_pieces.next() + let major = version_pieces + .next() .expect("malformed `xargo --version` output: not a major version piece") .parse() .expect("malformed `xargo --version` output: major version is not an integer"); - let minor = version_pieces.next() + let minor = version_pieces + .next() .expect("malformed `xargo --version` output: not a minor version piece") .parse() .expect("malformed `xargo --version` output: minor version is not an integer"); - let patch = version_pieces.next() + let patch = version_pieces + .next() .expect("malformed `xargo --version` output: not a patch version piece") .parse() .expect("malformed `xargo --version` output: patch version is not an integer"); @@ -232,18 +253,15 @@ fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { io::stdin().read_line(&mut buf).unwrap(); match buf.trim().to_lowercase().as_ref() { // Proceed. - "" | "y" | "yes" => {}, + "" | "y" | "yes" => {} "n" | "no" => show_error(format!("Aborting as per your request")), - a => show_error(format!("I do not understand `{}`", a)) + a => show_error(format!("I do not understand `{}`", a)), }; } else { println!("Running `{:?}` to {}.", cmd, text); } - if cmd.status() - .expect(&format!("failed to execute {:?}", cmd)) - .success().not() - { + if cmd.status().expect(&format!("failed to execute {:?}", cmd)).success().not() { show_error(format!("Failed to {}", text)); } } @@ -275,7 +293,9 @@ fn setup(ask_user: bool) { Ok(val) => PathBuf::from(val), Err(_) => { // Check for `rust-src` rustup component. - let sysroot = Command::new("rustc").args(&["--print", "sysroot"]).output() + let sysroot = Command::new("rustc") + .args(&["--print", "sysroot"]) + .output() .expect("failed to get rustc sysroot") .stdout; let sysroot = std::str::from_utf8(&sysroot).unwrap(); @@ -298,7 +318,11 @@ fn setup(ask_user: bool) { // Fallback: Ask the user to install the `rust-src` component, and use that. let mut cmd = Command::new("rustup"); cmd.args(&["component", "add", "rust-src"]); - ask_to_run(cmd, ask_user, "install the rustc-src component for the selected toolchain"); + ask_to_run( + cmd, + ask_user, + "install the rustc-src component for the selected toolchain", + ); rustup_src } } @@ -317,8 +341,10 @@ fn setup(ask_user: bool) { fs::create_dir_all(&dir).unwrap(); } // The interesting bit: Xargo.toml - File::create(dir.join("Xargo.toml")).unwrap() - .write_all(br#" + File::create(dir.join("Xargo.toml")) + .unwrap() + .write_all( + br#" [dependencies.std] default_features = false # We need the `panic_unwind` feature because we use the `unwind` panic strategy. @@ -326,10 +352,14 @@ default_features = false features = ["panic_unwind"] [dependencies.test] - "#).unwrap(); + "#, + ) + .unwrap(); // The boring bits: a dummy project for xargo. - File::create(dir.join("Cargo.toml")).unwrap() - .write_all(br#" + File::create(dir.join("Cargo.toml")) + .unwrap() + .write_all( + br#" [package] name = "miri-xargo" description = "A dummy project for building libstd with xargo." @@ -337,7 +367,9 @@ version = "0.0.0" [lib] path = "lib.rs" - "#).unwrap(); + "#, + ) + .unwrap(); File::create(dir.join("lib.rs")).unwrap(); // Prepare xargo invocation. let target = get_arg_flag_value("--target"); @@ -355,10 +387,7 @@ path = "lib.rs" command.arg("--target").arg(&target); } // Finally run it! - if command.status() - .expect("failed to run xargo") - .success().not() - { + if command.status().expect("failed to run xargo").success().not() { show_error(format!("Failed to run xargo")); } @@ -413,9 +442,7 @@ fn in_cargo_miri() { Some(s) if s.starts_with("-") => (MiriCommand::Run, 2), None => (MiriCommand::Run, 2), // Invalid command. - Some(s) => { - show_error(format!("Unknown command `{}`", s)) - } + Some(s) => show_error(format!("Unknown command `{}`", s)), }; let verbose = has_arg_flag("-v"); @@ -433,9 +460,10 @@ fn in_cargo_miri() { // Now run the command. for target in list_targets() { let mut args = std::env::args().skip(skip); - let kind = target.kind.get(0).expect( - "badly formatted cargo metadata: target::kind is an empty array", - ); + let kind = target + .kind + .get(0) + .expect("badly formatted cargo metadata: target::kind is an empty array"); // Now we run `cargo rustc $FLAGS $ARGS`, giving the user the // change to add additional arguments. `FLAGS` is set to identify // this target. The user gets to control what gets actually passed to Miri. @@ -470,22 +498,15 @@ fn in_cargo_miri() { // Add `--` (to end the `cargo` flags), and then the user flags. We add markers around the // user flags to be able to identify them later. "cargo rustc" adds more stuff after this, // so we have to mark both the beginning and the end. - cmd - .arg("--") - .arg("cargo-miri-marker-begin") - .args(args) - .arg("cargo-miri-marker-end"); + cmd.arg("--").arg("cargo-miri-marker-begin").args(args).arg("cargo-miri-marker-end"); let path = std::env::current_exe().expect("current executable path invalid"); cmd.env("RUSTC_WRAPPER", path); if verbose { eprintln!("+ {:?}", cmd); } - let exit_status = cmd - .spawn() - .expect("could not run cargo") - .wait() - .expect("failed to wait for cargo?"); + let exit_status = + cmd.spawn().expect("could not run cargo").wait().expect("failed to wait for cargo?"); if !exit_status.success() { std::process::exit(exit_status.code().unwrap_or(-1)) @@ -497,49 +518,43 @@ fn inside_cargo_rustc() { let sysroot = std::env::var("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); let rustc_args = std::env::args().skip(2); // skip `cargo rustc` - let mut args: Vec = rustc_args - .chain(Some("--sysroot".to_owned())) - .chain(Some(sysroot)) - .collect(); + let mut args: Vec = + rustc_args.chain(Some("--sysroot".to_owned())).chain(Some(sysroot)).collect(); args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string)); // See if we can find the `cargo-miri` markers. Those only get added to the binary we want to // run. They also serve to mark the user-defined arguments, which we have to move all the way // to the end (they get added somewhere in the middle). - let needs_miri = if let Some(begin) = args.iter().position(|arg| arg == "cargo-miri-marker-begin") { - let end = args - .iter() - .position(|arg| arg == "cargo-miri-marker-end") - .expect("cannot find end marker"); - // These mark the user arguments. We remove the first and last as they are the markers. - let mut user_args = args.drain(begin..=end); - assert_eq!(user_args.next().unwrap(), "cargo-miri-marker-begin"); - assert_eq!(user_args.next_back().unwrap(), "cargo-miri-marker-end"); - // Collect the rest and add it back at the end. - let mut user_args = user_args.collect::>(); - args.append(&mut user_args); - // Run this in Miri. - true - } else { - false - }; + let needs_miri = + if let Some(begin) = args.iter().position(|arg| arg == "cargo-miri-marker-begin") { + let end = args + .iter() + .position(|arg| arg == "cargo-miri-marker-end") + .expect("cannot find end marker"); + // These mark the user arguments. We remove the first and last as they are the markers. + let mut user_args = args.drain(begin..=end); + assert_eq!(user_args.next().unwrap(), "cargo-miri-marker-begin"); + assert_eq!(user_args.next_back().unwrap(), "cargo-miri-marker-end"); + // Collect the rest and add it back at the end. + let mut user_args = user_args.collect::>(); + args.append(&mut user_args); + // Run this in Miri. + true + } else { + false + }; - let mut command = if needs_miri { - Command::new(find_miri()) - } else { - Command::new("rustc") - }; + let mut command = if needs_miri { Command::new(find_miri()) } else { Command::new("rustc") }; command.args(&args); if has_arg_flag("-v") { eprintln!("+ {:?}", command); } match command.status() { - Ok(exit) => { + Ok(exit) => if !exit.success() { std::process::exit(exit.code().unwrap_or(42)); - } - } + }, Err(ref e) if needs_miri => panic!("error during miri run: {:?}", e), Err(ref e) => panic!("error during rustc call: {:?}", e), } diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 370d2a206178..19816fe008f5 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -1,25 +1,24 @@ #![feature(rustc_private)] -extern crate miri; extern crate getopts; +extern crate miri; extern crate rustc; -extern crate rustc_metadata; +extern crate rustc_codegen_utils; extern crate rustc_driver; extern crate rustc_errors; -extern crate rustc_codegen_utils; extern crate rustc_interface; +extern crate rustc_metadata; extern crate syntax; -use std::path::Path; -use std::io::Write; -use std::sync::{Mutex, Arc}; use std::io; +use std::io::Write; +use std::path::Path; +use std::sync::{Arc, Mutex}; - -use rustc_interface::{interface, Queries}; +use rustc::hir::def_id::LOCAL_CRATE; use rustc::hir::{self, itemlikevisit}; use rustc::ty::TyCtxt; -use rustc::hir::def_id::LOCAL_CRATE; use rustc_driver::Compilation; +use rustc_interface::{interface, Queries}; use miri::MiriConfig; @@ -29,7 +28,11 @@ struct MiriCompilerCalls { } impl rustc_driver::Callbacks for MiriCompilerCalls { - fn after_analysis<'tcx>(&mut self, compiler: &interface::Compiler, queries: &'tcx Queries<'tcx>) -> Compilation { + fn after_analysis<'tcx>( + &mut self, + compiler: &interface::Compiler, + queries: &'tcx Queries<'tcx>, + ) -> Compilation { compiler.session().abort_if_errors(); queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { if std::env::args().any(|arg| arg == "--test") { @@ -37,7 +40,8 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { impl<'tcx, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.kind { - if i.attrs.iter().any(|attr| attr.check_name(syntax::symbol::sym::test)) { + if i.attrs.iter().any(|attr| attr.check_name(syntax::symbol::sym::test)) + { let config = MiriConfig { validate: true, communicate: false, @@ -82,12 +86,10 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { } fn main() { - let path = option_env!("MIRI_RUSTC_TEST") - .map(String::from) - .unwrap_or_else(|| { - std::env::var("MIRI_RUSTC_TEST") - .expect("need to set MIRI_RUSTC_TEST to path of rustc tests") - }); + let path = option_env!("MIRI_RUSTC_TEST").map(String::from).unwrap_or_else(|| { + std::env::var("MIRI_RUSTC_TEST") + .expect("need to set MIRI_RUSTC_TEST to path of rustc tests") + }); let mut mir_not_found = Vec::new(); let mut crate_not_found = Vec::new(); @@ -115,14 +117,16 @@ fn main() { let stderr = std::io::stderr(); write!(stderr.lock(), "test [miri-pass] {} ... ", path.display()).unwrap(); let mut host_target = false; - let mut args: Vec = std::env::args().filter(|arg| { - if arg == "--miri_host_target" { - host_target = true; - false // remove the flag, rustc doesn't know it - } else { - true - } - }).collect(); + let mut args: Vec = std::env::args() + .filter(|arg| { + if arg == "--miri_host_target" { + host_target = true; + false // remove the flag, rustc doesn't know it + } else { + true + } + }) + .collect(); args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string)); // file to process args.push(path.display().to_string()); @@ -130,7 +134,13 @@ fn main() { let sysroot_flag = String::from("--sysroot"); if !args.contains(&sysroot_flag) { args.push(sysroot_flag); - args.push(Path::new(&std::env::var("HOME").unwrap()).join(".xargo").join("HOST").display().to_string()); + args.push( + Path::new(&std::env::var("HOME").unwrap()) + .join(".xargo") + .join("HOST") + .display() + .to_string(), + ); } // A threadsafe buffer for writing. @@ -148,14 +158,19 @@ fn main() { let buf = BufWriter::default(); let output = buf.clone(); let result = std::panic::catch_unwind(|| { - let _ = rustc_driver::run_compiler(&args, &mut MiriCompilerCalls { host_target }, None, Some(Box::new(buf))); + let _ = rustc_driver::run_compiler( + &args, + &mut MiriCompilerCalls { host_target }, + None, + Some(Box::new(buf)), + ); }); match result { Ok(()) => { success += 1; writeln!(stderr.lock(), "ok").unwrap() - }, + } Err(_) => { let output = output.0.lock().unwrap(); let output_err = std::str::from_utf8(&output).unwrap(); @@ -178,7 +193,8 @@ fn main() { if text.starts_with(c_abi) { c_abi_fns.push(text[c_abi.len()..end].to_string()); } else if text.starts_with(unimplemented_intrinsic_s) { - unimplemented_intrinsic.push(text[unimplemented_intrinsic_s.len()..end].to_string()); + unimplemented_intrinsic + .push(text[unimplemented_intrinsic_s.len()..end].to_string()); } else if text.starts_with(unsupported_s) { unsupported.push(text[unsupported_s.len()..end].to_string()); } else if text.starts_with(abi_s) { @@ -196,10 +212,19 @@ fn main() { } let stderr = std::io::stderr(); let mut stderr = stderr.lock(); - writeln!(stderr, "{} success, {} no mir, {} crate not found, {} failed, \ - {} C fn, {} ABI, {} unsupported, {} intrinsic", - success, mir_not_found.len(), crate_not_found.len(), failed.len(), - c_abi_fns.len(), abi.len(), unsupported.len(), unimplemented_intrinsic.len()).unwrap(); + writeln!( + stderr, + "{} success, {} no mir, {} crate not found, {} failed, {} C fn, {} ABI, {} unsupported, {} intrinsic", + success, + mir_not_found.len(), + crate_not_found.len(), + failed.len(), + c_abi_fns.len(), + abi.len(), + unsupported.len(), + unimplemented_intrinsic.len() + ) + .unwrap(); writeln!(stderr, "# The \"other reasons\" errors").unwrap(); writeln!(stderr, "(sorted, deduplicated)").unwrap(); print_vec(&mut stderr, failed); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 48af81296257..1af79b259613 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -7,29 +7,33 @@ extern crate log; extern crate log_settings; extern crate miri; extern crate rustc; -extern crate rustc_metadata; +extern crate rustc_codegen_utils; extern crate rustc_driver; extern crate rustc_errors; -extern crate rustc_codegen_utils; extern crate rustc_interface; +extern crate rustc_metadata; extern crate syntax; -use std::str::FromStr; use std::convert::TryFrom; use std::env; +use std::str::FromStr; use hex::FromHexError; -use rustc_interface::{interface, Queries}; use rustc::hir::def_id::LOCAL_CRATE; use rustc_driver::Compilation; +use rustc_interface::{interface, Queries}; struct MiriCompilerCalls { miri_config: miri::MiriConfig, } impl rustc_driver::Callbacks for MiriCompilerCalls { - fn after_analysis<'tcx>(&mut self, compiler: &interface::Compiler, queries: &'tcx Queries<'tcx>) -> Compilation { + fn after_analysis<'tcx>( + &mut self, + compiler: &interface::Compiler, + queries: &'tcx Queries<'tcx>, + ) -> Compilation { init_late_loggers(); compiler.session().abort_if_errors(); @@ -41,7 +45,9 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { config.args.insert(0, compiler.input().filestem().to_string()); if let Some(return_code) = miri::eval_main(tcx, entry_def_id, config) { - std::process::exit(i32::try_from(return_code).expect("Return value was too large!")); + std::process::exit( + i32::try_from(return_code).expect("Return value was too large!"), + ); } }); @@ -76,8 +82,10 @@ fn init_late_loggers() { // This way, if you set `MIRI_LOG=trace`, you get only the right parts of // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_mir::interpret=debug`. if log::Level::from_str(&var).is_ok() { - env::set_var("RUSTC_LOG", - &format!("rustc::mir::interpret={0},rustc_mir::interpret={0}", var)); + env::set_var( + "RUSTC_LOG", + &format!("rustc::mir::interpret={0},rustc_mir::interpret={0}", var), + ); } else { env::set_var("RUSTC_LOG", &var); } @@ -110,11 +118,9 @@ fn compile_time_sysroot() -> Option { let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); Some(match (home, toolchain) { (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain), - _ => { - option_env!("RUST_SYSROOT") - .expect("To build Miri without rustup, set the `RUST_SYSROOT` env var at build time") - .to_owned() - } + _ => option_env!("RUST_SYSROOT") + .expect("To build Miri without rustup, set the `RUST_SYSROOT` env var at build time") + .to_owned(), }) } @@ -135,21 +141,20 @@ fn main() { if rustc_args.is_empty() { // Very first arg: for `rustc`. rustc_args.push(arg); - } - else if after_dashdash { + } else if after_dashdash { // Everything that comes after are `miri` args. miri_args.push(arg); } else { match arg.as_str() { "-Zmiri-disable-validation" => { validate = false; - }, + } "-Zmiri-disable-isolation" => { communicate = true; - }, + } "-Zmiri-ignore-leaks" => { ignore_leaks = true; - }, + } "--" => { after_dashdash = true; } @@ -162,32 +167,40 @@ fn main() { FromHexError::InvalidHexCharacter { .. } => panic!( "-Zmiri-seed should only contain valid hex digits [0-9a-fA-F]" ), - FromHexError::OddLength => panic!("-Zmiri-seed should have an even number of digits"), + FromHexError::OddLength => + panic!("-Zmiri-seed should have an even number of digits"), err => panic!("Unknown error decoding -Zmiri-seed as hex: {:?}", err), }); if seed_raw.len() > 8 { - panic!(format!("-Zmiri-seed must be at most 8 bytes, was {}", seed_raw.len())); + panic!(format!( + "-Zmiri-seed must be at most 8 bytes, was {}", + seed_raw.len() + )); } let mut bytes = [0; 8]; bytes[..seed_raw.len()].copy_from_slice(&seed_raw); seed = Some(u64::from_be_bytes(bytes)); - - }, + } arg if arg.starts_with("-Zmiri-env-exclude=") => { - excluded_env_vars.push(arg.trim_start_matches("-Zmiri-env-exclude=").to_owned()); - }, + excluded_env_vars + .push(arg.trim_start_matches("-Zmiri-env-exclude=").to_owned()); + } arg if arg.starts_with("-Zmiri-track-pointer-tag=") => { - let id: u64 = match arg.trim_start_matches("-Zmiri-track-pointer-tag=").parse() { + let id: u64 = match arg.trim_start_matches("-Zmiri-track-pointer-tag=").parse() + { Ok(id) => id, - Err(err) => panic!("-Zmiri-track-pointer-tag requires a valid `u64` as the argument: {}", err), + Err(err) => panic!( + "-Zmiri-track-pointer-tag requires a valid `u64` as the argument: {}", + err + ), }; if let Some(id) = miri::PtrId::new(id) { tracked_pointer_tag = Some(id); } else { panic!("-Zmiri-track-pointer-tag must be a nonzero id"); } - }, + } _ => { rustc_args.push(arg); } @@ -225,6 +238,7 @@ fn main() { rustc_driver::install_ice_hook(); let result = rustc_driver::catch_fatal_errors(move || { rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None) - }).and_then(|result| result); + }) + .and_then(|result| result); std::process::exit(result.is_err() as i32); } diff --git a/src/eval.rs b/src/eval.rs index 9a70663716d6..4ed1b272b228 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -50,7 +50,11 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), Evaluator::new(config.communicate), - MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate, config.tracked_pointer_tag), + MemoryExtra::new( + StdRng::seed_from_u64(config.seed.unwrap_or(0)), + config.validate, + config.tracked_pointer_tag, + ), ); // Complete initialization. EnvVars::init(&mut ecx, config.excluded_env_vars); @@ -75,9 +79,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( .unwrap(); // First argument: pointer to `main()`. - let main_ptr = ecx - .memory - .create_fn_alloc(FnVal::Instance(main_instance)); + let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(main_instance)); // Second argument (argc): length of `config.args`. let argc = Scalar::from_uint(config.args.len() as u128, ecx.pointer_size()); // Third argument (`argv`): created from `config.args`. @@ -93,24 +95,20 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( argvs.push(arg_place.ptr); } // Make an array with all these pointers, in the Miri memory. - let argvs_layout = ecx.layout_of( - tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), argvs.len() as u64), - )?; + let argvs_layout = + ecx.layout_of(tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), argvs.len() as u64))?; let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into()); for (idx, arg) in argvs.into_iter().enumerate() { let place = ecx.mplace_field(argvs_place, idx as u64)?; ecx.write_scalar(arg, place.into())?; } - ecx.memory - .mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?; + ecx.memory.mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?; // A pointer to that place is the 3rd argument for main. let argv = argvs_place.ptr; // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`. { - let argc_place = ecx.allocate( - ecx.layout_of(tcx.types.isize)?, - MiriMemoryKind::Env.into(), - ); + let argc_place = + ecx.allocate(ecx.layout_of(tcx.types.isize)?, MiriMemoryKind::Env.into()); ecx.write_scalar(argc, argc_place.into())?; ecx.machine.argc = Some(argc_place.ptr); @@ -149,10 +147,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( }; // Return place (in static memory so that it does not count as leak). - let ret_place = ecx.allocate( - ecx.layout_of(tcx.types.isize)?, - MiriMemoryKind::Env.into(), - ); + let ret_place = ecx.allocate(ecx.layout_of(tcx.types.isize)?, MiriMemoryKind::Env.into()); // Call start function. ecx.call_function( start_instance, @@ -209,27 +204,30 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> return None; } } - return Some(return_code) + return Some(return_code); } Err(mut e) => { // Special treatment for some error kinds let msg = match e.kind { InterpError::MachineStop(ref info) => { - let info = info.downcast_ref::() + let info = info + .downcast_ref::() .expect("invalid MachineStop payload"); match info { TerminationInfo::Exit(code) => return Some(*code), TerminationInfo::PoppedTrackedPointerTag(item) => format!("popped tracked tag for item {:?}", item), TerminationInfo::Abort => - format!("the evaluated program aborted execution") + format!("the evaluated program aborted execution"), } } - err_unsup!(NoMirFor(..)) => - format!("{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", e), + err_unsup!(NoMirFor(..)) => format!( + "{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", + e + ), InterpError::InvalidProgram(_) => bug!("This error should be impossible in Miri: {}", e), - _ => e.to_string() + _ => e.to_string(), }; e.print_backtrace(); if let Some(frame) = ecx.stack().last() { @@ -242,9 +240,9 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> // We iterate with indices because we need to look at the next frame (the caller). for idx in 0..frames.len() { let frame_info = &frames[idx]; - let call_site_is_local = frames.get(idx + 1).map_or(false, |caller_info| { - caller_info.instance.def_id().is_local() - }); + let call_site_is_local = frames + .get(idx + 1) + .map_or(false, |caller_info| caller_info.instance.def_id().is_local()); if call_site_is_local { err.span_note(frame_info.call_site, &frame_info.to_string()); } else { diff --git a/src/helpers.rs b/src/helpers.rs index 5d7db0d12693..b6391ce2fde0 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,15 +1,14 @@ -use std::{mem, iter}; use std::ffi::OsStr; +use std::{iter, mem}; -use syntax::source_map::DUMMY_SP; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc::ty::{ self, - List, - TyCtxt, layout::{self, LayoutOf, Size, TyLayout}, + List, TyCtxt, }; +use syntax::source_map::DUMMY_SP; use rand::RngCore; @@ -19,15 +18,11 @@ impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tc /// Gets an instance for a path. fn resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> InterpResult<'tcx, DefId> { - tcx - .crates() + tcx.crates() .iter() .find(|&&krate| tcx.original_crate_name(krate).as_str() == path[0]) .and_then(|krate| { - let krate = DefId { - krate: *krate, - index: CRATE_DEF_INDEX, - }; + let krate = DefId { krate: *krate, index: CRATE_DEF_INDEX }; let mut items = tcx.item_children(krate); let mut path_it = path.iter().skip(1).peekable(); @@ -35,7 +30,7 @@ fn resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> InterpResult<'tc for item in mem::replace(&mut items, Default::default()).iter() { if item.ident.name.as_str() == *segment { if path_it.peek().is_none() { - return Some(item.res.def_id()) + return Some(item.res.def_id()); } items = tcx.item_children(item.res.def_id()); @@ -51,12 +46,13 @@ fn resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> InterpResult<'tc }) } - pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// Gets an instance for a path. fn resolve_path(&self, path: &[&str]) -> InterpResult<'tcx, ty::Instance<'tcx>> { - Ok(ty::Instance::mono(self.eval_context_ref().tcx.tcx, resolve_did(self.eval_context_ref().tcx.tcx, path)?)) + Ok(ty::Instance::mono( + self.eval_context_ref().tcx.tcx, + resolve_did(self.eval_context_ref().tcx.tcx, path)?, + )) } /// Write a 0 of the appropriate size to `dest`. @@ -74,11 +70,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Turn a Scalar into an Option fn test_null(&self, val: Scalar) -> InterpResult<'tcx, Option>> { let this = self.eval_context_ref(); - Ok(if this.is_null(val)? { - None - } else { - Some(val) - }) + Ok(if this.is_null(val)? { None } else { Some(val) }) } /// Get the `Place` for a local @@ -89,11 +81,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Generate some random bytes, and write them to `dest`. - fn gen_random( - &mut self, - ptr: Scalar, - len: usize, - ) -> InterpResult<'tcx> { + fn gen_random(&mut self, ptr: Scalar, len: usize) -> InterpResult<'tcx> { // Some programs pass in a null pointer and a length of 0 // to their platform's random-generation function (e.g. getrandom()) // on Linux. For compatibility with these programs, we don't perform @@ -110,8 +98,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Fill the buffer using the host's rng. getrandom::getrandom(&mut data) .map_err(|err| err_unsup_format!("getrandom failed: {}", err))?; - } - else { + } else { let rng = this.memory.extra.rng.get_mut(); rng.fill_bytes(&mut data); } @@ -132,23 +119,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Push frame. let mir = &*this.load_mir(f.def, None)?; - let span = this.stack().last() + let span = this + .stack() + .last() .and_then(Frame::current_source_info) .map(|si| si.span) .unwrap_or(DUMMY_SP); - this.push_stack_frame( - f, - span, - mir, - dest, - stack_pop, - )?; + this.push_stack_frame(f, span, mir, dest, stack_pop)?; // Initialize arguments. let mut callee_args = this.frame().body.args_iter(); for arg in args { let callee_arg = this.local_place( - callee_args.next().expect("callee has fewer arguments than expected") + callee_args.next().expect("callee has fewer arguments than expected"), )?; this.write_immediate(*arg, callee_arg)?; } @@ -167,10 +150,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); trace!("visit_frozen(place={:?}, size={:?})", *place, size); - debug_assert_eq!(size, + debug_assert_eq!( + size, this.size_and_align_of_mplace(place)? - .map(|(size, _)| size) - .unwrap_or_else(|| place.layout.size) + .map(|(size, _)| size) + .unwrap_or_else(|| place.layout.size) ); // Store how far we proceeded into the place so far. Everything to the left of // this offset has already been handled, in the sense that the frozen parts @@ -190,11 +174,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let frozen_size = unsafe_cell_offset - end_offset; // Everything between the end_ptr and this `UnsafeCell` is frozen. if frozen_size != Size::ZERO { - action(end_ptr, frozen_size, /*frozen*/true)?; + action(end_ptr, frozen_size, /*frozen*/ true)?; } // This `UnsafeCell` is NOT frozen. if unsafe_cell_size != Size::ZERO { - action(unsafe_cell_ptr, unsafe_cell_size, /*frozen*/false)?; + action(unsafe_cell_ptr, unsafe_cell_size, /*frozen*/ false)?; } // Update end end_ptr. end_ptr = unsafe_cell_ptr.wrapping_offset(unsafe_cell_size, this); @@ -208,7 +192,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx unsafe_cell_action: |place| { trace!("unsafe_cell_action on {:?}", place.ptr); // We need a size to go on. - let unsafe_cell_size = this.size_and_align_of_mplace(place)? + let unsafe_cell_size = this + .size_and_align_of_mplace(place)? .map(|(size, _)| size) // for extern types, just cover what we can .unwrap_or_else(|| place.layout.size); @@ -231,18 +216,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Visiting the memory covered by a `MemPlace`, being aware of /// whether we are inside an `UnsafeCell` or not. struct UnsafeCellVisitor<'ecx, 'mir, 'tcx, F> - where F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> + where + F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>, { ecx: &'ecx MiriEvalContext<'mir, 'tcx>, unsafe_cell_action: F, } - impl<'ecx, 'mir, 'tcx, F> - ValueVisitor<'mir, 'tcx, Evaluator<'tcx>> - for - UnsafeCellVisitor<'ecx, 'mir, 'tcx, F> + impl<'ecx, 'mir, 'tcx, F> ValueVisitor<'mir, 'tcx, Evaluator<'tcx>> + for UnsafeCellVisitor<'ecx, 'mir, 'tcx, F> where - F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> + F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>, { type V = MPlaceTy<'tcx, Tag>; @@ -252,11 +236,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Hook to detect `UnsafeCell`. - fn visit_value(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> - { + fn visit_value(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty); let is_unsafe_cell = match v.layout.ty.kind { - ty::Adt(adt, _) => Some(adt.did) == self.ecx.tcx.lang_items().unsafe_cell_type(), + ty::Adt(adt, _) => + Some(adt.did) == self.ecx.tcx.lang_items().unsafe_cell_type(), _ => false, }; if is_unsafe_cell { @@ -293,7 +277,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn visit_aggregate( &mut self, place: MPlaceTy<'tcx, Tag>, - fields: impl Iterator>>, + fields: impl Iterator>>, ) -> InterpResult<'tcx> { match place.layout.fields { layout::FieldPlacement::Array { .. } => { @@ -303,7 +287,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } layout::FieldPlacement::Arbitrary { .. } => { // Gather the subplaces and sort them before visiting. - let mut places = fields.collect::>>>()?; + let mut places = + fields.collect::>>>()?; places.sort_by_key(|place| place.ptr.assert_ptr().offset); self.walk_aggregate(place, places.into_iter().map(Ok)) } @@ -315,22 +300,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // We have to do *something* for unions. - fn visit_union(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> - { + fn visit_union(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { // With unions, we fall back to whatever the type says, to hopefully be consistent // with LLVM IR. // FIXME: are we consistent, and is this really the behavior we want? let frozen = self.ecx.type_is_freeze(v.layout.ty); - if frozen { - Ok(()) - } else { - (self.unsafe_cell_action)(v) - } + if frozen { Ok(()) } else { (self.unsafe_cell_action)(v) } } // We should never get to a primitive, but always short-circuit somewhere above. - fn visit_primitive(&mut self, _v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> - { + fn visit_primitive(&mut self, _v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { bug!("we should always short-circuit before coming to a primitive") } } @@ -382,7 +361,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// case. fn check_no_isolation(&mut self, name: &str) -> InterpResult<'tcx> { if !self.eval_context_mut().machine.communicate { - throw_unsup_format!("`{}` not available when isolation is enabled. Pass the flag `-Zmiri-disable-isolation` to disable it.", name) + throw_unsup_format!( + "`{}` not available when isolation is enabled. Pass the flag `-Zmiri-disable-isolation` to disable it.", + name + ) } Ok(()) } @@ -423,11 +405,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx TimedOut => "ETIMEDOUT", AlreadyExists => "EEXIST", WouldBlock => "EWOULDBLOCK", - _ => throw_unsup_format!("The {} error cannot be transformed into a raw os error", e) + _ => { + throw_unsup_format!("The {} error cannot be transformed into a raw os error", e) + } })? } else { // FIXME: we have to implement the Windows equivalent of this. - throw_unsup_format!("Setting the last OS error from an io::Error is unsupported for {}.", target.target_os) + throw_unsup_format!( + "Setting the last OS error from an io::Error is unsupported for {}.", + target.target_os + ) }; this.set_last_error(last_error) } @@ -454,7 +441,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. fn read_os_str_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, &'a OsStr> - where 'tcx: 'a, 'mir: 'a + where + 'tcx: 'a, + 'mir: 'a, { let this = self.eval_context_ref(); let bytes = this.memory.read_c_str(scalar)?; @@ -469,7 +458,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, os_str: &OsStr, scalar: Scalar, - size: u64 + size: u64, ) -> InterpResult<'tcx, bool> { let bytes = os_str_to_bytes(os_str)?; // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null @@ -477,7 +466,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if size <= bytes.len() as u64 { return Ok(false); } - self.eval_context_mut().memory.write_bytes(scalar, bytes.iter().copied().chain(iter::once(0u8)))?; + self.eval_context_mut() + .memory + .write_bytes(scalar, bytes.iter().copied().chain(iter::once(0u8)))?; Ok(true) } } @@ -488,7 +479,7 @@ fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> } #[cfg(target_os = "unix")] -fn bytes_to_os_str<'tcx, 'a>(bytes: &'a[u8]) -> InterpResult<'tcx, &'a OsStr> { +fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { Ok(std::os::unix::ffi::OsStringExt::from_bytes(bytes)) } @@ -522,11 +513,7 @@ pub fn immty_from_int_checked<'tcx>( let size = layout.size; let truncated = truncate(int as u128, size); if sign_extend(truncated, size) as i128 != int { - throw_unsup_format!( - "Signed value {:#x} does not fit in {} bits", - int, - size.bits() - ) + throw_unsup_format!("Signed value {:#x} does not fit in {} bits", int, size.bits()) } Ok(ImmTy::from_int(int, layout)) } @@ -542,12 +529,7 @@ pub fn immty_from_uint_checked<'tcx>( // `ImmTy::from_int` panic. let size = layout.size; if truncate(int, size) != int { - throw_unsup_format!( - "Unsigned value {:#x} does not fit in {} bits", - int, - size.bits() - ) + throw_unsup_format!("Unsigned value {:#x} does not fit in {} bits", int, size.bits()) } Ok(ImmTy::from_uint(int, layout)) } - diff --git a/src/intptrcast.rs b/src/intptrcast.rs index a55c58c13add..059d8217fabb 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -1,11 +1,11 @@ use std::cell::RefCell; -use std::collections::{HashMap, hash_map::Entry}; use std::cmp::max; +use std::collections::{hash_map::Entry, HashMap}; use rand::Rng; use rustc::ty::layout::HasDataLayout; -use rustc_mir::interpret::{AllocId, Pointer, InterpResult, Memory, AllocCheck, PointerArithmetic}; +use rustc_mir::interpret::{AllocCheck, AllocId, InterpResult, Memory, Pointer, PointerArithmetic}; use rustc_target::abi::Size; use crate::{Evaluator, Tag, STACK_ADDR}; @@ -47,14 +47,15 @@ impl<'mir, 'tcx> GlobalState { } let global_state = memory.extra.intptrcast.borrow(); + let pos = global_state.int_to_ptr_map.binary_search_by_key(&int, |(addr, _)| *addr); - Ok(match global_state.int_to_ptr_map.binary_search_by_key(&int, |(addr, _)| *addr) { + Ok(match pos { Ok(pos) => { let (_, alloc_id) = global_state.int_to_ptr_map[pos]; // `int` is equal to the starting address for an allocation, the offset should be // zero. The pointer is untagged because it was created from a cast Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged) - }, + } Err(0) => throw_unsup!(DanglingPointerDeref), Err(pos) => { // This is the largest of the adresses smaller than `int`, @@ -100,7 +101,10 @@ impl<'mir, 'tcx> GlobalState { entry.insert(base_addr); trace!( "Assigning base address {:#x} to allocation {:?} (slack: {}, align: {})", - base_addr, ptr.alloc_id, slack, align.bytes(), + base_addr, + ptr.alloc_id, + slack, + align.bytes(), ); // Remember next base address. If this allocation is zero-sized, leave a gap @@ -114,7 +118,8 @@ impl<'mir, 'tcx> GlobalState { } }; - debug_assert_eq!(base_addr % align.bytes(), 0); // sanity check + // Sanity check that the base address is aligned. + debug_assert_eq!(base_addr % align.bytes(), 0); // Add offset with the right kind of pointer-overflowing arithmetic. let dl = memory.data_layout(); Ok(dl.overflowing_offset(base_addr, ptr.offset.bytes()).0) @@ -125,7 +130,7 @@ impl<'mir, 'tcx> GlobalState { fn align_addr(addr: u64, align: u64) -> u64 { match addr % align { 0 => addr, - rem => addr.checked_add(align).unwrap() - rem + rem => addr.checked_add(align).unwrap() - rem, } } } diff --git a/src/lib.rs b/src/lib.rs index ee13631727d2..32d2bda719ea 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,57 +1,57 @@ #![feature(rustc_private)] #![feature(option_expect_none, option_unwrap_none)] - #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] #[macro_use] extern crate log; // From rustc. -extern crate syntax; extern crate rustc_apfloat; -#[macro_use] extern crate rustc; +extern crate syntax; +#[macro_use] +extern crate rustc; extern crate rustc_data_structures; extern crate rustc_mir; extern crate rustc_target; -mod shims; -mod operator; +mod eval; mod helpers; -mod range_map; -mod mono_hash_map; -mod stacked_borrows; mod intptrcast; mod machine; -mod eval; +mod mono_hash_map; +mod operator; +mod range_map; +mod shims; +mod stacked_borrows; // Make all those symbols available in the same place as our own. pub use rustc_mir::interpret::*; // Resolve ambiguity. pub use rustc_mir::interpret::{self, AllocMap, PlaceTy}; -pub use crate::shims::{EvalContextExt as ShimsEvalContextExt}; -pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextExt; -pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; -pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; -pub use crate::shims::time::{EvalContextExt as TimeEvalContextExt}; pub use crate::shims::dlsym::{Dlsym, EvalContextExt as DlsymEvalContextExt}; pub use crate::shims::env::{EnvVars, EvalContextExt as EnvEvalContextExt}; -pub use crate::shims::fs::{FileHandler, EvalContextExt as FileEvalContextExt}; +pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextExt; +pub use crate::shims::fs::{EvalContextExt as FileEvalContextExt, FileHandler}; +pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as PanicEvalContextExt}; +pub use crate::shims::time::EvalContextExt as TimeEvalContextExt; +pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; +pub use crate::shims::EvalContextExt as ShimsEvalContextExt; +pub use crate::eval::{create_ecx, eval_main, MiriConfig, TerminationInfo}; +pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; +pub use crate::machine::{ + AllocExtra, Evaluator, FrameData, MemoryExtra, MiriEvalContext, MiriEvalContextExt, + MiriMemoryKind, NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, +}; +pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; -pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; -pub use crate::mono_hash_map::MonoHashMap; pub use crate::stacked_borrows::{ - EvalContextExt as StackedBorEvalContextExt, Tag, Permission, Stack, Stacks, Item, PtrId, - GlobalState, + EvalContextExt as StackedBorEvalContextExt, GlobalState, Item, Permission, PtrId, Stack, + Stacks, Tag, }; -pub use crate::machine::{ - PAGE_SIZE, STACK_ADDR, STACK_SIZE, NUM_CPUS, - MemoryExtra, AllocExtra, FrameData, MiriMemoryKind, Evaluator, MiriEvalContext, MiriEvalContextExt, -}; -pub use crate::eval::{eval_main, create_ecx, MiriConfig, TerminationInfo}; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. diff --git a/src/machine.rs b/src/machine.rs index d5cd86d97878..37253a260de7 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -8,8 +8,12 @@ use std::rc::Rc; use rand::rngs::StdRng; use rustc::hir::def_id::DefId; -use rustc::ty::{self, layout::{Size, LayoutOf}, Ty, TyCtxt}; use rustc::mir; +use rustc::ty::{ + self, + layout::{LayoutOf, Size}, + Ty, TyCtxt, +}; use syntax::{attr, source_map::Span, symbol::sym}; use crate::*; @@ -33,7 +37,6 @@ pub struct FrameData<'tcx> { pub catch_panic: Option>, } - /// Extra memory kinds #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum MiriMemoryKind { @@ -114,7 +117,7 @@ pub struct Evaluator<'tcx> { /// The temporary used for storing the argument of /// the call to `miri_start_panic` (the panic payload) when unwinding. - pub(crate) panic_payload: Option> + pub(crate) panic_payload: Option>, } impl<'tcx> Evaluator<'tcx> { @@ -130,7 +133,7 @@ impl<'tcx> Evaluator<'tcx> { tls: TlsData::default(), communicate, file_handler: Default::default(), - panic_payload: None + panic_payload: None, } } } @@ -164,13 +167,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { type PointerTag = Tag; type ExtraFnVal = Dlsym; - type MemoryMap = MonoHashMap< - AllocId, - ( - MemoryKind, - Allocation, - ), - >; + type MemoryMap = + MonoHashMap, Allocation)>; const STATIC_KIND: Option = Some(MiriMemoryKind::Static); @@ -322,9 +320,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { stacked_borrows.static_base_ptr(alloc) } }, - AllocExtra { - stacked_borrows: stacks, - }, + AllocExtra { stacked_borrows: stacks }, ); (Cow::Owned(alloc), base_tag) } @@ -334,10 +330,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { if !memory_extra.validate { Tag::Untagged } else { - memory_extra - .stacked_borrows - .borrow_mut() - .static_base_ptr(id) + memory_extra.stacked_borrows.borrow_mut().static_base_ptr(id) } } @@ -356,9 +349,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } #[inline(always)] - fn stack_push( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - ) -> InterpResult<'tcx, FrameData<'tcx>> { + fn stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, FrameData<'tcx>> { Ok(FrameData { call_id: ecx.memory.extra.stacked_borrows.borrow_mut().new_call(), catch_panic: None, @@ -369,7 +360,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn stack_pop( ecx: &mut InterpCx<'mir, 'tcx, Self>, extra: FrameData<'tcx>, - unwinding: bool + unwinding: bool, ) -> InterpResult<'tcx, StackPopInfo> { ecx.handle_stack_pop(extra, unwinding) } diff --git a/src/mono_hash_map.rs b/src/mono_hash_map.rs index f2abe4217306..124ae6876026 100644 --- a/src/mono_hash_map.rs +++ b/src/mono_hash_map.rs @@ -5,10 +5,10 @@ //! The API is is completely tailored to what `memory.rs` needs. It is still in //! a separate file to minimize the amount of code that has to care about the unsafety. -use std::collections::hash_map::Entry; -use std::cell::RefCell; -use std::hash::Hash; use std::borrow::Borrow; +use std::cell::RefCell; +use std::collections::hash_map::Entry; +use std::hash::Hash; use rustc_data_structures::fx::FxHashMap; @@ -26,7 +26,7 @@ impl MonoHashMap { /// as long as the `Ref` returned by `RefCell::borrow()` is alive. So we can't return the /// iterator, as that would drop the `Ref`. We can't return both, as it's not possible in Rust /// to have a struct/tuple with a field that refers to another field. - pub fn iter(&self, f: impl FnOnce(&mut dyn Iterator) -> T) -> T { + pub fn iter(&self, f: impl FnOnce(&mut dyn Iterator) -> T) -> T { f(&mut self.0.borrow().iter().map(|(k, v)| (k, &**v))) } } @@ -40,30 +40,28 @@ impl Default for MonoHashMap { impl AllocMap for MonoHashMap { #[inline(always)] fn contains_key(&mut self, k: &Q) -> bool - where K: Borrow + where + K: Borrow, { self.0.get_mut().contains_key(k) } #[inline(always)] - fn insert(&mut self, k: K, v: V) -> Option - { + fn insert(&mut self, k: K, v: V) -> Option { self.0.get_mut().insert(k, Box::new(v)).map(|x| *x) } #[inline(always)] fn remove(&mut self, k: &Q) -> Option - where K: Borrow + where + K: Borrow, { self.0.get_mut().remove(k).map(|x| *x) } #[inline(always)] fn filter_map_collect(&self, mut f: impl FnMut(&K, &V) -> Option) -> Vec { - self.0.borrow() - .iter() - .filter_map(move |(k, v)| f(k, &*v)) - .collect() + self.0.borrow().iter().filter_map(move |(k, v)| f(k, &*v)).collect() } /// The most interesting method: Providing a shared ref without @@ -73,11 +71,7 @@ impl AllocMap for MonoHashMap { /// if it returns a reference, that is used directly, if it /// returns owned data, that is put into the map and returned. #[inline(always)] - fn get_or( - &self, - k: K, - vacant: impl FnOnce() -> Result - ) -> Result<&V, E> { + fn get_or(&self, k: K, vacant: impl FnOnce() -> Result) -> Result<&V, E> { let val: *const V = match self.0.borrow_mut().entry(k) { Entry::Occupied(entry) => &**entry.get(), Entry::Vacant(entry) => &**entry.insert(Box::new(vacant()?)), @@ -88,12 +82,7 @@ impl AllocMap for MonoHashMap { } #[inline(always)] - fn get_mut_or( - &mut self, - k: K, - vacant: impl FnOnce() -> Result - ) -> Result<&mut V, E> - { + fn get_mut_or(&mut self, k: K, vacant: impl FnOnce() -> Result) -> Result<&mut V, E> { match self.0.get_mut().entry(k) { Entry::Occupied(e) => Ok(e.into_mut()), Entry::Vacant(e) => { diff --git a/src/operator.rs b/src/operator.rs index 6b2c12e6b0b0..7c932a907e72 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,7 +1,10 @@ use std::convert::TryFrom; -use rustc::ty::{Ty, layout::{Size, LayoutOf}}; use rustc::mir; +use rustc::ty::{ + layout::{LayoutOf, Size}, + Ty, +}; use crate::*; @@ -13,11 +16,7 @@ pub trait EvalContextExt<'tcx> { right: ImmTy<'tcx, Tag>, ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)>; - fn ptr_eq( - &self, - left: Scalar, - right: Scalar, - ) -> InterpResult<'tcx, bool>; + fn ptr_eq(&self, left: Scalar, right: Scalar) -> InterpResult<'tcx, bool>; fn pointer_offset_inbounds( &self, @@ -41,12 +40,15 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { Ok(match bin_op { Eq | Ne => { // This supports fat pointers. + #[rustfmt::skip] let eq = match (*left, *right) { - (Immediate::Scalar(left), Immediate::Scalar(right)) => - self.ptr_eq(left.not_undef()?, right.not_undef()?)?, - (Immediate::ScalarPair(left1, left2), Immediate::ScalarPair(right1, right2)) => - self.ptr_eq(left1.not_undef()?, right1.not_undef()?)? && - self.ptr_eq(left2.not_undef()?, right2.not_undef()?)?, + (Immediate::Scalar(left), Immediate::Scalar(right)) => { + self.ptr_eq(left.not_undef()?, right.not_undef()?)? + } + (Immediate::ScalarPair(left1, left2), Immediate::ScalarPair(right1, right2)) => { + self.ptr_eq(left1.not_undef()?, right1.not_undef()?)? + && self.ptr_eq(left2.not_undef()?, right2.not_undef()?)? + } _ => bug!("Type system should not allow comparing Scalar with ScalarPair"), }; (Scalar::from_bool(if bin_op == Eq { eq } else { !eq }), false, self.tcx.types.bool) @@ -68,10 +70,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { } Offset => { - let pointee_ty = left.layout.ty - .builtin_deref(true) - .expect("Offset called on non-ptr type") - .ty; + let pointee_ty = + left.layout.ty.builtin_deref(true).expect("Offset called on non-ptr type").ty; let ptr = self.pointer_offset_inbounds( left.to_scalar()?, pointee_ty, @@ -80,15 +80,11 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { (ptr, false, left.layout.ty) } - _ => bug!("Invalid operator on pointers: {:?}", bin_op) + _ => bug!("Invalid operator on pointers: {:?}", bin_op), }) } - fn ptr_eq( - &self, - left: Scalar, - right: Scalar, - ) -> InterpResult<'tcx, bool> { + fn ptr_eq(&self, left: Scalar, right: Scalar) -> InterpResult<'tcx, bool> { let size = self.pointer_size(); // Just compare the integers. // TODO: Do we really want to *always* do that, even when comparing two live in-bounds pointers? diff --git a/src/range_map.rs b/src/range_map.rs index aa9a87887d37..01abaef27fd2 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -29,10 +29,7 @@ impl RangeMap { let size = size.bytes(); let mut map = RangeMap { v: Vec::new() }; if size > 0 { - map.v.push(Elem { - range: 0..size, - data: init - }); + map.v.push(Elem { range: 0..size, data: init }); } map } @@ -53,7 +50,7 @@ impl RangeMap { } else if offset >= elem.range.end { // We are too far left (offset is further right). debug_assert!(candidate >= left); // we are making progress - left = candidate+1; + left = candidate + 1; } else { // This is it! return candidate; @@ -69,18 +66,16 @@ impl RangeMap { let len = len.bytes(); // Compute a slice starting with the elements we care about. let slice: &[Elem] = if len == 0 { - // We just need any empty iterator. We don't even want to - // yield the element that surrounds this position. - &[] - } else { - let first_idx = self.find_offset(offset); - &self.v[first_idx..] - }; + // We just need any empty iterator. We don't even want to + // yield the element that surrounds this position. + &[] + } else { + let first_idx = self.find_offset(offset); + &self.v[first_idx..] + }; // The first offset that is not included any more. let end = offset + len; - slice.iter() - .take_while(move |elem| elem.range.start < end) - .map(|elem| &elem.data) + slice.iter().take_while(move |elem| elem.range.start < end).map(|elem| &elem.data) } pub fn iter_mut_all<'a>(&'a mut self) -> impl Iterator + 'a { @@ -99,18 +94,17 @@ impl RangeMap { // Nothing to do. return false; } - debug_assert!(elem.range.contains(&split_offset), - "the `split_offset` is not in the element to be split"); + debug_assert!( + elem.range.contains(&split_offset), + "the `split_offset` is not in the element to be split" + ); // Now we really have to split. Reduce length of first element. let second_range = split_offset..elem.range.end; elem.range.end = split_offset; // Copy the data, and insert second element. - let second = Elem { - range: second_range, - data: elem.data.clone(), - }; - self.v.insert(index+1, second); + let second = Elem { range: second_range, data: elem.data.clone() }; + self.v.insert(index + 1, second); return true; } @@ -130,73 +124,79 @@ impl RangeMap { let len = len.bytes(); // Compute a slice containing exactly the elements we care about let slice: &mut [Elem] = if len == 0 { - // We just need any empty iterator. We don't even want to - // yield the element that surrounds this position, nor do - // any splitting. - &mut [] - } else { - // Make sure we got a clear beginning - let mut first_idx = self.find_offset(offset); - if self.split_index(first_idx, offset) { - // The newly created 2nd element is ours - first_idx += 1; - } - let first_idx = first_idx; // no more mutation - // Find our end. Linear scan, but that's ok because the iteration - // is doing the same linear scan anyway -- no increase in complexity. - // We combine this scan with a scan for duplicates that we can merge, to reduce - // the number of elements. - // We stop searching after the first "block" of size 1, to avoid spending excessive - // amounts of time on the merging. - let mut equal_since_idx = first_idx; - // Once we see too many non-mergeable blocks, we stop. - // The initial value is chosen via... magic. Benchmarking and magic. - let mut successful_merge_count = 3usize; - let mut end_idx = first_idx; // when the loop is done, this is the first excluded element. - loop { - // Compute if `end` is the last element we need to look at. - let done = self.v[end_idx].range.end >= offset+len; - // We definitely need to include `end`, so move the index. - end_idx += 1; - debug_assert!(done || end_idx < self.v.len(), "iter_mut: end-offset {} is out-of-bounds", offset+len); - // see if we want to merge everything in `equal_since..end` (exclusive at the end!) - if successful_merge_count > 0 { - if done || self.v[end_idx].data != self.v[equal_since_idx].data { - // Everything in `equal_since..end` was equal. Make them just one element covering - // the entire range. - let removed_elems = end_idx - equal_since_idx - 1; // number of elements that we would remove - if removed_elems > 0 { - // Adjust the range of the first element to cover all of them. - let equal_until = self.v[end_idx - 1].range.end; // end of range of last of the equal elements - self.v[equal_since_idx].range.end = equal_until; - // Delete the rest of them. - self.v.splice(equal_since_idx+1..end_idx, std::iter::empty()); - // Adjust `end_idx` because we made the list shorter. - end_idx -= removed_elems; - // Adjust the count for the cutoff. - successful_merge_count += removed_elems; - } else { - // Adjust the count for the cutoff. - successful_merge_count -= 1; - } - // Go on scanning for the next block starting here. - equal_since_idx = end_idx; + // We just need any empty iterator. We don't even want to + // yield the element that surrounds this position, nor do + // any splitting. + &mut [] + } else { + // Make sure we got a clear beginning + let mut first_idx = self.find_offset(offset); + if self.split_index(first_idx, offset) { + // The newly created 2nd element is ours + first_idx += 1; + } + // No more mutation. + let first_idx = first_idx; + // Find our end. Linear scan, but that's ok because the iteration + // is doing the same linear scan anyway -- no increase in complexity. + // We combine this scan with a scan for duplicates that we can merge, to reduce + // the number of elements. + // We stop searching after the first "block" of size 1, to avoid spending excessive + // amounts of time on the merging. + let mut equal_since_idx = first_idx; + // Once we see too many non-mergeable blocks, we stop. + // The initial value is chosen via... magic. Benchmarking and magic. + let mut successful_merge_count = 3usize; + // When the loop is done, this is the first excluded element. + let mut end_idx = first_idx; + loop { + // Compute if `end` is the last element we need to look at. + let done = self.v[end_idx].range.end >= offset + len; + // We definitely need to include `end`, so move the index. + end_idx += 1; + debug_assert!( + done || end_idx < self.v.len(), + "iter_mut: end-offset {} is out-of-bounds", + offset + len + ); + // see if we want to merge everything in `equal_since..end` (exclusive at the end!) + if successful_merge_count > 0 { + if done || self.v[end_idx].data != self.v[equal_since_idx].data { + // Everything in `equal_since..end` was equal. Make them just one element covering + // the entire range. + let removed_elems = end_idx - equal_since_idx - 1; // number of elements that we would remove + if removed_elems > 0 { + // Adjust the range of the first element to cover all of them. + let equal_until = self.v[end_idx - 1].range.end; // end of range of last of the equal elements + self.v[equal_since_idx].range.end = equal_until; + // Delete the rest of them. + self.v.splice(equal_since_idx + 1..end_idx, std::iter::empty()); + // Adjust `end_idx` because we made the list shorter. + end_idx -= removed_elems; + // Adjust the count for the cutoff. + successful_merge_count += removed_elems; + } else { + // Adjust the count for the cutoff. + successful_merge_count -= 1; } - } - // Leave loop if this is the last element. - if done { - break; + // Go on scanning for the next block starting here. + equal_since_idx = end_idx; } } - // Move to last included instead of first excluded index. - let end_idx = end_idx-1; - // We need to split the end as well. Even if this performs a - // split, we don't have to adjust our index as we only care about - // the first part of the split. - self.split_index(end_idx, offset+len); - // Now we yield the slice. `end` is inclusive. - &mut self.v[first_idx..=end_idx] - }; + // Leave loop if this is the last element. + if done { + break; + } + } + // Move to last included instead of first excluded index. + let end_idx = end_idx - 1; + // We need to split the end as well. Even if this performs a + // split, we don't have to adjust our index as we only care about + // the first part of the split. + self.split_index(end_idx, offset + len); + // Now we yield the slice. `end` is inclusive. + &mut self.v[first_idx..=end_idx] + }; slice.iter_mut().map(|elem| &mut elem.data) } } @@ -209,12 +209,7 @@ mod tests { fn to_vec(map: &RangeMap, offset: u64, len: u64) -> Vec { (offset..offset + len) .into_iter() - .map(|i| map - .iter(Size::from_bytes(i), Size::from_bytes(1)) - .next() - .map(|&t| t) - .unwrap() - ) + .map(|i| map.iter(Size::from_bytes(i), Size::from_bytes(1)).next().map(|&t| t).unwrap()) .collect() } @@ -250,10 +245,7 @@ mod tests { *x = 43; } assert_eq!(map.v.len(), 5); - assert_eq!( - to_vec(&map, 10, 10), - vec![-1, 42, -1, -1, -1, 43, -1, -1, -1, -1] - ); + assert_eq!(to_vec(&map, 10, 10), vec![-1, 42, -1, -1, -1, 43, -1, -1, -1, -1]); for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(10)) { if *x < 42 { @@ -261,31 +253,23 @@ mod tests { } } assert_eq!(map.v.len(), 6); - assert_eq!( - to_vec(&map, 10, 10), - vec![23, 42, 23, 23, 23, 43, 23, 23, 23, 23] - ); + assert_eq!(to_vec(&map, 10, 10), vec![23, 42, 23, 23, 23, 43, 23, 23, 23, 23]); assert_eq!(to_vec(&map, 13, 5), vec![23, 23, 43, 23, 23]); - for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(5)) { *x = 19; } assert_eq!(map.v.len(), 6); - assert_eq!( - to_vec(&map, 10, 10), - vec![23, 42, 23, 23, 23, 19, 19, 19, 19, 19] - ); + assert_eq!(to_vec(&map, 10, 10), vec![23, 42, 23, 23, 23, 19, 19, 19, 19, 19]); // Should be seeing two blocks with 19. - assert_eq!(map.iter(Size::from_bytes(15), Size::from_bytes(2)) - .map(|&t| t).collect::>(), vec![19, 19]); + assert_eq!( + map.iter(Size::from_bytes(15), Size::from_bytes(2)).map(|&t| t).collect::>(), + vec![19, 19] + ); // A NOP `iter_mut` should trigger merging. - for _ in map.iter_mut(Size::from_bytes(15), Size::from_bytes(5)) { } + for _ in map.iter_mut(Size::from_bytes(15), Size::from_bytes(5)) {} assert_eq!(map.v.len(), 5); - assert_eq!( - to_vec(&map, 10, 10), - vec![23, 42, 23, 23, 23, 19, 19, 19, 19, 19] - ); + assert_eq!(to_vec(&map, 10, 10), vec![23, 42, 23, 23, 23, 19, 19, 19, 19, 19]); } } diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index dfee4066da1b..0069f8cc8087 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -15,8 +15,7 @@ impl Dlsym { Ok(match name { "getentropy" => Some(GetEntropy), "__pthread_get_minstack" => None, - _ => - throw_unsup_format!("Unsupported dlsym: {}", name), + _ => throw_unsup_format!("Unsupported dlsym: {}", name), }) } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 55742bd060b3..1a52d8721470 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -1,10 +1,10 @@ -use std::{iter, convert::TryInto}; +use std::{convert::TryInto, iter}; -use rustc::mir; -use rustc::ty::layout::{Align, LayoutOf, Size}; use rustc::hir::def_id::DefId; -use rustc_apfloat::Float; +use rustc::mir; use rustc::ty; +use rustc::ty::layout::{Align, LayoutOf, Size}; +use rustc_apfloat::Float; use syntax::attr; use syntax::symbol::sym; @@ -47,14 +47,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Scalar::from_int(0, this.pointer_size()) } else { let align = this.min_align(size, kind); - let ptr = this - .memory - .allocate(Size::from_bytes(size), align, kind.into()); + let ptr = this.memory.allocate(Size::from_bytes(size), align, kind.into()); if zero_init { // We just allocated this, the access is definitely in-bounds. - this.memory - .write_bytes(ptr.into(), iter::repeat(0u8).take(size as usize)) - .unwrap(); + this.memory.write_bytes(ptr.into(), iter::repeat(0u8).take(size as usize)).unwrap(); } Scalar::Ptr(ptr) } @@ -82,8 +78,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(Scalar::from_int(0, this.pointer_size())) } else { let new_ptr = - this.memory - .allocate(Size::from_bytes(new_size), new_align, kind.into()); + this.memory.allocate(Size::from_bytes(new_size), new_align, kind.into()); Ok(Scalar::Ptr(new_ptr)) } } else { @@ -110,12 +105,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// by this function. /// Returns Ok(Some(body)) if processing the foreign item /// is delegated to another function. + #[rustfmt::skip] fn emulate_foreign_item( &mut self, def_id: DefId, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, - _unwind: Option + _unwind: Option, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); @@ -136,11 +132,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // also be a custom user-provided implementation via `#![feature(panic_runtime)]` "__rust_start_panic" => { // FIXME we might want to cache this... but it's not really performance-critical. - let panic_runtime = tcx.crates().iter() + let panic_runtime = tcx + .crates() + .iter() .find(|cnum| tcx.is_panic_runtime(**cnum)) .expect("No panic runtime found!"); let panic_runtime = tcx.crate_name(*panic_runtime); - let start_panic_instance = this.resolve_path(&[&*panic_runtime.as_str(), "__rust_start_panic"])?; + let start_panic_instance = + this.resolve_path(&[&*panic_runtime.as_str(), "__rust_start_panic"])?; return Ok(Some(&*this.load_mir(start_panic_instance.def, None)?)); } // Similarly, we forward calls to the `panic_impl` foreign item to its implementation. @@ -151,7 +150,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); } - "exit" | "ExitProcess" => { + | "exit" + | "ExitProcess" + => { // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway let code = this.read_scalar(args[0])?.to_i32()?; throw_machine_stop!(TerminationInfo::Exit(code.into())); @@ -175,9 +176,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "calloc" => { let items = this.read_scalar(args[0])?.to_machine_usize(this)?; let len = this.read_scalar(args[1])?.to_machine_usize(this)?; - let size = items - .checked_mul(len) - .ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?; + let size = + items.checked_mul(len).ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?; let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C); this.write_scalar(res, dest)?; } @@ -250,9 +250,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx MiriMemoryKind::Rust.into(), ); // We just allocated this, the access is definitely in-bounds. - this.memory - .write_bytes(ptr.into(), iter::repeat(0u8).take(size as usize)) - .unwrap(); + this.memory.write_bytes(ptr.into(), iter::repeat(0u8).take(size as usize)).unwrap(); this.write_scalar(ptr, dest)?; } "__rust_dealloc" => { @@ -268,10 +266,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.force_ptr(ptr)?; this.memory.deallocate( ptr, - Some(( - Size::from_bytes(old_size), - Align::from_bytes(align).unwrap(), - )), + Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())), MiriMemoryKind::Rust.into(), )?; } @@ -346,7 +341,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "__rust_maybe_catch_panic" => { this.handle_catch_panic(args, dest, ret)?; - return Ok(None) + return Ok(None); } "memcmp" => { @@ -404,7 +399,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - "__errno_location" | "__error" => { + | "__errno_location" + | "__error" + => { let errno_place = this.machine.last_error.unwrap(); this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } @@ -434,7 +431,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "open" | "open64" => { + | "open" + | "open64" + => { let result = this.open(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } @@ -444,7 +443,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "close" | "close$NOCANCEL" => { + | "close" + | "close$NOCANCEL" + => { let result = this.close(args[0])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } @@ -510,7 +511,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // math functions - "cbrtf" | "coshf" | "sinhf" | "tanf" | "acosf" | "asinf" | "atanf" => { + | "cbrtf" + | "coshf" + | "sinhf" + | "tanf" + | "acosf" + | "asinf" + | "atanf" + => { // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); let f = match link_name { @@ -526,7 +534,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?; } // underscore case for windows - "_hypotf" | "hypotf" | "atan2f" => { + | "_hypotf" + | "hypotf" + | "atan2f" + => { // FIXME: Using host floats. let f1 = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); let f2 = f32::from_bits(this.read_scalar(args[1])?.to_u32()?); @@ -538,7 +549,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_u32(n.to_bits()), dest)?; } - "cbrt" | "cosh" | "sinh" | "tan" | "acos" | "asin" | "atan" => { + | "cbrt" + | "cosh" + | "sinh" + | "tan" + | "acos" + | "asin" + | "atan" + => { // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); let f = match link_name { @@ -555,7 +573,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // underscore case for windows, here and below // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) - "_hypot" | "hypot" | "atan2" => { + | "_hypot" + | "hypot" + | "atan2" + => { // FIXME: Using host floats. let f1 = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); let f2 = f64::from_bits(this.read_scalar(args[1])?.to_u64()?); @@ -567,7 +588,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?; } // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. - "_ldexp" | "ldexp" | "scalbn" => { + | "_ldexp" + | "ldexp" + | "scalbn" + => { let x = this.read_scalar(args[0])?.to_f64()?; let exp = this.read_scalar(args[1])?.to_i32()?; @@ -586,7 +610,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Some things needed for `sys::thread` initialization to go through. - "signal" | "sigaction" | "sigaltstack" => { + | "signal" + | "sigaction" + | "sigaltstack" + => { this.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?; } @@ -596,14 +623,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("sysconf() called with name {}", name); // TODO: Cache the sysconf integers via Miri's global cache. let paths = &[ - ( - &["libc", "_SC_PAGESIZE"], - Scalar::from_int(PAGE_SIZE, dest.layout.size), - ), - ( - &["libc", "_SC_GETPW_R_SIZE_MAX"], - Scalar::from_int(-1, dest.layout.size), - ), + (&["libc", "_SC_PAGESIZE"], Scalar::from_int(PAGE_SIZE, dest.layout.size)), + (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)), ( &["libc", "_SC_NPROCESSORS_ONLN"], Scalar::from_int(NUM_CPUS, dest.layout.size), @@ -688,7 +709,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Stack size/address stuff. - "pthread_attr_init" + | "pthread_attr_init" | "pthread_attr_destroy" | "pthread_self" | "pthread_attr_setstacksize" => { @@ -712,12 +733,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // We don't support threading. (Also for Windows.) - "pthread_create" | "CreateThread" => { + | "pthread_create" + | "CreateThread" + => { throw_unsup_format!("Miri does not support threading"); } // Stub out calls for condvar, mutex and rwlock, to just return `0`. - "pthread_mutexattr_init" + | "pthread_mutexattr_init" | "pthread_mutexattr_settype" | "pthread_mutex_init" | "pthread_mutexattr_destroy" @@ -732,7 +755,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "pthread_condattr_setclock" | "pthread_cond_init" | "pthread_condattr_destroy" - | "pthread_cond_destroy" => { + | "pthread_cond_destroy" + => { this.write_null(dest)?; } @@ -751,7 +775,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // macOS API stubs. - "pthread_attr_get_np" | "pthread_getattr_np" => { + | "pthread_attr_get_np" + | "pthread_getattr_np" + => { this.write_null(dest)?; } "pthread_get_stackaddr_np" => { @@ -822,32 +848,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; } - "InitializeCriticalSection" + + | "InitializeCriticalSection" | "EnterCriticalSection" | "LeaveCriticalSection" - | "DeleteCriticalSection" => { + | "DeleteCriticalSection" + => { // Nothing to do, not even a return value. } - "GetModuleHandleW" + + | "GetModuleHandleW" | "GetProcAddress" | "TryEnterCriticalSection" | "GetConsoleScreenBufferInfo" - | "SetConsoleTextAttribute" => { + | "SetConsoleTextAttribute" + => { // Pretend these do not exist / nothing happened, by returning zero. this.write_null(dest)?; } + "GetSystemInfo" => { let system_info = this.deref_operand(args[0])?; // Initialize with `0`. - this.memory - .write_bytes(system_info.ptr, iter::repeat(0u8).take(system_info.layout.size.bytes() as usize))?; + this.memory.write_bytes( + system_info.ptr, + iter::repeat(0u8).take(system_info.layout.size.bytes() as usize), + )?; // Set number of processors. let dword_size = Size::from_bytes(4); let num_cpus = this.mplace_field(system_info, 6)?; - this.write_scalar( - Scalar::from_int(NUM_CPUS, dword_size), - num_cpus.into(), - )?; + this.write_scalar(Scalar::from_int(NUM_CPUS, dword_size), num_cpus.into())?; } "TlsAlloc" => { @@ -894,9 +924,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // stdout/stderr use std::io::{self, Write}; - let buf_cont = this - .memory - .read_bytes(buf, Size::from_bytes(u64::from(n)))?; + let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(u64::from(n)))?; let res = if handle == -11 { io::stdout().write(buf_cont) } else { @@ -928,7 +956,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "GetCommandLineW" => { - this.write_scalar(this.machine.cmd_line.expect("machine must be initialized"), dest)?; + this.write_scalar( + this.machine.cmd_line.expect("machine must be initialized"), + dest, + )?; } // The actual name of 'RtlGenRandom' "SystemFunction036" => { @@ -955,10 +986,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, Option>> { let this = self.eval_context_mut(); if let Ok(instance) = this.resolve_path(path) { - let cid = GlobalId { - instance, - promoted: None, - }; + let cid = GlobalId { instance, promoted: None }; let const_val = this.const_eval_raw(cid)?; let const_val = this.read_scalar(const_val.into())?; return Ok(Some(const_val)); diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 47f3f50b76af..0b78111533a5 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1,11 +1,11 @@ use std::collections::HashMap; -use std::convert::{TryInto, TryFrom}; +use std::convert::{TryFrom, TryInto}; use std::fs::{remove_file, File, OpenOptions}; use std::io::{Read, Write}; use std::path::PathBuf; use std::time::SystemTime; -use rustc::ty::layout::{Size, Align, LayoutOf}; +use rustc::ty::layout::{Align, LayoutOf, Size}; use crate::stacked_borrows::Tag; use crate::*; @@ -172,18 +172,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; let buf = this.read_scalar(buf_op)?.not_undef()?; - let count = this - .read_scalar(count_op)? - .to_machine_usize(&*this.tcx)?; + let count = this.read_scalar(count_op)?.to_machine_usize(&*this.tcx)?; // Check that the *entire* buffer is actually valid memory. - this.memory.check_ptr_access(buf, Size::from_bytes(count), Align::from_bytes(1).unwrap())?; + this.memory.check_ptr_access( + buf, + Size::from_bytes(count), + Align::from_bytes(1).unwrap(), + )?; // We cap the number of read bytes to the largest value that we are able to fit in both the // host's and target's `isize`. This saves us from having to handle overflows later. - let count = count - .min(this.isize_max() as u64) - .min(isize::max_value() as u64); + let count = count.min(this.isize_max() as u64).min(isize::max_value() as u64); if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { // This can never fail because `count` was capped to be smaller than @@ -227,18 +227,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; let buf = this.read_scalar(buf_op)?.not_undef()?; - let count = this - .read_scalar(count_op)? - .to_machine_usize(&*this.tcx)?; + let count = this.read_scalar(count_op)?.to_machine_usize(&*this.tcx)?; // Check that the *entire* buffer is actually valid memory. - this.memory.check_ptr_access(buf, Size::from_bytes(count), Align::from_bytes(1).unwrap())?; + this.memory.check_ptr_access( + buf, + Size::from_bytes(count), + Align::from_bytes(1).unwrap(), + )?; // We cap the number of written bytes to the largest value that we are able to fit in both the // host's and target's `isize`. This saves us from having to handle overflows later. - let count = count - .min(this.isize_max() as u64) - .min(isize::max_value() as u64); + let count = count.min(this.isize_max() as u64).min(isize::max_value() as u64); if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; @@ -263,11 +263,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn statx( &mut self, - dirfd_op: OpTy<'tcx, Tag>, // Should be an `int` + dirfd_op: OpTy<'tcx, Tag>, // Should be an `int` pathname_op: OpTy<'tcx, Tag>, // Should be a `const char *` - flags_op: OpTy<'tcx, Tag>, // Should be an `int` - _mask_op: OpTy<'tcx, Tag>, // Should be an `unsigned int` - statxbuf_op: OpTy<'tcx, Tag> // Should be a `struct statx *` + flags_op: OpTy<'tcx, Tag>, // Should be an `int` + _mask_op: OpTy<'tcx, Tag>, // Should be an `unsigned int` + statxbuf_op: OpTy<'tcx, Tag>, // Should be a `struct statx *` ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -302,29 +302,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let path: PathBuf = this.read_os_str_from_c_str(pathname_scalar)?.into(); // `flags` should be a `c_int` but the `syscall` function provides an `isize`. - let flags: i32 = this - .read_scalar(flags_op)? - .to_machine_isize(&*this.tcx)? - .try_into() - .map_err(|e| err_unsup_format!( - "Failed to convert pointer sized operand to integer: {}", - e - ))?; + let flags: i32 = + this.read_scalar(flags_op)?.to_machine_isize(&*this.tcx)?.try_into().map_err(|e| { + err_unsup_format!("Failed to convert pointer sized operand to integer: {}", e) + })?; // `dirfd` should be a `c_int` but the `syscall` function provides an `isize`. - let dirfd: i32 = this - .read_scalar(dirfd_op)? - .to_machine_isize(&*this.tcx)? - .try_into() - .map_err(|e| err_unsup_format!( - "Failed to convert pointer sized operand to integer: {}", - e - ))?; + let dirfd: i32 = + this.read_scalar(dirfd_op)?.to_machine_isize(&*this.tcx)?.try_into().map_err(|e| { + err_unsup_format!("Failed to convert pointer sized operand to integer: {}", e) + })?; // we only support interpreting `path` as an absolute directory or as a directory relative // to `dirfd` when the latter is `AT_FDCWD`. The behavior of `statx` with a relative path // and a directory file descriptor other than `AT_FDCWD` is specified but it cannot be // tested from `libstd`. If you found this error, please open an issue reporting it. - if !(path.is_absolute() || dirfd == this.eval_libc_i32("AT_FDCWD")?) - { + if !(path.is_absolute() || dirfd == this.eval_libc_i32("AT_FDCWD")?) { throw_unsup_format!( "Using statx with a relative path and a file descriptor different from `AT_FDCWD` is not supported" ) @@ -368,29 +359,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // the owner, its group and other users. Given that we can only provide the file type // without using platform specific methods, we only set the bits corresponding to the file // type. This should be an `__u16` but `libc` provides its values as `u32`. - let mode: u16 = this.eval_libc(mode_name)? - .to_u32()? - .try_into() - .unwrap_or_else(|_| bug!("libc contains bad value for `{}` constant", mode_name)); + let mode: u16 = this + .eval_libc(mode_name)? + .to_u32()? + .try_into() + .unwrap_or_else(|_| bug!("libc contains bad value for `{}` constant", mode_name)); let size = metadata.len(); let (access_sec, access_nsec) = extract_sec_and_nsec( metadata.accessed(), &mut mask, - this.eval_libc("STATX_ATIME")?.to_u32()? + this.eval_libc("STATX_ATIME")?.to_u32()?, )?; let (created_sec, created_nsec) = extract_sec_and_nsec( metadata.created(), &mut mask, - this.eval_libc("STATX_BTIME")?.to_u32()? + this.eval_libc("STATX_BTIME")?.to_u32()?, )?; let (modified_sec, modified_nsec) = extract_sec_and_nsec( metadata.modified(), &mut mask, - this.eval_libc("STATX_MTIME")?.to_u32()? + this.eval_libc("STATX_MTIME")?.to_u32()?, )?; let __u32_layout = this.libc_ty_layout("__u32")?; @@ -401,16 +393,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // zero for the unavailable fields. // FIXME: Provide more fields using platform specific methods. let imms = [ - immty_from_uint_checked(mask, __u32_layout)?, // stx_mask + immty_from_uint_checked(mask, __u32_layout)?, // stx_mask immty_from_uint_checked(0u128, __u32_layout)?, // stx_blksize immty_from_uint_checked(0u128, __u64_layout)?, // stx_attributes immty_from_uint_checked(0u128, __u32_layout)?, // stx_nlink immty_from_uint_checked(0u128, __u32_layout)?, // stx_uid immty_from_uint_checked(0u128, __u32_layout)?, // stx_gid - immty_from_uint_checked(mode, __u16_layout)?, // stx_mode + immty_from_uint_checked(mode, __u16_layout)?, // stx_mode immty_from_uint_checked(0u128, __u16_layout)?, // statx padding immty_from_uint_checked(0u128, __u64_layout)?, // stx_ino - immty_from_uint_checked(size, __u64_layout)?, // stx_size + immty_from_uint_checked(size, __u64_layout)?, // stx_size immty_from_uint_checked(0u128, __u64_layout)?, // stx_blocks immty_from_uint_checked(0u128, __u64_layout)?, // stx_attributes immty_from_uint_checked(access_sec, __u64_layout)?, // stx_atime.tv_sec @@ -451,7 +443,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch, and // then sets the `mask` bits determined by `flag` when `time` is Ok. If `time` is an error, it // returns `(0, 0)` without setting any bits. -fn extract_sec_and_nsec<'tcx>(time: std::io::Result, mask: &mut u32, flag: u32) -> InterpResult<'tcx, (u64, u32)> { +fn extract_sec_and_nsec<'tcx>( + time: std::io::Result, + mask: &mut u32, + flag: u32, +) -> InterpResult<'tcx, (u64, u32)> { if let Ok(time) = time { let duration = system_time_to_duration(&time)?; *mask |= flag; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 57b77a8b7490..bde2dd4655bf 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -1,10 +1,10 @@ use std::iter; -use rustc_apfloat::Float; use rustc::mir; use rustc::mir::interpret::{InterpResult, PointerArithmetic}; -use rustc::ty::layout::{self, LayoutOf, Size, Align}; use rustc::ty; +use rustc::ty::layout::{self, Align, LayoutOf, Size}; +use rustc_apfloat::Float; use syntax::source_map::Span; use crate::*; @@ -17,13 +17,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, - unwind: Option + unwind: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if this.emulate_intrinsic(span, instance, args, ret)? { return Ok(()); } - let tcx = &{this.tcx.tcx}; + let tcx = &{ this.tcx.tcx }; let substs = instance.substs; // All these intrinsics take raw pointers, so if we access memory directly @@ -37,13 +37,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_machine_stop!(TerminationInfo::Abort); } "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), - _ => { + _ => if let Some(p) = ret { p } else { throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name); - } - } + }, }; match intrinsic_name { @@ -75,9 +74,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.copy_op(args[1], place.into())?; } - "atomic_load" | - "atomic_load_relaxed" | - "atomic_load_acq" => { + #[rustfmt::skip] + | "atomic_load" + | "atomic_load_relaxed" + | "atomic_load_acq" + => { let place = this.deref_operand(args[0])?; let val = this.read_scalar(place.into())?; // make sure it fits into a scalar; otherwise it cannot be atomic @@ -90,9 +91,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(val, dest)?; } - "atomic_store" | - "atomic_store_relaxed" | - "atomic_store_rel" => { + #[rustfmt::skip] + | "atomic_store" + | "atomic_store_relaxed" + | "atomic_store_rel" + => { let place = this.deref_operand(args[0])?; let val = this.read_scalar(args[1])?; // make sure it fits into a scalar; otherwise it cannot be atomic @@ -105,10 +108,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(val, place.into())?; } - "atomic_fence_acq" | - "atomic_fence_rel" | - "atomic_fence_acqrel" | - "atomic_fence" => { + #[rustfmt::skip] + | "atomic_fence_acq" + | "atomic_fence_rel" + | "atomic_fence_acqrel" + | "atomic_fence" + => { // we are inherently singlethreaded and singlecored, this is a nop } @@ -139,46 +144,49 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; - // binary_op will bail if either of them is not a scalar + // `binary_op` will bail if either of them is not a scalar. let eq = this.overflowing_binary_op(mir::BinOp::Eq, old, expect_old)?.0; let res = Immediate::ScalarPair(old.to_scalar_or_undef(), eq.into()); - this.write_immediate(res, dest)?; // old value is returned - // update ptr depending on comparison + // Return old value. + this.write_immediate(res, dest)?; + // Update ptr depending on comparison. if eq.to_bool()? { this.write_scalar(new, place.into())?; } } - "atomic_or" | - "atomic_or_acq" | - "atomic_or_rel" | - "atomic_or_acqrel" | - "atomic_or_relaxed" | - "atomic_xor" | - "atomic_xor_acq" | - "atomic_xor_rel" | - "atomic_xor_acqrel" | - "atomic_xor_relaxed" | - "atomic_and" | - "atomic_and_acq" | - "atomic_and_rel" | - "atomic_and_acqrel" | - "atomic_and_relaxed" | - "atomic_nand" | - "atomic_nand_acq" | - "atomic_nand_rel" | - "atomic_nand_acqrel" | - "atomic_nand_relaxed" | - "atomic_xadd" | - "atomic_xadd_acq" | - "atomic_xadd_rel" | - "atomic_xadd_acqrel" | - "atomic_xadd_relaxed" | - "atomic_xsub" | - "atomic_xsub_acq" | - "atomic_xsub_rel" | - "atomic_xsub_acqrel" | - "atomic_xsub_relaxed" => { + #[rustfmt::skip] + | "atomic_or" + | "atomic_or_acq" + | "atomic_or_rel" + | "atomic_or_acqrel" + | "atomic_or_relaxed" + | "atomic_xor" + | "atomic_xor_acq" + | "atomic_xor_rel" + | "atomic_xor_acqrel" + | "atomic_xor_relaxed" + | "atomic_and" + | "atomic_and_acq" + | "atomic_and_rel" + | "atomic_and_acqrel" + | "atomic_and_relaxed" + | "atomic_nand" + | "atomic_nand_acq" + | "atomic_nand_rel" + | "atomic_nand_acqrel" + | "atomic_nand_relaxed" + | "atomic_xadd" + | "atomic_xadd_acq" + | "atomic_xadd_rel" + | "atomic_xadd_acqrel" + | "atomic_xadd_relaxed" + | "atomic_xsub" + | "atomic_xsub_acq" + | "atomic_xsub_rel" + | "atomic_xsub_acqrel" + | "atomic_xsub_relaxed" + => { let place = this.deref_operand(args[0])?; if !place.layout.ty.is_integral() { bug!("Atomic arithmetic operations only work on integer types"); @@ -204,18 +212,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Atomics wrap around on overflow. let val = this.binary_op(op, old, rhs)?; - let val = if neg { - this.unary_op(mir::UnOp::Not, val)? - } else { - val - }; + let val = if neg { this.unary_op(mir::UnOp::Not, val)? } else { val }; this.write_immediate(*val, place.into())?; } "breakpoint" => unimplemented!(), // halt miri - "copy" | - "copy_nonoverlapping" => { + #[rustfmt::skip] + | "copy" + | "copy_nonoverlapping" + => { let elem_ty = substs.type_at(0); let elem_layout = this.layout_of(elem_ty)?; let elem_size = elem_layout.size.bytes(); @@ -244,8 +250,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_uint(discr_val, dest.layout.size), dest)?; } - "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | - "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" | "roundf32" => { + #[rustfmt::skip] + | "sinf32" + | "fabsf32" + | "cosf32" + | "sqrtf32" + | "expf32" + | "exp2f32" + | "logf32" + | "log10f32" + | "log2f32" + | "floorf32" + | "ceilf32" + | "truncf32" + | "roundf32" + => { // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); let f = match intrinsic_name { @@ -267,8 +286,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?; } - "sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" | - "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" | "roundf64" => { + #[rustfmt::skip] + | "sinf64" + | "fabsf64" + | "cosf64" + | "sqrtf64" + | "expf64" + | "exp2f64" + | "logf64" + | "log10f64" + | "log2f64" + | "floorf64" + | "ceilf64" + | "truncf64" + | "roundf64" + => { // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); let f = match intrinsic_name { @@ -290,7 +322,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_u64(f.to_bits()), dest)?; } - "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { + #[rustfmt::skip] + | "fadd_fast" + | "fsub_fast" + | "fmul_fast" + | "fdiv_fast" + | "frem_fast" + => { let a = this.read_immediate(args[0])?; let b = this.read_immediate(args[1])?; let op = match intrinsic_name { @@ -304,7 +342,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.binop_ignore_overflow(op, a, b, dest)?; } - "minnumf32" | "maxnumf32" | "copysignf32" => { + #[rustfmt::skip] + | "minnumf32" + | "maxnumf32" + | "copysignf32" + => { let a = this.read_scalar(args[0])?.to_f32()?; let b = this.read_scalar(args[1])?.to_f32()?; let res = match intrinsic_name { @@ -316,7 +358,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_f32(res), dest)?; } - "minnumf64" | "maxnumf64" | "copysignf64" => { + #[rustfmt::skip] + | "minnumf64" + | "maxnumf64" + | "copysignf64" + => { let a = this.read_scalar(args[0])?.to_f64()?; let b = this.read_scalar(args[1])?.to_f64()?; let res = match intrinsic_name { @@ -329,15 +375,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "exact_div" => - this.exact_div( - this.read_immediate(args[0])?, - this.read_immediate(args[1])?, - dest, - )?, + this.exact_div(this.read_immediate(args[0])?, this.read_immediate(args[1])?, dest)?, "forget" => {} - "likely" | "unlikely" => { + #[rustfmt::skip] + | "likely" + | "unlikely" + => { // These just return their argument let b = this.read_immediate(args[0])?; this.write_immediate(*b, dest)?; @@ -365,7 +410,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Do it in memory let mplace = this.force_allocation(dest)?; mplace.meta.unwrap_none(); // must be sized - this.memory.write_bytes(mplace.ptr, iter::repeat(0u8).take(dest.layout.size.bytes() as usize))?; + this.memory.write_bytes( + mplace.ptr, + iter::repeat(0u8).take(dest.layout.size.bytes() as usize), + )?; } } } @@ -405,20 +453,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); let f2 = f32::from_bits(this.read_scalar(args[1])?.to_u32()?); - this.write_scalar( - Scalar::from_u32(f.powf(f2).to_bits()), - dest, - )?; + this.write_scalar(Scalar::from_u32(f.powf(f2).to_bits()), dest)?; } "powf64" => { // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); let f2 = f64::from_bits(this.read_scalar(args[1])?.to_u64()?); - this.write_scalar( - Scalar::from_u64(f.powf(f2).to_bits()), - dest, - )?; + this.write_scalar(Scalar::from_u64(f.powf(f2).to_bits()), dest)?; } "fmaf32" => { @@ -426,10 +468,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let b = this.read_scalar(args[1])?.to_f32()?; let c = this.read_scalar(args[2])?.to_f32()?; let res = a.mul_add(b, c).value; - this.write_scalar( - Scalar::from_f32(res), - dest, - )?; + this.write_scalar(Scalar::from_f32(res), dest)?; } "fmaf64" => { @@ -437,53 +476,42 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let b = this.read_scalar(args[1])?.to_f64()?; let c = this.read_scalar(args[2])?.to_f64()?; let res = a.mul_add(b, c).value; - this.write_scalar( - Scalar::from_f64(res), - dest, - )?; + this.write_scalar(Scalar::from_f64(res), dest)?; } "powif32" => { // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); let i = this.read_scalar(args[1])?.to_i32()?; - this.write_scalar( - Scalar::from_u32(f.powi(i).to_bits()), - dest, - )?; + this.write_scalar(Scalar::from_u32(f.powi(i).to_bits()), dest)?; } "powif64" => { // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); let i = this.read_scalar(args[1])?.to_i32()?; - this.write_scalar( - Scalar::from_u64(f.powi(i).to_bits()), - dest, - )?; + this.write_scalar(Scalar::from_u64(f.powi(i).to_bits()), dest)?; } "size_of_val" => { let mplace = this.deref_operand(args[0])?; - let (size, _) = this.size_and_align_of_mplace(mplace)? + let (size, _) = this + .size_and_align_of_mplace(mplace)? .expect("size_of_val called on extern type"); let ptr_size = this.pointer_size(); - this.write_scalar( - Scalar::from_uint(size.bytes() as u128, ptr_size), - dest, - )?; + this.write_scalar(Scalar::from_uint(size.bytes() as u128, ptr_size), dest)?; } - "min_align_of_val" | - "align_of_val" => { + #[rustfmt::skip] + | "min_align_of_val" + | "align_of_val" + => { let mplace = this.deref_operand(args[0])?; - let (_, align) = this.size_and_align_of_mplace(mplace)? + let (_, align) = this + .size_and_align_of_mplace(mplace)? .expect("size_of_val called on extern type"); let ptr_size = this.pointer_size(); - this.write_scalar( - Scalar::from_uint(align.bytes(), ptr_size), - dest, - )?; + this.write_scalar(Scalar::from_uint(align.bytes(), ptr_size), dest)?; } "unchecked_div" => { @@ -493,12 +521,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if rval == 0 { throw_ub_format!("Division by 0 in unchecked_div"); } - this.binop_ignore_overflow( - mir::BinOp::Div, - l, - r, - dest, - )?; + this.binop_ignore_overflow(mir::BinOp::Div, l, r, dest)?; } "unchecked_rem" => { @@ -508,15 +531,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if rval == 0 { throw_ub_format!("Division by 0 in unchecked_rem"); } - this.binop_ignore_overflow( - mir::BinOp::Rem, - l, - r, - dest, - )?; + this.binop_ignore_overflow(mir::BinOp::Rem, l, r, dest)?; } - "unchecked_add" | "unchecked_sub" | "unchecked_mul" => { + #[rustfmt::skip] + | "unchecked_add" + | "unchecked_sub" + | "unchecked_mul" + => { let l = this.read_immediate(args[0])?; let r = this.read_immediate(args[1])?; let op = match intrinsic_name { @@ -555,9 +577,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mplace.meta.unwrap_none(); let ptr = mplace.ptr.to_ptr()?; // We know the return place is in-bounds - this.memory - .get_raw_mut(ptr.alloc_id)? - .mark_definedness(ptr, dest.layout.size, false); + this.memory.get_raw_mut(ptr.alloc_id)?.mark_definedness( + ptr, + dest.layout.size, + false, + ); } } } @@ -570,7 +594,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.read_scalar(args[0])?.not_undef()?; let count = this.read_scalar(args[2])?.to_machine_usize(this)?; let byte_count = ty_layout.size * count; - this.memory.write_bytes(ptr, iter::repeat(val_byte).take(byte_count.bytes() as usize))?; + this.memory + .write_bytes(ptr, iter::repeat(val_byte).take(byte_count.bytes() as usize))?; } name => throw_unsup_format!("unimplemented intrinsic: {}", name), diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 06ef58eaf526..2889807bf76a 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -1,14 +1,14 @@ pub mod dlsym; pub mod env; pub mod foreign_items; -pub mod intrinsics; -pub mod tls; pub mod fs; -pub mod time; +pub mod intrinsics; pub mod panic; +pub mod time; +pub mod tls; -use rustc::{mir, ty}; use crate::*; +use rustc::{mir, ty}; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -17,14 +17,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, - unwind: Option + unwind: Option, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); - trace!( - "eval_fn_call: {:#?}, {:?}", - instance, - ret.map(|p| *p.0) - ); + trace!("eval_fn_call: {:#?}, {:?}", instance, ret.map(|p| *p.0)); // There are some more lang items we want to hook that CTFE does not hook (yet). if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { @@ -59,10 +55,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); - let req_align = this.force_bits( - this.read_scalar(align_op)?.not_undef()?, - this.pointer_size(), - )? as usize; + let req_align = this + .force_bits(this.read_scalar(align_op)?.not_undef()?, this.pointer_size())? + as usize; // FIXME: This should actually panic in the interpreted program if !req_align.is_power_of_two() { @@ -72,7 +67,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr_scalar = this.read_scalar(ptr_op)?.not_undef()?; if let Ok(ptr) = this.force_ptr(ptr_scalar) { - let cur_align = this.memory.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead)?.1.bytes() as usize; + let cur_align = + this.memory.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead)?.1.bytes() + as usize; if cur_align >= req_align { // if the allocation alignment is at least the required alignment we use the // libcore implementation diff --git a/src/shims/panic.rs b/src/shims/panic.rs index fc3339352a98..f242f41f6f96 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -11,10 +11,10 @@ //! gets popped *during unwinding*, we take the panic payload and store it according to the extra //! metadata we remembered when pushing said frame. -use syntax::source_map::Span; use rustc::mir; use rustc::ty::{self, layout::LayoutOf}; use rustc_target::spec::PanicStrategy; +use syntax::source_map::Span; use crate::*; @@ -35,13 +35,12 @@ pub struct CatchUnwindData<'tcx> { impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// Handles the special "miri_start_panic" intrinsic, which is called /// by libpanic_unwind to delegate the actual unwinding process to Miri. fn handle_miri_start_panic( &mut self, args: &[OpTy<'tcx, Tag>], - unwind: Option + unwind: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -49,12 +48,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Get the raw pointer stored in arg[0] (the panic payload). let scalar = this.read_immediate(args[0])?; - assert!(this.machine.panic_payload.is_none(), "the panic runtime should avoid double-panics"); + assert!( + this.machine.panic_payload.is_none(), + "the panic runtime should avoid double-panics" + ); this.machine.panic_payload = Some(scalar); // Jump to the unwind block to begin unwinding. this.unwind_to_block(unwind); - return Ok(()) + return Ok(()); } fn handle_catch_panic( @@ -64,7 +66,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ret: mir::BasicBlock, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let tcx = &{this.tcx.tcx}; + let tcx = &{ this.tcx.tcx }; // fn __rust_maybe_catch_panic( // f: fn(*mut u8), @@ -82,8 +84,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Now we make a function call, and pass `f_arg` as first and only argument. let f_instance = this.memory.get_fn(f)?.as_instance()?; trace!("__rust_maybe_catch_panic: {:?}", f_instance); - let ret_place = - MPlaceTy::dangling(this.layout_of(tcx.mk_unit())?, this).into(); + let ret_place = MPlaceTy::dangling(this.layout_of(tcx.mk_unit())?, this).into(); this.call_function( f_instance, &[f_arg.into()], @@ -99,11 +100,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This lets `handle_stack_pop` (below) know that we should stop unwinding // when we pop this frame. if this.tcx.tcx.sess.panic_strategy() == PanicStrategy::Unwind { - this.frame_mut().extra.catch_panic = Some(CatchUnwindData { - data_place, - vtable_place, - dest, - }) + this.frame_mut().extra.catch_panic = + Some(CatchUnwindData { data_place, vtable_place, dest }) } return Ok(()); @@ -112,7 +110,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn handle_stack_pop( &mut self, mut extra: FrameData<'tcx>, - unwinding: bool + unwinding: bool, ) -> InterpResult<'tcx, StackPopInfo> { let this = self.eval_context_mut(); diff --git a/src/shims/time.rs b/src/shims/time.rs index da9ea07c4f25..a7d51eaa2e0f 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -9,10 +9,9 @@ fn get_time<'tcx>() -> InterpResult<'tcx, Duration> { system_time_to_duration(&SystemTime::now()) } -// Returns the time elapsed between the provided time and the unix epoch as a `Duration`. +/// Returns the time elapsed between the provided time and the unix epoch as a `Duration`. pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Duration> { - time - .duration_since(SystemTime::UNIX_EPOCH) + time.duration_since(SystemTime::UNIX_EPOCH) .map_err(|_| err_unsup_format!("Times before the Unix epoch are not supported").into()) } diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 420fd63a6181..cdfc0bcda8b6 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -2,14 +2,10 @@ use std::collections::BTreeMap; -use rustc_target::abi::LayoutOf; use rustc::{ty, ty::layout::HasDataLayout}; +use rustc_target::abi::LayoutOf; -use crate::{ - InterpResult, StackPopCleanup, - MPlaceTy, Scalar, Tag, - HelpersEvalContextExt, -}; +use crate::{HelpersEvalContextExt, InterpResult, MPlaceTy, Scalar, StackPopCleanup, Tag}; pub type TlsKey = u128; @@ -41,19 +37,10 @@ impl<'tcx> Default for TlsData<'tcx> { } impl<'tcx> TlsData<'tcx> { - pub fn create_tls_key( - &mut self, - dtor: Option>, - ) -> TlsKey { + pub fn create_tls_key(&mut self, dtor: Option>) -> TlsKey { let new_key = self.next_key; self.next_key += 1; - self.keys.insert( - new_key, - TlsEntry { - data: None, - dtor, - }, - ).unwrap_none(); + self.keys.insert(new_key, TlsEntry { data: None, dtor }).unwrap_none(); trace!("New TLS key allocated: {} with dtor {:?}", new_key, dtor); new_key } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 8782eb83d183..fb68f46d379e 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -3,17 +3,17 @@ use std::cell::RefCell; use std::collections::{HashMap, HashSet}; -use std::rc::Rc; use std::fmt; use std::num::NonZeroU64; +use std::rc::Rc; -use rustc::ty::{self, layout::Size}; -use rustc::hir::Mutability::{Mutable, Immutable}; +use rustc::hir::Mutability::{Immutable, Mutable}; use rustc::mir::RetagKind; +use rustc::ty::{self, layout::Size}; use crate::{ - InterpResult, HelpersEvalContextExt, TerminationInfo, - MemoryKind, MiriMemoryKind, RangeMap, AllocId, Pointer, Immediate, ImmTy, PlaceTy, MPlaceTy, + AllocId, HelpersEvalContextExt, ImmTy, Immediate, InterpResult, MPlaceTy, MemoryKind, + MiriMemoryKind, PlaceTy, Pointer, RangeMap, TerminationInfo, }; pub type PtrId = NonZeroU64; @@ -82,7 +82,6 @@ pub struct Stack { borrows: Vec, } - /// Extra per-allocation state. #[derive(Clone, Debug)] pub struct Stacks { @@ -217,7 +216,8 @@ impl Permission { /// This defines for a given permission, whether it permits the given kind of access. fn grants(self, access: AccessKind) -> bool { // Disabled grants nothing. Otherwise, all items grant read access, and except for SharedReadOnly they grant write access. - self != Permission::Disabled && (access == AccessKind::Read || self != Permission::SharedReadOnly) + self != Permission::Disabled + && (access == AccessKind::Read || self != Permission::SharedReadOnly) } } @@ -226,17 +226,16 @@ impl<'tcx> Stack { /// Find the item granting the given kind of access to the given tag, and return where /// it is on the stack. fn find_granting(&self, access: AccessKind, tag: Tag) -> Option { - self.borrows.iter() + self.borrows + .iter() .enumerate() // we also need to know *where* in the stack .rev() // search top-to-bottom // Return permission of first item that grants access. // We require a permission with the right tag, ensuring U3 and F3. - .find_map(|(idx, item)| - if tag == item.tag && item.perm.grants(access) { - Some(idx) - } else { - None - } + .find_map( + |(idx, item)| { + if tag == item.tag && item.perm.grants(access) { Some(idx) } else { None } + }, ) } @@ -245,13 +244,10 @@ impl<'tcx> Stack { fn find_first_write_incompatible(&self, granting: usize) -> usize { let perm = self.borrows[granting].perm; match perm { - Permission::SharedReadOnly => - bug!("Cannot use SharedReadOnly for writing"), - Permission::Disabled => - bug!("Cannot use Disabled for anything"), - Permission::Unique => - // On a write, everything above us is incompatible. - granting + 1, + Permission::SharedReadOnly => bug!("Cannot use SharedReadOnly for writing"), + Permission::Disabled => bug!("Cannot use Disabled for anything"), + // On a write, everything above us is incompatible. + Permission::Unique => granting + 1, Permission::SharedReadWrite => { // The SharedReadWrite *just* above us are compatible, to skip those. let mut idx = granting + 1; @@ -285,7 +281,8 @@ impl<'tcx> Stack { ))); } else { throw_ub!(UbExperimental(format!( - "deallocating while item is protected: {:?}", item + "deallocating while item is protected: {:?}", + item ))); } } @@ -295,20 +292,16 @@ impl<'tcx> Stack { /// Test if a memory `access` using pointer tagged `tag` is granted. /// If yes, return the index of the item that granted it. - fn access( - &mut self, - access: AccessKind, - tag: Tag, - global: &GlobalState, - ) -> InterpResult<'tcx> { + fn access(&mut self, access: AccessKind, tag: Tag, global: &GlobalState) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. - let granting_idx = self.find_granting(access, tag) - .ok_or_else(|| err_ub!(UbExperimental(format!( + let granting_idx = self.find_granting(access, tag).ok_or_else(|| { + err_ub!(UbExperimental(format!( "no item granting {} to tag {:?} found in borrow stack", access, tag, - ))))?; + ))) + })?; // Step 2: Remove incompatible items above them. Make sure we do not remove protected // items. Behavior differs for reads and writes. @@ -329,7 +322,7 @@ impl<'tcx> Stack { // This pattern occurs a lot in the standard library: create a raw pointer, then also create a shared // reference and use that. // We *disable* instead of removing `Unique` to avoid "connecting" two neighbouring blocks of SRWs. - for idx in (granting_idx+1 .. self.borrows.len()).rev() { + for idx in ((granting_idx + 1)..self.borrows.len()).rev() { let item = &mut self.borrows[idx]; if item.perm == Permission::Unique { trace!("access: disabling item {:?}", item); @@ -345,17 +338,14 @@ impl<'tcx> Stack { /// Deallocate a location: Like a write access, but also there must be no /// active protectors at all because we will remove all items. - fn dealloc( - &mut self, - tag: Tag, - global: &GlobalState, - ) -> InterpResult<'tcx> { + fn dealloc(&mut self, tag: Tag, global: &GlobalState) -> InterpResult<'tcx> { // Step 1: Find granting item. - self.find_granting(AccessKind::Write, tag) - .ok_or_else(|| err_ub!(UbExperimental(format!( + self.find_granting(AccessKind::Write, tag).ok_or_else(|| { + err_ub!(UbExperimental(format!( "no item granting write access for deallocation to tag {:?} found in borrow stack", tag, - ))))?; + ))) + })?; // Step 2: Remove all items. Also checks for protectors. for item in self.borrows.drain(..).rev() { @@ -369,18 +359,10 @@ impl<'tcx> Stack { /// `weak` controls whether this operation is weak or strong: weak granting does not act as /// an access, and they add the new item directly on top of the one it is derived /// from instead of all the way at the top of the stack. - fn grant( - &mut self, - derived_from: Tag, - new: Item, - global: &GlobalState, - ) -> InterpResult<'tcx> { + fn grant(&mut self, derived_from: Tag, new: Item, global: &GlobalState) -> InterpResult<'tcx> { // Figure out which access `perm` corresponds to. - let access = if new.perm.grants(AccessKind::Write) { - AccessKind::Write - } else { - AccessKind::Read - }; + let access = + if new.perm.grants(AccessKind::Write) { AccessKind::Write } else { AccessKind::Read }; // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. let granting_idx = self.find_granting(access, derived_from) @@ -392,7 +374,10 @@ impl<'tcx> Stack { // Either way, we ensure that we insert the new item in a way such that between // `derived_from` and the new one, there are only items *compatible with* `derived_from`. let new_idx = if new.perm == Permission::SharedReadWrite { - assert!(access == AccessKind::Write, "this case only makes sense for stack-like accesses"); + assert!( + access == AccessKind::Write, + "this case only makes sense for stack-like accesses" + ); // SharedReadWrite can coexist with "existing loans", meaning they don't act like a write // access. Instead of popping the stack, we insert the item at the place the stack would // be popped to (i.e., we insert it above all the write-compatible items). @@ -412,7 +397,7 @@ impl<'tcx> Stack { }; // Put the new item there. As an optimization, deduplicate if it is equal to one of its new neighbors. - if self.borrows[new_idx-1] == new || self.borrows.get(new_idx) == Some(&new) { + if self.borrows[new_idx - 1] == new || self.borrows.get(new_idx) == Some(&new) { // Optimization applies, done. trace!("reborrow: avoiding adding redundant item {:?}", new); } else { @@ -428,21 +413,11 @@ impl<'tcx> Stack { /// Map per-stack operations to higher-level per-location-range operations. impl<'tcx> Stacks { /// Creates new stack with initial tag. - fn new( - size: Size, - perm: Permission, - tag: Tag, - extra: MemoryExtra, - ) -> Self { + fn new(size: Size, perm: Permission, tag: Tag, extra: MemoryExtra) -> Self { let item = Item { perm, tag, protector: None }; - let stack = Stack { - borrows: vec![item], - }; + let stack = Stack { borrows: vec![item] }; - Stacks { - stacks: RefCell::new(RangeMap::new(size, stack)), - global: extra, - } + Stacks { stacks: RefCell::new(RangeMap::new(size, stack)), global: extra } } /// Call `f` on every stack in the range. @@ -470,33 +445,27 @@ impl Stacks { kind: MemoryKind, ) -> (Self, Tag) { let (tag, perm) = match kind { - MemoryKind::Stack => - // New unique borrow. This tag is not accessible by the program, - // so it will only ever be used when using the local directly (i.e., - // not through a pointer). That is, whenever we directly write to a local, this will pop - // everything else off the stack, invalidating all previous pointers, - // and in particular, *all* raw pointers. - (Tag::Tagged(extra.borrow_mut().new_ptr()), Permission::Unique), + // New unique borrow. This tag is not accessible by the program, + // so it will only ever be used when using the local directly (i.e., + // not through a pointer). That is, whenever we directly write to a local, this will pop + // everything else off the stack, invalidating all previous pointers, + // and in particular, *all* raw pointers. + MemoryKind::Stack => (Tag::Tagged(extra.borrow_mut().new_ptr()), Permission::Unique), + // Static memory can be referenced by "global" pointers from `tcx`. + // Thus we call `static_base_ptr` such that the global pointers get the same tag + // as what we use here. + // The base pointer is not unique, so the base permission is `SharedReadWrite`. MemoryKind::Machine(MiriMemoryKind::Static) => - // Static memory can be referenced by "global" pointers from `tcx`. - // Thus we call `static_base_ptr` such that the global pointers get the same tag - // as what we use here. - // The base pointer is not unique, so the base permission is `SharedReadWrite`. (extra.borrow_mut().static_base_ptr(id), Permission::SharedReadWrite), - _ => - // Everything else we handle entirely untagged for now. - // FIXME: experiment with more precise tracking. - (Tag::Untagged, Permission::SharedReadWrite), + // Everything else we handle entirely untagged for now. + // FIXME: experiment with more precise tracking. + _ => (Tag::Untagged, Permission::SharedReadWrite), }; (Stacks::new(size, perm, tag, extra), tag) } #[inline(always)] - pub fn memory_read<'tcx>( - &self, - ptr: Pointer, - size: Size, - ) -> InterpResult<'tcx> { + pub fn memory_read<'tcx>(&self, ptr: Pointer, size: Size) -> InterpResult<'tcx> { trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); self.for_each(ptr, size, |stack, global| { stack.access(AccessKind::Read, ptr.tag, global)?; @@ -505,11 +474,7 @@ impl Stacks { } #[inline(always)] - pub fn memory_written<'tcx>( - &mut self, - ptr: Pointer, - size: Size, - ) -> InterpResult<'tcx> { + pub fn memory_written<'tcx>(&mut self, ptr: Pointer, size: Size) -> InterpResult<'tcx> { trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); self.for_each(ptr, size, |stack, global| { stack.access(AccessKind::Write, ptr.tag, global)?; @@ -524,9 +489,7 @@ impl Stacks { size: Size, ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - self.for_each(ptr, size, |stack, global| { - stack.dealloc(ptr.tag, global) - }) + self.for_each(ptr, size, |stack, global| stack.dealloc(ptr.tag, global)) } } @@ -545,12 +508,20 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let protector = if protect { Some(this.frame().extra.call_id) } else { None }; let ptr = place.ptr.to_ptr().expect("we should have a proper pointer"); - trace!("reborrow: {} reference {:?} derived from {:?} (pointee {}): {:?}, size {}", - kind, new_tag, ptr.tag, place.layout.ty, ptr.erase_tag(), size.bytes()); + trace!( + "reborrow: {} reference {:?} derived from {:?} (pointee {}): {:?}, size {}", + kind, + new_tag, + ptr.tag, + place.layout.ty, + ptr.erase_tag(), + size.bytes() + ); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. let extra = &this.memory.get_raw(ptr.alloc_id)?.extra; - let stacked_borrows = extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); + let stacked_borrows = + extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); // Update the stacks. // Make sure that raw pointers and mutable shared references are reborrowed "weak": // There could be existing unique pointers reborrowed from them that should remain valid! @@ -564,7 +535,11 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We need a frozen-sensitive reborrow. return this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { // We are only ever `SharedReadOnly` inside the frozen bits. - let perm = if frozen { Permission::SharedReadOnly } else { Permission::SharedReadWrite }; + let perm = if frozen { + Permission::SharedReadOnly + } else { + Permission::SharedReadWrite + }; let item = Item { perm, tag: new_tag, protector }; stacked_borrows.for_each(cur_ptr, size, |stack, global| { stack.grant(cur_ptr.tag, item, global) @@ -573,9 +548,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } }; let item = Item { perm, tag: new_tag, protector }; - stacked_borrows.for_each(ptr, size, |stack, global| { - stack.grant(ptr.tag, item, global) - }) + stacked_borrows.for_each(ptr, size, |stack, global| stack.grant(ptr.tag, item, global)) } /// Retags an indidual pointer, returning the retagged version. @@ -589,7 +562,8 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); // We want a place for where the ptr *points to*, so we get one. let place = this.ref_to_mplace(val)?; - let size = this.size_and_align_of_mplace(place)? + let size = this + .size_and_align_of_mplace(place)? .map(|(size, _)| size) .unwrap_or_else(|| place.layout.size); // We can see dangling ptrs in here e.g. after a Box's `Unique` was @@ -622,11 +596,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn retag( - &mut self, - kind: RetagKind, - place: PlaceTy<'tcx, Tag> - ) -> InterpResult<'tcx> { + fn retag(&mut self, kind: RetagKind, place: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); // Determine mutability and whether to add a protector. // Cannot use `builtin_deref` because that reports *immutable* for `Box`, @@ -634,10 +604,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn qualify(ty: ty::Ty<'_>, kind: RetagKind) -> Option<(RefKind, bool)> { match ty.kind { // References are simple. - ty::Ref(_, _, Mutable) => - Some((RefKind::Unique { two_phase: kind == RetagKind::TwoPhase}, kind == RetagKind::FnEntry)), - ty::Ref(_, _, Immutable) => - Some((RefKind::Shared, kind == RetagKind::FnEntry)), + ty::Ref(_, _, Mutable) => Some(( + RefKind::Unique { two_phase: kind == RetagKind::TwoPhase }, + kind == RetagKind::FnEntry, + )), + ty::Ref(_, _, Immutable) => Some((RefKind::Shared, kind == RetagKind::FnEntry)), // Raw pointers need to be enabled. ty::RawPtr(tym) if kind == RetagKind::Raw => Some((RefKind::Raw { mutable: tym.mutbl == Mutable }, false)), diff --git a/tests/compiletest.rs b/tests/compiletest.rs index bc1ba2eda568..eaaa87464dbf 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -2,11 +2,11 @@ // Custom test runner, to avoid libtest being wrapped around compiletest which wraps libtest. #![test_runner(test_runner)] -use std::path::PathBuf; use std::env; +use std::path::PathBuf; -use compiletest_rs as compiletest; use colored::*; +use compiletest_rs as compiletest; fn miri_path() -> PathBuf { if rustc_test_suite().is_some() { @@ -57,12 +57,15 @@ fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec) { fn compile_fail(path: &str, target: &str, opt: bool) { let opt_str = if opt { " with optimizations" } else { "" }; - eprintln!("{}", format!( - "## Running compile-fail tests in {} against miri for target {}{}", - path, - target, - opt_str - ).green().bold()); + eprintln!( + "{}", + format!( + "## Running compile-fail tests in {} against miri for target {}{}", + path, target, opt_str + ) + .green() + .bold() + ); let mut flags = Vec::new(); if opt { @@ -76,12 +79,15 @@ fn compile_fail(path: &str, target: &str, opt: bool) { fn miri_pass(path: &str, target: &str, opt: bool) { let opt_str = if opt { " with optimizations" } else { "" }; - eprintln!("{}", format!( - "## Running run-pass tests in {} against miri for target {}{}", - path, - target, - opt_str - ).green().bold()); + eprintln!( + "{}", + format!( + "## Running run-pass tests in {} against miri for target {}{}", + path, target, opt_str + ) + .green() + .bold() + ); let mut flags = Vec::new(); if opt { From e325ad24f2ef170b2913d97a69da38ca664cb621 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 Dec 2019 17:44:02 +0100 Subject: [PATCH 1416/5092] support main functions with Result return type --- src/eval.rs | 5 ++--- tests/run-pass/main_result.rs | 3 +++ 2 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 tests/run-pass/main_result.rs diff --git a/src/eval.rs b/src/eval.rs index 4ed1b272b228..0cc302b967b2 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -62,9 +62,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Setup first stack-frame let main_instance = ty::Instance::mono(tcx, main_id); let main_mir = ecx.load_mir(main_instance.def, None)?; - - if !main_mir.return_ty().is_unit() || main_mir.arg_count != 0 { - throw_unsup_format!("miri does not support main functions without `fn()` type signatures"); + if main_mir.arg_count != 0 { + bug!("main function must not take any arguments"); } let start_id = tcx.lang_items().start_fn().unwrap(); diff --git a/tests/run-pass/main_result.rs b/tests/run-pass/main_result.rs new file mode 100644 index 000000000000..078760ee6667 --- /dev/null +++ b/tests/run-pass/main_result.rs @@ -0,0 +1,3 @@ +fn main() -> Result<(), Box> { + Ok(()) +} From bac261573f3693d3cffdb6789b957bd31395997a Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 22 Dec 2019 10:05:52 +0100 Subject: [PATCH 1417/5092] Rustup to rustc 1.42.0-nightly (005cf38f7 2019-12-22) --- rust-version | 2 +- src/stacked_borrows.rs | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index f3c0b833d1a1..999e8b0f8f73 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9ff30a7810c586819a78188c173a7b74adbb9730 +9ae6cedb8d1e37469be1434642a3e403fce50a03 diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index fb68f46d379e..d986a2db5383 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -7,7 +7,7 @@ use std::fmt; use std::num::NonZeroU64; use std::rc::Rc; -use rustc::hir::Mutability::{Immutable, Mutable}; +use rustc::hir::Mutability; use rustc::mir::RetagKind; use rustc::ty::{self, layout::Size}; @@ -604,14 +604,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn qualify(ty: ty::Ty<'_>, kind: RetagKind) -> Option<(RefKind, bool)> { match ty.kind { // References are simple. - ty::Ref(_, _, Mutable) => Some(( + ty::Ref(_, _, Mutability::Mut) => Some(( RefKind::Unique { two_phase: kind == RetagKind::TwoPhase }, kind == RetagKind::FnEntry, )), - ty::Ref(_, _, Immutable) => Some((RefKind::Shared, kind == RetagKind::FnEntry)), + ty::Ref(_, _, Mutability::Not) => + Some((RefKind::Shared, kind == RetagKind::FnEntry)), // Raw pointers need to be enabled. ty::RawPtr(tym) if kind == RetagKind::Raw => - Some((RefKind::Raw { mutable: tym.mutbl == Mutable }, false)), + Some((RefKind::Raw { mutable: tym.mutbl == Mutability::Mut }, false)), // Boxes do not get a protector: protectors reflect that references outlive the call // they were passed in to; that's just not the case for boxes. ty::Adt(..) if ty.is_box() => Some((RefKind::Unique { two_phase: false }, false)), From 2db6a3c04df4cdef73c5868e4fc8e5d3d766d3c7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 24 Dec 2019 11:43:42 +0100 Subject: [PATCH 1418/5092] use new try_from methods --- src/helpers.rs | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index b6391ce2fde0..b631f404523f 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -501,35 +501,22 @@ fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { Ok(&OsStr::new(s)) } -// FIXME: change `ImmTy::from_int` so it returns an `InterpResult` instead and remove this -// function. pub fn immty_from_int_checked<'tcx>( int: impl Into, layout: TyLayout<'tcx>, ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let int = int.into(); - // If `int` does not fit in `size` bits, we error instead of letting - // `ImmTy::from_int` panic. - let size = layout.size; - let truncated = truncate(int as u128, size); - if sign_extend(truncated, size) as i128 != int { - throw_unsup_format!("Signed value {:#x} does not fit in {} bits", int, size.bits()) - } - Ok(ImmTy::from_int(int, layout)) + Ok(ImmTy::try_from_int(int, layout).ok_or_else(|| + err_unsup_format!("Signed value {:#x} does not fit in {} bits", int, layout.size.bits()) + )?) } -// FIXME: change `ImmTy::from_uint` so it returns an `InterpResult` instead and remove this -// function. pub fn immty_from_uint_checked<'tcx>( int: impl Into, layout: TyLayout<'tcx>, ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let int = int.into(); - // If `int` does not fit in `size` bits, we error instead of letting - // `ImmTy::from_int` panic. - let size = layout.size; - if truncate(int, size) != int { - throw_unsup_format!("Unsigned value {:#x} does not fit in {} bits", int, size.bits()) - } - Ok(ImmTy::from_uint(int, layout)) + Ok(ImmTy::try_from_uint(int, layout).ok_or_else(|| + err_unsup_format!("Signed value {:#x} does not fit in {} bits", int, layout.size.bits()) + )?) } From cd12f47af6e9cc107e11962230252e1d66fd9861 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 24 Dec 2019 11:46:02 +0100 Subject: [PATCH 1419/5092] make bytes conversion functions private inside read/write functions --- src/helpers.rs | 54 ++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index b631f404523f..242e2b1d4a13 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -445,6 +445,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx 'tcx: 'a, 'mir: 'a, { + #[cfg(target_os = "unix")] + fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { + Ok(std::os::unix::ffi::OsStringExt::from_bytes(bytes)) + } + #[cfg(not(target_os = "unix"))] + fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { + let s = std::str::from_utf8(bytes) + .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; + Ok(&OsStr::new(s)) + } + let this = self.eval_context_ref(); let bytes = this.memory.read_c_str(scalar)?; bytes_to_os_str(bytes) @@ -460,6 +471,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx scalar: Scalar, size: u64, ) -> InterpResult<'tcx, bool> { + #[cfg(target_os = "unix")] + fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + std::os::unix::ffi::OsStringExt::into_bytes(os_str) + } + #[cfg(not(target_os = "unix"))] + fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the + // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually + // valid. + os_str + .to_str() + .map(|s| s.as_bytes()) + .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) + } + let bytes = os_str_to_bytes(os_str)?; // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null // terminator to memory using the `ptr` pointer would cause an out-of-bounds access. @@ -473,34 +499,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } -#[cfg(target_os = "unix")] -fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - std::os::unix::ffi::OsStringExt::into_bytes(os_str) -} - -#[cfg(target_os = "unix")] -fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { - Ok(std::os::unix::ffi::OsStringExt::from_bytes(bytes)) -} - -// On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the -// intermediate transformation into strings. Which invalidates non-utf8 paths that are actually -// valid. -#[cfg(not(target_os = "unix"))] -fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - os_str - .to_str() - .map(|s| s.as_bytes()) - .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) -} - -#[cfg(not(target_os = "unix"))] -fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { - let s = std::str::from_utf8(bytes) - .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; - Ok(&OsStr::new(s)) -} - pub fn immty_from_int_checked<'tcx>( int: impl Into, layout: TyLayout<'tcx>, From d9ecd77adafc669854e5b74a790b243ac6f0ec5f Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 24 Dec 2019 11:01:01 -0500 Subject: [PATCH 1420/5092] add dummy stat shim --- src/shims/foreign_items.rs | 5 ++++ src/shims/fs.rs | 49 ++++++++++++++++++++++++++++++++++++++ tests/run-pass/fs.rs | 7 ------ 3 files changed, 54 insertions(+), 7 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 1a52d8721470..9092828a1556 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -494,6 +494,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "stat64" => { + let result = this.stat(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + "clock_gettime" => { let result = this.clock_gettime(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 0b78111533a5..d891d132f24f 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -261,6 +261,55 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.try_unwrap_io_result(result) } + fn stat(&mut self, + _path_op: OpTy<'tcx, Tag>, + buf_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + let buf = this.deref_operand(buf_op)?; + + let dev_t_layout = this.libc_ty_layout("dev_t")?; + let mode_t_layout = this.libc_ty_layout("mode_t")?; + let nlink_t_layout = this.libc_ty_layout("nlink_t")?; + let ino_t_layout = this.libc_ty_layout("ino_t")?; + let uid_t_layout = this.libc_ty_layout("uid_t")?; + let gid_t_layout = this.libc_ty_layout("gid_t")?; + let time_t_layout = this.libc_ty_layout("time_t")?; + let long_layout = this.libc_ty_layout("c_long")?; + let off_t_layout = this.libc_ty_layout("off_t")?; + let blkcnt_t_layout = this.libc_ty_layout("blkcnt_t")?; + let blksize_t_layout = this.libc_ty_layout("blksize_t")?; + let uint32_t_layout = this.libc_ty_layout("uint32_t")?; + + let imms = [ + immty_from_uint_checked(0u128, dev_t_layout)?, // st_dev + immty_from_uint_checked(0u128, mode_t_layout)?, // st_mode + immty_from_uint_checked(0u128, nlink_t_layout)?, // st_nlink + immty_from_uint_checked(0u128, ino_t_layout)?, // st_ino + immty_from_uint_checked(0u128, uid_t_layout)?, // st_uid + immty_from_uint_checked(0u128, gid_t_layout)?, // st_gid + immty_from_uint_checked(0u128, dev_t_layout)?, // st_rdev + immty_from_uint_checked(0u128, time_t_layout)?, // st_atime + immty_from_uint_checked(0u128, long_layout)?, // st_atime_nsec + immty_from_uint_checked(0u128, time_t_layout)?, // st_mtime + immty_from_uint_checked(0u128, long_layout)?, // st_mtime_nsec + immty_from_uint_checked(0u128, time_t_layout)?, // st_ctime + immty_from_uint_checked(0u128, long_layout)?, // st_ctime_nsec + immty_from_uint_checked(0u128, time_t_layout)?, // st_birthtime + immty_from_uint_checked(0u128, long_layout)?, // st_birthtime_nsec + immty_from_uint_checked(0u128, off_t_layout)?, // st_size + immty_from_uint_checked(0u128, blkcnt_t_layout)?, // st_blocks + immty_from_uint_checked(0u128, blksize_t_layout)?, // st_blksize + immty_from_uint_checked(0u128, uint32_t_layout)?, // st_flags + immty_from_uint_checked(0u128, uint32_t_layout)?, // st_gen + ]; + + this.write_packed_immediates(&buf, &imms)?; + + Ok(0) + } + fn statx( &mut self, dirfd_op: OpTy<'tcx, Tag>, // Should be an `int` diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index b8f9e3229af6..9f000961d5a0 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -5,7 +5,6 @@ use std::fs::{File, remove_file}; use std::io::{Read, Write, ErrorKind, Result}; use std::path::{PathBuf, Path}; -#[cfg(target_os = "linux")] fn test_metadata(bytes: &[u8], path: &Path) -> Result<()> { // Test that the file metadata is correct. let metadata = path.metadata()?; @@ -16,12 +15,6 @@ fn test_metadata(bytes: &[u8], path: &Path) -> Result<()> { Ok(()) } -// FIXME: Implement stat64 for macos. -#[cfg(not(target_os = "linux"))] -fn test_metadata(_bytes: &[u8], _path: &Path) -> Result<()> { - Ok(()) -} - fn main() { let tmp = std::env::temp_dir(); let filename = PathBuf::from("miri_test_fs.txt"); From 6177e6df7e212340ad194319d698f321b44bb35a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 24 Dec 2019 11:21:00 -0500 Subject: [PATCH 1421/5092] provide correct name for shim --- src/shims/foreign_items.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 9092828a1556..51c43b28b68a 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -494,7 +494,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "stat64" => { + "stat$INODE64" => { let result = this.stat(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } From b2c4ff2aee08854d13b33877a4275307e27091ee Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 24 Dec 2019 11:53:03 -0500 Subject: [PATCH 1422/5092] add remanining fields to stat stuct --- src/shims/fs.rs | 64 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 10 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index d891d132f24f..8b102bf04abf 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -261,14 +261,58 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.try_unwrap_io_result(result) } - fn stat(&mut self, - _path_op: OpTy<'tcx, Tag>, + fn stat( + &mut self, + path_op: OpTy<'tcx, Tag>, buf_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + let path_scalar = this.read_scalar(path_op)?.not_undef()?; + let path = this.read_os_str_from_c_str(path_scalar)?; + let buf = this.deref_operand(buf_op)?; + let metadata = match std::fs::metadata(path) { + Ok(metadata) => metadata, + Err(e) => { + this.set_last_error_from_io_error(e)?; + return Ok(-1); + } + }; + + let file_type = metadata.file_type(); + + let mode_name = if file_type.is_file() { + "S_IFREG" + } else if file_type.is_dir() { + "S_IFDIR" + } else { + "S_IFLNK" + }; + + let mode = this.eval_libc(mode_name)?.to_u32()?; + + let size = metadata.len(); + + let (access_sec, access_nsec) = extract_sec_and_nsec( + metadata.accessed(), + &mut 0, + 0, + )?; + + let (created_sec, created_nsec) = extract_sec_and_nsec( + metadata.created(), + &mut 0, + 0, + )?; + + let (modified_sec, modified_nsec) = extract_sec_and_nsec( + metadata.modified(), + &mut 0, + 0, + )?; + let dev_t_layout = this.libc_ty_layout("dev_t")?; let mode_t_layout = this.libc_ty_layout("mode_t")?; let nlink_t_layout = this.libc_ty_layout("nlink_t")?; @@ -284,21 +328,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let imms = [ immty_from_uint_checked(0u128, dev_t_layout)?, // st_dev - immty_from_uint_checked(0u128, mode_t_layout)?, // st_mode + immty_from_uint_checked(mode, mode_t_layout)?, // st_mode immty_from_uint_checked(0u128, nlink_t_layout)?, // st_nlink immty_from_uint_checked(0u128, ino_t_layout)?, // st_ino immty_from_uint_checked(0u128, uid_t_layout)?, // st_uid immty_from_uint_checked(0u128, gid_t_layout)?, // st_gid immty_from_uint_checked(0u128, dev_t_layout)?, // st_rdev - immty_from_uint_checked(0u128, time_t_layout)?, // st_atime - immty_from_uint_checked(0u128, long_layout)?, // st_atime_nsec - immty_from_uint_checked(0u128, time_t_layout)?, // st_mtime - immty_from_uint_checked(0u128, long_layout)?, // st_mtime_nsec + immty_from_uint_checked(access_sec, time_t_layout)?, // st_atime + immty_from_uint_checked(access_nsec, long_layout)?, // st_atime_nsec + immty_from_uint_checked(modified_sec, time_t_layout)?, // st_mtime + immty_from_uint_checked(modified_nsec, long_layout)?, // st_mtime_nsec immty_from_uint_checked(0u128, time_t_layout)?, // st_ctime immty_from_uint_checked(0u128, long_layout)?, // st_ctime_nsec - immty_from_uint_checked(0u128, time_t_layout)?, // st_birthtime - immty_from_uint_checked(0u128, long_layout)?, // st_birthtime_nsec - immty_from_uint_checked(0u128, off_t_layout)?, // st_size + immty_from_uint_checked(created_sec, time_t_layout)?, // st_birthtime + immty_from_uint_checked(created_nsec, long_layout)?, // st_birthtime_nsec + immty_from_uint_checked(size, off_t_layout)?, // st_size immty_from_uint_checked(0u128, blkcnt_t_layout)?, // st_blocks immty_from_uint_checked(0u128, blksize_t_layout)?, // st_blksize immty_from_uint_checked(0u128, uint32_t_layout)?, // st_flags From 0184e10f2f1cfcdf845c680e9fd43b07c16483bd Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 24 Dec 2019 12:10:36 -0500 Subject: [PATCH 1423/5092] fix size for file mode --- src/shims/fs.rs | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 8b102bf04abf..b3d16dba6e6e 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -291,27 +291,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "S_IFLNK" }; - let mode = this.eval_libc(mode_name)?.to_u32()?; + let mode = this.eval_libc(mode_name)?.to_bits(Size::from_bits(16))? as u16; let size = metadata.len(); - let (access_sec, access_nsec) = extract_sec_and_nsec( - metadata.accessed(), - &mut 0, - 0, - )?; - - let (created_sec, created_nsec) = extract_sec_and_nsec( - metadata.created(), - &mut 0, - 0, - )?; - - let (modified_sec, modified_nsec) = extract_sec_and_nsec( - metadata.modified(), - &mut 0, - 0, - )?; + let (access_sec, access_nsec) = extract_sec_and_nsec(metadata.accessed(), &mut 0, 0)?; + let (created_sec, created_nsec) = extract_sec_and_nsec(metadata.created(), &mut 0, 0)?; + let (modified_sec, modified_nsec) = extract_sec_and_nsec(metadata.modified(), &mut 0, 0)?; let dev_t_layout = this.libc_ty_layout("dev_t")?; let mode_t_layout = this.libc_ty_layout("mode_t")?; From dbc118919aea52645cb278d4db6d38612a448095 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 25 Dec 2019 10:32:34 -0500 Subject: [PATCH 1424/5092] add padding to immediates --- src/shims/fs.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index b3d16dba6e6e..d4a000305f64 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -320,6 +320,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(0u128, uid_t_layout)?, // st_uid immty_from_uint_checked(0u128, gid_t_layout)?, // st_gid immty_from_uint_checked(0u128, dev_t_layout)?, // st_rdev + immty_from_uint_checked(0u128, dev_t_layout)?, // padding immty_from_uint_checked(access_sec, time_t_layout)?, // st_atime immty_from_uint_checked(access_nsec, long_layout)?, // st_atime_nsec immty_from_uint_checked(modified_sec, time_t_layout)?, // st_mtime From 75f7a118e63d6408b5cad81fe25f062405608f14 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 25 Dec 2019 11:27:25 -0500 Subject: [PATCH 1425/5092] remove restrictions due to `stat` unavailability --- src/shims/env.rs | 3 +-- tests/run-pass/fs.rs | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 3994cf78780a..1e655ca821d8 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -20,8 +20,7 @@ impl EnvVars { ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, mut excluded_env_vars: Vec, ) { - - // FIXME: this can be removed when we have the `stat64` shim for macos. + // FIXME: this can be removed when we fix the behavior of the `close` shim for macos. if ecx.tcx.sess.target.target.target_os.to_lowercase() != "linux" { // Exclude `TERM` var to avoid terminfo trying to open the termcap file. excluded_env_vars.push("TERM".to_owned()); diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 9f000961d5a0..85e39bc45112 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -51,7 +51,5 @@ fn main() { // Removing a non-existing file should fail with a "not found" error. assert_eq!(ErrorKind::NotFound, remove_file(&path).unwrap_err().kind()); // Reading the metadata of a non-existing file should fail with a "not found" error. - if cfg!(target_os = "linux") { // FIXME: Implement stat64 for macos. - assert_eq!(ErrorKind::NotFound, test_metadata(bytes, &path).unwrap_err().kind()); - } + assert_eq!(ErrorKind::NotFound, test_metadata(bytes, &path).unwrap_err().kind()); } From 6d88a4704a030b2c963abf38be481c1805b407d0 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 25 Dec 2019 11:30:01 -0500 Subject: [PATCH 1426/5092] restrict `stat` shim to macos only --- src/shims/fs.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index d4a000305f64..78ec2169fd68 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -268,6 +268,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + if this.tcx.sess.target.target.target_os.to_lowercase() != "macos" { + throw_unsup_format!("The `stat` shim is only only available in the `macos` platform.") + } + let path_scalar = this.read_scalar(path_op)?.not_undef()?; let path = this.read_os_str_from_c_str(path_scalar)?; From 515c11935969f6bffc42ab2e4cece862f109bb31 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 25 Dec 2019 11:39:57 -0500 Subject: [PATCH 1427/5092] Add padding on 64-bits only --- src/shims/fs.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 78ec2169fd68..adc60a52e6d1 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -295,6 +295,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "S_IFLNK" }; + // FIXME: use Scalar::to_u16 let mode = this.eval_libc(mode_name)?.to_bits(Size::from_bits(16))? as u16; let size = metadata.len(); @@ -316,6 +317,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let blksize_t_layout = this.libc_ty_layout("blksize_t")?; let uint32_t_layout = this.libc_ty_layout("uint32_t")?; + // We need to add 32 bits of padding after `st_rdev` if we are in a 64-bit platform. To do + // this, we store `st_rdev` as a `c_long` instead of a `dev_t`. + let st_rdev_layout = if this.tcx.sess.target.ptr_width == 64 { + long_layout + } else { + dev_t_layout + }; + let imms = [ immty_from_uint_checked(0u128, dev_t_layout)?, // st_dev immty_from_uint_checked(mode, mode_t_layout)?, // st_mode @@ -323,8 +332,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(0u128, ino_t_layout)?, // st_ino immty_from_uint_checked(0u128, uid_t_layout)?, // st_uid immty_from_uint_checked(0u128, gid_t_layout)?, // st_gid - immty_from_uint_checked(0u128, dev_t_layout)?, // st_rdev - immty_from_uint_checked(0u128, dev_t_layout)?, // padding + immty_from_uint_checked(0u128, st_rdev_layout)?, // st_rdev immty_from_uint_checked(access_sec, time_t_layout)?, // st_atime immty_from_uint_checked(access_nsec, long_layout)?, // st_atime_nsec immty_from_uint_checked(modified_sec, time_t_layout)?, // st_mtime From d17625900234f9643180075ea44756c98a92819a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 25 Dec 2019 16:09:54 -0500 Subject: [PATCH 1428/5092] deduplicate shared code between stat and statx --- src/shims/fs.rs | 173 +++++++++++++++++++++++++----------------------- 1 file changed, 92 insertions(+), 81 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index adc60a52e6d1..a5bac27cc449 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -269,40 +269,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); if this.tcx.sess.target.target.target_os.to_lowercase() != "macos" { - throw_unsup_format!("The `stat` shim is only only available in the `macos` platform.") + throw_unsup_format!("The `stat` shim is only only available for `macos` targets.") } let path_scalar = this.read_scalar(path_op)?.not_undef()?; - let path = this.read_os_str_from_c_str(path_scalar)?; + let path: PathBuf = this.read_os_str_from_c_str(path_scalar)?.into(); let buf = this.deref_operand(buf_op)?; - let metadata = match std::fs::metadata(path) { - Ok(metadata) => metadata, - Err(e) => { - this.set_last_error_from_io_error(e)?; - return Ok(-1); - } - }; - - let file_type = metadata.file_type(); - - let mode_name = if file_type.is_file() { - "S_IFREG" - } else if file_type.is_dir() { - "S_IFDIR" - } else { - "S_IFLNK" + let stats = match FileStatus::new(this, path, false)? { + Some(stats) => stats, + None => return Ok(-1), }; // FIXME: use Scalar::to_u16 - let mode = this.eval_libc(mode_name)?.to_bits(Size::from_bits(16))? as u16; + let mode: u16 = stats.mode.to_bits(Size::from_bits(16))? as u16; - let size = metadata.len(); - - let (access_sec, access_nsec) = extract_sec_and_nsec(metadata.accessed(), &mut 0, 0)?; - let (created_sec, created_nsec) = extract_sec_and_nsec(metadata.created(), &mut 0, 0)?; - let (modified_sec, modified_nsec) = extract_sec_and_nsec(metadata.modified(), &mut 0, 0)?; + let (access_sec, access_nsec) = stats.accessed.unwrap_or((0, 0)); + let (created_sec, created_nsec) = stats.created.unwrap_or((0, 0)); + let (modified_sec, modified_nsec) = stats.modified.unwrap_or((0, 0)); let dev_t_layout = this.libc_ty_layout("dev_t")?; let mode_t_layout = this.libc_ty_layout("mode_t")?; @@ -341,7 +326,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(0u128, long_layout)?, // st_ctime_nsec immty_from_uint_checked(created_sec, time_t_layout)?, // st_birthtime immty_from_uint_checked(created_nsec, long_layout)?, // st_birthtime_nsec - immty_from_uint_checked(size, off_t_layout)?, // st_size + immty_from_uint_checked(stats.size, off_t_layout)?, // st_size immty_from_uint_checked(0u128, blkcnt_t_layout)?, // st_blocks immty_from_uint_checked(0u128, blksize_t_layout)?, // st_blksize immty_from_uint_checked(0u128, uint32_t_layout)?, // st_flags @@ -365,6 +350,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("statx")?; + if this.tcx.sess.target.target.target_os.to_lowercase() != "linux" { + throw_unsup_format!("The `statx` shim is only only available for `linux` targets.") + } + let statxbuf_scalar = this.read_scalar(statxbuf_op)?.not_undef()?; let pathname_scalar = this.read_scalar(pathname_op)?.not_undef()?; @@ -422,60 +411,43 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If the `AT_SYMLINK_NOFOLLOW` flag is set, we query the file's metadata without following // symbolic links. - let metadata = if flags & this.eval_libc("AT_SYMLINK_NOFOLLOW")?.to_i32()? != 0 { - // FIXME: metadata for symlinks need testing. - std::fs::symlink_metadata(path) - } else { - std::fs::metadata(path) - }; + let is_symlink = flags & this.eval_libc("AT_SYMLINK_NOFOLLOW")?.to_i32()? != 0; - let metadata = match metadata { - Ok(metadata) => metadata, - Err(e) => { - this.set_last_error_from_io_error(e)?; - return Ok(-1); - } - }; - - let file_type = metadata.file_type(); - - let mode_name = if file_type.is_file() { - "S_IFREG" - } else if file_type.is_dir() { - "S_IFDIR" - } else { - "S_IFLNK" + let stats = match FileStatus::new(this, path, is_symlink)? { + Some(stats) => stats, + None => return Ok(-1), }; // The `mode` field specifies the type of the file and the permissions over the file for // the owner, its group and other users. Given that we can only provide the file type // without using platform specific methods, we only set the bits corresponding to the file // type. This should be an `__u16` but `libc` provides its values as `u32`. - let mode: u16 = this - .eval_libc(mode_name)? + let mode: u16 = stats + .mode .to_u32()? .try_into() - .unwrap_or_else(|_| bug!("libc contains bad value for `{}` constant", mode_name)); + .unwrap_or_else(|_| bug!("libc contains bad value for constant")); - let size = metadata.len(); + let (access_sec, access_nsec) = if let Some(tup) = stats.accessed { + tup + } else { + mask |= this.eval_libc("STATX_ATIME")?.to_u32()?; + (0, 0) + }; - let (access_sec, access_nsec) = extract_sec_and_nsec( - metadata.accessed(), - &mut mask, - this.eval_libc("STATX_ATIME")?.to_u32()?, - )?; + let (created_sec, created_nsec) = if let Some(tup) = stats.created { + tup + } else { + mask |= this.eval_libc("STATX_BTIME")?.to_u32()?; + (0, 0) + }; - let (created_sec, created_nsec) = extract_sec_and_nsec( - metadata.created(), - &mut mask, - this.eval_libc("STATX_BTIME")?.to_u32()?, - )?; - - let (modified_sec, modified_nsec) = extract_sec_and_nsec( - metadata.modified(), - &mut mask, - this.eval_libc("STATX_MTIME")?.to_u32()?, - )?; + let (modified_sec, modified_nsec) = if let Some(tup) = stats.modified { + tup + } else { + mask |= this.eval_libc("STATX_MTIME")?.to_u32()?; + (0, 0) + }; let __u32_layout = this.libc_ty_layout("__u32")?; let __u64_layout = this.libc_ty_layout("__u64")?; @@ -483,7 +455,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Now we transform all this fields into `ImmTy`s and write them to `statxbuf`. We write a // zero for the unavailable fields. - // FIXME: Provide more fields using platform specific methods. let imms = [ immty_from_uint_checked(mask, __u32_layout)?, // stx_mask immty_from_uint_checked(0u128, __u32_layout)?, // stx_blksize @@ -494,7 +465,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(mode, __u16_layout)?, // stx_mode immty_from_uint_checked(0u128, __u16_layout)?, // statx padding immty_from_uint_checked(0u128, __u64_layout)?, // stx_ino - immty_from_uint_checked(size, __u64_layout)?, // stx_size + immty_from_uint_checked(stats.size, __u64_layout)?, // stx_size immty_from_uint_checked(0u128, __u64_layout)?, // stx_blocks immty_from_uint_checked(0u128, __u64_layout)?, // stx_attributes immty_from_uint_checked(access_sec, __u64_layout)?, // stx_atime.tv_sec @@ -532,19 +503,59 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } -// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch, and -// then sets the `mask` bits determined by `flag` when `time` is Ok. If `time` is an error, it -// returns `(0, 0)` without setting any bits. -fn extract_sec_and_nsec<'tcx>( - time: std::io::Result, - mask: &mut u32, - flag: u32, -) -> InterpResult<'tcx, (u64, u32)> { - if let Ok(time) = time { +// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch when +// `time` is Ok. If `time` is an error, it returns `None`. +fn extract_sec_and_nsec<'tcx>(time: std::io::Result) -> InterpResult<'tcx, Option<(u64, u32)>> { + time.ok().map(|time| { let duration = system_time_to_duration(&time)?; - *mask |= flag; Ok((duration.as_secs(), duration.subsec_nanos())) - } else { - Ok((0, 0)) + }).transpose() +} + +struct FileStatus { + mode: Scalar, + size: u64, + created: Option<(u64, u32)>, + accessed: Option<(u64, u32)>, + modified: Option<(u64, u32)>, +} + +impl FileStatus { + fn new<'tcx, 'mir>(ecx: &mut MiriEvalContext<'mir, 'tcx>, path: PathBuf, is_symlink: bool) -> InterpResult<'tcx, Option> { + let metadata = if is_symlink { + // FIXME: metadata for symlinks need testing. + std::fs::symlink_metadata(path) + } else { + std::fs::metadata(path) + }; + + let metadata = match metadata { + Ok(metadata) => metadata, + Err(e) => { + ecx.set_last_error_from_io_error(e)?; + return Ok(None); + } + }; + + let file_type = metadata.file_type(); + + let mode_name = if file_type.is_file() { + "S_IFREG" + } else if file_type.is_dir() { + "S_IFDIR" + } else { + "S_IFLNK" + }; + + let mode = ecx.eval_libc(mode_name)?; + + let size = metadata.len(); + + let created = extract_sec_and_nsec(metadata.created())?; + let accessed = extract_sec_and_nsec(metadata.accessed())?; + let modified = extract_sec_and_nsec(metadata.modified())?; + + // FIXME: Provide more fields using platform specific methods. + Ok(Some(FileStatus { mode, size, created, accessed, modified })) } } From 1bc362908440792123d8b8022f6e09a7401389f2 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 25 Dec 2019 18:22:33 -0500 Subject: [PATCH 1429/5092] do padding correctly --- src/shims/fs.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index a5bac27cc449..8cd1afd02c9f 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -302,12 +302,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let blksize_t_layout = this.libc_ty_layout("blksize_t")?; let uint32_t_layout = this.libc_ty_layout("uint32_t")?; - // We need to add 32 bits of padding after `st_rdev` if we are in a 64-bit platform. To do - // this, we store `st_rdev` as a `c_long` instead of a `dev_t`. - let st_rdev_layout = if this.tcx.sess.target.ptr_width == 64 { - long_layout + // We need to add 32 bits of padding after `st_rdev` if we are in a 64-bit platform. + let pad_layout = if this.tcx.sess.target.ptr_width == 64 { + uint32_t_layout } else { - dev_t_layout + this.layout_of(this.tcx.mk_unit())? }; let imms = [ @@ -317,7 +316,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(0u128, ino_t_layout)?, // st_ino immty_from_uint_checked(0u128, uid_t_layout)?, // st_uid immty_from_uint_checked(0u128, gid_t_layout)?, // st_gid - immty_from_uint_checked(0u128, st_rdev_layout)?, // st_rdev + immty_from_uint_checked(0u128, dev_t_layout)?, // st_rdev + immty_from_uint_checked(0u128, pad_layout)?, // padding for 64-bit targets immty_from_uint_checked(access_sec, time_t_layout)?, // st_atime immty_from_uint_checked(access_nsec, long_layout)?, // st_atime_nsec immty_from_uint_checked(modified_sec, time_t_layout)?, // st_mtime From bbbb50a09aadfc53df8ed4810d9ff67b194b2492 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 25 Dec 2019 22:22:25 -0500 Subject: [PATCH 1430/5092] set mask for statx correctly --- src/shims/fs.rs | 52 ++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 8cd1afd02c9f..3084d977de82 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -277,17 +277,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.deref_operand(buf_op)?; - let stats = match FileStatus::new(this, path, false)? { - Some(stats) => stats, + let status = match FileStatus::new(this, path, false)? { + Some(status) => status, None => return Ok(-1), }; // FIXME: use Scalar::to_u16 - let mode: u16 = stats.mode.to_bits(Size::from_bits(16))? as u16; + let mode: u16 = status.mode.to_bits(Size::from_bits(16))? as u16; - let (access_sec, access_nsec) = stats.accessed.unwrap_or((0, 0)); - let (created_sec, created_nsec) = stats.created.unwrap_or((0, 0)); - let (modified_sec, modified_nsec) = stats.modified.unwrap_or((0, 0)); + let (access_sec, access_nsec) = status.accessed.unwrap_or((0, 0)); + let (created_sec, created_nsec) = status.created.unwrap_or((0, 0)); + let (modified_sec, modified_nsec) = status.modified.unwrap_or((0, 0)); let dev_t_layout = this.libc_ty_layout("dev_t")?; let mode_t_layout = this.libc_ty_layout("mode_t")?; @@ -326,7 +326,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(0u128, long_layout)?, // st_ctime_nsec immty_from_uint_checked(created_sec, time_t_layout)?, // st_birthtime immty_from_uint_checked(created_nsec, long_layout)?, // st_birthtime_nsec - immty_from_uint_checked(stats.size, off_t_layout)?, // st_size + immty_from_uint_checked(status.size, off_t_layout)?, // st_size immty_from_uint_checked(0u128, blkcnt_t_layout)?, // st_blocks immty_from_uint_checked(0u128, blksize_t_layout)?, // st_blksize immty_from_uint_checked(0u128, uint32_t_layout)?, // st_flags @@ -413,8 +413,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // symbolic links. let is_symlink = flags & this.eval_libc("AT_SYMLINK_NOFOLLOW")?.to_i32()? != 0; - let stats = match FileStatus::new(this, path, is_symlink)? { - Some(stats) => stats, + let status = match FileStatus::new(this, path, is_symlink)? { + Some(status) => status, None => return Ok(-1), }; @@ -422,32 +422,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // the owner, its group and other users. Given that we can only provide the file type // without using platform specific methods, we only set the bits corresponding to the file // type. This should be an `__u16` but `libc` provides its values as `u32`. - let mode: u16 = stats + let mode: u16 = status .mode .to_u32()? .try_into() .unwrap_or_else(|_| bug!("libc contains bad value for constant")); - let (access_sec, access_nsec) = if let Some(tup) = stats.accessed { - tup - } else { + let (access_sec, access_nsec) = status.accessed.map(|tup| { mask |= this.eval_libc("STATX_ATIME")?.to_u32()?; - (0, 0) - }; + InterpResult::Ok(tup) + }).unwrap_or(Ok((0, 0)))?; - let (created_sec, created_nsec) = if let Some(tup) = stats.created { - tup - } else { + let (created_sec, created_nsec) = status.created.map(|tup| { mask |= this.eval_libc("STATX_BTIME")?.to_u32()?; - (0, 0) - }; + InterpResult::Ok(tup) + }).unwrap_or(Ok((0, 0)))?; - let (modified_sec, modified_nsec) = if let Some(tup) = stats.modified { - tup - } else { + let (modified_sec, modified_nsec) = status.modified.map(|tup| { mask |= this.eval_libc("STATX_MTIME")?.to_u32()?; - (0, 0) - }; + InterpResult::Ok(tup) + }).unwrap_or(Ok((0, 0)))?; let __u32_layout = this.libc_ty_layout("__u32")?; let __u64_layout = this.libc_ty_layout("__u64")?; @@ -465,7 +459,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(mode, __u16_layout)?, // stx_mode immty_from_uint_checked(0u128, __u16_layout)?, // statx padding immty_from_uint_checked(0u128, __u64_layout)?, // stx_ino - immty_from_uint_checked(stats.size, __u64_layout)?, // stx_size + immty_from_uint_checked(status.size, __u64_layout)?, // stx_size immty_from_uint_checked(0u128, __u64_layout)?, // stx_blocks immty_from_uint_checked(0u128, __u64_layout)?, // stx_attributes immty_from_uint_checked(access_sec, __u64_layout)?, // stx_atime.tv_sec @@ -521,7 +515,11 @@ struct FileStatus { } impl FileStatus { - fn new<'tcx, 'mir>(ecx: &mut MiriEvalContext<'mir, 'tcx>, path: PathBuf, is_symlink: bool) -> InterpResult<'tcx, Option> { + fn new<'tcx, 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + path: PathBuf, + is_symlink: bool + ) -> InterpResult<'tcx, Option> { let metadata = if is_symlink { // FIXME: metadata for symlinks need testing. std::fs::symlink_metadata(path) From 2151e958ceba1fcbe906eebf0b42855a0a20178f Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 26 Dec 2019 12:12:19 -0500 Subject: [PATCH 1431/5092] minor fixes and updated docs --- src/shims/fs.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 3084d977de82..f4a792a0410c 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -411,9 +411,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If the `AT_SYMLINK_NOFOLLOW` flag is set, we query the file's metadata without following // symbolic links. - let is_symlink = flags & this.eval_libc("AT_SYMLINK_NOFOLLOW")?.to_i32()? != 0; + let follow_symlink = flags & this.eval_libc("AT_SYMLINK_NOFOLLOW")?.to_i32()? == 0; - let status = match FileStatus::new(this, path, is_symlink)? { + let status = match FileStatus::new(this, path, follow_symlink)? { Some(status) => status, None => return Ok(-1), }; @@ -428,6 +428,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .try_into() .unwrap_or_else(|_| bug!("libc contains bad value for constant")); + // We need to set the corresponding bits of `mask` if the access, creation and modification + // times were available. Otherwise we let them be zero. let (access_sec, access_nsec) = status.accessed.map(|tup| { mask |= this.eval_libc("STATX_ATIME")?.to_u32()?; InterpResult::Ok(tup) @@ -497,9 +499,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } -// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch when -// `time` is Ok. If `time` is an error, it returns `None`. -fn extract_sec_and_nsec<'tcx>(time: std::io::Result) -> InterpResult<'tcx, Option<(u64, u32)>> { +/// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch when +/// `time` is Ok. Returns `None` if `time` is an error. Fails if `time` happens before the unix +/// epoch. +fn extract_sec_and_nsec<'tcx>( + time: std::io::Result +) -> InterpResult<'tcx, Option<(u64, u32)>> { time.ok().map(|time| { let duration = system_time_to_duration(&time)?; Ok((duration.as_secs(), duration.subsec_nanos())) @@ -518,9 +523,9 @@ impl FileStatus { fn new<'tcx, 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, path: PathBuf, - is_symlink: bool + follow_symlink: bool ) -> InterpResult<'tcx, Option> { - let metadata = if is_symlink { + let metadata = if follow_symlink { // FIXME: metadata for symlinks need testing. std::fs::symlink_metadata(path) } else { From c8190e8de79b22843c4d0976def95aee120f0329 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 26 Dec 2019 13:30:04 -0500 Subject: [PATCH 1432/5092] rename metadata struct --- src/shims/fs.rs | 49 ++++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index f4a792a0410c..63aa750bdd54 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -269,7 +269,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); if this.tcx.sess.target.target.target_os.to_lowercase() != "macos" { - throw_unsup_format!("The `stat` shim is only only available for `macos` targets.") + throw_unsup_format!("The `stat` shim is only available for `macos` targets.") } let path_scalar = this.read_scalar(path_op)?.not_undef()?; @@ -277,17 +277,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.deref_operand(buf_op)?; - let status = match FileStatus::new(this, path, false)? { - Some(status) => status, + // `stat` always follows symlinks. `lstat` is used to get symlink metadata. + let metadata = match FileMetadata::new(this, path, true)? { + Some(metadata) => metadata, None => return Ok(-1), }; // FIXME: use Scalar::to_u16 - let mode: u16 = status.mode.to_bits(Size::from_bits(16))? as u16; + let mode: u16 = metadata.mode.to_bits(Size::from_bits(16))? as u16; - let (access_sec, access_nsec) = status.accessed.unwrap_or((0, 0)); - let (created_sec, created_nsec) = status.created.unwrap_or((0, 0)); - let (modified_sec, modified_nsec) = status.modified.unwrap_or((0, 0)); + let (access_sec, access_nsec) = metadata.accessed.unwrap_or((0, 0)); + let (created_sec, created_nsec) = metadata.created.unwrap_or((0, 0)); + let (modified_sec, modified_nsec) = metadata.modified.unwrap_or((0, 0)); let dev_t_layout = this.libc_ty_layout("dev_t")?; let mode_t_layout = this.libc_ty_layout("mode_t")?; @@ -302,7 +303,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let blksize_t_layout = this.libc_ty_layout("blksize_t")?; let uint32_t_layout = this.libc_ty_layout("uint32_t")?; - // We need to add 32 bits of padding after `st_rdev` if we are in a 64-bit platform. + // We need to add 32 bits of padding after `st_rdev` if we are on a 64-bit platform. let pad_layout = if this.tcx.sess.target.ptr_width == 64 { uint32_t_layout } else { @@ -326,7 +327,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(0u128, long_layout)?, // st_ctime_nsec immty_from_uint_checked(created_sec, time_t_layout)?, // st_birthtime immty_from_uint_checked(created_nsec, long_layout)?, // st_birthtime_nsec - immty_from_uint_checked(status.size, off_t_layout)?, // st_size + immty_from_uint_checked(metadata.size, off_t_layout)?, // st_size immty_from_uint_checked(0u128, blkcnt_t_layout)?, // st_blocks immty_from_uint_checked(0u128, blksize_t_layout)?, // st_blksize immty_from_uint_checked(0u128, uint32_t_layout)?, // st_flags @@ -351,7 +352,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("statx")?; if this.tcx.sess.target.target.target_os.to_lowercase() != "linux" { - throw_unsup_format!("The `statx` shim is only only available for `linux` targets.") + throw_unsup_format!("The `statx` shim is only available for `linux` targets.") } let statxbuf_scalar = this.read_scalar(statxbuf_op)?.not_undef()?; @@ -413,8 +414,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // symbolic links. let follow_symlink = flags & this.eval_libc("AT_SYMLINK_NOFOLLOW")?.to_i32()? == 0; - let status = match FileStatus::new(this, path, follow_symlink)? { - Some(status) => status, + let metadata = match FileMetadata::new(this, path, follow_symlink)? { + Some(metadata) => metadata, None => return Ok(-1), }; @@ -422,7 +423,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // the owner, its group and other users. Given that we can only provide the file type // without using platform specific methods, we only set the bits corresponding to the file // type. This should be an `__u16` but `libc` provides its values as `u32`. - let mode: u16 = status + let mode: u16 = metadata .mode .to_u32()? .try_into() @@ -430,17 +431,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We need to set the corresponding bits of `mask` if the access, creation and modification // times were available. Otherwise we let them be zero. - let (access_sec, access_nsec) = status.accessed.map(|tup| { + let (access_sec, access_nsec) = metadata.accessed.map(|tup| { mask |= this.eval_libc("STATX_ATIME")?.to_u32()?; InterpResult::Ok(tup) }).unwrap_or(Ok((0, 0)))?; - let (created_sec, created_nsec) = status.created.map(|tup| { + let (created_sec, created_nsec) = metadata.created.map(|tup| { mask |= this.eval_libc("STATX_BTIME")?.to_u32()?; InterpResult::Ok(tup) }).unwrap_or(Ok((0, 0)))?; - let (modified_sec, modified_nsec) = status.modified.map(|tup| { + let (modified_sec, modified_nsec) = metadata.modified.map(|tup| { mask |= this.eval_libc("STATX_MTIME")?.to_u32()?; InterpResult::Ok(tup) }).unwrap_or(Ok((0, 0)))?; @@ -461,7 +462,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(mode, __u16_layout)?, // stx_mode immty_from_uint_checked(0u128, __u16_layout)?, // statx padding immty_from_uint_checked(0u128, __u64_layout)?, // stx_ino - immty_from_uint_checked(status.size, __u64_layout)?, // stx_size + immty_from_uint_checked(metadata.size, __u64_layout)?, // stx_size immty_from_uint_checked(0u128, __u64_layout)?, // stx_blocks immty_from_uint_checked(0u128, __u64_layout)?, // stx_attributes immty_from_uint_checked(access_sec, __u64_layout)?, // stx_atime.tv_sec @@ -511,7 +512,9 @@ fn extract_sec_and_nsec<'tcx>( }).transpose() } -struct FileStatus { +/// Stores a file's metadata in order to avoid code duplication in the different metadata related +/// shims. +struct FileMetadata { mode: Scalar, size: u64, created: Option<(u64, u32)>, @@ -519,17 +522,17 @@ struct FileStatus { modified: Option<(u64, u32)>, } -impl FileStatus { +impl FileMetadata { fn new<'tcx, 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, path: PathBuf, follow_symlink: bool - ) -> InterpResult<'tcx, Option> { + ) -> InterpResult<'tcx, Option> { let metadata = if follow_symlink { + std::fs::metadata(path) + } else { // FIXME: metadata for symlinks need testing. std::fs::symlink_metadata(path) - } else { - std::fs::metadata(path) }; let metadata = match metadata { @@ -559,6 +562,6 @@ impl FileStatus { let modified = extract_sec_and_nsec(metadata.modified())?; // FIXME: Provide more fields using platform specific methods. - Ok(Some(FileStatus { mode, size, created, accessed, modified })) + Ok(Some(FileMetadata { mode, size, created, accessed, modified })) } } From 4aef81eb85a47ff123db8204c59c610fa28f8693 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 27 Dec 2019 14:26:05 +0100 Subject: [PATCH 1433/5092] Remove `to_ptr` uses --- rust-version | 2 +- src/shims/foreign_items.rs | 2 +- src/shims/intrinsics.rs | 2 +- src/stacked_borrows.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index 999e8b0f8f73..b8bd5f9e5744 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9ae6cedb8d1e37469be1434642a3e403fce50a03 +8f5f8f916f00f7989a4ebf7b7dbfe1afd605f828 diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 51c43b28b68a..5bdd12b4eb1d 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -271,7 +271,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; } "__rust_realloc" => { - let ptr = this.read_scalar(args[0])?.to_ptr()?; let old_size = this.read_scalar(args[1])?.to_machine_usize(this)?; let align = this.read_scalar(args[2])?.to_machine_usize(this)?; let new_size = this.read_scalar(args[3])?.to_machine_usize(this)?; @@ -281,6 +280,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if !align.is_power_of_two() { throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); } + let ptr = this.force_ptr(this.read_scalar(args[0])?.not_undef()?)?; let align = Align::from_bytes(align).unwrap(); let new_ptr = this.memory.reallocate( ptr, diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index bde2dd4655bf..37aee1f5652c 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -575,7 +575,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Do it in memory let mplace = this.force_allocation(dest)?; mplace.meta.unwrap_none(); - let ptr = mplace.ptr.to_ptr()?; + let ptr = mplace.ptr.assert_ptr(); // We know the return place is in-bounds this.memory.get_raw_mut(ptr.alloc_id)?.mark_definedness( ptr, diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index d986a2db5383..18edb603c6cf 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -507,7 +507,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let protector = if protect { Some(this.frame().extra.call_id) } else { None }; - let ptr = place.ptr.to_ptr().expect("we should have a proper pointer"); + let ptr = place.ptr.assert_ptr(); trace!( "reborrow: {} reference {:?} derived from {:?} (pointee {}): {:?}, size {}", kind, From dc4b8ac2e65d80bbe68893fd8ab409c7e86187ec Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 27 Dec 2019 08:34:35 -0500 Subject: [PATCH 1434/5092] close file silently if the file is read only --- src/shims/fs.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 63aa750bdd54..c6cae22331d1 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -15,6 +15,7 @@ use shims::time::system_time_to_duration; #[derive(Debug)] pub struct FileHandle { file: File, + read_only: bool, } pub struct FileHandler { @@ -56,10 +57,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if (o_rdonly | o_wronly | o_rdwr) & !0b11 != 0 { throw_unsup_format!("Access mode flags on this platform are unsupported"); } + let mut read_only = false; + // Now we check the access mode let access_mode = flag & 0b11; if access_mode == o_rdonly { + read_only = true; options.read(true); } else if access_mode == o_wronly { options.write(true); @@ -105,7 +109,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = options.open(&path).map(|file| { let mut fh = &mut this.machine.file_handler; fh.low += 1; - fh.handles.insert(fh.low, FileHandle { file }).unwrap_none(); + fh.handles.insert(fh.low, FileHandle { file, read_only }).unwrap_none(); fh.low }); @@ -148,6 +152,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(handle) = this.machine.file_handler.handles.remove(&fd) { + if handle.read_only { + return Ok(0); + } // `File::sync_all` does the checks that are done when closing a file. We do this to // to handle possible errors correctly. let result = this.try_unwrap_io_result(handle.file.sync_all().map(|_| 0i32)); From f00fd3990b5016bbfbbecf65d8f6bb40ca2c861a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 27 Dec 2019 08:37:52 -0500 Subject: [PATCH 1435/5092] avoid excluding TERM env var --- src/shims/env.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 1e655ca821d8..cb47e2d79fef 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -18,14 +18,8 @@ pub struct EnvVars { impl EnvVars { pub(crate) fn init<'mir, 'tcx>( ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, - mut excluded_env_vars: Vec, + excluded_env_vars: Vec, ) { - // FIXME: this can be removed when we fix the behavior of the `close` shim for macos. - if ecx.tcx.sess.target.target.target_os.to_lowercase() != "linux" { - // Exclude `TERM` var to avoid terminfo trying to open the termcap file. - excluded_env_vars.push("TERM".to_owned()); - } - if ecx.machine.communicate { for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { From a4bd68a45f50a9e77efde073e047beff8593e3ad Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Fri, 27 Dec 2019 20:32:20 -0500 Subject: [PATCH 1436/5092] Add helper 'alloc_os_str_as_c_str' and use it in env_var emulation --- src/helpers.rs | 14 +++++++++++++ src/shims/env.rs | 43 +++++++++++++++++++------------------- src/shims/foreign_items.rs | 12 +++++++++++ 3 files changed, 47 insertions(+), 22 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 242e2b1d4a13..18b433a0e4a5 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -497,6 +497,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .write_bytes(scalar, bytes.iter().copied().chain(iter::once(0u8)))?; Ok(true) } + + fn alloc_os_str_as_c_str( + &mut self, + os_str: &OsStr, + memkind: MemoryKind + ) -> Pointer { + let size = os_str.len() as u64 + 1; // Make space for `0` terminator. + let this = self.eval_context_mut(); + + let arg_type = this.tcx.mk_array(this.tcx.types.u8, size); + let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind); + self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap(); + arg_place.ptr.assert_ptr() + } } pub fn immty_from_int_checked<'tcx>( diff --git a/src/shims/env.rs b/src/shims/env.rs index 1e655ca821d8..1151561553f9 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,18 +1,18 @@ use std::collections::HashMap; -use std::ffi::OsString; +use std::ffi::{OsString, OsStr}; use std::env; use crate::stacked_borrows::Tag; use crate::*; use rustc::ty::layout::Size; -use rustc_mir::interpret::{Memory, Pointer}; +use rustc_mir::interpret::Pointer; #[derive(Default)] pub struct EnvVars { /// Stores pointers to the environment variables. These variables must be stored as /// null-terminated C strings with the `"{name}={value}"` format. - map: HashMap, Pointer>, + map: HashMap>, } impl EnvVars { @@ -30,24 +30,23 @@ impl EnvVars { for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { let var_ptr = - alloc_env_var(name.as_bytes(), value.as_bytes(), &mut ecx.memory); - ecx.machine.env_vars.map.insert(name.into_bytes(), var_ptr); + alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx); + ecx.machine.env_vars.map.insert(OsString::from(name), var_ptr); } } } } } -fn alloc_env_var<'mir, 'tcx>( - name: &[u8], - value: &[u8], - memory: &mut Memory<'mir, 'tcx, Evaluator<'tcx>>, +fn alloc_env_var_as_c_str<'mir, 'tcx>( + name: &OsStr, + value: &OsStr, + ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, ) -> Pointer { - let mut bytes = name.to_vec(); - bytes.push(b'='); - bytes.extend_from_slice(value); - bytes.push(0); - memory.allocate_static_bytes(bytes.as_slice(), MiriMemoryKind::Env.into()) + let mut name_osstring = name.to_os_string(); + name_osstring.push("="); + name_osstring.push(value); + ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Env.into()) } impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -56,7 +55,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let name_ptr = this.read_scalar(name_op)?.not_undef()?; - let name = this.memory.read_c_str(name_ptr)?; + let name = this.read_os_str_from_c_str(name_ptr)?; Ok(match this.machine.env_vars.map.get(name) { // The offset is used to strip the "{name}=" part of the string. Some(var_ptr) => { @@ -71,20 +70,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name_op: OpTy<'tcx, Tag>, value_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { - let this = self.eval_context_mut(); + let mut this = self.eval_context_mut(); let name_ptr = this.read_scalar(name_op)?.not_undef()?; let value_ptr = this.read_scalar(value_op)?.not_undef()?; - let value = this.memory.read_c_str(value_ptr)?; + let value = this.read_os_str_from_c_str(value_ptr)?; let mut new = None; if !this.is_null(name_ptr)? { - let name = this.memory.read_c_str(name_ptr)?; - if !name.is_empty() && !name.contains(&b'=') { + let name = this.read_os_str_from_c_str(name_ptr)?; + if !name.is_empty() && !name.to_string_lossy().contains('=') { new = Some((name.to_owned(), value.to_owned())); } } if let Some((name, value)) = new { - let var_ptr = alloc_env_var(&name, &value, &mut this.memory); + let var_ptr = alloc_env_var_as_c_str(&name, &value, &mut this); if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), var_ptr) { this.memory .deallocate(var, None, MiriMemoryKind::Env.into())?; @@ -101,8 +100,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_ptr = this.read_scalar(name_op)?.not_undef()?; let mut success = None; if !this.is_null(name_ptr)? { - let name = this.memory.read_c_str(name_ptr)?.to_owned(); - if !name.is_empty() && !name.contains(&b'=') { + let name = this.read_os_str_from_c_str(name_ptr)?.to_owned(); + if !name.is_empty() && !name.to_string_lossy().contains('=') { success = Some(this.machine.env_vars.map.remove(&name)); } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 5bdd12b4eb1d..07e3b7d75826 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -956,10 +956,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "GetEnvironmentVariableW" => { + // args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars) + // args[1] : LPWSTR lpBuffer (32-bit pointer to a string of 16-bit Unicode chars) + // lpBuffer : ptr to buffer that receives contents of the env_var as a null-terminated string. + // Return `# of chars` stored in the buffer pointed to by lpBuffer, excluding null-terminator. + // Return 0 upon failure. + // This is not the env var you are looking for. this.set_last_error(Scalar::from_u32(203))?; // ERROR_ENVVAR_NOT_FOUND this.write_null(dest)?; } + "SetEnvironmentVariableW" => { + // args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars) + // args[1] : LPCWSTR lpValue (32-bit ptr to a const string of 16-bit Unicode chars) + // Return nonzero if success, else return 0. + throw_unsup_format!("can't set environment variable on Windows"); + } "GetCommandLineW" => { this.write_scalar( this.machine.cmd_line.expect("machine must be initialized"), From b7e6135d7bdd006d4f80d90e20db127ce3be0c3a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 28 Dec 2019 08:38:31 -0500 Subject: [PATCH 1437/5092] Use Scalar::to_u16 --- src/shims/fs.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 63aa750bdd54..2ce002212cf3 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -283,8 +283,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx None => return Ok(-1), }; - // FIXME: use Scalar::to_u16 - let mode: u16 = metadata.mode.to_bits(Size::from_bits(16))? as u16; + let mode: u16 = metadata.mode.to_u16()?; let (access_sec, access_nsec) = metadata.accessed.unwrap_or((0, 0)); let (created_sec, created_nsec) = metadata.created.unwrap_or((0, 0)); From c60ab94d20af93161dd48525d46ef6b010a34f6c Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 28 Dec 2019 09:09:42 -0500 Subject: [PATCH 1438/5092] bump rustc version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index b8bd5f9e5744..9f1b291f7f04 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8f5f8f916f00f7989a4ebf7b7dbfe1afd605f828 +f564c4db0d97eabd7fdd72e589d3e415790ee2a4 From e952e37a39d7c3c54ba419c576ed34405a3d220f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 Dec 2019 12:38:40 +0100 Subject: [PATCH 1439/5092] compile-fail tests work with optimizations now --- tests/compile-fail/validity/nonzero.rs | 1 + tests/compiletest.rs | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/compile-fail/validity/nonzero.rs b/tests/compile-fail/validity/nonzero.rs index f820b0e810b8..dbb31b3f1757 100644 --- a/tests/compile-fail/validity/nonzero.rs +++ b/tests/compile-fail/validity/nonzero.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmir-opt-level=1 #![feature(rustc_attrs)] #![allow(unused_attributes)] diff --git a/tests/compiletest.rs b/tests/compiletest.rs index eaaa87464dbf..9cead530b57c 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -69,9 +69,7 @@ fn compile_fail(path: &str, target: &str, opt: bool) { let mut flags = Vec::new(); if opt { - // FIXME: Opt level 2 ICEs during stack trace generation. - // See https://github.com/rust-lang/rust/issues/66077. - flags.push("-Zmir-opt-level=1".to_owned()); + flags.push("-Zmir-opt-level=3".to_owned()); } run_tests("compile-fail", path, target, flags); From ce4e1f9fe71234a38319c5c900f7e9b69ff8178e Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 27 Dec 2019 09:11:21 -0500 Subject: [PATCH 1440/5092] add comments --- src/shims/fs.rs | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index c6cae22331d1..8829f21abd89 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -152,16 +152,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(handle) = this.machine.file_handler.handles.remove(&fd) { - if handle.read_only { - return Ok(0); + // We sync the file if it was opened in a mode different than read-only. + if !handle.read_only { + // `File::sync_all` does the checks that are done when closing a file. We do this to + // to handle possible errors correctly. + let result = this.try_unwrap_io_result(handle.file.sync_all().map(|_| 0i32)); + // Now we actually close the file. + drop(handle); + // And return the result. + result + } else { + // We drop the file, this closes it but ignores any errors produced when closing + // it. This is done because `File::sync_call` cannot be done over files like + // `/dev/urandom`. Check + // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439 for a deeper + // discussion. + drop(handle); + Ok(0) } - // `File::sync_all` does the checks that are done when closing a file. We do this to - // to handle possible errors correctly. - let result = this.try_unwrap_io_result(handle.file.sync_all().map(|_| 0i32)); - // Now we actually close the file. - drop(handle); - // And return the result. - result } else { this.handle_not_found() } From a40a99d849b11f8580163d5d161221ae6f53f8d8 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 30 Dec 2019 17:26:17 -0500 Subject: [PATCH 1441/5092] avoid double negation --- src/shims/fs.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 8829f21abd89..1403d2867383 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -15,7 +15,7 @@ use shims::time::system_time_to_duration; #[derive(Debug)] pub struct FileHandle { file: File, - read_only: bool, + writable: bool, } pub struct FileHandler { @@ -57,13 +57,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if (o_rdonly | o_wronly | o_rdwr) & !0b11 != 0 { throw_unsup_format!("Access mode flags on this platform are unsupported"); } - let mut read_only = false; + let mut writable = true; // Now we check the access mode let access_mode = flag & 0b11; if access_mode == o_rdonly { - read_only = true; + writable = false; options.read(true); } else if access_mode == o_wronly { options.write(true); @@ -109,7 +109,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = options.open(&path).map(|file| { let mut fh = &mut this.machine.file_handler; fh.low += 1; - fh.handles.insert(fh.low, FileHandle { file, read_only }).unwrap_none(); + fh.handles.insert(fh.low, FileHandle { file, writable }).unwrap_none(); fh.low }); @@ -153,7 +153,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(handle) = this.machine.file_handler.handles.remove(&fd) { // We sync the file if it was opened in a mode different than read-only. - if !handle.read_only { + if handle.writable { // `File::sync_all` does the checks that are done when closing a file. We do this to // to handle possible errors correctly. let result = this.try_unwrap_io_result(handle.file.sync_all().map(|_| 0i32)); @@ -164,7 +164,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { // We drop the file, this closes it but ignores any errors produced when closing // it. This is done because `File::sync_call` cannot be done over files like - // `/dev/urandom`. Check + // `/dev/urandom` which are read-only. Check // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439 for a deeper // discussion. drop(handle); From e1fceafcea2b458cc44592947ef06ddf0ad39e58 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 31 Dec 2019 12:06:42 +0100 Subject: [PATCH 1442/5092] with FS access, default HashMap should work on macOS --- tests/run-pass/hashmap.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass/hashmap.rs index 1ff9c26ba18c..a63036780c99 100644 --- a/tests/run-pass/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -1,3 +1,6 @@ +// macOS needs FS access for its HashMap: +// compile-flags: -Zmiri-disable-isolation + use std::collections::{self, HashMap}; use std::hash::{BuildHasherDefault, BuildHasher}; @@ -18,14 +21,8 @@ fn test_map(mut map: HashMap) { assert_eq!(map.values().fold(0, |x, y| x+y), num*(num-1)/2); // TODO: Test Entry API, Iterators, ... - } fn main() { - if cfg!(target_os = "macos") { // TODO: Implement libstd HashMap seeding for macOS (https://github.com/rust-lang/miri/issues/686). - // Until then, use a deterministic map. - test_map::>(HashMap::default()); - } else { - test_map(HashMap::new()); - } + test_map(HashMap::new()); } From 31fbb5a9b2553cd095144fd0a5af4c976a5a3ae5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 31 Dec 2019 12:10:52 +0100 Subject: [PATCH 1443/5092] fix imports --- tests/run-pass/hashmap.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass/hashmap.rs index a63036780c99..85116796d385 100644 --- a/tests/run-pass/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -1,8 +1,8 @@ // macOS needs FS access for its HashMap: // compile-flags: -Zmiri-disable-isolation -use std::collections::{self, HashMap}; -use std::hash::{BuildHasherDefault, BuildHasher}; +use std::collections::HashMap; +use std::hash::BuildHasher; fn test_map(mut map: HashMap) { map.insert(0, 0); From 84a43fcb6f024d00142bd61b4c7545901b9c036d Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 1 Jan 2020 03:22:06 -0500 Subject: [PATCH 1444/5092] Rustup This is mainly to see if CI can reproduce a strange issue I'm running into locally --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 9f1b291f7f04..a5ba2d9a6130 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -f564c4db0d97eabd7fdd72e589d3e415790ee2a4 +38aa6bdfd705ea0604d7d5dd9fabc5e8f853a4fc From 959033cbfb81a8b5631a1e2c1c4b308a30a12412 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Wed, 1 Jan 2020 21:33:51 -0500 Subject: [PATCH 1445/5092] Bump rustc version to fix miri --- rust-version | 2 +- tests/run-pass/c_enums.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index a5ba2d9a6130..71bc3b30f412 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -38aa6bdfd705ea0604d7d5dd9fabc5e8f853a4fc +0ec370670220b712b042ee09aab067ec7e5878d5 diff --git a/tests/run-pass/c_enums.rs b/tests/run-pass/c_enums.rs index 16b795342eab..5c2cecb33002 100644 --- a/tests/run-pass/c_enums.rs +++ b/tests/run-pass/c_enums.rs @@ -1,3 +1,5 @@ +#![allow(const_err)] // don't warn about truncating casts + enum Foo { Bar = 42, Baz, From c68996dda7771a404ce45690d0c1c02c268092a7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Jan 2020 15:57:33 +0100 Subject: [PATCH 1446/5092] note a FIXME --- tests/run-pass/c_enums.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/c_enums.rs b/tests/run-pass/c_enums.rs index 5c2cecb33002..84c33ca0323f 100644 --- a/tests/run-pass/c_enums.rs +++ b/tests/run-pass/c_enums.rs @@ -1,4 +1,4 @@ -#![allow(const_err)] // don't warn about truncating casts +#![allow(const_err)] // don't warn about truncating casts. FIXME: remove this, the error shouldn't even be shown enum Foo { Bar = 42, From 0a3f460d6966da30bc0128ab89959e17cf64fb04 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Wed, 1 Jan 2020 14:57:10 -0800 Subject: [PATCH 1447/5092] Update panic machinery to match #[track_caller] changes. This gets miri's tests passing again with https://github.com/rust-lang/rust/pull/67137. --- src/machine.rs | 1 + src/shims/panic.rs | 5 +---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 37253a260de7..502120d316b7 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -182,6 +182,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn find_mir_or_eval_fn( ecx: &mut InterpCx<'mir, 'tcx, Self>, + _span: Span, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, diff --git a/src/shims/panic.rs b/src/shims/panic.rs index f242f41f6f96..8f082f45c915 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -187,15 +187,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let msg = msg.description(); let msg = this.allocate_str(msg, MiriMemoryKind::Env.into()); - // Second arg: Caller location. - let location = this.alloc_caller_location_for_span(span); - // Call the lang item. let panic = this.tcx.lang_items().panic_fn().unwrap(); let panic = ty::Instance::mono(this.tcx.tcx, panic); this.call_function( panic, - &[msg.to_ref(), location.ptr.into()], + &[msg.to_ref()], None, StackPopCleanup::Goto { ret: None, unwind }, )?; From ebacb8ae4ee46e72791e115a4cdce1344a5db53b Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 5 Jan 2020 17:53:45 +0900 Subject: [PATCH 1448/5092] Rustup --- rust-version | 2 +- src/eval.rs | 2 +- src/helpers.rs | 2 +- src/lib.rs | 1 + src/machine.rs | 3 ++- src/shims/foreign_items.rs | 4 ++-- src/shims/intrinsics.rs | 2 +- src/shims/panic.rs | 2 +- 8 files changed, 10 insertions(+), 8 deletions(-) diff --git a/rust-version b/rust-version index 71bc3b30f412..44bed6b73d1a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0ec370670220b712b042ee09aab067ec7e5878d5 +093241deae70ba38413aff823b31c23731debf14 diff --git a/src/eval.rs b/src/eval.rs index 0cc302b967b2..1968111307e7 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -47,7 +47,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( config: MiriConfig, ) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'tcx>>, MPlaceTy<'tcx, Tag>)> { let mut ecx = InterpCx::new( - tcx.at(syntax::source_map::DUMMY_SP), + tcx.at(rustc_span::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), Evaluator::new(config.communicate), MemoryExtra::new( diff --git a/src/helpers.rs b/src/helpers.rs index 18b433a0e4a5..17d74d2ef757 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -8,7 +8,7 @@ use rustc::ty::{ layout::{self, LayoutOf, Size, TyLayout}, List, TyCtxt, }; -use syntax::source_map::DUMMY_SP; +use rustc_span::source_map::DUMMY_SP; use rand::RngCore; diff --git a/src/lib.rs b/src/lib.rs index 32d2bda719ea..2ddcdf8ff777 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ extern crate rustc_apfloat; extern crate syntax; #[macro_use] extern crate rustc; +extern crate rustc_span; extern crate rustc_data_structures; extern crate rustc_mir; extern crate rustc_target; diff --git a/src/machine.rs b/src/machine.rs index 502120d316b7..4c1446c82c74 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -14,7 +14,8 @@ use rustc::ty::{ layout::{LayoutOf, Size}, Ty, TyCtxt, }; -use syntax::{attr, source_map::Span, symbol::sym}; +use rustc_span::{source_map::Span, symbol::sym}; +use syntax::attr; use crate::*; diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 07e3b7d75826..6ad16c6f6764 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -5,8 +5,8 @@ use rustc::mir; use rustc::ty; use rustc::ty::layout::{Align, LayoutOf, Size}; use rustc_apfloat::Float; +use rustc_span::symbol::sym; use syntax::attr; -use syntax::symbol::sym; use crate::*; @@ -961,7 +961,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // lpBuffer : ptr to buffer that receives contents of the env_var as a null-terminated string. // Return `# of chars` stored in the buffer pointed to by lpBuffer, excluding null-terminator. // Return 0 upon failure. - + // This is not the env var you are looking for. this.set_last_error(Scalar::from_u32(203))?; // ERROR_ENVVAR_NOT_FOUND this.write_null(dest)?; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 37aee1f5652c..a7aec53c37de 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -5,7 +5,7 @@ use rustc::mir::interpret::{InterpResult, PointerArithmetic}; use rustc::ty; use rustc::ty::layout::{self, Align, LayoutOf, Size}; use rustc_apfloat::Float; -use syntax::source_map::Span; +use rustc_span::source_map::Span; use crate::*; diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 8f082f45c915..950a23aa59ca 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -14,7 +14,7 @@ use rustc::mir; use rustc::ty::{self, layout::LayoutOf}; use rustc_target::spec::PanicStrategy; -use syntax::source_map::Span; +use rustc_span::source_map::Span; use crate::*; From 3607dafd9b81ff2ea18861ce8bea110513e87807 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 6 Jan 2020 13:22:24 +0900 Subject: [PATCH 1449/5092] More rustup --- src/bin/miri-rustc-tests.rs | 4 ++-- src/bin/miri.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 19816fe008f5..f3b271c35952 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -7,7 +7,7 @@ extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_interface; extern crate rustc_metadata; -extern crate syntax; +extern crate rustc_span; use std::io; use std::io::Write; @@ -40,7 +40,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { impl<'tcx, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.kind { - if i.attrs.iter().any(|attr| attr.check_name(syntax::symbol::sym::test)) + if i.attrs.iter().any(|attr| attr.check_name(rustc_span::symbol::sym::test)) { let config = MiriConfig { validate: true, diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 1af79b259613..17c5fc20608e 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -12,7 +12,7 @@ extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_interface; extern crate rustc_metadata; -extern crate syntax; +extern crate rustc_span; use std::convert::TryFrom; use std::env; From e979589357fa3331337575a3ade04eaf48c4cccd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jan 2020 10:43:41 +0100 Subject: [PATCH 1450/5092] no longer test 32bit macOS --- travis.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/travis.sh b/travis.sh index af297129e821..7046a3226b7d 100755 --- a/travis.sh +++ b/travis.sh @@ -2,9 +2,7 @@ set -euo pipefail # Determine configuration -if [ "$TRAVIS_OS_NAME" == osx ]; then - FOREIGN_TARGET=i686-apple-darwin -else +if [ "$TRAVIS_OS_NAME" == linux ]; then FOREIGN_TARGET=i686-unknown-linux-gnu fi export CARGO_EXTRA_FLAGS="--all-features" @@ -28,6 +26,8 @@ echo "Test host architecture" run_tests echo -echo "Test foreign architecture ($FOREIGN_TARGET)" -MIRI_TEST_TARGET="$FOREIGN_TARGET" run_tests -echo +if [ -n "$FOREIGN_TARGET" ]; then + echo "Test foreign architecture ($FOREIGN_TARGET)" + MIRI_TEST_TARGET="$FOREIGN_TARGET" run_tests + echo +fi From 6a614708ca599cd4e2514429c167d8e045ca8128 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jan 2020 11:02:25 +0100 Subject: [PATCH 1451/5092] fix testing if a variable exists --- travis.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/travis.sh b/travis.sh index 7046a3226b7d..3d4b8651fb83 100755 --- a/travis.sh +++ b/travis.sh @@ -26,7 +26,7 @@ echo "Test host architecture" run_tests echo -if [ -n "$FOREIGN_TARGET" ]; then +if [ -n "${FOREIGN_TARGET+exists}" ]; then echo "Test foreign architecture ($FOREIGN_TARGET)" MIRI_TEST_TARGET="$FOREIGN_TARGET" run_tests echo From 0217a25a12d87d010c3df381b0b3d1206837ad95 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jan 2020 11:38:35 +0100 Subject: [PATCH 1452/5092] remove no-longer-needed allow(const_err) --- tests/run-pass/c_enums.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/run-pass/c_enums.rs b/tests/run-pass/c_enums.rs index 84c33ca0323f..16b795342eab 100644 --- a/tests/run-pass/c_enums.rs +++ b/tests/run-pass/c_enums.rs @@ -1,5 +1,3 @@ -#![allow(const_err)] // don't warn about truncating casts. FIXME: remove this, the error shouldn't even be shown - enum Foo { Bar = 42, Baz, From 86ee705cd5667ff868fa00456f14b29bc3b30c88 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Tue, 7 Jan 2020 04:53:41 +0900 Subject: [PATCH 1453/5092] Rustup --- benches/helpers/miri_helper.rs | 3 ++- rust-version | 2 +- src/bin/miri-rustc-tests.rs | 6 ++++-- src/bin/miri.rs | 3 ++- src/eval.rs | 2 +- src/helpers.rs | 4 ++-- src/lib.rs | 1 + src/machine.rs | 2 +- src/shims/foreign_items.rs | 2 +- src/shims/fs.rs | 2 +- src/stacked_borrows.rs | 2 +- 11 files changed, 17 insertions(+), 12 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 92aedcc4244a..122d381f7927 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -2,12 +2,13 @@ extern crate getopts; extern crate miri; extern crate rustc; extern crate rustc_driver; +extern crate rustc_hir; extern crate rustc_interface; extern crate test; use self::miri::eval_main; use crate::test::Bencher; -use rustc::hir::def_id::LOCAL_CRATE; +use rustc_hir::def_id::LOCAL_CRATE; use rustc_driver::Compilation; use rustc_interface::{interface, Queries}; diff --git a/rust-version b/rust-version index 44bed6b73d1a..d39ff0adb268 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -093241deae70ba38413aff823b31c23731debf14 +ebbb2bf37aedaaa64dfaa52ba337ca6efb6b9093 diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index f3b271c35952..2ac0ab9ca4de 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -5,6 +5,7 @@ extern crate rustc; extern crate rustc_codegen_utils; extern crate rustc_driver; extern crate rustc_errors; +extern crate rustc_hir; extern crate rustc_interface; extern crate rustc_metadata; extern crate rustc_span; @@ -14,8 +15,9 @@ use std::io::Write; use std::path::Path; use std::sync::{Arc, Mutex}; -use rustc::hir::def_id::LOCAL_CRATE; -use rustc::hir::{self, itemlikevisit}; +use rustc_hir as hir; +use rustc_hir::def_id::LOCAL_CRATE; +use rustc_hir::itemlikevisit; use rustc::ty::TyCtxt; use rustc_driver::Compilation; use rustc_interface::{interface, Queries}; diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 17c5fc20608e..228c50e4a57b 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -10,6 +10,7 @@ extern crate rustc; extern crate rustc_codegen_utils; extern crate rustc_driver; extern crate rustc_errors; +extern crate rustc_hir; extern crate rustc_interface; extern crate rustc_metadata; extern crate rustc_span; @@ -20,7 +21,7 @@ use std::str::FromStr; use hex::FromHexError; -use rustc::hir::def_id::LOCAL_CRATE; +use rustc_hir::def_id::LOCAL_CRATE; use rustc_driver::Compilation; use rustc_interface::{interface, Queries}; diff --git a/src/eval.rs b/src/eval.rs index 1968111307e7..eac9b8a83baa 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -5,7 +5,7 @@ use std::ffi::OsStr; use rand::rngs::StdRng; use rand::SeedableRng; -use rustc::hir::def_id::DefId; +use rustc_hir::def_id::DefId; use rustc::ty::layout::{LayoutOf, Size}; use rustc::ty::{self, TyCtxt}; diff --git a/src/helpers.rs b/src/helpers.rs index 17d74d2ef757..ff9a16a02456 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,7 +1,7 @@ use std::ffi::OsStr; use std::{iter, mem}; -use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; +use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc::ty::{ self, @@ -331,7 +331,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function to get the `TyLayout` of a `libc` type fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyLayout<'tcx>> { let this = self.eval_context_mut(); - let ty = this.resolve_path(&["libc", name])?.ty(*this.tcx); + let ty = this.resolve_path(&["libc", name])?.monomorphic_ty(*this.tcx); this.layout_of(ty) } diff --git a/src/lib.rs b/src/lib.rs index 2ddcdf8ff777..19a84db3e17e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ extern crate rustc_apfloat; extern crate syntax; #[macro_use] extern crate rustc; +extern crate rustc_hir; extern crate rustc_span; extern crate rustc_data_structures; extern crate rustc_mir; diff --git a/src/machine.rs b/src/machine.rs index 4c1446c82c74..f8c7168a5847 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -7,7 +7,7 @@ use std::rc::Rc; use rand::rngs::StdRng; -use rustc::hir::def_id::DefId; +use rustc_hir::def_id::DefId; use rustc::mir; use rustc::ty::{ self, diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 6ad16c6f6764..2d6eafdf8f19 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -1,6 +1,6 @@ use std::{convert::TryInto, iter}; -use rustc::hir::def_id::DefId; +use rustc_hir::def_id::DefId; use rustc::mir; use rustc::ty; use rustc::ty::layout::{Align, LayoutOf, Size}; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 8c8bd6f7bb97..858369682892 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -389,7 +389,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // function and `resolve_path` is returning the latter. let statx_ty = this .resolve_path(&["libc", "unix", "linux_like", "linux", "gnu", "statx"])? - .ty(*this.tcx); + .monomorphic_ty(*this.tcx); let statxbuf_ty = this.tcx.mk_mut_ptr(statx_ty); let statxbuf_layout = this.layout_of(statxbuf_ty)?; let statxbuf_imm = ImmTy::from_scalar(statxbuf_scalar, statxbuf_layout); diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 18edb603c6cf..53a94e74cbf0 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -7,7 +7,7 @@ use std::fmt; use std::num::NonZeroU64; use std::rc::Rc; -use rustc::hir::Mutability; +use rustc_hir::Mutability; use rustc::mir::RetagKind; use rustc::ty::{self, layout::Size}; From 4a1dbc77dc9f64aebd0b16927bb71f3178376d30 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 6 Jan 2020 16:30:17 -0500 Subject: [PATCH 1454/5092] Add shim for symbolic link creation --- src/shims/foreign_items.rs | 5 +++++ src/shims/fs.rs | 31 ++++++++++++++++++++++++++++++- tests/run-pass/fs.rs | 17 ++++++++++++++++- 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 07e3b7d75826..6a2f42f83215 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -494,6 +494,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "symlink" => { + let result = this.symlink(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + "stat$INODE64" => { let result = this.stat(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 8c8bd6f7bb97..c5b753f3b6a2 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -276,6 +276,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.try_unwrap_io_result(result) } + fn symlink( + &mut self, + target_op: OpTy<'tcx, Tag>, + linkpath_op: OpTy<'tcx, Tag> + ) -> InterpResult<'tcx, i32> { + #[cfg(target_family = "unix")] + fn create_link(src: PathBuf, dst: PathBuf) -> std::io::Result<()> { + std::os::unix::fs::symlink(src, dst) + } + + #[cfg(target_family = "windows")] + fn create_link(src: PathBuf, dst: PathBuf) -> std::io::Result<()> { + use std::os::windows::fs; + if src.is_dir() { + fs::symlink_dir(src, dst) + } else { + fs::symlink(src, dst) + } + } + + let this = self.eval_context_mut(); + + this.check_no_isolation("symlink")?; + + let target = this.read_os_str_from_c_str(this.read_scalar(target_op)?.not_undef()?)?.into(); + let linkpath = this.read_os_str_from_c_str(this.read_scalar(linkpath_op)?.not_undef()?)?.into(); + + this.try_unwrap_io_result(create_link(target, linkpath).map(|_| 0)) + } + fn stat( &mut self, path_op: OpTy<'tcx, Tag>, @@ -545,7 +575,6 @@ impl FileMetadata { let metadata = if follow_symlink { std::fs::metadata(path) } else { - // FIXME: metadata for symlinks need testing. std::fs::symlink_metadata(path) }; diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 85e39bc45112..9e0428fb57c2 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -39,9 +39,24 @@ fn main() { // Test that metadata of an absolute path is correct. test_metadata(bytes, &path).unwrap(); // Test that metadata of a relative path is correct. - std::env::set_current_dir(tmp).unwrap(); + std::env::set_current_dir(&tmp).unwrap(); test_metadata(bytes, &filename).unwrap(); + // Creating a symbolic link should succeed + let symlink_path = tmp.join("miri_test_fs_symlink.txt"); + std::os::unix::fs::symlink(&path, &symlink_path).unwrap(); + // Test that the symbolic link has the same contents as the file. + let mut symlink_file = File::open(&symlink_path).unwrap(); + let mut contents = Vec::new(); + symlink_file.read_to_end(&mut contents).unwrap(); + assert_eq!(bytes, contents.as_slice()); + // Test that metadata of a symbolic link is correct. + test_metadata(bytes, &symlink_path).unwrap(); + // Test that the metadata of a symbolic link is correct when not following it. + assert!(symlink_path.symlink_metadata().unwrap().file_type().is_symlink()); + // Removing symbolic link should succeed. + remove_file(&symlink_path).unwrap(); + // Removing file should succeed. remove_file(&path).unwrap(); From 329310fbd63c564df6dd76f40181668861a7ed16 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 7 Jan 2020 11:09:07 -0500 Subject: [PATCH 1455/5092] Clean paths for robustness --- tests/run-pass/fs.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 9e0428fb57c2..90b5dcfb5fa6 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -19,7 +19,11 @@ fn main() { let tmp = std::env::temp_dir(); let filename = PathBuf::from("miri_test_fs.txt"); let path = tmp.join(&filename); + let symlink_path = tmp.join("miri_test_fs_symlink.txt"); let bytes = b"Hello, World!\n"; + // Clean the paths for robustness. + remove_file(&path).unwrap_or(()); + remove_file(&symlink_path).unwrap_or(()); // Test creating, writing and closing a file (closing is tested when `file` is dropped). let mut file = File::create(&path).unwrap(); @@ -42,8 +46,7 @@ fn main() { std::env::set_current_dir(&tmp).unwrap(); test_metadata(bytes, &filename).unwrap(); - // Creating a symbolic link should succeed - let symlink_path = tmp.join("miri_test_fs_symlink.txt"); + // Creating a symbolic link should succeed. std::os::unix::fs::symlink(&path, &symlink_path).unwrap(); // Test that the symbolic link has the same contents as the file. let mut symlink_file = File::open(&symlink_path).unwrap(); From 91cf68fac569d0817fc8649bff28d727bbed47b2 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 7 Jan 2020 11:29:25 -0500 Subject: [PATCH 1456/5092] Add lstat shim for macos --- src/shims/foreign_items.rs | 5 +++++ src/shims/fs.rs | 26 ++++++++++++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 6a2f42f83215..f3baebad143b 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -504,6 +504,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "lstat$INODE64" => { + let result = this.lstat(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + "clock_gettime" => { let result = this.clock_gettime(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index c5b753f3b6a2..3927f0e64919 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -312,6 +312,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx buf_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + this.check_no_isolation("stat")?; + // `stat` always follows symlinks. + this.stat_or_lstat(true, path_op, buf_op) + } + + // `lstat` is used to get symlink metadata. + fn lstat( + &mut self, + path_op: OpTy<'tcx, Tag>, + buf_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + this.check_no_isolation("lstat")?; + this.stat_or_lstat(false, path_op, buf_op) + } + + fn stat_or_lstat( + &mut self, + follow_symlink: bool, + path_op: OpTy<'tcx, Tag>, + buf_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); if this.tcx.sess.target.target.target_os.to_lowercase() != "macos" { throw_unsup_format!("The `stat` shim is only available for `macos` targets.") @@ -322,8 +345,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.deref_operand(buf_op)?; - // `stat` always follows symlinks. `lstat` is used to get symlink metadata. - let metadata = match FileMetadata::new(this, path, true)? { + let metadata = match FileMetadata::new(this, path, follow_symlink)? { Some(metadata) => metadata, None => return Ok(-1), }; From b9f6b9721a72abfb9f83d8b25cb41ed5c618d755 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 24 Dec 2019 00:07:55 +0100 Subject: [PATCH 1457/5092] Split error reporting from main eval function --- src/eval.rs | 120 ++++++++++++++++++++++++++-------------------------- 1 file changed, 61 insertions(+), 59 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index eac9b8a83baa..b2f290414cee 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -8,6 +8,7 @@ use rand::SeedableRng; use rustc_hir::def_id::DefId; use rustc::ty::layout::{LayoutOf, Size}; use rustc::ty::{self, TyCtxt}; +use rustc_mir::interpret::InterpErrorInfo; use crate::*; @@ -205,64 +206,65 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> } return Some(return_code); } - Err(mut e) => { - // Special treatment for some error kinds - let msg = match e.kind { - InterpError::MachineStop(ref info) => { - let info = info - .downcast_ref::() - .expect("invalid MachineStop payload"); - match info { - TerminationInfo::Exit(code) => return Some(*code), - TerminationInfo::PoppedTrackedPointerTag(item) => - format!("popped tracked tag for item {:?}", item), - TerminationInfo::Abort => - format!("the evaluated program aborted execution"), - } - } - err_unsup!(NoMirFor(..)) => format!( - "{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", - e - ), - InterpError::InvalidProgram(_) => - bug!("This error should be impossible in Miri: {}", e), - _ => e.to_string(), - }; - e.print_backtrace(); - if let Some(frame) = ecx.stack().last() { - let span = frame.current_source_info().unwrap().span; - - let msg = format!("Miri evaluation error: {}", msg); - let mut err = ecx.tcx.sess.struct_span_err(span, msg.as_str()); - let frames = ecx.generate_stacktrace(None); - err.span_label(span, msg); - // We iterate with indices because we need to look at the next frame (the caller). - for idx in 0..frames.len() { - let frame_info = &frames[idx]; - let call_site_is_local = frames - .get(idx + 1) - .map_or(false, |caller_info| caller_info.instance.def_id().is_local()); - if call_site_is_local { - err.span_note(frame_info.call_site, &frame_info.to_string()); - } else { - err.note(&frame_info.to_string()); - } - } - err.emit(); - } else { - ecx.tcx.sess.err(&msg); - } - - for (i, frame) in ecx.stack().iter().enumerate() { - trace!("-------------------"); - trace!("Frame {}", i); - trace!(" return: {:?}", frame.return_place.map(|p| *p)); - for (i, local) in frame.locals.iter().enumerate() { - trace!(" local {}: {:?}", i, local.value); - } - } - // Let the reported error determine the return code. - return None; - } + Err(e) => report_err(&ecx, e), } } + +fn report_err<'tcx, 'mir>( + ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, + mut e: InterpErrorInfo<'tcx>, +) -> Option { + // Special treatment for some error kinds + let msg = match e.kind { + InterpError::MachineStop(ref info) => { + let info = info.downcast_ref::().expect("invalid MachineStop payload"); + match info { + TerminationInfo::Exit(code) => return Some(*code), + TerminationInfo::PoppedTrackedPointerTag(item) => + format!("popped tracked tag for item {:?}", item), + TerminationInfo::Abort => format!("the evaluated program aborted execution"), + } + } + err_unsup!(NoMirFor(..)) => format!( + "{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", + e + ), + InterpError::InvalidProgram(_) => bug!("This error should be impossible in Miri: {}", e), + _ => e.to_string(), + }; + e.print_backtrace(); + if let Some(frame) = ecx.stack().last() { + let span = frame.current_source_info().unwrap().span; + + let msg = format!("Miri evaluation error: {}", msg); + let mut err = ecx.tcx.sess.struct_span_err(span, msg.as_str()); + let frames = ecx.generate_stacktrace(None); + err.span_label(span, msg); + // We iterate with indices because we need to look at the next frame (the caller). + for idx in 0..frames.len() { + let frame_info = &frames[idx]; + let call_site_is_local = frames + .get(idx + 1) + .map_or(false, |caller_info| caller_info.instance.def_id().is_local()); + if call_site_is_local { + err.span_note(frame_info.call_site, &frame_info.to_string()); + } else { + err.note(&frame_info.to_string()); + } + } + err.emit(); + } else { + ecx.tcx.sess.err(&msg); + } + + for (i, frame) in ecx.stack().iter().enumerate() { + trace!("-------------------"); + trace!("Frame {}", i); + trace!(" return: {:?}", frame.return_place.map(|p| *p)); + for (i, local) in frame.locals.iter().enumerate() { + trace!(" local {}: {:?}", i, local.value); + } + } + // Let the reported error determine the return code. + return None; +} From 2673ba99fd28abc8448159a51d288ec942e7a65e Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 24 Dec 2019 00:08:47 +0100 Subject: [PATCH 1458/5092] Trailing return --- src/eval.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/eval.rs b/src/eval.rs index b2f290414cee..9c15fedca3d0 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -204,7 +204,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> return None; } } - return Some(return_code); + Some(return_code) } Err(e) => report_err(&ecx, e), } From 4de031b3da1c3dc8091a64daa46322ced3796c0f Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 24 Dec 2019 00:11:40 +0100 Subject: [PATCH 1459/5092] Move error reporting to its own module --- src/diagnostics.rs | 62 ++++++++++++++++++++++++++++++++++++++++++++++ src/eval.rs | 60 -------------------------------------------- src/lib.rs | 2 ++ 3 files changed, 64 insertions(+), 60 deletions(-) create mode 100644 src/diagnostics.rs diff --git a/src/diagnostics.rs b/src/diagnostics.rs new file mode 100644 index 000000000000..30be49ff770c --- /dev/null +++ b/src/diagnostics.rs @@ -0,0 +1,62 @@ +use rustc_mir::interpret::InterpErrorInfo; + +use crate::*; + +pub fn report_err<'tcx, 'mir>( + ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, + mut e: InterpErrorInfo<'tcx>, +) -> Option { + // Special treatment for some error kinds + let msg = match e.kind { + InterpError::MachineStop(ref info) => { + let info = info.downcast_ref::().expect("invalid MachineStop payload"); + match info { + TerminationInfo::Exit(code) => return Some(*code), + TerminationInfo::PoppedTrackedPointerTag(item) => + format!("popped tracked tag for item {:?}", item), + TerminationInfo::Abort => format!("the evaluated program aborted execution"), + } + } + err_unsup!(NoMirFor(..)) => format!( + "{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", + e + ), + InterpError::InvalidProgram(_) => bug!("This error should be impossible in Miri: {}", e), + _ => e.to_string(), + }; + e.print_backtrace(); + if let Some(frame) = ecx.stack().last() { + let span = frame.current_source_info().unwrap().span; + + let msg = format!("Miri evaluation error: {}", msg); + let mut err = ecx.tcx.sess.struct_span_err(span, msg.as_str()); + let frames = ecx.generate_stacktrace(None); + err.span_label(span, msg); + // We iterate with indices because we need to look at the next frame (the caller). + for idx in 0..frames.len() { + let frame_info = &frames[idx]; + let call_site_is_local = frames + .get(idx + 1) + .map_or(false, |caller_info| caller_info.instance.def_id().is_local()); + if call_site_is_local { + err.span_note(frame_info.call_site, &frame_info.to_string()); + } else { + err.note(&frame_info.to_string()); + } + } + err.emit(); + } else { + ecx.tcx.sess.err(&msg); + } + + for (i, frame) in ecx.stack().iter().enumerate() { + trace!("-------------------"); + trace!("Frame {}", i); + trace!(" return: {:?}", frame.return_place.map(|p| *p)); + for (i, local) in frame.locals.iter().enumerate() { + trace!(" local {}: {:?}", i, local.value); + } + } + // Let the reported error determine the return code. + return None; +} diff --git a/src/eval.rs b/src/eval.rs index 9c15fedca3d0..e5dfbe32c12e 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -8,7 +8,6 @@ use rand::SeedableRng; use rustc_hir::def_id::DefId; use rustc::ty::layout::{LayoutOf, Size}; use rustc::ty::{self, TyCtxt}; -use rustc_mir::interpret::InterpErrorInfo; use crate::*; @@ -209,62 +208,3 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Err(e) => report_err(&ecx, e), } } - -fn report_err<'tcx, 'mir>( - ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, - mut e: InterpErrorInfo<'tcx>, -) -> Option { - // Special treatment for some error kinds - let msg = match e.kind { - InterpError::MachineStop(ref info) => { - let info = info.downcast_ref::().expect("invalid MachineStop payload"); - match info { - TerminationInfo::Exit(code) => return Some(*code), - TerminationInfo::PoppedTrackedPointerTag(item) => - format!("popped tracked tag for item {:?}", item), - TerminationInfo::Abort => format!("the evaluated program aborted execution"), - } - } - err_unsup!(NoMirFor(..)) => format!( - "{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", - e - ), - InterpError::InvalidProgram(_) => bug!("This error should be impossible in Miri: {}", e), - _ => e.to_string(), - }; - e.print_backtrace(); - if let Some(frame) = ecx.stack().last() { - let span = frame.current_source_info().unwrap().span; - - let msg = format!("Miri evaluation error: {}", msg); - let mut err = ecx.tcx.sess.struct_span_err(span, msg.as_str()); - let frames = ecx.generate_stacktrace(None); - err.span_label(span, msg); - // We iterate with indices because we need to look at the next frame (the caller). - for idx in 0..frames.len() { - let frame_info = &frames[idx]; - let call_site_is_local = frames - .get(idx + 1) - .map_or(false, |caller_info| caller_info.instance.def_id().is_local()); - if call_site_is_local { - err.span_note(frame_info.call_site, &frame_info.to_string()); - } else { - err.note(&frame_info.to_string()); - } - } - err.emit(); - } else { - ecx.tcx.sess.err(&msg); - } - - for (i, frame) in ecx.stack().iter().enumerate() { - trace!("-------------------"); - trace!("Frame {}", i); - trace!(" return: {:?}", frame.return_place.map(|p| *p)); - for (i, local) in frame.locals.iter().enumerate() { - trace!(" local {}: {:?}", i, local.value); - } - } - // Let the reported error determine the return code. - return None; -} diff --git a/src/lib.rs b/src/lib.rs index 19a84db3e17e..b5925bb26c89 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,7 @@ extern crate rustc_data_structures; extern crate rustc_mir; extern crate rustc_target; +mod diagnostics; mod eval; mod helpers; mod intptrcast; @@ -41,6 +42,7 @@ pub use crate::shims::time::EvalContextExt as TimeEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::EvalContextExt as ShimsEvalContextExt; +pub use crate::diagnostics::report_err; pub use crate::eval::{create_ecx, eval_main, MiriConfig, TerminationInfo}; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; pub use crate::machine::{ From 4411903cca01933cc98ac903b3864768b6136024 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 24 Dec 2019 00:22:32 +0100 Subject: [PATCH 1460/5092] Add a scheme for registering and obtaining errors even without access to an `InterpCx` --- src/diagnostics.rs | 17 +++++++++++++++++ src/lib.rs | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 30be49ff770c..2431d9230f36 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -60,3 +60,20 @@ pub fn report_err<'tcx, 'mir>( // Let the reported error determine the return code. return None; } + +use std::cell::RefCell; +thread_local! { + static ECX: RefCell>> = RefCell::new(Vec::new()); +} + +pub fn register_err(e: InterpErrorInfo<'static>) { + ECX.with(|ecx| ecx.borrow_mut().push(e)); +} + +pub fn process_errors(mut f: impl FnMut(InterpErrorInfo<'static>)) { + ECX.with(|ecx| { + for e in ecx.borrow_mut().drain(..) { + f(e); + } + }); +} diff --git a/src/lib.rs b/src/lib.rs index b5925bb26c89..bf6b111754de 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,7 +42,7 @@ pub use crate::shims::time::EvalContextExt as TimeEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::EvalContextExt as ShimsEvalContextExt; -pub use crate::diagnostics::report_err; +pub use crate::diagnostics::{process_errors, register_err, report_err}; pub use crate::eval::{create_ecx, eval_main, MiriConfig, TerminationInfo}; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; pub use crate::machine::{ From 96d6efdf32f346c45f58897b2f7fff38a476cfbe Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 24 Dec 2019 02:04:07 +0100 Subject: [PATCH 1461/5092] Emit errors without halting interpretation --- src/diagnostics.rs | 16 ++++++++++------ src/lib.rs | 4 +++- src/stacked_borrows.rs | 15 ++++++++++----- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 2431d9230f36..504863b13427 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -70,10 +70,14 @@ pub fn register_err(e: InterpErrorInfo<'static>) { ECX.with(|ecx| ecx.borrow_mut().push(e)); } -pub fn process_errors(mut f: impl FnMut(InterpErrorInfo<'static>)) { - ECX.with(|ecx| { - for e in ecx.borrow_mut().drain(..) { - f(e); - } - }); +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn process_errors(&self) { + let this = self.eval_context_ref(); + ECX.with(|ecx| { + for e in ecx.borrow_mut().drain(..) { + report_err(this, e); + } + }); + } } diff --git a/src/lib.rs b/src/lib.rs index bf6b111754de..ae92a777d88e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,7 +42,9 @@ pub use crate::shims::time::EvalContextExt as TimeEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::EvalContextExt as ShimsEvalContextExt; -pub use crate::diagnostics::{process_errors, register_err, report_err}; +pub use crate::diagnostics::{ + register_err, report_err, EvalContextExt as DiagnosticsEvalContextExt, +}; pub use crate::eval::{create_ecx, eval_main, MiriConfig, TerminationInfo}; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; pub use crate::machine::{ diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 53a94e74cbf0..3d446c6b468e 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -10,11 +10,9 @@ use std::rc::Rc; use rustc_hir::Mutability; use rustc::mir::RetagKind; use rustc::ty::{self, layout::Size}; +use rustc_mir::interpret::InterpError; -use crate::{ - AllocId, HelpersEvalContextExt, ImmTy, Immediate, InterpResult, MPlaceTy, MemoryKind, - MiriMemoryKind, PlaceTy, Pointer, RangeMap, TerminationInfo, -}; +use crate::*; pub type PtrId = NonZeroU64; pub type CallId = NonZeroU64; @@ -269,7 +267,12 @@ impl<'tcx> Stack { fn check_protector(item: &Item, tag: Option, global: &GlobalState) -> InterpResult<'tcx> { if let Tag::Tagged(id) = item.tag { if Some(id) == global.tracked_pointer_tag { - throw_machine_stop!(TerminationInfo::PoppedTrackedPointerTag(item.clone())); + register_err( + InterpError::MachineStop(Box::new(TerminationInfo::PoppedTrackedPointerTag( + item.clone(), + ))) + .into(), + ); } } if let Some(call) = item.protector { @@ -630,6 +633,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_immediate(val, place)?; } + this.process_errors(); + Ok(()) } } From bb58e42da2315c30594222bccb64b8a63fb537be Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 24 Dec 2019 02:16:43 +0100 Subject: [PATCH 1462/5092] Tell the user about stacked borrow debugging flags --- src/stacked_borrows.rs | 44 +++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 3d446c6b468e..77295e8dd536 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -4,6 +4,7 @@ use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::fmt; +use std::fmt::Write; use std::num::NonZeroU64; use std::rc::Rc; @@ -278,10 +279,13 @@ impl<'tcx> Stack { if let Some(call) = item.protector { if global.is_active(call) { if let Some(tag) = tag { - throw_ub!(UbExperimental(format!( - "not granting access to tag {:?} because incompatible item is protected: {:?}", - tag, item - ))); + return Err(err_ub_experimental( + tag, + format!( + "not granting access to tag {:?} because incompatible item is protected: {:?}", + tag, item + ), + )); } else { throw_ub!(UbExperimental(format!( "deallocating while item is protected: {:?}", @@ -300,10 +304,10 @@ impl<'tcx> Stack { // Step 1: Find granting item. let granting_idx = self.find_granting(access, tag).ok_or_else(|| { - err_ub!(UbExperimental(format!( - "no item granting {} to tag {:?} found in borrow stack", - access, tag, - ))) + err_ub_experimental( + tag, + format!("no item granting {} to tag {:?} found in borrow stack.", access, tag), + ) })?; // Step 2: Remove incompatible items above them. Make sure we do not remove protected @@ -344,10 +348,11 @@ impl<'tcx> Stack { fn dealloc(&mut self, tag: Tag, global: &GlobalState) -> InterpResult<'tcx> { // Step 1: Find granting item. self.find_granting(AccessKind::Write, tag).ok_or_else(|| { - err_ub!(UbExperimental(format!( + err_ub_experimental( + tag,format!( "no item granting write access for deallocation to tag {:?} found in borrow stack", tag, - ))) + )) })?; // Step 2: Remove all items. Also checks for protectors. @@ -369,9 +374,14 @@ impl<'tcx> Stack { // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. let granting_idx = self.find_granting(access, derived_from) - .ok_or_else(|| err_ub!(UbExperimental(format!( - "trying to reborrow for {:?}, but parent tag {:?} does not have an appropriate item in the borrow stack", new.perm, derived_from, - ))))?; + .ok_or_else(|| + err_ub_experimental( + derived_from, + format!( + "trying to reborrow for {:?}, but parent tag {:?} does not have an appropriate item in the borrow stack", + new.perm, derived_from, + ), + ))?; // Compute where to put the new item. // Either way, we ensure that we insert the new item in a way such that between @@ -638,3 +648,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } } + +fn err_ub_experimental(tag: Tag, mut msg: String) -> InterpErrorInfo<'static> { + if let Tag::Tagged(id) = tag { + // FIXME: do not add this message when the flag is already set + write!(msg, " Rerun with `-Zmiri-track-pointer-tag={}` for more information", id).unwrap(); + } + err_ub!(UbExperimental(msg)).into() +} From aec175e0deb39d35a9b5c0f329141c4b22930e01 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 8 Jan 2020 12:49:46 +0100 Subject: [PATCH 1463/5092] Process delayed errors on every step --- src/eval.rs | 4 +++- src/stacked_borrows.rs | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index e5dfbe32c12e..1e9332c9a32d 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -183,7 +183,9 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> // Perform the main execution. let res: InterpResult<'_, i64> = (|| { - ecx.run()?; + while ecx.step()? { + ecx.process_errors(); + } // Read the return code pointer *before* we run TLS destructors, to assert // that it was written to by the time that `start` lang item returned. let return_code = ecx.read_scalar(ret_place.into())?.not_undef()?.to_machine_isize(&ecx)?; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 77295e8dd536..ace4fef3ce3b 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -643,8 +643,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_immediate(val, place)?; } - this.process_errors(); - Ok(()) } } From c0a7fd56021a375478bd9e202bf5692e4e48736a Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 8 Jan 2020 12:50:15 +0100 Subject: [PATCH 1464/5092] Remove debugging hint until we can actuall use `note:` --- src/stacked_borrows.rs | 51 +++++++++++++----------------------------- 1 file changed, 15 insertions(+), 36 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index ace4fef3ce3b..7bb7dd6cec11 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -4,7 +4,6 @@ use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::fmt; -use std::fmt::Write; use std::num::NonZeroU64; use std::rc::Rc; @@ -279,13 +278,10 @@ impl<'tcx> Stack { if let Some(call) = item.protector { if global.is_active(call) { if let Some(tag) = tag { - return Err(err_ub_experimental( - tag, - format!( - "not granting access to tag {:?} because incompatible item is protected: {:?}", - tag, item - ), - )); + throw_ub!(UbExperimental(format!( + "not granting access to tag {:?} because incompatible item is protected: {:?}", + tag, item + ))); } else { throw_ub!(UbExperimental(format!( "deallocating while item is protected: {:?}", @@ -303,12 +299,9 @@ impl<'tcx> Stack { // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. - let granting_idx = self.find_granting(access, tag).ok_or_else(|| { - err_ub_experimental( - tag, - format!("no item granting {} to tag {:?} found in borrow stack.", access, tag), - ) - })?; + let granting_idx = self.find_granting(access, tag).ok_or_else(|| err_ub!(UbExperimental( + format!("no item granting {} to tag {:?} found in borrow stack.", access, tag), + )))?; // Step 2: Remove incompatible items above them. Make sure we do not remove protected // items. Behavior differs for reads and writes. @@ -347,13 +340,10 @@ impl<'tcx> Stack { /// active protectors at all because we will remove all items. fn dealloc(&mut self, tag: Tag, global: &GlobalState) -> InterpResult<'tcx> { // Step 1: Find granting item. - self.find_granting(AccessKind::Write, tag).ok_or_else(|| { - err_ub_experimental( - tag,format!( - "no item granting write access for deallocation to tag {:?} found in borrow stack", - tag, - )) - })?; + self.find_granting(AccessKind::Write, tag).ok_or_else(|| err_ub!(UbExperimental(format!( + "no item granting write access for deallocation to tag {:?} found in borrow stack", + tag, + ))))?; // Step 2: Remove all items. Also checks for protectors. for item in self.borrows.drain(..).rev() { @@ -374,14 +364,10 @@ impl<'tcx> Stack { // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. let granting_idx = self.find_granting(access, derived_from) - .ok_or_else(|| - err_ub_experimental( - derived_from, - format!( - "trying to reborrow for {:?}, but parent tag {:?} does not have an appropriate item in the borrow stack", - new.perm, derived_from, - ), - ))?; + .ok_or_else(|| err_ub!(UbExperimental(format!( + "trying to reborrow for {:?}, but parent tag {:?} does not have an appropriate item in the borrow stack", + new.perm, derived_from, + ))))?; // Compute where to put the new item. // Either way, we ensure that we insert the new item in a way such that between @@ -647,10 +633,3 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } -fn err_ub_experimental(tag: Tag, mut msg: String) -> InterpErrorInfo<'static> { - if let Tag::Tagged(id) = tag { - // FIXME: do not add this message when the flag is already set - write!(msg, " Rerun with `-Zmiri-track-pointer-tag={}` for more information", id).unwrap(); - } - err_ub!(UbExperimental(msg)).into() -} From 90a8f2f6a300505c528cf5afe8ead9c31c9bbfca Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 8 Jan 2020 13:02:55 +0100 Subject: [PATCH 1465/5092] Make the non-halting diagnostic scheme independent of `InterpError` --- src/diagnostics.rs | 34 ++++++++++++++++++++++++++-------- src/eval.rs | 1 - src/lib.rs | 2 +- src/stacked_borrows.rs | 8 +------- 4 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 504863b13427..cf27a9c3762f 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -1,7 +1,12 @@ use rustc_mir::interpret::InterpErrorInfo; +use std::cell::RefCell; use crate::*; +pub enum NonHaltingDiagnostic { + PoppedTrackedPointerTag(Item), +} + pub fn report_err<'tcx, 'mir>( ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, mut e: InterpErrorInfo<'tcx>, @@ -12,8 +17,6 @@ pub fn report_err<'tcx, 'mir>( let info = info.downcast_ref::().expect("invalid MachineStop payload"); match info { TerminationInfo::Exit(code) => return Some(*code), - TerminationInfo::PoppedTrackedPointerTag(item) => - format!("popped tracked tag for item {:?}", item), TerminationInfo::Abort => format!("the evaluated program aborted execution"), } } @@ -25,11 +28,23 @@ pub fn report_err<'tcx, 'mir>( _ => e.to_string(), }; e.print_backtrace(); + report_msg(ecx, msg, true) +} + +pub fn report_msg<'tcx, 'mir>( + ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, + msg: String, + error: bool, +) -> Option { if let Some(frame) = ecx.stack().last() { let span = frame.current_source_info().unwrap().span; - let msg = format!("Miri evaluation error: {}", msg); - let mut err = ecx.tcx.sess.struct_span_err(span, msg.as_str()); + let mut err = if error { + let msg = format!("Miri evaluation error: {}", msg); + ecx.tcx.sess.struct_span_err(span, msg.as_str()) + } else { + ecx.tcx.sess.diagnostic().span_note_diag(span, msg.as_str()) + }; let frames = ecx.generate_stacktrace(None); err.span_label(span, msg); // We iterate with indices because we need to look at the next frame (the caller). @@ -61,12 +76,11 @@ pub fn report_err<'tcx, 'mir>( return None; } -use std::cell::RefCell; thread_local! { - static ECX: RefCell>> = RefCell::new(Vec::new()); + static ECX: RefCell> = RefCell::new(Vec::new()); } -pub fn register_err(e: InterpErrorInfo<'static>) { +pub fn register_err(e: NonHaltingDiagnostic) { ECX.with(|ecx| ecx.borrow_mut().push(e)); } @@ -76,7 +90,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); ECX.with(|ecx| { for e in ecx.borrow_mut().drain(..) { - report_err(this, e); + let msg = match e { + NonHaltingDiagnostic::PoppedTrackedPointerTag(item) => + format!("popped tracked tag for item {:?}", item), + }; + report_msg(this, msg, false); } }); } diff --git a/src/eval.rs b/src/eval.rs index 1e9332c9a32d..171f2627ad4a 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -33,7 +33,6 @@ pub struct MiriConfig { /// Details of premature program termination. pub enum TerminationInfo { Exit(i64), - PoppedTrackedPointerTag(Item), Abort, } diff --git a/src/lib.rs b/src/lib.rs index ae92a777d88e..60e521772156 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,7 +43,7 @@ pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::EvalContextExt as ShimsEvalContextExt; pub use crate::diagnostics::{ - register_err, report_err, EvalContextExt as DiagnosticsEvalContextExt, + register_err, report_err, EvalContextExt as DiagnosticsEvalContextExt, NonHaltingDiagnostic, }; pub use crate::eval::{create_ecx, eval_main, MiriConfig, TerminationInfo}; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 7bb7dd6cec11..a98c8e26c652 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -10,7 +10,6 @@ use std::rc::Rc; use rustc_hir::Mutability; use rustc::mir::RetagKind; use rustc::ty::{self, layout::Size}; -use rustc_mir::interpret::InterpError; use crate::*; @@ -267,12 +266,7 @@ impl<'tcx> Stack { fn check_protector(item: &Item, tag: Option, global: &GlobalState) -> InterpResult<'tcx> { if let Tag::Tagged(id) = item.tag { if Some(id) == global.tracked_pointer_tag { - register_err( - InterpError::MachineStop(Box::new(TerminationInfo::PoppedTrackedPointerTag( - item.clone(), - ))) - .into(), - ); + register_err(NonHaltingDiagnostic::PoppedTrackedPointerTag(item.clone())); } } if let Some(call) = item.protector { From c69ebaaed229679e54b70e82824ce82c31efa7fc Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 8 Jan 2020 13:20:39 +0100 Subject: [PATCH 1466/5092] Use names that actually represent what's going on --- src/diagnostics.rs | 12 ++++++------ src/eval.rs | 2 +- src/lib.rs | 2 +- src/stacked_borrows.rs | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index cf27a9c3762f..a4f40d51a3a8 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -77,19 +77,19 @@ pub fn report_msg<'tcx, 'mir>( } thread_local! { - static ECX: RefCell> = RefCell::new(Vec::new()); + static DIAGNOSTICS: RefCell> = RefCell::new(Vec::new()); } -pub fn register_err(e: NonHaltingDiagnostic) { - ECX.with(|ecx| ecx.borrow_mut().push(e)); +pub fn register_diagnostic(e: NonHaltingDiagnostic) { + DIAGNOSTICS.with(|diagnostics| diagnostics.borrow_mut().push(e)); } impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn process_errors(&self) { + fn process_diagnostics(&self) { let this = self.eval_context_ref(); - ECX.with(|ecx| { - for e in ecx.borrow_mut().drain(..) { + DIAGNOSTICS.with(|diagnostics| { + for e in diagnostics.borrow_mut().drain(..) { let msg = match e { NonHaltingDiagnostic::PoppedTrackedPointerTag(item) => format!("popped tracked tag for item {:?}", item), diff --git a/src/eval.rs b/src/eval.rs index 171f2627ad4a..e9e74db9b754 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -183,7 +183,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> // Perform the main execution. let res: InterpResult<'_, i64> = (|| { while ecx.step()? { - ecx.process_errors(); + ecx.process_diagnostics(); } // Read the return code pointer *before* we run TLS destructors, to assert // that it was written to by the time that `start` lang item returned. diff --git a/src/lib.rs b/src/lib.rs index 60e521772156..4d2411a6697d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,7 +43,7 @@ pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::EvalContextExt as ShimsEvalContextExt; pub use crate::diagnostics::{ - register_err, report_err, EvalContextExt as DiagnosticsEvalContextExt, NonHaltingDiagnostic, + register_diagnostic, report_err, EvalContextExt as DiagnosticsEvalContextExt, NonHaltingDiagnostic, }; pub use crate::eval::{create_ecx, eval_main, MiriConfig, TerminationInfo}; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index a98c8e26c652..60304503145f 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -266,7 +266,7 @@ impl<'tcx> Stack { fn check_protector(item: &Item, tag: Option, global: &GlobalState) -> InterpResult<'tcx> { if let Tag::Tagged(id) = item.tag { if Some(id) == global.tracked_pointer_tag { - register_err(NonHaltingDiagnostic::PoppedTrackedPointerTag(item.clone())); + register_diagnostic(NonHaltingDiagnostic::PoppedTrackedPointerTag(item.clone())); } } if let Some(call) = item.protector { From b1676a3e894efc0728bdb3d7ef598231eaca9a41 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 9 Jan 2020 11:20:13 +0100 Subject: [PATCH 1467/5092] test that unwrap gets us the right panic location --- rust-version | 2 +- tests/run-pass/panic/std-panic-locations.rs | 38 +++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 tests/run-pass/panic/std-panic-locations.rs diff --git a/rust-version b/rust-version index d39ff0adb268..d1b498871e87 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -ebbb2bf37aedaaa64dfaa52ba337ca6efb6b9093 +adc65725004c8aac16392fe4052c3e347181157d diff --git a/tests/run-pass/panic/std-panic-locations.rs b/tests/run-pass/panic/std-panic-locations.rs new file mode 100644 index 000000000000..baa1bc900f73 --- /dev/null +++ b/tests/run-pass/panic/std-panic-locations.rs @@ -0,0 +1,38 @@ +#![feature(option_expect_none, option_unwrap_none)] + +//! Test that panic locations for `#[track_caller]` functions in std have the correct +//! location reported. + +fn main() { + // inspect the `PanicInfo` we receive to ensure the right file is the source + std::panic::set_hook(Box::new(|info| { + let actual = info.location().unwrap(); + if actual.file() != file!() { + eprintln!("expected a location in the test file, found {:?}", actual); + panic!(); + } + })); + + fn assert_panicked(f: impl FnOnce() + std::panic::UnwindSafe) { + std::panic::catch_unwind(f).unwrap_err(); + } + + let nope: Option<()> = None; + assert_panicked(|| nope.unwrap()); + assert_panicked(|| nope.expect("")); + + let yep: Option<()> = Some(()); + assert_panicked(|| yep.unwrap_none()); + assert_panicked(|| yep.expect_none("")); + + let oops: Result<(), ()> = Err(()); + assert_panicked(|| oops.unwrap()); + assert_panicked(|| oops.expect("")); + + let fine: Result<(), ()> = Ok(()); + assert_panicked(|| fine.unwrap_err()); + assert_panicked(|| fine.expect_err("")); + + // Cleanup: reset to default hook. + drop(std::panic::take_hook()); +} From e9b4323048e8866871134bda9b27c8c6d4f0d844 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 9 Jan 2020 11:24:41 +0100 Subject: [PATCH 1468/5092] also make sure the hook actually gets called --- tests/run-pass/panic/std-panic-locations.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/panic/std-panic-locations.rs b/tests/run-pass/panic/std-panic-locations.rs index baa1bc900f73..ac2e8d5305df 100644 --- a/tests/run-pass/panic/std-panic-locations.rs +++ b/tests/run-pass/panic/std-panic-locations.rs @@ -1,11 +1,15 @@ #![feature(option_expect_none, option_unwrap_none)] - //! Test that panic locations for `#[track_caller]` functions in std have the correct //! location reported. +use std::sync::atomic::{AtomicUsize, Ordering}; + +static HOOK_COUNT: AtomicUsize = AtomicUsize::new(0); + fn main() { // inspect the `PanicInfo` we receive to ensure the right file is the source std::panic::set_hook(Box::new(|info| { + HOOK_COUNT.fetch_add(1, Ordering::Relaxed); let actual = info.location().unwrap(); if actual.file() != file!() { eprintln!("expected a location in the test file, found {:?}", actual); @@ -35,4 +39,6 @@ fn main() { // Cleanup: reset to default hook. drop(std::panic::take_hook()); + + assert_eq!(HOOK_COUNT.load(Ordering::Relaxed), 8); } From 833816dd359edd79a103a32039f8aa24f8e051d9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 9 Jan 2020 11:41:08 +0100 Subject: [PATCH 1469/5092] Unwind panicking does not currently work on Windows --- tests/run-pass/panic/std-panic-locations.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-pass/panic/std-panic-locations.rs b/tests/run-pass/panic/std-panic-locations.rs index ac2e8d5305df..d5f38fc2672e 100644 --- a/tests/run-pass/panic/std-panic-locations.rs +++ b/tests/run-pass/panic/std-panic-locations.rs @@ -1,3 +1,4 @@ +// ignore-windows: Unwind panicking does not currently work on Windows #![feature(option_expect_none, option_unwrap_none)] //! Test that panic locations for `#[track_caller]` functions in std have the correct //! location reported. From bfc7a7effd8836765fc8bcb28084b90b29d8906c Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 9 Jan 2020 12:38:58 +0100 Subject: [PATCH 1470/5092] Remove trailing newline --- src/stacked_borrows.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 60304503145f..1b7a118e637d 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -626,4 +626,3 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } } - From dbffbe52148ec0ef6cf5522b4171de40c93d4d65 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 9 Jan 2020 12:42:56 +0100 Subject: [PATCH 1471/5092] Document all the things --- src/diagnostics.rs | 9 ++++++++- src/eval.rs | 2 +- src/lib.rs | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index a4f40d51a3a8..e68dfad1b9fa 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -3,11 +3,13 @@ use std::cell::RefCell; use crate::*; +/// Miri specific diagnostics pub enum NonHaltingDiagnostic { PoppedTrackedPointerTag(Item), } -pub fn report_err<'tcx, 'mir>( +/// Emit a custom diagnostic without going through the miri-engine machinery +pub fn report_diagnostic<'tcx, 'mir>( ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, mut e: InterpErrorInfo<'tcx>, ) -> Option { @@ -31,6 +33,8 @@ pub fn report_err<'tcx, 'mir>( report_msg(ecx, msg, true) } +/// Report an error or note (depending on the `error` argument) at the current frame's current statement. +/// Also emits a full stacktrace of the interpreter stack. pub fn report_msg<'tcx, 'mir>( ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, msg: String, @@ -80,12 +84,15 @@ thread_local! { static DIAGNOSTICS: RefCell> = RefCell::new(Vec::new()); } +/// Schedule a diagnostic for emitting. This function works even if you have no `InterpCx` available. +/// The diagnostic will be emitted after the current interpreter step is finished. pub fn register_diagnostic(e: NonHaltingDiagnostic) { DIAGNOSTICS.with(|diagnostics| diagnostics.borrow_mut().push(e)); } impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + /// Emit all diagnostics that were registed with `register_diagnostics` fn process_diagnostics(&self) { let this = self.eval_context_ref(); DIAGNOSTICS.with(|diagnostics| { diff --git a/src/eval.rs b/src/eval.rs index e9e74db9b754..7a3945220f77 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -206,6 +206,6 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> } Some(return_code) } - Err(e) => report_err(&ecx, e), + Err(e) => report_diagnostic(&ecx, e), } } diff --git a/src/lib.rs b/src/lib.rs index 4d2411a6697d..880a14b98c80 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,7 +43,7 @@ pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::EvalContextExt as ShimsEvalContextExt; pub use crate::diagnostics::{ - register_diagnostic, report_err, EvalContextExt as DiagnosticsEvalContextExt, NonHaltingDiagnostic, + register_diagnostic, report_diagnostic, EvalContextExt as DiagnosticsEvalContextExt, NonHaltingDiagnostic, }; pub use crate::eval::{create_ecx, eval_main, MiriConfig, TerminationInfo}; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; From 0b5a30515e6977e4a9deaefa1c0ff243afbd6ef6 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 10 Jan 2020 12:01:05 -0500 Subject: [PATCH 1472/5092] small corrections --- src/shims/fs.rs | 2 +- tests/run-pass/fs.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 3927f0e64919..57a88f2ccaae 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -337,7 +337,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); if this.tcx.sess.target.target.target_os.to_lowercase() != "macos" { - throw_unsup_format!("The `stat` shim is only available for `macos` targets.") + throw_unsup_format!("The `stat` and `lstat` shims are only available for `macos` targets.") } let path_scalar = this.read_scalar(path_op)?.not_undef()?; diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 90b5dcfb5fa6..81c56e4aafc7 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -22,8 +22,8 @@ fn main() { let symlink_path = tmp.join("miri_test_fs_symlink.txt"); let bytes = b"Hello, World!\n"; // Clean the paths for robustness. - remove_file(&path).unwrap_or(()); - remove_file(&symlink_path).unwrap_or(()); + remove_file(&path).ok(); + remove_file(&symlink_path).ok(); // Test creating, writing and closing a file (closing is tested when `file` is dropped). let mut file = File::create(&path).unwrap(); From 5e71f2debc4df0bd25d29329cd21a7c55c5dc3ba Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 10 Jan 2020 12:18:24 -0500 Subject: [PATCH 1473/5092] fix windows symlink creation --- src/shims/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 57a88f2ccaae..b67504261672 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -292,7 +292,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if src.is_dir() { fs::symlink_dir(src, dst) } else { - fs::symlink(src, dst) + fs::symlink_file(src, dst) } } From 4fa2f4e10fdc05cd899f8267c4073ed8b4195845 Mon Sep 17 00:00:00 2001 From: jethrogb Date: Mon, 13 Jan 2020 20:06:58 -0800 Subject: [PATCH 1474/5092] Update .gitattributes See https://github.com/rust-lang/rust/pull/57858 --- .gitattributes | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitattributes b/.gitattributes index 6313b56c5784..2742e4d1d5b9 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,6 @@ * text=auto eol=lf + +# Older git versions try to fix line endings on images, this prevents it. +*.png binary +*.jpg binary +*.ico binary From 23c74449a2793da00a41d1abf35cfe1c99f660a4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 Jan 2020 19:27:21 +0100 Subject: [PATCH 1475/5092] rustup --- rust-version | 2 +- src/helpers.rs | 4 ++-- src/shims/intrinsics.rs | 4 ++-- src/shims/panic.rs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index d1b498871e87..09255212910c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -adc65725004c8aac16392fe4052c3e347181157d +31dd4f4acbcbdb02b0745d2136399ed664a28050 diff --git a/src/helpers.rs b/src/helpers.rs index ff9a16a02456..fba933d278d2 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -76,7 +76,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Get the `Place` for a local fn local_place(&mut self, local: mir::Local) -> InterpResult<'tcx, PlaceTy<'tcx, Tag>> { let this = self.eval_context_mut(); - let place = mir::Place { base: mir::PlaceBase::Local(local), projection: List::empty() }; + let place = mir::Place { local: local, projection: List::empty() }; this.eval_place(&place) } @@ -349,7 +349,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx for &imm in imms { this.write_immediate_to_mplace( *imm, - place.offset(offset, None, imm.layout, &*this.tcx)?, + place.offset(offset, MemPlaceMeta::None, imm.layout, &*this.tcx)?, )?; offset += imm.layout.size; } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index a7aec53c37de..151edfda4318 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -409,7 +409,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => { // Do it in memory let mplace = this.force_allocation(dest)?; - mplace.meta.unwrap_none(); // must be sized + assert!(!mplace.layout.is_unsized()); this.memory.write_bytes( mplace.ptr, iter::repeat(0u8).take(dest.layout.size.bytes() as usize), @@ -574,7 +574,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => { // Do it in memory let mplace = this.force_allocation(dest)?; - mplace.meta.unwrap_none(); + assert!(!mplace.layout.is_unsized()); let ptr = mplace.ptr.assert_ptr(); // We know the return place is in-bounds this.memory.get_raw_mut(ptr.alloc_id)?.mark_definedness( diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 950a23aa59ca..d676f0464657 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -132,7 +132,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let payload = this.machine.panic_payload.take().unwrap(); let payload = this.ref_to_mplace(payload)?; let payload_data_place = payload.ptr; - let payload_vtable_place = payload.meta.expect("Expected fat pointer"); + let payload_vtable_place = payload.meta.unwrap_meta(); this.write_scalar(payload_data_place, unwind_data.data_place.into())?; this.write_scalar(payload_vtable_place, unwind_data.vtable_place.into())?; From 88f01027534e6dceb2b977158bd97bcad5c89a01 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 Jan 2020 19:35:41 +0100 Subject: [PATCH 1476/5092] rustup more --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 09255212910c..5927df6c9519 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -31dd4f4acbcbdb02b0745d2136399ed664a28050 +6d0bb91bcba33a70fae4b0c663fb4403ed78f071 From 0acc30956166b81c75fd2c8db250eabce6babf7d Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Sat, 18 Jan 2020 16:21:30 +0100 Subject: [PATCH 1477/5092] Document miri can only be installed on nightly This updates the installation instructions to point out that miri is only available on nightly, and encodes this assumption into the installation instructions. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bbf26ff6f71e..cf18e6a0670b 100644 --- a/README.md +++ b/README.md @@ -51,10 +51,10 @@ program, and cannot run all programs: ## Using Miri -Install Miri via `rustup`: +Install Miri on Rust nightly via `rustup`: ```sh -rustup component add miri +rustup +nightly component add miri ``` If `rustup` says the `miri` component is unavailable, that's because not all From b2303a7da170f8b9a6efa0b2c9149c103cde6990 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 19 Jan 2020 10:03:18 -0600 Subject: [PATCH 1478/5092] slice_patterns is stable now --- rust-version | 2 +- tests/run-pass/issue-15080.rs | 2 -- tests/run-pass/issue-17877.rs | 2 -- tests/run-pass/subslice_array.rs | 2 -- tests/run-pass/vec-matching-fold.rs | 2 -- 5 files changed, 1 insertion(+), 9 deletions(-) diff --git a/rust-version b/rust-version index 5927df6c9519..d6464fa872e3 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6d0bb91bcba33a70fae4b0c663fb4403ed78f071 +6250d56355d72264ece721e8d0dc95b16a6824b1 diff --git a/tests/run-pass/issue-15080.rs b/tests/run-pass/issue-15080.rs index 7f19759b910a..2008e6e157db 100644 --- a/tests/run-pass/issue-15080.rs +++ b/tests/run-pass/issue-15080.rs @@ -1,5 +1,3 @@ -#![feature(slice_patterns)] - fn main() { let mut x: &[_] = &[1, 2, 3, 4]; diff --git a/tests/run-pass/issue-17877.rs b/tests/run-pass/issue-17877.rs index d2806e5ed350..fa24ab9f4aae 100644 --- a/tests/run-pass/issue-17877.rs +++ b/tests/run-pass/issue-17877.rs @@ -1,5 +1,3 @@ -#![feature(slice_patterns)] - fn main() { assert_eq!(match [0u8; 16*1024] { _ => 42_usize, diff --git a/tests/run-pass/subslice_array.rs b/tests/run-pass/subslice_array.rs index df3631c647fb..9b6b12d748ad 100644 --- a/tests/run-pass/subslice_array.rs +++ b/tests/run-pass/subslice_array.rs @@ -1,5 +1,3 @@ -#![feature(slice_patterns)] - fn bar(a: &'static str, b: &'static str) -> [&'static str; 4] { [a, b, b, a] } diff --git a/tests/run-pass/vec-matching-fold.rs b/tests/run-pass/vec-matching-fold.rs index 54fbb702924f..8fd36253b57f 100644 --- a/tests/run-pass/vec-matching-fold.rs +++ b/tests/run-pass/vec-matching-fold.rs @@ -1,5 +1,3 @@ -#![feature(slice_patterns)] - use std::fmt::Debug; fn foldl(values: &[T], From 625fa742bca46f992c347c438658d6b747e03c51 Mon Sep 17 00:00:00 2001 From: David Cook Date: Fri, 24 Jan 2020 19:02:58 -0600 Subject: [PATCH 1479/5092] Shim intrinsics::atomic_singlethreadfence, etc. --- src/shims/intrinsics.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 151edfda4318..04e724ff1d34 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -113,6 +113,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "atomic_fence_rel" | "atomic_fence_acqrel" | "atomic_fence" + | "atomic_singlethreadfence_acq" + | "atomic_singlethreadfence_rel" + | "atomic_singlethreadfence_acqrel" + | "atomic_singlethreadfence" => { // we are inherently singlethreaded and singlecored, this is a nop } From 9265e0cd5e4e9677ef5bdcea7a781ae7d064b4e2 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 25 Jan 2020 13:48:26 -0600 Subject: [PATCH 1480/5092] Add compiler fences to test --- tests/run-pass/atomic.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/atomic.rs b/tests/run-pass/atomic.rs index a9dd29bd62bf..b03a8c8901e1 100644 --- a/tests/run-pass/atomic.rs +++ b/tests/run-pass/atomic.rs @@ -1,4 +1,4 @@ -use std::sync::atomic::{fence, AtomicBool, AtomicIsize, AtomicU64, Ordering::*}; +use std::sync::atomic::{compiler_fence, fence, AtomicBool, AtomicIsize, AtomicU64, Ordering::*}; fn main() { atomic_bool(); @@ -70,4 +70,8 @@ fn atomic_fences() { fence(Release); fence(Acquire); fence(AcqRel); + compiler_fence(SeqCst); + compiler_fence(Release); + compiler_fence(Acquire); + compiler_fence(AcqRel); } From d94b88ef9837569d0efeb4725d03475e2b816e03 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 25 Jan 2020 22:21:33 -0600 Subject: [PATCH 1481/5092] Add support for AT_EMPTY_PATH to statx shim --- src/shims/fs.rs | 41 +++++++++++++++++++++++++++++++++++++---- tests/run-pass/fs.rs | 2 ++ 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 8a7cf9d31c0b..0875a3314c80 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -345,7 +345,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.deref_operand(buf_op)?; - let metadata = match FileMetadata::new(this, path, follow_symlink)? { + let metadata = match FileMetadata::from_path(this, path, follow_symlink)? { Some(metadata) => metadata, None => return Ok(-1), }; @@ -454,6 +454,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.read_scalar(flags_op)?.to_machine_isize(&*this.tcx)?.try_into().map_err(|e| { err_unsup_format!("Failed to convert pointer sized operand to integer: {}", e) })?; + let empty_path_flag = flags & this.eval_libc("AT_EMPTY_PATH")?.to_i32()? != 0; // `dirfd` should be a `c_int` but the `syscall` function provides an `isize`. let dirfd: i32 = this.read_scalar(dirfd_op)?.to_machine_isize(&*this.tcx)?.try_into().map_err(|e| { @@ -463,7 +464,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // to `dirfd` when the latter is `AT_FDCWD`. The behavior of `statx` with a relative path // and a directory file descriptor other than `AT_FDCWD` is specified but it cannot be // tested from `libstd`. If you found this error, please open an issue reporting it. - if !(path.is_absolute() || dirfd == this.eval_libc_i32("AT_FDCWD")?) { + if !( + path.is_absolute() || + dirfd == this.eval_libc_i32("AT_FDCWD")? || + (path.as_os_str().is_empty() && empty_path_flag) + ) { throw_unsup_format!( "Using statx with a relative path and a file descriptor different from `AT_FDCWD` is not supported" ) @@ -480,7 +485,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // symbolic links. let follow_symlink = flags & this.eval_libc("AT_SYMLINK_NOFOLLOW")?.to_i32()? == 0; - let metadata = match FileMetadata::new(this, path, follow_symlink)? { + // If the path is empty, and the AT_EMPTY_PATH flag is set, we query the open file + // represented by dirfd, whether it's a directory or otherwise. + let metadata = if path.as_os_str().is_empty() && empty_path_flag { + FileMetadata::from_fd(this, dirfd)? + } else { + FileMetadata::from_path(this, path, follow_symlink)? + }; + let metadata = match metadata { Some(metadata) => metadata, None => return Ok(-1), }; @@ -589,7 +601,7 @@ struct FileMetadata { } impl FileMetadata { - fn new<'tcx, 'mir>( + fn from_path<'tcx, 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, path: PathBuf, follow_symlink: bool @@ -600,6 +612,27 @@ impl FileMetadata { std::fs::symlink_metadata(path) }; + FileMetadata::from_meta(ecx, metadata) + } + + fn from_fd<'tcx, 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + fd: i32, + ) -> InterpResult<'tcx, Option> { + let option = ecx.machine.file_handler.handles.get(&fd); + let handle = match option { + Some(handle) => handle, + None => return ecx.handle_not_found().map(|_: i32| None), + }; + let metadata = handle.file.metadata(); + + FileMetadata::from_meta(ecx, metadata) + } + + fn from_meta<'tcx, 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + metadata: Result, + ) -> InterpResult<'tcx, Option> { let metadata = match metadata { Ok(metadata) => metadata, Err(e) => { diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 81c56e4aafc7..cc8f6e01f323 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -29,8 +29,10 @@ fn main() { let mut file = File::create(&path).unwrap(); // Writing 0 bytes should not change the file contents. file.write(&mut []).unwrap(); + assert_eq!(file.metadata().unwrap().len(), 0); file.write(bytes).unwrap(); + assert_eq!(file.metadata().unwrap().len(), bytes.len() as u64); // Test opening, reading and closing a file. let mut file = File::open(&path).unwrap(); let mut contents = Vec::new(); From c5797130d7a1766b412cc30c8346ed646ffcc2d3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jan 2020 11:06:13 -0600 Subject: [PATCH 1482/5092] bump rustc --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index d6464fa872e3..e7e27291d553 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6250d56355d72264ece721e8d0dc95b16a6824b1 +698fcd38fa9548e64a2092ff48c9d15ceb57d40c From 90f3aae2dead72d502ec4e25a659efb159186f19 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 26 Jan 2020 11:58:08 -0600 Subject: [PATCH 1483/5092] Add fstat shim for OSX --- src/shims/foreign_items.rs | 5 ++ src/shims/fs.rs | 140 ++++++++++++++++++++++--------------- 2 files changed, 89 insertions(+), 56 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index deeb37da44a3..381b43c39ec2 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -509,6 +509,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "fstat$INODE64" => { + let result = this.fstat(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + "clock_gettime" => { let result = this.clock_gettime(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 0875a3314c80..d054dd47729b 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -328,6 +328,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.stat_or_lstat(false, path_op, buf_op) } + fn fstat( + &mut self, + fd_op: OpTy<'tcx, Tag>, + buf_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.check_no_isolation("fstat")?; + + if this.tcx.sess.target.target.target_os.to_lowercase() != "macos" { + throw_unsup_format!("The `fstat` shim is only available for `macos` targets.") + } + + let fd = this.read_scalar(fd_op)?.to_i32()?; + + let metadata = match FileMetadata::from_fd(this, fd)? { + Some(metadata) => metadata, + None => return Ok(-1), + }; + stat_write_buf(this, metadata, buf_op) + } + fn stat_or_lstat( &mut self, follow_symlink: bool, @@ -343,66 +365,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let path_scalar = this.read_scalar(path_op)?.not_undef()?; let path: PathBuf = this.read_os_str_from_c_str(path_scalar)?.into(); - let buf = this.deref_operand(buf_op)?; - let metadata = match FileMetadata::from_path(this, path, follow_symlink)? { Some(metadata) => metadata, None => return Ok(-1), }; - - let mode: u16 = metadata.mode.to_u16()?; - - let (access_sec, access_nsec) = metadata.accessed.unwrap_or((0, 0)); - let (created_sec, created_nsec) = metadata.created.unwrap_or((0, 0)); - let (modified_sec, modified_nsec) = metadata.modified.unwrap_or((0, 0)); - - let dev_t_layout = this.libc_ty_layout("dev_t")?; - let mode_t_layout = this.libc_ty_layout("mode_t")?; - let nlink_t_layout = this.libc_ty_layout("nlink_t")?; - let ino_t_layout = this.libc_ty_layout("ino_t")?; - let uid_t_layout = this.libc_ty_layout("uid_t")?; - let gid_t_layout = this.libc_ty_layout("gid_t")?; - let time_t_layout = this.libc_ty_layout("time_t")?; - let long_layout = this.libc_ty_layout("c_long")?; - let off_t_layout = this.libc_ty_layout("off_t")?; - let blkcnt_t_layout = this.libc_ty_layout("blkcnt_t")?; - let blksize_t_layout = this.libc_ty_layout("blksize_t")?; - let uint32_t_layout = this.libc_ty_layout("uint32_t")?; - - // We need to add 32 bits of padding after `st_rdev` if we are on a 64-bit platform. - let pad_layout = if this.tcx.sess.target.ptr_width == 64 { - uint32_t_layout - } else { - this.layout_of(this.tcx.mk_unit())? - }; - - let imms = [ - immty_from_uint_checked(0u128, dev_t_layout)?, // st_dev - immty_from_uint_checked(mode, mode_t_layout)?, // st_mode - immty_from_uint_checked(0u128, nlink_t_layout)?, // st_nlink - immty_from_uint_checked(0u128, ino_t_layout)?, // st_ino - immty_from_uint_checked(0u128, uid_t_layout)?, // st_uid - immty_from_uint_checked(0u128, gid_t_layout)?, // st_gid - immty_from_uint_checked(0u128, dev_t_layout)?, // st_rdev - immty_from_uint_checked(0u128, pad_layout)?, // padding for 64-bit targets - immty_from_uint_checked(access_sec, time_t_layout)?, // st_atime - immty_from_uint_checked(access_nsec, long_layout)?, // st_atime_nsec - immty_from_uint_checked(modified_sec, time_t_layout)?, // st_mtime - immty_from_uint_checked(modified_nsec, long_layout)?, // st_mtime_nsec - immty_from_uint_checked(0u128, time_t_layout)?, // st_ctime - immty_from_uint_checked(0u128, long_layout)?, // st_ctime_nsec - immty_from_uint_checked(created_sec, time_t_layout)?, // st_birthtime - immty_from_uint_checked(created_nsec, long_layout)?, // st_birthtime_nsec - immty_from_uint_checked(metadata.size, off_t_layout)?, // st_size - immty_from_uint_checked(0u128, blkcnt_t_layout)?, // st_blocks - immty_from_uint_checked(0u128, blksize_t_layout)?, // st_blksize - immty_from_uint_checked(0u128, uint32_t_layout)?, // st_flags - immty_from_uint_checked(0u128, uint32_t_layout)?, // st_gen - ]; - - this.write_packed_immediates(&buf, &imms)?; - - Ok(0) + stat_write_buf(this, metadata, buf_op) } fn statx( @@ -663,3 +630,64 @@ impl FileMetadata { Ok(Some(FileMetadata { mode, size, created, accessed, modified })) } } + +fn stat_write_buf<'tcx, 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + metadata: FileMetadata, + buf_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, i32> { + let mode: u16 = metadata.mode.to_u16()?; + + let (access_sec, access_nsec) = metadata.accessed.unwrap_or((0, 0)); + let (created_sec, created_nsec) = metadata.created.unwrap_or((0, 0)); + let (modified_sec, modified_nsec) = metadata.modified.unwrap_or((0, 0)); + + let dev_t_layout = ecx.libc_ty_layout("dev_t")?; + let mode_t_layout = ecx.libc_ty_layout("mode_t")?; + let nlink_t_layout = ecx.libc_ty_layout("nlink_t")?; + let ino_t_layout = ecx.libc_ty_layout("ino_t")?; + let uid_t_layout = ecx.libc_ty_layout("uid_t")?; + let gid_t_layout = ecx.libc_ty_layout("gid_t")?; + let time_t_layout = ecx.libc_ty_layout("time_t")?; + let long_layout = ecx.libc_ty_layout("c_long")?; + let off_t_layout = ecx.libc_ty_layout("off_t")?; + let blkcnt_t_layout = ecx.libc_ty_layout("blkcnt_t")?; + let blksize_t_layout = ecx.libc_ty_layout("blksize_t")?; + let uint32_t_layout = ecx.libc_ty_layout("uint32_t")?; + + // We need to add 32 bits of padding after `st_rdev` if we are on a 64-bit platform. + let pad_layout = if ecx.tcx.sess.target.ptr_width == 64 { + uint32_t_layout + } else { + ecx.layout_of(ecx.tcx.mk_unit())? + }; + + let imms = [ + immty_from_uint_checked(0u128, dev_t_layout)?, // st_dev + immty_from_uint_checked(mode, mode_t_layout)?, // st_mode + immty_from_uint_checked(0u128, nlink_t_layout)?, // st_nlink + immty_from_uint_checked(0u128, ino_t_layout)?, // st_ino + immty_from_uint_checked(0u128, uid_t_layout)?, // st_uid + immty_from_uint_checked(0u128, gid_t_layout)?, // st_gid + immty_from_uint_checked(0u128, dev_t_layout)?, // st_rdev + immty_from_uint_checked(0u128, pad_layout)?, // padding for 64-bit targets + immty_from_uint_checked(access_sec, time_t_layout)?, // st_atime + immty_from_uint_checked(access_nsec, long_layout)?, // st_atime_nsec + immty_from_uint_checked(modified_sec, time_t_layout)?, // st_mtime + immty_from_uint_checked(modified_nsec, long_layout)?, // st_mtime_nsec + immty_from_uint_checked(0u128, time_t_layout)?, // st_ctime + immty_from_uint_checked(0u128, long_layout)?, // st_ctime_nsec + immty_from_uint_checked(created_sec, time_t_layout)?, // st_birthtime + immty_from_uint_checked(created_nsec, long_layout)?, // st_birthtime_nsec + immty_from_uint_checked(metadata.size, off_t_layout)?, // st_size + immty_from_uint_checked(0u128, blkcnt_t_layout)?, // st_blocks + immty_from_uint_checked(0u128, blksize_t_layout)?, // st_blksize + immty_from_uint_checked(0u128, uint32_t_layout)?, // st_flags + immty_from_uint_checked(0u128, uint32_t_layout)?, // st_gen + ]; + + let buf = ecx.deref_operand(buf_op)?; + ecx.write_packed_immediates(&buf, &imms)?; + + Ok(0) +} From 03b5d95cffd587224fc16b4cafca25e0e52df337 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 26 Jan 2020 12:36:36 -0600 Subject: [PATCH 1484/5092] Add shim for lseek64 --- src/shims/foreign_items.rs | 5 +++++ src/shims/fs.rs | 34 +++++++++++++++++++++++++++++++++- tests/run-pass/fs.rs | 8 +++++++- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index deeb37da44a3..9d025b2b7b24 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -489,6 +489,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "lseek64" => { + let result = this.lseek64(args[0], args[1], args[2])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + "unlink" => { let result = this.unlink(args[0])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 8a7cf9d31c0b..4cfff9446b85 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; use std::fs::{remove_file, File, OpenOptions}; -use std::io::{Read, Write}; +use std::io::{Read, Seek, SeekFrom, Write}; use std::path::PathBuf; use std::time::SystemTime; @@ -264,6 +264,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + fn lseek64( + &mut self, + fd_op: OpTy<'tcx, Tag>, + offset_op: OpTy<'tcx, Tag>, + whence_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i64> { + let this = self.eval_context_mut(); + + this.check_no_isolation("lseek64")?; + + let fd = this.read_scalar(fd_op)?.to_i32()?; + let offset = this.read_scalar(offset_op)?.to_i64()?; + let whence = this.read_scalar(whence_op)?.to_i32()?; + + let seek_from = if whence == this.eval_libc_i32("SEEK_SET")? { + SeekFrom::Start(offset as u64) + } else if whence == this.eval_libc_i32("SEEK_CUR")? { + SeekFrom::Current(offset) + } else if whence == this.eval_libc_i32("SEEK_END")? { + SeekFrom::End(offset) + } else { + throw_unsup_format!("Unsupported whence argument to lseek64: {}", whence) + }; + + if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { + let result = handle.file.seek(seek_from).map(|offset| offset as i64); + this.try_unwrap_io_result(result) + } else { + this.handle_not_found() + } + } + fn unlink(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 81c56e4aafc7..4da67369aef8 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -2,7 +2,7 @@ // compile-flags: -Zmiri-disable-isolation use std::fs::{File, remove_file}; -use std::io::{Read, Write, ErrorKind, Result}; +use std::io::{Read, Write, ErrorKind, Result, Seek, SeekFrom}; use std::path::{PathBuf, Path}; fn test_metadata(bytes: &[u8], path: &Path) -> Result<()> { @@ -40,6 +40,12 @@ fn main() { file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); + // Test that seeking to the beginning and reading until EOF gets the text again. + file.seek(SeekFrom::Start(0)).unwrap(); + let mut contents = Vec::new(); + file.read_to_end(&mut contents).unwrap(); + assert_eq!(bytes, contents.as_slice()); + // Test that metadata of an absolute path is correct. test_metadata(bytes, &path).unwrap(); // Test that metadata of a relative path is correct. From 01b5e8260e3a5e17ee4ce83a88fc07aeac774625 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 26 Jan 2020 15:10:01 -0600 Subject: [PATCH 1485/5092] Add no-op shim for posix_fadvise --- src/shims/foreign_items.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index deeb37da44a3..7bd85a4e94d4 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -780,6 +780,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } + "posix_fadvise" => { + // fadvise is only informational, we can ignore it. + this.write_null(dest)?; + } + "mmap" => { // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. let addr = this.read_scalar(args[0])?.not_undef()?; From 0d0902a1e131f57995e705c362b46d59bbf63234 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 26 Jan 2020 18:07:31 -0600 Subject: [PATCH 1486/5092] Apply shim to lseek too (for macOS) --- src/shims/foreign_items.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 9d025b2b7b24..a6c1a31b4feb 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -489,7 +489,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "lseek64" => { + | "lseek64" + | "lseek" + => { let result = this.lseek64(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } From 4e42e774834683570b1c0ca59ce5bb1a11119fb5 Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 27 Jan 2020 06:28:45 -0600 Subject: [PATCH 1487/5092] Add test for posix_fadvise --- tests/run-pass/fs.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 81c56e4aafc7..43f394bd3274 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -1,8 +1,13 @@ // ignore-windows: File handling is not implemented yet // compile-flags: -Zmiri-disable-isolation +#![feature(rustc_private)] + +extern crate libc; + use std::fs::{File, remove_file}; use std::io::{Read, Write, ErrorKind, Result}; +use std::os::unix::io::AsRawFd; use std::path::{PathBuf, Path}; fn test_metadata(bytes: &[u8], path: &Path) -> Result<()> { @@ -40,6 +45,16 @@ fn main() { file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); + // Test calling posix_fadvise on the file. + unsafe { + libc::posix_fadvise( + file.as_raw_fd(), + 0, + bytes.len() as i64, + libc::POSIX_FADV_DONTNEED, + ); + } + // Test that metadata of an absolute path is correct. test_metadata(bytes, &path).unwrap(); // Test that metadata of a relative path is correct. From 9f6df672381bdb0077a91ed785c80fef78eb8def Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 28 Jan 2020 22:55:07 +0100 Subject: [PATCH 1488/5092] test track_caller with fn ptrs --- tests/run-pass/track-caller-attribute.rs | 30 ++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/tests/run-pass/track-caller-attribute.rs b/tests/run-pass/track-caller-attribute.rs index 68a0c95b44db..f6797c24ebec 100644 --- a/tests/run-pass/track-caller-attribute.rs +++ b/tests/run-pass/track-caller-attribute.rs @@ -19,15 +19,33 @@ macro_rules! caller_location_from_macro { () => (core::panic::Location::caller()); } +fn test_fn_ptr() { + fn pass_to_ptr_call(f: fn(T), x: T) { + f(x); + } + + #[track_caller] + fn tracked_unit(_: ()) { + let expected_line = line!() - 1; + let location = std::panic::Location::caller(); + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), expected_line, "call shims report location as fn definition"); + } + + pass_to_ptr_call(tracked_unit, ()); +} + fn main() { let location = Location::caller(); + let expected_line = line!() - 1; assert_eq!(location.file(), file!()); - assert_eq!(location.line(), 23); + assert_eq!(location.line(), expected_line); assert_eq!(location.column(), 20); let tracked = tracked(); + let expected_line = line!() - 1; assert_eq!(tracked.file(), file!()); - assert_eq!(tracked.line(), 28); + assert_eq!(tracked.line(), expected_line); assert_eq!(tracked.column(), 19); let nested = nested_intrinsic(); @@ -43,12 +61,16 @@ fn main() { // `Location::caller()` in a macro should behave similarly to `file!` and `line!`, // i.e. point to where the macro was invoked, instead of the macro itself. let inmacro = caller_location_from_macro!(); + let expected_line = line!() - 1; assert_eq!(inmacro.file(), file!()); - assert_eq!(inmacro.line(), 45); + assert_eq!(inmacro.line(), expected_line); assert_eq!(inmacro.column(), 19); let intrinsic = core::intrinsics::caller_location(); + let expected_line = line!() - 1; assert_eq!(intrinsic.file(), file!()); - assert_eq!(intrinsic.line(), 50); + assert_eq!(intrinsic.line(), expected_line); assert_eq!(intrinsic.column(), 21); + + test_fn_ptr(); } From b2d404d19af4949c5159ec6353984413776b925b Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 28 Jan 2020 18:59:49 -0600 Subject: [PATCH 1489/5092] Move posix_fadvise test to new libc test file --- tests/run-pass/fs.rs | 15 --------------- tests/run-pass/libc.rs | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 15 deletions(-) create mode 100644 tests/run-pass/libc.rs diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 43f394bd3274..81c56e4aafc7 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -1,13 +1,8 @@ // ignore-windows: File handling is not implemented yet // compile-flags: -Zmiri-disable-isolation -#![feature(rustc_private)] - -extern crate libc; - use std::fs::{File, remove_file}; use std::io::{Read, Write, ErrorKind, Result}; -use std::os::unix::io::AsRawFd; use std::path::{PathBuf, Path}; fn test_metadata(bytes: &[u8], path: &Path) -> Result<()> { @@ -45,16 +40,6 @@ fn main() { file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); - // Test calling posix_fadvise on the file. - unsafe { - libc::posix_fadvise( - file.as_raw_fd(), - 0, - bytes.len() as i64, - libc::POSIX_FADV_DONTNEED, - ); - } - // Test that metadata of an absolute path is correct. test_metadata(bytes, &path).unwrap(); // Test that metadata of a relative path is correct. diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs new file mode 100644 index 000000000000..8ba97e2e4356 --- /dev/null +++ b/tests/run-pass/libc.rs @@ -0,0 +1,35 @@ +// ignore-windows: No libc on Windows +// compile-flags: -Zmiri-disable-isolation + +#![feature(rustc_private)] + +extern crate libc; + +use std::env::temp_dir; +use std::fs::{File, remove_file}; +use std::io::Write; +use std::os::unix::io::AsRawFd; + +fn main() { + let path = temp_dir().join("miri_test_libc.txt"); + // Cleanup before test + remove_file(&path).ok(); + + // Set up an open file + let mut file = File::create(&path).unwrap(); + let bytes = b"Hello, World!\n"; + file.write(bytes).unwrap(); + + // Test calling posix_fadvise on a file. + let result = unsafe { + libc::posix_fadvise( + file.as_raw_fd(), + 0, + bytes.len() as i64, + libc::POSIX_FADV_DONTNEED, + ) + }; + drop(file); + remove_file(&path).unwrap(); + assert_eq!(result, 0); +} From 2a2dde1494cec11a885e899d737904f920bd183b Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 28 Jan 2020 19:04:16 -0600 Subject: [PATCH 1490/5092] Try fixing test on i686-unknown-linux-gnu --- tests/run-pass/libc.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index 8ba97e2e4356..25f96b472b23 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -5,6 +5,7 @@ extern crate libc; +use std::convert::TryInto; use std::env::temp_dir; use std::fs::{File, remove_file}; use std::io::Write; @@ -25,7 +26,7 @@ fn main() { libc::posix_fadvise( file.as_raw_fd(), 0, - bytes.len() as i64, + bytes.len().try_into().unwrap(), libc::POSIX_FADV_DONTNEED, ) }; From d8da3968d67b7ccea4262fe1d2b296e7ed3434fa Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 28 Jan 2020 19:43:55 -0600 Subject: [PATCH 1491/5092] Change function name, comments, and error message --- src/shims/fs.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index d054dd47729b..c5017dc85bbd 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -347,7 +347,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(metadata) => metadata, None => return Ok(-1), }; - stat_write_buf(this, metadata, buf_op) + stat_macos_write_buf(this, metadata, buf_op) } fn stat_or_lstat( @@ -369,7 +369,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(metadata) => metadata, None => return Ok(-1), }; - stat_write_buf(this, metadata, buf_op) + stat_macos_write_buf(this, metadata, buf_op) } fn statx( @@ -427,17 +427,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.read_scalar(dirfd_op)?.to_machine_isize(&*this.tcx)?.try_into().map_err(|e| { err_unsup_format!("Failed to convert pointer sized operand to integer: {}", e) })?; - // we only support interpreting `path` as an absolute directory or as a directory relative - // to `dirfd` when the latter is `AT_FDCWD`. The behavior of `statx` with a relative path - // and a directory file descriptor other than `AT_FDCWD` is specified but it cannot be - // tested from `libstd`. If you found this error, please open an issue reporting it. + // We only support: + // * interpreting `path` as an absolute directory, + // * interpreting `path` as a path relative to `dirfd` when the latter is `AT_FDCWD`, or + // * interpreting `dirfd` as any file descriptor when `path` is empty and AT_EMPTY_PATH is + // set. + // The behavior of `statx` with a relative path and a directory file descriptor other than + // `AT_FDCWD` is specified but it cannot be tested from `libstd`. If you found this error, + // please open an issue reporting it. if !( path.is_absolute() || dirfd == this.eval_libc_i32("AT_FDCWD")? || (path.as_os_str().is_empty() && empty_path_flag) ) { throw_unsup_format!( - "Using statx with a relative path and a file descriptor different from `AT_FDCWD` is not supported" + "Using statx is only supported with absolute paths, relative paths with the file \ + descriptor `AT_FDCWD`, and empty paths with the `AT_EMPTY_PATH` flag set and any \ + file descriptor" ) } @@ -631,7 +637,7 @@ impl FileMetadata { } } -fn stat_write_buf<'tcx, 'mir>( +fn stat_macos_write_buf<'tcx, 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, metadata: FileMetadata, buf_op: OpTy<'tcx, Tag>, From a39a5f8189f925bf6a3131af28801903a8143fd2 Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 28 Jan 2020 19:57:56 -0600 Subject: [PATCH 1492/5092] Disable posix_fadvise test on macOS, not in libc --- tests/run-pass/libc.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index 25f96b472b23..eb23cd16b757 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -5,13 +5,14 @@ extern crate libc; -use std::convert::TryInto; -use std::env::temp_dir; -use std::fs::{File, remove_file}; -use std::io::Write; -use std::os::unix::io::AsRawFd; +#[cfg(not(target_os = "macos"))] +fn test_posix_fadvise() { + use std::convert::TryInto; + use std::env::temp_dir; + use std::fs::{File, remove_file}; + use std::io::Write; + use std::os::unix::io::AsRawFd; -fn main() { let path = temp_dir().join("miri_test_libc.txt"); // Cleanup before test remove_file(&path).ok(); @@ -34,3 +35,8 @@ fn main() { remove_file(&path).unwrap(); assert_eq!(result, 0); } + +fn main() { + #[cfg(not(target_os = "macos"))] + test_posix_fadvise(); +} From a30914bcddeca1ae58e578a0aa1d49580c0cfcee Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 28 Jan 2020 20:39:06 -0600 Subject: [PATCH 1493/5092] Conditional compilation fix --- tests/run-pass/libc.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index eb23cd16b757..5b7b37db327b 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -3,6 +3,7 @@ #![feature(rustc_private)] +#[allow(unused)] // necessary on macos due to conditional compilation extern crate libc; #[cfg(not(target_os = "macos"))] From 3d8bf92a11f348d8dd2183873ca60e2e4859e5b9 Mon Sep 17 00:00:00 2001 From: Tim Diekmann Date: Sun, 26 Jan 2020 19:50:26 +0100 Subject: [PATCH 1494/5092] Rename `Alloc` to `AllocRef` Required to land https://github.com/rust-lang/rust/pull/68529. Please see that PR for details. The CI is expected to fail until the PR is landed. --- tests/compile-fail/deallocate-bad-alignment.rs | 2 +- tests/compile-fail/deallocate-bad-size.rs | 2 +- tests/compile-fail/deallocate-twice.rs | 2 +- tests/compile-fail/reallocate-bad-size.rs | 2 +- tests/compile-fail/reallocate-change-alloc.rs | 2 +- tests/compile-fail/reallocate-dangling.rs | 2 +- tests/run-pass/heap_allocator.rs | 6 +++--- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/compile-fail/deallocate-bad-alignment.rs b/tests/compile-fail/deallocate-bad-alignment.rs index d124136a9653..2ac35a450cf1 100644 --- a/tests/compile-fail/deallocate-bad-alignment.rs +++ b/tests/compile-fail/deallocate-bad-alignment.rs @@ -3,7 +3,7 @@ extern crate alloc; use alloc::alloc::Global; -use std::alloc::*; +use std::alloc::{AllocRef, Layout}; // error-pattern: incorrect alloc info: expected size 1 and align 2, got size 1 and align 1 diff --git a/tests/compile-fail/deallocate-bad-size.rs b/tests/compile-fail/deallocate-bad-size.rs index 7a95b0ac7e90..c5b48f5ddf59 100644 --- a/tests/compile-fail/deallocate-bad-size.rs +++ b/tests/compile-fail/deallocate-bad-size.rs @@ -3,7 +3,7 @@ extern crate alloc; use alloc::alloc::Global; -use std::alloc::*; +use std::alloc::{AllocRef, Layout}; // error-pattern: incorrect alloc info: expected size 2 and align 1, got size 1 and align 1 diff --git a/tests/compile-fail/deallocate-twice.rs b/tests/compile-fail/deallocate-twice.rs index 03fab76d601b..02c442f0ab85 100644 --- a/tests/compile-fail/deallocate-twice.rs +++ b/tests/compile-fail/deallocate-twice.rs @@ -3,7 +3,7 @@ extern crate alloc; use alloc::alloc::Global; -use std::alloc::*; +use std::alloc::{AllocRef, Layout}; // error-pattern: tried to deallocate dangling pointer diff --git a/tests/compile-fail/reallocate-bad-size.rs b/tests/compile-fail/reallocate-bad-size.rs index 24d913205447..905e8e061721 100644 --- a/tests/compile-fail/reallocate-bad-size.rs +++ b/tests/compile-fail/reallocate-bad-size.rs @@ -3,7 +3,7 @@ extern crate alloc; use alloc::alloc::Global; -use std::alloc::*; +use std::alloc::{AllocRef, Layout}; // error-pattern: incorrect alloc info: expected size 2 and align 1, got size 1 and align 1 diff --git a/tests/compile-fail/reallocate-change-alloc.rs b/tests/compile-fail/reallocate-change-alloc.rs index 312edfd52b27..21468739b31c 100644 --- a/tests/compile-fail/reallocate-change-alloc.rs +++ b/tests/compile-fail/reallocate-change-alloc.rs @@ -3,7 +3,7 @@ extern crate alloc; use alloc::alloc::Global; -use std::alloc::*; +use std::alloc::{AllocRef, Layout}; fn main() { unsafe { diff --git a/tests/compile-fail/reallocate-dangling.rs b/tests/compile-fail/reallocate-dangling.rs index 450f63cc40d3..ee73cfce8634 100644 --- a/tests/compile-fail/reallocate-dangling.rs +++ b/tests/compile-fail/reallocate-dangling.rs @@ -3,7 +3,7 @@ extern crate alloc; use alloc::alloc::Global; -use std::alloc::*; +use std::alloc::{AllocRef, Layout}; // error-pattern: dangling pointer was dereferenced diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index 7bcb08058c36..907fbf962df0 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -1,10 +1,10 @@ #![feature(allocator_api)] use std::ptr::NonNull; -use std::alloc::{Global, Alloc, Layout, System}; +use std::alloc::{Global, AllocRef, Layout, System}; use std::slice; -fn check_alloc(mut allocator: T) { unsafe { +fn check_alloc(mut allocator: T) { unsafe { for &align in &[4, 8, 16, 32] { let layout = Layout::from_size_align(20, align).unwrap(); @@ -40,7 +40,7 @@ fn check_alloc(mut allocator: T) { unsafe { } } } -fn check_align_requests(mut allocator: T) { +fn check_align_requests(mut allocator: T) { for &size in &[2, 8, 64] { // size less than and bigger than alignment for &align in &[4, 8, 16, 32] { // Be sure to cover less than and bigger than `MIN_ALIGN` for all architectures let iterations = 32; From 74e0482ec347d165c5629c7eeff84719cb40e524 Mon Sep 17 00:00:00 2001 From: Tim Diekmann Date: Wed, 29 Jan 2020 04:10:40 +0100 Subject: [PATCH 1495/5092] Bump rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index e7e27291d553..5ce2e4651361 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -698fcd38fa9548e64a2092ff48c9d15ceb57d40c +3761dcd3467441f78939ccb3b341b03b6a7558d7 From 6e9abea2726462ec0901fa3d386eeee1a7771c6a Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 28 Jan 2020 22:59:28 -0600 Subject: [PATCH 1496/5092] Update comment --- src/shims/fs.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index c5017dc85bbd..b5c0dead1f8f 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -432,9 +432,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // * interpreting `path` as a path relative to `dirfd` when the latter is `AT_FDCWD`, or // * interpreting `dirfd` as any file descriptor when `path` is empty and AT_EMPTY_PATH is // set. - // The behavior of `statx` with a relative path and a directory file descriptor other than - // `AT_FDCWD` is specified but it cannot be tested from `libstd`. If you found this error, - // please open an issue reporting it. + // Other behaviors cannot be tested from `libstd` and thus are not implemented. If you + // found this error, please open an issue reporting it. if !( path.is_absolute() || dirfd == this.eval_libc_i32("AT_FDCWD")? || From 2f25e4cd17e0f97d4da9547c9b2201b5918c34b5 Mon Sep 17 00:00:00 2001 From: David Cook Date: Wed, 29 Jan 2020 19:04:18 -0600 Subject: [PATCH 1497/5092] Error with EINVAL on unsupported `whence` argument --- src/shims/fs.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 4cfff9446b85..388117daee6b 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -285,7 +285,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if whence == this.eval_libc_i32("SEEK_END")? { SeekFrom::End(offset) } else { - throw_unsup_format!("Unsupported whence argument to lseek64: {}", whence) + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + return Ok(-1); }; if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { From acd156d722c6d285ad5332b7b7aeb57f3b25b09a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Jan 2020 12:17:02 +0100 Subject: [PATCH 1498/5092] add test that relies on non-reborrowing-cast-to-raw --- tests/run-pass/stacked-borrows/stacked-borrows.rs | 7 +++---- tests/run-pass/stacked-borrows/stacked-borrows.stderr | 8 +------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index fe6a9a54d4f3..208cb7e15e03 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -129,16 +129,15 @@ fn two_raw() { unsafe { } } // Make sure that creating a *mut does not invalidate existing shared references. -fn shr_and_raw() { /* unsafe { +fn shr_and_raw() { unsafe { use std::mem; - // FIXME: This is currently disabled because "as *mut _" incurs a reborrow. let x = &mut 0; let y1: &i32 = mem::transmute(&*x); // launder lifetimes let y2 = x as *mut _; let _val = *y1; *y2 += 1; // TODO: Once this works, add compile-fail test that tries to read from y1 again. -} */ } +} } fn disjoint_mutable_subborrows() { struct Foo { @@ -165,5 +164,5 @@ fn disjoint_mutable_subborrows() { let b = unsafe{ borrow_field_b(ptr) }; b.push(4); a.push_str(" world"); - dbg!(a,b); + eprintln!("{:?} {:?}", a, b); } diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.stderr b/tests/run-pass/stacked-borrows/stacked-borrows.stderr index 4493d45ae157..8ee4e25dbef8 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.stderr +++ b/tests/run-pass/stacked-borrows/stacked-borrows.stderr @@ -1,7 +1 @@ -[$DIR/stacked-borrows.rs:168] a = "hello world" -[$DIR/stacked-borrows.rs:168] b = [ - 0, - 1, - 2, - 4, -] +"hello world" [0, 1, 2, 4] From e0adfe4d459482240d0614990fcb0ea112d48cf4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Jan 2020 12:21:37 +0100 Subject: [PATCH 1499/5092] new compile-fail test involving non-reborrowing-cast-to-raw --- tests/compile-fail/stacked_borrows/illegal_read8.rs | 13 +++++++++++++ tests/run-pass/stacked-borrows/stacked-borrows.rs | 1 - 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/stacked_borrows/illegal_read8.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read8.rs b/tests/compile-fail/stacked_borrows/illegal_read8.rs new file mode 100644 index 000000000000..72fca84ba19b --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read8.rs @@ -0,0 +1,13 @@ +// Make sure that creating a raw ptr next to a shared ref works +// but the shared ref still gets invalidated when the raw ptr is used for writing. + +fn main() { unsafe { + use std::mem; + let x = &mut 0; + let y1: &i32 = mem::transmute(&*x); // launder lifetimes + let y2 = x as *mut _; + let _val = *y2; + let _val = *y1; + *y2 += 1; + let _fail = *y1; //~ ERROR borrow stack +} } diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index 208cb7e15e03..824437f4f1bf 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -136,7 +136,6 @@ fn shr_and_raw() { unsafe { let y2 = x as *mut _; let _val = *y1; *y2 += 1; - // TODO: Once this works, add compile-fail test that tries to read from y1 again. } } fn disjoint_mutable_subborrows() { From 3cf413e4c29f4100efbf6841e2fb3876565f5638 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Jan 2020 12:22:54 +0100 Subject: [PATCH 1500/5092] remove inadequate comment --- tests/run-pass/stacked-borrows/stacked-borrows.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index 824437f4f1bf..a70285d5152a 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -119,9 +119,6 @@ fn direct_mut_to_const_raw() { // Make sure that we can create two raw pointers from a mutable reference and use them both. fn two_raw() { unsafe { let x = &mut 0; - // Given the implicit reborrows, the only reason this currently works is that we - // do not track raw pointers: The creation of `y2` reborrows `x` and thus pops - // `y1` off the stack. let y1 = x as *mut _; let y2 = x as *mut _; *y1 += 2; From b2c9871f7d83d9ac4c7838d4bcd2c91454620244 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Jan 2020 13:29:55 +0100 Subject: [PATCH 1501/5092] update another comment --- tests/run-pass/stacked-borrows/stacked-borrows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index a70285d5152a..765c6188b6e1 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -108,7 +108,7 @@ fn drop_after_sharing() { // Make sure that coercing &mut T to *const T produces a writeable pointer. fn direct_mut_to_const_raw() { - // FIXME: This is currently disabled, waiting on a fix for + // TODO: This is currently disabled, waiting on a decision on /*let x = &mut 0; let y: *const i32 = x; unsafe { *(y as *mut i32) = 1; } From ef154df60778055f7d4cd570537c9f73ceb75b8f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Jan 2020 13:38:49 +0100 Subject: [PATCH 1502/5092] pass MPlaceTy by-value, as we usually do --- src/helpers.rs | 2 +- src/shims/fs.rs | 4 ++-- src/shims/time.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index fba933d278d2..a765d58bbcf3 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -339,7 +339,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // different values into a struct. fn write_packed_immediates( &mut self, - place: &MPlaceTy<'tcx, Tag>, + place: MPlaceTy<'tcx, Tag>, imms: &[ImmTy<'tcx, Tag>], ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/shims/fs.rs b/src/shims/fs.rs index b5c0dead1f8f..2871dcbdcb8f 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -533,7 +533,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(0u128, __u64_layout)?, // stx_dev_minor ]; - this.write_packed_immediates(&statxbuf_place, &imms)?; + this.write_packed_immediates(statxbuf_place, &imms)?; Ok(0) } @@ -692,7 +692,7 @@ fn stat_macos_write_buf<'tcx, 'mir>( ]; let buf = ecx.deref_operand(buf_op)?; - ecx.write_packed_immediates(&buf, &imms)?; + ecx.write_packed_immediates(buf, &imms)?; Ok(0) } diff --git a/src/shims/time.rs b/src/shims/time.rs index a7d51eaa2e0f..6adea524d2d8 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -45,7 +45,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_int_checked(tv_nsec, this.libc_ty_layout("c_long")?)?, ]; - this.write_packed_immediates(&tp, &imms)?; + this.write_packed_immediates(tp, &imms)?; Ok(0) } @@ -77,7 +77,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_int_checked(tv_usec, this.libc_ty_layout("suseconds_t")?)?, ]; - this.write_packed_immediates(&tv, &imms)?; + this.write_packed_immediates(tv, &imms)?; Ok(0) } From 2dc309729e948eec9a20d6f05a28e73d8f0513ca Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 31 Jan 2020 11:38:07 +0100 Subject: [PATCH 1503/5092] rely on improved cargo install --- .appveyor.yml | 2 +- .travis.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 16fd20c9da61..4281fe0180f0 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -30,7 +30,7 @@ install: - rustup toolchain uninstall beta - rustup update # Install "master" toolchain - - cargo install rustup-toolchain-install-master & exit 0 + - cargo install rustup-toolchain-install-master # We need to install cargo here as well or else the DLL search path inside `cargo run` # will be for the wrong toolchain. (On Unix, `./miri` takes care of this, but not here.) - rustup-toolchain-install-master -f -n master %RUSTC_HASH% -c rust-src -c rustc-dev -c cargo diff --git a/.travis.yml b/.travis.yml index cbb7c69db1cd..3f0ca8a016bd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,7 +37,7 @@ before_script: - rustup toolchain uninstall beta - rustup update # Install "master" toolchain -- cargo install rustup-toolchain-install-master || echo "rustup-toolchain-install-master already installed" +- cargo install rustup-toolchain-install-master - travis_retry rustup-toolchain-install-master -f -n master $RUSTC_HASH -c rust-src -c rustc-dev - rustup default master - rustc --version From 121791b9af0a5d36f619e257262f8e46189c202f Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 2 Feb 2020 18:45:53 +0900 Subject: [PATCH 1504/5092] Bump rustc --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 5ce2e4651361..e3e82ead16d5 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -3761dcd3467441f78939ccb3b341b03b6a7558d7 +0cbcb17d3306d6e22eafc2c05ce885db97d0189c From 4b6a0d7a8ead04a5fe02caccb5608295c0bd0bc8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 6 Feb 2020 11:20:28 +0100 Subject: [PATCH 1505/5092] bump rustc; adjust tests --- rust-version | 2 +- src/shims/intrinsics.rs | 40 ---------------------------- tests/compile-fail/div-by-zero-1.rs | 4 +-- tests/compile-fail/div-by-zero-2.rs | 9 +++++++ tests/compile-fail/div-by-zero-3.rs | 11 -------- tests/compile-fail/unchecked_add1.rs | 2 +- tests/compile-fail/unchecked_add2.rs | 2 +- tests/compile-fail/unchecked_mul1.rs | 2 +- tests/compile-fail/unchecked_mul2.rs | 2 +- tests/compile-fail/unchecked_sub1.rs | 2 +- tests/compile-fail/unchecked_sub2.rs | 2 +- 11 files changed, 17 insertions(+), 61 deletions(-) create mode 100644 tests/compile-fail/div-by-zero-2.rs delete mode 100644 tests/compile-fail/div-by-zero-3.rs diff --git a/rust-version b/rust-version index e3e82ead16d5..1ea3561cca3a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0cbcb17d3306d6e22eafc2c05ce885db97d0189c +333c32a5a4a51cae562c47e0669bc5aeaf741c45 diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 04e724ff1d34..9cae97a4060c 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -518,46 +518,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_uint(align.bytes(), ptr_size), dest)?; } - "unchecked_div" => { - let l = this.read_immediate(args[0])?; - let r = this.read_immediate(args[1])?; - let rval = r.to_scalar()?.to_bits(args[1].layout.size)?; - if rval == 0 { - throw_ub_format!("Division by 0 in unchecked_div"); - } - this.binop_ignore_overflow(mir::BinOp::Div, l, r, dest)?; - } - - "unchecked_rem" => { - let l = this.read_immediate(args[0])?; - let r = this.read_immediate(args[1])?; - let rval = r.to_scalar()?.to_bits(args[1].layout.size)?; - if rval == 0 { - throw_ub_format!("Division by 0 in unchecked_rem"); - } - this.binop_ignore_overflow(mir::BinOp::Rem, l, r, dest)?; - } - - #[rustfmt::skip] - | "unchecked_add" - | "unchecked_sub" - | "unchecked_mul" - => { - let l = this.read_immediate(args[0])?; - let r = this.read_immediate(args[1])?; - let op = match intrinsic_name { - "unchecked_add" => mir::BinOp::Add, - "unchecked_sub" => mir::BinOp::Sub, - "unchecked_mul" => mir::BinOp::Mul, - _ => bug!(), - }; - let (res, overflowed, _ty) = this.overflowing_binary_op(op, l, r)?; - if overflowed { - throw_ub_format!("Overflowing arithmetic in {}", intrinsic_name); - } - this.write_scalar(res, dest)?; - } - "uninit" => { // Check fast path: we don't want to force an allocation in case the destination is a simple value, // but we also do not want to create a new allocation with 0s and then copy that over. diff --git a/tests/compile-fail/div-by-zero-1.rs b/tests/compile-fail/div-by-zero-1.rs index 987c18e4c492..d67d06dc1e67 100644 --- a/tests/compile-fail/div-by-zero-1.rs +++ b/tests/compile-fail/div-by-zero-1.rs @@ -2,10 +2,8 @@ use std::intrinsics::*; -//error-pattern: Division by 0 in unchecked_div - fn main() { unsafe { - let _n = unchecked_div(1i64, 0); + let _n = unchecked_div(1i64, 0); //~ERROR dividing by zero } } diff --git a/tests/compile-fail/div-by-zero-2.rs b/tests/compile-fail/div-by-zero-2.rs new file mode 100644 index 000000000000..e904049e3b46 --- /dev/null +++ b/tests/compile-fail/div-by-zero-2.rs @@ -0,0 +1,9 @@ +#![feature(core_intrinsics)] + +use std::intrinsics::*; + +fn main() { + unsafe { + let _n = unchecked_rem(3u32, 0); //~ ERROR calculating the remainder with a divisor of zero + } +} diff --git a/tests/compile-fail/div-by-zero-3.rs b/tests/compile-fail/div-by-zero-3.rs deleted file mode 100644 index 3200504ddb6e..000000000000 --- a/tests/compile-fail/div-by-zero-3.rs +++ /dev/null @@ -1,11 +0,0 @@ -#![feature(core_intrinsics)] - -use std::intrinsics::*; - -//error-pattern: Division by 0 in unchecked_rem - -fn main() { - unsafe { - let _n = unchecked_rem(3u32, 0); - } -} diff --git a/tests/compile-fail/unchecked_add1.rs b/tests/compile-fail/unchecked_add1.rs index 2447c8ba4a81..eb5a41fdfaf9 100644 --- a/tests/compile-fail/unchecked_add1.rs +++ b/tests/compile-fail/unchecked_add1.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MAX overflow - unsafe { std::intrinsics::unchecked_add(40000u16, 30000); } //~ ERROR Overflowing arithmetic in unchecked_add + unsafe { std::intrinsics::unchecked_add(40000u16, 30000); } //~ ERROR Overflow executing `unchecked_add` } diff --git a/tests/compile-fail/unchecked_add2.rs b/tests/compile-fail/unchecked_add2.rs index e292cdf6d961..fa6a232aedee 100644 --- a/tests/compile-fail/unchecked_add2.rs +++ b/tests/compile-fail/unchecked_add2.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MIN overflow - unsafe { std::intrinsics::unchecked_add(-30000i16, -8000); } //~ ERROR Overflowing arithmetic in unchecked_add + unsafe { std::intrinsics::unchecked_add(-30000i16, -8000); } //~ ERROR Overflow executing `unchecked_add` } diff --git a/tests/compile-fail/unchecked_mul1.rs b/tests/compile-fail/unchecked_mul1.rs index 57bfaf124c24..a3681a57df79 100644 --- a/tests/compile-fail/unchecked_mul1.rs +++ b/tests/compile-fail/unchecked_mul1.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MAX overflow - unsafe { std::intrinsics::unchecked_mul(300u16, 250u16); } //~ ERROR Overflowing arithmetic in unchecked_mul + unsafe { std::intrinsics::unchecked_mul(300u16, 250u16); } //~ ERROR Overflow executing `unchecked_mul` } diff --git a/tests/compile-fail/unchecked_mul2.rs b/tests/compile-fail/unchecked_mul2.rs index 690f2dc76284..8fe677f8ded5 100644 --- a/tests/compile-fail/unchecked_mul2.rs +++ b/tests/compile-fail/unchecked_mul2.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MIN overflow - unsafe { std::intrinsics::unchecked_mul(1_000_000_000i32, -4); } //~ ERROR Overflowing arithmetic in unchecked_mul + unsafe { std::intrinsics::unchecked_mul(1_000_000_000i32, -4); } //~ ERROR Overflow executing `unchecked_mul` } diff --git a/tests/compile-fail/unchecked_sub1.rs b/tests/compile-fail/unchecked_sub1.rs index 0be8afa2c34c..230607f03305 100644 --- a/tests/compile-fail/unchecked_sub1.rs +++ b/tests/compile-fail/unchecked_sub1.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MIN overflow - unsafe { std::intrinsics::unchecked_sub(14u32, 22); } //~ ERROR Overflowing arithmetic in unchecked_sub + unsafe { std::intrinsics::unchecked_sub(14u32, 22); } //~ ERROR Overflow executing `unchecked_sub` } diff --git a/tests/compile-fail/unchecked_sub2.rs b/tests/compile-fail/unchecked_sub2.rs index bc23fa37c367..1ea41a3c0fb0 100644 --- a/tests/compile-fail/unchecked_sub2.rs +++ b/tests/compile-fail/unchecked_sub2.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MAX overflow - unsafe { std::intrinsics::unchecked_sub(30000i16, -7000); } //~ ERROR Overflowing arithmetic in unchecked_sub + unsafe { std::intrinsics::unchecked_sub(30000i16, -7000); } //~ ERROR Overflow executing `unchecked_sub` } From 5d2caef3cebe97fc6cf67971064c0d5cf7bc974a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 6 Feb 2020 11:24:38 +0100 Subject: [PATCH 1506/5092] also test div-by-minus-1 --- tests/compile-fail/unchecked_div1.rs | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 tests/compile-fail/unchecked_div1.rs diff --git a/tests/compile-fail/unchecked_div1.rs b/tests/compile-fail/unchecked_div1.rs new file mode 100644 index 000000000000..1d1bbb09aa26 --- /dev/null +++ b/tests/compile-fail/unchecked_div1.rs @@ -0,0 +1,5 @@ +#![feature(core_intrinsics)] +fn main() { + // MIN/-1 cannot be represented + unsafe { std::intrinsics::unchecked_div(i16::min_value(), -1); } //~ ERROR Overflow executing `unchecked_div` +} From 98a1cac4ef4cb766c64fb476fabf7d162dd30361 Mon Sep 17 00:00:00 2001 From: David Cook Date: Thu, 6 Feb 2020 17:50:33 -0600 Subject: [PATCH 1507/5092] Add tests to cover SEEK_CUR and SEEK_END --- tests/run-pass/fs.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 4da67369aef8..73e6f37453fa 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -45,6 +45,17 @@ fn main() { let mut contents = Vec::new(); file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); + // Test seeking relative to the end of the file. + file.seek(SeekFrom::End(-1)).unwrap(); + let mut contents = Vec::new(); + file.read_to_end(&mut contents).unwrap(); + assert_eq!(&bytes[bytes.len() - 1..], contents.as_slice()); + // Test seeking relative to the current position. + file.seek(SeekFrom::Start(5)).unwrap(); + file.seek(SeekFrom::Current(-3)).unwrap(); + let mut contents = Vec::new(); + file.read_to_end(&mut contents).unwrap(); + assert_eq!(&bytes[2..], contents.as_slice()); // Test that metadata of an absolute path is correct. test_metadata(bytes, &path).unwrap(); From d208a5fe3b16ce53764df7df610cf929b4a25d57 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 7 Feb 2020 13:47:39 +0100 Subject: [PATCH 1508/5092] rustup; fix generator test --- rust-version | 2 +- tests/compile-fail/generator-pinned-moved.rs | 2 +- tests/run-pass/generator.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 1ea3561cca3a..edb99d8eb0d5 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -333c32a5a4a51cae562c47e0669bc5aeaf741c45 +b5e21dbb5cabdaaadc47a4d8e3f59979dcad2871 diff --git a/tests/compile-fail/generator-pinned-moved.rs b/tests/compile-fail/generator-pinned-moved.rs index 2ae98adad773..70ceacd8ca6f 100644 --- a/tests/compile-fail/generator-pinned-moved.rs +++ b/tests/compile-fail/generator-pinned-moved.rs @@ -25,7 +25,7 @@ where fn next(&mut self) -> Option { let me = unsafe { Pin::new_unchecked(&mut self.0) }; - match me.resume() { + match me.resume(()) { GeneratorState::Yielded(x) => Some(x), GeneratorState::Complete(_) => None, } diff --git a/tests/run-pass/generator.rs b/tests/run-pass/generator.rs index c31b5b9ed3bb..7f95f374ac7d 100644 --- a/tests/run-pass/generator.rs +++ b/tests/run-pass/generator.rs @@ -9,7 +9,7 @@ fn finish(mut amt: usize, mut t: T) -> T::Return // We are not moving the `t` around until it gets dropped, so this is okay. let mut t = unsafe { Pin::new_unchecked(&mut t) }; loop { - match t.as_mut().resume() { + match t.as_mut().resume(()) { GeneratorState::Yielded(y) => amt -= y, GeneratorState::Complete(ret) => { assert_eq!(amt, 0); From 418dd641dc41e3e9edc832f9083a669836110d15 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 7 Feb 2020 14:02:36 +0100 Subject: [PATCH 1509/5092] test more generator resume things --- tests/run-pass/generator.rs | 155 ++++++++++++++++++++++++++++---- tests/run-pass/generator.stderr | 1 + 2 files changed, 138 insertions(+), 18 deletions(-) create mode 100644 tests/run-pass/generator.stderr diff --git a/tests/run-pass/generator.rs b/tests/run-pass/generator.rs index 7f95f374ac7d..a7c72ed3530c 100644 --- a/tests/run-pass/generator.rs +++ b/tests/run-pass/generator.rs @@ -1,30 +1,33 @@ #![feature(generators, generator_trait, never_type)] -use std::ops::{GeneratorState, Generator}; +use std::panic::{catch_unwind, AssertUnwindSafe}; +use std::ops::{GeneratorState::{self, *}, Generator}; use std::pin::Pin; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::fmt::Debug; -fn finish(mut amt: usize, mut t: T) -> T::Return - where T: Generator -{ - // We are not moving the `t` around until it gets dropped, so this is okay. - let mut t = unsafe { Pin::new_unchecked(&mut t) }; - loop { - match t.as_mut().resume(()) { - GeneratorState::Yielded(y) => amt -= y, - GeneratorState::Complete(ret) => { - assert_eq!(amt, 0); - return ret +fn basic() { + fn finish(mut amt: usize, mut t: T) -> T::Return + where T: Generator + { + // We are not moving the `t` around until it gets dropped, so this is okay. + let mut t = unsafe { Pin::new_unchecked(&mut t) }; + loop { + match t.as_mut().resume(()) { + GeneratorState::Yielded(y) => amt -= y, + GeneratorState::Complete(ret) => { + assert_eq!(amt, 0); + return ret + } } } } -} -enum Never {} -fn never() -> Never { - panic!() -} + enum Never {} + fn never() -> Never { + panic!() + } -fn main() { finish(1, || yield 1); finish(3, || { @@ -94,3 +97,119 @@ fn main() { let _x: (String, !) = (String::new(), { yield 2; return }); }); } + +fn smoke_resume_arg() { + fn drain + Unpin, R, Y>( + gen: &mut G, + inout: Vec<(R, GeneratorState)>, + ) where + Y: Debug + PartialEq, + G::Return: Debug + PartialEq, + { + let mut gen = Pin::new(gen); + + for (input, out) in inout { + assert_eq!(gen.as_mut().resume(input), out); + } + } + + static DROPS: AtomicUsize = AtomicUsize::new(0); + + #[derive(Debug, PartialEq)] + struct DropMe; + + impl Drop for DropMe { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::SeqCst); + } + } + + fn expect_drops(expected_drops: usize, f: impl FnOnce() -> T) -> T { + DROPS.store(0, Ordering::SeqCst); + + let res = f(); + + let actual_drops = DROPS.load(Ordering::SeqCst); + assert_eq!(actual_drops, expected_drops); + res + } + + drain( + &mut |mut b| { + while b != 0 { + b = yield (b + 1); + } + -1 + }, + vec![(1, Yielded(2)), (-45, Yielded(-44)), (500, Yielded(501)), (0, Complete(-1))], + ); + + expect_drops(2, || drain(&mut |a| yield a, vec![(DropMe, Yielded(DropMe))])); + + expect_drops(6, || { + drain( + &mut |a| yield yield a, + vec![(DropMe, Yielded(DropMe)), (DropMe, Yielded(DropMe)), (DropMe, Complete(DropMe))], + ) + }); + + #[allow(unreachable_code)] + expect_drops(2, || drain(&mut |a| yield return a, vec![(DropMe, Complete(DropMe))])); + + expect_drops(2, || { + drain( + &mut |a: DropMe| { + if false { yield () } else { a } + }, + vec![(DropMe, Complete(DropMe))], + ) + }); + + expect_drops(4, || { + drain( + #[allow(unused_assignments, unused_variables)] + &mut |mut a: DropMe| { + a = yield; + a = yield; + a = yield; + }, + vec![ + (DropMe, Yielded(())), + (DropMe, Yielded(())), + (DropMe, Yielded(())), + (DropMe, Complete(())), + ], + ) + }); +} + +fn panic_drop_resume() { + static DROP: AtomicUsize = AtomicUsize::new(0); + + struct Dropper {} + + impl Drop for Dropper { + fn drop(&mut self) { + DROP.fetch_add(1, Ordering::SeqCst); + } + } + + let mut gen = |_arg| { + if true { + panic!(); + } + yield (); + }; + let mut gen = Pin::new(&mut gen); + + assert_eq!(DROP.load(Ordering::Acquire), 0); + let res = catch_unwind(AssertUnwindSafe(|| gen.as_mut().resume(Dropper {}))); + assert!(res.is_err()); + assert_eq!(DROP.load(Ordering::Acquire), 1); +} + +fn main() { + basic(); + smoke_resume_arg(); + panic_drop_resume(); +} diff --git a/tests/run-pass/generator.stderr b/tests/run-pass/generator.stderr new file mode 100644 index 000000000000..17f385d4d695 --- /dev/null +++ b/tests/run-pass/generator.stderr @@ -0,0 +1 @@ +thread 'main' panicked at 'explicit panic', $DIR/generator.rs:199:13 From 45f6744fdac14196378c0d2f28c48d27024d9589 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 7 Feb 2020 14:19:58 +0100 Subject: [PATCH 1510/5092] panics dont work on Windows, just the smoke test should be enough --- tests/run-pass/generator.rs | 27 --------------------------- tests/run-pass/generator.stderr | 1 - 2 files changed, 28 deletions(-) delete mode 100644 tests/run-pass/generator.stderr diff --git a/tests/run-pass/generator.rs b/tests/run-pass/generator.rs index a7c72ed3530c..e85d2cf8f29a 100644 --- a/tests/run-pass/generator.rs +++ b/tests/run-pass/generator.rs @@ -1,6 +1,5 @@ #![feature(generators, generator_trait, never_type)] -use std::panic::{catch_unwind, AssertUnwindSafe}; use std::ops::{GeneratorState::{self, *}, Generator}; use std::pin::Pin; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -183,33 +182,7 @@ fn smoke_resume_arg() { }); } -fn panic_drop_resume() { - static DROP: AtomicUsize = AtomicUsize::new(0); - - struct Dropper {} - - impl Drop for Dropper { - fn drop(&mut self) { - DROP.fetch_add(1, Ordering::SeqCst); - } - } - - let mut gen = |_arg| { - if true { - panic!(); - } - yield (); - }; - let mut gen = Pin::new(&mut gen); - - assert_eq!(DROP.load(Ordering::Acquire), 0); - let res = catch_unwind(AssertUnwindSafe(|| gen.as_mut().resume(Dropper {}))); - assert!(res.is_err()); - assert_eq!(DROP.load(Ordering::Acquire), 1); -} - fn main() { basic(); smoke_resume_arg(); - panic_drop_resume(); } diff --git a/tests/run-pass/generator.stderr b/tests/run-pass/generator.stderr deleted file mode 100644 index 17f385d4d695..000000000000 --- a/tests/run-pass/generator.stderr +++ /dev/null @@ -1 +0,0 @@ -thread 'main' panicked at 'explicit panic', $DIR/generator.rs:199:13 From 38204b63211302a77bb9ff677f6b1df9f5acd734 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 26 Jan 2020 16:45:05 -0600 Subject: [PATCH 1511/5092] Add shim for rename --- src/shims/foreign_items.rs | 5 +++++ src/shims/fs.rs | 28 +++++++++++++++++++++++++++- tests/run-pass/fs.rs | 14 +++++++++++++- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 5b40f3c69063..2fd886ed0e84 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -521,6 +521,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "rename" => { + let result = this.rename(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + "clock_gettime" => { let result = this.clock_gettime(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index f0efc073f75c..2ae215e7204f 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; -use std::fs::{remove_file, File, OpenOptions}; +use std::fs::{remove_file, rename, File, OpenOptions}; use std::io::{Read, Seek, SeekFrom, Write}; use std::path::PathBuf; use std::time::SystemTime; @@ -582,6 +582,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.set_last_error(ebadf)?; Ok((-1).into()) } + + fn rename( + &mut self, + oldpath_op: OpTy<'tcx, Tag>, + newpath_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.check_no_isolation("rename")?; + + let oldpath_scalar = this.read_scalar(oldpath_op)?.not_undef()?; + let newpath_scalar = this.read_scalar(newpath_op)?.not_undef()?; + + if this.is_null(oldpath_scalar)? || this.is_null(newpath_scalar)? { + let efault = this.eval_libc("EFAULT")?; + this.set_last_error(efault)?; + return Ok(-1); + } + + let oldpath = this.read_os_str_from_c_str(oldpath_scalar)?; + let newpath = this.read_os_str_from_c_str(newpath_scalar)?; + + let result = rename(oldpath, newpath).map(|_| 0); + + this.try_unwrap_io_result(result) + } } /// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch when diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 7483bf3ec8b8..9e1891adf34e 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -1,7 +1,7 @@ // ignore-windows: File handling is not implemented yet // compile-flags: -Zmiri-disable-isolation -use std::fs::{File, remove_file}; +use std::fs::{File, remove_file, rename}; use std::io::{Read, Write, ErrorKind, Result, Seek, SeekFrom}; use std::path::{PathBuf, Path}; @@ -82,6 +82,18 @@ fn main() { // Removing file should succeed. remove_file(&path).unwrap(); + // Renaming a file should succeed. + let path1 = tmp.join("rename_source.txt"); + let path2 = tmp.join("rename_destination.txt"); + // Clean files for robustness. + remove_file(&path1).ok(); + remove_file(&path2).ok(); + let file = File::create(&path1).unwrap(); + drop(file); + rename(&path1, &path2).unwrap(); + assert!(path2.metadata().unwrap().is_file()); + remove_file(&path2).ok(); + // The two following tests also check that the `__errno_location()` shim is working properly. // Opening a non-existing file should fail with a "not found" error. assert_eq!(ErrorKind::NotFound, File::open(&path).unwrap_err().kind()); From f7e085764445c679bdc2694733119f2b5aeedf8e Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 8 Feb 2020 22:40:46 -0600 Subject: [PATCH 1512/5092] Test that src path of rename is no longer a file --- tests/run-pass/fs.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 9e1891adf34e..e9132fbd61db 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -91,6 +91,7 @@ fn main() { let file = File::create(&path1).unwrap(); drop(file); rename(&path1, &path2).unwrap(); + assert_eq!(ErrorKind::NotFound, path1.metadata().unwrap_err().kind()); assert!(path2.metadata().unwrap().is_file()); remove_file(&path2).ok(); From 87644d120fb6d0f349e003d212dd8dd5053edd49 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Feb 2020 21:44:09 +0100 Subject: [PATCH 1513/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index edb99d8eb0d5..89a8a40f1b2b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -b5e21dbb5cabdaaadc47a4d8e3f59979dcad2871 +2d2be570970d784db5539a1d309cd22b85be910a From a843fd4e17bc88895a265136a775e73b4d44dd0a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Feb 2020 21:50:54 +0100 Subject: [PATCH 1514/5092] add test for layout optimizations --- tests/run-pass/stacked-borrows/refcell.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/run-pass/stacked-borrows/refcell.rs b/tests/run-pass/stacked-borrows/refcell.rs index 0939a666193e..83db10577ceb 100644 --- a/tests/run-pass/stacked-borrows/refcell.rs +++ b/tests/run-pass/stacked-borrows/refcell.rs @@ -4,6 +4,7 @@ fn main() { basic(); ref_protector(); ref_mut_protector(); + rust_issue_68303(); } fn basic() { @@ -66,3 +67,11 @@ fn ref_mut_protector() { let rc = RefCell::new(0); break_it(&rc, rc.borrow_mut()) } + +/// Make sure we do not have bad enum layout optimizations. +fn rust_issue_68303() { + let optional=Some(RefCell::new(false)); + let mut handle=optional.as_ref().unwrap().borrow_mut(); + assert!(optional.is_some()); + *handle=true; +} From 26d25220ef1e4757b167c0ddca0410d7eb20a9fa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 13 Feb 2020 14:01:35 +0100 Subject: [PATCH 1515/5092] fix for Panic InterpError refactoring --- src/machine.rs | 2 +- src/operator.rs | 2 +- src/shims/foreign_items.rs | 2 +- src/shims/panic.rs | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index f8c7168a5847..5d933fe8a7f6 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -219,7 +219,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn assert_panic( ecx: &mut InterpCx<'mir, 'tcx, Self>, span: Span, - msg: &AssertMessage<'tcx>, + msg: &mir::AssertMessage<'tcx>, unwind: Option, ) -> InterpResult<'tcx> { ecx.assert_panic(span, msg, unwind) diff --git a/src/operator.rs b/src/operator.rs index 7c932a907e72..8860b949fe94 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -105,7 +105,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); let offset = offset .checked_mul(pointee_size) - .ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?; + .ok_or_else(|| err_ub_format!("overflow during offset comutation for inbounds pointer arithmetic"))?; // We do this first, to rule out overflows. let offset_ptr = ptr.ptr_signed_offset(offset, self)?; // What we need to check is that starting at `min(ptr, offset_ptr)`, diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 5b40f3c69063..4a1d62d3567e 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -177,7 +177,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let items = this.read_scalar(args[0])?.to_machine_usize(this)?; let len = this.read_scalar(args[1])?.to_machine_usize(this)?; let size = - items.checked_mul(len).ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?; + items.checked_mul(len).ok_or_else(|| err_ub_format!("overflow during calloc size computation"))?; let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C); this.write_scalar(res, dest)?; } diff --git a/src/shims/panic.rs b/src/shims/panic.rs index d676f0464657..880932ae0472 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -153,10 +153,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn assert_panic( &mut self, span: Span, - msg: &AssertMessage<'tcx>, + msg: &mir::AssertMessage<'tcx>, unwind: Option, ) -> InterpResult<'tcx> { - use rustc::mir::interpret::PanicInfo::*; + use rustc::mir::AssertKind::*; let this = self.eval_context_mut(); match msg { From a61596d3332c9b2103404d6ee4f0b47fd6d569a5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 14 Feb 2020 08:59:42 +0100 Subject: [PATCH 1516/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 89a8a40f1b2b..a0f512a72700 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -2d2be570970d784db5539a1d309cd22b85be910a +21ed50522ddb998f5367229984a4510af578899f From 91868125a519db341f86410590b959b10de03f11 Mon Sep 17 00:00:00 2001 From: David Cook Date: Fri, 14 Feb 2020 08:19:16 -0600 Subject: [PATCH 1517/5092] Removing file after rename must succeed Co-Authored-By: Ralf Jung --- tests/run-pass/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index e9132fbd61db..71c6e854f7c5 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -93,7 +93,7 @@ fn main() { rename(&path1, &path2).unwrap(); assert_eq!(ErrorKind::NotFound, path1.metadata().unwrap_err().kind()); assert!(path2.metadata().unwrap().is_file()); - remove_file(&path2).ok(); + remove_file(&path2).unwrap(); // The two following tests also check that the `__errno_location()` shim is working properly. // Opening a non-existing file should fail with a "not found" error. From e7d6e718b91d4122ee5ba8fa2ac67fb49af93f89 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sun, 2 Feb 2020 16:21:12 -0500 Subject: [PATCH 1518/5092] reorganize shims by platform --- src/shims/foreign_items.rs | 226 ++++--------------------- src/shims/foreign_items/posix.rs | 111 ++++++++++++ src/shims/foreign_items/posix/linux.rs | 46 +++++ src/shims/foreign_items/posix/macos.rs | 62 +++++++ src/shims/foreign_items/windows.rs | 75 ++++++++ 5 files changed, 328 insertions(+), 192 deletions(-) create mode 100644 src/shims/foreign_items/posix.rs create mode 100644 src/shims/foreign_items/posix/linux.rs create mode 100644 src/shims/foreign_items/posix/macos.rs create mode 100644 src/shims/foreign_items/windows.rs diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index ff5ffb0e3ac6..d3a8ac1b065f 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -1,3 +1,6 @@ +mod windows; +mod posix; + use std::{convert::TryInto, iter}; use rustc_hir::def_id::DefId; @@ -167,6 +170,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Next: functions that return. + match link_name { + "__rust_maybe_catch_panic" => { + this.handle_catch_panic(args, dest, ret)?; + return Ok(None); + } + + _ => this.emulate_foreign_item_by_name(link_name, args, dest)?, + }; + + this.dump_place(*dest); + this.go_to_block(ret); + + Ok(None) + } + + fn emulate_foreign_item_by_name( + &mut self, + link_name: &str, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let tcx = &{ this.tcx.tcx }; + match link_name { "malloc" => { let size = this.read_scalar(args[0])?.to_machine_usize(this)?; @@ -339,11 +366,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - "__rust_maybe_catch_panic" => { - this.handle_catch_panic(args, dest, ret)?; - return Ok(None); - } - "memcmp" => { let left = this.read_scalar(args[0])?.not_undef()?; let right = this.read_scalar(args[1])?.not_undef()?; @@ -399,143 +421,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - | "__errno_location" - | "__error" - => { - let errno_place = this.machine.last_error.unwrap(); - this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; - } - - "getenv" => { - let result = this.getenv(args[0])?; - this.write_scalar(result, dest)?; - } - - "unsetenv" => { - let result = this.unsetenv(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - - "setenv" => { - let result = this.setenv(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - - "getcwd" => { - let result = this.getcwd(args[0], args[1])?; - this.write_scalar(result, dest)?; - } - - "chdir" => { - let result = this.chdir(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - - | "open" - | "open64" - => { - let result = this.open(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - - "fcntl" => { - let result = this.fcntl(args[0], args[1], args.get(2).cloned())?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - - | "close" - | "close$NOCANCEL" - => { - let result = this.close(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - - "read" => { - let result = this.read(args[0], args[1], args[2])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - - "write" => { - let fd = this.read_scalar(args[0])?.to_i32()?; - let buf = this.read_scalar(args[1])?.not_undef()?; - let n = this.read_scalar(args[2])?.to_machine_usize(tcx)?; - trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); - let result = if fd == 1 || fd == 2 { - // stdout/stderr - use std::io::{self, Write}; - - let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(n))?; - // We need to flush to make sure this actually appears on the screen - let res = if fd == 1 { - // Stdout is buffered, flush to make sure it appears on the screen. - // This is the write() syscall of the interpreted program, we want it - // to correspond to a write() syscall on the host -- there is no good - // in adding extra buffering here. - let res = io::stdout().write(buf_cont); - io::stdout().flush().unwrap(); - res - } else { - // No need to flush, stderr is not buffered. - io::stderr().write(buf_cont) - }; - match res { - Ok(n) => n as i64, - Err(_) => -1, - } - } else { - this.write(args[0], args[1], args[2])? - }; - // Now, `result` is the value we return back to the program. - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - - | "lseek64" - | "lseek" - => { - let result = this.lseek64(args[0], args[1], args[2])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - - "unlink" => { - let result = this.unlink(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - - "symlink" => { - let result = this.symlink(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - - "stat$INODE64" => { - let result = this.stat(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - - "lstat$INODE64" => { - let result = this.lstat(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - - "fstat$INODE64" => { - let result = this.fstat(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } "rename" => { let result = this.rename(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "clock_gettime" => { - let result = this.clock_gettime(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - - "gettimeofday" => { - let result = this.gettimeofday(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - "strlen" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let n = this.memory.read_c_str(ptr)?.len(); @@ -950,60 +841,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // which one it is. this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?; } - "WriteFile" => { - let handle = this.read_scalar(args[0])?.to_machine_isize(this)?; - let buf = this.read_scalar(args[1])?.not_undef()?; - let n = this.read_scalar(args[2])?.to_u32()?; - let written_place = this.deref_operand(args[3])?; - // Spec says to always write `0` first. - this.write_null(written_place.into())?; - let written = if handle == -11 || handle == -12 { - // stdout/stderr - use std::io::{self, Write}; - - let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(u64::from(n)))?; - let res = if handle == -11 { - io::stdout().write(buf_cont) - } else { - io::stderr().write(buf_cont) - }; - res.ok().map(|n| n as u32) - } else { - eprintln!("Miri: Ignored output to handle {}", handle); - // Pretend it all went well. - Some(n) - }; - // If there was no error, write back how much was written. - if let Some(n) = written { - this.write_scalar(Scalar::from_u32(n), written_place.into())?; - } - // Return whether this was a success. - this.write_scalar( - Scalar::from_int(if written.is_some() { 1 } else { 0 }, dest.layout.size), - dest, - )?; - } "GetConsoleMode" => { // Everything is a pipe. this.write_null(dest)?; } - "GetEnvironmentVariableW" => { - // args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars) - // args[1] : LPWSTR lpBuffer (32-bit pointer to a string of 16-bit Unicode chars) - // lpBuffer : ptr to buffer that receives contents of the env_var as a null-terminated string. - // Return `# of chars` stored in the buffer pointed to by lpBuffer, excluding null-terminator. - // Return 0 upon failure. - - // This is not the env var you are looking for. - this.set_last_error(Scalar::from_u32(203))?; // ERROR_ENVVAR_NOT_FOUND - this.write_null(dest)?; - } - "SetEnvironmentVariableW" => { - // args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars) - // args[1] : LPCWSTR lpValue (32-bit ptr to a const string of 16-bit Unicode chars) - // Return nonzero if success, else return 0. - throw_unsup_format!("can't set environment variable on Windows"); - } "GetCommandLineW" => { this.write_scalar( this.machine.cmd_line.expect("machine must be initialized"), @@ -1018,13 +859,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_bool(true), dest)?; } - // We can't execute anything else. - _ => throw_unsup_format!("can't call foreign function: {}", link_name), - } + _ => match this.tcx.sess.target.target.target_os.to_lowercase().as_str() { + "linux" | "macos" => posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?, + "windows" => windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?, + target => throw_unsup_format!("The {} target platform is not supported", target), + } + }; - this.dump_place(*dest); - this.go_to_block(ret); - Ok(None) + Ok(()) } /// Evaluates the scalar at the specified path. Returns Some(val) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs new file mode 100644 index 000000000000..ecdec1fb165c --- /dev/null +++ b/src/shims/foreign_items/posix.rs @@ -0,0 +1,111 @@ +mod linux; +mod macos; + +use crate::*; +use rustc::ty::layout::Size; + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn emulate_foreign_item_by_name( + &mut self, + link_name: &str, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let tcx = &{ this.tcx.tcx }; + + match link_name { + // Environment related shims + "getenv" => { + let result = this.getenv(args[0])?; + this.write_scalar(result, dest)?; + } + + "unsetenv" => { + let result = this.unsetenv(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "setenv" => { + let result = this.setenv(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "getcwd" => { + let result = this.getcwd(args[0], args[1])?; + this.write_scalar(result, dest)?; + } + + "chdir" => { + let result = this.chdir(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + // File related shims + "fcntl" => { + let result = this.fcntl(args[0], args[1], args.get(2).cloned())?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "read" => { + let result = this.read(args[0], args[1], args[2])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "write" => { + let fd = this.read_scalar(args[0])?.to_i32()?; + let buf = this.read_scalar(args[1])?.not_undef()?; + let n = this.read_scalar(args[2])?.to_machine_usize(tcx)?; + trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); + let result = if fd == 1 || fd == 2 { + // stdout/stderr + use std::io::{self, Write}; + + let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(n))?; + // We need to flush to make sure this actually appears on the screen + let res = if fd == 1 { + // Stdout is buffered, flush to make sure it appears on the screen. + // This is the write() syscall of the interpreted program, we want it + // to correspond to a write() syscall on the host -- there is no good + // in adding extra buffering here. + let res = io::stdout().write(buf_cont); + io::stdout().flush().unwrap(); + res + } else { + // No need to flush, stderr is not buffered. + io::stderr().write(buf_cont) + }; + match res { + Ok(n) => n as i64, + Err(_) => -1, + } + } else { + this.write(args[0], args[1], args[2])? + }; + // Now, `result` is the value we return back to the program. + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "unlink" => { + let result = this.unlink(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "symlink" => { + let result = this.symlink(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + _ => { + match this.tcx.sess.target.target.target_os.to_lowercase().as_str() { + "linux" => linux::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?, + "macos" => macos::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?, + _ => unreachable!(), + } + } + }; + + Ok(()) + } +} diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs new file mode 100644 index 000000000000..bc61aea18c73 --- /dev/null +++ b/src/shims/foreign_items/posix/linux.rs @@ -0,0 +1,46 @@ +use crate::*; + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn emulate_foreign_item_by_name( + &mut self, + link_name: &str, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + match link_name { + "__errno_location" => { + let errno_place = this.machine.last_error.unwrap(); + this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; + } + + // File related shims + "open64" => { + let result = this.open(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "close" => { + let result = this.close(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "lseek64" => { + let result = this.lseek64(args[0], args[1], args[2])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + // Time related shims + "clock_gettime" => { + let result = this.clock_gettime(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + _ => throw_unsup_format!("can't call foreign function: {}", link_name), + }; + + Ok(()) + } +} diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs new file mode 100644 index 000000000000..e0ac92868a2c --- /dev/null +++ b/src/shims/foreign_items/posix/macos.rs @@ -0,0 +1,62 @@ +use crate::*; + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn emulate_foreign_item_by_name( + &mut self, + link_name: &str, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + match link_name { + "__error" => { + let errno_place = this.machine.last_error.unwrap(); + this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; + } + + // File related shims + "open" => { + let result = this.open(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "close$NOCANCEL" => { + let result = this.close(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "stat$INODE64" => { + let result = this.stat(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "lstat$INODE64" => { + let result = this.lstat(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "fstat$INODE64" => { + let result = this.fstat(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "lseek" => { + let result = this.lseek64(args[0], args[1], args[2])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + // Time related shims + "gettimeofday" => { + let result = this.gettimeofday(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + _ => throw_unsup_format!("can't call foreign function: {}", link_name), + }; + + Ok(()) + } +} + diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs new file mode 100644 index 000000000000..23aa8ae7deb3 --- /dev/null +++ b/src/shims/foreign_items/windows.rs @@ -0,0 +1,75 @@ +use crate::*; +use rustc::ty::layout::Size; + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn emulate_foreign_item_by_name( + &mut self, + link_name: &str, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + match link_name { + // Environment related shims + "GetEnvironmentVariableW" => { + // args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars) + // args[1] : LPWSTR lpBuffer (32-bit pointer to a string of 16-bit Unicode chars) + // lpBuffer : ptr to buffer that receives contents of the env_var as a null-terminated string. + // Return `# of chars` stored in the buffer pointed to by lpBuffer, excluding null-terminator. + // Return 0 upon failure. + + // This is not the env var you are looking for. + this.set_last_error(Scalar::from_u32(203))?; // ERROR_ENVVAR_NOT_FOUND + this.write_null(dest)?; + } + + "SetEnvironmentVariableW" => { + // args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars) + // args[1] : LPCWSTR lpValue (32-bit ptr to a const string of 16-bit Unicode chars) + // Return nonzero if success, else return 0. + throw_unsup_format!("can't set environment variable on Windows"); + } + + // File related shims + "WriteFile" => { + let handle = this.read_scalar(args[0])?.to_machine_isize(this)?; + let buf = this.read_scalar(args[1])?.not_undef()?; + let n = this.read_scalar(args[2])?.to_u32()?; + let written_place = this.deref_operand(args[3])?; + // Spec says to always write `0` first. + this.write_null(written_place.into())?; + let written = if handle == -11 || handle == -12 { + // stdout/stderr + use std::io::{self, Write}; + + let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(u64::from(n)))?; + let res = if handle == -11 { + io::stdout().write(buf_cont) + } else { + io::stderr().write(buf_cont) + }; + res.ok().map(|n| n as u32) + } else { + eprintln!("Miri: Ignored output to handle {}", handle); + // Pretend it all went well. + Some(n) + }; + // If there was no error, write back how much was written. + if let Some(n) = written { + this.write_scalar(Scalar::from_u32(n), written_place.into())?; + } + // Return whether this was a success. + this.write_scalar( + Scalar::from_int(if written.is_some() { 1 } else { 0 }, dest.layout.size), + dest, + )?; + } + _ => throw_unsup_format!("can't call foreign function: {}", link_name), + } + + Ok(()) + } +} + From f2f8fb2c20e1a0371f43379ac13eb323f95b4f4b Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 5 Feb 2020 19:46:50 -0500 Subject: [PATCH 1519/5092] migrate more functions --- src/shims/foreign_items.rs | 157 ------------------------- src/shims/foreign_items/posix/linux.rs | 3 + src/shims/foreign_items/posix/macos.rs | 29 +++++ src/shims/foreign_items/windows.rs | 128 ++++++++++++++++++++ 4 files changed, 160 insertions(+), 157 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index d3a8ac1b065f..f8a61a7c5a12 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -702,163 +702,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - // macOS API stubs. - | "pthread_attr_get_np" - | "pthread_getattr_np" - => { - this.write_null(dest)?; - } - "pthread_get_stackaddr_np" => { - let stack_addr = Scalar::from_uint(STACK_ADDR, dest.layout.size); - this.write_scalar(stack_addr, dest)?; - } - "pthread_get_stacksize_np" => { - let stack_size = Scalar::from_uint(STACK_SIZE, dest.layout.size); - this.write_scalar(stack_size, dest)?; - } - "_tlv_atexit" => { - // FIXME: register the destructor. - } - "_NSGetArgc" => { - this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?; - } - "_NSGetArgv" => { - this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; - } - "SecRandomCopyBytes" => { - let len = this.read_scalar(args[1])?.to_machine_usize(this)?; - let ptr = this.read_scalar(args[2])?.not_undef()?; - this.gen_random(ptr, len as usize)?; - this.write_null(dest)?; - } - - // Windows API stubs. - // HANDLE = isize - // DWORD = ULONG = u32 - // BOOL = i32 - "GetProcessHeap" => { - // Just fake a HANDLE - this.write_scalar(Scalar::from_int(1, this.pointer_size()), dest)?; - } - "HeapAlloc" => { - let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?; - let flags = this.read_scalar(args[1])?.to_u32()?; - let size = this.read_scalar(args[2])?.to_machine_usize(this)?; - let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY - let res = this.malloc(size, zero_init, MiriMemoryKind::WinHeap); - this.write_scalar(res, dest)?; - } - "HeapFree" => { - let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?; - let _flags = this.read_scalar(args[1])?.to_u32()?; - let ptr = this.read_scalar(args[2])?.not_undef()?; - this.free(ptr, MiriMemoryKind::WinHeap)?; - this.write_scalar(Scalar::from_int(1, Size::from_bytes(4)), dest)?; - } - "HeapReAlloc" => { - let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?; - let _flags = this.read_scalar(args[1])?.to_u32()?; - let ptr = this.read_scalar(args[2])?.not_undef()?; - let size = this.read_scalar(args[3])?.to_machine_usize(this)?; - let res = this.realloc(ptr, size, MiriMemoryKind::WinHeap)?; - this.write_scalar(res, dest)?; - } - - "SetLastError" => { - this.set_last_error(this.read_scalar(args[0])?.not_undef()?)?; - } - "GetLastError" => { - let last_error = this.get_last_error()?; - this.write_scalar(last_error, dest)?; - } - - "AddVectoredExceptionHandler" => { - // Any non zero value works for the stdlib. This is just used for stack overflows anyway. - this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; - } - - | "InitializeCriticalSection" - | "EnterCriticalSection" - | "LeaveCriticalSection" - | "DeleteCriticalSection" - => { - // Nothing to do, not even a return value. - } - - | "GetModuleHandleW" - | "GetProcAddress" - | "TryEnterCriticalSection" - | "GetConsoleScreenBufferInfo" - | "SetConsoleTextAttribute" - => { - // Pretend these do not exist / nothing happened, by returning zero. - this.write_null(dest)?; - } - - "GetSystemInfo" => { - let system_info = this.deref_operand(args[0])?; - // Initialize with `0`. - this.memory.write_bytes( - system_info.ptr, - iter::repeat(0u8).take(system_info.layout.size.bytes() as usize), - )?; - // Set number of processors. - let dword_size = Size::from_bytes(4); - let num_cpus = this.mplace_field(system_info, 6)?; - this.write_scalar(Scalar::from_int(NUM_CPUS, dword_size), num_cpus.into())?; - } - - "TlsAlloc" => { - // This just creates a key; Windows does not natively support TLS destructors. - - // Create key and return it. - let key = this.machine.tls.create_tls_key(None) as u128; - - // Figure out how large a TLS key actually is. This is `c::DWORD`. - if dest.layout.size.bits() < 128 - && key >= (1u128 << dest.layout.size.bits() as u128) - { - throw_unsup!(OutOfTls); - } - this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; - } - "TlsGetValue" => { - let key = this.read_scalar(args[0])?.to_u32()? as u128; - let ptr = this.machine.tls.load_tls(key, tcx)?; - this.write_scalar(ptr, dest)?; - } - "TlsSetValue" => { - let key = this.read_scalar(args[0])?.to_u32()? as u128; - let new_ptr = this.read_scalar(args[1])?.not_undef()?; - this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?; - - // Return success (`1`). - this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; - } - "GetStdHandle" => { - let which = this.read_scalar(args[0])?.to_i32()?; - // We just make this the identity function, so we know later in `WriteFile` - // which one it is. - this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?; - } - "GetConsoleMode" => { - // Everything is a pipe. - this.write_null(dest)?; - } - "GetCommandLineW" => { - this.write_scalar( - this.machine.cmd_line.expect("machine must be initialized"), - dest, - )?; - } - // The actual name of 'RtlGenRandom' - "SystemFunction036" => { - let ptr = this.read_scalar(args[0])?.not_undef()?; - let len = this.read_scalar(args[1])?.to_u32()?; - this.gen_random(ptr, len as usize)?; - this.write_scalar(Scalar::from_bool(true), dest)?; - } - _ => match this.tcx.sess.target.target.target_os.to_lowercase().as_str() { "linux" | "macos" => posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?, "windows" => windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?, diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index bc61aea18c73..31a0a815891e 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -38,6 +38,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "pthread_getattr_np" => { + this.write_null(dest)?; + } _ => throw_unsup_format!("can't call foreign function: {}", link_name), }; diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index e0ac92868a2c..8ed793b6c03c 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -53,6 +53,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + // macOS API stubs. + "pthread_attr_get_np" => { + this.write_null(dest)?; + } + "pthread_get_stackaddr_np" => { + let stack_addr = Scalar::from_uint(STACK_ADDR, dest.layout.size); + this.write_scalar(stack_addr, dest)?; + } + "pthread_get_stacksize_np" => { + let stack_size = Scalar::from_uint(STACK_SIZE, dest.layout.size); + this.write_scalar(stack_size, dest)?; + } + "_tlv_atexit" => { + // FIXME: register the destructor. + } + "_NSGetArgc" => { + this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?; + } + "_NSGetArgv" => { + this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; + } + "SecRandomCopyBytes" => { + let len = this.read_scalar(args[1])?.to_machine_usize(this)?; + let ptr = this.read_scalar(args[2])?.not_undef()?; + this.gen_random(ptr, len as usize)?; + this.write_null(dest)?; + } + + _ => throw_unsup_format!("can't call foreign function: {}", link_name), }; diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 23aa8ae7deb3..e16a89a126fd 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -1,5 +1,6 @@ use crate::*; use rustc::ty::layout::Size; +use std::iter; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -10,6 +11,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + let tcx = &{ this.tcx.tcx }; match link_name { // Environment related shims @@ -66,6 +68,132 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest, )?; } + // Windows API stubs. + // HANDLE = isize + // DWORD = ULONG = u32 + // BOOL = i32 + "GetProcessHeap" => { + // Just fake a HANDLE + this.write_scalar(Scalar::from_int(1, this.pointer_size()), dest)?; + } + "HeapAlloc" => { + let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?; + let flags = this.read_scalar(args[1])?.to_u32()?; + let size = this.read_scalar(args[2])?.to_machine_usize(this)?; + let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY + let res = this.malloc(size, zero_init, MiriMemoryKind::WinHeap); + this.write_scalar(res, dest)?; + } + "HeapFree" => { + let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?; + let _flags = this.read_scalar(args[1])?.to_u32()?; + let ptr = this.read_scalar(args[2])?.not_undef()?; + this.free(ptr, MiriMemoryKind::WinHeap)?; + this.write_scalar(Scalar::from_int(1, Size::from_bytes(4)), dest)?; + } + "HeapReAlloc" => { + let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?; + let _flags = this.read_scalar(args[1])?.to_u32()?; + let ptr = this.read_scalar(args[2])?.not_undef()?; + let size = this.read_scalar(args[3])?.to_machine_usize(this)?; + let res = this.realloc(ptr, size, MiriMemoryKind::WinHeap)?; + this.write_scalar(res, dest)?; + } + + "SetLastError" => { + this.set_last_error(this.read_scalar(args[0])?.not_undef()?)?; + } + "GetLastError" => { + let last_error = this.get_last_error()?; + this.write_scalar(last_error, dest)?; + } + + "AddVectoredExceptionHandler" => { + // Any non zero value works for the stdlib. This is just used for stack overflows anyway. + this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; + } + + | "InitializeCriticalSection" + | "EnterCriticalSection" + | "LeaveCriticalSection" + | "DeleteCriticalSection" + => { + // Nothing to do, not even a return value. + } + + | "GetModuleHandleW" + | "GetProcAddress" + | "TryEnterCriticalSection" + | "GetConsoleScreenBufferInfo" + | "SetConsoleTextAttribute" + => { + // Pretend these do not exist / nothing happened, by returning zero. + this.write_null(dest)?; + } + + "GetSystemInfo" => { + let system_info = this.deref_operand(args[0])?; + // Initialize with `0`. + this.memory.write_bytes( + system_info.ptr, + iter::repeat(0u8).take(system_info.layout.size.bytes() as usize), + )?; + // Set number of processors. + let dword_size = Size::from_bytes(4); + let num_cpus = this.mplace_field(system_info, 6)?; + this.write_scalar(Scalar::from_int(NUM_CPUS, dword_size), num_cpus.into())?; + } + + "TlsAlloc" => { + // This just creates a key; Windows does not natively support TLS destructors. + + // Create key and return it. + let key = this.machine.tls.create_tls_key(None) as u128; + + // Figure out how large a TLS key actually is. This is `c::DWORD`. + if dest.layout.size.bits() < 128 + && key >= (1u128 << dest.layout.size.bits() as u128) + { + throw_unsup!(OutOfTls); + } + this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; + } + "TlsGetValue" => { + let key = this.read_scalar(args[0])?.to_u32()? as u128; + let ptr = this.machine.tls.load_tls(key, tcx)?; + this.write_scalar(ptr, dest)?; + } + "TlsSetValue" => { + let key = this.read_scalar(args[0])?.to_u32()? as u128; + let new_ptr = this.read_scalar(args[1])?.not_undef()?; + this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?; + + // Return success (`1`). + this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; + } + "GetStdHandle" => { + let which = this.read_scalar(args[0])?.to_i32()?; + // We just make this the identity function, so we know later in `WriteFile` + // which one it is. + this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?; + } + "GetConsoleMode" => { + // Everything is a pipe. + this.write_null(dest)?; + } + "GetCommandLineW" => { + this.write_scalar( + this.machine.cmd_line.expect("machine must be initialized"), + dest, + )?; + } + // The actual name of 'RtlGenRandom' + "SystemFunction036" => { + let ptr = this.read_scalar(args[0])?.not_undef()?; + let len = this.read_scalar(args[1])?.to_u32()?; + this.gen_random(ptr, len as usize)?; + this.write_scalar(Scalar::from_bool(true), dest)?; + } _ => throw_unsup_format!("can't call foreign function: {}", link_name), } From c233c4ad9c84e138bc05db4fd5953239a9b0cd0a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 8 Feb 2020 11:58:42 -0500 Subject: [PATCH 1520/5092] migrate more functions --- src/shims/foreign_items.rs | 110 ------------------------- src/shims/foreign_items/posix.rs | 80 +++++++++++++++++- src/shims/foreign_items/posix/linux.rs | 34 ++++++++ src/shims/foreign_items/posix/macos.rs | 23 ++++++ 4 files changed, 136 insertions(+), 111 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index f8a61a7c5a12..6b4ce45f752f 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -208,33 +208,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C); this.write_scalar(res, dest)?; } - "posix_memalign" => { - let ret = this.deref_operand(args[0])?; - let align = this.read_scalar(args[1])?.to_machine_usize(this)?; - let size = this.read_scalar(args[2])?.to_machine_usize(this)?; - // Align must be power of 2, and also at least ptr-sized (POSIX rules). - if !align.is_power_of_two() { - throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); - } - if align < this.pointer_size().bytes() { - throw_ub_format!( - "posix_memalign: alignment must be at least the size of a pointer, but is {}", - align, - ); - } - - if size == 0 { - this.write_null(ret.into())?; - } else { - let ptr = this.memory.allocate( - Size::from_bytes(size), - Align::from_bytes(align).unwrap(), - MiriMemoryKind::C.into(), - ); - this.write_scalar(ptr, ret.into())?; - } - this.write_null(dest)?; - } "free" => { let ptr = this.read_scalar(args[0])?.not_undef()?; this.free(ptr, MiriMemoryKind::C)?; @@ -319,53 +292,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(new_ptr, dest)?; } - "syscall" => { - let sys_getrandom = this - .eval_path_scalar(&["libc", "SYS_getrandom"])? - .expect("Failed to get libc::SYS_getrandom") - .to_machine_usize(this)?; - - let sys_statx = this - .eval_path_scalar(&["libc", "SYS_statx"])? - .expect("Failed to get libc::SYS_statx") - .to_machine_usize(this)?; - - match this.read_scalar(args[0])?.to_machine_usize(this)? { - // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` - // is called if a `HashMap` is created the regular way (e.g. HashMap). - id if id == sys_getrandom => { - // The first argument is the syscall id, - // so skip over it. - linux_getrandom(this, &args[1..], dest)?; - } - id if id == sys_statx => { - // The first argument is the syscall id, - // so skip over it. - let result = this.statx(args[1], args[2], args[3], args[4], args[5])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - id => throw_unsup_format!("miri does not support syscall ID {}", id), - } - } - - "getrandom" => { - linux_getrandom(this, args, dest)?; - } - - "dlsym" => { - let _handle = this.read_scalar(args[0])?; - let symbol = this.read_scalar(args[1])?.not_undef()?; - let symbol_name = this.memory.read_c_str(symbol)?; - let err = format!("bad c unicode symbol: {:?}", symbol_name); - let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err); - if let Some(dlsym) = Dlsym::from_str(symbol_name)? { - let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); - this.write_scalar(Scalar::from(ptr), dest)?; - } else { - this.write_null(dest)?; - } - } - "memcmp" => { let left = this.read_scalar(args[0])?.not_undef()?; let right = this.read_scalar(args[1])?.not_undef()?; @@ -386,24 +312,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, Size::from_bits(32)), dest)?; } - "memrchr" => { - let ptr = this.read_scalar(args[0])?.not_undef()?; - let val = this.read_scalar(args[1])?.to_i32()? as u8; - let num = this.read_scalar(args[2])?.to_machine_usize(this)?; - if let Some(idx) = this - .memory - .read_bytes(ptr, Size::from_bytes(num))? - .iter() - .rev() - .position(|&c| c == val) - { - let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), this)?; - this.write_scalar(new_ptr, dest)?; - } else { - this.write_null(dest)?; - } - } - "memchr" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let val = this.read_scalar(args[1])?.to_i32()? as u8; @@ -728,21 +636,3 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(None); } } - -// Shims the linux 'getrandom()' syscall. -fn linux_getrandom<'tcx>( - this: &mut MiriEvalContext<'_, 'tcx>, - args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag>, -) -> InterpResult<'tcx> { - let ptr = this.read_scalar(args[0])?.not_undef()?; - let len = this.read_scalar(args[1])?.to_machine_usize(this)?; - - // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, - // neither of which have any effect on our current PRNG. - let _flags = this.read_scalar(args[2])?.to_i32()?; - - this.gen_random(ptr, len as usize)?; - this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; - Ok(()) -} diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index ecdec1fb165c..f738bdd7e6e0 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -2,7 +2,7 @@ mod linux; mod macos; use crate::*; -use rustc::ty::layout::Size; +use rustc::ty::layout::{Align, Size}; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -97,6 +97,66 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "posix_memalign" => { + let ret = this.deref_operand(args[0])?; + let align = this.read_scalar(args[1])?.to_machine_usize(this)?; + let size = this.read_scalar(args[2])?.to_machine_usize(this)?; + // Align must be power of 2, and also at least ptr-sized (POSIX rules). + if !align.is_power_of_two() { + throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); + } + if align < this.pointer_size().bytes() { + throw_ub_format!( + "posix_memalign: alignment must be at least the size of a pointer, but is {}", + align, + ); + } + + if size == 0 { + this.write_null(ret.into())?; + } else { + let ptr = this.memory.allocate( + Size::from_bytes(size), + Align::from_bytes(align).unwrap(), + MiriMemoryKind::C.into(), + ); + this.write_scalar(ptr, ret.into())?; + } + this.write_null(dest)?; + } + + "dlsym" => { + let _handle = this.read_scalar(args[0])?; + let symbol = this.read_scalar(args[1])?.not_undef()?; + let symbol_name = this.memory.read_c_str(symbol)?; + let err = format!("bad c unicode symbol: {:?}", symbol_name); + let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err); + if let Some(dlsym) = Dlsym::from_str(symbol_name)? { + let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); + this.write_scalar(Scalar::from(ptr), dest)?; + } else { + this.write_null(dest)?; + } + } + + "memrchr" => { + let ptr = this.read_scalar(args[0])?.not_undef()?; + let val = this.read_scalar(args[1])?.to_i32()? as u8; + let num = this.read_scalar(args[2])?.to_machine_usize(this)?; + if let Some(idx) = this + .memory + .read_bytes(ptr, Size::from_bytes(num))? + .iter() + .rev() + .position(|&c| c == val) + { + let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), this)?; + this.write_scalar(new_ptr, dest)?; + } else { + this.write_null(dest)?; + } + } + _ => { match this.tcx.sess.target.target.target_os.to_lowercase().as_str() { "linux" => linux::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?, @@ -109,3 +169,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } } + +// Shims the posix 'getrandom()' syscall. +fn getrandom<'tcx>( + this: &mut MiriEvalContext<'_, 'tcx>, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag>, +) -> InterpResult<'tcx> { + let ptr = this.read_scalar(args[0])?.not_undef()?; + let len = this.read_scalar(args[1])?.to_machine_usize(this)?; + + // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, + // neither of which have any effect on our current PRNG. + let _flags = this.read_scalar(args[2])?.to_i32()?; + + this.gen_random(ptr, len as usize)?; + this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; + Ok(()) +} diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 31a0a815891e..8d928b60ecbd 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -41,6 +41,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "pthread_getattr_np" => { this.write_null(dest)?; } + + "syscall" => { + let sys_getrandom = this + .eval_path_scalar(&["libc", "SYS_getrandom"])? + .expect("Failed to get libc::SYS_getrandom") + .to_machine_usize(this)?; + + let sys_statx = this + .eval_path_scalar(&["libc", "SYS_statx"])? + .expect("Failed to get libc::SYS_statx") + .to_machine_usize(this)?; + + match this.read_scalar(args[0])?.to_machine_usize(this)? { + // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` + // is called if a `HashMap` is created the regular way (e.g. HashMap). + id if id == sys_getrandom => { + // The first argument is the syscall id, + // so skip over it. + super::getrandom(this, &args[1..], dest)?; + } + id if id == sys_statx => { + // The first argument is the syscall id, + // so skip over it. + let result = this.statx(args[1], args[2], args[3], args[4], args[5])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + id => throw_unsup_format!("miri does not support syscall ID {}", id), + } + } + + "getrandom" => { + super::getrandom(this, args, dest)?; + } + _ => throw_unsup_format!("can't call foreign function: {}", link_name), }; diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 8ed793b6c03c..c4bfb98562db 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -57,23 +57,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "pthread_attr_get_np" => { this.write_null(dest)?; } + "pthread_get_stackaddr_np" => { let stack_addr = Scalar::from_uint(STACK_ADDR, dest.layout.size); this.write_scalar(stack_addr, dest)?; } + "pthread_get_stacksize_np" => { let stack_size = Scalar::from_uint(STACK_SIZE, dest.layout.size); this.write_scalar(stack_size, dest)?; } + "_tlv_atexit" => { // FIXME: register the destructor. } + "_NSGetArgc" => { this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?; } + "_NSGetArgv" => { this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; } + "SecRandomCopyBytes" => { let len = this.read_scalar(args[1])?.to_machine_usize(this)?; let ptr = this.read_scalar(args[2])?.not_undef()?; @@ -81,6 +87,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } + "syscall" => { + let sys_getrandom = this + .eval_path_scalar(&["libc", "SYS_getrandom"])? + .expect("Failed to get libc::SYS_getrandom") + .to_machine_usize(this)?; + + match this.read_scalar(args[0])?.to_machine_usize(this)? { + // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` + // is called if a `HashMap` is created the regular way (e.g. HashMap). + id if id == sys_getrandom => { + // The first argument is the syscall id, + // so skip over it. + super::getrandom(this, &args[1..], dest)?; + } + id => throw_unsup_format!("miri does not support syscall ID {}", id), + } + } _ => throw_unsup_format!("can't call foreign function: {}", link_name), }; From 39a78f0b2490cd2e0b2b2432209d6a230ef97979 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Feb 2020 13:47:31 +0100 Subject: [PATCH 1521/5092] make sure assertions and debug-assertions also panic (and can be caught) --- tests/run-pass/panic/catch_panic.rs | 4 ++++ tests/run-pass/panic/catch_panic.stderr | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index 722da68b70b2..84d4e56431b7 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -61,6 +61,10 @@ fn main() { test(|_old_val| { let _val = [0, 1, 2][4]; loop {} }); test(|_old_val| { let _val = 1/0; loop {} }); + // Assertion and debug assertion + test(|_old_val| { assert!(false); loop {} }); + test(|_old_val| { debug_assert!(false); loop {} }); + // Cleanup: reset to default hook. drop(std::panic::take_hook()); diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr index fd9a2f14ec3b..d4837f555494 100644 --- a/tests/run-pass/panic/catch_panic.stderr +++ b/tests/run-pass/panic/catch_panic.stderr @@ -16,4 +16,8 @@ thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4' Caught panic message (String): index out of bounds: the len is 3 but the index is 4 thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:62:34 Caught panic message (String): attempt to divide by zero +thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:65:23 +Caught panic message (&str): assertion failed: false +thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:66:23 +Caught panic message (&str): assertion failed: false Success! From 6ff5b3fcf94e5d0e58a9b2f7432b1f564bae9f46 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Feb 2020 13:55:51 +0100 Subject: [PATCH 1522/5092] make sure we also trigger debug assertions in libstd --- src/lib.rs | 2 +- tests/run-pass/panic/catch_panic.rs | 3 ++- tests/run-pass/panic/catch_panic.stderr | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 880a14b98c80..c34b90877d9d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,5 +62,5 @@ pub use crate::stacked_borrows::{ /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. pub fn miri_default_args() -> &'static [&'static str] { - &["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0", "--cfg=miri"] + &["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0", "--cfg=miri", "-Cdebug-assertions=on"] } diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index 84d4e56431b7..4d4206923a5e 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -1,4 +1,5 @@ // ignore-windows: Unwind panicking does not currently work on Windows +// normalize-stderr-test "[^ ]*libcore/macros/mod.rs[0-9:]*" -> "$$LOC" #![feature(never_type)] #![allow(const_err)] use std::panic::{catch_unwind, AssertUnwindSafe}; @@ -11,7 +12,6 @@ thread_local! { } struct DropTester; - impl Drop for DropTester { fn drop(&mut self) { DROPPED.with(|c| { @@ -64,6 +64,7 @@ fn main() { // Assertion and debug assertion test(|_old_val| { assert!(false); loop {} }); test(|_old_val| { debug_assert!(false); loop {} }); + test(|_old_val| { unsafe { (1 as *const i32).read() }; loop {} }); // trigger debug-assertion in libstd // Cleanup: reset to default hook. drop(std::panic::take_hook()); diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr index d4837f555494..636179beeade 100644 --- a/tests/run-pass/panic/catch_panic.stderr +++ b/tests/run-pass/panic/catch_panic.stderr @@ -20,4 +20,6 @@ thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:65:23 Caught panic message (&str): assertion failed: false thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:66:23 Caught panic message (&str): assertion failed: false +thread 'main' panicked at 'attempt to copy from unaligned or null pointer', $LOC +Caught panic message (String): attempt to copy from unaligned or null pointer Success! From 8acf52b3ca5ddc464d88ea6913d66706a3b70d4b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Feb 2020 14:01:00 +0100 Subject: [PATCH 1523/5092] fix compile-fail tests to avoid libstd debug assertions --- tests/compile-fail/copy_null.rs | 8 +++++++- tests/compile-fail/copy_overlapping.rs | 10 +++++++--- tests/compile-fail/copy_unaligned.rs | 8 +++++++- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/tests/compile-fail/copy_null.rs b/tests/compile-fail/copy_null.rs index 08391b12ae1b..ce2fbe170e45 100644 --- a/tests/compile-fail/copy_null.rs +++ b/tests/compile-fail/copy_null.rs @@ -1,8 +1,14 @@ //error-pattern: invalid use of NULL pointer +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); +} fn main() { let mut data = [0u16; 4]; let ptr = &mut data[0] as *mut u16; // Even copying 0 elements from NULL should error. - unsafe { ptr.copy_from(std::ptr::null(), 0); } + unsafe { copy_nonoverlapping(std::ptr::null(), ptr, 0); } } diff --git a/tests/compile-fail/copy_overlapping.rs b/tests/compile-fail/copy_overlapping.rs index 748bccff5d3a..76e1e20d2177 100644 --- a/tests/compile-fail/copy_overlapping.rs +++ b/tests/compile-fail/copy_overlapping.rs @@ -1,12 +1,16 @@ -#![feature(core_intrinsics)] - //error-pattern: copy_nonoverlapping called on overlapping ranges +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); +} fn main() { let mut data = [0u8; 16]; unsafe { let a = data.as_mut_ptr(); let b = a.wrapping_offset(1) as *mut _; - std::ptr::copy_nonoverlapping(a, b, 2); + copy_nonoverlapping(a, b, 2); } } diff --git a/tests/compile-fail/copy_unaligned.rs b/tests/compile-fail/copy_unaligned.rs index e1f243210ade..1a2692978f79 100644 --- a/tests/compile-fail/copy_unaligned.rs +++ b/tests/compile-fail/copy_unaligned.rs @@ -1,8 +1,14 @@ //error-pattern: tried to access memory with alignment 1, but alignment 2 is required +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); +} fn main() { let mut data = [0u16; 8]; let ptr = (&mut data[0] as *mut u16 as *mut u8).wrapping_add(1) as *mut u16; // Even copying 0 elements to something unaligned should error - unsafe { ptr.copy_from(&data[5], 0); } + unsafe { copy_nonoverlapping(&data[5], ptr, 0); } } From fda6104ee9bd7dee1f50a9ca2891ca27169040e0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Feb 2020 12:37:15 +0100 Subject: [PATCH 1524/5092] update README --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index cf18e6a0670b..b5e54e64bc40 100644 --- a/README.md +++ b/README.md @@ -147,8 +147,8 @@ Several `-Z` flags are relevant for Miri: * `-Zmiri-seed=` is a custom `-Z` flag added by Miri. It configures the seed of the RNG that Miri uses to resolve non-determinism. This RNG is used - to pick base addresses for allocations, and when the interpreted program - requests system entropy. The default seed is 0. + to pick base addresses for allocations. When isolation is enabled (the default), + this is also used to emulate system entropy. The default seed is 0. **NOTE**: This entropy is not good enough for cryptographic use! Do not generate secret keys in Miri or perform other kinds of cryptographic operations that rely on proper random numbers. @@ -157,8 +157,8 @@ Several `-Z` flags are relevant for Miri: useful for debugging. It means Miri will miss bugs in your program. However, this can also help to make Miri run faster. * `-Zmiri-disable-isolation` disables host host isolation. As a consequence, - the program has access to host resources such as environment variables and - randomness (and, eventually, file systems and more). + the program has access to host resources such as environment variables, file + systems, and randomness. * `-Zmiri-ignore-leaks` disables the memory leak checker. * `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from the host. Can be used multiple times to exclude several variables. The `TERM` From e449dccd3764b8adb1be4787b345eae9b0c7306e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Feb 2020 12:38:00 +0100 Subject: [PATCH 1525/5092] clarify caveats --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b5e54e64bc40..1f008e735ec2 100644 --- a/README.md +++ b/README.md @@ -14,13 +14,13 @@ for example: * Not sufficiently aligned memory accesses and references * Violation of *some* basic type invariants (a `bool` that is not 0 or 1, for example, or an invalid enum discriminant) -* WIP: Violations of the rules governing aliasing for reference types +* **Experimental**: Violations of the rules governing aliasing for reference types Miri has already discovered some [real-world bugs](#bugs-found-by-miri). If you found a bug with Miri, we'd appreciate if you tell us and we'll add it to the list! -Be aware that Miri will not catch all cases of undefined behavior in your +Be aware that Miri will **not catch all cases of undefined behavior** in your program, and cannot run all programs: * There are still plenty of open questions around the basic invariants for some From 085874d1ffd224dfe39a1aaa82e4f286b8614c91 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 26 Jan 2020 11:19:06 -0600 Subject: [PATCH 1526/5092] Add F_DUPFD/F_DUPFD_CLOEXEC to fcntl shim --- src/shims/fs.rs | 21 +++++++++++++++++++-- tests/run-pass/fs.rs | 2 ++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 2ae215e7204f..07390be2c8bb 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -28,7 +28,7 @@ impl Default for FileHandler { FileHandler { handles: Default::default(), // 0, 1 and 2 are reserved for stdin, stdout and stderr. - low: 3, + low: 2, } } } @@ -120,7 +120,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, fd_op: OpTy<'tcx, Tag>, cmd_op: OpTy<'tcx, Tag>, - _arg1_op: Option>, + arg_op: Option>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -139,6 +139,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { this.handle_not_found() } + } else if cmd == this.eval_libc_i32("F_DUPFD")? || cmd == this.eval_libc_i32("F_DUPFD_CLOEXEC")? { + let arg = match arg_op { + Some(arg_op) => this.read_scalar(arg_op)?.to_i32()?, + None => throw_unsup_format!("fcntl with command F_DUPFD or F_DUPFD_CLOEXEC requires a third argument"), + }; + let fh = &mut this.machine.file_handler; + let (file_result, writable) = match fh.handles.get(&fd) { + Some(original) => (original.file.try_clone(), original.writable), + None => return this.handle_not_found(), + }; + let fd_result = file_result.map(|duplicated| { + let new_fd = std::cmp::max(fh.low + 1, arg); + fh.low = new_fd; + fh.handles.insert(fh.low, FileHandle { file: duplicated, writable }).unwrap_none(); + new_fd + }); + this.try_unwrap_io_result(fd_result) } else { throw_unsup_format!("The {:#x} command is not supported for `fcntl`)", cmd); } diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 71c6e854f7c5..632ed13f2eac 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -41,6 +41,8 @@ fn main() { // Reading until EOF should get the whole text. file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); + // Cloning a file should be successful + file.try_clone().unwrap(); // Test that seeking to the beginning and reading until EOF gets the text again. file.seek(SeekFrom::Start(0)).unwrap(); From 3aff8038685e60c453182ec169babedeab19c606 Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 28 Jan 2020 23:18:09 -0600 Subject: [PATCH 1527/5092] Add comment --- src/shims/fs.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 07390be2c8bb..b766dd6de47a 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -140,6 +140,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.handle_not_found() } } else if cmd == this.eval_libc_i32("F_DUPFD")? || cmd == this.eval_libc_i32("F_DUPFD_CLOEXEC")? { + // Note that we always assume the FD_CLOEXEC flag is set for every open file, in part + // because exec() isn't supported. The F_DUPFD and F_DUPFD_CLOEXEC commands only + // differ in whether the FD_CLOEXEC flag is pre-set on the duplicated file descriptor, + // thus they can share the same implementation here. let arg = match arg_op { Some(arg_op) => this.read_scalar(arg_op)?.to_i32()?, None => throw_unsup_format!("fcntl with command F_DUPFD or F_DUPFD_CLOEXEC requires a third argument"), From 1de9d107cf0e6f922fc017606a675b6a727e2bd6 Mon Sep 17 00:00:00 2001 From: David Cook Date: Thu, 30 Jan 2020 18:31:34 -0600 Subject: [PATCH 1528/5092] Style fixes --- src/shims/fs.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index b766dd6de47a..d17ef79f0eed 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -142,12 +142,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if cmd == this.eval_libc_i32("F_DUPFD")? || cmd == this.eval_libc_i32("F_DUPFD_CLOEXEC")? { // Note that we always assume the FD_CLOEXEC flag is set for every open file, in part // because exec() isn't supported. The F_DUPFD and F_DUPFD_CLOEXEC commands only - // differ in whether the FD_CLOEXEC flag is pre-set on the duplicated file descriptor, + // differ in whether the FD_CLOEXEC flag is pre-set on the new file descriptor, // thus they can share the same implementation here. - let arg = match arg_op { - Some(arg_op) => this.read_scalar(arg_op)?.to_i32()?, - None => throw_unsup_format!("fcntl with command F_DUPFD or F_DUPFD_CLOEXEC requires a third argument"), - }; + let arg_op = arg_op + .ok_or_else(|| err_unsup_format!("fcntl with command F_DUPFD or F_DUPFD_CLOEXEC requires a third argument"))?; + let arg = this.read_scalar(arg_op)?.to_i32()?; let fh = &mut this.machine.file_handler; let (file_result, writable) = match fh.handles.get(&fd) { Some(original) => (original.file.try_clone(), original.writable), From eda35e153bc6f323d0707dff89a99d0034a1f39d Mon Sep 17 00:00:00 2001 From: David Cook Date: Thu, 30 Jan 2020 18:38:30 -0600 Subject: [PATCH 1529/5092] Add methods to FileHandler --- src/shims/fs.rs | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index d17ef79f0eed..792996f678d4 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -23,6 +23,17 @@ pub struct FileHandler { low: i32, } +impl FileHandler { + fn next_fd(&self) -> i32 { + self.low + 1 + } + + fn register_fd(&mut self, fd: i32, handle: FileHandle) { + self.low = fd; + self.handles.insert(fd, handle).unwrap_none(); + } +} + impl Default for FileHandler { fn default() -> Self { FileHandler { @@ -107,10 +118,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; let fd = options.open(&path).map(|file| { - let mut fh = &mut this.machine.file_handler; - fh.low += 1; - fh.handles.insert(fh.low, FileHandle { file, writable }).unwrap_none(); - fh.low + let fh = &mut this.machine.file_handler; + let fd = fh.next_fd(); + fh.register_fd(fd, FileHandle { file, writable }); + fd }); this.try_unwrap_io_result(fd) @@ -153,9 +164,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx None => return this.handle_not_found(), }; let fd_result = file_result.map(|duplicated| { - let new_fd = std::cmp::max(fh.low + 1, arg); - fh.low = new_fd; - fh.handles.insert(fh.low, FileHandle { file: duplicated, writable }).unwrap_none(); + let new_fd = std::cmp::max(fh.next_fd(), arg); + fh.register_fd(new_fd, FileHandle { file: duplicated, writable }); new_fd }); this.try_unwrap_io_result(fd_result) From 636ad629f8dc0d803b5738c78fb0ad44efb767c9 Mon Sep 17 00:00:00 2001 From: David Cook Date: Thu, 30 Jan 2020 18:43:34 -0600 Subject: [PATCH 1530/5092] Functional test of cloned file handle --- tests/run-pass/fs.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 632ed13f2eac..324630df1e94 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -41,8 +41,14 @@ fn main() { // Reading until EOF should get the whole text. file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); - // Cloning a file should be successful - file.try_clone().unwrap(); + + // Cloning a file should be successful. + let file = File::open(&path).unwrap(); + let mut cloned = file.try_clone().unwrap(); + // Reading from a cloned file should get the same text. + let mut contents = Vec::new(); + cloned.read_to_end(&mut contents).unwrap(); + assert_eq!(bytes, contents.as_slice()); // Test that seeking to the beginning and reading until EOF gets the text again. file.seek(SeekFrom::Start(0)).unwrap(); From 962a7404265ff59c13e5f548da64b45609f3065f Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 9 Feb 2020 14:43:45 -0600 Subject: [PATCH 1531/5092] Rewrite file descriptor handling --- src/shims/fs.rs | 116 +++++++++++++++++++++++++++---------------- tests/run-pass/fs.rs | 1 + 2 files changed, 74 insertions(+), 43 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 792996f678d4..26bcdbde0573 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::BTreeMap; use std::convert::{TryFrom, TryInto}; use std::fs::{remove_file, rename, File, OpenOptions}; use std::io::{Read, Seek, SeekFrom, Write}; @@ -13,34 +13,58 @@ use helpers::immty_from_uint_checked; use shims::time::system_time_to_duration; #[derive(Debug)] -pub struct FileHandle { - file: File, - writable: bool, +pub enum FileHandle { + StdInPlaceholder, + StdOutPlaceholder, + StdErrPlaceholder, + File { file: File, writable: bool }, + // In the future, could add support for dirfd() and other functions by + // adding a Directory variant here } pub struct FileHandler { - handles: HashMap, - low: i32, + handles: BTreeMap, } impl FileHandler { - fn next_fd(&self) -> i32 { - self.low + 1 + fn insert_fd(&mut self, file_handle: FileHandle) -> i32 { + self.insert_fd_with_min_fd(file_handle, 3) } - fn register_fd(&mut self, fd: i32, handle: FileHandle) { - self.low = fd; - self.handles.insert(fd, handle).unwrap_none(); + fn insert_fd_with_min_fd(&mut self, file_handle: FileHandle, min_fd: i32) -> i32 { + let min_fd = std::cmp::max(min_fd, 3); + let candidate_new_fd = self + .handles + .range(min_fd..) + .zip(min_fd..) + .find_map(|((fd, _fh), counter)| { + if *fd != counter { + // There was a gap in the fds stored, return the first unused one + // (note that this relies on BTreeMap iterating in key order) + Some(counter) + } else { + // This fd is used, keep going + None + } + }); + let new_fd = candidate_new_fd.unwrap_or_else(|| { + // find_map ran out of BTreeMap entries before finding a free fd, use one plus the + // maximum fd in the map + self.handles.keys().rev().next().map(|last_fd| last_fd + 1).unwrap_or(min_fd) + }); + self.handles.insert(new_fd, file_handle).unwrap_none(); + new_fd } } impl Default for FileHandler { fn default() -> Self { - FileHandler { - handles: Default::default(), - // 0, 1 and 2 are reserved for stdin, stdout and stderr. - low: 2, - } + let mut handles: BTreeMap = Default::default(); + // 0, 1 and 2 are reserved for stdin, stdout and stderr. + handles.insert(0, FileHandle::StdInPlaceholder); + handles.insert(1, FileHandle::StdOutPlaceholder); + handles.insert(2, FileHandle::StdErrPlaceholder); + FileHandler { handles } } } @@ -119,9 +143,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = options.open(&path).map(|file| { let fh = &mut this.machine.file_handler; - let fd = fh.next_fd(); - fh.register_fd(fd, FileHandle { file, writable }); - fd + fh.insert_fd(FileHandle::File { file, writable }) }); this.try_unwrap_io_result(fd) @@ -150,23 +172,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { this.handle_not_found() } - } else if cmd == this.eval_libc_i32("F_DUPFD")? || cmd == this.eval_libc_i32("F_DUPFD_CLOEXEC")? { + } else if cmd == this.eval_libc_i32("F_DUPFD")? + || cmd == this.eval_libc_i32("F_DUPFD_CLOEXEC")? + { // Note that we always assume the FD_CLOEXEC flag is set for every open file, in part // because exec() isn't supported. The F_DUPFD and F_DUPFD_CLOEXEC commands only // differ in whether the FD_CLOEXEC flag is pre-set on the new file descriptor, // thus they can share the same implementation here. - let arg_op = arg_op - .ok_or_else(|| err_unsup_format!("fcntl with command F_DUPFD or F_DUPFD_CLOEXEC requires a third argument"))?; + let arg_op = arg_op.ok_or_else(|| { + err_unsup_format!( + "fcntl with command F_DUPFD or F_DUPFD_CLOEXEC requires a third argument" + ) + })?; let arg = this.read_scalar(arg_op)?.to_i32()?; let fh = &mut this.machine.file_handler; let (file_result, writable) = match fh.handles.get(&fd) { - Some(original) => (original.file.try_clone(), original.writable), + Some(FileHandle::File { file, writable }) => (file.try_clone(), *writable), + Some(_) => throw_unsup_format!("Duplicating file descriptors for stdin, stdout, or stderr is not supported"), None => return this.handle_not_found(), }; let fd_result = file_result.map(|duplicated| { - let new_fd = std::cmp::max(fh.next_fd(), arg); - fh.register_fd(new_fd, FileHandle { file: duplicated, writable }); - new_fd + fh.insert_fd_with_min_fd(FileHandle::File { file: duplicated, writable }, arg) }); this.try_unwrap_io_result(fd_result) } else { @@ -181,23 +207,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; - if let Some(handle) = this.machine.file_handler.handles.remove(&fd) { + if fd <= 2 { + // early return to prevent removing StdInPlaceholder, etc., from the handles map + return this.handle_not_found(); + } + + if let Some(FileHandle::File { file, writable }) = this.machine.file_handler.handles.remove(&fd) { // We sync the file if it was opened in a mode different than read-only. - if handle.writable { + if writable { // `File::sync_all` does the checks that are done when closing a file. We do this to // to handle possible errors correctly. - let result = this.try_unwrap_io_result(handle.file.sync_all().map(|_| 0i32)); + let result = this.try_unwrap_io_result(file.sync_all().map(|_| 0i32)); // Now we actually close the file. - drop(handle); + drop(file); // And return the result. result } else { // We drop the file, this closes it but ignores any errors produced when closing - // it. This is done because `File::sync_call` cannot be done over files like + // it. This is done because `File::sync_all` cannot be done over files like // `/dev/urandom` which are read-only. Check // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439 for a deeper // discussion. - drop(handle); + drop(file); Ok(0) } } else { @@ -230,7 +261,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // host's and target's `isize`. This saves us from having to handle overflows later. let count = count.min(this.isize_max() as u64).min(isize::max_value() as u64); - if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { + if let Some(FileHandle::File { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { // This can never fail because `count` was capped to be smaller than // `isize::max_value()`. let count = isize::try_from(count).unwrap(); @@ -238,8 +269,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // because it was a target's `usize`. Also we are sure that its smaller than // `usize::max_value()` because it is a host's `isize`. let mut bytes = vec![0; count as usize]; - let result = handle - .file + let result = file .read(&mut bytes) // `File::read` never returns a value larger than `count`, so this cannot fail. .map(|c| i64::try_from(c).unwrap()); @@ -285,9 +315,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // host's and target's `isize`. This saves us from having to handle overflows later. let count = count.min(this.isize_max() as u64).min(isize::max_value() as u64); - if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { + if let Some(FileHandle::File { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; - let result = handle.file.write(&bytes).map(|c| i64::try_from(c).unwrap()); + let result = file.write(&bytes).map(|c| i64::try_from(c).unwrap()); this.try_unwrap_io_result(result) } else { this.handle_not_found() @@ -320,8 +350,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); }; - if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { - let result = handle.file.seek(seek_from).map(|offset| offset as i64); + if let Some(FileHandle::File { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { + let result = file.seek(seek_from).map(|offset| offset as i64); this.try_unwrap_io_result(result) } else { this.handle_not_found() @@ -682,11 +712,11 @@ impl FileMetadata { fd: i32, ) -> InterpResult<'tcx, Option> { let option = ecx.machine.file_handler.handles.get(&fd); - let handle = match option { - Some(handle) => handle, - None => return ecx.handle_not_found().map(|_: i32| None), + let file = match option { + Some(FileHandle::File { file, writable: _ }) => file, + Some(_) | None => return ecx.handle_not_found().map(|_: i32| None), }; - let metadata = handle.file.metadata(); + let metadata = file.metadata(); FileMetadata::from_meta(ecx, metadata) } diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 324630df1e94..8fc03bcb11b8 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -50,6 +50,7 @@ fn main() { cloned.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); + let mut file = File::open(&path).unwrap(); // Test that seeking to the beginning and reading until EOF gets the text again. file.seek(SeekFrom::Start(0)).unwrap(); let mut contents = Vec::new(); From a6a8f09f1e411cc1c3edbcabb7801db8d4dadc4f Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 16 Feb 2020 16:51:02 -0600 Subject: [PATCH 1532/5092] Address review comments --- src/lib.rs | 1 + src/shims/fs.rs | 16 +++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c34b90877d9d..85ee98aa3a12 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ #![feature(rustc_private)] #![feature(option_expect_none, option_unwrap_none)] +#![feature(map_first_last)] #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 26bcdbde0573..a0df362bcee4 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -33,6 +33,11 @@ impl FileHandler { fn insert_fd_with_min_fd(&mut self, file_handle: FileHandle, min_fd: i32) -> i32 { let min_fd = std::cmp::max(min_fd, 3); + + // Find the lowest unused FD, starting from min_fd. If the first such unused FD is in + // between used FDs, the find_map combinator will return it. If the first such unused FD + // is after all other used FDs, the find_map combinator will return None, and we will use + // the FD following the greatest FD thus far. let candidate_new_fd = self .handles .range(min_fd..) @@ -50,8 +55,9 @@ impl FileHandler { let new_fd = candidate_new_fd.unwrap_or_else(|| { // find_map ran out of BTreeMap entries before finding a free fd, use one plus the // maximum fd in the map - self.handles.keys().rev().next().map(|last_fd| last_fd + 1).unwrap_or(min_fd) + self.handles.last_entry().map(|entry| entry.key() + 1).unwrap_or(min_fd) }); + self.handles.insert(new_fd, file_handle).unwrap_none(); new_fd } @@ -153,7 +159,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, fd_op: OpTy<'tcx, Tag>, cmd_op: OpTy<'tcx, Tag>, - arg_op: Option>, + start_op: Option>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -179,12 +185,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // because exec() isn't supported. The F_DUPFD and F_DUPFD_CLOEXEC commands only // differ in whether the FD_CLOEXEC flag is pre-set on the new file descriptor, // thus they can share the same implementation here. - let arg_op = arg_op.ok_or_else(|| { + let start_op = start_op.ok_or_else(|| { err_unsup_format!( "fcntl with command F_DUPFD or F_DUPFD_CLOEXEC requires a third argument" ) })?; - let arg = this.read_scalar(arg_op)?.to_i32()?; + let start = this.read_scalar(start_op)?.to_i32()?; let fh = &mut this.machine.file_handler; let (file_result, writable) = match fh.handles.get(&fd) { Some(FileHandle::File { file, writable }) => (file.try_clone(), *writable), @@ -192,7 +198,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx None => return this.handle_not_found(), }; let fd_result = file_result.map(|duplicated| { - fh.insert_fd_with_min_fd(FileHandle::File { file: duplicated, writable }, arg) + fh.insert_fd_with_min_fd(FileHandle::File { file: duplicated, writable }, start) }); this.try_unwrap_io_result(fd_result) } else { From 8216f3c0f35aa948fe96d0eed17b0e5855799bd4 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 16 Feb 2020 16:59:54 -0600 Subject: [PATCH 1533/5092] Back out placeholder variants from FileHandle --- src/shims/fs.rs | 49 ++++++++++++++++--------------------------------- 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index a0df362bcee4..a3c45101a0b7 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -13,15 +13,12 @@ use helpers::immty_from_uint_checked; use shims::time::system_time_to_duration; #[derive(Debug)] -pub enum FileHandle { - StdInPlaceholder, - StdOutPlaceholder, - StdErrPlaceholder, - File { file: File, writable: bool }, - // In the future, could add support for dirfd() and other functions by - // adding a Directory variant here +pub struct FileHandle { + file: File, + writable: bool, } +#[derive(Debug, Default)] pub struct FileHandler { handles: BTreeMap, } @@ -63,17 +60,6 @@ impl FileHandler { } } -impl Default for FileHandler { - fn default() -> Self { - let mut handles: BTreeMap = Default::default(); - // 0, 1 and 2 are reserved for stdin, stdout and stderr. - handles.insert(0, FileHandle::StdInPlaceholder); - handles.insert(1, FileHandle::StdOutPlaceholder); - handles.insert(2, FileHandle::StdErrPlaceholder); - FileHandler { handles } - } -} - impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn open( @@ -149,7 +135,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = options.open(&path).map(|file| { let fh = &mut this.machine.file_handler; - fh.insert_fd(FileHandle::File { file, writable }) + fh.insert_fd(FileHandle { file, writable }) }); this.try_unwrap_io_result(fd) @@ -185,6 +171,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // because exec() isn't supported. The F_DUPFD and F_DUPFD_CLOEXEC commands only // differ in whether the FD_CLOEXEC flag is pre-set on the new file descriptor, // thus they can share the same implementation here. + if fd <= 2 { + throw_unsup_format!("Duplicating file descriptors for stdin, stdout, or stderr is not supported") + } let start_op = start_op.ok_or_else(|| { err_unsup_format!( "fcntl with command F_DUPFD or F_DUPFD_CLOEXEC requires a third argument" @@ -193,12 +182,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let start = this.read_scalar(start_op)?.to_i32()?; let fh = &mut this.machine.file_handler; let (file_result, writable) = match fh.handles.get(&fd) { - Some(FileHandle::File { file, writable }) => (file.try_clone(), *writable), - Some(_) => throw_unsup_format!("Duplicating file descriptors for stdin, stdout, or stderr is not supported"), + Some(FileHandle { file, writable }) => (file.try_clone(), *writable), None => return this.handle_not_found(), }; let fd_result = file_result.map(|duplicated| { - fh.insert_fd_with_min_fd(FileHandle::File { file: duplicated, writable }, start) + fh.insert_fd_with_min_fd(FileHandle { file: duplicated, writable }, start) }); this.try_unwrap_io_result(fd_result) } else { @@ -213,12 +201,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; - if fd <= 2 { - // early return to prevent removing StdInPlaceholder, etc., from the handles map - return this.handle_not_found(); - } - - if let Some(FileHandle::File { file, writable }) = this.machine.file_handler.handles.remove(&fd) { + if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.remove(&fd) { // We sync the file if it was opened in a mode different than read-only. if writable { // `File::sync_all` does the checks that are done when closing a file. We do this to @@ -267,7 +250,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // host's and target's `isize`. This saves us from having to handle overflows later. let count = count.min(this.isize_max() as u64).min(isize::max_value() as u64); - if let Some(FileHandle::File { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { + if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { // This can never fail because `count` was capped to be smaller than // `isize::max_value()`. let count = isize::try_from(count).unwrap(); @@ -321,7 +304,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // host's and target's `isize`. This saves us from having to handle overflows later. let count = count.min(this.isize_max() as u64).min(isize::max_value() as u64); - if let Some(FileHandle::File { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { + if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; let result = file.write(&bytes).map(|c| i64::try_from(c).unwrap()); this.try_unwrap_io_result(result) @@ -356,7 +339,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); }; - if let Some(FileHandle::File { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { + if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { let result = file.seek(seek_from).map(|offset| offset as i64); this.try_unwrap_io_result(result) } else { @@ -719,8 +702,8 @@ impl FileMetadata { ) -> InterpResult<'tcx, Option> { let option = ecx.machine.file_handler.handles.get(&fd); let file = match option { - Some(FileHandle::File { file, writable: _ }) => file, - Some(_) | None => return ecx.handle_not_found().map(|_: i32| None), + Some(FileHandle { file, writable: _ }) => file, + None => return ecx.handle_not_found().map(|_: i32| None), }; let metadata = file.metadata(); From 0933314bffefdd6dcec2705a157d8228acf6fb49 Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 17 Feb 2020 22:36:33 -0600 Subject: [PATCH 1534/5092] Rewrite file system tests --- tests/run-pass/fs.rs | 134 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 109 insertions(+), 25 deletions(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 8fc03bcb11b8..3851a4d45e92 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -5,25 +5,23 @@ use std::fs::{File, remove_file, rename}; use std::io::{Read, Write, ErrorKind, Result, Seek, SeekFrom}; use std::path::{PathBuf, Path}; -fn test_metadata(bytes: &[u8], path: &Path) -> Result<()> { - // Test that the file metadata is correct. - let metadata = path.metadata()?; - // `path` should point to a file. - assert!(metadata.is_file()); - // The size of the file must be equal to the number of written bytes. - assert_eq!(bytes.len() as u64, metadata.len()); - Ok(()) +fn main() { + test_file(); + test_file_clone(); + test_seek(); + test_metadata(); + test_symlink(); + test_errors(); + test_rename(); } -fn main() { +fn test_file() { let tmp = std::env::temp_dir(); - let filename = PathBuf::from("miri_test_fs.txt"); + let filename = PathBuf::from("miri_test_fs_file.txt"); let path = tmp.join(&filename); - let symlink_path = tmp.join("miri_test_fs_symlink.txt"); let bytes = b"Hello, World!\n"; // Clean the paths for robustness. remove_file(&path).ok(); - remove_file(&symlink_path).ok(); // Test creating, writing and closing a file (closing is tested when `file` is dropped). let mut file = File::create(&path).unwrap(); @@ -42,6 +40,21 @@ fn main() { file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); + // Removing file should succeed. + remove_file(&path).unwrap(); +} + +fn test_file_clone() { + let tmp = std::env::temp_dir(); + let filename = PathBuf::from("miri_test_fs_file_clone.txt"); + let path = tmp.join(&filename); + let bytes = b"Hello, World!\n"; + // Clean the paths for robustness. + remove_file(&path).ok(); + + let mut file = File::create(&path).unwrap(); + file.write(bytes).unwrap(); + // Cloning a file should be successful. let file = File::open(&path).unwrap(); let mut cloned = file.try_clone().unwrap(); @@ -50,7 +63,24 @@ fn main() { cloned.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); + // Removing file should succeed. + remove_file(&path).unwrap(); +} + +fn test_seek() { + let tmp = std::env::temp_dir(); + let filename = PathBuf::from("miri_test_fs_seek.txt"); + let path = tmp.join(&filename); + let bytes = b"Hello, World!\n"; + // Clean the paths for robustness. + remove_file(&path).ok(); + + let mut file = File::create(&path).unwrap(); + file.write(bytes).unwrap(); + let mut file = File::open(&path).unwrap(); + let mut contents = Vec::new(); + file.read_to_end(&mut contents).unwrap(); // Test that seeking to the beginning and reading until EOF gets the text again. file.seek(SeekFrom::Start(0)).unwrap(); let mut contents = Vec::new(); @@ -68,11 +98,53 @@ fn main() { file.read_to_end(&mut contents).unwrap(); assert_eq!(&bytes[2..], contents.as_slice()); + // Removing file should succeed. + remove_file(&path).unwrap(); +} + +fn check_metadata(bytes: &[u8], path: &Path) -> Result<()> { + // Test that the file metadata is correct. + let metadata = path.metadata()?; + // `path` should point to a file. + assert!(metadata.is_file()); + // The size of the file must be equal to the number of written bytes. + assert_eq!(bytes.len() as u64, metadata.len()); + Ok(()) +} + +fn test_metadata() { + let tmp = std::env::temp_dir(); + let filename = PathBuf::from("miri_test_fs_metadata.txt"); + let path = tmp.join(&filename); + let bytes = b"Hello, World!\n"; + // Clean the paths for robustness. + remove_file(&path).ok(); + + let mut file = File::create(&path).unwrap(); + file.write(bytes).unwrap(); + // Test that metadata of an absolute path is correct. - test_metadata(bytes, &path).unwrap(); + check_metadata(bytes, &path).unwrap(); // Test that metadata of a relative path is correct. std::env::set_current_dir(&tmp).unwrap(); - test_metadata(bytes, &filename).unwrap(); + check_metadata(bytes, &filename).unwrap(); + + // Removing file should succeed. + remove_file(&path).unwrap(); +} + +fn test_symlink() { + let tmp = std::env::temp_dir(); + let filename = PathBuf::from("miri_test_fs_link_target.txt"); + let path = tmp.join(&filename); + let symlink_path = tmp.join("miri_test_fs_symlink.txt"); + let bytes = b"Hello, World!\n"; + // Clean the paths for robustness. + remove_file(&path).ok(); + remove_file(&symlink_path).ok(); + + let mut file = File::create(&path).unwrap(); + file.write(bytes).unwrap(); // Creating a symbolic link should succeed. std::os::unix::fs::symlink(&path, &symlink_path).unwrap(); @@ -82,7 +154,7 @@ fn main() { symlink_file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); // Test that metadata of a symbolic link is correct. - test_metadata(bytes, &symlink_path).unwrap(); + check_metadata(bytes, &symlink_path).unwrap(); // Test that the metadata of a symbolic link is correct when not following it. assert!(symlink_path.symlink_metadata().unwrap().file_type().is_symlink()); // Removing symbolic link should succeed. @@ -90,10 +162,30 @@ fn main() { // Removing file should succeed. remove_file(&path).unwrap(); +} +fn test_errors() { + let tmp = std::env::temp_dir(); + let filename = PathBuf::from("miri_test_fs_errors.txt"); + let path = tmp.join(&filename); + let bytes = b"Hello, World!\n"; + // Clean the paths for robustness. + remove_file(&path).ok(); + + // The following tests also check that the `__errno_location()` shim is working properly. + // Opening a non-existing file should fail with a "not found" error. + assert_eq!(ErrorKind::NotFound, File::open(&path).unwrap_err().kind()); + // Removing a non-existing file should fail with a "not found" error. + assert_eq!(ErrorKind::NotFound, remove_file(&path).unwrap_err().kind()); + // Reading the metadata of a non-existing file should fail with a "not found" error. + assert_eq!(ErrorKind::NotFound, check_metadata(bytes, &path).unwrap_err().kind()); +} + +fn test_rename() { + let tmp = std::env::temp_dir(); // Renaming a file should succeed. - let path1 = tmp.join("rename_source.txt"); - let path2 = tmp.join("rename_destination.txt"); + let path1 = tmp.join("miri_test_fs_rename_source.txt"); + let path2 = tmp.join("miri_test_fs_rename_destination.txt"); // Clean files for robustness. remove_file(&path1).ok(); remove_file(&path2).ok(); @@ -103,12 +195,4 @@ fn main() { assert_eq!(ErrorKind::NotFound, path1.metadata().unwrap_err().kind()); assert!(path2.metadata().unwrap().is_file()); remove_file(&path2).unwrap(); - - // The two following tests also check that the `__errno_location()` shim is working properly. - // Opening a non-existing file should fail with a "not found" error. - assert_eq!(ErrorKind::NotFound, File::open(&path).unwrap_err().kind()); - // Removing a non-existing file should fail with a "not found" error. - assert_eq!(ErrorKind::NotFound, remove_file(&path).unwrap_err().kind()); - // Reading the metadata of a non-existing file should fail with a "not found" error. - assert_eq!(ErrorKind::NotFound, test_metadata(bytes, &path).unwrap_err().kind()); } From ae7d98b68fb34723bb0b8e18f1de71f7e0491397 Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 18 Feb 2020 18:06:33 -0600 Subject: [PATCH 1535/5092] Extract constant for minimum fd --- src/shims/fs.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index a3c45101a0b7..e5ed22634db9 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -23,13 +23,16 @@ pub struct FileHandler { handles: BTreeMap, } +// fd numbers 0, 1, and 2 are reserved for stdin, stdout, and stderr +const MIN_NORMAL_FILE_FD: i32 = 3; + impl FileHandler { fn insert_fd(&mut self, file_handle: FileHandle) -> i32 { - self.insert_fd_with_min_fd(file_handle, 3) + self.insert_fd_with_min_fd(file_handle, 0) } fn insert_fd_with_min_fd(&mut self, file_handle: FileHandle, min_fd: i32) -> i32 { - let min_fd = std::cmp::max(min_fd, 3); + let min_fd = std::cmp::max(min_fd, MIN_NORMAL_FILE_FD); // Find the lowest unused FD, starting from min_fd. If the first such unused FD is in // between used FDs, the find_map combinator will return it. If the first such unused FD @@ -171,7 +174,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // because exec() isn't supported. The F_DUPFD and F_DUPFD_CLOEXEC commands only // differ in whether the FD_CLOEXEC flag is pre-set on the new file descriptor, // thus they can share the same implementation here. - if fd <= 2 { + if fd < MIN_NORMAL_FILE_FD { throw_unsup_format!("Duplicating file descriptors for stdin, stdout, or stderr is not supported") } let start_op = start_op.ok_or_else(|| { From 56f9ee2c2d04f8c9fad132a22bcfb7e76874e98b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 Feb 2020 09:15:12 +0100 Subject: [PATCH 1536/5092] bump Rust (no changes needed) --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index a0f512a72700..12ac7b51b998 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -21ed50522ddb998f5367229984a4510af578899f +a2fb0c28be794f28028884650db70c17fea8e35b From 8b3176381690d01eb1cb50926ebb784bdac3ab9f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 Feb 2020 11:04:59 +0100 Subject: [PATCH 1537/5092] fs test: factor some common code --- tests/run-pass/fs.rs | 59 +++++++++++++++----------------------------- 1 file changed, 20 insertions(+), 39 deletions(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 3851a4d45e92..a69f9f3b23d8 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -15,13 +15,18 @@ fn main() { test_rename(); } -fn test_file() { +/// Prepare: compute filename and make sure the file does not exist. +fn prepare(filename: &str) -> PathBuf { let tmp = std::env::temp_dir(); - let filename = PathBuf::from("miri_test_fs_file.txt"); - let path = tmp.join(&filename); - let bytes = b"Hello, World!\n"; + let path = tmp.join(filename); // Clean the paths for robustness. remove_file(&path).ok(); + path +} + +fn test_file() { + let path = prepare("miri_test_fs_file.txt"); + let bytes = b"Hello, World!\n"; // Test creating, writing and closing a file (closing is tested when `file` is dropped). let mut file = File::create(&path).unwrap(); @@ -45,12 +50,8 @@ fn test_file() { } fn test_file_clone() { - let tmp = std::env::temp_dir(); - let filename = PathBuf::from("miri_test_fs_file_clone.txt"); - let path = tmp.join(&filename); + let path = prepare("miri_test_fs_file_clone.txt"); let bytes = b"Hello, World!\n"; - // Clean the paths for robustness. - remove_file(&path).ok(); let mut file = File::create(&path).unwrap(); file.write(bytes).unwrap(); @@ -68,12 +69,8 @@ fn test_file_clone() { } fn test_seek() { - let tmp = std::env::temp_dir(); - let filename = PathBuf::from("miri_test_fs_seek.txt"); - let path = tmp.join(&filename); + let path = prepare("miri_test_fs_seek.txt"); let bytes = b"Hello, World!\n"; - // Clean the paths for robustness. - remove_file(&path).ok(); let mut file = File::create(&path).unwrap(); file.write(bytes).unwrap(); @@ -113,12 +110,8 @@ fn check_metadata(bytes: &[u8], path: &Path) -> Result<()> { } fn test_metadata() { - let tmp = std::env::temp_dir(); - let filename = PathBuf::from("miri_test_fs_metadata.txt"); - let path = tmp.join(&filename); + let path = prepare("miri_test_fs_metadata.txt"); let bytes = b"Hello, World!\n"; - // Clean the paths for robustness. - remove_file(&path).ok(); let mut file = File::create(&path).unwrap(); file.write(bytes).unwrap(); @@ -126,22 +119,17 @@ fn test_metadata() { // Test that metadata of an absolute path is correct. check_metadata(bytes, &path).unwrap(); // Test that metadata of a relative path is correct. - std::env::set_current_dir(&tmp).unwrap(); - check_metadata(bytes, &filename).unwrap(); + std::env::set_current_dir(path.parent().unwrap()).unwrap(); + check_metadata(bytes, Path::new(path.file_name().unwrap())).unwrap(); // Removing file should succeed. remove_file(&path).unwrap(); } fn test_symlink() { - let tmp = std::env::temp_dir(); - let filename = PathBuf::from("miri_test_fs_link_target.txt"); - let path = tmp.join(&filename); - let symlink_path = tmp.join("miri_test_fs_symlink.txt"); + let path = prepare("miri_test_fs_link_target.txt"); + let symlink_path = prepare("miri_test_fs_symlink.txt"); let bytes = b"Hello, World!\n"; - // Clean the paths for robustness. - remove_file(&path).ok(); - remove_file(&symlink_path).ok(); let mut file = File::create(&path).unwrap(); file.write(bytes).unwrap(); @@ -165,12 +153,8 @@ fn test_symlink() { } fn test_errors() { - let tmp = std::env::temp_dir(); - let filename = PathBuf::from("miri_test_fs_errors.txt"); - let path = tmp.join(&filename); + let path = prepare("miri_test_fs_errors.txt"); let bytes = b"Hello, World!\n"; - // Clean the paths for robustness. - remove_file(&path).ok(); // The following tests also check that the `__errno_location()` shim is working properly. // Opening a non-existing file should fail with a "not found" error. @@ -182,13 +166,10 @@ fn test_errors() { } fn test_rename() { - let tmp = std::env::temp_dir(); // Renaming a file should succeed. - let path1 = tmp.join("miri_test_fs_rename_source.txt"); - let path2 = tmp.join("miri_test_fs_rename_destination.txt"); - // Clean files for robustness. - remove_file(&path1).ok(); - remove_file(&path2).ok(); + let path1 = prepare("miri_test_fs_rename_source.txt"); + let path2 = prepare("miri_test_fs_rename_destination.txt"); + let file = File::create(&path1).unwrap(); drop(file); rename(&path1, &path2).unwrap(); From f79c453860ce113374029685b2b78b966a89559e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 Feb 2020 11:08:24 +0100 Subject: [PATCH 1538/5092] factor more common code --- tests/run-pass/fs.rs | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index a69f9f3b23d8..ebbd0b0c57ca 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -24,9 +24,17 @@ fn prepare(filename: &str) -> PathBuf { path } +/// Prepare like above, and also write some initial content to the file. +fn prepare_with_content(filename: &str, content: &[u8]) -> PathBuf { + let path = prepare(filename); + let mut file = File::create(&path).unwrap(); + file.write(content).unwrap(); + path +} + fn test_file() { - let path = prepare("miri_test_fs_file.txt"); let bytes = b"Hello, World!\n"; + let path = prepare("miri_test_fs_file.txt"); // Test creating, writing and closing a file (closing is tested when `file` is dropped). let mut file = File::create(&path).unwrap(); @@ -50,11 +58,8 @@ fn test_file() { } fn test_file_clone() { - let path = prepare("miri_test_fs_file_clone.txt"); let bytes = b"Hello, World!\n"; - - let mut file = File::create(&path).unwrap(); - file.write(bytes).unwrap(); + let path = prepare_with_content("miri_test_fs_file_clone.txt", bytes); // Cloning a file should be successful. let file = File::open(&path).unwrap(); @@ -69,11 +74,8 @@ fn test_file_clone() { } fn test_seek() { - let path = prepare("miri_test_fs_seek.txt"); - let bytes = b"Hello, World!\n"; - - let mut file = File::create(&path).unwrap(); - file.write(bytes).unwrap(); + let bytes = b"Hello, entire World!\n"; + let path = prepare_with_content("miri_test_fs_seek.txt", bytes); let mut file = File::open(&path).unwrap(); let mut contents = Vec::new(); @@ -110,11 +112,8 @@ fn check_metadata(bytes: &[u8], path: &Path) -> Result<()> { } fn test_metadata() { - let path = prepare("miri_test_fs_metadata.txt"); - let bytes = b"Hello, World!\n"; - - let mut file = File::create(&path).unwrap(); - file.write(bytes).unwrap(); + let bytes = b"Hello, meta-World!\n"; + let path = prepare_with_content("miri_test_fs_metadata.txt", bytes); // Test that metadata of an absolute path is correct. check_metadata(bytes, &path).unwrap(); @@ -127,12 +126,9 @@ fn test_metadata() { } fn test_symlink() { - let path = prepare("miri_test_fs_link_target.txt"); - let symlink_path = prepare("miri_test_fs_symlink.txt"); let bytes = b"Hello, World!\n"; - - let mut file = File::create(&path).unwrap(); - file.write(bytes).unwrap(); + let path = prepare_with_content("miri_test_fs_link_target.txt", bytes); + let symlink_path = prepare("miri_test_fs_symlink.txt"); // Creating a symbolic link should succeed. std::os::unix::fs::symlink(&path, &symlink_path).unwrap(); @@ -153,8 +149,8 @@ fn test_symlink() { } fn test_errors() { - let path = prepare("miri_test_fs_errors.txt"); let bytes = b"Hello, World!\n"; + let path = prepare("miri_test_fs_errors.txt"); // The following tests also check that the `__errno_location()` shim is working properly. // Opening a non-existing file should fail with a "not found" error. From 3cd13cb1746193f077766985273b144beba01480 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 Feb 2020 11:14:30 +0100 Subject: [PATCH 1539/5092] test a bit more --- tests/run-pass/fs.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index ebbd0b0c57ca..453432f64f10 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -80,6 +80,7 @@ fn test_seek() { let mut file = File::open(&path).unwrap(); let mut contents = Vec::new(); file.read_to_end(&mut contents).unwrap(); + assert_eq!(bytes, contents.as_slice()); // Test that seeking to the beginning and reading until EOF gets the text again. file.seek(SeekFrom::Start(0)).unwrap(); let mut contents = Vec::new(); From 8fe7543191e10145ba56f676f529e9db4664dee0 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 8 Feb 2020 13:29:26 -0500 Subject: [PATCH 1540/5092] add helper function for target platform checks --- src/helpers.rs | 13 +++++++++++++ src/shims/fs.rs | 16 ++++------------ 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index a765d58bbcf3..c92aa6dfaa7c 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -368,6 +368,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(()) } + /// Helper function used inside the shims of foreign functions to check that the target + /// platform is `platform`. It returns an error using the `name` of the foreign function if + /// this is not the case. + fn check_platform(&mut self, platform: &str, name: &str) -> InterpResult<'tcx> { + if self.eval_context_mut().tcx.sess.target.target.target_os.to_lowercase() != platform { + throw_unsup_format!( + "`{}` is only available in the `{}` platform", + name, + platform, + ) + } + Ok(()) + } /// Sets the last error variable. fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 2ae215e7204f..42a860780ff8 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -347,6 +347,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.check_no_isolation("stat")?; + this.check_platform("macos", "stat")?; // `stat` always follows symlinks. this.stat_or_lstat(true, path_op, buf_op) } @@ -359,6 +360,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.check_no_isolation("lstat")?; + this.check_platform("macos", "lstat")?; this.stat_or_lstat(false, path_op, buf_op) } @@ -370,10 +372,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.check_no_isolation("fstat")?; - - if this.tcx.sess.target.target.target_os.to_lowercase() != "macos" { - throw_unsup_format!("The `fstat` shim is only available for `macos` targets.") - } + this.check_platform("macos", "fstat")?; let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -392,10 +391,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if this.tcx.sess.target.target.target_os.to_lowercase() != "macos" { - throw_unsup_format!("The `stat` and `lstat` shims are only available for `macos` targets.") - } - let path_scalar = this.read_scalar(path_op)?.not_undef()?; let path: PathBuf = this.read_os_str_from_c_str(path_scalar)?.into(); @@ -417,10 +412,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.check_no_isolation("statx")?; - - if this.tcx.sess.target.target.target_os.to_lowercase() != "linux" { - throw_unsup_format!("The `statx` shim is only available for `linux` targets.") - } + this.check_platform("linux", "statx")?; let statxbuf_scalar = this.read_scalar(statxbuf_op)?.not_undef()?; let pathname_scalar = this.read_scalar(pathname_op)?.not_undef()?; From 63160c66cd31c6f48a4a68ff469c4bdebc8eff2f Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 11 Feb 2020 18:32:28 -0500 Subject: [PATCH 1541/5092] move pthread related functions --- src/shims/foreign_items.rs | 112 +------------------------------ src/shims/foreign_items/posix.rs | 112 ++++++++++++++++++++++++++++++- 2 files changed, 112 insertions(+), 112 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 6b4ce45f752f..9ad4a6dbaf62 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -6,7 +6,7 @@ use std::{convert::TryInto, iter}; use rustc_hir::def_id::DefId; use rustc::mir; use rustc::ty; -use rustc::ty::layout::{Align, LayoutOf, Size}; +use rustc::ty::layout::{Align, Size}; use rustc_apfloat::Float; use rustc_span::symbol::sym; use syntax::attr; @@ -192,7 +192,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let tcx = &{ this.tcx.tcx }; match link_name { "malloc" => { @@ -487,115 +486,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - // Hook pthread calls that go to the thread-local storage memory subsystem. - "pthread_key_create" => { - let key_place = this.deref_operand(args[0])?; - - // Extract the function type out of the signature (that seems easier than constructing it ourselves). - let dtor = match this.test_null(this.read_scalar(args[1])?.not_undef()?)? { - Some(dtor_ptr) => Some(this.memory.get_fn(dtor_ptr)?.as_instance()?), - None => None, - }; - - // Figure out how large a pthread TLS key actually is. - // This is `libc::pthread_key_t`. - let key_type = args[0].layout.ty - .builtin_deref(true) - .ok_or_else(|| err_ub_format!( - "wrong signature used for `pthread_key_create`: first argument must be a raw pointer." - ))? - .ty; - let key_layout = this.layout_of(key_type)?; - - // Create key and write it into the memory where `key_ptr` wants it. - let key = this.machine.tls.create_tls_key(dtor) as u128; - if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) - { - throw_unsup!(OutOfTls); - } - - this.write_scalar(Scalar::from_uint(key, key_layout.size), key_place.into())?; - - // Return success (`0`). - this.write_null(dest)?; - } - "pthread_key_delete" => { - let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; - this.machine.tls.delete_tls_key(key)?; - // Return success (0) - this.write_null(dest)?; - } - "pthread_getspecific" => { - let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; - let ptr = this.machine.tls.load_tls(key, tcx)?; - this.write_scalar(ptr, dest)?; - } - "pthread_setspecific" => { - let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; - let new_ptr = this.read_scalar(args[1])?.not_undef()?; - this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?; - - // Return success (`0`). - this.write_null(dest)?; - } - - // Stack size/address stuff. - | "pthread_attr_init" - | "pthread_attr_destroy" - | "pthread_self" - | "pthread_attr_setstacksize" => { - this.write_null(dest)?; - } - "pthread_attr_getstack" => { - let addr_place = this.deref_operand(args[1])?; - let size_place = this.deref_operand(args[2])?; - - this.write_scalar( - Scalar::from_uint(STACK_ADDR, addr_place.layout.size), - addr_place.into(), - )?; - this.write_scalar( - Scalar::from_uint(STACK_SIZE, size_place.layout.size), - size_place.into(), - )?; - - // Return success (`0`). - this.write_null(dest)?; - } - - // We don't support threading. (Also for Windows.) - | "pthread_create" - | "CreateThread" - => { - throw_unsup_format!("Miri does not support threading"); - } - - // Stub out calls for condvar, mutex and rwlock, to just return `0`. - | "pthread_mutexattr_init" - | "pthread_mutexattr_settype" - | "pthread_mutex_init" - | "pthread_mutexattr_destroy" - | "pthread_mutex_lock" - | "pthread_mutex_unlock" - | "pthread_mutex_destroy" - | "pthread_rwlock_rdlock" - | "pthread_rwlock_unlock" - | "pthread_rwlock_wrlock" - | "pthread_rwlock_destroy" - | "pthread_condattr_init" - | "pthread_condattr_setclock" - | "pthread_cond_init" - | "pthread_condattr_destroy" - | "pthread_cond_destroy" - => { - this.write_null(dest)?; - } - - // We don't support fork so we don't have to do anything for atfork. - "pthread_atfork" => { - this.write_null(dest)?; - } - "posix_fadvise" => { // fadvise is only informational, we can ignore it. this.write_null(dest)?; diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index f738bdd7e6e0..2ec8b9d7a601 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -2,7 +2,7 @@ mod linux; mod macos; use crate::*; -use rustc::ty::layout::{Align, Size}; +use rustc::ty::layout::{Align, LayoutOf, Size}; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -157,6 +157,116 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + // Hook pthread calls that go to the thread-local storage memory subsystem. + "pthread_key_create" => { + let key_place = this.deref_operand(args[0])?; + + // Extract the function type out of the signature (that seems easier than constructing it ourselves). + let dtor = match this.test_null(this.read_scalar(args[1])?.not_undef()?)? { + Some(dtor_ptr) => Some(this.memory.get_fn(dtor_ptr)?.as_instance()?), + None => None, + }; + + // Figure out how large a pthread TLS key actually is. + // This is `libc::pthread_key_t`. + let key_type = args[0].layout.ty + .builtin_deref(true) + .ok_or_else(|| err_ub_format!( + "wrong signature used for `pthread_key_create`: first argument must be a raw pointer." + ))? + .ty; + let key_layout = this.layout_of(key_type)?; + + // Create key and write it into the memory where `key_ptr` wants it. + let key = this.machine.tls.create_tls_key(dtor) as u128; + if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) + { + throw_unsup!(OutOfTls); + } + + this.write_scalar(Scalar::from_uint(key, key_layout.size), key_place.into())?; + + // Return success (`0`). + this.write_null(dest)?; + } + "pthread_key_delete" => { + let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; + this.machine.tls.delete_tls_key(key)?; + // Return success (0) + this.write_null(dest)?; + } + "pthread_getspecific" => { + let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; + let ptr = this.machine.tls.load_tls(key, tcx)?; + this.write_scalar(ptr, dest)?; + } + "pthread_setspecific" => { + let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; + let new_ptr = this.read_scalar(args[1])?.not_undef()?; + this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?; + + // Return success (`0`). + this.write_null(dest)?; + } + + // Stack size/address stuff. + | "pthread_attr_init" + | "pthread_attr_destroy" + | "pthread_self" + | "pthread_attr_setstacksize" => { + this.write_null(dest)?; + } + "pthread_attr_getstack" => { + let addr_place = this.deref_operand(args[1])?; + let size_place = this.deref_operand(args[2])?; + + this.write_scalar( + Scalar::from_uint(STACK_ADDR, addr_place.layout.size), + addr_place.into(), + )?; + this.write_scalar( + Scalar::from_uint(STACK_SIZE, size_place.layout.size), + size_place.into(), + )?; + + // Return success (`0`). + this.write_null(dest)?; + } + + // We don't support threading. (Also for Windows.) + | "pthread_create" + | "CreateThread" + => { + throw_unsup_format!("Miri does not support threading"); + } + + // Stub out calls for condvar, mutex and rwlock, to just return `0`. + | "pthread_mutexattr_init" + | "pthread_mutexattr_settype" + | "pthread_mutex_init" + | "pthread_mutexattr_destroy" + | "pthread_mutex_lock" + | "pthread_mutex_unlock" + | "pthread_mutex_destroy" + | "pthread_rwlock_rdlock" + | "pthread_rwlock_unlock" + | "pthread_rwlock_wrlock" + | "pthread_rwlock_destroy" + | "pthread_condattr_init" + | "pthread_condattr_setclock" + | "pthread_cond_init" + | "pthread_condattr_destroy" + | "pthread_cond_destroy" + => { + this.write_null(dest)?; + } + + // We don't support fork so we don't have to do anything for atfork. + "pthread_atfork" => { + this.write_null(dest)?; + } + + _ => { match this.tcx.sess.target.target.target_os.to_lowercase().as_str() { "linux" => linux::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?, From b81949358540fd4da759b943f8a2d7382fc2a0e3 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 11 Feb 2020 18:48:38 -0500 Subject: [PATCH 1542/5092] move remaining shims --- src/shims/foreign_items.rs | 63 +------------------------- src/shims/foreign_items/posix.rs | 56 +++++++++++++++++++++++ src/shims/foreign_items/posix/linux.rs | 5 ++ 3 files changed, 63 insertions(+), 61 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 9ad4a6dbaf62..59f9a8c63a7e 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -193,6 +193,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + // Here we dispatch all the shims for foreign functions. If you have a platform specific + // shim, add it to the corresponding submodule. match link_name { "malloc" => { let size = this.read_scalar(args[0])?.to_machine_usize(this)?; @@ -439,67 +441,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_f64(res), dest)?; } - // Some things needed for `sys::thread` initialization to go through. - | "signal" - | "sigaction" - | "sigaltstack" - => { - this.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?; - } - - "sysconf" => { - let name = this.read_scalar(args[0])?.to_i32()?; - - trace!("sysconf() called with name {}", name); - // TODO: Cache the sysconf integers via Miri's global cache. - let paths = &[ - (&["libc", "_SC_PAGESIZE"], Scalar::from_int(PAGE_SIZE, dest.layout.size)), - (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)), - ( - &["libc", "_SC_NPROCESSORS_ONLN"], - Scalar::from_int(NUM_CPUS, dest.layout.size), - ), - ]; - let mut result = None; - for &(path, path_value) in paths { - if let Some(val) = this.eval_path_scalar(path)? { - let val = val.to_i32()?; - if val == name { - result = Some(path_value); - break; - } - } - } - if let Some(result) = result { - this.write_scalar(result, dest)?; - } else { - throw_unsup_format!("Unimplemented sysconf name: {}", name) - } - } - - "sched_getaffinity" => { - // Return an error; `num_cpus` then falls back to `sysconf`. - this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; - } - - "isatty" => { - this.write_null(dest)?; - } - - "posix_fadvise" => { - // fadvise is only informational, we can ignore it. - this.write_null(dest)?; - } - - "mmap" => { - // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. - let addr = this.read_scalar(args[0])?.not_undef()?; - this.write_scalar(addr, dest)?; - } - "mprotect" => { - this.write_null(dest)?; - } - _ => match this.tcx.sess.target.target.target_os.to_lowercase().as_str() { "linux" | "macos" => posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?, "windows" => windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?, diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 2ec8b9d7a601..f524e4df291e 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -266,6 +266,62 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } + // Some things needed for `sys::thread` initialization to go through. + | "signal" + | "sigaction" + | "sigaltstack" + => { + this.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?; + } + + "sysconf" => { + let name = this.read_scalar(args[0])?.to_i32()?; + + trace!("sysconf() called with name {}", name); + // TODO: Cache the sysconf integers via Miri's global cache. + let paths = &[ + (&["libc", "_SC_PAGESIZE"], Scalar::from_int(PAGE_SIZE, dest.layout.size)), + (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)), + ( + &["libc", "_SC_NPROCESSORS_ONLN"], + Scalar::from_int(NUM_CPUS, dest.layout.size), + ), + ]; + let mut result = None; + for &(path, path_value) in paths { + if let Some(val) = this.eval_path_scalar(path)? { + let val = val.to_i32()?; + if val == name { + result = Some(path_value); + break; + } + } + } + if let Some(result) = result { + this.write_scalar(result, dest)?; + } else { + throw_unsup_format!("Unimplemented sysconf name: {}", name) + } + } + + "isatty" => { + this.write_null(dest)?; + } + + "posix_fadvise" => { + // fadvise is only informational, we can ignore it. + this.write_null(dest)?; + } + + "mmap" => { + // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. + let addr = this.read_scalar(args[0])?.not_undef()?; + this.write_scalar(addr, dest)?; + } + + "mprotect" => { + this.write_null(dest)?; + } _ => { match this.tcx.sess.target.target.target_os.to_lowercase().as_str() { diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 8d928b60ecbd..7267cc1af8e5 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -75,6 +75,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx super::getrandom(this, args, dest)?; } + "sched_getaffinity" => { + // Return an error; `num_cpus` then falls back to `sysconf`. + this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; + } + _ => throw_unsup_format!("can't call foreign function: {}", link_name), }; From 1dbc0c9869071df351dd40a28e0e3d78c5105bfa Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 11 Feb 2020 19:00:41 -0500 Subject: [PATCH 1543/5092] remove hack for panics --- src/shims/foreign_items.rs | 35 +++++++++++--------------- src/shims/foreign_items/posix.rs | 15 ++++++++--- src/shims/foreign_items/posix/linux.rs | 6 +++-- src/shims/foreign_items/posix/macos.rs | 6 +++-- src/shims/foreign_items/windows.rs | 6 +++-- 5 files changed, 37 insertions(+), 31 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 59f9a8c63a7e..14e08f5181f5 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -170,17 +170,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Next: functions that return. - match link_name { - "__rust_maybe_catch_panic" => { - this.handle_catch_panic(args, dest, ret)?; - return Ok(None); - } - - _ => this.emulate_foreign_item_by_name(link_name, args, dest)?, - }; - - this.dump_place(*dest); - this.go_to_block(ret); + if this.emulate_foreign_item_by_name(link_name, args, dest, ret)? { + this.dump_place(*dest); + this.go_to_block(ret); + } Ok(None) } @@ -190,7 +183,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx link_name: &str, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { + ret: mir::BasicBlock, + ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); // Here we dispatch all the shims for foreign functions. If you have a platform specific @@ -293,6 +287,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(new_ptr, dest)?; } + "__rust_maybe_catch_panic" => { + this.handle_catch_panic(args, dest, ret)?; + return Ok(false); + } + "memcmp" => { let left = this.read_scalar(args[0])?.not_undef()?; let right = this.read_scalar(args[1])?.not_undef()?; @@ -330,12 +329,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - - "rename" => { - let result = this.rename(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - "strlen" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let n = this.memory.read_c_str(ptr)?.len(); @@ -442,13 +435,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } _ => match this.tcx.sess.target.target.target_os.to_lowercase().as_str() { - "linux" | "macos" => posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?, - "windows" => windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?, + "linux" | "macos" => return posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), + "windows" => return windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), target => throw_unsup_format!("The {} target platform is not supported", target), } }; - Ok(()) + Ok(true) } /// Evaluates the scalar at the specified path. Returns Some(val) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index f524e4df291e..746a0f25ebb1 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -2,6 +2,7 @@ mod linux; mod macos; use crate::*; +use rustc::mir; use rustc::ty::layout::{Align, LayoutOf, Size}; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -11,7 +12,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx link_name: &str, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { + ret: mir::BasicBlock, + ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); let tcx = &{ this.tcx.tcx }; @@ -97,6 +99,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "rename" => { + let result = this.rename(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + "posix_memalign" => { let ret = this.deref_operand(args[0])?; let align = this.read_scalar(args[1])?.to_machine_usize(this)?; @@ -325,14 +332,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => { match this.tcx.sess.target.target.target_os.to_lowercase().as_str() { - "linux" => linux::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?, - "macos" => macos::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?, + "linux" => return linux::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), + "macos" => return macos::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), _ => unreachable!(), } } }; - Ok(()) + Ok(true) } } diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 7267cc1af8e5..27e42b0082e5 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -1,4 +1,5 @@ use crate::*; +use rustc::mir; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -7,7 +8,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx link_name: &str, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { + _ret: mir::BasicBlock, + ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); match link_name { @@ -83,6 +85,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => throw_unsup_format!("can't call foreign function: {}", link_name), }; - Ok(()) + Ok(true) } } diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index c4bfb98562db..274248e8b54f 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -1,4 +1,5 @@ use crate::*; +use rustc::mir; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -7,7 +8,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx link_name: &str, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { + _ret: mir::BasicBlock, + ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); match link_name { @@ -108,7 +110,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => throw_unsup_format!("can't call foreign function: {}", link_name), }; - Ok(()) + Ok(true) } } diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index e16a89a126fd..b0d323439714 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -1,4 +1,5 @@ use crate::*; +use rustc::mir; use rustc::ty::layout::Size; use std::iter; @@ -9,7 +10,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx link_name: &str, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { + _ret: mir::BasicBlock, + ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); let tcx = &{ this.tcx.tcx }; @@ -197,7 +199,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => throw_unsup_format!("can't call foreign function: {}", link_name), } - Ok(()) + Ok(true) } } From bc7513bffd45c6dd52b94d29dd43e5c436c73d68 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 19 Feb 2020 16:52:34 -0500 Subject: [PATCH 1544/5092] move CreateThread to windows shims --- src/shims/foreign_items/posix.rs | 6 ++---- src/shims/foreign_items/windows.rs | 4 ++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 746a0f25ebb1..f50b640e17cd 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -240,10 +240,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - // We don't support threading. (Also for Windows.) - | "pthread_create" - | "CreateThread" - => { + // We don't support threading. + "pthread_create" => { throw_unsup_format!("Miri does not support threading"); } diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index b0d323439714..1eb84be0e3a0 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -196,6 +196,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.gen_random(ptr, len as usize)?; this.write_scalar(Scalar::from_bool(true), dest)?; } + // We don't support threading. + "CreateThread" => { + throw_unsup_format!("Miri does not support threading"); + } _ => throw_unsup_format!("can't call foreign function: {}", link_name), } From 32bc015e35fb8665a77a368cc4a0b668be127f23 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 19 Feb 2020 17:03:00 -0500 Subject: [PATCH 1545/5092] reorganize comments for shim's classification --- src/shims/foreign_items/posix.rs | 1 + src/shims/foreign_items/posix/linux.rs | 1 + src/shims/foreign_items/posix/macos.rs | 2 +- src/shims/foreign_items/windows.rs | 11 +++++++---- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index f50b640e17cd..a4bc7e4726d0 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -104,6 +104,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + // Other shims "posix_memalign" => { let ret = this.deref_operand(args[0])?; let align = this.read_scalar(args[1])?.to_machine_usize(this)?; diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 27e42b0082e5..cf1431c8f117 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -40,6 +40,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + // Other shims "pthread_getattr_np" => { this.write_null(dest)?; } diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 274248e8b54f..d0bb3109424d 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -55,7 +55,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - // macOS API stubs. + // Other shims "pthread_attr_get_np" => { this.write_null(dest)?; } diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 1eb84be0e3a0..29eac99e565c 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -16,6 +16,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tcx = &{ this.tcx.tcx }; match link_name { + // Windows API stubs. + // HANDLE = isize + // DWORD = ULONG = u32 + // BOOL = i32 + // Environment related shims "GetEnvironmentVariableW" => { // args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars) @@ -70,10 +75,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest, )?; } - // Windows API stubs. - // HANDLE = isize - // DWORD = ULONG = u32 - // BOOL = i32 + + // Other shims "GetProcessHeap" => { // Just fake a HANDLE this.write_scalar(Scalar::from_int(1, this.pointer_size()), dest)?; From dbef2340b293e1ad825c7ed2aadff24ad4991cc3 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 19 Feb 2020 17:09:12 -0500 Subject: [PATCH 1546/5092] add docs for `emulate_foreign_item_by_bame --- src/shims/foreign_items.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 14e08f5181f5..3df653d1741a 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -178,6 +178,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(None) } + /// Emulates calling a foreign item using its name, failing if the item is not supported. + /// Returns Ok(false) if after calling this function, the call should return earlier instead of + /// going to the next block. fn emulate_foreign_item_by_name( &mut self, link_name: &str, From 9a7bc3972ceeeab709b277f0930c5becce5e9adf Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 19 Feb 2020 17:17:47 -0500 Subject: [PATCH 1547/5092] promote open and lseek shims to posix --- src/shims/foreign_items/posix.rs | 10 ++++++++++ src/shims/foreign_items/posix/linux.rs | 10 ---------- src/shims/foreign_items/posix/macos.rs | 10 ---------- 3 files changed, 10 insertions(+), 20 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index a4bc7e4726d0..6dc21d15b9f6 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -45,6 +45,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // File related shims + "open" | "open64" => { + let result = this.open(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + "fcntl" => { let result = this.fcntl(args[0], args[1], args.get(2).cloned())?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; @@ -104,6 +109,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "lseek" | "lseek64" => { + let result = this.lseek64(args[0], args[1], args[2])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + // Other shims "posix_memalign" => { let ret = this.deref_operand(args[0])?; diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index cf1431c8f117..1c03e3cb1cfe 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -19,21 +19,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // File related shims - "open64" => { - let result = this.open(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - "close" => { let result = this.close(args[0])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "lseek64" => { - let result = this.lseek64(args[0], args[1], args[2])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - // Time related shims "clock_gettime" => { let result = this.clock_gettime(args[0], args[1])?; diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index d0bb3109424d..bf7146267944 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -19,11 +19,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // File related shims - "open" => { - let result = this.open(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - "close$NOCANCEL" => { let result = this.close(args[0])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; @@ -44,11 +39,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "lseek" => { - let result = this.lseek64(args[0], args[1], args[2])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - // Time related shims "gettimeofday" => { let result = this.gettimeofday(args[0], args[1])?; From b213f88b58b915097049d0432cbc83114f326959 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 19 Feb 2020 17:23:27 -0500 Subject: [PATCH 1548/5092] promote memrchr to work on any platform --- src/shims/foreign_items.rs | 18 ++++++++++++++++++ src/shims/foreign_items/posix.rs | 18 ------------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 3df653d1741a..59a6a41a6f39 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -332,6 +332,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + "memrchr" => { + let ptr = this.read_scalar(args[0])?.not_undef()?; + let val = this.read_scalar(args[1])?.to_i32()? as u8; + let num = this.read_scalar(args[2])?.to_machine_usize(this)?; + if let Some(idx) = this + .memory + .read_bytes(ptr, Size::from_bytes(num))? + .iter() + .rev() + .position(|&c| c == val) + { + let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), this)?; + this.write_scalar(new_ptr, dest)?; + } else { + this.write_null(dest)?; + } + } + "strlen" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let n = this.memory.read_c_str(ptr)?.len(); diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 6dc21d15b9f6..d82c7eddc7d7 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -157,24 +157,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - "memrchr" => { - let ptr = this.read_scalar(args[0])?.not_undef()?; - let val = this.read_scalar(args[1])?.to_i32()? as u8; - let num = this.read_scalar(args[2])?.to_machine_usize(this)?; - if let Some(idx) = this - .memory - .read_bytes(ptr, Size::from_bytes(num))? - .iter() - .rev() - .position(|&c| c == val) - { - let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), this)?; - this.write_scalar(new_ptr, dest)?; - } else { - this.write_null(dest)?; - } - } - // Hook pthread calls that go to the thread-local storage memory subsystem. "pthread_key_create" => { let key_place = this.deref_operand(args[0])?; From 3418b40dac84d124db68a10fb0e17668139751e9 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 19 Feb 2020 17:28:48 -0500 Subject: [PATCH 1549/5092] remove syscall shim from macos and move getrandom to linux module --- src/shims/foreign_items/posix.rs | 18 ------------------ src/shims/foreign_items/posix/linux.rs | 22 ++++++++++++++++++++-- src/shims/foreign_items/posix/macos.rs | 18 ------------------ 3 files changed, 20 insertions(+), 38 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index d82c7eddc7d7..a391baa0b22c 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -333,21 +333,3 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(true) } } - -// Shims the posix 'getrandom()' syscall. -fn getrandom<'tcx>( - this: &mut MiriEvalContext<'_, 'tcx>, - args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag>, -) -> InterpResult<'tcx> { - let ptr = this.read_scalar(args[0])?.not_undef()?; - let len = this.read_scalar(args[1])?.to_machine_usize(this)?; - - // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, - // neither of which have any effect on our current PRNG. - let _flags = this.read_scalar(args[2])?.to_i32()?; - - this.gen_random(ptr, len as usize)?; - this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; - Ok(()) -} diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 1c03e3cb1cfe..8635455b1d7d 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -52,7 +52,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx id if id == sys_getrandom => { // The first argument is the syscall id, // so skip over it. - super::getrandom(this, &args[1..], dest)?; + getrandom(this, &args[1..], dest)?; } id if id == sys_statx => { // The first argument is the syscall id, @@ -65,7 +65,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "getrandom" => { - super::getrandom(this, args, dest)?; + getrandom(this, args, dest)?; } "sched_getaffinity" => { @@ -79,3 +79,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(true) } } + +// Shims the posix 'getrandom()' syscall. +fn getrandom<'tcx>( + this: &mut MiriEvalContext<'_, 'tcx>, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag>, +) -> InterpResult<'tcx> { + let ptr = this.read_scalar(args[0])?.not_undef()?; + let len = this.read_scalar(args[1])?.to_machine_usize(this)?; + + // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, + // neither of which have any effect on our current PRNG. + let _flags = this.read_scalar(args[2])?.to_i32()?; + + this.gen_random(ptr, len as usize)?; + this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; + Ok(()) +} diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index bf7146267944..8cfe959c3938 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -79,24 +79,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - "syscall" => { - let sys_getrandom = this - .eval_path_scalar(&["libc", "SYS_getrandom"])? - .expect("Failed to get libc::SYS_getrandom") - .to_machine_usize(this)?; - - match this.read_scalar(args[0])?.to_machine_usize(this)? { - // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` - // is called if a `HashMap` is created the regular way (e.g. HashMap). - id if id == sys_getrandom => { - // The first argument is the syscall id, - // so skip over it. - super::getrandom(this, &args[1..], dest)?; - } - id => throw_unsup_format!("miri does not support syscall ID {}", id), - } - } - _ => throw_unsup_format!("can't call foreign function: {}", link_name), }; From bb3a711b3e28dc768c30925d78e6c2daaf00ab30 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 19 Feb 2020 17:53:33 -0500 Subject: [PATCH 1550/5092] rename platform specific shims --- src/shims/foreign_items/posix/linux.rs | 2 +- src/shims/foreign_items/posix/macos.rs | 6 +++--- src/shims/fs.rs | 20 ++++++++++---------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 8635455b1d7d..819da6804381 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -57,7 +57,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx id if id == sys_statx => { // The first argument is the syscall id, // so skip over it. - let result = this.statx(args[1], args[2], args[3], args[4], args[5])?; + let result = this.linux_statx(args[1], args[2], args[3], args[4], args[5])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } id => throw_unsup_format!("miri does not support syscall ID {}", id), diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 8cfe959c3938..3698df95bd19 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -25,17 +25,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "stat$INODE64" => { - let result = this.stat(args[0], args[1])?; + let result = this.macos_stat(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } "lstat$INODE64" => { - let result = this.lstat(args[0], args[1])?; + let result = this.macos_lstat(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } "fstat$INODE64" => { - let result = this.fstat(args[0], args[1])?; + let result = this.macos_fstat(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 42a860780ff8..afa71f654075 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -340,7 +340,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.try_unwrap_io_result(create_link(target, linkpath).map(|_| 0)) } - fn stat( + fn macos_stat( &mut self, path_op: OpTy<'tcx, Tag>, buf_op: OpTy<'tcx, Tag>, @@ -349,11 +349,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("stat")?; this.check_platform("macos", "stat")?; // `stat` always follows symlinks. - this.stat_or_lstat(true, path_op, buf_op) + this.macos_stat_or_lstat(true, path_op, buf_op) } // `lstat` is used to get symlink metadata. - fn lstat( + fn macos_lstat( &mut self, path_op: OpTy<'tcx, Tag>, buf_op: OpTy<'tcx, Tag>, @@ -361,10 +361,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.check_no_isolation("lstat")?; this.check_platform("macos", "lstat")?; - this.stat_or_lstat(false, path_op, buf_op) + this.macos_stat_or_lstat(false, path_op, buf_op) } - fn fstat( + fn macos_fstat( &mut self, fd_op: OpTy<'tcx, Tag>, buf_op: OpTy<'tcx, Tag>, @@ -380,10 +380,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(metadata) => metadata, None => return Ok(-1), }; - stat_macos_write_buf(this, metadata, buf_op) + macos_stat_write_buf(this, metadata, buf_op) } - fn stat_or_lstat( + fn macos_stat_or_lstat( &mut self, follow_symlink: bool, path_op: OpTy<'tcx, Tag>, @@ -398,10 +398,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(metadata) => metadata, None => return Ok(-1), }; - stat_macos_write_buf(this, metadata, buf_op) + macos_stat_write_buf(this, metadata, buf_op) } - fn statx( + fn linux_statx( &mut self, dirfd_op: OpTy<'tcx, Tag>, // Should be an `int` pathname_op: OpTy<'tcx, Tag>, // Should be a `const char *` @@ -688,7 +688,7 @@ impl FileMetadata { } } -fn stat_macos_write_buf<'tcx, 'mir>( +fn macos_stat_write_buf<'tcx, 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, metadata: FileMetadata, buf_op: OpTy<'tcx, Tag>, From a60dfcf6e77e4335357a7b26de415d1e1bc21250 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 20 Feb 2020 11:09:12 +0100 Subject: [PATCH 1551/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 12ac7b51b998..00feed476418 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a2fb0c28be794f28028884650db70c17fea8e35b +de362d88ea17ab23ca2483cb798bc7aeb81a48f5 From 32a354efa3c089b1f47c8c72c24a6100422be5b8 Mon Sep 17 00:00:00 2001 From: David Cook Date: Thu, 20 Feb 2020 21:54:52 -0600 Subject: [PATCH 1552/5092] Test error case of std::fs::rename --- tests/run-pass/fs.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 453432f64f10..a6ce8627cde7 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -169,8 +169,16 @@ fn test_rename() { let file = File::create(&path1).unwrap(); drop(file); + + // Renaming should succeed rename(&path1, &path2).unwrap(); + // Check that the old file path isn't present assert_eq!(ErrorKind::NotFound, path1.metadata().unwrap_err().kind()); + // Check that the file has moved successfully assert!(path2.metadata().unwrap().is_file()); + + // Renaming a nonexistent file should fail + assert_eq!(ErrorKind::NotFound, rename(&path1, &path2).unwrap_err().kind()); + remove_file(&path2).unwrap(); } From 627d7cba644575467eb276a853acc07f7fcf2b33 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 21 Feb 2020 10:28:24 +0100 Subject: [PATCH 1553/5092] fix for const-prop lint changes --- rust-version | 2 +- tests/run-pass/panic/catch_panic.rs | 2 +- tests/run-pass/panic/div-by-zero-2.rs | 2 +- tests/run-pass/panic/overflowing-lsh-neg.rs | 3 +-- tests/run-pass/panic/overflowing-lsh-neg.stderr | 2 +- tests/run-pass/panic/overflowing-rsh-1.rs | 2 +- tests/run-pass/panic/overflowing-rsh-2.rs | 2 +- 7 files changed, 7 insertions(+), 8 deletions(-) diff --git a/rust-version b/rust-version index 00feed476418..fe788019e012 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -de362d88ea17ab23ca2483cb798bc7aeb81a48f5 +2851e59a52673e0242532035047009c6e121c95a diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index 4d4206923a5e..21a6fee7c921 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -1,7 +1,7 @@ // ignore-windows: Unwind panicking does not currently work on Windows // normalize-stderr-test "[^ ]*libcore/macros/mod.rs[0-9:]*" -> "$$LOC" #![feature(never_type)] -#![allow(const_err)] +#![allow(unconditional_panic)] use std::panic::{catch_unwind, AssertUnwindSafe}; use std::cell::Cell; diff --git a/tests/run-pass/panic/div-by-zero-2.rs b/tests/run-pass/panic/div-by-zero-2.rs index 6cc319bf0bc4..cfacc9db0d66 100644 --- a/tests/run-pass/panic/div-by-zero-2.rs +++ b/tests/run-pass/panic/div-by-zero-2.rs @@ -1,5 +1,5 @@ // ignore-windows: Unwind panicking does not currently work on Windows -#![allow(const_err)] +#![allow(unconditional_panic)] fn main() { let _n = 1 / 0; diff --git a/tests/run-pass/panic/overflowing-lsh-neg.rs b/tests/run-pass/panic/overflowing-lsh-neg.rs index b214243c88f8..ee15ca0284ef 100644 --- a/tests/run-pass/panic/overflowing-lsh-neg.rs +++ b/tests/run-pass/panic/overflowing-lsh-neg.rs @@ -1,6 +1,5 @@ // ignore-windows: Unwind panicking does not currently work on Windows -#![allow(exceeding_bitshifts)] -#![allow(const_err)] +#![allow(arithmetic_overflow)] fn main() { let _n = 2i64 << -1; diff --git a/tests/run-pass/panic/overflowing-lsh-neg.stderr b/tests/run-pass/panic/overflowing-lsh-neg.stderr index fe5a35e6b381..e1e7daa119ab 100644 --- a/tests/run-pass/panic/overflowing-lsh-neg.stderr +++ b/tests/run-pass/panic/overflowing-lsh-neg.stderr @@ -1 +1 @@ -thread 'main' panicked at 'attempt to shift left with overflow', $DIR/overflowing-lsh-neg.rs:6:14 +thread 'main' panicked at 'attempt to shift left with overflow', $DIR/overflowing-lsh-neg.rs:5:14 diff --git a/tests/run-pass/panic/overflowing-rsh-1.rs b/tests/run-pass/panic/overflowing-rsh-1.rs index 68ea51d16731..36ab948a5efa 100644 --- a/tests/run-pass/panic/overflowing-rsh-1.rs +++ b/tests/run-pass/panic/overflowing-rsh-1.rs @@ -1,5 +1,5 @@ // ignore-windows: Unwind panicking does not currently work on Windows -#![allow(exceeding_bitshifts, const_err)] +#![allow(arithmetic_overflow)] fn main() { let _n = 1i64 >> 64; diff --git a/tests/run-pass/panic/overflowing-rsh-2.rs b/tests/run-pass/panic/overflowing-rsh-2.rs index 4e287f20adf8..da77a46a805e 100644 --- a/tests/run-pass/panic/overflowing-rsh-2.rs +++ b/tests/run-pass/panic/overflowing-rsh-2.rs @@ -1,5 +1,5 @@ // ignore-windows: Unwind panicking does not currently work on Windows -#![allow(exceeding_bitshifts, const_err)] +#![allow(arithmetic_overflow)] fn main() { // Make sure we catch overflows that would be hidden by first casting the RHS to u32 From 0e7e5b9655cd1baab18e7ef28693cb22a94b3d0d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 21 Feb 2020 11:03:52 +0100 Subject: [PATCH 1554/5092] fix test-cargo-miri --- test-cargo-miri/tests/test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 4c196ef5e0f5..0095802a59a8 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -55,7 +55,7 @@ fn do_panic() { // In large, friendly letters :) // FIXME: see above #[test] -#[allow(const_err)] +#[allow(unconditional_panic)] #[cfg_attr(not(windows), should_panic(expected="the len is 0 but the index is 42"))] fn fail_index_check() { #[cfg(not(windows))] From 3e2f29a0796af501485e13cfa06302aa6e479d6a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 21 Feb 2020 11:05:56 +0100 Subject: [PATCH 1555/5092] remove some no-longer-needed allow(const_err) --- tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs b/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs index 32393a37d2ec..bd8926aaf1ad 100644 --- a/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs +++ b/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs @@ -1,7 +1,4 @@ -// allow(const_err) to work around a bug in warnings -#[allow(const_err)] static FOO: fn() = || { assert_ne!(42, 43) }; -#[allow(const_err)] static BAR: fn(i32, i32) = |a, b| { assert_ne!(a, b) }; // use to first make the closure FnOnce() before making it fn() From 08332bc73027e0dbe0601a63a82fd3917fa8531a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 21 Feb 2020 20:06:31 +0100 Subject: [PATCH 1556/5092] dont overwrite bootstrap flags --- src/bin/cargo-miri.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 9c6eab1ec737..e990bc00277c 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -381,8 +381,6 @@ path = "lib.rs" command.env("RUSTFLAGS", miri::miri_default_args().join(" ")); command.env("XARGO_HOME", &dir); command.env("XARGO_RUST_SRC", &rust_src); - // In bootstrap, make sure we don't get debug assertons into our libstd. - command.env("RUSTC_DEBUG_ASSERTIONS", "false"); // Handle target flag. if let Some(ref target) = target { command.arg("--target").arg(&target); From 9e9a0900261946b726137637dfbd4a70fa83f233 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 22 Feb 2020 02:18:42 -0500 Subject: [PATCH 1557/5092] minor fixes --- src/helpers.rs | 2 +- src/shims/foreign_items.rs | 38 +++++++++++++------------- src/shims/foreign_items/posix/linux.rs | 4 ++- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index c92aa6dfaa7c..2ce4ca6c91dc 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -374,7 +374,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn check_platform(&mut self, platform: &str, name: &str) -> InterpResult<'tcx> { if self.eval_context_mut().tcx.sess.target.target.target_os.to_lowercase() != platform { throw_unsup_format!( - "`{}` is only available in the `{}` platform", + "`{}` is only available on the `{}` platform", name, platform, ) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 59a6a41a6f39..37296132c038 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -179,8 +179,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Emulates calling a foreign item using its name, failing if the item is not supported. - /// Returns Ok(false) if after calling this function, the call should return earlier instead of - /// going to the next block. + /// Returns `true` if the caller is expected to jump to the return block, and `false` if + /// jumping has already been taken care of. fn emulate_foreign_item_by_name( &mut self, link_name: &str, @@ -315,23 +315,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, Size::from_bits(32)), dest)?; } - "memchr" => { - let ptr = this.read_scalar(args[0])?.not_undef()?; - let val = this.read_scalar(args[1])?.to_i32()? as u8; - let num = this.read_scalar(args[2])?.to_machine_usize(this)?; - let idx = this - .memory - .read_bytes(ptr, Size::from_bytes(num))? - .iter() - .position(|&c| c == val); - if let Some(idx) = idx { - let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), this)?; - this.write_scalar(new_ptr, dest)?; - } else { - this.write_null(dest)?; - } - } - "memrchr" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let val = this.read_scalar(args[1])?.to_i32()? as u8; @@ -350,6 +333,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + "memchr" => { + let ptr = this.read_scalar(args[0])?.not_undef()?; + let val = this.read_scalar(args[1])?.to_i32()? as u8; + let num = this.read_scalar(args[2])?.to_machine_usize(this)?; + let idx = this + .memory + .read_bytes(ptr, Size::from_bytes(num))? + .iter() + .position(|&c| c == val); + if let Some(idx) = idx { + let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), this)?; + this.write_scalar(new_ptr, dest)?; + } else { + this.write_null(dest)?; + } + } + "strlen" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let n = this.memory.read_c_str(ptr)?.len(); diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 819da6804381..098d05663543 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -25,6 +25,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Time related shims + + // This is a POSIX function but it has only been tested on linux. "clock_gettime" => { let result = this.clock_gettime(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; @@ -80,7 +82,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } -// Shims the posix 'getrandom()' syscall. +// Shims the linux 'getrandom()' syscall. fn getrandom<'tcx>( this: &mut MiriEvalContext<'_, 'tcx>, args: &[OpTy<'tcx, Tag>], From 86a4354746c81d06fc09c5c0633449a26bee442a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 21 Feb 2020 08:34:25 +0100 Subject: [PATCH 1558/5092] fix README --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1f008e735ec2..f16751cd7478 100644 --- a/README.md +++ b/README.md @@ -171,11 +171,10 @@ Several `-Z` flags are relevant for Miri: sets this flag per default. * `-Zmir-emit-retag` controls whether `Retag` statements are emitted. Miri enables this per default because it is needed for validation. -* `-Zmiri-track-pointer-tag=` aborts interpretation with a backtrace when the - given pointer tag is popped from a borrow stack (which is where the tag - becomes invalid and any future use of it will error anyway). This helps you - in finding out why UB is happening and where in your code would be a good - place to look for it. +* `-Zmiri-track-pointer-tag=` shows a backtrace when the given pointer tag + is popped from a borrow stack (which is where the tag becomes invalid and any + future use of it will error). This helps you in finding out why UB is + happening and where in your code would be a good place to look for it. Moreover, Miri recognizes some environment variables: From c2bcab55b09db9adc5d33b48011a31587a8e80a1 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 22 Feb 2020 08:55:45 -0500 Subject: [PATCH 1559/5092] improve docs --- src/shims/foreign_items/posix/linux.rs | 5 +++++ src/shims/foreign_items/posix/macos.rs | 3 +++ src/shims/fs.rs | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 098d05663543..9da54b6d4070 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -19,6 +19,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // File related shims + + // The only reason this is not in the `posix` module is because the `macos` item has a + // different name. "close" => { let result = this.close(args[0])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; @@ -56,6 +59,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // so skip over it. getrandom(this, &args[1..], dest)?; } + // `statx` is used by `libstd` to retrieve metadata information in `linux` + // instead of using `stat`,`lstat` or `fstat` as in the `macos` platform. id if id == sys_statx => { // The first argument is the syscall id, // so skip over it. diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 3698df95bd19..25ac7e93867f 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -19,6 +19,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // File related shims + + // The only reason this is not in the `posix` module is because the `linux` item has a + // different name. "close$NOCANCEL" => { let result = this.close(args[0])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index afa71f654075..b3d8d6a0ac7f 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -383,6 +383,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx macos_stat_write_buf(this, metadata, buf_op) } + /// Emulate `stat` or `lstat` on the `macos` platform. This function is not intended to be + /// called directly from `emulate_foreign_item_by_name`, so it does not check if isolation is + /// disabled or if the target platform is the correct one. Please use `macos_stat` or + /// `macos_lstat` instead. fn macos_stat_or_lstat( &mut self, follow_symlink: bool, From 208665836eef558e92925e48bf35d162dfd4d5a3 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 22 Feb 2020 09:02:25 -0500 Subject: [PATCH 1560/5092] panic if target platform is incorrect instead --- src/helpers.rs | 23 +++++++++++------------ src/shims/fs.rs | 8 ++++---- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 2ce4ca6c91dc..2ae6910fce2d 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -368,18 +368,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(()) } - /// Helper function used inside the shims of foreign functions to check that the target - /// platform is `platform`. It returns an error using the `name` of the foreign function if - /// this is not the case. - fn check_platform(&mut self, platform: &str, name: &str) -> InterpResult<'tcx> { - if self.eval_context_mut().tcx.sess.target.target.target_os.to_lowercase() != platform { - throw_unsup_format!( - "`{}` is only available on the `{}` platform", - name, - platform, - ) - } - Ok(()) + /// Helper function used inside the shims of foreign functions to assert that the target + /// platform is `platform`. It panics showing a message with the `name` of the foreign function + /// if this is not the case. + fn assert_platform(&mut self, platform: &str, name: &str) { + assert_eq!( + self.eval_context_mut().tcx.sess.target.target.target_os.to_lowercase(), + platform, + "`{}` is only available on the `{}` platform", + name, + platform + ) } /// Sets the last error variable. diff --git a/src/shims/fs.rs b/src/shims/fs.rs index b3d8d6a0ac7f..f846c339defe 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -347,7 +347,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.check_no_isolation("stat")?; - this.check_platform("macos", "stat")?; + this.assert_platform("macos", "stat"); // `stat` always follows symlinks. this.macos_stat_or_lstat(true, path_op, buf_op) } @@ -360,7 +360,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.check_no_isolation("lstat")?; - this.check_platform("macos", "lstat")?; + this.assert_platform("macos", "lstat"); this.macos_stat_or_lstat(false, path_op, buf_op) } @@ -372,7 +372,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.check_no_isolation("fstat")?; - this.check_platform("macos", "fstat")?; + this.assert_platform("macos", "fstat"); let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -416,7 +416,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.check_no_isolation("statx")?; - this.check_platform("linux", "statx")?; + this.assert_platform("linux", "statx"); let statxbuf_scalar = this.read_scalar(statxbuf_op)?.not_undef()?; let pathname_scalar = this.read_scalar(pathname_op)?.not_undef()?; From 5d3554898524c01bb85a12367fc9e36f27bcfe05 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Feb 2020 18:44:40 +0100 Subject: [PATCH 1561/5092] helpers.rs cleanup --- src/helpers.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 2ae6910fce2d..a38782765059 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -359,11 +359,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function used inside the shims of foreign functions to check that isolation is /// disabled. It returns an error using the `name` of the foreign function if this is not the /// case. - fn check_no_isolation(&mut self, name: &str) -> InterpResult<'tcx> { - if !self.eval_context_mut().machine.communicate { + fn check_no_isolation(&self, name: &str) -> InterpResult<'tcx> { + if !self.eval_context_ref().machine.communicate { throw_unsup_format!( "`{}` not available when isolation is enabled. Pass the flag `-Zmiri-disable-isolation` to disable it.", - name + name, ) } Ok(()) @@ -371,13 +371,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function used inside the shims of foreign functions to assert that the target /// platform is `platform`. It panics showing a message with the `name` of the foreign function /// if this is not the case. - fn assert_platform(&mut self, platform: &str, name: &str) { + fn assert_platform(&self, platform: &str, name: &str) { assert_eq!( - self.eval_context_mut().tcx.sess.target.target.target_os.to_lowercase(), + self.eval_context_ref().tcx.sess.target.target.target_os.to_lowercase(), platform, "`{}` is only available on the `{}` platform", name, - platform + platform, ) } @@ -389,8 +389,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Gets the last error variable. - fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { - let this = self.eval_context_mut(); + fn get_last_error(&self) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_ref(); let errno_place = this.machine.last_error.unwrap(); this.read_scalar(errno_place.into())?.not_undef() } From beb82ea4a41ba582dca6391fa622bfbb4d987226 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Feb 2020 18:48:38 +0100 Subject: [PATCH 1562/5092] add private helper trait for fs shim --- src/shims/fs.rs | 195 +++++++++++++++++++++++++----------------------- 1 file changed, 100 insertions(+), 95 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index a51a2f525085..aa562926686d 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -63,6 +63,105 @@ impl FileHandler { } } +impl<'mir, 'tcx> EvalContextExtPrivate<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + /// Emulate `stat` or `lstat` on the `macos` platform. This function is not intended to be + /// called directly from `emulate_foreign_item_by_name`, so it does not check if isolation is + /// disabled or if the target platform is the correct one. Please use `macos_stat` or + /// `macos_lstat` instead. + fn macos_stat_or_lstat( + &mut self, + follow_symlink: bool, + path_op: OpTy<'tcx, Tag>, + buf_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + let path_scalar = this.read_scalar(path_op)?.not_undef()?; + let path: PathBuf = this.read_os_str_from_c_str(path_scalar)?.into(); + + let metadata = match FileMetadata::from_path(this, path, follow_symlink)? { + Some(metadata) => metadata, + None => return Ok(-1), + }; + this.macos_stat_write_buf(metadata, buf_op) + } + + fn macos_stat_write_buf( + &mut self, + metadata: FileMetadata, + buf_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + let mode: u16 = metadata.mode.to_u16()?; + + let (access_sec, access_nsec) = metadata.accessed.unwrap_or((0, 0)); + let (created_sec, created_nsec) = metadata.created.unwrap_or((0, 0)); + let (modified_sec, modified_nsec) = metadata.modified.unwrap_or((0, 0)); + + let dev_t_layout = this.libc_ty_layout("dev_t")?; + let mode_t_layout = this.libc_ty_layout("mode_t")?; + let nlink_t_layout = this.libc_ty_layout("nlink_t")?; + let ino_t_layout = this.libc_ty_layout("ino_t")?; + let uid_t_layout = this.libc_ty_layout("uid_t")?; + let gid_t_layout = this.libc_ty_layout("gid_t")?; + let time_t_layout = this.libc_ty_layout("time_t")?; + let long_layout = this.libc_ty_layout("c_long")?; + let off_t_layout = this.libc_ty_layout("off_t")?; + let blkcnt_t_layout = this.libc_ty_layout("blkcnt_t")?; + let blksize_t_layout = this.libc_ty_layout("blksize_t")?; + let uint32_t_layout = this.libc_ty_layout("uint32_t")?; + + // We need to add 32 bits of padding after `st_rdev` if we are on a 64-bit platform. + let pad_layout = if this.tcx.sess.target.ptr_width == 64 { + uint32_t_layout + } else { + this.layout_of(this.tcx.mk_unit())? + }; + + let imms = [ + immty_from_uint_checked(0u128, dev_t_layout)?, // st_dev + immty_from_uint_checked(mode, mode_t_layout)?, // st_mode + immty_from_uint_checked(0u128, nlink_t_layout)?, // st_nlink + immty_from_uint_checked(0u128, ino_t_layout)?, // st_ino + immty_from_uint_checked(0u128, uid_t_layout)?, // st_uid + immty_from_uint_checked(0u128, gid_t_layout)?, // st_gid + immty_from_uint_checked(0u128, dev_t_layout)?, // st_rdev + immty_from_uint_checked(0u128, pad_layout)?, // padding for 64-bit targets + immty_from_uint_checked(access_sec, time_t_layout)?, // st_atime + immty_from_uint_checked(access_nsec, long_layout)?, // st_atime_nsec + immty_from_uint_checked(modified_sec, time_t_layout)?, // st_mtime + immty_from_uint_checked(modified_nsec, long_layout)?, // st_mtime_nsec + immty_from_uint_checked(0u128, time_t_layout)?, // st_ctime + immty_from_uint_checked(0u128, long_layout)?, // st_ctime_nsec + immty_from_uint_checked(created_sec, time_t_layout)?, // st_birthtime + immty_from_uint_checked(created_nsec, long_layout)?, // st_birthtime_nsec + immty_from_uint_checked(metadata.size, off_t_layout)?, // st_size + immty_from_uint_checked(0u128, blkcnt_t_layout)?, // st_blocks + immty_from_uint_checked(0u128, blksize_t_layout)?, // st_blksize + immty_from_uint_checked(0u128, uint32_t_layout)?, // st_flags + immty_from_uint_checked(0u128, uint32_t_layout)?, // st_gen + ]; + + let buf = this.deref_operand(buf_op)?; + this.write_packed_immediates(buf, &imms)?; + + Ok(0) + } + + /// Function used when a handle is not found inside `FileHandler`. It returns `Ok(-1)`and sets + /// the last OS error to `libc::EBADF` (invalid file descriptor). This function uses + /// `T: From` instead of `i32` directly because some fs functions return different integer + /// types (like `read`, that returns an `i64`). + fn handle_not_found>(&mut self) -> InterpResult<'tcx, T> { + let this = self.eval_context_mut(); + let ebadf = this.eval_libc("EBADF")?; + this.set_last_error(ebadf)?; + Ok((-1).into()) + } +} + impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn open( @@ -432,29 +531,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(metadata) => metadata, None => return Ok(-1), }; - macos_stat_write_buf(this, metadata, buf_op) - } - - /// Emulate `stat` or `lstat` on the `macos` platform. This function is not intended to be - /// called directly from `emulate_foreign_item_by_name`, so it does not check if isolation is - /// disabled or if the target platform is the correct one. Please use `macos_stat` or - /// `macos_lstat` instead. - fn macos_stat_or_lstat( - &mut self, - follow_symlink: bool, - path_op: OpTy<'tcx, Tag>, - buf_op: OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, i32> { - let this = self.eval_context_mut(); - - let path_scalar = this.read_scalar(path_op)?.not_undef()?; - let path: PathBuf = this.read_os_str_from_c_str(path_scalar)?.into(); - - let metadata = match FileMetadata::from_path(this, path, follow_symlink)? { - Some(metadata) => metadata, - None => return Ok(-1), - }; - macos_stat_write_buf(this, metadata, buf_op) + this.macos_stat_write_buf(metadata, buf_op) } fn linux_statx( @@ -620,17 +697,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - /// Function used when a handle is not found inside `FileHandler`. It returns `Ok(-1)`and sets - /// the last OS error to `libc::EBADF` (invalid file descriptor). This function uses - /// `T: From` instead of `i32` directly because some fs functions return different integer - /// types (like `read`, that returns an `i64`). - fn handle_not_found>(&mut self) -> InterpResult<'tcx, T> { - let this = self.eval_context_mut(); - let ebadf = this.eval_libc("EBADF")?; - this.set_last_error(ebadf)?; - Ok((-1).into()) - } - fn rename( &mut self, oldpath_op: OpTy<'tcx, Tag>, @@ -743,64 +809,3 @@ impl FileMetadata { Ok(Some(FileMetadata { mode, size, created, accessed, modified })) } } - -fn macos_stat_write_buf<'tcx, 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, - metadata: FileMetadata, - buf_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, i32> { - let mode: u16 = metadata.mode.to_u16()?; - - let (access_sec, access_nsec) = metadata.accessed.unwrap_or((0, 0)); - let (created_sec, created_nsec) = metadata.created.unwrap_or((0, 0)); - let (modified_sec, modified_nsec) = metadata.modified.unwrap_or((0, 0)); - - let dev_t_layout = ecx.libc_ty_layout("dev_t")?; - let mode_t_layout = ecx.libc_ty_layout("mode_t")?; - let nlink_t_layout = ecx.libc_ty_layout("nlink_t")?; - let ino_t_layout = ecx.libc_ty_layout("ino_t")?; - let uid_t_layout = ecx.libc_ty_layout("uid_t")?; - let gid_t_layout = ecx.libc_ty_layout("gid_t")?; - let time_t_layout = ecx.libc_ty_layout("time_t")?; - let long_layout = ecx.libc_ty_layout("c_long")?; - let off_t_layout = ecx.libc_ty_layout("off_t")?; - let blkcnt_t_layout = ecx.libc_ty_layout("blkcnt_t")?; - let blksize_t_layout = ecx.libc_ty_layout("blksize_t")?; - let uint32_t_layout = ecx.libc_ty_layout("uint32_t")?; - - // We need to add 32 bits of padding after `st_rdev` if we are on a 64-bit platform. - let pad_layout = if ecx.tcx.sess.target.ptr_width == 64 { - uint32_t_layout - } else { - ecx.layout_of(ecx.tcx.mk_unit())? - }; - - let imms = [ - immty_from_uint_checked(0u128, dev_t_layout)?, // st_dev - immty_from_uint_checked(mode, mode_t_layout)?, // st_mode - immty_from_uint_checked(0u128, nlink_t_layout)?, // st_nlink - immty_from_uint_checked(0u128, ino_t_layout)?, // st_ino - immty_from_uint_checked(0u128, uid_t_layout)?, // st_uid - immty_from_uint_checked(0u128, gid_t_layout)?, // st_gid - immty_from_uint_checked(0u128, dev_t_layout)?, // st_rdev - immty_from_uint_checked(0u128, pad_layout)?, // padding for 64-bit targets - immty_from_uint_checked(access_sec, time_t_layout)?, // st_atime - immty_from_uint_checked(access_nsec, long_layout)?, // st_atime_nsec - immty_from_uint_checked(modified_sec, time_t_layout)?, // st_mtime - immty_from_uint_checked(modified_nsec, long_layout)?, // st_mtime_nsec - immty_from_uint_checked(0u128, time_t_layout)?, // st_ctime - immty_from_uint_checked(0u128, long_layout)?, // st_ctime_nsec - immty_from_uint_checked(created_sec, time_t_layout)?, // st_birthtime - immty_from_uint_checked(created_nsec, long_layout)?, // st_birthtime_nsec - immty_from_uint_checked(metadata.size, off_t_layout)?, // st_size - immty_from_uint_checked(0u128, blkcnt_t_layout)?, // st_blocks - immty_from_uint_checked(0u128, blksize_t_layout)?, // st_blksize - immty_from_uint_checked(0u128, uint32_t_layout)?, // st_flags - immty_from_uint_checked(0u128, uint32_t_layout)?, // st_gen - ]; - - let buf = ecx.deref_operand(buf_op)?; - ecx.write_packed_immediates(buf, &imms)?; - - Ok(0) -} From e575fb1f57c693efd07322cddd7e69e19da82a1c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Feb 2020 18:48:44 +0100 Subject: [PATCH 1563/5092] improve comments --- src/shims/foreign_items/posix/linux.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 9da54b6d4070..4d3e1798ce14 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -18,7 +18,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } - // File related shims + // File related shims (but also see "syscall" below for statx) // The only reason this is not in the `posix` module is because the `macos` item has a // different name. @@ -59,8 +59,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // so skip over it. getrandom(this, &args[1..], dest)?; } - // `statx` is used by `libstd` to retrieve metadata information in `linux` - // instead of using `stat`,`lstat` or `fstat` as in the `macos` platform. + // `statx` is used by `libstd` to retrieve metadata information on `linux` + // instead of using `stat`,`lstat` or `fstat` as on `macos`. id if id == sys_statx => { // The first argument is the syscall id, // so skip over it. @@ -87,7 +87,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } -// Shims the linux 'getrandom()' syscall. +// Shims the linux `getrandom` syscall. fn getrandom<'tcx>( this: &mut MiriEvalContext<'_, 'tcx>, args: &[OpTy<'tcx, Tag>], From 4a9a0a9078bd57a200c1c4d83a7ebf2e3690e3c8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Feb 2020 18:54:08 +0100 Subject: [PATCH 1564/5092] avoid lowercasing platforms --- src/eval.rs | 2 +- src/helpers.rs | 2 +- src/shims/foreign_items.rs | 2 +- src/shims/foreign_items/posix.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 7a3945220f77..9ce3d2b08c23 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -169,7 +169,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option { // FIXME: We always ignore leaks on some platforms where we do not // correctly implement TLS destructors. - let target_os = tcx.sess.target.target.target_os.to_lowercase(); + let target_os = tcx.sess.target.target.target_os.as_str(); let ignore_leaks = config.ignore_leaks || target_os == "windows" || target_os == "macos"; let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) { diff --git a/src/helpers.rs b/src/helpers.rs index a38782765059..5128176acb58 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -373,7 +373,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// if this is not the case. fn assert_platform(&self, platform: &str, name: &str) { assert_eq!( - self.eval_context_ref().tcx.sess.target.target.target_os.to_lowercase(), + self.eval_context_ref().tcx.sess.target.target.target_os, platform, "`{}` is only available on the `{}` platform", name, diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 37296132c038..3d8d3bd52607 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -455,7 +455,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_f64(res), dest)?; } - _ => match this.tcx.sess.target.target.target_os.to_lowercase().as_str() { + _ => match this.tcx.sess.target.target.target_os.as_str() { "linux" | "macos" => return posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), "windows" => return windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), target => throw_unsup_format!("The {} target platform is not supported", target), diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index a391baa0b22c..a8b4aad8819b 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -322,7 +322,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } _ => { - match this.tcx.sess.target.target.target_os.to_lowercase().as_str() { + match this.tcx.sess.target.target.target_os.as_str() { "linux" => return linux::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), "macos" => return macos::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), _ => unreachable!(), From 5b34f06bae63f9da496a907408789e17fc2ead0b Mon Sep 17 00:00:00 2001 From: David Cook Date: Fri, 24 Jan 2020 18:56:23 -0600 Subject: [PATCH 1565/5092] Add shims for mkdir and rmdir --- src/shims/foreign_items/posix.rs | 10 ++++++++ src/shims/fs.rs | 41 +++++++++++++++++++++++++++++++- tests/run-pass/fs.rs | 24 ++++++++++++++++++- 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index a8b4aad8819b..e520e23199e3 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -109,6 +109,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "mkdir" => { + let result = this.mkdir(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "rmdir" => { + let result = this.rmdir(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + "lseek" | "lseek64" => { let result = this.lseek64(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index aa562926686d..45471a638a18 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1,6 +1,6 @@ use std::collections::BTreeMap; use std::convert::{TryFrom, TryInto}; -use std::fs::{remove_file, rename, File, OpenOptions}; +use std::fs::{remove_dir, remove_file, rename, DirBuilder, File, OpenOptions}; use std::io::{Read, Seek, SeekFrom, Write}; use std::path::PathBuf; use std::time::SystemTime; @@ -722,6 +722,45 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.try_unwrap_io_result(result) } + + fn mkdir( + &mut self, + path_op: OpTy<'tcx, Tag>, + mode_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.check_no_isolation("mkdir")?; + + let mode = this.read_scalar(mode_op)?.to_u32()?; + + let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + + let mut builder = DirBuilder::new(); + #[cfg(target_family = "unix")] + { + use std::os::unix::fs::DirBuilderExt; + builder.mode(mode); + } + let result = builder.create(path).map(|_| 0i32); + + this.try_unwrap_io_result(result) + } + + fn rmdir( + &mut self, + path_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.check_no_isolation("rmdir")?; + + let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + + let result = remove_dir(path).map(|_| 0i32); + + this.try_unwrap_io_result(result) + } } /// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch when diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index a6ce8627cde7..7f920d8c19d8 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -1,7 +1,7 @@ // ignore-windows: File handling is not implemented yet // compile-flags: -Zmiri-disable-isolation -use std::fs::{File, remove_file, rename}; +use std::fs::{File, create_dir, remove_dir, remove_dir_all, remove_file, rename}; use std::io::{Read, Write, ErrorKind, Result, Seek, SeekFrom}; use std::path::{PathBuf, Path}; @@ -13,6 +13,7 @@ fn main() { test_symlink(); test_errors(); test_rename(); + test_directory(); } /// Prepare: compute filename and make sure the file does not exist. @@ -24,6 +25,15 @@ fn prepare(filename: &str) -> PathBuf { path } +/// Prepare directory: compute directory name and make sure it does not exist. +fn prepare_dir(dirname: &str) -> PathBuf { + let tmp = std::env::temp_dir(); + let path = tmp.join(&dirname); + // Clean the directory for robustness. + remove_dir_all(&path).ok(); + path +} + /// Prepare like above, and also write some initial content to the file. fn prepare_with_content(filename: &str, content: &[u8]) -> PathBuf { let path = prepare(filename); @@ -182,3 +192,15 @@ fn test_rename() { remove_file(&path2).unwrap(); } + +fn test_directory() { + let dir_path = prepare_dir("miri_test_fs_dir"); + // Creating a directory should succeed. + create_dir(&dir_path).unwrap(); + // Test that the metadata of a directory is correct. + assert!(dir_path.metadata().unwrap().is_dir()); + // Deleting the directory should succeed. + remove_dir(&dir_path).unwrap(); + // Reading the metadata of a non-existent file should fail with a "not found" error. + assert_eq!(ErrorKind::NotFound, check_metadata(&[], &dir_path).unwrap_err().kind()); +} From d7c3f588eb78917952aab237c11a0edaae3c84f3 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 25 Jan 2020 12:57:15 -0600 Subject: [PATCH 1566/5092] Add shims for opendir and closedir --- src/lib.rs | 2 +- src/machine.rs | 2 + src/shims/foreign_items/posix.rs | 5 +++ src/shims/foreign_items/posix/linux.rs | 7 ++++ src/shims/fs.rs | 57 +++++++++++++++++++++++++- 5 files changed, 71 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 85ee98aa3a12..0c4439287b32 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,7 +36,7 @@ pub use rustc_mir::interpret::{self, AllocMap, PlaceTy}; pub use crate::shims::dlsym::{Dlsym, EvalContextExt as DlsymEvalContextExt}; pub use crate::shims::env::{EnvVars, EvalContextExt as EnvEvalContextExt}; pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextExt; -pub use crate::shims::fs::{EvalContextExt as FileEvalContextExt, FileHandler}; +pub use crate::shims::fs::{DirHandler, EvalContextExt as FileEvalContextExt, FileHandler}; pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as PanicEvalContextExt}; pub use crate::shims::time::EvalContextExt as TimeEvalContextExt; diff --git a/src/machine.rs b/src/machine.rs index 5d933fe8a7f6..a6bb35c811aa 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -115,6 +115,7 @@ pub struct Evaluator<'tcx> { pub(crate) communicate: bool, pub(crate) file_handler: FileHandler, + pub(crate) dir_handler: DirHandler, /// The temporary used for storing the argument of /// the call to `miri_start_panic` (the panic payload) when unwinding. @@ -134,6 +135,7 @@ impl<'tcx> Evaluator<'tcx> { tls: TlsData::default(), communicate, file_handler: Default::default(), + dir_handler: Default::default(), panic_payload: None, } } diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index e520e23199e3..636137f62de0 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -119,6 +119,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "closedir" => { + let result = this.closedir(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + "lseek" | "lseek64" => { let result = this.lseek64(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 4d3e1798ce14..4c13624008c9 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -27,6 +27,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + // The only reason this is not in the `posix` module is because the `macos` item has a + // different name. + "opendir" => { + let result = this.opendir(args[0])?; + this.write_scalar(result, dest)?; + } + // Time related shims // This is a POSIX function but it has only been tested on linux. diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 45471a638a18..333b559627c1 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1,6 +1,7 @@ use std::collections::BTreeMap; +use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; -use std::fs::{remove_dir, remove_file, rename, DirBuilder, File, OpenOptions}; +use std::fs::{read_dir, remove_dir, remove_file, rename, DirBuilder, File, OpenOptions, ReadDir}; use std::io::{Read, Seek, SeekFrom, Write}; use std::path::PathBuf; use std::time::SystemTime; @@ -162,6 +163,11 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' } } +#[derive(Debug, Default)] +pub struct DirHandler { + streams: HashMap, ReadDir>, +} + impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn open( @@ -761,6 +767,55 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.try_unwrap_io_result(result) } + + fn opendir(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + + this.check_no_isolation("opendir")?; + + let name = this.read_os_str_from_c_str(this.read_scalar(name_op)?.not_undef()?)?; + + let result = read_dir(name); + + match result { + Ok(dir_iter) => { + let size = 1; + let kind = MiriMemoryKind::Env; + let align = this.min_align(size, kind); + let dir_ptr = this.memory.allocate(Size::from_bytes(size), align, kind.into()); + let prev = this + .machine + .dir_handler + .streams + .insert(dir_ptr, dir_iter); + if let Some(_) = prev { + throw_unsup_format!("The pointer allocated for opendir was already registered by a previous call to opendir") + } else { + Ok(Scalar::Ptr(dir_ptr)) + } + } + Err(e) => { + this.set_last_error_from_io_error(e)?; + Ok(Scalar::from_int(0, this.memory.pointer_size())) + } + } + } + + fn closedir(&mut self, dirp_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.check_no_isolation("closedir")?; + + let dirp = this.force_ptr(this.read_scalar(dirp_op)?.not_undef()?)?; + + if let Some(dir_iter) = this.machine.dir_handler.streams.remove(&dirp) { + drop(dir_iter); + this.memory.deallocate(dirp, None, MiriMemoryKind::Env.into())?; + Ok(0) + } else { + this.handle_not_found() + } + } } /// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch when From 5d353391111c3b0b6d14c08b5813cc175780789a Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 25 Jan 2020 17:36:51 -0600 Subject: [PATCH 1567/5092] Add shim for readdir64_r --- src/shims/foreign_items/posix/linux.rs | 7 ++ src/shims/fs.rs | 116 ++++++++++++++++++++++++- tests/run-pass/fs.rs | 20 ++++- 3 files changed, 141 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 4c13624008c9..2872e92fa1ee 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -34,6 +34,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(result, dest)?; } + // The `macos` module has a parallel foreign item, `readdir_r`, which uses a different + // struct layout. + "readdir64_r" => { + let result = this.readdir64_r(args[0], args[1], args[2])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + // Time related shims // This is a POSIX function but it has only been tested on linux. diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 333b559627c1..a5acafdaaaf0 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; -use std::fs::{read_dir, remove_dir, remove_file, rename, DirBuilder, File, OpenOptions, ReadDir}; +use std::fs::{read_dir, remove_dir, remove_file, rename, DirBuilder, File, FileType, OpenOptions, ReadDir}; use std::io::{Read, Seek, SeekFrom, Write}; use std::path::PathBuf; use std::time::SystemTime; @@ -161,6 +161,43 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' this.set_last_error(ebadf)?; Ok((-1).into()) } + + fn file_type_to_d_type(&mut self, file_type: std::io::Result) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + match file_type { + Ok(file_type) => { + if file_type.is_dir() { + Ok(this.eval_libc("DT_DIR")?.to_u8()? as i32) + } else if file_type.is_file() { + Ok(this.eval_libc("DT_REG")?.to_u8()? as i32) + } else if file_type.is_symlink() { + Ok(this.eval_libc("DT_LNK")?.to_u8()? as i32) + } else { + #[cfg(unix)] + { + use std::os::unix::fs::FileTypeExt; + if file_type.is_block_device() { + Ok(this.eval_libc("DT_BLK")?.to_u8()? as i32) + } else if file_type.is_char_device() { + Ok(this.eval_libc("DT_CHR")?.to_u8()? as i32) + } else if file_type.is_fifo() { + Ok(this.eval_libc("DT_FIFO")?.to_u8()? as i32) + } else if file_type.is_socket() { + Ok(this.eval_libc("DT_SOCK")?.to_u8()? as i32) + } else { + Ok(this.eval_libc("DT_UNKNOWN")?.to_u8()? as i32) + } + } + #[cfg(not(unix))] + Ok(this.eval_libc("DT_UNKNOWN")?.to_u8()? as i32) + } + } + Err(e) => return match e.raw_os_error() { + Some(error) => Ok(error), + None => throw_unsup_format!("The error {} couldn't be converted to a return value", e), + } + } + } } #[derive(Debug, Default)] @@ -801,6 +838,83 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + fn readdir64_r( + &mut self, + dirp_op: OpTy<'tcx, Tag>, + entry_op: OpTy<'tcx, Tag>, + result_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.check_no_isolation("readdir64_r")?; + + let dirp = this.force_ptr(this.read_scalar(dirp_op)?.not_undef()?)?; + + let entry_ptr = this.force_ptr(this.read_scalar(entry_op)?.not_undef()?)?; + let dirent64_layout = this.libc_ty_layout("dirent64")?; + this.memory.check_ptr_access( + Scalar::Ptr(entry_ptr), + dirent64_layout.size, + dirent64_layout.align.abi, + )?; + + if let Some(dir_iter) = this.machine.dir_handler.streams.get_mut(&dirp) { + match dir_iter.next() { + Some(Ok(dir_entry)) => { + // write into entry, write pointer to result, return 0 on success + let entry_place = this.deref_operand(entry_op)?; + let ino64_t_layout = this.libc_ty_layout("ino64_t")?; + let off64_t_layout = this.libc_ty_layout("off64_t")?; + let c_ushort_layout = this.libc_ty_layout("c_ushort")?; + let c_uchar_layout = this.libc_ty_layout("c_uchar")?; + + let name_offset = dirent64_layout.details.fields.offset(4); + let name_ptr = entry_ptr.offset(name_offset, this)?; + + #[cfg(unix)] + let ino = std::os::unix::fs::DirEntryExt::ino(&dir_entry); + #[cfg(not(unix))] + let ino = 0; + + #[cfg(unix)] + let file_name = dir_entry.file_name(); + #[cfg(unix)] + let file_name = std::os::unix::ffi::OsStrExt::as_bytes(file_name.as_os_str()); + #[cfg(not(unix))] + let file_name = b""; + + let file_type = this.file_type_to_d_type(dir_entry.file_type())? as u128; + + let imms = [ + immty_from_uint_checked(ino, ino64_t_layout)?, // d_ino + immty_from_uint_checked(0u128, off64_t_layout)?, // d_off + immty_from_uint_checked(0u128, c_ushort_layout)?, // d_reclen + immty_from_uint_checked(file_type, c_uchar_layout)?, // d_type + ]; + this.write_packed_immediates(entry_place, &imms)?; + this.memory.write_bytes(Scalar::Ptr(name_ptr), file_name.iter().copied())?; + + let result_place = this.deref_operand(result_op)?; + this.write_scalar(this.read_scalar(entry_op)?, result_place.into())?; + + Ok(0) + } + None => { + // end of stream: return 0, assign *result=NULL + this.write_null(this.deref_operand(result_op)?.into())?; + Ok(0) + } + Some(Err(e)) => match e.raw_os_error() { + // return positive error number on error + Some(error) => Ok(error), + None => throw_unsup_format!("The error {} couldn't be converted to a return value", e), + } + } + } else { + throw_unsup_format!("The DIR pointer passed to readdir64_r did not come from opendir") + } + } + fn closedir(&mut self, dirp_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 7f920d8c19d8..cc450e6c0141 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -1,7 +1,7 @@ // ignore-windows: File handling is not implemented yet // compile-flags: -Zmiri-disable-isolation -use std::fs::{File, create_dir, remove_dir, remove_dir_all, remove_file, rename}; +use std::fs::{File, create_dir, read_dir, remove_dir, remove_dir_all, remove_file, rename}; use std::io::{Read, Write, ErrorKind, Result, Seek, SeekFrom}; use std::path::{PathBuf, Path}; @@ -199,6 +199,24 @@ fn test_directory() { create_dir(&dir_path).unwrap(); // Test that the metadata of a directory is correct. assert!(dir_path.metadata().unwrap().is_dir()); + + // Create some files inside the directory + let f1_path = dir_path.join("f1"); + drop(File::create(&f1_path).unwrap()); + let f2_path = dir_path.join("f2"); + drop(File::create(&f2_path).unwrap()); + // Test that the files are present inside the directory + let mut dir_iter = read_dir(&dir_path).unwrap(); + let first_dir_entry = dir_iter.next().unwrap().unwrap(); + let second_dir_entry = dir_iter.next().unwrap().unwrap(); + assert!(first_dir_entry.file_name() == "f1" || first_dir_entry.file_name() == "f2"); + assert!(second_dir_entry.file_name() == "f1" || second_dir_entry.file_name() == "f2"); + assert!(dir_iter.next().is_none()); + drop(dir_iter); + // Clean up the files in the directory + remove_file(&f1_path).unwrap(); + remove_file(&f2_path).unwrap(); + // Deleting the directory should succeed. remove_dir(&dir_path).unwrap(); // Reading the metadata of a non-existent file should fail with a "not found" error. From 974362ef6446c5ef044a29a5ce0bc2502fd9bea1 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 26 Jan 2020 14:13:22 -0600 Subject: [PATCH 1568/5092] Handle differing sizes of mode_t mode_t is a u32 on Linux and a u16 on macOS --- src/shims/fs.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index a5acafdaaaf0..bedffe4b8ed1 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -775,7 +775,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("mkdir")?; + #[cfg(target_os = "linux")] let mode = this.read_scalar(mode_op)?.to_u32()?; + #[cfg(not(target_os = "linux"))] + let mode = this.read_scalar(mode_op)?.not_undef()?.to_u16()?; let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; @@ -783,8 +786,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[cfg(target_family = "unix")] { use std::os::unix::fs::DirBuilderExt; - builder.mode(mode); + builder.mode(mode.into()); } + #[cfg(not(target_family = "unix"))] + let _mode = mode; let result = builder.create(path).map(|_| 0i32); this.try_unwrap_io_result(result) From ba61a9b37c6261b93e4d46b8adb44e5317456b73 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 26 Jan 2020 14:47:36 -0600 Subject: [PATCH 1569/5092] Add shims for macOS-specific symbols --- src/shims/foreign_items/posix/macos.rs | 14 +++++ src/shims/fs.rs | 77 ++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 25ac7e93867f..e6f4047eee47 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -42,6 +42,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + // The only reason this is not in the `posix` module is because the `linux` item has a + // different name. + "opendir$INODE64" => { + let result = this.opendir(args[0])?; + this.write_scalar(result, dest)?; + } + + // The `linux` module has a parallel foreign item, `readdir64_r`, which uses a + // different struct layout. + "readdir_r$INODE64" => { + let result = this.readdir_r(args[0], args[1], args[2])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + // Time related shims "gettimeofday" => { let result = this.gettimeofday(args[0], args[1])?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index bedffe4b8ed1..12684018eec3 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -920,6 +920,83 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + fn readdir_r( + &mut self, + dirp_op: OpTy<'tcx, Tag>, + entry_op: OpTy<'tcx, Tag>, + result_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.check_no_isolation("readdir_r")?; + + let dirp = this.force_ptr(this.read_scalar(dirp_op)?.not_undef()?)?; + + let entry_ptr = this.force_ptr(this.read_scalar(entry_op)?.not_undef()?)?; + let dirent_layout = this.libc_ty_layout("dirent")?; + this.memory.check_ptr_access( + Scalar::Ptr(entry_ptr), + dirent_layout.size, + dirent_layout.align.abi, + )?; + + if let Some(dir_iter) = this.machine.dir_handler.streams.get_mut(&dirp) { + match dir_iter.next() { + Some(Ok(dir_entry)) => { + // write into entry, write pointer to result, return 0 on success + let entry_place = this.deref_operand(entry_op)?; + let ino_t_layout = this.libc_ty_layout("ino_t")?; + let off_t_layout = this.libc_ty_layout("off_t")?; + let c_ushort_layout = this.libc_ty_layout("c_ushort")?; + let c_uchar_layout = this.libc_ty_layout("c_uchar")?; + + let name_offset = dirent_layout.details.fields.offset(4); + let name_ptr = entry_ptr.offset(name_offset, this)?; + + #[cfg(unix)] + let ino = std::os::unix::fs::DirEntryExt::ino(&dir_entry); + #[cfg(not(unix))] + let ino = 0; + + #[cfg(unix)] + let file_name = dir_entry.file_name(); + #[cfg(unix)] + let file_name = std::os::unix::ffi::OsStrExt::as_bytes(file_name.as_os_str()); + #[cfg(not(unix))] + let file_name = b""; + + let file_type = this.file_type_to_d_type(dir_entry.file_type())? as u128; + + let imms = [ + immty_from_uint_checked(ino, ino_t_layout)?, // d_ino + immty_from_uint_checked(0u128, off_t_layout)?, // d_off + immty_from_uint_checked(0u128, c_ushort_layout)?, // d_reclen + immty_from_uint_checked(file_type, c_uchar_layout)?, // d_type + ]; + this.write_packed_immediates(entry_place, &imms)?; + this.memory.write_bytes(Scalar::Ptr(name_ptr), file_name.iter().copied())?; + + let result_place = this.deref_operand(result_op)?; + this.write_scalar(this.read_scalar(entry_op)?, result_place.into())?; + + Ok(0) + } + None => { + // end of stream: return 0, assign *result=NULL + this.write_null(this.deref_operand(result_op)?.into())?; + Ok(0) + } + Some(Err(e)) => match e.raw_os_error() { + // return positive error number on error + Some(error) => Ok(error), + None => throw_unsup_format!("The error {} couldn't be converted to a return value", e), + } + } + } else { + throw_unsup_format!("The DIR pointer passed to readdir_r did not come from opendir") + } + } + fn closedir(&mut self, dirp_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); From d461c12c83bc9805b818b9ba9a4791ee81158d97 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 26 Jan 2020 15:09:24 -0600 Subject: [PATCH 1570/5092] Add more information to test asserts --- tests/run-pass/fs.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index cc450e6c0141..8db755c7a730 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -209,8 +209,16 @@ fn test_directory() { let mut dir_iter = read_dir(&dir_path).unwrap(); let first_dir_entry = dir_iter.next().unwrap().unwrap(); let second_dir_entry = dir_iter.next().unwrap().unwrap(); - assert!(first_dir_entry.file_name() == "f1" || first_dir_entry.file_name() == "f2"); - assert!(second_dir_entry.file_name() == "f1" || second_dir_entry.file_name() == "f2"); + assert!( + first_dir_entry.file_name() == "f1" || first_dir_entry.file_name() == "f2", + "File name was {:?} instead of f1 or f2", + first_dir_entry.file_name(), + ); + assert!( + second_dir_entry.file_name() == "f1" || second_dir_entry.file_name() == "f2", + "File name was {:?} instead of f1 or f2", + second_dir_entry.file_name(), + ); assert!(dir_iter.next().is_none()); drop(dir_iter); // Clean up the files in the directory From a82049587c2abbf85dc40a68c52834b068f88406 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 26 Jan 2020 15:45:35 -0600 Subject: [PATCH 1571/5092] Use longer file names in test --- tests/run-pass/fs.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 8db755c7a730..59eb4e014378 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -201,29 +201,31 @@ fn test_directory() { assert!(dir_path.metadata().unwrap().is_dir()); // Create some files inside the directory - let f1_path = dir_path.join("f1"); - drop(File::create(&f1_path).unwrap()); - let f2_path = dir_path.join("f2"); - drop(File::create(&f2_path).unwrap()); + let path_1 = dir_path.join("test_file_1"); + drop(File::create(&path_1).unwrap()); + let path_2 = dir_path.join("test_file_2"); + drop(File::create(&path_2).unwrap()); // Test that the files are present inside the directory let mut dir_iter = read_dir(&dir_path).unwrap(); let first_dir_entry = dir_iter.next().unwrap().unwrap(); let second_dir_entry = dir_iter.next().unwrap().unwrap(); assert!( - first_dir_entry.file_name() == "f1" || first_dir_entry.file_name() == "f2", - "File name was {:?} instead of f1 or f2", + first_dir_entry.file_name() == "test_file_1" || + first_dir_entry.file_name() == "test_file_2", + "File name was {:?} instead of test_file_1 or test_file_2", first_dir_entry.file_name(), ); assert!( - second_dir_entry.file_name() == "f1" || second_dir_entry.file_name() == "f2", - "File name was {:?} instead of f1 or f2", + second_dir_entry.file_name() == "test_file_1" || + second_dir_entry.file_name() == "test_file_2", + "File name was {:?} instead of test_file_1 or test_file_2", second_dir_entry.file_name(), ); assert!(dir_iter.next().is_none()); drop(dir_iter); // Clean up the files in the directory - remove_file(&f1_path).unwrap(); - remove_file(&f2_path).unwrap(); + remove_file(&path_1).unwrap(); + remove_file(&path_2).unwrap(); // Deleting the directory should succeed. remove_dir(&dir_path).unwrap(); From 515d29aa2ccf6a7339fedab6ac827c45a8357ca5 Mon Sep 17 00:00:00 2001 From: David Cook Date: Thu, 30 Jan 2020 18:57:01 -0600 Subject: [PATCH 1572/5092] Fix dirent layout for macOS --- src/shims/fs.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 12684018eec3..55c66d1cf363 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -950,7 +950,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let c_ushort_layout = this.libc_ty_layout("c_ushort")?; let c_uchar_layout = this.libc_ty_layout("c_uchar")?; - let name_offset = dirent_layout.details.fields.offset(4); + let name_offset = dirent_layout.details.fields.offset(5); let name_ptr = entry_ptr.offset(name_offset, this)?; #[cfg(unix)] @@ -969,8 +969,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let imms = [ immty_from_uint_checked(ino, ino_t_layout)?, // d_ino - immty_from_uint_checked(0u128, off_t_layout)?, // d_off + immty_from_uint_checked(0u128, off_t_layout)?, // d_seekoff immty_from_uint_checked(0u128, c_ushort_layout)?, // d_reclen + immty_from_uint_checked(file_name.len() as u128, c_ushort_layout)?, // d_namlen immty_from_uint_checked(file_type, c_uchar_layout)?, // d_type ]; this.write_packed_immediates(entry_place, &imms)?; From 9a6921a17f6a87470e6425be2d435956b54cbde0 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 8 Feb 2020 20:44:02 -0600 Subject: [PATCH 1573/5092] Add doc comment inside DirHandler --- src/shims/fs.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 55c66d1cf363..b0ae210f55e5 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -202,6 +202,16 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' #[derive(Debug, Default)] pub struct DirHandler { + /// Directory iterators used to emulate libc "directory streams", as used in opendir, readdir, + /// and closedir. + /// + /// When opendir is called, a new allocation is made, a directory iterator is created on the + /// host for the target directory, and an entry is stored in this hash map, indexed by a + /// pointer to the allocation which represents the directory stream. When readdir is called, + /// the directory stream pointer is used to look up the corresponding ReadDir iterator from + /// this HashMap, and information from the next directory entry is returned. When closedir is + /// called, the ReadDir iterator is removed from this HashMap, and the allocation that + /// represented the directory stream is deallocated. streams: HashMap, ReadDir>, } From d4b73efa81bf031dfff846ec2a4cd0f04e462572 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 8 Feb 2020 20:44:35 -0600 Subject: [PATCH 1574/5092] Fix interpreted OS detection --- src/shims/fs.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index b0ae210f55e5..15f5237e0b57 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -785,10 +785,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("mkdir")?; - #[cfg(target_os = "linux")] - let mode = this.read_scalar(mode_op)?.to_u32()?; - #[cfg(not(target_os = "linux"))] - let mode = this.read_scalar(mode_op)?.not_undef()?.to_u16()?; + let mode = if this.tcx.sess.target.target.target_os.to_lowercase() == "macos" { + this.read_scalar(mode_op)?.not_undef()?.to_u16()? as u32 + } else { + this.read_scalar(mode_op)?.to_u32()? + }; let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; From 341212acd67d2409265333f2c598d446525b5468 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 8 Feb 2020 22:27:26 -0600 Subject: [PATCH 1575/5092] Rewrite fs tests --- tests/run-pass/fs.rs | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 59eb4e014378..b938fceb8d02 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -206,23 +206,10 @@ fn test_directory() { let path_2 = dir_path.join("test_file_2"); drop(File::create(&path_2).unwrap()); // Test that the files are present inside the directory - let mut dir_iter = read_dir(&dir_path).unwrap(); - let first_dir_entry = dir_iter.next().unwrap().unwrap(); - let second_dir_entry = dir_iter.next().unwrap().unwrap(); - assert!( - first_dir_entry.file_name() == "test_file_1" || - first_dir_entry.file_name() == "test_file_2", - "File name was {:?} instead of test_file_1 or test_file_2", - first_dir_entry.file_name(), - ); - assert!( - second_dir_entry.file_name() == "test_file_1" || - second_dir_entry.file_name() == "test_file_2", - "File name was {:?} instead of test_file_1 or test_file_2", - second_dir_entry.file_name(), - ); - assert!(dir_iter.next().is_none()); - drop(dir_iter); + let dir_iter = read_dir(&dir_path).unwrap(); + let mut file_names = dir_iter.map(|e| e.unwrap().file_name()).collect::>(); + file_names.sort_unstable(); + assert_eq!(file_names, vec!["test_file_1", "test_file_2"]); // Clean up the files in the directory remove_file(&path_1).unwrap(); remove_file(&path_2).unwrap(); From 947fa1fa26ca5ebc19dd8b39ee8289ce54e0c8db Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 16 Feb 2020 12:12:20 -0600 Subject: [PATCH 1576/5092] Miscellaneous review comments --- src/shims/fs.rs | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 15f5237e0b57..6dcdf5717c01 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -785,7 +785,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("mkdir")?; - let mode = if this.tcx.sess.target.target.target_os.to_lowercase() == "macos" { + let _mode = if this.tcx.sess.target.target.target_os.to_lowercase() == "macos" { this.read_scalar(mode_op)?.not_undef()?.to_u16()? as u32 } else { this.read_scalar(mode_op)?.to_u32()? @@ -794,13 +794,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; let mut builder = DirBuilder::new(); + + // If the host supports it, forward on the mode of the directory + // (i.e. permission bits and the sticky bit) #[cfg(target_family = "unix")] { use std::os::unix::fs::DirBuilderExt; - builder.mode(mode.into()); + builder.mode(_mode.into()); } - #[cfg(not(target_family = "unix"))] - let _mode = mode; + let result = builder.create(path).map(|_| 0i32); this.try_unwrap_io_result(result) @@ -842,7 +844,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .streams .insert(dir_ptr, dir_iter); if let Some(_) = prev { - throw_unsup_format!("The pointer allocated for opendir was already registered by a previous call to opendir") + panic!("The pointer allocated for opendir was already registered by a previous call to opendir") } else { Ok(Scalar::Ptr(dir_ptr)) } @@ -868,11 +870,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let entry_ptr = this.force_ptr(this.read_scalar(entry_op)?.not_undef()?)?; let dirent64_layout = this.libc_ty_layout("dirent64")?; - this.memory.check_ptr_access( - Scalar::Ptr(entry_ptr), - dirent64_layout.size, - dirent64_layout.align.abi, - )?; if let Some(dir_iter) = this.machine.dir_handler.streams.get_mut(&dirp) { match dir_iter.next() { @@ -945,11 +942,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let entry_ptr = this.force_ptr(this.read_scalar(entry_op)?.not_undef()?)?; let dirent_layout = this.libc_ty_layout("dirent")?; - this.memory.check_ptr_access( - Scalar::Ptr(entry_ptr), - dirent_layout.size, - dirent_layout.align.abi, - )?; if let Some(dir_iter) = this.machine.dir_handler.streams.get_mut(&dirp) { match dir_iter.next() { From 94f611348f4484fe95c5adacac93923f3fcab9a7 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 16 Feb 2020 13:13:16 -0600 Subject: [PATCH 1577/5092] Use os_str_length_as_c_str in readdir[64]_r --- src/helpers.rs | 41 ++++++++++++++++++++++++++--------------- src/shims/fs.rs | 43 +++++++++++++++++++++---------------------- 2 files changed, 47 insertions(+), 37 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 5128176acb58..24adc72fa87b 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -483,21 +483,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx scalar: Scalar, size: u64, ) -> InterpResult<'tcx, bool> { - #[cfg(target_os = "unix")] - fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - std::os::unix::ffi::OsStringExt::into_bytes(os_str) - } - #[cfg(not(target_os = "unix"))] - fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the - // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually - // valid. - os_str - .to_str() - .map(|s| s.as_bytes()) - .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) - } - let bytes = os_str_to_bytes(os_str)?; // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null // terminator to memory using the `ptr` pointer would cause an out-of-bounds access. @@ -510,6 +495,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(true) } + /// Helper function to determine how long an OsStr would be as a C string, not including the + /// null terminator. + fn os_str_length_as_c_str( + &mut self, + os_str: &OsStr, + ) -> InterpResult<'tcx, usize> { + let bytes = os_str_to_bytes(os_str)?; + Ok(bytes.len()) + } + fn alloc_os_str_as_c_str( &mut self, os_str: &OsStr, @@ -525,6 +520,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } +#[cfg(target_os = "unix")] +fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + std::os::unix::ffi::OsStringExt::into_bytes(os_str) +} + +#[cfg(not(target_os = "unix"))] +fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the + // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually + // valid. + os_str + .to_str() + .map(|s| s.as_bytes()) + .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) +} + pub fn immty_from_int_checked<'tcx>( int: impl Into, layout: TyLayout<'tcx>, diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 6dcdf5717c01..cee9174696ff 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -875,27 +875,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match dir_iter.next() { Some(Ok(dir_entry)) => { // write into entry, write pointer to result, return 0 on success + + let name_offset = dirent64_layout.details.fields.offset(4); + let name_ptr = entry_ptr.offset(name_offset, this)?; + + let name_fits = this.write_os_str_to_c_str(&dir_entry.file_name(), Scalar::Ptr(name_ptr), 256)?; + if !name_fits { + panic!("A directory entry had a name too large to fit in libc::dirent64"); + } + let entry_place = this.deref_operand(entry_op)?; let ino64_t_layout = this.libc_ty_layout("ino64_t")?; let off64_t_layout = this.libc_ty_layout("off64_t")?; let c_ushort_layout = this.libc_ty_layout("c_ushort")?; let c_uchar_layout = this.libc_ty_layout("c_uchar")?; - let name_offset = dirent64_layout.details.fields.offset(4); - let name_ptr = entry_ptr.offset(name_offset, this)?; - #[cfg(unix)] let ino = std::os::unix::fs::DirEntryExt::ino(&dir_entry); #[cfg(not(unix))] let ino = 0; - #[cfg(unix)] - let file_name = dir_entry.file_name(); - #[cfg(unix)] - let file_name = std::os::unix::ffi::OsStrExt::as_bytes(file_name.as_os_str()); - #[cfg(not(unix))] - let file_name = b""; - let file_type = this.file_type_to_d_type(dir_entry.file_type())? as u128; let imms = [ @@ -905,7 +904,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(file_type, c_uchar_layout)?, // d_type ]; this.write_packed_immediates(entry_place, &imms)?; - this.memory.write_bytes(Scalar::Ptr(name_ptr), file_name.iter().copied())?; let result_place = this.deref_operand(result_op)?; this.write_scalar(this.read_scalar(entry_op)?, result_place.into())?; @@ -947,26 +945,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match dir_iter.next() { Some(Ok(dir_entry)) => { // write into entry, write pointer to result, return 0 on success + + let name_offset = dirent_layout.details.fields.offset(5); + let name_ptr = entry_ptr.offset(name_offset, this)?; + + let file_name = dir_entry.file_name(); + let name_fits = this.write_os_str_to_c_str(&file_name, Scalar::Ptr(name_ptr), 1024)?; + if !name_fits { + panic!("A directory entry had a name too large to fit in libc::dirent"); + } + let entry_place = this.deref_operand(entry_op)?; let ino_t_layout = this.libc_ty_layout("ino_t")?; let off_t_layout = this.libc_ty_layout("off_t")?; let c_ushort_layout = this.libc_ty_layout("c_ushort")?; let c_uchar_layout = this.libc_ty_layout("c_uchar")?; - let name_offset = dirent_layout.details.fields.offset(5); - let name_ptr = entry_ptr.offset(name_offset, this)?; - #[cfg(unix)] let ino = std::os::unix::fs::DirEntryExt::ino(&dir_entry); #[cfg(not(unix))] let ino = 0; - #[cfg(unix)] - let file_name = dir_entry.file_name(); - #[cfg(unix)] - let file_name = std::os::unix::ffi::OsStrExt::as_bytes(file_name.as_os_str()); - #[cfg(not(unix))] - let file_name = b""; + let file_name_len = this.os_str_length_as_c_str(&file_name)? as u128; let file_type = this.file_type_to_d_type(dir_entry.file_type())? as u128; @@ -974,11 +974,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(ino, ino_t_layout)?, // d_ino immty_from_uint_checked(0u128, off_t_layout)?, // d_seekoff immty_from_uint_checked(0u128, c_ushort_layout)?, // d_reclen - immty_from_uint_checked(file_name.len() as u128, c_ushort_layout)?, // d_namlen + immty_from_uint_checked(file_name_len, c_ushort_layout)?, // d_namlen immty_from_uint_checked(file_type, c_uchar_layout)?, // d_type ]; this.write_packed_immediates(entry_place, &imms)?; - this.memory.write_bytes(Scalar::Ptr(name_ptr), file_name.iter().copied())?; let result_place = this.deref_operand(result_op)?; this.write_scalar(this.read_scalar(entry_op)?, result_place.into())?; From d6da4ab4b8c7295ad44869ff31784619086c6642 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 16 Feb 2020 13:22:50 -0600 Subject: [PATCH 1578/5092] Add comments --- src/shims/fs.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index cee9174696ff..1144425fe605 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -874,7 +874,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(dir_iter) = this.machine.dir_handler.streams.get_mut(&dirp) { match dir_iter.next() { Some(Ok(dir_entry)) => { - // write into entry, write pointer to result, return 0 on success + // Write into entry, write pointer to result, return 0 on success. + // The name is written with write_os_str_to_c_str, while the rest of the + // dirent64 struct is written using write_packed_immediates. let name_offset = dirent64_layout.details.fields.offset(4); let name_ptr = entry_ptr.offset(name_offset, this)?; @@ -944,7 +946,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(dir_iter) = this.machine.dir_handler.streams.get_mut(&dirp) { match dir_iter.next() { Some(Ok(dir_entry)) => { - // write into entry, write pointer to result, return 0 on success + // Write into entry, write pointer to result, return 0 on success. + // The name is written with write_os_str_to_c_str, while the rest of the + // dirent struct is written using write_packed_Immediates. let name_offset = dirent_layout.details.fields.offset(5); let name_ptr = entry_ptr.offset(name_offset, this)?; From 725d6bfa9c73c70733c3511901f5ddb6296587da Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 16 Feb 2020 13:39:06 -0600 Subject: [PATCH 1579/5092] Move error up, early return --- src/shims/fs.rs | 211 ++++++++++++++++++++++++------------------------ 1 file changed, 107 insertions(+), 104 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 1144425fe605..7ae378192a21 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -871,60 +871,62 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let entry_ptr = this.force_ptr(this.read_scalar(entry_op)?.not_undef()?)?; let dirent64_layout = this.libc_ty_layout("dirent64")?; - if let Some(dir_iter) = this.machine.dir_handler.streams.get_mut(&dirp) { - match dir_iter.next() { - Some(Ok(dir_entry)) => { - // Write into entry, write pointer to result, return 0 on success. - // The name is written with write_os_str_to_c_str, while the rest of the - // dirent64 struct is written using write_packed_immediates. + let dir_iter = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { + err_unsup_format!("The DIR pointer passed to readdir64_r did not come from opendir") + })?; + match dir_iter.next() { + Some(Ok(dir_entry)) => { + // Write into entry, write pointer to result, return 0 on success. + // The name is written with write_os_str_to_c_str, while the rest of the + // dirent64 struct is written using write_packed_immediates. - let name_offset = dirent64_layout.details.fields.offset(4); - let name_ptr = entry_ptr.offset(name_offset, this)?; + let name_offset = dirent64_layout.details.fields.offset(4); + let name_ptr = entry_ptr.offset(name_offset, this)?; - let name_fits = this.write_os_str_to_c_str(&dir_entry.file_name(), Scalar::Ptr(name_ptr), 256)?; - if !name_fits { - panic!("A directory entry had a name too large to fit in libc::dirent64"); - } - - let entry_place = this.deref_operand(entry_op)?; - let ino64_t_layout = this.libc_ty_layout("ino64_t")?; - let off64_t_layout = this.libc_ty_layout("off64_t")?; - let c_ushort_layout = this.libc_ty_layout("c_ushort")?; - let c_uchar_layout = this.libc_ty_layout("c_uchar")?; - - #[cfg(unix)] - let ino = std::os::unix::fs::DirEntryExt::ino(&dir_entry); - #[cfg(not(unix))] - let ino = 0; - - let file_type = this.file_type_to_d_type(dir_entry.file_type())? as u128; - - let imms = [ - immty_from_uint_checked(ino, ino64_t_layout)?, // d_ino - immty_from_uint_checked(0u128, off64_t_layout)?, // d_off - immty_from_uint_checked(0u128, c_ushort_layout)?, // d_reclen - immty_from_uint_checked(file_type, c_uchar_layout)?, // d_type - ]; - this.write_packed_immediates(entry_place, &imms)?; - - let result_place = this.deref_operand(result_op)?; - this.write_scalar(this.read_scalar(entry_op)?, result_place.into())?; - - Ok(0) - } - None => { - // end of stream: return 0, assign *result=NULL - this.write_null(this.deref_operand(result_op)?.into())?; - Ok(0) - } - Some(Err(e)) => match e.raw_os_error() { - // return positive error number on error - Some(error) => Ok(error), - None => throw_unsup_format!("The error {} couldn't be converted to a return value", e), + let file_name = dir_entry.file_name(); + let name_fits = this.write_os_str_to_c_str(&file_name, Scalar::Ptr(name_ptr), 256)?; + if !name_fits { + panic!("A directory entry had a name too large to fit in libc::dirent64"); } + + let entry_place = this.deref_operand(entry_op)?; + let ino64_t_layout = this.libc_ty_layout("ino64_t")?; + let off64_t_layout = this.libc_ty_layout("off64_t")?; + let c_ushort_layout = this.libc_ty_layout("c_ushort")?; + let c_uchar_layout = this.libc_ty_layout("c_uchar")?; + + #[cfg(unix)] + let ino = std::os::unix::fs::DirEntryExt::ino(&dir_entry); + #[cfg(not(unix))] + let ino = 0; + + let file_type = this.file_type_to_d_type(dir_entry.file_type())? as u128; + + let imms = [ + immty_from_uint_checked(ino, ino64_t_layout)?, // d_ino + immty_from_uint_checked(0u128, off64_t_layout)?, // d_off + immty_from_uint_checked(0u128, c_ushort_layout)?, // d_reclen + immty_from_uint_checked(file_type, c_uchar_layout)?, // d_type + ]; + this.write_packed_immediates(entry_place, &imms)?; + + let result_place = this.deref_operand(result_op)?; + this.write_scalar(this.read_scalar(entry_op)?, result_place.into())?; + + Ok(0) } - } else { - throw_unsup_format!("The DIR pointer passed to readdir64_r did not come from opendir") + None => { + // end of stream: return 0, assign *result=NULL + this.write_null(this.deref_operand(result_op)?.into())?; + Ok(0) + } + Some(Err(e)) => match e.raw_os_error() { + // return positive error number on error + Some(error) => Ok(error), + None => { + throw_unsup_format!("The error {} couldn't be converted to a return value", e) + } + }, } } @@ -943,64 +945,65 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let entry_ptr = this.force_ptr(this.read_scalar(entry_op)?.not_undef()?)?; let dirent_layout = this.libc_ty_layout("dirent")?; - if let Some(dir_iter) = this.machine.dir_handler.streams.get_mut(&dirp) { - match dir_iter.next() { - Some(Ok(dir_entry)) => { - // Write into entry, write pointer to result, return 0 on success. - // The name is written with write_os_str_to_c_str, while the rest of the - // dirent struct is written using write_packed_Immediates. + let dir_iter = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { + err_unsup_format!("The DIR pointer passed to readdir_r did not come from opendir") + })?; + match dir_iter.next() { + Some(Ok(dir_entry)) => { + // Write into entry, write pointer to result, return 0 on success. + // The name is written with write_os_str_to_c_str, while the rest of the + // dirent struct is written using write_packed_Immediates. - let name_offset = dirent_layout.details.fields.offset(5); - let name_ptr = entry_ptr.offset(name_offset, this)?; + let name_offset = dirent_layout.details.fields.offset(5); + let name_ptr = entry_ptr.offset(name_offset, this)?; - let file_name = dir_entry.file_name(); - let name_fits = this.write_os_str_to_c_str(&file_name, Scalar::Ptr(name_ptr), 1024)?; - if !name_fits { - panic!("A directory entry had a name too large to fit in libc::dirent"); - } - - let entry_place = this.deref_operand(entry_op)?; - let ino_t_layout = this.libc_ty_layout("ino_t")?; - let off_t_layout = this.libc_ty_layout("off_t")?; - let c_ushort_layout = this.libc_ty_layout("c_ushort")?; - let c_uchar_layout = this.libc_ty_layout("c_uchar")?; - - #[cfg(unix)] - let ino = std::os::unix::fs::DirEntryExt::ino(&dir_entry); - #[cfg(not(unix))] - let ino = 0; - - let file_name_len = this.os_str_length_as_c_str(&file_name)? as u128; - - let file_type = this.file_type_to_d_type(dir_entry.file_type())? as u128; - - let imms = [ - immty_from_uint_checked(ino, ino_t_layout)?, // d_ino - immty_from_uint_checked(0u128, off_t_layout)?, // d_seekoff - immty_from_uint_checked(0u128, c_ushort_layout)?, // d_reclen - immty_from_uint_checked(file_name_len, c_ushort_layout)?, // d_namlen - immty_from_uint_checked(file_type, c_uchar_layout)?, // d_type - ]; - this.write_packed_immediates(entry_place, &imms)?; - - let result_place = this.deref_operand(result_op)?; - this.write_scalar(this.read_scalar(entry_op)?, result_place.into())?; - - Ok(0) - } - None => { - // end of stream: return 0, assign *result=NULL - this.write_null(this.deref_operand(result_op)?.into())?; - Ok(0) - } - Some(Err(e)) => match e.raw_os_error() { - // return positive error number on error - Some(error) => Ok(error), - None => throw_unsup_format!("The error {} couldn't be converted to a return value", e), + let file_name = dir_entry.file_name(); + let name_fits = this.write_os_str_to_c_str(&file_name, Scalar::Ptr(name_ptr), 1024)?; + if !name_fits { + panic!("A directory entry had a name too large to fit in libc::dirent"); } + + let entry_place = this.deref_operand(entry_op)?; + let ino_t_layout = this.libc_ty_layout("ino_t")?; + let off_t_layout = this.libc_ty_layout("off_t")?; + let c_ushort_layout = this.libc_ty_layout("c_ushort")?; + let c_uchar_layout = this.libc_ty_layout("c_uchar")?; + + #[cfg(unix)] + let ino = std::os::unix::fs::DirEntryExt::ino(&dir_entry); + #[cfg(not(unix))] + let ino = 0; + + let file_name_len = this.os_str_length_as_c_str(&file_name)? as u128; + + let file_type = this.file_type_to_d_type(dir_entry.file_type())? as u128; + + let imms = [ + immty_from_uint_checked(ino, ino_t_layout)?, // d_ino + immty_from_uint_checked(0u128, off_t_layout)?, // d_seekoff + immty_from_uint_checked(0u128, c_ushort_layout)?, // d_reclen + immty_from_uint_checked(file_name_len, c_ushort_layout)?, // d_namlen + immty_from_uint_checked(file_type, c_uchar_layout)?, // d_type + ]; + this.write_packed_immediates(entry_place, &imms)?; + + let result_place = this.deref_operand(result_op)?; + this.write_scalar(this.read_scalar(entry_op)?, result_place.into())?; + + Ok(0) } - } else { - throw_unsup_format!("The DIR pointer passed to readdir_r did not come from opendir") + None => { + // end of stream: return 0, assign *result=NULL + this.write_null(this.deref_operand(result_op)?.into())?; + Ok(0) + } + Some(Err(e)) => match e.raw_os_error() { + // return positive error number on error + Some(error) => Ok(error), + None => { + throw_unsup_format!("The error {} couldn't be converted to a return value", e) + } + }, } } From a555e1ec25389ab870009387812d07237badfbcd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Feb 2020 22:44:16 +0100 Subject: [PATCH 1580/5092] cargo update --- Cargo.lock | 373 ++++++++++++++++--------------------- test-cargo-miri/Cargo.lock | 50 ++--- 2 files changed, 184 insertions(+), 239 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9550b2bfdfe3..7f5719b82a0c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,15 +2,15 @@ # It is not intended for manual editing. [[package]] name = "aho-corasick" -version = "0.7.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "arrayref" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -20,26 +20,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "atty" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "autocfg" -version = "0.1.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "backtrace" -version = "0.3.40" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -48,17 +49,14 @@ name = "backtrace-sys" version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "base64" -version = "0.10.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "bitflags" @@ -67,17 +65,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "blake2b_simd" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "byteorder" -version = "1.3.2" +version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -90,18 +88,18 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cc" -version = "1.0.47" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -114,25 +112,17 @@ name = "chrono" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "colored" -version = "1.9.0" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -142,17 +132,17 @@ name = "compiletest_rs" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "diff 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "rustfix 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tester 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -160,21 +150,22 @@ dependencies = [ [[package]] name = "constant_time_eq" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "crossbeam-utils" -version = "0.6.6" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "diff" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -201,8 +192,8 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -211,11 +202,11 @@ name = "env_logger" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -223,7 +214,7 @@ name = "failure" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -232,9 +223,9 @@ name = "failure_derive" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -244,37 +235,40 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "getopts" version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "getrandom" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hermit-abi" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "hex" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -282,12 +276,12 @@ name = "humantime" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "itoa" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -297,7 +291,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.65" +version = "0.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -310,7 +304,7 @@ dependencies = [ [[package]] name = "memchr" -version = "2.2.1" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -326,39 +320,39 @@ dependencies = [ name = "miri" version = "0.1.0" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cargo_metadata 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "colored 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "colored 1.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "compiletest_rs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-integer" -version = "0.1.41" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -368,7 +362,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -376,7 +370,7 @@ dependencies = [ [[package]] name = "quick-error" -version = "1.2.2" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -384,16 +378,16 @@ name = "quote" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -408,25 +402,12 @@ dependencies = [ "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "rand_core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -437,27 +418,6 @@ dependencies = [ "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rand_os" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "redox_syscall" version = "0.1.56" @@ -465,29 +425,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "redox_users" -version = "0.3.1" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex" -version = "1.3.1" +version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex-syntax" -version = "0.6.12" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -500,12 +459,13 @@ dependencies = [ [[package]] name = "rust-argon2" -version = "0.5.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2b_simd 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", + "constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -533,8 +493,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -548,7 +508,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -558,30 +518,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.103" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.103" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.42" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -595,17 +555,17 @@ version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "syn" -version = "1.0.8" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -615,9 +575,9 @@ name = "synstructure" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -627,8 +587,8 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -645,10 +605,10 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.0.5" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -657,13 +617,13 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "thread_local" -version = "0.3.6" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -674,14 +634,14 @@ name = "time" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "unicode-width" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -701,7 +661,7 @@ dependencies = [ [[package]] name = "wasi" -version = "0.7.0" +version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -720,7 +680,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi-util" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -731,38 +691,28 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "wincolor" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [metadata] -"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" -"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" +"checksum aho-corasick 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "743ad5a418686aad3b87fd14c43badd828cf26e214a00f92a384291cf22e1811" +"checksum arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" "checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" -"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" -"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" -"checksum backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea" +"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" +"checksum backtrace 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)" = "e4036b9bf40f3cf16aba72a3d65e8a520fc4bafcdc7079aea8f848c58c5b5536" "checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" -"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" +"checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -"checksum blake2b_simd 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b83b7baab1e671718d78204225800d6b170e648188ac7dc992e9d6bddf87d0c0" -"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" +"checksum blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" +"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" "checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" -"checksum cargo_metadata 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8d2d1617e838936c0d2323a65cc151e03ae19a7678dd24f72bccf27119b90a5d" -"checksum cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)" = "aa87058dce70a3ff5621797f1506cb837edd02ac4c0ae642b4542dce802908b8" +"checksum cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46e3374c604fb39d1a2f35ed5e4a4e30e60d01fab49446e08f1b3e9a90aef202" +"checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "31850b4a4d6bae316f7a09e691c944c28299298837edc0a03f755618c23cbc01" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum colored 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "433e7ac7d511768127ed85b0c4947f47a254131e37864b2dc13f52aa32cd37e5" +"checksum colored 1.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8815e2ab78f3a59928fc32e141fbeece88320a240e43f47b2fd64ea3a88a5b3d" "checksum compiletest_rs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d7b678957210a00ba0fbeacc23d38cbfbf29895564da1616564634351e1dac5e" -"checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120" -"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" -"checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" +"checksum constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +"checksum diff 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" "checksum directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c" "checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" "checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" @@ -770,37 +720,33 @@ dependencies = [ "checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" "checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" "checksum filetime 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1ff6d4dab0aa0c8e6346d46052e93b13a16cf847b54ed357087c35011048cc7d" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" -"checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407" -"checksum hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "023b39be39e3a2da62a94feb433e91e8bcd37676fbc8bea371daf52b7a769a3e" +"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +"checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8" +"checksum hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" +"checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" +"checksum libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" -"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" +"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" "checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226" -"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" -"checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4" +"checksum num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" +"checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" -"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" -"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" +"checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548" +"checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" -"checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" +"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" -"checksum redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecedbca3bf205f8d8f5c2b44d83cd0690e39ee84b951ed649e9f1841132b66d" -"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" -"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" +"checksum redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" +"checksum regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "322cf97724bea3ee221b78fe25ac9c46114ebb51747ad5babd51a2fc6a8235a8" +"checksum regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b28dfe3fe9badec5dbf0a79a9cccad2cfc2ab5484bdb3e44cbd1ae8b3ba2be06" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" -"checksum rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf" +"checksum rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" "checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" "checksum rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" @@ -808,25 +754,24 @@ dependencies = [ "checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "1217f97ab8e8904b57dd22eb61cde455fa7446a9c1cf43966066da047c1f3702" -"checksum serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "a8c6faef9a2e64b0064f48570289b4bf8823b7581f1d6157c1b52152306651d0" -"checksum serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)" = "1a3351dcbc1f067e2c92ab7c3c1f288ad1a4cffc470b5aaddb4c2e0a3ae80043" +"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" +"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" +"checksum serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "9371ade75d4c2d6cb154141b9752cf3781ec9c05e0e5cf35060e1e70ee7b9c25" "checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9" "checksum socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e8b74de517221a2cb01a53349cf54182acdc31a074727d3079068448c0676d85" -"checksum syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "661641ea2aa15845cddeb97dad000d22070bb5c1fb456b96c1cba883ec691e92" +"checksum syn 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a0294dc449adc58bb6592fff1a23d3e5e6e235afc6a0ffca2657d19e7bbffe5" "checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" -"checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" +"checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" "checksum tester 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee72ec31009a42b53de9a6b7d8f462b493ab3b1e4767bda1fcdbb52127f13b6c" -"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" +"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" -"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" +"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6aba5e34f93dc7051dfad05b98a18e9156f27e7b431fe1d2398cb6061c0a1dba" -"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" +"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" +"checksum winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfbf554c6ad11084fb7517daca16cfdcaccbdadba4fc336f032a8b12c2ad80" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9" diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 118afff39bd6..f4d20ab8e158 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -2,7 +2,7 @@ # It is not intended for manual editing. [[package]] name = "byteorder" -version = "1.3.2" +version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -17,9 +17,9 @@ dependencies = [ name = "cargo-miri-test" version = "0.1.0" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -29,34 +29,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "getrandom" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "hermit-abi" -version = "0.1.3" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libc" -version = "0.2.65" +version = "0.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num_cpus" -version = "1.11.1" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -66,11 +66,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rand" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -91,7 +91,7 @@ name = "rand_core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -112,21 +112,21 @@ dependencies = [ [[package]] name = "wasi" -version = "0.7.0" +version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] -"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" +"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" "checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407" -"checksum hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "307c3c9f937f38e3534b1d6447ecf090cafcc9744e4a6360e8b037b2cf5af120" -"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" -"checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72" +"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +"checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8" +"checksum libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018" +"checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" -"checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" +"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" +"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" From 89cbe0ae567603b416ae995f38c428445ff10159 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 16 Feb 2020 13:44:19 -0600 Subject: [PATCH 1581/5092] Add comments --- src/shims/fs.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 7ae378192a21..7ad36ed407b6 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -173,6 +173,10 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' } else if file_type.is_symlink() { Ok(this.eval_libc("DT_LNK")?.to_u8()? as i32) } else { + // Certain file types are only supported when the host is a Unix system. + // (i.e. devices and sockets) If it is, check those cases, if not, fall back to + // DT_UNKNOWN sooner. + #[cfg(unix)] { use std::os::unix::fs::FileTypeExt; @@ -895,6 +899,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let c_ushort_layout = this.libc_ty_layout("c_ushort")?; let c_uchar_layout = this.libc_ty_layout("c_uchar")?; + // If the host is a Unix system, fill in the inode number with its real value. + // If not, use 0 as a fallback value. #[cfg(unix)] let ino = std::os::unix::fs::DirEntryExt::ino(&dir_entry); #[cfg(not(unix))] @@ -969,6 +975,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let c_ushort_layout = this.libc_ty_layout("c_ushort")?; let c_uchar_layout = this.libc_ty_layout("c_uchar")?; + // If the host is a Unix system, fill in the inode number with its real value. + // If not, use 0 as a fallback value. #[cfg(unix)] let ino = std::os::unix::fs::DirEntryExt::ino(&dir_entry); #[cfg(not(unix))] From dd00e5830fb40bd3afe3e41910d280353dbe75d9 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 16 Feb 2020 14:49:48 -0600 Subject: [PATCH 1582/5092] Use ID numbers in lieu of allocations for DIR* --- src/shims/fs.rs | 65 +++++++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 7ad36ed407b6..f3b1cc7124c8 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -204,19 +204,39 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' } } -#[derive(Debug, Default)] +#[derive(Debug)] pub struct DirHandler { /// Directory iterators used to emulate libc "directory streams", as used in opendir, readdir, /// and closedir. /// - /// When opendir is called, a new allocation is made, a directory iterator is created on the - /// host for the target directory, and an entry is stored in this hash map, indexed by a - /// pointer to the allocation which represents the directory stream. When readdir is called, - /// the directory stream pointer is used to look up the corresponding ReadDir iterator from - /// this HashMap, and information from the next directory entry is returned. When closedir is - /// called, the ReadDir iterator is removed from this HashMap, and the allocation that - /// represented the directory stream is deallocated. - streams: HashMap, ReadDir>, + /// When opendir is called, a directory iterator is created on the host for the target + /// directory, and an entry is stored in this hash map, indexed by an ID which represents + /// the directory stream. When readdir is called, the directory stream ID is used to look up + /// the corresponding ReadDir iterator from this HashMap, and information from the next + /// directory entry is returned. When closedir is called, the ReadDir iterator is removed from + /// this HashMap. + streams: HashMap, + /// ID number to be used by the next call to opendir + next_id: u64, +} + +impl DirHandler { + fn insert_new(&mut self, read_dir: ReadDir) -> u64 { + let id = self.next_id; + self.next_id += 1; + self.streams.insert(id, read_dir).unwrap_none(); + id + } +} + +impl Default for DirHandler { + fn default() -> DirHandler { + DirHandler { + streams: HashMap::new(), + // Skip 0 as an ID, because it looks like a null pointer to libc + next_id: 1, + } + } } impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -838,20 +858,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match result { Ok(dir_iter) => { - let size = 1; - let kind = MiriMemoryKind::Env; - let align = this.min_align(size, kind); - let dir_ptr = this.memory.allocate(Size::from_bytes(size), align, kind.into()); - let prev = this - .machine - .dir_handler - .streams - .insert(dir_ptr, dir_iter); - if let Some(_) = prev { - panic!("The pointer allocated for opendir was already registered by a previous call to opendir") - } else { - Ok(Scalar::Ptr(dir_ptr)) - } + let id = this.machine.dir_handler.insert_new(dir_iter); + + // The libc API for opendir says that this method returns a pointer to an opaque + // structure, but we are returning an ID number. Thus, pass it as a scalar of + // pointer width. + Ok(Scalar::from_int(id, this.pointer_size())) } Err(e) => { this.set_last_error_from_io_error(e)?; @@ -870,7 +882,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("readdir64_r")?; - let dirp = this.force_ptr(this.read_scalar(dirp_op)?.not_undef()?)?; + let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; let entry_ptr = this.force_ptr(this.read_scalar(entry_op)?.not_undef()?)?; let dirent64_layout = this.libc_ty_layout("dirent64")?; @@ -946,7 +958,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("readdir_r")?; - let dirp = this.force_ptr(this.read_scalar(dirp_op)?.not_undef()?)?; + let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; let entry_ptr = this.force_ptr(this.read_scalar(entry_op)?.not_undef()?)?; let dirent_layout = this.libc_ty_layout("dirent")?; @@ -1020,11 +1032,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("closedir")?; - let dirp = this.force_ptr(this.read_scalar(dirp_op)?.not_undef()?)?; + let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; if let Some(dir_iter) = this.machine.dir_handler.streams.remove(&dirp) { drop(dir_iter); - this.memory.deallocate(dirp, None, MiriMemoryKind::Env.into())?; Ok(0) } else { this.handle_not_found() From e530829797ed2dd0cbab0309979ad5846c69b497 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 1 Jan 2020 04:12:27 -0500 Subject: [PATCH 1583/5092] Use 'cargo check' to build the sysroot and target crate Fixes #1057 Since we are no longer using "cargo rustc", we now use the rustc arguments passed by Cargo to determine whether we are building a build dependency, normal dependency, or "target" (final binary or test) crate. --- Cargo.toml | 1 + src/bin/cargo-miri.rs | 88 +++++++++++++++++++++++++++++++------------ 2 files changed, 65 insertions(+), 24 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index da9481cce526..236905b895f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,6 +50,7 @@ rustc-workspace-hack = "1.0.0" # between "cargo build" and "cargo intall". num-traits = "*" serde = { version = "*", features = ["derive"] } +serde_json = "1.0.44" [build-dependencies] vergen = "3" diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index e990bc00277c..55503c635dba 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -6,7 +6,7 @@ use std::ops::Not; use std::path::{Path, PathBuf}; use std::process::Command; -const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 17); +const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 19); const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and tests in Miri @@ -84,6 +84,34 @@ fn get_arg_flag_value(name: &str) -> Option { } } + +/// Determines if we are being invoked (as rustc) to build a runnable +/// executable. We run "cargo check", so this should only happen when +/// we are trying to compile a build script or build script dependency, +/// which actually needs to be executed on the host platform. +/// +/// Currently, we detect this by checking for "--emit=link", +/// which indicates that Cargo instruced rustc to output +/// a native object. +fn is_build_dep() -> bool { + std::env::args().any(|arg| arg.starts_with("--emit=") && arg.contains("link")) +} + +/// Returns whether or not Cargo invoked the wrapper (this binary) to compile +/// the final, target crate (either a test for 'cargo test', or a binary for 'cargo run') +/// Cargo does not give us this information directly, so we need to check +/// various command-line flags. +fn is_target_crate(is_build_script: bool) -> bool { + let is_bin = get_arg_flag_value("--crate-type").as_deref() == Some("bin"); + let is_test = std::env::args().find(|arg| arg == "--test").is_some(); + + // The final runnable (under Miri) crate will either be a binary crate + // or a test crate. We make sure to exclude build scripts here, since + // they are also build with "--crate-type bin" + (is_bin || is_test) && !is_build_script +} + + fn list_targets() -> impl Iterator { // We need to get the manifest, and then the metadata, to enumerate targets. let manifest_path = @@ -197,7 +225,7 @@ fn xargo() -> Command { // Bootstrap tells us where to find xargo Command::new(val) } else { - Command::new("xargo") + Command::new("xargo-check") } } @@ -467,7 +495,7 @@ fn in_cargo_miri() { // change to add additional arguments. `FLAGS` is set to identify // this target. The user gets to control what gets actually passed to Miri. let mut cmd = cargo(); - cmd.arg("rustc"); + cmd.arg("check"); match (subcommand, kind.as_str()) { (MiriCommand::Run, "bin") => { // FIXME: we just run all the binaries here. @@ -494,10 +522,15 @@ fn in_cargo_miri() { } cmd.arg(arg); } - // Add `--` (to end the `cargo` flags), and then the user flags. We add markers around the - // user flags to be able to identify them later. "cargo rustc" adds more stuff after this, - // so we have to mark both the beginning and the end. - cmd.arg("--").arg("cargo-miri-marker-begin").args(args).arg("cargo-miri-marker-end"); + + // Serialize our actual args into a special environemt variable. + // This will be read by `inside_cargo_rustc` when we go to invoke + // our actual target crate (the binary or the test we are running). + // Since we're using "cargo check", we have no other way of passing + // these arguments. + let args_vec: Vec = args.collect(); + cmd.env("MIRI_MAGIC_ARGS", serde_json::to_string(&args_vec).expect("failed to serialize args")); + let path = std::env::current_exe().expect("current executable path invalid"); cmd.env("RUSTC_WRAPPER", path); if verbose { @@ -517,25 +550,32 @@ fn inside_cargo_rustc() { let sysroot = std::env::var("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); let rustc_args = std::env::args().skip(2); // skip `cargo rustc` - let mut args: Vec = - rustc_args.chain(Some("--sysroot".to_owned())).chain(Some(sysroot)).collect(); - args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string)); - // See if we can find the `cargo-miri` markers. Those only get added to the binary we want to - // run. They also serve to mark the user-defined arguments, which we have to move all the way - // to the end (they get added somewhere in the middle). + let in_build_script = is_build_dep(); + + // Build scripts need to be compiled to actual runnable executables, + // and therefore completely bypass Miri. We make sure to only specify + // our custom Xargo sysroot for non-build-script crate - that is, + // crates which are ultimately going to get interpreted by Miri. + let mut args = if in_build_script { + rustc_args.collect() + } else { + let mut args: Vec = rustc_args + .chain(Some("--sysroot".to_owned())) + .chain(Some(sysroot)) + .collect(); + args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string)); + args + }; + let needs_miri = - if let Some(begin) = args.iter().position(|arg| arg == "cargo-miri-marker-begin") { - let end = args - .iter() - .position(|arg| arg == "cargo-miri-marker-end") - .expect("cannot find end marker"); - // These mark the user arguments. We remove the first and last as they are the markers. - let mut user_args = args.drain(begin..=end); - assert_eq!(user_args.next().unwrap(), "cargo-miri-marker-begin"); - assert_eq!(user_args.next_back().unwrap(), "cargo-miri-marker-end"); - // Collect the rest and add it back at the end. - let mut user_args = user_args.collect::>(); + if is_target_crate(in_build_script) { + // This is the 'target crate '- the binary or test crate that + // we want to interpret under Miri. We deserialize the user-provided arguments + // from the special environment variable "MIRI_MAGIC_ARGS", and feed them + // to the 'miri' binary. + let magic = std::env::var("MIRI_MAGIC_ARGS").expect("missing MIRI_MAGIC_ARGS"); + let mut user_args: Vec = serde_json::from_str(&magic).expect("failed to deserialize args"); args.append(&mut user_args); // Run this in Miri. true From 443163f93071587f72014018eeb45a2225fdff79 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Feb 2020 14:17:19 +0100 Subject: [PATCH 1584/5092] refactor cargo-miri a bit --- src/bin/cargo-miri.rs | 168 +++++++++++++++++++++--------------------- 1 file changed, 85 insertions(+), 83 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 55503c635dba..17063b6ff67f 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -23,7 +23,7 @@ Common options: --features Features to compile for the package -V, --version Print version info and exit -Other [options] are the same as `cargo rustc`. Everything after the first "--" is +Other [options] are the same as `cargo check`. Everything after the first "--" is passed verbatim to Miri, which will pass everything after the second "--" verbatim to the interpreted program. "#; @@ -84,33 +84,30 @@ fn get_arg_flag_value(name: &str) -> Option { } } - -/// Determines if we are being invoked (as rustc) to build a runnable -/// executable. We run "cargo check", so this should only happen when -/// we are trying to compile a build script or build script dependency, -/// which actually needs to be executed on the host platform. -/// -/// Currently, we detect this by checking for "--emit=link", -/// which indicates that Cargo instruced rustc to output -/// a native object. -fn is_build_dep() -> bool { - std::env::args().any(|arg| arg.starts_with("--emit=") && arg.contains("link")) +/// Returns the path to the `miri` binary +fn find_miri() -> PathBuf { + let mut path = std::env::current_exe().expect("current executable path invalid"); + path.set_file_name("miri"); + path } -/// Returns whether or not Cargo invoked the wrapper (this binary) to compile -/// the final, target crate (either a test for 'cargo test', or a binary for 'cargo run') -/// Cargo does not give us this information directly, so we need to check -/// various command-line flags. -fn is_target_crate(is_build_script: bool) -> bool { - let is_bin = get_arg_flag_value("--crate-type").as_deref() == Some("bin"); - let is_test = std::env::args().find(|arg| arg == "--test").is_some(); - - // The final runnable (under Miri) crate will either be a binary crate - // or a test crate. We make sure to exclude build scripts here, since - // they are also build with "--crate-type bin" - (is_bin || is_test) && !is_build_script +fn cargo() -> Command { + if let Ok(val) = std::env::var("CARGO") { + // Bootstrap tells us where to find cargo + Command::new(val) + } else { + Command::new("cargo") + } } +fn xargo() -> Command { + if let Ok(val) = std::env::var("XARGO") { + // Bootstrap tells us where to find xargo + Command::new(val) + } else { + Command::new("xargo-check") + } +} fn list_targets() -> impl Iterator { // We need to get the manifest, and then the metadata, to enumerate targets. @@ -155,13 +152,6 @@ fn list_targets() -> impl Iterator { package.targets.into_iter() } -/// Returns the path to the `miri` binary -fn find_miri() -> PathBuf { - let mut path = std::env::current_exe().expect("current executable path invalid"); - path.set_file_name("miri"); - path -} - /// Make sure that the `miri` and `rustc` binary are from the same sysroot. /// This can be violated e.g. when miri is locally built and installed with a different /// toolchain than what is used when `cargo miri` is run. @@ -211,24 +201,6 @@ fn test_sysroot_consistency() { } } -fn cargo() -> Command { - if let Ok(val) = std::env::var("CARGO") { - // Bootstrap tells us where to find cargo - Command::new(val) - } else { - Command::new("cargo") - } -} - -fn xargo() -> Command { - if let Ok(val) = std::env::var("XARGO") { - // Bootstrap tells us where to find xargo - Command::new(val) - } else { - Command::new("xargo-check") - } -} - fn xargo_version() -> Option<(u32, u32, u32)> { let out = xargo().arg("--version").output().ok()?; if !out.status.success() { @@ -385,6 +357,7 @@ features = ["panic_unwind"] ) .unwrap(); // The boring bits: a dummy project for xargo. + // FIXME: With xargo-check, can we avoid doing this? File::create(dir.join("Cargo.toml")) .unwrap() .write_all( @@ -447,12 +420,12 @@ fn main() { } if let Some("miri") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { - // This arm is for when `cargo miri` is called. We call `cargo rustc` for each applicable target, + // This arm is for when `cargo miri` is called. We call `cargo check` for each applicable target, // but with the `RUSTC` env var set to the `cargo-miri` binary so that we come back in the other branch, // and dispatch the invocations to `rustc` and `miri`, respectively. in_cargo_miri(); } else if let Some("rustc") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { - // This arm is executed when `cargo-miri` runs `cargo rustc` with the `RUSTC_WRAPPER` env var set to itself: + // This arm is executed when `cargo-miri` runs `cargo check` with the `RUSTC_WRAPPER` env var set to itself: // dependencies get dispatched to `rustc`, the final test/binary to `miri`. inside_cargo_rustc(); } else { @@ -491,7 +464,7 @@ fn in_cargo_miri() { .kind .get(0) .expect("badly formatted cargo metadata: target::kind is an empty array"); - // Now we run `cargo rustc $FLAGS $ARGS`, giving the user the + // Now we run `cargo check $FLAGS $ARGS`, giving the user the // change to add additional arguments. `FLAGS` is set to identify // this target. The user gets to control what gets actually passed to Miri. let mut cmd = cargo(); @@ -515,7 +488,7 @@ fn in_cargo_miri() { // The remaining targets we do not even want to build. _ => continue, } - // Add user-defined args until first `--`. + // Forward user-defined `cargo` args until first `--`. while let Some(arg) = args.next() { if arg == "--" { break; @@ -523,17 +496,21 @@ fn in_cargo_miri() { cmd.arg(arg); } - // Serialize our actual args into a special environemt variable. + // Serialize the remaining args into a special environemt variable. // This will be read by `inside_cargo_rustc` when we go to invoke // our actual target crate (the binary or the test we are running). // Since we're using "cargo check", we have no other way of passing // these arguments. let args_vec: Vec = args.collect(); - cmd.env("MIRI_MAGIC_ARGS", serde_json::to_string(&args_vec).expect("failed to serialize args")); + cmd.env("MIRI_ARGS", serde_json::to_string(&args_vec).expect("failed to serialize args")); + // Set `RUSTC_WRAPPER` to ourselves. Cargo will prepend that binary to its usual invocation, + // i.e., the first argument is `rustc` -- which is what we use in `main` to distinguish + // the two codepaths. let path = std::env::current_exe().expect("current executable path invalid"); cmd.env("RUSTC_WRAPPER", path); if verbose { + cmd.env("MIRI_VERBOSE", ""); // this makes `inside_cargo_rustc` verbose. eprintln!("+ {:?}", cmd); } @@ -547,45 +524,71 @@ fn in_cargo_miri() { } fn inside_cargo_rustc() { - let sysroot = std::env::var("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); + /// Determines if we are being invoked (as rustc) to build a runnable + /// executable. We run "cargo check", so this should only happen when + /// we are trying to compile a build script or build script dependency, + /// which actually needs to be executed on the host platform. + /// + /// Currently, we detect this by checking for "--emit=link", + /// which indicates that Cargo instruced rustc to output + /// a native object. + fn is_target_crate() -> bool { + // `--emit` is sometimes missing, e.g. cargo calls rustc for "--print". + // That is definitely not a target crate. + // If `--emit` is present, then host crates are built ("--emit=link,...), + // while the rest is only checked. + get_arg_flag_value("--emit").map_or(false, |emit| !emit.contains("link")) + } - let rustc_args = std::env::args().skip(2); // skip `cargo rustc` + /// Returns whether or not Cargo invoked the wrapper (this binary) to compile + /// the final, target crate (either a test for 'cargo test', or a binary for 'cargo run') + /// Cargo does not give us this information directly, so we need to check + /// various command-line flags. + fn is_runnable_crate() -> bool { + let is_bin = get_arg_flag_value("--crate-type").as_deref() == Some("bin"); + let is_test = has_arg_flag("--test"); - let in_build_script = is_build_dep(); + // The final runnable (under Miri) crate will either be a binary crate + // or a test crate. We make sure to exclude build scripts here, since + // they are also build with "--crate-type bin" + is_bin || is_test + } - // Build scripts need to be compiled to actual runnable executables, - // and therefore completely bypass Miri. We make sure to only specify - // our custom Xargo sysroot for non-build-script crate - that is, - // crates which are ultimately going to get interpreted by Miri. - let mut args = if in_build_script { - rustc_args.collect() - } else { - let mut args: Vec = rustc_args - .chain(Some("--sysroot".to_owned())) - .chain(Some(sysroot)) - .collect(); + let verbose = std::env::var("MIRI_VERBOSE").is_ok(); + let target_crate = is_target_crate(); + + // Figure out which arguments we need to pass. + let mut args: Vec = std::env::args().skip(2).collect(); // skip `cargo-miri rustc` + // We make sure to only specify our custom Xargo sysroot and + // other args for target crates - that is, crates which are ultimately + // going to get interpreted by Miri. + if target_crate { + let sysroot = std::env::var("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); + args.push("--sysroot".to_owned()); + args.push(sysroot); args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string)); - args - }; + } - let needs_miri = - if is_target_crate(in_build_script) { - // This is the 'target crate '- the binary or test crate that + // Figure out the binary we need to call. If this is a runnable target crate, we want to call + // Miri to start interpretation; otherwise we want to call rustc to build the crate as usual. + let mut command = + if target_crate && is_runnable_crate() { + // This is the 'target crate' - the binary or test crate that // we want to interpret under Miri. We deserialize the user-provided arguments - // from the special environment variable "MIRI_MAGIC_ARGS", and feed them + // from the special environment variable "MIRI_ARGS", and feed them // to the 'miri' binary. - let magic = std::env::var("MIRI_MAGIC_ARGS").expect("missing MIRI_MAGIC_ARGS"); - let mut user_args: Vec = serde_json::from_str(&magic).expect("failed to deserialize args"); + let magic = std::env::var("MIRI_ARGS").expect("missing MIRI_ARGS"); + let mut user_args: Vec = serde_json::from_str(&magic).expect("failed to deserialize MIRI_ARGS"); args.append(&mut user_args); // Run this in Miri. - true + Command::new(find_miri()) } else { - false + Command::new("rustc") }; - let mut command = if needs_miri { Command::new(find_miri()) } else { Command::new("rustc") }; + // Run it. command.args(&args); - if has_arg_flag("-v") { + if verbose { eprintln!("+ {:?}", command); } @@ -594,7 +597,6 @@ fn inside_cargo_rustc() { if !exit.success() { std::process::exit(exit.code().unwrap_or(42)); }, - Err(ref e) if needs_miri => panic!("error during miri run: {:?}", e), - Err(ref e) => panic!("error during rustc call: {:?}", e), + Err(ref e) => panic!("error running {:?}:\n{:?}", command, e), } } From 47f2b127350e7d95fac67191467ecba3aed1befb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Feb 2020 14:42:45 +0100 Subject: [PATCH 1585/5092] fix Cargo.toml --- Cargo.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 236905b895f8..896c726b9aa6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,8 @@ required-features = ["rustc_tests"] cargo_metadata = { version = "0.9.0", optional = true } directories = { version = "2.0", optional = true } rustc_version = { version = "0.2.3", optional = true } +serde_json = { version = "1.0.44", optional = true } + getrandom = { version = "0.1.8", features = ["std"] } byteorder = "1.3" env_logger = "0.7.1" @@ -50,14 +52,13 @@ rustc-workspace-hack = "1.0.0" # between "cargo build" and "cargo intall". num-traits = "*" serde = { version = "*", features = ["derive"] } -serde_json = "1.0.44" [build-dependencies] vergen = "3" [features] default = ["cargo_miri"] -cargo_miri = ["cargo_metadata", "directories", "rustc_version"] +cargo_miri = ["cargo_metadata", "directories", "rustc_version", "serde_json"] rustc_tests = [] [dev-dependencies] From faf7bf538d3bf61321ca0128ad039d5d13fc2a40 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Feb 2020 14:45:35 +0100 Subject: [PATCH 1586/5092] update lockfile --- Cargo.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.lock b/Cargo.lock index 7f5719b82a0c..951e91dad5b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -334,6 +334,7 @@ dependencies = [ "rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] From 274ae0438fb4e942ad29fd60f0adf277cc6777d9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Feb 2020 16:22:02 +0100 Subject: [PATCH 1587/5092] add an option to disable Stacked Borrows --- README.md | 17 +++++--- src/bin/miri.rs | 5 +++ src/eval.rs | 5 ++- src/lib.rs | 2 +- src/machine.rs | 40 ++++++++++++------- src/shims/panic.rs | 4 +- src/stacked_borrows.rs | 2 +- tests/compile-fail/modifying_constants.rs | 4 +- tests/compile-fail/reference_to_packed.rs | 4 +- tests/compile-fail/stack_free.rs | 4 +- .../static_memory_modification1.rs | 4 +- .../static_memory_modification2.rs | 4 +- .../static_memory_modification3.rs | 4 +- tests/run-pass/observed_local_mut.rs | 4 +- tests/run-pass/transmute_fat.rs | 4 +- 15 files changed, 66 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index f16751cd7478..f18a5d668c39 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,8 @@ for example: * Not sufficiently aligned memory accesses and references * Violation of *some* basic type invariants (a `bool` that is not 0 or 1, for example, or an invalid enum discriminant) -* **Experimental**: Violations of the rules governing aliasing for reference types +* **Experimental**: Violations of the [Stacked Borrows] rules governing aliasing + for reference types Miri has already discovered some [real-world bugs](#bugs-found-by-miri). If you found a bug with Miri, we'd appreciate if you tell us and we'll add it to the @@ -47,6 +48,7 @@ program, and cannot run all programs: [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md [`unreachable_unchecked`]: https://doc.rust-lang.org/stable/std/hint/fn.unreachable_unchecked.html [`copy_nonoverlapping`]: https://doc.rust-lang.org/stable/std/ptr/fn.copy_nonoverlapping.html +[Stacked Borrows]: https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md ## Using Miri @@ -152,10 +154,13 @@ Several `-Z` flags are relevant for Miri: **NOTE**: This entropy is not good enough for cryptographic use! Do not generate secret keys in Miri or perform other kinds of cryptographic operations that rely on proper random numbers. -* `-Zmiri-disable-validation` disables enforcing validity invariants and - reference aliasing rules, which are enforced by default. This is mostly - useful for debugging. It means Miri will miss bugs in your program. However, - this can also help to make Miri run faster. +* `-Zmiri-disable-validation` disables enforcing validity invariants, which are + enforced by default. This is mostly useful for debugging. It means Miri will + miss bugs in your program. However, this can also help to make Miri run + faster. +* `-Zmiri-disable-stacked-borrows` disables checking the experimental + [Stacked Borrows] aliasing rules. This can make Miri run faster, but it also + means no aliasing violations will be detected. * `-Zmiri-disable-isolation` disables host host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness. @@ -234,7 +239,7 @@ Definite bugs found: * [The Unix allocator calling `posix_memalign` in an invalid way](https://github.com/rust-lang/rust/issues/62251) * [`getrandom` calling the `getrandom` syscall in an invalid way](https://github.com/rust-random/getrandom/pull/73) -Violations of Stacked Borrows found that are likely bugs (but Stacked Borrows is currently just an experiment): +Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): * [`VecDeque` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/56161) * [`BTreeMap` creating mutable references that overlap with shared references](https://github.com/rust-lang/rust/pull/58431) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 228c50e4a57b..9523609889cd 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -130,6 +130,7 @@ fn main() { // Parse our arguments and split them across `rustc` and `miri`. let mut validate = true; + let mut stacked_borrows = true; let mut communicate = false; let mut ignore_leaks = false; let mut seed: Option = None; @@ -150,6 +151,9 @@ fn main() { "-Zmiri-disable-validation" => { validate = false; } + "-Zmiri-disable-stacked-borrows" => { + stacked_borrows = false; + } "-Zmiri-disable-isolation" => { communicate = true; } @@ -229,6 +233,7 @@ fn main() { debug!("miri arguments: {:?}", miri_args); let miri_config = miri::MiriConfig { validate, + stacked_borrows, communicate, ignore_leaks, excluded_env_vars, diff --git a/src/eval.rs b/src/eval.rs index 9ce3d2b08c23..5a0c766b5ae1 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -14,8 +14,10 @@ use crate::*; /// Configuration needed to spawn a Miri instance. #[derive(Clone)] pub struct MiriConfig { - /// Determine if validity checking and Stacked Borrows are enabled. + /// Determine if validity checking is enabled. pub validate: bool, + /// Determines if Stacked Borrows is enabled. + pub stacked_borrows: bool, /// Determines if communication with the host environment is enabled. pub communicate: bool, /// Determines if memory leaks should be ignored. @@ -52,6 +54,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( MemoryExtra::new( StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate, + config.stacked_borrows, config.tracked_pointer_tag, ), ); diff --git a/src/lib.rs b/src/lib.rs index 85ee98aa3a12..7cea203d5e76 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,7 +56,7 @@ pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ - EvalContextExt as StackedBorEvalContextExt, GlobalState, Item, Permission, PtrId, Stack, + EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, Stack, Stacks, Tag, }; diff --git a/src/machine.rs b/src/machine.rs index 5d933fe8a7f6..7aaf97cc1236 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -4,6 +4,7 @@ use std::borrow::Cow; use std::cell::RefCell; use std::rc::Rc; +use std::num::NonZeroU64; use rand::rngs::StdRng; @@ -63,14 +64,14 @@ impl Into> for MiriMemoryKind { /// Extra per-allocation data #[derive(Debug, Clone)] pub struct AllocExtra { - /// Stacked Borrows state is only added if validation is enabled. + /// Stacked Borrows state is only added if it is enabled. pub stacked_borrows: Option, } /// Extra global memory data #[derive(Clone, Debug)] pub struct MemoryExtra { - pub stacked_borrows: stacked_borrows::MemoryExtra, + pub stacked_borrows: Option, pub intptrcast: intptrcast::MemoryExtra, /// The random number generator used for resolving non-determinism. @@ -81,9 +82,14 @@ pub struct MemoryExtra { } impl MemoryExtra { - pub fn new(rng: StdRng, validate: bool, tracked_pointer_tag: Option) -> Self { + pub fn new(rng: StdRng, validate: bool, stacked_borrows: bool, tracked_pointer_tag: Option) -> Self { + let stacked_borrows = if stacked_borrows { + Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(tracked_pointer_tag)))) + } else { + None + }; MemoryExtra { - stacked_borrows: Rc::new(RefCell::new(GlobalState::new(tracked_pointer_tag))), + stacked_borrows, intptrcast: Default::default(), rng: RefCell::new(rng), validate, @@ -299,11 +305,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ) -> (Cow<'b, Allocation>, Self::PointerTag) { let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); - let (stacks, base_tag) = if memory_extra.validate { + let (stacks, base_tag) = if let Some(stacked_borrows) = memory_extra.stacked_borrows.as_ref() { let (stacks, base_tag) = Stacks::new_allocation( id, alloc.size, - Rc::clone(&memory_extra.stacked_borrows), + Rc::clone(stacked_borrows), kind, ); (Some(stacks), base_tag) @@ -311,15 +317,15 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { // No stacks, no tag. (None, Tag::Untagged) }; - let mut stacked_borrows = memory_extra.stacked_borrows.borrow_mut(); + let mut stacked_borrows = memory_extra.stacked_borrows.as_ref().map(|sb| sb.borrow_mut()); let alloc: Allocation = alloc.with_tags_and_extra( |alloc| { - if !memory_extra.validate { - Tag::Untagged - } else { + if let Some(stacked_borrows) = stacked_borrows.as_mut() { // Only statics may already contain pointers at this point assert_eq!(kind, MiriMemoryKind::Static.into()); stacked_borrows.static_base_ptr(alloc) + } else { + Tag::Untagged } }, AllocExtra { stacked_borrows: stacks }, @@ -329,10 +335,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn tag_static_base_pointer(memory_extra: &MemoryExtra, id: AllocId) -> Self::PointerTag { - if !memory_extra.validate { - Tag::Untagged + if let Some(stacked_borrows) = memory_extra.stacked_borrows.as_ref() { + stacked_borrows.borrow_mut().static_base_ptr(id) } else { - memory_extra.stacked_borrows.borrow_mut().static_base_ptr(id) + Tag::Untagged } } @@ -342,7 +348,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { kind: mir::RetagKind, place: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { - if !Self::enforce_validity(ecx) { + if ecx.memory.extra.stacked_borrows.is_none() { // No tracking. Ok(()) } else { @@ -352,8 +358,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, FrameData<'tcx>> { + let call_id = ecx.memory.extra.stacked_borrows.as_ref().map_or( + NonZeroU64::new(1).unwrap(), + |stacked_borrows| stacked_borrows.borrow_mut().new_call(), + ); Ok(FrameData { - call_id: ecx.memory.extra.stacked_borrows.borrow_mut().new_call(), + call_id, catch_panic: None, }) } diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 880932ae0472..e930af7f46c5 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -146,7 +146,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { StackPopInfo::Normal }; - this.memory.extra.stacked_borrows.borrow_mut().end_call(extra.call_id); + if let Some(stacked_borrows) = this.memory.extra.stacked_borrows.as_ref() { + stacked_borrows.borrow_mut().end_call(extra.call_id); + } Ok(res) } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 1b7a118e637d..9a674830c8ec 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -575,7 +575,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // breaking `Rc::from_raw`. RefKind::Raw { .. } => Tag::Untagged, // All other pointesr are properly tracked. - _ => Tag::Tagged(this.memory.extra.stacked_borrows.borrow_mut().new_ptr()), + _ => Tag::Tagged(this.memory.extra.stacked_borrows.as_ref().unwrap().borrow_mut().new_ptr()), }; // Reborrow. diff --git a/tests/compile-fail/modifying_constants.rs b/tests/compile-fail/modifying_constants.rs index 4546e8a4d7c9..9770917b629b 100644 --- a/tests/compile-fail/modifying_constants.rs +++ b/tests/compile-fail/modifying_constants.rs @@ -1,5 +1,5 @@ -// This should fail even without validation -// compile-flags: -Zmiri-disable-validation +// This should fail even without validation/SB +// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { let x = &1; // the `&1` is promoted to a constant, but it used to be that only the pointer is marked static, not the pointee diff --git a/tests/compile-fail/reference_to_packed.rs b/tests/compile-fail/reference_to_packed.rs index befe96f2b35d..030353c2cedb 100644 --- a/tests/compile-fail/reference_to_packed.rs +++ b/tests/compile-fail/reference_to_packed.rs @@ -1,5 +1,5 @@ -// This should fail even without validation -// compile-flags: -Zmiri-disable-validation +// This should fail even without validation/SB +// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows #![allow(dead_code, unused_variables)] diff --git a/tests/compile-fail/stack_free.rs b/tests/compile-fail/stack_free.rs index 43cc17308c06..b8ed2e3f1f35 100644 --- a/tests/compile-fail/stack_free.rs +++ b/tests/compile-fail/stack_free.rs @@ -1,5 +1,5 @@ -// Validation changes why we fail -// compile-flags: -Zmiri-disable-validation +// Validation/SB changes why we fail +// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows // error-pattern: tried to deallocate `Stack` memory but gave `Machine(Rust)` as the kind diff --git a/tests/compile-fail/static_memory_modification1.rs b/tests/compile-fail/static_memory_modification1.rs index 07a277a16f3a..a7bb33431e72 100644 --- a/tests/compile-fail/static_memory_modification1.rs +++ b/tests/compile-fail/static_memory_modification1.rs @@ -1,5 +1,5 @@ -// Validation detects that we are casting & to &mut and so it changes why we fail -// compile-flags: -Zmiri-disable-validation +// Stacked Borrows detects that we are casting & to &mut and so it changes why we fail +// compile-flags: -Zmiri-disable-stacked-borrows static X: usize = 5; diff --git a/tests/compile-fail/static_memory_modification2.rs b/tests/compile-fail/static_memory_modification2.rs index 73928f533cb7..065206a60dbf 100644 --- a/tests/compile-fail/static_memory_modification2.rs +++ b/tests/compile-fail/static_memory_modification2.rs @@ -1,5 +1,5 @@ -// Validation detects that we are casting & to &mut and so it changes why we fail -// compile-flags: -Zmiri-disable-validation +// Stacked Borrows detects that we are casting & to &mut and so it changes why we fail +// compile-flags: -Zmiri-disable-stacked-borrows use std::mem::transmute; diff --git a/tests/compile-fail/static_memory_modification3.rs b/tests/compile-fail/static_memory_modification3.rs index 280f34a5a021..94f88205073e 100644 --- a/tests/compile-fail/static_memory_modification3.rs +++ b/tests/compile-fail/static_memory_modification3.rs @@ -1,5 +1,5 @@ -// Validation detects that we are casting & to &mut and so it changes why we fail -// compile-flags: -Zmiri-disable-validation +// Stacked Borrows detects that we are casting & to &mut and so it changes why we fail +// compile-flags: -Zmiri-disable-stacked-borrows use std::mem::transmute; diff --git a/tests/run-pass/observed_local_mut.rs b/tests/run-pass/observed_local_mut.rs index c58e8c84bb2e..888b6f85e3fd 100644 --- a/tests/run-pass/observed_local_mut.rs +++ b/tests/run-pass/observed_local_mut.rs @@ -1,5 +1,5 @@ -// Validation catches this (correctly) as UB. -// compile-flags: -Zmiri-disable-validation +// Stacked Borrows catches this (correctly) as UB. +// compile-flags: -Zmiri-disable-stacked-borrows // This test is intended to guard against the problem described in commit // 39bb1254d1eaf74f45a4e741097e33fc942168d5. diff --git a/tests/run-pass/transmute_fat.rs b/tests/run-pass/transmute_fat.rs index 27da44935b10..238122de8d4c 100644 --- a/tests/run-pass/transmute_fat.rs +++ b/tests/run-pass/transmute_fat.rs @@ -1,5 +1,5 @@ -// Validation disallows this becuase the reference is never cast to a raw pointer. -// compile-flags: -Zmiri-disable-validation +// Stacked Borrows disallows this becuase the reference is never cast to a raw pointer. +// compile-flags: -Zmiri-disable-stacked-borrows fn main() { // If we are careful, we can exploit data layout... From 25ddc659d08061f588589c9f271c25250aa55f0d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Feb 2020 16:25:29 +0100 Subject: [PATCH 1588/5092] move validate field from memory to machine --- src/eval.rs | 6 ++++-- src/machine.rs | 14 +++++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 5a0c766b5ae1..eca634d02098 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -50,10 +50,12 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let mut ecx = InterpCx::new( tcx.at(rustc_span::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), - Evaluator::new(config.communicate), + Evaluator::new( + config.communicate, + config.validate, + ), MemoryExtra::new( StdRng::seed_from_u64(config.seed.unwrap_or(0)), - config.validate, config.stacked_borrows, config.tracked_pointer_tag, ), diff --git a/src/machine.rs b/src/machine.rs index 7aaf97cc1236..8fa5268c1900 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -76,13 +76,10 @@ pub struct MemoryExtra { /// The random number generator used for resolving non-determinism. pub(crate) rng: RefCell, - - /// Whether to enforce the validity invariant. - pub(crate) validate: bool, } impl MemoryExtra { - pub fn new(rng: StdRng, validate: bool, stacked_borrows: bool, tracked_pointer_tag: Option) -> Self { + pub fn new(rng: StdRng, stacked_borrows: bool, tracked_pointer_tag: Option) -> Self { let stacked_borrows = if stacked_borrows { Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(tracked_pointer_tag)))) } else { @@ -92,7 +89,6 @@ impl MemoryExtra { stacked_borrows, intptrcast: Default::default(), rng: RefCell::new(rng), - validate, } } } @@ -120,6 +116,9 @@ pub struct Evaluator<'tcx> { /// and random number generation is delegated to the host. pub(crate) communicate: bool, + /// Whether to enforce the validity invariant. + pub(crate) validate: bool, + pub(crate) file_handler: FileHandler, /// The temporary used for storing the argument of @@ -128,7 +127,7 @@ pub struct Evaluator<'tcx> { } impl<'tcx> Evaluator<'tcx> { - pub(crate) fn new(communicate: bool) -> Self { + pub(crate) fn new(communicate: bool, validate: bool) -> Self { Evaluator { // `env_vars` could be initialized properly here if `Memory` were available before // calling this method. @@ -139,6 +138,7 @@ impl<'tcx> Evaluator<'tcx> { last_error: None, tls: TlsData::default(), communicate, + validate, file_handler: Default::default(), panic_payload: None, } @@ -183,7 +183,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { - ecx.memory.extra.validate + ecx.machine.validate } #[inline(always)] From 9fcc8a2a9172802c30b7918c03b24ec556d5fd8e Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 24 Feb 2020 19:16:41 -0600 Subject: [PATCH 1589/5092] Review comments --- src/shims/foreign_items/posix/linux.rs | 2 +- src/shims/foreign_items/posix/macos.rs | 2 +- src/shims/fs.rs | 42 ++++++++++++++++++-------- tests/run-pass/fs.rs | 2 ++ 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 2872e92fa1ee..8a1ce5594ae4 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -37,7 +37,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // The `macos` module has a parallel foreign item, `readdir_r`, which uses a different // struct layout. "readdir64_r" => { - let result = this.readdir64_r(args[0], args[1], args[2])?; + let result = this.linux_readdir64_r(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index e6f4047eee47..cb6cd9ba44b4 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -52,7 +52,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // The `linux` module has a parallel foreign item, `readdir64_r`, which uses a // different struct layout. "readdir_r$INODE64" => { - let result = this.readdir_r(args[0], args[1], args[2])?; + let result = this.macos_readdir_r(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } diff --git a/src/shims/fs.rs b/src/shims/fs.rs index f3b1cc7124c8..d999b8066cc8 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -809,7 +809,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("mkdir")?; - let _mode = if this.tcx.sess.target.target.target_os.to_lowercase() == "macos" { + let _mode = if this.tcx.sess.target.target.target_os.as_str() == "macos" { this.read_scalar(mode_op)?.not_undef()?.to_u16()? as u32 } else { this.read_scalar(mode_op)?.to_u32()? @@ -863,16 +863,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // The libc API for opendir says that this method returns a pointer to an opaque // structure, but we are returning an ID number. Thus, pass it as a scalar of // pointer width. - Ok(Scalar::from_int(id, this.pointer_size())) + Ok(Scalar::from_machine_usize(id, this)) } Err(e) => { this.set_last_error_from_io_error(e)?; - Ok(Scalar::from_int(0, this.memory.pointer_size())) + Ok(Scalar::from_machine_usize(0, this)) } } } - fn readdir64_r( + fn linux_readdir64_r( &mut self, dirp_op: OpTy<'tcx, Tag>, entry_op: OpTy<'tcx, Tag>, @@ -884,9 +884,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; - let entry_ptr = this.force_ptr(this.read_scalar(entry_op)?.not_undef()?)?; - let dirent64_layout = this.libc_ty_layout("dirent64")?; - let dir_iter = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { err_unsup_format!("The DIR pointer passed to readdir64_r did not come from opendir") })?; @@ -896,13 +893,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // The name is written with write_os_str_to_c_str, while the rest of the // dirent64 struct is written using write_packed_immediates. + // For reference: + // pub struct dirent64 { + // pub d_ino: ino64_t, + // pub d_off: off64_t, + // pub d_reclen: c_ushort, + // pub d_type: c_uchar, + // pub d_name: [c_char; 256], + // } + + let entry_ptr = this.force_ptr(this.read_scalar(entry_op)?.not_undef()?)?; + let dirent64_layout = this.libc_ty_layout("dirent64")?; let name_offset = dirent64_layout.details.fields.offset(4); let name_ptr = entry_ptr.offset(name_offset, this)?; let file_name = dir_entry.file_name(); let name_fits = this.write_os_str_to_c_str(&file_name, Scalar::Ptr(name_ptr), 256)?; if !name_fits { - panic!("A directory entry had a name too large to fit in libc::dirent64"); + throw_unsup_format!("A directory entry had a name too large to fit in libc::dirent64"); } let entry_place = this.deref_operand(entry_op)?; @@ -948,7 +956,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn readdir_r( + fn macos_readdir_r( &mut self, dirp_op: OpTy<'tcx, Tag>, entry_op: OpTy<'tcx, Tag>, @@ -960,8 +968,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; - let entry_ptr = this.force_ptr(this.read_scalar(entry_op)?.not_undef()?)?; - let dirent_layout = this.libc_ty_layout("dirent")?; let dir_iter = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { err_unsup_format!("The DIR pointer passed to readdir_r did not come from opendir") @@ -972,13 +978,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // The name is written with write_os_str_to_c_str, while the rest of the // dirent struct is written using write_packed_Immediates. + // For reference: + // pub struct dirent { + // pub d_ino: u64, + // pub d_seekoff: u64, + // pub d_reclen: u16, + // pub d_namlen: u16, + // pub d_type: u8, + // pub d_name: [c_char; 1024], + // } + + let entry_ptr = this.force_ptr(this.read_scalar(entry_op)?.not_undef()?)?; + let dirent_layout = this.libc_ty_layout("dirent")?; let name_offset = dirent_layout.details.fields.offset(5); let name_ptr = entry_ptr.offset(name_offset, this)?; let file_name = dir_entry.file_name(); let name_fits = this.write_os_str_to_c_str(&file_name, Scalar::Ptr(name_ptr), 1024)?; if !name_fits { - panic!("A directory entry had a name too large to fit in libc::dirent"); + throw_unsup_format!("A directory entry had a name too large to fit in libc::dirent"); } let entry_place = this.deref_operand(entry_op)?; diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index b938fceb8d02..f859f934bdd1 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -199,6 +199,8 @@ fn test_directory() { create_dir(&dir_path).unwrap(); // Test that the metadata of a directory is correct. assert!(dir_path.metadata().unwrap().is_dir()); + // Creating a directory when it already exists should fail. + assert_eq!(ErrorKind::AlreadyExists, create_dir(&dir_path).unwrap_err().kind()); // Create some files inside the directory let path_1 = dir_path.join("test_file_1"); From 9e03b4133894614b37469cde63d4f4c28341ec81 Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 24 Feb 2020 19:38:17 -0600 Subject: [PATCH 1590/5092] Migrate readdir_r from pointers to places --- src/shims/fs.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index d999b8066cc8..a3ac59bdf6e7 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -902,13 +902,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // pub d_name: [c_char; 256], // } - let entry_ptr = this.force_ptr(this.read_scalar(entry_op)?.not_undef()?)?; - let dirent64_layout = this.libc_ty_layout("dirent64")?; - let name_offset = dirent64_layout.details.fields.offset(4); - let name_ptr = entry_ptr.offset(name_offset, this)?; + let entry_place = this.deref_operand(entry_op)?; + let name_place = this.mplace_field(entry_place, 4)?; let file_name = dir_entry.file_name(); - let name_fits = this.write_os_str_to_c_str(&file_name, Scalar::Ptr(name_ptr), 256)?; + let name_fits = this.write_os_str_to_c_str(&file_name, name_place.ptr, name_place.layout.size.bytes())?; if !name_fits { throw_unsup_format!("A directory entry had a name too large to fit in libc::dirent64"); } @@ -988,13 +986,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // pub d_name: [c_char; 1024], // } - let entry_ptr = this.force_ptr(this.read_scalar(entry_op)?.not_undef()?)?; - let dirent_layout = this.libc_ty_layout("dirent")?; - let name_offset = dirent_layout.details.fields.offset(5); - let name_ptr = entry_ptr.offset(name_offset, this)?; + let entry_place = this.deref_operand(entry_op)?; + let name_place = this.mplace_field(entry_place, 5)?; let file_name = dir_entry.file_name(); - let name_fits = this.write_os_str_to_c_str(&file_name, Scalar::Ptr(name_ptr), 1024)?; + let name_fits = this.write_os_str_to_c_str(&file_name, name_place.ptr, name_place.layout.size.bytes())?; if !name_fits { throw_unsup_format!("A directory entry had a name too large to fit in libc::dirent"); } From ad8c784009bfa0934815fcf7383c1ff1e2cb8cc1 Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 24 Feb 2020 19:50:25 -0600 Subject: [PATCH 1591/5092] Return length from write_os_str_to_c_str --- src/helpers.rs | 57 ++++++++++++++++++++---------------------------- src/shims/env.rs | 2 +- src/shims/fs.rs | 12 ++++++---- 3 files changed, 33 insertions(+), 38 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 24adc72fa87b..53facf89dce9 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -474,35 +474,42 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what - /// the Unix APIs usually handle. This function returns `Ok(false)` without trying to write if - /// `size` is not large enough to fit the contents of `os_string` plus a null terminator. It - /// returns `Ok(true)` if the writing process was successful. + /// the Unix APIs usually handle. This function returns `Ok((false, length))` without trying + /// to write if `size` is not large enough to fit the contents of `os_string` plus a null + /// terminator. It returns `Ok((true, length))` if the writing process was successful. The + /// string length returned does not include the null terminator. fn write_os_str_to_c_str( &mut self, os_str: &OsStr, scalar: Scalar, size: u64, - ) -> InterpResult<'tcx, bool> { + ) -> InterpResult<'tcx, (bool, u64)> { + #[cfg(target_os = "unix")] + fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + std::os::unix::ffi::OsStringExt::into_bytes(os_str) + } + #[cfg(not(target_os = "unix"))] + fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the + // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually + // valid. + os_str + .to_str() + .map(|s| s.as_bytes()) + .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) + } + let bytes = os_str_to_bytes(os_str)?; // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null // terminator to memory using the `ptr` pointer would cause an out-of-bounds access. - if size <= bytes.len() as u64 { - return Ok(false); + let string_length = bytes.len() as u64; + if size <= string_length { + return Ok((false, string_length)); } self.eval_context_mut() .memory .write_bytes(scalar, bytes.iter().copied().chain(iter::once(0u8)))?; - Ok(true) - } - - /// Helper function to determine how long an OsStr would be as a C string, not including the - /// null terminator. - fn os_str_length_as_c_str( - &mut self, - os_str: &OsStr, - ) -> InterpResult<'tcx, usize> { - let bytes = os_str_to_bytes(os_str)?; - Ok(bytes.len()) + Ok((true, string_length)) } fn alloc_os_str_as_c_str( @@ -520,22 +527,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } -#[cfg(target_os = "unix")] -fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - std::os::unix::ffi::OsStringExt::into_bytes(os_str) -} - -#[cfg(not(target_os = "unix"))] -fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the - // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually - // valid. - os_str - .to_str() - .map(|s| s.as_bytes()) - .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) -} - pub fn immty_from_int_checked<'tcx>( int: impl Into, layout: TyLayout<'tcx>, diff --git a/src/shims/env.rs b/src/shims/env.rs index 96174010441c..3fd895576e53 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -124,7 +124,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If we cannot get the current directory, we return null match env::current_dir() { Ok(cwd) => { - if this.write_os_str_to_c_str(&OsString::from(cwd), buf, size)? { + if this.write_os_str_to_c_str(&OsString::from(cwd), buf, size)?.0 { return Ok(buf); } let erange = this.eval_libc("ERANGE")?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index a3ac59bdf6e7..cbdaf9a65b7d 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -906,7 +906,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_place = this.mplace_field(entry_place, 4)?; let file_name = dir_entry.file_name(); - let name_fits = this.write_os_str_to_c_str(&file_name, name_place.ptr, name_place.layout.size.bytes())?; + let (name_fits, _) = this.write_os_str_to_c_str( + &file_name, name_place.ptr, + name_place.layout.size.bytes(), + )?; if !name_fits { throw_unsup_format!("A directory entry had a name too large to fit in libc::dirent64"); } @@ -990,7 +993,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_place = this.mplace_field(entry_place, 5)?; let file_name = dir_entry.file_name(); - let name_fits = this.write_os_str_to_c_str(&file_name, name_place.ptr, name_place.layout.size.bytes())?; + let (name_fits, file_name_len) = this.write_os_str_to_c_str( + &file_name, name_place.ptr, + name_place.layout.size.bytes(), + )?; if !name_fits { throw_unsup_format!("A directory entry had a name too large to fit in libc::dirent"); } @@ -1008,8 +1014,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[cfg(not(unix))] let ino = 0; - let file_name_len = this.os_str_length_as_c_str(&file_name)? as u128; - let file_type = this.file_type_to_d_type(dir_entry.file_type())? as u128; let imms = [ From 739d796b0588bb7c38c2a69f17d44084d48d5010 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 25 Feb 2020 18:12:00 +0100 Subject: [PATCH 1592/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index fe788019e012..d338cf6694bb 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -2851e59a52673e0242532035047009c6e121c95a +e3a277943e5e55a4ef169d5cc629de664db5e24e From 7e128beff92f0a3c790e18dd1c43e107629d6fa9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 26 Feb 2020 13:50:33 +0100 Subject: [PATCH 1593/5092] fix build failures --- benches/helpers/miri_helper.rs | 1 + src/bin/miri-rustc-tests.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 122d381f7927..2483f2de3a86 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -31,6 +31,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { self.bencher.iter(|| { let config = miri::MiriConfig { validate: true, + stacked_borrows: true, communicate: false, ignore_leaks: false, excluded_env_vars: vec![], diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 2ac0ab9ca4de..abda47f75b1c 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -46,6 +46,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { { let config = MiriConfig { validate: true, + stacked_borrows: true, communicate: false, ignore_leaks: false, excluded_env_vars: vec![], @@ -67,6 +68,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { let config = MiriConfig { validate: true, + stacked_borrows: true, communicate: false, ignore_leaks: false, excluded_env_vars: vec![], From df59d7ff749a685d6259271be9c0d6466b347f2f Mon Sep 17 00:00:00 2001 From: David Cook Date: Wed, 26 Feb 2020 07:59:11 -0600 Subject: [PATCH 1594/5092] Review comments --- src/shims/fs.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index cbdaf9a65b7d..880d7ddd0ae9 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -881,6 +881,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.check_no_isolation("readdir64_r")?; + this.assert_platform("linux", "readdir64_r"); let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; @@ -907,7 +908,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let file_name = dir_entry.file_name(); let (name_fits, _) = this.write_os_str_to_c_str( - &file_name, name_place.ptr, + &file_name, + name_place.ptr, name_place.layout.size.bytes(), )?; if !name_fits { @@ -966,10 +968,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.check_no_isolation("readdir_r")?; + this.assert_platform("macos", "readdir_r"); let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; - let dir_iter = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { err_unsup_format!("The DIR pointer passed to readdir_r did not come from opendir") })?; @@ -994,7 +996,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let file_name = dir_entry.file_name(); let (name_fits, file_name_len) = this.write_os_str_to_c_str( - &file_name, name_place.ptr, + &file_name, + name_place.ptr, name_place.layout.size.bytes(), )?; if !name_fits { From 62f9f4c578ab2780468ac3a25fe46d0d9a1c8146 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 26 Feb 2020 15:15:16 +0100 Subject: [PATCH 1595/5092] fix Windows build failure --- src/shims/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 880d7ddd0ae9..cc8f18af7d61 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -927,7 +927,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[cfg(unix)] let ino = std::os::unix::fs::DirEntryExt::ino(&dir_entry); #[cfg(not(unix))] - let ino = 0; + let ino = 0u64; let file_type = this.file_type_to_d_type(dir_entry.file_type())? as u128; @@ -1015,7 +1015,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[cfg(unix)] let ino = std::os::unix::fs::DirEntryExt::ino(&dir_entry); #[cfg(not(unix))] - let ino = 0; + let ino = 0u64; let file_type = this.file_type_to_d_type(dir_entry.file_type())? as u128; From 5187e5ddd68bf0ac3d6da3302eb11ca46c83e7ce Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 28 Feb 2020 10:00:20 +0100 Subject: [PATCH 1596/5092] avoid Scalar::to_bits --- src/shims/foreign_items/posix.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 636137f62de0..e80908d8fa09 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -205,18 +205,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_key_delete" => { - let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; + let key = this.force_bits(this.read_scalar(args[0])?.not_undef()?, args[0].layout.size)?; this.machine.tls.delete_tls_key(key)?; // Return success (0) this.write_null(dest)?; } "pthread_getspecific" => { - let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; + let key = this.force_bits(this.read_scalar(args[0])?.not_undef()?, args[0].layout.size)?; let ptr = this.machine.tls.load_tls(key, tcx)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { - let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; + let key = this.force_bits(this.read_scalar(args[0])?.not_undef()?, args[0].layout.size)?; let new_ptr = this.read_scalar(args[1])?.not_undef()?; this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?; From df732c863e4c7d86f23ea2e47abd7db4798bde82 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 29 Feb 2020 13:28:59 +0100 Subject: [PATCH 1597/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index d338cf6694bb..f1a0bf19e34b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e3a277943e5e55a4ef169d5cc629de664db5e24e +04e7f96dd89b1f0ad615dff1c85d11d4c4c64cb4 From 2b04e3954a1aace62bd8e127f2b80c8cdfeeb5e6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 29 Feb 2020 19:46:42 +0100 Subject: [PATCH 1598/5092] Remove incorrect try_lock from Windows critical section shim --- src/shims/foreign_items/windows.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 29eac99e565c..623b0f307b91 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -124,11 +124,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "DeleteCriticalSection" => { // Nothing to do, not even a return value. + // (Windows locks are reentrant, and we have only 1 thread, + // so not doing any futher checks here is at least not incorrect.) } | "GetModuleHandleW" | "GetProcAddress" - | "TryEnterCriticalSection" | "GetConsoleScreenBufferInfo" | "SetConsoleTextAttribute" => { From ea5aa19487a28246c2fa29155c4f7be21b4cdfd0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Mar 2020 10:22:13 +0100 Subject: [PATCH 1599/5092] rustup --- rust-version | 2 +- src/lib.rs | 2 +- src/machine.rs | 2 +- src/shims/foreign_items.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index f1a0bf19e34b..f28fce1af27c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -04e7f96dd89b1f0ad615dff1c85d11d4c4c64cb4 +d9051341a1c142542a3f7dab509266606c775382 diff --git a/src/lib.rs b/src/lib.rs index 10dfc32b0f78..f62f9a850d15 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,7 @@ extern crate log; // From rustc. extern crate rustc_apfloat; -extern crate syntax; +extern crate rustc_ast; #[macro_use] extern crate rustc; extern crate rustc_hir; diff --git a/src/machine.rs b/src/machine.rs index ec4c69159c6e..f90c8b82e64f 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -16,7 +16,7 @@ use rustc::ty::{ Ty, TyCtxt, }; use rustc_span::{source_map::Span, symbol::sym}; -use syntax::attr; +use rustc_ast::attr; use crate::*; diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 3d8d3bd52607..f8b42e509133 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -9,7 +9,7 @@ use rustc::ty; use rustc::ty::layout::{Align, Size}; use rustc_apfloat::Float; use rustc_span::symbol::sym; -use syntax::attr; +use rustc_ast::attr; use crate::*; From cc1ebd0af62c4d0b7138a07893ee73d3e4ef05a5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Mar 2020 10:26:24 +0100 Subject: [PATCH 1600/5092] some formatting --- src/eval.rs | 7 ++----- src/helpers.rs | 12 +++++------ src/lib.rs | 18 +++++++++++------ src/machine.rs | 46 +++++++++++++++++------------------------- src/operator.rs | 6 +++--- src/stacked_borrows.rs | 25 ++++++++++++++--------- 6 files changed, 57 insertions(+), 57 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index eca634d02098..cc02100dd3b3 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -5,9 +5,9 @@ use std::ffi::OsStr; use rand::rngs::StdRng; use rand::SeedableRng; -use rustc_hir::def_id::DefId; use rustc::ty::layout::{LayoutOf, Size}; use rustc::ty::{self, TyCtxt}; +use rustc_hir::def_id::DefId; use crate::*; @@ -50,10 +50,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let mut ecx = InterpCx::new( tcx.at(rustc_span::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), - Evaluator::new( - config.communicate, - config.validate, - ), + Evaluator::new(config.communicate, config.validate), MemoryExtra::new( StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.stacked_borrows, diff --git a/src/helpers.rs b/src/helpers.rs index 53facf89dce9..19db6852c56a 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,13 +1,13 @@ use std::ffi::OsStr; use std::{iter, mem}; -use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc::ty::{ self, layout::{self, LayoutOf, Size, TyLayout}, List, TyCtxt, }; +use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_span::source_map::DUMMY_SP; use rand::RngCore; @@ -515,7 +515,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn alloc_os_str_as_c_str( &mut self, os_str: &OsStr, - memkind: MemoryKind + memkind: MemoryKind, ) -> Pointer { let size = os_str.len() as u64 + 1; // Make space for `0` terminator. let this = self.eval_context_mut(); @@ -532,9 +532,9 @@ pub fn immty_from_int_checked<'tcx>( layout: TyLayout<'tcx>, ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let int = int.into(); - Ok(ImmTy::try_from_int(int, layout).ok_or_else(|| + Ok(ImmTy::try_from_int(int, layout).ok_or_else(|| { err_unsup_format!("Signed value {:#x} does not fit in {} bits", int, layout.size.bits()) - )?) + })?) } pub fn immty_from_uint_checked<'tcx>( @@ -542,7 +542,7 @@ pub fn immty_from_uint_checked<'tcx>( layout: TyLayout<'tcx>, ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let int = int.into(); - Ok(ImmTy::try_from_uint(int, layout).ok_or_else(|| + Ok(ImmTy::try_from_uint(int, layout).ok_or_else(|| { err_unsup_format!("Signed value {:#x} does not fit in {} bits", int, layout.size.bits()) - )?) + })?) } diff --git a/src/lib.rs b/src/lib.rs index f62f9a850d15..2a805f855579 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,10 +11,10 @@ extern crate rustc_apfloat; extern crate rustc_ast; #[macro_use] extern crate rustc; -extern crate rustc_hir; -extern crate rustc_span; extern crate rustc_data_structures; +extern crate rustc_hir; extern crate rustc_mir; +extern crate rustc_span; extern crate rustc_target; mod diagnostics; @@ -44,7 +44,8 @@ pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::EvalContextExt as ShimsEvalContextExt; pub use crate::diagnostics::{ - register_diagnostic, report_diagnostic, EvalContextExt as DiagnosticsEvalContextExt, NonHaltingDiagnostic, + register_diagnostic, report_diagnostic, EvalContextExt as DiagnosticsEvalContextExt, + NonHaltingDiagnostic, }; pub use crate::eval::{create_ecx, eval_main, MiriConfig, TerminationInfo}; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; @@ -56,12 +57,17 @@ pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ - EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, Stack, - Stacks, Tag, + EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, Stack, Stacks, Tag, }; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. pub fn miri_default_args() -> &'static [&'static str] { - &["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0", "--cfg=miri", "-Cdebug-assertions=on"] + &[ + "-Zalways-encode-mir", + "-Zmir-emit-retag", + "-Zmir-opt-level=0", + "--cfg=miri", + "-Cdebug-assertions=on", + ] } diff --git a/src/machine.rs b/src/machine.rs index f90c8b82e64f..b5c76070ae30 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -3,20 +3,20 @@ use std::borrow::Cow; use std::cell::RefCell; -use std::rc::Rc; use std::num::NonZeroU64; +use std::rc::Rc; use rand::rngs::StdRng; -use rustc_hir::def_id::DefId; use rustc::mir; use rustc::ty::{ self, layout::{LayoutOf, Size}, Ty, TyCtxt, }; -use rustc_span::{source_map::Span, symbol::sym}; use rustc_ast::attr; +use rustc_hir::def_id::DefId; +use rustc_span::{source_map::Span, symbol::sym}; use crate::*; @@ -85,11 +85,7 @@ impl MemoryExtra { } else { None }; - MemoryExtra { - stacked_borrows, - intptrcast: Default::default(), - rng: RefCell::new(rng), - } + MemoryExtra { stacked_borrows, intptrcast: Default::default(), rng: RefCell::new(rng) } } } @@ -307,18 +303,15 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ) -> (Cow<'b, Allocation>, Self::PointerTag) { let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); - let (stacks, base_tag) = if let Some(stacked_borrows) = memory_extra.stacked_borrows.as_ref() { - let (stacks, base_tag) = Stacks::new_allocation( - id, - alloc.size, - Rc::clone(stacked_borrows), - kind, - ); - (Some(stacks), base_tag) - } else { - // No stacks, no tag. - (None, Tag::Untagged) - }; + let (stacks, base_tag) = + if let Some(stacked_borrows) = memory_extra.stacked_borrows.as_ref() { + let (stacks, base_tag) = + Stacks::new_allocation(id, alloc.size, Rc::clone(stacked_borrows), kind); + (Some(stacks), base_tag) + } else { + // No stacks, no tag. + (None, Tag::Untagged) + }; let mut stacked_borrows = memory_extra.stacked_borrows.as_ref().map(|sb| sb.borrow_mut()); let alloc: Allocation = alloc.with_tags_and_extra( |alloc| { @@ -360,14 +353,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, FrameData<'tcx>> { - let call_id = ecx.memory.extra.stacked_borrows.as_ref().map_or( - NonZeroU64::new(1).unwrap(), - |stacked_borrows| stacked_borrows.borrow_mut().new_call(), - ); - Ok(FrameData { - call_id, - catch_panic: None, - }) + let stacked_borrows = ecx.memory.extra.stacked_borrows.as_ref(); + let call_id = stacked_borrows.map_or(NonZeroU64::new(1).unwrap(), |stacked_borrows| { + stacked_borrows.borrow_mut().new_call() + }); + Ok(FrameData { call_id, catch_panic: None }) } #[inline(always)] diff --git a/src/operator.rs b/src/operator.rs index 8860b949fe94..c494e4ff8c72 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -103,9 +103,9 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { offset: i64, ) -> InterpResult<'tcx, Scalar> { let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); - let offset = offset - .checked_mul(pointee_size) - .ok_or_else(|| err_ub_format!("overflow during offset comutation for inbounds pointer arithmetic"))?; + let offset = offset.checked_mul(pointee_size).ok_or_else(|| { + err_ub_format!("overflow during offset comutation for inbounds pointer arithmetic") + })?; // We do this first, to rule out overflows. let offset_ptr = ptr.ptr_signed_offset(offset, self)?; // What we need to check is that starting at `min(ptr, offset_ptr)`, diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 9a674830c8ec..a51f8c457143 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -7,9 +7,9 @@ use std::fmt; use std::num::NonZeroU64; use std::rc::Rc; -use rustc_hir::Mutability; use rustc::mir::RetagKind; use rustc::ty::{self, layout::Size}; +use rustc_hir::Mutability; use crate::*; @@ -293,9 +293,12 @@ impl<'tcx> Stack { // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. - let granting_idx = self.find_granting(access, tag).ok_or_else(|| err_ub!(UbExperimental( - format!("no item granting {} to tag {:?} found in borrow stack.", access, tag), - )))?; + let granting_idx = self.find_granting(access, tag).ok_or_else(|| { + err_ub!(UbExperimental(format!( + "no item granting {} to tag {:?} found in borrow stack.", + access, tag + ),)) + })?; // Step 2: Remove incompatible items above them. Make sure we do not remove protected // items. Behavior differs for reads and writes. @@ -334,10 +337,12 @@ impl<'tcx> Stack { /// active protectors at all because we will remove all items. fn dealloc(&mut self, tag: Tag, global: &GlobalState) -> InterpResult<'tcx> { // Step 1: Find granting item. - self.find_granting(AccessKind::Write, tag).ok_or_else(|| err_ub!(UbExperimental(format!( - "no item granting write access for deallocation to tag {:?} found in borrow stack", - tag, - ))))?; + self.find_granting(AccessKind::Write, tag).ok_or_else(|| { + err_ub!(UbExperimental(format!( + "no item granting write access for deallocation to tag {:?} found in borrow stack", + tag, + ))) + })?; // Step 2: Remove all items. Also checks for protectors. for item in self.borrows.drain(..).rev() { @@ -575,7 +580,9 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // breaking `Rc::from_raw`. RefKind::Raw { .. } => Tag::Untagged, // All other pointesr are properly tracked. - _ => Tag::Tagged(this.memory.extra.stacked_borrows.as_ref().unwrap().borrow_mut().new_ptr()), + _ => Tag::Tagged( + this.memory.extra.stacked_borrows.as_ref().unwrap().borrow_mut().new_ptr(), + ), }; // Reborrow. From af98bd9a53f575bf755d172b2e64e552c59a5180 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Mar 2020 11:53:34 +0100 Subject: [PATCH 1601/5092] fix trailing indent in xargo files --- src/bin/cargo-miri.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 17063b6ff67f..88609d4dea63 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -353,7 +353,7 @@ default_features = false features = ["panic_unwind"] [dependencies.test] - "#, +"#, ) .unwrap(); // The boring bits: a dummy project for xargo. @@ -369,7 +369,7 @@ version = "0.0.0" [lib] path = "lib.rs" - "#, +"#, ) .unwrap(); File::create(dir.join("lib.rs")).unwrap(); From 48a4e3f4d89a365dde0e0b257d7af6631d4d69aa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Mar 2020 11:54:19 +0100 Subject: [PATCH 1602/5092] format a few things --- src/bin/cargo-miri.rs | 31 ++++++++++++++++--------------- src/bin/miri-rustc-tests.rs | 8 +++++--- src/bin/miri.rs | 2 +- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 88609d4dea63..f8a408561b0b 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -563,7 +563,8 @@ fn inside_cargo_rustc() { // other args for target crates - that is, crates which are ultimately // going to get interpreted by Miri. if target_crate { - let sysroot = std::env::var("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); + let sysroot = + std::env::var("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); args.push("--sysroot".to_owned()); args.push(sysroot); args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string)); @@ -571,20 +572,20 @@ fn inside_cargo_rustc() { // Figure out the binary we need to call. If this is a runnable target crate, we want to call // Miri to start interpretation; otherwise we want to call rustc to build the crate as usual. - let mut command = - if target_crate && is_runnable_crate() { - // This is the 'target crate' - the binary or test crate that - // we want to interpret under Miri. We deserialize the user-provided arguments - // from the special environment variable "MIRI_ARGS", and feed them - // to the 'miri' binary. - let magic = std::env::var("MIRI_ARGS").expect("missing MIRI_ARGS"); - let mut user_args: Vec = serde_json::from_str(&magic).expect("failed to deserialize MIRI_ARGS"); - args.append(&mut user_args); - // Run this in Miri. - Command::new(find_miri()) - } else { - Command::new("rustc") - }; + let mut command = if target_crate && is_runnable_crate() { + // This is the 'target crate' - the binary or test crate that + // we want to interpret under Miri. We deserialize the user-provided arguments + // from the special environment variable "MIRI_ARGS", and feed them + // to the 'miri' binary. + let magic = std::env::var("MIRI_ARGS").expect("missing MIRI_ARGS"); + let mut user_args: Vec = + serde_json::from_str(&magic).expect("failed to deserialize MIRI_ARGS"); + args.append(&mut user_args); + // Run this in Miri. + Command::new(find_miri()) + } else { + Command::new("rustc") + }; // Run it. command.args(&args); diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index abda47f75b1c..9cc9901a9134 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -15,11 +15,11 @@ use std::io::Write; use std::path::Path; use std::sync::{Arc, Mutex}; +use rustc::ty::TyCtxt; +use rustc_driver::Compilation; use rustc_hir as hir; use rustc_hir::def_id::LOCAL_CRATE; use rustc_hir::itemlikevisit; -use rustc::ty::TyCtxt; -use rustc_driver::Compilation; use rustc_interface::{interface, Queries}; use miri::MiriConfig; @@ -42,7 +42,9 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { impl<'tcx, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.kind { - if i.attrs.iter().any(|attr| attr.check_name(rustc_span::symbol::sym::test)) + if i.attrs + .iter() + .any(|attr| attr.check_name(rustc_span::symbol::sym::test)) { let config = MiriConfig { validate: true, diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 9523609889cd..e69e7f7b6f50 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -21,8 +21,8 @@ use std::str::FromStr; use hex::FromHexError; -use rustc_hir::def_id::LOCAL_CRATE; use rustc_driver::Compilation; +use rustc_hir::def_id::LOCAL_CRATE; use rustc_interface::{interface, Queries}; struct MiriCompilerCalls { From 340e14ee4204599c573e4f651e636aeaab5ce037 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Feb 2020 17:45:57 +0100 Subject: [PATCH 1603/5092] tweak benchmark --- bench-cargo-miri/mse/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench-cargo-miri/mse/src/main.rs b/bench-cargo-miri/mse/src/main.rs index 696de93442ed..b4ad1575104e 100644 --- a/bench-cargo-miri/mse/src/main.rs +++ b/bench-cargo-miri/mse/src/main.rs @@ -2,7 +2,7 @@ static EXPECTED: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, static PCM: &[i16] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1, 0, 1, 0, 0, -2, 0, -2, 0, -2, 0, -2, -2, -2, -3, -3, -3, -3, -4, -2, -5, -2, -5, -2, -4, 0, -4, 0, -4, 0, -4, 1, -4, 1, -4, 2, -4, 2, -4, 2, -4, 2, -4, 2, -3, 1, -4, 0, -4, 0, -5, 0, -5, 0, -5, 0, -4, 2, -4, 3, -4, 4, -3, 5, -2, 5, -3, 6, -3, 6, -3, 5, -3, 5, -2, 4, -2, 3, -5, 0, -6, 0, -3, -2, -4, -4, -9, -5, -9, -4, -4, -2, -4, -2, -4, 0, -2, 1, 1, 1, 4, 2, 8, 2, 12, 1, 13, 0, 12, 0, 11, 0, 8, -2, 7, 0, 7, -3, 11, -8, 15, -9, 17, -6, 17, -5, 13, -3, 7, 0, 3, 0, -2, 0, -4, 0, -4, -2, -6, 0, -14, -2, -17, -4, -8, 0, -7, 5, -17, 7, -18, 10, -7, 18, -2, 25, -3, 27, 0, 31, 4, 34, 4, 34, 8, 36, 8, 37, 2, 36, 4, 34, 8, 28, 3, 15, 0, 11, 0, 12, -5, 8, -4, 10, 0, 23, -4, 31, -8, 30, -2, 30, 0, 26, -6, 22, -6, 20, -12, 15, -19, 10, -10, 13, -14, 6, -43, -13, -43, -16, -9, -12, -10, -29, -42, -40, -37, -28, -5, -21, 1, -24, -8, -20, 4, -18, 26, -24, 44, -26, 66, -30, 86, -37, 88, -41, 72, -46, 50, -31, 28, 23, 14, 64, 16, 51, 26, 32, 34, 39, 42, 48, 35, 58, 0, 72, -36, 69, -59, 58, -98, 54, -124, 36, -103, 12, -110, 5, -173, -19, -146, -59, -4, -42, 51, 1, -23, -6, -30, -6, 45, 46, 47, 70, 6, 55, 19, 60, 38, 62, 42, 47, 61, 46, 40, 42, -19, 22, -34, 6, -35, -50, -61, -141, -37, -171, 17, -163, 26, -180, 46, -154, 80, -63, 48, -4, 18, 20, 50, 47, 58, 53, 44, 61, 57, 85, 37, 80, 0, 86, -8, 106, -95, 49, -213, -8, -131, 47, 49, 63, 40, -39, -69, -74, -37, -20, 63, -12, 58, -14, -12, 25, -31, 41, 11, 45, 76, 47, 167, 5, 261, -37, 277, -83, 183, -172, 35, -122, -79, 138, -70, 266, 69, 124, 228, 0, 391, -29, 594, -84, 702, -78, 627, -8, 551, -13, 509, 13, 372, 120, 352, 125, 622, 127, 691, 223, 362, 126, 386, -33, 915, 198, 958, 457, 456, 298, 500, 233, 1027, 469, 1096, 426, 918, 160, 1067, 141, 1220, 189, 1245, 164, 1375, 297, 1378, 503, 1299, 702, 1550, 929, 1799, 855, 1752, 547, 1830, 602, 1928, 832, 1736, 796, 1735, 933, 1961, 1385, 1935, 1562, 2105, 1485, 2716, 1449, 2948, 1305, 2768, 1205, 2716, 1346, 2531, 1450, 2470, 1653, 3117, 2111, 3370, 2176, 2696, 1947, 2925, 2305, 3846, 2658, 2425, 2184, -877, 1981, -2261, 2623, -1645, 2908, -1876, 2732, -2704, 2953, -2484, 3116, -2120, 2954, -2442, 3216, -2466, 3499, -2192, 3234, -2392, 3361, -2497, 3869, -2078, 3772, -1858, 3915, -2066, 4438, -2285, 2934, -2294, -280, -2066, -1762, -1992, -1412, -2298, -1535, -2399, -1789, -2223, -1419, -2244, -1334, -2092, -1476, -1777, -1396, -2014, -1571, -2199, -1574, -1843, -1167, -1910, -1446, -2007, -1818]; fn main() { - for i in 0..5 { + for _ in 0..2 { mse(PCM.len(), PCM, EXPECTED); } } From 5d8fbfcb5f0a9db6c55e1953e5f9680a7e65cbda Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Feb 2020 21:55:02 +0100 Subject: [PATCH 1604/5092] rename memory kind: Env -> Machine --- src/eval.rs | 14 +++++++------- src/machine.rs | 6 +++--- src/shims/env.rs | 6 +++--- src/shims/panic.rs | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index cc02100dd3b3..a46d6ce8a8ed 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -90,14 +90,14 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Make space for `0` terminator. let size = arg.len() as u64 + 1; let arg_type = tcx.mk_array(tcx.types.u8, size); - let arg_place = ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Env.into()); + let arg_place = ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Machine.into()); ecx.write_os_str_to_c_str(OsStr::new(arg), arg_place.ptr, size)?; argvs.push(arg_place.ptr); } // Make an array with all these pointers, in the Miri memory. let argvs_layout = ecx.layout_of(tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), argvs.len() as u64))?; - let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into()); + let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into()); for (idx, arg) in argvs.into_iter().enumerate() { let place = ecx.mplace_field(argvs_place, idx as u64)?; ecx.write_scalar(arg, place.into())?; @@ -108,13 +108,13 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`. { let argc_place = - ecx.allocate(ecx.layout_of(tcx.types.isize)?, MiriMemoryKind::Env.into()); + ecx.allocate(ecx.layout_of(tcx.types.isize)?, MiriMemoryKind::Machine.into()); ecx.write_scalar(argc, argc_place.into())?; ecx.machine.argc = Some(argc_place.ptr); let argv_place = ecx.allocate( ecx.layout_of(tcx.mk_imm_ptr(tcx.types.unit))?, - MiriMemoryKind::Env.into(), + MiriMemoryKind::Machine.into(), ); ecx.write_scalar(argv, argv_place.into())?; ecx.machine.argv = Some(argv_place.ptr); @@ -134,7 +134,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let cmd_utf16: Vec = cmd.encode_utf16().collect(); let cmd_type = tcx.mk_array(tcx.types.u16, cmd_utf16.len() as u64); - let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Env.into()); + let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Machine.into()); ecx.machine.cmd_line = Some(cmd_place.ptr); // Store the UTF-16 string. We just allocated so we know the bounds are fine. let char_size = Size::from_bytes(2); @@ -147,7 +147,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( }; // Return place (in static memory so that it does not count as leak). - let ret_place = ecx.allocate(ecx.layout_of(tcx.types.isize)?, MiriMemoryKind::Env.into()); + let ret_place = ecx.allocate(ecx.layout_of(tcx.types.isize)?, MiriMemoryKind::Machine.into()); // Call start function. ecx.call_function( start_instance, @@ -158,7 +158,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Set the last_error to 0 let errno_layout = ecx.layout_of(tcx.types.u32)?; - let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Env.into()); + let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Machine.into()); ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?; ecx.machine.last_error = Some(errno_place); diff --git a/src/machine.rs b/src/machine.rs index b5c76070ae30..9362ca16eac4 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -48,8 +48,8 @@ pub enum MiriMemoryKind { C, /// Windows `HeapAlloc` memory. WinHeap, - /// Memory for env vars and args, errno and other parts of the machine-managed environment. - Env, + /// Memory for env vars and args, errno, extern statics and other parts of the machine-managed environment. + Machine, /// Rust statics. Static, } @@ -433,7 +433,7 @@ impl MayLeak for MiriMemoryKind { use self::MiriMemoryKind::*; match self { Rust | C | WinHeap => false, - Env | Static => true, + Machine | Static => true, } } } diff --git a/src/shims/env.rs b/src/shims/env.rs index 3fd895576e53..10f749216541 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -40,7 +40,7 @@ fn alloc_env_var_as_c_str<'mir, 'tcx>( let mut name_osstring = name.to_os_string(); name_osstring.push("="); name_osstring.push(value); - ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Env.into()) + ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into()) } impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -80,7 +80,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let var_ptr = alloc_env_var_as_c_str(&name, &value, &mut this); if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), var_ptr) { this.memory - .deallocate(var, None, MiriMemoryKind::Env.into())?; + .deallocate(var, None, MiriMemoryKind::Machine.into())?; } Ok(0) } else { @@ -102,7 +102,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(old) = success { if let Some(var) = old { this.memory - .deallocate(var, None, MiriMemoryKind::Env.into())?; + .deallocate(var, None, MiriMemoryKind::Machine.into())?; } Ok(0) } else { diff --git a/src/shims/panic.rs b/src/shims/panic.rs index e930af7f46c5..11c5a882be9b 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -187,7 +187,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // First arg: Message. let msg = msg.description(); - let msg = this.allocate_str(msg, MiriMemoryKind::Env.into()); + let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into()); // Call the lang item. let panic = this.tcx.lang_items().panic_fn().unwrap(); From 8ef303cd3263c8d30db711484393455b38c8d41c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Feb 2020 22:32:37 +0100 Subject: [PATCH 1605/5092] port from find_foreign_static to canonical_alloc_id --- src/eval.rs | 1 + src/machine.rs | 75 +++++++++++++++++++++++++++++------------- src/stacked_borrows.rs | 2 +- 3 files changed, 54 insertions(+), 24 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index a46d6ce8a8ed..267b79d0eba7 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -58,6 +58,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ), ); // Complete initialization. + MemoryExtra::init_extern_statics(&mut ecx)?; EnvVars::init(&mut ecx, config.excluded_env_vars); // Setup first stack-frame diff --git a/src/machine.rs b/src/machine.rs index 9362ca16eac4..e4e709f7e287 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -3,6 +3,7 @@ use std::borrow::Cow; use std::cell::RefCell; +use std::collections::HashMap; use std::num::NonZeroU64; use std::rc::Rc; @@ -12,7 +13,7 @@ use rustc::mir; use rustc::ty::{ self, layout::{LayoutOf, Size}, - Ty, TyCtxt, + Ty, }; use rustc_ast::attr; use rustc_hir::def_id::DefId; @@ -74,7 +75,11 @@ pub struct MemoryExtra { pub stacked_borrows: Option, pub intptrcast: intptrcast::MemoryExtra, + /// Mapping extern static names to their canonical allocation. + pub(crate) extern_statics: HashMap<&'static str, AllocId>, + /// The random number generator used for resolving non-determinism. + /// Needs to be queried by ptr_to_int, hence needs interior mutability. pub(crate) rng: RefCell, } @@ -85,7 +90,34 @@ impl MemoryExtra { } else { None }; - MemoryExtra { stacked_borrows, intptrcast: Default::default(), rng: RefCell::new(rng) } + MemoryExtra { + stacked_borrows, + intptrcast: Default::default(), + extern_statics: HashMap::default(), + rng: RefCell::new(rng), + } + } + + /// Sets up the "extern statics" for this machine. + pub fn init_extern_statics<'mir, 'tcx>( + this: &mut MiriEvalContext<'mir, 'tcx>, + ) -> InterpResult<'tcx> { + match this.tcx.sess.target.target.target_os.as_str() { + "linux" => { + // "__cxa_thread_atexit_impl" + // This should be all-zero, pointer-sized. + let layout = this.layout_of(this.tcx.types.usize)?; + let place = this.allocate(layout, MiriMemoryKind::Machine.into()); + this.write_scalar(Scalar::from_machine_usize(0, &*this.tcx), place.into())?; + this.memory + .extra + .extern_statics + .insert("__cxa_thread_atexit_impl", place.ptr.assert_ptr().alloc_id) + .unwrap_none(); + } + _ => {} // No "extern statics" supported on this platform + } + Ok(()) } } @@ -267,32 +299,29 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { Ok(()) } - fn find_foreign_static( - tcx: TyCtxt<'tcx>, - def_id: DefId, - ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { + fn canonical_alloc_id(mem: &Memory<'mir, 'tcx, Self>, id: AllocId) -> AllocId { + let tcx = mem.tcx; + // Figure out if this is an extern static, and if yes, which one. + let def_id = match tcx.alloc_map.lock().get(id) { + Some(GlobalAlloc::Static(def_id)) if tcx.is_foreign_item(def_id) => def_id, + _ => { + // No need to canonicalize anything. + return id; + } + }; let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { Some(name) => name.as_str(), None => tcx.item_name(def_id).as_str(), }; - - let alloc = match &*link_name { - "__cxa_thread_atexit_impl" => { - // This should be all-zero, pointer-sized. - let size = tcx.data_layout.pointer_size; - let data = vec![0; size.bytes() as usize]; - Allocation::from_bytes(&data, tcx.data_layout.pointer_align.abi) - } - _ => throw_unsup_format!("can't access foreign static: {}", link_name), - }; - Ok(Cow::Owned(alloc)) - } - - #[inline(always)] - fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { - // We are not interested in detecting loops. - Ok(()) + // Check if we know this one. + if let Some(canonical_id) = mem.extra.extern_statics.get(&*link_name) { + trace!("canonical_alloc_id: {:?} ({}) -> {:?}", id, link_name, canonical_id); + *canonical_id + } else { + // Return original id; `Memory::get_static_alloc` will throw an error. + id + } } fn init_allocation_extra<'b>( diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index a51f8c457143..9a511aaed577 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -453,7 +453,7 @@ impl Stacks { // Thus we call `static_base_ptr` such that the global pointers get the same tag // as what we use here. // The base pointer is not unique, so the base permission is `SharedReadWrite`. - MemoryKind::Machine(MiriMemoryKind::Static) => + MemoryKind::Machine(MiriMemoryKind::Static) | MemoryKind::Machine(MiriMemoryKind::Machine) => (extra.borrow_mut().static_base_ptr(id), Permission::SharedReadWrite), // Everything else we handle entirely untagged for now. // FIXME: experiment with more precise tracking. From 90327335fc65c7cde6f917a898c35dcf1d019673 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Feb 2020 22:35:13 +0100 Subject: [PATCH 1606/5092] canonicalize alloc ID for ptr-to-int cast --- src/intptrcast.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 059d8217fabb..375ebf09967d 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -5,7 +5,7 @@ use std::collections::{hash_map::Entry, HashMap}; use rand::Rng; use rustc::ty::layout::HasDataLayout; -use rustc_mir::interpret::{AllocCheck, AllocId, InterpResult, Memory, Pointer, PointerArithmetic}; +use rustc_mir::interpret::{AllocCheck, AllocId, InterpResult, Memory, Machine, Pointer, PointerArithmetic}; use rustc_target::abi::Size; use crate::{Evaluator, Tag, STACK_ADDR}; @@ -80,12 +80,13 @@ impl<'mir, 'tcx> GlobalState { ) -> InterpResult<'tcx, u64> { let mut global_state = memory.extra.intptrcast.borrow_mut(); let global_state = &mut *global_state; + let id = Evaluator::canonical_alloc_id(memory, ptr.alloc_id); // There is nothing wrong with a raw pointer being cast to an integer only after // it became dangling. Hence `MaybeDead`. - let (size, align) = memory.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead)?; + let (size, align) = memory.get_size_and_align(id, AllocCheck::MaybeDead)?; - let base_addr = match global_state.base_addr.entry(ptr.alloc_id) { + let base_addr = match global_state.base_addr.entry(id) { Entry::Occupied(entry) => *entry.get(), Entry::Vacant(entry) => { // This allocation does not have a base address yet, pick one. @@ -102,7 +103,7 @@ impl<'mir, 'tcx> GlobalState { trace!( "Assigning base address {:#x} to allocation {:?} (slack: {}, align: {})", base_addr, - ptr.alloc_id, + id, slack, align.bytes(), ); @@ -112,7 +113,7 @@ impl<'mir, 'tcx> GlobalState { global_state.next_base_addr = base_addr.checked_add(max(size.bytes(), 1)).unwrap(); // Given that `next_base_addr` increases in each allocation, pushing the // corresponding tuple keeps `int_to_ptr_map` sorted - global_state.int_to_ptr_map.push((base_addr, ptr.alloc_id)); + global_state.int_to_ptr_map.push((base_addr, id)); base_addr } From 21a5da99a4cc87a0053b677c68e4837a833f9941 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Mar 2020 09:00:43 +0100 Subject: [PATCH 1607/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index f28fce1af27c..82d8da1d0301 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d9051341a1c142542a3f7dab509266606c775382 +e86c9e6ef8be7ddec0360f20aae7d86c69c59a83 From 59bddba5f39ab0f61062d06d54aa12eaf18da364 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Mar 2020 09:05:55 +0100 Subject: [PATCH 1608/5092] remove unused import --- src/machine.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/machine.rs b/src/machine.rs index e4e709f7e287..331e75414a0b 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -16,7 +16,6 @@ use rustc::ty::{ Ty, }; use rustc_ast::attr; -use rustc_hir::def_id::DefId; use rustc_span::{source_map::Span, symbol::sym}; use crate::*; From 88c45f9891ede9d5b6643783f51f722fcf817d08 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Feb 2020 09:32:02 +0100 Subject: [PATCH 1609/5092] adjust for rustc changes --- rust-version | 2 +- src/helpers.rs | 9 +++------ tests/compile-fail/validity/cast_fn_ptr1.rs | 2 +- tests/compile-fail/validity/cast_fn_ptr2.rs | 2 +- tests/compile-fail/validity/fn_ptr_offset.rs | 2 +- tests/compile-fail/validity/invalid_bool.rs | 2 +- tests/compile-fail/validity/invalid_char.rs | 2 +- 7 files changed, 9 insertions(+), 12 deletions(-) diff --git a/rust-version b/rust-version index 82d8da1d0301..0b22c04d3050 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e86c9e6ef8be7ddec0360f20aae7d86c69c59a83 +c839a7b4c26e58319b0c40448dd423facff34cd0 diff --git a/src/helpers.rs b/src/helpers.rs index 19db6852c56a..5ff0a5671cdb 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -300,18 +300,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // We have to do *something* for unions. - fn visit_union(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn visit_union(&mut self, v: MPlaceTy<'tcx, Tag>, fields: usize) -> InterpResult<'tcx> { + assert!(fields > 0); // we should never reach "pseudo-unions" with 0 fields, like primitives + // With unions, we fall back to whatever the type says, to hopefully be consistent // with LLVM IR. // FIXME: are we consistent, and is this really the behavior we want? let frozen = self.ecx.type_is_freeze(v.layout.ty); if frozen { Ok(()) } else { (self.unsafe_cell_action)(v) } } - - // We should never get to a primitive, but always short-circuit somewhere above. - fn visit_primitive(&mut self, _v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { - bug!("we should always short-circuit before coming to a primitive") - } } } diff --git a/tests/compile-fail/validity/cast_fn_ptr1.rs b/tests/compile-fail/validity/cast_fn_ptr1.rs index d1f6e33e4598..eb94ba256beb 100644 --- a/tests/compile-fail/validity/cast_fn_ptr1.rs +++ b/tests/compile-fail/validity/cast_fn_ptr1.rs @@ -7,5 +7,5 @@ fn main() { let g: fn(*const i32) = unsafe { std::mem::transmute(f as fn(&i32)) }; g(0usize as *const i32) - //~^ ERROR encountered 0, but expected something greater or equal to 1 + //~^ ERROR encountered a NULL reference } diff --git a/tests/compile-fail/validity/cast_fn_ptr2.rs b/tests/compile-fail/validity/cast_fn_ptr2.rs index 809f118c1df1..a3faa84f1de0 100644 --- a/tests/compile-fail/validity/cast_fn_ptr2.rs +++ b/tests/compile-fail/validity/cast_fn_ptr2.rs @@ -7,5 +7,5 @@ fn main() { let g: fn() -> &'static i32 = unsafe { std::mem::transmute(f as fn() -> *const i32) }; let _x = g(); - //~^ ERROR encountered 0, but expected something greater or equal to 1 + //~^ ERROR encountered a NULL reference } diff --git a/tests/compile-fail/validity/fn_ptr_offset.rs b/tests/compile-fail/validity/fn_ptr_offset.rs index 4989f4d3af7b..5eec58b5e234 100644 --- a/tests/compile-fail/validity/fn_ptr_offset.rs +++ b/tests/compile-fail/validity/fn_ptr_offset.rs @@ -6,5 +6,5 @@ fn main() { let x : fn() = f; let y : *mut u8 = unsafe { mem::transmute(x) }; let y = y.wrapping_offset(1); - let _x : fn() = unsafe { mem::transmute(y) }; //~ ERROR encountered a potentially NULL pointer + let _x : fn() = unsafe { mem::transmute(y) }; //~ ERROR encountered a pointer, but expected a function pointer } diff --git a/tests/compile-fail/validity/invalid_bool.rs b/tests/compile-fail/validity/invalid_bool.rs index ce464616195d..35f4d4228e70 100644 --- a/tests/compile-fail/validity/invalid_bool.rs +++ b/tests/compile-fail/validity/invalid_bool.rs @@ -1,3 +1,3 @@ fn main() { - let _b = unsafe { std::mem::transmute::(2) }; //~ ERROR encountered 2, but expected something less or equal to 1 + let _b = unsafe { std::mem::transmute::(2) }; //~ ERROR encountered 2, but expected a boolean } diff --git a/tests/compile-fail/validity/invalid_char.rs b/tests/compile-fail/validity/invalid_char.rs index a3f907036349..42922cdc917c 100644 --- a/tests/compile-fail/validity/invalid_char.rs +++ b/tests/compile-fail/validity/invalid_char.rs @@ -1,6 +1,6 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); - let _val = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered 4294967295, but expected something less or equal to 1114111 + let _val = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered 4294967295, but expected a valid unicode codepoint 'a' => {true}, 'b' => {false}, _ => {true}, From 5960e8b80e96da62bf13ea72ed63dae23f8dfe96 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 2 Mar 2020 14:17:14 -0500 Subject: [PATCH 1610/5092] Rename XARGO env var to XARGO_CHECK This reflects the fact that we want bootstrap to override `xargo-check`, not `xargo --- src/bin/cargo-miri.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index f8a408561b0b..1a99e5786ff7 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -101,7 +101,7 @@ fn cargo() -> Command { } fn xargo() -> Command { - if let Ok(val) = std::env::var("XARGO") { + if let Ok(val) = std::env::var("XARGO_CHECK") { // Bootstrap tells us where to find xargo Command::new(val) } else { @@ -280,7 +280,7 @@ fn setup(ask_user: bool) { // First, we need xargo. if xargo_version().map_or(true, |v| v < XARGO_MIN_VERSION) { - if std::env::var("XARGO").is_ok() { + if std::env::var("XARGO_CHECK").is_ok() { // The user manually gave us a xargo binary; don't do anything automatically. show_error(format!("Your xargo is too old; please upgrade to the latest version")) } From 68f70195fa562280f9e23b39bc19e05fe4239856 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Mar 2020 22:10:48 +0100 Subject: [PATCH 1611/5092] rename xargo -> xargo_check --- src/bin/cargo-miri.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 1a99e5786ff7..8f26aaf4e91a 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -100,7 +100,7 @@ fn cargo() -> Command { } } -fn xargo() -> Command { +fn xargo_check() -> Command { if let Ok(val) = std::env::var("XARGO_CHECK") { // Bootstrap tells us where to find xargo Command::new(val) @@ -202,7 +202,7 @@ fn test_sysroot_consistency() { } fn xargo_version() -> Option<(u32, u32, u32)> { - let out = xargo().arg("--version").output().ok()?; + let out = xargo_check().arg("--version").output().ok()?; if !out.status.success() { return None; } @@ -376,7 +376,7 @@ path = "lib.rs" // Prepare xargo invocation. let target = get_arg_flag_value("--target"); let print_sysroot = !ask_user && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path - let mut command = xargo(); + let mut command = xargo_check(); command.arg("build").arg("-q"); command.current_dir(&dir); command.env("RUSTFLAGS", miri::miri_default_args().join(" ")); From 0e021ad76cfb2fb4507e3713522707e109ee6ddd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Mar 2020 22:30:20 +0100 Subject: [PATCH 1612/5092] switch extern_statics map to symbols --- src/machine.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 331e75414a0b..c8705eb29e8c 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -16,7 +16,7 @@ use rustc::ty::{ Ty, }; use rustc_ast::attr; -use rustc_span::{source_map::Span, symbol::sym}; +use rustc_span::{source_map::Span, symbol::{sym, Symbol}}; use crate::*; @@ -75,7 +75,7 @@ pub struct MemoryExtra { pub intptrcast: intptrcast::MemoryExtra, /// Mapping extern static names to their canonical allocation. - pub(crate) extern_statics: HashMap<&'static str, AllocId>, + pub(crate) extern_statics: HashMap, /// The random number generator used for resolving non-determinism. /// Needs to be queried by ptr_to_int, hence needs interior mutability. @@ -111,7 +111,7 @@ impl MemoryExtra { this.memory .extra .extern_statics - .insert("__cxa_thread_atexit_impl", place.ptr.assert_ptr().alloc_id) + .insert(Symbol::intern("__cxa_thread_atexit_impl"), place.ptr.assert_ptr().alloc_id) .unwrap_none(); } _ => {} // No "extern statics" supported on this platform @@ -310,11 +310,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { }; let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { - Some(name) => name.as_str(), - None => tcx.item_name(def_id).as_str(), + Some(name) => name, + None => tcx.item_name(def_id), }; // Check if we know this one. - if let Some(canonical_id) = mem.extra.extern_statics.get(&*link_name) { + if let Some(canonical_id) = mem.extra.extern_statics.get(&link_name) { trace!("canonical_alloc_id: {:?} ({}) -> {:?}", id, link_name, canonical_id); *canonical_id } else { From 92a28f8d8f139d0b6b0f8efa009fee0e72103d1e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Mar 2020 22:36:15 +0100 Subject: [PATCH 1613/5092] HashMap -> FxHashMap --- src/intptrcast.rs | 7 ++++--- src/machine.rs | 6 +++--- src/mono_hash_map.rs | 8 ++++---- src/shims/env.rs | 4 ++-- src/shims/fs.rs | 10 +++++----- src/stacked_borrows.rs | 10 +++++----- 6 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 375ebf09967d..91d9f4e84ee3 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -1,9 +1,10 @@ use std::cell::RefCell; use std::cmp::max; -use std::collections::{hash_map::Entry, HashMap}; +use std::collections::hash_map::Entry; use rand::Rng; +use rustc_data_structures::fx::FxHashMap; use rustc::ty::layout::HasDataLayout; use rustc_mir::interpret::{AllocCheck, AllocId, InterpResult, Memory, Machine, Pointer, PointerArithmetic}; use rustc_target::abi::Size; @@ -21,7 +22,7 @@ pub struct GlobalState { /// `AllocExtra` because function pointers also have a base address, and /// they do not have an `AllocExtra`. /// This is the inverse of `int_to_ptr_map`. - pub base_addr: HashMap, + pub base_addr: FxHashMap, /// This is used as a memory address when a new pointer is casted to an integer. It /// is always larger than any address that was previously made part of a block. pub next_base_addr: u64, @@ -31,7 +32,7 @@ impl Default for GlobalState { fn default() -> Self { GlobalState { int_to_ptr_map: Vec::default(), - base_addr: HashMap::default(), + base_addr: FxHashMap::default(), next_base_addr: STACK_ADDR, } } diff --git a/src/machine.rs b/src/machine.rs index c8705eb29e8c..0df567a2fa51 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -3,12 +3,12 @@ use std::borrow::Cow; use std::cell::RefCell; -use std::collections::HashMap; use std::num::NonZeroU64; use std::rc::Rc; use rand::rngs::StdRng; +use rustc_data_structures::fx::FxHashMap; use rustc::mir; use rustc::ty::{ self, @@ -75,7 +75,7 @@ pub struct MemoryExtra { pub intptrcast: intptrcast::MemoryExtra, /// Mapping extern static names to their canonical allocation. - pub(crate) extern_statics: HashMap, + pub(crate) extern_statics: FxHashMap, /// The random number generator used for resolving non-determinism. /// Needs to be queried by ptr_to_int, hence needs interior mutability. @@ -92,7 +92,7 @@ impl MemoryExtra { MemoryExtra { stacked_borrows, intptrcast: Default::default(), - extern_statics: HashMap::default(), + extern_statics: FxHashMap::default(), rng: RefCell::new(rng), } } diff --git a/src/mono_hash_map.rs b/src/mono_hash_map.rs index 124ae6876026..fc33126aa2e7 100644 --- a/src/mono_hash_map.rs +++ b/src/mono_hash_map.rs @@ -1,6 +1,6 @@ -//! This is a "monotonic `HashMap`": A `HashMap` that, when shared, can be pushed to but not +//! This is a "monotonic `FxHashMap`": A `FxHashMap` that, when shared, can be pushed to but not //! otherwise mutated. We also box items in the map. This means we can safely provide -//! shared references into existing items in the `HashMap`, because they will not be dropped +//! shared references into existing items in the `FxHashMap`, because they will not be dropped //! (from being removed) or moved (because they are boxed). //! The API is is completely tailored to what `memory.rs` needs. It is still in //! a separate file to minimize the amount of code that has to care about the unsafety. @@ -21,8 +21,8 @@ impl MonoHashMap { /// This function exists for priroda to be able to iterate over all evaluator memory. /// /// The function is somewhat roundabout with the closure argument because internally the - /// `MonoHashMap` uses a `RefCell`. When iterating over the `HashMap` inside the `RefCell`, - /// we need to keep a borrow to the `HashMap` inside the iterator. The borrow is only alive + /// `MonoHashMap` uses a `RefCell`. When iterating over the `FxHashMap` inside the `RefCell`, + /// we need to keep a borrow to the `FxHashMap` inside the iterator. The borrow is only alive /// as long as the `Ref` returned by `RefCell::borrow()` is alive. So we can't return the /// iterator, as that would drop the `Ref`. We can't return both, as it's not possible in Rust /// to have a struct/tuple with a field that refers to another field. diff --git a/src/shims/env.rs b/src/shims/env.rs index 10f749216541..79f0c5b3d902 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,10 +1,10 @@ -use std::collections::HashMap; use std::ffi::{OsString, OsStr}; use std::env; use crate::stacked_borrows::Tag; use crate::*; +use rustc_data_structures::fx::FxHashMap; use rustc::ty::layout::Size; use rustc_mir::interpret::Pointer; @@ -12,7 +12,7 @@ use rustc_mir::interpret::Pointer; pub struct EnvVars { /// Stores pointers to the environment variables. These variables must be stored as /// null-terminated C strings with the `"{name}={value}"` format. - map: HashMap>, + map: FxHashMap>, } impl EnvVars { diff --git a/src/shims/fs.rs b/src/shims/fs.rs index cc8f18af7d61..8a48518fa9bc 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1,11 +1,11 @@ use std::collections::BTreeMap; -use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; use std::fs::{read_dir, remove_dir, remove_file, rename, DirBuilder, File, FileType, OpenOptions, ReadDir}; use std::io::{Read, Seek, SeekFrom, Write}; use std::path::PathBuf; use std::time::SystemTime; +use rustc_data_structures::fx::FxHashMap; use rustc::ty::layout::{Align, LayoutOf, Size}; use crate::stacked_borrows::Tag; @@ -212,10 +212,10 @@ pub struct DirHandler { /// When opendir is called, a directory iterator is created on the host for the target /// directory, and an entry is stored in this hash map, indexed by an ID which represents /// the directory stream. When readdir is called, the directory stream ID is used to look up - /// the corresponding ReadDir iterator from this HashMap, and information from the next + /// the corresponding ReadDir iterator from this map, and information from the next /// directory entry is returned. When closedir is called, the ReadDir iterator is removed from - /// this HashMap. - streams: HashMap, + /// the map. + streams: FxHashMap, /// ID number to be used by the next call to opendir next_id: u64, } @@ -232,7 +232,7 @@ impl DirHandler { impl Default for DirHandler { fn default() -> DirHandler { DirHandler { - streams: HashMap::new(), + streams: FxHashMap::default(), // Skip 0 as an ID, because it looks like a null pointer to libc next_id: 1, } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 9a511aaed577..6188d05780cb 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -2,11 +2,11 @@ //! for further information. use std::cell::RefCell; -use std::collections::{HashMap, HashSet}; use std::fmt; use std::num::NonZeroU64; use std::rc::Rc; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc::mir::RetagKind; use rustc::ty::{self, layout::Size}; use rustc_hir::Mutability; @@ -96,11 +96,11 @@ pub struct GlobalState { /// Table storing the "base" tag for each allocation. /// The base tag is the one used for the initial pointer. /// We need this in a separate table to handle cyclic statics. - base_ptr_ids: HashMap, + base_ptr_ids: FxHashMap, /// Next unused call ID (for protectors). next_call_id: CallId, /// Those call IDs corresponding to functions that are still running. - active_calls: HashSet, + active_calls: FxHashSet, /// The id to trace in this execution run tracked_pointer_tag: Option, } @@ -153,9 +153,9 @@ impl GlobalState { pub fn new(tracked_pointer_tag: Option) -> Self { GlobalState { next_ptr_id: NonZeroU64::new(1).unwrap(), - base_ptr_ids: HashMap::default(), + base_ptr_ids: FxHashMap::default(), next_call_id: NonZeroU64::new(1).unwrap(), - active_calls: HashSet::default(), + active_calls: FxHashSet::default(), tracked_pointer_tag, } } From 58519a7a7930d4ac494d971a737525221c70f26a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 3 Mar 2020 15:00:19 +0100 Subject: [PATCH 1614/5092] try even harder to catch invalid generator fields --- tests/run-pass/generator.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/generator.rs b/tests/run-pass/generator.rs index e85d2cf8f29a..18eaf5e55c15 100644 --- a/tests/run-pass/generator.rs +++ b/tests/run-pass/generator.rs @@ -4,6 +4,8 @@ use std::ops::{GeneratorState::{self, *}, Generator}; use std::pin::Pin; use std::sync::atomic::{AtomicUsize, Ordering}; use std::fmt::Debug; +use std::mem::ManuallyDrop; +use std::ptr; fn basic() { fn finish(mut amt: usize, mut t: T) -> T::Return @@ -12,8 +14,13 @@ fn basic() { // We are not moving the `t` around until it gets dropped, so this is okay. let mut t = unsafe { Pin::new_unchecked(&mut t) }; loop { - match t.as_mut().resume(()) { - GeneratorState::Yielded(y) => amt -= y, + let state = t.as_mut().resume(()); + // Test if the generator is valid (according to type invariants). + let _ = unsafe { ManuallyDrop::new(ptr::read(t.as_mut().get_unchecked_mut())) }; + match state { + GeneratorState::Yielded(y) => { + amt -= y; + } GeneratorState::Complete(ret) => { assert_eq!(amt, 0); return ret @@ -109,6 +116,8 @@ fn smoke_resume_arg() { for (input, out) in inout { assert_eq!(gen.as_mut().resume(input), out); + // Test if the generator is valid (according to type invariants). + let _ = unsafe { ManuallyDrop::new(ptr::read(gen.as_mut().get_unchecked_mut())) }; } } From ad1f0f6e65bbcdec4bba9a130105f86b56782ef7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 4 Mar 2020 08:54:12 +0100 Subject: [PATCH 1615/5092] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 0b22c04d3050..838ec0e9a7df 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c839a7b4c26e58319b0c40448dd423facff34cd0 +4d71c164a89b705df6affd31a5262c832d1bc48d From db0d03229c54e3dead1cd8afde62e1ba9b1707bc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 4 Mar 2020 09:50:26 +0100 Subject: [PATCH 1616/5092] fix allocator tests --- tests/compile-fail/deallocate-bad-alignment.rs | 2 +- tests/compile-fail/deallocate-bad-size.rs | 2 +- tests/compile-fail/deallocate-twice.rs | 2 +- tests/compile-fail/reallocate-bad-size.rs | 2 +- tests/compile-fail/reallocate-change-alloc.rs | 2 +- tests/compile-fail/reallocate-dangling.rs | 2 +- tests/run-pass/heap_allocator.rs | 14 +++++++------- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/compile-fail/deallocate-bad-alignment.rs b/tests/compile-fail/deallocate-bad-alignment.rs index 2ac35a450cf1..876339919717 100644 --- a/tests/compile-fail/deallocate-bad-alignment.rs +++ b/tests/compile-fail/deallocate-bad-alignment.rs @@ -9,7 +9,7 @@ use std::alloc::{AllocRef, Layout}; fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap().0; Global.dealloc(x, Layout::from_size_align_unchecked(1, 2)); } } diff --git a/tests/compile-fail/deallocate-bad-size.rs b/tests/compile-fail/deallocate-bad-size.rs index c5b48f5ddf59..3b7b3cc6a726 100644 --- a/tests/compile-fail/deallocate-bad-size.rs +++ b/tests/compile-fail/deallocate-bad-size.rs @@ -9,7 +9,7 @@ use std::alloc::{AllocRef, Layout}; fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap().0; Global.dealloc(x, Layout::from_size_align_unchecked(2, 1)); } } diff --git a/tests/compile-fail/deallocate-twice.rs b/tests/compile-fail/deallocate-twice.rs index 02c442f0ab85..ee4c5dbedf90 100644 --- a/tests/compile-fail/deallocate-twice.rs +++ b/tests/compile-fail/deallocate-twice.rs @@ -9,7 +9,7 @@ use std::alloc::{AllocRef, Layout}; fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap().0; Global.dealloc(x, Layout::from_size_align_unchecked(1, 1)); Global.dealloc(x, Layout::from_size_align_unchecked(1, 1)); } diff --git a/tests/compile-fail/reallocate-bad-size.rs b/tests/compile-fail/reallocate-bad-size.rs index 905e8e061721..f7117dbb646d 100644 --- a/tests/compile-fail/reallocate-bad-size.rs +++ b/tests/compile-fail/reallocate-bad-size.rs @@ -9,7 +9,7 @@ use std::alloc::{AllocRef, Layout}; fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap().0; Global.realloc(x, Layout::from_size_align_unchecked(2, 1), 1).unwrap(); } } diff --git a/tests/compile-fail/reallocate-change-alloc.rs b/tests/compile-fail/reallocate-change-alloc.rs index 21468739b31c..df517f9c81f2 100644 --- a/tests/compile-fail/reallocate-change-alloc.rs +++ b/tests/compile-fail/reallocate-change-alloc.rs @@ -7,7 +7,7 @@ use std::alloc::{AllocRef, Layout}; fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap().0; Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1).unwrap(); let _z = *(x.as_ptr() as *mut u8); //~ ERROR dangling pointer was dereferenced } diff --git a/tests/compile-fail/reallocate-dangling.rs b/tests/compile-fail/reallocate-dangling.rs index ee73cfce8634..19a9017e71b8 100644 --- a/tests/compile-fail/reallocate-dangling.rs +++ b/tests/compile-fail/reallocate-dangling.rs @@ -9,7 +9,7 @@ use std::alloc::{AllocRef, Layout}; fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap().0; Global.dealloc(x, Layout::from_size_align_unchecked(1, 1)); Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1).unwrap(); } diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index 907fbf962df0..8077be405f4b 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -9,28 +9,28 @@ fn check_alloc(mut allocator: T) { unsafe { let layout = Layout::from_size_align(20, align).unwrap(); for _ in 0..32 { - let a = allocator.alloc(layout).unwrap(); + let a = allocator.alloc(layout).unwrap().0; assert_eq!(a.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); allocator.dealloc(a, layout); } - let p1 = allocator.alloc_zeroed(layout).unwrap(); + let p1 = allocator.alloc_zeroed(layout).unwrap().0; assert_eq!(p1.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); - let p2 = allocator.realloc(p1, layout, 40).unwrap(); + let p2 = allocator.realloc(p1, layout, 40).unwrap().0; let layout = Layout::from_size_align(40, align).unwrap(); assert_eq!(p2.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); let slice = slice::from_raw_parts(p2.as_ptr(), 20); assert_eq!(&slice, &[0_u8; 20]); // old size == new size - let p3 = allocator.realloc(p2, layout, 40).unwrap(); + let p3 = allocator.realloc(p2, layout, 40).unwrap().0; assert_eq!(p3.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); let slice = slice::from_raw_parts(p3.as_ptr(), 20); assert_eq!(&slice, &[0_u8; 20]); // old size > new size - let p4 = allocator.realloc(p3, layout, 10).unwrap(); + let p4 = allocator.realloc(p3, layout, 10).unwrap().0; let layout = Layout::from_size_align(10, align).unwrap(); assert_eq!(p4.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); let slice = slice::from_raw_parts(p4.as_ptr(), 10); @@ -46,7 +46,7 @@ fn check_align_requests(mut allocator: T) { let iterations = 32; unsafe { let pointers: Vec<_> = (0..iterations).map(|_| { - allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap() + allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap().0 }).collect(); for &ptr in &pointers { assert_eq!((ptr.as_ptr() as usize) % align, 0, @@ -67,7 +67,7 @@ fn global_to_box() { let l = Layout::new::(); // allocate manually with global allocator, then turn into Box and free there unsafe { - let ptr = Global.alloc(l).unwrap().as_ptr() as *mut T; + let ptr = Global.alloc(l).unwrap().0.as_ptr() as *mut T; let b = Box::from_raw(ptr); drop(b); } From 5c4dc072bd6f36b6929673582a423c1be7ba485c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 4 Mar 2020 10:29:00 +0100 Subject: [PATCH 1617/5092] downgrade serde_json to match rustc workspace --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 896c726b9aa6..f71fec3c2846 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ required-features = ["rustc_tests"] cargo_metadata = { version = "0.9.0", optional = true } directories = { version = "2.0", optional = true } rustc_version = { version = "0.2.3", optional = true } -serde_json = { version = "1.0.44", optional = true } +serde_json = { version = "1.0.40", optional = true } getrandom = { version = "0.1.8", features = ["std"] } byteorder = "1.3" From 148269dd4b64c21c8dfa66d5d67a48443b1aea94 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 4 Mar 2020 13:01:06 +0100 Subject: [PATCH 1618/5092] finally stop using min/max_value and the integer modules --- rust-version | 2 +- src/shims/foreign_items.rs | 8 ++++---- src/shims/fs.rs | 8 ++++---- src/shims/mod.rs | 2 +- tests/compile-fail/exact_div4.rs | 4 ++-- tests/compile-fail/ptr_offset_overflow.rs | 2 +- tests/compile-fail/slice-too-big.rs | 1 - tests/compile-fail/unchecked_div1.rs | 2 +- tests/run-pass/align_offset.rs | 6 +++--- tests/run-pass/integer-ops.rs | 11 ++++------- tests/run-pass/ints.rs | 8 ++++---- tests/run-pass/panic/overflowing-rsh-2.rs | 2 +- tests/run-pass/pointers.rs | 2 -- tests/run-pass/ptr_arith_offset_overflow.rs | 4 ++-- tests/run-pass/ptr_int_casts.rs | 2 +- tests/run-pass/u128.rs | 4 ++-- 16 files changed, 31 insertions(+), 37 deletions(-) diff --git a/rust-version b/rust-version index 838ec0e9a7df..62e7b6845d51 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4d71c164a89b705df6affd31a5262c832d1bc48d +7a3700c37132385e8e965c18e73d0a09f9146335 diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index f8b42e509133..88ebc269cf1b 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -443,10 +443,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Saturating cast to i16. Even those are outside the valid exponent range to // `scalbn` below will do its over/underflow handling. - let exp = if exp > i16::max_value() as i32 { - i16::max_value() - } else if exp < i16::min_value() as i32 { - i16::min_value() + let exp = if exp > i16::MAX as i32 { + i16::MAX + } else if exp < i16::MIN as i32 { + i16::MIN } else { exp.try_into().unwrap() }; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 8a48518fa9bc..0ea53b16fd19 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -427,15 +427,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We cap the number of read bytes to the largest value that we are able to fit in both the // host's and target's `isize`. This saves us from having to handle overflows later. - let count = count.min(this.isize_max() as u64).min(isize::max_value() as u64); + let count = count.min(this.isize_max() as u64).min(isize::MAX as u64); if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { // This can never fail because `count` was capped to be smaller than - // `isize::max_value()`. + // `isize::MAX`. let count = isize::try_from(count).unwrap(); // We want to read at most `count` bytes. We are sure that `count` is not negative // because it was a target's `usize`. Also we are sure that its smaller than - // `usize::max_value()` because it is a host's `isize`. + // `usize::MAX` because it is a host's `isize`. let mut bytes = vec![0; count as usize]; let result = file .read(&mut bytes) @@ -481,7 +481,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We cap the number of written bytes to the largest value that we are able to fit in both the // host's and target's `isize`. This saves us from having to handle overflows later. - let count = count.min(this.isize_max() as u64).min(isize::max_value() as u64); + let count = count.min(this.isize_max() as u64).min(isize::MAX as u64); if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 2889807bf76a..04379553587d 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -27,7 +27,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (dest, ret) = ret.unwrap(); let n = this .align_offset(args[0], args[1])? - .unwrap_or_else(|| this.truncate(u128::max_value(), dest.layout)); + .unwrap_or_else(|| this.truncate(u128::MAX, dest.layout)); this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; this.go_to_block(ret); return Ok(None); diff --git a/tests/compile-fail/exact_div4.rs b/tests/compile-fail/exact_div4.rs index 736d4f2516d2..c241b2df660e 100644 --- a/tests/compile-fail/exact_div4.rs +++ b/tests/compile-fail/exact_div4.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { - // divison of min_value by -1 - unsafe { std::intrinsics::exact_div(i64::min_value(), -1); } //~ ERROR result of dividing MIN by -1 cannot be represented + // divison of MIN by -1 + unsafe { std::intrinsics::exact_div(i64::MIN, -1); } //~ ERROR result of dividing MIN by -1 cannot be represented } diff --git a/tests/compile-fail/ptr_offset_overflow.rs b/tests/compile-fail/ptr_offset_overflow.rs index e52384e91967..452bf341c9e2 100644 --- a/tests/compile-fail/ptr_offset_overflow.rs +++ b/tests/compile-fail/ptr_offset_overflow.rs @@ -2,5 +2,5 @@ fn main() { let v = [1i8, 2]; let x = &v[1] as *const i8; - let _val = unsafe { x.offset(isize::min_value()) }; + let _val = unsafe { x.offset(isize::MIN) }; } diff --git a/tests/compile-fail/slice-too-big.rs b/tests/compile-fail/slice-too-big.rs index 08ab48175aed..157ea03bc932 100644 --- a/tests/compile-fail/slice-too-big.rs +++ b/tests/compile-fail/slice-too-big.rs @@ -1,5 +1,4 @@ use std::mem; -use std::usize; fn main() { unsafe { let ptr = Box::into_raw(Box::new(0u8)); diff --git a/tests/compile-fail/unchecked_div1.rs b/tests/compile-fail/unchecked_div1.rs index 1d1bbb09aa26..b42b34ff462d 100644 --- a/tests/compile-fail/unchecked_div1.rs +++ b/tests/compile-fail/unchecked_div1.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MIN/-1 cannot be represented - unsafe { std::intrinsics::unchecked_div(i16::min_value(), -1); } //~ ERROR Overflow executing `unchecked_div` + unsafe { std::intrinsics::unchecked_div(i16::MIN, -1); } //~ ERROR Overflow executing `unchecked_div` } diff --git a/tests/run-pass/align_offset.rs b/tests/run-pass/align_offset.rs index 1202fd00be15..f92163464708 100644 --- a/tests/run-pass/align_offset.rs +++ b/tests/run-pass/align_offset.rs @@ -5,15 +5,15 @@ fn test_align_offset() { assert_eq!(raw.align_offset(2), 0); assert_eq!(raw.align_offset(4), 0); - assert_eq!(raw.align_offset(8), usize::max_value()); // requested alignment higher than allocation alignment + assert_eq!(raw.align_offset(8), usize::MAX); // requested alignment higher than allocation alignment assert_eq!(raw.wrapping_offset(1).align_offset(2), 1); assert_eq!(raw.wrapping_offset(1).align_offset(4), 3); - assert_eq!(raw.wrapping_offset(1).align_offset(8), usize::max_value()); // requested alignment higher than allocation alignment + assert_eq!(raw.wrapping_offset(1).align_offset(8), usize::MAX); // requested alignment higher than allocation alignment assert_eq!(raw.wrapping_offset(2).align_offset(2), 0); assert_eq!(raw.wrapping_offset(2).align_offset(4), 2); - assert_eq!(raw.wrapping_offset(2).align_offset(8), usize::max_value()); // requested alignment higher than allocation alignment + assert_eq!(raw.wrapping_offset(2).align_offset(8), usize::MAX); // requested alignment higher than allocation alignment } fn test_align_to() { diff --git a/tests/run-pass/integer-ops.rs b/tests/run-pass/integer-ops.rs index 0264099eb68d..4ae42df59200 100644 --- a/tests/run-pass/integer-ops.rs +++ b/tests/run-pass/integer-ops.rs @@ -8,16 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::i32; - pub fn main() { // This tests that do (not) do sign extension properly when loading integers - assert_eq!(u32::max_value() as i64, 4294967295); - assert_eq!(i32::min_value() as i64, -2147483648); + assert_eq!(u32::MAX as i64, 4294967295); + assert_eq!(i32::MIN as i64, -2147483648); - assert_eq!(i8::min_value(), -128); - - assert_eq!(i8::max_value(), 127); + assert_eq!(i8::MAX, 127); + assert_eq!(i8::MIN, -128); assert_eq!(i32::from_str_radix("A", 16), Ok(10)); diff --git a/tests/run-pass/ints.rs b/tests/run-pass/ints.rs index 00ca2aa41dd3..5d7c383088de 100644 --- a/tests/run-pass/ints.rs +++ b/tests/run-pass/ints.rs @@ -51,8 +51,8 @@ fn main() { assert_eq!(arith(), 5*5); assert_eq!(match_int(), 20); assert_eq!(match_int_range(), 4); - assert_eq!(i64::min_value().overflowing_mul(-1), (i64::min_value(), true)); - assert_eq!(i32::min_value().overflowing_mul(-1), (i32::min_value(), true)); - assert_eq!(i16::min_value().overflowing_mul(-1), (i16::min_value(), true)); - assert_eq!(i8::min_value().overflowing_mul(-1), (i8::min_value(), true)); + assert_eq!(i64::MIN.overflowing_mul(-1), (i64::MIN, true)); + assert_eq!(i32::MIN.overflowing_mul(-1), (i32::MIN, true)); + assert_eq!(i16::MIN.overflowing_mul(-1), (i16::MIN, true)); + assert_eq!(i8::MIN.overflowing_mul(-1), (i8::MIN, true)); } diff --git a/tests/run-pass/panic/overflowing-rsh-2.rs b/tests/run-pass/panic/overflowing-rsh-2.rs index da77a46a805e..27cc65fa7685 100644 --- a/tests/run-pass/panic/overflowing-rsh-2.rs +++ b/tests/run-pass/panic/overflowing-rsh-2.rs @@ -3,5 +3,5 @@ fn main() { // Make sure we catch overflows that would be hidden by first casting the RHS to u32 - let _n = 1i64 >> (u32::max_value() as i64 + 1); + let _n = 1i64 >> (u32::MAX as i64 + 1); } diff --git a/tests/run-pass/pointers.rs b/tests/run-pass/pointers.rs index e0847de97ba9..5bf60c32541d 100644 --- a/tests/run-pass/pointers.rs +++ b/tests/run-pass/pointers.rs @@ -1,5 +1,3 @@ -use std::usize; - fn one_line_ref() -> i16 { *&1 } diff --git a/tests/run-pass/ptr_arith_offset_overflow.rs b/tests/run-pass/ptr_arith_offset_overflow.rs index 56fd448b0cc2..fdd980e2177b 100644 --- a/tests/run-pass/ptr_arith_offset_overflow.rs +++ b/tests/run-pass/ptr_arith_offset_overflow.rs @@ -5,8 +5,8 @@ fn main() { let x = &mut ptr::null(); // going through memory as there are more sanity checks along that path *x = v.as_ptr().wrapping_offset(1); // ptr to the 2nd element // Adding 2*isize::max and then 1 is like substracting 1 - *x = x.wrapping_offset(isize::max_value()); - *x = x.wrapping_offset(isize::max_value()); + *x = x.wrapping_offset(isize::MAX); + *x = x.wrapping_offset(isize::MAX); *x = x.wrapping_offset(1); assert_eq!(unsafe { **x }, 1); } diff --git a/tests/run-pass/ptr_int_casts.rs b/tests/run-pass/ptr_int_casts.rs index c279024f35ea..468b37af5bea 100644 --- a/tests/run-pass/ptr_int_casts.rs +++ b/tests/run-pass/ptr_int_casts.rs @@ -16,7 +16,7 @@ fn main() { // this used to trigger an ICE on 32bit) let val = &mut ptr::null(); *val = (1 as *const u8).wrapping_offset(-4); - assert_eq!(*val as usize, usize::max_value() - 2); + assert_eq!(*val as usize, usize::MAX - 2); { // ptr-int-ptr let x = 13; diff --git a/tests/run-pass/u128.rs b/tests/run-pass/u128.rs index 5a5d7c1f9442..a2ca7746b1c0 100644 --- a/tests/run-pass/u128.rs +++ b/tests/run-pass/u128.rs @@ -48,14 +48,14 @@ fn main() { assert_eq!("10000000000000000000000000000000000000000000000000000000000000000000", format!("{:b}", j)); assert_eq!("340282366920938463463374607431768211455", - format!("{}", u128::max_value())); + format!("{}", u128::MAX)); assert_eq!("147573952589676412928", format!("{:?}", j)); // common traits assert_eq!(x, b(x.clone())); // overflow checks assert_eq!((z).checked_mul(z), Some(0x734C_C2F2_A521)); assert_eq!((k).checked_mul(k), None); - let l: u128 = b(u128::max_value() - 10); + let l: u128 = b(u128::MAX - 10); let o: u128 = b(17); assert_eq!(l.checked_add(b(11)), None); assert_eq!(l.checked_sub(l), Some(0)); From d82d7013600a9f0ce6ffb74aed0a0701bdeccd79 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 6 Mar 2020 09:06:23 +0100 Subject: [PATCH 1619/5092] add option to track a particular AllocId (does nothing yet) --- benches/helpers/miri_helper.rs | 11 +---------- src/bin/miri-rustc-tests.rs | 22 ++-------------------- src/bin/miri.rs | 13 +++++++++++++ src/eval.rs | 19 +++++++++++++++++++ src/machine.rs | 9 +++++++-- 5 files changed, 42 insertions(+), 32 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 2483f2de3a86..b478a7d23eb9 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -29,16 +29,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { tcx.entry_fn(LOCAL_CRATE).expect("no main or start function found"); self.bencher.iter(|| { - let config = miri::MiriConfig { - validate: true, - stacked_borrows: true, - communicate: false, - ignore_leaks: false, - excluded_env_vars: vec![], - args: vec![], - seed: None, - tracked_pointer_tag: None, - }; + let config = miri::MiriConfig::default(); eval_main(tcx, entry_def_id, config); }); }); diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 9cc9901a9134..509a1592152d 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -46,16 +46,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { .iter() .any(|attr| attr.check_name(rustc_span::symbol::sym::test)) { - let config = MiriConfig { - validate: true, - stacked_borrows: true, - communicate: false, - ignore_leaks: false, - excluded_env_vars: vec![], - args: vec![], - seed: None, - tracked_pointer_tag: None, - }; + let config = MiriConfig::default(); let did = self.0.hir().body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); miri::eval_main(self.0, did, config); @@ -68,16 +59,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { } tcx.hir().krate().visit_all_item_likes(&mut Visitor(tcx)); } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { - let config = MiriConfig { - validate: true, - stacked_borrows: true, - communicate: false, - ignore_leaks: false, - excluded_env_vars: vec![], - args: vec![], - seed: None, - tracked_pointer_tag: None, - }; + let config = MiriConfig::default(); miri::eval_main(tcx, entry_def_id, config); compiler.session().abort_if_errors(); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index e69e7f7b6f50..d2709643237f 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -135,6 +135,7 @@ fn main() { let mut ignore_leaks = false; let mut seed: Option = None; let mut tracked_pointer_tag: Option = None; + let mut tracked_alloc_id: Option = None; let mut rustc_args = vec![]; let mut miri_args = vec![]; let mut after_dashdash = false; @@ -206,6 +207,17 @@ fn main() { panic!("-Zmiri-track-pointer-tag must be a nonzero id"); } } + arg if arg.starts_with("-Zmiri-track-alloc-id=") => { + let id: u64 = match arg.trim_start_matches("-Zmiri-track-alloc-id=").parse() + { + Ok(id) => id, + Err(err) => panic!( + "-Zmiri-track-alloc-id requires a valid `u64` as the argument: {}", + err + ), + }; + tracked_alloc_id = Some(miri::AllocId(id)); + } _ => { rustc_args.push(arg); } @@ -240,6 +252,7 @@ fn main() { seed, args: miri_args, tracked_pointer_tag, + tracked_alloc_id, }; rustc_driver::install_ice_hook(); let result = rustc_driver::catch_fatal_errors(move || { diff --git a/src/eval.rs b/src/eval.rs index 267b79d0eba7..1981a8d1e03e 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -30,6 +30,24 @@ pub struct MiriConfig { pub seed: Option, /// The stacked borrow id to report about pub tracked_pointer_tag: Option, + /// The allocation id to report about. + pub tracked_alloc_id: Option, +} + +impl Default for MiriConfig { + fn default() -> MiriConfig { + MiriConfig { + validate: true, + stacked_borrows: true, + communicate: false, + ignore_leaks: false, + excluded_env_vars: vec![], + args: vec![], + seed: None, + tracked_pointer_tag: None, + tracked_alloc_id: None, + } + } } /// Details of premature program termination. @@ -55,6 +73,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.stacked_borrows, config.tracked_pointer_tag, + config.tracked_alloc_id, ), ); // Complete initialization. diff --git a/src/machine.rs b/src/machine.rs index 0df567a2fa51..07885148e1fd 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -75,15 +75,19 @@ pub struct MemoryExtra { pub intptrcast: intptrcast::MemoryExtra, /// Mapping extern static names to their canonical allocation. - pub(crate) extern_statics: FxHashMap, + extern_statics: FxHashMap, /// The random number generator used for resolving non-determinism. /// Needs to be queried by ptr_to_int, hence needs interior mutability. pub(crate) rng: RefCell, + + /// An allocation ID to report when it is being allocated + /// (helps for debugging memory leaks). + tracked_alloc_id: Option, } impl MemoryExtra { - pub fn new(rng: StdRng, stacked_borrows: bool, tracked_pointer_tag: Option) -> Self { + pub fn new(rng: StdRng, stacked_borrows: bool, tracked_pointer_tag: Option, tracked_alloc_id: Option) -> Self { let stacked_borrows = if stacked_borrows { Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(tracked_pointer_tag)))) } else { @@ -94,6 +98,7 @@ impl MemoryExtra { intptrcast: Default::default(), extern_statics: FxHashMap::default(), rng: RefCell::new(rng), + tracked_alloc_id, } } From ade4c4e7331fcff40643c1666ca89078b84b125a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 6 Mar 2020 09:11:41 +0100 Subject: [PATCH 1620/5092] make the new option actually do something --- README.md | 2 ++ src/diagnostics.rs | 6 +++++- src/machine.rs | 4 ++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f18a5d668c39..839facef0962 100644 --- a/README.md +++ b/README.md @@ -180,6 +180,8 @@ Several `-Z` flags are relevant for Miri: is popped from a borrow stack (which is where the tag becomes invalid and any future use of it will error). This helps you in finding out why UB is happening and where in your code would be a good place to look for it. +* `-Zmiri-track-alloc-id=` shows a backtrace when the given allocation is + being allocated. This helps in debugging memory leaks. Moreover, Miri recognizes some environment variables: diff --git a/src/diagnostics.rs b/src/diagnostics.rs index e68dfad1b9fa..fb6598495af5 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -6,6 +6,7 @@ use crate::*; /// Miri specific diagnostics pub enum NonHaltingDiagnostic { PoppedTrackedPointerTag(Item), + CreatedAlloc(AllocId), } /// Emit a custom diagnostic without going through the miri-engine machinery @@ -97,9 +98,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); DIAGNOSTICS.with(|diagnostics| { for e in diagnostics.borrow_mut().drain(..) { + use NonHaltingDiagnostic::*; let msg = match e { - NonHaltingDiagnostic::PoppedTrackedPointerTag(item) => + PoppedTrackedPointerTag(item) => format!("popped tracked tag for item {:?}", item), + CreatedAlloc(AllocId(id)) => + format!("created allocation with id {}", id), }; report_msg(this, msg, false); } diff --git a/src/machine.rs b/src/machine.rs index 07885148e1fd..d15e290cbfdc 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -334,6 +334,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { alloc: Cow<'b, Allocation>, kind: Option>, ) -> (Cow<'b, Allocation>, Self::PointerTag) { + if Some(id) == memory_extra.tracked_alloc_id { + register_diagnostic(NonHaltingDiagnostic::CreatedAlloc(id)); + } + let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); let (stacks, base_tag) = From 6670f43917db0df610401f50dc62c5d262c496b0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 6 Mar 2020 10:46:12 +0100 Subject: [PATCH 1621/5092] README: add another bug Miri found --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f18a5d668c39..3a7d92e906c1 100644 --- a/README.md +++ b/README.md @@ -245,6 +245,7 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [`BTreeMap` creating mutable references that overlap with shared references](https://github.com/rust-lang/rust/pull/58431) * [`LinkedList` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/60072) * [`Vec::push` invalidating existing references into the vector](https://github.com/rust-lang/rust/issues/60847) +* [`align_to_mut` violating uniqueness of mutable references](https://github.com/rust-lang/rust/issues/68549) ## License From d13fe01f824f9a58f94058948e57f4d8c6365866 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 4 Mar 2020 12:15:14 -0500 Subject: [PATCH 1622/5092] add working shim for environ --- src/eval.rs | 2 +- src/machine.rs | 14 ++++++++++++++ src/shims/env.rs | 15 +++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/eval.rs b/src/eval.rs index 1981a8d1e03e..dacd996c4a6e 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -77,8 +77,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ), ); // Complete initialization. - MemoryExtra::init_extern_statics(&mut ecx)?; EnvVars::init(&mut ecx, config.excluded_env_vars); + MemoryExtra::init_extern_statics(&mut ecx)?; // Setup first stack-frame let main_instance = ty::Instance::mono(tcx, main_id); diff --git a/src/machine.rs b/src/machine.rs index d15e290cbfdc..0e3cc58df736 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -84,6 +84,9 @@ pub struct MemoryExtra { /// An allocation ID to report when it is being allocated /// (helps for debugging memory leaks). tracked_alloc_id: Option, + + /// The `AllocId` for the `environ` static. + pub(crate) environ: Option>, } impl MemoryExtra { @@ -99,6 +102,7 @@ impl MemoryExtra { extern_statics: FxHashMap::default(), rng: RefCell::new(rng), tracked_alloc_id, + environ: None, } } @@ -118,6 +122,16 @@ impl MemoryExtra { .extern_statics .insert(Symbol::intern("__cxa_thread_atexit_impl"), place.ptr.assert_ptr().alloc_id) .unwrap_none(); + + // "environ" + let layout = this.layout_of(this.tcx.types.usize)?; + let place = this.allocate(layout, MiriMemoryKind::Machine.into()); + this.write_scalar(this.memory.extra.environ.unwrap(), place.into())?; + this.memory + .extra + .extern_statics + .insert(Symbol::intern("environ"), place.ptr.assert_ptr().alloc_id) + .unwrap_none(); } _ => {} // No "extern statics" supported on this platform } diff --git a/src/shims/env.rs b/src/shims/env.rs index 79f0c5b3d902..833fef69f28f 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -2,6 +2,7 @@ use std::ffi::{OsString, OsStr}; use std::env; use crate::stacked_borrows::Tag; +use crate::rustc_target::abi::LayoutOf; use crate::*; use rustc_data_structures::fx::FxHashMap; @@ -20,15 +21,29 @@ impl EnvVars { ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, excluded_env_vars: Vec, ) { + let mut vars = Vec::new(); if ecx.machine.communicate { for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { let var_ptr = alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx); ecx.machine.env_vars.map.insert(OsString::from(name), var_ptr); + vars.push(var_ptr.into()); } } } + // Add the trailing null pointer + vars.push(Scalar::from_int(0, ecx.pointer_size())); + // Make an array with all these pointers inside Miri. + let tcx = ecx.tcx; + let environ_layout = + ecx.layout_of(tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), vars.len() as u64)).unwrap(); + let environ_place = ecx.allocate(environ_layout, MiriMemoryKind::Machine.into()); + for (idx, var) in vars.into_iter().enumerate() { + let place = ecx.mplace_field(environ_place, idx as u64).unwrap(); + ecx.write_scalar(var, place.into()).unwrap(); + } + ecx.memory.extra.environ = Some(environ_place.ptr.into()); } } From 4f5fdc581014ecb17a9aa14ada2a2f186c9a46a8 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 4 Mar 2020 13:24:01 -0500 Subject: [PATCH 1623/5092] update the environ shim when environment changes --- src/eval.rs | 2 +- src/machine.rs | 19 ++++++++++--------- src/shims/env.rs | 41 +++++++++++++++++++++++++++-------------- 3 files changed, 38 insertions(+), 24 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index dacd996c4a6e..1981a8d1e03e 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -77,8 +77,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ), ); // Complete initialization. - EnvVars::init(&mut ecx, config.excluded_env_vars); MemoryExtra::init_extern_statics(&mut ecx)?; + EnvVars::init(&mut ecx, config.excluded_env_vars); // Setup first stack-frame let main_instance = ty::Instance::mono(tcx, main_id); diff --git a/src/machine.rs b/src/machine.rs index 0e3cc58df736..ece4b62d3af1 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -70,7 +70,7 @@ pub struct AllocExtra { /// Extra global memory data #[derive(Clone, Debug)] -pub struct MemoryExtra { +pub struct MemoryExtra<'tcx> { pub stacked_borrows: Option, pub intptrcast: intptrcast::MemoryExtra, @@ -85,11 +85,11 @@ pub struct MemoryExtra { /// (helps for debugging memory leaks). tracked_alloc_id: Option, - /// The `AllocId` for the `environ` static. - pub(crate) environ: Option>, + /// Place where the `environ` static is stored. + pub(crate) environ: Option>, } -impl MemoryExtra { +impl<'tcx> MemoryExtra<'tcx> { pub fn new(rng: StdRng, stacked_borrows: bool, tracked_pointer_tag: Option, tracked_alloc_id: Option) -> Self { let stacked_borrows = if stacked_borrows { Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(tracked_pointer_tag)))) @@ -107,7 +107,7 @@ impl MemoryExtra { } /// Sets up the "extern statics" for this machine. - pub fn init_extern_statics<'mir, 'tcx>( + pub fn init_extern_statics<'mir>( this: &mut MiriEvalContext<'mir, 'tcx>, ) -> InterpResult<'tcx> { match this.tcx.sess.target.target.target_os.as_str() { @@ -126,12 +126,13 @@ impl MemoryExtra { // "environ" let layout = this.layout_of(this.tcx.types.usize)?; let place = this.allocate(layout, MiriMemoryKind::Machine.into()); - this.write_scalar(this.memory.extra.environ.unwrap(), place.into())?; + this.write_scalar(Scalar::from_machine_usize(0, &*this.tcx), place.into())?; this.memory .extra .extern_statics .insert(Symbol::intern("environ"), place.ptr.assert_ptr().alloc_id) .unwrap_none(); + this.memory.extra.environ = Some(place); } _ => {} // No "extern statics" supported on this platform } @@ -217,7 +218,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryKinds = MiriMemoryKind; type FrameExtra = FrameData<'tcx>; - type MemoryExtra = MemoryExtra; + type MemoryExtra = MemoryExtra<'tcx>; type AllocExtra = AllocExtra; type PointerTag = Tag; type ExtraFnVal = Dlsym; @@ -343,7 +344,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } fn init_allocation_extra<'b>( - memory_extra: &MemoryExtra, + memory_extra: &MemoryExtra<'tcx>, id: AllocId, alloc: Cow<'b, Allocation>, kind: Option>, @@ -380,7 +381,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } #[inline(always)] - fn tag_static_base_pointer(memory_extra: &MemoryExtra, id: AllocId) -> Self::PointerTag { + fn tag_static_base_pointer(memory_extra: &MemoryExtra<'tcx>, id: AllocId) -> Self::PointerTag { if let Some(stacked_borrows) = memory_extra.stacked_borrows.as_ref() { stacked_borrows.borrow_mut().static_base_ptr(id) } else { diff --git a/src/shims/env.rs b/src/shims/env.rs index 833fef69f28f..05c098bc4e72 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -21,29 +21,16 @@ impl EnvVars { ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, excluded_env_vars: Vec, ) { - let mut vars = Vec::new(); if ecx.machine.communicate { for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { let var_ptr = alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx); ecx.machine.env_vars.map.insert(OsString::from(name), var_ptr); - vars.push(var_ptr.into()); } } } - // Add the trailing null pointer - vars.push(Scalar::from_int(0, ecx.pointer_size())); - // Make an array with all these pointers inside Miri. - let tcx = ecx.tcx; - let environ_layout = - ecx.layout_of(tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), vars.len() as u64)).unwrap(); - let environ_place = ecx.allocate(environ_layout, MiriMemoryKind::Machine.into()); - for (idx, var) in vars.into_iter().enumerate() { - let place = ecx.mplace_field(environ_place, idx as u64).unwrap(); - ecx.write_scalar(var, place.into()).unwrap(); - } - ecx.memory.extra.environ = Some(environ_place.ptr.into()); + ecx.update_environ().unwrap(); } } @@ -94,6 +81,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some((name, value)) = new { let var_ptr = alloc_env_var_as_c_str(&name, &value, &mut this); if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), var_ptr) { + this.update_environ()?; this.memory .deallocate(var, None, MiriMemoryKind::Machine.into())?; } @@ -112,6 +100,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name = this.read_os_str_from_c_str(name_ptr)?.to_owned(); if !name.is_empty() && !name.to_string_lossy().contains('=') { success = Some(this.machine.env_vars.map.remove(&name)); + this.update_environ()?; } } if let Some(old) = success { @@ -165,4 +154,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } + + fn update_environ(&mut self) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + // Collect all the pointers to each variable in a vector. + let mut vars: Vec> = this.machine.env_vars.map.values().map(|&ptr| ptr.into()).collect(); + // Add the trailing null pointer. + vars.push(Scalar::from_int(0, this.pointer_size())); + // Make an array with all these pointers inside Miri. + let tcx = this.tcx; + let vars_layout = + this.layout_of(tcx.mk_array(tcx.types.usize, vars.len() as u64))?; + let vars_place = this.allocate(vars_layout, MiriMemoryKind::Machine.into()); + for (idx, var) in vars.into_iter().enumerate() { + let place = this.mplace_field(vars_place, idx as u64)?; + this.write_scalar(var, place.into())?; + } + + this.write_scalar( + vars_place.ptr, + this.memory.extra.environ.unwrap().into(), + )?; + + Ok(()) + } } From a28330febb07e46b5f5bc73356eb4b36b549c51e Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 5 Mar 2020 09:41:35 -0500 Subject: [PATCH 1624/5092] add testcase for `environ` shim --- tests/run-pass/env.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/run-pass/env.rs b/tests/run-pass/env.rs index faf947420347..0b7ee8adc1a7 100644 --- a/tests/run-pass/env.rs +++ b/tests/run-pass/env.rs @@ -8,4 +8,6 @@ fn main() { assert_eq!(env::var("MIRI_TEST"), Ok("the answer".to_owned())); // Test that miri environment is isolated when communication is disabled. assert!(env::var("MIRI_ENV_VAR_TEST").is_err()); + // Test that the new variable is in the `std::env::Vars` iterator + assert!(env::vars().any(|(name, value)| name == "MIRI_TEST")) } From 7882dfb3f599df93d1e0d0a643e41072c6bf5683 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 5 Mar 2020 23:25:55 +0100 Subject: [PATCH 1625/5092] fix env update, and expand test --- src/shims/env.rs | 4 ++-- tests/run-pass/env.rs | 23 +++++++++++++++++++---- tests/run-pass/env.stdout | 14 ++++++++++++++ 3 files changed, 35 insertions(+), 6 deletions(-) create mode 100644 tests/run-pass/env.stdout diff --git a/src/shims/env.rs b/src/shims/env.rs index 05c098bc4e72..3469beb971d6 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -81,10 +81,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some((name, value)) = new { let var_ptr = alloc_env_var_as_c_str(&name, &value, &mut this); if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), var_ptr) { - this.update_environ()?; this.memory .deallocate(var, None, MiriMemoryKind::Machine.into())?; } + this.update_environ()?; Ok(0) } else { Ok(-1) @@ -100,7 +100,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name = this.read_os_str_from_c_str(name_ptr)?.to_owned(); if !name.is_empty() && !name.to_string_lossy().contains('=') { success = Some(this.machine.env_vars.map.remove(&name)); - this.update_environ()?; } } if let Some(old) = success { @@ -108,6 +107,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.memory .deallocate(var, None, MiriMemoryKind::Machine.into())?; } + this.update_environ()?; Ok(0) } else { Ok(-1) diff --git a/tests/run-pass/env.rs b/tests/run-pass/env.rs index 0b7ee8adc1a7..c7506b23c1da 100644 --- a/tests/run-pass/env.rs +++ b/tests/run-pass/env.rs @@ -3,11 +3,26 @@ use std::env; fn main() { + // Test that miri environment is isolated when communication is disabled. + // (`MIRI_ENV_VAR_TEST` is set by the test harness.) + assert_eq!(env::var("MIRI_ENV_VAR_TEST"), Err(env::VarError::NotPresent)); + + // Test base state. + println!("{:#?}", env::vars().collect::>()); assert_eq!(env::var("MIRI_TEST"), Err(env::VarError::NotPresent)); + + // Set the variable. env::set_var("MIRI_TEST", "the answer"); assert_eq!(env::var("MIRI_TEST"), Ok("the answer".to_owned())); - // Test that miri environment is isolated when communication is disabled. - assert!(env::var("MIRI_ENV_VAR_TEST").is_err()); - // Test that the new variable is in the `std::env::Vars` iterator - assert!(env::vars().any(|(name, value)| name == "MIRI_TEST")) + println!("{:#?}", env::vars().collect::>()); + + // Change the variable. + env::set_var("MIRI_TEST", "42"); + assert_eq!(env::var("MIRI_TEST"), Ok("42".to_owned())); + println!("{:#?}", env::vars().collect::>()); + + // Remove the variable. + env::remove_var("MIRI_TEST"); + assert_eq!(env::var("MIRI_TEST"), Err(env::VarError::NotPresent)); + println!("{:#?}", env::vars().collect::>()); } diff --git a/tests/run-pass/env.stdout b/tests/run-pass/env.stdout new file mode 100644 index 000000000000..9a8f979598eb --- /dev/null +++ b/tests/run-pass/env.stdout @@ -0,0 +1,14 @@ +[] +[ + ( + "MIRI_TEST", + "the answer", + ), +] +[ + ( + "MIRI_TEST", + "42", + ), +] +[] From fefa8e53440cddf4acaa592184a513b7d9b9ce2e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 6 Mar 2020 14:28:34 +0100 Subject: [PATCH 1626/5092] expand clock and fs tests a bit --- tests/run-pass/clock.rs | 8 +++++++- tests/run-pass/fs.rs | 6 +++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/clock.rs b/tests/run-pass/clock.rs index 23f45f91ada1..b4c3fa08fdc6 100644 --- a/tests/run-pass/clock.rs +++ b/tests/run-pass/clock.rs @@ -4,5 +4,11 @@ use std::time::SystemTime; fn main() { - let _now = SystemTime::now(); + let now1 = SystemTime::now(); + + // Do some work to make time pass. + for _ in 0..10 { drop(vec![42]); } + + let now2 = SystemTime::now(); + assert!(now2 > now1); } diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index f859f934bdd1..0f3512b36605 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -215,9 +215,13 @@ fn test_directory() { // Clean up the files in the directory remove_file(&path_1).unwrap(); remove_file(&path_2).unwrap(); + // Now there should be nothing left in the directory. + let dir_iter = read_dir(&dir_path).unwrap(); + let file_names = dir_iter.map(|e| e.unwrap().file_name()).collect::>(); + assert!(file_names.is_empty()); // Deleting the directory should succeed. remove_dir(&dir_path).unwrap(); - // Reading the metadata of a non-existent file should fail with a "not found" error. + // Reading the metadata of a non-existent directory should fail with a "not found" error. assert_eq!(ErrorKind::NotFound, check_metadata(&[], &dir_path).unwrap_err().kind()); } From aedc34c6e5ee8d675212bb60d54e1394e9ee9964 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 6 Mar 2020 09:38:16 -0500 Subject: [PATCH 1627/5092] deallocate old environ --- src/machine.rs | 2 +- src/shims/env.rs | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index ece4b62d3af1..188001c170ab 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -85,7 +85,7 @@ pub struct MemoryExtra<'tcx> { /// (helps for debugging memory leaks). tracked_alloc_id: Option, - /// Place where the `environ` static is stored. + /// Place where the `environ` static is stored. Its value should not change after initialization. pub(crate) environ: Option>, } diff --git a/src/shims/env.rs b/src/shims/env.rs index 3469beb971d6..0408741cf2a6 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -155,8 +155,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + /// Updates the `environ` static. It should not be called before + /// `MemoryExtra::init_extern_statics`. fn update_environ(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + // Deallocate the old environ value. + let old_vars_ptr = this.read_scalar(this.memory.extra.environ.unwrap().into())?.not_undef()?; + // The pointer itself can be null because `MemoryExtra::init_extern_statics` only + // initializes the place for the static but not the static itself. + if !this.is_null(old_vars_ptr)? { + this.memory.deallocate(this.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Machine.into())?; + } // Collect all the pointers to each variable in a vector. let mut vars: Vec> = this.machine.env_vars.map.values().map(|&ptr| ptr.into()).collect(); // Add the trailing null pointer. @@ -170,7 +179,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let place = this.mplace_field(vars_place, idx as u64)?; this.write_scalar(var, place.into())?; } - this.write_scalar( vars_place.ptr, this.memory.extra.environ.unwrap().into(), From 6eccc809f21c11f583ec237dffdbebc7e6b66038 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 7 Mar 2020 09:26:04 -0500 Subject: [PATCH 1628/5092] test that `environ` gets deallocated on changes --- tests/compile-fail/environ-gets-deallocated.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 tests/compile-fail/environ-gets-deallocated.rs diff --git a/tests/compile-fail/environ-gets-deallocated.rs b/tests/compile-fail/environ-gets-deallocated.rs new file mode 100644 index 000000000000..014c8c431e7f --- /dev/null +++ b/tests/compile-fail/environ-gets-deallocated.rs @@ -0,0 +1,10 @@ +extern "C" { + static environ: *const *const u8; +} + +fn main() { + let pointer = unsafe { environ }; + let _x = unsafe { *pointer }; + std::env::set_var("FOO", "BAR"); + let _y = unsafe { *pointer }; //~ ERROR dangling pointer was dereferenced +} From e31b8b3342f4fc97198609f5e7e13e484969c8b1 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 7 Mar 2020 09:39:44 -0500 Subject: [PATCH 1629/5092] add `_NSGetEnviron` foreign function for macos --- src/machine.rs | 28 ++++++++++++++------------ src/shims/foreign_items/posix/macos.rs | 5 ++++- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 188001c170ab..5a50a76dfb9f 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -110,19 +110,21 @@ impl<'tcx> MemoryExtra<'tcx> { pub fn init_extern_statics<'mir>( this: &mut MiriEvalContext<'mir, 'tcx>, ) -> InterpResult<'tcx> { - match this.tcx.sess.target.target.target_os.as_str() { - "linux" => { - // "__cxa_thread_atexit_impl" - // This should be all-zero, pointer-sized. - let layout = this.layout_of(this.tcx.types.usize)?; - let place = this.allocate(layout, MiriMemoryKind::Machine.into()); - this.write_scalar(Scalar::from_machine_usize(0, &*this.tcx), place.into())?; - this.memory - .extra - .extern_statics - .insert(Symbol::intern("__cxa_thread_atexit_impl"), place.ptr.assert_ptr().alloc_id) - .unwrap_none(); - + let target_os = this.tcx.sess.target.target.target_os.as_str(); + match target_os { + "linux" | "macos" => { + if target_os == "linux" { + // "__cxa_thread_atexit_impl" + // This should be all-zero, pointer-sized. + let layout = this.layout_of(this.tcx.types.usize)?; + let place = this.allocate(layout, MiriMemoryKind::Machine.into()); + this.write_scalar(Scalar::from_machine_usize(0, &*this.tcx), place.into())?; + this.memory + .extra + .extern_statics + .insert(Symbol::intern("__cxa_thread_atexit_impl"), place.ptr.assert_ptr().alloc_id) + .unwrap_none(); + } // "environ" let layout = this.layout_of(this.tcx.types.usize)?; let place = this.allocate(layout, MiriMemoryKind::Machine.into()); diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index cb6cd9ba44b4..d167191279eb 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -41,7 +41,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.macos_fstat(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - + // Environment related shims + "_NSGetEnviron" => { + this.write_scalar(this.memory.extra.environ.unwrap().ptr, dest)?; + } // The only reason this is not in the `posix` module is because the `linux` item has a // different name. "opendir$INODE64" => { From 18a71ef7b36fa8ed2031b69e414261e086fd711c Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 7 Mar 2020 11:35:00 -0500 Subject: [PATCH 1630/5092] minor corrections --- src/eval.rs | 2 +- src/machine.rs | 2 +- src/shims/env.rs | 4 ++-- tests/compile-fail/environ-gets-deallocated.rs | 18 ++++++++++++++++-- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 1981a8d1e03e..13b55a93f216 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -78,7 +78,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ); // Complete initialization. MemoryExtra::init_extern_statics(&mut ecx)?; - EnvVars::init(&mut ecx, config.excluded_env_vars); + EnvVars::init(&mut ecx, config.excluded_env_vars)?; // Setup first stack-frame let main_instance = ty::Instance::mono(tcx, main_id); diff --git a/src/machine.rs b/src/machine.rs index 5a50a76dfb9f..0f0c44300108 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -85,7 +85,7 @@ pub struct MemoryExtra<'tcx> { /// (helps for debugging memory leaks). tracked_alloc_id: Option, - /// Place where the `environ` static is stored. Its value should not change after initialization. + /// Place where the `environ` static is stored. Lazily initialized, but then never changes. pub(crate) environ: Option>, } diff --git a/src/shims/env.rs b/src/shims/env.rs index 0408741cf2a6..1962ca026ccc 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -20,7 +20,7 @@ impl EnvVars { pub(crate) fn init<'mir, 'tcx>( ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, excluded_env_vars: Vec, - ) { + ) -> InterpResult<'tcx> { if ecx.machine.communicate { for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { @@ -30,7 +30,7 @@ impl EnvVars { } } } - ecx.update_environ().unwrap(); + ecx.update_environ() } } diff --git a/tests/compile-fail/environ-gets-deallocated.rs b/tests/compile-fail/environ-gets-deallocated.rs index 014c8c431e7f..a3d82a884213 100644 --- a/tests/compile-fail/environ-gets-deallocated.rs +++ b/tests/compile-fail/environ-gets-deallocated.rs @@ -1,9 +1,23 @@ -extern "C" { +//ignore-windows: TODO env var emulation stubbed out on Windows + +#[cfg(target_os="linux")] +fn get_environ() -> *const *const u8 { + extern "C" { static environ: *const *const u8; + } + environ +} + +#[cfg(target_os="macos")] +fn get_environ() -> *const *const u8 { + extern "C" { + fn _NSGetEnviron() -> *mut *const *const u8; + } + unsafe { *_NSGetEnviron() } } fn main() { - let pointer = unsafe { environ }; + let pointer = get_environ(); let _x = unsafe { *pointer }; std::env::set_var("FOO", "BAR"); let _y = unsafe { *pointer }; //~ ERROR dangling pointer was dereferenced From 6fd3c9174c7ad518bfa7f4646477cf5606209474 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sun, 8 Mar 2020 14:31:57 +0100 Subject: [PATCH 1631/5092] rm custom `intrinsics::discriminant_value` --- src/shims/intrinsics.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 9cae97a4060c..44283364a986 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -248,12 +248,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - "discriminant_value" => { - let place = this.deref_operand(args[0])?; - let discr_val = this.read_discriminant(place.into())?.0; - this.write_scalar(Scalar::from_uint(discr_val, dest.layout.size), dest)?; - } - #[rustfmt::skip] | "sinf32" | "fabsf32" From 8392a0c589461e998a28a52a070b5fa5a143cf77 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 7 Mar 2020 15:33:27 -0500 Subject: [PATCH 1632/5092] only expose environ on linux --- src/eval.rs | 2 +- src/machine.rs | 26 +++++++------------ src/shims/env.rs | 9 +++++-- src/shims/foreign_items/posix/macos.rs | 10 ++++--- .../compile-fail/environ-gets-deallocated.rs | 4 +-- 5 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 13b55a93f216..a82c40a99e01 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -77,8 +77,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ), ); // Complete initialization. - MemoryExtra::init_extern_statics(&mut ecx)?; EnvVars::init(&mut ecx, config.excluded_env_vars)?; + MemoryExtra::init_extern_statics(&mut ecx)?; // Setup first stack-frame let main_instance = ty::Instance::mono(tcx, main_id); diff --git a/src/machine.rs b/src/machine.rs index 0f0c44300108..d21ff3289757 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -112,29 +112,23 @@ impl<'tcx> MemoryExtra<'tcx> { ) -> InterpResult<'tcx> { let target_os = this.tcx.sess.target.target.target_os.as_str(); match target_os { - "linux" | "macos" => { - if target_os == "linux" { - // "__cxa_thread_atexit_impl" - // This should be all-zero, pointer-sized. - let layout = this.layout_of(this.tcx.types.usize)?; - let place = this.allocate(layout, MiriMemoryKind::Machine.into()); - this.write_scalar(Scalar::from_machine_usize(0, &*this.tcx), place.into())?; - this.memory - .extra - .extern_statics - .insert(Symbol::intern("__cxa_thread_atexit_impl"), place.ptr.assert_ptr().alloc_id) - .unwrap_none(); - } - // "environ" + "linux" => { + // "__cxa_thread_atexit_impl" + // This should be all-zero, pointer-sized. let layout = this.layout_of(this.tcx.types.usize)?; let place = this.allocate(layout, MiriMemoryKind::Machine.into()); this.write_scalar(Scalar::from_machine_usize(0, &*this.tcx), place.into())?; this.memory .extra .extern_statics - .insert(Symbol::intern("environ"), place.ptr.assert_ptr().alloc_id) + .insert(Symbol::intern("__cxa_thread_atexit_impl"), place.ptr.assert_ptr().alloc_id) + .unwrap_none(); + // "environ" + this.memory + .extra + .extern_statics + .insert(Symbol::intern("environ"), this.memory.extra.environ.unwrap().ptr.assert_ptr().alloc_id) .unwrap_none(); - this.memory.extra.environ = Some(place); } _ => {} // No "extern statics" supported on this platform } diff --git a/src/shims/env.rs b/src/shims/env.rs index 1962ca026ccc..aaecbebc3603 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -30,6 +30,11 @@ impl EnvVars { } } } + // Initialize the `environ` static + let layout = ecx.layout_of(ecx.tcx.types.usize)?; + let place = ecx.allocate(layout, MiriMemoryKind::Machine.into()); + ecx.write_scalar(Scalar::from_machine_usize(0, &*ecx.tcx), place.into())?; + ecx.memory.extra.environ = Some(place); ecx.update_environ() } } @@ -156,12 +161,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Updates the `environ` static. It should not be called before - /// `MemoryExtra::init_extern_statics`. + /// `EnvVars::init`. fn update_environ(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); // Deallocate the old environ value. let old_vars_ptr = this.read_scalar(this.memory.extra.environ.unwrap().into())?.not_undef()?; - // The pointer itself can be null because `MemoryExtra::init_extern_statics` only + // The pointer itself can be null because `EnvVars::init` only // initializes the place for the static but not the static itself. if !this.is_null(old_vars_ptr)? { this.memory.deallocate(this.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Machine.into())?; diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index d167191279eb..c5c6423e8501 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -41,10 +41,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.macos_fstat(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - // Environment related shims - "_NSGetEnviron" => { - this.write_scalar(this.memory.extra.environ.unwrap().ptr, dest)?; - } + // The only reason this is not in the `posix` module is because the `linux` item has a // different name. "opendir$INODE64" => { @@ -59,6 +56,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + // Environment related shims + "_NSGetEnviron" => { + this.write_scalar(this.memory.extra.environ.unwrap().ptr, dest)?; + } + // Time related shims "gettimeofday" => { let result = this.gettimeofday(args[0], args[1])?; diff --git a/tests/compile-fail/environ-gets-deallocated.rs b/tests/compile-fail/environ-gets-deallocated.rs index a3d82a884213..6131613fc00b 100644 --- a/tests/compile-fail/environ-gets-deallocated.rs +++ b/tests/compile-fail/environ-gets-deallocated.rs @@ -3,9 +3,9 @@ #[cfg(target_os="linux")] fn get_environ() -> *const *const u8 { extern "C" { - static environ: *const *const u8; + static mut environ: *const *const u8; } - environ + unsafe { environ } } #[cfg(target_os="macos")] From 5c4cc2e3e0a4c8afff1bc4de718966233c7c03ee Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 8 Mar 2020 16:29:57 +0100 Subject: [PATCH 1633/5092] bump dependencies --- Cargo.lock | 104 ++++++++++++++++++++++++++++------------------------- 1 file changed, 55 insertions(+), 49 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 951e91dad5b2..b36418a1cbac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,17 @@ # It is not intended for manual editing. [[package]] name = "aho-corasick" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "anyhow" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "arrayref" version = "0.3.6" @@ -35,10 +40,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "backtrace" -version = "0.3.44" +version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace-sys 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", @@ -46,7 +51,7 @@ dependencies = [ [[package]] name = "backtrace-sys" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", @@ -109,7 +114,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "chrono" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", @@ -119,7 +124,7 @@ dependencies = [ [[package]] name = "colored" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -129,7 +134,7 @@ dependencies = [ [[package]] name = "compiletest_rs" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "diff 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -139,7 +144,7 @@ dependencies = [ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rustfix 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rustfix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", @@ -211,21 +216,21 @@ dependencies = [ [[package]] name = "failure" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "failure_derive" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -322,8 +327,8 @@ version = "0.1.0" dependencies = [ "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "colored 1.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "compiletest_rs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "colored 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)", + "compiletest_rs 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -363,7 +368,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -376,10 +381,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "quote" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -439,15 +444,15 @@ name = "regex" version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex-syntax" -version = "0.6.14" +version = "0.6.16" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -489,10 +494,10 @@ dependencies = [ [[package]] name = "rustfix" -version = "0.4.6" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", @@ -530,9 +535,9 @@ name = "serde_derive" version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -563,11 +568,11 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -576,9 +581,9 @@ name = "synstructure" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -656,8 +661,8 @@ version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -693,13 +698,14 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] -"checksum aho-corasick 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "743ad5a418686aad3b87fd14c43badd828cf26e214a00f92a384291cf22e1811" +"checksum aho-corasick 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)" = "d5e63fd144e18ba274ae7095c0197a870a7b9468abc801dd62f190d80817d2ec" +"checksum anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "7825f6833612eb2414095684fcf6c635becf3ce97fe48cf6421321e93bfbd53c" "checksum arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" "checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" "checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" "checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" -"checksum backtrace 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)" = "e4036b9bf40f3cf16aba72a3d65e8a520fc4bafcdc7079aea8f848c58c5b5536" -"checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" +"checksum backtrace 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)" = "ad235dabf00f36301792cfe82499880ba54c6486be094d1047b02bacb67c14e8" +"checksum backtrace-sys 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "e17b52e737c40a7d75abca20b29a19a0eb7ba9fc72c5a72dd282a0a3c2c0dc35" "checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" @@ -708,9 +714,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46e3374c604fb39d1a2f35ed5e4a4e30e60d01fab49446e08f1b3e9a90aef202" "checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "31850b4a4d6bae316f7a09e691c944c28299298837edc0a03f755618c23cbc01" -"checksum colored 1.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8815e2ab78f3a59928fc32e141fbeece88320a240e43f47b2fd64ea3a88a5b3d" -"checksum compiletest_rs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d7b678957210a00ba0fbeacc23d38cbfbf29895564da1616564634351e1dac5e" +"checksum chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" +"checksum colored 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" +"checksum compiletest_rs 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46cc00afd45129f775f8f8ee57c1ae2f7aabdf9692b2d74e36b917b91277bc7c" "checksum constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" "checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" "checksum diff 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" @@ -718,8 +724,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" "checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" "checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" -"checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" -"checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" +"checksum failure 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b8529c2421efa3066a5cbd8063d2244603824daccb6936b079010bb2aa89464b" +"checksum failure_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "030a733c8287d6213886dd487564ff5c8f6aae10278b3588ed177f9d18f8d231" "checksum filetime 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1ff6d4dab0aa0c8e6346d46052e93b13a16cf847b54ed357087c35011048cc7d" "checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" "checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" @@ -735,9 +741,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" "checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" -"checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548" +"checksum proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435" "checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" -"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +"checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" "checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" @@ -745,13 +751,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" "checksum redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" "checksum regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "322cf97724bea3ee221b78fe25ac9c46114ebb51747ad5babd51a2fc6a8235a8" -"checksum regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b28dfe3fe9badec5dbf0a79a9cccad2cfc2ab5484bdb3e44cbd1ae8b3ba2be06" +"checksum regex-syntax 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "1132f845907680735a84409c3bebc64d1364a5683ffbce899550cd09d5eaefc1" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" "checksum rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" "checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" "checksum rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum rustfix 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7150ac777a2931a53489f5a41eb0937b84e3092a20cd0e73ad436b65b507f607" +"checksum rustfix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "804b11883a5ce0ad0378fbf95a8dea59ee6b51c331a73b8f471b6bdaa3bd40c1" "checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" @@ -760,7 +766,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "9371ade75d4c2d6cb154141b9752cf3781ec9c05e0e5cf35060e1e70ee7b9c25" "checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9" "checksum socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e8b74de517221a2cb01a53349cf54182acdc31a074727d3079068448c0676d85" -"checksum syn 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a0294dc449adc58bb6592fff1a23d3e5e6e235afc6a0ffca2657d19e7bbffe5" +"checksum syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "123bd9499cfb380418d509322d7a6d52e5315f064fe4b3ad18a53d6b92c07859" "checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" From 69260115acbf5007277e0202b64e588dc3808d70 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 8 Mar 2020 16:50:19 +0100 Subject: [PATCH 1634/5092] readme: mention the leaks we found --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 936da469f599..3d7003af72e4 100644 --- a/README.md +++ b/README.md @@ -240,6 +240,7 @@ Definite bugs found: * [`rand` performing unaligned reads](https://github.com/rust-random/rand/issues/779) * [The Unix allocator calling `posix_memalign` in an invalid way](https://github.com/rust-lang/rust/issues/62251) * [`getrandom` calling the `getrandom` syscall in an invalid way](https://github.com/rust-random/getrandom/pull/73) +* [`Vec`](https://github.com/rust-lang/rust/issues/69770) and [`BTreeMap`](https://github.com/rust-lang/rust/issues/69769) leaking memory under some (panicky) conditions Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From 87dbf10e84c4545c90be11325107fa0f2876f1fd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 8 Mar 2020 17:18:53 +0100 Subject: [PATCH 1635/5092] move environ init to update_environ --- src/shims/env.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index aaecbebc3603..b06db5676f3e 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -30,11 +30,6 @@ impl EnvVars { } } } - // Initialize the `environ` static - let layout = ecx.layout_of(ecx.tcx.types.usize)?; - let place = ecx.allocate(layout, MiriMemoryKind::Machine.into()); - ecx.write_scalar(Scalar::from_machine_usize(0, &*ecx.tcx), place.into())?; - ecx.memory.extra.environ = Some(place); ecx.update_environ() } } @@ -160,17 +155,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - /// Updates the `environ` static. It should not be called before - /// `EnvVars::init`. + /// Updates the `environ` static. + /// The first time it gets called, also initializes `extra.environ`. fn update_environ(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - // Deallocate the old environ value. - let old_vars_ptr = this.read_scalar(this.memory.extra.environ.unwrap().into())?.not_undef()?; - // The pointer itself can be null because `EnvVars::init` only - // initializes the place for the static but not the static itself. - if !this.is_null(old_vars_ptr)? { + // Deallocate the old environ value, if any. + if let Some(environ) = this.memory.extra.environ { + let old_vars_ptr = this.read_scalar(environ.into())?.not_undef()?; this.memory.deallocate(this.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Machine.into())?; + } else { + // No `environ` allocated yet, let's do that. + let layout = this.layout_of(this.tcx.types.usize)?; + let place = this.allocate(layout, MiriMemoryKind::Machine.into()); + this.write_scalar(Scalar::from_machine_usize(0, &*this.tcx), place.into())?; + this.memory.extra.environ = Some(place); } + // Collect all the pointers to each variable in a vector. let mut vars: Vec> = this.machine.env_vars.map.values().map(|&ptr| ptr.into()).collect(); // Add the trailing null pointer. From 5dc60d974b0a76a1f4107790ea2249993d529e80 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sun, 8 Mar 2020 11:54:47 -0500 Subject: [PATCH 1636/5092] move environ place to EnvVars --- src/machine.rs | 20 ++++++++------------ src/shims/env.rs | 15 +++++++++------ src/shims/foreign_items/posix/macos.rs | 2 +- 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index d21ff3289757..f69606e48f52 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -70,7 +70,7 @@ pub struct AllocExtra { /// Extra global memory data #[derive(Clone, Debug)] -pub struct MemoryExtra<'tcx> { +pub struct MemoryExtra { pub stacked_borrows: Option, pub intptrcast: intptrcast::MemoryExtra, @@ -84,12 +84,9 @@ pub struct MemoryExtra<'tcx> { /// An allocation ID to report when it is being allocated /// (helps for debugging memory leaks). tracked_alloc_id: Option, - - /// Place where the `environ` static is stored. Lazily initialized, but then never changes. - pub(crate) environ: Option>, } -impl<'tcx> MemoryExtra<'tcx> { +impl MemoryExtra { pub fn new(rng: StdRng, stacked_borrows: bool, tracked_pointer_tag: Option, tracked_alloc_id: Option) -> Self { let stacked_borrows = if stacked_borrows { Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(tracked_pointer_tag)))) @@ -102,12 +99,11 @@ impl<'tcx> MemoryExtra<'tcx> { extern_statics: FxHashMap::default(), rng: RefCell::new(rng), tracked_alloc_id, - environ: None, } } /// Sets up the "extern statics" for this machine. - pub fn init_extern_statics<'mir>( + pub fn init_extern_statics<'tcx, 'mir>( this: &mut MiriEvalContext<'mir, 'tcx>, ) -> InterpResult<'tcx> { let target_os = this.tcx.sess.target.target.target_os.as_str(); @@ -127,7 +123,7 @@ impl<'tcx> MemoryExtra<'tcx> { this.memory .extra .extern_statics - .insert(Symbol::intern("environ"), this.memory.extra.environ.unwrap().ptr.assert_ptr().alloc_id) + .insert(Symbol::intern("environ"), this.machine.env_vars.environ.unwrap().ptr.assert_ptr().alloc_id) .unwrap_none(); } _ => {} // No "extern statics" supported on this platform @@ -140,7 +136,7 @@ impl<'tcx> MemoryExtra<'tcx> { pub struct Evaluator<'tcx> { /// Environment variables set by `setenv`. /// Miri does not expose env vars from the host to the emulated program. - pub(crate) env_vars: EnvVars, + pub(crate) env_vars: EnvVars<'tcx>, /// Program arguments (`Option` because we can only initialize them after creating the ecx). /// These are *pointers* to argc/argv because macOS. @@ -214,7 +210,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryKinds = MiriMemoryKind; type FrameExtra = FrameData<'tcx>; - type MemoryExtra = MemoryExtra<'tcx>; + type MemoryExtra = MemoryExtra; type AllocExtra = AllocExtra; type PointerTag = Tag; type ExtraFnVal = Dlsym; @@ -340,7 +336,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } fn init_allocation_extra<'b>( - memory_extra: &MemoryExtra<'tcx>, + memory_extra: &MemoryExtra, id: AllocId, alloc: Cow<'b, Allocation>, kind: Option>, @@ -377,7 +373,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } #[inline(always)] - fn tag_static_base_pointer(memory_extra: &MemoryExtra<'tcx>, id: AllocId) -> Self::PointerTag { + fn tag_static_base_pointer(memory_extra: &MemoryExtra, id: AllocId) -> Self::PointerTag { if let Some(stacked_borrows) = memory_extra.stacked_borrows.as_ref() { stacked_borrows.borrow_mut().static_base_ptr(id) } else { diff --git a/src/shims/env.rs b/src/shims/env.rs index b06db5676f3e..7c6b6c942e5e 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -10,14 +10,17 @@ use rustc::ty::layout::Size; use rustc_mir::interpret::Pointer; #[derive(Default)] -pub struct EnvVars { +pub struct EnvVars<'tcx> { /// Stores pointers to the environment variables. These variables must be stored as /// null-terminated C strings with the `"{name}={value}"` format. map: FxHashMap>, + + /// Place where the `environ` static is stored. Lazily initialized, but then never changes. + pub(crate) environ: Option>, } -impl EnvVars { - pub(crate) fn init<'mir, 'tcx>( +impl<'tcx> EnvVars<'tcx> { + pub(crate) fn init<'mir>( ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, excluded_env_vars: Vec, ) -> InterpResult<'tcx> { @@ -160,7 +163,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn update_environ(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); // Deallocate the old environ value, if any. - if let Some(environ) = this.memory.extra.environ { + if let Some(environ) = this.machine.env_vars.environ { let old_vars_ptr = this.read_scalar(environ.into())?.not_undef()?; this.memory.deallocate(this.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Machine.into())?; } else { @@ -168,7 +171,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let layout = this.layout_of(this.tcx.types.usize)?; let place = this.allocate(layout, MiriMemoryKind::Machine.into()); this.write_scalar(Scalar::from_machine_usize(0, &*this.tcx), place.into())?; - this.memory.extra.environ = Some(place); + this.machine.env_vars.environ = Some(place); } // Collect all the pointers to each variable in a vector. @@ -186,7 +189,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } this.write_scalar( vars_place.ptr, - this.memory.extra.environ.unwrap().into(), + this.machine.env_vars.environ.unwrap().into(), )?; Ok(()) diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index c5c6423e8501..0d067cc04138 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -58,7 +58,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Environment related shims "_NSGetEnviron" => { - this.write_scalar(this.memory.extra.environ.unwrap().ptr, dest)?; + this.write_scalar(this.machine.env_vars.environ.unwrap().ptr, dest)?; } // Time related shims From 83944562476ad783f8cace5d94af3490a41a256b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 8 Mar 2020 20:00:40 +0100 Subject: [PATCH 1637/5092] properly panic in panic_if_uninhabited and align_offset shims --- src/shims/intrinsics.rs | 4 +- src/shims/mod.rs | 34 +++++------ src/shims/panic.rs | 37 +++++++----- tests/run-pass/panic/catch_panic.rs | 56 +++++++++++++------ tests/run-pass/panic/catch_panic.stderr | 26 +++++---- tests/run-pass/{panic => }/transmute_fat2.rs | 0 .../{panic => }/transmute_fat2.stderr | 0 7 files changed, 96 insertions(+), 61 deletions(-) rename tests/run-pass/{panic => }/transmute_fat2.rs (100%) rename tests/run-pass/{panic => }/transmute_fat2.stderr (100%) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 9cae97a4060c..05047a6040c1 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -448,8 +448,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ty = substs.type_at(0); let layout = this.layout_of(ty)?; if layout.abi.is_uninhabited() { - // FIXME: This should throw a panic in the interpreted program instead. - throw_unsup_format!("Trying to instantiate uninhabited type {}", ty) + // Return here because we paniced instead of returning normally from the intrinsic. + return this.start_panic(&format!("Attempted to instantiate uninhabited type {}", ty), unwind); } } diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 04379553587d..6adf01385855 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -24,12 +24,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // There are some more lang items we want to hook that CTFE does not hook (yet). if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { - let (dest, ret) = ret.unwrap(); - let n = this - .align_offset(args[0], args[1])? - .unwrap_or_else(|| this.truncate(u128::MAX, dest.layout)); - this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; - this.go_to_block(ret); + this.align_offset(args[0], args[1], ret, unwind)?; return Ok(None); } @@ -52,35 +47,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, ptr_op: OpTy<'tcx, Tag>, align_op: OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, Option> { + ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + unwind: Option, + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + let (dest, ret) = ret.unwrap(); let req_align = this .force_bits(this.read_scalar(align_op)?.not_undef()?, this.pointer_size())? as usize; - // FIXME: This should actually panic in the interpreted program + // Stop if the alignment is not a power of two. if !req_align.is_power_of_two() { - throw_unsup_format!("Required alignment should always be a power of two") + return this.start_panic("align_offset: align is not a power-of-two", unwind); } let ptr_scalar = this.read_scalar(ptr_op)?.not_undef()?; + // Default: no result. + let mut result = this.truncate(u128::MAX, dest.layout); if let Ok(ptr) = this.force_ptr(ptr_scalar) { + // Only do anything if we can identify the allocation this goes to. let cur_align = this.memory.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead)?.1.bytes() as usize; if cur_align >= req_align { - // if the allocation alignment is at least the required alignment we use the + // If the allocation alignment is at least the required alignment we use the // libcore implementation - return Ok(Some( - (this.force_bits(ptr_scalar, this.pointer_size())? as *const i8) - .align_offset(req_align) as u128, - )); + result = (this.force_bits(ptr_scalar, this.pointer_size())? as *const i8).align_offset(req_align) as u128; } } - // If the allocation alignment is smaller than then required alignment or the pointer was - // actually an integer, we return `None` - Ok(None) + + // Return result, and jump to caller. + this.write_scalar(Scalar::from_uint(result, dest.layout.size), dest)?; + this.go_to_block(ret); + Ok(()) } } diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 11c5a882be9b..2968bd9b58d8 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -152,6 +152,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(res) } + /// Starta a panic in the interpreter with the given message as payload. + fn start_panic( + &mut self, + msg: &str, + unwind: Option, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + // First arg: message. + let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into()); + + // Call the lang item. + let panic = this.tcx.lang_items().panic_fn().unwrap(); + let panic = ty::Instance::mono(this.tcx.tcx, panic); + this.call_function( + panic, + &[msg.to_ref()], + None, + StackPopCleanup::Goto { ret: None, unwind }, + ) + } + fn assert_panic( &mut self, span: Span, @@ -184,20 +206,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } _ => { // Forward everything else to `panic` lang item. - - // First arg: Message. - let msg = msg.description(); - let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into()); - - // Call the lang item. - let panic = this.tcx.lang_items().panic_fn().unwrap(); - let panic = ty::Instance::mono(this.tcx.tcx, panic); - this.call_function( - panic, - &[msg.to_ref()], - None, - StackPopCleanup::Goto { ret: None, unwind }, - )?; + this.start_panic(msg.description(), unwind)?; } } Ok(()) diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index 21a6fee7c921..33c2beb682ae 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -1,5 +1,5 @@ // ignore-windows: Unwind panicking does not currently work on Windows -// normalize-stderr-test "[^ ]*libcore/macros/mod.rs[0-9:]*" -> "$$LOC" +// normalize-stderr-test "[^ ]*libcore/(macros|mem)/mod.rs[0-9:]*" -> "$$LOC" #![feature(never_type)] #![allow(unconditional_panic)] use std::panic::{catch_unwind, AssertUnwindSafe}; @@ -47,24 +47,41 @@ fn main() { })); // Std panics - test(|_old_val| std::panic!("Hello from panic: std")); - test(|old_val| std::panic!(format!("Hello from panic: {:?}", old_val))); - test(|old_val| std::panic!("Hello from panic: {:?}", old_val)); - test(|_old_val| std::panic!(1337)); + test(None, |_old_val| std::panic!("Hello from panic: std")); + test(None, |old_val| std::panic!(format!("Hello from panic: {:?}", old_val))); + test(None, |old_val| std::panic!("Hello from panic: {:?}", old_val)); + test(None, |_old_val| std::panic!(1337)); // Core panics - test(|_old_val| core::panic!("Hello from panic: core")); - test(|old_val| core::panic!(&format!("Hello from panic: {:?}", old_val))); - test(|old_val| core::panic!("Hello from panic: {:?}", old_val)); + test(None, |_old_val| core::panic!("Hello from panic: core")); + test(None, |old_val| core::panic!(&format!("Hello from panic: {:?}", old_val))); + test(None, |old_val| core::panic!("Hello from panic: {:?}", old_val)); - // Built-in panics - test(|_old_val| { let _val = [0, 1, 2][4]; loop {} }); - test(|_old_val| { let _val = 1/0; loop {} }); + // Built-in panics; also make sure the message is right. + test( + Some("index out of bounds: the len is 3 but the index is 4"), + |_old_val| { let _val = [0, 1, 2][4]; loop {} }, + ); + test( + Some("attempt to divide by zero"), + |_old_val| { let _val = 1/0; loop {} }, + ); + + // libcore panics from shims. + #[allow(deprecated, invalid_value)] + test( + Some("Attempted to instantiate uninhabited type !"), + |_old_val| unsafe { std::mem::uninitialized::() }, + ); + test( + Some("align_offset: align is not a power-of-two"), + |_old_val| { (0usize as *const u8).align_offset(3); loop {} }, + ); // Assertion and debug assertion - test(|_old_val| { assert!(false); loop {} }); - test(|_old_val| { debug_assert!(false); loop {} }); - test(|_old_val| { unsafe { (1 as *const i32).read() }; loop {} }); // trigger debug-assertion in libstd + test(None, |_old_val| { assert!(false); loop {} }); + test(None, |_old_val| { debug_assert!(false); loop {} }); + test(None, |_old_val| { unsafe { (1 as *const i32).read() }; loop {} }); // trigger debug-assertion in libstd // Cleanup: reset to default hook. drop(std::panic::take_hook()); @@ -72,7 +89,7 @@ fn main() { eprintln!("Success!"); // Make sure we get this in stderr } -fn test(do_panic: impl FnOnce(usize) -> !) { +fn test(expect_msg: Option<&str>, do_panic: impl FnOnce(usize) -> !) { // Reset test flags. DROPPED.with(|c| c.set(false)); HOOK_CALLED.with(|c| c.set(false)); @@ -84,16 +101,21 @@ fn test(do_panic: impl FnOnce(usize) -> !) { })).expect_err("do_panic() did not panic!"); // See if we can extract the panic message. - if let Some(s) = res.downcast_ref::() { + let msg = if let Some(s) = res.downcast_ref::() { eprintln!("Caught panic message (String): {}", s); + Some(s.as_str()) } else if let Some(s) = res.downcast_ref::<&str>() { eprintln!("Caught panic message (&str): {}", s); + Some(*s) } else { eprintln!("Failed get caught panic message."); + None + }; + if let Some(expect_msg) = expect_msg { + assert_eq!(expect_msg, msg.unwrap()); } // Test flags. assert!(DROPPED.with(|c| c.get())); assert!(HOOK_CALLED.with(|c| c.get())); } - diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr index 636179beeade..4ff22fe2176a 100644 --- a/tests/run-pass/panic/catch_panic.stderr +++ b/tests/run-pass/panic/catch_panic.stderr @@ -1,24 +1,28 @@ -thread 'main' panicked at 'Hello from panic: std', $DIR/catch_panic.rs:50:21 +thread 'main' panicked at 'Hello from panic: std', $DIR/catch_panic.rs:50:27 Caught panic message (&str): Hello from panic: std -thread 'main' panicked at 'Hello from panic: 1', $DIR/catch_panic.rs:51:20 +thread 'main' panicked at 'Hello from panic: 1', $DIR/catch_panic.rs:51:26 Caught panic message (String): Hello from panic: 1 -thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:52:20 +thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:52:26 Caught panic message (String): Hello from panic: 2 -thread 'main' panicked at 'Box', $DIR/catch_panic.rs:53:21 +thread 'main' panicked at 'Box', $DIR/catch_panic.rs:53:27 Failed get caught panic message. -thread 'main' panicked at 'Hello from panic: core', $DIR/catch_panic.rs:56:21 +thread 'main' panicked at 'Hello from panic: core', $DIR/catch_panic.rs:56:27 Caught panic message (String): Hello from panic: core -thread 'main' panicked at 'Hello from panic: 5', $DIR/catch_panic.rs:57:20 +thread 'main' panicked at 'Hello from panic: 5', $DIR/catch_panic.rs:57:26 Caught panic message (String): Hello from panic: 5 -thread 'main' panicked at 'Hello from panic: 6', $DIR/catch_panic.rs:58:20 +thread 'main' panicked at 'Hello from panic: 6', $DIR/catch_panic.rs:58:26 Caught panic message (String): Hello from panic: 6 -thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4', $DIR/catch_panic.rs:61:34 +thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4', $DIR/catch_panic.rs:63:33 Caught panic message (String): index out of bounds: the len is 3 but the index is 4 -thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:62:34 +thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:67:33 Caught panic message (String): attempt to divide by zero -thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:65:23 +thread 'main' panicked at 'Attempted to instantiate uninhabited type !', $LOC +Caught panic message (String): Attempted to instantiate uninhabited type ! +thread 'main' panicked at 'align_offset: align is not a power-of-two', $LOC +Caught panic message (String): align_offset: align is not a power-of-two +thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:82:29 Caught panic message (&str): assertion failed: false -thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:66:23 +thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:83:29 Caught panic message (&str): assertion failed: false thread 'main' panicked at 'attempt to copy from unaligned or null pointer', $LOC Caught panic message (String): attempt to copy from unaligned or null pointer diff --git a/tests/run-pass/panic/transmute_fat2.rs b/tests/run-pass/transmute_fat2.rs similarity index 100% rename from tests/run-pass/panic/transmute_fat2.rs rename to tests/run-pass/transmute_fat2.rs diff --git a/tests/run-pass/panic/transmute_fat2.stderr b/tests/run-pass/transmute_fat2.stderr similarity index 100% rename from tests/run-pass/panic/transmute_fat2.stderr rename to tests/run-pass/transmute_fat2.stderr From 5ef48593fb27af0194b082f7d5d9960b0d5f6320 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 4 Mar 2020 23:16:24 +0100 Subject: [PATCH 1638/5092] adjust error --- tests/compile-fail/slice-too-big.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile-fail/slice-too-big.rs b/tests/compile-fail/slice-too-big.rs index 157ea03bc932..6a4c18249ee7 100644 --- a/tests/compile-fail/slice-too-big.rs +++ b/tests/compile-fail/slice-too-big.rs @@ -2,5 +2,5 @@ use std::mem; fn main() { unsafe { let ptr = Box::into_raw(Box::new(0u8)); - let _x: &[u8] = mem::transmute((ptr, usize::MAX)); //~ ERROR: invalid slice: total size is bigger than largest supported object + let _x: &[u8] = mem::transmute((ptr, usize::MAX)); //~ ERROR: invalid reference metadata: slice is bigger than largest supported object } } From 5040cb7f81277ef6232f0f2548923b9b19fd5725 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 9 Mar 2020 17:03:45 +0100 Subject: [PATCH 1639/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 62e7b6845d51..f8f856bff76f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7a3700c37132385e8e965c18e73d0a09f9146335 +3dbade652ed8ebac70f903e01f51cd92c4e4302c From 881e65c01bfa5e483aa7deed3aee9771d672f231 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 11 Mar 2020 14:58:27 +0200 Subject: [PATCH 1640/5092] bump rust-version to latest --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index f8f856bff76f..fb138448f9f4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -3dbade652ed8ebac70f903e01f51cd92c4e4302c +303d8aff6092709edd4dbd35b1c88e9aa40bf6d8 From e81ebffa59929574c8ac8fa380e27eb9e612cff9 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 11 Mar 2020 15:39:37 +0200 Subject: [PATCH 1641/5092] Implement panic_if_any_invalid and panic_if_zero_invalid intrinsics --- src/shims/intrinsics.rs | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 05047a6040c1..d0305c0e9fbd 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -449,7 +449,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let layout = this.layout_of(ty)?; if layout.abi.is_uninhabited() { // Return here because we paniced instead of returning normally from the intrinsic. - return this.start_panic(&format!("Attempted to instantiate uninhabited type {}", ty), unwind); + return this.start_panic(&format!("attempted to instantiate uninhabited type {}", ty), unwind); + } + } + + "panic_if_zero_invalid" => { + let ty = substs.type_at(0); + let layout = this.layout_of(ty)?; + // Check if it permits zeroed raw initialization + if !layout.might_permit_raw_init(this, /*zero:*/ true).unwrap() { + // Return here because we paniced instead of returning normally from the intrinsic. + return this.start_panic(&format!("attempted to zero-initialize type `{}`, which is invalid", ty), unwind); + } + } + + "panic_if_any_invalid" => { + let ty = substs.type_at(0); + let layout = this.layout_of(ty)?; + // rustc handles all these in a single function, but we don't so we need to make sure `mem::uninitialized::()` returns the right error. + // So we check for `is_uninhabited` here too. + if layout.abi.is_uninhabited() { + return this.start_panic(&format!("attempted to instantiate uninhabited type {}", ty), unwind); + } + // Check if it permits any raw initialization + if !layout.might_permit_raw_init(this, /*zero:*/ false).unwrap() { + // Return here because we paniced instead of returning normally from the intrinsic. + return this.start_panic(&format!("attempted to leave type `{}` uninitialized, which is invalid", ty), unwind); } } From 2802c3cf0b91e18de1f37e24929a406033df0cc0 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 11 Mar 2020 16:02:49 +0200 Subject: [PATCH 1642/5092] Add tests for the new panic_if_any_invalid, panic_if_zero_invalid intrinsics --- tests/run-pass/panic/catch_panic.rs | 39 ++++++++++++++++++++++--- tests/run-pass/panic/catch_panic.stderr | 22 +++++++++++--- 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index 33c2beb682ae..a406fd434a05 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -69,10 +69,41 @@ fn main() { // libcore panics from shims. #[allow(deprecated, invalid_value)] - test( - Some("Attempted to instantiate uninhabited type !"), - |_old_val| unsafe { std::mem::uninitialized::() }, - ); + { + test( + Some("attempted to instantiate uninhabited type !"), + |_old_val| unsafe { std::mem::uninitialized::() }, + ); + test( + Some("attempted to zero-initialize type `!`, which is invalid"), + |_old_val| unsafe { std::mem::zeroed::() }, + ); + test( + Some("attempted to leave type `fn()` uninitialized, which is invalid"), + |_old_val| unsafe { std::mem::uninitialized::(); loop {} }, + ); + test( + Some("attempted to zero-initialize type `fn()`, which is invalid"), + |_old_val| unsafe { std::mem::zeroed::(); loop {} }, + ); + test( + Some("attempted to leave type `*const dyn std::marker::Sync` uninitialized, which is invalid"), + |_old_val| unsafe { std::mem::uninitialized::<*const dyn Sync>(); loop {} }, + ); + test( + Some("attempted to zero-initialize type `*mut dyn std::marker::Sync`, which is invalid"), + |_old_val| unsafe { std::mem::zeroed::<*mut dyn Sync>(); loop {} }, + ); + test( + Some("attempted to leave type `&u8` uninitialized, which is invalid"), + |_old_val| unsafe { std::mem::uninitialized::<&u8>(); loop {} }, + ); + test( + Some("attempted to zero-initialize type `&u8`, which is invalid"), + |_old_val| unsafe { std::mem::zeroed::<&u8>(); loop {} }, + ); + } + test( Some("align_offset: align is not a power-of-two"), |_old_val| { (0usize as *const u8).align_offset(3); loop {} }, diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr index 4ff22fe2176a..1899ea3c684a 100644 --- a/tests/run-pass/panic/catch_panic.stderr +++ b/tests/run-pass/panic/catch_panic.stderr @@ -16,13 +16,27 @@ thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4' Caught panic message (String): index out of bounds: the len is 3 but the index is 4 thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:67:33 Caught panic message (String): attempt to divide by zero -thread 'main' panicked at 'Attempted to instantiate uninhabited type !', $LOC -Caught panic message (String): Attempted to instantiate uninhabited type ! +thread 'main' panicked at 'attempted to instantiate uninhabited type !', $LOC +Caught panic message (String): attempted to instantiate uninhabited type ! +thread 'main' panicked at 'attempted to zero-initialize type `!`, which is invalid', $LOC +Caught panic message (String): attempted to zero-initialize type `!`, which is invalid +thread 'main' panicked at 'attempted to leave type `fn()` uninitialized, which is invalid', $LOC +Caught panic message (String): attempted to leave type `fn()` uninitialized, which is invalid +thread 'main' panicked at 'attempted to zero-initialize type `fn()`, which is invalid', $LOC +Caught panic message (String): attempted to zero-initialize type `fn()`, which is invalid +thread 'main' panicked at 'attempted to leave type `*const dyn std::marker::Sync` uninitialized, which is invalid', $LOC +Caught panic message (String): attempted to leave type `*const dyn std::marker::Sync` uninitialized, which is invalid +thread 'main' panicked at 'attempted to zero-initialize type `*mut dyn std::marker::Sync`, which is invalid', $LOC +Caught panic message (String): attempted to zero-initialize type `*mut dyn std::marker::Sync`, which is invalid +thread 'main' panicked at 'attempted to leave type `&u8` uninitialized, which is invalid', $LOC +Caught panic message (String): attempted to leave type `&u8` uninitialized, which is invalid +thread 'main' panicked at 'attempted to zero-initialize type `&u8`, which is invalid', $LOC +Caught panic message (String): attempted to zero-initialize type `&u8`, which is invalid thread 'main' panicked at 'align_offset: align is not a power-of-two', $LOC Caught panic message (String): align_offset: align is not a power-of-two -thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:82:29 +thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:113:29 Caught panic message (&str): assertion failed: false -thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:83:29 +thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:114:29 Caught panic message (&str): assertion failed: false thread 'main' panicked at 'attempt to copy from unaligned or null pointer', $LOC Caught panic message (String): attempt to copy from unaligned or null pointer From 548c90e102fe46a8348bbf7cb06c92782c66a02a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Mar 2020 19:52:39 +0100 Subject: [PATCH 1643/5092] share some code between panic intrinsics, and fix the message --- src/shims/intrinsics.rs | 33 +++++++------------------ tests/run-pass/panic/catch_panic.rs | 4 +-- tests/run-pass/panic/catch_panic.stderr | 8 +++--- 3 files changed, 15 insertions(+), 30 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index d0305c0e9fbd..fbb0a654294f 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -444,35 +444,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(result_ptr, dest)?; } - "panic_if_uninhabited" => { - let ty = substs.type_at(0); - let layout = this.layout_of(ty)?; - if layout.abi.is_uninhabited() { - // Return here because we paniced instead of returning normally from the intrinsic. - return this.start_panic(&format!("attempted to instantiate uninhabited type {}", ty), unwind); - } - } - - "panic_if_zero_invalid" => { - let ty = substs.type_at(0); - let layout = this.layout_of(ty)?; - // Check if it permits zeroed raw initialization - if !layout.might_permit_raw_init(this, /*zero:*/ true).unwrap() { - // Return here because we paniced instead of returning normally from the intrinsic. - return this.start_panic(&format!("attempted to zero-initialize type `{}`, which is invalid", ty), unwind); - } - } - + "panic_if_uninhabited" | + "panic_if_zero_invalid" | "panic_if_any_invalid" => { let ty = substs.type_at(0); let layout = this.layout_of(ty)?; - // rustc handles all these in a single function, but we don't so we need to make sure `mem::uninitialized::()` returns the right error. - // So we check for `is_uninhabited` here too. if layout.abi.is_uninhabited() { - return this.start_panic(&format!("attempted to instantiate uninhabited type {}", ty), unwind); + // Return here because we paniced instead of returning normally from the intrinsic. + return this.start_panic(&format!("attempted to instantiate uninhabited type `{}`", ty), unwind); } - // Check if it permits any raw initialization - if !layout.might_permit_raw_init(this, /*zero:*/ false).unwrap() { + if intrinsic_name == "panic_if_zero_invalid" && !layout.might_permit_raw_init(this, /*zero:*/ true).unwrap() { + // Return here because we paniced instead of returning normally from the intrinsic. + return this.start_panic(&format!("attempted to zero-initialize type `{}`, which is invalid", ty), unwind); + } + if intrinsic_name == "panic_if_any_invalid" && !layout.might_permit_raw_init(this, /*zero:*/ false).unwrap() { // Return here because we paniced instead of returning normally from the intrinsic. return this.start_panic(&format!("attempted to leave type `{}` uninitialized, which is invalid", ty), unwind); } diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index a406fd434a05..cc97ba5a85d2 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -71,11 +71,11 @@ fn main() { #[allow(deprecated, invalid_value)] { test( - Some("attempted to instantiate uninhabited type !"), + Some("attempted to instantiate uninhabited type `!`"), |_old_val| unsafe { std::mem::uninitialized::() }, ); test( - Some("attempted to zero-initialize type `!`, which is invalid"), + Some("attempted to instantiate uninhabited type `!`"), |_old_val| unsafe { std::mem::zeroed::() }, ); test( diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr index 1899ea3c684a..8d97fd6321f1 100644 --- a/tests/run-pass/panic/catch_panic.stderr +++ b/tests/run-pass/panic/catch_panic.stderr @@ -16,10 +16,10 @@ thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4' Caught panic message (String): index out of bounds: the len is 3 but the index is 4 thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:67:33 Caught panic message (String): attempt to divide by zero -thread 'main' panicked at 'attempted to instantiate uninhabited type !', $LOC -Caught panic message (String): attempted to instantiate uninhabited type ! -thread 'main' panicked at 'attempted to zero-initialize type `!`, which is invalid', $LOC -Caught panic message (String): attempted to zero-initialize type `!`, which is invalid +thread 'main' panicked at 'attempted to instantiate uninhabited type `!`', $LOC +Caught panic message (String): attempted to instantiate uninhabited type `!` +thread 'main' panicked at 'attempted to instantiate uninhabited type `!`', $LOC +Caught panic message (String): attempted to instantiate uninhabited type `!` thread 'main' panicked at 'attempted to leave type `fn()` uninitialized, which is invalid', $LOC Caught panic message (String): attempted to leave type `fn()` uninitialized, which is invalid thread 'main' panicked at 'attempted to zero-initialize type `fn()`, which is invalid', $LOC From 45d5a37787accac8bd4276ea47872a561069109c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Mar 2020 20:05:44 +0100 Subject: [PATCH 1644/5092] rustup+fix --- rust-version | 2 +- src/machine.rs | 3 +-- src/shims/panic.rs | 10 +++------- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/rust-version b/rust-version index fb138448f9f4..66d096c0a02b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -303d8aff6092709edd4dbd35b1c88e9aa40bf6d8 +c20d7eecbc0928b57da8fe30b2ef8528e2bdd5be diff --git a/src/machine.rs b/src/machine.rs index f69606e48f52..bd5884786c0e 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -265,11 +265,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn assert_panic( ecx: &mut InterpCx<'mir, 'tcx, Self>, - span: Span, msg: &mir::AssertMessage<'tcx>, unwind: Option, ) -> InterpResult<'tcx> { - ecx.assert_panic(span, msg, unwind) + ecx.assert_panic(msg, unwind) } #[inline(always)] diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 2968bd9b58d8..d6f563deb0f9 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -14,7 +14,6 @@ use rustc::mir; use rustc::ty::{self, layout::LayoutOf}; use rustc_target::spec::PanicStrategy; -use rustc_span::source_map::Span; use crate::*; @@ -176,7 +175,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn assert_panic( &mut self, - span: Span, msg: &mir::AssertMessage<'tcx>, unwind: Option, ) -> InterpResult<'tcx> { @@ -187,11 +185,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx BoundsCheck { ref index, ref len } => { // Forward to `panic_bounds_check` lang item. - // First arg: Caller location. - let location = this.alloc_caller_location_for_span(span); - // Second arg: index. + // First arg: index. let index = this.read_scalar(this.eval_operand(index, None)?)?; - // Third arg: len. + // Second arg: len. let len = this.read_scalar(this.eval_operand(len, None)?)?; // Call the lang item. @@ -199,7 +195,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let panic_bounds_check = ty::Instance::mono(this.tcx.tcx, panic_bounds_check); this.call_function( panic_bounds_check, - &[location.ptr.into(), index.into(), len.into()], + &[index.into(), len.into()], None, StackPopCleanup::Goto { ret: None, unwind }, )?; From 76ee8ff4589b5085c68c5efbebd8d3fb07b8a00d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Mar 2020 20:21:44 +0100 Subject: [PATCH 1645/5092] use ctfe_backtracte variable for backtrace control --- src/bin/miri.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index d2709643237f..e40bfcf6276a 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -7,13 +7,10 @@ extern crate log; extern crate log_settings; extern crate miri; extern crate rustc; -extern crate rustc_codegen_utils; extern crate rustc_driver; -extern crate rustc_errors; extern crate rustc_hir; extern crate rustc_interface; -extern crate rustc_metadata; -extern crate rustc_span; +extern crate rustc_session; use std::convert::TryFrom; use std::env; @@ -21,9 +18,11 @@ use std::str::FromStr; use hex::FromHexError; +use rustc_session::CtfeBacktrace; use rustc_driver::Compilation; use rustc_hir::def_id::LOCAL_CRATE; use rustc_interface::{interface, Queries}; +use rustc::ty::TyCtxt; struct MiriCompilerCalls { miri_config: miri::MiriConfig, @@ -35,10 +34,10 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { compiler: &interface::Compiler, queries: &'tcx Queries<'tcx>, ) -> Compilation { - init_late_loggers(); compiler.session().abort_if_errors(); queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { + init_late_loggers(tcx); let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!"); let mut config = self.miri_config.clone(); @@ -72,7 +71,7 @@ fn init_early_loggers() { } } -fn init_late_loggers() { +fn init_late_loggers(tcx: TyCtxt<'_>) { // We initialize loggers right before we start evaluation. We overwrite the `RUSTC_LOG` // env var if it is not set, control it based on `MIRI_LOG`. if let Ok(var) = env::var("MIRI_LOG") { @@ -96,10 +95,13 @@ fn init_late_loggers() { // If `MIRI_BACKTRACE` is set and `RUSTC_CTFE_BACKTRACE` is not, set `RUSTC_CTFE_BACKTRACE`. // Do this late, so we ideally only apply this to Miri's errors. - if let Ok(var) = env::var("MIRI_BACKTRACE") { - if env::var("RUSTC_CTFE_BACKTRACE") == Err(env::VarError::NotPresent) { - env::set_var("RUSTC_CTFE_BACKTRACE", &var); - } + if let Ok(val) = env::var("MIRI_BACKTRACE") { + let ctfe_backtrace = match &*val { + "immediate" => CtfeBacktrace::Immediate, + "0" => CtfeBacktrace::Disabled, + _ => CtfeBacktrace::Capture, + }; + *tcx.sess.ctfe_backtrace.borrow_mut() = ctfe_backtrace; } } From 5531a79f4cb0b3f1bbde6c138890f41df58e657c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Mar 2020 20:46:58 +0100 Subject: [PATCH 1646/5092] rustup, test Abort terminator --- rust-version | 2 +- src/lib.rs | 1 + src/machine.rs | 5 +++++ src/shims/intrinsics.rs | 1 + tests/compile-fail/abort-terminator.rs | 9 +++++++++ 5 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/abort-terminator.rs diff --git a/rust-version b/rust-version index 66d096c0a02b..ddc3de9a5461 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c20d7eecbc0928b57da8fe30b2ef8528e2bdd5be +54b7d21f59a363e53eb1c31d76b40af2ff99321c diff --git a/src/lib.rs b/src/lib.rs index 2a805f855579..86fbabbd629e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ #![feature(rustc_private)] #![feature(option_expect_none, option_unwrap_none)] #![feature(map_first_last)] +#![feature(never_type)] #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] diff --git a/src/machine.rs b/src/machine.rs index bd5884786c0e..8302c71e2bd1 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -271,6 +271,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx.assert_panic(msg, unwind) } + #[inline(always)] + fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, !> { + throw_machine_stop!(TerminationInfo::Abort) + } + #[inline(always)] fn binary_ptr_op( ecx: &rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>, diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index e1c5fdb7c2d0..121e60c9b058 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -34,6 +34,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Handle diverging intrinsics. let (dest, ret) = match intrinsic_name { "abort" => { + // FIXME: remove, once the intrinsic on the rustc side is fixed. throw_machine_stop!(TerminationInfo::Abort); } "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), diff --git a/tests/compile-fail/abort-terminator.rs b/tests/compile-fail/abort-terminator.rs new file mode 100644 index 000000000000..1bfa289a52b4 --- /dev/null +++ b/tests/compile-fail/abort-terminator.rs @@ -0,0 +1,9 @@ +// error-pattern: the evaluated program aborted +#![feature(unwind_attributes)] + +#[unwind(aborts)] +fn panic_abort() { panic!() } + +fn main() { + panic_abort(); +} From 13ae3147f047d7ff1488e6eabc067dacbdef58c9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Mar 2020 21:20:16 +0100 Subject: [PATCH 1647/5092] refactor handling of diverging intrinsics/foreign functions --- src/shims/foreign_items.rs | 55 +++++++++++++++++++------------------- src/shims/intrinsics.rs | 25 +++++++++-------- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 88ebc269cf1b..86c227121540 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -127,9 +127,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tcx = &{ this.tcx.tcx }; // First: functions that diverge. - let (dest, ret) = match link_name { - // Note that this matches calls to the *foreign* item `__rust_start_panic* - - // that is, calls to `extern "Rust" { fn __rust_start_panic(...) }`. + let (dest, ret) = match ret { + None => match link_name { + // This matches calls to the foreign item `panic_impl`. + // The implementation is provided by the function with the `#[panic_handler]` attribute. + "panic_impl" => { + let panic_impl_id = this.tcx.lang_items().panic_impl().unwrap(); + let panic_impl_instance = ty::Instance::mono(*this.tcx, panic_impl_id); + return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); + } + | "exit" + | "ExitProcess" + => { + // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway + let code = this.read_scalar(args[0])?.to_i32()?; + throw_machine_stop!(TerminationInfo::Exit(code.into())); + } + _ => throw_unsup_format!("can't call (diverging) foreign function: {}", link_name), + }, + Some(p) => p, + }; + + // Second: some functions that we forward to MIR implementations. + match link_name { + // This matches calls to the *foreign* item `__rust_start_panic*, that is, + // calls to `extern "Rust" { fn __rust_start_panic(...) }`. // We forward this to the underlying *implementation* in the panic runtime crate. // Normally, this will be either `libpanic_unwind` or `libpanic_abort`, but it could // also be a custom user-provided implementation via `#![feature(panic_runtime)]` @@ -145,31 +167,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.resolve_path(&[&*panic_runtime.as_str(), "__rust_start_panic"])?; return Ok(Some(&*this.load_mir(start_panic_instance.def, None)?)); } - // Similarly, we forward calls to the `panic_impl` foreign item to its implementation. - // The implementation is provided by the function with the `#[panic_handler]` attribute. - "panic_impl" => { - let panic_impl_id = this.tcx.lang_items().panic_impl().unwrap(); - let panic_impl_instance = ty::Instance::mono(*this.tcx, panic_impl_id); - return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); - } + _ => {} + } - | "exit" - | "ExitProcess" - => { - // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway - let code = this.read_scalar(args[0])?.to_i32()?; - throw_machine_stop!(TerminationInfo::Exit(code.into())); - } - _ => { - if let Some(p) = ret { - p - } else { - throw_unsup_format!("can't call (diverging) foreign function: {}", link_name); - } - } - }; - - // Next: functions that return. + // Third: functions that return. if this.emulate_foreign_item_by_name(link_name, args, dest, ret)? { this.dump_place(*dest); this.go_to_block(ret); diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 121e60c9b058..cf06a647762a 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -31,22 +31,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // that might still hang around! let intrinsic_name = &*tcx.item_name(instance.def_id()).as_str(); - // Handle diverging intrinsics. - let (dest, ret) = match intrinsic_name { - "abort" => { - // FIXME: remove, once the intrinsic on the rustc side is fixed. - throw_machine_stop!(TerminationInfo::Abort); - } - "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), - _ => - if let Some(p) = ret { - p - } else { - throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name); - }, + // First handle intrinsics without return place. + let (dest, ret) = match ret { + None => match intrinsic_name { + "abort" => { + // FIXME: remove, once the intrinsic on the rustc side is fixed. + throw_machine_stop!(TerminationInfo::Abort); + } + _ => throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name), + }, + Some(p) => p, }; match intrinsic_name { + "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), + "arith_offset" => { let offset = this.read_scalar(args[1])?.to_machine_isize(this)?; let ptr = this.read_scalar(args[0])?.not_undef()?; From 497fbcbf44b52d28169bf74b00ef346920cd5d26 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 14 Mar 2020 09:27:35 +0100 Subject: [PATCH 1648/5092] rustup, fix for intrinsic rename and transmute error change --- rust-version | 2 +- src/shims/intrinsics.rs | 10 +++++----- tests/compile-fail/never_transmute_humans.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rust-version b/rust-version index ddc3de9a5461..4635ed380aa4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -54b7d21f59a363e53eb1c31d76b40af2ff99321c +1572c433eed495d0ade41511ae106b180e02851d diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index cf06a647762a..622e237ebb0a 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -438,20 +438,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(result_ptr, dest)?; } - "panic_if_uninhabited" | - "panic_if_zero_invalid" | - "panic_if_any_invalid" => { + "assert_inhabited" | + "assert_zero_valid" | + "assert_uninit_valid" => { let ty = substs.type_at(0); let layout = this.layout_of(ty)?; if layout.abi.is_uninhabited() { // Return here because we paniced instead of returning normally from the intrinsic. return this.start_panic(&format!("attempted to instantiate uninhabited type `{}`", ty), unwind); } - if intrinsic_name == "panic_if_zero_invalid" && !layout.might_permit_raw_init(this, /*zero:*/ true).unwrap() { + if intrinsic_name == "assert_zero_valid" && !layout.might_permit_raw_init(this, /*zero:*/ true).unwrap() { // Return here because we paniced instead of returning normally from the intrinsic. return this.start_panic(&format!("attempted to zero-initialize type `{}`, which is invalid", ty), unwind); } - if intrinsic_name == "panic_if_any_invalid" && !layout.might_permit_raw_init(this, /*zero:*/ false).unwrap() { + if intrinsic_name == "assert_uninit_valid" && !layout.might_permit_raw_init(this, /*zero:*/ false).unwrap() { // Return here because we paniced instead of returning normally from the intrinsic. return this.start_panic(&format!("attempted to leave type `{}` uninitialized, which is invalid", ty), unwind); } diff --git a/tests/compile-fail/never_transmute_humans.rs b/tests/compile-fail/never_transmute_humans.rs index 2e0d4e9bdf33..8a7d7bfcc682 100644 --- a/tests/compile-fail/never_transmute_humans.rs +++ b/tests/compile-fail/never_transmute_humans.rs @@ -7,6 +7,6 @@ struct Human; fn main() { let _x: ! = unsafe { - std::mem::transmute::(Human) //~ ERROR entering unreachable code + std::mem::transmute::(Human) //~ ERROR transmuting to uninhabited }; } From a92b2274ce064cce18b7c68d66ba7c019dde487c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 14 Mar 2020 12:05:25 +0100 Subject: [PATCH 1649/5092] fix typo and deduplicate comment --- src/shims/intrinsics.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 622e237ebb0a..3815ed516444 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -443,16 +443,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "assert_uninit_valid" => { let ty = substs.type_at(0); let layout = this.layout_of(ty)?; + // Return here because we panicked instead of returning normally from the intrinsic. if layout.abi.is_uninhabited() { - // Return here because we paniced instead of returning normally from the intrinsic. return this.start_panic(&format!("attempted to instantiate uninhabited type `{}`", ty), unwind); } if intrinsic_name == "assert_zero_valid" && !layout.might_permit_raw_init(this, /*zero:*/ true).unwrap() { - // Return here because we paniced instead of returning normally from the intrinsic. return this.start_panic(&format!("attempted to zero-initialize type `{}`, which is invalid", ty), unwind); } if intrinsic_name == "assert_uninit_valid" && !layout.might_permit_raw_init(this, /*zero:*/ false).unwrap() { - // Return here because we paniced instead of returning normally from the intrinsic. return this.start_panic(&format!("attempted to leave type `{}` uninitialized, which is invalid", ty), unwind); } } From 1c4f27f1b2f5517c5dfa6fea0cfef8c089b2e9ec Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 14 Mar 2020 11:53:09 +0100 Subject: [PATCH 1650/5092] adjust Miri to needs of changed unwinding strategy --- src/machine.rs | 16 ++--- src/shims/foreign_items.rs | 14 ++-- src/shims/intrinsics.rs | 3 +- src/shims/panic.rs | 136 ++++++++++++++++++------------------- 4 files changed, 83 insertions(+), 86 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 8302c71e2bd1..d94c6928cfe0 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -32,11 +32,10 @@ pub struct FrameData<'tcx> { /// Extra data for Stacked Borrows. pub call_id: stacked_borrows::CallId, - /// If this is Some(), then this is a special "catch unwind" frame (the frame of the closure - /// called by `__rustc_maybe_catch_panic`). When this frame is popped during unwinding a panic, - /// we stop unwinding, use the `CatchUnwindData` to - /// store the panic payload, and continue execution in the parent frame. - pub catch_panic: Option>, + /// If this is Some(), then this is a special "catch unwind" frame (the frame of `try_fn` + /// called by `try`). When this frame is popped during unwinding a panic, + /// we stop unwinding, use the `CatchUnwindData` to handle catching. + pub catch_unwind: Option>, } /// Extra memory kinds @@ -163,7 +162,8 @@ pub struct Evaluator<'tcx> { /// The temporary used for storing the argument of /// the call to `miri_start_panic` (the panic payload) when unwinding. - pub(crate) panic_payload: Option>, + /// This is pointer-sized, and matches the `Payload` type in `src/libpanic_unwind/miri.rs`. + pub(crate) panic_payload: Option>, } impl<'tcx> Evaluator<'tcx> { @@ -405,7 +405,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { let call_id = stacked_borrows.map_or(NonZeroU64::new(1).unwrap(), |stacked_borrows| { stacked_borrows.borrow_mut().new_call() }); - Ok(FrameData { call_id, catch_panic: None }) + Ok(FrameData { call_id, catch_unwind: None }) } #[inline(always)] @@ -413,7 +413,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx: &mut InterpCx<'mir, 'tcx, Self>, extra: FrameData<'tcx>, unwinding: bool, - ) -> InterpResult<'tcx, StackPopInfo> { + ) -> InterpResult<'tcx, StackPopJump> { ecx.handle_stack_pop(extra, unwinding) } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 86c227121540..0183757cff0a 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -150,12 +150,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Second: some functions that we forward to MIR implementations. match link_name { - // This matches calls to the *foreign* item `__rust_start_panic*, that is, - // calls to `extern "Rust" { fn __rust_start_panic(...) }`. + // This matches calls to the foreign item `__rust_start_panic`, that is, + // calls to `extern "Rust" { fn __rust_start_panic(...) }` + // (and `__rust_panic_cleanup`, respectively). // We forward this to the underlying *implementation* in the panic runtime crate. // Normally, this will be either `libpanic_unwind` or `libpanic_abort`, but it could // also be a custom user-provided implementation via `#![feature(panic_runtime)]` - "__rust_start_panic" => { + "__rust_start_panic" | "__rust_panic_cleanup"=> { // FIXME we might want to cache this... but it's not really performance-critical. let panic_runtime = tcx .crates() @@ -164,7 +165,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .expect("No panic runtime found!"); let panic_runtime = tcx.crate_name(*panic_runtime); let start_panic_instance = - this.resolve_path(&[&*panic_runtime.as_str(), "__rust_start_panic"])?; + this.resolve_path(&[&*panic_runtime.as_str(), link_name])?; return Ok(Some(&*this.load_mir(start_panic_instance.def, None)?)); } _ => {} @@ -291,11 +292,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(new_ptr, dest)?; } - "__rust_maybe_catch_panic" => { - this.handle_catch_panic(args, dest, ret)?; - return Ok(false); - } - "memcmp" => { let left = this.read_scalar(args[0])?.not_undef()?; let right = this.read_scalar(args[1])?.not_undef()?; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 3815ed516444..8d7645c81fe4 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -34,6 +34,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // First handle intrinsics without return place. let (dest, ret) = match ret { None => match intrinsic_name { + "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), "abort" => { // FIXME: remove, once the intrinsic on the rustc side is fixed. throw_machine_stop!(TerminationInfo::Abort); @@ -44,7 +45,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; match intrinsic_name { - "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), + "try" => return this.handle_try(args, dest, ret), "arith_offset" => { let offset = this.read_scalar(args[1])?.to_machine_isize(this)?; diff --git a/src/shims/panic.rs b/src/shims/panic.rs index d6f563deb0f9..2f61ab6c3958 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -17,24 +17,22 @@ use rustc_target::spec::PanicStrategy; use crate::*; -/// Holds all of the relevant data for a call to -/// `__rust_maybe_catch_panic`. -/// -/// If a panic occurs, we update this data with -/// the information from the panic site. +/// Holds all of the relevant data for when unwinding hits a `try` frame. #[derive(Debug)] pub struct CatchUnwindData<'tcx> { - /// The dereferenced `data_ptr` argument passed to `__rust_maybe_catch_panic`. - pub data_place: MPlaceTy<'tcx, Tag>, - /// The dereferenced `vtable_ptr` argument passed to `__rust_maybe_catch_panic`. - pub vtable_place: MPlaceTy<'tcx, Tag>, - /// The `dest` from the original call to `__rust_maybe_catch_panic`. - pub dest: PlaceTy<'tcx, Tag>, + /// The `catch_fn` callback to call in case of a panic. + catch_fn: Scalar, + /// The `data` argument for that callback. + data: Scalar, + /// The return place from the original call to `try`. + dest: PlaceTy<'tcx, Tag>, + /// The return block from the original call to `try`. + ret: mir::BasicBlock, } impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// Handles the special "miri_start_panic" intrinsic, which is called + /// Handles the special `miri_start_panic` intrinsic, which is called /// by libpanic_unwind to delegate the actual unwinding process to Miri. fn handle_miri_start_panic( &mut self, @@ -46,47 +44,50 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("miri_start_panic: {:?}", this.frame().span); // Get the raw pointer stored in arg[0] (the panic payload). - let scalar = this.read_immediate(args[0])?; + let payload = this.read_scalar(args[0])?.not_undef()?; assert!( this.machine.panic_payload.is_none(), "the panic runtime should avoid double-panics" ); - this.machine.panic_payload = Some(scalar); + this.machine.panic_payload = Some(payload); // Jump to the unwind block to begin unwinding. this.unwind_to_block(unwind); return Ok(()); } - fn handle_catch_panic( + /// Handles the `try` intrinsic, the underlying implementation of `std::panicking::try`. + fn handle_try( &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, ret: mir::BasicBlock, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let tcx = &{ this.tcx.tcx }; - // fn __rust_maybe_catch_panic( - // f: fn(*mut u8), - // data: *mut u8, - // data_ptr: *mut usize, - // vtable_ptr: *mut usize, - // ) -> u32 + // Signature: + // fn r#try(try_fn: fn(*mut u8), data: *mut u8, catch_fn: fn(*mut u8, *mut u8)) -> i32 + // Calls `try_fn` with `data` as argument. If that executes normally, returns 0. + // If that unwinds, calls `catch_fn` with the first argument being `data` and + // then second argument being a target-dependent `payload` (i.e. it is up to us to define + // what that is), and returns 1. + // The `payload` is passed (by libstd) to `__rust_panic_cleanup`, which is then expected to + // return a `Box`. + // In Miri, `miri_start_panic` is passed exactly that type, so we make the `payload` simply + // a pointer to `Box`. // Get all the arguments. - let f = this.read_scalar(args[0])?.not_undef()?; - let f_arg = this.read_scalar(args[1])?.not_undef()?; - let data_place = this.deref_operand(args[2])?; - let vtable_place = this.deref_operand(args[3])?; + let try_fn = this.read_scalar(args[0])?.not_undef()?; + let data = this.read_scalar(args[1])?.not_undef()?; + let catch_fn = this.read_scalar(args[2])?.not_undef()?; - // Now we make a function call, and pass `f_arg` as first and only argument. - let f_instance = this.memory.get_fn(f)?.as_instance()?; - trace!("__rust_maybe_catch_panic: {:?}", f_instance); - let ret_place = MPlaceTy::dangling(this.layout_of(tcx.mk_unit())?, this).into(); + // Now we make a function call, and pass `data` as first and only argument. + let f_instance = this.memory.get_fn(try_fn)?.as_instance()?; + trace!("try_fn: {:?}", f_instance); + let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); this.call_function( f_instance, - &[f_arg.into()], + &[data.into()], Some(ret_place), // Directly return to caller. StackPopCleanup::Goto { ret: Some(ret), unwind: None }, @@ -95,12 +96,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We ourselves will return `0`, eventually (will be overwritten if we catch a panic). this.write_null(dest)?; - // In unwind mode, we tag this frame with some extra data. + // In unwind mode, we tag this frame with the extra data needed to catch unwinding. // This lets `handle_stack_pop` (below) know that we should stop unwinding // when we pop this frame. - if this.tcx.tcx.sess.panic_strategy() == PanicStrategy::Unwind { - this.frame_mut().extra.catch_panic = - Some(CatchUnwindData { data_place, vtable_place, dest }) + if this.tcx.sess.panic_strategy() == PanicStrategy::Unwind { + this.frame_mut().extra.catch_unwind = Some(CatchUnwindData { catch_fn, data, dest, ret }); } return Ok(()); @@ -110,45 +110,45 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, mut extra: FrameData<'tcx>, unwinding: bool, - ) -> InterpResult<'tcx, StackPopInfo> { + ) -> InterpResult<'tcx, StackPopJump> { let this = self.eval_context_mut(); trace!("handle_stack_pop(extra = {:?}, unwinding = {})", extra, unwinding); - - // We only care about `catch_panic` if we're unwinding - if we're doing a normal - // return, then we don't need to do anything special. - let res = if let (true, Some(unwind_data)) = (unwinding, extra.catch_panic.take()) { - // We've just popped a frame that was pushed by `__rust_maybe_catch_panic`, - // and we are unwinding, so we should catch that. - trace!("unwinding: found catch_panic frame during unwinding: {:?}", this.frame().span); - - // `panic_payload` now holds a `*mut (dyn Any + Send)`, - // provided by the `miri_start_panic` intrinsic. - // We want to split this into its consituient parts - - // the data and vtable pointers - and store them according to - // `unwind_data`, i.e., we store them where `__rust_maybe_catch_panic` - // was told to put them. - let payload = this.machine.panic_payload.take().unwrap(); - let payload = this.ref_to_mplace(payload)?; - let payload_data_place = payload.ptr; - let payload_vtable_place = payload.meta.unwrap_meta(); - - this.write_scalar(payload_data_place, unwind_data.data_place.into())?; - this.write_scalar(payload_vtable_place, unwind_data.vtable_place.into())?; - - // We set the return value of `__rust_maybe_catch_panic` to 1, - // since there was a panic. - let dest = unwind_data.dest; - this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; - - StackPopInfo::StopUnwinding - } else { - StackPopInfo::Normal - }; if let Some(stacked_borrows) = this.memory.extra.stacked_borrows.as_ref() { stacked_borrows.borrow_mut().end_call(extra.call_id); } - Ok(res) + + // We only care about `catch_panic` if we're unwinding - if we're doing a normal + // return, then we don't need to do anything special. + if let (true, Some(catch_unwind)) = (unwinding, extra.catch_unwind.take()) { + // We've just popped a frame that was pushed by `try`, + // and we are unwinding, so we should catch that. + trace!("unwinding: found catch_panic frame during unwinding: {:?}", this.frame().span); + + // We set the return value of `try` to 1, since there was a panic. + this.write_scalar(Scalar::from_i32(1), catch_unwind.dest)?; + + // `panic_payload` holds what was passed to `miri_start_panic`. + // This is exactly the second argument we need to pass to `catch_fn`. + let payload = this.machine.panic_payload.take().unwrap(); + + // Push the `catch_fn` stackframe. + let f_instance = this.memory.get_fn(catch_unwind.catch_fn)?.as_instance()?; + trace!("catch_fn: {:?}", f_instance); + let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); + this.call_function( + f_instance, + &[catch_unwind.data.into(), payload.into()], + Some(ret_place), + // Directly return to caller of `try`. + StackPopCleanup::Goto { ret: Some(catch_unwind.ret), unwind: None }, + )?; + + // We pushed a new stack frame, the engine should not do any jumping now! + Ok(StackPopJump::NoJump) + } else { + Ok(StackPopJump::Normal) + } } /// Starta a panic in the interpreter with the given message as payload. From 956692d902f708d32d5d6242955fedee9d568f02 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 15 Mar 2020 11:15:09 +0100 Subject: [PATCH 1651/5092] bump rust-version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 4635ed380aa4..1bad03be36cb 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1572c433eed495d0ade41511ae106b180e02851d +7cdbc87a49b0b705a41a004a6d486b0952521ae7 From 17a677f4a9631a620e85678556d68828b6f7aa55 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 15 Mar 2020 11:17:07 +0100 Subject: [PATCH 1652/5092] abort intrinsic is handled by librustc_mir now --- src/shims/intrinsics.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 8d7645c81fe4..b91af778d979 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -35,10 +35,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (dest, ret) = match ret { None => match intrinsic_name { "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), - "abort" => { - // FIXME: remove, once the intrinsic on the rustc side is fixed. - throw_machine_stop!(TerminationInfo::Abort); - } _ => throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name), }, Some(p) => p, From 92e3032941ede436d90a1c655f34ddfd3bcd9957 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 15 Mar 2020 15:15:22 +0100 Subject: [PATCH 1653/5092] Cargo.toml: group all dependencies together --- Cargo.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f71fec3c2846..e788e775972a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,11 +56,11 @@ serde = { version = "*", features = ["derive"] } [build-dependencies] vergen = "3" +[dev-dependencies] +compiletest_rs = { version = "0.4", features = ["tmp"] } +colored = "1.6" + [features] default = ["cargo_miri"] cargo_miri = ["cargo_metadata", "directories", "rustc_version", "serde_json"] rustc_tests = [] - -[dev-dependencies] -compiletest_rs = { version = "0.4", features = ["tmp"] } -colored = "1.6" From a664156440916b96737c4c8317d9befca68d0440 Mon Sep 17 00:00:00 2001 From: Youngsuk Kim Date: Sun, 15 Mar 2020 18:06:21 -0400 Subject: [PATCH 1654/5092] Minor typo fix "initializiation" => "initialization" --- src/eval.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/eval.rs b/src/eval.rs index a82c40a99e01..2cf5a1dc444c 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -198,7 +198,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Ok(v) => v, Err(mut err) => { err.print_backtrace(); - panic!("Miri initialziation error: {}", err.kind) + panic!("Miri initialization error: {}", err.kind) } }; From bddf9e050b729d98fd64c26879a809b89593b0ec Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 16 Mar 2020 09:59:01 +0100 Subject: [PATCH 1655/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 1bad03be36cb..085e3695a196 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7cdbc87a49b0b705a41a004a6d486b0952521ae7 +97eda01bb79de1e0a52994f52cfb5a527687f505 From 8a26a288c2fa72e623e4c48d77216cf58c7177cc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 16 Mar 2020 21:32:57 +0100 Subject: [PATCH 1656/5092] rustup --- rust-version | 2 +- tests/compile-fail/exact_div2.rs | 2 +- tests/compile-fail/exact_div3.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 085e3695a196..dce708705b33 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -97eda01bb79de1e0a52994f52cfb5a527687f505 +dd67187965e136bff1ed05e035293441c60f0790 diff --git a/tests/compile-fail/exact_div2.rs b/tests/compile-fail/exact_div2.rs index f4400d0d8ae2..9b9ae807088d 100644 --- a/tests/compile-fail/exact_div2.rs +++ b/tests/compile-fail/exact_div2.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // divison with a remainder - unsafe { std::intrinsics::exact_div(2u16, 3); } //~ ERROR 2 cannot be divided by 3 without remainder + unsafe { std::intrinsics::exact_div(2u16, 3); } //~ ERROR 2u16 cannot be divided by 3u16 without remainder } diff --git a/tests/compile-fail/exact_div3.rs b/tests/compile-fail/exact_div3.rs index 0d5097a87a20..1cd112acfc2d 100644 --- a/tests/compile-fail/exact_div3.rs +++ b/tests/compile-fail/exact_div3.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // signed divison with a remainder - unsafe { std::intrinsics::exact_div(-19i8, 2); } //~ ERROR -19 cannot be divided by 2 without remainder + unsafe { std::intrinsics::exact_div(-19i8, 2); } //~ ERROR -19i8 cannot be divided by 2i8 without remainder } From 8b6af3eacbeb359c2041a3b5efc12042d3c33deb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 17 Mar 2020 15:18:53 +0100 Subject: [PATCH 1657/5092] avoid using unchecked casts or arithmetic --- src/bin/miri.rs | 3 +-- src/eval.rs | 13 +++++----- src/helpers.rs | 9 ++++--- src/shims/dlsym.rs | 2 +- src/shims/env.rs | 7 ++--- src/shims/foreign_items.rs | 10 +++---- src/shims/foreign_items/posix.rs | 4 ++- src/shims/foreign_items/posix/linux.rs | 2 +- src/shims/foreign_items/posix/macos.rs | 2 +- src/shims/foreign_items/windows.rs | 6 ++--- src/shims/fs.rs | 36 +++++++++++++------------- src/shims/intrinsics.rs | 9 ++++--- src/shims/mod.rs | 21 +++++++++------ src/shims/time.rs | 8 +++--- 14 files changed, 71 insertions(+), 61 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index e40bfcf6276a..4a54867c9964 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -259,7 +259,6 @@ fn main() { rustc_driver::install_ice_hook(); let result = rustc_driver::catch_fatal_errors(move || { rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None) - }) - .and_then(|result| result); + }); std::process::exit(result.is_err() as i32); } diff --git a/src/eval.rs b/src/eval.rs index 2cf5a1dc444c..64beff6eb77f 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -1,6 +1,7 @@ //! Main evaluator loop and setting up the initial stack frame. use std::ffi::OsStr; +use std::convert::TryFrom; use rand::rngs::StdRng; use rand::SeedableRng; @@ -101,14 +102,14 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // First argument: pointer to `main()`. let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(main_instance)); // Second argument (argc): length of `config.args`. - let argc = Scalar::from_uint(config.args.len() as u128, ecx.pointer_size()); + let argc = Scalar::from_uint(u64::try_from(config.args.len()).unwrap(), ecx.pointer_size()); // Third argument (`argv`): created from `config.args`. let argv = { // Put each argument in memory, collect pointers. let mut argvs = Vec::>::new(); for arg in config.args.iter() { // Make space for `0` terminator. - let size = arg.len() as u64 + 1; + let size = u64::try_from(arg.len()).unwrap().checked_add(1).unwrap(); let arg_type = tcx.mk_array(tcx.types.u8, size); let arg_place = ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Machine.into()); ecx.write_os_str_to_c_str(OsStr::new(arg), arg_place.ptr, size)?; @@ -116,10 +117,10 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } // Make an array with all these pointers, in the Miri memory. let argvs_layout = - ecx.layout_of(tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), argvs.len() as u64))?; + ecx.layout_of(tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), u64::try_from(argvs.len()).unwrap()))?; let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into()); for (idx, arg) in argvs.into_iter().enumerate() { - let place = ecx.mplace_field(argvs_place, idx as u64)?; + let place = ecx.mplace_field(argvs_place, u64::try_from(idx).unwrap())?; ecx.write_scalar(arg, place.into())?; } ecx.memory.mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?; @@ -153,13 +154,13 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( cmd.push(std::char::from_u32(0).unwrap()); let cmd_utf16: Vec = cmd.encode_utf16().collect(); - let cmd_type = tcx.mk_array(tcx.types.u16, cmd_utf16.len() as u64); + let cmd_type = tcx.mk_array(tcx.types.u16, u64::try_from(cmd_utf16.len()).unwrap()); let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Machine.into()); ecx.machine.cmd_line = Some(cmd_place.ptr); // Store the UTF-16 string. We just allocated so we know the bounds are fine. let char_size = Size::from_bytes(2); for (idx, &c) in cmd_utf16.iter().enumerate() { - let place = ecx.mplace_field(cmd_place, idx as u64)?; + let place = ecx.mplace_field(cmd_place, u64::try_from(idx).unwrap())?; ecx.write_scalar(Scalar::from_uint(c, char_size), place.into())?; } } diff --git a/src/helpers.rs b/src/helpers.rs index 5ff0a5671cdb..ecb3a5d8bce9 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,5 +1,6 @@ use std::ffi::OsStr; use std::{iter, mem}; +use std::convert::TryFrom; use rustc::mir; use rustc::ty::{ @@ -81,7 +82,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Generate some random bytes, and write them to `dest`. - fn gen_random(&mut self, ptr: Scalar, len: usize) -> InterpResult<'tcx> { + fn gen_random(&mut self, ptr: Scalar, len: u64) -> InterpResult<'tcx> { // Some programs pass in a null pointer and a length of 0 // to their platform's random-generation function (e.g. getrandom()) // on Linux. For compatibility with these programs, we don't perform @@ -92,7 +93,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let this = self.eval_context_mut(); - let mut data = vec![0; len]; + let mut data = vec![0; usize::try_from(len).unwrap()]; if this.machine.communicate { // Fill the buffer using the host's rng. @@ -499,7 +500,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let bytes = os_str_to_bytes(os_str)?; // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null // terminator to memory using the `ptr` pointer would cause an out-of-bounds access. - let string_length = bytes.len() as u64; + let string_length = u64::try_from(bytes.len()).unwrap(); if size <= string_length { return Ok((false, string_length)); } @@ -514,7 +515,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx os_str: &OsStr, memkind: MemoryKind, ) -> Pointer { - let size = os_str.len() as u64 + 1; // Make space for `0` terminator. + let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0` terminator. let this = self.eval_context_mut(); let arg_type = this.tcx.mk_array(this.tcx.types.u8, size); diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 0069f8cc8087..9027a97cf54e 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -37,7 +37,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx GetEntropy => { let ptr = this.read_scalar(args[0])?.not_undef()?; let len = this.read_scalar(args[1])?.to_machine_usize(this)?; - this.gen_random(ptr, len as usize)?; + this.gen_random(ptr, len)?; this.write_null(dest)?; } } diff --git a/src/shims/env.rs b/src/shims/env.rs index 7c6b6c942e5e..da634c1aeb23 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,5 +1,6 @@ use std::ffi::{OsString, OsStr}; use std::env; +use std::convert::TryFrom; use crate::stacked_borrows::Tag; use crate::rustc_target::abi::LayoutOf; @@ -58,7 +59,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(match this.machine.env_vars.map.get(name) { // The offset is used to strip the "{name}=" part of the string. Some(var_ptr) => { - Scalar::from(var_ptr.offset(Size::from_bytes(name.len() as u64 + 1), this)?) + Scalar::from(var_ptr.offset(Size::from_bytes(u64::try_from(name.len()).unwrap().checked_add(1).unwrap()), this)?) } None => Scalar::ptr_null(&*this.tcx), }) @@ -181,10 +182,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Make an array with all these pointers inside Miri. let tcx = this.tcx; let vars_layout = - this.layout_of(tcx.mk_array(tcx.types.usize, vars.len() as u64))?; + this.layout_of(tcx.mk_array(tcx.types.usize, u64::try_from(vars.len()).unwrap()))?; let vars_place = this.allocate(vars_layout, MiriMemoryKind::Machine.into()); for (idx, var) in vars.into_iter().enumerate() { - let place = this.mplace_field(vars_place, idx as u64)?; + let place = this.mplace_field(vars_place, u64::try_from(idx).unwrap())?; this.write_scalar(var, place.into())?; } this.write_scalar( diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 0183757cff0a..deabbdd60819 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -1,7 +1,7 @@ mod windows; mod posix; -use std::{convert::TryInto, iter}; +use std::{convert::{TryInto, TryFrom}, iter}; use rustc_hir::def_id::DefId; use rustc::mir; @@ -250,7 +250,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx MiriMemoryKind::Rust.into(), ); // We just allocated this, the access is definitely in-bounds. - this.memory.write_bytes(ptr.into(), iter::repeat(0u8).take(size as usize)).unwrap(); + this.memory.write_bytes(ptr.into(), iter::repeat(0u8).take(usize::try_from(size).unwrap())).unwrap(); this.write_scalar(ptr, dest)?; } "__rust_dealloc" => { @@ -350,7 +350,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "strlen" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let n = this.memory.read_c_str(ptr)?.len(); - this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_uint(u64::try_from(n).unwrap(), dest.layout.size), dest)?; } // math functions @@ -440,9 +440,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Saturating cast to i16. Even those are outside the valid exponent range to // `scalbn` below will do its over/underflow handling. - let exp = if exp > i16::MAX as i32 { + let exp = if exp > i32::from(i16::MAX) { i16::MAX - } else if exp < i16::MIN as i32 { + } else if exp < i32::from(i16::MIN) { i16::MIN } else { exp.try_into().unwrap() diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index e80908d8fa09..f73ec288284a 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -1,6 +1,8 @@ mod linux; mod macos; +use std::convert::TryFrom; + use crate::*; use rustc::mir; use rustc::ty::layout::{Align, LayoutOf, Size}; @@ -84,7 +86,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx io::stderr().write(buf_cont) }; match res { - Ok(n) => n as i64, + Ok(n) => i64::try_from(n).unwrap(), Err(_) => -1, } } else { diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 8a1ce5594ae4..023fee4ca7b1 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -114,7 +114,7 @@ fn getrandom<'tcx>( // neither of which have any effect on our current PRNG. let _flags = this.read_scalar(args[2])?.to_i32()?; - this.gen_random(ptr, len as usize)?; + this.gen_random(ptr, len)?; this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; Ok(()) } diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 0d067cc04138..34661fb2383c 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -97,7 +97,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "SecRandomCopyBytes" => { let len = this.read_scalar(args[1])?.to_machine_usize(this)?; let ptr = this.read_scalar(args[2])?.not_undef()?; - this.gen_random(ptr, len as usize)?; + this.gen_random(ptr, len)?; this.write_null(dest)?; } diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 623b0f307b91..306d2f7b0e37 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -165,12 +165,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { - let key = this.read_scalar(args[0])?.to_u32()? as u128; + let key = u128::from(this.read_scalar(args[0])?.to_u32()?); let ptr = this.machine.tls.load_tls(key, tcx)?; this.write_scalar(ptr, dest)?; } "TlsSetValue" => { - let key = this.read_scalar(args[0])?.to_u32()? as u128; + let key = u128::from(this.read_scalar(args[0])?.to_u32()?); let new_ptr = this.read_scalar(args[1])?.not_undef()?; this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?; @@ -197,7 +197,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "SystemFunction036" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let len = this.read_scalar(args[1])?.to_u32()?; - this.gen_random(ptr, len as usize)?; + this.gen_random(ptr, len.into())?; this.write_scalar(Scalar::from_bool(true), dest)?; } // We don't support threading. diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 0ea53b16fd19..7c755143f2e8 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -10,7 +10,7 @@ use rustc::ty::layout::{Align, LayoutOf, Size}; use crate::stacked_borrows::Tag; use crate::*; -use helpers::immty_from_uint_checked; +use helpers::{immty_from_int_checked, immty_from_uint_checked}; use shims::time::system_time_to_duration; #[derive(Debug)] @@ -56,7 +56,7 @@ impl FileHandler { let new_fd = candidate_new_fd.unwrap_or_else(|| { // find_map ran out of BTreeMap entries before finding a free fd, use one plus the // maximum fd in the map - self.handles.last_entry().map(|entry| entry.key() + 1).unwrap_or(min_fd) + self.handles.last_entry().map(|entry| entry.key().checked_add(1).unwrap()).unwrap_or(min_fd) }); self.handles.insert(new_fd, file_handle).unwrap_none(); @@ -167,11 +167,11 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' match file_type { Ok(file_type) => { if file_type.is_dir() { - Ok(this.eval_libc("DT_DIR")?.to_u8()? as i32) + Ok(this.eval_libc("DT_DIR")?.to_u8()?.into()) } else if file_type.is_file() { - Ok(this.eval_libc("DT_REG")?.to_u8()? as i32) + Ok(this.eval_libc("DT_REG")?.to_u8()?.into()) } else if file_type.is_symlink() { - Ok(this.eval_libc("DT_LNK")?.to_u8()? as i32) + Ok(this.eval_libc("DT_LNK")?.to_u8()?.into()) } else { // Certain file types are only supported when the host is a Unix system. // (i.e. devices and sockets) If it is, check those cases, if not, fall back to @@ -181,19 +181,19 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' { use std::os::unix::fs::FileTypeExt; if file_type.is_block_device() { - Ok(this.eval_libc("DT_BLK")?.to_u8()? as i32) + Ok(this.eval_libc("DT_BLK")?.to_u8()?.into()) } else if file_type.is_char_device() { - Ok(this.eval_libc("DT_CHR")?.to_u8()? as i32) + Ok(this.eval_libc("DT_CHR")?.to_u8()?.into()) } else if file_type.is_fifo() { - Ok(this.eval_libc("DT_FIFO")?.to_u8()? as i32) + Ok(this.eval_libc("DT_FIFO")?.to_u8()?.into()) } else if file_type.is_socket() { - Ok(this.eval_libc("DT_SOCK")?.to_u8()? as i32) + Ok(this.eval_libc("DT_SOCK")?.to_u8()?.into()) } else { - Ok(this.eval_libc("DT_UNKNOWN")?.to_u8()? as i32) + Ok(this.eval_libc("DT_UNKNOWN")?.to_u8()?.into()) } } #[cfg(not(unix))] - Ok(this.eval_libc("DT_UNKNOWN")?.to_u8()? as i32) + Ok(this.eval_libc("DT_UNKNOWN")?.to_u8()?.into()) } } Err(e) => return match e.raw_os_error() { @@ -507,7 +507,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let whence = this.read_scalar(whence_op)?.to_i32()?; let seek_from = if whence == this.eval_libc_i32("SEEK_SET")? { - SeekFrom::Start(offset as u64) + SeekFrom::Start(u64::try_from(offset).unwrap()) } else if whence == this.eval_libc_i32("SEEK_CUR")? { SeekFrom::Current(offset) } else if whence == this.eval_libc_i32("SEEK_END")? { @@ -519,7 +519,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { - let result = file.seek(seek_from).map(|offset| offset as i64); + let result = file.seek(seek_from).map(|offset| i64::try_from(offset).unwrap()); this.try_unwrap_io_result(result) } else { this.handle_not_found() @@ -810,7 +810,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("mkdir")?; let _mode = if this.tcx.sess.target.target.target_os.as_str() == "macos" { - this.read_scalar(mode_op)?.not_undef()?.to_u16()? as u32 + u32::from(this.read_scalar(mode_op)?.not_undef()?.to_u16()?) } else { this.read_scalar(mode_op)?.to_u32()? }; @@ -929,13 +929,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[cfg(not(unix))] let ino = 0u64; - let file_type = this.file_type_to_d_type(dir_entry.file_type())? as u128; + let file_type = this.file_type_to_d_type(dir_entry.file_type())?; let imms = [ immty_from_uint_checked(ino, ino64_t_layout)?, // d_ino immty_from_uint_checked(0u128, off64_t_layout)?, // d_off immty_from_uint_checked(0u128, c_ushort_layout)?, // d_reclen - immty_from_uint_checked(file_type, c_uchar_layout)?, // d_type + immty_from_int_checked(file_type, c_uchar_layout)?, // d_type ]; this.write_packed_immediates(entry_place, &imms)?; @@ -1017,14 +1017,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[cfg(not(unix))] let ino = 0u64; - let file_type = this.file_type_to_d_type(dir_entry.file_type())? as u128; + let file_type = this.file_type_to_d_type(dir_entry.file_type())?; let imms = [ immty_from_uint_checked(ino, ino_t_layout)?, // d_ino immty_from_uint_checked(0u128, off_t_layout)?, // d_seekoff immty_from_uint_checked(0u128, c_ushort_layout)?, // d_reclen immty_from_uint_checked(file_name_len, c_ushort_layout)?, // d_namlen - immty_from_uint_checked(file_type, c_uchar_layout)?, // d_type + immty_from_int_checked(file_type, c_uchar_layout)?, // d_type ]; this.write_packed_immediates(entry_place, &imms)?; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index b91af778d979..6837d45158d9 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -1,4 +1,5 @@ use std::iter; +use std::convert::TryFrom; use rustc::mir; use rustc::mir::interpret::{InterpResult, PointerArithmetic}; @@ -48,7 +49,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.read_scalar(args[0])?.not_undef()?; let pointee_ty = substs.type_at(0); - let pointee_size = this.layout_of(pointee_ty)?.size.bytes() as i64; + let pointee_size = i64::try_from(this.layout_of(pointee_ty)?.size.bytes()).unwrap(); let offset = offset.overflowing_mul(pointee_size).0; let result_ptr = ptr.ptr_wrapping_signed_offset(offset, this); this.write_scalar(result_ptr, dest)?; @@ -229,7 +230,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let count = this.read_scalar(args[2])?.to_machine_usize(this)?; let elem_align = elem_layout.align.abi; - let size = Size::from_bytes(count * elem_size); + let size = Size::from_bytes(count) * elem_size; let src = this.read_scalar(args[0])?.not_undef()?; let src = this.memory.check_ptr_access(src, size, elem_align)?; let dest = this.read_scalar(args[1])?.not_undef()?; @@ -419,7 +420,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let layout = this.layout_of(ty)?; let align = layout.align.pref.bytes(); let ptr_size = this.pointer_size(); - let align_val = Scalar::from_uint(align as u128, ptr_size); + let align_val = Scalar::from_uint(align, ptr_size); this.write_scalar(align_val, dest)?; } @@ -502,7 +503,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .size_and_align_of_mplace(mplace)? .expect("size_of_val called on extern type"); let ptr_size = this.pointer_size(); - this.write_scalar(Scalar::from_uint(size.bytes() as u128, ptr_size), dest)?; + this.write_scalar(Scalar::from_uint(size.bytes(), ptr_size), dest)?; } #[rustfmt::skip] diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 6adf01385855..d9e4d226ecc9 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -7,9 +7,12 @@ pub mod panic; pub mod time; pub mod tls; -use crate::*; +use std::convert::TryFrom; + use rustc::{mir, ty}; +use crate::*; + impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn find_mir_or_eval_fn( @@ -54,8 +57,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (dest, ret) = ret.unwrap(); let req_align = this - .force_bits(this.read_scalar(align_op)?.not_undef()?, this.pointer_size())? - as usize; + .force_bits(this.read_scalar(align_op)?.not_undef()?, this.pointer_size())?; // Stop if the alignment is not a power of two. if !req_align.is_power_of_two() { @@ -69,12 +71,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Ok(ptr) = this.force_ptr(ptr_scalar) { // Only do anything if we can identify the allocation this goes to. let cur_align = - this.memory.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead)?.1.bytes() - as usize; - if cur_align >= req_align { + this.memory.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead)?.1.bytes(); + if u128::from(cur_align) >= req_align { // If the allocation alignment is at least the required alignment we use the - // libcore implementation - result = (this.force_bits(ptr_scalar, this.pointer_size())? as *const i8).align_offset(req_align) as u128; + // libcore implementation. + // FIXME: is this correct in case of truncation? + result = u128::try_from( + (this.force_bits(ptr_scalar, this.pointer_size())? as *const i8) + .align_offset(usize::try_from(req_align).unwrap()) + ).unwrap(); } } diff --git a/src/shims/time.rs b/src/shims/time.rs index 6adea524d2d8..d761698e0d27 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -37,8 +37,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tp = this.deref_operand(tp_op)?; let duration = get_time()?; - let tv_sec = duration.as_secs() as i128; - let tv_nsec = duration.subsec_nanos() as i128; + let tv_sec = duration.as_secs(); + let tv_nsec = duration.subsec_nanos(); let imms = [ immty_from_int_checked(tv_sec, this.libc_ty_layout("time_t")?)?, @@ -69,8 +69,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tv = this.deref_operand(tv_op)?; let duration = get_time()?; - let tv_sec = duration.as_secs() as i128; - let tv_usec = duration.subsec_micros() as i128; + let tv_sec = duration.as_secs(); + let tv_usec = duration.subsec_micros(); let imms = [ immty_from_int_checked(tv_sec, this.libc_ty_layout("time_t")?)?, From b82cf36117dc23f18e39c4136aa63e99bc48ae03 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 17 Mar 2020 20:53:34 +0100 Subject: [PATCH 1658/5092] rustup; remove no longer existing intrinsics --- rust-version | 2 +- src/shims/intrinsics.rs | 66 +---------------------------------------- 2 files changed, 2 insertions(+), 66 deletions(-) diff --git a/rust-version b/rust-version index dce708705b33..1c3f12298f86 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -dd67187965e136bff1ed05e035293441c60f0790 +660326e9791d5caf3186b14521498c2584a494ab diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 6837d45158d9..7f437332d932 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -4,7 +4,7 @@ use std::convert::TryFrom; use rustc::mir; use rustc::mir::interpret::{InterpResult, PointerArithmetic}; use rustc::ty; -use rustc::ty::layout::{self, Align, LayoutOf, Size}; +use rustc::ty::layout::{Align, LayoutOf, Size}; use rustc_apfloat::Float; use rustc_span::source_map::Span; @@ -384,37 +384,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_immediate(*b, dest)?; } - "init" => { - // Check fast path: we don't want to force an allocation in case the destination is a simple value, - // but we also do not want to create a new allocation with 0s and then copy that over. - // FIXME: We do not properly validate in case of ZSTs and when doing it in memory! - // However, this only affects direct calls of the intrinsic; calls to the stable - // functions wrapping them do get their validation. - // FIXME: should we check that the destination pointer is aligned even for ZSTs? - if !dest.layout.is_zst() { - match dest.layout.abi { - layout::Abi::Scalar(ref s) => { - let x = Scalar::from_int(0, s.value.size(this)); - this.write_scalar(x, dest)?; - } - layout::Abi::ScalarPair(ref s1, ref s2) => { - let x = Scalar::from_int(0, s1.value.size(this)); - let y = Scalar::from_int(0, s2.value.size(this)); - this.write_immediate(Immediate::ScalarPair(x.into(), y.into()), dest)?; - } - _ => { - // Do it in memory - let mplace = this.force_allocation(dest)?; - assert!(!mplace.layout.is_unsized()); - this.memory.write_bytes( - mplace.ptr, - iter::repeat(0u8).take(dest.layout.size.bytes() as usize), - )?; - } - } - } - } - "pref_align_of" => { let ty = substs.type_at(0); let layout = this.layout_of(ty)?; @@ -518,39 +487,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_uint(align.bytes(), ptr_size), dest)?; } - "uninit" => { - // Check fast path: we don't want to force an allocation in case the destination is a simple value, - // but we also do not want to create a new allocation with 0s and then copy that over. - // FIXME: We do not properly validate in case of ZSTs and when doing it in memory! - // However, this only affects direct calls of the intrinsic; calls to the stable - // functions wrapping them do get their validation. - // FIXME: should we check alignment for ZSTs? - if !dest.layout.is_zst() { - match dest.layout.abi { - layout::Abi::Scalar(..) => { - let x = ScalarMaybeUndef::Undef; - this.write_immediate(Immediate::Scalar(x), dest)?; - } - layout::Abi::ScalarPair(..) => { - let x = ScalarMaybeUndef::Undef; - this.write_immediate(Immediate::ScalarPair(x, x), dest)?; - } - _ => { - // Do it in memory - let mplace = this.force_allocation(dest)?; - assert!(!mplace.layout.is_unsized()); - let ptr = mplace.ptr.assert_ptr(); - // We know the return place is in-bounds - this.memory.get_raw_mut(ptr.alloc_id)?.mark_definedness( - ptr, - dest.layout.size, - false, - ); - } - } - } - } - "write_bytes" => { let ty = substs.type_at(0); let ty_layout = this.layout_of(ty)?; From a32e25677f43d161db8fdb923cb80a7dc7c4ae48 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 18 Mar 2020 11:19:01 +0100 Subject: [PATCH 1659/5092] move repeated run of test suite (without and with MIR optimizations) out of compiletest --- README.md | 2 ++ tests/compiletest.rs | 57 ++++++++++++++++---------------------------- travis.sh | 1 + 3 files changed, 24 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 3d7003af72e4..a1b978316684 100644 --- a/README.md +++ b/README.md @@ -193,6 +193,8 @@ Moreover, Miri recognizes some environment variables: * `MIRI_TEST_TARGET` (recognized by the test suite) indicates which target architecture to test against. `miri` and `cargo miri` accept the `--target` flag for the same purpose. +* `MIRI_TEST_FLAGS` (recognized by the test suite) defines extra flags to be + passed to Miri. ## Contributing and getting help diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 9cead530b57c..f43ff8ca349d 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -24,9 +24,10 @@ fn rustc_lib_path() -> PathBuf { option_env!("RUSTC_LIB_PATH").unwrap().into() } -fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec) { +fn run_tests(mode: &str, path: &str, target: &str) { let in_rustc_test_suite = rustc_test_suite().is_some(); // Add some flags we always want. + let mut flags = Vec::new(); flags.push("--edition 2018".to_owned()); if in_rustc_test_suite { // Less aggressive warnings to make the rustc toolstate management less painful. @@ -38,6 +39,12 @@ fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec) { if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") { flags.push(format!("--sysroot {}", sysroot)); } + if let Ok(extra_flags) = std::env::var("MIRI_TEST_FLAGS") { + flags.push(extra_flags); + } + + let flags = flags.join(" "); + eprintln!(" Compiler flags: {}", flags); // The rest of the configuration. let mut config = compiletest::Config::default().tempdir(); @@ -51,48 +58,36 @@ fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec) { config.host = get_host(); config.src_base = PathBuf::from(path); config.target = target.to_owned(); - config.target_rustcflags = Some(flags.join(" ")); + config.target_rustcflags = Some(flags); compiletest::run_tests(&config); } -fn compile_fail(path: &str, target: &str, opt: bool) { - let opt_str = if opt { " with optimizations" } else { "" }; +fn compile_fail(path: &str, target: &str) { eprintln!( "{}", format!( - "## Running compile-fail tests in {} against miri for target {}{}", - path, target, opt_str + "## Running compile-fail tests in {} against miri for target {}", + path, target ) .green() .bold() ); - let mut flags = Vec::new(); - if opt { - flags.push("-Zmir-opt-level=3".to_owned()); - } - - run_tests("compile-fail", path, target, flags); + run_tests("compile-fail", path, target); } -fn miri_pass(path: &str, target: &str, opt: bool) { - let opt_str = if opt { " with optimizations" } else { "" }; +fn miri_pass(path: &str, target: &str) { eprintln!( "{}", format!( - "## Running run-pass tests in {} against miri for target {}{}", - path, target, opt_str + "## Running run-pass tests in {} against miri for target {}", + path, target ) .green() .bold() ); - let mut flags = Vec::new(); - if opt { - flags.push("-Zmir-opt-level=3".to_owned()); - } - - run_tests("ui", path, target, flags); + run_tests("ui", path, target); } fn get_host() -> String { @@ -112,21 +107,11 @@ fn get_target() -> String { std::env::var("MIRI_TEST_TARGET").unwrap_or_else(|_| get_host()) } -fn run_pass_miri(opt: bool) { - miri_pass("tests/run-pass", &get_target(), opt); -} - -fn compile_fail_miri(opt: bool) { - compile_fail("tests/compile-fail", &get_target(), opt); -} - fn test_runner(_tests: &[&()]) { - // Add a test env var to do environment communication tests + // Add a test env var to do environment communication tests. std::env::set_var("MIRI_ENV_VAR_TEST", "0"); - run_pass_miri(false); - run_pass_miri(true); - - compile_fail_miri(false); - compile_fail_miri(true); + let target = get_target(); + miri_pass("tests/run-pass", &target); + compile_fail("tests/compile-fail", &target); } diff --git a/travis.sh b/travis.sh index 3d4b8651fb83..fec9145ab0f7 100755 --- a/travis.sh +++ b/travis.sh @@ -17,6 +17,7 @@ echo # Test function run_tests { ./miri test --locked + MIRI_TEST_FLAGS="-Z mir-opt-level=3" ./miri test # "miri test" has built the sysroot for us, now this should pass without # any interactive questions. test-cargo-miri/run-test.py From 1b8979c8c7fc03bd5b9a686d87b6970232099fd6 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 18 Mar 2020 13:16:37 +0200 Subject: [PATCH 1660/5092] Add an optional message to abort --- src/diagnostics.rs | 3 ++- src/eval.rs | 2 +- src/machine.rs | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index fb6598495af5..b2590a843ba9 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -20,7 +20,8 @@ pub fn report_diagnostic<'tcx, 'mir>( let info = info.downcast_ref::().expect("invalid MachineStop payload"); match info { TerminationInfo::Exit(code) => return Some(*code), - TerminationInfo::Abort => format!("the evaluated program aborted execution"), + TerminationInfo::Abort(None) => format!("the evaluated program aborted execution"), + TerminationInfo::Abort(Some(msg)) => format!("the evaluated program aborted execution: {}", msg), } } err_unsup!(NoMirFor(..)) => format!( diff --git a/src/eval.rs b/src/eval.rs index 2cf5a1dc444c..7d42db689432 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -53,7 +53,7 @@ impl Default for MiriConfig { /// Details of premature program termination. pub enum TerminationInfo { Exit(i64), - Abort, + Abort(Option), } /// Returns a freshly created `InterpCx`, along with an `MPlaceTy` representing diff --git a/src/machine.rs b/src/machine.rs index d94c6928cfe0..3a8e7fc90241 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -273,7 +273,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, !> { - throw_machine_stop!(TerminationInfo::Abort) + throw_machine_stop!(TerminationInfo::Abort(None)) } #[inline(always)] From 52e1372e038d0372c7435b50e7d6e98a15b9a02f Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 18 Mar 2020 13:17:18 +0200 Subject: [PATCH 1661/5092] Abort instead of panic in asserting intrinsics, because they might not be panic safe --- src/shims/intrinsics.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index b91af778d979..112b4f3c0040 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -440,15 +440,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "assert_uninit_valid" => { let ty = substs.type_at(0); let layout = this.layout_of(ty)?; - // Return here because we panicked instead of returning normally from the intrinsic. + // Abort here because the caller might not be panic safe. if layout.abi.is_uninhabited() { - return this.start_panic(&format!("attempted to instantiate uninhabited type `{}`", ty), unwind); + throw_machine_stop!(TerminationInfo::Abort(Some(format!("attempted to instantiate uninhabited type `{}`", ty)))) } if intrinsic_name == "assert_zero_valid" && !layout.might_permit_raw_init(this, /*zero:*/ true).unwrap() { - return this.start_panic(&format!("attempted to zero-initialize type `{}`, which is invalid", ty), unwind); + throw_machine_stop!(TerminationInfo::Abort(Some(format!("attempted to zero-initialize type `{}`, which is invalid", ty)))) } if intrinsic_name == "assert_uninit_valid" && !layout.might_permit_raw_init(this, /*zero:*/ false).unwrap() { - return this.start_panic(&format!("attempted to leave type `{}` uninitialized, which is invalid", ty), unwind); + throw_machine_stop!(TerminationInfo::Abort(Some(format!("attempted to leave type `{}` uninitialized, which is invalid", ty)))) } } From 0826899ca04af6700269bde37137ab41d2f4dae5 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 18 Mar 2020 13:18:08 +0200 Subject: [PATCH 1662/5092] Remove uninhabit/zeroed tests to a new test file for abort checking --- tests/compile-fail/invalid_zero_init.rs | 6 +++ tests/compile-fail/uninit_uninhabited_type.rs | 7 ++++ tests/run-pass/panic/catch_panic.rs | 37 ------------------- tests/run-pass/panic/catch_panic.stderr | 20 +--------- 4 files changed, 15 insertions(+), 55 deletions(-) create mode 100644 tests/compile-fail/invalid_zero_init.rs create mode 100644 tests/compile-fail/uninit_uninhabited_type.rs diff --git a/tests/compile-fail/invalid_zero_init.rs b/tests/compile-fail/invalid_zero_init.rs new file mode 100644 index 000000000000..78c2b0fbeeb7 --- /dev/null +++ b/tests/compile-fail/invalid_zero_init.rs @@ -0,0 +1,6 @@ + // error-pattern: the evaluated program aborted execution: attempted to zero-initialize type `fn()`, which is invalid + +#[allow(deprecated, invalid_value)] +fn main() { + unsafe { std::mem::zeroed::() }; +} diff --git a/tests/compile-fail/uninit_uninhabited_type.rs b/tests/compile-fail/uninit_uninhabited_type.rs new file mode 100644 index 000000000000..b9048830783f --- /dev/null +++ b/tests/compile-fail/uninit_uninhabited_type.rs @@ -0,0 +1,7 @@ + // error-pattern: the evaluated program aborted execution: attempted to instantiate uninhabited type `!` +#![feature(never_type)] + +#[allow(deprecated, invalid_value)] +fn main() { + unsafe { std::mem::uninitialized::() }; +} diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index cc97ba5a85d2..6408c940d98a 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -67,43 +67,6 @@ fn main() { |_old_val| { let _val = 1/0; loop {} }, ); - // libcore panics from shims. - #[allow(deprecated, invalid_value)] - { - test( - Some("attempted to instantiate uninhabited type `!`"), - |_old_val| unsafe { std::mem::uninitialized::() }, - ); - test( - Some("attempted to instantiate uninhabited type `!`"), - |_old_val| unsafe { std::mem::zeroed::() }, - ); - test( - Some("attempted to leave type `fn()` uninitialized, which is invalid"), - |_old_val| unsafe { std::mem::uninitialized::(); loop {} }, - ); - test( - Some("attempted to zero-initialize type `fn()`, which is invalid"), - |_old_val| unsafe { std::mem::zeroed::(); loop {} }, - ); - test( - Some("attempted to leave type `*const dyn std::marker::Sync` uninitialized, which is invalid"), - |_old_val| unsafe { std::mem::uninitialized::<*const dyn Sync>(); loop {} }, - ); - test( - Some("attempted to zero-initialize type `*mut dyn std::marker::Sync`, which is invalid"), - |_old_val| unsafe { std::mem::zeroed::<*mut dyn Sync>(); loop {} }, - ); - test( - Some("attempted to leave type `&u8` uninitialized, which is invalid"), - |_old_val| unsafe { std::mem::uninitialized::<&u8>(); loop {} }, - ); - test( - Some("attempted to zero-initialize type `&u8`, which is invalid"), - |_old_val| unsafe { std::mem::zeroed::<&u8>(); loop {} }, - ); - } - test( Some("align_offset: align is not a power-of-two"), |_old_val| { (0usize as *const u8).align_offset(3); loop {} }, diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr index 8d97fd6321f1..6da9cd29963a 100644 --- a/tests/run-pass/panic/catch_panic.stderr +++ b/tests/run-pass/panic/catch_panic.stderr @@ -16,27 +16,11 @@ thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4' Caught panic message (String): index out of bounds: the len is 3 but the index is 4 thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:67:33 Caught panic message (String): attempt to divide by zero -thread 'main' panicked at 'attempted to instantiate uninhabited type `!`', $LOC -Caught panic message (String): attempted to instantiate uninhabited type `!` -thread 'main' panicked at 'attempted to instantiate uninhabited type `!`', $LOC -Caught panic message (String): attempted to instantiate uninhabited type `!` -thread 'main' panicked at 'attempted to leave type `fn()` uninitialized, which is invalid', $LOC -Caught panic message (String): attempted to leave type `fn()` uninitialized, which is invalid -thread 'main' panicked at 'attempted to zero-initialize type `fn()`, which is invalid', $LOC -Caught panic message (String): attempted to zero-initialize type `fn()`, which is invalid -thread 'main' panicked at 'attempted to leave type `*const dyn std::marker::Sync` uninitialized, which is invalid', $LOC -Caught panic message (String): attempted to leave type `*const dyn std::marker::Sync` uninitialized, which is invalid -thread 'main' panicked at 'attempted to zero-initialize type `*mut dyn std::marker::Sync`, which is invalid', $LOC -Caught panic message (String): attempted to zero-initialize type `*mut dyn std::marker::Sync`, which is invalid -thread 'main' panicked at 'attempted to leave type `&u8` uninitialized, which is invalid', $LOC -Caught panic message (String): attempted to leave type `&u8` uninitialized, which is invalid -thread 'main' panicked at 'attempted to zero-initialize type `&u8`, which is invalid', $LOC -Caught panic message (String): attempted to zero-initialize type `&u8`, which is invalid thread 'main' panicked at 'align_offset: align is not a power-of-two', $LOC Caught panic message (String): align_offset: align is not a power-of-two -thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:113:29 +thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:76:29 Caught panic message (&str): assertion failed: false -thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:114:29 +thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:77:29 Caught panic message (&str): assertion failed: false thread 'main' panicked at 'attempt to copy from unaligned or null pointer', $LOC Caught panic message (String): attempt to copy from unaligned or null pointer From 1103a10e2c1c9d3c6d9aeafb5154a5f5ef0495ea Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 8 Mar 2020 23:34:54 +0100 Subject: [PATCH 1663/5092] adjust for error reform --- src/helpers.rs | 3 +- src/intptrcast.rs | 8 +--- src/shims/foreign_items.rs | 41 ++++++++----------- src/shims/foreign_items/posix.rs | 11 ++--- src/shims/foreign_items/windows.rs | 9 +--- src/shims/tls.rs | 18 +++++--- tests/compile-fail/alignment.rs | 2 +- tests/compile-fail/atomic_unaligned.rs | 2 +- tests/compile-fail/cast_box_int_to_fn_ptr.rs | 2 +- tests/compile-fail/cast_fn_ptr1.rs | 2 +- tests/compile-fail/cast_fn_ptr2.rs | 2 +- tests/compile-fail/cast_fn_ptr3.rs | 2 +- tests/compile-fail/cast_fn_ptr4.rs | 2 +- tests/compile-fail/cast_fn_ptr5.rs | 2 +- tests/compile-fail/cast_int_to_fn_ptr.rs | 2 +- tests/compile-fail/copy_unaligned.rs | 2 +- tests/compile-fail/dangling_pointer_deref.rs | 2 +- tests/compile-fail/dangling_zst_deref.rs | 2 +- .../compile-fail/deallocate-bad-alignment.rs | 2 +- tests/compile-fail/deallocate-bad-size.rs | 2 +- tests/compile-fail/deallocate-twice.rs | 2 +- tests/compile-fail/deref-invalid-ptr.rs | 2 +- .../compile-fail/deref-partially-dangling.rs | 2 +- tests/compile-fail/deref_fn_ptr.rs | 2 +- .../compile-fail/environ-gets-deallocated.rs | 2 +- tests/compile-fail/execute_memory.rs | 2 +- tests/compile-fail/fn_ptr_offset.rs | 2 +- tests/compile-fail/generator-pinned-moved.rs | 2 +- .../intptrcast_alignment_check.rs | 2 +- tests/compile-fail/invalid_bool.rs | 2 +- tests/compile-fail/invalid_char.rs | 2 +- tests/compile-fail/modifying_constants.rs | 2 +- tests/compile-fail/out_of_bounds_ptr_1.rs | 2 +- tests/compile-fail/out_of_bounds_read1.rs | 2 +- tests/compile-fail/out_of_bounds_read2.rs | 2 +- ..._of_relocation_makes_the_rest_undefined.rs | 2 +- tests/compile-fail/pointer_byte_read.rs | 2 +- tests/compile-fail/ptr_offset_int_plus_int.rs | 2 +- tests/compile-fail/ptr_offset_int_plus_ptr.rs | 2 +- tests/compile-fail/ptr_offset_ptr_plus_0.rs | 2 +- tests/compile-fail/rc_as_raw.rs | 2 +- tests/compile-fail/reading_half_a_pointer.rs | 2 +- tests/compile-fail/reallocate-bad-size.rs | 2 +- tests/compile-fail/reallocate-change-alloc.rs | 2 +- tests/compile-fail/reallocate-dangling.rs | 2 +- tests/compile-fail/reference_to_packed.rs | 2 +- tests/compile-fail/stack_free.rs | 2 +- .../stacked_borrows/issue-miri-1050-2.rs | 2 +- .../static_memory_modification1.rs | 2 +- .../static_memory_modification2.rs | 2 +- .../static_memory_modification3.rs | 2 +- tests/compile-fail/storage_dead_dangling.rs | 2 +- tests/compile-fail/transmute-pair-undef.rs | 2 +- tests/compile-fail/transmute_fat1.rs | 2 +- tests/compile-fail/unaligned_ptr1.rs | 2 +- tests/compile-fail/unaligned_ptr2.rs | 2 +- tests/compile-fail/unaligned_ptr3.rs | 2 +- tests/compile-fail/unaligned_ptr_zst.rs | 2 +- tests/compile-fail/undefined_byte_read.rs | 2 +- tests/compile-fail/validity/dangling_ref1.rs | 2 +- tests/compile-fail/validity/dangling_ref2.rs | 2 +- tests/compile-fail/wild_pointer_deref.rs | 2 +- tests/compile-fail/zst2.rs | 2 +- 63 files changed, 93 insertions(+), 111 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index ecb3a5d8bce9..ff4df42dde66 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -42,8 +42,7 @@ fn resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> InterpResult<'tc None }) .ok_or_else(|| { - let path = path.iter().map(|&s| s.to_owned()).collect(); - err_unsup!(PathNotFound(path)).into() + err_unsup_format!("failed to find required Rust item: {:?}", path).into() }) } diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 91d9f4e84ee3..20a3b7998047 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -43,10 +43,6 @@ impl<'mir, 'tcx> GlobalState { int: u64, memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>, ) -> InterpResult<'tcx, Pointer> { - if int == 0 { - throw_unsup!(InvalidNullPointerUsage); - } - let global_state = memory.extra.intptrcast.borrow(); let pos = global_state.int_to_ptr_map.binary_search_by_key(&int, |(addr, _)| *addr); @@ -57,7 +53,7 @@ impl<'mir, 'tcx> GlobalState { // zero. The pointer is untagged because it was created from a cast Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged) } - Err(0) => throw_unsup!(DanglingPointerDeref), + Err(0) => throw_ub!(InvalidIntPointerUsage(int)), Err(pos) => { // This is the largest of the adresses smaller than `int`, // i.e. the greatest lower bound (glb) @@ -69,7 +65,7 @@ impl<'mir, 'tcx> GlobalState { // This pointer is untagged because it was created from a cast Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged) } else { - throw_unsup!(DanglingPointerDeref) + throw_ub!(InvalidIntPointerUsage(int)) } } }) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index deabbdd60819..4c7bcff267e1 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -222,12 +222,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "__rust_alloc" => { let size = this.read_scalar(args[0])?.to_machine_usize(this)?; let align = this.read_scalar(args[1])?.to_machine_usize(this)?; - if size == 0 { - throw_unsup!(HeapAllocZeroBytes); - } - if !align.is_power_of_two() { - throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); - } + Self::check_alloc_request(size, align)?; let ptr = this.memory.allocate( Size::from_bytes(size), Align::from_bytes(align).unwrap(), @@ -238,12 +233,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "__rust_alloc_zeroed" => { let size = this.read_scalar(args[0])?.to_machine_usize(this)?; let align = this.read_scalar(args[1])?.to_machine_usize(this)?; - if size == 0 { - throw_unsup!(HeapAllocZeroBytes); - } - if !align.is_power_of_two() { - throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); - } + Self::check_alloc_request(size, align)?; let ptr = this.memory.allocate( Size::from_bytes(size), Align::from_bytes(align).unwrap(), @@ -257,12 +247,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.read_scalar(args[0])?.not_undef()?; let old_size = this.read_scalar(args[1])?.to_machine_usize(this)?; let align = this.read_scalar(args[2])?.to_machine_usize(this)?; - if old_size == 0 { - throw_unsup!(HeapAllocZeroBytes); - } - if !align.is_power_of_two() { - throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); - } + // No need to check old_size/align; we anyway check that they match the allocation. let ptr = this.force_ptr(ptr)?; this.memory.deallocate( ptr, @@ -274,12 +259,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let old_size = this.read_scalar(args[1])?.to_machine_usize(this)?; let align = this.read_scalar(args[2])?.to_machine_usize(this)?; let new_size = this.read_scalar(args[3])?.to_machine_usize(this)?; - if old_size == 0 || new_size == 0 { - throw_unsup!(HeapAllocZeroBytes); - } - if !align.is_power_of_two() { - throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); - } + Self::check_alloc_request(new_size, align)?; + // No need to check old_size; we anyway check that they match the allocation. let ptr = this.force_ptr(this.read_scalar(args[0])?.not_undef()?)?; let align = Align::from_bytes(align).unwrap(); let new_ptr = this.memory.reallocate( @@ -462,6 +443,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(true) } + /// Check some basic requirements for this allocation request: + /// non-zero size, power-of-two alignment. + fn check_alloc_request(size: u64, align: u64) -> InterpResult<'tcx> { + if size == 0 { + throw_ub_format!("creating allocation with size 0"); + } + if !align.is_power_of_two() { + throw_ub_format!("creating allocation with non-power-of-two alignment {}", align); + } + Ok(()) + } + /// Evaluates the scalar at the specified path. Returns Some(val) /// if the path could be resolved, and None otherwise fn eval_path_scalar( diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index f73ec288284a..60b9aa6efcca 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -138,7 +138,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let size = this.read_scalar(args[2])?.to_machine_usize(this)?; // Align must be power of 2, and also at least ptr-sized (POSIX rules). if !align.is_power_of_two() { - throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); + throw_ub_format!("posix_memalign: alignment must be a power of two, but is {}", align); } if align < this.pointer_size().bytes() { throw_ub_format!( @@ -185,7 +185,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Figure out how large a pthread TLS key actually is. - // This is `libc::pthread_key_t`. + // To this end, deref the argument type. This is `libc::pthread_key_t`. let key_type = args[0].layout.ty .builtin_deref(true) .ok_or_else(|| err_ub_format!( @@ -195,12 +195,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let key_layout = this.layout_of(key_type)?; // Create key and write it into the memory where `key_ptr` wants it. - let key = this.machine.tls.create_tls_key(dtor) as u128; - if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) - { - throw_unsup!(OutOfTls); - } - + let key = this.machine.tls.create_tls_key(dtor, key_layout.size)?; this.write_scalar(Scalar::from_uint(key, key_layout.size), key_place.into())?; // Return success (`0`). diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 306d2f7b0e37..a35734573f29 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -154,14 +154,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This just creates a key; Windows does not natively support TLS destructors. // Create key and return it. - let key = this.machine.tls.create_tls_key(None) as u128; - - // Figure out how large a TLS key actually is. This is `c::DWORD`. - if dest.layout.size.bits() < 128 - && key >= (1u128 << dest.layout.size.bits() as u128) - { - throw_unsup!(OutOfTls); - } + let key = this.machine.tls.create_tls_key(None, dest.layout.size)?; this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { diff --git a/src/shims/tls.rs b/src/shims/tls.rs index cdfc0bcda8b6..094b58d99a28 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; -use rustc::{ty, ty::layout::HasDataLayout}; +use rustc::{ty, ty::layout::{Size, HasDataLayout}}; use rustc_target::abi::LayoutOf; use crate::{HelpersEvalContextExt, InterpResult, MPlaceTy, Scalar, StackPopCleanup, Tag}; @@ -37,12 +37,18 @@ impl<'tcx> Default for TlsData<'tcx> { } impl<'tcx> TlsData<'tcx> { - pub fn create_tls_key(&mut self, dtor: Option>) -> TlsKey { + /// Generate a new TLS key with the given destructor. + /// `max_size` determines the integer size the key has to fit in. + pub fn create_tls_key(&mut self, dtor: Option>, max_size: Size) -> InterpResult<'tcx, TlsKey> { let new_key = self.next_key; self.next_key += 1; self.keys.insert(new_key, TlsEntry { data: None, dtor }).unwrap_none(); trace!("New TLS key allocated: {} with dtor {:?}", new_key, dtor); - new_key + + if max_size.bits() < 128 && new_key >= (1u128 << max_size.bits() as u128) { + throw_unsup_format!("we ran out of TLS key space"); + } + Ok(new_key) } pub fn delete_tls_key(&mut self, key: TlsKey) -> InterpResult<'tcx> { @@ -51,7 +57,7 @@ impl<'tcx> TlsData<'tcx> { trace!("TLS key {} removed", key); Ok(()) } - None => throw_unsup!(TlsOutOfBounds), + None => throw_ub_format!("removing a non-existig TLS key: {}", key), } } @@ -65,7 +71,7 @@ impl<'tcx> TlsData<'tcx> { trace!("TLS key {} loaded: {:?}", key, data); Ok(data.unwrap_or_else(|| Scalar::ptr_null(cx).into())) } - None => throw_unsup!(TlsOutOfBounds), + None => throw_ub_format!("loading from a non-existing TLS key: {}", key), } } @@ -76,7 +82,7 @@ impl<'tcx> TlsData<'tcx> { *data = new_data; Ok(()) } - None => throw_unsup!(TlsOutOfBounds), + None => throw_ub_format!("storing to a non-existing TLS key: {}", key), } } diff --git a/tests/compile-fail/alignment.rs b/tests/compile-fail/alignment.rs index 4faaa359df62..bac1b92075a7 100644 --- a/tests/compile-fail/alignment.rs +++ b/tests/compile-fail/alignment.rs @@ -5,7 +5,7 @@ fn main() { let x_ptr: *mut u8 = &mut x[0]; let y_ptr = x_ptr as *mut u64; unsafe { - *y_ptr = 42; //~ ERROR tried to access memory with alignment 1, but alignment + *y_ptr = 42; //~ ERROR accessing memory with alignment 1, but alignment } panic!("unreachable in miri"); } diff --git a/tests/compile-fail/atomic_unaligned.rs b/tests/compile-fail/atomic_unaligned.rs index 5d2347c03ffe..bdec0ff504bb 100644 --- a/tests/compile-fail/atomic_unaligned.rs +++ b/tests/compile-fail/atomic_unaligned.rs @@ -7,6 +7,6 @@ fn main() { let zptr = &z as *const _ as *const u64; unsafe { ::std::intrinsics::atomic_load(zptr); - //~^ ERROR tried to access memory with alignment 4, but alignment 8 is required + //~^ ERROR accessing memory with alignment 4, but alignment 8 is required } } diff --git a/tests/compile-fail/cast_box_int_to_fn_ptr.rs b/tests/compile-fail/cast_box_int_to_fn_ptr.rs index 6dad2a472730..9eea9d92dcd7 100644 --- a/tests/compile-fail/cast_box_int_to_fn_ptr.rs +++ b/tests/compile-fail/cast_box_int_to_fn_ptr.rs @@ -7,5 +7,5 @@ fn main() { std::mem::transmute::<&Box, &fn(i32)>(&b) }; - (*g)(42) //~ ERROR tried to treat a memory pointer as a function pointer + (*g)(42) //~ ERROR it does not point to a function } diff --git a/tests/compile-fail/cast_fn_ptr1.rs b/tests/compile-fail/cast_fn_ptr1.rs index 0add977bf97b..3702ec8c94c4 100644 --- a/tests/compile-fail/cast_fn_ptr1.rs +++ b/tests/compile-fail/cast_fn_ptr1.rs @@ -5,5 +5,5 @@ fn main() { std::mem::transmute::(f) }; - g(42) //~ ERROR tried to call a function with incorrect number of arguments + g(42) //~ ERROR calling a function with more arguments than it expected } diff --git a/tests/compile-fail/cast_fn_ptr2.rs b/tests/compile-fail/cast_fn_ptr2.rs index 5af527016fb6..39f0867489ad 100644 --- a/tests/compile-fail/cast_fn_ptr2.rs +++ b/tests/compile-fail/cast_fn_ptr2.rs @@ -5,5 +5,5 @@ fn main() { std::mem::transmute::(f) }; - g(42) //~ ERROR tried to call a function with argument of type (i32, i32) passing data of type i32 + g(42) //~ ERROR calling a function with argument of type (i32, i32) passing data of type i32 } diff --git a/tests/compile-fail/cast_fn_ptr3.rs b/tests/compile-fail/cast_fn_ptr3.rs index 29507e7c7cf5..3523db24fa32 100644 --- a/tests/compile-fail/cast_fn_ptr3.rs +++ b/tests/compile-fail/cast_fn_ptr3.rs @@ -5,6 +5,6 @@ fn main() { std::mem::transmute::(f) }; - g() //~ ERROR tried to call a function with incorrect number of arguments + g() //~ ERROR calling a function with fewer arguments than it requires } diff --git a/tests/compile-fail/cast_fn_ptr4.rs b/tests/compile-fail/cast_fn_ptr4.rs index f9a2cf9f6965..22a36a71cef1 100644 --- a/tests/compile-fail/cast_fn_ptr4.rs +++ b/tests/compile-fail/cast_fn_ptr4.rs @@ -5,5 +5,5 @@ fn main() { std::mem::transmute::(f) }; - g(&42 as *const i32) //~ ERROR tried to call a function with argument of type *const [i32] passing data of type *const i32 + g(&42 as *const i32) //~ ERROR calling a function with argument of type *const [i32] passing data of type *const i32 } diff --git a/tests/compile-fail/cast_fn_ptr5.rs b/tests/compile-fail/cast_fn_ptr5.rs index e4ac95e67676..fb2b4403363e 100644 --- a/tests/compile-fail/cast_fn_ptr5.rs +++ b/tests/compile-fail/cast_fn_ptr5.rs @@ -5,5 +5,5 @@ fn main() { std::mem::transmute:: u32, fn()>(f) }; - g() //~ ERROR tried to call a function with return type u32 passing return place of type () + g() //~ ERROR calling a function with return type u32 passing return place of type () } diff --git a/tests/compile-fail/cast_int_to_fn_ptr.rs b/tests/compile-fail/cast_int_to_fn_ptr.rs index 4fd14751a279..3000779a9330 100644 --- a/tests/compile-fail/cast_int_to_fn_ptr.rs +++ b/tests/compile-fail/cast_int_to_fn_ptr.rs @@ -6,5 +6,5 @@ fn main() { std::mem::transmute::(42) }; - g(42) //~ ERROR dangling pointer was dereferenced + g(42) //~ ERROR invalid use of 42 as a pointer } diff --git a/tests/compile-fail/copy_unaligned.rs b/tests/compile-fail/copy_unaligned.rs index 1a2692978f79..a2a476223918 100644 --- a/tests/compile-fail/copy_unaligned.rs +++ b/tests/compile-fail/copy_unaligned.rs @@ -1,4 +1,4 @@ -//error-pattern: tried to access memory with alignment 1, but alignment 2 is required +//error-pattern: accessing memory with alignment 1, but alignment 2 is required #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd diff --git a/tests/compile-fail/dangling_pointer_deref.rs b/tests/compile-fail/dangling_pointer_deref.rs index e80720773057..f2c7ec584fef 100644 --- a/tests/compile-fail/dangling_pointer_deref.rs +++ b/tests/compile-fail/dangling_pointer_deref.rs @@ -3,6 +3,6 @@ fn main() { let b = Box::new(42); &*b as *const i32 }; - let x = unsafe { *p }; //~ ERROR dangling pointer was dereferenced + let x = unsafe { *p }; //~ ERROR dereferenced after this allocation got freed panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/dangling_zst_deref.rs b/tests/compile-fail/dangling_zst_deref.rs index 0a8480675f3d..13e5f9d32173 100644 --- a/tests/compile-fail/dangling_zst_deref.rs +++ b/tests/compile-fail/dangling_zst_deref.rs @@ -3,5 +3,5 @@ fn main() { let b = Box::new(42); &*b as *const i32 as *const () }; - let _x = unsafe { *p }; //~ ERROR dangling pointer was dereferenced + let _x = unsafe { *p }; //~ ERROR dereferenced after this allocation got freed } diff --git a/tests/compile-fail/deallocate-bad-alignment.rs b/tests/compile-fail/deallocate-bad-alignment.rs index 876339919717..f2cd87bac622 100644 --- a/tests/compile-fail/deallocate-bad-alignment.rs +++ b/tests/compile-fail/deallocate-bad-alignment.rs @@ -5,7 +5,7 @@ extern crate alloc; use alloc::alloc::Global; use std::alloc::{AllocRef, Layout}; -// error-pattern: incorrect alloc info: expected size 1 and align 2, got size 1 and align 1 +// error-pattern: allocation has size 1 and alignment 1, but gave size 1 and alignment 2 fn main() { unsafe { diff --git a/tests/compile-fail/deallocate-bad-size.rs b/tests/compile-fail/deallocate-bad-size.rs index 3b7b3cc6a726..498a662518e5 100644 --- a/tests/compile-fail/deallocate-bad-size.rs +++ b/tests/compile-fail/deallocate-bad-size.rs @@ -5,7 +5,7 @@ extern crate alloc; use alloc::alloc::Global; use std::alloc::{AllocRef, Layout}; -// error-pattern: incorrect alloc info: expected size 2 and align 1, got size 1 and align 1 +// error-pattern: allocation has size 1 and alignment 1, but gave size 2 and alignment 1 fn main() { unsafe { diff --git a/tests/compile-fail/deallocate-twice.rs b/tests/compile-fail/deallocate-twice.rs index ee4c5dbedf90..a851d75b9d5c 100644 --- a/tests/compile-fail/deallocate-twice.rs +++ b/tests/compile-fail/deallocate-twice.rs @@ -5,7 +5,7 @@ extern crate alloc; use alloc::alloc::Global; use std::alloc::{AllocRef, Layout}; -// error-pattern: tried to deallocate dangling pointer +// error-pattern: dereferenced after this allocation got freed fn main() { unsafe { diff --git a/tests/compile-fail/deref-invalid-ptr.rs b/tests/compile-fail/deref-invalid-ptr.rs index 2a8be87e1251..561017293a16 100644 --- a/tests/compile-fail/deref-invalid-ptr.rs +++ b/tests/compile-fail/deref-invalid-ptr.rs @@ -3,5 +3,5 @@ fn main() { let x = 2usize as *const u32; - let _y = unsafe { &*x as *const u32 }; //~ ERROR dangling pointer was dereferenced + let _y = unsafe { &*x as *const u32 }; //~ ERROR invalid use of 2 as a pointer } diff --git a/tests/compile-fail/deref-partially-dangling.rs b/tests/compile-fail/deref-partially-dangling.rs index 221e585c5ff3..a6d3aae414de 100644 --- a/tests/compile-fail/deref-partially-dangling.rs +++ b/tests/compile-fail/deref-partially-dangling.rs @@ -3,6 +3,6 @@ fn main() { let x = (1, 13); let xptr = &x as *const _ as *const (i32, i32, i32); - let val = unsafe { (*xptr).1 }; //~ ERROR pointer must be in-bounds at offset 12, but is outside bounds of allocation + let val = unsafe { (*xptr).1 }; //~ ERROR pointer must be in-bounds at offset 12, but is outside bounds of alloc assert_eq!(val, 13); } diff --git a/tests/compile-fail/deref_fn_ptr.rs b/tests/compile-fail/deref_fn_ptr.rs index ed2ac60f43fe..e604f96ea16f 100644 --- a/tests/compile-fail/deref_fn_ptr.rs +++ b/tests/compile-fail/deref_fn_ptr.rs @@ -2,7 +2,7 @@ fn f() {} fn main() { let x: u8 = unsafe { - *std::mem::transmute::(f) //~ ERROR tried to dereference a function pointer + *std::mem::transmute::(f) //~ ERROR contains a function }; panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/environ-gets-deallocated.rs b/tests/compile-fail/environ-gets-deallocated.rs index 6131613fc00b..dd00aef450cd 100644 --- a/tests/compile-fail/environ-gets-deallocated.rs +++ b/tests/compile-fail/environ-gets-deallocated.rs @@ -20,5 +20,5 @@ fn main() { let pointer = get_environ(); let _x = unsafe { *pointer }; std::env::set_var("FOO", "BAR"); - let _y = unsafe { *pointer }; //~ ERROR dangling pointer was dereferenced + let _y = unsafe { *pointer }; //~ ERROR dereferenced after this allocation got freed } diff --git a/tests/compile-fail/execute_memory.rs b/tests/compile-fail/execute_memory.rs index 295756ef0f56..2e6b58a753cd 100644 --- a/tests/compile-fail/execute_memory.rs +++ b/tests/compile-fail/execute_memory.rs @@ -7,6 +7,6 @@ fn main() { let x = box 42; unsafe { let f = std::mem::transmute::, fn()>(x); - f() //~ ERROR tried to treat a memory pointer as a function pointer + f() //~ ERROR function pointer but it does not point to a function } } diff --git a/tests/compile-fail/fn_ptr_offset.rs b/tests/compile-fail/fn_ptr_offset.rs index 9d29316fe24f..7e509d53c261 100644 --- a/tests/compile-fail/fn_ptr_offset.rs +++ b/tests/compile-fail/fn_ptr_offset.rs @@ -10,5 +10,5 @@ fn main() { let y : *mut u8 = unsafe { mem::transmute(x) }; let y = y.wrapping_offset(1); let x : fn() = unsafe { mem::transmute(y) }; - x(); //~ ERROR tried to use a function pointer after offsetting it + x(); //~ ERROR function pointer but it does not point to a function } diff --git a/tests/compile-fail/generator-pinned-moved.rs b/tests/compile-fail/generator-pinned-moved.rs index 70ceacd8ca6f..8f873f37a5f8 100644 --- a/tests/compile-fail/generator-pinned-moved.rs +++ b/tests/compile-fail/generator-pinned-moved.rs @@ -11,7 +11,7 @@ fn firstn() -> impl Generator { let num = &mut num; yield *num; - *num += 1; //~ ERROR dangling pointer was dereferenced + *num += 1; //~ ERROR dereferenced after this allocation got freed } } diff --git a/tests/compile-fail/intptrcast_alignment_check.rs b/tests/compile-fail/intptrcast_alignment_check.rs index fcf613ace462..1a8df5eacede 100644 --- a/tests/compile-fail/intptrcast_alignment_check.rs +++ b/tests/compile-fail/intptrcast_alignment_check.rs @@ -7,6 +7,6 @@ fn main() { let base_addr = x as *mut _ as usize; let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr+1 }; let u16_ptr = base_addr_aligned as *mut u16; - unsafe { *u16_ptr = 2; } //~ ERROR tried to access memory with alignment 1, but alignment 2 is required + unsafe { *u16_ptr = 2; } //~ ERROR memory with alignment 1, but alignment 2 is required println!("{:?}", x); } diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index e80dc15efaec..6ccea3531636 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -3,5 +3,5 @@ fn main() { let b = unsafe { std::mem::transmute::(2) }; - let _x = b == true; //~ ERROR invalid boolean value read + let _x = b == true; //~ ERROR interpreting an invalid 8-bit value as a bool: 2 } diff --git a/tests/compile-fail/invalid_char.rs b/tests/compile-fail/invalid_char.rs index b67ed9ba520d..ed61fcbe9d52 100644 --- a/tests/compile-fail/invalid_char.rs +++ b/tests/compile-fail/invalid_char.rs @@ -4,5 +4,5 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); let c = unsafe { std::mem::transmute::(-1) }; - let _x = c == 'x'; //~ ERROR tried to interpret an invalid 32-bit value as a char + let _x = c == 'x'; //~ ERROR interpreting an invalid 32-bit value as a char } diff --git a/tests/compile-fail/modifying_constants.rs b/tests/compile-fail/modifying_constants.rs index 9770917b629b..2d18dccd319c 100644 --- a/tests/compile-fail/modifying_constants.rs +++ b/tests/compile-fail/modifying_constants.rs @@ -4,6 +4,6 @@ fn main() { let x = &1; // the `&1` is promoted to a constant, but it used to be that only the pointer is marked static, not the pointee let y = unsafe { &mut *(x as *const i32 as *mut i32) }; - *y = 42; //~ ERROR tried to modify constant memory + *y = 42; //~ ERROR read-only assert_eq!(*x, 42); } diff --git a/tests/compile-fail/out_of_bounds_ptr_1.rs b/tests/compile-fail/out_of_bounds_ptr_1.rs index b46609305368..20bcc36f049d 100644 --- a/tests/compile-fail/out_of_bounds_ptr_1.rs +++ b/tests/compile-fail/out_of_bounds_ptr_1.rs @@ -1,4 +1,4 @@ -// error-pattern: must be in-bounds at offset 5, but is outside bounds of allocation +// error-pattern: must be in-bounds at offset 5, but is outside bounds of alloc fn main() { let v = [0i8; 4]; let x = &v as *const i8; diff --git a/tests/compile-fail/out_of_bounds_read1.rs b/tests/compile-fail/out_of_bounds_read1.rs index 1ab2d9714779..0c175af5266b 100644 --- a/tests/compile-fail/out_of_bounds_read1.rs +++ b/tests/compile-fail/out_of_bounds_read1.rs @@ -1,5 +1,5 @@ fn main() { let v: Vec = vec![1, 2]; - let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR outside bounds of allocation + let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR outside bounds of alloc panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/out_of_bounds_read2.rs b/tests/compile-fail/out_of_bounds_read2.rs index 1ab2d9714779..0c175af5266b 100644 --- a/tests/compile-fail/out_of_bounds_read2.rs +++ b/tests/compile-fail/out_of_bounds_read2.rs @@ -1,5 +1,5 @@ fn main() { let v: Vec = vec![1, 2]; - let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR outside bounds of allocation + let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR outside bounds of alloc panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs b/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs index 5c0d5b463d51..d8182aaae662 100644 --- a/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs +++ b/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs @@ -6,6 +6,6 @@ fn main() { // "attempted to interpret some raw bytes as a pointer address" instead of // "attempted to read undefined bytes" } - let x = *p; //~ ERROR attempted to read undefined bytes + let x = *p; //~ ERROR this operation requires initialized memory panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/pointer_byte_read.rs b/tests/compile-fail/pointer_byte_read.rs index ddb9bc1f995f..2ac27bf2b44d 100644 --- a/tests/compile-fail/pointer_byte_read.rs +++ b/tests/compile-fail/pointer_byte_read.rs @@ -3,5 +3,5 @@ fn main() { let y = &x; let z = &y as *const &i32 as *const u8; // the deref fails, because we are reading only a part of the pointer - let _val = unsafe { *z }; //~ ERROR tried to access part of a pointer value as raw bytes + let _val = unsafe { *z }; //~ ERROR unable to turn this pointer into raw bytes } diff --git a/tests/compile-fail/ptr_offset_int_plus_int.rs b/tests/compile-fail/ptr_offset_int_plus_int.rs index 051874696b11..f0cf00884e15 100644 --- a/tests/compile-fail/ptr_offset_int_plus_int.rs +++ b/tests/compile-fail/ptr_offset_int_plus_int.rs @@ -1,4 +1,4 @@ -// error-pattern: dangling pointer was dereferenced +// error-pattern: invalid use of 1 as a pointer fn main() { // Can't offset an integer pointer by non-zero offset. diff --git a/tests/compile-fail/ptr_offset_int_plus_ptr.rs b/tests/compile-fail/ptr_offset_int_plus_ptr.rs index bd90d0690917..705ca68970a1 100644 --- a/tests/compile-fail/ptr_offset_int_plus_ptr.rs +++ b/tests/compile-fail/ptr_offset_int_plus_ptr.rs @@ -1,4 +1,4 @@ -// error-pattern: dangling pointer was dereferenced +// error-pattern: invalid use of 1 as a pointer fn main() { let ptr = Box::into_raw(Box::new(0u32)); diff --git a/tests/compile-fail/ptr_offset_ptr_plus_0.rs b/tests/compile-fail/ptr_offset_ptr_plus_0.rs index a089a8b82131..d07ecc4dc7f3 100644 --- a/tests/compile-fail/ptr_offset_ptr_plus_0.rs +++ b/tests/compile-fail/ptr_offset_ptr_plus_0.rs @@ -1,4 +1,4 @@ -// error-pattern: outside bounds of allocation +// error-pattern: outside bounds of alloc fn main() { let x = Box::into_raw(Box::new(0u32)); diff --git a/tests/compile-fail/rc_as_raw.rs b/tests/compile-fail/rc_as_raw.rs index 086467eea311..cb50ca5fcece 100644 --- a/tests/compile-fail/rc_as_raw.rs +++ b/tests/compile-fail/rc_as_raw.rs @@ -17,5 +17,5 @@ fn main() { drop(strong); // But not any more. We can do Weak::as_raw(&weak), but accessing the pointer would lead to // undefined behaviour. - assert_eq!(42, **unsafe { &*Weak::as_raw(&weak) }); //~ ERROR dangling pointer + assert_eq!(42, **unsafe { &*Weak::as_raw(&weak) }); //~ ERROR dereferenced after this allocation got freed } diff --git a/tests/compile-fail/reading_half_a_pointer.rs b/tests/compile-fail/reading_half_a_pointer.rs index f8e9e5781e39..5554d0c49a11 100644 --- a/tests/compile-fail/reading_half_a_pointer.rs +++ b/tests/compile-fail/reading_half_a_pointer.rs @@ -24,6 +24,6 @@ fn main() { // starts 1 byte to the right, so using it would actually be wrong! let d_alias = &mut w.data as *mut _ as *mut *const u8; unsafe { - let _x = *d_alias; //~ ERROR tried to access part of a pointer value as raw bytes + let _x = *d_alias; //~ ERROR unable to turn this pointer into raw bytes } } diff --git a/tests/compile-fail/reallocate-bad-size.rs b/tests/compile-fail/reallocate-bad-size.rs index f7117dbb646d..a62c1adae7e6 100644 --- a/tests/compile-fail/reallocate-bad-size.rs +++ b/tests/compile-fail/reallocate-bad-size.rs @@ -5,7 +5,7 @@ extern crate alloc; use alloc::alloc::Global; use std::alloc::{AllocRef, Layout}; -// error-pattern: incorrect alloc info: expected size 2 and align 1, got size 1 and align 1 +// error-pattern: allocation has size 1 and alignment 1, but gave size 2 and alignment 1 fn main() { unsafe { diff --git a/tests/compile-fail/reallocate-change-alloc.rs b/tests/compile-fail/reallocate-change-alloc.rs index df517f9c81f2..0d4b60e0a336 100644 --- a/tests/compile-fail/reallocate-change-alloc.rs +++ b/tests/compile-fail/reallocate-change-alloc.rs @@ -9,6 +9,6 @@ fn main() { unsafe { let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap().0; Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1).unwrap(); - let _z = *(x.as_ptr() as *mut u8); //~ ERROR dangling pointer was dereferenced + let _z = *(x.as_ptr() as *mut u8); //~ ERROR dereferenced after this allocation got freed } } diff --git a/tests/compile-fail/reallocate-dangling.rs b/tests/compile-fail/reallocate-dangling.rs index 19a9017e71b8..9661d7e96674 100644 --- a/tests/compile-fail/reallocate-dangling.rs +++ b/tests/compile-fail/reallocate-dangling.rs @@ -5,7 +5,7 @@ extern crate alloc; use alloc::alloc::Global; use std::alloc::{AllocRef, Layout}; -// error-pattern: dangling pointer was dereferenced +// error-pattern: dereferenced after this allocation got freed fn main() { unsafe { diff --git a/tests/compile-fail/reference_to_packed.rs b/tests/compile-fail/reference_to_packed.rs index 030353c2cedb..08104e917d21 100644 --- a/tests/compile-fail/reference_to_packed.rs +++ b/tests/compile-fail/reference_to_packed.rs @@ -15,5 +15,5 @@ fn main() { y: 99, }; let p = unsafe { &foo.x }; - let i = *p; //~ ERROR tried to access memory with alignment 1, but alignment 4 is required + let i = *p; //~ ERROR memory with alignment 1, but alignment 4 is required } diff --git a/tests/compile-fail/stack_free.rs b/tests/compile-fail/stack_free.rs index b8ed2e3f1f35..ea09d3e2b44a 100644 --- a/tests/compile-fail/stack_free.rs +++ b/tests/compile-fail/stack_free.rs @@ -1,7 +1,7 @@ // Validation/SB changes why we fail // compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -// error-pattern: tried to deallocate `Stack` memory but gave `Machine(Rust)` as the kind +// error-pattern: deallocating `Stack` memory using `Machine(Rust)` deallocation operation fn main() { let x = 42; diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs b/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs index 74aab153ea90..69f19651e540 100644 --- a/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs +++ b/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs @@ -1,4 +1,4 @@ -// error-pattern: dangling pointer was dereferenced +// error-pattern: invalid use of 4 as a pointer use std::ptr::NonNull; fn main() { unsafe { diff --git a/tests/compile-fail/static_memory_modification1.rs b/tests/compile-fail/static_memory_modification1.rs index a7bb33431e72..6284fec1601a 100644 --- a/tests/compile-fail/static_memory_modification1.rs +++ b/tests/compile-fail/static_memory_modification1.rs @@ -6,7 +6,7 @@ static X: usize = 5; #[allow(mutable_transmutes)] fn main() { unsafe { - *std::mem::transmute::<&usize, &mut usize>(&X) = 6; //~ ERROR tried to modify constant memory + *std::mem::transmute::<&usize, &mut usize>(&X) = 6; //~ ERROR read-only assert_eq!(X, 6); } } diff --git a/tests/compile-fail/static_memory_modification2.rs b/tests/compile-fail/static_memory_modification2.rs index 065206a60dbf..558070d8a791 100644 --- a/tests/compile-fail/static_memory_modification2.rs +++ b/tests/compile-fail/static_memory_modification2.rs @@ -7,6 +7,6 @@ use std::mem::transmute; fn main() { unsafe { let s = "this is a test"; - transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; //~ ERROR tried to modify constant memory + transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; //~ ERROR read-only } } diff --git a/tests/compile-fail/static_memory_modification3.rs b/tests/compile-fail/static_memory_modification3.rs index 94f88205073e..93df1c594534 100644 --- a/tests/compile-fail/static_memory_modification3.rs +++ b/tests/compile-fail/static_memory_modification3.rs @@ -7,6 +7,6 @@ use std::mem::transmute; fn main() { unsafe { let bs = b"this is a test"; - transmute::<&[u8], &mut [u8]>(bs)[4] = 42; //~ ERROR tried to modify constant memory + transmute::<&[u8], &mut [u8]>(bs)[4] = 42; //~ ERROR read-only } } diff --git a/tests/compile-fail/storage_dead_dangling.rs b/tests/compile-fail/storage_dead_dangling.rs index 3047f086bdf3..bf2503917ccb 100644 --- a/tests/compile-fail/storage_dead_dangling.rs +++ b/tests/compile-fail/storage_dead_dangling.rs @@ -8,7 +8,7 @@ fn fill(v: &mut i32) { } fn evil() { - unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR dangling pointer was dereferenced + unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR dereferenced after this allocation got freed } fn main() { diff --git a/tests/compile-fail/transmute-pair-undef.rs b/tests/compile-fail/transmute-pair-undef.rs index 43f1eed42d07..0f02697f2615 100644 --- a/tests/compile-fail/transmute-pair-undef.rs +++ b/tests/compile-fail/transmute-pair-undef.rs @@ -18,5 +18,5 @@ fn main() { } let v = unsafe { *z.offset(first_undef) }; if v == 0 {} - //~^ ERROR attempted to read undefined bytes + //~^ ERROR this operation requires initialized memory } diff --git a/tests/compile-fail/transmute_fat1.rs b/tests/compile-fail/transmute_fat1.rs index ddc78c8bf1d4..978edb56340e 100644 --- a/tests/compile-fail/transmute_fat1.rs +++ b/tests/compile-fail/transmute_fat1.rs @@ -10,5 +10,5 @@ fn main() { let bad = unsafe { std::mem::transmute::<&[u8], [u8; 8]>(&[1u8]) }; - let _val = bad[0] + bad[bad.len()-1]; //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes + let _val = bad[0] + bad[bad.len()-1]; //~ ERROR unable to turn this pointer into raw bytes } diff --git a/tests/compile-fail/unaligned_ptr1.rs b/tests/compile-fail/unaligned_ptr1.rs index bcc4192d7d2a..ee1a13004231 100644 --- a/tests/compile-fail/unaligned_ptr1.rs +++ b/tests/compile-fail/unaligned_ptr1.rs @@ -5,5 +5,5 @@ fn main() { let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. - let _x = unsafe { *x }; //~ ERROR tried to access memory with alignment 2, but alignment 4 is required + let _x = unsafe { *x }; //~ ERROR memory with alignment 2, but alignment 4 is required } diff --git a/tests/compile-fail/unaligned_ptr2.rs b/tests/compile-fail/unaligned_ptr2.rs index 225bd14ade61..853d890ecf07 100644 --- a/tests/compile-fail/unaligned_ptr2.rs +++ b/tests/compile-fail/unaligned_ptr2.rs @@ -6,5 +6,5 @@ fn main() { let x = (x.as_ptr() as *const u8).wrapping_offset(3) as *const u32; // This must fail because alignment is violated: the offset is not sufficiently aligned. // Also make the offset not a power of 2, that used to ICE. - let _x = unsafe { *x }; //~ ERROR tried to access memory with alignment 1, but alignment 4 is required + let _x = unsafe { *x }; //~ ERROR memory with alignment 1, but alignment 4 is required } diff --git a/tests/compile-fail/unaligned_ptr3.rs b/tests/compile-fail/unaligned_ptr3.rs index f33a80d4588b..43f6b472da05 100644 --- a/tests/compile-fail/unaligned_ptr3.rs +++ b/tests/compile-fail/unaligned_ptr3.rs @@ -7,5 +7,5 @@ fn main() { // This must fail because alignment is violated. Test specifically for loading pointers, // which have special code in miri's memory. let _x = unsafe { *x }; - //~^ ERROR tried to access memory with alignment 2, but alignment + //~^ ERROR memory with alignment 2, but alignment } diff --git a/tests/compile-fail/unaligned_ptr_zst.rs b/tests/compile-fail/unaligned_ptr_zst.rs index 127ec04027d1..31f88c838149 100644 --- a/tests/compile-fail/unaligned_ptr_zst.rs +++ b/tests/compile-fail/unaligned_ptr_zst.rs @@ -6,5 +6,5 @@ fn main() { let x = x as *const _ as *const [u32; 0]; // This must fail because alignment is violated. Test specifically for loading ZST. let _x = unsafe { *x }; - //~^ ERROR tried to access memory with alignment 2, but alignment 4 is required + //~^ ERROR memory with alignment 2, but alignment 4 is required } diff --git a/tests/compile-fail/undefined_byte_read.rs b/tests/compile-fail/undefined_byte_read.rs index fca749ef9ccb..36c14137bdc1 100644 --- a/tests/compile-fail/undefined_byte_read.rs +++ b/tests/compile-fail/undefined_byte_read.rs @@ -1,6 +1,6 @@ fn main() { let v: Vec = Vec::with_capacity(10); let undef = unsafe { *v.get_unchecked(5) }; - let x = undef + 1; //~ ERROR attempted to read undefined bytes + let x = undef + 1; //~ ERROR this operation requires initialized memory panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/validity/dangling_ref1.rs b/tests/compile-fail/validity/dangling_ref1.rs index 194445b1ad7e..034510f3b283 100644 --- a/tests/compile-fail/validity/dangling_ref1.rs +++ b/tests/compile-fail/validity/dangling_ref1.rs @@ -1,5 +1,5 @@ use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR dangling reference (not entirely in bounds) + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR reference to unallocated address 16 } diff --git a/tests/compile-fail/validity/dangling_ref2.rs b/tests/compile-fail/validity/dangling_ref2.rs index 0dc9c3a1826c..4ad9b8135db4 100644 --- a/tests/compile-fail/validity/dangling_ref2.rs +++ b/tests/compile-fail/validity/dangling_ref2.rs @@ -3,5 +3,5 @@ use std::mem; fn main() { let val = 14; let ptr = (&val as *const i32).wrapping_offset(1); - let _x: &i32 = unsafe { mem::transmute(ptr) }; //~ ERROR dangling reference (not entirely in bounds) + let _x: &i32 = unsafe { mem::transmute(ptr) }; //~ ERROR dangling reference (going beyond the bounds of its allocation) } diff --git a/tests/compile-fail/wild_pointer_deref.rs b/tests/compile-fail/wild_pointer_deref.rs index ae32f7d5562b..5780cccdb842 100644 --- a/tests/compile-fail/wild_pointer_deref.rs +++ b/tests/compile-fail/wild_pointer_deref.rs @@ -1,5 +1,5 @@ fn main() { let p = 44 as *const i32; - let x = unsafe { *p }; //~ ERROR dangling pointer was dereferenced + let x = unsafe { *p }; //~ ERROR invalid use of 44 as a pointer panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/zst2.rs b/tests/compile-fail/zst2.rs index 950f7b3d60e6..907337dcdb2b 100644 --- a/tests/compile-fail/zst2.rs +++ b/tests/compile-fail/zst2.rs @@ -8,5 +8,5 @@ fn main() { let mut x_box = Box::new(1u8); let x = &mut *x_box as *mut _ as *mut [u8; 0]; drop(x_box); - unsafe { *x = zst_val; } //~ ERROR dangling pointer was dereferenced + unsafe { *x = zst_val; } //~ ERROR dereferenced after this allocation got freed } From e6e8773272a83b84b972910ca88570388ae06590 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 9 Mar 2020 09:43:20 +0100 Subject: [PATCH 1664/5092] start messages in lower-case --- src/helpers.rs | 6 +++--- src/shims/dlsym.rs | 2 +- src/shims/foreign_items.rs | 2 +- src/shims/foreign_items/posix.rs | 2 +- src/shims/fs.rs | 18 +++++++++--------- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index ff4df42dde66..43d9f1bf0b06 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -359,7 +359,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn check_no_isolation(&self, name: &str) -> InterpResult<'tcx> { if !self.eval_context_ref().machine.communicate { throw_unsup_format!( - "`{}` not available when isolation is enabled. Pass the flag `-Zmiri-disable-isolation` to disable it.", + "`{}` not available when isolation is enabled (pass the flag `-Zmiri-disable-isolation` to disable isolation)", name, ) } @@ -415,13 +415,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx AlreadyExists => "EEXIST", WouldBlock => "EWOULDBLOCK", _ => { - throw_unsup_format!("The {} error cannot be transformed into a raw os error", e) + throw_unsup_format!("io error {} cannot be transformed into a raw os error", e) } })? } else { // FIXME: we have to implement the Windows equivalent of this. throw_unsup_format!( - "Setting the last OS error from an io::Error is unsupported for {}.", + "setting the last OS error from an io::Error is unsupported for {}.", target.target_os ) }; diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 9027a97cf54e..b0e1850ec55d 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -15,7 +15,7 @@ impl Dlsym { Ok(match name { "getentropy" => Some(GetEntropy), "__pthread_get_minstack" => None, - _ => throw_unsup_format!("Unsupported dlsym: {}", name), + _ => throw_unsup_format!("unsupported dlsym: {}", name), }) } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 4c7bcff267e1..b4931d360044 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -436,7 +436,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => match this.tcx.sess.target.target.target_os.as_str() { "linux" | "macos" => return posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), "windows" => return windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), - target => throw_unsup_format!("The {} target platform is not supported", target), + target => throw_unsup_format!("the {} target platform is not supported", target), } }; diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 60b9aa6efcca..b9449c2653d6 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -310,7 +310,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(result) = result { this.write_scalar(result, dest)?; } else { - throw_unsup_format!("Unimplemented sysconf name: {}", name) + throw_unsup_format!("unimplemented sysconf name: {}", name) } } diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 7c755143f2e8..6894647de44d 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -198,7 +198,7 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' } Err(e) => return match e.raw_os_error() { Some(error) => Ok(error), - None => throw_unsup_format!("The error {} couldn't be converted to a return value", e), + None => throw_unsup_format!("the error {} couldn't be converted to a return value", e), } } } @@ -261,7 +261,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // windows. We need to check that in fact the access mode flags for the current platform // only use these two bits, otherwise we are in an unsupported platform and should error. if (o_rdonly | o_wronly | o_rdwr) & !0b11 != 0 { - throw_unsup_format!("Access mode flags on this platform are unsupported"); + throw_unsup_format!("access mode flags on this platform are unsupported"); } let mut writable = true; @@ -276,7 +276,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if access_mode == o_rdwr { options.read(true).write(true); } else { - throw_unsup_format!("Unsupported access mode {:#x}", access_mode); + throw_unsup_format!("unsupported access mode {:#x}", access_mode); } // We need to check that there aren't unsupported options in `flag`. For this we try to // reproduce the content of `flag` in the `mirror` variable using only the supported @@ -351,7 +351,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // differ in whether the FD_CLOEXEC flag is pre-set on the new file descriptor, // thus they can share the same implementation here. if fd < MIN_NORMAL_FILE_FD { - throw_unsup_format!("Duplicating file descriptors for stdin, stdout, or stderr is not supported") + throw_unsup_format!("duplicating file descriptors for stdin, stdout, or stderr is not supported") } let start_op = start_op.ok_or_else(|| { err_unsup_format!( @@ -369,7 +369,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }); this.try_unwrap_io_result(fd_result) } else { - throw_unsup_format!("The {:#x} command is not supported for `fcntl`)", cmd); + throw_unsup_format!("the {:#x} command is not supported for `fcntl`)", cmd); } } @@ -913,7 +913,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name_place.layout.size.bytes(), )?; if !name_fits { - throw_unsup_format!("A directory entry had a name too large to fit in libc::dirent64"); + throw_unsup_format!("a directory entry had a name too large to fit in libc::dirent64"); } let entry_place = this.deref_operand(entry_op)?; @@ -953,7 +953,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // return positive error number on error Some(error) => Ok(error), None => { - throw_unsup_format!("The error {} couldn't be converted to a return value", e) + throw_unsup_format!("the error {} couldn't be converted to a return value", e) } }, } @@ -1001,7 +1001,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name_place.layout.size.bytes(), )?; if !name_fits { - throw_unsup_format!("A directory entry had a name too large to fit in libc::dirent"); + throw_unsup_format!("a directory entry had a name too large to fit in libc::dirent"); } let entry_place = this.deref_operand(entry_op)?; @@ -1042,7 +1042,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // return positive error number on error Some(error) => Ok(error), None => { - throw_unsup_format!("The error {} couldn't be converted to a return value", e) + throw_unsup_format!("the error {} couldn't be converted to a return value", e) } }, } From 77cc0cddd9b0d90b2f7b68c6cb62d1eec33c9427 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 9 Mar 2020 10:22:30 +0100 Subject: [PATCH 1665/5092] add test for validation finding use-after-free --- tests/compile-fail/validity/dangling_ref3.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 tests/compile-fail/validity/dangling_ref3.rs diff --git a/tests/compile-fail/validity/dangling_ref3.rs b/tests/compile-fail/validity/dangling_ref3.rs new file mode 100644 index 000000000000..46e17375a828 --- /dev/null +++ b/tests/compile-fail/validity/dangling_ref3.rs @@ -0,0 +1,10 @@ +use std::mem; + +fn dangling() -> *const u8 { + let x = 0u8; + &x as *const _ +} + +fn main() { + let _x: &i32 = unsafe { mem::transmute(dangling()) }; //~ ERROR dangling reference (use-after-free) +} From 681819c8ad2a33923a33fc6829cfd588eb1f721f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 9 Mar 2020 09:38:33 +0100 Subject: [PATCH 1666/5092] getting a path should never fail we basically treat them as lang items --- src/helpers.rs | 73 +++++++++++++++----------- src/shims/foreign_items.rs | 18 +------ src/shims/foreign_items/posix.rs | 23 ++++---- src/shims/foreign_items/posix/linux.rs | 6 +-- src/shims/fs.rs | 12 ++--- src/shims/time.rs | 2 +- 6 files changed, 60 insertions(+), 74 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 43d9f1bf0b06..169bb4205649 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -18,7 +18,7 @@ use crate::*; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} /// Gets an instance for a path. -fn resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> InterpResult<'tcx, DefId> { +fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option { tcx.crates() .iter() .find(|&&krate| tcx.original_crate_name(krate).as_str() == path[0]) @@ -41,18 +41,47 @@ fn resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> InterpResult<'tc } None }) - .ok_or_else(|| { - err_unsup_format!("failed to find required Rust item: {:?}", path).into() - }) } pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Gets an instance for a path. - fn resolve_path(&self, path: &[&str]) -> InterpResult<'tcx, ty::Instance<'tcx>> { - Ok(ty::Instance::mono( - self.eval_context_ref().tcx.tcx, - resolve_did(self.eval_context_ref().tcx.tcx, path)?, - )) + fn resolve_path(&self, path: &[&str]) -> ty::Instance<'tcx> { + let did = try_resolve_did(self.eval_context_ref().tcx.tcx, path) + .unwrap_or_else(|| panic!("failed to find required Rust item: {:?}", path)); + ty::Instance::mono(self.eval_context_ref().tcx.tcx, did) + } + + /// Evaluates the scalar at the specified path. Returns Some(val) + /// if the path could be resolved, and None otherwise + fn eval_path_scalar( + &mut self, + path: &[&str], + ) -> InterpResult<'tcx, ScalarMaybeUndef> { + let this = self.eval_context_mut(); + let instance = this.resolve_path(path); + let cid = GlobalId { instance, promoted: None }; + let const_val = this.const_eval_raw(cid)?; + let const_val = this.read_scalar(const_val.into())?; + return Ok(const_val); + } + + /// Helper function to get a `libc` constant as a `Scalar`. + fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar> { + self.eval_context_mut() + .eval_path_scalar(&["libc", name])? + .not_undef() + } + + /// Helper function to get a `libc` constant as an `i32`. + fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { + self.eval_libc(name)?.to_i32() + } + + /// Helper function to get the `TyLayout` of a `libc` type + fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyLayout<'tcx>> { + let this = self.eval_context_mut(); + let ty = this.resolve_path(&["libc", name]).monomorphic_ty(*this.tcx); + this.layout_of(ty) } /// Write a 0 of the appropriate size to `dest`. @@ -97,7 +126,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.machine.communicate { // Fill the buffer using the host's rng. getrandom::getrandom(&mut data) - .map_err(|err| err_unsup_format!("getrandom failed: {}", err))?; + .map_err(|err| err_unsup_format!("host getrandom failed: {}", err))?; } else { let rng = this.memory.extra.rng.get_mut(); rng.fill_bytes(&mut data); @@ -312,26 +341,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - /// Helper function to get a `libc` constant as a `Scalar`. - fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar> { - self.eval_context_mut() - .eval_path_scalar(&["libc", name])? - .ok_or_else(|| err_unsup_format!("Path libc::{} cannot be resolved.", name))? - .not_undef() - } - - /// Helper function to get a `libc` constant as an `i32`. - fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { - self.eval_libc(name)?.to_i32() - } - - /// Helper function to get the `TyLayout` of a `libc` type - fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyLayout<'tcx>> { - let this = self.eval_context_mut(); - let ty = this.resolve_path(&["libc", name])?.monomorphic_ty(*this.tcx); - this.layout_of(ty) - } - // Writes several `ImmTy`s contiguosly into memory. This is useful when you have to pack // different values into a struct. fn write_packed_immediates( @@ -530,7 +539,7 @@ pub fn immty_from_int_checked<'tcx>( ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let int = int.into(); Ok(ImmTy::try_from_int(int, layout).ok_or_else(|| { - err_unsup_format!("Signed value {:#x} does not fit in {} bits", int, layout.size.bits()) + err_unsup_format!("signed value {:#x} does not fit in {} bits", int, layout.size.bits()) })?) } @@ -540,6 +549,6 @@ pub fn immty_from_uint_checked<'tcx>( ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let int = int.into(); Ok(ImmTy::try_from_uint(int, layout).ok_or_else(|| { - err_unsup_format!("Signed value {:#x} does not fit in {} bits", int, layout.size.bits()) + err_unsup_format!("unsigned value {:#x} does not fit in {} bits", int, layout.size.bits()) })?) } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index b4931d360044..fab90e3cc529 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -165,7 +165,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .expect("No panic runtime found!"); let panic_runtime = tcx.crate_name(*panic_runtime); let start_panic_instance = - this.resolve_path(&[&*panic_runtime.as_str(), link_name])?; + this.resolve_path(&[&*panic_runtime.as_str(), link_name]); return Ok(Some(&*this.load_mir(start_panic_instance.def, None)?)); } _ => {} @@ -454,20 +454,4 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(()) } - - /// Evaluates the scalar at the specified path. Returns Some(val) - /// if the path could be resolved, and None otherwise - fn eval_path_scalar( - &mut self, - path: &[&str], - ) -> InterpResult<'tcx, Option>> { - let this = self.eval_context_mut(); - if let Ok(instance) = this.resolve_path(path) { - let cid = GlobalId { instance, promoted: None }; - let const_val = this.const_eval_raw(cid)?; - let const_val = this.read_scalar(const_val.into())?; - return Ok(Some(const_val)); - } - return Ok(None); - } } diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index b9449c2653d6..85e9b88b6ec0 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -289,22 +289,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("sysconf() called with name {}", name); // TODO: Cache the sysconf integers via Miri's global cache. - let paths = &[ - (&["libc", "_SC_PAGESIZE"], Scalar::from_int(PAGE_SIZE, dest.layout.size)), - (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)), - ( - &["libc", "_SC_NPROCESSORS_ONLN"], - Scalar::from_int(NUM_CPUS, dest.layout.size), - ), + let sysconfs = &[ + ("_SC_PAGESIZE", Scalar::from_int(PAGE_SIZE, dest.layout.size)), + ("_SC_GETPW_R_SIZE_MAX", Scalar::from_int(-1, dest.layout.size)), + ("_SC_NPROCESSORS_ONLN", Scalar::from_int(NUM_CPUS, dest.layout.size)), ]; let mut result = None; - for &(path, path_value) in paths { - if let Some(val) = this.eval_path_scalar(path)? { - let val = val.to_i32()?; - if val == name { - result = Some(path_value); - break; - } + for &(sysconf_name, value) in sysconfs { + let sysconf_name = this.eval_libc_i32(sysconf_name)?; + if sysconf_name == name { + result = Some(value); + break; } } if let Some(result) = result { diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 023fee4ca7b1..82928c9bc17f 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -56,13 +56,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "syscall" => { let sys_getrandom = this - .eval_path_scalar(&["libc", "SYS_getrandom"])? - .expect("Failed to get libc::SYS_getrandom") + .eval_libc("SYS_getrandom")? .to_machine_usize(this)?; let sys_statx = this - .eval_path_scalar(&["libc", "SYS_statx"])? - .expect("Failed to get libc::SYS_statx") + .eval_libc("SYS_statx")? .to_machine_usize(this)?; match this.read_scalar(args[0])?.to_machine_usize(this)? { diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 6894647de44d..cb429109a4a5 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -643,7 +643,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // 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"])? + .resolve_path(&["libc", "unix", "linux_like", "linux", "gnu", "statx"]) .monomorphic_ty(*this.tcx); let statxbuf_ty = this.tcx.mk_mut_ptr(statx_ty); let statxbuf_layout = this.layout_of(statxbuf_ty)?; @@ -655,13 +655,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `flags` should be a `c_int` but the `syscall` function provides an `isize`. let flags: i32 = this.read_scalar(flags_op)?.to_machine_isize(&*this.tcx)?.try_into().map_err(|e| { - err_unsup_format!("Failed to convert pointer sized operand to integer: {}", e) + err_unsup_format!("failed to convert pointer sized operand to integer: {}", e) })?; let empty_path_flag = flags & this.eval_libc("AT_EMPTY_PATH")?.to_i32()? != 0; // `dirfd` should be a `c_int` but the `syscall` function provides an `isize`. let dirfd: i32 = this.read_scalar(dirfd_op)?.to_machine_isize(&*this.tcx)?.try_into().map_err(|e| { - err_unsup_format!("Failed to convert pointer sized operand to integer: {}", e) + err_unsup_format!("failed to convert pointer sized operand to integer: {}", e) })?; // We only support: // * interpreting `path` as an absolute directory, @@ -676,7 +676,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx (path.as_os_str().is_empty() && empty_path_flag) ) { throw_unsup_format!( - "Using statx is only supported with absolute paths, relative paths with the file \ + "using statx is only supported with absolute paths, relative paths with the file \ descriptor `AT_FDCWD`, and empty paths with the `AT_EMPTY_PATH` flag set and any \ file descriptor" ) @@ -886,7 +886,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; let dir_iter = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { - err_unsup_format!("The DIR pointer passed to readdir64_r did not come from opendir") + err_unsup_format!("the DIR pointer passed to readdir64_r did not come from opendir") })?; match dir_iter.next() { Some(Ok(dir_entry)) => { @@ -973,7 +973,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; let dir_iter = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { - err_unsup_format!("The DIR pointer passed to readdir_r did not come from opendir") + err_unsup_format!("the DIR pointer passed to readdir_r did not come from opendir") })?; match dir_iter.next() { Some(Ok(dir_entry)) => { diff --git a/src/shims/time.rs b/src/shims/time.rs index d761698e0d27..627478eaaab7 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -12,7 +12,7 @@ fn get_time<'tcx>() -> InterpResult<'tcx, Duration> { /// Returns the time elapsed between the provided time and the unix epoch as a `Duration`. pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Duration> { time.duration_since(SystemTime::UNIX_EPOCH) - .map_err(|_| err_unsup_format!("Times before the Unix epoch are not supported").into()) + .map_err(|_| err_unsup_format!("times before the Unix epoch are not supported").into()) } impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} From e1e158e1037f22516a4d227abfe3bf9f7a1b8c5e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 9 Mar 2020 11:42:59 +0100 Subject: [PATCH 1667/5092] adjust error messages for lower-case start --- tests/compile-fail/overflowing-unchecked-rsh.rs | 2 +- tests/compile-fail/unchecked_add1.rs | 2 +- tests/compile-fail/unchecked_add2.rs | 2 +- tests/compile-fail/unchecked_div1.rs | 2 +- tests/compile-fail/unchecked_mul1.rs | 2 +- tests/compile-fail/unchecked_mul2.rs | 2 +- tests/compile-fail/unchecked_sub1.rs | 2 +- tests/compile-fail/unchecked_sub2.rs | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/compile-fail/overflowing-unchecked-rsh.rs b/tests/compile-fail/overflowing-unchecked-rsh.rs index f59773f7e366..730d01597f4d 100644 --- a/tests/compile-fail/overflowing-unchecked-rsh.rs +++ b/tests/compile-fail/overflowing-unchecked-rsh.rs @@ -2,7 +2,7 @@ use std::intrinsics::*; -//error-pattern: Overflowing shift by 64 in `unchecked_shr` +//error-pattern: overflowing shift by 64 in `unchecked_shr` fn main() { unsafe { diff --git a/tests/compile-fail/unchecked_add1.rs b/tests/compile-fail/unchecked_add1.rs index eb5a41fdfaf9..f48b91422c6e 100644 --- a/tests/compile-fail/unchecked_add1.rs +++ b/tests/compile-fail/unchecked_add1.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MAX overflow - unsafe { std::intrinsics::unchecked_add(40000u16, 30000); } //~ ERROR Overflow executing `unchecked_add` + unsafe { std::intrinsics::unchecked_add(40000u16, 30000); } //~ ERROR overflow executing `unchecked_add` } diff --git a/tests/compile-fail/unchecked_add2.rs b/tests/compile-fail/unchecked_add2.rs index fa6a232aedee..150986541c3d 100644 --- a/tests/compile-fail/unchecked_add2.rs +++ b/tests/compile-fail/unchecked_add2.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MIN overflow - unsafe { std::intrinsics::unchecked_add(-30000i16, -8000); } //~ ERROR Overflow executing `unchecked_add` + unsafe { std::intrinsics::unchecked_add(-30000i16, -8000); } //~ ERROR overflow executing `unchecked_add` } diff --git a/tests/compile-fail/unchecked_div1.rs b/tests/compile-fail/unchecked_div1.rs index b42b34ff462d..53d80007646d 100644 --- a/tests/compile-fail/unchecked_div1.rs +++ b/tests/compile-fail/unchecked_div1.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MIN/-1 cannot be represented - unsafe { std::intrinsics::unchecked_div(i16::MIN, -1); } //~ ERROR Overflow executing `unchecked_div` + unsafe { std::intrinsics::unchecked_div(i16::MIN, -1); } //~ ERROR overflow executing `unchecked_div` } diff --git a/tests/compile-fail/unchecked_mul1.rs b/tests/compile-fail/unchecked_mul1.rs index a3681a57df79..050e3ff24377 100644 --- a/tests/compile-fail/unchecked_mul1.rs +++ b/tests/compile-fail/unchecked_mul1.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MAX overflow - unsafe { std::intrinsics::unchecked_mul(300u16, 250u16); } //~ ERROR Overflow executing `unchecked_mul` + unsafe { std::intrinsics::unchecked_mul(300u16, 250u16); } //~ ERROR overflow executing `unchecked_mul` } diff --git a/tests/compile-fail/unchecked_mul2.rs b/tests/compile-fail/unchecked_mul2.rs index 8fe677f8ded5..4fb77783b4ce 100644 --- a/tests/compile-fail/unchecked_mul2.rs +++ b/tests/compile-fail/unchecked_mul2.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MIN overflow - unsafe { std::intrinsics::unchecked_mul(1_000_000_000i32, -4); } //~ ERROR Overflow executing `unchecked_mul` + unsafe { std::intrinsics::unchecked_mul(1_000_000_000i32, -4); } //~ ERROR overflow executing `unchecked_mul` } diff --git a/tests/compile-fail/unchecked_sub1.rs b/tests/compile-fail/unchecked_sub1.rs index 230607f03305..69b32dd319b6 100644 --- a/tests/compile-fail/unchecked_sub1.rs +++ b/tests/compile-fail/unchecked_sub1.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MIN overflow - unsafe { std::intrinsics::unchecked_sub(14u32, 22); } //~ ERROR Overflow executing `unchecked_sub` + unsafe { std::intrinsics::unchecked_sub(14u32, 22); } //~ ERROR overflow executing `unchecked_sub` } diff --git a/tests/compile-fail/unchecked_sub2.rs b/tests/compile-fail/unchecked_sub2.rs index 1ea41a3c0fb0..5609ea7a3edd 100644 --- a/tests/compile-fail/unchecked_sub2.rs +++ b/tests/compile-fail/unchecked_sub2.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MAX overflow - unsafe { std::intrinsics::unchecked_sub(30000i16, -7000); } //~ ERROR Overflow executing `unchecked_sub` + unsafe { std::intrinsics::unchecked_sub(30000i16, -7000); } //~ ERROR overflow executing `unchecked_sub` } From 49051e05eaf91e97e106c56a4cbb0f59757494c6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 19 Mar 2020 08:41:01 +0100 Subject: [PATCH 1668/5092] rustup, and some final message adjustments --- rust-version | 2 +- tests/compile-fail/cast_fn_ptr1.rs | 4 ++-- tests/compile-fail/cast_fn_ptr5.rs | 4 ++-- tests/compile-fail/pointer_byte_read.rs | 2 +- tests/compile-fail/reading_half_a_pointer.rs | 2 +- tests/compile-fail/transmute_fat1.rs | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/rust-version b/rust-version index 1c3f12298f86..dd16aa7af94f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -660326e9791d5caf3186b14521498c2584a494ab +57e1da59cd0761330b4ea8d47b16340a78eeafa9 diff --git a/tests/compile-fail/cast_fn_ptr1.rs b/tests/compile-fail/cast_fn_ptr1.rs index 3702ec8c94c4..057cc64e9e3b 100644 --- a/tests/compile-fail/cast_fn_ptr1.rs +++ b/tests/compile-fail/cast_fn_ptr1.rs @@ -1,9 +1,9 @@ fn main() { - fn f() {} + fn f() {} //~ ERROR calling a function with more arguments than it expected let g = unsafe { std::mem::transmute::(f) }; - g(42) //~ ERROR calling a function with more arguments than it expected + g(42) } diff --git a/tests/compile-fail/cast_fn_ptr5.rs b/tests/compile-fail/cast_fn_ptr5.rs index fb2b4403363e..ff2a73d5a485 100644 --- a/tests/compile-fail/cast_fn_ptr5.rs +++ b/tests/compile-fail/cast_fn_ptr5.rs @@ -1,9 +1,9 @@ fn main() { - fn f() -> u32 { 42 } + fn f() -> u32 { 42 } //~ ERROR calling a function with return type u32 passing return place of type () let g = unsafe { std::mem::transmute:: u32, fn()>(f) }; - g() //~ ERROR calling a function with return type u32 passing return place of type () + g() } diff --git a/tests/compile-fail/pointer_byte_read.rs b/tests/compile-fail/pointer_byte_read.rs index 2ac27bf2b44d..dcb0fd3fb906 100644 --- a/tests/compile-fail/pointer_byte_read.rs +++ b/tests/compile-fail/pointer_byte_read.rs @@ -3,5 +3,5 @@ fn main() { let y = &x; let z = &y as *const &i32 as *const u8; // the deref fails, because we are reading only a part of the pointer - let _val = unsafe { *z }; //~ ERROR unable to turn this pointer into raw bytes + let _val = unsafe { *z }; //~ ERROR unable to turn pointer into raw bytes } diff --git a/tests/compile-fail/reading_half_a_pointer.rs b/tests/compile-fail/reading_half_a_pointer.rs index 5554d0c49a11..6e765a1b0ba1 100644 --- a/tests/compile-fail/reading_half_a_pointer.rs +++ b/tests/compile-fail/reading_half_a_pointer.rs @@ -24,6 +24,6 @@ fn main() { // starts 1 byte to the right, so using it would actually be wrong! let d_alias = &mut w.data as *mut _ as *mut *const u8; unsafe { - let _x = *d_alias; //~ ERROR unable to turn this pointer into raw bytes + let _x = *d_alias; //~ ERROR unable to turn pointer into raw bytes } } diff --git a/tests/compile-fail/transmute_fat1.rs b/tests/compile-fail/transmute_fat1.rs index 978edb56340e..da45dad7b7d4 100644 --- a/tests/compile-fail/transmute_fat1.rs +++ b/tests/compile-fail/transmute_fat1.rs @@ -10,5 +10,5 @@ fn main() { let bad = unsafe { std::mem::transmute::<&[u8], [u8; 8]>(&[1u8]) }; - let _val = bad[0] + bad[bad.len()-1]; //~ ERROR unable to turn this pointer into raw bytes + let _val = bad[0] + bad[bad.len()-1]; //~ ERROR unable to turn pointer into raw bytes } From 0f1713f67cb66b2af3fd84c34a58b92f0a0c99bf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 19 Mar 2020 15:50:02 +0100 Subject: [PATCH 1669/5092] whitelist platforms where panicking should work --- src/shims/foreign_items.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index fab90e3cc529..af2c6d6ebb9a 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -132,6 +132,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This matches calls to the foreign item `panic_impl`. // The implementation is provided by the function with the `#[panic_handler]` attribute. "panic_impl" => { + // Make sure panicking actually works on this platform. + match this.tcx.sess.target.target.target_os.as_str() { + "linux" | "macos" => {}, + _ => throw_unsup_format!("panicking is not supported on this platform"), + } + let panic_impl_id = this.tcx.lang_items().panic_impl().unwrap(); let panic_impl_instance = ty::Instance::mono(*this.tcx, panic_impl_id); return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); From 4608b94bd89d444cbb02ed41fca2ca002cc0c5ca Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 19 Mar 2020 23:00:02 +0100 Subject: [PATCH 1670/5092] implement CLOCK_MONOTONIC on Linux --- src/machine.rs | 5 +++++ src/shims/time.rs | 24 ++++++++++++------------ tests/run-pass/clock.rs | 14 -------------- tests/run-pass/time.rs | 18 ++++++++++++++++++ 4 files changed, 35 insertions(+), 26 deletions(-) delete mode 100644 tests/run-pass/clock.rs create mode 100644 tests/run-pass/time.rs diff --git a/src/machine.rs b/src/machine.rs index 3a8e7fc90241..3cf00781338c 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -5,6 +5,7 @@ use std::borrow::Cow; use std::cell::RefCell; use std::num::NonZeroU64; use std::rc::Rc; +use std::time::Instant; use rand::rngs::StdRng; @@ -164,6 +165,9 @@ pub struct Evaluator<'tcx> { /// the call to `miri_start_panic` (the panic payload) when unwinding. /// This is pointer-sized, and matches the `Payload` type in `src/libpanic_unwind/miri.rs`. pub(crate) panic_payload: Option>, + + /// The "time anchor" for this machine's monotone clock (for `Instant` simulation). + pub(crate) time_anchor: Instant, } impl<'tcx> Evaluator<'tcx> { @@ -182,6 +186,7 @@ impl<'tcx> Evaluator<'tcx> { file_handler: Default::default(), dir_handler: Default::default(), panic_payload: None, + time_anchor: Instant::now(), } } } diff --git a/src/shims/time.rs b/src/shims/time.rs index 627478eaaab7..c8807dd6ea84 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -1,14 +1,9 @@ -use std::time::{Duration, SystemTime}; +use std::time::{Duration, SystemTime, Instant}; use crate::stacked_borrows::Tag; use crate::*; use helpers::immty_from_int_checked; -// Returns the time elapsed between now and the unix epoch as a `Duration`. -fn get_time<'tcx>() -> InterpResult<'tcx, Duration> { - system_time_to_duration(&SystemTime::now()) -} - /// Returns the time elapsed between the provided time and the unix epoch as a `Duration`. pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Duration> { time.duration_since(SystemTime::UNIX_EPOCH) @@ -28,15 +23,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("clock_gettime")?; let clk_id = this.read_scalar(clk_id_op)?.to_i32()?; - if clk_id != this.eval_libc_i32("CLOCK_REALTIME")? { + let tp = this.deref_operand(tp_op)?; + + let duration = if clk_id == this.eval_libc_i32("CLOCK_REALTIME")? { + system_time_to_duration(&SystemTime::now())? + } else if clk_id == this.eval_libc_i32("CLOCK_MONOTONIC")? { + // Absolute time does not matter, only relative time does, so we can just + // use our own time anchor here. + Instant::now().duration_since(this.machine.time_anchor) + } else { let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; return Ok(-1); - } + }; - let tp = this.deref_operand(tp_op)?; - - let duration = get_time()?; let tv_sec = duration.as_secs(); let tv_nsec = duration.subsec_nanos(); @@ -68,7 +68,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tv = this.deref_operand(tv_op)?; - let duration = get_time()?; + let duration = system_time_to_duration(&SystemTime::now())?; let tv_sec = duration.as_secs(); let tv_usec = duration.subsec_micros(); diff --git a/tests/run-pass/clock.rs b/tests/run-pass/clock.rs deleted file mode 100644 index b4c3fa08fdc6..000000000000 --- a/tests/run-pass/clock.rs +++ /dev/null @@ -1,14 +0,0 @@ -// ignore-windows: TODO clock shims are not implemented on Windows -// compile-flags: -Zmiri-disable-isolation - -use std::time::SystemTime; - -fn main() { - let now1 = SystemTime::now(); - - // Do some work to make time pass. - for _ in 0..10 { drop(vec![42]); } - - let now2 = SystemTime::now(); - assert!(now2 > now1); -} diff --git a/tests/run-pass/time.rs b/tests/run-pass/time.rs new file mode 100644 index 000000000000..bbe8b4011dfa --- /dev/null +++ b/tests/run-pass/time.rs @@ -0,0 +1,18 @@ +// ignore-windows: TODO clock shims are not implemented on Windows +// compile-flags: -Zmiri-disable-isolation + +use std::time::{SystemTime, Instant}; + +fn main() { + let now1 = SystemTime::now(); + // Do some work to make time pass. + for _ in 0..10 { drop(vec![42]); } + let now2 = SystemTime::now(); + assert!(now2 > now1); + + let now1 = Instant::now(); + // Do some work to make time pass. + for _ in 0..10 { drop(vec![42]); } + let now2 = Instant::now(); + assert!(now2 > now1); +} From c3f6f47f7a773ad00c87cfb550006fb0906cef31 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 19 Mar 2020 23:19:17 +0100 Subject: [PATCH 1671/5092] we also do not check floats for being init'd --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a1b978316684..c2957416062d 100644 --- a/README.md +++ b/README.md @@ -29,8 +29,8 @@ program, and cannot run all programs: positives here, so if you program runs fine in Miri right now that is by no means a guarantee that it is UB-free when these questions get answered. - In particular, Miri does currently not check that integers are initialized - or that references point to valid data. + In particular, Miri does currently not check that integers/floats are + initialized or that references point to valid data. * If the program relies on unspecified details of how data is laid out, it will still run fine in Miri -- but might break (including causing UB) on different compiler versions or different platforms. From e3a72be1073903dc02040163305344b845516fe0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 20 Mar 2020 10:34:24 +0100 Subject: [PATCH 1672/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index dd16aa7af94f..ca9c782d127a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -57e1da59cd0761330b4ea8d47b16340a78eeafa9 +f4c675c476c18b1a11041193f2f59d695b126bc8 From 04c937e2813c5da2b003b272bff26b9d1f9ffca3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 20 Mar 2020 15:11:54 +0100 Subject: [PATCH 1673/5092] assert platform in time shims --- src/shims/time.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/shims/time.rs b/src/shims/time.rs index c8807dd6ea84..2d812208fba1 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -21,6 +21,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.check_no_isolation("clock_gettime")?; + this.assert_platform("linux"); let clk_id = this.read_scalar(clk_id_op)?.to_i32()?; let tp = this.deref_operand(tp_op)?; @@ -58,6 +59,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.check_no_isolation("gettimeofday")?; + this.assert_platform("macos"); + // Using tz is obsolete and should always be null let tz = this.read_scalar(tz_op)?.not_undef()?; if !this.is_null(tz)? { From 3a5f601710bd14d2f924dadc5864c5b6ac0bc84c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 20 Mar 2020 15:57:11 +0100 Subject: [PATCH 1674/5092] add some more miri-detected issues --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c2957416062d..e0e7df24faad 100644 --- a/README.md +++ b/README.md @@ -243,6 +243,7 @@ Definite bugs found: * [The Unix allocator calling `posix_memalign` in an invalid way](https://github.com/rust-lang/rust/issues/62251) * [`getrandom` calling the `getrandom` syscall in an invalid way](https://github.com/rust-random/getrandom/pull/73) * [`Vec`](https://github.com/rust-lang/rust/issues/69770) and [`BTreeMap`](https://github.com/rust-lang/rust/issues/69769) leaking memory under some (panicky) conditions +* [Memory leak in `beef`](https://github.com/maciejhirsz/beef/issues/12) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): @@ -251,6 +252,7 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [`LinkedList` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/60072) * [`Vec::push` invalidating existing references into the vector](https://github.com/rust-lang/rust/issues/60847) * [`align_to_mut` violating uniqueness of mutable references](https://github.com/rust-lang/rust/issues/68549) +* [Aliasing mutable references in `sized-chunks`](https://github.com/bodil/sized-chunks/issues/8) ## License From f430e544561a430f267c9fbde20962cef4702332 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 20 Mar 2020 15:54:41 +0100 Subject: [PATCH 1675/5092] implement mach_absolute_time for macOS --- src/shims/foreign_items/posix/macos.rs | 4 ++++ src/shims/fs.rs | 12 ++++++------ src/shims/time.rs | 21 +++++++++++++++++---- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 34661fb2383c..0bb4710769d9 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -66,6 +66,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.gettimeofday(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "mach_absolute_time" => { + let result = this.mach_absolute_time()?; + this.write_scalar(Scalar::from_uint(result, dest.layout.size), dest)?; + } // Other shims "pthread_attr_get_np" => { diff --git a/src/shims/fs.rs b/src/shims/fs.rs index cb429109a4a5..a5aae5ed90c3 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -574,8 +574,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx buf_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("stat")?; this.assert_platform("macos", "stat"); + this.check_no_isolation("stat")?; // `stat` always follows symlinks. this.macos_stat_or_lstat(true, path_op, buf_op) } @@ -587,8 +587,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx buf_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("lstat")?; this.assert_platform("macos", "lstat"); + this.check_no_isolation("lstat")?; this.macos_stat_or_lstat(false, path_op, buf_op) } @@ -599,8 +599,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("fstat")?; this.assert_platform("macos", "fstat"); + this.check_no_isolation("fstat")?; let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -621,8 +621,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("statx")?; this.assert_platform("linux", "statx"); + this.check_no_isolation("statx")?; let statxbuf_scalar = this.read_scalar(statxbuf_op)?.not_undef()?; let pathname_scalar = this.read_scalar(pathname_op)?.not_undef()?; @@ -880,8 +880,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("readdir64_r")?; this.assert_platform("linux", "readdir64_r"); + this.check_no_isolation("readdir64_r")?; let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; @@ -967,8 +967,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("readdir_r")?; this.assert_platform("macos", "readdir_r"); + this.check_no_isolation("readdir_r")?; let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; diff --git a/src/shims/time.rs b/src/shims/time.rs index 2d812208fba1..b270c9770f80 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -1,4 +1,5 @@ use std::time::{Duration, SystemTime, Instant}; +use std::convert::TryFrom; use crate::stacked_borrows::Tag; use crate::*; @@ -12,7 +13,6 @@ pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Du impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - // Foreign function used by linux fn clock_gettime( &mut self, clk_id_op: OpTy<'tcx, Tag>, @@ -20,8 +20,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + this.assert_platform("linux", "clock_gettime"); this.check_no_isolation("clock_gettime")?; - this.assert_platform("linux"); let clk_id = this.read_scalar(clk_id_op)?.to_i32()?; let tp = this.deref_operand(tp_op)?; @@ -50,7 +50,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - // Foreign function used by generic unix (in particular macOS) + fn gettimeofday( &mut self, tv_op: OpTy<'tcx, Tag>, @@ -58,8 +58,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + this.assert_platform("macos", "gettimeofday"); this.check_no_isolation("gettimeofday")?; - this.assert_platform("macos"); // Using tz is obsolete and should always be null let tz = this.read_scalar(tz_op)?.not_undef()?; @@ -84,4 +84,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } + + fn mach_absolute_time(&self) -> InterpResult<'tcx, u64> { + let this = self.eval_context_ref(); + + this.assert_platform("macos", "mach_absolute_time"); + this.check_no_isolation("mach_absolute_time")?; + + // This returns a u64, with time units determined dynamically by `mach_timebase_info`. + // We return plain nanoseconds. + let duration = Instant::now().duration_since(this.machine.time_anchor); + u64::try_from(duration.as_nanos()) + .map_err(|_| err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported").into()) + } } From bde3111c61a325a2ddaf7b47975ee2758b30e969 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 Mar 2020 10:16:47 +0100 Subject: [PATCH 1676/5092] test windows panic message --- src/shims/foreign_items.rs | 7 +------ src/shims/mod.rs | 8 ++++++++ src/shims/panic.rs | 8 ++++++++ tests/compile-fail/panic/windows1.rs | 9 +++++++++ tests/compile-fail/panic/windows2.rs | 9 +++++++++ tests/compile-fail/panic/windows3.rs | 10 ++++++++++ 6 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 tests/compile-fail/panic/windows1.rs create mode 100644 tests/compile-fail/panic/windows2.rs create mode 100644 tests/compile-fail/panic/windows3.rs diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index af2c6d6ebb9a..60da1f1e6cc6 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -132,12 +132,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This matches calls to the foreign item `panic_impl`. // The implementation is provided by the function with the `#[panic_handler]` attribute. "panic_impl" => { - // Make sure panicking actually works on this platform. - match this.tcx.sess.target.target.target_os.as_str() { - "linux" | "macos" => {}, - _ => throw_unsup_format!("panicking is not supported on this platform"), - } - + this.check_panic_supported()?; let panic_impl_id = this.tcx.lang_items().panic_impl().unwrap(); let panic_impl_instance = ty::Instance::mono(*this.tcx, panic_impl_id); return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); diff --git a/src/shims/mod.rs b/src/shims/mod.rs index d9e4d226ecc9..5b5a11b86b49 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -42,6 +42,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return this.emulate_foreign_item(instance.def_id(), args, ret, unwind); } + // Better error message for panics on Windows. + let def_id = instance.def_id(); + if Some(def_id) == this.tcx.lang_items().begin_panic_fn() || + Some(def_id) == this.tcx.lang_items().panic_impl() + { + this.check_panic_supported()?; + } + // Otherwise, load the MIR. Ok(Some(&*this.load_mir(instance.def, None)?)) } diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 2f61ab6c3958..8dded8bf4037 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -32,6 +32,14 @@ pub struct CatchUnwindData<'tcx> { impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + /// Check if panicking is supported on this platform, and give a good error otherwise. + fn check_panic_supported(&self) -> InterpResult<'tcx> { + match self.eval_context_ref().tcx.sess.target.target.target_os.as_str() { + "linux" | "macos" => Ok(()), + _ => throw_unsup_format!("panicking is not supported on this platform"), + } + } + /// Handles the special `miri_start_panic` intrinsic, which is called /// by libpanic_unwind to delegate the actual unwinding process to Miri. fn handle_miri_start_panic( diff --git a/tests/compile-fail/panic/windows1.rs b/tests/compile-fail/panic/windows1.rs new file mode 100644 index 000000000000..1d6faf1e751d --- /dev/null +++ b/tests/compile-fail/panic/windows1.rs @@ -0,0 +1,9 @@ +// ignore-linux +// ignore-macos + +// Test that panics on Windows give a reasonable error message. + +// error-pattern: panicking is not supported on this platform +fn main() { + core::panic!("this is {}", "Windows"); +} diff --git a/tests/compile-fail/panic/windows2.rs b/tests/compile-fail/panic/windows2.rs new file mode 100644 index 000000000000..023088a692ef --- /dev/null +++ b/tests/compile-fail/panic/windows2.rs @@ -0,0 +1,9 @@ +// ignore-linux +// ignore-macos + +// Test that panics on Windows give a reasonable error message. + +// error-pattern: panicking is not supported on this platform +fn main() { + std::panic!("this is Windows"); +} diff --git a/tests/compile-fail/panic/windows3.rs b/tests/compile-fail/panic/windows3.rs new file mode 100644 index 000000000000..b96022fc4ef5 --- /dev/null +++ b/tests/compile-fail/panic/windows3.rs @@ -0,0 +1,10 @@ +// ignore-linux +// ignore-macos + +// Test that panics on Windows give a reasonable error message. + +// error-pattern: panicking is not supported on this platform +#[allow(unconditional_panic)] +fn main() { + let _val = 1/0; +} From 5c09047411d3d1ba3a99893db64770864289d3a5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 Mar 2020 10:43:59 +0100 Subject: [PATCH 1677/5092] fix tests --- tests/compile-fail/abort-terminator.rs | 1 + tests/compile-fail/{ => panic}/double_panic.rs | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) rename tests/compile-fail/{ => panic}/double_panic.rs (60%) diff --git a/tests/compile-fail/abort-terminator.rs b/tests/compile-fail/abort-terminator.rs index 1bfa289a52b4..af1a155435fb 100644 --- a/tests/compile-fail/abort-terminator.rs +++ b/tests/compile-fail/abort-terminator.rs @@ -1,4 +1,5 @@ // error-pattern: the evaluated program aborted +// ignore-windows (panics dont work on Windows) #![feature(unwind_attributes)] #[unwind(aborts)] diff --git a/tests/compile-fail/double_panic.rs b/tests/compile-fail/panic/double_panic.rs similarity index 60% rename from tests/compile-fail/double_panic.rs rename to tests/compile-fail/panic/double_panic.rs index 759762196b75..3085d0b00657 100644 --- a/tests/compile-fail/double_panic.rs +++ b/tests/compile-fail/panic/double_panic.rs @@ -1,4 +1,6 @@ - // error-pattern: the evaluated program aborted +// error-pattern: the evaluated program aborted +// ignore-windows (panics dont work on Windows) + struct Foo; impl Drop for Foo { fn drop(&mut self) { From e890d4d5e11c97be0769df0cb1593394e8a9f8c6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 Mar 2020 12:52:23 +0100 Subject: [PATCH 1678/5092] call error location was fixed by rustup --- rust-version | 2 +- tests/compile-fail/cast_fn_ptr1.rs | 4 ++-- tests/compile-fail/cast_fn_ptr5.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index ca9c782d127a..aaf176861b0d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -f4c675c476c18b1a11041193f2f59d695b126bc8 +98803c182b2ba6ef5dccb6bf501958249295eac0 diff --git a/tests/compile-fail/cast_fn_ptr1.rs b/tests/compile-fail/cast_fn_ptr1.rs index 057cc64e9e3b..3702ec8c94c4 100644 --- a/tests/compile-fail/cast_fn_ptr1.rs +++ b/tests/compile-fail/cast_fn_ptr1.rs @@ -1,9 +1,9 @@ fn main() { - fn f() {} //~ ERROR calling a function with more arguments than it expected + fn f() {} let g = unsafe { std::mem::transmute::(f) }; - g(42) + g(42) //~ ERROR calling a function with more arguments than it expected } diff --git a/tests/compile-fail/cast_fn_ptr5.rs b/tests/compile-fail/cast_fn_ptr5.rs index ff2a73d5a485..fb2b4403363e 100644 --- a/tests/compile-fail/cast_fn_ptr5.rs +++ b/tests/compile-fail/cast_fn_ptr5.rs @@ -1,9 +1,9 @@ fn main() { - fn f() -> u32 { 42 } //~ ERROR calling a function with return type u32 passing return place of type () + fn f() -> u32 { 42 } let g = unsafe { std::mem::transmute:: u32, fn()>(f) }; - g() + g() //~ ERROR calling a function with return type u32 passing return place of type () } From 6355228d4e6e44db6b16301aeed8aacdd944f07a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 Mar 2020 13:13:08 +0100 Subject: [PATCH 1679/5092] remove no longer needed (and sometimes broken) 'extern crate' --- src/bin/miri-rustc-tests.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 509a1592152d..ab692e18f909 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -1,13 +1,9 @@ #![feature(rustc_private)] -extern crate getopts; extern crate miri; extern crate rustc; -extern crate rustc_codegen_utils; extern crate rustc_driver; -extern crate rustc_errors; extern crate rustc_hir; extern crate rustc_interface; -extern crate rustc_metadata; extern crate rustc_span; use std::io; From eb3be2f97de00c0f0e2118c9372684b78496e4ca Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 Mar 2020 17:43:28 +0100 Subject: [PATCH 1680/5092] ./miri check --- miri | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/miri b/miri index f1eae220e0de..47ff5024fc63 100755 --- a/miri +++ b/miri @@ -11,6 +11,9 @@ working directory. ./miri build : Just build miri. are passed to `cargo build`. +./miri check : +Just check miri. are passed to `cargo check`. + ./miri test : Build miri, set up a sysroot and then run the test suite. are passed to the final `cargo test` invocation. @@ -99,6 +102,10 @@ install|install-debug) # "--offline" to avoid querying the registry (for yanked packages). exec cargo install $CARGO_INSTALL_FLAGS --path "$(dirname "$0")" --force --locked --offline "$@" ;; +check|check-debug) + # Check, and let caller control flags. + exec cargo check $CARGO_BUILD_FLAGS "$@" + ;; build|build-debug) # Build, and let caller control flags. exec cargo build $CARGO_BUILD_FLAGS "$@" From 8acfafe186c073b047541f1aa177291850915c7d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 Mar 2020 17:54:18 +0100 Subject: [PATCH 1681/5092] test for zero-sized write_bytes to NULL --- tests/compile-fail/copy_null.rs | 3 +-- tests/compile-fail/write_bytes_null.rs | 10 ++++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 tests/compile-fail/write_bytes_null.rs diff --git a/tests/compile-fail/copy_null.rs b/tests/compile-fail/copy_null.rs index ce2fbe170e45..b14bdc4b3863 100644 --- a/tests/compile-fail/copy_null.rs +++ b/tests/compile-fail/copy_null.rs @@ -1,4 +1,3 @@ -//error-pattern: invalid use of NULL pointer #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd @@ -10,5 +9,5 @@ fn main() { let mut data = [0u16; 4]; let ptr = &mut data[0] as *mut u16; // Even copying 0 elements from NULL should error. - unsafe { copy_nonoverlapping(std::ptr::null(), ptr, 0); } + unsafe { copy_nonoverlapping(std::ptr::null(), ptr, 0); } //~ ERROR: invalid use of NULL pointer } diff --git a/tests/compile-fail/write_bytes_null.rs b/tests/compile-fail/write_bytes_null.rs new file mode 100644 index 000000000000..e80222162ee3 --- /dev/null +++ b/tests/compile-fail/write_bytes_null.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn write_bytes(dst: *mut T, val: u8, count: usize); +} + +fn main() { + unsafe { write_bytes::(std::ptr::null_mut(), 0, 0) }; //~ ERROR invalid use of NULL pointer +} From 238ed49a07b94e0f34f39cb88198fc868b781f0c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 Mar 2020 17:54:33 +0100 Subject: [PATCH 1682/5092] detect UB: overflow in copy/write_bytes --- src/shims/intrinsics.rs | 9 +++++---- tests/compile-fail/copy_overflow.rs | 10 ++++++++++ tests/compile-fail/write_bytes_overflow.rs | 9 +++++++++ 3 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 tests/compile-fail/copy_overflow.rs create mode 100644 tests/compile-fail/write_bytes_overflow.rs diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index a08c8a56cf2d..9a6bd58ba42e 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -4,7 +4,7 @@ use std::convert::TryFrom; use rustc::mir; use rustc::mir::interpret::{InterpResult, PointerArithmetic}; use rustc::ty; -use rustc::ty::layout::{Align, LayoutOf, Size}; +use rustc::ty::layout::{Align, LayoutOf}; use rustc_apfloat::Float; use rustc_span::source_map::Span; @@ -226,11 +226,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx => { let elem_ty = substs.type_at(0); let elem_layout = this.layout_of(elem_ty)?; - let elem_size = elem_layout.size.bytes(); let count = this.read_scalar(args[2])?.to_machine_usize(this)?; let elem_align = elem_layout.align.abi; - let size = Size::from_bytes(count) * elem_size; + let size = elem_layout.size.checked_mul(count, this) + .ok_or_else(|| err_ub_format!("overflow computing total size of `{}`", intrinsic_name))?; let src = this.read_scalar(args[0])?.not_undef()?; let src = this.memory.check_ptr_access(src, size, elem_align)?; let dest = this.read_scalar(args[1])?.not_undef()?; @@ -493,7 +493,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val_byte = this.read_scalar(args[1])?.to_u8()?; let ptr = this.read_scalar(args[0])?.not_undef()?; let count = this.read_scalar(args[2])?.to_machine_usize(this)?; - let byte_count = ty_layout.size * count; + let byte_count = ty_layout.size.checked_mul(count, this) + .ok_or_else(|| err_ub_format!("overflow computing total size of `write_bytes`"))?; this.memory .write_bytes(ptr, iter::repeat(val_byte).take(byte_count.bytes() as usize))?; } diff --git a/tests/compile-fail/copy_overflow.rs b/tests/compile-fail/copy_overflow.rs new file mode 100644 index 000000000000..c75cf6917b10 --- /dev/null +++ b/tests/compile-fail/copy_overflow.rs @@ -0,0 +1,10 @@ +// error-pattern: overflow computing total size of `copy` +use std::mem; + +fn main() { + let x = 0; + let mut y = 0; + unsafe { + (&mut y as *mut i32).copy_from(&x, 1usize << (mem::size_of::() * 8 - 1)); + } +} diff --git a/tests/compile-fail/write_bytes_overflow.rs b/tests/compile-fail/write_bytes_overflow.rs new file mode 100644 index 000000000000..a6bf2acb16f3 --- /dev/null +++ b/tests/compile-fail/write_bytes_overflow.rs @@ -0,0 +1,9 @@ +// error-pattern: overflow computing total size of `write_bytes` +use std::mem; + +fn main() { + let mut y = 0; + unsafe { + (&mut y as *mut i32).write_bytes(0u8, 1usize << (mem::size_of::() * 8 - 1)); + } +} From 83060738354664190d4a45f7aefd5a7f5bbab609 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 Mar 2020 23:17:07 +0100 Subject: [PATCH 1683/5092] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index aaf176861b0d..29c1f3a2a83e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -98803c182b2ba6ef5dccb6bf501958249295eac0 +38114ff16e7856f98b2b4be7ab4cd29b38bed59a From 78fe5288d0f76ecb0993ed3be3dfc4eb731cea84 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 Mar 2020 23:17:18 +0100 Subject: [PATCH 1684/5092] do more cross-testing --- .travis.yml | 2 -- travis.sh | 35 +++++++++++++++++++++-------------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3f0ca8a016bd..137ae4fe6625 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,8 +21,6 @@ env: - RUST_BACKTRACE=1 before_script: -# Linux: install extra stuff for cross-compilation -- if [[ "$TRAVIS_OS_NAME" == linux ]]; then sudo apt update && sudo apt install gcc-multilib; fi # Compute the rust version we use. We do not use "language: rust" to have more control here. - | if [[ "$TRAVIS_EVENT_TYPE" == cron ]]; then diff --git a/travis.sh b/travis.sh index fec9145ab0f7..4988c0e76ff6 100755 --- a/travis.sh +++ b/travis.sh @@ -2,9 +2,6 @@ set -euo pipefail # Determine configuration -if [ "$TRAVIS_OS_NAME" == linux ]; then - FOREIGN_TARGET=i686-unknown-linux-gnu -fi export CARGO_EXTRA_FLAGS="--all-features" export RUSTC_EXTRA_FLAGS="-D warnings" @@ -16,19 +13,29 @@ echo # Test function run_tests { - ./miri test --locked + if [ -n "${FOREIGN_TARGET+exists}" ]; then + echo "Testing foreign architecture $FOREIGN_TARGET" + else + echo "Testing host architecture" + fi + + ./miri test --locked + if ! [ -n "${FOREIGN_TARGET+exists}" ]; then + # Only for host architecture: tests with MIR optimizations MIRI_TEST_FLAGS="-Z mir-opt-level=3" ./miri test - # "miri test" has built the sysroot for us, now this should pass without - # any interactive questions. - test-cargo-miri/run-test.py + fi + # "miri test" has built the sysroot for us, now this should pass without + # any interactive questions. + test-cargo-miri/run-test.py + + echo } -echo "Test host architecture" +# host run_tests -echo - -if [ -n "${FOREIGN_TARGET+exists}" ]; then - echo "Test foreign architecture ($FOREIGN_TARGET)" - MIRI_TEST_TARGET="$FOREIGN_TARGET" run_tests - echo +# cross-test 32bit Linux from everywhere +MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests +if [ "$TRAVIS_OS_NAME" == linux ]; then + # cross-test 64bit macOS from Linux + FOREIGN_TARGET=x86_64-apple-darwin run_tests fi From 82fe7716765c665565ff668c440303fe21345890 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 Mar 2020 23:26:44 +0100 Subject: [PATCH 1685/5092] also cross-test Windows from Linux, macOS --- travis.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/travis.sh b/travis.sh index 4988c0e76ff6..e9fa3b6c1aed 100755 --- a/travis.sh +++ b/travis.sh @@ -35,7 +35,13 @@ function run_tests { run_tests # cross-test 32bit Linux from everywhere MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests + if [ "$TRAVIS_OS_NAME" == linux ]; then # cross-test 64bit macOS from Linux FOREIGN_TARGET=x86_64-apple-darwin run_tests + # cross-test 32bit Windows from Linux + FOREIGN_TARGET=i686-pc-windows-msvc run_tests +elif [ "$TRAVIS_OS_NAME" == osx ]; then + # cross-test 64bit Windows from macOS + FOREIGN_TARGET=x86_64-pc-windows-msvc run_tests fi From dece5bc4eec2fbe421cb95ca5c43e11cb6b93fc5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 Mar 2020 23:28:10 +0100 Subject: [PATCH 1686/5092] fix bad use of FOREIGN_TARGET --- travis.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/travis.sh b/travis.sh index e9fa3b6c1aed..8b2453584b09 100755 --- a/travis.sh +++ b/travis.sh @@ -13,14 +13,14 @@ echo # Test function run_tests { - if [ -n "${FOREIGN_TARGET+exists}" ]; then - echo "Testing foreign architecture $FOREIGN_TARGET" + if [ -n "${MIRI_TEST_TARGET+exists}" ]; then + echo "Testing foreign architecture $MIRI_TEST_TARGET" else echo "Testing host architecture" fi ./miri test --locked - if ! [ -n "${FOREIGN_TARGET+exists}" ]; then + if ! [ -n "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with MIR optimizations MIRI_TEST_FLAGS="-Z mir-opt-level=3" ./miri test fi @@ -38,10 +38,10 @@ MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests if [ "$TRAVIS_OS_NAME" == linux ]; then # cross-test 64bit macOS from Linux - FOREIGN_TARGET=x86_64-apple-darwin run_tests + MIRI_TEST_TARGET=x86_64-apple-darwin run_tests # cross-test 32bit Windows from Linux - FOREIGN_TARGET=i686-pc-windows-msvc run_tests + MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests elif [ "$TRAVIS_OS_NAME" == osx ]; then # cross-test 64bit Windows from macOS - FOREIGN_TARGET=x86_64-pc-windows-msvc run_tests + MIRI_TEST_TARGET=x86_64-pc-windows-msvc run_tests fi From d85f09c4e4bdee1d9698dce9a2163f46f1e1697d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Mar 2020 08:51:15 +0100 Subject: [PATCH 1687/5092] platform -> target --- src/eval.rs | 2 +- src/helpers.rs | 12 +++++------ src/machine.rs | 2 +- src/shims/foreign_items.rs | 2 +- src/shims/fs.rs | 26 ++++++++++++------------ src/shims/panic.rs | 4 ++-- src/shims/time.rs | 6 +++--- test-cargo-miri/tests/test.rs | 2 +- tests/compile-fail/panic/windows1.rs | 2 +- tests/compile-fail/panic/windows2.rs | 2 +- tests/compile-fail/panic/windows3.rs | 2 +- tests/run-pass/bitop-beyond-alignment.rs | 2 +- tests/run-pass/memchr.rs | 2 +- 13 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 898e1ff6e4be..de6c9fac1d5e 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -190,7 +190,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( /// Returns `Some(return_code)` if program executed completed. /// Returns `None` if an evaluation error occured. pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option { - // FIXME: We always ignore leaks on some platforms where we do not + // FIXME: We always ignore leaks on some OSs where we do not // correctly implement TLS destructors. let target_os = tcx.sess.target.target.target_os.as_str(); let ignore_leaks = config.ignore_leaks || target_os == "windows" || target_os == "macos"; diff --git a/src/helpers.rs b/src/helpers.rs index 169bb4205649..36d3181ce4e4 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -374,16 +374,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(()) } - /// Helper function used inside the shims of foreign functions to assert that the target - /// platform is `platform`. It panics showing a message with the `name` of the foreign function + /// Helper function used inside the shims of foreign functions to assert that the target OS + /// is `target_os`. It panics showing a message with the `name` of the foreign function /// if this is not the case. - fn assert_platform(&self, platform: &str, name: &str) { + fn assert_target_os(&self, target_os: &str, name: &str) { assert_eq!( self.eval_context_ref().tcx.sess.target.target.target_os, - platform, - "`{}` is only available on the `{}` platform", + target_os, + "`{}` is only available on the `{}` target OS", name, - platform, + target_os, ) } diff --git a/src/machine.rs b/src/machine.rs index 3cf00781338c..693c80f7deae 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -126,7 +126,7 @@ impl MemoryExtra { .insert(Symbol::intern("environ"), this.machine.env_vars.environ.unwrap().ptr.assert_ptr().alloc_id) .unwrap_none(); } - _ => {} // No "extern statics" supported on this platform + _ => {} // No "extern statics" supported on this target } Ok(()) } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 60da1f1e6cc6..6827b72427fb 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -437,7 +437,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => match this.tcx.sess.target.target.target_os.as_str() { "linux" | "macos" => return posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), "windows" => return windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), - target => throw_unsup_format!("the {} target platform is not supported", target), + target => throw_unsup_format!("the target `{}` is not supported", target), } }; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index a5aae5ed90c3..d799d8ed9a8a 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -66,9 +66,9 @@ impl FileHandler { impl<'mir, 'tcx> EvalContextExtPrivate<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// Emulate `stat` or `lstat` on the `macos` platform. This function is not intended to be + /// Emulate `stat` or `lstat` on `macos`. This function is not intended to be /// called directly from `emulate_foreign_item_by_name`, so it does not check if isolation is - /// disabled or if the target platform is the correct one. Please use `macos_stat` or + /// disabled or if the target OS is the correct one. Please use `macos_stat` or /// `macos_lstat` instead. fn macos_stat_or_lstat( &mut self, @@ -114,7 +114,7 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' let blksize_t_layout = this.libc_ty_layout("blksize_t")?; let uint32_t_layout = this.libc_ty_layout("uint32_t")?; - // We need to add 32 bits of padding after `st_rdev` if we are on a 64-bit platform. + // We need to add 32 bits of padding after `st_rdev` if we are on a 64-bit target. let pad_layout = if this.tcx.sess.target.ptr_width == 64 { uint32_t_layout } else { @@ -258,10 +258,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let o_wronly = this.eval_libc_i32("O_WRONLY")?; let o_rdwr = this.eval_libc_i32("O_RDWR")?; // The first two bits of the flag correspond to the access mode in linux, macOS and - // windows. We need to check that in fact the access mode flags for the current platform - // only use these two bits, otherwise we are in an unsupported platform and should error. + // windows. We need to check that in fact the access mode flags for the current target + // only use these two bits, otherwise we are in an unsupported target and should error. if (o_rdonly | o_wronly | o_rdwr) & !0b11 != 0 { - throw_unsup_format!("access mode flags on this platform are unsupported"); + throw_unsup_format!("access mode flags on this target are unsupported"); } let mut writable = true; @@ -574,7 +574,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx buf_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.assert_platform("macos", "stat"); + this.assert_target_os("macos", "stat"); this.check_no_isolation("stat")?; // `stat` always follows symlinks. this.macos_stat_or_lstat(true, path_op, buf_op) @@ -587,7 +587,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx buf_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.assert_platform("macos", "lstat"); + this.assert_target_os("macos", "lstat"); this.check_no_isolation("lstat")?; this.macos_stat_or_lstat(false, path_op, buf_op) } @@ -599,7 +599,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.assert_platform("macos", "fstat"); + this.assert_target_os("macos", "fstat"); this.check_no_isolation("fstat")?; let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -621,7 +621,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.assert_platform("linux", "statx"); + this.assert_target_os("linux", "statx"); this.check_no_isolation("statx")?; let statxbuf_scalar = this.read_scalar(statxbuf_op)?.not_undef()?; @@ -685,7 +685,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // the `_mask_op` paramter specifies the file information that the caller requested. // However `statx` is allowed to return information that was not requested or to not // return information that was requested. This `mask` represents the information we can - // actually provide in any host platform. + // actually provide for any target. let mut mask = this.eval_libc("STATX_TYPE")?.to_u32()? | this.eval_libc("STATX_SIZE")?.to_u32()?; @@ -880,7 +880,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.assert_platform("linux", "readdir64_r"); + this.assert_target_os("linux", "readdir64_r"); this.check_no_isolation("readdir64_r")?; let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; @@ -967,7 +967,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.assert_platform("macos", "readdir_r"); + this.assert_target_os("macos", "readdir_r"); this.check_no_isolation("readdir_r")?; let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 8dded8bf4037..703e711972a7 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -32,11 +32,11 @@ pub struct CatchUnwindData<'tcx> { impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// Check if panicking is supported on this platform, and give a good error otherwise. + /// Check if panicking is supported on this target, and give a good error otherwise. fn check_panic_supported(&self) -> InterpResult<'tcx> { match self.eval_context_ref().tcx.sess.target.target.target_os.as_str() { "linux" | "macos" => Ok(()), - _ => throw_unsup_format!("panicking is not supported on this platform"), + _ => throw_unsup_format!("panicking is not supported on this target"), } } diff --git a/src/shims/time.rs b/src/shims/time.rs index b270c9770f80..58db60e51688 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -20,7 +20,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.assert_platform("linux", "clock_gettime"); + this.assert_target_os("linux", "clock_gettime"); this.check_no_isolation("clock_gettime")?; let clk_id = this.read_scalar(clk_id_op)?.to_i32()?; @@ -58,7 +58,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.assert_platform("macos", "gettimeofday"); + this.assert_target_os("macos", "gettimeofday"); this.check_no_isolation("gettimeofday")?; // Using tz is obsolete and should always be null @@ -88,7 +88,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn mach_absolute_time(&self) -> InterpResult<'tcx, u64> { let this = self.eval_context_ref(); - this.assert_platform("macos", "mach_absolute_time"); + this.assert_target_os("macos", "mach_absolute_time"); this.check_no_isolation("mach_absolute_time")?; // This returns a u64, with time units determined dynamically by `mach_timebase_info`. diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 0095802a59a8..68d5426802b4 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -45,7 +45,7 @@ fn num_cpus() { // FIXME: Remove this `cfg` once we fix https://github.com/rust-lang/miri/issues/1059. // We cfg-gate the `should_panic` attribute and the `panic!` itself, so that the test -// stdout does not depend on the platform. +// stdout does not depend on the target. #[test] #[cfg_attr(not(windows), should_panic(expected="Explicit panic"))] fn do_panic() { // In large, friendly letters :) diff --git a/tests/compile-fail/panic/windows1.rs b/tests/compile-fail/panic/windows1.rs index 1d6faf1e751d..142ba85c42c7 100644 --- a/tests/compile-fail/panic/windows1.rs +++ b/tests/compile-fail/panic/windows1.rs @@ -3,7 +3,7 @@ // Test that panics on Windows give a reasonable error message. -// error-pattern: panicking is not supported on this platform +// error-pattern: panicking is not supported on this target fn main() { core::panic!("this is {}", "Windows"); } diff --git a/tests/compile-fail/panic/windows2.rs b/tests/compile-fail/panic/windows2.rs index 023088a692ef..da2cfb59362e 100644 --- a/tests/compile-fail/panic/windows2.rs +++ b/tests/compile-fail/panic/windows2.rs @@ -3,7 +3,7 @@ // Test that panics on Windows give a reasonable error message. -// error-pattern: panicking is not supported on this platform +// error-pattern: panicking is not supported on this target fn main() { std::panic!("this is Windows"); } diff --git a/tests/compile-fail/panic/windows3.rs b/tests/compile-fail/panic/windows3.rs index b96022fc4ef5..a2e7bf5a7d43 100644 --- a/tests/compile-fail/panic/windows3.rs +++ b/tests/compile-fail/panic/windows3.rs @@ -3,7 +3,7 @@ // Test that panics on Windows give a reasonable error message. -// error-pattern: panicking is not supported on this platform +// error-pattern: panicking is not supported on this target #[allow(unconditional_panic)] fn main() { let _val = 1/0; diff --git a/tests/run-pass/bitop-beyond-alignment.rs b/tests/run-pass/bitop-beyond-alignment.rs index a30f0fb61314..02031130b8dc 100644 --- a/tests/run-pass/bitop-beyond-alignment.rs +++ b/tests/run-pass/bitop-beyond-alignment.rs @@ -33,5 +33,5 @@ fn is_u64_aligned(u: &Tag) -> bool { pub fn main() { let x = mk_rec(); - is_u64_aligned(&x.t); // the result of this is non-deterministic (even with a fixed seed, results vary between platforms) + is_u64_aligned(&x.t); // the result of this is non-deterministic (even with a fixed seed, results vary between targets) } diff --git a/tests/run-pass/memchr.rs b/tests/run-pass/memchr.rs index 2f5e2c4bb739..e92c37ff2a8c 100644 --- a/tests/run-pass/memchr.rs +++ b/tests/run-pass/memchr.rs @@ -2,7 +2,7 @@ use core::slice::memchr::{memchr, memrchr}; -// test fallback implementations on all platforms +// test fallback implementations on all targets fn matches_one() { assert_eq!(Some(0), memchr(b'a', b"a")); } From e1b654f09a6adeddb5a8b5e91cdcec656184c33f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Mar 2020 08:55:53 +0100 Subject: [PATCH 1688/5092] mention cross-running in docs --- CONTRIBUTING.md | 10 ++++++---- README.md | 5 +++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c673e107d55d..573f9f6ef6e4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -52,18 +52,19 @@ all the same flags as `rustc` (though the ones only affecting code generation and linking obviously will have no effect) [and more][miri-flags]. Running the Miri driver requires some fiddling with environment variables, so -the `miri` script helps you do that. For example, you can run the driver on a -particular file by doing +the `miri` script helps you do that. For example, you can (cross-)run the +driver on a particular file by doing ```sh ./miri run tests/run-pass/format.rs ./miri run tests/run-pass/hello.rs --target i686-unknown-linux-gnu ``` -and you can run the test suite using: +and you can (cross-)run the test suite using: ``` ./miri test +MIRI_TEST_TARGET=i686-unknown-linux-gnu ./miri test ``` `./miri test FILTER` only runs those tests that contain `FILTER` in their @@ -104,7 +105,8 @@ and then you can use it as if it was installed by `rustup`. Make sure you use the same toolchain when calling `cargo miri` that you used when installing Miri! There's a test for the cargo wrapper in the `test-cargo-miri` directory; run -`./run-test.py` in there to execute it. +`./run-test.py` in there to execute it. Like `./miri test`, this respects the +`MIRI_TEST_TARGET` environment variable to execute the test for another target. ## Building Miri with a locally built rustc diff --git a/README.md b/README.md index e0e7df24faad..59394830d79b 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,11 @@ Now you can run your project in Miri: The first time you run Miri, it will perform some extra setup and install some dependencies. It will ask you for confirmation before installing anything. +Miri supports cross-execution: if you want to run the program as if it was a +Linux program, you can do `cargo miri run --target x86_64-unknown-linux-gnu`. +This is particularly useful if you are using Windows, as the Linux target is +much better supported than Windows targets. + You can pass arguments to Miri after the first `--`, and pass arguments to the interpreted program or test suite after the second `--`. For example, `cargo miri run -- -Zmiri-disable-validation` runs the program without validation of From b843de6dd22f9fdfd998cd0c105cce17a31ab639 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Mar 2020 09:04:10 +0100 Subject: [PATCH 1689/5092] run-test.py: also print what we are testing for --- test-cargo-miri/run-test.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index a4086bcc8c99..57b23a6a2afe 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -7,6 +7,10 @@ and the working directory to contain the cargo-miri-test project. import sys, subprocess, os +CGREEN = '\33[32m' +CBOLD = '\33[1m' +CEND = '\33[0m' + def fail(msg): print("\nTEST FAIL: {}".format(msg)) sys.exit(1) @@ -67,6 +71,9 @@ def test_cargo_miri_test(): os.chdir(os.path.dirname(os.path.realpath(__file__))) +target_str = " for target {}".format(os.environ['MIRI_TEST_TARGET']) if 'MIRI_TEST_TARGET' in os.environ else "" +print(CGREEN + CBOLD + "## Running `cargo miri` tests{}".format(target_str) + CEND) + if not 'MIRI_SYSROOT' in os.environ: # Make sure we got a working sysroot. # (If the sysroot gets built later when output is compared, that leads to test failures.) From a1b823886c072dfda3e3fdd34e5661beaf57d6d7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Mar 2020 18:50:12 +0100 Subject: [PATCH 1690/5092] give some context in error messages --- src/diagnostics.rs | 91 ++++++++++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 36 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index b2590a843ba9..ee4084f42daf 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -1,6 +1,7 @@ -use rustc_mir::interpret::InterpErrorInfo; use std::cell::RefCell; +use rustc_span::DUMMY_SP; + use crate::*; /// Miri specific diagnostics @@ -14,9 +15,16 @@ pub fn report_diagnostic<'tcx, 'mir>( ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, mut e: InterpErrorInfo<'tcx>, ) -> Option { - // Special treatment for some error kinds + use InterpError::*; + let title = match e.kind { + Unsupported(_) => "unsupported operation", + UndefinedBehavior(_) => "Undefined Behavior", + InvalidProgram(_) => bug!("This error should be impossible in Miri: {}", e), + ResourceExhaustion(_) => "resource exhaustion", + MachineStop(_) => "program stopped", + }; let msg = match e.kind { - InterpError::MachineStop(ref info) => { + MachineStop(ref info) => { let info = info.downcast_ref::().expect("invalid MachineStop payload"); match info { TerminationInfo::Exit(code) => return Some(*code), @@ -24,51 +32,62 @@ pub fn report_diagnostic<'tcx, 'mir>( TerminationInfo::Abort(Some(msg)) => format!("the evaluated program aborted execution: {}", msg), } } - err_unsup!(NoMirFor(..)) => format!( - "{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", - e - ), - InterpError::InvalidProgram(_) => bug!("This error should be impossible in Miri: {}", e), _ => e.to_string(), }; + let help = match e.kind { + Unsupported(UnsupportedOpInfo::NoMirFor(..)) => + Some("set `MIRI_SYSROOT` to a Miri sysroot, which you can prepare with `cargo miri setup`"), + Unsupported(_) => + Some("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"), + UndefinedBehavior(UndefinedBehaviorInfo::UbExperimental(_)) => + Some("this indicates a potential bug in the program: it violated *experimental* rules, and caused Undefined Behavior"), + UndefinedBehavior(_) => + Some("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior"), + _ => None, + }; e.print_backtrace(); - report_msg(ecx, msg, true) + report_msg(ecx, &format!("{}: {}", title, msg), msg, help, true) } /// Report an error or note (depending on the `error` argument) at the current frame's current statement. /// Also emits a full stacktrace of the interpreter stack. pub fn report_msg<'tcx, 'mir>( ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, - msg: String, + title: &str, + span_msg: String, + help: Option<&str>, error: bool, ) -> Option { - if let Some(frame) = ecx.stack().last() { - let span = frame.current_source_info().unwrap().span; - - let mut err = if error { - let msg = format!("Miri evaluation error: {}", msg); - ecx.tcx.sess.struct_span_err(span, msg.as_str()) - } else { - ecx.tcx.sess.diagnostic().span_note_diag(span, msg.as_str()) - }; - let frames = ecx.generate_stacktrace(None); - err.span_label(span, msg); - // We iterate with indices because we need to look at the next frame (the caller). - for idx in 0..frames.len() { - let frame_info = &frames[idx]; - let call_site_is_local = frames - .get(idx + 1) - .map_or(false, |caller_info| caller_info.instance.def_id().is_local()); - if call_site_is_local { - err.span_note(frame_info.call_site, &frame_info.to_string()); - } else { - err.note(&frame_info.to_string()); - } - } - err.emit(); + let span = if let Some(frame) = ecx.stack().last() { + frame.current_source_info().unwrap().span } else { - ecx.tcx.sess.err(&msg); + DUMMY_SP + }; + let mut err = if error { + ecx.tcx.sess.struct_span_err(span, title) + } else { + ecx.tcx.sess.diagnostic().span_note_diag(span, title) + }; + err.span_label(span, span_msg); + if let Some(help) = help { + err.help(help); } + // Add backtrace + let frames = ecx.generate_stacktrace(None); + // We iterate with indices because we need to look at the next frame (the caller). + for idx in 0..frames.len() { + let frame_info = &frames[idx]; + let call_site_is_local = frames + .get(idx + 1) + .map_or(false, |caller_info| caller_info.instance.def_id().is_local()); + if call_site_is_local { + err.span_note(frame_info.call_site, &frame_info.to_string()); + } else { + err.note(&frame_info.to_string()); + } + } + + err.emit(); for (i, frame) in ecx.stack().iter().enumerate() { trace!("-------------------"); @@ -106,7 +125,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx CreatedAlloc(AllocId(id)) => format!("created allocation with id {}", id), }; - report_msg(this, msg, false); + report_msg(this, "tracking was triggered", msg, None, false); } }); } From 6dcca62b63135306aab50afc85075afa7427559a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Mar 2020 19:48:59 +0100 Subject: [PATCH 1691/5092] move -Zmiri-disable-isolation hint to help --- src/diagnostics.rs | 86 +++++++++++++++++++++++++++++----------------- src/eval.rs | 8 +---- src/helpers.rs | 6 ++-- src/lib.rs | 6 ++-- 4 files changed, 62 insertions(+), 44 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index ee4084f42daf..c46ff5354dec 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -4,6 +4,13 @@ use rustc_span::DUMMY_SP; use crate::*; +/// Details of premature program termination. +pub enum TerminationInfo { + Exit(i64), + Abort(Option), + UnsupportedInIsolation(String), +} + /// Miri specific diagnostics pub enum NonHaltingDiagnostic { PoppedTrackedPointerTag(Item), @@ -11,47 +18,64 @@ pub enum NonHaltingDiagnostic { } /// Emit a custom diagnostic without going through the miri-engine machinery -pub fn report_diagnostic<'tcx, 'mir>( +pub fn report_error<'tcx, 'mir>( ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, mut e: InterpErrorInfo<'tcx>, ) -> Option { use InterpError::*; - let title = match e.kind { - Unsupported(_) => "unsupported operation", - UndefinedBehavior(_) => "Undefined Behavior", - InvalidProgram(_) => bug!("This error should be impossible in Miri: {}", e), - ResourceExhaustion(_) => "resource exhaustion", - MachineStop(_) => "program stopped", - }; - let msg = match e.kind { - MachineStop(ref info) => { - let info = info.downcast_ref::().expect("invalid MachineStop payload"); - match info { - TerminationInfo::Exit(code) => return Some(*code), - TerminationInfo::Abort(None) => format!("the evaluated program aborted execution"), - TerminationInfo::Abort(Some(msg)) => format!("the evaluated program aborted execution: {}", msg), - } - } - _ => e.to_string(), - }; - let help = match e.kind { - Unsupported(UnsupportedOpInfo::NoMirFor(..)) => - Some("set `MIRI_SYSROOT` to a Miri sysroot, which you can prepare with `cargo miri setup`"), - Unsupported(_) => - Some("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"), - UndefinedBehavior(UndefinedBehaviorInfo::UbExperimental(_)) => - Some("this indicates a potential bug in the program: it violated *experimental* rules, and caused Undefined Behavior"), - UndefinedBehavior(_) => - Some("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior"), - _ => None, - }; + e.print_backtrace(); + let (title, msg, help) = match e.kind { + MachineStop(info) => { + let info = info.downcast_ref::().expect("invalid MachineStop payload"); + use TerminationInfo::*; + let (title, msg) = match info { + Exit(code) => return Some(*code), + Abort(None) => + ("abnormal termination", format!("the evaluated program aborted execution")), + Abort(Some(msg)) => + ("abnormal termination", format!("the evaluated program aborted execution: {}", msg)), + UnsupportedInIsolation(msg) => + ("unsupported operation", format!("{}", msg)), + }; + let help = match info { + UnsupportedInIsolation(_) => + Some("pass the flag `-Zmiri-disable-isolation` to disable isolation"), + _ => None, + }; + (title, msg, help) + } + _ => { + let (title, msg) = match e.kind { + Unsupported(_) => + ("unsupported operation", e.to_string()), + UndefinedBehavior(_) => + ("Undefined Behavior", e.to_string()), + ResourceExhaustion(_) => + ("resource exhaustion", e.to_string()), + _ => + bug!("This error should be impossible in Miri: {}", e), + }; + let help = match e.kind { + Unsupported(UnsupportedOpInfo::NoMirFor(..)) => + Some("set `MIRI_SYSROOT` to a Miri sysroot, which you can prepare with `cargo miri setup`"), + Unsupported(_) => + Some("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"), + UndefinedBehavior(UndefinedBehaviorInfo::UbExperimental(_)) => + Some("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental"), + UndefinedBehavior(_) => + Some("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior"), + _ => None, + }; + (title, msg, help) + } + }; report_msg(ecx, &format!("{}: {}", title, msg), msg, help, true) } /// Report an error or note (depending on the `error` argument) at the current frame's current statement. /// Also emits a full stacktrace of the interpreter stack. -pub fn report_msg<'tcx, 'mir>( +fn report_msg<'tcx, 'mir>( ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, title: &str, span_msg: String, diff --git a/src/eval.rs b/src/eval.rs index de6c9fac1d5e..d2ca57c39a79 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -51,12 +51,6 @@ impl Default for MiriConfig { } } -/// Details of premature program termination. -pub enum TerminationInfo { - Exit(i64), - Abort(Option), -} - /// Returns a freshly created `InterpCx`, along with an `MPlaceTy` representing /// the location where the return value of the `start` lang item will be /// written to. @@ -229,6 +223,6 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> } Some(return_code) } - Err(e) => report_diagnostic(&ecx, e), + Err(e) => report_error(&ecx, e), } } diff --git a/src/helpers.rs b/src/helpers.rs index 36d3181ce4e4..ab6e33f23188 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -367,10 +367,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// case. fn check_no_isolation(&self, name: &str) -> InterpResult<'tcx> { if !self.eval_context_ref().machine.communicate { - throw_unsup_format!( - "`{}` not available when isolation is enabled (pass the flag `-Zmiri-disable-isolation` to disable isolation)", + throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!( + "`{}` not available when isolation is enabled", name, - ) + ))) } Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index 86fbabbd629e..32eb5b41e591 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,10 +45,10 @@ pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::EvalContextExt as ShimsEvalContextExt; pub use crate::diagnostics::{ - register_diagnostic, report_diagnostic, EvalContextExt as DiagnosticsEvalContextExt, - NonHaltingDiagnostic, + register_diagnostic, report_error, EvalContextExt as DiagnosticsEvalContextExt, + TerminationInfo, NonHaltingDiagnostic, }; -pub use crate::eval::{create_ecx, eval_main, MiriConfig, TerminationInfo}; +pub use crate::eval::{create_ecx, eval_main, MiriConfig}; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; pub use crate::machine::{ AllocExtra, Evaluator, FrameData, MemoryExtra, MiriEvalContext, MiriEvalContextExt, From dd4fef0cd95ba90ea6e1a13f054e2b66f36772ff Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Mar 2020 20:09:14 +0100 Subject: [PATCH 1692/5092] fix outdated sysroot help message --- src/diagnostics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index c46ff5354dec..1008c0468464 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -58,7 +58,7 @@ pub fn report_error<'tcx, 'mir>( }; let help = match e.kind { Unsupported(UnsupportedOpInfo::NoMirFor(..)) => - Some("set `MIRI_SYSROOT` to a Miri sysroot, which you can prepare with `cargo miri setup`"), + Some("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`"), Unsupported(_) => Some("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"), UndefinedBehavior(UndefinedBehaviorInfo::UbExperimental(_)) => From 6e302b830a8ac07efc1dca3ba1354338801bf7d4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Mar 2020 23:32:19 +0100 Subject: [PATCH 1693/5092] link to some websites for UB explanations --- src/diagnostics.rs | 43 +++++++++++++++++++++++++----------------- src/stacked_borrows.rs | 29 ++++++++++++++++++---------- 2 files changed, 45 insertions(+), 27 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 1008c0468464..a2cdffdf80b3 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -9,6 +9,7 @@ pub enum TerminationInfo { Exit(i64), Abort(Option), UnsupportedInIsolation(String), + ExperimentalUb { msg: String, url: String } } /// Miri specific diagnostics @@ -25,7 +26,7 @@ pub fn report_error<'tcx, 'mir>( use InterpError::*; e.print_backtrace(); - let (title, msg, help) = match e.kind { + let (title, msg, helps) = match e.kind { MachineStop(info) => { let info = info.downcast_ref::().expect("invalid MachineStop payload"); use TerminationInfo::*; @@ -37,13 +38,20 @@ pub fn report_error<'tcx, 'mir>( ("abnormal termination", format!("the evaluated program aborted execution: {}", msg)), UnsupportedInIsolation(msg) => ("unsupported operation", format!("{}", msg)), + ExperimentalUb { msg, .. } => + ("Undefined Behavior", format!("{}", msg)), }; - let help = match info { + let helps = match info { UnsupportedInIsolation(_) => - Some("pass the flag `-Zmiri-disable-isolation` to disable isolation"), - _ => None, + vec![format!("pass the flag `-Zmiri-disable-isolation` to disable isolation")], + ExperimentalUb { url, .. } => + vec![ + format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental"), + format!("see {} for further information", url), + ], + _ => vec![], }; - (title, msg, help) + (title, msg, helps) } _ => { let (title, msg) = match e.kind { @@ -56,21 +64,22 @@ pub fn report_error<'tcx, 'mir>( _ => bug!("This error should be impossible in Miri: {}", e), }; - let help = match e.kind { + let helps = match e.kind { Unsupported(UnsupportedOpInfo::NoMirFor(..)) => - Some("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`"), + vec![format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`")], Unsupported(_) => - Some("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"), - UndefinedBehavior(UndefinedBehaviorInfo::UbExperimental(_)) => - Some("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental"), + vec![format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support")], UndefinedBehavior(_) => - Some("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior"), - _ => None, + vec![ + format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior"), + format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information"), + ], + _ => vec![], }; - (title, msg, help) + (title, msg, helps) } }; - report_msg(ecx, &format!("{}: {}", title, msg), msg, help, true) + report_msg(ecx, &format!("{}: {}", title, msg), msg, &helps, true) } /// Report an error or note (depending on the `error` argument) at the current frame's current statement. @@ -79,7 +88,7 @@ fn report_msg<'tcx, 'mir>( ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, title: &str, span_msg: String, - help: Option<&str>, + helps: &[String], error: bool, ) -> Option { let span = if let Some(frame) = ecx.stack().last() { @@ -93,7 +102,7 @@ fn report_msg<'tcx, 'mir>( ecx.tcx.sess.diagnostic().span_note_diag(span, title) }; err.span_label(span, span_msg); - if let Some(help) = help { + for help in helps { err.help(help); } // Add backtrace @@ -149,7 +158,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx CreatedAlloc(AllocId(id)) => format!("created allocation with id {}", id), }; - report_msg(this, "tracking was triggered", msg, None, false); + report_msg(this, "tracking was triggered", msg, &[], false); } }); } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 6188d05780cb..05b9c478cfea 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -192,6 +192,15 @@ impl GlobalState { } } +/// Error reporting +fn err_sb_ub(msg: String) -> InterpError<'static> { + // FIXME: use `err_machine_stop!` macro, once that exists. + InterpError::MachineStop(Box::new(TerminationInfo::ExperimentalUb { + msg, + url: format!("https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md"), + })) +} + // # Stacked Borrows Core Begin /// We need to make at least the following things true: @@ -272,15 +281,15 @@ impl<'tcx> Stack { if let Some(call) = item.protector { if global.is_active(call) { if let Some(tag) = tag { - throw_ub!(UbExperimental(format!( + Err(err_sb_ub(format!( "not granting access to tag {:?} because incompatible item is protected: {:?}", tag, item - ))); + )))? } else { - throw_ub!(UbExperimental(format!( + Err(err_sb_ub(format!( "deallocating while item is protected: {:?}", item - ))); + )))? } } } @@ -294,10 +303,10 @@ impl<'tcx> Stack { // Step 1: Find granting item. let granting_idx = self.find_granting(access, tag).ok_or_else(|| { - err_ub!(UbExperimental(format!( + err_sb_ub(format!( "no item granting {} to tag {:?} found in borrow stack.", access, tag - ),)) + )) })?; // Step 2: Remove incompatible items above them. Make sure we do not remove protected @@ -338,10 +347,10 @@ impl<'tcx> Stack { fn dealloc(&mut self, tag: Tag, global: &GlobalState) -> InterpResult<'tcx> { // Step 1: Find granting item. self.find_granting(AccessKind::Write, tag).ok_or_else(|| { - err_ub!(UbExperimental(format!( + err_sb_ub(format!( "no item granting write access for deallocation to tag {:?} found in borrow stack", tag, - ))) + )) })?; // Step 2: Remove all items. Also checks for protectors. @@ -363,10 +372,10 @@ impl<'tcx> Stack { // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. let granting_idx = self.find_granting(access, derived_from) - .ok_or_else(|| err_ub!(UbExperimental(format!( + .ok_or_else(|| err_sb_ub(format!( "trying to reborrow for {:?}, but parent tag {:?} does not have an appropriate item in the borrow stack", new.perm, derived_from, - ))))?; + )))?; // Compute where to put the new item. // Either way, we ensure that we insert the new item in a way such that between From b4b8750e447058e06e8bf5ad38645ee05a81ef42 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 Mar 2020 10:34:15 +0100 Subject: [PATCH 1694/5092] bump Rust; HashMap should now work on macOS even with isolation --- rust-version | 2 +- src/shims/foreign_items/posix/macos.rs | 7 ------- tests/run-pass/hashmap.rs | 10 +++------- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/rust-version b/rust-version index 29c1f3a2a83e..70ece06e4f02 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -38114ff16e7856f98b2b4be7ab4cd29b38bed59a +8ff785011be6625e32afceee3a08e5cff7470feb diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 0bb4710769d9..ee02effecd2c 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -98,13 +98,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; } - "SecRandomCopyBytes" => { - let len = this.read_scalar(args[1])?.to_machine_usize(this)?; - let ptr = this.read_scalar(args[2])?.not_undef()?; - this.gen_random(ptr, len)?; - this.write_null(dest)?; - } - _ => throw_unsup_format!("can't call foreign function: {}", link_name), }; diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass/hashmap.rs index 85116796d385..488fe6afe65e 100644 --- a/tests/run-pass/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -1,10 +1,7 @@ -// macOS needs FS access for its HashMap: -// compile-flags: -Zmiri-disable-isolation - use std::collections::HashMap; use std::hash::BuildHasher; -fn test_map(mut map: HashMap) { +fn smoketest_map(mut map: HashMap) { map.insert(0, 0); assert_eq!(map.values().fold(0, |x, y| x+y), 0); @@ -19,10 +16,9 @@ fn test_map(mut map: HashMap) { map.insert(i, num-1-i); } assert_eq!(map.values().fold(0, |x, y| x+y), num*(num-1)/2); - - // TODO: Test Entry API, Iterators, ... } fn main() { - test_map(HashMap::new()); + // hashbrown uses Miri on its own CI; we just do a smoketest here. + smoketest_map(HashMap::new()); } From 2f371774ef632f2dcc4548a39e8b6b98422a725b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 Mar 2020 19:43:03 +0100 Subject: [PATCH 1695/5092] fix conditional compilation condition for os_str <-> bytes conversion --- src/helpers.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index ab6e33f23188..b4706f04d9b8 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -463,11 +463,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx 'tcx: 'a, 'mir: 'a, { - #[cfg(target_os = "unix")] + #[cfg(unix)] fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { - Ok(std::os::unix::ffi::OsStringExt::from_bytes(bytes)) + Ok(std::os::unix::ffi::OsStrExt::from_bytes(bytes)) } - #[cfg(not(target_os = "unix"))] + #[cfg(not(unix))] fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { let s = std::str::from_utf8(bytes) .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; @@ -490,11 +490,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx scalar: Scalar, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { - #[cfg(target_os = "unix")] + #[cfg(unix)] fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - std::os::unix::ffi::OsStringExt::into_bytes(os_str) + Ok(std::os::unix::ffi::OsStrExt::as_bytes(os_str)) } - #[cfg(not(target_os = "unix"))] + #[cfg(not(unix))] fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually From 284067cc15f5254b6b0391c1c93de8f34a8a4e8c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 Mar 2020 23:48:24 +0100 Subject: [PATCH 1696/5092] rustup --- rust-version | 2 +- src/stacked_borrows.rs | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index 70ece06e4f02..1270131b7267 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8ff785011be6625e32afceee3a08e5cff7470feb +1edd389cc4c7b5be7a3dd4fe4b986f6017018e54 diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 05b9c478cfea..37f2acf4c3bc 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -194,11 +194,10 @@ impl GlobalState { /// Error reporting fn err_sb_ub(msg: String) -> InterpError<'static> { - // FIXME: use `err_machine_stop!` macro, once that exists. - InterpError::MachineStop(Box::new(TerminationInfo::ExperimentalUb { + err_machine_stop!(TerminationInfo::ExperimentalUb { msg, url: format!("https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md"), - })) + }) } // # Stacked Borrows Core Begin From 90918111474cb573a4183bb9b8eb04dfd8150275 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 Mar 2020 23:53:54 +0100 Subject: [PATCH 1697/5092] use Wake trait for async-fn driver --- tests/run-pass/async-fn.rs | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 90448aca1779..b0a979123343 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -1,7 +1,9 @@ #![feature(never_type)] +#![feature(wake_trait)] -use std::{future::Future, pin::Pin, task::Poll, ptr}; -use std::task::{Waker, RawWaker, RawWakerVTable, Context}; +use std::{future::Future, pin::Pin, task::Poll}; +use std::task::{Wake, Waker, Context}; +use std::sync::Arc; // See if we can run a basic `async fn` pub async fn foo(x: &u32, y: u32) -> u32 { @@ -47,25 +49,14 @@ async fn partial_init(x: u32) -> u32 { } fn run_fut(mut fut: impl Future, output: u32) { - fn raw_waker_clone(_this: *const ()) -> RawWaker { - panic!("unimplemented"); + struct MyWaker; + impl Wake for MyWaker { + fn wake(self: Arc) { + unimplemented!() + } } - fn raw_waker_wake(_this: *const ()) { - panic!("unimplemented"); - } - fn raw_waker_wake_by_ref(_this: *const ()) { - panic!("unimplemented"); - } - fn raw_waker_drop(_this: *const ()) {} - static RAW_WAKER: RawWakerVTable = RawWakerVTable::new( - raw_waker_clone, - raw_waker_wake, - raw_waker_wake_by_ref, - raw_waker_drop, - ); - - let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &RAW_WAKER)) }; + let waker = Waker::from(Arc::new(MyWaker)); let mut context = Context::from_waker(&waker); assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(output)); } From 5f9167bdaa033f568b2528881b0fe3a2cdac27dc Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Mon, 23 Mar 2020 15:08:57 -0400 Subject: [PATCH 1698/5092] helper functions for env_var emulation in Windows --- src/helpers.rs | 115 +++++++++++++++++++++++++++++++++++++++++++++-- src/shims/env.rs | 20 +++++---- 2 files changed, 123 insertions(+), 12 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index b4706f04d9b8..76c5308cfd35 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,4 +1,4 @@ -use std::ffi::OsStr; +use std::ffi::{OsStr, OsString}; use std::{iter, mem}; use std::convert::TryFrom; @@ -456,6 +456,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + /// Dispatches to appropriate implementations for reading an OsString from Memory, + /// depending on the interpretation target. + /// FIXME: Use `Cow` to avoid copies + fn read_os_str_from_target_str(&self, scalar: Scalar) -> InterpResult<'tcx, OsString> { + let target_os = self.eval_context_ref().tcx.sess.target.target.target_os.as_str(); + match target_os { + "linux" | "macos" => self.read_os_str_from_c_str(scalar).map(|x| x.to_os_string()), + "windows" => self.read_os_str_from_wide_str(scalar), + unsupported => throw_unsup_format!("OsString support for target OS `{}` not yet available", unsupported), + } + } + /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. fn read_os_str_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, &'a OsStr> @@ -471,7 +483,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { let s = std::str::from_utf8(bytes) .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; - Ok(&OsStr::new(s)) + Ok(OsStr::new(s)) } let this = self.eval_context_ref(); @@ -479,6 +491,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx bytes_to_os_str(bytes) } + /// Helper function to read an OsString from a 0x0000-terminated sequence of u16, + /// which is what the Windows APIs usually handle. + fn read_os_str_from_wide_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, OsString> + where + 'tcx: 'a, + 'mir: 'a, + { + #[cfg(windows)] + pub fn u16vec_to_osstring<'tcx, 'a>(u16_vec: Vec) -> InterpResult<'tcx, OsString> { + Ok(std::os::windows::ffi::OsStringExt::from_wide(&u16_vec[..])) + } + #[cfg(not(windows))] + pub fn u16vec_to_osstring<'tcx, 'a>(u16_vec: Vec) -> InterpResult<'tcx, OsString> { + let s = String::from_utf16(&u16_vec[..]) + .map_err(|_| err_unsup_format!("{:?} is not a valid utf-16 string", u16_vec))?; + Ok(s.into()) + } + + let u16_vec = self.eval_context_ref().memory.read_wide_str(scalar)?; + u16vec_to_osstring(u16_vec) + } + + /// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. This function returns `Ok((false, length))` without trying /// to write if `size` is not large enough to fit the contents of `os_string` plus a null @@ -518,6 +553,66 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok((true, string_length)) } + /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what + /// the Windows APIs usually handle. This function returns `Ok((false, length))` without trying + /// to write if `size` is not large enough to fit the contents of `os_string` plus a null + /// terminator. It returns `Ok((true, length))` if the writing process was successful. The + /// string length returned does not include the null terminator. + fn write_os_str_to_wide_str( + &mut self, + os_str: &OsStr, + mplace: MPlaceTy<'tcx, Tag>, + size: u64, + ) -> InterpResult<'tcx, (bool, u64)> { + #[cfg(windows)] + fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec> { + Ok(std::os::windows::ffi::OsStrExt::encode_wide(os_str).collect()) + } + #[cfg(not(windows))] + fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec> { + // On non-Windows platforms the best we can do to transform Vec from/to OS strings is to do the + // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually + // valid. + os_str + .to_str() + .map(|s| s.encode_utf16().collect()) + .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) + } + + let u16_vec = os_str_to_u16vec(os_str)?; + // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required + // 0x0000 terminator to memory would cause an out-of-bounds access. + let string_length = u64::try_from(u16_vec.len()).unwrap(); + if size <= string_length { + return Ok((false, string_length)); + } + + let this = self.eval_context_mut(); + + // Store the UTF-16 string. + let char_size = Size::from_bytes(2); + for (idx, c) in u16_vec.into_iter().chain(iter::once(0x0000)).enumerate() { + let place = this.mplace_field(mplace, idx as u64)?; + this.write_scalar(Scalar::from_uint(c, char_size), place.into())?; + } + Ok((true, string_length)) + } + + /// Dispatches to appropriate implementations for allocating & writing OsString in Memory, + /// depending on the interpretation target. + fn alloc_os_str_as_target_str( + &mut self, + os_str: &OsStr, + memkind: MemoryKind, + ) -> InterpResult<'tcx, Pointer> { + let target_os = self.eval_context_ref().tcx.sess.target.target.target_os.as_str(); + match target_os { + "linux" | "macos" => Ok(self.alloc_os_str_as_c_str(os_str, memkind)), + "windows" => Ok(self.alloc_os_str_as_wide_str(os_str, memkind)), + unsupported => throw_unsup_format!("OsString support for target OS `{}` not yet available", unsupported), + } + } + fn alloc_os_str_as_c_str( &mut self, os_str: &OsStr, @@ -528,7 +623,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let arg_type = this.tcx.mk_array(this.tcx.types.u8, size); let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind); - self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap(); + assert!(self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap().0); + arg_place.ptr.assert_ptr() + } + + fn alloc_os_str_as_wide_str( + &mut self, + os_str: &OsStr, + memkind: MemoryKind, + ) -> Pointer { + let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0x0000` terminator. + let this = self.eval_context_mut(); + + let arg_type = this.tcx.mk_array(this.tcx.types.u16, size); + let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind); + assert!(self.write_os_str_to_wide_str(os_str, arg_place, size).unwrap().0); arg_place.ptr.assert_ptr() } } diff --git a/src/shims/env.rs b/src/shims/env.rs index da634c1aeb23..6b18cd25a1b0 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -13,7 +13,7 @@ use rustc_mir::interpret::Pointer; #[derive(Default)] pub struct EnvVars<'tcx> { /// Stores pointers to the environment variables. These variables must be stored as - /// null-terminated C strings with the `"{name}={value}"` format. + /// null-terminated target strings (c_str or wide_str) with the `"{name}={value}"` format. map: FxHashMap>, /// Place where the `environ` static is stored. Lazily initialized, but then never changes. @@ -29,7 +29,7 @@ impl<'tcx> EnvVars<'tcx> { for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { let var_ptr = - alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx); + alloc_env_var_as_target_str(name.as_ref(), value.as_ref(), ecx)?; ecx.machine.env_vars.map.insert(OsString::from(name), var_ptr); } } @@ -38,21 +38,23 @@ impl<'tcx> EnvVars<'tcx> { } } -fn alloc_env_var_as_c_str<'mir, 'tcx>( +fn alloc_env_var_as_target_str<'mir, 'tcx>( name: &OsStr, value: &OsStr, ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, -) -> Pointer { +) -> InterpResult<'tcx, Pointer> { let mut name_osstring = name.to_os_string(); name_osstring.push("="); name_osstring.push(value); - ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into()) + Ok(ecx.alloc_os_str_as_target_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into())?) } impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn getenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); + let target_os = this.tcx.sess.target.target.target_os.as_str(); + assert!(target_os == "linux" || target_os == "macos", "`{}` is only available for the UNIX target family"); let name_ptr = this.read_scalar(name_op)?.not_undef()?; let name = this.read_os_str_from_c_str(name_ptr)?; @@ -74,17 +76,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_ptr = this.read_scalar(name_op)?.not_undef()?; let value_ptr = this.read_scalar(value_op)?.not_undef()?; - let value = this.read_os_str_from_c_str(value_ptr)?; + let value = this.read_os_str_from_target_str(value_ptr)?; let mut new = None; if !this.is_null(name_ptr)? { - let name = this.read_os_str_from_c_str(name_ptr)?; + let name = this.read_os_str_from_target_str(name_ptr)?; if !name.is_empty() && !name.to_string_lossy().contains('=') { new = Some((name.to_owned(), value.to_owned())); } } if let Some((name, value)) = new { - let var_ptr = alloc_env_var_as_c_str(&name, &value, &mut this); - if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), var_ptr) { + let var_ptr = alloc_env_var_as_target_str(&name, &value, &mut this)?; + if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { this.memory .deallocate(var, None, MiriMemoryKind::Machine.into())?; } From 80088e131b0c3b15071602254b15a01cb2f82612 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 24 Mar 2020 08:24:36 +0100 Subject: [PATCH 1699/5092] rustup for trait MachineStopType --- rust-version | 2 +- src/diagnostics.rs | 57 +++++++++++++++++++++++++++++++--------------- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/rust-version b/rust-version index 1270131b7267..7658d0bff9d8 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1edd389cc4c7b5be7a3dd4fe4b986f6017018e54 +342c5f33d097b2dc07a2dbc0ca45a37379d2ff60 diff --git a/src/diagnostics.rs b/src/diagnostics.rs index a2cdffdf80b3..2e4023e0b5bf 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -1,4 +1,5 @@ use std::cell::RefCell; +use std::fmt; use rustc_span::DUMMY_SP; @@ -12,6 +13,26 @@ pub enum TerminationInfo { ExperimentalUb { msg: String, url: String } } +impl fmt::Debug for TerminationInfo { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use TerminationInfo::*; + match self { + Exit(code) => + write!(f, "the evaluated program completed with exit code {}", code), + Abort(None) => + write!(f, "the evaluated program aborted execution"), + Abort(Some(msg)) => + write!(f, "the evaluated program aborted execution: {}", msg), + UnsupportedInIsolation(msg) => + write!(f, "{}", msg), + ExperimentalUb { msg, .. } => + write!(f, "{}", msg), + } + } +} + +impl MachineStopType for TerminationInfo {} + /// Miri specific diagnostics pub enum NonHaltingDiagnostic { PoppedTrackedPointerTag(Item), @@ -25,21 +46,18 @@ pub fn report_error<'tcx, 'mir>( ) -> Option { use InterpError::*; - e.print_backtrace(); - let (title, msg, helps) = match e.kind { - MachineStop(info) => { + let (title, helps) = match e.kind { + MachineStop(ref info) => { let info = info.downcast_ref::().expect("invalid MachineStop payload"); use TerminationInfo::*; - let (title, msg) = match info { + let title = match info { Exit(code) => return Some(*code), - Abort(None) => - ("abnormal termination", format!("the evaluated program aborted execution")), - Abort(Some(msg)) => - ("abnormal termination", format!("the evaluated program aborted execution: {}", msg)), - UnsupportedInIsolation(msg) => - ("unsupported operation", format!("{}", msg)), - ExperimentalUb { msg, .. } => - ("Undefined Behavior", format!("{}", msg)), + Abort(_) => + "abnormal termination", + UnsupportedInIsolation(_) => + "unsupported operation", + ExperimentalUb { .. } => + "Undefined Behavior", }; let helps = match info { UnsupportedInIsolation(_) => @@ -51,16 +69,16 @@ pub fn report_error<'tcx, 'mir>( ], _ => vec![], }; - (title, msg, helps) + (title, helps) } _ => { - let (title, msg) = match e.kind { + let title = match e.kind { Unsupported(_) => - ("unsupported operation", e.to_string()), + "unsupported operation", UndefinedBehavior(_) => - ("Undefined Behavior", e.to_string()), + "Undefined Behavior", ResourceExhaustion(_) => - ("resource exhaustion", e.to_string()), + "resource exhaustion", _ => bug!("This error should be impossible in Miri: {}", e), }; @@ -76,9 +94,12 @@ pub fn report_error<'tcx, 'mir>( ], _ => vec![], }; - (title, msg, helps) + (title, helps) } }; + + e.print_backtrace(); + let msg = e.to_string(); report_msg(ecx, &format!("{}: {}", title, msg), msg, &helps, true) } From 87f549571543160626ba25b3082e16ad1b3cd6b2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 24 Mar 2020 08:25:37 +0100 Subject: [PATCH 1700/5092] 32bit macOS is no more --- src/shims/fs.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index d799d8ed9a8a..16d83188dbc2 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -114,13 +114,6 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' let blksize_t_layout = this.libc_ty_layout("blksize_t")?; let uint32_t_layout = this.libc_ty_layout("uint32_t")?; - // We need to add 32 bits of padding after `st_rdev` if we are on a 64-bit target. - let pad_layout = if this.tcx.sess.target.ptr_width == 64 { - uint32_t_layout - } else { - this.layout_of(this.tcx.mk_unit())? - }; - let imms = [ immty_from_uint_checked(0u128, dev_t_layout)?, // st_dev immty_from_uint_checked(mode, mode_t_layout)?, // st_mode @@ -129,7 +122,7 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' immty_from_uint_checked(0u128, uid_t_layout)?, // st_uid immty_from_uint_checked(0u128, gid_t_layout)?, // st_gid immty_from_uint_checked(0u128, dev_t_layout)?, // st_rdev - immty_from_uint_checked(0u128, pad_layout)?, // padding for 64-bit targets + immty_from_uint_checked(0u128, uint32_t_layout)?, // padding immty_from_uint_checked(access_sec, time_t_layout)?, // st_atime immty_from_uint_checked(access_nsec, long_layout)?, // st_atime_nsec immty_from_uint_checked(modified_sec, time_t_layout)?, // st_mtime From da721233d705b6f011747d75e7ada23e948b820e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Mar 2020 20:08:00 +0100 Subject: [PATCH 1701/5092] cross-test on a Windows host --- .appveyor.yml | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 4281fe0180f0..919802d12abe 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -2,7 +2,6 @@ environment: global: PROJECT_NAME: miri matrix: - - TARGET: x86_64-pc-windows-msvc - TARGET: i686-pc-windows-msvc # branches to build @@ -43,18 +42,33 @@ build_script: # Build and install miri - cargo build --release --all-features --all-targets --locked - cargo install --all-features --force --path . --locked --offline - # Get ourselves a MIR-full libstd, and use it henceforth - - cargo miri setup - - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\rust-lang\miri\cache\HOST test_script: - set RUST_TEST_NOCAPTURE=1 - set RUST_BACKTRACE=1 - # Test miri + # Test host miri: 32bit Windows + - cargo miri setup + - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\rust-lang\miri\cache\HOST - cargo test --release --all-features --locked - # Test cargo integration - cd test-cargo-miri - '"C:\msys64\mingw64\bin\python3.exe" run-test.py' + - cd .. + # Test foreign miri: 64bit Linux + - cargo miri setup --target x86_64-unknown-linux-gnu + - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\rust-lang\miri\cache + - set MIRI_TEST_TARGET=x86_64-unknown-linux-gnu + - cargo test --release --all-features --locked + - cd test-cargo-miri + - '"C:\msys64\mingw64\bin\python3.exe" run-test.py' + - cd .. + # Test foreign miri: 64bit macOS + - cargo miri setup --target x86_64-apple-darwin + - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\rust-lang\miri\cache + - set MIRI_TEST_TARGET=x86_64-apple-darwin + - cargo test --release --all-features --locked + - cd test-cargo-miri + - '"C:\msys64\mingw64\bin\python3.exe" run-test.py' + - cd .. after_test: # Don't cache "master" toolchain, it's a waste From 3517ce66abe20263316830f13a164aff78abc5a2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Mar 2020 20:32:42 +0100 Subject: [PATCH 1702/5092] need to unset MIRI_SYSROOT before calling 'cargo miri setup' --- .appveyor.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.appveyor.yml b/.appveyor.yml index 919802d12abe..e5c2f4fb7294 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -53,6 +53,7 @@ test_script: - cd test-cargo-miri - '"C:\msys64\mingw64\bin\python3.exe" run-test.py' - cd .. + - ps: $env:MIRI_SYSROOT = "" # Test foreign miri: 64bit Linux - cargo miri setup --target x86_64-unknown-linux-gnu - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\rust-lang\miri\cache @@ -61,6 +62,7 @@ test_script: - cd test-cargo-miri - '"C:\msys64\mingw64\bin\python3.exe" run-test.py' - cd .. + - ps: $env:MIRI_SYSROOT = "" # Test foreign miri: 64bit macOS - cargo miri setup --target x86_64-apple-darwin - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\rust-lang\miri\cache @@ -69,6 +71,7 @@ test_script: - cd test-cargo-miri - '"C:\msys64\mingw64\bin\python3.exe" run-test.py' - cd .. + - ps: $env:MIRI_SYSROOT = "" after_test: # Don't cache "master" toolchain, it's a waste From 4ac91384ff124d5b6258a648df5176909ff1b780 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 Mar 2020 19:24:16 +0100 Subject: [PATCH 1703/5092] route all path reading/writing through central read/write methods --- src/helpers.rs | 24 +++++++++++++++++++++++- src/shims/env.rs | 4 ++-- src/shims/fs.rs | 42 +++++++++++++++++++++--------------------- 3 files changed, 46 insertions(+), 24 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 76c5308cfd35..d8731b537719 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,6 +1,8 @@ use std::ffi::{OsStr, OsString}; +use std::path::Path; use std::{iter, mem}; use std::convert::TryFrom; +use std::borrow::Cow; use rustc::mir; use rustc::ty::{ @@ -491,6 +493,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx bytes_to_os_str(bytes) } + /// Read a null-terminated sequence of bytes, and perform path separator conversion if needed. + fn read_path_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, Cow<'a, Path>> + where + 'tcx: 'a, + 'mir: 'a, + { + let os_str = self.read_os_str_from_c_str(scalar)?; + Ok(Cow::Borrowed(Path::new(os_str))) + } + /// Helper function to read an OsString from a 0x0000-terminated sequence of u16, /// which is what the Windows APIs usually handle. fn read_os_str_from_wide_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, OsString> @@ -513,7 +525,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx u16vec_to_osstring(u16_vec) } - /// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. This function returns `Ok((false, length))` without trying /// to write if `size` is not large enough to fit the contents of `os_string` plus a null @@ -553,6 +564,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok((true, string_length)) } + /// Write a Path to the machine memory, adjusting path separators if needed. + fn write_path_to_c_str( + &mut self, + path: &Path, + scalar: Scalar, + size: u64, + ) -> InterpResult<'tcx, (bool, u64)> { + let os_str = path.as_os_str(); + self.write_os_str_to_c_str(os_str, scalar, size) + } + /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what /// the Windows APIs usually handle. This function returns `Ok((false, length))` without trying /// to write if `size` is not large enough to fit the contents of `os_string` plus a null diff --git a/src/shims/env.rs b/src/shims/env.rs index 6b18cd25a1b0..192fc0d47abe 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -134,7 +134,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If we cannot get the current directory, we return null match env::current_dir() { Ok(cwd) => { - if this.write_os_str_to_c_str(&OsString::from(cwd), buf, size)?.0 { + if this.write_path_to_c_str(&cwd, buf, size)?.0 { return Ok(buf); } let erange = this.eval_libc("ERANGE")?; @@ -150,7 +150,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("chdir")?; - let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_path_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; match env::set_current_dir(path) { Ok(()) => Ok(0), diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 16d83188dbc2..9778775fca64 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use std::convert::{TryFrom, TryInto}; use std::fs::{read_dir, remove_dir, remove_file, rename, DirBuilder, File, FileType, OpenOptions, ReadDir}; use std::io::{Read, Seek, SeekFrom, Write}; -use std::path::PathBuf; +use std::path::Path; use std::time::SystemTime; use rustc_data_structures::fx::FxHashMap; @@ -79,9 +79,9 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' let this = self.eval_context_mut(); let path_scalar = this.read_scalar(path_op)?.not_undef()?; - let path: PathBuf = this.read_os_str_from_c_str(path_scalar)?.into(); + let path = this.read_path_from_c_str(path_scalar)?.into_owned(); - let metadata = match FileMetadata::from_path(this, path, follow_symlink)? { + let metadata = match FileMetadata::from_path(this, &path, follow_symlink)? { Some(metadata) => metadata, None => return Ok(-1), }; @@ -303,7 +303,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("unsupported flags {:#x}", flag & !mirror); } - let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_path_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; let fd = options.open(&path).map(|file| { let fh = &mut this.machine.file_handler; @@ -524,10 +524,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("unlink")?; - let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_path_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; let result = remove_file(path).map(|_| 0); - this.try_unwrap_io_result(result) } @@ -537,12 +536,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx linkpath_op: OpTy<'tcx, Tag> ) -> InterpResult<'tcx, i32> { #[cfg(target_family = "unix")] - fn create_link(src: PathBuf, dst: PathBuf) -> std::io::Result<()> { + fn create_link(src: &Path, dst: &Path) -> std::io::Result<()> { std::os::unix::fs::symlink(src, dst) } #[cfg(target_family = "windows")] - fn create_link(src: PathBuf, dst: PathBuf) -> std::io::Result<()> { + fn create_link(src: &Path, dst: &Path) -> std::io::Result<()> { use std::os::windows::fs; if src.is_dir() { fs::symlink_dir(src, dst) @@ -555,10 +554,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("symlink")?; - let target = this.read_os_str_from_c_str(this.read_scalar(target_op)?.not_undef()?)?.into(); - let linkpath = this.read_os_str_from_c_str(this.read_scalar(linkpath_op)?.not_undef()?)?.into(); + let target = this.read_path_from_c_str(this.read_scalar(target_op)?.not_undef()?)?; + let linkpath = this.read_path_from_c_str(this.read_scalar(linkpath_op)?.not_undef()?)?; - this.try_unwrap_io_result(create_link(target, linkpath).map(|_| 0)) + let result = create_link(&target, &linkpath).map(|_| 0); + this.try_unwrap_io_result(result) } fn macos_stat( @@ -644,7 +644,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.ref_to_mplace(statxbuf_imm)? }; - let path: PathBuf = this.read_os_str_from_c_str(pathname_scalar)?.into(); + let path = this.read_path_from_c_str(pathname_scalar)?.into_owned(); // `flags` should be a `c_int` but the `syscall` function provides an `isize`. let flags: i32 = this.read_scalar(flags_op)?.to_machine_isize(&*this.tcx)?.try_into().map_err(|e| { @@ -691,7 +691,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let metadata = if path.as_os_str().is_empty() && empty_path_flag { FileMetadata::from_fd(this, dirfd)? } else { - FileMetadata::from_path(this, path, follow_symlink)? + FileMetadata::from_path(this, &path, follow_symlink)? }; let metadata = match metadata { Some(metadata) => metadata, @@ -785,8 +785,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } - let oldpath = this.read_os_str_from_c_str(oldpath_scalar)?; - let newpath = this.read_os_str_from_c_str(newpath_scalar)?; + let oldpath = this.read_path_from_c_str(oldpath_scalar)?; + let newpath = this.read_path_from_c_str(newpath_scalar)?; let result = rename(oldpath, newpath).map(|_| 0); @@ -808,7 +808,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.read_scalar(mode_op)?.to_u32()? }; - let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_path_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; let mut builder = DirBuilder::new(); @@ -833,7 +833,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("rmdir")?; - let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_path_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; let result = remove_dir(path).map(|_| 0i32); @@ -845,7 +845,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("opendir")?; - let name = this.read_os_str_from_c_str(this.read_scalar(name_op)?.not_undef()?)?; + let name = this.read_path_from_c_str(this.read_scalar(name_op)?.not_undef()?)?; let result = read_dir(name); @@ -899,7 +899,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let entry_place = this.deref_operand(entry_op)?; let name_place = this.mplace_field(entry_place, 4)?; - let file_name = dir_entry.file_name(); + let file_name = dir_entry.file_name(); // not a Path as there are no separators! let (name_fits, _) = this.write_os_str_to_c_str( &file_name, name_place.ptr, @@ -987,7 +987,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let entry_place = this.deref_operand(entry_op)?; let name_place = this.mplace_field(entry_place, 5)?; - let file_name = dir_entry.file_name(); + let file_name = dir_entry.file_name(); // not a Path as there are no separators! let (name_fits, file_name_len) = this.write_os_str_to_c_str( &file_name, name_place.ptr, @@ -1082,7 +1082,7 @@ struct FileMetadata { impl FileMetadata { fn from_path<'tcx, 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - path: PathBuf, + path: &Path, follow_symlink: bool ) -> InterpResult<'tcx, Option> { let metadata = if follow_symlink { From c4e29c8646e3836cec79bd17a73ac13a2b90e6e4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 Mar 2020 19:57:40 +0100 Subject: [PATCH 1704/5092] convert dir separators on path load/store --- src/helpers.rs | 78 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 69 insertions(+), 9 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index d8731b537719..abfe3253ce7b 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,9 +1,14 @@ use std::ffi::{OsStr, OsString}; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::{iter, mem}; use std::convert::TryFrom; use std::borrow::Cow; +#[cfg(unix)] +use std::os::unix::ffi::{OsStrExt, OsStringExt}; +#[cfg(windows)] +use std::os::windows::ffi::{OsStrExt, OsStringExt}; + use rustc::mir; use rustc::ty::{ self, @@ -479,7 +484,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx { #[cfg(unix)] fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { - Ok(std::os::unix::ffi::OsStrExt::from_bytes(bytes)) + Ok(OsStr::from_bytes(bytes)) } #[cfg(not(unix))] fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { @@ -499,8 +504,34 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx 'tcx: 'a, 'mir: 'a, { - let os_str = self.read_os_str_from_c_str(scalar)?; - Ok(Cow::Borrowed(Path::new(os_str))) + let this = self.eval_context_ref(); + let os_str = this.read_os_str_from_c_str(scalar)?; + + #[cfg(windows)] + return Ok(if this.tcx.sess.target.target.target_os == "windows" { + // Windows-on-Windows, all fine. + Cow::Borrowed(Path::new(os_str)) + } else { + // Unix target, Windows host. Need to convert target '/' to host '\'. + let converted = os_str + .encode_wide() + .map(|wchar| if wchar == '/' as u16 { '\\' as u16 } else { wchar }) + .collect::>(); + Cow::Owned(PathBuf::from(OsString::from_wide(&converted))) + }); + #[cfg(unix)] + return Ok(if this.tcx.sess.target.target.target_os == "windows" { + // Windows target, Unix host. Need to convert target '\' to host '/'. + let converted = os_str + .as_bytes() + .iter() + .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) + .collect::>(); + Cow::Owned(PathBuf::from(OsString::from_vec(converted))) + } else { + // Unix-on-Unix, all is fine. + Cow::Borrowed(Path::new(os_str)) + }); } /// Helper function to read an OsString from a 0x0000-terminated sequence of u16, @@ -512,7 +543,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx { #[cfg(windows)] pub fn u16vec_to_osstring<'tcx, 'a>(u16_vec: Vec) -> InterpResult<'tcx, OsString> { - Ok(std::os::windows::ffi::OsStringExt::from_wide(&u16_vec[..])) + Ok(OsString::from_wide(&u16_vec[..])) } #[cfg(not(windows))] pub fn u16vec_to_osstring<'tcx, 'a>(u16_vec: Vec) -> InterpResult<'tcx, OsString> { @@ -538,7 +569,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, (bool, u64)> { #[cfg(unix)] fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - Ok(std::os::unix::ffi::OsStrExt::as_bytes(os_str)) + Ok(os_str.as_bytes()) } #[cfg(not(unix))] fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { @@ -571,8 +602,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx scalar: Scalar, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { - let os_str = path.as_os_str(); - self.write_os_str_to_c_str(os_str, scalar, size) + let this = self.eval_context_mut(); + + #[cfg(windows)] + let os_str = if this.tcx.sess.target.target.target_os == "windows" { + // Windows-on-Windows, all fine. + Cow::Borrowed(path.as_os_str()) + } else { + // Unix target, Windows host. Need to convert host '\\' to target '/'. + let converted = path + .as_os_str() + .encode_wide() + .map(|wchar| if wchar == '\\' as u16 { '/' as u16 } else { wchar }) + .collect::>(); + Cow::Owned(OsString::from_wide(&converted)) + }; + #[cfg(unix)] + let os_str = if this.tcx.sess.target.target.target_os == "windows" { + // Windows target, Unix host. Need to convert host '/' to target '\'. + let converted = path + .as_os_str() + .as_bytes() + .iter() + .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) + .collect::>(); + Cow::Owned(OsString::from_vec(converted)) + } else { + // Unix-on-Unix, all is fine. + Cow::Borrowed(path.as_os_str()) + }; + + this.write_os_str_to_c_str(&os_str, scalar, size) } /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what @@ -588,7 +648,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, (bool, u64)> { #[cfg(windows)] fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec> { - Ok(std::os::windows::ffi::OsStrExt::encode_wide(os_str).collect()) + Ok(os_str.encode_wide().collect()) } #[cfg(not(windows))] fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec> { From 3ba588db496c99eb6a9280400271af4cb1958a91 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 Mar 2020 23:48:12 +0100 Subject: [PATCH 1705/5092] make fs.rs at least build under Windows --- tests/run-pass/fs.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 0f3512b36605..b6d460f7a981 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -142,7 +142,10 @@ fn test_symlink() { let symlink_path = prepare("miri_test_fs_symlink.txt"); // Creating a symbolic link should succeed. + #[cfg(unix)] std::os::unix::fs::symlink(&path, &symlink_path).unwrap(); + #[cfg(windows)] + std::os::windows::fs::symlink_file(&path, &symlink_path).unwrap(); // Test that the symbolic link has the same contents as the file. let mut symlink_file = File::open(&symlink_path).unwrap(); let mut contents = Vec::new(); From 8817397828f2e4aedf4251bdc02c6299d1d1654c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 Mar 2020 23:42:03 +0100 Subject: [PATCH 1706/5092] test harness informs tests about suitable temp dir --- tests/compiletest.rs | 2 ++ tests/run-pass/fs.rs | 10 ++++++---- tests/run-pass/libc.rs | 11 ++++++++--- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index f43ff8ca349d..d082a2cc484b 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -110,6 +110,8 @@ fn get_target() -> String { fn test_runner(_tests: &[&()]) { // Add a test env var to do environment communication tests. std::env::set_var("MIRI_ENV_VAR_TEST", "0"); + // Let the tests know where to store temp files (they might run for a different target, which can make this hard to find). + std::env::set_var("MIRI_TEMP", std::env::temp_dir()); let target = get_target(); miri_pass("tests/run-pass", &target); diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index b6d460f7a981..104ba46c3e45 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -16,10 +16,13 @@ fn main() { test_directory(); } +fn tmp() -> PathBuf { + std::env::var("MIRI_TEMP").map(PathBuf::from).unwrap_or_else(|_| std::env::temp_dir()) +} + /// Prepare: compute filename and make sure the file does not exist. fn prepare(filename: &str) -> PathBuf { - let tmp = std::env::temp_dir(); - let path = tmp.join(filename); + let path = tmp().join(filename); // Clean the paths for robustness. remove_file(&path).ok(); path @@ -27,8 +30,7 @@ fn prepare(filename: &str) -> PathBuf { /// Prepare directory: compute directory name and make sure it does not exist. fn prepare_dir(dirname: &str) -> PathBuf { - let tmp = std::env::temp_dir(); - let path = tmp.join(&dirname); + let path = tmp().join(&dirname); // Clean the directory for robustness. remove_dir_all(&path).ok(); path diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index 5b7b37db327b..064c00e81bb8 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -2,19 +2,24 @@ // compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] +#![allow(unused)] // necessary on macos due to conditional compilation + +use std::path::PathBuf; -#[allow(unused)] // necessary on macos due to conditional compilation extern crate libc; +fn tmp() -> PathBuf { + std::env::var("MIRI_TEMP").map(PathBuf::from).unwrap_or_else(|_| std::env::temp_dir()) +} + #[cfg(not(target_os = "macos"))] fn test_posix_fadvise() { use std::convert::TryInto; - use std::env::temp_dir; use std::fs::{File, remove_file}; use std::io::Write; use std::os::unix::io::AsRawFd; - let path = temp_dir().join("miri_test_libc.txt"); + let path = tmp().join("miri_test_libc.txt"); // Cleanup before test remove_file(&path).ok(); From e9e04e56fc6767f63458de1c137b5231cfd77b33 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 24 Mar 2020 08:38:05 +0100 Subject: [PATCH 1707/5092] move path methods together, to the bottom of the string helpers --- src/helpers.rs | 156 +++++++++++++++++++++++++------------------------ 1 file changed, 79 insertions(+), 77 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index abfe3253ce7b..7ca2b238218a 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -498,42 +498,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx bytes_to_os_str(bytes) } - /// Read a null-terminated sequence of bytes, and perform path separator conversion if needed. - fn read_path_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, Cow<'a, Path>> - where - 'tcx: 'a, - 'mir: 'a, - { - let this = self.eval_context_ref(); - let os_str = this.read_os_str_from_c_str(scalar)?; - - #[cfg(windows)] - return Ok(if this.tcx.sess.target.target.target_os == "windows" { - // Windows-on-Windows, all fine. - Cow::Borrowed(Path::new(os_str)) - } else { - // Unix target, Windows host. Need to convert target '/' to host '\'. - let converted = os_str - .encode_wide() - .map(|wchar| if wchar == '/' as u16 { '\\' as u16 } else { wchar }) - .collect::>(); - Cow::Owned(PathBuf::from(OsString::from_wide(&converted))) - }); - #[cfg(unix)] - return Ok(if this.tcx.sess.target.target.target_os == "windows" { - // Windows target, Unix host. Need to convert target '\' to host '/'. - let converted = os_str - .as_bytes() - .iter() - .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) - .collect::>(); - Cow::Owned(PathBuf::from(OsString::from_vec(converted))) - } else { - // Unix-on-Unix, all is fine. - Cow::Borrowed(Path::new(os_str)) - }); - } - /// Helper function to read an OsString from a 0x0000-terminated sequence of u16, /// which is what the Windows APIs usually handle. fn read_os_str_from_wide_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, OsString> @@ -595,46 +559,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok((true, string_length)) } - /// Write a Path to the machine memory, adjusting path separators if needed. - fn write_path_to_c_str( - &mut self, - path: &Path, - scalar: Scalar, - size: u64, - ) -> InterpResult<'tcx, (bool, u64)> { - let this = self.eval_context_mut(); - - #[cfg(windows)] - let os_str = if this.tcx.sess.target.target.target_os == "windows" { - // Windows-on-Windows, all fine. - Cow::Borrowed(path.as_os_str()) - } else { - // Unix target, Windows host. Need to convert host '\\' to target '/'. - let converted = path - .as_os_str() - .encode_wide() - .map(|wchar| if wchar == '\\' as u16 { '/' as u16 } else { wchar }) - .collect::>(); - Cow::Owned(OsString::from_wide(&converted)) - }; - #[cfg(unix)] - let os_str = if this.tcx.sess.target.target.target_os == "windows" { - // Windows target, Unix host. Need to convert host '/' to target '\'. - let converted = path - .as_os_str() - .as_bytes() - .iter() - .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) - .collect::>(); - Cow::Owned(OsString::from_vec(converted)) - } else { - // Unix-on-Unix, all is fine. - Cow::Borrowed(path.as_os_str()) - }; - - this.write_os_str_to_c_str(&os_str, scalar, size) - } - /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what /// the Windows APIs usually handle. This function returns `Ok((false, length))` without trying /// to write if `size` is not large enough to fit the contents of `os_string` plus a null @@ -674,7 +598,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Store the UTF-16 string. let char_size = Size::from_bytes(2); for (idx, c) in u16_vec.into_iter().chain(iter::once(0x0000)).enumerate() { - let place = this.mplace_field(mplace, idx as u64)?; + let place = this.mplace_field(mplace, u64::try_from(idx).unwrap())?; this.write_scalar(Scalar::from_uint(c, char_size), place.into())?; } Ok((true, string_length)) @@ -695,6 +619,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes. fn alloc_os_str_as_c_str( &mut self, os_str: &OsStr, @@ -709,6 +634,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx arg_place.ptr.assert_ptr() } + /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of `u16`. fn alloc_os_str_as_wide_str( &mut self, os_str: &OsStr, @@ -722,6 +648,82 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert!(self.write_os_str_to_wide_str(os_str, arg_place, size).unwrap().0); arg_place.ptr.assert_ptr() } + + /// Read a null-terminated sequence of bytes, and perform path separator conversion if needed. + fn read_path_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, Cow<'a, Path>> + where + 'tcx: 'a, + 'mir: 'a, + { + let this = self.eval_context_ref(); + let os_str = this.read_os_str_from_c_str(scalar)?; + + #[cfg(windows)] + return Ok(if this.tcx.sess.target.target.target_os == "windows" { + // Windows-on-Windows, all fine. + Cow::Borrowed(Path::new(os_str)) + } else { + // Unix target, Windows host. Need to convert target '/' to host '\'. + let converted = os_str + .encode_wide() + .map(|wchar| if wchar == '/' as u16 { '\\' as u16 } else { wchar }) + .collect::>(); + Cow::Owned(PathBuf::from(OsString::from_wide(&converted))) + }); + #[cfg(unix)] + return Ok(if this.tcx.sess.target.target.target_os == "windows" { + // Windows target, Unix host. Need to convert target '\' to host '/'. + let converted = os_str + .as_bytes() + .iter() + .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) + .collect::>(); + Cow::Owned(PathBuf::from(OsString::from_vec(converted))) + } else { + // Unix-on-Unix, all is fine. + Cow::Borrowed(Path::new(os_str)) + }); + } + + /// Write a Path to the machine memory, adjusting path separators if needed. + fn write_path_to_c_str( + &mut self, + path: &Path, + scalar: Scalar, + size: u64, + ) -> InterpResult<'tcx, (bool, u64)> { + let this = self.eval_context_mut(); + + #[cfg(windows)] + let os_str = if this.tcx.sess.target.target.target_os == "windows" { + // Windows-on-Windows, all fine. + Cow::Borrowed(path.as_os_str()) + } else { + // Unix target, Windows host. Need to convert host '\\' to target '/'. + let converted = path + .as_os_str() + .encode_wide() + .map(|wchar| if wchar == '\\' as u16 { '/' as u16 } else { wchar }) + .collect::>(); + Cow::Owned(OsString::from_wide(&converted)) + }; + #[cfg(unix)] + let os_str = if this.tcx.sess.target.target.target_os == "windows" { + // Windows target, Unix host. Need to convert host '/' to target '\'. + let converted = path + .as_os_str() + .as_bytes() + .iter() + .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) + .collect::>(); + Cow::Owned(OsString::from_vec(converted)) + } else { + // Unix-on-Unix, all is fine. + Cow::Borrowed(path.as_os_str()) + }; + + this.write_os_str_to_c_str(&os_str, scalar, size) + } } pub fn immty_from_int_checked<'tcx>( From 9b0e9dec49096a409d5f5e333dbf4f2a766b3c70 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 25 Mar 2020 09:05:24 +0100 Subject: [PATCH 1708/5092] rustup, adjust for renames --- rust-version | 2 +- src/machine.rs | 22 +++++++++++----------- src/stacked_borrows.rs | 10 +++++----- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/rust-version b/rust-version index 7658d0bff9d8..3a7d316af8e9 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -342c5f33d097b2dc07a2dbc0ca45a37379d2ff60 +02046a5d402c789c006d0da7662f800fe3c45faf diff --git a/src/machine.rs b/src/machine.rs index 693c80f7deae..84ac8b81a061 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -50,8 +50,8 @@ pub enum MiriMemoryKind { WinHeap, /// Memory for env vars and args, errno, extern statics and other parts of the machine-managed environment. Machine, - /// Rust statics. - Static, + /// Globals copied from `tcx`. + Global, } impl Into> for MiriMemoryKind { @@ -212,7 +212,7 @@ impl<'mir, 'tcx> MiriEvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> /// Machine hook implementations. impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { - type MemoryKinds = MiriMemoryKind; + type MemoryKind = MiriMemoryKind; type FrameExtra = FrameData<'tcx>; type MemoryExtra = MemoryExtra; @@ -223,7 +223,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryMap = MonoHashMap, Allocation)>; - const STATIC_KIND: Option = Some(MiriMemoryKind::Static); + const GLOBAL_KIND: Option = Some(MiriMemoryKind::Global); const CHECK_ALIGN: bool = true; @@ -348,7 +348,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { memory_extra: &MemoryExtra, id: AllocId, alloc: Cow<'b, Allocation>, - kind: Option>, + kind: Option>, ) -> (Cow<'b, Allocation>, Self::PointerTag) { if Some(id) == memory_extra.tracked_alloc_id { register_diagnostic(NonHaltingDiagnostic::CreatedAlloc(id)); @@ -369,9 +369,9 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { let alloc: Allocation = alloc.with_tags_and_extra( |alloc| { if let Some(stacked_borrows) = stacked_borrows.as_mut() { - // Only statics may already contain pointers at this point - assert_eq!(kind, MiriMemoryKind::Static.into()); - stacked_borrows.static_base_ptr(alloc) + // Only globals may already contain pointers at this point + assert_eq!(kind, MiriMemoryKind::Global.into()); + stacked_borrows.global_base_ptr(alloc) } else { Tag::Untagged } @@ -382,9 +382,9 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } #[inline(always)] - fn tag_static_base_pointer(memory_extra: &MemoryExtra, id: AllocId) -> Self::PointerTag { + fn tag_global_base_pointer(memory_extra: &MemoryExtra, id: AllocId) -> Self::PointerTag { if let Some(stacked_borrows) = memory_extra.stacked_borrows.as_ref() { - stacked_borrows.borrow_mut().static_base_ptr(id) + stacked_borrows.borrow_mut().global_base_ptr(id) } else { Tag::Untagged } @@ -486,7 +486,7 @@ impl MayLeak for MiriMemoryKind { use self::MiriMemoryKind::*; match self { Rust | C | WinHeap => false, - Machine | Static => true, + Machine | Global => true, } } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 37f2acf4c3bc..11b6cdca579a 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -182,7 +182,7 @@ impl GlobalState { self.active_calls.contains(&id) } - pub fn static_base_ptr(&mut self, id: AllocId) -> Tag { + pub fn global_base_ptr(&mut self, id: AllocId) -> Tag { self.base_ptr_ids.get(&id).copied().unwrap_or_else(|| { let tag = Tag::Tagged(self.new_ptr()); trace!("New allocation {:?} has base tag {:?}", id, tag); @@ -457,12 +457,12 @@ impl Stacks { // everything else off the stack, invalidating all previous pointers, // and in particular, *all* raw pointers. MemoryKind::Stack => (Tag::Tagged(extra.borrow_mut().new_ptr()), Permission::Unique), - // Static memory can be referenced by "global" pointers from `tcx`. - // Thus we call `static_base_ptr` such that the global pointers get the same tag + // Global memory can be referenced by global pointers from `tcx`. + // Thus we call `global_base_ptr` such that the global pointers get the same tag // as what we use here. // The base pointer is not unique, so the base permission is `SharedReadWrite`. - MemoryKind::Machine(MiriMemoryKind::Static) | MemoryKind::Machine(MiriMemoryKind::Machine) => - (extra.borrow_mut().static_base_ptr(id), Permission::SharedReadWrite), + MemoryKind::Machine(MiriMemoryKind::Global) | MemoryKind::Machine(MiriMemoryKind::Machine) => + (extra.borrow_mut().global_base_ptr(id), Permission::SharedReadWrite), // Everything else we handle entirely untagged for now. // FIXME: experiment with more precise tracking. _ => (Tag::Untagged, Permission::SharedReadWrite), From 47b91e619adffd19c60a5c20709f216c32e34c54 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 25 Mar 2020 09:12:23 +0100 Subject: [PATCH 1709/5092] test unreachable intrinsic --- src/shims/intrinsics.rs | 1 + tests/compile-fail/unreachable.rs | 4 ++++ 2 files changed, 5 insertions(+) create mode 100644 tests/compile-fail/unreachable.rs diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 9a6bd58ba42e..91371e2c9df9 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -36,6 +36,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (dest, ret) = match ret { None => match intrinsic_name { "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), + "unreachable" => throw_ub!(Unreachable), _ => throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name), }, Some(p) => p, diff --git a/tests/compile-fail/unreachable.rs b/tests/compile-fail/unreachable.rs new file mode 100644 index 000000000000..245ef29cad35 --- /dev/null +++ b/tests/compile-fail/unreachable.rs @@ -0,0 +1,4 @@ +// error-pattern: entering unreachable code +fn main() { + unsafe { std::hint::unreachable_unchecked() } +} From 962e2105df2fd8d9d829bf8f7e4a7ab4b7fd1168 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 25 Mar 2020 09:15:52 +0100 Subject: [PATCH 1710/5092] remove an unnecessary as_str --- src/machine.rs | 3 +-- src/shims/fs.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 84ac8b81a061..73e7ce665b85 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -106,8 +106,7 @@ impl MemoryExtra { pub fn init_extern_statics<'tcx, 'mir>( this: &mut MiriEvalContext<'mir, 'tcx>, ) -> InterpResult<'tcx> { - let target_os = this.tcx.sess.target.target.target_os.as_str(); - match target_os { + match this.tcx.sess.target.target.target_os.as_str() { "linux" => { // "__cxa_thread_atexit_impl" // This should be all-zero, pointer-sized. diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 9778775fca64..b779bf165d2b 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -802,7 +802,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("mkdir")?; - let _mode = if this.tcx.sess.target.target.target_os.as_str() == "macos" { + let _mode = if this.tcx.sess.target.target.target_os == "macos" { u32::from(this.read_scalar(mode_op)?.not_undef()?.to_u16()?) } else { this.read_scalar(mode_op)?.to_u32()? From e19552ba414eee7cb5236bf2a65a8da8a802e8ee Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 25 Mar 2020 11:44:11 +0100 Subject: [PATCH 1711/5092] cross-running windows-gnu should now also work --- travis.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/travis.sh b/travis.sh index 8b2453584b09..590b94b7f5db 100755 --- a/travis.sh +++ b/travis.sh @@ -44,4 +44,6 @@ if [ "$TRAVIS_OS_NAME" == linux ]; then elif [ "$TRAVIS_OS_NAME" == osx ]; then # cross-test 64bit Windows from macOS MIRI_TEST_TARGET=x86_64-pc-windows-msvc run_tests + # cross-test 32bit GNU Windows from macOS + MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests fi From 8ffbca797f8be62ac601cc1162e9605185597a00 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 25 Mar 2020 12:11:05 +0100 Subject: [PATCH 1712/5092] bump xargo version --- src/bin/cargo-miri.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 8f26aaf4e91a..9ef4996992a4 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -6,7 +6,7 @@ use std::ops::Not; use std::path::{Path, PathBuf}; use std::process::Command; -const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 19); +const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 20); const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and tests in Miri From 81d505670bb7f274bd33f43ebc879eb8f610d127 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Mar 2020 00:11:50 +0100 Subject: [PATCH 1713/5092] rustup; get rid of some try_from that are no longer needed --- rust-version | 2 +- src/eval.rs | 4 ++-- src/helpers.rs | 2 +- src/shims/env.rs | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index 3a7d316af8e9..538003d9fbae 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -02046a5d402c789c006d0da7662f800fe3c45faf +a5fb9ae5b2ed3cb011ada9dc1e8633aa0927f279 diff --git a/src/eval.rs b/src/eval.rs index d2ca57c39a79..8274b52bd085 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -114,7 +114,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ecx.layout_of(tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), u64::try_from(argvs.len()).unwrap()))?; let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into()); for (idx, arg) in argvs.into_iter().enumerate() { - let place = ecx.mplace_field(argvs_place, u64::try_from(idx).unwrap())?; + let place = ecx.mplace_field(argvs_place, idx)?; ecx.write_scalar(arg, place.into())?; } ecx.memory.mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?; @@ -154,7 +154,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Store the UTF-16 string. We just allocated so we know the bounds are fine. let char_size = Size::from_bytes(2); for (idx, &c) in cmd_utf16.iter().enumerate() { - let place = ecx.mplace_field(cmd_place, u64::try_from(idx).unwrap())?; + let place = ecx.mplace_field(cmd_place, idx)?; ecx.write_scalar(Scalar::from_uint(c, char_size), place.into())?; } } diff --git a/src/helpers.rs b/src/helpers.rs index 7ca2b238218a..11f95f40b909 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -598,7 +598,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Store the UTF-16 string. let char_size = Size::from_bytes(2); for (idx, c) in u16_vec.into_iter().chain(iter::once(0x0000)).enumerate() { - let place = this.mplace_field(mplace, u64::try_from(idx).unwrap())?; + let place = this.mplace_field(mplace, idx)?; this.write_scalar(Scalar::from_uint(c, char_size), place.into())?; } Ok((true, string_length)) diff --git a/src/shims/env.rs b/src/shims/env.rs index 192fc0d47abe..34c297248f0d 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -61,7 +61,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(match this.machine.env_vars.map.get(name) { // The offset is used to strip the "{name}=" part of the string. Some(var_ptr) => { - Scalar::from(var_ptr.offset(Size::from_bytes(u64::try_from(name.len()).unwrap().checked_add(1).unwrap()), this)?) + Scalar::from(var_ptr.offset(Size::from_bytes(name.len()) + Size::from_bytes(1), this)?) } None => Scalar::ptr_null(&*this.tcx), }) @@ -187,7 +187,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.layout_of(tcx.mk_array(tcx.types.usize, u64::try_from(vars.len()).unwrap()))?; let vars_place = this.allocate(vars_layout, MiriMemoryKind::Machine.into()); for (idx, var) in vars.into_iter().enumerate() { - let place = this.mplace_field(vars_place, u64::try_from(idx).unwrap())?; + let place = this.mplace_field(vars_place, idx)?; this.write_scalar(var, place.into())?; } this.write_scalar( From a97ce8d94b681f8fb23b70260a219e528047e52a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Mar 2020 19:25:51 +0100 Subject: [PATCH 1714/5092] test floating point casting better --- tests/run-pass/floats.rs | 47 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tests/run-pass/floats.rs b/tests/run-pass/floats.rs index 7577c48c5ae3..39dc73ed1891 100644 --- a/tests/run-pass/floats.rs +++ b/tests/run-pass/floats.rs @@ -1,17 +1,61 @@ fn main() { + // basic arithmetic assert_eq!(6.0_f32*6.0_f32, 36.0_f32); assert_eq!(6.0_f64*6.0_f64, 36.0_f64); assert_eq!(-{5.0_f32}, -5.0_f32); + assert_eq!(-{5.0_f64}, -5.0_f64); + // infinities, NaN assert!((5.0_f32/0.0).is_infinite()); + assert!((5.0_f64/0.0).is_infinite()); assert!((-5.0_f32).sqrt().is_nan()); + assert!((-5.0_f64).sqrt().is_nan()); + // byte-level transmute let x: u64 = unsafe { std::mem::transmute(42.0_f64) }; let y: f64 = unsafe { std::mem::transmute(x) }; assert_eq!(y, 42.0_f64); + let x: u32 = unsafe { std::mem::transmute(42.0_f32) }; + let y: f32 = unsafe { std::mem::transmute(x) }; + assert_eq!(y, 42.0_f32); + // f32 casts assert_eq!(5.0f32 as u32, 5); + assert_eq!(-5.0f32 as u32, 0); assert_eq!(5.0f32 as i32, 5); assert_eq!(-5.0f32 as i32, -5); + assert_eq!(std::f32::MAX as i32, i32::MAX); + assert_eq!(std::f32::INFINITY as i32, i32::MAX); + assert_eq!(std::f32::MAX as u32, u32::MAX); + assert_eq!(std::f32::INFINITY as u32, u32::MAX); + assert_eq!(std::f32::MIN as i32, i32::MIN); + assert_eq!(std::f32::NEG_INFINITY as i32, i32::MIN); + assert_eq!(std::f32::MIN as u32, 0); + assert_eq!(std::f32::NEG_INFINITY as u32, 0); + assert_eq!(std::f32::NAN as i32, 0); + assert_eq!(std::f32::NAN as u32, 0); + assert_eq!(u128::MAX as f32, std::f32::INFINITY); + assert_eq!((u32::MAX-127) as f32 as u32, u32::MAX); // rounding loss + assert_eq!((u32::MAX-128) as f32 as u32, u32::MAX-255); // rounding loss + // f64 casts + assert_eq!(5.0f64 as u64, 5); + assert_eq!(-5.0f64 as u64, 0); + assert_eq!(5.0f64 as i64, 5); + assert_eq!(-5.0f64 as i64, -5); + assert_eq!(std::f64::MAX as i64, i64::MAX); + assert_eq!(std::f64::INFINITY as i64, i64::MAX); + assert_eq!(std::f64::MAX as u64, u64::MAX); + assert_eq!(std::f64::INFINITY as u64, u64::MAX); + assert_eq!(std::f64::MIN as i64, i64::MIN); + assert_eq!(std::f64::NEG_INFINITY as i64, i64::MIN); + assert_eq!(std::f64::MIN as u64, 0); + assert_eq!(std::f64::NEG_INFINITY as u64, 0); + assert_eq!(std::f64::NAN as i64, 0); + assert_eq!(std::f64::NAN as u64, 0); + assert_eq!(u128::MAX as f64 as u128, u128::MAX); + assert_eq!((u64::MAX-1023) as f64 as u64, u64::MAX); // rounding loss + assert_eq!((u64::MAX-1024) as f64 as u64, u64::MAX-2047); // rounding loss + + // f32 min/max assert_eq!((1.0 as f32).max(-1.0), 1.0); assert_eq!((1.0 as f32).min(-1.0), -1.0); assert_eq!(std::f32::NAN.min(9.0), 9.0); @@ -19,6 +63,7 @@ fn main() { assert_eq!((9.0 as f32).min(std::f32::NAN), 9.0); assert_eq!((-9.0 as f32).max(std::f32::NAN), -9.0); + // f64 min/max assert_eq!((1.0 as f64).max(-1.0), 1.0); assert_eq!((1.0 as f64).min(-1.0), -1.0); assert_eq!(std::f64::NAN.min(9.0), 9.0); @@ -26,12 +71,14 @@ fn main() { assert_eq!((9.0 as f64).min(std::f64::NAN), 9.0); assert_eq!((-9.0 as f64).max(std::f64::NAN), -9.0); + // f32 copysign assert_eq!(3.5_f32.copysign(0.42), 3.5_f32); assert_eq!(3.5_f32.copysign(-0.42), -3.5_f32); assert_eq!((-3.5_f32).copysign(0.42), 3.5_f32); assert_eq!((-3.5_f32).copysign(-0.42), -3.5_f32); assert!(std::f32::NAN.copysign(1.0).is_nan()); + // f64 copysign assert_eq!(3.5_f64.copysign(0.42), 3.5_f64); assert_eq!(3.5_f64.copysign(-0.42), -3.5_f64); assert_eq!((-3.5_f64).copysign(0.42), 3.5_f64); From fc8f88e04e04f83879e7d2548de5b5addac10600 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Fri, 27 Mar 2020 00:08:27 -0400 Subject: [PATCH 1715/5092] change helper fn 'write_os_str_to_wide_str' --- rust-version | 2 +- src/helpers.rs | 26 +++++--------------------- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/rust-version b/rust-version index 538003d9fbae..a11e231acb30 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a5fb9ae5b2ed3cb011ada9dc1e8633aa0927f279 +7b73d14b0b35e7b4f79f2d71dc1bbbab31698288 diff --git a/src/helpers.rs b/src/helpers.rs index 11f95f40b909..cdad723502eb 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -463,18 +463,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - /// Dispatches to appropriate implementations for reading an OsString from Memory, - /// depending on the interpretation target. - /// FIXME: Use `Cow` to avoid copies - fn read_os_str_from_target_str(&self, scalar: Scalar) -> InterpResult<'tcx, OsString> { - let target_os = self.eval_context_ref().tcx.sess.target.target.target_os.as_str(); - match target_os { - "linux" | "macos" => self.read_os_str_from_c_str(scalar).map(|x| x.to_os_string()), - "windows" => self.read_os_str_from_wide_str(scalar), - unsupported => throw_unsup_format!("OsString support for target OS `{}` not yet available", unsupported), - } - } - /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. fn read_os_str_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, &'a OsStr> @@ -567,7 +555,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_os_str_to_wide_str( &mut self, os_str: &OsStr, - mplace: MPlaceTy<'tcx, Tag>, + scalar: Scalar, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { #[cfg(windows)] @@ -593,14 +581,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok((false, string_length)); } - let this = self.eval_context_mut(); - // Store the UTF-16 string. - let char_size = Size::from_bytes(2); - for (idx, c) in u16_vec.into_iter().chain(iter::once(0x0000)).enumerate() { - let place = this.mplace_field(mplace, idx)?; - this.write_scalar(Scalar::from_uint(c, char_size), place.into())?; - } + self.eval_context_mut() + .memory + .write_u16s(scalar, u16_vec.into_iter().chain(iter::once(0x0000)))?; Ok((true, string_length)) } @@ -645,7 +629,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let arg_type = this.tcx.mk_array(this.tcx.types.u16, size); let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind); - assert!(self.write_os_str_to_wide_str(os_str, arg_place, size).unwrap().0); + assert!(self.write_os_str_to_wide_str(os_str, arg_place.ptr, size).unwrap().0); arg_place.ptr.assert_ptr() } From 160ebaa364bb1c7c93885765d398dcecda857664 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Fri, 27 Mar 2020 00:10:45 -0400 Subject: [PATCH 1716/5092] add OS-specific handling to src/shims/env.rs --- src/shims/env.rs | 55 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 34c297248f0d..990ccf7d69bd 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -23,8 +23,12 @@ pub struct EnvVars<'tcx> { impl<'tcx> EnvVars<'tcx> { pub(crate) fn init<'mir>( ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, - excluded_env_vars: Vec, + mut excluded_env_vars: Vec, ) -> InterpResult<'tcx> { + if ecx.tcx.sess.target.target.target_os == "windows" { + // Exclude `TERM` var to avoid terminfo trying to open the termcap file. + excluded_env_vars.push("TERM".to_owned()); + } if ecx.machine.communicate { for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { @@ -49,19 +53,41 @@ fn alloc_env_var_as_target_str<'mir, 'tcx>( Ok(ecx.alloc_os_str_as_target_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into())?) } +fn alloc_env_var_as_c_str<'mir, 'tcx>( + name: &OsStr, + value: &OsStr, + ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, +) -> InterpResult<'tcx, Pointer> { + let mut name_osstring = name.to_os_string(); + name_osstring.push("="); + name_osstring.push(value); + Ok(ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into())) +} + +fn alloc_env_var_as_wide_str<'mir, 'tcx>( + name: &OsStr, + value: &OsStr, + ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, +) -> InterpResult<'tcx, Pointer> { + let mut name_osstring = name.to_os_string(); + name_osstring.push("="); + name_osstring.push(value); + Ok(ecx.alloc_os_str_as_wide_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into())) +} + impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn getenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let target_os = this.tcx.sess.target.target.target_os.as_str(); - assert!(target_os == "linux" || target_os == "macos", "`{}` is only available for the UNIX target family"); + let target_os = &this.tcx.sess.target.target.target_os; + assert!(target_os == "linux" || target_os == "macos", "`getenv` is only available for the UNIX target family"); let name_ptr = this.read_scalar(name_op)?.not_undef()?; let name = this.read_os_str_from_c_str(name_ptr)?; Ok(match this.machine.env_vars.map.get(name) { - // The offset is used to strip the "{name}=" part of the string. Some(var_ptr) => { - Scalar::from(var_ptr.offset(Size::from_bytes(name.len()) + Size::from_bytes(1), this)?) + // The offset is used to strip the "{name}=" part of the string. + Scalar::from(var_ptr.offset(Size::from_bytes(u64::try_from(name.len()).unwrap().checked_add(1).unwrap()), this)?) } None => Scalar::ptr_null(&*this.tcx), }) @@ -73,32 +99,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx value_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let mut this = self.eval_context_mut(); + let target_os = &this.tcx.sess.target.target.target_os; + assert!(target_os == "linux" || target_os == "macos", "`setenv` is only available for the UNIX target family"); let name_ptr = this.read_scalar(name_op)?.not_undef()?; let value_ptr = this.read_scalar(value_op)?.not_undef()?; - let value = this.read_os_str_from_target_str(value_ptr)?; + let mut new = None; if !this.is_null(name_ptr)? { - let name = this.read_os_str_from_target_str(name_ptr)?; + let name = this.read_os_str_from_c_str(name_ptr)?; if !name.is_empty() && !name.to_string_lossy().contains('=') { + let value = this.read_os_str_from_c_str(value_ptr)?; new = Some((name.to_owned(), value.to_owned())); } } if let Some((name, value)) = new { - let var_ptr = alloc_env_var_as_target_str(&name, &value, &mut this)?; + let var_ptr = alloc_env_var_as_c_str(&name, &value, &mut this)?; if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { this.memory .deallocate(var, None, MiriMemoryKind::Machine.into())?; } this.update_environ()?; - Ok(0) + Ok(0) // return zero on success } else { + // name argument is a null pointer, points to an empty string, or points to a string containing an '=' character. + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; Ok(-1) } } fn unsetenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + let target_os = &this.tcx.sess.target.target.target_os; + assert!(target_os == "linux" || target_os == "macos", "`unsetenv` is only available for the UNIX target family"); let name_ptr = this.read_scalar(name_op)?.not_undef()?; let mut success = None; @@ -116,6 +150,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.update_environ()?; Ok(0) } else { + // name argument is a null pointer, points to an empty string, or points to a string containing an '=' character. + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; Ok(-1) } } From 813d76d948cbaa8ae23fc645e1f4f02438d2ed9e Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Fri, 27 Mar 2020 07:07:21 -0400 Subject: [PATCH 1717/5092] follow-up to reviews --- src/helpers.rs | 15 --------------- src/shims/env.rs | 25 +++++++------------------ 2 files changed, 7 insertions(+), 33 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index cdad723502eb..3e89fdf6f3cc 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -588,21 +588,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok((true, string_length)) } - /// Dispatches to appropriate implementations for allocating & writing OsString in Memory, - /// depending on the interpretation target. - fn alloc_os_str_as_target_str( - &mut self, - os_str: &OsStr, - memkind: MemoryKind, - ) -> InterpResult<'tcx, Pointer> { - let target_os = self.eval_context_ref().tcx.sess.target.target.target_os.as_str(); - match target_os { - "linux" | "macos" => Ok(self.alloc_os_str_as_c_str(os_str, memkind)), - "windows" => Ok(self.alloc_os_str_as_wide_str(os_str, memkind)), - unsupported => throw_unsup_format!("OsString support for target OS `{}` not yet available", unsupported), - } - } - /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes. fn alloc_os_str_as_c_str( &mut self, diff --git a/src/shims/env.rs b/src/shims/env.rs index 990ccf7d69bd..7c126140491f 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -23,17 +23,17 @@ pub struct EnvVars<'tcx> { impl<'tcx> EnvVars<'tcx> { pub(crate) fn init<'mir>( ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, - mut excluded_env_vars: Vec, + excluded_env_vars: Vec, ) -> InterpResult<'tcx> { - if ecx.tcx.sess.target.target.target_os == "windows" { - // Exclude `TERM` var to avoid terminfo trying to open the termcap file. - excluded_env_vars.push("TERM".to_owned()); - } if ecx.machine.communicate { + let target_os = ecx.tcx.sess.target.target.target_os.as_str(); for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { - let var_ptr = - alloc_env_var_as_target_str(name.as_ref(), value.as_ref(), ecx)?; + let var_ptr = match target_os { + "linux" | "macos" => alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx)?, + "windows" => alloc_env_var_as_wide_str(name.as_ref(), value.as_ref(), ecx)?, + unsupported => throw_unsup_format!("OsString support for target OS `{}` not yet available", unsupported), + }; ecx.machine.env_vars.map.insert(OsString::from(name), var_ptr); } } @@ -42,17 +42,6 @@ impl<'tcx> EnvVars<'tcx> { } } -fn alloc_env_var_as_target_str<'mir, 'tcx>( - name: &OsStr, - value: &OsStr, - ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, -) -> InterpResult<'tcx, Pointer> { - let mut name_osstring = name.to_os_string(); - name_osstring.push("="); - name_osstring.push(value); - Ok(ecx.alloc_os_str_as_target_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into())?) -} - fn alloc_env_var_as_c_str<'mir, 'tcx>( name: &OsStr, value: &OsStr, From 07f7083409c3cdb112249bc4f5930c3713d1bbb4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 27 Mar 2020 12:35:08 +0100 Subject: [PATCH 1718/5092] env: more precise error --- src/shims/env.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 7c126140491f..79c386e894ec 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -32,7 +32,7 @@ impl<'tcx> EnvVars<'tcx> { let var_ptr = match target_os { "linux" | "macos" => alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx)?, "windows" => alloc_env_var_as_wide_str(name.as_ref(), value.as_ref(), ecx)?, - unsupported => throw_unsup_format!("OsString support for target OS `{}` not yet available", unsupported), + unsupported => throw_unsup_format!("environment support for target OS `{}` not yet available", unsupported), }; ecx.machine.env_vars.map.insert(OsString::from(name), var_ptr); } From 2fa07009f2a27c8d77ed48539cf66db6e2b5a676 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Fri, 13 Mar 2020 12:45:02 -0400 Subject: [PATCH 1719/5092] Windows shims for env var emulation Shims for GetEnvironmentVariableW / SetEnvironmentVariableW / GetEnvironmentStringsW. Passes test 'tests/run-pass/env.rs' --- src/shims/env.rs | 120 ++++++++++++++++++++++++++++- src/shims/foreign_items/windows.rs | 30 ++++---- tests/run-pass/env.rs | 2 - 3 files changed, 136 insertions(+), 16 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 79c386e894ec..97d74ad0e069 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,6 +1,7 @@ use std::ffi::{OsString, OsStr}; use std::env; use std::convert::TryFrom; +use std::collections::hash_map::Values; use crate::stacked_borrows::Tag; use crate::rustc_target::abi::LayoutOf; @@ -40,6 +41,10 @@ impl<'tcx> EnvVars<'tcx> { } ecx.update_environ() } + + pub(super) fn values(&self) -> InterpResult<'tcx, Values<'_, OsString, Pointer>> { + Ok(self.map.values()) + } } fn alloc_env_var_as_c_str<'mir, 'tcx>( @@ -82,6 +87,79 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) } + fn getenvironmentvariablew( + &mut self, + name_op: OpTy<'tcx, Tag>, // LPCWSTR lpName + buf_op: OpTy<'tcx, Tag>, // LPWSTR lpBuffer + size_op: OpTy<'tcx, Tag>, // DWORD nSize + ) -> InterpResult<'tcx, u64> { + let this = self.eval_context_mut(); + this.assert_target_os("windows", "GetEnvironmentVariableW"); + + let name_ptr = this.read_scalar(name_op)?.not_undef()?; + let name = this.read_os_str_from_wide_str(name_ptr)?; + Ok(match this.machine.env_vars.map.get(&name) { + Some(var_ptr) => { + // The offset is used to strip the "{name}=" part of the string. + let name_offset_bytes = + u64::try_from(name.len()).unwrap().checked_add(1).unwrap().checked_mul(2).unwrap(); + let var_ptr = Scalar::from(var_ptr.offset(Size::from_bytes(name_offset_bytes), this)?); + + let var_size = u64::try_from(this.read_os_str_from_wide_str(var_ptr)?.len()).unwrap(); + let buf_size = u64::try_from(this.read_scalar(size_op)?.to_i32()?).unwrap(); + let return_val = if var_size.checked_add(1).unwrap() > buf_size { + // If lpBuffer is not large enough to hold the data, the return value is the buffer size, in characters, + // required to hold the string and its terminating null character and the contents of lpBuffer are undefined. + var_size + 1 + } else { + let buf_ptr = this.read_scalar(buf_op)?.not_undef()?; + for i in 0..var_size { + this.memory.copy( + this.force_ptr(var_ptr.ptr_offset(Size::from_bytes(i) * 2, this)?)?, + this.force_ptr(buf_ptr.ptr_offset(Size::from_bytes(i) * 2, this)?)?, + Size::from_bytes(2), + true, + )?; + } + // If the function succeeds, the return value is the number of characters stored in the buffer pointed to by lpBuffer, + // not including the terminating null character. + var_size + }; + return_val + } + None => { + this.set_last_error(Scalar::from_u32(203))?; // ERROR_ENVVAR_NOT_FOUND + 0 // return zero upon failure + } + }) + } + + fn getenvironmentstringsw(&mut self) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + this.assert_target_os("windows", "GetEnvironmentStringsW"); + + // Info on layout of environment blocks in Windows: + // https://docs.microsoft.com/en-us/windows/win32/procthread/environment-variables + let mut env_vars = std::ffi::OsString::new(); + for &item in this.machine.env_vars.values()? { + let env_var = this.read_os_str_from_target_str(Scalar::from(item))?; + env_vars.push(env_var); + env_vars.push("\0"); + } + + // Allocate environment block + let tcx = this.tcx; + let env_block_size = env_vars.len().checked_add(1).unwrap(); + let env_block_type = tcx.mk_array(tcx.types.u16, u64::try_from(env_block_size).unwrap()); + let env_block_place = this.allocate(this.layout_of(env_block_type)?, MiriMemoryKind::WinHeap.into()); + + // Store environment variables to environment block + // Final null terminator(block terminator) is pushed by `write_os_str_to_wide_str` + this.write_os_str_to_wide_str(&env_vars, env_block_place, u64::try_from(env_block_size).unwrap())?; + + Ok(env_block_place.ptr) + } + fn setenv( &mut self, name_op: OpTy<'tcx, Tag>, @@ -118,6 +196,46 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + fn setenvironmentvariablew( + &mut self, + name_op: OpTy<'tcx, Tag>, // LPCWSTR lpName, + value_op: OpTy<'tcx, Tag>, // LPCWSTR lpValue, + ) -> InterpResult<'tcx, i32> { + let mut this = self.eval_context_mut(); + this.assert_target_os("windows", "SetEnvironmentVariableW"); + + let name_ptr = this.read_scalar(name_op)?.not_undef()?; + let value_ptr = this.read_scalar(value_op)?.not_undef()?; + + let mut new = None; + if !this.is_null(name_ptr)? { + let name = this.read_os_str_from_target_str(name_ptr)?; + if this.is_null(value_ptr)? { + // Delete environment variable `{name}` + if let Some(var) = this.machine.env_vars.map.remove(&name) { + this.memory.deallocate(var, None, MiriMemoryKind::Machine.into())?; + this.update_environ()?; + } + return Ok(1); // return non-zero on success + } + if !name.is_empty() && !name.to_string_lossy().contains('=') { + let value = this.read_os_str_from_target_str(value_ptr)?; + new = Some((name.to_owned(), value.to_owned())); + } + } + if let Some((name, value)) = new { + let var_ptr = alloc_env_var_as_target_str(&name, &value, &mut this)?; + if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { + this.memory + .deallocate(var, None, MiriMemoryKind::Machine.into())?; + } + this.update_environ()?; + Ok(1) // return non-zero on success + } else { + Ok(0) + } + } + fn unsetenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let target_os = &this.tcx.sess.target.target.target_os; @@ -126,7 +244,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_ptr = this.read_scalar(name_op)?.not_undef()?; let mut success = None; if !this.is_null(name_ptr)? { - let name = this.read_os_str_from_c_str(name_ptr)?.to_owned(); + let name = this.read_os_str_from_target_str(name_ptr)?.to_owned(); if !name.is_empty() && !name.to_string_lossy().contains('=') { success = Some(this.machine.env_vars.map.remove(&name)); } diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index a35734573f29..057f1c06a850 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -23,22 +23,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Environment related shims "GetEnvironmentVariableW" => { - // args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars) - // args[1] : LPWSTR lpBuffer (32-bit pointer to a string of 16-bit Unicode chars) - // lpBuffer : ptr to buffer that receives contents of the env_var as a null-terminated string. - // Return `# of chars` stored in the buffer pointed to by lpBuffer, excluding null-terminator. - // Return 0 upon failure. - - // This is not the env var you are looking for. - this.set_last_error(Scalar::from_u32(203))?; // ERROR_ENVVAR_NOT_FOUND - this.write_null(dest)?; + let result = this.getenvironmentvariablew(args[0], args[1], args[2])?; + this.write_scalar(Scalar::from_uint(result, dest.layout.size), dest)?; } "SetEnvironmentVariableW" => { - // args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars) - // args[1] : LPCWSTR lpValue (32-bit ptr to a const string of 16-bit Unicode chars) - // Return nonzero if success, else return 0. - throw_unsup_format!("can't set environment variable on Windows"); + let result = this.setenvironmentvariablew(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "GetEnvironmentStringsW" => { + let result = this.getenvironmentstringsw()?; + // If the function succeeds, the return value is a pointer to the environment block of the current process. + this.write_scalar(result, dest)?; + } + + "FreeEnvironmentStringsW" => { + let old_vars_ptr = this.read_scalar(args[0])?.not_undef()?; + let result = this.memory.deallocate(this.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::WinHeap.into()).is_ok(); + // If the function succeeds, the return value is nonzero. + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } // File related shims diff --git a/tests/run-pass/env.rs b/tests/run-pass/env.rs index c7506b23c1da..23a3724ff7fd 100644 --- a/tests/run-pass/env.rs +++ b/tests/run-pass/env.rs @@ -1,5 +1,3 @@ -//ignore-windows: TODO env var emulation stubbed out on Windows - use std::env; fn main() { From cf5822af460f342721662a4dc959713a1cd7778c Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Tue, 24 Mar 2020 16:00:11 -0400 Subject: [PATCH 1720/5092] exclude 'TERM' env_var to avoid terminfo trying to open the termcap file --- README.md | 2 +- src/shims/env.rs | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 59394830d79b..03b995aa56d3 100644 --- a/README.md +++ b/README.md @@ -166,7 +166,7 @@ Several `-Z` flags are relevant for Miri: * `-Zmiri-disable-stacked-borrows` disables checking the experimental [Stacked Borrows] aliasing rules. This can make Miri run faster, but it also means no aliasing violations will be detected. -* `-Zmiri-disable-isolation` disables host host isolation. As a consequence, +* `-Zmiri-disable-isolation` disables host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness. * `-Zmiri-ignore-leaks` disables the memory leak checker. diff --git a/src/shims/env.rs b/src/shims/env.rs index 97d74ad0e069..32ed65b39830 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -24,8 +24,12 @@ pub struct EnvVars<'tcx> { impl<'tcx> EnvVars<'tcx> { pub(crate) fn init<'mir>( ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, - excluded_env_vars: Vec, + mut excluded_env_vars: Vec, ) -> InterpResult<'tcx> { + if ecx.tcx.sess.target.target.target_os.to_lowercase() == "windows" { + // Exclude `TERM` var to avoid terminfo trying to open the termcap file. + excluded_env_vars.push("TERM".to_owned()); + } if ecx.machine.communicate { let target_os = ecx.tcx.sess.target.target.target_os.as_str(); for (name, value) in env::vars() { From 2051805e957d307f7f084172b61cf0a6d69edfc9 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Wed, 25 Mar 2020 00:52:53 -0400 Subject: [PATCH 1721/5092] follow-up to reviews --- src/shims/env.rs | 110 +++++++++++++++++------------ src/shims/foreign_items/windows.rs | 9 ++- 2 files changed, 69 insertions(+), 50 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 32ed65b39830..2e647589f411 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,3 +1,5 @@ +#![allow(non_snake_case)] + use std::ffi::{OsString, OsStr}; use std::env; use std::convert::TryFrom; @@ -26,7 +28,7 @@ impl<'tcx> EnvVars<'tcx> { ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, mut excluded_env_vars: Vec, ) -> InterpResult<'tcx> { - if ecx.tcx.sess.target.target.target_os.to_lowercase() == "windows" { + if ecx.tcx.sess.target.target.target_os == "windows" { // Exclude `TERM` var to avoid terminfo trying to open the termcap file. excluded_env_vars.push("TERM".to_owned()); } @@ -46,7 +48,7 @@ impl<'tcx> EnvVars<'tcx> { ecx.update_environ() } - pub(super) fn values(&self) -> InterpResult<'tcx, Values<'_, OsString, Pointer>> { + fn values(&self) -> InterpResult<'tcx, Values<'_, OsString, Pointer>> { Ok(self.map.values()) } } @@ -73,6 +75,28 @@ fn alloc_env_var_as_wide_str<'mir, 'tcx>( Ok(ecx.alloc_os_str_as_wide_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into())) } +fn alloc_env_var_as_c_str<'mir, 'tcx>( + name: &OsStr, + value: &OsStr, + ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, +) -> InterpResult<'tcx, Pointer> { + let mut name_osstring = name.to_os_string(); + name_osstring.push("="); + name_osstring.push(value); + Ok(ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into())) +} + +fn alloc_env_var_as_wide_str<'mir, 'tcx>( + name: &OsStr, + value: &OsStr, + ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, +) -> InterpResult<'tcx, Pointer> { + let mut name_osstring = name.to_os_string(); + name_osstring.push("="); + name_osstring.push(value); + Ok(ecx.alloc_os_str_as_wide_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into())) +} + impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn getenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { @@ -91,7 +115,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) } - fn getenvironmentvariablew( + fn GetEnvironmentVariableW( &mut self, name_op: OpTy<'tcx, Tag>, // LPCWSTR lpName buf_op: OpTy<'tcx, Tag>, // LPWSTR lpBuffer @@ -110,21 +134,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let var_ptr = Scalar::from(var_ptr.offset(Size::from_bytes(name_offset_bytes), this)?); let var_size = u64::try_from(this.read_os_str_from_wide_str(var_ptr)?.len()).unwrap(); - let buf_size = u64::try_from(this.read_scalar(size_op)?.to_i32()?).unwrap(); + // `buf_size` represent size in characters. + let buf_size = u64::try_from(this.read_scalar(size_op)?.to_u32()?).unwrap(); let return_val = if var_size.checked_add(1).unwrap() > buf_size { // If lpBuffer is not large enough to hold the data, the return value is the buffer size, in characters, // required to hold the string and its terminating null character and the contents of lpBuffer are undefined. var_size + 1 } else { let buf_ptr = this.read_scalar(buf_op)?.not_undef()?; - for i in 0..var_size { - this.memory.copy( - this.force_ptr(var_ptr.ptr_offset(Size::from_bytes(i) * 2, this)?)?, - this.force_ptr(buf_ptr.ptr_offset(Size::from_bytes(i) * 2, this)?)?, - Size::from_bytes(2), - true, - )?; - } + let bytes_to_be_copied = var_size.checked_add(1).unwrap().checked_mul(2).unwrap(); + this.memory.copy(this.force_ptr(var_ptr)?, this.force_ptr(buf_ptr)?, Size::from_bytes(bytes_to_be_copied), true)?; // If the function succeeds, the return value is the number of characters stored in the buffer pointed to by lpBuffer, // not including the terminating null character. var_size @@ -138,7 +157,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) } - fn getenvironmentstringsw(&mut self) -> InterpResult<'tcx, Scalar> { + fn GetEnvironmentStringsW(&mut self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("windows", "GetEnvironmentStringsW"); @@ -146,22 +165,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // https://docs.microsoft.com/en-us/windows/win32/procthread/environment-variables let mut env_vars = std::ffi::OsString::new(); for &item in this.machine.env_vars.values()? { - let env_var = this.read_os_str_from_target_str(Scalar::from(item))?; + let env_var = this.read_os_str_from_wide_str(Scalar::from(item))?; env_vars.push(env_var); env_vars.push("\0"); } + // Allocate environment block & Store environment variables to environment block. + // Final null terminator(block terminator) is added by `alloc_os_str_to_wide_str`. + let envblock_ptr = this.alloc_os_str_as_wide_str(&env_vars, MiriMemoryKind::WinHeap.into()); - // Allocate environment block - let tcx = this.tcx; - let env_block_size = env_vars.len().checked_add(1).unwrap(); - let env_block_type = tcx.mk_array(tcx.types.u16, u64::try_from(env_block_size).unwrap()); - let env_block_place = this.allocate(this.layout_of(env_block_type)?, MiriMemoryKind::WinHeap.into()); - - // Store environment variables to environment block - // Final null terminator(block terminator) is pushed by `write_os_str_to_wide_str` - this.write_os_str_to_wide_str(&env_vars, env_block_place, u64::try_from(env_block_size).unwrap())?; + Ok(envblock_ptr.into()) + } - Ok(env_block_place.ptr) + fn FreeEnvironmentStringsW(&mut self, env_block_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, bool> { + let this = self.eval_context_mut(); + this.assert_target_os("windows", "FreeEnvironmentStringsW"); + + let env_block_ptr = this.read_scalar(env_block_op)?.not_undef()?; + Ok(this.memory.deallocate(this.force_ptr(env_block_ptr)?, None, MiriMemoryKind::WinHeap.into()).is_ok()) } fn setenv( @@ -200,7 +220,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn setenvironmentvariablew( + fn SetEnvironmentVariableW( &mut self, name_op: OpTy<'tcx, Tag>, // LPCWSTR lpName, value_op: OpTy<'tcx, Tag>, // LPCWSTR lpValue, @@ -211,32 +231,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_ptr = this.read_scalar(name_op)?.not_undef()?; let value_ptr = this.read_scalar(value_op)?.not_undef()?; - let mut new = None; - if !this.is_null(name_ptr)? { - let name = this.read_os_str_from_target_str(name_ptr)?; - if this.is_null(value_ptr)? { - // Delete environment variable `{name}` - if let Some(var) = this.machine.env_vars.map.remove(&name) { - this.memory.deallocate(var, None, MiriMemoryKind::Machine.into())?; - this.update_environ()?; - } - return Ok(1); // return non-zero on success - } - if !name.is_empty() && !name.to_string_lossy().contains('=') { - let value = this.read_os_str_from_target_str(value_ptr)?; - new = Some((name.to_owned(), value.to_owned())); - } + if this.is_null(name_ptr)? { + // ERROR CODE is not clearly explained in docs.. For now, throw UB instead. + throw_ub_format!("Pointer to environment variable name is NULL"); } - if let Some((name, value)) = new { - let var_ptr = alloc_env_var_as_target_str(&name, &value, &mut this)?; + + let name = this.read_os_str_from_wide_str(name_ptr)?; + if name.is_empty() { + throw_unsup_format!("Environment variable name is an empty string"); + } else if name.to_string_lossy().contains('=') { + throw_unsup_format!("Environment variable name contains '='"); + } else if this.is_null(value_ptr)? { + // Delete environment variable `{name}` + if let Some(var) = this.machine.env_vars.map.remove(&name) { + this.memory.deallocate(var, None, MiriMemoryKind::Machine.into())?; + this.update_environ()?; + } + Ok(1) // return non-zero on success + } else { + let value = this.read_os_str_from_wide_str(value_ptr)?; + let var_ptr = alloc_env_var_as_wide_str(&name, &value, &mut this)?; if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { this.memory .deallocate(var, None, MiriMemoryKind::Machine.into())?; } this.update_environ()?; Ok(1) // return non-zero on success - } else { - Ok(0) } } @@ -248,7 +268,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_ptr = this.read_scalar(name_op)?.not_undef()?; let mut success = None; if !this.is_null(name_ptr)? { - let name = this.read_os_str_from_target_str(name_ptr)?.to_owned(); + let name = this.read_os_str_from_c_str(name_ptr)?.to_owned(); if !name.is_empty() && !name.to_string_lossy().contains('=') { success = Some(this.machine.env_vars.map.remove(&name)); } diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 057f1c06a850..cc64057135c1 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -23,24 +23,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Environment related shims "GetEnvironmentVariableW" => { - let result = this.getenvironmentvariablew(args[0], args[1], args[2])?; + let result = this.GetEnvironmentVariableW(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_uint(result, dest.layout.size), dest)?; } "SetEnvironmentVariableW" => { - let result = this.setenvironmentvariablew(args[0], args[1])?; + let result = this.SetEnvironmentVariableW(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } "GetEnvironmentStringsW" => { - let result = this.getenvironmentstringsw()?; + let result = this.GetEnvironmentStringsW()?; // If the function succeeds, the return value is a pointer to the environment block of the current process. this.write_scalar(result, dest)?; } "FreeEnvironmentStringsW" => { - let old_vars_ptr = this.read_scalar(args[0])?.not_undef()?; - let result = this.memory.deallocate(this.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::WinHeap.into()).is_ok(); + let result = this.FreeEnvironmentStringsW(args[0])?; // If the function succeeds, the return value is nonzero. this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } From 4e38fbe6be6d5c8d67de5ca65ab763f9f314a398 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Wed, 25 Mar 2020 10:38:27 -0400 Subject: [PATCH 1722/5092] follow-up2 to review (few issues not resolved yet) --- src/shims/env.rs | 45 +++++++++++++++++------------- src/shims/foreign_items/windows.rs | 4 +-- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 2e647589f411..cc7c305596dc 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,9 +1,6 @@ -#![allow(non_snake_case)] - use std::ffi::{OsString, OsStr}; use std::env; use std::convert::TryFrom; -use std::collections::hash_map::Values; use crate::stacked_borrows::Tag; use crate::rustc_target::abi::LayoutOf; @@ -47,10 +44,6 @@ impl<'tcx> EnvVars<'tcx> { } ecx.update_environ() } - - fn values(&self) -> InterpResult<'tcx, Values<'_, OsString, Pointer>> { - Ok(self.map.values()) - } } fn alloc_env_var_as_c_str<'mir, 'tcx>( @@ -115,11 +108,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) } + #[allow(non_snake_case)] fn GetEnvironmentVariableW( &mut self, - name_op: OpTy<'tcx, Tag>, // LPCWSTR lpName - buf_op: OpTy<'tcx, Tag>, // LPWSTR lpBuffer - size_op: OpTy<'tcx, Tag>, // DWORD nSize + name_op: OpTy<'tcx, Tag>, // LPCWSTR + buf_op: OpTy<'tcx, Tag>, // LPWSTR + size_op: OpTy<'tcx, Tag>, // DWORD ) -> InterpResult<'tcx, u64> { let this = self.eval_context_mut(); this.assert_target_os("windows", "GetEnvironmentVariableW"); @@ -134,7 +128,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let var_ptr = Scalar::from(var_ptr.offset(Size::from_bytes(name_offset_bytes), this)?); let var_size = u64::try_from(this.read_os_str_from_wide_str(var_ptr)?.len()).unwrap(); - // `buf_size` represent size in characters. + // `buf_size` represents the size in characters. let buf_size = u64::try_from(this.read_scalar(size_op)?.to_u32()?).unwrap(); let return_val = if var_size.checked_add(1).unwrap() > buf_size { // If lpBuffer is not large enough to hold the data, the return value is the buffer size, in characters, @@ -157,6 +151,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) } + #[allow(non_snake_case)] fn GetEnvironmentStringsW(&mut self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("windows", "GetEnvironmentStringsW"); @@ -164,24 +159,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Info on layout of environment blocks in Windows: // https://docs.microsoft.com/en-us/windows/win32/procthread/environment-variables let mut env_vars = std::ffi::OsString::new(); - for &item in this.machine.env_vars.values()? { + for &item in this.machine.env_vars.map.values() { let env_var = this.read_os_str_from_wide_str(Scalar::from(item))?; env_vars.push(env_var); env_vars.push("\0"); } // Allocate environment block & Store environment variables to environment block. // Final null terminator(block terminator) is added by `alloc_os_str_to_wide_str`. + // FIXME: MemoryKind should be `MiMemoryKind::Machine`, + // but using it results in a Stacked Borrows error when running MIRI on 'tests/run-pass/env.rs' + // For now, use `MiriMemoryKind::WinHeap` instead. let envblock_ptr = this.alloc_os_str_as_wide_str(&env_vars, MiriMemoryKind::WinHeap.into()); - + // If the function succeeds, the return value is a pointer to the environment block of the current process. Ok(envblock_ptr.into()) } - fn FreeEnvironmentStringsW(&mut self, env_block_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, bool> { + #[allow(non_snake_case)] + fn FreeEnvironmentStringsW(&mut self, env_block_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("windows", "FreeEnvironmentStringsW"); let env_block_ptr = this.read_scalar(env_block_op)?.not_undef()?; - Ok(this.memory.deallocate(this.force_ptr(env_block_ptr)?, None, MiriMemoryKind::WinHeap.into()).is_ok()) + // FIXME: MemoryKind should be `MiMemoryKind::Machine`, + // but using it results in a Stacked Borrows error when running MIRI on 'tests/run-pass/env.rs' + // For now, use `MiriMemoryKind::WinHeap` instead. + let result = this.memory.deallocate(this.force_ptr(env_block_ptr)?, None, MiriMemoryKind::WinHeap.into()); + // If the function succeeds, the return value is nonzero. + Ok(result.is_ok() as i32) } fn setenv( @@ -220,10 +224,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + #[allow(non_snake_case)] fn SetEnvironmentVariableW( &mut self, - name_op: OpTy<'tcx, Tag>, // LPCWSTR lpName, - value_op: OpTy<'tcx, Tag>, // LPCWSTR lpValue, + name_op: OpTy<'tcx, Tag>, // LPCWSTR + value_op: OpTy<'tcx, Tag>, // LPCWSTR ) -> InterpResult<'tcx, i32> { let mut this = self.eval_context_mut(); this.assert_target_os("windows", "SetEnvironmentVariableW"); @@ -233,14 +238,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.is_null(name_ptr)? { // ERROR CODE is not clearly explained in docs.. For now, throw UB instead. - throw_ub_format!("Pointer to environment variable name is NULL"); + throw_ub_format!("pointer to environment variable name is NULL"); } let name = this.read_os_str_from_wide_str(name_ptr)?; if name.is_empty() { - throw_unsup_format!("Environment variable name is an empty string"); + throw_unsup_format!("environment variable name is an empty string"); } else if name.to_string_lossy().contains('=') { - throw_unsup_format!("Environment variable name contains '='"); + throw_unsup_format!("environment variable name contains '='"); } else if this.is_null(value_ptr)? { // Delete environment variable `{name}` if let Some(var) = this.machine.env_vars.map.remove(&name) { diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index cc64057135c1..a64ef0f12935 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -34,14 +34,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "GetEnvironmentStringsW" => { let result = this.GetEnvironmentStringsW()?; - // If the function succeeds, the return value is a pointer to the environment block of the current process. this.write_scalar(result, dest)?; } "FreeEnvironmentStringsW" => { let result = this.FreeEnvironmentStringsW(args[0])?; - // If the function succeeds, the return value is nonzero. - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } // File related shims From f3e3af4beec260541dbeeead0a824caee7624e77 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Fri, 27 Mar 2020 09:18:13 -0400 Subject: [PATCH 1723/5092] adjust to change of 'fn write_os_str_to_wide_str' --- src/shims/env.rs | 52 ++++++++++++++---------------------------------- 1 file changed, 15 insertions(+), 37 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index cc7c305596dc..794a1aab422a 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -25,12 +25,12 @@ impl<'tcx> EnvVars<'tcx> { ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, mut excluded_env_vars: Vec, ) -> InterpResult<'tcx> { - if ecx.tcx.sess.target.target.target_os == "windows" { + let target_os = ecx.tcx.sess.target.target.target_os.as_str(); + if target_os == "windows" { // Exclude `TERM` var to avoid terminfo trying to open the termcap file. excluded_env_vars.push("TERM".to_owned()); } if ecx.machine.communicate { - let target_os = ecx.tcx.sess.target.target.target_os.as_str(); for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { let var_ptr = match target_os { @@ -68,28 +68,6 @@ fn alloc_env_var_as_wide_str<'mir, 'tcx>( Ok(ecx.alloc_os_str_as_wide_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into())) } -fn alloc_env_var_as_c_str<'mir, 'tcx>( - name: &OsStr, - value: &OsStr, - ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, -) -> InterpResult<'tcx, Pointer> { - let mut name_osstring = name.to_os_string(); - name_osstring.push("="); - name_osstring.push(value); - Ok(ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into())) -} - -fn alloc_env_var_as_wide_str<'mir, 'tcx>( - name: &OsStr, - value: &OsStr, - ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, -) -> InterpResult<'tcx, Pointer> { - let mut name_osstring = name.to_os_string(); - name_osstring.push("="); - name_osstring.push(value); - Ok(ecx.alloc_os_str_as_wide_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into())) -} - impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn getenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { @@ -126,26 +104,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_offset_bytes = u64::try_from(name.len()).unwrap().checked_add(1).unwrap().checked_mul(2).unwrap(); let var_ptr = Scalar::from(var_ptr.offset(Size::from_bytes(name_offset_bytes), this)?); + let var = this.read_os_str_from_wide_str(var_ptr)?; - let var_size = u64::try_from(this.read_os_str_from_wide_str(var_ptr)?.len()).unwrap(); + let buf_ptr = this.read_scalar(buf_op)?.not_undef()?; // `buf_size` represents the size in characters. let buf_size = u64::try_from(this.read_scalar(size_op)?.to_u32()?).unwrap(); - let return_val = if var_size.checked_add(1).unwrap() > buf_size { - // If lpBuffer is not large enough to hold the data, the return value is the buffer size, in characters, - // required to hold the string and its terminating null character and the contents of lpBuffer are undefined. - var_size + 1 - } else { - let buf_ptr = this.read_scalar(buf_op)?.not_undef()?; - let bytes_to_be_copied = var_size.checked_add(1).unwrap().checked_mul(2).unwrap(); - this.memory.copy(this.force_ptr(var_ptr)?, this.force_ptr(buf_ptr)?, Size::from_bytes(bytes_to_be_copied), true)?; + let (success, len) = this.write_os_str_to_wide_str(&var, buf_ptr, buf_size)?; + + if success { // If the function succeeds, the return value is the number of characters stored in the buffer pointed to by lpBuffer, // not including the terminating null character. - var_size - }; - return_val + len + } else { + // If lpBuffer is not large enough to hold the data, the return value is the buffer size, in characters, + // required to hold the string and its terminating null character and the contents of lpBuffer are undefined. + len + 1 + } } None => { - this.set_last_error(Scalar::from_u32(203))?; // ERROR_ENVVAR_NOT_FOUND + let envvar_not_found = this.eval_path_scalar(&["std", "sys", "windows", "c", "ERROR_ENVVAR_NOT_FOUND"])?; + this.set_last_error(envvar_not_found.not_undef()?)?; 0 // return zero upon failure } }) From eaca17fcc31a74690bc89d6b2aa7c41b4aedb79a Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Fri, 27 Mar 2020 09:59:42 -0400 Subject: [PATCH 1724/5092] add reference to issue#1013 --- src/shims/env.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 794a1aab422a..eee9a539185c 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -27,9 +27,11 @@ impl<'tcx> EnvVars<'tcx> { ) -> InterpResult<'tcx> { let target_os = ecx.tcx.sess.target.target.target_os.as_str(); if target_os == "windows" { - // Exclude `TERM` var to avoid terminfo trying to open the termcap file. + // Temporary hack: Exclude `TERM` var to avoid terminfo trying to open the termcap file. + // Can be removed once Issue#1013(Implement file system access for Windows) is resolved. excluded_env_vars.push("TERM".to_owned()); } + if ecx.machine.communicate { for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { From 3fe71dff5a58efaabd1686e2a25c09adb8d74092 Mon Sep 17 00:00:00 2001 From: Youngsuk Kim Date: Fri, 27 Mar 2020 10:15:35 -0400 Subject: [PATCH 1725/5092] Modify reference to issue 1013 Co-Authored-By: Ralf Jung --- src/shims/env.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index eee9a539185c..b6d701026378 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -28,7 +28,7 @@ impl<'tcx> EnvVars<'tcx> { let target_os = ecx.tcx.sess.target.target.target_os.as_str(); if target_os == "windows" { // Temporary hack: Exclude `TERM` var to avoid terminfo trying to open the termcap file. - // Can be removed once Issue#1013(Implement file system access for Windows) is resolved. + // Can be removed once https://github.com/rust-lang/miri/issues/1013 is resolved. excluded_env_vars.push("TERM".to_owned()); } From ea836eeb0d72d5f983489f283ea7fc5f6a7ad442 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Fri, 27 Mar 2020 14:18:19 -0400 Subject: [PATCH 1726/5092] remove or update 'ignore-windows' annotations in some tests --- tests/compile-fail/environ-gets-deallocated.rs | 2 +- tests/run-pass/env-exclude.rs | 1 - tests/run-pass/env-without-isolation.rs | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/compile-fail/environ-gets-deallocated.rs b/tests/compile-fail/environ-gets-deallocated.rs index dd00aef450cd..0f374a2e3f80 100644 --- a/tests/compile-fail/environ-gets-deallocated.rs +++ b/tests/compile-fail/environ-gets-deallocated.rs @@ -1,4 +1,4 @@ -//ignore-windows: TODO env var emulation stubbed out on Windows +//ignore-windows: Windows does not have a global environ list that the program can access directly #[cfg(target_os="linux")] fn get_environ() -> *const *const u8 { diff --git a/tests/run-pass/env-exclude.rs b/tests/run-pass/env-exclude.rs index efcf7a756114..1e251084f022 100644 --- a/tests/run-pass/env-exclude.rs +++ b/tests/run-pass/env-exclude.rs @@ -1,4 +1,3 @@ -// ignore-windows: TODO env var emulation stubbed out on Windows // compile-flags: -Zmiri-disable-isolation -Zmiri-env-exclude=MIRI_ENV_VAR_TEST fn main() { diff --git a/tests/run-pass/env-without-isolation.rs b/tests/run-pass/env-without-isolation.rs index 537e0923d20b..638476209888 100644 --- a/tests/run-pass/env-without-isolation.rs +++ b/tests/run-pass/env-without-isolation.rs @@ -1,4 +1,3 @@ -// ignore-windows: TODO env var emulation stubbed out on Windows // compile-flags: -Zmiri-disable-isolation fn main() { From da5f2f305b6ad749e01dc8d8698da0628ffd8365 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 27 Mar 2020 19:39:00 +0100 Subject: [PATCH 1727/5092] implement TLS cleanup for macOS --- src/eval.rs | 4 +-- src/shims/foreign_items/posix/macos.rs | 5 ++- src/shims/tls.rs | 44 ++++++++++++++++++++++++-- 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 8274b52bd085..7f07fc1a7db6 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -186,8 +186,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option { // FIXME: We always ignore leaks on some OSs where we do not // correctly implement TLS destructors. - let target_os = tcx.sess.target.target.target_os.as_str(); - let ignore_leaks = config.ignore_leaks || target_os == "windows" || target_os == "macos"; + let target_os = &tcx.sess.target.target.target_os; + let ignore_leaks = config.ignore_leaks || target_os == "windows"; let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) { Ok(v) => v, diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index ee02effecd2c..325be877d044 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -87,7 +87,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "_tlv_atexit" => { - // FIXME: register the destructor. + let dtor = this.read_scalar(args[0])?.not_undef()?; + let dtor = this.memory.get_fn(dtor)?.as_instance()?; + let data = this.read_scalar(args[1])?.not_undef()?; + this.machine.tls.set_global_dtor(dtor, data)?; } "_NSGetArgc" => { diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 094b58d99a28..6635978cb2e3 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -25,6 +25,12 @@ pub struct TlsData<'tcx> { /// pthreads-style thread-local storage. keys: BTreeMap>, + + /// A single global dtor (that's how things work on macOS) with a data argument. + global_dtor: Option<(ty::Instance<'tcx>, Scalar)>, + + /// Whether we are in the "destruct" phase, during which some operations are UB. + dtors_running: bool, } impl<'tcx> Default for TlsData<'tcx> { @@ -32,6 +38,8 @@ impl<'tcx> Default for TlsData<'tcx> { TlsData { next_key: 1, // start with 1 as we must not use 0 on Windows keys: Default::default(), + global_dtor: None, + dtors_running: false, } } } @@ -86,6 +94,19 @@ impl<'tcx> TlsData<'tcx> { } } + pub fn set_global_dtor(&mut self, dtor: ty::Instance<'tcx>, data: Scalar) -> InterpResult<'tcx> { + if self.dtors_running { + // UB, according to libstd docs. + throw_ub_format!("setting global destructor while destructors are already running"); + } + if self.global_dtor.is_some() { + throw_unsup_format!("setting more than one global destructor is not supported"); + } + + self.global_dtor = Some((dtor, data)); + Ok(()) + } + /// Returns a dtor, its argument and its index, if one is supposed to run /// /// An optional destructor function may be associated with each key value. @@ -134,11 +155,30 @@ impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tc pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn run_tls_dtors(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + assert!(!this.machine.tls.dtors_running, "running TLS dtors twice"); + this.machine.tls.dtors_running = true; + + // The macOS global dtor runs "before any TLS slots get freed", so do that first. + if let Some((instance, data)) = this.machine.tls.global_dtor { + trace!("Running global dtor {:?} on {:?}", instance, data); + + let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); + this.call_function( + instance, + &[data.into()], + Some(ret_place), + StackPopCleanup::None { cleanup: true }, + )?; + + // step until out of stackframes + this.run()?; + } + + // Now run the "keyed" destructors. let mut dtor = this.machine.tls.fetch_tls_dtor(None); - // FIXME: replace loop by some structure that works with stepping while let Some((instance, ptr, key)) = dtor { trace!("Running TLS dtor {:?} on {:?}", instance, ptr); - assert!(!this.is_null(ptr).unwrap(), "Data can't be NULL when dtor is called!"); + assert!(!this.is_null(ptr).unwrap(), "data can't be NULL when dtor is called!"); let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); this.call_function( From c5ef8a656fd211dd1d3c6d73cb3705dc4b301907 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 27 Mar 2020 19:39:35 +0100 Subject: [PATCH 1728/5092] enable leak tests on macOS --- tests/compile-fail/memleak.rs | 1 - tests/compile-fail/memleak_rc.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/tests/compile-fail/memleak.rs b/tests/compile-fail/memleak.rs index 06e01d7aea3a..c3b27abcdbb2 100644 --- a/tests/compile-fail/memleak.rs +++ b/tests/compile-fail/memleak.rs @@ -1,5 +1,4 @@ // ignore-windows: We do not check leaks on Windows -// ignore-macos: We do not check leaks on macOS //error-pattern: the evaluated program leaked memory diff --git a/tests/compile-fail/memleak_rc.rs b/tests/compile-fail/memleak_rc.rs index 14a85ecd8947..446d28681b9e 100644 --- a/tests/compile-fail/memleak_rc.rs +++ b/tests/compile-fail/memleak_rc.rs @@ -1,5 +1,4 @@ // ignore-windows: We do not check leaks on Windows -// ignore-macos: We do not check leaks on macOS //error-pattern: the evaluated program leaked memory From 579b3c49dac9def1495f7d97d4f5b2771bbeefd8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 27 Mar 2020 20:36:18 +0100 Subject: [PATCH 1729/5092] adjust MemoryKind comment --- src/shims/env.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index b6d701026378..ed689b1f4272 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -146,9 +146,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Allocate environment block & Store environment variables to environment block. // Final null terminator(block terminator) is added by `alloc_os_str_to_wide_str`. - // FIXME: MemoryKind should be `MiMemoryKind::Machine`, - // but using it results in a Stacked Borrows error when running MIRI on 'tests/run-pass/env.rs' - // For now, use `MiriMemoryKind::WinHeap` instead. + // FIXME: MemoryKind should be `Machine`, blocked on https://github.com/rust-lang/rust/pull/70479. let envblock_ptr = this.alloc_os_str_as_wide_str(&env_vars, MiriMemoryKind::WinHeap.into()); // If the function succeeds, the return value is a pointer to the environment block of the current process. Ok(envblock_ptr.into()) @@ -160,9 +158,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.assert_target_os("windows", "FreeEnvironmentStringsW"); let env_block_ptr = this.read_scalar(env_block_op)?.not_undef()?; - // FIXME: MemoryKind should be `MiMemoryKind::Machine`, - // but using it results in a Stacked Borrows error when running MIRI on 'tests/run-pass/env.rs' - // For now, use `MiriMemoryKind::WinHeap` instead. + // FIXME: MemoryKind should be `Machine`, blocked on https://github.com/rust-lang/rust/pull/70479. let result = this.memory.deallocate(this.force_ptr(env_block_ptr)?, None, MiriMemoryKind::WinHeap.into()); // If the function succeeds, the return value is nonzero. Ok(result.is_ok() as i32) From 032d9aa7d5160f39ab745a5da13d686ec214bb9b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Mar 2020 09:10:34 +0100 Subject: [PATCH 1730/5092] also do some float-to-float cast testing --- tests/run-pass/floats.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/floats.rs b/tests/run-pass/floats.rs index 39dc73ed1891..990745c85d67 100644 --- a/tests/run-pass/floats.rs +++ b/tests/run-pass/floats.rs @@ -17,7 +17,7 @@ fn main() { let y: f32 = unsafe { std::mem::transmute(x) }; assert_eq!(y, 42.0_f32); - // f32 casts + // f32-to-int casts assert_eq!(5.0f32 as u32, 5); assert_eq!(-5.0f32 as u32, 0); assert_eq!(5.0f32 as i32, 5); @@ -36,7 +36,7 @@ fn main() { assert_eq!((u32::MAX-127) as f32 as u32, u32::MAX); // rounding loss assert_eq!((u32::MAX-128) as f32 as u32, u32::MAX-255); // rounding loss - // f64 casts + // f64-to-int casts assert_eq!(5.0f64 as u64, 5); assert_eq!(-5.0f64 as u64, 0); assert_eq!(5.0f64 as i64, 5); @@ -55,6 +55,14 @@ fn main() { assert_eq!((u64::MAX-1023) as f64 as u64, u64::MAX); // rounding loss assert_eq!((u64::MAX-1024) as f64 as u64, u64::MAX-2047); // rounding loss + // f32 <-> f64 casts + assert_eq!(5.0f64 as f32, 5.0f32); + assert_eq!(5.0f32 as f64, 5.0f64); + assert_eq!(std::f64::MAX as f32, std::f32::INFINITY); + assert_eq!(std::f64::MIN as f32, std::f32::NEG_INFINITY); + assert_eq!(std::f32::INFINITY as f64, std::f64::INFINITY); + assert_eq!(std::f32::NEG_INFINITY as f64, std::f64::NEG_INFINITY); + // f32 min/max assert_eq!((1.0 as f32).max(-1.0), 1.0); assert_eq!((1.0 as f32).min(-1.0), -1.0); From b8a817fc03ada9a92df7fe916f1933f5b81f84af Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Mar 2020 09:20:07 +0100 Subject: [PATCH 1731/5092] avoid promotion so this can be compared with rustc --- tests/run-pass/floats.rs | 144 +++++++++++++++++++++------------------ 1 file changed, 78 insertions(+), 66 deletions(-) diff --git a/tests/run-pass/floats.rs b/tests/run-pass/floats.rs index 990745c85d67..5a7413e98ea8 100644 --- a/tests/run-pass/floats.rs +++ b/tests/run-pass/floats.rs @@ -1,9 +1,21 @@ +#![feature(track_caller)] +use std::fmt::Debug; + +// Helper function to avoid promotion so that this tests "run-time" casts, not CTFE. +// Doesn't make a big difference when running this in Miri, but when running this in +// rustc (with -Zmir-opt-level=0) for comparison it means we use LLVM casts. +#[track_caller] +#[inline(never)] +fn assert_eq(x: T, y: T) { + assert_eq!(x, y); +} + fn main() { // basic arithmetic - assert_eq!(6.0_f32*6.0_f32, 36.0_f32); - assert_eq!(6.0_f64*6.0_f64, 36.0_f64); - assert_eq!(-{5.0_f32}, -5.0_f32); - assert_eq!(-{5.0_f64}, -5.0_f64); + assert_eq(6.0_f32*6.0_f32, 36.0_f32); + assert_eq(6.0_f64*6.0_f64, 36.0_f64); + assert_eq(-{5.0_f32}, -5.0_f32); + assert_eq(-{5.0_f64}, -5.0_f64); // infinities, NaN assert!((5.0_f32/0.0).is_infinite()); assert!((5.0_f64/0.0).is_infinite()); @@ -12,84 +24,84 @@ fn main() { // byte-level transmute let x: u64 = unsafe { std::mem::transmute(42.0_f64) }; let y: f64 = unsafe { std::mem::transmute(x) }; - assert_eq!(y, 42.0_f64); + assert_eq(y, 42.0_f64); let x: u32 = unsafe { std::mem::transmute(42.0_f32) }; let y: f32 = unsafe { std::mem::transmute(x) }; - assert_eq!(y, 42.0_f32); + assert_eq(y, 42.0_f32); // f32-to-int casts - assert_eq!(5.0f32 as u32, 5); - assert_eq!(-5.0f32 as u32, 0); - assert_eq!(5.0f32 as i32, 5); - assert_eq!(-5.0f32 as i32, -5); - assert_eq!(std::f32::MAX as i32, i32::MAX); - assert_eq!(std::f32::INFINITY as i32, i32::MAX); - assert_eq!(std::f32::MAX as u32, u32::MAX); - assert_eq!(std::f32::INFINITY as u32, u32::MAX); - assert_eq!(std::f32::MIN as i32, i32::MIN); - assert_eq!(std::f32::NEG_INFINITY as i32, i32::MIN); - assert_eq!(std::f32::MIN as u32, 0); - assert_eq!(std::f32::NEG_INFINITY as u32, 0); - assert_eq!(std::f32::NAN as i32, 0); - assert_eq!(std::f32::NAN as u32, 0); - assert_eq!(u128::MAX as f32, std::f32::INFINITY); - assert_eq!((u32::MAX-127) as f32 as u32, u32::MAX); // rounding loss - assert_eq!((u32::MAX-128) as f32 as u32, u32::MAX-255); // rounding loss + assert_eq(5.0f32 as u32, 5); + assert_eq(-5.0f32 as u32, 0); + assert_eq(5.0f32 as i32, 5); + assert_eq(-5.0f32 as i32, -5); + assert_eq(std::f32::MAX as i32, i32::MAX); + assert_eq(std::f32::INFINITY as i32, i32::MAX); + assert_eq(std::f32::MAX as u32, u32::MAX); + assert_eq(std::f32::INFINITY as u32, u32::MAX); + assert_eq(std::f32::MIN as i32, i32::MIN); + assert_eq(std::f32::NEG_INFINITY as i32, i32::MIN); + assert_eq(std::f32::MIN as u32, 0); + assert_eq(std::f32::NEG_INFINITY as u32, 0); + assert_eq(std::f32::NAN as i32, 0); + assert_eq(std::f32::NAN as u32, 0); + assert_eq(u128::MAX as f32, std::f32::INFINITY); + assert_eq((u32::MAX-127) as f32 as u32, u32::MAX); // rounding loss + assert_eq((u32::MAX-128) as f32 as u32, u32::MAX-255); // rounding loss // f64-to-int casts - assert_eq!(5.0f64 as u64, 5); - assert_eq!(-5.0f64 as u64, 0); - assert_eq!(5.0f64 as i64, 5); - assert_eq!(-5.0f64 as i64, -5); - assert_eq!(std::f64::MAX as i64, i64::MAX); - assert_eq!(std::f64::INFINITY as i64, i64::MAX); - assert_eq!(std::f64::MAX as u64, u64::MAX); - assert_eq!(std::f64::INFINITY as u64, u64::MAX); - assert_eq!(std::f64::MIN as i64, i64::MIN); - assert_eq!(std::f64::NEG_INFINITY as i64, i64::MIN); - assert_eq!(std::f64::MIN as u64, 0); - assert_eq!(std::f64::NEG_INFINITY as u64, 0); - assert_eq!(std::f64::NAN as i64, 0); - assert_eq!(std::f64::NAN as u64, 0); - assert_eq!(u128::MAX as f64 as u128, u128::MAX); - assert_eq!((u64::MAX-1023) as f64 as u64, u64::MAX); // rounding loss - assert_eq!((u64::MAX-1024) as f64 as u64, u64::MAX-2047); // rounding loss + assert_eq(5.0f64 as u64, 5); + assert_eq(-5.0f64 as u64, 0); + assert_eq(5.0f64 as i64, 5); + assert_eq(-5.0f64 as i64, -5); + assert_eq(std::f64::MAX as i64, i64::MAX); + assert_eq(std::f64::INFINITY as i64, i64::MAX); + assert_eq(std::f64::MAX as u64, u64::MAX); + assert_eq(std::f64::INFINITY as u64, u64::MAX); + assert_eq(std::f64::MIN as i64, i64::MIN); + assert_eq(std::f64::NEG_INFINITY as i64, i64::MIN); + assert_eq(std::f64::MIN as u64, 0); + assert_eq(std::f64::NEG_INFINITY as u64, 0); + assert_eq(std::f64::NAN as i64, 0); + assert_eq(std::f64::NAN as u64, 0); + assert_eq(u128::MAX as f64 as u128, u128::MAX); + assert_eq((u64::MAX-1023) as f64 as u64, u64::MAX); // rounding loss + assert_eq((u64::MAX-1024) as f64 as u64, u64::MAX-2047); // rounding loss // f32 <-> f64 casts - assert_eq!(5.0f64 as f32, 5.0f32); - assert_eq!(5.0f32 as f64, 5.0f64); - assert_eq!(std::f64::MAX as f32, std::f32::INFINITY); - assert_eq!(std::f64::MIN as f32, std::f32::NEG_INFINITY); - assert_eq!(std::f32::INFINITY as f64, std::f64::INFINITY); - assert_eq!(std::f32::NEG_INFINITY as f64, std::f64::NEG_INFINITY); + assert_eq(5.0f64 as f32, 5.0f32); + assert_eq(5.0f32 as f64, 5.0f64); + assert_eq(std::f64::MAX as f32, std::f32::INFINITY); + assert_eq(std::f64::MIN as f32, std::f32::NEG_INFINITY); + assert_eq(std::f32::INFINITY as f64, std::f64::INFINITY); + assert_eq(std::f32::NEG_INFINITY as f64, std::f64::NEG_INFINITY); // f32 min/max - assert_eq!((1.0 as f32).max(-1.0), 1.0); - assert_eq!((1.0 as f32).min(-1.0), -1.0); - assert_eq!(std::f32::NAN.min(9.0), 9.0); - assert_eq!(std::f32::NAN.max(-9.0), -9.0); - assert_eq!((9.0 as f32).min(std::f32::NAN), 9.0); - assert_eq!((-9.0 as f32).max(std::f32::NAN), -9.0); + assert_eq((1.0 as f32).max(-1.0), 1.0); + assert_eq((1.0 as f32).min(-1.0), -1.0); + assert_eq(std::f32::NAN.min(9.0), 9.0); + assert_eq(std::f32::NAN.max(-9.0), -9.0); + assert_eq((9.0 as f32).min(std::f32::NAN), 9.0); + assert_eq((-9.0 as f32).max(std::f32::NAN), -9.0); // f64 min/max - assert_eq!((1.0 as f64).max(-1.0), 1.0); - assert_eq!((1.0 as f64).min(-1.0), -1.0); - assert_eq!(std::f64::NAN.min(9.0), 9.0); - assert_eq!(std::f64::NAN.max(-9.0), -9.0); - assert_eq!((9.0 as f64).min(std::f64::NAN), 9.0); - assert_eq!((-9.0 as f64).max(std::f64::NAN), -9.0); + assert_eq((1.0 as f64).max(-1.0), 1.0); + assert_eq((1.0 as f64).min(-1.0), -1.0); + assert_eq(std::f64::NAN.min(9.0), 9.0); + assert_eq(std::f64::NAN.max(-9.0), -9.0); + assert_eq((9.0 as f64).min(std::f64::NAN), 9.0); + assert_eq((-9.0 as f64).max(std::f64::NAN), -9.0); // f32 copysign - assert_eq!(3.5_f32.copysign(0.42), 3.5_f32); - assert_eq!(3.5_f32.copysign(-0.42), -3.5_f32); - assert_eq!((-3.5_f32).copysign(0.42), 3.5_f32); - assert_eq!((-3.5_f32).copysign(-0.42), -3.5_f32); + assert_eq(3.5_f32.copysign(0.42), 3.5_f32); + assert_eq(3.5_f32.copysign(-0.42), -3.5_f32); + assert_eq((-3.5_f32).copysign(0.42), 3.5_f32); + assert_eq((-3.5_f32).copysign(-0.42), -3.5_f32); assert!(std::f32::NAN.copysign(1.0).is_nan()); // f64 copysign - assert_eq!(3.5_f64.copysign(0.42), 3.5_f64); - assert_eq!(3.5_f64.copysign(-0.42), -3.5_f64); - assert_eq!((-3.5_f64).copysign(0.42), 3.5_f64); - assert_eq!((-3.5_f64).copysign(-0.42), -3.5_f64); + assert_eq(3.5_f64.copysign(0.42), 3.5_f64); + assert_eq(3.5_f64.copysign(-0.42), -3.5_f64); + assert_eq((-3.5_f64).copysign(0.42), 3.5_f64); + assert_eq((-3.5_f64).copysign(-0.42), -3.5_f64); assert!(std::f64::NAN.copysign(1.0).is_nan()); } From 02897e03cfe6b04d28c0f3197563d1dba3f7658d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Mar 2020 09:50:24 +0100 Subject: [PATCH 1732/5092] cleanup tcx usage and a few comments --- src/shims/foreign_items.rs | 6 +++--- src/shims/foreign_items/posix.rs | 5 ++--- src/shims/foreign_items/windows.rs | 3 +-- src/shims/intrinsics.rs | 3 +-- src/shims/tls.rs | 7 +++++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 6827b72427fb..0bed688187b0 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -124,7 +124,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Strip linker suffixes (seen on 32-bit macOS). let link_name = link_name.trim_end_matches("$UNIX2003"); - let tcx = &{ this.tcx.tcx }; + let tcx = this.tcx.tcx; // First: functions that diverge. let (dest, ret) = match ret { @@ -133,8 +133,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // The implementation is provided by the function with the `#[panic_handler]` attribute. "panic_impl" => { this.check_panic_supported()?; - let panic_impl_id = this.tcx.lang_items().panic_impl().unwrap(); - let panic_impl_instance = ty::Instance::mono(*this.tcx, panic_impl_id); + let panic_impl_id = tcx.lang_items().panic_impl().unwrap(); + let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id); return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); } | "exit" diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 85e9b88b6ec0..425fe4b1b479 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -17,7 +17,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ret: mir::BasicBlock, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - let tcx = &{ this.tcx.tcx }; match link_name { // Environment related shims @@ -65,7 +64,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "write" => { let fd = this.read_scalar(args[0])?.to_i32()?; let buf = this.read_scalar(args[1])?.not_undef()?; - let n = this.read_scalar(args[2])?.to_machine_usize(tcx)?; + let n = this.read_scalar(args[2])?.to_machine_usize(this)?; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { // stdout/stderr @@ -209,7 +208,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "pthread_getspecific" => { let key = this.force_bits(this.read_scalar(args[0])?.not_undef()?, args[0].layout.size)?; - let ptr = this.machine.tls.load_tls(key, tcx)?; + let ptr = this.machine.tls.load_tls(key, this)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index a64ef0f12935..9e71ba7d9074 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -13,7 +13,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ret: mir::BasicBlock, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - let tcx = &{ this.tcx.tcx }; match link_name { // Windows API stubs. @@ -160,7 +159,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "TlsGetValue" => { let key = u128::from(this.read_scalar(args[0])?.to_u32()?); - let ptr = this.machine.tls.load_tls(key, tcx)?; + let ptr = this.machine.tls.load_tls(key, this)?; this.write_scalar(ptr, dest)?; } "TlsSetValue" => { diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 91371e2c9df9..84e8cca556a1 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -24,13 +24,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.emulate_intrinsic(span, instance, args, ret)? { return Ok(()); } - let tcx = &{ this.tcx.tcx }; let substs = instance.substs; // All these intrinsics take raw pointers, so if we access memory directly // (as opposed to through a place), we have to remember to erase any tag // that might still hang around! - let intrinsic_name = &*tcx.item_name(instance.def_id()).as_str(); + let intrinsic_name = &*this.tcx.item_name(instance.def_id()).as_str(); // First handle intrinsics without return place. let (dest, ret) = match ret { diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 6635978cb2e3..461b5b3eed6a 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -70,7 +70,7 @@ impl<'tcx> TlsData<'tcx> { } pub fn load_tls( - &mut self, + &self, key: TlsKey, cx: &impl HasDataLayout, ) -> InterpResult<'tcx, Scalar> { @@ -107,7 +107,8 @@ impl<'tcx> TlsData<'tcx> { Ok(()) } - /// Returns a dtor, its argument and its index, if one is supposed to run + /// Returns a dtor, its argument and its index, if one is supposed to run. + /// `key` is the last dtors that was run; we return the *next* one after that. /// /// An optional destructor function may be associated with each key value. /// At thread exit, if a key value has a non-NULL destructor pointer, @@ -191,8 +192,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // step until out of stackframes this.run()?; + // Fetch next dtor after `key`. dtor = match this.machine.tls.fetch_tls_dtor(Some(key)) { dtor @ Some(_) => dtor, + // We ran each dtor once, start over from the beginning. None => this.machine.tls.fetch_tls_dtor(None), }; } From f7516883968322aa03e41dfb8cdd80719ea5ea13 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Mar 2020 10:29:05 +0100 Subject: [PATCH 1733/5092] miri build script: use incremental builds --- miri | 1 + 1 file changed, 1 insertion(+) diff --git a/miri b/miri index 47ff5024fc63..0cda9e80926e 100755 --- a/miri +++ b/miri @@ -49,6 +49,7 @@ fi # We enable debug-assertions to get tracing. # We enable line-only debuginfo for backtraces. export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR -C debug-assertions -C debuginfo=1 $RUSTC_EXTRA_FLAGS" +export CARGO_INCREMENTAL=1 ## Helper functions From 876bded2e8d5fe0dc3b084c3e9faa2739493d797 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Mar 2020 10:07:23 +0100 Subject: [PATCH 1734/5092] run Windows TLS dtor function --- src/eval.rs | 7 +++---- src/helpers.rs | 2 +- src/machine.rs | 34 ++++++++++++++++++++++++---------- src/shims/foreign_items.rs | 2 +- src/shims/tls.rs | 27 ++++++++++++++++++++++++++- 5 files changed, 55 insertions(+), 17 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 7f07fc1a7db6..512b4176df8b 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -184,10 +184,9 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( /// Returns `Some(return_code)` if program executed completed. /// Returns `None` if an evaluation error occured. pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option { - // FIXME: We always ignore leaks on some OSs where we do not - // correctly implement TLS destructors. - let target_os = &tcx.sess.target.target.target_os; - let ignore_leaks = config.ignore_leaks || target_os == "windows"; + // FIXME: on Windows, locks and TLS dtor management allocate and leave that memory in `static`s. + // So we need https://github.com/rust-lang/miri/issues/940 to fix the leaks there. + let ignore_leaks = config.ignore_leaks || tcx.sess.target.target.target_os == "windows"; let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) { Ok(v) => v, diff --git a/src/helpers.rs b/src/helpers.rs index 3e89fdf6f3cc..aa327b468bf8 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -413,7 +413,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn set_last_error_from_io_error(&mut self, e: std::io::Error) -> InterpResult<'tcx> { use std::io::ErrorKind::*; let this = self.eval_context_mut(); - let target = &this.tcx.tcx.sess.target.target; + let target = &this.tcx.sess.target.target; let last_error = if target.options.target_family == Some("unix".to_owned()) { this.eval_libc(match e.kind() { ConnectionRefused => "ECONNREFUSED", diff --git a/src/machine.rs b/src/machine.rs index 73e7ce665b85..4bf3d0d7f446 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -102,6 +102,20 @@ impl MemoryExtra { } } + fn add_extern_static<'tcx, 'mir>( + this: &mut MiriEvalContext<'mir, 'tcx>, + name: &str, + ptr: Scalar, + ) { + let ptr = ptr.assert_ptr(); + assert_eq!(ptr.offset, Size::ZERO); + this.memory + .extra + .extern_statics + .insert(Symbol::intern(name), ptr.alloc_id) + .unwrap_none(); + } + /// Sets up the "extern statics" for this machine. pub fn init_extern_statics<'tcx, 'mir>( this: &mut MiriEvalContext<'mir, 'tcx>, @@ -113,17 +127,17 @@ impl MemoryExtra { let layout = this.layout_of(this.tcx.types.usize)?; let place = this.allocate(layout, MiriMemoryKind::Machine.into()); this.write_scalar(Scalar::from_machine_usize(0, &*this.tcx), place.into())?; - this.memory - .extra - .extern_statics - .insert(Symbol::intern("__cxa_thread_atexit_impl"), place.ptr.assert_ptr().alloc_id) - .unwrap_none(); + Self::add_extern_static(this, "__cxa_thread_atexit_impl", place.ptr); // "environ" - this.memory - .extra - .extern_statics - .insert(Symbol::intern("environ"), this.machine.env_vars.environ.unwrap().ptr.assert_ptr().alloc_id) - .unwrap_none(); + Self::add_extern_static(this, "environ", this.machine.env_vars.environ.unwrap().ptr); + } + "windows" => { + // "_tls_used" + // This is some obscure hack that is part of the Windows TLS story. It's a `u8`. + let layout = this.layout_of(this.tcx.types.u8)?; + let place = this.allocate(layout, MiriMemoryKind::Machine.into()); + this.write_scalar(Scalar::from_u8(0), place.into())?; + Self::add_extern_static(this, "_tls_used", place.ptr); } _ => {} // No "extern statics" supported on this target } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 0bed688187b0..ecf24e2f2038 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -19,7 +19,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn min_align(&self, size: u64, kind: MiriMemoryKind) -> Align { let this = self.eval_context_ref(); // List taken from `libstd/sys_common/alloc.rs`. - let min_align = match this.tcx.tcx.sess.target.target.arch.as_str() { + let min_align = match this.tcx.sess.target.target.arch.as_str() { "x86" | "arm" | "mips" | "powerpc" | "powerpc64" | "asmjs" | "wasm32" => 8, "x86_64" | "aarch64" | "mips64" | "s390x" | "sparc64" => 16, arch => bug!("Unsupported target architecture: {}", arch), diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 461b5b3eed6a..c753689f4c25 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -159,6 +159,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert!(!this.machine.tls.dtors_running, "running TLS dtors twice"); this.machine.tls.dtors_running = true; + if this.tcx.sess.target.target.target_os == "windows" { + // Windows has a special magic linker section that is run on certain events. + // Instead of searching for that section and supporting arbitrary hooks in there + // (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. + let thread_callback = this.eval_path_scalar(&["std", "sys", "windows", "thread_local", "p_thread_callback"])?; + let thread_callback = this.memory.get_fn(thread_callback.not_undef()?)?.as_instance()?; + + // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. + let reason = this.eval_path_scalar(&["std", "sys", "windows", "c", "DLL_PROCESS_DETACH"])?; + let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); + this.call_function( + thread_callback, + &[Scalar::ptr_null(this).into(), reason.into(), Scalar::ptr_null(this).into()], + Some(ret_place), + StackPopCleanup::None { cleanup: true }, + )?; + + // step until out of stackframes + this.run()?; + + // Windows doesn't have other destructors. + return Ok(()); + } + // The macOS global dtor runs "before any TLS slots get freed", so do that first. if let Some((instance, data)) = this.machine.tls.global_dtor { trace!("Running global dtor {:?} on {:?}", instance, data); @@ -199,7 +225,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx None => this.machine.tls.fetch_tls_dtor(None), }; } - // FIXME: On a windows target, call `unsafe extern "system" fn on_tls_callback`. Ok(()) } } From 204c13b8c724b208b8e26148ba21087b543e960b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Mar 2020 11:06:56 +0100 Subject: [PATCH 1735/5092] env shim: make sure we clean up all the memory we allocate --- src/eval.rs | 5 +++++ src/lib.rs | 2 ++ src/machine.rs | 8 ++++++-- src/shims/env.rs | 37 ++++++++++++++++++++++++++----------- src/stacked_borrows.rs | 4 +++- 5 files changed, 42 insertions(+), 14 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 7f07fc1a7db6..d6e5162edaec 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -199,16 +199,21 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> // Perform the main execution. let res: InterpResult<'_, i64> = (|| { + // Main loop. while ecx.step()? { ecx.process_diagnostics(); } // Read the return code pointer *before* we run TLS destructors, to assert // that it was written to by the time that `start` lang item returned. let return_code = ecx.read_scalar(ret_place.into())?.not_undef()?.to_machine_isize(&ecx)?; + // Global destructors. ecx.run_tls_dtors()?; Ok(return_code) })(); + // Machine cleanup. + EnvVars::cleanup(&mut ecx).unwrap(); + // Process the result. match res { Ok(return_code) => { diff --git a/src/lib.rs b/src/lib.rs index 32eb5b41e591..0d93becb4482 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,8 @@ #![feature(option_expect_none, option_unwrap_none)] #![feature(map_first_last)] #![feature(never_type)] +#![feature(or_patterns)] + #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] diff --git a/src/machine.rs b/src/machine.rs index 73e7ce665b85..a530ef66d384 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -48,9 +48,13 @@ pub enum MiriMemoryKind { C, /// Windows `HeapAlloc` memory. WinHeap, - /// Memory for env vars and args, errno, extern statics and other parts of the machine-managed environment. + /// Memory for args, errno, extern statics and other parts of the machine-managed environment. + /// This memory may leak. Machine, + /// Memory for env vars. Separate from `Machine` because we clean it up and leak-check it. + Env, /// Globals copied from `tcx`. + /// This memory may leak. Global, } @@ -484,7 +488,7 @@ impl MayLeak for MiriMemoryKind { fn may_leak(self) -> bool { use self::MiriMemoryKind::*; match self { - Rust | C | WinHeap => false, + Rust | C | WinHeap | Env => false, Machine | Global => true, } } diff --git a/src/shims/env.rs b/src/shims/env.rs index ed689b1f4272..6cde82903bcc 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -46,6 +46,20 @@ impl<'tcx> EnvVars<'tcx> { } ecx.update_environ() } + + pub(crate) fn cleanup<'mir>( + ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, + ) -> InterpResult<'tcx> { + // Deallocate individual env vars. + for (_name, ptr) in ecx.machine.env_vars.map.drain() { + ecx.memory.deallocate(ptr, None, MiriMemoryKind::Env.into())?; + } + // Deallocate environ var list. + let environ = ecx.machine.env_vars.environ.take().unwrap(); + let old_vars_ptr = ecx.read_scalar(environ.into())?.not_undef()?; + ecx.memory.deallocate(ecx.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Env.into())?; + Ok(()) + } } fn alloc_env_var_as_c_str<'mir, 'tcx>( @@ -56,7 +70,7 @@ fn alloc_env_var_as_c_str<'mir, 'tcx>( let mut name_osstring = name.to_os_string(); name_osstring.push("="); name_osstring.push(value); - Ok(ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into())) + Ok(ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Env.into())) } fn alloc_env_var_as_wide_str<'mir, 'tcx>( @@ -67,7 +81,7 @@ fn alloc_env_var_as_wide_str<'mir, 'tcx>( let mut name_osstring = name.to_os_string(); name_osstring.push("="); name_osstring.push(value); - Ok(ecx.alloc_os_str_as_wide_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into())) + Ok(ecx.alloc_os_str_as_wide_str(name_osstring.as_os_str(), MiriMemoryKind::Env.into())) } impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -146,7 +160,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Allocate environment block & Store environment variables to environment block. // Final null terminator(block terminator) is added by `alloc_os_str_to_wide_str`. - // FIXME: MemoryKind should be `Machine`, blocked on https://github.com/rust-lang/rust/pull/70479. + // FIXME: MemoryKind should be `Env`, blocked on https://github.com/rust-lang/rust/pull/70479. let envblock_ptr = this.alloc_os_str_as_wide_str(&env_vars, MiriMemoryKind::WinHeap.into()); // If the function succeeds, the return value is a pointer to the environment block of the current process. Ok(envblock_ptr.into()) @@ -158,7 +172,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.assert_target_os("windows", "FreeEnvironmentStringsW"); let env_block_ptr = this.read_scalar(env_block_op)?.not_undef()?; - // FIXME: MemoryKind should be `Machine`, blocked on https://github.com/rust-lang/rust/pull/70479. + // FIXME: MemoryKind should be `Env`, blocked on https://github.com/rust-lang/rust/pull/70479. let result = this.memory.deallocate(this.force_ptr(env_block_ptr)?, None, MiriMemoryKind::WinHeap.into()); // If the function succeeds, the return value is nonzero. Ok(result.is_ok() as i32) @@ -188,7 +202,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let var_ptr = alloc_env_var_as_c_str(&name, &value, &mut this)?; if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { this.memory - .deallocate(var, None, MiriMemoryKind::Machine.into())?; + .deallocate(var, None, MiriMemoryKind::Env.into())?; } this.update_environ()?; Ok(0) // return zero on success @@ -225,7 +239,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if this.is_null(value_ptr)? { // Delete environment variable `{name}` if let Some(var) = this.machine.env_vars.map.remove(&name) { - this.memory.deallocate(var, None, MiriMemoryKind::Machine.into())?; + this.memory.deallocate(var, None, MiriMemoryKind::Env.into())?; this.update_environ()?; } Ok(1) // return non-zero on success @@ -234,7 +248,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let var_ptr = alloc_env_var_as_wide_str(&name, &value, &mut this)?; if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { this.memory - .deallocate(var, None, MiriMemoryKind::Machine.into())?; + .deallocate(var, None, MiriMemoryKind::Env.into())?; } this.update_environ()?; Ok(1) // return non-zero on success @@ -257,7 +271,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(old) = success { if let Some(var) = old { this.memory - .deallocate(var, None, MiriMemoryKind::Machine.into())?; + .deallocate(var, None, MiriMemoryKind::Env.into())?; } this.update_environ()?; Ok(0) @@ -314,12 +328,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// The first time it gets called, also initializes `extra.environ`. fn update_environ(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - // Deallocate the old environ value, if any. + // Deallocate the old environ list, if any. if let Some(environ) = this.machine.env_vars.environ { let old_vars_ptr = this.read_scalar(environ.into())?.not_undef()?; - this.memory.deallocate(this.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Machine.into())?; + this.memory.deallocate(this.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Env.into())?; } else { // No `environ` allocated yet, let's do that. + // This is memory backing an extern static, hence `Machine`, not `Env`. let layout = this.layout_of(this.tcx.types.usize)?; let place = this.allocate(layout, MiriMemoryKind::Machine.into()); this.write_scalar(Scalar::from_machine_usize(0, &*this.tcx), place.into())?; @@ -334,7 +349,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tcx = this.tcx; let vars_layout = this.layout_of(tcx.mk_array(tcx.types.usize, u64::try_from(vars.len()).unwrap()))?; - let vars_place = this.allocate(vars_layout, MiriMemoryKind::Machine.into()); + let vars_place = this.allocate(vars_layout, MiriMemoryKind::Env.into()); for (idx, var) in vars.into_iter().enumerate() { let place = this.mplace_field(vars_place, idx)?; this.write_scalar(var, place.into())?; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 11b6cdca579a..c130abf0576b 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -460,8 +460,10 @@ impl Stacks { // Global memory can be referenced by global pointers from `tcx`. // Thus we call `global_base_ptr` such that the global pointers get the same tag // as what we use here. + // `Machine` is used for extern statics, and thus must also be listed here. + // `Env` we list because we can get away with precise tracking there. // The base pointer is not unique, so the base permission is `SharedReadWrite`. - MemoryKind::Machine(MiriMemoryKind::Global) | MemoryKind::Machine(MiriMemoryKind::Machine) => + MemoryKind::Machine(MiriMemoryKind::Global | MiriMemoryKind::Machine | MiriMemoryKind::Env) => (extra.borrow_mut().global_base_ptr(id), Permission::SharedReadWrite), // Everything else we handle entirely untagged for now. // FIXME: experiment with more precise tracking. From 9e39bfbbd93a98980fd2371970cc1005420d66df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Mar 2020 11:41:31 +0100 Subject: [PATCH 1736/5092] organize shims and make some only available to libstd as they are incomplete --- src/helpers.rs | 1 + src/shims/foreign_items.rs | 17 +-- src/shims/foreign_items/posix.rs | 153 ++++++++++--------------- src/shims/foreign_items/posix/linux.rs | 56 ++++++--- src/shims/foreign_items/posix/macos.rs | 53 ++++----- src/shims/foreign_items/windows.rs | 115 +++++++++++-------- 6 files changed, 196 insertions(+), 199 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index aa327b468bf8..8e379065b07e 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -81,6 +81,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function to get a `libc` constant as an `i32`. fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { + // TODO: Cache the result. self.eval_libc(name)?.to_i32() } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index ecf24e2f2038..c92e338ef7e0 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -196,6 +196,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Here we dispatch all the shims for foreign functions. If you have a platform specific // shim, add it to the corresponding submodule. match link_name { + // Standard C allocation "malloc" => { let size = this.read_scalar(args[0])?.to_machine_usize(this)?; let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C); @@ -220,6 +221,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } + // Rust allocation + // (Usually these would be forwarded to to `#[global_allocator]`; we instead implement a generic + // allocation that also checks that all conditions are met, such as not permitting zero-sized allocations.) "__rust_alloc" => { let size = this.read_scalar(args[0])?.to_machine_usize(this)?; let align = this.read_scalar(args[1])?.to_machine_usize(this)?; @@ -274,6 +278,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(new_ptr, dest)?; } + // C memory handling functions "memcmp" => { let left = this.read_scalar(args[0])?.not_undef()?; let right = this.read_scalar(args[1])?.not_undef()?; @@ -293,7 +298,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, Size::from_bits(32)), dest)?; } - "memrchr" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let val = this.read_scalar(args[1])?.to_i32()? as u8; @@ -311,7 +315,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } } - "memchr" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let val = this.read_scalar(args[1])?.to_i32()? as u8; @@ -328,7 +331,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } } - "strlen" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let n = this.memory.read_c_str(ptr)?.len(); @@ -358,11 +360,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?; } - // underscore case for windows | "_hypotf" | "hypotf" | "atan2f" => { + // underscore case for windows, here and below + // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) // FIXME: Using host floats. let f1 = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); let f2 = f32::from_bits(this.read_scalar(args[1])?.to_u32()?); @@ -373,7 +376,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; this.write_scalar(Scalar::from_u32(n.to_bits()), dest)?; } - | "cbrt" | "cosh" | "sinh" @@ -396,8 +398,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; this.write_scalar(Scalar::from_u64(f.to_bits()), dest)?; } - // underscore case for windows, here and below - // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) | "_hypot" | "hypot" | "atan2" @@ -412,11 +412,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?; } - // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. | "_ldexp" | "ldexp" | "scalbn" => { + // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. let x = this.read_scalar(args[0])?.to_f64()?; let exp = this.read_scalar(args[1])?.to_i32()?; @@ -434,6 +434,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_f64(res), dest)?; } + // Target-specific shims _ => match this.tcx.sess.target.target.target_os.as_str() { "linux" | "macos" => return posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), "windows" => return windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 425fe4b1b479..9d331eece503 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -24,22 +24,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.getenv(args[0])?; this.write_scalar(result, dest)?; } - "unsetenv" => { let result = this.unsetenv(args[0])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "setenv" => { let result = this.setenv(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "getcwd" => { let result = this.getcwd(args[0], args[1])?; this.write_scalar(result, dest)?; } - "chdir" => { let result = this.chdir(args[0])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; @@ -50,17 +46,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.open(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "fcntl" => { let result = this.fcntl(args[0], args[1], args.get(2).cloned())?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "read" => { let result = this.read(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "write" => { let fd = this.read_scalar(args[0])?.to_i32()?; let buf = this.read_scalar(args[1])?.not_undef()?; @@ -94,43 +87,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Now, `result` is the value we return back to the program. this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "unlink" => { let result = this.unlink(args[0])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "symlink" => { let result = this.symlink(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "rename" => { let result = this.rename(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "mkdir" => { let result = this.mkdir(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "rmdir" => { let result = this.rmdir(args[0])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "closedir" => { let result = this.closedir(args[0])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "lseek" | "lseek64" => { let result = this.lseek64(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "posix_fadvise" => { + // fadvise is only informational, we can ignore it. + this.write_null(dest)?; + } - // Other shims + // Allocation "posix_memalign" => { let ret = this.deref_operand(args[0])?; let align = this.read_scalar(args[1])?.to_machine_usize(this)?; @@ -159,6 +149,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } + // Dynamic symbol loading "dlsym" => { let _handle = this.read_scalar(args[0])?; let symbol = this.read_scalar(args[1])?.not_undef()?; @@ -173,7 +164,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - // Hook pthread calls that go to the thread-local storage memory subsystem. + // Querying system information + "sysconf" => { + let name = this.read_scalar(args[0])?.to_i32()?; + + let sysconfs = &[ + ("_SC_PAGESIZE", Scalar::from_int(PAGE_SIZE, dest.layout.size)), + ("_SC_NPROCESSORS_ONLN", Scalar::from_int(NUM_CPUS, dest.layout.size)), + ]; + let mut result = None; + for &(sysconf_name, value) in sysconfs { + let sysconf_name = this.eval_libc_i32(sysconf_name)?; + if sysconf_name == name { + result = Some(value); + break; + } + } + if let Some(result) = result { + this.write_scalar(result, dest)?; + } else { + throw_unsup_format!("unimplemented sysconf name: {}", name) + } + } + + // Thread-local storage "pthread_key_create" => { let key_place = this.deref_operand(args[0])?; @@ -220,36 +234,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - // Stack size/address stuff. - | "pthread_attr_init" - | "pthread_attr_destroy" - | "pthread_self" - | "pthread_attr_setstacksize" => { - this.write_null(dest)?; - } - "pthread_attr_getstack" => { - let addr_place = this.deref_operand(args[1])?; - let size_place = this.deref_operand(args[2])?; - - this.write_scalar( - Scalar::from_uint(STACK_ADDR, addr_place.layout.size), - addr_place.into(), - )?; - this.write_scalar( - Scalar::from_uint(STACK_SIZE, size_place.layout.size), - size_place.into(), - )?; - - // Return success (`0`). - this.write_null(dest)?; - } - - // We don't support threading. + // Better error for attempts to create a thread "pthread_create" => { throw_unsup_format!("Miri does not support threading"); } - // Stub out calls for condvar, mutex and rwlock, to just return `0`. + // Miscellaneous + "isatty" => { + let _fd = this.read_scalar(args[0])?.to_i32()?; + // "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error" + // FIXME: we just say nothing is a terminal. + let enotty = this.eval_libc("ENOTTY")?; + this.set_last_error(enotty)?; + this.write_null(dest)?; + } + "pthread_atfork" => { + let _prepare = this.read_scalar(args[0])?.not_undef()?; + let _parent = this.read_scalar(args[1])?.not_undef()?; + let _child = this.read_scalar(args[1])?.not_undef()?; + // We do not support forking, so there is nothing to do here. + this.write_null(dest)?; + } + + // Incomplete shims that we "stub out" just to get pre-main initialziation code to work. + // These shims are enabled only when the caller is in the standard library. + | "pthread_attr_init" + | "pthread_attr_destroy" + | "pthread_self" + | "pthread_attr_setstacksize" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + this.write_null(dest)?; + } | "pthread_mutexattr_init" | "pthread_mutexattr_settype" | "pthread_mutex_init" @@ -265,68 +279,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "pthread_condattr_setclock" | "pthread_cond_init" | "pthread_condattr_destroy" - | "pthread_cond_destroy" + | "pthread_cond_destroy" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { this.write_null(dest)?; } - - // We don't support fork so we don't have to do anything for atfork. - "pthread_atfork" => { - this.write_null(dest)?; - } - - // Some things needed for `sys::thread` initialization to go through. | "signal" | "sigaction" | "sigaltstack" + | "mprotect" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - this.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?; - } - - "sysconf" => { - let name = this.read_scalar(args[0])?.to_i32()?; - - trace!("sysconf() called with name {}", name); - // TODO: Cache the sysconf integers via Miri's global cache. - let sysconfs = &[ - ("_SC_PAGESIZE", Scalar::from_int(PAGE_SIZE, dest.layout.size)), - ("_SC_GETPW_R_SIZE_MAX", Scalar::from_int(-1, dest.layout.size)), - ("_SC_NPROCESSORS_ONLN", Scalar::from_int(NUM_CPUS, dest.layout.size)), - ]; - let mut result = None; - for &(sysconf_name, value) in sysconfs { - let sysconf_name = this.eval_libc_i32(sysconf_name)?; - if sysconf_name == name { - result = Some(value); - break; - } - } - if let Some(result) = result { - this.write_scalar(result, dest)?; - } else { - throw_unsup_format!("unimplemented sysconf name: {}", name) - } - } - - "isatty" => { - this.write_null(dest)?; - } - - "posix_fadvise" => { - // fadvise is only informational, we can ignore it. - this.write_null(dest)?; - } - - "mmap" => { - // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. - let addr = this.read_scalar(args[0])?.not_undef()?; - this.write_scalar(addr, dest)?; - } - - "mprotect" => { this.write_null(dest)?; } + // Platform-specific shims _ => { match this.tcx.sess.target.target.target_os.as_str() { "linux" => return linux::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 82928c9bc17f..1a8cd195ec5b 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -13,47 +13,56 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); match link_name { + // errno "__errno_location" => { let errno_place = this.machine.last_error.unwrap(); this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } // File related shims (but also see "syscall" below for statx) - - // The only reason this is not in the `posix` module is because the `macos` item has a - // different name. + // These symbols have different names on Linux and macOS, which is the only reason they are not + // in the `posix` module. "close" => { let result = this.close(args[0])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - - // The only reason this is not in the `posix` module is because the `macos` item has a - // different name. "opendir" => { let result = this.opendir(args[0])?; this.write_scalar(result, dest)?; } - - // The `macos` module has a parallel foreign item, `readdir_r`, which uses a different - // struct layout. "readdir64_r" => { let result = this.linux_readdir64_r(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } // Time related shims - - // This is a POSIX function but it has only been tested on linux. "clock_gettime" => { + // This is a POSIX function but it has only been tested on linux. let result = this.clock_gettime(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - // Other shims - "pthread_getattr_np" => { + // Querying system information + "pthread_attr_getstack" => { + // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. + let _attr_place = this.deref_operand(args[0])?; + let addr_place = this.deref_operand(args[1])?; + let size_place = this.deref_operand(args[2])?; + + this.write_scalar( + Scalar::from_uint(STACK_ADDR, addr_place.layout.size), + addr_place.into(), + )?; + this.write_scalar( + Scalar::from_uint(STACK_SIZE, size_place.layout.size), + size_place.into(), + )?; + + // Return success (`0`). this.write_null(dest)?; } + // Dynamically invoked syscalls "syscall" => { let sys_getrandom = this .eval_libc("SYS_getrandom")? @@ -67,15 +76,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` // is called if a `HashMap` is created the regular way (e.g. HashMap). id if id == sys_getrandom => { - // The first argument is the syscall id, - // so skip over it. + // The first argument is the syscall id, so skip over it. getrandom(this, &args[1..], dest)?; } // `statx` is used by `libstd` to retrieve metadata information on `linux` // instead of using `stat`,`lstat` or `fstat` as on `macos`. id if id == sys_statx => { - // The first argument is the syscall id, - // so skip over it. + // The first argument is the syscall id, so skip over it. let result = this.linux_statx(args[1], args[2], args[3], args[4], args[5])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } @@ -83,15 +90,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + // Miscelanneous "getrandom" => { getrandom(this, args, dest)?; } - "sched_getaffinity" => { - // Return an error; `num_cpus` then falls back to `sysconf`. + let _pid = this.read_scalar(args[0])?.to_i32()?; + let _cpusetsize = this.read_scalar(args[1])?.to_machine_usize(this)?; + let _mask = this.deref_operand(args[2])?; + // FIXME: we just return an error; `num_cpus` then falls back to `sysconf`. + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; } + // Incomplete shims that we "stub out" just to get pre-main initialziation code to work. + // These shims are enabled only when the caller is in the standard library. + "pthread_getattr_np" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + this.write_null(dest)?; + } + _ => throw_unsup_format!("can't call foreign function: {}", link_name), }; diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 325be877d044..2261b1c4cfb9 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -13,44 +13,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); match link_name { + // errno "__error" => { let errno_place = this.machine.last_error.unwrap(); this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } // File related shims - - // The only reason this is not in the `posix` module is because the `linux` item has a - // different name. "close$NOCANCEL" => { let result = this.close(args[0])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "stat$INODE64" => { let result = this.macos_stat(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "lstat$INODE64" => { let result = this.macos_lstat(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "fstat$INODE64" => { let result = this.macos_fstat(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - - // The only reason this is not in the `posix` module is because the `linux` item has a - // different name. "opendir$INODE64" => { let result = this.opendir(args[0])?; this.write_scalar(result, dest)?; } - - // The `linux` module has a parallel foreign item, `readdir64_r`, which uses a - // different struct layout. "readdir_r$INODE64" => { let result = this.macos_readdir_r(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; @@ -71,21 +60,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_uint(result, dest.layout.size), dest)?; } - // Other shims - "pthread_attr_get_np" => { - this.write_null(dest)?; - } - - "pthread_get_stackaddr_np" => { - let stack_addr = Scalar::from_uint(STACK_ADDR, dest.layout.size); - this.write_scalar(stack_addr, dest)?; - } - - "pthread_get_stacksize_np" => { - let stack_size = Scalar::from_uint(STACK_SIZE, dest.layout.size); - this.write_scalar(stack_size, dest)?; + // Access to command-line arguments + "_NSGetArgc" => { + this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?; + } + "_NSGetArgv" => { + this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; } + // Thread-local storage "_tlv_atexit" => { let dtor = this.read_scalar(args[0])?.not_undef()?; let dtor = this.memory.get_fn(dtor)?.as_instance()?; @@ -93,12 +76,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.tls.set_global_dtor(dtor, data)?; } - "_NSGetArgc" => { - this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?; + // Querying system information + "pthread_get_stackaddr_np" => { + let _thread = this.read_scalar(args[0])?.not_undef()?; + let stack_addr = Scalar::from_uint(STACK_ADDR, dest.layout.size); + this.write_scalar(stack_addr, dest)?; + } + "pthread_get_stacksize_np" => { + let _thread = this.read_scalar(args[0])?.not_undef()?; + let stack_size = Scalar::from_uint(STACK_SIZE, dest.layout.size); + this.write_scalar(stack_size, dest)?; } - "_NSGetArgv" => { - this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; + // Incomplete shims that we "stub out" just to get pre-main initialziation code to work. + // These shims are enabled only when the caller is in the standard library. + "mmap" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. + let addr = this.read_scalar(args[0])?.not_undef()?; + this.write_scalar(addr, dest)?; } _ => throw_unsup_format!("can't call foreign function: {}", link_name), diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 9e71ba7d9074..9a626fe75e03 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -14,12 +14,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); + // Windows API stubs. + // HANDLE = isize + // DWORD = ULONG = u32 + // BOOL = i32 match link_name { - // Windows API stubs. - // HANDLE = isize - // DWORD = ULONG = u32 - // BOOL = i32 - // Environment related shims "GetEnvironmentVariableW" => { let result = this.GetEnvironmentVariableW(args[0], args[1], args[2])?; @@ -42,6 +41,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // File related shims + "GetStdHandle" => { + let which = this.read_scalar(args[0])?.to_i32()?; + // We just make this the identity function, so we know later in `WriteFile` + // which one it is. + this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?; + } "WriteFile" => { let handle = this.read_scalar(args[0])?.to_machine_isize(this)?; let buf = this.read_scalar(args[1])?.not_undef()?; @@ -61,9 +66,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; res.ok().map(|n| n as u32) } else { - eprintln!("Miri: Ignored output to handle {}", handle); - // Pretend it all went well. - Some(n) + throw_unsup_format!("on Windows, writing to anything except stdout/stderr is not supported") }; // If there was no error, write back how much was written. if let Some(n) = written { @@ -76,11 +79,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; } - // Other shims - "GetProcessHeap" => { - // Just fake a HANDLE - this.write_scalar(Scalar::from_int(1, this.pointer_size()), dest)?; - } + // Allocation "HeapAlloc" => { let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?; let flags = this.read_scalar(args[1])?.to_u32()?; @@ -105,6 +104,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } + // errno "SetLastError" => { this.set_last_error(this.read_scalar(args[0])?.not_undef()?)?; } @@ -113,30 +113,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(last_error, dest)?; } - "AddVectoredExceptionHandler" => { - // Any non zero value works for the stdlib. This is just used for stack overflows anyway. - this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; - } - - | "InitializeCriticalSection" - | "EnterCriticalSection" - | "LeaveCriticalSection" - | "DeleteCriticalSection" - => { - // Nothing to do, not even a return value. - // (Windows locks are reentrant, and we have only 1 thread, - // so not doing any futher checks here is at least not incorrect.) - } - - | "GetModuleHandleW" - | "GetProcAddress" - | "GetConsoleScreenBufferInfo" - | "SetConsoleTextAttribute" - => { - // Pretend these do not exist / nothing happened, by returning zero. - this.write_null(dest)?; - } - + // Querying system information "GetSystemInfo" => { let system_info = this.deref_operand(args[0])?; // Initialize with `0`. @@ -150,6 +127,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(NUM_CPUS, dword_size), num_cpus.into())?; } + // Thread-local storage "TlsAlloc" => { // This just creates a key; Windows does not natively support TLS destructors. @@ -170,33 +148,72 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Return success (`1`). this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; } - "GetStdHandle" => { - let which = this.read_scalar(args[0])?.to_i32()?; - // We just make this the identity function, so we know later in `WriteFile` - // which one it is. - this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?; - } - "GetConsoleMode" => { - // Everything is a pipe. - this.write_null(dest)?; - } + + // Access to command-line arguments "GetCommandLineW" => { this.write_scalar( this.machine.cmd_line.expect("machine must be initialized"), dest, )?; } - // The actual name of 'RtlGenRandom' + + // Miscellaneous "SystemFunction036" => { + // The actual name of 'RtlGenRandom' let ptr = this.read_scalar(args[0])?.not_undef()?; let len = this.read_scalar(args[1])?.to_u32()?; this.gen_random(ptr, len.into())?; this.write_scalar(Scalar::from_bool(true), dest)?; } - // We don't support threading. + "GetConsoleScreenBufferInfo" => { + // `term` needs this, so we fake it. + let _console = this.read_scalar(args[0])?.to_machine_isize(this)?; + let _buffer_info = this.deref_operand(args[1])?; + // Indicate an error. + // FIXME: we should set last_error, but to what? + this.write_null(dest)?; + } + "GetConsoleMode" => { + // Windows "isatty" (in libtest) needs this, so we fake it. + let _console = this.read_scalar(args[0])?.to_machine_isize(this)?; + let _mode = this.deref_operand(args[1])?; + // Indicate an error. + // FIXME: we should set last_error, but to what? + this.write_null(dest)?; + } + + // Better error for attempts to create a thread "CreateThread" => { throw_unsup_format!("Miri does not support threading"); } + + // Incomplete shims that we "stub out" just to get pre-main initialziation code to work. + // These shims are enabled only when the caller is in the standard library. + "GetProcessHeap" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + // Just fake a HANDLE + this.write_scalar(Scalar::from_int(1, this.pointer_size()), dest)?; + } + | "GetModuleHandleW" + | "GetProcAddress" + | "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") + => { + // Pretend these do not exist / nothing happened, by returning zero. + this.write_null(dest)?; + } + "AddVectoredExceptionHandler" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + // Any non zero value works for the stdlib. This is just used for stack overflows anyway. + this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; + } + | "InitializeCriticalSection" + | "EnterCriticalSection" + | "LeaveCriticalSection" + | "DeleteCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") + => { + // Nothing to do, not even a return value. + // (Windows locks are reentrant, and we have only 1 thread, + // so not doing any futher checks here is at least not incorrect.) + } + _ => throw_unsup_format!("can't call foreign function: {}", link_name), } From 6ab82f5d35d8505f2e65eebeed56d7eeb62d754e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Mar 2020 11:33:56 +0100 Subject: [PATCH 1737/5092] posix_fadvise is Linux-only; also validate arguments a bit --- src/shims/foreign_items/posix.rs | 4 ---- src/shims/foreign_items/posix/linux.rs | 9 +++++++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 9d331eece503..ce23bc4c972f 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -115,10 +115,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.lseek64(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "posix_fadvise" => { - // fadvise is only informational, we can ignore it. - this.write_null(dest)?; - } // Allocation "posix_memalign" => { diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 1a8cd195ec5b..88a18e3e75f9 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -34,6 +34,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.linux_readdir64_r(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + // Linux-only + "posix_fadvise" => { + let _fd = this.read_scalar(args[0])?.to_i32()?; + let _offset = this.read_scalar(args[1])?.to_machine_isize(this)?; + let _len = this.read_scalar(args[2])?.to_machine_isize(this)?; + let _advice = this.read_scalar(args[3])?.to_i32()?; + // fadvise is only informational, we can ignore it. + this.write_null(dest)?; + } // Time related shims "clock_gettime" => { From a6cab24dc057f87dce7cd3134a096725fc31d556 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Mar 2020 14:32:50 +0100 Subject: [PATCH 1738/5092] we don't deallocate the environ global, so leave it in the machine --- src/shims/env.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 6cde82903bcc..163a8c2e51d7 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -55,7 +55,7 @@ impl<'tcx> EnvVars<'tcx> { ecx.memory.deallocate(ptr, None, MiriMemoryKind::Env.into())?; } // Deallocate environ var list. - let environ = ecx.machine.env_vars.environ.take().unwrap(); + let environ = ecx.machine.env_vars.environ.unwrap(); let old_vars_ptr = ecx.read_scalar(environ.into())?.not_undef()?; ecx.memory.deallocate(ecx.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Env.into())?; Ok(()) From 99600ba7a9820bdaaa252a9b346f87642cd24ca3 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Sat, 28 Mar 2020 10:43:47 -0400 Subject: [PATCH 1739/5092] move OsStr helpers to a separate file --- src/helpers.rs | 241 +----------------------------------------- src/lib.rs | 1 + src/shims/mod.rs | 1 + src/shims/os_str.rs | 247 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 250 insertions(+), 240 deletions(-) create mode 100644 src/shims/os_str.rs diff --git a/src/helpers.rs b/src/helpers.rs index 3e89fdf6f3cc..e22839d9870a 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,13 +1,5 @@ -use std::ffi::{OsStr, OsString}; -use std::path::{Path, PathBuf}; -use std::{iter, mem}; use std::convert::TryFrom; -use std::borrow::Cow; - -#[cfg(unix)] -use std::os::unix::ffi::{OsStrExt, OsStringExt}; -#[cfg(windows)] -use std::os::windows::ffi::{OsStrExt, OsStringExt}; +use std::mem; use rustc::mir; use rustc::ty::{ @@ -462,237 +454,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } - - /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what - /// the Unix APIs usually handle. - fn read_os_str_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, &'a OsStr> - where - 'tcx: 'a, - 'mir: 'a, - { - #[cfg(unix)] - fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { - Ok(OsStr::from_bytes(bytes)) - } - #[cfg(not(unix))] - fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { - let s = std::str::from_utf8(bytes) - .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; - Ok(OsStr::new(s)) - } - - let this = self.eval_context_ref(); - let bytes = this.memory.read_c_str(scalar)?; - bytes_to_os_str(bytes) - } - - /// Helper function to read an OsString from a 0x0000-terminated sequence of u16, - /// which is what the Windows APIs usually handle. - fn read_os_str_from_wide_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, OsString> - where - 'tcx: 'a, - 'mir: 'a, - { - #[cfg(windows)] - pub fn u16vec_to_osstring<'tcx, 'a>(u16_vec: Vec) -> InterpResult<'tcx, OsString> { - Ok(OsString::from_wide(&u16_vec[..])) - } - #[cfg(not(windows))] - pub fn u16vec_to_osstring<'tcx, 'a>(u16_vec: Vec) -> InterpResult<'tcx, OsString> { - let s = String::from_utf16(&u16_vec[..]) - .map_err(|_| err_unsup_format!("{:?} is not a valid utf-16 string", u16_vec))?; - Ok(s.into()) - } - - let u16_vec = self.eval_context_ref().memory.read_wide_str(scalar)?; - u16vec_to_osstring(u16_vec) - } - - /// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what - /// the Unix APIs usually handle. This function returns `Ok((false, length))` without trying - /// to write if `size` is not large enough to fit the contents of `os_string` plus a null - /// terminator. It returns `Ok((true, length))` if the writing process was successful. The - /// string length returned does not include the null terminator. - fn write_os_str_to_c_str( - &mut self, - os_str: &OsStr, - scalar: Scalar, - size: u64, - ) -> InterpResult<'tcx, (bool, u64)> { - #[cfg(unix)] - fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - Ok(os_str.as_bytes()) - } - #[cfg(not(unix))] - fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the - // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually - // valid. - os_str - .to_str() - .map(|s| s.as_bytes()) - .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) - } - - let bytes = os_str_to_bytes(os_str)?; - // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null - // terminator to memory using the `ptr` pointer would cause an out-of-bounds access. - let string_length = u64::try_from(bytes.len()).unwrap(); - if size <= string_length { - return Ok((false, string_length)); - } - self.eval_context_mut() - .memory - .write_bytes(scalar, bytes.iter().copied().chain(iter::once(0u8)))?; - Ok((true, string_length)) - } - - /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what - /// the Windows APIs usually handle. This function returns `Ok((false, length))` without trying - /// to write if `size` is not large enough to fit the contents of `os_string` plus a null - /// terminator. It returns `Ok((true, length))` if the writing process was successful. The - /// string length returned does not include the null terminator. - fn write_os_str_to_wide_str( - &mut self, - os_str: &OsStr, - scalar: Scalar, - size: u64, - ) -> InterpResult<'tcx, (bool, u64)> { - #[cfg(windows)] - fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec> { - Ok(os_str.encode_wide().collect()) - } - #[cfg(not(windows))] - fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec> { - // On non-Windows platforms the best we can do to transform Vec from/to OS strings is to do the - // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually - // valid. - os_str - .to_str() - .map(|s| s.encode_utf16().collect()) - .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) - } - - let u16_vec = os_str_to_u16vec(os_str)?; - // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required - // 0x0000 terminator to memory would cause an out-of-bounds access. - let string_length = u64::try_from(u16_vec.len()).unwrap(); - if size <= string_length { - return Ok((false, string_length)); - } - - // Store the UTF-16 string. - self.eval_context_mut() - .memory - .write_u16s(scalar, u16_vec.into_iter().chain(iter::once(0x0000)))?; - Ok((true, string_length)) - } - - /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes. - fn alloc_os_str_as_c_str( - &mut self, - os_str: &OsStr, - memkind: MemoryKind, - ) -> Pointer { - let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0` terminator. - let this = self.eval_context_mut(); - - let arg_type = this.tcx.mk_array(this.tcx.types.u8, size); - let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind); - assert!(self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap().0); - arg_place.ptr.assert_ptr() - } - - /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of `u16`. - fn alloc_os_str_as_wide_str( - &mut self, - os_str: &OsStr, - memkind: MemoryKind, - ) -> Pointer { - let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0x0000` terminator. - let this = self.eval_context_mut(); - - let arg_type = this.tcx.mk_array(this.tcx.types.u16, size); - let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind); - assert!(self.write_os_str_to_wide_str(os_str, arg_place.ptr, size).unwrap().0); - arg_place.ptr.assert_ptr() - } - - /// Read a null-terminated sequence of bytes, and perform path separator conversion if needed. - fn read_path_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, Cow<'a, Path>> - where - 'tcx: 'a, - 'mir: 'a, - { - let this = self.eval_context_ref(); - let os_str = this.read_os_str_from_c_str(scalar)?; - - #[cfg(windows)] - return Ok(if this.tcx.sess.target.target.target_os == "windows" { - // Windows-on-Windows, all fine. - Cow::Borrowed(Path::new(os_str)) - } else { - // Unix target, Windows host. Need to convert target '/' to host '\'. - let converted = os_str - .encode_wide() - .map(|wchar| if wchar == '/' as u16 { '\\' as u16 } else { wchar }) - .collect::>(); - Cow::Owned(PathBuf::from(OsString::from_wide(&converted))) - }); - #[cfg(unix)] - return Ok(if this.tcx.sess.target.target.target_os == "windows" { - // Windows target, Unix host. Need to convert target '\' to host '/'. - let converted = os_str - .as_bytes() - .iter() - .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) - .collect::>(); - Cow::Owned(PathBuf::from(OsString::from_vec(converted))) - } else { - // Unix-on-Unix, all is fine. - Cow::Borrowed(Path::new(os_str)) - }); - } - - /// Write a Path to the machine memory, adjusting path separators if needed. - fn write_path_to_c_str( - &mut self, - path: &Path, - scalar: Scalar, - size: u64, - ) -> InterpResult<'tcx, (bool, u64)> { - let this = self.eval_context_mut(); - - #[cfg(windows)] - let os_str = if this.tcx.sess.target.target.target_os == "windows" { - // Windows-on-Windows, all fine. - Cow::Borrowed(path.as_os_str()) - } else { - // Unix target, Windows host. Need to convert host '\\' to target '/'. - let converted = path - .as_os_str() - .encode_wide() - .map(|wchar| if wchar == '\\' as u16 { '/' as u16 } else { wchar }) - .collect::>(); - Cow::Owned(OsString::from_wide(&converted)) - }; - #[cfg(unix)] - let os_str = if this.tcx.sess.target.target.target_os == "windows" { - // Windows target, Unix host. Need to convert host '/' to target '\'. - let converted = path - .as_os_str() - .as_bytes() - .iter() - .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) - .collect::>(); - Cow::Owned(OsString::from_vec(converted)) - } else { - // Unix-on-Unix, all is fine. - Cow::Borrowed(path.as_os_str()) - }; - - this.write_os_str_to_c_str(&os_str, scalar, size) - } } pub fn immty_from_int_checked<'tcx>( diff --git a/src/lib.rs b/src/lib.rs index 32eb5b41e591..32416ccaafff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,6 +39,7 @@ pub use crate::shims::env::{EnvVars, EvalContextExt as EnvEvalContextExt}; pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextExt; pub use crate::shims::fs::{DirHandler, EvalContextExt as FileEvalContextExt, FileHandler}; pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; +pub use crate::shims::os_str::EvalContextExt as OsStrEvalContextExt; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as PanicEvalContextExt}; pub use crate::shims::time::EvalContextExt as TimeEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 5b5a11b86b49..f950c8047834 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -3,6 +3,7 @@ pub mod env; pub mod foreign_items; pub mod fs; pub mod intrinsics; +pub mod os_str; pub mod panic; pub mod time; pub mod tls; diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs new file mode 100644 index 000000000000..2306d01de5d9 --- /dev/null +++ b/src/shims/os_str.rs @@ -0,0 +1,247 @@ +use std::borrow::Cow; +use std::convert::TryFrom; +use std::ffi::{OsStr, OsString}; +use std::iter; +#[cfg(unix)] +use std::os::unix::ffi::{OsStrExt, OsStringExt}; +#[cfg(windows)] +use std::os::windows::ffi::{OsStrExt, OsStringExt}; +use std::path::{Path, PathBuf}; + +use rustc::ty::layout::LayoutOf; + +use crate::*; + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what + /// the Unix APIs usually handle. + fn read_os_str_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, &'a OsStr> + where + 'tcx: 'a, + 'mir: 'a, + { + #[cfg(unix)] + fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { + Ok(OsStr::from_bytes(bytes)) + } + #[cfg(not(unix))] + fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { + let s = std::str::from_utf8(bytes) + .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; + Ok(OsStr::new(s)) + } + + let this = self.eval_context_ref(); + let bytes = this.memory.read_c_str(scalar)?; + bytes_to_os_str(bytes) + } + + /// Helper function to read an OsString from a 0x0000-terminated sequence of u16, + /// which is what the Windows APIs usually handle. + fn read_os_str_from_wide_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, OsString> + where + 'tcx: 'a, + 'mir: 'a, + { + #[cfg(windows)] + pub fn u16vec_to_osstring<'tcx, 'a>(u16_vec: Vec) -> InterpResult<'tcx, OsString> { + Ok(OsString::from_wide(&u16_vec[..])) + } + #[cfg(not(windows))] + pub fn u16vec_to_osstring<'tcx, 'a>(u16_vec: Vec) -> InterpResult<'tcx, OsString> { + let s = String::from_utf16(&u16_vec[..]) + .map_err(|_| err_unsup_format!("{:?} is not a valid utf-16 string", u16_vec))?; + Ok(s.into()) + } + + let u16_vec = self.eval_context_ref().memory.read_wide_str(scalar)?; + u16vec_to_osstring(u16_vec) + } + + /// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what + /// the Unix APIs usually handle. This function returns `Ok((false, length))` without trying + /// to write if `size` is not large enough to fit the contents of `os_string` plus a null + /// terminator. It returns `Ok((true, length))` if the writing process was successful. The + /// string length returned does not include the null terminator. + fn write_os_str_to_c_str( + &mut self, + os_str: &OsStr, + scalar: Scalar, + size: u64, + ) -> InterpResult<'tcx, (bool, u64)> { + #[cfg(unix)] + fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + Ok(os_str.as_bytes()) + } + #[cfg(not(unix))] + fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the + // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually + // valid. + os_str + .to_str() + .map(|s| s.as_bytes()) + .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) + } + + let bytes = os_str_to_bytes(os_str)?; + // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null + // terminator to memory using the `ptr` pointer would cause an out-of-bounds access. + let string_length = u64::try_from(bytes.len()).unwrap(); + if size <= string_length { + return Ok((false, string_length)); + } + self.eval_context_mut() + .memory + .write_bytes(scalar, bytes.iter().copied().chain(iter::once(0u8)))?; + Ok((true, string_length)) + } + + /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what + /// the Windows APIs usually handle. This function returns `Ok((false, length))` without trying + /// to write if `size` is not large enough to fit the contents of `os_string` plus a null + /// terminator. It returns `Ok((true, length))` if the writing process was successful. The + /// string length returned does not include the null terminator. + fn write_os_str_to_wide_str( + &mut self, + os_str: &OsStr, + scalar: Scalar, + size: u64, + ) -> InterpResult<'tcx, (bool, u64)> { + #[cfg(windows)] + fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec> { + Ok(os_str.encode_wide().collect()) + } + #[cfg(not(windows))] + fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec> { + // On non-Windows platforms the best we can do to transform Vec from/to OS strings is to do the + // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually + // valid. + os_str + .to_str() + .map(|s| s.encode_utf16().collect()) + .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) + } + + let u16_vec = os_str_to_u16vec(os_str)?; + // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required + // 0x0000 terminator to memory would cause an out-of-bounds access. + let string_length = u64::try_from(u16_vec.len()).unwrap(); + if size <= string_length { + return Ok((false, string_length)); + } + + // Store the UTF-16 string. + self.eval_context_mut() + .memory + .write_u16s(scalar, u16_vec.into_iter().chain(iter::once(0x0000)))?; + Ok((true, string_length)) + } + + /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes. + fn alloc_os_str_as_c_str( + &mut self, + os_str: &OsStr, + memkind: MemoryKind, + ) -> Pointer { + let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0` terminator. + let this = self.eval_context_mut(); + + let arg_type = this.tcx.mk_array(this.tcx.types.u8, size); + let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind); + assert!(self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap().0); + arg_place.ptr.assert_ptr() + } + + /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of `u16`. + fn alloc_os_str_as_wide_str( + &mut self, + os_str: &OsStr, + memkind: MemoryKind, + ) -> Pointer { + let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0x0000` terminator. + let this = self.eval_context_mut(); + + let arg_type = this.tcx.mk_array(this.tcx.types.u16, size); + let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind); + assert!(self.write_os_str_to_wide_str(os_str, arg_place.ptr, size).unwrap().0); + arg_place.ptr.assert_ptr() + } + + /// Read a null-terminated sequence of bytes, and perform path separator conversion if needed. + fn read_path_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, Cow<'a, Path>> + where + 'tcx: 'a, + 'mir: 'a, + { + let this = self.eval_context_ref(); + let os_str = this.read_os_str_from_c_str(scalar)?; + + #[cfg(windows)] + return Ok(if this.tcx.sess.target.target.target_os == "windows" { + // Windows-on-Windows, all fine. + Cow::Borrowed(Path::new(os_str)) + } else { + // Unix target, Windows host. Need to convert target '/' to host '\'. + let converted = os_str + .encode_wide() + .map(|wchar| if wchar == '/' as u16 { '\\' as u16 } else { wchar }) + .collect::>(); + Cow::Owned(PathBuf::from(OsString::from_wide(&converted))) + }); + #[cfg(unix)] + return Ok(if this.tcx.sess.target.target.target_os == "windows" { + // Windows target, Unix host. Need to convert target '\' to host '/'. + let converted = os_str + .as_bytes() + .iter() + .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) + .collect::>(); + Cow::Owned(PathBuf::from(OsString::from_vec(converted))) + } else { + // Unix-on-Unix, all is fine. + Cow::Borrowed(Path::new(os_str)) + }); + } + + /// Write a Path to the machine memory, adjusting path separators if needed. + fn write_path_to_c_str( + &mut self, + path: &Path, + scalar: Scalar, + size: u64, + ) -> InterpResult<'tcx, (bool, u64)> { + let this = self.eval_context_mut(); + + #[cfg(windows)] + let os_str = if this.tcx.sess.target.target.target_os == "windows" { + // Windows-on-Windows, all fine. + Cow::Borrowed(path.as_os_str()) + } else { + // Unix target, Windows host. Need to convert host '\\' to target '/'. + let converted = path + .as_os_str() + .encode_wide() + .map(|wchar| if wchar == '\\' as u16 { '/' as u16 } else { wchar }) + .collect::>(); + Cow::Owned(OsString::from_wide(&converted)) + }; + #[cfg(unix)] + let os_str = if this.tcx.sess.target.target.target_os == "windows" { + // Windows target, Unix host. Need to convert host '/' to target '\'. + let converted = path + .as_os_str() + .as_bytes() + .iter() + .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) + .collect::>(); + Cow::Owned(OsString::from_vec(converted)) + } else { + // Unix-on-Unix, all is fine. + Cow::Borrowed(path.as_os_str()) + }; + + this.write_os_str_to_c_str(&os_str, scalar, size) + } +} From 4e471f745f7e827a4e8986cd166f86953a0d6ab2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Mar 2020 15:45:45 +0100 Subject: [PATCH 1740/5092] fix float test comments and test a few more int->float casts --- tests/run-pass/floats.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/run-pass/floats.rs b/tests/run-pass/floats.rs index 5a7413e98ea8..394e91ac9c3b 100644 --- a/tests/run-pass/floats.rs +++ b/tests/run-pass/floats.rs @@ -2,8 +2,8 @@ use std::fmt::Debug; // Helper function to avoid promotion so that this tests "run-time" casts, not CTFE. -// Doesn't make a big difference when running this in Miri, but when running this in -// rustc (with -Zmir-opt-level=0) for comparison it means we use LLVM casts. +// Doesn't make a big difference when running this in Miri, but it means we can compare this +// with the LLVM backend by running `rustc -Zmir-opt-level=0 -Zsaturating-float-casts`. #[track_caller] #[inline(never)] fn assert_eq(x: T, y: T) { @@ -29,7 +29,7 @@ fn main() { let y: f32 = unsafe { std::mem::transmute(x) }; assert_eq(y, 42.0_f32); - // f32-to-int casts + // f32 <-> int casts assert_eq(5.0f32 as u32, 5); assert_eq(-5.0f32 as u32, 0); assert_eq(5.0f32 as i32, 5); @@ -44,11 +44,13 @@ fn main() { assert_eq(std::f32::NEG_INFINITY as u32, 0); assert_eq(std::f32::NAN as i32, 0); assert_eq(std::f32::NAN as u32, 0); - assert_eq(u128::MAX as f32, std::f32::INFINITY); assert_eq((u32::MAX-127) as f32 as u32, u32::MAX); // rounding loss assert_eq((u32::MAX-128) as f32 as u32, u32::MAX-255); // rounding loss + assert_eq(127i8 as f32, 127.0f32); + assert_eq(i128::MIN as f32, -170141183460469231731687303715884105728.0f32); + assert_eq(u128::MAX as f32, std::f32::INFINITY); // saturation - // f64-to-int casts + // f64 <-> int casts assert_eq(5.0f64 as u64, 5); assert_eq(-5.0f64 as u64, 0); assert_eq(5.0f64 as i64, 5); @@ -63,9 +65,11 @@ fn main() { assert_eq(std::f64::NEG_INFINITY as u64, 0); assert_eq(std::f64::NAN as i64, 0); assert_eq(std::f64::NAN as u64, 0); - assert_eq(u128::MAX as f64 as u128, u128::MAX); assert_eq((u64::MAX-1023) as f64 as u64, u64::MAX); // rounding loss assert_eq((u64::MAX-1024) as f64 as u64, u64::MAX-2047); // rounding loss + assert_eq(u128::MAX as f64 as u128, u128::MAX); + assert_eq(i16::MIN as f64, -32768.0f64); + assert_eq(u128::MAX as f64, 340282366920938463463374607431768211455.0f64); // even that fits... // f32 <-> f64 casts assert_eq(5.0f64 as f32, 5.0f32); From 4a70ebc1f3e1d635a3ed6ec5d8e37e6618e5f05d Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Sat, 28 Mar 2020 11:20:16 -0400 Subject: [PATCH 1741/5092] visually separate conditional imports in 'os_str.rs' --- src/shims/os_str.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 2306d01de5d9..316d5b0014a7 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -2,11 +2,12 @@ use std::borrow::Cow; use std::convert::TryFrom; use std::ffi::{OsStr, OsString}; use std::iter; +use std::path::{Path, PathBuf}; + #[cfg(unix)] use std::os::unix::ffi::{OsStrExt, OsStringExt}; #[cfg(windows)] use std::os::windows::ffi::{OsStrExt, OsStringExt}; -use std::path::{Path, PathBuf}; use rustc::ty::layout::LayoutOf; From fbbca59de7873ebad6452c576fe7f9e7011c466d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Mar 2020 17:35:40 +0100 Subject: [PATCH 1742/5092] avoid Scalar::from_(u)int in favor of giving the size explicitly --- src/eval.rs | 7 +++--- src/helpers.rs | 2 +- src/machine.rs | 4 ++-- src/shims/env.rs | 10 ++++---- src/shims/foreign_items.rs | 10 ++++---- src/shims/foreign_items/posix.rs | 33 +++++++++++++------------- src/shims/foreign_items/posix/linux.rs | 14 +++++------ src/shims/foreign_items/posix/macos.rs | 18 +++++++------- src/shims/foreign_items/windows.rs | 16 ++++++------- src/shims/intrinsics.rs | 9 +++---- src/shims/mod.rs | 2 +- 11 files changed, 61 insertions(+), 64 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index faf7f5532ccf..9838bd1e8cc2 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -6,7 +6,7 @@ use std::convert::TryFrom; use rand::rngs::StdRng; use rand::SeedableRng; -use rustc::ty::layout::{LayoutOf, Size}; +use rustc::ty::layout::LayoutOf; use rustc::ty::{self, TyCtxt}; use rustc_hir::def_id::DefId; @@ -96,7 +96,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // First argument: pointer to `main()`. let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(main_instance)); // Second argument (argc): length of `config.args`. - let argc = Scalar::from_uint(u64::try_from(config.args.len()).unwrap(), ecx.pointer_size()); + let argc = Scalar::from_machine_usize(u64::try_from(config.args.len()).unwrap(), &ecx); // Third argument (`argv`): created from `config.args`. let argv = { // Put each argument in memory, collect pointers. @@ -152,10 +152,9 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Machine.into()); ecx.machine.cmd_line = Some(cmd_place.ptr); // Store the UTF-16 string. We just allocated so we know the bounds are fine. - let char_size = Size::from_bytes(2); for (idx, &c) in cmd_utf16.iter().enumerate() { let place = ecx.mplace_field(cmd_place, idx)?; - ecx.write_scalar(Scalar::from_uint(c, char_size), place.into())?; + ecx.write_scalar(Scalar::from_u16(c), place.into())?; } } argv diff --git a/src/helpers.rs b/src/helpers.rs index 8e379065b07e..9bc0279aa455 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -100,7 +100,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Test if this immediate equals 0. fn is_null(&self, val: Scalar) -> InterpResult<'tcx, bool> { let this = self.eval_context_ref(); - let null = Scalar::from_int(0, this.memory.pointer_size()); + let null = Scalar::ptr_null(this); this.ptr_eq(val, null) } diff --git a/src/machine.rs b/src/machine.rs index f88210f30e8c..ebde404769ca 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -316,10 +316,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { let layout = ecx.layout_of(dest.layout.ty.builtin_deref(false).unwrap().ty)?; // First argument: `size`. // (`0` is allowed here -- this is expected to be handled by the lang item). - let size = Scalar::from_uint(layout.size.bytes(), ecx.pointer_size()); + let size = Scalar::from_machine_usize(layout.size.bytes(), ecx); // Second argument: `align`. - let align = Scalar::from_uint(layout.align.abi.bytes(), ecx.pointer_size()); + let align = Scalar::from_machine_usize(layout.align.abi.bytes(), ecx); // Call the `exchange_malloc` lang item. let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap(); diff --git a/src/shims/env.rs b/src/shims/env.rs index 163a8c2e51d7..7aa4148fa888 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -108,7 +108,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name_op: OpTy<'tcx, Tag>, // LPCWSTR buf_op: OpTy<'tcx, Tag>, // LPWSTR size_op: OpTy<'tcx, Tag>, // DWORD - ) -> InterpResult<'tcx, u64> { + ) -> InterpResult<'tcx, u32> { let this = self.eval_context_mut(); this.assert_target_os("windows", "GetEnvironmentVariableW"); @@ -124,17 +124,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf_ptr = this.read_scalar(buf_op)?.not_undef()?; // `buf_size` represents the size in characters. - let buf_size = u64::try_from(this.read_scalar(size_op)?.to_u32()?).unwrap(); + let buf_size = u64::from(this.read_scalar(size_op)?.to_u32()?); let (success, len) = this.write_os_str_to_wide_str(&var, buf_ptr, buf_size)?; if success { // If the function succeeds, the return value is the number of characters stored in the buffer pointed to by lpBuffer, // not including the terminating null character. - len + u32::try_from(len).unwrap() } else { // If lpBuffer is not large enough to hold the data, the return value is the buffer size, in characters, // required to hold the string and its terminating null character and the contents of lpBuffer are undefined. - len + 1 + u32::try_from(len).unwrap().checked_add(1).unwrap() } } None => { @@ -344,7 +344,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Collect all the pointers to each variable in a vector. let mut vars: Vec> = this.machine.env_vars.map.values().map(|&ptr| ptr.into()).collect(); // Add the trailing null pointer. - vars.push(Scalar::from_int(0, this.pointer_size())); + vars.push(Scalar::from_machine_usize(0, this)); // Make an array with all these pointers inside Miri. let tcx = this.tcx; let vars_layout = diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index c92e338ef7e0..3e21e1d453fc 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -47,7 +47,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn malloc(&mut self, size: u64, zero_init: bool, kind: MiriMemoryKind) -> Scalar { let this = self.eval_context_mut(); if size == 0 { - Scalar::from_int(0, this.pointer_size()) + Scalar::ptr_null(this) } else { let align = this.min_align(size, kind); let ptr = this.memory.allocate(Size::from_bytes(size), align, kind.into()); @@ -78,7 +78,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let new_align = this.min_align(new_size, kind); if this.is_null(old_ptr)? { if new_size == 0 { - Ok(Scalar::from_int(0, this.pointer_size())) + Ok(Scalar::ptr_null(this)) } else { let new_ptr = this.memory.allocate(Size::from_bytes(new_size), new_align, kind.into()); @@ -88,7 +88,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let old_ptr = this.force_ptr(old_ptr)?; if new_size == 0 { this.memory.deallocate(old_ptr, None, kind.into())?; - Ok(Scalar::from_int(0, this.pointer_size())) + Ok(Scalar::ptr_null(this)) } else { let new_ptr = this.memory.reallocate( old_ptr, @@ -296,7 +296,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } }; - this.write_scalar(Scalar::from_int(result, Size::from_bits(32)), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "memrchr" => { let ptr = this.read_scalar(args[0])?.not_undef()?; @@ -334,7 +334,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "strlen" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let n = this.memory.read_c_str(ptr)?.len(); - this.write_scalar(Scalar::from_uint(u64::try_from(n).unwrap(), dest.layout.size), dest)?; + this.write_scalar(Scalar::from_machine_usize(u64::try_from(n).unwrap(), this), dest)?; } // math functions diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index ce23bc4c972f..1a9e91eded7f 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -26,11 +26,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "unsetenv" => { let result = this.unsetenv(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "setenv" => { let result = this.setenv(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "getcwd" => { let result = this.getcwd(args[0], args[1])?; @@ -38,21 +38,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "chdir" => { let result = this.chdir(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } // File related shims "open" | "open64" => { let result = this.open(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "fcntl" => { let result = this.fcntl(args[0], args[1], args.get(2).cloned())?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "read" => { let result = this.read(args[0], args[1], args[2])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "write" => { let fd = this.read_scalar(args[0])?.to_i32()?; @@ -85,35 +85,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write(args[0], args[1], args[2])? }; // Now, `result` is the value we return back to the program. - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "unlink" => { let result = this.unlink(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "symlink" => { let result = this.symlink(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "rename" => { let result = this.rename(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "mkdir" => { let result = this.mkdir(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "rmdir" => { let result = this.rmdir(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "closedir" => { let result = this.closedir(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "lseek" | "lseek64" => { let result = this.lseek64(args[0], args[1], args[2])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + // "lseek" is only used on macOS which is 64bit-only, so `i64` always works. + this.write_scalar(Scalar::from_i64(result), dest)?; } // Allocation @@ -165,8 +166,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name = this.read_scalar(args[0])?.to_i32()?; let sysconfs = &[ - ("_SC_PAGESIZE", Scalar::from_int(PAGE_SIZE, dest.layout.size)), - ("_SC_NPROCESSORS_ONLN", Scalar::from_int(NUM_CPUS, dest.layout.size)), + ("_SC_PAGESIZE", Scalar::from_int(PAGE_SIZE, this.pointer_size())), + ("_SC_NPROCESSORS_ONLN", Scalar::from_int(NUM_CPUS, this.pointer_size())), ]; let mut result = None; for &(sysconf_name, value) in sysconfs { diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 88a18e3e75f9..d11d355eb346 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -24,7 +24,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // in the `posix` module. "close" => { let result = this.close(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" => { let result = this.opendir(args[0])?; @@ -32,7 +32,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "readdir64_r" => { let result = this.linux_readdir64_r(args[0], args[1], args[2])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } // Linux-only "posix_fadvise" => { @@ -48,7 +48,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "clock_gettime" => { // This is a POSIX function but it has only been tested on linux. let result = this.clock_gettime(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } // Querying system information @@ -59,11 +59,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let size_place = this.deref_operand(args[2])?; this.write_scalar( - Scalar::from_uint(STACK_ADDR, addr_place.layout.size), + Scalar::from_uint(STACK_ADDR, this.pointer_size()), addr_place.into(), )?; this.write_scalar( - Scalar::from_uint(STACK_SIZE, size_place.layout.size), + Scalar::from_uint(STACK_SIZE, this.pointer_size()), size_place.into(), )?; @@ -93,7 +93,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx id if id == sys_statx => { // The first argument is the syscall id, so skip over it. let result = this.linux_statx(args[1], args[2], args[3], args[4], args[5])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_machine_isize(result.into(), this), dest)?; } id => throw_unsup_format!("miri does not support syscall ID {}", id), } @@ -110,7 +110,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: we just return an error; `num_cpus` then falls back to `sysconf`. let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; - this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(-1), dest)?; } // Incomplete shims that we "stub out" just to get pre-main initialziation code to work. diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 2261b1c4cfb9..cc58924a54ab 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -22,19 +22,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "close$NOCANCEL" => { let result = this.close(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "stat$INODE64" => { let result = this.macos_stat(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "lstat$INODE64" => { let result = this.macos_lstat(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "fstat$INODE64" => { let result = this.macos_fstat(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir$INODE64" => { let result = this.opendir(args[0])?; @@ -42,7 +42,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "readdir_r$INODE64" => { let result = this.macos_readdir_r(args[0], args[1], args[2])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } // Environment related shims @@ -53,11 +53,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "gettimeofday" => { let result = this.gettimeofday(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "mach_absolute_time" => { let result = this.mach_absolute_time()?; - this.write_scalar(Scalar::from_uint(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_u64(result), dest)?; } // Access to command-line arguments @@ -79,12 +79,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_get_stackaddr_np" => { let _thread = this.read_scalar(args[0])?.not_undef()?; - let stack_addr = Scalar::from_uint(STACK_ADDR, dest.layout.size); + let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size()); this.write_scalar(stack_addr, dest)?; } "pthread_get_stacksize_np" => { let _thread = this.read_scalar(args[0])?.not_undef()?; - let stack_size = Scalar::from_uint(STACK_SIZE, dest.layout.size); + let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size()); this.write_scalar(stack_size, dest)?; } diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 9a626fe75e03..7f3f1d0c2d2e 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -22,12 +22,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Environment related shims "GetEnvironmentVariableW" => { let result = this.GetEnvironmentVariableW(args[0], args[1], args[2])?; - this.write_scalar(Scalar::from_uint(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_u32(result), dest)?; } "SetEnvironmentVariableW" => { let result = this.SetEnvironmentVariableW(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "GetEnvironmentStringsW" => { @@ -45,7 +45,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let which = this.read_scalar(args[0])?.to_i32()?; // We just make this the identity function, so we know later in `WriteFile` // which one it is. - this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?; + this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?; } "WriteFile" => { let handle = this.read_scalar(args[0])?.to_machine_isize(this)?; @@ -74,7 +74,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Return whether this was a success. this.write_scalar( - Scalar::from_int(if written.is_some() { 1 } else { 0 }, dest.layout.size), + Scalar::from_i32(if written.is_some() { 1 } else { 0 }), dest, )?; } @@ -93,7 +93,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let _flags = this.read_scalar(args[1])?.to_u32()?; let ptr = this.read_scalar(args[2])?.not_undef()?; this.free(ptr, MiriMemoryKind::WinHeap)?; - this.write_scalar(Scalar::from_int(1, Size::from_bytes(4)), dest)?; + this.write_scalar(Scalar::from_i32(1), dest)?; } "HeapReAlloc" => { let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?; @@ -146,7 +146,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?; // Return success (`1`). - this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(1), dest)?; } // Access to command-line arguments @@ -191,7 +191,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These shims are enabled only when the caller is in the standard library. "GetProcessHeap" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { // Just fake a HANDLE - this.write_scalar(Scalar::from_int(1, this.pointer_size()), dest)?; + this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } | "GetModuleHandleW" | "GetProcAddress" @@ -202,7 +202,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "AddVectoredExceptionHandler" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { // Any non zero value works for the stdlib. This is just used for stack overflows anyway. - this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_machine_usize(1, this), dest)?; } | "InitializeCriticalSection" | "EnterCriticalSection" diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 84e8cca556a1..91d0835589f4 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -388,8 +388,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ty = substs.type_at(0); let layout = this.layout_of(ty)?; let align = layout.align.pref.bytes(); - let ptr_size = this.pointer_size(); - let align_val = Scalar::from_uint(align, ptr_size); + let align_val = Scalar::from_machine_usize(align, this); this.write_scalar(align_val, dest)?; } @@ -471,8 +470,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (size, _) = this .size_and_align_of_mplace(mplace)? .expect("size_of_val called on extern type"); - let ptr_size = this.pointer_size(); - this.write_scalar(Scalar::from_uint(size.bytes(), ptr_size), dest)?; + this.write_scalar(Scalar::from_machine_usize(size.bytes(), this), dest)?; } #[rustfmt::skip] @@ -483,8 +481,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (_, align) = this .size_and_align_of_mplace(mplace)? .expect("size_of_val called on extern type"); - let ptr_size = this.pointer_size(); - this.write_scalar(Scalar::from_uint(align.bytes(), ptr_size), dest)?; + this.write_scalar(Scalar::from_machine_usize(align.bytes(), this), dest)?; } "write_bytes" => { diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 5b5a11b86b49..588f496d1f3f 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -92,7 +92,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Return result, and jump to caller. - this.write_scalar(Scalar::from_uint(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_uint(result, this.pointer_size()), dest)?; this.go_to_block(ret); Ok(()) } From b7fec6b17f1f4cbe228c964cfb8a0f76b46f749f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Mar 2020 17:38:38 +0100 Subject: [PATCH 1743/5092] use ptr_null where appropriate --- src/machine.rs | 2 +- src/shims/env.rs | 3 +-- src/shims/fs.rs | 2 +- src/shims/intrinsics.rs | 1 - 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index ebde404769ca..84329b8fd3cd 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -130,7 +130,7 @@ impl MemoryExtra { // This should be all-zero, pointer-sized. let layout = this.layout_of(this.tcx.types.usize)?; let place = this.allocate(layout, MiriMemoryKind::Machine.into()); - this.write_scalar(Scalar::from_machine_usize(0, &*this.tcx), place.into())?; + this.write_scalar(Scalar::from_machine_usize(0, this), place.into())?; Self::add_extern_static(this, "__cxa_thread_atexit_impl", place.ptr); // "environ" Self::add_extern_static(this, "environ", this.machine.env_vars.environ.unwrap().ptr); diff --git a/src/shims/env.rs b/src/shims/env.rs index 7aa4148fa888..98f1e7e3cfa3 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -337,14 +337,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This is memory backing an extern static, hence `Machine`, not `Env`. let layout = this.layout_of(this.tcx.types.usize)?; let place = this.allocate(layout, MiriMemoryKind::Machine.into()); - this.write_scalar(Scalar::from_machine_usize(0, &*this.tcx), place.into())?; this.machine.env_vars.environ = Some(place); } // Collect all the pointers to each variable in a vector. let mut vars: Vec> = this.machine.env_vars.map.values().map(|&ptr| ptr.into()).collect(); // Add the trailing null pointer. - vars.push(Scalar::from_machine_usize(0, this)); + vars.push(Scalar::ptr_null(this)); // Make an array with all these pointers inside Miri. let tcx = this.tcx; let vars_layout = diff --git a/src/shims/fs.rs b/src/shims/fs.rs index b779bf165d2b..debf412bdd41 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -860,7 +860,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Err(e) => { this.set_last_error_from_io_error(e)?; - Ok(Scalar::from_machine_usize(0, this)) + Ok(Scalar::ptr_null(this)) } } } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 91d0835589f4..fda52429e515 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -2,7 +2,6 @@ use std::iter; use std::convert::TryFrom; use rustc::mir; -use rustc::mir::interpret::{InterpResult, PointerArithmetic}; use rustc::ty; use rustc::ty::layout::{Align, LayoutOf}; use rustc_apfloat::Float; From d6795a77b4d18c96c3c967a0d05d90f20b49d0d2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Mar 2020 17:47:00 +0100 Subject: [PATCH 1744/5092] precise getrandom return type and align_offset arithmetic --- src/shims/foreign_items/posix/linux.rs | 2 +- src/shims/mod.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index d11d355eb346..f56d5b3959c7 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -140,6 +140,6 @@ fn getrandom<'tcx>( let _flags = this.read_scalar(args[2])?.to_i32()?; this.gen_random(ptr, len)?; - this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_machine_usize(len, this), dest)?; Ok(()) } diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 588f496d1f3f..58972731fb1d 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -75,7 +75,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr_scalar = this.read_scalar(ptr_op)?.not_undef()?; // Default: no result. - let mut result = this.truncate(u128::MAX, dest.layout); + let mut result = this.usize_max(); if let Ok(ptr) = this.force_ptr(ptr_scalar) { // Only do anything if we can identify the allocation this goes to. let cur_align = @@ -84,7 +84,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If the allocation alignment is at least the required alignment we use the // libcore implementation. // FIXME: is this correct in case of truncation? - result = u128::try_from( + result = u64::try_from( (this.force_bits(ptr_scalar, this.pointer_size())? as *const i8) .align_offset(usize::try_from(req_align).unwrap()) ).unwrap(); @@ -92,7 +92,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Return result, and jump to caller. - this.write_scalar(Scalar::from_uint(result, this.pointer_size()), dest)?; + this.write_scalar(Scalar::from_machine_usize(result, this), dest)?; this.go_to_block(ret); Ok(()) } From f181e75db2722739f8b8fd0dd25ba85636c9a805 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 Mar 2020 10:01:31 +0200 Subject: [PATCH 1745/5092] rustup --- rust-version | 2 +- src/helpers.rs | 2 +- src/shims/env.rs | 6 +++--- src/shims/foreign_items.rs | 6 +++--- src/shims/fs.rs | 6 +++--- src/shims/mod.rs | 2 +- src/shims/tls.rs | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/rust-version b/rust-version index a11e231acb30..0b3196a7a280 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7b73d14b0b35e7b4f79f2d71dc1bbbab31698288 +150322f86d441752874a8bed603d71119f190b8b diff --git a/src/helpers.rs b/src/helpers.rs index f7bc4d195cab..d0a5fc958662 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -92,7 +92,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Test if this immediate equals 0. fn is_null(&self, val: Scalar) -> InterpResult<'tcx, bool> { let this = self.eval_context_ref(); - let null = Scalar::ptr_null(this); + let null = Scalar::null_ptr(this); this.ptr_eq(val, null) } diff --git a/src/shims/env.rs b/src/shims/env.rs index 98f1e7e3cfa3..8a69e725abfc 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -98,7 +98,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // The offset is used to strip the "{name}=" part of the string. Scalar::from(var_ptr.offset(Size::from_bytes(u64::try_from(name.len()).unwrap().checked_add(1).unwrap()), this)?) } - None => Scalar::ptr_null(&*this.tcx), + None => Scalar::null_ptr(&*this.tcx), }) } @@ -305,7 +305,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Err(e) => this.set_last_error_from_io_error(e)?, } - Ok(Scalar::ptr_null(&*this.tcx)) + Ok(Scalar::null_ptr(&*this.tcx)) } fn chdir(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { @@ -343,7 +343,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Collect all the pointers to each variable in a vector. let mut vars: Vec> = this.machine.env_vars.map.values().map(|&ptr| ptr.into()).collect(); // Add the trailing null pointer. - vars.push(Scalar::ptr_null(this)); + vars.push(Scalar::null_ptr(this)); // Make an array with all these pointers inside Miri. let tcx = this.tcx; let vars_layout = diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 3e21e1d453fc..21c4b02e7085 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -47,7 +47,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn malloc(&mut self, size: u64, zero_init: bool, kind: MiriMemoryKind) -> Scalar { let this = self.eval_context_mut(); if size == 0 { - Scalar::ptr_null(this) + Scalar::null_ptr(this) } else { let align = this.min_align(size, kind); let ptr = this.memory.allocate(Size::from_bytes(size), align, kind.into()); @@ -78,7 +78,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let new_align = this.min_align(new_size, kind); if this.is_null(old_ptr)? { if new_size == 0 { - Ok(Scalar::ptr_null(this)) + Ok(Scalar::null_ptr(this)) } else { let new_ptr = this.memory.allocate(Size::from_bytes(new_size), new_align, kind.into()); @@ -88,7 +88,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let old_ptr = this.force_ptr(old_ptr)?; if new_size == 0 { this.memory.deallocate(old_ptr, None, kind.into())?; - Ok(Scalar::ptr_null(this)) + Ok(Scalar::null_ptr(this)) } else { let new_ptr = this.memory.reallocate( old_ptr, diff --git a/src/shims/fs.rs b/src/shims/fs.rs index debf412bdd41..5f8be275b2e4 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -420,7 +420,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We cap the number of read bytes to the largest value that we are able to fit in both the // host's and target's `isize`. This saves us from having to handle overflows later. - let count = count.min(this.isize_max() as u64).min(isize::MAX as u64); + let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64); if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { // This can never fail because `count` was capped to be smaller than @@ -474,7 +474,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We cap the number of written bytes to the largest value that we are able to fit in both the // host's and target's `isize`. This saves us from having to handle overflows later. - let count = count.min(this.isize_max() as u64).min(isize::MAX as u64); + let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64); if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; @@ -860,7 +860,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Err(e) => { this.set_last_error_from_io_error(e)?; - Ok(Scalar::ptr_null(this)) + Ok(Scalar::null_ptr(this)) } } } diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 1926cf93b687..731dc2fedc57 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -76,7 +76,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr_scalar = this.read_scalar(ptr_op)?.not_undef()?; // Default: no result. - let mut result = this.usize_max(); + let mut result = this.machine_usize_max(); if let Ok(ptr) = this.force_ptr(ptr_scalar) { // Only do anything if we can identify the allocation this goes to. let cur_align = diff --git a/src/shims/tls.rs b/src/shims/tls.rs index c753689f4c25..2727c3205040 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -77,7 +77,7 @@ impl<'tcx> TlsData<'tcx> { match self.keys.get(&key) { Some(&TlsEntry { data, .. }) => { trace!("TLS key {} loaded: {:?}", key, data); - Ok(data.unwrap_or_else(|| Scalar::ptr_null(cx).into())) + Ok(data.unwrap_or_else(|| Scalar::null_ptr(cx).into())) } None => throw_ub_format!("loading from a non-existing TLS key: {}", key), } @@ -173,7 +173,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); this.call_function( thread_callback, - &[Scalar::ptr_null(this).into(), reason.into(), Scalar::ptr_null(this).into()], + &[Scalar::null_ptr(this).into(), reason.into(), Scalar::null_ptr(this).into()], Some(ret_place), StackPopCleanup::None { cleanup: true }, )?; From a481b8f261a196ec8b4107273705a750c545856b Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Sat, 28 Mar 2020 14:42:22 -0400 Subject: [PATCH 1746/5092] partially implement 'set_last_error_from_io_error' for Windows --- src/helpers.rs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index d0a5fc958662..751d77a38978 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -71,6 +71,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .not_undef() } + /// Helper function to get a `windows` constant as a `Scalar`. + fn eval_windows(&mut self, name: &str) -> InterpResult<'tcx, Scalar> { + self.eval_context_mut() + .eval_path_scalar(&["std", "sys", "windows", "c", name])? + .not_undef() + } + /// Helper function to get a `libc` constant as an `i32`. fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { // TODO: Cache the result. @@ -428,11 +435,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } })? } else { - // FIXME: we have to implement the Windows equivalent of this. - throw_unsup_format!( - "setting the last OS error from an io::Error is unsupported for {}.", - target.target_os - ) + // FIXME: we have to finish implementing the Windows equivalent of this. + this.eval_windows(match e.kind() { + NotFound => "ERROR_FILE_NOT_FOUND", + _ => throw_unsup_format!( + "setting the last OS error from an io::Error is yet unsupported for {}.", + target.target_os + ) + })? }; this.set_last_error(last_error) } From 1141b21e50121976567cb54d6bd227bb7d5e1b61 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Sat, 28 Mar 2020 14:44:41 -0400 Subject: [PATCH 1747/5092] Windows shims for GetCurrentDirectoryW/SetCurrentDirectoryW --- src/shims/env.rs | 54 ++++++++++++- src/shims/foreign_items/windows.rs | 10 +++ src/shims/os_str.rs | 117 +++++++++++++++-------------- tests/run-pass/current_dir.rs | 7 +- 4 files changed, 127 insertions(+), 61 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 8a69e725abfc..78e7c37d9ce7 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -138,8 +138,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } None => { - let envvar_not_found = this.eval_path_scalar(&["std", "sys", "windows", "c", "ERROR_ENVVAR_NOT_FOUND"])?; - this.set_last_error(envvar_not_found.not_undef()?)?; + let envvar_not_found = this.eval_windows("ERROR_ENVVAR_NOT_FOUND")?; + this.set_last_error(envvar_not_found)?; 0 // return zero upon failure } }) @@ -289,6 +289,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); + let target_os = &this.tcx.sess.target.target.target_os; + assert!(target_os == "linux" || target_os == "macos", "`getcwd` is only available for the UNIX target family"); this.check_no_isolation("getcwd")?; @@ -308,8 +310,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(Scalar::null_ptr(&*this.tcx)) } + #[allow(non_snake_case)] + fn GetCurrentDirectoryW( + &mut self, + size_op: OpTy<'tcx, Tag>, // DWORD + buf_op: OpTy<'tcx, Tag>, // LPTSTR + ) -> InterpResult<'tcx, u32> { + let this = self.eval_context_mut(); + this.assert_target_os("windows", "GetCurrentDirectoryW"); + + this.check_no_isolation("GetCurrentDirectoryW")?; + + let size = u64::from(this.read_scalar(size_op)?.to_u32()?); + let buf = this.read_scalar(buf_op)?.not_undef()?; + + // If we cannot get the current directory, we return 0 + match env::current_dir() { + Ok(cwd) => { + let len = this.write_path_to_wide_str(&cwd, buf, size)?.1; + return Ok(u32::try_from(len).unwrap()) + } + Err(e) => this.set_last_error_from_io_error(e)?, + } + Ok(0) + } + fn chdir(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + let target_os = &this.tcx.sess.target.target.target_os; + assert!(target_os == "linux" || target_os == "macos", "`getcwd` is only available for the UNIX target family"); this.check_no_isolation("chdir")?; @@ -324,6 +353,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + #[allow(non_snake_case)] + fn SetCurrentDirectoryW ( + &mut self, + path_op: OpTy<'tcx, Tag> // LPCTSTR + ) -> InterpResult<'tcx, i32> { // Returns BOOL(i32 in Windows) + let this = self.eval_context_mut(); + this.assert_target_os("windows", "SetCurrentDirectoryW"); + + this.check_no_isolation("SetCurrentDirectoryW")?; + + let path = this.read_path_from_wide_str(this.read_scalar(path_op)?.not_undef()?)?; + + match env::set_current_dir(path) { + Ok(()) => Ok(1), + Err(e) => { + this.set_last_error_from_io_error(e)?; + Ok(0) + } + } + } + /// Updates the `environ` static. /// The first time it gets called, also initializes `extra.environ`. fn update_environ(&mut self) -> InterpResult<'tcx> { diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 7f3f1d0c2d2e..ecd1432df0cc 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -40,6 +40,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } + "GetCurrentDirectoryW" => { + let result = this.GetCurrentDirectoryW(args[0], args[1])?; + this.write_scalar(Scalar::from_u32(result), dest)?; + } + + "SetCurrentDirectoryW" => { + let result = this.SetCurrentDirectoryW(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + // File related shims "GetStdHandle" => { let which = this.read_scalar(args[0])?.to_i32()?; diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 316d5b0014a7..c513be4a61f6 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -177,36 +177,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx 'mir: 'a, { let this = self.eval_context_ref(); - let os_str = this.read_os_str_from_c_str(scalar)?; + let os_str: &'a OsStr = this.read_os_str_from_c_str(scalar)?; - #[cfg(windows)] - return Ok(if this.tcx.sess.target.target.target_os == "windows" { - // Windows-on-Windows, all fine. - Cow::Borrowed(Path::new(os_str)) - } else { - // Unix target, Windows host. Need to convert target '/' to host '\'. - let converted = os_str - .encode_wide() - .map(|wchar| if wchar == '/' as u16 { '\\' as u16 } else { wchar }) - .collect::>(); - Cow::Owned(PathBuf::from(OsString::from_wide(&converted))) - }); - #[cfg(unix)] - return Ok(if this.tcx.sess.target.target.target_os == "windows" { - // Windows target, Unix host. Need to convert target '\' to host '/'. - let converted = os_str - .as_bytes() - .iter() - .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) - .collect::>(); - Cow::Owned(PathBuf::from(OsString::from_vec(converted))) - } else { - // Unix-on-Unix, all is fine. - Cow::Borrowed(Path::new(os_str)) - }); + Ok(match convert_path_separator(os_str, &this.tcx.sess.target.target.target_os) { + Cow::Borrowed(x) => Cow::Borrowed(Path::new(x)), + Cow::Owned(y) => Cow::Owned(PathBuf::from(y)), + }) } - /// Write a Path to the machine memory, adjusting path separators if needed. + /// Read a null-terminated sequence of `u16`s, and perform path separator conversion if needed. + fn read_path_from_wide_str(&self, scalar: Scalar) -> InterpResult<'tcx, PathBuf> { + let this = self.eval_context_ref(); + let os_str: OsString = this.read_os_str_from_wide_str(scalar)?; + + Ok(PathBuf::from(&convert_path_separator(&os_str, &this.tcx.sess.target.target.target_os))) + } + + /// Write a Path to the machine memory (as a null-terminated sequence of bytes), + /// adjusting path separators if needed. fn write_path_to_c_str( &mut self, path: &Path, @@ -214,35 +202,52 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - - #[cfg(windows)] - let os_str = if this.tcx.sess.target.target.target_os == "windows" { - // Windows-on-Windows, all fine. - Cow::Borrowed(path.as_os_str()) - } else { - // Unix target, Windows host. Need to convert host '\\' to target '/'. - let converted = path - .as_os_str() - .encode_wide() - .map(|wchar| if wchar == '\\' as u16 { '/' as u16 } else { wchar }) - .collect::>(); - Cow::Owned(OsString::from_wide(&converted)) - }; - #[cfg(unix)] - let os_str = if this.tcx.sess.target.target.target_os == "windows" { - // Windows target, Unix host. Need to convert host '/' to target '\'. - let converted = path - .as_os_str() - .as_bytes() - .iter() - .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) - .collect::>(); - Cow::Owned(OsString::from_vec(converted)) - } else { - // Unix-on-Unix, all is fine. - Cow::Borrowed(path.as_os_str()) - }; - + let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os); this.write_os_str_to_c_str(&os_str, scalar, size) } + + /// Write a Path to the machine memory (as a null-terminated sequence of `u16`s), + /// adjusting path separators if needed. + fn write_path_to_wide_str( + &mut self, + path: &Path, + scalar: Scalar, + size: u64, + ) -> InterpResult<'tcx, (bool, u64)> { + let this = self.eval_context_mut(); + let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os); + this.write_os_str_to_wide_str(&os_str, scalar, size) + } +} + +/// Perform path separator conversion if needed. +fn convert_path_separator<'a>( + os_str: &'a OsStr, + target_os: &str, +) -> Cow<'a, OsStr> { + #[cfg(windows)] + return if target_os == "windows" { + // Windows-on-Windows, all fine. + Cow::Borrowed(os_str) + } else { + // Unix target, Windows host. Need to convert host '\\' to target '/'. + let converted = os_str + .encode_wide() + .map(|wchar| if wchar == '\\' as u16 { '/' as u16 } else { wchar }) + .collect::>(); + Cow::Owned(OsString::from_wide(&converted)) + }; + #[cfg(unix)] + return if target_os == "windows" { + // Windows target, Unix host. Need to convert host '/' to target '\'. + let converted = os_str + .as_bytes() + .iter() + .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) + .collect::>(); + Cow::Owned(OsString::from_vec(converted)) + } else { + // Unix-on-Unix, all is fine. + Cow::Borrowed(os_str) + }; } diff --git a/tests/run-pass/current_dir.rs b/tests/run-pass/current_dir.rs index 5e896659c85e..a88f820951ca 100644 --- a/tests/run-pass/current_dir.rs +++ b/tests/run-pass/current_dir.rs @@ -1,7 +1,6 @@ -// ignore-windows: TODO the windows hook is not done yet // compile-flags: -Zmiri-disable-isolation use std::env; -use std::path::Path; +use std::io::ErrorKind; fn main() { // Test that `getcwd` is available @@ -11,7 +10,9 @@ fn main() { // keep the current directory equal to `cwd`. let parent = cwd.parent().unwrap_or(&cwd); // Test that `chdir` is available - assert!(env::set_current_dir(&Path::new("..")).is_ok()); + assert!(env::set_current_dir("..").is_ok()); // Test that `..` goes to the parent directory assert_eq!(env::current_dir().unwrap(), parent); + // Test that `chdir` to a non-existing directory returns a proper error + assert_eq!(env::set_current_dir("thisdoesnotexist").unwrap_err().kind(), ErrorKind::NotFound); } From fe9ecb50d1dd1b8facd001e634449a9e8d52ad22 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Sun, 29 Mar 2020 09:46:13 -0400 Subject: [PATCH 1748/5092] Follow-up to reviews from RalfJung 1. Fix 'fn convert_path_separator' in src/shims/os_str.rs 2. Fix 'fn set_last_error_from_io_error' in src/helpers.rs 3. Minor comment fix for 'fn SetCurrentDirectoryW' in src/shims/env.rs --- src/helpers.rs | 10 +++++----- src/shims/env.rs | 2 +- src/shims/os_str.rs | 21 +++++++++++++-------- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 751d77a38978..5407eb120517 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -414,6 +414,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx use std::io::ErrorKind::*; let this = self.eval_context_mut(); let target = &this.tcx.sess.target.target; + let target_os = &target.target_os; let last_error = if target.options.target_family == Some("unix".to_owned()) { this.eval_libc(match e.kind() { ConnectionRefused => "ECONNREFUSED", @@ -434,15 +435,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("io error {} cannot be transformed into a raw os error", e) } })? - } else { + } else if target_os == "windows" { // FIXME: we have to finish implementing the Windows equivalent of this. this.eval_windows(match e.kind() { NotFound => "ERROR_FILE_NOT_FOUND", - _ => throw_unsup_format!( - "setting the last OS error from an io::Error is yet unsupported for {}.", - target.target_os - ) + _ => throw_unsup_format!("io error {} cannot be transformed into a raw os error", e) })? + } else { + throw_unsup_format!("setting the last OS error from an io::Error is unsupported for {}.", target_os) }; this.set_last_error(last_error) } diff --git a/src/shims/env.rs b/src/shims/env.rs index 78e7c37d9ce7..ce1be90ce699 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -357,7 +357,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn SetCurrentDirectoryW ( &mut self, path_op: OpTy<'tcx, Tag> // LPCTSTR - ) -> InterpResult<'tcx, i32> { // Returns BOOL(i32 in Windows) + ) -> InterpResult<'tcx, i32> { // Returns BOOL (i32 in Windows) let this = self.eval_context_mut(); this.assert_target_os("windows", "SetCurrentDirectoryW"); diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index c513be4a61f6..a182950f0065 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -179,7 +179,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); let os_str: &'a OsStr = this.read_os_str_from_c_str(scalar)?; - Ok(match convert_path_separator(os_str, &this.tcx.sess.target.target.target_os) { + Ok(match convert_path_separator(os_str, &this.tcx.sess.target.target.target_os, false) { Cow::Borrowed(x) => Cow::Borrowed(Path::new(x)), Cow::Owned(y) => Cow::Owned(PathBuf::from(y)), }) @@ -190,7 +190,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); let os_str: OsString = this.read_os_str_from_wide_str(scalar)?; - Ok(PathBuf::from(&convert_path_separator(&os_str, &this.tcx.sess.target.target.target_os))) + Ok(PathBuf::from(&convert_path_separator(&os_str, &this.tcx.sess.target.target.target_os, false))) } /// Write a Path to the machine memory (as a null-terminated sequence of bytes), @@ -202,7 +202,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os); + let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os, true); this.write_os_str_to_c_str(&os_str, scalar, size) } @@ -215,35 +215,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os); + let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os, true); this.write_os_str_to_wide_str(&os_str, scalar, size) } } /// Perform path separator conversion if needed. +/// if direction == true, Convert from 'host' to 'target'. +/// if direction == false, Convert from 'target' to 'host'. fn convert_path_separator<'a>( os_str: &'a OsStr, target_os: &str, + direction: bool, ) -> Cow<'a, OsStr> { #[cfg(windows)] return if target_os == "windows" { // Windows-on-Windows, all fine. Cow::Borrowed(os_str) } else { - // Unix target, Windows host. Need to convert host '\\' to target '/'. + // Unix target, Windows host. + let (from, to) = if direction { ('\\', '/') } else { ('/', '\\') }; let converted = os_str .encode_wide() - .map(|wchar| if wchar == '\\' as u16 { '/' as u16 } else { wchar }) + .map(|wchar| if wchar == from as u16 { to as u16 } else { wchar }) .collect::>(); Cow::Owned(OsString::from_wide(&converted)) }; #[cfg(unix)] return if target_os == "windows" { - // Windows target, Unix host. Need to convert host '/' to target '\'. + // Windows target, Unix host. + let (from, to) = if direction { ('/', '\\') } else { ('\\', '/') }; let converted = os_str .as_bytes() .iter() - .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) + .map(|&wchar| if wchar == from as u8 { to as u8 } else { wchar }) .collect::>(); Cow::Owned(OsString::from_vec(converted)) } else { From 7e0cc8307e80821cdc76c379805245b256071a89 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Sun, 29 Mar 2020 10:21:02 -0400 Subject: [PATCH 1749/5092] fix 'magic boolean' to enum --- src/shims/os_str.rs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index a182950f0065..59cedc6e9df7 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -179,7 +179,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); let os_str: &'a OsStr = this.read_os_str_from_c_str(scalar)?; - Ok(match convert_path_separator(os_str, &this.tcx.sess.target.target.target_os, false) { + Ok(match convert_path_separator(os_str, &this.tcx.sess.target.target.target_os, PathConversionDirection::TargetToHost) { Cow::Borrowed(x) => Cow::Borrowed(Path::new(x)), Cow::Owned(y) => Cow::Owned(PathBuf::from(y)), }) @@ -190,7 +190,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); let os_str: OsString = this.read_os_str_from_wide_str(scalar)?; - Ok(PathBuf::from(&convert_path_separator(&os_str, &this.tcx.sess.target.target.target_os, false))) + Ok(PathBuf::from(&convert_path_separator(&os_str, &this.tcx.sess.target.target.target_os, PathConversionDirection::TargetToHost))) } /// Write a Path to the machine memory (as a null-terminated sequence of bytes), @@ -202,7 +202,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os, true); + let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os, PathConversionDirection::HostToTarget); this.write_os_str_to_c_str(&os_str, scalar, size) } @@ -215,18 +215,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os, true); + let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os, PathConversionDirection::HostToTarget); this.write_os_str_to_wide_str(&os_str, scalar, size) } } +enum PathConversionDirection { + HostToTarget, + TargetToHost, +} + /// Perform path separator conversion if needed. -/// if direction == true, Convert from 'host' to 'target'. -/// if direction == false, Convert from 'target' to 'host'. fn convert_path_separator<'a>( os_str: &'a OsStr, target_os: &str, - direction: bool, + direction: PathConversionDirection, ) -> Cow<'a, OsStr> { #[cfg(windows)] return if target_os == "windows" { @@ -234,7 +237,10 @@ fn convert_path_separator<'a>( Cow::Borrowed(os_str) } else { // Unix target, Windows host. - let (from, to) = if direction { ('\\', '/') } else { ('/', '\\') }; + let (from, to) = match direction { + PathConversionDirection::HostToTarget => ('\\', '/'), + PathConversionDirection::TargetToHost => ('/', '\\'), + }; let converted = os_str .encode_wide() .map(|wchar| if wchar == from as u16 { to as u16 } else { wchar }) @@ -244,7 +250,10 @@ fn convert_path_separator<'a>( #[cfg(unix)] return if target_os == "windows" { // Windows target, Unix host. - let (from, to) = if direction { ('/', '\\') } else { ('\\', '/') }; + let (from, to) = match direction { + PathConversionDirection::HostToTarget => ('/', '\\'), + PathConversionDirection::TargetToHost => ('\\', '/'), + }; let converted = os_str .as_bytes() .iter() From 1667ded0d2bc0044f84f2e56aa77f76986199058 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Sun, 29 Mar 2020 11:15:53 -0400 Subject: [PATCH 1750/5092] fix fn GetCurrentDirectoryW + clarify return types of Windows shims --- src/shims/env.rs | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index ce1be90ce699..dfbeabf2a12b 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -105,10 +105,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn GetEnvironmentVariableW( &mut self, - name_op: OpTy<'tcx, Tag>, // LPCWSTR - buf_op: OpTy<'tcx, Tag>, // LPWSTR - size_op: OpTy<'tcx, Tag>, // DWORD - ) -> InterpResult<'tcx, u32> { + name_op: OpTy<'tcx, Tag>, // LPCWSTR + buf_op: OpTy<'tcx, Tag>, // LPWSTR + size_op: OpTy<'tcx, Tag>, // DWORD + ) -> InterpResult<'tcx, u32> { // Returns DWORD (u32 in Windows) let this = self.eval_context_mut(); this.assert_target_os("windows", "GetEnvironmentVariableW"); @@ -125,17 +125,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf_ptr = this.read_scalar(buf_op)?.not_undef()?; // `buf_size` represents the size in characters. let buf_size = u64::from(this.read_scalar(size_op)?.to_u32()?); - let (success, len) = this.write_os_str_to_wide_str(&var, buf_ptr, buf_size)?; - - if success { - // If the function succeeds, the return value is the number of characters stored in the buffer pointed to by lpBuffer, - // not including the terminating null character. - u32::try_from(len).unwrap() - } else { - // If lpBuffer is not large enough to hold the data, the return value is the buffer size, in characters, - // required to hold the string and its terminating null character and the contents of lpBuffer are undefined. - u32::try_from(len).unwrap().checked_add(1).unwrap() - } + HowWasBufferSize(this.write_os_str_to_wide_str(&var, buf_ptr, buf_size)?) } None => { let envvar_not_found = this.eval_windows("ERROR_ENVVAR_NOT_FOUND")?; @@ -326,10 +316,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If we cannot get the current directory, we return 0 match env::current_dir() { - Ok(cwd) => { - let len = this.write_path_to_wide_str(&cwd, buf, size)?.1; - return Ok(u32::try_from(len).unwrap()) - } + Ok(cwd) => + return Ok(HowWasBufferSize(this.write_path_to_wide_str(&cwd, buf, size)?)), Err(e) => this.set_last_error_from_io_error(e)?, } Ok(0) @@ -411,3 +399,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } } + +// Local helper function to be used in Windows shims +#[allow(non_snake_case)] +fn HowWasBufferSize((success, len): (bool, u64)) -> u32 { + if success { + // If the function succeeds, the return value is the number of characters stored in the buffer pointed to by lpBuffer, + // not including the terminating null character. + u32::try_from(len).unwrap() + } else { + // If lpBuffer is not large enough to hold the data, the return value is the buffer size, in characters, + // required to hold the string and its terminating null character and the contents of lpBuffer are undefined. + u32::try_from(len.checked_add(1).unwrap()).unwrap() + } +} From 1b0abc5797fa4e3d32a74b80ed653da1a9ab98ef Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Sun, 29 Mar 2020 13:10:23 -0400 Subject: [PATCH 1751/5092] small refactorings to 'src/shims/os_str.rs' & 'src/shims/env.rs' --- src/shims/env.rs | 17 +++---- src/shims/os_str.rs | 105 ++++++++++++++++++++++---------------------- 2 files changed, 62 insertions(+), 60 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index dfbeabf2a12b..350d76bc9dac 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -125,7 +125,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf_ptr = this.read_scalar(buf_op)?.not_undef()?; // `buf_size` represents the size in characters. let buf_size = u64::from(this.read_scalar(size_op)?.to_u32()?); - HowWasBufferSize(this.write_os_str_to_wide_str(&var, buf_ptr, buf_size)?) + windows_check_buffer_size(this.write_os_str_to_wide_str(&var, buf_ptr, buf_size)?) } None => { let envvar_not_found = this.eval_windows("ERROR_ENVVAR_NOT_FOUND")?; @@ -317,7 +317,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If we cannot get the current directory, we return 0 match env::current_dir() { Ok(cwd) => - return Ok(HowWasBufferSize(this.write_path_to_wide_str(&cwd, buf, size)?)), + return Ok(windows_check_buffer_size(this.write_path_to_wide_str(&cwd, buf, size)?)), Err(e) => this.set_last_error_from_io_error(e)?, } Ok(0) @@ -400,16 +400,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } -// Local helper function to be used in Windows shims -#[allow(non_snake_case)] -fn HowWasBufferSize((success, len): (bool, u64)) -> u32 { +/// Check whether an operation that writes to a target buffer was successful. +/// Accordingly select return value. +/// Local helper function to be used in Windows shims. +fn windows_check_buffer_size((success, len): (bool, u64)) -> u32 { if success { - // If the function succeeds, the return value is the number of characters stored in the buffer pointed to by lpBuffer, + // If the function succeeds, the return value is the number of characters stored in the target buffer, // not including the terminating null character. u32::try_from(len).unwrap() } else { - // If lpBuffer is not large enough to hold the data, the return value is the buffer size, in characters, - // required to hold the string and its terminating null character and the contents of lpBuffer are undefined. + // If the target buffer was not large enough to hold the data, the return value is the buffer size, in characters, + // required to hold the string and its terminating null character. u32::try_from(len.checked_add(1).unwrap()).unwrap() } } diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 59cedc6e9df7..74932ef6ca4e 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -13,6 +13,53 @@ use rustc::ty::layout::LayoutOf; use crate::*; +/// Represent how path separator conversion should be done. +enum Pathconversion { + HostToTarget, + TargetToHost, +} + +/// Perform path separator conversion if needed. +fn convert_path_separator<'a>( + os_str: &'a OsStr, + target_os: &str, + direction: Pathconversion, +) -> Cow<'a, OsStr> { + #[cfg(windows)] + return if target_os == "windows" { + // Windows-on-Windows, all fine. + Cow::Borrowed(os_str) + } else { + // Unix target, Windows host. + let (from, to) = match direction { + Pathconversion::HostToTarget => ('\\', '/'), + Pathconversion::TargetToHost => ('/', '\\'), + }; + let converted = os_str + .encode_wide() + .map(|wchar| if wchar == from as u16 { to as u16 } else { wchar }) + .collect::>(); + Cow::Owned(OsString::from_wide(&converted)) + }; + #[cfg(unix)] + return if target_os == "windows" { + // Windows target, Unix host. + let (from, to) = match direction { + Pathconversion::HostToTarget => ('/', '\\'), + Pathconversion::TargetToHost => ('\\', '/'), + }; + let converted = os_str + .as_bytes() + .iter() + .map(|&wchar| if wchar == from as u8 { to as u8 } else { wchar }) + .collect::>(); + Cow::Owned(OsString::from_vec(converted)) + } else { + // Unix-on-Unix, all is fine. + Cow::Borrowed(os_str) + }; +} + impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what @@ -177,9 +224,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx 'mir: 'a, { let this = self.eval_context_ref(); - let os_str: &'a OsStr = this.read_os_str_from_c_str(scalar)?; + let os_str = this.read_os_str_from_c_str(scalar)?; - Ok(match convert_path_separator(os_str, &this.tcx.sess.target.target.target_os, PathConversionDirection::TargetToHost) { + Ok(match convert_path_separator(os_str, &this.tcx.sess.target.target.target_os, Pathconversion::TargetToHost) { Cow::Borrowed(x) => Cow::Borrowed(Path::new(x)), Cow::Owned(y) => Cow::Owned(PathBuf::from(y)), }) @@ -188,9 +235,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Read a null-terminated sequence of `u16`s, and perform path separator conversion if needed. fn read_path_from_wide_str(&self, scalar: Scalar) -> InterpResult<'tcx, PathBuf> { let this = self.eval_context_ref(); - let os_str: OsString = this.read_os_str_from_wide_str(scalar)?; + let os_str = this.read_os_str_from_wide_str(scalar)?; - Ok(PathBuf::from(&convert_path_separator(&os_str, &this.tcx.sess.target.target.target_os, PathConversionDirection::TargetToHost))) + Ok(PathBuf::from(&convert_path_separator(&os_str, &this.tcx.sess.target.target.target_os, Pathconversion::TargetToHost))) } /// Write a Path to the machine memory (as a null-terminated sequence of bytes), @@ -202,7 +249,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os, PathConversionDirection::HostToTarget); + let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os, Pathconversion::HostToTarget); this.write_os_str_to_c_str(&os_str, scalar, size) } @@ -215,53 +262,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os, PathConversionDirection::HostToTarget); + let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os, Pathconversion::HostToTarget); this.write_os_str_to_wide_str(&os_str, scalar, size) } } - -enum PathConversionDirection { - HostToTarget, - TargetToHost, -} - -/// Perform path separator conversion if needed. -fn convert_path_separator<'a>( - os_str: &'a OsStr, - target_os: &str, - direction: PathConversionDirection, -) -> Cow<'a, OsStr> { - #[cfg(windows)] - return if target_os == "windows" { - // Windows-on-Windows, all fine. - Cow::Borrowed(os_str) - } else { - // Unix target, Windows host. - let (from, to) = match direction { - PathConversionDirection::HostToTarget => ('\\', '/'), - PathConversionDirection::TargetToHost => ('/', '\\'), - }; - let converted = os_str - .encode_wide() - .map(|wchar| if wchar == from as u16 { to as u16 } else { wchar }) - .collect::>(); - Cow::Owned(OsString::from_wide(&converted)) - }; - #[cfg(unix)] - return if target_os == "windows" { - // Windows target, Unix host. - let (from, to) = match direction { - PathConversionDirection::HostToTarget => ('/', '\\'), - PathConversionDirection::TargetToHost => ('\\', '/'), - }; - let converted = os_str - .as_bytes() - .iter() - .map(|&wchar| if wchar == from as u8 { to as u8 } else { wchar }) - .collect::>(); - Cow::Owned(OsString::from_vec(converted)) - } else { - // Unix-on-Unix, all is fine. - Cow::Borrowed(os_str) - }; -} From 9bdb4bbbbf17c2d94eece96ddc6114a3c9104f73 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Sun, 29 Mar 2020 13:13:42 -0400 Subject: [PATCH 1752/5092] Move definition of 'fn windows_check_buffer_size' to top of 'src/shims/env.rs' --- src/shims/env.rs | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 350d76bc9dac..5846f51b9042 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -10,6 +10,21 @@ use rustc_data_structures::fx::FxHashMap; use rustc::ty::layout::Size; use rustc_mir::interpret::Pointer; +/// Check whether an operation that writes to a target buffer was successful. +/// Accordingly select return value. +/// Local helper function to be used in Windows shims. +fn windows_check_buffer_size((success, len): (bool, u64)) -> u32 { + if success { + // If the function succeeds, the return value is the number of characters stored in the target buffer, + // not including the terminating null character. + u32::try_from(len).unwrap() + } else { + // If the target buffer was not large enough to hold the data, the return value is the buffer size, in characters, + // required to hold the string and its terminating null character. + u32::try_from(len.checked_add(1).unwrap()).unwrap() + } +} + #[derive(Default)] pub struct EnvVars<'tcx> { /// Stores pointers to the environment variables. These variables must be stored as @@ -399,18 +414,3 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } } - -/// Check whether an operation that writes to a target buffer was successful. -/// Accordingly select return value. -/// Local helper function to be used in Windows shims. -fn windows_check_buffer_size((success, len): (bool, u64)) -> u32 { - if success { - // If the function succeeds, the return value is the number of characters stored in the target buffer, - // not including the terminating null character. - u32::try_from(len).unwrap() - } else { - // If the target buffer was not large enough to hold the data, the return value is the buffer size, in characters, - // required to hold the string and its terminating null character. - u32::try_from(len.checked_add(1).unwrap()).unwrap() - } -} From a458cf3fe619764abd938eb6d5b27dd261bd8127 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Sun, 29 Mar 2020 14:19:59 -0400 Subject: [PATCH 1753/5092] make 'fn convert_path_separator' to take Cow<> (to remove unnecessary allocation) --- src/shims/os_str.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 74932ef6ca4e..0f81c24c252f 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -21,14 +21,14 @@ enum Pathconversion { /// Perform path separator conversion if needed. fn convert_path_separator<'a>( - os_str: &'a OsStr, + os_str: Cow<'a, OsStr>, target_os: &str, direction: Pathconversion, ) -> Cow<'a, OsStr> { #[cfg(windows)] return if target_os == "windows" { // Windows-on-Windows, all fine. - Cow::Borrowed(os_str) + os_str } else { // Unix target, Windows host. let (from, to) = match direction { @@ -56,7 +56,7 @@ fn convert_path_separator<'a>( Cow::Owned(OsString::from_vec(converted)) } else { // Unix-on-Unix, all is fine. - Cow::Borrowed(os_str) + os_str }; } @@ -226,7 +226,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); let os_str = this.read_os_str_from_c_str(scalar)?; - Ok(match convert_path_separator(os_str, &this.tcx.sess.target.target.target_os, Pathconversion::TargetToHost) { + Ok(match convert_path_separator(Cow::Borrowed(os_str), &this.tcx.sess.target.target.target_os, Pathconversion::TargetToHost) { Cow::Borrowed(x) => Cow::Borrowed(Path::new(x)), Cow::Owned(y) => Cow::Owned(PathBuf::from(y)), }) @@ -237,7 +237,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); let os_str = this.read_os_str_from_wide_str(scalar)?; - Ok(PathBuf::from(&convert_path_separator(&os_str, &this.tcx.sess.target.target.target_os, Pathconversion::TargetToHost))) + Ok(PathBuf::from(&convert_path_separator(Cow::Borrowed(&os_str), &this.tcx.sess.target.target.target_os, Pathconversion::TargetToHost))) } /// Write a Path to the machine memory (as a null-terminated sequence of bytes), @@ -249,7 +249,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os, Pathconversion::HostToTarget); + let os_str = convert_path_separator(Cow::Borrowed(path.as_os_str()), &this.tcx.sess.target.target.target_os, Pathconversion::HostToTarget); this.write_os_str_to_c_str(&os_str, scalar, size) } @@ -262,7 +262,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os, Pathconversion::HostToTarget); + let os_str = convert_path_separator(Cow::Borrowed(path.as_os_str()), &this.tcx.sess.target.target.target_os, Pathconversion::HostToTarget); this.write_os_str_to_wide_str(&os_str, scalar, size) } } From ed1305d986a3fff39da36de2c7ed6a3179d33c9a Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Sun, 29 Mar 2020 16:01:07 -0400 Subject: [PATCH 1754/5092] fix fn read_path_from_wide_str --- src/shims/os_str.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 0f81c24c252f..49afa3bdc362 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -237,7 +237,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); let os_str = this.read_os_str_from_wide_str(scalar)?; - Ok(PathBuf::from(&convert_path_separator(Cow::Borrowed(&os_str), &this.tcx.sess.target.target.target_os, Pathconversion::TargetToHost))) + Ok(convert_path_separator(Cow::Owned(os_str), &this.tcx.sess.target.target.target_os, Pathconversion::TargetToHost).into_owned().into()) } /// Write a Path to the machine memory (as a null-terminated sequence of bytes), From 808709c2889e11b079205fbbf830cd58d1f3711b Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 29 Mar 2020 16:03:05 -0500 Subject: [PATCH 1755/5092] Add support for OpenOptions::create_new()/O_EXCL --- src/shims/fs.rs | 9 ++++++++- tests/run-pass/fs.rs | 19 ++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 5f8be275b2e4..04ca538f8b6b 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -288,8 +288,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let o_creat = this.eval_libc_i32("O_CREAT")?; if flag & o_creat != 0 { - options.create(true); mirror |= o_creat; + + let o_excl = this.eval_libc_i32("O_EXCL")?; + if flag & o_excl != 0 { + mirror |= o_excl; + options.create_new(true); + } else { + options.create(true); + } } let o_cloexec = this.eval_libc_i32("O_CLOEXEC")?; if flag & o_cloexec != 0 { diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 104ba46c3e45..d8b6e5b44575 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -1,13 +1,16 @@ // ignore-windows: File handling is not implemented yet // compile-flags: -Zmiri-disable-isolation -use std::fs::{File, create_dir, read_dir, remove_dir, remove_dir_all, remove_file, rename}; +use std::fs::{ + File, create_dir, OpenOptions, read_dir, remove_dir, remove_dir_all, remove_file, rename, +}; use std::io::{Read, Write, ErrorKind, Result, Seek, SeekFrom}; use std::path::{PathBuf, Path}; fn main() { test_file(); test_file_clone(); + test_file_create_new(); test_seek(); test_metadata(); test_symlink(); @@ -85,6 +88,20 @@ fn test_file_clone() { remove_file(&path).unwrap(); } +fn test_file_create_new() { + let path = prepare("miri_test_fs_file_create_new.txt"); + + // Creating a new file that doesn't yet exist should succeed. + OpenOptions::new().write(true).create_new(true).open(&path).unwrap(); + // Creating a new file that already exists should fail. + assert_eq!(ErrorKind::AlreadyExists, OpenOptions::new().write(true).create_new(true).open(&path).unwrap_err().kind()); + // Optionally creating a new file that already exists should succeed. + OpenOptions::new().write(true).create(true).open(&path).unwrap(); + + // Clean up + remove_file(&path).unwrap(); +} + fn test_seek() { let bytes = b"Hello, entire World!\n"; let path = prepare_with_content("miri_test_fs_seek.txt", bytes); From 5ff7eef2ffbaeef58293e757b0b092ff1afdf411 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 Mar 2020 10:23:04 +0200 Subject: [PATCH 1756/5092] rustup; fix for TyLayout rename --- rust-version | 2 +- src/helpers.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index 0b3196a7a280..42644dc12140 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -150322f86d441752874a8bed603d71119f190b8b +0afdf43dc1d9be4c8b422840166b51dd99e56a16 diff --git a/src/helpers.rs b/src/helpers.rs index 5407eb120517..fc9bb19c882a 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -4,7 +4,7 @@ use std::mem; use rustc::mir; use rustc::ty::{ self, - layout::{self, LayoutOf, Size, TyLayout}, + layout::{self, LayoutOf, Size, TyAndLayout}, List, TyCtxt, }; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; @@ -84,8 +84,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx self.eval_libc(name)?.to_i32() } - /// Helper function to get the `TyLayout` of a `libc` type - fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyLayout<'tcx>> { + /// Helper function to get the `TyAndLayout` of a `libc` type + fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> { let this = self.eval_context_mut(); let ty = this.resolve_path(&["libc", name]).monomorphic_ty(*this.tcx); this.layout_of(ty) @@ -469,7 +469,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx pub fn immty_from_int_checked<'tcx>( int: impl Into, - layout: TyLayout<'tcx>, + layout: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let int = int.into(); Ok(ImmTy::try_from_int(int, layout).ok_or_else(|| { @@ -479,7 +479,7 @@ pub fn immty_from_int_checked<'tcx>( pub fn immty_from_uint_checked<'tcx>( int: impl Into, - layout: TyLayout<'tcx>, + layout: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let int = int.into(); Ok(ImmTy::try_from_uint(int, layout).ok_or_else(|| { From 846ce3c2616ea2fe1a3d5f040953dc5b50d2b2a0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 Mar 2020 10:23:16 +0200 Subject: [PATCH 1757/5092] test const-generic Vec::from(array) --- tests/run-pass/arrays.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/arrays.rs b/tests/run-pass/arrays.rs index b760d515395c..9589ffa1724c 100644 --- a/tests/run-pass/arrays.rs +++ b/tests/run-pass/arrays.rs @@ -35,7 +35,7 @@ fn slice_index() -> u8 { arr[5] } -fn try_from() { +fn from() { const N: usize = 16; type Array = [u8; N]; let array: Array = [0; N]; @@ -43,6 +43,9 @@ fn try_from() { let result = <&Array>::try_from(slice); assert_eq!(&array, result.unwrap()); + + let vec = Vec::from(array); + assert_eq!(vec.len(), N); } fn eq() { @@ -69,7 +72,7 @@ fn main() { assert_eq!(array_array(), [[5, 4], [3, 2], [1, 0]]); assert_eq!(array_repeat(), [42; 8]); assert_eq!(mini_array(), [42]); - try_from(); + from(); eq(); debug(); } From 8948a29a4cb3c6940e3863886e99bacfa1f325ae Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 Mar 2020 11:07:32 +0200 Subject: [PATCH 1758/5092] adjust for librustc rename; reduce 'extern crate' to rustc crates --- CONTRIBUTING.md | 2 +- benches/helpers/miri_helper.rs | 10 +++------- rust-version | 2 +- src/bin/miri-rustc-tests.rs | 12 +++++------- src/bin/miri.rs | 13 ++++--------- src/diagnostics.rs | 2 ++ src/eval.rs | 4 ++-- src/helpers.rs | 6 ++++-- src/intptrcast.rs | 3 ++- src/lib.rs | 6 +----- src/machine.rs | 5 +++-- src/operator.rs | 8 +++++--- src/range_map.rs | 2 +- src/shims/dlsym.rs | 2 +- src/shims/env.rs | 2 +- src/shims/foreign_items.rs | 6 +++--- src/shims/foreign_items/posix.rs | 6 ++++-- src/shims/foreign_items/posix/linux.rs | 2 +- src/shims/foreign_items/posix/macos.rs | 2 +- src/shims/foreign_items/windows.rs | 4 ++-- src/shims/fs.rs | 2 +- src/shims/intrinsics.rs | 6 +++--- src/shims/mod.rs | 4 +++- src/shims/os_str.rs | 2 +- src/shims/panic.rs | 8 +++++--- src/shims/tls.rs | 4 +++- src/stacked_borrows.rs | 6 ++++-- 27 files changed, 67 insertions(+), 64 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 573f9f6ef6e4..c7bfe6ccf1c1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -79,7 +79,7 @@ MIRI_LOG=info ./miri run tests/run-pass/vecs.rs ``` Setting `MIRI_LOG` like this will configure logging for Miri itself as well as -the `rustc::mir::interpret` and `rustc_mir::interpret` modules in rustc. You +the `rustc_middle::mir::interpret` and `rustc_mir::interpret` modules in rustc. You can also do more targeted configuration, e.g. the following helps debug the stacked borrows implementation: diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index b478a7d23eb9..589a95b668f3 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -1,17 +1,13 @@ -extern crate getopts; -extern crate miri; -extern crate rustc; extern crate rustc_driver; extern crate rustc_hir; extern crate rustc_interface; -extern crate test; -use self::miri::eval_main; -use crate::test::Bencher; use rustc_hir::def_id::LOCAL_CRATE; use rustc_driver::Compilation; use rustc_interface::{interface, Queries}; +use crate::test::Bencher; + struct MiriCompilerCalls<'a> { bencher: &'a mut Bencher, } @@ -30,7 +26,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { self.bencher.iter(|| { let config = miri::MiriConfig::default(); - eval_main(tcx, entry_def_id, config); + miri::eval_main(tcx, entry_def_id, config); }); }); diff --git a/rust-version b/rust-version index 42644dc12140..4f4cff76583b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0afdf43dc1d9be4c8b422840166b51dd99e56a16 +8926bb497d9b127eb318aea5aed0e745d8381591 diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index ab692e18f909..97292cf1dbe5 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -1,6 +1,6 @@ #![feature(rustc_private)] -extern crate miri; -extern crate rustc; + +extern crate rustc_middle; extern crate rustc_driver; extern crate rustc_hir; extern crate rustc_interface; @@ -11,15 +11,13 @@ use std::io::Write; use std::path::Path; use std::sync::{Arc, Mutex}; -use rustc::ty::TyCtxt; +use rustc_middle::ty::TyCtxt; use rustc_driver::Compilation; use rustc_hir as hir; use rustc_hir::def_id::LOCAL_CRATE; use rustc_hir::itemlikevisit; use rustc_interface::{interface, Queries}; -use miri::MiriConfig; - struct MiriCompilerCalls { /// whether we are building for the host host_target: bool, @@ -42,7 +40,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { .iter() .any(|attr| attr.check_name(rustc_span::symbol::sym::test)) { - let config = MiriConfig::default(); + let config = miri::MiriConfig::default(); let did = self.0.hir().body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); miri::eval_main(self.0, did, config); @@ -55,7 +53,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { } tcx.hir().krate().visit_all_item_likes(&mut Visitor(tcx)); } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { - let config = MiriConfig::default(); + let config = miri::MiriConfig::default(); miri::eval_main(tcx, entry_def_id, config); compiler.session().abort_if_errors(); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 4a54867c9964..14d78053c0fd 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -1,12 +1,6 @@ #![feature(rustc_private)] -extern crate env_logger; -extern crate getopts; -#[macro_use] -extern crate log; -extern crate log_settings; -extern crate miri; -extern crate rustc; +extern crate rustc_middle; extern crate rustc_driver; extern crate rustc_hir; extern crate rustc_interface; @@ -17,12 +11,13 @@ use std::env; use std::str::FromStr; use hex::FromHexError; +use log::debug; use rustc_session::CtfeBacktrace; use rustc_driver::Compilation; use rustc_hir::def_id::LOCAL_CRATE; use rustc_interface::{interface, Queries}; -use rustc::ty::TyCtxt; +use rustc_middle::ty::TyCtxt; struct MiriCompilerCalls { miri_config: miri::MiriConfig, @@ -84,7 +79,7 @@ fn init_late_loggers(tcx: TyCtxt<'_>) { if log::Level::from_str(&var).is_ok() { env::set_var( "RUSTC_LOG", - &format!("rustc::mir::interpret={0},rustc_mir::interpret={0}", var), + &format!("rustc_middle::mir::interpret={0},rustc_mir::interpret={0}", var), ); } else { env::set_var("RUSTC_LOG", &var); diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 2e4023e0b5bf..a528960cb262 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -1,6 +1,8 @@ use std::cell::RefCell; use std::fmt; +use log::trace; + use rustc_span::DUMMY_SP; use crate::*; diff --git a/src/eval.rs b/src/eval.rs index 9838bd1e8cc2..a4867bd5de46 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -6,8 +6,8 @@ use std::convert::TryFrom; use rand::rngs::StdRng; use rand::SeedableRng; -use rustc::ty::layout::LayoutOf; -use rustc::ty::{self, TyCtxt}; +use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::{self, TyCtxt}; use rustc_hir::def_id::DefId; use crate::*; diff --git a/src/helpers.rs b/src/helpers.rs index fc9bb19c882a..15f1b286de22 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,8 +1,10 @@ use std::convert::TryFrom; use std::mem; -use rustc::mir; -use rustc::ty::{ +use log::trace; + +use rustc_middle::mir; +use rustc_middle::ty::{ self, layout::{self, LayoutOf, Size, TyAndLayout}, List, TyCtxt, diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 20a3b7998047..8eb28e4f4700 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -2,10 +2,11 @@ use std::cell::RefCell; use std::cmp::max; use std::collections::hash_map::Entry; +use log::trace; use rand::Rng; use rustc_data_structures::fx::FxHashMap; -use rustc::ty::layout::HasDataLayout; +use rustc_middle::ty::layout::HasDataLayout; use rustc_mir::interpret::{AllocCheck, AllocId, InterpResult, Memory, Machine, Pointer, PointerArithmetic}; use rustc_target::abi::Size; diff --git a/src/lib.rs b/src/lib.rs index 4fa78b7ec88e..c04fbfeab98c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,13 +7,9 @@ #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] -#[macro_use] -extern crate log; -// From rustc. extern crate rustc_apfloat; extern crate rustc_ast; -#[macro_use] -extern crate rustc; +#[macro_use] extern crate rustc_middle; extern crate rustc_data_structures; extern crate rustc_hir; extern crate rustc_mir; diff --git a/src/machine.rs b/src/machine.rs index 84329b8fd3cd..4b7f3a76569f 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -7,11 +7,12 @@ use std::num::NonZeroU64; use std::rc::Rc; use std::time::Instant; +use log::trace; use rand::rngs::StdRng; use rustc_data_structures::fx::FxHashMap; -use rustc::mir; -use rustc::ty::{ +use rustc_middle::mir; +use rustc_middle::ty::{ self, layout::{LayoutOf, Size}, Ty, diff --git a/src/operator.rs b/src/operator.rs index c494e4ff8c72..2232be713ed5 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,7 +1,9 @@ use std::convert::TryFrom; -use rustc::mir; -use rustc::ty::{ +use log::trace; + +use rustc_middle::mir; +use rustc_middle::ty::{ layout::{LayoutOf, Size}, Ty, }; @@ -33,7 +35,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { left: ImmTy<'tcx, Tag>, right: ImmTy<'tcx, Tag>, ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { - use rustc::mir::BinOp::*; + use rustc_middle::mir::BinOp::*; trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); diff --git a/src/range_map.rs b/src/range_map.rs index 01abaef27fd2..1d12d8a1ba65 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -7,7 +7,7 @@ use std::ops; -use rustc::ty::layout::Size; +use rustc_middle::ty::layout::Size; #[derive(Clone, Debug)] struct Elem { diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index b0e1850ec55d..b5fe3cb7229c 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -1,4 +1,4 @@ -use rustc::mir; +use rustc_middle::mir; use crate::*; diff --git a/src/shims/env.rs b/src/shims/env.rs index 5846f51b9042..76d1de5d9a64 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -7,7 +7,7 @@ use crate::rustc_target::abi::LayoutOf; use crate::*; use rustc_data_structures::fx::FxHashMap; -use rustc::ty::layout::Size; +use rustc_middle::ty::layout::Size; use rustc_mir::interpret::Pointer; /// Check whether an operation that writes to a target buffer was successful. diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 21c4b02e7085..da2f9d439c7e 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -4,9 +4,9 @@ mod posix; use std::{convert::{TryInto, TryFrom}, iter}; use rustc_hir::def_id::DefId; -use rustc::mir; -use rustc::ty; -use rustc::ty::layout::{Align, Size}; +use rustc_middle::mir; +use rustc_middle::ty; +use rustc_middle::ty::layout::{Align, Size}; use rustc_apfloat::Float; use rustc_span::symbol::sym; use rustc_ast::attr; diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 1a9e91eded7f..28161592985a 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -3,9 +3,11 @@ mod macos; use std::convert::TryFrom; +use log::trace; + use crate::*; -use rustc::mir; -use rustc::ty::layout::{Align, LayoutOf, Size}; +use rustc_middle::mir; +use rustc_middle::ty::layout::{Align, LayoutOf, Size}; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index f56d5b3959c7..286bd5798b04 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -1,5 +1,5 @@ use crate::*; -use rustc::mir; +use rustc_middle::mir; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index cc58924a54ab..44c45d90c198 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -1,5 +1,5 @@ use crate::*; -use rustc::mir; +use rustc_middle::mir; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index ecd1432df0cc..f39d477f8278 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -1,6 +1,6 @@ use crate::*; -use rustc::mir; -use rustc::ty::layout::Size; +use rustc_middle::mir; +use rustc_middle::ty::layout::Size; use std::iter; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 5f8be275b2e4..75e90384fd56 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -6,7 +6,7 @@ use std::path::Path; use std::time::SystemTime; use rustc_data_structures::fx::FxHashMap; -use rustc::ty::layout::{Align, LayoutOf, Size}; +use rustc_middle::ty::layout::{Align, LayoutOf, Size}; use crate::stacked_borrows::Tag; use crate::*; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index fda52429e515..641b8b256363 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -1,9 +1,9 @@ use std::iter; use std::convert::TryFrom; -use rustc::mir; -use rustc::ty; -use rustc::ty::layout::{Align, LayoutOf}; +use rustc_middle::mir; +use rustc_middle::ty; +use rustc_middle::ty::layout::{Align, LayoutOf}; use rustc_apfloat::Float; use rustc_span::source_map::Span; diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 731dc2fedc57..e5db537cff1f 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -10,7 +10,9 @@ pub mod tls; use std::convert::TryFrom; -use rustc::{mir, ty}; +use log::trace; + +use rustc_middle::{mir, ty}; use crate::*; diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 49afa3bdc362..704994da4bd4 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -9,7 +9,7 @@ use std::os::unix::ffi::{OsStrExt, OsStringExt}; #[cfg(windows)] use std::os::windows::ffi::{OsStrExt, OsStringExt}; -use rustc::ty::layout::LayoutOf; +use rustc_middle::ty::layout::LayoutOf; use crate::*; diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 703e711972a7..77741b7cca40 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -11,8 +11,10 @@ //! gets popped *during unwinding*, we take the panic payload and store it according to the extra //! metadata we remembered when pushing said frame. -use rustc::mir; -use rustc::ty::{self, layout::LayoutOf}; +use log::trace; + +use rustc_middle::mir; +use rustc_middle::ty::{self, layout::LayoutOf}; use rustc_target::spec::PanicStrategy; use crate::*; @@ -186,7 +188,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx msg: &mir::AssertMessage<'tcx>, unwind: Option, ) -> InterpResult<'tcx> { - use rustc::mir::AssertKind::*; + use rustc_middle::mir::AssertKind::*; let this = self.eval_context_mut(); match msg { diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 2727c3205040..76f946f724ec 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -2,7 +2,9 @@ use std::collections::BTreeMap; -use rustc::{ty, ty::layout::{Size, HasDataLayout}}; +use log::trace; + +use rustc_middle::{ty, ty::layout::{Size, HasDataLayout}}; use rustc_target::abi::LayoutOf; use crate::{HelpersEvalContextExt, InterpResult, MPlaceTy, Scalar, StackPopCleanup, Tag}; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index c130abf0576b..90920069c5ee 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -6,9 +6,11 @@ use std::fmt; use std::num::NonZeroU64; use std::rc::Rc; +use log::trace; + use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc::mir::RetagKind; -use rustc::ty::{self, layout::Size}; +use rustc_middle::mir::RetagKind; +use rustc_middle::ty::{self, layout::Size}; use rustc_hir::Mutability; use crate::*; From 1cfd80ea2d35ed0b7463c6e1e29a602c2a366db5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 Mar 2020 22:13:53 +0200 Subject: [PATCH 1759/5092] rustup; fix Windows env var memory type --- rust-version | 2 +- src/shims/env.rs | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 4f4cff76583b..a812b46de17f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8926bb497d9b127eb318aea5aed0e745d8381591 +9a12971da5c08f9a95d54bdaef5cd83698ed4509 diff --git a/src/shims/env.rs b/src/shims/env.rs index 76d1de5d9a64..d30e953cf56a 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -165,8 +165,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Allocate environment block & Store environment variables to environment block. // Final null terminator(block terminator) is added by `alloc_os_str_to_wide_str`. - // FIXME: MemoryKind should be `Env`, blocked on https://github.com/rust-lang/rust/pull/70479. - let envblock_ptr = this.alloc_os_str_as_wide_str(&env_vars, MiriMemoryKind::WinHeap.into()); + let envblock_ptr = this.alloc_os_str_as_wide_str(&env_vars, MiriMemoryKind::Env.into()); // If the function succeeds, the return value is a pointer to the environment block of the current process. Ok(envblock_ptr.into()) } @@ -177,8 +176,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.assert_target_os("windows", "FreeEnvironmentStringsW"); let env_block_ptr = this.read_scalar(env_block_op)?.not_undef()?; - // FIXME: MemoryKind should be `Env`, blocked on https://github.com/rust-lang/rust/pull/70479. - let result = this.memory.deallocate(this.force_ptr(env_block_ptr)?, None, MiriMemoryKind::WinHeap.into()); + let result = this.memory.deallocate(this.force_ptr(env_block_ptr)?, None, MiriMemoryKind::Env.into()); // If the function succeeds, the return value is nonzero. Ok(result.is_ok() as i32) } From 62eaecd2aa16917e8ed02cb2ead6d23825347c29 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 31 Mar 2020 17:50:10 +0200 Subject: [PATCH 1760/5092] test subtracting SystemTime and Instant --- tests/run-pass/time.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/run-pass/time.rs b/tests/run-pass/time.rs index bbe8b4011dfa..5352630fc298 100644 --- a/tests/run-pass/time.rs +++ b/tests/run-pass/time.rs @@ -9,10 +9,22 @@ fn main() { for _ in 0..10 { drop(vec![42]); } let now2 = SystemTime::now(); assert!(now2 > now1); + let diff = now2.duration_since(now1).unwrap(); + assert!(diff.as_micros() > 0); + assert_eq!(now1 + diff, now2); + assert_eq!(now2 - diff, now1); let now1 = Instant::now(); // Do some work to make time pass. for _ in 0..10 { drop(vec![42]); } let now2 = Instant::now(); assert!(now2 > now1); + + #[cfg(target_os = "linux")] + { + let diff = now2.duration_since(now1); + assert!(diff.as_micros() > 0); + assert_eq!(now1 + diff, now2); + assert_eq!(now2 - diff, now1); + } } From 26b5012368910fecdab844a5ee75dfdc65996654 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 31 Mar 2020 17:53:27 +0200 Subject: [PATCH 1761/5092] add TODO --- tests/run-pass/time.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/time.rs b/tests/run-pass/time.rs index 5352630fc298..ca16f5ed5217 100644 --- a/tests/run-pass/time.rs +++ b/tests/run-pass/time.rs @@ -20,7 +20,7 @@ fn main() { let now2 = Instant::now(); assert!(now2 > now1); - #[cfg(target_os = "linux")] + #[cfg(target_os = "linux")] // TODO: macOS does not support Instant subtraction { let diff = now2.duration_since(now1); assert!(diff.as_micros() > 0); From b3f9e5304950c5677506fad7f2e6d44d8ef88ae3 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Tue, 31 Mar 2020 11:26:32 -0400 Subject: [PATCH 1762/5092] Implement 'GetSystemTimeAsFileTime' shim for Windows --- src/helpers.rs | 31 +++++++++++++++++++-------- src/shims/env.rs | 2 +- src/shims/foreign_items/windows.rs | 5 +++++ src/shims/time.rs | 34 +++++++++++++++++++++++++++++- tests/run-pass/time.rs | 26 ++++++++++++----------- 5 files changed, 75 insertions(+), 23 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 15f1b286de22..7d22b85b18eb 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -73,19 +73,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .not_undef() } - /// Helper function to get a `windows` constant as a `Scalar`. - fn eval_windows(&mut self, name: &str) -> InterpResult<'tcx, Scalar> { - self.eval_context_mut() - .eval_path_scalar(&["std", "sys", "windows", "c", name])? - .not_undef() - } - /// Helper function to get a `libc` constant as an `i32`. fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { // TODO: Cache the result. self.eval_libc(name)?.to_i32() } + /// Helper function to get a `windows` constant as a `Scalar`. + fn eval_windows(&mut self, module: &str, name: &str) -> InterpResult<'tcx, Scalar> { + self.eval_context_mut() + .eval_path_scalar(&["std", "sys", "windows", module, name])? + .not_undef() + } + + /// Helper function to get a `windows` constant as an `u64`. + fn eval_windows_u64(&mut self, module: &str, name: &str) -> InterpResult<'tcx, u64> { + // TODO: Cache the result. + self.eval_windows(module, name)?.to_u64() + } + /// Helper function to get the `TyAndLayout` of a `libc` type fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> { let this = self.eval_context_mut(); @@ -93,6 +99,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.layout_of(ty) } + /// Helper function to get the `TyAndLayout` of a `windows` type + fn windows_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> { + let this = self.eval_context_mut(); + let ty = this.resolve_path(&["std", "sys", "windows", "c", name]).monomorphic_ty(*this.tcx); + this.layout_of(ty) + } + /// Write a 0 of the appropriate size to `dest`. fn write_null(&mut self, dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest) @@ -350,7 +363,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - // Writes several `ImmTy`s contiguosly into memory. This is useful when you have to pack + // Writes several `ImmTy`s contiguously into memory. This is useful when you have to pack // different values into a struct. fn write_packed_immediates( &mut self, @@ -439,7 +452,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx })? } else if target_os == "windows" { // FIXME: we have to finish implementing the Windows equivalent of this. - this.eval_windows(match e.kind() { + this.eval_windows("c", match e.kind() { NotFound => "ERROR_FILE_NOT_FOUND", _ => throw_unsup_format!("io error {} cannot be transformed into a raw os error", e) })? diff --git a/src/shims/env.rs b/src/shims/env.rs index d30e953cf56a..3ffe4fc421f9 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -143,7 +143,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx windows_check_buffer_size(this.write_os_str_to_wide_str(&var, buf_ptr, buf_size)?) } None => { - let envvar_not_found = this.eval_windows("ERROR_ENVVAR_NOT_FOUND")?; + let envvar_not_found = this.eval_windows("c", "ERROR_ENVVAR_NOT_FOUND")?; this.set_last_error(envvar_not_found)?; 0 // return zero upon failure } diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index f39d477f8278..ee39773d71f8 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -167,6 +167,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; } + // Time related shims + "GetSystemTimeAsFileTime" => { + this.GetSystemTimeAsFileTime(args[0])?; + } + // Miscellaneous "SystemFunction036" => { // The actual name of 'RtlGenRandom' diff --git a/src/shims/time.rs b/src/shims/time.rs index 58db60e51688..d501fa8a0fdb 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -3,7 +3,9 @@ use std::convert::TryFrom; use crate::stacked_borrows::Tag; use crate::*; -use helpers::immty_from_int_checked; +use helpers::{immty_from_int_checked, immty_from_uint_checked}; + +use rustc_middle::ty::layout::LayoutOf; /// Returns the time elapsed between the provided time and the unix epoch as a `Duration`. pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Duration> { @@ -85,6 +87,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } + #[allow(non_snake_case)] + fn GetSystemTimeAsFileTime(&mut self, LPFILETIME_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + this.assert_target_os("windows", "GetSystemTimeAsFileTime"); + this.check_no_isolation("GetSystemTimeAsFileTime")?; + + let NANOS_PER_SEC = this.eval_windows_u64("time", "NANOS_PER_SEC")?; + let INTERVALS_PER_SEC = this.eval_windows_u64("time", "INTERVALS_PER_SEC")?; + let INTERVALS_TO_UNIX_EPOCH = this.eval_windows_u64("time", "INTERVALS_TO_UNIX_EPOCH")?; + let NANOS_PER_INTERVAL = NANOS_PER_SEC / INTERVALS_PER_SEC; + let SECONDS_TO_UNIX_EPOCH = INTERVALS_TO_UNIX_EPOCH / INTERVALS_PER_SEC; + + let duration = system_time_to_duration(&SystemTime::now())? + .checked_add(Duration::from_secs(SECONDS_TO_UNIX_EPOCH)) + .unwrap(); + let duration_ticks = u64::try_from(duration.as_nanos() / u128::from(NANOS_PER_INTERVAL)) + .map_err(|_| err_unsup_format!("programs running longer than 2^64 ticks are not supported"))?; + + let dwLowDateTime = u32::try_from(duration_ticks & 0x00000000FFFFFFFF).unwrap(); + let dwHighDateTime = u32::try_from((duration_ticks & 0xFFFFFFFF00000000) >> 32).unwrap(); + let DWORD_tylayout = this.layout_of(this.tcx.types.u32)?; + let imms = [ + immty_from_uint_checked(dwLowDateTime, DWORD_tylayout)?, + immty_from_uint_checked(dwHighDateTime, DWORD_tylayout)?, + ]; + this.write_packed_immediates(this.deref_operand(LPFILETIME_op)?, &imms)?; + Ok(()) + } + fn mach_absolute_time(&self) -> InterpResult<'tcx, u64> { let this = self.eval_context_ref(); diff --git a/tests/run-pass/time.rs b/tests/run-pass/time.rs index ca16f5ed5217..fc2059fa2561 100644 --- a/tests/run-pass/time.rs +++ b/tests/run-pass/time.rs @@ -1,4 +1,3 @@ -// ignore-windows: TODO clock shims are not implemented on Windows // compile-flags: -Zmiri-disable-isolation use std::time::{SystemTime, Instant}; @@ -14,17 +13,20 @@ fn main() { assert_eq!(now1 + diff, now2); assert_eq!(now2 - diff, now1); - let now1 = Instant::now(); - // Do some work to make time pass. - for _ in 0..10 { drop(vec![42]); } - let now2 = Instant::now(); - assert!(now2 > now1); - - #[cfg(target_os = "linux")] // TODO: macOS does not support Instant subtraction + #[cfg(not(windows))] // `Instant` shims not yet implemented on Windows { - let diff = now2.duration_since(now1); - assert!(diff.as_micros() > 0); - assert_eq!(now1 + diff, now2); - assert_eq!(now2 - diff, now1); + let now1 = Instant::now(); + // Do some work to make time pass. + for _ in 0..10 { drop(vec![42]); } + let now2 = Instant::now(); + assert!(now2 > now1); + + #[cfg(target_os = "linux")] // TODO: macOS does not support Instant subtraction + { + let diff = now2.duration_since(now1); + assert!(diff.as_micros() > 0); + assert_eq!(now1 + diff, now2); + assert_eq!(now2 - diff, now1); + } } } From 3911388e06694f4ddbd7045f8684f905090e9e84 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 Apr 2020 19:12:22 +0200 Subject: [PATCH 1763/5092] remove ICEin intrinsic --- src/shims/intrinsics.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 641b8b256363..e0eb0df87c48 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -217,8 +217,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_immediate(*val, place.into())?; } - "breakpoint" => unimplemented!(), // halt miri - #[rustfmt::skip] | "copy" | "copy_nonoverlapping" From 1e3800ffb1b74d51f68f6d63306ff94b4297eb73 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 Apr 2020 19:40:10 +0200 Subject: [PATCH 1764/5092] rustup --- rust-version | 2 +- src/helpers.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index a812b46de17f..9a662aa0c26c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9a12971da5c08f9a95d54bdaef5cd83698ed4509 +235938d1acdd93d6641a741c81f64e415b786751 diff --git a/src/helpers.rs b/src/helpers.rs index 15f1b286de22..e95b0d850b68 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -115,7 +115,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn local_place(&mut self, local: mir::Local) -> InterpResult<'tcx, PlaceTy<'tcx, Tag>> { let this = self.eval_context_mut(); let place = mir::Place { local: local, projection: List::empty() }; - this.eval_place(&place) + this.eval_place(place) } /// Generate some random bytes, and write them to `dest`. From 41d90709f25b813c33943102b0d28329de1aaf73 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 Apr 2020 20:12:51 +0200 Subject: [PATCH 1765/5092] sanity check time values a bit more --- tests/run-pass/time.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/time.rs b/tests/run-pass/time.rs index fc2059fa2561..a9ca28161cac 100644 --- a/tests/run-pass/time.rs +++ b/tests/run-pass/time.rs @@ -3,16 +3,22 @@ use std::time::{SystemTime, Instant}; fn main() { + // Check `SystemTime`. let now1 = SystemTime::now(); // Do some work to make time pass. for _ in 0..10 { drop(vec![42]); } let now2 = SystemTime::now(); assert!(now2 > now1); let diff = now2.duration_since(now1).unwrap(); - assert!(diff.as_micros() > 0); assert_eq!(now1 + diff, now2); assert_eq!(now2 - diff, now1); + // Sanity-check the time we got. + let seconds_since_epoch = now1.duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs(); + let years_since_epoch = seconds_since_epoch / 3600 / 24 / 365; + let year = 1970 + years_since_epoch; + assert!(2020 <= year && year < 2100); + // Check `Instant`. #[cfg(not(windows))] // `Instant` shims not yet implemented on Windows { let now1 = Instant::now(); @@ -24,9 +30,11 @@ fn main() { #[cfg(target_os = "linux")] // TODO: macOS does not support Instant subtraction { let diff = now2.duration_since(now1); - assert!(diff.as_micros() > 0); assert_eq!(now1 + diff, now2); assert_eq!(now2 - diff, now1); + // Sanity-check the difference we got. + assert!(diff.as_micros() > 1); + assert!(diff.as_micros() < 1_000_000); } } } From 94d5eb02768fc5362bbfeff9739856aa130d7397 Mon Sep 17 00:00:00 2001 From: William Brown Date: Thu, 2 Apr 2020 09:50:21 +1000 Subject: [PATCH 1766/5092] Update readme to make supported codo clearer --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.md b/README.md index 03b995aa56d3..9ca69df9607f 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,30 @@ fn does_not_work_on_miri() { } ``` +An exhaustive list of what `miri` does not support is not available, as this could be +an unbounded set with FFI and more. However `miri` will explicitly tell you when it finds +something unsupported with an error: + +``` +error: unsupported operation: can't call foreign function: mach_timebase_info + --> /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/sys/unix/time.rs:239:13 + | +239 | mach_timebase_info(&mut info); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't call foreign function: mach_timebase_info + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = note: inside call to `std::sys::unix::time::inner::info` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/sys/unix/time.rs:156:24 + = note: inside call to `std::sys::unix::time::inner::Instant::checked_sub_instant` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/time.rs:263:9 +note: inside call to `std::time::Instant::duration_since` at tests/run-pass/time.rs:25:20 + --> tests/run-pass/time.rs:25:20 + | +25 | let diff = now2.duration_since(now1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside call to `main` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/rt.rs:67:34 +``` + +If you do not see an error like this, you are able to keep using `miri`! + ### Running Miri on CI To run Miri on CI, make sure that you handle the case where the latest nightly From 957ec2be10e628c0d31cfa4af7b7a26eccb89dfc Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Wed, 1 Apr 2020 20:35:56 -0400 Subject: [PATCH 1767/5092] Add support for 'std::time::Instant' in Windows --- src/shims/foreign_items/windows.rs | 13 +++++++----- src/shims/time.rs | 32 ++++++++++++++++++++++++++++++ tests/run-pass/time.rs | 29 ++++++++++++--------------- 3 files changed, 53 insertions(+), 21 deletions(-) diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index ee39773d71f8..5e1bffef8a4b 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -24,27 +24,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.GetEnvironmentVariableW(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_u32(result), dest)?; } - "SetEnvironmentVariableW" => { let result = this.SetEnvironmentVariableW(args[0], args[1])?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "GetEnvironmentStringsW" => { let result = this.GetEnvironmentStringsW()?; this.write_scalar(result, dest)?; } - "FreeEnvironmentStringsW" => { let result = this.FreeEnvironmentStringsW(args[0])?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "GetCurrentDirectoryW" => { let result = this.GetCurrentDirectoryW(args[0], args[1])?; this.write_scalar(Scalar::from_u32(result), dest)?; } - "SetCurrentDirectoryW" => { let result = this.SetCurrentDirectoryW(args[0])?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -171,6 +166,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "GetSystemTimeAsFileTime" => { this.GetSystemTimeAsFileTime(args[0])?; } + "QueryPerformanceCounter" => { + let result = this.QueryPerformanceCounter(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "QueryPerformanceFrequency" => { + let result = this.QueryPerformanceFrequency(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } // Miscellaneous "SystemFunction036" => { diff --git a/src/shims/time.rs b/src/shims/time.rs index d501fa8a0fdb..65e83ab0af78 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -117,6 +117,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } + #[allow(non_snake_case)] + fn QueryPerformanceCounter(&mut self, lpPerformanceCount_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.assert_target_os("windows", "QueryPerformanceCounter"); + this.check_no_isolation("QueryPerformanceCounter")?; + + // QPC uses a hardware counter as its basis. + // Miri will assume that the machine's hardware counter has a resolution of 1 nanosecond. + let duration = Instant::now().duration_since(this.machine.time_anchor); + let qpc = i64::try_from(duration.as_nanos()) + .map_err(|_| err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported"))?; + this.write_scalar(Scalar::from_i64(qpc), this.deref_operand(lpPerformanceCount_op)?.into())?; + Ok(-1) // return non-zero on success + } + + #[allow(non_snake_case)] + fn QueryPerformanceFrequency(&mut self, lpFrequency_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.assert_target_os("windows", "QueryPerformanceFrequency"); + this.check_no_isolation("QueryPerformanceFrequency")?; + + // Retrieves the frequency of the hardware performance counter. + // The frequency of the performance counter is fixed at system boot and + // is consistent across all processors. + // Miri will assume that the frequency of + // the machine's hardware performance counter is 1 GHz ( = 1 x 10^9 Hz). + this.write_scalar(Scalar::from_i64(1_000_000_000), this.deref_operand(lpFrequency_op)?.into())?; + Ok(-1) // Return non-zero on success + } + fn mach_absolute_time(&self) -> InterpResult<'tcx, u64> { let this = self.eval_context_ref(); diff --git a/tests/run-pass/time.rs b/tests/run-pass/time.rs index a9ca28161cac..264fa9de0352 100644 --- a/tests/run-pass/time.rs +++ b/tests/run-pass/time.rs @@ -19,22 +19,19 @@ fn main() { assert!(2020 <= year && year < 2100); // Check `Instant`. - #[cfg(not(windows))] // `Instant` shims not yet implemented on Windows - { - let now1 = Instant::now(); - // Do some work to make time pass. - for _ in 0..10 { drop(vec![42]); } - let now2 = Instant::now(); - assert!(now2 > now1); + let now1 = Instant::now(); + // Do some work to make time pass. + for _ in 0..10 { drop(vec![42]); } + let now2 = Instant::now(); + assert!(now2 > now1); - #[cfg(target_os = "linux")] // TODO: macOS does not support Instant subtraction - { - let diff = now2.duration_since(now1); - assert_eq!(now1 + diff, now2); - assert_eq!(now2 - diff, now1); - // Sanity-check the difference we got. - assert!(diff.as_micros() > 1); - assert!(diff.as_micros() < 1_000_000); - } + #[cfg(target_os = "linux")] // TODO: macOS does not support Instant subtraction + { + let diff = now2.duration_since(now1); + assert_eq!(now1 + diff, now2); + assert_eq!(now2 - diff, now1); + // Sanity-check the difference we got. + assert!(diff.as_micros() > 1); + assert!(diff.as_micros() < 1_000_000); } } From ff982b1821c6b4846c7a14053ba3a00a3f97f22b Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Wed, 1 Apr 2020 21:26:47 -0400 Subject: [PATCH 1768/5092] fix incorrect error message in shim 'QueryPerformanceCounter' --- src/shims/time.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index 65e83ab0af78..d4c88cdb614b 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -128,7 +128,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miri will assume that the machine's hardware counter has a resolution of 1 nanosecond. let duration = Instant::now().duration_since(this.machine.time_anchor); let qpc = i64::try_from(duration.as_nanos()) - .map_err(|_| err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported"))?; + .map_err(|_| err_unsup_format!("programs running longer than 2^63 nanoseconds are not supported"))?; this.write_scalar(Scalar::from_i64(qpc), this.deref_operand(lpPerformanceCount_op)?.into())?; Ok(-1) // return non-zero on success } From 5130aa55a2d5e846b491a58a19aad8e00554d61f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 Mar 2020 20:15:02 +0200 Subject: [PATCH 1769/5092] adjust stacktrace printing to rustc changes --- src/diagnostics.rs | 13 +++++-------- tests/compile-fail/never_transmute_void.rs | 4 ++-- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index a528960cb262..8595551b6cbd 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -130,14 +130,11 @@ fn report_msg<'tcx, 'mir>( } // Add backtrace let frames = ecx.generate_stacktrace(None); - // We iterate with indices because we need to look at the next frame (the caller). - for idx in 0..frames.len() { - let frame_info = &frames[idx]; - let call_site_is_local = frames - .get(idx + 1) - .map_or(false, |caller_info| caller_info.instance.def_id().is_local()); - if call_site_is_local { - err.span_note(frame_info.call_site, &frame_info.to_string()); + for (idx, frame_info) in frames.iter().enumerate() { + let is_local = frame_info.instance.def_id().is_local(); + // No span for non-local frames and the first frame (which is the error site). + if is_local && idx > 0 { + err.span_note(frame_info.span, &frame_info.to_string()); } else { err.note(&frame_info.to_string()); } diff --git a/tests/compile-fail/never_transmute_void.rs b/tests/compile-fail/never_transmute_void.rs index 2a822ab1b515..5e9e2ac204ea 100644 --- a/tests/compile-fail/never_transmute_void.rs +++ b/tests/compile-fail/never_transmute_void.rs @@ -7,12 +7,12 @@ enum Void {} fn f(v: Void) -> ! { - match v {} //~ ERROR entering unreachable code + match v {} //~ ERROR entering unreachable code } fn main() { let v: Void = unsafe { std::mem::transmute::<(), Void>(()) }; - f(v); //~ inside call to `f` + f(v); //~ inside `main` } From f599687f3fdb062a8ff2fe139cbe47249c5f29a1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 Mar 2020 22:54:49 +0200 Subject: [PATCH 1770/5092] adjust for span not being passed around any more --- src/diagnostics.rs | 2 +- src/helpers.rs | 9 +-------- src/machine.rs | 6 ++---- src/shims/intrinsics.rs | 4 +--- src/shims/panic.rs | 4 ++-- 5 files changed, 7 insertions(+), 18 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 8595551b6cbd..9ff434021150 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -129,7 +129,7 @@ fn report_msg<'tcx, 'mir>( err.help(help); } // Add backtrace - let frames = ecx.generate_stacktrace(None); + let frames = ecx.generate_stacktrace(); for (idx, frame_info) in frames.iter().enumerate() { let is_local = frame_info.instance.def_id().is_local(); // No span for non-local frames and the first frame (which is the error site). diff --git a/src/helpers.rs b/src/helpers.rs index 568e9c925d55..827bf1f9dde0 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -10,7 +10,6 @@ use rustc_middle::ty::{ List, TyCtxt, }; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; -use rustc_span::source_map::DUMMY_SP; use rand::RngCore; @@ -170,13 +169,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Push frame. let mir = &*this.load_mir(f.def, None)?; - let span = this - .stack() - .last() - .and_then(Frame::current_source_info) - .map(|si| si.span) - .unwrap_or(DUMMY_SP); - this.push_stack_frame(f, span, mir, dest, stack_pop)?; + this.push_stack_frame(f, mir, dest, stack_pop)?; // Initialize arguments. let mut callee_args = this.frame().body.args_iter(); diff --git a/src/machine.rs b/src/machine.rs index 4b7f3a76569f..61c9f71407bf 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -18,7 +18,7 @@ use rustc_middle::ty::{ Ty, }; use rustc_ast::attr; -use rustc_span::{source_map::Span, symbol::{sym, Symbol}}; +use rustc_span::symbol::{sym, Symbol}; use crate::*; @@ -253,7 +253,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn find_mir_or_eval_fn( ecx: &mut InterpCx<'mir, 'tcx, Self>, - _span: Span, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, @@ -276,13 +275,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn call_intrinsic( ecx: &mut rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>, - span: Span, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, ) -> InterpResult<'tcx> { - ecx.call_intrinsic(span, instance, args, ret, unwind) + ecx.call_intrinsic(instance, args, ret, unwind) } #[inline(always)] diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index e0eb0df87c48..b7900bfaa5d5 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -5,7 +5,6 @@ use rustc_middle::mir; use rustc_middle::ty; use rustc_middle::ty::layout::{Align, LayoutOf}; use rustc_apfloat::Float; -use rustc_span::source_map::Span; use crate::*; @@ -13,14 +12,13 @@ impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tc pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn call_intrinsic( &mut self, - span: Span, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - if this.emulate_intrinsic(span, instance, args, ret)? { + if this.emulate_intrinsic(instance, args, ret)? { return Ok(()); } let substs = instance.substs; diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 77741b7cca40..3474945980a9 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -51,7 +51,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - trace!("miri_start_panic: {:?}", this.frame().span); + trace!("miri_start_panic: {:?}", this.frame().instance); // Get the raw pointer stored in arg[0] (the panic payload). let payload = this.read_scalar(args[0])?.not_undef()?; @@ -133,7 +133,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let (true, Some(catch_unwind)) = (unwinding, extra.catch_unwind.take()) { // We've just popped a frame that was pushed by `try`, // and we are unwinding, so we should catch that. - trace!("unwinding: found catch_panic frame during unwinding: {:?}", this.frame().span); + trace!("unwinding: found catch_panic frame during unwinding: {:?}", this.frame().instance); // We set the return value of `try` to 1, since there was a panic. this.write_scalar(Scalar::from_i32(1), catch_unwind.dest)?; From 165dfd78a94bb5f30e655b51cde633649107ad42 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Apr 2020 09:14:23 +0200 Subject: [PATCH 1771/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 9a662aa0c26c..6ed19772cad9 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -235938d1acdd93d6641a741c81f64e415b786751 +b793f403bdfbcc0ff3e15ed8177a81d79ba4a29b From 5ce2466892126a3ea92138df67f09243a22dcb96 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Apr 2020 09:19:56 +0200 Subject: [PATCH 1772/5092] fix for FieldPlacement rename --- src/helpers.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 827bf1f9dde0..7b1ac1aacfc8 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -324,19 +324,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fields: impl Iterator>>, ) -> InterpResult<'tcx> { match place.layout.fields { - layout::FieldPlacement::Array { .. } => { + layout::FieldsShape::Array { .. } => { // For the array layout, we know the iterator will yield sorted elements so // we can avoid the allocation. self.walk_aggregate(place, fields) } - layout::FieldPlacement::Arbitrary { .. } => { + layout::FieldsShape::Arbitrary { .. } => { // Gather the subplaces and sort them before visiting. let mut places = fields.collect::>>>()?; places.sort_by_key(|place| place.ptr.assert_ptr().offset); self.walk_aggregate(place, places.into_iter().map(Ok)) } - layout::FieldPlacement::Union { .. } => { + layout::FieldsShape::Union { .. } => { // Uh, what? bug!("a union is not an aggregate we should ever visit") } From 0b07f6f5d32d6a46de21776eac714e0a04fce71d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Apr 2020 09:49:48 +0200 Subject: [PATCH 1773/5092] set CARGO_INCREMENTAL=0 on CI, it's just a waste of time there --- .appveyor.yml | 1 + .travis.yml | 1 + miri | 5 ++++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index e5c2f4fb7294..294ef26be0be 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -46,6 +46,7 @@ build_script: test_script: - set RUST_TEST_NOCAPTURE=1 - set RUST_BACKTRACE=1 + - set CARGO_INCREMENTAL=0 # Test host miri: 32bit Windows - cargo miri setup - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\rust-lang\miri\cache\HOST diff --git a/.travis.yml b/.travis.yml index 137ae4fe6625..a074d6b14d8d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,7 @@ env: global: - RUST_TEST_NOCAPTURE=1 - RUST_BACKTRACE=1 + - CARGO_INCREMENTAL=0 before_script: # Compute the rust version we use. We do not use "language: rust" to have more control here. diff --git a/miri b/miri index 0cda9e80926e..8cd2cfc3ae0c 100755 --- a/miri +++ b/miri @@ -49,7 +49,10 @@ fi # We enable debug-assertions to get tracing. # We enable line-only debuginfo for backtraces. export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR -C debug-assertions -C debuginfo=1 $RUSTC_EXTRA_FLAGS" -export CARGO_INCREMENTAL=1 +if [ -z "$CARGO_INCREMENTAL" ]; then + # Default CARGO_INCREMENTAL to 1. + export CARGO_INCREMENTAL=1 +fi ## Helper functions From 033eae5ad73ef69648f7b794040de1cb2c4317a1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Apr 2020 11:45:17 +0200 Subject: [PATCH 1774/5092] rustup for AllocRef changes --- rust-version | 2 +- tests/run-pass/heap_allocator.rs | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/rust-version b/rust-version index 6ed19772cad9..2cb1f848a684 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -b793f403bdfbcc0ff3e15ed8177a81d79ba4a29b +127a11a344eb59b5aea1464e98257c262dcba967 diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index 8077be405f4b..c2fcfea58cdf 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -1,7 +1,7 @@ #![feature(allocator_api)] use std::ptr::NonNull; -use std::alloc::{Global, AllocRef, Layout, System}; +use std::alloc::{Global, AllocRef, Layout, System, AllocInit, ReallocPlacement}; use std::slice; fn check_alloc(mut allocator: T) { unsafe { @@ -9,28 +9,29 @@ fn check_alloc(mut allocator: T) { unsafe { let layout = Layout::from_size_align(20, align).unwrap(); for _ in 0..32 { - let a = allocator.alloc(layout).unwrap().0; + let a = allocator.alloc(layout, AllocInit::Uninitialized).unwrap().ptr; assert_eq!(a.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); allocator.dealloc(a, layout); } - let p1 = allocator.alloc_zeroed(layout).unwrap().0; + let p1 = allocator.alloc(layout, AllocInit::Zeroed).unwrap().ptr; assert_eq!(p1.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); - let p2 = allocator.realloc(p1, layout, 40).unwrap().0; + // old size < new size + let p2 = allocator.grow(p1, layout, 40, ReallocPlacement::MayMove, AllocInit::Uninitialized).unwrap().ptr; let layout = Layout::from_size_align(40, align).unwrap(); assert_eq!(p2.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); let slice = slice::from_raw_parts(p2.as_ptr(), 20); assert_eq!(&slice, &[0_u8; 20]); // old size == new size - let p3 = allocator.realloc(p2, layout, 40).unwrap().0; + let p3 = allocator.grow(p2, layout, 40, ReallocPlacement::MayMove, AllocInit::Uninitialized).unwrap().ptr; assert_eq!(p3.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); let slice = slice::from_raw_parts(p3.as_ptr(), 20); assert_eq!(&slice, &[0_u8; 20]); // old size > new size - let p4 = allocator.realloc(p3, layout, 10).unwrap().0; + let p4 = allocator.shrink(p3, layout, 10, ReallocPlacement::MayMove).unwrap().ptr; let layout = Layout::from_size_align(10, align).unwrap(); assert_eq!(p4.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); let slice = slice::from_raw_parts(p4.as_ptr(), 10); @@ -46,7 +47,7 @@ fn check_align_requests(mut allocator: T) { let iterations = 32; unsafe { let pointers: Vec<_> = (0..iterations).map(|_| { - allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap().0 + allocator.alloc(Layout::from_size_align(size, align).unwrap(), AllocInit::Uninitialized).unwrap().ptr }).collect(); for &ptr in &pointers { assert_eq!((ptr.as_ptr() as usize) % align, 0, @@ -67,7 +68,7 @@ fn global_to_box() { let l = Layout::new::(); // allocate manually with global allocator, then turn into Box and free there unsafe { - let ptr = Global.alloc(l).unwrap().0.as_ptr() as *mut T; + let ptr = Global.alloc(l, AllocInit::Uninitialized).unwrap().ptr.as_ptr() as *mut T; let b = Box::from_raw(ptr); drop(b); } From cd132f563ea5385c8dfed2b9c9032ea3e8dc3edc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Apr 2020 13:33:59 +0200 Subject: [PATCH 1775/5092] port compile-fail allocator tests to stable API --- tests/compile-fail/deallocate-bad-alignment.rs | 11 +++-------- tests/compile-fail/deallocate-bad-size.rs | 11 +++-------- tests/compile-fail/deallocate-twice.rs | 13 ++++--------- tests/compile-fail/reallocate-bad-size.rs | 11 +++-------- tests/compile-fail/reallocate-change-alloc.rs | 13 ++++--------- tests/compile-fail/reallocate-dangling.rs | 13 ++++--------- 6 files changed, 21 insertions(+), 51 deletions(-) diff --git a/tests/compile-fail/deallocate-bad-alignment.rs b/tests/compile-fail/deallocate-bad-alignment.rs index f2cd87bac622..9b5ee9a934b0 100644 --- a/tests/compile-fail/deallocate-bad-alignment.rs +++ b/tests/compile-fail/deallocate-bad-alignment.rs @@ -1,15 +1,10 @@ -#![feature(allocator_api)] - -extern crate alloc; - -use alloc::alloc::Global; -use std::alloc::{AllocRef, Layout}; +use std::alloc::{alloc, dealloc, realloc, Layout}; // error-pattern: allocation has size 1 and alignment 1, but gave size 1 and alignment 2 fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap().0; - Global.dealloc(x, Layout::from_size_align_unchecked(1, 2)); + let x = alloc(Layout::from_size_align_unchecked(1, 1)); + dealloc(x, Layout::from_size_align_unchecked(1, 2)); } } diff --git a/tests/compile-fail/deallocate-bad-size.rs b/tests/compile-fail/deallocate-bad-size.rs index 498a662518e5..39a0d48c8b1a 100644 --- a/tests/compile-fail/deallocate-bad-size.rs +++ b/tests/compile-fail/deallocate-bad-size.rs @@ -1,15 +1,10 @@ -#![feature(allocator_api)] - -extern crate alloc; - -use alloc::alloc::Global; -use std::alloc::{AllocRef, Layout}; +use std::alloc::{alloc, dealloc, realloc, Layout}; // error-pattern: allocation has size 1 and alignment 1, but gave size 2 and alignment 1 fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap().0; - Global.dealloc(x, Layout::from_size_align_unchecked(2, 1)); + let x = alloc(Layout::from_size_align_unchecked(1, 1)); + dealloc(x, Layout::from_size_align_unchecked(2, 1)); } } diff --git a/tests/compile-fail/deallocate-twice.rs b/tests/compile-fail/deallocate-twice.rs index a851d75b9d5c..3c5e8e96360c 100644 --- a/tests/compile-fail/deallocate-twice.rs +++ b/tests/compile-fail/deallocate-twice.rs @@ -1,16 +1,11 @@ -#![feature(allocator_api)] - -extern crate alloc; - -use alloc::alloc::Global; -use std::alloc::{AllocRef, Layout}; +use std::alloc::{alloc, dealloc, realloc, Layout}; // error-pattern: dereferenced after this allocation got freed fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap().0; - Global.dealloc(x, Layout::from_size_align_unchecked(1, 1)); - Global.dealloc(x, Layout::from_size_align_unchecked(1, 1)); + let x = alloc(Layout::from_size_align_unchecked(1, 1)); + dealloc(x, Layout::from_size_align_unchecked(1, 1)); + dealloc(x, Layout::from_size_align_unchecked(1, 1)); } } diff --git a/tests/compile-fail/reallocate-bad-size.rs b/tests/compile-fail/reallocate-bad-size.rs index a62c1adae7e6..bbdef4421b6c 100644 --- a/tests/compile-fail/reallocate-bad-size.rs +++ b/tests/compile-fail/reallocate-bad-size.rs @@ -1,15 +1,10 @@ -#![feature(allocator_api)] - -extern crate alloc; - -use alloc::alloc::Global; -use std::alloc::{AllocRef, Layout}; +use std::alloc::{alloc, dealloc, realloc, Layout}; // error-pattern: allocation has size 1 and alignment 1, but gave size 2 and alignment 1 fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap().0; - Global.realloc(x, Layout::from_size_align_unchecked(2, 1), 1).unwrap(); + let x = alloc(Layout::from_size_align_unchecked(1, 1)); + realloc(x, Layout::from_size_align_unchecked(2, 1), 1); } } diff --git a/tests/compile-fail/reallocate-change-alloc.rs b/tests/compile-fail/reallocate-change-alloc.rs index 0d4b60e0a336..8130d72dee59 100644 --- a/tests/compile-fail/reallocate-change-alloc.rs +++ b/tests/compile-fail/reallocate-change-alloc.rs @@ -1,14 +1,9 @@ -#![feature(allocator_api)] - -extern crate alloc; - -use alloc::alloc::Global; -use std::alloc::{AllocRef, Layout}; +use std::alloc::{alloc, dealloc, realloc, Layout}; fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap().0; - Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1).unwrap(); - let _z = *(x.as_ptr() as *mut u8); //~ ERROR dereferenced after this allocation got freed + let x = alloc(Layout::from_size_align_unchecked(1, 1)); + realloc(x, Layout::from_size_align_unchecked(1, 1), 1); + let _z = *x; //~ ERROR dereferenced after this allocation got freed } } diff --git a/tests/compile-fail/reallocate-dangling.rs b/tests/compile-fail/reallocate-dangling.rs index 9661d7e96674..702ddc0724a3 100644 --- a/tests/compile-fail/reallocate-dangling.rs +++ b/tests/compile-fail/reallocate-dangling.rs @@ -1,16 +1,11 @@ -#![feature(allocator_api)] - -extern crate alloc; - -use alloc::alloc::Global; -use std::alloc::{AllocRef, Layout}; +use std::alloc::{alloc, dealloc, realloc, Layout}; // error-pattern: dereferenced after this allocation got freed fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap().0; - Global.dealloc(x, Layout::from_size_align_unchecked(1, 1)); - Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1).unwrap(); + let x = alloc(Layout::from_size_align_unchecked(1, 1)); + dealloc(x, Layout::from_size_align_unchecked(1, 1)); + realloc(x, Layout::from_size_align_unchecked(1, 1), 1); } } From d5beecb79c71340c36fa79d994ac5848fb1159db Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Apr 2020 15:14:53 +0200 Subject: [PATCH 1776/5092] correct factual mistake in Windows message, and use "+" sugar --- src/shims/time.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index d501fa8a0fdb..735b52528fda 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -100,11 +100,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let NANOS_PER_INTERVAL = NANOS_PER_SEC / INTERVALS_PER_SEC; let SECONDS_TO_UNIX_EPOCH = INTERVALS_TO_UNIX_EPOCH / INTERVALS_PER_SEC; - let duration = system_time_to_duration(&SystemTime::now())? - .checked_add(Duration::from_secs(SECONDS_TO_UNIX_EPOCH)) - .unwrap(); + let duration = system_time_to_duration(&SystemTime::now())? + Duration::from_secs(SECONDS_TO_UNIX_EPOCH); let duration_ticks = u64::try_from(duration.as_nanos() / u128::from(NANOS_PER_INTERVAL)) - .map_err(|_| err_unsup_format!("programs running longer than 2^64 ticks are not supported"))?; + .map_err(|_| err_unsup_format!("programs running more than 2^64 Windows ticks after the Windows epoch are not supported"))?; let dwLowDateTime = u32::try_from(duration_ticks & 0x00000000FFFFFFFF).unwrap(); let dwHighDateTime = u32::try_from((duration_ticks & 0xFFFFFFFF00000000) >> 32).unwrap(); From a494825d5aca389f5c6ff7407bd927a5faee35b8 Mon Sep 17 00:00:00 2001 From: Youngsuk Kim Date: Thu, 2 Apr 2020 16:03:56 -0400 Subject: [PATCH 1777/5092] Update comments in src/shims/time.rs Co-Authored-By: Ralf Jung --- src/shims/time.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index d4c88cdb614b..07819fd56f15 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -125,7 +125,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("QueryPerformanceCounter")?; // QPC uses a hardware counter as its basis. - // Miri will assume that the machine's hardware counter has a resolution of 1 nanosecond. + // Miri will emulate a counter with a resolution of 1 nanosecond. let duration = Instant::now().duration_since(this.machine.time_anchor); let qpc = i64::try_from(duration.as_nanos()) .map_err(|_| err_unsup_format!("programs running longer than 2^63 nanoseconds are not supported"))?; From 5157b8769f6f5196e73133a4cd3ec009823e71fd Mon Sep 17 00:00:00 2001 From: Youngsuk Kim Date: Thu, 2 Apr 2020 16:04:10 -0400 Subject: [PATCH 1778/5092] Update comments in src/shims/time.rs Co-Authored-By: Ralf Jung --- src/shims/time.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index 07819fd56f15..769fb4cf5b33 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -124,7 +124,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.assert_target_os("windows", "QueryPerformanceCounter"); this.check_no_isolation("QueryPerformanceCounter")?; - // QPC uses a hardware counter as its basis. + // QueryPerformanceCounter uses a hardware counter as its basis. // Miri will emulate a counter with a resolution of 1 nanosecond. let duration = Instant::now().duration_since(this.machine.time_anchor); let qpc = i64::try_from(duration.as_nanos()) From f762c70b5185573112e4c897d23a29b0bf6636bd Mon Sep 17 00:00:00 2001 From: Youngsuk Kim Date: Thu, 2 Apr 2020 16:04:50 -0400 Subject: [PATCH 1779/5092] Update comments in src/shims/time.rs Co-Authored-By: Ralf Jung --- src/shims/time.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index 769fb4cf5b33..d7b423fc8aae 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -143,8 +143,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Retrieves the frequency of the hardware performance counter. // The frequency of the performance counter is fixed at system boot and // is consistent across all processors. - // Miri will assume that the frequency of - // the machine's hardware performance counter is 1 GHz ( = 1 x 10^9 Hz). + // Miri emulates a "hardware" performance counter with a resolution of 1ns, + // and thus 10^9 counts per second. this.write_scalar(Scalar::from_i64(1_000_000_000), this.deref_operand(lpFrequency_op)?.into())?; Ok(-1) // Return non-zero on success } From d5de67a5a0719daffc9e5ed6d434c9feaf093fe7 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Thu, 2 Apr 2020 16:15:23 -0400 Subject: [PATCH 1780/5092] change cfg gate to enable testing Instant subtraction in Windows --- tests/run-pass/time.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/time.rs b/tests/run-pass/time.rs index 264fa9de0352..aa02ac15388e 100644 --- a/tests/run-pass/time.rs +++ b/tests/run-pass/time.rs @@ -25,7 +25,7 @@ fn main() { let now2 = Instant::now(); assert!(now2 > now1); - #[cfg(target_os = "linux")] // TODO: macOS does not support Instant subtraction + #[cfg(not(target_os = "macos"))] // TODO: macOS does not support Instant subtraction { let diff = now2.duration_since(now1); assert_eq!(now1 + diff, now2); From 9f3383d55d99635a38c5406f60d16c478534d9f6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 3 Apr 2020 00:05:35 +0200 Subject: [PATCH 1781/5092] rustup for import changes --- rust-version | 2 +- src/eval.rs | 2 +- src/helpers.rs | 17 +++++++---------- src/intptrcast.rs | 3 +-- src/machine.rs | 10 +++------- src/operator.rs | 7 ++----- src/range_map.rs | 2 +- src/shims/env.rs | 8 +++----- src/shims/foreign_items.rs | 5 ++--- src/shims/foreign_items/posix.rs | 2 +- src/shims/foreign_items/windows.rs | 8 +++++--- src/shims/fs.rs | 2 +- src/shims/intrinsics.rs | 5 ++--- src/shims/os_str.rs | 2 +- src/shims/panic.rs | 5 ++--- src/shims/time.rs | 4 ++-- src/shims/tls.rs | 4 ++-- src/stacked_borrows.rs | 3 ++- 18 files changed, 39 insertions(+), 52 deletions(-) diff --git a/rust-version b/rust-version index 2cb1f848a684..e3dc200835fd 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -127a11a344eb59b5aea1464e98257c262dcba967 +537ccdf3ac44c8c7a8d36cbdbe6fb224afabb7ae diff --git a/src/eval.rs b/src/eval.rs index a4867bd5de46..46e66bc0a81e 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -6,7 +6,7 @@ use std::convert::TryFrom; use rand::rngs::StdRng; use rand::SeedableRng; -use rustc_middle::ty::layout::LayoutOf; +use rustc_target::abi::LayoutOf; use rustc_middle::ty::{self, TyCtxt}; use rustc_hir::def_id::DefId; diff --git a/src/helpers.rs b/src/helpers.rs index 7b1ac1aacfc8..9f46a0c1ce2d 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -4,12 +4,9 @@ use std::mem; use log::trace; use rustc_middle::mir; -use rustc_middle::ty::{ - self, - layout::{self, LayoutOf, Size, TyAndLayout}, - List, TyCtxt, -}; +use rustc_middle::ty::{self, List, TyCtxt, layout::TyAndLayout}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; +use rustc_target::abi::{LayoutOf, Size, FieldsShape, Variants}; use rand::RngCore; @@ -298,7 +295,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // walking this value, we have to make sure it is not a // `Variants::Multiple`. match v.layout.variants { - layout::Variants::Multiple { .. } => { + Variants::Multiple { .. } => { // A multi-variant enum, or generator, or so. // Treat this like a union: without reading from memory, // we cannot determine the variant we are in. Reading from @@ -308,7 +305,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `UnsafeCell` action. (self.unsafe_cell_action)(v) } - layout::Variants::Single { .. } => { + Variants::Single { .. } => { // Proceed further, try to find where exactly that `UnsafeCell` // is hiding. self.walk_value(v) @@ -324,19 +321,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fields: impl Iterator>>, ) -> InterpResult<'tcx> { match place.layout.fields { - layout::FieldsShape::Array { .. } => { + FieldsShape::Array { .. } => { // For the array layout, we know the iterator will yield sorted elements so // we can avoid the allocation. self.walk_aggregate(place, fields) } - layout::FieldsShape::Arbitrary { .. } => { + FieldsShape::Arbitrary { .. } => { // Gather the subplaces and sort them before visiting. let mut places = fields.collect::>>>()?; places.sort_by_key(|place| place.ptr.assert_ptr().offset); self.walk_aggregate(place, places.into_iter().map(Ok)) } - layout::FieldsShape::Union { .. } => { + FieldsShape::Union { .. } => { // Uh, what? bug!("a union is not an aggregate we should ever visit") } diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 8eb28e4f4700..ac27138d7630 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -6,9 +6,8 @@ use log::trace; use rand::Rng; use rustc_data_structures::fx::FxHashMap; -use rustc_middle::ty::layout::HasDataLayout; use rustc_mir::interpret::{AllocCheck, AllocId, InterpResult, Memory, Machine, Pointer, PointerArithmetic}; -use rustc_target::abi::Size; +use rustc_target::abi::{Size, HasDataLayout}; use crate::{Evaluator, Tag, STACK_ADDR}; diff --git a/src/machine.rs b/src/machine.rs index 61c9f71407bf..f794453228b8 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -11,12 +11,8 @@ use log::trace; use rand::rngs::StdRng; use rustc_data_structures::fx::FxHashMap; -use rustc_middle::mir; -use rustc_middle::ty::{ - self, - layout::{LayoutOf, Size}, - Ty, -}; +use rustc_middle::{mir, ty}; +use rustc_target::abi::{LayoutOf, Size}; use rustc_ast::attr; use rustc_span::symbol::{sym, Symbol}; @@ -303,7 +299,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { bin_op: mir::BinOp, left: ImmTy<'tcx, Tag>, right: ImmTy<'tcx, Tag>, - ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { + ) -> InterpResult<'tcx, (Scalar, bool, ty::Ty<'tcx>)> { ecx.binary_ptr_op(bin_op, left, right) } diff --git a/src/operator.rs b/src/operator.rs index 2232be713ed5..a28a0098e92e 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -2,11 +2,8 @@ use std::convert::TryFrom; use log::trace; -use rustc_middle::mir; -use rustc_middle::ty::{ - layout::{LayoutOf, Size}, - Ty, -}; +use rustc_middle::{mir, ty::Ty}; +use rustc_target::abi::{LayoutOf, Size}; use crate::*; diff --git a/src/range_map.rs b/src/range_map.rs index 1d12d8a1ba65..16ad5fd7c2b2 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -7,7 +7,7 @@ use std::ops; -use rustc_middle::ty::layout::Size; +use rustc_target::abi::Size; #[derive(Clone, Debug)] struct Elem { diff --git a/src/shims/env.rs b/src/shims/env.rs index 3ffe4fc421f9..440168272294 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -2,14 +2,12 @@ use std::ffi::{OsString, OsStr}; use std::env; use std::convert::TryFrom; -use crate::stacked_borrows::Tag; -use crate::rustc_target::abi::LayoutOf; -use crate::*; - +use rustc_target::abi::{Size, LayoutOf}; use rustc_data_structures::fx::FxHashMap; -use rustc_middle::ty::layout::Size; use rustc_mir::interpret::Pointer; +use crate::*; + /// Check whether an operation that writes to a target buffer was successful. /// Accordingly select return value. /// Local helper function to be used in Windows shims. diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index da2f9d439c7e..7e7f17b0dbd4 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -4,9 +4,8 @@ mod posix; use std::{convert::{TryInto, TryFrom}, iter}; use rustc_hir::def_id::DefId; -use rustc_middle::mir; -use rustc_middle::ty; -use rustc_middle::ty::layout::{Align, Size}; +use rustc_middle::{mir, ty}; +use rustc_target::abi::{Align, Size}; use rustc_apfloat::Float; use rustc_span::symbol::sym; use rustc_ast::attr; diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 28161592985a..c9fd59c69327 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -7,7 +7,7 @@ use log::trace; use crate::*; use rustc_middle::mir; -use rustc_middle::ty::layout::{Align, LayoutOf, Size}; +use rustc_target::abi::{Align, LayoutOf, Size}; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index ee39773d71f8..276dd8fda9ff 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -1,8 +1,10 @@ -use crate::*; -use rustc_middle::mir; -use rustc_middle::ty::layout::Size; use std::iter; +use rustc_middle::mir; +use rustc_target::abi::Size; + +use crate::*; + impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn emulate_foreign_item_by_name( diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 89d067be860d..52244dcfc847 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -6,7 +6,7 @@ use std::path::Path; use std::time::SystemTime; use rustc_data_structures::fx::FxHashMap; -use rustc_middle::ty::layout::{Align, LayoutOf, Size}; +use rustc_target::abi::{Align, LayoutOf, Size}; use crate::stacked_borrows::Tag; use crate::*; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index b7900bfaa5d5..844eac398de8 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -1,10 +1,9 @@ use std::iter; use std::convert::TryFrom; -use rustc_middle::mir; -use rustc_middle::ty; -use rustc_middle::ty::layout::{Align, LayoutOf}; +use rustc_middle::{mir, ty}; use rustc_apfloat::Float; +use rustc_target::abi::{Align, LayoutOf}; use crate::*; diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 704994da4bd4..c24d6df41e39 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -9,7 +9,7 @@ use std::os::unix::ffi::{OsStrExt, OsStringExt}; #[cfg(windows)] use std::os::windows::ffi::{OsStrExt, OsStringExt}; -use rustc_middle::ty::layout::LayoutOf; +use rustc_target::abi::LayoutOf; use crate::*; diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 3474945980a9..33e47147a33b 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -13,9 +13,8 @@ use log::trace; -use rustc_middle::mir; -use rustc_middle::ty::{self, layout::LayoutOf}; -use rustc_target::spec::PanicStrategy; +use rustc_middle::{mir, ty}; +use rustc_target::{spec::PanicStrategy, abi::LayoutOf}; use crate::*; diff --git a/src/shims/time.rs b/src/shims/time.rs index 735b52528fda..a7fca5e0dde2 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -1,12 +1,12 @@ use std::time::{Duration, SystemTime, Instant}; use std::convert::TryFrom; +use rustc_target::abi::LayoutOf; + use crate::stacked_borrows::Tag; use crate::*; use helpers::{immty_from_int_checked, immty_from_uint_checked}; -use rustc_middle::ty::layout::LayoutOf; - /// Returns the time elapsed between the provided time and the unix epoch as a `Duration`. pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Duration> { time.duration_since(SystemTime::UNIX_EPOCH) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 76f946f724ec..36ad4bd9b691 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -4,8 +4,8 @@ use std::collections::BTreeMap; use log::trace; -use rustc_middle::{ty, ty::layout::{Size, HasDataLayout}}; -use rustc_target::abi::LayoutOf; +use rustc_middle::ty; +use rustc_target::abi::{LayoutOf, Size, HasDataLayout}; use crate::{HelpersEvalContextExt, InterpResult, MPlaceTy, Scalar, StackPopCleanup, Tag}; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 90920069c5ee..89b2a8bb3e2b 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -10,7 +10,8 @@ use log::trace; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_middle::mir::RetagKind; -use rustc_middle::ty::{self, layout::Size}; +use rustc_middle::ty; +use rustc_target::abi::Size; use rustc_hir::Mutability; use crate::*; From ef89525249614cd201aaa06d1652b693e9964c45 Mon Sep 17 00:00:00 2001 From: William Brown Date: Fri, 3 Apr 2020 09:07:57 +1000 Subject: [PATCH 1782/5092] Apply feedback --- README.md | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 9ca69df9607f..f755f85b601e 100644 --- a/README.md +++ b/README.md @@ -102,28 +102,15 @@ fn does_not_work_on_miri() { An exhaustive list of what `miri` does not support is not available, as this could be an unbounded set with FFI and more. However `miri` will explicitly tell you when it finds -something unsupported with an error: +something unsupported with an error, containing a message such as: ``` error: unsupported operation: can't call foreign function: mach_timebase_info - --> /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/sys/unix/time.rs:239:13 - | -239 | mach_timebase_info(&mut info); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't call foreign function: mach_timebase_info - | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: inside call to `std::sys::unix::time::inner::info` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/sys/unix/time.rs:156:24 - = note: inside call to `std::sys::unix::time::inner::Instant::checked_sub_instant` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/time.rs:263:9 -note: inside call to `std::time::Instant::duration_since` at tests/run-pass/time.rs:25:20 - --> tests/run-pass/time.rs:25:20 - | -25 | let diff = now2.duration_since(now1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: inside call to `main` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/rt.rs:67:34 + ... + = help: this is likely not a bug in the program; it indicates that the program \ + performed an operation that the interpreter does not support ``` -If you do not see an error like this, you are able to keep using `miri`! - ### Running Miri on CI To run Miri on CI, make sure that you handle the case where the latest nightly From bd9ec746a59eec97322eb7e7c24eb350ac94dba0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 Apr 2020 12:07:22 +0200 Subject: [PATCH 1783/5092] Rust bootstrap sysroot now has src in the same place as rust-src, so remove special hack --- rust-version | 2 +- src/bin/cargo-miri.rs | 41 +++++++++++++---------------------------- 2 files changed, 14 insertions(+), 29 deletions(-) diff --git a/rust-version b/rust-version index e3dc200835fd..895cbb5fa9a0 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -537ccdf3ac44c8c7a8d36cbdbe6fb224afabb7ae +6050e523bae6de61de4e060facc43dc512adaccd diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 9ef4996992a4..083918de0f3a 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -301,34 +301,19 @@ fn setup(ask_user: bool) { .stdout; let sysroot = std::str::from_utf8(&sysroot).unwrap(); let sysroot = Path::new(sysroot.trim_end_matches('\n')); - // First try: `$SYSROOT/lib/rustlib/src/rust`; test if that contains `Cargo.lock`. - let rustup_src = sysroot.join("lib").join("rustlib").join("src").join("rust"); - let base_dir = if rustup_src.join("Cargo.lock").exists() { - // Just use this. - rustup_src - } else { - // Maybe this is a local toolchain built with `x.py` and linked into `rustup`? - // Second try: `$SYSROOT/../../..`; test if that contains `x.py`. - let local_src = sysroot.parent().and_then(Path::parent).and_then(Path::parent); - match local_src { - Some(local_src) if local_src.join("x.py").exists() => { - // Use this. - PathBuf::from(local_src) - } - _ => { - // Fallback: Ask the user to install the `rust-src` component, and use that. - let mut cmd = Command::new("rustup"); - cmd.args(&["component", "add", "rust-src"]); - ask_to_run( - cmd, - ask_user, - "install the rustc-src component for the selected toolchain", - ); - rustup_src - } - } - }; - base_dir.join("src") // Xargo wants the src-subdir + // Check for `$SYSROOT/lib/rustlib/src/rust/src`; test if that contains `libstd/lib.rs`. + let rustup_src = sysroot.join("lib").join("rustlib").join("src").join("rust").join("src"); + if !rustup_src.join("libstd").join("lib.rs").exists() { + // Ask the user to install the `rust-src` component, and use that. + let mut cmd = Command::new("rustup"); + cmd.args(&["component", "add", "rust-src"]); + ask_to_run( + cmd, + ask_user, + "install the rustc-src component for the selected toolchain", + ); + } + rustup_src } }; if !rust_src.exists() { From 73210be73baace3006e9a63b290e2356276a1173 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 Apr 2020 19:35:46 +0200 Subject: [PATCH 1784/5092] tweak README --- README.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index f755f85b601e..1c2c885674a5 100644 --- a/README.md +++ b/README.md @@ -87,8 +87,8 @@ miri run -- -Zmiri-disable-validation` runs the program without validation of basic type invariants and without checking the aliasing of references. When compiling code via `cargo miri`, the `miri` config flag is set. You can -use this to ignore test cases that will fail under Miri because they do things -Miri does not support: +use this to ignore test cases that fail under Miri because they do things Miri +does not support: ```rust #[test] @@ -100,12 +100,11 @@ fn does_not_work_on_miri() { } ``` -An exhaustive list of what `miri` does not support is not available, as this could be -an unbounded set with FFI and more. However `miri` will explicitly tell you when it finds -something unsupported with an error, containing a message such as: +There is no way to list all the infinite things Miri cannot do, but the +interpreter will explicitly tell you when it finds something unsupported: ``` -error: unsupported operation: can't call foreign function: mach_timebase_info +error: unsupported operation: Miri does not support threading ... = help: this is likely not a bug in the program; it indicates that the program \ performed an operation that the interpreter does not support From 0eccf1d9aa753a04b6dd0b276c9bd11a1fd5534e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Apr 2020 09:42:39 +0200 Subject: [PATCH 1785/5092] update Windows leak comment --- src/eval.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 46e66bc0a81e..54ace889c7a9 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -183,8 +183,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( /// Returns `Some(return_code)` if program executed completed. /// Returns `None` if an evaluation error occured. pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option { - // FIXME: on Windows, locks and TLS dtor management allocate and leave that memory in `static`s. - // So we need https://github.com/rust-lang/miri/issues/940 to fix the leaks there. + // FIXME: on Windows, we ignore leaks (https://github.com/rust-lang/miri/issues/1302). let ignore_leaks = config.ignore_leaks || tcx.sess.target.target.target_os == "windows"; let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) { From 95ea03c124d988c6c16d826c180a14447e53daa8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Apr 2020 10:20:12 +0200 Subject: [PATCH 1786/5092] add empty line before backtrace, to separate it from help text --- src/diagnostics.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 9ff434021150..d12b21be5a60 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -102,7 +102,7 @@ pub fn report_error<'tcx, 'mir>( e.print_backtrace(); let msg = e.to_string(); - report_msg(ecx, &format!("{}: {}", title, msg), msg, &helps, true) + report_msg(ecx, &format!("{}: {}", title, msg), msg, helps, true) } /// Report an error or note (depending on the `error` argument) at the current frame's current statement. @@ -111,7 +111,7 @@ fn report_msg<'tcx, 'mir>( ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, title: &str, span_msg: String, - helps: &[String], + mut helps: Vec, error: bool, ) -> Option { let span = if let Some(frame) = ecx.stack().last() { @@ -125,8 +125,12 @@ fn report_msg<'tcx, 'mir>( ecx.tcx.sess.diagnostic().span_note_diag(span, title) }; err.span_label(span, span_msg); - for help in helps { - err.help(help); + if !helps.is_empty() { + // Add visual separator before backtrace. + helps.last_mut().unwrap().push_str("\n"); + for help in helps { + err.help(&help); + } } // Add backtrace let frames = ecx.generate_stacktrace(); @@ -178,7 +182,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx CreatedAlloc(AllocId(id)) => format!("created allocation with id {}", id), }; - report_msg(this, "tracking was triggered", msg, &[], false); + report_msg(this, "tracking was triggered", msg, vec![], false); } }); } From e7fafa190478bfbf6dfe661d8d02dc126fd86840 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Sun, 5 Apr 2020 15:21:15 +0200 Subject: [PATCH 1787/5092] Replace last_entry with last_key_value --- src/shims/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 52244dcfc847..c70cc874164f 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -56,7 +56,7 @@ impl FileHandler { let new_fd = candidate_new_fd.unwrap_or_else(|| { // find_map ran out of BTreeMap entries before finding a free fd, use one plus the // maximum fd in the map - self.handles.last_entry().map(|entry| entry.key().checked_add(1).unwrap()).unwrap_or(min_fd) + self.handles.last_key_value().map(|(fd, _)| fd.checked_add(1).unwrap()).unwrap_or(min_fd) }); self.handles.insert(new_fd, file_handle).unwrap_none(); From 46679bc9eff4f7f7414bc162c0e6c00e7b91cc39 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 26 Jan 2020 14:25:09 -0600 Subject: [PATCH 1788/5092] Add shims for RwLock::try_read/RwLock::try_write --- src/shims/foreign_items/posix.rs | 2 ++ tests/run-pass/sync.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index c9fd59c69327..4be63804a45b 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -271,8 +271,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "pthread_mutex_unlock" | "pthread_mutex_destroy" | "pthread_rwlock_rdlock" + | "pthread_rwlock_tryrdlock" | "pthread_rwlock_unlock" | "pthread_rwlock_wrlock" + | "pthread_rwlock_trywrlock" | "pthread_rwlock_destroy" | "pthread_condattr_init" | "pthread_condattr_setclock" diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index 54d79566eae4..14243349f967 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -12,7 +12,9 @@ fn main() { { let rw = sync::RwLock::new(0); drop(rw.read()); + drop(rw.try_read()); drop(rw.write()); + drop(rw.try_write()); drop(rw); } } From 88f319fb4c0597856d62ee67eba6354b496cbe8f Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 27 Jan 2020 21:49:06 -0600 Subject: [PATCH 1789/5092] Add failing tests for mutex and rwlock --- src/shims/foreign_items/posix.rs | 1 + tests/run-pass/sync.rs | 73 +++++++++++++++++++++++++++++--- 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 4be63804a45b..061ae93d8f67 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -268,6 +268,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "pthread_mutex_init" | "pthread_mutexattr_destroy" | "pthread_mutex_lock" + | "pthread_mutex_trylock" | "pthread_mutex_unlock" | "pthread_mutex_destroy" | "pthread_rwlock_rdlock" diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index 14243349f967..6a0b41d5f6a7 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -1,20 +1,81 @@ // Just instantiate some data structures to make sure we got all their foreign items covered. // Requires full MIR on Windows. +#![feature(rustc_private)] + use std::sync; +extern crate libc; + fn main() { let m = sync::Mutex::new(0); - drop(m.lock()); + { + let _guard = m.lock(); + let try_lock_error = m.try_lock().unwrap_err(); + if let sync::TryLockError::Poisoned(e) = try_lock_error { + panic!("{}", e); + } + } + drop(m.try_lock().unwrap()); drop(m); #[cfg(not(target_os = "windows"))] // TODO: implement RwLock on Windows { let rw = sync::RwLock::new(0); - drop(rw.read()); - drop(rw.try_read()); - drop(rw.write()); - drop(rw.try_write()); - drop(rw); + { + let _read_guard = rw.read().unwrap(); + drop(rw.read().unwrap()); + drop(rw.try_read().unwrap()); + let try_lock_error = rw.try_write().unwrap_err(); + if let sync::TryLockError::Poisoned(e) = try_lock_error { + panic!("{}", e); + } + } + + { + let _write_guard = rw.write().unwrap(); + let try_lock_error = rw.try_read().unwrap_err(); + if let sync::TryLockError::Poisoned(e) = try_lock_error { + panic!("{}", e); + } + let try_lock_error = rw.try_write().unwrap_err(); + if let sync::TryLockError::Poisoned(e) = try_lock_error { + panic!("{}", e); + } + } + + // need to go a layer deeper and test the behavior of libc functions, because + // std::sys::unix::rwlock::RWLock keeps track of write_locked and num_readers + + unsafe { + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, std::ptr::null_mut()), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), libc::EBUSY); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); + } + + unsafe { + let mut rw: libc::pthread_rwlock_t = std::mem::zeroed(); + assert_eq!(libc::pthread_rwlock_init(&mut rw as *mut _, std::ptr::null_mut()), 0); + + assert_eq!(libc::pthread_rwlock_rdlock(&mut rw as *mut _), 0); + assert_eq!(libc::pthread_rwlock_rdlock(&mut rw as *mut _), 0); + assert_eq!(libc::pthread_rwlock_unlock(&mut rw as *mut _), 0); + assert_eq!(libc::pthread_rwlock_tryrdlock(&mut rw as *mut _), 0); + assert_eq!(libc::pthread_rwlock_unlock(&mut rw as *mut _), 0); + assert_eq!(libc::pthread_rwlock_trywrlock(&mut rw as *mut _), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_unlock(&mut rw as *mut _), 0); + + assert_eq!(libc::pthread_rwlock_wrlock(&mut rw as *mut _), 0); + assert_eq!(libc::pthread_rwlock_tryrdlock(&mut rw as *mut _), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_trywrlock(&mut rw as *mut _), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_unlock(&mut rw as *mut _), 0); + + assert_eq!(libc::pthread_rwlock_destroy(&mut rw as *mut _), 0); + } } } From c2683dad34f6f51761661840de8164dd001bb782 Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 28 Jan 2020 21:07:09 -0600 Subject: [PATCH 1790/5092] Clean up test case --- tests/run-pass/sync.rs | 67 +++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index 6a0b41d5f6a7..8c92b47fb276 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -3,45 +3,33 @@ #![feature(rustc_private)] -use std::sync; +use std::sync::{Mutex, RwLock, TryLockError}; extern crate libc; fn main() { - let m = sync::Mutex::new(0); + let m = Mutex::new(0); { let _guard = m.lock(); - let try_lock_error = m.try_lock().unwrap_err(); - if let sync::TryLockError::Poisoned(e) = try_lock_error { - panic!("{}", e); - } + assert!(m.try_lock().unwrap_err().would_block()); } drop(m.try_lock().unwrap()); drop(m); #[cfg(not(target_os = "windows"))] // TODO: implement RwLock on Windows { - let rw = sync::RwLock::new(0); + let rw = RwLock::new(0); { let _read_guard = rw.read().unwrap(); drop(rw.read().unwrap()); drop(rw.try_read().unwrap()); - let try_lock_error = rw.try_write().unwrap_err(); - if let sync::TryLockError::Poisoned(e) = try_lock_error { - panic!("{}", e); - } + assert!(rw.try_write().unwrap_err().would_block()); } { let _write_guard = rw.write().unwrap(); - let try_lock_error = rw.try_read().unwrap_err(); - if let sync::TryLockError::Poisoned(e) = try_lock_error { - panic!("{}", e); - } - let try_lock_error = rw.try_write().unwrap_err(); - if let sync::TryLockError::Poisoned(e) = try_lock_error { - panic!("{}", e); - } + assert!(rw.try_read().unwrap_err().would_block()); + assert!(rw.try_write().unwrap_err().would_block()); } // need to go a layer deeper and test the behavior of libc functions, because @@ -58,24 +46,35 @@ fn main() { assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); } + let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { - let mut rw: libc::pthread_rwlock_t = std::mem::zeroed(); - assert_eq!(libc::pthread_rwlock_init(&mut rw as *mut _, std::ptr::null_mut()), 0); + assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_rdlock(&mut rw as *mut _), 0); - assert_eq!(libc::pthread_rwlock_rdlock(&mut rw as *mut _), 0); - assert_eq!(libc::pthread_rwlock_unlock(&mut rw as *mut _), 0); - assert_eq!(libc::pthread_rwlock_tryrdlock(&mut rw as *mut _), 0); - assert_eq!(libc::pthread_rwlock_unlock(&mut rw as *mut _), 0); - assert_eq!(libc::pthread_rwlock_trywrlock(&mut rw as *mut _), libc::EBUSY); - assert_eq!(libc::pthread_rwlock_unlock(&mut rw as *mut _), 0); + assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_wrlock(&mut rw as *mut _), 0); - assert_eq!(libc::pthread_rwlock_tryrdlock(&mut rw as *mut _), libc::EBUSY); - assert_eq!(libc::pthread_rwlock_trywrlock(&mut rw as *mut _), libc::EBUSY); - assert_eq!(libc::pthread_rwlock_unlock(&mut rw as *mut _), 0); - - assert_eq!(libc::pthread_rwlock_destroy(&mut rw as *mut _), 0); + assert_eq!(libc::pthread_rwlock_destroy(rw.get()), 0); + } + } +} + +trait TryLockErrorExt { + fn would_block(&self) -> bool; +} + +impl TryLockErrorExt for TryLockError { + fn would_block(&self) -> bool { + match self { + TryLockError::WouldBlock => true, + TryLockError::Poisoned(_) => false, } } } From dd9896b0f8752c71c82c5d538ec0b115ffb5cf4e Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 17 Feb 2020 21:30:24 -0600 Subject: [PATCH 1791/5092] Implement mutex and rwlock functions --- src/lib.rs | 1 + src/shims/foreign_items/posix.rs | 91 +++++-- src/shims/mod.rs | 1 + src/shims/sync.rs | 436 +++++++++++++++++++++++++++++++ tests/run-pass/sync.rs | 97 ++++--- 5 files changed, 567 insertions(+), 59 deletions(-) create mode 100644 src/shims/sync.rs diff --git a/src/lib.rs b/src/lib.rs index c04fbfeab98c..2f381b4a3454 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,6 +39,7 @@ pub use crate::shims::fs::{DirHandler, EvalContextExt as FileEvalContextExt, Fil pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::shims::os_str::EvalContextExt as OsStrEvalContextExt; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as PanicEvalContextExt}; +pub use crate::shims::sync::{EvalContextExt as SyncEvalContextExt}; pub use crate::shims::time::EvalContextExt as TimeEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::EvalContextExt as ShimsEvalContextExt; diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 061ae93d8f67..2b9e94ba11db 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -255,28 +255,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - // Incomplete shims that we "stub out" just to get pre-main initialziation code to work. + // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. | "pthread_attr_init" | "pthread_attr_destroy" | "pthread_self" - | "pthread_attr_setstacksize" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - this.write_null(dest)?; - } - | "pthread_mutexattr_init" - | "pthread_mutexattr_settype" - | "pthread_mutex_init" - | "pthread_mutexattr_destroy" - | "pthread_mutex_lock" - | "pthread_mutex_trylock" - | "pthread_mutex_unlock" - | "pthread_mutex_destroy" - | "pthread_rwlock_rdlock" - | "pthread_rwlock_tryrdlock" - | "pthread_rwlock_unlock" - | "pthread_rwlock_wrlock" - | "pthread_rwlock_trywrlock" - | "pthread_rwlock_destroy" + | "pthread_attr_setstacksize" | "pthread_condattr_init" | "pthread_condattr_setclock" | "pthread_cond_init" @@ -285,6 +269,77 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx => { this.write_null(dest)?; } + + "pthread_mutexattr_init" => { + let result = this.pthread_mutexattr_init(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "pthread_mutexattr_settype" => { + let result = this.pthread_mutexattr_settype(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "pthread_mutexattr_destroy" => { + let result = this.pthread_mutexattr_destroy(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "pthread_mutex_init" => { + let result = this.pthread_mutex_init(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "pthread_mutex_lock" => { + let result = this.pthread_mutex_lock(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "pthread_mutex_trylock" => { + let result = this.pthread_mutex_trylock(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "pthread_mutex_unlock" => { + let result = this.pthread_mutex_unlock(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "pthread_mutex_destroy" => { + let result = this.pthread_mutex_destroy(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "pthread_rwlock_rdlock" => { + let result = this.pthread_rwlock_rdlock(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "pthread_rwlock_tryrdlock" => { + let result = this.pthread_rwlock_tryrdlock(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "pthread_rwlock_wrlock" => { + let result = this.pthread_rwlock_wrlock(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "pthread_rwlock_trywrlock" => { + let result = this.pthread_rwlock_trywrlock(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "pthread_rwlock_unlock" => { + let result = this.pthread_rwlock_unlock(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "pthread_rwlock_destroy" => { + let result = this.pthread_rwlock_destroy(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + | "signal" | "sigaction" | "sigaltstack" diff --git a/src/shims/mod.rs b/src/shims/mod.rs index e5db537cff1f..764e404141e4 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -5,6 +5,7 @@ pub mod fs; pub mod intrinsics; pub mod os_str; pub mod panic; +pub mod sync; pub mod time; pub mod tls; diff --git a/src/shims/sync.rs b/src/shims/sync.rs new file mode 100644 index 000000000000..c9329586627d --- /dev/null +++ b/src/shims/sync.rs @@ -0,0 +1,436 @@ +use rustc_middle::ty::{TyKind, TypeAndMut}; +use rustc_target::abi::{LayoutOf, Size}; + +use crate::stacked_borrows::Tag; +use crate::*; + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + // pthread_mutexattr_t is either 4 or 8 bytes, depending on the platform + // memory layout: store an i32 in the first four bytes equal to the + // corresponding libc mutex kind constant (i.e. PTHREAD_MUTEX_NORMAL) + + fn pthread_mutexattr_init(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + check_ptr_target_min_size(this, attr_op, 4)?; + + let attr = this.read_scalar(attr_op)?.not_undef()?; + if this.is_null(attr)? { + return this.eval_libc_i32("EINVAL"); + } + + let attr_place = this.deref_operand(attr_op)?; + let i32_layout = this.layout_of(this.tcx.types.i32)?; + let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, this)?; + let default_kind = this.eval_libc("PTHREAD_MUTEX_DEFAULT")?; + this.write_scalar(default_kind, kind_place.into())?; + + Ok(0) + } + + fn pthread_mutexattr_settype( + &mut self, + attr_op: OpTy<'tcx, Tag>, + kind_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + check_ptr_target_min_size(this, attr_op, 4)?; + + let attr = this.read_scalar(attr_op)?.not_undef()?; + if this.is_null(attr)? { + return this.eval_libc_i32("EINVAL"); + } + + let kind = this.read_scalar(kind_op)?.not_undef()?; + if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? || + kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? || + kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { + let attr_place = this.deref_operand(attr_op)?; + let i32_layout = this.layout_of(this.tcx.types.i32)?; + let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, this)?; + this.write_scalar(kind, kind_place.into())?; + } else { + let einval = this.eval_libc_i32("EINVAL")?; + return Ok(einval); + } + + Ok(0) + } + + fn pthread_mutexattr_destroy(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + check_ptr_target_min_size(this, attr_op, 4)?; + + let attr = this.read_scalar(attr_op)?.not_undef()?; + if this.is_null(attr)? { + return this.eval_libc_i32("EINVAL"); + } + + let attr_place = this.deref_operand(attr_op)?; + let i32_layout = this.layout_of(this.tcx.types.i32)?; + let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, this)?; + this.write_scalar(ScalarMaybeUndef::Undef, kind_place.into())?; + + Ok(0) + } + + // pthread_mutex_t is between 24 and 48 bytes, depending on the platform + // memory layout: + // bytes 0-3: count of how many times this mutex has been locked, as a u32 + // bytes 12-15: mutex kind, as an i32 + // (the kind should be at this offset for compatibility with the static + // initializer macro) + + fn pthread_mutex_init( + &mut self, + mutex_op: OpTy<'tcx, Tag>, + attr_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + check_ptr_target_min_size(this, mutex_op, 16)?; + check_ptr_target_min_size(this, attr_op, 4)?; + + let mutex = this.read_scalar(mutex_op)?.not_undef()?; + if this.is_null(mutex)? { + return this.eval_libc_i32("EINVAL"); + } + let mutex_place = this.deref_operand(mutex_op)?; + + let i32_layout = this.layout_of(this.tcx.types.i32)?; + + let attr = this.read_scalar(attr_op)?.not_undef()?; + let kind = if this.is_null(attr)? { + this.eval_libc("PTHREAD_MUTEX_DEFAULT")? + } else { + let attr_place = this.deref_operand(attr_op)?; + let attr_kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, this)?; + this.read_scalar(attr_kind_place.into())?.not_undef()? + }; + + let u32_layout = this.layout_of(this.tcx.types.u32)?; + let locked_count_place = mutex_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + this.write_scalar(Scalar::from_u32(0), locked_count_place.into())?; + + let mutex_kind_place = mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, &*this.tcx)?; + this.write_scalar(kind, mutex_kind_place.into())?; + + Ok(0) + } + + fn pthread_mutex_lock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + check_ptr_target_min_size(this, mutex_op, 16)?; + + let mutex = this.read_scalar(mutex_op)?.not_undef()?; + if this.is_null(mutex)? { + return this.eval_libc_i32("EINVAL"); + } + let mutex_place = this.deref_operand(mutex_op)?; + + let i32_layout = this.layout_of(this.tcx.types.i32)?; + let kind_place = mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, this)?; + let kind = this.read_scalar(kind_place.into())?.not_undef()?; + + let u32_layout = this.layout_of(this.tcx.types.u32)?; + let locked_count_place = mutex_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + let locked_count = this.read_scalar(locked_count_place.into())?.to_u32()?; + + if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { + if locked_count == 0 { + this.write_scalar(Scalar::from_u32(1), locked_count_place.into())?; + Ok(0) + } else { + throw_unsup_format!("Deadlock due to locking a PTHREAD_MUTEX_NORMAL mutex twice"); + } + } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { + if locked_count == 0 { + this.write_scalar(Scalar::from_u32(1), locked_count_place.into())?; + Ok(0) + } else { + this.eval_libc_i32("EDEADLK") + } + } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { + this.write_scalar(Scalar::from_u32(locked_count + 1), locked_count_place.into())?; + Ok(0) + } else { + this.eval_libc_i32("EINVAL") + } + } + + fn pthread_mutex_trylock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + check_ptr_target_min_size(this, mutex_op, 16)?; + + let mutex = this.read_scalar(mutex_op)?.not_undef()?; + if this.is_null(mutex)? { + return this.eval_libc_i32("EINVAL"); + } + let mutex_place = this.deref_operand(mutex_op)?; + + let i32_layout = this.layout_of(this.tcx.types.i32)?; + let kind_place = mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, this)?; + let kind = this.read_scalar(kind_place.into())?.not_undef()?; + + let u32_layout = this.layout_of(this.tcx.types.u32)?; + let locked_count_place = mutex_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + let locked_count = this.read_scalar(locked_count_place.into())?.to_u32()?; + + if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? || + kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { + if locked_count == 0 { + this.write_scalar(Scalar::from_u32(1), locked_count_place.into())?; + Ok(0) + } else { + this.eval_libc_i32("EBUSY") + } + } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { + this.write_scalar(Scalar::from_u32(locked_count + 1), locked_count_place.into())?; + Ok(0) + } else { + this.eval_libc_i32("EINVAL") + } + } + + fn pthread_mutex_unlock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + check_ptr_target_min_size(this, mutex_op, 16)?; + + let mutex = this.read_scalar(mutex_op)?.not_undef()?; + if this.is_null(mutex)? { + return this.eval_libc_i32("EINVAL"); + } + let mutex_place = this.deref_operand(mutex_op)?; + + let i32_layout = this.layout_of(this.tcx.types.i32)?; + let kind_place = mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, this)?; + let kind = this.read_scalar(kind_place.into())?.not_undef()?; + + let u32_layout = this.layout_of(this.tcx.types.u32)?; + let locked_count_place = mutex_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + let locked_count = this.read_scalar(locked_count_place.into())?.to_u32()?; + + if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { + if locked_count == 1 { + this.write_scalar(Scalar::from_u32(0), locked_count_place.into())?; + Ok(0) + } else { + throw_ub_format!("Attempted to unlock a PTHREAD_MUTEX_NORMAL mutex that was not locked"); + } + } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { + if locked_count == 1 { + this.write_scalar(Scalar::from_u32(0), locked_count_place.into())?; + Ok(0) + } else { + this.eval_libc_i32("EPERM") + } + } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { + if locked_count > 0 { + this.write_scalar(Scalar::from_u32(locked_count - 1), locked_count_place.into())?; + Ok(0) + } else { + this.eval_libc_i32("EPERM") + } + } else { + this.eval_libc_i32("EINVAL") + } + } + + fn pthread_mutex_destroy(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + check_ptr_target_min_size(this, mutex_op, 16)?; + + let mutex = this.read_scalar(mutex_op)?.not_undef()?; + if this.is_null(mutex)? { + return this.eval_libc_i32("EINVAL"); + } + let mutex_place = this.deref_operand(mutex_op)?; + + let u32_layout = this.layout_of(this.tcx.types.u32)?; + let locked_count_place = mutex_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + if this.read_scalar(locked_count_place.into())?.to_u32()? != 0 { + return this.eval_libc_i32("EBUSY"); + } + + let i32_layout = this.layout_of(this.tcx.types.i32)?; + let kind_place = mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, this)?; + this.write_scalar(ScalarMaybeUndef::Undef, kind_place.into())?; + this.write_scalar(ScalarMaybeUndef::Undef, locked_count_place.into())?; + + Ok(0) + } + + // pthread_rwlock_t is between 32 and 56 bytes, depending on the platform + // memory layout: + // bytes 0-3: reader count, as a u32 + // bytes 4-7: writer count, as a u32 + + fn pthread_rwlock_rdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + check_ptr_target_min_size(this, rwlock_op, 8)?; + + let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; + if this.is_null(rwlock)? { + return this.eval_libc_i32("EINVAL"); + } + let rwlock_place = this.deref_operand(rwlock_op)?; + + let u32_layout = this.layout_of(this.tcx.types.u32)?; + let readers_place = rwlock_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + let writers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let readers = this.read_scalar(readers_place.into())?.to_u32()?; + let writers = this.read_scalar(writers_place.into())?.to_u32()?; + if writers != 0 { + throw_unsup_format!("Deadlock due to read-locking a pthreads read-write lock while it is already write-locked"); + } else { + this.write_scalar(Scalar::from_u32(readers + 1), readers_place.into())?; + Ok(0) + } + } + + fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + check_ptr_target_min_size(this, rwlock_op, 8)?; + + let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; + if this.is_null(rwlock)? { + return this.eval_libc_i32("EINVAL"); + } + let rwlock_place = this.deref_operand(rwlock_op)?; + + let u32_layout = this.layout_of(this.tcx.types.u32)?; + let readers_place = rwlock_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + let writers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let readers = this.read_scalar(readers_place.into())?.to_u32()?; + let writers = this.read_scalar(writers_place.into())?.to_u32()?; + if writers != 0 { + this.eval_libc_i32("EBUSY") + } else { + this.write_scalar(Scalar::from_u32(readers + 1), readers_place.into())?; + Ok(0) + } + } + + fn pthread_rwlock_wrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + check_ptr_target_min_size(this, rwlock_op, 8)?; + + let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; + if this.is_null(rwlock)? { + return this.eval_libc_i32("EINVAL"); + } + let rwlock_place = this.deref_operand(rwlock_op)?; + + let u32_layout = this.layout_of(this.tcx.types.u32)?; + let readers_place = rwlock_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + let writers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let readers = this.read_scalar(readers_place.into())?.to_u32()?; + let writers = this.read_scalar(writers_place.into())?.to_u32()?; + if readers != 0 { + throw_unsup_format!("Deadlock due to write-locking a pthreads read-write lock while it is already read-locked"); + } else if writers != 0 { + throw_unsup_format!("Deadlock due to write-locking a pthreads read-write lock while it is already write-locked"); + } else { + this.write_scalar(Scalar::from_u32(1), writers_place.into())?; + Ok(0) + } + } + + fn pthread_rwlock_trywrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + check_ptr_target_min_size(this, rwlock_op, 8)?; + + let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; + if this.is_null(rwlock)? { + return this.eval_libc_i32("EINVAL"); + } + let rwlock_place = this.deref_operand(rwlock_op)?; + + let u32_layout = this.layout_of(this.tcx.types.u32)?; + let readers_place = rwlock_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + let writers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let readers = this.read_scalar(readers_place.into())?.to_u32()?; + let writers = this.read_scalar(writers_place.into())?.to_u32()?; + if readers != 0 || writers != 0 { + this.eval_libc_i32("EBUSY") + } else { + this.write_scalar(Scalar::from_u32(1), writers_place.into())?; + Ok(0) + } + } + + fn pthread_rwlock_unlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + check_ptr_target_min_size(this, rwlock_op, 8)?; + + let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; + if this.is_null(rwlock)? { + return this.eval_libc_i32("EINVAL"); + } + let rwlock_place = this.deref_operand(rwlock_op)?; + + let u32_layout = this.layout_of(this.tcx.types.u32)?; + let readers_place = rwlock_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + let writers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let readers = this.read_scalar(readers_place.into())?.to_u32()?; + let writers = this.read_scalar(writers_place.into())?.to_u32()?; + if readers != 0 { + this.write_scalar(Scalar::from_u32(readers - 1), readers_place.into())?; + Ok(0) + } else if writers != 0 { + this.write_scalar(Scalar::from_u32(0), writers_place.into())?; + Ok(0) + } else { + this.eval_libc_i32("EPERM") + } + } + + fn pthread_rwlock_destroy(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + check_ptr_target_min_size(this, rwlock_op, 8)?; + + let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; + if this.is_null(rwlock)? { + return this.eval_libc_i32("EINVAL"); + } + let rwlock_place = this.deref_operand(rwlock_op)?; + + let u32_layout = this.layout_of(this.tcx.types.u32)?; + let readers_place = rwlock_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + if this.read_scalar(readers_place.into())?.to_u32()? != 0 { + return this.eval_libc_i32("EBUSY"); + } + let writers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + if this.read_scalar(writers_place.into())?.to_u32()? != 0 { + return this.eval_libc_i32("EBUSY"); + } + + this.write_scalar(ScalarMaybeUndef::Undef, readers_place.into())?; + this.write_scalar(ScalarMaybeUndef::Undef, writers_place.into())?; + + Ok(0) + } +} + +fn check_ptr_target_min_size<'mir, 'tcx: 'mir>(ecx: &MiriEvalContext<'mir, 'tcx>, operand: OpTy<'tcx, Tag>, min_size: u64) -> InterpResult<'tcx, ()> { + let target_ty = match operand.layout.ty.kind { + TyKind::RawPtr(TypeAndMut{ ty, mutbl: _ }) => ty, + _ => panic!("Argument to pthread function was not a raw pointer"), + }; + let target_layout = ecx.layout_of(target_ty)?; + assert!(target_layout.size.bytes() >= min_size); + Ok(()) +} diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index 8c92b47fb276..d6ce939c6c36 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -1,4 +1,3 @@ -// Just instantiate some data structures to make sure we got all their foreign items covered. // Requires full MIR on Windows. #![feature(rustc_private)] @@ -8,6 +7,16 @@ use std::sync::{Mutex, RwLock, TryLockError}; extern crate libc; fn main() { + test_mutex(); + #[cfg(not(target_os = "windows"))] // TODO: implement RwLock on Windows + { + test_rwlock_stdlib(); + test_rwlock_libc_init(); + test_rwlock_libc_static_initializer(); + } +} + +fn test_mutex() { let m = Mutex::new(0); { let _guard = m.lock(); @@ -15,54 +24,60 @@ fn main() { } drop(m.try_lock().unwrap()); drop(m); +} - #[cfg(not(target_os = "windows"))] // TODO: implement RwLock on Windows +#[cfg(not(target_os = "windows"))] +fn test_rwlock_stdlib() { + let rw = RwLock::new(0); { - let rw = RwLock::new(0); - { - let _read_guard = rw.read().unwrap(); - drop(rw.read().unwrap()); - drop(rw.try_read().unwrap()); - assert!(rw.try_write().unwrap_err().would_block()); - } + let _read_guard = rw.read().unwrap(); + drop(rw.read().unwrap()); + drop(rw.try_read().unwrap()); + assert!(rw.try_write().unwrap_err().would_block()); + } - { - let _write_guard = rw.write().unwrap(); - assert!(rw.try_read().unwrap_err().would_block()); - assert!(rw.try_write().unwrap_err().would_block()); - } + { + let _write_guard = rw.write().unwrap(); + assert!(rw.try_read().unwrap_err().would_block()); + assert!(rw.try_write().unwrap_err().would_block()); + } +} - // need to go a layer deeper and test the behavior of libc functions, because - // std::sys::unix::rwlock::RWLock keeps track of write_locked and num_readers +// need to go a layer deeper and test the behavior of libc functions, because +// std::sys::unix::rwlock::RWLock keeps track of write_locked and num_readers - unsafe { - let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, std::ptr::null_mut()), 0); - assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), libc::EBUSY); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); - } +#[cfg(not(target_os = "windows"))] +fn test_rwlock_libc_init() { + unsafe { + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, std::ptr::null_mut()), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), libc::EBUSY); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); + } +} - let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); - unsafe { - assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); - assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); +#[cfg(not(target_os = "windows"))] +fn test_rwlock_libc_static_initializer() { + let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); + unsafe { + assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), libc::EBUSY); - assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); - assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_destroy(rw.get()), 0); - } + assert_eq!(libc::pthread_rwlock_destroy(rw.get()), 0); } } From 765050f302f75a8f4c5de3ab527aec4d4f9f883e Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 17 Feb 2020 22:52:44 -0600 Subject: [PATCH 1792/5092] Revise mutex/rwlock memory layout for macOS compat --- src/shims/sync.rs | 54 ++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index c9329586627d..320872773031 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -79,7 +79,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // pthread_mutex_t is between 24 and 48 bytes, depending on the platform // memory layout: - // bytes 0-3: count of how many times this mutex has been locked, as a u32 + // bytes 0-3: reserved for signature on macOS + // bytes 4-7: count of how many times this mutex has been locked, as a u32 // bytes 12-15: mutex kind, as an i32 // (the kind should be at this offset for compatibility with the static // initializer macro) @@ -112,7 +113,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; let u32_layout = this.layout_of(this.tcx.types.u32)?; - let locked_count_place = mutex_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + let locked_count_place = mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; this.write_scalar(Scalar::from_u32(0), locked_count_place.into())?; let mutex_kind_place = mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, &*this.tcx)?; @@ -137,7 +138,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let kind = this.read_scalar(kind_place.into())?.not_undef()?; let u32_layout = this.layout_of(this.tcx.types.u32)?; - let locked_count_place = mutex_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + let locked_count_place = mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; let locked_count = this.read_scalar(locked_count_place.into())?.to_u32()?; if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { @@ -178,7 +179,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let kind = this.read_scalar(kind_place.into())?.not_undef()?; let u32_layout = this.layout_of(this.tcx.types.u32)?; - let locked_count_place = mutex_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + let locked_count_place = mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; let locked_count = this.read_scalar(locked_count_place.into())?.to_u32()?; if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? || @@ -213,7 +214,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let kind = this.read_scalar(kind_place.into())?.not_undef()?; let u32_layout = this.layout_of(this.tcx.types.u32)?; - let locked_count_place = mutex_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + let locked_count_place = mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; let locked_count = this.read_scalar(locked_count_place.into())?.to_u32()?; if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { @@ -254,7 +255,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mutex_place = this.deref_operand(mutex_op)?; let u32_layout = this.layout_of(this.tcx.types.u32)?; - let locked_count_place = mutex_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + let locked_count_place = mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; if this.read_scalar(locked_count_place.into())?.to_u32()? != 0 { return this.eval_libc_i32("EBUSY"); } @@ -269,13 +270,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // pthread_rwlock_t is between 32 and 56 bytes, depending on the platform // memory layout: - // bytes 0-3: reader count, as a u32 - // bytes 4-7: writer count, as a u32 + // bytes 0-3: reserved for signature on macOS + // bytes 4-7: reader count, as a u32 + // bytes 8-11: writer count, as a u32 fn pthread_rwlock_rdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, rwlock_op, 8)?; + check_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { @@ -284,8 +286,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let rwlock_place = this.deref_operand(rwlock_op)?; let u32_layout = this.layout_of(this.tcx.types.u32)?; - let readers_place = rwlock_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; - let writers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?; let readers = this.read_scalar(readers_place.into())?.to_u32()?; let writers = this.read_scalar(writers_place.into())?.to_u32()?; if writers != 0 { @@ -299,7 +301,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, rwlock_op, 8)?; + check_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { @@ -308,8 +310,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let rwlock_place = this.deref_operand(rwlock_op)?; let u32_layout = this.layout_of(this.tcx.types.u32)?; - let readers_place = rwlock_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; - let writers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?; let readers = this.read_scalar(readers_place.into())?.to_u32()?; let writers = this.read_scalar(writers_place.into())?.to_u32()?; if writers != 0 { @@ -323,7 +325,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_wrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, rwlock_op, 8)?; + check_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { @@ -332,8 +334,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let rwlock_place = this.deref_operand(rwlock_op)?; let u32_layout = this.layout_of(this.tcx.types.u32)?; - let readers_place = rwlock_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; - let writers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?; let readers = this.read_scalar(readers_place.into())?.to_u32()?; let writers = this.read_scalar(writers_place.into())?.to_u32()?; if readers != 0 { @@ -349,7 +351,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_trywrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, rwlock_op, 8)?; + check_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { @@ -358,8 +360,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let rwlock_place = this.deref_operand(rwlock_op)?; let u32_layout = this.layout_of(this.tcx.types.u32)?; - let readers_place = rwlock_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; - let writers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?; let readers = this.read_scalar(readers_place.into())?.to_u32()?; let writers = this.read_scalar(writers_place.into())?.to_u32()?; if readers != 0 || writers != 0 { @@ -373,7 +375,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_unlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, rwlock_op, 8)?; + check_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { @@ -382,8 +384,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let rwlock_place = this.deref_operand(rwlock_op)?; let u32_layout = this.layout_of(this.tcx.types.u32)?; - let readers_place = rwlock_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; - let writers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?; let readers = this.read_scalar(readers_place.into())?.to_u32()?; let writers = this.read_scalar(writers_place.into())?.to_u32()?; if readers != 0 { @@ -400,7 +402,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_destroy(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, rwlock_op, 8)?; + check_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { @@ -409,11 +411,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let rwlock_place = this.deref_operand(rwlock_op)?; let u32_layout = this.layout_of(this.tcx.types.u32)?; - let readers_place = rwlock_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; if this.read_scalar(readers_place.into())?.to_u32()? != 0 { return this.eval_libc_i32("EBUSY"); } - let writers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?; if this.read_scalar(writers_place.into())?.to_u32()? != 0 { return this.eval_libc_i32("EBUSY"); } From dca83d73cbfe847738cbd310a4da786979768dd0 Mon Sep 17 00:00:00 2001 From: David Cook Date: Thu, 20 Feb 2020 22:19:51 -0600 Subject: [PATCH 1793/5092] Add test that exercises ReentrantMutex --- tests/run-pass/reentrant-println.rs | 17 +++++++++++++++++ tests/run-pass/reentrant-println.stdout | 2 ++ 2 files changed, 19 insertions(+) create mode 100644 tests/run-pass/reentrant-println.rs create mode 100644 tests/run-pass/reentrant-println.stdout diff --git a/tests/run-pass/reentrant-println.rs b/tests/run-pass/reentrant-println.rs new file mode 100644 index 000000000000..3703d21e0421 --- /dev/null +++ b/tests/run-pass/reentrant-println.rs @@ -0,0 +1,17 @@ +use std::fmt::{Display, Error, Formatter}; + +// This test case exercises std::sys_common::remutex::ReentrantMutex +// by calling println!() from inside fmt + +struct InterruptingCow(); + +impl Display for InterruptingCow { + fn fmt(&self, _f: &mut Formatter<'_>) -> Result<(), Error> { + println!("Moo"); + Ok(()) + } +} + +fn main() { + println!("\"Knock knock\" \"Who's {} there?\"", InterruptingCow()); +} diff --git a/tests/run-pass/reentrant-println.stdout b/tests/run-pass/reentrant-println.stdout new file mode 100644 index 000000000000..8a57d32f84ca --- /dev/null +++ b/tests/run-pass/reentrant-println.stdout @@ -0,0 +1,2 @@ +"Knock knock" "Who's Moo + there?" From c773ca8614772115788fb59a8cdab49efd09e477 Mon Sep 17 00:00:00 2001 From: David Cook Date: Fri, 21 Feb 2020 19:05:24 -0600 Subject: [PATCH 1794/5092] Style fixes --- tests/run-pass/reentrant-println.rs | 4 ++-- tests/run-pass/sync.rs | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/run-pass/reentrant-println.rs b/tests/run-pass/reentrant-println.rs index 3703d21e0421..09c4fc3f74d3 100644 --- a/tests/run-pass/reentrant-println.rs +++ b/tests/run-pass/reentrant-println.rs @@ -3,7 +3,7 @@ use std::fmt::{Display, Error, Formatter}; // This test case exercises std::sys_common::remutex::ReentrantMutex // by calling println!() from inside fmt -struct InterruptingCow(); +struct InterruptingCow; impl Display for InterruptingCow { fn fmt(&self, _f: &mut Formatter<'_>) -> Result<(), Error> { @@ -13,5 +13,5 @@ impl Display for InterruptingCow { } fn main() { - println!("\"Knock knock\" \"Who's {} there?\"", InterruptingCow()); + println!("\"Knock knock\" \"Who's {} there?\"", InterruptingCow); } diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index d6ce939c6c36..46cad3c16201 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -1,5 +1,3 @@ -// Requires full MIR on Windows. - #![feature(rustc_private)] use std::sync::{Mutex, RwLock, TryLockError}; From 5cc091bc6e307c4e46f94aac6cf54d0e0e2ce70a Mon Sep 17 00:00:00 2001 From: David Cook Date: Fri, 21 Feb 2020 19:10:20 -0600 Subject: [PATCH 1795/5092] Add test of recursive mutex using libc FFI --- tests/run-pass/sync.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index 46cad3c16201..b24706108379 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -8,6 +8,7 @@ fn main() { test_mutex(); #[cfg(not(target_os = "windows"))] // TODO: implement RwLock on Windows { + test_mutex_libc_recursive(); test_rwlock_stdlib(); test_rwlock_libc_init(); test_rwlock_libc_static_initializer(); @@ -24,6 +25,28 @@ fn test_mutex() { drop(m); } +#[cfg(not(target_os = "windows"))] +fn test_mutex_libc_recursive() { + unsafe { + let mut attr: libc::pthread_mutexattr_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutexattr_init(&mut attr as *mut _), 0); + assert_eq!(libc::pthread_mutexattr_settype(&mut attr as *mut _, libc::PTHREAD_MUTEX_RECURSIVE), 0); + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mut attr as *mut _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), libc::EPERM); + assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutexattr_destroy(&mut attr as *mut _), 0); + } +} + #[cfg(not(target_os = "windows"))] fn test_rwlock_stdlib() { let rw = RwLock::new(0); From d11315ebfb4c2d95a1ca6c52bec105237b10e933 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 15 Mar 2020 15:10:08 -0500 Subject: [PATCH 1796/5092] Fix misleading function names --- src/shims/sync.rs | 32 ++++++++++++++++---------------- tests/run-pass/sync.rs | 4 ++-- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 320872773031..22e62beae2f2 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -13,7 +13,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutexattr_init(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, attr_op, 4)?; + assert_ptr_target_min_size(this, attr_op, 4)?; let attr = this.read_scalar(attr_op)?.not_undef()?; if this.is_null(attr)? { @@ -36,7 +36,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, attr_op, 4)?; + assert_ptr_target_min_size(this, attr_op, 4)?; let attr = this.read_scalar(attr_op)?.not_undef()?; if this.is_null(attr)? { @@ -62,7 +62,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutexattr_destroy(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, attr_op, 4)?; + assert_ptr_target_min_size(this, attr_op, 4)?; let attr = this.read_scalar(attr_op)?.not_undef()?; if this.is_null(attr)? { @@ -92,8 +92,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, mutex_op, 16)?; - check_ptr_target_min_size(this, attr_op, 4)?; + assert_ptr_target_min_size(this, mutex_op, 16)?; + assert_ptr_target_min_size(this, attr_op, 4)?; let mutex = this.read_scalar(mutex_op)?.not_undef()?; if this.is_null(mutex)? { @@ -125,7 +125,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_lock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, mutex_op, 16)?; + assert_ptr_target_min_size(this, mutex_op, 16)?; let mutex = this.read_scalar(mutex_op)?.not_undef()?; if this.is_null(mutex)? { @@ -166,7 +166,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_trylock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, mutex_op, 16)?; + assert_ptr_target_min_size(this, mutex_op, 16)?; let mutex = this.read_scalar(mutex_op)?.not_undef()?; if this.is_null(mutex)? { @@ -201,7 +201,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_unlock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, mutex_op, 16)?; + assert_ptr_target_min_size(this, mutex_op, 16)?; let mutex = this.read_scalar(mutex_op)?.not_undef()?; if this.is_null(mutex)? { @@ -246,7 +246,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_destroy(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, mutex_op, 16)?; + assert_ptr_target_min_size(this, mutex_op, 16)?; let mutex = this.read_scalar(mutex_op)?.not_undef()?; if this.is_null(mutex)? { @@ -277,7 +277,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_rdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, rwlock_op, 12)?; + assert_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { @@ -301,7 +301,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, rwlock_op, 12)?; + assert_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { @@ -325,7 +325,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_wrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, rwlock_op, 12)?; + assert_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { @@ -351,7 +351,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_trywrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, rwlock_op, 12)?; + assert_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { @@ -375,7 +375,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_unlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, rwlock_op, 12)?; + assert_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { @@ -402,7 +402,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_destroy(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, rwlock_op, 12)?; + assert_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { @@ -427,7 +427,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } -fn check_ptr_target_min_size<'mir, 'tcx: 'mir>(ecx: &MiriEvalContext<'mir, 'tcx>, operand: OpTy<'tcx, Tag>, min_size: u64) -> InterpResult<'tcx, ()> { +fn assert_ptr_target_min_size<'mir, 'tcx: 'mir>(ecx: &MiriEvalContext<'mir, 'tcx>, operand: OpTy<'tcx, Tag>, min_size: u64) -> InterpResult<'tcx, ()> { let target_ty = match operand.layout.ty.kind { TyKind::RawPtr(TypeAndMut{ ty, mutbl: _ }) => ty, _ => panic!("Argument to pthread function was not a raw pointer"), diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index b24706108379..c1e44789aa74 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -10,7 +10,7 @@ fn main() { { test_mutex_libc_recursive(); test_rwlock_stdlib(); - test_rwlock_libc_init(); + test_mutex_libc_init(); test_rwlock_libc_static_initializer(); } } @@ -68,7 +68,7 @@ fn test_rwlock_stdlib() { // std::sys::unix::rwlock::RWLock keeps track of write_locked and num_readers #[cfg(not(target_os = "windows"))] -fn test_rwlock_libc_init() { +fn test_mutex_libc_init() { unsafe { let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, std::ptr::null_mut()), 0); From fd94255b9d4ab69b110bb5d2acef5c288fe4a0e1 Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 17 Mar 2020 08:19:57 -0500 Subject: [PATCH 1797/5092] Add comments explaining asserts --- src/shims/sync.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 22e62beae2f2..61346bfd85ba 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -13,6 +13,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutexattr_init(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Ensure that the following write at an offset to the attr pointer is within bounds assert_ptr_target_min_size(this, attr_op, 4)?; let attr = this.read_scalar(attr_op)?.not_undef()?; @@ -36,6 +37,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Ensure that the following write at an offset to the attr pointer is within bounds assert_ptr_target_min_size(this, attr_op, 4)?; let attr = this.read_scalar(attr_op)?.not_undef()?; @@ -62,6 +64,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutexattr_destroy(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Ensure that the following write at an offset to the attr pointer is within bounds assert_ptr_target_min_size(this, attr_op, 4)?; let attr = this.read_scalar(attr_op)?.not_undef()?; @@ -92,7 +95,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Ensure that the following writes at offsets to the mutex pointer are within bounds assert_ptr_target_min_size(this, mutex_op, 16)?; + // Ensure that the following read at an offset to the attr pointer is within bounds assert_ptr_target_min_size(this, attr_op, 4)?; let mutex = this.read_scalar(mutex_op)?.not_undef()?; @@ -125,6 +130,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_lock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Ensure that the following reads and writes at offsets to the mutex pointer are within bounds assert_ptr_target_min_size(this, mutex_op, 16)?; let mutex = this.read_scalar(mutex_op)?.not_undef()?; @@ -166,6 +172,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_trylock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Ensure that the following reads and writes at offsets to the mutex pointer are within bounds assert_ptr_target_min_size(this, mutex_op, 16)?; let mutex = this.read_scalar(mutex_op)?.not_undef()?; @@ -201,6 +208,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_unlock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Ensure that the following reads and writes at offsets to the mutex pointer are within bounds assert_ptr_target_min_size(this, mutex_op, 16)?; let mutex = this.read_scalar(mutex_op)?.not_undef()?; @@ -246,6 +254,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_destroy(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Ensure that the following read and writes at offsets to the mutex pointer are within bounds assert_ptr_target_min_size(this, mutex_op, 16)?; let mutex = this.read_scalar(mutex_op)?.not_undef()?; @@ -277,6 +286,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_rdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Ensure that the following reads and write at offsets to the rwlock pointer are within bounds assert_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; @@ -301,6 +311,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Ensure that the following reads and write at offsets to the rwlock pointer are within bounds assert_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; @@ -325,6 +336,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_wrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Ensure that the following reads and write at offsets to the rwlock pointer are within bounds assert_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; @@ -351,6 +363,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_trywrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Ensure that the following reads and write at offsets to the rwlock pointer are within bounds assert_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; @@ -375,6 +388,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_unlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Ensure that the following reads and writes at offsets to the rwlock pointer are within bounds assert_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; @@ -402,6 +416,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_destroy(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Ensure that the following reads and writes at offsets to the rwlock pointer are within bounds assert_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; From 141319a412ddca4a2b16f45eed459c4a735e8f8f Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 22 Mar 2020 15:18:02 -0500 Subject: [PATCH 1798/5092] Refactor sync shims with setters and getters --- src/shims/sync.rs | 400 +++++++++++++++++++++++++--------------------- 1 file changed, 219 insertions(+), 181 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 61346bfd85ba..b8d9a88865e6 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -6,26 +6,16 @@ use crate::*; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - // pthread_mutexattr_t is either 4 or 8 bytes, depending on the platform - // memory layout: store an i32 in the first four bytes equal to the - // corresponding libc mutex kind constant (i.e. PTHREAD_MUTEX_NORMAL) - fn pthread_mutexattr_init(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Ensure that the following write at an offset to the attr pointer is within bounds - assert_ptr_target_min_size(this, attr_op, 4)?; - let attr = this.read_scalar(attr_op)?.not_undef()?; if this.is_null(attr)? { return this.eval_libc_i32("EINVAL"); } - let attr_place = this.deref_operand(attr_op)?; - let i32_layout = this.layout_of(this.tcx.types.i32)?; - let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, this)?; let default_kind = this.eval_libc("PTHREAD_MUTEX_DEFAULT")?; - this.write_scalar(default_kind, kind_place.into())?; + mutexattr_set_kind(this, attr_op, default_kind)?; Ok(0) } @@ -37,22 +27,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Ensure that the following write at an offset to the attr pointer is within bounds - assert_ptr_target_min_size(this, attr_op, 4)?; - let attr = this.read_scalar(attr_op)?.not_undef()?; if this.is_null(attr)? { return this.eval_libc_i32("EINVAL"); } let kind = this.read_scalar(kind_op)?.not_undef()?; - if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? || - kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? || - kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { - let attr_place = this.deref_operand(attr_op)?; - let i32_layout = this.layout_of(this.tcx.types.i32)?; - let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, this)?; - this.write_scalar(kind, kind_place.into())?; + if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? + || kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? + || kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? + { + mutexattr_set_kind(this, attr_op, kind)?; } else { let einval = this.eval_libc_i32("EINVAL")?; return Ok(einval); @@ -64,30 +49,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutexattr_destroy(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Ensure that the following write at an offset to the attr pointer is within bounds - assert_ptr_target_min_size(this, attr_op, 4)?; - let attr = this.read_scalar(attr_op)?.not_undef()?; if this.is_null(attr)? { return this.eval_libc_i32("EINVAL"); } - let attr_place = this.deref_operand(attr_op)?; - let i32_layout = this.layout_of(this.tcx.types.i32)?; - let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, this)?; - this.write_scalar(ScalarMaybeUndef::Undef, kind_place.into())?; + mutexattr_set_kind(this, attr_op, ScalarMaybeUndef::Undef)?; Ok(0) } - // pthread_mutex_t is between 24 and 48 bytes, depending on the platform - // memory layout: - // bytes 0-3: reserved for signature on macOS - // bytes 4-7: count of how many times this mutex has been locked, as a u32 - // bytes 12-15: mutex kind, as an i32 - // (the kind should be at this offset for compatibility with the static - // initializer macro) - fn pthread_mutex_init( &mut self, mutex_op: OpTy<'tcx, Tag>, @@ -95,34 +66,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Ensure that the following writes at offsets to the mutex pointer are within bounds - assert_ptr_target_min_size(this, mutex_op, 16)?; - // Ensure that the following read at an offset to the attr pointer is within bounds - assert_ptr_target_min_size(this, attr_op, 4)?; - let mutex = this.read_scalar(mutex_op)?.not_undef()?; if this.is_null(mutex)? { return this.eval_libc_i32("EINVAL"); } - let mutex_place = this.deref_operand(mutex_op)?; - - let i32_layout = this.layout_of(this.tcx.types.i32)?; let attr = this.read_scalar(attr_op)?.not_undef()?; let kind = if this.is_null(attr)? { this.eval_libc("PTHREAD_MUTEX_DEFAULT")? } else { - let attr_place = this.deref_operand(attr_op)?; - let attr_kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, this)?; - this.read_scalar(attr_kind_place.into())?.not_undef()? + mutexattr_get_kind(this, attr_op)?.not_undef()? }; - let u32_layout = this.layout_of(this.tcx.types.u32)?; - let locked_count_place = mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; - this.write_scalar(Scalar::from_u32(0), locked_count_place.into())?; - - let mutex_kind_place = mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, &*this.tcx)?; - this.write_scalar(kind, mutex_kind_place.into())?; + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(0))?; + mutex_set_kind(this, mutex_op, kind)?; Ok(0) } @@ -130,39 +87,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_lock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Ensure that the following reads and writes at offsets to the mutex pointer are within bounds - assert_ptr_target_min_size(this, mutex_op, 16)?; - let mutex = this.read_scalar(mutex_op)?.not_undef()?; if this.is_null(mutex)? { return this.eval_libc_i32("EINVAL"); } - let mutex_place = this.deref_operand(mutex_op)?; - let i32_layout = this.layout_of(this.tcx.types.i32)?; - let kind_place = mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, this)?; - let kind = this.read_scalar(kind_place.into())?.not_undef()?; - - let u32_layout = this.layout_of(this.tcx.types.u32)?; - let locked_count_place = mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; - let locked_count = this.read_scalar(locked_count_place.into())?.to_u32()?; + let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; + let locked_count = mutex_get_locked_count(this, mutex_op)?.to_u32()?; if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { if locked_count == 0 { - this.write_scalar(Scalar::from_u32(1), locked_count_place.into())?; + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(1))?; Ok(0) } else { throw_unsup_format!("Deadlock due to locking a PTHREAD_MUTEX_NORMAL mutex twice"); } } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { if locked_count == 0 { - this.write_scalar(Scalar::from_u32(1), locked_count_place.into())?; + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(1))?; Ok(0) } else { this.eval_libc_i32("EDEADLK") } } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { - this.write_scalar(Scalar::from_u32(locked_count + 1), locked_count_place.into())?; + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(locked_count + 1))?; Ok(0) } else { this.eval_libc_i32("EINVAL") @@ -172,33 +120,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_trylock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Ensure that the following reads and writes at offsets to the mutex pointer are within bounds - assert_ptr_target_min_size(this, mutex_op, 16)?; - let mutex = this.read_scalar(mutex_op)?.not_undef()?; if this.is_null(mutex)? { return this.eval_libc_i32("EINVAL"); } - let mutex_place = this.deref_operand(mutex_op)?; - let i32_layout = this.layout_of(this.tcx.types.i32)?; - let kind_place = mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, this)?; - let kind = this.read_scalar(kind_place.into())?.not_undef()?; + let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; + let locked_count = mutex_get_locked_count(this, mutex_op)?.to_u32()?; - let u32_layout = this.layout_of(this.tcx.types.u32)?; - let locked_count_place = mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; - let locked_count = this.read_scalar(locked_count_place.into())?.to_u32()?; - - if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? || - kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { + if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? + || kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? + { if locked_count == 0 { - this.write_scalar(Scalar::from_u32(1), locked_count_place.into())?; + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(1))?; Ok(0) } else { this.eval_libc_i32("EBUSY") } } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { - this.write_scalar(Scalar::from_u32(locked_count + 1), locked_count_place.into())?; + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(locked_count + 1))?; Ok(0) } else { this.eval_libc_i32("EINVAL") @@ -208,40 +148,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_unlock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Ensure that the following reads and writes at offsets to the mutex pointer are within bounds - assert_ptr_target_min_size(this, mutex_op, 16)?; - let mutex = this.read_scalar(mutex_op)?.not_undef()?; if this.is_null(mutex)? { return this.eval_libc_i32("EINVAL"); } - let mutex_place = this.deref_operand(mutex_op)?; - let i32_layout = this.layout_of(this.tcx.types.i32)?; - let kind_place = mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, this)?; - let kind = this.read_scalar(kind_place.into())?.not_undef()?; - - let u32_layout = this.layout_of(this.tcx.types.u32)?; - let locked_count_place = mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; - let locked_count = this.read_scalar(locked_count_place.into())?.to_u32()?; + let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; + let locked_count = mutex_get_locked_count(this, mutex_op)?.to_u32()?; if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { if locked_count == 1 { - this.write_scalar(Scalar::from_u32(0), locked_count_place.into())?; + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(0))?; Ok(0) } else { - throw_ub_format!("Attempted to unlock a PTHREAD_MUTEX_NORMAL mutex that was not locked"); + throw_ub_format!( + "Attempted to unlock a PTHREAD_MUTEX_NORMAL mutex that was not locked" + ); } } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { if locked_count == 1 { - this.write_scalar(Scalar::from_u32(0), locked_count_place.into())?; + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(0))?; Ok(0) } else { this.eval_libc_i32("EPERM") } } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { if locked_count > 0 { - this.write_scalar(Scalar::from_u32(locked_count - 1), locked_count_place.into())?; + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(locked_count - 1))?; Ok(0) } else { this.eval_libc_i32("EPERM") @@ -254,56 +187,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_destroy(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Ensure that the following read and writes at offsets to the mutex pointer are within bounds - assert_ptr_target_min_size(this, mutex_op, 16)?; - let mutex = this.read_scalar(mutex_op)?.not_undef()?; if this.is_null(mutex)? { return this.eval_libc_i32("EINVAL"); } - let mutex_place = this.deref_operand(mutex_op)?; - let u32_layout = this.layout_of(this.tcx.types.u32)?; - let locked_count_place = mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; - if this.read_scalar(locked_count_place.into())?.to_u32()? != 0 { + if mutex_get_locked_count(this, mutex_op)?.to_u32()? != 0 { return this.eval_libc_i32("EBUSY"); } - let i32_layout = this.layout_of(this.tcx.types.i32)?; - let kind_place = mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, this)?; - this.write_scalar(ScalarMaybeUndef::Undef, kind_place.into())?; - this.write_scalar(ScalarMaybeUndef::Undef, locked_count_place.into())?; + mutex_set_kind(this, mutex_op, ScalarMaybeUndef::Undef)?; + mutex_set_locked_count(this, mutex_op, ScalarMaybeUndef::Undef)?; Ok(0) } - // pthread_rwlock_t is between 32 and 56 bytes, depending on the platform - // memory layout: - // bytes 0-3: reserved for signature on macOS - // bytes 4-7: reader count, as a u32 - // bytes 8-11: writer count, as a u32 - fn pthread_rwlock_rdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Ensure that the following reads and write at offsets to the rwlock pointer are within bounds - assert_ptr_target_min_size(this, rwlock_op, 12)?; - let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { return this.eval_libc_i32("EINVAL"); } - let rwlock_place = this.deref_operand(rwlock_op)?; - let u32_layout = this.layout_of(this.tcx.types.u32)?; - let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; - let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?; - let readers = this.read_scalar(readers_place.into())?.to_u32()?; - let writers = this.read_scalar(writers_place.into())?.to_u32()?; + let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; + let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; if writers != 0 { - throw_unsup_format!("Deadlock due to read-locking a pthreads read-write lock while it is already write-locked"); + throw_unsup_format!( + "Deadlock due to read-locking a pthreads read-write lock while it is already write-locked" + ); } else { - this.write_scalar(Scalar::from_u32(readers + 1), readers_place.into())?; + rwlock_set_readers(this, rwlock_op, Scalar::from_u32(readers + 1))?; Ok(0) } } @@ -311,24 +225,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Ensure that the following reads and write at offsets to the rwlock pointer are within bounds - assert_ptr_target_min_size(this, rwlock_op, 12)?; - let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { return this.eval_libc_i32("EINVAL"); } - let rwlock_place = this.deref_operand(rwlock_op)?; - let u32_layout = this.layout_of(this.tcx.types.u32)?; - let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; - let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?; - let readers = this.read_scalar(readers_place.into())?.to_u32()?; - let writers = this.read_scalar(writers_place.into())?.to_u32()?; + let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; + let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; if writers != 0 { this.eval_libc_i32("EBUSY") } else { - this.write_scalar(Scalar::from_u32(readers + 1), readers_place.into())?; + rwlock_set_readers(this, rwlock_op, Scalar::from_u32(readers + 1))?; Ok(0) } } @@ -336,26 +243,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_wrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Ensure that the following reads and write at offsets to the rwlock pointer are within bounds - assert_ptr_target_min_size(this, rwlock_op, 12)?; - let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { return this.eval_libc_i32("EINVAL"); } - let rwlock_place = this.deref_operand(rwlock_op)?; - let u32_layout = this.layout_of(this.tcx.types.u32)?; - let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; - let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?; - let readers = this.read_scalar(readers_place.into())?.to_u32()?; - let writers = this.read_scalar(writers_place.into())?.to_u32()?; + let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; + let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; if readers != 0 { - throw_unsup_format!("Deadlock due to write-locking a pthreads read-write lock while it is already read-locked"); + throw_unsup_format!( + "Deadlock due to write-locking a pthreads read-write lock while it is already read-locked" + ); } else if writers != 0 { - throw_unsup_format!("Deadlock due to write-locking a pthreads read-write lock while it is already write-locked"); + throw_unsup_format!( + "Deadlock due to write-locking a pthreads read-write lock while it is already write-locked" + ); } else { - this.write_scalar(Scalar::from_u32(1), writers_place.into())?; + rwlock_set_writers(this, rwlock_op, Scalar::from_u32(1))?; Ok(0) } } @@ -363,24 +267,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_trywrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Ensure that the following reads and write at offsets to the rwlock pointer are within bounds - assert_ptr_target_min_size(this, rwlock_op, 12)?; - let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { return this.eval_libc_i32("EINVAL"); } - let rwlock_place = this.deref_operand(rwlock_op)?; - let u32_layout = this.layout_of(this.tcx.types.u32)?; - let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; - let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?; - let readers = this.read_scalar(readers_place.into())?.to_u32()?; - let writers = this.read_scalar(writers_place.into())?.to_u32()?; + let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; + let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; if readers != 0 || writers != 0 { this.eval_libc_i32("EBUSY") } else { - this.write_scalar(Scalar::from_u32(1), writers_place.into())?; + rwlock_set_writers(this, rwlock_op, Scalar::from_u32(1))?; Ok(0) } } @@ -388,25 +285,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_unlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Ensure that the following reads and writes at offsets to the rwlock pointer are within bounds - assert_ptr_target_min_size(this, rwlock_op, 12)?; - let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { return this.eval_libc_i32("EINVAL"); } - let rwlock_place = this.deref_operand(rwlock_op)?; - let u32_layout = this.layout_of(this.tcx.types.u32)?; - let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; - let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?; - let readers = this.read_scalar(readers_place.into())?.to_u32()?; - let writers = this.read_scalar(writers_place.into())?.to_u32()?; + let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; + let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; if readers != 0 { - this.write_scalar(Scalar::from_u32(readers - 1), readers_place.into())?; + rwlock_set_readers(this, rwlock_op, Scalar::from_u32(readers - 1))?; Ok(0) } else if writers != 0 { - this.write_scalar(Scalar::from_u32(0), writers_place.into())?; + rwlock_set_writers(this, rwlock_op, Scalar::from_u32(0))?; Ok(0) } else { this.eval_libc_i32("EPERM") @@ -416,38 +306,186 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_destroy(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Ensure that the following reads and writes at offsets to the rwlock pointer are within bounds - assert_ptr_target_min_size(this, rwlock_op, 12)?; - let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { return this.eval_libc_i32("EINVAL"); } - let rwlock_place = this.deref_operand(rwlock_op)?; - let u32_layout = this.layout_of(this.tcx.types.u32)?; - let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; - if this.read_scalar(readers_place.into())?.to_u32()? != 0 { + if rwlock_get_readers(this, rwlock_op)?.to_u32()? != 0 { return this.eval_libc_i32("EBUSY"); } - let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?; - if this.read_scalar(writers_place.into())?.to_u32()? != 0 { + if rwlock_get_writers(this, rwlock_op)?.to_u32()? != 0 { return this.eval_libc_i32("EBUSY"); } - this.write_scalar(ScalarMaybeUndef::Undef, readers_place.into())?; - this.write_scalar(ScalarMaybeUndef::Undef, writers_place.into())?; + rwlock_set_readers(this, rwlock_op, ScalarMaybeUndef::Undef)?; + rwlock_set_writers(this, rwlock_op, ScalarMaybeUndef::Undef)?; Ok(0) } } -fn assert_ptr_target_min_size<'mir, 'tcx: 'mir>(ecx: &MiriEvalContext<'mir, 'tcx>, operand: OpTy<'tcx, Tag>, min_size: u64) -> InterpResult<'tcx, ()> { +fn assert_ptr_target_min_size<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + operand: OpTy<'tcx, Tag>, + min_size: u64, +) -> InterpResult<'tcx, ()> { let target_ty = match operand.layout.ty.kind { - TyKind::RawPtr(TypeAndMut{ ty, mutbl: _ }) => ty, + TyKind::RawPtr(TypeAndMut { ty, mutbl: _ }) => ty, _ => panic!("Argument to pthread function was not a raw pointer"), }; let target_layout = ecx.layout_of(target_ty)?; assert!(target_layout.size.bytes() >= min_size); Ok(()) } + +// pthread_mutexattr_t is either 4 or 8 bytes, depending on the platform +// memory layout: store an i32 in the first four bytes equal to the +// corresponding libc mutex kind constant (i.e. PTHREAD_MUTEX_NORMAL) + +fn mutexattr_get_kind<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + attr_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the attr pointer is within bounds + assert_ptr_target_min_size(ecx, attr_op, 4)?; + let attr_place = ecx.deref_operand(attr_op)?; + let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; + let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, ecx)?; + ecx.read_scalar(kind_place.into()) +} + +fn mutexattr_set_kind<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + attr_op: OpTy<'tcx, Tag>, + kind: impl Into>, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the attr pointer is within bounds + assert_ptr_target_min_size(ecx, attr_op, 4)?; + let attr_place = ecx.deref_operand(attr_op)?; + let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; + let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, ecx)?; + ecx.write_scalar(kind.into(), kind_place.into()) +} + +// pthread_mutex_t is between 24 and 48 bytes, depending on the platform +// memory layout: +// bytes 0-3: reserved for signature on macOS +// bytes 4-7: count of how many times this mutex has been locked, as a u32 +// bytes 12-15: mutex kind, as an i32 +// (the kind should be at this offset for compatibility with the static +// initializer macro) + +fn mutex_get_locked_count<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + mutex_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the mutex pointer is within bounds + assert_ptr_target_min_size(ecx, mutex_op, 16)?; + let mutex_place = ecx.deref_operand(mutex_op)?; + let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; + let locked_count_place = + mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; + ecx.read_scalar(locked_count_place.into()) +} + +fn mutex_set_locked_count<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + mutex_op: OpTy<'tcx, Tag>, + locked_count: impl Into>, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the mutex pointer is within bounds + assert_ptr_target_min_size(ecx, mutex_op, 16)?; + let mutex_place = ecx.deref_operand(mutex_op)?; + let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; + let locked_count_place = + mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; + ecx.write_scalar(locked_count.into(), locked_count_place.into()) +} + +fn mutex_get_kind<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + mutex_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the mutex pointer is within bounds + assert_ptr_target_min_size(ecx, mutex_op, 16)?; + let mutex_place = ecx.deref_operand(mutex_op)?; + let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; + let kind_place = + mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, ecx)?; + ecx.read_scalar(kind_place.into()) +} + +fn mutex_set_kind<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + mutex_op: OpTy<'tcx, Tag>, + kind: impl Into>, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the mutex pointer is within bounds + assert_ptr_target_min_size(ecx, mutex_op, 16)?; + let mutex_place = ecx.deref_operand(mutex_op)?; + let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; + let kind_place = + mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, ecx)?; + ecx.write_scalar(kind.into(), kind_place.into()) +} + +// pthread_rwlock_t is between 32 and 56 bytes, depending on the platform +// memory layout: +// bytes 0-3: reserved for signature on macOS +// bytes 4-7: reader count, as a u32 +// bytes 8-11: writer count, as a u32 + +fn rwlock_get_readers<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + rwlock_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the rwlock pointer is within bounds + assert_ptr_target_min_size(ecx, rwlock_op, 12)?; + let rwlock_place = ecx.deref_operand(rwlock_op)?; + let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; + let readers_place = + rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; + ecx.read_scalar(readers_place.into()) +} + +fn rwlock_set_readers<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + rwlock_op: OpTy<'tcx, Tag>, + readers: impl Into>, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the rwlock pointer is within bounds + assert_ptr_target_min_size(ecx, rwlock_op, 12)?; + let rwlock_place = ecx.deref_operand(rwlock_op)?; + let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; + let readers_place = + rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; + ecx.write_scalar(readers.into(), readers_place.into()) +} + +fn rwlock_get_writers<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + rwlock_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the rwlock pointer is within bounds + assert_ptr_target_min_size(ecx, rwlock_op, 12)?; + let rwlock_place = ecx.deref_operand(rwlock_op)?; + let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; + let writers_place = + rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, ecx)?; + ecx.read_scalar(writers_place.into()) +} + +fn rwlock_set_writers<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + rwlock_op: OpTy<'tcx, Tag>, + writers: impl Into>, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the rwlock pointer is within bounds + assert_ptr_target_min_size(ecx, rwlock_op, 12)?; + let rwlock_place = ecx.deref_operand(rwlock_op)?; + let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; + let writers_place = + rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, ecx)?; + ecx.write_scalar(writers.into(), writers_place.into()) +} From ba3884dae6d34370c0841d61acefe8d4a3f8d05c Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 22 Mar 2020 16:16:02 -0500 Subject: [PATCH 1799/5092] Use checked addition/subtraction on lock counts --- src/shims/sync.rs | 54 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index b8d9a88865e6..987513d323ec 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -110,8 +110,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.eval_libc_i32("EDEADLK") } } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(locked_count + 1))?; - Ok(0) + match locked_count.checked_add(1) { + Some(new_count) => { + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(new_count))?; + Ok(0) + } + None => this.eval_libc_i32("EAGAIN"), + } } else { this.eval_libc_i32("EINVAL") } @@ -138,8 +143,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.eval_libc_i32("EBUSY") } } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(locked_count + 1))?; - Ok(0) + match locked_count.checked_add(1) { + Some(new_count) => { + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(new_count))?; + Ok(0) + } + None => this.eval_libc_i32("EAGAIN"), + } } else { this.eval_libc_i32("EINVAL") } @@ -173,11 +183,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.eval_libc_i32("EPERM") } } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { - if locked_count > 0 { - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(locked_count - 1))?; - Ok(0) - } else { - this.eval_libc_i32("EPERM") + match locked_count.checked_sub(1) { + Some(new_count) => { + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(new_count))?; + Ok(0) + } + None => { + // locked_count was already zero + this.eval_libc_i32("EPERM") + } } } else { this.eval_libc_i32("EINVAL") @@ -217,8 +231,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "Deadlock due to read-locking a pthreads read-write lock while it is already write-locked" ); } else { - rwlock_set_readers(this, rwlock_op, Scalar::from_u32(readers + 1))?; - Ok(0) + match readers.checked_add(1) { + Some(new_readers) => { + rwlock_set_readers(this, rwlock_op, Scalar::from_u32(new_readers))?; + Ok(0) + } + None => this.eval_libc_i32("EAGAIN"), + } } } @@ -235,8 +254,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if writers != 0 { this.eval_libc_i32("EBUSY") } else { - rwlock_set_readers(this, rwlock_op, Scalar::from_u32(readers + 1))?; - Ok(0) + match readers.checked_add(1) { + Some(new_readers) => { + rwlock_set_readers(this, rwlock_op, Scalar::from_u32(new_readers))?; + Ok(0) + } + None => this.eval_libc_i32("EAGAIN"), + } } } @@ -292,8 +316,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; - if readers != 0 { - rwlock_set_readers(this, rwlock_op, Scalar::from_u32(readers - 1))?; + if let Some(new_readers) = readers.checked_sub(1) { + rwlock_set_readers(this, rwlock_op, Scalar::from_u32(new_readers))?; Ok(0) } else if writers != 0 { rwlock_set_writers(this, rwlock_op, Scalar::from_u32(0))?; From e5e3256b5942a0c2e280700fff7f33bbdc803436 Mon Sep 17 00:00:00 2001 From: David Cook Date: Thu, 26 Mar 2020 21:23:10 -0500 Subject: [PATCH 1800/5092] Address review comments --- src/shims/sync.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 987513d323ec..960eca5510a2 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -167,7 +167,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let locked_count = mutex_get_locked_count(this, mutex_op)?.to_u32()?; if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { - if locked_count == 1 { + if locked_count != 0 { mutex_set_locked_count(this, mutex_op, Scalar::from_u32(0))?; Ok(0) } else { @@ -176,7 +176,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); } } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { - if locked_count == 1 { + if locked_count != 0 { mutex_set_locked_count(this, mutex_op, Scalar::from_u32(0))?; Ok(0) } else { @@ -363,8 +363,9 @@ fn assert_ptr_target_min_size<'mir, 'tcx: 'mir>( Ok(()) } -// pthread_mutexattr_t is either 4 or 8 bytes, depending on the platform -// memory layout: store an i32 in the first four bytes equal to the +// pthread_mutexattr_t is either 4 or 8 bytes, depending on the platform. + +// Our chosen memory layout: store an i32 in the first four bytes equal to the // corresponding libc mutex kind constant (i.e. PTHREAD_MUTEX_NORMAL) fn mutexattr_get_kind<'mir, 'tcx: 'mir>( @@ -392,13 +393,14 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( ecx.write_scalar(kind.into(), kind_place.into()) } -// pthread_mutex_t is between 24 and 48 bytes, depending on the platform -// memory layout: +// pthread_mutex_t is between 24 and 48 bytes, depending on the platform. + +// Our chosen memory layout: // bytes 0-3: reserved for signature on macOS +// (need to avoid this because it is set by static initializer macros) // bytes 4-7: count of how many times this mutex has been locked, as a u32 // bytes 12-15: mutex kind, as an i32 -// (the kind should be at this offset for compatibility with the static -// initializer macro) +// (the kind has to be at this offset for compatibility with static initializer macros) fn mutex_get_locked_count<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, @@ -454,9 +456,11 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( ecx.write_scalar(kind.into(), kind_place.into()) } -// pthread_rwlock_t is between 32 and 56 bytes, depending on the platform -// memory layout: +// pthread_rwlock_t is between 32 and 56 bytes, depending on the platform. + +// Our chosen memory layout: // bytes 0-3: reserved for signature on macOS +// (need to avoid this because it is set by static initializer macros) // bytes 4-7: reader count, as a u32 // bytes 8-11: writer count, as a u32 From 735fc12e1ad35e8789a922eb506f64756f499a32 Mon Sep 17 00:00:00 2001 From: David Cook Date: Fri, 27 Mar 2020 20:06:53 -0500 Subject: [PATCH 1801/5092] Handle variation in layout of pthread_mutex_t --- src/shims/sync.rs | 86 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 74 insertions(+), 12 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 960eca5510a2..6ce45e3ad4dd 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -1,5 +1,7 @@ +use std::sync::atomic::{AtomicU64, Ordering}; + use rustc_middle::ty::{TyKind, TypeAndMut}; -use rustc_target::abi::{LayoutOf, Size}; +use rustc_target::abi::{FieldsShape, LayoutOf, Size}; use crate::stacked_borrows::Tag; use crate::*; @@ -399,15 +401,67 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( // bytes 0-3: reserved for signature on macOS // (need to avoid this because it is set by static initializer macros) // bytes 4-7: count of how many times this mutex has been locked, as a u32 -// bytes 12-15: mutex kind, as an i32 -// (the kind has to be at this offset for compatibility with static initializer macros) +// bytes 12-15 or 16-19 (depending on platform): mutex kind, as an i32 +// (the kind has to be at its offset for compatibility with static initializer macros) + +static LIBC_MUTEX_KIND_OFFSET_CACHE: AtomicU64 = AtomicU64::new(0); + +fn libc_mutex_kind_offset<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, +) -> InterpResult<'tcx, u64> { + // Check if this offset has already been found and memoized + let cached_value = LIBC_MUTEX_KIND_OFFSET_CACHE.load(Ordering::Relaxed); + if cached_value != 0 { + return Ok(cached_value); + } + + // This function infers the offset of the `kind` field of libc's pthread_mutex_t + // C struct by examining the array inside libc::PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP. + // At time of writing, it is always all zero bytes except for a one byte at one of + // four positions, depending on the target OS's C struct layout and the endianness of the + // target architecture. This offset will then be used in getters and setters below, so that + // mutexes created from static initializers can be emulated with the correct behavior. + let initializer_path = ["libc", "PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP"]; + let initializer_instance = ecx.resolve_path(&initializer_path); + let initializer_cid = GlobalId { instance: initializer_instance, promoted: None }; + let initializer_const_val = ecx.const_eval_raw(initializer_cid)?; + let array_mplacety = ecx.mplace_field(initializer_const_val, 0)?; + let array_length = match array_mplacety.layout.fields { + FieldsShape::Array { count, .. } => count, + _ => bug!("Couldn't get array length from type {:?}", array_mplacety.layout.ty), + }; + + let kind_offset = if array_length < 20 { + bug!("libc::PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP array was shorter than expected"); + } else if ecx.read_scalar(ecx.mplace_field(array_mplacety, 16)?.into())?.to_u8()? != 0 { + // for little-endian architectures + 16 + } else if ecx.read_scalar(ecx.mplace_field(array_mplacety, 19)?.into())?.to_u8()? != 0 { + // for big-endian architectures + // (note that the i32 spans bytes 16 through 19, so the offset of the kind field is 16) + 16 + } else if ecx.read_scalar(ecx.mplace_field(array_mplacety, 12)?.into())?.to_u8()? != 0 { + // for little-endian architectures + 12 + } else if ecx.read_scalar(ecx.mplace_field(array_mplacety, 15)?.into())?.to_u8()? != 0 { + // for big-endian architectures + // (note that the i32 spans bytes 12 through 15, so the offset of the kind field is 12) + 12 + } else { + bug!("Couldn't determine offset of `kind` in pthread_mutex_t"); + }; + + // Save offset to memoization cache for future calls + LIBC_MUTEX_KIND_OFFSET_CACHE.store(kind_offset, Ordering::Relaxed); + Ok(kind_offset) +} fn mutex_get_locked_count<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { // Ensure that the following read at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 16)?; + assert_ptr_target_min_size(ecx, mutex_op, 20)?; let mutex_place = ecx.deref_operand(mutex_op)?; let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; let locked_count_place = @@ -421,7 +475,7 @@ fn mutex_set_locked_count<'mir, 'tcx: 'mir>( locked_count: impl Into>, ) -> InterpResult<'tcx, ()> { // Ensure that the following write at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 16)?; + assert_ptr_target_min_size(ecx, mutex_op, 20)?; let mutex_place = ecx.deref_operand(mutex_op)?; let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; let locked_count_place = @@ -430,15 +484,19 @@ fn mutex_set_locked_count<'mir, 'tcx: 'mir>( } fn mutex_get_kind<'mir, 'tcx: 'mir>( - ecx: &MiriEvalContext<'mir, 'tcx>, + ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { // Ensure that the following read at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 16)?; + assert_ptr_target_min_size(ecx, mutex_op, 20)?; let mutex_place = ecx.deref_operand(mutex_op)?; let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; - let kind_place = - mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, ecx)?; + let kind_place = mutex_place.offset( + Size::from_bytes(libc_mutex_kind_offset(ecx)?), + MemPlaceMeta::None, + i32_layout, + ecx, + )?; ecx.read_scalar(kind_place.into()) } @@ -448,11 +506,15 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( kind: impl Into>, ) -> InterpResult<'tcx, ()> { // Ensure that the following write at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 16)?; + assert_ptr_target_min_size(ecx, mutex_op, 20)?; let mutex_place = ecx.deref_operand(mutex_op)?; let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; - let kind_place = - mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, ecx)?; + let kind_place = mutex_place.offset( + Size::from_bytes(libc_mutex_kind_offset(ecx)?), + MemPlaceMeta::None, + i32_layout, + ecx, + )?; ecx.write_scalar(kind.into(), kind_place.into()) } From de29546414cc5a987fd3317a9c3e5415e15a133b Mon Sep 17 00:00:00 2001 From: David Cook Date: Fri, 27 Mar 2020 20:26:21 -0500 Subject: [PATCH 1802/5092] Add and rearrange mutex tests --- tests/run-pass/sync.rs | 58 ++++++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index c1e44789aa74..025ae81372cf 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -5,17 +5,18 @@ use std::sync::{Mutex, RwLock, TryLockError}; extern crate libc; fn main() { - test_mutex(); + test_mutex_stdlib(); #[cfg(not(target_os = "windows"))] // TODO: implement RwLock on Windows { - test_mutex_libc_recursive(); + test_mutex_libc_init_recursive(); + test_mutex_libc_init_normal(); + test_mutex_libc_static_initializer_recursive(); test_rwlock_stdlib(); - test_mutex_libc_init(); test_rwlock_libc_static_initializer(); } } -fn test_mutex() { +fn test_mutex_stdlib() { let m = Mutex::new(0); { let _guard = m.lock(); @@ -26,7 +27,7 @@ fn test_mutex() { } #[cfg(not(target_os = "windows"))] -fn test_mutex_libc_recursive() { +fn test_mutex_libc_init_recursive() { unsafe { let mut attr: libc::pthread_mutexattr_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutexattr_init(&mut attr as *mut _), 0); @@ -47,6 +48,39 @@ fn test_mutex_libc_recursive() { } } +#[cfg(not(target_os = "windows"))] +fn test_mutex_libc_init_normal() { + unsafe { + let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), 0); + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), libc::EBUSY); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); + } +} + +#[cfg(not(target_os = "windows"))] +fn test_mutex_libc_static_initializer_recursive() { + let mutex = std::cell::UnsafeCell::new(libc::PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP); + unsafe { + assert_eq!(libc::pthread_mutex_lock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_trylock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_trylock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_lock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), libc::EPERM); + assert_eq!(libc::pthread_mutex_destroy(mutex.get()), 0); + } +} + #[cfg(not(target_os = "windows"))] fn test_rwlock_stdlib() { let rw = RwLock::new(0); @@ -67,20 +101,6 @@ fn test_rwlock_stdlib() { // need to go a layer deeper and test the behavior of libc functions, because // std::sys::unix::rwlock::RWLock keeps track of write_locked and num_readers -#[cfg(not(target_os = "windows"))] -fn test_mutex_libc_init() { - unsafe { - let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, std::ptr::null_mut()), 0); - assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), libc::EBUSY); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); - } -} - #[cfg(not(target_os = "windows"))] fn test_rwlock_libc_static_initializer() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); From c7466c9531c1a282380183c78001014c35dc9fac Mon Sep 17 00:00:00 2001 From: David Cook Date: Fri, 27 Mar 2020 20:40:54 -0500 Subject: [PATCH 1803/5092] Add TerminationInfo::Deadlock, use in mutex shim --- src/diagnostics.rs | 6 +++- src/shims/sync.rs | 76 +++++----------------------------------------- 2 files changed, 13 insertions(+), 69 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 9ff434021150..2b53efe864e5 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -12,7 +12,8 @@ pub enum TerminationInfo { Exit(i64), Abort(Option), UnsupportedInIsolation(String), - ExperimentalUb { msg: String, url: String } + ExperimentalUb { msg: String, url: String }, + Deadlock, } impl fmt::Debug for TerminationInfo { @@ -29,6 +30,8 @@ impl fmt::Debug for TerminationInfo { write!(f, "{}", msg), ExperimentalUb { msg, .. } => write!(f, "{}", msg), + Deadlock => + write!(f, "the evaluated program deadlocked"), } } } @@ -60,6 +63,7 @@ pub fn report_error<'tcx, 'mir>( "unsupported operation", ExperimentalUb { .. } => "Undefined Behavior", + Deadlock => "deadlock", }; let helps = match info { UnsupportedInIsolation(_) => diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 6ce45e3ad4dd..94e563353b88 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -1,7 +1,5 @@ -use std::sync::atomic::{AtomicU64, Ordering}; - use rustc_middle::ty::{TyKind, TypeAndMut}; -use rustc_target::abi::{FieldsShape, LayoutOf, Size}; +use rustc_target::abi::{LayoutOf, Size}; use crate::stacked_borrows::Tag; use crate::*; @@ -102,7 +100,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex_set_locked_count(this, mutex_op, Scalar::from_u32(1))?; Ok(0) } else { - throw_unsup_format!("Deadlock due to locking a PTHREAD_MUTEX_NORMAL mutex twice"); + throw_machine_stop!(TerminationInfo::Deadlock); } } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { if locked_count == 0 { @@ -404,58 +402,6 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( // bytes 12-15 or 16-19 (depending on platform): mutex kind, as an i32 // (the kind has to be at its offset for compatibility with static initializer macros) -static LIBC_MUTEX_KIND_OFFSET_CACHE: AtomicU64 = AtomicU64::new(0); - -fn libc_mutex_kind_offset<'mir, 'tcx: 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, -) -> InterpResult<'tcx, u64> { - // Check if this offset has already been found and memoized - let cached_value = LIBC_MUTEX_KIND_OFFSET_CACHE.load(Ordering::Relaxed); - if cached_value != 0 { - return Ok(cached_value); - } - - // This function infers the offset of the `kind` field of libc's pthread_mutex_t - // C struct by examining the array inside libc::PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP. - // At time of writing, it is always all zero bytes except for a one byte at one of - // four positions, depending on the target OS's C struct layout and the endianness of the - // target architecture. This offset will then be used in getters and setters below, so that - // mutexes created from static initializers can be emulated with the correct behavior. - let initializer_path = ["libc", "PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP"]; - let initializer_instance = ecx.resolve_path(&initializer_path); - let initializer_cid = GlobalId { instance: initializer_instance, promoted: None }; - let initializer_const_val = ecx.const_eval_raw(initializer_cid)?; - let array_mplacety = ecx.mplace_field(initializer_const_val, 0)?; - let array_length = match array_mplacety.layout.fields { - FieldsShape::Array { count, .. } => count, - _ => bug!("Couldn't get array length from type {:?}", array_mplacety.layout.ty), - }; - - let kind_offset = if array_length < 20 { - bug!("libc::PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP array was shorter than expected"); - } else if ecx.read_scalar(ecx.mplace_field(array_mplacety, 16)?.into())?.to_u8()? != 0 { - // for little-endian architectures - 16 - } else if ecx.read_scalar(ecx.mplace_field(array_mplacety, 19)?.into())?.to_u8()? != 0 { - // for big-endian architectures - // (note that the i32 spans bytes 16 through 19, so the offset of the kind field is 16) - 16 - } else if ecx.read_scalar(ecx.mplace_field(array_mplacety, 12)?.into())?.to_u8()? != 0 { - // for little-endian architectures - 12 - } else if ecx.read_scalar(ecx.mplace_field(array_mplacety, 15)?.into())?.to_u8()? != 0 { - // for big-endian architectures - // (note that the i32 spans bytes 12 through 15, so the offset of the kind field is 12) - 12 - } else { - bug!("Couldn't determine offset of `kind` in pthread_mutex_t"); - }; - - // Save offset to memoization cache for future calls - LIBC_MUTEX_KIND_OFFSET_CACHE.store(kind_offset, Ordering::Relaxed); - Ok(kind_offset) -} - fn mutex_get_locked_count<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, @@ -491,12 +437,9 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>( assert_ptr_target_min_size(ecx, mutex_op, 20)?; let mutex_place = ecx.deref_operand(mutex_op)?; let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; - let kind_place = mutex_place.offset( - Size::from_bytes(libc_mutex_kind_offset(ecx)?), - MemPlaceMeta::None, - i32_layout, - ecx, - )?; + let kind_offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; + let kind_place = + mutex_place.offset(Size::from_bytes(kind_offset), MemPlaceMeta::None, i32_layout, ecx)?; ecx.read_scalar(kind_place.into()) } @@ -509,12 +452,9 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( assert_ptr_target_min_size(ecx, mutex_op, 20)?; let mutex_place = ecx.deref_operand(mutex_op)?; let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; - let kind_place = mutex_place.offset( - Size::from_bytes(libc_mutex_kind_offset(ecx)?), - MemPlaceMeta::None, - i32_layout, - ecx, - )?; + let kind_offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; + let kind_place = + mutex_place.offset(Size::from_bytes(kind_offset), MemPlaceMeta::None, i32_layout, ecx)?; ecx.write_scalar(kind.into(), kind_place.into()) } From 7f6df15aa2215ade35992b396bb76c8ae8fcf4df Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 28 Mar 2020 09:25:02 -0500 Subject: [PATCH 1804/5092] Rearrange functions --- src/shims/sync.rs | 342 +++++++++++++++++++++++----------------------- 1 file changed, 171 insertions(+), 171 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 94e563353b88..4e4f8c112e53 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -4,6 +4,177 @@ use rustc_target::abi::{LayoutOf, Size}; use crate::stacked_borrows::Tag; use crate::*; +fn assert_ptr_target_min_size<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + operand: OpTy<'tcx, Tag>, + min_size: u64, +) -> InterpResult<'tcx, ()> { + let target_ty = match operand.layout.ty.kind { + TyKind::RawPtr(TypeAndMut { ty, mutbl: _ }) => ty, + _ => panic!("Argument to pthread function was not a raw pointer"), + }; + let target_layout = ecx.layout_of(target_ty)?; + assert!(target_layout.size.bytes() >= min_size); + Ok(()) +} + +// pthread_mutexattr_t is either 4 or 8 bytes, depending on the platform. + +// Our chosen memory layout: store an i32 in the first four bytes equal to the +// corresponding libc mutex kind constant (i.e. PTHREAD_MUTEX_NORMAL) + +fn mutexattr_get_kind<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + attr_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the attr pointer is within bounds + assert_ptr_target_min_size(ecx, attr_op, 4)?; + let attr_place = ecx.deref_operand(attr_op)?; + let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; + let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, ecx)?; + ecx.read_scalar(kind_place.into()) +} + +fn mutexattr_set_kind<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + attr_op: OpTy<'tcx, Tag>, + kind: impl Into>, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the attr pointer is within bounds + assert_ptr_target_min_size(ecx, attr_op, 4)?; + let attr_place = ecx.deref_operand(attr_op)?; + let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; + let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, ecx)?; + ecx.write_scalar(kind.into(), kind_place.into()) +} + +// pthread_mutex_t is between 24 and 48 bytes, depending on the platform. + +// Our chosen memory layout: +// bytes 0-3: reserved for signature on macOS +// (need to avoid this because it is set by static initializer macros) +// bytes 4-7: count of how many times this mutex has been locked, as a u32 +// bytes 12-15 or 16-19 (depending on platform): mutex kind, as an i32 +// (the kind has to be at its offset for compatibility with static initializer macros) + +fn mutex_get_locked_count<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + mutex_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the mutex pointer is within bounds + assert_ptr_target_min_size(ecx, mutex_op, 20)?; + let mutex_place = ecx.deref_operand(mutex_op)?; + let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; + let locked_count_place = + mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; + ecx.read_scalar(locked_count_place.into()) +} + +fn mutex_set_locked_count<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + mutex_op: OpTy<'tcx, Tag>, + locked_count: impl Into>, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the mutex pointer is within bounds + assert_ptr_target_min_size(ecx, mutex_op, 20)?; + let mutex_place = ecx.deref_operand(mutex_op)?; + let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; + let locked_count_place = + mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; + ecx.write_scalar(locked_count.into(), locked_count_place.into()) +} + +fn mutex_get_kind<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + mutex_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the mutex pointer is within bounds + assert_ptr_target_min_size(ecx, mutex_op, 20)?; + let mutex_place = ecx.deref_operand(mutex_op)?; + let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; + let kind_offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; + let kind_place = + mutex_place.offset(Size::from_bytes(kind_offset), MemPlaceMeta::None, i32_layout, ecx)?; + ecx.read_scalar(kind_place.into()) +} + +fn mutex_set_kind<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + mutex_op: OpTy<'tcx, Tag>, + kind: impl Into>, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the mutex pointer is within bounds + assert_ptr_target_min_size(ecx, mutex_op, 20)?; + let mutex_place = ecx.deref_operand(mutex_op)?; + let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; + let kind_offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; + let kind_place = + mutex_place.offset(Size::from_bytes(kind_offset), MemPlaceMeta::None, i32_layout, ecx)?; + ecx.write_scalar(kind.into(), kind_place.into()) +} + +// pthread_rwlock_t is between 32 and 56 bytes, depending on the platform. + +// Our chosen memory layout: +// bytes 0-3: reserved for signature on macOS +// (need to avoid this because it is set by static initializer macros) +// bytes 4-7: reader count, as a u32 +// bytes 8-11: writer count, as a u32 + +fn rwlock_get_readers<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + rwlock_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the rwlock pointer is within bounds + assert_ptr_target_min_size(ecx, rwlock_op, 12)?; + let rwlock_place = ecx.deref_operand(rwlock_op)?; + let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; + let readers_place = + rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; + ecx.read_scalar(readers_place.into()) +} + +fn rwlock_set_readers<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + rwlock_op: OpTy<'tcx, Tag>, + readers: impl Into>, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the rwlock pointer is within bounds + assert_ptr_target_min_size(ecx, rwlock_op, 12)?; + let rwlock_place = ecx.deref_operand(rwlock_op)?; + let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; + let readers_place = + rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; + ecx.write_scalar(readers.into(), readers_place.into()) +} + +fn rwlock_get_writers<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + rwlock_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the rwlock pointer is within bounds + assert_ptr_target_min_size(ecx, rwlock_op, 12)?; + let rwlock_place = ecx.deref_operand(rwlock_op)?; + let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; + let writers_place = + rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, ecx)?; + ecx.read_scalar(writers_place.into()) +} + +fn rwlock_set_writers<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + rwlock_op: OpTy<'tcx, Tag>, + writers: impl Into>, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the rwlock pointer is within bounds + assert_ptr_target_min_size(ecx, rwlock_op, 12)?; + let rwlock_place = ecx.deref_operand(rwlock_op)?; + let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; + let writers_place = + rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, ecx)?; + ecx.write_scalar(writers.into(), writers_place.into()) +} + impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn pthread_mutexattr_init(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { @@ -348,174 +519,3 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } } - -fn assert_ptr_target_min_size<'mir, 'tcx: 'mir>( - ecx: &MiriEvalContext<'mir, 'tcx>, - operand: OpTy<'tcx, Tag>, - min_size: u64, -) -> InterpResult<'tcx, ()> { - let target_ty = match operand.layout.ty.kind { - TyKind::RawPtr(TypeAndMut { ty, mutbl: _ }) => ty, - _ => panic!("Argument to pthread function was not a raw pointer"), - }; - let target_layout = ecx.layout_of(target_ty)?; - assert!(target_layout.size.bytes() >= min_size); - Ok(()) -} - -// pthread_mutexattr_t is either 4 or 8 bytes, depending on the platform. - -// Our chosen memory layout: store an i32 in the first four bytes equal to the -// corresponding libc mutex kind constant (i.e. PTHREAD_MUTEX_NORMAL) - -fn mutexattr_get_kind<'mir, 'tcx: 'mir>( - ecx: &MiriEvalContext<'mir, 'tcx>, - attr_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { - // Ensure that the following read at an offset to the attr pointer is within bounds - assert_ptr_target_min_size(ecx, attr_op, 4)?; - let attr_place = ecx.deref_operand(attr_op)?; - let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; - let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, ecx)?; - ecx.read_scalar(kind_place.into()) -} - -fn mutexattr_set_kind<'mir, 'tcx: 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, - attr_op: OpTy<'tcx, Tag>, - kind: impl Into>, -) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the attr pointer is within bounds - assert_ptr_target_min_size(ecx, attr_op, 4)?; - let attr_place = ecx.deref_operand(attr_op)?; - let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; - let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, ecx)?; - ecx.write_scalar(kind.into(), kind_place.into()) -} - -// pthread_mutex_t is between 24 and 48 bytes, depending on the platform. - -// Our chosen memory layout: -// bytes 0-3: reserved for signature on macOS -// (need to avoid this because it is set by static initializer macros) -// bytes 4-7: count of how many times this mutex has been locked, as a u32 -// bytes 12-15 or 16-19 (depending on platform): mutex kind, as an i32 -// (the kind has to be at its offset for compatibility with static initializer macros) - -fn mutex_get_locked_count<'mir, 'tcx: 'mir>( - ecx: &MiriEvalContext<'mir, 'tcx>, - mutex_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { - // Ensure that the following read at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 20)?; - let mutex_place = ecx.deref_operand(mutex_op)?; - let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; - let locked_count_place = - mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; - ecx.read_scalar(locked_count_place.into()) -} - -fn mutex_set_locked_count<'mir, 'tcx: 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, - mutex_op: OpTy<'tcx, Tag>, - locked_count: impl Into>, -) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 20)?; - let mutex_place = ecx.deref_operand(mutex_op)?; - let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; - let locked_count_place = - mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; - ecx.write_scalar(locked_count.into(), locked_count_place.into()) -} - -fn mutex_get_kind<'mir, 'tcx: 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, - mutex_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { - // Ensure that the following read at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 20)?; - let mutex_place = ecx.deref_operand(mutex_op)?; - let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; - let kind_offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - let kind_place = - mutex_place.offset(Size::from_bytes(kind_offset), MemPlaceMeta::None, i32_layout, ecx)?; - ecx.read_scalar(kind_place.into()) -} - -fn mutex_set_kind<'mir, 'tcx: 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, - mutex_op: OpTy<'tcx, Tag>, - kind: impl Into>, -) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 20)?; - let mutex_place = ecx.deref_operand(mutex_op)?; - let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; - let kind_offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - let kind_place = - mutex_place.offset(Size::from_bytes(kind_offset), MemPlaceMeta::None, i32_layout, ecx)?; - ecx.write_scalar(kind.into(), kind_place.into()) -} - -// pthread_rwlock_t is between 32 and 56 bytes, depending on the platform. - -// Our chosen memory layout: -// bytes 0-3: reserved for signature on macOS -// (need to avoid this because it is set by static initializer macros) -// bytes 4-7: reader count, as a u32 -// bytes 8-11: writer count, as a u32 - -fn rwlock_get_readers<'mir, 'tcx: 'mir>( - ecx: &MiriEvalContext<'mir, 'tcx>, - rwlock_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { - // Ensure that the following read at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 12)?; - let rwlock_place = ecx.deref_operand(rwlock_op)?; - let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; - let readers_place = - rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; - ecx.read_scalar(readers_place.into()) -} - -fn rwlock_set_readers<'mir, 'tcx: 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, - rwlock_op: OpTy<'tcx, Tag>, - readers: impl Into>, -) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 12)?; - let rwlock_place = ecx.deref_operand(rwlock_op)?; - let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; - let readers_place = - rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; - ecx.write_scalar(readers.into(), readers_place.into()) -} - -fn rwlock_get_writers<'mir, 'tcx: 'mir>( - ecx: &MiriEvalContext<'mir, 'tcx>, - rwlock_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { - // Ensure that the following read at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 12)?; - let rwlock_place = ecx.deref_operand(rwlock_op)?; - let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; - let writers_place = - rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, ecx)?; - ecx.read_scalar(writers_place.into()) -} - -fn rwlock_set_writers<'mir, 'tcx: 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, - rwlock_op: OpTy<'tcx, Tag>, - writers: impl Into>, -) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 12)?; - let rwlock_place = ecx.deref_operand(rwlock_op)?; - let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; - let writers_place = - rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, ecx)?; - ecx.write_scalar(writers.into(), writers_place.into()) -} From bb06a0cf0e60ef09782a41b76d5204498355193a Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 28 Mar 2020 09:35:51 -0500 Subject: [PATCH 1805/5092] Restrict mutex static initializer test to Linux On macOS, libc does not have a static initializer for recursive mutexes --- tests/run-pass/sync.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index 025ae81372cf..24d7b0be5342 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -10,10 +10,13 @@ fn main() { { test_mutex_libc_init_recursive(); test_mutex_libc_init_normal(); - test_mutex_libc_static_initializer_recursive(); test_rwlock_stdlib(); test_rwlock_libc_static_initializer(); } + #[cfg(target_os = "linux")] + { + test_mutex_libc_static_initializer_recursive(); + } } fn test_mutex_stdlib() { @@ -64,7 +67,7 @@ fn test_mutex_libc_init_normal() { } } -#[cfg(not(target_os = "windows"))] +#[cfg(target_os = "linux")] fn test_mutex_libc_static_initializer_recursive() { let mutex = std::cell::UnsafeCell::new(libc::PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP); unsafe { From 37ddde9f70237a05dfdfb0aba837b8704a5dc7d0 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 28 Mar 2020 10:16:08 -0500 Subject: [PATCH 1806/5092] Implement TryEnterCriticalSection --- src/shims/foreign_items/windows.rs | 5 +++++ tests/run-pass/sync.rs | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index cfc94bfd9b71..3c819fddc410 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -233,6 +233,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // (Windows locks are reentrant, and we have only 1 thread, // so not doing any futher checks here is at least not incorrect.) } + "TryEnterCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") + => { + // There is only one thread, so this always succeeds and returns TRUE + this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; + } _ => throw_unsup_format!("can't call foreign function: {}", link_name), } diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index 24d7b0be5342..0ddf429fad9c 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -1,6 +1,6 @@ #![feature(rustc_private)] -use std::sync::{Mutex, RwLock, TryLockError}; +use std::sync::{Mutex, TryLockError}; extern crate libc; @@ -86,6 +86,7 @@ fn test_mutex_libc_static_initializer_recursive() { #[cfg(not(target_os = "windows"))] fn test_rwlock_stdlib() { + use std::sync::RwLock; let rw = RwLock::new(0); { let _read_guard = rw.read().unwrap(); From e1a1592991e0432c1e591e92e274f9943e690e3f Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 28 Mar 2020 10:58:36 -0500 Subject: [PATCH 1807/5092] Set some explicit return value sizes --- src/shims/foreign_items/posix.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 2b9e94ba11db..fbf8a3b9504f 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -272,72 +272,72 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "pthread_mutexattr_init" => { let result = this.pthread_mutexattr_init(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_settype" => { let result = this.pthread_mutexattr_settype(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_destroy" => { let result = this.pthread_mutexattr_destroy(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_init" => { let result = this.pthread_mutex_init(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_lock" => { let result = this.pthread_mutex_lock(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_trylock" => { let result = this.pthread_mutex_trylock(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_unlock" => { let result = this.pthread_mutex_unlock(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_destroy" => { let result = this.pthread_mutex_destroy(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_rdlock" => { let result = this.pthread_rwlock_rdlock(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_tryrdlock" => { let result = this.pthread_rwlock_tryrdlock(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_wrlock" => { let result = this.pthread_rwlock_wrlock(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_trywrlock" => { let result = this.pthread_rwlock_trywrlock(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_unlock" => { let result = this.pthread_rwlock_unlock(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_destroy" => { let result = this.pthread_rwlock_destroy(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } | "signal" From 8293d80b53a60121961027c3ba8e29823b153179 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 28 Mar 2020 11:14:50 -0500 Subject: [PATCH 1808/5092] Set explicit return value size for windows shim --- src/shims/foreign_items/windows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 3c819fddc410..443d44fae1c3 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -236,7 +236,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "TryEnterCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { // There is only one thread, so this always succeeds and returns TRUE - this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(1), dest)?; } _ => throw_unsup_format!("can't call foreign function: {}", link_name), From ac8c98da8e806a7e18dcc0cee8201085e5c7abb6 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 29 Mar 2020 01:38:34 -0500 Subject: [PATCH 1809/5092] Store layouts of i32 and u32 inside Evaluator --- src/lib.rs | 5 +++-- src/machine.rs | 53 ++++++++++++++++++++++++++++++++++++++++++++++- src/shims/sync.rs | 42 ++++++++++++++++++------------------- 3 files changed, 75 insertions(+), 25 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2f381b4a3454..82ac2e8d2188 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,8 +51,9 @@ pub use crate::diagnostics::{ pub use crate::eval::{create_ecx, eval_main, MiriConfig}; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; pub use crate::machine::{ - AllocExtra, Evaluator, FrameData, MemoryExtra, MiriEvalContext, MiriEvalContextExt, - MiriMemoryKind, NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, + AllocExtra, EvalContextExt as MachineEvalContextExt, Evaluator, FrameData, MemoryExtra, + MiriEvalContext, MiriEvalContextExt, MiriMemoryKind, NUM_CPUS, PAGE_SIZE, STACK_ADDR, + STACK_SIZE, }; pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; diff --git a/src/machine.rs b/src/machine.rs index f794453228b8..a60ae8a4be21 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -11,7 +11,7 @@ use log::trace; use rand::rngs::StdRng; use rustc_data_structures::fx::FxHashMap; -use rustc_middle::{mir, ty}; +use rustc_middle::{mir, ty::{self, layout::TyAndLayout}}; use rustc_target::abi::{LayoutOf, Size}; use rustc_ast::attr; use rustc_span::symbol::{sym, Symbol}; @@ -146,6 +146,39 @@ impl MemoryExtra { } } +/// Cached layouts of primitive types +#[derive(Default)] +struct PrimitiveLayouts<'tcx> { + i32: RefCell>>, + u32: RefCell>>, +} + +impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> { + fn i32(&self, ecx: &MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx, TyAndLayout<'tcx>> { + { + let layout_ref = self.i32.borrow(); + if layout_ref.is_some() { + return Ok(layout_ref.unwrap()); + } + } + let layout = ecx.layout_of(ecx.tcx.types.i32)?; + *self.i32.borrow_mut() = Some(layout); + Ok(layout) + } + + fn u32(&self, ecx: &MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx, TyAndLayout<'tcx>> { + { + let layout_ref = self.u32.borrow(); + if layout_ref.is_some() { + return Ok(layout_ref.unwrap()); + } + } + let layout = ecx.layout_of(ecx.tcx.types.u32)?; + *self.u32.borrow_mut() = Some(layout); + Ok(layout) + } +} + /// The machine itself. pub struct Evaluator<'tcx> { /// Environment variables set by `setenv`. @@ -182,6 +215,9 @@ pub struct Evaluator<'tcx> { /// The "time anchor" for this machine's monotone clock (for `Instant` simulation). pub(crate) time_anchor: Instant, + + /// Cached `TyLayout`s for primitive data types that are commonly used inside Miri. + primitive_layouts: PrimitiveLayouts<'tcx>, } impl<'tcx> Evaluator<'tcx> { @@ -201,6 +237,7 @@ impl<'tcx> Evaluator<'tcx> { dir_handler: Default::default(), panic_payload: None, time_anchor: Instant::now(), + primitive_layouts: PrimitiveLayouts::default(), } } } @@ -224,6 +261,20 @@ impl<'mir, 'tcx> MiriEvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> } } +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} +/// Provides convenience methods for use elsewhere +pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { + fn i32_layout(&self) -> InterpResult<'tcx, TyAndLayout<'tcx>> { + let this = self.eval_context_ref(); + this.machine.primitive_layouts.i32(this) + } + + fn u32_layout(&self) -> InterpResult<'tcx, TyAndLayout<'tcx>> { + let this = self.eval_context_ref(); + this.machine.primitive_layouts.u32(this) + } +} + /// Machine hook implementations. impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryKind = MiriMemoryKind; diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 4e4f8c112e53..eac2053493a8 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -30,8 +30,7 @@ fn mutexattr_get_kind<'mir, 'tcx: 'mir>( // Ensure that the following read at an offset to the attr pointer is within bounds assert_ptr_target_min_size(ecx, attr_op, 4)?; let attr_place = ecx.deref_operand(attr_op)?; - let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; - let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, ecx)?; + let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, ecx.i32_layout()?, ecx)?; ecx.read_scalar(kind_place.into()) } @@ -43,8 +42,7 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( // Ensure that the following write at an offset to the attr pointer is within bounds assert_ptr_target_min_size(ecx, attr_op, 4)?; let attr_place = ecx.deref_operand(attr_op)?; - let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; - let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, ecx)?; + let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, ecx.i32_layout()?, ecx)?; ecx.write_scalar(kind.into(), kind_place.into()) } @@ -64,9 +62,8 @@ fn mutex_get_locked_count<'mir, 'tcx: 'mir>( // Ensure that the following read at an offset to the mutex pointer is within bounds assert_ptr_target_min_size(ecx, mutex_op, 20)?; let mutex_place = ecx.deref_operand(mutex_op)?; - let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; let locked_count_place = - mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; + mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, ecx.u32_layout()?, ecx)?; ecx.read_scalar(locked_count_place.into()) } @@ -78,9 +75,8 @@ fn mutex_set_locked_count<'mir, 'tcx: 'mir>( // Ensure that the following write at an offset to the mutex pointer is within bounds assert_ptr_target_min_size(ecx, mutex_op, 20)?; let mutex_place = ecx.deref_operand(mutex_op)?; - let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; let locked_count_place = - mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; + mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, ecx.u32_layout()?, ecx)?; ecx.write_scalar(locked_count.into(), locked_count_place.into()) } @@ -91,10 +87,13 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>( // Ensure that the following read at an offset to the mutex pointer is within bounds assert_ptr_target_min_size(ecx, mutex_op, 20)?; let mutex_place = ecx.deref_operand(mutex_op)?; - let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; let kind_offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - let kind_place = - mutex_place.offset(Size::from_bytes(kind_offset), MemPlaceMeta::None, i32_layout, ecx)?; + let kind_place = mutex_place.offset( + Size::from_bytes(kind_offset), + MemPlaceMeta::None, + ecx.i32_layout()?, + ecx, + )?; ecx.read_scalar(kind_place.into()) } @@ -106,10 +105,13 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( // Ensure that the following write at an offset to the mutex pointer is within bounds assert_ptr_target_min_size(ecx, mutex_op, 20)?; let mutex_place = ecx.deref_operand(mutex_op)?; - let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; let kind_offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - let kind_place = - mutex_place.offset(Size::from_bytes(kind_offset), MemPlaceMeta::None, i32_layout, ecx)?; + let kind_place = mutex_place.offset( + Size::from_bytes(kind_offset), + MemPlaceMeta::None, + ecx.i32_layout()?, + ecx, + )?; ecx.write_scalar(kind.into(), kind_place.into()) } @@ -128,9 +130,8 @@ fn rwlock_get_readers<'mir, 'tcx: 'mir>( // Ensure that the following read at an offset to the rwlock pointer is within bounds assert_ptr_target_min_size(ecx, rwlock_op, 12)?; let rwlock_place = ecx.deref_operand(rwlock_op)?; - let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; let readers_place = - rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; + rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, ecx.u32_layout()?, ecx)?; ecx.read_scalar(readers_place.into()) } @@ -142,9 +143,8 @@ fn rwlock_set_readers<'mir, 'tcx: 'mir>( // Ensure that the following write at an offset to the rwlock pointer is within bounds assert_ptr_target_min_size(ecx, rwlock_op, 12)?; let rwlock_place = ecx.deref_operand(rwlock_op)?; - let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; let readers_place = - rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; + rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, ecx.u32_layout()?, ecx)?; ecx.write_scalar(readers.into(), readers_place.into()) } @@ -155,9 +155,8 @@ fn rwlock_get_writers<'mir, 'tcx: 'mir>( // Ensure that the following read at an offset to the rwlock pointer is within bounds assert_ptr_target_min_size(ecx, rwlock_op, 12)?; let rwlock_place = ecx.deref_operand(rwlock_op)?; - let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; let writers_place = - rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, ecx)?; + rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, ecx.u32_layout()?, ecx)?; ecx.read_scalar(writers_place.into()) } @@ -169,9 +168,8 @@ fn rwlock_set_writers<'mir, 'tcx: 'mir>( // Ensure that the following write at an offset to the rwlock pointer is within bounds assert_ptr_target_min_size(ecx, rwlock_op, 12)?; let rwlock_place = ecx.deref_operand(rwlock_op)?; - let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; let writers_place = - rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, ecx)?; + rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, ecx.u32_layout()?, ecx)?; ecx.write_scalar(writers.into(), writers_place.into()) } From b8444deb64b1175152c98bd772a3fd445a77ac6e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 Mar 2020 13:02:02 +0100 Subject: [PATCH 1810/5092] test Vec::extend --- tests/run-pass/{vecs.rs => vec.rs} | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) rename tests/run-pass/{vecs.rs => vec.rs} (73%) diff --git a/tests/run-pass/vecs.rs b/tests/run-pass/vec.rs similarity index 73% rename from tests/run-pass/vecs.rs rename to tests/run-pass/vec.rs index 739def804975..a2f448496fd9 100644 --- a/tests/run-pass/vecs.rs +++ b/tests/run-pass/vec.rs @@ -71,6 +71,26 @@ fn vec_reallocate() -> Vec { v } +fn vec_push_ptr_stable() { + let mut v = Vec::with_capacity(10); + v.push(0); + let v0 = unsafe { &*(&v[0] as *const _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. + v.push(1); + let _val = *v0; +} + +fn vec_extend_ptr_stable() { + let mut v = Vec::with_capacity(10); + v.push(0); + let v0 = unsafe { &*(&v[0] as *const _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. + v.extend(&[1]); + let _val = *v0; + v.extend(vec![2]); + let _val = *v0; + v.extend(std::iter::once(3)); + let _val = *v0; +} + fn main() { assert_eq!(vec_reallocate().len(), 5); @@ -89,4 +109,7 @@ fn main() { // Test interesting empty slice comparison // (one is a real pointer, one an integer pointer). assert_eq!((200..-5).step_by(1).collect::>(), []); + + vec_push_ptr_stable(); + vec_extend_ptr_stable(); } From 9159b1eef891d35c5153b6e4027a1dd7d158e61b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 Mar 2020 10:41:44 +0200 Subject: [PATCH 1811/5092] test some more vec ptr invalidation --- tests/run-pass/vec.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/run-pass/vec.rs b/tests/run-pass/vec.rs index a2f448496fd9..5304e3ed71a8 100644 --- a/tests/run-pass/vec.rs +++ b/tests/run-pass/vec.rs @@ -83,12 +83,25 @@ fn vec_extend_ptr_stable() { let mut v = Vec::with_capacity(10); v.push(0); let v0 = unsafe { &*(&v[0] as *const _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. + // `slice::Iter` (with `T: Copy`) specialization v.extend(&[1]); let _val = *v0; + // `vec::IntoIter` specialization v.extend(vec![2]); let _val = *v0; + // `TrustedLen` specialization v.extend(std::iter::once(3)); let _val = *v0; + // base case + v.extend(std::iter::once(3).filter(|_| true)); + let _val = *v0; +} + +fn vec_truncate_ptr_stable() { + let mut v = vec![0; 10]; + let v0 = unsafe { &*(&v[0] as *const _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. + v.truncate(5); + let _val = *v0; } fn main() { @@ -112,4 +125,5 @@ fn main() { vec_push_ptr_stable(); vec_extend_ptr_stable(); + vec_truncate_ptr_stable(); } From ab32084ddbe1a28c3e58ab80acdb62bb520eaf6f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 Mar 2020 13:27:59 +0200 Subject: [PATCH 1812/5092] use mutable reference --- tests/run-pass/vec.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/run-pass/vec.rs b/tests/run-pass/vec.rs index 5304e3ed71a8..954cd6a1557a 100644 --- a/tests/run-pass/vec.rs +++ b/tests/run-pass/vec.rs @@ -74,7 +74,7 @@ fn vec_reallocate() -> Vec { fn vec_push_ptr_stable() { let mut v = Vec::with_capacity(10); v.push(0); - let v0 = unsafe { &*(&v[0] as *const _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. + let v0 = unsafe { &mut *(&mut v[0] as *mut _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. v.push(1); let _val = *v0; } @@ -82,7 +82,7 @@ fn vec_push_ptr_stable() { fn vec_extend_ptr_stable() { let mut v = Vec::with_capacity(10); v.push(0); - let v0 = unsafe { &*(&v[0] as *const _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. + let v0 = unsafe { &mut *(&mut v[0] as *mut _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. // `slice::Iter` (with `T: Copy`) specialization v.extend(&[1]); let _val = *v0; @@ -99,7 +99,7 @@ fn vec_extend_ptr_stable() { fn vec_truncate_ptr_stable() { let mut v = vec![0; 10]; - let v0 = unsafe { &*(&v[0] as *const _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. + let v0 = unsafe { &mut *(&mut v[0] as *mut _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. v.truncate(5); let _val = *v0; } From 41abcdb42262ec49495838eac38dbe2e9cd0a3ba Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 Mar 2020 13:39:04 +0200 Subject: [PATCH 1813/5092] for consistency also rename floats.rs --- tests/run-pass/{floats.rs => float.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/run-pass/{floats.rs => float.rs} (100%) diff --git a/tests/run-pass/floats.rs b/tests/run-pass/float.rs similarity index 100% rename from tests/run-pass/floats.rs rename to tests/run-pass/float.rs From 3eb76f4a77d68f3f84e264fe51725e7b66256ec3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Apr 2020 18:28:05 +0200 Subject: [PATCH 1814/5092] rustup --- rust-version | 2 +- tests/run-pass/vec.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 895cbb5fa9a0..6e980a4e228e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6050e523bae6de61de4e060facc43dc512adaccd +e6cef0445779724b469ab7b9a8d3c05d9e848ca8 diff --git a/tests/run-pass/vec.rs b/tests/run-pass/vec.rs index 954cd6a1557a..5c791e4db0a7 100644 --- a/tests/run-pass/vec.rs +++ b/tests/run-pass/vec.rs @@ -123,6 +123,7 @@ fn main() { // (one is a real pointer, one an integer pointer). assert_eq!((200..-5).step_by(1).collect::>(), []); + // liballoc has a more extensive test of this, but let's at least do a smoke test here. vec_push_ptr_stable(); vec_extend_ptr_stable(); vec_truncate_ptr_stable(); From 79f3307f308ac1d9304437509db0f8a4a295d63b Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 5 Apr 2020 12:09:31 -0500 Subject: [PATCH 1815/5092] Update comments, rearrange code --- src/machine.rs | 2 + src/shims/foreign_items/posix.rs | 128 +++++++++++++--------------- src/shims/sync.rs | 9 +- tests/run-pass/libc.rs | 85 ++++++++++++++++++ tests/run-pass/reentrant-println.rs | 2 +- tests/run-pass/sync.rs | 88 ------------------- 6 files changed, 151 insertions(+), 163 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index a60ae8a4be21..bfb832085e0b 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -217,6 +217,8 @@ pub struct Evaluator<'tcx> { pub(crate) time_anchor: Instant, /// Cached `TyLayout`s for primitive data types that are commonly used inside Miri. + /// FIXME: Search through the rest of the codebase for more layout_of() calls that + /// could be cached here. primitive_layouts: PrimitiveLayouts<'tcx>, } diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index fbf8a3b9504f..3ececb9c20bb 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -233,6 +233,64 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } + // Synchronization primitives + "pthread_mutexattr_init" => { + let result = this.pthread_mutexattr_init(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_mutexattr_settype" => { + let result = this.pthread_mutexattr_settype(args[0], args[1])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_mutexattr_destroy" => { + let result = this.pthread_mutexattr_destroy(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_mutex_init" => { + let result = this.pthread_mutex_init(args[0], args[1])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_mutex_lock" => { + let result = this.pthread_mutex_lock(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_mutex_trylock" => { + let result = this.pthread_mutex_trylock(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_mutex_unlock" => { + let result = this.pthread_mutex_unlock(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_mutex_destroy" => { + let result = this.pthread_mutex_destroy(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_rwlock_rdlock" => { + let result = this.pthread_rwlock_rdlock(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_rwlock_tryrdlock" => { + let result = this.pthread_rwlock_tryrdlock(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_rwlock_wrlock" => { + let result = this.pthread_rwlock_wrlock(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_rwlock_trywrlock" => { + let result = this.pthread_rwlock_trywrlock(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_rwlock_unlock" => { + let result = this.pthread_rwlock_unlock(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_rwlock_destroy" => { + let result = this.pthread_rwlock_destroy(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + // Better error for attempts to create a thread "pthread_create" => { throw_unsup_format!("Miri does not support threading"); @@ -270,76 +328,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - "pthread_mutexattr_init" => { - let result = this.pthread_mutexattr_init(args[0])?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } - - "pthread_mutexattr_settype" => { - let result = this.pthread_mutexattr_settype(args[0], args[1])?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } - - "pthread_mutexattr_destroy" => { - let result = this.pthread_mutexattr_destroy(args[0])?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } - - "pthread_mutex_init" => { - let result = this.pthread_mutex_init(args[0], args[1])?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } - - "pthread_mutex_lock" => { - let result = this.pthread_mutex_lock(args[0])?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } - - "pthread_mutex_trylock" => { - let result = this.pthread_mutex_trylock(args[0])?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } - - "pthread_mutex_unlock" => { - let result = this.pthread_mutex_unlock(args[0])?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } - - "pthread_mutex_destroy" => { - let result = this.pthread_mutex_destroy(args[0])?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } - - "pthread_rwlock_rdlock" => { - let result = this.pthread_rwlock_rdlock(args[0])?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } - - "pthread_rwlock_tryrdlock" => { - let result = this.pthread_rwlock_tryrdlock(args[0])?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } - - "pthread_rwlock_wrlock" => { - let result = this.pthread_rwlock_wrlock(args[0])?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } - - "pthread_rwlock_trywrlock" => { - let result = this.pthread_rwlock_trywrlock(args[0])?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } - - "pthread_rwlock_unlock" => { - let result = this.pthread_rwlock_unlock(args[0])?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } - - "pthread_rwlock_destroy" => { - let result = this.pthread_rwlock_destroy(args[0])?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } - | "signal" | "sigaction" | "sigaltstack" diff --git a/src/shims/sync.rs b/src/shims/sync.rs index eac2053493a8..c2ea02af5b66 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -20,8 +20,9 @@ fn assert_ptr_target_min_size<'mir, 'tcx: 'mir>( // pthread_mutexattr_t is either 4 or 8 bytes, depending on the platform. -// Our chosen memory layout: store an i32 in the first four bytes equal to the -// corresponding libc mutex kind constant (i.e. PTHREAD_MUTEX_NORMAL) +// Our chosen memory layout for emulation (does not have to match the platform layout!): +// store an i32 in the first four bytes equal to the corresponding libc mutex kind constant +// (e.g. PTHREAD_MUTEX_NORMAL). fn mutexattr_get_kind<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, @@ -48,7 +49,7 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( // pthread_mutex_t is between 24 and 48 bytes, depending on the platform. -// Our chosen memory layout: +// Our chosen memory layout for the emulated mutex (does not have to match the platform layout!): // bytes 0-3: reserved for signature on macOS // (need to avoid this because it is set by static initializer macros) // bytes 4-7: count of how many times this mutex has been locked, as a u32 @@ -117,7 +118,7 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( // pthread_rwlock_t is between 32 and 56 bytes, depending on the platform. -// Our chosen memory layout: +// Our chosen memory layout for the emulated rwlock (does not have to match the platform layout!): // bytes 0-3: reserved for signature on macOS // (need to avoid this because it is set by static initializer macros) // bytes 4-7: reader count, as a u32 diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index 064c00e81bb8..7ea793089d2f 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -42,7 +42,92 @@ fn test_posix_fadvise() { assert_eq!(result, 0); } +fn test_mutex_libc_init_recursive() { + unsafe { + let mut attr: libc::pthread_mutexattr_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutexattr_init(&mut attr as *mut _), 0); + assert_eq!(libc::pthread_mutexattr_settype(&mut attr as *mut _, libc::PTHREAD_MUTEX_RECURSIVE), 0); + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mut attr as *mut _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), libc::EPERM); + assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutexattr_destroy(&mut attr as *mut _), 0); + } +} + +fn test_mutex_libc_init_normal() { + unsafe { + let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), 0); + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), libc::EBUSY); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); + } +} + +// Only linux provides PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, +// libc for macOS just has the default PTHREAD_MUTEX_INITIALIZER. +#[cfg(target_os = "linux")] +fn test_mutex_libc_static_initializer_recursive() { + let mutex = std::cell::UnsafeCell::new(libc::PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP); + unsafe { + assert_eq!(libc::pthread_mutex_lock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_trylock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_trylock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_lock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), libc::EPERM); + assert_eq!(libc::pthread_mutex_destroy(mutex.get()), 0); + } +} + +// Testing the behavior of std::sync::RwLock does not fully exercise the pthread rwlock shims, we +// need to go a layer deeper and test the behavior of the libc functions, because +// std::sys::unix::rwlock::RWLock itself keeps track of write_locked and num_readers. +fn test_rwlock_libc_static_initializer() { + let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); + unsafe { + assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + + assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + + assert_eq!(libc::pthread_rwlock_destroy(rw.get()), 0); + } +} + fn main() { #[cfg(not(target_os = "macos"))] test_posix_fadvise(); + + test_mutex_libc_init_recursive(); + test_mutex_libc_init_normal(); + test_rwlock_libc_static_initializer(); + + #[cfg(target_os = "linux")] + test_mutex_libc_static_initializer_recursive(); } diff --git a/tests/run-pass/reentrant-println.rs b/tests/run-pass/reentrant-println.rs index 09c4fc3f74d3..e73e82b8ec9e 100644 --- a/tests/run-pass/reentrant-println.rs +++ b/tests/run-pass/reentrant-println.rs @@ -1,7 +1,7 @@ use std::fmt::{Display, Error, Formatter}; // This test case exercises std::sys_common::remutex::ReentrantMutex -// by calling println!() from inside fmt +// by calling println!() from inside fmt. struct InterruptingCow; diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index 0ddf429fad9c..1ede5d42bb4b 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -2,20 +2,11 @@ use std::sync::{Mutex, TryLockError}; -extern crate libc; - fn main() { test_mutex_stdlib(); #[cfg(not(target_os = "windows"))] // TODO: implement RwLock on Windows { - test_mutex_libc_init_recursive(); - test_mutex_libc_init_normal(); test_rwlock_stdlib(); - test_rwlock_libc_static_initializer(); - } - #[cfg(target_os = "linux")] - { - test_mutex_libc_static_initializer_recursive(); } } @@ -29,61 +20,6 @@ fn test_mutex_stdlib() { drop(m); } -#[cfg(not(target_os = "windows"))] -fn test_mutex_libc_init_recursive() { - unsafe { - let mut attr: libc::pthread_mutexattr_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutexattr_init(&mut attr as *mut _), 0); - assert_eq!(libc::pthread_mutexattr_settype(&mut attr as *mut _, libc::PTHREAD_MUTEX_RECURSIVE), 0); - let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mut attr as *mut _), 0); - assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), libc::EPERM); - assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutexattr_destroy(&mut attr as *mut _), 0); - } -} - -#[cfg(not(target_os = "windows"))] -fn test_mutex_libc_init_normal() { - unsafe { - let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), 0); - let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); - assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), libc::EBUSY); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); - } -} - -#[cfg(target_os = "linux")] -fn test_mutex_libc_static_initializer_recursive() { - let mutex = std::cell::UnsafeCell::new(libc::PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP); - unsafe { - assert_eq!(libc::pthread_mutex_lock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_trylock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_trylock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_lock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_unlock(mutex.get()), libc::EPERM); - assert_eq!(libc::pthread_mutex_destroy(mutex.get()), 0); - } -} - #[cfg(not(target_os = "windows"))] fn test_rwlock_stdlib() { use std::sync::RwLock; @@ -102,30 +38,6 @@ fn test_rwlock_stdlib() { } } -// need to go a layer deeper and test the behavior of libc functions, because -// std::sys::unix::rwlock::RWLock keeps track of write_locked and num_readers - -#[cfg(not(target_os = "windows"))] -fn test_rwlock_libc_static_initializer() { - let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); - unsafe { - assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); - assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); - - assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), libc::EBUSY); - assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); - assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); - - assert_eq!(libc::pthread_rwlock_destroy(rw.get()), 0); - } -} - trait TryLockErrorExt { fn would_block(&self) -> bool; } From 177c0d3baa1d44db6ff574147a62b8b487d65f1e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Apr 2020 19:13:36 +0200 Subject: [PATCH 1816/5092] also test push_str ptr stability (the original report) --- tests/run-pass/vec.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/run-pass/vec.rs b/tests/run-pass/vec.rs index 5c791e4db0a7..731358564b8a 100644 --- a/tests/run-pass/vec.rs +++ b/tests/run-pass/vec.rs @@ -104,6 +104,14 @@ fn vec_truncate_ptr_stable() { let _val = *v0; } +fn push_str_ptr_stable() { + let mut buf = String::with_capacity(11); + buf.push_str("hello"); + let hello: &str = unsafe { &*(buf.as_str() as *const _) }; // laundering the lifetime -- we take care that `buf` does not reallocate, so that's okay. + buf.push_str(" world"); + assert_eq!(format!("{}", hello), "hello"); +} + fn main() { assert_eq!(vec_reallocate().len(), 5); @@ -127,4 +135,5 @@ fn main() { vec_push_ptr_stable(); vec_extend_ptr_stable(); vec_truncate_ptr_stable(); + push_str_ptr_stable(); } From 100141f57c27d0b282aec6156d60ab9d26583a47 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 5 Apr 2020 12:32:09 -0500 Subject: [PATCH 1817/5092] Remove null checks, fall through to UB upon deref --- src/shims/sync.rs | 70 ----------------------------------------------- 1 file changed, 70 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index c2ea02af5b66..c9d846288a43 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -179,11 +179,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutexattr_init(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let attr = this.read_scalar(attr_op)?.not_undef()?; - if this.is_null(attr)? { - return this.eval_libc_i32("EINVAL"); - } - let default_kind = this.eval_libc("PTHREAD_MUTEX_DEFAULT")?; mutexattr_set_kind(this, attr_op, default_kind)?; @@ -197,11 +192,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let attr = this.read_scalar(attr_op)?.not_undef()?; - if this.is_null(attr)? { - return this.eval_libc_i32("EINVAL"); - } - let kind = this.read_scalar(kind_op)?.not_undef()?; if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? || kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? @@ -219,11 +209,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutexattr_destroy(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let attr = this.read_scalar(attr_op)?.not_undef()?; - if this.is_null(attr)? { - return this.eval_libc_i32("EINVAL"); - } - mutexattr_set_kind(this, attr_op, ScalarMaybeUndef::Undef)?; Ok(0) @@ -236,11 +221,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let mutex = this.read_scalar(mutex_op)?.not_undef()?; - if this.is_null(mutex)? { - return this.eval_libc_i32("EINVAL"); - } - let attr = this.read_scalar(attr_op)?.not_undef()?; let kind = if this.is_null(attr)? { this.eval_libc("PTHREAD_MUTEX_DEFAULT")? @@ -257,11 +237,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_lock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let mutex = this.read_scalar(mutex_op)?.not_undef()?; - if this.is_null(mutex)? { - return this.eval_libc_i32("EINVAL"); - } - let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; let locked_count = mutex_get_locked_count(this, mutex_op)?.to_u32()?; @@ -295,11 +270,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_trylock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let mutex = this.read_scalar(mutex_op)?.not_undef()?; - if this.is_null(mutex)? { - return this.eval_libc_i32("EINVAL"); - } - let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; let locked_count = mutex_get_locked_count(this, mutex_op)?.to_u32()?; @@ -328,11 +298,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_unlock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let mutex = this.read_scalar(mutex_op)?.not_undef()?; - if this.is_null(mutex)? { - return this.eval_libc_i32("EINVAL"); - } - let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; let locked_count = mutex_get_locked_count(this, mutex_op)?.to_u32()?; @@ -371,11 +336,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_destroy(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let mutex = this.read_scalar(mutex_op)?.not_undef()?; - if this.is_null(mutex)? { - return this.eval_libc_i32("EINVAL"); - } - if mutex_get_locked_count(this, mutex_op)?.to_u32()? != 0 { return this.eval_libc_i32("EBUSY"); } @@ -389,11 +349,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_rdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; - if this.is_null(rwlock)? { - return this.eval_libc_i32("EINVAL"); - } - let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; if writers != 0 { @@ -414,11 +369,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; - if this.is_null(rwlock)? { - return this.eval_libc_i32("EINVAL"); - } - let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; if writers != 0 { @@ -437,11 +387,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_wrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; - if this.is_null(rwlock)? { - return this.eval_libc_i32("EINVAL"); - } - let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; if readers != 0 { @@ -461,11 +406,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_trywrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; - if this.is_null(rwlock)? { - return this.eval_libc_i32("EINVAL"); - } - let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; if readers != 0 || writers != 0 { @@ -479,11 +419,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_unlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; - if this.is_null(rwlock)? { - return this.eval_libc_i32("EINVAL"); - } - let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; if let Some(new_readers) = readers.checked_sub(1) { @@ -500,11 +435,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_destroy(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; - if this.is_null(rwlock)? { - return this.eval_libc_i32("EINVAL"); - } - if rwlock_get_readers(this, rwlock_op)?.to_u32()? != 0 { return this.eval_libc_i32("EBUSY"); } From e7944419d4b7403c51028204ec5c4c53e776e94a Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 5 Apr 2020 12:44:23 -0500 Subject: [PATCH 1818/5092] Use Deadlock machine stop uniformly --- src/shims/sync.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index c9d846288a43..90d7104b9e7b 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -352,9 +352,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; if writers != 0 { - throw_unsup_format!( - "Deadlock due to read-locking a pthreads read-write lock while it is already write-locked" - ); + throw_machine_stop!(TerminationInfo::Deadlock); } else { match readers.checked_add(1) { Some(new_readers) => { @@ -390,13 +388,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; if readers != 0 { - throw_unsup_format!( - "Deadlock due to write-locking a pthreads read-write lock while it is already read-locked" - ); + throw_machine_stop!(TerminationInfo::Deadlock); } else if writers != 0 { - throw_unsup_format!( - "Deadlock due to write-locking a pthreads read-write lock while it is already write-locked" - ); + throw_machine_stop!(TerminationInfo::Deadlock); } else { rwlock_set_writers(this, rwlock_op, Scalar::from_u32(1))?; Ok(0) From d5d5a569264d6ca18ff4d4648d62a81ce85114f7 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 5 Apr 2020 13:25:49 -0500 Subject: [PATCH 1819/5092] Add tests --- .../libc_pthread_mutex_normal_deadlock.rs | 16 ++++++++++++++++ .../libc_pthread_rwlock_read_write_deadlock.rs | 13 +++++++++++++ .../libc_pthread_rwlock_write_read_deadlock.rs | 13 +++++++++++++ ...libc_pthread_rwlock_write_write_deadlock.rs | 13 +++++++++++++ tests/run-pass/libc.rs | 18 ++++++++++++++++++ 5 files changed, 73 insertions(+) create mode 100644 tests/compile-fail/libc_pthread_mutex_normal_deadlock.rs create mode 100644 tests/compile-fail/libc_pthread_rwlock_read_write_deadlock.rs create mode 100644 tests/compile-fail/libc_pthread_rwlock_write_read_deadlock.rs create mode 100644 tests/compile-fail/libc_pthread_rwlock_write_write_deadlock.rs diff --git a/tests/compile-fail/libc_pthread_mutex_normal_deadlock.rs b/tests/compile-fail/libc_pthread_mutex_normal_deadlock.rs new file mode 100644 index 000000000000..7034bf64ec90 --- /dev/null +++ b/tests/compile-fail/libc_pthread_mutex_normal_deadlock.rs @@ -0,0 +1,16 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + unsafe { + let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), 0); + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR deadlock + } +} diff --git a/tests/compile-fail/libc_pthread_rwlock_read_write_deadlock.rs b/tests/compile-fail/libc_pthread_rwlock_read_write_deadlock.rs new file mode 100644 index 000000000000..dd4707d60e4c --- /dev/null +++ b/tests/compile-fail/libc_pthread_rwlock_read_write_deadlock.rs @@ -0,0 +1,13 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); + unsafe { + assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); + libc::pthread_rwlock_wrlock(rw.get()); //~ ERROR: deadlock + } +} diff --git a/tests/compile-fail/libc_pthread_rwlock_write_read_deadlock.rs b/tests/compile-fail/libc_pthread_rwlock_write_read_deadlock.rs new file mode 100644 index 000000000000..1b460e7174d2 --- /dev/null +++ b/tests/compile-fail/libc_pthread_rwlock_write_read_deadlock.rs @@ -0,0 +1,13 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); + unsafe { + assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); + libc::pthread_rwlock_rdlock(rw.get()); //~ ERROR: deadlock + } +} diff --git a/tests/compile-fail/libc_pthread_rwlock_write_write_deadlock.rs b/tests/compile-fail/libc_pthread_rwlock_write_write_deadlock.rs new file mode 100644 index 000000000000..cc327ec46bc2 --- /dev/null +++ b/tests/compile-fail/libc_pthread_rwlock_write_write_deadlock.rs @@ -0,0 +1,13 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); + unsafe { + assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); + libc::pthread_rwlock_wrlock(rw.get()); //~ ERROR: deadlock + } +} diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index 7ea793089d2f..c930a034b130 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -78,6 +78,23 @@ fn test_mutex_libc_init_normal() { } } +fn test_mutex_libc_init_errorcheck() { + unsafe { + let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_ERRORCHECK), 0); + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), libc::EBUSY); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), libc::EDEADLK); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), libc::EPERM); + assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); + } +} + // Only linux provides PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, // libc for macOS just has the default PTHREAD_MUTEX_INITIALIZER. #[cfg(target_os = "linux")] @@ -126,6 +143,7 @@ fn main() { test_mutex_libc_init_recursive(); test_mutex_libc_init_normal(); + test_mutex_libc_init_errorcheck(); test_rwlock_libc_static_initializer(); #[cfg(target_os = "linux")] From f9dc942cfdafc4fe86bc0ec1f0963f88eaa580c1 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 5 Apr 2020 13:53:03 -0500 Subject: [PATCH 1820/5092] Changes to error handling --- src/shims/sync.rs | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 90d7104b9e7b..d7ae32daaa2b 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -263,7 +263,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx None => this.eval_libc_i32("EAGAIN"), } } else { - this.eval_libc_i32("EINVAL") + throw_ub_format!("called pthread_mutex_lock on an unsupported type of mutex"); } } @@ -291,7 +291,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx None => this.eval_libc_i32("EAGAIN"), } } else { - this.eval_libc_i32("EINVAL") + throw_ub_format!("called pthread_mutex_trylock on an unsupported type of mutex"); } } @@ -306,9 +306,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex_set_locked_count(this, mutex_op, Scalar::from_u32(0))?; Ok(0) } else { - throw_ub_format!( - "Attempted to unlock a PTHREAD_MUTEX_NORMAL mutex that was not locked" - ); + throw_ub_format!("unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked"); } } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { if locked_count != 0 { @@ -329,7 +327,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } else { - this.eval_libc_i32("EINVAL") + throw_ub_format!("called pthread_mutex_unlock on an unsupported type of mutex"); } } @@ -337,7 +335,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); if mutex_get_locked_count(this, mutex_op)?.to_u32()? != 0 { - return this.eval_libc_i32("EBUSY"); + throw_ub_format!("destroyed a locked mutex"); } mutex_set_kind(this, mutex_op, ScalarMaybeUndef::Undef)?; @@ -422,18 +420,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx rwlock_set_writers(this, rwlock_op, Scalar::from_u32(0))?; Ok(0) } else { - this.eval_libc_i32("EPERM") + throw_ub_format!("unlocked an rwlock that was not locked"); } } fn pthread_rwlock_destroy(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if rwlock_get_readers(this, rwlock_op)?.to_u32()? != 0 { - return this.eval_libc_i32("EBUSY"); - } - if rwlock_get_writers(this, rwlock_op)?.to_u32()? != 0 { - return this.eval_libc_i32("EBUSY"); + if rwlock_get_readers(this, rwlock_op)?.to_u32()? != 0 + || rwlock_get_writers(this, rwlock_op)?.to_u32()? != 0 + { + throw_ub_format!("destroyed a locked rwlock"); } rwlock_set_readers(this, rwlock_op, ScalarMaybeUndef::Undef)?; From 134d6a2faab1801e9b3d23b6ee11ba1643eae0fe Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 5 Apr 2020 14:55:57 -0500 Subject: [PATCH 1821/5092] Add tests, improve test coverage --- .../libc_pthread_mutex_destroy_locked.rs | 16 ++++++++++++++++ ...libc_pthread_mutex_normal_unlock_unlocked.rs | 17 +++++++++++++++++ .../libc_pthread_rwlock_destroy_read_locked.rs | 13 +++++++++++++ .../libc_pthread_rwlock_destroy_write_locked.rs | 13 +++++++++++++ .../libc_pthread_rwlock_unlock_unlocked.rs | 12 ++++++++++++ tests/run-pass/libc.rs | 8 +++++++- 6 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/libc_pthread_mutex_destroy_locked.rs create mode 100644 tests/compile-fail/libc_pthread_mutex_normal_unlock_unlocked.rs create mode 100644 tests/compile-fail/libc_pthread_rwlock_destroy_read_locked.rs create mode 100644 tests/compile-fail/libc_pthread_rwlock_destroy_write_locked.rs create mode 100644 tests/compile-fail/libc_pthread_rwlock_unlock_unlocked.rs diff --git a/tests/compile-fail/libc_pthread_mutex_destroy_locked.rs b/tests/compile-fail/libc_pthread_mutex_destroy_locked.rs new file mode 100644 index 000000000000..e7ed8ad29621 --- /dev/null +++ b/tests/compile-fail/libc_pthread_mutex_destroy_locked.rs @@ -0,0 +1,16 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + unsafe { + let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), 0); + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + libc::pthread_mutex_destroy(&mut mutex as *mut _); //~ ERROR destroyed a locked mutex + } +} diff --git a/tests/compile-fail/libc_pthread_mutex_normal_unlock_unlocked.rs b/tests/compile-fail/libc_pthread_mutex_normal_unlock_unlocked.rs new file mode 100644 index 000000000000..65de62484d5e --- /dev/null +++ b/tests/compile-fail/libc_pthread_mutex_normal_unlock_unlocked.rs @@ -0,0 +1,17 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + unsafe { + let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), 0); + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + libc::pthread_mutex_unlock(&mut mutex as *mut _); //~ ERROR was not locked + } +} diff --git a/tests/compile-fail/libc_pthread_rwlock_destroy_read_locked.rs b/tests/compile-fail/libc_pthread_rwlock_destroy_read_locked.rs new file mode 100644 index 000000000000..8750a7388fca --- /dev/null +++ b/tests/compile-fail/libc_pthread_rwlock_destroy_read_locked.rs @@ -0,0 +1,13 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); + unsafe { + assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); + libc::pthread_rwlock_destroy(rw.get()); //~ ERROR destroyed a locked rwlock + } +} diff --git a/tests/compile-fail/libc_pthread_rwlock_destroy_write_locked.rs b/tests/compile-fail/libc_pthread_rwlock_destroy_write_locked.rs new file mode 100644 index 000000000000..aecccfa50310 --- /dev/null +++ b/tests/compile-fail/libc_pthread_rwlock_destroy_write_locked.rs @@ -0,0 +1,13 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); + unsafe { + assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); + libc::pthread_rwlock_destroy(rw.get()); //~ ERROR destroyed a locked rwlock + } +} diff --git a/tests/compile-fail/libc_pthread_rwlock_unlock_unlocked.rs b/tests/compile-fail/libc_pthread_rwlock_unlock_unlocked.rs new file mode 100644 index 000000000000..8b3de53828df --- /dev/null +++ b/tests/compile-fail/libc_pthread_rwlock_unlock_unlocked.rs @@ -0,0 +1,12 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); + unsafe { + libc::pthread_rwlock_unlock(rw.get()); //~ ERROR was not locked + } +} diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index c930a034b130..a449d9340a31 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -15,7 +15,7 @@ fn tmp() -> PathBuf { #[cfg(not(target_os = "macos"))] fn test_posix_fadvise() { use std::convert::TryInto; - use std::fs::{File, remove_file}; + use std::fs::{remove_file, File}; use std::io::Write; use std::os::unix::io::AsRawFd; @@ -66,6 +66,7 @@ fn test_mutex_libc_init_recursive() { fn test_mutex_libc_init_normal() { unsafe { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, 0x12345678), libc::EINVAL); assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), 0); let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); @@ -133,6 +134,11 @@ fn test_rwlock_libc_static_initializer() { assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_destroy(rw.get()), 0); } } From bc54c7628dbcccc8d727abea591e9ac14ea2fed2 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 5 Apr 2020 16:03:44 -0500 Subject: [PATCH 1822/5092] Eagerly compute i32 and u32 layouts --- src/eval.rs | 15 +++++---- src/lib.rs | 5 ++- src/machine.rs | 79 ++++++++++++++++++----------------------------- src/shims/sync.rs | 58 ++++++++++++++++++++++++---------- 4 files changed, 83 insertions(+), 74 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 46e66bc0a81e..c3510188e3cb 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -1,14 +1,14 @@ //! Main evaluator loop and setting up the initial stack frame. -use std::ffi::OsStr; use std::convert::TryFrom; +use std::ffi::OsStr; use rand::rngs::StdRng; use rand::SeedableRng; -use rustc_target::abi::LayoutOf; -use rustc_middle::ty::{self, TyCtxt}; use rustc_hir::def_id::DefId; +use rustc_middle::ty::{self, layout::LayoutCx, TyCtxt}; +use rustc_target::abi::LayoutOf; use crate::*; @@ -60,10 +60,13 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( main_id: DefId, config: MiriConfig, ) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'tcx>>, MPlaceTy<'tcx, Tag>)> { + let tcx_at = tcx.at(rustc_span::source_map::DUMMY_SP); + let param_env = ty::ParamEnv::reveal_all(); + let layout_cx = LayoutCx { tcx, param_env }; let mut ecx = InterpCx::new( - tcx.at(rustc_span::source_map::DUMMY_SP), - ty::ParamEnv::reveal_all(), - Evaluator::new(config.communicate, config.validate), + tcx_at, + param_env, + Evaluator::new(config.communicate, config.validate, layout_cx), MemoryExtra::new( StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.stacked_borrows, diff --git a/src/lib.rs b/src/lib.rs index 82ac2e8d2188..2f381b4a3454 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,9 +51,8 @@ pub use crate::diagnostics::{ pub use crate::eval::{create_ecx, eval_main, MiriConfig}; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; pub use crate::machine::{ - AllocExtra, EvalContextExt as MachineEvalContextExt, Evaluator, FrameData, MemoryExtra, - MiriEvalContext, MiriEvalContextExt, MiriMemoryKind, NUM_CPUS, PAGE_SIZE, STACK_ADDR, - STACK_SIZE, + AllocExtra, Evaluator, FrameData, MemoryExtra, MiriEvalContext, MiriEvalContextExt, + MiriMemoryKind, NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, }; pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; diff --git a/src/machine.rs b/src/machine.rs index bfb832085e0b..26ff23511f73 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -10,11 +10,18 @@ use std::time::Instant; use log::trace; use rand::rngs::StdRng; -use rustc_data_structures::fx::FxHashMap; -use rustc_middle::{mir, ty::{self, layout::TyAndLayout}}; -use rustc_target::abi::{LayoutOf, Size}; use rustc_ast::attr; +use rustc_data_structures::fx::FxHashMap; +use rustc_middle::{ + mir, + ty::{ + self, + layout::{LayoutCx, LayoutError, TyAndLayout}, + TyCtxt, + }, +}; use rustc_span::symbol::{sym, Symbol}; +use rustc_target::abi::{LayoutOf, Size}; use crate::*; @@ -146,36 +153,18 @@ impl MemoryExtra { } } -/// Cached layouts of primitive types -#[derive(Default)] -struct PrimitiveLayouts<'tcx> { - i32: RefCell>>, - u32: RefCell>>, +/// Precomputed layouts of primitive types +pub(crate) struct PrimitiveLayouts<'tcx> { + pub(crate) i32: TyAndLayout<'tcx>, + pub(crate) u32: TyAndLayout<'tcx>, } impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> { - fn i32(&self, ecx: &MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx, TyAndLayout<'tcx>> { - { - let layout_ref = self.i32.borrow(); - if layout_ref.is_some() { - return Ok(layout_ref.unwrap()); - } - } - let layout = ecx.layout_of(ecx.tcx.types.i32)?; - *self.i32.borrow_mut() = Some(layout); - Ok(layout) - } - - fn u32(&self, ecx: &MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx, TyAndLayout<'tcx>> { - { - let layout_ref = self.u32.borrow(); - if layout_ref.is_some() { - return Ok(layout_ref.unwrap()); - } - } - let layout = ecx.layout_of(ecx.tcx.types.u32)?; - *self.u32.borrow_mut() = Some(layout); - Ok(layout) + fn new(layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result> { + Ok(Self { + i32: layout_cx.layout_of(layout_cx.tcx.types.i32)?, + u32: layout_cx.layout_of(layout_cx.tcx.types.u32)?, + }) } } @@ -216,14 +205,20 @@ pub struct Evaluator<'tcx> { /// The "time anchor" for this machine's monotone clock (for `Instant` simulation). pub(crate) time_anchor: Instant, - /// Cached `TyLayout`s for primitive data types that are commonly used inside Miri. + /// Precomputed `TyLayout`s for primitive data types that are commonly used inside Miri. /// FIXME: Search through the rest of the codebase for more layout_of() calls that - /// could be cached here. - primitive_layouts: PrimitiveLayouts<'tcx>, + /// could be stored here. + pub(crate) layouts: PrimitiveLayouts<'tcx>, } impl<'tcx> Evaluator<'tcx> { - pub(crate) fn new(communicate: bool, validate: bool) -> Self { + pub(crate) fn new( + communicate: bool, + validate: bool, + layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>, + ) -> Self { + let layouts = PrimitiveLayouts::new(layout_cx) + .expect("Couldn't get layouts of primitive types"); Evaluator { // `env_vars` could be initialized properly here if `Memory` were available before // calling this method. @@ -239,7 +234,7 @@ impl<'tcx> Evaluator<'tcx> { dir_handler: Default::default(), panic_payload: None, time_anchor: Instant::now(), - primitive_layouts: PrimitiveLayouts::default(), + layouts, } } } @@ -263,20 +258,6 @@ impl<'mir, 'tcx> MiriEvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> } } -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} -/// Provides convenience methods for use elsewhere -pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { - fn i32_layout(&self) -> InterpResult<'tcx, TyAndLayout<'tcx>> { - let this = self.eval_context_ref(); - this.machine.primitive_layouts.i32(this) - } - - fn u32_layout(&self) -> InterpResult<'tcx, TyAndLayout<'tcx>> { - let this = self.eval_context_ref(); - this.machine.primitive_layouts.u32(this) - } -} - /// Machine hook implementations. impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryKind = MiriMemoryKind; diff --git a/src/shims/sync.rs b/src/shims/sync.rs index d7ae32daaa2b..b03dcbfd8969 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -31,7 +31,8 @@ fn mutexattr_get_kind<'mir, 'tcx: 'mir>( // Ensure that the following read at an offset to the attr pointer is within bounds assert_ptr_target_min_size(ecx, attr_op, 4)?; let attr_place = ecx.deref_operand(attr_op)?; - let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, ecx.i32_layout()?, ecx)?; + let kind_place = + attr_place.offset(Size::ZERO, MemPlaceMeta::None, ecx.machine.layouts.i32, ecx)?; ecx.read_scalar(kind_place.into()) } @@ -43,7 +44,8 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( // Ensure that the following write at an offset to the attr pointer is within bounds assert_ptr_target_min_size(ecx, attr_op, 4)?; let attr_place = ecx.deref_operand(attr_op)?; - let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, ecx.i32_layout()?, ecx)?; + let kind_place = + attr_place.offset(Size::ZERO, MemPlaceMeta::None, ecx.machine.layouts.i32, ecx)?; ecx.write_scalar(kind.into(), kind_place.into()) } @@ -63,8 +65,12 @@ fn mutex_get_locked_count<'mir, 'tcx: 'mir>( // Ensure that the following read at an offset to the mutex pointer is within bounds assert_ptr_target_min_size(ecx, mutex_op, 20)?; let mutex_place = ecx.deref_operand(mutex_op)?; - let locked_count_place = - mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, ecx.u32_layout()?, ecx)?; + let locked_count_place = mutex_place.offset( + Size::from_bytes(4), + MemPlaceMeta::None, + ecx.machine.layouts.u32, + ecx, + )?; ecx.read_scalar(locked_count_place.into()) } @@ -76,8 +82,12 @@ fn mutex_set_locked_count<'mir, 'tcx: 'mir>( // Ensure that the following write at an offset to the mutex pointer is within bounds assert_ptr_target_min_size(ecx, mutex_op, 20)?; let mutex_place = ecx.deref_operand(mutex_op)?; - let locked_count_place = - mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, ecx.u32_layout()?, ecx)?; + let locked_count_place = mutex_place.offset( + Size::from_bytes(4), + MemPlaceMeta::None, + ecx.machine.layouts.u32, + ecx, + )?; ecx.write_scalar(locked_count.into(), locked_count_place.into()) } @@ -92,7 +102,7 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>( let kind_place = mutex_place.offset( Size::from_bytes(kind_offset), MemPlaceMeta::None, - ecx.i32_layout()?, + ecx.machine.layouts.i32, ecx, )?; ecx.read_scalar(kind_place.into()) @@ -110,7 +120,7 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( let kind_place = mutex_place.offset( Size::from_bytes(kind_offset), MemPlaceMeta::None, - ecx.i32_layout()?, + ecx.machine.layouts.i32, ecx, )?; ecx.write_scalar(kind.into(), kind_place.into()) @@ -131,8 +141,12 @@ fn rwlock_get_readers<'mir, 'tcx: 'mir>( // Ensure that the following read at an offset to the rwlock pointer is within bounds assert_ptr_target_min_size(ecx, rwlock_op, 12)?; let rwlock_place = ecx.deref_operand(rwlock_op)?; - let readers_place = - rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, ecx.u32_layout()?, ecx)?; + let readers_place = rwlock_place.offset( + Size::from_bytes(4), + MemPlaceMeta::None, + ecx.machine.layouts.u32, + ecx, + )?; ecx.read_scalar(readers_place.into()) } @@ -144,8 +158,12 @@ fn rwlock_set_readers<'mir, 'tcx: 'mir>( // Ensure that the following write at an offset to the rwlock pointer is within bounds assert_ptr_target_min_size(ecx, rwlock_op, 12)?; let rwlock_place = ecx.deref_operand(rwlock_op)?; - let readers_place = - rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, ecx.u32_layout()?, ecx)?; + let readers_place = rwlock_place.offset( + Size::from_bytes(4), + MemPlaceMeta::None, + ecx.machine.layouts.u32, + ecx, + )?; ecx.write_scalar(readers.into(), readers_place.into()) } @@ -156,8 +174,12 @@ fn rwlock_get_writers<'mir, 'tcx: 'mir>( // Ensure that the following read at an offset to the rwlock pointer is within bounds assert_ptr_target_min_size(ecx, rwlock_op, 12)?; let rwlock_place = ecx.deref_operand(rwlock_op)?; - let writers_place = - rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, ecx.u32_layout()?, ecx)?; + let writers_place = rwlock_place.offset( + Size::from_bytes(8), + MemPlaceMeta::None, + ecx.machine.layouts.u32, + ecx, + )?; ecx.read_scalar(writers_place.into()) } @@ -169,8 +191,12 @@ fn rwlock_set_writers<'mir, 'tcx: 'mir>( // Ensure that the following write at an offset to the rwlock pointer is within bounds assert_ptr_target_min_size(ecx, rwlock_op, 12)?; let rwlock_place = ecx.deref_operand(rwlock_op)?; - let writers_place = - rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, ecx.u32_layout()?, ecx)?; + let writers_place = rwlock_place.offset( + Size::from_bytes(8), + MemPlaceMeta::None, + ecx.machine.layouts.u32, + ecx, + )?; ecx.write_scalar(writers.into(), writers_place.into()) } From 0f5f0e1520a4f001674478ee5b8eb7a644b2c66a Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 5 Apr 2020 20:55:39 -0500 Subject: [PATCH 1823/5092] Fix spelling typo --- src/shims/foreign_items/posix/linux.rs | 2 +- src/shims/foreign_items/posix/macos.rs | 2 +- src/shims/foreign_items/windows.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 286bd5798b04..16c6c002b69c 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -113,7 +113,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(-1), dest)?; } - // Incomplete shims that we "stub out" just to get pre-main initialziation code to work. + // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "pthread_getattr_np" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { this.write_null(dest)?; diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 44c45d90c198..9810a77ffde1 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -88,7 +88,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(stack_size, dest)?; } - // Incomplete shims that we "stub out" just to get pre-main initialziation code to work. + // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "mmap" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 443d44fae1c3..1d17cbcefdee 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -207,7 +207,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("Miri does not support threading"); } - // Incomplete shims that we "stub out" just to get pre-main initialziation code to work. + // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "GetProcessHeap" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { // Just fake a HANDLE From 86c57a8490ba6d06e284865adc33af7f4ebdb887 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Apr 2020 09:33:36 +0200 Subject: [PATCH 1824/5092] mention ./miri build --- CONTRIBUTING.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c7bfe6ccf1c1..3967ca05f924 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,6 +28,15 @@ install that exact version of rustc as a toolchain: [`rustup-toolchain-install-master`]: https://github.com/kennytm/rustup-toolchain-install-master +Now building Miri is just one command away: + +``` +./miri build +``` + +Run `./miri` without arguments to see the other commands our build tool +supports. + ### Fixing Miri when rustc changes Miri is heavily tied to rustc internals, so it is very common that rustc changes From 3554f54173f40d96a7f81497c7955bae5bebfe1d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Apr 2020 09:34:27 +0200 Subject: [PATCH 1825/5092] make just ./miri print help text without 'unknown command' --- miri | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/miri b/miri index 8cd2cfc3ae0c..b4d205bd52c5 100755 --- a/miri +++ b/miri @@ -141,8 +141,10 @@ run|run-debug) exec cargo run $CARGO_BUILD_FLAGS -- --sysroot "$MIRI_SYSROOT" "$@" ;; *) - echo "Unknown command: $COMMAND" - echo + if [ -n "$COMMAND" ]; then + echo "Unknown command: $COMMAND" + echo + fi echo "$USAGE" exit 1 esac From ac3a24673cb242090f4b298f986f4940575483b5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Apr 2020 09:37:15 +0200 Subject: [PATCH 1826/5092] wording --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3967ca05f924..50cfe14a28eb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -69,7 +69,7 @@ driver on a particular file by doing ./miri run tests/run-pass/hello.rs --target i686-unknown-linux-gnu ``` -and you can (cross-)run the test suite using: +and you can (cross-)run the entire test suite using: ``` ./miri test From 80497e5d3c5fe08e95bcbe114fae39661a909e16 Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 6 Apr 2020 07:23:58 -0500 Subject: [PATCH 1827/5092] Clean up conditional compilation --- tests/run-pass/libc.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index a449d9340a31..fc154c05c8fc 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -12,7 +12,7 @@ fn tmp() -> PathBuf { std::env::var("MIRI_TEMP").map(PathBuf::from).unwrap_or_else(|_| std::env::temp_dir()) } -#[cfg(not(target_os = "macos"))] +#[cfg(target_os = "linux")] fn test_posix_fadvise() { use std::convert::TryInto; use std::fs::{remove_file, File}; @@ -144,7 +144,7 @@ fn test_rwlock_libc_static_initializer() { } fn main() { - #[cfg(not(target_os = "macos"))] + #[cfg(target_os = "linux")] test_posix_fadvise(); test_mutex_libc_init_recursive(); From a46f8b66c30f4eec58fd781f18583bd87a2f923a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 7 Apr 2020 16:13:19 +0200 Subject: [PATCH 1828/5092] prefer float assoc consts over std module --- tests/run-pass/float.rs | 70 ++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index 394e91ac9c3b..5acaf6a2a97c 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -34,37 +34,37 @@ fn main() { assert_eq(-5.0f32 as u32, 0); assert_eq(5.0f32 as i32, 5); assert_eq(-5.0f32 as i32, -5); - assert_eq(std::f32::MAX as i32, i32::MAX); - assert_eq(std::f32::INFINITY as i32, i32::MAX); - assert_eq(std::f32::MAX as u32, u32::MAX); - assert_eq(std::f32::INFINITY as u32, u32::MAX); - assert_eq(std::f32::MIN as i32, i32::MIN); - assert_eq(std::f32::NEG_INFINITY as i32, i32::MIN); - assert_eq(std::f32::MIN as u32, 0); - assert_eq(std::f32::NEG_INFINITY as u32, 0); - assert_eq(std::f32::NAN as i32, 0); - assert_eq(std::f32::NAN as u32, 0); + assert_eq(f32::MAX as i32, i32::MAX); + assert_eq(f32::INFINITY as i32, i32::MAX); + assert_eq(f32::MAX as u32, u32::MAX); + assert_eq(f32::INFINITY as u32, u32::MAX); + assert_eq(f32::MIN as i32, i32::MIN); + assert_eq(f32::NEG_INFINITY as i32, i32::MIN); + assert_eq(f32::MIN as u32, 0); + assert_eq(f32::NEG_INFINITY as u32, 0); + assert_eq(f32::NAN as i32, 0); + assert_eq(f32::NAN as u32, 0); assert_eq((u32::MAX-127) as f32 as u32, u32::MAX); // rounding loss assert_eq((u32::MAX-128) as f32 as u32, u32::MAX-255); // rounding loss assert_eq(127i8 as f32, 127.0f32); assert_eq(i128::MIN as f32, -170141183460469231731687303715884105728.0f32); - assert_eq(u128::MAX as f32, std::f32::INFINITY); // saturation + assert_eq(u128::MAX as f32, f32::INFINITY); // saturation // f64 <-> int casts assert_eq(5.0f64 as u64, 5); assert_eq(-5.0f64 as u64, 0); assert_eq(5.0f64 as i64, 5); assert_eq(-5.0f64 as i64, -5); - assert_eq(std::f64::MAX as i64, i64::MAX); - assert_eq(std::f64::INFINITY as i64, i64::MAX); - assert_eq(std::f64::MAX as u64, u64::MAX); - assert_eq(std::f64::INFINITY as u64, u64::MAX); - assert_eq(std::f64::MIN as i64, i64::MIN); - assert_eq(std::f64::NEG_INFINITY as i64, i64::MIN); - assert_eq(std::f64::MIN as u64, 0); - assert_eq(std::f64::NEG_INFINITY as u64, 0); - assert_eq(std::f64::NAN as i64, 0); - assert_eq(std::f64::NAN as u64, 0); + assert_eq(f64::MAX as i64, i64::MAX); + assert_eq(f64::INFINITY as i64, i64::MAX); + assert_eq(f64::MAX as u64, u64::MAX); + assert_eq(f64::INFINITY as u64, u64::MAX); + assert_eq(f64::MIN as i64, i64::MIN); + assert_eq(f64::NEG_INFINITY as i64, i64::MIN); + assert_eq(f64::MIN as u64, 0); + assert_eq(f64::NEG_INFINITY as u64, 0); + assert_eq(f64::NAN as i64, 0); + assert_eq(f64::NAN as u64, 0); assert_eq((u64::MAX-1023) as f64 as u64, u64::MAX); // rounding loss assert_eq((u64::MAX-1024) as f64 as u64, u64::MAX-2047); // rounding loss assert_eq(u128::MAX as f64 as u128, u128::MAX); @@ -74,38 +74,38 @@ fn main() { // f32 <-> f64 casts assert_eq(5.0f64 as f32, 5.0f32); assert_eq(5.0f32 as f64, 5.0f64); - assert_eq(std::f64::MAX as f32, std::f32::INFINITY); - assert_eq(std::f64::MIN as f32, std::f32::NEG_INFINITY); - assert_eq(std::f32::INFINITY as f64, std::f64::INFINITY); - assert_eq(std::f32::NEG_INFINITY as f64, std::f64::NEG_INFINITY); + assert_eq(f64::MAX as f32, f32::INFINITY); + assert_eq(f64::MIN as f32, f32::NEG_INFINITY); + assert_eq(f32::INFINITY as f64, f64::INFINITY); + assert_eq(f32::NEG_INFINITY as f64, f64::NEG_INFINITY); // f32 min/max assert_eq((1.0 as f32).max(-1.0), 1.0); assert_eq((1.0 as f32).min(-1.0), -1.0); - assert_eq(std::f32::NAN.min(9.0), 9.0); - assert_eq(std::f32::NAN.max(-9.0), -9.0); - assert_eq((9.0 as f32).min(std::f32::NAN), 9.0); - assert_eq((-9.0 as f32).max(std::f32::NAN), -9.0); + assert_eq(f32::NAN.min(9.0), 9.0); + assert_eq(f32::NAN.max(-9.0), -9.0); + assert_eq((9.0 as f32).min(f32::NAN), 9.0); + assert_eq((-9.0 as f32).max(f32::NAN), -9.0); // f64 min/max assert_eq((1.0 as f64).max(-1.0), 1.0); assert_eq((1.0 as f64).min(-1.0), -1.0); - assert_eq(std::f64::NAN.min(9.0), 9.0); - assert_eq(std::f64::NAN.max(-9.0), -9.0); - assert_eq((9.0 as f64).min(std::f64::NAN), 9.0); - assert_eq((-9.0 as f64).max(std::f64::NAN), -9.0); + assert_eq(f64::NAN.min(9.0), 9.0); + assert_eq(f64::NAN.max(-9.0), -9.0); + assert_eq((9.0 as f64).min(f64::NAN), 9.0); + assert_eq((-9.0 as f64).max(f64::NAN), -9.0); // f32 copysign assert_eq(3.5_f32.copysign(0.42), 3.5_f32); assert_eq(3.5_f32.copysign(-0.42), -3.5_f32); assert_eq((-3.5_f32).copysign(0.42), 3.5_f32); assert_eq((-3.5_f32).copysign(-0.42), -3.5_f32); - assert!(std::f32::NAN.copysign(1.0).is_nan()); + assert!(f32::NAN.copysign(1.0).is_nan()); // f64 copysign assert_eq(3.5_f64.copysign(0.42), 3.5_f64); assert_eq(3.5_f64.copysign(-0.42), -3.5_f64); assert_eq((-3.5_f64).copysign(0.42), 3.5_f64); assert_eq((-3.5_f64).copysign(-0.42), -3.5_f64); - assert!(std::f64::NAN.copysign(1.0).is_nan()); + assert!(f64::NAN.copysign(1.0).is_nan()); } From f462b4c25720db832b125b828bb474dd03628747 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 Apr 2020 13:35:30 +0200 Subject: [PATCH 1829/5092] memory reachable through globals is not a leak any more; adjust for better memory dumping --- src/machine.rs | 37 ++++++++++++++++++++--------- tests/run-pass/leak-in-static.rs | 8 +++++++ tests/run-pass/panic/catch_panic.rs | 3 --- 3 files changed, 34 insertions(+), 14 deletions(-) create mode 100644 tests/run-pass/leak-in-static.rs diff --git a/src/machine.rs b/src/machine.rs index f794453228b8..ab4fe4a2178d 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -6,6 +6,7 @@ use std::cell::RefCell; use std::num::NonZeroU64; use std::rc::Rc; use std::time::Instant; +use std::fmt; use log::trace; use rand::rngs::StdRng; @@ -62,6 +63,31 @@ impl Into> for MiriMemoryKind { } } +impl MayLeak for MiriMemoryKind { + #[inline(always)] + fn may_leak(self) -> bool { + use self::MiriMemoryKind::*; + match self { + Rust | C | WinHeap | Env => false, + Machine | Global => true, + } + } +} + +impl fmt::Display for MiriMemoryKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use self::MiriMemoryKind::*; + match self { + Rust => write!(f, "Rust heap"), + C => write!(f, "C heap"), + WinHeap => write!(f, "Windows heap"), + Machine => write!(f, "machine-managed memory"), + Env => write!(f, "environment variable"), + Global => write!(f, "global"), + } + } +} + /// Extra per-allocation data #[derive(Debug, Clone)] pub struct AllocExtra { @@ -491,14 +517,3 @@ impl AllocationExtra for AllocExtra { } } } - -impl MayLeak for MiriMemoryKind { - #[inline(always)] - fn may_leak(self) -> bool { - use self::MiriMemoryKind::*; - match self { - Rust | C | WinHeap | Env => false, - Machine | Global => true, - } - } -} diff --git a/tests/run-pass/leak-in-static.rs b/tests/run-pass/leak-in-static.rs new file mode 100644 index 000000000000..b12cbbf6e64f --- /dev/null +++ b/tests/run-pass/leak-in-static.rs @@ -0,0 +1,8 @@ +static mut LEAKER: Option>> = None; + +fn main() { + // Having memory "leaked" in globals is allowed. + unsafe { + LEAKER = Some(Box::new(vec![0; 42])); + } +} diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index 6408c940d98a..7689b85f7650 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -77,9 +77,6 @@ fn main() { test(None, |_old_val| { debug_assert!(false); loop {} }); test(None, |_old_val| { unsafe { (1 as *const i32).read() }; loop {} }); // trigger debug-assertion in libstd - // Cleanup: reset to default hook. - drop(std::panic::take_hook()); - eprintln!("Success!"); // Make sure we get this in stderr } From 7841f445932096adcf07944b707af73fc73830f1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 7 Apr 2020 19:33:03 +0200 Subject: [PATCH 1830/5092] rustup --- rust-version | 2 +- tests/compile-fail/stack_free.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 6e980a4e228e..b1fd330a9d66 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e6cef0445779724b469ab7b9a8d3c05d9e848ca8 +42abbd8878d3b67238f3611b0587c704ba94f39c diff --git a/tests/compile-fail/stack_free.rs b/tests/compile-fail/stack_free.rs index ea09d3e2b44a..50a590e448a6 100644 --- a/tests/compile-fail/stack_free.rs +++ b/tests/compile-fail/stack_free.rs @@ -1,7 +1,7 @@ // Validation/SB changes why we fail // compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -// error-pattern: deallocating `Stack` memory using `Machine(Rust)` deallocation operation +// error-pattern: deallocating stack variable memory using Rust heap deallocation operation fn main() { let x = 42; From 925465ebab87af43a40a32083f9db2799364c001 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 8 Apr 2020 11:39:35 +0200 Subject: [PATCH 1831/5092] more editing for CONTRIBUTING guide --- CONTRIBUTING.md | 69 ++++++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 50cfe14a28eb..41dd7765145d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,14 +5,14 @@ find useful. ## Getting started -Check out the issues on this GitHub repository for some ideas. There's lots that -needs to be done that we haven't documented in the issues yet, however. For more -ideas or help with hacking on Miri, you can contact us (`oli-obk` and `RalfJ`) -on the [Rust Zulip]. +Check out the issues on this GitHub repository for some ideas. In particular, +look for the green `E-*` labels which mark issues that should be rather +well-suited for onboarding. For more ideas or help with hacking on Miri, you can +contact us (`oli-obk` and `RalfJ`) on the [Rust Zulip]. [Rust Zulip]: https://rust-lang.zulipchat.com -## Building Miri with a pre-built rustc +## Preparing the build environment Miri heavily relies on internal rustc interfaces to execute MIR. Still, some things (like adding support for a new intrinsic or a shim for an external @@ -28,7 +28,11 @@ install that exact version of rustc as a toolchain: [`rustup-toolchain-install-master`]: https://github.com/kennytm/rustup-toolchain-install-master -Now building Miri is just one command away: +## Building and testing Miri + +Invoking Miri requires getting a bunch of flags right and setting up a custom +sysroot with xargo. The `miri` script takes care of that for you. With the +build environment prepared, compiling Miri is just one command away: ``` ./miri build @@ -37,32 +41,16 @@ Now building Miri is just one command away: Run `./miri` without arguments to see the other commands our build tool supports. -### Fixing Miri when rustc changes +### Testing the Miri driver -Miri is heavily tied to rustc internals, so it is very common that rustc changes -break Miri. Fixing those is a good way to get starting working on Miri. -Usually, Miri will require changes similar to the other consumers of the changed -rustc API, so reading the rustc PR diff is a good way to get an idea for what is -needed. +The Miri driver in the `src/bin/miri.rs` binary is the "heart" of Miri: it is +basically a version of `rustc` that, instead of compiling your code, runs it. +It accepts all the same flags as `rustc` (though the ones only affecting code +generation and linking obviously will have no effect) [and more][miri-flags]. -To update the `rustc-version` file and install the latest rustc, you can run: -``` -./rustup-toolchain HEAD -``` +[miri-flags]: README.md#miri--z-flags-and-environment-variables -Now try `./miri test`, and submit a PR once that works again. - -## Testing the Miri driver -[testing-miri]: #testing-the-miri-driver - -The Miri driver in the `miri` binary is the "heart" of Miri: it is basically a -version of `rustc` that, instead of compiling your code, runs it. It accepts -all the same flags as `rustc` (though the ones only affecting code generation -and linking obviously will have no effect) [and more][miri-flags]. - -Running the Miri driver requires some fiddling with environment variables, so -the `miri` script helps you do that. For example, you can (cross-)run the -driver on a particular file by doing +For example, you can (cross-)run the driver on a particular file by doing ```sh ./miri run tests/run-pass/format.rs @@ -99,7 +87,7 @@ MIRI_LOG=rustc_mir::interpret=info,miri::stacked_borrows ./miri run tests/run-pa In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an evaluation error was originally raised. -## Testing `cargo miri` +### Testing `cargo miri` Working with the driver directly gives you full control, but you also lose all the convenience provided by cargo. Once your test case depends on a crate, it @@ -117,7 +105,24 @@ There's a test for the cargo wrapper in the `test-cargo-miri` directory; run `./run-test.py` in there to execute it. Like `./miri test`, this respects the `MIRI_TEST_TARGET` environment variable to execute the test for another target. -## Building Miri with a locally built rustc +### Fixing Miri when rustc changes + +Miri is heavily tied to rustc internals, so it is very common that rustc changes +break Miri. Usually, Miri will require changes similar to the other consumers +of the changed rustc API, so reading the rustc PR diff is a good way to get an +idea for what is needed. + +To update the `rustc-version` file and install the latest rustc, you can run: +``` +./rustup-toolchain HEAD +``` + +Now try `./miri test`, and submit a PR once that works again. Even if you choose +not to use `./rustup-toolchain`, it is important that the `rustc-version` file +is updated, as our CI makes sure that Miri works well with that particular +version of rustc. + +## Advanced topic: Building Miri with a locally built rustc A big part of the Miri driver lives in rustc, so working on Miri will sometimes require using a locally built rustc. The bug you want to fix may actually be on @@ -143,4 +148,4 @@ rustup override set custom ``` With this, you should now have a working development setup! See -[above][testing-miri] for how to proceed working with the Miri driver. +[above](#building-and-testing-miri) for how to proceed working on Miri. From b1009c4aa5356163d91ef9b30d987e1633d04add Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 8 Apr 2020 12:30:45 +0200 Subject: [PATCH 1832/5092] more editing --- CONTRIBUTING.md | 44 ++++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 41dd7765145d..5862d2d402ae 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,9 +14,9 @@ contact us (`oli-obk` and `RalfJ`) on the [Rust Zulip]. ## Preparing the build environment -Miri heavily relies on internal rustc interfaces to execute MIR. Still, some -things (like adding support for a new intrinsic or a shim for an external -function being called) can be done by working just on the Miri side. +Miri heavily relies on internal and unstable rustc interfaces to execute MIR, +which means it is important that you install a version of rustc that Miri +actually works with. The `rust-version` file contains the commit hash of rustc that Miri is currently tested against. Other versions will likely not work. After installing @@ -25,13 +25,15 @@ install that exact version of rustc as a toolchain: ``` ./rustup-toolchain ``` +This will set up a rustup toolchain called `miri` and set it as an override for +the current directory. [`rustup-toolchain-install-master`]: https://github.com/kennytm/rustup-toolchain-install-master ## Building and testing Miri Invoking Miri requires getting a bunch of flags right and setting up a custom -sysroot with xargo. The `miri` script takes care of that for you. With the +sysroot with xargo. The `miri` script takes care of that for you. With the build environment prepared, compiling Miri is just one command away: ``` @@ -76,7 +78,7 @@ MIRI_LOG=info ./miri run tests/run-pass/vecs.rs ``` Setting `MIRI_LOG` like this will configure logging for Miri itself as well as -the `rustc_middle::mir::interpret` and `rustc_mir::interpret` modules in rustc. You +the `rustc_middle::mir::interpret` and `rustc_mir::interpret` modules in rustc. You can also do more targeted configuration, e.g. the following helps debug the stacked borrows implementation: @@ -90,8 +92,8 @@ evaluation error was originally raised. ### Testing `cargo miri` Working with the driver directly gives you full control, but you also lose all -the convenience provided by cargo. Once your test case depends on a crate, it -is probably easier to test it with the cargo wrapper. You can install your +the convenience provided by cargo. Once your test case depends on a crate, it +is probably easier to test it with the cargo wrapper. You can install your development version of Miri using ``` @@ -105,27 +107,33 @@ There's a test for the cargo wrapper in the `test-cargo-miri` directory; run `./run-test.py` in there to execute it. Like `./miri test`, this respects the `MIRI_TEST_TARGET` environment variable to execute the test for another target. -### Fixing Miri when rustc changes +## Advanced topic: other build environments -Miri is heavily tied to rustc internals, so it is very common that rustc changes -break Miri. Usually, Miri will require changes similar to the other consumers -of the changed rustc API, so reading the rustc PR diff is a good way to get an -idea for what is needed. +We described above the simplest way to get a working build environment for Miri, +which is to use the version of rustc indicated by `rustc-version`. But +sometimes, that is not enough. + +### Updating `rustc-version` + +The `rustc-version` file is regularly updated to keep Miri close to the latest +version of rustc. Usually, new contributors do not have to worry about this. But +sometimes a newer rustc is needed for a patch, and sometimes Miri needs fixing +for changes in rustc. In both cases, `rustc-version` needs updating. To update the `rustc-version` file and install the latest rustc, you can run: ``` ./rustup-toolchain HEAD ``` -Now try `./miri test`, and submit a PR once that works again. Even if you choose -not to use `./rustup-toolchain`, it is important that the `rustc-version` file -is updated, as our CI makes sure that Miri works well with that particular -version of rustc. +Now edit Miri until `./miri test` passes, and submit a PR. Generally, it is +preferred to separate updating `rustc-version` and doing what it takes to get +Miri working again, from implementing new features that rely on the updated +rustc. This avoids blocking all Miri development on landing a big PR. -## Advanced topic: Building Miri with a locally built rustc +### Building Miri with a locally built rustc A big part of the Miri driver lives in rustc, so working on Miri will sometimes -require using a locally built rustc. The bug you want to fix may actually be on +require using a locally built rustc. The bug you want to fix may actually be on the rustc side, or you just need to get more detailed trace of the execution than what is possible with release builds -- in both cases, you should develop miri against a rustc you compiled yourself, with debug assertions (and hence From 4069302a8ce80b51c4a6ae4dcdeb4fb14a0f4e2c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 8 Apr 2020 15:17:26 +0200 Subject: [PATCH 1833/5092] add EbrCell to trophy case --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 1c2c885674a5..efa38f8f739e 100644 --- a/README.md +++ b/README.md @@ -259,6 +259,7 @@ Definite bugs found: * [`getrandom` calling the `getrandom` syscall in an invalid way](https://github.com/rust-random/getrandom/pull/73) * [`Vec`](https://github.com/rust-lang/rust/issues/69770) and [`BTreeMap`](https://github.com/rust-lang/rust/issues/69769) leaking memory under some (panicky) conditions * [Memory leak in `beef`](https://github.com/maciejhirsz/beef/issues/12) +* [Invalid use of undefined memory in `EbrCell`](https://github.com/Firstyear/concread/commit/b15be53b6ec076acb295a5c0483cdb4bf9be838f#diff-6282b2fc8e98bd089a1f0c86f648157cR229) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From fedca29e6979b77db1d4712dc62be041cf7f2d36 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 8 Apr 2020 15:56:59 +0200 Subject: [PATCH 1834/5092] tweak wording --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5862d2d402ae..a143190d5bdb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -45,7 +45,7 @@ supports. ### Testing the Miri driver -The Miri driver in the `src/bin/miri.rs` binary is the "heart" of Miri: it is +The Miri driver compiled from `src/bin/miri.rs` is the "heart" of Miri: it is basically a version of `rustc` that, instead of compiling your code, runs it. It accepts all the same flags as `rustc` (though the ones only affecting code generation and linking obviously will have no effect) [and more][miri-flags]. From d276d952ff448f1c1bdf9200fe1f9db00f2f1817 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 10 Apr 2020 10:27:59 +0200 Subject: [PATCH 1835/5092] fix unused warnings in tests --- tests/compile-fail/deallocate-bad-alignment.rs | 2 +- tests/compile-fail/deallocate-bad-size.rs | 2 +- tests/compile-fail/deallocate-twice.rs | 2 +- tests/compile-fail/reallocate-bad-size.rs | 2 +- tests/compile-fail/reallocate-change-alloc.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/compile-fail/deallocate-bad-alignment.rs b/tests/compile-fail/deallocate-bad-alignment.rs index 9b5ee9a934b0..621c05344b4a 100644 --- a/tests/compile-fail/deallocate-bad-alignment.rs +++ b/tests/compile-fail/deallocate-bad-alignment.rs @@ -1,4 +1,4 @@ -use std::alloc::{alloc, dealloc, realloc, Layout}; +use std::alloc::{alloc, dealloc, Layout}; // error-pattern: allocation has size 1 and alignment 1, but gave size 1 and alignment 2 diff --git a/tests/compile-fail/deallocate-bad-size.rs b/tests/compile-fail/deallocate-bad-size.rs index 39a0d48c8b1a..386bb56b9091 100644 --- a/tests/compile-fail/deallocate-bad-size.rs +++ b/tests/compile-fail/deallocate-bad-size.rs @@ -1,4 +1,4 @@ -use std::alloc::{alloc, dealloc, realloc, Layout}; +use std::alloc::{alloc, dealloc, Layout}; // error-pattern: allocation has size 1 and alignment 1, but gave size 2 and alignment 1 diff --git a/tests/compile-fail/deallocate-twice.rs b/tests/compile-fail/deallocate-twice.rs index 3c5e8e96360c..67312b0d96dd 100644 --- a/tests/compile-fail/deallocate-twice.rs +++ b/tests/compile-fail/deallocate-twice.rs @@ -1,4 +1,4 @@ -use std::alloc::{alloc, dealloc, realloc, Layout}; +use std::alloc::{alloc, dealloc, Layout}; // error-pattern: dereferenced after this allocation got freed diff --git a/tests/compile-fail/reallocate-bad-size.rs b/tests/compile-fail/reallocate-bad-size.rs index bbdef4421b6c..7826f26f9b8c 100644 --- a/tests/compile-fail/reallocate-bad-size.rs +++ b/tests/compile-fail/reallocate-bad-size.rs @@ -1,4 +1,4 @@ -use std::alloc::{alloc, dealloc, realloc, Layout}; +use std::alloc::{alloc, realloc, Layout}; // error-pattern: allocation has size 1 and alignment 1, but gave size 2 and alignment 1 diff --git a/tests/compile-fail/reallocate-change-alloc.rs b/tests/compile-fail/reallocate-change-alloc.rs index 8130d72dee59..297029676962 100644 --- a/tests/compile-fail/reallocate-change-alloc.rs +++ b/tests/compile-fail/reallocate-change-alloc.rs @@ -1,4 +1,4 @@ -use std::alloc::{alloc, dealloc, realloc, Layout}; +use std::alloc::{alloc, realloc, Layout}; fn main() { unsafe { From f77e0281c942f9f9df2db7ec5a52306fbaa75906 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 10 Apr 2020 10:28:07 +0200 Subject: [PATCH 1836/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index b1fd330a9d66..40c0005e0806 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -42abbd8878d3b67238f3611b0587c704ba94f39c +0c835b0cca83fe21090562603e4bda77c183ace3 From 280394d366c0523f24a3a73e2e58650a5a4bfc1a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 10 Apr 2020 10:28:23 +0200 Subject: [PATCH 1837/5092] cargo update --- Cargo.lock | 234 +++++++++++++------------------------ test-cargo-miri/Cargo.lock | 35 +++--- 2 files changed, 91 insertions(+), 178 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b36418a1cbac..f8ac5fe4b18b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,7 +2,7 @@ # It is not intended for manual editing. [[package]] name = "aho-corasick" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -10,7 +10,7 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.26" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -28,8 +28,8 @@ name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -38,26 +38,6 @@ name = "autocfg" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "backtrace" -version = "0.3.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "backtrace-sys 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "backtrace-sys" -version = "0.1.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "base64" version = "0.11.0" @@ -83,30 +63,17 @@ name = "byteorder" version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "c2-chacha" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "cargo_metadata" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "cc" -version = "1.0.50" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "cfg-if" version = "0.1.10" @@ -138,16 +105,16 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "diff 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rustfix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rustfix 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tester 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -197,7 +164,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -210,37 +177,17 @@ dependencies = [ "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "failure" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "backtrace 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "failure_derive" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "filetime" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -259,16 +206,16 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "hermit-abi" -version = "0.1.8" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -296,7 +243,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.67" +version = "0.2.68" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -317,7 +264,7 @@ name = "miow" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "socket2 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -338,10 +285,10 @@ dependencies = [ "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "vergen 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -368,7 +315,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -384,7 +331,7 @@ name = "quote" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -393,18 +340,18 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_chacha" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -441,18 +388,18 @@ dependencies = [ [[package]] name = "regex" -version = "1.3.4" +version = "1.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex-syntax" -version = "0.6.16" +version = "0.6.17" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -474,11 +421,6 @@ dependencies = [ "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rustc-demangle" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "rustc-workspace-hack" version = "1.0.0" @@ -494,18 +436,18 @@ dependencies = [ [[package]] name = "rustfix" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "anyhow 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ryu" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -514,7 +456,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -524,30 +466,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.104" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.104" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.48" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -557,43 +499,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "socket2" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "syn" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "synstructure" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "tempfile" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -614,7 +545,7 @@ name = "termcolor" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -623,7 +554,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -640,7 +571,7 @@ name = "time" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -657,12 +588,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "vergen" -version = "3.0.4" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -686,7 +616,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi-util" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -698,21 +628,17 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] -"checksum aho-corasick 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)" = "d5e63fd144e18ba274ae7095c0197a870a7b9468abc801dd62f190d80817d2ec" -"checksum anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "7825f6833612eb2414095684fcf6c635becf3ce97fe48cf6421321e93bfbd53c" +"checksum aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" +"checksum anyhow 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "d9a60d744a80c30fcb657dfe2c1b22bcb3e814c1a1e3674f32bf5820b570fbff" "checksum arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" "checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" "checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" "checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" -"checksum backtrace 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)" = "ad235dabf00f36301792cfe82499880ba54c6486be094d1047b02bacb67c14e8" -"checksum backtrace-sys 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "e17b52e737c40a7d75abca20b29a19a0eb7ba9fc72c5a72dd282a0a3c2c0dc35" "checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" -"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" "checksum cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46e3374c604fb39d1a2f35ed5e4a4e30e60d01fab49446e08f1b3e9a90aef202" -"checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" "checksum colored 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" @@ -724,50 +650,46 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" "checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" "checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" -"checksum failure 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b8529c2421efa3066a5cbd8063d2244603824daccb6936b079010bb2aa89464b" -"checksum failure_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "030a733c8287d6213886dd487564ff5c8f6aae10278b3588ed177f9d18f8d231" -"checksum filetime 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1ff6d4dab0aa0c8e6346d46052e93b13a16cf847b54ed357087c35011048cc7d" +"checksum filetime 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f59efc38004c988e4201d11d263b8171f49a2e7ec0bdbb71773433f271504a5e" "checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" "checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" -"checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8" +"checksum hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" "checksum hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" "checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018" +"checksum libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" "checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226" "checksum num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" "checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" -"checksum proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435" +"checksum proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3" "checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" "checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" "checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" +"checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" "checksum redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" -"checksum regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "322cf97724bea3ee221b78fe25ac9c46114ebb51747ad5babd51a2fc6a8235a8" -"checksum regex-syntax 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "1132f845907680735a84409c3bebc64d1364a5683ffbce899550cd09d5eaefc1" +"checksum regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7f6946991529684867e47d86474e3a6d0c0ab9b82d5821e314b1ede31fa3a4b3" +"checksum regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" "checksum rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" -"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" "checksum rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum rustfix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "804b11883a5ce0ad0378fbf95a8dea59ee6b51c331a73b8f471b6bdaa3bd40c1" -"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" +"checksum rustfix 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f2c50b74badcddeb8f7652fa8323ce440b95286f8e4b64ebfd871c609672704e" +"checksum ryu 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535622e6be132bccd223f4bb2b8ac8d53cda3c7a6394944d3b2b33fb974f9d76" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" -"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" -"checksum serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "9371ade75d4c2d6cb154141b9752cf3781ec9c05e0e5cf35060e1e70ee7b9c25" +"checksum serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399" +"checksum serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c" +"checksum serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)" = "da07b57ee2623368351e9a0488bb0b261322a15a6e0ae53e243cbdc0f4208da9" "checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9" -"checksum socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e8b74de517221a2cb01a53349cf54182acdc31a074727d3079068448c0676d85" -"checksum syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "123bd9499cfb380418d509322d7a6d52e5315f064fe4b3ad18a53d6b92c07859" -"checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" +"checksum socket2 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" +"checksum syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" "checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" @@ -776,9 +698,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" -"checksum vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6aba5e34f93dc7051dfad05b98a18e9156f27e7b431fe1d2398cb6061c0a1dba" +"checksum vergen 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ce50d8996df1f85af15f2cd8d33daae6e479575123ef4314a51a70a230739cb" "checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfbf554c6ad11084fb7517daca16cfdcaccbdadba4fc336f032a8b12c2ad80" +"checksum winapi-util 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "fa515c5163a99cc82bab70fd3bfdd36d827be85de63737b40fcef2ce084a436e" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index f4d20ab8e158..ecf71a5f437a 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -5,14 +5,6 @@ name = "byteorder" version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "c2-chacha" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "cargo-miri-test" version = "0.1.0" @@ -33,21 +25,21 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "hermit-abi" -version = "0.1.8" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libc" -version = "0.2.67" +version = "0.2.68" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -55,8 +47,8 @@ name = "num_cpus" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -70,8 +62,8 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -79,10 +71,10 @@ dependencies = [ [[package]] name = "rand_chacha" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -117,15 +109,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" -"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" -"checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8" -"checksum libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018" +"checksum hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" +"checksum libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" "checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" "checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" +"checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" From 93027da5ed4ce1e98b39ec9b35ca93961ef8a723 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 10 Apr 2020 14:57:22 +0200 Subject: [PATCH 1838/5092] bump compiletest --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f8ac5fe4b18b..0dbf00e6c566 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -101,7 +101,7 @@ dependencies = [ [[package]] name = "compiletest_rs" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "diff 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -275,7 +275,7 @@ dependencies = [ "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "compiletest_rs 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "compiletest_rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -642,7 +642,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" "checksum colored 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" -"checksum compiletest_rs 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46cc00afd45129f775f8f8ee57c1ae2f7aabdf9692b2d74e36b917b91277bc7c" +"checksum compiletest_rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f737835bfbbe29ed1ff82d5137520338d7ed5bf1a1d4b9c1c7c58bb45b8fa29" "checksum constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" "checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" "checksum diff 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" diff --git a/Cargo.toml b/Cargo.toml index e788e775972a..8ccc9484c88b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,7 +57,7 @@ serde = { version = "*", features = ["derive"] } vergen = "3" [dev-dependencies] -compiletest_rs = { version = "0.4", features = ["tmp"] } +compiletest_rs = { version = "0.5", features = ["tmp"] } colored = "1.6" [features] From ea37f580e4f521d9b1eeadea59ecc4fd579a594b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 Apr 2020 09:16:55 +0200 Subject: [PATCH 1839/5092] add push_str issue to trophy case --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index efa38f8f739e..4968e6665712 100644 --- a/README.md +++ b/README.md @@ -269,6 +269,7 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [`Vec::push` invalidating existing references into the vector](https://github.com/rust-lang/rust/issues/60847) * [`align_to_mut` violating uniqueness of mutable references](https://github.com/rust-lang/rust/issues/68549) * [Aliasing mutable references in `sized-chunks`](https://github.com/bodil/sized-chunks/issues/8) +* [`String::push_str` invalidating existing references into the string](https://github.com/rust-lang/rust/issues/70301) ## License From b2bf4ec2f5e6938dfcebe0690beabbef22652afb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 Apr 2020 09:30:13 +0200 Subject: [PATCH 1840/5092] organize compile-fail tests in folders --- tests/compile-fail/{ => alloc}/deallocate-bad-alignment.rs | 0 tests/compile-fail/{ => alloc}/deallocate-bad-size.rs | 0 tests/compile-fail/{ => alloc}/deallocate-twice.rs | 0 tests/compile-fail/{ => alloc}/reallocate-bad-size.rs | 0 tests/compile-fail/{ => alloc}/reallocate-change-alloc.rs | 0 tests/compile-fail/{ => alloc}/reallocate-dangling.rs | 0 tests/compile-fail/{ => alloc}/stack_free.rs | 0 .../{ => dangling_pointers}/dangling_pointer_deref.rs | 0 .../{ => dangling_pointers}/dangling_zst_deref.rs | 0 .../compile-fail/{ => dangling_pointers}/deref-invalid-ptr.rs | 4 ++-- .../{ => dangling_pointers}/deref-partially-dangling.rs | 0 .../{ => dangling_pointers}/maybe_null_pointer_deref_zst.rs | 0 .../{ => dangling_pointers}/maybe_null_pointer_write_zst.rs | 0 .../{ => dangling_pointers}/out_of_bounds_read1.rs | 0 .../{ => dangling_pointers}/out_of_bounds_read2.rs | 0 .../{ => dangling_pointers}/wild_pointer_deref.rs | 0 .../{ => function_pointers}/cast_box_int_to_fn_ptr.rs | 0 tests/compile-fail/{ => function_pointers}/cast_fn_ptr1.rs | 0 tests/compile-fail/{ => function_pointers}/cast_fn_ptr2.rs | 0 tests/compile-fail/{ => function_pointers}/cast_fn_ptr3.rs | 0 tests/compile-fail/{ => function_pointers}/cast_fn_ptr4.rs | 0 tests/compile-fail/{ => function_pointers}/cast_fn_ptr5.rs | 0 .../{ => function_pointers}/cast_int_to_fn_ptr.rs | 0 tests/compile-fail/{ => function_pointers}/deref_fn_ptr.rs | 0 tests/compile-fail/{ => function_pointers}/execute_memory.rs | 0 tests/compile-fail/{ => function_pointers}/fn_ptr_offset.rs | 0 tests/compile-fail/{ => intrinsics}/assume.rs | 0 tests/compile-fail/{ => intrinsics}/copy_null.rs | 0 tests/compile-fail/{ => intrinsics}/copy_overflow.rs | 0 tests/compile-fail/{ => intrinsics}/copy_overlapping.rs | 0 tests/compile-fail/{ => intrinsics}/copy_unaligned.rs | 0 tests/compile-fail/{ => intrinsics}/ctlz_nonzero.rs | 0 tests/compile-fail/{ => intrinsics}/cttz_nonzero.rs | 0 tests/compile-fail/{ => intrinsics}/div-by-zero-1.rs | 0 tests/compile-fail/{ => intrinsics}/div-by-zero-2.rs | 0 tests/compile-fail/{ => intrinsics}/exact_div1.rs | 0 tests/compile-fail/{ => intrinsics}/exact_div2.rs | 0 tests/compile-fail/{ => intrinsics}/exact_div3.rs | 0 tests/compile-fail/{ => intrinsics}/exact_div4.rs | 0 tests/compile-fail/{ => intrinsics}/out_of_bounds_ptr_1.rs | 0 tests/compile-fail/{ => intrinsics}/out_of_bounds_ptr_2.rs | 0 .../{ => intrinsics}/overflowing-unchecked-rsh.rs | 0 tests/compile-fail/{ => intrinsics}/ptr_offset_0_plus_0.rs | 0 .../compile-fail/{ => intrinsics}/ptr_offset_int_plus_int.rs | 0 .../compile-fail/{ => intrinsics}/ptr_offset_int_plus_ptr.rs | 0 tests/compile-fail/{ => intrinsics}/ptr_offset_overflow.rs | 0 tests/compile-fail/{ => intrinsics}/ptr_offset_ptr_plus_0.rs | 0 tests/compile-fail/{ => intrinsics}/unchecked_add1.rs | 0 tests/compile-fail/{ => intrinsics}/unchecked_add2.rs | 0 tests/compile-fail/{ => intrinsics}/unchecked_div1.rs | 0 tests/compile-fail/{ => intrinsics}/unchecked_mul1.rs | 0 tests/compile-fail/{ => intrinsics}/unchecked_mul2.rs | 0 tests/compile-fail/{ => intrinsics}/unchecked_sub1.rs | 0 tests/compile-fail/{ => intrinsics}/unchecked_sub2.rs | 0 tests/compile-fail/{ => intrinsics}/write_bytes_null.rs | 0 tests/compile-fail/{ => intrinsics}/write_bytes_overflow.rs | 0 .../{ => sync}/libc_pthread_mutex_destroy_locked.rs | 0 .../{ => sync}/libc_pthread_mutex_normal_deadlock.rs | 0 .../{ => sync}/libc_pthread_mutex_normal_unlock_unlocked.rs | 0 .../{ => sync}/libc_pthread_rwlock_destroy_read_locked.rs | 0 .../{ => sync}/libc_pthread_rwlock_destroy_write_locked.rs | 0 .../{ => sync}/libc_pthread_rwlock_read_write_deadlock.rs | 0 .../{ => sync}/libc_pthread_rwlock_unlock_unlocked.rs | 0 .../{ => sync}/libc_pthread_rwlock_write_read_deadlock.rs | 0 .../{ => sync}/libc_pthread_rwlock_write_write_deadlock.rs | 0 tests/compile-fail/{ => unaligned_pointers}/alignment.rs | 0 .../compile-fail/{ => unaligned_pointers}/atomic_unaligned.rs | 0 .../{ => unaligned_pointers}/intptrcast_alignment_check.rs | 0 .../{ => unaligned_pointers}/reference_to_packed.rs | 0 tests/compile-fail/{ => unaligned_pointers}/unaligned_ptr1.rs | 0 tests/compile-fail/{ => unaligned_pointers}/unaligned_ptr2.rs | 0 tests/compile-fail/{ => unaligned_pointers}/unaligned_ptr3.rs | 0 .../{ => unaligned_pointers}/unaligned_ptr_zst.rs | 0 73 files changed, 2 insertions(+), 2 deletions(-) rename tests/compile-fail/{ => alloc}/deallocate-bad-alignment.rs (100%) rename tests/compile-fail/{ => alloc}/deallocate-bad-size.rs (100%) rename tests/compile-fail/{ => alloc}/deallocate-twice.rs (100%) rename tests/compile-fail/{ => alloc}/reallocate-bad-size.rs (100%) rename tests/compile-fail/{ => alloc}/reallocate-change-alloc.rs (100%) rename tests/compile-fail/{ => alloc}/reallocate-dangling.rs (100%) rename tests/compile-fail/{ => alloc}/stack_free.rs (100%) rename tests/compile-fail/{ => dangling_pointers}/dangling_pointer_deref.rs (100%) rename tests/compile-fail/{ => dangling_pointers}/dangling_zst_deref.rs (100%) rename tests/compile-fail/{ => dangling_pointers}/deref-invalid-ptr.rs (75%) rename tests/compile-fail/{ => dangling_pointers}/deref-partially-dangling.rs (100%) rename tests/compile-fail/{ => dangling_pointers}/maybe_null_pointer_deref_zst.rs (100%) rename tests/compile-fail/{ => dangling_pointers}/maybe_null_pointer_write_zst.rs (100%) rename tests/compile-fail/{ => dangling_pointers}/out_of_bounds_read1.rs (100%) rename tests/compile-fail/{ => dangling_pointers}/out_of_bounds_read2.rs (100%) rename tests/compile-fail/{ => dangling_pointers}/wild_pointer_deref.rs (100%) rename tests/compile-fail/{ => function_pointers}/cast_box_int_to_fn_ptr.rs (100%) rename tests/compile-fail/{ => function_pointers}/cast_fn_ptr1.rs (100%) rename tests/compile-fail/{ => function_pointers}/cast_fn_ptr2.rs (100%) rename tests/compile-fail/{ => function_pointers}/cast_fn_ptr3.rs (100%) rename tests/compile-fail/{ => function_pointers}/cast_fn_ptr4.rs (100%) rename tests/compile-fail/{ => function_pointers}/cast_fn_ptr5.rs (100%) rename tests/compile-fail/{ => function_pointers}/cast_int_to_fn_ptr.rs (100%) rename tests/compile-fail/{ => function_pointers}/deref_fn_ptr.rs (100%) rename tests/compile-fail/{ => function_pointers}/execute_memory.rs (100%) rename tests/compile-fail/{ => function_pointers}/fn_ptr_offset.rs (100%) rename tests/compile-fail/{ => intrinsics}/assume.rs (100%) rename tests/compile-fail/{ => intrinsics}/copy_null.rs (100%) rename tests/compile-fail/{ => intrinsics}/copy_overflow.rs (100%) rename tests/compile-fail/{ => intrinsics}/copy_overlapping.rs (100%) rename tests/compile-fail/{ => intrinsics}/copy_unaligned.rs (100%) rename tests/compile-fail/{ => intrinsics}/ctlz_nonzero.rs (100%) rename tests/compile-fail/{ => intrinsics}/cttz_nonzero.rs (100%) rename tests/compile-fail/{ => intrinsics}/div-by-zero-1.rs (100%) rename tests/compile-fail/{ => intrinsics}/div-by-zero-2.rs (100%) rename tests/compile-fail/{ => intrinsics}/exact_div1.rs (100%) rename tests/compile-fail/{ => intrinsics}/exact_div2.rs (100%) rename tests/compile-fail/{ => intrinsics}/exact_div3.rs (100%) rename tests/compile-fail/{ => intrinsics}/exact_div4.rs (100%) rename tests/compile-fail/{ => intrinsics}/out_of_bounds_ptr_1.rs (100%) rename tests/compile-fail/{ => intrinsics}/out_of_bounds_ptr_2.rs (100%) rename tests/compile-fail/{ => intrinsics}/overflowing-unchecked-rsh.rs (100%) rename tests/compile-fail/{ => intrinsics}/ptr_offset_0_plus_0.rs (100%) rename tests/compile-fail/{ => intrinsics}/ptr_offset_int_plus_int.rs (100%) rename tests/compile-fail/{ => intrinsics}/ptr_offset_int_plus_ptr.rs (100%) rename tests/compile-fail/{ => intrinsics}/ptr_offset_overflow.rs (100%) rename tests/compile-fail/{ => intrinsics}/ptr_offset_ptr_plus_0.rs (100%) rename tests/compile-fail/{ => intrinsics}/unchecked_add1.rs (100%) rename tests/compile-fail/{ => intrinsics}/unchecked_add2.rs (100%) rename tests/compile-fail/{ => intrinsics}/unchecked_div1.rs (100%) rename tests/compile-fail/{ => intrinsics}/unchecked_mul1.rs (100%) rename tests/compile-fail/{ => intrinsics}/unchecked_mul2.rs (100%) rename tests/compile-fail/{ => intrinsics}/unchecked_sub1.rs (100%) rename tests/compile-fail/{ => intrinsics}/unchecked_sub2.rs (100%) rename tests/compile-fail/{ => intrinsics}/write_bytes_null.rs (100%) rename tests/compile-fail/{ => intrinsics}/write_bytes_overflow.rs (100%) rename tests/compile-fail/{ => sync}/libc_pthread_mutex_destroy_locked.rs (100%) rename tests/compile-fail/{ => sync}/libc_pthread_mutex_normal_deadlock.rs (100%) rename tests/compile-fail/{ => sync}/libc_pthread_mutex_normal_unlock_unlocked.rs (100%) rename tests/compile-fail/{ => sync}/libc_pthread_rwlock_destroy_read_locked.rs (100%) rename tests/compile-fail/{ => sync}/libc_pthread_rwlock_destroy_write_locked.rs (100%) rename tests/compile-fail/{ => sync}/libc_pthread_rwlock_read_write_deadlock.rs (100%) rename tests/compile-fail/{ => sync}/libc_pthread_rwlock_unlock_unlocked.rs (100%) rename tests/compile-fail/{ => sync}/libc_pthread_rwlock_write_read_deadlock.rs (100%) rename tests/compile-fail/{ => sync}/libc_pthread_rwlock_write_write_deadlock.rs (100%) rename tests/compile-fail/{ => unaligned_pointers}/alignment.rs (100%) rename tests/compile-fail/{ => unaligned_pointers}/atomic_unaligned.rs (100%) rename tests/compile-fail/{ => unaligned_pointers}/intptrcast_alignment_check.rs (100%) rename tests/compile-fail/{ => unaligned_pointers}/reference_to_packed.rs (100%) rename tests/compile-fail/{ => unaligned_pointers}/unaligned_ptr1.rs (100%) rename tests/compile-fail/{ => unaligned_pointers}/unaligned_ptr2.rs (100%) rename tests/compile-fail/{ => unaligned_pointers}/unaligned_ptr3.rs (100%) rename tests/compile-fail/{ => unaligned_pointers}/unaligned_ptr_zst.rs (100%) diff --git a/tests/compile-fail/deallocate-bad-alignment.rs b/tests/compile-fail/alloc/deallocate-bad-alignment.rs similarity index 100% rename from tests/compile-fail/deallocate-bad-alignment.rs rename to tests/compile-fail/alloc/deallocate-bad-alignment.rs diff --git a/tests/compile-fail/deallocate-bad-size.rs b/tests/compile-fail/alloc/deallocate-bad-size.rs similarity index 100% rename from tests/compile-fail/deallocate-bad-size.rs rename to tests/compile-fail/alloc/deallocate-bad-size.rs diff --git a/tests/compile-fail/deallocate-twice.rs b/tests/compile-fail/alloc/deallocate-twice.rs similarity index 100% rename from tests/compile-fail/deallocate-twice.rs rename to tests/compile-fail/alloc/deallocate-twice.rs diff --git a/tests/compile-fail/reallocate-bad-size.rs b/tests/compile-fail/alloc/reallocate-bad-size.rs similarity index 100% rename from tests/compile-fail/reallocate-bad-size.rs rename to tests/compile-fail/alloc/reallocate-bad-size.rs diff --git a/tests/compile-fail/reallocate-change-alloc.rs b/tests/compile-fail/alloc/reallocate-change-alloc.rs similarity index 100% rename from tests/compile-fail/reallocate-change-alloc.rs rename to tests/compile-fail/alloc/reallocate-change-alloc.rs diff --git a/tests/compile-fail/reallocate-dangling.rs b/tests/compile-fail/alloc/reallocate-dangling.rs similarity index 100% rename from tests/compile-fail/reallocate-dangling.rs rename to tests/compile-fail/alloc/reallocate-dangling.rs diff --git a/tests/compile-fail/stack_free.rs b/tests/compile-fail/alloc/stack_free.rs similarity index 100% rename from tests/compile-fail/stack_free.rs rename to tests/compile-fail/alloc/stack_free.rs diff --git a/tests/compile-fail/dangling_pointer_deref.rs b/tests/compile-fail/dangling_pointers/dangling_pointer_deref.rs similarity index 100% rename from tests/compile-fail/dangling_pointer_deref.rs rename to tests/compile-fail/dangling_pointers/dangling_pointer_deref.rs diff --git a/tests/compile-fail/dangling_zst_deref.rs b/tests/compile-fail/dangling_pointers/dangling_zst_deref.rs similarity index 100% rename from tests/compile-fail/dangling_zst_deref.rs rename to tests/compile-fail/dangling_pointers/dangling_zst_deref.rs diff --git a/tests/compile-fail/deref-invalid-ptr.rs b/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs similarity index 75% rename from tests/compile-fail/deref-invalid-ptr.rs rename to tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs index 561017293a16..e0bba8c7c730 100644 --- a/tests/compile-fail/deref-invalid-ptr.rs +++ b/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs @@ -2,6 +2,6 @@ // compile-flags: -Zmiri-disable-validation fn main() { - let x = 2usize as *const u32; - let _y = unsafe { &*x as *const u32 }; //~ ERROR invalid use of 2 as a pointer + let x = 16usize as *const u32; + let _y = unsafe { &*x as *const u32 }; //~ ERROR invalid use of 16 as a pointer } diff --git a/tests/compile-fail/deref-partially-dangling.rs b/tests/compile-fail/dangling_pointers/deref-partially-dangling.rs similarity index 100% rename from tests/compile-fail/deref-partially-dangling.rs rename to tests/compile-fail/dangling_pointers/deref-partially-dangling.rs diff --git a/tests/compile-fail/maybe_null_pointer_deref_zst.rs b/tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.rs similarity index 100% rename from tests/compile-fail/maybe_null_pointer_deref_zst.rs rename to tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.rs diff --git a/tests/compile-fail/maybe_null_pointer_write_zst.rs b/tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.rs similarity index 100% rename from tests/compile-fail/maybe_null_pointer_write_zst.rs rename to tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.rs diff --git a/tests/compile-fail/out_of_bounds_read1.rs b/tests/compile-fail/dangling_pointers/out_of_bounds_read1.rs similarity index 100% rename from tests/compile-fail/out_of_bounds_read1.rs rename to tests/compile-fail/dangling_pointers/out_of_bounds_read1.rs diff --git a/tests/compile-fail/out_of_bounds_read2.rs b/tests/compile-fail/dangling_pointers/out_of_bounds_read2.rs similarity index 100% rename from tests/compile-fail/out_of_bounds_read2.rs rename to tests/compile-fail/dangling_pointers/out_of_bounds_read2.rs diff --git a/tests/compile-fail/wild_pointer_deref.rs b/tests/compile-fail/dangling_pointers/wild_pointer_deref.rs similarity index 100% rename from tests/compile-fail/wild_pointer_deref.rs rename to tests/compile-fail/dangling_pointers/wild_pointer_deref.rs diff --git a/tests/compile-fail/cast_box_int_to_fn_ptr.rs b/tests/compile-fail/function_pointers/cast_box_int_to_fn_ptr.rs similarity index 100% rename from tests/compile-fail/cast_box_int_to_fn_ptr.rs rename to tests/compile-fail/function_pointers/cast_box_int_to_fn_ptr.rs diff --git a/tests/compile-fail/cast_fn_ptr1.rs b/tests/compile-fail/function_pointers/cast_fn_ptr1.rs similarity index 100% rename from tests/compile-fail/cast_fn_ptr1.rs rename to tests/compile-fail/function_pointers/cast_fn_ptr1.rs diff --git a/tests/compile-fail/cast_fn_ptr2.rs b/tests/compile-fail/function_pointers/cast_fn_ptr2.rs similarity index 100% rename from tests/compile-fail/cast_fn_ptr2.rs rename to tests/compile-fail/function_pointers/cast_fn_ptr2.rs diff --git a/tests/compile-fail/cast_fn_ptr3.rs b/tests/compile-fail/function_pointers/cast_fn_ptr3.rs similarity index 100% rename from tests/compile-fail/cast_fn_ptr3.rs rename to tests/compile-fail/function_pointers/cast_fn_ptr3.rs diff --git a/tests/compile-fail/cast_fn_ptr4.rs b/tests/compile-fail/function_pointers/cast_fn_ptr4.rs similarity index 100% rename from tests/compile-fail/cast_fn_ptr4.rs rename to tests/compile-fail/function_pointers/cast_fn_ptr4.rs diff --git a/tests/compile-fail/cast_fn_ptr5.rs b/tests/compile-fail/function_pointers/cast_fn_ptr5.rs similarity index 100% rename from tests/compile-fail/cast_fn_ptr5.rs rename to tests/compile-fail/function_pointers/cast_fn_ptr5.rs diff --git a/tests/compile-fail/cast_int_to_fn_ptr.rs b/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs similarity index 100% rename from tests/compile-fail/cast_int_to_fn_ptr.rs rename to tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs diff --git a/tests/compile-fail/deref_fn_ptr.rs b/tests/compile-fail/function_pointers/deref_fn_ptr.rs similarity index 100% rename from tests/compile-fail/deref_fn_ptr.rs rename to tests/compile-fail/function_pointers/deref_fn_ptr.rs diff --git a/tests/compile-fail/execute_memory.rs b/tests/compile-fail/function_pointers/execute_memory.rs similarity index 100% rename from tests/compile-fail/execute_memory.rs rename to tests/compile-fail/function_pointers/execute_memory.rs diff --git a/tests/compile-fail/fn_ptr_offset.rs b/tests/compile-fail/function_pointers/fn_ptr_offset.rs similarity index 100% rename from tests/compile-fail/fn_ptr_offset.rs rename to tests/compile-fail/function_pointers/fn_ptr_offset.rs diff --git a/tests/compile-fail/assume.rs b/tests/compile-fail/intrinsics/assume.rs similarity index 100% rename from tests/compile-fail/assume.rs rename to tests/compile-fail/intrinsics/assume.rs diff --git a/tests/compile-fail/copy_null.rs b/tests/compile-fail/intrinsics/copy_null.rs similarity index 100% rename from tests/compile-fail/copy_null.rs rename to tests/compile-fail/intrinsics/copy_null.rs diff --git a/tests/compile-fail/copy_overflow.rs b/tests/compile-fail/intrinsics/copy_overflow.rs similarity index 100% rename from tests/compile-fail/copy_overflow.rs rename to tests/compile-fail/intrinsics/copy_overflow.rs diff --git a/tests/compile-fail/copy_overlapping.rs b/tests/compile-fail/intrinsics/copy_overlapping.rs similarity index 100% rename from tests/compile-fail/copy_overlapping.rs rename to tests/compile-fail/intrinsics/copy_overlapping.rs diff --git a/tests/compile-fail/copy_unaligned.rs b/tests/compile-fail/intrinsics/copy_unaligned.rs similarity index 100% rename from tests/compile-fail/copy_unaligned.rs rename to tests/compile-fail/intrinsics/copy_unaligned.rs diff --git a/tests/compile-fail/ctlz_nonzero.rs b/tests/compile-fail/intrinsics/ctlz_nonzero.rs similarity index 100% rename from tests/compile-fail/ctlz_nonzero.rs rename to tests/compile-fail/intrinsics/ctlz_nonzero.rs diff --git a/tests/compile-fail/cttz_nonzero.rs b/tests/compile-fail/intrinsics/cttz_nonzero.rs similarity index 100% rename from tests/compile-fail/cttz_nonzero.rs rename to tests/compile-fail/intrinsics/cttz_nonzero.rs diff --git a/tests/compile-fail/div-by-zero-1.rs b/tests/compile-fail/intrinsics/div-by-zero-1.rs similarity index 100% rename from tests/compile-fail/div-by-zero-1.rs rename to tests/compile-fail/intrinsics/div-by-zero-1.rs diff --git a/tests/compile-fail/div-by-zero-2.rs b/tests/compile-fail/intrinsics/div-by-zero-2.rs similarity index 100% rename from tests/compile-fail/div-by-zero-2.rs rename to tests/compile-fail/intrinsics/div-by-zero-2.rs diff --git a/tests/compile-fail/exact_div1.rs b/tests/compile-fail/intrinsics/exact_div1.rs similarity index 100% rename from tests/compile-fail/exact_div1.rs rename to tests/compile-fail/intrinsics/exact_div1.rs diff --git a/tests/compile-fail/exact_div2.rs b/tests/compile-fail/intrinsics/exact_div2.rs similarity index 100% rename from tests/compile-fail/exact_div2.rs rename to tests/compile-fail/intrinsics/exact_div2.rs diff --git a/tests/compile-fail/exact_div3.rs b/tests/compile-fail/intrinsics/exact_div3.rs similarity index 100% rename from tests/compile-fail/exact_div3.rs rename to tests/compile-fail/intrinsics/exact_div3.rs diff --git a/tests/compile-fail/exact_div4.rs b/tests/compile-fail/intrinsics/exact_div4.rs similarity index 100% rename from tests/compile-fail/exact_div4.rs rename to tests/compile-fail/intrinsics/exact_div4.rs diff --git a/tests/compile-fail/out_of_bounds_ptr_1.rs b/tests/compile-fail/intrinsics/out_of_bounds_ptr_1.rs similarity index 100% rename from tests/compile-fail/out_of_bounds_ptr_1.rs rename to tests/compile-fail/intrinsics/out_of_bounds_ptr_1.rs diff --git a/tests/compile-fail/out_of_bounds_ptr_2.rs b/tests/compile-fail/intrinsics/out_of_bounds_ptr_2.rs similarity index 100% rename from tests/compile-fail/out_of_bounds_ptr_2.rs rename to tests/compile-fail/intrinsics/out_of_bounds_ptr_2.rs diff --git a/tests/compile-fail/overflowing-unchecked-rsh.rs b/tests/compile-fail/intrinsics/overflowing-unchecked-rsh.rs similarity index 100% rename from tests/compile-fail/overflowing-unchecked-rsh.rs rename to tests/compile-fail/intrinsics/overflowing-unchecked-rsh.rs diff --git a/tests/compile-fail/ptr_offset_0_plus_0.rs b/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs similarity index 100% rename from tests/compile-fail/ptr_offset_0_plus_0.rs rename to tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs diff --git a/tests/compile-fail/ptr_offset_int_plus_int.rs b/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs similarity index 100% rename from tests/compile-fail/ptr_offset_int_plus_int.rs rename to tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs diff --git a/tests/compile-fail/ptr_offset_int_plus_ptr.rs b/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs similarity index 100% rename from tests/compile-fail/ptr_offset_int_plus_ptr.rs rename to tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs diff --git a/tests/compile-fail/ptr_offset_overflow.rs b/tests/compile-fail/intrinsics/ptr_offset_overflow.rs similarity index 100% rename from tests/compile-fail/ptr_offset_overflow.rs rename to tests/compile-fail/intrinsics/ptr_offset_overflow.rs diff --git a/tests/compile-fail/ptr_offset_ptr_plus_0.rs b/tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.rs similarity index 100% rename from tests/compile-fail/ptr_offset_ptr_plus_0.rs rename to tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.rs diff --git a/tests/compile-fail/unchecked_add1.rs b/tests/compile-fail/intrinsics/unchecked_add1.rs similarity index 100% rename from tests/compile-fail/unchecked_add1.rs rename to tests/compile-fail/intrinsics/unchecked_add1.rs diff --git a/tests/compile-fail/unchecked_add2.rs b/tests/compile-fail/intrinsics/unchecked_add2.rs similarity index 100% rename from tests/compile-fail/unchecked_add2.rs rename to tests/compile-fail/intrinsics/unchecked_add2.rs diff --git a/tests/compile-fail/unchecked_div1.rs b/tests/compile-fail/intrinsics/unchecked_div1.rs similarity index 100% rename from tests/compile-fail/unchecked_div1.rs rename to tests/compile-fail/intrinsics/unchecked_div1.rs diff --git a/tests/compile-fail/unchecked_mul1.rs b/tests/compile-fail/intrinsics/unchecked_mul1.rs similarity index 100% rename from tests/compile-fail/unchecked_mul1.rs rename to tests/compile-fail/intrinsics/unchecked_mul1.rs diff --git a/tests/compile-fail/unchecked_mul2.rs b/tests/compile-fail/intrinsics/unchecked_mul2.rs similarity index 100% rename from tests/compile-fail/unchecked_mul2.rs rename to tests/compile-fail/intrinsics/unchecked_mul2.rs diff --git a/tests/compile-fail/unchecked_sub1.rs b/tests/compile-fail/intrinsics/unchecked_sub1.rs similarity index 100% rename from tests/compile-fail/unchecked_sub1.rs rename to tests/compile-fail/intrinsics/unchecked_sub1.rs diff --git a/tests/compile-fail/unchecked_sub2.rs b/tests/compile-fail/intrinsics/unchecked_sub2.rs similarity index 100% rename from tests/compile-fail/unchecked_sub2.rs rename to tests/compile-fail/intrinsics/unchecked_sub2.rs diff --git a/tests/compile-fail/write_bytes_null.rs b/tests/compile-fail/intrinsics/write_bytes_null.rs similarity index 100% rename from tests/compile-fail/write_bytes_null.rs rename to tests/compile-fail/intrinsics/write_bytes_null.rs diff --git a/tests/compile-fail/write_bytes_overflow.rs b/tests/compile-fail/intrinsics/write_bytes_overflow.rs similarity index 100% rename from tests/compile-fail/write_bytes_overflow.rs rename to tests/compile-fail/intrinsics/write_bytes_overflow.rs diff --git a/tests/compile-fail/libc_pthread_mutex_destroy_locked.rs b/tests/compile-fail/sync/libc_pthread_mutex_destroy_locked.rs similarity index 100% rename from tests/compile-fail/libc_pthread_mutex_destroy_locked.rs rename to tests/compile-fail/sync/libc_pthread_mutex_destroy_locked.rs diff --git a/tests/compile-fail/libc_pthread_mutex_normal_deadlock.rs b/tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.rs similarity index 100% rename from tests/compile-fail/libc_pthread_mutex_normal_deadlock.rs rename to tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.rs diff --git a/tests/compile-fail/libc_pthread_mutex_normal_unlock_unlocked.rs b/tests/compile-fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs similarity index 100% rename from tests/compile-fail/libc_pthread_mutex_normal_unlock_unlocked.rs rename to tests/compile-fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs diff --git a/tests/compile-fail/libc_pthread_rwlock_destroy_read_locked.rs b/tests/compile-fail/sync/libc_pthread_rwlock_destroy_read_locked.rs similarity index 100% rename from tests/compile-fail/libc_pthread_rwlock_destroy_read_locked.rs rename to tests/compile-fail/sync/libc_pthread_rwlock_destroy_read_locked.rs diff --git a/tests/compile-fail/libc_pthread_rwlock_destroy_write_locked.rs b/tests/compile-fail/sync/libc_pthread_rwlock_destroy_write_locked.rs similarity index 100% rename from tests/compile-fail/libc_pthread_rwlock_destroy_write_locked.rs rename to tests/compile-fail/sync/libc_pthread_rwlock_destroy_write_locked.rs diff --git a/tests/compile-fail/libc_pthread_rwlock_read_write_deadlock.rs b/tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock.rs similarity index 100% rename from tests/compile-fail/libc_pthread_rwlock_read_write_deadlock.rs rename to tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock.rs diff --git a/tests/compile-fail/libc_pthread_rwlock_unlock_unlocked.rs b/tests/compile-fail/sync/libc_pthread_rwlock_unlock_unlocked.rs similarity index 100% rename from tests/compile-fail/libc_pthread_rwlock_unlock_unlocked.rs rename to tests/compile-fail/sync/libc_pthread_rwlock_unlock_unlocked.rs diff --git a/tests/compile-fail/libc_pthread_rwlock_write_read_deadlock.rs b/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock.rs similarity index 100% rename from tests/compile-fail/libc_pthread_rwlock_write_read_deadlock.rs rename to tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock.rs diff --git a/tests/compile-fail/libc_pthread_rwlock_write_write_deadlock.rs b/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock.rs similarity index 100% rename from tests/compile-fail/libc_pthread_rwlock_write_write_deadlock.rs rename to tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock.rs diff --git a/tests/compile-fail/alignment.rs b/tests/compile-fail/unaligned_pointers/alignment.rs similarity index 100% rename from tests/compile-fail/alignment.rs rename to tests/compile-fail/unaligned_pointers/alignment.rs diff --git a/tests/compile-fail/atomic_unaligned.rs b/tests/compile-fail/unaligned_pointers/atomic_unaligned.rs similarity index 100% rename from tests/compile-fail/atomic_unaligned.rs rename to tests/compile-fail/unaligned_pointers/atomic_unaligned.rs diff --git a/tests/compile-fail/intptrcast_alignment_check.rs b/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs similarity index 100% rename from tests/compile-fail/intptrcast_alignment_check.rs rename to tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs diff --git a/tests/compile-fail/reference_to_packed.rs b/tests/compile-fail/unaligned_pointers/reference_to_packed.rs similarity index 100% rename from tests/compile-fail/reference_to_packed.rs rename to tests/compile-fail/unaligned_pointers/reference_to_packed.rs diff --git a/tests/compile-fail/unaligned_ptr1.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs similarity index 100% rename from tests/compile-fail/unaligned_ptr1.rs rename to tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs diff --git a/tests/compile-fail/unaligned_ptr2.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs similarity index 100% rename from tests/compile-fail/unaligned_ptr2.rs rename to tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs diff --git a/tests/compile-fail/unaligned_ptr3.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs similarity index 100% rename from tests/compile-fail/unaligned_ptr3.rs rename to tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs diff --git a/tests/compile-fail/unaligned_ptr_zst.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs similarity index 100% rename from tests/compile-fail/unaligned_ptr_zst.rs rename to tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs From c63c413331a14e58eb95f13494eea8d1bafa19b9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 Apr 2020 09:32:34 +0200 Subject: [PATCH 1841/5092] a few more inf/nan/negz tests --- tests/run-pass/float.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index 5acaf6a2a97c..e7b59683d697 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -18,9 +18,22 @@ fn main() { assert_eq(-{5.0_f64}, -5.0_f64); // infinities, NaN assert!((5.0_f32/0.0).is_infinite()); + assert_ne!({5.0_f32/0.0}, {-5.0_f32/0.0}); assert!((5.0_f64/0.0).is_infinite()); + assert_ne!({5.0_f64/0.0}, {5.0_f64/-0.0}); assert!((-5.0_f32).sqrt().is_nan()); assert!((-5.0_f64).sqrt().is_nan()); + assert_ne!(f32::NAN, f32::NAN); + assert_ne!(f64::NAN, f64::NAN); + // negative zero + let posz = 0.0f32; + let negz = -0.0f32; + assert_eq(posz, negz); + assert_ne!(posz.to_bits(), negz.to_bits()); + let posz = 0.0f64; + let negz = -0.0f64; + assert_eq(posz, negz); + assert_ne!(posz.to_bits(), negz.to_bits()); // byte-level transmute let x: u64 = unsafe { std::mem::transmute(42.0_f64) }; let y: f64 = unsafe { std::mem::transmute(x) }; From 5db01f7371ec40cd210979f29242f8c80ea2ef15 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 Apr 2020 10:30:55 +0200 Subject: [PATCH 1842/5092] copy lots of float-to-int cast tests from wasm test suite --- tests/run-pass/float.rs | 159 +++++++++++++++++++++++++++++++--------- 1 file changed, 123 insertions(+), 36 deletions(-) diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index e7b59683d697..7eab7f1ed524 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -11,6 +11,12 @@ fn assert_eq(x: T, y: T) { } fn main() { + basic(); + casts(); + ops(); +} + +fn basic() { // basic arithmetic assert_eq(6.0_f32*6.0_f32, 36.0_f32); assert_eq(6.0_f64*6.0_f64, 36.0_f64); @@ -41,57 +47,138 @@ fn main() { let x: u32 = unsafe { std::mem::transmute(42.0_f32) }; let y: f32 = unsafe { std::mem::transmute(x) }; assert_eq(y, 42.0_f32); +} - // f32 <-> int casts - assert_eq(5.0f32 as u32, 5); - assert_eq(-5.0f32 as u32, 0); - assert_eq(5.0f32 as i32, 5); - assert_eq(-5.0f32 as i32, -5); - assert_eq(f32::MAX as i32, i32::MAX); - assert_eq(f32::INFINITY as i32, i32::MAX); - assert_eq(f32::MAX as u32, u32::MAX); - assert_eq(f32::INFINITY as u32, u32::MAX); - assert_eq(f32::MIN as i32, i32::MIN); - assert_eq(f32::NEG_INFINITY as i32, i32::MIN); - assert_eq(f32::MIN as u32, 0); - assert_eq(f32::NEG_INFINITY as u32, 0); - assert_eq(f32::NAN as i32, 0); - assert_eq(f32::NAN as u32, 0); - assert_eq((u32::MAX-127) as f32 as u32, u32::MAX); // rounding loss - assert_eq((u32::MAX-128) as f32 as u32, u32::MAX-255); // rounding loss +fn casts() { + // f32 -> i32 + assert_eq::(0.0f32 as i32, 0); + assert_eq::(-0.0f32 as i32, 0); + assert_eq::(/*0x1p-149*/ f32::from_bits(0x00000001) as i32, 0); + assert_eq::(/*-0x1p-149*/ f32::from_bits(0x80000001) as i32, 0); + assert_eq::(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd) as i32, 1); + assert_eq::(/*-0x1.19999ap+0*/ f32::from_bits(0xbf8ccccd) as i32, -1); + assert_eq::(1.9f32 as i32, 1); + assert_eq::(-1.9f32 as i32, -1); + assert_eq::(5.0f32 as i32, 5); + assert_eq::(-5.0f32 as i32, -5); + assert_eq::(2147483520.0f32 as i32, 2147483520); + assert_eq::(-2147483648.0f32 as i32, -2147483648); + // unrepresentable casts + assert_eq::(2147483648.0f32 as i32, i32::MAX); + assert_eq::(-2147483904.0f32 as i32, i32::MIN); + assert_eq::(f32::MAX as i32, i32::MAX); + assert_eq::(f32::MIN as i32, i32::MIN); + assert_eq::(f32::INFINITY as i32, i32::MAX); + assert_eq::(f32::NEG_INFINITY as i32, i32::MIN); + assert_eq::(f32::NAN as i32, 0); + assert_eq::((-f32::NAN) as i32, 0); + + // f32 -> u32 + assert_eq::(0.0f32 as u32, 0); + assert_eq::(-0.0f32 as u32, 0); + assert_eq::(/*0x1p-149*/ f32::from_bits(0x00000001) as u32, 0); + assert_eq::(/*-0x1p-149*/ f32::from_bits(0x80000001) as u32, 0); + assert_eq::(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd) as u32, 1); + assert_eq::(1.9f32 as u32, 1); + assert_eq::(5.0f32 as u32, 5); + assert_eq::(2147483648.0f32 as u32, 0x8000_0000); + assert_eq::(4294967040.0f32 as u32, 0u32.wrapping_sub(256)); + assert_eq::(/*-0x1.ccccccp-1*/ f32::from_bits(0xbf666666) as u32, 0); + assert_eq::(/*-0x1.fffffep-1*/ f32::from_bits(0xbf7fffff) as u32, 0); + assert_eq::((u32::MAX-127) as f32 as u32, u32::MAX); // rounding loss + assert_eq::((u32::MAX-128) as f32 as u32, u32::MAX-255); // rounding loss + // unrepresentable casts + assert_eq::(4294967296.0f32 as u32, u32::MAX); + assert_eq::(-5.0f32 as u32, 0); + assert_eq::(f32::MAX as u32, u32::MAX); + assert_eq::(f32::MIN as u32, 0); + assert_eq::(f32::INFINITY as u32, u32::MAX); + assert_eq::(f32::NEG_INFINITY as u32, 0); + assert_eq::(f32::NAN as u32, 0); + assert_eq::((-f32::NAN) as u32, 0); + + // f32 -> i64 + assert_eq::(4294967296.0f32 as i64, 4294967296); + assert_eq::(-4294967296.0f32 as i64, -4294967296); + assert_eq::(9223371487098961920.0f32 as i64, 9223371487098961920); + assert_eq::(-9223372036854775808.0f32 as i64, -9223372036854775808); + + // f64 -> i32 + assert_eq::(0.0f64 as i32, 0); + assert_eq::(-0.0f64 as i32, 0); + assert_eq::(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a) as i32, 1); + assert_eq::(/*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a) as i32, -1); + assert_eq::(1.9f64 as i32, 1); + assert_eq::(-1.9f64 as i32, -1); + assert_eq::(1e8f64 as i32, 100_000_000); + assert_eq::(2147483647.0f64 as i32, 2147483647); + assert_eq::(-2147483648.0f64 as i32, -2147483648); + // unrepresentable casts + assert_eq::(2147483648.0f64 as i32, i32::MAX); + assert_eq::(-2147483649.0f64 as i32, i32::MIN); + + // f64 -> i64 + assert_eq::(0.0f64 as i64, 0); + assert_eq::(-0.0f64 as i64, 0); + assert_eq::(/*0x0.0000000000001p-1022*/ f64::from_bits(0x1) as i64, 0); + assert_eq::(/*-0x0.0000000000001p-1022*/ f64::from_bits(0x8000000000000001) as i64, 0); + assert_eq::(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a) as i64, 1); + assert_eq::(/*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a) as i64, -1); + assert_eq::(5.0f64 as i64, 5); + assert_eq::(5.9f64 as i64, 5); + assert_eq::(-5.0f64 as i64, -5); + assert_eq::(-5.9f64 as i64, -5); + assert_eq::(4294967296.0f64 as i64, 4294967296); + assert_eq::(-4294967296.0f64 as i64, -4294967296); + assert_eq::(9223372036854774784.0f64 as i64, 9223372036854774784); + assert_eq::(-9223372036854775808.0f64 as i64, -9223372036854775808); + // unrepresentable casts + assert_eq::(9223372036854775808.0f64 as i64, i64::MAX); + assert_eq::(-9223372036854777856.0f64 as i64, i64::MIN); + assert_eq::(f64::MAX as i64, i64::MAX); + assert_eq::(f64::MIN as i64, i64::MIN); + assert_eq::(f64::INFINITY as i64, i64::MAX); + assert_eq::(f64::NEG_INFINITY as i64, i64::MIN); + assert_eq::(f64::NAN as i64, 0); + assert_eq::((-f64::NAN) as i64, 0); + + // f64 -> u64 + assert_eq::(0.0f64 as u64, 0); + assert_eq::(-0.0f64 as u64, 0); + assert_eq::(5.0f64 as u64, 5); + assert_eq::(-5.0f64 as u64, 0); + assert_eq::(1e16f64 as u64, 10000000000000000); + assert_eq::((u64::MAX-1023) as f64 as u64, u64::MAX); // rounding loss + assert_eq::((u64::MAX-1024) as f64 as u64, u64::MAX-2047); // rounding loss + assert_eq::(9223372036854775808.0f64 as u64, 9223372036854775808); + // unrepresentable casts + assert_eq::(18446744073709551616.0f64 as u64, u64::MAX); + assert_eq::(f64::MAX as u64, u64::MAX); + assert_eq::(f64::MIN as u64, 0); + assert_eq::(f64::INFINITY as u64, u64::MAX); + assert_eq::(f64::NEG_INFINITY as u64, 0); + assert_eq::(f64::NAN as u64, 0); + assert_eq::((-f64::NAN) as u64, 0); + + // int -> f32 assert_eq(127i8 as f32, 127.0f32); assert_eq(i128::MIN as f32, -170141183460469231731687303715884105728.0f32); assert_eq(u128::MAX as f32, f32::INFINITY); // saturation - // f64 <-> int casts - assert_eq(5.0f64 as u64, 5); - assert_eq(-5.0f64 as u64, 0); - assert_eq(5.0f64 as i64, 5); - assert_eq(-5.0f64 as i64, -5); - assert_eq(f64::MAX as i64, i64::MAX); - assert_eq(f64::INFINITY as i64, i64::MAX); - assert_eq(f64::MAX as u64, u64::MAX); - assert_eq(f64::INFINITY as u64, u64::MAX); - assert_eq(f64::MIN as i64, i64::MIN); - assert_eq(f64::NEG_INFINITY as i64, i64::MIN); - assert_eq(f64::MIN as u64, 0); - assert_eq(f64::NEG_INFINITY as u64, 0); - assert_eq(f64::NAN as i64, 0); - assert_eq(f64::NAN as u64, 0); - assert_eq((u64::MAX-1023) as f64 as u64, u64::MAX); // rounding loss - assert_eq((u64::MAX-1024) as f64 as u64, u64::MAX-2047); // rounding loss - assert_eq(u128::MAX as f64 as u128, u128::MAX); + // int -> f64 assert_eq(i16::MIN as f64, -32768.0f64); assert_eq(u128::MAX as f64, 340282366920938463463374607431768211455.0f64); // even that fits... - // f32 <-> f64 casts + // f32 <-> f64 assert_eq(5.0f64 as f32, 5.0f32); assert_eq(5.0f32 as f64, 5.0f64); assert_eq(f64::MAX as f32, f32::INFINITY); assert_eq(f64::MIN as f32, f32::NEG_INFINITY); assert_eq(f32::INFINITY as f64, f64::INFINITY); assert_eq(f32::NEG_INFINITY as f64, f64::NEG_INFINITY); +} +fn ops() { // f32 min/max assert_eq((1.0 as f32).max(-1.0), 1.0); assert_eq((1.0 as f32).min(-1.0), -1.0); From faff175f3e0095d5ddabb83f290309ed0dcfcf44 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 Apr 2020 11:00:38 +0200 Subject: [PATCH 1843/5092] some some int-to-float and float-to-float cast tests from wasm test suite --- tests/run-pass/float.rs | 68 +++++++++++++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 13 deletions(-) diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index 7eab7f1ed524..738df2f6c59e 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -76,7 +76,7 @@ fn casts() { // f32 -> u32 assert_eq::(0.0f32 as u32, 0); assert_eq::(-0.0f32 as u32, 0); - assert_eq::(/*0x1p-149*/ f32::from_bits(0x00000001) as u32, 0); + assert_eq::(/*0x1p-149*/ f32::from_bits(0x1) as u32, 0); assert_eq::(/*-0x1p-149*/ f32::from_bits(0x80000001) as u32, 0); assert_eq::(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd) as u32, 1); assert_eq::(1.9f32 as u32, 1); @@ -161,21 +161,63 @@ fn casts() { assert_eq::((-f64::NAN) as u64, 0); // int -> f32 - assert_eq(127i8 as f32, 127.0f32); - assert_eq(i128::MIN as f32, -170141183460469231731687303715884105728.0f32); - assert_eq(u128::MAX as f32, f32::INFINITY); // saturation + assert_eq::(127i8 as f32, 127.0); + assert_eq::(2147483647i32 as f32, 2147483648.0); + assert_eq::((-2147483648i32) as f32, -2147483648.0); + assert_eq::(1234567890i32 as f32, /*0x1.26580cp+30*/ f32::from_bits(0x4e932c06)); + assert_eq::(16777217i32 as f32, 16777216.0); + assert_eq::((-16777217i32) as f32, -16777216.0); + assert_eq::(16777219i32 as f32, 16777220.0); + assert_eq::((-16777219i32) as f32, -16777220.0); + assert_eq::(0x7fffff4000000001i64 as f32, /*0x1.fffffep+62*/ f32::from_bits(0x5effffff)); + assert_eq::(0x8000004000000001u64 as i64 as f32, /*-0x1.fffffep+62*/ f32::from_bits(0xdeffffff)); + assert_eq::(0x0020000020000001i64 as f32, /*0x1.000002p+53*/ f32::from_bits(0x5a000001)); + assert_eq::(0xffdfffffdfffffffu64 as i64 as f32, /*-0x1.000002p+53*/ f32::from_bits(0xda000001)); + assert_eq::(i128::MIN as f32, -170141183460469231731687303715884105728.0f32); + assert_eq::(u128::MAX as f32, f32::INFINITY); // saturation // int -> f64 - assert_eq(i16::MIN as f64, -32768.0f64); - assert_eq(u128::MAX as f64, 340282366920938463463374607431768211455.0f64); // even that fits... + assert_eq::(127i8 as f64, 127.0); + assert_eq::(i16::MIN as f64, -32768.0f64); + assert_eq::(2147483647i32 as f64, 2147483647.0); + assert_eq::(-2147483648i32 as f64, -2147483648.0); + assert_eq::(987654321i32 as f64, 987654321.0); + assert_eq::(9223372036854775807i64 as f64, 9223372036854775807.0); + assert_eq::(-9223372036854775808i64 as f64, -9223372036854775808.0); + assert_eq::(4669201609102990i64 as f64, 4669201609102990.0); // Feigenbaum (?) + assert_eq::(9007199254740993i64 as f64, 9007199254740992.0); + assert_eq::(-9007199254740993i64 as f64, -9007199254740992.0); + assert_eq::(9007199254740995i64 as f64, 9007199254740996.0); + assert_eq::(-9007199254740995i64 as f64, -9007199254740996.0); + assert_eq::(u128::MAX as f64, 340282366920938463463374607431768211455.0f64); // even that fits... - // f32 <-> f64 - assert_eq(5.0f64 as f32, 5.0f32); - assert_eq(5.0f32 as f64, 5.0f64); - assert_eq(f64::MAX as f32, f32::INFINITY); - assert_eq(f64::MIN as f32, f32::NEG_INFINITY); - assert_eq(f32::INFINITY as f64, f64::INFINITY); - assert_eq(f32::NEG_INFINITY as f64, f64::NEG_INFINITY); + // f32 -> f64 + assert_eq::((0.0f32 as f64).to_bits(), 0.0f64.to_bits()); + assert_eq::(((-0.0f32) as f64).to_bits(), (-0.0f64).to_bits()); + assert_eq::(5.0f32 as f64, 5.0f64); + assert_eq::(/*0x1p-149*/ f32::from_bits(0x1) as f64, /*0x1p-149*/ f64::from_bits(0x36a0000000000000)); + assert_eq::(/*-0x1p-149*/ f32::from_bits(0x80000001) as f64, /*-0x1p-149*/ f64::from_bits(0xb6a0000000000000)); + assert_eq::(/*0x1.fffffep+127*/ f32::from_bits(0x7f7fffff) as f64, /*0x1.fffffep+127*/ f64::from_bits(0x47efffffe0000000)); + assert_eq::(/*-0x1.fffffep+127*/ (-f32::from_bits(0x7f7fffff)) as f64, /*-0x1.fffffep+127*/ -f64::from_bits(0x47efffffe0000000)); + assert_eq::(/*0x1p-119*/ f32::from_bits(0x4000000) as f64, /*0x1p-119*/ f64::from_bits(0x3880000000000000)); + assert_eq::(/*0x1.8f867ep+125*/ f32::from_bits(0x7e47c33f) as f64, 6.6382536710104395e+37); + assert_eq::(f32::INFINITY as f64, f64::INFINITY); + assert_eq::(f32::NEG_INFINITY as f64, f64::NEG_INFINITY); + + // f64 -> f32 + assert_eq::((0.0f64 as f32).to_bits(), 0.0f32.to_bits()); + assert_eq::(((-0.0f64) as f32).to_bits(), (-0.0f32).to_bits()); + assert_eq::(5.0f64 as f32, 5.0f32); + assert_eq::(/*0x0.0000000000001p-1022*/ f64::from_bits(0x1) as f32, 0.0); + assert_eq::(/*-0x0.0000000000001p-1022*/ (-f64::from_bits(0x1)) as f32, -0.0); + + assert_eq::(/*0x1.fffffe0000000p-127*/ f64::from_bits(0x380fffffe0000000) as f32, /*0x1p-149*/ f32::from_bits(0x800000)); + assert_eq::(/*0x1.4eae4f7024c7p+108*/ f64::from_bits(0x46b4eae4f7024c70) as f32, /*0x1.4eae5p+108*/ f32::from_bits(0x75a75728)); + + assert_eq::(f64::MAX as f32, f32::INFINITY); + assert_eq::(f64::MIN as f32, f32::NEG_INFINITY); + assert_eq::(f64::INFINITY as f32, f32::INFINITY); + assert_eq::(f64::NEG_INFINITY as f32, f32::NEG_INFINITY); } fn ops() { From e5e0ced87e04ee866b5064978b2d88115e03ffa3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 Apr 2020 11:03:41 +0200 Subject: [PATCH 1844/5092] smoketest f32 fast-math intrinsics --- tests/run-pass/float_fast_math.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/tests/run-pass/float_fast_math.rs b/tests/run-pass/float_fast_math.rs index ba7e6ac3ec06..8e5a88ff336a 100644 --- a/tests/run-pass/float_fast_math.rs +++ b/tests/run-pass/float_fast_math.rs @@ -3,7 +3,19 @@ use std::intrinsics::{fadd_fast, fsub_fast, fmul_fast, fdiv_fast, frem_fast}; #[inline(never)] -pub fn test_operations(a: f64, b: f64) { +pub fn test_operations_f64(a: f64, b: f64) { + // make sure they all map to the correct operation + unsafe { + assert_eq!(fadd_fast(a, b), a + b); + assert_eq!(fsub_fast(a, b), a - b); + assert_eq!(fmul_fast(a, b), a * b); + assert_eq!(fdiv_fast(a, b), a / b); + assert_eq!(frem_fast(a, b), a % b); + } +} + +#[inline(never)] +pub fn test_operations_f32(a: f32, b: f32) { // make sure they all map to the correct operation unsafe { assert_eq!(fadd_fast(a, b), a + b); @@ -15,6 +27,8 @@ pub fn test_operations(a: f64, b: f64) { } fn main() { - test_operations(1., 2.); - test_operations(10., 5.); + test_operations_f64(1., 2.); + test_operations_f64(10., 5.); + test_operations_f32(11., 2.); + test_operations_f32(10., 15.); } From 97791a56da50a87a3d1c3e4290290d436f9931f7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 12 Apr 2020 10:08:12 +0200 Subject: [PATCH 1845/5092] avoid ref in matches --- src/bin/cargo-miri.rs | 12 ++++++------ src/diagnostics.rs | 4 ++-- src/machine.rs | 6 +++--- src/mono_hash_map.rs | 2 +- src/shims/panic.rs | 2 +- src/shims/tls.rs | 6 +++--- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 083918de0f3a..dfb5a5a98912 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -115,7 +115,7 @@ fn list_targets() -> impl Iterator { get_arg_flag_value("--manifest-path").map(|m| Path::new(&m).canonicalize().unwrap()); let mut cmd = cargo_metadata::MetadataCommand::new(); - if let Some(ref manifest_path) = manifest_path { + if let Some(manifest_path) = manifest_path.as_ref() { cmd.manifest_path(manifest_path); } let mut metadata = if let Ok(metadata) = cmd.exec() { @@ -131,7 +131,7 @@ fn list_targets() -> impl Iterator { .iter() .position(|package| { let package_manifest_path = Path::new(&package.manifest_path); - if let Some(ref manifest_path) = manifest_path { + if let Some(manifest_path) = manifest_path.as_ref() { package_manifest_path == manifest_path } else { let current_dir = current_dir.as_ref().expect("could not read current directory"); @@ -368,7 +368,7 @@ path = "lib.rs" command.env("XARGO_HOME", &dir); command.env("XARGO_RUST_SRC", &rust_src); // Handle target flag. - if let Some(ref target) = target { + if let Some(target) = target.as_ref() { command.arg("--target").arg(&target); } // Finally run it! @@ -379,9 +379,9 @@ path = "lib.rs" // That should be it! But we need to figure out where xargo built stuff. // Unfortunately, it puts things into a different directory when the // architecture matches the host. - let is_host = match target { + let is_host = match target.as_ref() { None => true, - Some(target) => target == rustc_version::version_meta().unwrap().host, + Some(target) => target == &rustc_version::version_meta().unwrap().host, }; let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; std::env::set_var("MIRI_SYSROOT", &sysroot); // pass the env var to the processes we spawn, which will turn it into "--sysroot" flags @@ -583,6 +583,6 @@ fn inside_cargo_rustc() { if !exit.success() { std::process::exit(exit.code().unwrap_or(42)); }, - Err(ref e) => panic!("error running {:?}:\n{:?}", command, e), + Err(e) => panic!("error running {:?}:\n{:?}", command, e), } } diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 24e68934c66f..90e532321e40 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -51,8 +51,8 @@ pub fn report_error<'tcx, 'mir>( ) -> Option { use InterpError::*; - let (title, helps) = match e.kind { - MachineStop(ref info) => { + let (title, helps) = match &e.kind { + MachineStop(info) => { let info = info.downcast_ref::().expect("invalid MachineStop payload"); use TerminationInfo::*; let title = match info { diff --git a/src/machine.rs b/src/machine.rs index 3c5983730506..612f1bb328cc 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -518,7 +518,7 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - if let Some(ref stacked_borrows) = alloc.extra.stacked_borrows { + if let Some(stacked_borrows) = alloc.extra.stacked_borrows.as_ref() { stacked_borrows.memory_read(ptr, size) } else { Ok(()) @@ -531,7 +531,7 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - if let Some(ref mut stacked_borrows) = alloc.extra.stacked_borrows { + if let Some(stacked_borrows) = alloc.extra.stacked_borrows.as_mut() { stacked_borrows.memory_written(ptr, size) } else { Ok(()) @@ -544,7 +544,7 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - if let Some(ref mut stacked_borrows) = alloc.extra.stacked_borrows { + if let Some(stacked_borrows) = alloc.extra.stacked_borrows.as_mut() { stacked_borrows.memory_deallocated(ptr, size) } else { Ok(()) diff --git a/src/mono_hash_map.rs b/src/mono_hash_map.rs index fc33126aa2e7..fb0169920ee2 100644 --- a/src/mono_hash_map.rs +++ b/src/mono_hash_map.rs @@ -64,7 +64,7 @@ impl AllocMap for MonoHashMap { self.0.borrow().iter().filter_map(move |(k, v)| f(k, &*v)).collect() } - /// The most interesting method: Providing a shared ref without + /// The most interesting method: Providing a shared reference without /// holding the `RefCell` open, and inserting new data if the key /// is not used yet. /// `vacant` is called if the key is not found in the map; diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 33e47147a33b..281fe1e671bb 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -191,7 +191,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); match msg { - BoundsCheck { ref index, ref len } => { + BoundsCheck { index, len } => { // Forward to `panic_bounds_check` lang item. // First arg: index. diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 36ad4bd9b691..cba7dde53d81 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -87,7 +87,7 @@ impl<'tcx> TlsData<'tcx> { pub fn store_tls(&mut self, key: TlsKey, new_data: Option>) -> InterpResult<'tcx> { match self.keys.get_mut(&key) { - Some(&mut TlsEntry { ref mut data, .. }) => { + Some(TlsEntry { data, .. }) => { trace!("TLS key {} stored: {:?}", key, new_data); *data = new_data; Ok(()) @@ -139,12 +139,12 @@ impl<'tcx> TlsData<'tcx> { Some(key) => Excluded(key), None => Unbounded, }; - for (&key, &mut TlsEntry { ref mut data, dtor }) in + for (&key, TlsEntry { data, dtor }) in thread_local.range_mut((start, Unbounded)) { if let Some(data_scalar) = *data { if let Some(dtor) = dtor { - let ret = Some((dtor, data_scalar, key)); + let ret = Some((*dtor, data_scalar, key)); *data = None; return ret; } From 314e7238cf5f5fa6030035814193df455d337ad7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 12 Apr 2020 10:32:36 +0200 Subject: [PATCH 1846/5092] avoid a bunch of as_ref/as_mut --- src/bin/cargo-miri.rs | 14 +++++++------- src/machine.rs | 12 ++++++------ src/shims/panic.rs | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index dfb5a5a98912..04020009c694 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -115,7 +115,7 @@ fn list_targets() -> impl Iterator { get_arg_flag_value("--manifest-path").map(|m| Path::new(&m).canonicalize().unwrap()); let mut cmd = cargo_metadata::MetadataCommand::new(); - if let Some(manifest_path) = manifest_path.as_ref() { + if let Some(manifest_path) = &manifest_path { cmd.manifest_path(manifest_path); } let mut metadata = if let Ok(metadata) = cmd.exec() { @@ -131,7 +131,7 @@ fn list_targets() -> impl Iterator { .iter() .position(|package| { let package_manifest_path = Path::new(&package.manifest_path); - if let Some(manifest_path) = manifest_path.as_ref() { + if let Some(manifest_path) = &manifest_path { package_manifest_path == manifest_path } else { let current_dir = current_dir.as_ref().expect("could not read current directory"); @@ -368,8 +368,8 @@ path = "lib.rs" command.env("XARGO_HOME", &dir); command.env("XARGO_RUST_SRC", &rust_src); // Handle target flag. - if let Some(target) = target.as_ref() { - command.arg("--target").arg(&target); + if let Some(target) = &target { + command.arg("--target").arg(target); } // Finally run it! if command.status().expect("failed to run xargo").success().not() { @@ -379,7 +379,7 @@ path = "lib.rs" // That should be it! But we need to figure out where xargo built stuff. // Unfortunately, it puts things into a different directory when the // architecture matches the host. - let is_host = match target.as_ref() { + let is_host = match &target { None => true, Some(target) => target == &rustc_version::version_meta().unwrap().host, }; @@ -404,12 +404,12 @@ fn main() { return; } - if let Some("miri") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { + if let Some("miri") = std::env::args().nth(1).as_deref() { // This arm is for when `cargo miri` is called. We call `cargo check` for each applicable target, // but with the `RUSTC` env var set to the `cargo-miri` binary so that we come back in the other branch, // and dispatch the invocations to `rustc` and `miri`, respectively. in_cargo_miri(); - } else if let Some("rustc") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { + } else if let Some("rustc") = std::env::args().nth(1).as_deref() { // This arm is executed when `cargo-miri` runs `cargo check` with the `RUSTC_WRAPPER` env var set to itself: // dependencies get dispatched to `rustc`, the final test/binary to `miri`. inside_cargo_rustc(); diff --git a/src/machine.rs b/src/machine.rs index 612f1bb328cc..72635f7bf57b 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -429,7 +429,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); let (stacks, base_tag) = - if let Some(stacked_borrows) = memory_extra.stacked_borrows.as_ref() { + if let Some(stacked_borrows) = &memory_extra.stacked_borrows { let (stacks, base_tag) = Stacks::new_allocation(id, alloc.size, Rc::clone(stacked_borrows), kind); (Some(stacks), base_tag) @@ -440,7 +440,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { let mut stacked_borrows = memory_extra.stacked_borrows.as_ref().map(|sb| sb.borrow_mut()); let alloc: Allocation = alloc.with_tags_and_extra( |alloc| { - if let Some(stacked_borrows) = stacked_borrows.as_mut() { + if let Some(stacked_borrows) = &mut stacked_borrows { // Only globals may already contain pointers at this point assert_eq!(kind, MiriMemoryKind::Global.into()); stacked_borrows.global_base_ptr(alloc) @@ -455,7 +455,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn tag_global_base_pointer(memory_extra: &MemoryExtra, id: AllocId) -> Self::PointerTag { - if let Some(stacked_borrows) = memory_extra.stacked_borrows.as_ref() { + if let Some(stacked_borrows) = &memory_extra.stacked_borrows { stacked_borrows.borrow_mut().global_base_ptr(id) } else { Tag::Untagged @@ -518,7 +518,7 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - if let Some(stacked_borrows) = alloc.extra.stacked_borrows.as_ref() { + if let Some(stacked_borrows) = &alloc.extra.stacked_borrows { stacked_borrows.memory_read(ptr, size) } else { Ok(()) @@ -531,7 +531,7 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - if let Some(stacked_borrows) = alloc.extra.stacked_borrows.as_mut() { + if let Some(stacked_borrows) = &mut alloc.extra.stacked_borrows { stacked_borrows.memory_written(ptr, size) } else { Ok(()) @@ -544,7 +544,7 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - if let Some(stacked_borrows) = alloc.extra.stacked_borrows.as_mut() { + if let Some(stacked_borrows) = &mut alloc.extra.stacked_borrows { stacked_borrows.memory_deallocated(ptr, size) } else { Ok(()) diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 281fe1e671bb..1aec236a533c 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -123,7 +123,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); trace!("handle_stack_pop(extra = {:?}, unwinding = {})", extra, unwinding); - if let Some(stacked_borrows) = this.memory.extra.stacked_borrows.as_ref() { + if let Some(stacked_borrows) = &this.memory.extra.stacked_borrows { stacked_borrows.borrow_mut().end_call(extra.call_id); } From 6414003ab96f30c7739a62722405f968d2d1a576 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 12 Apr 2020 11:01:59 +0200 Subject: [PATCH 1847/5092] organize intrinsics into groups --- src/shims/intrinsics.rs | 519 ++++++++++++++++++++-------------------- 1 file changed, 262 insertions(+), 257 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 844eac398de8..de34f1a7b6ce 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -37,9 +37,62 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(p) => p, }; + // Then handle terminating intrinsics. match intrinsic_name { - "try" => return this.handle_try(args, dest, ret), + // Raw memory accesses + #[rustfmt::skip] + | "copy" + | "copy_nonoverlapping" + => { + let elem_ty = substs.type_at(0); + let elem_layout = this.layout_of(elem_ty)?; + let count = this.read_scalar(args[2])?.to_machine_usize(this)?; + let elem_align = elem_layout.align.abi; + let size = elem_layout.size.checked_mul(count, this) + .ok_or_else(|| err_ub_format!("overflow computing total size of `{}`", intrinsic_name))?; + let src = this.read_scalar(args[0])?.not_undef()?; + let src = this.memory.check_ptr_access(src, size, elem_align)?; + let dest = this.read_scalar(args[1])?.not_undef()?; + let dest = this.memory.check_ptr_access(dest, size, elem_align)?; + + if let (Some(src), Some(dest)) = (src, dest) { + this.memory.copy( + src, + dest, + size, + intrinsic_name.ends_with("_nonoverlapping"), + )?; + } + } + + "move_val_init" => { + let place = this.deref_operand(args[0])?; + this.copy_op(args[1], place.into())?; + } + + "volatile_load" => { + let place = this.deref_operand(args[0])?; + this.copy_op(place.into(), dest)?; + } + "volatile_store" => { + let place = this.deref_operand(args[0])?; + this.copy_op(args[1], place.into())?; + } + + "write_bytes" => { + let ty = substs.type_at(0); + let ty_layout = this.layout_of(ty)?; + let val_byte = this.read_scalar(args[1])?.to_u8()?; + let ptr = this.read_scalar(args[0])?.not_undef()?; + let count = this.read_scalar(args[2])?.to_machine_usize(this)?; + let byte_count = ty_layout.size.checked_mul(count, this) + .ok_or_else(|| err_ub_format!("overflow computing total size of `write_bytes`"))?; + this.memory + .write_bytes(ptr, iter::repeat(val_byte).take(byte_count.bytes() as usize))?; + } + + // Pointer arithmetic "arith_offset" => { let offset = this.read_scalar(args[1])?.to_machine_isize(this)?; let ptr = this.read_scalar(args[0])?.not_undef()?; @@ -50,24 +103,183 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result_ptr = ptr.ptr_wrapping_signed_offset(offset, this); this.write_scalar(result_ptr, dest)?; } - - "assume" => { - let cond = this.read_scalar(args[0])?.to_bool()?; - if !cond { - throw_ub_format!("`assume` intrinsic called with `false`"); - } + "offset" => { + let offset = this.read_scalar(args[1])?.to_machine_isize(this)?; + let ptr = this.read_scalar(args[0])?.not_undef()?; + let result_ptr = this.pointer_offset_inbounds(ptr, substs.type_at(0), offset)?; + this.write_scalar(result_ptr, dest)?; } - "volatile_load" => { - let place = this.deref_operand(args[0])?; - this.copy_op(place.into(), dest)?; + // Floating-point operations + #[rustfmt::skip] + | "sinf32" + | "fabsf32" + | "cosf32" + | "sqrtf32" + | "expf32" + | "exp2f32" + | "logf32" + | "log10f32" + | "log2f32" + | "floorf32" + | "ceilf32" + | "truncf32" + | "roundf32" + => { + // FIXME: Using host floats. + let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); + let f = match intrinsic_name { + "sinf32" => f.sin(), + "fabsf32" => f.abs(), + "cosf32" => f.cos(), + "sqrtf32" => f.sqrt(), + "expf32" => f.exp(), + "exp2f32" => f.exp2(), + "logf32" => f.ln(), + "log10f32" => f.log10(), + "log2f32" => f.log2(), + "floorf32" => f.floor(), + "ceilf32" => f.ceil(), + "truncf32" => f.trunc(), + "roundf32" => f.round(), + _ => bug!(), + }; + this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?; } - "volatile_store" => { - let place = this.deref_operand(args[0])?; - this.copy_op(args[1], place.into())?; + #[rustfmt::skip] + | "sinf64" + | "fabsf64" + | "cosf64" + | "sqrtf64" + | "expf64" + | "exp2f64" + | "logf64" + | "log10f64" + | "log2f64" + | "floorf64" + | "ceilf64" + | "truncf64" + | "roundf64" + => { + // FIXME: Using host floats. + let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); + let f = match intrinsic_name { + "sinf64" => f.sin(), + "fabsf64" => f.abs(), + "cosf64" => f.cos(), + "sqrtf64" => f.sqrt(), + "expf64" => f.exp(), + "exp2f64" => f.exp2(), + "logf64" => f.ln(), + "log10f64" => f.log10(), + "log2f64" => f.log2(), + "floorf64" => f.floor(), + "ceilf64" => f.ceil(), + "truncf64" => f.trunc(), + "roundf64" => f.round(), + _ => bug!(), + }; + this.write_scalar(Scalar::from_u64(f.to_bits()), dest)?; } + #[rustfmt::skip] + | "fadd_fast" + | "fsub_fast" + | "fmul_fast" + | "fdiv_fast" + | "frem_fast" + => { + let a = this.read_immediate(args[0])?; + let b = this.read_immediate(args[1])?; + let op = match intrinsic_name { + "fadd_fast" => mir::BinOp::Add, + "fsub_fast" => mir::BinOp::Sub, + "fmul_fast" => mir::BinOp::Mul, + "fdiv_fast" => mir::BinOp::Div, + "frem_fast" => mir::BinOp::Rem, + _ => bug!(), + }; + this.binop_ignore_overflow(op, a, b, dest)?; + } + + #[rustfmt::skip] + | "minnumf32" + | "maxnumf32" + | "copysignf32" + => { + let a = this.read_scalar(args[0])?.to_f32()?; + let b = this.read_scalar(args[1])?.to_f32()?; + let res = match intrinsic_name { + "minnumf32" => a.min(b), + "maxnumf32" => a.max(b), + "copysignf32" => a.copy_sign(b), + _ => bug!(), + }; + this.write_scalar(Scalar::from_f32(res), dest)?; + } + + #[rustfmt::skip] + | "minnumf64" + | "maxnumf64" + | "copysignf64" + => { + let a = this.read_scalar(args[0])?.to_f64()?; + let b = this.read_scalar(args[1])?.to_f64()?; + let res = match intrinsic_name { + "minnumf64" => a.min(b), + "maxnumf64" => a.max(b), + "copysignf64" => a.copy_sign(b), + _ => bug!(), + }; + this.write_scalar(Scalar::from_f64(res), dest)?; + } + + "powf32" => { + // FIXME: Using host floats. + let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); + let f2 = f32::from_bits(this.read_scalar(args[1])?.to_u32()?); + this.write_scalar(Scalar::from_u32(f.powf(f2).to_bits()), dest)?; + } + + "powf64" => { + // FIXME: Using host floats. + let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); + let f2 = f64::from_bits(this.read_scalar(args[1])?.to_u64()?); + this.write_scalar(Scalar::from_u64(f.powf(f2).to_bits()), dest)?; + } + + "fmaf32" => { + let a = this.read_scalar(args[0])?.to_f32()?; + let b = this.read_scalar(args[1])?.to_f32()?; + let c = this.read_scalar(args[2])?.to_f32()?; + let res = a.mul_add(b, c).value; + this.write_scalar(Scalar::from_f32(res), dest)?; + } + + "fmaf64" => { + let a = this.read_scalar(args[0])?.to_f64()?; + let b = this.read_scalar(args[1])?.to_f64()?; + let c = this.read_scalar(args[2])?.to_f64()?; + let res = a.mul_add(b, c).value; + this.write_scalar(Scalar::from_f64(res), dest)?; + } + + "powif32" => { + // FIXME: Using host floats. + let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); + let i = this.read_scalar(args[1])?.to_i32()?; + this.write_scalar(Scalar::from_u32(f.powi(i).to_bits()), dest)?; + } + + "powif64" => { + // FIXME: Using host floats. + let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); + let i = this.read_scalar(args[1])?.to_i32()?; + this.write_scalar(Scalar::from_u64(f.powi(i).to_bits()), dest)?; + } + + // Atomic operations #[rustfmt::skip] | "atomic_load" | "atomic_load_relaxed" @@ -214,190 +426,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_immediate(*val, place.into())?; } - #[rustfmt::skip] - | "copy" - | "copy_nonoverlapping" - => { - let elem_ty = substs.type_at(0); - let elem_layout = this.layout_of(elem_ty)?; - let count = this.read_scalar(args[2])?.to_machine_usize(this)?; - let elem_align = elem_layout.align.abi; - - let size = elem_layout.size.checked_mul(count, this) - .ok_or_else(|| err_ub_format!("overflow computing total size of `{}`", intrinsic_name))?; - let src = this.read_scalar(args[0])?.not_undef()?; - let src = this.memory.check_ptr_access(src, size, elem_align)?; - let dest = this.read_scalar(args[1])?.not_undef()?; - let dest = this.memory.check_ptr_access(dest, size, elem_align)?; - - if let (Some(src), Some(dest)) = (src, dest) { - this.memory.copy( - src, - dest, - size, - intrinsic_name.ends_with("_nonoverlapping"), - )?; - } - } - - #[rustfmt::skip] - | "sinf32" - | "fabsf32" - | "cosf32" - | "sqrtf32" - | "expf32" - | "exp2f32" - | "logf32" - | "log10f32" - | "log2f32" - | "floorf32" - | "ceilf32" - | "truncf32" - | "roundf32" - => { - // FIXME: Using host floats. - let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); - let f = match intrinsic_name { - "sinf32" => f.sin(), - "fabsf32" => f.abs(), - "cosf32" => f.cos(), - "sqrtf32" => f.sqrt(), - "expf32" => f.exp(), - "exp2f32" => f.exp2(), - "logf32" => f.ln(), - "log10f32" => f.log10(), - "log2f32" => f.log2(), - "floorf32" => f.floor(), - "ceilf32" => f.ceil(), - "truncf32" => f.trunc(), - "roundf32" => f.round(), - _ => bug!(), - }; - this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?; - } - - #[rustfmt::skip] - | "sinf64" - | "fabsf64" - | "cosf64" - | "sqrtf64" - | "expf64" - | "exp2f64" - | "logf64" - | "log10f64" - | "log2f64" - | "floorf64" - | "ceilf64" - | "truncf64" - | "roundf64" - => { - // FIXME: Using host floats. - let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); - let f = match intrinsic_name { - "sinf64" => f.sin(), - "fabsf64" => f.abs(), - "cosf64" => f.cos(), - "sqrtf64" => f.sqrt(), - "expf64" => f.exp(), - "exp2f64" => f.exp2(), - "logf64" => f.ln(), - "log10f64" => f.log10(), - "log2f64" => f.log2(), - "floorf64" => f.floor(), - "ceilf64" => f.ceil(), - "truncf64" => f.trunc(), - "roundf64" => f.round(), - _ => bug!(), - }; - this.write_scalar(Scalar::from_u64(f.to_bits()), dest)?; - } - - #[rustfmt::skip] - | "fadd_fast" - | "fsub_fast" - | "fmul_fast" - | "fdiv_fast" - | "frem_fast" - => { - let a = this.read_immediate(args[0])?; - let b = this.read_immediate(args[1])?; - let op = match intrinsic_name { - "fadd_fast" => mir::BinOp::Add, - "fsub_fast" => mir::BinOp::Sub, - "fmul_fast" => mir::BinOp::Mul, - "fdiv_fast" => mir::BinOp::Div, - "frem_fast" => mir::BinOp::Rem, - _ => bug!(), - }; - this.binop_ignore_overflow(op, a, b, dest)?; - } - - #[rustfmt::skip] - | "minnumf32" - | "maxnumf32" - | "copysignf32" - => { - let a = this.read_scalar(args[0])?.to_f32()?; - let b = this.read_scalar(args[1])?.to_f32()?; - let res = match intrinsic_name { - "minnumf32" => a.min(b), - "maxnumf32" => a.max(b), - "copysignf32" => a.copy_sign(b), - _ => bug!(), - }; - this.write_scalar(Scalar::from_f32(res), dest)?; - } - - #[rustfmt::skip] - | "minnumf64" - | "maxnumf64" - | "copysignf64" - => { - let a = this.read_scalar(args[0])?.to_f64()?; - let b = this.read_scalar(args[1])?.to_f64()?; - let res = match intrinsic_name { - "minnumf64" => a.min(b), - "maxnumf64" => a.max(b), - "copysignf64" => a.copy_sign(b), - _ => bug!(), - }; - this.write_scalar(Scalar::from_f64(res), dest)?; - } - - "exact_div" => - this.exact_div(this.read_immediate(args[0])?, this.read_immediate(args[1])?, dest)?, - - "forget" => {} - - #[rustfmt::skip] - | "likely" - | "unlikely" - => { - // These just return their argument - let b = this.read_immediate(args[0])?; - this.write_immediate(*b, dest)?; - } - - "pref_align_of" => { - let ty = substs.type_at(0); - let layout = this.layout_of(ty)?; - let align = layout.align.pref.bytes(); - let align_val = Scalar::from_machine_usize(align, this); - this.write_scalar(align_val, dest)?; - } - - "move_val_init" => { - let place = this.deref_operand(args[0])?; - this.copy_op(args[1], place.into())?; - } - - "offset" => { - let offset = this.read_scalar(args[1])?.to_machine_isize(this)?; - let ptr = this.read_scalar(args[0])?.not_undef()?; - let result_ptr = this.pointer_offset_inbounds(ptr, substs.type_at(0), offset)?; - this.write_scalar(result_ptr, dest)?; - } - + // Query type information "assert_inhabited" | "assert_zero_valid" | "assert_uninit_valid" => { @@ -415,56 +444,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - "powf32" => { - // FIXME: Using host floats. - let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); - let f2 = f32::from_bits(this.read_scalar(args[1])?.to_u32()?); - this.write_scalar(Scalar::from_u32(f.powf(f2).to_bits()), dest)?; - } - - "powf64" => { - // FIXME: Using host floats. - let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); - let f2 = f64::from_bits(this.read_scalar(args[1])?.to_u64()?); - this.write_scalar(Scalar::from_u64(f.powf(f2).to_bits()), dest)?; - } - - "fmaf32" => { - let a = this.read_scalar(args[0])?.to_f32()?; - let b = this.read_scalar(args[1])?.to_f32()?; - let c = this.read_scalar(args[2])?.to_f32()?; - let res = a.mul_add(b, c).value; - this.write_scalar(Scalar::from_f32(res), dest)?; - } - - "fmaf64" => { - let a = this.read_scalar(args[0])?.to_f64()?; - let b = this.read_scalar(args[1])?.to_f64()?; - let c = this.read_scalar(args[2])?.to_f64()?; - let res = a.mul_add(b, c).value; - this.write_scalar(Scalar::from_f64(res), dest)?; - } - - "powif32" => { - // FIXME: Using host floats. - let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); - let i = this.read_scalar(args[1])?.to_i32()?; - this.write_scalar(Scalar::from_u32(f.powi(i).to_bits()), dest)?; - } - - "powif64" => { - // FIXME: Using host floats. - let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); - let i = this.read_scalar(args[1])?.to_i32()?; - this.write_scalar(Scalar::from_u64(f.powi(i).to_bits()), dest)?; - } - - "size_of_val" => { - let mplace = this.deref_operand(args[0])?; - let (size, _) = this - .size_and_align_of_mplace(mplace)? - .expect("size_of_val called on extern type"); - this.write_scalar(Scalar::from_machine_usize(size.bytes(), this), dest)?; + "pref_align_of" => { + let ty = substs.type_at(0); + let layout = this.layout_of(ty)?; + let align = layout.align.pref.bytes(); + let align_val = Scalar::from_machine_usize(align, this); + this.write_scalar(align_val, dest)?; } #[rustfmt::skip] @@ -478,18 +463,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_usize(align.bytes(), this), dest)?; } - "write_bytes" => { - let ty = substs.type_at(0); - let ty_layout = this.layout_of(ty)?; - let val_byte = this.read_scalar(args[1])?.to_u8()?; - let ptr = this.read_scalar(args[0])?.not_undef()?; - let count = this.read_scalar(args[2])?.to_machine_usize(this)?; - let byte_count = ty_layout.size.checked_mul(count, this) - .ok_or_else(|| err_ub_format!("overflow computing total size of `write_bytes`"))?; - this.memory - .write_bytes(ptr, iter::repeat(val_byte).take(byte_count.bytes() as usize))?; + "size_of_val" => { + let mplace = this.deref_operand(args[0])?; + let (size, _) = this + .size_and_align_of_mplace(mplace)? + .expect("size_of_val called on extern type"); + this.write_scalar(Scalar::from_machine_usize(size.bytes(), this), dest)?; } + // Other + "assume" => { + let cond = this.read_scalar(args[0])?.to_bool()?; + if !cond { + throw_ub_format!("`assume` intrinsic called with `false`"); + } + } + + "exact_div" => + this.exact_div(this.read_immediate(args[0])?, this.read_immediate(args[1])?, dest)?, + + "forget" => {} + + #[rustfmt::skip] + | "likely" + | "unlikely" + => { + // These just return their argument + let b = this.read_immediate(args[0])?; + this.write_immediate(*b, dest)?; + } + + "try" => return this.handle_try(args, dest, ret), + name => throw_unsup_format!("unimplemented intrinsic: {}", name), } From fd0957f5cd17e2b341c356ffc09b59eb81176eb0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 12 Apr 2020 11:02:56 +0200 Subject: [PATCH 1848/5092] remove an intrinsic that was moved to rustc --- src/shims/intrinsics.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index de34f1a7b6ce..7c21ecee1d34 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -444,14 +444,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - "pref_align_of" => { - let ty = substs.type_at(0); - let layout = this.layout_of(ty)?; - let align = layout.align.pref.bytes(); - let align_val = Scalar::from_machine_usize(align, this); - this.write_scalar(align_val, dest)?; - } - #[rustfmt::skip] | "min_align_of_val" | "align_of_val" From 2a3ce5d618d80a83ba0166e18b70a9ec69fd8f96 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 12 Apr 2020 11:04:18 +0200 Subject: [PATCH 1849/5092] there is no 'align_of_val' intrinsic --- src/shims/intrinsics.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 7c21ecee1d34..0f17bee00887 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -444,10 +444,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - #[rustfmt::skip] - | "min_align_of_val" - | "align_of_val" - => { + "min_align_of_val" => { let mplace = this.deref_operand(args[0])?; let (_, align) = this .size_and_align_of_mplace(mplace)? From 8d1f5336c2dda92b007e8a4306315f7e81c76424 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 12 Apr 2020 11:07:37 +0200 Subject: [PATCH 1850/5092] also test unsafe cast intrinsic (happy cases) --- tests/run-pass/float.rs | 185 +++++++++++++++++++++++++++------------- 1 file changed, 125 insertions(+), 60 deletions(-) diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index 738df2f6c59e..4c30cd01c4c0 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -10,6 +10,63 @@ fn assert_eq(x: T, y: T) { assert_eq!(x, y); } +trait FloatToInt: Copy { + fn cast(self) -> Int; + unsafe fn cast_unchecked(self) -> Int; +} + +impl FloatToInt for f32 { + fn cast(self) -> i8 { self as _ } + unsafe fn cast_unchecked(self) -> i8 { self.to_int_unchecked() } +} +impl FloatToInt for f32 { + fn cast(self) -> i32 { self as _ } + unsafe fn cast_unchecked(self) -> i32 { self.to_int_unchecked() } +} +impl FloatToInt for f32 { + fn cast(self) -> u32 { self as _ } + unsafe fn cast_unchecked(self) -> u32 { self.to_int_unchecked() } +} +impl FloatToInt for f32 { + fn cast(self) -> i64 { self as _ } + unsafe fn cast_unchecked(self) -> i64 { self.to_int_unchecked() } +} +impl FloatToInt for f32 { + fn cast(self) -> u64 { self as _ } + unsafe fn cast_unchecked(self) -> u64 { self.to_int_unchecked() } +} + +impl FloatToInt for f64 { + fn cast(self) -> i8 { self as _ } + unsafe fn cast_unchecked(self) -> i8 { self.to_int_unchecked() } +} +impl FloatToInt for f64 { + fn cast(self) -> i32 { self as _ } + unsafe fn cast_unchecked(self) -> i32 { self.to_int_unchecked() } +} +impl FloatToInt for f64 { + fn cast(self) -> u32 { self as _ } + unsafe fn cast_unchecked(self) -> u32 { self.to_int_unchecked() } +} +impl FloatToInt for f64 { + fn cast(self) -> i64 { self as _ } + unsafe fn cast_unchecked(self) -> i64 { self.to_int_unchecked() } +} +impl FloatToInt for f64 { + fn cast(self) -> u64 { self as _ } + unsafe fn cast_unchecked(self) -> u64 { self.to_int_unchecked() } +} + +/// Test this cast both via `as` and via `approx_unchecked` (i.e., it must not saturate). +#[track_caller] +#[inline(never)] +fn test_cast(x: F, y: I) + where F: FloatToInt, I: PartialEq + Debug +{ + assert_eq!(x.cast(), y); + assert_eq!(unsafe { x.cast_unchecked() }, y); +} + fn main() { basic(); casts(); @@ -50,19 +107,23 @@ fn basic() { } fn casts() { + // f32 -> i8 + test_cast::(127.99, 127); + test_cast::(-128.99, -128); + // f32 -> i32 - assert_eq::(0.0f32 as i32, 0); - assert_eq::(-0.0f32 as i32, 0); - assert_eq::(/*0x1p-149*/ f32::from_bits(0x00000001) as i32, 0); - assert_eq::(/*-0x1p-149*/ f32::from_bits(0x80000001) as i32, 0); - assert_eq::(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd) as i32, 1); - assert_eq::(/*-0x1.19999ap+0*/ f32::from_bits(0xbf8ccccd) as i32, -1); - assert_eq::(1.9f32 as i32, 1); - assert_eq::(-1.9f32 as i32, -1); - assert_eq::(5.0f32 as i32, 5); - assert_eq::(-5.0f32 as i32, -5); - assert_eq::(2147483520.0f32 as i32, 2147483520); - assert_eq::(-2147483648.0f32 as i32, -2147483648); + test_cast::(0.0, 0); + test_cast::(-0.0, 0); + test_cast::(/*0x1p-149*/ f32::from_bits(0x00000001), 0); + test_cast::(/*-0x1p-149*/ f32::from_bits(0x80000001), 0); + test_cast::(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd), 1); + test_cast::(/*-0x1.19999ap+0*/ f32::from_bits(0xbf8ccccd), -1); + test_cast::(1.9, 1); + test_cast::(-1.9, -1); + test_cast::(5.0, 5); + test_cast::(-5.0, -5); + test_cast::(2147483520.0, 2147483520); + test_cast::(-2147483648.0, -2147483648); // unrepresentable casts assert_eq::(2147483648.0f32 as i32, i32::MAX); assert_eq::(-2147483904.0f32 as i32, i32::MIN); @@ -74,19 +135,19 @@ fn casts() { assert_eq::((-f32::NAN) as i32, 0); // f32 -> u32 - assert_eq::(0.0f32 as u32, 0); - assert_eq::(-0.0f32 as u32, 0); - assert_eq::(/*0x1p-149*/ f32::from_bits(0x1) as u32, 0); - assert_eq::(/*-0x1p-149*/ f32::from_bits(0x80000001) as u32, 0); - assert_eq::(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd) as u32, 1); - assert_eq::(1.9f32 as u32, 1); - assert_eq::(5.0f32 as u32, 5); - assert_eq::(2147483648.0f32 as u32, 0x8000_0000); - assert_eq::(4294967040.0f32 as u32, 0u32.wrapping_sub(256)); - assert_eq::(/*-0x1.ccccccp-1*/ f32::from_bits(0xbf666666) as u32, 0); - assert_eq::(/*-0x1.fffffep-1*/ f32::from_bits(0xbf7fffff) as u32, 0); - assert_eq::((u32::MAX-127) as f32 as u32, u32::MAX); // rounding loss - assert_eq::((u32::MAX-128) as f32 as u32, u32::MAX-255); // rounding loss + test_cast::(0.0, 0); + test_cast::(-0.0, 0); + test_cast::(/*0x1p-149*/ f32::from_bits(0x1), 0); + test_cast::(/*-0x1p-149*/ f32::from_bits(0x80000001), 0); + test_cast::(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd), 1); + test_cast::(1.9, 1); + test_cast::(5.0, 5); + test_cast::(2147483648.0, 0x8000_0000); + test_cast::(4294967040.0, 0u32.wrapping_sub(256)); + test_cast::(/*-0x1.ccccccp-1*/ f32::from_bits(0xbf666666), 0); + test_cast::(/*-0x1.fffffep-1*/ f32::from_bits(0xbf7fffff), 0); + test_cast::((u32::MAX-127) as f32, u32::MAX); // rounding loss + test_cast::((u32::MAX-128) as f32, u32::MAX-255); // rounding loss // unrepresentable casts assert_eq::(4294967296.0f32 as u32, u32::MAX); assert_eq::(-5.0f32 as u32, 0); @@ -98,40 +159,44 @@ fn casts() { assert_eq::((-f32::NAN) as u32, 0); // f32 -> i64 - assert_eq::(4294967296.0f32 as i64, 4294967296); - assert_eq::(-4294967296.0f32 as i64, -4294967296); - assert_eq::(9223371487098961920.0f32 as i64, 9223371487098961920); - assert_eq::(-9223372036854775808.0f32 as i64, -9223372036854775808); + test_cast::(4294967296.0, 4294967296); + test_cast::(-4294967296.0, -4294967296); + test_cast::(9223371487098961920.0, 9223371487098961920); + test_cast::(-9223372036854775808.0, -9223372036854775808); + + // f64 -> i8 + test_cast::(127.99, 127); + test_cast::(-128.99, -128); // f64 -> i32 - assert_eq::(0.0f64 as i32, 0); - assert_eq::(-0.0f64 as i32, 0); - assert_eq::(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a) as i32, 1); - assert_eq::(/*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a) as i32, -1); - assert_eq::(1.9f64 as i32, 1); - assert_eq::(-1.9f64 as i32, -1); - assert_eq::(1e8f64 as i32, 100_000_000); - assert_eq::(2147483647.0f64 as i32, 2147483647); - assert_eq::(-2147483648.0f64 as i32, -2147483648); + test_cast::(0.0, 0); + test_cast::(-0.0, 0); + test_cast::(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a), 1); + test_cast::(/*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a), -1); + test_cast::(1.9, 1); + test_cast::(-1.9, -1); + test_cast::(1e8, 100_000_000); + test_cast::(2147483647.0, 2147483647); + test_cast::(-2147483648.0, -2147483648); // unrepresentable casts assert_eq::(2147483648.0f64 as i32, i32::MAX); assert_eq::(-2147483649.0f64 as i32, i32::MIN); // f64 -> i64 - assert_eq::(0.0f64 as i64, 0); - assert_eq::(-0.0f64 as i64, 0); - assert_eq::(/*0x0.0000000000001p-1022*/ f64::from_bits(0x1) as i64, 0); - assert_eq::(/*-0x0.0000000000001p-1022*/ f64::from_bits(0x8000000000000001) as i64, 0); - assert_eq::(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a) as i64, 1); - assert_eq::(/*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a) as i64, -1); - assert_eq::(5.0f64 as i64, 5); - assert_eq::(5.9f64 as i64, 5); - assert_eq::(-5.0f64 as i64, -5); - assert_eq::(-5.9f64 as i64, -5); - assert_eq::(4294967296.0f64 as i64, 4294967296); - assert_eq::(-4294967296.0f64 as i64, -4294967296); - assert_eq::(9223372036854774784.0f64 as i64, 9223372036854774784); - assert_eq::(-9223372036854775808.0f64 as i64, -9223372036854775808); + test_cast::(0.0, 0); + test_cast::(-0.0, 0); + test_cast::(/*0x0.0000000000001p-1022*/ f64::from_bits(0x1), 0); + test_cast::(/*-0x0.0000000000001p-1022*/ f64::from_bits(0x8000000000000001), 0); + test_cast::(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a), 1); + test_cast::(/*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a), -1); + test_cast::(5.0, 5); + test_cast::(5.9, 5); + test_cast::(-5.0, -5); + test_cast::(-5.9, -5); + test_cast::(4294967296.0, 4294967296); + test_cast::(-4294967296.0, -4294967296); + test_cast::(9223372036854774784.0, 9223372036854774784); + test_cast::(-9223372036854775808.0, -9223372036854775808); // unrepresentable casts assert_eq::(9223372036854775808.0f64 as i64, i64::MAX); assert_eq::(-9223372036854777856.0f64 as i64, i64::MIN); @@ -143,14 +208,14 @@ fn casts() { assert_eq::((-f64::NAN) as i64, 0); // f64 -> u64 - assert_eq::(0.0f64 as u64, 0); - assert_eq::(-0.0f64 as u64, 0); - assert_eq::(5.0f64 as u64, 5); - assert_eq::(-5.0f64 as u64, 0); - assert_eq::(1e16f64 as u64, 10000000000000000); - assert_eq::((u64::MAX-1023) as f64 as u64, u64::MAX); // rounding loss - assert_eq::((u64::MAX-1024) as f64 as u64, u64::MAX-2047); // rounding loss - assert_eq::(9223372036854775808.0f64 as u64, 9223372036854775808); + test_cast::(0.0, 0); + test_cast::(-0.0, 0); + test_cast::(5.0, 5); + test_cast::(-5.0, 0); + test_cast::(1e16, 10000000000000000); + test_cast::((u64::MAX-1023) as f64, u64::MAX); // rounding loss + test_cast::((u64::MAX-1024) as f64, u64::MAX-2047); // rounding loss + test_cast::(9223372036854775808.0, 9223372036854775808); // unrepresentable casts assert_eq::(18446744073709551616.0f64 as u64, u64::MAX); assert_eq::(f64::MAX as u64, u64::MAX); From 78ce616490c085f479fb08604f7016d8ce54a58b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 12 Apr 2020 11:35:12 +0200 Subject: [PATCH 1851/5092] implement float_to_int_unchecked --- src/shims/intrinsics.rs | 72 +++++++++++++++++++++++++++++++++++++++-- tests/run-pass/float.rs | 6 ++-- 2 files changed, 73 insertions(+), 5 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 0f17bee00887..8f4bda404d72 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -1,9 +1,10 @@ use std::iter; use std::convert::TryFrom; +use rustc_ast::ast::FloatTy; use rustc_middle::{mir, ty}; -use rustc_apfloat::Float; -use rustc_target::abi::{Align, LayoutOf}; +use rustc_apfloat::{Float, FloatConvert, Round, ieee::{Double, Single}}; +use rustc_target::abi::{Align, LayoutOf, Size}; use crate::*; @@ -279,6 +280,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_u64(f.powi(i).to_bits()), dest)?; } + "float_to_int_unchecked" => { + let val = this.read_immediate(args[0])?; + + let res = match val.layout.ty.kind { + ty::Float(FloatTy::F32) => { + this.float_to_int_unchecked(val.to_scalar()?.to_f32()?, dest.layout.ty)? + } + ty::Float(FloatTy::F64) => { + this.float_to_int_unchecked(val.to_scalar()?.to_f64()?, dest.layout.ty)? + } + _ => bug!("`float_to_int_unchecked` called with non-float input type {:?}", val.layout.ty), + }; + + this.write_scalar(res, dest)?; + } + // Atomic operations #[rustfmt::skip] | "atomic_load" @@ -491,4 +508,55 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.go_to_block(ret); Ok(()) } + + fn float_to_int_unchecked( + &self, + f: F, + dest_ty: ty::Ty<'tcx>, + ) -> InterpResult<'tcx, Scalar> + where + F: Float + Into> + FloatConvert + FloatConvert, + { + let this = self.eval_context_ref(); + + // Step 1: cut off the fractional part of `f`. The result of this is + // guaranteed to be precisely representable in IEEE floats. + let f = f.round_to_integral(Round::TowardZero).value; + + // Step 2: Cast the truncated float to the target integer type and see if we lose any information in this step. + Ok(match dest_ty.kind { + // Unsigned + ty::Uint(t) => { + let width = t.bit_width().unwrap_or_else(|| this.pointer_size().bits()); + let res = f.to_u128(usize::try_from(width).unwrap()); + if res.status.is_empty() { + // No status flags means there was no further rounding or other loss of precision. + Scalar::from_uint(res.value, Size::from_bits(width)) + } else { + // `f` was not representable in this integer type. + throw_ub_format!( + "`float_to_int_unchecked` intrinsic called on {} which cannot be represented in target type `{:?}`", + f, dest_ty, + ); + } + } + // Signed + ty::Int(t) => { + let width = t.bit_width().unwrap_or_else(|| this.pointer_size().bits()); + let res = f.to_i128(usize::try_from(width).unwrap()); + if res.status.is_empty() { + // No status flags means there was no further rounding or other loss of precision. + Scalar::from_int(res.value, Size::from_bits(width)) + } else { + // `f` was not representable in this integer type. + throw_ub_format!( + "`float_to_int_unchecked` intrinsic called on {} which cannot be represented in target type `{:?}`", + f, dest_ty, + ); + } + } + // Nothing else + _ => bug!("`float_to_int_unchecked` called with non-int output type {:?}", dest_ty), + }) + } } diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index 4c30cd01c4c0..3f86a21d18e2 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -146,9 +146,9 @@ fn casts() { test_cast::(4294967040.0, 0u32.wrapping_sub(256)); test_cast::(/*-0x1.ccccccp-1*/ f32::from_bits(0xbf666666), 0); test_cast::(/*-0x1.fffffep-1*/ f32::from_bits(0xbf7fffff), 0); - test_cast::((u32::MAX-127) as f32, u32::MAX); // rounding loss test_cast::((u32::MAX-128) as f32, u32::MAX-255); // rounding loss // unrepresentable casts + assert_eq::((u32::MAX-127) as f32 as u32, u32::MAX); // rounds up and then becomes unrepresentable assert_eq::(4294967296.0f32 as u32, u32::MAX); assert_eq::(-5.0f32 as u32, 0); assert_eq::(f32::MAX as u32, u32::MAX); @@ -211,12 +211,12 @@ fn casts() { test_cast::(0.0, 0); test_cast::(-0.0, 0); test_cast::(5.0, 5); - test_cast::(-5.0, 0); test_cast::(1e16, 10000000000000000); - test_cast::((u64::MAX-1023) as f64, u64::MAX); // rounding loss test_cast::((u64::MAX-1024) as f64, u64::MAX-2047); // rounding loss test_cast::(9223372036854775808.0, 9223372036854775808); // unrepresentable casts + assert_eq::(-5.0f64 as u64, 0); + assert_eq::((u64::MAX-1023) as f64 as u64, u64::MAX); // rounds up and then becomes unrepresentable assert_eq::(18446744073709551616.0f64 as u64, u64::MAX); assert_eq::(f64::MAX as u64, u64::MAX); assert_eq::(f64::MIN as u64, 0); From 30d07c861620c4c03226a9a0c693691b2e44ca58 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 12 Apr 2020 11:40:53 +0200 Subject: [PATCH 1852/5092] move error-pattern to inline annotation where possible --- tests/compile-fail/intrinsics/copy_overlapping.rs | 3 +-- tests/compile-fail/intrinsics/copy_unaligned.rs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/compile-fail/intrinsics/copy_overlapping.rs b/tests/compile-fail/intrinsics/copy_overlapping.rs index 76e1e20d2177..8d3c68139317 100644 --- a/tests/compile-fail/intrinsics/copy_overlapping.rs +++ b/tests/compile-fail/intrinsics/copy_overlapping.rs @@ -1,4 +1,3 @@ -//error-pattern: copy_nonoverlapping called on overlapping ranges #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd @@ -11,6 +10,6 @@ fn main() { unsafe { let a = data.as_mut_ptr(); let b = a.wrapping_offset(1) as *mut _; - copy_nonoverlapping(a, b, 2); + copy_nonoverlapping(a, b, 2); //~ ERROR copy_nonoverlapping called on overlapping ranges } } diff --git a/tests/compile-fail/intrinsics/copy_unaligned.rs b/tests/compile-fail/intrinsics/copy_unaligned.rs index a2a476223918..84f4de93461e 100644 --- a/tests/compile-fail/intrinsics/copy_unaligned.rs +++ b/tests/compile-fail/intrinsics/copy_unaligned.rs @@ -1,4 +1,3 @@ -//error-pattern: accessing memory with alignment 1, but alignment 2 is required #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd @@ -10,5 +9,5 @@ fn main() { let mut data = [0u16; 8]; let ptr = (&mut data[0] as *mut u16 as *mut u8).wrapping_add(1) as *mut u16; // Even copying 0 elements to something unaligned should error - unsafe { copy_nonoverlapping(&data[5], ptr, 0); } + unsafe { copy_nonoverlapping(&data[5], ptr, 0); } //~ ERROR accessing memory with alignment 1, but alignment 2 is required } From 25c71e5c0e88fb9fa9e657549658760f2e8d6bb2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 12 Apr 2020 12:00:55 +0200 Subject: [PATCH 1853/5092] test some more corner cases in happy float casts --- tests/run-pass/float.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index 3f86a21d18e2..364388571f44 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -56,6 +56,14 @@ impl FloatToInt for f64 { fn cast(self) -> u64 { self as _ } unsafe fn cast_unchecked(self) -> u64 { self.to_int_unchecked() } } +impl FloatToInt for f64 { + fn cast(self) -> i128 { self as _ } + unsafe fn cast_unchecked(self) -> i128 { self.to_int_unchecked() } +} +impl FloatToInt for f64 { + fn cast(self) -> u128 { self as _ } + unsafe fn cast_unchecked(self) -> u128 { self.to_int_unchecked() } +} /// Test this cast both via `as` and via `approx_unchecked` (i.e., it must not saturate). #[track_caller] @@ -137,6 +145,7 @@ fn casts() { // f32 -> u32 test_cast::(0.0, 0); test_cast::(-0.0, 0); + test_cast::(-0.9999999, 0); test_cast::(/*0x1p-149*/ f32::from_bits(0x1), 0); test_cast::(/*-0x1p-149*/ f32::from_bits(0x80000001), 0); test_cast::(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd), 1); @@ -210,6 +219,7 @@ fn casts() { // f64 -> u64 test_cast::(0.0, 0); test_cast::(-0.0, 0); + test_cast::(-0.99999999999, 0); test_cast::(5.0, 5); test_cast::(1e16, 10000000000000000); test_cast::((u64::MAX-1024) as f64, u64::MAX-2047); // rounding loss @@ -225,6 +235,14 @@ fn casts() { assert_eq::(f64::NAN as u64, 0); assert_eq::((-f64::NAN) as u64, 0); + // f64 -> i128 + assert_eq::(f64::MAX as i128, i128::MAX); + assert_eq::(f64::MIN as i128, i128::MIN); + + // f64 -> u128 + assert_eq::(f64::MAX as u128, u128::MAX); + assert_eq::(f64::MIN as u128, 0); + // int -> f32 assert_eq::(127i8 as f32, 127.0); assert_eq::(2147483647i32 as f32, 2147483648.0); @@ -275,10 +293,8 @@ fn casts() { assert_eq::(5.0f64 as f32, 5.0f32); assert_eq::(/*0x0.0000000000001p-1022*/ f64::from_bits(0x1) as f32, 0.0); assert_eq::(/*-0x0.0000000000001p-1022*/ (-f64::from_bits(0x1)) as f32, -0.0); - assert_eq::(/*0x1.fffffe0000000p-127*/ f64::from_bits(0x380fffffe0000000) as f32, /*0x1p-149*/ f32::from_bits(0x800000)); assert_eq::(/*0x1.4eae4f7024c7p+108*/ f64::from_bits(0x46b4eae4f7024c70) as f32, /*0x1.4eae5p+108*/ f32::from_bits(0x75a75728)); - assert_eq::(f64::MAX as f32, f32::INFINITY); assert_eq::(f64::MIN as f32, f32::NEG_INFINITY); assert_eq::(f64::INFINITY as f32, f32::INFINITY); From 17c52d47e70aff4a6ee290de5475228cdb3cc2a3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 12 Apr 2020 12:01:07 +0200 Subject: [PATCH 1854/5092] add tests for invalid float-to-int casts --- tests/compile-fail/intrinsics/float_to_int_32_inf1.rs | 10 ++++++++++ .../compile-fail/intrinsics/float_to_int_32_infneg1.rs | 10 ++++++++++ tests/compile-fail/intrinsics/float_to_int_32_nan.rs | 10 ++++++++++ .../compile-fail/intrinsics/float_to_int_32_nanneg.rs | 10 ++++++++++ tests/compile-fail/intrinsics/float_to_int_32_neg.rs | 10 ++++++++++ .../intrinsics/float_to_int_32_too_big1.rs | 10 ++++++++++ .../intrinsics/float_to_int_32_too_big2.rs | 10 ++++++++++ .../intrinsics/float_to_int_32_too_small1.rs | 10 ++++++++++ tests/compile-fail/intrinsics/float_to_int_64_inf1.rs | 10 ++++++++++ .../compile-fail/intrinsics/float_to_int_64_infneg1.rs | 10 ++++++++++ .../compile-fail/intrinsics/float_to_int_64_infneg2.rs | 10 ++++++++++ tests/compile-fail/intrinsics/float_to_int_64_nan.rs | 10 ++++++++++ tests/compile-fail/intrinsics/float_to_int_64_neg.rs | 10 ++++++++++ .../intrinsics/float_to_int_64_too_big1.rs | 10 ++++++++++ .../intrinsics/float_to_int_64_too_big2.rs | 10 ++++++++++ .../intrinsics/float_to_int_64_too_big3.rs | 10 ++++++++++ .../intrinsics/float_to_int_64_too_big4.rs | 10 ++++++++++ .../intrinsics/float_to_int_64_too_big5.rs | 10 ++++++++++ .../intrinsics/float_to_int_64_too_small1.rs | 10 ++++++++++ .../intrinsics/float_to_int_64_too_small2.rs | 10 ++++++++++ .../intrinsics/float_to_int_64_too_small3.rs | 10 ++++++++++ 21 files changed, 210 insertions(+) create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_inf1.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_infneg1.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_nan.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_nanneg.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_neg.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_too_big1.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_too_big2.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_too_small1.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_inf1.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_infneg1.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_infneg2.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_nan.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_neg.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_big1.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_big2.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_big3.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_big4.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_big5.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_small1.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_small2.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_small3.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_32_inf1.rs b/tests/compile-fail/intrinsics/float_to_int_32_inf1.rs new file mode 100644 index 000000000000..a56f4aefad3a --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_inf1.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(f32::INFINITY); } //~ ERROR: cannot be represented in target type `i32` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_32_infneg1.rs b/tests/compile-fail/intrinsics/float_to_int_32_infneg1.rs new file mode 100644 index 000000000000..d18f75fcca8a --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_infneg1.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(f32::NEG_INFINITY); } //~ ERROR: cannot be represented in target type `i32` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_32_nan.rs b/tests/compile-fail/intrinsics/float_to_int_32_nan.rs new file mode 100644 index 000000000000..e1fe8c7cf2f7 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_nan.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(f32::NAN); } //~ ERROR: cannot be represented in target type `u32` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_32_nanneg.rs b/tests/compile-fail/intrinsics/float_to_int_32_nanneg.rs new file mode 100644 index 000000000000..38899045c92c --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_nanneg.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(-f32::NAN); } //~ ERROR: cannot be represented in target type `u32` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_32_neg.rs b/tests/compile-fail/intrinsics/float_to_int_32_neg.rs new file mode 100644 index 000000000000..f15cf9a9cd64 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_neg.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(-1.000000001f32); } //~ ERROR: cannot be represented in target type `u32` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_32_too_big1.rs b/tests/compile-fail/intrinsics/float_to_int_32_too_big1.rs new file mode 100644 index 000000000000..ccbf917c8e89 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_too_big1.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(2147483648.0f32); } //~ ERROR: cannot be represented in target type `i32` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_32_too_big2.rs b/tests/compile-fail/intrinsics/float_to_int_32_too_big2.rs new file mode 100644 index 000000000000..6598fd36e038 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_too_big2.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::((u32::MAX-127) as f32); } //~ ERROR: cannot be represented in target type `u32` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_32_too_small1.rs b/tests/compile-fail/intrinsics/float_to_int_32_too_small1.rs new file mode 100644 index 000000000000..89f09e1e3f18 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_too_small1.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(-2147483904.0f32); } //~ ERROR: cannot be represented in target type `i32` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_64_inf1.rs b/tests/compile-fail/intrinsics/float_to_int_64_inf1.rs new file mode 100644 index 000000000000..e1a7b818d853 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_inf1.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(f64::INFINITY); } //~ ERROR: cannot be represented in target type `u128` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_64_infneg1.rs b/tests/compile-fail/intrinsics/float_to_int_64_infneg1.rs new file mode 100644 index 000000000000..a1d757b1511e --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_infneg1.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(f64::NEG_INFINITY); } //~ ERROR: cannot be represented in target type `u128` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_64_infneg2.rs b/tests/compile-fail/intrinsics/float_to_int_64_infneg2.rs new file mode 100644 index 000000000000..e48d19f1a6a8 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_infneg2.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(f64::NEG_INFINITY); } //~ ERROR: cannot be represented in target type `i128` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_64_nan.rs b/tests/compile-fail/intrinsics/float_to_int_64_nan.rs new file mode 100644 index 000000000000..03f378f5bcb7 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_nan.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(f64::NAN); } //~ ERROR: cannot be represented in target type `u32` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_64_neg.rs b/tests/compile-fail/intrinsics/float_to_int_64_neg.rs new file mode 100644 index 000000000000..d0b5a3e21cf9 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_neg.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(-1.0000000000001f64); } //~ ERROR: cannot be represented in target type `u128` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big1.rs b/tests/compile-fail/intrinsics/float_to_int_64_too_big1.rs new file mode 100644 index 000000000000..f928f161872e --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big1.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(2147483648.0f64); } //~ ERROR: cannot be represented in target type `i32` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big2.rs b/tests/compile-fail/intrinsics/float_to_int_64_too_big2.rs new file mode 100644 index 000000000000..feb24c362dda --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big2.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(9223372036854775808.0f64); } //~ ERROR: cannot be represented in target type `i64` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big3.rs b/tests/compile-fail/intrinsics/float_to_int_64_too_big3.rs new file mode 100644 index 000000000000..cd491bfed7eb --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big3.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(18446744073709551616.0f64); } //~ ERROR: cannot be represented in target type `u64` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big4.rs b/tests/compile-fail/intrinsics/float_to_int_64_too_big4.rs new file mode 100644 index 000000000000..d5b24347b941 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big4.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(340282366920938463463374607431768211455.0f64); } //~ ERROR: cannot be represented in target type `u128` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big5.rs b/tests/compile-fail/intrinsics/float_to_int_64_too_big5.rs new file mode 100644 index 000000000000..9c31c690b4e8 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big5.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(240282366920938463463374607431768211455.0f64); } //~ ERROR: cannot be represented in target type `i128` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_small1.rs b/tests/compile-fail/intrinsics/float_to_int_64_too_small1.rs new file mode 100644 index 000000000000..08f2f9e3fd26 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_small1.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(-2147483649.0f64); } //~ ERROR: cannot be represented in target type `i32` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_small2.rs b/tests/compile-fail/intrinsics/float_to_int_64_too_small2.rs new file mode 100644 index 000000000000..f7b205de5346 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_small2.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(-9223372036854777856.0f64); } //~ ERROR: cannot be represented in target type `i64` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_small3.rs b/tests/compile-fail/intrinsics/float_to_int_64_too_small3.rs new file mode 100644 index 000000000000..779441f7448c --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_small3.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(-240282366920938463463374607431768211455.0f64); } //~ ERROR: cannot be represented in target type `i128` +} From a82efce590037c9871292e34adbd4e0a6e031fc8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 12 Apr 2020 22:01:46 +0200 Subject: [PATCH 1855/5092] remove some unnecessary trait bounds --- src/shims/intrinsics.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 8f4bda404d72..0147d72b2386 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -3,7 +3,7 @@ use std::convert::TryFrom; use rustc_ast::ast::FloatTy; use rustc_middle::{mir, ty}; -use rustc_apfloat::{Float, FloatConvert, Round, ieee::{Double, Single}}; +use rustc_apfloat::{Float, Round}; use rustc_target::abi::{Align, LayoutOf, Size}; use crate::*; @@ -515,7 +515,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest_ty: ty::Ty<'tcx>, ) -> InterpResult<'tcx, Scalar> where - F: Float + Into> + FloatConvert + FloatConvert, + F: Float + Into> { let this = self.eval_context_ref(); From 91d7964513adb5aa29d1fa3f657555e110d54474 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 13 Apr 2020 00:41:39 +0200 Subject: [PATCH 1856/5092] rustup --- rust-version | 2 +- src/bin/miri-rustc-tests.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 40c0005e0806..e051ed2ecc5c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0c835b0cca83fe21090562603e4bda77c183ace3 +4d1fbaccb822b6d52dc786589de7918d3c5effb1 diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 97292cf1dbe5..bae7356eb72c 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -41,7 +41,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { .any(|attr| attr.check_name(rustc_span::symbol::sym::test)) { let config = miri::MiriConfig::default(); - let did = self.0.hir().body_owner_def_id(body_id); + let did = self.0.hir().body_owner_def_id(body_id).to_def_id(); println!("running test: {}", self.0.def_path_debug_str(did)); miri::eval_main(self.0, did, config); self.0.sess.abort_if_errors(); From 75297d3536df77155b7413a9b7f453ed5dc01bb6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 13 Apr 2020 09:18:11 +0200 Subject: [PATCH 1857/5092] for alignment errors, note that there might be false positives --- src/diagnostics.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 90e532321e40..c387eed5c41c 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -93,6 +93,11 @@ pub fn report_error<'tcx, 'mir>( vec![format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`")], Unsupported(_) => vec![format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support")], + UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. }) => + vec![ + format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior"), + format!("but alignment errors can also be false positives, see https://github.com/rust-lang/miri/issues/1074"), + ], UndefinedBehavior(_) => vec![ format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior"), From a6b66c31d7587254c71e60fa171827b3277f4a46 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 13 Apr 2020 11:30:02 +0200 Subject: [PATCH 1858/5092] note Miri's leak check abilities and that they are disabled on Windows --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4968e6665712..c3c5bba2c6f9 100644 --- a/README.md +++ b/README.md @@ -17,12 +17,17 @@ for example: * **Experimental**: Violations of the [Stacked Borrows] rules governing aliasing for reference types +On top of that, Miri will also tell you about memory leaks: when there is memory +still allocated at the end of the execution, and that memory is not reachable +from a global `static`, Miri will raise an error. Note however that +[leak checking is currently disabled on Windows targets](https://github.com/rust-lang/miri/issues/1302). + Miri has already discovered some [real-world bugs](#bugs-found-by-miri). If you found a bug with Miri, we'd appreciate if you tell us and we'll add it to the list! -Be aware that Miri will **not catch all cases of undefined behavior** in your -program, and cannot run all programs: +However, be aware that Miri will **not catch all cases of undefined behavior** +in your program, and cannot run all programs: * There are still plenty of open questions around the basic invariants for some types and when these invariants even have to hold. Miri tries to avoid false From 5f6d250b303d839896ead366153997d0e8e013e0 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Mon, 13 Apr 2020 21:18:34 +0530 Subject: [PATCH 1859/5092] [macOS] Implement `mach_timebase_info` Since we return nanoseceonds instead of ticks from `mach_absolute_time`, we don't need to scale the absolute time --- src/shims/foreign_items/posix/macos.rs | 5 +++++ src/shims/time.rs | 22 ++++++++++++++++++++++ tests/run-pass/time.rs | 15 ++++++--------- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 9810a77ffde1..e7baacf7274d 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -60,6 +60,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_u64(result), dest)?; } + "mach_timebase_info" => { + let result = this.mach_timebase_info(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + }, + // Access to command-line arguments "_NSGetArgc" => { this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?; diff --git a/src/shims/time.rs b/src/shims/time.rs index 0d7a4929e4e0..adcca21fb4c0 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -13,6 +13,7 @@ pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Du .map_err(|_| err_unsup_format!("times before the Unix epoch are not supported").into()) } + impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn clock_gettime( @@ -159,4 +160,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx u64::try_from(duration.as_nanos()) .map_err(|_| err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported").into()) } + + fn mach_timebase_info(&mut self, info_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.assert_target_os("macos", "mach_timebase_info"); + this.check_no_isolation("mach_timebase_info")?; + + let info = this.deref_operand(info_op)?; + + // Since we return nanoseceonds instead of ticks from + // `mach_absolute_time`, we don't need to scale the absolute + // time. + let (numer, denom) = (1,1); + let imms = [ + immty_from_int_checked(numer, this.libc_ty_layout("uint32_t")?)?, + immty_from_int_checked(denom, this.libc_ty_layout("uint32_t")?)? + ]; + + this.write_packed_immediates(info, &imms)?; + Ok(0) + } } diff --git a/tests/run-pass/time.rs b/tests/run-pass/time.rs index aa02ac15388e..9ae64fbae42a 100644 --- a/tests/run-pass/time.rs +++ b/tests/run-pass/time.rs @@ -25,13 +25,10 @@ fn main() { let now2 = Instant::now(); assert!(now2 > now1); - #[cfg(not(target_os = "macos"))] // TODO: macOS does not support Instant subtraction - { - let diff = now2.duration_since(now1); - assert_eq!(now1 + diff, now2); - assert_eq!(now2 - diff, now1); - // Sanity-check the difference we got. - assert!(diff.as_micros() > 1); - assert!(diff.as_micros() < 1_000_000); - } + let diff = now2.duration_since(now1); + assert_eq!(now1 + diff, now2); + assert_eq!(now2 - diff, now1); + // Sanity-check the difference we got. + assert!(diff.as_micros() > 1); + assert!(diff.as_micros() < 1_000_000); } From fd8beaf5c4abac980d5730a4e19ec6c1879907b6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 13 Apr 2020 17:51:22 +0200 Subject: [PATCH 1860/5092] add option to disable alignment checks --- src/bin/miri.rs | 5 +++++ src/eval.rs | 4 ++++ src/machine.rs | 17 +++++++++++++++-- .../unaligned_pointers/alignment.rs | 2 +- tests/run-pass/disable-alignment-check.rs | 11 +++++++++++ 5 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 tests/run-pass/disable-alignment-check.rs diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 14d78053c0fd..1ceb6e621a47 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -128,6 +128,7 @@ fn main() { // Parse our arguments and split them across `rustc` and `miri`. let mut validate = true; let mut stacked_borrows = true; + let mut check_alignment = true; let mut communicate = false; let mut ignore_leaks = false; let mut seed: Option = None; @@ -152,6 +153,9 @@ fn main() { "-Zmiri-disable-stacked-borrows" => { stacked_borrows = false; } + "-Zmiri-disable-alignment-check" => { + check_alignment = false; + } "-Zmiri-disable-isolation" => { communicate = true; } @@ -243,6 +247,7 @@ fn main() { let miri_config = miri::MiriConfig { validate, stacked_borrows, + check_alignment, communicate, ignore_leaks, excluded_env_vars, diff --git a/src/eval.rs b/src/eval.rs index 094be194f178..b360b1bd8bbc 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -19,6 +19,8 @@ pub struct MiriConfig { pub validate: bool, /// Determines if Stacked Borrows is enabled. pub stacked_borrows: bool, + /// Determines if alignment checking is enabled. + pub check_alignment: bool, /// Determines if communication with the host environment is enabled. pub communicate: bool, /// Determines if memory leaks should be ignored. @@ -40,6 +42,7 @@ impl Default for MiriConfig { MiriConfig { validate: true, stacked_borrows: true, + check_alignment: true, communicate: false, ignore_leaks: false, excluded_env_vars: vec![], @@ -72,6 +75,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( config.stacked_borrows, config.tracked_pointer_tag, config.tracked_alloc_id, + config.check_alignment, ), ); // Complete initialization. diff --git a/src/machine.rs b/src/machine.rs index 72635f7bf57b..54dfb49d798b 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -118,10 +118,19 @@ pub struct MemoryExtra { /// An allocation ID to report when it is being allocated /// (helps for debugging memory leaks). tracked_alloc_id: Option, + + /// Controls whether alignment of memory accesses is being checked. + check_alignment: bool, } impl MemoryExtra { - pub fn new(rng: StdRng, stacked_borrows: bool, tracked_pointer_tag: Option, tracked_alloc_id: Option) -> Self { + pub fn new( + rng: StdRng, + stacked_borrows: bool, + tracked_pointer_tag: Option, + tracked_alloc_id: Option, + check_alignment: bool, + ) -> Self { let stacked_borrows = if stacked_borrows { Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(tracked_pointer_tag)))) } else { @@ -133,6 +142,7 @@ impl MemoryExtra { extern_statics: FxHashMap::default(), rng: RefCell::new(rng), tracked_alloc_id, + check_alignment, } } @@ -299,7 +309,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { const GLOBAL_KIND: Option = Some(MiriMemoryKind::Global); - const CHECK_ALIGN: bool = true; + #[inline(always)] + fn enforce_alignment(memory_extra: &MemoryExtra) -> bool { + memory_extra.check_alignment + } #[inline(always)] fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { diff --git a/tests/compile-fail/unaligned_pointers/alignment.rs b/tests/compile-fail/unaligned_pointers/alignment.rs index bac1b92075a7..b732a949af87 100644 --- a/tests/compile-fail/unaligned_pointers/alignment.rs +++ b/tests/compile-fail/unaligned_pointers/alignment.rs @@ -2,7 +2,7 @@ fn main() { // miri always gives allocations the worst possible alignment, so a `u8` array is guaranteed // to be at the virtual location 1 (so one byte offset from the ultimate alignemnt location 0) let mut x = [0u8; 20]; - let x_ptr: *mut u8 = &mut x[0]; + let x_ptr: *mut u8 = x.as_mut_ptr(); let y_ptr = x_ptr as *mut u64; unsafe { *y_ptr = 42; //~ ERROR accessing memory with alignment 1, but alignment diff --git a/tests/run-pass/disable-alignment-check.rs b/tests/run-pass/disable-alignment-check.rs new file mode 100644 index 000000000000..2fb0dd8369df --- /dev/null +++ b/tests/run-pass/disable-alignment-check.rs @@ -0,0 +1,11 @@ +// compile-flags: -Zmiri-disable-alignment-check + +fn main() { + let mut x = [0u8; 20]; + let x_ptr: *mut u8 = x.as_mut_ptr(); + // At least one of these is definitely unaligned. + unsafe { + *(x_ptr as *mut u64) = 42; + *(x_ptr.add(1) as *mut u64) = 42; + } +} From 0ad111415387f1e7480dd64fdf7e872045479868 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 13 Apr 2020 17:55:39 +0200 Subject: [PATCH 1861/5092] mention new option in README and diagnostics --- README.md | 2 ++ src/diagnostics.rs | 1 + 2 files changed, 3 insertions(+) diff --git a/README.md b/README.md index 4968e6665712..3df1bef7cbbb 100644 --- a/README.md +++ b/README.md @@ -176,6 +176,8 @@ Several `-Z` flags are relevant for Miri: * `-Zmiri-disable-stacked-borrows` disables checking the experimental [Stacked Borrows] aliasing rules. This can make Miri run faster, but it also means no aliasing violations will be detected. +* `-Zmiri-disable-alignment-check` disables checking pointer alignment on memory + accesses. * `-Zmiri-disable-isolation` disables host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness. diff --git a/src/diagnostics.rs b/src/diagnostics.rs index c387eed5c41c..2359b67323d7 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -97,6 +97,7 @@ pub fn report_error<'tcx, 'mir>( vec![ format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior"), format!("but alignment errors can also be false positives, see https://github.com/rust-lang/miri/issues/1074"), + format!("you can disable the alignment check with `-Zmiri-disable-alignment-check`, but that could hide true bugs") ], UndefinedBehavior(_) => vec![ From f6bb8111f280653c86f220847bd4eb04fa9bebca Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Tue, 14 Apr 2020 09:40:40 +0530 Subject: [PATCH 1862/5092] Use pre-defined u32 layout Also fix typo and remove newline --- src/shims/time.rs | 7 ++++--- tests/run-pass/time.rs | 1 - 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index adcca21fb4c0..835541f9a957 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -169,13 +169,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let info = this.deref_operand(info_op)?; - // Since we return nanoseceonds instead of ticks from + // Since we return nanoseconds instead of ticks from // `mach_absolute_time`, we don't need to scale the absolute // time. let (numer, denom) = (1,1); + let uint32_layout = this.layout_of(this.tcx.types.u32)?; let imms = [ - immty_from_int_checked(numer, this.libc_ty_layout("uint32_t")?)?, - immty_from_int_checked(denom, this.libc_ty_layout("uint32_t")?)? + immty_from_int_checked(numer, uint32_layout)?, + immty_from_int_checked(denom, uint32_layout)? ]; this.write_packed_immediates(info, &imms)?; diff --git a/tests/run-pass/time.rs b/tests/run-pass/time.rs index 9ae64fbae42a..2c9b579f7e29 100644 --- a/tests/run-pass/time.rs +++ b/tests/run-pass/time.rs @@ -24,7 +24,6 @@ fn main() { for _ in 0..10 { drop(vec![42]); } let now2 = Instant::now(); assert!(now2 > now1); - let diff = now2.duration_since(now1); assert_eq!(now1 + diff, now2); assert_eq!(now2 - diff, now1); From 48aaf674f73add4c7d96e03a4d6cd8fa61d5ffbb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Apr 2020 09:26:42 +0200 Subject: [PATCH 1863/5092] tweak flag section in README --- README.md | 54 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 3df1bef7cbbb..88b91d416d4d 100644 --- a/README.md +++ b/README.md @@ -160,31 +160,43 @@ up the sysroot. If you are using `miri` (the Miri driver) directly, see ## Miri `-Z` flags and environment variables [miri-flags]: #miri--z-flags-and-environment-variables -Several `-Z` flags are relevant for Miri: +Miri adds its own set of `-Z` flags: -* `-Zmiri-seed=` is a custom `-Z` flag added by Miri. It configures the - seed of the RNG that Miri uses to resolve non-determinism. This RNG is used - to pick base addresses for allocations. When isolation is enabled (the default), - this is also used to emulate system entropy. The default seed is 0. - **NOTE**: This entropy is not good enough for cryptographic use! Do not - generate secret keys in Miri or perform other kinds of cryptographic - operations that rely on proper random numbers. -* `-Zmiri-disable-validation` disables enforcing validity invariants, which are - enforced by default. This is mostly useful for debugging. It means Miri will - miss bugs in your program. However, this can also help to make Miri run - faster. +* `-Zmiri-disable-alignment-check` disables checking pointer alignment. This is + useful to avoid [false positives][alignment-false-positives]. However, setting + this flag means Miri could miss bugs in your program. * `-Zmiri-disable-stacked-borrows` disables checking the experimental [Stacked Borrows] aliasing rules. This can make Miri run faster, but it also means no aliasing violations will be detected. -* `-Zmiri-disable-alignment-check` disables checking pointer alignment on memory - accesses. +* `-Zmiri-disable-validation` disables enforcing validity invariants, which are + enforced by default. This is mostly useful to focus on other failures (such + as out-of-bounds accesses) first. Setting this flag means Miri will miss bugs + in your program. However, this can also help to make Miri run faster. * `-Zmiri-disable-isolation` disables host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness. -* `-Zmiri-ignore-leaks` disables the memory leak checker. * `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from - the host. Can be used multiple times to exclude several variables. The `TERM` - environment variable is excluded by default. + the host so that it cannot be accessed by the program. Can be used multiple + times to exclude several variables. On Windows, the `TERM` environment + variable is excluded by default. +* `-Zmiri-ignore-leaks` disables the memory leak checker. +* `-Zmiri-seed=` configures the seed of the RNG that Miri uses to resolve + non-determinism. This RNG is used to pick base addresses for allocations. + When isolation is enabled (the default), this is also used to emulate system + entropy. The default seed is 0. **NOTE**: This entropy is not good enough + for cryptographic use! Do not generate secret keys in Miri or perform other + kinds of cryptographic operations that rely on proper random numbers. +* `-Zmiri-track-alloc-id=` shows a backtrace when the given allocation is + being allocated. This helps in debugging memory leaks. +* `-Zmiri-track-pointer-tag=` shows a backtrace when the given pointer tag + is popped from a borrow stack (which is where the tag becomes invalid and any + future use of it will error). This helps you in finding out why UB is + happening and where in your code would be a good place to look for it. + +[alignment-false-positives]: https://github.com/rust-lang/miri/issues/1074 + +Some native rustc `-Z` flags are also very relevant for Miri: + * `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri overrides the default to be `0`; be advised that using any higher level can make Miri miss bugs in your program because they got optimized away. @@ -192,13 +204,7 @@ Several `-Z` flags are relevant for Miri: functions. This is needed so that Miri can execute such functions, so Miri sets this flag per default. * `-Zmir-emit-retag` controls whether `Retag` statements are emitted. Miri - enables this per default because it is needed for validation. -* `-Zmiri-track-pointer-tag=` shows a backtrace when the given pointer tag - is popped from a borrow stack (which is where the tag becomes invalid and any - future use of it will error). This helps you in finding out why UB is - happening and where in your code would be a good place to look for it. -* `-Zmiri-track-alloc-id=` shows a backtrace when the given allocation is - being allocated. This helps in debugging memory leaks. + enables this per default because it is needed for [Stacked Borrows]. Moreover, Miri recognizes some environment variables: From 8e73db6510f1ca8625dc4efe3791cc9f37a7c915 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Apr 2020 09:26:47 +0200 Subject: [PATCH 1864/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index e051ed2ecc5c..48247d653cdc 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4d1fbaccb822b6d52dc786589de7918d3c5effb1 +47f49695dfb4fe9e584239fdc59c771887148a57 From f4a15444cf90452876733549731ab94517656e8b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Apr 2020 09:50:20 +0200 Subject: [PATCH 1865/5092] fix comment in alignment test --- tests/compile-fail/unaligned_pointers/alignment.rs | 8 ++++---- .../unaligned_pointers/intptrcast_alignment_check.rs | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/compile-fail/unaligned_pointers/alignment.rs b/tests/compile-fail/unaligned_pointers/alignment.rs index b732a949af87..8532f91a5c00 100644 --- a/tests/compile-fail/unaligned_pointers/alignment.rs +++ b/tests/compile-fail/unaligned_pointers/alignment.rs @@ -1,11 +1,11 @@ fn main() { - // miri always gives allocations the worst possible alignment, so a `u8` array is guaranteed - // to be at the virtual location 1 (so one byte offset from the ultimate alignemnt location 0) let mut x = [0u8; 20]; let x_ptr: *mut u8 = x.as_mut_ptr(); - let y_ptr = x_ptr as *mut u64; + // At least one of these is definitely unaligned. + // Currently, we guarantee to complain about the first one already (https://github.com/rust-lang/miri/issues/1074). unsafe { - *y_ptr = 42; //~ ERROR accessing memory with alignment 1, but alignment + *(x_ptr as *mut u64) = 42; //~ ERROR accessing memory with alignment 1, but alignment + *(x_ptr.add(1) as *mut u64) = 42; } panic!("unreachable in miri"); } diff --git a/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs b/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs index 1a8df5eacede..0a3b48dab5a0 100644 --- a/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs +++ b/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs @@ -2,6 +2,8 @@ // that arise from pointers being insufficiently aligned. The only way to achieve // that is not not let programs exploit integer information for alignment, so here // we test that this is indeed the case. +// +// See https://github.com/rust-lang/miri/issues/1074. fn main() { let x = &mut [0u8; 3]; let base_addr = x as *mut _ as usize; From 90729bb0394d64ee93026410480e8155c92ab7e5 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Tue, 14 Apr 2020 13:31:24 +0530 Subject: [PATCH 1866/5092] Use precomputed TyLayout from `machine.layouts` And add comment documenting successful return value from `mach_timebase_info`. --- src/shims/time.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index 835541f9a957..c22ac9ca1a50 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -173,13 +173,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `mach_absolute_time`, we don't need to scale the absolute // time. let (numer, denom) = (1,1); - let uint32_layout = this.layout_of(this.tcx.types.u32)?; let imms = [ - immty_from_int_checked(numer, uint32_layout)?, - immty_from_int_checked(denom, uint32_layout)? + immty_from_int_checked(numer, this.machine.layouts.u32)?, + immty_from_int_checked(denom, this.machine.layouts.u32)? ]; this.write_packed_immediates(info, &imms)?; - Ok(0) + Ok(0) // KERN_SUCCESS } } From 179e78d0ad95c60689f0df4cc6e3491b53b586ad Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Apr 2020 09:58:58 +0200 Subject: [PATCH 1867/5092] make sure our disable flags do not miss all bugs; move type-assert intrinsic tests to their folder --- .../dangling_pointers/dangling_pointer_deref.rs | 3 +++ .../compile-fail/dangling_pointers/dangling_zst_deref.rs | 3 +++ .../{ => intrinsics}/uninit_uninhabited_type.rs | 2 +- tests/compile-fail/intrinsics/zero_fn_ptr.rs | 6 ++++++ tests/compile-fail/invalid_bool.rs | 3 ++- tests/compile-fail/invalid_char.rs | 3 ++- tests/compile-fail/invalid_enum_discriminant.rs | 3 ++- tests/compile-fail/invalid_int.rs | 8 ++++++++ tests/compile-fail/invalid_zero_init.rs | 6 ------ ...writing_part_of_relocation_makes_the_rest_undefined.rs | 3 +++ 10 files changed, 30 insertions(+), 10 deletions(-) rename tests/compile-fail/{ => intrinsics}/uninit_uninhabited_type.rs (53%) create mode 100644 tests/compile-fail/intrinsics/zero_fn_ptr.rs create mode 100644 tests/compile-fail/invalid_int.rs delete mode 100644 tests/compile-fail/invalid_zero_init.rs diff --git a/tests/compile-fail/dangling_pointers/dangling_pointer_deref.rs b/tests/compile-fail/dangling_pointers/dangling_pointer_deref.rs index f2c7ec584fef..e088a5532581 100644 --- a/tests/compile-fail/dangling_pointers/dangling_pointer_deref.rs +++ b/tests/compile-fail/dangling_pointers/dangling_pointer_deref.rs @@ -1,3 +1,6 @@ +// Make sure we find these even with many checks disabled. +// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation + fn main() { let p = { let b = Box::new(42); diff --git a/tests/compile-fail/dangling_pointers/dangling_zst_deref.rs b/tests/compile-fail/dangling_pointers/dangling_zst_deref.rs index 13e5f9d32173..f1b5149dabb4 100644 --- a/tests/compile-fail/dangling_pointers/dangling_zst_deref.rs +++ b/tests/compile-fail/dangling_pointers/dangling_zst_deref.rs @@ -1,3 +1,6 @@ +// Make sure we find these even with many checks disabled. +// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation + fn main() { let p = { let b = Box::new(42); diff --git a/tests/compile-fail/uninit_uninhabited_type.rs b/tests/compile-fail/intrinsics/uninit_uninhabited_type.rs similarity index 53% rename from tests/compile-fail/uninit_uninhabited_type.rs rename to tests/compile-fail/intrinsics/uninit_uninhabited_type.rs index b9048830783f..deb3586c781e 100644 --- a/tests/compile-fail/uninit_uninhabited_type.rs +++ b/tests/compile-fail/intrinsics/uninit_uninhabited_type.rs @@ -1,4 +1,4 @@ - // error-pattern: the evaluated program aborted execution: attempted to instantiate uninhabited type `!` +// error-pattern: the evaluated program aborted execution: attempted to instantiate uninhabited type `!` #![feature(never_type)] #[allow(deprecated, invalid_value)] diff --git a/tests/compile-fail/intrinsics/zero_fn_ptr.rs b/tests/compile-fail/intrinsics/zero_fn_ptr.rs new file mode 100644 index 000000000000..81dbf6c429b3 --- /dev/null +++ b/tests/compile-fail/intrinsics/zero_fn_ptr.rs @@ -0,0 +1,6 @@ +// error-pattern: the evaluated program aborted execution: attempted to zero-initialize type `fn()`, which is invalid + +#[allow(deprecated, invalid_value)] +fn main() { + unsafe { std::mem::zeroed::() }; +} diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index 6ccea3531636..38033146ade8 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -1,5 +1,6 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmiri-disable-validation +// Make sure we find these even with many checks disabled. +// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation fn main() { let b = unsafe { std::mem::transmute::(2) }; diff --git a/tests/compile-fail/invalid_char.rs b/tests/compile-fail/invalid_char.rs index ed61fcbe9d52..ab10ab1e2173 100644 --- a/tests/compile-fail/invalid_char.rs +++ b/tests/compile-fail/invalid_char.rs @@ -1,5 +1,6 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmiri-disable-validation +// Make sure we find these even with many checks disabled. +// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); diff --git a/tests/compile-fail/invalid_enum_discriminant.rs b/tests/compile-fail/invalid_enum_discriminant.rs index c1b8727c129b..cdbea6aa1223 100644 --- a/tests/compile-fail/invalid_enum_discriminant.rs +++ b/tests/compile-fail/invalid_enum_discriminant.rs @@ -1,5 +1,6 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmiri-disable-validation +// Make sure we find these even with many checks disabled. +// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation // error-pattern: invalid enum discriminant diff --git a/tests/compile-fail/invalid_int.rs b/tests/compile-fail/invalid_int.rs new file mode 100644 index 000000000000..26a85802079b --- /dev/null +++ b/tests/compile-fail/invalid_int.rs @@ -0,0 +1,8 @@ +// Validation makes this fail in the wrong place +// Make sure we find these even with many checks disabled. +// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation + +fn main() { + let i = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + let _x = i + 0; //~ ERROR this operation requires initialized memory +} diff --git a/tests/compile-fail/invalid_zero_init.rs b/tests/compile-fail/invalid_zero_init.rs deleted file mode 100644 index 78c2b0fbeeb7..000000000000 --- a/tests/compile-fail/invalid_zero_init.rs +++ /dev/null @@ -1,6 +0,0 @@ - // error-pattern: the evaluated program aborted execution: attempted to zero-initialize type `fn()`, which is invalid - -#[allow(deprecated, invalid_value)] -fn main() { - unsafe { std::mem::zeroed::() }; -} diff --git a/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs b/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs index d8182aaae662..3eab4c0f3d5e 100644 --- a/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs +++ b/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs @@ -1,3 +1,6 @@ +// Make sure we find these even with many checks disabled. +// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation + fn main() { let mut p = &42; unsafe { From e6822d60b3e2cc63ff0ae4603b1021cd0fb4dae8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Apr 2020 10:03:10 +0200 Subject: [PATCH 1868/5092] make sure we find some things without validation or stacked borrows, respectively --- tests/compile-fail/stacked_borrows/load_invalid_mut.rs | 3 +++ tests/compile-fail/stacked_borrows/load_invalid_shr.rs | 3 +++ tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs | 4 ++-- tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs | 4 ++-- tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs | 4 ++-- tests/compile-fail/validity/dangling_ref1.rs | 2 ++ tests/compile-fail/validity/dangling_ref2.rs | 2 ++ tests/compile-fail/validity/dangling_ref3.rs | 2 ++ 8 files changed, 18 insertions(+), 6 deletions(-) diff --git a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs index 1704b7fe19b2..c2c4ce6726df 100644 --- a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs @@ -1,3 +1,6 @@ +// Make sure we catch this even without validation +// compile-flags: -Zmiri-disable-validation + // Make sure that we cannot load from memory a `&mut` that got already invalidated. fn main() { let x = &mut 42; diff --git a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs index 4757a2c1e589..7d681f649a10 100644 --- a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs @@ -1,3 +1,6 @@ +// Make sure we catch this even without validation +// compile-flags: -Zmiri-disable-validation + // Make sure that we cannot load from memory a `&` that got already invalidated. fn main() { let x = &mut 42; diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs index ee1a13004231..0a67cfc5a1b3 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs @@ -1,5 +1,5 @@ -// This should fail even without validation -// compile-flags: -Zmiri-disable-validation +// This should fail even without validation or Stacked Borrows. +// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs index 853d890ecf07..b1fb2f4aa976 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs @@ -1,5 +1,5 @@ -// This should fail even without validation. -// compile-flags: -Zmiri-disable-validation +// This should fail even without validation or Stacked Borrows. +// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { let x = [2u32, 3]; // Make it big enough so we don't get an out-of-bounds error. diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs index 43f6b472da05..c5a3398384e4 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs @@ -1,5 +1,5 @@ -// This should fail even without validation. -// compile-flags: -Zmiri-disable-validation +// This should fail even without validation or Stacked Borrows. +// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { let x = [2u16, 3, 4, 5]; // Make it big enough so we don't get an out-of-bounds error. diff --git a/tests/compile-fail/validity/dangling_ref1.rs b/tests/compile-fail/validity/dangling_ref1.rs index 034510f3b283..a83c6af21acf 100644 --- a/tests/compile-fail/validity/dangling_ref1.rs +++ b/tests/compile-fail/validity/dangling_ref1.rs @@ -1,3 +1,5 @@ +// Make sure we catch this even without Stacked Borrows +// compile-flags: -Zmiri-disable-stacked-borrows use std::mem; fn main() { diff --git a/tests/compile-fail/validity/dangling_ref2.rs b/tests/compile-fail/validity/dangling_ref2.rs index 4ad9b8135db4..7aff1a49785c 100644 --- a/tests/compile-fail/validity/dangling_ref2.rs +++ b/tests/compile-fail/validity/dangling_ref2.rs @@ -1,3 +1,5 @@ +// Make sure we catch this even without Stacked Borrows +// compile-flags: -Zmiri-disable-stacked-borrows use std::mem; fn main() { diff --git a/tests/compile-fail/validity/dangling_ref3.rs b/tests/compile-fail/validity/dangling_ref3.rs index 46e17375a828..495a266a85dc 100644 --- a/tests/compile-fail/validity/dangling_ref3.rs +++ b/tests/compile-fail/validity/dangling_ref3.rs @@ -1,3 +1,5 @@ +// Make sure we catch this even without Stacked Borrows +// compile-flags: -Zmiri-disable-stacked-borrows use std::mem; fn dangling() -> *const u8 { From fff45b77adc7a08b1ee2d3c277e74f2ec7027ea2 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Tue, 14 Apr 2020 13:59:43 +0530 Subject: [PATCH 1869/5092] Reword comment in mach_timebase_info Co-Authored-By: Ralf Jung --- src/shims/time.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index c22ac9ca1a50..a87db9878202 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -169,9 +169,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let info = this.deref_operand(info_op)?; - // Since we return nanoseconds instead of ticks from - // `mach_absolute_time`, we don't need to scale the absolute - // time. + // Since our emulated ticks in `mach_absolute_time` *are* nanoseconds, + // no scaling needs to happen. let (numer, denom) = (1,1); let imms = [ immty_from_int_checked(numer, this.machine.layouts.u32)?, From 90d71cd13f26c50f1d1904eb3b436c4e1faf7d2c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 13 Apr 2020 16:08:12 +0200 Subject: [PATCH 1870/5092] adjust for frame hook changes --- src/machine.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 54dfb49d798b..67b847603d8a 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -490,21 +490,25 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } #[inline(always)] - fn stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, FrameData<'tcx>> { + fn init_frame_extra( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + frame: Frame<'mir, 'tcx, Tag>, + ) -> InterpResult<'tcx, Frame<'mir, 'tcx, Tag, FrameData<'tcx>>> { let stacked_borrows = ecx.memory.extra.stacked_borrows.as_ref(); let call_id = stacked_borrows.map_or(NonZeroU64::new(1).unwrap(), |stacked_borrows| { stacked_borrows.borrow_mut().new_call() }); - Ok(FrameData { call_id, catch_unwind: None }) + let extra = FrameData { call_id, catch_unwind: None }; + Ok(frame.with_extra(extra)) } #[inline(always)] - fn stack_pop( + fn after_stack_pop( ecx: &mut InterpCx<'mir, 'tcx, Self>, - extra: FrameData<'tcx>, + frame: Frame<'mir, 'tcx, Tag, FrameData<'tcx>>, unwinding: bool, ) -> InterpResult<'tcx, StackPopJump> { - ecx.handle_stack_pop(extra, unwinding) + ecx.handle_stack_pop(frame.extra, unwinding) } #[inline(always)] From 0805b4bf2e6070a6e2f1026624dee87b65ee4ed7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 13 Apr 2020 17:31:19 +0200 Subject: [PATCH 1871/5092] retag return places --- src/machine.rs | 16 ++++++++++++---- src/stacked_borrows.rs | 43 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 67b847603d8a..94603c3dfb4d 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -481,11 +481,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { kind: mir::RetagKind, place: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { - if ecx.memory.extra.stacked_borrows.is_none() { - // No tracking. - Ok(()) - } else { + if ecx.memory.extra.stacked_borrows.is_some() { ecx.retag(kind, place) + } else { + Ok(()) } } @@ -502,6 +501,15 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { Ok(frame.with_extra(extra)) } + #[inline(always)] + fn after_stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { + if ecx.memory.extra.stacked_borrows.is_some() { + ecx.retag_return_place() + } else { + Ok(()) + } + } + #[inline(always)] fn after_stack_pop( ecx: &mut InterpCx<'mir, 'tcx, Self>, diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 89b2a8bb3e2b..a69948002c12 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -11,7 +11,7 @@ use log::trace; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_middle::mir::RetagKind; use rustc_middle::ty; -use rustc_target::abi::Size; +use rustc_target::abi::{LayoutOf, Size}; use rustc_hir::Mutability; use crate::*; @@ -569,7 +569,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx val: ImmTy<'tcx, Tag>, kind: RefKind, protect: bool, - ) -> InterpResult<'tcx, Immediate> { + ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let this = self.eval_context_mut(); // We want a place for where the ptr *points to*, so we get one. let place = this.ref_to_mplace(val)?; @@ -582,7 +582,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let place = this.mplace_access_checked(place)?; if size == Size::ZERO { // Nothing to do for ZSTs. - return Ok(*val); + return Ok(val); } // Compute new borrow. @@ -603,7 +603,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let new_place = place.replace_tag(new_tag); // Return new pointer. - Ok(new_place.to_ref()) + Ok(ImmTy::from_immediate(new_place.to_ref(), val.layout)) } } @@ -640,9 +640,42 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Fast path. let val = this.read_immediate(this.place_to_op(place)?)?; let val = this.retag_reference(val, mutbl, protector)?; - this.write_immediate(val, place)?; + this.write_immediate(*val, place)?; } Ok(()) } + + /// After a stack frame got pushed, retag the return place so that we are sure + /// it does not alias with anything. + /// + /// This is a HACK because there is nothing in MIR that would make the retag + /// explicit. Also see https://github.com/rust-lang/rust/issues/71117. + fn retag_return_place(&mut self) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let return_place = if let Some(return_place) = this.frame_mut().return_place { + return_place + } else { + // No return place, nothing to do. + return Ok(()); + }; + if return_place.layout.is_zst() { + // There may not be any memory here, nothing to do. + return Ok(()); + } + // We need this to be in-memory to use tagged pointers. + let return_place = this.force_allocation(return_place)?; + + // We have to turn the place into a pointer to use the existing code. + // (The pointer type does not matter, so we use a raw pointer.) + let ptr_layout = this.layout_of(this.tcx.mk_mut_ptr(return_place.layout.ty))?; + let val = ImmTy::from_immediate(return_place.to_ref(), ptr_layout); + // Reborrow it. + let val = this.retag_reference(val, RefKind::Unique { two_phase: false }, /*protector*/ true)?; + // And use reborrowed pointer for return place. + let return_place = this.ref_to_mplace(val)?; + this.frame_mut().return_place = Some(return_place.into()); + + Ok(()) + } } From 3548dcf8cc3021dcfe425df90d7feb14c0bdda61 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 Apr 2020 12:39:28 +0200 Subject: [PATCH 1872/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 48247d653cdc..937073ef4fcc 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -47f49695dfb4fe9e584239fdc59c771887148a57 +df768c5c8fcb361c4dc94b4c776d6a78c12862e1 From a85dab42ea2f5704260232112d240b1ee51017be Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 Apr 2020 12:41:54 +0200 Subject: [PATCH 1873/5092] tighten Instance sanity check --- tests/run-pass/time.rs | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/tests/run-pass/time.rs b/tests/run-pass/time.rs index 2c9b579f7e29..d430062a1533 100644 --- a/tests/run-pass/time.rs +++ b/tests/run-pass/time.rs @@ -1,22 +1,29 @@ // compile-flags: -Zmiri-disable-isolation -use std::time::{SystemTime, Instant}; +use std::time::{SystemTime, Instant, Duration}; + +fn duration_sanity(diff: Duration) { + // On my laptop, I observed times around 15-40ms. Add 10x lee-way both ways. + assert!(diff.as_millis() > 1); + assert!(diff.as_millis() < 500); +} fn main() { // Check `SystemTime`. let now1 = SystemTime::now(); - // Do some work to make time pass. - for _ in 0..10 { drop(vec![42]); } - let now2 = SystemTime::now(); - assert!(now2 > now1); - let diff = now2.duration_since(now1).unwrap(); - assert_eq!(now1 + diff, now2); - assert_eq!(now2 - diff, now1); - // Sanity-check the time we got. let seconds_since_epoch = now1.duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs(); let years_since_epoch = seconds_since_epoch / 3600 / 24 / 365; let year = 1970 + years_since_epoch; assert!(2020 <= year && year < 2100); + // Do some work to make time pass. + for _ in 0..10 { drop(vec![42]); } + let now2 = SystemTime::now(); + assert!(now2 > now1); + // Sanity-check the difference we got. + let diff = now2.duration_since(now1).unwrap(); + assert_eq!(now1 + diff, now2); + assert_eq!(now2 - diff, now1); + duration_sanity(diff); // Check `Instant`. let now1 = Instant::now(); @@ -24,10 +31,9 @@ fn main() { for _ in 0..10 { drop(vec![42]); } let now2 = Instant::now(); assert!(now2 > now1); + // Sanity-check the difference we got. let diff = now2.duration_since(now1); assert_eq!(now1 + diff, now2); assert_eq!(now2 - diff, now1); - // Sanity-check the difference we got. - assert!(diff.as_micros() > 1); - assert!(diff.as_micros() < 1_000_000); + duration_sanity(diff); } From b77968e8bd2bc556d0bd3cfb9f7d2521a6896199 Mon Sep 17 00:00:00 2001 From: Ozaren Date: Tue, 14 Apr 2020 19:00:56 -0400 Subject: [PATCH 1874/5092] added deallocation tracking --- README.md | 3 ++- src/diagnostics.rs | 3 +++ src/machine.rs | 14 +++++++++++++- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 76f95ee55e80..a86de4a55519 100644 --- a/README.md +++ b/README.md @@ -192,7 +192,8 @@ Miri adds its own set of `-Z` flags: for cryptographic use! Do not generate secret keys in Miri or perform other kinds of cryptographic operations that rely on proper random numbers. * `-Zmiri-track-alloc-id=` shows a backtrace when the given allocation is - being allocated. This helps in debugging memory leaks. + being allocated or freed. This helps in debugging memory leaks and + use after free bugs. * `-Zmiri-track-pointer-tag=` shows a backtrace when the given pointer tag is popped from a borrow stack (which is where the tag becomes invalid and any future use of it will error). This helps you in finding out why UB is diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 2359b67323d7..8c7bb8a47c63 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -42,6 +42,7 @@ impl MachineStopType for TerminationInfo {} pub enum NonHaltingDiagnostic { PoppedTrackedPointerTag(Item), CreatedAlloc(AllocId), + FreedAlloc(AllocId), } /// Emit a custom diagnostic without going through the miri-engine machinery @@ -191,6 +192,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx format!("popped tracked tag for item {:?}", item), CreatedAlloc(AllocId(id)) => format!("created allocation with id {}", id), + FreedAlloc(AllocId(id)) => + format!("freed allocation with id {}", id), }; report_msg(this, "tracking was triggered", msg, vec![], false); } diff --git a/src/machine.rs b/src/machine.rs index 94603c3dfb4d..5cf42df8268b 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -116,7 +116,7 @@ pub struct MemoryExtra { pub(crate) rng: RefCell, /// An allocation ID to report when it is being allocated - /// (helps for debugging memory leaks). + /// (helps for debugging memory leaks and use after free bugs). tracked_alloc_id: Option, /// Controls whether alignment of memory accesses is being checked. @@ -466,6 +466,18 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { (Cow::Owned(alloc), base_tag) } + #[inline(always)] + fn before_deallocation( + memory_extra: &mut Self::MemoryExtra, + id: AllocId, + ) -> InterpResult<'tcx> { + if Some(id) == memory_extra.tracked_alloc_id { + register_diagnostic(NonHaltingDiagnostic::FreedAlloc(id)); + } + + Ok(()) + } + #[inline(always)] fn tag_global_base_pointer(memory_extra: &MemoryExtra, id: AllocId) -> Self::PointerTag { if let Some(stacked_borrows) = &memory_extra.stacked_borrows { From 07c696e27e0398f4bf1b77db09fadef1591d28e4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 Apr 2020 18:00:16 +0200 Subject: [PATCH 1875/5092] test some so-far untested intrinsics --- src/shims/intrinsics.rs | 4 +++- tests/run-pass/intrinsics.rs | 17 +++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 0f17bee00887..0979cd7f062d 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -471,7 +471,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "exact_div" => this.exact_div(this.read_immediate(args[0])?, this.read_immediate(args[1])?, dest)?, - "forget" => {} + "forget" => { + // We get an argument... and forget about it. + } #[rustfmt::skip] | "likely" diff --git a/tests/run-pass/intrinsics.rs b/tests/run-pass/intrinsics.rs index 754a38f63535..63439c996af0 100644 --- a/tests/run-pass/intrinsics.rs +++ b/tests/run-pass/intrinsics.rs @@ -1,8 +1,16 @@ #![feature(core_intrinsics)] -use std::intrinsics::type_name; +use std::intrinsics; use std::mem::{size_of, size_of_val}; +struct Bomb; + +impl Drop for Bomb { + fn drop(&mut self) { + eprintln!("BOOM!"); + } +} + fn main() { assert_eq!(size_of::>(), 8); assert_eq!(size_of_val(&()), 0); @@ -11,5 +19,10 @@ fn main() { assert_eq!(size_of_val(&[1, 2, 3] as &[i32]), 12); assert_eq!(size_of_val("foobar"), 6); - assert_eq!(type_name::>(), "core::option::Option"); + assert_eq!(intrinsics::type_name::>(), "core::option::Option"); + + assert_eq!(intrinsics::likely(false), false); + assert_eq!(intrinsics::unlikely(true), true); + + unsafe { intrinsics::forget(Bomb); } } From b0fe99e81defb29e7e6920f5307f4d940dd718fa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 16 Apr 2020 09:06:21 +0200 Subject: [PATCH 1876/5092] consolidate ptr tests in fewer files --- tests/run-pass/ptr_arith_offset.rs | 6 --- tests/run-pass/ptr_arith_offset_overflow.rs | 12 ----- tests/run-pass/ptr_int_casts.rs | 28 ++++++++++- tests/run-pass/ptr_int_ops.rs | 20 -------- tests/run-pass/ptr_offset.rs | 56 ++++++++++++++++++++- tests/run-pass/ptr_offset_from.rs | 29 ----------- tests/run-pass/{raw.rs => ptr_raw.rs} | 0 7 files changed, 81 insertions(+), 70 deletions(-) delete mode 100644 tests/run-pass/ptr_arith_offset.rs delete mode 100644 tests/run-pass/ptr_arith_offset_overflow.rs delete mode 100644 tests/run-pass/ptr_int_ops.rs delete mode 100644 tests/run-pass/ptr_offset_from.rs rename tests/run-pass/{raw.rs => ptr_raw.rs} (100%) diff --git a/tests/run-pass/ptr_arith_offset.rs b/tests/run-pass/ptr_arith_offset.rs deleted file mode 100644 index a6ee151e3e13..000000000000 --- a/tests/run-pass/ptr_arith_offset.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn main() { - let v = [1i16, 2]; - let x = &v as *const [i16] as *const i16; - let x = x.wrapping_offset(1); - assert_eq!(unsafe { *x }, 2); -} diff --git a/tests/run-pass/ptr_arith_offset_overflow.rs b/tests/run-pass/ptr_arith_offset_overflow.rs deleted file mode 100644 index fdd980e2177b..000000000000 --- a/tests/run-pass/ptr_arith_offset_overflow.rs +++ /dev/null @@ -1,12 +0,0 @@ -use std::ptr; - -fn main() { - let v = [1i16, 2]; - let x = &mut ptr::null(); // going through memory as there are more sanity checks along that path - *x = v.as_ptr().wrapping_offset(1); // ptr to the 2nd element - // Adding 2*isize::max and then 1 is like substracting 1 - *x = x.wrapping_offset(isize::MAX); - *x = x.wrapping_offset(isize::MAX); - *x = x.wrapping_offset(1); - assert_eq!(unsafe { **x }, 1); -} diff --git a/tests/run-pass/ptr_int_casts.rs b/tests/run-pass/ptr_int_casts.rs index 468b37af5bea..b9815126a8c7 100644 --- a/tests/run-pass/ptr_int_casts.rs +++ b/tests/run-pass/ptr_int_casts.rs @@ -7,7 +7,7 @@ fn eq_ref(x: &T, y: &T) -> bool { fn f() -> i32 { 42 } -fn main() { +fn ptr_int_casts() { // int-ptr-int assert_eq!(1 as *const i32 as usize, 1); assert_eq!((1 as *const i32).wrapping_offset(4) as usize, 1 + 4*4); @@ -40,3 +40,29 @@ fn main() { // involving types other than usize assert_eq!((-1i32) as usize as *const i32 as usize, (-1i32) as usize); } + +fn ptr_int_ops() { + let v = [1i16, 2]; + let x = &v[1] as *const i16 as usize; + // arithmetic + let _y = x + 4; + let _y = 4 + x; + let _y = x - 2; + // bit-operations, covered by alignment + assert_eq!(x & 1, 0); + assert_eq!(x & 0, 0); + assert_eq!(1 & (x+1), 1); + let _y = !1 & x; + let _y = !0 & x; + let _y = x & !1; + // remainder, covered by alignment + assert_eq!(x % 2, 0); + assert_eq!((x+1) % 2, 1); + // remainder with 1 is always 0 + assert_eq!(x % 1, 0); +} + +fn main() { + ptr_int_casts(); + ptr_int_ops(); +} diff --git a/tests/run-pass/ptr_int_ops.rs b/tests/run-pass/ptr_int_ops.rs deleted file mode 100644 index 9a29c2d30837..000000000000 --- a/tests/run-pass/ptr_int_ops.rs +++ /dev/null @@ -1,20 +0,0 @@ -fn main() { - let v = [1i16, 2]; - let x = &v[1] as *const i16 as usize; - // arithmetic - let _y = x + 4; - let _y = 4 + x; - let _y = x - 2; - // bit-operations, covered by alignment - assert_eq!(x & 1, 0); - assert_eq!(x & 0, 0); - assert_eq!(1 & (x+1), 1); - let _y = !1 & x; - let _y = !0 & x; - let _y = x & !1; - // remainder, covered by alignment - assert_eq!(x % 2, 0); - assert_eq!((x+1) % 2, 1); - // remainder with 1 is always 0 - assert_eq!(x % 1, 0); -} diff --git a/tests/run-pass/ptr_offset.rs b/tests/run-pass/ptr_offset.rs index 1c7f0eb71797..f83720b547c0 100644 --- a/tests/run-pass/ptr_offset.rs +++ b/tests/run-pass/ptr_offset.rs @@ -1,6 +1,58 @@ -fn f() -> i32 { 42 } +#![feature(ptr_offset_from)] +use std::{mem, ptr}; fn main() { + test_offset_from(); + test_vec_into_iter(); + ptr_arith_offset(); + ptr_arith_offset_overflow(); + ptr_offset(); +} + +fn test_offset_from() { unsafe { + let buf = [0u32; 4]; + + let x = buf.as_ptr() as *const u8; + let y = x.offset(12); + + assert_eq!(y.offset_from(x), 12); + assert_eq!(x.offset_from(y), -12); + assert_eq!((y as *const u32).offset_from(x as *const u32), 12/4); + assert_eq!((x as *const u32).offset_from(y as *const u32), -12/4); + + let x = (((x as usize) * 2) / 2) as *const u8; + assert_eq!(y.offset_from(x), 12); + assert_eq!(x.offset_from(y), -12); +} } + +// This also internally uses offset_from. +fn test_vec_into_iter() { + let v = Vec::::new(); + let i = v.into_iter(); + i.size_hint(); +} + +fn ptr_arith_offset() { + let v = [1i16, 2]; + let x = &v as *const [i16] as *const i16; + let x = x.wrapping_offset(1); + assert_eq!(unsafe { *x }, 2); +} + +fn ptr_arith_offset_overflow() { + let v = [1i16, 2]; + let x = &mut ptr::null(); // going through memory as there are more sanity checks along that path + *x = v.as_ptr().wrapping_offset(1); // ptr to the 2nd element + // Adding 2*isize::max and then 1 is like substracting 1 + *x = x.wrapping_offset(isize::MAX); + *x = x.wrapping_offset(isize::MAX); + *x = x.wrapping_offset(1); + assert_eq!(unsafe { **x }, 1); +} + +fn ptr_offset() { + fn f() -> i32 { 42 } + let v = [1i16, 2]; let x = &v as *const [i16; 2] as *const i16; let x = unsafe { x.offset(1) }; @@ -10,7 +62,7 @@ fn main() { unsafe { let p = f as fn() -> i32 as usize; let x = (p as *mut u32).offset(0) as usize; - let f: fn() -> i32 = std::mem::transmute(x); + let f: fn() -> i32 = mem::transmute(x); assert_eq!(f(), 42); } } diff --git a/tests/run-pass/ptr_offset_from.rs b/tests/run-pass/ptr_offset_from.rs deleted file mode 100644 index 92eb3f6e46e3..000000000000 --- a/tests/run-pass/ptr_offset_from.rs +++ /dev/null @@ -1,29 +0,0 @@ -#![feature(ptr_offset_from)] - -fn test_raw() { unsafe { - let buf = [0u32; 4]; - - let x = buf.as_ptr() as *const u8; - let y = x.offset(12); - - assert_eq!(y.offset_from(x), 12); - assert_eq!(x.offset_from(y), -12); - assert_eq!((y as *const u32).offset_from(x as *const u32), 12/4); - assert_eq!((x as *const u32).offset_from(y as *const u32), -12/4); - - let x = (((x as usize) * 2) / 2) as *const u8; - assert_eq!(y.offset_from(x), 12); - assert_eq!(x.offset_from(y), -12); -} } - -// This also internally uses offset_from. -fn test_vec_into_iter() { - let v = Vec::::new(); - let i = v.into_iter(); - i.size_hint(); -} - -fn main() { - test_raw(); - test_vec_into_iter(); -} diff --git a/tests/run-pass/raw.rs b/tests/run-pass/ptr_raw.rs similarity index 100% rename from tests/run-pass/raw.rs rename to tests/run-pass/ptr_raw.rs From 974f9c30239a550ab8ccef75dd409ebb1faacf89 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 16 Apr 2020 09:25:12 +0200 Subject: [PATCH 1877/5092] avoid test-wide allowance of unused/dead code --- tests/run-pass/bitop-beyond-alignment.rs | 3 +-- tests/run-pass/dst-field-align.rs | 4 ++-- tests/run-pass/foreign-fn-linkname.rs | 2 -- tests/run-pass/issue-15063.rs | 3 +-- tests/run-pass/issue-35815.rs | 3 +-- tests/run-pass/issue-53728.rs | 6 ++++-- tests/run-pass/libc.rs | 8 +++----- tests/run-pass/packed_struct.rs | 4 +++- tests/run-pass/regions-mock-trans.rs | 4 ++-- tests/run-pass/rfc1623.rs | 2 +- tests/run-pass/small_enum_size_bug.rs | 3 +-- tests/run-pass/static_mut.rs | 3 +-- tests/run-pass/tag-align-dyn-u64.rs | 3 +-- tests/run-pass/union.rs | 5 +++-- 14 files changed, 24 insertions(+), 29 deletions(-) diff --git a/tests/run-pass/bitop-beyond-alignment.rs b/tests/run-pass/bitop-beyond-alignment.rs index 02031130b8dc..e540a2a4b723 100644 --- a/tests/run-pass/bitop-beyond-alignment.rs +++ b/tests/run-pass/bitop-beyond-alignment.rs @@ -8,14 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(dead_code)] - use std::mem; enum Tag { Tag2(A) } +#[allow(dead_code)] struct Rec { c8: u8, t: Tag diff --git a/tests/run-pass/dst-field-align.rs b/tests/run-pass/dst-field-align.rs index 7cd0c851b638..6c827d7b3bea 100644 --- a/tests/run-pass/dst-field-align.rs +++ b/tests/run-pass/dst-field-align.rs @@ -1,5 +1,4 @@ -#![allow(dead_code)] - +#[allow(dead_code)] struct Foo { a: u16, b: T @@ -17,6 +16,7 @@ struct Baz { a: T } +#[allow(dead_code)] struct HasDrop { ptr: Box, data: T diff --git a/tests/run-pass/foreign-fn-linkname.rs b/tests/run-pass/foreign-fn-linkname.rs index ebb0e5364b94..60303c7d7c7c 100644 --- a/tests/run-pass/foreign-fn-linkname.rs +++ b/tests/run-pass/foreign-fn-linkname.rs @@ -1,7 +1,5 @@ //ignore-windows: Uses POSIX APIs - #![feature(rustc_private)] -#![allow(unused_extern_crates)] // rustc bug https://github.com/rust-lang/rust/issues/56098 extern crate libc; diff --git a/tests/run-pass/issue-15063.rs b/tests/run-pass/issue-15063.rs index 8ccf87ee7079..c85590bb8b4b 100644 --- a/tests/run-pass/issue-15063.rs +++ b/tests/run-pass/issue-15063.rs @@ -1,5 +1,4 @@ -#![allow(dead_code)] - +#[allow(dead_code)] enum Two { A, B } impl Drop for Two { fn drop(&mut self) { diff --git a/tests/run-pass/issue-35815.rs b/tests/run-pass/issue-35815.rs index fb0bd8e202ff..62b3220967ed 100644 --- a/tests/run-pass/issue-35815.rs +++ b/tests/run-pass/issue-35815.rs @@ -1,7 +1,6 @@ -#![allow(dead_code)] - use std::mem; +#[allow(dead_code)] struct Foo { a: i64, b: bool, diff --git a/tests/run-pass/issue-53728.rs b/tests/run-pass/issue-53728.rs index 6d440b66b35a..0c858d3444fb 100644 --- a/tests/run-pass/issue-53728.rs +++ b/tests/run-pass/issue-53728.rs @@ -1,14 +1,16 @@ -#![allow(dead_code)] - #[repr(u16)] +#[allow(dead_code)] enum DeviceKind { Nil = 0, } + #[repr(packed)] +#[allow(dead_code)] struct DeviceInfo { endianness: u8, device_kind: DeviceKind, } + fn main() { let _x = None::<(DeviceInfo, u8)>; let _y = None::<(DeviceInfo, u16)>; diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index fc154c05c8fc..14d12de0d186 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -2,14 +2,12 @@ // compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] -#![allow(unused)] // necessary on macos due to conditional compilation - -use std::path::PathBuf; extern crate libc; -fn tmp() -> PathBuf { - std::env::var("MIRI_TEMP").map(PathBuf::from).unwrap_or_else(|_| std::env::temp_dir()) +#[cfg(target_os = "linux")] +fn tmp() -> std::path::PathBuf { + std::env::var("MIRI_TEMP").map(std::path::PathBuf::from).unwrap_or_else(|_| std::env::temp_dir()) } #[cfg(target_os = "linux")] diff --git a/tests/run-pass/packed_struct.rs b/tests/run-pass/packed_struct.rs index 303e90742fc1..52b75d1a520a 100644 --- a/tests/run-pass/packed_struct.rs +++ b/tests/run-pass/packed_struct.rs @@ -1,4 +1,3 @@ -#![allow(dead_code)] #![feature(unsize, coerce_unsized)] #[repr(packed)] @@ -8,12 +7,14 @@ struct S { } #[repr(packed)] +#[allow(dead_code)] struct Test1<'a> { x: u8, other: &'a u32, } #[repr(packed)] +#[allow(dead_code)] struct Test2<'a> { x: u8, other: &'a Test1<'a>, @@ -26,6 +27,7 @@ fn test(t: Test2) { fn test_unsizing() { #[repr(packed)] + #[allow(dead_code)] struct UnalignedPtr<'a, T: ?Sized> where T: 'a, { diff --git a/tests/run-pass/regions-mock-trans.rs b/tests/run-pass/regions-mock-trans.rs index 020ed4927a88..0b2433d84fa8 100644 --- a/tests/run-pass/regions-mock-trans.rs +++ b/tests/run-pass/regions-mock-trans.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -#![allow(dead_code)] - extern crate libc; use std::mem; @@ -13,11 +11,13 @@ struct Bcx<'a> { fcx: &'a Fcx<'a> } +#[allow(dead_code)] struct Fcx<'a> { arena: &'a Arena, ccx: &'a Ccx } +#[allow(dead_code)] struct Ccx { x: isize } diff --git a/tests/run-pass/rfc1623.rs b/tests/run-pass/rfc1623.rs index 2f893d8150c9..76e2c01e7450 100644 --- a/tests/run-pass/rfc1623.rs +++ b/tests/run-pass/rfc1623.rs @@ -1,4 +1,4 @@ -#![allow(dead_code)] +#![allow(dead_code)] // tons of unused statics here... // very simple test for a 'static static with default lifetime static STATIC_STR: &str = "&'static str"; diff --git a/tests/run-pass/small_enum_size_bug.rs b/tests/run-pass/small_enum_size_bug.rs index 7576a97e36ad..bb2f597444e7 100644 --- a/tests/run-pass/small_enum_size_bug.rs +++ b/tests/run-pass/small_enum_size_bug.rs @@ -1,5 +1,4 @@ -#![allow(dead_code)] - +#[allow(dead_code)] enum E { A = 1, B = 2, diff --git a/tests/run-pass/static_mut.rs b/tests/run-pass/static_mut.rs index be5830698b21..0aa6a2e92b62 100644 --- a/tests/run-pass/static_mut.rs +++ b/tests/run-pass/static_mut.rs @@ -1,8 +1,7 @@ -#![allow(dead_code)] - static mut FOO: i32 = 42; static BAR: Foo = Foo(unsafe { &FOO as *const _} ); +#[allow(dead_code)] struct Foo(*const i32); unsafe impl Sync for Foo {} diff --git a/tests/run-pass/tag-align-dyn-u64.rs b/tests/run-pass/tag-align-dyn-u64.rs index 81c19022ab08..8a97758fbb59 100644 --- a/tests/run-pass/tag-align-dyn-u64.rs +++ b/tests/run-pass/tag-align-dyn-u64.rs @@ -8,14 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(dead_code)] - use std::mem; enum Tag { Tag2(A) } +#[allow(dead_code)] struct Rec { c8: u8, t: Tag diff --git a/tests/run-pass/union.rs b/tests/run-pass/union.rs index 342c94f3d4a3..c80918ee527c 100644 --- a/tests/run-pass/union.rs +++ b/tests/run-pass/union.rs @@ -1,5 +1,4 @@ #![feature(untagged_unions)] -#![allow(dead_code, unused_variables)] fn main() { a(); @@ -9,6 +8,7 @@ fn main() { } fn a() { + #[allow(dead_code)] union U { f1: u32, f2: f32, @@ -27,6 +27,7 @@ fn b() { y: u32, } + #[allow(dead_code)] union U { s: S, both: u64, @@ -82,7 +83,7 @@ fn d() { unsafe { match u { MyUnion { f1: 10 } => { } - MyUnion { f2 } => { panic!("foo"); } + MyUnion { f2: _f2 } => { panic!("foo"); } } } } From 3e3613f2e2f8ff27499d263ae3cd95565f685dea Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 16 Apr 2020 09:27:40 +0200 Subject: [PATCH 1878/5092] merge packed_static and packed_struct --- tests/run-pass/packed_static.rs | 10 ---- tests/run-pass/packed_struct.rs | 90 +++++++++++++++++++-------------- 2 files changed, 53 insertions(+), 47 deletions(-) delete mode 100644 tests/run-pass/packed_static.rs diff --git a/tests/run-pass/packed_static.rs b/tests/run-pass/packed_static.rs deleted file mode 100644 index 1fa3a369670b..000000000000 --- a/tests/run-pass/packed_static.rs +++ /dev/null @@ -1,10 +0,0 @@ -#[repr(packed)] -struct Foo { - i: i32 -} - -fn main() { - assert_eq!({FOO.i}, 42); -} - -static FOO: Foo = Foo { i: 42 }; diff --git a/tests/run-pass/packed_struct.rs b/tests/run-pass/packed_struct.rs index 52b75d1a520a..cb0bc9859345 100644 --- a/tests/run-pass/packed_struct.rs +++ b/tests/run-pass/packed_struct.rs @@ -1,28 +1,48 @@ #![feature(unsize, coerce_unsized)] -#[repr(packed)] -struct S { - a: i32, - b: i64, -} -#[repr(packed)] -#[allow(dead_code)] -struct Test1<'a> { - x: u8, - other: &'a u32, -} +fn test_basic() { + #[repr(packed)] + struct S { + a: i32, + b: i64, + } -#[repr(packed)] -#[allow(dead_code)] -struct Test2<'a> { - x: u8, - other: &'a Test1<'a>, -} + #[repr(packed)] + #[allow(dead_code)] + struct Test1<'a> { + x: u8, + other: &'a u32, + } -fn test(t: Test2) { - let x = *t.other.other; - assert_eq!(x, 42); + #[repr(packed)] + #[allow(dead_code)] + struct Test2<'a> { + x: u8, + other: &'a Test1<'a>, + } + + fn test(t: Test2) { + let x = *t.other.other; + assert_eq!(x, 42); + } + + let mut x = S { + a: 42, + b: 99, + }; + let a = x.a; + let b = x.b; + assert_eq!(a, 42); + assert_eq!(b, 99); + // can't do `assert_eq!(x.a, 42)`, because `assert_eq!` takes a reference + assert_eq!({x.a}, 42); + assert_eq!({x.b}, 99); + + x.b = 77; + assert_eq!({x.b}, 77); + + test(Test2 { x: 0, other: &Test1 { x: 0, other: &42 }}); } fn test_unsizing() { @@ -83,25 +103,21 @@ fn test_inner_packed() { let _o2 = o.clone(); } +fn test_static() { + #[repr(packed)] + struct Foo { + i: i32 + } + + static FOO: Foo = Foo { i: 42 }; + + assert_eq!({FOO.i}, 42); +} + fn main() { - let mut x = S { - a: 42, - b: 99, - }; - let a = x.a; - let b = x.b; - assert_eq!(a, 42); - assert_eq!(b, 99); - // can't do `assert_eq!(x.a, 42)`, because `assert_eq!` takes a reference - assert_eq!({x.a}, 42); - assert_eq!({x.b}, 99); - - x.b = 77; - assert_eq!({x.b}, 77); - - test(Test2 { x: 0, other: &Test1 { x: 0, other: &42 }}); - + test_basic(); test_unsizing(); test_drop(); test_inner_packed(); + test_static(); } From ff3b382b14a329e597fa8f714f75c40344522ebb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 16 Apr 2020 18:35:42 +0200 Subject: [PATCH 1879/5092] ReadBytesAsPointer is always supported --- src/diagnostics.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 8c7bb8a47c63..ff52e2385e47 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -92,6 +92,8 @@ pub fn report_error<'tcx, 'mir>( let helps = match e.kind { Unsupported(UnsupportedOpInfo::NoMirFor(..)) => vec![format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`")], + Unsupported(UnsupportedOpInfo::ReadBytesAsPointer) => + panic!("`ReadBytesAsPointer` cannot be raised by Miri"), Unsupported(_) => vec![format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support")], UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. }) => From 57c7119315132220ef547bed0dc8d15272190291 Mon Sep 17 00:00:00 2001 From: David Cook Date: Thu, 16 Apr 2020 23:24:57 -0500 Subject: [PATCH 1880/5092] Handle std::sync::atomic::spin_loop_hint() --- src/shims/foreign_items.rs | 17 +++++++++++++---- tests/run-pass/sync.rs | 6 ++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 7e7f17b0dbd4..e816a35253d9 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -434,10 +434,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Target-specific shims - _ => match this.tcx.sess.target.target.target_os.as_str() { - "linux" | "macos" => return posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), - "windows" => return windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), - target => throw_unsup_format!("the target `{}` is not supported", target), + _ => { + match this.tcx.sess.target.target.arch.as_str() { + "x86" | "x86_64" => match link_name { + "llvm.x86.sse2.pause" => return Ok(true), + _ => {} + } + _ => {} + } + match this.tcx.sess.target.target.target_os.as_str() { + "linux" | "macos" => return posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), + "windows" => return windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), + target => throw_unsup_format!("the target `{}` is not supported", target), + } } }; diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index 1ede5d42bb4b..90885880e681 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -1,6 +1,7 @@ #![feature(rustc_private)] use std::sync::{Mutex, TryLockError}; +use std::sync::atomic; fn main() { test_mutex_stdlib(); @@ -8,6 +9,7 @@ fn main() { { test_rwlock_stdlib(); } + test_spin_loop_hint(); } fn test_mutex_stdlib() { @@ -50,3 +52,7 @@ impl TryLockErrorExt for TryLockError { } } } + +fn test_spin_loop_hint() { + atomic::spin_loop_hint(); +} From 6a81014ae9f169b4b6277b76052ea0a032049477 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 17 Apr 2020 11:03:20 +0200 Subject: [PATCH 1881/5092] test #[derive] on packed struct --- tests/run-pass/packed_struct.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/run-pass/packed_struct.rs b/tests/run-pass/packed_struct.rs index cb0bc9859345..7aa53ef568f5 100644 --- a/tests/run-pass/packed_struct.rs +++ b/tests/run-pass/packed_struct.rs @@ -1,5 +1,7 @@ #![feature(unsize, coerce_unsized)] +use std::collections::hash_map::DefaultHasher; +use std::hash::Hash; fn test_basic() { #[repr(packed)] @@ -114,10 +116,31 @@ fn test_static() { assert_eq!({FOO.i}, 42); } +fn test_derive() { + #[repr(packed)] + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)] + struct P { + a: usize, + b: u8, + c: usize, + } + + let x = P {a: 1usize, b: 2u8, c: 3usize}; + let y = P {a: 1usize, b: 2u8, c: 4usize}; + + let _clone = x.clone(); + assert!(x != y); + assert_eq!(x.partial_cmp(&y).unwrap(), x.cmp(&y)); + x.hash(&mut DefaultHasher::new()); + P::default(); + format!("{:?}", x); +} + fn main() { test_basic(); test_unsizing(); test_drop(); test_inner_packed(); test_static(); + test_derive(); } From 6ad0187265dfbd9dc145042a5a809db688abbe7a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 17 Apr 2020 14:19:26 +0200 Subject: [PATCH 1882/5092] rustup for FieldsShape::Primitive --- rust-version | 2 +- src/helpers.rs | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index 937073ef4fcc..e9b00f649776 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -df768c5c8fcb361c4dc94b4c776d6a78c12862e1 +b2c1a606feb1fbdb0ac0acba76f881ef172ed474 diff --git a/src/helpers.rs b/src/helpers.rs index 9f46a0c1ce2d..40a33f09a83c 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,5 +1,6 @@ use std::convert::TryFrom; use std::mem; +use std::num::NonZeroUsize; use log::trace; @@ -333,17 +334,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx places.sort_by_key(|place| place.ptr.assert_ptr().offset); self.walk_aggregate(place, places.into_iter().map(Ok)) } - FieldsShape::Union { .. } => { + FieldsShape::Union { .. } | FieldsShape::Primitive => { // Uh, what? - bug!("a union is not an aggregate we should ever visit") + bug!("unions/primitives are not aggregates we should ever visit") } } } // We have to do *something* for unions. - fn visit_union(&mut self, v: MPlaceTy<'tcx, Tag>, fields: usize) -> InterpResult<'tcx> { - assert!(fields > 0); // we should never reach "pseudo-unions" with 0 fields, like primitives - + fn visit_union(&mut self, v: MPlaceTy<'tcx, Tag>, _fields: NonZeroUsize) -> InterpResult<'tcx> { // With unions, we fall back to whatever the type says, to hopefully be consistent // with LLVM IR. // FIXME: are we consistent, and is this really the behavior we want? From 521e77d712a4b633701f57dc8d404827db76518a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 17 Apr 2020 20:43:54 +0200 Subject: [PATCH 1883/5092] test that we properly check dynamic alignment --- .../unaligned_pointers/dyn_alignment.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/compile-fail/unaligned_pointers/dyn_alignment.rs diff --git a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs new file mode 100644 index 000000000000..a8cf54edc85f --- /dev/null +++ b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs @@ -0,0 +1,19 @@ +// should find the bug even without these +// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows + +#[repr(align(256))] +#[derive(Debug)] +struct MuchAlign; + +fn main() { + let buf = [0u32; 256]; + // `buf` is sufficiently aligned for `layout.align` on a `dyn Debug`, but not + // for the actual alignment required by `MuchAlign`. + // We craft a wide reference `&dyn Debug` with the vtable for `MuchAlign`. That should be UB, + // as the reference is not aligned to its dynamic alignment requirements. + let mut ptr = &MuchAlign as &dyn std::fmt::Debug; + // Overwrite the data part of `ptr`. + unsafe { (&mut ptr as *mut _ as *mut *const u8).write(&buf as *const _ as *const u8); } + // Re-borrow that. This should be UB. + let _ptr = &*ptr; //~ ERROR accessing memory with alignment 4, but alignment 256 is required +} From c6ab27577b3291036788735058194e9bb05dc70c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 18 Apr 2020 02:06:36 +0200 Subject: [PATCH 1884/5092] test that we check dynamic actual size of object --- tests/compile-fail/dangling_pointers/dyn_size.rs | 13 +++++++++++++ .../unaligned_pointers/dyn_alignment.rs | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/dangling_pointers/dyn_size.rs diff --git a/tests/compile-fail/dangling_pointers/dyn_size.rs b/tests/compile-fail/dangling_pointers/dyn_size.rs new file mode 100644 index 000000000000..c8f1ee31137a --- /dev/null +++ b/tests/compile-fail/dangling_pointers/dyn_size.rs @@ -0,0 +1,13 @@ +// should find the bug even without these +// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows + +struct SliceWithHead(u8, [u8]); + +fn main() { + let buf = [0u32; 1]; + // We craft a wide pointer `*const SliceWithHead` such that the unsized tail is only partially allocated. + // That should be UB, as the reference is not fully dereferencable. + let ptr: *const SliceWithHead = unsafe { std::mem::transmute((&buf, 4usize)) }; + // Re-borrow that. This should be UB. + let _ptr = unsafe { &*ptr }; //~ ERROR pointer must be in-bounds at offset 5 +} diff --git a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs index a8cf54edc85f..4d0b3af0952c 100644 --- a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs +++ b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs @@ -12,7 +12,7 @@ fn main() { // We craft a wide reference `&dyn Debug` with the vtable for `MuchAlign`. That should be UB, // as the reference is not aligned to its dynamic alignment requirements. let mut ptr = &MuchAlign as &dyn std::fmt::Debug; - // Overwrite the data part of `ptr`. + // Overwrite the data part of `ptr` so it points to `buf`. unsafe { (&mut ptr as *mut _ as *mut *const u8).write(&buf as *const _ as *const u8); } // Re-borrow that. This should be UB. let _ptr = &*ptr; //~ ERROR accessing memory with alignment 4, but alignment 256 is required From 0345ee42da3a206e92cecd42b0b472b82552af95 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 18 Apr 2020 09:15:59 +0200 Subject: [PATCH 1885/5092] some UB gets masked by optimizations --- tests/compile-fail/dangling_pointers/dyn_size.rs | 4 ++-- tests/compile-fail/unaligned_pointers/dyn_alignment.rs | 4 ++-- tests/compile-fail/validity/nonzero.rs | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/compile-fail/dangling_pointers/dyn_size.rs b/tests/compile-fail/dangling_pointers/dyn_size.rs index c8f1ee31137a..39a091387c6c 100644 --- a/tests/compile-fail/dangling_pointers/dyn_size.rs +++ b/tests/compile-fail/dangling_pointers/dyn_size.rs @@ -1,5 +1,5 @@ -// should find the bug even without these -// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows +// should find the bug even without these, but gets masked by optimizations +// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Zmir-opt-level=0 struct SliceWithHead(u8, [u8]); diff --git a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs index 4d0b3af0952c..aa293a5d2167 100644 --- a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs +++ b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs @@ -1,5 +1,5 @@ -// should find the bug even without these -// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows +// should find the bug even without these, but gets masked by optimizations +// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Zmir-opt-level=0 #[repr(align(256))] #[derive(Debug)] diff --git a/tests/compile-fail/validity/nonzero.rs b/tests/compile-fail/validity/nonzero.rs index dbb31b3f1757..8ff19a2b4386 100644 --- a/tests/compile-fail/validity/nonzero.rs +++ b/tests/compile-fail/validity/nonzero.rs @@ -1,4 +1,5 @@ -// compile-flags: -Zmir-opt-level=1 +// gets masked by optimizations +// compile-flags: -Zmir-opt-level=0 #![feature(rustc_attrs)] #![allow(unused_attributes)] From bb38ab4340b944cb047ea0977d4198aaa9a36dec Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 18 Apr 2020 10:11:45 +0200 Subject: [PATCH 1886/5092] use u128::MAX symbolic name --- tests/compile-fail/intrinsics/float_to_int_64_too_big4.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big4.rs b/tests/compile-fail/intrinsics/float_to_int_64_too_big4.rs index d5b24347b941..e9623dba947f 100644 --- a/tests/compile-fail/intrinsics/float_to_int_64_too_big4.rs +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big4.rs @@ -6,5 +6,5 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(340282366920938463463374607431768211455.0f64); } //~ ERROR: cannot be represented in target type `u128` + unsafe { float_to_int_unchecked::(u128::MAX as f64); } //~ ERROR: cannot be represented in target type `u128` } From 699685c07cc017792eae9f7a21553e394f49d1c1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 18 Apr 2020 13:07:50 +0200 Subject: [PATCH 1887/5092] rename test_cast -> test_both_cast to make purpose clearer --- tests/run-pass/float.rs | 128 ++++++++++++++++++++-------------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index 364388571f44..c56d12a0c00e 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -68,7 +68,7 @@ impl FloatToInt for f64 { /// Test this cast both via `as` and via `approx_unchecked` (i.e., it must not saturate). #[track_caller] #[inline(never)] -fn test_cast(x: F, y: I) +fn test_both_cast(x: F, y: I) where F: FloatToInt, I: PartialEq + Debug { assert_eq!(x.cast(), y); @@ -116,22 +116,22 @@ fn basic() { fn casts() { // f32 -> i8 - test_cast::(127.99, 127); - test_cast::(-128.99, -128); + test_both_cast::(127.99, 127); + test_both_cast::(-128.99, -128); // f32 -> i32 - test_cast::(0.0, 0); - test_cast::(-0.0, 0); - test_cast::(/*0x1p-149*/ f32::from_bits(0x00000001), 0); - test_cast::(/*-0x1p-149*/ f32::from_bits(0x80000001), 0); - test_cast::(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd), 1); - test_cast::(/*-0x1.19999ap+0*/ f32::from_bits(0xbf8ccccd), -1); - test_cast::(1.9, 1); - test_cast::(-1.9, -1); - test_cast::(5.0, 5); - test_cast::(-5.0, -5); - test_cast::(2147483520.0, 2147483520); - test_cast::(-2147483648.0, -2147483648); + test_both_cast::(0.0, 0); + test_both_cast::(-0.0, 0); + test_both_cast::(/*0x1p-149*/ f32::from_bits(0x00000001), 0); + test_both_cast::(/*-0x1p-149*/ f32::from_bits(0x80000001), 0); + test_both_cast::(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd), 1); + test_both_cast::(/*-0x1.19999ap+0*/ f32::from_bits(0xbf8ccccd), -1); + test_both_cast::(1.9, 1); + test_both_cast::(-1.9, -1); + test_both_cast::(5.0, 5); + test_both_cast::(-5.0, -5); + test_both_cast::(2147483520.0, 2147483520); + test_both_cast::(-2147483648.0, -2147483648); // unrepresentable casts assert_eq::(2147483648.0f32 as i32, i32::MAX); assert_eq::(-2147483904.0f32 as i32, i32::MIN); @@ -143,19 +143,19 @@ fn casts() { assert_eq::((-f32::NAN) as i32, 0); // f32 -> u32 - test_cast::(0.0, 0); - test_cast::(-0.0, 0); - test_cast::(-0.9999999, 0); - test_cast::(/*0x1p-149*/ f32::from_bits(0x1), 0); - test_cast::(/*-0x1p-149*/ f32::from_bits(0x80000001), 0); - test_cast::(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd), 1); - test_cast::(1.9, 1); - test_cast::(5.0, 5); - test_cast::(2147483648.0, 0x8000_0000); - test_cast::(4294967040.0, 0u32.wrapping_sub(256)); - test_cast::(/*-0x1.ccccccp-1*/ f32::from_bits(0xbf666666), 0); - test_cast::(/*-0x1.fffffep-1*/ f32::from_bits(0xbf7fffff), 0); - test_cast::((u32::MAX-128) as f32, u32::MAX-255); // rounding loss + test_both_cast::(0.0, 0); + test_both_cast::(-0.0, 0); + test_both_cast::(-0.9999999, 0); + test_both_cast::(/*0x1p-149*/ f32::from_bits(0x1), 0); + test_both_cast::(/*-0x1p-149*/ f32::from_bits(0x80000001), 0); + test_both_cast::(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd), 1); + test_both_cast::(1.9, 1); + test_both_cast::(5.0, 5); + test_both_cast::(2147483648.0, 0x8000_0000); + test_both_cast::(4294967040.0, 0u32.wrapping_sub(256)); + test_both_cast::(/*-0x1.ccccccp-1*/ f32::from_bits(0xbf666666), 0); + test_both_cast::(/*-0x1.fffffep-1*/ f32::from_bits(0xbf7fffff), 0); + test_both_cast::((u32::MAX-128) as f32, u32::MAX-255); // rounding loss // unrepresentable casts assert_eq::((u32::MAX-127) as f32 as u32, u32::MAX); // rounds up and then becomes unrepresentable assert_eq::(4294967296.0f32 as u32, u32::MAX); @@ -168,44 +168,44 @@ fn casts() { assert_eq::((-f32::NAN) as u32, 0); // f32 -> i64 - test_cast::(4294967296.0, 4294967296); - test_cast::(-4294967296.0, -4294967296); - test_cast::(9223371487098961920.0, 9223371487098961920); - test_cast::(-9223372036854775808.0, -9223372036854775808); + test_both_cast::(4294967296.0, 4294967296); + test_both_cast::(-4294967296.0, -4294967296); + test_both_cast::(9223371487098961920.0, 9223371487098961920); + test_both_cast::(-9223372036854775808.0, -9223372036854775808); // f64 -> i8 - test_cast::(127.99, 127); - test_cast::(-128.99, -128); + test_both_cast::(127.99, 127); + test_both_cast::(-128.99, -128); // f64 -> i32 - test_cast::(0.0, 0); - test_cast::(-0.0, 0); - test_cast::(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a), 1); - test_cast::(/*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a), -1); - test_cast::(1.9, 1); - test_cast::(-1.9, -1); - test_cast::(1e8, 100_000_000); - test_cast::(2147483647.0, 2147483647); - test_cast::(-2147483648.0, -2147483648); + test_both_cast::(0.0, 0); + test_both_cast::(-0.0, 0); + test_both_cast::(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a), 1); + test_both_cast::(/*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a), -1); + test_both_cast::(1.9, 1); + test_both_cast::(-1.9, -1); + test_both_cast::(1e8, 100_000_000); + test_both_cast::(2147483647.0, 2147483647); + test_both_cast::(-2147483648.0, -2147483648); // unrepresentable casts assert_eq::(2147483648.0f64 as i32, i32::MAX); assert_eq::(-2147483649.0f64 as i32, i32::MIN); // f64 -> i64 - test_cast::(0.0, 0); - test_cast::(-0.0, 0); - test_cast::(/*0x0.0000000000001p-1022*/ f64::from_bits(0x1), 0); - test_cast::(/*-0x0.0000000000001p-1022*/ f64::from_bits(0x8000000000000001), 0); - test_cast::(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a), 1); - test_cast::(/*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a), -1); - test_cast::(5.0, 5); - test_cast::(5.9, 5); - test_cast::(-5.0, -5); - test_cast::(-5.9, -5); - test_cast::(4294967296.0, 4294967296); - test_cast::(-4294967296.0, -4294967296); - test_cast::(9223372036854774784.0, 9223372036854774784); - test_cast::(-9223372036854775808.0, -9223372036854775808); + test_both_cast::(0.0, 0); + test_both_cast::(-0.0, 0); + test_both_cast::(/*0x0.0000000000001p-1022*/ f64::from_bits(0x1), 0); + test_both_cast::(/*-0x0.0000000000001p-1022*/ f64::from_bits(0x8000000000000001), 0); + test_both_cast::(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a), 1); + test_both_cast::(/*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a), -1); + test_both_cast::(5.0, 5); + test_both_cast::(5.9, 5); + test_both_cast::(-5.0, -5); + test_both_cast::(-5.9, -5); + test_both_cast::(4294967296.0, 4294967296); + test_both_cast::(-4294967296.0, -4294967296); + test_both_cast::(9223372036854774784.0, 9223372036854774784); + test_both_cast::(-9223372036854775808.0, -9223372036854775808); // unrepresentable casts assert_eq::(9223372036854775808.0f64 as i64, i64::MAX); assert_eq::(-9223372036854777856.0f64 as i64, i64::MIN); @@ -217,13 +217,13 @@ fn casts() { assert_eq::((-f64::NAN) as i64, 0); // f64 -> u64 - test_cast::(0.0, 0); - test_cast::(-0.0, 0); - test_cast::(-0.99999999999, 0); - test_cast::(5.0, 5); - test_cast::(1e16, 10000000000000000); - test_cast::((u64::MAX-1024) as f64, u64::MAX-2047); // rounding loss - test_cast::(9223372036854775808.0, 9223372036854775808); + test_both_cast::(0.0, 0); + test_both_cast::(-0.0, 0); + test_both_cast::(-0.99999999999, 0); + test_both_cast::(5.0, 5); + test_both_cast::(1e16, 10000000000000000); + test_both_cast::((u64::MAX-1024) as f64, u64::MAX-2047); // rounding loss + test_both_cast::(9223372036854775808.0, 9223372036854775808); // unrepresentable casts assert_eq::(-5.0f64 as u64, 0); assert_eq::((u64::MAX-1023) as f64 as u64, u64::MAX); // rounds up and then becomes unrepresentable From 14f50b34a3ee72beca54283a61e152bb088aa8e6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 18 Apr 2020 17:53:54 +0200 Subject: [PATCH 1888/5092] use pre-computed layouts some more --- src/eval.rs | 6 +++--- src/machine.rs | 22 +++++++++++++++------- src/shims/env.rs | 2 +- src/shims/panic.rs | 6 +++--- src/shims/time.rs | 4 +--- src/shims/tls.rs | 8 ++++---- 6 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index b360b1bd8bbc..1caffe264761 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -130,7 +130,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`. { let argc_place = - ecx.allocate(ecx.layout_of(tcx.types.isize)?, MiriMemoryKind::Machine.into()); + ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into()); ecx.write_scalar(argc, argc_place.into())?; ecx.machine.argc = Some(argc_place.ptr); @@ -168,7 +168,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( }; // Return place (in static memory so that it does not count as leak). - let ret_place = ecx.allocate(ecx.layout_of(tcx.types.isize)?, MiriMemoryKind::Machine.into()); + let ret_place = ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into()); // Call start function. ecx.call_function( start_instance, @@ -178,7 +178,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( )?; // Set the last_error to 0 - let errno_layout = ecx.layout_of(tcx.types.u32)?; + let errno_layout = ecx.machine.layouts.u32; let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Machine.into()); ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?; ecx.machine.last_error = Some(errno_place); diff --git a/src/machine.rs b/src/machine.rs index 5cf42df8268b..236b31ec4af5 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -168,7 +168,7 @@ impl MemoryExtra { "linux" => { // "__cxa_thread_atexit_impl" // This should be all-zero, pointer-sized. - let layout = this.layout_of(this.tcx.types.usize)?; + let layout = this.machine.layouts.usize; let place = this.allocate(layout, MiriMemoryKind::Machine.into()); this.write_scalar(Scalar::from_machine_usize(0, this), place.into())?; Self::add_extern_static(this, "__cxa_thread_atexit_impl", place.ptr); @@ -178,7 +178,7 @@ impl MemoryExtra { "windows" => { // "_tls_used" // This is some obscure hack that is part of the Windows TLS story. It's a `u8`. - let layout = this.layout_of(this.tcx.types.u8)?; + let layout = this.machine.layouts.u8; let place = this.allocate(layout, MiriMemoryKind::Machine.into()); this.write_scalar(Scalar::from_u8(0), place.into())?; Self::add_extern_static(this, "_tls_used", place.ptr); @@ -190,16 +190,26 @@ impl MemoryExtra { } /// Precomputed layouts of primitive types -pub(crate) struct PrimitiveLayouts<'tcx> { - pub(crate) i32: TyAndLayout<'tcx>, - pub(crate) u32: TyAndLayout<'tcx>, +pub struct PrimitiveLayouts<'tcx> { + pub unit: TyAndLayout<'tcx>, + pub i8: TyAndLayout<'tcx>, + pub i32: TyAndLayout<'tcx>, + pub isize: TyAndLayout<'tcx>, + pub u8: TyAndLayout<'tcx>, + pub u32: TyAndLayout<'tcx>, + pub usize: TyAndLayout<'tcx>, } impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> { fn new(layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result> { Ok(Self { + unit: layout_cx.layout_of(layout_cx.tcx.mk_unit())?, + i8: layout_cx.layout_of(layout_cx.tcx.types.i8)?, i32: layout_cx.layout_of(layout_cx.tcx.types.i32)?, + isize: layout_cx.layout_of(layout_cx.tcx.types.isize)?, + u8: layout_cx.layout_of(layout_cx.tcx.types.u8)?, u32: layout_cx.layout_of(layout_cx.tcx.types.u32)?, + usize: layout_cx.layout_of(layout_cx.tcx.types.usize)?, }) } } @@ -242,8 +252,6 @@ pub struct Evaluator<'tcx> { pub(crate) time_anchor: Instant, /// Precomputed `TyLayout`s for primitive data types that are commonly used inside Miri. - /// FIXME: Search through the rest of the codebase for more layout_of() calls that - /// could be stored here. pub(crate) layouts: PrimitiveLayouts<'tcx>, } diff --git a/src/shims/env.rs b/src/shims/env.rs index 440168272294..8dd2a3ca302a 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -384,7 +384,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { // No `environ` allocated yet, let's do that. // This is memory backing an extern static, hence `Machine`, not `Env`. - let layout = this.layout_of(this.tcx.types.usize)?; + let layout = this.machine.layouts.usize; let place = this.allocate(layout, MiriMemoryKind::Machine.into()); this.machine.env_vars.environ = Some(place); } diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 1aec236a533c..450f735ad686 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -14,7 +14,7 @@ use log::trace; use rustc_middle::{mir, ty}; -use rustc_target::{spec::PanicStrategy, abi::LayoutOf}; +use rustc_target::spec::PanicStrategy; use crate::*; @@ -93,7 +93,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Now we make a function call, and pass `data` as first and only argument. let f_instance = this.memory.get_fn(try_fn)?.as_instance()?; trace!("try_fn: {:?}", f_instance); - let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); + let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); this.call_function( f_instance, &[data.into()], @@ -144,7 +144,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Push the `catch_fn` stackframe. let f_instance = this.memory.get_fn(catch_unwind.catch_fn)?.as_instance()?; trace!("catch_fn: {:?}", f_instance); - let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); + let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); this.call_function( f_instance, &[catch_unwind.data.into(), payload.into()], diff --git a/src/shims/time.rs b/src/shims/time.rs index a87db9878202..de9a0313b144 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -1,8 +1,6 @@ use std::time::{Duration, SystemTime, Instant}; use std::convert::TryFrom; -use rustc_target::abi::LayoutOf; - use crate::stacked_borrows::Tag; use crate::*; use helpers::{immty_from_int_checked, immty_from_uint_checked}; @@ -107,7 +105,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dwLowDateTime = u32::try_from(duration_ticks & 0x00000000FFFFFFFF).unwrap(); let dwHighDateTime = u32::try_from((duration_ticks & 0xFFFFFFFF00000000) >> 32).unwrap(); - let DWORD_tylayout = this.layout_of(this.tcx.types.u32)?; + let DWORD_tylayout = this.machine.layouts.u32; let imms = [ immty_from_uint_checked(dwLowDateTime, DWORD_tylayout)?, immty_from_uint_checked(dwHighDateTime, DWORD_tylayout)?, diff --git a/src/shims/tls.rs b/src/shims/tls.rs index cba7dde53d81..ba072e8ffd5d 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -5,7 +5,7 @@ use std::collections::BTreeMap; use log::trace; use rustc_middle::ty; -use rustc_target::abi::{LayoutOf, Size, HasDataLayout}; +use rustc_target::abi::{Size, HasDataLayout}; use crate::{HelpersEvalContextExt, InterpResult, MPlaceTy, Scalar, StackPopCleanup, Tag}; @@ -172,7 +172,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. let reason = this.eval_path_scalar(&["std", "sys", "windows", "c", "DLL_PROCESS_DETACH"])?; - let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); + let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); this.call_function( thread_callback, &[Scalar::null_ptr(this).into(), reason.into(), Scalar::null_ptr(this).into()], @@ -191,7 +191,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some((instance, data)) = this.machine.tls.global_dtor { trace!("Running global dtor {:?} on {:?}", instance, data); - let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); + let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); this.call_function( instance, &[data.into()], @@ -209,7 +209,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("Running TLS dtor {:?} on {:?}", instance, ptr); assert!(!this.is_null(ptr).unwrap(), "data can't be NULL when dtor is called!"); - let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); + let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); this.call_function( instance, &[ptr.into()], From 11cd87e4572fc3ce19a19bf0dd9a2bcfd3c8e89a Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 18 Apr 2020 19:16:52 -0500 Subject: [PATCH 1889/5092] Flip matching --- src/shims/foreign_items.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index e816a35253d9..c4acbd6a1b9a 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -433,15 +433,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_f64(res), dest)?; } + "llvm.x86.sse2.pause" if this.tcx.sess.target.target.arch == "x86" || this.tcx.sess.target.target.arch == "x86_64" => {} + // Target-specific shims _ => { - match this.tcx.sess.target.target.arch.as_str() { - "x86" | "x86_64" => match link_name { - "llvm.x86.sse2.pause" => return Ok(true), - _ => {} - } - _ => {} - } match this.tcx.sess.target.target.target_os.as_str() { "linux" | "macos" => return posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), "windows" => return windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), From 7b69a6271e3e1469da26dce61284dbcb1face302 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 18 Apr 2020 19:31:02 -0500 Subject: [PATCH 1890/5092] Add support for std::thread::yield_now --- src/shims/foreign_items/posix.rs | 3 +++ src/shims/foreign_items/windows.rs | 5 +++++ tests/run-pass/sync.rs | 5 +++++ 3 files changed, 13 insertions(+) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 3ececb9c20bb..35decd6ddbf2 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -312,6 +312,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We do not support forking, so there is nothing to do here. this.write_null(dest)?; } + "sched_yield" => { + this.write_null(dest)?; + } // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 1d17cbcefdee..0125127a9f40 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -201,6 +201,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: we should set last_error, but to what? this.write_null(dest)?; } + "SwitchToThread" => { + // Note that once Miri supports concurrency, this will need to return a nonzero + // value if this call does result in switching to another thread. + this.write_null(dest)?; + } // Better error for attempts to create a thread "CreateThread" => { diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index 90885880e681..a4fd6f584c58 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -10,6 +10,7 @@ fn main() { test_rwlock_stdlib(); } test_spin_loop_hint(); + test_thread_yield_now(); } fn test_mutex_stdlib() { @@ -56,3 +57,7 @@ impl TryLockErrorExt for TryLockError { fn test_spin_loop_hint() { atomic::spin_loop_hint(); } + +fn test_thread_yield_now() { + std::thread::yield_now(); +} From fbf47d17845cc3df5b116e45ecfea71005b61735 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 19 Apr 2020 09:21:00 +0200 Subject: [PATCH 1891/5092] note source of test values --- tests/run-pass/float.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index c56d12a0c00e..fc513ead8dd8 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -114,6 +114,8 @@ fn basic() { assert_eq(y, 42.0_f32); } +/// Many of these test values are taken from +/// https://github.com/WebAssembly/testsuite/blob/master/conversions.wast. fn casts() { // f32 -> i8 test_both_cast::(127.99, 127); From 70c828b76125bc5f469e5e776f2e984708876974 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 19 Apr 2020 09:34:54 +0200 Subject: [PATCH 1892/5092] test some more extreme cast cases --- .../intrinsics/float_to_int_64_too_big6.rs | 10 ++++++++++ .../intrinsics/float_to_int_64_too_big7.rs | 10 ++++++++++ 2 files changed, 20 insertions(+) create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_big6.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_big7.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big6.rs b/tests/compile-fail/intrinsics/float_to_int_64_too_big6.rs new file mode 100644 index 000000000000..f008131a6e52 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big6.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(f64::MAX); } //~ ERROR: cannot be represented in target type `u128` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big7.rs b/tests/compile-fail/intrinsics/float_to_int_64_too_big7.rs new file mode 100644 index 000000000000..69922e60a6bc --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big7.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(f64::MIN); } //~ ERROR: cannot be represented in target type `i128` +} From 547a4cc9209e04c2bbbe84edcd625272e51e45b2 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 19 Apr 2020 09:22:40 -0500 Subject: [PATCH 1893/5092] Review comments --- src/shims/foreign_items.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index c4acbd6a1b9a..75a2475d228a 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -433,15 +433,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_f64(res), dest)?; } + // Architecture-specific shims "llvm.x86.sse2.pause" if this.tcx.sess.target.target.arch == "x86" || this.tcx.sess.target.target.arch == "x86_64" => {} - // Target-specific shims - _ => { - match this.tcx.sess.target.target.target_os.as_str() { - "linux" | "macos" => return posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), - "windows" => return windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), - target => throw_unsup_format!("the target `{}` is not supported", target), - } + // Platform-specific shims + _ => match this.tcx.sess.target.target.target_os.as_str() { + "linux" | "macos" => return posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), + "windows" => return windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), + target => throw_unsup_format!("the target `{}` is not supported", target), } }; From 5224c72403fd4f5cbbfd574c9a18fed5678c7488 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Wed, 1 Apr 2020 16:55:52 -0700 Subject: [PATCH 1894/5092] Move the stack to the evaluator to make Miri compile with the newest Rustc. --- src/diagnostics.rs | 10 +++++----- src/eval.rs | 2 +- src/helpers.rs | 4 ++-- src/intptrcast.rs | 4 ++-- src/machine.rs | 26 ++++++++++++++++++++++---- src/shims/dlsym.rs | 2 +- src/shims/env.rs | 10 +++++----- src/shims/foreign_items.rs | 2 +- src/shims/foreign_items/posix.rs | 2 +- src/shims/foreign_items/posix/linux.rs | 2 +- src/shims/foreign_items/posix/macos.rs | 2 +- src/shims/foreign_items/windows.rs | 2 +- src/shims/fs.rs | 4 ++-- src/shims/intrinsics.rs | 2 +- src/shims/mod.rs | 2 +- src/shims/os_str.rs | 2 +- src/shims/panic.rs | 2 +- src/shims/time.rs | 3 +-- src/shims/tls.rs | 2 +- src/stacked_borrows.rs | 4 ++-- 20 files changed, 53 insertions(+), 36 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index ff52e2385e47..5189982b1361 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -47,7 +47,7 @@ pub enum NonHaltingDiagnostic { /// Emit a custom diagnostic without going through the miri-engine machinery pub fn report_error<'tcx, 'mir>( - ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, + ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, mut e: InterpErrorInfo<'tcx>, ) -> Option { use InterpError::*; @@ -121,13 +121,13 @@ pub fn report_error<'tcx, 'mir>( /// Report an error or note (depending on the `error` argument) at the current frame's current statement. /// Also emits a full stacktrace of the interpreter stack. fn report_msg<'tcx, 'mir>( - ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, + ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, title: &str, span_msg: String, mut helps: Vec, error: bool, ) -> Option { - let span = if let Some(frame) = ecx.stack().last() { + let span = if let Some(frame) = ecx.machine.stack.last() { frame.current_source_info().unwrap().span } else { DUMMY_SP @@ -159,7 +159,7 @@ fn report_msg<'tcx, 'mir>( err.emit(); - for (i, frame) in ecx.stack().iter().enumerate() { + for (i, frame) in ecx.machine.stack.iter().enumerate() { trace!("-------------------"); trace!("Frame {}", i); trace!(" return: {:?}", frame.return_place.map(|p| *p)); @@ -181,7 +181,7 @@ pub fn register_diagnostic(e: NonHaltingDiagnostic) { DIAGNOSTICS.with(|diagnostics| diagnostics.borrow_mut().push(e)); } -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Emit all diagnostics that were registed with `register_diagnostics` fn process_diagnostics(&self) { diff --git a/src/eval.rs b/src/eval.rs index 1caffe264761..548ecee7bc42 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -62,7 +62,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig, -) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'tcx>>, MPlaceTy<'tcx, Tag>)> { +) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, MPlaceTy<'tcx, Tag>)> { let tcx_at = tcx.at(rustc_span::source_map::DUMMY_SP); let param_env = ty::ParamEnv::reveal_all(); let layout_cx = LayoutCx { tcx, param_env }; diff --git a/src/helpers.rs b/src/helpers.rs index 40a33f09a83c..644ea25fbc4b 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -13,7 +13,7 @@ use rand::RngCore; use crate::*; -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} /// Gets an instance for a path. fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option { @@ -265,7 +265,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx unsafe_cell_action: F, } - impl<'ecx, 'mir, 'tcx, F> ValueVisitor<'mir, 'tcx, Evaluator<'tcx>> + impl<'ecx, 'mir, 'tcx: 'mir, F> ValueVisitor<'mir, 'tcx, Evaluator<'mir, 'tcx>> for UnsafeCellVisitor<'ecx, 'mir, 'tcx, F> where F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>, diff --git a/src/intptrcast.rs b/src/intptrcast.rs index ac27138d7630..5413e6b935b9 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -41,7 +41,7 @@ impl Default for GlobalState { impl<'mir, 'tcx> GlobalState { pub fn int_to_ptr( int: u64, - memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>, + memory: &Memory<'mir, 'tcx, Evaluator<'mir, 'tcx>>, ) -> InterpResult<'tcx, Pointer> { let global_state = memory.extra.intptrcast.borrow(); let pos = global_state.int_to_ptr_map.binary_search_by_key(&int, |(addr, _)| *addr); @@ -73,7 +73,7 @@ impl<'mir, 'tcx> GlobalState { pub fn ptr_to_int( ptr: Pointer, - memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>, + memory: &Memory<'mir, 'tcx, Evaluator<'mir, 'tcx>>, ) -> InterpResult<'tcx, u64> { let mut global_state = memory.extra.intptrcast.borrow_mut(); let global_state = &mut *global_state; diff --git a/src/machine.rs b/src/machine.rs index 236b31ec4af5..90e6a0e51394 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -215,7 +215,7 @@ impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> { } /// The machine itself. -pub struct Evaluator<'tcx> { +pub struct Evaluator<'mir, 'tcx> { /// Environment variables set by `setenv`. /// Miri does not expose env vars from the host to the emulated program. pub(crate) env_vars: EnvVars<'tcx>, @@ -251,11 +251,14 @@ pub struct Evaluator<'tcx> { /// The "time anchor" for this machine's monotone clock (for `Instant` simulation). pub(crate) time_anchor: Instant, + /// The call stack. + pub(crate) stack: Vec>>, + /// Precomputed `TyLayout`s for primitive data types that are commonly used inside Miri. pub(crate) layouts: PrimitiveLayouts<'tcx>, } -impl<'tcx> Evaluator<'tcx> { +impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { pub(crate) fn new( communicate: bool, validate: bool, @@ -279,12 +282,13 @@ impl<'tcx> Evaluator<'tcx> { panic_payload: None, time_anchor: Instant::now(), layouts, + stack: Vec::default(), } } } /// A rustc InterpCx for Miri. -pub type MiriEvalContext<'mir, 'tcx> = InterpCx<'mir, 'tcx, Evaluator<'tcx>>; +pub type MiriEvalContext<'mir, 'tcx> = InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>; /// A little trait that's useful to be inherited by extension traits. pub trait MiriEvalContextExt<'mir, 'tcx> { @@ -303,7 +307,7 @@ impl<'mir, 'tcx> MiriEvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> } /// Machine hook implementations. -impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { +impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { type MemoryKind = MiriMemoryKind; type FrameExtra = FrameData<'tcx>; @@ -322,6 +326,20 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { memory_extra.check_alignment } + #[inline(always)] + fn stack<'a>( + ecx: &'a InterpCx<'mir, 'tcx, Self>, + ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] { + &ecx.machine.stack + } + + #[inline(always)] + fn stack_mut<'a>( + ecx: &'a mut InterpCx<'mir, 'tcx, Self>, + ) -> &'a mut Vec> { + &mut ecx.machine.stack + } + #[inline(always)] fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { ecx.machine.validate diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index b5fe3cb7229c..0f6ba63e984f 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -20,7 +20,7 @@ impl Dlsym { } } -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn call_dlsym( &mut self, diff --git a/src/shims/env.rs b/src/shims/env.rs index 8dd2a3ca302a..8459aa3241c8 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -35,7 +35,7 @@ pub struct EnvVars<'tcx> { impl<'tcx> EnvVars<'tcx> { pub(crate) fn init<'mir>( - ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, + ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, mut excluded_env_vars: Vec, ) -> InterpResult<'tcx> { let target_os = ecx.tcx.sess.target.target.target_os.as_str(); @@ -61,7 +61,7 @@ impl<'tcx> EnvVars<'tcx> { } pub(crate) fn cleanup<'mir>( - ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, + ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, ) -> InterpResult<'tcx> { // Deallocate individual env vars. for (_name, ptr) in ecx.machine.env_vars.map.drain() { @@ -78,7 +78,7 @@ impl<'tcx> EnvVars<'tcx> { fn alloc_env_var_as_c_str<'mir, 'tcx>( name: &OsStr, value: &OsStr, - ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, + ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, ) -> InterpResult<'tcx, Pointer> { let mut name_osstring = name.to_os_string(); name_osstring.push("="); @@ -89,7 +89,7 @@ fn alloc_env_var_as_c_str<'mir, 'tcx>( fn alloc_env_var_as_wide_str<'mir, 'tcx>( name: &OsStr, value: &OsStr, - ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, + ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, ) -> InterpResult<'tcx, Pointer> { let mut name_osstring = name.to_os_string(); name_osstring.push("="); @@ -97,7 +97,7 @@ fn alloc_env_var_as_wide_str<'mir, 'tcx>( Ok(ecx.alloc_os_str_as_wide_str(name_osstring.as_os_str(), MiriMemoryKind::Env.into())) } -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn getenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 7e7f17b0dbd4..c7ab8dfd8738 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -12,7 +12,7 @@ use rustc_ast::attr; use crate::*; -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Returns the minimum alignment for the target architecture for allocations of the given size. fn min_align(&self, size: u64, kind: MiriMemoryKind) -> Align { diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 3ececb9c20bb..9fda0ad4eeed 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -9,7 +9,7 @@ use crate::*; use rustc_middle::mir; use rustc_target::abi::{Align, LayoutOf, Size}; -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn emulate_foreign_item_by_name( &mut self, diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 16c6c002b69c..b00704e47a02 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -1,7 +1,7 @@ use crate::*; use rustc_middle::mir; -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn emulate_foreign_item_by_name( &mut self, diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index e7baacf7274d..125b6b768530 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -1,7 +1,7 @@ use crate::*; use rustc_middle::mir; -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn emulate_foreign_item_by_name( &mut self, diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 1d17cbcefdee..8d564d4676ba 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -5,7 +5,7 @@ use rustc_target::abi::Size; use crate::*; -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn emulate_foreign_item_by_name( &mut self, diff --git a/src/shims/fs.rs b/src/shims/fs.rs index c70cc874164f..3e20f5f97288 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -64,7 +64,7 @@ impl FileHandler { } } -impl<'mir, 'tcx> EvalContextExtPrivate<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExtPrivate<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Emulate `stat` or `lstat` on `macos`. This function is not intended to be /// called directly from `emulate_foreign_item_by_name`, so it does not check if isolation is @@ -232,7 +232,7 @@ impl Default for DirHandler { } } -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn open( &mut self, diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 1f9004221920..b64aeef485ea 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -8,7 +8,7 @@ use rustc_target::abi::{Align, LayoutOf, Size}; use crate::*; -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn call_intrinsic( &mut self, diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 764e404141e4..71ff6024ec6f 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -17,7 +17,7 @@ use rustc_middle::{mir, ty}; use crate::*; -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn find_mir_or_eval_fn( &mut self, diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index c24d6df41e39..73dc9119a820 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -60,7 +60,7 @@ fn convert_path_separator<'a>( }; } -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 450f735ad686..c926046a0442 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -31,7 +31,7 @@ pub struct CatchUnwindData<'tcx> { ret: mir::BasicBlock, } -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Check if panicking is supported on this target, and give a good error otherwise. fn check_panic_supported(&self) -> InterpResult<'tcx> { diff --git a/src/shims/time.rs b/src/shims/time.rs index de9a0313b144..e26d2ce2e39d 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -11,8 +11,7 @@ pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Du .map_err(|_| err_unsup_format!("times before the Unix epoch are not supported").into()) } - -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn clock_gettime( &mut self, diff --git a/src/shims/tls.rs b/src/shims/tls.rs index ba072e8ffd5d..7b8446840295 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -154,7 +154,7 @@ impl<'tcx> TlsData<'tcx> { } } -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn run_tls_dtors(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index a69948002c12..3412f00964b4 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -506,7 +506,7 @@ impl Stacks { /// Retagging/reborrowing. There is some policy in here, such as which permissions /// to grant for which references, and when to add protectors. -impl<'mir, 'tcx> EvalContextPrivExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn reborrow( &mut self, @@ -607,7 +607,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn retag(&mut self, kind: RetagKind, place: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); From 192fd3d97e9371345d82c79351da80984cd65e9a Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 16 Apr 2020 10:14:46 -0700 Subject: [PATCH 1895/5092] Move stack and stack_mut implementation in Machine to match their position in the trait. --- src/machine.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 90e6a0e51394..2ab5f10af66d 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -326,20 +326,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { memory_extra.check_alignment } - #[inline(always)] - fn stack<'a>( - ecx: &'a InterpCx<'mir, 'tcx, Self>, - ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] { - &ecx.machine.stack - } - - #[inline(always)] - fn stack_mut<'a>( - ecx: &'a mut InterpCx<'mir, 'tcx, Self>, - ) -> &'a mut Vec> { - &mut ecx.machine.stack - } - #[inline(always)] fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { ecx.machine.validate @@ -539,6 +525,20 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { Ok(frame.with_extra(extra)) } + #[inline(always)] + fn stack<'a>( + ecx: &'a InterpCx<'mir, 'tcx, Self>, + ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] { + &ecx.machine.stack + } + + #[inline(always)] + fn stack_mut<'a>( + ecx: &'a mut InterpCx<'mir, 'tcx, Self>, + ) -> &'a mut Vec> { + &mut ecx.machine.stack + } + #[inline(always)] fn after_stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { if ecx.memory.extra.stacked_borrows.is_some() { From 5d2c8358f844a943ac5318cfdbe166a6688397cb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 20 Apr 2020 09:33:34 +0200 Subject: [PATCH 1896/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index e9b00f649776..b48a98d229f2 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -b2c1a606feb1fbdb0ac0acba76f881ef172ed474 +9b2f8dbba39dd4167f22a7026674a585c3d907d8 From 73772fede6de215faf7bf4846895cde959f82759 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 20 Apr 2020 10:04:17 +0200 Subject: [PATCH 1897/5092] adjust for Weak::as_raw -> as_ptr rename --- tests/compile-fail/{rc_as_raw.rs => rc_as_ptr.rs} | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) rename tests/compile-fail/{rc_as_raw.rs => rc_as_ptr.rs} (71%) diff --git a/tests/compile-fail/rc_as_raw.rs b/tests/compile-fail/rc_as_ptr.rs similarity index 71% rename from tests/compile-fail/rc_as_raw.rs rename to tests/compile-fail/rc_as_ptr.rs index cb50ca5fcece..0b98c7d2bba3 100644 --- a/tests/compile-fail/rc_as_raw.rs +++ b/tests/compile-fail/rc_as_ptr.rs @@ -5,17 +5,17 @@ use std::rc::{Rc, Weak}; use std::ptr; -/// Taken from the `Weak::as_raw` doctest. +/// Taken from the `Weak::as_ptr` doctest. fn main() { let strong = Rc::new(Box::new(42)); let weak = Rc::downgrade(&strong); // Both point to the same object - assert!(ptr::eq(&*strong, Weak::as_raw(&weak))); + assert!(ptr::eq(&*strong, Weak::as_ptr(&weak))); // The strong here keeps it alive, so we can still access the object. - assert_eq!(42, **unsafe { &*Weak::as_raw(&weak) }); + assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); drop(strong); // But not any more. We can do Weak::as_raw(&weak), but accessing the pointer would lead to // undefined behaviour. - assert_eq!(42, **unsafe { &*Weak::as_raw(&weak) }); //~ ERROR dereferenced after this allocation got freed + assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); //~ ERROR dereferenced after this allocation got freed } From 7406c1224b2dd7123ddcd6d06b809dd571fba2dd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 20 Apr 2020 10:38:38 +0200 Subject: [PATCH 1898/5092] adjust for asm -> llvm_asm rename --- test-cargo-miri/build.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test-cargo-miri/build.rs b/test-cargo-miri/build.rs index 950fc3c82bb1..b1f5fc172620 100644 --- a/test-cargo-miri/build.rs +++ b/test-cargo-miri/build.rs @@ -1,10 +1,10 @@ -#![feature(asm)] +#![feature(llvm_asm)] fn not_in_miri() -> i32 { // Inline assembly definitely does not work in Miri. let dummy = 42; unsafe { - asm!("" : : "r"(&dummy)); + llvm_asm!("" : : "r"(&dummy)); } return dummy; } From 54897f66f8daeec04042ab416718407b13641b86 Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 21 Apr 2020 21:17:54 -0500 Subject: [PATCH 1899/5092] Implement ftruncate64/ftruncate for File::set_len --- src/shims/foreign_items/posix/linux.rs | 4 ++++ src/shims/foreign_items/posix/macos.rs | 4 ++++ src/shims/fs.rs | 30 ++++++++++++++++++++++++++ tests/run-pass/fs.rs | 27 +++++++++++++++++++++++ 4 files changed, 65 insertions(+) diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index b00704e47a02..a32f0fa60678 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -34,6 +34,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.linux_readdir64_r(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "ftruncate64" => { + let result = this.ftruncate64(args[0], args[1])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } // Linux-only "posix_fadvise" => { let _fd = this.read_scalar(args[0])?.to_i32()?; diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 125b6b768530..dd3dba6ec07c 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -44,6 +44,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.macos_readdir_r(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "ftruncate" => { + let result = this.ftruncate64(args[0], args[1])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } // Environment related shims "_NSGetEnviron" => { diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 3e20f5f97288..e7d41b36f5a6 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1062,6 +1062,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.handle_not_found() } } + + fn ftruncate64( + &mut self, fd_op: OpTy<'tcx, Tag>, + length_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.check_no_isolation("ftruncate64")?; + + let fd = this.read_scalar(fd_op)?.to_i32()?; + let length = this.read_scalar(length_op)?.to_i64()?; + if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get_mut(&fd) { + if *writable { + if let Ok(length) = length.try_into() { + let result = file.set_len(length); + this.try_unwrap_io_result(result.map(|_| 0i32)) + } else { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + Ok(-1) + } + } else { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + Ok(-1) + } + } else { + this.handle_not_found() + } + } } /// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch when diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index d8b6e5b44575..1a139de8148a 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -13,6 +13,7 @@ fn main() { test_file_create_new(); test_seek(); test_metadata(); + test_file_set_len(); test_symlink(); test_errors(); test_rename(); @@ -155,6 +156,32 @@ fn test_metadata() { remove_file(&path).unwrap(); } +fn test_file_set_len() { + let bytes = b"Hello, World!\n"; + let path = prepare_with_content("miri_test_fs_set_len.txt", bytes); + + // Test extending the file + let mut file = OpenOptions::new().read(true).write(true).open(&path).unwrap(); + let bytes_extended = b"Hello, World!\n\x00\x00\x00\x00\x00\x00"; + file.set_len(20).unwrap(); + let mut contents = Vec::new(); + file.read_to_end(&mut contents).unwrap(); + assert_eq!(bytes_extended, contents.as_slice()); + + // Test truncating the file + file.seek(SeekFrom::Start(0)).unwrap(); + file.set_len(10).unwrap(); + let mut contents = Vec::new(); + file.read_to_end(&mut contents).unwrap(); + assert_eq!(&bytes[..10], contents.as_slice()); + + // Can't use set_len on a file not opened for writing + let file = OpenOptions::new().read(true).open(&path).unwrap(); + assert_eq!(ErrorKind::InvalidInput, file.set_len(14).unwrap_err().kind()); + + remove_file(&path).unwrap(); +} + fn test_symlink() { let bytes = b"Hello, World!\n"; let path = prepare_with_content("miri_test_fs_link_target.txt", bytes); From e37d0e312596c06659b881c240a5afdd58395665 Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 21 Apr 2020 21:28:22 -0500 Subject: [PATCH 1900/5092] Print hex dump of alloc on reading undef bytes --- src/diagnostics.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 5189982b1361..77aaacea0240 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -114,6 +114,9 @@ pub fn report_error<'tcx, 'mir>( }; e.print_backtrace(); + if let UndefinedBehavior(UndefinedBehaviorInfo::InvalidUndefBytes(Some(ptr))) = e.kind { + ecx.memory.dump_alloc(ptr.alloc_id); + } let msg = e.to_string(); report_msg(ecx, &format!("{}: {}", title, msg), msg, helps, true) } From f49839ac30d616ceba6d46af4ecc94e80db21512 Mon Sep 17 00:00:00 2001 From: David Cook Date: Wed, 22 Apr 2020 07:09:20 -0500 Subject: [PATCH 1901/5092] Add comment --- src/shims/fs.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index e7d41b36f5a6..ea0b998c2e3d 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1084,6 +1084,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(-1) } } else { + // The file is not writable let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; Ok(-1) From 270adbc7c61a85ce8f4a3b636396b142e83b2f11 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 18 Apr 2020 13:56:09 +0200 Subject: [PATCH 1902/5092] Stacked Borrows: alignment does not matter --- src/stacked_borrows.rs | 10 ++++++---- tests/run-pass/packed_struct.rs | 8 +++++++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 3412f00964b4..03140c867b2d 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -11,7 +11,7 @@ use log::trace; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_middle::mir::RetagKind; use rustc_middle::ty; -use rustc_target::abi::{LayoutOf, Size}; +use rustc_target::abi::{Align, LayoutOf, Size}; use rustc_hir::Mutability; use crate::*; @@ -577,11 +577,13 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .size_and_align_of_mplace(place)? .map(|(size, _)| size) .unwrap_or_else(|| place.layout.size); + // `reborrow` relies on getting a `Pointer` and everything being in-bounds, + // so let's ensure that. However, we do not care about alignment. // We can see dangling ptrs in here e.g. after a Box's `Unique` was - // updated using "self.0 = ..." (can happen in Box::from_raw); see miri#1050. - let place = this.mplace_access_checked(place)?; + // updated using "self.0 = ..." (can happen in Box::from_raw) so we cannot ICE; see miri#1050. + let place = this.mplace_access_checked(place, Some(Align::from_bytes(1).unwrap()))?; + // Nothing to do for ZSTs. if size == Size::ZERO { - // Nothing to do for ZSTs. return Ok(val); } diff --git a/tests/run-pass/packed_struct.rs b/tests/run-pass/packed_struct.rs index 7aa53ef568f5..5582caaf37ea 100644 --- a/tests/run-pass/packed_struct.rs +++ b/tests/run-pass/packed_struct.rs @@ -1,4 +1,4 @@ -#![feature(unsize, coerce_unsized)] +#![feature(unsize, coerce_unsized, raw_ref_op)] use std::collections::hash_map::DefaultHasher; use std::hash::Hash; @@ -6,6 +6,7 @@ use std::hash::Hash; fn test_basic() { #[repr(packed)] struct S { + fill: u8, a: i32, b: i64, } @@ -30,6 +31,7 @@ fn test_basic() { } let mut x = S { + fill: 0, a: 42, b: 99, }; @@ -37,9 +39,13 @@ fn test_basic() { let b = x.b; assert_eq!(a, 42); assert_eq!(b, 99); + assert_eq!(&x.fill, &0); // `fill` just requirs 1-byte-align, so this is fine // can't do `assert_eq!(x.a, 42)`, because `assert_eq!` takes a reference assert_eq!({x.a}, 42); assert_eq!({x.b}, 99); + // but we *can* take a raw pointer! + assert_eq!(unsafe { (&raw const x.a).read_unaligned() }, 42); + assert_eq!(unsafe { (&raw const x.b).read_unaligned() }, 99); x.b = 77; assert_eq!({x.b}, 77); From 4b9abdaa504bdf375c09afd9e994f3d066466d3c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 22 Apr 2020 23:32:28 +0200 Subject: [PATCH 1903/5092] rustup --- rust-version | 2 +- src/eval.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index b48a98d229f2..871e50b995be 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9b2f8dbba39dd4167f22a7026674a585c3d907d8 +b2e36e6c2d229126b59e892c9147fbb68115d292 diff --git a/src/eval.rs b/src/eval.rs index 548ecee7bc42..61a5b71f0bdb 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -98,6 +98,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( start_id, tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))), ) + .unwrap() .unwrap(); // First argument: pointer to `main()`. From 9057dae235df4d893b3051991e9794af15b32902 Mon Sep 17 00:00:00 2001 From: David Cook Date: Wed, 22 Apr 2020 17:41:06 -0500 Subject: [PATCH 1904/5092] Reorder output --- src/diagnostics.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 77aaacea0240..565db7b178a1 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -114,11 +114,14 @@ pub fn report_error<'tcx, 'mir>( }; e.print_backtrace(); + let msg = e.to_string(); + let result = report_msg(ecx, &format!("{}: {}", title, msg), msg, helps, true); + if let UndefinedBehavior(UndefinedBehaviorInfo::InvalidUndefBytes(Some(ptr))) = e.kind { ecx.memory.dump_alloc(ptr.alloc_id); } - let msg = e.to_string(); - report_msg(ecx, &format!("{}: {}", title, msg), msg, helps, true) + + result } /// Report an error or note (depending on the `error` argument) at the current frame's current statement. From 5b60f0df2afba76fb6bd4cc3ae0c85ea2cfd484c Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 23 Apr 2020 02:37:58 +0000 Subject: [PATCH 1905/5092] Add ryu and tikv to trophy case --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index a86de4a55519..4d37f2c353c5 100644 --- a/README.md +++ b/README.md @@ -274,6 +274,7 @@ Definite bugs found: * [`Vec`](https://github.com/rust-lang/rust/issues/69770) and [`BTreeMap`](https://github.com/rust-lang/rust/issues/69769) leaking memory under some (panicky) conditions * [Memory leak in `beef`](https://github.com/maciejhirsz/beef/issues/12) * [Invalid use of undefined memory in `EbrCell`](https://github.com/Firstyear/concread/commit/b15be53b6ec076acb295a5c0483cdb4bf9be838f#diff-6282b2fc8e98bd089a1f0c86f648157cR229) +* [Unaligned pointer access in TiKV](https://github.com/tikv/tikv/issues/7613) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): @@ -284,6 +285,7 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [`align_to_mut` violating uniqueness of mutable references](https://github.com/rust-lang/rust/issues/68549) * [Aliasing mutable references in `sized-chunks`](https://github.com/bodil/sized-chunks/issues/8) * [`String::push_str` invalidating existing references into the string](https://github.com/rust-lang/rust/issues/70301) +- [`ryu` creating incorrect mutable references](https://github.com/dtolnay/ryu/issues/24) ## License From f84aa4a424221a8b3739f6232fec8f419d176fba Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 23 Apr 2020 02:46:36 -0600 Subject: [PATCH 1906/5092] Update README.md Co-Authored-By: Ralf Jung --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4d37f2c353c5..3d88b24da682 100644 --- a/README.md +++ b/README.md @@ -285,7 +285,7 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [`align_to_mut` violating uniqueness of mutable references](https://github.com/rust-lang/rust/issues/68549) * [Aliasing mutable references in `sized-chunks`](https://github.com/bodil/sized-chunks/issues/8) * [`String::push_str` invalidating existing references into the string](https://github.com/rust-lang/rust/issues/70301) -- [`ryu` creating incorrect mutable references](https://github.com/dtolnay/ryu/issues/24) +* [`ryu` using raw pointers outside their valid memory area](https://github.com/dtolnay/ryu/issues/24) ## License From 60fa9acdf727fa98c42ed0f95b7a4cb6b4550829 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 23 Apr 2020 08:46:49 -0700 Subject: [PATCH 1907/5092] Disable interactive prompts in CI --- src/bin/cargo-miri.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 04020009c694..ea99ee11495f 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -1,5 +1,6 @@ #![feature(inner_deref)] +use std::env; use std::fs::{self, File}; use std::io::{self, BufRead, Write}; use std::ops::Not; @@ -435,7 +436,8 @@ fn in_cargo_miri() { test_sysroot_consistency(); // We always setup. - let ask = subcommand != MiriCommand::Setup; + // Disable interactive prompts in CI (GitHub Actions, Travis, AppVeyor, etc). + let ask = subcommand != MiriCommand::Setup && env::var_os("CI").is_none(); setup(ask); if subcommand == MiriCommand::Setup { // Stop here. From 28f4f84303076e7f537ad847e61ec1166ea62fac Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 23 Apr 2020 09:12:05 -0700 Subject: [PATCH 1908/5092] Remove unneeded setup step from CI instructions in readme --- README.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/README.md b/README.md index 3d88b24da682..ea2aa955ba4d 100644 --- a/README.md +++ b/README.md @@ -127,16 +127,11 @@ MIRI_NIGHTLY=nightly-$(curl -s https://rust-lang.github.io/rustup-components-his echo "Installing latest nightly with Miri: $MIRI_NIGHTLY" rustup set profile minimal rustup default "$MIRI_NIGHTLY" - rustup component add miri -cargo miri setup cargo miri test ``` -We use `cargo miri setup` to avoid getting interactive questions about the extra -setup needed for Miri. - ### Common Problems When using the above instructions, you may encounter a number of confusing compiler From 2584507ce2eb9a7fc4c00213d216fc57c794e141 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 23 Apr 2020 10:12:48 -0700 Subject: [PATCH 1909/5092] Preserve consistent output whether or not CI is set --- src/bin/cargo-miri.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index ea99ee11495f..0252f22e7668 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -247,7 +247,9 @@ fn xargo_version() -> Option<(u32, u32, u32)> { Some((major, minor, patch)) } -fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { +fn ask_to_run(mut cmd: Command, subcommand: MiriCommand, text: &str) { + // Disable interactive prompts in CI (GitHub Actions, Travis, AppVeyor, etc). + let ask = subcommand != MiriCommand::Setup && env::var_os("CI").is_none(); if ask { let mut buf = String::new(); print!("I will run `{:?}` to {}. Proceed? [Y/n] ", cmd, text); @@ -271,9 +273,9 @@ fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { /// Performs the setup required to make `cargo miri` work: Getting a custom-built libstd. Then sets /// `MIRI_SYSROOT`. Skipped if `MIRI_SYSROOT` is already set, in which case we expect the user has /// done all this already. -fn setup(ask_user: bool) { +fn setup(subcommand: MiriCommand) { if std::env::var("MIRI_SYSROOT").is_ok() { - if !ask_user { + if subcommand == MiriCommand::Setup { println!("WARNING: MIRI_SYSROOT already set, not doing anything.") } return; @@ -287,7 +289,7 @@ fn setup(ask_user: bool) { } let mut cmd = cargo(); cmd.args(&["install", "xargo", "-f"]); - ask_to_run(cmd, ask_user, "install a recent enough xargo"); + ask_to_run(cmd, subcommand, "install a recent enough xargo"); } // Determine where the rust sources are located. `XARGO_RUST_SRC` env var trumps everything. @@ -310,7 +312,7 @@ fn setup(ask_user: bool) { cmd.args(&["component", "add", "rust-src"]); ask_to_run( cmd, - ask_user, + subcommand, "install the rustc-src component for the selected toolchain", ); } @@ -361,7 +363,8 @@ path = "lib.rs" File::create(dir.join("lib.rs")).unwrap(); // Prepare xargo invocation. let target = get_arg_flag_value("--target"); - let print_sysroot = !ask_user && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path + let print_sysroot = subcommand == MiriCommand::Setup + && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path let mut command = xargo_check(); command.arg("build").arg("-q"); command.current_dir(&dir); @@ -389,7 +392,7 @@ path = "lib.rs" if print_sysroot { // Print just the sysroot and nothing else; this way we do not need any escaping. println!("{}", sysroot.display()); - } else if !ask_user { + } else if subcommand == MiriCommand::Setup { println!("A libstd for Miri is now available in `{}`.", sysroot.display()); } } @@ -436,9 +439,7 @@ fn in_cargo_miri() { test_sysroot_consistency(); // We always setup. - // Disable interactive prompts in CI (GitHub Actions, Travis, AppVeyor, etc). - let ask = subcommand != MiriCommand::Setup && env::var_os("CI").is_none(); - setup(ask); + setup(subcommand); if subcommand == MiriCommand::Setup { // Stop here. return; From a5eaa5703c65c1708cdace6dfe11ebc84a9b4316 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 Apr 2020 19:20:09 +0200 Subject: [PATCH 1910/5092] test suite: rely on CARGO_BIN_EXE_ env vars to find Miri binary --- build.rs | 8 +------- tests/compiletest.rs | 2 +- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/build.rs b/build.rs index 97bb9358832c..56956920e2e2 100644 --- a/build.rs +++ b/build.rs @@ -1,11 +1,5 @@ -extern crate vergen; - -use std::env; - fn main() { - // Forward the profile to the main compilation - println!("cargo:rustc-env=PROFILE={}", env::var("PROFILE").unwrap()); - // Don't rebuild miri even if nothing changed + // Don't rebuild miri when nothing changed. println!("cargo:rerun-if-changed=build.rs"); // vergen vergen::generate_cargo_keys(vergen::ConstantsFlags::all()) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index d082a2cc484b..ca1879962089 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -12,7 +12,7 @@ fn miri_path() -> PathBuf { if rustc_test_suite().is_some() { PathBuf::from(option_env!("MIRI_PATH").unwrap()) } else { - PathBuf::from(concat!("target/", env!("PROFILE"), "/miri")) + PathBuf::from(env!("CARGO_BIN_EXE_miri")) } } From a4dd463eaf548de04c55296c8ed31516fe5c5983 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 23 Apr 2020 10:27:38 -0700 Subject: [PATCH 1911/5092] Keep MiriCommand out of ask_to_run function --- src/bin/cargo-miri.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 0252f22e7668..17d7ecf8c870 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -247,10 +247,9 @@ fn xargo_version() -> Option<(u32, u32, u32)> { Some((major, minor, patch)) } -fn ask_to_run(mut cmd: Command, subcommand: MiriCommand, text: &str) { +fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { // Disable interactive prompts in CI (GitHub Actions, Travis, AppVeyor, etc). - let ask = subcommand != MiriCommand::Setup && env::var_os("CI").is_none(); - if ask { + if ask && env::var_os("CI").is_none() { let mut buf = String::new(); print!("I will run `{:?}` to {}. Proceed? [Y/n] ", cmd, text); io::stdout().flush().unwrap(); @@ -281,6 +280,10 @@ fn setup(subcommand: MiriCommand) { return; } + // Subcommands other than `setup` will do a setup if necessary, but + // interactively confirm first. + let ask_user = subcommand != MiriCommand::Setup; + // First, we need xargo. if xargo_version().map_or(true, |v| v < XARGO_MIN_VERSION) { if std::env::var("XARGO_CHECK").is_ok() { @@ -289,7 +292,7 @@ fn setup(subcommand: MiriCommand) { } let mut cmd = cargo(); cmd.args(&["install", "xargo", "-f"]); - ask_to_run(cmd, subcommand, "install a recent enough xargo"); + ask_to_run(cmd, ask_user, "install a recent enough xargo"); } // Determine where the rust sources are located. `XARGO_RUST_SRC` env var trumps everything. @@ -312,7 +315,7 @@ fn setup(subcommand: MiriCommand) { cmd.args(&["component", "add", "rust-src"]); ask_to_run( cmd, - subcommand, + ask_user, "install the rustc-src component for the selected toolchain", ); } From 4dec02dd921e26524394c720895f5e18689c7e74 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 24 Apr 2020 00:52:43 +0200 Subject: [PATCH 1912/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 871e50b995be..8ed0e6ba3531 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -b2e36e6c2d229126b59e892c9147fbb68115d292 +14b15521c52549ebbb113173b4abecd124b5a823 From d9ac84d05fc58aa82b4c4306f42231bb6aeb9226 Mon Sep 17 00:00:00 2001 From: David Cook Date: Thu, 23 Apr 2020 20:00:09 -0500 Subject: [PATCH 1913/5092] Add message before dumping alloc --- src/diagnostics.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 565db7b178a1..e72232323ba2 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -118,7 +118,12 @@ pub fn report_error<'tcx, 'mir>( let result = report_msg(ecx, &format!("{}: {}", title, msg), msg, helps, true); if let UndefinedBehavior(UndefinedBehaviorInfo::InvalidUndefBytes(Some(ptr))) = e.kind { + eprintln!( + "Uninitialized read occurred at offset 0x{:x} into this allocation:", + ptr.offset.bytes(), + ); ecx.memory.dump_alloc(ptr.alloc_id); + eprintln!(); } result From 7f92eab3c477f321a55f53b6e04ac8ca2cd04ebf Mon Sep 17 00:00:00 2001 From: David Cook Date: Thu, 23 Apr 2020 20:00:25 -0500 Subject: [PATCH 1914/5092] Add test to exercise InvalidUndefBytes --- tests/compile-fail/undefined_buffer.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/compile-fail/undefined_buffer.rs diff --git a/tests/compile-fail/undefined_buffer.rs b/tests/compile-fail/undefined_buffer.rs new file mode 100644 index 000000000000..dac02a8690e9 --- /dev/null +++ b/tests/compile-fail/undefined_buffer.rs @@ -0,0 +1,20 @@ +// error-pattern: reading uninitialized memory + +use std::alloc::{alloc, dealloc, Layout}; +use std::slice::from_raw_parts; + +fn main() { + let layout = Layout::from_size_align(32, 8).unwrap(); + unsafe { + let ptr = alloc(layout); + *ptr = 0x41; + *ptr.add(1) = 0x42; + *ptr.add(2) = 0x43; + *ptr.add(3) = 0x44; + *ptr.add(16) = 0x00; + let slice1 = from_raw_parts(ptr, 16); + let slice2 = from_raw_parts(ptr.add(16), 16); + drop(slice1.cmp(slice2)); + dealloc(ptr, layout); + } +} From c46668c556be7fbb5ad71b946ce0cec66372356e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Apr 2020 11:12:50 +0200 Subject: [PATCH 1915/5092] fix exit code on rustc errors --- src/bin/miri.rs | 9 +++++++-- tests/compile-fail/rustc-error.rs | 4 ++++ 2 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 tests/compile-fail/rustc-error.rs diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 1ceb6e621a47..53a13bf85a5a 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -259,6 +259,11 @@ fn main() { rustc_driver::install_ice_hook(); let result = rustc_driver::catch_fatal_errors(move || { rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None) - }); - std::process::exit(result.is_err() as i32); + }) + .and_then(|result| result); + let exit_code = match result { + Ok(_) => rustc_driver::EXIT_SUCCESS, + Err(_) => rustc_driver::EXIT_FAILURE, + }; + std::process::exit(exit_code); } diff --git a/tests/compile-fail/rustc-error.rs b/tests/compile-fail/rustc-error.rs new file mode 100644 index 000000000000..3579a143f53b --- /dev/null +++ b/tests/compile-fail/rustc-error.rs @@ -0,0 +1,4 @@ +// Make sure we exit with non-0 status code when the program fails to build. +fn main() { + println("Hello, world!"); //~ ERROR expected function, found macro +} From b128879529cc3a2262965b183780166fbac0d0ef Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Apr 2020 11:16:03 +0200 Subject: [PATCH 1916/5092] make sure we do not discard information on the Ok exit side --- src/bin/miri.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 53a13bf85a5a..4e20e3a12da7 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -262,7 +262,7 @@ fn main() { }) .and_then(|result| result); let exit_code = match result { - Ok(_) => rustc_driver::EXIT_SUCCESS, + Ok(()) => rustc_driver::EXIT_SUCCESS, Err(_) => rustc_driver::EXIT_FAILURE, }; std::process::exit(exit_code); From 72442acaff7c1f2fc805f5cbd39d1661e50cd9d3 Mon Sep 17 00:00:00 2001 From: Hero Bird Date: Sat, 25 Apr 2020 14:58:20 +0200 Subject: [PATCH 1917/5092] Add miri trophy for LazyArray::swap (ink! PR) Details to the found in https://github.com/rust-lang/miri/issues/1364. Note that this was not a found in a `master` or production release of ink!, however without analysing the code via `miri` this could have potentially happened. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ea2aa955ba4d..d29f1e2be259 100644 --- a/README.md +++ b/README.md @@ -281,6 +281,7 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [Aliasing mutable references in `sized-chunks`](https://github.com/bodil/sized-chunks/issues/8) * [`String::push_str` invalidating existing references into the string](https://github.com/rust-lang/rust/issues/70301) * [`ryu` using raw pointers outside their valid memory area](https://github.com/dtolnay/ryu/issues/24) +* [`LazyArray::swap` method creating overlapping mutable references (ink! PR)](https://github.com/rust-lang/miri/issues/1364) ## License From 3f43305894fc25ab55c48923a0f1987ee2e9b28b Mon Sep 17 00:00:00 2001 From: Hero Bird Date: Sat, 25 Apr 2020 19:42:48 +0200 Subject: [PATCH 1918/5092] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d29f1e2be259..ecff779873ab 100644 --- a/README.md +++ b/README.md @@ -281,7 +281,7 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [Aliasing mutable references in `sized-chunks`](https://github.com/bodil/sized-chunks/issues/8) * [`String::push_str` invalidating existing references into the string](https://github.com/rust-lang/rust/issues/70301) * [`ryu` using raw pointers outside their valid memory area](https://github.com/dtolnay/ryu/issues/24) -* [`LazyArray::swap` method creating overlapping mutable references (ink! PR)](https://github.com/rust-lang/miri/issues/1364) +* [ink! creating overlapping mutable references](https://github.com/rust-lang/miri/issues/1364) ## License From e267fb4edec86c84b6c0e415a647ba9f8b9f0c9e Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 26 Apr 2020 22:13:36 -0500 Subject: [PATCH 1919/5092] Review comments --- src/diagnostics.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index e72232323ba2..114f1d9be362 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -115,8 +115,9 @@ pub fn report_error<'tcx, 'mir>( e.print_backtrace(); let msg = e.to_string(); - let result = report_msg(ecx, &format!("{}: {}", title, msg), msg, helps, true); + report_msg(ecx, &format!("{}: {}", title, msg), msg, helps, true); + // Extra output to help debug specific issues. if let UndefinedBehavior(UndefinedBehaviorInfo::InvalidUndefBytes(Some(ptr))) = e.kind { eprintln!( "Uninitialized read occurred at offset 0x{:x} into this allocation:", @@ -126,7 +127,7 @@ pub fn report_error<'tcx, 'mir>( eprintln!(); } - result + None } /// Report an error or note (depending on the `error` argument) at the current frame's current statement. @@ -137,7 +138,7 @@ fn report_msg<'tcx, 'mir>( span_msg: String, mut helps: Vec, error: bool, -) -> Option { +) { let span = if let Some(frame) = ecx.machine.stack.last() { frame.current_source_info().unwrap().span } else { @@ -178,8 +179,6 @@ fn report_msg<'tcx, 'mir>( trace!(" local {}: {:?}", i, local.value); } } - // Let the reported error determine the return code. - return None; } thread_local! { From da86c81e39ff27925e7052e1cc612414c7eeb244 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Mon, 27 Apr 2020 09:35:19 +0530 Subject: [PATCH 1920/5092] Add test to verify arg size mismatch throws UB Also: bump up `rust-version` --- rust-version | 2 +- tests/compile-fail/shim_arg_size.rs | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/shim_arg_size.rs diff --git a/rust-version b/rust-version index 8ed0e6ba3531..53979b82cf83 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -14b15521c52549ebbb113173b4abecd124b5a823 +e83f7563495dbe2629b0cbc738afb0808c4482e1 diff --git a/tests/compile-fail/shim_arg_size.rs b/tests/compile-fail/shim_arg_size.rs new file mode 100644 index 000000000000..38b5475b9f7e --- /dev/null +++ b/tests/compile-fail/shim_arg_size.rs @@ -0,0 +1,15 @@ +#![feature(rustc_private)] + +extern crate libc; + +// error-pattern: scalar size mismatch +fn main() { + extern "C" { + fn malloc(size: u32) -> *mut std::ffi::c_void; + } + + unsafe { + let p1 = malloc(42); + libc::free(p1); + }; +} From ae9796b9d82609e7a7325930f38fe469d676bc8b Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Mon, 27 Apr 2020 10:00:35 +0530 Subject: [PATCH 1921/5092] Fix shim_arg_size test for 32-bit machines --- tests/compile-fail/shim_arg_size.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/compile-fail/shim_arg_size.rs b/tests/compile-fail/shim_arg_size.rs index 38b5475b9f7e..a31461fdbf48 100644 --- a/tests/compile-fail/shim_arg_size.rs +++ b/tests/compile-fail/shim_arg_size.rs @@ -5,7 +5,13 @@ extern crate libc; // error-pattern: scalar size mismatch fn main() { extern "C" { + // Use the wrong type(ie. not the pointer width) for the `size` + // argument. + #[cfg(target_pointer_width="64")] fn malloc(size: u32) -> *mut std::ffi::c_void; + + #[cfg(target_pointer_width="32")] + fn malloc(size: u16) -> *mut std::ffi::c_void; } unsafe { From 73f258c451a36294587e48166f72fdae01217891 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Mon, 27 Apr 2020 15:34:42 +0530 Subject: [PATCH 1922/5092] Replace error-pattern with annotation; remove unreachable line --- tests/compile-fail/shim_arg_size.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/compile-fail/shim_arg_size.rs b/tests/compile-fail/shim_arg_size.rs index a31461fdbf48..dd8d6dac51de 100644 --- a/tests/compile-fail/shim_arg_size.rs +++ b/tests/compile-fail/shim_arg_size.rs @@ -1,8 +1,5 @@ #![feature(rustc_private)] -extern crate libc; - -// error-pattern: scalar size mismatch fn main() { extern "C" { // Use the wrong type(ie. not the pointer width) for the `size` @@ -15,7 +12,6 @@ fn main() { } unsafe { - let p1 = malloc(42); - libc::free(p1); + let _p1 = malloc(42); //~ ERROR Undefined Behavior: scalar size mismatch }; } From a5ddaa07eb79ff6288a686aa17b134116eab4eb8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Apr 2020 12:27:56 +0200 Subject: [PATCH 1923/5092] rename tests: undefined -> uninit --- ...rs => overwriting_part_of_relocation_makes_the_rest_uninit.rs} | 0 .../{transmute-pair-undef.rs => transmute-pair-uninit.rs} | 0 tests/compile-fail/{undefined_buffer.rs => uninit_buffer.rs} | 0 .../compile-fail/{undefined_byte_read.rs => uninit_byte_read.rs} | 0 tests/run-pass/{move-undef-primval.rs => move-uninit-primval.rs} | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename tests/compile-fail/{overwriting_part_of_relocation_makes_the_rest_undefined.rs => overwriting_part_of_relocation_makes_the_rest_uninit.rs} (100%) rename tests/compile-fail/{transmute-pair-undef.rs => transmute-pair-uninit.rs} (100%) rename tests/compile-fail/{undefined_buffer.rs => uninit_buffer.rs} (100%) rename tests/compile-fail/{undefined_byte_read.rs => uninit_byte_read.rs} (100%) rename tests/run-pass/{move-undef-primval.rs => move-uninit-primval.rs} (100%) diff --git a/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs b/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_uninit.rs similarity index 100% rename from tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs rename to tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_uninit.rs diff --git a/tests/compile-fail/transmute-pair-undef.rs b/tests/compile-fail/transmute-pair-uninit.rs similarity index 100% rename from tests/compile-fail/transmute-pair-undef.rs rename to tests/compile-fail/transmute-pair-uninit.rs diff --git a/tests/compile-fail/undefined_buffer.rs b/tests/compile-fail/uninit_buffer.rs similarity index 100% rename from tests/compile-fail/undefined_buffer.rs rename to tests/compile-fail/uninit_buffer.rs diff --git a/tests/compile-fail/undefined_byte_read.rs b/tests/compile-fail/uninit_byte_read.rs similarity index 100% rename from tests/compile-fail/undefined_byte_read.rs rename to tests/compile-fail/uninit_byte_read.rs diff --git a/tests/run-pass/move-undef-primval.rs b/tests/run-pass/move-uninit-primval.rs similarity index 100% rename from tests/run-pass/move-undef-primval.rs rename to tests/run-pass/move-uninit-primval.rs From 82f17ab91714bcc8bd2a5591e90db690d449d38c Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 16 Mar 2020 16:48:44 -0700 Subject: [PATCH 1924/5092] Implement basic support for concurrency (Linux only). --- src/eval.rs | 3 +- src/lib.rs | 3 + src/machine.rs | 67 ++++-- src/shims/foreign_items/posix.rs | 101 ++++++++- src/shims/foreign_items/windows.rs | 6 +- src/shims/tls.rs | 92 ++++---- src/threads.rs | 303 +++++++++++++++++++++++++++ tests/compile-fail/thread-spawn.rs | 7 - tests/run-pass/concurrency/simple.rs | 59 ++++++ 9 files changed, 568 insertions(+), 73 deletions(-) create mode 100644 src/threads.rs delete mode 100644 tests/compile-fail/thread-spawn.rs create mode 100644 tests/run-pass/concurrency/simple.rs diff --git a/src/eval.rs b/src/eval.rs index 61a5b71f0bdb..b0a59c64d1e1 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -205,7 +205,8 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> // Perform the main execution. let res: InterpResult<'_, i64> = (|| { // Main loop. - while ecx.step()? { + while ecx.schedule()? { + assert!(ecx.step()?); ecx.process_diagnostics(); } // Read the return code pointer *before* we run TLS destructors, to assert diff --git a/src/lib.rs b/src/lib.rs index 2f381b4a3454..c042526be64c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,6 +12,7 @@ extern crate rustc_ast; #[macro_use] extern crate rustc_middle; extern crate rustc_data_structures; extern crate rustc_hir; +extern crate rustc_index; extern crate rustc_mir; extern crate rustc_span; extern crate rustc_target; @@ -26,6 +27,7 @@ mod operator; mod range_map; mod shims; mod stacked_borrows; +mod threads; // Make all those symbols available in the same place as our own. pub use rustc_mir::interpret::*; @@ -60,6 +62,7 @@ pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, Stack, Stacks, Tag, }; +pub use crate::threads::EvalContextExt as ThreadsEvalContextExt; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. diff --git a/src/machine.rs b/src/machine.rs index 2ab5f10af66d..9d1fa9b78c32 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -26,6 +26,8 @@ use rustc_target::abi::{LayoutOf, Size}; use crate::*; +pub use crate::threads::{ThreadId, ThreadSet, ThreadLocalStorage}; + // Some global facts about the emulated machine. pub const PAGE_SIZE: u64 = 4 * 1024; // FIXME: adjust to target architecture pub const STACK_ADDR: u64 = 32 * PAGE_SIZE; // not really about the "stack", but where we start assigning integer addresses to allocations @@ -107,6 +109,7 @@ pub struct AllocExtra { pub struct MemoryExtra { pub stacked_borrows: Option, pub intptrcast: intptrcast::MemoryExtra, + pub tls: ThreadLocalStorage, /// Mapping extern static names to their canonical allocation. extern_statics: FxHashMap, @@ -143,6 +146,7 @@ impl MemoryExtra { rng: RefCell::new(rng), tracked_alloc_id, check_alignment, + tls: Default::default(), } } @@ -251,8 +255,8 @@ pub struct Evaluator<'mir, 'tcx> { /// The "time anchor" for this machine's monotone clock (for `Instant` simulation). pub(crate) time_anchor: Instant, - /// The call stack. - pub(crate) stack: Vec>>, + /// The set of threads. + pub(crate) threads: ThreadSet<'mir, 'tcx>, /// Precomputed `TyLayout`s for primitive data types that are commonly used inside Miri. pub(crate) layouts: PrimitiveLayouts<'tcx>, @@ -282,7 +286,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { panic_payload: None, time_anchor: Instant::now(), layouts, - stack: Vec::default(), + threads: Default::default(), } } } @@ -326,6 +330,19 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { memory_extra.check_alignment } + #[inline(always)] + fn stack<'a>( + ecx: &'a InterpCx<'mir, 'tcx, Self> + ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] { + ecx.active_thread_stack() + } + + fn stack_mut<'a>( + ecx: &'a mut InterpCx<'mir, 'tcx, Self> + ) -> &'a mut Vec> { + ecx.active_thread_stack_mut() + } + #[inline(always)] fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { ecx.machine.validate @@ -418,29 +435,39 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn canonical_alloc_id(mem: &Memory<'mir, 'tcx, Self>, id: AllocId) -> AllocId { let tcx = mem.tcx; - // Figure out if this is an extern static, and if yes, which one. - let def_id = match tcx.alloc_map.lock().get(id) { - Some(GlobalAlloc::Static(def_id)) if tcx.is_foreign_item(def_id) => def_id, + let alloc = tcx.alloc_map.lock().get(id); + match alloc { + Some(GlobalAlloc::Static(def_id)) if tcx.is_foreign_item(def_id) => { + // Figure out if this is an extern static, and if yes, which one. + let attrs = tcx.get_attrs(def_id); + let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { + Some(name) => name, + None => tcx.item_name(def_id), + }; + // Check if we know this one. + if let Some(canonical_id) = mem.extra.extern_statics.get(&link_name) { + trace!("canonical_alloc_id: {:?} ({}) -> {:?}", id, link_name, canonical_id); + *canonical_id + } else { + // Return original id; `Memory::get_static_alloc` will throw an error. + id + } + }, + Some(GlobalAlloc::Static(def_id)) if tcx.has_attr(def_id, sym::thread_local) => { + // We have a thread local, so we need to get a unique allocation id for it. + mem.extra.tls.get_or_register_allocation(*tcx, id) + }, _ => { // No need to canonicalize anything. - return id; + id } - }; - let attrs = tcx.get_attrs(def_id); - let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { - Some(name) => name, - None => tcx.item_name(def_id), - }; - // Check if we know this one. - if let Some(canonical_id) = mem.extra.extern_statics.get(&link_name) { - trace!("canonical_alloc_id: {:?} ({}) -> {:?}", id, link_name, canonical_id); - *canonical_id - } else { - // Return original id; `Memory::get_static_alloc` will throw an error. - id } } + fn resolve_thread_local_allocation_id(extra: &Self::MemoryExtra, id: AllocId) -> AllocId { + extra.tls.resolve_allocation(id) + } + fn init_allocation_extra<'b>( memory_extra: &MemoryExtra, id: AllocId, diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 70e16a65b59b..47b661061d69 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -6,6 +6,7 @@ use std::convert::TryFrom; use log::trace; use crate::*; +use rustc_index::vec::Idx; use rustc_middle::mir; use rustc_target::abi::{Align, LayoutOf, Size}; @@ -221,13 +222,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "pthread_getspecific" => { let key = this.force_bits(this.read_scalar(args[0])?.not_undef()?, args[0].layout.size)?; - let ptr = this.machine.tls.load_tls(key, this)?; + let active_thread = this.get_active_thread()?; + let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { let key = this.force_bits(this.read_scalar(args[0])?.not_undef()?, args[0].layout.size)?; + let active_thread = this.get_active_thread()?; let new_ptr = this.read_scalar(args[1])?.not_undef()?; - this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?; + this.machine.tls.store_tls(key, active_thread, this.test_null(new_ptr)?)?; // Return success (`0`). this.write_null(dest)?; @@ -291,11 +294,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } - // Better error for attempts to create a thread - "pthread_create" => { - throw_unsup_format!("Miri does not support threading"); - } - // Miscellaneous "isatty" => { let _fd = this.read_scalar(args[0])?.to_i32()?; @@ -316,7 +314,94 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - // Incomplete shims that we "stub out" just to get pre-main initialization code to work. + // Threading + "pthread_create" => { + assert_eq!(args.len(), 4); + let func = args[2]; + let fn_ptr = this.read_scalar(func)?.not_undef()?; + let fn_val = this.memory.get_fn(fn_ptr)?; + let instance = match fn_val { + rustc_mir::interpret::FnVal::Instance(instance) => instance, + _ => unreachable!(), + }; + let thread_info_place = this.deref_operand(args[0])?; + let thread_info_type = args[0].layout.ty + .builtin_deref(true) + .ok_or_else(|| err_ub_format!( + "wrong signature used for `pthread_create`: first argument must be a raw pointer." + ))? + .ty; + let thread_info_layout = this.layout_of(thread_info_type)?; + let func_arg = match *args[3] { + rustc_mir::interpret::Operand::Immediate(immediate) => immediate, + _ => unreachable!(), + }; + let func_args = [func_arg]; + let ret_place = + this.allocate(this.layout_of(this.tcx.types.usize)?, MiriMemoryKind::Machine.into()); + let new_thread_id = this.create_thread()?; + let old_thread_id = this.set_active_thread(new_thread_id)?; + this.call_function( + instance, + &func_args[..], + Some(ret_place.into()), + StackPopCleanup::None { cleanup: true }, + )?; + this.set_active_thread(old_thread_id)?; + this.write_scalar( + Scalar::from_uint(new_thread_id.index() as u128, thread_info_layout.size), + thread_info_place.into(), + )?; + + // Return success (`0`). + this.write_null(dest)?; + } + "pthread_join" => { + assert_eq!(args.len(), 2); + assert!( + this.is_null(this.read_scalar(args[1])?.not_undef()?)?, + "Miri supports pthread_join only with retval==NULL" + ); + let thread = this.read_scalar(args[0])?.not_undef()?.to_machine_usize(this)?; + this.join_thread(thread.into())?; + + // Return success (`0`). + this.write_null(dest)?; + } + "pthread_detach" => { + let thread = this.read_scalar(args[0])?.not_undef()?.to_machine_usize(this)?; + this.detach_thread(thread.into())?; + + // Return success (`0`). + this.write_null(dest)?; + } + + "pthread_attr_getguardsize" => { + assert_eq!(args.len(), 2); + + let guard_size = this.deref_operand(args[1])?; + let guard_size_type = args[1].layout.ty + .builtin_deref(true) + .ok_or_else(|| err_ub_format!( + "wrong signature used for `pthread_attr_getguardsize`: first argument must be a raw pointer." + ))? + .ty; + let guard_size_layout = this.layout_of(guard_size_type)?; + this.write_scalar(Scalar::from_uint(crate::PAGE_SIZE, guard_size_layout.size), guard_size.into())?; + + // Return success (`0`). + this.write_null(dest)?; + } + + "prctl" => { + let option = this.read_scalar(args[0])?.not_undef()?.to_i32()?; + assert_eq!(option, 0xf, "Miri supports only PR_SET_NAME"); + + // Return success (`0`). + this.write_null(dest)?; + } + + // Incomplete shims that we "stub out" just to get pre-main initialziation code to work. // These shims are enabled only when the caller is in the standard library. | "pthread_attr_init" | "pthread_attr_destroy" diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 0950a02bf92f..a58444b21bff 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -144,13 +144,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "TlsGetValue" => { let key = u128::from(this.read_scalar(args[0])?.to_u32()?); - let ptr = this.machine.tls.load_tls(key, this)?; + let active_thread = this.get_active_thread()?; + let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "TlsSetValue" => { let key = u128::from(this.read_scalar(args[0])?.to_u32()?); + let active_thread = this.get_active_thread()?; let new_ptr = this.read_scalar(args[1])?.not_undef()?; - this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?; + this.machine.tls.store_tls(key, active_thread, this.test_null(new_ptr)?)?; // Return success (`1`). this.write_scalar(Scalar::from_i32(1), dest)?; diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 7b8446840295..d16acb750037 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -1,22 +1,24 @@ //! Implement thread-local storage. use std::collections::BTreeMap; +use std::collections::btree_map::Entry; use log::trace; use rustc_middle::ty; use rustc_target::abi::{Size, HasDataLayout}; -use crate::{HelpersEvalContextExt, InterpResult, MPlaceTy, Scalar, StackPopCleanup, Tag}; +use crate::{HelpersEvalContextExt, ThreadsEvalContextExt, InterpResult, MPlaceTy, Scalar, StackPopCleanup, Tag}; +use crate::machine::ThreadId; pub type TlsKey = u128; -#[derive(Copy, Clone, Debug)] +#[derive(Clone, Debug)] pub struct TlsEntry<'tcx> { /// The data for this key. None is used to represent NULL. /// (We normalize this early to avoid having to do a NULL-ptr-test each time we access the data.) /// Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. - data: Option>, + data: BTreeMap>, dtor: Option>, } @@ -52,7 +54,7 @@ impl<'tcx> TlsData<'tcx> { pub fn create_tls_key(&mut self, dtor: Option>, max_size: Size) -> InterpResult<'tcx, TlsKey> { let new_key = self.next_key; self.next_key += 1; - self.keys.insert(new_key, TlsEntry { data: None, dtor }).unwrap_none(); + self.keys.insert(new_key, TlsEntry { data: Default::default(), dtor }).unwrap_none(); trace!("New TLS key allocated: {} with dtor {:?}", new_key, dtor); if max_size.bits() < 128 && new_key >= (1u128 << max_size.bits() as u128) { @@ -74,22 +76,34 @@ impl<'tcx> TlsData<'tcx> { pub fn load_tls( &self, key: TlsKey, + thread_id: ThreadId, cx: &impl HasDataLayout, ) -> InterpResult<'tcx, Scalar> { match self.keys.get(&key) { - Some(&TlsEntry { data, .. }) => { - trace!("TLS key {} loaded: {:?}", key, data); - Ok(data.unwrap_or_else(|| Scalar::null_ptr(cx).into())) + Some(TlsEntry { data, .. }) => { + let value = data.get(&thread_id).cloned(); + trace!("TLS key {} for thread {:?} loaded: {:?}", key, thread_id, value); + Ok(value.unwrap_or_else(|| Scalar::null_ptr(cx).into())) } None => throw_ub_format!("loading from a non-existing TLS key: {}", key), } } - pub fn store_tls(&mut self, key: TlsKey, new_data: Option>) -> InterpResult<'tcx> { + pub fn store_tls( + &mut self, + key: TlsKey, thread_id: ThreadId, new_data: Option>) -> InterpResult<'tcx> { match self.keys.get_mut(&key) { Some(TlsEntry { data, .. }) => { - trace!("TLS key {} stored: {:?}", key, new_data); - *data = new_data; + match new_data { + Some(ptr) => { + trace!("TLS key {} for thread {:?} stored: {:?}", key, thread_id, ptr); + data.insert(thread_id, ptr); + } + None => { + trace!("TLS key {} for thread {:?} removed", key, thread_id); + data.remove(&thread_id); + } + } Ok(()) } None => throw_ub_format!("storing to a non-existing TLS key: {}", key), @@ -131,7 +145,8 @@ impl<'tcx> TlsData<'tcx> { fn fetch_tls_dtor( &mut self, key: Option, - ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { + thread_id: ThreadId, + ) -> Option<(ty::Instance<'tcx>, ThreadId, Scalar, TlsKey)> { use std::collections::Bound::*; let thread_local = &mut self.keys; @@ -142,12 +157,15 @@ impl<'tcx> TlsData<'tcx> { for (&key, TlsEntry { data, dtor }) in thread_local.range_mut((start, Unbounded)) { - if let Some(data_scalar) = *data { - if let Some(dtor) = dtor { - let ret = Some((*dtor, data_scalar, key)); - *data = None; - return ret; + match data.entry(thread_id) { + Entry::Occupied(entry) => { + let (thread_id, data_scalar) = entry.remove_entry(); + if let Some(dtor) = dtor { + let ret = Some((dtor, thread_id, data_scalar, key)); + return ret; + } } + Entry::Vacant(_) => {} } } None @@ -156,6 +174,7 @@ impl<'tcx> TlsData<'tcx> { impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + /// Run TLS destructors for the currently active thread. fn run_tls_dtors(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); assert!(!this.machine.tls.dtors_running, "running TLS dtors twice"); @@ -204,28 +223,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Now run the "keyed" destructors. - let mut dtor = this.machine.tls.fetch_tls_dtor(None); - while let Some((instance, ptr, key)) = dtor { - trace!("Running TLS dtor {:?} on {:?}", instance, ptr); - assert!(!this.is_null(ptr).unwrap(), "data can't be NULL when dtor is called!"); + for thread_id in this.get_all_thread_ids() { + this.set_active_thread(thread_id)?; + let mut dtor = this.machine.tls.fetch_tls_dtor(None, thread_id); + while let Some((instance, thread_id, ptr, key)) = dtor { + trace!("Running TLS dtor {:?} on {:?} at {:?}", instance, ptr, thread_id); + assert!(!this.is_null(ptr).unwrap(), "Data can't be NULL when dtor is called!"); - let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); - this.call_function( - instance, - &[ptr.into()], - Some(ret_place), - StackPopCleanup::None { cleanup: true }, - )?; + let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); + this.call_function( + instance, + &[ptr.into()], + Some(ret_place), + StackPopCleanup::None { cleanup: true }, + )?; - // step until out of stackframes - this.run()?; + // step until out of stackframes + this.run()?; - // Fetch next dtor after `key`. - dtor = match this.machine.tls.fetch_tls_dtor(Some(key)) { - dtor @ Some(_) => dtor, - // We ran each dtor once, start over from the beginning. - None => this.machine.tls.fetch_tls_dtor(None), - }; + // Fetch next dtor after `key`. + dtor = match this.machine.tls.fetch_tls_dtor(Some(key), thread_id) { + dtor @ Some(_) => dtor, + // We ran each dtor once, start over from the beginning. + None => this.machine.tls.fetch_tls_dtor(None, thread_id), + }; + } } Ok(()) } diff --git a/src/threads.rs b/src/threads.rs new file mode 100644 index 000000000000..14ee58c2ee3e --- /dev/null +++ b/src/threads.rs @@ -0,0 +1,303 @@ +//! Implements threads. + +use std::cell::RefCell; +use std::collections::hash_map::Entry; + +use log::trace; + +use rustc_middle::ty; +use rustc_data_structures::fx::FxHashMap; +use rustc_index::vec::{Idx, IndexVec}; + +use crate::*; + +/// A thread identifier. +#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] +pub struct ThreadId(usize); + +impl Idx for ThreadId { + fn new(idx: usize) -> Self { + ThreadId(idx) + } + fn index(self) -> usize { + self.0 + } +} + +impl From for ThreadId { + fn from(id: u64) -> Self { + Self(id as usize) + } +} + +/// The state of a thread. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum ThreadState { + /// The thread is enabled and can be executed. + Enabled, + /// The thread tried to join the specified thread and is blocked until that + /// thread terminates. + Blocked(ThreadId), + /// The thread has terminated its execution (we do not delete terminated + /// threads.) + Terminated, +} + +/// A thread. +pub struct Thread<'mir, 'tcx> { + state: ThreadState, + /// The virtual call stack. + stack: Vec>>, + /// Is the thread detached? + /// + /// A thread is detached if its join handle was destroyed and no other + /// thread can join it. + detached: bool, +} + +impl<'mir, 'tcx> Thread<'mir, 'tcx> { + /// Check if the thread terminated. If yes, change the state to terminated + /// and return `true`. + fn check_terminated(&mut self) -> bool { + if self.state == ThreadState::Enabled { + if self.stack.is_empty() { + self.state = ThreadState::Terminated; + return true; + } + } + false + } +} + +impl<'mir, 'tcx> std::fmt::Debug for Thread<'mir, 'tcx> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.state) + } +} + +impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> { + fn default() -> Self { + Self { state: ThreadState::Enabled, stack: Vec::new(), detached: false } + } +} + +/// A set of threads. +#[derive(Debug)] +pub struct ThreadSet<'mir, 'tcx> { + /// Identifier of the currently active thread. + active_thread: ThreadId, + /// Threads used in the program. + /// + /// Note that this vector also contains terminated threads. + threads: IndexVec>, + + /// List of threads that just terminated. TODO: Cleanup. + terminated_threads: Vec, +} + +impl<'mir, 'tcx> Default for ThreadSet<'mir, 'tcx> { + fn default() -> Self { + let mut threads = IndexVec::new(); + threads.push(Default::default()); + Self { + active_thread: ThreadId::new(0), + threads: threads, + terminated_threads: Default::default(), + } + } +} + +impl<'mir, 'tcx: 'mir> ThreadSet<'mir, 'tcx> { + /// Borrow the stack of the active thread. + fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] { + &self.threads[self.active_thread].stack + } + /// Mutably borrow the stack of the active thread. + fn active_thread_stack_mut(&mut self) -> &mut Vec>> { + &mut self.threads[self.active_thread].stack + } + /// Create a new thread and returns its id. + fn create_thread(&mut self) -> ThreadId { + let new_thread_id = ThreadId::new(self.threads.len()); + self.threads.push(Default::default()); + new_thread_id + } + /// Set an active thread and return the id of the thread that was active before. + fn set_active_thread(&mut self, id: ThreadId) -> ThreadId { + let active_thread_id = self.active_thread; + self.active_thread = id; + assert!(self.active_thread.index() < self.threads.len()); + active_thread_id + } + /// Get the id of the currently active thread. + fn get_active_thread(&self) -> ThreadId { + self.active_thread + } + /// Mark the thread as detached, which means that no other thread will try + /// to join it and the thread is responsible for cleaning up. + fn detach_thread(&mut self, id: ThreadId) { + self.threads[id].detached = true; + } + /// Mark that the active thread tries to join the thread with `joined_thread_id`. + fn join_thread(&mut self, joined_thread_id: ThreadId) { + assert!(!self.threads[joined_thread_id].detached, "Bug: trying to join a detached thread."); + assert_ne!(joined_thread_id, self.active_thread, "Bug: trying to join itself"); + assert!( + self.threads + .iter() + .all(|thread| thread.state != ThreadState::Blocked(joined_thread_id)), + "Bug: multiple threads try to join the same thread." + ); + if self.threads[joined_thread_id].state != ThreadState::Terminated { + // The joined thread is still running, we need to wait for it. + self.threads[self.active_thread].state = ThreadState::Blocked(joined_thread_id); + trace!( + "{:?} blocked on {:?} when trying to join", + self.active_thread, + joined_thread_id + ); + } + } + /// Get ids of all threads ever allocated. + fn get_all_thread_ids(&mut self) -> Vec { + (0..self.threads.len()).map(ThreadId::new).collect() + } + /// Decide which thread to run next. + /// + /// Returns `false` if all threads terminated. + fn schedule(&mut self) -> InterpResult<'tcx, bool> { + if self.threads[self.active_thread].check_terminated() { + // Check if we need to unblock any threads. + for (i, thread) in self.threads.iter_enumerated_mut() { + if thread.state == ThreadState::Blocked(self.active_thread) { + trace!("unblocking {:?} because {:?} terminated", i, self.active_thread); + thread.state = ThreadState::Enabled; + } + } + } + if self.threads[self.active_thread].state == ThreadState::Enabled { + return Ok(true); + } + if let Some(enabled_thread) = + self.threads.iter().position(|thread| thread.state == ThreadState::Enabled) + { + self.active_thread = ThreadId::new(enabled_thread); + return Ok(true); + } + if self.threads.iter().all(|thread| thread.state == ThreadState::Terminated) { + Ok(false) + } else { + throw_machine_stop!(TerminationInfo::Abort(Some(format!("execution deadlocked")))) + } + } +} + +/// In Rust, a thread local variable is just a specially marked static. To +/// ensure a property that each memory allocation has a globally unique +/// allocation identifier, we create a fresh allocation id for each thread. This +/// data structure keeps the track of the created allocation identifiers and +/// their relation to the original static allocations. +#[derive(Clone, Debug, Default)] +pub struct ThreadLocalStorage { + /// A map from a thread local allocation identifier to the static from which + /// it was created. + thread_local_origin: RefCell>, + /// A map from a thread local static and thread id to the unique thread + /// local allocation. + thread_local_allocations: RefCell>, + /// The currently active thread. + active_thread: Option, +} + +impl ThreadLocalStorage { + /// For static allocation identifier `original_id` get a thread local + /// allocation identifier. If it is not allocated yet, allocate. + pub fn get_or_register_allocation(&self, tcx: ty::TyCtxt<'_>, original_id: AllocId) -> AllocId { + match self + .thread_local_allocations + .borrow_mut() + .entry((original_id, self.active_thread.unwrap())) + { + Entry::Occupied(entry) => *entry.get(), + Entry::Vacant(entry) => { + let fresh_id = tcx.alloc_map.lock().reserve(); + entry.insert(fresh_id); + self.thread_local_origin.borrow_mut().insert(fresh_id, original_id); + trace!( + "get_or_register_allocation(original_id={:?}) -> {:?}", + original_id, + fresh_id + ); + fresh_id + } + } + } + /// For thread local allocation identifier `alloc_id`, retrieve the original + /// static allocation identifier from which it was created. + pub fn resolve_allocation(&self, alloc_id: AllocId) -> AllocId { + trace!("resolve_allocation(alloc_id: {:?})", alloc_id); + if let Some(original_id) = self.thread_local_origin.borrow().get(&alloc_id) { + trace!("resolve_allocation(alloc_id: {:?}) -> {:?}", alloc_id, original_id); + *original_id + } else { + alloc_id + } + } + /// Set which thread is currently active. + fn set_active_thread(&mut self, active_thread: ThreadId) { + self.active_thread = Some(active_thread); + } +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn create_thread(&mut self) -> InterpResult<'tcx, ThreadId> { + let this = self.eval_context_mut(); + Ok(this.machine.threads.create_thread()) + } + fn detach_thread(&mut self, thread_id: ThreadId) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + this.machine.threads.detach_thread(thread_id); + Ok(()) + } + fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + this.machine.threads.join_thread(joined_thread_id); + Ok(()) + } + fn set_active_thread(&mut self, thread_id: ThreadId) -> InterpResult<'tcx, ThreadId> { + let this = self.eval_context_mut(); + this.memory.extra.tls.set_active_thread(thread_id); + Ok(this.machine.threads.set_active_thread(thread_id)) + } + fn get_active_thread(&self) -> InterpResult<'tcx, ThreadId> { + let this = self.eval_context_ref(); + Ok(this.machine.threads.get_active_thread()) + } + fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] { + let this = self.eval_context_ref(); + this.machine.threads.active_thread_stack() + } + fn active_thread_stack_mut(&mut self) -> &mut Vec>> { + let this = self.eval_context_mut(); + this.machine.threads.active_thread_stack_mut() + } + fn get_all_thread_ids(&mut self) -> Vec { + let this = self.eval_context_mut(); + this.machine.threads.get_all_thread_ids() + } + /// Decide which thread to run next. + /// + /// Returns `false` if all threads terminated. + fn schedule(&mut self) -> InterpResult<'tcx, bool> { + let this = self.eval_context_mut(); + // Find the next thread to run. + if this.machine.threads.schedule()? { + let active_thread = this.machine.threads.get_active_thread(); + this.memory.extra.tls.set_active_thread(active_thread); + Ok(true) + } else { + Ok(false) + } + } +} diff --git a/tests/compile-fail/thread-spawn.rs b/tests/compile-fail/thread-spawn.rs deleted file mode 100644 index 450dea99f552..000000000000 --- a/tests/compile-fail/thread-spawn.rs +++ /dev/null @@ -1,7 +0,0 @@ -use std::thread; - -// error-pattern: Miri does not support threading - -fn main() { - thread::spawn(|| {}); -} diff --git a/tests/run-pass/concurrency/simple.rs b/tests/run-pass/concurrency/simple.rs new file mode 100644 index 000000000000..5c295d1702dd --- /dev/null +++ b/tests/run-pass/concurrency/simple.rs @@ -0,0 +1,59 @@ +use std::thread; + +fn create_and_detach() { + thread::spawn(|| ()); +} + +fn create_and_join() { + thread::spawn(|| ()).join().unwrap(); +} + +fn create_and_get_result() { + let nine = thread::spawn(|| 5 + 4).join().unwrap(); + assert_eq!(nine, 9); +} + +fn create_and_leak_result() { + thread::spawn(|| 7); +} + +fn create_nested_and_detach() { + thread::spawn(|| { + thread::spawn(|| ()); + }); +} + +fn create_nested_and_join() { + let handle = thread::spawn(|| thread::spawn(|| ())); + let handle_nested = handle.join().unwrap(); + handle_nested.join().unwrap(); +} + +fn create_move_in() { + let x = String::from("Hello!"); + thread::spawn(move || { + assert_eq!(x.len(), 6); + }) + .join() + .unwrap(); +} + +fn create_move_out() { + let result = thread::spawn(|| { + String::from("Hello!") + }) + .join() + .unwrap(); + assert_eq!(result.len(), 6); +} + +fn main() { + create_and_detach(); + create_and_join(); + create_and_get_result(); + create_and_leak_result(); + create_nested_and_detach(); + create_nested_and_join(); + create_move_in(); + create_move_out(); +} From 58a6a2729aa03ef8ca1c68f9c0396fafa1208f58 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Wed, 1 Apr 2020 16:26:41 -0700 Subject: [PATCH 1925/5092] Add a warning that Miri does not check for data-races. --- README.md | 4 +++- src/shims/foreign_items/posix.rs | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ecff779873ab..fb981a71f0e4 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,9 @@ in your program, and cannot run all programs: * Miri runs the program as a platform-independent interpreter, so the program has no access to most platform-specific APIs or FFI. A few APIs have been implemented (such as printing to stdout) but most have not: for example, Miri - currently does not support concurrency, or SIMD, or networking. + currently does not support SIMD or networking. +* Miri currently does not check for data-races and other concurrency related + issues. [rust]: https://www.rust-lang.org/ [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 47b661061d69..878ab8896dda 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -316,6 +316,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_create" => { + println!("WARNING: The thread support is experimental. \ + For example, Miri does not detect data races yet."); assert_eq!(args.len(), 4); let func = args[2]; let fn_ptr = this.read_scalar(func)?.not_undef()?; From 8dd8f199cab87584387ff1dbd74430e908e1f1e2 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Wed, 1 Apr 2020 16:28:33 -0700 Subject: [PATCH 1926/5092] Update to support the updated API. --- src/machine.rs | 9 +++++++-- src/threads.rs | 13 +++++++++---- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 9d1fa9b78c32..e6fea672c608 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -464,8 +464,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } } - fn resolve_thread_local_allocation_id(extra: &Self::MemoryExtra, id: AllocId) -> AllocId { - extra.tls.resolve_allocation(id) + #[inline(always)] + fn resolve_maybe_global_alloc( + tcx: ty::query::TyCtxtAt<'tcx>, + extra: &Self::MemoryExtra, + id: AllocId, + ) -> Option> { + extra.tls.resolve_allocation(*tcx, id) } fn init_allocation_extra<'b>( diff --git a/src/threads.rs b/src/threads.rs index 14ee58c2ee3e..618713e3c3de 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -5,9 +5,10 @@ use std::collections::hash_map::Entry; use log::trace; -use rustc_middle::ty; use rustc_data_structures::fx::FxHashMap; use rustc_index::vec::{Idx, IndexVec}; +use rustc_middle::mir; +use rustc_middle::ty; use crate::*; @@ -234,13 +235,17 @@ impl ThreadLocalStorage { } /// For thread local allocation identifier `alloc_id`, retrieve the original /// static allocation identifier from which it was created. - pub fn resolve_allocation(&self, alloc_id: AllocId) -> AllocId { + pub fn resolve_allocation<'tcx>( + &self, + tcx: ty::TyCtxt<'tcx>, + alloc_id: AllocId, + ) -> Option> { trace!("resolve_allocation(alloc_id: {:?})", alloc_id); if let Some(original_id) = self.thread_local_origin.borrow().get(&alloc_id) { trace!("resolve_allocation(alloc_id: {:?}) -> {:?}", alloc_id, original_id); - *original_id + tcx.alloc_map.lock().get(*original_id) } else { - alloc_id + tcx.alloc_map.lock().get(alloc_id) } } /// Set which thread is currently active. From 92946b5a9cc52bfef2338b2075cec85561652449 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Wed, 1 Apr 2020 16:28:53 -0700 Subject: [PATCH 1927/5092] Add a test for thread locals. --- tests/run-pass/concurrency/thread_locals.rs | 48 +++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 tests/run-pass/concurrency/thread_locals.rs diff --git a/tests/run-pass/concurrency/thread_locals.rs b/tests/run-pass/concurrency/thread_locals.rs new file mode 100644 index 000000000000..d0d25ba7f70c --- /dev/null +++ b/tests/run-pass/concurrency/thread_locals.rs @@ -0,0 +1,48 @@ +#![feature(thread_local)] + +use std::thread; + +#[thread_local] +static mut A: u8 = 0; +#[thread_local] +static mut B: u8 = 0; +static mut C: u8 = 0; + +unsafe fn get_a_ref() -> *mut u8 { + &mut A +} + +fn main() { + + unsafe { + let x = get_a_ref(); + *x = 5; + assert_eq!(A, 5); + B = 15; + C = 25; + } + + thread::spawn(|| { + unsafe { + assert_eq!(A, 0); + assert_eq!(B, 0); + assert_eq!(C, 25); + B = 14; + C = 24; + let y = get_a_ref(); + assert_eq!(*y, 0); + *y = 4; + assert_eq!(A, 4); + assert_eq!(*get_a_ref(), 4); + + } + }).join().unwrap(); + + unsafe { + assert_eq!(*get_a_ref(), 5); + assert_eq!(A, 5); + assert_eq!(B, 15); + assert_eq!(C, 24); + } + +} \ No newline at end of file From aef4c955995468d7efec81b951a1414bd3278a23 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Fri, 3 Apr 2020 16:09:42 -0700 Subject: [PATCH 1928/5092] Fix the problem of sending pointed to thread local statics. Add a regression test. --- src/machine.rs | 23 +++++++++++++++++++ tests/run-pass/concurrency/simple.stdout | 10 ++++++++ tests/run-pass/concurrency/thread_locals.rs | 16 +++++++++---- .../run-pass/concurrency/thread_locals.stdout | 1 + 4 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 tests/run-pass/concurrency/simple.stdout create mode 100644 tests/run-pass/concurrency/thread_locals.stdout diff --git a/src/machine.rs b/src/machine.rs index e6fea672c608..7ed5f1e5539f 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -433,6 +433,29 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { Ok(()) } + fn access_local( + ecx: &InterpCx<'mir, 'tcx, Self>, + frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, + local: mir::Local, + ) -> InterpResult<'tcx, Operand> { + match frame.body.local_decls[local].local_info { + mir::LocalInfo::StaticRef { def_id, is_thread_local: true } => { + let static_alloc_id = ecx.tcx.alloc_map.lock().create_static_alloc(def_id); + let alloc_id = ecx.memory.extra.tls.get_or_register_allocation(*ecx.memory.tcx, static_alloc_id); + let tag = Self::tag_global_base_pointer(&ecx.memory.extra, alloc_id); + let pointer: Pointer = alloc_id.into(); + let pointer = pointer.with_tag(tag); + let scalar: Scalar<_> = pointer.into(); + let scalar: ScalarMaybeUndef<_> = scalar.into(); + let immediate: Immediate<_> = scalar.into(); + Ok( + Operand::Immediate(immediate) + ) + }, + _ => frame.locals[local].access(), + } + } + fn canonical_alloc_id(mem: &Memory<'mir, 'tcx, Self>, id: AllocId) -> AllocId { let tcx = mem.tcx; let alloc = tcx.alloc_map.lock().get(id); diff --git a/tests/run-pass/concurrency/simple.stdout b/tests/run-pass/concurrency/simple.stdout new file mode 100644 index 000000000000..0506b7bdf83c --- /dev/null +++ b/tests/run-pass/concurrency/simple.stdout @@ -0,0 +1,10 @@ +WARNING: The thread support is experimental. For example, Miri does not detect data races yet. +WARNING: The thread support is experimental. For example, Miri does not detect data races yet. +WARNING: The thread support is experimental. For example, Miri does not detect data races yet. +WARNING: The thread support is experimental. For example, Miri does not detect data races yet. +WARNING: The thread support is experimental. For example, Miri does not detect data races yet. +WARNING: The thread support is experimental. For example, Miri does not detect data races yet. +WARNING: The thread support is experimental. For example, Miri does not detect data races yet. +WARNING: The thread support is experimental. For example, Miri does not detect data races yet. +WARNING: The thread support is experimental. For example, Miri does not detect data races yet. +WARNING: The thread support is experimental. For example, Miri does not detect data races yet. diff --git a/tests/run-pass/concurrency/thread_locals.rs b/tests/run-pass/concurrency/thread_locals.rs index d0d25ba7f70c..1c268a4ff874 100644 --- a/tests/run-pass/concurrency/thread_locals.rs +++ b/tests/run-pass/concurrency/thread_locals.rs @@ -12,18 +12,24 @@ unsafe fn get_a_ref() -> *mut u8 { &mut A } +struct Sender(*mut u8); + +unsafe impl Send for Sender {} + fn main() { - unsafe { + let ptr = unsafe { let x = get_a_ref(); *x = 5; assert_eq!(A, 5); B = 15; C = 25; - } + Sender(&mut A) + }; - thread::spawn(|| { + thread::spawn(move || { unsafe { + assert_eq!(*ptr.0, 5); assert_eq!(A, 0); assert_eq!(B, 0); assert_eq!(C, 25); @@ -32,6 +38,7 @@ fn main() { let y = get_a_ref(); assert_eq!(*y, 0); *y = 4; + assert_eq!(*ptr.0, 5); assert_eq!(A, 4); assert_eq!(*get_a_ref(), 4); @@ -45,4 +52,5 @@ fn main() { assert_eq!(C, 24); } -} \ No newline at end of file +} + diff --git a/tests/run-pass/concurrency/thread_locals.stdout b/tests/run-pass/concurrency/thread_locals.stdout new file mode 100644 index 000000000000..9a53b4a5c913 --- /dev/null +++ b/tests/run-pass/concurrency/thread_locals.stdout @@ -0,0 +1 @@ +WARNING: The thread support is experimental. For example, Miri does not detect data races yet. From 1f33f04fd453a63a88cb25771466c2618b46d372 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 6 Apr 2020 13:44:47 -0700 Subject: [PATCH 1929/5092] Move pthread_create and related shims to a separate file. --- src/lib.rs | 1 + src/shims/foreign_items/posix.rs | 62 +++-------------------- src/shims/mod.rs | 1 + src/shims/threads.rs | 84 ++++++++++++++++++++++++++++++++ src/threads.rs | 4 -- 5 files changed, 93 insertions(+), 59 deletions(-) create mode 100644 src/shims/threads.rs diff --git a/src/lib.rs b/src/lib.rs index c042526be64c..d8b3397c8e9b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,6 +42,7 @@ pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::shims::os_str::EvalContextExt as OsStrEvalContextExt; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as PanicEvalContextExt}; pub use crate::shims::sync::{EvalContextExt as SyncEvalContextExt}; +pub use crate::shims::threads::EvalContextExt as ThreadShimsEvalContextExt; pub use crate::shims::time::EvalContextExt as TimeEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::EvalContextExt as ShimsEvalContextExt; diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 878ab8896dda..7d2cb16afee4 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -6,7 +6,6 @@ use std::convert::TryFrom; use log::trace; use crate::*; -use rustc_index::vec::Idx; use rustc_middle::mir; use rustc_target::abi::{Align, LayoutOf, Size}; @@ -316,66 +315,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_create" => { - println!("WARNING: The thread support is experimental. \ - For example, Miri does not detect data races yet."); assert_eq!(args.len(), 4); - let func = args[2]; - let fn_ptr = this.read_scalar(func)?.not_undef()?; - let fn_val = this.memory.get_fn(fn_ptr)?; - let instance = match fn_val { - rustc_mir::interpret::FnVal::Instance(instance) => instance, - _ => unreachable!(), - }; - let thread_info_place = this.deref_operand(args[0])?; - let thread_info_type = args[0].layout.ty - .builtin_deref(true) - .ok_or_else(|| err_ub_format!( - "wrong signature used for `pthread_create`: first argument must be a raw pointer." - ))? - .ty; - let thread_info_layout = this.layout_of(thread_info_type)?; - let func_arg = match *args[3] { - rustc_mir::interpret::Operand::Immediate(immediate) => immediate, - _ => unreachable!(), - }; - let func_args = [func_arg]; - let ret_place = - this.allocate(this.layout_of(this.tcx.types.usize)?, MiriMemoryKind::Machine.into()); - let new_thread_id = this.create_thread()?; - let old_thread_id = this.set_active_thread(new_thread_id)?; - this.call_function( - instance, - &func_args[..], - Some(ret_place.into()), - StackPopCleanup::None { cleanup: true }, - )?; - this.set_active_thread(old_thread_id)?; - this.write_scalar( - Scalar::from_uint(new_thread_id.index() as u128, thread_info_layout.size), - thread_info_place.into(), - )?; - - // Return success (`0`). - this.write_null(dest)?; + let result = this.pthread_create(args[0], args[1], args[2], args[3])?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_join" => { assert_eq!(args.len(), 2); - assert!( - this.is_null(this.read_scalar(args[1])?.not_undef()?)?, - "Miri supports pthread_join only with retval==NULL" - ); - let thread = this.read_scalar(args[0])?.not_undef()?.to_machine_usize(this)?; - this.join_thread(thread.into())?; - - // Return success (`0`). - this.write_null(dest)?; + let result = this.pthread_join(args[0], args[1])?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_detach" => { - let thread = this.read_scalar(args[0])?.not_undef()?.to_machine_usize(this)?; - this.detach_thread(thread.into())?; - - // Return success (`0`). - this.write_null(dest)?; + assert_eq!(args.len(), 1); + let result = this.pthread_detach(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_attr_getguardsize" => { diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 71ff6024ec6f..118058dd32e7 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -6,6 +6,7 @@ pub mod intrinsics; pub mod os_str; pub mod panic; pub mod sync; +pub mod threads; pub mod time; pub mod tls; diff --git a/src/shims/threads.rs b/src/shims/threads.rs new file mode 100644 index 000000000000..6e1087dd81d8 --- /dev/null +++ b/src/shims/threads.rs @@ -0,0 +1,84 @@ +use crate::*; +use rustc_index::vec::Idx; +use rustc_target::abi::LayoutOf; + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn pthread_create( + &mut self, + thread: OpTy<'tcx, Tag>, + _attr: OpTy<'tcx, Tag>, + start_routine: OpTy<'tcx, Tag>, + arg: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + println!( + "WARNING: The thread support is experimental. \ + For example, Miri does not detect data races yet." + ); + + let this = self.eval_context_mut(); + + let new_thread_id = this.create_thread()?; + let old_thread_id = this.set_active_thread(new_thread_id)?; + + let thread_info_place = this.deref_operand(thread)?; + let thread_info_type = thread.layout.ty + .builtin_deref(true) + .ok_or_else(|| err_ub_format!( + "wrong signature used for `pthread_create`: first argument must be a raw pointer." + ))? + .ty; + let thread_info_layout = this.layout_of(thread_info_type)?; + this.write_scalar( + Scalar::from_uint(new_thread_id.index() as u128, thread_info_layout.size), + thread_info_place.into(), + )?; + + let fn_ptr = this.read_scalar(start_routine)?.not_undef()?; + let instance = this.memory.get_fn(fn_ptr)?.as_instance()?; + + let func_arg = match *arg { + rustc_mir::interpret::Operand::Immediate(immediate) => immediate, + _ => unreachable!(), + }; + let func_args = [func_arg]; + + let ret_place = + this.allocate(this.layout_of(this.tcx.types.usize)?, MiriMemoryKind::Machine.into()); + + this.call_function( + instance, + &func_args[..], + Some(ret_place.into()), + StackPopCleanup::None { cleanup: true }, + )?; + + this.set_active_thread(old_thread_id)?; + + Ok(0) + } + fn pthread_join( + &mut self, + thread: OpTy<'tcx, Tag>, + retval: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + if !this.is_null(this.read_scalar(retval)?.not_undef()?)? { + throw_unsup_format!("Miri supports pthread_join only with retval==NULL"); + } + + let thread_id = this.read_scalar(thread)?.not_undef()?.to_machine_usize(this)?; + this.join_thread(thread_id.into())?; + + Ok(0) + } + fn pthread_detach(&mut self, thread: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + let thread_id = this.read_scalar(thread)?.not_undef()?.to_machine_usize(this)?; + this.detach_thread(thread_id.into())?; + + Ok(0) + } +} diff --git a/src/threads.rs b/src/threads.rs index 618713e3c3de..9d982359bfbb 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -91,9 +91,6 @@ pub struct ThreadSet<'mir, 'tcx> { /// /// Note that this vector also contains terminated threads. threads: IndexVec>, - - /// List of threads that just terminated. TODO: Cleanup. - terminated_threads: Vec, } impl<'mir, 'tcx> Default for ThreadSet<'mir, 'tcx> { @@ -103,7 +100,6 @@ impl<'mir, 'tcx> Default for ThreadSet<'mir, 'tcx> { Self { active_thread: ThreadId::new(0), threads: threads, - terminated_threads: Default::default(), } } } From ed9c7d168b0ded92e4bfb53acd2f71b61b54e306 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 6 Apr 2020 14:00:45 -0700 Subject: [PATCH 1930/5092] Report that we do not support foreign thread local statics. --- src/machine.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 7ed5f1e5539f..2f0aa9157535 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -14,6 +14,7 @@ use rand::rngs::StdRng; use rustc_ast::attr; use rustc_data_structures::fx::FxHashMap; use rustc_middle::{ + middle::codegen_fn_attrs::CodegenFnAttrFlags, mir, ty::{ self, @@ -21,7 +22,7 @@ use rustc_middle::{ TyCtxt, }, }; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::{def_id::DefId, symbol::{sym, Symbol}}; use rustc_target::abi::{LayoutOf, Size}; use crate::*; @@ -459,8 +460,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn canonical_alloc_id(mem: &Memory<'mir, 'tcx, Self>, id: AllocId) -> AllocId { let tcx = mem.tcx; let alloc = tcx.alloc_map.lock().get(id); + fn is_thread_local<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { + tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) + } match alloc { Some(GlobalAlloc::Static(def_id)) if tcx.is_foreign_item(def_id) => { + if is_thread_local(*tcx, def_id) { + unimplemented!("Foreign thread local statics are not supported yet."); + } // Figure out if this is an extern static, and if yes, which one. let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { @@ -476,7 +483,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { id } }, - Some(GlobalAlloc::Static(def_id)) if tcx.has_attr(def_id, sym::thread_local) => { + Some(GlobalAlloc::Static(def_id)) if is_thread_local(*tcx, def_id) => { // We have a thread local, so we need to get a unique allocation id for it. mem.extra.tls.get_or_register_allocation(*tcx, id) }, From 52184193c363e030818a18a60123eed25b12c7c9 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 6 Apr 2020 14:41:05 -0700 Subject: [PATCH 1931/5092] Fix comments in TLS. --- src/machine.rs | 2 +- src/shims/tls.rs | 8 +++++--- src/threads.rs | 13 +++++-------- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 2f0aa9157535..a7d62897b8f0 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -27,7 +27,7 @@ use rustc_target::abi::{LayoutOf, Size}; use crate::*; -pub use crate::threads::{ThreadId, ThreadSet, ThreadLocalStorage}; +pub use crate::threads::{ThreadId, ThreadSet, ThreadState, ThreadLocalStorage}; // Some global facts about the emulated machine. pub const PAGE_SIZE: u64 = 4 * 1024; // FIXME: adjust to target architecture diff --git a/src/shims/tls.rs b/src/shims/tls.rs index d16acb750037..ec8c31fe2c12 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -9,7 +9,7 @@ use rustc_middle::ty; use rustc_target::abi::{Size, HasDataLayout}; use crate::{HelpersEvalContextExt, ThreadsEvalContextExt, InterpResult, MPlaceTy, Scalar, StackPopCleanup, Tag}; -use crate::machine::ThreadId; +use crate::machine::{ThreadId, ThreadState}; pub type TlsKey = u128; @@ -174,7 +174,7 @@ impl<'tcx> TlsData<'tcx> { impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// Run TLS destructors for the currently active thread. + /// Run TLS destructors for all threads. fn run_tls_dtors(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); assert!(!this.machine.tls.dtors_running, "running TLS dtors twice"); @@ -223,7 +223,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Now run the "keyed" destructors. - for thread_id in this.get_all_thread_ids() { + for (thread_id, thread_state) in this.get_all_thread_ids_with_states() { + assert!(thread_state == ThreadState::Terminated, + "TLS destructors should be executed after all threads terminated."); this.set_active_thread(thread_id)?; let mut dtor = this.machine.tls.fetch_tls_dtor(None, thread_id); while let Some((instance, thread_id, ptr, key)) = dtor { diff --git a/src/threads.rs b/src/threads.rs index 9d982359bfbb..4458f4410e4c 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -97,10 +97,7 @@ impl<'mir, 'tcx> Default for ThreadSet<'mir, 'tcx> { fn default() -> Self { let mut threads = IndexVec::new(); threads.push(Default::default()); - Self { - active_thread: ThreadId::new(0), - threads: threads, - } + Self { active_thread: ThreadId::new(0), threads: threads } } } @@ -156,8 +153,8 @@ impl<'mir, 'tcx: 'mir> ThreadSet<'mir, 'tcx> { } } /// Get ids of all threads ever allocated. - fn get_all_thread_ids(&mut self) -> Vec { - (0..self.threads.len()).map(ThreadId::new).collect() + fn get_all_thread_ids_with_states(&self) -> Vec<(ThreadId, ThreadState)> { + self.threads.iter_enumerated().map(|(id, thread)| (id, thread.state)).collect() } /// Decide which thread to run next. /// @@ -283,9 +280,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.machine.threads.active_thread_stack_mut() } - fn get_all_thread_ids(&mut self) -> Vec { + fn get_all_thread_ids_with_states(&mut self) -> Vec<(ThreadId, ThreadState)> { let this = self.eval_context_mut(); - this.machine.threads.get_all_thread_ids() + this.machine.threads.get_all_thread_ids_with_states() } /// Decide which thread to run next. /// From f21197f081048e383ff10427216db7867b746832 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 6 Apr 2020 16:12:13 -0700 Subject: [PATCH 1932/5092] Store the thread name. --- src/shims/foreign_items/posix.rs | 13 +++++-------- src/shims/threads.rs | 20 ++++++++++++++++++++ src/threads.rs | 26 ++++++++++++++++++++------ 3 files changed, 45 insertions(+), 14 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 7d2cb16afee4..4e08593d61c3 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -329,6 +329,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.pthread_detach(args[0])?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "prctl" => { + assert_eq!(args.len(), 5); + let result = this.prctl(args[0], args[1], args[2], args[3], args[4])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } "pthread_attr_getguardsize" => { assert_eq!(args.len(), 2); @@ -347,14 +352,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - "prctl" => { - let option = this.read_scalar(args[0])?.not_undef()?.to_i32()?; - assert_eq!(option, 0xf, "Miri supports only PR_SET_NAME"); - - // Return success (`0`). - this.write_null(dest)?; - } - // Incomplete shims that we "stub out" just to get pre-main initialziation code to work. // These shims are enabled only when the caller is in the standard library. | "pthread_attr_init" diff --git a/src/shims/threads.rs b/src/shims/threads.rs index 6e1087dd81d8..3a55fb3c706c 100644 --- a/src/shims/threads.rs +++ b/src/shims/threads.rs @@ -79,6 +79,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let thread_id = this.read_scalar(thread)?.not_undef()?.to_machine_usize(this)?; this.detach_thread(thread_id.into())?; + Ok(0) + } + fn prctl( + &mut self, + option: OpTy<'tcx, Tag>, + arg2: OpTy<'tcx, Tag>, + _arg3: OpTy<'tcx, Tag>, + _arg4: OpTy<'tcx, Tag>, + _arg5: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + let option = this.read_scalar(option)?.not_undef()?.to_i32()?; + if option != this.eval_libc_i32("PR_SET_NAME")? { + throw_unsup_format!("Miri supports only PR_SET_NAME"); + } + let address = this.read_scalar(arg2)?.not_undef()?; + let name = this.memory.read_c_str(address)?.to_owned(); + this.set_active_thread_name(name)?; + Ok(0) } } diff --git a/src/threads.rs b/src/threads.rs index 4458f4410e4c..4ce35d50abc3 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -47,6 +47,8 @@ pub enum ThreadState { /// A thread. pub struct Thread<'mir, 'tcx> { state: ThreadState, + /// Name of the thread. + thread_name: Option>, /// The virtual call stack. stack: Vec>>, /// Is the thread detached? @@ -78,7 +80,7 @@ impl<'mir, 'tcx> std::fmt::Debug for Thread<'mir, 'tcx> { impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> { fn default() -> Self { - Self { state: ThreadState::Enabled, stack: Vec::new(), detached: false } + Self { state: ThreadState::Enabled, thread_name: None, stack: Vec::new(), detached: false } } } @@ -117,16 +119,20 @@ impl<'mir, 'tcx: 'mir> ThreadSet<'mir, 'tcx> { new_thread_id } /// Set an active thread and return the id of the thread that was active before. - fn set_active_thread(&mut self, id: ThreadId) -> ThreadId { + fn set_active_thread_id(&mut self, id: ThreadId) -> ThreadId { let active_thread_id = self.active_thread; self.active_thread = id; assert!(self.active_thread.index() < self.threads.len()); active_thread_id } /// Get the id of the currently active thread. - fn get_active_thread(&self) -> ThreadId { + fn get_active_thread_id(&self) -> ThreadId { self.active_thread } + /// Get the borrow of the currently active thread. + fn active_thread_mut(&mut self) -> &mut Thread<'mir, 'tcx> { + &mut self.threads[self.active_thread] + } /// Mark the thread as detached, which means that no other thread will try /// to join it and the thread is responsible for cleaning up. fn detach_thread(&mut self, id: ThreadId) { @@ -152,6 +158,10 @@ impl<'mir, 'tcx: 'mir> ThreadSet<'mir, 'tcx> { ); } } + /// Set the name of the active thread. + fn set_thread_name(&mut self, new_thread_name: Vec) { + self.active_thread_mut().thread_name = Some(new_thread_name); + } /// Get ids of all threads ever allocated. fn get_all_thread_ids_with_states(&self) -> Vec<(ThreadId, ThreadState)> { self.threads.iter_enumerated().map(|(id, thread)| (id, thread.state)).collect() @@ -266,11 +276,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn set_active_thread(&mut self, thread_id: ThreadId) -> InterpResult<'tcx, ThreadId> { let this = self.eval_context_mut(); this.memory.extra.tls.set_active_thread(thread_id); - Ok(this.machine.threads.set_active_thread(thread_id)) + Ok(this.machine.threads.set_active_thread_id(thread_id)) } fn get_active_thread(&self) -> InterpResult<'tcx, ThreadId> { let this = self.eval_context_ref(); - Ok(this.machine.threads.get_active_thread()) + Ok(this.machine.threads.get_active_thread_id()) } fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] { let this = self.eval_context_ref(); @@ -280,6 +290,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.machine.threads.active_thread_stack_mut() } + fn set_active_thread_name(&mut self, new_thread_name: Vec) -> InterpResult<'tcx, ()> { + let this = self.eval_context_mut(); + Ok(this.machine.threads.set_thread_name(new_thread_name)) + } fn get_all_thread_ids_with_states(&mut self) -> Vec<(ThreadId, ThreadState)> { let this = self.eval_context_mut(); this.machine.threads.get_all_thread_ids_with_states() @@ -291,7 +305,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); // Find the next thread to run. if this.machine.threads.schedule()? { - let active_thread = this.machine.threads.get_active_thread(); + let active_thread = this.machine.threads.get_active_thread_id(); this.memory.extra.tls.set_active_thread(active_thread); Ok(true) } else { From b04bf8a51480c05fc9984476a78f07b927f2672f Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 6 Apr 2020 16:12:25 -0700 Subject: [PATCH 1933/5092] Rustfmt the test. --- tests/run-pass/concurrency/thread_locals.rs | 38 +++++++++------------ 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/tests/run-pass/concurrency/thread_locals.rs b/tests/run-pass/concurrency/thread_locals.rs index 1c268a4ff874..50aa6fee2f87 100644 --- a/tests/run-pass/concurrency/thread_locals.rs +++ b/tests/run-pass/concurrency/thread_locals.rs @@ -17,7 +17,6 @@ struct Sender(*mut u8); unsafe impl Send for Sender {} fn main() { - let ptr = unsafe { let x = get_a_ref(); *x = 5; @@ -26,24 +25,23 @@ fn main() { C = 25; Sender(&mut A) }; - - thread::spawn(move || { - unsafe { - assert_eq!(*ptr.0, 5); - assert_eq!(A, 0); - assert_eq!(B, 0); - assert_eq!(C, 25); - B = 14; - C = 24; - let y = get_a_ref(); - assert_eq!(*y, 0); - *y = 4; - assert_eq!(*ptr.0, 5); - assert_eq!(A, 4); - assert_eq!(*get_a_ref(), 4); - - } - }).join().unwrap(); + + thread::spawn(move || unsafe { + assert_eq!(*ptr.0, 5); + assert_eq!(A, 0); + assert_eq!(B, 0); + assert_eq!(C, 25); + B = 14; + C = 24; + let y = get_a_ref(); + assert_eq!(*y, 0); + *y = 4; + assert_eq!(*ptr.0, 5); + assert_eq!(A, 4); + assert_eq!(*get_a_ref(), 4); + }) + .join() + .unwrap(); unsafe { assert_eq!(*get_a_ref(), 5); @@ -51,6 +49,4 @@ fn main() { assert_eq!(B, 15); assert_eq!(C, 24); } - } - From 2202278f6af676266034e756bd3848efe4e10ab8 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 6 Apr 2020 16:30:30 -0700 Subject: [PATCH 1934/5092] Fix pthread_self. --- src/shims/foreign_items/posix.rs | 5 ++++- src/shims/threads.rs | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 4e08593d61c3..4cd3b8499112 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -329,6 +329,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.pthread_detach(args[0])?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "pthread_self" => { + assert_eq!(args.len(), 0); + this.pthread_self(dest)?; + } "prctl" => { assert_eq!(args.len(), 5); let result = this.prctl(args[0], args[1], args[2], args[3], args[4])?; @@ -356,7 +360,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These shims are enabled only when the caller is in the standard library. | "pthread_attr_init" | "pthread_attr_destroy" - | "pthread_self" | "pthread_attr_setstacksize" | "pthread_condattr_init" | "pthread_condattr_setclock" diff --git a/src/shims/threads.rs b/src/shims/threads.rs index 3a55fb3c706c..fc733d7f5c9f 100644 --- a/src/shims/threads.rs +++ b/src/shims/threads.rs @@ -81,6 +81,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } + fn pthread_self(&mut self, dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let thread_id = this.get_active_thread()?; + this.write_scalar(Scalar::from_uint(thread_id.index() as u128, dest.layout.size), dest) + } fn prctl( &mut self, option: OpTy<'tcx, Tag>, From 1c8a59c69189b42b97db49292d0ca198a7d5977a Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Tue, 7 Apr 2020 20:20:41 -0700 Subject: [PATCH 1935/5092] Rebase on PR 1157. --- src/shims/sync.rs | 392 +++++++++++++++++++----- src/threads.rs | 81 ++++- tests/run-pass/concurrency/locks.rs | 29 ++ tests/run-pass/concurrency/locks.stdout | 3 + 4 files changed, 420 insertions(+), 85 deletions(-) create mode 100644 tests/run-pass/concurrency/locks.rs create mode 100644 tests/run-pass/concurrency/locks.stdout diff --git a/src/shims/sync.rs b/src/shims/sync.rs index b03dcbfd8969..eb5435811434 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -2,6 +2,7 @@ use rustc_middle::ty::{TyKind, TypeAndMut}; use rustc_target::abi::{LayoutOf, Size}; use crate::stacked_borrows::Tag; +use crate::threads::{BlockSetId, ThreadId}; use crate::*; fn assert_ptr_target_min_size<'mir, 'tcx: 'mir>( @@ -55,15 +56,17 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( // bytes 0-3: reserved for signature on macOS // (need to avoid this because it is set by static initializer macros) // bytes 4-7: count of how many times this mutex has been locked, as a u32 +// bytes 8-11: when count > 0, id of the owner thread as a u32 // bytes 12-15 or 16-19 (depending on platform): mutex kind, as an i32 // (the kind has to be at its offset for compatibility with static initializer macros) +// bytes 20-23: when count > 0, id of the blockset in which the blocked threads are waiting. fn mutex_get_locked_count<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { // Ensure that the following read at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 20)?; + assert_ptr_target_min_size(ecx, mutex_op, 24)?; let mutex_place = ecx.deref_operand(mutex_op)?; let locked_count_place = mutex_place.offset( Size::from_bytes(4), @@ -80,7 +83,7 @@ fn mutex_set_locked_count<'mir, 'tcx: 'mir>( locked_count: impl Into>, ) -> InterpResult<'tcx, ()> { // Ensure that the following write at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 20)?; + assert_ptr_target_min_size(ecx, mutex_op, 24)?; let mutex_place = ecx.deref_operand(mutex_op)?; let locked_count_place = mutex_place.offset( Size::from_bytes(4), @@ -91,12 +94,45 @@ fn mutex_set_locked_count<'mir, 'tcx: 'mir>( ecx.write_scalar(locked_count.into(), locked_count_place.into()) } +fn mutex_get_owner<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + mutex_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the mutex pointer is within bounds + assert_ptr_target_min_size(ecx, mutex_op, 24)?; + let mutex_place = ecx.deref_operand(mutex_op)?; + let mutex_id_place = mutex_place.offset( + Size::from_bytes(8), + MemPlaceMeta::None, + ecx.machine.layouts.u32, + ecx, + )?; + ecx.read_scalar(mutex_id_place.into()) +} + +fn mutex_set_owner<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + mutex_op: OpTy<'tcx, Tag>, + mutex_id: impl Into>, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the mutex pointer is within bounds + assert_ptr_target_min_size(ecx, mutex_op, 24)?; + let mutex_place = ecx.deref_operand(mutex_op)?; + let mutex_id_place = mutex_place.offset( + Size::from_bytes(8), + MemPlaceMeta::None, + ecx.machine.layouts.u32, + ecx, + )?; + ecx.write_scalar(mutex_id.into(), mutex_id_place.into()) +} + fn mutex_get_kind<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { // Ensure that the following read at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 20)?; + assert_ptr_target_min_size(ecx, mutex_op, 24)?; let mutex_place = ecx.deref_operand(mutex_op)?; let kind_offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; let kind_place = mutex_place.offset( @@ -114,7 +150,7 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( kind: impl Into>, ) -> InterpResult<'tcx, ()> { // Ensure that the following write at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 20)?; + assert_ptr_target_min_size(ecx, mutex_op, 24)?; let mutex_place = ecx.deref_operand(mutex_op)?; let kind_offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; let kind_place = mutex_place.offset( @@ -126,6 +162,55 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( ecx.write_scalar(kind.into(), kind_place.into()) } +fn mutex_get_blockset<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + mutex_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the mutex pointer is within bounds + assert_ptr_target_min_size(ecx, mutex_op, 24)?; + let mutex_place = ecx.deref_operand(mutex_op)?; + let mutex_id_place = mutex_place.offset( + Size::from_bytes(20), + MemPlaceMeta::None, + ecx.machine.layouts.u32, + ecx, + )?; + ecx.read_scalar(mutex_id_place.into()) +} + +fn mutex_set_blockset<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + mutex_op: OpTy<'tcx, Tag>, + mutex_id: impl Into>, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the mutex pointer is within bounds + assert_ptr_target_min_size(ecx, mutex_op, 24)?; + let mutex_place = ecx.deref_operand(mutex_op)?; + let mutex_id_place = mutex_place.offset( + Size::from_bytes(20), + MemPlaceMeta::None, + ecx.machine.layouts.u32, + ecx, + )?; + ecx.write_scalar(mutex_id.into(), mutex_id_place.into()) +} + +fn mutex_get_or_create_blockset<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + mutex_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, BlockSetId> { + let blockset = mutex_get_blockset(ecx, mutex_op)?.to_u32()?; + if blockset == 0 { + // 0 is a default value and also not a valid blockset id. Need to + // allocate a new blockset. + let blockset = ecx.create_blockset()?; + mutex_set_blockset(ecx, mutex_op, blockset.to_u32_scalar())?; + Ok(blockset) + } else { + Ok(blockset.into()) + } +} + // pthread_rwlock_t is between 32 and 56 bytes, depending on the platform. // Our chosen memory layout for the emulated rwlock (does not have to match the platform layout!): @@ -133,13 +218,17 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( // (need to avoid this because it is set by static initializer macros) // bytes 4-7: reader count, as a u32 // bytes 8-11: writer count, as a u32 +// bytes 12-15: when writer or reader count > 0, id of the blockset in which the +// blocked writers are waiting. +// bytes 16-20: when writer count > 0, id of the blockset in which the blocked +// readers are waiting. fn rwlock_get_readers<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { // Ensure that the following read at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 12)?; + assert_ptr_target_min_size(ecx, rwlock_op, 20)?; let rwlock_place = ecx.deref_operand(rwlock_op)?; let readers_place = rwlock_place.offset( Size::from_bytes(4), @@ -156,7 +245,7 @@ fn rwlock_set_readers<'mir, 'tcx: 'mir>( readers: impl Into>, ) -> InterpResult<'tcx, ()> { // Ensure that the following write at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 12)?; + assert_ptr_target_min_size(ecx, rwlock_op, 20)?; let rwlock_place = ecx.deref_operand(rwlock_op)?; let readers_place = rwlock_place.offset( Size::from_bytes(4), @@ -172,7 +261,7 @@ fn rwlock_get_writers<'mir, 'tcx: 'mir>( rwlock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { // Ensure that the following read at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 12)?; + assert_ptr_target_min_size(ecx, rwlock_op, 20)?; let rwlock_place = ecx.deref_operand(rwlock_op)?; let writers_place = rwlock_place.offset( Size::from_bytes(8), @@ -189,7 +278,7 @@ fn rwlock_set_writers<'mir, 'tcx: 'mir>( writers: impl Into>, ) -> InterpResult<'tcx, ()> { // Ensure that the following write at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 12)?; + assert_ptr_target_min_size(ecx, rwlock_op, 20)?; let rwlock_place = ecx.deref_operand(rwlock_op)?; let writers_place = rwlock_place.offset( Size::from_bytes(8), @@ -200,6 +289,104 @@ fn rwlock_set_writers<'mir, 'tcx: 'mir>( ecx.write_scalar(writers.into(), writers_place.into()) } +fn rwlock_get_writer_blockset<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + rwlock_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the rwlock pointer is within bounds + assert_ptr_target_min_size(ecx, rwlock_op, 20)?; + let rwlock_place = ecx.deref_operand(rwlock_op)?; + let blockset_place = rwlock_place.offset( + Size::from_bytes(12), + MemPlaceMeta::None, + ecx.machine.layouts.u32, + ecx, + )?; + ecx.read_scalar(blockset_place.into()) +} + +fn rwlock_set_writer_blockset<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + rwlock_op: OpTy<'tcx, Tag>, + blockset: impl Into>, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the rwlock pointer is within bounds + assert_ptr_target_min_size(ecx, rwlock_op, 20)?; + let rwlock_place = ecx.deref_operand(rwlock_op)?; + let blockset_place = rwlock_place.offset( + Size::from_bytes(12), + MemPlaceMeta::None, + ecx.machine.layouts.u32, + ecx, + )?; + ecx.write_scalar(blockset.into(), blockset_place.into()) +} + +fn rwlock_get_or_create_writer_blockset<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + rwlock_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, BlockSetId> { + let blockset = rwlock_get_writer_blockset(ecx, rwlock_op)?.to_u32()?; + if blockset == 0 { + // 0 is a default value and also not a valid blockset id. Need to + // allocate a new blockset. + let blockset = ecx.create_blockset()?; + rwlock_set_writer_blockset(ecx, rwlock_op, blockset.to_u32_scalar())?; + Ok(blockset) + } else { + Ok(blockset.into()) + } +} + +fn rwlock_get_reader_blockset<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + rwlock_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the rwlock pointer is within bounds + assert_ptr_target_min_size(ecx, rwlock_op, 20)?; + let rwlock_place = ecx.deref_operand(rwlock_op)?; + let blockset_place = rwlock_place.offset( + Size::from_bytes(16), + MemPlaceMeta::None, + ecx.machine.layouts.u32, + ecx, + )?; + ecx.read_scalar(blockset_place.into()) +} + +fn rwlock_set_reader_blockset<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + rwlock_op: OpTy<'tcx, Tag>, + blockset: impl Into>, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the rwlock pointer is within bounds + assert_ptr_target_min_size(ecx, rwlock_op, 20)?; + let rwlock_place = ecx.deref_operand(rwlock_op)?; + let blockset_place = rwlock_place.offset( + Size::from_bytes(16), + MemPlaceMeta::None, + ecx.machine.layouts.u32, + ecx, + )?; + ecx.write_scalar(blockset.into(), blockset_place.into()) +} + +fn rwlock_get_or_create_reader_blockset<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + rwlock_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, BlockSetId> { + let blockset = rwlock_get_reader_blockset(ecx, rwlock_op)?.to_u32()?; + if blockset == 0 { + // 0 is a default value and also not a valid blockset id. Need to + // allocate a new blockset. + let blockset = ecx.create_blockset()?; + rwlock_set_reader_blockset(ecx, rwlock_op, blockset.to_u32_scalar())?; + Ok(blockset) + } else { + Ok(blockset.into()) + } +} + impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn pthread_mutexattr_init(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { @@ -265,31 +452,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; let locked_count = mutex_get_locked_count(this, mutex_op)?.to_u32()?; + let active_thread = this.get_active_thread()?; - if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { - if locked_count == 0 { - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(1))?; - Ok(0) - } else { - throw_machine_stop!(TerminationInfo::Deadlock); - } - } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { - if locked_count == 0 { - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(1))?; - Ok(0) - } else { - this.eval_libc_i32("EDEADLK") - } - } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { - match locked_count.checked_add(1) { - Some(new_count) => { - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(new_count))?; - Ok(0) - } - None => this.eval_libc_i32("EAGAIN"), - } + if locked_count == 0 { + // The mutex is unlocked. Let's lock it. + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(1))?; + mutex_set_owner(this, mutex_op, active_thread.to_u32_scalar())?; + Ok(0) } else { - throw_ub_format!("called pthread_mutex_lock on an unsupported type of mutex"); + // The mutex is locked. Let's check by whom. + let owner_thread: ThreadId = + mutex_get_owner(this, mutex_op)?.not_undef()?.to_u32()?.into(); + if owner_thread != active_thread { + // Block the active thread. + let blockset = mutex_get_or_create_blockset(this, mutex_op)?; + this.block_active_thread(blockset)?; + Ok(0) + } else { + // Trying to acquire the same mutex again. + if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { + throw_machine_stop!(TerminationInfo::Deadlock); + } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { + this.eval_libc_i32("EDEADLK") + } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { + match locked_count.checked_add(1) { + Some(new_count) => { + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(new_count))?; + Ok(0) + } + None => this.eval_libc_i32("EAGAIN"), + } + } else { + throw_ub_format!("called pthread_mutex_lock on an unsupported type of mutex"); + } + } } } @@ -298,26 +494,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; let locked_count = mutex_get_locked_count(this, mutex_op)?.to_u32()?; + let active_thread = this.get_active_thread()?; - if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? - || kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? - { - if locked_count == 0 { - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(1))?; - Ok(0) - } else { - this.eval_libc_i32("EBUSY") - } - } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { - match locked_count.checked_add(1) { - Some(new_count) => { - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(new_count))?; - Ok(0) - } - None => this.eval_libc_i32("EAGAIN"), - } + if locked_count == 0 { + // The mutex is unlocked. Let's lock it. + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(1))?; + mutex_set_owner(this, mutex_op, active_thread.to_u32_scalar())?; + Ok(0) } else { - throw_ub_format!("called pthread_mutex_trylock on an unsupported type of mutex"); + let owner_thread: ThreadId = mutex_get_owner(this, mutex_op)?.to_u32()?.into(); + if owner_thread != active_thread { + this.eval_libc_i32("EBUSY") + } else { + if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? + || kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? + { + this.eval_libc_i32("EBUSY") + } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { + match locked_count.checked_add(1) { + Some(new_count) => { + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(new_count))?; + Ok(0) + } + None => this.eval_libc_i32("EAGAIN"), + } + } else { + throw_ub_format!( + "called pthread_mutex_trylock on an unsupported type of mutex" + ); + } + } } } @@ -326,34 +532,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; let locked_count = mutex_get_locked_count(this, mutex_op)?.to_u32()?; + let owner_thread: ThreadId = mutex_get_owner(this, mutex_op)?.to_u32()?.into(); - if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { - if locked_count != 0 { - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(0))?; - Ok(0) + if owner_thread != this.get_active_thread()? { + throw_ub_format!("called pthread_mutex_unlock on a mutex owned by another thread"); + } else if locked_count == 1 { + let blockset = mutex_get_or_create_blockset(this, mutex_op)?; + if let Some(new_owner) = this.unblock_random_thread(blockset)? { + // We have at least one thread waiting on this mutex. Transfer + // ownership to it. + mutex_set_owner(this, mutex_op, new_owner.to_u32_scalar())?; } else { - throw_ub_format!("unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked"); - } - } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { - if locked_count != 0 { + // No thread is waiting on this mutex. mutex_set_locked_count(this, mutex_op, Scalar::from_u32(0))?; - Ok(0) - } else { - this.eval_libc_i32("EPERM") - } - } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { - match locked_count.checked_sub(1) { - Some(new_count) => { - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(new_count))?; - Ok(0) - } - None => { - // locked_count was already zero - this.eval_libc_i32("EPERM") - } } + Ok(0) } else { - throw_ub_format!("called pthread_mutex_unlock on an unsupported type of mutex"); + if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { + throw_ub_format!("unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked"); + } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { + this.eval_libc_i32("EPERM") + } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { + match locked_count.checked_sub(1) { + Some(new_count) => { + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(new_count))?; + Ok(0) + } + None => { + // locked_count was already zero + this.eval_libc_i32("EPERM") + } + } + } else { + throw_ub_format!("called pthread_mutex_unlock on an unsupported type of mutex"); + } } } @@ -366,6 +578,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex_set_kind(this, mutex_op, ScalarMaybeUndef::Undef)?; mutex_set_locked_count(this, mutex_op, ScalarMaybeUndef::Undef)?; + mutex_set_blockset(this, mutex_op, ScalarMaybeUndef::Undef)?; Ok(0) } @@ -375,8 +588,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; + if writers != 0 { - throw_machine_stop!(TerminationInfo::Deadlock); + // The lock is locked by a writer. + assert_eq!(writers, 1); + let reader_blockset = rwlock_get_or_create_reader_blockset(this, rwlock_op)?; + this.block_active_thread(reader_blockset)?; + Ok(0) } else { match readers.checked_add(1) { Some(new_readers) => { @@ -411,14 +629,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; - if readers != 0 { - throw_machine_stop!(TerminationInfo::Deadlock); - } else if writers != 0 { - throw_machine_stop!(TerminationInfo::Deadlock); + let writer_blockset = rwlock_get_or_create_writer_blockset(this, rwlock_op)?; + if readers != 0 || writers != 0 { + this.block_active_thread(writer_blockset)?; } else { rwlock_set_writers(this, rwlock_op, Scalar::from_u32(1))?; - Ok(0) } + Ok(0) } fn pthread_rwlock_trywrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { @@ -439,11 +656,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; + let writer_blockset = rwlock_get_or_create_writer_blockset(this, rwlock_op)?; if let Some(new_readers) = readers.checked_sub(1) { + assert_eq!(writers, 0); rwlock_set_readers(this, rwlock_op, Scalar::from_u32(new_readers))?; + if new_readers == 0 { + if let Some(_writer) = this.unblock_random_thread(writer_blockset)? { + rwlock_set_writers(this, rwlock_op, Scalar::from_u32(1))?; + } + } Ok(0) } else if writers != 0 { + let reader_blockset = rwlock_get_or_create_reader_blockset(this, rwlock_op)?; rwlock_set_writers(this, rwlock_op, Scalar::from_u32(0))?; + if let Some(_writer) = this.unblock_random_thread(writer_blockset)? { + rwlock_set_writers(this, rwlock_op, Scalar::from_u32(1))?; + } else { + let mut readers = 0; + while let Some(_reader) = this.unblock_random_thread(reader_blockset)? { + readers += 1; + } + rwlock_set_readers(this, rwlock_op, Scalar::from_u32(readers))? + } Ok(0) } else { throw_ub_format!("unlocked an rwlock that was not locked"); @@ -461,6 +695,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx rwlock_set_readers(this, rwlock_op, ScalarMaybeUndef::Undef)?; rwlock_set_writers(this, rwlock_op, ScalarMaybeUndef::Undef)?; + rwlock_set_reader_blockset(this, rwlock_op, ScalarMaybeUndef::Undef)?; + rwlock_set_writer_blockset(this, rwlock_op, ScalarMaybeUndef::Undef)?; Ok(0) } diff --git a/src/threads.rs b/src/threads.rs index 4ce35d50abc3..5991ba4ed1f6 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -2,6 +2,7 @@ use std::cell::RefCell; use std::collections::hash_map::Entry; +use std::convert::TryFrom; use log::trace; @@ -31,6 +32,37 @@ impl From for ThreadId { } } +impl From for ThreadId { + fn from(id: u32) -> Self { + Self(id as usize) + } +} + +impl ThreadId { + pub fn to_u32_scalar<'tcx>(&self) -> Scalar { + Scalar::from_u32(u32::try_from(self.0).unwrap()) + } +} + +/// An identifier of a set of blocked threads. +/// +/// Note: 0 is not a valid identifier. +#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] +pub struct BlockSetId(u32); + +impl From for BlockSetId { + fn from(id: u32) -> Self { + assert_ne!(id, 0, "0 is not a valid blockset id"); + Self(id) + } +} + +impl BlockSetId { + pub fn to_u32_scalar<'tcx>(&self) -> Scalar { + Scalar::from_u32(self.0) + } +} + /// The state of a thread. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum ThreadState { @@ -38,7 +70,9 @@ pub enum ThreadState { Enabled, /// The thread tried to join the specified thread and is blocked until that /// thread terminates. - Blocked(ThreadId), + BlockedOnJoin(ThreadId), + /// The thread is blocked and belongs to the given blockset.. + Blocked(BlockSetId), /// The thread has terminated its execution (we do not delete terminated /// threads.) Terminated, @@ -93,13 +127,15 @@ pub struct ThreadSet<'mir, 'tcx> { /// /// Note that this vector also contains terminated threads. threads: IndexVec>, + /// A counter used to generate unique identifiers for blocksets. + blockset_counter: u32, } impl<'mir, 'tcx> Default for ThreadSet<'mir, 'tcx> { fn default() -> Self { let mut threads = IndexVec::new(); threads.push(Default::default()); - Self { active_thread: ThreadId::new(0), threads: threads } + Self { active_thread: ThreadId::new(0), threads: threads, blockset_counter: 0 } } } @@ -145,12 +181,12 @@ impl<'mir, 'tcx: 'mir> ThreadSet<'mir, 'tcx> { assert!( self.threads .iter() - .all(|thread| thread.state != ThreadState::Blocked(joined_thread_id)), + .all(|thread| thread.state != ThreadState::BlockedOnJoin(joined_thread_id)), "Bug: multiple threads try to join the same thread." ); if self.threads[joined_thread_id].state != ThreadState::Terminated { // The joined thread is still running, we need to wait for it. - self.threads[self.active_thread].state = ThreadState::Blocked(joined_thread_id); + self.active_thread_mut().state = ThreadState::BlockedOnJoin(joined_thread_id); trace!( "{:?} blocked on {:?} when trying to join", self.active_thread, @@ -162,10 +198,29 @@ impl<'mir, 'tcx: 'mir> ThreadSet<'mir, 'tcx> { fn set_thread_name(&mut self, new_thread_name: Vec) { self.active_thread_mut().thread_name = Some(new_thread_name); } - /// Get ids of all threads ever allocated. + /// Get ids and states of all threads ever allocated. fn get_all_thread_ids_with_states(&self) -> Vec<(ThreadId, ThreadState)> { self.threads.iter_enumerated().map(|(id, thread)| (id, thread.state)).collect() } + fn create_blockset(&mut self) -> BlockSetId { + self.blockset_counter = self.blockset_counter.checked_add(1).unwrap(); + self.blockset_counter.into() + } + fn block_active_thread(&mut self, set: BlockSetId) { + let state = &mut self.active_thread_mut().state; + assert_eq!(*state, ThreadState::Enabled); + *state = ThreadState::Blocked(set); + } + fn unblock_random_thread(&mut self, set: BlockSetId) -> Option { + for (id, thread) in self.threads.iter_enumerated_mut() { + if thread.state == ThreadState::Blocked(set) { + trace!("unblocking {:?} in blockset {:?}", id, set); + thread.state = ThreadState::Enabled; + return Some(id); + } + } + None + } /// Decide which thread to run next. /// /// Returns `false` if all threads terminated. @@ -173,7 +228,7 @@ impl<'mir, 'tcx: 'mir> ThreadSet<'mir, 'tcx> { if self.threads[self.active_thread].check_terminated() { // Check if we need to unblock any threads. for (i, thread) in self.threads.iter_enumerated_mut() { - if thread.state == ThreadState::Blocked(self.active_thread) { + if thread.state == ThreadState::BlockedOnJoin(self.active_thread) { trace!("unblocking {:?} because {:?} terminated", i, self.active_thread); thread.state = ThreadState::Enabled; } @@ -191,7 +246,7 @@ impl<'mir, 'tcx: 'mir> ThreadSet<'mir, 'tcx> { if self.threads.iter().all(|thread| thread.state == ThreadState::Terminated) { Ok(false) } else { - throw_machine_stop!(TerminationInfo::Abort(Some(format!("execution deadlocked")))) + throw_machine_stop!(TerminationInfo::Deadlock); } } } @@ -298,6 +353,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.machine.threads.get_all_thread_ids_with_states() } + fn create_blockset(&mut self) -> InterpResult<'tcx, BlockSetId> { + let this = self.eval_context_mut(); + Ok(this.machine.threads.create_blockset()) + } + fn block_active_thread(&mut self, set: BlockSetId) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + Ok(this.machine.threads.block_active_thread(set)) + } + fn unblock_random_thread(&mut self, set: BlockSetId) -> InterpResult<'tcx, Option> { + let this = self.eval_context_mut(); + Ok(this.machine.threads.unblock_random_thread(set)) + } /// Decide which thread to run next. /// /// Returns `false` if all threads terminated. diff --git a/tests/run-pass/concurrency/locks.rs b/tests/run-pass/concurrency/locks.rs new file mode 100644 index 000000000000..575aeadd7fed --- /dev/null +++ b/tests/run-pass/concurrency/locks.rs @@ -0,0 +1,29 @@ +//! This test just calls the relevant APIs to check if Miri crashes. + +use std::sync::{Arc, Mutex}; +use std::thread; + +fn main() { + + let data = Arc::new(Mutex::new(0)); + let mut threads = Vec::new(); + + for _ in 0..3 { + let data = Arc::clone(&data); + let thread = thread::spawn(move || { + let mut data = data.lock().unwrap(); + *data += 1; + }); + threads.push(thread); + } + + for thread in threads { + thread.join().unwrap(); + } + + assert!(data.try_lock().is_ok()); + + let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap(); + assert_eq!(data, 3); + +} \ No newline at end of file diff --git a/tests/run-pass/concurrency/locks.stdout b/tests/run-pass/concurrency/locks.stdout new file mode 100644 index 000000000000..2486b320db18 --- /dev/null +++ b/tests/run-pass/concurrency/locks.stdout @@ -0,0 +1,3 @@ +WARNING: The thread support is experimental. For example, Miri does not detect data races yet. +WARNING: The thread support is experimental. For example, Miri does not detect data races yet. +WARNING: The thread support is experimental. For example, Miri does not detect data races yet. From d907fb50215c2f79e4fd312447a67439620bb2ab Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 9 Apr 2020 12:06:33 -0700 Subject: [PATCH 1936/5092] Rename ThreadSet to ThreadManager. --- src/machine.rs | 4 ++-- src/threads.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index a7d62897b8f0..b56755083f4d 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -27,7 +27,7 @@ use rustc_target::abi::{LayoutOf, Size}; use crate::*; -pub use crate::threads::{ThreadId, ThreadSet, ThreadState, ThreadLocalStorage}; +pub use crate::threads::{ThreadId, ThreadManager, ThreadState, ThreadLocalStorage}; // Some global facts about the emulated machine. pub const PAGE_SIZE: u64 = 4 * 1024; // FIXME: adjust to target architecture @@ -257,7 +257,7 @@ pub struct Evaluator<'mir, 'tcx> { pub(crate) time_anchor: Instant, /// The set of threads. - pub(crate) threads: ThreadSet<'mir, 'tcx>, + pub(crate) threads: ThreadManager<'mir, 'tcx>, /// Precomputed `TyLayout`s for primitive data types that are commonly used inside Miri. pub(crate) layouts: PrimitiveLayouts<'tcx>, diff --git a/src/threads.rs b/src/threads.rs index 5991ba4ed1f6..2352f26ebeef 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -120,7 +120,7 @@ impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> { /// A set of threads. #[derive(Debug)] -pub struct ThreadSet<'mir, 'tcx> { +pub struct ThreadManager<'mir, 'tcx> { /// Identifier of the currently active thread. active_thread: ThreadId, /// Threads used in the program. @@ -131,7 +131,7 @@ pub struct ThreadSet<'mir, 'tcx> { blockset_counter: u32, } -impl<'mir, 'tcx> Default for ThreadSet<'mir, 'tcx> { +impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { fn default() -> Self { let mut threads = IndexVec::new(); threads.push(Default::default()); @@ -139,7 +139,7 @@ impl<'mir, 'tcx> Default for ThreadSet<'mir, 'tcx> { } } -impl<'mir, 'tcx: 'mir> ThreadSet<'mir, 'tcx> { +impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Borrow the stack of the active thread. fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] { &self.threads[self.active_thread].stack From 0c4303cd7f903d2c05e70c05800dddefd7ccb7c6 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 9 Apr 2020 13:37:38 -0700 Subject: [PATCH 1937/5092] Small refactoring in pthread sync: extract common functionallity to separate functions. --- src/shims/sync.rs | 235 ++++++++++++---------------------------------- 1 file changed, 58 insertions(+), 177 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index eb5435811434..76f97aab2391 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -1,4 +1,4 @@ -use rustc_middle::ty::{TyKind, TypeAndMut}; +use rustc_middle::ty::{layout::TyAndLayout, TyKind, TypeAndMut}; use rustc_target::abi::{LayoutOf, Size}; use crate::stacked_borrows::Tag; @@ -19,22 +19,48 @@ fn assert_ptr_target_min_size<'mir, 'tcx: 'mir>( Ok(()) } +fn get_at_offset<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + op: OpTy<'tcx, Tag>, + offset: u64, + layout: TyAndLayout<'tcx>, + min_size: u64, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the attr pointer is within bounds + assert_ptr_target_min_size(ecx, op, min_size)?; + let op_place = ecx.deref_operand(op)?; + let value_place = op_place.offset(Size::from_bytes(offset), MemPlaceMeta::None, layout, ecx)?; + ecx.read_scalar(value_place.into()) +} + +fn set_at_offset<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + op: OpTy<'tcx, Tag>, + offset: u64, + value: impl Into>, + layout: TyAndLayout<'tcx>, + min_size: u64, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the attr pointer is within bounds + assert_ptr_target_min_size(ecx, op, min_size)?; + let op_place = ecx.deref_operand(op)?; + let value_place = op_place.offset(Size::from_bytes(offset), MemPlaceMeta::None, layout, ecx)?; + ecx.write_scalar(value.into(), value_place.into()) +} + // pthread_mutexattr_t is either 4 or 8 bytes, depending on the platform. // Our chosen memory layout for emulation (does not have to match the platform layout!): // store an i32 in the first four bytes equal to the corresponding libc mutex kind constant // (e.g. PTHREAD_MUTEX_NORMAL). +const PTHREAD_MUTEXATTR_T_MIN_SIZE: u64 = 4; + fn mutexattr_get_kind<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, attr_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { - // Ensure that the following read at an offset to the attr pointer is within bounds - assert_ptr_target_min_size(ecx, attr_op, 4)?; - let attr_place = ecx.deref_operand(attr_op)?; - let kind_place = - attr_place.offset(Size::ZERO, MemPlaceMeta::None, ecx.machine.layouts.i32, ecx)?; - ecx.read_scalar(kind_place.into()) + get_at_offset(ecx, attr_op, 0, ecx.machine.layouts.i32, PTHREAD_MUTEXATTR_T_MIN_SIZE) } fn mutexattr_set_kind<'mir, 'tcx: 'mir>( @@ -42,12 +68,7 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( attr_op: OpTy<'tcx, Tag>, kind: impl Into>, ) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the attr pointer is within bounds - assert_ptr_target_min_size(ecx, attr_op, 4)?; - let attr_place = ecx.deref_operand(attr_op)?; - let kind_place = - attr_place.offset(Size::ZERO, MemPlaceMeta::None, ecx.machine.layouts.i32, ecx)?; - ecx.write_scalar(kind.into(), kind_place.into()) + set_at_offset(ecx, attr_op, 0, kind, ecx.machine.layouts.i32, PTHREAD_MUTEXATTR_T_MIN_SIZE) } // pthread_mutex_t is between 24 and 48 bytes, depending on the platform. @@ -61,20 +82,13 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( // (the kind has to be at its offset for compatibility with static initializer macros) // bytes 20-23: when count > 0, id of the blockset in which the blocked threads are waiting. +const PTHREAD_MUTEX_T_MIN_SIZE: u64 = 24; + fn mutex_get_locked_count<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { - // Ensure that the following read at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 24)?; - let mutex_place = ecx.deref_operand(mutex_op)?; - let locked_count_place = mutex_place.offset( - Size::from_bytes(4), - MemPlaceMeta::None, - ecx.machine.layouts.u32, - ecx, - )?; - ecx.read_scalar(locked_count_place.into()) + get_at_offset(ecx, mutex_op, 4, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } fn mutex_set_locked_count<'mir, 'tcx: 'mir>( @@ -82,66 +96,30 @@ fn mutex_set_locked_count<'mir, 'tcx: 'mir>( mutex_op: OpTy<'tcx, Tag>, locked_count: impl Into>, ) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 24)?; - let mutex_place = ecx.deref_operand(mutex_op)?; - let locked_count_place = mutex_place.offset( - Size::from_bytes(4), - MemPlaceMeta::None, - ecx.machine.layouts.u32, - ecx, - )?; - ecx.write_scalar(locked_count.into(), locked_count_place.into()) + set_at_offset(ecx, mutex_op, 4, locked_count, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } fn mutex_get_owner<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { - // Ensure that the following read at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 24)?; - let mutex_place = ecx.deref_operand(mutex_op)?; - let mutex_id_place = mutex_place.offset( - Size::from_bytes(8), - MemPlaceMeta::None, - ecx.machine.layouts.u32, - ecx, - )?; - ecx.read_scalar(mutex_id_place.into()) + get_at_offset(ecx, mutex_op, 8, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } fn mutex_set_owner<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, - mutex_id: impl Into>, + owner: impl Into>, ) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 24)?; - let mutex_place = ecx.deref_operand(mutex_op)?; - let mutex_id_place = mutex_place.offset( - Size::from_bytes(8), - MemPlaceMeta::None, - ecx.machine.layouts.u32, - ecx, - )?; - ecx.write_scalar(mutex_id.into(), mutex_id_place.into()) + set_at_offset(ecx, mutex_op, 8, owner, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } fn mutex_get_kind<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { - // Ensure that the following read at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 24)?; - let mutex_place = ecx.deref_operand(mutex_op)?; - let kind_offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - let kind_place = mutex_place.offset( - Size::from_bytes(kind_offset), - MemPlaceMeta::None, - ecx.machine.layouts.i32, - ecx, - )?; - ecx.read_scalar(kind_place.into()) + let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; + get_at_offset(ecx, mutex_op, offset, ecx.machine.layouts.i32, PTHREAD_MUTEX_T_MIN_SIZE) } fn mutex_set_kind<'mir, 'tcx: 'mir>( @@ -149,50 +127,23 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( mutex_op: OpTy<'tcx, Tag>, kind: impl Into>, ) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 24)?; - let mutex_place = ecx.deref_operand(mutex_op)?; - let kind_offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - let kind_place = mutex_place.offset( - Size::from_bytes(kind_offset), - MemPlaceMeta::None, - ecx.machine.layouts.i32, - ecx, - )?; - ecx.write_scalar(kind.into(), kind_place.into()) + let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; + set_at_offset(ecx, mutex_op, offset, kind, ecx.machine.layouts.i32, PTHREAD_MUTEX_T_MIN_SIZE) } fn mutex_get_blockset<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { - // Ensure that the following read at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 24)?; - let mutex_place = ecx.deref_operand(mutex_op)?; - let mutex_id_place = mutex_place.offset( - Size::from_bytes(20), - MemPlaceMeta::None, - ecx.machine.layouts.u32, - ecx, - )?; - ecx.read_scalar(mutex_id_place.into()) + get_at_offset(ecx, mutex_op, 20, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } fn mutex_set_blockset<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, - mutex_id: impl Into>, + blockset: impl Into>, ) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 24)?; - let mutex_place = ecx.deref_operand(mutex_op)?; - let mutex_id_place = mutex_place.offset( - Size::from_bytes(20), - MemPlaceMeta::None, - ecx.machine.layouts.u32, - ecx, - )?; - ecx.write_scalar(mutex_id.into(), mutex_id_place.into()) + set_at_offset(ecx, mutex_op, 20, blockset, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } fn mutex_get_or_create_blockset<'mir, 'tcx: 'mir>( @@ -223,20 +174,13 @@ fn mutex_get_or_create_blockset<'mir, 'tcx: 'mir>( // bytes 16-20: when writer count > 0, id of the blockset in which the blocked // readers are waiting. +const PTHREAD_RWLOCK_T_MIN_SIZE: u64 = 20; + fn rwlock_get_readers<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { - // Ensure that the following read at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 20)?; - let rwlock_place = ecx.deref_operand(rwlock_op)?; - let readers_place = rwlock_place.offset( - Size::from_bytes(4), - MemPlaceMeta::None, - ecx.machine.layouts.u32, - ecx, - )?; - ecx.read_scalar(readers_place.into()) + get_at_offset(ecx, rwlock_op, 4, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } fn rwlock_set_readers<'mir, 'tcx: 'mir>( @@ -244,32 +188,14 @@ fn rwlock_set_readers<'mir, 'tcx: 'mir>( rwlock_op: OpTy<'tcx, Tag>, readers: impl Into>, ) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 20)?; - let rwlock_place = ecx.deref_operand(rwlock_op)?; - let readers_place = rwlock_place.offset( - Size::from_bytes(4), - MemPlaceMeta::None, - ecx.machine.layouts.u32, - ecx, - )?; - ecx.write_scalar(readers.into(), readers_place.into()) + set_at_offset(ecx, rwlock_op, 4, readers, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } fn rwlock_get_writers<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { - // Ensure that the following read at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 20)?; - let rwlock_place = ecx.deref_operand(rwlock_op)?; - let writers_place = rwlock_place.offset( - Size::from_bytes(8), - MemPlaceMeta::None, - ecx.machine.layouts.u32, - ecx, - )?; - ecx.read_scalar(writers_place.into()) + get_at_offset(ecx, rwlock_op, 8, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } fn rwlock_set_writers<'mir, 'tcx: 'mir>( @@ -277,32 +203,14 @@ fn rwlock_set_writers<'mir, 'tcx: 'mir>( rwlock_op: OpTy<'tcx, Tag>, writers: impl Into>, ) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 20)?; - let rwlock_place = ecx.deref_operand(rwlock_op)?; - let writers_place = rwlock_place.offset( - Size::from_bytes(8), - MemPlaceMeta::None, - ecx.machine.layouts.u32, - ecx, - )?; - ecx.write_scalar(writers.into(), writers_place.into()) + set_at_offset(ecx, rwlock_op, 8, writers, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } fn rwlock_get_writer_blockset<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { - // Ensure that the following read at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 20)?; - let rwlock_place = ecx.deref_operand(rwlock_op)?; - let blockset_place = rwlock_place.offset( - Size::from_bytes(12), - MemPlaceMeta::None, - ecx.machine.layouts.u32, - ecx, - )?; - ecx.read_scalar(blockset_place.into()) + get_at_offset(ecx, rwlock_op, 12, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } fn rwlock_set_writer_blockset<'mir, 'tcx: 'mir>( @@ -310,16 +218,7 @@ fn rwlock_set_writer_blockset<'mir, 'tcx: 'mir>( rwlock_op: OpTy<'tcx, Tag>, blockset: impl Into>, ) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 20)?; - let rwlock_place = ecx.deref_operand(rwlock_op)?; - let blockset_place = rwlock_place.offset( - Size::from_bytes(12), - MemPlaceMeta::None, - ecx.machine.layouts.u32, - ecx, - )?; - ecx.write_scalar(blockset.into(), blockset_place.into()) + set_at_offset(ecx, rwlock_op, 12, blockset, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } fn rwlock_get_or_create_writer_blockset<'mir, 'tcx: 'mir>( @@ -342,16 +241,7 @@ fn rwlock_get_reader_blockset<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { - // Ensure that the following read at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 20)?; - let rwlock_place = ecx.deref_operand(rwlock_op)?; - let blockset_place = rwlock_place.offset( - Size::from_bytes(16), - MemPlaceMeta::None, - ecx.machine.layouts.u32, - ecx, - )?; - ecx.read_scalar(blockset_place.into()) + get_at_offset(ecx, rwlock_op, 16, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } fn rwlock_set_reader_blockset<'mir, 'tcx: 'mir>( @@ -359,16 +249,7 @@ fn rwlock_set_reader_blockset<'mir, 'tcx: 'mir>( rwlock_op: OpTy<'tcx, Tag>, blockset: impl Into>, ) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 20)?; - let rwlock_place = ecx.deref_operand(rwlock_op)?; - let blockset_place = rwlock_place.offset( - Size::from_bytes(16), - MemPlaceMeta::None, - ecx.machine.layouts.u32, - ecx, - )?; - ecx.write_scalar(blockset.into(), blockset_place.into()) + set_at_offset(ecx, rwlock_op, 16, blockset, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } fn rwlock_get_or_create_reader_blockset<'mir, 'tcx: 'mir>( From 963e9698f9ab959de06f42047ef1979bde0aac84 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Tue, 14 Apr 2020 17:21:52 -0700 Subject: [PATCH 1938/5092] Generate fresh allocation ids for thread locals in eval_maybe_thread_local_static_const. --- src/diagnostics.rs | 4 +- src/machine.rs | 112 ++++++++++++++++++++------------------------- src/shims/tls.rs | 2 +- 3 files changed, 53 insertions(+), 65 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 114f1d9be362..b7c96dd7e98a 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -139,7 +139,7 @@ fn report_msg<'tcx, 'mir>( mut helps: Vec, error: bool, ) { - let span = if let Some(frame) = ecx.machine.stack.last() { + let span = if let Some(frame) = ecx.active_thread_stack().last() { frame.current_source_info().unwrap().span } else { DUMMY_SP @@ -171,7 +171,7 @@ fn report_msg<'tcx, 'mir>( err.emit(); - for (i, frame) in ecx.machine.stack.iter().enumerate() { + for (i, frame) in ecx.active_thread_stack().iter().enumerate() { trace!("-------------------"); trace!("Frame {}", i); trace!(" return: {:?}", frame.return_place.map(|p| *p)); diff --git a/src/machine.rs b/src/machine.rs index b56755083f4d..a9582f595ff6 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -22,7 +22,7 @@ use rustc_middle::{ TyCtxt, }, }; -use rustc_span::{def_id::DefId, symbol::{sym, Symbol}}; +use rustc_span::symbol::{sym, Symbol}; use rustc_target::abi::{LayoutOf, Size}; use crate::*; @@ -331,19 +331,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { memory_extra.check_alignment } - #[inline(always)] - fn stack<'a>( - ecx: &'a InterpCx<'mir, 'tcx, Self> - ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] { - ecx.active_thread_stack() - } - - fn stack_mut<'a>( - ecx: &'a mut InterpCx<'mir, 'tcx, Self> - ) -> &'a mut Vec> { - ecx.active_thread_stack_mut() - } - #[inline(always)] fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { ecx.machine.validate @@ -434,63 +421,52 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { Ok(()) } - fn access_local( + fn eval_maybe_thread_local_static_const( ecx: &InterpCx<'mir, 'tcx, Self>, - frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, - local: mir::Local, - ) -> InterpResult<'tcx, Operand> { - match frame.body.local_decls[local].local_info { - mir::LocalInfo::StaticRef { def_id, is_thread_local: true } => { - let static_alloc_id = ecx.tcx.alloc_map.lock().create_static_alloc(def_id); - let alloc_id = ecx.memory.extra.tls.get_or_register_allocation(*ecx.memory.tcx, static_alloc_id); - let tag = Self::tag_global_base_pointer(&ecx.memory.extra, alloc_id); - let pointer: Pointer = alloc_id.into(); - let pointer = pointer.with_tag(tag); - let scalar: Scalar<_> = pointer.into(); - let scalar: ScalarMaybeUndef<_> = scalar.into(); - let immediate: Immediate<_> = scalar.into(); - Ok( - Operand::Immediate(immediate) - ) - }, - _ => frame.locals[local].access(), + mut val: mir::interpret::ConstValue<'tcx> + )-> InterpResult<'tcx, mir::interpret::ConstValue<'tcx>> { + match &mut val { + mir::interpret::ConstValue::Scalar(Scalar::Ptr(ptr)) => { + let alloc_id = ptr.alloc_id; + let alloc = ecx.tcx.alloc_map.lock().get(alloc_id); + match alloc { + Some(GlobalAlloc::Static(def_id)) + if ecx.tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) => { + // We have a thread-local static. + let new_alloc_id = ecx.memory.extra.tls.get_or_register_allocation( + *ecx.memory.tcx, alloc_id); + ptr.alloc_id = new_alloc_id; + }, + _ => {}, + } + } + _ => {}, } + Ok(val) } fn canonical_alloc_id(mem: &Memory<'mir, 'tcx, Self>, id: AllocId) -> AllocId { let tcx = mem.tcx; - let alloc = tcx.alloc_map.lock().get(id); - fn is_thread_local<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { - tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) - } - match alloc { - Some(GlobalAlloc::Static(def_id)) if tcx.is_foreign_item(def_id) => { - if is_thread_local(*tcx, def_id) { - unimplemented!("Foreign thread local statics are not supported yet."); - } - // Figure out if this is an extern static, and if yes, which one. - let attrs = tcx.get_attrs(def_id); - let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { - Some(name) => name, - None => tcx.item_name(def_id), - }; - // Check if we know this one. - if let Some(canonical_id) = mem.extra.extern_statics.get(&link_name) { - trace!("canonical_alloc_id: {:?} ({}) -> {:?}", id, link_name, canonical_id); - *canonical_id - } else { - // Return original id; `Memory::get_static_alloc` will throw an error. - id - } - }, - Some(GlobalAlloc::Static(def_id)) if is_thread_local(*tcx, def_id) => { - // We have a thread local, so we need to get a unique allocation id for it. - mem.extra.tls.get_or_register_allocation(*tcx, id) - }, + // Figure out if this is an extern static, and if yes, which one. + let def_id = match tcx.alloc_map.lock().get(id) { + Some(GlobalAlloc::Static(def_id)) if tcx.is_foreign_item(def_id) => def_id, _ => { // No need to canonicalize anything. - id + return id; } + }; + let attrs = tcx.get_attrs(def_id); + let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { + Some(name) => name, + None => tcx.item_name(def_id), + }; + // Check if we know this one. + if let Some(canonical_id) = mem.extra.extern_statics.get(&link_name) { + trace!("canonical_alloc_id: {:?} ({}) -> {:?}", id, link_name, canonical_id); + *canonical_id + } else { + // Return original id; `Memory::get_static_alloc` will throw an error. + id } } @@ -587,6 +563,18 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { Ok(frame.with_extra(extra)) } + fn stack<'a>( + ecx: &'a InterpCx<'mir, 'tcx, Self> + ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] { + ecx.active_thread_stack() + } + + fn stack_mut<'a>( + ecx: &'a mut InterpCx<'mir, 'tcx, Self> + ) -> &'a mut Vec> { + ecx.active_thread_stack_mut() + } + #[inline(always)] fn stack<'a>( ecx: &'a InterpCx<'mir, 'tcx, Self>, diff --git a/src/shims/tls.rs b/src/shims/tls.rs index ec8c31fe2c12..5cef3871c033 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -161,7 +161,7 @@ impl<'tcx> TlsData<'tcx> { Entry::Occupied(entry) => { let (thread_id, data_scalar) = entry.remove_entry(); if let Some(dtor) = dtor { - let ret = Some((dtor, thread_id, data_scalar, key)); + let ret = Some((*dtor, thread_id, data_scalar, key)); return ret; } } From 51b16e56cd297afd308aea5b258a677901c7b45e Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Wed, 15 Apr 2020 14:34:34 -0700 Subject: [PATCH 1939/5092] Generate thread local allocations in eval_maybe_thread_local_static_const. --- src/machine.rs | 64 ++++++++++++++++++++--------- src/threads.rs | 108 ++++++++++++++++--------------------------------- 2 files changed, 78 insertions(+), 94 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index a9582f595ff6..a5183d3e8166 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -18,6 +18,7 @@ use rustc_middle::{ mir, ty::{ self, + Instance, layout::{LayoutCx, LayoutError, TyAndLayout}, TyCtxt, }, @@ -27,7 +28,7 @@ use rustc_target::abi::{LayoutOf, Size}; use crate::*; -pub use crate::threads::{ThreadId, ThreadManager, ThreadState, ThreadLocalStorage}; +pub use crate::threads::{ThreadId, ThreadManager, ThreadState}; // Some global facts about the emulated machine. pub const PAGE_SIZE: u64 = 4 * 1024; // FIXME: adjust to target architecture @@ -110,7 +111,6 @@ pub struct AllocExtra { pub struct MemoryExtra { pub stacked_borrows: Option, pub intptrcast: intptrcast::MemoryExtra, - pub tls: ThreadLocalStorage, /// Mapping extern static names to their canonical allocation. extern_statics: FxHashMap, @@ -147,7 +147,6 @@ impl MemoryExtra { rng: RefCell::new(rng), tracked_alloc_id, check_alignment, - tls: Default::default(), } } @@ -423,24 +422,58 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn eval_maybe_thread_local_static_const( ecx: &InterpCx<'mir, 'tcx, Self>, - mut val: mir::interpret::ConstValue<'tcx> - )-> InterpResult<'tcx, mir::interpret::ConstValue<'tcx>> { + mut val: mir::interpret::ConstValue<'tcx>, + ) -> InterpResult<'tcx, mir::interpret::ConstValue<'tcx>> { match &mut val { mir::interpret::ConstValue::Scalar(Scalar::Ptr(ptr)) => { let alloc_id = ptr.alloc_id; let alloc = ecx.tcx.alloc_map.lock().get(alloc_id); match alloc { Some(GlobalAlloc::Static(def_id)) - if ecx.tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) => { + if ecx + .tcx + .codegen_fn_attrs(def_id) + .flags + .contains(CodegenFnAttrFlags::THREAD_LOCAL) => + { // We have a thread-local static. - let new_alloc_id = ecx.memory.extra.tls.get_or_register_allocation( - *ecx.memory.tcx, alloc_id); + let new_alloc_id = if let Some(new_alloc_id) = + ecx.get_thread_local_alloc_id(alloc_id) + { + new_alloc_id + } else { + if ecx.tcx.is_foreign_item(def_id) { + throw_unsup_format!( + "Foreign thread-local statics are not supported." + ) + } + let instance = Instance::mono(ecx.tcx.tcx, def_id); + let gid = GlobalId { instance, promoted: None }; + let raw_const = ecx + .tcx + .const_eval_raw(ty::ParamEnv::reveal_all().and(gid)) + .map_err(|err| { + // no need to report anything, the const_eval call takes care of that + // for statics + assert!(ecx.tcx.is_static(def_id)); + match err { + ErrorHandled::Reported => err_inval!(ReferencedConstant), + ErrorHandled::TooGeneric => err_inval!(TooGeneric), + } + })?; + let id = raw_const.alloc_id; + let mut alloc_map = ecx.tcx.alloc_map.lock(); + let allocation = alloc_map.unwrap_memory(id); + let new_alloc_id = alloc_map.create_memory_alloc(allocation); + ecx.set_thread_local_alloc_id(alloc_id, new_alloc_id); + new_alloc_id + }; ptr.alloc_id = new_alloc_id; - }, - _ => {}, + } + _ => {} } } - _ => {}, + _ => {} } Ok(val) } @@ -470,15 +503,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } } - #[inline(always)] - fn resolve_maybe_global_alloc( - tcx: ty::query::TyCtxtAt<'tcx>, - extra: &Self::MemoryExtra, - id: AllocId, - ) -> Option> { - extra.tls.resolve_allocation(*tcx, id) - } - fn init_allocation_extra<'b>( memory_extra: &MemoryExtra, id: AllocId, diff --git a/src/threads.rs b/src/threads.rs index 2352f26ebeef..170fb0c4767e 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -1,15 +1,12 @@ //! Implements threads. use std::cell::RefCell; -use std::collections::hash_map::Entry; use std::convert::TryFrom; use log::trace; use rustc_data_structures::fx::FxHashMap; use rustc_index::vec::{Idx, IndexVec}; -use rustc_middle::mir; -use rustc_middle::ty; use crate::*; @@ -129,17 +126,41 @@ pub struct ThreadManager<'mir, 'tcx> { threads: IndexVec>, /// A counter used to generate unique identifiers for blocksets. blockset_counter: u32, + /// A mapping from an allocation id of a thread-local static to an + /// allocation id of a thread specific allocation. + thread_local_alloc_ids: RefCell>, } impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { fn default() -> Self { let mut threads = IndexVec::new(); threads.push(Default::default()); - Self { active_thread: ThreadId::new(0), threads: threads, blockset_counter: 0 } + Self { + active_thread: ThreadId::new(0), + threads: threads, + blockset_counter: 0, + thread_local_alloc_ids: Default::default(), + } } } impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { + /// Check if we have an allocation for the given thread local static for the + /// active thread. + pub fn get_thread_local_alloc_id(&self, static_alloc_id: AllocId) -> Option { + self.thread_local_alloc_ids.borrow().get(&(static_alloc_id, self.active_thread)).cloned() + } + /// Set the allocation id as the allocation id of the given thread local + /// static for the active thread. + pub fn set_thread_local_alloc_id(&self, static_alloc_id: AllocId, new_alloc_id: AllocId) { + assert!( + self.thread_local_alloc_ids + .borrow_mut() + .insert((static_alloc_id, self.active_thread), new_alloc_id) + .is_none(), + "Bug: a thread local initialized twice for the same thread." + ); + } /// Borrow the stack of the active thread. fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] { &self.threads[self.active_thread].stack @@ -251,69 +272,16 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } } -/// In Rust, a thread local variable is just a specially marked static. To -/// ensure a property that each memory allocation has a globally unique -/// allocation identifier, we create a fresh allocation id for each thread. This -/// data structure keeps the track of the created allocation identifiers and -/// their relation to the original static allocations. -#[derive(Clone, Debug, Default)] -pub struct ThreadLocalStorage { - /// A map from a thread local allocation identifier to the static from which - /// it was created. - thread_local_origin: RefCell>, - /// A map from a thread local static and thread id to the unique thread - /// local allocation. - thread_local_allocations: RefCell>, - /// The currently active thread. - active_thread: Option, -} - -impl ThreadLocalStorage { - /// For static allocation identifier `original_id` get a thread local - /// allocation identifier. If it is not allocated yet, allocate. - pub fn get_or_register_allocation(&self, tcx: ty::TyCtxt<'_>, original_id: AllocId) -> AllocId { - match self - .thread_local_allocations - .borrow_mut() - .entry((original_id, self.active_thread.unwrap())) - { - Entry::Occupied(entry) => *entry.get(), - Entry::Vacant(entry) => { - let fresh_id = tcx.alloc_map.lock().reserve(); - entry.insert(fresh_id); - self.thread_local_origin.borrow_mut().insert(fresh_id, original_id); - trace!( - "get_or_register_allocation(original_id={:?}) -> {:?}", - original_id, - fresh_id - ); - fresh_id - } - } - } - /// For thread local allocation identifier `alloc_id`, retrieve the original - /// static allocation identifier from which it was created. - pub fn resolve_allocation<'tcx>( - &self, - tcx: ty::TyCtxt<'tcx>, - alloc_id: AllocId, - ) -> Option> { - trace!("resolve_allocation(alloc_id: {:?})", alloc_id); - if let Some(original_id) = self.thread_local_origin.borrow().get(&alloc_id) { - trace!("resolve_allocation(alloc_id: {:?}) -> {:?}", alloc_id, original_id); - tcx.alloc_map.lock().get(*original_id) - } else { - tcx.alloc_map.lock().get(alloc_id) - } - } - /// Set which thread is currently active. - fn set_active_thread(&mut self, active_thread: ThreadId) { - self.active_thread = Some(active_thread); - } -} - impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn get_thread_local_alloc_id(&self, static_alloc_id: AllocId) -> Option { + let this = self.eval_context_ref(); + this.machine.threads.get_thread_local_alloc_id(static_alloc_id) + } + fn set_thread_local_alloc_id(&self, static_alloc_id: AllocId, thread_local_alloc_id: AllocId) { + let this = self.eval_context_ref(); + this.machine.threads.set_thread_local_alloc_id(static_alloc_id, thread_local_alloc_id) + } fn create_thread(&mut self) -> InterpResult<'tcx, ThreadId> { let this = self.eval_context_mut(); Ok(this.machine.threads.create_thread()) @@ -330,7 +298,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } fn set_active_thread(&mut self, thread_id: ThreadId) -> InterpResult<'tcx, ThreadId> { let this = self.eval_context_mut(); - this.memory.extra.tls.set_active_thread(thread_id); Ok(this.machine.threads.set_active_thread_id(thread_id)) } fn get_active_thread(&self) -> InterpResult<'tcx, ThreadId> { @@ -370,13 +337,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Returns `false` if all threads terminated. fn schedule(&mut self) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - // Find the next thread to run. - if this.machine.threads.schedule()? { - let active_thread = this.machine.threads.get_active_thread_id(); - this.memory.extra.tls.set_active_thread(active_thread); - Ok(true) - } else { - Ok(false) - } + this.machine.threads.schedule() } } From 325c31e578210d0c72d8d5f1612074ddcbe514bb Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Wed, 15 Apr 2020 21:25:12 -0700 Subject: [PATCH 1940/5092] Address some of the reviewers comments. --- src/eval.rs | 2 +- src/machine.rs | 24 ++++---- src/shims/foreign_items/posix.rs | 57 ++++++++----------- src/shims/threads.rs | 14 +++-- src/threads.rs | 43 ++++++++++++-- tests/compile-fail/thread-spawn.rs | 9 +++ tests/run-pass/concurrency/locks.rs | 2 + tests/run-pass/concurrency/locks.stderr | 2 + tests/run-pass/concurrency/locks.stdout | 3 - tests/run-pass/concurrency/simple.rs | 2 + tests/run-pass/concurrency/simple.stderr | 2 + tests/run-pass/concurrency/simple.stdout | 10 ---- tests/run-pass/concurrency/thread_locals.rs | 2 + .../run-pass/concurrency/thread_locals.stderr | 2 + .../run-pass/concurrency/thread_locals.stdout | 1 - 15 files changed, 101 insertions(+), 74 deletions(-) create mode 100644 tests/compile-fail/thread-spawn.rs create mode 100644 tests/run-pass/concurrency/locks.stderr delete mode 100644 tests/run-pass/concurrency/locks.stdout create mode 100644 tests/run-pass/concurrency/simple.stderr delete mode 100644 tests/run-pass/concurrency/simple.stdout create mode 100644 tests/run-pass/concurrency/thread_locals.stderr delete mode 100644 tests/run-pass/concurrency/thread_locals.stdout diff --git a/src/eval.rs b/src/eval.rs index b0a59c64d1e1..d83039e47568 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -206,7 +206,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> let res: InterpResult<'_, i64> = (|| { // Main loop. while ecx.schedule()? { - assert!(ecx.step()?); + assert!(ecx.step()?, "Bug: a terminated thread was scheduled for execution."); ecx.process_diagnostics(); } // Read the return code pointer *before* we run TLS destructors, to assert diff --git a/src/machine.rs b/src/machine.rs index a5183d3e8166..0920364a44a8 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -428,41 +428,37 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { mir::interpret::ConstValue::Scalar(Scalar::Ptr(ptr)) => { let alloc_id = ptr.alloc_id; let alloc = ecx.tcx.alloc_map.lock().get(alloc_id); + let tcx = ecx.tcx; + let is_thread_local = |def_id| { + tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) + }; match alloc { - Some(GlobalAlloc::Static(def_id)) - if ecx - .tcx - .codegen_fn_attrs(def_id) - .flags - .contains(CodegenFnAttrFlags::THREAD_LOCAL) => - { - // We have a thread-local static. + Some(GlobalAlloc::Static(def_id)) if is_thread_local(def_id) => { let new_alloc_id = if let Some(new_alloc_id) = ecx.get_thread_local_alloc_id(alloc_id) { new_alloc_id } else { - if ecx.tcx.is_foreign_item(def_id) { + if tcx.is_foreign_item(def_id) { throw_unsup_format!( "Foreign thread-local statics are not supported." ) } - let instance = Instance::mono(ecx.tcx.tcx, def_id); + let instance = Instance::mono(tcx.tcx, def_id); let gid = GlobalId { instance, promoted: None }; - let raw_const = ecx - .tcx + let raw_const = tcx .const_eval_raw(ty::ParamEnv::reveal_all().and(gid)) .map_err(|err| { // no need to report anything, the const_eval call takes care of that // for statics - assert!(ecx.tcx.is_static(def_id)); + assert!(tcx.is_static(def_id)); match err { ErrorHandled::Reported => err_inval!(ReferencedConstant), ErrorHandled::TooGeneric => err_inval!(TooGeneric), } })?; let id = raw_const.alloc_id; - let mut alloc_map = ecx.tcx.alloc_map.lock(); + let mut alloc_map = tcx.alloc_map.lock(); let allocation = alloc_map.unwrap_memory(id); let new_alloc_id = alloc_map.create_memory_alloc(allocation); ecx.set_thread_local_alloc_id(alloc_id, new_alloc_id); diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 4cd3b8499112..5bb556aaa50b 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -293,26 +293,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } - // Miscellaneous - "isatty" => { - let _fd = this.read_scalar(args[0])?.to_i32()?; - // "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error" - // FIXME: we just say nothing is a terminal. - let enotty = this.eval_libc("ENOTTY")?; - this.set_last_error(enotty)?; - this.write_null(dest)?; - } - "pthread_atfork" => { - let _prepare = this.read_scalar(args[0])?.not_undef()?; - let _parent = this.read_scalar(args[1])?.not_undef()?; - let _child = this.read_scalar(args[1])?.not_undef()?; - // We do not support forking, so there is nothing to do here. - this.write_null(dest)?; - } - "sched_yield" => { - this.write_null(dest)?; - } - // Threading "pthread_create" => { assert_eq!(args.len(), 4); @@ -339,20 +319,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } - "pthread_attr_getguardsize" => { - assert_eq!(args.len(), 2); - - let guard_size = this.deref_operand(args[1])?; - let guard_size_type = args[1].layout.ty - .builtin_deref(true) - .ok_or_else(|| err_ub_format!( - "wrong signature used for `pthread_attr_getguardsize`: first argument must be a raw pointer." - ))? - .ty; - let guard_size_layout = this.layout_of(guard_size_type)?; - this.write_scalar(Scalar::from_uint(crate::PAGE_SIZE, guard_size_layout.size), guard_size.into())?; - - // Return success (`0`). + // Miscellaneous + "isatty" => { + let _fd = this.read_scalar(args[0])?.to_i32()?; + // "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error" + // FIXME: we just say nothing is a terminal. + let enotty = this.eval_libc("ENOTTY")?; + this.set_last_error(enotty)?; + this.write_null(dest)?; + } + "pthread_atfork" => { + let _prepare = this.read_scalar(args[0])?.not_undef()?; + let _parent = this.read_scalar(args[1])?.not_undef()?; + let _child = this.read_scalar(args[1])?.not_undef()?; + // We do not support forking, so there is nothing to do here. this.write_null(dest)?; } @@ -369,6 +349,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx => { this.write_null(dest)?; } + "pthread_attr_getguardsize" if this.frame().instance.to_string().starts_with("std::sys::unix::") + => { + let guard_size = this.deref_operand(args[1])?; + let guard_size_layout = this.libc_ty_layout("size_t")?; + this.write_scalar(Scalar::from_uint(crate::PAGE_SIZE, guard_size_layout.size), guard_size.into())?; + + // Return success (`0`). + this.write_null(dest)?; + } | "signal" | "sigaction" diff --git a/src/shims/threads.rs b/src/shims/threads.rs index fc733d7f5c9f..d8ba11d267f3 100644 --- a/src/shims/threads.rs +++ b/src/shims/threads.rs @@ -11,13 +11,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx start_routine: OpTy<'tcx, Tag>, arg: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { - println!( - "WARNING: The thread support is experimental. \ - For example, Miri does not detect data races yet." - ); - let this = self.eval_context_mut(); + this.tcx.sess.warn( + "The thread support is experimental. \ + For example, Miri does not detect data races yet.", + ); + let new_thread_id = this.create_thread()?; let old_thread_id = this.set_active_thread(new_thread_id)?; @@ -57,6 +57,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } + fn pthread_join( &mut self, thread: OpTy<'tcx, Tag>, @@ -73,6 +74,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } + fn pthread_detach(&mut self, thread: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -81,12 +83,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } + fn pthread_self(&mut self, dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let thread_id = this.get_active_thread()?; this.write_scalar(Scalar::from_uint(thread_id.index() as u128, dest.layout.size), dest) } + fn prctl( &mut self, option: OpTy<'tcx, Tag>, diff --git a/src/threads.rs b/src/threads.rs index 170fb0c4767e..c623fcae817d 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -2,6 +2,7 @@ use std::cell::RefCell; use std::convert::TryFrom; +use std::num::NonZeroU32; use log::trace; @@ -42,21 +43,18 @@ impl ThreadId { } /// An identifier of a set of blocked threads. -/// -/// Note: 0 is not a valid identifier. #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] -pub struct BlockSetId(u32); +pub struct BlockSetId(NonZeroU32); impl From for BlockSetId { fn from(id: u32) -> Self { - assert_ne!(id, 0, "0 is not a valid blockset id"); - Self(id) + Self(NonZeroU32::new(id).expect("0 is not a valid blockset id")) } } impl BlockSetId { pub fn to_u32_scalar<'tcx>(&self) -> Scalar { - Scalar::from_u32(self.0) + Scalar::from_u32(self.0.get()) } } @@ -150,6 +148,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { pub fn get_thread_local_alloc_id(&self, static_alloc_id: AllocId) -> Option { self.thread_local_alloc_ids.borrow().get(&(static_alloc_id, self.active_thread)).cloned() } + /// Set the allocation id as the allocation id of the given thread local /// static for the active thread. pub fn set_thread_local_alloc_id(&self, static_alloc_id: AllocId, new_alloc_id: AllocId) { @@ -161,20 +160,24 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { "Bug: a thread local initialized twice for the same thread." ); } + /// Borrow the stack of the active thread. fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] { &self.threads[self.active_thread].stack } + /// Mutably borrow the stack of the active thread. fn active_thread_stack_mut(&mut self) -> &mut Vec>> { &mut self.threads[self.active_thread].stack } + /// Create a new thread and returns its id. fn create_thread(&mut self) -> ThreadId { let new_thread_id = ThreadId::new(self.threads.len()); self.threads.push(Default::default()); new_thread_id } + /// Set an active thread and return the id of the thread that was active before. fn set_active_thread_id(&mut self, id: ThreadId) -> ThreadId { let active_thread_id = self.active_thread; @@ -182,19 +185,23 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { assert!(self.active_thread.index() < self.threads.len()); active_thread_id } + /// Get the id of the currently active thread. fn get_active_thread_id(&self) -> ThreadId { self.active_thread } + /// Get the borrow of the currently active thread. fn active_thread_mut(&mut self) -> &mut Thread<'mir, 'tcx> { &mut self.threads[self.active_thread] } + /// Mark the thread as detached, which means that no other thread will try /// to join it and the thread is responsible for cleaning up. fn detach_thread(&mut self, id: ThreadId) { self.threads[id].detached = true; } + /// Mark that the active thread tries to join the thread with `joined_thread_id`. fn join_thread(&mut self, joined_thread_id: ThreadId) { assert!(!self.threads[joined_thread_id].detached, "Bug: trying to join a detached thread."); @@ -215,23 +222,32 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { ); } } + /// Set the name of the active thread. fn set_thread_name(&mut self, new_thread_name: Vec) { self.active_thread_mut().thread_name = Some(new_thread_name); } + /// Get ids and states of all threads ever allocated. fn get_all_thread_ids_with_states(&self) -> Vec<(ThreadId, ThreadState)> { self.threads.iter_enumerated().map(|(id, thread)| (id, thread.state)).collect() } + + /// Allocate a new blockset id. fn create_blockset(&mut self) -> BlockSetId { self.blockset_counter = self.blockset_counter.checked_add(1).unwrap(); self.blockset_counter.into() } + + /// Block the currently active thread and put it into the given blockset. fn block_active_thread(&mut self, set: BlockSetId) { let state = &mut self.active_thread_mut().state; assert_eq!(*state, ThreadState::Enabled); *state = ThreadState::Blocked(set); } + + /// Unblock any one thread from the given blockset if it contains at least + /// one. Return the id of the unblocked thread. fn unblock_random_thread(&mut self, set: BlockSetId) -> Option { for (id, thread) in self.threads.iter_enumerated_mut() { if thread.state == ThreadState::Blocked(set) { @@ -242,6 +258,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } None } + /// Decide which thread to run next. /// /// Returns `false` if all threads terminated. @@ -278,60 +295,74 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); this.machine.threads.get_thread_local_alloc_id(static_alloc_id) } + fn set_thread_local_alloc_id(&self, static_alloc_id: AllocId, thread_local_alloc_id: AllocId) { let this = self.eval_context_ref(); this.machine.threads.set_thread_local_alloc_id(static_alloc_id, thread_local_alloc_id) } + fn create_thread(&mut self) -> InterpResult<'tcx, ThreadId> { let this = self.eval_context_mut(); Ok(this.machine.threads.create_thread()) } + fn detach_thread(&mut self, thread_id: ThreadId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.machine.threads.detach_thread(thread_id); Ok(()) } + fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.machine.threads.join_thread(joined_thread_id); Ok(()) } + fn set_active_thread(&mut self, thread_id: ThreadId) -> InterpResult<'tcx, ThreadId> { let this = self.eval_context_mut(); Ok(this.machine.threads.set_active_thread_id(thread_id)) } + fn get_active_thread(&self) -> InterpResult<'tcx, ThreadId> { let this = self.eval_context_ref(); Ok(this.machine.threads.get_active_thread_id()) } + fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] { let this = self.eval_context_ref(); this.machine.threads.active_thread_stack() } + fn active_thread_stack_mut(&mut self) -> &mut Vec>> { let this = self.eval_context_mut(); this.machine.threads.active_thread_stack_mut() } + fn set_active_thread_name(&mut self, new_thread_name: Vec) -> InterpResult<'tcx, ()> { let this = self.eval_context_mut(); Ok(this.machine.threads.set_thread_name(new_thread_name)) } + fn get_all_thread_ids_with_states(&mut self) -> Vec<(ThreadId, ThreadState)> { let this = self.eval_context_mut(); this.machine.threads.get_all_thread_ids_with_states() } + fn create_blockset(&mut self) -> InterpResult<'tcx, BlockSetId> { let this = self.eval_context_mut(); Ok(this.machine.threads.create_blockset()) } + fn block_active_thread(&mut self, set: BlockSetId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); Ok(this.machine.threads.block_active_thread(set)) } + fn unblock_random_thread(&mut self, set: BlockSetId) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); Ok(this.machine.threads.unblock_random_thread(set)) } + /// Decide which thread to run next. /// /// Returns `false` if all threads terminated. diff --git a/tests/compile-fail/thread-spawn.rs b/tests/compile-fail/thread-spawn.rs new file mode 100644 index 000000000000..4b9073f3a73e --- /dev/null +++ b/tests/compile-fail/thread-spawn.rs @@ -0,0 +1,9 @@ +// ignore-linux +// ignore-macos +use std::thread; + +// error-pattern: Miri does not support threading + +fn main() { + thread::spawn(|| {}); +} diff --git a/tests/run-pass/concurrency/locks.rs b/tests/run-pass/concurrency/locks.rs index 575aeadd7fed..49935db91bd9 100644 --- a/tests/run-pass/concurrency/locks.rs +++ b/tests/run-pass/concurrency/locks.rs @@ -1,3 +1,5 @@ +// ignore-windows + //! This test just calls the relevant APIs to check if Miri crashes. use std::sync::{Arc, Mutex}; diff --git a/tests/run-pass/concurrency/locks.stderr b/tests/run-pass/concurrency/locks.stderr new file mode 100644 index 000000000000..20a2bf3eeb87 --- /dev/null +++ b/tests/run-pass/concurrency/locks.stderr @@ -0,0 +1,2 @@ +warning: The thread support is experimental. For example, Miri does not detect data races yet. + diff --git a/tests/run-pass/concurrency/locks.stdout b/tests/run-pass/concurrency/locks.stdout deleted file mode 100644 index 2486b320db18..000000000000 --- a/tests/run-pass/concurrency/locks.stdout +++ /dev/null @@ -1,3 +0,0 @@ -WARNING: The thread support is experimental. For example, Miri does not detect data races yet. -WARNING: The thread support is experimental. For example, Miri does not detect data races yet. -WARNING: The thread support is experimental. For example, Miri does not detect data races yet. diff --git a/tests/run-pass/concurrency/simple.rs b/tests/run-pass/concurrency/simple.rs index 5c295d1702dd..5adc521f59c2 100644 --- a/tests/run-pass/concurrency/simple.rs +++ b/tests/run-pass/concurrency/simple.rs @@ -1,3 +1,5 @@ +// ignore-windows + use std::thread; fn create_and_detach() { diff --git a/tests/run-pass/concurrency/simple.stderr b/tests/run-pass/concurrency/simple.stderr new file mode 100644 index 000000000000..20a2bf3eeb87 --- /dev/null +++ b/tests/run-pass/concurrency/simple.stderr @@ -0,0 +1,2 @@ +warning: The thread support is experimental. For example, Miri does not detect data races yet. + diff --git a/tests/run-pass/concurrency/simple.stdout b/tests/run-pass/concurrency/simple.stdout deleted file mode 100644 index 0506b7bdf83c..000000000000 --- a/tests/run-pass/concurrency/simple.stdout +++ /dev/null @@ -1,10 +0,0 @@ -WARNING: The thread support is experimental. For example, Miri does not detect data races yet. -WARNING: The thread support is experimental. For example, Miri does not detect data races yet. -WARNING: The thread support is experimental. For example, Miri does not detect data races yet. -WARNING: The thread support is experimental. For example, Miri does not detect data races yet. -WARNING: The thread support is experimental. For example, Miri does not detect data races yet. -WARNING: The thread support is experimental. For example, Miri does not detect data races yet. -WARNING: The thread support is experimental. For example, Miri does not detect data races yet. -WARNING: The thread support is experimental. For example, Miri does not detect data races yet. -WARNING: The thread support is experimental. For example, Miri does not detect data races yet. -WARNING: The thread support is experimental. For example, Miri does not detect data races yet. diff --git a/tests/run-pass/concurrency/thread_locals.rs b/tests/run-pass/concurrency/thread_locals.rs index 50aa6fee2f87..1805a1da3d0b 100644 --- a/tests/run-pass/concurrency/thread_locals.rs +++ b/tests/run-pass/concurrency/thread_locals.rs @@ -1,3 +1,5 @@ +// ignore-windows + #![feature(thread_local)] use std::thread; diff --git a/tests/run-pass/concurrency/thread_locals.stderr b/tests/run-pass/concurrency/thread_locals.stderr new file mode 100644 index 000000000000..20a2bf3eeb87 --- /dev/null +++ b/tests/run-pass/concurrency/thread_locals.stderr @@ -0,0 +1,2 @@ +warning: The thread support is experimental. For example, Miri does not detect data races yet. + diff --git a/tests/run-pass/concurrency/thread_locals.stdout b/tests/run-pass/concurrency/thread_locals.stdout deleted file mode 100644 index 9a53b4a5c913..000000000000 --- a/tests/run-pass/concurrency/thread_locals.stdout +++ /dev/null @@ -1 +0,0 @@ -WARNING: The thread support is experimental. For example, Miri does not detect data races yet. From 4609c3c520f8b9b4d014f4a0a8ee12528fba6211 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 16 Apr 2020 08:34:30 -0700 Subject: [PATCH 1941/5092] Rename eval_maybe_thread_local_static_const to adjust_global_const. --- src/machine.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine.rs b/src/machine.rs index 0920364a44a8..d79e0255f025 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -420,7 +420,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { Ok(()) } - fn eval_maybe_thread_local_static_const( + fn adjust_global_const( ecx: &InterpCx<'mir, 'tcx, Self>, mut val: mir::interpret::ConstValue<'tcx>, ) -> InterpResult<'tcx, mir::interpret::ConstValue<'tcx>> { From d9ec0f2b36cc53e770193fa5a409f51cc3a7cc5a Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 16 Apr 2020 12:21:01 -0700 Subject: [PATCH 1942/5092] Add a missing newline in the test. --- tests/run-pass/concurrency/locks.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/run-pass/concurrency/locks.rs b/tests/run-pass/concurrency/locks.rs index 49935db91bd9..3c8373691b84 100644 --- a/tests/run-pass/concurrency/locks.rs +++ b/tests/run-pass/concurrency/locks.rs @@ -6,7 +6,6 @@ use std::sync::{Arc, Mutex}; use std::thread; fn main() { - let data = Arc::new(Mutex::new(0)); let mut threads = Vec::new(); @@ -27,5 +26,4 @@ fn main() { let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap(); assert_eq!(data, 3); - -} \ No newline at end of file +} From 552080a5b7c4ec01d3ed74b411bfefaaebf70feb Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 16 Apr 2020 12:22:30 -0700 Subject: [PATCH 1943/5092] Fix imports. --- src/lib.rs | 4 +++- src/machine.rs | 2 -- src/shims/tls.rs | 6 ++++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d8b3397c8e9b..bedacf705ac4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -63,7 +63,9 @@ pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, Stack, Stacks, Tag, }; -pub use crate::threads::EvalContextExt as ThreadsEvalContextExt; +pub use crate::threads::{ + EvalContextExt as ThreadsEvalContextExt, ThreadId, ThreadManager, ThreadState, +}; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. diff --git a/src/machine.rs b/src/machine.rs index d79e0255f025..23d4e37c66d1 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -28,8 +28,6 @@ use rustc_target::abi::{LayoutOf, Size}; use crate::*; -pub use crate::threads::{ThreadId, ThreadManager, ThreadState}; - // Some global facts about the emulated machine. pub const PAGE_SIZE: u64 = 4 * 1024; // FIXME: adjust to target architecture pub const STACK_ADDR: u64 = 32 * PAGE_SIZE; // not really about the "stack", but where we start assigning integer addresses to allocations diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 5cef3871c033..da0c585958a3 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -8,8 +8,10 @@ use log::trace; use rustc_middle::ty; use rustc_target::abi::{Size, HasDataLayout}; -use crate::{HelpersEvalContextExt, ThreadsEvalContextExt, InterpResult, MPlaceTy, Scalar, StackPopCleanup, Tag}; -use crate::machine::{ThreadId, ThreadState}; +use crate::{ + HelpersEvalContextExt, InterpResult, MPlaceTy, Scalar, StackPopCleanup, Tag, ThreadId, + ThreadState, ThreadsEvalContextExt, +}; pub type TlsKey = u128; From 94118d4d9ad4bbce3533638ca5fc540275d14a69 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 16 Apr 2020 12:22:58 -0700 Subject: [PATCH 1944/5092] Make an assert message consistent with other asserts. --- src/eval.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/eval.rs b/src/eval.rs index d83039e47568..085a53862fd4 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -206,7 +206,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> let res: InterpResult<'_, i64> = (|| { // Main loop. while ecx.schedule()? { - assert!(ecx.step()?, "Bug: a terminated thread was scheduled for execution."); + assert!(ecx.step()?, "a terminated thread was scheduled for execution"); ecx.process_diagnostics(); } // Read the return code pointer *before* we run TLS destructors, to assert From 1d0eb93ebddd35126cc22f938ff9247ff0e27b0b Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 16 Apr 2020 12:26:32 -0700 Subject: [PATCH 1945/5092] Fix typo in a comment. --- src/shims/foreign_items/posix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 5bb556aaa50b..9e85bcc66bb2 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -336,7 +336,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - // Incomplete shims that we "stub out" just to get pre-main initialziation code to work. + // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. | "pthread_attr_init" | "pthread_attr_destroy" From 688cacbdd73427ec5bd86300cc75a07fa89ec310 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 16 Apr 2020 13:32:40 -0700 Subject: [PATCH 1946/5092] Cleanup the implementation of adjust_global_const. --- src/machine.rs | 50 +---------------------- src/threads.rs | 106 +++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 94 insertions(+), 62 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 23d4e37c66d1..a81273960d09 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -14,11 +14,9 @@ use rand::rngs::StdRng; use rustc_ast::attr; use rustc_data_structures::fx::FxHashMap; use rustc_middle::{ - middle::codegen_fn_attrs::CodegenFnAttrFlags, mir, ty::{ self, - Instance, layout::{LayoutCx, LayoutError, TyAndLayout}, TyCtxt, }, @@ -422,53 +420,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx: &InterpCx<'mir, 'tcx, Self>, mut val: mir::interpret::ConstValue<'tcx>, ) -> InterpResult<'tcx, mir::interpret::ConstValue<'tcx>> { - match &mut val { - mir::interpret::ConstValue::Scalar(Scalar::Ptr(ptr)) => { - let alloc_id = ptr.alloc_id; - let alloc = ecx.tcx.alloc_map.lock().get(alloc_id); - let tcx = ecx.tcx; - let is_thread_local = |def_id| { - tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) - }; - match alloc { - Some(GlobalAlloc::Static(def_id)) if is_thread_local(def_id) => { - let new_alloc_id = if let Some(new_alloc_id) = - ecx.get_thread_local_alloc_id(alloc_id) - { - new_alloc_id - } else { - if tcx.is_foreign_item(def_id) { - throw_unsup_format!( - "Foreign thread-local statics are not supported." - ) - } - let instance = Instance::mono(tcx.tcx, def_id); - let gid = GlobalId { instance, promoted: None }; - let raw_const = tcx - .const_eval_raw(ty::ParamEnv::reveal_all().and(gid)) - .map_err(|err| { - // no need to report anything, the const_eval call takes care of that - // for statics - assert!(tcx.is_static(def_id)); - match err { - ErrorHandled::Reported => err_inval!(ReferencedConstant), - ErrorHandled::TooGeneric => err_inval!(TooGeneric), - } - })?; - let id = raw_const.alloc_id; - let mut alloc_map = tcx.alloc_map.lock(); - let allocation = alloc_map.unwrap_memory(id); - let new_alloc_id = alloc_map.create_memory_alloc(allocation); - ecx.set_thread_local_alloc_id(alloc_id, new_alloc_id); - new_alloc_id - }; - ptr.alloc_id = new_alloc_id; - } - _ => {} - } - } - _ => {} - } + ecx.remap_thread_local_alloc_ids(&mut val)?; Ok(val) } diff --git a/src/threads.rs b/src/threads.rs index c623fcae817d..c8348e262696 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -7,7 +7,13 @@ use std::num::NonZeroU32; use log::trace; use rustc_data_structures::fx::FxHashMap; +use rustc_hir::def_id::DefId; use rustc_index::vec::{Idx, IndexVec}; +use rustc_middle::{ + middle::codegen_fn_attrs::CodegenFnAttrFlags, + mir, + ty::{self, Instance}, +}; use crate::*; @@ -124,9 +130,9 @@ pub struct ThreadManager<'mir, 'tcx> { threads: IndexVec>, /// A counter used to generate unique identifiers for blocksets. blockset_counter: u32, - /// A mapping from an allocation id of a thread-local static to an - /// allocation id of a thread specific allocation. - thread_local_alloc_ids: RefCell>, + /// A mapping from a thread-local static to an allocation id of a thread + /// specific allocation. + thread_local_alloc_ids: RefCell>, } impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { @@ -145,19 +151,19 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Check if we have an allocation for the given thread local static for the /// active thread. - pub fn get_thread_local_alloc_id(&self, static_alloc_id: AllocId) -> Option { - self.thread_local_alloc_ids.borrow().get(&(static_alloc_id, self.active_thread)).cloned() + pub fn get_thread_local_alloc_id(&self, def_id: DefId) -> Option { + self.thread_local_alloc_ids.borrow().get(&(def_id, self.active_thread)).cloned() } /// Set the allocation id as the allocation id of the given thread local /// static for the active thread. - pub fn set_thread_local_alloc_id(&self, static_alloc_id: AllocId, new_alloc_id: AllocId) { + pub fn set_thread_local_alloc_id(&self, def_id: DefId, new_alloc_id: AllocId) { assert!( self.thread_local_alloc_ids .borrow_mut() - .insert((static_alloc_id, self.active_thread), new_alloc_id) + .insert((def_id, self.active_thread), new_alloc_id) .is_none(), - "Bug: a thread local initialized twice for the same thread." + "a thread local initialized twice for the same thread" ); } @@ -291,14 +297,88 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn get_thread_local_alloc_id(&self, static_alloc_id: AllocId) -> Option { + /// A workaround for thread-local statics until + /// https://github.com/rust-lang/rust/issues/70685 is fixed: change the + /// thread-local allocation id with a freshly generated allocation id for + /// the currently active thread. + fn remap_thread_local_alloc_ids( + &self, + val: &mut mir::interpret::ConstValue<'tcx>, + ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); - this.machine.threads.get_thread_local_alloc_id(static_alloc_id) + match val { + mir::interpret::ConstValue::Scalar(Scalar::Ptr(ptr)) => { + let alloc_id = ptr.alloc_id; + let alloc = this.tcx.alloc_map.lock().get(alloc_id); + let tcx = this.tcx; + let is_thread_local = |def_id| { + tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) + }; + match alloc { + Some(GlobalAlloc::Static(def_id)) if is_thread_local(def_id) => { + ptr.alloc_id = this.get_or_create_thread_local_alloc_id(def_id)?; + } + _ => {} + } + } + _ => { + // FIXME: Handling only `Scalar` seems to work for now, but at + // least in principle thread-locals could be in any constant, so + // we should also consider other cases. However, once + // https://github.com/rust-lang/rust/issues/70685 gets fixed, + // this code will have to be rewritten anyway. + } + } + Ok(()) } - - fn set_thread_local_alloc_id(&self, static_alloc_id: AllocId, thread_local_alloc_id: AllocId) { + /// Get a thread-specific allocation id for the given thread-local static. + /// If needed, allocate a new one. + /// + /// FIXME: This method should be replaced as soon as + /// https://github.com/rust-lang/rust/issues/70685 gets fixed. + fn get_or_create_thread_local_alloc_id(&self, def_id: DefId) -> InterpResult<'tcx, AllocId> { let this = self.eval_context_ref(); - this.machine.threads.set_thread_local_alloc_id(static_alloc_id, thread_local_alloc_id) + let tcx = this.tcx; + if let Some(new_alloc_id) = this.machine.threads.get_thread_local_alloc_id(def_id) { + // We already have a thread-specific allocation id for this + // thread-local static. + Ok(new_alloc_id) + } else { + // We need to allocate a thread-specific allocation id for this + // thread-local static. + // + // At first, we invoke the `const_eval_raw` query and extract the + // allocation from it. Unfortunately, we have to duplicate the code + // from `Memory::get_global_alloc` that does this. + // + // Then we store the retrieved allocation back into the `alloc_map` + // to get a fresh allocation id, which we can use as a + // thread-specific allocation id for the thread-local static. + if tcx.is_foreign_item(def_id) { + throw_unsup_format!("foreign thread-local statics are not supported"); + } + // Invoke the `const_eval_raw` query. + let instance = Instance::mono(tcx.tcx, def_id); + let gid = GlobalId { instance, promoted: None }; + let raw_const = + tcx.const_eval_raw(ty::ParamEnv::reveal_all().and(gid)).map_err(|err| { + // no need to report anything, the const_eval call takes care of that + // for statics + assert!(tcx.is_static(def_id)); + err + })?; + let id = raw_const.alloc_id; + // Extract the allocation from the query result. + let mut alloc_map = tcx.alloc_map.lock(); + let allocation = alloc_map.unwrap_memory(id); + // Create a new allocation id for the same allocation in this hacky + // way. Internally, `alloc_map` deduplicates allocations, but this + // is fine because Miri will make a copy before a first mutable + // access. + let new_alloc_id = alloc_map.create_memory_alloc(allocation); + this.machine.threads.set_thread_local_alloc_id(def_id, new_alloc_id); + Ok(new_alloc_id) + } } fn create_thread(&mut self) -> InterpResult<'tcx, ThreadId> { From a585dc8289120aa4ee232c1f8317a21eb5ae2c1a Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 16 Apr 2020 13:39:21 -0700 Subject: [PATCH 1947/5092] Add a missing newline. --- src/threads.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/threads.rs b/src/threads.rs index c8348e262696..72584b726557 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -331,6 +331,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(()) } + /// Get a thread-specific allocation id for the given thread-local static. /// If needed, allocate a new one. /// From 44e930559917968d4513e5915f5957f2fe1f3e11 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 16 Apr 2020 13:52:14 -0700 Subject: [PATCH 1948/5092] Rename threads to thread to match the Rust standard library. --- src/lib.rs | 6 +++--- src/shims/mod.rs | 2 +- src/shims/sync.rs | 2 +- src/shims/{threads.rs => thread.rs} | 0 src/{threads.rs => thread.rs} | 0 5 files changed, 5 insertions(+), 5 deletions(-) rename src/shims/{threads.rs => thread.rs} (100%) rename src/{threads.rs => thread.rs} (100%) diff --git a/src/lib.rs b/src/lib.rs index bedacf705ac4..96e6f7d63e69 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,7 +27,7 @@ mod operator; mod range_map; mod shims; mod stacked_borrows; -mod threads; +mod thread; // Make all those symbols available in the same place as our own. pub use rustc_mir::interpret::*; @@ -42,7 +42,7 @@ pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::shims::os_str::EvalContextExt as OsStrEvalContextExt; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as PanicEvalContextExt}; pub use crate::shims::sync::{EvalContextExt as SyncEvalContextExt}; -pub use crate::shims::threads::EvalContextExt as ThreadShimsEvalContextExt; +pub use crate::shims::thread::EvalContextExt as ThreadShimsEvalContextExt; pub use crate::shims::time::EvalContextExt as TimeEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::EvalContextExt as ShimsEvalContextExt; @@ -63,7 +63,7 @@ pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, Stack, Stacks, Tag, }; -pub use crate::threads::{ +pub use crate::thread::{ EvalContextExt as ThreadsEvalContextExt, ThreadId, ThreadManager, ThreadState, }; diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 118058dd32e7..166d1a5456df 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -6,7 +6,7 @@ pub mod intrinsics; pub mod os_str; pub mod panic; pub mod sync; -pub mod threads; +pub mod thread; pub mod time; pub mod tls; diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 76f97aab2391..d8a00156384c 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -2,7 +2,7 @@ use rustc_middle::ty::{layout::TyAndLayout, TyKind, TypeAndMut}; use rustc_target::abi::{LayoutOf, Size}; use crate::stacked_borrows::Tag; -use crate::threads::{BlockSetId, ThreadId}; +use crate::thread::BlockSetId; use crate::*; fn assert_ptr_target_min_size<'mir, 'tcx: 'mir>( diff --git a/src/shims/threads.rs b/src/shims/thread.rs similarity index 100% rename from src/shims/threads.rs rename to src/shims/thread.rs diff --git a/src/threads.rs b/src/thread.rs similarity index 100% rename from src/threads.rs rename to src/thread.rs From d062f63519bfe7e366f0cadfdb15073434558351 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 16 Apr 2020 19:40:02 -0700 Subject: [PATCH 1949/5092] Fix support for MacOS. --- src/eval.rs | 16 ++- src/lib.rs | 2 +- src/shims/foreign_items/posix/macos.rs | 3 +- src/shims/tls.rs | 157 ++++++++++++++----------- src/thread.rs | 49 ++++---- 5 files changed, 131 insertions(+), 96 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 085a53862fd4..ab82c39836b2 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -205,15 +205,25 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> // Perform the main execution. let res: InterpResult<'_, i64> = (|| { // Main loop. - while ecx.schedule()? { - assert!(ecx.step()?, "a terminated thread was scheduled for execution"); + loop { + match ecx.schedule()? { + SchedulingAction::ExecuteStep => { + assert!(ecx.step()?, "a terminated thread was scheduled for execution"); + } + SchedulingAction::ExecuteDtors => { + ecx.run_tls_dtors_for_active_thread()?; + } + SchedulingAction::Stop => { + break; + } + } ecx.process_diagnostics(); } // Read the return code pointer *before* we run TLS destructors, to assert // that it was written to by the time that `start` lang item returned. let return_code = ecx.read_scalar(ret_place.into())?.not_undef()?.to_machine_isize(&ecx)?; // Global destructors. - ecx.run_tls_dtors()?; + ecx.run_windows_tls_dtors()?; Ok(return_code) })(); diff --git a/src/lib.rs b/src/lib.rs index 96e6f7d63e69..beee94b918b5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,7 +64,7 @@ pub use crate::stacked_borrows::{ EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, Stack, Stacks, Tag, }; pub use crate::thread::{ - EvalContextExt as ThreadsEvalContextExt, ThreadId, ThreadManager, ThreadState, + EvalContextExt as ThreadsEvalContextExt, SchedulingAction, ThreadId, ThreadManager, ThreadState, }; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index dd3dba6ec07c..9f65d0f9c47d 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -82,7 +82,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dtor = this.read_scalar(args[0])?.not_undef()?; let dtor = this.memory.get_fn(dtor)?.as_instance()?; let data = this.read_scalar(args[1])?.not_undef()?; - this.machine.tls.set_global_dtor(dtor, data)?; + let active_thread = this.get_active_thread()?; + this.machine.tls.set_global_dtor(active_thread, dtor, data)?; } // Querying system information diff --git a/src/shims/tls.rs b/src/shims/tls.rs index da0c585958a3..6dc3025acd5a 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -2,15 +2,17 @@ use std::collections::BTreeMap; use std::collections::btree_map::Entry; +use std::collections::HashSet; use log::trace; +use rustc_index::vec::Idx; use rustc_middle::ty; use rustc_target::abi::{Size, HasDataLayout}; use crate::{ HelpersEvalContextExt, InterpResult, MPlaceTy, Scalar, StackPopCleanup, Tag, ThreadId, - ThreadState, ThreadsEvalContextExt, + ThreadsEvalContextExt, }; pub type TlsKey = u128; @@ -32,11 +34,11 @@ pub struct TlsData<'tcx> { /// pthreads-style thread-local storage. keys: BTreeMap>, - /// A single global dtor (that's how things work on macOS) with a data argument. - global_dtor: Option<(ty::Instance<'tcx>, Scalar)>, + /// A single global per thread dtor (that's how things work on macOS) with a data argument. + global_dtors: BTreeMap, Scalar)>, /// Whether we are in the "destruct" phase, during which some operations are UB. - dtors_running: bool, + dtors_running: HashSet, } impl<'tcx> Default for TlsData<'tcx> { @@ -44,8 +46,8 @@ impl<'tcx> Default for TlsData<'tcx> { TlsData { next_key: 1, // start with 1 as we must not use 0 on Windows keys: Default::default(), - global_dtor: None, - dtors_running: false, + global_dtors: Default::default(), + dtors_running: Default::default(), } } } @@ -112,16 +114,15 @@ impl<'tcx> TlsData<'tcx> { } } - pub fn set_global_dtor(&mut self, dtor: ty::Instance<'tcx>, data: Scalar) -> InterpResult<'tcx> { - if self.dtors_running { + /// Set global dtor for the given thread. + pub fn set_global_dtor(&mut self, thread: ThreadId, dtor: ty::Instance<'tcx>, data: Scalar) -> InterpResult<'tcx> { + if self.dtors_running.contains(&thread) { // UB, according to libstd docs. throw_ub_format!("setting global destructor while destructors are already running"); } - if self.global_dtor.is_some() { - throw_unsup_format!("setting more than one global destructor is not supported"); + if self.global_dtors.insert(thread, (dtor, data)).is_some() { + throw_unsup_format!("setting more than one global destructor for the same thread is not supported"); } - - self.global_dtor = Some((dtor, data)); Ok(()) } @@ -148,7 +149,7 @@ impl<'tcx> TlsData<'tcx> { &mut self, key: Option, thread_id: ThreadId, - ) -> Option<(ty::Instance<'tcx>, ThreadId, Scalar, TlsKey)> { + ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { use std::collections::Bound::*; let thread_local = &mut self.keys; @@ -161,9 +162,9 @@ impl<'tcx> TlsData<'tcx> { { match data.entry(thread_id) { Entry::Occupied(entry) => { - let (thread_id, data_scalar) = entry.remove_entry(); + let data_scalar = entry.remove(); if let Some(dtor) = dtor { - let ret = Some((*dtor, thread_id, data_scalar, key)); + let ret = Some((*dtor, data_scalar, key)); return ret; } } @@ -176,41 +177,61 @@ impl<'tcx> TlsData<'tcx> { impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// Run TLS destructors for all threads. - fn run_tls_dtors(&mut self) -> InterpResult<'tcx> { + + /// Run TLS destructors for the main thread on Windows. The implementation + /// assumes that we do not support concurrency on Windows yet. + /// + /// Note: on non-Windows OS this function is a no-op. + fn run_windows_tls_dtors(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - assert!(!this.machine.tls.dtors_running, "running TLS dtors twice"); - this.machine.tls.dtors_running = true; - - if this.tcx.sess.target.target.target_os == "windows" { - // Windows has a special magic linker section that is run on certain events. - // Instead of searching for that section and supporting arbitrary hooks in there - // (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. - let thread_callback = this.eval_path_scalar(&["std", "sys", "windows", "thread_local", "p_thread_callback"])?; - let thread_callback = this.memory.get_fn(thread_callback.not_undef()?)?.as_instance()?; - - // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. - let reason = this.eval_path_scalar(&["std", "sys", "windows", "c", "DLL_PROCESS_DETACH"])?; - let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); - this.call_function( - thread_callback, - &[Scalar::null_ptr(this).into(), reason.into(), Scalar::null_ptr(this).into()], - Some(ret_place), - StackPopCleanup::None { cleanup: true }, - )?; - - // step until out of stackframes - this.run()?; - - // Windows doesn't have other destructors. + if this.tcx.sess.target.target.target_os != "windows" { return Ok(()); } + let active_thread = this.get_active_thread()?; + assert_eq!(active_thread.index(), 0, "concurrency on Windows not supported"); + assert!(!this.machine.tls.dtors_running.contains(&active_thread), "running TLS dtors twice"); + this.machine.tls.dtors_running.insert(active_thread); + // Windows has a special magic linker section that is run on certain events. + // Instead of searching for that section and supporting arbitrary hooks in there + // (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. + let thread_callback = this.eval_path_scalar(&["std", "sys", "windows", "thread_local", "p_thread_callback"])?; + let thread_callback = this.memory.get_fn(thread_callback.not_undef()?)?.as_instance()?; + + // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. + let reason = this.eval_path_scalar(&["std", "sys", "windows", "c", "DLL_PROCESS_DETACH"])?; + let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); + this.call_function( + thread_callback, + &[Scalar::null_ptr(this).into(), reason.into(), Scalar::null_ptr(this).into()], + Some(ret_place), + StackPopCleanup::None { cleanup: true }, + )?; + + // step until out of stackframes + this.run()?; + + // Windows doesn't have other destructors. + Ok(()) + } + + /// Run TLS destructors for the active thread. + /// + /// Note: on Windows OS this function is a no-op because we do not support + /// concurrency on Windows yet. + fn run_tls_dtors_for_active_thread(&mut self) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + if this.tcx.sess.target.target.target_os == "windows" { + return Ok(()); + } + let thread_id = this.get_active_thread()?; + assert!(!this.machine.tls.dtors_running.contains(&thread_id), "running TLS dtors twice"); + this.machine.tls.dtors_running.insert(thread_id); // The macOS global dtor runs "before any TLS slots get freed", so do that first. - if let Some((instance, data)) = this.machine.tls.global_dtor { - trace!("Running global dtor {:?} on {:?}", instance, data); + if let Some(&(instance, data)) = this.machine.tls.global_dtors.get(&thread_id) { + trace!("Running global dtor {:?} on {:?} at {:?}", instance, data, thread_id); let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); this.call_function( @@ -224,35 +245,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.run()?; } - // Now run the "keyed" destructors. - for (thread_id, thread_state) in this.get_all_thread_ids_with_states() { - assert!(thread_state == ThreadState::Terminated, - "TLS destructors should be executed after all threads terminated."); - this.set_active_thread(thread_id)?; - let mut dtor = this.machine.tls.fetch_tls_dtor(None, thread_id); - while let Some((instance, thread_id, ptr, key)) = dtor { - trace!("Running TLS dtor {:?} on {:?} at {:?}", instance, ptr, thread_id); - assert!(!this.is_null(ptr).unwrap(), "Data can't be NULL when dtor is called!"); + assert!(this.has_terminated(thread_id)?, "running TLS dtors for non-terminated thread"); + let mut dtor = this.machine.tls.fetch_tls_dtor(None, thread_id); + while let Some((instance, ptr, key)) = dtor { + trace!("Running TLS dtor {:?} on {:?} at {:?}", instance, ptr, thread_id); + assert!(!this.is_null(ptr).unwrap(), "Data can't be NULL when dtor is called!"); - let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); - this.call_function( - instance, - &[ptr.into()], - Some(ret_place), - StackPopCleanup::None { cleanup: true }, - )?; + let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); + this.call_function( + instance, + &[ptr.into()], + Some(ret_place), + StackPopCleanup::None { cleanup: true }, + )?; - // step until out of stackframes - this.run()?; + // step until out of stackframes + this.run()?; - // Fetch next dtor after `key`. - dtor = match this.machine.tls.fetch_tls_dtor(Some(key), thread_id) { - dtor @ Some(_) => dtor, - // We ran each dtor once, start over from the beginning. - None => this.machine.tls.fetch_tls_dtor(None, thread_id), - }; - } + // Fetch next dtor after `key`. + dtor = match this.machine.tls.fetch_tls_dtor(Some(key), thread_id) { + dtor @ Some(_) => dtor, + // We ran each dtor once, start over from the beginning. + None => this.machine.tls.fetch_tls_dtor(None, thread_id), + }; } + Ok(()) } } diff --git a/src/thread.rs b/src/thread.rs index 72584b726557..d40b2a176e73 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -17,6 +17,16 @@ use rustc_middle::{ use crate::*; +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum SchedulingAction { + /// Execute step on the active thread. + ExecuteStep, + /// Execute destructors of the active thread. + ExecuteDtors, + /// Stop the program. + Stop, +} + /// A thread identifier. #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] pub struct ThreadId(usize); @@ -197,6 +207,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { self.active_thread } + /// Has the given thread terminated? + fn has_terminated(&self, thread_id: ThreadId) -> bool { + self.threads[thread_id].state == ThreadState::Terminated + } + /// Get the borrow of the currently active thread. fn active_thread_mut(&mut self) -> &mut Thread<'mir, 'tcx> { &mut self.threads[self.active_thread] @@ -234,11 +249,6 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { self.active_thread_mut().thread_name = Some(new_thread_name); } - /// Get ids and states of all threads ever allocated. - fn get_all_thread_ids_with_states(&self) -> Vec<(ThreadId, ThreadState)> { - self.threads.iter_enumerated().map(|(id, thread)| (id, thread.state)).collect() - } - /// Allocate a new blockset id. fn create_blockset(&mut self) -> BlockSetId { self.blockset_counter = self.blockset_counter.checked_add(1).unwrap(); @@ -265,10 +275,8 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { None } - /// Decide which thread to run next. - /// - /// Returns `false` if all threads terminated. - fn schedule(&mut self) -> InterpResult<'tcx, bool> { + /// Decide which action to take next and on which thread. + fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { if self.threads[self.active_thread].check_terminated() { // Check if we need to unblock any threads. for (i, thread) in self.threads.iter_enumerated_mut() { @@ -277,18 +285,19 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { thread.state = ThreadState::Enabled; } } + return Ok(SchedulingAction::ExecuteDtors); } if self.threads[self.active_thread].state == ThreadState::Enabled { - return Ok(true); + return Ok(SchedulingAction::ExecuteStep); } if let Some(enabled_thread) = self.threads.iter().position(|thread| thread.state == ThreadState::Enabled) { self.active_thread = ThreadId::new(enabled_thread); - return Ok(true); + return Ok(SchedulingAction::ExecuteStep); } if self.threads.iter().all(|thread| thread.state == ThreadState::Terminated) { - Ok(false) + Ok(SchedulingAction::Stop) } else { throw_machine_stop!(TerminationInfo::Deadlock); } @@ -409,6 +418,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(this.machine.threads.get_active_thread_id()) } + fn has_terminated(&self, thread_id: ThreadId) -> InterpResult<'tcx, bool> { + let this = self.eval_context_ref(); + Ok(this.machine.threads.has_terminated(thread_id)) + } + fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] { let this = self.eval_context_ref(); this.machine.threads.active_thread_stack() @@ -424,11 +438,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(this.machine.threads.set_thread_name(new_thread_name)) } - fn get_all_thread_ids_with_states(&mut self) -> Vec<(ThreadId, ThreadState)> { - let this = self.eval_context_mut(); - this.machine.threads.get_all_thread_ids_with_states() - } - fn create_blockset(&mut self) -> InterpResult<'tcx, BlockSetId> { let this = self.eval_context_mut(); Ok(this.machine.threads.create_blockset()) @@ -444,10 +453,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(this.machine.threads.unblock_random_thread(set)) } - /// Decide which thread to run next. - /// - /// Returns `false` if all threads terminated. - fn schedule(&mut self) -> InterpResult<'tcx, bool> { + /// Decide which action to take next and on which thread. + fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { let this = self.eval_context_mut(); this.machine.threads.schedule() } From 134533d066a4ab57d1a3e7ed9590052db313b5e6 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Fri, 17 Apr 2020 15:38:23 -0700 Subject: [PATCH 1950/5092] Add a comment explaining global destructors on MacOS. --- src/shims/tls.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 6dc3025acd5a..722b24d74752 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -114,8 +114,21 @@ impl<'tcx> TlsData<'tcx> { } } - /// Set global dtor for the given thread. - pub fn set_global_dtor(&mut self, thread: ThreadId, dtor: ty::Instance<'tcx>, data: Scalar) -> InterpResult<'tcx> { + /// Set global dtor for the given thread. This function is used to implement + /// `_tlv_atexit` shim on MacOS. + /// + /// Global destructors are available only on MacOS and (potentially + /// confusingly) they seem to be still per thread as can be guessed from the + /// following comment in the [`_tlv_atexit` + /// implementation](https://github.com/opensource-apple/dyld/blob/195030646877261f0c8c7ad8b001f52d6a26f514/src/threadLocalVariables.c#L389): + /// + /// // NOTE: this does not need locks because it only operates on current thread data + pub fn set_global_dtor( + &mut self, + thread: ThreadId, + dtor: ty::Instance<'tcx>, + data: Scalar + ) -> InterpResult<'tcx> { if self.dtors_running.contains(&thread) { // UB, according to libstd docs. throw_ub_format!("setting global destructor while destructors are already running"); From 46fd333daa8dc71f1c61aa87ecbf9881fae920c6 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sat, 18 Apr 2020 15:39:53 -0700 Subject: [PATCH 1951/5092] Implement thread::yield_now. --- src/shims/foreign_items/posix.rs | 5 +++++ src/shims/thread.rs | 8 ++++++++ src/thread.rs | 32 +++++++++++++++++++++++++++----- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 9e85bcc66bb2..4574d203efb7 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -318,6 +318,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.prctl(args[0], args[1], args[2], args[3], args[4])?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "sched_yield" => { + assert_eq!(args.len(), 0); + let result = this.sched_yield()?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } // Miscellaneous "isatty" => { diff --git a/src/shims/thread.rs b/src/shims/thread.rs index d8ba11d267f3..ccdf6df3f9d6 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -111,4 +111,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } + + fn sched_yield(&mut self) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.yield_active_thread()?; + + Ok(0) + } } diff --git a/src/thread.rs b/src/thread.rs index d40b2a176e73..31296ad96ff0 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -143,6 +143,8 @@ pub struct ThreadManager<'mir, 'tcx> { /// A mapping from a thread-local static to an allocation id of a thread /// specific allocation. thread_local_alloc_ids: RefCell>, + /// A flag that indicates that we should change the active thread. + yield_active_thread: bool, } impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { @@ -154,6 +156,7 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { threads: threads, blockset_counter: 0, thread_local_alloc_ids: Default::default(), + yield_active_thread: false, } } } @@ -275,6 +278,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { None } + /// Change the active thread to some enabled thread. + fn yield_active_thread(&mut self) { + self.yield_active_thread = true; + } + /// Decide which action to take next and on which thread. fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { if self.threads[self.active_thread].check_terminated() { @@ -287,13 +295,21 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } return Ok(SchedulingAction::ExecuteDtors); } - if self.threads[self.active_thread].state == ThreadState::Enabled { + if self.threads[self.active_thread].state == ThreadState::Enabled + && !self.yield_active_thread + { return Ok(SchedulingAction::ExecuteStep); } - if let Some(enabled_thread) = - self.threads.iter().position(|thread| thread.state == ThreadState::Enabled) - { - self.active_thread = ThreadId::new(enabled_thread); + for (id, thread) in self.threads.iter_enumerated() { + if thread.state == ThreadState::Enabled { + if !(self.yield_active_thread && id == self.active_thread) { + self.active_thread = id; + break; + } + } + } + self.yield_active_thread = false; + if self.threads[self.active_thread].state == ThreadState::Enabled { return Ok(SchedulingAction::ExecuteStep); } if self.threads.iter().all(|thread| thread.state == ThreadState::Terminated) { @@ -453,6 +469,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(this.machine.threads.unblock_random_thread(set)) } + fn yield_active_thread(&mut self) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + this.machine.threads.yield_active_thread(); + Ok(()) + } + /// Decide which action to take next and on which thread. fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { let this = self.eval_context_mut(); From 421be273cc389a5d426063f71cba82bf1c364f00 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sat, 18 Apr 2020 12:25:11 -0700 Subject: [PATCH 1952/5092] Add concurrency tests. --- src/shims/sync.rs | 1 + src/shims/tls.rs | 2 + src/thread.rs | 4 +- .../concurrency/dangling_tls_lib.rs | 46 ++++++++++++++++ .../libc_pthread_mutex_deadlock.rs | 32 ++++++++++++ .../libc_pthread_mutex_wrong_owner.rs | 32 ++++++++++++ ...libc_pthread_rwlock_write_read_deadlock.rs | 32 ++++++++++++ ...ibc_pthread_rwlock_write_write_deadlock.rs | 32 ++++++++++++ tests/run-pass/concurrency/locks.rs | 52 +++++++++++++++++-- 9 files changed, 227 insertions(+), 6 deletions(-) create mode 100644 tests/compile-fail/concurrency/dangling_tls_lib.rs create mode 100644 tests/compile-fail/concurrency/libc_pthread_mutex_deadlock.rs create mode 100644 tests/compile-fail/concurrency/libc_pthread_mutex_wrong_owner.rs create mode 100644 tests/compile-fail/concurrency/libc_pthread_rwlock_write_read_deadlock.rs create mode 100644 tests/compile-fail/concurrency/libc_pthread_rwlock_write_write_deadlock.rs diff --git a/src/shims/sync.rs b/src/shims/sync.rs index d8a00156384c..6a1ea108dbb0 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -532,6 +532,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + // FIXME: We should check that this lock was locked by the active thread. fn pthread_rwlock_unlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 722b24d74752..89ec16596599 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -233,6 +233,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// /// Note: on Windows OS this function is a no-op because we do not support /// concurrency on Windows yet. + /// + /// FIXME: we do not support yet deallocation of thread local statics. fn run_tls_dtors_for_active_thread(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if this.tcx.sess.target.target.target_os == "windows" { diff --git a/src/thread.rs b/src/thread.rs index 31296ad96ff0..ab6a4c94db83 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -164,13 +164,13 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Check if we have an allocation for the given thread local static for the /// active thread. - pub fn get_thread_local_alloc_id(&self, def_id: DefId) -> Option { + fn get_thread_local_alloc_id(&self, def_id: DefId) -> Option { self.thread_local_alloc_ids.borrow().get(&(def_id, self.active_thread)).cloned() } /// Set the allocation id as the allocation id of the given thread local /// static for the active thread. - pub fn set_thread_local_alloc_id(&self, def_id: DefId, new_alloc_id: AllocId) { + fn set_thread_local_alloc_id(&self, def_id: DefId, new_alloc_id: AllocId) { assert!( self.thread_local_alloc_ids .borrow_mut() diff --git a/tests/compile-fail/concurrency/dangling_tls_lib.rs b/tests/compile-fail/concurrency/dangling_tls_lib.rs new file mode 100644 index 000000000000..ad12c107bffb --- /dev/null +++ b/tests/compile-fail/concurrency/dangling_tls_lib.rs @@ -0,0 +1,46 @@ +// ignore-windows + +#![feature(thread_local_internals)] + +use std::cell::RefCell; +use std::thread; + +static A: std::thread::LocalKey> = { + #[inline] + fn __init() -> RefCell { + RefCell::new(0) + } + + unsafe fn __getit() -> Option<&'static RefCell> { + static __KEY: std::thread::__OsLocalKeyInner> = + std::thread::__OsLocalKeyInner::new(); + __KEY.get(__init) + } + + unsafe { std::thread::LocalKey::new(__getit) } +}; + +struct Sender(*mut u8); + +unsafe impl Send for Sender {} + +fn main() { + A.with(|f| { + assert_eq!(*f.borrow(), 0); + *f.borrow_mut() = 4; + }); + + let handle = thread::spawn(|| { + let ptr = A.with(|f| { + assert_eq!(*f.borrow(), 0); + *f.borrow_mut() = 5; + &mut *f.borrow_mut() as *mut u8 + }); + Sender(ptr) + }); + let ptr = handle.join().unwrap().0; + A.with(|f| { + assert_eq!(*f.borrow(), 4); + }); + let _x = unsafe { *ptr }; //~ ERROR Undefined Behavior +} diff --git a/tests/compile-fail/concurrency/libc_pthread_mutex_deadlock.rs b/tests/compile-fail/concurrency/libc_pthread_mutex_deadlock.rs new file mode 100644 index 000000000000..5d04635a36c8 --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_mutex_deadlock.rs @@ -0,0 +1,32 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +use std::cell::UnsafeCell; +use std::sync::Arc; +use std::thread; + +struct Mutex(UnsafeCell); + +unsafe impl Send for Mutex {} +unsafe impl Sync for Mutex {} + +fn new_lock() -> Arc { + Arc::new(Mutex(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER))) +} + +fn main() { + unsafe { + let lock = new_lock(); + assert_eq!(libc::pthread_mutex_lock(lock.0.get() as *mut _), 0); + + let lock_copy = lock.clone(); + thread::spawn(move || { + assert_eq!(libc::pthread_mutex_lock(lock_copy.0.get() as *mut _), 0); //~ ERROR: deadlock + }) + .join() + .unwrap(); + } +} diff --git a/tests/compile-fail/concurrency/libc_pthread_mutex_wrong_owner.rs b/tests/compile-fail/concurrency/libc_pthread_mutex_wrong_owner.rs new file mode 100644 index 000000000000..3009721abe2e --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_mutex_wrong_owner.rs @@ -0,0 +1,32 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +use std::cell::UnsafeCell; +use std::sync::Arc; +use std::thread; + +struct Mutex(UnsafeCell); + +unsafe impl Send for Mutex {} +unsafe impl Sync for Mutex {} + +fn new_lock() -> Arc { + Arc::new(Mutex(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER))) +} + +fn main() { + unsafe { + let lock = new_lock(); + assert_eq!(libc::pthread_mutex_lock(lock.0.get() as *mut _), 0); + + let lock_copy = lock.clone(); + thread::spawn(move || { + assert_eq!(libc::pthread_mutex_unlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: Undefined Behavior: called pthread_mutex_unlock on a mutex owned by another thread + }) + .join() + .unwrap(); + } +} diff --git a/tests/compile-fail/concurrency/libc_pthread_rwlock_write_read_deadlock.rs b/tests/compile-fail/concurrency/libc_pthread_rwlock_write_read_deadlock.rs new file mode 100644 index 000000000000..19dce431c8b1 --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_rwlock_write_read_deadlock.rs @@ -0,0 +1,32 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +use std::cell::UnsafeCell; +use std::sync::Arc; +use std::thread; + +struct RwLock(UnsafeCell); + +unsafe impl Send for RwLock {} +unsafe impl Sync for RwLock {} + +fn new_lock() -> Arc { + Arc::new(RwLock(UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER))) +} + +fn main() { + unsafe { + let lock = new_lock(); + assert_eq!(libc::pthread_rwlock_rdlock(lock.0.get() as *mut _), 0); + + let lock_copy = lock.clone(); + thread::spawn(move || { + assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: deadlock + }) + .join() + .unwrap(); + } +} diff --git a/tests/compile-fail/concurrency/libc_pthread_rwlock_write_write_deadlock.rs b/tests/compile-fail/concurrency/libc_pthread_rwlock_write_write_deadlock.rs new file mode 100644 index 000000000000..098c1c2fe26c --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_rwlock_write_write_deadlock.rs @@ -0,0 +1,32 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +use std::cell::UnsafeCell; +use std::sync::Arc; +use std::thread; + +struct RwLock(UnsafeCell); + +unsafe impl Send for RwLock {} +unsafe impl Sync for RwLock {} + +fn new_lock() -> Arc { + Arc::new(RwLock(UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER))) +} + +fn main() { + unsafe { + let lock = new_lock(); + assert_eq!(libc::pthread_rwlock_wrlock(lock.0.get() as *mut _), 0); + + let lock_copy = lock.clone(); + thread::spawn(move || { + assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: deadlock + }) + .join() + .unwrap(); + } +} diff --git a/tests/run-pass/concurrency/locks.rs b/tests/run-pass/concurrency/locks.rs index 3c8373691b84..90c10b8ffe24 100644 --- a/tests/run-pass/concurrency/locks.rs +++ b/tests/run-pass/concurrency/locks.rs @@ -1,11 +1,9 @@ // ignore-windows -//! This test just calls the relevant APIs to check if Miri crashes. - -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, Mutex, RwLock}; use std::thread; -fn main() { +fn check_mutex() { let data = Arc::new(Mutex::new(0)); let mut threads = Vec::new(); @@ -27,3 +25,49 @@ fn main() { let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap(); assert_eq!(data, 3); } + +fn check_rwlock_write() { + let data = Arc::new(RwLock::new(0)); + let mut threads = Vec::new(); + + for _ in 0..3 { + let data = Arc::clone(&data); + let thread = thread::spawn(move || { + let mut data = data.write().unwrap(); + *data += 1; + }); + threads.push(thread); + } + + for thread in threads { + thread.join().unwrap(); + } + + assert!(data.try_write().is_ok()); + + let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap(); + assert_eq!(data, 3); +} + +fn check_rwlock_read_no_deadlock() { + let l1 = Arc::new(RwLock::new(0)); + let l2 = Arc::new(RwLock::new(0)); + + let l1_copy = Arc::clone(&l1); + let l2_copy = Arc::clone(&l2); + let _guard1 = l1.read().unwrap(); + let handle = thread::spawn(move || { + let _guard2 = l2_copy.read().unwrap(); + thread::yield_now(); + let _guard1 = l1_copy.read().unwrap(); + }); + thread::yield_now(); + let _guard2 = l2.read().unwrap(); + handle.join().unwrap(); +} + +fn main() { + check_mutex(); + check_rwlock_write(); + check_rwlock_read_no_deadlock(); +} From c84b2890adb6b67712c6cff565eed2521dc9ba65 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 19 Apr 2020 12:22:33 -0700 Subject: [PATCH 1953/5092] Update a comment in README about what concurrency checks we support. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fb981a71f0e4..cf50049daedf 100644 --- a/README.md +++ b/README.md @@ -48,8 +48,8 @@ in your program, and cannot run all programs: has no access to most platform-specific APIs or FFI. A few APIs have been implemented (such as printing to stdout) but most have not: for example, Miri currently does not support SIMD or networking. -* Miri currently does not check for data-races and other concurrency related - issues. +* Miri currently does not check for data-races and most other concurrency + related issues. [rust]: https://www.rust-lang.org/ [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md From d6c03926ab8aff457a3e9b607bdcca654bfe17fe Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 19 Apr 2020 12:24:46 -0700 Subject: [PATCH 1954/5092] Rename MacOS set global dtor function. --- src/shims/foreign_items/posix/macos.rs | 2 +- src/shims/tls.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 9f65d0f9c47d..9f6ea00b0313 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -83,7 +83,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dtor = this.memory.get_fn(dtor)?.as_instance()?; let data = this.read_scalar(args[1])?.not_undef()?; let active_thread = this.get_active_thread()?; - this.machine.tls.set_global_dtor(active_thread, dtor, data)?; + this.machine.tls.set_thread_global_dtor(active_thread, dtor, data)?; } // Querying system information diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 89ec16596599..c08ec78c136d 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -123,7 +123,7 @@ impl<'tcx> TlsData<'tcx> { /// implementation](https://github.com/opensource-apple/dyld/blob/195030646877261f0c8c7ad8b001f52d6a26f514/src/threadLocalVariables.c#L389): /// /// // NOTE: this does not need locks because it only operates on current thread data - pub fn set_global_dtor( + pub fn set_thread_global_dtor( &mut self, thread: ThreadId, dtor: ty::Instance<'tcx>, From 69df2e19de4bf49df6e250cd367c553737dd6d0c Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 19 Apr 2020 14:01:12 -0700 Subject: [PATCH 1955/5092] Move prctl to Linux specific shims. --- src/shims/foreign_items/posix.rs | 5 ----- src/shims/foreign_items/posix/linux.rs | 7 +++++++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 4574d203efb7..6e2a7a9fcb4f 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -313,11 +313,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert_eq!(args.len(), 0); this.pthread_self(dest)?; } - "prctl" => { - assert_eq!(args.len(), 5); - let result = this.prctl(args[0], args[1], args[2], args[3], args[4])?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } "sched_yield" => { assert_eq!(args.len(), 0); let result = this.sched_yield()?; diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index a32f0fa60678..eb58f7466089 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -75,6 +75,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } + // Threading + "prctl" => { + assert_eq!(args.len(), 5); + let result = this.prctl(args[0], args[1], args[2], args[3], args[4])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + // Dynamically invoked syscalls "syscall" => { let sys_getrandom = this From eab38dfe00d99bca183b7744823f8614d04e5304 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 19 Apr 2020 14:01:56 -0700 Subject: [PATCH 1956/5092] Change the warning message. --- src/shims/thread.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/thread.rs b/src/shims/thread.rs index ccdf6df3f9d6..077da0b1a19d 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -14,7 +14,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.tcx.sess.warn( - "The thread support is experimental. \ + "thread support is experimental. \ For example, Miri does not detect data races yet.", ); From 75e6549c119cd0d30f764c3d8c2a742c63bc495f Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 19 Apr 2020 14:18:30 -0700 Subject: [PATCH 1957/5092] Improve prctl, add a test. --- src/shims/thread.rs | 15 ++++++++++----- .../concurrency/libc_prctl_thread_name.rs | 17 +++++++++++++++++ 2 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 tests/run-pass/concurrency/libc_prctl_thread_name.rs diff --git a/src/shims/thread.rs b/src/shims/thread.rs index 077da0b1a19d..ab3b436b8665 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -102,12 +102,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let option = this.read_scalar(option)?.not_undef()?.to_i32()?; - if option != this.eval_libc_i32("PR_SET_NAME")? { - throw_unsup_format!("Miri supports only PR_SET_NAME"); + if option == this.eval_libc_i32("PR_SET_NAME")? { + let address = this.read_scalar(arg2)?.not_undef()?; + let name = this.memory.read_c_str(address)?.to_owned(); + this.set_active_thread_name(name)?; + } else if option == this.eval_libc_i32("PR_GET_NAME")? { + let address = this.read_scalar(arg2)?.not_undef()?; + let name = this.get_active_thread_name()?; + this.memory.write_bytes(address, name)?; + } else { + throw_unsup_format!("Unsupported prctl option."); } - let address = this.read_scalar(arg2)?.not_undef()?; - let name = this.memory.read_c_str(address)?.to_owned(); - this.set_active_thread_name(name)?; Ok(0) } diff --git a/tests/run-pass/concurrency/libc_prctl_thread_name.rs b/tests/run-pass/concurrency/libc_prctl_thread_name.rs new file mode 100644 index 000000000000..235ac27e0a59 --- /dev/null +++ b/tests/run-pass/concurrency/libc_prctl_thread_name.rs @@ -0,0 +1,17 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +use std::ffi::CString; + +fn main() { + unsafe { + let thread_name = CString::new("hello").expect("CString::new failed"); + assert_eq!(libc::prctl(libc::PR_SET_NAME, thread_name.as_ptr() as u64, 0, 0, 0), 0); + let mut buf = [0; 6]; + assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr() as u64, 0, 0, 0), 0); + assert_eq!(thread_name.as_bytes_with_nul(), buf); + } +} From 94cbe88e8073381dbf7aeed2f0cf720b08f05785 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 19 Apr 2020 14:21:18 -0700 Subject: [PATCH 1958/5092] Many small changes to thread management. --- src/shims/sync.rs | 8 ++-- src/thread.rs | 112 ++++++++++++++++++++++++++++++++++------------ 2 files changed, 87 insertions(+), 33 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 6a1ea108dbb0..97afbbe98f6a 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -419,7 +419,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_ub_format!("called pthread_mutex_unlock on a mutex owned by another thread"); } else if locked_count == 1 { let blockset = mutex_get_or_create_blockset(this, mutex_op)?; - if let Some(new_owner) = this.unblock_random_thread(blockset)? { + if let Some(new_owner) = this.unblock_some_thread(blockset)? { // We have at least one thread waiting on this mutex. Transfer // ownership to it. mutex_set_owner(this, mutex_op, new_owner.to_u32_scalar())?; @@ -543,7 +543,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert_eq!(writers, 0); rwlock_set_readers(this, rwlock_op, Scalar::from_u32(new_readers))?; if new_readers == 0 { - if let Some(_writer) = this.unblock_random_thread(writer_blockset)? { + if let Some(_writer) = this.unblock_some_thread(writer_blockset)? { rwlock_set_writers(this, rwlock_op, Scalar::from_u32(1))?; } } @@ -551,11 +551,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if writers != 0 { let reader_blockset = rwlock_get_or_create_reader_blockset(this, rwlock_op)?; rwlock_set_writers(this, rwlock_op, Scalar::from_u32(0))?; - if let Some(_writer) = this.unblock_random_thread(writer_blockset)? { + if let Some(_writer) = this.unblock_some_thread(writer_blockset)? { rwlock_set_writers(this, rwlock_op, Scalar::from_u32(1))?; } else { let mut readers = 0; - while let Some(_reader) = this.unblock_random_thread(reader_blockset)? { + while let Some(_reader) = this.unblock_some_thread(reader_blockset)? { readers += 1; } rwlock_set_readers(this, rwlock_op, Scalar::from_u32(readers))? diff --git a/src/thread.rs b/src/thread.rs index ab6a4c94db83..5eb6560a09e6 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -31,6 +31,9 @@ pub enum SchedulingAction { #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] pub struct ThreadId(usize); +/// The main thread. When it terminates, the whole application terminates. +const MAIN_THREAD: ThreadId = ThreadId(0); + impl Idx for ThreadId { fn new(idx: usize) -> Self { ThreadId(idx) @@ -42,13 +45,13 @@ impl Idx for ThreadId { impl From for ThreadId { fn from(id: u64) -> Self { - Self(id as usize) + Self(usize::try_from(id).unwrap()) } } impl From for ThreadId { fn from(id: u32) -> Self { - Self(id as usize) + Self(usize::try_from(id).unwrap()) } } @@ -82,10 +85,10 @@ pub enum ThreadState { /// The thread tried to join the specified thread and is blocked until that /// thread terminates. BlockedOnJoin(ThreadId), - /// The thread is blocked and belongs to the given blockset.. + /// The thread is blocked and belongs to the given blockset. Blocked(BlockSetId), /// The thread has terminated its execution (we do not delete terminated - /// threads.) + /// threads). Terminated, } @@ -150,6 +153,7 @@ pub struct ThreadManager<'mir, 'tcx> { impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { fn default() -> Self { let mut threads = IndexVec::new(); + // Create the main thread and add it to the list of threads. threads.push(Default::default()); Self { active_thread: ThreadId::new(0), @@ -170,14 +174,13 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Set the allocation id as the allocation id of the given thread local /// static for the active thread. + /// + /// Panics if a thread local is initialized twice for the same thread. fn set_thread_local_alloc_id(&self, def_id: DefId, new_alloc_id: AllocId) { - assert!( - self.thread_local_alloc_ids - .borrow_mut() - .insert((def_id, self.active_thread), new_alloc_id) - .is_none(), - "a thread local initialized twice for the same thread" - ); + self.thread_local_alloc_ids + .borrow_mut() + .insert((def_id, self.active_thread), new_alloc_id) + .unwrap_none(); } /// Borrow the stack of the active thread. @@ -227,15 +230,20 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Mark that the active thread tries to join the thread with `joined_thread_id`. - fn join_thread(&mut self, joined_thread_id: ThreadId) { - assert!(!self.threads[joined_thread_id].detached, "Bug: trying to join a detached thread."); - assert_ne!(joined_thread_id, self.active_thread, "Bug: trying to join itself"); - assert!( - self.threads - .iter() - .all(|thread| thread.state != ThreadState::BlockedOnJoin(joined_thread_id)), - "Bug: multiple threads try to join the same thread." - ); + fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> { + if self.threads[joined_thread_id].detached { + throw_ub_format!("trying to join a detached thread"); + } + if joined_thread_id == self.active_thread { + throw_ub_format!("trying to join itself"); + } + if self + .threads + .iter() + .any(|thread| thread.state == ThreadState::BlockedOnJoin(joined_thread_id)) + { + throw_ub_format!("multiple threads try to join the same thread"); + } if self.threads[joined_thread_id].state != ThreadState::Terminated { // The joined thread is still running, we need to wait for it. self.active_thread_mut().state = ThreadState::BlockedOnJoin(joined_thread_id); @@ -245,6 +253,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { joined_thread_id ); } + Ok(()) } /// Set the name of the active thread. @@ -252,6 +261,15 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { self.active_thread_mut().thread_name = Some(new_thread_name); } + /// Get the name of the active thread. + fn get_thread_name(&mut self) -> InterpResult<'tcx, Vec> { + if let Some(ref thread_name) = self.active_thread_mut().thread_name { + Ok(thread_name.clone()) + } else { + throw_ub_format!("thread {:?} has no name set", self.active_thread) + } + } + /// Allocate a new blockset id. fn create_blockset(&mut self) -> BlockSetId { self.blockset_counter = self.blockset_counter.checked_add(1).unwrap(); @@ -267,7 +285,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Unblock any one thread from the given blockset if it contains at least /// one. Return the id of the unblocked thread. - fn unblock_random_thread(&mut self, set: BlockSetId) -> Option { + fn unblock_some_thread(&mut self, set: BlockSetId) -> Option { for (id, thread) in self.threads.iter_enumerated_mut() { if thread.state == ThreadState::Blocked(set) { trace!("unblocking {:?} in blockset {:?}", id, set); @@ -284,6 +302,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Decide which action to take next and on which thread. + /// + /// The currently implemented scheduling policy is the one that is commonly + /// used in stateless model checkers such as Loom: run the active thread as + /// long as we can and switch only when we have to (the active thread was + /// blocked, terminated, or was explicitly asked to be preempted). fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { if self.threads[self.active_thread].check_terminated() { // Check if we need to unblock any threads. @@ -295,14 +318,24 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } return Ok(SchedulingAction::ExecuteDtors); } + if self.threads[MAIN_THREAD].state == ThreadState::Terminated { + // The main thread terminated; stop the program. + if self.threads.iter().any(|thread| thread.state != ThreadState::Terminated) { + // FIXME: This check should be either configurable or just emit a warning. + throw_unsup_format!("the main thread terminated without waiting for other threads"); + } + return Ok(SchedulingAction::Stop); + } if self.threads[self.active_thread].state == ThreadState::Enabled && !self.yield_active_thread { + // The currently active thread is still enabled, just continue with it. return Ok(SchedulingAction::ExecuteStep); } + // We need to pick a new thread for execution. for (id, thread) in self.threads.iter_enumerated() { if thread.state == ThreadState::Enabled { - if !(self.yield_active_thread && id == self.active_thread) { + if !self.yield_active_thread || id != self.active_thread { self.active_thread = id; break; } @@ -312,14 +345,16 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { if self.threads[self.active_thread].state == ThreadState::Enabled { return Ok(SchedulingAction::ExecuteStep); } + // We have not found a thread to execute. if self.threads.iter().all(|thread| thread.state == ThreadState::Terminated) { - Ok(SchedulingAction::Stop) + unreachable!(); } else { throw_machine_stop!(TerminationInfo::Deadlock); } } } +// Public interface to thread management. impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// A workaround for thread-local statics until @@ -331,8 +366,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx val: &mut mir::interpret::ConstValue<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); - match val { - mir::interpret::ConstValue::Scalar(Scalar::Ptr(ptr)) => { + match *val { + mir::interpret::ConstValue::Scalar(Scalar::Ptr(ref mut ptr)) => { let alloc_id = ptr.alloc_id; let alloc = this.tcx.alloc_map.lock().get(alloc_id); let tcx = this.tcx; @@ -407,68 +442,86 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + #[inline] fn create_thread(&mut self) -> InterpResult<'tcx, ThreadId> { let this = self.eval_context_mut(); Ok(this.machine.threads.create_thread()) } + #[inline] fn detach_thread(&mut self, thread_id: ThreadId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.machine.threads.detach_thread(thread_id); Ok(()) } + #[inline] fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.machine.threads.join_thread(joined_thread_id); - Ok(()) + this.machine.threads.join_thread(joined_thread_id) } + #[inline] fn set_active_thread(&mut self, thread_id: ThreadId) -> InterpResult<'tcx, ThreadId> { let this = self.eval_context_mut(); Ok(this.machine.threads.set_active_thread_id(thread_id)) } + #[inline] fn get_active_thread(&self) -> InterpResult<'tcx, ThreadId> { let this = self.eval_context_ref(); Ok(this.machine.threads.get_active_thread_id()) } + #[inline] fn has_terminated(&self, thread_id: ThreadId) -> InterpResult<'tcx, bool> { let this = self.eval_context_ref(); Ok(this.machine.threads.has_terminated(thread_id)) } + #[inline] fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] { let this = self.eval_context_ref(); this.machine.threads.active_thread_stack() } + #[inline] fn active_thread_stack_mut(&mut self) -> &mut Vec>> { let this = self.eval_context_mut(); this.machine.threads.active_thread_stack_mut() } + #[inline] fn set_active_thread_name(&mut self, new_thread_name: Vec) -> InterpResult<'tcx, ()> { let this = self.eval_context_mut(); Ok(this.machine.threads.set_thread_name(new_thread_name)) } + #[inline] + fn get_active_thread_name(&mut self) -> InterpResult<'tcx, Vec> { + let this = self.eval_context_mut(); + this.machine.threads.get_thread_name() + } + + #[inline] fn create_blockset(&mut self) -> InterpResult<'tcx, BlockSetId> { let this = self.eval_context_mut(); Ok(this.machine.threads.create_blockset()) } + #[inline] fn block_active_thread(&mut self, set: BlockSetId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); Ok(this.machine.threads.block_active_thread(set)) } - fn unblock_random_thread(&mut self, set: BlockSetId) -> InterpResult<'tcx, Option> { + #[inline] + fn unblock_some_thread(&mut self, set: BlockSetId) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); - Ok(this.machine.threads.unblock_random_thread(set)) + Ok(this.machine.threads.unblock_some_thread(set)) } + #[inline] fn yield_active_thread(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.machine.threads.yield_active_thread(); @@ -476,6 +529,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Decide which action to take next and on which thread. + #[inline] fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { let this = self.eval_context_mut(); this.machine.threads.schedule() From 80459bbf774f6238936837ace61fa6c1c95051ec Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 19 Apr 2020 14:22:55 -0700 Subject: [PATCH 1959/5092] Improve concurrency tests. --- .../concurrency/dangling_tls_lib.rs | 2 +- ...libc_pthread_rwlock_write_read_deadlock.rs | 32 ------------------- ...ibc_pthread_rwlock_write_write_deadlock.rs | 32 ------------------- .../{ => concurrency}/thread-spawn.rs | 5 +-- .../libc_pthread_mutex_deadlock.rs | 0 .../libc_pthread_mutex_wrong_owner.rs | 0 ...libc_pthread_rwlock_write_read_deadlock.rs | 25 +++++++++++++-- ...wlock_write_read_deadlock_single_thread.rs | 13 ++++++++ ...ibc_pthread_rwlock_write_write_deadlock.rs | 25 +++++++++++++-- ...lock_write_write_deadlock_single_thread.rs | 13 ++++++++ tests/run-pass/concurrency/locks.rs | 4 ++- tests/run-pass/concurrency/locks.stderr | 2 +- tests/run-pass/concurrency/simple.rs | 2 +- tests/run-pass/concurrency/simple.stderr | 2 +- tests/run-pass/concurrency/thread_locals.rs | 7 +++- .../run-pass/concurrency/thread_locals.stderr | 2 +- 16 files changed, 87 insertions(+), 79 deletions(-) delete mode 100644 tests/compile-fail/concurrency/libc_pthread_rwlock_write_read_deadlock.rs delete mode 100644 tests/compile-fail/concurrency/libc_pthread_rwlock_write_write_deadlock.rs rename tests/compile-fail/{ => concurrency}/thread-spawn.rs (52%) rename tests/compile-fail/{concurrency => sync}/libc_pthread_mutex_deadlock.rs (100%) rename tests/compile-fail/{concurrency => sync}/libc_pthread_mutex_wrong_owner.rs (100%) create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs diff --git a/tests/compile-fail/concurrency/dangling_tls_lib.rs b/tests/compile-fail/concurrency/dangling_tls_lib.rs index ad12c107bffb..684dd0e86f60 100644 --- a/tests/compile-fail/concurrency/dangling_tls_lib.rs +++ b/tests/compile-fail/concurrency/dangling_tls_lib.rs @@ -1,4 +1,4 @@ -// ignore-windows +// ignore-windows: Concurrency on Windows is not supported yet. #![feature(thread_local_internals)] diff --git a/tests/compile-fail/concurrency/libc_pthread_rwlock_write_read_deadlock.rs b/tests/compile-fail/concurrency/libc_pthread_rwlock_write_read_deadlock.rs deleted file mode 100644 index 19dce431c8b1..000000000000 --- a/tests/compile-fail/concurrency/libc_pthread_rwlock_write_read_deadlock.rs +++ /dev/null @@ -1,32 +0,0 @@ -// ignore-windows: No libc on Windows - -#![feature(rustc_private)] - -extern crate libc; - -use std::cell::UnsafeCell; -use std::sync::Arc; -use std::thread; - -struct RwLock(UnsafeCell); - -unsafe impl Send for RwLock {} -unsafe impl Sync for RwLock {} - -fn new_lock() -> Arc { - Arc::new(RwLock(UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER))) -} - -fn main() { - unsafe { - let lock = new_lock(); - assert_eq!(libc::pthread_rwlock_rdlock(lock.0.get() as *mut _), 0); - - let lock_copy = lock.clone(); - thread::spawn(move || { - assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: deadlock - }) - .join() - .unwrap(); - } -} diff --git a/tests/compile-fail/concurrency/libc_pthread_rwlock_write_write_deadlock.rs b/tests/compile-fail/concurrency/libc_pthread_rwlock_write_write_deadlock.rs deleted file mode 100644 index 098c1c2fe26c..000000000000 --- a/tests/compile-fail/concurrency/libc_pthread_rwlock_write_write_deadlock.rs +++ /dev/null @@ -1,32 +0,0 @@ -// ignore-windows: No libc on Windows - -#![feature(rustc_private)] - -extern crate libc; - -use std::cell::UnsafeCell; -use std::sync::Arc; -use std::thread; - -struct RwLock(UnsafeCell); - -unsafe impl Send for RwLock {} -unsafe impl Sync for RwLock {} - -fn new_lock() -> Arc { - Arc::new(RwLock(UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER))) -} - -fn main() { - unsafe { - let lock = new_lock(); - assert_eq!(libc::pthread_rwlock_wrlock(lock.0.get() as *mut _), 0); - - let lock_copy = lock.clone(); - thread::spawn(move || { - assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: deadlock - }) - .join() - .unwrap(); - } -} diff --git a/tests/compile-fail/thread-spawn.rs b/tests/compile-fail/concurrency/thread-spawn.rs similarity index 52% rename from tests/compile-fail/thread-spawn.rs rename to tests/compile-fail/concurrency/thread-spawn.rs index 4b9073f3a73e..f0e4ab3817d3 100644 --- a/tests/compile-fail/thread-spawn.rs +++ b/tests/compile-fail/concurrency/thread-spawn.rs @@ -1,5 +1,6 @@ -// ignore-linux -// ignore-macos +// ignore-linux: Only Windows is not supported. +// ignore-macos: Only Windows is not supported. + use std::thread; // error-pattern: Miri does not support threading diff --git a/tests/compile-fail/concurrency/libc_pthread_mutex_deadlock.rs b/tests/compile-fail/sync/libc_pthread_mutex_deadlock.rs similarity index 100% rename from tests/compile-fail/concurrency/libc_pthread_mutex_deadlock.rs rename to tests/compile-fail/sync/libc_pthread_mutex_deadlock.rs diff --git a/tests/compile-fail/concurrency/libc_pthread_mutex_wrong_owner.rs b/tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.rs similarity index 100% rename from tests/compile-fail/concurrency/libc_pthread_mutex_wrong_owner.rs rename to tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.rs diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock.rs b/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock.rs index 1b460e7174d2..19dce431c8b1 100644 --- a/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock.rs +++ b/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock.rs @@ -4,10 +4,29 @@ extern crate libc; +use std::cell::UnsafeCell; +use std::sync::Arc; +use std::thread; + +struct RwLock(UnsafeCell); + +unsafe impl Send for RwLock {} +unsafe impl Sync for RwLock {} + +fn new_lock() -> Arc { + Arc::new(RwLock(UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER))) +} + fn main() { - let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { - assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); - libc::pthread_rwlock_rdlock(rw.get()); //~ ERROR: deadlock + let lock = new_lock(); + assert_eq!(libc::pthread_rwlock_rdlock(lock.0.get() as *mut _), 0); + + let lock_copy = lock.clone(); + thread::spawn(move || { + assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: deadlock + }) + .join() + .unwrap(); } } diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs b/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs new file mode 100644 index 000000000000..1b460e7174d2 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs @@ -0,0 +1,13 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); + unsafe { + assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); + libc::pthread_rwlock_rdlock(rw.get()); //~ ERROR: deadlock + } +} diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock.rs b/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock.rs index cc327ec46bc2..098c1c2fe26c 100644 --- a/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock.rs +++ b/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock.rs @@ -4,10 +4,29 @@ extern crate libc; +use std::cell::UnsafeCell; +use std::sync::Arc; +use std::thread; + +struct RwLock(UnsafeCell); + +unsafe impl Send for RwLock {} +unsafe impl Sync for RwLock {} + +fn new_lock() -> Arc { + Arc::new(RwLock(UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER))) +} + fn main() { - let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { - assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); - libc::pthread_rwlock_wrlock(rw.get()); //~ ERROR: deadlock + let lock = new_lock(); + assert_eq!(libc::pthread_rwlock_wrlock(lock.0.get() as *mut _), 0); + + let lock_copy = lock.clone(); + thread::spawn(move || { + assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: deadlock + }) + .join() + .unwrap(); } } diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs b/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs new file mode 100644 index 000000000000..cc327ec46bc2 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs @@ -0,0 +1,13 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); + unsafe { + assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); + libc::pthread_rwlock_wrlock(rw.get()); //~ ERROR: deadlock + } +} diff --git a/tests/run-pass/concurrency/locks.rs b/tests/run-pass/concurrency/locks.rs index 90c10b8ffe24..f5469712c5f5 100644 --- a/tests/run-pass/concurrency/locks.rs +++ b/tests/run-pass/concurrency/locks.rs @@ -1,4 +1,4 @@ -// ignore-windows +// ignore-windows: Concurrency on Windows is not supported yet. use std::sync::{Arc, Mutex, RwLock}; use std::thread; @@ -11,6 +11,7 @@ fn check_mutex() { let data = Arc::clone(&data); let thread = thread::spawn(move || { let mut data = data.lock().unwrap(); + thread::yield_now(); *data += 1; }); threads.push(thread); @@ -34,6 +35,7 @@ fn check_rwlock_write() { let data = Arc::clone(&data); let thread = thread::spawn(move || { let mut data = data.write().unwrap(); + thread::yield_now(); *data += 1; }); threads.push(thread); diff --git a/tests/run-pass/concurrency/locks.stderr b/tests/run-pass/concurrency/locks.stderr index 20a2bf3eeb87..2dbfb7721d36 100644 --- a/tests/run-pass/concurrency/locks.stderr +++ b/tests/run-pass/concurrency/locks.stderr @@ -1,2 +1,2 @@ -warning: The thread support is experimental. For example, Miri does not detect data races yet. +warning: thread support is experimental. For example, Miri does not detect data races yet. diff --git a/tests/run-pass/concurrency/simple.rs b/tests/run-pass/concurrency/simple.rs index 5adc521f59c2..ad47bb144b58 100644 --- a/tests/run-pass/concurrency/simple.rs +++ b/tests/run-pass/concurrency/simple.rs @@ -1,4 +1,4 @@ -// ignore-windows +// ignore-windows: Concurrency on Windows is not supported yet. use std::thread; diff --git a/tests/run-pass/concurrency/simple.stderr b/tests/run-pass/concurrency/simple.stderr index 20a2bf3eeb87..2dbfb7721d36 100644 --- a/tests/run-pass/concurrency/simple.stderr +++ b/tests/run-pass/concurrency/simple.stderr @@ -1,2 +1,2 @@ -warning: The thread support is experimental. For example, Miri does not detect data races yet. +warning: thread support is experimental. For example, Miri does not detect data races yet. diff --git a/tests/run-pass/concurrency/thread_locals.rs b/tests/run-pass/concurrency/thread_locals.rs index 1805a1da3d0b..384c2ac9155b 100644 --- a/tests/run-pass/concurrency/thread_locals.rs +++ b/tests/run-pass/concurrency/thread_locals.rs @@ -1,4 +1,9 @@ -// ignore-windows +// ignore-windows: Concurrency on Windows is not supported yet. + +//! The main purpose of this test is to check that if we take a pointer to +//! thread's `t1` thread-local `A` and send it to another thread `t2`, +//! dereferencing the pointer on `t2` resolves to `t1`'s thread-local. In this +//! test, we also check that thread-locals act as per-thread statics. #![feature(thread_local)] diff --git a/tests/run-pass/concurrency/thread_locals.stderr b/tests/run-pass/concurrency/thread_locals.stderr index 20a2bf3eeb87..2dbfb7721d36 100644 --- a/tests/run-pass/concurrency/thread_locals.stderr +++ b/tests/run-pass/concurrency/thread_locals.stderr @@ -1,2 +1,2 @@ -warning: The thread support is experimental. For example, Miri does not detect data races yet. +warning: thread support is experimental. For example, Miri does not detect data races yet. From 17f7bc86ae4bf5d160ae13552387afb922f75cdc Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 19 Apr 2020 15:23:30 -0700 Subject: [PATCH 1960/5092] Fix how a pthread_create function argument is constructed. --- src/shims/thread.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/shims/thread.rs b/src/shims/thread.rs index ab3b436b8665..ee4369cb412e 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -37,11 +37,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fn_ptr = this.read_scalar(start_routine)?.not_undef()?; let instance = this.memory.get_fn(fn_ptr)?.as_instance()?; - let func_arg = match *arg { - rustc_mir::interpret::Operand::Immediate(immediate) => immediate, - _ => unreachable!(), - }; - let func_args = [func_arg]; + let func_arg = this.read_immediate(arg)?; + let func_args = [*func_arg]; let ret_place = this.allocate(this.layout_of(this.tcx.types.usize)?, MiriMemoryKind::Machine.into()); From 5b55e0706c3fff3fd015e5396422a2a1eda19779 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 19 Apr 2020 16:42:58 -0700 Subject: [PATCH 1961/5092] Add more concurrency tests. --- .../libc_pthread_create_main_terminate.rs | 24 +++++++++++++++ .../concurrency/libc_pthread_join_detached.rs | 24 +++++++++++++++ .../concurrency/libc_pthread_join_joined.rs | 24 +++++++++++++++ .../concurrency/libc_pthread_join_multiple.rs | 30 +++++++++++++++++++ .../concurrency/libc_pthread_join_self.rs | 16 ++++++++++ 5 files changed, 118 insertions(+) create mode 100644 tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs create mode 100644 tests/compile-fail/concurrency/libc_pthread_join_detached.rs create mode 100644 tests/compile-fail/concurrency/libc_pthread_join_joined.rs create mode 100644 tests/compile-fail/concurrency/libc_pthread_join_multiple.rs create mode 100644 tests/compile-fail/concurrency/libc_pthread_join_self.rs diff --git a/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs b/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs new file mode 100644 index 000000000000..e34d3f5c93bc --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs @@ -0,0 +1,24 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +// Check that we terminate the program when the main thread terminates. + +//~^^^^ ERROR: unsupported operation: the main thread terminated without waiting for other threads + +#![feature(rustc_private)] + +extern crate libc; + +use std::{mem, ptr}; + +extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { + ptr::null_mut() +} + +fn main() { + unsafe { + let mut native: libc::pthread_t = mem::zeroed(); + let attr: libc::pthread_attr_t = mem::zeroed(); + // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented. + assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0); + } +} diff --git a/tests/compile-fail/concurrency/libc_pthread_join_detached.rs b/tests/compile-fail/concurrency/libc_pthread_join_detached.rs new file mode 100644 index 000000000000..ad83fb2efef3 --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_join_detached.rs @@ -0,0 +1,24 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +// Joining a detached thread is undefined behavior. + +#![feature(rustc_private)] + +extern crate libc; + +use std::{mem, ptr}; + +extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { + ptr::null_mut() +} + +fn main() { + unsafe { + let mut native: libc::pthread_t = mem::zeroed(); + let attr: libc::pthread_attr_t = mem::zeroed(); + // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented. + assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0); + assert_eq!(libc::pthread_detach(native), 0); + assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join a detached or already joined thread + } +} diff --git a/tests/compile-fail/concurrency/libc_pthread_join_joined.rs b/tests/compile-fail/concurrency/libc_pthread_join_joined.rs new file mode 100644 index 000000000000..3ca042449690 --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_join_joined.rs @@ -0,0 +1,24 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +// Joining an already joined thread is undefined behavior. + +#![feature(rustc_private)] + +extern crate libc; + +use std::{mem, ptr}; + +extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { + ptr::null_mut() +} + +fn main() { + unsafe { + let mut native: libc::pthread_t = mem::zeroed(); + let attr: libc::pthread_attr_t = mem::zeroed(); + // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented. + assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0); + assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); + assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join a detached or already joined thread + } +} diff --git a/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs b/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs new file mode 100644 index 000000000000..08ce94022c6f --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs @@ -0,0 +1,30 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +// Joining the same thread multiple times is undefined behavior. + +#![feature(rustc_private)] + +extern crate libc; + +use std::thread; +use std::{mem, ptr}; + +extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { + ptr::null_mut() +} + +fn main() { + unsafe { + let mut native: libc::pthread_t = mem::zeroed(); + let attr: libc::pthread_attr_t = mem::zeroed(); + // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented. + assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0); + let mut native_copy: libc::pthread_t = mem::zeroed(); + ptr::copy_nonoverlapping(&native, &mut native_copy, 1); + let handle = thread::spawn(move || { + assert_eq!(libc::pthread_join(native_copy, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join a detached or already joined thread + }); + assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); + handle.join().unwrap(); + } +} diff --git a/tests/compile-fail/concurrency/libc_pthread_join_self.rs b/tests/compile-fail/concurrency/libc_pthread_join_self.rs new file mode 100644 index 000000000000..1aeb274dcd1d --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_join_self.rs @@ -0,0 +1,16 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +// Joining itself is undefined behavior. + +#![feature(rustc_private)] + +extern crate libc; + +use std::ptr; + +fn main() { + unsafe { + let native: libc::pthread_t = libc::pthread_self(); + assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join itself + } +} From e4dc3567f8bb2b5b50230aa31d4ad57b631ac8db Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 19 Apr 2020 16:43:40 -0700 Subject: [PATCH 1962/5092] Track if a thread was already joined. --- src/thread.rs | 57 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/src/thread.rs b/src/thread.rs index 5eb6560a09e6..657792bd2c67 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -92,6 +92,18 @@ pub enum ThreadState { Terminated, } +/// The join status of a thread. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +enum ThreadJoinStatus { + /// The thread can be joined. + Joinable, + /// A thread is detached if its join handle was destroyed and no other + /// thread can join it. + Detached, + /// The thread was already joined by some thread and cannot be joined again. + Joined, +} + /// A thread. pub struct Thread<'mir, 'tcx> { state: ThreadState, @@ -99,11 +111,8 @@ pub struct Thread<'mir, 'tcx> { thread_name: Option>, /// The virtual call stack. stack: Vec>>, - /// Is the thread detached? - /// - /// A thread is detached if its join handle was destroyed and no other - /// thread can join it. - detached: bool, + /// The join status. + join_status: ThreadJoinStatus, } impl<'mir, 'tcx> Thread<'mir, 'tcx> { @@ -128,7 +137,12 @@ impl<'mir, 'tcx> std::fmt::Debug for Thread<'mir, 'tcx> { impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> { fn default() -> Self { - Self { state: ThreadState::Enabled, thread_name: None, stack: Vec::new(), detached: false } + Self { + state: ThreadState::Enabled, + thread_name: None, + stack: Vec::new(), + join_status: ThreadJoinStatus::Joinable, + } } } @@ -225,25 +239,31 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Mark the thread as detached, which means that no other thread will try /// to join it and the thread is responsible for cleaning up. - fn detach_thread(&mut self, id: ThreadId) { - self.threads[id].detached = true; + fn detach_thread(&mut self, id: ThreadId) -> InterpResult<'tcx> { + if self.threads[id].join_status != ThreadJoinStatus::Joinable { + throw_ub_format!("trying to detach thread that was already detached or joined"); + } + self.threads[id].join_status = ThreadJoinStatus::Detached; + Ok(()) } /// Mark that the active thread tries to join the thread with `joined_thread_id`. fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> { - if self.threads[joined_thread_id].detached { - throw_ub_format!("trying to join a detached thread"); + if self.threads[joined_thread_id].join_status != ThreadJoinStatus::Joinable { + throw_ub_format!("trying to join a detached or already joined thread"); } if joined_thread_id == self.active_thread { throw_ub_format!("trying to join itself"); } - if self - .threads - .iter() - .any(|thread| thread.state == ThreadState::BlockedOnJoin(joined_thread_id)) - { - throw_ub_format!("multiple threads try to join the same thread"); - } + assert!( + self.threads + .iter() + .all(|thread| thread.state != ThreadState::BlockedOnJoin(joined_thread_id)), + "a joinable thread has threads waiting for its termination" + ); + // Mark the joined thread as being joined so that we detect if other + // threads try to join it. + self.threads[joined_thread_id].join_status = ThreadJoinStatus::Joined; if self.threads[joined_thread_id].state != ThreadState::Terminated { // The joined thread is still running, we need to wait for it. self.active_thread_mut().state = ThreadState::BlockedOnJoin(joined_thread_id); @@ -451,8 +471,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn detach_thread(&mut self, thread_id: ThreadId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.machine.threads.detach_thread(thread_id); - Ok(()) + this.machine.threads.detach_thread(thread_id) } #[inline] From 9a01c3fa3e294cfb22fb259da05e54f7ec2a6320 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 19 Apr 2020 20:52:53 -0700 Subject: [PATCH 1963/5092] Clarify comments about TLS destructor handling in Windows, add a test for TLS destructors. --- src/eval.rs | 3 +- src/shims/tls.rs | 3 +- src/thread.rs | 11 +++++ .../concurrency/dangling_tls_lib.rs | 3 ++ tests/run-pass/concurrency/tls_lib_drop.rs | 46 +++++++++++++++++++ .../run-pass/concurrency/tls_lib_drop.stderr | 2 + .../run-pass/concurrency/tls_lib_drop.stdout | 2 + 7 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 tests/run-pass/concurrency/tls_lib_drop.rs create mode 100644 tests/run-pass/concurrency/tls_lib_drop.stderr create mode 100644 tests/run-pass/concurrency/tls_lib_drop.stdout diff --git a/src/eval.rs b/src/eval.rs index ab82c39836b2..c5a04d75858c 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -222,7 +222,8 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> // Read the return code pointer *before* we run TLS destructors, to assert // that it was written to by the time that `start` lang item returned. let return_code = ecx.read_scalar(ret_place.into())?.not_undef()?.to_machine_isize(&ecx)?; - // Global destructors. + // Run Windows destructors. (We do not support concurrency on Windows + // yet, so we run the destructor of the main thread separately.) ecx.run_windows_tls_dtors()?; Ok(return_code) })(); diff --git a/src/shims/tls.rs b/src/shims/tls.rs index c08ec78c136d..31a9ee3c9425 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -6,7 +6,6 @@ use std::collections::HashSet; use log::trace; -use rustc_index::vec::Idx; use rustc_middle::ty; use rustc_target::abi::{Size, HasDataLayout}; @@ -201,7 +200,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(()); } let active_thread = this.get_active_thread()?; - assert_eq!(active_thread.index(), 0, "concurrency on Windows not supported"); + assert_eq!(this.get_total_thread_count()?, 1, "concurrency on Windows not supported"); assert!(!this.machine.tls.dtors_running.contains(&active_thread), "running TLS dtors twice"); this.machine.tls.dtors_running.insert(active_thread); // Windows has a special magic linker section that is run on certain events. diff --git a/src/thread.rs b/src/thread.rs index 657792bd2c67..8c353d6a8853 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -227,6 +227,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { self.active_thread } + /// Get the total number of threads that were ever spawn by this program. + fn get_total_thread_count(&self) -> usize { + self.threads.len() + } + /// Has the given thread terminated? fn has_terminated(&self, thread_id: ThreadId) -> bool { self.threads[thread_id].state == ThreadState::Terminated @@ -492,6 +497,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(this.machine.threads.get_active_thread_id()) } + #[inline] + fn get_total_thread_count(&self) -> InterpResult<'tcx, usize> { + let this = self.eval_context_ref(); + Ok(this.machine.threads.get_total_thread_count()) + } + #[inline] fn has_terminated(&self, thread_id: ThreadId) -> InterpResult<'tcx, bool> { let this = self.eval_context_ref(); diff --git a/tests/compile-fail/concurrency/dangling_tls_lib.rs b/tests/compile-fail/concurrency/dangling_tls_lib.rs index 684dd0e86f60..6be5538bb444 100644 --- a/tests/compile-fail/concurrency/dangling_tls_lib.rs +++ b/tests/compile-fail/concurrency/dangling_tls_lib.rs @@ -1,5 +1,8 @@ // ignore-windows: Concurrency on Windows is not supported yet. +//! Check that we catch if a thread local is accessed after the thread has +//! terminated. + #![feature(thread_local_internals)] use std::cell::RefCell; diff --git a/tests/run-pass/concurrency/tls_lib_drop.rs b/tests/run-pass/concurrency/tls_lib_drop.rs new file mode 100644 index 000000000000..c9b04a728258 --- /dev/null +++ b/tests/run-pass/concurrency/tls_lib_drop.rs @@ -0,0 +1,46 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +//! Check that destructors of the library thread locals are executed immediately +//! after a thread terminates. + +#![feature(thread_local_internals)] + +use std::cell::RefCell; +use std::thread; + +struct TestCell { + value: RefCell, +} + +impl Drop for TestCell { + fn drop(&mut self) { + println!("Dropping: {}", self.value.borrow()) + } +} + +static A: std::thread::LocalKey = { + #[inline] + fn __init() -> TestCell { + TestCell { value: RefCell::new(0) } + } + + unsafe fn __getit() -> Option<&'static TestCell> { + static __KEY: std::thread::__OsLocalKeyInner = + std::thread::__OsLocalKeyInner::new(); + __KEY.get(__init) + } + + unsafe { std::thread::LocalKey::new(__getit) } +}; + +fn main() { + thread::spawn(|| { + A.with(|f| { + assert_eq!(*f.value.borrow(), 0); + *f.value.borrow_mut() = 5; + }); + }) + .join() + .unwrap(); + println!("Continue main.") +} diff --git a/tests/run-pass/concurrency/tls_lib_drop.stderr b/tests/run-pass/concurrency/tls_lib_drop.stderr new file mode 100644 index 000000000000..2dbfb7721d36 --- /dev/null +++ b/tests/run-pass/concurrency/tls_lib_drop.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental. For example, Miri does not detect data races yet. + diff --git a/tests/run-pass/concurrency/tls_lib_drop.stdout b/tests/run-pass/concurrency/tls_lib_drop.stdout new file mode 100644 index 000000000000..d2bbb866b77e --- /dev/null +++ b/tests/run-pass/concurrency/tls_lib_drop.stdout @@ -0,0 +1,2 @@ +Dropping: 5 +Continue main. From 3bb16574486ecabd702587c6811ae5154cb3b12c Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 19 Apr 2020 21:03:23 -0700 Subject: [PATCH 1964/5092] Small style fix. --- src/machine.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine.rs b/src/machine.rs index a81273960d09..4032a399e3eb 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -282,7 +282,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { panic_payload: None, time_anchor: Instant::now(), layouts, - threads: Default::default(), + threads: ThreadManager::default(), } } } From 452e36efb3840f4b44c70c3939e3a88f27e47710 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 19 Apr 2020 21:21:22 -0700 Subject: [PATCH 1965/5092] Print the thread name in Debug. --- src/thread.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/thread.rs b/src/thread.rs index 8c353d6a8853..76f1e20cb13a 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -131,7 +131,16 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> { impl<'mir, 'tcx> std::fmt::Debug for Thread<'mir, 'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.state) + if let Some(ref name) = self.thread_name { + if let Ok(name_str) = std::str::from_utf8(name) { + write!(f, "{}", name_str)?; + } else { + write!(f, "")?; + } + } else { + write!(f, "unnamed")?; + } + write!(f, "({:?}, {:?})", self.state, self.join_status) } } From 69eaaadc28e027fd749c2f6e500daa48f8c2aba3 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 20 Apr 2020 11:53:19 -0700 Subject: [PATCH 1966/5092] Fix merge error. --- src/machine.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 4032a399e3eb..3853f6559959 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -545,20 +545,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx.active_thread_stack_mut() } - #[inline(always)] - fn stack<'a>( - ecx: &'a InterpCx<'mir, 'tcx, Self>, - ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] { - &ecx.machine.stack - } - - #[inline(always)] - fn stack_mut<'a>( - ecx: &'a mut InterpCx<'mir, 'tcx, Self>, - ) -> &'a mut Vec> { - &mut ecx.machine.stack - } - #[inline(always)] fn after_stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { if ecx.memory.extra.stacked_borrows.is_some() { From e7c2694b8b93ad44256d7ce3d179f172a4c6a9b0 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 20 Apr 2020 13:22:28 -0700 Subject: [PATCH 1967/5092] Make the main thread detached. --- src/thread.rs | 4 +++- .../concurrency/libc_pthread_join_self.rs | 14 +++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/thread.rs b/src/thread.rs index 76f1e20cb13a..80c9965aa1d8 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -177,7 +177,9 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { fn default() -> Self { let mut threads = IndexVec::new(); // Create the main thread and add it to the list of threads. - threads.push(Default::default()); + let mut main_thread = Thread::default(); + main_thread.join_status = ThreadJoinStatus::Detached; + threads.push(main_thread); Self { active_thread: ThreadId::new(0), threads: threads, diff --git a/tests/compile-fail/concurrency/libc_pthread_join_self.rs b/tests/compile-fail/concurrency/libc_pthread_join_self.rs index 1aeb274dcd1d..d765a95d8be7 100644 --- a/tests/compile-fail/concurrency/libc_pthread_join_self.rs +++ b/tests/compile-fail/concurrency/libc_pthread_join_self.rs @@ -6,11 +6,15 @@ extern crate libc; -use std::ptr; +use std::{ptr, thread}; fn main() { - unsafe { - let native: libc::pthread_t = libc::pthread_self(); - assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join itself - } + let handle = thread::spawn(|| { + unsafe { + let native: libc::pthread_t = libc::pthread_self(); + assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join itself + } + }); + thread::yield_now(); + handle.join().unwrap(); } From e7b82fde4a06ec7a75511a900379017d37d991fd Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 20 Apr 2020 13:22:51 -0700 Subject: [PATCH 1968/5092] Fix the test annotation. --- .../concurrency/libc_pthread_create_main_terminate.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs b/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs index e34d3f5c93bc..ea11691955ce 100644 --- a/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs +++ b/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs @@ -1,9 +1,8 @@ // ignore-windows: Concurrency on Windows is not supported yet. +// error-pattern: unsupported operation: the main thread terminated without waiting for other threads // Check that we terminate the program when the main thread terminates. -//~^^^^ ERROR: unsupported operation: the main thread terminated without waiting for other threads - #![feature(rustc_private)] extern crate libc; From 40e50bf58bd82482026bb1e1f0766bdf909fe9cb Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 20 Apr 2020 13:23:11 -0700 Subject: [PATCH 1969/5092] Clarify test comments. --- tests/compile-fail/concurrency/libc_pthread_join_multiple.rs | 2 +- tests/run-pass/concurrency/tls_lib_drop.rs | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs b/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs index 08ce94022c6f..949fcc282f0f 100644 --- a/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs +++ b/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs @@ -1,6 +1,6 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// Joining the same thread multiple times is undefined behavior. +// Joining the same thread from multiple threads is undefined behavior. #![feature(rustc_private)] diff --git a/tests/run-pass/concurrency/tls_lib_drop.rs b/tests/run-pass/concurrency/tls_lib_drop.rs index c9b04a728258..d39528cfefe3 100644 --- a/tests/run-pass/concurrency/tls_lib_drop.rs +++ b/tests/run-pass/concurrency/tls_lib_drop.rs @@ -2,6 +2,9 @@ //! Check that destructors of the library thread locals are executed immediately //! after a thread terminates. +//! +//! FIXME: We should have a similar test for thread-local statics (statics +//! annotated with `#[thread_local]`) once they support destructors. #![feature(thread_local_internals)] From 8a7dbde372388c0f4125f3aad0f697f8af138026 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 20 Apr 2020 16:49:27 -0700 Subject: [PATCH 1970/5092] Check prctl argument types and fix the test. --- src/shims/thread.rs | 20 ++++++++++++++++--- .../concurrency/libc_prctl_thread_name.rs | 4 ++-- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/shims/thread.rs b/src/shims/thread.rs index ee4369cb412e..65187326223c 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -92,12 +92,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, option: OpTy<'tcx, Tag>, arg2: OpTy<'tcx, Tag>, - _arg3: OpTy<'tcx, Tag>, - _arg4: OpTy<'tcx, Tag>, - _arg5: OpTy<'tcx, Tag>, + arg3: OpTy<'tcx, Tag>, + arg4: OpTy<'tcx, Tag>, + arg5: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // prctl last 5 arguments are declared as variadic. Therefore, we need + // to check their types manually. + let c_long_size = this.libc_ty_layout("c_long")?.size.bytes(); + let check_arg = |arg: OpTy<'tcx, Tag>| -> InterpResult<'tcx> { + match this.read_scalar(arg)?.not_undef()? { + Scalar::Raw { size, .. } if u64::from(size) == c_long_size => Ok(()), + _ => throw_ub_format!("an argument of unsupported type was passed to prctl"), + } + }; + check_arg(arg2)?; + check_arg(arg3)?; + check_arg(arg4)?; + check_arg(arg5)?; + let option = this.read_scalar(option)?.not_undef()?.to_i32()?; if option == this.eval_libc_i32("PR_SET_NAME")? { let address = this.read_scalar(arg2)?.not_undef()?; diff --git a/tests/run-pass/concurrency/libc_prctl_thread_name.rs b/tests/run-pass/concurrency/libc_prctl_thread_name.rs index 235ac27e0a59..aa3f62f03d77 100644 --- a/tests/run-pass/concurrency/libc_prctl_thread_name.rs +++ b/tests/run-pass/concurrency/libc_prctl_thread_name.rs @@ -9,9 +9,9 @@ use std::ffi::CString; fn main() { unsafe { let thread_name = CString::new("hello").expect("CString::new failed"); - assert_eq!(libc::prctl(libc::PR_SET_NAME, thread_name.as_ptr() as u64, 0, 0, 0), 0); + assert_eq!(libc::prctl(libc::PR_SET_NAME, thread_name.as_ptr() as libc::c_long, 0 as libc::c_long, 0 as libc::c_long, 0 as libc::c_long), 0); let mut buf = [0; 6]; - assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr() as u64, 0, 0, 0), 0); + assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr() as libc::c_long, 0 as libc::c_long, 0 as libc::c_long, 0 as libc::c_long), 0); assert_eq!(thread_name.as_bytes_with_nul(), buf); } } From d45e985669d1bc532862ed3a50dce9cfdf08d7ff Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 20 Apr 2020 16:57:30 -0700 Subject: [PATCH 1971/5092] Clarify FIXME. --- src/thread.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/thread.rs b/src/thread.rs index 80c9965aa1d8..aee9b8a6f56d 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -357,7 +357,12 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { if self.threads[MAIN_THREAD].state == ThreadState::Terminated { // The main thread terminated; stop the program. if self.threads.iter().any(|thread| thread.state != ThreadState::Terminated) { - // FIXME: This check should be either configurable or just emit a warning. + // FIXME: This check should be either configurable or just emit + // a warning. For example, it seems normal for a program to + // terminate without waiting for its detached threads to + // terminate. However, this case is not trivial to support + // because we also probably do not want to consider the memory + // owned by these threads as leaked. throw_unsup_format!("the main thread terminated without waiting for other threads"); } return Ok(SchedulingAction::Stop); From eaa63266d8456ac8c3d1b82f4e1078fcd271e95c Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 20 Apr 2020 17:02:43 -0700 Subject: [PATCH 1972/5092] Make multiple threads to try to join a thread while it is still running. --- tests/compile-fail/concurrency/libc_pthread_join_multiple.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs b/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs index 949fcc282f0f..0d99b69ed914 100644 --- a/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs +++ b/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs @@ -10,6 +10,8 @@ use std::thread; use std::{mem, ptr}; extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { + thread::yield_now(); + thread::yield_now(); ptr::null_mut() } From cc9248a7c891614cf79e7ec708de2ff99d4eb06c Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 20 Apr 2020 17:10:25 -0700 Subject: [PATCH 1973/5092] Ignore prctl test on MacOS because it does not support it. --- tests/run-pass/concurrency/libc_prctl_thread_name.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-pass/concurrency/libc_prctl_thread_name.rs b/tests/run-pass/concurrency/libc_prctl_thread_name.rs index aa3f62f03d77..b8ba27b3a895 100644 --- a/tests/run-pass/concurrency/libc_prctl_thread_name.rs +++ b/tests/run-pass/concurrency/libc_prctl_thread_name.rs @@ -1,4 +1,5 @@ // ignore-windows: No libc on Windows +// ignore-macos: No prctl on MacOS #![feature(rustc_private)] From 90e9a87fa79f541efecadde6daa53299b9350e07 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 20 Apr 2020 17:13:22 -0700 Subject: [PATCH 1974/5092] Add an explanatory comment to the test. --- tests/compile-fail/concurrency/libc_pthread_join_multiple.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs b/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs index 0d99b69ed914..f8a43cfcde64 100644 --- a/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs +++ b/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs @@ -10,6 +10,7 @@ use std::thread; use std::{mem, ptr}; extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { + // Yield the thread several times so that other threads can join it. thread::yield_now(); thread::yield_now(); ptr::null_mut() From 8240ed26a97a6d1642546e56144870305ff4676c Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 20 Apr 2020 17:23:51 -0700 Subject: [PATCH 1975/5092] Change the test not to rely on internals. --- tests/run-pass/concurrency/tls_lib_drop.rs | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/tests/run-pass/concurrency/tls_lib_drop.rs b/tests/run-pass/concurrency/tls_lib_drop.rs index d39528cfefe3..0d1808cbe0fa 100644 --- a/tests/run-pass/concurrency/tls_lib_drop.rs +++ b/tests/run-pass/concurrency/tls_lib_drop.rs @@ -2,11 +2,6 @@ //! Check that destructors of the library thread locals are executed immediately //! after a thread terminates. -//! -//! FIXME: We should have a similar test for thread-local statics (statics -//! annotated with `#[thread_local]`) once they support destructors. - -#![feature(thread_local_internals)] use std::cell::RefCell; use std::thread; @@ -21,20 +16,9 @@ impl Drop for TestCell { } } -static A: std::thread::LocalKey = { - #[inline] - fn __init() -> TestCell { - TestCell { value: RefCell::new(0) } - } - - unsafe fn __getit() -> Option<&'static TestCell> { - static __KEY: std::thread::__OsLocalKeyInner = - std::thread::__OsLocalKeyInner::new(); - __KEY.get(__init) - } - - unsafe { std::thread::LocalKey::new(__getit) } -}; +thread_local! { + static A: TestCell = TestCell { value: RefCell::new(0) }; +} fn main() { thread::spawn(|| { From feb188360ee5ff6ae4cdc8e6a20ec29f9cd385ba Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Fri, 24 Apr 2020 15:16:24 -0700 Subject: [PATCH 1976/5092] Unify TLS dtors; move stepping outside. --- src/eval.rs | 7 +- src/shims/tls.rs | 112 +++++++++++------- src/thread.rs | 13 ++ .../concurrency/tls_lib_drop_single_thread.rs | 25 ++++ .../tls_lib_drop_single_thread.stderr | 2 + 5 files changed, 110 insertions(+), 49 deletions(-) create mode 100644 tests/run-pass/concurrency/tls_lib_drop_single_thread.rs create mode 100644 tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr diff --git a/src/eval.rs b/src/eval.rs index c5a04d75858c..9131946f8dc1 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -211,7 +211,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> assert!(ecx.step()?, "a terminated thread was scheduled for execution"); } SchedulingAction::ExecuteDtors => { - ecx.run_tls_dtors_for_active_thread()?; + ecx.schedule_tls_dtors_for_active_thread()?; } SchedulingAction::Stop => { break; @@ -219,12 +219,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> } ecx.process_diagnostics(); } - // Read the return code pointer *before* we run TLS destructors, to assert - // that it was written to by the time that `start` lang item returned. let return_code = ecx.read_scalar(ret_place.into())?.not_undef()?.to_machine_isize(&ecx)?; - // Run Windows destructors. (We do not support concurrency on Windows - // yet, so we run the destructor of the main thread separately.) - ecx.run_windows_tls_dtors()?; Ok(return_code) })(); diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 31a9ee3c9425..615950621a24 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -38,6 +38,9 @@ pub struct TlsData<'tcx> { /// Whether we are in the "destruct" phase, during which some operations are UB. dtors_running: HashSet, + + /// The last TlsKey used to retrieve a TLS destructor. + last_dtor_key: BTreeMap, } impl<'tcx> Default for TlsData<'tcx> { @@ -47,6 +50,7 @@ impl<'tcx> Default for TlsData<'tcx> { keys: Default::default(), global_dtors: Default::default(), dtors_running: Default::default(), + last_dtor_key: Default::default(), } } } @@ -187,21 +191,15 @@ impl<'tcx> TlsData<'tcx> { } } -impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} -pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - - /// Run TLS destructors for the main thread on Windows. The implementation - /// assumes that we do not support concurrency on Windows yet. - /// - /// Note: on non-Windows OS this function is a no-op. - fn run_windows_tls_dtors(&mut self) -> InterpResult<'tcx> { +impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + /// Schedule TLS destructors for the main thread on Windows. The + /// implementation assumes that we do not support concurrency on Windows + /// yet. + fn schedule_windows_tls_dtors(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - if this.tcx.sess.target.target.target_os != "windows" { - return Ok(()); - } let active_thread = this.get_active_thread()?; assert_eq!(this.get_total_thread_count()?, 1, "concurrency on Windows not supported"); - assert!(!this.machine.tls.dtors_running.contains(&active_thread), "running TLS dtors twice"); this.machine.tls.dtors_running.insert(active_thread); // Windows has a special magic linker section that is run on certain events. // Instead of searching for that section and supporting arbitrary hooks in there @@ -221,30 +219,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx StackPopCleanup::None { cleanup: true }, )?; - // step until out of stackframes - this.run()?; - - // Windows doesn't have other destructors. + this.enable_thread(active_thread)?; Ok(()) } - /// Run TLS destructors for the active thread. + /// Schedule the MacOS global dtor to be executed. /// - /// Note: on Windows OS this function is a no-op because we do not support - /// concurrency on Windows yet. - /// - /// FIXME: we do not support yet deallocation of thread local statics. - fn run_tls_dtors_for_active_thread(&mut self) -> InterpResult<'tcx> { + /// Note: It is safe to call this function also on other Unixes. + fn schedule_macos_global_tls_dtors(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - if this.tcx.sess.target.target.target_os == "windows" { - return Ok(()); - } let thread_id = this.get_active_thread()?; - assert!(!this.machine.tls.dtors_running.contains(&thread_id), "running TLS dtors twice"); - this.machine.tls.dtors_running.insert(thread_id); - // The macOS global dtor runs "before any TLS slots get freed", so do that first. - if let Some(&(instance, data)) = this.machine.tls.global_dtors.get(&thread_id) { + if let Some((instance, data)) = this.machine.tls.global_dtors.remove(&thread_id) { trace!("Running global dtor {:?} on {:?} at {:?}", instance, data, thread_id); let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); @@ -255,14 +241,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx StackPopCleanup::None { cleanup: true }, )?; - // step until out of stackframes - this.run()?; + // Enable the thread so that it steps through the destructor which + // we just scheduled. Since we deleted the destructor, it is + // guaranteed that we will schedule it again. The `dtors_running` + // flag will prevent the code from adding the destructor again. + this.enable_thread(thread_id)?; } + Ok(()) + } - assert!(this.has_terminated(thread_id)?, "running TLS dtors for non-terminated thread"); - let mut dtor = this.machine.tls.fetch_tls_dtor(None, thread_id); - while let Some((instance, ptr, key)) = dtor { - trace!("Running TLS dtor {:?} on {:?} at {:?}", instance, ptr, thread_id); + /// Schedule a pthread TLS destructor. + fn schedule_pthread_tls_dtors(&mut self) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let active_thread = this.get_active_thread()?; + + assert!(this.has_terminated(active_thread)?, "running TLS dtors for non-terminated thread"); + // Fetch next dtor after `key`. + let last_key = this.machine.tls.last_dtor_key.get(&active_thread).cloned(); + let dtor = match this.machine.tls.fetch_tls_dtor(last_key, active_thread) { + dtor @ Some(_) => dtor, + // We ran each dtor once, start over from the beginning. + None => { + this.machine.tls.fetch_tls_dtor(None, active_thread) + } + }; + if let Some((instance, ptr, key)) = dtor { + this.machine.tls.last_dtor_key.insert(active_thread, key); + trace!("Running TLS dtor {:?} on {:?} at {:?}", instance, ptr, active_thread); assert!(!this.is_null(ptr).unwrap(), "Data can't be NULL when dtor is called!"); let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); @@ -273,15 +278,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx StackPopCleanup::None { cleanup: true }, )?; - // step until out of stackframes - this.run()?; + this.enable_thread(active_thread)?; + return Ok(()); + } + this.machine.tls.last_dtor_key.remove(&active_thread); - // Fetch next dtor after `key`. - dtor = match this.machine.tls.fetch_tls_dtor(Some(key), thread_id) { - dtor @ Some(_) => dtor, - // We ran each dtor once, start over from the beginning. - None => this.machine.tls.fetch_tls_dtor(None, thread_id), - }; + Ok(()) + } +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + + /// Schedule an active thread's TLS destructor to run on the active thread. + /// Note that this function does not run the destructors itself, it just + /// schedules them one by one each time it is called. + /// + /// FIXME: we do not support yet deallocation of thread local statics. + fn schedule_tls_dtors_for_active_thread(&mut self) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let active_thread = this.get_active_thread()?; + + if this.tcx.sess.target.target.target_os == "windows" { + if !this.machine.tls.dtors_running.contains(&active_thread) { + this.machine.tls.dtors_running.insert(active_thread); + this.schedule_windows_tls_dtors()?; + } + } else { + this.machine.tls.dtors_running.insert(active_thread); + this.schedule_macos_global_tls_dtors()?; + this.schedule_pthread_tls_dtors()?; } Ok(()) diff --git a/src/thread.rs b/src/thread.rs index aee9b8a6f56d..c4e0f9be1877 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -248,6 +248,12 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { self.threads[thread_id].state == ThreadState::Terminated } + /// Enable the thread for execution. The thread must be terminated. + fn enable_thread(&mut self, thread_id: ThreadId) { + assert!(self.has_terminated(thread_id)); + self.threads[thread_id].state = ThreadState::Enabled; + } + /// Get the borrow of the currently active thread. fn active_thread_mut(&mut self) -> &mut Thread<'mir, 'tcx> { &mut self.threads[self.active_thread] @@ -525,6 +531,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(this.machine.threads.has_terminated(thread_id)) } + #[inline] + fn enable_thread(&mut self, thread_id: ThreadId) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + this.machine.threads.enable_thread(thread_id); + Ok(()) + } + #[inline] fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] { let this = self.eval_context_ref(); diff --git a/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs b/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs new file mode 100644 index 000000000000..f232cee5bdd1 --- /dev/null +++ b/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs @@ -0,0 +1,25 @@ +//! Check that destructors of the thread locals are executed on all OSes. + +use std::cell::RefCell; + +struct TestCell { + value: RefCell, +} + +impl Drop for TestCell { + fn drop(&mut self) { + eprintln!("Dropping: {}", self.value.borrow()) + } +} + +thread_local! { + static A: TestCell = TestCell { value: RefCell::new(0) }; +} + +fn main() { + A.with(|f| { + assert_eq!(*f.value.borrow(), 0); + *f.value.borrow_mut() = 5; + }); + eprintln!("Continue main.") +} diff --git a/tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr b/tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr new file mode 100644 index 000000000000..a9d705e5b9a2 --- /dev/null +++ b/tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr @@ -0,0 +1,2 @@ +Continue main. +Dropping: 5 From 04abf066f15c2ce2d1a788a1021bb14dcb9ac045 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Fri, 24 Apr 2020 16:46:51 -0700 Subject: [PATCH 1977/5092] Move copying of the thread name to the client side. --- src/shims/thread.rs | 2 +- src/thread.rs | 20 ++++++++++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/shims/thread.rs b/src/shims/thread.rs index 65187326223c..67e833f222e4 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -119,7 +119,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.set_active_thread_name(name)?; } else if option == this.eval_libc_i32("PR_GET_NAME")? { let address = this.read_scalar(arg2)?.not_undef()?; - let name = this.get_active_thread_name()?; + let name = this.get_active_thread_name()?.to_vec(); this.memory.write_bytes(address, name)?; } else { throw_unsup_format!("Unsupported prctl option."); diff --git a/src/thread.rs b/src/thread.rs index c4e0f9be1877..eb7af536cf11 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -254,11 +254,16 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { self.threads[thread_id].state = ThreadState::Enabled; } - /// Get the borrow of the currently active thread. + /// Get a mutable borrow of the currently active thread. fn active_thread_mut(&mut self) -> &mut Thread<'mir, 'tcx> { &mut self.threads[self.active_thread] } + /// Get a shared borrow of the currently active thread. + fn active_thread_ref(&self) -> &Thread<'mir, 'tcx> { + &self.threads[self.active_thread] + } + /// Mark the thread as detached, which means that no other thread will try /// to join it and the thread is responsible for cleaning up. fn detach_thread(&mut self, id: ThreadId) -> InterpResult<'tcx> { @@ -304,9 +309,9 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Get the name of the active thread. - fn get_thread_name(&mut self) -> InterpResult<'tcx, Vec> { - if let Some(ref thread_name) = self.active_thread_mut().thread_name { - Ok(thread_name.clone()) + fn get_thread_name(&self) -> InterpResult<'tcx, &[u8]> { + if let Some(ref thread_name) = self.active_thread_ref().thread_name { + Ok(thread_name) } else { throw_ub_format!("thread {:?} has no name set", self.active_thread) } @@ -557,8 +562,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[inline] - fn get_active_thread_name(&mut self) -> InterpResult<'tcx, Vec> { - let this = self.eval_context_mut(); + fn get_active_thread_name<'c>(&'c self) -> InterpResult<'tcx, &'c [u8]> + where + 'mir: 'c, + { + let this = self.eval_context_ref(); this.machine.threads.get_thread_name() } From bc9d007e3eccae1bbb7b90bbfd2c2d583e44166f Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Fri, 24 Apr 2020 16:47:18 -0700 Subject: [PATCH 1978/5092] Improve Debug formatting of the thread name. --- src/thread.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/thread.rs b/src/thread.rs index eb7af536cf11..ecdaced3f8c5 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -132,13 +132,9 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> { impl<'mir, 'tcx> std::fmt::Debug for Thread<'mir, 'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if let Some(ref name) = self.thread_name { - if let Ok(name_str) = std::str::from_utf8(name) { - write!(f, "{}", name_str)?; - } else { - write!(f, "")?; - } + write!(f, "{}", String::from_utf8_lossy(name))?; } else { - write!(f, "unnamed")?; + write!(f, "")?; } write!(f, "({:?}, {:?})", self.state, self.join_status) } From ff5e35b90a7717bffb4bf2f1ae898e2c73920281 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 26 Apr 2020 14:24:48 -0700 Subject: [PATCH 1979/5092] Added a test that joining main is UB. --- .../concurrency/libc_pthread_join_main.rs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/compile-fail/concurrency/libc_pthread_join_main.rs diff --git a/tests/compile-fail/concurrency/libc_pthread_join_main.rs b/tests/compile-fail/concurrency/libc_pthread_join_main.rs new file mode 100644 index 000000000000..69e1a68ef97a --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_join_main.rs @@ -0,0 +1,20 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +// Joining the main thread is undefined behavior. + +#![feature(rustc_private)] + +extern crate libc; + +use std::{ptr, thread}; + +fn main() { + let thread_id: libc::pthread_t = unsafe { libc::pthread_self() }; + let handle = thread::spawn(move || { + unsafe { + assert_eq!(libc::pthread_join(thread_id, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join a detached or already joined thread + } + }); + thread::yield_now(); + handle.join().unwrap(); +} From 64164b10e8b321745284bf7da7656e464b4ec9f4 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 26 Apr 2020 14:42:07 -0700 Subject: [PATCH 1980/5092] Improve comments. --- src/thread.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/thread.rs b/src/thread.rs index ecdaced3f8c5..9a332a0dcf2c 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -61,7 +61,8 @@ impl ThreadId { } } -/// An identifier of a set of blocked threads. +/// An identifier of a set of blocked threads. 0 is used to indicate the absence +/// of a blockset identifier and, therefore, is not a valid identifier. #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] pub struct BlockSetId(NonZeroU32); @@ -116,8 +117,8 @@ pub struct Thread<'mir, 'tcx> { } impl<'mir, 'tcx> Thread<'mir, 'tcx> { - /// Check if the thread terminated. If yes, change the state to terminated - /// and return `true`. + /// Check if the thread is done executing (no more stack frames). If yes, + /// change the state to terminated and return `true`. fn check_terminated(&mut self) -> bool { if self.state == ThreadState::Enabled { if self.stack.is_empty() { @@ -174,6 +175,7 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { let mut threads = IndexVec::new(); // Create the main thread and add it to the list of threads. let mut main_thread = Thread::default(); + // The main thread can *not* be joined on. main_thread.join_status = ThreadJoinStatus::Detached; threads.push(main_thread); Self { @@ -282,7 +284,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { self.threads .iter() .all(|thread| thread.state != ThreadState::BlockedOnJoin(joined_thread_id)), - "a joinable thread has threads waiting for its termination" + "a joinable thread already has threads waiting for its termination" ); // Mark the joined thread as being joined so that we detect if other // threads try to join it. @@ -349,7 +351,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// The currently implemented scheduling policy is the one that is commonly /// used in stateless model checkers such as Loom: run the active thread as /// long as we can and switch only when we have to (the active thread was - /// blocked, terminated, or was explicitly asked to be preempted). + /// blocked, terminated, or has explicitly asked to be preempted). fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { if self.threads[self.active_thread].check_terminated() { // Check if we need to unblock any threads. From 60cd8aa4b0dadaf5e32bcf86ee6cbddb93c69c01 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 26 Apr 2020 14:44:59 -0700 Subject: [PATCH 1981/5092] Delete a duplicate test. --- .../concurrency/dangling_tls_lib.rs | 49 ------------------- 1 file changed, 49 deletions(-) delete mode 100644 tests/compile-fail/concurrency/dangling_tls_lib.rs diff --git a/tests/compile-fail/concurrency/dangling_tls_lib.rs b/tests/compile-fail/concurrency/dangling_tls_lib.rs deleted file mode 100644 index 6be5538bb444..000000000000 --- a/tests/compile-fail/concurrency/dangling_tls_lib.rs +++ /dev/null @@ -1,49 +0,0 @@ -// ignore-windows: Concurrency on Windows is not supported yet. - -//! Check that we catch if a thread local is accessed after the thread has -//! terminated. - -#![feature(thread_local_internals)] - -use std::cell::RefCell; -use std::thread; - -static A: std::thread::LocalKey> = { - #[inline] - fn __init() -> RefCell { - RefCell::new(0) - } - - unsafe fn __getit() -> Option<&'static RefCell> { - static __KEY: std::thread::__OsLocalKeyInner> = - std::thread::__OsLocalKeyInner::new(); - __KEY.get(__init) - } - - unsafe { std::thread::LocalKey::new(__getit) } -}; - -struct Sender(*mut u8); - -unsafe impl Send for Sender {} - -fn main() { - A.with(|f| { - assert_eq!(*f.borrow(), 0); - *f.borrow_mut() = 4; - }); - - let handle = thread::spawn(|| { - let ptr = A.with(|f| { - assert_eq!(*f.borrow(), 0); - *f.borrow_mut() = 5; - &mut *f.borrow_mut() as *mut u8 - }); - Sender(ptr) - }); - let ptr = handle.join().unwrap().0; - A.with(|f| { - assert_eq!(*f.borrow(), 4); - }); - let _x = unsafe { *ptr }; //~ ERROR Undefined Behavior -} From 39efdf31cf4f69ac0e33f79efe83243c6cdb4d35 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 26 Apr 2020 14:56:31 -0700 Subject: [PATCH 1982/5092] Move prctl test to the same file as other libc tests. --- .../concurrency/libc_prctl_thread_name.rs | 18 ------------------ tests/run-pass/libc.rs | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 18 deletions(-) delete mode 100644 tests/run-pass/concurrency/libc_prctl_thread_name.rs diff --git a/tests/run-pass/concurrency/libc_prctl_thread_name.rs b/tests/run-pass/concurrency/libc_prctl_thread_name.rs deleted file mode 100644 index b8ba27b3a895..000000000000 --- a/tests/run-pass/concurrency/libc_prctl_thread_name.rs +++ /dev/null @@ -1,18 +0,0 @@ -// ignore-windows: No libc on Windows -// ignore-macos: No prctl on MacOS - -#![feature(rustc_private)] - -extern crate libc; - -use std::ffi::CString; - -fn main() { - unsafe { - let thread_name = CString::new("hello").expect("CString::new failed"); - assert_eq!(libc::prctl(libc::PR_SET_NAME, thread_name.as_ptr() as libc::c_long, 0 as libc::c_long, 0 as libc::c_long, 0 as libc::c_long), 0); - let mut buf = [0; 6]; - assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr() as libc::c_long, 0 as libc::c_long, 0 as libc::c_long, 0 as libc::c_long), 0); - assert_eq!(thread_name.as_bytes_with_nul(), buf); - } -} diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index 14d12de0d186..5873d4296950 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -141,6 +141,20 @@ fn test_rwlock_libc_static_initializer() { } } +/// Test whether the `prctl` shim correctly sets the thread name. +/// +/// Note: `prctl` exists only on Linux. +fn test_prctl_thread_name() { + use std::ffi::CString; + unsafe { + let thread_name = CString::new("hello").expect("CString::new failed"); + assert_eq!(libc::prctl(libc::PR_SET_NAME, thread_name.as_ptr() as libc::c_long, 0 as libc::c_long, 0 as libc::c_long, 0 as libc::c_long), 0); + let mut buf = [0; 6]; + assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr() as libc::c_long, 0 as libc::c_long, 0 as libc::c_long, 0 as libc::c_long), 0); + assert_eq!(thread_name.as_bytes_with_nul(), buf); + } +} + fn main() { #[cfg(target_os = "linux")] test_posix_fadvise(); @@ -152,4 +166,7 @@ fn main() { #[cfg(target_os = "linux")] test_mutex_libc_static_initializer_recursive(); + + #[cfg(target_os = "linux")] + test_prctl_thread_name(); } From 6842eb2b84337ff01158ca7c0eee669b0d1e061f Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 26 Apr 2020 15:52:01 -0700 Subject: [PATCH 1983/5092] Rename global tls dtor to thread dtor. --- src/shims/foreign_items/posix/macos.rs | 2 +- src/shims/tls.rs | 39 ++++++++++++++------------ 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 9f6ea00b0313..200b88f29c8f 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -83,7 +83,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dtor = this.memory.get_fn(dtor)?.as_instance()?; let data = this.read_scalar(args[1])?.not_undef()?; let active_thread = this.get_active_thread()?; - this.machine.tls.set_thread_global_dtor(active_thread, dtor, data)?; + this.machine.tls.set_thread_dtor(active_thread, dtor, data)?; } // Querying system information diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 615950621a24..d3d50977320b 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -33,8 +33,9 @@ pub struct TlsData<'tcx> { /// pthreads-style thread-local storage. keys: BTreeMap>, - /// A single global per thread dtor (that's how things work on macOS) with a data argument. - global_dtors: BTreeMap, Scalar)>, + /// A single per thread destructor of the thread local storage (that's how + /// things work on macOS) with a data argument. + thread_dtors: BTreeMap, Scalar)>, /// Whether we are in the "destruct" phase, during which some operations are UB. dtors_running: HashSet, @@ -48,7 +49,7 @@ impl<'tcx> Default for TlsData<'tcx> { TlsData { next_key: 1, // start with 1 as we must not use 0 on Windows keys: Default::default(), - global_dtors: Default::default(), + thread_dtors: Default::default(), dtors_running: Default::default(), last_dtor_key: Default::default(), } @@ -117,16 +118,16 @@ impl<'tcx> TlsData<'tcx> { } } - /// Set global dtor for the given thread. This function is used to implement - /// `_tlv_atexit` shim on MacOS. + /// Set the thread wide destructor of the thread local storage for the given + /// thread. This function is used to implement `_tlv_atexit` shim on MacOS. /// - /// Global destructors are available only on MacOS and (potentially - /// confusingly) they seem to be still per thread as can be guessed from the - /// following comment in the [`_tlv_atexit` + /// Thread wide dtors are available only on MacOS. There is one destructor + /// per thread as can be guessed from the following comment in the + /// [`_tlv_atexit` /// implementation](https://github.com/opensource-apple/dyld/blob/195030646877261f0c8c7ad8b001f52d6a26f514/src/threadLocalVariables.c#L389): /// /// // NOTE: this does not need locks because it only operates on current thread data - pub fn set_thread_global_dtor( + pub fn set_thread_dtor( &mut self, thread: ThreadId, dtor: ty::Instance<'tcx>, @@ -134,10 +135,10 @@ impl<'tcx> TlsData<'tcx> { ) -> InterpResult<'tcx> { if self.dtors_running.contains(&thread) { // UB, according to libstd docs. - throw_ub_format!("setting global destructor while destructors are already running"); + throw_ub_format!("setting thread's local storage destructor while destructors are already running"); } - if self.global_dtors.insert(thread, (dtor, data)).is_some() { - throw_unsup_format!("setting more than one global destructor for the same thread is not supported"); + if self.thread_dtors.insert(thread, (dtor, data)).is_some() { + throw_unsup_format!("setting more than one thread local storage destructor for the same thread is not supported"); } Ok(()) } @@ -223,15 +224,15 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - /// Schedule the MacOS global dtor to be executed. + /// Schedule the MacOS thread destructor of the thread local storage to be + /// executed. /// /// Note: It is safe to call this function also on other Unixes. - fn schedule_macos_global_tls_dtors(&mut self) -> InterpResult<'tcx> { + fn schedule_macos_tls_dtor(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let thread_id = this.get_active_thread()?; - // The macOS global dtor runs "before any TLS slots get freed", so do that first. - if let Some((instance, data)) = this.machine.tls.global_dtors.remove(&thread_id) { - trace!("Running global dtor {:?} on {:?} at {:?}", instance, data, thread_id); + if let Some((instance, data)) = this.machine.tls.thread_dtors.remove(&thread_id) { + trace!("Running macos dtor {:?} on {:?} at {:?}", instance, data, thread_id); let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); this.call_function( @@ -306,7 +307,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } else { this.machine.tls.dtors_running.insert(active_thread); - this.schedule_macos_global_tls_dtors()?; + // The macOS thread wide destructor runs "before any TLS slots get + // freed", so do that first. + this.schedule_macos_tls_dtor()?; this.schedule_pthread_tls_dtors()?; } From c4574dde8dbd3f996418927a3edc8a83e9709f9c Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 26 Apr 2020 15:52:45 -0700 Subject: [PATCH 1984/5092] Many small changes to clean up code. --- src/shims/thread.rs | 44 +++++++++++--------------------------------- src/shims/tls.rs | 8 +++++--- src/thread.rs | 7 +++++++ 3 files changed, 23 insertions(+), 36 deletions(-) diff --git a/src/shims/thread.rs b/src/shims/thread.rs index 67e833f222e4..c2ef27223780 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -1,5 +1,4 @@ use crate::*; -use rustc_index::vec::Idx; use rustc_target::abi::LayoutOf; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -19,18 +18,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); let new_thread_id = this.create_thread()?; + // Also switch to new thread so that we can push the first stackframe. let old_thread_id = this.set_active_thread(new_thread_id)?; let thread_info_place = this.deref_operand(thread)?; - let thread_info_type = thread.layout.ty - .builtin_deref(true) - .ok_or_else(|| err_ub_format!( - "wrong signature used for `pthread_create`: first argument must be a raw pointer." - ))? - .ty; - let thread_info_layout = this.layout_of(thread_info_type)?; this.write_scalar( - Scalar::from_uint(new_thread_id.index() as u128, thread_info_layout.size), + Scalar::from_uint(new_thread_id.to_u128(), thread_info_place.layout.size), thread_info_place.into(), )?; @@ -38,14 +31,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let instance = this.memory.get_fn(fn_ptr)?.as_instance()?; let func_arg = this.read_immediate(arg)?; - let func_args = [*func_arg]; let ret_place = this.allocate(this.layout_of(this.tcx.types.usize)?, MiriMemoryKind::Machine.into()); this.call_function( instance, - &func_args[..], + &[*func_arg], Some(ret_place.into()), StackPopCleanup::None { cleanup: true }, )?; @@ -66,7 +58,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("Miri supports pthread_join only with retval==NULL"); } - let thread_id = this.read_scalar(thread)?.not_undef()?.to_machine_usize(this)?; + let thread_id = this.read_scalar(thread)?.to_machine_usize(this)?; this.join_thread(thread_id.into())?; Ok(0) @@ -75,7 +67,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_detach(&mut self, thread: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let thread_id = this.read_scalar(thread)?.not_undef()?.to_machine_usize(this)?; + let thread_id = this.read_scalar(thread)?.to_machine_usize(this)?; this.detach_thread(thread_id.into())?; Ok(0) @@ -85,34 +77,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let thread_id = this.get_active_thread()?; - this.write_scalar(Scalar::from_uint(thread_id.index() as u128, dest.layout.size), dest) + this.write_scalar(Scalar::from_uint(thread_id.to_u128(), dest.layout.size), dest) } fn prctl( &mut self, option: OpTy<'tcx, Tag>, arg2: OpTy<'tcx, Tag>, - arg3: OpTy<'tcx, Tag>, - arg4: OpTy<'tcx, Tag>, - arg5: OpTy<'tcx, Tag>, + _arg3: OpTy<'tcx, Tag>, + _arg4: OpTy<'tcx, Tag>, + _arg5: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // prctl last 5 arguments are declared as variadic. Therefore, we need - // to check their types manually. - let c_long_size = this.libc_ty_layout("c_long")?.size.bytes(); - let check_arg = |arg: OpTy<'tcx, Tag>| -> InterpResult<'tcx> { - match this.read_scalar(arg)?.not_undef()? { - Scalar::Raw { size, .. } if u64::from(size) == c_long_size => Ok(()), - _ => throw_ub_format!("an argument of unsupported type was passed to prctl"), - } - }; - check_arg(arg2)?; - check_arg(arg3)?; - check_arg(arg4)?; - check_arg(arg5)?; - - let option = this.read_scalar(option)?.not_undef()?.to_i32()?; + let option = this.read_scalar(option)?.to_i32()?; if option == this.eval_libc_i32("PR_SET_NAME")? { let address = this.read_scalar(arg2)?.not_undef()?; let name = this.memory.read_c_str(address)?.to_owned(); @@ -122,7 +100,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name = this.get_active_thread_name()?.to_vec(); this.memory.write_bytes(address, name)?; } else { - throw_unsup_format!("Unsupported prctl option."); + throw_unsup_format!("unsupported prctl option {}", option); } Ok(0) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index d3d50977320b..087b44af2f58 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -20,7 +20,6 @@ pub type TlsKey = u128; pub struct TlsEntry<'tcx> { /// The data for this key. None is used to represent NULL. /// (We normalize this early to avoid having to do a NULL-ptr-test each time we access the data.) - /// Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. data: BTreeMap>, dtor: Option>, } @@ -89,7 +88,7 @@ impl<'tcx> TlsData<'tcx> { ) -> InterpResult<'tcx, Scalar> { match self.keys.get(&key) { Some(TlsEntry { data, .. }) => { - let value = data.get(&thread_id).cloned(); + let value = data.get(&thread_id).copied(); trace!("TLS key {} for thread {:?} loaded: {:?}", key, thread_id, value); Ok(value.unwrap_or_else(|| Scalar::null_ptr(cx).into())) } @@ -99,7 +98,10 @@ impl<'tcx> TlsData<'tcx> { pub fn store_tls( &mut self, - key: TlsKey, thread_id: ThreadId, new_data: Option>) -> InterpResult<'tcx> { + key: TlsKey, + thread_id: ThreadId, + new_data: Option> + ) -> InterpResult<'tcx> { match self.keys.get_mut(&key) { Some(TlsEntry { data, .. }) => { match new_data { diff --git a/src/thread.rs b/src/thread.rs index 9a332a0dcf2c..f9094d771e6d 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -1,5 +1,6 @@ //! Implements threads. +use std::convert::TryInto; use std::cell::RefCell; use std::convert::TryFrom; use std::num::NonZeroU32; @@ -34,6 +35,12 @@ pub struct ThreadId(usize); /// The main thread. When it terminates, the whole application terminates. const MAIN_THREAD: ThreadId = ThreadId(0); +impl ThreadId { + pub fn to_u128(self) -> u128 { + self.0.try_into().unwrap() + } +} + impl Idx for ThreadId { fn new(idx: usize) -> Self { ThreadId(idx) From 911ff7eade22e7bd15e79167a22845005f29b3fb Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 26 Apr 2020 20:49:53 -0700 Subject: [PATCH 1985/5092] Improve style and comments. --- src/eval.rs | 2 +- src/shims/tls.rs | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 9131946f8dc1..89d61d141a23 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -211,7 +211,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> assert!(ecx.step()?, "a terminated thread was scheduled for execution"); } SchedulingAction::ExecuteDtors => { - ecx.schedule_tls_dtors_for_active_thread()?; + ecx.schedule_next_tls_dtor_for_active_thread()?; } SchedulingAction::Stop => { break; diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 087b44af2f58..54850de82c87 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -105,9 +105,9 @@ impl<'tcx> TlsData<'tcx> { match self.keys.get_mut(&key) { Some(TlsEntry { data, .. }) => { match new_data { - Some(ptr) => { - trace!("TLS key {} for thread {:?} stored: {:?}", key, thread_id, ptr); - data.insert(thread_id, ptr); + Some(scalar) => { + trace!("TLS key {} for thread {:?} stored: {:?}", key, thread_id, scalar); + data.insert(thread_id, scalar); } None => { trace!("TLS key {} for thread {:?} removed", key, thread_id); @@ -271,7 +271,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some((instance, ptr, key)) = dtor { this.machine.tls.last_dtor_key.insert(active_thread, key); trace!("Running TLS dtor {:?} on {:?} at {:?}", instance, ptr, active_thread); - assert!(!this.is_null(ptr).unwrap(), "Data can't be NULL when dtor is called!"); + assert!(!this.is_null(ptr).unwrap(), "data can't be NULL when dtor is called!"); let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); this.call_function( @@ -295,10 +295,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Schedule an active thread's TLS destructor to run on the active thread. /// Note that this function does not run the destructors itself, it just - /// schedules them one by one each time it is called. + /// schedules them one by one each time it is called and reenables the + /// thread so that it can be executed normally by the main execution loop. /// /// FIXME: we do not support yet deallocation of thread local statics. - fn schedule_tls_dtors_for_active_thread(&mut self) -> InterpResult<'tcx> { + /// Issue: https://github.com/rust-lang/miri/issues/1369 + fn schedule_next_tls_dtor_for_active_thread(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let active_thread = this.get_active_thread()?; From d9e18ada39b52518c70df7801be564e58f4e8a66 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 26 Apr 2020 20:50:58 -0700 Subject: [PATCH 1986/5092] Make sure to remove thread local data only if we have destructor. --- src/shims/tls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 54850de82c87..7d4aae367082 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -181,8 +181,8 @@ impl<'tcx> TlsData<'tcx> { { match data.entry(thread_id) { Entry::Occupied(entry) => { - let data_scalar = entry.remove(); if let Some(dtor) = dtor { + let data_scalar = entry.remove(); let ret = Some((*dtor, data_scalar, key)); return ret; } From 174adad2b34ddacc129232c6127a260270d1f52a Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 26 Apr 2020 20:51:21 -0700 Subject: [PATCH 1987/5092] Use DLL_THREAD_DETACH when calling windows TLS destructor. --- src/shims/tls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 7d4aae367082..eb8c99b72f6f 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -213,7 +213,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let thread_callback = this.memory.get_fn(thread_callback.not_undef()?)?.as_instance()?; // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. - let reason = this.eval_path_scalar(&["std", "sys", "windows", "c", "DLL_PROCESS_DETACH"])?; + let reason = this.eval_path_scalar(&["std", "sys", "windows", "c", "DLL_THREAD_DETACH"])?; let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); this.call_function( thread_callback, From 9ba3ef2a44118fb2692a65a04500cdef4f6036d5 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 26 Apr 2020 21:01:03 -0700 Subject: [PATCH 1988/5092] Change representation and conversion of ThreadId and BlockSetId. --- src/shims/sync.rs | 6 +++--- src/thread.rs | 20 +++++++++----------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 97afbbe98f6a..b0605b4e8146 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -158,7 +158,7 @@ fn mutex_get_or_create_blockset<'mir, 'tcx: 'mir>( mutex_set_blockset(ecx, mutex_op, blockset.to_u32_scalar())?; Ok(blockset) } else { - Ok(blockset.into()) + Ok(BlockSetId::new(blockset)) } } @@ -233,7 +233,7 @@ fn rwlock_get_or_create_writer_blockset<'mir, 'tcx: 'mir>( rwlock_set_writer_blockset(ecx, rwlock_op, blockset.to_u32_scalar())?; Ok(blockset) } else { - Ok(blockset.into()) + Ok(BlockSetId::new(blockset)) } } @@ -264,7 +264,7 @@ fn rwlock_get_or_create_reader_blockset<'mir, 'tcx: 'mir>( rwlock_set_reader_blockset(ecx, rwlock_op, blockset.to_u32_scalar())?; Ok(blockset) } else { - Ok(blockset.into()) + Ok(BlockSetId::new(blockset)) } } diff --git a/src/thread.rs b/src/thread.rs index f9094d771e6d..749d6bf955f2 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -30,7 +30,7 @@ pub enum SchedulingAction { /// A thread identifier. #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] -pub struct ThreadId(usize); +pub struct ThreadId(u32); /// The main thread. When it terminates, the whole application terminates. const MAIN_THREAD: ThreadId = ThreadId(0); @@ -43,22 +43,22 @@ impl ThreadId { impl Idx for ThreadId { fn new(idx: usize) -> Self { - ThreadId(idx) + ThreadId(u32::try_from(idx).unwrap()) } fn index(self) -> usize { - self.0 + usize::try_from(self.0).unwrap() } } impl From for ThreadId { fn from(id: u64) -> Self { - Self(usize::try_from(id).unwrap()) + Self(u32::try_from(id).unwrap()) } } impl From for ThreadId { fn from(id: u32) -> Self { - Self(usize::try_from(id).unwrap()) + Self(u32::try_from(id).unwrap()) } } @@ -73,13 +73,11 @@ impl ThreadId { #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] pub struct BlockSetId(NonZeroU32); -impl From for BlockSetId { - fn from(id: u32) -> Self { +impl BlockSetId { + /// Panics if `id` is 0. + pub fn new(id: u32) -> Self { Self(NonZeroU32::new(id).expect("0 is not a valid blockset id")) } -} - -impl BlockSetId { pub fn to_u32_scalar<'tcx>(&self) -> Scalar { Scalar::from_u32(self.0.get()) } @@ -325,7 +323,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Allocate a new blockset id. fn create_blockset(&mut self) -> BlockSetId { self.blockset_counter = self.blockset_counter.checked_add(1).unwrap(); - self.blockset_counter.into() + BlockSetId::new(self.blockset_counter) } /// Block the currently active thread and put it into the given blockset. From 207c6e7fa74758a64104c2d77218e263d92cf1c6 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 26 Apr 2020 21:13:33 -0700 Subject: [PATCH 1989/5092] Improve comments and code clarity. --- src/shims/sync.rs | 16 ++++++++++------ src/thread.rs | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index b0605b4e8146..9dad302706c2 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -80,7 +80,8 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( // bytes 8-11: when count > 0, id of the owner thread as a u32 // bytes 12-15 or 16-19 (depending on platform): mutex kind, as an i32 // (the kind has to be at its offset for compatibility with static initializer macros) -// bytes 20-23: when count > 0, id of the blockset in which the blocked threads are waiting. +// bytes 20-23: when count > 0, id of the blockset in which the blocked threads +// are waiting or 0 if blockset is not yet assigned. const PTHREAD_MUTEX_T_MIN_SIZE: u64 = 24; @@ -170,9 +171,9 @@ fn mutex_get_or_create_blockset<'mir, 'tcx: 'mir>( // bytes 4-7: reader count, as a u32 // bytes 8-11: writer count, as a u32 // bytes 12-15: when writer or reader count > 0, id of the blockset in which the -// blocked writers are waiting. +// blocked writers are waiting or 0 if blockset is not yet assigned. // bytes 16-20: when writer count > 0, id of the blockset in which the blocked -// readers are waiting. +// readers are waiting or 0 if blockset is not yet assigned. const PTHREAD_RWLOCK_T_MIN_SIZE: u64 = 20; @@ -342,8 +343,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } else { // The mutex is locked. Let's check by whom. - let owner_thread: ThreadId = - mutex_get_owner(this, mutex_op)?.not_undef()?.to_u32()?.into(); + let owner_thread: ThreadId = mutex_get_owner(this, mutex_op)?.to_u32()?.into(); if owner_thread != active_thread { // Block the active thread. let blockset = mutex_get_or_create_blockset(this, mutex_op)?; @@ -425,6 +425,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex_set_owner(this, mutex_op, new_owner.to_u32_scalar())?; } else { // No thread is waiting on this mutex. + mutex_set_owner(this, mutex_op, Scalar::from_u32(0))?; mutex_set_locked_count(this, mutex_op, Scalar::from_u32(0))?; } Ok(0) @@ -550,10 +551,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } else if writers != 0 { let reader_blockset = rwlock_get_or_create_reader_blockset(this, rwlock_op)?; - rwlock_set_writers(this, rwlock_op, Scalar::from_u32(0))?; + // We are prioritizing writers here against the readers. As a + // result, not only readers can starve writers, but also writers can + // starve readers. if let Some(_writer) = this.unblock_some_thread(writer_blockset)? { rwlock_set_writers(this, rwlock_op, Scalar::from_u32(1))?; } else { + rwlock_set_writers(this, rwlock_op, Scalar::from_u32(0))?; let mut readers = 0; while let Some(_reader) = this.unblock_some_thread(reader_blockset)? { readers += 1; diff --git a/src/thread.rs b/src/thread.rs index 749d6bf955f2..9408dbe56cd9 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -1,8 +1,8 @@ //! Implements threads. -use std::convert::TryInto; use std::cell::RefCell; use std::convert::TryFrom; +use std::convert::TryInto; use std::num::NonZeroU32; use log::trace; From 356aecce7f3c438db6804a72a5022a2537d35104 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 26 Apr 2020 21:25:46 -0700 Subject: [PATCH 1990/5092] Add a FIXME. --- src/shims/thread.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shims/thread.rs b/src/shims/thread.rs index c2ef27223780..27e998085290 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -55,6 +55,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); if !this.is_null(this.read_scalar(retval)?.not_undef()?)? { + // FIXME: implement reading the thread function's return place. throw_unsup_format!("Miri supports pthread_join only with retval==NULL"); } From f204b67b0f5ae6f498d29938790cd989e58f5bec Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 26 Apr 2020 21:49:36 -0700 Subject: [PATCH 1991/5092] Merge dtors_running and last_dtor_key fields. --- src/shims/tls.rs | 47 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index eb8c99b72f6f..a98a80256414 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -2,10 +2,10 @@ use std::collections::BTreeMap; use std::collections::btree_map::Entry; -use std::collections::HashSet; use log::trace; +use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty; use rustc_target::abi::{Size, HasDataLayout}; @@ -24,6 +24,12 @@ pub struct TlsEntry<'tcx> { dtor: Option>, } +#[derive(Clone, Debug)] +struct RunningDtorsState { + /// The last TlsKey used to retrieve a TLS destructor. + last_dtor_key: Option, +} + #[derive(Debug)] pub struct TlsData<'tcx> { /// The Key to use for the next thread-local allocation. @@ -36,11 +42,10 @@ pub struct TlsData<'tcx> { /// things work on macOS) with a data argument. thread_dtors: BTreeMap, Scalar)>, - /// Whether we are in the "destruct" phase, during which some operations are UB. - dtors_running: HashSet, - - /// The last TlsKey used to retrieve a TLS destructor. - last_dtor_key: BTreeMap, + /// State for currently running TLS dtors. If this map contains a key for a + /// specific thread, it means that we are in the "destruct" phase, during + /// which some operations are UB. + dtors_running: FxHashMap, } impl<'tcx> Default for TlsData<'tcx> { @@ -50,7 +55,6 @@ impl<'tcx> Default for TlsData<'tcx> { keys: Default::default(), thread_dtors: Default::default(), dtors_running: Default::default(), - last_dtor_key: Default::default(), } } } @@ -135,7 +139,7 @@ impl<'tcx> TlsData<'tcx> { dtor: ty::Instance<'tcx>, data: Scalar ) -> InterpResult<'tcx> { - if self.dtors_running.contains(&thread) { + if self.dtors_running.contains_key(&thread) { // UB, according to libstd docs. throw_ub_format!("setting thread's local storage destructor while destructors are already running"); } @@ -192,6 +196,21 @@ impl<'tcx> TlsData<'tcx> { } None } + + /// Set that dtors are running for `thread`. It is guaranteed not to change + /// the existing values stored in `dtors_running` for this thread. Returns + /// `true` if dtors for `thread` are already running. + fn set_dtors_running_for_thread(&mut self, thread: ThreadId) -> bool { + if self.dtors_running.contains_key(&thread) { + true + } else { + self.dtors_running.insert( + thread, + RunningDtorsState { last_dtor_key: None } + ); + false + } + } } impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -203,7 +222,6 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let active_thread = this.get_active_thread()?; assert_eq!(this.get_total_thread_count()?, 1, "concurrency on Windows not supported"); - this.machine.tls.dtors_running.insert(active_thread); // Windows has a special magic linker section that is run on certain events. // Instead of searching for that section and supporting arbitrary hooks in there // (that would be basically https://github.com/rust-lang/miri/issues/450), @@ -260,7 +278,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert!(this.has_terminated(active_thread)?, "running TLS dtors for non-terminated thread"); // Fetch next dtor after `key`. - let last_key = this.machine.tls.last_dtor_key.get(&active_thread).cloned(); + let last_key = this.machine.tls.dtors_running[&active_thread].last_dtor_key.clone(); let dtor = match this.machine.tls.fetch_tls_dtor(last_key, active_thread) { dtor @ Some(_) => dtor, // We ran each dtor once, start over from the beginning. @@ -269,7 +287,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } }; if let Some((instance, ptr, key)) = dtor { - this.machine.tls.last_dtor_key.insert(active_thread, key); + this.machine.tls.dtors_running.get_mut(&active_thread).unwrap().last_dtor_key = Some(key); trace!("Running TLS dtor {:?} on {:?} at {:?}", instance, ptr, active_thread); assert!(!this.is_null(ptr).unwrap(), "data can't be NULL when dtor is called!"); @@ -284,7 +302,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.enable_thread(active_thread)?; return Ok(()); } - this.machine.tls.last_dtor_key.remove(&active_thread); + this.machine.tls.dtors_running.get_mut(&active_thread).unwrap().last_dtor_key = None; Ok(()) } @@ -305,12 +323,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let active_thread = this.get_active_thread()?; if this.tcx.sess.target.target.target_os == "windows" { - if !this.machine.tls.dtors_running.contains(&active_thread) { - this.machine.tls.dtors_running.insert(active_thread); + if !this.machine.tls.set_dtors_running_for_thread(active_thread) { this.schedule_windows_tls_dtors()?; } } else { - this.machine.tls.dtors_running.insert(active_thread); + this.machine.tls.set_dtors_running_for_thread(active_thread); // The macOS thread wide destructor runs "before any TLS slots get // freed", so do that first. this.schedule_macos_tls_dtor()?; From 331dbd1469abb9ee7959684305732b0613f0bf15 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 26 Apr 2020 22:05:09 -0700 Subject: [PATCH 1992/5092] Add a test for joining in a destructor. --- tests/run-pass/concurrency/tls_lib_drop.rs | 45 +++++++++++++++++-- .../run-pass/concurrency/tls_lib_drop.stdout | 2 + 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/tests/run-pass/concurrency/tls_lib_drop.rs b/tests/run-pass/concurrency/tls_lib_drop.rs index 0d1808cbe0fa..de2566de85c6 100644 --- a/tests/run-pass/concurrency/tls_lib_drop.rs +++ b/tests/run-pass/concurrency/tls_lib_drop.rs @@ -1,8 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -//! Check that destructors of the library thread locals are executed immediately -//! after a thread terminates. - use std::cell::RefCell; use std::thread; @@ -20,7 +17,9 @@ thread_local! { static A: TestCell = TestCell { value: RefCell::new(0) }; } -fn main() { +/// Check that destructors of the library thread locals are executed immediately +/// after a thread terminates. +fn check_destructors() { thread::spawn(|| { A.with(|f| { assert_eq!(*f.value.borrow(), 0); @@ -31,3 +30,41 @@ fn main() { .unwrap(); println!("Continue main.") } + +struct JoinCell { + value: RefCell>>, +} + +impl Drop for JoinCell { + fn drop(&mut self) { + let join_handle = self.value.borrow_mut().take().unwrap(); + println!("Joining: {}", join_handle.join().unwrap()); + } +} + +thread_local! { + static B: JoinCell = JoinCell { value: RefCell::new(None) }; +} + +/// Check that the destructor can be blocked joining another thread. +fn check_blocking() { + thread::spawn(|| { + B.with(|f| { + assert!(f.value.borrow().is_none()); + let handle = thread::spawn(|| 7); + *f.value.borrow_mut() = Some(handle); + }); + }) + .join() + .unwrap(); + println!("Continue main 2."); + // Preempt the main thread so that the destructor gets executed and can join + // the thread. + thread::yield_now(); + thread::yield_now(); +} + +fn main() { + check_destructors(); + check_blocking(); +} diff --git a/tests/run-pass/concurrency/tls_lib_drop.stdout b/tests/run-pass/concurrency/tls_lib_drop.stdout index d2bbb866b77e..d622c0ccce88 100644 --- a/tests/run-pass/concurrency/tls_lib_drop.stdout +++ b/tests/run-pass/concurrency/tls_lib_drop.stdout @@ -1,2 +1,4 @@ Dropping: 5 Continue main. +Continue main 2. +Joining: 7 From c56ef31780c63e03ada0a8282e5d95ba1f082d92 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 27 Apr 2020 11:01:35 -0700 Subject: [PATCH 1993/5092] Improve comments. --- src/shims/thread.rs | 3 +++ src/thread.rs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/shims/thread.rs b/src/shims/thread.rs index 27e998085290..d11853d53452 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -32,6 +32,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let func_arg = this.read_immediate(arg)?; + // Note: the returned value is currently ignored (see the FIXME in + // pthread_join below) because the Rust standard library does not use + // it. let ret_place = this.allocate(this.layout_of(this.tcx.types.usize)?, MiriMemoryKind::Machine.into()); diff --git a/src/thread.rs b/src/thread.rs index 9408dbe56cd9..715107530cef 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -358,6 +358,9 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// long as we can and switch only when we have to (the active thread was /// blocked, terminated, or has explicitly asked to be preempted). fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { + // Check whether the thread has **just** terminated (`check_terminated` + // checks whether the thread has popped all its stack and if yes, sets + // the thread state to terminated.) if self.threads[self.active_thread].check_terminated() { // Check if we need to unblock any threads. for (i, thread) in self.threads.iter_enumerated_mut() { From df2ca53b6978c7ac2ec6e271a5ee73fba70877c5 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 27 Apr 2020 12:32:57 -0700 Subject: [PATCH 1994/5092] Make From implementations non-failing. --- src/shims/thread.rs | 6 ++++-- src/thread.rs | 12 +++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/shims/thread.rs b/src/shims/thread.rs index d11853d53452..29a4ed367687 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -1,3 +1,5 @@ +use std::convert::TryInto; + use crate::*; use rustc_target::abi::LayoutOf; @@ -63,7 +65,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let thread_id = this.read_scalar(thread)?.to_machine_usize(this)?; - this.join_thread(thread_id.into())?; + this.join_thread(thread_id.try_into().expect("thread ID should fit in u32"))?; Ok(0) } @@ -72,7 +74,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let thread_id = this.read_scalar(thread)?.to_machine_usize(this)?; - this.detach_thread(thread_id.into())?; + this.detach_thread(thread_id.try_into().expect("thread ID should fit in u32"))?; Ok(0) } diff --git a/src/thread.rs b/src/thread.rs index 715107530cef..69e7bcdb298c 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -3,7 +3,7 @@ use std::cell::RefCell; use std::convert::TryFrom; use std::convert::TryInto; -use std::num::NonZeroU32; +use std::num::{NonZeroU32, TryFromIntError}; use log::trace; @@ -45,20 +45,22 @@ impl Idx for ThreadId { fn new(idx: usize) -> Self { ThreadId(u32::try_from(idx).unwrap()) } + fn index(self) -> usize { usize::try_from(self.0).unwrap() } } -impl From for ThreadId { - fn from(id: u64) -> Self { - Self(u32::try_from(id).unwrap()) +impl TryFrom for ThreadId { + type Error = TryFromIntError; + fn try_from(id: u64) -> Result { + u32::try_from(id).map(|id_u32| Self(id_u32)) } } impl From for ThreadId { fn from(id: u32) -> Self { - Self(u32::try_from(id).unwrap()) + Self(id) } } From 1355574bebb5f7cb572bb7399964f91101e8852e Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 27 Apr 2020 14:00:39 -0700 Subject: [PATCH 1995/5092] Delete remaining tls entries after all destructors completed. --- src/shims/tls.rs | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index a98a80256414..d5ea430dd276 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -211,6 +211,14 @@ impl<'tcx> TlsData<'tcx> { false } } + + /// Delete all TLS entries for the given thread. This function should be + /// called after all TLS destructors have already finished. + fn delete_all_thread_tls(&mut self, thread_id: ThreadId) { + for TlsEntry { data, .. } in self.keys.values_mut() { + data.remove(&thread_id); + } + } } impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -271,8 +279,9 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - /// Schedule a pthread TLS destructor. - fn schedule_pthread_tls_dtors(&mut self) -> InterpResult<'tcx> { + /// Schedule a pthread TLS destructor. Returns `true` if found + /// a destructor to schedule, and `false` otherwise. + fn schedule_pthread_tls_dtors(&mut self) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); let active_thread = this.get_active_thread()?; @@ -300,11 +309,11 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; this.enable_thread(active_thread)?; - return Ok(()); + return Ok(true); } this.machine.tls.dtors_running.get_mut(&active_thread).unwrap().last_dtor_key = None; - Ok(()) + Ok(false) } } @@ -322,16 +331,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let active_thread = this.get_active_thread()?; - if this.tcx.sess.target.target.target_os == "windows" { + let finished = if this.tcx.sess.target.target.target_os == "windows" { if !this.machine.tls.set_dtors_running_for_thread(active_thread) { this.schedule_windows_tls_dtors()?; } + true } else { this.machine.tls.set_dtors_running_for_thread(active_thread); // The macOS thread wide destructor runs "before any TLS slots get // freed", so do that first. this.schedule_macos_tls_dtor()?; - this.schedule_pthread_tls_dtors()?; + this.schedule_pthread_tls_dtors()? + }; + + if finished { + this.machine.tls.delete_all_thread_tls(active_thread); } Ok(()) From 3b5854191c35107a50ff83dd1e8b46f58d964224 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 27 Apr 2020 15:21:01 -0700 Subject: [PATCH 1996/5092] Fix MacOS and Windows builds. --- src/shims/tls.rs | 25 +++++++++++++++++-------- tests/run-pass/libc.rs | 1 + 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index d5ea430dd276..f13d9e6dfee8 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -253,10 +253,10 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Schedule the MacOS thread destructor of the thread local storage to be - /// executed. + /// executed. Returns `true` if scheduled. /// /// Note: It is safe to call this function also on other Unixes. - fn schedule_macos_tls_dtor(&mut self) -> InterpResult<'tcx> { + fn schedule_macos_tls_dtor(&mut self) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); let thread_id = this.get_active_thread()?; if let Some((instance, data)) = this.machine.tls.thread_dtors.remove(&thread_id) { @@ -275,8 +275,10 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // guaranteed that we will schedule it again. The `dtors_running` // flag will prevent the code from adding the destructor again. this.enable_thread(thread_id)?; + Ok(true) + } else { + Ok(false) } - Ok(()) } /// Schedule a pthread TLS destructor. Returns `true` if found @@ -331,20 +333,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let active_thread = this.get_active_thread()?; - let finished = if this.tcx.sess.target.target.target_os == "windows" { + let scheduled_next = if this.tcx.sess.target.target.target_os == "windows" { if !this.machine.tls.set_dtors_running_for_thread(active_thread) { this.schedule_windows_tls_dtors()?; + true + } else { + false } - true } else { this.machine.tls.set_dtors_running_for_thread(active_thread); // The macOS thread wide destructor runs "before any TLS slots get // freed", so do that first. - this.schedule_macos_tls_dtor()?; - this.schedule_pthread_tls_dtors()? + if this.schedule_macos_tls_dtor()? { + true + } else { + this.schedule_pthread_tls_dtors()? + } }; - if finished { + if !scheduled_next { + // No dtors scheduled means that we are finished. Delete the + // remaining TLS entries. this.machine.tls.delete_all_thread_tls(active_thread); } diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index 5873d4296950..36805fc83e30 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -144,6 +144,7 @@ fn test_rwlock_libc_static_initializer() { /// Test whether the `prctl` shim correctly sets the thread name. /// /// Note: `prctl` exists only on Linux. +#[cfg(target_os = "linux")] fn test_prctl_thread_name() { use std::ffi::CString; unsafe { From a5445e0230c7e15357099bcda9e34dc8aa77bc9c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 28 Apr 2020 10:30:21 +0200 Subject: [PATCH 1997/5092] rustup for more LocalDefId changes --- benches/helpers/miri_helper.rs | 2 +- rust-version | 2 +- src/bin/miri-rustc-tests.rs | 2 +- src/bin/miri.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 589a95b668f3..2e71c7eb8b1d 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -26,7 +26,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { self.bencher.iter(|| { let config = miri::MiriConfig::default(); - miri::eval_main(tcx, entry_def_id, config); + miri::eval_main(tcx, entry_def_id.to_def_id(), config); }); }); diff --git a/rust-version b/rust-version index 53979b82cf83..173566bdf616 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e83f7563495dbe2629b0cbc738afb0808c4482e1 +fb5615a4771ea3d54256f969dc84d2dfd38d812c diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index bae7356eb72c..add9cfe897fb 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -54,7 +54,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { tcx.hir().krate().visit_all_item_likes(&mut Visitor(tcx)); } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { let config = miri::MiriConfig::default(); - miri::eval_main(tcx, entry_def_id, config); + miri::eval_main(tcx, entry_def_id.to_def_id(), config); compiler.session().abort_if_errors(); } else { diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 4e20e3a12da7..06101fe24e2d 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -39,7 +39,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { // Add filename to `miri` arguments. config.args.insert(0, compiler.input().filestem().to_string()); - if let Some(return_code) = miri::eval_main(tcx, entry_def_id, config) { + if let Some(return_code) = miri::eval_main(tcx, entry_def_id.to_def_id(), config) { std::process::exit( i32::try_from(return_code).expect("Return value was too large!"), ); From 46b03174d02c06fe062747e732733a39a1971817 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Wed, 29 Apr 2020 13:16:22 -0700 Subject: [PATCH 1998/5092] Improve code readability and comments. --- src/eval.rs | 3 ++ src/shims/sync.rs | 2 +- src/shims/thread.rs | 4 +-- src/shims/tls.rs | 67 +++++++++++++++++++++++++++------------------ src/thread.rs | 7 ++--- 5 files changed, 50 insertions(+), 33 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 89d61d141a23..6352d0626865 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -211,6 +211,9 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> assert!(ecx.step()?, "a terminated thread was scheduled for execution"); } SchedulingAction::ExecuteDtors => { + // This will either enable the thread again (so we go back + // to `ExecuteStep`), or determine that this thread is done + // for good. ecx.schedule_next_tls_dtor_for_active_thread()?; } SchedulingAction::Stop => { diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 9dad302706c2..bc64b1e97a50 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -555,7 +555,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // result, not only readers can starve writers, but also writers can // starve readers. if let Some(_writer) = this.unblock_some_thread(writer_blockset)? { - rwlock_set_writers(this, rwlock_op, Scalar::from_u32(1))?; + assert_eq!(writers, 1); } else { rwlock_set_writers(this, rwlock_op, Scalar::from_u32(0))?; let mut readers = 0; diff --git a/src/shims/thread.rs b/src/shims/thread.rs index 29a4ed367687..3aca9520f671 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -25,7 +25,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let thread_info_place = this.deref_operand(thread)?; this.write_scalar( - Scalar::from_uint(new_thread_id.to_u128(), thread_info_place.layout.size), + Scalar::from_uint(new_thread_id.to_u32(), thread_info_place.layout.size), thread_info_place.into(), )?; @@ -83,7 +83,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let thread_id = this.get_active_thread()?; - this.write_scalar(Scalar::from_uint(thread_id.to_u128(), dest.layout.size), dest) + this.write_scalar(Scalar::from_uint(thread_id.to_u32(), dest.layout.size), dest) } fn prctl( diff --git a/src/shims/tls.rs b/src/shims/tls.rs index f13d9e6dfee8..8a5bb7b42c5d 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -26,7 +26,9 @@ pub struct TlsEntry<'tcx> { #[derive(Clone, Debug)] struct RunningDtorsState { - /// The last TlsKey used to retrieve a TLS destructor. + /// The last TlsKey used to retrieve a TLS destructor. `None` means that we + /// have not tried to retrieve a TLS destructor yet or that we already tried + /// all keys. last_dtor_key: Option, } @@ -40,7 +42,7 @@ pub struct TlsData<'tcx> { /// A single per thread destructor of the thread local storage (that's how /// things work on macOS) with a data argument. - thread_dtors: BTreeMap, Scalar)>, + macos_thread_dtors: BTreeMap, Scalar)>, /// State for currently running TLS dtors. If this map contains a key for a /// specific thread, it means that we are in the "destruct" phase, during @@ -53,7 +55,7 @@ impl<'tcx> Default for TlsData<'tcx> { TlsData { next_key: 1, // start with 1 as we must not use 0 on Windows keys: Default::default(), - thread_dtors: Default::default(), + macos_thread_dtors: Default::default(), dtors_running: Default::default(), } } @@ -143,7 +145,7 @@ impl<'tcx> TlsData<'tcx> { // UB, according to libstd docs. throw_ub_format!("setting thread's local storage destructor while destructors are already running"); } - if self.thread_dtors.insert(thread, (dtor, data)).is_some() { + if self.macos_thread_dtors.insert(thread, (dtor, data)).is_some() { throw_unsup_format!("setting more than one thread local storage destructor for the same thread is not supported"); } Ok(()) @@ -186,6 +188,7 @@ impl<'tcx> TlsData<'tcx> { match data.entry(thread_id) { Entry::Occupied(entry) => { if let Some(dtor) = dtor { + // Set TLS data to NULL, and call dtor with old value. let data_scalar = entry.remove(); let ret = Some((*dtor, data_scalar, key)); return ret; @@ -204,6 +207,8 @@ impl<'tcx> TlsData<'tcx> { if self.dtors_running.contains_key(&thread) { true } else { + // We need to guard this `insert` with a check because otherwise we + // would risk to overwrite `last_dtor_key` with `None`. self.dtors_running.insert( thread, RunningDtorsState { last_dtor_key: None } @@ -259,7 +264,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn schedule_macos_tls_dtor(&mut self) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); let thread_id = this.get_active_thread()?; - if let Some((instance, data)) = this.machine.tls.thread_dtors.remove(&thread_id) { + if let Some((instance, data)) = this.machine.tls.macos_thread_dtors.remove(&thread_id) { trace!("Running macos dtor {:?} on {:?} at {:?}", instance, data, thread_id); let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); @@ -283,7 +288,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Schedule a pthread TLS destructor. Returns `true` if found /// a destructor to schedule, and `false` otherwise. - fn schedule_pthread_tls_dtors(&mut self) -> InterpResult<'tcx, bool> { + fn schedule_next_pthread_tls_dtor(&mut self) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); let active_thread = this.get_active_thread()?; @@ -329,33 +334,43 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// /// FIXME: we do not support yet deallocation of thread local statics. /// Issue: https://github.com/rust-lang/miri/issues/1369 + /// + /// Note: we consistently run TLS destructors for all threads, including the + /// main thread. However, it is not clear that we should run the TLS + /// destructors for the main thread. See issue: + /// https://github.com/rust-lang/rust/issues/28129. fn schedule_next_tls_dtor_for_active_thread(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let active_thread = this.get_active_thread()?; - let scheduled_next = if this.tcx.sess.target.target.target_os == "windows" { - if !this.machine.tls.set_dtors_running_for_thread(active_thread) { + if this.machine.tls.set_dtors_running_for_thread(active_thread) { + // This is the first time we got asked to schedule a destructor. The + // Windows schedule destructor function must be called exactly once, + // this is why it is in this block. + if this.tcx.sess.target.target.target_os == "windows" { + // On Windows, we signal that the thread quit by starting the + // relevant function, reenabling the thread, and going back to + // the scheduler. this.schedule_windows_tls_dtors()?; - true - } else { - false + return Ok(()) } - } else { - this.machine.tls.set_dtors_running_for_thread(active_thread); - // The macOS thread wide destructor runs "before any TLS slots get - // freed", so do that first. - if this.schedule_macos_tls_dtor()? { - true - } else { - this.schedule_pthread_tls_dtors()? - } - }; - - if !scheduled_next { - // No dtors scheduled means that we are finished. Delete the - // remaining TLS entries. - this.machine.tls.delete_all_thread_tls(active_thread); } + // The macOS thread wide destructor runs "before any TLS slots get + // freed", so do that first. + if this.schedule_macos_tls_dtor()? { + // We have scheduled a MacOS dtor to run on the thread. Execute it + // to completion and come back here. Scheduling a destructor + // destroys it, so we will not enter this branch again. + return Ok(()) + } + if this.schedule_next_pthread_tls_dtor()? { + // We have scheduled a pthread destructor and removed it from the + // destructors list. Run it to completion and come back here. + return Ok(()) + } + + // All dtors done! + this.machine.tls.delete_all_thread_tls(active_thread); Ok(()) } diff --git a/src/thread.rs b/src/thread.rs index 69e7bcdb298c..7d394c900274 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -2,7 +2,6 @@ use std::cell::RefCell; use std::convert::TryFrom; -use std::convert::TryInto; use std::num::{NonZeroU32, TryFromIntError}; use log::trace; @@ -36,8 +35,8 @@ pub struct ThreadId(u32); const MAIN_THREAD: ThreadId = ThreadId(0); impl ThreadId { - pub fn to_u128(self) -> u128 { - self.0.try_into().unwrap() + pub fn to_u32(self) -> u32 { + self.0 } } @@ -362,7 +361,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { // Check whether the thread has **just** terminated (`check_terminated` // checks whether the thread has popped all its stack and if yes, sets - // the thread state to terminated.) + // the thread state to terminated). if self.threads[self.active_thread].check_terminated() { // Check if we need to unblock any threads. for (i, thread) in self.threads.iter_enumerated_mut() { From 0e052ab8970777e8f418c4ccf495845804aeae90 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Wed, 29 Apr 2020 15:12:09 -0700 Subject: [PATCH 1999/5092] Use Entry API in set_dtors_running. --- src/shims/tls.rs | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 8a5bb7b42c5d..57b041e685f7 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -1,7 +1,8 @@ //! Implement thread-local storage. use std::collections::BTreeMap; -use std::collections::btree_map::Entry; +use std::collections::btree_map::Entry as BTreeEntry; +use std::collections::hash_map::Entry as HashMapEntry; use log::trace; @@ -186,7 +187,7 @@ impl<'tcx> TlsData<'tcx> { thread_local.range_mut((start, Unbounded)) { match data.entry(thread_id) { - Entry::Occupied(entry) => { + BTreeEntry::Occupied(entry) => { if let Some(dtor) = dtor { // Set TLS data to NULL, and call dtor with old value. let data_scalar = entry.remove(); @@ -194,7 +195,7 @@ impl<'tcx> TlsData<'tcx> { return ret; } } - Entry::Vacant(_) => {} + BTreeEntry::Vacant(_) => {} } } None @@ -204,16 +205,14 @@ impl<'tcx> TlsData<'tcx> { /// the existing values stored in `dtors_running` for this thread. Returns /// `true` if dtors for `thread` are already running. fn set_dtors_running_for_thread(&mut self, thread: ThreadId) -> bool { - if self.dtors_running.contains_key(&thread) { - true - } else { - // We need to guard this `insert` with a check because otherwise we - // would risk to overwrite `last_dtor_key` with `None`. - self.dtors_running.insert( - thread, - RunningDtorsState { last_dtor_key: None } - ); - false + match self.dtors_running.entry(thread) { + HashMapEntry::Occupied(_) => true, + HashMapEntry::Vacant(entry) => { + // We cannot just do `self.dtors_running.insert` because that + // would overwrite `last_dtor_key` with `None`. + entry.insert(RunningDtorsState { last_dtor_key: None }); + false + } } } From 603ec0b3d848f4f0f63f4842231ac13e0fa0ce8c Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Wed, 29 Apr 2020 15:20:26 -0700 Subject: [PATCH 2000/5092] Fix a regression in Windows dtors. --- src/shims/tls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 57b041e685f7..f78b46ec3e7f 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -342,7 +342,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let active_thread = this.get_active_thread()?; - if this.machine.tls.set_dtors_running_for_thread(active_thread) { + if !this.machine.tls.set_dtors_running_for_thread(active_thread) { // This is the first time we got asked to schedule a destructor. The // Windows schedule destructor function must be called exactly once, // this is why it is in this block. From 488f3801e2a22afb093d03cf176169d91212374c Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 30 Apr 2020 00:03:43 +0000 Subject: [PATCH 2001/5092] Add servo_arc to trophy case --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ecff779873ab..82a047e3ff1b 100644 --- a/README.md +++ b/README.md @@ -270,6 +270,7 @@ Definite bugs found: * [Memory leak in `beef`](https://github.com/maciejhirsz/beef/issues/12) * [Invalid use of undefined memory in `EbrCell`](https://github.com/Firstyear/concread/commit/b15be53b6ec076acb295a5c0483cdb4bf9be838f#diff-6282b2fc8e98bd089a1f0c86f648157cR229) * [Unaligned pointer access in TiKV](https://github.com/tikv/tikv/issues/7613) +* [Invalid use of integer as pointer in `servo_arc`](https://github.com/servo/servo/issues/26357) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From e9212d14ac1083515d79ace2ced6f5846598983f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Apr 2020 10:19:34 +0200 Subject: [PATCH 2002/5092] more helpful error on workspaces --- src/bin/cargo-miri.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 17d7ecf8c870..1d93654e33e9 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -144,7 +144,8 @@ fn list_targets() -> impl Iterator { }) .unwrap_or_else(|| { show_error(format!( - "This seems to be a workspace, which is not supported by cargo-miri" + "this seems to be a workspace, which is not supported by `cargo miri`.\n\ + Try to `cd` into the crate you want to test, and re-run `cargo miri` there." )) }); let package = metadata.packages.remove(package_index); From 1aabd6da7509cd67ec2b23f3499686ebf4d73704 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Apr 2020 10:24:57 +0200 Subject: [PATCH 2003/5092] Tweak error wording --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 82a047e3ff1b..0df666532341 100644 --- a/README.md +++ b/README.md @@ -270,7 +270,7 @@ Definite bugs found: * [Memory leak in `beef`](https://github.com/maciejhirsz/beef/issues/12) * [Invalid use of undefined memory in `EbrCell`](https://github.com/Firstyear/concread/commit/b15be53b6ec076acb295a5c0483cdb4bf9be838f#diff-6282b2fc8e98bd089a1f0c86f648157cR229) * [Unaligned pointer access in TiKV](https://github.com/tikv/tikv/issues/7613) -* [Invalid use of integer as pointer in `servo_arc`](https://github.com/servo/servo/issues/26357) +* [Dangling shared reference in `servo_arc`](https://github.com/servo/servo/issues/26357) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From 48da0cf489c1cbbb309692db4049632d83740a8e Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 30 Apr 2020 08:35:59 -0700 Subject: [PATCH 2004/5092] Fix prctl SET_NAME and GET_NAME behaviour. --- src/shims/thread.rs | 10 ++++++++-- src/thread.rs | 8 ++++---- tests/run-pass/libc.rs | 17 +++++++++++++---- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/shims/thread.rs b/src/shims/thread.rs index 3aca9520f671..2f553c1c729e 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -99,11 +99,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let option = this.read_scalar(option)?.to_i32()?; if option == this.eval_libc_i32("PR_SET_NAME")? { let address = this.read_scalar(arg2)?.not_undef()?; - let name = this.memory.read_c_str(address)?.to_owned(); + let mut name = this.memory.read_c_str(address)?.to_owned(); + // The name should be no more than 16 bytes, including the null + // byte. Since `read_c_str` returns the string without the null + // byte, we need to truncate to 15. + name.truncate(15); this.set_active_thread_name(name)?; } else if option == this.eval_libc_i32("PR_GET_NAME")? { let address = this.read_scalar(arg2)?.not_undef()?; - let name = this.get_active_thread_name()?.to_vec(); + let mut name = this.get_active_thread_name()?.to_vec(); + name.push(0u8); + assert!(name.len() <= 16); this.memory.write_bytes(address, name)?; } else { throw_unsup_format!("unsupported prctl option {}", option); diff --git a/src/thread.rs b/src/thread.rs index 7d394c900274..376920e225ba 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -313,11 +313,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Get the name of the active thread. - fn get_thread_name(&self) -> InterpResult<'tcx, &[u8]> { + fn get_thread_name(&self) -> &[u8] { if let Some(ref thread_name) = self.active_thread_ref().thread_name { - Ok(thread_name) + thread_name } else { - throw_ub_format!("thread {:?} has no name set", self.active_thread) + b"" } } @@ -574,7 +574,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx 'mir: 'c, { let this = self.eval_context_ref(); - this.machine.threads.get_thread_name() + Ok(this.machine.threads.get_thread_name()) } #[inline] diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index 36805fc83e30..04ca5c0b3b1a 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -147,12 +147,21 @@ fn test_rwlock_libc_static_initializer() { #[cfg(target_os = "linux")] fn test_prctl_thread_name() { use std::ffi::CString; + use libc::c_long; unsafe { + let mut buf = [255; 10]; + assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr() as c_long, 0 as c_long, 0 as c_long, 0 as c_long), 0); + assert_eq!(b"\0", &buf); let thread_name = CString::new("hello").expect("CString::new failed"); - assert_eq!(libc::prctl(libc::PR_SET_NAME, thread_name.as_ptr() as libc::c_long, 0 as libc::c_long, 0 as libc::c_long, 0 as libc::c_long), 0); - let mut buf = [0; 6]; - assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr() as libc::c_long, 0 as libc::c_long, 0 as libc::c_long, 0 as libc::c_long), 0); - assert_eq!(thread_name.as_bytes_with_nul(), buf); + assert_eq!(libc::prctl(libc::PR_SET_NAME, thread_name.as_ptr() as c_long, 0 as c_long, 0 as c_long, 0 as c_long), 0); + let mut buf = [255; 6]; + assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr() as c_long, 0 as c_long, 0 as c_long, 0 as c_long), 0); + assert_eq!(b"hello\0", &buf); + let long_thread_name = CString::new("01234567890123456789").expect("CString::new failed"); + assert_eq!(libc::prctl(libc::PR_SET_NAME, long_thread_name.as_ptr() as c_long, 0 as c_long, 0 as c_long, 0 as c_long), 0); + let mut buf = [255; 16]; + assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr() as c_long, 0 as c_long, 0 as c_long, 0 as c_long), 0); + assert_eq!(b"012345678901234\0", &buf); } } From ba670d69701acd444019c296a0699f7549439e33 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Apr 2020 19:38:17 +0200 Subject: [PATCH 2005/5092] make sure macos function has 'macos' in its name --- src/shims/foreign_items/posix/macos.rs | 2 +- src/shims/tls.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 200b88f29c8f..0e3019ce33a3 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -83,7 +83,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dtor = this.memory.get_fn(dtor)?.as_instance()?; let data = this.read_scalar(args[1])?.not_undef()?; let active_thread = this.get_active_thread()?; - this.machine.tls.set_thread_dtor(active_thread, dtor, data)?; + this.machine.tls.set_macos_thread_dtor(active_thread, dtor, data)?; } // Querying system information diff --git a/src/shims/tls.rs b/src/shims/tls.rs index f78b46ec3e7f..1ef4728faf07 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -136,7 +136,7 @@ impl<'tcx> TlsData<'tcx> { /// implementation](https://github.com/opensource-apple/dyld/blob/195030646877261f0c8c7ad8b001f52d6a26f514/src/threadLocalVariables.c#L389): /// /// // NOTE: this does not need locks because it only operates on current thread data - pub fn set_thread_dtor( + pub fn set_macos_thread_dtor( &mut self, thread: ThreadId, dtor: ty::Instance<'tcx>, From 580c1194d96d08bc2efaba4fbd86e916b849a194 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Apr 2020 19:39:56 +0200 Subject: [PATCH 2006/5092] README tweak --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a64161809e64..ee23df5ed17e 100644 --- a/README.md +++ b/README.md @@ -48,8 +48,8 @@ in your program, and cannot run all programs: has no access to most platform-specific APIs or FFI. A few APIs have been implemented (such as printing to stdout) but most have not: for example, Miri currently does not support SIMD or networking. -* Miri currently does not check for data-races and most other concurrency - related issues. +* Miri currently does not check for data-races and most other concurrency-related + issues. [rust]: https://www.rust-lang.org/ [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md From 1a704a517a46c84ca6d347b863ea12173f55b8ec Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 May 2020 10:29:39 +0200 Subject: [PATCH 2007/5092] rustup, adjust error messages --- rust-version | 2 +- tests/compile-fail/validity/execute_memory.rs | 2 +- tests/compile-fail/validity/fn_ptr_offset.rs | 2 +- tests/compile-fail/validity/invalid_bool.rs | 2 +- tests/compile-fail/validity/invalid_char.rs | 2 +- tests/compile-fail/validity/invalid_enum_discriminant.rs | 2 +- tests/compile-fail/validity/transmute_through_ptr.rs | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rust-version b/rust-version index 173566bdf616..1070924d744d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -fb5615a4771ea3d54256f969dc84d2dfd38d812c +e94eaa6dce468928b4e1326b2f0054f3075681ff diff --git a/tests/compile-fail/validity/execute_memory.rs b/tests/compile-fail/validity/execute_memory.rs index 426a51faf8a3..5230e7fdf529 100644 --- a/tests/compile-fail/validity/execute_memory.rs +++ b/tests/compile-fail/validity/execute_memory.rs @@ -3,6 +3,6 @@ fn main() { let x = box 42; unsafe { - let _f = std::mem::transmute::, fn()>(x); //~ ERROR encountered a pointer, but expected a function pointer + let _f = std::mem::transmute::, fn()>(x); //~ ERROR expected a function pointer } } diff --git a/tests/compile-fail/validity/fn_ptr_offset.rs b/tests/compile-fail/validity/fn_ptr_offset.rs index 5eec58b5e234..c651fbe070fb 100644 --- a/tests/compile-fail/validity/fn_ptr_offset.rs +++ b/tests/compile-fail/validity/fn_ptr_offset.rs @@ -6,5 +6,5 @@ fn main() { let x : fn() = f; let y : *mut u8 = unsafe { mem::transmute(x) }; let y = y.wrapping_offset(1); - let _x : fn() = unsafe { mem::transmute(y) }; //~ ERROR encountered a pointer, but expected a function pointer + let _x : fn() = unsafe { mem::transmute(y) }; //~ ERROR expected a function pointer } diff --git a/tests/compile-fail/validity/invalid_bool.rs b/tests/compile-fail/validity/invalid_bool.rs index 35f4d4228e70..0b2d648d02ad 100644 --- a/tests/compile-fail/validity/invalid_bool.rs +++ b/tests/compile-fail/validity/invalid_bool.rs @@ -1,3 +1,3 @@ fn main() { - let _b = unsafe { std::mem::transmute::(2) }; //~ ERROR encountered 2, but expected a boolean + let _b = unsafe { std::mem::transmute::(2) }; //~ ERROR encountered 0x02, but expected a boolean } diff --git a/tests/compile-fail/validity/invalid_char.rs b/tests/compile-fail/validity/invalid_char.rs index 42922cdc917c..2801f3297156 100644 --- a/tests/compile-fail/validity/invalid_char.rs +++ b/tests/compile-fail/validity/invalid_char.rs @@ -1,6 +1,6 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); - let _val = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered 4294967295, but expected a valid unicode codepoint + let _val = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered 0xffffffff, but expected a valid unicode codepoint 'a' => {true}, 'b' => {false}, _ => {true}, diff --git a/tests/compile-fail/validity/invalid_enum_discriminant.rs b/tests/compile-fail/validity/invalid_enum_discriminant.rs index 13be4e7dcea8..a3234ba0920c 100644 --- a/tests/compile-fail/validity/invalid_enum_discriminant.rs +++ b/tests/compile-fail/validity/invalid_enum_discriminant.rs @@ -4,5 +4,5 @@ pub enum Foo { } fn main() { - let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR encountered 42, but expected a valid enum discriminant + let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR encountered 0x0000002a, but expected a valid enum discriminant } diff --git a/tests/compile-fail/validity/transmute_through_ptr.rs b/tests/compile-fail/validity/transmute_through_ptr.rs index 4b6a3c95928a..617781c12751 100644 --- a/tests/compile-fail/validity/transmute_through_ptr.rs +++ b/tests/compile-fail/validity/transmute_through_ptr.rs @@ -10,5 +10,5 @@ fn main() { let mut x = Bool::True; evil(&mut x); let _y = x; // reading this ought to be enough to trigger validation - //~^ ERROR encountered 44, but expected a valid enum discriminant + //~^ ERROR encountered 0x0000002c, but expected a valid enum discriminant } From 393165f859c9722494b62da232be332f5428be6c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 May 2020 14:43:59 +0200 Subject: [PATCH 2008/5092] rustup; fix for changed error messages --- rust-version | 2 +- src/diagnostics.rs | 2 +- src/intptrcast.rs | 8 +++++--- tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs | 2 +- .../compile-fail/dangling_pointers/wild_pointer_deref.rs | 2 +- .../compile-fail/function_pointers/cast_int_to_fn_ptr.rs | 2 +- tests/compile-fail/intrinsics/copy_null.rs | 2 +- tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs | 2 +- tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs | 2 +- tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs | 2 +- tests/compile-fail/intrinsics/write_bytes_null.rs | 2 +- tests/compile-fail/invalid_bool.rs | 2 +- tests/compile-fail/invalid_enum_discriminant.rs | 2 +- tests/compile-fail/null_pointer_deref.rs | 2 +- tests/compile-fail/null_pointer_deref_zst.rs | 2 +- tests/compile-fail/null_pointer_write.rs | 2 +- tests/compile-fail/null_pointer_write_zst.rs | 2 +- tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs | 2 +- 18 files changed, 22 insertions(+), 20 deletions(-) diff --git a/rust-version b/rust-version index 1070924d744d..7e957fa4257d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e94eaa6dce468928b4e1326b2f0054f3075681ff +fd61d06772d17c6242265d860fbfb5eafd282caa diff --git a/src/diagnostics.rs b/src/diagnostics.rs index b7c96dd7e98a..06d12b99c1ea 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -16,7 +16,7 @@ pub enum TerminationInfo { Deadlock, } -impl fmt::Debug for TerminationInfo { +impl fmt::Display for TerminationInfo { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use TerminationInfo::*; match self { diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 5413e6b935b9..f51c8a7ce743 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -9,7 +9,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_mir::interpret::{AllocCheck, AllocId, InterpResult, Memory, Machine, Pointer, PointerArithmetic}; use rustc_target::abi::{Size, HasDataLayout}; -use crate::{Evaluator, Tag, STACK_ADDR}; +use crate::{Evaluator, Tag, STACK_ADDR, CheckInAllocMsg}; pub type MemoryExtra = RefCell; @@ -46,6 +46,8 @@ impl<'mir, 'tcx> GlobalState { let global_state = memory.extra.intptrcast.borrow(); let pos = global_state.int_to_ptr_map.binary_search_by_key(&int, |(addr, _)| *addr); + // The int must be in-bounds after being cast to a pointer, so we error + // with `CheckInAllocMsg::InboundsTest`. Ok(match pos { Ok(pos) => { let (_, alloc_id) = global_state.int_to_ptr_map[pos]; @@ -53,7 +55,7 @@ impl<'mir, 'tcx> GlobalState { // zero. The pointer is untagged because it was created from a cast Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged) } - Err(0) => throw_ub!(InvalidIntPointerUsage(int)), + Err(0) => throw_ub!(DanglingIntPointer(int, CheckInAllocMsg::InboundsTest)), Err(pos) => { // This is the largest of the adresses smaller than `int`, // i.e. the greatest lower bound (glb) @@ -65,7 +67,7 @@ impl<'mir, 'tcx> GlobalState { // This pointer is untagged because it was created from a cast Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged) } else { - throw_ub!(InvalidIntPointerUsage(int)) + throw_ub!(DanglingIntPointer(int, CheckInAllocMsg::InboundsTest)) } } }) diff --git a/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs b/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs index e0bba8c7c730..6aa93e714721 100644 --- a/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs +++ b/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs @@ -3,5 +3,5 @@ fn main() { let x = 16usize as *const u32; - let _y = unsafe { &*x as *const u32 }; //~ ERROR invalid use of 16 as a pointer + let _y = unsafe { &*x as *const u32 }; //~ ERROR inbounds test failed: 0x10 is not a valid pointer } diff --git a/tests/compile-fail/dangling_pointers/wild_pointer_deref.rs b/tests/compile-fail/dangling_pointers/wild_pointer_deref.rs index 5780cccdb842..371e72d2822d 100644 --- a/tests/compile-fail/dangling_pointers/wild_pointer_deref.rs +++ b/tests/compile-fail/dangling_pointers/wild_pointer_deref.rs @@ -1,5 +1,5 @@ fn main() { let p = 44 as *const i32; - let x = unsafe { *p }; //~ ERROR invalid use of 44 as a pointer + let x = unsafe { *p }; //~ ERROR inbounds test failed: 0x2c is not a valid pointer panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs b/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs index 3000779a9330..94ff3327123b 100644 --- a/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs +++ b/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs @@ -6,5 +6,5 @@ fn main() { std::mem::transmute::(42) }; - g(42) //~ ERROR invalid use of 42 as a pointer + g(42) //~ ERROR inbounds test failed: 0x2a is not a valid pointer } diff --git a/tests/compile-fail/intrinsics/copy_null.rs b/tests/compile-fail/intrinsics/copy_null.rs index b14bdc4b3863..60cb7e4eff51 100644 --- a/tests/compile-fail/intrinsics/copy_null.rs +++ b/tests/compile-fail/intrinsics/copy_null.rs @@ -9,5 +9,5 @@ fn main() { let mut data = [0u16; 4]; let ptr = &mut data[0] as *mut u16; // Even copying 0 elements from NULL should error. - unsafe { copy_nonoverlapping(std::ptr::null(), ptr, 0); } //~ ERROR: invalid use of NULL pointer + unsafe { copy_nonoverlapping(std::ptr::null(), ptr, 0); } //~ ERROR: memory access failed: 0x0 is not a valid pointer } diff --git a/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs b/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs index 96a9fb8402f6..d6cf3d65f296 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs +++ b/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs @@ -1,4 +1,4 @@ -// error-pattern: invalid use of NULL pointer +// error-pattern: inbounds test failed: 0x0 is not a valid pointer fn main() { let x = 0 as *mut i32; diff --git a/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs b/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs index f0cf00884e15..4bee2fec6b7b 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs +++ b/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs @@ -1,4 +1,4 @@ -// error-pattern: invalid use of 1 as a pointer +// error-pattern: inbounds test failed: 0x1 is not a valid pointer fn main() { // Can't offset an integer pointer by non-zero offset. diff --git a/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs b/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs index 705ca68970a1..892dbca1128f 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs +++ b/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs @@ -1,4 +1,4 @@ -// error-pattern: invalid use of 1 as a pointer +// error-pattern: inbounds test failed: 0x1 is not a valid pointer fn main() { let ptr = Box::into_raw(Box::new(0u32)); diff --git a/tests/compile-fail/intrinsics/write_bytes_null.rs b/tests/compile-fail/intrinsics/write_bytes_null.rs index e80222162ee3..c3f77b27b4ff 100644 --- a/tests/compile-fail/intrinsics/write_bytes_null.rs +++ b/tests/compile-fail/intrinsics/write_bytes_null.rs @@ -6,5 +6,5 @@ extern "rust-intrinsic" { } fn main() { - unsafe { write_bytes::(std::ptr::null_mut(), 0, 0) }; //~ ERROR invalid use of NULL pointer + unsafe { write_bytes::(std::ptr::null_mut(), 0, 0) }; //~ ERROR memory access failed: 0x0 is not a valid pointer } diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index 38033146ade8..23441ea7d4aa 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -4,5 +4,5 @@ fn main() { let b = unsafe { std::mem::transmute::(2) }; - let _x = b == true; //~ ERROR interpreting an invalid 8-bit value as a bool: 2 + let _x = b == true; //~ ERROR interpreting an invalid 8-bit value as a bool } diff --git a/tests/compile-fail/invalid_enum_discriminant.rs b/tests/compile-fail/invalid_enum_discriminant.rs index cdbea6aa1223..893dd03c64e6 100644 --- a/tests/compile-fail/invalid_enum_discriminant.rs +++ b/tests/compile-fail/invalid_enum_discriminant.rs @@ -2,7 +2,7 @@ // Make sure we find these even with many checks disabled. // compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation -// error-pattern: invalid enum discriminant +// error-pattern: enum value has invalid discriminant: 0x0000002a use std::mem; diff --git a/tests/compile-fail/null_pointer_deref.rs b/tests/compile-fail/null_pointer_deref.rs index 8bf0392b8903..bd4758f737e7 100644 --- a/tests/compile-fail/null_pointer_deref.rs +++ b/tests/compile-fail/null_pointer_deref.rs @@ -1,4 +1,4 @@ fn main() { - let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR invalid use of NULL pointer + let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR inbounds test failed: 0x0 is not a valid pointer panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/null_pointer_deref_zst.rs b/tests/compile-fail/null_pointer_deref_zst.rs index b2800e96292d..cfd3a75e3b8c 100644 --- a/tests/compile-fail/null_pointer_deref_zst.rs +++ b/tests/compile-fail/null_pointer_deref_zst.rs @@ -1,4 +1,4 @@ fn main() { - let x: () = unsafe { *std::ptr::null() }; //~ ERROR invalid use of NULL pointer + let x: () = unsafe { *std::ptr::null() }; //~ ERROR memory access failed: 0x0 is not a valid pointer panic!("this should never print: {:?}", x); } diff --git a/tests/compile-fail/null_pointer_write.rs b/tests/compile-fail/null_pointer_write.rs index 1577b2a1b13b..97c9ee8b1f52 100644 --- a/tests/compile-fail/null_pointer_write.rs +++ b/tests/compile-fail/null_pointer_write.rs @@ -1,3 +1,3 @@ fn main() { - unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR invalid use of NULL pointer + unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR inbounds test failed: 0x0 is not a valid pointer } diff --git a/tests/compile-fail/null_pointer_write_zst.rs b/tests/compile-fail/null_pointer_write_zst.rs index 7e91d736bd29..0f7244ba25cc 100644 --- a/tests/compile-fail/null_pointer_write_zst.rs +++ b/tests/compile-fail/null_pointer_write_zst.rs @@ -2,5 +2,5 @@ fn main() { // Not using the () type here, as writes of that type do not even have MIR generated. // Also not assigning directly as that's array initialization, not assignment. let zst_val = [1u8; 0]; - unsafe { *std::ptr::null_mut() = zst_val }; //~ ERROR invalid use of NULL pointer + unsafe { *std::ptr::null_mut() = zst_val }; //~ ERROR memory access failed: 0x0 is not a valid pointer } diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs b/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs index 69f19651e540..c40d8de21dd7 100644 --- a/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs +++ b/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs @@ -1,4 +1,4 @@ -// error-pattern: invalid use of 4 as a pointer +// error-pattern: inbounds test failed: 0x4 is not a valid pointer use std::ptr::NonNull; fn main() { unsafe { From 5e25dfaef83d1a2855cc4e4a1aecca77ba0dc47a Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 1 May 2020 21:34:16 +0000 Subject: [PATCH 2009/5092] Add another tikv stacked borrowing error to trophy case --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ee23df5ed17e..08e30b5f77dd 100644 --- a/README.md +++ b/README.md @@ -285,6 +285,7 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [`String::push_str` invalidating existing references into the string](https://github.com/rust-lang/rust/issues/70301) * [`ryu` using raw pointers outside their valid memory area](https://github.com/dtolnay/ryu/issues/24) * [ink! creating overlapping mutable references](https://github.com/rust-lang/miri/issues/1364) +* [Stacked borrowing violation in TiKV](https://github.com/tikv/tikv/pull/7709) ## License From dbd6403955a4d7ebb589a1b40c1b55d1cf04cfe2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 May 2020 02:13:48 +0200 Subject: [PATCH 2010/5092] rustup for fixed error messages --- rust-version | 2 +- tests/compile-fail/invalid_bool.rs | 2 +- tests/compile-fail/invalid_char.rs | 7 ++++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 7e957fa4257d..853c4ff10335 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -fd61d06772d17c6242265d860fbfb5eafd282caa +7f65393b9abf5e70d0b9a8080558f17c5625bd40 diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index 23441ea7d4aa..6dee9ec3c91a 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -4,5 +4,5 @@ fn main() { let b = unsafe { std::mem::transmute::(2) }; - let _x = b == true; //~ ERROR interpreting an invalid 8-bit value as a bool + let _x = b == true; //~ ERROR interpreting an invalid 8-bit value as a bool: 0x02 } diff --git a/tests/compile-fail/invalid_char.rs b/tests/compile-fail/invalid_char.rs index ab10ab1e2173..b240cb22ebe9 100644 --- a/tests/compile-fail/invalid_char.rs +++ b/tests/compile-fail/invalid_char.rs @@ -3,7 +3,8 @@ // compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation fn main() { - assert!(std::char::from_u32(-1_i32 as u32).is_none()); - let c = unsafe { std::mem::transmute::(-1) }; - let _x = c == 'x'; //~ ERROR interpreting an invalid 32-bit value as a char + let c = 0xFFFFFFu32; + assert!(std::char::from_u32(c).is_none()); + let c = unsafe { std::mem::transmute::(c) }; + let _x = c == 'x'; //~ ERROR interpreting an invalid 32-bit value as a char: 0x00ffffff } From ee6460e7639832f87f4c6f077cce932cd804301e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 May 2020 11:00:37 +0200 Subject: [PATCH 2011/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 853c4ff10335..7affb621bc70 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7f65393b9abf5e70d0b9a8080558f17c5625bd40 +dae90c195989b09475b6c0225a3018cbd7afa587 From 15c299e6570d2f96c364b41cff5e937b8825501e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 May 2020 11:04:45 +0200 Subject: [PATCH 2012/5092] Adjust wording --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 08e30b5f77dd..4ca4840714a8 100644 --- a/README.md +++ b/README.md @@ -285,7 +285,7 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [`String::push_str` invalidating existing references into the string](https://github.com/rust-lang/rust/issues/70301) * [`ryu` using raw pointers outside their valid memory area](https://github.com/dtolnay/ryu/issues/24) * [ink! creating overlapping mutable references](https://github.com/rust-lang/miri/issues/1364) -* [Stacked borrowing violation in TiKV](https://github.com/tikv/tikv/pull/7709) +* [TiKV creating overlapping mutable reference and raw pointer](https://github.com/tikv/tikv/pull/7709) ## License From df4623e5d8518db4ca845f3db6b36e57f87c3d81 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 May 2020 11:08:20 +0200 Subject: [PATCH 2013/5092] trophy case: consistent wording (X doing Y) --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index ee23df5ed17e..1e271f7a2c1f 100644 --- a/README.md +++ b/README.md @@ -269,10 +269,10 @@ Definite bugs found: * [The Unix allocator calling `posix_memalign` in an invalid way](https://github.com/rust-lang/rust/issues/62251) * [`getrandom` calling the `getrandom` syscall in an invalid way](https://github.com/rust-random/getrandom/pull/73) * [`Vec`](https://github.com/rust-lang/rust/issues/69770) and [`BTreeMap`](https://github.com/rust-lang/rust/issues/69769) leaking memory under some (panicky) conditions -* [Memory leak in `beef`](https://github.com/maciejhirsz/beef/issues/12) -* [Invalid use of undefined memory in `EbrCell`](https://github.com/Firstyear/concread/commit/b15be53b6ec076acb295a5c0483cdb4bf9be838f#diff-6282b2fc8e98bd089a1f0c86f648157cR229) -* [Unaligned pointer access in TiKV](https://github.com/tikv/tikv/issues/7613) -* [Dangling shared reference in `servo_arc`](https://github.com/servo/servo/issues/26357) +* [`beef` leaking memory](https://github.com/maciejhirsz/beef/issues/12) +* [`EbrCell` using uninitialized memory incorrectly](https://github.com/Firstyear/concread/commit/b15be53b6ec076acb295a5c0483cdb4bf9be838f#diff-6282b2fc8e98bd089a1f0c86f648157cR229) +* [TiKV performing an unaligned pointer access](https://github.com/tikv/tikv/issues/7613) +* [`servo_arc` creating a dangling shared reference](https://github.com/servo/servo/issues/26357) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): @@ -281,7 +281,7 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [`LinkedList` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/60072) * [`Vec::push` invalidating existing references into the vector](https://github.com/rust-lang/rust/issues/60847) * [`align_to_mut` violating uniqueness of mutable references](https://github.com/rust-lang/rust/issues/68549) -* [Aliasing mutable references in `sized-chunks`](https://github.com/bodil/sized-chunks/issues/8) +* [`sized-chunks` creating aliasing mutable references](https://github.com/bodil/sized-chunks/issues/8) * [`String::push_str` invalidating existing references into the string](https://github.com/rust-lang/rust/issues/70301) * [`ryu` using raw pointers outside their valid memory area](https://github.com/dtolnay/ryu/issues/24) * [ink! creating overlapping mutable references](https://github.com/rust-lang/miri/issues/1364) From 157854095957cee97962921b87cdda14d2131787 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 May 2020 12:10:24 +0200 Subject: [PATCH 2014/5092] bump Rust, fix warnings --- rust-version | 2 +- src/diagnostics.rs | 2 +- src/eval.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 7affb621bc70..81fe678f1172 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -dae90c195989b09475b6c0225a3018cbd7afa587 +0a675c5e02e6ecfda7d4e04aabd23a9935e0c4bf diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 06d12b99c1ea..e5e7f0c90475 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -48,7 +48,7 @@ pub enum NonHaltingDiagnostic { /// Emit a custom diagnostic without going through the miri-engine machinery pub fn report_error<'tcx, 'mir>( ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, - mut e: InterpErrorInfo<'tcx>, + e: InterpErrorInfo<'tcx>, ) -> Option { use InterpError::*; diff --git a/src/eval.rs b/src/eval.rs index 6352d0626865..5daad7cc068b 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -196,7 +196,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) { Ok(v) => v, - Err(mut err) => { + Err(err) => { err.print_backtrace(); panic!("Miri initialization error: {}", err.kind) } From ff1f0b06cca7697db480087820640115946fb7f7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 May 2020 12:24:40 +0200 Subject: [PATCH 2015/5092] explain what happens in a test --- tests/run-pass/transmute_fat2.rs | 1 + tests/run-pass/transmute_fat2.stderr | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/transmute_fat2.rs b/tests/run-pass/transmute_fat2.rs index 8cbe9a099bb6..c667aab6bb5f 100644 --- a/tests/run-pass/transmute_fat2.rs +++ b/tests/run-pass/transmute_fat2.rs @@ -8,5 +8,6 @@ fn main() { let bad = unsafe { std::mem::transmute::(42) }; + // This created a slice with length 0, so the following will fail the bounds check. bad[0]; } diff --git a/tests/run-pass/transmute_fat2.stderr b/tests/run-pass/transmute_fat2.stderr index 08849a5b517a..2539e58814d6 100644 --- a/tests/run-pass/transmute_fat2.stderr +++ b/tests/run-pass/transmute_fat2.stderr @@ -1 +1 @@ -thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', $DIR/transmute_fat2.rs:11:5 +thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', $DIR/transmute_fat2.rs:12:5 From 994b13eaee64ac87fbdee4cc0efd7cae0d3f9c2a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 May 2020 12:24:57 +0200 Subject: [PATCH 2016/5092] yield on x86 'pause' hint --- src/shims/foreign_items.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 9e531accd06a..25aece5989b9 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -434,7 +434,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Architecture-specific shims - "llvm.x86.sse2.pause" if this.tcx.sess.target.target.arch == "x86" || this.tcx.sess.target.target.arch == "x86_64" => {} + "llvm.x86.sse2.pause" if this.tcx.sess.target.target.arch == "x86" || this.tcx.sess.target.target.arch == "x86_64" => { + this.sched_yield()?; + } // Platform-specific shims _ => match this.tcx.sess.target.target.target_os.as_str() { From 2b591b849f6654da993304e6b3c14472e8b4d205 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 May 2020 12:25:07 +0200 Subject: [PATCH 2017/5092] test panics in threads --- tests/run-pass/concurrency/simple.rs | 11 +++++++++++ tests/run-pass/concurrency/simple.stderr | 1 + 2 files changed, 12 insertions(+) diff --git a/tests/run-pass/concurrency/simple.rs b/tests/run-pass/concurrency/simple.rs index ad47bb144b58..a06581349057 100644 --- a/tests/run-pass/concurrency/simple.rs +++ b/tests/run-pass/concurrency/simple.rs @@ -49,6 +49,16 @@ fn create_move_out() { assert_eq!(result.len(), 6); } +fn panic() { + let result = thread::spawn(|| { + panic!("Hello!") + }) + .join() + .unwrap_err(); + let msg = result.downcast_ref::<&'static str>().unwrap(); + assert_eq!(*msg, "Hello!"); +} + fn main() { create_and_detach(); create_and_join(); @@ -58,4 +68,5 @@ fn main() { create_nested_and_join(); create_move_in(); create_move_out(); + panic(); } diff --git a/tests/run-pass/concurrency/simple.stderr b/tests/run-pass/concurrency/simple.stderr index 2dbfb7721d36..dff33c6531c4 100644 --- a/tests/run-pass/concurrency/simple.stderr +++ b/tests/run-pass/concurrency/simple.stderr @@ -1,2 +1,3 @@ warning: thread support is experimental. For example, Miri does not detect data races yet. +thread '' panicked at 'Hello!', $DIR/simple.rs:54:9 From c26fb591fa562268d8eb47599717f8d6c96f1d3b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 May 2020 12:40:15 +0200 Subject: [PATCH 2018/5092] also test std::hint::spin_loop --- tests/run-pass/sync.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index a4fd6f584c58..8b8594d4df69 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -1,7 +1,8 @@ -#![feature(rustc_private)] +#![feature(rustc_private, renamed_spin_loop)] use std::sync::{Mutex, TryLockError}; use std::sync::atomic; +use std::hint; fn main() { test_mutex_stdlib(); @@ -56,6 +57,7 @@ impl TryLockErrorExt for TryLockError { fn test_spin_loop_hint() { atomic::spin_loop_hint(); + hint::spin_loop(); } fn test_thread_yield_now() { From f2f4e6fc65f15d593dacb79f6558d66618705415 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 May 2020 12:51:48 +0200 Subject: [PATCH 2019/5092] also test panic from thread with name --- tests/run-pass/concurrency/simple.rs | 10 ++++++++++ tests/run-pass/concurrency/simple.stderr | 1 + 2 files changed, 11 insertions(+) diff --git a/tests/run-pass/concurrency/simple.rs b/tests/run-pass/concurrency/simple.rs index a06581349057..c22506821f54 100644 --- a/tests/run-pass/concurrency/simple.rs +++ b/tests/run-pass/concurrency/simple.rs @@ -59,6 +59,15 @@ fn panic() { assert_eq!(*msg, "Hello!"); } +fn panic_named() { + thread::Builder::new().name("childthread".to_string()).spawn(move || { + panic!("Hello, world!"); + }) + .unwrap() + .join() + .unwrap_err(); +} + fn main() { create_and_detach(); create_and_join(); @@ -69,4 +78,5 @@ fn main() { create_move_in(); create_move_out(); panic(); + panic_named(); } diff --git a/tests/run-pass/concurrency/simple.stderr b/tests/run-pass/concurrency/simple.stderr index dff33c6531c4..e52d07cdc73f 100644 --- a/tests/run-pass/concurrency/simple.stderr +++ b/tests/run-pass/concurrency/simple.stderr @@ -1,3 +1,4 @@ warning: thread support is experimental. For example, Miri does not detect data races yet. thread '' panicked at 'Hello!', $DIR/simple.rs:54:9 +thread 'childthread' panicked at 'Hello, world!', $DIR/simple.rs:64:9 From 6680118588f4ba52683b9fffbb7ac88a50b4f971 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 May 2020 12:56:38 +0200 Subject: [PATCH 2020/5092] de-duplicate default thread name --- src/thread.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/thread.rs b/src/thread.rs index 376920e225ba..2119175e12cc 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -134,16 +134,20 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> { } false } + + /// Get the name of the current thread, or `` if it was not set. + fn thread_name(&self) -> &[u8] { + if let Some(ref thread_name) = self.thread_name { + thread_name + } else { + b"" + } + } } impl<'mir, 'tcx> std::fmt::Debug for Thread<'mir, 'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if let Some(ref name) = self.thread_name { - write!(f, "{}", String::from_utf8_lossy(name))?; - } else { - write!(f, "")?; - } - write!(f, "({:?}, {:?})", self.state, self.join_status) + write!(f, "{}({:?}, {:?})", String::from_utf8_lossy(self.thread_name()), self.state, self.join_status) } } @@ -314,11 +318,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Get the name of the active thread. fn get_thread_name(&self) -> &[u8] { - if let Some(ref thread_name) = self.active_thread_ref().thread_name { - thread_name - } else { - b"" - } + self.active_thread_ref().thread_name() } /// Allocate a new blockset id. From 6b18f6e10602b5ea08fbd94c5e10396f984d8174 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 May 2020 13:22:56 +0200 Subject: [PATCH 2021/5092] fix setting thread name on macOS --- src/shims/foreign_items/posix/macos.rs | 6 ++++++ src/shims/thread.rs | 14 ++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 0e3019ce33a3..3677960fd877 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -98,6 +98,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(stack_size, dest)?; } + // Threading + "pthread_setname_np" => { + let ptr = this.read_scalar(args[0])?.not_undef()?; + this.pthread_setname_np(ptr)?; + } + // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "mmap" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { diff --git a/src/shims/thread.rs b/src/shims/thread.rs index 2f553c1c729e..ac1bb39a6982 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -95,6 +95,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _arg5: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + this.assert_target_os("linux", "prctl"); let option = this.read_scalar(option)?.to_i32()?; if option == this.eval_libc_i32("PR_SET_NAME")? { @@ -118,6 +119,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } + fn pthread_setname_np( + &mut self, + ptr: Scalar, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + this.assert_target_os("macos", "pthread_setname_np"); + + let name = this.memory.read_c_str(ptr)?.to_owned(); + this.set_active_thread_name(name)?; + + Ok(()) + } + fn sched_yield(&mut self) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); From 61a86e1ffea5bbda721ab2d2702807f085e2a3a4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 May 2020 09:37:40 +0200 Subject: [PATCH 2022/5092] Windows lock primitives: check that we are truly sinle-threaded --- src/shims/foreign_items/windows.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index a58444b21bff..f55b5b8450e0 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -236,12 +236,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "LeaveCriticalSection" | "DeleteCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + assert_eq!(this.get_total_thread_count()?, 1, "concurrency on Windows not supported"); // Nothing to do, not even a return value. // (Windows locks are reentrant, and we have only 1 thread, // so not doing any futher checks here is at least not incorrect.) } "TryEnterCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + assert_eq!(this.get_total_thread_count()?, 1, "concurrency on Windows not supported"); // There is only one thread, so this always succeeds and returns TRUE this.write_scalar(Scalar::from_i32(1), dest)?; } From 65c3914a29b250081b4dd659657d612929fdaef2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 May 2020 09:43:09 +0200 Subject: [PATCH 2023/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 81fe678f1172..be7b603f9054 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0a675c5e02e6ecfda7d4e04aabd23a9935e0c4bf +ff4df04799c406c8149a041c3163321758aac924 From ec95ed4556e63e93fb5abb453bfb9db41c4c5a76 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 May 2020 09:45:15 +0200 Subject: [PATCH 2024/5092] rename single-threaded sync test --- tests/run-pass/{sync.rs => sync_singlethread.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/run-pass/{sync.rs => sync_singlethread.rs} (100%) diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync_singlethread.rs similarity index 100% rename from tests/run-pass/sync.rs rename to tests/run-pass/sync_singlethread.rs From 78f329513af3e5f34cfd4d9a09fe3a9a4427194f Mon Sep 17 00:00:00 2001 From: Chase Albert Date: Thu, 2 Apr 2020 17:09:20 -0400 Subject: [PATCH 2025/5092] Check that shims are called with the correct number of arguments --- src/helpers.rs | 11 +- src/lib.rs | 3 + src/shims/dlsym.rs | 6 +- src/shims/foreign_items.rs | 91 ++++++++------ src/shims/foreign_items/posix.rs | 160 ++++++++++++++++--------- src/shims/foreign_items/posix/linux.rs | 57 +++++---- src/shims/foreign_items/posix/macos.rs | 47 +++++--- src/shims/foreign_items/windows.rs | 127 ++++++++++++++------ src/shims/fs.rs | 25 ++-- src/shims/intrinsics.rs | 143 +++++++++++++--------- src/shims/mod.rs | 4 +- src/shims/panic.rs | 11 +- 12 files changed, 445 insertions(+), 240 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 644ea25fbc4b..43a20d290c80 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,4 +1,4 @@ -use std::convert::TryFrom; +use std::convert::{TryFrom, TryInto}; use std::mem; use std::num::NonZeroUsize; @@ -471,6 +471,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } +/// Check that the number of args is what we expect. +pub fn check_arg_count<'a, 'tcx, const N: usize>(args: &'a [OpTy<'tcx, Tag>]) -> InterpResult<'tcx, &'a [OpTy<'tcx, Tag>; N]> + where &'a [OpTy<'tcx, Tag>; N]: TryFrom<&'a [OpTy<'tcx, Tag>]> { + if let Ok(ops) = args.try_into() { + return Ok(ops); + } + throw_ub_format!("incorrect number of arguments, got {}, needed {}", args.len(), N) +} + pub fn immty_from_int_checked<'tcx>( int: impl Into, layout: TyAndLayout<'tcx>, diff --git a/src/lib.rs b/src/lib.rs index beee94b918b5..e8cf507d35a0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,9 @@ #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] +#![allow(incomplete_features)] +#![feature(const_generics)] + extern crate rustc_apfloat; extern crate rustc_ast; #[macro_use] extern crate rustc_middle; diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 0f6ba63e984f..3c4a942b596f 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -1,6 +1,7 @@ use rustc_middle::mir; use crate::*; +use helpers::check_arg_count; #[derive(Debug, Copy, Clone)] pub enum Dlsym { @@ -35,8 +36,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match dlsym { GetEntropy => { - let ptr = this.read_scalar(args[0])?.not_undef()?; - let len = this.read_scalar(args[1])?.to_machine_usize(this)?; + let &[ptr, len] = check_arg_count(args)?; + let ptr = this.read_scalar(ptr)?.not_undef()?; + let len = this.read_scalar(len)?.to_machine_usize(this)?; this.gen_random(ptr, len)?; this.write_null(dest)?; } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 25aece5989b9..643f76bfe37a 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -11,6 +11,7 @@ use rustc_span::symbol::sym; use rustc_ast::attr; use crate::*; +use helpers::check_arg_count; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -139,8 +140,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "exit" | "ExitProcess" => { + let &[code] = check_arg_count(args)?; // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway - let code = this.read_scalar(args[0])?.to_i32()?; + let code = this.read_scalar(code)?.to_i32()?; throw_machine_stop!(TerminationInfo::Exit(code.into())); } _ => throw_unsup_format!("can't call (diverging) foreign function: {}", link_name), @@ -197,25 +199,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Standard C allocation "malloc" => { - let size = this.read_scalar(args[0])?.to_machine_usize(this)?; + let &[size] = check_arg_count(args)?; + let size = this.read_scalar(size)?.to_machine_usize(this)?; let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C); this.write_scalar(res, dest)?; } "calloc" => { - let items = this.read_scalar(args[0])?.to_machine_usize(this)?; - let len = this.read_scalar(args[1])?.to_machine_usize(this)?; + let &[items, len] = check_arg_count(args)?; + let items = this.read_scalar(items)?.to_machine_usize(this)?; + let len = this.read_scalar(len)?.to_machine_usize(this)?; let size = items.checked_mul(len).ok_or_else(|| err_ub_format!("overflow during calloc size computation"))?; let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C); this.write_scalar(res, dest)?; } "free" => { - let ptr = this.read_scalar(args[0])?.not_undef()?; + let &[ptr] = check_arg_count(args)?; + let ptr = this.read_scalar(ptr)?.not_undef()?; this.free(ptr, MiriMemoryKind::C)?; } "realloc" => { - let old_ptr = this.read_scalar(args[0])?.not_undef()?; - let new_size = this.read_scalar(args[1])?.to_machine_usize(this)?; + let &[old_ptr, new_size] = check_arg_count(args)?; + let old_ptr = this.read_scalar(old_ptr)?.not_undef()?; + let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; let res = this.realloc(old_ptr, new_size, MiriMemoryKind::C)?; this.write_scalar(res, dest)?; } @@ -224,8 +230,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // (Usually these would be forwarded to to `#[global_allocator]`; we instead implement a generic // allocation that also checks that all conditions are met, such as not permitting zero-sized allocations.) "__rust_alloc" => { - let size = this.read_scalar(args[0])?.to_machine_usize(this)?; - let align = this.read_scalar(args[1])?.to_machine_usize(this)?; + let &[size, align] = check_arg_count(args)?; + let size = this.read_scalar(size)?.to_machine_usize(this)?; + let align = this.read_scalar(align)?.to_machine_usize(this)?; Self::check_alloc_request(size, align)?; let ptr = this.memory.allocate( Size::from_bytes(size), @@ -235,8 +242,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "__rust_alloc_zeroed" => { - let size = this.read_scalar(args[0])?.to_machine_usize(this)?; - let align = this.read_scalar(args[1])?.to_machine_usize(this)?; + let &[size, align] = check_arg_count(args)?; + let size = this.read_scalar(size)?.to_machine_usize(this)?; + let align = this.read_scalar(align)?.to_machine_usize(this)?; Self::check_alloc_request(size, align)?; let ptr = this.memory.allocate( Size::from_bytes(size), @@ -248,9 +256,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "__rust_dealloc" => { - let ptr = this.read_scalar(args[0])?.not_undef()?; - let old_size = this.read_scalar(args[1])?.to_machine_usize(this)?; - let align = this.read_scalar(args[2])?.to_machine_usize(this)?; + let &[ptr, old_size, align] = check_arg_count(args)?; + let ptr = this.read_scalar(ptr)?.not_undef()?; + let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; + let align = this.read_scalar(align)?.to_machine_usize(this)?; // No need to check old_size/align; we anyway check that they match the allocation. let ptr = this.force_ptr(ptr)?; this.memory.deallocate( @@ -260,12 +269,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; } "__rust_realloc" => { - let old_size = this.read_scalar(args[1])?.to_machine_usize(this)?; - let align = this.read_scalar(args[2])?.to_machine_usize(this)?; - let new_size = this.read_scalar(args[3])?.to_machine_usize(this)?; + let &[ptr, old_size, align, new_size] = check_arg_count(args)?; + let ptr = this.force_ptr(this.read_scalar(ptr)?.not_undef()?)?; + let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; + let align = this.read_scalar(align)?.to_machine_usize(this)?; + let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; Self::check_alloc_request(new_size, align)?; // No need to check old_size; we anyway check that they match the allocation. - let ptr = this.force_ptr(this.read_scalar(args[0])?.not_undef()?)?; let align = Align::from_bytes(align).unwrap(); let new_ptr = this.memory.reallocate( ptr, @@ -279,9 +289,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // C memory handling functions "memcmp" => { - let left = this.read_scalar(args[0])?.not_undef()?; - let right = this.read_scalar(args[1])?.not_undef()?; - let n = Size::from_bytes(this.read_scalar(args[2])?.to_machine_usize(this)?); + let &[left, right, n] = check_arg_count(args)?; + let left = this.read_scalar(left)?.not_undef()?; + let right = this.read_scalar(right)?.not_undef()?; + let n = Size::from_bytes(this.read_scalar(n)?.to_machine_usize(this)?); let result = { let left_bytes = this.memory.read_bytes(left, n)?; @@ -298,9 +309,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "memrchr" => { - let ptr = this.read_scalar(args[0])?.not_undef()?; - let val = this.read_scalar(args[1])?.to_i32()? as u8; - let num = this.read_scalar(args[2])?.to_machine_usize(this)?; + let &[ptr, val, num] = check_arg_count(args)?; + let ptr = this.read_scalar(ptr)?.not_undef()?; + let val = this.read_scalar(val)?.to_i32()? as u8; + let num = this.read_scalar(num)?.to_machine_usize(this)?; if let Some(idx) = this .memory .read_bytes(ptr, Size::from_bytes(num))? @@ -315,9 +327,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "memchr" => { - let ptr = this.read_scalar(args[0])?.not_undef()?; - let val = this.read_scalar(args[1])?.to_i32()? as u8; - let num = this.read_scalar(args[2])?.to_machine_usize(this)?; + let &[ptr, val, num] = check_arg_count(args)?; + let ptr = this.read_scalar(ptr)?.not_undef()?; + let val = this.read_scalar(val)?.to_i32()? as u8; + let num = this.read_scalar(num)?.to_machine_usize(this)?; let idx = this .memory .read_bytes(ptr, Size::from_bytes(num))? @@ -331,7 +344,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "strlen" => { - let ptr = this.read_scalar(args[0])?.not_undef()?; + let &[ptr] = check_arg_count(args)?; + let ptr = this.read_scalar(ptr)?.not_undef()?; let n = this.memory.read_c_str(ptr)?.len(); this.write_scalar(Scalar::from_machine_usize(u64::try_from(n).unwrap(), this), dest)?; } @@ -345,8 +359,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asinf" | "atanf" => { + let &[f] = check_arg_count(args)?; // FIXME: Using host floats. - let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); + let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let f = match link_name { "cbrtf" => f.cbrt(), "coshf" => f.cosh(), @@ -363,11 +378,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypotf" | "atan2f" => { + let &[f1, f2] = check_arg_count(args)?; // underscore case for windows, here and below // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) // FIXME: Using host floats. - let f1 = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); - let f2 = f32::from_bits(this.read_scalar(args[1])?.to_u32()?); + let f1 = f32::from_bits(this.read_scalar(f1)?.to_u32()?); + let f2 = f32::from_bits(this.read_scalar(f2)?.to_u32()?); let n = match link_name { "_hypotf" | "hypotf" => f1.hypot(f2), "atan2f" => f1.atan2(f2), @@ -383,8 +399,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asin" | "atan" => { + let &[f] = check_arg_count(args)?; // FIXME: Using host floats. - let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); + let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let f = match link_name { "cbrt" => f.cbrt(), "cosh" => f.cosh(), @@ -401,9 +418,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypot" | "atan2" => { + let &[f1, f2] = check_arg_count(args)?; // FIXME: Using host floats. - let f1 = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); - let f2 = f64::from_bits(this.read_scalar(args[1])?.to_u64()?); + let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?); + let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?); let n = match link_name { "_hypot" | "hypot" => f1.hypot(f2), "atan2" => f1.atan2(f2), @@ -415,9 +433,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "ldexp" | "scalbn" => { + let &[x, exp] = check_arg_count(args)?; // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. - let x = this.read_scalar(args[0])?.to_f64()?; - let exp = this.read_scalar(args[1])?.to_i32()?; + let x = this.read_scalar(x)?.to_f64()?; + let exp = this.read_scalar(exp)?.to_i32()?; // Saturating cast to i16. Even those are outside the valid exponent range to // `scalbn` below will do its over/underflow handling. diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 6e2a7a9fcb4f..4c50d5ddc5b8 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -6,6 +6,7 @@ use std::convert::TryFrom; use log::trace; use crate::*; +use helpers::check_arg_count; use rustc_middle::mir; use rustc_target::abi::{Align, LayoutOf, Size}; @@ -23,43 +24,51 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Environment related shims "getenv" => { - let result = this.getenv(args[0])?; + let &[name] = check_arg_count(args)?; + let result = this.getenv(name)?; this.write_scalar(result, dest)?; } "unsetenv" => { - let result = this.unsetenv(args[0])?; + let &[name] = check_arg_count(args)?; + let result = this.unsetenv(name)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "setenv" => { - let result = this.setenv(args[0], args[1])?; + let &[name, value, _overwrite] = check_arg_count(args)?; + let result = this.setenv(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "getcwd" => { - let result = this.getcwd(args[0], args[1])?; + let &[buf, size] = check_arg_count(args)?; + let result = this.getcwd(buf, size)?; this.write_scalar(result, dest)?; } "chdir" => { - let result = this.chdir(args[0])?; + let &[path] = check_arg_count(args)?; + let result = this.chdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // File related shims "open" | "open64" => { - let result = this.open(args[0], args[1])?; + let &[path, flag, _mode] = check_arg_count(args)?; + let result = this.open(path, flag)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fcntl" => { - let result = this.fcntl(args[0], args[1], args.get(2).cloned())?; + let result = this.fcntl(args); this.write_scalar(Scalar::from_i32(result), dest)?; } "read" => { - let result = this.read(args[0], args[1], args[2])?; + let &[fd, buf, count] = check_arg_count(args)?; + let result = this.read(fd, buf, count)?; this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "write" => { - let fd = this.read_scalar(args[0])?.to_i32()?; - let buf = this.read_scalar(args[1])?.not_undef()?; - let n = this.read_scalar(args[2])?.to_machine_usize(this)?; + let &[fd, buf, n] = check_arg_count(args)?; + let fd = this.read_scalar(fd)?.to_i32()?; + let buf = this.read_scalar(buf)?.not_undef()?; + let n = this.read_scalar(n)?.to_machine_usize(this)?; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { // stdout/stderr @@ -84,46 +93,55 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Err(_) => -1, } } else { - this.write(args[0], args[1], args[2])? + let &[fd, buf, count] = check_arg_count(args)?; + this.write(fd, buf, count)? }; // Now, `result` is the value we return back to the program. this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "unlink" => { - let result = this.unlink(args[0])?; + let &[path] = check_arg_count(args)?; + let result = this.unlink(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "symlink" => { - let result = this.symlink(args[0], args[1])?; + let &[target, linkpath] = check_arg_count(args)?; + let result = this.symlink(target, linkpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rename" => { - let result = this.rename(args[0], args[1])?; + let &[oldpath, newpath] = check_arg_count(args)?; + let result = this.rename(oldpath, newpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mkdir" => { - let result = this.mkdir(args[0], args[1])?; + let &[path, mode] = check_arg_count(args)?; + let result = this.mkdir(path, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rmdir" => { - let result = this.rmdir(args[0])?; + let &[path] = check_arg_count(args)?; + let result = this.rmdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "closedir" => { - let result = this.closedir(args[0])?; + let &[dirp] = check_arg_count(args)?; + let result = this.closedir(dirp)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lseek" | "lseek64" => { - let result = this.lseek64(args[0], args[1], args[2])?; + let &[fd, offset, whence] = check_arg_count(args)?; + let result = this.lseek64(fd, offset, whence)?; // "lseek" is only used on macOS which is 64bit-only, so `i64` always works. this.write_scalar(Scalar::from_i64(result), dest)?; } // Allocation "posix_memalign" => { - let ret = this.deref_operand(args[0])?; - let align = this.read_scalar(args[1])?.to_machine_usize(this)?; - let size = this.read_scalar(args[2])?.to_machine_usize(this)?; + let &[ret, align, size] = check_arg_count(args)?; + let ret = this.deref_operand(ret)?; + let align = this.read_scalar(align)?.to_machine_usize(this)?; + let size = this.read_scalar(size)?.to_machine_usize(this)?; // Align must be power of 2, and also at least ptr-sized (POSIX rules). if !align.is_power_of_two() { throw_ub_format!("posix_memalign: alignment must be a power of two, but is {}", align); @@ -150,8 +168,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamic symbol loading "dlsym" => { - let _handle = this.read_scalar(args[0])?; - let symbol = this.read_scalar(args[1])?.not_undef()?; + let &[_handle, symbol] = check_arg_count(args)?; + let _handle = this.read_scalar(_handle)?.not_undef()?; + let symbol = this.read_scalar(symbol)?.not_undef()?; let symbol_name = this.memory.read_c_str(symbol)?; let err = format!("bad c unicode symbol: {:?}", symbol_name); let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err); @@ -165,7 +184,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "sysconf" => { - let name = this.read_scalar(args[0])?.to_i32()?; + let &[name] = check_arg_count(args)?; + let name = this.read_scalar(name)?.to_i32()?; let sysconfs = &[ ("_SC_PAGESIZE", Scalar::from_int(PAGE_SIZE, this.pointer_size())), @@ -188,17 +208,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "pthread_key_create" => { - let key_place = this.deref_operand(args[0])?; + let &[key, dtor] = check_arg_count(args)?; + let key_place = this.deref_operand(key)?; + let dtor = this.read_scalar(dtor)?.not_undef()?; // Extract the function type out of the signature (that seems easier than constructing it ourselves). - let dtor = match this.test_null(this.read_scalar(args[1])?.not_undef()?)? { + let dtor = match this.test_null(dtor)? { Some(dtor_ptr) => Some(this.memory.get_fn(dtor_ptr)?.as_instance()?), None => None, }; // Figure out how large a pthread TLS key actually is. // To this end, deref the argument type. This is `libc::pthread_key_t`. - let key_type = args[0].layout.ty + let key_type = key.layout.ty .builtin_deref(true) .ok_or_else(|| err_ub_format!( "wrong signature used for `pthread_key_create`: first argument must be a raw pointer." @@ -214,21 +236,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_key_delete" => { - let key = this.force_bits(this.read_scalar(args[0])?.not_undef()?, args[0].layout.size)?; + let &[key] = check_arg_count(args)?; + let key = this.force_bits(this.read_scalar(key)?.not_undef()?, key.layout.size)?; this.machine.tls.delete_tls_key(key)?; // Return success (0) this.write_null(dest)?; } "pthread_getspecific" => { - let key = this.force_bits(this.read_scalar(args[0])?.not_undef()?, args[0].layout.size)?; + let &[key] = check_arg_count(args)?; + let key = this.force_bits(this.read_scalar(key)?.not_undef()?, key.layout.size)?; let active_thread = this.get_active_thread()?; let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { - let key = this.force_bits(this.read_scalar(args[0])?.not_undef()?, args[0].layout.size)?; + let &[key, new_ptr] = check_arg_count(args)?; + let key = this.force_bits(this.read_scalar(key)?.not_undef()?, key.layout.size)?; let active_thread = this.get_active_thread()?; - let new_ptr = this.read_scalar(args[1])?.not_undef()?; + let new_ptr = this.read_scalar(new_ptr)?.not_undef()?; this.machine.tls.store_tls(key, active_thread, this.test_null(new_ptr)?)?; // Return success (`0`). @@ -237,91 +262,106 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Synchronization primitives "pthread_mutexattr_init" => { - let result = this.pthread_mutexattr_init(args[0])?; + let &[attr] = check_arg_count(args)?; + let result = this.pthread_mutexattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_settype" => { - let result = this.pthread_mutexattr_settype(args[0], args[1])?; + let &[attr, kind] = check_arg_count(args)?; + let result = this.pthread_mutexattr_settype(attr, kind)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_destroy" => { - let result = this.pthread_mutexattr_destroy(args[0])?; + let &[attr] = check_arg_count(args)?; + let result = this.pthread_mutexattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_init" => { - let result = this.pthread_mutex_init(args[0], args[1])?; + let &[mutex, attr] = check_arg_count(args)?; + let result = this.pthread_mutex_init(mutex, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_lock" => { - let result = this.pthread_mutex_lock(args[0])?; + let &[mutex] = check_arg_count(args)?; + let result = this.pthread_mutex_lock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_trylock" => { - let result = this.pthread_mutex_trylock(args[0])?; + let &[mutex] = check_arg_count(args)?; + let result = this.pthread_mutex_trylock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_unlock" => { - let result = this.pthread_mutex_unlock(args[0])?; + let &[mutex] = check_arg_count(args)?; + let result = this.pthread_mutex_unlock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_destroy" => { - let result = this.pthread_mutex_destroy(args[0])?; + let &[mutex] = check_arg_count(args)?; + let result = this.pthread_mutex_destroy(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_rdlock" => { - let result = this.pthread_rwlock_rdlock(args[0])?; + let &[rwlock] = check_arg_count(args)?; + let result = this.pthread_rwlock_rdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_tryrdlock" => { - let result = this.pthread_rwlock_tryrdlock(args[0])?; + let &[rwlock] = check_arg_count(args)?; + let result = this.pthread_rwlock_tryrdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_wrlock" => { - let result = this.pthread_rwlock_wrlock(args[0])?; + let &[rwlock] = check_arg_count(args)?; + let result = this.pthread_rwlock_wrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_trywrlock" => { - let result = this.pthread_rwlock_trywrlock(args[0])?; + let &[rwlock] = check_arg_count(args)?; + let result = this.pthread_rwlock_trywrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_unlock" => { - let result = this.pthread_rwlock_unlock(args[0])?; + let &[rwlock] = check_arg_count(args)?; + let result = this.pthread_rwlock_unlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_destroy" => { - let result = this.pthread_rwlock_destroy(args[0])?; + let &[rwlock] = check_arg_count(args)?; + let result = this.pthread_rwlock_destroy(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Threading "pthread_create" => { - assert_eq!(args.len(), 4); - let result = this.pthread_create(args[0], args[1], args[2], args[3])?; + let &[thread, attr, start, arg] = check_arg_count(args)?; + let result = this.pthread_create(thread, attr, start, arg)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_join" => { - assert_eq!(args.len(), 2); - let result = this.pthread_join(args[0], args[1])?; + let &[thread, retval] = check_arg_count(args)?; + let result = this.pthread_join(thread, retval)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_detach" => { - assert_eq!(args.len(), 1); - let result = this.pthread_detach(args[0])?; + let &[thread] = check_arg_count(args)?; + let result = this.pthread_detach(thread)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_self" => { - assert_eq!(args.len(), 0); + let &[] = check_arg_count(args)?; this.pthread_self(dest)?; } "sched_yield" => { - assert_eq!(args.len(), 0); + let &[] = check_arg_count(args)?; let result = this.sched_yield()?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Miscellaneous "isatty" => { - let _fd = this.read_scalar(args[0])?.to_i32()?; + let &[_fd] = check_arg_count(args)?; + let _fd = this.read_scalar(_fd)?.to_i32()?; // "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error" // FIXME: we just say nothing is a terminal. let enotty = this.eval_libc("ENOTTY")?; @@ -329,9 +369,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_atfork" => { - let _prepare = this.read_scalar(args[0])?.not_undef()?; - let _parent = this.read_scalar(args[1])?.not_undef()?; - let _child = this.read_scalar(args[1])?.not_undef()?; + let &[_prepare, _parent, _child] = check_arg_count(args)?; + let _prepare = this.read_scalar(_prepare)?.not_undef()?; + let _parent = this.read_scalar(_parent)?.not_undef()?; + let _child = this.read_scalar(_child)?.not_undef()?; // We do not support forking, so there is nothing to do here. this.write_null(dest)?; } @@ -351,7 +392,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "pthread_attr_getguardsize" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - let guard_size = this.deref_operand(args[1])?; + let &[_attr, guard_size] = check_arg_count(args)?; + let guard_size = this.deref_operand(guard_size)?; let guard_size_layout = this.libc_ty_layout("size_t")?; this.write_scalar(Scalar::from_uint(crate::PAGE_SIZE, guard_size_layout.size), guard_size.into())?; diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index eb58f7466089..b0f4a45f1c01 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -1,4 +1,5 @@ use crate::*; +use helpers::check_arg_count; use rustc_middle::mir; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -15,6 +16,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // errno "__errno_location" => { + let &[] = check_arg_count(args)?; let errno_place = this.machine.last_error.unwrap(); this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } @@ -23,27 +25,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These symbols have different names on Linux and macOS, which is the only reason they are not // in the `posix` module. "close" => { - let result = this.close(args[0])?; + let &[fd] = check_arg_count(args)?; + let result = this.close(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" => { - let result = this.opendir(args[0])?; + let &[name] = check_arg_count(args)?; + let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir64_r" => { - let result = this.linux_readdir64_r(args[0], args[1], args[2])?; + let &[dirp, entry, result] = check_arg_count(args)?; + let result = this.linux_readdir64_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate64" => { - let result = this.ftruncate64(args[0], args[1])?; + let &[fd, length] = check_arg_count(args)?; + let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Linux-only "posix_fadvise" => { - let _fd = this.read_scalar(args[0])?.to_i32()?; - let _offset = this.read_scalar(args[1])?.to_machine_isize(this)?; - let _len = this.read_scalar(args[2])?.to_machine_isize(this)?; - let _advice = this.read_scalar(args[3])?.to_i32()?; + let &[_fd, _offset, _len, _advice] = check_arg_count(args)?; + let _fd = this.read_scalar(_fd)?.to_i32()?; + let _offset = this.read_scalar(_offset)?.to_machine_isize(this)?; + let _len = this.read_scalar(_len)?.to_machine_isize(this)?; + let _advice = this.read_scalar(_advice)?.to_i32()?; // fadvise is only informational, we can ignore it. this.write_null(dest)?; } @@ -51,16 +58,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "clock_gettime" => { // This is a POSIX function but it has only been tested on linux. - let result = this.clock_gettime(args[0], args[1])?; + let &[clk_id, tp] = check_arg_count(args)?; + let result = this.clock_gettime(clk_id, tp)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Querying system information "pthread_attr_getstack" => { // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. - let _attr_place = this.deref_operand(args[0])?; - let addr_place = this.deref_operand(args[1])?; - let size_place = this.deref_operand(args[2])?; + let &[_attr_place, addr_place, size_place] = check_arg_count(args)?; + let _attr_place = this.deref_operand(_attr_place)?; + let addr_place = this.deref_operand(addr_place)?; + let size_place = this.deref_operand(size_place)?; this.write_scalar( Scalar::from_uint(STACK_ADDR, this.pointer_size()), @@ -77,8 +86,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "prctl" => { - assert_eq!(args.len(), 5); - let result = this.prctl(args[0], args[1], args[2], args[3], args[4])?; + let &[option, arg2, arg3, arg4, arg5] = check_arg_count(args)?; + let result = this.prctl(option, arg2, arg3, arg4, arg5)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -92,6 +101,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .eval_libc("SYS_statx")? .to_machine_usize(this)?; + if args.is_empty() { + throw_ub_format!("incorrect number of arguments, needed at least 1"); + } match this.read_scalar(args[0])?.to_machine_usize(this)? { // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` // is called if a `HashMap` is created the regular way (e.g. HashMap). @@ -103,7 +115,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // instead of using `stat`,`lstat` or `fstat` as on `macos`. id if id == sys_statx => { // The first argument is the syscall id, so skip over it. - let result = this.linux_statx(args[1], args[2], args[3], args[4], args[5])?; + let &[_, dirfd, pathname, flags, mask, statxbuf] = check_arg_count(args)?; + let result = this.linux_statx(dirfd, pathname, flags, mask, statxbuf)?; this.write_scalar(Scalar::from_machine_isize(result.into(), this), dest)?; } id => throw_unsup_format!("miri does not support syscall ID {}", id), @@ -115,9 +128,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx getrandom(this, args, dest)?; } "sched_getaffinity" => { - let _pid = this.read_scalar(args[0])?.to_i32()?; - let _cpusetsize = this.read_scalar(args[1])?.to_machine_usize(this)?; - let _mask = this.deref_operand(args[2])?; + let &[_pid, _cpusetsize, _mask] = check_arg_count(args)?; + let _pid = this.read_scalar(_pid)?.to_i32()?; + let _cpusetsize = this.read_scalar(_cpusetsize)?.to_machine_usize(this)?; + let _mask = this.deref_operand(_mask)?; // FIXME: we just return an error; `num_cpus` then falls back to `sysconf`. let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; @@ -143,12 +157,13 @@ fn getrandom<'tcx>( args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { - let ptr = this.read_scalar(args[0])?.not_undef()?; - let len = this.read_scalar(args[1])?.to_machine_usize(this)?; + let &[ptr, len, _flags] = check_arg_count(args)?; + let ptr = this.read_scalar(ptr)?.not_undef()?; + let len = this.read_scalar(len)?.to_machine_usize(this)?; // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, // neither of which have any effect on our current PRNG. - let _flags = this.read_scalar(args[2])?.to_i32()?; + let _flags = this.read_scalar(_flags)?.to_i32()?; this.gen_random(ptr, len)?; this.write_scalar(Scalar::from_machine_usize(len, this), dest)?; diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 3677960fd877..e9fd3aa8ac81 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -1,4 +1,5 @@ use crate::*; +use helpers::check_arg_count; use rustc_middle::mir; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -15,85 +16,102 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // errno "__error" => { + let &[] = check_arg_count(args)?; let errno_place = this.machine.last_error.unwrap(); this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } // File related shims "close$NOCANCEL" => { - let result = this.close(args[0])?; + let &[result] = check_arg_count(args)?; + let result = this.close(result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "stat$INODE64" => { - let result = this.macos_stat(args[0], args[1])?; + let &[path, buf] = check_arg_count(args)?; + let result = this.macos_stat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lstat$INODE64" => { - let result = this.macos_lstat(args[0], args[1])?; + let &[path, buf] = check_arg_count(args)?; + let result = this.macos_lstat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fstat$INODE64" => { - let result = this.macos_fstat(args[0], args[1])?; + let &[fd, buf] = check_arg_count(args)?; + let result = this.macos_fstat(fd, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir$INODE64" => { - let result = this.opendir(args[0])?; + let &[name] = check_arg_count(args)?; + let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir_r$INODE64" => { - let result = this.macos_readdir_r(args[0], args[1], args[2])?; + let &[dirp, entry, result] = check_arg_count(args)?; + let result = this.macos_readdir_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate" => { - let result = this.ftruncate64(args[0], args[1])?; + let &[fd, length] = check_arg_count(args)?; + let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Environment related shims "_NSGetEnviron" => { + let &[] = check_arg_count(args)?; this.write_scalar(this.machine.env_vars.environ.unwrap().ptr, dest)?; } // Time related shims "gettimeofday" => { - let result = this.gettimeofday(args[0], args[1])?; + let &[tv, tz] = check_arg_count(args)?; + let result = this.gettimeofday(tv, tz)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mach_absolute_time" => { + let &[] = check_arg_count(args)?; let result = this.mach_absolute_time()?; this.write_scalar(Scalar::from_u64(result), dest)?; } "mach_timebase_info" => { - let result = this.mach_timebase_info(args[0])?; + let &[info] = check_arg_count(args)?; + let result = this.mach_timebase_info(info)?; this.write_scalar(Scalar::from_i32(result), dest)?; }, // Access to command-line arguments "_NSGetArgc" => { + let &[] = check_arg_count(args)?; this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?; } "_NSGetArgv" => { + let &[] = check_arg_count(args)?; this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; } // Thread-local storage "_tlv_atexit" => { - let dtor = this.read_scalar(args[0])?.not_undef()?; + let &[dtor, data] = check_arg_count(args)?; + let dtor = this.read_scalar(dtor)?.not_undef()?; let dtor = this.memory.get_fn(dtor)?.as_instance()?; - let data = this.read_scalar(args[1])?.not_undef()?; + let data = this.read_scalar(data)?.not_undef()?; let active_thread = this.get_active_thread()?; this.machine.tls.set_macos_thread_dtor(active_thread, dtor, data)?; } // Querying system information "pthread_get_stackaddr_np" => { - let _thread = this.read_scalar(args[0])?.not_undef()?; + let &[_thread] = check_arg_count(args)?; + let _thread = this.read_scalar(_thread)?.not_undef()?; let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size()); this.write_scalar(stack_addr, dest)?; } "pthread_get_stacksize_np" => { - let _thread = this.read_scalar(args[0])?.not_undef()?; + let &[_thread] = check_arg_count(args)?; + let _thread = this.read_scalar(_thread)?.not_undef()?; let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size()); this.write_scalar(stack_size, dest)?; } @@ -108,7 +126,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These shims are enabled only when the caller is in the standard library. "mmap" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. - let addr = this.read_scalar(args[0])?.not_undef()?; + let &[addr, _, _, _, _, _] = check_arg_count(args)?; + let addr = this.read_scalar(addr)?.not_undef()?; this.write_scalar(addr, dest)?; } diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index f55b5b8450e0..9edd20ddcab1 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -4,6 +4,7 @@ use rustc_middle::mir; use rustc_target::abi::Size; use crate::*; +use helpers::check_arg_count; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -23,42 +24,50 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Environment related shims "GetEnvironmentVariableW" => { - let result = this.GetEnvironmentVariableW(args[0], args[1], args[2])?; + let &[name, buf, size] = check_arg_count(args)?; + let result = this.GetEnvironmentVariableW(name, buf, size)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetEnvironmentVariableW" => { - let result = this.SetEnvironmentVariableW(args[0], args[1])?; + let &[name, value] = check_arg_count(args)?; + let result = this.SetEnvironmentVariableW(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetEnvironmentStringsW" => { + let &[] = check_arg_count(args)?; let result = this.GetEnvironmentStringsW()?; this.write_scalar(result, dest)?; } "FreeEnvironmentStringsW" => { - let result = this.FreeEnvironmentStringsW(args[0])?; + let &[env_block] = check_arg_count(args)?; + let result = this.FreeEnvironmentStringsW(env_block)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetCurrentDirectoryW" => { - let result = this.GetCurrentDirectoryW(args[0], args[1])?; + let &[size, buf] = check_arg_count(args)?; + let result = this.GetCurrentDirectoryW(size, buf)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetCurrentDirectoryW" => { - let result = this.SetCurrentDirectoryW(args[0])?; + let &[path] = check_arg_count(args)?; + let result = this.SetCurrentDirectoryW(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // File related shims "GetStdHandle" => { - let which = this.read_scalar(args[0])?.to_i32()?; + let &[which] = check_arg_count(args)?; + let which = this.read_scalar(which)?.to_i32()?; // We just make this the identity function, so we know later in `WriteFile` // which one it is. this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?; } "WriteFile" => { - let handle = this.read_scalar(args[0])?.to_machine_isize(this)?; - let buf = this.read_scalar(args[1])?.not_undef()?; - let n = this.read_scalar(args[2])?.to_u32()?; - let written_place = this.deref_operand(args[3])?; + let &[handle, buf, n, written_ptr, _overlapped] = check_arg_count(args)?; + let handle = this.read_scalar(handle)?.to_machine_isize(this)?; + let buf = this.read_scalar(buf)?.not_undef()?; + let n = this.read_scalar(n)?.to_u32()?; + let written_place = this.deref_operand(written_ptr)?; // Spec says to always write `0` first. this.write_null(written_place.into())?; let written = if handle == -11 || handle == -12 { @@ -88,41 +97,48 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Allocation "HeapAlloc" => { - let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?; - let flags = this.read_scalar(args[1])?.to_u32()?; - let size = this.read_scalar(args[2])?.to_machine_usize(this)?; + let &[_handle, flags, size] = check_arg_count(args)?; + let _handle = this.read_scalar(_handle)?.to_machine_isize(this)?; + let flags = this.read_scalar(flags)?.to_u32()?; + let size = this.read_scalar(size)?.to_machine_usize(this)?; let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY let res = this.malloc(size, zero_init, MiriMemoryKind::WinHeap); this.write_scalar(res, dest)?; } "HeapFree" => { - let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?; - let _flags = this.read_scalar(args[1])?.to_u32()?; - let ptr = this.read_scalar(args[2])?.not_undef()?; + let &[_handle, _flags, ptr] = check_arg_count(args)?; + let _handle = this.read_scalar(_handle)?.to_machine_isize(this)?; + let _flags = this.read_scalar(_flags)?.to_u32()?; + let ptr = this.read_scalar(ptr)?.not_undef()?; this.free(ptr, MiriMemoryKind::WinHeap)?; this.write_scalar(Scalar::from_i32(1), dest)?; } "HeapReAlloc" => { - let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?; - let _flags = this.read_scalar(args[1])?.to_u32()?; - let ptr = this.read_scalar(args[2])?.not_undef()?; - let size = this.read_scalar(args[3])?.to_machine_usize(this)?; + let &[_handle, _flags, ptr, size] = check_arg_count(args)?; + let _handle = this.read_scalar(_handle)?.to_machine_isize(this)?; + let _flags = this.read_scalar(_flags)?.to_u32()?; + let ptr = this.read_scalar(ptr)?.not_undef()?; + let size = this.read_scalar(size)?.to_machine_usize(this)?; let res = this.realloc(ptr, size, MiriMemoryKind::WinHeap)?; this.write_scalar(res, dest)?; } // errno "SetLastError" => { - this.set_last_error(this.read_scalar(args[0])?.not_undef()?)?; + let &[error] = check_arg_count(args)?; + let error = this.read_scalar(error)?.not_undef()?; + this.set_last_error(error)?; } "GetLastError" => { + let &[] = check_arg_count(args)?; let last_error = this.get_last_error()?; this.write_scalar(last_error, dest)?; } // Querying system information "GetSystemInfo" => { - let system_info = this.deref_operand(args[0])?; + let &[system_info] = check_arg_count(args)?; + let system_info = this.deref_operand(system_info)?; // Initialize with `0`. this.memory.write_bytes( system_info.ptr, @@ -139,19 +155,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This just creates a key; Windows does not natively support TLS destructors. // Create key and return it. + let &[] = check_arg_count(args)?; let key = this.machine.tls.create_tls_key(None, dest.layout.size)?; this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { - let key = u128::from(this.read_scalar(args[0])?.to_u32()?); + let &[key] = check_arg_count(args)?; + let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread()?; let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "TlsSetValue" => { - let key = u128::from(this.read_scalar(args[0])?.to_u32()?); + let &[key, new_ptr] = check_arg_count(args)?; + let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread()?; - let new_ptr = this.read_scalar(args[1])?.not_undef()?; + let new_ptr = this.read_scalar(new_ptr)?.not_undef()?; this.machine.tls.store_tls(key, active_thread, this.test_null(new_ptr)?)?; // Return success (`1`). @@ -160,6 +179,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Access to command-line arguments "GetCommandLineW" => { + let &[] = check_arg_count(args)?; this.write_scalar( this.machine.cmd_line.expect("machine must be initialized"), dest, @@ -168,42 +188,52 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "GetSystemTimeAsFileTime" => { - this.GetSystemTimeAsFileTime(args[0])?; + #[allow(non_snake_case)] + let &[LPFILETIME] = check_arg_count(args)?; + this.GetSystemTimeAsFileTime(LPFILETIME)?; } "QueryPerformanceCounter" => { - let result = this.QueryPerformanceCounter(args[0])?; + #[allow(non_snake_case)] + let &[lpPerformanceCount] = check_arg_count(args)?; + let result = this.QueryPerformanceCounter(lpPerformanceCount)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "QueryPerformanceFrequency" => { - let result = this.QueryPerformanceFrequency(args[0])?; + #[allow(non_snake_case)] + let &[lpFrequency] = check_arg_count(args)?; + let result = this.QueryPerformanceFrequency(lpFrequency)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Miscellaneous "SystemFunction036" => { // The actual name of 'RtlGenRandom' - let ptr = this.read_scalar(args[0])?.not_undef()?; - let len = this.read_scalar(args[1])?.to_u32()?; + let &[ptr, len] = check_arg_count(args)?; + let ptr = this.read_scalar(ptr)?.not_undef()?; + let len = this.read_scalar(len)?.to_u32()?; this.gen_random(ptr, len.into())?; this.write_scalar(Scalar::from_bool(true), dest)?; } "GetConsoleScreenBufferInfo" => { // `term` needs this, so we fake it. - let _console = this.read_scalar(args[0])?.to_machine_isize(this)?; - let _buffer_info = this.deref_operand(args[1])?; + let &[_console, _buffer_info] = check_arg_count(args)?; + let _console = this.read_scalar(_console)?.to_machine_isize(this)?; + let _buffer_info = this.deref_operand(_buffer_info)?; // Indicate an error. // FIXME: we should set last_error, but to what? this.write_null(dest)?; } "GetConsoleMode" => { // Windows "isatty" (in libtest) needs this, so we fake it. - let _console = this.read_scalar(args[0])?.to_machine_isize(this)?; - let _mode = this.deref_operand(args[1])?; + let &[_console, _mode] = check_arg_count(args)?; + let _console = this.read_scalar(_console)?.to_machine_isize(this)?; + let _mode = this.deref_operand(_mode)?; // Indicate an error. // FIXME: we should set last_error, but to what? this.write_null(dest)?; } "SwitchToThread" => { + let &[] = check_arg_count(args)?; // Note that once Miri supports concurrency, this will need to return a nonzero // value if this call does result in switching to another thread. this.write_null(dest)?; @@ -217,17 +247,34 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "GetProcessHeap" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + let &[] = check_arg_count(args)?; // Just fake a HANDLE this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } - | "GetModuleHandleW" - | "GetProcAddress" - | "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") + "GetModuleHandleW" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - // Pretend these do not exist / nothing happened, by returning zero. + #[allow(non_snake_case)] + let &[_lpModuleName] = check_arg_count(args)?; + // Pretend this does not exist / nothing happened, by returning zero. + this.write_null(dest)?; + } + "GetProcAddress" if this.frame().instance.to_string().starts_with("std::sys::windows::") + => { + #[allow(non_snake_case)] + let &[_hModule, _lpProcName] = check_arg_count(args)?; + // Pretend this does not exist / nothing happened, by returning zero. + this.write_null(dest)?; + } + "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") + => { + #[allow(non_snake_case)] + let &[_hConsoleOutput, _wAttribute] = check_arg_count(args)?; + // Pretend these does not exist / nothing happened, by returning zero. this.write_null(dest)?; } "AddVectoredExceptionHandler" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + #[allow(non_snake_case)] + let &[_First, _Handler] = check_arg_count(args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_machine_usize(1, this), dest)?; } @@ -236,6 +283,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "LeaveCriticalSection" | "DeleteCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + #[allow(non_snake_case)] + let &[_lpCriticalSection] = check_arg_count(args)?; assert_eq!(this.get_total_thread_count()?, 1, "concurrency on Windows not supported"); // Nothing to do, not even a return value. // (Windows locks are reentrant, and we have only 1 thread, @@ -243,6 +292,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "TryEnterCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + #[allow(non_snake_case)] + let &[_lpCriticalSection] = check_arg_count(args)?; assert_eq!(this.get_total_thread_count()?, 1, "concurrency on Windows not supported"); // There is only one thread, so this always succeeds and returns TRUE this.write_scalar(Scalar::from_i32(1), dest)?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index ea0b998c2e3d..b9bb0fadf1a4 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -10,7 +10,7 @@ use rustc_target::abi::{Align, LayoutOf, Size}; use crate::stacked_borrows::Tag; use crate::*; -use helpers::{immty_from_int_checked, immty_from_uint_checked}; +use helpers::{check_arg_count, immty_from_int_checked, immty_from_uint_checked}; use shims::time::system_time_to_duration; #[derive(Debug)] @@ -322,16 +322,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn fcntl( &mut self, - fd_op: OpTy<'tcx, Tag>, - cmd_op: OpTy<'tcx, Tag>, - start_op: Option>, + args: &[OpTy<'tcx, Tag>], ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.check_no_isolation("fcntl")?; - let fd = this.read_scalar(fd_op)?.to_i32()?; - let cmd = this.read_scalar(cmd_op)?.to_i32()?; + let (fd, cmd, start) = if args.len() == 2 { + let &[fd, cmd] = check_arg_count(args)?; + (fd, cmd, None) + } else { + // If args.len() isn't 2 or 3 this will error appropriately. + let &[fd, cmd, start] = check_arg_count(args)?; + (fd, cmd, Some(start)) + }; + let fd = this.read_scalar(fd)?.to_i32()?; + let cmd = this.read_scalar(cmd)?.to_i32()?; // We only support getting the flags for a descriptor. if cmd == this.eval_libc_i32("F_GETFD")? { // Currently this is the only flag that `F_GETFD` returns. It is OK to just return the @@ -353,12 +359,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if fd < MIN_NORMAL_FILE_FD { throw_unsup_format!("duplicating file descriptors for stdin, stdout, or stderr is not supported") } - let start_op = start_op.ok_or_else(|| { + let start = start.ok_or_else(|| { err_unsup_format!( "fcntl with command F_DUPFD or F_DUPFD_CLOEXEC requires a third argument" ) })?; - let start = this.read_scalar(start_op)?.to_i32()?; + let start = this.read_scalar(start)?.to_i32()?; let fh = &mut this.machine.file_handler; let (file_result, writable) = match fh.handles.get(&fd) { Some(FileHandle { file, writable }) => (file.try_clone(), *writable), @@ -1064,7 +1070,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } fn ftruncate64( - &mut self, fd_op: OpTy<'tcx, Tag>, + &mut self, + fd_op: OpTy<'tcx, Tag>, length_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index b64aeef485ea..a77443ef5224 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -7,6 +7,7 @@ use rustc_apfloat::{Float, Round}; use rustc_target::abi::{Align, LayoutOf, Size}; use crate::*; +use helpers::check_arg_count; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -45,16 +46,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "copy" | "copy_nonoverlapping" => { + let &[src, dest, count] = check_arg_count(args)?; let elem_ty = substs.type_at(0); let elem_layout = this.layout_of(elem_ty)?; - let count = this.read_scalar(args[2])?.to_machine_usize(this)?; + let count = this.read_scalar(count)?.to_machine_usize(this)?; let elem_align = elem_layout.align.abi; let size = elem_layout.size.checked_mul(count, this) .ok_or_else(|| err_ub_format!("overflow computing total size of `{}`", intrinsic_name))?; - let src = this.read_scalar(args[0])?.not_undef()?; + let src = this.read_scalar(src)?.not_undef()?; let src = this.memory.check_ptr_access(src, size, elem_align)?; - let dest = this.read_scalar(args[1])?.not_undef()?; + let dest = this.read_scalar(dest)?.not_undef()?; let dest = this.memory.check_ptr_access(dest, size, elem_align)?; if let (Some(src), Some(dest)) = (src, dest) { @@ -68,25 +70,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "move_val_init" => { - let place = this.deref_operand(args[0])?; - this.copy_op(args[1], place.into())?; + let &[place, dest] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + this.copy_op(dest, place.into())?; } "volatile_load" => { - let place = this.deref_operand(args[0])?; + let &[place] = check_arg_count(args)?; + let place = this.deref_operand(place)?; this.copy_op(place.into(), dest)?; } "volatile_store" => { - let place = this.deref_operand(args[0])?; - this.copy_op(args[1], place.into())?; + let &[place, dest] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + this.copy_op(dest, place.into())?; } "write_bytes" => { + let &[ptr, val_byte, count] = check_arg_count(args)?; let ty = substs.type_at(0); let ty_layout = this.layout_of(ty)?; - let val_byte = this.read_scalar(args[1])?.to_u8()?; - let ptr = this.read_scalar(args[0])?.not_undef()?; - let count = this.read_scalar(args[2])?.to_machine_usize(this)?; + let val_byte = this.read_scalar(val_byte)?.to_u8()?; + let ptr = this.read_scalar(ptr)?.not_undef()?; + let count = this.read_scalar(count)?.to_machine_usize(this)?; let byte_count = ty_layout.size.checked_mul(count, this) .ok_or_else(|| err_ub_format!("overflow computing total size of `write_bytes`"))?; this.memory @@ -95,8 +101,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Pointer arithmetic "arith_offset" => { - let offset = this.read_scalar(args[1])?.to_machine_isize(this)?; - let ptr = this.read_scalar(args[0])?.not_undef()?; + let &[ptr, offset] = check_arg_count(args)?; + let ptr = this.read_scalar(ptr)?.not_undef()?; + let offset = this.read_scalar(offset)?.to_machine_isize(this)?; let pointee_ty = substs.type_at(0); let pointee_size = i64::try_from(this.layout_of(pointee_ty)?.size.bytes()).unwrap(); @@ -105,8 +112,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(result_ptr, dest)?; } "offset" => { - let offset = this.read_scalar(args[1])?.to_machine_isize(this)?; - let ptr = this.read_scalar(args[0])?.not_undef()?; + let &[ptr, offset] = check_arg_count(args)?; + let ptr = this.read_scalar(ptr)?.not_undef()?; + let offset = this.read_scalar(offset)?.to_machine_isize(this)?; let result_ptr = this.pointer_offset_inbounds(ptr, substs.type_at(0), offset)?; this.write_scalar(result_ptr, dest)?; } @@ -127,8 +135,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "truncf32" | "roundf32" => { + let &[f] = check_arg_count(args)?; // FIXME: Using host floats. - let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); + let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let f = match intrinsic_name { "sinf32" => f.sin(), "fabsf32" => f.abs(), @@ -163,8 +172,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "truncf64" | "roundf64" => { + let &[f] = check_arg_count(args)?; // FIXME: Using host floats. - let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); + let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let f = match intrinsic_name { "sinf64" => f.sin(), "fabsf64" => f.abs(), @@ -191,8 +201,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "fdiv_fast" | "frem_fast" => { - let a = this.read_immediate(args[0])?; - let b = this.read_immediate(args[1])?; + let &[a, b] = check_arg_count(args)?; + let a = this.read_immediate(a)?; + let b = this.read_immediate(b)?; let op = match intrinsic_name { "fadd_fast" => mir::BinOp::Add, "fsub_fast" => mir::BinOp::Sub, @@ -209,8 +220,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "maxnumf32" | "copysignf32" => { - let a = this.read_scalar(args[0])?.to_f32()?; - let b = this.read_scalar(args[1])?.to_f32()?; + let &[a, b] = check_arg_count(args)?; + let a = this.read_scalar(a)?.to_f32()?; + let b = this.read_scalar(b)?.to_f32()?; let res = match intrinsic_name { "minnumf32" => a.min(b), "maxnumf32" => a.max(b), @@ -225,8 +237,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "maxnumf64" | "copysignf64" => { - let a = this.read_scalar(args[0])?.to_f64()?; - let b = this.read_scalar(args[1])?.to_f64()?; + let &[a, b] = check_arg_count(args)?; + let a = this.read_scalar(a)?.to_f64()?; + let b = this.read_scalar(b)?.to_f64()?; let res = match intrinsic_name { "minnumf64" => a.min(b), "maxnumf64" => a.max(b), @@ -235,53 +248,60 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; this.write_scalar(Scalar::from_f64(res), dest)?; } - + "powf32" => { + let &[f, f2] = check_arg_count(args)?; // FIXME: Using host floats. - let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); - let f2 = f32::from_bits(this.read_scalar(args[1])?.to_u32()?); + let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); + let f2 = f32::from_bits(this.read_scalar(f2)?.to_u32()?); this.write_scalar(Scalar::from_u32(f.powf(f2).to_bits()), dest)?; } "powf64" => { + let &[f, f2] = check_arg_count(args)?; // FIXME: Using host floats. - let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); - let f2 = f64::from_bits(this.read_scalar(args[1])?.to_u64()?); + let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); + let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?); this.write_scalar(Scalar::from_u64(f.powf(f2).to_bits()), dest)?; } "fmaf32" => { - let a = this.read_scalar(args[0])?.to_f32()?; - let b = this.read_scalar(args[1])?.to_f32()?; - let c = this.read_scalar(args[2])?.to_f32()?; + let &[a, b, c] = check_arg_count(args)?; + let a = this.read_scalar(a)?.to_f32()?; + let b = this.read_scalar(b)?.to_f32()?; + let c = this.read_scalar(c)?.to_f32()?; let res = a.mul_add(b, c).value; this.write_scalar(Scalar::from_f32(res), dest)?; } "fmaf64" => { - let a = this.read_scalar(args[0])?.to_f64()?; - let b = this.read_scalar(args[1])?.to_f64()?; - let c = this.read_scalar(args[2])?.to_f64()?; + let &[a, b, c] = check_arg_count(args)?; + let a = this.read_scalar(a)?.to_f64()?; + let b = this.read_scalar(b)?.to_f64()?; + let c = this.read_scalar(c)?.to_f64()?; let res = a.mul_add(b, c).value; this.write_scalar(Scalar::from_f64(res), dest)?; } "powif32" => { + let &[f, i] = check_arg_count(args)?; // FIXME: Using host floats. - let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); - let i = this.read_scalar(args[1])?.to_i32()?; + let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); + let i = this.read_scalar(i)?.to_i32()?; this.write_scalar(Scalar::from_u32(f.powi(i).to_bits()), dest)?; } "powif64" => { + let &[f, i] = check_arg_count(args)?; // FIXME: Using host floats. - let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); - let i = this.read_scalar(args[1])?.to_i32()?; + let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); + let i = this.read_scalar(i)?.to_i32()?; this.write_scalar(Scalar::from_u64(f.powi(i).to_bits()), dest)?; } "float_to_int_unchecked" => { - let val = this.read_immediate(args[0])?; + let &[val] = check_arg_count(args)?; + let val = this.read_immediate(val)?; let res = match val.layout.ty.kind { ty::Float(FloatTy::F32) => { @@ -302,7 +322,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "atomic_load_relaxed" | "atomic_load_acq" => { - let place = this.deref_operand(args[0])?; + let &[place] = check_arg_count(args)?; + let place = this.deref_operand(place)?; let val = this.read_scalar(place.into())?; // make sure it fits into a scalar; otherwise it cannot be atomic // Check alignment requirements. Atomics must always be aligned to their size, @@ -319,8 +340,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "atomic_store_relaxed" | "atomic_store_rel" => { - let place = this.deref_operand(args[0])?; - let val = this.read_scalar(args[1])?; // make sure it fits into a scalar; otherwise it cannot be atomic + let &[place, val] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + let val = this.read_scalar(val)?; // make sure it fits into a scalar; otherwise it cannot be atomic // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must @@ -345,8 +367,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } _ if intrinsic_name.starts_with("atomic_xchg") => { - let place = this.deref_operand(args[0])?; - let new = this.read_scalar(args[1])?; + let &[place, new] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + let new = this.read_scalar(new)?; let old = this.read_scalar(place.into())?; // Check alignment requirements. Atomics must always be aligned to their size, @@ -360,9 +383,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } _ if intrinsic_name.starts_with("atomic_cxchg") => { - let place = this.deref_operand(args[0])?; - let expect_old = this.read_immediate(args[1])?; // read as immediate for the sake of `binary_op()` - let new = this.read_scalar(args[2])?; + let &[place, expect_old, new] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + let expect_old = this.read_immediate(expect_old)?; // read as immediate for the sake of `binary_op()` + let new = this.read_scalar(new)?; let old = this.read_immediate(place.into())?; // read as immediate for the sake of `binary_op()` // Check alignment requirements. Atomics must always be aligned to their size, @@ -414,11 +438,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "atomic_xsub_acqrel" | "atomic_xsub_relaxed" => { - let place = this.deref_operand(args[0])?; + let &[place, rhs] = check_arg_count(args)?; + let place = this.deref_operand(place)?; if !place.layout.ty.is_integral() { bug!("Atomic arithmetic operations only work on integer types"); } - let rhs = this.read_immediate(args[1])?; + let rhs = this.read_immediate(rhs)?; let old = this.read_immediate(place.into())?; // Check alignment requirements. Atomics must always be aligned to their size, @@ -447,6 +472,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "assert_inhabited" | "assert_zero_valid" | "assert_uninit_valid" => { + let &[] = check_arg_count(args)?; let ty = substs.type_at(0); let layout = this.layout_of(ty)?; // Abort here because the caller might not be panic safe. @@ -462,7 +488,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "min_align_of_val" => { - let mplace = this.deref_operand(args[0])?; + let &[mplace] = check_arg_count(args)?; + let mplace = this.deref_operand(mplace)?; let (_, align) = this .size_and_align_of_mplace(mplace)? .expect("size_of_val called on extern type"); @@ -470,7 +497,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "size_of_val" => { - let mplace = this.deref_operand(args[0])?; + let &[mplace] = check_arg_count(args)?; + let mplace = this.deref_operand(mplace)?; let (size, _) = this .size_and_align_of_mplace(mplace)? .expect("size_of_val called on extern type"); @@ -479,17 +507,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Other "assume" => { - let cond = this.read_scalar(args[0])?.to_bool()?; + let &[cond] = check_arg_count(args)?; + let cond = this.read_scalar(cond)?.not_undef()?.to_bool()?; if !cond { throw_ub_format!("`assume` intrinsic called with `false`"); } } - "exact_div" => - this.exact_div(this.read_immediate(args[0])?, this.read_immediate(args[1])?, dest)?, + "exact_div" => { + let &[num, denom] = check_arg_count(args)?; + this.exact_div(this.read_immediate(num)?, this.read_immediate(denom)?, dest)?; + } "forget" => { // We get an argument... and forget about it. + let &[_] = check_arg_count(args)?; } #[rustfmt::skip] @@ -497,7 +529,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "unlikely" => { // These just return their argument - let b = this.read_immediate(args[0])?; + let &[b] = check_arg_count(args)?; + let b = this.read_immediate(b)?; this.write_immediate(*b, dest)?; } diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 166d1a5456df..cd525e173ed7 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -17,6 +17,7 @@ use log::trace; use rustc_middle::{mir, ty}; use crate::*; +use helpers::check_arg_count; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -32,7 +33,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // There are some more lang items we want to hook that CTFE does not hook (yet). if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { - this.align_offset(args[0], args[1], ret, unwind)?; + let &[ptr, align] = check_arg_count(args)?; + this.align_offset(ptr, align, ret, unwind)?; return Ok(None); } diff --git a/src/shims/panic.rs b/src/shims/panic.rs index c926046a0442..43f90f1b04f7 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -17,6 +17,7 @@ use rustc_middle::{mir, ty}; use rustc_target::spec::PanicStrategy; use crate::*; +use helpers::check_arg_count; /// Holds all of the relevant data for when unwinding hits a `try` frame. #[derive(Debug)] @@ -53,7 +54,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("miri_start_panic: {:?}", this.frame().instance); // Get the raw pointer stored in arg[0] (the panic payload). - let payload = this.read_scalar(args[0])?.not_undef()?; + let &[payload] = check_arg_count(args)?; + let payload = this.read_scalar(payload)?.not_undef()?; assert!( this.machine.panic_payload.is_none(), "the panic runtime should avoid double-panics" @@ -86,9 +88,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // a pointer to `Box`. // Get all the arguments. - let try_fn = this.read_scalar(args[0])?.not_undef()?; - let data = this.read_scalar(args[1])?.not_undef()?; - let catch_fn = this.read_scalar(args[2])?.not_undef()?; + let &[try_fn, data, catch_fn] = check_arg_count(args)?; + let try_fn = this.read_scalar(try_fn)?.not_undef()?; + let data = this.read_scalar(data)?.not_undef()?; + let catch_fn = this.read_scalar(catch_fn)?.not_undef()?; // Now we make a function call, and pass `data` as first and only argument. let f_instance = this.memory.get_fn(try_fn)?.as_instance()?; From 46aaab30fec9ba85ac086137109e66bf5557dd7e Mon Sep 17 00:00:00 2001 From: Chase Albert Date: Thu, 30 Apr 2020 17:30:21 -0400 Subject: [PATCH 2026/5092] Add a test for check_arg_count. --- tests/compile-fail/check_arg_count.rs | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/compile-fail/check_arg_count.rs diff --git a/tests/compile-fail/check_arg_count.rs b/tests/compile-fail/check_arg_count.rs new file mode 100644 index 000000000000..663fa60f72d7 --- /dev/null +++ b/tests/compile-fail/check_arg_count.rs @@ -0,0 +1,7 @@ +#![feature(core_intrinsics)] + +use std::intrinsics; + +fn main() { + unsafe { intrinsics::forget(); } //~ ERROR this function takes 1 argument but 0 arguments were supplied +} From 4d3dff2addc479d54e03bf41ff3fe6f6f0302fdc Mon Sep 17 00:00:00 2001 From: Chase Albert Date: Thu, 30 Apr 2020 17:30:27 -0400 Subject: [PATCH 2027/5092] Address consistency of naming for unused/merely validated arguments. --- src/shims/foreign_items/posix.rs | 18 ++++++------- src/shims/foreign_items/posix/linux.rs | 37 ++++++++++++++------------ src/shims/foreign_items/posix/macos.rs | 8 +++--- src/shims/foreign_items/windows.rs | 24 ++++++++--------- 4 files changed, 45 insertions(+), 42 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 4c50d5ddc5b8..6b28e7070165 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -56,7 +56,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "fcntl" => { - let result = this.fcntl(args); + let result = this.fcntl(args)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "read" => { @@ -168,8 +168,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamic symbol loading "dlsym" => { - let &[_handle, symbol] = check_arg_count(args)?; - let _handle = this.read_scalar(_handle)?.not_undef()?; + let &[handle, symbol] = check_arg_count(args)?; + this.read_scalar(handle)?.not_undef()?; let symbol = this.read_scalar(symbol)?.not_undef()?; let symbol_name = this.memory.read_c_str(symbol)?; let err = format!("bad c unicode symbol: {:?}", symbol_name); @@ -360,8 +360,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscellaneous "isatty" => { - let &[_fd] = check_arg_count(args)?; - let _fd = this.read_scalar(_fd)?.to_i32()?; + let &[fd] = check_arg_count(args)?; + this.read_scalar(fd)?.to_i32()?; // "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error" // FIXME: we just say nothing is a terminal. let enotty = this.eval_libc("ENOTTY")?; @@ -369,10 +369,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_atfork" => { - let &[_prepare, _parent, _child] = check_arg_count(args)?; - let _prepare = this.read_scalar(_prepare)?.not_undef()?; - let _parent = this.read_scalar(_parent)?.not_undef()?; - let _child = this.read_scalar(_child)?.not_undef()?; + let &[prepare, parent, child] = check_arg_count(args)?; + this.read_scalar(prepare)?.not_undef()?; + this.read_scalar(parent)?.not_undef()?; + this.read_scalar(child)?.not_undef()?; // We do not support forking, so there is nothing to do here. this.write_null(dest)?; } diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index b0f4a45f1c01..3f9d1b259a86 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -46,11 +46,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Linux-only "posix_fadvise" => { - let &[_fd, _offset, _len, _advice] = check_arg_count(args)?; - let _fd = this.read_scalar(_fd)?.to_i32()?; - let _offset = this.read_scalar(_offset)?.to_machine_isize(this)?; - let _len = this.read_scalar(_len)?.to_machine_isize(this)?; - let _advice = this.read_scalar(_advice)?.to_i32()?; + let &[fd, offset, len, advice] = check_arg_count(args)?; + this.read_scalar(fd)?.to_i32()?; + this.read_scalar(offset)?.to_machine_isize(this)?; + this.read_scalar(len)?.to_machine_isize(this)?; + this.read_scalar(advice)?.to_i32()?; // fadvise is only informational, we can ignore it. this.write_null(dest)?; } @@ -66,8 +66,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_attr_getstack" => { // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. - let &[_attr_place, addr_place, size_place] = check_arg_count(args)?; - let _attr_place = this.deref_operand(_attr_place)?; + let &[attr_place, addr_place, size_place] = check_arg_count(args)?; + this.deref_operand(attr_place)?; let addr_place = this.deref_operand(addr_place)?; let size_place = this.deref_operand(size_place)?; @@ -102,14 +102,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .to_machine_usize(this)?; if args.is_empty() { - throw_ub_format!("incorrect number of arguments, needed at least 1"); + throw_ub_format!("incorrect number of arguments for syscall, needed at least 1"); } match this.read_scalar(args[0])?.to_machine_usize(this)? { // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` // is called if a `HashMap` is created the regular way (e.g. HashMap). id if id == sys_getrandom => { // The first argument is the syscall id, so skip over it. - getrandom(this, &args[1..], dest)?; + let &[_, ptr, len, flags] = check_arg_count(args)?; + getrandom(this, ptr, len, flags, dest)?; } // `statx` is used by `libstd` to retrieve metadata information on `linux` // instead of using `stat`,`lstat` or `fstat` as on `macos`. @@ -125,13 +126,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscelanneous "getrandom" => { - getrandom(this, args, dest)?; + let &[ptr, len, flags] = check_arg_count(args)?; + getrandom(this, ptr, len, flags, dest)?; } "sched_getaffinity" => { - let &[_pid, _cpusetsize, _mask] = check_arg_count(args)?; - let _pid = this.read_scalar(_pid)?.to_i32()?; - let _cpusetsize = this.read_scalar(_cpusetsize)?.to_machine_usize(this)?; - let _mask = this.deref_operand(_mask)?; + let &[pid, cpusetsize, mask] = check_arg_count(args)?; + this.read_scalar(pid)?.to_i32()?; + this.read_scalar(cpusetsize)?.to_machine_usize(this)?; + this.deref_operand(mask)?; // FIXME: we just return an error; `num_cpus` then falls back to `sysconf`. let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; @@ -154,16 +156,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Shims the linux `getrandom` syscall. fn getrandom<'tcx>( this: &mut MiriEvalContext<'_, 'tcx>, - args: &[OpTy<'tcx, Tag>], + ptr: OpTy<'tcx, Tag>, + len: OpTy<'tcx, Tag>, + flags: OpTy<'tcx, Tag>, dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { - let &[ptr, len, _flags] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.not_undef()?; let len = this.read_scalar(len)?.to_machine_usize(this)?; // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, // neither of which have any effect on our current PRNG. - let _flags = this.read_scalar(_flags)?.to_i32()?; + this.read_scalar(flags)?.to_i32()?; this.gen_random(ptr, len)?; this.write_scalar(Scalar::from_machine_usize(len, this), dest)?; diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index e9fd3aa8ac81..685f66d443d4 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -104,14 +104,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_get_stackaddr_np" => { - let &[_thread] = check_arg_count(args)?; - let _thread = this.read_scalar(_thread)?.not_undef()?; + let &[thread] = check_arg_count(args)?; + this.read_scalar(thread)?.not_undef()?; let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size()); this.write_scalar(stack_addr, dest)?; } "pthread_get_stacksize_np" => { - let &[_thread] = check_arg_count(args)?; - let _thread = this.read_scalar(_thread)?.not_undef()?; + let &[thread] = check_arg_count(args)?; + this.read_scalar(thread)?.not_undef()?; let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size()); this.write_scalar(stack_size, dest)?; } diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 9edd20ddcab1..3d7afc616e8e 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -97,8 +97,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Allocation "HeapAlloc" => { - let &[_handle, flags, size] = check_arg_count(args)?; - let _handle = this.read_scalar(_handle)?.to_machine_isize(this)?; + let &[handle, flags, size] = check_arg_count(args)?; + this.read_scalar(handle)?.to_machine_isize(this)?; let flags = this.read_scalar(flags)?.to_u32()?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY @@ -106,16 +106,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } "HeapFree" => { - let &[_handle, _flags, ptr] = check_arg_count(args)?; - let _handle = this.read_scalar(_handle)?.to_machine_isize(this)?; + let &[handle, _flags, ptr] = check_arg_count(args)?; + this.read_scalar(handle)?.to_machine_isize(this)?; let _flags = this.read_scalar(_flags)?.to_u32()?; let ptr = this.read_scalar(ptr)?.not_undef()?; this.free(ptr, MiriMemoryKind::WinHeap)?; this.write_scalar(Scalar::from_i32(1), dest)?; } "HeapReAlloc" => { - let &[_handle, _flags, ptr, size] = check_arg_count(args)?; - let _handle = this.read_scalar(_handle)?.to_machine_isize(this)?; + let &[handle, _flags, ptr, size] = check_arg_count(args)?; + this.read_scalar(handle)?.to_machine_isize(this)?; let _flags = this.read_scalar(_flags)?.to_u32()?; let ptr = this.read_scalar(ptr)?.not_undef()?; let size = this.read_scalar(size)?.to_machine_usize(this)?; @@ -216,18 +216,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "GetConsoleScreenBufferInfo" => { // `term` needs this, so we fake it. - let &[_console, _buffer_info] = check_arg_count(args)?; - let _console = this.read_scalar(_console)?.to_machine_isize(this)?; - let _buffer_info = this.deref_operand(_buffer_info)?; + let &[console, buffer_info] = check_arg_count(args)?; + this.read_scalar(console)?.to_machine_isize(this)?; + this.deref_operand(buffer_info)?; // Indicate an error. // FIXME: we should set last_error, but to what? this.write_null(dest)?; } "GetConsoleMode" => { // Windows "isatty" (in libtest) needs this, so we fake it. - let &[_console, _mode] = check_arg_count(args)?; - let _console = this.read_scalar(_console)?.to_machine_isize(this)?; - let _mode = this.deref_operand(_mode)?; + let &[console, mode] = check_arg_count(args)?; + this.read_scalar(console)?.to_machine_isize(this)?; + this.deref_operand(mode)?; // Indicate an error. // FIXME: we should set last_error, but to what? this.write_null(dest)?; From f46d1974313c83886508088ff1beac3a107c3790 Mon Sep 17 00:00:00 2001 From: Chase Albert Date: Thu, 30 Apr 2020 18:16:56 -0400 Subject: [PATCH 2028/5092] Test for too many args. --- tests/compile-fail/check_arg_count.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/compile-fail/check_arg_count.rs b/tests/compile-fail/check_arg_count.rs index 663fa60f72d7..0cc6dcb9a98d 100644 --- a/tests/compile-fail/check_arg_count.rs +++ b/tests/compile-fail/check_arg_count.rs @@ -4,4 +4,5 @@ use std::intrinsics; fn main() { unsafe { intrinsics::forget(); } //~ ERROR this function takes 1 argument but 0 arguments were supplied + unsafe { intrinsics::forget(1, 2); } //~ ERROR this function takes 1 argument but 2 arguments were supplied } From 4e3d1fee51a3a326c4146cb0986820ed129fce95 Mon Sep 17 00:00:00 2001 From: Chase Albert Date: Mon, 4 May 2020 14:24:22 -0400 Subject: [PATCH 2029/5092] Address comments. --- src/helpers.rs | 2 +- src/shims/foreign_items.rs | 1 + src/shims/foreign_items/posix/linux.rs | 3 ++- src/shims/foreign_items/posix/macos.rs | 5 +++-- src/shims/foreign_items/windows.rs | 8 ++++---- src/shims/fs.rs | 25 +++++++++---------------- src/shims/thread.rs | 4 ++-- 7 files changed, 22 insertions(+), 26 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 43a20d290c80..510efe466088 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -477,7 +477,7 @@ pub fn check_arg_count<'a, 'tcx, const N: usize>(args: &'a [OpTy<'tcx, Tag>]) -> if let Ok(ops) = args.try_into() { return Ok(ops); } - throw_ub_format!("incorrect number of arguments, got {}, needed {}", args.len(), N) + throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N) } pub fn immty_from_int_checked<'tcx>( diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 643f76bfe37a..8a75fb03a53c 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -454,6 +454,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Architecture-specific shims "llvm.x86.sse2.pause" if this.tcx.sess.target.target.arch == "x86" || this.tcx.sess.target.target.arch == "x86_64" => { + let &[] = check_arg_count(args)?; this.sched_yield()?; } diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 3f9d1b259a86..e0f54cac1570 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -102,7 +102,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .to_machine_usize(this)?; if args.is_empty() { - throw_ub_format!("incorrect number of arguments for syscall, needed at least 1"); + throw_ub_format!("incorrect number of arguments for syscall: got 0, expected at least 1"); } match this.read_scalar(args[0])?.to_machine_usize(this)? { // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` @@ -143,6 +143,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "pthread_getattr_np" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + let &[_thread, _attr] = check_arg_count(args)?; this.write_null(dest)?; } diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 685f66d443d4..1cfecbc93461 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -118,8 +118,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_setname_np" => { - let ptr = this.read_scalar(args[0])?.not_undef()?; - this.pthread_setname_np(ptr)?; + let &[name] = check_arg_count(args)?; + let name = this.read_scalar(name)?.not_undef()?; + this.pthread_setname_np(name)?; } // Incomplete shims that we "stub out" just to get pre-main initialization code to work. diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 3d7afc616e8e..ab912476f6a9 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -106,17 +106,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } "HeapFree" => { - let &[handle, _flags, ptr] = check_arg_count(args)?; + let &[handle, flags, ptr] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; - let _flags = this.read_scalar(_flags)?.to_u32()?; + this.read_scalar(flags)?.to_u32()?; let ptr = this.read_scalar(ptr)?.not_undef()?; this.free(ptr, MiriMemoryKind::WinHeap)?; this.write_scalar(Scalar::from_i32(1), dest)?; } "HeapReAlloc" => { - let &[handle, _flags, ptr, size] = check_arg_count(args)?; + let &[handle, flags, ptr, size] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; - let _flags = this.read_scalar(_flags)?.to_u32()?; + this.read_scalar(flags)?.to_u32()?; let ptr = this.read_scalar(ptr)?.not_undef()?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let res = this.realloc(ptr, size, MiriMemoryKind::WinHeap)?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index b9bb0fadf1a4..ecb906f158e3 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -328,22 +328,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("fcntl")?; - let (fd, cmd, start) = if args.len() == 2 { - let &[fd, cmd] = check_arg_count(args)?; - (fd, cmd, None) - } else { - // If args.len() isn't 2 or 3 this will error appropriately. - let &[fd, cmd, start] = check_arg_count(args)?; - (fd, cmd, Some(start)) - }; - let fd = this.read_scalar(fd)?.to_i32()?; - let cmd = this.read_scalar(cmd)?.to_i32()?; + if args.len() < 2 { + throw_ub_format!("incorrect number of arguments for fcntl: got {}, expected at least 2", args.len()); + } + let cmd = this.read_scalar(args[1])?.to_i32()?; // We only support getting the flags for a descriptor. if cmd == this.eval_libc_i32("F_GETFD")? { // Currently this is the only flag that `F_GETFD` returns. It is OK to just return the // `FD_CLOEXEC` value without checking if the flag is set for the file because `std` // always sets this flag when opening a file. However we still need to check that the // file itself is open. + let &[fd, _] = check_arg_count(args)?; + let fd = this.read_scalar(fd)?.to_i32()?; if this.machine.file_handler.handles.contains_key(&fd) { Ok(this.eval_libc_i32("FD_CLOEXEC")?) } else { @@ -356,15 +352,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // because exec() isn't supported. The F_DUPFD and F_DUPFD_CLOEXEC commands only // differ in whether the FD_CLOEXEC flag is pre-set on the new file descriptor, // thus they can share the same implementation here. + let &[fd, _, start] = check_arg_count(args)?; + let fd = this.read_scalar(fd)?.to_i32()?; + let start = this.read_scalar(start)?.to_i32()?; if fd < MIN_NORMAL_FILE_FD { throw_unsup_format!("duplicating file descriptors for stdin, stdout, or stderr is not supported") } - let start = start.ok_or_else(|| { - err_unsup_format!( - "fcntl with command F_DUPFD or F_DUPFD_CLOEXEC requires a third argument" - ) - })?; - let start = this.read_scalar(start)?.to_i32()?; let fh = &mut this.machine.file_handler; let (file_result, writable) = match fh.handles.get(&fd) { Some(FileHandle { file, writable }) => (file.try_clone(), *writable), diff --git a/src/shims/thread.rs b/src/shims/thread.rs index ac1bb39a6982..3ea1ee0aa17d 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -121,12 +121,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_setname_np( &mut self, - ptr: Scalar, + name: Scalar, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.assert_target_os("macos", "pthread_setname_np"); - let name = this.memory.read_c_str(ptr)?.to_owned(); + let name = this.memory.read_c_str(name)?.to_owned(); this.set_active_thread_name(name)?; Ok(()) From f741f2cc714b90a224f0b8739c6d57107bf372cc Mon Sep 17 00:00:00 2001 From: Chase Albert Date: Mon, 4 May 2020 23:22:00 -0400 Subject: [PATCH 2030/5092] Correct the test. --- tests/compile-fail/check_arg_count.rs | 8 -------- tests/compile-fail/check_arg_count_too_few_args.rs | 12 ++++++++++++ tests/compile-fail/check_arg_count_too_many_args.rs | 12 ++++++++++++ 3 files changed, 24 insertions(+), 8 deletions(-) delete mode 100644 tests/compile-fail/check_arg_count.rs create mode 100644 tests/compile-fail/check_arg_count_too_few_args.rs create mode 100644 tests/compile-fail/check_arg_count_too_many_args.rs diff --git a/tests/compile-fail/check_arg_count.rs b/tests/compile-fail/check_arg_count.rs deleted file mode 100644 index 0cc6dcb9a98d..000000000000 --- a/tests/compile-fail/check_arg_count.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(core_intrinsics)] - -use std::intrinsics; - -fn main() { - unsafe { intrinsics::forget(); } //~ ERROR this function takes 1 argument but 0 arguments were supplied - unsafe { intrinsics::forget(1, 2); } //~ ERROR this function takes 1 argument but 2 arguments were supplied -} diff --git a/tests/compile-fail/check_arg_count_too_few_args.rs b/tests/compile-fail/check_arg_count_too_few_args.rs new file mode 100644 index 000000000000..c6c19e042dd4 --- /dev/null +++ b/tests/compile-fail/check_arg_count_too_few_args.rs @@ -0,0 +1,12 @@ +#![feature(core_intrinsics)] +#![feature(rustc_private)] + +fn main() { + extern "C" { + fn malloc() -> *mut std::ffi::c_void; + } + + unsafe { + let _ = malloc(); //~ ERROR Undefined Behavior: incorrect number of arguments: got 0, expected 1 + }; +} diff --git a/tests/compile-fail/check_arg_count_too_many_args.rs b/tests/compile-fail/check_arg_count_too_many_args.rs new file mode 100644 index 000000000000..cca03e53ec10 --- /dev/null +++ b/tests/compile-fail/check_arg_count_too_many_args.rs @@ -0,0 +1,12 @@ +#![feature(core_intrinsics)] +#![feature(rustc_private)] + +fn main() { + extern "C" { + fn malloc(_: i32, _: i32) -> *mut std::ffi::c_void; + } + + unsafe { + let _ = malloc(1, 2); //~ ERROR Undefined Behavior: incorrect number of arguments: got 2, expected 1 + }; +} From 5566e3901c5dffe55cf093e05d8a9bf097958122 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 May 2020 11:44:33 +0200 Subject: [PATCH 2031/5092] deduplicate FD extraction --- src/shims/fs.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index ecb906f158e3..ba4611373c8a 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -331,6 +331,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if args.len() < 2 { throw_ub_format!("incorrect number of arguments for fcntl: got {}, expected at least 2", args.len()); } + let fd = this.read_scalar(args[0])?.to_i32()?; let cmd = this.read_scalar(args[1])?.to_i32()?; // We only support getting the flags for a descriptor. if cmd == this.eval_libc_i32("F_GETFD")? { @@ -338,8 +339,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `FD_CLOEXEC` value without checking if the flag is set for the file because `std` // always sets this flag when opening a file. However we still need to check that the // file itself is open. - let &[fd, _] = check_arg_count(args)?; - let fd = this.read_scalar(fd)?.to_i32()?; + let &[_, _] = check_arg_count(args)?; if this.machine.file_handler.handles.contains_key(&fd) { Ok(this.eval_libc_i32("FD_CLOEXEC")?) } else { @@ -352,8 +352,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // because exec() isn't supported. The F_DUPFD and F_DUPFD_CLOEXEC commands only // differ in whether the FD_CLOEXEC flag is pre-set on the new file descriptor, // thus they can share the same implementation here. - let &[fd, _, start] = check_arg_count(args)?; - let fd = this.read_scalar(fd)?.to_i32()?; + let &[_, _, start] = check_arg_count(args)?; let start = this.read_scalar(start)?.to_i32()?; if fd < MIN_NORMAL_FILE_FD { throw_unsup_format!("duplicating file descriptors for stdin, stdout, or stderr is not supported") From cd6be9885217d409dc23572714a7b499784e921f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 May 2020 11:57:08 +0200 Subject: [PATCH 2032/5092] make sure we check argument count everywhere --- src/shims/foreign_items/posix.rs | 43 +++++++++++++++++++----------- src/shims/foreign_items/windows.rs | 17 +++++------- src/shims/intrinsics.rs | 1 + 3 files changed, 35 insertions(+), 26 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 6b28e7070165..a68414ddbc2f 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -379,19 +379,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. - | "pthread_attr_init" - | "pthread_attr_destroy" - | "pthread_attr_setstacksize" - | "pthread_condattr_init" - | "pthread_condattr_setclock" - | "pthread_cond_init" - | "pthread_condattr_destroy" - | "pthread_cond_destroy" if this.frame().instance.to_string().starts_with("std::sys::unix::") - => { - this.write_null(dest)?; - } - "pthread_attr_getguardsize" if this.frame().instance.to_string().starts_with("std::sys::unix::") - => { + "pthread_attr_getguardsize" + if this.frame().instance.to_string().starts_with("std::sys::unix::") => { let &[_attr, guard_size] = check_arg_count(args)?; let guard_size = this.deref_operand(guard_size)?; let guard_size_layout = this.libc_ty_layout("size_t")?; @@ -401,11 +390,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } + | "pthread_attr_init" + | "pthread_attr_destroy" + | "pthread_condattr_init" + | "pthread_condattr_destroy" + | "pthread_cond_destroy" + if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + let &[_] = check_arg_count(args)?; + this.write_null(dest)?; + } + | "pthread_cond_init" + | "pthread_attr_setstacksize" + | "pthread_condattr_setclock" + if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + let &[_, _] = check_arg_count(args)?; + this.write_null(dest)?; + } + | "signal" - | "sigaction" | "sigaltstack" - | "mprotect" if this.frame().instance.to_string().starts_with("std::sys::unix::") - => { + if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + let &[_, _] = check_arg_count(args)?; + this.write_null(dest)?; + } + | "sigaction" + | "mprotect" + if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + let &[_, _, _] = check_arg_count(args)?; this.write_null(dest)?; } diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index ab912476f6a9..cff1887ff8b5 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -251,22 +251,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Just fake a HANDLE this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } - "GetModuleHandleW" if this.frame().instance.to_string().starts_with("std::sys::windows::") - => { + "GetModuleHandleW" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] let &[_lpModuleName] = check_arg_count(args)?; // Pretend this does not exist / nothing happened, by returning zero. this.write_null(dest)?; } - "GetProcAddress" if this.frame().instance.to_string().starts_with("std::sys::windows::") - => { + "GetProcAddress" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] let &[_hModule, _lpProcName] = check_arg_count(args)?; // Pretend this does not exist / nothing happened, by returning zero. this.write_null(dest)?; } - "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") - => { + "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] let &[_hConsoleOutput, _wAttribute] = check_arg_count(args)?; // Pretend these does not exist / nothing happened, by returning zero. @@ -281,8 +278,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "InitializeCriticalSection" | "EnterCriticalSection" | "LeaveCriticalSection" - | "DeleteCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") - => { + | "DeleteCriticalSection" + if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] let &[_lpCriticalSection] = check_arg_count(args)?; assert_eq!(this.get_total_thread_count()?, 1, "concurrency on Windows not supported"); @@ -290,8 +287,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // (Windows locks are reentrant, and we have only 1 thread, // so not doing any futher checks here is at least not incorrect.) } - "TryEnterCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") - => { + "TryEnterCriticalSection" + if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] let &[_lpCriticalSection] = check_arg_count(args)?; assert_eq!(this.get_total_thread_count()?, 1, "concurrency on Windows not supported"); diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index a77443ef5224..cf485b547746 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -363,6 +363,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "atomic_singlethreadfence_acqrel" | "atomic_singlethreadfence" => { + let &[] = check_arg_count(args)?; // we are inherently singlethreaded and singlecored, this is a nop } From 5656cb73d45c6403c3e3ba2be0283b1779365ecb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 May 2020 11:57:39 +0200 Subject: [PATCH 2033/5092] fix a comment now that we have concurrency --- src/shims/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index cf485b547746..08087b0350d9 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -364,7 +364,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "atomic_singlethreadfence" => { let &[] = check_arg_count(args)?; - // we are inherently singlethreaded and singlecored, this is a nop + // FIXME: this will become relevant once we try to detect data races. } _ if intrinsic_name.starts_with("atomic_xchg") => { From 40800cfa197100f45419586fbdc622d17ea47b7f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 May 2020 12:19:54 +0200 Subject: [PATCH 2034/5092] make sure we check the size of all arguments --- src/shims/foreign_items/posix.rs | 7 ++++--- src/shims/foreign_items/windows.rs | 3 ++- src/shims/fs.rs | 14 ++++++++++++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index a68414ddbc2f..951a40293b72 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -34,7 +34,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "setenv" => { - let &[name, value, _overwrite] = check_arg_count(args)?; + let &[name, value, overwrite] = check_arg_count(args)?; + this.read_scalar(overwrite)?.to_i32()?; let result = this.setenv(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -51,8 +52,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "open" | "open64" => { - let &[path, flag, _mode] = check_arg_count(args)?; - let result = this.open(path, flag)?; + let &[path, flag, mode] = check_arg_count(args)?; + let result = this.open(path, flag, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fcntl" => { diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index cff1887ff8b5..7f3cd03cd2d3 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -63,7 +63,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?; } "WriteFile" => { - let &[handle, buf, n, written_ptr, _overlapped] = check_arg_count(args)?; + let &[handle, buf, n, written_ptr, overlapped] = check_arg_count(args)?; + this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore let handle = this.read_scalar(handle)?.to_machine_isize(this)?; let buf = this.read_scalar(buf)?.not_undef()?; let n = this.read_scalar(n)?.to_u32()?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index ba4611373c8a..58abf748dd5a 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -238,6 +238,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, path_op: OpTy<'tcx, Tag>, flag_op: OpTy<'tcx, Tag>, + mode_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -245,6 +246,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let flag = this.read_scalar(flag_op)?.to_i32()?; + // Check mode (size depends on platform). + // FIXME: should we do something with the mode? + match this.tcx.sess.target.target.target_os.as_str() { + "macos" => { + // FIXME: I think `mode` should be `u16` on macOS, but see + // . + // For now, just don't check on macos. + } + _ => { + this.read_scalar(mode_op)?.to_u32()?; + } + }; + let mut options = OpenOptions::new(); let o_rdonly = this.eval_libc_i32("O_RDONLY")?; From 45ef97535ff64b22cf281c087c6bf1f603208985 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 May 2020 16:49:01 +0200 Subject: [PATCH 2035/5092] fs shim: check that mode is default --- src/shims/fs.rs | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 58abf748dd5a..0de0b33fb2e2 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -246,18 +246,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let flag = this.read_scalar(flag_op)?.to_i32()?; - // Check mode (size depends on platform). - // FIXME: should we do something with the mode? - match this.tcx.sess.target.target.target_os.as_str() { - "macos" => { - // FIXME: I think `mode` should be `u16` on macOS, but see - // . - // For now, just don't check on macos. - } - _ => { - this.read_scalar(mode_op)?.to_u32()?; - } - }; + // Get the mode. On macOS, the argument type `mode_t` is actually `u16`, but + // C integer promotion rules mean that on the ABI level, it gets passed as `u32` + // (see https://github.com/rust-lang/rust/issues/71915). + let mode = this.read_scalar(mode_op)?.to_u32()?; + if mode != 0o666 { + throw_unsup_format!("non-default mode 0o{:o} is not supported", mode); + } let mut options = OpenOptions::new(); From da6846c8a953c065ec868d91d4e40d0b4dda4659 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 May 2020 22:46:42 +0200 Subject: [PATCH 2036/5092] copy some float cast tests from rustc --- tests/run-pass/float.rs | 113 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 112 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index fc513ead8dd8..3347b0a07c26 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -1,4 +1,4 @@ -#![feature(track_caller)] +#![feature(track_caller, stmt_expr_attributes)] use std::fmt::Debug; // Helper function to avoid promotion so that this tests "run-time" casts, not CTFE. @@ -78,6 +78,7 @@ fn test_both_cast(x: F, y: I) fn main() { basic(); casts(); + more_casts(); ops(); } @@ -334,3 +335,113 @@ fn ops() { assert_eq((-3.5_f64).copysign(-0.42), -3.5_f64); assert!(f64::NAN.copysign(1.0).is_nan()); } + +/// Tests taken from rustc test suite. +/// + +// Poor-man's black-box +#[inline(never)] +fn black_box(x: T) -> T { x } + +macro_rules! test { + ($val:expr, $src_ty:ident -> $dest_ty:ident, $expected:expr) => ( + // black_box disables constant evaluation to test run-time conversions: + assert_eq!(black_box::<$src_ty>($val) as $dest_ty, $expected, + "run-time {} -> {}", stringify!($src_ty), stringify!($dest_ty)); + + { + const X: $src_ty = $val; + const Y: $dest_ty = X as $dest_ty; + assert_eq!(Y, $expected, + "const eval {} -> {}", stringify!($src_ty), stringify!($dest_ty)); + } + ); + + ($fval:expr, f* -> $ity:ident, $ival:expr) => ( + test!($fval, f32 -> $ity, $ival); + test!($fval, f64 -> $ity, $ival); + ) +} + +macro_rules! common_fptoi_tests { + ($fty:ident -> $($ity:ident)+) => ({ $( + test!($fty::NAN, $fty -> $ity, 0); + test!($fty::INFINITY, $fty -> $ity, $ity::MAX); + test!($fty::NEG_INFINITY, $fty -> $ity, $ity::MIN); + // These two tests are not solely float->int tests, in particular the latter relies on + // `u128::MAX as f32` not being UB. But that's okay, since this file tests int->float + // as well, the test is just slightly misplaced. + test!($ity::MIN as $fty, $fty -> $ity, $ity::MIN); + test!($ity::MAX as $fty, $fty -> $ity, $ity::MAX); + test!(0., $fty -> $ity, 0); + test!($fty::MIN_POSITIVE, $fty -> $ity, 0); + test!(-0.9, $fty -> $ity, 0); + test!(1., $fty -> $ity, 1); + test!(42., $fty -> $ity, 42); + )+ }); + + (f* -> $($ity:ident)+) => ({ + common_fptoi_tests!(f32 -> $($ity)+); + common_fptoi_tests!(f64 -> $($ity)+); + }) +} + +macro_rules! fptoui_tests { + ($fty: ident -> $($ity: ident)+) => ({ $( + test!(-0., $fty -> $ity, 0); + test!(-$fty::MIN_POSITIVE, $fty -> $ity, 0); + test!(-0.99999994, $fty -> $ity, 0); + test!(-1., $fty -> $ity, 0); + test!(-100., $fty -> $ity, 0); + test!(#[allow(overflowing_literals)] -1e50, $fty -> $ity, 0); + test!(#[allow(overflowing_literals)] -1e130, $fty -> $ity, 0); + )+ }); + + (f* -> $($ity:ident)+) => ({ + fptoui_tests!(f32 -> $($ity)+); + fptoui_tests!(f64 -> $($ity)+); + }) +} + +fn more_casts() { + common_fptoi_tests!(f* -> i8 i16 i32 i64 u8 u16 u32 u64); + fptoui_tests!(f* -> u8 u16 u32 u64); + common_fptoi_tests!(f* -> i128 u128); + fptoui_tests!(f* -> u128); + + // The following tests cover edge cases for some integer types. + + // # u8 + test!(254., f* -> u8, 254); + test!(256., f* -> u8, 255); + + // # i8 + test!(-127., f* -> i8, -127); + test!(-129., f* -> i8, -128); + test!(126., f* -> i8, 126); + test!(128., f* -> i8, 127); + + // # i32 + // -2147483648. is i32::MIN (exactly) + test!(-2147483648., f* -> i32, i32::MIN); + // 2147483648. is i32::MAX rounded up + test!(2147483648., f32 -> i32, 2147483647); + // With 24 significand bits, floats with magnitude in [2^30 + 1, 2^31] are rounded to + // multiples of 2^7. Therefore, nextDown(round(i32::MAX)) is 2^31 - 128: + test!(2147483520., f32 -> i32, 2147483520); + // Similarly, nextUp(i32::MIN) is i32::MIN + 2^8 and nextDown(i32::MIN) is i32::MIN - 2^7 + test!(-2147483904., f* -> i32, i32::MIN); + test!(-2147483520., f* -> i32, -2147483520); + + // # u32 + // round(MAX) and nextUp(round(MAX)) + test!(4294967040., f* -> u32, 4294967040); + test!(4294967296., f* -> u32, 4294967295); + + // # u128 + // float->int: + test!(f32::MAX, f32 -> u128, 0xffffff00000000000000000000000000); + // nextDown(f32::MAX) = 2^128 - 2 * 2^104 + const SECOND_LARGEST_F32: f32 = 340282326356119256160033759537265639424.; + test!(SECOND_LARGEST_F32, f32 -> u128, 0xfffffe00000000000000000000000000); +} From 356848c9b9a3bd8226bbabd08611b1e519acc9c7 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 7 May 2020 02:42:12 +0000 Subject: [PATCH 2037/5092] Add two more TiKV bugs to trophy case --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5a520385fd17..bfabc12659ac 100644 --- a/README.md +++ b/README.md @@ -273,6 +273,7 @@ Definite bugs found: * [`EbrCell` using uninitialized memory incorrectly](https://github.com/Firstyear/concread/commit/b15be53b6ec076acb295a5c0483cdb4bf9be838f#diff-6282b2fc8e98bd089a1f0c86f648157cR229) * [TiKV performing an unaligned pointer access](https://github.com/tikv/tikv/issues/7613) * [`servo_arc` creating a dangling shared reference](https://github.com/servo/servo/issues/26357) +* [TiKV constructing out-of-bounds pointers and overlapping mutable references](https://github.com/tikv/tikv/pull/7751) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From fb3a067ac6af5ed2d0f393a4dce0c92d437f1fc1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 May 2020 08:38:52 +0200 Subject: [PATCH 2038/5092] rustup; fix error messages --- rust-version | 2 +- tests/compile-fail/issue-miri-1112.rs | 2 +- tests/compile-fail/validity/dangling_ref1.rs | 2 +- tests/compile-fail/validity/invalid_wide_raw.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index be7b603f9054..33dc39f86913 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -ff4df04799c406c8149a041c3163321758aac924 +97f3eeec8216d7155c24674b9be55e7c672bcae3 diff --git a/tests/compile-fail/issue-miri-1112.rs b/tests/compile-fail/issue-miri-1112.rs index 29cc5c781200..a00bed190e60 100644 --- a/tests/compile-fail/issue-miri-1112.rs +++ b/tests/compile-fail/issue-miri-1112.rs @@ -32,7 +32,7 @@ impl FunnyPointer { data: data as *const _ as *const (), vtable: ptr as *const _ as *const (), }; - let obj = std::mem::transmute::(obj); //~ ERROR invalid drop fn in vtable + let obj = std::mem::transmute::(obj); //~ ERROR invalid drop function pointer in vtable &*obj } } diff --git a/tests/compile-fail/validity/dangling_ref1.rs b/tests/compile-fail/validity/dangling_ref1.rs index a83c6af21acf..5097135f02d3 100644 --- a/tests/compile-fail/validity/dangling_ref1.rs +++ b/tests/compile-fail/validity/dangling_ref1.rs @@ -3,5 +3,5 @@ use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR reference to unallocated address 16 + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 16 is unallocated) } diff --git a/tests/compile-fail/validity/invalid_wide_raw.rs b/tests/compile-fail/validity/invalid_wide_raw.rs index 8f1e184ed22e..c23267213222 100644 --- a/tests/compile-fail/validity/invalid_wide_raw.rs +++ b/tests/compile-fail/validity/invalid_wide_raw.rs @@ -6,5 +6,5 @@ fn main() { struct S { x: * mut dyn T } - dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); //~ ERROR: encountered dangling or unaligned vtable pointer + dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); //~ ERROR: encountered dangling vtable pointer } From 132feb88db9bf49efdbbe27d09ed68f1c6b6eb67 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 May 2020 11:21:31 +0200 Subject: [PATCH 2039/5092] adjust wording --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bfabc12659ac..35d15d59ee4d 100644 --- a/README.md +++ b/README.md @@ -273,7 +273,7 @@ Definite bugs found: * [`EbrCell` using uninitialized memory incorrectly](https://github.com/Firstyear/concread/commit/b15be53b6ec076acb295a5c0483cdb4bf9be838f#diff-6282b2fc8e98bd089a1f0c86f648157cR229) * [TiKV performing an unaligned pointer access](https://github.com/tikv/tikv/issues/7613) * [`servo_arc` creating a dangling shared reference](https://github.com/servo/servo/issues/26357) -* [TiKV constructing out-of-bounds pointers and overlapping mutable references](https://github.com/tikv/tikv/pull/7751) +* [TiKV constructing out-of-bounds pointers (and overlapping mutable references)](https://github.com/tikv/tikv/pull/7751) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From b4ad90669b7e51e50d87f893b6bcbe39410b9db0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 May 2020 23:59:26 +0200 Subject: [PATCH 2040/5092] rustup --- rust-version | 2 +- tests/compile-fail/validity/dangling_ref1.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 33dc39f86913..050d500e53f9 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -97f3eeec8216d7155c24674b9be55e7c672bcae3 +a08c47310c7d49cbdc5d7afb38408ba519967ecd diff --git a/tests/compile-fail/validity/dangling_ref1.rs b/tests/compile-fail/validity/dangling_ref1.rs index 5097135f02d3..78425cde4a8a 100644 --- a/tests/compile-fail/validity/dangling_ref1.rs +++ b/tests/compile-fail/validity/dangling_ref1.rs @@ -3,5 +3,5 @@ use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 16 is unallocated) + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) } From 914e483c89c9b1619001e2c9dcc75a53968da3e7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 May 2020 09:55:28 +0200 Subject: [PATCH 2041/5092] fix cargo-miri intercepting --help/--version arguments --- src/bin/cargo-miri.rs | 50 +++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 1d93654e33e9..4392cb93ddb4 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -401,31 +401,6 @@ path = "lib.rs" } } -fn main() { - // Check for version and help flags even when invoked as `cargo-miri`. - if std::env::args().any(|a| a == "--help" || a == "-h") { - show_help(); - return; - } - if std::env::args().any(|a| a == "--version" || a == "-V") { - show_version(); - return; - } - - if let Some("miri") = std::env::args().nth(1).as_deref() { - // This arm is for when `cargo miri` is called. We call `cargo check` for each applicable target, - // but with the `RUSTC` env var set to the `cargo-miri` binary so that we come back in the other branch, - // and dispatch the invocations to `rustc` and `miri`, respectively. - in_cargo_miri(); - } else if let Some("rustc") = std::env::args().nth(1).as_deref() { - // This arm is executed when `cargo-miri` runs `cargo check` with the `RUSTC_WRAPPER` env var set to itself: - // dependencies get dispatched to `rustc`, the final test/binary to `miri`. - inside_cargo_rustc(); - } else { - show_error(format!("must be called with either `miri` or `rustc` as first argument.")) - } -} - fn in_cargo_miri() { let (subcommand, skip) = match std::env::args().nth(2).as_deref() { Some("test") => (MiriCommand::Test, 3), @@ -593,3 +568,28 @@ fn inside_cargo_rustc() { Err(e) => panic!("error running {:?}:\n{:?}", command, e), } } + +fn main() { + // Check for version and help flags even when invoked as `cargo-miri`. + if has_arg_flag("--help") || has_arg_flag("-h") { + show_help(); + return; + } + if has_arg_flag("--version") || has_arg_flag("-V") { + show_version(); + return; + } + + if let Some("miri") = std::env::args().nth(1).as_deref() { + // This arm is for when `cargo miri` is called. We call `cargo check` for each applicable target, + // but with the `RUSTC` env var set to the `cargo-miri` binary so that we come back in the other branch, + // and dispatch the invocations to `rustc` and `miri`, respectively. + in_cargo_miri(); + } else if let Some("rustc") = std::env::args().nth(1).as_deref() { + // This arm is executed when `cargo-miri` runs `cargo check` with the `RUSTC_WRAPPER` env var set to itself: + // dependencies get dispatched to `rustc`, the final test/binary to `miri`. + inside_cargo_rustc(); + } else { + show_error(format!("must be called with either `miri` or `rustc` as first argument.")) + } +} From 379ac82a1c1d7530070e6676f03c8ca5eb9f7894 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 May 2020 10:15:09 +0200 Subject: [PATCH 2042/5092] bump Rust, fix for renames --- rust-version | 2 +- src/diagnostics.rs | 2 +- src/helpers.rs | 2 +- src/shims/sync.rs | 56 +++++++++++++++++++++++----------------------- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/rust-version b/rust-version index 050d500e53f9..d53d4d68e486 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a08c47310c7d49cbdc5d7afb38408ba519967ecd +0f9088f9610618e724cfc0cf2ba3721918be5ec9 diff --git a/src/diagnostics.rs b/src/diagnostics.rs index e5e7f0c90475..8296f71773c2 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -118,7 +118,7 @@ pub fn report_error<'tcx, 'mir>( report_msg(ecx, &format!("{}: {}", title, msg), msg, helps, true); // Extra output to help debug specific issues. - if let UndefinedBehavior(UndefinedBehaviorInfo::InvalidUndefBytes(Some(ptr))) = e.kind { + if let UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some(ptr))) = e.kind { eprintln!( "Uninitialized read occurred at offset 0x{:x} into this allocation:", ptr.offset.bytes(), diff --git a/src/helpers.rs b/src/helpers.rs index 510efe466088..8b20ee2f0d83 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -54,7 +54,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn eval_path_scalar( &mut self, path: &[&str], - ) -> InterpResult<'tcx, ScalarMaybeUndef> { + ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_mut(); let instance = this.resolve_path(path); let cid = GlobalId { instance, promoted: None }; diff --git a/src/shims/sync.rs b/src/shims/sync.rs index bc64b1e97a50..c205c5c8dddb 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -25,7 +25,7 @@ fn get_at_offset<'mir, 'tcx: 'mir>( offset: u64, layout: TyAndLayout<'tcx>, min_size: u64, -) -> InterpResult<'tcx, ScalarMaybeUndef> { +) -> InterpResult<'tcx, ScalarMaybeUninit> { // Ensure that the following read at an offset to the attr pointer is within bounds assert_ptr_target_min_size(ecx, op, min_size)?; let op_place = ecx.deref_operand(op)?; @@ -37,7 +37,7 @@ fn set_at_offset<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, op: OpTy<'tcx, Tag>, offset: u64, - value: impl Into>, + value: impl Into>, layout: TyAndLayout<'tcx>, min_size: u64, ) -> InterpResult<'tcx, ()> { @@ -59,14 +59,14 @@ const PTHREAD_MUTEXATTR_T_MIN_SIZE: u64 = 4; fn mutexattr_get_kind<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, attr_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { +) -> InterpResult<'tcx, ScalarMaybeUninit> { get_at_offset(ecx, attr_op, 0, ecx.machine.layouts.i32, PTHREAD_MUTEXATTR_T_MIN_SIZE) } fn mutexattr_set_kind<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, attr_op: OpTy<'tcx, Tag>, - kind: impl Into>, + kind: impl Into>, ) -> InterpResult<'tcx, ()> { set_at_offset(ecx, attr_op, 0, kind, ecx.machine.layouts.i32, PTHREAD_MUTEXATTR_T_MIN_SIZE) } @@ -88,14 +88,14 @@ const PTHREAD_MUTEX_T_MIN_SIZE: u64 = 24; fn mutex_get_locked_count<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { +) -> InterpResult<'tcx, ScalarMaybeUninit> { get_at_offset(ecx, mutex_op, 4, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } fn mutex_set_locked_count<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, - locked_count: impl Into>, + locked_count: impl Into>, ) -> InterpResult<'tcx, ()> { set_at_offset(ecx, mutex_op, 4, locked_count, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } @@ -103,14 +103,14 @@ fn mutex_set_locked_count<'mir, 'tcx: 'mir>( fn mutex_get_owner<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { +) -> InterpResult<'tcx, ScalarMaybeUninit> { get_at_offset(ecx, mutex_op, 8, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } fn mutex_set_owner<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, - owner: impl Into>, + owner: impl Into>, ) -> InterpResult<'tcx, ()> { set_at_offset(ecx, mutex_op, 8, owner, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } @@ -118,7 +118,7 @@ fn mutex_set_owner<'mir, 'tcx: 'mir>( fn mutex_get_kind<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { +) -> InterpResult<'tcx, ScalarMaybeUninit> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; get_at_offset(ecx, mutex_op, offset, ecx.machine.layouts.i32, PTHREAD_MUTEX_T_MIN_SIZE) } @@ -126,7 +126,7 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>( fn mutex_set_kind<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, - kind: impl Into>, + kind: impl Into>, ) -> InterpResult<'tcx, ()> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; set_at_offset(ecx, mutex_op, offset, kind, ecx.machine.layouts.i32, PTHREAD_MUTEX_T_MIN_SIZE) @@ -135,14 +135,14 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( fn mutex_get_blockset<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { +) -> InterpResult<'tcx, ScalarMaybeUninit> { get_at_offset(ecx, mutex_op, 20, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } fn mutex_set_blockset<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, - blockset: impl Into>, + blockset: impl Into>, ) -> InterpResult<'tcx, ()> { set_at_offset(ecx, mutex_op, 20, blockset, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } @@ -180,14 +180,14 @@ const PTHREAD_RWLOCK_T_MIN_SIZE: u64 = 20; fn rwlock_get_readers<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { +) -> InterpResult<'tcx, ScalarMaybeUninit> { get_at_offset(ecx, rwlock_op, 4, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } fn rwlock_set_readers<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, - readers: impl Into>, + readers: impl Into>, ) -> InterpResult<'tcx, ()> { set_at_offset(ecx, rwlock_op, 4, readers, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } @@ -195,14 +195,14 @@ fn rwlock_set_readers<'mir, 'tcx: 'mir>( fn rwlock_get_writers<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { +) -> InterpResult<'tcx, ScalarMaybeUninit> { get_at_offset(ecx, rwlock_op, 8, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } fn rwlock_set_writers<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, - writers: impl Into>, + writers: impl Into>, ) -> InterpResult<'tcx, ()> { set_at_offset(ecx, rwlock_op, 8, writers, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } @@ -210,14 +210,14 @@ fn rwlock_set_writers<'mir, 'tcx: 'mir>( fn rwlock_get_writer_blockset<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { +) -> InterpResult<'tcx, ScalarMaybeUninit> { get_at_offset(ecx, rwlock_op, 12, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } fn rwlock_set_writer_blockset<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, - blockset: impl Into>, + blockset: impl Into>, ) -> InterpResult<'tcx, ()> { set_at_offset(ecx, rwlock_op, 12, blockset, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } @@ -241,14 +241,14 @@ fn rwlock_get_or_create_writer_blockset<'mir, 'tcx: 'mir>( fn rwlock_get_reader_blockset<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { +) -> InterpResult<'tcx, ScalarMaybeUninit> { get_at_offset(ecx, rwlock_op, 16, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } fn rwlock_set_reader_blockset<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, - blockset: impl Into>, + blockset: impl Into>, ) -> InterpResult<'tcx, ()> { set_at_offset(ecx, rwlock_op, 16, blockset, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } @@ -304,7 +304,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutexattr_destroy(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - mutexattr_set_kind(this, attr_op, ScalarMaybeUndef::Undef)?; + mutexattr_set_kind(this, attr_op, ScalarMaybeUninit::Uninit)?; Ok(0) } @@ -458,9 +458,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_ub_format!("destroyed a locked mutex"); } - mutex_set_kind(this, mutex_op, ScalarMaybeUndef::Undef)?; - mutex_set_locked_count(this, mutex_op, ScalarMaybeUndef::Undef)?; - mutex_set_blockset(this, mutex_op, ScalarMaybeUndef::Undef)?; + mutex_set_kind(this, mutex_op, ScalarMaybeUninit::Uninit)?; + mutex_set_locked_count(this, mutex_op, ScalarMaybeUninit::Uninit)?; + mutex_set_blockset(this, mutex_op, ScalarMaybeUninit::Uninit)?; Ok(0) } @@ -579,10 +579,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_ub_format!("destroyed a locked rwlock"); } - rwlock_set_readers(this, rwlock_op, ScalarMaybeUndef::Undef)?; - rwlock_set_writers(this, rwlock_op, ScalarMaybeUndef::Undef)?; - rwlock_set_reader_blockset(this, rwlock_op, ScalarMaybeUndef::Undef)?; - rwlock_set_writer_blockset(this, rwlock_op, ScalarMaybeUndef::Undef)?; + rwlock_set_readers(this, rwlock_op, ScalarMaybeUninit::Uninit)?; + rwlock_set_writers(this, rwlock_op, ScalarMaybeUninit::Uninit)?; + rwlock_set_reader_blockset(this, rwlock_op, ScalarMaybeUninit::Uninit)?; + rwlock_set_writer_blockset(this, rwlock_op, ScalarMaybeUninit::Uninit)?; Ok(0) } From 70f83a342c43da584a029d60f79547b175f28947 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 May 2020 11:45:43 +0200 Subject: [PATCH 2043/5092] re-do cargo-miri host/target detection logic to match rustbuild --- src/bin/cargo-miri.rs | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 4392cb93ddb4..0d73c7cf853a 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -462,6 +462,14 @@ fn in_cargo_miri() { } cmd.arg(arg); } + // We want to always run `cargo` with `--target`. This later helps us detect + // which crates are proc-macro/build-script (host crates) and which crates are + // needed for the program itself. + if get_arg_flag_value("--target").is_none() { + // When no `--target` is given, default to the host. + cmd.arg("--target"); + cmd.arg(rustc_version::version_meta().unwrap().host); + } // Serialize the remaining args into a special environemt variable. // This will be read by `inside_cargo_rustc` when we go to invoke @@ -491,24 +499,21 @@ fn in_cargo_miri() { } fn inside_cargo_rustc() { - /// Determines if we are being invoked (as rustc) to build a runnable - /// executable. We run "cargo check", so this should only happen when - /// we are trying to compile a build script or build script dependency, - /// which actually needs to be executed on the host platform. + /// Determines if we are being invoked (as rustc) to build a crate for + /// the "target" architecture, in contrast to the "host" architecture. + /// Host crates are for build scripts and proc macros and still need to + /// be built like normal; target crates need to be built for or interpreted + /// by Miri. /// - /// Currently, we detect this by checking for "--emit=link", - /// which indicates that Cargo instruced rustc to output - /// a native object. + /// Currently, we detect this by checking for "--target=", which flag is + /// never set for host crates. This matches what rustc bootstrap does, + /// which hopefully makes it "reliable enough". fn is_target_crate() -> bool { - // `--emit` is sometimes missing, e.g. cargo calls rustc for "--print". - // That is definitely not a target crate. - // If `--emit` is present, then host crates are built ("--emit=link,...), - // while the rest is only checked. - get_arg_flag_value("--emit").map_or(false, |emit| !emit.contains("link")) + get_arg_flag_value("--target").is_some() } /// Returns whether or not Cargo invoked the wrapper (this binary) to compile - /// the final, target crate (either a test for 'cargo test', or a binary for 'cargo run') + /// the final, binary crate (either a test for 'cargo test', or a binary for 'cargo run') /// Cargo does not give us this information directly, so we need to check /// various command-line flags. fn is_runnable_crate() -> bool { From e73fc97f0b9b7db87e977c3051699d959c603a6e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 May 2020 11:52:26 +0200 Subject: [PATCH 2044/5092] cargo-miri: honor RUSTC env var --- src/bin/cargo-miri.rs | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 0d73c7cf853a..44106955e0f4 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -6,6 +6,7 @@ use std::io::{self, BufRead, Write}; use std::ops::Not; use std::path::{Path, PathBuf}; use std::process::Command; +use std::ffi::OsString; const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 20); @@ -85,29 +86,23 @@ fn get_arg_flag_value(name: &str) -> Option { } } -/// Returns the path to the `miri` binary -fn find_miri() -> PathBuf { +/// Returns a command for the right `miri` binary. +fn miri() -> Command { let mut path = std::env::current_exe().expect("current executable path invalid"); path.set_file_name("miri"); - path + Command::new(path) } fn cargo() -> Command { - if let Ok(val) = std::env::var("CARGO") { - // Bootstrap tells us where to find cargo - Command::new(val) - } else { - Command::new("cargo") - } + Command::new(env::var_os("CARGO").unwrap_or_else(|| OsString::from("cargo"))) } fn xargo_check() -> Command { - if let Ok(val) = std::env::var("XARGO_CHECK") { - // Bootstrap tells us where to find xargo - Command::new(val) - } else { - Command::new("xargo-check") - } + Command::new(env::var_os("XARGO_CHECK").unwrap_or_else(|| OsString::from("xargo-check"))) +} + +fn rustc() -> Command { + Command::new(env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"))) } fn list_targets() -> impl Iterator { @@ -188,8 +183,8 @@ fn test_sysroot_consistency() { return; } - let rustc_sysroot = get_sysroot(Command::new("rustc")); - let miri_sysroot = get_sysroot(Command::new(find_miri())); + let rustc_sysroot = get_sysroot(rustc()); + let miri_sysroot = get_sysroot(miri()); if rustc_sysroot != miri_sysroot { show_error(format!( @@ -301,7 +296,7 @@ fn setup(subcommand: MiriCommand) { Ok(val) => PathBuf::from(val), Err(_) => { // Check for `rust-src` rustup component. - let sysroot = Command::new("rustc") + let sysroot = rustc() .args(&["--print", "sysroot"]) .output() .expect("failed to get rustc sysroot") @@ -554,9 +549,9 @@ fn inside_cargo_rustc() { serde_json::from_str(&magic).expect("failed to deserialize MIRI_ARGS"); args.append(&mut user_args); // Run this in Miri. - Command::new(find_miri()) + miri() } else { - Command::new("rustc") + rustc() }; // Run it. From 1ba42b9f55b11a13a507534e9b832b4d754d6435 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 May 2020 11:53:24 +0200 Subject: [PATCH 2045/5092] Wording Co-authored-by: Oliver Scherer --- src/bin/cargo-miri.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 44106955e0f4..8b238a7f7972 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -500,7 +500,7 @@ fn inside_cargo_rustc() { /// be built like normal; target crates need to be built for or interpreted /// by Miri. /// - /// Currently, we detect this by checking for "--target=", which flag is + /// Currently, we detect this by checking for "--target=", which is /// never set for host crates. This matches what rustc bootstrap does, /// which hopefully makes it "reliable enough". fn is_target_crate() -> bool { From 20097be2feaaa92c3a2843fb1c57c6a28d3dcf29 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 May 2020 11:54:35 +0200 Subject: [PATCH 2046/5092] more comment --- src/bin/cargo-miri.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 8b238a7f7972..8bd9947092a7 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -502,7 +502,8 @@ fn inside_cargo_rustc() { /// /// Currently, we detect this by checking for "--target=", which is /// never set for host crates. This matches what rustc bootstrap does, - /// which hopefully makes it "reliable enough". + /// which hopefully makes it "reliable enough". This relies on us always + /// invoking cargo itself with `--target`, which `in_cargo_miri` ensures. fn is_target_crate() -> bool { get_arg_flag_value("--target").is_some() } From 024cc435f4e19e2d34f8e2099f8da1fb2bf1b952 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 May 2020 11:58:18 +0200 Subject: [PATCH 2047/5092] avoid env::var which requires valid UTF-8 --- src/bin/cargo-miri.rs | 15 +++++++++------ src/bin/miri.rs | 9 +++++---- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 8bd9947092a7..37ab41b317db 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -269,7 +269,7 @@ fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { /// `MIRI_SYSROOT`. Skipped if `MIRI_SYSROOT` is already set, in which case we expect the user has /// done all this already. fn setup(subcommand: MiriCommand) { - if std::env::var("MIRI_SYSROOT").is_ok() { + if std::env::var_os("MIRI_SYSROOT").is_some() { if subcommand == MiriCommand::Setup { println!("WARNING: MIRI_SYSROOT already set, not doing anything.") } @@ -282,7 +282,7 @@ fn setup(subcommand: MiriCommand) { // First, we need xargo. if xargo_version().map_or(true, |v| v < XARGO_MIN_VERSION) { - if std::env::var("XARGO_CHECK").is_ok() { + if std::env::var_os("XARGO_CHECK").is_some() { // The user manually gave us a xargo binary; don't do anything automatically. show_error(format!("Your xargo is too old; please upgrade to the latest version")) } @@ -292,9 +292,9 @@ fn setup(subcommand: MiriCommand) { } // Determine where the rust sources are located. `XARGO_RUST_SRC` env var trumps everything. - let rust_src = match std::env::var("XARGO_RUST_SRC") { - Ok(val) => PathBuf::from(val), - Err(_) => { + let rust_src = match std::env::var_os("XARGO_RUST_SRC") { + Some(val) => PathBuf::from(val), + None => { // Check for `rust-src` rustup component. let sysroot = rustc() .args(&["--print", "sysroot"]) @@ -522,7 +522,7 @@ fn inside_cargo_rustc() { is_bin || is_test } - let verbose = std::env::var("MIRI_VERBOSE").is_ok(); + let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); let target_crate = is_target_crate(); // Figure out which arguments we need to pass. @@ -531,6 +531,7 @@ fn inside_cargo_rustc() { // other args for target crates - that is, crates which are ultimately // going to get interpreted by Miri. if target_crate { + // FIXME: breaks for non-UTF-8 sysroots (use `var_os` instead). let sysroot = std::env::var("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); args.push("--sysroot".to_owned()); @@ -545,6 +546,8 @@ fn inside_cargo_rustc() { // we want to interpret under Miri. We deserialize the user-provided arguments // from the special environment variable "MIRI_ARGS", and feed them // to the 'miri' binary. + // + // `env::var` is okay here, well-formed JSON is always UTF-8. let magic = std::env::var("MIRI_ARGS").expect("missing MIRI_ARGS"); let mut user_args: Vec = serde_json::from_str(&magic).expect("failed to deserialize MIRI_ARGS"); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 06101fe24e2d..31f78aa9895a 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -61,7 +61,7 @@ fn init_early_loggers() { // If it is not set, we avoid initializing now so that we can initialize // later with our custom settings, and *not* log anything for what happens before // `miri` gets started. - if env::var("RUSTC_LOG").is_ok() { + if env::var_os("RUSTC_LOG").is_some() { rustc_driver::init_rustc_env_logger(); } } @@ -69,8 +69,9 @@ fn init_early_loggers() { fn init_late_loggers(tcx: TyCtxt<'_>) { // We initialize loggers right before we start evaluation. We overwrite the `RUSTC_LOG` // env var if it is not set, control it based on `MIRI_LOG`. + // (FIXE: use `var_os`, but then we need to manually concatenate instead of `format!`.) if let Ok(var) = env::var("MIRI_LOG") { - if env::var("RUSTC_LOG").is_err() { + if env::var_os("RUSTC_LOG").is_none() { // We try to be a bit clever here: if `MIRI_LOG` is just a single level // used for everything, we only apply it to the parts of rustc that are // CTFE-related. Otherwise, we use it verbatim for `RUSTC_LOG`. @@ -90,8 +91,8 @@ fn init_late_loggers(tcx: TyCtxt<'_>) { // If `MIRI_BACKTRACE` is set and `RUSTC_CTFE_BACKTRACE` is not, set `RUSTC_CTFE_BACKTRACE`. // Do this late, so we ideally only apply this to Miri's errors. - if let Ok(val) = env::var("MIRI_BACKTRACE") { - let ctfe_backtrace = match &*val { + if let Some(val) = env::var_os("MIRI_BACKTRACE") { + let ctfe_backtrace = match &*val.to_string_lossy() { "immediate" => CtfeBacktrace::Immediate, "0" => CtfeBacktrace::Disabled, _ => CtfeBacktrace::Capture, From ba801a45dbbc9075f4bf13ee4b6b57c311e331ff Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 May 2020 12:24:30 +0200 Subject: [PATCH 2048/5092] make Miri work in rustc bootstrap stage 0 --- README.md | 7 +++++++ src/bin/cargo-miri.rs | 49 ++++++++++++++++++++++++++++--------------- src/bin/miri.rs | 6 ++++++ 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 35d15d59ee4d..1dd4a91e822f 100644 --- a/README.md +++ b/README.md @@ -222,6 +222,13 @@ Moreover, Miri recognizes some environment variables: * `MIRI_TEST_FLAGS` (recognized by the test suite) defines extra flags to be passed to Miri. +The following environment variables are internal, but used to communicate between +different Miri binaries, and as such worht documenting: + +* `MIRI_BE_RUSTC` when set to any value tells the Miri driver to actually not + interpret the code but compile it like rustc would. This is useful to be sure + that the compiled `rlib`s are compatible with Miri. + ## Contributing and getting help If you want to contribute to Miri, great! Please check out our diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 37ab41b317db..a1f502ab262f 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -86,11 +86,15 @@ fn get_arg_flag_value(name: &str) -> Option { } } -/// Returns a command for the right `miri` binary. -fn miri() -> Command { +/// Returns the path to the `miri` binary +fn find_miri() -> PathBuf { let mut path = std::env::current_exe().expect("current executable path invalid"); path.set_file_name("miri"); - Command::new(path) + path +} + +fn miri() -> Command { + Command::new(find_miri()) } fn cargo() -> Command { @@ -322,7 +326,8 @@ fn setup(subcommand: MiriCommand) { show_error(format!("Given Rust source directory `{}` does not exist.", rust_src.display())); } - // Next, we need our own libstd. We will do this work in whatever is a good cache dir for this platform. + // Next, we need our own libstd. Prepare a xargo project for that purpose. + // We will do this work in whatever is a good cache dir for this platform. let dirs = directories::ProjectDirs::from("org", "rust-lang", "miri").unwrap(); let dir = dirs.cache_dir(); if !dir.exists() { @@ -360,20 +365,31 @@ path = "lib.rs" ) .unwrap(); File::create(dir.join("lib.rs")).unwrap(); - // Prepare xargo invocation. + + // Determine architectures. + // We always need to set a target so rustc bootstrap can tell apart host from target crates. + let host = rustc_version::version_meta().unwrap().host; let target = get_arg_flag_value("--target"); - let print_sysroot = subcommand == MiriCommand::Setup - && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path + let target = target.as_ref().unwrap_or(&host); + // Now invoke xargo. let mut command = xargo_check(); command.arg("build").arg("-q"); + command.arg("--target").arg(target); command.current_dir(&dir); - command.env("RUSTFLAGS", miri::miri_default_args().join(" ")); command.env("XARGO_HOME", &dir); command.env("XARGO_RUST_SRC", &rust_src); - // Handle target flag. - if let Some(target) = &target { - command.arg("--target").arg(target); + // Use Miri as rustc to build a libstd compatible with us (and use the right flags). + // However, when we are running in bootstrap, we cannot just overwrite `RUSTC`, + // because we still need bootstrap to distinguish between host and target crates. + // In that case we overwrite `RUSTC_REAL` instead which determines the rustc used + // for target crates. + if env::var_os("RUSTC_STAGE").is_some() { + command.env("RUSTC_REAL", find_miri()); + } else { + command.env("RUSTC", find_miri()); } + command.env("MIRI_BE_RUSTC", "1"); + command.env("RUSTFLAGS", miri::miri_default_args().join(" ")); // Finally run it! if command.status().expect("failed to run xargo").success().not() { show_error(format!("Failed to run xargo")); @@ -382,12 +398,11 @@ path = "lib.rs" // That should be it! But we need to figure out where xargo built stuff. // Unfortunately, it puts things into a different directory when the // architecture matches the host. - let is_host = match &target { - None => true, - Some(target) => target == &rustc_version::version_meta().unwrap().host, - }; - let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; + let sysroot = if target == &host { dir.join("HOST") } else { PathBuf::from(dir) }; std::env::set_var("MIRI_SYSROOT", &sysroot); // pass the env var to the processes we spawn, which will turn it into "--sysroot" flags + // Figure out what to print. + let print_sysroot = subcommand == MiriCommand::Setup + && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path if print_sysroot { // Print just the sysroot and nothing else; this way we do not need any escaping. println!("{}", sysroot.display()); @@ -476,7 +491,7 @@ fn in_cargo_miri() { // Set `RUSTC_WRAPPER` to ourselves. Cargo will prepend that binary to its usual invocation, // i.e., the first argument is `rustc` -- which is what we use in `main` to distinguish - // the two codepaths. + // the two codepaths. (That extra argument is why we prefer this over setting `RUSTC`.) let path = std::env::current_exe().expect("current executable path invalid"); cmd.env("RUSTC_WRAPPER", path); if verbose { diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 31f78aa9895a..1e382a5a9bea 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -124,6 +124,12 @@ fn compile_time_sysroot() -> Option { } fn main() { + // If the environment asks us to actually be rustc, then do that. + if env::var_os("MIRI_BE_RUSTC").is_some() { + eprintln!("miri-as-rustc called with args: {:?}", env::args()); + return rustc_driver::main(); + } + init_early_loggers(); // Parse our arguments and split them across `rustc` and `miri`. From ac65350789d7f6be1b1b4942d6a3e0b54e9bca3c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 May 2020 13:20:34 +0200 Subject: [PATCH 2049/5092] adjust default sysroot when being rustc Also while at it, refactor how we pass the default Miri flags --- src/bin/miri.rs | 101 +++++++++++++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 44 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 1e382a5a9bea..c9391cec66f0 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -16,7 +16,6 @@ use log::debug; use rustc_session::CtfeBacktrace; use rustc_driver::Compilation; use rustc_hir::def_id::LOCAL_CRATE; -use rustc_interface::{interface, Queries}; use rustc_middle::ty::TyCtxt; struct MiriCompilerCalls { @@ -26,8 +25,8 @@ struct MiriCompilerCalls { impl rustc_driver::Callbacks for MiriCompilerCalls { fn after_analysis<'tcx>( &mut self, - compiler: &interface::Compiler, - queries: &'tcx Queries<'tcx>, + compiler: &rustc_interface::interface::Compiler, + queries: &'tcx rustc_interface::Queries<'tcx>, ) -> Compilation { compiler.session().abort_if_errors(); @@ -106,12 +105,12 @@ fn init_late_loggers(tcx: TyCtxt<'_>) { fn compile_time_sysroot() -> Option { if option_env!("RUSTC_STAGE").is_some() { // This is being built as part of rustc, and gets shipped with rustup. - // We can rely on the sysroot computation in librustc. + // We can rely on the sysroot computation in librustc_session. return None; } // For builds outside rustc, we need to ensure that we got a sysroot - // that gets used as a default. The sysroot computation in librustc would - // end up somewhere in the build dir. + // that gets used as a default. The sysroot computation in librustc_session would + // end up somewhere in the build dir (see `get_or_default_sysroot`). // Taken from PR . let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); @@ -123,13 +122,47 @@ fn compile_time_sysroot() -> Option { }) } -fn main() { - // If the environment asks us to actually be rustc, then do that. - if env::var_os("MIRI_BE_RUSTC").is_some() { - eprintln!("miri-as-rustc called with args: {:?}", env::args()); - return rustc_driver::main(); +/// Execute a compiler with the given CLI arguments and callbacks. +fn run_compiler(mut args: Vec, callbacks: &mut (dyn rustc_driver::Callbacks + Send)) { + // Make sure we use the right default sysroot. The default sysroot is wrong, + // because `get_or_default_sysroot` in `librustc_session` bases that on `current_exe`. + // + // Make sure we always call `compile_time_sysroot` as that also does some sanity-checks + // of the environment we were built in. + // FIXME: Ideally we'd turn a bad build env into a compile-time error via CTFE or so. + if let Some(sysroot) = compile_time_sysroot() { + let sysroot_flag = "--sysroot"; + if !args.iter().any(|e| e == sysroot_flag) { + // We need to overwrite the default that librustc_session would compute. + args.push(sysroot_flag.to_owned()); + args.push(sysroot); + } } + // Invoke compiler, and handle return code. + let result = rustc_driver::catch_fatal_errors(move || { + rustc_driver::run_compiler(&args, callbacks, None, None) + }) + .and_then(|result| result); + let exit_code = match result { + Ok(()) => rustc_driver::EXIT_SUCCESS, + Err(_) => rustc_driver::EXIT_FAILURE, + }; + std::process::exit(exit_code); +} + +fn main() { + rustc_driver::install_ice_hook(); + + // If the environment asks us to actually be rustc, then do that. + if env::var_os("MIRI_BE_RUSTC").is_some() { + rustc_driver::init_rustc_env_logger(); + // We cannot use `rustc_driver::main` as we need to adjust the CLI arguments. + let mut callbacks = rustc_driver::TimePassesCallbacks::default(); + return run_compiler(env::args().collect(), &mut callbacks); + } + + // Init loggers the Miri way. init_early_loggers(); // Parse our arguments and split them across `rustc` and `miri`. @@ -142,16 +175,20 @@ fn main() { let mut tracked_pointer_tag: Option = None; let mut tracked_alloc_id: Option = None; let mut rustc_args = vec![]; - let mut miri_args = vec![]; + let mut crate_args = vec![]; let mut after_dashdash = false; let mut excluded_env_vars = vec![]; - for arg in std::env::args() { + for arg in env::args() { if rustc_args.is_empty() { - // Very first arg: for `rustc`. + // Very first arg: binary name. rustc_args.push(arg); + // After this, push Miri default args (before everything else so they can be overwritten). + for arg in miri::miri_default_args().iter() { + rustc_args.push(arg.to_string()); + } } else if after_dashdash { - // Everything that comes after are `miri` args. - miri_args.push(arg); + // Everything that comes after `--` is forwarded to the interpreted crate. + crate_args.push(arg); } else { match arg.as_str() { "-Zmiri-disable-validation" => { @@ -227,30 +264,15 @@ fn main() { tracked_alloc_id = Some(miri::AllocId(id)); } _ => { + // Forward to rustc. rustc_args.push(arg); } } } } - // Determine sysroot if needed. Make sure we always call `compile_time_sysroot` - // as that also does some sanity-checks of the environment we were built in. - // FIXME: Ideally we'd turn a bad build env into a compile-time error, but - // CTFE does not seem powerful enough for that yet. - if let Some(sysroot) = compile_time_sysroot() { - let sysroot_flag = "--sysroot"; - if !rustc_args.iter().any(|e| e == sysroot_flag) { - // We need to overwrite the default that librustc would compute. - rustc_args.push(sysroot_flag.to_owned()); - rustc_args.push(sysroot); - } - } - - // Finally, add the default flags all the way in the beginning, but after the binary name. - rustc_args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string)); - debug!("rustc arguments: {:?}", rustc_args); - debug!("miri arguments: {:?}", miri_args); + debug!("crate arguments: {:?}", crate_args); let miri_config = miri::MiriConfig { validate, stacked_borrows, @@ -259,18 +281,9 @@ fn main() { ignore_leaks, excluded_env_vars, seed, - args: miri_args, + args: crate_args, tracked_pointer_tag, tracked_alloc_id, }; - rustc_driver::install_ice_hook(); - let result = rustc_driver::catch_fatal_errors(move || { - rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None) - }) - .and_then(|result| result); - let exit_code = match result { - Ok(()) => rustc_driver::EXIT_SUCCESS, - Err(_) => rustc_driver::EXIT_FAILURE, - }; - std::process::exit(exit_code); + return run_compiler(rustc_args, &mut MiriCompilerCalls { miri_config }); } From e65d87b110dd6890a3bd5b52198a535d8b91d355 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 May 2020 14:08:58 +0200 Subject: [PATCH 2050/5092] Typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1dd4a91e822f..057ff5e7ce84 100644 --- a/README.md +++ b/README.md @@ -223,7 +223,7 @@ Moreover, Miri recognizes some environment variables: passed to Miri. The following environment variables are internal, but used to communicate between -different Miri binaries, and as such worht documenting: +different Miri binaries, and as such worth documenting: * `MIRI_BE_RUSTC` when set to any value tells the Miri driver to actually not interpret the code but compile it like rustc would. This is useful to be sure From 3fdab9c44681247a94b8d09e4396b6058751ffcb Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 8 May 2020 13:56:10 +0200 Subject: [PATCH 2051/5092] Update to rustc changes --- src/machine.rs | 4 ++-- src/thread.rs | 7 +++---- tests/compile-fail/validity/invalid_wide_raw.rs | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 3853f6559959..51aa7ae31047 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -427,7 +427,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn canonical_alloc_id(mem: &Memory<'mir, 'tcx, Self>, id: AllocId) -> AllocId { let tcx = mem.tcx; // Figure out if this is an extern static, and if yes, which one. - let def_id = match tcx.alloc_map.lock().get(id) { + let def_id = match tcx.get_global_alloc(id) { Some(GlobalAlloc::Static(def_id)) if tcx.is_foreign_item(def_id) => def_id, _ => { // No need to canonicalize anything. @@ -494,7 +494,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { if Some(id) == memory_extra.tracked_alloc_id { register_diagnostic(NonHaltingDiagnostic::FreedAlloc(id)); } - + Ok(()) } diff --git a/src/thread.rs b/src/thread.rs index 2119175e12cc..d78beed28cfb 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -428,7 +428,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match *val { mir::interpret::ConstValue::Scalar(Scalar::Ptr(ref mut ptr)) => { let alloc_id = ptr.alloc_id; - let alloc = this.tcx.alloc_map.lock().get(alloc_id); + let alloc = this.tcx.get_global_alloc(alloc_id); let tcx = this.tcx; let is_thread_local = |def_id| { tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) @@ -489,13 +489,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx })?; let id = raw_const.alloc_id; // Extract the allocation from the query result. - let mut alloc_map = tcx.alloc_map.lock(); - let allocation = alloc_map.unwrap_memory(id); + let allocation = tcx.global_alloc(id).unwrap_memory(); // Create a new allocation id for the same allocation in this hacky // way. Internally, `alloc_map` deduplicates allocations, but this // is fine because Miri will make a copy before a first mutable // access. - let new_alloc_id = alloc_map.create_memory_alloc(allocation); + let new_alloc_id = tcx.create_memory_alloc(allocation); this.machine.threads.set_thread_local_alloc_id(def_id, new_alloc_id); Ok(new_alloc_id) } diff --git a/tests/compile-fail/validity/invalid_wide_raw.rs b/tests/compile-fail/validity/invalid_wide_raw.rs index c23267213222..6e0809b15ca4 100644 --- a/tests/compile-fail/validity/invalid_wide_raw.rs +++ b/tests/compile-fail/validity/invalid_wide_raw.rs @@ -6,5 +6,5 @@ fn main() { struct S { x: * mut dyn T } - dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); //~ ERROR: encountered dangling vtable pointer + dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); //~ ERROR: encountered dangling vtable pointer in wide pointer } From 4f06197aff96b84905d973ce5a46d43b9a3062f8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 May 2020 10:32:29 +0200 Subject: [PATCH 2052/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index d53d4d68e486..aafee80cbe02 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0f9088f9610618e724cfc0cf2ba3721918be5ec9 +6f5c7827b71d1e1e4831fa7522e49acaf2a9e44e From 81046fa5e5d8780449c5afd2ce3ec505563a5f76 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 May 2020 18:41:03 +0200 Subject: [PATCH 2053/5092] cargo-miri: never invoke rustc, always go through 'MIRI_BE_RUSTC=1 miri' instead --- src/bin/cargo-miri.rs | 123 ++++++++++++------------------------------ src/bin/miri.rs | 8 +-- 2 files changed, 38 insertions(+), 93 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index a1f502ab262f..2e1609e1edff 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -8,6 +8,8 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::ffi::OsString; +use rustc_version::VersionMeta; + const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 20); const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and tests in Miri @@ -97,6 +99,10 @@ fn miri() -> Command { Command::new(find_miri()) } +fn version_info() -> VersionMeta { + VersionMeta::for_command(miri()).expect("failed to determine underlying rustc version of Miri") +} + fn cargo() -> Command { Command::new(env::var_os("CARGO").unwrap_or_else(|| OsString::from("cargo"))) } @@ -105,10 +111,6 @@ fn xargo_check() -> Command { Command::new(env::var_os("XARGO_CHECK").unwrap_or_else(|| OsString::from("xargo-check"))) } -fn rustc() -> Command { - Command::new(env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"))) -} - fn list_targets() -> impl Iterator { // We need to get the manifest, and then the metadata, to enumerate targets. let manifest_path = @@ -153,55 +155,6 @@ fn list_targets() -> impl Iterator { package.targets.into_iter() } -/// Make sure that the `miri` and `rustc` binary are from the same sysroot. -/// This can be violated e.g. when miri is locally built and installed with a different -/// toolchain than what is used when `cargo miri` is run. -fn test_sysroot_consistency() { - fn get_sysroot(mut cmd: Command) -> PathBuf { - let out = cmd - .arg("--print") - .arg("sysroot") - .output() - .expect("Failed to run rustc to get sysroot info"); - let stdout = String::from_utf8(out.stdout).expect("stdout is not valid UTF-8"); - let stderr = String::from_utf8(out.stderr).expect("stderr is not valid UTF-8"); - assert!( - out.status.success(), - "Bad status code {} when getting sysroot info via {:?}.\nstdout:\n{}\nstderr:\n{}", - out.status, - cmd, - stdout, - stderr, - ); - let stdout = stdout.trim(); - PathBuf::from(stdout) - .canonicalize() - .unwrap_or_else(|_| panic!("Failed to canonicalize sysroot: {}", stdout)) - } - - // Do not check sysroots if we got built as part of a Rust distribution. - // During `bootstrap`, the sysroot does not match anyway, and then some distros - // play symlink tricks so the sysroots may be different even for the final stage - // (see ). - if option_env!("RUSTC_STAGE").is_some() { - return; - } - - let rustc_sysroot = get_sysroot(rustc()); - let miri_sysroot = get_sysroot(miri()); - - if rustc_sysroot != miri_sysroot { - show_error(format!( - "miri was built for a different sysroot than the rustc in your current toolchain.\n\ - Make sure you use the same toolchain to run miri that you used to build it!\n\ - rustc sysroot: `{}`\n\ - miri sysroot: `{}`", - rustc_sysroot.display(), - miri_sysroot.display() - )); - } -} - fn xargo_version() -> Option<(u32, u32, u32)> { let out = xargo_check().arg("--version").output().ok()?; if !out.status.success() { @@ -300,10 +253,10 @@ fn setup(subcommand: MiriCommand) { Some(val) => PathBuf::from(val), None => { // Check for `rust-src` rustup component. - let sysroot = rustc() + let sysroot = miri() .args(&["--print", "sysroot"]) .output() - .expect("failed to get rustc sysroot") + .expect("failed to determine sysroot") .stdout; let sysroot = std::str::from_utf8(&sysroot).unwrap(); let sysroot = Path::new(sysroot.trim_end_matches('\n')); @@ -316,7 +269,7 @@ fn setup(subcommand: MiriCommand) { ask_to_run( cmd, ask_user, - "install the rustc-src component for the selected toolchain", + "install the `rust-src` component for the selected toolchain", ); } rustup_src @@ -368,7 +321,7 @@ path = "lib.rs" // Determine architectures. // We always need to set a target so rustc bootstrap can tell apart host from target crates. - let host = rustc_version::version_meta().unwrap().host; + let host = version_info().host; let target = get_arg_flag_value("--target"); let target = target.as_ref().unwrap_or(&host); // Now invoke xargo. @@ -424,9 +377,6 @@ fn in_cargo_miri() { }; let verbose = has_arg_flag("-v"); - // Some basic sanity checks - test_sysroot_consistency(); - // We always setup. setup(subcommand); if subcommand == MiriCommand::Setup { @@ -478,7 +428,7 @@ fn in_cargo_miri() { if get_arg_flag_value("--target").is_none() { // When no `--target` is given, default to the host. cmd.arg("--target"); - cmd.arg(rustc_version::version_meta().unwrap().host); + cmd.arg(version_info().host); } // Serialize the remaining args into a special environemt variable. @@ -540,51 +490,46 @@ fn inside_cargo_rustc() { let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); let target_crate = is_target_crate(); - // Figure out which arguments we need to pass. - let mut args: Vec = std::env::args().skip(2).collect(); // skip `cargo-miri rustc` - // We make sure to only specify our custom Xargo sysroot and - // other args for target crates - that is, crates which are ultimately - // going to get interpreted by Miri. + let mut cmd = miri(); + // Forward arguments. + cmd.args(std::env::args().skip(2)); // skip `cargo-miri rustc` + + // We make sure to only specify our custom Xargo sysroot for target crates - that is, + // crates which are ultimately going to get interpreted by Miri. if target_crate { - // FIXME: breaks for non-UTF-8 sysroots (use `var_os` instead). let sysroot = - std::env::var("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); - args.push("--sysroot".to_owned()); - args.push(sysroot); - args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string)); + env::var_os("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); + cmd.arg("--sysroot"); + cmd.arg(sysroot); } - // Figure out the binary we need to call. If this is a runnable target crate, we want to call - // Miri to start interpretation; otherwise we want to call rustc to build the crate as usual. - let mut command = if target_crate && is_runnable_crate() { - // This is the 'target crate' - the binary or test crate that - // we want to interpret under Miri. We deserialize the user-provided arguments - // from the special environment variable "MIRI_ARGS", and feed them - // to the 'miri' binary. + // If this is a runnable target crate, we want Miri to start interpretation; + // otherwise we want Miri to behave like rustc and build the crate as usual. + if target_crate && is_runnable_crate() { + // This is the binary or test crate that we want to interpret under Miri. + // We deserialize the arguments that are meant for Miri from the special environment + // variable "MIRI_ARGS", and feed them to the 'miri' binary. // // `env::var` is okay here, well-formed JSON is always UTF-8. let magic = std::env::var("MIRI_ARGS").expect("missing MIRI_ARGS"); - let mut user_args: Vec = + let miri_args: Vec = serde_json::from_str(&magic).expect("failed to deserialize MIRI_ARGS"); - args.append(&mut user_args); - // Run this in Miri. - miri() + cmd.args(miri_args); } else { - rustc() + // We want to compile, not interpret. + cmd.env("MIRI_BE_RUSTC", "1"); }; // Run it. - command.args(&args); if verbose { - eprintln!("+ {:?}", command); + eprintln!("+ {:?}", cmd); } - - match command.status() { + match cmd.status() { Ok(exit) => if !exit.success() { std::process::exit(exit.code().unwrap_or(42)); }, - Err(e) => panic!("error running {:?}:\n{:?}", command, e), + Err(e) => panic!("error running {:?}:\n{:?}", cmd, e), } } @@ -609,6 +554,6 @@ fn main() { // dependencies get dispatched to `rustc`, the final test/binary to `miri`. inside_cargo_rustc(); } else { - show_error(format!("must be called with either `miri` or `rustc` as first argument.")) + show_error(format!("`cargo-miri` must be called with either `miri` or `rustc` as first argument.")) } } diff --git a/src/bin/miri.rs b/src/bin/miri.rs index c9391cec66f0..ff3872f2fd02 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -139,6 +139,10 @@ fn run_compiler(mut args: Vec, callbacks: &mut (dyn rustc_driver::Callba } } + // Some options have different defaults in Miri than in plain rustc; apply those by making + // them the first arguments after the binary name (but later arguments can overwrite them). + args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string)); + // Invoke compiler, and handle return code. let result = rustc_driver::catch_fatal_errors(move || { rustc_driver::run_compiler(&args, callbacks, None, None) @@ -182,10 +186,6 @@ fn main() { if rustc_args.is_empty() { // Very first arg: binary name. rustc_args.push(arg); - // After this, push Miri default args (before everything else so they can be overwritten). - for arg in miri::miri_default_args().iter() { - rustc_args.push(arg.to_string()); - } } else if after_dashdash { // Everything that comes after `--` is forwarded to the interpreted crate. crate_args.push(arg); From 12114c5137682cb99673d2757ed2af9b2dfc2113 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 May 2020 18:52:21 +0200 Subject: [PATCH 2054/5092] fix dead link in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 057ff5e7ce84..26d9b39fdd8e 100644 --- a/README.md +++ b/README.md @@ -156,7 +156,7 @@ Try deleting `~/.cache/miri`. This means the sysroot you are using was not compiled with Miri in mind. This should never happen when you use `cargo miri` because that takes care of setting up the sysroot. If you are using `miri` (the Miri driver) directly, see -[below][testing-miri] for how to set up the sysroot. +[CONTRIBUTING.md](CONTRIBUTING.md) for how to use `./miri`. ## Miri `-Z` flags and environment variables From 845b89c23607516b5cae90cc3c925c9ab32059c7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 May 2020 18:56:38 +0200 Subject: [PATCH 2055/5092] we do not need to set RUSTFLAGS for xargo any more as miri-as-rustc already uses these flags --- src/bin/cargo-miri.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 2e1609e1edff..ca7fafd3d9c2 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -342,7 +342,6 @@ path = "lib.rs" command.env("RUSTC", find_miri()); } command.env("MIRI_BE_RUSTC", "1"); - command.env("RUSTFLAGS", miri::miri_default_args().join(" ")); // Finally run it! if command.status().expect("failed to run xargo").success().not() { show_error(format!("Failed to run xargo")); From 938fe00f0246afe007850a362aa2050151772baa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 11 May 2020 00:07:59 +0200 Subject: [PATCH 2056/5092] fix some comments, and run_compiler return type --- README.md | 4 ++-- src/bin/cargo-miri.rs | 8 +++----- src/bin/miri.rs | 10 +++++----- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 26d9b39fdd8e..02fbd6cdfacf 100644 --- a/README.md +++ b/README.md @@ -155,8 +155,8 @@ Try deleting `~/.cache/miri`. This means the sysroot you are using was not compiled with Miri in mind. This should never happen when you use `cargo miri` because that takes care of setting -up the sysroot. If you are using `miri` (the Miri driver) directly, see -[CONTRIBUTING.md](CONTRIBUTING.md) for how to use `./miri`. +up the sysroot. If you are using `miri` (the Miri driver) directly, see the +[contributors' guide](CONTRIBUTING.md) for how to use `./miri` to best do that. ## Miri `-Z` flags and environment variables diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index ca7fafd3d9c2..b2e5238489f2 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -479,10 +479,6 @@ fn inside_cargo_rustc() { fn is_runnable_crate() -> bool { let is_bin = get_arg_flag_value("--crate-type").as_deref() == Some("bin"); let is_test = has_arg_flag("--test"); - - // The final runnable (under Miri) crate will either be a binary crate - // or a test crate. We make sure to exclude build scripts here, since - // they are also build with "--crate-type bin" is_bin || is_test } @@ -494,7 +490,8 @@ fn inside_cargo_rustc() { cmd.args(std::env::args().skip(2)); // skip `cargo-miri rustc` // We make sure to only specify our custom Xargo sysroot for target crates - that is, - // crates which are ultimately going to get interpreted by Miri. + // crates which are needed for interpretation by Miri. proc-macros and build scripts + // should use the default sysroot. if target_crate { let sysroot = env::var_os("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); @@ -506,6 +503,7 @@ fn inside_cargo_rustc() { // otherwise we want Miri to behave like rustc and build the crate as usual. if target_crate && is_runnable_crate() { // This is the binary or test crate that we want to interpret under Miri. + // (Testing `target_crate` is needed to exclude build scripts.) // We deserialize the arguments that are meant for Miri from the special environment // variable "MIRI_ARGS", and feed them to the 'miri' binary. // diff --git a/src/bin/miri.rs b/src/bin/miri.rs index ff3872f2fd02..96de81b62430 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -68,7 +68,7 @@ fn init_early_loggers() { fn init_late_loggers(tcx: TyCtxt<'_>) { // We initialize loggers right before we start evaluation. We overwrite the `RUSTC_LOG` // env var if it is not set, control it based on `MIRI_LOG`. - // (FIXE: use `var_os`, but then we need to manually concatenate instead of `format!`.) + // (FIXME: use `var_os`, but then we need to manually concatenate instead of `format!`.) if let Ok(var) = env::var("MIRI_LOG") { if env::var_os("RUSTC_LOG").is_none() { // We try to be a bit clever here: if `MIRI_LOG` is just a single level @@ -123,7 +123,7 @@ fn compile_time_sysroot() -> Option { } /// Execute a compiler with the given CLI arguments and callbacks. -fn run_compiler(mut args: Vec, callbacks: &mut (dyn rustc_driver::Callbacks + Send)) { +fn run_compiler(mut args: Vec, callbacks: &mut (dyn rustc_driver::Callbacks + Send)) -> ! { // Make sure we use the right default sysroot. The default sysroot is wrong, // because `get_or_default_sysroot` in `librustc_session` bases that on `current_exe`. // @@ -152,7 +152,7 @@ fn run_compiler(mut args: Vec, callbacks: &mut (dyn rustc_driver::Callba Ok(()) => rustc_driver::EXIT_SUCCESS, Err(_) => rustc_driver::EXIT_FAILURE, }; - std::process::exit(exit_code); + std::process::exit(exit_code) } fn main() { @@ -163,7 +163,7 @@ fn main() { rustc_driver::init_rustc_env_logger(); // We cannot use `rustc_driver::main` as we need to adjust the CLI arguments. let mut callbacks = rustc_driver::TimePassesCallbacks::default(); - return run_compiler(env::args().collect(), &mut callbacks); + run_compiler(env::args().collect(), &mut callbacks) } // Init loggers the Miri way. @@ -285,5 +285,5 @@ fn main() { tracked_pointer_tag, tracked_alloc_id, }; - return run_compiler(rustc_args, &mut MiriCompilerCalls { miri_config }); + run_compiler(rustc_args, &mut MiriCompilerCalls { miri_config }) } From 88fc42bbc8f9589bdbcca9d86026e4673b54deee Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 11 May 2020 10:37:35 +0200 Subject: [PATCH 2057/5092] compiletest: no need to call rustc here --- tests/compiletest.rs | 34 ++++++++-------------------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index ca1879962089..17125de9f55f 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -9,23 +9,11 @@ use colored::*; use compiletest_rs as compiletest; fn miri_path() -> PathBuf { - if rustc_test_suite().is_some() { - PathBuf::from(option_env!("MIRI_PATH").unwrap()) - } else { - PathBuf::from(env!("CARGO_BIN_EXE_miri")) - } -} - -fn rustc_test_suite() -> Option { - option_env!("RUSTC_TEST_SUITE").map(PathBuf::from) -} - -fn rustc_lib_path() -> PathBuf { - option_env!("RUSTC_LIB_PATH").unwrap().into() + PathBuf::from(option_env!("MIRI_PATH").unwrap_or(env!("CARGO_BIN_EXE_miri"))) } fn run_tests(mode: &str, path: &str, target: &str) { - let in_rustc_test_suite = rustc_test_suite().is_some(); + let in_rustc_test_suite = option_env!("RUSTC_STAGE").is_some(); // Add some flags we always want. let mut flags = Vec::new(); flags.push("--edition 2018".to_owned()); @@ -50,9 +38,9 @@ fn run_tests(mode: &str, path: &str, target: &str) { let mut config = compiletest::Config::default().tempdir(); config.mode = mode.parse().expect("Invalid mode"); config.rustc_path = miri_path(); - if in_rustc_test_suite { - config.run_lib_path = rustc_lib_path(); - config.compile_lib_path = rustc_lib_path(); + if let Some(lib_path) = option_env!("RUSTC_LIB_PATH") { + config.run_lib_path = PathBuf::from(lib_path); + config.compile_lib_path = PathBuf::from(lib_path); } config.filter = env::args().nth(1); config.host = get_host(); @@ -91,15 +79,9 @@ fn miri_pass(path: &str, target: &str) { } fn get_host() -> String { - let rustc = rustc_test_suite().unwrap_or(PathBuf::from("rustc")); - let rustc_version = std::process::Command::new(rustc) - .arg("-vV") - .output() - .expect("rustc not found for -vV") - .stdout; - let rustc_version = std::str::from_utf8(&rustc_version).expect("rustc -vV is not utf8"); - let version_meta = rustc_version::version_meta_for(&rustc_version) - .expect("failed to parse rustc version info"); + let version_meta = rustc_version::VersionMeta::for_command( + std::process::Command::new(miri_path()) + ).expect("failed to parse rustc version info"); version_meta.host } From 791ec8fef740ecbf3ad63ae1c5a3001e1ec45598 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 11 May 2020 10:54:21 +0200 Subject: [PATCH 2058/5092] fmt --- tests/compiletest.rs | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 17125de9f55f..2be0661b93ee 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -53,12 +53,9 @@ fn run_tests(mode: &str, path: &str, target: &str) { fn compile_fail(path: &str, target: &str) { eprintln!( "{}", - format!( - "## Running compile-fail tests in {} against miri for target {}", - path, target - ) - .green() - .bold() + format!("## Running compile-fail tests in {} against miri for target {}", path, target) + .green() + .bold() ); run_tests("compile-fail", path, target); @@ -67,21 +64,18 @@ fn compile_fail(path: &str, target: &str) { fn miri_pass(path: &str, target: &str) { eprintln!( "{}", - format!( - "## Running run-pass tests in {} against miri for target {}", - path, target - ) - .green() - .bold() + format!("## Running run-pass tests in {} against miri for target {}", path, target) + .green() + .bold() ); run_tests("ui", path, target); } fn get_host() -> String { - let version_meta = rustc_version::VersionMeta::for_command( - std::process::Command::new(miri_path()) - ).expect("failed to parse rustc version info"); + let version_meta = + rustc_version::VersionMeta::for_command(std::process::Command::new(miri_path())) + .expect("failed to parse rustc version info"); version_meta.host } From 880e6847cfb895459a183346f62767f4a9f31660 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 May 2020 23:49:10 +0200 Subject: [PATCH 2059/5092] play with bash on AppVeyor Also consistently order and format our two CI files --- .appveyor.yml | 106 +++++++++++++++------------------------------ .travis.yml | 48 +++++++++----------- travis.sh => ci.sh | 19 ++++---- 3 files changed, 67 insertions(+), 106 deletions(-) rename travis.sh => ci.sh (73%) diff --git a/.appveyor.yml b/.appveyor.yml index 294ef26be0be..209e38dc532a 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,84 +1,50 @@ +build: off # No Visual Studio auto-build. environment: - global: - PROJECT_NAME: miri - matrix: - - TARGET: i686-pc-windows-msvc + global: + PROJECT_NAME: miri + matrix: + - TARGET: i686-pc-windows-msvc +matrix: + fast_finish: true # Immediately finish build once one of the jobs fails. +cache: +- '%USERPROFILE%\.cargo' +- '%USERPROFILE%\.rustup' # branches to build branches: # whitelist only: - - auto - - try - -matrix: - fast_finish: true # set this flag to immediately finish build once one of the jobs fails. - -cache: - - '%USERPROFILE%\.cargo' - - '%USERPROFILE%\.rustup' + - auto + - try install: - # Compute the rust version we use - - set /p RUSTC_HASH= Date: Mon, 11 May 2020 10:13:17 +0200 Subject: [PATCH 2060/5092] fix warnings for non-Unix builds --- src/shims/fs.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 0de0b33fb2e2..8613f6bb0994 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -549,12 +549,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx target_op: OpTy<'tcx, Tag>, linkpath_op: OpTy<'tcx, Tag> ) -> InterpResult<'tcx, i32> { - #[cfg(target_family = "unix")] + #[cfg(unix)] fn create_link(src: &Path, dst: &Path) -> std::io::Result<()> { std::os::unix::fs::symlink(src, dst) } - #[cfg(target_family = "windows")] + #[cfg(windows)] fn create_link(src: &Path, dst: &Path) -> std::io::Result<()> { use std::os::windows::fs; if src.is_dir() { @@ -816,7 +816,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("mkdir")?; - let _mode = if this.tcx.sess.target.target.target_os == "macos" { + #[cfg_attr(not(unix), allow(unused_variables))] + let mode = if this.tcx.sess.target.target.target_os == "macos" { u32::from(this.read_scalar(mode_op)?.not_undef()?.to_u16()?) } else { this.read_scalar(mode_op)?.to_u32()? @@ -824,14 +825,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let path = this.read_path_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + #[cfg_attr(not(unix), allow(unused_mut))] let mut builder = DirBuilder::new(); // If the host supports it, forward on the mode of the directory // (i.e. permission bits and the sticky bit) - #[cfg(target_family = "unix")] + #[cfg(unix)] { use std::os::unix::fs::DirBuilderExt; - builder.mode(_mode.into()); + builder.mode(mode.into()); } let result = builder.create(path).map(|_| 0i32); From fdebecbb086a6f1a4606d50a53231ae69eb1a47a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 11 May 2020 10:40:25 +0200 Subject: [PATCH 2061/5092] fix python interpreter on Windows --- .appveyor.yml | 1 + ci.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 209e38dc532a..741a1de11a80 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -38,6 +38,7 @@ install: - cargo --version test_script: +- set PYTHON=C:\msys64\mingw64\bin\python3.exe - bash ci.sh after_test: diff --git a/ci.sh b/ci.sh index 4bc039e607ba..ecc881919dee 100755 --- a/ci.sh +++ b/ci.sh @@ -29,7 +29,7 @@ function run_tests { fi # "miri test" has built the sysroot for us, now this should pass without # any interactive questions. - test-cargo-miri/run-test.py + ${PYTHON:-python3} test-cargo-miri/run-test.py echo } From dec0bf15f67d5181917d02a469756d91059ebace Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 11 May 2020 10:59:01 +0200 Subject: [PATCH 2062/5092] Windows CI: rely on stable cargo --- .appveyor.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 741a1de11a80..34887459f6d9 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -29,10 +29,8 @@ install: - rustup toolchain uninstall beta nightly - rustup update # Install "master" toolchain. -# We need to install cargo here as well or else the DLL search path inside `cargo run` -# will be for the wrong toolchain. (On Unix, `./miri` takes care of this, but not here.) - cargo install rustup-toolchain-install-master -- rustup-toolchain-install-master -f -n master %RUSTC_HASH% -c rust-src -c rustc-dev -c cargo +- rustup-toolchain-install-master -f -n master %RUSTC_HASH% -c rust-src -c rustc-dev - rustup default master - rustc --version - cargo --version From 131bdf88a759e3737d1eb28801e7816340f236b5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 11 May 2020 11:19:26 +0200 Subject: [PATCH 2063/5092] always lock on CI --- ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index ecc881919dee..a7254f2958a0 100755 --- a/ci.sh +++ b/ci.sh @@ -25,7 +25,7 @@ function run_tests { ./miri test --locked if ! [ -n "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with MIR optimizations - MIRI_TEST_FLAGS="-Z mir-opt-level=3" ./miri test + MIRI_TEST_FLAGS="-Z mir-opt-level=3" ./miri test --locked fi # "miri test" has built the sysroot for us, now this should pass without # any interactive questions. From aaa3208432ac25739f38c81b0646234afa62fafa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 May 2020 19:21:04 +0200 Subject: [PATCH 2064/5092] test Linux on macOS host --- ci.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/ci.sh b/ci.sh index a7254f2958a0..922469aeca54 100755 --- a/ci.sh +++ b/ci.sh @@ -42,6 +42,7 @@ if [ "${TRAVIS_OS_NAME:-}" == linux ]; then MIRI_TEST_TARGET=x86_64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests elif [ "${TRAVIS_OS_NAME:-}" == osx ]; then + MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests MIRI_TEST_TARGET=x86_64-pc-windows-msvc run_tests MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests elif [ "${CI_WINDOWS:-}" == True ]; then From e0f9081c5cdcf21d3e02c1e31bac5a5d95a4c581 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 16 May 2020 11:30:11 +0200 Subject: [PATCH 2065/5092] use new rustc_driver::catch_with_exit_code --- rust-version | 2 +- src/bin/miri.rs | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/rust-version b/rust-version index aafee80cbe02..b1b25c4bcab6 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6f5c7827b71d1e1e4831fa7522e49acaf2a9e44e +84539360498cab3c70a7c9114c0b8106c8e1b06b diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 96de81b62430..48e4a60c71f9 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -144,14 +144,9 @@ fn run_compiler(mut args: Vec, callbacks: &mut (dyn rustc_driver::Callba args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string)); // Invoke compiler, and handle return code. - let result = rustc_driver::catch_fatal_errors(move || { + let exit_code = rustc_driver::catch_with_exit_code(move || { rustc_driver::run_compiler(&args, callbacks, None, None) - }) - .and_then(|result| result); - let exit_code = match result { - Ok(()) => rustc_driver::EXIT_SUCCESS, - Err(_) => rustc_driver::EXIT_FAILURE, - }; + }); std::process::exit(exit_code) } From e22baedb1f1099488cdfcc49f561ec24ea457395 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 May 2020 10:08:45 +0200 Subject: [PATCH 2066/5092] add test suite filter example to README and 'cargo miri --help' --- README.md | 11 ++++++----- src/bin/cargo-miri.rs | 6 +++++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 02fbd6cdfacf..12fc6d22cf85 100644 --- a/README.md +++ b/README.md @@ -83,16 +83,17 @@ Now you can run your project in Miri: The first time you run Miri, it will perform some extra setup and install some dependencies. It will ask you for confirmation before installing anything. +You can pass arguments to Miri after the first `--`, and pass arguments to the +interpreted program or test suite after the second `--`. For example, `cargo +miri run -- -Zmiri-disable-stacked-borrows` runs the program without checking +the aliasing of references. To filter the tests being run, use `cargo miri test +-- -- filter`. + Miri supports cross-execution: if you want to run the program as if it was a Linux program, you can do `cargo miri run --target x86_64-unknown-linux-gnu`. This is particularly useful if you are using Windows, as the Linux target is much better supported than Windows targets. -You can pass arguments to Miri after the first `--`, and pass arguments to the -interpreted program or test suite after the second `--`. For example, `cargo -miri run -- -Zmiri-disable-validation` runs the program without validation of -basic type invariants and without checking the aliasing of references. - When compiling code via `cargo miri`, the `miri` config flag is set. You can use this to ignore test cases that fail under Miri because they do things Miri does not support: diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index b2e5238489f2..5dadd3f931db 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -15,7 +15,7 @@ const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 20); const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and tests in Miri Usage: - cargo miri [subcommand] [options] [--] [...] [--] [...] + cargo miri [subcommand] [...] [--] [...] [--] [...] Subcommands: run Run binaries (default) @@ -30,6 +30,10 @@ Common options: Other [options] are the same as `cargo check`. Everything after the first "--" is passed verbatim to Miri, which will pass everything after the second "--" verbatim to the interpreted program. + +Examples: + cargo miri run -- -Zmiri-disable-stacked-borrows + cargo miri test -- -- test-suite-filter "#; #[derive(Copy, Clone, Debug, PartialEq, Eq)] From d90a087df9830e08db88f83fc7da3c1b2609c10c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 May 2020 11:20:05 +0200 Subject: [PATCH 2067/5092] fix libstd rebuilds due to RUSTFLAGS changes --- src/bin/cargo-miri.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 5dadd3f931db..12f59c05b0a9 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -335,6 +335,7 @@ path = "lib.rs" command.current_dir(&dir); command.env("XARGO_HOME", &dir); command.env("XARGO_RUST_SRC", &rust_src); + command.env_remove("RUSTFLAGS"); // Make sure external `RUSTFLAGS` do not influence the build. // Use Miri as rustc to build a libstd compatible with us (and use the right flags). // However, when we are running in bootstrap, we cannot just overwrite `RUSTC`, // because we still need bootstrap to distinguish between host and target crates. From 87c46944482a8cc5a7256fc0d5dcd9fd015b51d6 Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 21 Apr 2020 22:01:40 -0500 Subject: [PATCH 2068/5092] Add file sync shims Adds implementations for fsync, fdatasync, and sync_file_range --- src/shims/foreign_items/posix.rs | 8 ++++ src/shims/foreign_items/posix/linux.rs | 5 +++ src/shims/fs.rs | 62 ++++++++++++++++++++++++++ tests/run-pass/fs.rs | 24 ++++++++++ tests/run-pass/libc.rs | 36 ++++++++++++++- 5 files changed, 134 insertions(+), 1 deletion(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 951a40293b72..6311f0a4a9fc 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -136,6 +136,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // "lseek" is only used on macOS which is 64bit-only, so `i64` always works. this.write_scalar(Scalar::from_i64(result), dest)?; } + "fsync" => { + let result = this.fsync(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "fdatasync" => { + let result = this.fdatasync(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } // Allocation "posix_memalign" => { diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index e0f54cac1570..16d7d059e73b 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -54,6 +54,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // fadvise is only informational, we can ignore it. this.write_null(dest)?; } + // Linux-only + "sync_file_range" => { + let result = this.sync_file_range(args[0], args[1], args[2], args[3])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } // Time related shims "clock_gettime" => { diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 8613f6bb0994..b7579f6cb732 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -375,6 +375,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fh.insert_fd_with_min_fd(FileHandle { file: duplicated, writable }, start) }); this.try_unwrap_io_result(fd_result) + } else if this.tcx.sess.target.target.target_os == "macos" + && cmd == this.eval_libc_i32("F_FULLFSYNC")? + { + if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { + let result = file.sync_all(); + this.try_unwrap_io_result(result.map(|_| 0i32)) + } else { + this.handle_not_found() + } } else { throw_unsup_format!("the {:#x} command is not supported for `fcntl`)", cmd); } @@ -1103,6 +1112,59 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.handle_not_found() } } + + fn fsync(&mut self, fd_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.check_no_isolation("fsync")?; + + let fd = this.read_scalar(fd_op)?.to_i32()?; + if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { + let result = file.sync_all(); + this.try_unwrap_io_result(result.map(|_| 0i32)) + } else { + this.handle_not_found() + } + } + + fn fdatasync(&mut self, fd_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.check_no_isolation("fdatasync")?; + + let fd = this.read_scalar(fd_op)?.to_i32()?; + if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { + let result = file.sync_data(); + this.try_unwrap_io_result(result.map(|_| 0i32)) + } else { + this.handle_not_found() + } + } + + fn sync_file_range( + &mut self, + fd_op: OpTy<'tcx, Tag>, + offset_op: OpTy<'tcx, Tag>, + nbytes_op: OpTy<'tcx, Tag>, + flags_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.check_no_isolation("sync_file_range")?; + + let fd = this.read_scalar(fd_op)?.to_i32()?; + let _offset = this.read_scalar(offset_op)?.to_i64()?; + let _nbytes = this.read_scalar(nbytes_op)?.to_i64()?; + let _flags = this.read_scalar(flags_op)?.to_u32()?; + if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { + // In the interest of host compatibility, we conservatively ignore + // offset, nbytes, and flags, and sync the entire file. + let result = file.sync_data(); + this.try_unwrap_io_result(result.map(|_| 0i32)) + } else { + this.handle_not_found() + } + } } /// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch when diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 1a139de8148a..df022a7c70d8 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -14,6 +14,8 @@ fn main() { test_seek(); test_metadata(); test_file_set_len(); + test_file_sync_all(); + test_file_sync_data(); test_symlink(); test_errors(); test_rename(); @@ -182,6 +184,28 @@ fn test_file_set_len() { remove_file(&path).unwrap(); } +fn test_file_sync_all() { + let bytes = b"Hello, World!\n"; + let path = prepare_with_content("miri_test_fs_sync_all.txt", bytes); + + // Test that we can call sync_all (can't readily test effects of this operation) + let file = File::open(&path).unwrap(); + file.sync_all().unwrap(); + + remove_file(&path).unwrap(); +} + +fn test_file_sync_data() { + let bytes = b"Hello, World!\n"; + let path = prepare_with_content("miri_test_fs_sync_data.txt", bytes); + + // Test that we can call sync_data (can't readily test effects of this operation) + let file = File::open(&path).unwrap(); + file.sync_data().unwrap(); + + remove_file(&path).unwrap(); +} + fn test_symlink() { let bytes = b"Hello, World!\n"; let path = prepare_with_content("miri_test_fs_link_target.txt", bytes); diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index 04ca5c0b3b1a..5897c46f6375 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -17,7 +17,7 @@ fn test_posix_fadvise() { use std::io::Write; use std::os::unix::io::AsRawFd; - let path = tmp().join("miri_test_libc.txt"); + let path = tmp().join("miri_test_libc_posix_fadvise.txt"); // Cleanup before test remove_file(&path).ok(); @@ -40,6 +40,37 @@ fn test_posix_fadvise() { assert_eq!(result, 0); } +#[cfg(target_os = "linux")] +fn test_sync_file_range() { + use std::fs::{remove_file, File}; + use std::io::Write; + use std::os::unix::io::AsRawFd; + + let path = tmp().join("miri_test_libc_sync_file_range.txt"); + // Cleanup before test + remove_file(&path).ok(); + + // Write to a file + let mut file = File::create(&path).unwrap(); + let bytes = b"Hello, World!\n"; + file.write(bytes).unwrap(); + + // Test calling sync_file_range on a file. + let result = unsafe { + libc::sync_file_range( + file.as_raw_fd(), + 0, + 0, + libc::SYNC_FILE_RANGE_WAIT_BEFORE + | libc::SYNC_FILE_RANGE_WRITE + | libc::SYNC_FILE_RANGE_WAIT_AFTER, + ) + }; + drop(file); + remove_file(&path).unwrap(); + assert_eq!(result, 0); +} + fn test_mutex_libc_init_recursive() { unsafe { let mut attr: libc::pthread_mutexattr_t = std::mem::zeroed(); @@ -169,6 +200,9 @@ fn main() { #[cfg(target_os = "linux")] test_posix_fadvise(); + #[cfg(target_os = "linux")] + test_sync_file_range(); + test_mutex_libc_init_recursive(); test_mutex_libc_init_normal(); test_mutex_libc_init_errorcheck(); From 0b060c73648169ef6ff261ff323880a240619475 Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 19 May 2020 08:57:31 -0500 Subject: [PATCH 2069/5092] Review comments --- src/shims/foreign_items/posix.rs | 6 ++++-- src/shims/foreign_items/posix/linux.rs | 4 ++-- src/shims/fs.rs | 25 ++++++++++++++++++++++--- tests/run-pass/fs.rs | 21 +++++---------------- 4 files changed, 33 insertions(+), 23 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 6311f0a4a9fc..14d072d8e3c0 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -137,11 +137,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i64(result), dest)?; } "fsync" => { - let result = this.fsync(args[0])?; + let &[fd] = check_arg_count(args)?; + let result = this.fsync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fdatasync" => { - let result = this.fdatasync(args[0])?; + let &[fd] = check_arg_count(args)?; + let result = this.fdatasync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 16d7d059e73b..bc6ae89966d7 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -54,9 +54,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // fadvise is only informational, we can ignore it. this.write_null(dest)?; } - // Linux-only "sync_file_range" => { - let result = this.sync_file_range(args[0], args[1], args[2], args[3])?; + let &[fd, offset, nbytes, flags] = check_arg_count(args)?; + let result = this.sync_file_range(fd, offset, nbytes, flags)?; this.write_scalar(Scalar::from_i32(result), dest)?; } diff --git a/src/shims/fs.rs b/src/shims/fs.rs index b7579f6cb732..ac405138f524 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -378,6 +378,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if this.tcx.sess.target.target.target_os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC")? { + // On macOS, fsync does not wait for the underlying disk to finish writing, while this + // F_FULLFSYNC operation does. The standard library uses F_FULLFSYNC for both + // File::sync_data() and File::sync_all(). + let &[_, _] = check_arg_count(args)?; if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { let result = file.sync_all(); this.try_unwrap_io_result(result.map(|_| 0i32)) @@ -1153,9 +1157,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("sync_file_range")?; let fd = this.read_scalar(fd_op)?.to_i32()?; - let _offset = this.read_scalar(offset_op)?.to_i64()?; - let _nbytes = this.read_scalar(nbytes_op)?.to_i64()?; - let _flags = this.read_scalar(flags_op)?.to_u32()?; + let offset = this.read_scalar(offset_op)?.to_i64()?; + let nbytes = this.read_scalar(nbytes_op)?.to_i64()?; + let flags = this.read_scalar(flags_op)?.to_i32()?; + + if offset < 0 || nbytes < 0 { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + return Ok(-1); + } + let allowed_flags = this.eval_libc_i32("SYNC_FILE_RANGE_WAIT_BEFORE")? + | this.eval_libc_i32("SYNC_FILE_RANGE_WRITE")? + | this.eval_libc_i32("SYNC_FILE_RANGE_WAIT_AFTER")?; + if flags & allowed_flags != flags { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + return Ok(-1); + } + if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { // In the interest of host compatibility, we conservatively ignore // offset, nbytes, and flags, and sync the entire file. diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index df022a7c70d8..d831129dc80f 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -14,8 +14,7 @@ fn main() { test_seek(); test_metadata(); test_file_set_len(); - test_file_sync_all(); - test_file_sync_data(); + test_file_sync(); test_symlink(); test_errors(); test_rename(); @@ -184,24 +183,14 @@ fn test_file_set_len() { remove_file(&path).unwrap(); } -fn test_file_sync_all() { +fn test_file_sync() { let bytes = b"Hello, World!\n"; - let path = prepare_with_content("miri_test_fs_sync_all.txt", bytes); + let path = prepare_with_content("miri_test_fs_sync.txt", bytes); - // Test that we can call sync_all (can't readily test effects of this operation) - let file = File::open(&path).unwrap(); - file.sync_all().unwrap(); - - remove_file(&path).unwrap(); -} - -fn test_file_sync_data() { - let bytes = b"Hello, World!\n"; - let path = prepare_with_content("miri_test_fs_sync_data.txt", bytes); - - // Test that we can call sync_data (can't readily test effects of this operation) + // Test that we can call sync_data and sync_all (can't readily test effects of this operation) let file = File::open(&path).unwrap(); file.sync_data().unwrap(); + file.sync_all().unwrap(); remove_file(&path).unwrap(); } From cc1a2119f68ae05f625e150c15521bc006db60f9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 May 2020 00:00:35 +0200 Subject: [PATCH 2070/5092] adjust for changed allocation strategy --- rust-version | 2 +- tests/run-pass/heap.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index b1b25c4bcab6..7b8f0d43c89e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -84539360498cab3c70a7c9114c0b8106c8e1b06b +672b272077561ca7b5027a8aff9ea2957c7d4c21 diff --git a/tests/run-pass/heap.rs b/tests/run-pass/heap.rs index b533f9164698..44537e74b5a4 100644 --- a/tests/run-pass/heap.rs +++ b/tests/run-pass/heap.rs @@ -14,12 +14,12 @@ fn allocate_reallocate() { // 6 byte heap alloc (__rust_allocate) s.push_str("foobar"); assert_eq!(s.len(), 6); - assert_eq!(s.capacity(), 6); + assert_eq!(s.capacity(), 8); // heap size doubled to 12 (__rust_reallocate) s.push_str("baz"); assert_eq!(s.len(), 9); - assert_eq!(s.capacity(), 12); + assert_eq!(s.capacity(), 16); // heap size reduced to 9 (__rust_reallocate) s.shrink_to_fit(); From 00a4421573fd420990167ec5ea2358cb19928846 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 May 2020 15:43:26 +0200 Subject: [PATCH 2071/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 7b8f0d43c89e..1465f2b175c2 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -672b272077561ca7b5027a8aff9ea2957c7d4c21 +82911b3bba76e73afe2881b732fe6b0edb35d5d3 From 08ddbd6ce024e1bee9a11d61f52dc0e3b753c616 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 May 2020 22:38:06 +0200 Subject: [PATCH 2072/5092] prepare Dlsym system for dynamic symbols on Windows --- src/shims/dlsym.rs | 19 ++++++++++++++----- src/shims/foreign_items/posix.rs | 4 +--- src/shims/foreign_items/windows.rs | 11 ++++++++--- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 3c4a942b596f..1416db346cd0 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -11,12 +11,21 @@ pub enum Dlsym { impl Dlsym { // Returns an error for unsupported symbols, and None if this symbol // should become a NULL pointer (pretend it does not exist). - pub fn from_str(name: &str) -> InterpResult<'static, Option> { + pub fn from_str(name: &[u8], target_os: &str) -> InterpResult<'static, Option> { use self::Dlsym::*; - Ok(match name { - "getentropy" => Some(GetEntropy), - "__pthread_get_minstack" => None, - _ => throw_unsup_format!("unsupported dlsym: {}", name), + let name = String::from_utf8_lossy(name); + Ok(match target_os { + "linux" | "macos" => match &*name { + "getentropy" => Some(GetEntropy), + "__pthread_get_minstack" => None, + _ => throw_unsup_format!("unsupported dlsym: {}", name), + } + "windows" => match &*name { + "SetThreadStackGuarantee" => None, + "AcquireSRWLockExclusive" => None, + _ => throw_unsup_format!("unsupported dlsym: {}", name), + } + os => bug!("dlsym not implemented for target_os {}", os), }) } } diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 951a40293b72..39b00feec194 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -173,9 +173,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.read_scalar(handle)?.not_undef()?; let symbol = this.read_scalar(symbol)?.not_undef()?; let symbol_name = this.memory.read_c_str(symbol)?; - let err = format!("bad c unicode symbol: {:?}", symbol_name); - let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err); - if let Some(dlsym) = Dlsym::from_str(symbol_name)? { + if let Some(dlsym) = Dlsym::from_str(symbol_name, &this.tcx.sess.target.target.target_os)? { let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); this.write_scalar(Scalar::from(ptr), dest)?; } else { diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 7f3cd03cd2d3..a11e3b8aa6a0 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -260,9 +260,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "GetProcAddress" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] - let &[_hModule, _lpProcName] = check_arg_count(args)?; - // Pretend this does not exist / nothing happened, by returning zero. - this.write_null(dest)?; + let &[_hModule, lpProcName] = check_arg_count(args)?; + let name = this.memory.read_c_str(this.read_scalar(lpProcName)?.not_undef()?)?; + if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.target.target_os)? { + let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); + this.write_scalar(Scalar::from(ptr), dest)?; + } else { + this.write_null(dest)?; + } } "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] From f09decb398f86ebfb7938b5aca39202acb50d45e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 May 2020 23:00:59 +0200 Subject: [PATCH 2073/5092] disentangle macos and linux dlsyms --- src/shims/dlsym.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 1416db346cd0..301687092813 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -15,15 +15,18 @@ impl Dlsym { use self::Dlsym::*; let name = String::from_utf8_lossy(name); Ok(match target_os { - "linux" | "macos" => match &*name { - "getentropy" => Some(GetEntropy), + "linux" => match &*name { "__pthread_get_minstack" => None, - _ => throw_unsup_format!("unsupported dlsym: {}", name), + _ => throw_unsup_format!("unsupported Linux dlsym: {}", name), + } + "macos" => match &*name { + "getentropy" => Some(GetEntropy), + _ => throw_unsup_format!("unsupported macOS dlsym: {}", name), } "windows" => match &*name { "SetThreadStackGuarantee" => None, "AcquireSRWLockExclusive" => None, - _ => throw_unsup_format!("unsupported dlsym: {}", name), + _ => throw_unsup_format!("unsupported Windows dlsym: {}", name), } os => bug!("dlsym not implemented for target_os {}", os), }) From 526fae75413392dcfd05256145c5503011d9c89a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 May 2020 23:06:31 +0200 Subject: [PATCH 2074/5092] GetProcAddress: basic validation for hModule argument --- src/shims/foreign_items/windows.rs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index a11e3b8aa6a0..60448406a67d 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -206,6 +206,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } + // Dynamic symbol loading + "GetProcAddress" => { + #[allow(non_snake_case)] + let &[hModule, lpProcName] = check_arg_count(args)?; + this.read_scalar(hModule)?.not_undef()?; + let name = this.memory.read_c_str(this.read_scalar(lpProcName)?.not_undef()?)?; + if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.target.target_os)? { + let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); + this.write_scalar(Scalar::from(ptr), dest)?; + } else { + this.write_null(dest)?; + } + } + // Miscellaneous "SystemFunction036" => { // The actual name of 'RtlGenRandom' @@ -258,17 +272,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Pretend this does not exist / nothing happened, by returning zero. this.write_null(dest)?; } - "GetProcAddress" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - #[allow(non_snake_case)] - let &[_hModule, lpProcName] = check_arg_count(args)?; - let name = this.memory.read_c_str(this.read_scalar(lpProcName)?.not_undef()?)?; - if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.target.target_os)? { - let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); - this.write_scalar(Scalar::from(ptr), dest)?; - } else { - this.write_null(dest)?; - } - } "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] let &[_hConsoleOutput, _wAttribute] = check_arg_count(args)?; From 402535ef8639b4ba42ad4c1be7ff50542f8104d1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 May 2020 23:24:37 +0200 Subject: [PATCH 2075/5092] also pretend GetSystemTimePreciseAsFileTime does not exist --- src/shims/dlsym.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 301687092813..87c7f447ac03 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -26,6 +26,7 @@ impl Dlsym { "windows" => match &*name { "SetThreadStackGuarantee" => None, "AcquireSRWLockExclusive" => None, + "GetSystemTimePreciseAsFileTime" => None, _ => throw_unsup_format!("unsupported Windows dlsym: {}", name), } os => bug!("dlsym not implemented for target_os {}", os), From 11d9409e82e68876dd292c364d4bfaf66220de36 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 22 May 2020 09:00:32 +0200 Subject: [PATCH 2076/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 1465f2b175c2..0b9281beeb4f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -82911b3bba76e73afe2881b732fe6b0edb35d5d3 +458a3e76294fd859fb037f425404180c91e14767 From 42a3e8783861e82a58a769df8e2e718b38cd25cd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 22 May 2020 10:29:47 +0200 Subject: [PATCH 2077/5092] rustup, and now we also need to install llvm-tools --- .appveyor.yml | 2 +- .travis.yml | 2 +- rust-version | 2 +- rustup-toolchain | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 34887459f6d9..5cb5267a6da5 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -30,7 +30,7 @@ install: - rustup update # Install "master" toolchain. - cargo install rustup-toolchain-install-master -- rustup-toolchain-install-master -f -n master %RUSTC_HASH% -c rust-src -c rustc-dev +- rustup-toolchain-install-master -f -n master %RUSTC_HASH% -c rust-src -c rustc-dev -c llvm-tools - rustup default master - rustc --version - cargo --version diff --git a/.travis.yml b/.travis.yml index 1605737a7b09..fcef17b124dd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,7 +36,7 @@ before_script: - rustup update # Install "master" toolchain. - cargo install rustup-toolchain-install-master -- travis_retry rustup-toolchain-install-master -f -n master $RUSTC_HASH -c rust-src -c rustc-dev +- travis_retry rustup-toolchain-install-master -f -n master $RUSTC_HASH -c rust-src -c rustc-dev -c llvm-tools - rustup default master - rustc --version - cargo --version diff --git a/rust-version b/rust-version index 0b9281beeb4f..a4414470549d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -458a3e76294fd859fb037f425404180c91e14767 +c60b675e280fedded8d8487acd051cd342e486f2 diff --git a/rustup-toolchain b/rustup-toolchain index 4e8e0b01ebc4..3fbebe1565f7 100755 --- a/rustup-toolchain +++ b/rustup-toolchain @@ -39,7 +39,7 @@ fi # Install and setup new toolchain. rustup toolchain uninstall miri -rustup-toolchain-install-master -n miri -c rust-src -c rustc-dev -- "$NEW_COMMIT" +rustup-toolchain-install-master -n miri -c rust-src -c rustc-dev -c llvm-tools -- "$NEW_COMMIT" rustup override set miri # Cleanup. From fbb8c1526ae55f479bdfaf7c00341cb4d36ad597 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 22 May 2020 11:56:18 +0200 Subject: [PATCH 2078/5092] verify the size of all shim arguments --- src/shims/foreign_items/posix.rs | 8 ++++---- src/shims/foreign_items/posix/macos.rs | 4 ++-- src/shims/foreign_items/windows.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 39b00feec194..09191011a4a8 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -170,7 +170,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamic symbol loading "dlsym" => { let &[handle, symbol] = check_arg_count(args)?; - this.read_scalar(handle)?.not_undef()?; + this.read_scalar(handle)?.to_machine_usize(this)?; let symbol = this.read_scalar(symbol)?.not_undef()?; let symbol_name = this.memory.read_c_str(symbol)?; if let Some(dlsym) = Dlsym::from_str(symbol_name, &this.tcx.sess.target.target.target_os)? { @@ -369,9 +369,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "pthread_atfork" => { let &[prepare, parent, child] = check_arg_count(args)?; - this.read_scalar(prepare)?.not_undef()?; - this.read_scalar(parent)?.not_undef()?; - this.read_scalar(child)?.not_undef()?; + this.force_bits(this.read_scalar(prepare)?.not_undef()?, this.memory.pointer_size())?; + this.force_bits(this.read_scalar(parent)?.not_undef()?, this.memory.pointer_size())?; + this.force_bits(this.read_scalar(child)?.not_undef()?, this.memory.pointer_size())?; // We do not support forking, so there is nothing to do here. this.write_null(dest)?; } diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 1cfecbc93461..e6d39af45395 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -105,13 +105,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_get_stackaddr_np" => { let &[thread] = check_arg_count(args)?; - this.read_scalar(thread)?.not_undef()?; + this.read_scalar(thread)?.to_machine_usize(this)?; let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size()); this.write_scalar(stack_addr, dest)?; } "pthread_get_stacksize_np" => { let &[thread] = check_arg_count(args)?; - this.read_scalar(thread)?.not_undef()?; + this.read_scalar(thread)?.to_machine_usize(this)?; let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size()); this.write_scalar(stack_size, dest)?; } diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 60448406a67d..c24824153ca2 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -210,7 +210,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "GetProcAddress" => { #[allow(non_snake_case)] let &[hModule, lpProcName] = check_arg_count(args)?; - this.read_scalar(hModule)?.not_undef()?; + this.read_scalar(hModule)?.to_machine_isize(this)?; let name = this.memory.read_c_str(this.read_scalar(lpProcName)?.not_undef()?)?; if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.target.target_os)? { let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); From 87a846f2d672547fa86508120584f494c05f0de6 Mon Sep 17 00:00:00 2001 From: David Cook Date: Thu, 14 May 2020 08:03:49 -0500 Subject: [PATCH 2079/5092] Update to match rustc changes --- src/diagnostics.rs | 18 +++++++++++------- tests/compile-fail/uninit_buffer.rs | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 8296f71773c2..2d8b1248dcf4 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -118,13 +118,17 @@ pub fn report_error<'tcx, 'mir>( report_msg(ecx, &format!("{}: {}", title, msg), msg, helps, true); // Extra output to help debug specific issues. - if let UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some(ptr))) = e.kind { - eprintln!( - "Uninitialized read occurred at offset 0x{:x} into this allocation:", - ptr.offset.bytes(), - ); - ecx.memory.dump_alloc(ptr.alloc_id); - eprintln!(); + match e.kind { + UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some(access))) => { + eprintln!( + "Uninitialized read occurred at offsets 0x{:x}..0x{:x} into this allocation:", + access.uninit_ptr.offset.bytes(), + access.uninit_ptr.offset.bytes() + access.uninit_size.bytes(), + ); + ecx.memory.dump_alloc(access.uninit_ptr.alloc_id); + eprintln!(); + } + _ => {} } None diff --git a/tests/compile-fail/uninit_buffer.rs b/tests/compile-fail/uninit_buffer.rs index dac02a8690e9..351181016e4b 100644 --- a/tests/compile-fail/uninit_buffer.rs +++ b/tests/compile-fail/uninit_buffer.rs @@ -1,4 +1,4 @@ -// error-pattern: reading uninitialized memory +// error-pattern: 12 bytes are uninitialized use std::alloc::{alloc, dealloc, Layout}; use std::slice::from_raw_parts; From 58bc2185e13adc3875b7d9f15d5660858bc194e9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 22 May 2020 17:03:37 +0200 Subject: [PATCH 2080/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index a4414470549d..adf285ab17ba 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c60b675e280fedded8d8487acd051cd342e486f2 +a9ca1ec9280ca1e5020edd699917c3367a30a798 From 404c37999be2b0f5a8769870f985fd6677ee3905 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 May 2020 16:30:50 +0200 Subject: [PATCH 2081/5092] test discriminant_value intrinsic --- tests/run-pass/intrinsics.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/run-pass/intrinsics.rs b/tests/run-pass/intrinsics.rs index 63439c996af0..ffa7f080aa4e 100644 --- a/tests/run-pass/intrinsics.rs +++ b/tests/run-pass/intrinsics.rs @@ -25,4 +25,9 @@ fn main() { assert_eq!(intrinsics::unlikely(true), true); unsafe { intrinsics::forget(Bomb); } + + let _v = intrinsics::discriminant_value(&Some(())); + let _v = intrinsics::discriminant_value(&0); + let _v = intrinsics::discriminant_value(&true); + let _v = intrinsics::discriminant_value(&vec![1,2,3]); } From e6ced2f9c45ee73f092d36035e4ba70300ca5516 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 May 2020 11:58:19 +0200 Subject: [PATCH 2082/5092] add interesting unsizing test --- tests/run-pass/dyn-lcsit.rs | 68 +++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 tests/run-pass/dyn-lcsit.rs diff --git a/tests/run-pass/dyn-lcsit.rs b/tests/run-pass/dyn-lcsit.rs new file mode 100644 index 000000000000..fa11e9a2a318 --- /dev/null +++ b/tests/run-pass/dyn-lcsit.rs @@ -0,0 +1,68 @@ +// Taken from the rustc test suite; this triggers an interesting case in unsizing. + +#![allow(non_upper_case_globals, incomplete_features)] +#![feature(associated_type_bounds)] +#![feature(impl_trait_in_bindings)] + +use std::ops::Add; + +trait Tr1 { type As1; fn mk(&self) -> Self::As1; } +trait Tr2<'a> { fn tr2(self) -> &'a Self; } + +fn assert_copy(x: T) { let _x = x; let _x = x; } +fn assert_static(_: T) {} +fn assert_forall_tr2 Tr2<'a>>(_: T) {} + +#[derive(Copy, Clone)] +struct S1; +#[derive(Copy, Clone)] +struct S2; +impl Tr1 for S1 { type As1 = S2; fn mk(&self) -> Self::As1 { S2 } } + +const cdef_et1: &dyn Tr1 = &S1; +const sdef_et1: &dyn Tr1 = &S1; +pub fn use_et1() { assert_copy(cdef_et1.mk()); assert_copy(sdef_et1.mk()); } + +const cdef_et2: &(dyn Tr1 + Sync) = &S1; +static sdef_et2: &(dyn Tr1 + Sync) = &S1; +pub fn use_et2() { assert_static(cdef_et2.mk()); assert_static(sdef_et2.mk()); } + +const cdef_et3: &dyn Tr1>>> = { + struct A; + impl Tr1 for A { + type As1 = core::ops::Range; + fn mk(&self) -> Self::As1 { 0..10 } + }; + &A +}; +pub fn use_et3() { + let _0 = cdef_et3.mk().clone(); + let mut s = 0u8; + for _1 in _0 { + let _2 = _1 + 1u8; + s += _2.into(); + } + assert_eq!(s, (0..10).map(|x| x + 1).sum()); +} + +const cdef_et4: &(dyn Tr1 Tr2<'a>> + Sync) = { + #[derive(Copy, Clone)] + struct A; + impl Tr1 for A { + type As1 = A; + fn mk(&self) -> A { A } + } + impl<'a> Tr2<'a> for A { + fn tr2(self) -> &'a Self { &A } + } + &A +}; +static sdef_et4: &(dyn Tr1 Tr2<'a>> + Sync) = cdef_et4; +pub fn use_et4() { assert_forall_tr2(cdef_et4.mk()); assert_forall_tr2(sdef_et4.mk()); } + +fn main() { + let _ = use_et1(); + let _ = use_et2(); + let _ = use_et3(); + let _ = use_et4(); +} From 7a3ccb1b5711eb6ed563953e988652fbacc7f312 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 May 2020 14:00:32 +0200 Subject: [PATCH 2083/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index adf285ab17ba..4275de5f8cbb 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a9ca1ec9280ca1e5020edd699917c3367a30a798 +7726070fa755f660b5da3f82f46e07d9c6866f69 From cf7d88fd91046f1f851a3d0687188d9cd283a162 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 22 May 2020 10:12:32 +0200 Subject: [PATCH 2084/5092] unset RUSTC_WRAPPER for xargo invocation --- src/bin/cargo-miri.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 12f59c05b0a9..2e2d4ce956b1 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -335,7 +335,6 @@ path = "lib.rs" command.current_dir(&dir); command.env("XARGO_HOME", &dir); command.env("XARGO_RUST_SRC", &rust_src); - command.env_remove("RUSTFLAGS"); // Make sure external `RUSTFLAGS` do not influence the build. // Use Miri as rustc to build a libstd compatible with us (and use the right flags). // However, when we are running in bootstrap, we cannot just overwrite `RUSTC`, // because we still need bootstrap to distinguish between host and target crates. @@ -347,6 +346,12 @@ path = "lib.rs" command.env("RUSTC", find_miri()); } command.env("MIRI_BE_RUSTC", "1"); + // Make sure there are no other wrappers or flags getting in our way + // (Cc https://github.com/rust-lang/miri/issues/1421). + // This is consistent with normal `cargo build` that does not apply `RUSTFLAGS` + // to the sysroot either. + command.env_remove("RUSTC_WRAPPER"); + command.env_remove("RUSTFLAGS"); // Finally run it! if command.status().expect("failed to run xargo").success().not() { show_error(format!("Failed to run xargo")); @@ -446,6 +451,9 @@ fn in_cargo_miri() { // Set `RUSTC_WRAPPER` to ourselves. Cargo will prepend that binary to its usual invocation, // i.e., the first argument is `rustc` -- which is what we use in `main` to distinguish // the two codepaths. (That extra argument is why we prefer this over setting `RUSTC`.) + if env::var_os("RUSTC_WRAPPER").is_some() { + println!("WARNING: Ignoring existing `RUSTC_WRAPPER` environment variable, Miri does not support wrapping."); + } let path = std::env::current_exe().expect("current executable path invalid"); cmd.env("RUSTC_WRAPPER", path); if verbose { From 2c94ad08d8cbd065a3673cee5d894963c33236c0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 May 2020 19:20:44 +0200 Subject: [PATCH 2085/5092] use helper method to compute size of int type --- src/lib.rs | 1 + src/shims/intrinsics.rs | 16 +++++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e8cf507d35a0..0ea0d57caccc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ #![allow(incomplete_features)] #![feature(const_generics)] +extern crate rustc_attr; extern crate rustc_apfloat; extern crate rustc_ast; #[macro_use] extern crate rustc_middle; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 08087b0350d9..1a8c9163211a 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -1,10 +1,12 @@ use std::iter; use std::convert::TryFrom; +use rustc_attr as attr; use rustc_ast::ast::FloatTy; use rustc_middle::{mir, ty}; +use rustc_middle::ty::layout::IntegerExt; use rustc_apfloat::{Float, Round}; -use rustc_target::abi::{Align, LayoutOf, Size}; +use rustc_target::abi::{Align, Integer, LayoutOf}; use crate::*; use helpers::check_arg_count; @@ -563,11 +565,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(match dest_ty.kind { // Unsigned ty::Uint(t) => { - let width = t.bit_width().unwrap_or_else(|| this.pointer_size().bits()); - let res = f.to_u128(usize::try_from(width).unwrap()); + let size = Integer::from_attr(this, attr::IntType::UnsignedInt(t)).size(); + let res = f.to_u128(size.bits_usize()); if res.status.is_empty() { // No status flags means there was no further rounding or other loss of precision. - Scalar::from_uint(res.value, Size::from_bits(width)) + Scalar::from_uint(res.value, size) } else { // `f` was not representable in this integer type. throw_ub_format!( @@ -578,11 +580,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Signed ty::Int(t) => { - let width = t.bit_width().unwrap_or_else(|| this.pointer_size().bits()); - let res = f.to_i128(usize::try_from(width).unwrap()); + let size = Integer::from_attr(this, attr::IntType::SignedInt(t)).size(); + let res = f.to_i128(size.bits_usize()); if res.status.is_empty() { // No status flags means there was no further rounding or other loss of precision. - Scalar::from_int(res.value, Size::from_bits(width)) + Scalar::from_int(res.value, size) } else { // `f` was not representable in this integer type. throw_ub_format!( From 679245769b6984ec5a7edf70fb4744d8411468b8 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Tue, 21 Apr 2020 16:38:14 -0700 Subject: [PATCH 2086/5092] Implement support for synchronization primitives. --- src/eval.rs | 6 + src/lib.rs | 6 +- src/machine.rs | 8 +- src/shims/foreign_items/posix.rs | 48 +- src/shims/sync.rs | 674 +++++++++++------- src/sync.rs | 299 ++++++++ src/thread.rs | 151 +++- tests/run-pass/concurrency/barrier.rs | 27 + tests/run-pass/concurrency/barrier.stderr | 2 + tests/run-pass/concurrency/barrier.stdout | 20 + tests/run-pass/concurrency/condvar.rs | 28 + tests/run-pass/concurrency/condvar.stderr | 2 + .../run-pass/concurrency/libc_pthread_cond.rs | 199 ++++++ .../concurrency/libc_pthread_cond.stderr | 2 + tests/run-pass/concurrency/mpsc.rs | 56 ++ tests/run-pass/concurrency/mpsc.stderr | 2 + tests/run-pass/concurrency/once.rs | 44 ++ tests/run-pass/concurrency/once.stderr | 2 + 18 files changed, 1290 insertions(+), 286 deletions(-) create mode 100644 src/sync.rs create mode 100644 tests/run-pass/concurrency/barrier.rs create mode 100644 tests/run-pass/concurrency/barrier.stderr create mode 100644 tests/run-pass/concurrency/barrier.stdout create mode 100644 tests/run-pass/concurrency/condvar.rs create mode 100644 tests/run-pass/concurrency/condvar.stderr create mode 100644 tests/run-pass/concurrency/libc_pthread_cond.rs create mode 100644 tests/run-pass/concurrency/libc_pthread_cond.stderr create mode 100644 tests/run-pass/concurrency/mpsc.rs create mode 100644 tests/run-pass/concurrency/mpsc.stderr create mode 100644 tests/run-pass/concurrency/once.rs create mode 100644 tests/run-pass/concurrency/once.stderr diff --git a/src/eval.rs b/src/eval.rs index 5daad7cc068b..30901a8f127f 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -210,6 +210,12 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> SchedulingAction::ExecuteStep => { assert!(ecx.step()?, "a terminated thread was scheduled for execution"); } + SchedulingAction::ExecuteCallback => { + assert!(ecx.machine.communicate, + "scheduler callbacks require disabled isolation, but the code \ + that created the callback did not check it"); + ecx.run_scheduler_callback()?; + } SchedulingAction::ExecuteDtors => { // This will either enable the thread again (so we go back // to `ExecuteStep`), or determine that this thread is done diff --git a/src/lib.rs b/src/lib.rs index 0ea0d57caccc..e79fc2add39e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,6 +31,7 @@ mod operator; mod range_map; mod shims; mod stacked_borrows; +mod sync; mod thread; // Make all those symbols available in the same place as our own. @@ -45,7 +46,7 @@ pub use crate::shims::fs::{DirHandler, EvalContextExt as FileEvalContextExt, Fil pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::shims::os_str::EvalContextExt as OsStrEvalContextExt; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as PanicEvalContextExt}; -pub use crate::shims::sync::{EvalContextExt as SyncEvalContextExt}; +pub use crate::shims::sync::{EvalContextExt as SyncShimsEvalContextExt}; pub use crate::shims::thread::EvalContextExt as ThreadShimsEvalContextExt; pub use crate::shims::time::EvalContextExt as TimeEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; @@ -70,6 +71,9 @@ pub use crate::stacked_borrows::{ pub use crate::thread::{ EvalContextExt as ThreadsEvalContextExt, SchedulingAction, ThreadId, ThreadManager, ThreadState, }; +pub use crate::sync::{ + EvalContextExt as SyncEvalContextExt, CondvarId, MutexId, RwLockId +}; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. diff --git a/src/machine.rs b/src/machine.rs index 51aa7ae31047..4fb08cd259b6 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -5,7 +5,7 @@ use std::borrow::Cow; use std::cell::RefCell; use std::num::NonZeroU64; use std::rc::Rc; -use std::time::Instant; +use std::time::{Instant, SystemTime}; use std::fmt; use log::trace; @@ -251,6 +251,11 @@ pub struct Evaluator<'mir, 'tcx> { /// The "time anchor" for this machine's monotone clock (for `Instant` simulation). pub(crate) time_anchor: Instant, + /// The approximate system time when "time anchor" was created. This is used + /// for converting system time to monotone time so that we can simplify the + /// thread scheduler to deal only with a single representation of time. + pub(crate) time_anchor_timestamp: SystemTime, + /// The set of threads. pub(crate) threads: ThreadManager<'mir, 'tcx>, @@ -281,6 +286,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { dir_handler: Default::default(), panic_payload: None, time_anchor: Instant::now(), + time_anchor_timestamp: SystemTime::now(), layouts, threads: ThreadManager::default(), } diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 09191011a4a8..352e38113abb 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -330,6 +330,45 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.pthread_rwlock_destroy(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "pthread_condattr_init" => { + let result = this.pthread_condattr_init(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_condattr_setclock" => { + let result = this.pthread_condattr_setclock(args[0], args[1])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_condattr_getclock" => { + let result = this.pthread_condattr_getclock(args[0], args[1])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_condattr_destroy" => { + let result = this.pthread_condattr_destroy(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_cond_init" => { + let result = this.pthread_cond_init(args[0], args[1])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_cond_signal" => { + let result = this.pthread_cond_signal(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_cond_broadcast" => { + let result = this.pthread_cond_broadcast(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_cond_wait" => { + let result = this.pthread_cond_wait(args[0], args[1])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_cond_timedwait" => { + this.pthread_cond_timedwait(args[0], args[1], args[2], dest)?; + } + "pthread_cond_destroy" => { + let result = this.pthread_cond_destroy(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } // Threading "pthread_create" => { @@ -391,16 +430,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "pthread_attr_init" | "pthread_attr_destroy" - | "pthread_condattr_init" - | "pthread_condattr_destroy" - | "pthread_cond_destroy" - if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - let &[_] = check_arg_count(args)?; - this.write_null(dest)?; - } - | "pthread_cond_init" | "pthread_attr_setstacksize" - | "pthread_condattr_setclock" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { let &[_, _] = check_arg_count(args)?; this.write_null(dest)?; diff --git a/src/shims/sync.rs b/src/shims/sync.rs index c205c5c8dddb..dfd7999457eb 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -1,8 +1,10 @@ +use std::time::{Duration, SystemTime}; + use rustc_middle::ty::{layout::TyAndLayout, TyKind, TypeAndMut}; use rustc_target::abi::{LayoutOf, Size}; use crate::stacked_borrows::Tag; -use crate::thread::BlockSetId; + use crate::*; fn assert_ptr_target_min_size<'mir, 'tcx: 'mir>( @@ -76,45 +78,12 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( // Our chosen memory layout for the emulated mutex (does not have to match the platform layout!): // bytes 0-3: reserved for signature on macOS // (need to avoid this because it is set by static initializer macros) -// bytes 4-7: count of how many times this mutex has been locked, as a u32 -// bytes 8-11: when count > 0, id of the owner thread as a u32 +// bytes 4-7: mutex id as u32 or 0 if id is not assigned yet. // bytes 12-15 or 16-19 (depending on platform): mutex kind, as an i32 // (the kind has to be at its offset for compatibility with static initializer macros) -// bytes 20-23: when count > 0, id of the blockset in which the blocked threads -// are waiting or 0 if blockset is not yet assigned. const PTHREAD_MUTEX_T_MIN_SIZE: u64 = 24; -fn mutex_get_locked_count<'mir, 'tcx: 'mir>( - ecx: &MiriEvalContext<'mir, 'tcx>, - mutex_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { - get_at_offset(ecx, mutex_op, 4, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) -} - -fn mutex_set_locked_count<'mir, 'tcx: 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, - mutex_op: OpTy<'tcx, Tag>, - locked_count: impl Into>, -) -> InterpResult<'tcx, ()> { - set_at_offset(ecx, mutex_op, 4, locked_count, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) -} - -fn mutex_get_owner<'mir, 'tcx: 'mir>( - ecx: &MiriEvalContext<'mir, 'tcx>, - mutex_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { - get_at_offset(ecx, mutex_op, 8, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) -} - -fn mutex_set_owner<'mir, 'tcx: 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, - mutex_op: OpTy<'tcx, Tag>, - owner: impl Into>, -) -> InterpResult<'tcx, ()> { - set_at_offset(ecx, mutex_op, 8, owner, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) -} - fn mutex_get_kind<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, @@ -132,34 +101,34 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( set_at_offset(ecx, mutex_op, offset, kind, ecx.machine.layouts.i32, PTHREAD_MUTEX_T_MIN_SIZE) } -fn mutex_get_blockset<'mir, 'tcx: 'mir>( +fn mutex_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { - get_at_offset(ecx, mutex_op, 20, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) +) -> InterpResult<'tcx, ScalarMaybeUndef> { + get_at_offset(ecx, mutex_op, 4, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } -fn mutex_set_blockset<'mir, 'tcx: 'mir>( +fn mutex_set_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, - blockset: impl Into>, + id: impl Into>, ) -> InterpResult<'tcx, ()> { - set_at_offset(ecx, mutex_op, 20, blockset, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) + set_at_offset(ecx, mutex_op, 4, id, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } -fn mutex_get_or_create_blockset<'mir, 'tcx: 'mir>( +fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, BlockSetId> { - let blockset = mutex_get_blockset(ecx, mutex_op)?.to_u32()?; - if blockset == 0 { - // 0 is a default value and also not a valid blockset id. Need to - // allocate a new blockset. - let blockset = ecx.create_blockset()?; - mutex_set_blockset(ecx, mutex_op, blockset.to_u32_scalar())?; - Ok(blockset) +) -> InterpResult<'tcx, MutexId> { + let id = mutex_get_id(ecx, mutex_op)?.to_u32()?; + if id == 0 { + // 0 is a default value and also not a valid mutex id. Need to allocate + // a new mutex. + let id = ecx.mutex_create(); + mutex_set_id(ecx, mutex_op, id.to_u32_scalar())?; + Ok(id) } else { - Ok(BlockSetId::new(blockset)) + Ok(id.into()) } } @@ -168,107 +137,162 @@ fn mutex_get_or_create_blockset<'mir, 'tcx: 'mir>( // Our chosen memory layout for the emulated rwlock (does not have to match the platform layout!): // bytes 0-3: reserved for signature on macOS // (need to avoid this because it is set by static initializer macros) -// bytes 4-7: reader count, as a u32 -// bytes 8-11: writer count, as a u32 -// bytes 12-15: when writer or reader count > 0, id of the blockset in which the -// blocked writers are waiting or 0 if blockset is not yet assigned. -// bytes 16-20: when writer count > 0, id of the blockset in which the blocked -// readers are waiting or 0 if blockset is not yet assigned. +// bytes 4-7: rwlock id as u32 or 0 if id is not assigned yet. -const PTHREAD_RWLOCK_T_MIN_SIZE: u64 = 20; +const PTHREAD_RWLOCK_T_MIN_SIZE: u64 = 32; -fn rwlock_get_readers<'mir, 'tcx: 'mir>( +fn rwlock_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { get_at_offset(ecx, rwlock_op, 4, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } -fn rwlock_set_readers<'mir, 'tcx: 'mir>( +fn rwlock_set_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, - readers: impl Into>, + id: impl Into>, ) -> InterpResult<'tcx, ()> { - set_at_offset(ecx, rwlock_op, 4, readers, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) + set_at_offset(ecx, rwlock_op, 4, id, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } -fn rwlock_get_writers<'mir, 'tcx: 'mir>( - ecx: &MiriEvalContext<'mir, 'tcx>, - rwlock_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { - get_at_offset(ecx, rwlock_op, 8, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) -} - -fn rwlock_set_writers<'mir, 'tcx: 'mir>( +fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, - writers: impl Into>, -) -> InterpResult<'tcx, ()> { - set_at_offset(ecx, rwlock_op, 8, writers, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) -} - -fn rwlock_get_writer_blockset<'mir, 'tcx: 'mir>( - ecx: &MiriEvalContext<'mir, 'tcx>, - rwlock_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { - get_at_offset(ecx, rwlock_op, 12, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) -} - -fn rwlock_set_writer_blockset<'mir, 'tcx: 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, - rwlock_op: OpTy<'tcx, Tag>, - blockset: impl Into>, -) -> InterpResult<'tcx, ()> { - set_at_offset(ecx, rwlock_op, 12, blockset, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) -} - -fn rwlock_get_or_create_writer_blockset<'mir, 'tcx: 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, - rwlock_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, BlockSetId> { - let blockset = rwlock_get_writer_blockset(ecx, rwlock_op)?.to_u32()?; - if blockset == 0 { - // 0 is a default value and also not a valid blockset id. Need to - // allocate a new blockset. - let blockset = ecx.create_blockset()?; - rwlock_set_writer_blockset(ecx, rwlock_op, blockset.to_u32_scalar())?; - Ok(blockset) +) -> InterpResult<'tcx, RwLockId> { + let id = rwlock_get_id(ecx, rwlock_op)?.to_u32()?; + if id == 0 { + // 0 is a default value and also not a valid rwlock id. Need to allocate + // a new read-write lock. + let id = ecx.rwlock_create(); + rwlock_set_id(ecx, rwlock_op, id.to_u32_scalar())?; + Ok(id) } else { - Ok(BlockSetId::new(blockset)) + Ok(id.into()) } } -fn rwlock_get_reader_blockset<'mir, 'tcx: 'mir>( +// pthread_condattr_t + +// Our chosen memory layout for emulation (does not have to match the platform layout!): +// store an i32 in the first four bytes equal to the corresponding libc clock id constant +// (e.g. CLOCK_REALTIME). + +const PTHREAD_CONDATTR_T_MIN_SIZE: u64 = 4; + +fn condattr_get_clock_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, - rwlock_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { - get_at_offset(ecx, rwlock_op, 16, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) + attr_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + get_at_offset(ecx, attr_op, 0, ecx.machine.layouts.i32, PTHREAD_CONDATTR_T_MIN_SIZE) } -fn rwlock_set_reader_blockset<'mir, 'tcx: 'mir>( +fn condattr_set_clock_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - rwlock_op: OpTy<'tcx, Tag>, - blockset: impl Into>, + attr_op: OpTy<'tcx, Tag>, + clock_id: impl Into>, ) -> InterpResult<'tcx, ()> { - set_at_offset(ecx, rwlock_op, 16, blockset, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) + set_at_offset(ecx, attr_op, 0, clock_id, ecx.machine.layouts.i32, PTHREAD_CONDATTR_T_MIN_SIZE) } -fn rwlock_get_or_create_reader_blockset<'mir, 'tcx: 'mir>( +// pthread_cond_t + +// Our chosen memory layout for the emulated conditional variable (does not have +// to match the platform layout!): + +// bytes 4-7: the conditional variable id as u32 or 0 if id is not assigned yet. +// bytes 8-11: the clock id constant as i32 + +const PTHREAD_COND_T_MIN_SIZE: u64 = 12; + +fn cond_get_id<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + cond_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + get_at_offset(ecx, cond_op, 4, ecx.machine.layouts.u32, PTHREAD_COND_T_MIN_SIZE) +} + +fn cond_set_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - rwlock_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, BlockSetId> { - let blockset = rwlock_get_reader_blockset(ecx, rwlock_op)?.to_u32()?; - if blockset == 0 { - // 0 is a default value and also not a valid blockset id. Need to - // allocate a new blockset. - let blockset = ecx.create_blockset()?; - rwlock_set_reader_blockset(ecx, rwlock_op, blockset.to_u32_scalar())?; - Ok(blockset) + cond_op: OpTy<'tcx, Tag>, + id: impl Into>, +) -> InterpResult<'tcx, ()> { + set_at_offset(ecx, cond_op, 4, id, ecx.machine.layouts.u32, PTHREAD_COND_T_MIN_SIZE) +} + +fn cond_get_or_create_id<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + cond_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, CondvarId> { + let id = cond_get_id(ecx, cond_op)?.to_u32()?; + if id == 0 { + // 0 is a default value and also not a valid conditional variable id. + // Need to allocate a new id. + let id = ecx.condvar_create(); + cond_set_id(ecx, cond_op, id.to_u32_scalar())?; + Ok(id) } else { - Ok(BlockSetId::new(blockset)) + Ok(id.into()) } } +fn cond_get_clock_id<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + cond_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + get_at_offset(ecx, cond_op, 8, ecx.machine.layouts.i32, PTHREAD_COND_T_MIN_SIZE) +} + +fn cond_set_clock_id<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + cond_op: OpTy<'tcx, Tag>, + clock_id: impl Into>, +) -> InterpResult<'tcx, ()> { + set_at_offset(ecx, cond_op, 8, clock_id, ecx.machine.layouts.i32, PTHREAD_COND_T_MIN_SIZE) +} + +/// Try to reacquire the mutex associated with the condition variable after we were signaled. +fn reacquire_cond_mutex<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + thread: ThreadId, + mutex: MutexId, +) -> InterpResult<'tcx> { + if ecx.mutex_is_locked(mutex) { + ecx.mutex_enqueue(mutex, thread); + } else { + ecx.mutex_lock(mutex, thread); + ecx.unblock_thread(thread)?; + } + Ok(()) +} + +/// Release the mutex associated with the condition variable because we are +/// entering the waiting state. +fn release_cond_mutex<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + active_thread: ThreadId, + mutex: MutexId, +) -> InterpResult<'tcx> { + if let Some((owner_thread, current_locked_count)) = ecx.mutex_unlock(mutex) { + if current_locked_count != 0 { + throw_unsup_format!("awaiting on multiple times acquired lock is not supported"); + } + if owner_thread != active_thread { + throw_ub_format!("awaiting on a mutex owned by a different thread"); + } + if let Some(thread) = ecx.mutex_dequeue(mutex) { + // We have at least one thread waiting on this mutex. Transfer + // ownership to it. + ecx.mutex_lock(mutex, thread); + ecx.unblock_thread(thread)?; + } + } else { + throw_ub_format!("awaiting on unlocked mutex"); + } + ecx.block_thread(active_thread)?; + Ok(()) +} + impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn pthread_mutexattr_init(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { @@ -323,7 +347,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutexattr_get_kind(this, attr_op)?.not_undef()? }; - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(0))?; + let _ = mutex_get_or_create_id(this, mutex_op)?; mutex_set_kind(this, mutex_op, kind)?; Ok(0) @@ -333,21 +357,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; - let locked_count = mutex_get_locked_count(this, mutex_op)?.to_u32()?; + let id = mutex_get_or_create_id(this, mutex_op)?; let active_thread = this.get_active_thread()?; - if locked_count == 0 { - // The mutex is unlocked. Let's lock it. - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(1))?; - mutex_set_owner(this, mutex_op, active_thread.to_u32_scalar())?; - Ok(0) - } else { - // The mutex is locked. Let's check by whom. - let owner_thread: ThreadId = mutex_get_owner(this, mutex_op)?.to_u32()?.into(); + if this.mutex_is_locked(id) { + let owner_thread = this.mutex_get_owner(id); if owner_thread != active_thread { // Block the active thread. - let blockset = mutex_get_or_create_blockset(this, mutex_op)?; - this.block_active_thread(blockset)?; + this.block_thread(active_thread)?; + this.mutex_enqueue(id, active_thread); Ok(0) } else { // Trying to acquire the same mutex again. @@ -356,17 +374,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { this.eval_libc_i32("EDEADLK") } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { - match locked_count.checked_add(1) { - Some(new_count) => { - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(new_count))?; - Ok(0) - } - None => this.eval_libc_i32("EAGAIN"), - } + this.mutex_lock(id, active_thread); + Ok(0) } else { throw_ub_format!("called pthread_mutex_lock on an unsupported type of mutex"); } } + } else { + // The mutex is unlocked. Let's lock it. + this.mutex_lock(id, active_thread); + Ok(0) } } @@ -374,16 +391,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; - let locked_count = mutex_get_locked_count(this, mutex_op)?.to_u32()?; + let id = mutex_get_or_create_id(this, mutex_op)?; let active_thread = this.get_active_thread()?; - if locked_count == 0 { - // The mutex is unlocked. Let's lock it. - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(1))?; - mutex_set_owner(this, mutex_op, active_thread.to_u32_scalar())?; - Ok(0) - } else { - let owner_thread: ThreadId = mutex_get_owner(this, mutex_op)?.to_u32()?.into(); + if this.mutex_is_locked(id) { + let owner_thread = this.mutex_get_owner(id); if owner_thread != active_thread { this.eval_libc_i32("EBUSY") } else { @@ -392,19 +404,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx { this.eval_libc_i32("EBUSY") } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { - match locked_count.checked_add(1) { - Some(new_count) => { - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(new_count))?; - Ok(0) - } - None => this.eval_libc_i32("EAGAIN"), - } + this.mutex_lock(id, active_thread); + Ok(0) } else { throw_ub_format!( "called pthread_mutex_trylock on an unsupported type of mutex" ); } } + } else { + // The mutex is unlocked. Let's lock it. + this.mutex_lock(id, active_thread); + Ok(0) } } @@ -412,21 +423,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; - let locked_count = mutex_get_locked_count(this, mutex_op)?.to_u32()?; - let owner_thread: ThreadId = mutex_get_owner(this, mutex_op)?.to_u32()?.into(); + let id = mutex_get_or_create_id(this, mutex_op)?; - if owner_thread != this.get_active_thread()? { - throw_ub_format!("called pthread_mutex_unlock on a mutex owned by another thread"); - } else if locked_count == 1 { - let blockset = mutex_get_or_create_blockset(this, mutex_op)?; - if let Some(new_owner) = this.unblock_some_thread(blockset)? { - // We have at least one thread waiting on this mutex. Transfer - // ownership to it. - mutex_set_owner(this, mutex_op, new_owner.to_u32_scalar())?; - } else { - // No thread is waiting on this mutex. - mutex_set_owner(this, mutex_op, Scalar::from_u32(0))?; - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(0))?; + if let Some((owner_thread, current_locked_count)) = this.mutex_unlock(id) { + if owner_thread != this.get_active_thread()? { + throw_ub_format!("called pthread_mutex_unlock on a mutex owned by another thread"); + } + if current_locked_count == 0 { + // The mutex is unlocked. + if let Some(thread) = this.mutex_dequeue(id) { + // We have at least one thread waiting on this mutex. Transfer + // ownership to it. + this.mutex_lock(id, thread); + this.unblock_thread(thread)?; + } } Ok(0) } else { @@ -435,16 +445,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { this.eval_libc_i32("EPERM") } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { - match locked_count.checked_sub(1) { - Some(new_count) => { - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(new_count))?; - Ok(0) - } - None => { - // locked_count was already zero - this.eval_libc_i32("EPERM") - } - } + this.eval_libc_i32("EPERM") } else { throw_ub_format!("called pthread_mutex_unlock on an unsupported type of mutex"); } @@ -454,13 +455,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_destroy(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if mutex_get_locked_count(this, mutex_op)?.to_u32()? != 0 { + let id = mutex_get_or_create_id(this, mutex_op)?; + + if this.mutex_is_locked(id) { throw_ub_format!("destroyed a locked mutex"); } - mutex_set_kind(this, mutex_op, ScalarMaybeUninit::Uninit)?; - mutex_set_locked_count(this, mutex_op, ScalarMaybeUninit::Uninit)?; - mutex_set_blockset(this, mutex_op, ScalarMaybeUninit::Uninit)?; + mutex_set_kind(this, mutex_op, ScalarMaybeUndef::Undef)?; + mutex_set_id(this, mutex_op, ScalarMaybeUndef::Undef)?; Ok(0) } @@ -468,121 +470,305 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_rdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; - let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; + let id = rwlock_get_or_create_id(this, rwlock_op)?; + let active_thread = this.get_active_thread()?; - if writers != 0 { - // The lock is locked by a writer. - assert_eq!(writers, 1); - let reader_blockset = rwlock_get_or_create_reader_blockset(this, rwlock_op)?; - this.block_active_thread(reader_blockset)?; + if this.rwlock_is_write_locked(id) { + this.rwlock_enqueue_reader(id, active_thread); + this.block_thread(active_thread)?; Ok(0) } else { - match readers.checked_add(1) { - Some(new_readers) => { - rwlock_set_readers(this, rwlock_op, Scalar::from_u32(new_readers))?; - Ok(0) - } - None => this.eval_libc_i32("EAGAIN"), - } + this.rwlock_reader_add(id, active_thread); + Ok(0) } } fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; - let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; - if writers != 0 { + let id = rwlock_get_or_create_id(this, rwlock_op)?; + let active_thread = this.get_active_thread()?; + + if this.rwlock_is_write_locked(id) { this.eval_libc_i32("EBUSY") } else { - match readers.checked_add(1) { - Some(new_readers) => { - rwlock_set_readers(this, rwlock_op, Scalar::from_u32(new_readers))?; - Ok(0) - } - None => this.eval_libc_i32("EAGAIN"), - } + this.rwlock_reader_add(id, active_thread); + Ok(0) } } fn pthread_rwlock_wrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; - let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; - let writer_blockset = rwlock_get_or_create_writer_blockset(this, rwlock_op)?; - if readers != 0 || writers != 0 { - this.block_active_thread(writer_blockset)?; + let id = rwlock_get_or_create_id(this, rwlock_op)?; + let active_thread = this.get_active_thread()?; + + if this.rwlock_is_locked(id) { + this.block_thread(active_thread)?; + this.rwlock_enqueue_writer(id, active_thread); } else { - rwlock_set_writers(this, rwlock_op, Scalar::from_u32(1))?; + this.rwlock_writer_set(id, active_thread); } + Ok(0) } fn pthread_rwlock_trywrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; - let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; - if readers != 0 || writers != 0 { + let id = rwlock_get_or_create_id(this, rwlock_op)?; + let active_thread = this.get_active_thread()?; + + if this.rwlock_is_locked(id) { this.eval_libc_i32("EBUSY") } else { - rwlock_set_writers(this, rwlock_op, Scalar::from_u32(1))?; + this.rwlock_writer_set(id, active_thread); Ok(0) } } - // FIXME: We should check that this lock was locked by the active thread. fn pthread_rwlock_unlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; - let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; - let writer_blockset = rwlock_get_or_create_writer_blockset(this, rwlock_op)?; - if let Some(new_readers) = readers.checked_sub(1) { - assert_eq!(writers, 0); - rwlock_set_readers(this, rwlock_op, Scalar::from_u32(new_readers))?; - if new_readers == 0 { - if let Some(_writer) = this.unblock_some_thread(writer_blockset)? { - rwlock_set_writers(this, rwlock_op, Scalar::from_u32(1))?; + let id = rwlock_get_or_create_id(this, rwlock_op)?; + let active_thread = this.get_active_thread()?; + + if this.rwlock_reader_remove(id, active_thread) { + // The thread was a reader. + if this.rwlock_is_locked(id) { + // No more readers owning the lock. Give it to a writer if there + // is any. + if let Some(writer) = this.rwlock_dequeue_writer(id) { + this.unblock_thread(writer)?; + this.rwlock_writer_set(id, writer); } } Ok(0) - } else if writers != 0 { - let reader_blockset = rwlock_get_or_create_reader_blockset(this, rwlock_op)?; + } else if Some(active_thread) == this.rwlock_writer_remove(id) { + // The thread was a writer. + // // We are prioritizing writers here against the readers. As a // result, not only readers can starve writers, but also writers can // starve readers. - if let Some(_writer) = this.unblock_some_thread(writer_blockset)? { - assert_eq!(writers, 1); + if let Some(writer) = this.rwlock_dequeue_writer(id) { + // Give the lock to another writer. + this.unblock_thread(writer)?; + this.rwlock_writer_set(id, writer); } else { - rwlock_set_writers(this, rwlock_op, Scalar::from_u32(0))?; - let mut readers = 0; - while let Some(_reader) = this.unblock_some_thread(reader_blockset)? { - readers += 1; + // Give the lock to all readers. + while let Some(reader) = this.rwlock_dequeue_reader(id) { + this.unblock_thread(reader)?; + this.rwlock_reader_add(id, reader); } - rwlock_set_readers(this, rwlock_op, Scalar::from_u32(readers))? } Ok(0) } else { - throw_ub_format!("unlocked an rwlock that was not locked"); + throw_ub_format!("unlocked an rwlock that was not locked by the active thread"); } } fn pthread_rwlock_destroy(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if rwlock_get_readers(this, rwlock_op)?.to_u32()? != 0 - || rwlock_get_writers(this, rwlock_op)?.to_u32()? != 0 - { + let id = rwlock_get_or_create_id(this, rwlock_op)?; + + if this.rwlock_is_locked(id) { throw_ub_format!("destroyed a locked rwlock"); } - rwlock_set_readers(this, rwlock_op, ScalarMaybeUninit::Uninit)?; - rwlock_set_writers(this, rwlock_op, ScalarMaybeUninit::Uninit)?; - rwlock_set_reader_blockset(this, rwlock_op, ScalarMaybeUninit::Uninit)?; - rwlock_set_writer_blockset(this, rwlock_op, ScalarMaybeUninit::Uninit)?; + rwlock_set_id(this, rwlock_op, ScalarMaybeUndef::Undef)?; + + Ok(0) + } + + fn pthread_condattr_init(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + let default_clock_id = this.eval_libc("CLOCK_REALTIME")?; + condattr_set_clock_id(this, attr_op, default_clock_id)?; + + Ok(0) + } + + fn pthread_condattr_setclock( + &mut self, + attr_op: OpTy<'tcx, Tag>, + clock_id_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + let clock_id = this.read_scalar(clock_id_op)?.not_undef()?; + if clock_id == this.eval_libc("CLOCK_REALTIME")? + || clock_id == this.eval_libc("CLOCK_MONOTONIC")? + { + condattr_set_clock_id(this, attr_op, clock_id)?; + } else { + let einval = this.eval_libc_i32("EINVAL")?; + return Ok(einval); + } + + Ok(0) + } + + fn pthread_condattr_getclock( + &mut self, + attr_op: OpTy<'tcx, Tag>, + clk_id_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + let clock_id = condattr_get_clock_id(this, attr_op)?; + this.write_scalar(clock_id, this.deref_operand(clk_id_op)?.into())?; + + Ok(0) + } + + fn pthread_condattr_destroy(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + condattr_set_clock_id(this, attr_op, ScalarMaybeUndef::Undef)?; + + Ok(0) + } + + fn pthread_cond_init( + &mut self, + cond_op: OpTy<'tcx, Tag>, + attr_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + let attr = this.read_scalar(attr_op)?.not_undef()?; + let clock_id = if this.is_null(attr)? { + this.eval_libc("CLOCK_REALTIME")? + } else { + condattr_get_clock_id(this, attr_op)?.not_undef()? + }; + + let _ = cond_get_or_create_id(this, cond_op)?; + cond_set_clock_id(this, cond_op, clock_id)?; + + Ok(0) + } + + fn pthread_cond_signal(&mut self, cond_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + let id = cond_get_or_create_id(this, cond_op)?; + if let Some((thread, mutex)) = this.condvar_signal(id) { + reacquire_cond_mutex(this, thread, mutex)?; + this.unregister_callback_if_exists(thread)?; + } + + Ok(0) + } + + fn pthread_cond_broadcast(&mut self, cond_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + let id = cond_get_or_create_id(this, cond_op)?; + + while let Some((thread, mutex)) = this.condvar_signal(id) { + reacquire_cond_mutex(this, thread, mutex)?; + this.unregister_callback_if_exists(thread)?; + } + + Ok(0) + } + + fn pthread_cond_wait( + &mut self, + cond_op: OpTy<'tcx, Tag>, + mutex_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + let id = cond_get_or_create_id(this, cond_op)?; + let mutex_id = mutex_get_or_create_id(this, mutex_op)?; + let active_thread = this.get_active_thread()?; + + release_cond_mutex(this, active_thread, mutex_id)?; + this.condvar_wait(id, active_thread, mutex_id); + + Ok(0) + } + + fn pthread_cond_timedwait( + &mut self, + cond_op: OpTy<'tcx, Tag>, + mutex_op: OpTy<'tcx, Tag>, + abstime_op: OpTy<'tcx, Tag>, + dest: PlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + this.check_no_isolation("pthread_cond_timedwait")?; + + let id = cond_get_or_create_id(this, cond_op)?; + let mutex_id = mutex_get_or_create_id(this, mutex_op)?; + let active_thread = this.get_active_thread()?; + + release_cond_mutex(this, active_thread, mutex_id)?; + this.condvar_wait(id, active_thread, mutex_id); + + // We return success for now and override it in the timeout callback. + this.write_scalar(Scalar::from_i32(0), dest)?; + + // Extract the timeout. + let clock_id = cond_get_clock_id(this, cond_op)?.to_i32()?; + let duration = { + let tp = this.deref_operand(abstime_op)?; + let mut offset = Size::from_bytes(0); + let layout = this.libc_ty_layout("time_t")?; + let seconds_place = tp.offset(offset, MemPlaceMeta::None, layout, this)?; + let seconds = this.read_scalar(seconds_place.into())?.to_u64()?; + offset += layout.size; + let layout = this.libc_ty_layout("c_long")?; + let nanoseconds_place = tp.offset(offset, MemPlaceMeta::None, layout, this)?; + let nanoseconds = this.read_scalar(nanoseconds_place.into())?.to_u64()?; + Duration::new(seconds, nanoseconds as u32) + }; + + let timeout_time = if clock_id == this.eval_libc_i32("CLOCK_REALTIME")? { + let time_anchor_since_epoch = + this.machine.time_anchor_timestamp.duration_since(SystemTime::UNIX_EPOCH).unwrap(); + let duration_since_time_anchor = duration.checked_sub(time_anchor_since_epoch).unwrap(); + this.machine.time_anchor.checked_add(duration_since_time_anchor).unwrap() + } else if clock_id == this.eval_libc_i32("CLOCK_MONOTONIC")? { + this.machine.time_anchor.checked_add(duration).unwrap() + } else { + throw_ub_format!("Unsupported clock id."); + }; + + // Register the timeout callback. + this.register_callback( + active_thread, + timeout_time, + Box::new(move |ecx| { + // Try to reacquire the mutex. + reacquire_cond_mutex(ecx, active_thread, mutex_id)?; + + // Remove the thread from the conditional variable. + ecx.condvar_remove_waiter(id, active_thread); + + // Set the timeout value. + let timeout = ecx.eval_libc_i32("ETIMEDOUT")?; + ecx.write_scalar(Scalar::from_i32(timeout), dest)?; + + Ok(()) + }), + )?; + + Ok(()) + } + + fn pthread_cond_destroy(&mut self, cond_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + let id = cond_get_or_create_id(this, cond_op)?; + if this.condvar_is_awaited(id) { + throw_ub_format!("destroyed an awaited conditional variable"); + } + cond_set_id(this, cond_op, ScalarMaybeUndef::Undef)?; + cond_set_clock_id(this, cond_op, ScalarMaybeUndef::Undef)?; Ok(0) } diff --git a/src/sync.rs b/src/sync.rs new file mode 100644 index 000000000000..5d181692fb2a --- /dev/null +++ b/src/sync.rs @@ -0,0 +1,299 @@ +use std::collections::{hash_map::Entry, HashMap, VecDeque}; +use std::convert::TryFrom; +use std::num::NonZeroU32; +use std::time::Instant; + +use rustc_index::vec::{Idx, IndexVec}; + +use crate::*; + +macro_rules! declare_id { + ($name: ident) => { + #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] + pub struct $name(NonZeroU32); + + impl Idx for $name { + fn new(idx: usize) -> Self { + $name(NonZeroU32::new(u32::try_from(idx).unwrap() + 1).unwrap()) + } + fn index(self) -> usize { + usize::try_from(self.0.get() - 1).unwrap() + } + } + + impl From for $name { + fn from(id: u32) -> Self { + Self(NonZeroU32::new(id).unwrap()) + } + } + + impl $name { + pub fn to_u32_scalar<'tcx>(&self) -> Scalar { + Scalar::from_u32(self.0.get()) + } + } + }; +} + +declare_id!(MutexId); + +/// The mutex state. +#[derive(Default, Debug)] +struct Mutex { + /// The thread that currently owns the lock. + owner: Option, + /// How many times the mutex was locked by the owner. + lock_count: usize, + /// The queue of threads waiting for this mutex. + queue: VecDeque, +} + +declare_id!(RwLockId); + +/// The read-write lock state. +#[derive(Default, Debug)] +struct RwLock { + /// The writer thread that currently owns the lock. + writer: Option, + /// The readers that currently own the lock and how many times they acquired + /// the lock. + readers: HashMap, + /// The queue of writer threads waiting for this lock. + writer_queue: VecDeque, + /// The queue of reader threads waiting for this lock. + reader_queue: VecDeque, +} + +declare_id!(CondvarId); + +/// A thread waiting on a conditional variable. +#[derive(Debug)] +struct CondvarWaiter { + /// The thread that is waiting on this variable. + thread: ThreadId, + /// The mutex on which the thread is waiting. + mutex: MutexId, + /// The moment in time when the waiter should time out. + timeout: Option, +} + +/// The conditional variable state. +#[derive(Default, Debug)] +struct Condvar { + waiters: VecDeque, +} + +/// The state of all synchronization variables. +#[derive(Default, Debug)] +pub(super) struct SynchronizationState { + mutexes: IndexVec, + rwlocks: IndexVec, + condvars: IndexVec, +} + +// Public interface to synchronization primitives. Please note that in most +// cases, the function calls are infallible and it is the client's (shim +// implementation's) responsibility to detect and deal with erroneous +// situations. +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + #[inline] + /// Create state for a new mutex. + fn mutex_create(&mut self) -> MutexId { + let this = self.eval_context_mut(); + this.machine.threads.sync.mutexes.push(Default::default()) + } + + #[inline] + /// Get the id of the thread that currently owns this lock. + fn mutex_get_owner(&mut self, id: MutexId) -> ThreadId { + let this = self.eval_context_ref(); + this.machine.threads.sync.mutexes[id].owner.unwrap() + } + + #[inline] + /// Check if locked. + fn mutex_is_locked(&mut self, id: MutexId) -> bool { + let this = self.eval_context_mut(); + this.machine.threads.sync.mutexes[id].owner.is_some() + } + + /// Lock by setting the mutex owner and increasing the lock count. + fn mutex_lock(&mut self, id: MutexId, thread: ThreadId) { + let this = self.eval_context_mut(); + let mutex = &mut this.machine.threads.sync.mutexes[id]; + if let Some(current_owner) = mutex.owner { + assert_eq!(thread, current_owner, "mutex already locked by another thread"); + assert!( + mutex.lock_count > 0, + "invariant violation: lock_count == 0 iff the thread is unlocked" + ); + } else { + mutex.owner = Some(thread); + } + mutex.lock_count = mutex.lock_count.checked_add(1).unwrap(); + } + + /// Unlock by decreasing the lock count. If the lock count reaches 0, unset + /// the owner. + fn mutex_unlock(&mut self, id: MutexId) -> Option<(ThreadId, usize)> { + let this = self.eval_context_mut(); + let mutex = &mut this.machine.threads.sync.mutexes[id]; + if let Some(current_owner) = mutex.owner { + mutex.lock_count = mutex + .lock_count + .checked_sub(1) + .expect("invariant violation: lock_count == 0 iff the thread is unlocked"); + if mutex.lock_count == 0 { + mutex.owner = None; + } + Some((current_owner, mutex.lock_count)) + } else { + None + } + } + + #[inline] + /// Take a thread out the queue waiting for the lock. + fn mutex_enqueue(&mut self, id: MutexId, thread: ThreadId) { + let this = self.eval_context_mut(); + this.machine.threads.sync.mutexes[id].queue.push_back(thread); + } + + #[inline] + /// Take a thread out the queue waiting for the lock. + fn mutex_dequeue(&mut self, id: MutexId) -> Option { + let this = self.eval_context_mut(); + this.machine.threads.sync.mutexes[id].queue.pop_front() + } + + #[inline] + /// Create state for a new read write lock. + fn rwlock_create(&mut self) -> RwLockId { + let this = self.eval_context_mut(); + this.machine.threads.sync.rwlocks.push(Default::default()) + } + + #[inline] + /// Check if locked. + fn rwlock_is_locked(&mut self, id: RwLockId) -> bool { + let this = self.eval_context_mut(); + this.machine.threads.sync.rwlocks[id].writer.is_some() + || !this.machine.threads.sync.rwlocks[id].readers.is_empty() + } + + #[inline] + /// Check if write locked. + fn rwlock_is_write_locked(&mut self, id: RwLockId) -> bool { + let this = self.eval_context_mut(); + this.machine.threads.sync.rwlocks[id].writer.is_some() + } + + /// Add a reader that collectively with other readers owns the lock. + fn rwlock_reader_add(&mut self, id: RwLockId, reader: ThreadId) { + let this = self.eval_context_mut(); + assert!(!this.rwlock_is_write_locked(id), "the lock is write locked"); + let count = this.machine.threads.sync.rwlocks[id].readers.entry(reader).or_insert(0); + *count += 1; + } + + /// Try removing the reader. Returns `true` if succeeded. + fn rwlock_reader_remove(&mut self, id: RwLockId, reader: ThreadId) -> bool { + let this = self.eval_context_mut(); + match this.machine.threads.sync.rwlocks[id].readers.entry(reader) { + Entry::Occupied(mut entry) => { + let count = entry.get_mut(); + *count -= 1; + if *count == 0 { + entry.remove(); + } + true + } + Entry::Vacant(_) => false, + } + } + + #[inline] + /// Put the reader in the queue waiting for the lock. + fn rwlock_enqueue_reader(&mut self, id: RwLockId, reader: ThreadId) { + let this = self.eval_context_mut(); + assert!(this.rwlock_is_write_locked(id), "queueing on not write locked lock"); + this.machine.threads.sync.rwlocks[id].reader_queue.push_back(reader); + } + + #[inline] + /// Take the reader out the queue waiting for the lock. + fn rwlock_dequeue_reader(&mut self, id: RwLockId) -> Option { + let this = self.eval_context_mut(); + this.machine.threads.sync.rwlocks[id].reader_queue.pop_front() + } + + #[inline] + /// Lock by setting the writer that owns the lock. + fn rwlock_writer_set(&mut self, id: RwLockId, writer: ThreadId) { + let this = self.eval_context_mut(); + assert!(!this.rwlock_is_locked(id), "the lock is already locked"); + this.machine.threads.sync.rwlocks[id].writer = Some(writer); + } + + #[inline] + /// Try removing the writer. + fn rwlock_writer_remove(&mut self, id: RwLockId) -> Option { + let this = self.eval_context_mut(); + this.machine.threads.sync.rwlocks[id].writer.take() + } + + #[inline] + /// Put the writer in the queue waiting for the lock. + fn rwlock_enqueue_writer(&mut self, id: RwLockId, writer: ThreadId) { + let this = self.eval_context_mut(); + assert!(this.rwlock_is_locked(id), "queueing on unlocked lock"); + this.machine.threads.sync.rwlocks[id].writer_queue.push_back(writer); + } + + #[inline] + /// Take the writer out the queue waiting for the lock. + fn rwlock_dequeue_writer(&mut self, id: RwLockId) -> Option { + let this = self.eval_context_mut(); + this.machine.threads.sync.rwlocks[id].writer_queue.pop_front() + } + + #[inline] + /// Create state for a new conditional variable. + fn condvar_create(&mut self) -> CondvarId { + let this = self.eval_context_mut(); + this.machine.threads.sync.condvars.push(Default::default()) + } + + #[inline] + /// Is the conditional variable awaited? + fn condvar_is_awaited(&mut self, id: CondvarId) -> bool { + let this = self.eval_context_mut(); + !this.machine.threads.sync.condvars[id].waiters.is_empty() + } + + /// Mark that the thread is waiting on the conditional variable. + fn condvar_wait(&mut self, id: CondvarId, thread: ThreadId, mutex: MutexId) { + let this = self.eval_context_mut(); + let waiters = &mut this.machine.threads.sync.condvars[id].waiters; + assert!(waiters.iter().all(|waiter| waiter.thread != thread), "thread is already waiting"); + waiters.push_back(CondvarWaiter { thread, mutex, timeout: None }); + } + + /// Wake up some thread (if there is any) sleeping on the conditional + /// variable. + fn condvar_signal(&mut self, id: CondvarId) -> Option<(ThreadId, MutexId)> { + let this = self.eval_context_mut(); + this.machine.threads.sync.condvars[id] + .waiters + .pop_front() + .map(|waiter| (waiter.thread, waiter.mutex)) + } + + #[inline] + /// Remove the thread from the queue of threads waiting on this conditional variable. + fn condvar_remove_waiter(&mut self, id: CondvarId, thread: ThreadId) { + let this = self.eval_context_mut(); + this.machine.threads.sync.condvars[id].waiters.retain(|waiter| waiter.thread != thread); + } +} diff --git a/src/thread.rs b/src/thread.rs index d78beed28cfb..6ebf35a6527f 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -1,8 +1,10 @@ //! Implements threads. use std::cell::RefCell; +use std::collections::hash_map::Entry; use std::convert::TryFrom; use std::num::{NonZeroU32, TryFromIntError}; +use std::time::Instant; use log::trace; @@ -15,18 +17,24 @@ use rustc_middle::{ ty::{self, Instance}, }; +use crate::sync::SynchronizationState; use crate::*; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum SchedulingAction { /// Execute step on the active thread. ExecuteStep, + /// Execute a scheduler's callback. + ExecuteCallback, /// Execute destructors of the active thread. ExecuteDtors, /// Stop the program. Stop, } +type EventCallback<'mir, 'tcx> = + Box>) -> InterpResult<'tcx> + 'tcx>; + /// A thread identifier. #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] pub struct ThreadId(u32); @@ -94,6 +102,7 @@ pub enum ThreadState { BlockedOnJoin(ThreadId), /// The thread is blocked and belongs to the given blockset. Blocked(BlockSetId), + BlockedThread, /// The thread has terminated its execution (we do not delete terminated /// threads). Terminated, @@ -162,6 +171,23 @@ impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> { } } +/// Callbacks are used to implement timeouts. For example, waiting on a +/// conditional variable with a timeout creates a callback that is called after +/// the specified time and unblocks the thread. If another thread signals on the +/// conditional variable, the signal handler deletes the callback. +struct CallBackInfo<'mir, 'tcx> { + /// The callback should be called no earlier than this time. + call_time: Instant, + /// The called function. + callback: EventCallback<'mir, 'tcx>, +} + +impl<'mir, 'tcx> std::fmt::Debug for CallBackInfo<'mir, 'tcx> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "CallBack({:?})", self.call_time) + } +} + /// A set of threads. #[derive(Debug)] pub struct ThreadManager<'mir, 'tcx> { @@ -171,6 +197,8 @@ pub struct ThreadManager<'mir, 'tcx> { /// /// Note that this vector also contains terminated threads. threads: IndexVec>, + /// FIXME: make private. + pub(crate) sync: SynchronizationState, /// A counter used to generate unique identifiers for blocksets. blockset_counter: u32, /// A mapping from a thread-local static to an allocation id of a thread @@ -178,6 +206,8 @@ pub struct ThreadManager<'mir, 'tcx> { thread_local_alloc_ids: RefCell>, /// A flag that indicates that we should change the active thread. yield_active_thread: bool, + /// Callbacks that are called once the specified time passes. + callbacks: FxHashMap>, } impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { @@ -191,9 +221,11 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { Self { active_thread: ThreadId::new(0), threads: threads, + sync: SynchronizationState::default(), blockset_counter: 0, thread_local_alloc_ids: Default::default(), yield_active_thread: false, + callbacks: FxHashMap::default(), } } } @@ -321,30 +353,18 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { self.active_thread_ref().thread_name() } - /// Allocate a new blockset id. - fn create_blockset(&mut self) -> BlockSetId { - self.blockset_counter = self.blockset_counter.checked_add(1).unwrap(); - BlockSetId::new(self.blockset_counter) - } - - /// Block the currently active thread and put it into the given blockset. - fn block_active_thread(&mut self, set: BlockSetId) { - let state = &mut self.active_thread_mut().state; + /// Put the thread into the blocked state. + fn block_thread(&mut self, thread: ThreadId) { + let state = &mut self.threads[thread].state; assert_eq!(*state, ThreadState::Enabled); - *state = ThreadState::Blocked(set); + *state = ThreadState::BlockedThread; } - /// Unblock any one thread from the given blockset if it contains at least - /// one. Return the id of the unblocked thread. - fn unblock_some_thread(&mut self, set: BlockSetId) -> Option { - for (id, thread) in self.threads.iter_enumerated_mut() { - if thread.state == ThreadState::Blocked(set) { - trace!("unblocking {:?} in blockset {:?}", id, set); - thread.state = ThreadState::Enabled; - return Some(id); - } - } - None + /// Put the blocked thread into the enabled state. + fn unblock_thread(&mut self, thread: ThreadId) { + let state = &mut self.threads[thread].state; + assert_eq!(*state, ThreadState::BlockedThread); + *state = ThreadState::Enabled; } /// Change the active thread to some enabled thread. @@ -352,6 +372,39 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { self.yield_active_thread = true; } + /// Register the given `callback` to be called once the `call_time` passes. + fn register_callback( + &mut self, + thread: ThreadId, + call_time: Instant, + callback: EventCallback<'mir, 'tcx>, + ) { + self.callbacks + .insert(thread, CallBackInfo { call_time: call_time, callback: callback }) + .unwrap_none(); + } + + /// Unregister the callback for the `thread`. + fn unregister_callback_if_exists(&mut self, thread: ThreadId) { + self.callbacks.remove(&thread); + } + + /// Get a callback that is ready to be called. + fn get_callback(&mut self) -> Option<(ThreadId, EventCallback<'mir, 'tcx>)> { + let current_time = Instant::now(); + // We use a for loop here to make the scheduler more deterministic. + for thread in self.threads.indices() { + match self.callbacks.entry(thread) { + Entry::Occupied(entry) => + if current_time >= entry.get().call_time { + return Some((thread, entry.remove().callback)); + }, + Entry::Vacant(_) => {} + } + } + None + } + /// Decide which action to take next and on which thread. /// /// The currently implemented scheduling policy is the one that is commonly @@ -407,6 +460,18 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { // We have not found a thread to execute. if self.threads.iter().all(|thread| thread.state == ThreadState::Terminated) { unreachable!(); + } else if let Some(next_call_time) = + self.callbacks.values().min_by_key(|info| info.call_time) + { + // All threads are currently blocked, but we have unexecuted + // callbacks, which may unblock some of the threads. Hence, + // sleep until the first callback. + if let Some(sleep_time) = + next_call_time.call_time.checked_duration_since(Instant::now()) + { + std::thread::sleep(sleep_time); + } + Ok(SchedulingAction::ExecuteCallback) } else { throw_machine_stop!(TerminationInfo::Deadlock); } @@ -577,21 +642,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[inline] - fn create_blockset(&mut self) -> InterpResult<'tcx, BlockSetId> { + fn block_thread(&mut self, thread: ThreadId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - Ok(this.machine.threads.create_blockset()) + Ok(this.machine.threads.block_thread(thread)) } #[inline] - fn block_active_thread(&mut self, set: BlockSetId) -> InterpResult<'tcx> { + fn unblock_thread(&mut self, thread: ThreadId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - Ok(this.machine.threads.block_active_thread(set)) - } - - #[inline] - fn unblock_some_thread(&mut self, set: BlockSetId) -> InterpResult<'tcx, Option> { - let this = self.eval_context_mut(); - Ok(this.machine.threads.unblock_some_thread(set)) + Ok(this.machine.threads.unblock_thread(thread)) } #[inline] @@ -601,6 +660,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } + #[inline] + fn register_callback( + &mut self, + thread: ThreadId, + call_time: Instant, + callback: EventCallback<'mir, 'tcx>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + this.machine.threads.register_callback(thread, call_time, callback); + Ok(()) + } + + #[inline] + fn unregister_callback_if_exists(&mut self, thread: ThreadId) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + this.machine.threads.unregister_callback_if_exists(thread); + Ok(()) + } + + /// Execute the callback on the callback's thread. + #[inline] + fn run_scheduler_callback(&mut self) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let (thread, callback) = this.machine.threads.get_callback().expect("no callback found"); + let old_thread = this.set_active_thread(thread)?; + callback(this)?; + this.set_active_thread(old_thread)?; + Ok(()) + } + /// Decide which action to take next and on which thread. #[inline] fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { diff --git a/tests/run-pass/concurrency/barrier.rs b/tests/run-pass/concurrency/barrier.rs new file mode 100644 index 000000000000..1e976a63453d --- /dev/null +++ b/tests/run-pass/concurrency/barrier.rs @@ -0,0 +1,27 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +//! Check if Rust barriers are working. + +use std::sync::{Arc, Barrier}; +use std::thread; + + +/// This test is taken from the Rust documentation. +fn main() { + let mut handles = Vec::with_capacity(10); + let barrier = Arc::new(Barrier::new(10)); + for _ in 0..10 { + let c = barrier.clone(); + // The same messages will be printed together. + // You will NOT see any interleaving. + handles.push(thread::spawn(move|| { + println!("before wait"); + c.wait(); + println!("after wait"); + })); + } + // Wait for other threads to finish. + for handle in handles { + handle.join().unwrap(); + } +} \ No newline at end of file diff --git a/tests/run-pass/concurrency/barrier.stderr b/tests/run-pass/concurrency/barrier.stderr new file mode 100644 index 000000000000..2dbfb7721d36 --- /dev/null +++ b/tests/run-pass/concurrency/barrier.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental. For example, Miri does not detect data races yet. + diff --git a/tests/run-pass/concurrency/barrier.stdout b/tests/run-pass/concurrency/barrier.stdout new file mode 100644 index 000000000000..f2c036a1735e --- /dev/null +++ b/tests/run-pass/concurrency/barrier.stdout @@ -0,0 +1,20 @@ +before wait +before wait +before wait +before wait +before wait +before wait +before wait +before wait +before wait +before wait +after wait +after wait +after wait +after wait +after wait +after wait +after wait +after wait +after wait +after wait diff --git a/tests/run-pass/concurrency/condvar.rs b/tests/run-pass/concurrency/condvar.rs new file mode 100644 index 000000000000..ab971ee6e8c6 --- /dev/null +++ b/tests/run-pass/concurrency/condvar.rs @@ -0,0 +1,28 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +//! Check if Rust conditional variables are working. + +use std::sync::{Arc, Condvar, Mutex}; +use std::thread; + +/// The test taken from the Rust documentation. +fn main() { + let pair = Arc::new((Mutex::new(false), Condvar::new())); + let pair2 = pair.clone(); + + // Inside of our lock, spawn a new thread, and then wait for it to start. + thread::spawn(move || { + let (lock, cvar) = &*pair2; + let mut started = lock.lock().unwrap(); + *started = true; + // We notify the condvar that the value has changed. + cvar.notify_one(); + }); + + // Wait for the thread to start up. + let (lock, cvar) = &*pair; + let mut started = lock.lock().unwrap(); + while !*started { + started = cvar.wait(started).unwrap(); + } +} diff --git a/tests/run-pass/concurrency/condvar.stderr b/tests/run-pass/concurrency/condvar.stderr new file mode 100644 index 000000000000..2dbfb7721d36 --- /dev/null +++ b/tests/run-pass/concurrency/condvar.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental. For example, Miri does not detect data races yet. + diff --git a/tests/run-pass/concurrency/libc_pthread_cond.rs b/tests/run-pass/concurrency/libc_pthread_cond.rs new file mode 100644 index 000000000000..83a651e6f04a --- /dev/null +++ b/tests/run-pass/concurrency/libc_pthread_cond.rs @@ -0,0 +1,199 @@ +// ignore-windows: No libc on Windows +// compile-flags: -Zmiri-disable-isolation + +#![feature(rustc_private)] + +extern crate libc; + +use std::cell::UnsafeCell; +use std::mem::{self, MaybeUninit}; +use std::sync::Arc; +use std::thread; + +struct Mutex { + inner: UnsafeCell, +} + +unsafe impl Sync for Mutex {} + +impl std::fmt::Debug for Mutex { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Mutex") + } +} + +struct Cond { + inner: UnsafeCell, +} + +unsafe impl Sync for Cond {} + +impl std::fmt::Debug for Cond { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Cond") + } +} + +unsafe fn create_cond_attr_monotonic() -> libc::pthread_condattr_t { + let mut attr = MaybeUninit::::uninit(); + assert_eq!(libc::pthread_condattr_init(attr.as_mut_ptr()), 0); + assert_eq!(libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC), 0); + attr.assume_init() +} + +unsafe fn create_cond(attr: Option) -> Cond { + let cond: Cond = mem::zeroed(); + if let Some(mut attr) = attr { + assert_eq!(libc::pthread_cond_init(cond.inner.get() as *mut _, &attr as *const _), 0); + assert_eq!(libc::pthread_condattr_destroy(&mut attr as *mut _), 0); + } else { + assert_eq!(libc::pthread_cond_init(cond.inner.get() as *mut _, 0 as *const _), 0); + } + cond +} + +unsafe fn create_mutex() -> Mutex { + mem::zeroed() +} + +unsafe fn create_timeout(seconds: i64) -> libc::timespec { + let mut now: libc::timespec = mem::zeroed(); + assert_eq!(libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut now), 0); + libc::timespec { tv_sec: now.tv_sec + seconds, tv_nsec: now.tv_nsec } +} + +fn test_pthread_condattr_t() { + unsafe { + let mut attr = create_cond_attr_monotonic(); + let mut clock_id = MaybeUninit::::uninit(); + assert_eq!(libc::pthread_condattr_getclock(&attr as *const _, clock_id.as_mut_ptr()), 0); + assert_eq!(clock_id.assume_init(), libc::CLOCK_MONOTONIC); + assert_eq!(libc::pthread_condattr_destroy(&mut attr as *mut _), 0); + } +} + +fn test_signal() { + unsafe { + let cond = Arc::new(create_cond(None)); + let mutex = Arc::new(create_mutex()); + + assert_eq!(libc::pthread_mutex_lock(mutex.inner.get() as *mut _), 0); + + let spawn_mutex = Arc::clone(&mutex); + let spawn_cond = Arc::clone(&cond); + let handle = thread::spawn(move || { + assert_eq!(libc::pthread_mutex_lock(spawn_mutex.inner.get() as *mut _), 0); + assert_eq!(libc::pthread_cond_signal(spawn_cond.inner.get() as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(spawn_mutex.inner.get() as *mut _), 0); + }); + + assert_eq!( + libc::pthread_cond_wait(cond.inner.get() as *mut _, mutex.inner.get() as *mut _), + 0 + ); + assert_eq!(libc::pthread_mutex_unlock(mutex.inner.get() as *mut _), 0); + + handle.join().unwrap(); + + let mutex = Arc::try_unwrap(mutex).unwrap(); + assert_eq!(libc::pthread_mutex_destroy(mutex.inner.get() as *mut _), 0); + let cond = Arc::try_unwrap(cond).unwrap(); + assert_eq!(libc::pthread_cond_destroy(cond.inner.get() as *mut _), 0); + } +} + +fn test_broadcast() { + unsafe { + let cond = Arc::new(create_cond(None)); + let mutex = Arc::new(create_mutex()); + + assert_eq!(libc::pthread_mutex_lock(mutex.inner.get() as *mut _), 0); + + let spawn_mutex = Arc::clone(&mutex); + let spawn_cond = Arc::clone(&cond); + let handle = thread::spawn(move || { + assert_eq!(libc::pthread_mutex_lock(spawn_mutex.inner.get() as *mut _), 0); + assert_eq!(libc::pthread_cond_broadcast(spawn_cond.inner.get() as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(spawn_mutex.inner.get() as *mut _), 0); + }); + + assert_eq!( + libc::pthread_cond_wait(cond.inner.get() as *mut _, mutex.inner.get() as *mut _), + 0 + ); + assert_eq!(libc::pthread_mutex_unlock(mutex.inner.get() as *mut _), 0); + + handle.join().unwrap(); + + let mutex = Arc::try_unwrap(mutex).unwrap(); + assert_eq!(libc::pthread_mutex_destroy(mutex.inner.get() as *mut _), 0); + let cond = Arc::try_unwrap(cond).unwrap(); + assert_eq!(libc::pthread_cond_destroy(cond.inner.get() as *mut _), 0); + } +} + +fn test_timed_wait_timeout() { + unsafe { + let attr = create_cond_attr_monotonic(); + let cond = create_cond(Some(attr)); + let mutex = create_mutex(); + let timeout = create_timeout(1); + + assert_eq!(libc::pthread_mutex_lock(mutex.inner.get() as *mut _), 0); + assert_eq!( + libc::pthread_cond_timedwait( + cond.inner.get() as *mut _, + mutex.inner.get() as *mut _, + &timeout + ), + libc::ETIMEDOUT + ); + assert_eq!(libc::pthread_mutex_unlock(mutex.inner.get() as *mut _), 0); + assert_eq!(libc::pthread_mutex_destroy(mutex.inner.get() as *mut _), 0); + assert_eq!(libc::pthread_cond_destroy(cond.inner.get() as *mut _), 0); + } +} + +fn test_timed_wait_notimeout() { + unsafe { + let attr = create_cond_attr_monotonic(); + let cond = Arc::new(create_cond(Some(attr))); + let mutex = Arc::new(create_mutex()); + let timeout = create_timeout(100); + + assert_eq!(libc::pthread_mutex_lock(mutex.inner.get() as *mut _), 0); + + let spawn_mutex = Arc::clone(&mutex); + let spawn_cond = Arc::clone(&cond); + let handle = thread::spawn(move || { + assert_eq!(libc::pthread_mutex_lock(spawn_mutex.inner.get() as *mut _), 0); + assert_eq!(libc::pthread_cond_signal(spawn_cond.inner.get() as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(spawn_mutex.inner.get() as *mut _), 0); + }); + + assert_eq!( + libc::pthread_cond_timedwait( + cond.inner.get() as *mut _, + mutex.inner.get() as *mut _, + &timeout + ), + 0 + ); + assert_eq!(libc::pthread_mutex_unlock(mutex.inner.get() as *mut _), 0); + + handle.join().unwrap(); + + let mutex = Arc::try_unwrap(mutex).unwrap(); + assert_eq!(libc::pthread_mutex_destroy(mutex.inner.get() as *mut _), 0); + let cond = Arc::try_unwrap(cond).unwrap(); + assert_eq!(libc::pthread_cond_destroy(cond.inner.get() as *mut _), 0); + } +} + +fn main() { + test_pthread_condattr_t(); + test_signal(); + test_broadcast(); + test_timed_wait_timeout(); + test_timed_wait_notimeout(); +} diff --git a/tests/run-pass/concurrency/libc_pthread_cond.stderr b/tests/run-pass/concurrency/libc_pthread_cond.stderr new file mode 100644 index 000000000000..2dbfb7721d36 --- /dev/null +++ b/tests/run-pass/concurrency/libc_pthread_cond.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental. For example, Miri does not detect data races yet. + diff --git a/tests/run-pass/concurrency/mpsc.rs b/tests/run-pass/concurrency/mpsc.rs new file mode 100644 index 000000000000..3558f5415d07 --- /dev/null +++ b/tests/run-pass/concurrency/mpsc.rs @@ -0,0 +1,56 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +//! Check if Rust channels are working. + +use std::sync::mpsc::{channel, sync_channel}; +use std::thread; + +/// The test taken from the Rust documentation. +fn simple_send() { + let (tx, rx) = channel(); + thread::spawn(move || { + tx.send(10).unwrap(); + }); + assert_eq!(rx.recv().unwrap(), 10); +} + +/// The test taken from the Rust documentation. +fn multiple_send() { + let (tx, rx) = channel(); + for i in 0..10 { + let tx = tx.clone(); + thread::spawn(move || { + tx.send(i).unwrap(); + }); + } + + let mut sum = 0; + for _ in 0..10 { + let j = rx.recv().unwrap(); + assert!(0 <= j && j < 10); + sum += j; + } + assert_eq!(sum, 45); +} + +/// The test taken from the Rust documentation. +fn send_on_sync() { + let (sender, receiver) = sync_channel(1); + + // this returns immediately + sender.send(1).unwrap(); + + thread::spawn(move || { + // this will block until the previous message has been received + sender.send(2).unwrap(); + }); + + assert_eq!(receiver.recv().unwrap(), 1); + assert_eq!(receiver.recv().unwrap(), 2); +} + +fn main() { + simple_send(); + multiple_send(); + send_on_sync(); +} diff --git a/tests/run-pass/concurrency/mpsc.stderr b/tests/run-pass/concurrency/mpsc.stderr new file mode 100644 index 000000000000..2dbfb7721d36 --- /dev/null +++ b/tests/run-pass/concurrency/mpsc.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental. For example, Miri does not detect data races yet. + diff --git a/tests/run-pass/concurrency/once.rs b/tests/run-pass/concurrency/once.rs new file mode 100644 index 000000000000..499ceacfa8c4 --- /dev/null +++ b/tests/run-pass/concurrency/once.rs @@ -0,0 +1,44 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +//! Check if Rust once statics are working. The test taken from the Rust +//! documentation. + +use std::sync::Once; +use std::thread; + +static mut VAL: usize = 0; +static INIT: Once = Once::new(); + +fn get_cached_val() -> usize { + unsafe { + INIT.call_once(|| { + VAL = expensive_computation(); + }); + VAL + } +} + +fn expensive_computation() -> usize { + let mut i = 1; + let mut c = 1; + while i < 10000 { + i *= c; + c += 1; + } + i +} + +fn main() { + let handles: Vec<_> = (0..10) + .map(|_| { + thread::spawn(|| { + thread::yield_now(); + let val = get_cached_val(); + assert_eq!(val, 40320); + }) + }) + .collect(); + for handle in handles { + handle.join().unwrap(); + } +} diff --git a/tests/run-pass/concurrency/once.stderr b/tests/run-pass/concurrency/once.stderr new file mode 100644 index 000000000000..2dbfb7721d36 --- /dev/null +++ b/tests/run-pass/concurrency/once.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental. For example, Miri does not detect data races yet. + From d0de439ac8366afce491250a64b78702fa5d7dd6 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 30 Apr 2020 13:47:12 -0700 Subject: [PATCH 2087/5092] Cleanup. --- src/thread.rs | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/src/thread.rs b/src/thread.rs index 6ebf35a6527f..856468705d30 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -3,7 +3,7 @@ use std::cell::RefCell; use std::collections::hash_map::Entry; use std::convert::TryFrom; -use std::num::{NonZeroU32, TryFromIntError}; +use std::num::TryFromIntError; use std::time::Instant; use log::trace; @@ -77,21 +77,6 @@ impl ThreadId { } } -/// An identifier of a set of blocked threads. 0 is used to indicate the absence -/// of a blockset identifier and, therefore, is not a valid identifier. -#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] -pub struct BlockSetId(NonZeroU32); - -impl BlockSetId { - /// Panics if `id` is 0. - pub fn new(id: u32) -> Self { - Self(NonZeroU32::new(id).expect("0 is not a valid blockset id")) - } - pub fn to_u32_scalar<'tcx>(&self) -> Scalar { - Scalar::from_u32(self.0.get()) - } -} - /// The state of a thread. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum ThreadState { @@ -100,9 +85,10 @@ pub enum ThreadState { /// The thread tried to join the specified thread and is blocked until that /// thread terminates. BlockedOnJoin(ThreadId), - /// The thread is blocked and belongs to the given blockset. - Blocked(BlockSetId), - BlockedThread, + /// The thread is blocked on some synchronization primitive. It is the + /// responsibility of the synchronization primitives to track threads that + /// are blocked by them. + BlockedOnSync, /// The thread has terminated its execution (we do not delete terminated /// threads). Terminated, @@ -357,13 +343,13 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { fn block_thread(&mut self, thread: ThreadId) { let state = &mut self.threads[thread].state; assert_eq!(*state, ThreadState::Enabled); - *state = ThreadState::BlockedThread; + *state = ThreadState::BlockedOnSync; } /// Put the blocked thread into the enabled state. fn unblock_thread(&mut self, thread: ThreadId) { let state = &mut self.threads[thread].state; - assert_eq!(*state, ThreadState::BlockedThread); + assert_eq!(*state, ThreadState::BlockedOnSync); *state = ThreadState::Enabled; } From 044a068c672cf8edae2cd9d5032995f37f1c3718 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 30 Apr 2020 14:07:07 -0700 Subject: [PATCH 2088/5092] Improve code readability and comments. --- src/eval.rs | 4 ++-- src/shims/sync.rs | 12 +++++----- src/sync.rs | 15 +++++++----- src/thread.rs | 60 +++++++++++++++++++++++------------------------ 4 files changed, 47 insertions(+), 44 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 30901a8f127f..7a6c562e7ca0 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -210,11 +210,11 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> SchedulingAction::ExecuteStep => { assert!(ecx.step()?, "a terminated thread was scheduled for execution"); } - SchedulingAction::ExecuteCallback => { + SchedulingAction::ExecuteTimeoutCallback => { assert!(ecx.machine.communicate, "scheduler callbacks require disabled isolation, but the code \ that created the callback did not check it"); - ecx.run_scheduler_callback()?; + ecx.run_timeout_callback()?; } SchedulingAction::ExecuteDtors => { // This will either enable the thread again (so we go back diff --git a/src/shims/sync.rs b/src/shims/sync.rs index dfd7999457eb..f31efe18e1c1 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -128,7 +128,7 @@ fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( mutex_set_id(ecx, mutex_op, id.to_u32_scalar())?; Ok(id) } else { - Ok(id.into()) + Ok(MutexId::from_u32(id)) } } @@ -168,7 +168,7 @@ fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( rwlock_set_id(ecx, rwlock_op, id.to_u32_scalar())?; Ok(id) } else { - Ok(id.into()) + Ok(RwLockId::from_u32(id)) } } @@ -232,7 +232,7 @@ fn cond_get_or_create_id<'mir, 'tcx: 'mir>( cond_set_id(ecx, cond_op, id.to_u32_scalar())?; Ok(id) } else { - Ok(id.into()) + Ok(CondvarId::from_u32(id)) } } @@ -656,7 +656,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let id = cond_get_or_create_id(this, cond_op)?; if let Some((thread, mutex)) = this.condvar_signal(id) { reacquire_cond_mutex(this, thread, mutex)?; - this.unregister_callback_if_exists(thread)?; + this.unregister_timeout_callback_if_exists(thread)?; } Ok(0) @@ -668,7 +668,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx while let Some((thread, mutex)) = this.condvar_signal(id) { reacquire_cond_mutex(this, thread, mutex)?; - this.unregister_callback_if_exists(thread)?; + this.unregister_timeout_callback_if_exists(thread)?; } Ok(0) @@ -739,7 +739,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Register the timeout callback. - this.register_callback( + this.register_timeout_callback( active_thread, timeout_time, Box::new(move |ecx| { diff --git a/src/sync.rs b/src/sync.rs index 5d181692fb2a..88b5d6c060dd 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -9,9 +9,18 @@ use crate::*; macro_rules! declare_id { ($name: ident) => { + /// 0 is used to indicate that the id was not yet assigned and, + /// therefore, is not a valid identifier. #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] pub struct $name(NonZeroU32); + impl $name { + // Panics if `id == 0`. + pub fn from_u32(id: u32) -> Self { + Self(NonZeroU32::new(id).unwrap()) + } + } + impl Idx for $name { fn new(idx: usize) -> Self { $name(NonZeroU32::new(u32::try_from(idx).unwrap() + 1).unwrap()) @@ -21,12 +30,6 @@ macro_rules! declare_id { } } - impl From for $name { - fn from(id: u32) -> Self { - Self(NonZeroU32::new(id).unwrap()) - } - } - impl $name { pub fn to_u32_scalar<'tcx>(&self) -> Scalar { Scalar::from_u32(self.0.get()) diff --git a/src/thread.rs b/src/thread.rs index 856468705d30..f67de48b710d 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -24,15 +24,17 @@ use crate::*; pub enum SchedulingAction { /// Execute step on the active thread. ExecuteStep, - /// Execute a scheduler's callback. - ExecuteCallback, + /// Execute a timeout callback. + ExecuteTimeoutCallback, /// Execute destructors of the active thread. ExecuteDtors, /// Stop the program. Stop, } -type EventCallback<'mir, 'tcx> = +/// Timeout timeout_callbacks can be created by synchronization primitives to tell the +/// scheduler that they should be called once some period of time passes. +type TimeoutCallback<'mir, 'tcx> = Box>) -> InterpResult<'tcx> + 'tcx>; /// A thread identifier. @@ -161,14 +163,14 @@ impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> { /// conditional variable with a timeout creates a callback that is called after /// the specified time and unblocks the thread. If another thread signals on the /// conditional variable, the signal handler deletes the callback. -struct CallBackInfo<'mir, 'tcx> { +struct TimeoutCallbackInfo<'mir, 'tcx> { /// The callback should be called no earlier than this time. call_time: Instant, /// The called function. - callback: EventCallback<'mir, 'tcx>, + callback: TimeoutCallback<'mir, 'tcx>, } -impl<'mir, 'tcx> std::fmt::Debug for CallBackInfo<'mir, 'tcx> { +impl<'mir, 'tcx> std::fmt::Debug for TimeoutCallbackInfo<'mir, 'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "CallBack({:?})", self.call_time) } @@ -183,17 +185,16 @@ pub struct ThreadManager<'mir, 'tcx> { /// /// Note that this vector also contains terminated threads. threads: IndexVec>, - /// FIXME: make private. + /// This field is pub(crate) because the synchronization primitives + /// (`crate::sync`) need a way to access it. pub(crate) sync: SynchronizationState, - /// A counter used to generate unique identifiers for blocksets. - blockset_counter: u32, /// A mapping from a thread-local static to an allocation id of a thread /// specific allocation. thread_local_alloc_ids: RefCell>, /// A flag that indicates that we should change the active thread. yield_active_thread: bool, /// Callbacks that are called once the specified time passes. - callbacks: FxHashMap>, + timeout_callbacks: FxHashMap>, } impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { @@ -208,10 +209,9 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { active_thread: ThreadId::new(0), threads: threads, sync: SynchronizationState::default(), - blockset_counter: 0, thread_local_alloc_ids: Default::default(), yield_active_thread: false, - callbacks: FxHashMap::default(), + timeout_callbacks: FxHashMap::default(), } } } @@ -359,28 +359,28 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Register the given `callback` to be called once the `call_time` passes. - fn register_callback( + fn register_timeout_callback( &mut self, thread: ThreadId, call_time: Instant, - callback: EventCallback<'mir, 'tcx>, + callback: TimeoutCallback<'mir, 'tcx>, ) { - self.callbacks - .insert(thread, CallBackInfo { call_time: call_time, callback: callback }) + self.timeout_callbacks + .insert(thread, TimeoutCallbackInfo { call_time: call_time, callback: callback }) .unwrap_none(); } /// Unregister the callback for the `thread`. - fn unregister_callback_if_exists(&mut self, thread: ThreadId) { - self.callbacks.remove(&thread); + fn unregister_timeout_callback_if_exists(&mut self, thread: ThreadId) { + self.timeout_callbacks.remove(&thread); } /// Get a callback that is ready to be called. - fn get_callback(&mut self) -> Option<(ThreadId, EventCallback<'mir, 'tcx>)> { + fn get_callback(&mut self) -> Option<(ThreadId, TimeoutCallback<'mir, 'tcx>)> { let current_time = Instant::now(); // We use a for loop here to make the scheduler more deterministic. for thread in self.threads.indices() { - match self.callbacks.entry(thread) { + match self.timeout_callbacks.entry(thread) { Entry::Occupied(entry) => if current_time >= entry.get().call_time { return Some((thread, entry.remove().callback)); @@ -447,17 +447,17 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { if self.threads.iter().all(|thread| thread.state == ThreadState::Terminated) { unreachable!(); } else if let Some(next_call_time) = - self.callbacks.values().min_by_key(|info| info.call_time) + self.timeout_callbacks.values().min_by_key(|info| info.call_time) { // All threads are currently blocked, but we have unexecuted - // callbacks, which may unblock some of the threads. Hence, + // timeout_callbacks, which may unblock some of the threads. Hence, // sleep until the first callback. if let Some(sleep_time) = next_call_time.call_time.checked_duration_since(Instant::now()) { std::thread::sleep(sleep_time); } - Ok(SchedulingAction::ExecuteCallback) + Ok(SchedulingAction::ExecuteTimeoutCallback) } else { throw_machine_stop!(TerminationInfo::Deadlock); } @@ -647,27 +647,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[inline] - fn register_callback( + fn register_timeout_callback( &mut self, thread: ThreadId, call_time: Instant, - callback: EventCallback<'mir, 'tcx>, + callback: TimeoutCallback<'mir, 'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.machine.threads.register_callback(thread, call_time, callback); + this.machine.threads.register_timeout_callback(thread, call_time, callback); Ok(()) } #[inline] - fn unregister_callback_if_exists(&mut self, thread: ThreadId) -> InterpResult<'tcx> { + fn unregister_timeout_callback_if_exists(&mut self, thread: ThreadId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.machine.threads.unregister_callback_if_exists(thread); + this.machine.threads.unregister_timeout_callback_if_exists(thread); Ok(()) } - /// Execute the callback on the callback's thread. + /// Execute a timeout callback on the callback's thread. #[inline] - fn run_scheduler_callback(&mut self) -> InterpResult<'tcx> { + fn run_timeout_callback(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (thread, callback) = this.machine.threads.get_callback().expect("no callback found"); let old_thread = this.set_active_thread(thread)?; From 6e774dec86daeda8aa6ae2fa20c2334cd8841db6 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 30 Apr 2020 14:48:09 -0700 Subject: [PATCH 2089/5092] Move all run-pass synchronization primitive tests to sync.rs. --- tests/run-pass/concurrency/barrier.rs | 27 --- tests/run-pass/concurrency/condvar.rs | 28 --- tests/run-pass/concurrency/condvar.stderr | 2 - tests/run-pass/concurrency/locks.rs | 75 ------ tests/run-pass/concurrency/locks.stderr | 2 - tests/run-pass/concurrency/mpsc.rs | 56 ----- tests/run-pass/concurrency/mpsc.stderr | 2 - tests/run-pass/concurrency/once.rs | 44 ---- tests/run-pass/concurrency/once.stderr | 2 - tests/run-pass/concurrency/sync.rs | 216 ++++++++++++++++++ .../{barrier.stderr => sync.stderr} | 0 .../{barrier.stdout => sync.stdout} | 0 12 files changed, 216 insertions(+), 238 deletions(-) delete mode 100644 tests/run-pass/concurrency/barrier.rs delete mode 100644 tests/run-pass/concurrency/condvar.rs delete mode 100644 tests/run-pass/concurrency/condvar.stderr delete mode 100644 tests/run-pass/concurrency/locks.rs delete mode 100644 tests/run-pass/concurrency/locks.stderr delete mode 100644 tests/run-pass/concurrency/mpsc.rs delete mode 100644 tests/run-pass/concurrency/mpsc.stderr delete mode 100644 tests/run-pass/concurrency/once.rs delete mode 100644 tests/run-pass/concurrency/once.stderr create mode 100644 tests/run-pass/concurrency/sync.rs rename tests/run-pass/concurrency/{barrier.stderr => sync.stderr} (100%) rename tests/run-pass/concurrency/{barrier.stdout => sync.stdout} (100%) diff --git a/tests/run-pass/concurrency/barrier.rs b/tests/run-pass/concurrency/barrier.rs deleted file mode 100644 index 1e976a63453d..000000000000 --- a/tests/run-pass/concurrency/barrier.rs +++ /dev/null @@ -1,27 +0,0 @@ -// ignore-windows: Concurrency on Windows is not supported yet. - -//! Check if Rust barriers are working. - -use std::sync::{Arc, Barrier}; -use std::thread; - - -/// This test is taken from the Rust documentation. -fn main() { - let mut handles = Vec::with_capacity(10); - let barrier = Arc::new(Barrier::new(10)); - for _ in 0..10 { - let c = barrier.clone(); - // The same messages will be printed together. - // You will NOT see any interleaving. - handles.push(thread::spawn(move|| { - println!("before wait"); - c.wait(); - println!("after wait"); - })); - } - // Wait for other threads to finish. - for handle in handles { - handle.join().unwrap(); - } -} \ No newline at end of file diff --git a/tests/run-pass/concurrency/condvar.rs b/tests/run-pass/concurrency/condvar.rs deleted file mode 100644 index ab971ee6e8c6..000000000000 --- a/tests/run-pass/concurrency/condvar.rs +++ /dev/null @@ -1,28 +0,0 @@ -// ignore-windows: Concurrency on Windows is not supported yet. - -//! Check if Rust conditional variables are working. - -use std::sync::{Arc, Condvar, Mutex}; -use std::thread; - -/// The test taken from the Rust documentation. -fn main() { - let pair = Arc::new((Mutex::new(false), Condvar::new())); - let pair2 = pair.clone(); - - // Inside of our lock, spawn a new thread, and then wait for it to start. - thread::spawn(move || { - let (lock, cvar) = &*pair2; - let mut started = lock.lock().unwrap(); - *started = true; - // We notify the condvar that the value has changed. - cvar.notify_one(); - }); - - // Wait for the thread to start up. - let (lock, cvar) = &*pair; - let mut started = lock.lock().unwrap(); - while !*started { - started = cvar.wait(started).unwrap(); - } -} diff --git a/tests/run-pass/concurrency/condvar.stderr b/tests/run-pass/concurrency/condvar.stderr deleted file mode 100644 index 2dbfb7721d36..000000000000 --- a/tests/run-pass/concurrency/condvar.stderr +++ /dev/null @@ -1,2 +0,0 @@ -warning: thread support is experimental. For example, Miri does not detect data races yet. - diff --git a/tests/run-pass/concurrency/locks.rs b/tests/run-pass/concurrency/locks.rs deleted file mode 100644 index f5469712c5f5..000000000000 --- a/tests/run-pass/concurrency/locks.rs +++ /dev/null @@ -1,75 +0,0 @@ -// ignore-windows: Concurrency on Windows is not supported yet. - -use std::sync::{Arc, Mutex, RwLock}; -use std::thread; - -fn check_mutex() { - let data = Arc::new(Mutex::new(0)); - let mut threads = Vec::new(); - - for _ in 0..3 { - let data = Arc::clone(&data); - let thread = thread::spawn(move || { - let mut data = data.lock().unwrap(); - thread::yield_now(); - *data += 1; - }); - threads.push(thread); - } - - for thread in threads { - thread.join().unwrap(); - } - - assert!(data.try_lock().is_ok()); - - let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap(); - assert_eq!(data, 3); -} - -fn check_rwlock_write() { - let data = Arc::new(RwLock::new(0)); - let mut threads = Vec::new(); - - for _ in 0..3 { - let data = Arc::clone(&data); - let thread = thread::spawn(move || { - let mut data = data.write().unwrap(); - thread::yield_now(); - *data += 1; - }); - threads.push(thread); - } - - for thread in threads { - thread.join().unwrap(); - } - - assert!(data.try_write().is_ok()); - - let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap(); - assert_eq!(data, 3); -} - -fn check_rwlock_read_no_deadlock() { - let l1 = Arc::new(RwLock::new(0)); - let l2 = Arc::new(RwLock::new(0)); - - let l1_copy = Arc::clone(&l1); - let l2_copy = Arc::clone(&l2); - let _guard1 = l1.read().unwrap(); - let handle = thread::spawn(move || { - let _guard2 = l2_copy.read().unwrap(); - thread::yield_now(); - let _guard1 = l1_copy.read().unwrap(); - }); - thread::yield_now(); - let _guard2 = l2.read().unwrap(); - handle.join().unwrap(); -} - -fn main() { - check_mutex(); - check_rwlock_write(); - check_rwlock_read_no_deadlock(); -} diff --git a/tests/run-pass/concurrency/locks.stderr b/tests/run-pass/concurrency/locks.stderr deleted file mode 100644 index 2dbfb7721d36..000000000000 --- a/tests/run-pass/concurrency/locks.stderr +++ /dev/null @@ -1,2 +0,0 @@ -warning: thread support is experimental. For example, Miri does not detect data races yet. - diff --git a/tests/run-pass/concurrency/mpsc.rs b/tests/run-pass/concurrency/mpsc.rs deleted file mode 100644 index 3558f5415d07..000000000000 --- a/tests/run-pass/concurrency/mpsc.rs +++ /dev/null @@ -1,56 +0,0 @@ -// ignore-windows: Concurrency on Windows is not supported yet. - -//! Check if Rust channels are working. - -use std::sync::mpsc::{channel, sync_channel}; -use std::thread; - -/// The test taken from the Rust documentation. -fn simple_send() { - let (tx, rx) = channel(); - thread::spawn(move || { - tx.send(10).unwrap(); - }); - assert_eq!(rx.recv().unwrap(), 10); -} - -/// The test taken from the Rust documentation. -fn multiple_send() { - let (tx, rx) = channel(); - for i in 0..10 { - let tx = tx.clone(); - thread::spawn(move || { - tx.send(i).unwrap(); - }); - } - - let mut sum = 0; - for _ in 0..10 { - let j = rx.recv().unwrap(); - assert!(0 <= j && j < 10); - sum += j; - } - assert_eq!(sum, 45); -} - -/// The test taken from the Rust documentation. -fn send_on_sync() { - let (sender, receiver) = sync_channel(1); - - // this returns immediately - sender.send(1).unwrap(); - - thread::spawn(move || { - // this will block until the previous message has been received - sender.send(2).unwrap(); - }); - - assert_eq!(receiver.recv().unwrap(), 1); - assert_eq!(receiver.recv().unwrap(), 2); -} - -fn main() { - simple_send(); - multiple_send(); - send_on_sync(); -} diff --git a/tests/run-pass/concurrency/mpsc.stderr b/tests/run-pass/concurrency/mpsc.stderr deleted file mode 100644 index 2dbfb7721d36..000000000000 --- a/tests/run-pass/concurrency/mpsc.stderr +++ /dev/null @@ -1,2 +0,0 @@ -warning: thread support is experimental. For example, Miri does not detect data races yet. - diff --git a/tests/run-pass/concurrency/once.rs b/tests/run-pass/concurrency/once.rs deleted file mode 100644 index 499ceacfa8c4..000000000000 --- a/tests/run-pass/concurrency/once.rs +++ /dev/null @@ -1,44 +0,0 @@ -// ignore-windows: Concurrency on Windows is not supported yet. - -//! Check if Rust once statics are working. The test taken from the Rust -//! documentation. - -use std::sync::Once; -use std::thread; - -static mut VAL: usize = 0; -static INIT: Once = Once::new(); - -fn get_cached_val() -> usize { - unsafe { - INIT.call_once(|| { - VAL = expensive_computation(); - }); - VAL - } -} - -fn expensive_computation() -> usize { - let mut i = 1; - let mut c = 1; - while i < 10000 { - i *= c; - c += 1; - } - i -} - -fn main() { - let handles: Vec<_> = (0..10) - .map(|_| { - thread::spawn(|| { - thread::yield_now(); - let val = get_cached_val(); - assert_eq!(val, 40320); - }) - }) - .collect(); - for handle in handles { - handle.join().unwrap(); - } -} diff --git a/tests/run-pass/concurrency/once.stderr b/tests/run-pass/concurrency/once.stderr deleted file mode 100644 index 2dbfb7721d36..000000000000 --- a/tests/run-pass/concurrency/once.stderr +++ /dev/null @@ -1,2 +0,0 @@ -warning: thread support is experimental. For example, Miri does not detect data races yet. - diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs new file mode 100644 index 000000000000..b09bfe9e0c86 --- /dev/null +++ b/tests/run-pass/concurrency/sync.rs @@ -0,0 +1,216 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +use std::sync::mpsc::{channel, sync_channel}; +use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock}; +use std::thread; + +// Check if Rust barriers are working. + +/// This test is taken from the Rust documentation. +fn check_barriers() { + let mut handles = Vec::with_capacity(10); + let barrier = Arc::new(Barrier::new(10)); + for _ in 0..10 { + let c = barrier.clone(); + // The same messages will be printed together. + // You will NOT see any interleaving. + handles.push(thread::spawn(move || { + println!("before wait"); + c.wait(); + println!("after wait"); + })); + } + // Wait for other threads to finish. + for handle in handles { + handle.join().unwrap(); + } +} + +// Check if Rust conditional variables are working. + +/// The test taken from the Rust documentation. +fn check_conditional_variables() { + let pair = Arc::new((Mutex::new(false), Condvar::new())); + let pair2 = pair.clone(); + + // Inside of our lock, spawn a new thread, and then wait for it to start. + thread::spawn(move || { + let (lock, cvar) = &*pair2; + let mut started = lock.lock().unwrap(); + *started = true; + // We notify the condvar that the value has changed. + cvar.notify_one(); + }); + + // Wait for the thread to start up. + let (lock, cvar) = &*pair; + let mut started = lock.lock().unwrap(); + while !*started { + started = cvar.wait(started).unwrap(); + } +} + +// Check if locks are working. + +fn check_mutex() { + let data = Arc::new(Mutex::new(0)); + let mut threads = Vec::new(); + + for _ in 0..3 { + let data = Arc::clone(&data); + let thread = thread::spawn(move || { + let mut data = data.lock().unwrap(); + thread::yield_now(); + *data += 1; + }); + threads.push(thread); + } + + for thread in threads { + thread.join().unwrap(); + } + + assert!(data.try_lock().is_ok()); + + let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap(); + assert_eq!(data, 3); +} + +fn check_rwlock_write() { + let data = Arc::new(RwLock::new(0)); + let mut threads = Vec::new(); + + for _ in 0..3 { + let data = Arc::clone(&data); + let thread = thread::spawn(move || { + let mut data = data.write().unwrap(); + thread::yield_now(); + *data += 1; + }); + threads.push(thread); + } + + for thread in threads { + thread.join().unwrap(); + } + + assert!(data.try_write().is_ok()); + + let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap(); + assert_eq!(data, 3); +} + +fn check_rwlock_read_no_deadlock() { + let l1 = Arc::new(RwLock::new(0)); + let l2 = Arc::new(RwLock::new(0)); + + let l1_copy = Arc::clone(&l1); + let l2_copy = Arc::clone(&l2); + let _guard1 = l1.read().unwrap(); + let handle = thread::spawn(move || { + let _guard2 = l2_copy.read().unwrap(); + thread::yield_now(); + let _guard1 = l1_copy.read().unwrap(); + }); + thread::yield_now(); + let _guard2 = l2.read().unwrap(); + handle.join().unwrap(); +} + +// Check if channels are working. + +/// The test taken from the Rust documentation. +fn simple_send() { + let (tx, rx) = channel(); + thread::spawn(move || { + tx.send(10).unwrap(); + }); + assert_eq!(rx.recv().unwrap(), 10); +} + +/// The test taken from the Rust documentation. +fn multiple_send() { + let (tx, rx) = channel(); + for i in 0..10 { + let tx = tx.clone(); + thread::spawn(move || { + tx.send(i).unwrap(); + }); + } + + let mut sum = 0; + for _ in 0..10 { + let j = rx.recv().unwrap(); + assert!(0 <= j && j < 10); + sum += j; + } + assert_eq!(sum, 45); +} + +/// The test taken from the Rust documentation. +fn send_on_sync() { + let (sender, receiver) = sync_channel(1); + + // this returns immediately + sender.send(1).unwrap(); + + thread::spawn(move || { + // this will block until the previous message has been received + sender.send(2).unwrap(); + }); + + assert_eq!(receiver.recv().unwrap(), 1); + assert_eq!(receiver.recv().unwrap(), 2); +} + +// Check if Rust once statics are working. + +static mut VAL: usize = 0; +static INIT: Once = Once::new(); + +fn get_cached_val() -> usize { + unsafe { + INIT.call_once(|| { + VAL = expensive_computation(); + }); + VAL + } +} + +fn expensive_computation() -> usize { + let mut i = 1; + let mut c = 1; + while i < 10000 { + i *= c; + c += 1; + } + i +} + +/// The test taken from the Rust documentation. +fn check_once() { + let handles: Vec<_> = (0..10) + .map(|_| { + thread::spawn(|| { + thread::yield_now(); + let val = get_cached_val(); + assert_eq!(val, 40320); + }) + }) + .collect(); + for handle in handles { + handle.join().unwrap(); + } +} + +fn main() { + check_barriers(); + check_conditional_variables(); + check_mutex(); + check_rwlock_write(); + check_rwlock_read_no_deadlock(); + simple_send(); + multiple_send(); + send_on_sync(); + check_once(); +} diff --git a/tests/run-pass/concurrency/barrier.stderr b/tests/run-pass/concurrency/sync.stderr similarity index 100% rename from tests/run-pass/concurrency/barrier.stderr rename to tests/run-pass/concurrency/sync.stderr diff --git a/tests/run-pass/concurrency/barrier.stdout b/tests/run-pass/concurrency/sync.stdout similarity index 100% rename from tests/run-pass/concurrency/barrier.stdout rename to tests/run-pass/concurrency/sync.stdout From 4a303b13095122c2007bf8751bdbc0e89b8708d3 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 30 Apr 2020 14:59:35 -0700 Subject: [PATCH 2090/5092] Add a timeout test for conditional variables. --- tests/run-pass/concurrency/sync.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index b09bfe9e0c86..e422a7fbdbc5 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -1,8 +1,10 @@ // ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-isolation use std::sync::mpsc::{channel, sync_channel}; use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock}; use std::thread; +use std::time::{Duration, Instant}; // Check if Rust barriers are working. @@ -50,6 +52,17 @@ fn check_conditional_variables() { } } +/// Test that waiting on a conditional variable with a timeout does not +/// deadlock. +fn check_conditional_variables_timeout() { + let lock = Mutex::new(()); + let cvar = Condvar::new(); + let guard = lock.lock().unwrap(); + let now = Instant::now(); + let _guard = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap().0; + assert!(now.elapsed().as_millis() >= 100); +} + // Check if locks are working. fn check_mutex() { @@ -206,6 +219,7 @@ fn check_once() { fn main() { check_barriers(); check_conditional_variables(); + check_conditional_variables_timeout(); check_mutex(); check_rwlock_write(); check_rwlock_read_no_deadlock(); From 86eb262e8a2d270cc8195185b217710f815761b3 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 30 Apr 2020 15:37:27 -0700 Subject: [PATCH 2091/5092] Cleanup Condvar tests. --- src/shims/sync.rs | 12 +- .../run-pass/concurrency/libc_pthread_cond.rs | 214 ++++-------------- .../concurrency/libc_pthread_cond.stderr | 2 - tests/run-pass/concurrency/sync.rs | 54 ++++- 4 files changed, 103 insertions(+), 179 deletions(-) delete mode 100644 tests/run-pass/concurrency/libc_pthread_cond.stderr diff --git a/src/shims/sync.rs b/src/shims/sync.rs index f31efe18e1c1..a586be8139ba 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -1,4 +1,5 @@ use std::time::{Duration, SystemTime}; +use std::convert::TryInto; use rustc_middle::ty::{layout::TyAndLayout, TyKind, TypeAndMut}; use rustc_target::abi::{LayoutOf, Size}; @@ -719,12 +720,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut offset = Size::from_bytes(0); let layout = this.libc_ty_layout("time_t")?; let seconds_place = tp.offset(offset, MemPlaceMeta::None, layout, this)?; - let seconds = this.read_scalar(seconds_place.into())?.to_u64()?; + let seconds = this.read_scalar(seconds_place.into())?; offset += layout.size; let layout = this.libc_ty_layout("c_long")?; let nanoseconds_place = tp.offset(offset, MemPlaceMeta::None, layout, this)?; - let nanoseconds = this.read_scalar(nanoseconds_place.into())?.to_u64()?; - Duration::new(seconds, nanoseconds as u32) + let nanoseconds = this.read_scalar(nanoseconds_place.into())?; + let (seconds, nanoseconds) = if this.pointer_size().bytes() == 8 { + (seconds.to_u64()?, nanoseconds.to_u64()?.try_into().unwrap()) + } else { + (seconds.to_u32()?.into(), nanoseconds.to_u32()?) + }; + Duration::new(seconds, nanoseconds) }; let timeout_time = if clock_id == this.eval_libc_i32("CLOCK_REALTIME")? { diff --git a/tests/run-pass/concurrency/libc_pthread_cond.rs b/tests/run-pass/concurrency/libc_pthread_cond.rs index 83a651e6f04a..9b7a06b431c0 100644 --- a/tests/run-pass/concurrency/libc_pthread_cond.rs +++ b/tests/run-pass/concurrency/libc_pthread_cond.rs @@ -1,199 +1,75 @@ // ignore-windows: No libc on Windows +// ignore-macos: pthread_condattr_setclock is not supported on MacOS. // compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] +/// Test that conditional variable timeouts are working properly with both +/// monotonic and system clocks. extern crate libc; -use std::cell::UnsafeCell; -use std::mem::{self, MaybeUninit}; -use std::sync::Arc; -use std::thread; +use std::mem; +use std::time::Instant; -struct Mutex { - inner: UnsafeCell, -} +fn test_timed_wait_timeout_monotonic() { + unsafe { + let mut attr: libc::pthread_condattr_t = mem::zeroed(); + assert_eq!(libc::pthread_condattr_init(&mut attr as *mut _), 0); + assert_eq!(libc::pthread_condattr_setclock(&mut attr as *mut _, libc::CLOCK_MONOTONIC), 0); -unsafe impl Sync for Mutex {} - -impl std::fmt::Debug for Mutex { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Mutex") - } -} - -struct Cond { - inner: UnsafeCell, -} - -unsafe impl Sync for Cond {} - -impl std::fmt::Debug for Cond { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Cond") - } -} - -unsafe fn create_cond_attr_monotonic() -> libc::pthread_condattr_t { - let mut attr = MaybeUninit::::uninit(); - assert_eq!(libc::pthread_condattr_init(attr.as_mut_ptr()), 0); - assert_eq!(libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC), 0); - attr.assume_init() -} - -unsafe fn create_cond(attr: Option) -> Cond { - let cond: Cond = mem::zeroed(); - if let Some(mut attr) = attr { - assert_eq!(libc::pthread_cond_init(cond.inner.get() as *mut _, &attr as *const _), 0); + let mut cond: libc::pthread_cond_t = mem::zeroed(); + assert_eq!(libc::pthread_cond_init(&mut cond as *mut _, &attr as *const _), 0); assert_eq!(libc::pthread_condattr_destroy(&mut attr as *mut _), 0); - } else { - assert_eq!(libc::pthread_cond_init(cond.inner.get() as *mut _, 0 as *const _), 0); - } - cond -} -unsafe fn create_mutex() -> Mutex { - mem::zeroed() -} + let mut mutex: libc::pthread_mutex_t = mem::zeroed(); -unsafe fn create_timeout(seconds: i64) -> libc::timespec { - let mut now: libc::timespec = mem::zeroed(); - assert_eq!(libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut now), 0); - libc::timespec { tv_sec: now.tv_sec + seconds, tv_nsec: now.tv_nsec } -} - -fn test_pthread_condattr_t() { - unsafe { - let mut attr = create_cond_attr_monotonic(); - let mut clock_id = MaybeUninit::::uninit(); - assert_eq!(libc::pthread_condattr_getclock(&attr as *const _, clock_id.as_mut_ptr()), 0); - assert_eq!(clock_id.assume_init(), libc::CLOCK_MONOTONIC); - assert_eq!(libc::pthread_condattr_destroy(&mut attr as *mut _), 0); - } -} - -fn test_signal() { - unsafe { - let cond = Arc::new(create_cond(None)); - let mutex = Arc::new(create_mutex()); - - assert_eq!(libc::pthread_mutex_lock(mutex.inner.get() as *mut _), 0); - - let spawn_mutex = Arc::clone(&mutex); - let spawn_cond = Arc::clone(&cond); - let handle = thread::spawn(move || { - assert_eq!(libc::pthread_mutex_lock(spawn_mutex.inner.get() as *mut _), 0); - assert_eq!(libc::pthread_cond_signal(spawn_cond.inner.get() as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(spawn_mutex.inner.get() as *mut _), 0); - }); + let mut now: libc::timespec = mem::zeroed(); + assert_eq!(libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut now), 0); + let timeout = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: now.tv_nsec }; + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + let current_time = Instant::now(); assert_eq!( - libc::pthread_cond_wait(cond.inner.get() as *mut _, mutex.inner.get() as *mut _), - 0 - ); - assert_eq!(libc::pthread_mutex_unlock(mutex.inner.get() as *mut _), 0); - - handle.join().unwrap(); - - let mutex = Arc::try_unwrap(mutex).unwrap(); - assert_eq!(libc::pthread_mutex_destroy(mutex.inner.get() as *mut _), 0); - let cond = Arc::try_unwrap(cond).unwrap(); - assert_eq!(libc::pthread_cond_destroy(cond.inner.get() as *mut _), 0); - } -} - -fn test_broadcast() { - unsafe { - let cond = Arc::new(create_cond(None)); - let mutex = Arc::new(create_mutex()); - - assert_eq!(libc::pthread_mutex_lock(mutex.inner.get() as *mut _), 0); - - let spawn_mutex = Arc::clone(&mutex); - let spawn_cond = Arc::clone(&cond); - let handle = thread::spawn(move || { - assert_eq!(libc::pthread_mutex_lock(spawn_mutex.inner.get() as *mut _), 0); - assert_eq!(libc::pthread_cond_broadcast(spawn_cond.inner.get() as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(spawn_mutex.inner.get() as *mut _), 0); - }); - - assert_eq!( - libc::pthread_cond_wait(cond.inner.get() as *mut _, mutex.inner.get() as *mut _), - 0 - ); - assert_eq!(libc::pthread_mutex_unlock(mutex.inner.get() as *mut _), 0); - - handle.join().unwrap(); - - let mutex = Arc::try_unwrap(mutex).unwrap(); - assert_eq!(libc::pthread_mutex_destroy(mutex.inner.get() as *mut _), 0); - let cond = Arc::try_unwrap(cond).unwrap(); - assert_eq!(libc::pthread_cond_destroy(cond.inner.get() as *mut _), 0); - } -} - -fn test_timed_wait_timeout() { - unsafe { - let attr = create_cond_attr_monotonic(); - let cond = create_cond(Some(attr)); - let mutex = create_mutex(); - let timeout = create_timeout(1); - - assert_eq!(libc::pthread_mutex_lock(mutex.inner.get() as *mut _), 0); - assert_eq!( - libc::pthread_cond_timedwait( - cond.inner.get() as *mut _, - mutex.inner.get() as *mut _, - &timeout - ), + libc::pthread_cond_timedwait(&mut cond as *mut _, &mut mutex as *mut _, &timeout), libc::ETIMEDOUT ); - assert_eq!(libc::pthread_mutex_unlock(mutex.inner.get() as *mut _), 0); - assert_eq!(libc::pthread_mutex_destroy(mutex.inner.get() as *mut _), 0); - assert_eq!(libc::pthread_cond_destroy(cond.inner.get() as *mut _), 0); + assert!(current_time.elapsed().as_millis() >= 900); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_cond_destroy(&mut cond as *mut _), 0); } } -fn test_timed_wait_notimeout() { +fn test_timed_wait_timeout_realtime() { unsafe { - let attr = create_cond_attr_monotonic(); - let cond = Arc::new(create_cond(Some(attr))); - let mutex = Arc::new(create_mutex()); - let timeout = create_timeout(100); + let mut attr: libc::pthread_condattr_t = mem::zeroed(); + assert_eq!(libc::pthread_condattr_init(&mut attr as *mut _), 0); + assert_eq!(libc::pthread_condattr_setclock(&mut attr as *mut _, libc::CLOCK_REALTIME), 0); - assert_eq!(libc::pthread_mutex_lock(mutex.inner.get() as *mut _), 0); + let mut cond: libc::pthread_cond_t = mem::zeroed(); + assert_eq!(libc::pthread_cond_init(&mut cond as *mut _, &attr as *const _), 0); + assert_eq!(libc::pthread_condattr_destroy(&mut attr as *mut _), 0); - let spawn_mutex = Arc::clone(&mutex); - let spawn_cond = Arc::clone(&cond); - let handle = thread::spawn(move || { - assert_eq!(libc::pthread_mutex_lock(spawn_mutex.inner.get() as *mut _), 0); - assert_eq!(libc::pthread_cond_signal(spawn_cond.inner.get() as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(spawn_mutex.inner.get() as *mut _), 0); - }); + let mut mutex: libc::pthread_mutex_t = mem::zeroed(); + let mut now: libc::timespec = mem::zeroed(); + assert_eq!(libc::clock_gettime(libc::CLOCK_REALTIME, &mut now), 0); + let timeout = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: now.tv_nsec }; + + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + let current_time = Instant::now(); assert_eq!( - libc::pthread_cond_timedwait( - cond.inner.get() as *mut _, - mutex.inner.get() as *mut _, - &timeout - ), - 0 + libc::pthread_cond_timedwait(&mut cond as *mut _, &mut mutex as *mut _, &timeout), + libc::ETIMEDOUT ); - assert_eq!(libc::pthread_mutex_unlock(mutex.inner.get() as *mut _), 0); - - handle.join().unwrap(); - - let mutex = Arc::try_unwrap(mutex).unwrap(); - assert_eq!(libc::pthread_mutex_destroy(mutex.inner.get() as *mut _), 0); - let cond = Arc::try_unwrap(cond).unwrap(); - assert_eq!(libc::pthread_cond_destroy(cond.inner.get() as *mut _), 0); + assert!(current_time.elapsed().as_millis() >= 900); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_cond_destroy(&mut cond as *mut _), 0); } } fn main() { - test_pthread_condattr_t(); - test_signal(); - test_broadcast(); - test_timed_wait_timeout(); - test_timed_wait_notimeout(); + test_timed_wait_timeout_monotonic(); + test_timed_wait_timeout_realtime(); } diff --git a/tests/run-pass/concurrency/libc_pthread_cond.stderr b/tests/run-pass/concurrency/libc_pthread_cond.stderr deleted file mode 100644 index 2dbfb7721d36..000000000000 --- a/tests/run-pass/concurrency/libc_pthread_cond.stderr +++ /dev/null @@ -1,2 +0,0 @@ -warning: thread support is experimental. For example, Miri does not detect data races yet. - diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index e422a7fbdbc5..e3f3a03b11ae 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -31,7 +31,7 @@ fn check_barriers() { // Check if Rust conditional variables are working. /// The test taken from the Rust documentation. -fn check_conditional_variables() { +fn check_conditional_variables_notify_one() { let pair = Arc::new((Mutex::new(false), Condvar::new())); let pair2 = pair.clone(); @@ -52,17 +52,59 @@ fn check_conditional_variables() { } } +/// The test taken from the Rust documentation. +fn check_conditional_variables_notify_all() { + let pair = Arc::new((Mutex::new(false), Condvar::new())); + let pair2 = pair.clone(); + + thread::spawn(move || { + let (lock, cvar) = &*pair2; + let mut started = lock.lock().unwrap(); + *started = true; + // We notify the condvar that the value has changed. + cvar.notify_all(); + }); + + // Wait for the thread to start up. + let (lock, cvar) = &*pair; + let mut started = lock.lock().unwrap(); + // As long as the value inside the `Mutex` is `false`, we wait. + while !*started { + started = cvar.wait(started).unwrap(); + } +} + /// Test that waiting on a conditional variable with a timeout does not /// deadlock. -fn check_conditional_variables_timeout() { +fn check_conditional_variables_timed_wait_timeout() { let lock = Mutex::new(()); let cvar = Condvar::new(); let guard = lock.lock().unwrap(); let now = Instant::now(); - let _guard = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap().0; + let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap(); + assert!(timeout.timed_out()); assert!(now.elapsed().as_millis() >= 100); } +/// Test that signaling a conditional variable when waiting with a timeout works +/// as expected. +fn check_conditional_variables_timed_wait_notimeout() { + let pair = Arc::new((Mutex::new(()), Condvar::new())); + let pair2 = pair.clone(); + + let (lock, cvar) = &*pair; + let guard = lock.lock().unwrap(); + + let handle = thread::spawn(move || { + let (_lock, cvar) = &*pair2; + cvar.notify_one(); + }); + + let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap(); + assert!(!timeout.timed_out()); + handle.join().unwrap(); +} + // Check if locks are working. fn check_mutex() { @@ -218,8 +260,10 @@ fn check_once() { fn main() { check_barriers(); - check_conditional_variables(); - check_conditional_variables_timeout(); + check_conditional_variables_notify_one(); + check_conditional_variables_notify_all(); + check_conditional_variables_timed_wait_timeout(); + check_conditional_variables_timed_wait_notimeout(); check_mutex(); check_rwlock_write(); check_rwlock_read_no_deadlock(); From 0bbac1275177176c6bb1a8640b5ef34dbb5c5074 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 18 May 2020 16:28:19 +0200 Subject: [PATCH 2092/5092] Change how the time is handled. --- src/machine.rs | 8 +------- src/shims/sync.rs | 10 ++++------ src/sync.rs | 5 +---- src/thread.rs | 47 ++++++++++++++++++++++++++++++----------------- 4 files changed, 36 insertions(+), 34 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 4fb08cd259b6..51aa7ae31047 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -5,7 +5,7 @@ use std::borrow::Cow; use std::cell::RefCell; use std::num::NonZeroU64; use std::rc::Rc; -use std::time::{Instant, SystemTime}; +use std::time::Instant; use std::fmt; use log::trace; @@ -251,11 +251,6 @@ pub struct Evaluator<'mir, 'tcx> { /// The "time anchor" for this machine's monotone clock (for `Instant` simulation). pub(crate) time_anchor: Instant, - /// The approximate system time when "time anchor" was created. This is used - /// for converting system time to monotone time so that we can simplify the - /// thread scheduler to deal only with a single representation of time. - pub(crate) time_anchor_timestamp: SystemTime, - /// The set of threads. pub(crate) threads: ThreadManager<'mir, 'tcx>, @@ -286,7 +281,6 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { dir_handler: Default::default(), panic_payload: None, time_anchor: Instant::now(), - time_anchor_timestamp: SystemTime::now(), layouts, threads: ThreadManager::default(), } diff --git a/src/shims/sync.rs b/src/shims/sync.rs index a586be8139ba..5432c76dfe71 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -1,10 +1,11 @@ -use std::time::{Duration, SystemTime}; use std::convert::TryInto; +use std::time::{Duration, SystemTime}; use rustc_middle::ty::{layout::TyAndLayout, TyKind, TypeAndMut}; use rustc_target::abi::{LayoutOf, Size}; use crate::stacked_borrows::Tag; +use crate::thread::Time; use crate::*; @@ -734,12 +735,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; let timeout_time = if clock_id == this.eval_libc_i32("CLOCK_REALTIME")? { - let time_anchor_since_epoch = - this.machine.time_anchor_timestamp.duration_since(SystemTime::UNIX_EPOCH).unwrap(); - let duration_since_time_anchor = duration.checked_sub(time_anchor_since_epoch).unwrap(); - this.machine.time_anchor.checked_add(duration_since_time_anchor).unwrap() + Time::RealTime(SystemTime::UNIX_EPOCH.checked_add(duration).unwrap()) } else if clock_id == this.eval_libc_i32("CLOCK_MONOTONIC")? { - this.machine.time_anchor.checked_add(duration).unwrap() + Time::Monotonic(this.machine.time_anchor.checked_add(duration).unwrap()) } else { throw_ub_format!("Unsupported clock id."); }; diff --git a/src/sync.rs b/src/sync.rs index 88b5d6c060dd..e05d111cb283 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -1,7 +1,6 @@ use std::collections::{hash_map::Entry, HashMap, VecDeque}; use std::convert::TryFrom; use std::num::NonZeroU32; -use std::time::Instant; use rustc_index::vec::{Idx, IndexVec}; @@ -76,8 +75,6 @@ struct CondvarWaiter { thread: ThreadId, /// The mutex on which the thread is waiting. mutex: MutexId, - /// The moment in time when the waiter should time out. - timeout: Option, } /// The conditional variable state. @@ -280,7 +277,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let waiters = &mut this.machine.threads.sync.condvars[id].waiters; assert!(waiters.iter().all(|waiter| waiter.thread != thread), "thread is already waiting"); - waiters.push_back(CondvarWaiter { thread, mutex, timeout: None }); + waiters.push_back(CondvarWaiter { thread, mutex }); } /// Wake up some thread (if there is any) sleeping on the conditional diff --git a/src/thread.rs b/src/thread.rs index f67de48b710d..69b31b541ae5 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -4,7 +4,7 @@ use std::cell::RefCell; use std::collections::hash_map::Entry; use std::convert::TryFrom; use std::num::TryFromIntError; -use std::time::Instant; +use std::time::{Duration, Instant, SystemTime}; use log::trace; @@ -159,13 +159,30 @@ impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> { } } +#[derive(Debug)] +pub enum Time { + Monotonic(Instant), + RealTime(SystemTime), +} + +impl Time { + /// How long do we have to wait from now until the specified time? + fn get_wait_time(&self) -> Duration { + match self { + Time::Monotonic(instant) => instant.saturating_duration_since(Instant::now()), + Time::RealTime(time) => + time.duration_since(SystemTime::now()).unwrap_or(Duration::new(0, 0)), + } + } +} + /// Callbacks are used to implement timeouts. For example, waiting on a /// conditional variable with a timeout creates a callback that is called after /// the specified time and unblocks the thread. If another thread signals on the /// conditional variable, the signal handler deletes the callback. struct TimeoutCallbackInfo<'mir, 'tcx> { /// The callback should be called no earlier than this time. - call_time: Instant, + call_time: Time, /// The called function. callback: TimeoutCallback<'mir, 'tcx>, } @@ -362,11 +379,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { fn register_timeout_callback( &mut self, thread: ThreadId, - call_time: Instant, + call_time: Time, callback: TimeoutCallback<'mir, 'tcx>, ) { self.timeout_callbacks - .insert(thread, TimeoutCallbackInfo { call_time: call_time, callback: callback }) + .insert(thread, TimeoutCallbackInfo { call_time, callback }) .unwrap_none(); } @@ -376,13 +393,12 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Get a callback that is ready to be called. - fn get_callback(&mut self) -> Option<(ThreadId, TimeoutCallback<'mir, 'tcx>)> { - let current_time = Instant::now(); + fn get_ready_callback(&mut self) -> Option<(ThreadId, TimeoutCallback<'mir, 'tcx>)> { // We use a for loop here to make the scheduler more deterministic. for thread in self.threads.indices() { match self.timeout_callbacks.entry(thread) { Entry::Occupied(entry) => - if current_time >= entry.get().call_time { + if entry.get().call_time.get_wait_time() == Duration::new(0, 0) { return Some((thread, entry.remove().callback)); }, Entry::Vacant(_) => {} @@ -445,18 +461,14 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } // We have not found a thread to execute. if self.threads.iter().all(|thread| thread.state == ThreadState::Terminated) { - unreachable!(); - } else if let Some(next_call_time) = - self.timeout_callbacks.values().min_by_key(|info| info.call_time) + unreachable!("all threads terminated without the main thread terminating?!"); + } else if let Some(sleep_time) = + self.timeout_callbacks.values().map(|info| info.call_time.get_wait_time()).min() { // All threads are currently blocked, but we have unexecuted // timeout_callbacks, which may unblock some of the threads. Hence, // sleep until the first callback. - if let Some(sleep_time) = - next_call_time.call_time.checked_duration_since(Instant::now()) - { - std::thread::sleep(sleep_time); - } + std::thread::sleep(sleep_time); Ok(SchedulingAction::ExecuteTimeoutCallback) } else { throw_machine_stop!(TerminationInfo::Deadlock); @@ -650,7 +662,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn register_timeout_callback( &mut self, thread: ThreadId, - call_time: Instant, + call_time: Time, callback: TimeoutCallback<'mir, 'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -669,7 +681,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn run_timeout_callback(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let (thread, callback) = this.machine.threads.get_callback().expect("no callback found"); + let (thread, callback) = + this.machine.threads.get_ready_callback().expect("no callback found"); let old_thread = this.set_active_thread(thread)?; callback(this)?; this.set_active_thread(old_thread)?; From 3da61fa4274b370dc2c72ce8b7bdbbfeb836110a Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 18 May 2020 16:39:19 +0200 Subject: [PATCH 2093/5092] Add comments explaining the declare_id macro. --- src/sync.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sync.rs b/src/sync.rs index e05d111cb283..7957faeb7e3d 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -6,6 +6,10 @@ use rustc_index::vec::{Idx, IndexVec}; use crate::*; +/// We cannot use the `newtype_index!` macro because we have to use 0 as a +/// sentinel value meaning that the identifier is not assigned. This is because +/// the pthreads static initializers initialize memory with zeros (see the +/// `src/shims/sync.rs` file). macro_rules! declare_id { ($name: ident) => { /// 0 is used to indicate that the id was not yet assigned and, @@ -22,9 +26,13 @@ macro_rules! declare_id { impl Idx for $name { fn new(idx: usize) -> Self { + // We use 0 as a sentinel value (see the comment above) and, + // therefore, need to shift by one when converting from an index + // into a vector. $name(NonZeroU32::new(u32::try_from(idx).unwrap() + 1).unwrap()) } fn index(self) -> usize { + // See the comment in `Self::new`. usize::try_from(self.0.get() - 1).unwrap() } } From fdfd56b75b2aefefe6545eed704550ff5de3bdd7 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 18 May 2020 17:18:15 +0200 Subject: [PATCH 2094/5092] Small changes. --- src/shims/sync.rs | 63 +++++++---------- src/sync.rs | 70 +++++++++++++------ src/thread.rs | 7 +- .../libc_pthread_rwlock_read_wrong_owner.rs | 32 +++++++++ .../libc_pthread_rwlock_write_wrong_owner.rs | 32 +++++++++ 5 files changed, 143 insertions(+), 61 deletions(-) create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_read_wrong_owner.rs create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_write_wrong_owner.rs diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 5432c76dfe71..ee2579c22f17 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -202,6 +202,7 @@ fn condattr_set_clock_id<'mir, 'tcx: 'mir>( // Our chosen memory layout for the emulated conditional variable (does not have // to match the platform layout!): +// bytes 0-3: reserved for signature on macOS // bytes 4-7: the conditional variable id as u32 or 0 if id is not assigned yet. // bytes 8-11: the clock id constant as i32 @@ -275,19 +276,13 @@ fn release_cond_mutex<'mir, 'tcx: 'mir>( active_thread: ThreadId, mutex: MutexId, ) -> InterpResult<'tcx> { - if let Some((owner_thread, current_locked_count)) = ecx.mutex_unlock(mutex) { - if current_locked_count != 0 { - throw_unsup_format!("awaiting on multiple times acquired lock is not supported"); + if let Some((old_owner_thread, old_locked_count)) = ecx.mutex_unlock(mutex)? { + if old_locked_count != 1 { + throw_unsup_format!("awaiting on a lock acquired multiple times is not supported"); } - if owner_thread != active_thread { + if old_owner_thread != active_thread { throw_ub_format!("awaiting on a mutex owned by a different thread"); } - if let Some(thread) = ecx.mutex_dequeue(mutex) { - // We have at least one thread waiting on this mutex. Transfer - // ownership to it. - ecx.mutex_lock(mutex, thread); - ecx.unblock_thread(thread)?; - } } else { throw_ub_format!("awaiting on unlocked mutex"); } @@ -349,7 +344,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutexattr_get_kind(this, attr_op)?.not_undef()? }; - let _ = mutex_get_or_create_id(this, mutex_op)?; + // Write 0 to use the same code path as the static initializers. + mutex_set_id(this, mutex_op, Scalar::from_i32(0))?; + mutex_set_kind(this, mutex_op, kind)?; Ok(0) @@ -427,19 +424,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; let id = mutex_get_or_create_id(this, mutex_op)?; - if let Some((owner_thread, current_locked_count)) = this.mutex_unlock(id) { - if owner_thread != this.get_active_thread()? { + if let Some((old_owner_thread, _old_locked_count)) = this.mutex_unlock(id)? { + if old_owner_thread != this.get_active_thread()? { throw_ub_format!("called pthread_mutex_unlock on a mutex owned by another thread"); } - if current_locked_count == 0 { - // The mutex is unlocked. - if let Some(thread) = this.mutex_dequeue(id) { - // We have at least one thread waiting on this mutex. Transfer - // ownership to it. - this.mutex_lock(id, thread); - this.unblock_thread(thread)?; - } - } Ok(0) } else { if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { @@ -476,11 +464,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let active_thread = this.get_active_thread()?; if this.rwlock_is_write_locked(id) { - this.rwlock_enqueue_reader(id, active_thread); - this.block_thread(active_thread)?; + this.rwlock_enqueue_and_block_reader(id, active_thread)?; Ok(0) } else { - this.rwlock_reader_add(id, active_thread); + this.rwlock_reader_lock(id, active_thread); Ok(0) } } @@ -494,7 +481,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.rwlock_is_write_locked(id) { this.eval_libc_i32("EBUSY") } else { - this.rwlock_reader_add(id, active_thread); + this.rwlock_reader_lock(id, active_thread); Ok(0) } } @@ -506,10 +493,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let active_thread = this.get_active_thread()?; if this.rwlock_is_locked(id) { - this.block_thread(active_thread)?; - this.rwlock_enqueue_writer(id, active_thread); + this.rwlock_enqueue_and_block_writer(id, active_thread)?; } else { - this.rwlock_writer_set(id, active_thread); + this.rwlock_writer_lock(id, active_thread); } Ok(0) @@ -524,7 +510,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.rwlock_is_locked(id) { this.eval_libc_i32("EBUSY") } else { - this.rwlock_writer_set(id, active_thread); + this.rwlock_writer_lock(id, active_thread); Ok(0) } } @@ -535,18 +521,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let id = rwlock_get_or_create_id(this, rwlock_op)?; let active_thread = this.get_active_thread()?; - if this.rwlock_reader_remove(id, active_thread) { + if this.rwlock_reader_unlock(id, active_thread) { // The thread was a reader. if this.rwlock_is_locked(id) { // No more readers owning the lock. Give it to a writer if there // is any. if let Some(writer) = this.rwlock_dequeue_writer(id) { this.unblock_thread(writer)?; - this.rwlock_writer_set(id, writer); + this.rwlock_writer_lock(id, writer); } } Ok(0) - } else if Some(active_thread) == this.rwlock_writer_remove(id) { + } else if Some(active_thread) == this.rwlock_writer_unlock(id) { // The thread was a writer. // // We are prioritizing writers here against the readers. As a @@ -555,12 +541,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(writer) = this.rwlock_dequeue_writer(id) { // Give the lock to another writer. this.unblock_thread(writer)?; - this.rwlock_writer_set(id, writer); + this.rwlock_writer_lock(id, writer); } else { // Give the lock to all readers. while let Some(reader) = this.rwlock_dequeue_reader(id) { this.unblock_thread(reader)?; - this.rwlock_reader_add(id, reader); + this.rwlock_reader_lock(id, reader); } } Ok(0) @@ -586,6 +572,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_condattr_init(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // The default value of the clock attribute shall refer to the system + // clock. + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_condattr_setclock.html let default_clock_id = this.eval_libc("CLOCK_REALTIME")?; condattr_set_clock_id(this, attr_op, default_clock_id)?; @@ -647,7 +636,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx condattr_get_clock_id(this, attr_op)?.not_undef()? }; - let _ = cond_get_or_create_id(this, cond_op)?; + // Write 0 to use the same code path as the static initializers. + cond_set_id(this, cond_op, Scalar::from_i32(0))?; + cond_set_clock_id(this, cond_op, clock_id)?; Ok(0) diff --git a/src/sync.rs b/src/sync.rs index 7957faeb7e3d..a71d4597c669 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -1,6 +1,7 @@ use std::collections::{hash_map::Entry, HashMap, VecDeque}; use std::convert::TryFrom; use std::num::NonZeroU32; +use std::ops::Not; use rustc_index::vec::{Idx, IndexVec}; @@ -142,34 +143,47 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex.lock_count = mutex.lock_count.checked_add(1).unwrap(); } - /// Unlock by decreasing the lock count. If the lock count reaches 0, unset - /// the owner. - fn mutex_unlock(&mut self, id: MutexId) -> Option<(ThreadId, usize)> { + /// Try unlocking by decreasing the lock count and returning the old owner + /// and the old lock count. If the lock count reaches 0, release the lock + /// and potentially give to a new owner. If the lock was not locked, return + /// `None`. + /// + /// Note: It is the caller's responsibility to check that the thread that + /// unlocked the lock actually is the same one, which owned it. + fn mutex_unlock(&mut self, id: MutexId) -> InterpResult<'tcx, Option<(ThreadId, usize)>> { let this = self.eval_context_mut(); let mutex = &mut this.machine.threads.sync.mutexes[id]; if let Some(current_owner) = mutex.owner { - mutex.lock_count = mutex - .lock_count + // Mutex is locked. + let old_lock_count = mutex.lock_count; + mutex.lock_count = old_lock_count .checked_sub(1) .expect("invariant violation: lock_count == 0 iff the thread is unlocked"); if mutex.lock_count == 0 { mutex.owner = None; + // The mutex is completely unlocked. Try transfering ownership + // to another thread. + if let Some(new_owner) = this.mutex_dequeue(id) { + this.mutex_lock(id, new_owner); + this.unblock_thread(new_owner)?; + } } - Some((current_owner, mutex.lock_count)) + Ok(Some((current_owner, old_lock_count))) } else { - None + // Mutex is unlocked. + Ok(None) } } #[inline] - /// Take a thread out the queue waiting for the lock. + /// Put the thread into the queue waiting for the lock. fn mutex_enqueue(&mut self, id: MutexId, thread: ThreadId) { let this = self.eval_context_mut(); this.machine.threads.sync.mutexes[id].queue.push_back(thread); } #[inline] - /// Take a thread out the queue waiting for the lock. + /// Take a thread out of the queue waiting for the lock. fn mutex_dequeue(&mut self, id: MutexId) -> Option { let this = self.eval_context_mut(); this.machine.threads.sync.mutexes[id].queue.pop_front() @@ -187,7 +201,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn rwlock_is_locked(&mut self, id: RwLockId) -> bool { let this = self.eval_context_mut(); this.machine.threads.sync.rwlocks[id].writer.is_some() - || !this.machine.threads.sync.rwlocks[id].readers.is_empty() + || this.machine.threads.sync.rwlocks[id].readers.is_empty().not() } #[inline] @@ -197,16 +211,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.threads.sync.rwlocks[id].writer.is_some() } - /// Add a reader that collectively with other readers owns the lock. - fn rwlock_reader_add(&mut self, id: RwLockId, reader: ThreadId) { + /// Read-lock the lock by adding the `reader` the list of threads that own + /// this lock. + fn rwlock_reader_lock(&mut self, id: RwLockId, reader: ThreadId) { let this = self.eval_context_mut(); assert!(!this.rwlock_is_write_locked(id), "the lock is write locked"); let count = this.machine.threads.sync.rwlocks[id].readers.entry(reader).or_insert(0); - *count += 1; + *count = count.checked_add(1).expect("the reader counter overflowed"); } - /// Try removing the reader. Returns `true` if succeeded. - fn rwlock_reader_remove(&mut self, id: RwLockId, reader: ThreadId) -> bool { + /// Try read-unlock the lock for `reader`. Returns `true` if succeeded, + /// `false` if this `reader` did not hold the lock. + fn rwlock_reader_unlock(&mut self, id: RwLockId, reader: ThreadId) -> bool { let this = self.eval_context_mut(); match this.machine.threads.sync.rwlocks[id].readers.entry(reader) { Entry::Occupied(mut entry) => { @@ -222,15 +238,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[inline] - /// Put the reader in the queue waiting for the lock. - fn rwlock_enqueue_reader(&mut self, id: RwLockId, reader: ThreadId) { + /// Put the reader in the queue waiting for the lock and block it. + fn rwlock_enqueue_and_block_reader( + &mut self, + id: RwLockId, + reader: ThreadId, + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); assert!(this.rwlock_is_write_locked(id), "queueing on not write locked lock"); this.machine.threads.sync.rwlocks[id].reader_queue.push_back(reader); + this.block_thread(reader) } #[inline] - /// Take the reader out the queue waiting for the lock. + /// Take a reader out the queue waiting for the lock. fn rwlock_dequeue_reader(&mut self, id: RwLockId) -> Option { let this = self.eval_context_mut(); this.machine.threads.sync.rwlocks[id].reader_queue.pop_front() @@ -238,25 +259,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] /// Lock by setting the writer that owns the lock. - fn rwlock_writer_set(&mut self, id: RwLockId, writer: ThreadId) { + fn rwlock_writer_lock(&mut self, id: RwLockId, writer: ThreadId) { let this = self.eval_context_mut(); assert!(!this.rwlock_is_locked(id), "the lock is already locked"); this.machine.threads.sync.rwlocks[id].writer = Some(writer); } #[inline] - /// Try removing the writer. - fn rwlock_writer_remove(&mut self, id: RwLockId) -> Option { + /// Try to unlock by removing the writer. + fn rwlock_writer_unlock(&mut self, id: RwLockId) -> Option { let this = self.eval_context_mut(); this.machine.threads.sync.rwlocks[id].writer.take() } #[inline] /// Put the writer in the queue waiting for the lock. - fn rwlock_enqueue_writer(&mut self, id: RwLockId, writer: ThreadId) { + fn rwlock_enqueue_and_block_writer( + &mut self, + id: RwLockId, + writer: ThreadId, + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); assert!(this.rwlock_is_locked(id), "queueing on unlocked lock"); this.machine.threads.sync.rwlocks[id].writer_queue.push_back(writer); + this.block_thread(writer) } #[inline] diff --git a/src/thread.rs b/src/thread.rs index 69b31b541ae5..e61761e599cd 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -32,7 +32,7 @@ pub enum SchedulingAction { Stop, } -/// Timeout timeout_callbacks can be created by synchronization primitives to tell the +/// Timeout callbacks can be created by synchronization primitives to tell the /// scheduler that they should be called once some period of time passes. type TimeoutCallback<'mir, 'tcx> = Box>) -> InterpResult<'tcx> + 'tcx>; @@ -189,7 +189,7 @@ struct TimeoutCallbackInfo<'mir, 'tcx> { impl<'mir, 'tcx> std::fmt::Debug for TimeoutCallbackInfo<'mir, 'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "CallBack({:?})", self.call_time) + write!(f, "TimeoutCallback({:?})", self.call_time) } } @@ -394,7 +394,8 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Get a callback that is ready to be called. fn get_ready_callback(&mut self) -> Option<(ThreadId, TimeoutCallback<'mir, 'tcx>)> { - // We use a for loop here to make the scheduler more deterministic. + // We iterate over all threads in the order of their indices because + // this allows us to have a deterministic scheduler. for thread in self.threads.indices() { match self.timeout_callbacks.entry(thread) { Entry::Occupied(entry) => diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_read_wrong_owner.rs b/tests/compile-fail/sync/libc_pthread_rwlock_read_wrong_owner.rs new file mode 100644 index 000000000000..a73a8496a329 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_read_wrong_owner.rs @@ -0,0 +1,32 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +use std::cell::UnsafeCell; +use std::sync::Arc; +use std::thread; + +struct RwLock(UnsafeCell); + +unsafe impl Send for RwLock {} +unsafe impl Sync for RwLock {} + +fn new_lock() -> Arc { + Arc::new(RwLock(UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER))) +} + +fn main() { + unsafe { + let lock = new_lock(); + assert_eq!(libc::pthread_rwlock_rdlock(lock.0.get() as *mut _), 0); + + let lock_copy = lock.clone(); + thread::spawn(move || { + assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: Undefined Behavior: unlocked an rwlock that was not locked by the active thread + }) + .join() + .unwrap(); + } +} diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_wrong_owner.rs b/tests/compile-fail/sync/libc_pthread_rwlock_write_wrong_owner.rs new file mode 100644 index 000000000000..663dedb6f6fc --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_write_wrong_owner.rs @@ -0,0 +1,32 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +use std::cell::UnsafeCell; +use std::sync::Arc; +use std::thread; + +struct RwLock(UnsafeCell); + +unsafe impl Send for RwLock {} +unsafe impl Sync for RwLock {} + +fn new_lock() -> Arc { + Arc::new(RwLock(UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER))) +} + +fn main() { + unsafe { + let lock = new_lock(); + assert_eq!(libc::pthread_rwlock_wrlock(lock.0.get() as *mut _), 0); + + let lock_copy = lock.clone(); + thread::spawn(move || { + assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: Undefined Behavior: unlocked an rwlock that was not locked by the active thread + }) + .join() + .unwrap(); + } +} From 0838347d8f77091ffb5a30606010d0bbedda22a4 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Tue, 19 May 2020 16:26:42 +0200 Subject: [PATCH 2095/5092] Change the scheduling to execute timeout callbacks first. --- src/thread.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/thread.rs b/src/thread.rs index e61761e599cd..70c2419c4d49 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -441,6 +441,22 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } return Ok(SchedulingAction::Stop); } + // At least for `pthread_cond_timedwait` we need to report timeout when + // the function is called already after the specified time even if a + // signal is received before the thread gets scheduled. Therefore, we + // need to schedule all timeout callbacks before we continue regular + // execution. + // + // Documentation: + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html# + if let Some(sleep_time) = + self.timeout_callbacks.values().map(|info| info.call_time.get_wait_time()).min() + { + if sleep_time == Duration::new(0, 0) { + return Ok(SchedulingAction::ExecuteTimeoutCallback); + } + } + // No callbacks scheduled, pick a regular thread to execute. if self.threads[self.active_thread].state == ThreadState::Enabled && !self.yield_active_thread { From 8b5a9836be5b115f27f48406f68bf64d931ceabc Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Tue, 19 May 2020 16:47:25 +0200 Subject: [PATCH 2096/5092] Small changes. --- src/shims/sync.rs | 27 ++++++++---- src/sync.rs | 1 + .../run-pass/concurrency/libc_pthread_cond.rs | 42 ++++--------------- tests/run-pass/concurrency/sync.rs | 5 ++- 4 files changed, 30 insertions(+), 45 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index ee2579c22f17..f34799f74251 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -254,7 +254,8 @@ fn cond_set_clock_id<'mir, 'tcx: 'mir>( set_at_offset(ecx, cond_op, 8, clock_id, ecx.machine.layouts.i32, PTHREAD_COND_T_MIN_SIZE) } -/// Try to reacquire the mutex associated with the condition variable after we were signaled. +/// Try to reacquire the mutex associated with the condition variable after we +/// were signaled. fn reacquire_cond_mutex<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, thread: ThreadId, @@ -269,6 +270,17 @@ fn reacquire_cond_mutex<'mir, 'tcx: 'mir>( Ok(()) } +/// Reacquire the conditional variable and remove the timeout callback if any +/// was registered. +fn post_cond_signal<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + thread: ThreadId, + mutex: MutexId, +) -> InterpResult<'tcx> { + reacquire_cond_mutex(ecx, thread, mutex)?; + ecx.unregister_timeout_callback_if_exists(thread) +} + /// Release the mutex associated with the condition variable because we are /// entering the waiting state. fn release_cond_mutex<'mir, 'tcx: 'mir>( @@ -648,8 +660,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let id = cond_get_or_create_id(this, cond_op)?; if let Some((thread, mutex)) = this.condvar_signal(id) { - reacquire_cond_mutex(this, thread, mutex)?; - this.unregister_timeout_callback_if_exists(thread)?; + post_cond_signal(this, thread, mutex)?; } Ok(0) @@ -660,8 +671,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let id = cond_get_or_create_id(this, cond_op)?; while let Some((thread, mutex)) = this.condvar_signal(id) { - reacquire_cond_mutex(this, thread, mutex)?; - this.unregister_timeout_callback_if_exists(thread)?; + post_cond_signal(this, thread, mutex)?; } Ok(0) @@ -730,7 +740,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if clock_id == this.eval_libc_i32("CLOCK_MONOTONIC")? { Time::Monotonic(this.machine.time_anchor.checked_add(duration).unwrap()) } else { - throw_ub_format!("Unsupported clock id."); + throw_unsup_format!("Unsupported clock id."); }; // Register the timeout callback. @@ -738,13 +748,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx active_thread, timeout_time, Box::new(move |ecx| { - // Try to reacquire the mutex. + // We are not waiting for the condvar any more, wait for the + // mutex instead. reacquire_cond_mutex(ecx, active_thread, mutex_id)?; // Remove the thread from the conditional variable. ecx.condvar_remove_waiter(id, active_thread); - // Set the timeout value. + // Set the return value: we timed out. let timeout = ecx.eval_libc_i32("ETIMEDOUT")?; ecx.write_scalar(Scalar::from_i32(timeout), dest)?; diff --git a/src/sync.rs b/src/sync.rs index a71d4597c669..cbae29bdbb36 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -179,6 +179,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Put the thread into the queue waiting for the lock. fn mutex_enqueue(&mut self, id: MutexId, thread: ThreadId) { let this = self.eval_context_mut(); + assert!(this.mutex_is_locked(id), "queing on unlocked mutex"); this.machine.threads.sync.mutexes[id].queue.push_back(thread); } diff --git a/tests/run-pass/concurrency/libc_pthread_cond.rs b/tests/run-pass/concurrency/libc_pthread_cond.rs index 9b7a06b431c0..39b6a7e4ef80 100644 --- a/tests/run-pass/concurrency/libc_pthread_cond.rs +++ b/tests/run-pass/concurrency/libc_pthread_cond.rs @@ -11,11 +11,11 @@ extern crate libc; use std::mem; use std::time::Instant; -fn test_timed_wait_timeout_monotonic() { +fn test_timed_wait_timeout(clock_id: i32) { unsafe { let mut attr: libc::pthread_condattr_t = mem::zeroed(); assert_eq!(libc::pthread_condattr_init(&mut attr as *mut _), 0); - assert_eq!(libc::pthread_condattr_setclock(&mut attr as *mut _, libc::CLOCK_MONOTONIC), 0); + assert_eq!(libc::pthread_condattr_setclock(&mut attr as *mut _, clock_id), 0); let mut cond: libc::pthread_cond_t = mem::zeroed(); assert_eq!(libc::pthread_cond_init(&mut cond as *mut _, &attr as *const _), 0); @@ -24,7 +24,7 @@ fn test_timed_wait_timeout_monotonic() { let mut mutex: libc::pthread_mutex_t = mem::zeroed(); let mut now: libc::timespec = mem::zeroed(); - assert_eq!(libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut now), 0); + assert_eq!(libc::clock_gettime(clock_id, &mut now), 0); let timeout = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: now.tv_nsec }; assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); @@ -33,36 +33,8 @@ fn test_timed_wait_timeout_monotonic() { libc::pthread_cond_timedwait(&mut cond as *mut _, &mut mutex as *mut _, &timeout), libc::ETIMEDOUT ); - assert!(current_time.elapsed().as_millis() >= 900); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_cond_destroy(&mut cond as *mut _), 0); - } -} - -fn test_timed_wait_timeout_realtime() { - unsafe { - let mut attr: libc::pthread_condattr_t = mem::zeroed(); - assert_eq!(libc::pthread_condattr_init(&mut attr as *mut _), 0); - assert_eq!(libc::pthread_condattr_setclock(&mut attr as *mut _, libc::CLOCK_REALTIME), 0); - - let mut cond: libc::pthread_cond_t = mem::zeroed(); - assert_eq!(libc::pthread_cond_init(&mut cond as *mut _, &attr as *const _), 0); - assert_eq!(libc::pthread_condattr_destroy(&mut attr as *mut _), 0); - - let mut mutex: libc::pthread_mutex_t = mem::zeroed(); - - let mut now: libc::timespec = mem::zeroed(); - assert_eq!(libc::clock_gettime(libc::CLOCK_REALTIME, &mut now), 0); - let timeout = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: now.tv_nsec }; - - assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - let current_time = Instant::now(); - assert_eq!( - libc::pthread_cond_timedwait(&mut cond as *mut _, &mut mutex as *mut _, &timeout), - libc::ETIMEDOUT - ); - assert!(current_time.elapsed().as_millis() >= 900); + let elapsed_time = current_time.elapsed().as_millis(); + assert!(900 <= elapsed_time && elapsed_time <= 1100); assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); assert_eq!(libc::pthread_cond_destroy(&mut cond as *mut _), 0); @@ -70,6 +42,6 @@ fn test_timed_wait_timeout_realtime() { } fn main() { - test_timed_wait_timeout_monotonic(); - test_timed_wait_timeout_realtime(); + test_timed_wait_timeout(libc::CLOCK_MONOTONIC); + test_timed_wait_timeout(libc::CLOCK_REALTIME); } diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index e3f3a03b11ae..5c19eee342f1 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -35,8 +35,9 @@ fn check_conditional_variables_notify_one() { let pair = Arc::new((Mutex::new(false), Condvar::new())); let pair2 = pair.clone(); - // Inside of our lock, spawn a new thread, and then wait for it to start. + // Spawn a new thread. thread::spawn(move || { + thread::yield_now(); let (lock, cvar) = &*pair2; let mut started = lock.lock().unwrap(); *started = true; @@ -44,7 +45,7 @@ fn check_conditional_variables_notify_one() { cvar.notify_one(); }); - // Wait for the thread to start up. + // Wait for the thread to fully start up. let (lock, cvar) = &*pair; let mut started = lock.lock().unwrap(); while !*started { From babedc938e2c9a681737b3468b9124a58b2ec677 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Tue, 19 May 2020 18:33:26 +0200 Subject: [PATCH 2097/5092] Rewrite notify all test. --- tests/run-pass/concurrency/sync.rs | 39 ++++++++++++++++++------------ 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index 5c19eee342f1..faf47851bd01 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -53,25 +53,32 @@ fn check_conditional_variables_notify_one() { } } -/// The test taken from the Rust documentation. fn check_conditional_variables_notify_all() { - let pair = Arc::new((Mutex::new(false), Condvar::new())); - let pair2 = pair.clone(); + let pair = Arc::new(((Mutex::new(())), Condvar::new())); - thread::spawn(move || { - let (lock, cvar) = &*pair2; - let mut started = lock.lock().unwrap(); - *started = true; - // We notify the condvar that the value has changed. - cvar.notify_all(); - }); + // Spawn threads and block them on the conditional variable. + let handles: Vec<_> = (0..5) + .map(|_| { + let pair2 = pair.clone(); + thread::spawn(move || { + let (lock, cvar) = &*pair2; + let guard = lock.lock().unwrap(); + // Block waiting on the conditional variable. + let _ = cvar.wait(guard).unwrap(); + }) + }) + .inspect(|_| { + thread::yield_now(); + thread::yield_now(); + }) + .collect(); - // Wait for the thread to start up. - let (lock, cvar) = &*pair; - let mut started = lock.lock().unwrap(); - // As long as the value inside the `Mutex` is `false`, we wait. - while !*started { - started = cvar.wait(started).unwrap(); + let (_, cvar) = &*pair; + // Unblock all threads. + cvar.notify_all(); + + for handle in handles { + handle.join().unwrap(); } } From bd97074517c6ba334247b70f33199e40374c223a Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Tue, 19 May 2020 18:44:32 +0200 Subject: [PATCH 2098/5092] Small changes. --- src/shims/sync.rs | 79 ++++++++++++------- src/sync.rs | 16 +++- src/thread.rs | 11 ++- .../libc_pthread_mutex_normal_deadlock.rs | 4 +- .../sync/libc_pthread_mutex_wrong_owner.rs | 2 +- tests/run-pass/concurrency/sync.rs | 7 +- 6 files changed, 77 insertions(+), 42 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index f34799f74251..4fe353473981 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -288,15 +288,12 @@ fn release_cond_mutex<'mir, 'tcx: 'mir>( active_thread: ThreadId, mutex: MutexId, ) -> InterpResult<'tcx> { - if let Some((old_owner_thread, old_locked_count)) = ecx.mutex_unlock(mutex)? { + if let Some(old_locked_count) = ecx.mutex_unlock(mutex, active_thread)? { if old_locked_count != 1 { throw_unsup_format!("awaiting on a lock acquired multiple times is not supported"); } - if old_owner_thread != active_thread { - throw_ub_format!("awaiting on a mutex owned by a different thread"); - } } else { - throw_ub_format!("awaiting on unlocked mutex"); + throw_ub_format!("awaiting on unlocked or owned by a different thread mutex"); } ecx.block_thread(active_thread)?; Ok(()) @@ -321,7 +318,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let kind = this.read_scalar(kind_op)?.not_undef()?; - if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? + if kind == this.eval_libc("PTHREAD_MUTEX_DEFAULT")? + || kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? || kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? || kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { @@ -380,6 +378,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } else { // Trying to acquire the same mutex again. + if kind == this.eval_libc("PTHREAD_MUTEX_DEFAULT")? { + // FIXME: Sometimes this is actually a Deadlock. + // https://github.com/rust-lang/miri/issues/1419 + throw_ub_format!( + "trying to acquire already locked PTHREAD_MUTEX_DEFAULT (see #1419)" + ); + } if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { throw_machine_stop!(TerminationInfo::Deadlock); } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { @@ -388,7 +393,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.mutex_lock(id, active_thread); Ok(0) } else { - throw_ub_format!("called pthread_mutex_lock on an unsupported type of mutex"); + throw_unsup_format!( + "called pthread_mutex_lock on an unsupported type of mutex" + ); } } } else { @@ -410,7 +417,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if owner_thread != active_thread { this.eval_libc_i32("EBUSY") } else { - if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? + if kind == this.eval_libc("PTHREAD_MUTEX_DEFAULT")? + || kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? || kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { this.eval_libc_i32("EBUSY") @@ -418,7 +426,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.mutex_lock(id, active_thread); Ok(0) } else { - throw_ub_format!( + throw_unsup_format!( "called pthread_mutex_trylock on an unsupported type of mutex" ); } @@ -435,21 +443,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; let id = mutex_get_or_create_id(this, mutex_op)?; + let active_thread = this.get_active_thread()?; - if let Some((old_owner_thread, _old_locked_count)) = this.mutex_unlock(id)? { - if old_owner_thread != this.get_active_thread()? { - throw_ub_format!("called pthread_mutex_unlock on a mutex owned by another thread"); - } + if let Some(_old_locked_count) = this.mutex_unlock(id, active_thread)? { + // The mutex was locked by the current thread. Ok(0) } else { - if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { - throw_ub_format!("unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked"); + // The mutex was locked by another thread or not locked at all. See + // the “Unlock When Not Owner” column in + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_unlock.html. + if kind == this.eval_libc("PTHREAD_MUTEX_DEFAULT")? { + throw_ub_format!( + "unlocked a PTHREAD_MUTEX_DEFAULT mutex that was not locked by the current thread" + ); + } else if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { + throw_ub_format!( + "unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked by the current thread" + ); } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { this.eval_libc_i32("EPERM") } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { this.eval_libc_i32("EPERM") } else { - throw_ub_format!("called pthread_mutex_unlock on an unsupported type of mutex"); + throw_unsup_format!("called pthread_mutex_unlock on an unsupported type of mutex"); } } } @@ -505,6 +521,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let active_thread = this.get_active_thread()?; if this.rwlock_is_locked(id) { + // Note: this will deadlock if the lock is already locked by this + // thread in any way. + // + // Relevant documentation: + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_wrlock.html + // An in depth discussion on this topic: + // https://github.com/rust-lang/rust/issues/53127 + // + // FIXME: Detect and report the deadlock proactively. (We currently + // report the deadlock only when no thread can continue execution, + // but we could detect that this lock is already locked and report + // an error.) this.rwlock_enqueue_and_block_writer(id, active_thread)?; } else { this.rwlock_writer_lock(id, active_thread); @@ -719,19 +747,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let clock_id = cond_get_clock_id(this, cond_op)?.to_i32()?; let duration = { let tp = this.deref_operand(abstime_op)?; - let mut offset = Size::from_bytes(0); - let layout = this.libc_ty_layout("time_t")?; - let seconds_place = tp.offset(offset, MemPlaceMeta::None, layout, this)?; + let seconds_place = this.mplace_field(tp, 0)?; let seconds = this.read_scalar(seconds_place.into())?; - offset += layout.size; - let layout = this.libc_ty_layout("c_long")?; - let nanoseconds_place = tp.offset(offset, MemPlaceMeta::None, layout, this)?; + let nanoseconds_place = this.mplace_field(tp, 1)?; let nanoseconds = this.read_scalar(nanoseconds_place.into())?; - let (seconds, nanoseconds) = if this.pointer_size().bytes() == 8 { - (seconds.to_u64()?, nanoseconds.to_u64()?.try_into().unwrap()) - } else { - (seconds.to_u32()?.into(), nanoseconds.to_u32()?) - }; + let (seconds, nanoseconds) = ( + seconds.to_machine_usize(this)?, + nanoseconds.to_machine_usize(this)?.try_into().unwrap(), + ); Duration::new(seconds, nanoseconds) }; @@ -740,7 +763,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if clock_id == this.eval_libc_i32("CLOCK_MONOTONIC")? { Time::Monotonic(this.machine.time_anchor.checked_add(duration).unwrap()) } else { - throw_unsup_format!("Unsupported clock id."); + throw_unsup_format!("unsupported clock id: {}", clock_id); }; // Register the timeout callback. diff --git a/src/sync.rs b/src/sync.rs index cbae29bdbb36..026542926ed8 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -30,10 +30,12 @@ macro_rules! declare_id { // We use 0 as a sentinel value (see the comment above) and, // therefore, need to shift by one when converting from an index // into a vector. - $name(NonZeroU32::new(u32::try_from(idx).unwrap() + 1).unwrap()) + let shifted_idx = u32::try_from(idx).unwrap().checked_add(1).unwrap(); + $name(NonZeroU32::new(shifted_idx).unwrap()) } fn index(self) -> usize { // See the comment in `Self::new`. + // (This cannot underflow because self is NonZeroU32.) usize::try_from(self.0.get() - 1).unwrap() } } @@ -150,11 +152,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// /// Note: It is the caller's responsibility to check that the thread that /// unlocked the lock actually is the same one, which owned it. - fn mutex_unlock(&mut self, id: MutexId) -> InterpResult<'tcx, Option<(ThreadId, usize)>> { + fn mutex_unlock( + &mut self, + id: MutexId, + expected_owner: ThreadId, + ) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); let mutex = &mut this.machine.threads.sync.mutexes[id]; if let Some(current_owner) = mutex.owner { // Mutex is locked. + if current_owner != expected_owner { + // Only the owner can unlock the mutex. + return Ok(None); + } let old_lock_count = mutex.lock_count; mutex.lock_count = old_lock_count .checked_sub(1) @@ -168,7 +178,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.unblock_thread(new_owner)?; } } - Ok(Some((current_owner, old_lock_count))) + Ok(Some(old_lock_count)) } else { // Mutex is unlocked. Ok(None) diff --git a/src/thread.rs b/src/thread.rs index 70c2419c4d49..45b07477fa23 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -159,6 +159,7 @@ impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> { } } +/// A specific moment in time. #[derive(Debug)] pub enum Time { Monotonic(Instant), @@ -449,9 +450,9 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { // // Documentation: // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html# - if let Some(sleep_time) = - self.timeout_callbacks.values().map(|info| info.call_time.get_wait_time()).min() - { + let potential_sleep_time = + self.timeout_callbacks.values().map(|info| info.call_time.get_wait_time()).min(); + if let Some(sleep_time) = potential_sleep_time { if sleep_time == Duration::new(0, 0) { return Ok(SchedulingAction::ExecuteTimeoutCallback); } @@ -479,9 +480,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { // We have not found a thread to execute. if self.threads.iter().all(|thread| thread.state == ThreadState::Terminated) { unreachable!("all threads terminated without the main thread terminating?!"); - } else if let Some(sleep_time) = - self.timeout_callbacks.values().map(|info| info.call_time.get_wait_time()).min() - { + } else if let Some(sleep_time) = potential_sleep_time { // All threads are currently blocked, but we have unexecuted // timeout_callbacks, which may unblock some of the threads. Hence, // sleep until the first callback. diff --git a/tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.rs b/tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.rs index 7034bf64ec90..4af8ee5df4b7 100644 --- a/tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.rs +++ b/tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.rs @@ -11,6 +11,8 @@ fn main() { let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR deadlock + // FIXME: The error should be deadlock. See issue + // https://github.com/rust-lang/miri/issues/1419. + libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR Undefined Behavior } } diff --git a/tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.rs b/tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.rs index 3009721abe2e..e67e8d366ebf 100644 --- a/tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.rs +++ b/tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.rs @@ -24,7 +24,7 @@ fn main() { let lock_copy = lock.clone(); thread::spawn(move || { - assert_eq!(libc::pthread_mutex_unlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: Undefined Behavior: called pthread_mutex_unlock on a mutex owned by another thread + assert_eq!(libc::pthread_mutex_unlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: Undefined Behavior: unlocked a PTHREAD_MUTEX_DEFAULT mutex that was not locked }) .join() .unwrap(); diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index faf47851bd01..2009c01ce9f9 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -91,7 +91,8 @@ fn check_conditional_variables_timed_wait_timeout() { let now = Instant::now(); let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap(); assert!(timeout.timed_out()); - assert!(now.elapsed().as_millis() >= 100); + let elapsed_time = now.elapsed().as_millis(); + assert!(100 <= elapsed_time && elapsed_time <= 300); } /// Test that signaling a conditional variable when waiting with a timeout works @@ -243,7 +244,7 @@ fn get_cached_val() -> usize { fn expensive_computation() -> usize { let mut i = 1; let mut c = 1; - while i < 10000 { + while i < 1000 { i *= c; c += 1; } @@ -257,7 +258,7 @@ fn check_once() { thread::spawn(|| { thread::yield_now(); let val = get_cached_val(); - assert_eq!(val, 40320); + assert_eq!(val, 5040); }) }) .collect(); From 6ff0af3adf6aa9d1dac07d45cd40bdc8b123d229 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 24 May 2020 20:20:28 +0200 Subject: [PATCH 2099/5092] Fix #1419. --- src/shims/sync.rs | 58 ++++++++++++++----- .../libc_pthread_mutex_normal_deadlock.rs | 4 +- 2 files changed, 45 insertions(+), 17 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 4fe353473981..ee139b057914 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -58,8 +58,31 @@ fn set_at_offset<'mir, 'tcx: 'mir>( // store an i32 in the first four bytes equal to the corresponding libc mutex kind constant // (e.g. PTHREAD_MUTEX_NORMAL). +/// A flag that allows to distinguish `PTHREAD_MUTEX_NORMAL` from +/// `PTHREAD_MUTEX_DEFAULT`. Since in `glibc` they have the same numeric values, +/// but different behaviour, we need a way to distinguish them. We do this by +/// setting this bit flag to the `PTHREAD_MUTEX_NORMAL` mutexes. See the comment +/// in `pthread_mutexattr_settype` function. +const PTHREAD_MUTEX_NORMAL_FLAG: i32 = 0x8000000; + const PTHREAD_MUTEXATTR_T_MIN_SIZE: u64 = 4; +fn is_mutex_kind_default<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + kind: Scalar, +) -> InterpResult<'tcx, bool> { + Ok(kind == ecx.eval_libc("PTHREAD_MUTEX_DEFAULT")?) +} + +fn is_mutex_kind_normal<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + kind: Scalar, +) -> InterpResult<'tcx, bool> { + let kind = kind.to_i32()?; + let mutex_normal_kind = ecx.eval_libc("PTHREAD_MUTEX_NORMAL")?.to_i32()?; + Ok(kind == (mutex_normal_kind | PTHREAD_MUTEX_NORMAL_FLAG)) +} + fn mutexattr_get_kind<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, attr_op: OpTy<'tcx, Tag>, @@ -318,8 +341,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let kind = this.read_scalar(kind_op)?.not_undef()?; - if kind == this.eval_libc("PTHREAD_MUTEX_DEFAULT")? - || kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? + if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { + // In `glibc` implementation, the numeric values of + // `PTHREAD_MUTEX_NORMAL` and `PTHREAD_MUTEX_DEFAULT` are equal, but + // they have different behaviour in some cases. Therefore, we add + // this flag to ensure that we can distinguish + // `PTHREAD_MUTEX_NORMAL` from `PTHREAD_MUTEX_DEFAULT`. + let normal_kind = kind.to_i32()? | PTHREAD_MUTEX_NORMAL_FLAG; + // Check that after setting the flag, the kind is distinguishable + // from all other kinds. + assert_ne!(normal_kind, this.eval_libc("PTHREAD_MUTEX_DEFAULT")?.to_i32()?); + assert_ne!(normal_kind, this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")?.to_i32()?); + assert_ne!(normal_kind, this.eval_libc("PTHREAD_MUTEX_RECURSIVE")?.to_i32()?); + mutexattr_set_kind(this, attr_op, Scalar::from_i32(normal_kind))?; + } else if kind == this.eval_libc("PTHREAD_MUTEX_DEFAULT")? || kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? || kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { @@ -378,14 +413,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } else { // Trying to acquire the same mutex again. - if kind == this.eval_libc("PTHREAD_MUTEX_DEFAULT")? { - // FIXME: Sometimes this is actually a Deadlock. - // https://github.com/rust-lang/miri/issues/1419 - throw_ub_format!( - "trying to acquire already locked PTHREAD_MUTEX_DEFAULT (see #1419)" - ); - } - if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { + if is_mutex_kind_default(this, kind)? { + throw_ub_format!("trying to acquire already locked PTHREAD_MUTEX_DEFAULT"); + } else if is_mutex_kind_normal(this, kind)? { throw_machine_stop!(TerminationInfo::Deadlock); } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { this.eval_libc_i32("EDEADLK") @@ -417,8 +447,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if owner_thread != active_thread { this.eval_libc_i32("EBUSY") } else { - if kind == this.eval_libc("PTHREAD_MUTEX_DEFAULT")? - || kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? + if is_mutex_kind_default(this, kind)? + || is_mutex_kind_normal(this, kind)? || kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { this.eval_libc_i32("EBUSY") @@ -452,11 +482,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // The mutex was locked by another thread or not locked at all. See // the “Unlock When Not Owner” column in // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_unlock.html. - if kind == this.eval_libc("PTHREAD_MUTEX_DEFAULT")? { + if is_mutex_kind_default(this, kind)? { throw_ub_format!( "unlocked a PTHREAD_MUTEX_DEFAULT mutex that was not locked by the current thread" ); - } else if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { + } else if is_mutex_kind_normal(this, kind)? { throw_ub_format!( "unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked by the current thread" ); diff --git a/tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.rs b/tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.rs index 4af8ee5df4b7..96e0ff3bfff7 100644 --- a/tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.rs +++ b/tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.rs @@ -11,8 +11,6 @@ fn main() { let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - // FIXME: The error should be deadlock. See issue - // https://github.com/rust-lang/miri/issues/1419. - libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR Undefined Behavior + libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR deadlock: the evaluated program deadlocked } } From 90590a399d326641a9132bb4a33f4645c08b73d8 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 24 May 2020 20:29:56 +0200 Subject: [PATCH 2100/5092] Small fixes. --- src/shims/sync.rs | 21 +++++++++++++------ src/thread.rs | 15 +++++++++---- .../sync/libc_pthread_mutex_NULL_deadlock.rs | 16 ++++++++++++++ .../libc_pthread_mutex_default_deadlock.rs | 17 +++++++++++++++ .../sync/libc_pthread_mutex_wrong_owner.rs | 2 +- 5 files changed, 60 insertions(+), 11 deletions(-) create mode 100644 tests/compile-fail/sync/libc_pthread_mutex_NULL_deadlock.rs create mode 100644 tests/compile-fail/sync/libc_pthread_mutex_default_deadlock.rs diff --git a/src/shims/sync.rs b/src/shims/sync.rs index ee139b057914..95092a042d34 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -301,6 +301,8 @@ fn post_cond_signal<'mir, 'tcx: 'mir>( mutex: MutexId, ) -> InterpResult<'tcx> { reacquire_cond_mutex(ecx, thread, mutex)?; + // Waiting for the mutex is not included in the waiting time because we need + // to acquire the mutex always even if we get a timeout. ecx.unregister_timeout_callback_if_exists(thread) } @@ -343,10 +345,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let kind = this.read_scalar(kind_op)?.not_undef()?; if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { // In `glibc` implementation, the numeric values of - // `PTHREAD_MUTEX_NORMAL` and `PTHREAD_MUTEX_DEFAULT` are equal, but - // they have different behaviour in some cases. Therefore, we add - // this flag to ensure that we can distinguish - // `PTHREAD_MUTEX_NORMAL` from `PTHREAD_MUTEX_DEFAULT`. + // `PTHREAD_MUTEX_NORMAL` and `PTHREAD_MUTEX_DEFAULT` are equal. + // However, a mutex created by explicitly passing + // `PTHREAD_MUTEX_NORMAL` type has in some cases different behaviour + // from the default mutex for which the type was not explicitly + // specified. For a more detailed discussion, please see + // https://github.com/rust-lang/miri/issues/1419. + // + // To distinguish these two cases in already constructed mutexes, we + // use the same trick as glibc: for the case when + // `pthread_mutexattr_settype` is caled explicitly, we set the + // `PTHREAD_MUTEX_NORMAL_FLAG` flag. let normal_kind = kind.to_i32()? | PTHREAD_MUTEX_NORMAL_FLAG; // Check that after setting the flag, the kind is distinguishable // from all other kinds. @@ -414,7 +423,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { // Trying to acquire the same mutex again. if is_mutex_kind_default(this, kind)? { - throw_ub_format!("trying to acquire already locked PTHREAD_MUTEX_DEFAULT"); + throw_ub_format!("trying to acquire already locked default mutex"); } else if is_mutex_kind_normal(this, kind)? { throw_machine_stop!(TerminationInfo::Deadlock); } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { @@ -484,7 +493,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_unlock.html. if is_mutex_kind_default(this, kind)? { throw_ub_format!( - "unlocked a PTHREAD_MUTEX_DEFAULT mutex that was not locked by the current thread" + "unlocked a default mutex that was not locked by the current thread" ); } else if is_mutex_kind_normal(this, kind)? { throw_ub_format!( diff --git a/src/thread.rs b/src/thread.rs index 45b07477fa23..59f08eec1649 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -377,6 +377,9 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Register the given `callback` to be called once the `call_time` passes. + /// + /// The callback will be called with `thread` being the active thread, and + /// the callback may not change the active thread. fn register_timeout_callback( &mut self, thread: ThreadId, @@ -452,10 +455,8 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html# let potential_sleep_time = self.timeout_callbacks.values().map(|info| info.call_time.get_wait_time()).min(); - if let Some(sleep_time) = potential_sleep_time { - if sleep_time == Duration::new(0, 0) { - return Ok(SchedulingAction::ExecuteTimeoutCallback); - } + if potential_sleep_time == Some(Duration::new(0, 0)) { + return Ok(SchedulingAction::ExecuteTimeoutCallback); } // No callbacks scheduled, pick a regular thread to execute. if self.threads[self.active_thread].state == ThreadState::Enabled @@ -699,6 +700,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let (thread, callback) = this.machine.threads.get_ready_callback().expect("no callback found"); + // This back-and-forth with `set_active_thread` is here because of two + // design decisions: + // 1. Make the caller and not the callback responsible for changing + // thread. + // 2. Make the scheduler the only place that can change the active + // thread. let old_thread = this.set_active_thread(thread)?; callback(this)?; this.set_active_thread(old_thread)?; diff --git a/tests/compile-fail/sync/libc_pthread_mutex_NULL_deadlock.rs b/tests/compile-fail/sync/libc_pthread_mutex_NULL_deadlock.rs new file mode 100644 index 000000000000..3a737b2e3e15 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_mutex_NULL_deadlock.rs @@ -0,0 +1,16 @@ +// ignore-windows: No libc on Windows +// +// Check that if we pass NULL attribute, then we get the default mutex type. + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + unsafe { + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, std::ptr::null() as *const _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR Undefined Behavior: trying to acquire already locked default mutex + } +} diff --git a/tests/compile-fail/sync/libc_pthread_mutex_default_deadlock.rs b/tests/compile-fail/sync/libc_pthread_mutex_default_deadlock.rs new file mode 100644 index 000000000000..0f6f570d70b0 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_mutex_default_deadlock.rs @@ -0,0 +1,17 @@ +// ignore-windows: No libc on Windows +// +// Check that if we do not set the mutex type, it is the default. + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + unsafe { + let mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR Undefined Behavior: trying to acquire already locked default mutex + } +} diff --git a/tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.rs b/tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.rs index e67e8d366ebf..d69929d4ed46 100644 --- a/tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.rs +++ b/tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.rs @@ -24,7 +24,7 @@ fn main() { let lock_copy = lock.clone(); thread::spawn(move || { - assert_eq!(libc::pthread_mutex_unlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: Undefined Behavior: unlocked a PTHREAD_MUTEX_DEFAULT mutex that was not locked + assert_eq!(libc::pthread_mutex_unlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: Undefined Behavior: unlocked a default mutex that was not locked by the current thread }) .join() .unwrap(); From dec205757ae2e370e631729c96f1d8e4a0ab1936 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 25 May 2020 00:28:01 +0200 Subject: [PATCH 2101/5092] Fix compilation errors after rebase. --- src/shims/foreign_items/posix.rs | 34 ++++++++++++++++++++++---------- src/shims/sync.rs | 30 ++++++++++++++-------------- 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 352e38113abb..db2fab526c1f 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -331,42 +331,52 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_init" => { - let result = this.pthread_condattr_init(args[0])?; + let &[attr] = check_arg_count(args)?; + let result = this.pthread_condattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_setclock" => { - let result = this.pthread_condattr_setclock(args[0], args[1])?; + let &[attr, clock_id] = check_arg_count(args)?; + let result = this.pthread_condattr_setclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_getclock" => { - let result = this.pthread_condattr_getclock(args[0], args[1])?; + let &[attr, clock_id] = check_arg_count(args)?; + let result = this.pthread_condattr_getclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_destroy" => { - let result = this.pthread_condattr_destroy(args[0])?; + let &[attr] = check_arg_count(args)?; + let result = this.pthread_condattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_init" => { - let result = this.pthread_cond_init(args[0], args[1])?; + let &[cond, attr] = check_arg_count(args)?; + let result = this.pthread_cond_init(cond, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_signal" => { - let result = this.pthread_cond_signal(args[0])?; + let &[cond] = check_arg_count(args)?; + let result = this.pthread_cond_signal(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_broadcast" => { - let result = this.pthread_cond_broadcast(args[0])?; + let &[cond] = check_arg_count(args)?; + let result = this.pthread_cond_broadcast(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_wait" => { - let result = this.pthread_cond_wait(args[0], args[1])?; + let &[cond, mutex] = check_arg_count(args)?; + let result = this.pthread_cond_wait(cond, mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_timedwait" => { - this.pthread_cond_timedwait(args[0], args[1], args[2], dest)?; + let &[cond, mutex, abstime] = check_arg_count(args)?; + this.pthread_cond_timedwait(cond, mutex, abstime, dest)?; } "pthread_cond_destroy" => { - let result = this.pthread_cond_destroy(args[0])?; + let &[cond] = check_arg_count(args)?; + let result = this.pthread_cond_destroy(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -430,6 +440,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "pthread_attr_init" | "pthread_attr_destroy" + if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + let &[_] = check_arg_count(args)?; + this.write_null(dest)?; + } | "pthread_attr_setstacksize" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { let &[_, _] = check_arg_count(args)?; diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 95092a042d34..5b0de43e5466 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -129,14 +129,14 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( fn mutex_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { +) -> InterpResult<'tcx, ScalarMaybeUninit> { get_at_offset(ecx, mutex_op, 4, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } fn mutex_set_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, - id: impl Into>, + id: impl Into>, ) -> InterpResult<'tcx, ()> { set_at_offset(ecx, mutex_op, 4, id, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } @@ -176,7 +176,7 @@ fn rwlock_get_id<'mir, 'tcx: 'mir>( fn rwlock_set_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, - id: impl Into>, + id: impl Into>, ) -> InterpResult<'tcx, ()> { set_at_offset(ecx, rwlock_op, 4, id, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } @@ -208,14 +208,14 @@ const PTHREAD_CONDATTR_T_MIN_SIZE: u64 = 4; fn condattr_get_clock_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, attr_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { +) -> InterpResult<'tcx, ScalarMaybeUninit> { get_at_offset(ecx, attr_op, 0, ecx.machine.layouts.i32, PTHREAD_CONDATTR_T_MIN_SIZE) } fn condattr_set_clock_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, attr_op: OpTy<'tcx, Tag>, - clock_id: impl Into>, + clock_id: impl Into>, ) -> InterpResult<'tcx, ()> { set_at_offset(ecx, attr_op, 0, clock_id, ecx.machine.layouts.i32, PTHREAD_CONDATTR_T_MIN_SIZE) } @@ -234,14 +234,14 @@ const PTHREAD_COND_T_MIN_SIZE: u64 = 12; fn cond_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, cond_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { +) -> InterpResult<'tcx, ScalarMaybeUninit> { get_at_offset(ecx, cond_op, 4, ecx.machine.layouts.u32, PTHREAD_COND_T_MIN_SIZE) } fn cond_set_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, cond_op: OpTy<'tcx, Tag>, - id: impl Into>, + id: impl Into>, ) -> InterpResult<'tcx, ()> { set_at_offset(ecx, cond_op, 4, id, ecx.machine.layouts.u32, PTHREAD_COND_T_MIN_SIZE) } @@ -265,14 +265,14 @@ fn cond_get_or_create_id<'mir, 'tcx: 'mir>( fn cond_get_clock_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, cond_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { +) -> InterpResult<'tcx, ScalarMaybeUninit> { get_at_offset(ecx, cond_op, 8, ecx.machine.layouts.i32, PTHREAD_COND_T_MIN_SIZE) } fn cond_set_clock_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, cond_op: OpTy<'tcx, Tag>, - clock_id: impl Into>, + clock_id: impl Into>, ) -> InterpResult<'tcx, ()> { set_at_offset(ecx, cond_op, 8, clock_id, ecx.machine.layouts.i32, PTHREAD_COND_T_MIN_SIZE) } @@ -518,8 +518,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_ub_format!("destroyed a locked mutex"); } - mutex_set_kind(this, mutex_op, ScalarMaybeUndef::Undef)?; - mutex_set_id(this, mutex_op, ScalarMaybeUndef::Undef)?; + mutex_set_kind(this, mutex_op, ScalarMaybeUninit::Uninit)?; + mutex_set_id(this, mutex_op, ScalarMaybeUninit::Uninit)?; Ok(0) } @@ -643,7 +643,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_ub_format!("destroyed a locked rwlock"); } - rwlock_set_id(this, rwlock_op, ScalarMaybeUndef::Undef)?; + rwlock_set_id(this, rwlock_op, ScalarMaybeUninit::Uninit)?; Ok(0) } @@ -696,7 +696,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_condattr_destroy(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - condattr_set_clock_id(this, attr_op, ScalarMaybeUndef::Undef)?; + condattr_set_clock_id(this, attr_op, ScalarMaybeUninit::Uninit)?; Ok(0) } @@ -835,8 +835,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.condvar_is_awaited(id) { throw_ub_format!("destroyed an awaited conditional variable"); } - cond_set_id(this, cond_op, ScalarMaybeUndef::Undef)?; - cond_set_clock_id(this, cond_op, ScalarMaybeUndef::Undef)?; + cond_set_id(this, cond_op, ScalarMaybeUninit::Uninit)?; + cond_set_clock_id(this, cond_op, ScalarMaybeUninit::Uninit)?; Ok(0) } From 34ddd775e8352c4905b56f183421902cdda9d100 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 25 May 2020 08:07:07 +0200 Subject: [PATCH 2102/5092] Increase the elapsed time window. --- tests/run-pass/concurrency/libc_pthread_cond.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/concurrency/libc_pthread_cond.rs b/tests/run-pass/concurrency/libc_pthread_cond.rs index 39b6a7e4ef80..27f5ead450fa 100644 --- a/tests/run-pass/concurrency/libc_pthread_cond.rs +++ b/tests/run-pass/concurrency/libc_pthread_cond.rs @@ -34,7 +34,7 @@ fn test_timed_wait_timeout(clock_id: i32) { libc::ETIMEDOUT ); let elapsed_time = current_time.elapsed().as_millis(); - assert!(900 <= elapsed_time && elapsed_time <= 1100); + assert!(900 <= elapsed_time && elapsed_time <= 1300); assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); assert_eq!(libc::pthread_cond_destroy(&mut cond as *mut _), 0); From 1fecbd8a87238330ad5f8f3c211ba03b19d0c2e8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 May 2020 09:42:08 +0200 Subject: [PATCH 2103/5092] macos does not have pthread_condattr_setclock/getclock --- src/shims/foreign_items/posix.rs | 10 ---------- src/shims/foreign_items/posix/linux.rs | 10 ++++++++++ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index db2fab526c1f..1652a3a1b545 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -335,16 +335,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.pthread_condattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "pthread_condattr_setclock" => { - let &[attr, clock_id] = check_arg_count(args)?; - let result = this.pthread_condattr_setclock(attr, clock_id)?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } - "pthread_condattr_getclock" => { - let &[attr, clock_id] = check_arg_count(args)?; - let result = this.pthread_condattr_getclock(attr, clock_id)?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } "pthread_condattr_destroy" => { let &[attr] = check_arg_count(args)?; let result = this.pthread_condattr_destroy(attr)?; diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index e0f54cac1570..323418f39ba0 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -90,6 +90,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.prctl(option, arg2, arg3, arg4, arg5)?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "pthread_condattr_setclock" => { + let &[attr, clock_id] = check_arg_count(args)?; + let result = this.pthread_condattr_setclock(attr, clock_id)?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_condattr_getclock" => { + let &[attr, clock_id] = check_arg_count(args)?; + let result = this.pthread_condattr_getclock(attr, clock_id)?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } // Dynamically invoked syscalls "syscall" => { From 9ff77f6cb36993026626a6463a6d22bca699a528 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 May 2020 09:45:42 +0200 Subject: [PATCH 2104/5092] add an assertion --- src/sync.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sync.rs b/src/sync.rs index 026542926ed8..107ad5ace172 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -238,6 +238,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match this.machine.threads.sync.rwlocks[id].readers.entry(reader) { Entry::Occupied(mut entry) => { let count = entry.get_mut(); + assert!(*count > 0, "rwlock locked with count == 0"); *count -= 1; if *count == 0 { entry.remove(); From a95f754a9cdd729b525cee2501c98636db6e9c39 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 May 2020 10:39:37 +0200 Subject: [PATCH 2105/5092] better error when reading from stdin --- src/shims/foreign_items/posix.rs | 22 ++++++++++++++++------ src/shims/fs.rs | 26 +++++++++++++------------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 1652a3a1b545..651b619e163d 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -62,20 +62,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "read" => { let &[fd, buf, count] = check_arg_count(args)?; - let result = this.read(fd, buf, count)?; + let fd = this.read_scalar(fd)?.to_i32()?; + let buf = this.read_scalar(buf)?.not_undef()?; + let count = this.read_scalar(count)?.to_machine_usize(this)?; + let result = if fd == 0 { + throw_unsup_format!("reading from stdin is not implemented") + } else if fd == 1 || fd == 2 { + throw_unsup_format!("cannot read from stdout/stderr") + } else { + this.read(fd, buf, count)? + }; this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "write" => { let &[fd, buf, n] = check_arg_count(args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.not_undef()?; - let n = this.read_scalar(n)?.to_machine_usize(this)?; - trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); - let result = if fd == 1 || fd == 2 { + let count = this.read_scalar(n)?.to_machine_usize(this)?; + trace!("Called write({:?}, {:?}, {:?})", fd, buf, count); + let result = if fd == 0 { + throw_unsup_format!("cannot write to stdin") + } else if fd == 1 || fd == 2 { // stdout/stderr use std::io::{self, Write}; - let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(n))?; + let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(count))?; // We need to flush to make sure this actually appears on the screen let res = if fd == 1 { // Stdout is buffered, flush to make sure it appears on the screen. @@ -94,7 +105,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Err(_) => -1, } } else { - let &[fd, buf, count] = check_arg_count(args)?; this.write(fd, buf, count)? }; // Now, `result` is the value we return back to the program. diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 8613f6bb0994..07360636280f 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -5,6 +5,8 @@ use std::io::{Read, Seek, SeekFrom, Write}; use std::path::Path; use std::time::SystemTime; +use log::trace; + use rustc_data_structures::fx::FxHashMap; use rustc_target::abi::{Align, LayoutOf, Size}; @@ -413,17 +415,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn read( &mut self, - fd_op: OpTy<'tcx, Tag>, - buf_op: OpTy<'tcx, Tag>, - count_op: OpTy<'tcx, Tag>, + fd: i32, + buf: Scalar, + count: u64, ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); this.check_no_isolation("read")?; + assert!(fd >= 3); - let fd = this.read_scalar(fd_op)?.to_i32()?; - let buf = this.read_scalar(buf_op)?.not_undef()?; - let count = this.read_scalar(count_op)?.to_machine_usize(&*this.tcx)?; + trace!("Reading from FD {}, size {}", fd, count); // Check that the *entire* buffer is actually valid memory. this.memory.check_ptr_access( @@ -437,6 +438,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64); if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { + trace!("read: FD mapped to {:?}", file); // This can never fail because `count` was capped to be smaller than // `isize::MAX`. let count = isize::try_from(count).unwrap(); @@ -461,23 +463,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } else { + trace!("read: FD not found"); this.handle_not_found() } } fn write( &mut self, - fd_op: OpTy<'tcx, Tag>, - buf_op: OpTy<'tcx, Tag>, - count_op: OpTy<'tcx, Tag>, + fd: i32, + buf: Scalar, + count: u64, ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); this.check_no_isolation("write")?; - - let fd = this.read_scalar(fd_op)?.to_i32()?; - let buf = this.read_scalar(buf_op)?.not_undef()?; - let count = this.read_scalar(count_op)?.to_machine_usize(&*this.tcx)?; + assert!(fd >= 3); // Check that the *entire* buffer is actually valid memory. this.memory.check_ptr_access( From 7ba8bbc49fa245f02dbca25fea446a75a4c19150 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 24 May 2020 13:17:16 -0500 Subject: [PATCH 2106/5092] Update comments --- src/shims/fs.rs | 8 +++++--- tests/run-pass/libc.rs | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index ac405138f524..66e191e3ed4a 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -378,9 +378,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if this.tcx.sess.target.target.target_os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC")? { - // On macOS, fsync does not wait for the underlying disk to finish writing, while this - // F_FULLFSYNC operation does. The standard library uses F_FULLFSYNC for both - // File::sync_data() and File::sync_all(). let &[_, _] = check_arg_count(args)?; if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { let result = file.sync_all(); @@ -1118,6 +1115,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } fn fsync(&mut self, fd_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + // On macOS, `fsync` (unlike `fcntl(F_FULLFSYNC)`) does not wait for the + // underlying disk to finish writing. In the interest of host compatibility, + // we conservatively implement this with `sync_all`, which + // *does* wait for the disk. + let this = self.eval_context_mut(); this.check_no_isolation("fsync")?; diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index 5897c46f6375..08199c1452d3 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -47,10 +47,10 @@ fn test_sync_file_range() { use std::os::unix::io::AsRawFd; let path = tmp().join("miri_test_libc_sync_file_range.txt"); - // Cleanup before test + // Cleanup before test. remove_file(&path).ok(); - // Write to a file + // Write to a file. let mut file = File::create(&path).unwrap(); let bytes = b"Hello, World!\n"; file.write(bytes).unwrap(); From 325208247428723f45f2db36c7a1f14f9d558a2b Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 25 May 2020 13:20:29 -0500 Subject: [PATCH 2107/5092] Fix test on Windows hosts FlushFileBuffers requires that a file be opened for writing --- tests/run-pass/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index d831129dc80f..a031233d581a 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -188,7 +188,7 @@ fn test_file_sync() { let path = prepare_with_content("miri_test_fs_sync.txt", bytes); // Test that we can call sync_data and sync_all (can't readily test effects of this operation) - let file = File::open(&path).unwrap(); + let file = OpenOptions::new().write(true).open(&path).unwrap(); file.sync_data().unwrap(); file.sync_all().unwrap(); From c01bc142194ae294356ac3b5b8666c3c351f14d5 Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 25 May 2020 19:50:06 -0500 Subject: [PATCH 2108/5092] Fix fsync shim for Windows hosts with RO files --- src/shims/fs.rs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 66e191e3ed4a..7f1c5caaf642 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1125,9 +1125,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("fsync")?; let fd = this.read_scalar(fd_op)?.to_i32()?; - if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { - let result = file.sync_all(); - this.try_unwrap_io_result(result.map(|_| 0i32)) + if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get_mut(&fd) { + if !*writable && cfg!(windows) { + // sync_all() will return an error on Windows hosts if the file is not opened for writing. + Ok(0i32) + } else { + let result = file.sync_all(); + this.try_unwrap_io_result(result.map(|_| 0i32)) + } } else { this.handle_not_found() } @@ -1139,9 +1144,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("fdatasync")?; let fd = this.read_scalar(fd_op)?.to_i32()?; - if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { - let result = file.sync_data(); - this.try_unwrap_io_result(result.map(|_| 0i32)) + if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get_mut(&fd) { + if !*writable && cfg!(windows) { + // sync_data() will return an error on Windows hosts if the file is not opened for writing. + Ok(0i32) + } else { + let result = file.sync_data(); + this.try_unwrap_io_result(result.map(|_| 0i32)) + } } else { this.handle_not_found() } From 60f466d6ad235dee5524bb56283fd0d477bf5c89 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 28 May 2020 08:51:38 +0200 Subject: [PATCH 2109/5092] use strip_prefix where it makes sense --- src/bin/miri.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 48e4a60c71f9..ecd232cac562 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -1,4 +1,5 @@ #![feature(rustc_private)] +#![feature(str_strip)] extern crate rustc_middle; extern crate rustc_driver; @@ -208,7 +209,7 @@ fn main() { if seed.is_some() { panic!("Cannot specify -Zmiri-seed multiple times!"); } - let seed_raw = hex::decode(arg.trim_start_matches("-Zmiri-seed=")) + let seed_raw = hex::decode(arg.strip_prefix("-Zmiri-seed=").unwrap()) .unwrap_or_else(|err| match err { FromHexError::InvalidHexCharacter { .. } => panic!( "-Zmiri-seed should only contain valid hex digits [0-9a-fA-F]" @@ -230,10 +231,10 @@ fn main() { } arg if arg.starts_with("-Zmiri-env-exclude=") => { excluded_env_vars - .push(arg.trim_start_matches("-Zmiri-env-exclude=").to_owned()); + .push(arg.strip_prefix("-Zmiri-env-exclude=").unwrap().to_owned()); } arg if arg.starts_with("-Zmiri-track-pointer-tag=") => { - let id: u64 = match arg.trim_start_matches("-Zmiri-track-pointer-tag=").parse() + let id: u64 = match arg.strip_prefix("-Zmiri-track-pointer-tag=").unwrap().parse() { Ok(id) => id, Err(err) => panic!( @@ -248,7 +249,7 @@ fn main() { } } arg if arg.starts_with("-Zmiri-track-alloc-id=") => { - let id: u64 = match arg.trim_start_matches("-Zmiri-track-alloc-id=").parse() + let id: u64 = match arg.strip_prefix("-Zmiri-track-alloc-id=").unwrap().parse() { Ok(id) => id, Err(err) => panic!( From 0790f75ae4892772583ef637b2fcde31039d8999 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 May 2020 11:00:06 +0200 Subject: [PATCH 2110/5092] make cargo-miri a separate crate in a workspace --- Cargo.lock | 18 +++++++++----- Cargo.toml | 29 +++++----------------- cargo-miri/Cargo.toml | 28 +++++++++++++++++++++ src/bin/cargo-miri.rs => cargo-miri/bin.rs | 0 build.rs => cargo-miri/build.rs | 0 miri | 12 +++++---- 6 files changed, 53 insertions(+), 34 deletions(-) create mode 100644 cargo-miri/Cargo.toml rename src/bin/cargo-miri.rs => cargo-miri/bin.rs (100%) rename build.rs => cargo-miri/build.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 0dbf00e6c566..23eafaaa6e4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -63,6 +63,18 @@ name = "byteorder" version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cargo-miri" +version = "0.1.0" +dependencies = [ + "cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", + "vergen 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cargo_metadata" version = "0.9.1" @@ -273,22 +285,16 @@ name = "miri" version = "0.1.0" dependencies = [ "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)", "compiletest_rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "vergen 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 8ccc9484c88b..6eede5ef464b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] -authors = ["Scott Olson "] -description = "An experimental interpreter for Rust MIR." +authors = ["Miri Team"] +description = "An experimental interpreter for Rust MIR (core driver)." license = "MIT/Apache-2.0" name = "miri" repository = "https://github.com/rust-lang/miri" @@ -8,6 +8,9 @@ version = "0.1.0" default-run = "miri" edition = "2018" +[workspace] +members = ["cargo-miri"] + [lib] test = true # we have unit tests doctest = false # but no doc tests @@ -17,12 +20,6 @@ name = "miri" test = false # we have no unit tests doctest = false # and no doc tests -[[bin]] -name = "cargo-miri" -test = false # we have no unit tests -doctest = false # and no doc tests -required-features = ["cargo_miri"] - [[bin]] name = "miri-rustc-tests" test = false # we have no unit tests @@ -30,11 +27,6 @@ doctest = false # and no doc tests required-features = ["rustc_tests"] [dependencies] -cargo_metadata = { version = "0.9.0", optional = true } -directories = { version = "2.0", optional = true } -rustc_version = { version = "0.2.3", optional = true } -serde_json = { version = "1.0.40", optional = true } - getrandom = { version = "0.1.8", features = ["std"] } byteorder = "1.3" env_logger = "0.7.1" @@ -48,19 +40,10 @@ rand = "0.7" # for more information. rustc-workspace-hack = "1.0.0" -# Some extra dependency for better feature control to avoid having to rebuild -# between "cargo build" and "cargo intall". -num-traits = "*" -serde = { version = "*", features = ["derive"] } - -[build-dependencies] -vergen = "3" - [dev-dependencies] compiletest_rs = { version = "0.5", features = ["tmp"] } +rustc_version = "0.2.3" colored = "1.6" [features] -default = ["cargo_miri"] -cargo_miri = ["cargo_metadata", "directories", "rustc_version", "serde_json"] rustc_tests = [] diff --git a/cargo-miri/Cargo.toml b/cargo-miri/Cargo.toml new file mode 100644 index 000000000000..86b2576273d2 --- /dev/null +++ b/cargo-miri/Cargo.toml @@ -0,0 +1,28 @@ +[package] +authors = ["Miri Team"] +description = "An experimental interpreter for Rust MIR (cargo wrapper)." +license = "MIT/Apache-2.0" +name = "cargo-miri" +repository = "https://github.com/rust-lang/miri" +version = "0.1.0" +edition = "2018" + +[[bin]] +name = "cargo-miri" +path = "bin.rs" +test = false # we have no unit tests +doctest = false # and no doc tests + +[dependencies] +cargo_metadata = "0.9.0" +directories = "2.0" +rustc_version = "0.2.3" +serde_json = "1.0.40" + +# A noop dependency that changes in the Rust repository, it's a bit of a hack. +# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` +# for more information. +rustc-workspace-hack = "1.0.0" + +[build-dependencies] +vergen = "3" diff --git a/src/bin/cargo-miri.rs b/cargo-miri/bin.rs similarity index 100% rename from src/bin/cargo-miri.rs rename to cargo-miri/bin.rs diff --git a/build.rs b/cargo-miri/build.rs similarity index 100% rename from build.rs rename to cargo-miri/build.rs diff --git a/miri b/miri index b4d205bd52c5..948a839ef727 100755 --- a/miri +++ b/miri @@ -59,9 +59,9 @@ fi # Build a sysroot and set MIRI_SYSROOT to use it. Arguments are passed to `cargo miri setup`. build_sysroot() { # Build once, for the user to see. - cargo run $CARGO_BUILD_FLAGS --bin cargo-miri -- miri setup "$@" + cargo run $CARGO_BUILD_FLAGS -p cargo-miri -- miri setup "$@" # Call again, to just set env var. - export MIRI_SYSROOT="$(cargo run $CARGO_BUILD_FLAGS -q --bin cargo-miri -- miri setup --print-sysroot "$@")" + export MIRI_SYSROOT="$(cargo run $CARGO_BUILD_FLAGS -q -p cargo-miri -- miri setup --print-sysroot "$@")" } # Prepare and set MIRI_SYSROOT. Respects `MIRI_TEST_TARGET` and takes into account @@ -104,21 +104,23 @@ case "$COMMAND" in install|install-debug) # "--locked" to respect the Cargo.lock file if it exists, # "--offline" to avoid querying the registry (for yanked packages). - exec cargo install $CARGO_INSTALL_FLAGS --path "$(dirname "$0")" --force --locked --offline "$@" + cargo install $CARGO_INSTALL_FLAGS --path "$(dirname "$0")" --force --locked --offline "$@" + cargo install $CARGO_INSTALL_FLAGS --path "$(dirname "$0")"/cargo-miri --force --locked --offline "$@" ;; check|check-debug) # Check, and let caller control flags. - exec cargo check $CARGO_BUILD_FLAGS "$@" + exec cargo check $CARGO_BUILD_FLAGS --all "$@" ;; build|build-debug) # Build, and let caller control flags. - exec cargo build $CARGO_BUILD_FLAGS "$@" + exec cargo build $CARGO_BUILD_FLAGS --all "$@" ;; test|test-debug) # First build and get a sysroot. cargo build $CARGO_BUILD_FLAGS find_sysroot # Then test, and let caller control flags. + # No `--all` as `cargo-miri` has no tests. exec cargo test $CARGO_BUILD_FLAGS "$@" ;; run|run-debug) From b71fea710cd8be5e34ac0b91ceb4aed6ceaad836 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 May 2020 11:23:04 +0200 Subject: [PATCH 2111/5092] just respect existing RUSTFLAGS instead of providing another override --- ci.sh | 2 +- miri | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ci.sh b/ci.sh index 922469aeca54..8c3fcebe94db 100755 --- a/ci.sh +++ b/ci.sh @@ -4,7 +4,7 @@ set -euo pipefail # Determine configuration export RUST_TEST_NOCAPTURE=1 export RUST_BACKTRACE=1 -export RUSTC_EXTRA_FLAGS="-D warnings" +export RUSTFLAGS="-D warnings" export CARGO_INCREMENTAL=0 export CARGO_EXTRA_FLAGS="--all-features" diff --git a/miri b/miri index 948a839ef727..4b6426adb1dc 100755 --- a/miri +++ b/miri @@ -45,14 +45,14 @@ if ! test -d "$LIBDIR"; then echo "Please report a bug at https://github.com/rust-lang/miri/issues." exit 2 fi -# We set the rpath so that Miri finds the private rustc libraries it needs. -# We enable debug-assertions to get tracing. -# We enable line-only debuginfo for backtraces. -export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR -C debug-assertions -C debuginfo=1 $RUSTC_EXTRA_FLAGS" if [ -z "$CARGO_INCREMENTAL" ]; then # Default CARGO_INCREMENTAL to 1. export CARGO_INCREMENTAL=1 fi +# We set the rpath so that Miri finds the private rustc libraries it needs. +# We enable debug-assertions to get tracing. +# We enable line-only debuginfo for backtraces. +export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR -C debug-assertions -C debuginfo=1 $RUSTFLAGS" ## Helper functions From c4c7463aa5af77915041baf0acce4bd29f88029c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 May 2020 11:30:37 +0200 Subject: [PATCH 2112/5092] make sure CI fails when we do not recognize the platform --- ci.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ci.sh b/ci.sh index 8c3fcebe94db..785d7aa5520c 100755 --- a/ci.sh +++ b/ci.sh @@ -48,4 +48,7 @@ elif [ "${TRAVIS_OS_NAME:-}" == osx ]; then elif [ "${CI_WINDOWS:-}" == True ]; then MIRI_TEST_TARGET=x86_64-unknown-linux-gnu run_tests MIRI_TEST_TARGET=x86_64-apple-darwin run_tests +else + echo "FATAL: unknown CI platform" + exit 1 fi From 254fc50bc14d83c54283220ed39e33ce06241eef Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 May 2020 11:32:12 +0200 Subject: [PATCH 2113/5092] fmt --- cargo-miri/bin.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 2e2d4ce956b1..4974ef63f5db 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -1,12 +1,12 @@ #![feature(inner_deref)] use std::env; +use std::ffi::OsString; use std::fs::{self, File}; use std::io::{self, BufRead, Write}; use std::ops::Not; use std::path::{Path, PathBuf}; use std::process::Command; -use std::ffi::OsString; use rustc_version::VersionMeta; @@ -265,7 +265,8 @@ fn setup(subcommand: MiriCommand) { let sysroot = std::str::from_utf8(&sysroot).unwrap(); let sysroot = Path::new(sysroot.trim_end_matches('\n')); // Check for `$SYSROOT/lib/rustlib/src/rust/src`; test if that contains `libstd/lib.rs`. - let rustup_src = sysroot.join("lib").join("rustlib").join("src").join("rust").join("src"); + let rustup_src = + sysroot.join("lib").join("rustlib").join("src").join("rust").join("src"); if !rustup_src.join("libstd").join("lib.rs").exists() { // Ask the user to install the `rust-src` component, and use that. let mut cmd = Command::new("rustup"); @@ -363,8 +364,7 @@ path = "lib.rs" let sysroot = if target == &host { dir.join("HOST") } else { PathBuf::from(dir) }; std::env::set_var("MIRI_SYSROOT", &sysroot); // pass the env var to the processes we spawn, which will turn it into "--sysroot" flags // Figure out what to print. - let print_sysroot = subcommand == MiriCommand::Setup - && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path + let print_sysroot = subcommand == MiriCommand::Setup && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path if print_sysroot { // Print just the sysroot and nothing else; this way we do not need any escaping. println!("{}", sysroot.display()); @@ -564,6 +564,8 @@ fn main() { // dependencies get dispatched to `rustc`, the final test/binary to `miri`. inside_cargo_rustc(); } else { - show_error(format!("`cargo-miri` must be called with either `miri` or `rustc` as first argument.")) + show_error(format!( + "`cargo-miri` must be called with either `miri` or `rustc` as first argument." + )) } } From 7fcf92dfea6c5ba7cec44fbae5e41ca2f181dcd8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 May 2020 11:21:03 +0200 Subject: [PATCH 2114/5092] re-add some fake dependencies to avoid rebuilds --- Cargo.lock | 2 ++ Cargo.toml | 5 +++++ cargo-miri/Cargo.toml | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 23eafaaa6e4a..182216b9ec32 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,6 +71,7 @@ dependencies = [ "directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", "vergen 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -290,6 +291,7 @@ dependencies = [ "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 6eede5ef464b..375cb0aa35b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,11 @@ rand = "0.7" # for more information. rustc-workspace-hack = "1.0.0" +# Enable some feature flags that dev-dependencies need but dependencies +# do not. This makes `./miri install` after `./miri build` faster. +[target."cfg(unix)".dependencies] +libc = "0.2" + [dev-dependencies] compiletest_rs = { version = "0.5", features = ["tmp"] } rustc_version = "0.2.3" diff --git a/cargo-miri/Cargo.toml b/cargo-miri/Cargo.toml index 86b2576273d2..d6a98be2bbdf 100644 --- a/cargo-miri/Cargo.toml +++ b/cargo-miri/Cargo.toml @@ -24,5 +24,9 @@ serde_json = "1.0.40" # for more information. rustc-workspace-hack = "1.0.0" +# Enable some feature flags that dev-dependencies need but dependencies +# do not. This makes `./miri install` after `./miri build` faster. +serde = { version = "*", features = ["derive"] } + [build-dependencies] vergen = "3" From 35964b10b0d4fadfdb921cc8a3f24a90ba8b50b3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 May 2020 14:18:18 +0200 Subject: [PATCH 2115/5092] no workspace as that is incompatible with the rustc submodule --- Cargo.lock | 93 ----------- Cargo.toml | 3 - cargo-miri/Cargo.lock | 351 ++++++++++++++++++++++++++++++++++++++++++ miri | 16 +- 4 files changed, 362 insertions(+), 101 deletions(-) create mode 100644 cargo-miri/Cargo.lock diff --git a/Cargo.lock b/Cargo.lock index 182216b9ec32..f68a6133be57 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,11 +43,6 @@ name = "base64" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "bitflags" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "blake2b_simd" version = "0.5.10" @@ -63,45 +58,11 @@ name = "byteorder" version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "cargo-miri" -version = "0.1.0" -dependencies = [ - "cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", - "vergen 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cargo_metadata" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "chrono" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "colored" version = "1.9.3" @@ -153,15 +114,6 @@ name = "diff" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "directories" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "dirs" version = "2.0.2" @@ -299,23 +251,6 @@ dependencies = [ "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "num-integer" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-traits" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "ppv-lite86" version = "0.2.6" @@ -464,7 +399,6 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -574,16 +508,6 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "time" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "unicode-width" version = "0.1.7" @@ -594,15 +518,6 @@ name = "unicode-xid" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "vergen" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" @@ -643,18 +558,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" "checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" "checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" -"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" -"checksum cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46e3374c604fb39d1a2f35ed5e4a4e30e60d01fab49446e08f1b3e9a90aef202" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" "checksum colored 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" "checksum compiletest_rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f737835bfbbe29ed1ff82d5137520338d7ed5bf1a1d4b9c1c7c58bb45b8fa29" "checksum constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" "checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" "checksum diff 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" -"checksum directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c" "checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" "checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" "checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" @@ -670,8 +581,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" "checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226" -"checksum num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" -"checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" "checksum proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3" "checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" @@ -703,10 +612,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" "checksum tester 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee72ec31009a42b53de9a6b7d8f462b493ab3b1e4767bda1fcdbb52127f13b6c" "checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" -"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" -"checksum vergen 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ce50d8996df1f85af15f2cd8d33daae6e479575123ef4314a51a70a230739cb" "checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" diff --git a/Cargo.toml b/Cargo.toml index 375cb0aa35b0..c33008e48a79 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,9 +8,6 @@ version = "0.1.0" default-run = "miri" edition = "2018" -[workspace] -members = ["cargo-miri"] - [lib] test = true # we have unit tests doctest = false # but no doc tests diff --git a/cargo-miri/Cargo.lock b/cargo-miri/Cargo.lock new file mode 100644 index 000000000000..c6d80add0787 --- /dev/null +++ b/cargo-miri/Cargo.lock @@ -0,0 +1,351 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[package]] +name = "arrayvec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" + +[[package]] +name = "autocfg" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" + +[[package]] +name = "base64" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "blake2b_simd" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq", +] + +[[package]] +name = "cargo-miri" +version = "0.1.0" +dependencies = [ + "cargo_metadata", + "directories", + "rustc-workspace-hack", + "rustc_version", + "serde", + "serde_json", + "vergen", +] + +[[package]] +name = "cargo_metadata" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46e3374c604fb39d1a2f35ed5e4a4e30e60d01fab49446e08f1b3e9a90aef202" +dependencies = [ + "semver", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "chrono" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" +dependencies = [ + "num-integer", + "num-traits", + "time", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "crossbeam-utils" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +dependencies = [ + "autocfg", + "cfg-if", + "lazy_static", +] + +[[package]] +name = "directories" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c" +dependencies = [ + "cfg-if", + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" +dependencies = [ + "cfg-if", + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "getrandom" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "itoa" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3baa92041a6fec78c687fa0cc2b3fae8884f743d672cf551bed1d6dac6988d0f" + +[[package]] +name = "num-integer" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" +dependencies = [ + "autocfg", +] + +[[package]] +name = "proc-macro2" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53f5ffe53a6b28e37c9c1ce74893477864d64f74778a93a4beb43c8fa167f639" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" + +[[package]] +name = "redox_users" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" +dependencies = [ + "getrandom", + "redox_syscall", + "rust-argon2", +] + +[[package]] +name = "rust-argon2" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" +dependencies = [ + "base64", + "blake2b_simd", + "constant_time_eq", + "crossbeam-utils", +] + +[[package]] +name = "rustc-workspace-hack" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "ryu" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3d612bc64430efeb3f7ee6ef26d590dce0c43249217bddc62112540c7941e1" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", + "serde", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "serde" +version = "1.0.110" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99e7b308464d16b56eba9964e4972a3eee817760ab60d88c3f86e1fecb08204c" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.110" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "818fbf6bfa9a42d3bfcaca148547aa00c7b915bec71d1757aa2d44ca68771984" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993948e75b189211a9b31a7528f950c6adc21f9720b6438ff80a7fa2f864cea2" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "syn" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b5f192649e48a5302a13f2feb224df883b98933222369e4b3b0fe2a5447269" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "time" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" + +[[package]] +name = "vergen" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ce50d8996df1f85af15f2cd8d33daae6e479575123ef4314a51a70a230739cb" +dependencies = [ + "bitflags", + "chrono", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/miri b/miri index 4b6426adb1dc..237a53efb1ad 100755 --- a/miri +++ b/miri @@ -49,6 +49,10 @@ if [ -z "$CARGO_INCREMENTAL" ]; then # Default CARGO_INCREMENTAL to 1. export CARGO_INCREMENTAL=1 fi +if [ -z "$CARGO_TARGET_DIR" ]; then + # Share target dir between `miri` and `cargo-miri`. + export CARGO_TARGET_DIR="$(dirname "$0")"/target +fi # We set the rpath so that Miri finds the private rustc libraries it needs. # We enable debug-assertions to get tracing. # We enable line-only debuginfo for backtraces. @@ -59,9 +63,9 @@ export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR -C debug-assertions -C debugin # Build a sysroot and set MIRI_SYSROOT to use it. Arguments are passed to `cargo miri setup`. build_sysroot() { # Build once, for the user to see. - cargo run $CARGO_BUILD_FLAGS -p cargo-miri -- miri setup "$@" + cargo run $CARGO_BUILD_FLAGS --manifest-path "$(dirname "$0")"/cargo-miri/Cargo.toml -- miri setup "$@" # Call again, to just set env var. - export MIRI_SYSROOT="$(cargo run $CARGO_BUILD_FLAGS -q -p cargo-miri -- miri setup --print-sysroot "$@")" + export MIRI_SYSROOT="$(cargo run $CARGO_BUILD_FLAGS --manifest-path "$(dirname "$0")"/cargo-miri/Cargo.toml -q -- miri setup --print-sysroot "$@")" } # Prepare and set MIRI_SYSROOT. Respects `MIRI_TEST_TARGET` and takes into account @@ -109,18 +113,20 @@ install|install-debug) ;; check|check-debug) # Check, and let caller control flags. - exec cargo check $CARGO_BUILD_FLAGS --all "$@" + cargo check $CARGO_BUILD_FLAGS --manifest-path "$(dirname "$0")"/Cargo.toml "$@" + cargo check $CARGO_BUILD_FLAGS --manifest-path "$(dirname "$0")"/cargo-miri/Cargo.toml "$@" ;; build|build-debug) # Build, and let caller control flags. - exec cargo build $CARGO_BUILD_FLAGS --all "$@" + cargo build $CARGO_BUILD_FLAGS --manifest-path "$(dirname "$0")"/Cargo.toml "$@" + cargo build $CARGO_BUILD_FLAGS --manifest-path "$(dirname "$0")"/cargo-miri/Cargo.toml "$@" ;; test|test-debug) # First build and get a sysroot. cargo build $CARGO_BUILD_FLAGS find_sysroot # Then test, and let caller control flags. - # No `--all` as `cargo-miri` has no tests. + # Only in root project as `cargo-miri` has no tests. exec cargo test $CARGO_BUILD_FLAGS "$@" ;; run|run-debug) From ac454a248524b8b273b17337e3d59a45772f357f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 May 2020 14:24:41 +0200 Subject: [PATCH 2116/5092] cargo-miri: allow overwriting miri command, and make that consistent with compiletest --- cargo-miri/bin.rs | 3 +++ tests/compiletest.rs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 4974ef63f5db..197552a4b126 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -94,6 +94,9 @@ fn get_arg_flag_value(name: &str) -> Option { /// Returns the path to the `miri` binary fn find_miri() -> PathBuf { + if let Some(path) = env::var_os("MIRI") { + return path.into(); + } let mut path = std::env::current_exe().expect("current executable path invalid"); path.set_file_name("miri"); path diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 2be0661b93ee..a64f0edb9464 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -9,7 +9,7 @@ use colored::*; use compiletest_rs as compiletest; fn miri_path() -> PathBuf { - PathBuf::from(option_env!("MIRI_PATH").unwrap_or(env!("CARGO_BIN_EXE_miri"))) + PathBuf::from(option_env!("MIRI").unwrap_or(env!("CARGO_BIN_EXE_miri"))) } fn run_tests(mode: &str, path: &str, target: &str) { From 229784ba624f6d018abb7c1fcb18d5b4387f72a3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 28 May 2020 09:19:01 +0200 Subject: [PATCH 2117/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 4275de5f8cbb..a2f999a91caf 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7726070fa755f660b5da3f82f46e07d9c6866f69 +45127211566c53bac386b66909a830649182ab7a From f55c0153f1f259032fe6eda8bce036993da3a932 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 29 May 2020 10:01:07 +0200 Subject: [PATCH 2118/5092] str_strip is stable --- rust-version | 2 +- src/bin/miri.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/rust-version b/rust-version index a2f999a91caf..73f017b8d2c6 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -45127211566c53bac386b66909a830649182ab7a +255c0338dc0b02f833fb1a816d76febd50c399c4 diff --git a/src/bin/miri.rs b/src/bin/miri.rs index ecd232cac562..41490531a78b 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -1,5 +1,4 @@ #![feature(rustc_private)] -#![feature(str_strip)] extern crate rustc_middle; extern crate rustc_driver; From 394a57fc22d061c943985c741cca6cb5694586c5 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Fri, 15 May 2020 01:44:41 -0700 Subject: [PATCH 2119/5092] Remove pointer arithmetic intrinsics These are now implemented in rustc's mir interpreter Signed-off-by: Joe Richey --- src/operator.rs | 46 +---------------------------------------- src/shims/intrinsics.rs | 20 ------------------ 2 files changed, 1 insertion(+), 65 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index a28a0098e92e..bfc8e908dc15 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,9 +1,6 @@ -use std::convert::TryFrom; - use log::trace; use rustc_middle::{mir, ty::Ty}; -use rustc_target::abi::{LayoutOf, Size}; use crate::*; @@ -16,13 +13,6 @@ pub trait EvalContextExt<'tcx> { ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)>; fn ptr_eq(&self, left: Scalar, right: Scalar) -> InterpResult<'tcx, bool>; - - fn pointer_offset_inbounds( - &self, - ptr: Scalar, - pointee_ty: Ty<'tcx>, - offset: i64, - ) -> InterpResult<'tcx, Scalar>; } impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { @@ -71,7 +61,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { Offset => { let pointee_ty = left.layout.ty.builtin_deref(true).expect("Offset called on non-ptr type").ty; - let ptr = self.pointer_offset_inbounds( + let ptr = self.ptr_offset_inbounds( left.to_scalar()?, pointee_ty, right.to_scalar()?.to_machine_isize(self)?, @@ -91,38 +81,4 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { let right = self.force_bits(right, size)?; Ok(left == right) } - - /// Raises an error if the offset moves the pointer outside of its allocation. - /// For integers, we consider each of them their own tiny allocation of size 0, - /// so offset-by-0 is okay for them -- except for NULL, which we rule out entirely. - fn pointer_offset_inbounds( - &self, - ptr: Scalar, - pointee_ty: Ty<'tcx>, - offset: i64, - ) -> InterpResult<'tcx, Scalar> { - let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); - let offset = offset.checked_mul(pointee_size).ok_or_else(|| { - err_ub_format!("overflow during offset comutation for inbounds pointer arithmetic") - })?; - // We do this first, to rule out overflows. - let offset_ptr = ptr.ptr_signed_offset(offset, self)?; - // What we need to check is that starting at `min(ptr, offset_ptr)`, - // we could do an access of size `abs(offset)`. Alignment does not matter. - let (min_ptr, abs_offset) = if offset >= 0 { - (ptr, u64::try_from(offset).unwrap()) - } else { - // Negative offset. - // If the negation overflows, the result will be negative so the try_from will fail. - (offset_ptr, u64::try_from(-offset).unwrap()) - }; - self.memory.check_ptr_access_align( - min_ptr, - Size::from_bytes(abs_offset), - None, - CheckInAllocMsg::InboundsTest, - )?; - // That's it! - Ok(offset_ptr) - } } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 1a8c9163211a..ec86e878ec60 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -101,26 +101,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .write_bytes(ptr, iter::repeat(val_byte).take(byte_count.bytes() as usize))?; } - // Pointer arithmetic - "arith_offset" => { - let &[ptr, offset] = check_arg_count(args)?; - let ptr = this.read_scalar(ptr)?.not_undef()?; - let offset = this.read_scalar(offset)?.to_machine_isize(this)?; - - let pointee_ty = substs.type_at(0); - let pointee_size = i64::try_from(this.layout_of(pointee_ty)?.size.bytes()).unwrap(); - let offset = offset.overflowing_mul(pointee_size).0; - let result_ptr = ptr.ptr_wrapping_signed_offset(offset, this); - this.write_scalar(result_ptr, dest)?; - } - "offset" => { - let &[ptr, offset] = check_arg_count(args)?; - let ptr = this.read_scalar(ptr)?.not_undef()?; - let offset = this.read_scalar(offset)?.to_machine_isize(this)?; - let result_ptr = this.pointer_offset_inbounds(ptr, substs.type_at(0), offset)?; - this.write_scalar(result_ptr, dest)?; - } - // Floating-point operations #[rustfmt::skip] | "sinf32" From c77e9022d5d75a2d273b39f0539bfbf52d0ba6e6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 May 2020 09:14:56 +0200 Subject: [PATCH 2120/5092] rustup (and account for stabilization) --- rust-version | 2 +- src/shims/intrinsics.rs | 1 - tests/compile-fail/rc_as_ptr.rs | 1 - tests/run-pass/rc.rs | 1 - 4 files changed, 1 insertion(+), 4 deletions(-) diff --git a/rust-version b/rust-version index 73f017b8d2c6..0124f254ec1e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -255c0338dc0b02f833fb1a816d76febd50c399c4 +0e9e4083100aa3ebf09b8f1ace0348cb37475eb9 diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index ec86e878ec60..c16fbc278c8d 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -1,5 +1,4 @@ use std::iter; -use std::convert::TryFrom; use rustc_attr as attr; use rustc_ast::ast::FloatTy; diff --git a/tests/compile-fail/rc_as_ptr.rs b/tests/compile-fail/rc_as_ptr.rs index 0b98c7d2bba3..1a9c322ac8d0 100644 --- a/tests/compile-fail/rc_as_ptr.rs +++ b/tests/compile-fail/rc_as_ptr.rs @@ -1,6 +1,5 @@ // This should fail even without validation // compile-flags: -Zmiri-disable-validation -#![feature(weak_into_raw)] use std::rc::{Rc, Weak}; use std::ptr; diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index 9ab460c96165..3dc61fe1f00d 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -1,4 +1,3 @@ -#![feature(weak_into_raw)] #![feature(new_uninit)] #![feature(get_mut_unchecked)] From 7589bc7ba92df64cbf3cab214724a6d500a0e2b3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 May 2020 22:29:27 +0200 Subject: [PATCH 2121/5092] sync cleanup: mark infallible ops as such; consistent combine en/dequeue with (un)block; comments --- src/shims/foreign_items/posix.rs | 4 +- src/shims/foreign_items/posix/macos.rs | 2 +- src/shims/foreign_items/windows.rs | 8 ++-- src/shims/sync.rs | 60 +++++++++++++------------- src/shims/thread.rs | 16 +++---- src/shims/tls.rs | 18 ++++---- src/sync.rs | 54 ++++++++++++++--------- src/thread.rs | 52 +++++++++++----------- 8 files changed, 110 insertions(+), 104 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 651b619e163d..77f0c5b9fbd6 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -254,14 +254,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "pthread_getspecific" => { let &[key] = check_arg_count(args)?; let key = this.force_bits(this.read_scalar(key)?.not_undef()?, key.layout.size)?; - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { let &[key, new_ptr] = check_arg_count(args)?; let key = this.force_bits(this.read_scalar(key)?.not_undef()?, key.layout.size)?; - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); let new_ptr = this.read_scalar(new_ptr)?.not_undef()?; this.machine.tls.store_tls(key, active_thread, this.test_null(new_ptr)?)?; diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index e6d39af45395..fb50e4d91817 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -98,7 +98,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dtor = this.read_scalar(dtor)?.not_undef()?; let dtor = this.memory.get_fn(dtor)?.as_instance()?; let data = this.read_scalar(data)?.not_undef()?; - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); this.machine.tls.set_macos_thread_dtor(active_thread, dtor, data)?; } diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index c24824153ca2..2a30a2348997 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -163,14 +163,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "TlsGetValue" => { let &[key] = check_arg_count(args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "TlsSetValue" => { let &[key, new_ptr] = check_arg_count(args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); let new_ptr = this.read_scalar(new_ptr)?.not_undef()?; this.machine.tls.store_tls(key, active_thread, this.test_null(new_ptr)?)?; @@ -291,7 +291,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] let &[_lpCriticalSection] = check_arg_count(args)?; - assert_eq!(this.get_total_thread_count()?, 1, "concurrency on Windows not supported"); + assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows not supported"); // Nothing to do, not even a return value. // (Windows locks are reentrant, and we have only 1 thread, // so not doing any futher checks here is at least not incorrect.) @@ -300,7 +300,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] let &[_lpCriticalSection] = check_arg_count(args)?; - assert_eq!(this.get_total_thread_count()?, 1, "concurrency on Windows not supported"); + assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows not supported"); // There is only one thread, so this always succeeds and returns TRUE this.write_scalar(Scalar::from_i32(1), dest)?; } diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 5b0de43e5466..01c7b4a1eb4f 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -284,15 +284,16 @@ fn reacquire_cond_mutex<'mir, 'tcx: 'mir>( thread: ThreadId, mutex: MutexId, ) -> InterpResult<'tcx> { + ecx.unblock_thread(thread); if ecx.mutex_is_locked(mutex) { - ecx.mutex_enqueue(mutex, thread); + ecx.mutex_enqueue_and_block(mutex, thread); } else { ecx.mutex_lock(mutex, thread); - ecx.unblock_thread(thread)?; } Ok(()) } +/// After a thread waiting on a condvar was signalled: /// Reacquire the conditional variable and remove the timeout callback if any /// was registered. fn post_cond_signal<'mir, 'tcx: 'mir>( @@ -303,12 +304,13 @@ fn post_cond_signal<'mir, 'tcx: 'mir>( reacquire_cond_mutex(ecx, thread, mutex)?; // Waiting for the mutex is not included in the waiting time because we need // to acquire the mutex always even if we get a timeout. - ecx.unregister_timeout_callback_if_exists(thread) + ecx.unregister_timeout_callback_if_exists(thread); + Ok(()) } /// Release the mutex associated with the condition variable because we are /// entering the waiting state. -fn release_cond_mutex<'mir, 'tcx: 'mir>( +fn release_cond_mutex_and_block<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, active_thread: ThreadId, mutex: MutexId, @@ -320,7 +322,7 @@ fn release_cond_mutex<'mir, 'tcx: 'mir>( } else { throw_ub_format!("awaiting on unlocked or owned by a different thread mutex"); } - ecx.block_thread(active_thread)?; + ecx.block_thread(active_thread); Ok(()) } @@ -411,14 +413,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; let id = mutex_get_or_create_id(this, mutex_op)?; - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); if this.mutex_is_locked(id) { let owner_thread = this.mutex_get_owner(id); if owner_thread != active_thread { - // Block the active thread. - this.block_thread(active_thread)?; - this.mutex_enqueue(id, active_thread); + // Enqueue the active thread. + this.mutex_enqueue_and_block(id, active_thread); Ok(0) } else { // Trying to acquire the same mutex again. @@ -449,7 +450,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; let id = mutex_get_or_create_id(this, mutex_op)?; - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); if this.mutex_is_locked(id) { let owner_thread = this.mutex_get_owner(id); @@ -482,7 +483,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; let id = mutex_get_or_create_id(this, mutex_op)?; - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); if let Some(_old_locked_count) = this.mutex_unlock(id, active_thread)? { // The mutex was locked by the current thread. @@ -528,10 +529,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); if this.rwlock_is_write_locked(id) { - this.rwlock_enqueue_and_block_reader(id, active_thread)?; + this.rwlock_enqueue_and_block_reader(id, active_thread); Ok(0) } else { this.rwlock_reader_lock(id, active_thread); @@ -543,7 +544,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); if this.rwlock_is_write_locked(id) { this.eval_libc_i32("EBUSY") @@ -557,7 +558,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); if this.rwlock_is_locked(id) { // Note: this will deadlock if the lock is already locked by this @@ -565,14 +566,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // // Relevant documentation: // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_wrlock.html - // An in depth discussion on this topic: + // An in-depth discussion on this topic: // https://github.com/rust-lang/rust/issues/53127 // // FIXME: Detect and report the deadlock proactively. (We currently // report the deadlock only when no thread can continue execution, // but we could detect that this lock is already locked and report // an error.) - this.rwlock_enqueue_and_block_writer(id, active_thread)?; + this.rwlock_enqueue_and_block_writer(id, active_thread); } else { this.rwlock_writer_lock(id, active_thread); } @@ -584,7 +585,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); if this.rwlock_is_locked(id) { this.eval_libc_i32("EBUSY") @@ -598,15 +599,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); if this.rwlock_reader_unlock(id, active_thread) { // The thread was a reader. if this.rwlock_is_locked(id) { // No more readers owning the lock. Give it to a writer if there // is any. - if let Some(writer) = this.rwlock_dequeue_writer(id) { - this.unblock_thread(writer)?; + if let Some(writer) = this.rwlock_dequeue_and_unblock_writer(id) { this.rwlock_writer_lock(id, writer); } } @@ -617,14 +617,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We are prioritizing writers here against the readers. As a // result, not only readers can starve writers, but also writers can // starve readers. - if let Some(writer) = this.rwlock_dequeue_writer(id) { + if let Some(writer) = this.rwlock_dequeue_and_unblock_writer(id) { // Give the lock to another writer. - this.unblock_thread(writer)?; this.rwlock_writer_lock(id, writer); } else { // Give the lock to all readers. - while let Some(reader) = this.rwlock_dequeue_reader(id) { - this.unblock_thread(reader)?; + while let Some(reader) = this.rwlock_dequeue_and_unblock_reader(id) { this.rwlock_reader_lock(id, reader); } } @@ -753,9 +751,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let id = cond_get_or_create_id(this, cond_op)?; let mutex_id = mutex_get_or_create_id(this, mutex_op)?; - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); - release_cond_mutex(this, active_thread, mutex_id)?; + release_cond_mutex_and_block(this, active_thread, mutex_id)?; this.condvar_wait(id, active_thread, mutex_id); Ok(0) @@ -774,9 +772,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let id = cond_get_or_create_id(this, cond_op)?; let mutex_id = mutex_get_or_create_id(this, mutex_op)?; - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); - release_cond_mutex(this, active_thread, mutex_id)?; + release_cond_mutex_and_block(this, active_thread, mutex_id)?; this.condvar_wait(id, active_thread, mutex_id); // We return success for now and override it in the timeout callback. @@ -823,7 +821,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) }), - )?; + ); Ok(()) } @@ -833,7 +831,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let id = cond_get_or_create_id(this, cond_op)?; if this.condvar_is_awaited(id) { - throw_ub_format!("destroyed an awaited conditional variable"); + throw_ub_format!("destroying an awaited conditional variable"); } cond_set_id(this, cond_op, ScalarMaybeUninit::Uninit)?; cond_set_clock_id(this, cond_op, ScalarMaybeUninit::Uninit)?; diff --git a/src/shims/thread.rs b/src/shims/thread.rs index 3ea1ee0aa17d..e5d3a9f0d6f8 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -19,9 +19,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx For example, Miri does not detect data races yet.", ); - let new_thread_id = this.create_thread()?; + let new_thread_id = this.create_thread(); // Also switch to new thread so that we can push the first stackframe. - let old_thread_id = this.set_active_thread(new_thread_id)?; + let old_thread_id = this.set_active_thread(new_thread_id); let thread_info_place = this.deref_operand(thread)?; this.write_scalar( @@ -47,7 +47,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx StackPopCleanup::None { cleanup: true }, )?; - this.set_active_thread(old_thread_id)?; + this.set_active_thread(old_thread_id); Ok(0) } @@ -82,7 +82,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_self(&mut self, dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let thread_id = this.get_active_thread()?; + let thread_id = this.get_active_thread(); this.write_scalar(Scalar::from_uint(thread_id.to_u32(), dest.layout.size), dest) } @@ -105,10 +105,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // byte. Since `read_c_str` returns the string without the null // byte, we need to truncate to 15. name.truncate(15); - this.set_active_thread_name(name)?; + this.set_active_thread_name(name); } else if option == this.eval_libc_i32("PR_GET_NAME")? { let address = this.read_scalar(arg2)?.not_undef()?; - let mut name = this.get_active_thread_name()?.to_vec(); + let mut name = this.get_active_thread_name().to_vec(); name.push(0u8); assert!(name.len() <= 16); this.memory.write_bytes(address, name)?; @@ -127,7 +127,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.assert_target_os("macos", "pthread_setname_np"); let name = this.memory.read_c_str(name)?.to_owned(); - this.set_active_thread_name(name)?; + this.set_active_thread_name(name); Ok(()) } @@ -135,7 +135,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn sched_yield(&mut self) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.yield_active_thread()?; + this.yield_active_thread(); Ok(0) } diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 1ef4728faf07..695614633682 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -232,8 +232,8 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// yet. fn schedule_windows_tls_dtors(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let active_thread = this.get_active_thread()?; - assert_eq!(this.get_total_thread_count()?, 1, "concurrency on Windows not supported"); + let active_thread = this.get_active_thread(); + assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows not supported"); // Windows has a special magic linker section that is run on certain events. // Instead of searching for that section and supporting arbitrary hooks in there // (that would be basically https://github.com/rust-lang/miri/issues/450), @@ -252,7 +252,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx StackPopCleanup::None { cleanup: true }, )?; - this.enable_thread(active_thread)?; + this.enable_thread(active_thread); Ok(()) } @@ -262,7 +262,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Note: It is safe to call this function also on other Unixes. fn schedule_macos_tls_dtor(&mut self) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - let thread_id = this.get_active_thread()?; + let thread_id = this.get_active_thread(); if let Some((instance, data)) = this.machine.tls.macos_thread_dtors.remove(&thread_id) { trace!("Running macos dtor {:?} on {:?} at {:?}", instance, data, thread_id); @@ -278,7 +278,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // we just scheduled. Since we deleted the destructor, it is // guaranteed that we will schedule it again. The `dtors_running` // flag will prevent the code from adding the destructor again. - this.enable_thread(thread_id)?; + this.enable_thread(thread_id); Ok(true) } else { Ok(false) @@ -289,9 +289,9 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// a destructor to schedule, and `false` otherwise. fn schedule_next_pthread_tls_dtor(&mut self) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); - assert!(this.has_terminated(active_thread)?, "running TLS dtors for non-terminated thread"); + assert!(this.has_terminated(active_thread), "running TLS dtors for non-terminated thread"); // Fetch next dtor after `key`. let last_key = this.machine.tls.dtors_running[&active_thread].last_dtor_key.clone(); let dtor = match this.machine.tls.fetch_tls_dtor(last_key, active_thread) { @@ -314,7 +314,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx StackPopCleanup::None { cleanup: true }, )?; - this.enable_thread(active_thread)?; + this.enable_thread(active_thread); return Ok(true); } this.machine.tls.dtors_running.get_mut(&active_thread).unwrap().last_dtor_key = None; @@ -340,7 +340,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// https://github.com/rust-lang/rust/issues/28129. fn schedule_next_tls_dtor_for_active_thread(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); if !this.machine.tls.set_dtors_running_for_thread(active_thread) { // This is the first time we got asked to schedule a destructor. The diff --git a/src/sync.rs b/src/sync.rs index 107ad5ace172..8418bd429515 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -145,13 +145,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex.lock_count = mutex.lock_count.checked_add(1).unwrap(); } - /// Try unlocking by decreasing the lock count and returning the old owner - /// and the old lock count. If the lock count reaches 0, release the lock - /// and potentially give to a new owner. If the lock was not locked, return - /// `None`. - /// - /// Note: It is the caller's responsibility to check that the thread that - /// unlocked the lock actually is the same one, which owned it. + /// Try unlocking by decreasing the lock count and returning the old lock + /// count. If the lock count reaches 0, release the lock and potentially + /// give to a new owner. If the lock was not locked by `expected_owner`, + /// return `None`. fn mutex_unlock( &mut self, id: MutexId, @@ -173,9 +170,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex.owner = None; // The mutex is completely unlocked. Try transfering ownership // to another thread. - if let Some(new_owner) = this.mutex_dequeue(id) { + if let Some(new_owner) = this.mutex_dequeue_and_unblock(id) { this.mutex_lock(id, new_owner); - this.unblock_thread(new_owner)?; } } Ok(Some(old_lock_count)) @@ -187,17 +183,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] /// Put the thread into the queue waiting for the lock. - fn mutex_enqueue(&mut self, id: MutexId, thread: ThreadId) { + fn mutex_enqueue_and_block(&mut self, id: MutexId, thread: ThreadId) { let this = self.eval_context_mut(); assert!(this.mutex_is_locked(id), "queing on unlocked mutex"); this.machine.threads.sync.mutexes[id].queue.push_back(thread); + this.block_thread(thread); } #[inline] /// Take a thread out of the queue waiting for the lock. - fn mutex_dequeue(&mut self, id: MutexId) -> Option { + fn mutex_dequeue_and_unblock(&mut self, id: MutexId) -> Option { let this = self.eval_context_mut(); - this.machine.threads.sync.mutexes[id].queue.pop_front() + if let Some(thread) = this.machine.threads.sync.mutexes[id].queue.pop_front() { + this.unblock_thread(thread); + Some(thread) + } else { + None + } } #[inline] @@ -255,25 +257,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, id: RwLockId, reader: ThreadId, - ) -> InterpResult<'tcx> { + ) { let this = self.eval_context_mut(); assert!(this.rwlock_is_write_locked(id), "queueing on not write locked lock"); this.machine.threads.sync.rwlocks[id].reader_queue.push_back(reader); - this.block_thread(reader) + this.block_thread(reader); } #[inline] /// Take a reader out the queue waiting for the lock. - fn rwlock_dequeue_reader(&mut self, id: RwLockId) -> Option { + fn rwlock_dequeue_and_unblock_reader(&mut self, id: RwLockId) -> Option { let this = self.eval_context_mut(); - this.machine.threads.sync.rwlocks[id].reader_queue.pop_front() + if let Some(reader) = this.machine.threads.sync.rwlocks[id].reader_queue.pop_front() { + this.unblock_thread(reader); + Some(reader) + } else { + None + } } #[inline] /// Lock by setting the writer that owns the lock. fn rwlock_writer_lock(&mut self, id: RwLockId, writer: ThreadId) { let this = self.eval_context_mut(); - assert!(!this.rwlock_is_locked(id), "the lock is already locked"); + assert!(!this.rwlock_is_locked(id), "the relock is already locked"); this.machine.threads.sync.rwlocks[id].writer = Some(writer); } @@ -290,18 +297,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, id: RwLockId, writer: ThreadId, - ) -> InterpResult<'tcx> { + ) { let this = self.eval_context_mut(); assert!(this.rwlock_is_locked(id), "queueing on unlocked lock"); this.machine.threads.sync.rwlocks[id].writer_queue.push_back(writer); - this.block_thread(writer) + this.block_thread(writer); } #[inline] /// Take the writer out the queue waiting for the lock. - fn rwlock_dequeue_writer(&mut self, id: RwLockId) -> Option { + fn rwlock_dequeue_and_unblock_writer(&mut self, id: RwLockId) -> Option { let this = self.eval_context_mut(); - this.machine.threads.sync.rwlocks[id].writer_queue.pop_front() + if let Some(writer) = this.machine.threads.sync.rwlocks[id].writer_queue.pop_front() { + this.unblock_thread(writer); + Some(writer) + } else { + None + } } #[inline] diff --git a/src/thread.rs b/src/thread.rs index 59f08eec1649..246a383d178b 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -581,9 +581,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[inline] - fn create_thread(&mut self) -> InterpResult<'tcx, ThreadId> { + fn create_thread(&mut self) -> ThreadId { let this = self.eval_context_mut(); - Ok(this.machine.threads.create_thread()) + this.machine.threads.create_thread() } #[inline] @@ -599,34 +599,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[inline] - fn set_active_thread(&mut self, thread_id: ThreadId) -> InterpResult<'tcx, ThreadId> { + fn set_active_thread(&mut self, thread_id: ThreadId) -> ThreadId { let this = self.eval_context_mut(); - Ok(this.machine.threads.set_active_thread_id(thread_id)) + this.machine.threads.set_active_thread_id(thread_id) } #[inline] - fn get_active_thread(&self) -> InterpResult<'tcx, ThreadId> { + fn get_active_thread(&self) -> ThreadId { let this = self.eval_context_ref(); - Ok(this.machine.threads.get_active_thread_id()) + this.machine.threads.get_active_thread_id() } #[inline] - fn get_total_thread_count(&self) -> InterpResult<'tcx, usize> { + fn get_total_thread_count(&self) -> usize { let this = self.eval_context_ref(); - Ok(this.machine.threads.get_total_thread_count()) + this.machine.threads.get_total_thread_count() } #[inline] - fn has_terminated(&self, thread_id: ThreadId) -> InterpResult<'tcx, bool> { + fn has_terminated(&self, thread_id: ThreadId) -> bool { let this = self.eval_context_ref(); - Ok(this.machine.threads.has_terminated(thread_id)) + this.machine.threads.has_terminated(thread_id) } #[inline] - fn enable_thread(&mut self, thread_id: ThreadId) -> InterpResult<'tcx> { + fn enable_thread(&mut self, thread_id: ThreadId) { let this = self.eval_context_mut(); this.machine.threads.enable_thread(thread_id); - Ok(()) } #[inline] @@ -642,37 +641,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[inline] - fn set_active_thread_name(&mut self, new_thread_name: Vec) -> InterpResult<'tcx, ()> { + fn set_active_thread_name(&mut self, new_thread_name: Vec) { let this = self.eval_context_mut(); - Ok(this.machine.threads.set_thread_name(new_thread_name)) + this.machine.threads.set_thread_name(new_thread_name); } #[inline] - fn get_active_thread_name<'c>(&'c self) -> InterpResult<'tcx, &'c [u8]> + fn get_active_thread_name<'c>(&'c self) -> &'c [u8] where 'mir: 'c, { let this = self.eval_context_ref(); - Ok(this.machine.threads.get_thread_name()) + this.machine.threads.get_thread_name() } #[inline] - fn block_thread(&mut self, thread: ThreadId) -> InterpResult<'tcx> { + fn block_thread(&mut self, thread: ThreadId) { let this = self.eval_context_mut(); - Ok(this.machine.threads.block_thread(thread)) + this.machine.threads.block_thread(thread); } #[inline] - fn unblock_thread(&mut self, thread: ThreadId) -> InterpResult<'tcx> { + fn unblock_thread(&mut self, thread: ThreadId) { let this = self.eval_context_mut(); - Ok(this.machine.threads.unblock_thread(thread)) + this.machine.threads.unblock_thread(thread); } #[inline] - fn yield_active_thread(&mut self) -> InterpResult<'tcx> { + fn yield_active_thread(&mut self) { let this = self.eval_context_mut(); this.machine.threads.yield_active_thread(); - Ok(()) } #[inline] @@ -681,17 +679,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx thread: ThreadId, call_time: Time, callback: TimeoutCallback<'mir, 'tcx>, - ) -> InterpResult<'tcx> { + ) { let this = self.eval_context_mut(); this.machine.threads.register_timeout_callback(thread, call_time, callback); - Ok(()) } #[inline] - fn unregister_timeout_callback_if_exists(&mut self, thread: ThreadId) -> InterpResult<'tcx> { + fn unregister_timeout_callback_if_exists(&mut self, thread: ThreadId) { let this = self.eval_context_mut(); this.machine.threads.unregister_timeout_callback_if_exists(thread); - Ok(()) } /// Execute a timeout callback on the callback's thread. @@ -706,9 +702,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // thread. // 2. Make the scheduler the only place that can change the active // thread. - let old_thread = this.set_active_thread(thread)?; + let old_thread = this.set_active_thread(thread); callback(this)?; - this.set_active_thread(old_thread)?; + this.set_active_thread(old_thread); Ok(()) } From a80821e046c75878f4b63eac35c642b48c5825c3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 May 2020 22:35:58 +0200 Subject: [PATCH 2122/5092] also combine re-locking into the dequeue-and-unblock operation --- src/shims/sync.rs | 13 +++++-------- src/sync.rs | 32 ++++++++++++++++++-------------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 01c7b4a1eb4f..2669776db5ba 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -606,9 +606,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.rwlock_is_locked(id) { // No more readers owning the lock. Give it to a writer if there // is any. - if let Some(writer) = this.rwlock_dequeue_and_unblock_writer(id) { - this.rwlock_writer_lock(id, writer); - } + this.rwlock_dequeue_and_lock_writer(id); } Ok(0) } else if Some(active_thread) == this.rwlock_writer_unlock(id) { @@ -617,13 +615,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We are prioritizing writers here against the readers. As a // result, not only readers can starve writers, but also writers can // starve readers. - if let Some(writer) = this.rwlock_dequeue_and_unblock_writer(id) { - // Give the lock to another writer. - this.rwlock_writer_lock(id, writer); + if this.rwlock_dequeue_and_lock_writer(id) { + // Someone got the write lock, nice. } else { // Give the lock to all readers. - while let Some(reader) = this.rwlock_dequeue_and_unblock_reader(id) { - this.rwlock_reader_lock(id, reader); + while this.rwlock_dequeue_and_lock_reader(id) { + // Rinse and repeat. } } Ok(0) diff --git a/src/sync.rs b/src/sync.rs index 8418bd429515..723815dbf226 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -170,9 +170,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex.owner = None; // The mutex is completely unlocked. Try transfering ownership // to another thread. - if let Some(new_owner) = this.mutex_dequeue_and_unblock(id) { - this.mutex_lock(id, new_owner); - } + this.mutex_dequeue_and_lock(id); } Ok(Some(old_lock_count)) } else { @@ -182,7 +180,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[inline] - /// Put the thread into the queue waiting for the lock. + /// Put the thread into the queue waiting for the mutex. fn mutex_enqueue_and_block(&mut self, id: MutexId, thread: ThreadId) { let this = self.eval_context_mut(); assert!(this.mutex_is_locked(id), "queing on unlocked mutex"); @@ -191,14 +189,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[inline] - /// Take a thread out of the queue waiting for the lock. - fn mutex_dequeue_and_unblock(&mut self, id: MutexId) -> Option { + /// Take a thread out of the queue waiting for the mutex, and lock + /// the mutex for it. Returns `true` if some thread has the mutex now. + fn mutex_dequeue_and_lock(&mut self, id: MutexId) -> bool { let this = self.eval_context_mut(); if let Some(thread) = this.machine.threads.sync.mutexes[id].queue.pop_front() { this.unblock_thread(thread); - Some(thread) + this.mutex_lock(id, thread); + true } else { - None + false } } @@ -266,13 +266,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] /// Take a reader out the queue waiting for the lock. - fn rwlock_dequeue_and_unblock_reader(&mut self, id: RwLockId) -> Option { + /// Returns `true` if some thread got the rwlock. + fn rwlock_dequeue_and_lock_reader(&mut self, id: RwLockId) -> bool { let this = self.eval_context_mut(); if let Some(reader) = this.machine.threads.sync.rwlocks[id].reader_queue.pop_front() { this.unblock_thread(reader); - Some(reader) + this.rwlock_reader_lock(id, reader); + true } else { - None + false } } @@ -306,13 +308,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] /// Take the writer out the queue waiting for the lock. - fn rwlock_dequeue_and_unblock_writer(&mut self, id: RwLockId) -> Option { + /// Returns `true` if some thread got the rwlock. + fn rwlock_dequeue_and_lock_writer(&mut self, id: RwLockId) -> bool { let this = self.eval_context_mut(); if let Some(writer) = this.machine.threads.sync.rwlocks[id].writer_queue.pop_front() { this.unblock_thread(writer); - Some(writer) + this.rwlock_writer_lock(id, writer); + true } else { - None + false } } From acb3ec0866ab9abad7772ce0c1e6eeb267e111cd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 May 2020 22:48:43 +0200 Subject: [PATCH 2123/5092] test and fix for rwlock unlock bug --- src/shims/sync.rs | 3 +- src/sync.rs | 2 +- tests/run-pass/concurrency/sync.rs | 47 ++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 2669776db5ba..39a087dc9ac2 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -1,5 +1,6 @@ use std::convert::TryInto; use std::time::{Duration, SystemTime}; +use std::ops::Not; use rustc_middle::ty::{layout::TyAndLayout, TyKind, TypeAndMut}; use rustc_target::abi::{LayoutOf, Size}; @@ -603,7 +604,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.rwlock_reader_unlock(id, active_thread) { // The thread was a reader. - if this.rwlock_is_locked(id) { + if this.rwlock_is_locked(id).not() { // No more readers owning the lock. Give it to a writer if there // is any. this.rwlock_dequeue_and_lock_writer(id); diff --git a/src/sync.rs b/src/sync.rs index 723815dbf226..5ba29b5afa25 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -282,7 +282,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Lock by setting the writer that owns the lock. fn rwlock_writer_lock(&mut self, id: RwLockId, writer: ThreadId) { let this = self.eval_context_mut(); - assert!(!this.rwlock_is_locked(id), "the relock is already locked"); + assert!(!this.rwlock_is_locked(id), "the rwlock is already locked"); this.machine.threads.sync.rwlocks[id].writer = Some(writer); } diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index 2009c01ce9f9..e36c79491f91 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -267,6 +267,51 @@ fn check_once() { } } +fn check_rwlock_unlock_bug1() { + // There was a bug where when un-read-locking an rwlock that still has other + // readers waiting, we'd accidentally also let a writer in. + // That caused an ICE. + let l = Arc::new(RwLock::new(0)); + + let r1 = l.read().unwrap(); + let r2 = l.read().unwrap(); + + // Make a waiting writer. + let l2 = l.clone(); + thread::spawn(move || { + let mut w = l2.write().unwrap(); + *w += 1; + }); + thread::yield_now(); + + drop(r1); + assert_eq!(*r2, 0); + thread::yield_now(); + thread::yield_now(); + thread::yield_now(); + assert_eq!(*r2, 0); + drop(r2); +} + +fn check_rwlock_unlock_bug2() { + // There was a bug where when un-read-locking an rwlock by letting the last reader leaver, + // we'd forget to wake up a writer. + // That meant the writer thread could never run again. + let l = Arc::new(RwLock::new(0)); + + let r = l.read().unwrap(); + + // Make a waiting writer. + let l2 = l.clone(); + let h = thread::spawn(move || { + let _w = l2.write().unwrap(); + }); + thread::yield_now(); + + drop(r); + h.join().unwrap(); +} + fn main() { check_barriers(); check_conditional_variables_notify_one(); @@ -280,4 +325,6 @@ fn main() { multiple_send(); send_on_sync(); check_once(); + check_rwlock_unlock_bug1(); + check_rwlock_unlock_bug2(); } From 67ad3041409ba87187c7c72e6f19ae79e1a7715f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 May 2020 22:50:49 +0200 Subject: [PATCH 2124/5092] update unsupported example in README (now that threading is supported on some platforms) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 12fc6d22cf85..b2738bb062aa 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ There is no way to list all the infinite things Miri cannot do, but the interpreter will explicitly tell you when it finds something unsupported: ``` -error: unsupported operation: Miri does not support threading +error: unsupported operation: can't call foreign function: bind ... = help: this is likely not a bug in the program; it indicates that the program \ performed an operation that the interpreter does not support From 0b6ec575b9d0c683b854ba4ea3da726620c209b9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 May 2020 22:54:37 +0200 Subject: [PATCH 2125/5092] make mutex_unlock infallible --- src/shims/sync.rs | 4 ++-- src/sync.rs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 39a087dc9ac2..8986455a14fc 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -316,7 +316,7 @@ fn release_cond_mutex_and_block<'mir, 'tcx: 'mir>( active_thread: ThreadId, mutex: MutexId, ) -> InterpResult<'tcx> { - if let Some(old_locked_count) = ecx.mutex_unlock(mutex, active_thread)? { + if let Some(old_locked_count) = ecx.mutex_unlock(mutex, active_thread) { if old_locked_count != 1 { throw_unsup_format!("awaiting on a lock acquired multiple times is not supported"); } @@ -486,7 +486,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let id = mutex_get_or_create_id(this, mutex_op)?; let active_thread = this.get_active_thread(); - if let Some(_old_locked_count) = this.mutex_unlock(id, active_thread)? { + if let Some(_old_locked_count) = this.mutex_unlock(id, active_thread) { // The mutex was locked by the current thread. Ok(0) } else { diff --git a/src/sync.rs b/src/sync.rs index 5ba29b5afa25..0d4b4d6b7c1c 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -153,14 +153,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, id: MutexId, expected_owner: ThreadId, - ) -> InterpResult<'tcx, Option> { + ) -> Option { let this = self.eval_context_mut(); let mutex = &mut this.machine.threads.sync.mutexes[id]; if let Some(current_owner) = mutex.owner { // Mutex is locked. if current_owner != expected_owner { // Only the owner can unlock the mutex. - return Ok(None); + return None; } let old_lock_count = mutex.lock_count; mutex.lock_count = old_lock_count @@ -172,10 +172,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // to another thread. this.mutex_dequeue_and_lock(id); } - Ok(Some(old_lock_count)) + Some(old_lock_count) } else { // Mutex is unlocked. - Ok(None) + None } } From 3032224d19394551580a402744ff85b8de5ae99a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 31 May 2020 10:30:25 +0200 Subject: [PATCH 2126/5092] rustup, adjust error message --- rust-version | 2 +- tests/compile-fail/validity/invalid_char.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 0124f254ec1e..dd0af02836c7 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0e9e4083100aa3ebf09b8f1ace0348cb37475eb9 +b6fa392238a459c29a47e2cf824d79a49a8ba039 diff --git a/tests/compile-fail/validity/invalid_char.rs b/tests/compile-fail/validity/invalid_char.rs index 2801f3297156..079823f894a8 100644 --- a/tests/compile-fail/validity/invalid_char.rs +++ b/tests/compile-fail/validity/invalid_char.rs @@ -1,6 +1,6 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); - let _val = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered 0xffffffff, but expected a valid unicode codepoint + let _val = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered 0xffffffff, but expected a valid unicode scalar value 'a' => {true}, 'b' => {false}, _ => {true}, From 7d406b152ada9c2af9af66724462710da014ff1a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 May 2020 18:46:26 +0200 Subject: [PATCH 2127/5092] test WTF8 encoding corner cases --- tests/run-pass/wtf8.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 tests/run-pass/wtf8.rs diff --git a/tests/run-pass/wtf8.rs b/tests/run-pass/wtf8.rs new file mode 100644 index 000000000000..2b4da785f2ee --- /dev/null +++ b/tests/run-pass/wtf8.rs @@ -0,0 +1,23 @@ +// ignore-linux: tests Windows-only APIs +// ignore-macos: tests Windows-only APIs + +use std::os::windows::ffi::{OsStrExt, OsStringExt}; +use std::ffi::{OsStr, OsString}; + +fn test1() { + let base = "a\té \u{7f}💩\r"; + let mut base: Vec = OsStr::new(base).encode_wide().collect(); + base.push(0xD800); + let _res = OsString::from_wide(&base); +} + +fn test2() { + let mut base: Vec = OsStr::new("aé ").encode_wide().collect(); + base.push(0xD83D); + let mut _res: Vec = OsString::from_wide(&base).encode_wide().collect(); +} + +fn main() { + test1(); + test2(); +} From 7cd68eb11b08571e75d882510dea7ce95f2d439f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 1 Jun 2020 01:15:00 +0200 Subject: [PATCH 2128/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index dd0af02836c7..c5327e4d2bbc 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -b6fa392238a459c29a47e2cf824d79a49a8ba039 +5fd2f06e99a985dd896684cb2c9f8c7090eca1ab From 17dd44ee92a0fc08fd6bc04c10ecd880d7a225a9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 1 Jun 2020 19:23:54 +0200 Subject: [PATCH 2129/5092] rustup --- rust-version | 2 +- src/machine.rs | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index c5327e4d2bbc..daae7a34d048 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -5fd2f06e99a985dd896684cb2c9f8c7090eca1ab +d3cba254e464303a6495942f3a831c2bbd7f1768 diff --git a/src/machine.rs b/src/machine.rs index 51aa7ae31047..4f45b4f93f18 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -22,6 +22,7 @@ use rustc_middle::{ }, }; use rustc_span::symbol::{sym, Symbol}; +use rustc_span::def_id::DefId; use rustc_target::abi::{LayoutOf, Size}; use crate::*; @@ -416,10 +417,18 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { Ok(()) } + fn thread_local_alloc_id( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + def_id: DefId, + ) -> InterpResult<'tcx, AllocId> { + ecx.get_or_create_thread_local_alloc_id(def_id) + } + fn adjust_global_const( ecx: &InterpCx<'mir, 'tcx, Self>, mut val: mir::interpret::ConstValue<'tcx>, ) -> InterpResult<'tcx, mir::interpret::ConstValue<'tcx>> { + // FIXME: Remove this, do The Right Thing in `thread_local_alloc_id` instead. ecx.remap_thread_local_alloc_ids(&mut val)?; Ok(val) } From dcb2b30982352362a0f10cbd45be298b31306eff Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Jun 2020 09:40:21 +0200 Subject: [PATCH 2130/5092] rustup, and adjust timing tests --- rust-version | 2 +- tests/run-pass/concurrency/libc_pthread_cond.rs | 2 ++ tests/run-pass/concurrency/sync.rs | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index daae7a34d048..d163c3162282 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d3cba254e464303a6495942f3a831c2bbd7f1768 +680a4b2fbdca0dc6c5ceec826a8dbeabe28f305d diff --git a/tests/run-pass/concurrency/libc_pthread_cond.rs b/tests/run-pass/concurrency/libc_pthread_cond.rs index 27f5ead450fa..8aa3b210f4b0 100644 --- a/tests/run-pass/concurrency/libc_pthread_cond.rs +++ b/tests/run-pass/concurrency/libc_pthread_cond.rs @@ -25,6 +25,8 @@ fn test_timed_wait_timeout(clock_id: i32) { let mut now: libc::timespec = mem::zeroed(); assert_eq!(libc::clock_gettime(clock_id, &mut now), 0); + // Waiting for a second... mostly because waiting less requires mich more tricky arithmetic. + // FIXME: wait less. let timeout = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: now.tv_nsec }; assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index e36c79491f91..b36ad27ebe19 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -109,7 +109,7 @@ fn check_conditional_variables_timed_wait_notimeout() { cvar.notify_one(); }); - let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap(); + let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(200)).unwrap(); assert!(!timeout.timed_out()); handle.join().unwrap(); } From e352d4fbb7bc46b66debd642967f18b9c7ecea2f Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 6 Jun 2020 16:54:13 +0000 Subject: [PATCH 2131/5092] Finish fixing Windows host support --- src/shims/fs.rs | 32 ++++++++++++++++++++++++-------- tests/run-pass/fs.rs | 5 +++++ tests/run-pass/libc.rs | 22 +++++++++++++++++++--- 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 7f1c5caaf642..ece4d236ba0d 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -379,9 +379,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx && cmd == this.eval_libc_i32("F_FULLFSYNC")? { let &[_, _] = check_arg_count(args)?; - if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { - let result = file.sync_all(); - this.try_unwrap_io_result(result.map(|_| 0i32)) + if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get_mut(&fd) { + if !*writable && cfg!(windows) { + // sync_all() will return an error on Windows hosts if the file is not opened + // for writing. (FlushFileBuffers requires that the file handle have the + // GENERIC_WRITE right) + Ok(0i32) + } else { + let result = file.sync_all(); + this.try_unwrap_io_result(result.map(|_| 0i32)) + } } else { this.handle_not_found() } @@ -1128,6 +1135,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get_mut(&fd) { if !*writable && cfg!(windows) { // sync_all() will return an error on Windows hosts if the file is not opened for writing. + // (FlushFileBuffers requires that the file handle have the GENERIC_WRITE right) Ok(0i32) } else { let result = file.sync_all(); @@ -1147,6 +1155,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get_mut(&fd) { if !*writable && cfg!(windows) { // sync_data() will return an error on Windows hosts if the file is not opened for writing. + // (FlushFileBuffers requires that the file handle have the GENERIC_WRITE right) Ok(0i32) } else { let result = file.sync_data(); @@ -1187,11 +1196,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } - if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { - // In the interest of host compatibility, we conservatively ignore - // offset, nbytes, and flags, and sync the entire file. - let result = file.sync_data(); - this.try_unwrap_io_result(result.map(|_| 0i32)) + if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get_mut(&fd) { + if !*writable && cfg!(windows) { + // sync_data() will return an error on Windows hosts if the file is not opened for + // writing. (FlushFileBuffers requires that the file handle have the GENERIC_WRITE + // right) + Ok(0i32) + } else { + // In the interest of host compatibility, we conservatively ignore + // offset, nbytes, and flags, and sync the entire file. + let result = file.sync_data(); + this.try_unwrap_io_result(result.map(|_| 0i32)) + } } else { this.handle_not_found() } diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index a031233d581a..caa9bffc2bc8 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -192,6 +192,11 @@ fn test_file_sync() { file.sync_data().unwrap(); file.sync_all().unwrap(); + // Test that we can call sync_data and sync_all on a file opened for reading. + let file = File::open(&path).unwrap(); + file.sync_data().unwrap(); + file.sync_all().unwrap(); + remove_file(&path).unwrap(); } diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index 08199c1452d3..6f30cb5a9150 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -55,8 +55,8 @@ fn test_sync_file_range() { let bytes = b"Hello, World!\n"; file.write(bytes).unwrap(); - // Test calling sync_file_range on a file. - let result = unsafe { + // Test calling sync_file_range on the file. + let result_1 = unsafe { libc::sync_file_range( file.as_raw_fd(), 0, @@ -67,8 +67,24 @@ fn test_sync_file_range() { ) }; drop(file); + + // Test calling sync_file_range on a file opened for reading. + let file = File::open(&path).unwrap(); + let result_2 = unsafe { + libc::sync_file_range( + file.as_raw_fd(), + 0, + 0, + libc::SYNC_FILE_RANGE_WAIT_BEFORE + | libc::SYNC_FILE_RANGE_WRITE + | libc::SYNC_FILE_RANGE_WAIT_AFTER, + ) + }; + drop(file); + remove_file(&path).unwrap(); - assert_eq!(result, 0); + assert_eq!(result_1, 0); + assert_eq!(result_2, 0); } fn test_mutex_libc_init_recursive() { From ea4a5587ca230b9f485085fb5c5891de9452bf13 Mon Sep 17 00:00:00 2001 From: Youngsuk Kim Date: Mon, 8 Jun 2020 17:30:43 -0400 Subject: [PATCH 2132/5092] Add a case to list of 'StackedBorrows violations' A small fix was made to libstd in rust-lang/rust#70479 (back in March). (Miri reported UB due to Stacked Borrows violation - [link to Miri error log](https://github.com/rust-lang/miri/pull/1225#discussion_r397830221)) Thank you for reviewing :+1: --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b2738bb062aa..6b2b36d18c32 100644 --- a/README.md +++ b/README.md @@ -295,6 +295,7 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [`ryu` using raw pointers outside their valid memory area](https://github.com/dtolnay/ryu/issues/24) * [ink! creating overlapping mutable references](https://github.com/rust-lang/miri/issues/1364) * [TiKV creating overlapping mutable reference and raw pointer](https://github.com/tikv/tikv/pull/7709) +* [Windows `Env` iterator creating `*const T` from `&T` to read memory outside of `T`](https://github.com/rust-lang/rust/pull/70479) ## License From a60c130b0d4e1caecd525682c320224023bdf4a5 Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 8 Jun 2020 23:34:02 +0000 Subject: [PATCH 2133/5092] Extract common logic for Windows host workaround --- src/shims/fs.rs | 64 +++++++++++++++++++------------------------------ 1 file changed, 24 insertions(+), 40 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index ece4d236ba0d..c789263ebea7 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -232,6 +232,18 @@ impl Default for DirHandler { } } +fn maybe_sync_file(file: &File, writable: bool, operation: fn(&File) -> std::io::Result<()>) -> std::io::Result { + if !writable && cfg!(windows) { + // sync_all() and sync_data() will return an error on Windows hosts if the file is not opened + // for writing. (FlushFileBuffers requires that the file handle have the + // GENERIC_WRITE right) + Ok(0i32) + } else { + let result = operation(file); + result.map(|_| 0i32) + } +} + impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn open( @@ -379,16 +391,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx && cmd == this.eval_libc_i32("F_FULLFSYNC")? { let &[_, _] = check_arg_count(args)?; - if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get_mut(&fd) { - if !*writable && cfg!(windows) { - // sync_all() will return an error on Windows hosts if the file is not opened - // for writing. (FlushFileBuffers requires that the file handle have the - // GENERIC_WRITE right) - Ok(0i32) - } else { - let result = file.sync_all(); - this.try_unwrap_io_result(result.map(|_| 0i32)) - } + if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get(&fd) { + let io_result = maybe_sync_file(file, *writable, File::sync_all); + this.try_unwrap_io_result(io_result) } else { this.handle_not_found() } @@ -1132,15 +1137,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("fsync")?; let fd = this.read_scalar(fd_op)?.to_i32()?; - if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get_mut(&fd) { - if !*writable && cfg!(windows) { - // sync_all() will return an error on Windows hosts if the file is not opened for writing. - // (FlushFileBuffers requires that the file handle have the GENERIC_WRITE right) - Ok(0i32) - } else { - let result = file.sync_all(); - this.try_unwrap_io_result(result.map(|_| 0i32)) - } + if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get(&fd) { + let io_result = maybe_sync_file(file, *writable, File::sync_all); + this.try_unwrap_io_result(io_result) } else { this.handle_not_found() } @@ -1152,15 +1151,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("fdatasync")?; let fd = this.read_scalar(fd_op)?.to_i32()?; - if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get_mut(&fd) { - if !*writable && cfg!(windows) { - // sync_data() will return an error on Windows hosts if the file is not opened for writing. - // (FlushFileBuffers requires that the file handle have the GENERIC_WRITE right) - Ok(0i32) - } else { - let result = file.sync_data(); - this.try_unwrap_io_result(result.map(|_| 0i32)) - } + if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get(&fd) { + let io_result = maybe_sync_file(file, *writable, File::sync_data); + this.try_unwrap_io_result(io_result) } else { this.handle_not_found() } @@ -1196,18 +1189,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } - if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get_mut(&fd) { - if !*writable && cfg!(windows) { - // sync_data() will return an error on Windows hosts if the file is not opened for - // writing. (FlushFileBuffers requires that the file handle have the GENERIC_WRITE - // right) - Ok(0i32) - } else { - // In the interest of host compatibility, we conservatively ignore - // offset, nbytes, and flags, and sync the entire file. - let result = file.sync_data(); - this.try_unwrap_io_result(result.map(|_| 0i32)) - } + if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get(&fd) { + let io_result = maybe_sync_file(file, *writable, File::sync_data); + this.try_unwrap_io_result(io_result) } else { this.handle_not_found() } From 34f495a99438f8af3ba6c60ba97acc094d58ac65 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 10 Jun 2020 10:55:48 +0200 Subject: [PATCH 2134/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index d163c3162282..177b6ada7340 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -680a4b2fbdca0dc6c5ceec826a8dbeabe28f305d +bb8674837a9cc5225020e07fc3f164762bb4c11c From 399435240550ade667e3315e22e8c72458e31e2f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 12 Jun 2020 10:00:46 +0200 Subject: [PATCH 2135/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 177b6ada7340..adb8991d4ad8 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -bb8674837a9cc5225020e07fc3f164762bb4c11c +50c0192c64241d723066add22c53d472e2b9cba9 From e063ce27370e217f37905620edaaec73e1bbc618 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 13 Jun 2020 11:30:31 +0200 Subject: [PATCH 2136/5092] rustup; and a bit of UnsafeCell detection refactoring --- rust-version | 2 +- src/helpers.rs | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/rust-version b/rust-version index adb8991d4ad8..017196c1669d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -50c0192c64241d723066add22c53d472e2b9cba9 +1fb612bd15bb3ef098fd24c20d0727de573b4410 diff --git a/src/helpers.rs b/src/helpers.rs index 8b20ee2f0d83..4e5e0dcfca25 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -291,6 +291,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if self.ecx.type_is_freeze(v.layout.ty) { // This is `Freeze`, there cannot be an `UnsafeCell` Ok(()) + } else if matches!(v.layout.fields, FieldsShape::Union(..)) { + // A (non-frozen) union. We fall back to whatever the type says. + (self.unsafe_cell_action)(v) } else { // We want to not actually read from memory for this visit. So, before // walking this value, we have to make sure it is not a @@ -341,13 +344,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - // We have to do *something* for unions. - fn visit_union(&mut self, v: MPlaceTy<'tcx, Tag>, _fields: NonZeroUsize) -> InterpResult<'tcx> { - // With unions, we fall back to whatever the type says, to hopefully be consistent - // with LLVM IR. - // FIXME: are we consistent, and is this really the behavior we want? - let frozen = self.ecx.type_is_freeze(v.layout.ty); - if frozen { Ok(()) } else { (self.unsafe_cell_action)(v) } + fn visit_union(&mut self, _v: MPlaceTy<'tcx, Tag>, _fields: NonZeroUsize) -> InterpResult<'tcx> { + bug!("we should have already handled unions in `visit_value`") } } } From 9df8d588eaa87f79b6a7bdc139621d240c198962 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 15 Jun 2020 10:58:20 +0200 Subject: [PATCH 2137/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 017196c1669d..4ecda8a5f4f5 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1fb612bd15bb3ef098fd24c20d0727de573b4410 +4fb54ed484e2239a3e9eff3be17df00d2a162be3 From 5c5b61ffb0810e4aa318fd5f20a49f016f3a1e36 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 15 Jun 2020 17:38:27 +0200 Subject: [PATCH 2138/5092] rustup --- rust-version | 2 +- src/eval.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 4ecda8a5f4f5..342ec7486e67 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4fb54ed484e2239a3e9eff3be17df00d2a162be3 +ff4a2533a0720f9cdd86e02eafa3725f07aa7752 diff --git a/src/eval.rs b/src/eval.rs index 7a6c562e7ca0..56d6f3ed3c5b 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -63,11 +63,11 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( main_id: DefId, config: MiriConfig, ) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, MPlaceTy<'tcx, Tag>)> { - let tcx_at = tcx.at(rustc_span::source_map::DUMMY_SP); let param_env = ty::ParamEnv::reveal_all(); let layout_cx = LayoutCx { tcx, param_env }; let mut ecx = InterpCx::new( - tcx_at, + tcx, + rustc_span::source_map::DUMMY_SP, param_env, Evaluator::new(config.communicate, config.validate, layout_cx), MemoryExtra::new( From 2940da9d1f22982b237cf7c64d7e9e5829397f88 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 20 Jun 2020 11:48:42 +0200 Subject: [PATCH 2139/5092] bump Rust --- rust-version | 2 +- .../{invalid_enum_discriminant.rs => invalid_enum_tag.rs} | 2 +- .../{invalid_enum_discriminant.rs => invalid_enum_tag.rs} | 2 +- tests/compile-fail/validity/transmute_through_ptr.rs | 4 ++-- tests/run-pass/panic/catch_panic.rs | 4 ++-- tests/run-pass/panic/catch_panic.stderr | 4 ++-- tests/run-pass/specialization.rs | 1 + 7 files changed, 10 insertions(+), 9 deletions(-) rename tests/compile-fail/{invalid_enum_discriminant.rs => invalid_enum_tag.rs} (85%) rename tests/compile-fail/validity/{invalid_enum_discriminant.rs => invalid_enum_tag.rs} (63%) diff --git a/rust-version b/rust-version index 342ec7486e67..f001577e7f0c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -ff4a2533a0720f9cdd86e02eafa3725f07aa7752 +033013cab3a861224fd55f494c8be1cb0349eb49 diff --git a/tests/compile-fail/invalid_enum_discriminant.rs b/tests/compile-fail/invalid_enum_tag.rs similarity index 85% rename from tests/compile-fail/invalid_enum_discriminant.rs rename to tests/compile-fail/invalid_enum_tag.rs index 893dd03c64e6..762a70d803a4 100644 --- a/tests/compile-fail/invalid_enum_discriminant.rs +++ b/tests/compile-fail/invalid_enum_tag.rs @@ -2,7 +2,7 @@ // Make sure we find these even with many checks disabled. // compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation -// error-pattern: enum value has invalid discriminant: 0x0000002a +// error-pattern: enum value has invalid tag: 0x0000002a use std::mem; diff --git a/tests/compile-fail/validity/invalid_enum_discriminant.rs b/tests/compile-fail/validity/invalid_enum_tag.rs similarity index 63% rename from tests/compile-fail/validity/invalid_enum_discriminant.rs rename to tests/compile-fail/validity/invalid_enum_tag.rs index a3234ba0920c..897bfa90a702 100644 --- a/tests/compile-fail/validity/invalid_enum_discriminant.rs +++ b/tests/compile-fail/validity/invalid_enum_tag.rs @@ -4,5 +4,5 @@ pub enum Foo { } fn main() { - let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR encountered 0x0000002a, but expected a valid enum discriminant + let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR encountered 0x0000002a, but expected a valid enum tag } diff --git a/tests/compile-fail/validity/transmute_through_ptr.rs b/tests/compile-fail/validity/transmute_through_ptr.rs index 617781c12751..1d5cf16aa5ea 100644 --- a/tests/compile-fail/validity/transmute_through_ptr.rs +++ b/tests/compile-fail/validity/transmute_through_ptr.rs @@ -3,12 +3,12 @@ enum Bool { True } fn evil(x: &mut Bool) { let x = x as *mut _ as *mut u32; - unsafe { *x = 44; } // out-of-bounds enum discriminant + unsafe { *x = 44; } // out-of-bounds enum tag } fn main() { let mut x = Bool::True; evil(&mut x); let _y = x; // reading this ought to be enough to trigger validation - //~^ ERROR encountered 0x0000002c, but expected a valid enum discriminant + //~^ ERROR encountered 0x0000002c, but expected a valid enum tag } diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index 7689b85f7650..288ae1965a69 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -1,5 +1,5 @@ // ignore-windows: Unwind panicking does not currently work on Windows -// normalize-stderr-test "[^ ]*libcore/(macros|mem)/mod.rs[0-9:]*" -> "$$LOC" +// normalize-stderr-test "[^ ]*libcore/[a-z/]+.rs[0-9:]*" -> "$$LOC" #![feature(never_type)] #![allow(unconditional_panic)] use std::panic::{catch_unwind, AssertUnwindSafe}; @@ -75,7 +75,7 @@ fn main() { // Assertion and debug assertion test(None, |_old_val| { assert!(false); loop {} }); test(None, |_old_val| { debug_assert!(false); loop {} }); - test(None, |_old_val| { unsafe { (1 as *const i32).read() }; loop {} }); // trigger debug-assertion in libstd + test(None, |_old_val| { unsafe { std::char::from_u32_unchecked(0xFD10000); } loop {} }); // trigger debug-assertion in libstd eprintln!("Success!"); // Make sure we get this in stderr } diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr index 6da9cd29963a..f64ff1186619 100644 --- a/tests/run-pass/panic/catch_panic.stderr +++ b/tests/run-pass/panic/catch_panic.stderr @@ -22,6 +22,6 @@ thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:76:29 Caught panic message (&str): assertion failed: false thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:77:29 Caught panic message (&str): assertion failed: false -thread 'main' panicked at 'attempt to copy from unaligned or null pointer', $LOC -Caught panic message (String): attempt to copy from unaligned or null pointer +thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', $LOC +Caught panic message (String): called `Option::unwrap()` on a `None` value Success! diff --git a/tests/run-pass/specialization.rs b/tests/run-pass/specialization.rs index 13894926d36d..44cef00a22c3 100644 --- a/tests/run-pass/specialization.rs +++ b/tests/run-pass/specialization.rs @@ -1,3 +1,4 @@ +#![allow(incomplete_features)] #![feature(specialization)] trait IsUnit { From a29f86b512a0a6a353c11f44af768da6bdc5c782 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 20 Jun 2020 14:28:55 +0200 Subject: [PATCH 2140/5092] make sure '&raw *' on a dangling raw ptr is UB --- .../dangling_pointers/dangling_pointer_addr_of.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.rs diff --git a/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.rs b/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.rs new file mode 100644 index 000000000000..5df5b324f457 --- /dev/null +++ b/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.rs @@ -0,0 +1,13 @@ +// Make sure we find these even with many checks disabled. +// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +#![feature(raw_ref_macros)] +use std::ptr; + +fn main() { + let p = { + let b = Box::new(42); + &*b as *const i32 + }; + let x = unsafe { ptr::raw_const!(*p) }; //~ ERROR dereferenced after this allocation got freed + panic!("this should never print: {:?}", x); +} From 03fe3772a8a6859b2aa890f5a002e7cc3707e326 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 20 Jun 2020 14:31:47 +0200 Subject: [PATCH 2141/5092] make sure the raw_ptr macros also avoid UB --- tests/run-pass/packed_struct.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/packed_struct.rs b/tests/run-pass/packed_struct.rs index 5582caaf37ea..43419695ba04 100644 --- a/tests/run-pass/packed_struct.rs +++ b/tests/run-pass/packed_struct.rs @@ -1,7 +1,8 @@ -#![feature(unsize, coerce_unsized, raw_ref_op)] +#![feature(unsize, coerce_unsized, raw_ref_op, raw_ref_macros)] use std::collections::hash_map::DefaultHasher; use std::hash::Hash; +use std::ptr; fn test_basic() { #[repr(packed)] @@ -45,7 +46,9 @@ fn test_basic() { assert_eq!({x.b}, 99); // but we *can* take a raw pointer! assert_eq!(unsafe { (&raw const x.a).read_unaligned() }, 42); + assert_eq!(unsafe { ptr::raw_const!(x.a).read_unaligned() }, 42); assert_eq!(unsafe { (&raw const x.b).read_unaligned() }, 99); + assert_eq!(unsafe { ptr::raw_const!(x.b).read_unaligned() }, 99); x.b = 77; assert_eq!({x.b}, 77); From 8d1d5724727ee5a6862881bc97da86b9c90f9b21 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 20 Jun 2020 14:34:57 +0200 Subject: [PATCH 2142/5092] unaligned-raw-deref is always UB --- .../unaligned_pointers/unaligned_ptr_addr_of.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs new file mode 100644 index 000000000000..cd52cd44c2b2 --- /dev/null +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs @@ -0,0 +1,12 @@ +// This should fail even without validation or Stacked Borrows. +// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows +#![feature(raw_ref_macros)] +use std::ptr; + +fn main() { + let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. + let x = &x[0] as *const _ as *const u32; + // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. + // The deref is UB even if we just put the result into a raw pointer. + let _x = unsafe { ptr::raw_const!(*x) }; //~ ERROR memory with alignment 2, but alignment 4 is required +} From 2e5a0dc172916bef6f8506d5e8b08b8653d98360 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Jun 2020 11:32:01 +0200 Subject: [PATCH 2143/5092] add a miscompilation test --- tests/run-pass/issue-73223.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/run-pass/issue-73223.rs diff --git a/tests/run-pass/issue-73223.rs b/tests/run-pass/issue-73223.rs new file mode 100644 index 000000000000..3a32d970d637 --- /dev/null +++ b/tests/run-pass/issue-73223.rs @@ -0,0 +1,22 @@ +fn main() { + let mut state = State { prev: None, next: Some(8) }; + let path = "/nested/some/more"; + assert_eq!(state.rest(path), "some/more"); +} + +struct State { + prev: Option, + next: Option, +} + +impl State { + fn rest<'r>(&mut self, path: &'r str) -> &'r str { + let start = match self.next.take() { + Some(v) => v, + None => return "", + }; + + self.prev = Some(start); + &path[start..] + } +} From 4788f775f85e1a40aef5893dac5b97e0c7a314ae Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Jun 2020 11:38:34 +0200 Subject: [PATCH 2144/5092] rustup; stop testing with mir opts as they are currently broken --- ci.sh | 7 ++++--- rust-version | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ci.sh b/ci.sh index 785d7aa5520c..0625c2557572 100755 --- a/ci.sh +++ b/ci.sh @@ -23,10 +23,11 @@ function run_tests { fi ./miri test --locked - if ! [ -n "${MIRI_TEST_TARGET+exists}" ]; then + #if ! [ -n "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with MIR optimizations - MIRI_TEST_FLAGS="-Z mir-opt-level=3" ./miri test --locked - fi + # FIXME: disabled because of . + #MIRI_TEST_FLAGS="-Z mir-opt-level=3" ./miri test --locked + #fi # "miri test" has built the sysroot for us, now this should pass without # any interactive questions. ${PYTHON:-python3} test-cargo-miri/run-test.py diff --git a/rust-version b/rust-version index f001577e7f0c..9f71640a53f1 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -033013cab3a861224fd55f494c8be1cb0349eb49 +1a4e2b6f9c75a0e21722c88a0e3b610d6ffc3ae3 From 9d41e4c899e81b25b20ee92a542be4982197b9c8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 25 Jun 2020 11:34:52 +0200 Subject: [PATCH 2145/5092] rustup --- ci.sh | 8 ++++---- rust-version | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ci.sh b/ci.sh index 0625c2557572..ac0d080a4839 100755 --- a/ci.sh +++ b/ci.sh @@ -23,11 +23,11 @@ function run_tests { fi ./miri test --locked - #if ! [ -n "${MIRI_TEST_TARGET+exists}" ]; then + if ! [ -n "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with MIR optimizations - # FIXME: disabled because of . - #MIRI_TEST_FLAGS="-Z mir-opt-level=3" ./miri test --locked - #fi + # FIXME:only testing level 1 because of . + MIRI_TEST_FLAGS="-Z mir-opt-level=1" ./miri test --locked + fi # "miri test" has built the sysroot for us, now this should pass without # any interactive questions. ${PYTHON:-python3} test-cargo-miri/run-test.py diff --git a/rust-version b/rust-version index 9f71640a53f1..8a53046ddfbf 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1a4e2b6f9c75a0e21722c88a0e3b610d6ffc3ae3 +67100f61e62a86f2bf9e38552ee138e231eddc74 From 3ea8c5fa33d9385d1c01c28b0cbc4796611cb52e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 26 Jun 2020 20:36:08 +0200 Subject: [PATCH 2146/5092] bump Rust --- rust-version | 2 +- tests/compile-fail/intrinsics/exact_div2.rs | 2 +- tests/compile-fail/intrinsics/exact_div3.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 8a53046ddfbf..159f752cc0df 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -67100f61e62a86f2bf9e38552ee138e231eddc74 +7750c3d46bc19784adb1ee6e37a5ec7e4cd7e772 diff --git a/tests/compile-fail/intrinsics/exact_div2.rs b/tests/compile-fail/intrinsics/exact_div2.rs index 9b9ae807088d..1327046920d2 100644 --- a/tests/compile-fail/intrinsics/exact_div2.rs +++ b/tests/compile-fail/intrinsics/exact_div2.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // divison with a remainder - unsafe { std::intrinsics::exact_div(2u16, 3); } //~ ERROR 2u16 cannot be divided by 3u16 without remainder + unsafe { std::intrinsics::exact_div(2u16, 3); } //~ ERROR 2_u16 cannot be divided by 3_u16 without remainder } diff --git a/tests/compile-fail/intrinsics/exact_div3.rs b/tests/compile-fail/intrinsics/exact_div3.rs index 1cd112acfc2d..6a309442749b 100644 --- a/tests/compile-fail/intrinsics/exact_div3.rs +++ b/tests/compile-fail/intrinsics/exact_div3.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // signed divison with a remainder - unsafe { std::intrinsics::exact_div(-19i8, 2); } //~ ERROR -19i8 cannot be divided by 2i8 without remainder + unsafe { std::intrinsics::exact_div(-19i8, 2); } //~ ERROR -19_i8 cannot be divided by 2_i8 without remainder } From b46f946c81477e22c14d92ab93609ade18dc86d6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Jun 2020 11:57:43 +0200 Subject: [PATCH 2147/5092] supply our own implementation of the CTFE pointer comparison intrinsics --- src/shims/intrinsics.rs | 37 ++++++++++++++++++++++++++---------- tests/run-pass/intrinsics.rs | 7 ++++++- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index c16fbc278c8d..015d9edc11b7 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -6,6 +6,7 @@ use rustc_middle::{mir, ty}; use rustc_middle::ty::layout::IntegerExt; use rustc_apfloat::{Float, Round}; use rustc_target::abi::{Align, Integer, LayoutOf}; +use rustc_span::symbol::sym; use crate::*; use helpers::check_arg_count; @@ -20,17 +21,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx unwind: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - if this.emulate_intrinsic(instance, args, ret)? { + let intrinsic_name = this.tcx.item_name(instance.def_id()); + // We want to overwrite some of the intrinsic implementations that CTFE uses. + let prefer_miri_intrinsic = match intrinsic_name { + sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => true, + _ => false, + }; + + if !prefer_miri_intrinsic && this.emulate_intrinsic(instance, args, ret)? { return Ok(()); } - let substs = instance.substs; - - // All these intrinsics take raw pointers, so if we access memory directly - // (as opposed to through a place), we have to remember to erase any tag - // that might still hang around! - let intrinsic_name = &*this.tcx.item_name(instance.def_id()).as_str(); // First handle intrinsics without return place. + let intrinsic_name = &*intrinsic_name.as_str(); let (dest, ret) = match ret { None => match intrinsic_name { "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), @@ -42,13 +45,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Then handle terminating intrinsics. match intrinsic_name { + // Miri overwriting CTFE intrinsics. + "ptr_guaranteed_eq" => { + let &[left, right] = check_arg_count(args)?; + let left = this.read_immediate(left)?; + let right = this.read_immediate(right)?; + this.binop_ignore_overflow(mir::BinOp::Eq, left, right, dest)?; + } + "ptr_guaranteed_ne" => { + let &[left, right] = check_arg_count(args)?; + let left = this.read_immediate(left)?; + let right = this.read_immediate(right)?; + this.binop_ignore_overflow(mir::BinOp::Ne, left, right, dest)?; + } + // Raw memory accesses #[rustfmt::skip] | "copy" | "copy_nonoverlapping" => { let &[src, dest, count] = check_arg_count(args)?; - let elem_ty = substs.type_at(0); + let elem_ty = instance.substs.type_at(0); let elem_layout = this.layout_of(elem_ty)?; let count = this.read_scalar(count)?.to_machine_usize(this)?; let elem_align = elem_layout.align.abi; @@ -89,7 +106,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "write_bytes" => { let &[ptr, val_byte, count] = check_arg_count(args)?; - let ty = substs.type_at(0); + let ty = instance.substs.type_at(0); let ty_layout = this.layout_of(ty)?; let val_byte = this.read_scalar(val_byte)?.to_u8()?; let ptr = this.read_scalar(ptr)?.not_undef()?; @@ -455,7 +472,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "assert_zero_valid" | "assert_uninit_valid" => { let &[] = check_arg_count(args)?; - let ty = substs.type_at(0); + let ty = instance.substs.type_at(0); let layout = this.layout_of(ty)?; // Abort here because the caller might not be panic safe. if layout.abi.is_uninhabited() { diff --git a/tests/run-pass/intrinsics.rs b/tests/run-pass/intrinsics.rs index ffa7f080aa4e..8f7dbac67064 100644 --- a/tests/run-pass/intrinsics.rs +++ b/tests/run-pass/intrinsics.rs @@ -1,4 +1,4 @@ -#![feature(core_intrinsics)] +#![feature(core_intrinsics, const_raw_ptr_comparison)] use std::intrinsics; use std::mem::{size_of, size_of_val}; @@ -30,4 +30,9 @@ fn main() { let _v = intrinsics::discriminant_value(&0); let _v = intrinsics::discriminant_value(&true); let _v = intrinsics::discriminant_value(&vec![1,2,3]); + + let addr = &13 as *const i32; + let addr2 = (addr as usize).wrapping_add(usize::MAX).wrapping_add(1); + assert!(addr.guaranteed_eq(addr2 as *const _)); + assert!(addr.guaranteed_ne(0x100 as *const _)); } From 395f5d40dcd50b3e83c3cd0a15f1927c141bf48c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Jun 2020 12:36:20 +0200 Subject: [PATCH 2148/5092] Rename shims::{sync -> posic_sync} and move sync_singlethread test to other sync test --- src/lib.rs | 24 +++++++++---------- src/shims/{sync.rs => posix_sync.rs} | 3 +++ src/thread.rs | 4 ++-- .../{ => concurrency}/sync_singlethread.rs | 0 4 files changed, 17 insertions(+), 14 deletions(-) rename src/shims/{sync.rs => posix_sync.rs} (99%) rename tests/run-pass/{ => concurrency}/sync_singlethread.rs (100%) diff --git a/src/lib.rs b/src/lib.rs index e79fc2add39e..e0da83840edd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,18 +39,18 @@ pub use rustc_mir::interpret::*; // Resolve ambiguity. pub use rustc_mir::interpret::{self, AllocMap, PlaceTy}; -pub use crate::shims::dlsym::{Dlsym, EvalContextExt as DlsymEvalContextExt}; -pub use crate::shims::env::{EnvVars, EvalContextExt as EnvEvalContextExt}; -pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextExt; -pub use crate::shims::fs::{DirHandler, EvalContextExt as FileEvalContextExt, FileHandler}; -pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; -pub use crate::shims::os_str::EvalContextExt as OsStrEvalContextExt; -pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as PanicEvalContextExt}; -pub use crate::shims::sync::{EvalContextExt as SyncShimsEvalContextExt}; -pub use crate::shims::thread::EvalContextExt as ThreadShimsEvalContextExt; -pub use crate::shims::time::EvalContextExt as TimeEvalContextExt; -pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; -pub use crate::shims::EvalContextExt as ShimsEvalContextExt; +pub use crate::shims::dlsym::{Dlsym, EvalContextExt as _}; +pub use crate::shims::env::{EnvVars, EvalContextExt as _}; +pub use crate::shims::foreign_items::EvalContextExt as _; +pub use crate::shims::fs::{DirHandler, EvalContextExt as _, FileHandler}; +pub use crate::shims::intrinsics::EvalContextExt as _; +pub use crate::shims::os_str::EvalContextExt as _; +pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _}; +pub use crate::shims::posix_sync::{EvalContextExt as _}; +pub use crate::shims::thread::EvalContextExt as _; +pub use crate::shims::time::EvalContextExt as _; +pub use crate::shims::tls::{EvalContextExt as _, TlsData}; +pub use crate::shims::EvalContextExt as _; pub use crate::diagnostics::{ register_diagnostic, report_error, EvalContextExt as DiagnosticsEvalContextExt, diff --git a/src/shims/sync.rs b/src/shims/posix_sync.rs similarity index 99% rename from src/shims/sync.rs rename to src/shims/posix_sync.rs index 8986455a14fc..cdc1f8cc763a 100644 --- a/src/shims/sync.rs +++ b/src/shims/posix_sync.rs @@ -522,6 +522,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex_set_kind(this, mutex_op, ScalarMaybeUninit::Uninit)?; mutex_set_id(this, mutex_op, ScalarMaybeUninit::Uninit)?; + // FIXME: delete interpreter state associated with this mutex. Ok(0) } @@ -640,6 +641,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } rwlock_set_id(this, rwlock_op, ScalarMaybeUninit::Uninit)?; + // FIXME: delete interpreter state associated with this rwlock. Ok(0) } @@ -833,6 +835,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } cond_set_id(this, cond_op, ScalarMaybeUninit::Uninit)?; cond_set_clock_id(this, cond_op, ScalarMaybeUninit::Uninit)?; + // FIXME: delete interpreter state associated with this condvar. Ok(0) } diff --git a/src/thread.rs b/src/thread.rs index 246a383d178b..896f93ef1a3a 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -91,8 +91,8 @@ pub enum ThreadState { /// responsibility of the synchronization primitives to track threads that /// are blocked by them. BlockedOnSync, - /// The thread has terminated its execution (we do not delete terminated - /// threads). + /// The thread has terminated its execution. We do not delete terminated + /// threads (FIXME: why?). Terminated, } diff --git a/tests/run-pass/sync_singlethread.rs b/tests/run-pass/concurrency/sync_singlethread.rs similarity index 100% rename from tests/run-pass/sync_singlethread.rs rename to tests/run-pass/concurrency/sync_singlethread.rs From af5887e869c91df9920856e2ba2ee3e85cea6a78 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Jun 2020 13:19:35 +0200 Subject: [PATCH 2149/5092] module organization: move platform-specific code to shims::{posix::{linux, macos}, windows} --- src/intptrcast.rs | 2 +- src/lib.rs | 7 +++---- src/machine.rs | 4 ++-- src/shims/foreign_items.rs | 9 +++------ src/shims/mod.rs | 13 ++++++++----- .../posix.rs => posix/foreign_items.rs} | 15 ++++++++------- src/shims/{ => posix}/fs.rs | 4 ++-- .../linux.rs => posix/linux/foreign_items.rs} | 8 ++++++-- src/shims/posix/linux/mod.rs | 1 + .../macos.rs => posix/macos/foreign_items.rs} | 5 ++++- src/shims/posix/macos/mod.rs | 1 + src/shims/posix/mod.rs | 10 ++++++++++ src/shims/{posix_sync.rs => posix/sync.rs} | 6 +++--- src/shims/{ => posix}/thread.rs | 0 src/shims/tls.rs | 5 +---- .../windows.rs => windows/foreign_items.rs} | 0 src/shims/windows/mod.rs | 1 + 17 files changed, 54 insertions(+), 37 deletions(-) rename src/shims/{foreign_items/posix.rs => posix/foreign_items.rs} (98%) rename src/shims/{ => posix}/fs.rs (99%) rename src/shims/{foreign_items/posix/linux.rs => posix/linux/foreign_items.rs} (97%) create mode 100644 src/shims/posix/linux/mod.rs rename src/shims/{foreign_items/posix/macos.rs => posix/macos/foreign_items.rs} (98%) create mode 100644 src/shims/posix/macos/mod.rs create mode 100644 src/shims/posix/mod.rs rename src/shims/{posix_sync.rs => posix/sync.rs} (99%) rename src/shims/{ => posix}/thread.rs (100%) rename src/shims/{foreign_items/windows.rs => windows/foreign_items.rs} (100%) create mode 100644 src/shims/windows/mod.rs diff --git a/src/intptrcast.rs b/src/intptrcast.rs index f51c8a7ce743..c908bdf24eba 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -9,7 +9,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_mir::interpret::{AllocCheck, AllocId, InterpResult, Memory, Machine, Pointer, PointerArithmetic}; use rustc_target::abi::{Size, HasDataLayout}; -use crate::{Evaluator, Tag, STACK_ADDR, CheckInAllocMsg}; +use crate::*; pub type MemoryExtra = RefCell; diff --git a/src/lib.rs b/src/lib.rs index e0da83840edd..fa357eb9b134 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,6 +34,8 @@ mod stacked_borrows; mod sync; mod thread; +// Establish a "crate-wide prelude": we often import `crate::*`. + // Make all those symbols available in the same place as our own. pub use rustc_mir::interpret::*; // Resolve ambiguity. @@ -42,13 +44,10 @@ pub use rustc_mir::interpret::{self, AllocMap, PlaceTy}; pub use crate::shims::dlsym::{Dlsym, EvalContextExt as _}; pub use crate::shims::env::{EnvVars, EvalContextExt as _}; pub use crate::shims::foreign_items::EvalContextExt as _; -pub use crate::shims::fs::{DirHandler, EvalContextExt as _, FileHandler}; pub use crate::shims::intrinsics::EvalContextExt as _; pub use crate::shims::os_str::EvalContextExt as _; -pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _}; -pub use crate::shims::posix_sync::{EvalContextExt as _}; -pub use crate::shims::thread::EvalContextExt as _; pub use crate::shims::time::EvalContextExt as _; +pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _}; pub use crate::shims::tls::{EvalContextExt as _, TlsData}; pub use crate::shims::EvalContextExt as _; diff --git a/src/machine.rs b/src/machine.rs index 4f45b4f93f18..6233222c004d 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -241,8 +241,8 @@ pub struct Evaluator<'mir, 'tcx> { /// Whether to enforce the validity invariant. pub(crate) validate: bool, - pub(crate) file_handler: FileHandler, - pub(crate) dir_handler: DirHandler, + pub(crate) file_handler: shims::posix::FileHandler, + pub(crate) dir_handler: shims::posix::DirHandler, /// The temporary used for storing the argument of /// the call to `miri_start_panic` (the panic payload) when unwinding. diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 8a75fb03a53c..14c5aac4899a 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -1,6 +1,3 @@ -mod windows; -mod posix; - use std::{convert::{TryInto, TryFrom}, iter}; use rustc_hir::def_id::DefId; @@ -455,13 +452,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Architecture-specific shims "llvm.x86.sse2.pause" if this.tcx.sess.target.target.arch == "x86" || this.tcx.sess.target.target.arch == "x86_64" => { let &[] = check_arg_count(args)?; - this.sched_yield()?; + this.yield_active_thread(); } // Platform-specific shims _ => match this.tcx.sess.target.target.target_os.as_str() { - "linux" | "macos" => return posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), - "windows" => return windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), + "linux" | "macos" => return shims::posix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), + "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), target => throw_unsup_format!("the target `{}` is not supported", target), } }; diff --git a/src/shims/mod.rs b/src/shims/mod.rs index cd525e173ed7..37e7b8c40462 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -1,15 +1,18 @@ + +pub mod foreign_items; +pub mod intrinsics; +pub mod posix; +pub mod windows; + pub mod dlsym; pub mod env; -pub mod foreign_items; -pub mod fs; -pub mod intrinsics; pub mod os_str; pub mod panic; -pub mod sync; -pub mod thread; pub mod time; pub mod tls; +// End module management, begin local code + use std::convert::TryFrom; use log::trace; diff --git a/src/shims/foreign_items/posix.rs b/src/shims/posix/foreign_items.rs similarity index 98% rename from src/shims/foreign_items/posix.rs rename to src/shims/posix/foreign_items.rs index 8e4d140b06cb..bbda40def620 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/posix/foreign_items.rs @@ -1,15 +1,16 @@ -mod linux; -mod macos; - use std::convert::TryFrom; use log::trace; -use crate::*; -use helpers::check_arg_count; use rustc_middle::mir; use rustc_target::abi::{Align, LayoutOf, Size}; +use crate::*; +use helpers::check_arg_count; +use shims::posix::fs::EvalContextExt as _; +use shims::posix::sync::EvalContextExt as _; +use shims::posix::thread::EvalContextExt as _; + impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn emulate_foreign_item_by_name( @@ -476,8 +477,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Platform-specific shims _ => { match this.tcx.sess.target.target.target_os.as_str() { - "linux" => return linux::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), - "macos" => return macos::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), + "linux" => return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), + "macos" => return shims::posix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), _ => unreachable!(), } } diff --git a/src/shims/fs.rs b/src/shims/posix/fs.rs similarity index 99% rename from src/shims/fs.rs rename to src/shims/posix/fs.rs index 29e0da14ff1e..87aa28120c28 100644 --- a/src/shims/fs.rs +++ b/src/shims/posix/fs.rs @@ -10,13 +10,13 @@ use log::trace; use rustc_data_structures::fx::FxHashMap; use rustc_target::abi::{Align, LayoutOf, Size}; -use crate::stacked_borrows::Tag; use crate::*; +use stacked_borrows::Tag; use helpers::{check_arg_count, immty_from_int_checked, immty_from_uint_checked}; use shims::time::system_time_to_duration; #[derive(Debug)] -pub struct FileHandle { +struct FileHandle { file: File, writable: bool, } diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/posix/linux/foreign_items.rs similarity index 97% rename from src/shims/foreign_items/posix/linux.rs rename to src/shims/posix/linux/foreign_items.rs index 2d124f9d8c6c..ff30609d9ab2 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -1,7 +1,11 @@ -use crate::*; -use helpers::check_arg_count; use rustc_middle::mir; +use crate::*; +use crate::helpers::check_arg_count; +use shims::posix::fs::EvalContextExt as _; +use shims::posix::sync::EvalContextExt as _; +use shims::posix::thread::EvalContextExt as _; + impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn emulate_foreign_item_by_name( diff --git a/src/shims/posix/linux/mod.rs b/src/shims/posix/linux/mod.rs new file mode 100644 index 000000000000..09c6507b24f8 --- /dev/null +++ b/src/shims/posix/linux/mod.rs @@ -0,0 +1 @@ +pub mod foreign_items; diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/posix/macos/foreign_items.rs similarity index 98% rename from src/shims/foreign_items/posix/macos.rs rename to src/shims/posix/macos/foreign_items.rs index fb50e4d91817..ef649c3e8406 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -1,6 +1,9 @@ +use rustc_middle::mir; + use crate::*; use helpers::check_arg_count; -use rustc_middle::mir; +use shims::posix::fs::EvalContextExt as _; +use shims::posix::thread::EvalContextExt as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { diff --git a/src/shims/posix/macos/mod.rs b/src/shims/posix/macos/mod.rs new file mode 100644 index 000000000000..09c6507b24f8 --- /dev/null +++ b/src/shims/posix/macos/mod.rs @@ -0,0 +1 @@ +pub mod foreign_items; diff --git a/src/shims/posix/mod.rs b/src/shims/posix/mod.rs new file mode 100644 index 000000000000..2f505cfb9c0b --- /dev/null +++ b/src/shims/posix/mod.rs @@ -0,0 +1,10 @@ +pub mod foreign_items; + +mod fs; +mod sync; +mod thread; + +mod linux; +mod macos; + +pub use fs::{DirHandler, FileHandler}; diff --git a/src/shims/posix_sync.rs b/src/shims/posix/sync.rs similarity index 99% rename from src/shims/posix_sync.rs rename to src/shims/posix/sync.rs index cdc1f8cc763a..a61c80d5118c 100644 --- a/src/shims/posix_sync.rs +++ b/src/shims/posix/sync.rs @@ -5,10 +5,10 @@ use std::ops::Not; use rustc_middle::ty::{layout::TyAndLayout, TyKind, TypeAndMut}; use rustc_target::abi::{LayoutOf, Size}; -use crate::stacked_borrows::Tag; -use crate::thread::Time; - use crate::*; +use stacked_borrows::Tag; +use thread::Time; + fn assert_ptr_target_min_size<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, diff --git a/src/shims/thread.rs b/src/shims/posix/thread.rs similarity index 100% rename from src/shims/thread.rs rename to src/shims/posix/thread.rs diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 695614633682..704598ef2c6c 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -10,10 +10,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty; use rustc_target::abi::{Size, HasDataLayout}; -use crate::{ - HelpersEvalContextExt, InterpResult, MPlaceTy, Scalar, StackPopCleanup, Tag, ThreadId, - ThreadsEvalContextExt, -}; +use crate::*; pub type TlsKey = u128; diff --git a/src/shims/foreign_items/windows.rs b/src/shims/windows/foreign_items.rs similarity index 100% rename from src/shims/foreign_items/windows.rs rename to src/shims/windows/foreign_items.rs diff --git a/src/shims/windows/mod.rs b/src/shims/windows/mod.rs new file mode 100644 index 000000000000..09c6507b24f8 --- /dev/null +++ b/src/shims/windows/mod.rs @@ -0,0 +1 @@ +pub mod foreign_items; From dca00ab85ec970432ebaf1cf59b0e795db2d65cd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Jun 2020 13:50:52 +0200 Subject: [PATCH 2150/5092] introduce platform-specific module hierarchy for dlsym (similar to foreign_items) --- src/shims/dlsym.rs | 43 ++++----------- src/shims/posix/dlsym.rs | 39 +++++++++++++ src/shims/posix/linux/dlsym.rs | 34 ++++++++++++ src/shims/posix/linux/mod.rs | 1 + src/shims/posix/macos/dlsym.rs | 49 +++++++++++++++++ src/shims/posix/macos/mod.rs | 1 + src/shims/posix/mod.rs | 1 + src/shims/windows/dlsym.rs | 55 +++++++++++++++++++ src/shims/windows/mod.rs | 3 + src/shims/windows/sync.rs | 0 .../run-pass/concurrency/sync_singlethread.rs | 6 +- 11 files changed, 194 insertions(+), 38 deletions(-) create mode 100644 src/shims/posix/dlsym.rs create mode 100644 src/shims/posix/linux/dlsym.rs create mode 100644 src/shims/posix/macos/dlsym.rs create mode 100644 src/shims/windows/dlsym.rs create mode 100644 src/shims/windows/sync.rs diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 87c7f447ac03..9b15cb9ac9a3 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -1,34 +1,24 @@ use rustc_middle::mir; use crate::*; -use helpers::check_arg_count; +use shims::posix::dlsym as posix; +use shims::windows::dlsym as windows; #[derive(Debug, Copy, Clone)] +#[allow(non_camel_case_types)] pub enum Dlsym { - GetEntropy, + Posix(posix::Dlsym), + Windows(windows::Dlsym), } impl Dlsym { // Returns an error for unsupported symbols, and None if this symbol // should become a NULL pointer (pretend it does not exist). pub fn from_str(name: &[u8], target_os: &str) -> InterpResult<'static, Option> { - use self::Dlsym::*; - let name = String::from_utf8_lossy(name); + let name = &*String::from_utf8_lossy(name); Ok(match target_os { - "linux" => match &*name { - "__pthread_get_minstack" => None, - _ => throw_unsup_format!("unsupported Linux dlsym: {}", name), - } - "macos" => match &*name { - "getentropy" => Some(GetEntropy), - _ => throw_unsup_format!("unsupported macOS dlsym: {}", name), - } - "windows" => match &*name { - "SetThreadStackGuarantee" => None, - "AcquireSRWLockExclusive" => None, - "GetSystemTimePreciseAsFileTime" => None, - _ => throw_unsup_format!("unsupported Windows dlsym: {}", name), - } + "linux" | "macos" => posix::Dlsym::from_str(name, target_os)?.map(Dlsym::Posix), + "windows" => windows::Dlsym::from_str(name)?.map(Dlsym::Windows), os => bug!("dlsym not implemented for target_os {}", os), }) } @@ -42,23 +32,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, ) -> InterpResult<'tcx> { - use self::Dlsym::*; - let this = self.eval_context_mut(); - let (dest, ret) = ret.expect("we don't support any diverging dlsym"); - match dlsym { - GetEntropy => { - let &[ptr, len] = check_arg_count(args)?; - let ptr = this.read_scalar(ptr)?.not_undef()?; - let len = this.read_scalar(len)?.to_machine_usize(this)?; - this.gen_random(ptr, len)?; - this.write_null(dest)?; - } + Dlsym::Posix(dlsym) => posix::EvalContextExt::call_dlsym(this, dlsym, args, ret), + Dlsym::Windows(dlsym) => windows::EvalContextExt::call_dlsym(this, dlsym, args, ret), } - - this.dump_place(*dest); - this.go_to_block(ret); - Ok(()) } } diff --git a/src/shims/posix/dlsym.rs b/src/shims/posix/dlsym.rs new file mode 100644 index 000000000000..52d9844bed51 --- /dev/null +++ b/src/shims/posix/dlsym.rs @@ -0,0 +1,39 @@ +use rustc_middle::mir; + +use crate::*; +use shims::posix::linux::dlsym as linux; +use shims::posix::macos::dlsym as macos; + +#[derive(Debug, Copy, Clone)] +pub enum Dlsym { + Linux(linux::Dlsym), + MacOs(macos::Dlsym), +} + +impl Dlsym { + // Returns an error for unsupported symbols, and None if this symbol + // should become a NULL pointer (pretend it does not exist). + pub fn from_str(name: &str, target_os: &str) -> InterpResult<'static, Option> { + Ok(match target_os { + "linux" => linux::Dlsym::from_str(name)?.map(Dlsym::Linux), + "macos" => macos::Dlsym::from_str(name)?.map(Dlsym::MacOs), + _ => unreachable!(), + }) + } +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn call_dlsym( + &mut self, + dlsym: Dlsym, + args: &[OpTy<'tcx, Tag>], + ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + match dlsym { + Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, ret), + Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, args, ret), + } + } +} diff --git a/src/shims/posix/linux/dlsym.rs b/src/shims/posix/linux/dlsym.rs new file mode 100644 index 000000000000..9be300edf495 --- /dev/null +++ b/src/shims/posix/linux/dlsym.rs @@ -0,0 +1,34 @@ +use rustc_middle::mir; + +use crate::*; + +#[derive(Debug, Copy, Clone)] +pub enum Dlsym { +} + +impl Dlsym { + // Returns an error for unsupported symbols, and None if this symbol + // should become a NULL pointer (pretend it does not exist). + pub fn from_str(name: &str) -> InterpResult<'static, Option> { + Ok(match &*name { + "__pthread_get_minstack" => None, + _ => throw_unsup_format!("unsupported Linux dlsym: {}", name), + }) + } +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn call_dlsym( + &mut self, + dlsym: Dlsym, + _args: &[OpTy<'tcx, Tag>], + ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let (_dest, _ret) = ret.expect("we don't support any diverging dlsym"); + assert!(this.tcx.sess.target.target.target_os == "linux"); + + match dlsym {} + } +} diff --git a/src/shims/posix/linux/mod.rs b/src/shims/posix/linux/mod.rs index 09c6507b24f8..cadd6a8ea384 100644 --- a/src/shims/posix/linux/mod.rs +++ b/src/shims/posix/linux/mod.rs @@ -1 +1,2 @@ pub mod foreign_items; +pub mod dlsym; diff --git a/src/shims/posix/macos/dlsym.rs b/src/shims/posix/macos/dlsym.rs new file mode 100644 index 000000000000..8256c10b0d39 --- /dev/null +++ b/src/shims/posix/macos/dlsym.rs @@ -0,0 +1,49 @@ +use rustc_middle::mir; + +use crate::*; +use helpers::check_arg_count; + +#[derive(Debug, Copy, Clone)] +#[allow(non_camel_case_types)] +pub enum Dlsym { + getentropy, +} + +impl Dlsym { + // Returns an error for unsupported symbols, and None if this symbol + // should become a NULL pointer (pretend it does not exist). + pub fn from_str(name: &str) -> InterpResult<'static, Option> { + Ok(match name { + "getentropy" => Some(Dlsym::getentropy), + _ => throw_unsup_format!("unsupported macOS dlsym: {}", name), + }) + } +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn call_dlsym( + &mut self, + dlsym: Dlsym, + args: &[OpTy<'tcx, Tag>], + ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let (dest, ret) = ret.expect("we don't support any diverging dlsym"); + assert!(this.tcx.sess.target.target.target_os == "macos"); + + match dlsym { + Dlsym::getentropy => { + let &[ptr, len] = check_arg_count(args)?; + let ptr = this.read_scalar(ptr)?.not_undef()?; + let len = this.read_scalar(len)?.to_machine_usize(this)?; + this.gen_random(ptr, len)?; + this.write_null(dest)?; + } + } + + this.dump_place(*dest); + this.go_to_block(ret); + Ok(()) + } +} diff --git a/src/shims/posix/macos/mod.rs b/src/shims/posix/macos/mod.rs index 09c6507b24f8..cadd6a8ea384 100644 --- a/src/shims/posix/macos/mod.rs +++ b/src/shims/posix/macos/mod.rs @@ -1 +1,2 @@ pub mod foreign_items; +pub mod dlsym; diff --git a/src/shims/posix/mod.rs b/src/shims/posix/mod.rs index 2f505cfb9c0b..9916c65be0fb 100644 --- a/src/shims/posix/mod.rs +++ b/src/shims/posix/mod.rs @@ -1,4 +1,5 @@ pub mod foreign_items; +pub mod dlsym; mod fs; mod sync; diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs new file mode 100644 index 000000000000..34ed6ca150e0 --- /dev/null +++ b/src/shims/windows/dlsym.rs @@ -0,0 +1,55 @@ +use rustc_middle::mir; + +use crate::*; +use helpers::check_arg_count; + +#[derive(Debug, Copy, Clone)] +pub enum Dlsym { + AcquireSRWLockExclusive, + AcquireSRWLockShared, +} + +impl Dlsym { + // Returns an error for unsupported symbols, and None if this symbol + // should become a NULL pointer (pretend it does not exist). + pub fn from_str(name: &str) -> InterpResult<'static, Option> { + Ok(match name { + "AcquireSRWLockExclusive" => Some(Dlsym::AcquireSRWLockExclusive), + "AcquireSRWLockShared" => Some(Dlsym::AcquireSRWLockShared), + "SetThreadStackGuarantee" => None, + "GetSystemTimePreciseAsFileTime" => None, + _ => throw_unsup_format!("unsupported Windows dlsym: {}", name), + }) + } +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn call_dlsym( + &mut self, + dlsym: Dlsym, + args: &[OpTy<'tcx, Tag>], + ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let (dest, ret) = ret.expect("we don't support any diverging dlsym"); + assert!(this.tcx.sess.target.target.target_os == "windows"); + + match dlsym { + Dlsym::AcquireSRWLockExclusive => { + let &[ptr] = check_arg_count(args)?; + let lock = this.deref_operand(ptr)?; // points to ptr-sized data + throw_unsup_format!("AcquireSRWLockExclusive is not actually implemented"); + } + Dlsym::AcquireSRWLockShared => { + let &[ptr] = check_arg_count(args)?; + let lock = this.deref_operand(ptr)?; // points to ptr-sized data + throw_unsup_format!("AcquireSRWLockExclusive is not actually implemented"); + } + } + + this.dump_place(*dest); + this.go_to_block(ret); + Ok(()) + } +} diff --git a/src/shims/windows/mod.rs b/src/shims/windows/mod.rs index 09c6507b24f8..04f9ace8e799 100644 --- a/src/shims/windows/mod.rs +++ b/src/shims/windows/mod.rs @@ -1 +1,4 @@ pub mod foreign_items; +pub mod dlsym; + +mod sync; diff --git a/src/shims/windows/sync.rs b/src/shims/windows/sync.rs new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/run-pass/concurrency/sync_singlethread.rs b/tests/run-pass/concurrency/sync_singlethread.rs index 8b8594d4df69..749db855e296 100644 --- a/tests/run-pass/concurrency/sync_singlethread.rs +++ b/tests/run-pass/concurrency/sync_singlethread.rs @@ -6,10 +6,7 @@ use std::hint; fn main() { test_mutex_stdlib(); - #[cfg(not(target_os = "windows"))] // TODO: implement RwLock on Windows - { - test_rwlock_stdlib(); - } + test_rwlock_stdlib(); test_spin_loop_hint(); test_thread_yield_now(); } @@ -24,7 +21,6 @@ fn test_mutex_stdlib() { drop(m); } -#[cfg(not(target_os = "windows"))] fn test_rwlock_stdlib() { use std::sync::RwLock; let rw = RwLock::new(0); From 8e9296994837c82c39b2c4cee7623d9181e4bc80 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Jun 2020 14:35:58 +0200 Subject: [PATCH 2151/5092] implement Windows SRWLock shims --- src/shims/tls.rs | 2 +- src/shims/windows/dlsym.rs | 33 +++++- src/shims/windows/foreign_items.rs | 3 +- src/shims/windows/sync.rs | 161 +++++++++++++++++++++++++++++ 4 files changed, 193 insertions(+), 6 deletions(-) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 704598ef2c6c..0cd9ef056505 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -230,7 +230,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn schedule_windows_tls_dtors(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let active_thread = this.get_active_thread(); - assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows not supported"); + assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); // Windows has a special magic linker section that is run on certain events. // Instead of searching for that section and supporting arbitrary hooks in there // (that would be basically https://github.com/rust-lang/miri/issues/450), diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 34ed6ca150e0..737fd4314f63 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -2,11 +2,16 @@ use rustc_middle::mir; use crate::*; use helpers::check_arg_count; +use shims::windows::sync::EvalContextExt as _; #[derive(Debug, Copy, Clone)] pub enum Dlsym { AcquireSRWLockExclusive, + ReleaseSRWLockExclusive, + TryAcquireSRWLockExclusive, AcquireSRWLockShared, + ReleaseSRWLockShared, + TryAcquireSRWLockShared, } impl Dlsym { @@ -15,7 +20,11 @@ impl Dlsym { pub fn from_str(name: &str) -> InterpResult<'static, Option> { Ok(match name { "AcquireSRWLockExclusive" => Some(Dlsym::AcquireSRWLockExclusive), + "ReleaseSRWLockExclusive" => Some(Dlsym::ReleaseSRWLockExclusive), + "TryAcquireSRWLockExclusive" => Some(Dlsym::TryAcquireSRWLockExclusive), "AcquireSRWLockShared" => Some(Dlsym::AcquireSRWLockShared), + "ReleaseSRWLockShared" => Some(Dlsym::ReleaseSRWLockShared), + "TryAcquireSRWLockShared" => Some(Dlsym::TryAcquireSRWLockShared), "SetThreadStackGuarantee" => None, "GetSystemTimePreciseAsFileTime" => None, _ => throw_unsup_format!("unsupported Windows dlsym: {}", name), @@ -38,13 +47,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match dlsym { Dlsym::AcquireSRWLockExclusive => { let &[ptr] = check_arg_count(args)?; - let lock = this.deref_operand(ptr)?; // points to ptr-sized data - throw_unsup_format!("AcquireSRWLockExclusive is not actually implemented"); + this.AcquireSRWLockExclusive(ptr)?; + } + Dlsym::ReleaseSRWLockExclusive => { + let &[ptr] = check_arg_count(args)?; + this.ReleaseSRWLockExclusive(ptr)?; + } + Dlsym::TryAcquireSRWLockExclusive => { + let &[ptr] = check_arg_count(args)?; + let ret = this.TryAcquireSRWLockExclusive(ptr)?; + this.write_scalar(Scalar::from_u8(ret), dest)?; } Dlsym::AcquireSRWLockShared => { let &[ptr] = check_arg_count(args)?; - let lock = this.deref_operand(ptr)?; // points to ptr-sized data - throw_unsup_format!("AcquireSRWLockExclusive is not actually implemented"); + this.AcquireSRWLockShared(ptr)?; + } + Dlsym::ReleaseSRWLockShared => { + let &[ptr] = check_arg_count(args)?; + this.ReleaseSRWLockShared(ptr)?; + } + Dlsym::TryAcquireSRWLockShared => { + let &[ptr] = check_arg_count(args)?; + let ret = this.TryAcquireSRWLockShared(ptr)?; + this.write_scalar(Scalar::from_u8(ret), dest)?; } } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 2a30a2348997..ddb70b752e79 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -21,6 +21,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // HANDLE = isize // DWORD = ULONG = u32 // BOOL = i32 + // BOOLEAN = u8 match link_name { // Environment related shims "GetEnvironmentVariableW" => { @@ -301,7 +302,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] let &[_lpCriticalSection] = check_arg_count(args)?; assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows not supported"); - // There is only one thread, so this always succeeds and returns TRUE + // There is only one thread, so this always succeeds and returns TRUE. this.write_scalar(Scalar::from_i32(1), dest)?; } diff --git a/src/shims/windows/sync.rs b/src/shims/windows/sync.rs index e69de29bb2d1..ef40eb089110 100644 --- a/src/shims/windows/sync.rs +++ b/src/shims/windows/sync.rs @@ -0,0 +1,161 @@ +use rustc_target::abi::Size; + +use crate::*; + +// Locks are pointer-sized pieces of data, initialized to 0. +// We use them to count readers, with usize::MAX representing the write-locked state. + +fn deref_lock<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + lock_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, MPlaceTy<'tcx, Tag>> { + // `lock` is a pointer to `void*`; cast it to a pointer to `usize`. + let lock = ecx.deref_operand(lock_op)?; + let usize = ecx.machine.layouts.usize; + assert_eq!(lock.layout.size, usize.size); + Ok(lock.offset(Size::ZERO, MemPlaceMeta::None, usize, ecx)?) +} + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + #[allow(non_snake_case)] + fn AcquireSRWLockExclusive( + &mut self, + lock_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); + + let lock = deref_lock(this, lock_op)?; + let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?; + if lock_val == 0 { + // Currently not locked. Lock it. + let new_val = Scalar::from_machine_usize(this.machine_usize_max(), this); + this.write_scalar(new_val, lock.into())?; + } else { + // Lock is already held. This is a deadlock. + throw_machine_stop!(TerminationInfo::Deadlock); + } + + Ok(()) + } + + #[allow(non_snake_case)] + fn TryAcquireSRWLockExclusive( + &mut self, + lock_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, u8> { + let this = self.eval_context_mut(); + assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); + + let lock = deref_lock(this, lock_op)?; + let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?; + if lock_val == 0 { + // Currently not locked. Lock it. + let new_val = this.machine_usize_max(); + this.write_scalar(Scalar::from_machine_usize(new_val, this), lock.into())?; + Ok(1) + } else { + // Lock is already held. + Ok(0) + } + } + + #[allow(non_snake_case)] + fn ReleaseSRWLockExclusive( + &mut self, + lock_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); + + let lock = deref_lock(this, lock_op)?; + let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?; + if lock_val == this.machine_usize_max() { + // Currently locked. Unlock it. + let new_val = 0; + this.write_scalar(Scalar::from_machine_usize(new_val, this), lock.into())?; + } else { + // Lock is not locked. + throw_ub_format!("calling ReleaseSRWLockExclusive on an SRWLock that is not exclusively locked"); + } + + Ok(()) + } + + #[allow(non_snake_case)] + fn AcquireSRWLockShared( + &mut self, + lock_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); + + let lock = deref_lock(this, lock_op)?; + let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?; + if lock_val == this.machine_usize_max() { + // Currently write locked. This is a deadlock. + throw_machine_stop!(TerminationInfo::Deadlock); + } else { + // Bump up read counter (cannot overflow as we just checkd against usize::MAX); + let new_val = lock_val+1; + // Make sure this does not reach the "write locked" flag. + if new_val == this.machine_usize_max() { + throw_unsup_format!("SRWLock read-acquired too many times"); + } + this.write_scalar(Scalar::from_machine_usize(new_val, this), lock.into())?; + } + + Ok(()) + } + + #[allow(non_snake_case)] + fn TryAcquireSRWLockShared( + &mut self, + lock_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, u8> { + let this = self.eval_context_mut(); + assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); + + let lock = deref_lock(this, lock_op)?; + let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?; + if lock_val == this.machine_usize_max() { + // Currently write locked. + Ok(0) + } else { + // Bump up read counter (cannot overflow as we just checkd against usize::MAX); + let new_val = lock_val+1; + // Make sure this does not reach the "write locked" flag. + if new_val == this.machine_usize_max() { + throw_unsup_format!("SRWLock read-acquired too many times"); + } + this.write_scalar(Scalar::from_machine_usize(new_val, this), lock.into())?; + Ok(1) + } + } + + #[allow(non_snake_case)] + fn ReleaseSRWLockShared( + &mut self, + lock_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); + + let lock = deref_lock(this, lock_op)?; + let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?; + if lock_val == this.machine_usize_max() { + // Currently write locked. This is a UB. + throw_ub_format!("calling ReleaseSRWLockShared on write-locked SRWLock"); + } else if lock_val == 0 { + // Currently not locked at all. + throw_ub_format!("calling ReleaseSRWLockShared on unlocked SRWLock"); + } else { + // Decrement read counter (cannot overflow as we just checkd against 0); + let new_val = lock_val-1; + this.write_scalar(Scalar::from_machine_usize(new_val, this), lock.into())?; + } + + Ok(()) + } +} From e54619b5e18ce9781faed975f5101db621608ea0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Jun 2020 14:43:37 +0200 Subject: [PATCH 2152/5092] with this, we support panics on Windows --- src/shims/foreign_items.rs | 1 - src/shims/mod.rs | 8 -------- src/shims/panic.rs | 8 -------- tests/compile-fail/abort-terminator.rs | 1 - tests/compile-fail/panic/double_panic.rs | 1 - tests/compile-fail/panic/windows1.rs | 9 --------- tests/compile-fail/panic/windows2.rs | 9 --------- tests/compile-fail/panic/windows3.rs | 10 ---------- tests/run-pass/panic/catch_panic.rs | 2 +- tests/run-pass/panic/div-by-zero-2.rs | 1 - tests/run-pass/panic/div-by-zero-2.stderr | 2 +- tests/run-pass/panic/overflowing-lsh-neg.rs | 1 - tests/run-pass/panic/overflowing-lsh-neg.stderr | 2 +- tests/run-pass/panic/overflowing-rsh-1.rs | 1 - tests/run-pass/panic/overflowing-rsh-1.stderr | 2 +- tests/run-pass/panic/overflowing-rsh-2.rs | 1 - tests/run-pass/panic/overflowing-rsh-2.stderr | 2 +- tests/run-pass/panic/panic1.rs | 1 - tests/run-pass/panic/panic1.stderr | 2 +- tests/run-pass/panic/panic2.rs | 1 - tests/run-pass/panic/panic2.stderr | 2 +- tests/run-pass/panic/panic3.rs | 1 - tests/run-pass/panic/panic3.stderr | 2 +- tests/run-pass/panic/panic4.rs | 1 - tests/run-pass/panic/panic4.stderr | 2 +- tests/run-pass/panic/std-panic-locations.rs | 1 - tests/run-pass/transmute_fat2.rs | 1 - tests/run-pass/transmute_fat2.stderr | 2 +- 28 files changed, 10 insertions(+), 67 deletions(-) delete mode 100644 tests/compile-fail/panic/windows1.rs delete mode 100644 tests/compile-fail/panic/windows2.rs delete mode 100644 tests/compile-fail/panic/windows3.rs diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 14c5aac4899a..a7495beef72e 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -129,7 +129,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This matches calls to the foreign item `panic_impl`. // The implementation is provided by the function with the `#[panic_handler]` attribute. "panic_impl" => { - this.check_panic_supported()?; let panic_impl_id = tcx.lang_items().panic_impl().unwrap(); let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id); return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 37e7b8c40462..56754a9ebde5 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -52,14 +52,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return this.emulate_foreign_item(instance.def_id(), args, ret, unwind); } - // Better error message for panics on Windows. - let def_id = instance.def_id(); - if Some(def_id) == this.tcx.lang_items().begin_panic_fn() || - Some(def_id) == this.tcx.lang_items().panic_impl() - { - this.check_panic_supported()?; - } - // Otherwise, load the MIR. Ok(Some(&*this.load_mir(instance.def, None)?)) } diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 43f90f1b04f7..8e291c201215 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -34,14 +34,6 @@ pub struct CatchUnwindData<'tcx> { impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// Check if panicking is supported on this target, and give a good error otherwise. - fn check_panic_supported(&self) -> InterpResult<'tcx> { - match self.eval_context_ref().tcx.sess.target.target.target_os.as_str() { - "linux" | "macos" => Ok(()), - _ => throw_unsup_format!("panicking is not supported on this target"), - } - } - /// Handles the special `miri_start_panic` intrinsic, which is called /// by libpanic_unwind to delegate the actual unwinding process to Miri. fn handle_miri_start_panic( diff --git a/tests/compile-fail/abort-terminator.rs b/tests/compile-fail/abort-terminator.rs index af1a155435fb..1bfa289a52b4 100644 --- a/tests/compile-fail/abort-terminator.rs +++ b/tests/compile-fail/abort-terminator.rs @@ -1,5 +1,4 @@ // error-pattern: the evaluated program aborted -// ignore-windows (panics dont work on Windows) #![feature(unwind_attributes)] #[unwind(aborts)] diff --git a/tests/compile-fail/panic/double_panic.rs b/tests/compile-fail/panic/double_panic.rs index 3085d0b00657..80d74f026232 100644 --- a/tests/compile-fail/panic/double_panic.rs +++ b/tests/compile-fail/panic/double_panic.rs @@ -1,5 +1,4 @@ // error-pattern: the evaluated program aborted -// ignore-windows (panics dont work on Windows) struct Foo; impl Drop for Foo { diff --git a/tests/compile-fail/panic/windows1.rs b/tests/compile-fail/panic/windows1.rs deleted file mode 100644 index 142ba85c42c7..000000000000 --- a/tests/compile-fail/panic/windows1.rs +++ /dev/null @@ -1,9 +0,0 @@ -// ignore-linux -// ignore-macos - -// Test that panics on Windows give a reasonable error message. - -// error-pattern: panicking is not supported on this target -fn main() { - core::panic!("this is {}", "Windows"); -} diff --git a/tests/compile-fail/panic/windows2.rs b/tests/compile-fail/panic/windows2.rs deleted file mode 100644 index da2cfb59362e..000000000000 --- a/tests/compile-fail/panic/windows2.rs +++ /dev/null @@ -1,9 +0,0 @@ -// ignore-linux -// ignore-macos - -// Test that panics on Windows give a reasonable error message. - -// error-pattern: panicking is not supported on this target -fn main() { - std::panic!("this is Windows"); -} diff --git a/tests/compile-fail/panic/windows3.rs b/tests/compile-fail/panic/windows3.rs deleted file mode 100644 index a2e7bf5a7d43..000000000000 --- a/tests/compile-fail/panic/windows3.rs +++ /dev/null @@ -1,10 +0,0 @@ -// ignore-linux -// ignore-macos - -// Test that panics on Windows give a reasonable error message. - -// error-pattern: panicking is not supported on this target -#[allow(unconditional_panic)] -fn main() { - let _val = 1/0; -} diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index 288ae1965a69..ac41de586e8a 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -1,7 +1,7 @@ -// ignore-windows: Unwind panicking does not currently work on Windows // normalize-stderr-test "[^ ]*libcore/[a-z/]+.rs[0-9:]*" -> "$$LOC" #![feature(never_type)] #![allow(unconditional_panic)] + use std::panic::{catch_unwind, AssertUnwindSafe}; use std::cell::Cell; diff --git a/tests/run-pass/panic/div-by-zero-2.rs b/tests/run-pass/panic/div-by-zero-2.rs index cfacc9db0d66..fac5415696fc 100644 --- a/tests/run-pass/panic/div-by-zero-2.rs +++ b/tests/run-pass/panic/div-by-zero-2.rs @@ -1,4 +1,3 @@ -// ignore-windows: Unwind panicking does not currently work on Windows #![allow(unconditional_panic)] fn main() { diff --git a/tests/run-pass/panic/div-by-zero-2.stderr b/tests/run-pass/panic/div-by-zero-2.stderr index 77dca2aac1e2..d255811be2a9 100644 --- a/tests/run-pass/panic/div-by-zero-2.stderr +++ b/tests/run-pass/panic/div-by-zero-2.stderr @@ -1 +1 @@ -thread 'main' panicked at 'attempt to divide by zero', $DIR/div-by-zero-2.rs:5:14 +thread 'main' panicked at 'attempt to divide by zero', $DIR/div-by-zero-2.rs:4:14 diff --git a/tests/run-pass/panic/overflowing-lsh-neg.rs b/tests/run-pass/panic/overflowing-lsh-neg.rs index ee15ca0284ef..bf5eed1c550f 100644 --- a/tests/run-pass/panic/overflowing-lsh-neg.rs +++ b/tests/run-pass/panic/overflowing-lsh-neg.rs @@ -1,4 +1,3 @@ -// ignore-windows: Unwind panicking does not currently work on Windows #![allow(arithmetic_overflow)] fn main() { diff --git a/tests/run-pass/panic/overflowing-lsh-neg.stderr b/tests/run-pass/panic/overflowing-lsh-neg.stderr index e1e7daa119ab..04d98a0a2f15 100644 --- a/tests/run-pass/panic/overflowing-lsh-neg.stderr +++ b/tests/run-pass/panic/overflowing-lsh-neg.stderr @@ -1 +1 @@ -thread 'main' panicked at 'attempt to shift left with overflow', $DIR/overflowing-lsh-neg.rs:5:14 +thread 'main' panicked at 'attempt to shift left with overflow', $DIR/overflowing-lsh-neg.rs:4:14 diff --git a/tests/run-pass/panic/overflowing-rsh-1.rs b/tests/run-pass/panic/overflowing-rsh-1.rs index 36ab948a5efa..4c0106f0fb1f 100644 --- a/tests/run-pass/panic/overflowing-rsh-1.rs +++ b/tests/run-pass/panic/overflowing-rsh-1.rs @@ -1,4 +1,3 @@ -// ignore-windows: Unwind panicking does not currently work on Windows #![allow(arithmetic_overflow)] fn main() { diff --git a/tests/run-pass/panic/overflowing-rsh-1.stderr b/tests/run-pass/panic/overflowing-rsh-1.stderr index 20a45739ae2e..a9a72f46222d 100644 --- a/tests/run-pass/panic/overflowing-rsh-1.stderr +++ b/tests/run-pass/panic/overflowing-rsh-1.stderr @@ -1 +1 @@ -thread 'main' panicked at 'attempt to shift right with overflow', $DIR/overflowing-rsh-1.rs:5:14 +thread 'main' panicked at 'attempt to shift right with overflow', $DIR/overflowing-rsh-1.rs:4:14 diff --git a/tests/run-pass/panic/overflowing-rsh-2.rs b/tests/run-pass/panic/overflowing-rsh-2.rs index 27cc65fa7685..19d16e7bc84a 100644 --- a/tests/run-pass/panic/overflowing-rsh-2.rs +++ b/tests/run-pass/panic/overflowing-rsh-2.rs @@ -1,4 +1,3 @@ -// ignore-windows: Unwind panicking does not currently work on Windows #![allow(arithmetic_overflow)] fn main() { diff --git a/tests/run-pass/panic/overflowing-rsh-2.stderr b/tests/run-pass/panic/overflowing-rsh-2.stderr index 3381116ae6c8..24b61194565d 100644 --- a/tests/run-pass/panic/overflowing-rsh-2.stderr +++ b/tests/run-pass/panic/overflowing-rsh-2.stderr @@ -1 +1 @@ -thread 'main' panicked at 'attempt to shift right with overflow', $DIR/overflowing-rsh-2.rs:6:14 +thread 'main' panicked at 'attempt to shift right with overflow', $DIR/overflowing-rsh-2.rs:5:14 diff --git a/tests/run-pass/panic/panic1.rs b/tests/run-pass/panic/panic1.rs index 61321c658166..9d9ad28df5a7 100644 --- a/tests/run-pass/panic/panic1.rs +++ b/tests/run-pass/panic/panic1.rs @@ -1,4 +1,3 @@ -// ignore-windows: Unwind panicking does not currently work on Windows fn main() { std::panic!("panicking from libstd"); } diff --git a/tests/run-pass/panic/panic1.stderr b/tests/run-pass/panic/panic1.stderr index 305fc1a1a6e6..954b8799a082 100644 --- a/tests/run-pass/panic/panic1.stderr +++ b/tests/run-pass/panic/panic1.stderr @@ -1 +1 @@ -thread 'main' panicked at 'panicking from libstd', $DIR/panic1.rs:3:5 +thread 'main' panicked at 'panicking from libstd', $DIR/panic1.rs:2:5 diff --git a/tests/run-pass/panic/panic2.rs b/tests/run-pass/panic/panic2.rs index d6ab864795ea..d90e3f2e0ac1 100644 --- a/tests/run-pass/panic/panic2.rs +++ b/tests/run-pass/panic/panic2.rs @@ -1,4 +1,3 @@ -// ignore-windows: Unwind panicking does not currently work on Windows fn main() { std::panic!("{}-panicking from libstd", 42); } diff --git a/tests/run-pass/panic/panic2.stderr b/tests/run-pass/panic/panic2.stderr index cd40559c81ef..e90e3502cbfb 100644 --- a/tests/run-pass/panic/panic2.stderr +++ b/tests/run-pass/panic/panic2.stderr @@ -1 +1 @@ -thread 'main' panicked at '42-panicking from libstd', $DIR/panic2.rs:3:5 +thread 'main' panicked at '42-panicking from libstd', $DIR/panic2.rs:2:5 diff --git a/tests/run-pass/panic/panic3.rs b/tests/run-pass/panic/panic3.rs index 10a42c7e6c00..418ee4f8411e 100644 --- a/tests/run-pass/panic/panic3.rs +++ b/tests/run-pass/panic/panic3.rs @@ -1,4 +1,3 @@ -// ignore-windows: Unwind panicking does not currently work on Windows fn main() { core::panic!("panicking from libcore"); } diff --git a/tests/run-pass/panic/panic3.stderr b/tests/run-pass/panic/panic3.stderr index e3aa902f0cbc..0a3c191b282e 100644 --- a/tests/run-pass/panic/panic3.stderr +++ b/tests/run-pass/panic/panic3.stderr @@ -1 +1 @@ -thread 'main' panicked at 'panicking from libcore', $DIR/panic3.rs:3:5 +thread 'main' panicked at 'panicking from libcore', $DIR/panic3.rs:2:5 diff --git a/tests/run-pass/panic/panic4.rs b/tests/run-pass/panic/panic4.rs index 06e2dd008fff..0fcc53813b5d 100644 --- a/tests/run-pass/panic/panic4.rs +++ b/tests/run-pass/panic/panic4.rs @@ -1,4 +1,3 @@ -// ignore-windows: Unwind panicking does not currently work on Windows fn main() { core::panic!("{}-panicking from libcore", 42); } diff --git a/tests/run-pass/panic/panic4.stderr b/tests/run-pass/panic/panic4.stderr index 1a242a868cae..946059b1e49f 100644 --- a/tests/run-pass/panic/panic4.stderr +++ b/tests/run-pass/panic/panic4.stderr @@ -1 +1 @@ -thread 'main' panicked at '42-panicking from libcore', $DIR/panic4.rs:3:5 +thread 'main' panicked at '42-panicking from libcore', $DIR/panic4.rs:2:5 diff --git a/tests/run-pass/panic/std-panic-locations.rs b/tests/run-pass/panic/std-panic-locations.rs index d5f38fc2672e..ac2e8d5305df 100644 --- a/tests/run-pass/panic/std-panic-locations.rs +++ b/tests/run-pass/panic/std-panic-locations.rs @@ -1,4 +1,3 @@ -// ignore-windows: Unwind panicking does not currently work on Windows #![feature(option_expect_none, option_unwrap_none)] //! Test that panic locations for `#[track_caller]` functions in std have the correct //! location reported. diff --git a/tests/run-pass/transmute_fat2.rs b/tests/run-pass/transmute_fat2.rs index c667aab6bb5f..3dff2cc1e0c9 100644 --- a/tests/run-pass/transmute_fat2.rs +++ b/tests/run-pass/transmute_fat2.rs @@ -1,4 +1,3 @@ -// ignore-windows: Unwind panicking does not currently work on Windows fn main() { #[cfg(target_pointer_width="64")] let bad = unsafe { diff --git a/tests/run-pass/transmute_fat2.stderr b/tests/run-pass/transmute_fat2.stderr index 2539e58814d6..08849a5b517a 100644 --- a/tests/run-pass/transmute_fat2.stderr +++ b/tests/run-pass/transmute_fat2.stderr @@ -1 +1 @@ -thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', $DIR/transmute_fat2.rs:12:5 +thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', $DIR/transmute_fat2.rs:11:5 From a9dc2796cac8d49f67f6055d3fe3561a13f604b7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 28 Jun 2020 09:23:01 +0200 Subject: [PATCH 2153/5092] Move get/set_at_offset helpers to global helpers file --- src/helpers.rs | 31 +++++++++++++++ src/shims/posix/sync.rs | 84 +++++++---------------------------------- 2 files changed, 45 insertions(+), 70 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 4e5e0dcfca25..c1eaf4eb4865 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -467,6 +467,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } + + fn read_scalar_at_offset( + &self, + op: OpTy<'tcx, Tag>, + offset: u64, + layout: TyAndLayout<'tcx>, + ) -> InterpResult<'tcx, ScalarMaybeUninit> { + let this = self.eval_context_ref(); + let op_place = this.deref_operand(op)?; + let offset = Size::from_bytes(offset); + // Ensure that the following read at an offset is within bounds + assert!(op_place.layout.size >= offset + layout.size); + let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; + this.read_scalar(value_place.into()) + } + + fn write_scalar_at_offset( + &mut self, + op: OpTy<'tcx, Tag>, + offset: u64, + value: impl Into>, + layout: TyAndLayout<'tcx>, + ) -> InterpResult<'tcx, ()> { + let this = self.eval_context_mut(); + let op_place = this.deref_operand(op)?; + let offset = Size::from_bytes(offset); + // Ensure that the following read at an offset is within bounds + assert!(op_place.layout.size >= offset + layout.size); + let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; + this.write_scalar(value, value_place.into()) + } } /// Check that the number of args is what we expect. diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index a61c80d5118c..bc4be56557a4 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -2,57 +2,11 @@ use std::convert::TryInto; use std::time::{Duration, SystemTime}; use std::ops::Not; -use rustc_middle::ty::{layout::TyAndLayout, TyKind, TypeAndMut}; -use rustc_target::abi::{LayoutOf, Size}; - use crate::*; use stacked_borrows::Tag; use thread::Time; -fn assert_ptr_target_min_size<'mir, 'tcx: 'mir>( - ecx: &MiriEvalContext<'mir, 'tcx>, - operand: OpTy<'tcx, Tag>, - min_size: u64, -) -> InterpResult<'tcx, ()> { - let target_ty = match operand.layout.ty.kind { - TyKind::RawPtr(TypeAndMut { ty, mutbl: _ }) => ty, - _ => panic!("Argument to pthread function was not a raw pointer"), - }; - let target_layout = ecx.layout_of(target_ty)?; - assert!(target_layout.size.bytes() >= min_size); - Ok(()) -} - -fn get_at_offset<'mir, 'tcx: 'mir>( - ecx: &MiriEvalContext<'mir, 'tcx>, - op: OpTy<'tcx, Tag>, - offset: u64, - layout: TyAndLayout<'tcx>, - min_size: u64, -) -> InterpResult<'tcx, ScalarMaybeUninit> { - // Ensure that the following read at an offset to the attr pointer is within bounds - assert_ptr_target_min_size(ecx, op, min_size)?; - let op_place = ecx.deref_operand(op)?; - let value_place = op_place.offset(Size::from_bytes(offset), MemPlaceMeta::None, layout, ecx)?; - ecx.read_scalar(value_place.into()) -} - -fn set_at_offset<'mir, 'tcx: 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, - op: OpTy<'tcx, Tag>, - offset: u64, - value: impl Into>, - layout: TyAndLayout<'tcx>, - min_size: u64, -) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the attr pointer is within bounds - assert_ptr_target_min_size(ecx, op, min_size)?; - let op_place = ecx.deref_operand(op)?; - let value_place = op_place.offset(Size::from_bytes(offset), MemPlaceMeta::None, layout, ecx)?; - ecx.write_scalar(value.into(), value_place.into()) -} - // pthread_mutexattr_t is either 4 or 8 bytes, depending on the platform. // Our chosen memory layout for emulation (does not have to match the platform layout!): @@ -66,8 +20,6 @@ fn set_at_offset<'mir, 'tcx: 'mir>( /// in `pthread_mutexattr_settype` function. const PTHREAD_MUTEX_NORMAL_FLAG: i32 = 0x8000000; -const PTHREAD_MUTEXATTR_T_MIN_SIZE: u64 = 4; - fn is_mutex_kind_default<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, kind: Scalar, @@ -88,7 +40,7 @@ fn mutexattr_get_kind<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, attr_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - get_at_offset(ecx, attr_op, 0, ecx.machine.layouts.i32, PTHREAD_MUTEXATTR_T_MIN_SIZE) + ecx.read_scalar_at_offset(attr_op, 0, ecx.machine.layouts.i32) } fn mutexattr_set_kind<'mir, 'tcx: 'mir>( @@ -96,7 +48,7 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( attr_op: OpTy<'tcx, Tag>, kind: impl Into>, ) -> InterpResult<'tcx, ()> { - set_at_offset(ecx, attr_op, 0, kind, ecx.machine.layouts.i32, PTHREAD_MUTEXATTR_T_MIN_SIZE) + ecx.write_scalar_at_offset(attr_op, 0, kind, ecx.machine.layouts.i32) } // pthread_mutex_t is between 24 and 48 bytes, depending on the platform. @@ -108,14 +60,12 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( // bytes 12-15 or 16-19 (depending on platform): mutex kind, as an i32 // (the kind has to be at its offset for compatibility with static initializer macros) -const PTHREAD_MUTEX_T_MIN_SIZE: u64 = 24; - fn mutex_get_kind<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - get_at_offset(ecx, mutex_op, offset, ecx.machine.layouts.i32, PTHREAD_MUTEX_T_MIN_SIZE) + ecx.read_scalar_at_offset(mutex_op, offset, ecx.machine.layouts.i32) } fn mutex_set_kind<'mir, 'tcx: 'mir>( @@ -124,14 +74,14 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( kind: impl Into>, ) -> InterpResult<'tcx, ()> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - set_at_offset(ecx, mutex_op, offset, kind, ecx.machine.layouts.i32, PTHREAD_MUTEX_T_MIN_SIZE) + ecx.write_scalar_at_offset(mutex_op, offset, kind, ecx.machine.layouts.i32) } fn mutex_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - get_at_offset(ecx, mutex_op, 4, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) + ecx.read_scalar_at_offset(mutex_op, 4, ecx.machine.layouts.u32) } fn mutex_set_id<'mir, 'tcx: 'mir>( @@ -139,7 +89,7 @@ fn mutex_set_id<'mir, 'tcx: 'mir>( mutex_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { - set_at_offset(ecx, mutex_op, 4, id, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) + ecx.write_scalar_at_offset(mutex_op, 4, id, ecx.machine.layouts.u32) } fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( @@ -165,13 +115,11 @@ fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( // (need to avoid this because it is set by static initializer macros) // bytes 4-7: rwlock id as u32 or 0 if id is not assigned yet. -const PTHREAD_RWLOCK_T_MIN_SIZE: u64 = 32; - fn rwlock_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - get_at_offset(ecx, rwlock_op, 4, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) + ecx.read_scalar_at_offset(rwlock_op, 4, ecx.machine.layouts.u32) } fn rwlock_set_id<'mir, 'tcx: 'mir>( @@ -179,7 +127,7 @@ fn rwlock_set_id<'mir, 'tcx: 'mir>( rwlock_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { - set_at_offset(ecx, rwlock_op, 4, id, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) + ecx.write_scalar_at_offset(rwlock_op, 4, id, ecx.machine.layouts.u32) } fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( @@ -204,13 +152,11 @@ fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( // store an i32 in the first four bytes equal to the corresponding libc clock id constant // (e.g. CLOCK_REALTIME). -const PTHREAD_CONDATTR_T_MIN_SIZE: u64 = 4; - fn condattr_get_clock_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, attr_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - get_at_offset(ecx, attr_op, 0, ecx.machine.layouts.i32, PTHREAD_CONDATTR_T_MIN_SIZE) + ecx.read_scalar_at_offset(attr_op, 0, ecx.machine.layouts.i32) } fn condattr_set_clock_id<'mir, 'tcx: 'mir>( @@ -218,7 +164,7 @@ fn condattr_set_clock_id<'mir, 'tcx: 'mir>( attr_op: OpTy<'tcx, Tag>, clock_id: impl Into>, ) -> InterpResult<'tcx, ()> { - set_at_offset(ecx, attr_op, 0, clock_id, ecx.machine.layouts.i32, PTHREAD_CONDATTR_T_MIN_SIZE) + ecx.write_scalar_at_offset(attr_op, 0, clock_id, ecx.machine.layouts.i32) } // pthread_cond_t @@ -230,13 +176,11 @@ fn condattr_set_clock_id<'mir, 'tcx: 'mir>( // bytes 4-7: the conditional variable id as u32 or 0 if id is not assigned yet. // bytes 8-11: the clock id constant as i32 -const PTHREAD_COND_T_MIN_SIZE: u64 = 12; - fn cond_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, cond_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - get_at_offset(ecx, cond_op, 4, ecx.machine.layouts.u32, PTHREAD_COND_T_MIN_SIZE) + ecx.read_scalar_at_offset(cond_op, 4, ecx.machine.layouts.u32) } fn cond_set_id<'mir, 'tcx: 'mir>( @@ -244,7 +188,7 @@ fn cond_set_id<'mir, 'tcx: 'mir>( cond_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { - set_at_offset(ecx, cond_op, 4, id, ecx.machine.layouts.u32, PTHREAD_COND_T_MIN_SIZE) + ecx.write_scalar_at_offset(cond_op, 4, id, ecx.machine.layouts.u32) } fn cond_get_or_create_id<'mir, 'tcx: 'mir>( @@ -267,7 +211,7 @@ fn cond_get_clock_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, cond_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - get_at_offset(ecx, cond_op, 8, ecx.machine.layouts.i32, PTHREAD_COND_T_MIN_SIZE) + ecx.read_scalar_at_offset(cond_op, 8, ecx.machine.layouts.i32) } fn cond_set_clock_id<'mir, 'tcx: 'mir>( @@ -275,7 +219,7 @@ fn cond_set_clock_id<'mir, 'tcx: 'mir>( cond_op: OpTy<'tcx, Tag>, clock_id: impl Into>, ) -> InterpResult<'tcx, ()> { - set_at_offset(ecx, cond_op, 8, clock_id, ecx.machine.layouts.i32, PTHREAD_COND_T_MIN_SIZE) + ecx.write_scalar_at_offset(cond_op, 8, clock_id, ecx.machine.layouts.i32) } /// Try to reacquire the mutex associated with the condition variable after we From 3a5bcb97edd5bab769341aacde18a05c015aa396 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 28 Jun 2020 09:47:20 +0200 Subject: [PATCH 2154/5092] move rwlock dequeuing to shared code, and use that code for Windows rwlocks --- src/shims/posix/sync.rs | 22 +-- src/shims/windows/foreign_items.rs | 6 +- src/shims/windows/sync.rs | 126 ++++++------- src/sync.rs | 165 +++++++++++------- .../compile-fail/concurrency/thread-spawn.rs | 2 +- 5 files changed, 160 insertions(+), 161 deletions(-) diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index bc4be56557a4..cce0ddc930df 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -1,6 +1,5 @@ use std::convert::TryInto; use std::time::{Duration, SystemTime}; -use std::ops::Not; use crate::*; use stacked_borrows::Tag; @@ -548,27 +547,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let active_thread = this.get_active_thread(); if this.rwlock_reader_unlock(id, active_thread) { - // The thread was a reader. - if this.rwlock_is_locked(id).not() { - // No more readers owning the lock. Give it to a writer if there - // is any. - this.rwlock_dequeue_and_lock_writer(id); - } Ok(0) - } else if Some(active_thread) == this.rwlock_writer_unlock(id) { - // The thread was a writer. - // - // We are prioritizing writers here against the readers. As a - // result, not only readers can starve writers, but also writers can - // starve readers. - if this.rwlock_dequeue_and_lock_writer(id) { - // Someone got the write lock, nice. - } else { - // Give the lock to all readers. - while this.rwlock_dequeue_and_lock_reader(id) { - // Rinse and repeat. - } - } + } else if this.rwlock_writer_unlock(id, active_thread) { Ok(0) } else { throw_ub_format!("unlocked an rwlock that was not locked by the active thread"); diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index ddb70b752e79..e8937bbb3085 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -257,7 +257,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Better error for attempts to create a thread "CreateThread" => { - throw_unsup_format!("Miri does not support threading"); + throw_unsup_format!("Miri does not support concurrency on Windows"); } // Incomplete shims that we "stub out" just to get pre-main initialization code to work. @@ -292,7 +292,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] let &[_lpCriticalSection] = check_arg_count(args)?; - assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows not supported"); + assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); // Nothing to do, not even a return value. // (Windows locks are reentrant, and we have only 1 thread, // so not doing any futher checks here is at least not incorrect.) @@ -301,7 +301,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] let &[_lpCriticalSection] = check_arg_count(args)?; - assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows not supported"); + assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); // There is only one thread, so this always succeeds and returns TRUE. this.write_scalar(Scalar::from_i32(1), dest)?; } diff --git a/src/shims/windows/sync.rs b/src/shims/windows/sync.rs index ef40eb089110..7bad3c08a598 100644 --- a/src/shims/windows/sync.rs +++ b/src/shims/windows/sync.rs @@ -1,19 +1,22 @@ -use rustc_target::abi::Size; - use crate::*; // Locks are pointer-sized pieces of data, initialized to 0. -// We use them to count readers, with usize::MAX representing the write-locked state. +// We use the first 4 bytes to store the RwLockId. -fn deref_lock<'mir, 'tcx: 'mir>( +fn srwlock_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, lock_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, MPlaceTy<'tcx, Tag>> { - // `lock` is a pointer to `void*`; cast it to a pointer to `usize`. - let lock = ecx.deref_operand(lock_op)?; - let usize = ecx.machine.layouts.usize; - assert_eq!(lock.layout.size, usize.size); - Ok(lock.offset(Size::ZERO, MemPlaceMeta::None, usize, ecx)?) +) -> InterpResult<'tcx, RwLockId> { + let id = ecx.read_scalar_at_offset(lock_op, 0, ecx.machine.layouts.u32)?.to_u32()?; + if id == 0 { + // 0 is a default value and also not a valid rwlock id. Need to allocate + // a new rwlock. + let id = ecx.rwlock_create(); + ecx.write_scalar_at_offset(lock_op, 0, id.to_u32_scalar(), ecx.machine.layouts.u32)?; + Ok(id) + } else { + Ok(RwLockId::from_u32(id)) + } } impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -24,17 +27,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx lock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); + let id = srwlock_get_or_create_id(this, lock_op)?; + let active_thread = this.get_active_thread(); - let lock = deref_lock(this, lock_op)?; - let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?; - if lock_val == 0 { - // Currently not locked. Lock it. - let new_val = Scalar::from_machine_usize(this.machine_usize_max(), this); - this.write_scalar(new_val, lock.into())?; + if this.rwlock_is_locked(id) { + // Note: this will deadlock if the lock is already locked by this + // thread in any way. + // + // FIXME: Detect and report the deadlock proactively. (We currently + // report the deadlock only when no thread can continue execution, + // but we could detect that this lock is already locked and report + // an error.) + this.rwlock_enqueue_and_block_writer(id, active_thread); } else { - // Lock is already held. This is a deadlock. - throw_machine_stop!(TerminationInfo::Deadlock); + this.rwlock_writer_lock(id, active_thread); } Ok(()) @@ -46,18 +52,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx lock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, u8> { let this = self.eval_context_mut(); - assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); + let id = srwlock_get_or_create_id(this, lock_op)?; + let active_thread = this.get_active_thread(); - let lock = deref_lock(this, lock_op)?; - let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?; - if lock_val == 0 { - // Currently not locked. Lock it. - let new_val = this.machine_usize_max(); - this.write_scalar(Scalar::from_machine_usize(new_val, this), lock.into())?; - Ok(1) - } else { + if this.rwlock_is_locked(id) { // Lock is already held. Ok(0) + } else { + this.rwlock_writer_lock(id, active_thread); + Ok(1) } } @@ -67,17 +70,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx lock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); + let id = srwlock_get_or_create_id(this, lock_op)?; + let active_thread = this.get_active_thread(); - let lock = deref_lock(this, lock_op)?; - let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?; - if lock_val == this.machine_usize_max() { - // Currently locked. Unlock it. - let new_val = 0; - this.write_scalar(Scalar::from_machine_usize(new_val, this), lock.into())?; - } else { - // Lock is not locked. - throw_ub_format!("calling ReleaseSRWLockExclusive on an SRWLock that is not exclusively locked"); + if !this.rwlock_writer_unlock(id, active_thread) { + // The docs do not say anything about this case, but it seems better to not allow it. + throw_ub_format!("calling ReleaseSRWLockExclusive on an SRWLock that is not exclusively locked by the current thread"); } Ok(()) @@ -89,21 +87,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx lock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); + let id = srwlock_get_or_create_id(this, lock_op)?; + let active_thread = this.get_active_thread(); - let lock = deref_lock(this, lock_op)?; - let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?; - if lock_val == this.machine_usize_max() { - // Currently write locked. This is a deadlock. - throw_machine_stop!(TerminationInfo::Deadlock); + if this.rwlock_is_write_locked(id) { + this.rwlock_enqueue_and_block_reader(id, active_thread); } else { - // Bump up read counter (cannot overflow as we just checkd against usize::MAX); - let new_val = lock_val+1; - // Make sure this does not reach the "write locked" flag. - if new_val == this.machine_usize_max() { - throw_unsup_format!("SRWLock read-acquired too many times"); - } - this.write_scalar(Scalar::from_machine_usize(new_val, this), lock.into())?; + this.rwlock_reader_lock(id, active_thread); } Ok(()) @@ -115,21 +105,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx lock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, u8> { let this = self.eval_context_mut(); - assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); + let id = srwlock_get_or_create_id(this, lock_op)?; + let active_thread = this.get_active_thread(); - let lock = deref_lock(this, lock_op)?; - let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?; - if lock_val == this.machine_usize_max() { - // Currently write locked. + if this.rwlock_is_write_locked(id) { Ok(0) } else { - // Bump up read counter (cannot overflow as we just checkd against usize::MAX); - let new_val = lock_val+1; - // Make sure this does not reach the "write locked" flag. - if new_val == this.machine_usize_max() { - throw_unsup_format!("SRWLock read-acquired too many times"); - } - this.write_scalar(Scalar::from_machine_usize(new_val, this), lock.into())?; + this.rwlock_reader_lock(id, active_thread); Ok(1) } } @@ -140,20 +122,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx lock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); + let id = srwlock_get_or_create_id(this, lock_op)?; + let active_thread = this.get_active_thread(); - let lock = deref_lock(this, lock_op)?; - let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?; - if lock_val == this.machine_usize_max() { - // Currently write locked. This is a UB. - throw_ub_format!("calling ReleaseSRWLockShared on write-locked SRWLock"); - } else if lock_val == 0 { - // Currently not locked at all. - throw_ub_format!("calling ReleaseSRWLockShared on unlocked SRWLock"); - } else { - // Decrement read counter (cannot overflow as we just checkd against 0); - let new_val = lock_val-1; - this.write_scalar(Scalar::from_machine_usize(new_val, this), lock.into())?; + if !this.rwlock_reader_unlock(id, active_thread) { + // The docs do not say anything about this case, but it seems better to not allow it. + throw_ub_format!("calling ReleaseSRWLockShared on an SRWLock that is not locked by the current thread"); } Ok(()) diff --git a/src/sync.rs b/src/sync.rs index 0d4b4d6b7c1c..7e3c27b386df 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -3,6 +3,8 @@ use std::convert::TryFrom; use std::num::NonZeroU32; use std::ops::Not; +use log::trace; + use rustc_index::vec::{Idx, IndexVec}; use crate::*; @@ -102,6 +104,52 @@ pub(super) struct SynchronizationState { condvars: IndexVec, } +// Private extension trait for local helper methods +impl<'mir, 'tcx: 'mir> EvalContextExtPriv<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + /// Take a reader out of the queue waiting for the lock. + /// Returns `true` if some thread got the rwlock. + #[inline] + fn rwlock_dequeue_and_lock_reader(&mut self, id: RwLockId) -> bool { + let this = self.eval_context_mut(); + if let Some(reader) = this.machine.threads.sync.rwlocks[id].reader_queue.pop_front() { + this.unblock_thread(reader); + this.rwlock_reader_lock(id, reader); + true + } else { + false + } + } + + /// Take the writer out of the queue waiting for the lock. + /// Returns `true` if some thread got the rwlock. + #[inline] + fn rwlock_dequeue_and_lock_writer(&mut self, id: RwLockId) -> bool { + let this = self.eval_context_mut(); + if let Some(writer) = this.machine.threads.sync.rwlocks[id].writer_queue.pop_front() { + this.unblock_thread(writer); + this.rwlock_writer_lock(id, writer); + true + } else { + false + } + } + + /// Take a thread out of the queue waiting for the mutex, and lock + /// the mutex for it. Returns `true` if some thread has the mutex now. + #[inline] + fn mutex_dequeue_and_lock(&mut self, id: MutexId) -> bool { + let this = self.eval_context_mut(); + if let Some(thread) = this.machine.threads.sync.mutexes[id].queue.pop_front() { + this.unblock_thread(thread); + this.mutex_lock(id, thread); + true + } else { + false + } + } +} + // Public interface to synchronization primitives. Please note that in most // cases, the function calls are infallible and it is the client's (shim // implementation's) responsibility to detect and deal with erroneous @@ -124,8 +172,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] /// Check if locked. - fn mutex_is_locked(&mut self, id: MutexId) -> bool { - let this = self.eval_context_mut(); + fn mutex_is_locked(&self, id: MutexId) -> bool { + let this = self.eval_context_ref(); this.machine.threads.sync.mutexes[id].owner.is_some() } @@ -174,7 +222,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Some(old_lock_count) } else { - // Mutex is unlocked. + // Mutex is not locked. None } } @@ -188,20 +236,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.block_thread(thread); } - #[inline] - /// Take a thread out of the queue waiting for the mutex, and lock - /// the mutex for it. Returns `true` if some thread has the mutex now. - fn mutex_dequeue_and_lock(&mut self, id: MutexId) -> bool { - let this = self.eval_context_mut(); - if let Some(thread) = this.machine.threads.sync.mutexes[id].queue.pop_front() { - this.unblock_thread(thread); - this.mutex_lock(id, thread); - true - } else { - false - } - } - #[inline] /// Create state for a new read write lock. fn rwlock_create(&mut self) -> RwLockId { @@ -211,17 +245,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] /// Check if locked. - fn rwlock_is_locked(&mut self, id: RwLockId) -> bool { - let this = self.eval_context_mut(); - this.machine.threads.sync.rwlocks[id].writer.is_some() - || this.machine.threads.sync.rwlocks[id].readers.is_empty().not() + fn rwlock_is_locked(&self, id: RwLockId) -> bool { + let this = self.eval_context_ref(); + let rwlock = &this.machine.threads.sync.rwlocks[id]; + trace!( + "rwlock_is_locked: {:?} writer is {:?} and there are {} reader threads (some of which could hold multiple read locks)", + id, rwlock.writer, rwlock.readers.len(), + ); + rwlock.writer.is_some()|| rwlock.readers.is_empty().not() } #[inline] /// Check if write locked. - fn rwlock_is_write_locked(&mut self, id: RwLockId) -> bool { - let this = self.eval_context_mut(); - this.machine.threads.sync.rwlocks[id].writer.is_some() + fn rwlock_is_write_locked(&self, id: RwLockId) -> bool { + let this = self.eval_context_ref(); + let rwlock = &this.machine.threads.sync.rwlocks[id]; + trace!("rwlock_is_write_locked: {:?} writer is {:?}", id, rwlock.writer); + rwlock.writer.is_some() } /// Read-lock the lock by adding the `reader` the list of threads that own @@ -229,12 +269,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn rwlock_reader_lock(&mut self, id: RwLockId, reader: ThreadId) { let this = self.eval_context_mut(); assert!(!this.rwlock_is_write_locked(id), "the lock is write locked"); + trace!("rwlock_reader_lock: {:?} now also held (one more time) by {:?}", id, reader); let count = this.machine.threads.sync.rwlocks[id].readers.entry(reader).or_insert(0); *count = count.checked_add(1).expect("the reader counter overflowed"); } - /// Try read-unlock the lock for `reader`. Returns `true` if succeeded, - /// `false` if this `reader` did not hold the lock. + /// Try read-unlock the lock for `reader` and potentially give the lock to a new owner. + /// Returns `true` if succeeded, `false` if this `reader` did not hold the lock. fn rwlock_reader_unlock(&mut self, id: RwLockId, reader: ThreadId) -> bool { let this = self.eval_context_mut(); match this.machine.threads.sync.rwlocks[id].readers.entry(reader) { @@ -243,12 +284,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert!(*count > 0, "rwlock locked with count == 0"); *count -= 1; if *count == 0 { + trace!("rwlock_reader_unlock: {:?} no longer held by {:?}", id, reader); entry.remove(); + } else { + trace!("rwlock_reader_unlock: {:?} held one less time by {:?}", id, reader); } - true } - Entry::Vacant(_) => false, + Entry::Vacant(_) => return false, // we did not even own this lock } + // The thread was a reader. If the lock is not held any more, give it to a writer. + if this.rwlock_is_locked(id).not() { + this.rwlock_dequeue_and_lock_writer(id); + } + true } #[inline] @@ -259,38 +307,49 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx reader: ThreadId, ) { let this = self.eval_context_mut(); - assert!(this.rwlock_is_write_locked(id), "queueing on not write locked lock"); + assert!(this.rwlock_is_write_locked(id), "read-queueing on not write locked rwlock"); this.machine.threads.sync.rwlocks[id].reader_queue.push_back(reader); this.block_thread(reader); } - #[inline] - /// Take a reader out the queue waiting for the lock. - /// Returns `true` if some thread got the rwlock. - fn rwlock_dequeue_and_lock_reader(&mut self, id: RwLockId) -> bool { - let this = self.eval_context_mut(); - if let Some(reader) = this.machine.threads.sync.rwlocks[id].reader_queue.pop_front() { - this.unblock_thread(reader); - this.rwlock_reader_lock(id, reader); - true - } else { - false - } - } - #[inline] /// Lock by setting the writer that owns the lock. fn rwlock_writer_lock(&mut self, id: RwLockId, writer: ThreadId) { let this = self.eval_context_mut(); assert!(!this.rwlock_is_locked(id), "the rwlock is already locked"); + trace!("rwlock_writer_lock: {:?} now held by {:?}", id, writer); this.machine.threads.sync.rwlocks[id].writer = Some(writer); } #[inline] /// Try to unlock by removing the writer. - fn rwlock_writer_unlock(&mut self, id: RwLockId) -> Option { + fn rwlock_writer_unlock(&mut self, id: RwLockId, expected_writer: ThreadId) -> bool { let this = self.eval_context_mut(); - this.machine.threads.sync.rwlocks[id].writer.take() + let rwlock = &mut this.machine.threads.sync.rwlocks[id]; + if let Some(current_writer) = rwlock.writer { + if current_writer != expected_writer { + // Only the owner can unlock the rwlock. + return false; + } + rwlock.writer = None; + trace!("rwlock_writer_unlock: {:?} unlocked by {:?}", id, expected_writer); + // The thread was a writer. + // + // We are prioritizing writers here against the readers. As a + // result, not only readers can starve writers, but also writers can + // starve readers. + if this.rwlock_dequeue_and_lock_writer(id) { + // Someone got the write lock, nice. + } else { + // Give the lock to all readers. + while this.rwlock_dequeue_and_lock_reader(id) { + // Rinse and repeat. + } + } + true + } else { + false + } } #[inline] @@ -301,25 +360,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx writer: ThreadId, ) { let this = self.eval_context_mut(); - assert!(this.rwlock_is_locked(id), "queueing on unlocked lock"); + assert!(this.rwlock_is_locked(id), "write-queueing on unlocked rwlock"); this.machine.threads.sync.rwlocks[id].writer_queue.push_back(writer); this.block_thread(writer); } - #[inline] - /// Take the writer out the queue waiting for the lock. - /// Returns `true` if some thread got the rwlock. - fn rwlock_dequeue_and_lock_writer(&mut self, id: RwLockId) -> bool { - let this = self.eval_context_mut(); - if let Some(writer) = this.machine.threads.sync.rwlocks[id].writer_queue.pop_front() { - this.unblock_thread(writer); - this.rwlock_writer_lock(id, writer); - true - } else { - false - } - } - #[inline] /// Create state for a new conditional variable. fn condvar_create(&mut self) -> CondvarId { diff --git a/tests/compile-fail/concurrency/thread-spawn.rs b/tests/compile-fail/concurrency/thread-spawn.rs index f0e4ab3817d3..27760eed8dba 100644 --- a/tests/compile-fail/concurrency/thread-spawn.rs +++ b/tests/compile-fail/concurrency/thread-spawn.rs @@ -3,7 +3,7 @@ use std::thread; -// error-pattern: Miri does not support threading +// error-pattern: Miri does not support concurrency on Windows fn main() { thread::spawn(|| {}); From fcdacce4b1638bb00aa4f9e0b8c5c5707c5ab969 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 28 Jun 2020 11:31:34 +0200 Subject: [PATCH 2155/5092] fix some ignore-windows comments --- .../concurrency/libc_pthread_create_main_terminate.rs | 2 +- tests/compile-fail/concurrency/libc_pthread_join_detached.rs | 2 +- tests/compile-fail/concurrency/libc_pthread_join_joined.rs | 2 +- tests/compile-fail/concurrency/libc_pthread_join_main.rs | 2 +- tests/compile-fail/concurrency/libc_pthread_join_multiple.rs | 2 +- tests/compile-fail/concurrency/libc_pthread_join_self.rs | 2 +- tests/compile-fail/environ-gets-deallocated.rs | 2 +- tests/run-pass/calloc.rs | 2 +- tests/run-pass/malloc.rs | 2 +- tests/run-pass/thread-local.rs | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs b/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs index ea11691955ce..35ee03242d11 100644 --- a/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs +++ b/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +// ignore-windows: No libc on Windows // error-pattern: unsupported operation: the main thread terminated without waiting for other threads // Check that we terminate the program when the main thread terminates. diff --git a/tests/compile-fail/concurrency/libc_pthread_join_detached.rs b/tests/compile-fail/concurrency/libc_pthread_join_detached.rs index ad83fb2efef3..dcd06596de13 100644 --- a/tests/compile-fail/concurrency/libc_pthread_join_detached.rs +++ b/tests/compile-fail/concurrency/libc_pthread_join_detached.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +// ignore-windows: No libc on Windows // Joining a detached thread is undefined behavior. diff --git a/tests/compile-fail/concurrency/libc_pthread_join_joined.rs b/tests/compile-fail/concurrency/libc_pthread_join_joined.rs index 3ca042449690..26f33f1f5f94 100644 --- a/tests/compile-fail/concurrency/libc_pthread_join_joined.rs +++ b/tests/compile-fail/concurrency/libc_pthread_join_joined.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +// ignore-windows: No libc on Windows // Joining an already joined thread is undefined behavior. diff --git a/tests/compile-fail/concurrency/libc_pthread_join_main.rs b/tests/compile-fail/concurrency/libc_pthread_join_main.rs index 69e1a68ef97a..15e43776ab82 100644 --- a/tests/compile-fail/concurrency/libc_pthread_join_main.rs +++ b/tests/compile-fail/concurrency/libc_pthread_join_main.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +// ignore-windows: No libc on Windows // Joining the main thread is undefined behavior. diff --git a/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs b/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs index f8a43cfcde64..d86233a67643 100644 --- a/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs +++ b/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +// ignore-windows: No libc on Windows // Joining the same thread from multiple threads is undefined behavior. diff --git a/tests/compile-fail/concurrency/libc_pthread_join_self.rs b/tests/compile-fail/concurrency/libc_pthread_join_self.rs index d765a95d8be7..2a8fe12eafd6 100644 --- a/tests/compile-fail/concurrency/libc_pthread_join_self.rs +++ b/tests/compile-fail/concurrency/libc_pthread_join_self.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +// ignore-windows: No libc on Windows // Joining itself is undefined behavior. diff --git a/tests/compile-fail/environ-gets-deallocated.rs b/tests/compile-fail/environ-gets-deallocated.rs index 0f374a2e3f80..b5a4441d2f9b 100644 --- a/tests/compile-fail/environ-gets-deallocated.rs +++ b/tests/compile-fail/environ-gets-deallocated.rs @@ -1,4 +1,4 @@ -//ignore-windows: Windows does not have a global environ list that the program can access directly +// ignore-windows: Windows does not have a global environ list that the program can access directly #[cfg(target_os="linux")] fn get_environ() -> *const *const u8 { diff --git a/tests/run-pass/calloc.rs b/tests/run-pass/calloc.rs index 4c520da85e87..6793f86c116c 100644 --- a/tests/run-pass/calloc.rs +++ b/tests/run-pass/calloc.rs @@ -1,4 +1,4 @@ -//ignore-windows: Uses POSIX APIs +// ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/run-pass/malloc.rs b/tests/run-pass/malloc.rs index f66263425ee8..8e0d9ac62932 100644 --- a/tests/run-pass/malloc.rs +++ b/tests/run-pass/malloc.rs @@ -1,4 +1,4 @@ -//ignore-windows: Uses POSIX APIs +// ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/run-pass/thread-local.rs b/tests/run-pass/thread-local.rs index 8de45811be44..1aa442edad3b 100644 --- a/tests/run-pass/thread-local.rs +++ b/tests/run-pass/thread-local.rs @@ -1,4 +1,4 @@ -//ignore-windows: Uses POSIX APIs +// ignore-windows: No libc on Windows #![feature(rustc_private)] extern crate libc; From c379793cdee2ef6e777fce7e4f19993d29e77f9d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Jul 2020 09:50:52 +0200 Subject: [PATCH 2156/5092] add option to track call IDs --- README.md | 3 +++ src/bin/miri.rs | 28 +++++++++++++++++++++------- src/diagnostics.rs | 7 +++++-- src/eval.rs | 6 +++++- src/lib.rs | 2 +- src/machine.rs | 3 ++- src/stacked_borrows.rs | 12 +++++++++--- 7 files changed, 46 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 6b2b36d18c32..ab4d4c02db1e 100644 --- a/README.md +++ b/README.md @@ -196,6 +196,9 @@ Miri adds its own set of `-Z` flags: is popped from a borrow stack (which is where the tag becomes invalid and any future use of it will error). This helps you in finding out why UB is happening and where in your code would be a good place to look for it. +* `-Zmiri-track-call-id=` shows a backtrace when the given call id is + assigned to a stack frame. This helps in debugging UB related to Stacked + Borrows "protectors". [alignment-false-positives]: https://github.com/rust-lang/miri/issues/1074 diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 41490531a78b..f22f19845c6c 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -172,6 +172,7 @@ fn main() { let mut ignore_leaks = false; let mut seed: Option = None; let mut tracked_pointer_tag: Option = None; + let mut tracked_call_id: Option = None; let mut tracked_alloc_id: Option = None; let mut rustc_args = vec![]; let mut crate_args = vec![]; @@ -233,26 +234,38 @@ fn main() { .push(arg.strip_prefix("-Zmiri-env-exclude=").unwrap().to_owned()); } arg if arg.starts_with("-Zmiri-track-pointer-tag=") => { - let id: u64 = match arg.strip_prefix("-Zmiri-track-pointer-tag=").unwrap().parse() - { + let id: u64 = match arg.strip_prefix("-Zmiri-track-pointer-tag=").unwrap().parse() { Ok(id) => id, Err(err) => panic!( - "-Zmiri-track-pointer-tag requires a valid `u64` as the argument: {}", + "-Zmiri-track-pointer-tag requires a valid `u64` argument: {}", err ), }; if let Some(id) = miri::PtrId::new(id) { tracked_pointer_tag = Some(id); } else { - panic!("-Zmiri-track-pointer-tag must be a nonzero id"); + panic!("-Zmiri-track-pointer-tag requires a nonzero argument"); + } + } + arg if arg.starts_with("-Zmiri-track-call-id=") => { + let id: u64 = match arg.strip_prefix("-Zmiri-track-call-id=").unwrap().parse() { + Ok(id) => id, + Err(err) => panic!( + "-Zmiri-track-call-id requires a valid `u64` argument: {}", + err + ), + }; + if let Some(id) = miri::CallId::new(id) { + tracked_call_id = Some(id); + } else { + panic!("-Zmiri-track-call-id requires a nonzero argument"); } } arg if arg.starts_with("-Zmiri-track-alloc-id=") => { - let id: u64 = match arg.strip_prefix("-Zmiri-track-alloc-id=").unwrap().parse() - { + let id: u64 = match arg.strip_prefix("-Zmiri-track-alloc-id=").unwrap().parse() { Ok(id) => id, Err(err) => panic!( - "-Zmiri-track-alloc-id requires a valid `u64` as the argument: {}", + "-Zmiri-track-alloc-id requires a valid `u64` argument: {}", err ), }; @@ -278,6 +291,7 @@ fn main() { seed, args: crate_args, tracked_pointer_tag, + tracked_call_id, tracked_alloc_id, }; run_compiler(rustc_args, &mut MiriCompilerCalls { miri_config }) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 2d8b1248dcf4..8fdf039ce8e6 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -40,7 +40,8 @@ impl MachineStopType for TerminationInfo {} /// Miri specific diagnostics pub enum NonHaltingDiagnostic { - PoppedTrackedPointerTag(Item), + PoppedPointerTag(Item), + CreatedCallId(CallId), CreatedAlloc(AllocId), FreedAlloc(AllocId), } @@ -204,8 +205,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx for e in diagnostics.borrow_mut().drain(..) { use NonHaltingDiagnostic::*; let msg = match e { - PoppedTrackedPointerTag(item) => + PoppedPointerTag(item) => format!("popped tracked tag for item {:?}", item), + CreatedCallId(id) => + format!("function call with id {}", id), CreatedAlloc(AllocId(id)) => format!("created allocation with id {}", id), FreedAlloc(AllocId(id)) => diff --git a/src/eval.rs b/src/eval.rs index 56d6f3ed3c5b..ee429dd3143e 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -31,8 +31,10 @@ pub struct MiriConfig { pub args: Vec, /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`). pub seed: Option, - /// The stacked borrow id to report about + /// The stacked borrows pointer id to report about pub tracked_pointer_tag: Option, + /// The stacked borrows call ID to report about + pub tracked_call_id: Option, /// The allocation id to report about. pub tracked_alloc_id: Option, } @@ -49,6 +51,7 @@ impl Default for MiriConfig { args: vec![], seed: None, tracked_pointer_tag: None, + tracked_call_id: None, tracked_alloc_id: None, } } @@ -74,6 +77,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.stacked_borrows, config.tracked_pointer_tag, + config.tracked_call_id, config.tracked_alloc_id, config.check_alignment, ), diff --git a/src/lib.rs b/src/lib.rs index fa357eb9b134..816917081a8c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,7 +65,7 @@ pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ - EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, Stack, Stacks, Tag, + EvalContextExt as StackedBorEvalContextExt, Item, Permission, CallId, PtrId, Stack, Stacks, Tag, }; pub use crate::thread::{ EvalContextExt as ThreadsEvalContextExt, SchedulingAction, ThreadId, ThreadManager, ThreadState, diff --git a/src/machine.rs b/src/machine.rs index 6233222c004d..f23d8833bd82 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -129,11 +129,12 @@ impl MemoryExtra { rng: StdRng, stacked_borrows: bool, tracked_pointer_tag: Option, + tracked_call_id: Option, tracked_alloc_id: Option, check_alignment: bool, ) -> Self { let stacked_borrows = if stacked_borrows { - Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(tracked_pointer_tag)))) + Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(tracked_pointer_tag, tracked_call_id)))) } else { None }; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 03140c867b2d..3c263670bc7f 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -104,8 +104,10 @@ pub struct GlobalState { next_call_id: CallId, /// Those call IDs corresponding to functions that are still running. active_calls: FxHashSet, - /// The id to trace in this execution run + /// The pointer id to trace tracked_pointer_tag: Option, + /// The call id to trace + tracked_call_id: Option, } /// Memory extra state gives us interior mutable access to the global state. pub type MemoryExtra = Rc>; @@ -153,13 +155,14 @@ impl fmt::Display for RefKind { /// Utilities for initialization and ID generation impl GlobalState { - pub fn new(tracked_pointer_tag: Option) -> Self { + pub fn new(tracked_pointer_tag: Option, tracked_call_id: Option) -> Self { GlobalState { next_ptr_id: NonZeroU64::new(1).unwrap(), base_ptr_ids: FxHashMap::default(), next_call_id: NonZeroU64::new(1).unwrap(), active_calls: FxHashSet::default(), tracked_pointer_tag, + tracked_call_id, } } @@ -172,6 +175,9 @@ impl GlobalState { pub fn new_call(&mut self) -> CallId { let id = self.next_call_id; trace!("new_call: Assigning ID {}", id); + if Some(id) == self.tracked_call_id { + register_diagnostic(NonHaltingDiagnostic::CreatedCallId(id)); + } assert!(self.active_calls.insert(id)); self.next_call_id = NonZeroU64::new(id.get() + 1).unwrap(); id @@ -277,7 +283,7 @@ impl<'tcx> Stack { fn check_protector(item: &Item, tag: Option, global: &GlobalState) -> InterpResult<'tcx> { if let Tag::Tagged(id) = item.tag { if Some(id) == global.tracked_pointer_tag { - register_diagnostic(NonHaltingDiagnostic::PoppedTrackedPointerTag(item.clone())); + register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag(item.clone())); } } if let Some(call) = item.protector { From 6ca67a346bcbef6e996d9ea1b313bd4363d57adc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Jul 2020 10:37:29 +0200 Subject: [PATCH 2157/5092] rustup --- rust-version | 2 +- tests/run-pass/float.rs | 2 +- tests/run-pass/track-caller-attribute.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 159f752cc0df..e14dd73c70fe 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7750c3d46bc19784adb1ee6e37a5ec7e4cd7e772 +9491f18c5de3ff1c4bf9c3fdacf52d9859e26f7c diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index 3347b0a07c26..0b89f11b0609 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -1,4 +1,4 @@ -#![feature(track_caller, stmt_expr_attributes)] +#![feature(stmt_expr_attributes)] use std::fmt::Debug; // Helper function to avoid promotion so that this tests "run-time" casts, not CTFE. diff --git a/tests/run-pass/track-caller-attribute.rs b/tests/run-pass/track-caller-attribute.rs index f6797c24ebec..be655703daa0 100644 --- a/tests/run-pass/track-caller-attribute.rs +++ b/tests/run-pass/track-caller-attribute.rs @@ -1,4 +1,4 @@ -#![feature(track_caller, core_intrinsics)] +#![feature(core_intrinsics)] use std::panic::Location; From c5b324b031c1152c558737928cb345d07a1e5b82 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Thu, 2 Jul 2020 20:00:27 +0100 Subject: [PATCH 2158/5092] Remove likely and unlikely from intrinsics shim They are now implemented in MIR interpreter by rust-lang/rust#73778 --- src/shims/intrinsics.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 015d9edc11b7..68f67a1ed98d 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -523,16 +523,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[_] = check_arg_count(args)?; } - #[rustfmt::skip] - | "likely" - | "unlikely" - => { - // These just return their argument - let &[b] = check_arg_count(args)?; - let b = this.read_immediate(b)?; - this.write_immediate(*b, dest)?; - } - "try" => return this.handle_try(args, dest, ret), name => throw_unsup_format!("unimplemented intrinsic: {}", name), From e310e2f0b925f24572b188eee18935767480517a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 3 Jul 2020 11:18:44 +0200 Subject: [PATCH 2159/5092] set --target when building miri This helps cargo tell apart `./miri` builds and `cargo check` (e.g. through rust-analyzer). See https://github.com/rust-lang/cargo/issues/8440. --- miri | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/miri b/miri index 237a53efb1ad..37e87ec79861 100755 --- a/miri +++ b/miri @@ -94,12 +94,12 @@ COMMAND="$1" # . case "$COMMAND" in *-debug) - CARGO_INSTALL_FLAGS="--debug $CARGO_EXTRA_FLAGS" - CARGO_BUILD_FLAGS="$CARGO_EXTRA_FLAGS" + CARGO_INSTALL_FLAGS="--target $TARGET --debug $CARGO_EXTRA_FLAGS" + CARGO_BUILD_FLAGS="--target $TARGET $CARGO_EXTRA_FLAGS" ;; *) - CARGO_INSTALL_FLAGS="$CARGO_EXTRA_FLAGS" - CARGO_BUILD_FLAGS="--release $CARGO_EXTRA_FLAGS" + CARGO_INSTALL_FLAGS="--target $TARGET $CARGO_EXTRA_FLAGS" + CARGO_BUILD_FLAGS="--target $TARGET --release $CARGO_EXTRA_FLAGS" ;; esac From ab65cb3c6779f1d59ea2022c4d9d6effca2c614d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Jul 2020 20:01:12 +0200 Subject: [PATCH 2160/5092] support relative XARGO_RUST_SRC --- cargo-miri/bin.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 197552a4b126..68f25b411a9d 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -257,7 +257,10 @@ fn setup(subcommand: MiriCommand) { // Determine where the rust sources are located. `XARGO_RUST_SRC` env var trumps everything. let rust_src = match std::env::var_os("XARGO_RUST_SRC") { - Some(val) => PathBuf::from(val), + Some(val) => { + let val = PathBuf::from(val); + val.canonicalize().unwrap_or(val) + } None => { // Check for `rust-src` rustup component. let sysroot = miri() From 28b44d970c0b58a7e4d683580ecee4bf9c8cb073 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Jul 2020 12:53:00 +0200 Subject: [PATCH 2161/5092] test validation of uninit memory (used to ICE) --- .../validity/invalid_bool_uninit.rs | 10 + .../validity/invalid_char_uninit.rs | 10 + .../invalid_enum_tag_256variants_uninit.rs | 270 ++++++++++++++++++ .../validity/invalid_fnptr_uninit.rs | 10 + 4 files changed, 300 insertions(+) create mode 100644 tests/compile-fail/validity/invalid_bool_uninit.rs create mode 100644 tests/compile-fail/validity/invalid_char_uninit.rs create mode 100644 tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs create mode 100644 tests/compile-fail/validity/invalid_fnptr_uninit.rs diff --git a/tests/compile-fail/validity/invalid_bool_uninit.rs b/tests/compile-fail/validity/invalid_bool_uninit.rs new file mode 100644 index 000000000000..89b57b2d50d1 --- /dev/null +++ b/tests/compile-fail/validity/invalid_bool_uninit.rs @@ -0,0 +1,10 @@ +#![allow(invalid_value)] + +union MyUninit { + init: (), + uninit: bool, +} + +fn main() { + let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR encountered uninitialized bytes, but expected a boolean +} diff --git a/tests/compile-fail/validity/invalid_char_uninit.rs b/tests/compile-fail/validity/invalid_char_uninit.rs new file mode 100644 index 000000000000..34798dfbc659 --- /dev/null +++ b/tests/compile-fail/validity/invalid_char_uninit.rs @@ -0,0 +1,10 @@ +#![allow(invalid_value)] + +union MyUninit { + init: (), + uninit: char, +} + +fn main() { + let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) +} diff --git a/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs b/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs new file mode 100644 index 000000000000..c0f53d72a295 --- /dev/null +++ b/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs @@ -0,0 +1,270 @@ +#![allow(unused, deprecated, invalid_value)] + +#[derive(Copy, Clone)] +enum A { + A0, + A1, + A2, + A3, + A4, + A5, + A6, + A7, + A8, + A9, + A10, + A11, + A12, + A13, + A14, + A15, + A16, + A17, + A18, + A19, + A20, + A21, + A22, + A23, + A24, + A25, + A26, + A27, + A28, + A29, + A30, + A31, + A32, + A33, + A34, + A35, + A36, + A37, + A38, + A39, + A40, + A41, + A42, + A43, + A44, + A45, + A46, + A47, + A48, + A49, + A50, + A51, + A52, + A53, + A54, + A55, + A56, + A57, + A58, + A59, + A60, + A61, + A62, + A63, + A64, + A65, + A66, + A67, + A68, + A69, + A70, + A71, + A72, + A73, + A74, + A75, + A76, + A77, + A78, + A79, + A80, + A81, + A82, + A83, + A84, + A85, + A86, + A87, + A88, + A89, + A90, + A91, + A92, + A93, + A94, + A95, + A96, + A97, + A98, + A99, + A100, + A101, + A102, + A103, + A104, + A105, + A106, + A107, + A108, + A109, + A110, + A111, + A112, + A113, + A114, + A115, + A116, + A117, + A118, + A119, + A120, + A121, + A122, + A123, + A124, + A125, + A126, + A127, + A128, + A129, + A130, + A131, + A132, + A133, + A134, + A135, + A136, + A137, + A138, + A139, + A140, + A141, + A142, + A143, + A144, + A145, + A146, + A147, + A148, + A149, + A150, + A151, + A152, + A153, + A154, + A155, + A156, + A157, + A158, + A159, + A160, + A161, + A162, + A163, + A164, + A165, + A166, + A167, + A168, + A169, + A170, + A171, + A172, + A173, + A174, + A175, + A176, + A177, + A178, + A179, + A180, + A181, + A182, + A183, + A184, + A185, + A186, + A187, + A188, + A189, + A190, + A191, + A192, + A193, + A194, + A195, + A196, + A197, + A198, + A199, + A200, + A201, + A202, + A203, + A204, + A205, + A206, + A207, + A208, + A209, + A210, + A211, + A212, + A213, + A214, + A215, + A216, + A217, + A218, + A219, + A220, + A221, + A222, + A223, + A224, + A225, + A226, + A227, + A228, + A229, + A230, + A231, + A232, + A233, + A234, + A235, + A236, + A237, + A238, + A239, + A240, + A241, + A242, + A243, + A244, + A245, + A246, + A247, + A248, + A249, + A250, + A251, + A252, + A253, + A254, + A255, +} + +union MyUninit { + init: (), + uninit: A, +} + +fn main() { + let _a = unsafe { MyUninit { init: () }.uninit }; //~ ERROR encountered uninitialized bytes, but expected a valid enum tag +} diff --git a/tests/compile-fail/validity/invalid_fnptr_uninit.rs b/tests/compile-fail/validity/invalid_fnptr_uninit.rs new file mode 100644 index 000000000000..dbd6711dc65a --- /dev/null +++ b/tests/compile-fail/validity/invalid_fnptr_uninit.rs @@ -0,0 +1,10 @@ +#![allow(invalid_value)] + +union MyUninit { + init: (), + uninit: fn(), +} + +fn main() { + let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR encountered uninitialized bytes, but expected a function pointer +} From 6c2521f54f22254fe7fdfea4d22b7abbf243e2cf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Jul 2020 13:43:20 +0200 Subject: [PATCH 2162/5092] adjust error messages --- tests/compile-fail/validity/invalid_enum_tag.rs | 2 +- .../validity/invalid_enum_tag_256variants_uninit.rs | 2 +- tests/compile-fail/validity/transmute_through_ptr.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/compile-fail/validity/invalid_enum_tag.rs b/tests/compile-fail/validity/invalid_enum_tag.rs index 897bfa90a702..39e8eed683a3 100644 --- a/tests/compile-fail/validity/invalid_enum_tag.rs +++ b/tests/compile-fail/validity/invalid_enum_tag.rs @@ -4,5 +4,5 @@ pub enum Foo { } fn main() { - let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR encountered 0x0000002a, but expected a valid enum tag + let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR encountered 0x0000002a at ., but expected a valid enum tag } diff --git a/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs b/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs index c0f53d72a295..74e24491e610 100644 --- a/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs +++ b/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs @@ -266,5 +266,5 @@ union MyUninit { } fn main() { - let _a = unsafe { MyUninit { init: () }.uninit }; //~ ERROR encountered uninitialized bytes, but expected a valid enum tag + let _a = unsafe { MyUninit { init: () }.uninit }; //~ ERROR encountered uninitialized bytes at ., but expected a valid enum tag } diff --git a/tests/compile-fail/validity/transmute_through_ptr.rs b/tests/compile-fail/validity/transmute_through_ptr.rs index 1d5cf16aa5ea..6a88fdaea1ee 100644 --- a/tests/compile-fail/validity/transmute_through_ptr.rs +++ b/tests/compile-fail/validity/transmute_through_ptr.rs @@ -10,5 +10,5 @@ fn main() { let mut x = Bool::True; evil(&mut x); let _y = x; // reading this ought to be enough to trigger validation - //~^ ERROR encountered 0x0000002c, but expected a valid enum tag + //~^ ERROR encountered 0x0000002c at ., but expected a valid enum tag } From 04019eec3cc17684fff1790b0d15a5df89a9aa79 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 7 Jul 2020 22:57:58 +0200 Subject: [PATCH 2163/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index e14dd73c70fe..e339c77f1ac3 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9491f18c5de3ff1c4bf9c3fdacf52d9859e26f7c +e1beee4992ad4b235fc700bf7af1ee86f894ea53 From dcb0f6309e93fd302952c1e8a7fb890fd32a5548 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 8 Jul 2020 11:05:22 +0200 Subject: [PATCH 2164/5092] we cannot track all machine memory any more due to int-ptr-casts --- rust-version | 2 +- src/machine.rs | 12 ++++++++---- src/shims/env.rs | 4 ++-- src/stacked_borrows.rs | 6 +++--- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/rust-version b/rust-version index e339c77f1ac3..f1a465c7d624 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e1beee4992ad4b235fc700bf7af1ee86f894ea53 +8ac1525e091d3db28e67adcbbd6db1e1deaa37fb diff --git a/src/machine.rs b/src/machine.rs index f23d8833bd82..49d647838c9e 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -54,7 +54,7 @@ pub enum MiriMemoryKind { C, /// Windows `HeapAlloc` memory. WinHeap, - /// Memory for args, errno, extern statics and other parts of the machine-managed environment. + /// Memory for args, errno, and other parts of the machine-managed environment. /// This memory may leak. Machine, /// Memory for env vars. Separate from `Machine` because we clean it up and leak-check it. @@ -62,6 +62,9 @@ pub enum MiriMemoryKind { /// Globals copied from `tcx`. /// This memory may leak. Global, + /// Memory for extern statics. + /// This memory may leak. + ExternGlobal, } impl Into> for MiriMemoryKind { @@ -77,7 +80,7 @@ impl MayLeak for MiriMemoryKind { use self::MiriMemoryKind::*; match self { Rust | C | WinHeap | Env => false, - Machine | Global => true, + Machine | Global | ExternGlobal => true, } } } @@ -92,6 +95,7 @@ impl fmt::Display for MiriMemoryKind { Machine => write!(f, "machine-managed memory"), Env => write!(f, "environment variable"), Global => write!(f, "global"), + ExternGlobal => write!(f, "extern global"), } } } @@ -171,7 +175,7 @@ impl MemoryExtra { // "__cxa_thread_atexit_impl" // This should be all-zero, pointer-sized. let layout = this.machine.layouts.usize; - let place = this.allocate(layout, MiriMemoryKind::Machine.into()); + let place = this.allocate(layout, MiriMemoryKind::ExternGlobal.into()); this.write_scalar(Scalar::from_machine_usize(0, this), place.into())?; Self::add_extern_static(this, "__cxa_thread_atexit_impl", place.ptr); // "environ" @@ -181,7 +185,7 @@ impl MemoryExtra { // "_tls_used" // This is some obscure hack that is part of the Windows TLS story. It's a `u8`. let layout = this.machine.layouts.u8; - let place = this.allocate(layout, MiriMemoryKind::Machine.into()); + let place = this.allocate(layout, MiriMemoryKind::ExternGlobal.into()); this.write_scalar(Scalar::from_u8(0), place.into())?; Self::add_extern_static(this, "_tls_used", place.ptr); } diff --git a/src/shims/env.rs b/src/shims/env.rs index 8459aa3241c8..4a2bec28bd17 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -383,9 +383,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.memory.deallocate(this.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Env.into())?; } else { // No `environ` allocated yet, let's do that. - // This is memory backing an extern static, hence `Machine`, not `Env`. + // This is memory backing an extern static, hence `ExternGlobal`, not `Env`. let layout = this.machine.layouts.usize; - let place = this.allocate(layout, MiriMemoryKind::Machine.into()); + let place = this.allocate(layout, MiriMemoryKind::ExternGlobal.into()); this.machine.env_vars.environ = Some(place); } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 3c263670bc7f..6942acc5e2b0 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -466,13 +466,13 @@ impl Stacks { // everything else off the stack, invalidating all previous pointers, // and in particular, *all* raw pointers. MemoryKind::Stack => (Tag::Tagged(extra.borrow_mut().new_ptr()), Permission::Unique), - // Global memory can be referenced by global pointers from `tcx`. + // `Global` memory can be referenced by global pointers from `tcx`. // Thus we call `global_base_ptr` such that the global pointers get the same tag // as what we use here. - // `Machine` is used for extern statics, and thus must also be listed here. + // `ExternGlobal` is used for extern statics, and thus must also be listed here. // `Env` we list because we can get away with precise tracking there. // The base pointer is not unique, so the base permission is `SharedReadWrite`. - MemoryKind::Machine(MiriMemoryKind::Global | MiriMemoryKind::Machine | MiriMemoryKind::Env) => + MemoryKind::Machine(MiriMemoryKind::Global | MiriMemoryKind::ExternGlobal | MiriMemoryKind::Env) => (extra.borrow_mut().global_base_ptr(id), Permission::SharedReadWrite), // Everything else we handle entirely untagged for now. // FIXME: experiment with more precise tracking. From 7d9d74e06505b48d2894a24ccbe716ffa931bd2b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 9 Jul 2020 08:59:28 +0200 Subject: [PATCH 2165/5092] on Windows, strip the '\\?\' prefix from the canonical path --- cargo-miri/bin.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 68f25b411a9d..e2f32cb0a538 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -258,8 +258,20 @@ fn setup(subcommand: MiriCommand) { // Determine where the rust sources are located. `XARGO_RUST_SRC` env var trumps everything. let rust_src = match std::env::var_os("XARGO_RUST_SRC") { Some(val) => { - let val = PathBuf::from(val); - val.canonicalize().unwrap_or(val) + let path = PathBuf::from(val); + let path = path.canonicalize().unwrap_or(path); + + // On Windows, this produces a path starting with `\\?\`, which xargo cannot deal with. + // Strip that prefix; the resulting path should still be valid. + #[cfg(windows)] + let path = { + let str = path.into_os_string().into_string() + .expect("non-unicode paths are currently not supported"); + let str = str.strip_prefix(r"\\?\").map(String::from).unwrap_or(str); + PathBuf::from(str) + }; + + path } None => { // Check for `rust-src` rustup component. From ee056ccf7b2341ae72af4d6be7acad6e80155301 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 9 Jul 2020 12:45:35 +0200 Subject: [PATCH 2166/5092] better way to get an absolute path --- cargo-miri/bin.rs | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index e2f32cb0a538..852dbd7d3ea2 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -259,19 +259,8 @@ fn setup(subcommand: MiriCommand) { let rust_src = match std::env::var_os("XARGO_RUST_SRC") { Some(val) => { let path = PathBuf::from(val); - let path = path.canonicalize().unwrap_or(path); - - // On Windows, this produces a path starting with `\\?\`, which xargo cannot deal with. - // Strip that prefix; the resulting path should still be valid. - #[cfg(windows)] - let path = { - let str = path.into_os_string().into_string() - .expect("non-unicode paths are currently not supported"); - let str = str.strip_prefix(r"\\?\").map(String::from).unwrap_or(str); - PathBuf::from(str) - }; - - path + // Make path absolute, but not via `canonicalize` (which does not work very well on Windows). + env::current_dir().unwrap().join(path) } None => { // Check for `rust-src` rustup component. From 2fbc4aa7ca8d53cc4613db954886e04b79d6804e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 9 Jul 2020 13:02:42 +0200 Subject: [PATCH 2167/5092] Cleanup code Co-authored-by: Aleksey Kladov --- cargo-miri/bin.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 852dbd7d3ea2..6d4c51256feb 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -257,8 +257,7 @@ fn setup(subcommand: MiriCommand) { // Determine where the rust sources are located. `XARGO_RUST_SRC` env var trumps everything. let rust_src = match std::env::var_os("XARGO_RUST_SRC") { - Some(val) => { - let path = PathBuf::from(val); + Some(path) => { // Make path absolute, but not via `canonicalize` (which does not work very well on Windows). env::current_dir().unwrap().join(path) } From 22e7a6263b457aa6b3402aaebbf98f47da92c03d Mon Sep 17 00:00:00 2001 From: Justus K Date: Thu, 9 Jul 2020 13:16:38 +0200 Subject: [PATCH 2168/5092] Early exit if program doesn't contain a main fn --- src/bin/miri.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index f22f19845c6c..73e52af4ec51 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -5,6 +5,7 @@ extern crate rustc_driver; extern crate rustc_hir; extern crate rustc_interface; extern crate rustc_session; +extern crate rustc_errors; use std::convert::TryFrom; use std::env; @@ -13,7 +14,8 @@ use std::str::FromStr; use hex::FromHexError; use log::debug; -use rustc_session::CtfeBacktrace; +use rustc_session::{CtfeBacktrace, config::ErrorOutputType}; +use rustc_errors::emitter::{HumanReadableErrorType, ColorConfig}; use rustc_driver::Compilation; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::ty::TyCtxt; @@ -32,7 +34,12 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { init_late_loggers(tcx); - let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!"); + let (entry_def_id, _) = if let Some((entry_def, x)) = tcx.entry_fn(LOCAL_CRATE) { + (entry_def, x) + } else { + let output_ty = ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto)); + rustc_session::early_error(output_ty, "miri can only run programs that have a main function"); + }; let mut config = self.miri_config.clone(); // Add filename to `miri` arguments. From c93fc933bd54be1f5237c5411bc70cbc0176cf39 Mon Sep 17 00:00:00 2001 From: Justus K Date: Thu, 9 Jul 2020 14:08:45 +0200 Subject: [PATCH 2169/5092] Add ui test for early exiting if no main --- tests/run-pass/no_main.rs | 1 + tests/run-pass/no_main.stderr | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 tests/run-pass/no_main.rs create mode 100644 tests/run-pass/no_main.stderr diff --git a/tests/run-pass/no_main.rs b/tests/run-pass/no_main.rs new file mode 100644 index 000000000000..1ae9a6a35c25 --- /dev/null +++ b/tests/run-pass/no_main.rs @@ -0,0 +1 @@ +#![no_main] diff --git a/tests/run-pass/no_main.stderr b/tests/run-pass/no_main.stderr new file mode 100644 index 000000000000..52591a8d6da3 --- /dev/null +++ b/tests/run-pass/no_main.stderr @@ -0,0 +1,2 @@ +error: miri can only run programs that have a main function + From d23e245f38f556e833ca7fc4f616b78e791b923b Mon Sep 17 00:00:00 2001 From: Justus K Date: Thu, 9 Jul 2020 17:21:09 +0200 Subject: [PATCH 2170/5092] Move no_main test to compile-fail --- tests/compile-fail/no_main.rs | 2 ++ tests/run-pass/no_main.rs | 1 - tests/run-pass/no_main.stderr | 2 -- 3 files changed, 2 insertions(+), 3 deletions(-) create mode 100644 tests/compile-fail/no_main.rs delete mode 100644 tests/run-pass/no_main.rs delete mode 100644 tests/run-pass/no_main.stderr diff --git a/tests/compile-fail/no_main.rs b/tests/compile-fail/no_main.rs new file mode 100644 index 000000000000..a9e8e816828c --- /dev/null +++ b/tests/compile-fail/no_main.rs @@ -0,0 +1,2 @@ +// error-pattern: miri can only run programs that have a main function +#![no_main] diff --git a/tests/run-pass/no_main.rs b/tests/run-pass/no_main.rs deleted file mode 100644 index 1ae9a6a35c25..000000000000 --- a/tests/run-pass/no_main.rs +++ /dev/null @@ -1 +0,0 @@ -#![no_main] diff --git a/tests/run-pass/no_main.stderr b/tests/run-pass/no_main.stderr deleted file mode 100644 index 52591a8d6da3..000000000000 --- a/tests/run-pass/no_main.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: miri can only run programs that have a main function - From 2602e951c0301e6502e835b1842e3e144d10c306 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Thu, 28 May 2020 11:24:47 +0530 Subject: [PATCH 2171/5092] Handle `read`s on STDIN --- src/shims/posix/foreign_items.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index bbda40def620..8efe8f0ed3fd 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -67,7 +67,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.read_scalar(buf)?.not_undef()?; let count = this.read_scalar(count)?.to_machine_usize(this)?; let result = if fd == 0 { - throw_unsup_format!("reading from stdin is not implemented") + use std::io::{self, Read}; + + let mut buffer = String::new(); + let res = io::stdin().read_to_string(&mut buffer); + + match res { + Ok(bytes) => { + this.memory.write_bytes(buf, buffer.bytes())?; + i64::try_from(bytes).unwrap() + }, + Err(_) => -1, + } } else if fd == 1 || fd == 2 { throw_unsup_format!("cannot read from stdout/stderr") } else { From 15466e00b05c9167687e75582568c3d699e22e62 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 Jul 2020 11:07:17 +0200 Subject: [PATCH 2172/5092] go back to using canonicalize() --- cargo-miri/bin.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 6d4c51256feb..33a1124aaba0 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -10,7 +10,7 @@ use std::process::Command; use rustc_version::VersionMeta; -const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 20); +const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 21); const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and tests in Miri @@ -258,8 +258,9 @@ fn setup(subcommand: MiriCommand) { // Determine where the rust sources are located. `XARGO_RUST_SRC` env var trumps everything. let rust_src = match std::env::var_os("XARGO_RUST_SRC") { Some(path) => { - // Make path absolute, but not via `canonicalize` (which does not work very well on Windows). - env::current_dir().unwrap().join(path) + let path = PathBuf::from(path); + // Make path absolute if possible. + path.canonicalize().unwrap_or(path) } None => { // Check for `rust-src` rustup component. From f68bba9906c85a508531daaa1f64da723185b6c4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 Jul 2020 20:56:47 +0200 Subject: [PATCH 2173/5092] test casting a dangling ptr back from an int --- tests/run-pass/intptrcast.rs | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/tests/run-pass/intptrcast.rs b/tests/run-pass/intptrcast.rs index c2711f9845d0..6e72d30d4123 100644 --- a/tests/run-pass/intptrcast.rs +++ b/tests/run-pass/intptrcast.rs @@ -12,6 +12,20 @@ fn cast() { assert_eq!(z, y % 256); } +/// Test usize->ptr cast for dangling and OOB address. +/// That is safe, and thus has to work. +fn cast_dangling() { + let b = Box::new(0); + let x = &*b as *const i32 as usize; + drop(b); + let _val = x as *const i32; + + let b = Box::new(0); + let mut x = &*b as *const i32 as usize; + x += 0x100; + let _val = x as *const i32; +} + fn format() { // Pointer string formatting! We can't check the output as it changes when libstd changes, // but we can make sure Miri does not error. @@ -47,8 +61,7 @@ fn ptr_eq_dangling() { drop(b); let b = Box::new(0); let y = &*b as *const i32; // different allocation - // We cannot compare these even though both are inbounds -- they *could* be - // equal if memory was reused. + // They *could* be equal if memory was reused, but probably are not. assert!(x != y); } @@ -57,27 +70,27 @@ fn ptr_eq_out_of_bounds() { let x = (&*b as *const i32).wrapping_sub(0x800); // out-of-bounds let b = Box::new(0); let y = &*b as *const i32; // different allocation - // We cannot compare these even though both allocations are live -- they *could* be - // equal (with the right base addresses). + // They *could* be equal (with the right base addresses), but probably are not. assert!(x != y); } fn ptr_eq_out_of_bounds_null() { let b = Box::new(0); let x = (&*b as *const i32).wrapping_sub(0x800); // out-of-bounds - // We cannot compare this with NULL. After all, this *could* be NULL (with the right base address). + // This *could* be NULL (with the right base address), but probably is not. assert!(x != std::ptr::null()); } fn ptr_eq_integer() { let b = Box::new(0); let x = &*b as *const i32; - // We cannot compare this with a non-NULL integer. After all, these *could* be equal (with the right base address). + // These *could* be equal (with the right base address), but probably are not. assert!(x != 64 as *const i32); } fn main() { cast(); + cast_dangling(); format(); transmute(); ptr_bitops1(); From 74ff4f805a2f6f8f098f1e3323bc57277cfeb2fa Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Sun, 12 Jul 2020 20:27:19 +0530 Subject: [PATCH 2174/5092] Read into buffer of fixed size for `read`s to STDIN Also: - Check isolation is disabled. - Add FIXMEs to set error numbers in `read` and `write`. --- src/shims/posix/foreign_items.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 8efe8f0ed3fd..200d50433b3e 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -69,14 +69,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = if fd == 0 { use std::io::{self, Read}; - let mut buffer = String::new(); - let res = io::stdin().read_to_string(&mut buffer); + this.check_no_isolation("read")?; + + let mut buffer = vec![0; count as usize]; + let res = io::stdin() + .read(&mut buffer) + // `Stdin::read` never returns a value larger + // than `count`, so this cannot fail. + .map(|c| i64::try_from(c).unwrap()); match res { Ok(bytes) => { - this.memory.write_bytes(buf, buffer.bytes())?; + this.memory.write_bytes(buf, buffer)?; i64::try_from(bytes).unwrap() }, + // FIXME: set errno to appropriate value Err(_) => -1, } } else if fd == 1 || fd == 2 { @@ -114,6 +121,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; match res { Ok(n) => i64::try_from(n).unwrap(), + // FIXME: set errno to appropriate value Err(_) => -1, } } else { From ce5ed69eac64dc581debf39c0ec4322126ff55f0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 Jul 2020 08:42:15 +0200 Subject: [PATCH 2175/5092] rustup; fix Windows TLS --- rust-version | 2 +- src/shims/tls.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index f1a465c7d624..c8c4d489e1d6 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8ac1525e091d3db28e67adcbbd6db1e1deaa37fb +567ad7455d5f25f6b38d2fded1cb621e0c34a48b diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 0cd9ef056505..d2d5522c4023 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -236,7 +236,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'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. - let thread_callback = this.eval_path_scalar(&["std", "sys", "windows", "thread_local", "p_thread_callback"])?; + let thread_callback = this.eval_path_scalar(&["std", "sys", "windows", "thread_local_key", "p_thread_callback"])?; let thread_callback = this.memory.get_fn(thread_callback.not_undef()?)?.as_instance()?; // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. From 6dbfb2d9dee84b29612527044fc308e6304cfbf2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 Jul 2020 10:09:28 +0200 Subject: [PATCH 2176/5092] make cfg(miri) greppable --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ab4d4c02db1e..e20c53b68dc5 100644 --- a/README.md +++ b/README.md @@ -94,9 +94,9 @@ Linux program, you can do `cargo miri run --target x86_64-unknown-linux-gnu`. This is particularly useful if you are using Windows, as the Linux target is much better supported than Windows targets. -When compiling code via `cargo miri`, the `miri` config flag is set. You can -use this to ignore test cases that fail under Miri because they do things Miri -does not support: +When compiling code via `cargo miri`, the `cfg(miri)` config flag is set. You +can use this to ignore test cases that fail under Miri because they do things +Miri does not support: ```rust #[test] From c28786d320048b81d2433689fac7ce5429292b46 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 16 Jul 2020 12:16:43 +0200 Subject: [PATCH 2177/5092] remove an unnecessary intermediate cast --- src/shims/posix/fs.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 87aa28120c28..7754c02744e6 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -461,9 +461,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { trace!("read: FD mapped to {:?}", file); - // This can never fail because `count` was capped to be smaller than - // `isize::MAX`. - let count = isize::try_from(count).unwrap(); // We want to read at most `count` bytes. We are sure that `count` is not negative // because it was a target's `usize`. Also we are sure that its smaller than // `usize::MAX` because it is a host's `isize`. From d617d615e4f310eadde6e3be1c1e970e9608bb81 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 17 Jul 2020 12:54:38 +0200 Subject: [PATCH 2178/5092] fix non-fatal diagnostics stacktraces --- src/diagnostics.rs | 101 +++++++++++++++++++++++++++++++++------------ src/eval.rs | 3 +- src/thread.rs | 3 ++ 3 files changed, 79 insertions(+), 28 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 8fdf039ce8e6..009f8aa29cec 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -3,7 +3,8 @@ use std::fmt; use log::trace; -use rustc_span::DUMMY_SP; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::{source_map::DUMMY_SP, Span}; use crate::*; @@ -116,7 +117,17 @@ pub fn report_error<'tcx, 'mir>( e.print_backtrace(); let msg = e.to_string(); - report_msg(ecx, &format!("{}: {}", title, msg), msg, helps, true); + report_msg(*ecx.tcx, /*error*/true, &format!("{}: {}", title, msg), msg, helps, &ecx.generate_stacktrace()); + + // Debug-dump all locals. + for (i, frame) in ecx.active_thread_stack().iter().enumerate() { + trace!("-------------------"); + trace!("Frame {}", i); + trace!(" return: {:?}", frame.return_place.map(|p| *p)); + for (i, local) in frame.locals.iter().enumerate() { + trace!(" local {}: {:?}", i, local.value); + } + } // Extra output to help debug specific issues. match e.kind { @@ -135,24 +146,21 @@ pub fn report_error<'tcx, 'mir>( None } -/// Report an error or note (depending on the `error` argument) at the current frame's current statement. +/// Report an error or note (depending on the `error` argument) with the given stacktrace. /// Also emits a full stacktrace of the interpreter stack. -fn report_msg<'tcx, 'mir>( - ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, +fn report_msg<'tcx>( + tcx: TyCtxt<'tcx>, + error: bool, title: &str, span_msg: String, mut helps: Vec, - error: bool, + stacktrace: &[FrameInfo<'tcx>], ) { - let span = if let Some(frame) = ecx.active_thread_stack().last() { - frame.current_source_info().unwrap().span - } else { - DUMMY_SP - }; + let span = stacktrace.first().map_or(DUMMY_SP, |fi| fi.span); let mut err = if error { - ecx.tcx.sess.struct_span_err(span, title) + tcx.sess.struct_span_err(span, title) } else { - ecx.tcx.sess.diagnostic().span_note_diag(span, title) + tcx.sess.diagnostic().span_note_diag(span, title) }; err.span_label(span, span_msg); if !helps.is_empty() { @@ -163,8 +171,7 @@ fn report_msg<'tcx, 'mir>( } } // Add backtrace - let frames = ecx.generate_stacktrace(); - for (idx, frame_info) in frames.iter().enumerate() { + for (idx, frame_info) in stacktrace.iter().enumerate() { let is_local = frame_info.instance.def_id().is_local(); // No span for non-local frames and the first frame (which is the error site). if is_local && idx > 0 { @@ -175,15 +182,6 @@ fn report_msg<'tcx, 'mir>( } err.emit(); - - for (i, frame) in ecx.active_thread_stack().iter().enumerate() { - trace!("-------------------"); - trace!("Frame {}", i); - trace!(" return: {:?}", frame.return_place.map(|p| *p)); - for (i, local) in frame.locals.iter().enumerate() { - trace!(" local {}: {:?}", i, local.value); - } - } } thread_local! { @@ -196,13 +194,62 @@ pub fn register_diagnostic(e: NonHaltingDiagnostic) { DIAGNOSTICS.with(|diagnostics| diagnostics.borrow_mut().push(e)); } +/// Remember enough about the topmost frame so that we can restore the stack +/// after a step was taken. +pub struct TopFrameInfo<'tcx> { + stack_size: usize, + instance: ty::Instance<'tcx>, + span: Span, +} + impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn preprocess_diagnostics(&self) -> TopFrameInfo<'tcx> { + // Ensure we have no lingering diagnostics. + DIAGNOSTICS.with(|diagnostics| assert!(diagnostics.borrow().is_empty())); + + let this = self.eval_context_ref(); + let frame = this.frame(); + + TopFrameInfo { + stack_size: this.active_thread_stack().len(), + instance: frame.instance, + span: frame.current_source_info().map_or(DUMMY_SP, |si| si.span), + } + } + /// Emit all diagnostics that were registed with `register_diagnostics` - fn process_diagnostics(&self) { + fn process_diagnostics(&self, info: TopFrameInfo<'tcx>) { let this = self.eval_context_ref(); DIAGNOSTICS.with(|diagnostics| { - for e in diagnostics.borrow_mut().drain(..) { + let mut diagnostics = diagnostics.borrow_mut(); + if diagnostics.is_empty() { + return; + } + // We need to fix up the stack trace, because the machine has already + // stepped to the next statement. + let mut stacktrace = this.generate_stacktrace(); + // Remove newly pushed frames. + while stacktrace.len() > info.stack_size { + stacktrace.remove(0); + } + // Add popped frame back. + if stacktrace.len() < info.stack_size { + assert!(stacktrace.len() == info.stack_size-1, "we should never pop more than one frame at once"); + let frame_info = FrameInfo { + instance: info.instance, + span: info.span, + lint_root: None, + }; + stacktrace.insert(0, frame_info); + } else { + // Adjust topmost frame. + stacktrace[0].span = info.span; + assert_eq!(stacktrace[0].instance, info.instance, "we should not pop and push a frame in one step"); + } + + // Show diagnostics. + for e in diagnostics.drain(..) { use NonHaltingDiagnostic::*; let msg = match e { PoppedPointerTag(item) => @@ -214,7 +261,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx FreedAlloc(AllocId(id)) => format!("freed allocation with id {}", id), }; - report_msg(this, "tracking was triggered", msg, vec![], false); + report_msg(*this.tcx, /*error*/false, "tracking was triggered", msg, vec![], &stacktrace); } }); } diff --git a/src/eval.rs b/src/eval.rs index ee429dd3143e..79ceb6be806e 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -212,7 +212,9 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> loop { match ecx.schedule()? { SchedulingAction::ExecuteStep => { + let info = ecx.preprocess_diagnostics(); assert!(ecx.step()?, "a terminated thread was scheduled for execution"); + ecx.process_diagnostics(info); } SchedulingAction::ExecuteTimeoutCallback => { assert!(ecx.machine.communicate, @@ -230,7 +232,6 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> break; } } - ecx.process_diagnostics(); } let return_code = ecx.read_scalar(ret_place.into())?.not_undef()?.to_machine_isize(&ecx)?; Ok(return_code) diff --git a/src/thread.rs b/src/thread.rs index 896f93ef1a3a..aee7d395ddfc 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -373,6 +373,9 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Change the active thread to some enabled thread. fn yield_active_thread(&mut self) { + // We do not immediately, as swapping out the current stack while execution a MIR statement + // could lead to all sorts of confusion. + // We should only switch stacks between steps. self.yield_active_thread = true; } From 545aa6019557ae2777233e1d8f6cbd8b6f7b3180 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 17 Jul 2020 13:39:25 +0200 Subject: [PATCH 2179/5092] fix typo Co-authored-by: Oliver Scherer --- src/thread.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/thread.rs b/src/thread.rs index aee7d395ddfc..42a4dbded58f 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -373,7 +373,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Change the active thread to some enabled thread. fn yield_active_thread(&mut self) { - // We do not immediately, as swapping out the current stack while execution a MIR statement + // We do not yield immediately, as swapping out the current stack while executing a MIR statement // could lead to all sorts of confusion. // We should only switch stacks between steps. self.yield_active_thread = true; From 4c1beb2e453cdd8f3678e399aaa60c2c02980348 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Fri, 17 Jul 2020 00:03:56 +0530 Subject: [PATCH 2180/5092] Ensure buffer for reading from Stdin is smaller than machine usize Also, set appropriate error code on failure --- src/shims/posix/foreign_items.rs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 200d50433b3e..81708e61b1ab 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -1,4 +1,5 @@ use std::convert::TryFrom; +use std::io::{self, Read, Write}; use log::trace; @@ -11,6 +12,7 @@ use shims::posix::fs::EvalContextExt as _; use shims::posix::sync::EvalContextExt as _; use shims::posix::thread::EvalContextExt as _; + impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn emulate_foreign_item_by_name( @@ -67,10 +69,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.read_scalar(buf)?.not_undef()?; let count = this.read_scalar(count)?.to_machine_usize(this)?; let result = if fd == 0 { - use std::io::{self, Read}; this.check_no_isolation("read")?; + // We cap the number of read bytes to the largest + // value that we are able to fit in both the + // host's and target's `isize`. This saves us from + // having to handle overflows later. + let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64); + // This can never fail because `count` was capped + // to be smaller than `isize::MAX`. + let count = isize::try_from(count).unwrap(); + + // We want to read at most `count` bytes. We are + // sure that `count` is not negative because it + // was a target's `usize`. Also we are sure that + // its smaller than `usize::MAX` because it is a + // host's `isize`. let mut buffer = vec![0; count as usize]; let res = io::stdin() .read(&mut buffer) @@ -83,8 +98,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.memory.write_bytes(buf, buffer)?; i64::try_from(bytes).unwrap() }, - // FIXME: set errno to appropriate value - Err(_) => -1, + Err(e) => { + this.set_last_error_from_io_error(e)?; + -1 + }, } } else if fd == 1 || fd == 2 { throw_unsup_format!("cannot read from stdout/stderr") @@ -103,7 +120,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("cannot write to stdin") } else if fd == 1 || fd == 2 { // stdout/stderr - use std::io::{self, Write}; let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(count))?; // We need to flush to make sure this actually appears on the screen From f4d1841811c260c96c71a41774d3cb61b62dad7f Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Sat, 18 Jul 2020 10:45:06 +0530 Subject: [PATCH 2181/5092] Remove unnecessary cast --- src/shims/posix/foreign_items.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 81708e61b1ab..e0ad0d8d4112 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -12,7 +12,6 @@ use shims::posix::fs::EvalContextExt as _; use shims::posix::sync::EvalContextExt as _; use shims::posix::thread::EvalContextExt as _; - impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn emulate_foreign_item_by_name( @@ -77,9 +76,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // host's and target's `isize`. This saves us from // having to handle overflows later. let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64); - // This can never fail because `count` was capped - // to be smaller than `isize::MAX`. - let count = isize::try_from(count).unwrap(); // We want to read at most `count` bytes. We are // sure that `count` is not negative because it From d1aee6965bca6d31d1d414e7174b40e89a326483 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Sat, 18 Jul 2020 12:48:26 +0200 Subject: [PATCH 2182/5092] Remove unreachable intrinsic --- src/shims/intrinsics.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 68f67a1ed98d..c44caed34f65 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -37,7 +37,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (dest, ret) = match ret { None => match intrinsic_name { "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), - "unreachable" => throw_ub!(Unreachable), _ => throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name), }, Some(p) => p, From cded9b7142b3b8d0e986d85e93ea502bd7a0d668 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 18 Jul 2020 17:58:16 +0200 Subject: [PATCH 2183/5092] set errno on stdout write failure --- src/shims/posix/foreign_items.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index e0ad0d8d4112..80611a18e4fc 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -133,8 +133,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; match res { Ok(n) => i64::try_from(n).unwrap(), - // FIXME: set errno to appropriate value - Err(_) => -1, + Err(e) => { + this.set_last_error_from_io_error(e)?; + -1 + } } } else { this.write(fd, buf, count)? From 7d6aec68878ae15044ec8f075a5bede15ae421d3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 Jul 2020 10:40:13 +0200 Subject: [PATCH 2184/5092] rustup --- rust-version | 2 +- src/helpers.rs | 4 ++-- src/shims/posix/fs.rs | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index c8c4d489e1d6..bfbf6b81b2e2 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -567ad7455d5f25f6b38d2fded1cb621e0c34a48b +4825e12fc9c79954aa0fe18f5521efa6c19c7539 diff --git a/src/helpers.rs b/src/helpers.rs index c1eaf4eb4865..473da84aeea3 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -92,14 +92,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function to get the `TyAndLayout` of a `libc` type fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> { let this = self.eval_context_mut(); - let ty = this.resolve_path(&["libc", name]).monomorphic_ty(*this.tcx); + let ty = this.resolve_path(&["libc", name]).ty(*this.tcx, ty::ParamEnv::reveal_all()); this.layout_of(ty) } /// Helper function to get the `TyAndLayout` of a `windows` type fn windows_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> { let this = self.eval_context_mut(); - let ty = this.resolve_path(&["std", "sys", "windows", "c", name]).monomorphic_ty(*this.tcx); + let ty = this.resolve_path(&["std", "sys", "windows", "c", name]).ty(*this.tcx, ty::ParamEnv::reveal_all()); this.layout_of(ty) } diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 7754c02744e6..a43e86dcc5b5 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -9,6 +9,7 @@ use log::trace; use rustc_data_structures::fx::FxHashMap; use rustc_target::abi::{Align, LayoutOf, Size}; +use rustc_middle::ty; use crate::*; use stacked_borrows::Tag; @@ -670,7 +671,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // function and `resolve_path` is returning the latter. let statx_ty = this .resolve_path(&["libc", "unix", "linux_like", "linux", "gnu", "statx"]) - .monomorphic_ty(*this.tcx); + .ty(*this.tcx, ty::ParamEnv::reveal_all()); let statxbuf_ty = this.tcx.mk_mut_ptr(statx_ty); let statxbuf_layout = this.layout_of(statxbuf_ty)?; let statxbuf_imm = ImmTy::from_scalar(statxbuf_scalar, statxbuf_layout); From 4033358956eaca6ccd7fe6d905b572c243673a62 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 Jul 2020 15:20:36 +0200 Subject: [PATCH 2185/5092] make miri_start_panic intrinsic an FFI function --- src/shims/foreign_items.rs | 6 +++++- src/shims/intrinsics.rs | 9 +++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index a7495beef72e..cf85636b57bf 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -111,7 +111,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx def_id: DefId, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, - _unwind: Option, + unwind: Option, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); @@ -126,6 +126,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // First: functions that diverge. let (dest, ret) = match ret { None => match link_name { + "miri_start_panic" => { + this.handle_miri_start_panic(args, unwind)?; + return Ok(None); + } // This matches calls to the foreign item `panic_impl`. // The implementation is provided by the function with the `#[panic_handler]` attribute. "panic_impl" => { diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index c44caed34f65..f542bebd82ad 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -18,7 +18,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, - unwind: Option, + _unwind: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let intrinsic_name = this.tcx.item_name(instance.def_id()); @@ -32,13 +32,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(()); } - // First handle intrinsics without return place. + // All supported intrinsics have a return place. let intrinsic_name = &*intrinsic_name.as_str(); let (dest, ret) = match ret { - None => match intrinsic_name { - "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), - _ => throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name), - }, + None => throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name), Some(p) => p, }; From fef5fa2ae160118d7165a6394ff9d5447da17729 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 Jul 2020 15:47:33 +0200 Subject: [PATCH 2186/5092] add a Miri extern fn to mark an allocation as being a static root for leak checking --- src/eval.rs | 8 +++++--- src/machine.rs | 4 ++++ src/shims/foreign_items.rs | 11 +++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 79ceb6be806e..24cf0cbf06be 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -5,6 +5,7 @@ use std::ffi::OsStr; use rand::rngs::StdRng; use rand::SeedableRng; +use log::info; use rustc_hir::def_id::DefId; use rustc_middle::ty::{self, layout::LayoutCx, TyCtxt}; @@ -195,8 +196,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( /// Returns `Some(return_code)` if program executed completed. /// Returns `None` if an evaluation error occured. pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option { - // FIXME: on Windows, we ignore leaks (https://github.com/rust-lang/miri/issues/1302). - let ignore_leaks = config.ignore_leaks || tcx.sess.target.target.target_os == "windows"; + // Copy setting before we move `config`. + let ignore_leaks = config.ignore_leaks; let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) { Ok(v) => v, @@ -244,7 +245,8 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> match res { Ok(return_code) => { if !ignore_leaks { - let leaks = ecx.memory.leak_report(); + info!("Additonal static roots: {:?}", ecx.machine.static_roots); + let leaks = ecx.memory.leak_report(&ecx.machine.static_roots); if leaks != 0 { tcx.sess.err("the evaluated program leaked memory"); // Ignore the provided return code - let the reported error diff --git a/src/machine.rs b/src/machine.rs index 49d647838c9e..e9217896ef6e 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -262,6 +262,9 @@ pub struct Evaluator<'mir, 'tcx> { /// Precomputed `TyLayout`s for primitive data types that are commonly used inside Miri. pub(crate) layouts: PrimitiveLayouts<'tcx>, + + /// Allocations that are considered roots of static memory (that may leak). + pub(crate) static_roots: Vec, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { @@ -289,6 +292,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { time_anchor: Instant::now(), layouts, threads: ThreadManager::default(), + static_roots: Vec::new(), } } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index cf85636b57bf..f1b04afe0a62 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -197,6 +197,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Here we dispatch all the shims for foreign functions. If you have a platform specific // shim, add it to the corresponding submodule. match link_name { + // Miri-specific extern functions + "miri_static_root" => { + let &[ptr] = check_arg_count(args)?; + let ptr = this.read_scalar(ptr)?.not_undef()?; + let ptr = this.force_ptr(ptr)?; + if ptr.offset != Size::ZERO { + throw_unsup_format!("Pointer passed to miri_static_root must point to beginning of an allocated block"); + } + this.machine.static_roots.push(ptr.alloc_id); + } + // Standard C allocation "malloc" => { let &[size] = check_arg_count(args)?; From bc0569253f6e8ab98232dd8020bd44b7262c91ec Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 Jul 2020 15:49:22 +0200 Subject: [PATCH 2187/5092] enable leak check tests on Windows --- src/shims/foreign_items.rs | 2 +- tests/compile-fail/memleak.rs | 2 -- tests/compile-fail/memleak_rc.rs | 2 -- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index f1b04afe0a62..7323a664bda8 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -203,7 +203,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.read_scalar(ptr)?.not_undef()?; let ptr = this.force_ptr(ptr)?; if ptr.offset != Size::ZERO { - throw_unsup_format!("Pointer passed to miri_static_root must point to beginning of an allocated block"); + throw_unsup_format!("pointer passed to miri_static_root must point to beginning of an allocated block"); } this.machine.static_roots.push(ptr.alloc_id); } diff --git a/tests/compile-fail/memleak.rs b/tests/compile-fail/memleak.rs index c3b27abcdbb2..71b4e2f442f3 100644 --- a/tests/compile-fail/memleak.rs +++ b/tests/compile-fail/memleak.rs @@ -1,5 +1,3 @@ -// ignore-windows: We do not check leaks on Windows - //error-pattern: the evaluated program leaked memory fn main() { diff --git a/tests/compile-fail/memleak_rc.rs b/tests/compile-fail/memleak_rc.rs index 446d28681b9e..b2bc6722afb0 100644 --- a/tests/compile-fail/memleak_rc.rs +++ b/tests/compile-fail/memleak_rc.rs @@ -1,5 +1,3 @@ -// ignore-windows: We do not check leaks on Windows - //error-pattern: the evaluated program leaked memory use std::rc::Rc; From 06f8bf6afa887a04ecdce0e5d8c7b4c66e2736d2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 Jul 2020 17:14:25 +0200 Subject: [PATCH 2188/5092] document Miri extern functions --- README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/README.md b/README.md index e20c53b68dc5..f97639ea5bdf 100644 --- a/README.md +++ b/README.md @@ -233,6 +233,29 @@ different Miri binaries, and as such worth documenting: interpret the code but compile it like rustc would. This is useful to be sure that the compiled `rlib`s are compatible with Miri. +## Miri `extern` functions + +Miri provides some `extern` functions that programs can import to access +Miri-specific functionality: + +```rust +#[cfg(miri)] +extern "Rust" { + /// Miri-provided extern function to mark the block `ptr` points to as a "root" + /// for some static memory. This memory and everything reachable by it is not + /// considered leaking even if it still exists when the program terminates. + /// + /// `ptr` has to point to the beginning of an allocated block. + fn miri_static_root(ptr: *const u8); + + /// Miri-provided extern function to begin unwinding with the given payload. + /// + /// This is internal and unstable and should not be used; we give it here + /// just to be complete. + fn miri_start_panic(payload: *mut u8) -> !; +} +``` + ## Contributing and getting help If you want to contribute to Miri, great! Please check out our From c641fbde0223cde9fae67de3cc4892998a21cec0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Jul 2020 10:02:25 +0200 Subject: [PATCH 2189/5092] update rust-version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index bfbf6b81b2e2..d0c938c53faf 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4825e12fc9c79954aa0fe18f5521efa6c19c7539 +0e11fc8053d32c44e7152865852acc5c3c54efb3 From 5161ba346c646914b4992aa9cc97d0e4309128b6 Mon Sep 17 00:00:00 2001 From: Philippe Nadon Date: Thu, 23 Jul 2020 09:50:45 -0600 Subject: [PATCH 2190/5092] renamed ScalarMaybeUninit::not_undef to check_init Related to PR https://github.com/rust-lang/rust/pull/74664 --- src/eval.rs | 2 +- src/helpers.rs | 8 +++--- src/operator.rs | 6 ++--- src/shims/env.rs | 34 +++++++++++++------------- src/shims/foreign_items.rs | 18 +++++++------- src/shims/intrinsics.rs | 8 +++--- src/shims/mod.rs | 4 +-- src/shims/panic.rs | 8 +++--- src/shims/posix/foreign_items.rs | 22 ++++++++--------- src/shims/posix/fs.rs | 26 ++++++++++---------- src/shims/posix/linux/foreign_items.rs | 2 +- src/shims/posix/macos/dlsym.rs | 2 +- src/shims/posix/macos/foreign_items.rs | 8 +++--- src/shims/posix/sync.rs | 18 +++++++------- src/shims/posix/thread.rs | 8 +++--- src/shims/time.rs | 2 +- src/shims/tls.rs | 2 +- src/shims/windows/foreign_items.rs | 14 +++++------ 18 files changed, 96 insertions(+), 96 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 24cf0cbf06be..8561edcc05b9 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -234,7 +234,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> } } } - let return_code = ecx.read_scalar(ret_place.into())?.not_undef()?.to_machine_isize(&ecx)?; + let return_code = ecx.read_scalar(ret_place.into())?.check_init()?.to_machine_isize(&ecx)?; Ok(return_code) })(); diff --git a/src/helpers.rs b/src/helpers.rs index 473da84aeea3..d271b845c215 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -67,7 +67,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar> { self.eval_context_mut() .eval_path_scalar(&["libc", name])? - .not_undef() + .check_init() } /// Helper function to get a `libc` constant as an `i32`. @@ -80,7 +80,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn eval_windows(&mut self, module: &str, name: &str) -> InterpResult<'tcx, Scalar> { self.eval_context_mut() .eval_path_scalar(&["std", "sys", "windows", module, name])? - .not_undef() + .check_init() } /// Helper function to get a `windows` constant as an `u64`. @@ -407,7 +407,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn get_last_error(&self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_ref(); let errno_place = this.machine.last_error.unwrap(); - this.read_scalar(errno_place.into())?.not_undef() + this.read_scalar(errno_place.into())?.check_init() } /// Sets the last OS error using a `std::io::Error`. This function tries to produce the most @@ -467,7 +467,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } - + fn read_scalar_at_offset( &self, op: OpTy<'tcx, Tag>, diff --git a/src/operator.rs b/src/operator.rs index bfc8e908dc15..5b86b9a76f6b 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -32,11 +32,11 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { #[rustfmt::skip] let eq = match (*left, *right) { (Immediate::Scalar(left), Immediate::Scalar(right)) => { - self.ptr_eq(left.not_undef()?, right.not_undef()?)? + self.ptr_eq(left.check_init()?, right.check_init()?)? } (Immediate::ScalarPair(left1, left2), Immediate::ScalarPair(right1, right2)) => { - self.ptr_eq(left1.not_undef()?, right1.not_undef()?)? - && self.ptr_eq(left2.not_undef()?, right2.not_undef()?)? + self.ptr_eq(left1.check_init()?, right1.check_init()?)? + && self.ptr_eq(left2.check_init()?, right2.check_init()?)? } _ => bug!("Type system should not allow comparing Scalar with ScalarPair"), }; diff --git a/src/shims/env.rs b/src/shims/env.rs index 4a2bec28bd17..86a7a58ac4aa 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -69,7 +69,7 @@ impl<'tcx> EnvVars<'tcx> { } // Deallocate environ var list. let environ = ecx.machine.env_vars.environ.unwrap(); - let old_vars_ptr = ecx.read_scalar(environ.into())?.not_undef()?; + let old_vars_ptr = ecx.read_scalar(environ.into())?.check_init()?; ecx.memory.deallocate(ecx.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Env.into())?; Ok(()) } @@ -104,7 +104,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let target_os = &this.tcx.sess.target.target.target_os; assert!(target_os == "linux" || target_os == "macos", "`getenv` is only available for the UNIX target family"); - let name_ptr = this.read_scalar(name_op)?.not_undef()?; + let name_ptr = this.read_scalar(name_op)?.check_init()?; let name = this.read_os_str_from_c_str(name_ptr)?; Ok(match this.machine.env_vars.map.get(name) { Some(var_ptr) => { @@ -125,7 +125,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("windows", "GetEnvironmentVariableW"); - let name_ptr = this.read_scalar(name_op)?.not_undef()?; + let name_ptr = this.read_scalar(name_op)?.check_init()?; let name = this.read_os_str_from_wide_str(name_ptr)?; Ok(match this.machine.env_vars.map.get(&name) { Some(var_ptr) => { @@ -135,7 +135,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let var_ptr = Scalar::from(var_ptr.offset(Size::from_bytes(name_offset_bytes), this)?); let var = this.read_os_str_from_wide_str(var_ptr)?; - let buf_ptr = this.read_scalar(buf_op)?.not_undef()?; + let buf_ptr = this.read_scalar(buf_op)?.check_init()?; // `buf_size` represents the size in characters. let buf_size = u64::from(this.read_scalar(size_op)?.to_u32()?); windows_check_buffer_size(this.write_os_str_to_wide_str(&var, buf_ptr, buf_size)?) @@ -153,7 +153,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("windows", "GetEnvironmentStringsW"); - // Info on layout of environment blocks in Windows: + // Info on layout of environment blocks in Windows: // https://docs.microsoft.com/en-us/windows/win32/procthread/environment-variables let mut env_vars = std::ffi::OsString::new(); for &item in this.machine.env_vars.map.values() { @@ -173,7 +173,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("windows", "FreeEnvironmentStringsW"); - let env_block_ptr = this.read_scalar(env_block_op)?.not_undef()?; + let env_block_ptr = this.read_scalar(env_block_op)?.check_init()?; let result = this.memory.deallocate(this.force_ptr(env_block_ptr)?, None, MiriMemoryKind::Env.into()); // If the function succeeds, the return value is nonzero. Ok(result.is_ok() as i32) @@ -188,8 +188,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let target_os = &this.tcx.sess.target.target.target_os; assert!(target_os == "linux" || target_os == "macos", "`setenv` is only available for the UNIX target family"); - let name_ptr = this.read_scalar(name_op)?.not_undef()?; - let value_ptr = this.read_scalar(value_op)?.not_undef()?; + let name_ptr = this.read_scalar(name_op)?.check_init()?; + let value_ptr = this.read_scalar(value_op)?.check_init()?; let mut new = None; if !this.is_null(name_ptr)? { @@ -224,14 +224,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut this = self.eval_context_mut(); this.assert_target_os("windows", "SetEnvironmentVariableW"); - let name_ptr = this.read_scalar(name_op)?.not_undef()?; - let value_ptr = this.read_scalar(value_op)?.not_undef()?; + let name_ptr = this.read_scalar(name_op)?.check_init()?; + let value_ptr = this.read_scalar(value_op)?.check_init()?; if this.is_null(name_ptr)? { // ERROR CODE is not clearly explained in docs.. For now, throw UB instead. throw_ub_format!("pointer to environment variable name is NULL"); } - + let name = this.read_os_str_from_wide_str(name_ptr)?; if name.is_empty() { throw_unsup_format!("environment variable name is an empty string"); @@ -261,7 +261,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let target_os = &this.tcx.sess.target.target.target_os; assert!(target_os == "linux" || target_os == "macos", "`unsetenv` is only available for the UNIX target family"); - let name_ptr = this.read_scalar(name_op)?.not_undef()?; + let name_ptr = this.read_scalar(name_op)?.check_init()?; let mut success = None; if !this.is_null(name_ptr)? { let name = this.read_os_str_from_c_str(name_ptr)?.to_owned(); @@ -295,7 +295,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("getcwd")?; - let buf = this.read_scalar(buf_op)?.not_undef()?; + let buf = this.read_scalar(buf_op)?.check_init()?; let size = this.read_scalar(size_op)?.to_machine_usize(&*this.tcx)?; // If we cannot get the current directory, we return null match env::current_dir() { @@ -323,7 +323,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("GetCurrentDirectoryW")?; let size = u64::from(this.read_scalar(size_op)?.to_u32()?); - let buf = this.read_scalar(buf_op)?.not_undef()?; + let buf = this.read_scalar(buf_op)?.check_init()?; // If we cannot get the current directory, we return 0 match env::current_dir() { @@ -341,7 +341,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("chdir")?; - let path = this.read_path_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?; match env::set_current_dir(path) { Ok(()) => Ok(0), @@ -362,7 +362,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("SetCurrentDirectoryW")?; - let path = this.read_path_from_wide_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_path_from_wide_str(this.read_scalar(path_op)?.check_init()?)?; match env::set_current_dir(path) { Ok(()) => Ok(1), @@ -379,7 +379,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); // Deallocate the old environ list, if any. if let Some(environ) = this.machine.env_vars.environ { - let old_vars_ptr = this.read_scalar(environ.into())?.not_undef()?; + let old_vars_ptr = this.read_scalar(environ.into())?.check_init()?; this.memory.deallocate(this.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Env.into())?; } else { // No `environ` allocated yet, let's do that. diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 7323a664bda8..d4f248f0329d 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -226,12 +226,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "free" => { let &[ptr] = check_arg_count(args)?; - let ptr = this.read_scalar(ptr)?.not_undef()?; + let ptr = this.read_scalar(ptr)?.check_init()?; this.free(ptr, MiriMemoryKind::C)?; } "realloc" => { let &[old_ptr, new_size] = check_arg_count(args)?; - let old_ptr = this.read_scalar(old_ptr)?.not_undef()?; + let old_ptr = this.read_scalar(old_ptr)?.check_init()?; let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; let res = this.realloc(old_ptr, new_size, MiriMemoryKind::C)?; this.write_scalar(res, dest)?; @@ -268,7 +268,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "__rust_dealloc" => { let &[ptr, old_size, align] = check_arg_count(args)?; - let ptr = this.read_scalar(ptr)?.not_undef()?; + let ptr = this.read_scalar(ptr)?.check_init()?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; // No need to check old_size/align; we anyway check that they match the allocation. @@ -281,7 +281,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "__rust_realloc" => { let &[ptr, old_size, align, new_size] = check_arg_count(args)?; - let ptr = this.force_ptr(this.read_scalar(ptr)?.not_undef()?)?; + let ptr = this.force_ptr(this.read_scalar(ptr)?.check_init()?)?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; @@ -301,8 +301,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // C memory handling functions "memcmp" => { let &[left, right, n] = check_arg_count(args)?; - let left = this.read_scalar(left)?.not_undef()?; - let right = this.read_scalar(right)?.not_undef()?; + let left = this.read_scalar(left)?.check_init()?; + let right = this.read_scalar(right)?.check_init()?; let n = Size::from_bytes(this.read_scalar(n)?.to_machine_usize(this)?); let result = { @@ -321,7 +321,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "memrchr" => { let &[ptr, val, num] = check_arg_count(args)?; - let ptr = this.read_scalar(ptr)?.not_undef()?; + let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; if let Some(idx) = this @@ -339,7 +339,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "memchr" => { let &[ptr, val, num] = check_arg_count(args)?; - let ptr = this.read_scalar(ptr)?.not_undef()?; + let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; let idx = this @@ -356,7 +356,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "strlen" => { let &[ptr] = check_arg_count(args)?; - let ptr = this.read_scalar(ptr)?.not_undef()?; + let ptr = this.read_scalar(ptr)?.check_init()?; let n = this.memory.read_c_str(ptr)?.len(); this.write_scalar(Scalar::from_machine_usize(u64::try_from(n).unwrap(), this), dest)?; } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index f542bebd82ad..ce0368b4a082 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -68,9 +68,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let size = elem_layout.size.checked_mul(count, this) .ok_or_else(|| err_ub_format!("overflow computing total size of `{}`", intrinsic_name))?; - let src = this.read_scalar(src)?.not_undef()?; + let src = this.read_scalar(src)?.check_init()?; let src = this.memory.check_ptr_access(src, size, elem_align)?; - let dest = this.read_scalar(dest)?.not_undef()?; + let dest = this.read_scalar(dest)?.check_init()?; let dest = this.memory.check_ptr_access(dest, size, elem_align)?; if let (Some(src), Some(dest)) = (src, dest) { @@ -105,7 +105,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ty = instance.substs.type_at(0); let ty_layout = this.layout_of(ty)?; let val_byte = this.read_scalar(val_byte)?.to_u8()?; - let ptr = this.read_scalar(ptr)?.not_undef()?; + let ptr = this.read_scalar(ptr)?.check_init()?; let count = this.read_scalar(count)?.to_machine_usize(this)?; let byte_count = ty_layout.size.checked_mul(count, this) .ok_or_else(|| err_ub_format!("overflow computing total size of `write_bytes`"))?; @@ -503,7 +503,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Other "assume" => { let &[cond] = check_arg_count(args)?; - let cond = this.read_scalar(cond)?.not_undef()?.to_bool()?; + let cond = this.read_scalar(cond)?.check_init()?.to_bool()?; if !cond { throw_ub_format!("`assume` intrinsic called with `false`"); } diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 56754a9ebde5..05dd4059eb1b 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -67,14 +67,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (dest, ret) = ret.unwrap(); let req_align = this - .force_bits(this.read_scalar(align_op)?.not_undef()?, this.pointer_size())?; + .force_bits(this.read_scalar(align_op)?.check_init()?, this.pointer_size())?; // Stop if the alignment is not a power of two. if !req_align.is_power_of_two() { return this.start_panic("align_offset: align is not a power-of-two", unwind); } - let ptr_scalar = this.read_scalar(ptr_op)?.not_undef()?; + let ptr_scalar = this.read_scalar(ptr_op)?.check_init()?; // Default: no result. let mut result = this.machine_usize_max(); diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 8e291c201215..45a41b9b7be0 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -47,7 +47,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Get the raw pointer stored in arg[0] (the panic payload). let &[payload] = check_arg_count(args)?; - let payload = this.read_scalar(payload)?.not_undef()?; + let payload = this.read_scalar(payload)?.check_init()?; assert!( this.machine.panic_payload.is_none(), "the panic runtime should avoid double-panics" @@ -81,9 +81,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Get all the arguments. let &[try_fn, data, catch_fn] = check_arg_count(args)?; - let try_fn = this.read_scalar(try_fn)?.not_undef()?; - let data = this.read_scalar(data)?.not_undef()?; - let catch_fn = this.read_scalar(catch_fn)?.not_undef()?; + let try_fn = this.read_scalar(try_fn)?.check_init()?; + let data = this.read_scalar(data)?.check_init()?; + let catch_fn = this.read_scalar(catch_fn)?.check_init()?; // Now we make a function call, and pass `data` as first and only argument. let f_instance = this.memory.get_fn(try_fn)?.as_instance()?; diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 80611a18e4fc..4bb94ae89449 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -65,7 +65,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "read" => { let &[fd, buf, count] = check_arg_count(args)?; let fd = this.read_scalar(fd)?.to_i32()?; - let buf = this.read_scalar(buf)?.not_undef()?; + let buf = this.read_scalar(buf)?.check_init()?; let count = this.read_scalar(count)?.to_machine_usize(this)?; let result = if fd == 0 { @@ -109,7 +109,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "write" => { let &[fd, buf, n] = check_arg_count(args)?; let fd = this.read_scalar(fd)?.to_i32()?; - let buf = this.read_scalar(buf)?.not_undef()?; + let buf = this.read_scalar(buf)?.check_init()?; let count = this.read_scalar(n)?.to_machine_usize(this)?; trace!("Called write({:?}, {:?}, {:?})", fd, buf, count); let result = if fd == 0 { @@ -225,7 +225,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "dlsym" => { let &[handle, symbol] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_usize(this)?; - let symbol = this.read_scalar(symbol)?.not_undef()?; + let symbol = this.read_scalar(symbol)?.check_init()?; let symbol_name = this.memory.read_c_str(symbol)?; if let Some(dlsym) = Dlsym::from_str(symbol_name, &this.tcx.sess.target.target.target_os)? { let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); @@ -263,7 +263,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "pthread_key_create" => { let &[key, dtor] = check_arg_count(args)?; let key_place = this.deref_operand(key)?; - let dtor = this.read_scalar(dtor)?.not_undef()?; + let dtor = this.read_scalar(dtor)?.check_init()?; // Extract the function type out of the signature (that seems easier than constructing it ourselves). let dtor = match this.test_null(dtor)? { @@ -290,23 +290,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "pthread_key_delete" => { let &[key] = check_arg_count(args)?; - let key = this.force_bits(this.read_scalar(key)?.not_undef()?, key.layout.size)?; + let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; this.machine.tls.delete_tls_key(key)?; // Return success (0) this.write_null(dest)?; } "pthread_getspecific" => { let &[key] = check_arg_count(args)?; - let key = this.force_bits(this.read_scalar(key)?.not_undef()?, key.layout.size)?; + let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { let &[key, new_ptr] = check_arg_count(args)?; - let key = this.force_bits(this.read_scalar(key)?.not_undef()?, key.layout.size)?; + let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); - let new_ptr = this.read_scalar(new_ptr)?.not_undef()?; + let new_ptr = this.read_scalar(new_ptr)?.check_init()?; this.machine.tls.store_tls(key, active_thread, this.test_null(new_ptr)?)?; // Return success (`0`). @@ -462,9 +462,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "pthread_atfork" => { let &[prepare, parent, child] = check_arg_count(args)?; - this.force_bits(this.read_scalar(prepare)?.not_undef()?, this.memory.pointer_size())?; - this.force_bits(this.read_scalar(parent)?.not_undef()?, this.memory.pointer_size())?; - this.force_bits(this.read_scalar(child)?.not_undef()?, this.memory.pointer_size())?; + this.force_bits(this.read_scalar(prepare)?.check_init()?, this.memory.pointer_size())?; + this.force_bits(this.read_scalar(parent)?.check_init()?, this.memory.pointer_size())?; + this.force_bits(this.read_scalar(child)?.check_init()?, this.memory.pointer_size())?; // We do not support forking, so there is nothing to do here. this.write_null(dest)?; } diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index a43e86dcc5b5..a50228a4847c 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -81,7 +81,7 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let path_scalar = this.read_scalar(path_op)?.not_undef()?; + let path_scalar = this.read_scalar(path_op)?.check_init()?; let path = this.read_path_from_c_str(path_scalar)?.into_owned(); let metadata = match FileMetadata::from_path(this, &path, follow_symlink)? { @@ -334,7 +334,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("unsupported flags {:#x}", flag & !mirror); } - let path = this.read_path_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?; let fd = options.open(&path).map(|file| { let fh = &mut this.machine.file_handler; @@ -558,7 +558,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("unlink")?; - let path = this.read_path_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?; let result = remove_file(path).map(|_| 0); this.try_unwrap_io_result(result) @@ -588,8 +588,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("symlink")?; - let target = this.read_path_from_c_str(this.read_scalar(target_op)?.not_undef()?)?; - let linkpath = this.read_path_from_c_str(this.read_scalar(linkpath_op)?.not_undef()?)?; + let target = this.read_path_from_c_str(this.read_scalar(target_op)?.check_init()?)?; + let linkpath = this.read_path_from_c_str(this.read_scalar(linkpath_op)?.check_init()?)?; let result = create_link(&target, &linkpath).map(|_| 0); this.try_unwrap_io_result(result) @@ -651,8 +651,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.assert_target_os("linux", "statx"); this.check_no_isolation("statx")?; - let statxbuf_scalar = this.read_scalar(statxbuf_op)?.not_undef()?; - let pathname_scalar = this.read_scalar(pathname_op)?.not_undef()?; + let statxbuf_scalar = this.read_scalar(statxbuf_op)?.check_init()?; + let pathname_scalar = this.read_scalar(pathname_op)?.check_init()?; // If the statxbuf or pathname pointers are null, the function fails with `EFAULT`. if this.is_null(statxbuf_scalar)? || this.is_null(pathname_scalar)? { @@ -810,8 +810,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("rename")?; - let oldpath_scalar = this.read_scalar(oldpath_op)?.not_undef()?; - let newpath_scalar = this.read_scalar(newpath_op)?.not_undef()?; + let oldpath_scalar = this.read_scalar(oldpath_op)?.check_init()?; + let newpath_scalar = this.read_scalar(newpath_op)?.check_init()?; if this.is_null(oldpath_scalar)? || this.is_null(newpath_scalar)? { let efault = this.eval_libc("EFAULT")?; @@ -838,12 +838,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[cfg_attr(not(unix), allow(unused_variables))] let mode = if this.tcx.sess.target.target.target_os == "macos" { - u32::from(this.read_scalar(mode_op)?.not_undef()?.to_u16()?) + u32::from(this.read_scalar(mode_op)?.check_init()?.to_u16()?) } else { this.read_scalar(mode_op)?.to_u32()? }; - let path = this.read_path_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?; #[cfg_attr(not(unix), allow(unused_mut))] let mut builder = DirBuilder::new(); @@ -869,7 +869,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("rmdir")?; - let path = this.read_path_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?; let result = remove_dir(path).map(|_| 0i32); @@ -881,7 +881,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("opendir")?; - let name = this.read_path_from_c_str(this.read_scalar(name_op)?.not_undef()?)?; + let name = this.read_path_from_c_str(this.read_scalar(name_op)?.check_init()?)?; let result = read_dir(name); diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index ff30609d9ab2..ccb0ef8226e6 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -181,7 +181,7 @@ fn getrandom<'tcx>( flags: OpTy<'tcx, Tag>, dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { - let ptr = this.read_scalar(ptr)?.not_undef()?; + let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_machine_usize(this)?; // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, diff --git a/src/shims/posix/macos/dlsym.rs b/src/shims/posix/macos/dlsym.rs index 8256c10b0d39..0236b10e5fc8 100644 --- a/src/shims/posix/macos/dlsym.rs +++ b/src/shims/posix/macos/dlsym.rs @@ -35,7 +35,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match dlsym { Dlsym::getentropy => { let &[ptr, len] = check_arg_count(args)?; - let ptr = this.read_scalar(ptr)?.not_undef()?; + let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_machine_usize(this)?; this.gen_random(ptr, len)?; this.write_null(dest)?; diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index ef649c3e8406..2e7258c800ac 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -98,9 +98,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "_tlv_atexit" => { let &[dtor, data] = check_arg_count(args)?; - let dtor = this.read_scalar(dtor)?.not_undef()?; + let dtor = this.read_scalar(dtor)?.check_init()?; let dtor = this.memory.get_fn(dtor)?.as_instance()?; - let data = this.read_scalar(data)?.not_undef()?; + let data = this.read_scalar(data)?.check_init()?; let active_thread = this.get_active_thread(); this.machine.tls.set_macos_thread_dtor(active_thread, dtor, data)?; } @@ -122,7 +122,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_setname_np" => { let &[name] = check_arg_count(args)?; - let name = this.read_scalar(name)?.not_undef()?; + let name = this.read_scalar(name)?.check_init()?; this.pthread_setname_np(name)?; } @@ -131,7 +131,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "mmap" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. let &[addr, _, _, _, _, _] = check_arg_count(args)?; - let addr = this.read_scalar(addr)?.not_undef()?; + let addr = this.read_scalar(addr)?.check_init()?; this.write_scalar(addr, dest)?; } diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index cce0ddc930df..28a45b194771 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -288,7 +288,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let kind = this.read_scalar(kind_op)?.not_undef()?; + let kind = this.read_scalar(kind_op)?.check_init()?; if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { // In `glibc` implementation, the numeric values of // `PTHREAD_MUTEX_NORMAL` and `PTHREAD_MUTEX_DEFAULT` are equal. @@ -337,11 +337,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let attr = this.read_scalar(attr_op)?.not_undef()?; + let attr = this.read_scalar(attr_op)?.check_init()?; let kind = if this.is_null(attr)? { this.eval_libc("PTHREAD_MUTEX_DEFAULT")? } else { - mutexattr_get_kind(this, attr_op)?.not_undef()? + mutexattr_get_kind(this, attr_op)?.check_init()? }; // Write 0 to use the same code path as the static initializers. @@ -355,7 +355,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_lock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; + let kind = mutex_get_kind(this, mutex_op)?.check_init()?; let id = mutex_get_or_create_id(this, mutex_op)?; let active_thread = this.get_active_thread(); @@ -392,7 +392,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_trylock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; + let kind = mutex_get_kind(this, mutex_op)?.check_init()?; let id = mutex_get_or_create_id(this, mutex_op)?; let active_thread = this.get_active_thread(); @@ -425,7 +425,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_unlock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; + let kind = mutex_get_kind(this, mutex_op)?.check_init()?; let id = mutex_get_or_create_id(this, mutex_op)?; let active_thread = this.get_active_thread(); @@ -589,7 +589,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let clock_id = this.read_scalar(clock_id_op)?.not_undef()?; + let clock_id = this.read_scalar(clock_id_op)?.check_init()?; if clock_id == this.eval_libc("CLOCK_REALTIME")? || clock_id == this.eval_libc("CLOCK_MONOTONIC")? { @@ -630,11 +630,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let attr = this.read_scalar(attr_op)?.not_undef()?; + let attr = this.read_scalar(attr_op)?.check_init()?; let clock_id = if this.is_null(attr)? { this.eval_libc("CLOCK_REALTIME")? } else { - condattr_get_clock_id(this, attr_op)?.not_undef()? + condattr_get_clock_id(this, attr_op)?.check_init()? }; // Write 0 to use the same code path as the static initializers. diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index e5d3a9f0d6f8..7c9c489e6fb4 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -29,7 +29,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx thread_info_place.into(), )?; - let fn_ptr = this.read_scalar(start_routine)?.not_undef()?; + let fn_ptr = this.read_scalar(start_routine)?.check_init()?; let instance = this.memory.get_fn(fn_ptr)?.as_instance()?; let func_arg = this.read_immediate(arg)?; @@ -59,7 +59,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if !this.is_null(this.read_scalar(retval)?.not_undef()?)? { + if !this.is_null(this.read_scalar(retval)?.check_init()?)? { // FIXME: implement reading the thread function's return place. throw_unsup_format!("Miri supports pthread_join only with retval==NULL"); } @@ -99,7 +99,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let option = this.read_scalar(option)?.to_i32()?; if option == this.eval_libc_i32("PR_SET_NAME")? { - let address = this.read_scalar(arg2)?.not_undef()?; + let address = this.read_scalar(arg2)?.check_init()?; let mut name = this.memory.read_c_str(address)?.to_owned(); // The name should be no more than 16 bytes, including the null // byte. Since `read_c_str` returns the string without the null @@ -107,7 +107,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name.truncate(15); this.set_active_thread_name(name); } else if option == this.eval_libc_i32("PR_GET_NAME")? { - let address = this.read_scalar(arg2)?.not_undef()?; + let address = this.read_scalar(arg2)?.check_init()?; let mut name = this.get_active_thread_name().to_vec(); name.push(0u8); assert!(name.len() <= 16); diff --git a/src/shims/time.rs b/src/shims/time.rs index e26d2ce2e39d..193c87f7f099 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -62,7 +62,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("gettimeofday")?; // Using tz is obsolete and should always be null - let tz = this.read_scalar(tz_op)?.not_undef()?; + let tz = this.read_scalar(tz_op)?.check_init()?; if !this.is_null(tz)? { let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; diff --git a/src/shims/tls.rs b/src/shims/tls.rs index d2d5522c4023..8d05442ad6bc 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -237,7 +237,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // we specifically look up the static in libstd that we know is placed // in that section. let thread_callback = this.eval_path_scalar(&["std", "sys", "windows", "thread_local_key", "p_thread_callback"])?; - let thread_callback = this.memory.get_fn(thread_callback.not_undef()?)?.as_instance()?; + let thread_callback = this.memory.get_fn(thread_callback.check_init()?)?.as_instance()?; // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. let reason = this.eval_path_scalar(&["std", "sys", "windows", "c", "DLL_THREAD_DETACH"])?; diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index e8937bbb3085..fc1093b64fb4 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -67,7 +67,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[handle, buf, n, written_ptr, overlapped] = check_arg_count(args)?; this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore let handle = this.read_scalar(handle)?.to_machine_isize(this)?; - let buf = this.read_scalar(buf)?.not_undef()?; + let buf = this.read_scalar(buf)?.check_init()?; let n = this.read_scalar(n)?.to_u32()?; let written_place = this.deref_operand(written_ptr)?; // Spec says to always write `0` first. @@ -111,7 +111,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[handle, flags, ptr] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; - let ptr = this.read_scalar(ptr)?.not_undef()?; + let ptr = this.read_scalar(ptr)?.check_init()?; this.free(ptr, MiriMemoryKind::WinHeap)?; this.write_scalar(Scalar::from_i32(1), dest)?; } @@ -119,7 +119,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[handle, flags, ptr, size] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; - let ptr = this.read_scalar(ptr)?.not_undef()?; + let ptr = this.read_scalar(ptr)?.check_init()?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let res = this.realloc(ptr, size, MiriMemoryKind::WinHeap)?; this.write_scalar(res, dest)?; @@ -128,7 +128,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // errno "SetLastError" => { let &[error] = check_arg_count(args)?; - let error = this.read_scalar(error)?.not_undef()?; + let error = this.read_scalar(error)?.check_init()?; this.set_last_error(error)?; } "GetLastError" => { @@ -172,7 +172,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[key, new_ptr] = check_arg_count(args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); - let new_ptr = this.read_scalar(new_ptr)?.not_undef()?; + let new_ptr = this.read_scalar(new_ptr)?.check_init()?; this.machine.tls.store_tls(key, active_thread, this.test_null(new_ptr)?)?; // Return success (`1`). @@ -212,7 +212,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] let &[hModule, lpProcName] = check_arg_count(args)?; this.read_scalar(hModule)?.to_machine_isize(this)?; - let name = this.memory.read_c_str(this.read_scalar(lpProcName)?.not_undef()?)?; + let name = this.memory.read_c_str(this.read_scalar(lpProcName)?.check_init()?)?; if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.target.target_os)? { let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); this.write_scalar(Scalar::from(ptr), dest)?; @@ -225,7 +225,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "SystemFunction036" => { // The actual name of 'RtlGenRandom' let &[ptr, len] = check_arg_count(args)?; - let ptr = this.read_scalar(ptr)?.not_undef()?; + let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_u32()?; this.gen_random(ptr, len.into())?; this.write_scalar(Scalar::from_bool(true), dest)?; From 21268157ff89c13ee5d079e322bb692bb9216802 Mon Sep 17 00:00:00 2001 From: Philippe Nadon Date: Thu, 23 Jul 2020 10:28:00 -0600 Subject: [PATCH 2191/5092] renamed Immediate::to_scalar_or_undef to Immediate::to_scalar_or_uninit in src/shims/intrinsics.rs related issue #71193 --- src/shims/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index ce0368b4a082..ee64b1ffca44 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -392,7 +392,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `binary_op` will bail if either of them is not a scalar. let eq = this.overflowing_binary_op(mir::BinOp::Eq, old, expect_old)?.0; - let res = Immediate::ScalarPair(old.to_scalar_or_undef(), eq.into()); + let res = Immediate::ScalarPair(old.to_scalar_or_uninit(), eq.into()); // Return old value. this.write_immediate(res, dest)?; // Update ptr depending on comparison. From 6282e927740b4e054e90879171fdb3f6feb9deff Mon Sep 17 00:00:00 2001 From: Phil Nadon Date: Sun, 26 Jul 2020 07:54:24 -0600 Subject: [PATCH 2192/5092] Updated Rust version to latest master Updated Rust version since the latest version contains changes which allow this version of Miri to build. --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index d0c938c53faf..211af60b88aa 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0e11fc8053d32c44e7152865852acc5c3c54efb3 +13f9aa190957b993a268fd4a046fce76ca8814ee From 6dd700fd177e22ab24b97c175ea9ce8611c07932 Mon Sep 17 00:00:00 2001 From: Philippe Nadon Date: Mon, 27 Jul 2020 13:07:25 -0600 Subject: [PATCH 2193/5092] Changed not_undef to check_init in foreign_items.rs Due to changes from upstream, a commit using not_undef was inserted, which had to be updated to use check_init. related issue #71193 --- src/shims/foreign_items.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index d4f248f0329d..98e66db92da3 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -200,7 +200,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miri-specific extern functions "miri_static_root" => { let &[ptr] = check_arg_count(args)?; - let ptr = this.read_scalar(ptr)?.not_undef()?; + let ptr = this.read_scalar(ptr)?.check_init()?; let ptr = this.force_ptr(ptr)?; if ptr.offset != Size::ZERO { throw_unsup_format!("pointer passed to miri_static_root must point to beginning of an allocated block"); From 0a4e8caa8c303e8a8b5459bb79c7474eb53619ae Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jul 2020 11:15:01 +0200 Subject: [PATCH 2194/5092] adjust to canonical_alloc_id removal --- src/diagnostics.rs | 4 ++-- src/intptrcast.rs | 3 +-- src/machine.rs | 38 ++++++++++---------------------------- src/thread.rs | 41 +---------------------------------------- 4 files changed, 14 insertions(+), 72 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 009f8aa29cec..3c6486244591 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -94,8 +94,8 @@ pub fn report_error<'tcx, 'mir>( let helps = match e.kind { Unsupported(UnsupportedOpInfo::NoMirFor(..)) => vec![format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`")], - Unsupported(UnsupportedOpInfo::ReadBytesAsPointer) => - panic!("`ReadBytesAsPointer` cannot be raised by Miri"), + Unsupported(UnsupportedOpInfo::ReadBytesAsPointer | UnsupportedOpInfo::ThreadLocalStatic(_) | UnsupportedOpInfo::ReadExternStatic(_)) => + panic!("Error should never be raised by Miri: {:?}", e.kind), Unsupported(_) => vec![format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support")], UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. }) => diff --git a/src/intptrcast.rs b/src/intptrcast.rs index c908bdf24eba..188ff94861bd 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -6,7 +6,6 @@ use log::trace; use rand::Rng; use rustc_data_structures::fx::FxHashMap; -use rustc_mir::interpret::{AllocCheck, AllocId, InterpResult, Memory, Machine, Pointer, PointerArithmetic}; use rustc_target::abi::{Size, HasDataLayout}; use crate::*; @@ -79,7 +78,7 @@ impl<'mir, 'tcx> GlobalState { ) -> InterpResult<'tcx, u64> { let mut global_state = memory.extra.intptrcast.borrow_mut(); let global_state = &mut *global_state; - let id = Evaluator::canonical_alloc_id(memory, ptr.alloc_id); + let id = ptr.alloc_id; // There is nothing wrong with a raw pointer being cast to an integer only after // it became dangling. Hence `MaybeDead`. diff --git a/src/machine.rs b/src/machine.rs index e9217896ef6e..d418409df067 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -426,44 +426,26 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { Ok(()) } - fn thread_local_alloc_id( + fn thread_local_static_alloc_id( ecx: &mut InterpCx<'mir, 'tcx, Self>, def_id: DefId, ) -> InterpResult<'tcx, AllocId> { ecx.get_or_create_thread_local_alloc_id(def_id) } - fn adjust_global_const( - ecx: &InterpCx<'mir, 'tcx, Self>, - mut val: mir::interpret::ConstValue<'tcx>, - ) -> InterpResult<'tcx, mir::interpret::ConstValue<'tcx>> { - // FIXME: Remove this, do The Right Thing in `thread_local_alloc_id` instead. - ecx.remap_thread_local_alloc_ids(&mut val)?; - Ok(val) - } - - fn canonical_alloc_id(mem: &Memory<'mir, 'tcx, Self>, id: AllocId) -> AllocId { - let tcx = mem.tcx; - // Figure out if this is an extern static, and if yes, which one. - let def_id = match tcx.get_global_alloc(id) { - Some(GlobalAlloc::Static(def_id)) if tcx.is_foreign_item(def_id) => def_id, - _ => { - // No need to canonicalize anything. - return id; - } - }; - let attrs = tcx.get_attrs(def_id); + fn extern_static_alloc_id( + memory: &Memory<'mir, 'tcx, Self>, + def_id: DefId, + ) -> InterpResult<'tcx, AllocId> { + let attrs = memory.tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { Some(name) => name, - None => tcx.item_name(def_id), + None => memory.tcx.item_name(def_id), }; - // Check if we know this one. - if let Some(canonical_id) = mem.extra.extern_statics.get(&link_name) { - trace!("canonical_alloc_id: {:?} ({}) -> {:?}", id, link_name, canonical_id); - *canonical_id + if let Some(&id) = memory.extra.extern_statics.get(&link_name) { + Ok(id) } else { - // Return original id; `Memory::get_static_alloc` will throw an error. - id + throw_unsup_format!("`extern` static {:?} is not supported by Miri", def_id) } } diff --git a/src/thread.rs b/src/thread.rs index 42a4dbded58f..0a83b71665c5 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -11,11 +11,7 @@ use log::trace; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; use rustc_index::vec::{Idx, IndexVec}; -use rustc_middle::{ - middle::codegen_fn_attrs::CodegenFnAttrFlags, - mir, - ty::{self, Instance}, -}; +use rustc_middle::ty::{self, Instance}; use crate::sync::SynchronizationState; use crate::*; @@ -499,41 +495,6 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { // Public interface to thread management. impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// A workaround for thread-local statics until - /// https://github.com/rust-lang/rust/issues/70685 is fixed: change the - /// thread-local allocation id with a freshly generated allocation id for - /// the currently active thread. - fn remap_thread_local_alloc_ids( - &self, - val: &mut mir::interpret::ConstValue<'tcx>, - ) -> InterpResult<'tcx> { - let this = self.eval_context_ref(); - match *val { - mir::interpret::ConstValue::Scalar(Scalar::Ptr(ref mut ptr)) => { - let alloc_id = ptr.alloc_id; - let alloc = this.tcx.get_global_alloc(alloc_id); - let tcx = this.tcx; - let is_thread_local = |def_id| { - tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) - }; - match alloc { - Some(GlobalAlloc::Static(def_id)) if is_thread_local(def_id) => { - ptr.alloc_id = this.get_or_create_thread_local_alloc_id(def_id)?; - } - _ => {} - } - } - _ => { - // FIXME: Handling only `Scalar` seems to work for now, but at - // least in principle thread-locals could be in any constant, so - // we should also consider other cases. However, once - // https://github.com/rust-lang/rust/issues/70685 gets fixed, - // this code will have to be rewritten anyway. - } - } - Ok(()) - } - /// Get a thread-specific allocation id for the given thread-local static. /// If needed, allocate a new one. /// From 7b07fc385c1b9e61f8388c5540d344ecf25bb932 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jul 2020 12:11:27 +0200 Subject: [PATCH 2195/5092] get_or_create_thread_local_alloc_id: share code with Memory::get_global_alloc --- src/thread.rs | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/src/thread.rs b/src/thread.rs index 0a83b71665c5..8d493ac8f3bd 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -11,7 +11,6 @@ use log::trace; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; use rustc_index::vec::{Idx, IndexVec}; -use rustc_middle::ty::{self, Instance}; use crate::sync::SynchronizationState; use crate::*; @@ -497,9 +496,6 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Get a thread-specific allocation id for the given thread-local static. /// If needed, allocate a new one. - /// - /// FIXME: This method should be replaced as soon as - /// https://github.com/rust-lang/rust/issues/70685 gets fixed. fn get_or_create_thread_local_alloc_id(&self, def_id: DefId) -> InterpResult<'tcx, AllocId> { let this = self.eval_context_ref(); let tcx = this.tcx; @@ -511,29 +507,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We need to allocate a thread-specific allocation id for this // thread-local static. // - // At first, we invoke the `const_eval_raw` query and extract the - // allocation from it. Unfortunately, we have to duplicate the code - // from `Memory::get_global_alloc` that does this. - // + // At first, we compute the initial value for this static. // Then we store the retrieved allocation back into the `alloc_map` // to get a fresh allocation id, which we can use as a // thread-specific allocation id for the thread-local static. + // On first access to that allocation, it will be copied over to the machine memory. if tcx.is_foreign_item(def_id) { throw_unsup_format!("foreign thread-local statics are not supported"); } - // Invoke the `const_eval_raw` query. - let instance = Instance::mono(tcx.tcx, def_id); - let gid = GlobalId { instance, promoted: None }; - let raw_const = - tcx.const_eval_raw(ty::ParamEnv::reveal_all().and(gid)).map_err(|err| { - // no need to report anything, the const_eval call takes care of that - // for statics - assert!(tcx.is_static(def_id)); - err - })?; - let id = raw_const.alloc_id; - // Extract the allocation from the query result. - let allocation = tcx.global_alloc(id).unwrap_memory(); + let allocation = interpret::get_static(*tcx, def_id)?; // Create a new allocation id for the same allocation in this hacky // way. Internally, `alloc_map` deduplicates allocations, but this // is fine because Miri will make a copy before a first mutable From 390899e8b9c9b3b415a630e663418f1ad7e10c4d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jul 2020 15:55:15 +0200 Subject: [PATCH 2196/5092] test referencing unsupported extern static --- tests/compile-fail/extern_static.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 tests/compile-fail/extern_static.rs diff --git a/tests/compile-fail/extern_static.rs b/tests/compile-fail/extern_static.rs new file mode 100644 index 000000000000..650dfd0ac787 --- /dev/null +++ b/tests/compile-fail/extern_static.rs @@ -0,0 +1,10 @@ +#![feature(raw_ref_op)] +//! Even referencing an unknown `extern static` already triggers an error. + +extern "C" { + static mut FOO: i32; +} + +fn main() { + let _val = unsafe { &raw const FOO }; //~ ERROR is not supported by Miri +} From 2a42f8e93c3be903cbfd940cbee3299506e184c7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jul 2020 15:53:02 +0200 Subject: [PATCH 2197/5092] fix and test order of TLS dtors and thread joining --- src/shims/tls.rs | 4 +-- src/thread.rs | 26 ++++++++++++++----- tests/run-pass/concurrency/tls_lib_drop.rs | 8 +++--- .../run-pass/concurrency/tls_lib_drop.stdout | 6 ++--- 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 8d05442ad6bc..4a0d5fc22ad6 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -328,9 +328,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// schedules them one by one each time it is called and reenables the /// thread so that it can be executed normally by the main execution loop. /// - /// FIXME: we do not support yet deallocation of thread local statics. - /// Issue: https://github.com/rust-lang/miri/issues/1369 - /// /// Note: we consistently run TLS destructors for all threads, including the /// main thread. However, it is not clear that we should run the TLS /// destructors for the main thread. See issue: @@ -367,6 +364,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // All dtors done! this.machine.tls.delete_all_thread_tls(active_thread); + this.thread_terminated(); Ok(()) } diff --git a/src/thread.rs b/src/thread.rs index 8d493ac8f3bd..8520dcd073a7 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -410,6 +410,20 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { None } + /// Handles thread termination of the active thread: wakes up threads joining on this one, + /// and deallocated thread-local statics. + /// + /// This is called from `tls.rs` after handling the TLS dtors. + fn thread_terminated(&mut self) { + for (i, thread) in self.threads.iter_enumerated_mut() { + // Check if we need to unblock any threads. + if thread.state == ThreadState::BlockedOnJoin(self.active_thread) { + trace!("unblocking {:?} because {:?} terminated", i, self.active_thread); + thread.state = ThreadState::Enabled; + } + } + } + /// Decide which action to take next and on which thread. /// /// The currently implemented scheduling policy is the one that is commonly @@ -421,13 +435,6 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { // checks whether the thread has popped all its stack and if yes, sets // the thread state to terminated). if self.threads[self.active_thread].check_terminated() { - // Check if we need to unblock any threads. - for (i, thread) in self.threads.iter_enumerated_mut() { - if thread.state == ThreadState::BlockedOnJoin(self.active_thread) { - trace!("unblocking {:?} because {:?} terminated", i, self.active_thread); - thread.state = ThreadState::Enabled; - } - } return Ok(SchedulingAction::ExecuteDtors); } if self.threads[MAIN_THREAD].state == ThreadState::Terminated { @@ -660,4 +667,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.machine.threads.schedule() } + + #[inline] + fn thread_terminated(&mut self) { + self.eval_context_mut().machine.threads.thread_terminated() + } } diff --git a/tests/run-pass/concurrency/tls_lib_drop.rs b/tests/run-pass/concurrency/tls_lib_drop.rs index de2566de85c6..46f59ef6204f 100644 --- a/tests/run-pass/concurrency/tls_lib_drop.rs +++ b/tests/run-pass/concurrency/tls_lib_drop.rs @@ -9,7 +9,8 @@ struct TestCell { impl Drop for TestCell { fn drop(&mut self) { - println!("Dropping: {}", self.value.borrow()) + for _ in 0..10 { thread::yield_now(); } + println!("Dropping: {} (should be before 'Continue main 1').", self.value.borrow()) } } @@ -28,7 +29,7 @@ fn check_destructors() { }) .join() .unwrap(); - println!("Continue main.") + println!("Continue main 1.") } struct JoinCell { @@ -37,8 +38,9 @@ struct JoinCell { impl Drop for JoinCell { fn drop(&mut self) { + for _ in 0..10 { thread::yield_now(); } let join_handle = self.value.borrow_mut().take().unwrap(); - println!("Joining: {}", join_handle.join().unwrap()); + println!("Joining: {} (should be before 'Continue main 2').", join_handle.join().unwrap()); } } diff --git a/tests/run-pass/concurrency/tls_lib_drop.stdout b/tests/run-pass/concurrency/tls_lib_drop.stdout index d622c0ccce88..484979b04ca7 100644 --- a/tests/run-pass/concurrency/tls_lib_drop.stdout +++ b/tests/run-pass/concurrency/tls_lib_drop.stdout @@ -1,4 +1,4 @@ -Dropping: 5 -Continue main. +Dropping: 5 (should be before 'Continue main 1'). +Continue main 1. +Joining: 7 (should be before 'Continue main 2'). Continue main 2. -Joining: 7 From c77540ce13890ba5f16f276967e86f8d7fb8f78e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jul 2020 12:53:39 +0200 Subject: [PATCH 2198/5092] deallocate thread-local statics when the thread dies --- src/machine.rs | 16 ++++-- src/shims/env.rs | 4 +- src/shims/tls.rs | 2 +- src/stacked_borrows.rs | 4 +- src/thread.rs | 56 ++++++++++++------- .../thread_local_static_dealloc.rs | 13 +++++ 6 files changed, 63 insertions(+), 32 deletions(-) create mode 100644 tests/compile-fail/concurrency/thread_local_static_dealloc.rs diff --git a/src/machine.rs b/src/machine.rs index d418409df067..5dfe99627437 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -64,7 +64,10 @@ pub enum MiriMemoryKind { Global, /// Memory for extern statics. /// This memory may leak. - ExternGlobal, + ExternStatic, + /// Memory for thread-local statics. + /// This memory may leak. + Tls, } impl Into> for MiriMemoryKind { @@ -80,7 +83,7 @@ impl MayLeak for MiriMemoryKind { use self::MiriMemoryKind::*; match self { Rust | C | WinHeap | Env => false, - Machine | Global | ExternGlobal => true, + Machine | Global | ExternStatic | Tls => true, } } } @@ -94,8 +97,9 @@ impl fmt::Display for MiriMemoryKind { WinHeap => write!(f, "Windows heap"), Machine => write!(f, "machine-managed memory"), Env => write!(f, "environment variable"), - Global => write!(f, "global"), - ExternGlobal => write!(f, "extern global"), + Global => write!(f, "global (static or const)"), + ExternStatic => write!(f, "extern static"), + Tls => write!(f, "thread-local static"), } } } @@ -175,7 +179,7 @@ impl MemoryExtra { // "__cxa_thread_atexit_impl" // This should be all-zero, pointer-sized. let layout = this.machine.layouts.usize; - let place = this.allocate(layout, MiriMemoryKind::ExternGlobal.into()); + let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into()); this.write_scalar(Scalar::from_machine_usize(0, this), place.into())?; Self::add_extern_static(this, "__cxa_thread_atexit_impl", place.ptr); // "environ" @@ -185,7 +189,7 @@ impl MemoryExtra { // "_tls_used" // This is some obscure hack that is part of the Windows TLS story. It's a `u8`. let layout = this.machine.layouts.u8; - let place = this.allocate(layout, MiriMemoryKind::ExternGlobal.into()); + let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into()); this.write_scalar(Scalar::from_u8(0), place.into())?; Self::add_extern_static(this, "_tls_used", place.ptr); } diff --git a/src/shims/env.rs b/src/shims/env.rs index 86a7a58ac4aa..d7474dbf87ef 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -383,9 +383,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.memory.deallocate(this.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Env.into())?; } else { // No `environ` allocated yet, let's do that. - // This is memory backing an extern static, hence `ExternGlobal`, not `Env`. + // This is memory backing an extern static, hence `ExternStatic`, not `Env`. let layout = this.machine.layouts.usize; - let place = this.allocate(layout, MiriMemoryKind::ExternGlobal.into()); + let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into()); this.machine.env_vars.environ = Some(place); } diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 4a0d5fc22ad6..d92945974007 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -364,7 +364,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // All dtors done! this.machine.tls.delete_all_thread_tls(active_thread); - this.thread_terminated(); + this.thread_terminated()?; Ok(()) } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 6942acc5e2b0..cefe334574b4 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -469,10 +469,10 @@ impl Stacks { // `Global` memory can be referenced by global pointers from `tcx`. // Thus we call `global_base_ptr` such that the global pointers get the same tag // as what we use here. - // `ExternGlobal` is used for extern statics, and thus must also be listed here. + // `ExternStatic` is used for extern statics, and thus must also be listed here. // `Env` we list because we can get away with precise tracking there. // The base pointer is not unique, so the base permission is `SharedReadWrite`. - MemoryKind::Machine(MiriMemoryKind::Global | MiriMemoryKind::ExternGlobal | MiriMemoryKind::Env) => + MemoryKind::Machine(MiriMemoryKind::Global | MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls | MiriMemoryKind::Env) => (extra.borrow_mut().global_base_ptr(id), Permission::SharedReadWrite), // Everything else we handle entirely untagged for now. // FIXME: experiment with more precise tracking. diff --git a/src/thread.rs b/src/thread.rs index 8520dcd073a7..1e710a25edc9 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -410,18 +410,31 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { None } - /// Handles thread termination of the active thread: wakes up threads joining on this one, - /// and deallocated thread-local statics. - /// - /// This is called from `tls.rs` after handling the TLS dtors. - fn thread_terminated(&mut self) { + /// Wakes up threads joining on the active one and deallocates thread-local statics. + /// The `AllocId` that can now be freed is returned. + fn thread_terminated(&mut self) -> Vec { + let mut free_tls_statics = Vec::new(); + { + let mut thread_local_statics = self.thread_local_alloc_ids.borrow_mut(); + thread_local_statics.retain(|&(_def_id, thread), &mut alloc_id| { + if thread != self.active_thread { + // Keep this static around. + return true; + } + // Delete this static from the map and from memory. + // We cannot free directly here as we cannot use `?` in this context. + free_tls_statics.push(alloc_id); + return false; + }); + } + // Check if we need to unblock any threads. for (i, thread) in self.threads.iter_enumerated_mut() { - // Check if we need to unblock any threads. if thread.state == ThreadState::BlockedOnJoin(self.active_thread) { trace!("unblocking {:?} because {:?} terminated", i, self.active_thread); thread.state = ThreadState::Enabled; } } + return free_tls_statics; } /// Decide which action to take next and on which thread. @@ -503,8 +516,8 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Get a thread-specific allocation id for the given thread-local static. /// If needed, allocate a new one. - fn get_or_create_thread_local_alloc_id(&self, def_id: DefId) -> InterpResult<'tcx, AllocId> { - let this = self.eval_context_ref(); + fn get_or_create_thread_local_alloc_id(&mut self, def_id: DefId) -> InterpResult<'tcx, AllocId> { + let this = self.eval_context_mut(); let tcx = this.tcx; if let Some(new_alloc_id) = this.machine.threads.get_thread_local_alloc_id(def_id) { // We already have a thread-specific allocation id for this @@ -513,21 +526,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { // We need to allocate a thread-specific allocation id for this // thread-local static. - // - // At first, we compute the initial value for this static. - // Then we store the retrieved allocation back into the `alloc_map` - // to get a fresh allocation id, which we can use as a - // thread-specific allocation id for the thread-local static. - // On first access to that allocation, it will be copied over to the machine memory. + // First, we compute the initial value for this static. if tcx.is_foreign_item(def_id) { throw_unsup_format!("foreign thread-local statics are not supported"); } let allocation = interpret::get_static(*tcx, def_id)?; - // Create a new allocation id for the same allocation in this hacky - // way. Internally, `alloc_map` deduplicates allocations, but this - // is fine because Miri will make a copy before a first mutable - // access. - let new_alloc_id = tcx.create_memory_alloc(allocation); + // Create a fresh allocation with this content. + let new_alloc_id = this.memory.allocate_with(allocation.clone(), MiriMemoryKind::Tls.into()).alloc_id; this.machine.threads.set_thread_local_alloc_id(def_id, new_alloc_id); Ok(new_alloc_id) } @@ -668,8 +673,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.threads.schedule() } + /// Handles thread termination of the active thread: wakes up threads joining on this one, + /// and deallocated thread-local statics. + /// + /// This is called from `tls.rs` after handling the TLS dtors. #[inline] - fn thread_terminated(&mut self) { - self.eval_context_mut().machine.threads.thread_terminated() + fn thread_terminated(&mut self) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + for alloc_id in this.machine.threads.thread_terminated() { + let ptr = this.memory.global_base_pointer(alloc_id.into())?; + this.memory.deallocate(ptr, None, MiriMemoryKind::Tls.into())?; + } + Ok(()) } } diff --git a/tests/compile-fail/concurrency/thread_local_static_dealloc.rs b/tests/compile-fail/concurrency/thread_local_static_dealloc.rs new file mode 100644 index 000000000000..1b20ce8bfb38 --- /dev/null +++ b/tests/compile-fail/concurrency/thread_local_static_dealloc.rs @@ -0,0 +1,13 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +//! Ensure that thread-local statics get deallocated when the thread dies. + +#![feature(thread_local)] + +#[thread_local] +static mut TLS: u8 = 0; + +fn main() { unsafe { + let dangling_ptr = std::thread::spawn(|| &TLS as *const u8 as usize).join().unwrap(); + let _val = *(dangling_ptr as *const u8); +} } From 6fbaa72642dacf92746c695046c8dfe6834ef18f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jul 2020 13:10:11 +0200 Subject: [PATCH 2199/5092] fix diagnostics printing when triggered during TLS dtor scheduling --- src/diagnostics.rs | 24 ++++++++++++++++++------ src/eval.rs | 4 ++-- src/shims/tls.rs | 3 +++ 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 3c6486244591..2e8809cd7361 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -162,7 +162,15 @@ fn report_msg<'tcx>( } else { tcx.sess.diagnostic().span_note_diag(span, title) }; - err.span_label(span, span_msg); + // Show main message. + if span != DUMMY_SP { + err.span_label(span, span_msg); + } else { + // Make sure we show the message even when it is a dummy span. + err.note(&span_msg); + err.note("(no span available)"); + } + // Show help messages. if !helps.is_empty() { // Add visual separator before backtrace. helps.last_mut().unwrap().push_str("\n"); @@ -198,7 +206,7 @@ pub fn register_diagnostic(e: NonHaltingDiagnostic) { /// after a step was taken. pub struct TopFrameInfo<'tcx> { stack_size: usize, - instance: ty::Instance<'tcx>, + instance: Option>, span: Span, } @@ -209,11 +217,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx DIAGNOSTICS.with(|diagnostics| assert!(diagnostics.borrow().is_empty())); let this = self.eval_context_ref(); + if this.active_thread_stack().is_empty() { + // Diagnostics can happen even with the emoty stack (e.g. deallocation thread-local statics). + return TopFrameInfo { stack_size: 0, instance: None, span: DUMMY_SP }; + } let frame = this.frame(); TopFrameInfo { stack_size: this.active_thread_stack().len(), - instance: frame.instance, + instance: Some(frame.instance), span: frame.current_source_info().map_or(DUMMY_SP, |si| si.span), } } @@ -237,15 +249,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if stacktrace.len() < info.stack_size { assert!(stacktrace.len() == info.stack_size-1, "we should never pop more than one frame at once"); let frame_info = FrameInfo { - instance: info.instance, + instance: info.instance.unwrap(), span: info.span, lint_root: None, }; stacktrace.insert(0, frame_info); - } else { + } else if let Some(instance) = info.instance { // Adjust topmost frame. stacktrace[0].span = info.span; - assert_eq!(stacktrace[0].instance, info.instance, "we should not pop and push a frame in one step"); + assert_eq!(stacktrace[0].instance, instance, "we should not pop and push a frame in one step"); } // Show diagnostics. diff --git a/src/eval.rs b/src/eval.rs index 8561edcc05b9..cc5a6eb21fab 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -211,11 +211,10 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> let res: InterpResult<'_, i64> = (|| { // Main loop. loop { + let info = ecx.preprocess_diagnostics(); match ecx.schedule()? { SchedulingAction::ExecuteStep => { - let info = ecx.preprocess_diagnostics(); assert!(ecx.step()?, "a terminated thread was scheduled for execution"); - ecx.process_diagnostics(info); } SchedulingAction::ExecuteTimeoutCallback => { assert!(ecx.machine.communicate, @@ -233,6 +232,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> break; } } + ecx.process_diagnostics(info); } let return_code = ecx.read_scalar(ret_place.into())?.check_init()?.to_machine_isize(&ecx)?; Ok(return_code) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index d92945974007..2ba0782f7054 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -348,6 +348,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(()) } } + // The remaining dtors make some progress each time around the scheduler loop, + // until they return `false` to indicate that they are done. + // The macOS thread wide destructor runs "before any TLS slots get // freed", so do that first. if this.schedule_macos_tls_dtor()? { From bec7aab7fd089d89e940029038669f851d497caa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jul 2020 14:10:31 +0200 Subject: [PATCH 2200/5092] Typos Co-authored-by: Oliver Scherer --- src/diagnostics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 2e8809cd7361..1b41ba441837 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -218,7 +218,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); if this.active_thread_stack().is_empty() { - // Diagnostics can happen even with the emoty stack (e.g. deallocation thread-local statics). + // Diagnostics can happen even with the empty stack (e.g. deallocation of thread-local statics). return TopFrameInfo { stack_size: 0, instance: None, span: DUMMY_SP }; } let frame = this.frame(); From cae90b6d293dc0e9bb3275457a94323bd14d51a1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jul 2020 23:40:27 +0200 Subject: [PATCH 2201/5092] rustup and test fixes --- rust-version | 2 +- tests/compile-fail/concurrency/thread_local_static_dealloc.rs | 2 +- tests/run-pass/panic/catch_panic.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 211af60b88aa..3f188639fa3d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -13f9aa190957b993a268fd4a046fce76ca8814ee +efc02b03d18b0cbaa55b1e421d792f70a39230b2 diff --git a/tests/compile-fail/concurrency/thread_local_static_dealloc.rs b/tests/compile-fail/concurrency/thread_local_static_dealloc.rs index 1b20ce8bfb38..73e4ab596585 100644 --- a/tests/compile-fail/concurrency/thread_local_static_dealloc.rs +++ b/tests/compile-fail/concurrency/thread_local_static_dealloc.rs @@ -9,5 +9,5 @@ static mut TLS: u8 = 0; fn main() { unsafe { let dangling_ptr = std::thread::spawn(|| &TLS as *const u8 as usize).join().unwrap(); - let _val = *(dangling_ptr as *const u8); + let _val = *(dangling_ptr as *const u8); //~ ERROR dereferenced after this allocation got freed } } diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index ac41de586e8a..811c370d812f 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -1,4 +1,4 @@ -// normalize-stderr-test "[^ ]*libcore/[a-z/]+.rs[0-9:]*" -> "$$LOC" +// normalize-stderr-test "[^ ]*libcore/[a-z_/]+.rs[0-9:]*" -> "$$LOC" #![feature(never_type)] #![allow(unconditional_panic)] From ee39ac9840519e7b5a90d9f0f506a092f4177cd9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 28 Jul 2020 14:00:33 +0200 Subject: [PATCH 2202/5092] rustup for new folder layout --- cargo-miri/bin.rs | 8 ++++---- rust-version | 2 +- tests/run-pass/panic/catch_panic.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 33a1124aaba0..000a4d41cc5d 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -10,7 +10,7 @@ use std::process::Command; use rustc_version::VersionMeta; -const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 21); +const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 22); const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and tests in Miri @@ -271,10 +271,10 @@ fn setup(subcommand: MiriCommand) { .stdout; let sysroot = std::str::from_utf8(&sysroot).unwrap(); let sysroot = Path::new(sysroot.trim_end_matches('\n')); - // Check for `$SYSROOT/lib/rustlib/src/rust/src`; test if that contains `libstd/lib.rs`. + // Check for `$SYSROOT/lib/rustlib/src/rust/library`; test if that contains `std/Cargo.toml`. let rustup_src = - sysroot.join("lib").join("rustlib").join("src").join("rust").join("src"); - if !rustup_src.join("libstd").join("lib.rs").exists() { + sysroot.join("lib").join("rustlib").join("src").join("rust").join("library"); + if !rustup_src.join("std").join("Cargo.toml").exists() { // Ask the user to install the `rust-src` component, and use that. let mut cmd = Command::new("rustup"); cmd.args(&["component", "add", "rust-src"]); diff --git a/rust-version b/rust-version index 3f188639fa3d..1ba022ac9694 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -efc02b03d18b0cbaa55b1e421d792f70a39230b2 +1454bbd4fdac9b7272b93fe82860613dccc0afad diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index 811c370d812f..6dc47f2f591a 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -1,4 +1,4 @@ -// normalize-stderr-test "[^ ]*libcore/[a-z_/]+.rs[0-9:]*" -> "$$LOC" +// normalize-stderr-test "[^ ]*core/[a-z_/]+.rs[0-9:]*" -> "$$LOC" #![feature(never_type)] #![allow(unconditional_panic)] From 797436cefb8dcc0c54a0712874602fe2900f5c00 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 Jul 2020 18:21:32 +0200 Subject: [PATCH 2203/5092] only check-build the dummy xargo project --- cargo-miri/bin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 000a4d41cc5d..85d72daadbdf 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -338,7 +338,7 @@ path = "lib.rs" let target = target.as_ref().unwrap_or(&host); // Now invoke xargo. let mut command = xargo_check(); - command.arg("build").arg("-q"); + command.arg("check").arg("-q"); command.arg("--target").arg(target); command.current_dir(&dir); command.env("XARGO_HOME", &dir); From d340933112da9e5dcca01f6f9e6e024c31a9e4b8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Jul 2020 18:31:19 +0200 Subject: [PATCH 2204/5092] rustup --- rust-version | 2 +- src/diagnostics.rs | 3 +-- src/shims/foreign_items.rs | 4 +++- src/shims/intrinsics.rs | 4 +++- src/shims/posix/macos/dlsym.rs | 4 +++- src/shims/windows/dlsym.rs | 4 +++- 6 files changed, 14 insertions(+), 7 deletions(-) diff --git a/rust-version b/rust-version index 1ba022ac9694..0765203ccbc3 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1454bbd4fdac9b7272b93fe82860613dccc0afad +21867225a74d3b07c2b65e32c67f45197db36896 diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 1b41ba441837..a20e8126c13a 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -137,8 +137,7 @@ pub fn report_error<'tcx, 'mir>( access.uninit_ptr.offset.bytes(), access.uninit_ptr.offset.bytes() + access.uninit_size.bytes(), ); - ecx.memory.dump_alloc(access.uninit_ptr.alloc_id); - eprintln!(); + eprintln!("{:?}", ecx.memory.dump_alloc(access.uninit_ptr.alloc_id)); } _ => {} } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 98e66db92da3..0379ec0c0778 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -1,5 +1,7 @@ use std::{convert::{TryInto, TryFrom}, iter}; +use log::trace; + use rustc_hir::def_id::DefId; use rustc_middle::{mir, ty}; use rustc_target::abi::{Align, Size}; @@ -175,7 +177,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Third: functions that return. if this.emulate_foreign_item_by_name(link_name, args, dest, ret)? { - this.dump_place(*dest); + trace!("{:?}", this.dump_place(*dest)); this.go_to_block(ret); } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index ee64b1ffca44..105026c70d83 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -1,5 +1,7 @@ use std::iter; +use log::trace; + use rustc_attr as attr; use rustc_ast::ast::FloatTy; use rustc_middle::{mir, ty}; @@ -524,7 +526,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name => throw_unsup_format!("unimplemented intrinsic: {}", name), } - this.dump_place(*dest); + trace!("{:?}", this.dump_place(*dest)); this.go_to_block(ret); Ok(()) } diff --git a/src/shims/posix/macos/dlsym.rs b/src/shims/posix/macos/dlsym.rs index 0236b10e5fc8..c9f57090ff8a 100644 --- a/src/shims/posix/macos/dlsym.rs +++ b/src/shims/posix/macos/dlsym.rs @@ -1,5 +1,7 @@ use rustc_middle::mir; +use log::trace; + use crate::*; use helpers::check_arg_count; @@ -42,7 +44,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - this.dump_place(*dest); + trace!("{:?}", this.dump_place(*dest)); this.go_to_block(ret); Ok(()) } diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 737fd4314f63..91bfedff8db6 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -1,5 +1,7 @@ use rustc_middle::mir; +use log::trace; + use crate::*; use helpers::check_arg_count; use shims::windows::sync::EvalContextExt as _; @@ -73,7 +75,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - this.dump_place(*dest); + trace!("{:?}", this.dump_place(*dest)); this.go_to_block(ret); Ok(()) } From 2dfde5b696b4f84907da50f151aafc322c975d94 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Jul 2020 18:31:40 +0200 Subject: [PATCH 2205/5092] remove upstreamed intrinsic impls --- src/shims/intrinsics.rs | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 105026c70d83..53d4d08eba0d 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -484,24 +484,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - "min_align_of_val" => { - let &[mplace] = check_arg_count(args)?; - let mplace = this.deref_operand(mplace)?; - let (_, align) = this - .size_and_align_of_mplace(mplace)? - .expect("size_of_val called on extern type"); - this.write_scalar(Scalar::from_machine_usize(align.bytes(), this), dest)?; - } - - "size_of_val" => { - let &[mplace] = check_arg_count(args)?; - let mplace = this.deref_operand(mplace)?; - let (size, _) = this - .size_and_align_of_mplace(mplace)? - .expect("size_of_val called on extern type"); - this.write_scalar(Scalar::from_machine_usize(size.bytes(), this), dest)?; - } - // Other "assume" => { let &[cond] = check_arg_count(args)?; From 729ccbc65e6d1e0004fba28aaa7a3c9c9408c15c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 31 Jul 2020 18:30:07 +0200 Subject: [PATCH 2206/5092] test track_caller on trait objects --- tests/run-pass/track-caller-attribute.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/run-pass/track-caller-attribute.rs b/tests/run-pass/track-caller-attribute.rs index be655703daa0..a9cfd2e0ebde 100644 --- a/tests/run-pass/track-caller-attribute.rs +++ b/tests/run-pass/track-caller-attribute.rs @@ -35,6 +35,28 @@ fn test_fn_ptr() { pass_to_ptr_call(tracked_unit, ()); } +fn test_trait_obj() { + trait Tracked { + #[track_caller] + fn handle(&self) { // `fn` here is what the `location` should point at. + let location = std::panic::Location::caller(); + assert_eq!(location.file(), file!()); + // we only call this via trait object, so the def site should *always* be returned + assert_eq!(location.line(), line!() - 4); + assert_eq!(location.column(), 9); + } + } + + impl Tracked for () {} + impl Tracked for u8 {} + + let tracked: &dyn Tracked = &5u8; + tracked.handle(); + + const TRACKED: &dyn Tracked = &(); + TRACKED.handle(); +} + fn main() { let location = Location::caller(); let expected_line = line!() - 1; @@ -73,4 +95,5 @@ fn main() { assert_eq!(intrinsic.column(), 21); test_fn_ptr(); + test_trait_obj(); } From 35309a200ba880b2c5203e16a115ab14d0088e12 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 1 Aug 2020 14:18:52 +0200 Subject: [PATCH 2207/5092] rustup; fix linked_list test --- rust-version | 2 +- tests/run-pass/linked-list.rs | 22 ++++++++++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/rust-version b/rust-version index 0765203ccbc3..7c4b8a50cc28 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -21867225a74d3b07c2b65e32c67f45197db36896 +dfe1e3b641abbede6230e3931d14f0d43e5b8e54 diff --git a/tests/run-pass/linked-list.rs b/tests/run-pass/linked-list.rs index f1d21728b2f0..976a35da6061 100644 --- a/tests/run-pass/linked-list.rs +++ b/tests/run-pass/linked-list.rs @@ -1,4 +1,4 @@ -#![feature(linked_list_extras)] +#![feature(linked_list_cursors)] use std::collections::LinkedList; fn list_from(v: &[T]) -> LinkedList { @@ -9,25 +9,27 @@ fn main() { let mut m = list_from(&[0, 2, 4, 6, 8]); let len = m.len(); { - let mut it = m.iter_mut(); - it.insert_next(-2); + let mut it = m.cursor_front_mut(); + it.insert_before(-2); loop { - match it.next() { + match it.current().copied() { None => break, Some(elt) => { - it.insert_next(*elt + 1); match it.peek_next() { - Some(x) => assert_eq!(*x, *elt + 2), - None => assert_eq!(8, *elt), + Some(x) => assert_eq!(*x, elt + 2), + None => assert_eq!(8, elt), } + it.insert_after(elt + 1); + it.move_next(); // Move by 2 to skip the one we inserted. + it.move_next(); } } } - it.insert_next(0); - it.insert_next(1); + it.insert_before(99); + it.insert_after(-10); } assert_eq!(m.len(), 3 + len * 2); assert_eq!(m.into_iter().collect::>(), - [-2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1]); + [-10, -2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 99]); } From 5d221450690cc0a31da829563042762dff3139df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 31 Jul 2020 19:28:59 +0200 Subject: [PATCH 2208/5092] test unwinding past topmost frame of a stack --- .../concurrency/unwind_top_of_stack.rs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 tests/compile-fail/concurrency/unwind_top_of_stack.rs diff --git a/tests/compile-fail/concurrency/unwind_top_of_stack.rs b/tests/compile-fail/concurrency/unwind_top_of_stack.rs new file mode 100644 index 000000000000..93b15202fc38 --- /dev/null +++ b/tests/compile-fail/concurrency/unwind_top_of_stack.rs @@ -0,0 +1,24 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// error-pattern: unwinding past the topmost frame of the stack + +//! Unwinding past the top frame of a stack is Undefined Behavior. + +#![feature(rustc_private)] + +extern crate libc; + +use std::{mem, ptr}; + +extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { + panic!() +} + +fn main() { + unsafe { + let mut native: libc::pthread_t = mem::zeroed(); + let attr: libc::pthread_attr_t = mem::zeroed(); + // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented. + assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0); + assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); + } +} From e3956f4200184c88f0f6100f15669b1e6639804f Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Fri, 31 Jul 2020 22:53:35 +0530 Subject: [PATCH 2209/5092] Add FileDescriptor trait to abstract fn's on File's and Std{in,out,err} --- src/machine.rs | 2 +- src/shims/posix/fs.rs | 190 ++++++++++++++++++++++++++++-------------- 2 files changed, 130 insertions(+), 62 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index e9217896ef6e..bcdd92070942 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -246,7 +246,7 @@ pub struct Evaluator<'mir, 'tcx> { /// Whether to enforce the validity invariant. pub(crate) validate: bool, - pub(crate) file_handler: shims::posix::FileHandler, + pub(crate) file_handler: shims::posix::FileHandler<'tcx>, pub(crate) dir_handler: shims::posix::DirHandler, /// The temporary used for storing the argument of diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index a43e86dcc5b5..5415e9e1f77c 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use std::convert::{TryFrom, TryInto}; use std::fs::{read_dir, remove_dir, remove_file, rename, DirBuilder, File, FileType, OpenOptions, ReadDir}; -use std::io::{Read, Seek, SeekFrom, Write}; +use std::io::{self, Read, Seek, SeekFrom, Write}; use std::path::Path; use std::time::SystemTime; @@ -22,15 +22,42 @@ struct FileHandle { writable: bool, } -#[derive(Debug, Default)] -pub struct FileHandler { - handles: BTreeMap, +trait FileDescriptor<'tcx> : std::fmt::Debug { + fn as_file_handle(&self) -> InterpResult<'tcx, &FileHandle>; + + fn read(&mut self, bytes: &mut [u8]) -> Result; + fn write(&mut self, bytes: &[u8]) -> Result; + fn seek(&mut self, offset: SeekFrom) -> Result; } +impl<'tcx> FileDescriptor<'tcx> for FileHandle { + fn as_file_handle(&self) -> InterpResult<'tcx, &FileHandle> { + Ok(&self) + } + + fn read(&mut self, bytes: &mut [u8]) -> Result { + self.file.read(bytes) + } + + fn write(&mut self, bytes: &[u8]) -> Result { + self.file.write(bytes) + } + + fn seek(&mut self, offset: SeekFrom) -> Result { + self.file.seek(offset) + } +} + +#[derive(Debug, Default)] +pub struct FileHandler<'tcx> { + handles: BTreeMap>>, +} + + // fd numbers 0, 1, and 2 are reserved for stdin, stdout, and stderr const MIN_NORMAL_FILE_FD: i32 = 3; -impl FileHandler { +impl<'tcx> FileHandler<'tcx> { fn insert_fd(&mut self, file_handle: FileHandle) -> i32 { self.insert_fd_with_min_fd(file_handle, 0) } @@ -62,7 +89,7 @@ impl FileHandler { self.handles.last_key_value().map(|(fd, _)| fd.checked_add(1).unwrap()).unwrap_or(min_fd) }); - self.handles.insert(new_fd, file_handle).unwrap_none(); + self.handles.insert(new_fd, Box::new(file_handle)).unwrap_none(); new_fd } } @@ -383,20 +410,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let fh = &mut this.machine.file_handler; let (file_result, writable) = match fh.handles.get(&fd) { - Some(FileHandle { file, writable }) => (file.try_clone(), *writable), + Some(file_descriptor) => match file_descriptor.as_file_handle() { + Ok(FileHandle { file, writable }) => (file.try_clone(), writable.clone()), + Err(_) => return this.handle_not_found(), + }, None => return this.handle_not_found(), }; let fd_result = file_result.map(|duplicated| { - fh.insert_fd_with_min_fd(FileHandle { file: duplicated, writable }, start) + fh.insert_fd_with_min_fd(FileHandle { file: duplicated, writable: writable }, start) }); this.try_unwrap_io_result(fd_result) } else if this.tcx.sess.target.target.target_os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC")? { let &[_, _] = check_arg_count(args)?; - if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get(&fd) { - let io_result = maybe_sync_file(file, *writable, File::sync_all); - this.try_unwrap_io_result(io_result) + if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { + match file_descriptor.as_file_handle() { + Ok(FileHandle { file, writable }) => { + let io_result = maybe_sync_file(&file, *writable, File::sync_all); + this.try_unwrap_io_result(io_result) + }, + Err(_) => this.handle_not_found(), + } } else { this.handle_not_found() } @@ -412,24 +447,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; - if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.remove(&fd) { - // We sync the file if it was opened in a mode different than read-only. - if writable { - // `File::sync_all` does the checks that are done when closing a file. We do this to - // to handle possible errors correctly. - let result = this.try_unwrap_io_result(file.sync_all().map(|_| 0i32)); - // Now we actually close the file. - drop(file); - // And return the result. - result - } else { - // We drop the file, this closes it but ignores any errors produced when closing - // it. This is done because `File::sync_all` cannot be done over files like - // `/dev/urandom` which are read-only. Check - // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439 for a deeper - // discussion. - drop(file); - Ok(0) + if let Some(file_descriptor) = this.machine.file_handler.handles.remove(&fd) { + match file_descriptor.as_file_handle() { + Ok(FileHandle { file, writable }) => { + // We sync the file if it was opened in a mode different than read-only. + if *writable { + // `File::sync_all` does the checks that are done when closing a file. We do this to + // to handle possible errors correctly. + let result = this.try_unwrap_io_result(file.sync_all().map(|_| 0i32)); + // Now we actually close the file. + drop(file); + // And return the result. + result + } else { + // We drop the file, this closes it but ignores any errors produced when closing + // it. This is done because `File::sync_all` cannot be done over files like + // `/dev/urandom` which are read-only. Check + // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439 for a deeper + // discussion. + drop(file); + Ok(0) + } + }, + Err(_) => this.handle_not_found() } } else { this.handle_not_found() @@ -460,15 +500,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // host's and target's `isize`. This saves us from having to handle overflows later. let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64); - if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { - trace!("read: FD mapped to {:?}", file); + if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { + trace!("read: FD mapped to {:?}", file_descriptor); // We want to read at most `count` bytes. We are sure that `count` is not negative // because it was a target's `usize`. Also we are sure that its smaller than // `usize::MAX` because it is a host's `isize`. let mut bytes = vec![0; count as usize]; - let result = file + // `File::read` never returns a value larger than `count`, + // so this cannot fail. + let result = file_descriptor .read(&mut bytes) - // `File::read` never returns a value larger than `count`, so this cannot fail. .map(|c| i64::try_from(c).unwrap()); match result { @@ -510,9 +551,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // host's and target's `isize`. This saves us from having to handle overflows later. let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64); - if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { + if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; - let result = file.write(&bytes).map(|c| i64::try_from(c).unwrap()); + let result = file_descriptor + .write(&bytes) + .map(|c| i64::try_from(c).unwrap()); this.try_unwrap_io_result(result) } else { this.handle_not_found() @@ -545,8 +588,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); }; - if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { - let result = file.seek(seek_from).map(|offset| i64::try_from(offset).unwrap()); + if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { + let result = file_descriptor + .seek(seek_from) + .map(|offset| i64::try_from(offset).unwrap()); this.try_unwrap_io_result(result) } else { this.handle_not_found() @@ -1103,21 +1148,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; let length = this.read_scalar(length_op)?.to_i64()?; - if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get_mut(&fd) { - if *writable { - if let Ok(length) = length.try_into() { - let result = file.set_len(length); - this.try_unwrap_io_result(result.map(|_| 0i32)) - } else { - let einval = this.eval_libc("EINVAL")?; - this.set_last_error(einval)?; - Ok(-1) + if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { + match file_descriptor.as_file_handle() { + Ok(FileHandle { file, writable }) => { + if *writable { + if let Ok(length) = length.try_into() { + let result = file.set_len(length); + this.try_unwrap_io_result(result.map(|_| 0i32)) + } else { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + Ok(-1) + } + } else { + // The file is not writable + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + Ok(-1) + } } - } else { - // The file is not writable - let einval = this.eval_libc("EINVAL")?; - this.set_last_error(einval)?; - Ok(-1) + Err(_) => this.handle_not_found() } } else { this.handle_not_found() @@ -1135,9 +1185,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("fsync")?; let fd = this.read_scalar(fd_op)?.to_i32()?; - if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get(&fd) { - let io_result = maybe_sync_file(file, *writable, File::sync_all); - this.try_unwrap_io_result(io_result) + if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { + match file_descriptor.as_file_handle() { + Ok(FileHandle { file, writable }) => { + let io_result = maybe_sync_file(&file, *writable, File::sync_all); + this.try_unwrap_io_result(io_result) + } + Err(_) => this.handle_not_found() + } } else { this.handle_not_found() } @@ -1149,9 +1204,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("fdatasync")?; let fd = this.read_scalar(fd_op)?.to_i32()?; - if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get(&fd) { - let io_result = maybe_sync_file(file, *writable, File::sync_data); - this.try_unwrap_io_result(io_result) + if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { + match file_descriptor.as_file_handle() { + Ok(FileHandle { file, writable }) => { + let io_result = maybe_sync_file(&file, *writable, File::sync_data); + this.try_unwrap_io_result(io_result) + } + Err(_) => this.handle_not_found() + } } else { this.handle_not_found() } @@ -1187,9 +1247,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } - if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get(&fd) { - let io_result = maybe_sync_file(file, *writable, File::sync_data); - this.try_unwrap_io_result(io_result) + if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { + match file_descriptor.as_file_handle() { + Ok(FileHandle { file, writable }) => { + let io_result = maybe_sync_file(&file, *writable, File::sync_data); + this.try_unwrap_io_result(io_result) + }, + Err(_) => this.handle_not_found() + } } else { this.handle_not_found() } @@ -1239,7 +1304,10 @@ impl FileMetadata { ) -> InterpResult<'tcx, Option> { let option = ecx.machine.file_handler.handles.get(&fd); let file = match option { - Some(FileHandle { file, writable: _ }) => file, + Some(file_descriptor) => match file_descriptor.as_file_handle() { + Ok(FileHandle { file, writable: _ }) => file, + Err(_) => return ecx.handle_not_found().map(|_: i32| None), + }, None => return ecx.handle_not_found().map(|_: i32| None), }; let metadata = file.metadata(); From 3386f12eca5db75ee679c5d08fecec88ae99e6a0 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Mon, 3 Aug 2020 11:01:42 +0530 Subject: [PATCH 2210/5092] Wrap io::Result from `FileDescriptor::{read,write,seek}` in InterpResult The outer InterpResult will be used to indicate that a fn is not implemented for a struct(eg. `write` for Stdin). The inner io::Result is just the result from the read/write/seek. --- src/shims/posix/fs.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 5415e9e1f77c..6f46401ece65 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -25,9 +25,9 @@ struct FileHandle { trait FileDescriptor<'tcx> : std::fmt::Debug { fn as_file_handle(&self) -> InterpResult<'tcx, &FileHandle>; - fn read(&mut self, bytes: &mut [u8]) -> Result; - fn write(&mut self, bytes: &[u8]) -> Result; - fn seek(&mut self, offset: SeekFrom) -> Result; + fn read(&mut self, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result>; + fn write(&mut self, bytes: &[u8]) -> InterpResult<'tcx, io::Result>; + fn seek(&mut self, offset: SeekFrom) -> InterpResult<'tcx, io::Result>; } impl<'tcx> FileDescriptor<'tcx> for FileHandle { @@ -35,16 +35,16 @@ impl<'tcx> FileDescriptor<'tcx> for FileHandle { Ok(&self) } - fn read(&mut self, bytes: &mut [u8]) -> Result { - self.file.read(bytes) + fn read(&mut self, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + Ok(self.file.read(bytes)) } - fn write(&mut self, bytes: &[u8]) -> Result { - self.file.write(bytes) + fn write(&mut self, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + Ok(self.file.write(bytes)) } - fn seek(&mut self, offset: SeekFrom) -> Result { - self.file.seek(offset) + fn seek(&mut self, offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + Ok(self.file.seek(offset)) } } @@ -509,7 +509,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `File::read` never returns a value larger than `count`, // so this cannot fail. let result = file_descriptor - .read(&mut bytes) + .read(&mut bytes)? .map(|c| i64::try_from(c).unwrap()); match result { @@ -554,7 +554,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; let result = file_descriptor - .write(&bytes) + .write(&bytes)? .map(|c| i64::try_from(c).unwrap()); this.try_unwrap_io_result(result) } else { @@ -590,7 +590,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { let result = file_descriptor - .seek(seek_from) + .seek(seek_from)? .map(|offset| i64::try_from(offset).unwrap()); this.try_unwrap_io_result(result) } else { From cda255cfb4f240639493e76190db9708fc08a590 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 3 Aug 2020 14:20:46 +0200 Subject: [PATCH 2211/5092] rustup; inner_deref has been stabilized --- cargo-miri/bin.rs | 2 -- rust-version | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 85d72daadbdf..a2d6c3fc5b71 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -1,5 +1,3 @@ -#![feature(inner_deref)] - use std::env; use std::ffi::OsString; use std::fs::{self, File}; diff --git a/rust-version b/rust-version index 7c4b8a50cc28..807d4e85591d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -dfe1e3b641abbede6230e3931d14f0d43e5b8e54 +dbc2ef25fb5e15445de38f19ba75547a6cf35cae From 79e066fc95c036e64716a4222c580782a9c932c2 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Mon, 3 Aug 2020 20:39:09 +0530 Subject: [PATCH 2212/5092] Remove unnecessary `clone()` on `writable` --- src/shims/posix/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 6f46401ece65..1bba30a1ea0f 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -411,13 +411,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fh = &mut this.machine.file_handler; let (file_result, writable) = match fh.handles.get(&fd) { Some(file_descriptor) => match file_descriptor.as_file_handle() { - Ok(FileHandle { file, writable }) => (file.try_clone(), writable.clone()), + Ok(FileHandle { file, writable }) => (file.try_clone(), *writable), Err(_) => return this.handle_not_found(), }, None => return this.handle_not_found(), }; let fd_result = file_result.map(|duplicated| { - fh.insert_fd_with_min_fd(FileHandle { file: duplicated, writable: writable }, start) + fh.insert_fd_with_min_fd(FileHandle { file: duplicated, writable }, start) }); this.try_unwrap_io_result(fd_result) } else if this.tcx.sess.target.target.target_os == "macos" From bea7113eb8b3ce63b95a9c6a4f8d39c7f912d9e1 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Sat, 1 Aug 2020 17:08:28 +0530 Subject: [PATCH 2213/5092] Add `impl FileDescriptor` for stdin, stdout, stderr - Use `FileDescriptor::read` for stdin reads - Use `FileDescriptor::write` for stdout/err writes - Handle stdout/err reads in `FileDescriptor::read` --- src/shims/posix/foreign_items.rs | 74 ++--------------------- src/shims/posix/fs.rs | 74 +++++++++++++++++++++-- tests/compile-fail/fs/read_from_stdout.rs | 14 +++++ tests/compile-fail/fs/write_to_stdin.rs | 14 +++++ 4 files changed, 104 insertions(+), 72 deletions(-) create mode 100644 tests/compile-fail/fs/read_from_stdout.rs create mode 100644 tests/compile-fail/fs/write_to_stdin.rs diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 4bb94ae89449..594f58d26461 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -1,5 +1,4 @@ -use std::convert::TryFrom; -use std::io::{self, Read, Write}; +use std::io::{self, Write}; use log::trace; @@ -67,43 +66,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.check_init()?; let count = this.read_scalar(count)?.to_machine_usize(this)?; - let result = if fd == 0 { - - this.check_no_isolation("read")?; - - // We cap the number of read bytes to the largest - // value that we are able to fit in both the - // host's and target's `isize`. This saves us from - // having to handle overflows later. - let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64); - - // We want to read at most `count` bytes. We are - // sure that `count` is not negative because it - // was a target's `usize`. Also we are sure that - // its smaller than `usize::MAX` because it is a - // host's `isize`. - let mut buffer = vec![0; count as usize]; - let res = io::stdin() - .read(&mut buffer) - // `Stdin::read` never returns a value larger - // than `count`, so this cannot fail. - .map(|c| i64::try_from(c).unwrap()); - - match res { - Ok(bytes) => { - this.memory.write_bytes(buf, buffer)?; - i64::try_from(bytes).unwrap() - }, - Err(e) => { - this.set_last_error_from_io_error(e)?; - -1 - }, - } - } else if fd == 1 || fd == 2 { - throw_unsup_format!("cannot read from stdout/stderr") - } else { - this.read(fd, buf, count)? - }; + let result = this.read(fd, buf, count)?; this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "write" => { @@ -112,35 +75,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.read_scalar(buf)?.check_init()?; let count = this.read_scalar(n)?.to_machine_usize(this)?; trace!("Called write({:?}, {:?}, {:?})", fd, buf, count); - let result = if fd == 0 { - throw_unsup_format!("cannot write to stdin") - } else if fd == 1 || fd == 2 { - // stdout/stderr - - let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(count))?; - // We need to flush to make sure this actually appears on the screen - let res = if fd == 1 { - // Stdout is buffered, flush to make sure it appears on the screen. - // This is the write() syscall of the interpreted program, we want it - // to correspond to a write() syscall on the host -- there is no good - // in adding extra buffering here. - let res = io::stdout().write(buf_cont); - io::stdout().flush().unwrap(); - res - } else { - // No need to flush, stderr is not buffered. - io::stderr().write(buf_cont) - }; - match res { - Ok(n) => i64::try_from(n).unwrap(), - Err(e) => { - this.set_last_error_from_io_error(e)?; - -1 - } - } - } else { - this.write(fd, buf, count)? - }; + let result = this.write(fd, buf, count)?; + if fd == 1 { + io::stdout().flush().unwrap(); + } // Now, `result` is the value we return back to the program. this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 2d784490656c..65d50aa504d3 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -48,11 +48,77 @@ impl<'tcx> FileDescriptor<'tcx> for FileHandle { } } -#[derive(Debug, Default)] +impl<'tcx> FileDescriptor<'tcx> for io::Stdin { + fn as_file_handle(&self) -> InterpResult<'tcx, &FileHandle> { + throw_unsup_format!("stdin cannot be used as FileHandle"); + } + + fn read(&mut self, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + Ok(Read::read(self, bytes)) + } + + fn write(&mut self, _bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("cannot write to stdin"); + } + + fn seek(&mut self, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("cannot seek on stdin"); + } +} + +impl<'tcx> FileDescriptor<'tcx> for io::Stdout { + fn as_file_handle(&self) -> InterpResult<'tcx, &FileHandle> { + throw_unsup_format!("stdout cannot be used as FileHandle"); + } + + fn read(&mut self, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("cannot read from stdout"); + } + + fn write(&mut self, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + Ok(Write::write(self, bytes)) + } + + fn seek(&mut self, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("cannot seek on stdout"); + } +} + +impl<'tcx> FileDescriptor<'tcx> for io::Stderr { + fn as_file_handle(&self) -> InterpResult<'tcx, &FileHandle> { + throw_unsup_format!("stdout cannot be used as FileHandle"); + } + + fn read(&mut self, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("cannot read from stderr"); + } + + fn write(&mut self, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + Ok(Write::write(self, bytes)) + } + + fn seek(&mut self, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("cannot seek on stderr"); + } +} + +#[derive(Debug)] pub struct FileHandler<'tcx> { handles: BTreeMap>>, } +impl<'tcx> Default for FileHandler<'tcx> { + fn default() -> Self { + let mut handles = BTreeMap::new(); + handles.insert(0i32, Box::new(io::stdin()) as Box>); + handles.insert(1i32, Box::new(io::stdout()) as Box>); + handles.insert(2i32, Box::new(io::stderr()) as Box>); + FileHandler { + handles + } + } +} + // fd numbers 0, 1, and 2 are reserved for stdin, stdout, and stderr const MIN_NORMAL_FILE_FD: i32 = 3; @@ -485,7 +551,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.check_no_isolation("read")?; - assert!(fd >= 3); trace!("Reading from FD {}, size {}", fd, count); @@ -537,8 +602,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); - this.check_no_isolation("write")?; - assert!(fd >= 3); + if fd >= 3 { + this.check_no_isolation("write")?; + } // Check that the *entire* buffer is actually valid memory. this.memory.check_ptr_access( diff --git a/tests/compile-fail/fs/read_from_stdout.rs b/tests/compile-fail/fs/read_from_stdout.rs new file mode 100644 index 000000000000..17f1735f6ade --- /dev/null +++ b/tests/compile-fail/fs/read_from_stdout.rs @@ -0,0 +1,14 @@ +// compile-flags: -Zmiri-disable-isolation +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +fn main() -> std::io::Result<()> { + let mut bytes = [0u8; 512]; + unsafe { + libc::read(1, bytes.as_mut_ptr() as *mut libc::c_void, 512); //~ ERROR cannot read from stdout + } + Ok(()) +} diff --git a/tests/compile-fail/fs/write_to_stdin.rs b/tests/compile-fail/fs/write_to_stdin.rs new file mode 100644 index 000000000000..30d24b5dc444 --- /dev/null +++ b/tests/compile-fail/fs/write_to_stdin.rs @@ -0,0 +1,14 @@ +// compile-flags: -Zmiri-disable-isolation +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +fn main() -> std::io::Result<()> { + let bytes = b"hello"; + unsafe { + libc::write(0, bytes.as_ptr() as *const libc::c_void, 5); //~ ERROR cannot write to stdin + } + Ok(()) +} From bdef57ea45594752f904983effc81fe938fbdfe9 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Tue, 4 Aug 2020 20:40:48 +0530 Subject: [PATCH 2214/5092] Flush to stdout from FileDescriptor::write for `Stdout` Also, remove unnecessary `-Zmiri-disable-isolation` in test --- src/shims/posix/foreign_items.rs | 5 ----- src/shims/posix/fs.rs | 10 +++++++++- tests/compile-fail/fs/write_to_stdin.rs | 1 - 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 594f58d26461..151ab95f1e3c 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -1,5 +1,3 @@ -use std::io::{self, Write}; - use log::trace; use rustc_middle::mir; @@ -76,9 +74,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let count = this.read_scalar(n)?.to_machine_usize(this)?; trace!("Called write({:?}, {:?}, {:?})", fd, buf, count); let result = this.write(fd, buf, count)?; - if fd == 1 { - io::stdout().flush().unwrap(); - } // Now, `result` is the value we return back to the program. this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 65d50aa504d3..3e1ba3976f77 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -76,7 +76,15 @@ impl<'tcx> FileDescriptor<'tcx> for io::Stdout { } fn write(&mut self, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { - Ok(Write::write(self, bytes)) + let result = Write::write(self, bytes); + // Stdout is buffered, flush to make sure it appears on the + // screen. This is the write() syscall of the interpreted + // program, we want it to correspond to a write() syscall on + // the host -- there is no good in adding extra buffering + // here. + io::stdout().flush().unwrap(); + + Ok(result) } fn seek(&mut self, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { diff --git a/tests/compile-fail/fs/write_to_stdin.rs b/tests/compile-fail/fs/write_to_stdin.rs index 30d24b5dc444..c2754636c860 100644 --- a/tests/compile-fail/fs/write_to_stdin.rs +++ b/tests/compile-fail/fs/write_to_stdin.rs @@ -1,4 +1,3 @@ -// compile-flags: -Zmiri-disable-isolation // ignore-windows: No libc on Windows #![feature(rustc_private)] From 422113a49188f6c4e1e625f6efbe78da87441f09 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 5 Aug 2020 13:38:15 +0200 Subject: [PATCH 2215/5092] rustup --- rust-version | 2 +- tests/run-pass/heap_allocator.rs | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/rust-version b/rust-version index 807d4e85591d..4fb52f22fa0a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -dbc2ef25fb5e15445de38f19ba75547a6cf35cae +1d69e3b1d753951bc7df0f02d6fd4719065d98c3 diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index c2fcfea58cdf..557550d6f433 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -1,7 +1,7 @@ -#![feature(allocator_api)] +#![feature(allocator_api, slice_ptr_get)] use std::ptr::NonNull; -use std::alloc::{Global, AllocRef, Layout, System, AllocInit, ReallocPlacement}; +use std::alloc::{Global, AllocRef, Layout, System}; use std::slice; fn check_alloc(mut allocator: T) { unsafe { @@ -9,29 +9,30 @@ fn check_alloc(mut allocator: T) { unsafe { let layout = Layout::from_size_align(20, align).unwrap(); for _ in 0..32 { - let a = allocator.alloc(layout, AllocInit::Uninitialized).unwrap().ptr; + let a = allocator.alloc(layout).unwrap().as_non_null_ptr(); assert_eq!(a.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); allocator.dealloc(a, layout); } - let p1 = allocator.alloc(layout, AllocInit::Zeroed).unwrap().ptr; + let p1 = allocator.alloc_zeroed(layout).unwrap().as_non_null_ptr(); assert_eq!(p1.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); + assert_eq!(*p1.as_ptr(), 0); // old size < new size - let p2 = allocator.grow(p1, layout, 40, ReallocPlacement::MayMove, AllocInit::Uninitialized).unwrap().ptr; + let p2 = allocator.grow(p1, layout, 40).unwrap().as_non_null_ptr(); let layout = Layout::from_size_align(40, align).unwrap(); assert_eq!(p2.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); let slice = slice::from_raw_parts(p2.as_ptr(), 20); assert_eq!(&slice, &[0_u8; 20]); // old size == new size - let p3 = allocator.grow(p2, layout, 40, ReallocPlacement::MayMove, AllocInit::Uninitialized).unwrap().ptr; + let p3 = allocator.grow(p2, layout, 40).unwrap().as_non_null_ptr(); assert_eq!(p3.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); let slice = slice::from_raw_parts(p3.as_ptr(), 20); assert_eq!(&slice, &[0_u8; 20]); // old size > new size - let p4 = allocator.shrink(p3, layout, 10, ReallocPlacement::MayMove).unwrap().ptr; + let p4 = allocator.shrink(p3, layout, 10).unwrap().as_non_null_ptr(); let layout = Layout::from_size_align(10, align).unwrap(); assert_eq!(p4.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); let slice = slice::from_raw_parts(p4.as_ptr(), 10); @@ -47,7 +48,7 @@ fn check_align_requests(mut allocator: T) { let iterations = 32; unsafe { let pointers: Vec<_> = (0..iterations).map(|_| { - allocator.alloc(Layout::from_size_align(size, align).unwrap(), AllocInit::Uninitialized).unwrap().ptr + allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap().as_non_null_ptr() }).collect(); for &ptr in &pointers { assert_eq!((ptr.as_ptr() as usize) % align, 0, @@ -68,7 +69,7 @@ fn global_to_box() { let l = Layout::new::(); // allocate manually with global allocator, then turn into Box and free there unsafe { - let ptr = Global.alloc(l, AllocInit::Uninitialized).unwrap().ptr.as_ptr() as *mut T; + let ptr = Global.alloc(l).unwrap().as_non_null_ptr().as_ptr() as *mut T; let b = Box::from_raw(ptr); drop(b); } From 773dfb31f0c35ec992892b4677ea5764068f8092 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Sat, 8 Aug 2020 14:42:50 +0530 Subject: [PATCH 2216/5092] Bubble up error from FileDescriptor::as_file_handle ...instead of handle_not_found --- src/shims/posix/fs.rs | 114 +++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 67 deletions(-) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 3e1ba3976f77..13c7827f8879 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -484,9 +484,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let fh = &mut this.machine.file_handler; let (file_result, writable) = match fh.handles.get(&fd) { - Some(file_descriptor) => match file_descriptor.as_file_handle() { - Ok(FileHandle { file, writable }) => (file.try_clone(), *writable), - Err(_) => return this.handle_not_found(), + Some(file_descriptor) => { + let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + (file.try_clone(), *writable) }, None => return this.handle_not_found(), }; @@ -522,28 +522,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.remove(&fd) { - match file_descriptor.as_file_handle() { - Ok(FileHandle { file, writable }) => { - // We sync the file if it was opened in a mode different than read-only. - if *writable { - // `File::sync_all` does the checks that are done when closing a file. We do this to - // to handle possible errors correctly. - let result = this.try_unwrap_io_result(file.sync_all().map(|_| 0i32)); - // Now we actually close the file. - drop(file); - // And return the result. - result - } else { - // We drop the file, this closes it but ignores any errors produced when closing - // it. This is done because `File::sync_all` cannot be done over files like - // `/dev/urandom` which are read-only. Check - // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439 for a deeper - // discussion. - drop(file); - Ok(0) - } - }, - Err(_) => this.handle_not_found() + let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + // We sync the file if it was opened in a mode different than read-only. + if *writable { + // `File::sync_all` does the checks that are done when closing a file. We do this to + // to handle possible errors correctly. + let result = this.try_unwrap_io_result(file.sync_all().map(|_| 0i32)); + // Now we actually close the file. + drop(file); + // And return the result. + result + } else { + // We drop the file, this closes it but ignores any errors produced when closing + // it. This is done because `File::sync_all` cannot be done over files like + // `/dev/urandom` which are read-only. Check + // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439 for a deeper + // discussion. + drop(file); + Ok(0) } } else { this.handle_not_found() @@ -1223,25 +1219,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; let length = this.read_scalar(length_op)?.to_i64()?; if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { - match file_descriptor.as_file_handle() { - Ok(FileHandle { file, writable }) => { - if *writable { - if let Ok(length) = length.try_into() { - let result = file.set_len(length); - this.try_unwrap_io_result(result.map(|_| 0i32)) - } else { - let einval = this.eval_libc("EINVAL")?; - this.set_last_error(einval)?; - Ok(-1) - } - } else { - // The file is not writable - let einval = this.eval_libc("EINVAL")?; - this.set_last_error(einval)?; - Ok(-1) - } + let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + if *writable { + if let Ok(length) = length.try_into() { + let result = file.set_len(length); + this.try_unwrap_io_result(result.map(|_| 0i32)) + } else { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + Ok(-1) } - Err(_) => this.handle_not_found() + } else { + // The file is not writable + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + Ok(-1) } } else { this.handle_not_found() @@ -1260,13 +1252,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { - match file_descriptor.as_file_handle() { - Ok(FileHandle { file, writable }) => { - let io_result = maybe_sync_file(&file, *writable, File::sync_all); - this.try_unwrap_io_result(io_result) - } - Err(_) => this.handle_not_found() - } + let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + let io_result = maybe_sync_file(&file, *writable, File::sync_all); + this.try_unwrap_io_result(io_result) } else { this.handle_not_found() } @@ -1279,13 +1267,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { - match file_descriptor.as_file_handle() { - Ok(FileHandle { file, writable }) => { - let io_result = maybe_sync_file(&file, *writable, File::sync_data); - this.try_unwrap_io_result(io_result) - } - Err(_) => this.handle_not_found() - } + let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + let io_result = maybe_sync_file(&file, *writable, File::sync_data); + this.try_unwrap_io_result(io_result) } else { this.handle_not_found() } @@ -1322,13 +1306,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { - match file_descriptor.as_file_handle() { - Ok(FileHandle { file, writable }) => { - let io_result = maybe_sync_file(&file, *writable, File::sync_data); - this.try_unwrap_io_result(io_result) - }, - Err(_) => this.handle_not_found() - } + let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + let io_result = maybe_sync_file(&file, *writable, File::sync_data); + this.try_unwrap_io_result(io_result) } else { this.handle_not_found() } @@ -1378,9 +1358,9 @@ impl FileMetadata { ) -> InterpResult<'tcx, Option> { let option = ecx.machine.file_handler.handles.get(&fd); let file = match option { - Some(file_descriptor) => match file_descriptor.as_file_handle() { - Ok(FileHandle { file, writable: _ }) => file, - Err(_) => return ecx.handle_not_found().map(|_: i32| None), + Some(file_descriptor) => { + let FileHandle { file, writable: _ } = file_descriptor.as_file_handle()?; + file }, None => return ecx.handle_not_found().map(|_: i32| None), }; From 045bcab1eb9a0d0efbed0ae6d2e3dd30270284e6 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Sat, 8 Aug 2020 15:08:29 +0530 Subject: [PATCH 2217/5092] Add FIXME's for `dup` and other syscalls to support stdin/out/err --- src/shims/posix/fs.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 13c7827f8879..ec6fb7c53735 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -485,6 +485,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fh = &mut this.machine.file_handler; let (file_result, writable) = match fh.handles.get(&fd) { Some(file_descriptor) => { + // FIXME: Support "dup" for all FDs(stdin, etc) let FileHandle { file, writable } = file_descriptor.as_file_handle()?; (file.try_clone(), *writable) }, @@ -499,6 +500,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx { let &[_, _] = check_arg_count(args)?; if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { + // FIXME: Support fullfsync for all FDs match file_descriptor.as_file_handle() { Ok(FileHandle { file, writable }) => { let io_result = maybe_sync_file(&file, *writable, File::sync_all); @@ -522,6 +524,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.remove(&fd) { + // FIXME: Support `close` for all FDs(stdin, etc) let FileHandle { file, writable } = file_descriptor.as_file_handle()?; // We sync the file if it was opened in a mode different than read-only. if *writable { @@ -1219,6 +1222,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; let length = this.read_scalar(length_op)?.to_i64()?; if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { + // FIXME: Support ftruncate64 for all FDs let FileHandle { file, writable } = file_descriptor.as_file_handle()?; if *writable { if let Ok(length) = length.try_into() { @@ -1252,6 +1256,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { + // FIXME: Support fsync for all FDs let FileHandle { file, writable } = file_descriptor.as_file_handle()?; let io_result = maybe_sync_file(&file, *writable, File::sync_all); this.try_unwrap_io_result(io_result) @@ -1267,6 +1272,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { + // FIXME: Support fdatasync for all FDs let FileHandle { file, writable } = file_descriptor.as_file_handle()?; let io_result = maybe_sync_file(&file, *writable, File::sync_data); this.try_unwrap_io_result(io_result) @@ -1306,6 +1312,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { + // FIXME: Support sync_data_range for all FDs let FileHandle { file, writable } = file_descriptor.as_file_handle()?; let io_result = maybe_sync_file(&file, *writable, File::sync_data); this.try_unwrap_io_result(io_result) From 1069f6b17468a48af5a8ab441bf355ac955f4596 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Sat, 8 Aug 2020 17:28:41 +0530 Subject: [PATCH 2218/5092] Fix handling of as_file_handle error for `fullfsync` --- src/shims/posix/fs.rs | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index ec6fb7c53735..e0b2837cae90 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -501,13 +501,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[_, _] = check_arg_count(args)?; if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support fullfsync for all FDs - match file_descriptor.as_file_handle() { - Ok(FileHandle { file, writable }) => { - let io_result = maybe_sync_file(&file, *writable, File::sync_all); - this.try_unwrap_io_result(io_result) - }, - Err(_) => this.handle_not_found(), - } + let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + let io_result = maybe_sync_file(&file, *writable, File::sync_all); + this.try_unwrap_io_result(io_result) } else { this.handle_not_found() } @@ -1365,10 +1361,7 @@ impl FileMetadata { ) -> InterpResult<'tcx, Option> { let option = ecx.machine.file_handler.handles.get(&fd); let file = match option { - Some(file_descriptor) => { - let FileHandle { file, writable: _ } = file_descriptor.as_file_handle()?; - file - }, + Some(file_descriptor) => &file_descriptor.as_file_handle()?.file, None => return ecx.handle_not_found().map(|_: i32| None), }; let metadata = file.metadata(); From 07a4383ac8930d3d1a243f3e44f6cbc33e42696b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 8 Aug 2020 10:27:23 +0200 Subject: [PATCH 2219/5092] rustup --- rust-version | 2 +- src/bin/miri-rustc-tests.rs | 2 +- src/machine.rs | 3 +-- src/shims/foreign_items.rs | 3 +-- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index 4fb52f22fa0a..75cd757fcc4c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1d69e3b1d753951bc7df0f02d6fd4719065d98c3 +c92fc8db8b009b7661cff31fa59a7c0348653bd0 diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index add9cfe897fb..56d19e62749e 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -38,7 +38,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { if let hir::ItemKind::Fn(.., body_id) = i.kind { if i.attrs .iter() - .any(|attr| attr.check_name(rustc_span::symbol::sym::test)) + .any(|attr| self.0.sess.check_name(attr, rustc_span::symbol::sym::test)) { let config = miri::MiriConfig::default(); let did = self.0.hir().body_owner_def_id(body_id).to_def_id(); diff --git a/src/machine.rs b/src/machine.rs index f9dd48fdbae2..9e22825ccac4 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -11,7 +11,6 @@ use std::fmt; use log::trace; use rand::rngs::StdRng; -use rustc_ast::attr; use rustc_data_structures::fx::FxHashMap; use rustc_middle::{ mir, @@ -442,7 +441,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { def_id: DefId, ) -> InterpResult<'tcx, AllocId> { let attrs = memory.tcx.get_attrs(def_id); - let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { + let link_name = match memory.tcx.sess.first_attr_value_str_by_name(&attrs, sym::link_name) { Some(name) => name, None => memory.tcx.item_name(def_id), }; diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 0379ec0c0778..355801eb8ffb 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -7,7 +7,6 @@ use rustc_middle::{mir, ty}; use rustc_target::abi::{Align, Size}; use rustc_apfloat::Float; use rustc_span::symbol::sym; -use rustc_ast::attr; use crate::*; use helpers::check_arg_count; @@ -117,7 +116,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); - let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { + let link_name = match this.tcx.sess.first_attr_value_str_by_name(&attrs, sym::link_name) { Some(name) => name.as_str(), None => this.tcx.item_name(def_id).as_str(), }; From 5657f08bea978ddd9114c5a25a07e115ee609425 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 8 Aug 2020 15:21:04 +0200 Subject: [PATCH 2220/5092] fs: move isolation handling to inside trait --- src/helpers.rs | 13 ++++-- src/shims/posix/fs.rs | 53 ++++++++++++++----------- tests/compile-fail/fs/isolated_stdin.rs | 13 ++++++ 3 files changed, 52 insertions(+), 27 deletions(-) create mode 100644 tests/compile-fail/fs/isolated_stdin.rs diff --git a/src/helpers.rs b/src/helpers.rs index d271b845c215..0426115773d9 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -376,13 +376,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// case. fn check_no_isolation(&self, name: &str) -> InterpResult<'tcx> { if !self.eval_context_ref().machine.communicate { - throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!( - "`{}` not available when isolation is enabled", - name, - ))) + isolation_error(name)?; } Ok(()) } + /// Helper function used inside the shims of foreign functions to assert that the target OS /// is `target_os`. It panics showing a message with the `name` of the foreign function /// if this is not the case. @@ -509,6 +507,13 @@ pub fn check_arg_count<'a, 'tcx, const N: usize>(args: &'a [OpTy<'tcx, Tag>]) -> throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N) } +pub fn isolation_error(name: &str) -> InterpResult<'static> { + throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!( + "`{}` not available when isolation is enabled", + name, + ))) +} + pub fn immty_from_int_checked<'tcx>( int: impl Into, layout: TyAndLayout<'tcx>, diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index e0b2837cae90..cf050b708694 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -25,9 +25,9 @@ struct FileHandle { trait FileDescriptor<'tcx> : std::fmt::Debug { fn as_file_handle(&self) -> InterpResult<'tcx, &FileHandle>; - fn read(&mut self, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result>; - fn write(&mut self, bytes: &[u8]) -> InterpResult<'tcx, io::Result>; - fn seek(&mut self, offset: SeekFrom) -> InterpResult<'tcx, io::Result>; + fn read(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result>; + fn write(&mut self, communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result>; + fn seek(&mut self, communicate_allowed: bool, offset: SeekFrom) -> InterpResult<'tcx, io::Result>; } impl<'tcx> FileDescriptor<'tcx> for FileHandle { @@ -35,15 +35,18 @@ impl<'tcx> FileDescriptor<'tcx> for FileHandle { Ok(&self) } - fn read(&mut self, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + fn read(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + assert!(communicate_allowed, "isolation should have prevented even opening a file"); Ok(self.file.read(bytes)) } - fn write(&mut self, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + fn write(&mut self, communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + assert!(communicate_allowed, "isolation should have prevented even opening a file"); Ok(self.file.write(bytes)) } - fn seek(&mut self, offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + fn seek(&mut self, communicate_allowed: bool, offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + assert!(communicate_allowed, "isolation should have prevented even opening a file"); Ok(self.file.seek(offset)) } } @@ -53,15 +56,19 @@ impl<'tcx> FileDescriptor<'tcx> for io::Stdin { throw_unsup_format!("stdin cannot be used as FileHandle"); } - fn read(&mut self, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + fn read(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + if !communicate_allowed { + // We want isolation mode to be deterministic, so we have to disallow all reads, even stdin. + helpers::isolation_error("read")?; + } Ok(Read::read(self, bytes)) } - fn write(&mut self, _bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + fn write(&mut self, _communicate_allowed: bool, _bytes: &[u8]) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot write to stdin"); } - fn seek(&mut self, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + fn seek(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot seek on stdin"); } } @@ -71,11 +78,12 @@ impl<'tcx> FileDescriptor<'tcx> for io::Stdout { throw_unsup_format!("stdout cannot be used as FileHandle"); } - fn read(&mut self, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + fn read(&mut self, _communicate_allowed: bool, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot read from stdout"); } - fn write(&mut self, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + fn write(&mut self, _communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + // We allow writing to stderr even with isolation enabled. let result = Write::write(self, bytes); // Stdout is buffered, flush to make sure it appears on the // screen. This is the write() syscall of the interpreted @@ -87,7 +95,7 @@ impl<'tcx> FileDescriptor<'tcx> for io::Stdout { Ok(result) } - fn seek(&mut self, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + fn seek(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot seek on stdout"); } } @@ -97,15 +105,16 @@ impl<'tcx> FileDescriptor<'tcx> for io::Stderr { throw_unsup_format!("stdout cannot be used as FileHandle"); } - fn read(&mut self, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + fn read(&mut self, _communicate_allowed: bool, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot read from stderr"); } - fn write(&mut self, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + fn write(&mut self, _communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + // We allow writing to stderr even with isolation enabled. Ok(Write::write(self, bytes)) } - fn seek(&mut self, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + fn seek(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot seek on stderr"); } } @@ -553,7 +562,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); - this.check_no_isolation("read")?; + // Isolation check is done via `FileDescriptor` trait. trace!("Reading from FD {}, size {}", fd, count); @@ -577,7 +586,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `File::read` never returns a value larger than `count`, // so this cannot fail. let result = file_descriptor - .read(&mut bytes)? + .read(this.machine.communicate, &mut bytes)? .map(|c| i64::try_from(c).unwrap()); match result { @@ -605,9 +614,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); - if fd >= 3 { - this.check_no_isolation("write")?; - } + // Isolation check is done via `FileDescriptor` trait. // Check that the *entire* buffer is actually valid memory. this.memory.check_ptr_access( @@ -623,7 +630,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; let result = file_descriptor - .write(&bytes)? + .write(this.machine.communicate, &bytes)? .map(|c| i64::try_from(c).unwrap()); this.try_unwrap_io_result(result) } else { @@ -639,7 +646,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); - this.check_no_isolation("lseek64")?; + // Isolation check is done via `FileDescriptor` trait. let fd = this.read_scalar(fd_op)?.to_i32()?; let offset = this.read_scalar(offset_op)?.to_i64()?; @@ -659,7 +666,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { let result = file_descriptor - .seek(seek_from)? + .seek(this.machine.communicate, seek_from)? .map(|offset| i64::try_from(offset).unwrap()); this.try_unwrap_io_result(result) } else { diff --git a/tests/compile-fail/fs/isolated_stdin.rs b/tests/compile-fail/fs/isolated_stdin.rs new file mode 100644 index 000000000000..6c467a2d1f14 --- /dev/null +++ b/tests/compile-fail/fs/isolated_stdin.rs @@ -0,0 +1,13 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +fn main() -> std::io::Result<()> { + let mut bytes = [0u8; 512]; + unsafe { + libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512); //~ ERROR `read` not available when isolation is enabled + } + Ok(()) +} From 5ea5e9fc2c0848d1d670f02644ea953e0800a123 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 10 Aug 2020 09:02:45 +0200 Subject: [PATCH 2221/5092] accept ReferencedConstant errors in Miri (can happen post-monomorphization) --- src/diagnostics.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index a20e8126c13a..ca3dd4dd66f2 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -88,6 +88,8 @@ pub fn report_error<'tcx, 'mir>( "Undefined Behavior", ResourceExhaustion(_) => "resource exhaustion", + InvalidProgram(InvalidProgramInfo::ReferencedConstant) => + "post-monomorphization error", _ => bug!("This error should be impossible in Miri: {}", e), }; From da2260db441503ba9d93b55db3ca49710eff23b2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 10 Aug 2020 10:10:08 +0200 Subject: [PATCH 2222/5092] make sure opening a file fails with isolation enabled --- tests/compile-fail/fs/isolated_file.rs | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 tests/compile-fail/fs/isolated_file.rs diff --git a/tests/compile-fail/fs/isolated_file.rs b/tests/compile-fail/fs/isolated_file.rs new file mode 100644 index 000000000000..5b7270f18931 --- /dev/null +++ b/tests/compile-fail/fs/isolated_file.rs @@ -0,0 +1,6 @@ +// ignore-windows: File handling is not implemented yet +// error-pattern: `open` not available when isolation is enabled + +fn main() { + let _file = std::fs::File::open("file.txt").unwrap(); +} From 94f13efefda1f891905913d088869bc1589a45c9 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 11 Aug 2020 11:37:29 +0200 Subject: [PATCH 2223/5092] Bump for rustc changes --- src/thread.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/thread.rs b/src/thread.rs index 1e710a25edc9..cffbec93c5ca 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -530,7 +530,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if tcx.is_foreign_item(def_id) { throw_unsup_format!("foreign thread-local statics are not supported"); } - let allocation = interpret::get_static(*tcx, def_id)?; + let allocation = tcx.eval_static_initializer(def_id)?; // Create a fresh allocation with this content. let new_alloc_id = this.memory.allocate_with(allocation.clone(), MiriMemoryKind::Tls.into()).alloc_id; this.machine.threads.set_thread_local_alloc_id(def_id, new_alloc_id); From 2f68a1f5b53acbd263f224666ff524be5e0e2c24 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Aug 2020 09:19:40 +0200 Subject: [PATCH 2224/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 75cd757fcc4c..c8fd55f4c3b2 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c92fc8db8b009b7661cff31fa59a7c0348653bd0 +c94ed5ca91f1363b66970ce2cbd6e2773e3cb1d3 From 80929e17ae4806a1d2fb5cf282f430c5e34f7796 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 10 Aug 2020 09:04:37 +0200 Subject: [PATCH 2225/5092] add test for unused ill-formed constant also use better span in TopFrameInfo --- src/diagnostics.rs | 2 +- tests/compile-fail/erroneous_const.rs | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/erroneous_const.rs diff --git a/src/diagnostics.rs b/src/diagnostics.rs index ca3dd4dd66f2..eed60c2696e1 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -227,7 +227,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx TopFrameInfo { stack_size: this.active_thread_stack().len(), instance: Some(frame.instance), - span: frame.current_source_info().map_or(DUMMY_SP, |si| si.span), + span: frame.current_span(), } } diff --git a/tests/compile-fail/erroneous_const.rs b/tests/compile-fail/erroneous_const.rs new file mode 100644 index 000000000000..287e07358141 --- /dev/null +++ b/tests/compile-fail/erroneous_const.rs @@ -0,0 +1,19 @@ +//! Make sure we detect erroneous constants post-monomorphization even when they are unused. +//! (https://github.com/rust-lang/miri/issues/1382) +#![feature(const_panic)] +#![feature(never_type)] +#![warn(warnings, const_err)] + +struct PrintName(T); +impl PrintName { + const VOID: ! = panic!(); //~WARN any use of this value will cause an error +} + +fn no_codegen() { + if false { + let _ = PrintName::::VOID; //~ERROR referenced constant has errors + } +} +fn main() { + no_codegen::(); +} From 925d60760eb953af3ffd288fa5a8e9546f60311e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 13 Aug 2020 08:43:28 +0200 Subject: [PATCH 2226/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index c8fd55f4c3b2..198b3970e0d1 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c94ed5ca91f1363b66970ce2cbd6e2773e3cb1d3 +814bc4fe9364865bfaa94d7825b8eabc11245c7c From 46852d736e896ed9328308115dc06d8fbf84a3ac Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Thu, 13 Aug 2020 15:01:52 +0530 Subject: [PATCH 2227/5092] Remove lifetime from FileDescriptor trait Also: - Remove type annotate `handles` declaration instead of every insert. - Add note about flush being unnecessary when writing to stderr --- src/machine.rs | 2 +- src/shims/posix/fs.rs | 67 ++++++++++++++++++++++--------------------- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 9e22825ccac4..04bba6c33cdb 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -249,7 +249,7 @@ pub struct Evaluator<'mir, 'tcx> { /// Whether to enforce the validity invariant. pub(crate) validate: bool, - pub(crate) file_handler: shims::posix::FileHandler<'tcx>, + pub(crate) file_handler: shims::posix::FileHandler, pub(crate) dir_handler: shims::posix::DirHandler, /// The temporary used for storing the argument of diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index cf050b708694..5f31a6375cb7 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -22,41 +22,41 @@ struct FileHandle { writable: bool, } -trait FileDescriptor<'tcx> : std::fmt::Debug { - fn as_file_handle(&self) -> InterpResult<'tcx, &FileHandle>; +trait FileDescriptor : std::fmt::Debug { + fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle>; - fn read(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result>; - fn write(&mut self, communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result>; - fn seek(&mut self, communicate_allowed: bool, offset: SeekFrom) -> InterpResult<'tcx, io::Result>; + fn read<'tcx>(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result>; + fn write<'tcx>(&mut self, communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result>; + fn seek<'tcx>(&mut self, communicate_allowed: bool, offset: SeekFrom) -> InterpResult<'tcx, io::Result>; } -impl<'tcx> FileDescriptor<'tcx> for FileHandle { - fn as_file_handle(&self) -> InterpResult<'tcx, &FileHandle> { +impl FileDescriptor for FileHandle { + fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { Ok(&self) } - fn read(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + fn read<'tcx>(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { assert!(communicate_allowed, "isolation should have prevented even opening a file"); Ok(self.file.read(bytes)) } - fn write(&mut self, communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + fn write<'tcx>(&mut self, communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { assert!(communicate_allowed, "isolation should have prevented even opening a file"); Ok(self.file.write(bytes)) } - fn seek(&mut self, communicate_allowed: bool, offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + fn seek<'tcx>(&mut self, communicate_allowed: bool, offset: SeekFrom) -> InterpResult<'tcx, io::Result> { assert!(communicate_allowed, "isolation should have prevented even opening a file"); Ok(self.file.seek(offset)) } } -impl<'tcx> FileDescriptor<'tcx> for io::Stdin { - fn as_file_handle(&self) -> InterpResult<'tcx, &FileHandle> { +impl FileDescriptor for io::Stdin { + fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { throw_unsup_format!("stdin cannot be used as FileHandle"); } - fn read(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + fn read<'tcx>(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { if !communicate_allowed { // We want isolation mode to be deterministic, so we have to disallow all reads, even stdin. helpers::isolation_error("read")?; @@ -64,25 +64,25 @@ impl<'tcx> FileDescriptor<'tcx> for io::Stdin { Ok(Read::read(self, bytes)) } - fn write(&mut self, _communicate_allowed: bool, _bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + fn write<'tcx>(&mut self, _communicate_allowed: bool, _bytes: &[u8]) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot write to stdin"); } - fn seek(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + fn seek<'tcx>(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot seek on stdin"); } } -impl<'tcx> FileDescriptor<'tcx> for io::Stdout { - fn as_file_handle(&self) -> InterpResult<'tcx, &FileHandle> { +impl FileDescriptor for io::Stdout { + fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { throw_unsup_format!("stdout cannot be used as FileHandle"); } - fn read(&mut self, _communicate_allowed: bool, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + fn read<'tcx>(&mut self, _communicate_allowed: bool, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot read from stdout"); } - fn write(&mut self, _communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + fn write<'tcx>(&mut self, _communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { // We allow writing to stderr even with isolation enabled. let result = Write::write(self, bytes); // Stdout is buffered, flush to make sure it appears on the @@ -95,41 +95,42 @@ impl<'tcx> FileDescriptor<'tcx> for io::Stdout { Ok(result) } - fn seek(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + fn seek<'tcx>(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot seek on stdout"); } } -impl<'tcx> FileDescriptor<'tcx> for io::Stderr { - fn as_file_handle(&self) -> InterpResult<'tcx, &FileHandle> { +impl FileDescriptor for io::Stderr { + fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { throw_unsup_format!("stdout cannot be used as FileHandle"); } - fn read(&mut self, _communicate_allowed: bool, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + fn read<'tcx>(&mut self, _communicate_allowed: bool, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot read from stderr"); } - fn write(&mut self, _communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + fn write<'tcx>(&mut self, _communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { // We allow writing to stderr even with isolation enabled. + // No need to flush, stderr is not buffered. Ok(Write::write(self, bytes)) } - fn seek(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + fn seek<'tcx>(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot seek on stderr"); } } #[derive(Debug)] -pub struct FileHandler<'tcx> { - handles: BTreeMap>>, +pub struct FileHandler { + handles: BTreeMap>, } -impl<'tcx> Default for FileHandler<'tcx> { +impl<'tcx> Default for FileHandler { fn default() -> Self { - let mut handles = BTreeMap::new(); - handles.insert(0i32, Box::new(io::stdin()) as Box>); - handles.insert(1i32, Box::new(io::stdout()) as Box>); - handles.insert(2i32, Box::new(io::stderr()) as Box>); + let mut handles : BTreeMap<_, Box> = BTreeMap::new(); + handles.insert(0i32, Box::new(io::stdin())); + handles.insert(1i32, Box::new(io::stdout())); + handles.insert(2i32, Box::new(io::stderr())); FileHandler { handles } @@ -140,7 +141,7 @@ impl<'tcx> Default for FileHandler<'tcx> { // fd numbers 0, 1, and 2 are reserved for stdin, stdout, and stderr const MIN_NORMAL_FILE_FD: i32 = 3; -impl<'tcx> FileHandler<'tcx> { +impl<'tcx> FileHandler { fn insert_fd(&mut self, file_handle: FileHandle) -> i32 { self.insert_fd_with_min_fd(file_handle, 0) } From 0c2506411700591f218c03dca19b47388bd80f60 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Thu, 13 Aug 2020 16:18:08 +0530 Subject: [PATCH 2228/5092] Remove unnecessary whitespace Co-authored-by: Ralf Jung --- src/shims/posix/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 5f31a6375cb7..06a8bf1cb020 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -127,7 +127,7 @@ pub struct FileHandler { impl<'tcx> Default for FileHandler { fn default() -> Self { - let mut handles : BTreeMap<_, Box> = BTreeMap::new(); + let mut handles: BTreeMap<_, Box> = BTreeMap::new(); handles.insert(0i32, Box::new(io::stdin())); handles.insert(1i32, Box::new(io::stdout())); handles.insert(2i32, Box::new(io::stderr())); From df311293e2a4a413020840494cc310a3d1d1541f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 13 Aug 2020 14:00:10 +0200 Subject: [PATCH 2229/5092] fix Stderr::as_file_handle error message --- src/shims/posix/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 06a8bf1cb020..b4719c25baee 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -102,7 +102,7 @@ impl FileDescriptor for io::Stdout { impl FileDescriptor for io::Stderr { fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { - throw_unsup_format!("stdout cannot be used as FileHandle"); + throw_unsup_format!("stderr cannot be used as FileHandle"); } fn read<'tcx>(&mut self, _communicate_allowed: bool, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { From cb985670c1997534a0cd1cfee606e81e4fa136dc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Aug 2020 17:08:34 +0200 Subject: [PATCH 2230/5092] make alignment check integer-based by default, and add an option to make it symbolic --- src/bin/miri.rs | 54 ++++++------------- src/eval.rs | 16 ++++-- src/lib.rs | 2 +- src/machine.rs | 11 ++-- .../unaligned_pointers/atomic_unaligned.rs | 1 + .../unaligned_pointers/dyn_alignment.rs | 4 +- .../intptrcast_alignment_check.rs | 10 ++-- .../unaligned_pointers/reference_to_packed.rs | 2 +- .../unaligned_pointers/unaligned_ptr_zst.rs | 4 +- tests/run-pass/align.rs | 11 ++++ 10 files changed, 62 insertions(+), 53 deletions(-) create mode 100644 tests/run-pass/align.rs diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 73e52af4ec51..134702047522 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -172,48 +172,41 @@ fn main() { init_early_loggers(); // Parse our arguments and split them across `rustc` and `miri`. - let mut validate = true; - let mut stacked_borrows = true; - let mut check_alignment = true; - let mut communicate = false; - let mut ignore_leaks = false; - let mut seed: Option = None; - let mut tracked_pointer_tag: Option = None; - let mut tracked_call_id: Option = None; - let mut tracked_alloc_id: Option = None; + let mut miri_config = miri::MiriConfig::default(); let mut rustc_args = vec![]; - let mut crate_args = vec![]; let mut after_dashdash = false; - let mut excluded_env_vars = vec![]; for arg in env::args() { if rustc_args.is_empty() { // Very first arg: binary name. rustc_args.push(arg); } else if after_dashdash { // Everything that comes after `--` is forwarded to the interpreted crate. - crate_args.push(arg); + miri_config.args.push(arg); } else { match arg.as_str() { "-Zmiri-disable-validation" => { - validate = false; + miri_config.validate = false; } "-Zmiri-disable-stacked-borrows" => { - stacked_borrows = false; + miri_config.stacked_borrows = false; } "-Zmiri-disable-alignment-check" => { - check_alignment = false; + miri_config.check_alignment = miri::AlignmentCheck::None; + } + "-Zmiri-symbolic-alignment-check" => { + miri_config.check_alignment = miri::AlignmentCheck::Symbolic; } "-Zmiri-disable-isolation" => { - communicate = true; + miri_config.communicate = true; } "-Zmiri-ignore-leaks" => { - ignore_leaks = true; + miri_config.ignore_leaks = true; } "--" => { after_dashdash = true; } arg if arg.starts_with("-Zmiri-seed=") => { - if seed.is_some() { + if miri_config.seed.is_some() { panic!("Cannot specify -Zmiri-seed multiple times!"); } let seed_raw = hex::decode(arg.strip_prefix("-Zmiri-seed=").unwrap()) @@ -234,10 +227,10 @@ fn main() { let mut bytes = [0; 8]; bytes[..seed_raw.len()].copy_from_slice(&seed_raw); - seed = Some(u64::from_be_bytes(bytes)); + miri_config.seed = Some(u64::from_be_bytes(bytes)); } arg if arg.starts_with("-Zmiri-env-exclude=") => { - excluded_env_vars + miri_config.excluded_env_vars .push(arg.strip_prefix("-Zmiri-env-exclude=").unwrap().to_owned()); } arg if arg.starts_with("-Zmiri-track-pointer-tag=") => { @@ -249,7 +242,7 @@ fn main() { ), }; if let Some(id) = miri::PtrId::new(id) { - tracked_pointer_tag = Some(id); + miri_config.tracked_pointer_tag = Some(id); } else { panic!("-Zmiri-track-pointer-tag requires a nonzero argument"); } @@ -263,7 +256,7 @@ fn main() { ), }; if let Some(id) = miri::CallId::new(id) { - tracked_call_id = Some(id); + miri_config.tracked_call_id = Some(id); } else { panic!("-Zmiri-track-call-id requires a nonzero argument"); } @@ -276,7 +269,7 @@ fn main() { err ), }; - tracked_alloc_id = Some(miri::AllocId(id)); + miri_config.tracked_alloc_id = Some(miri::AllocId(id)); } _ => { // Forward to rustc. @@ -287,19 +280,6 @@ fn main() { } debug!("rustc arguments: {:?}", rustc_args); - debug!("crate arguments: {:?}", crate_args); - let miri_config = miri::MiriConfig { - validate, - stacked_borrows, - check_alignment, - communicate, - ignore_leaks, - excluded_env_vars, - seed, - args: crate_args, - tracked_pointer_tag, - tracked_call_id, - tracked_alloc_id, - }; + debug!("crate arguments: {:?}", miri_config.args); run_compiler(rustc_args, &mut MiriCompilerCalls { miri_config }) } diff --git a/src/eval.rs b/src/eval.rs index cc5a6eb21fab..8e4604c3360a 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -13,6 +13,16 @@ use rustc_target::abi::LayoutOf; use crate::*; +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum AlignmentCheck { + /// Do not check alignment. + None, + /// Check alignment "symbolically", i.e., using only the requested alignment for an allocation and not its real base address. + Symbolic, + /// Check alignment on the actual physical integer address. + Int, +} + /// Configuration needed to spawn a Miri instance. #[derive(Clone)] pub struct MiriConfig { @@ -20,8 +30,8 @@ pub struct MiriConfig { pub validate: bool, /// Determines if Stacked Borrows is enabled. pub stacked_borrows: bool, - /// Determines if alignment checking is enabled. - pub check_alignment: bool, + /// Controls alignment checking. + pub check_alignment: AlignmentCheck, /// Determines if communication with the host environment is enabled. pub communicate: bool, /// Determines if memory leaks should be ignored. @@ -45,7 +55,7 @@ impl Default for MiriConfig { MiriConfig { validate: true, stacked_borrows: true, - check_alignment: true, + check_alignment: AlignmentCheck::Int, communicate: false, ignore_leaks: false, excluded_env_vars: vec![], diff --git a/src/lib.rs b/src/lib.rs index 816917081a8c..1b66d5ff6f31 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,7 +55,7 @@ pub use crate::diagnostics::{ register_diagnostic, report_error, EvalContextExt as DiagnosticsEvalContextExt, TerminationInfo, NonHaltingDiagnostic, }; -pub use crate::eval::{create_ecx, eval_main, MiriConfig}; +pub use crate::eval::{create_ecx, eval_main, AlignmentCheck, MiriConfig}; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; pub use crate::machine::{ AllocExtra, Evaluator, FrameData, MemoryExtra, MiriEvalContext, MiriEvalContextExt, diff --git a/src/machine.rs b/src/machine.rs index 04bba6c33cdb..f2abb2ae0e7e 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -128,7 +128,7 @@ pub struct MemoryExtra { tracked_alloc_id: Option, /// Controls whether alignment of memory accesses is being checked. - check_alignment: bool, + check_alignment: AlignmentCheck, } impl MemoryExtra { @@ -138,7 +138,7 @@ impl MemoryExtra { tracked_pointer_tag: Option, tracked_call_id: Option, tracked_alloc_id: Option, - check_alignment: bool, + check_alignment: AlignmentCheck, ) -> Self { let stacked_borrows = if stacked_borrows { Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(tracked_pointer_tag, tracked_call_id)))) @@ -336,7 +336,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn enforce_alignment(memory_extra: &MemoryExtra) -> bool { - memory_extra.check_alignment + memory_extra.check_alignment != AlignmentCheck::None + } + + #[inline(always)] + fn force_int_for_alignment_check(memory_extra: &Self::MemoryExtra) -> bool { + memory_extra.check_alignment == AlignmentCheck::Int } #[inline(always)] diff --git a/tests/compile-fail/unaligned_pointers/atomic_unaligned.rs b/tests/compile-fail/unaligned_pointers/atomic_unaligned.rs index bdec0ff504bb..77eff5087dac 100644 --- a/tests/compile-fail/unaligned_pointers/atomic_unaligned.rs +++ b/tests/compile-fail/unaligned_pointers/atomic_unaligned.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-symbolic-alignment-check #![feature(core_intrinsics)] fn main() { diff --git a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs index aa293a5d2167..a40db99a72a6 100644 --- a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs +++ b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs @@ -1,4 +1,4 @@ -// should find the bug even without these, but gets masked by optimizations +// should find the bug even without validation and stacked borrows, but gets masked by optimizations // compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Zmir-opt-level=0 #[repr(align(256))] @@ -15,5 +15,5 @@ fn main() { // Overwrite the data part of `ptr` so it points to `buf`. unsafe { (&mut ptr as *mut _ as *mut *const u8).write(&buf as *const _ as *const u8); } // Re-borrow that. This should be UB. - let _ptr = &*ptr; //~ ERROR accessing memory with alignment 4, but alignment 256 is required + let _ptr = &*ptr; //~ ERROR alignment 256 is required } diff --git a/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs b/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs index 0a3b48dab5a0..3865d4578637 100644 --- a/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs +++ b/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs @@ -1,7 +1,9 @@ -// Even with intptrcast and without validation, we want to be *sure* to catch bugs -// that arise from pointers being insufficiently aligned. The only way to achieve -// that is not not let programs exploit integer information for alignment, so here -// we test that this is indeed the case. +// compile-flags: -Zmiri-symbolic-alignment-check +// With the symbolic alignment check, even with intptrcast and without +// validation, we want to be *sure* to catch bugs that arise from pointers being +// insufficiently aligned. The only way to achieve that is not not let programs +// exploit integer information for alignment, so here we test that this is +// indeed the case. // // See https://github.com/rust-lang/miri/issues/1074. fn main() { diff --git a/tests/compile-fail/unaligned_pointers/reference_to_packed.rs b/tests/compile-fail/unaligned_pointers/reference_to_packed.rs index 08104e917d21..a1240c90182a 100644 --- a/tests/compile-fail/unaligned_pointers/reference_to_packed.rs +++ b/tests/compile-fail/unaligned_pointers/reference_to_packed.rs @@ -15,5 +15,5 @@ fn main() { y: 99, }; let p = unsafe { &foo.x }; - let i = *p; //~ ERROR memory with alignment 1, but alignment 4 is required + let i = *p; //~ ERROR alignment 4 is required } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs index 31f88c838149..beba47359b55 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs @@ -2,9 +2,9 @@ // compile-flags: -Zmiri-disable-validation fn main() { - let x = &2u16; + let x = &2u8; let x = x as *const _ as *const [u32; 0]; // This must fail because alignment is violated. Test specifically for loading ZST. let _x = unsafe { *x }; - //~^ ERROR memory with alignment 2, but alignment 4 is required + //~^ ERROR alignment 4 is required } diff --git a/tests/run-pass/align.rs b/tests/run-pass/align.rs new file mode 100644 index 000000000000..b3d268f45e4b --- /dev/null +++ b/tests/run-pass/align.rs @@ -0,0 +1,11 @@ +// This manually makes sure that we have a pointer with the proper alignment. +// Do this a couple times in a loop because it may work "by chance". +fn main() { + for _ in 0..10 { + let x = &mut [0u8; 3]; + let base_addr = x as *mut _ as usize; + let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr+1 }; + let u16_ptr = base_addr_aligned as *mut u16; + unsafe { *u16_ptr = 2; } + } +} From 5a579f281d913d7d838413564272fafc23c6c336 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Aug 2020 17:12:32 +0200 Subject: [PATCH 2231/5092] document -Zmiri-symbolic-alignment-check --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index f97639ea5bdf..a189fd233f58 100644 --- a/README.md +++ b/README.md @@ -189,6 +189,17 @@ Miri adds its own set of `-Z` flags: entropy. The default seed is 0. **NOTE**: This entropy is not good enough for cryptographic use! Do not generate secret keys in Miri or perform other kinds of cryptographic operations that rely on proper random numbers. +* `-Zmiri-symbolic-alignment-check` makes the alignment check more strict. By + default, alignment is checked by casting the pointer to an integer, and making + sure that is a multiple of the alignment. This can lead to cases where a + program passes the alignment check by pure chance, because things "happened to + be" sufficiently aligned. To avoid such cases, the symbolic alignment check + only takes into account the requested alignment of the relevant allocation, + and the offset into that allocation. This avoids such false negatives, but it + also incurs some false positives when the code does manual integer arithmetic + to ensure alignment. (The standard library `align_to` method works fine in + both modes; under symbolic alignment it only fills the middle slice when the + allocation guarantees sufficient alignment.) * `-Zmiri-track-alloc-id=` shows a backtrace when the given allocation is being allocated or freed. This helps in debugging memory leaks and use after free bugs. From 664706662ff1221e88e70dd5c6ceef391e2528a6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Aug 2020 17:16:53 +0200 Subject: [PATCH 2232/5092] adjust diagnostics to alignment check mode --- src/diagnostics.rs | 7 ++++--- src/machine.rs | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index eed60c2696e1..81cd04921722 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -100,11 +100,12 @@ pub fn report_error<'tcx, 'mir>( panic!("Error should never be raised by Miri: {:?}", e.kind), Unsupported(_) => vec![format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support")], - UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. }) => + UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. }) + if ecx.memory.extra.check_alignment == AlignmentCheck::Symbolic + => vec![ format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior"), - format!("but alignment errors can also be false positives, see https://github.com/rust-lang/miri/issues/1074"), - format!("you can disable the alignment check with `-Zmiri-disable-alignment-check`, but that could hide true bugs") + format!("but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives"), ], UndefinedBehavior(_) => vec![ diff --git a/src/machine.rs b/src/machine.rs index f2abb2ae0e7e..b76159694d82 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -128,7 +128,7 @@ pub struct MemoryExtra { tracked_alloc_id: Option, /// Controls whether alignment of memory accesses is being checked. - check_alignment: AlignmentCheck, + pub(crate) check_alignment: AlignmentCheck, } impl MemoryExtra { From d4e5943259de7573556711ed6496c409dd754ea3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Aug 2020 18:16:34 +0200 Subject: [PATCH 2233/5092] use real align_offset unless we symbolic alignment check is enabled --- src/shims/mod.rs | 35 ++++++++++--------- tests/run-pass/align.rs | 28 +++++++++++---- ...ign_offset.rs => align_offset_symbolic.rs} | 2 ++ ...et.stdout => align_offset_symbolic.stdout} | 0 4 files changed, 41 insertions(+), 24 deletions(-) rename tests/run-pass/{align_offset.rs => align_offset_symbolic.rs} (98%) rename tests/run-pass/{align_offset.stdout => align_offset_symbolic.stdout} (100%) diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 05dd4059eb1b..eab27496cb28 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -13,8 +13,6 @@ pub mod tls; // End module management, begin local code -use std::convert::TryFrom; - use log::trace; use rustc_middle::{mir, ty}; @@ -37,8 +35,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // There are some more lang items we want to hook that CTFE does not hook (yet). if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { let &[ptr, align] = check_arg_count(args)?; - this.align_offset(ptr, align, ret, unwind)?; - return Ok(None); + if this.align_offset(ptr, align, ret, unwind)? { + return Ok(None); + } } // Try to see if we can do something about foreign items. @@ -56,46 +55,48 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(Some(&*this.load_mir(instance.def, None)?)) } + /// Returns `true` if the computation was performed, and `false` if we should just evaluate + /// the actual MIR of `align_offset`. fn align_offset( &mut self, ptr_op: OpTy<'tcx, Tag>, align_op: OpTy<'tcx, Tag>, ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, - ) -> InterpResult<'tcx> { + ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); let (dest, ret) = ret.unwrap(); + if this.memory.extra.check_alignment != AlignmentCheck::Symbolic { + // Just use actual implementation. + return Ok(false); + } + let req_align = this .force_bits(this.read_scalar(align_op)?.check_init()?, this.pointer_size())?; // Stop if the alignment is not a power of two. if !req_align.is_power_of_two() { - return this.start_panic("align_offset: align is not a power-of-two", unwind); + this.start_panic("align_offset: align is not a power-of-two", unwind)?; + return Ok(true); // nothing left to do } let ptr_scalar = this.read_scalar(ptr_op)?.check_init()?; - // Default: no result. - let mut result = this.machine_usize_max(); if let Ok(ptr) = this.force_ptr(ptr_scalar) { // Only do anything if we can identify the allocation this goes to. let cur_align = this.memory.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead)?.1.bytes(); if u128::from(cur_align) >= req_align { // If the allocation alignment is at least the required alignment we use the - // libcore implementation. - // FIXME: is this correct in case of truncation? - result = u64::try_from( - (this.force_bits(ptr_scalar, this.pointer_size())? as *const i8) - .align_offset(usize::try_from(req_align).unwrap()) - ).unwrap(); + // real implementation. + return Ok(false); } } - // Return result, and jump to caller. - this.write_scalar(Scalar::from_machine_usize(result, this), dest)?; + // Return error result (usize::MAX), and jump to caller. + this.write_scalar(Scalar::from_machine_usize(this.machine_usize_max(), this), dest)?; this.go_to_block(ret); - Ok(()) + Ok(true) } } diff --git a/tests/run-pass/align.rs b/tests/run-pass/align.rs index b3d268f45e4b..81e7e8c7ccac 100644 --- a/tests/run-pass/align.rs +++ b/tests/run-pass/align.rs @@ -1,11 +1,25 @@ -// This manually makes sure that we have a pointer with the proper alignment. -// Do this a couple times in a loop because it may work "by chance". +/// This manually makes sure that we have a pointer with the proper alignment. +fn manual_alignment() { + let x = &mut [0u8; 3]; + let base_addr = x as *mut _ as usize; + let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr+1 }; + let u16_ptr = base_addr_aligned as *mut u16; + unsafe { *u16_ptr = 2; } +} + +/// Test standard library `align_to`. +fn align_to() { + const LEN: usize = 128; + let buf = &[0u8; LEN]; + let (l, m, r) = unsafe { buf.align_to::() }; + assert!(m.len()*4 >= LEN-4); + assert!(l.len() + r.len() <= 4); +} + fn main() { + // Do this a couple times in a loop because it may work "by chance". for _ in 0..10 { - let x = &mut [0u8; 3]; - let base_addr = x as *mut _ as usize; - let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr+1 }; - let u16_ptr = base_addr_aligned as *mut u16; - unsafe { *u16_ptr = 2; } + manual_alignment(); + align_to(); } } diff --git a/tests/run-pass/align_offset.rs b/tests/run-pass/align_offset_symbolic.rs similarity index 98% rename from tests/run-pass/align_offset.rs rename to tests/run-pass/align_offset_symbolic.rs index f92163464708..70b2e00896dc 100644 --- a/tests/run-pass/align_offset.rs +++ b/tests/run-pass/align_offset_symbolic.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-symbolic-alignment-check + fn test_align_offset() { let d = Box::new([0u32; 4]); // Get u8 pointer to base diff --git a/tests/run-pass/align_offset.stdout b/tests/run-pass/align_offset_symbolic.stdout similarity index 100% rename from tests/run-pass/align_offset.stdout rename to tests/run-pass/align_offset_symbolic.stdout From 0913653e065896cbbacf164c36673fec48f947d1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Aug 2020 18:31:48 +0200 Subject: [PATCH 2234/5092] make sure we test panic of interpreter-impelemted align_offset --- tests/run-pass/panic/catch_panic.rs | 5 ++++- tests/run-pass/panic/catch_panic.stderr | 24 ++++++++++++------------ 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index 6dc47f2f591a..3afff1d36d36 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -1,4 +1,7 @@ // normalize-stderr-test "[^ ]*core/[a-z_/]+.rs[0-9:]*" -> "$$LOC" +// normalize-stderr-test "catch_panic\.rs:[0-9]{2}" -> "catch_panic.rs:LL" +// We test the `align_offset` panic below, make sure we test the interpreter impl and not the "real" one. +// compile-flags: -Zmiri-symbolic-alignment-check #![feature(never_type)] #![allow(unconditional_panic)] @@ -99,7 +102,7 @@ fn test(expect_msg: Option<&str>, do_panic: impl FnOnce(usize) -> !) { eprintln!("Caught panic message (&str): {}", s); Some(*s) } else { - eprintln!("Failed get caught panic message."); + eprintln!("Failed to get caught panic message."); None }; if let Some(expect_msg) = expect_msg { diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr index f64ff1186619..c31f54aac729 100644 --- a/tests/run-pass/panic/catch_panic.stderr +++ b/tests/run-pass/panic/catch_panic.stderr @@ -1,26 +1,26 @@ -thread 'main' panicked at 'Hello from panic: std', $DIR/catch_panic.rs:50:27 +thread 'main' panicked at 'Hello from panic: std', $DIR/catch_panic.rs:LL:27 Caught panic message (&str): Hello from panic: std -thread 'main' panicked at 'Hello from panic: 1', $DIR/catch_panic.rs:51:26 +thread 'main' panicked at 'Hello from panic: 1', $DIR/catch_panic.rs:LL:26 Caught panic message (String): Hello from panic: 1 -thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:52:26 +thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:LL:26 Caught panic message (String): Hello from panic: 2 -thread 'main' panicked at 'Box', $DIR/catch_panic.rs:53:27 -Failed get caught panic message. -thread 'main' panicked at 'Hello from panic: core', $DIR/catch_panic.rs:56:27 +thread 'main' panicked at 'Box', $DIR/catch_panic.rs:LL:27 +Failed to get caught panic message. +thread 'main' panicked at 'Hello from panic: core', $DIR/catch_panic.rs:LL:27 Caught panic message (String): Hello from panic: core -thread 'main' panicked at 'Hello from panic: 5', $DIR/catch_panic.rs:57:26 +thread 'main' panicked at 'Hello from panic: 5', $DIR/catch_panic.rs:LL:26 Caught panic message (String): Hello from panic: 5 -thread 'main' panicked at 'Hello from panic: 6', $DIR/catch_panic.rs:58:26 +thread 'main' panicked at 'Hello from panic: 6', $DIR/catch_panic.rs:LL:26 Caught panic message (String): Hello from panic: 6 -thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4', $DIR/catch_panic.rs:63:33 +thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4', $DIR/catch_panic.rs:LL:33 Caught panic message (String): index out of bounds: the len is 3 but the index is 4 -thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:67:33 +thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:LL:33 Caught panic message (String): attempt to divide by zero thread 'main' panicked at 'align_offset: align is not a power-of-two', $LOC Caught panic message (String): align_offset: align is not a power-of-two -thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:76:29 +thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:LL:29 Caught panic message (&str): assertion failed: false -thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:77:29 +thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:LL:29 Caught panic message (&str): assertion failed: false thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', $LOC Caught panic message (String): called `Option::unwrap()` on a `None` value From f691e573b242a046b9c411eb8e362b8a0715f07e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 Aug 2020 11:51:18 +0200 Subject: [PATCH 2235/5092] tweak alignment check docs --- README.md | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index a189fd233f58..37ed718a1a2b 100644 --- a/README.md +++ b/README.md @@ -165,9 +165,8 @@ up the sysroot. If you are using `miri` (the Miri driver) directly, see the Miri adds its own set of `-Z` flags: -* `-Zmiri-disable-alignment-check` disables checking pointer alignment. This is - useful to avoid [false positives][alignment-false-positives]. However, setting - this flag means Miri could miss bugs in your program. +* `-Zmiri-disable-alignment-check` disables checking pointer alignment, so you + can focus on other failures. * `-Zmiri-disable-stacked-borrows` disables checking the experimental [Stacked Borrows] aliasing rules. This can make Miri run faster, but it also means no aliasing violations will be detected. @@ -193,12 +192,13 @@ Miri adds its own set of `-Z` flags: default, alignment is checked by casting the pointer to an integer, and making sure that is a multiple of the alignment. This can lead to cases where a program passes the alignment check by pure chance, because things "happened to - be" sufficiently aligned. To avoid such cases, the symbolic alignment check - only takes into account the requested alignment of the relevant allocation, - and the offset into that allocation. This avoids such false negatives, but it - also incurs some false positives when the code does manual integer arithmetic - to ensure alignment. (The standard library `align_to` method works fine in - both modes; under symbolic alignment it only fills the middle slice when the + be" sufficiently aligned -- there is no UB in this execution but there would + be UB in others. To avoid such cases, the symbolic alignment check only takes + into account the requested alignment of the relevant allocation, and the + offset into that allocation. This avoids missing such bugs, but it also + incurs some false positives when the code does manual integer arithmetic to + ensure alignment. (The standard library `align_to` method works fine in both + modes; under symbolic alignment it only fills the middle slice when the allocation guarantees sufficient alignment.) * `-Zmiri-track-alloc-id=` shows a backtrace when the given allocation is being allocated or freed. This helps in debugging memory leaks and @@ -211,8 +211,6 @@ Miri adds its own set of `-Z` flags: assigned to a stack frame. This helps in debugging UB related to Stacked Borrows "protectors". -[alignment-false-positives]: https://github.com/rust-lang/miri/issues/1074 - Some native rustc `-Z` flags are also very relevant for Miri: * `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri From db159b8709dac1cb8adeac91c3257906e55319ec Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 Aug 2020 16:51:48 +0200 Subject: [PATCH 2236/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 198b3970e0d1..e322ff61d1bd 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -814bc4fe9364865bfaa94d7825b8eabc11245c7c +8cdc94e84040ce797fd33d0a7cfda4ec4f2f2421 From 5b1bc4ba94cdbb403388cd7c5b45f5ecf4ccd922 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 Aug 2020 17:09:09 +0200 Subject: [PATCH 2237/5092] make another test more robust against random alignment --- tests/compile-fail/unaligned_pointers/alignment.rs | 8 ++++---- .../unaligned_pointers/reference_to_packed.rs | 14 ++++++++------ .../unaligned_pointers/unaligned_ptr1.rs | 10 ++++++---- .../unaligned_pointers/unaligned_ptr2.rs | 12 +++++++----- .../unaligned_pointers/unaligned_ptr3.rs | 14 ++++++++------ .../unaligned_pointers/unaligned_ptr_addr_of.rs | 12 +++++++----- 6 files changed, 40 insertions(+), 30 deletions(-) diff --git a/tests/compile-fail/unaligned_pointers/alignment.rs b/tests/compile-fail/unaligned_pointers/alignment.rs index 8532f91a5c00..e4d7621b8b12 100644 --- a/tests/compile-fail/unaligned_pointers/alignment.rs +++ b/tests/compile-fail/unaligned_pointers/alignment.rs @@ -1,11 +1,11 @@ +// error-pattern: but alignment 4 is required + fn main() { let mut x = [0u8; 20]; let x_ptr: *mut u8 = x.as_mut_ptr(); // At least one of these is definitely unaligned. - // Currently, we guarantee to complain about the first one already (https://github.com/rust-lang/miri/issues/1074). unsafe { - *(x_ptr as *mut u64) = 42; //~ ERROR accessing memory with alignment 1, but alignment - *(x_ptr.add(1) as *mut u64) = 42; + *(x_ptr as *mut u32) = 42; + *(x_ptr.add(1) as *mut u32) = 42; } - panic!("unreachable in miri"); } diff --git a/tests/compile-fail/unaligned_pointers/reference_to_packed.rs b/tests/compile-fail/unaligned_pointers/reference_to_packed.rs index a1240c90182a..998394c6c70c 100644 --- a/tests/compile-fail/unaligned_pointers/reference_to_packed.rs +++ b/tests/compile-fail/unaligned_pointers/reference_to_packed.rs @@ -10,10 +10,12 @@ struct Foo { } fn main() { - let foo = Foo { - x: 42, - y: 99, - }; - let p = unsafe { &foo.x }; - let i = *p; //~ ERROR alignment 4 is required + for _ in 0..10 { // Try many times as this might work by chance. + let foo = Foo { + x: 42, + y: 99, + }; + let p = unsafe { &foo.x }; + let i = *p; //~ ERROR alignment 4 is required + } } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs index 0a67cfc5a1b3..43e6fd67d246 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs @@ -2,8 +2,10 @@ // compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { - let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. - let x = &x[0] as *const _ as *const u32; - // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. - let _x = unsafe { *x }; //~ ERROR memory with alignment 2, but alignment 4 is required + for _ in 0..10 { // Try many times as this might work by chance. + let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. + let x = &x[0] as *const _ as *const u32; + // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. + let _x = unsafe { *x }; //~ ERROR memory with alignment 2, but alignment 4 is required + } } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs index b1fb2f4aa976..f4ed8d47b53f 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs @@ -2,9 +2,11 @@ // compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { - let x = [2u32, 3]; // Make it big enough so we don't get an out-of-bounds error. - let x = (x.as_ptr() as *const u8).wrapping_offset(3) as *const u32; - // This must fail because alignment is violated: the offset is not sufficiently aligned. - // Also make the offset not a power of 2, that used to ICE. - let _x = unsafe { *x }; //~ ERROR memory with alignment 1, but alignment 4 is required + for _ in 0..10 { // Try many times as this might work by chance. + let x = [2u32, 3]; // Make it big enough so we don't get an out-of-bounds error. + let x = (x.as_ptr() as *const u8).wrapping_offset(3) as *const u32; + // This must fail because alignment is violated: the offset is not sufficiently aligned. + // Also make the offset not a power of 2, that used to ICE. + let _x = unsafe { *x }; //~ ERROR memory with alignment 1, but alignment 4 is required + } } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs index c5a3398384e4..61c2a3cde894 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs @@ -2,10 +2,12 @@ // compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { - let x = [2u16, 3, 4, 5]; // Make it big enough so we don't get an out-of-bounds error. - let x = &x[0] as *const _ as *const *const u8; // cast to ptr-to-ptr, so that we load a ptr - // This must fail because alignment is violated. Test specifically for loading pointers, - // which have special code in miri's memory. - let _x = unsafe { *x }; - //~^ ERROR memory with alignment 2, but alignment + for _ in 0..10 { // Try many times as this might work by chance. + let x = [2u16, 3, 4, 5]; // Make it big enough so we don't get an out-of-bounds error. + let x = &x[0] as *const _ as *const *const u8; // cast to ptr-to-ptr, so that we load a ptr + // This must fail because alignment is violated. Test specifically for loading pointers, + // which have special code in miri's memory. + let _x = unsafe { *x }; + //~^ ERROR but alignment + } } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs index cd52cd44c2b2..88e2634efaf6 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs @@ -4,9 +4,11 @@ use std::ptr; fn main() { - let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. - let x = &x[0] as *const _ as *const u32; - // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. - // The deref is UB even if we just put the result into a raw pointer. - let _x = unsafe { ptr::raw_const!(*x) }; //~ ERROR memory with alignment 2, but alignment 4 is required + for _ in 0..10 { // Try many times as this might work by chance. + let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. + let x = &x[0] as *const _ as *const u32; + // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. + // The deref is UB even if we just put the result into a raw pointer. + let _x = unsafe { ptr::raw_const!(*x) }; //~ ERROR memory with alignment 2, but alignment 4 is required + } } From d5b15297acc5f585b308700d27c0f1420154a14e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Aug 2020 10:11:54 +0200 Subject: [PATCH 2238/5092] forgot to add alignment test loop in one test --- rust-version | 2 +- .../unaligned_pointers/alignment.rs | 2 ++ .../unaligned_pointers/atomic_unaligned.rs | 2 +- .../unaligned_pointers/dyn_alignment.rs | 22 ++++++++++--------- .../intptrcast_alignment_check.rs | 3 ++- .../unaligned_pointers/reference_to_packed.rs | 2 +- .../unaligned_pointers/unaligned_ptr1.rs | 2 +- .../unaligned_pointers/unaligned_ptr2.rs | 14 ++++++------ .../unaligned_pointers/unaligned_ptr3.rs | 3 +-- .../unaligned_pointers/unaligned_ptr_zst.rs | 11 +++++----- 10 files changed, 34 insertions(+), 29 deletions(-) diff --git a/rust-version b/rust-version index e322ff61d1bd..6d85c7fb3888 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8cdc94e84040ce797fd33d0a7cfda4ec4f2f2421 +515c9fa505e18a65d7f61bc3e9eb833b79a68618 diff --git a/tests/compile-fail/unaligned_pointers/alignment.rs b/tests/compile-fail/unaligned_pointers/alignment.rs index e4d7621b8b12..ff31fc6c293e 100644 --- a/tests/compile-fail/unaligned_pointers/alignment.rs +++ b/tests/compile-fail/unaligned_pointers/alignment.rs @@ -1,6 +1,8 @@ // error-pattern: but alignment 4 is required fn main() { + // No retry needed, this fails reliably. + let mut x = [0u8; 20]; let x_ptr: *mut u8 = x.as_mut_ptr(); // At least one of these is definitely unaligned. diff --git a/tests/compile-fail/unaligned_pointers/atomic_unaligned.rs b/tests/compile-fail/unaligned_pointers/atomic_unaligned.rs index 77eff5087dac..7e0704ac6fc0 100644 --- a/tests/compile-fail/unaligned_pointers/atomic_unaligned.rs +++ b/tests/compile-fail/unaligned_pointers/atomic_unaligned.rs @@ -8,6 +8,6 @@ fn main() { let zptr = &z as *const _ as *const u64; unsafe { ::std::intrinsics::atomic_load(zptr); - //~^ ERROR accessing memory with alignment 4, but alignment 8 is required + //~^ERROR accessing memory with alignment 4, but alignment 8 is required } } diff --git a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs index a40db99a72a6..91d9ec475b1f 100644 --- a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs +++ b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs @@ -6,14 +6,16 @@ struct MuchAlign; fn main() { - let buf = [0u32; 256]; - // `buf` is sufficiently aligned for `layout.align` on a `dyn Debug`, but not - // for the actual alignment required by `MuchAlign`. - // We craft a wide reference `&dyn Debug` with the vtable for `MuchAlign`. That should be UB, - // as the reference is not aligned to its dynamic alignment requirements. - let mut ptr = &MuchAlign as &dyn std::fmt::Debug; - // Overwrite the data part of `ptr` so it points to `buf`. - unsafe { (&mut ptr as *mut _ as *mut *const u8).write(&buf as *const _ as *const u8); } - // Re-borrow that. This should be UB. - let _ptr = &*ptr; //~ ERROR alignment 256 is required + for _ in 0..10 { // Try many times as this might work by chance. + let buf = [0u32; 256]; + // `buf` is sufficiently aligned for `layout.align` on a `dyn Debug`, but not + // for the actual alignment required by `MuchAlign`. + // We craft a wide reference `&dyn Debug` with the vtable for `MuchAlign`. That should be UB, + // as the reference is not aligned to its dynamic alignment requirements. + let mut ptr = &MuchAlign as &dyn std::fmt::Debug; + // Overwrite the data part of `ptr` so it points to `buf`. + unsafe { (&mut ptr as *mut _ as *mut *const u8).write(&buf as *const _ as *const u8); } + // Re-borrow that. This should be UB. + let _ptr = &*ptr; //~ERROR alignment 256 is required + } } diff --git a/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs b/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs index 3865d4578637..9872a493c02a 100644 --- a/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs +++ b/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs @@ -9,8 +9,9 @@ fn main() { let x = &mut [0u8; 3]; let base_addr = x as *mut _ as usize; + // Manually make sure the pointer is properly aligned. let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr+1 }; let u16_ptr = base_addr_aligned as *mut u16; - unsafe { *u16_ptr = 2; } //~ ERROR memory with alignment 1, but alignment 2 is required + unsafe { *u16_ptr = 2; } //~ERROR memory with alignment 1, but alignment 2 is required println!("{:?}", x); } diff --git a/tests/compile-fail/unaligned_pointers/reference_to_packed.rs b/tests/compile-fail/unaligned_pointers/reference_to_packed.rs index 998394c6c70c..6fa952118535 100644 --- a/tests/compile-fail/unaligned_pointers/reference_to_packed.rs +++ b/tests/compile-fail/unaligned_pointers/reference_to_packed.rs @@ -16,6 +16,6 @@ fn main() { y: 99, }; let p = unsafe { &foo.x }; - let i = *p; //~ ERROR alignment 4 is required + let i = *p; //~ERROR alignment 4 is required } } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs index 43e6fd67d246..1d72e5170b7c 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs @@ -6,6 +6,6 @@ fn main() { let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. - let _x = unsafe { *x }; //~ ERROR memory with alignment 2, but alignment 4 is required + let _x = unsafe { *x }; //~ERROR memory with alignment 2, but alignment 4 is required } } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs index f4ed8d47b53f..49612e2b8a09 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs @@ -2,11 +2,11 @@ // compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { - for _ in 0..10 { // Try many times as this might work by chance. - let x = [2u32, 3]; // Make it big enough so we don't get an out-of-bounds error. - let x = (x.as_ptr() as *const u8).wrapping_offset(3) as *const u32; - // This must fail because alignment is violated: the offset is not sufficiently aligned. - // Also make the offset not a power of 2, that used to ICE. - let _x = unsafe { *x }; //~ ERROR memory with alignment 1, but alignment 4 is required - } + // No retry needed, this fails reliably. + + let x = [2u32, 3]; // Make it big enough so we don't get an out-of-bounds error. + let x = (x.as_ptr() as *const u8).wrapping_offset(3) as *const u32; + // This must fail because alignment is violated: the offset is not sufficiently aligned. + // Also make the offset not a power of 2, that used to ICE. + let _x = unsafe { *x }; //~ERROR memory with alignment 1, but alignment 4 is required } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs index 61c2a3cde894..ecab83b05a09 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs @@ -7,7 +7,6 @@ fn main() { let x = &x[0] as *const _ as *const *const u8; // cast to ptr-to-ptr, so that we load a ptr // This must fail because alignment is violated. Test specifically for loading pointers, // which have special code in miri's memory. - let _x = unsafe { *x }; - //~^ ERROR but alignment + let _x = unsafe { *x }; //~ERROR but alignment } } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs index beba47359b55..2b6ff3f71c60 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs @@ -2,9 +2,10 @@ // compile-flags: -Zmiri-disable-validation fn main() { - let x = &2u8; - let x = x as *const _ as *const [u32; 0]; - // This must fail because alignment is violated. Test specifically for loading ZST. - let _x = unsafe { *x }; - //~^ ERROR alignment 4 is required + for _ in 0..10 { // Try many times as this might work by chance. + let x = &2u8; + let x = x as *const _ as *const [u32; 0]; + // This must fail because alignment is violated. Test specifically for loading ZST. + let _x = unsafe { *x }; //~ERROR alignment 4 is required + } } From 20942fb3a72b30a69f2ad5775b58b358dabab002 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Wed, 19 Aug 2020 22:19:22 -0700 Subject: [PATCH 2239/5092] Remove byteorder dependency miri hasn't actually depended on byteorder directly for a while. Let's remove this dependency so Rust also depends less on it. --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c33008e48a79..89f568146e07 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,6 @@ required-features = ["rustc_tests"] [dependencies] getrandom = { version = "0.1.8", features = ["std"] } -byteorder = "1.3" env_logger = "0.7.1" log = "0.4" shell-escape = "0.1.4" From 237bea2c179adac24e12c190add9d8366192b32d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 20 Aug 2020 10:13:21 +0200 Subject: [PATCH 2240/5092] avoid promotion in alignment test to get different alignment on each try --- rust-version | 2 +- tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 6d85c7fb3888..e00eb00ee556 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -515c9fa505e18a65d7f61bc3e9eb833b79a68618 +1a22a0ff93d63f738151f096434e732466b4a42e diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs index 2b6ff3f71c60..169e98abf311 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs @@ -3,8 +3,8 @@ fn main() { for _ in 0..10 { // Try many times as this might work by chance. - let x = &2u8; - let x = x as *const _ as *const [u32; 0]; + let x = 2u8; + let x = &x as *const _ as *const [u32; 0]; // This must fail because alignment is violated. Test specifically for loading ZST. let _x = unsafe { *x }; //~ERROR alignment 4 is required } From f3747b635e90faa5ee02e4207c5ed2bca64be274 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Thu, 20 Aug 2020 16:48:35 -0700 Subject: [PATCH 2241/5092] Update lockfile --- Cargo.lock | 385 ++++++++++++++++++++++++++--------------------------- 1 file changed, 188 insertions(+), 197 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f68a6133be57..d09ec19af652 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,618 +4,609 @@ name = "aho-corasick" version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" dependencies = [ - "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr", ] [[package]] name = "anyhow" version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9a60d744a80c30fcb657dfe2c1b22bcb3e814c1a1e3674f32bf5820b570fbff" [[package]] name = "arrayref" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" [[package]] name = "arrayvec" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi", + "libc", + "winapi", ] [[package]] name = "autocfg" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" [[package]] name = "base64" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" [[package]] name = "blake2b_simd" version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" dependencies = [ - "arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayref", + "arrayvec", + "constant_time_eq", ] -[[package]] -name = "byteorder" -version = "1.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "colored" version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" dependencies = [ - "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "atty", + "lazy_static", + "winapi", ] [[package]] name = "compiletest_rs" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f737835bfbbe29ed1ff82d5137520338d7ed5bf1a1d4b9c1c7c58bb45b8fa29" dependencies = [ - "diff 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", - "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustfix 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tester 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "diff", + "filetime", + "getopts", + "libc", + "log", + "miow", + "regex", + "rustfix", + "serde", + "serde_derive", + "serde_json", + "tempfile", + "tester", + "winapi", ] [[package]] name = "constant_time_eq" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" [[package]] name = "crossbeam-utils" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", + "cfg-if", + "lazy_static", ] [[package]] name = "diff" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" [[package]] name = "dirs" version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "dirs-sys", ] [[package]] name = "dirs-sys" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "redox_users", + "winapi", ] [[package]] name = "env_logger" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" dependencies = [ - "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty", + "humantime", + "log", + "regex", + "termcolor", ] [[package]] name = "filetime" version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f59efc38004c988e4201d11d263b8171f49a2e7ec0bdbb71773433f271504a5e" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "redox_syscall", + "winapi", ] [[package]] name = "getopts" version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" dependencies = [ - "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width", ] [[package]] name = "getrandom" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "wasi", ] [[package]] name = "hermit-abi" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" dependencies = [ - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "hex" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" [[package]] name = "humantime" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" dependencies = [ - "quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error", ] [[package]] name = "itoa" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" version = "0.2.68" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" [[package]] name = "log" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", ] [[package]] name = "memchr" version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" [[package]] name = "miow" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226" dependencies = [ - "socket2 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "socket2", + "winapi", ] [[package]] name = "miri" version = "0.1.0" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "colored 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "compiletest_rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "colored", + "compiletest_rs", + "env_logger", + "getrandom", + "hex", + "libc", + "log", + "rand", + "rustc-workspace-hack", + "rustc_version", + "shell-escape", ] [[package]] name = "ppv-lite86" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" [[package]] name = "proc-macro2" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3" dependencies = [ - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid", ] [[package]] name = "quick-error" version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" dependencies = [ - "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", ] [[package]] name = "rand" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", + "libc", + "rand_chacha", + "rand_core", + "rand_hc", ] [[package]] name = "rand_chacha" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" dependencies = [ - "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86", + "rand_core", ] [[package]] name = "rand_core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", ] [[package]] name = "rand_hc" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" dependencies = [ - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core", ] [[package]] name = "redox_syscall" version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" [[package]] name = "redox_users" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" dependencies = [ - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", + "redox_syscall", + "rust-argon2", ] [[package]] name = "regex" version = "1.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6946991529684867e47d86474e3a6d0c0ab9b82d5821e314b1ede31fa3a4b3" dependencies = [ - "aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick", + "memchr", + "regex-syntax", + "thread_local", ] [[package]] name = "regex-syntax" version = "0.6.17" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae" [[package]] name = "remove_dir_all" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi", ] [[package]] name = "rust-argon2" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" dependencies = [ - "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "base64", + "blake2b_simd", + "constant_time_eq", + "crossbeam-utils", ] [[package]] name = "rustc-workspace-hack" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" [[package]] name = "rustc_version" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "semver", ] [[package]] name = "rustfix" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2c50b74badcddeb8f7652fa8323ce440b95286f8e4b64ebfd871c609672704e" dependencies = [ - "anyhow 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", + "anyhow", + "log", + "serde", + "serde_json", ] [[package]] name = "ryu" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "535622e6be132bccd223f4bb2b8ac8d53cda3c7a6394944d3b2b33fb974f9d76" [[package]] name = "semver" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "semver-parser", ] [[package]] name = "semver-parser" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399" dependencies = [ - "serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c" dependencies = [ - "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "serde_json" version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da07b57ee2623368351e9a0488bb0b261322a15a6e0ae53e243cbdc0f4208da9" dependencies = [ - "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa", + "ryu", + "serde", ] [[package]] name = "shell-escape" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9" [[package]] name = "socket2" version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "redox_syscall", + "winapi", ] [[package]] name = "syn" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" dependencies = [ - "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "unicode-xid", ] [[package]] name = "tempfile" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "rand", + "redox_syscall", + "remove_dir_all", + "winapi", ] [[package]] name = "term" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" dependencies = [ - "dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "dirs", + "winapi", ] [[package]] name = "termcolor" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" dependencies = [ - "winapi-util 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util", ] [[package]] name = "tester" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee72ec31009a42b53de9a6b7d8f462b493ab3b1e4767bda1fcdbb52127f13b6c" dependencies = [ - "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts", + "libc", + "term", ] [[package]] name = "thread_local" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static", ] [[package]] name = "unicode-width" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" [[package]] name = "unicode-xid" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "winapi" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa515c5163a99cc82bab70fd3bfdd36d827be85de63737b40fcef2ce084a436e" dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" -"checksum anyhow 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "d9a60d744a80c30fcb657dfe2c1b22bcb3e814c1a1e3674f32bf5820b570fbff" -"checksum arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" -"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" -"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" -"checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" -"checksum blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" -"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" -"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum colored 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" -"checksum compiletest_rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f737835bfbbe29ed1ff82d5137520338d7ed5bf1a1d4b9c1c7c58bb45b8fa29" -"checksum constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" -"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" -"checksum diff 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" -"checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" -"checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" -"checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" -"checksum filetime 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f59efc38004c988e4201d11d263b8171f49a2e7ec0bdbb71773433f271504a5e" -"checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" -"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" -"checksum hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" -"checksum hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" -"checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -"checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" -"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" -"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" -"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" -"checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226" -"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" -"checksum proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3" -"checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" -"checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" -"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -"checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" -"checksum redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" -"checksum regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7f6946991529684867e47d86474e3a6d0c0ab9b82d5821e314b1ede31fa3a4b3" -"checksum regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae" -"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" -"checksum rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" -"checksum rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum rustfix 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f2c50b74badcddeb8f7652fa8323ce440b95286f8e4b64ebfd871c609672704e" -"checksum ryu 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535622e6be132bccd223f4bb2b8ac8d53cda3c7a6394944d3b2b33fb974f9d76" -"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399" -"checksum serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c" -"checksum serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)" = "da07b57ee2623368351e9a0488bb0b261322a15a6e0ae53e243cbdc0f4208da9" -"checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9" -"checksum socket2 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" -"checksum syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" -"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" -"checksum term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" -"checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" -"checksum tester 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee72ec31009a42b53de9a6b7d8f462b493ab3b1e4767bda1fcdbb52127f13b6c" -"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" -"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" -"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" -"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" -"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-util 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "fa515c5163a99cc82bab70fd3bfdd36d827be85de63737b40fcef2ce084a436e" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" From 2619b4fa1883b324f56798e37b79efe98e66e642 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 21 Aug 2020 01:37:56 -0700 Subject: [PATCH 2242/5092] Bump cargo_metadata to 0.11 --- cargo-miri/Cargo.lock | 18 +++++++++++++----- cargo-miri/Cargo.toml | 2 +- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/cargo-miri/Cargo.lock b/cargo-miri/Cargo.lock index c6d80add0787..0052bfa183d0 100644 --- a/cargo-miri/Cargo.lock +++ b/cargo-miri/Cargo.lock @@ -56,13 +56,12 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.9.1" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46e3374c604fb39d1a2f35ed5e4a4e30e60d01fab49446e08f1b3e9a90aef202" +checksum = "89fec17b16f1ac67908af82e47d0a90a7afd0e1827b181cd77504323d3263d35" dependencies = [ - "semver", + "semver 0.10.0", "serde", - "serde_derive", "serde_json", ] @@ -229,7 +228,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" dependencies = [ - "semver", + "semver 0.9.0", ] [[package]] @@ -243,6 +242,15 @@ name = "semver" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "394cec28fa623e00903caf7ba4fa6fb9a0e260280bb8cdbbba029611108a0190" dependencies = [ "semver-parser", "serde", diff --git a/cargo-miri/Cargo.toml b/cargo-miri/Cargo.toml index d6a98be2bbdf..91c478369484 100644 --- a/cargo-miri/Cargo.toml +++ b/cargo-miri/Cargo.toml @@ -14,7 +14,7 @@ test = false # we have no unit tests doctest = false # and no doc tests [dependencies] -cargo_metadata = "0.9.0" +cargo_metadata = "0.11" directories = "2.0" rustc_version = "0.2.3" serde_json = "1.0.40" From 3b7f36ef8d9ce4419c643b774b58831ba86b8a8f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 22 Aug 2020 14:31:46 +0200 Subject: [PATCH 2243/5092] emphasize that some flags are unsound to use --- README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 37ed718a1a2b..f47ee0969040 100644 --- a/README.md +++ b/README.md @@ -166,14 +166,17 @@ up the sysroot. If you are using `miri` (the Miri driver) directly, see the Miri adds its own set of `-Z` flags: * `-Zmiri-disable-alignment-check` disables checking pointer alignment, so you - can focus on other failures. + can focus on other failures, but it means Miri can miss bugs in your program. + Using this flag is **unsound**. * `-Zmiri-disable-stacked-borrows` disables checking the experimental [Stacked Borrows] aliasing rules. This can make Miri run faster, but it also - means no aliasing violations will be detected. + means no aliasing violations will be detected. Using this flag is **unsound** + (but the affected soundness rules are experimental). * `-Zmiri-disable-validation` disables enforcing validity invariants, which are enforced by default. This is mostly useful to focus on other failures (such - as out-of-bounds accesses) first. Setting this flag means Miri will miss bugs - in your program. However, this can also help to make Miri run faster. + as out-of-bounds accesses) first. Setting this flag means Miri can miss bugs + in your program. However, this can also help to make Miri run faster. Using + this flag is **unsound**. * `-Zmiri-disable-isolation` disables host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness. From 8da9d23e5e7a509e8bee4e0a4b12b9e694a6f225 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 22 Aug 2020 18:03:34 +0200 Subject: [PATCH 2244/5092] tweak test matrix: test big-endian, and test less on macOS host (it is slow) --- ci.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ci.sh b/ci.sh index ac0d080a4839..c2c36e1efc1f 100755 --- a/ci.sh +++ b/ci.sh @@ -43,9 +43,8 @@ if [ "${TRAVIS_OS_NAME:-}" == linux ]; then MIRI_TEST_TARGET=x86_64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests elif [ "${TRAVIS_OS_NAME:-}" == osx ]; then - MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests + MIRI_TEST_TARGET=mips64-unknown-linux-gnuabi64 run_tests # big-endian architecture MIRI_TEST_TARGET=x86_64-pc-windows-msvc run_tests - MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests elif [ "${CI_WINDOWS:-}" == True ]; then MIRI_TEST_TARGET=x86_64-unknown-linux-gnu run_tests MIRI_TEST_TARGET=x86_64-apple-darwin run_tests From df9b2127ce5c8ac567f0dc60e3b7b828e10d5613 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 22 Aug 2020 18:07:43 +0200 Subject: [PATCH 2245/5092] fix a test for big-endian targets --- tests/run-pass/transmute_fat2.rs | 8 ++++++-- tests/run-pass/transmute_fat2.stderr | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/run-pass/transmute_fat2.rs b/tests/run-pass/transmute_fat2.rs index 3dff2cc1e0c9..2f0271d5813f 100644 --- a/tests/run-pass/transmute_fat2.rs +++ b/tests/run-pass/transmute_fat2.rs @@ -1,9 +1,13 @@ fn main() { - #[cfg(target_pointer_width="64")] + #[cfg(all(target_endian="little", target_pointer_width="64"))] let bad = unsafe { std::mem::transmute::(42) }; - #[cfg(target_pointer_width="32")] + #[cfg(all(target_endian="big", target_pointer_width="64"))] + let bad = unsafe { + std::mem::transmute::(42 << 64) + }; + #[cfg(all(target_endian="little", target_pointer_width="32"))] let bad = unsafe { std::mem::transmute::(42) }; diff --git a/tests/run-pass/transmute_fat2.stderr b/tests/run-pass/transmute_fat2.stderr index 08849a5b517a..c8298a6c23c6 100644 --- a/tests/run-pass/transmute_fat2.stderr +++ b/tests/run-pass/transmute_fat2.stderr @@ -1 +1 @@ -thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', $DIR/transmute_fat2.rs:11:5 +thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', $DIR/transmute_fat2.rs:15:5 From 2f9de18f8870e4265478b2d98d6c3dac6a62336d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Aug 2020 10:06:44 +0200 Subject: [PATCH 2246/5092] rustup; account for ptr_offset_from stabilization --- rust-version | 2 +- tests/run-pass/ptr_offset.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/rust-version b/rust-version index e00eb00ee556..15fcdfa88c36 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1a22a0ff93d63f738151f096434e732466b4a42e +c4b6d9411f939c1ad7b3521b907fa101f3360462 diff --git a/tests/run-pass/ptr_offset.rs b/tests/run-pass/ptr_offset.rs index f83720b547c0..71d057b8c9ce 100644 --- a/tests/run-pass/ptr_offset.rs +++ b/tests/run-pass/ptr_offset.rs @@ -1,4 +1,3 @@ -#![feature(ptr_offset_from)] use std::{mem, ptr}; fn main() { From 3bc8302a54653f3f92b015106a5322f7ce8e29a0 Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 25 Aug 2020 19:00:46 -0500 Subject: [PATCH 2247/5092] Support --test/--bin/--lib in cargo-miri --- cargo-miri/bin.rs | 80 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 71 insertions(+), 9 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index a2d6c3fc5b71..029c5e5610c2 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -378,6 +378,69 @@ path = "lib.rs" } } +enum CargoTargets { + All, + Filtered { lib: bool, bin: Vec, test: Vec }, +} + +impl CargoTargets { + fn matches(&self, kind: &str, name: &str) -> bool { + match self { + CargoTargets::All => true, + CargoTargets::Filtered { lib, bin, test } => match kind { + "lib" => *lib, + "bin" => bin.iter().any(|n| n == name), + "test" => test.iter().any(|n| n == name), + _ => false, + }, + } + } +} + +fn parse_cargo_miri_args( + mut args: impl Iterator, +) -> (CargoTargets, Vec, Vec) { + let mut lib_present = false; + let mut bin_targets = Vec::new(); + let mut test_targets = Vec::new(); + let mut additional_args = Vec::new(); + while let Some(arg) = args.next() { + match arg { + arg if arg == "--" => break, + arg if arg == "--lib" => lib_present = true, + arg if arg == "--bin" => { + if let Some(binary) = args.next() { + if binary == "--" { + show_error(format!("\"--bin\" takes one argument.")); + } else { + bin_targets.push(binary) + } + } else { + show_error(format!("\"--bin\" takes one argument.")); + } + } + arg if arg == "--test" => { + if let Some(test) = args.next() { + if test == "--" { + show_error(format!("\"--test\" takes one argument.")); + } else { + test_targets.push(test) + } + } else { + show_error(format!("\"--test\" takes one argument.")); + } + } + other => additional_args.push(other), + } + } + let targets = if !lib_present && bin_targets.len() == 0 && test_targets.len() == 0 { + CargoTargets::All + } else { + CargoTargets::Filtered { lib: lib_present, bin: bin_targets, test: test_targets } + }; + (targets, additional_args, args.collect()) +} + fn in_cargo_miri() { let (subcommand, skip) = match std::env::args().nth(2).as_deref() { Some("test") => (MiriCommand::Test, 3), @@ -398,13 +461,18 @@ fn in_cargo_miri() { return; } + let (target_filters, cargo_args, miri_args) = + parse_cargo_miri_args(std::env::args().skip(skip)); + // Now run the command. for target in list_targets() { - let mut args = std::env::args().skip(skip); let kind = target .kind .get(0) .expect("badly formatted cargo metadata: target::kind is an empty array"); + if !target_filters.matches(kind, &target.name) { + continue; + } // Now we run `cargo check $FLAGS $ARGS`, giving the user the // change to add additional arguments. `FLAGS` is set to identify // this target. The user gets to control what gets actually passed to Miri. @@ -412,8 +480,6 @@ fn in_cargo_miri() { cmd.arg("check"); match (subcommand, kind.as_str()) { (MiriCommand::Run, "bin") => { - // FIXME: we just run all the binaries here. - // We should instead support `cargo miri --bin foo`. cmd.arg("--bin").arg(target.name); } (MiriCommand::Test, "test") => { @@ -430,10 +496,7 @@ fn in_cargo_miri() { _ => continue, } // Forward user-defined `cargo` args until first `--`. - while let Some(arg) = args.next() { - if arg == "--" { - break; - } + for arg in cargo_args.iter() { cmd.arg(arg); } // We want to always run `cargo` with `--target`. This later helps us detect @@ -450,8 +513,7 @@ fn in_cargo_miri() { // our actual target crate (the binary or the test we are running). // Since we're using "cargo check", we have no other way of passing // these arguments. - let args_vec: Vec = args.collect(); - cmd.env("MIRI_ARGS", serde_json::to_string(&args_vec).expect("failed to serialize args")); + cmd.env("MIRI_ARGS", serde_json::to_string(&miri_args).expect("failed to serialize args")); // Set `RUSTC_WRAPPER` to ourselves. Cargo will prepend that binary to its usual invocation, // i.e., the first argument is `rustc` -- which is what we use in `main` to distinguish From 40847abd5f2da77bce75ee12564a49b01c3588e7 Mon Sep 17 00:00:00 2001 From: David Cook Date: Wed, 26 Aug 2020 18:41:01 -0500 Subject: [PATCH 2248/5092] Review comments --- cargo-miri/bin.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 029c5e5610c2..9ac1f3e4c2d4 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -406,7 +406,10 @@ fn parse_cargo_miri_args( let mut additional_args = Vec::new(); while let Some(arg) = args.next() { match arg { - arg if arg == "--" => break, + arg if arg == "--" => { + // Miri arguments begin after the first "--". + break; + } arg if arg == "--lib" => lib_present = true, arg if arg == "--bin" => { if let Some(binary) = args.next() { @@ -419,6 +422,7 @@ fn parse_cargo_miri_args( show_error(format!("\"--bin\" takes one argument.")); } } + arg if arg.starts_with("--bin=") => bin_targets.push((&arg[6..]).to_string()), arg if arg == "--test" => { if let Some(test) = args.next() { if test == "--" { @@ -430,6 +434,7 @@ fn parse_cargo_miri_args( show_error(format!("\"--test\" takes one argument.")); } } + arg if arg.starts_with("--test=") => test_targets.push((&arg[7..]).to_string()), other => additional_args.push(other), } } @@ -480,6 +485,7 @@ fn in_cargo_miri() { cmd.arg("check"); match (subcommand, kind.as_str()) { (MiriCommand::Run, "bin") => { + // FIXME: we default to running all binaries here. cmd.arg("--bin").arg(target.name); } (MiriCommand::Test, "test") => { @@ -495,7 +501,7 @@ fn in_cargo_miri() { // The remaining targets we do not even want to build. _ => continue, } - // Forward user-defined `cargo` args until first `--`. + // Forward further `cargo` args. for arg in cargo_args.iter() { cmd.arg(arg); } From 4608341ca071634b9aae2ea967f25b5cfe970e7e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 27 Aug 2020 08:37:11 +0200 Subject: [PATCH 2249/5092] add encoding_rs OOB arithmetic --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f47ee0969040..d8474868703d 100644 --- a/README.md +++ b/README.md @@ -320,6 +320,7 @@ Definite bugs found: * [TiKV performing an unaligned pointer access](https://github.com/tikv/tikv/issues/7613) * [`servo_arc` creating a dangling shared reference](https://github.com/servo/servo/issues/26357) * [TiKV constructing out-of-bounds pointers (and overlapping mutable references)](https://github.com/tikv/tikv/pull/7751) +* [`encoding_rs` doing out-of-bounds pointer arithmetic](https://github.com/hsivonen/encoding_rs/pull/53) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From 39e6baeb91fc720494ae8ebd6f7c2cd29a19130f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 27 Aug 2020 09:27:58 +0200 Subject: [PATCH 2250/5092] rustup --- rust-version | 2 +- tests/run-pass/heap_allocator.rs | 30 +++++++++++++++--------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/rust-version b/rust-version index 15fcdfa88c36..f5fb70874020 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c4b6d9411f939c1ad7b3521b907fa101f3360462 +18b0585b52741ca158dfebef7968326e2704352e diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index 557550d6f433..cf9a2f4b6925 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -6,39 +6,39 @@ use std::slice; fn check_alloc(mut allocator: T) { unsafe { for &align in &[4, 8, 16, 32] { - let layout = Layout::from_size_align(20, align).unwrap(); + let layout_20 = Layout::from_size_align(20, align).unwrap(); + let layout_40 = Layout::from_size_align(40, 4*align).unwrap(); + let layout_10 = Layout::from_size_align(10, align/2).unwrap(); for _ in 0..32 { - let a = allocator.alloc(layout).unwrap().as_non_null_ptr(); - assert_eq!(a.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); - allocator.dealloc(a, layout); + let a = allocator.alloc(layout_20).unwrap().as_non_null_ptr(); + assert_eq!(a.as_ptr() as usize % layout_20.align(), 0, "pointer is incorrectly aligned"); + allocator.dealloc(a, layout_20); } - let p1 = allocator.alloc_zeroed(layout).unwrap().as_non_null_ptr(); - assert_eq!(p1.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); + let p1 = allocator.alloc_zeroed(layout_20).unwrap().as_non_null_ptr(); + assert_eq!(p1.as_ptr() as usize % layout_20.align(), 0, "pointer is incorrectly aligned"); assert_eq!(*p1.as_ptr(), 0); // old size < new size - let p2 = allocator.grow(p1, layout, 40).unwrap().as_non_null_ptr(); - let layout = Layout::from_size_align(40, align).unwrap(); - assert_eq!(p2.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); + let p2 = allocator.grow(p1, layout_20, layout_40).unwrap().as_non_null_ptr(); + assert_eq!(p2.as_ptr() as usize % layout_40.align(), 0, "pointer is incorrectly aligned"); let slice = slice::from_raw_parts(p2.as_ptr(), 20); assert_eq!(&slice, &[0_u8; 20]); // old size == new size - let p3 = allocator.grow(p2, layout, 40).unwrap().as_non_null_ptr(); - assert_eq!(p3.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); + let p3 = allocator.grow(p2, layout_40, layout_40).unwrap().as_non_null_ptr(); + assert_eq!(p3.as_ptr() as usize % layout_40.align(), 0, "pointer is incorrectly aligned"); let slice = slice::from_raw_parts(p3.as_ptr(), 20); assert_eq!(&slice, &[0_u8; 20]); // old size > new size - let p4 = allocator.shrink(p3, layout, 10).unwrap().as_non_null_ptr(); - let layout = Layout::from_size_align(10, align).unwrap(); - assert_eq!(p4.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); + let p4 = allocator.shrink(p3, layout_40, layout_10).unwrap().as_non_null_ptr(); + assert_eq!(p4.as_ptr() as usize % layout_10.align(), 0, "pointer is incorrectly aligned"); let slice = slice::from_raw_parts(p4.as_ptr(), 10); assert_eq!(&slice, &[0_u8; 10]); - allocator.dealloc(p4, layout); + allocator.dealloc(p4, layout_10); } } } From 64e2d3e2d0d8de0f750381ba8786fdd398c538a4 Mon Sep 17 00:00:00 2001 From: David Cook Date: Thu, 27 Aug 2020 05:00:56 -0500 Subject: [PATCH 2251/5092] Review comments --- cargo-miri/bin.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 9ac1f3e4c2d4..98304d247f98 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -422,7 +422,7 @@ fn parse_cargo_miri_args( show_error(format!("\"--bin\" takes one argument.")); } } - arg if arg.starts_with("--bin=") => bin_targets.push((&arg[6..]).to_string()), + arg if arg.starts_with("--bin=") => bin_targets.push((&arg["--bin=".len()..]).to_string()), arg if arg == "--test" => { if let Some(test) = args.next() { if test == "--" { @@ -434,7 +434,7 @@ fn parse_cargo_miri_args( show_error(format!("\"--test\" takes one argument.")); } } - arg if arg.starts_with("--test=") => test_targets.push((&arg[7..]).to_string()), + arg if arg.starts_with("--test=") => test_targets.push((&arg["--test=".len()..]).to_string()), other => additional_args.push(other), } } @@ -466,6 +466,7 @@ fn in_cargo_miri() { return; } + // FIXME: this accepts --test, --lib, and multiple --bin for `cargo miri run`. let (target_filters, cargo_args, miri_args) = parse_cargo_miri_args(std::env::args().skip(skip)); From 5d9d75fc1f2fc87f419913db7bf8a073b04f955d Mon Sep 17 00:00:00 2001 From: David Cook Date: Fri, 28 Aug 2020 23:12:11 -0500 Subject: [PATCH 2252/5092] Test cargo miri target selection --- test-cargo-miri/run-test.py | 12 ++++++++++++ test-cargo-miri/test.stdout.ref4 | 12 ++++++++++++ test-cargo-miri/test.stdout.ref5 | 6 ++++++ 3 files changed, 30 insertions(+) create mode 100644 test-cargo-miri/test.stdout.ref4 create mode 100644 test-cargo-miri/test.stdout.ref5 diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 57b23a6a2afe..a258c7f73c2d 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -50,6 +50,10 @@ def test_cargo_miri_run(): cargo_miri("run"), "stdout.ref", "stderr.ref" ) + test("cargo miri run (with target)", + cargo_miri("run") + ["--bin", "cargo-miri-test"], + "stdout.ref", "stderr.ref" + ) test("cargo miri run (with arguments)", cargo_miri("run") + ["--", "--", "hello world", '"hello world"'], "stdout.ref", "stderr.ref2" @@ -68,6 +72,14 @@ def test_cargo_miri_test(): cargo_miri("test") + ["--", "-Zmiri-disable-isolation", "--", "num_cpus"], "test.stdout.ref3", "test.stderr.ref" ) + test("cargo miri test (test target)", + cargo_miri("test") + ["--test", "test"], + "test.stdout.ref4", "test.stderr.ref" + ) + test("cargo miri test (bin target)", + cargo_miri("test") + ["--bin", "cargo-miri-test"], + "test.stdout.ref5", "test.stderr.ref" + ) os.chdir(os.path.dirname(os.path.realpath(__file__))) diff --git a/test-cargo-miri/test.stdout.ref4 b/test-cargo-miri/test.stdout.ref4 new file mode 100644 index 000000000000..b6403bf6c091 --- /dev/null +++ b/test-cargo-miri/test.stdout.ref4 @@ -0,0 +1,12 @@ + +running 7 tests +test do_panic ... ok +test does_not_work_on_miri ... ignored +test entropy_rng ... ok +test fail_index_check ... ok +test num_cpus ... ok +test simple1 ... ok +test simple2 ... ok + +test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out + diff --git a/test-cargo-miri/test.stdout.ref5 b/test-cargo-miri/test.stdout.ref5 new file mode 100644 index 000000000000..4caa30a7f0e5 --- /dev/null +++ b/test-cargo-miri/test.stdout.ref5 @@ -0,0 +1,6 @@ + +running 1 test +test test::rng ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out + From 3ba7f46058db2baa7e03cbca5570a4a4c1ac832b Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 29 Aug 2020 21:38:37 -0500 Subject: [PATCH 2253/5092] Move panic payload state from Machine to Thread --- src/machine.rs | 6 -- src/shims/panic.rs | 10 +-- src/thread.rs | 37 +++++++++ tests/run-pass/panic/concurrent-panic.rs | 80 ++++++++++++++++++++ tests/run-pass/panic/concurrent-panic.stderr | 4 + 5 files changed, 124 insertions(+), 13 deletions(-) create mode 100644 tests/run-pass/panic/concurrent-panic.rs create mode 100644 tests/run-pass/panic/concurrent-panic.stderr diff --git a/src/machine.rs b/src/machine.rs index b76159694d82..ebe3c509ad87 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -252,11 +252,6 @@ pub struct Evaluator<'mir, 'tcx> { pub(crate) file_handler: shims::posix::FileHandler, pub(crate) dir_handler: shims::posix::DirHandler, - /// The temporary used for storing the argument of - /// the call to `miri_start_panic` (the panic payload) when unwinding. - /// This is pointer-sized, and matches the `Payload` type in `src/libpanic_unwind/miri.rs`. - pub(crate) panic_payload: Option>, - /// The "time anchor" for this machine's monotone clock (for `Instant` simulation). pub(crate) time_anchor: Instant, @@ -291,7 +286,6 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { validate, file_handler: Default::default(), dir_handler: Default::default(), - panic_payload: None, time_anchor: Instant::now(), layouts, threads: ThreadManager::default(), diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 45a41b9b7be0..b9d8ceb1dfb5 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -48,11 +48,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Get the raw pointer stored in arg[0] (the panic payload). let &[payload] = check_arg_count(args)?; let payload = this.read_scalar(payload)?.check_init()?; - assert!( - this.machine.panic_payload.is_none(), - "the panic runtime should avoid double-panics" - ); - this.machine.panic_payload = Some(payload); + this.set_panic_payload(payload); // Jump to the unwind block to begin unwinding. this.unwind_to_block(unwind); @@ -132,9 +128,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We set the return value of `try` to 1, since there was a panic. this.write_scalar(Scalar::from_i32(1), catch_unwind.dest)?; - // `panic_payload` holds what was passed to `miri_start_panic`. + // The Thread's `panic_payload` holds what was passed to `miri_start_panic`. // This is exactly the second argument we need to pass to `catch_fn`. - let payload = this.machine.panic_payload.take().unwrap(); + let payload = this.take_panic_payload(); // Push the `catch_fn` stackframe. let f_instance = this.memory.get_fn(catch_unwind.catch_fn)?.as_instance()?; diff --git a/src/thread.rs b/src/thread.rs index cffbec93c5ca..dd5358bfb5e0 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -106,12 +106,21 @@ enum ThreadJoinStatus { /// A thread. pub struct Thread<'mir, 'tcx> { state: ThreadState, + /// Name of the thread. thread_name: Option>, + /// The virtual call stack. stack: Vec>>, + /// The join status. join_status: ThreadJoinStatus, + + /// The temporary used for storing the argument of + /// the call to `miri_start_panic` (the panic payload) when unwinding. + /// This is pointer-sized, and matches the `Payload` type in `src/libpanic_unwind/miri.rs`. + panic_payload: Option>, + } impl<'mir, 'tcx> Thread<'mir, 'tcx> { @@ -150,6 +159,7 @@ impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> { thread_name: None, stack: Vec::new(), join_status: ThreadJoinStatus::Joinable, + panic_payload: None, } } } @@ -509,6 +519,21 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { throw_machine_stop!(TerminationInfo::Deadlock); } } + + /// Store the panic payload when beginning unwinding. + fn set_panic_payload(&mut self, payload: Scalar) { + let thread = self.active_thread_mut(); + assert!( + thread.panic_payload.is_none(), + "the panic runtime should avoid double-panics" + ); + thread.panic_payload = Some(payload); + } + + /// Retrieve the panic payload, for use in `catch_unwind`. + fn take_panic_payload(&mut self) -> Scalar { + self.active_thread_mut().panic_payload.take().unwrap() + } } // Public interface to thread management. @@ -686,4 +711,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(()) } + + /// Store the panic payload when beginning unwinding. + fn set_panic_payload(&mut self, payload: Scalar) { + let this = self.eval_context_mut(); + this.machine.threads.set_panic_payload(payload); + } + + /// Retrieve the panic payload, for use in `catch_unwind`. + fn take_panic_payload(&mut self) -> Scalar { + let this = self.eval_context_mut(); + this.machine.threads.take_panic_payload() + } } diff --git a/tests/run-pass/panic/concurrent-panic.rs b/tests/run-pass/panic/concurrent-panic.rs new file mode 100644 index 000000000000..e798f514711f --- /dev/null +++ b/tests/run-pass/panic/concurrent-panic.rs @@ -0,0 +1,80 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +use std::sync::{Arc, Condvar, Mutex}; +use std::thread::{spawn, JoinHandle}; + +struct BlockOnDrop(Option>); + +impl BlockOnDrop { + fn new(handle: JoinHandle<()>) -> BlockOnDrop { + BlockOnDrop(Some(handle)) + } +} + +impl Drop for BlockOnDrop { + fn drop(&mut self) { + let _ = self.0.take().unwrap().join(); + } +} + +/// Cause a panic in one thread while another thread is unwinding. +fn main() { + let t1_started_pair = Arc::new((Mutex::new(false), Condvar::new())); + let t2_started_pair = Arc::new((Mutex::new(false), Condvar::new())); + + let t1_continue_mutex = Arc::new(Mutex::new(())); + let t1_continue_guard = t1_continue_mutex.lock(); + + let t1 = { + let t1_started_pair = t1_started_pair.clone(); + let t1_continue_mutex = t1_continue_mutex.clone(); + spawn(move || { + let (mutex, condvar) = &*t1_started_pair; + *mutex.lock().unwrap() = true; + condvar.notify_one(); + + drop(t1_continue_mutex.lock()); + panic!("panic in thread 1"); + }) + }; + let t2 = { + let t2_started_pair = t2_started_pair.clone(); + let block_on_drop = BlockOnDrop::new(t1); + spawn(move || { + let _ = block_on_drop; + + let (mutex, condvar) = &*t2_started_pair; + *mutex.lock().unwrap() = true; + condvar.notify_one(); + + panic!("panic in thread 2"); + }) + }; + + // Wait for thread 1 to signal it has started. + let (t1_started_mutex, t1_started_condvar) = &*t1_started_pair; + let mut t1_started_guard = t1_started_mutex.lock().unwrap(); + while !*t1_started_guard { + t1_started_guard = t1_started_condvar.wait(t1_started_guard).unwrap(); + } + // Thread 1 should now be blocked waiting on t1_continue_mutex. + + // Wait for thread 2 to signal it has started. + let (t2_started_mutex, t2_started_condvar) = &*t2_started_pair; + let mut t2_started_guard = t2_started_mutex.lock().unwrap(); + while !*t2_started_guard { + t2_started_guard = t2_started_condvar.wait(t2_started_guard).unwrap(); + } + // Thread 2 should now have already panicked and be in the middle of + // unwinding. It should now be blocked on joining thread 1. + + // Unlock t1_continue_mutex, and allow thread 1 to proceed. + drop(t1_continue_guard); + // Thread 1 will panic the next time it is scheduled. This will test the + // behavior of interest to this test, whether Miri properly handles + // concurrent panics in two different threads. + + // Block the main thread on waiting to join thread 2. Thread 2 should + // already be blocked on joining thread 1, so thread 1 will be scheduled + // to run next, as it is the only ready thread. + assert!(t2.join().is_err()); +} diff --git a/tests/run-pass/panic/concurrent-panic.stderr b/tests/run-pass/panic/concurrent-panic.stderr new file mode 100644 index 000000000000..6652137c9659 --- /dev/null +++ b/tests/run-pass/panic/concurrent-panic.stderr @@ -0,0 +1,4 @@ +warning: thread support is experimental. For example, Miri does not detect data races yet. + +thread '' panicked at 'panic in thread 2', $DIR/concurrent-panic.rs:49:13 +thread '' panicked at 'panic in thread 1', $DIR/concurrent-panic.rs:36:13 From da2f268443bcaf889896dd3ca4e6635b9e5cc4b5 Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 31 Aug 2020 19:32:14 -0500 Subject: [PATCH 2254/5092] Review comments --- src/shims/panic.rs | 9 +++-- src/thread.rs | 36 ++++---------------- tests/run-pass/panic/concurrent-panic.rs | 29 +++++++++++----- tests/run-pass/panic/concurrent-panic.stderr | 11 ++++-- 4 files changed, 43 insertions(+), 42 deletions(-) diff --git a/src/shims/panic.rs b/src/shims/panic.rs index b9d8ceb1dfb5..f907b76b679c 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -48,7 +48,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Get the raw pointer stored in arg[0] (the panic payload). let &[payload] = check_arg_count(args)?; let payload = this.read_scalar(payload)?.check_init()?; - this.set_panic_payload(payload); + let thread = this.active_thread_mut(); + assert!( + thread.panic_payload.is_none(), + "the panic runtime should avoid double-panics" + ); + thread.panic_payload = Some(payload); // Jump to the unwind block to begin unwinding. this.unwind_to_block(unwind); @@ -130,7 +135,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // The Thread's `panic_payload` holds what was passed to `miri_start_panic`. // This is exactly the second argument we need to pass to `catch_fn`. - let payload = this.take_panic_payload(); + let payload = this.active_thread_mut().panic_payload.take().unwrap(); // Push the `catch_fn` stackframe. let f_instance = this.memory.get_fn(catch_unwind.catch_fn)?.as_instance()?; diff --git a/src/thread.rs b/src/thread.rs index dd5358bfb5e0..a542d0895b25 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -119,8 +119,7 @@ pub struct Thread<'mir, 'tcx> { /// The temporary used for storing the argument of /// the call to `miri_start_panic` (the panic payload) when unwinding. /// This is pointer-sized, and matches the `Payload` type in `src/libpanic_unwind/miri.rs`. - panic_payload: Option>, - + pub(crate) panic_payload: Option>, } impl<'mir, 'tcx> Thread<'mir, 'tcx> { @@ -519,21 +518,6 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { throw_machine_stop!(TerminationInfo::Deadlock); } } - - /// Store the panic payload when beginning unwinding. - fn set_panic_payload(&mut self, payload: Scalar) { - let thread = self.active_thread_mut(); - assert!( - thread.panic_payload.is_none(), - "the panic runtime should avoid double-panics" - ); - thread.panic_payload = Some(payload); - } - - /// Retrieve the panic payload, for use in `catch_unwind`. - fn take_panic_payload(&mut self) -> Scalar { - self.active_thread_mut().panic_payload.take().unwrap() - } } // Public interface to thread management. @@ -593,6 +577,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.threads.get_active_thread_id() } + #[inline] + fn active_thread_mut(&mut self) -> &mut Thread<'mir, 'tcx> { + let this = self.eval_context_mut(); + this.machine.threads.active_thread_mut() + } + #[inline] fn get_total_thread_count(&self) -> usize { let this = self.eval_context_ref(); @@ -711,16 +701,4 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(()) } - - /// Store the panic payload when beginning unwinding. - fn set_panic_payload(&mut self, payload: Scalar) { - let this = self.eval_context_mut(); - this.machine.threads.set_panic_payload(payload); - } - - /// Retrieve the panic payload, for use in `catch_unwind`. - fn take_panic_payload(&mut self) -> Scalar { - let this = self.eval_context_mut(); - this.machine.threads.take_panic_payload() - } } diff --git a/tests/run-pass/panic/concurrent-panic.rs b/tests/run-pass/panic/concurrent-panic.rs index e798f514711f..0ff5788e204d 100644 --- a/tests/run-pass/panic/concurrent-panic.rs +++ b/tests/run-pass/panic/concurrent-panic.rs @@ -1,4 +1,8 @@ // ignore-windows: Concurrency on Windows is not supported yet. + +//! Cause a panic in one thread while another thread is unwinding. This checks +//! that separate threads have their own panicking state. + use std::sync::{Arc, Condvar, Mutex}; use std::thread::{spawn, JoinHandle}; @@ -12,11 +16,12 @@ impl BlockOnDrop { impl Drop for BlockOnDrop { fn drop(&mut self) { + eprintln!("Thread 2 blocking on thread 1"); let _ = self.0.take().unwrap().join(); + eprintln!("Thread 1 has exited"); } } -/// Cause a panic in one thread while another thread is unwinding. fn main() { let t1_started_pair = Arc::new((Mutex::new(false), Condvar::new())); let t2_started_pair = Arc::new((Mutex::new(false), Condvar::new())); @@ -28,6 +33,7 @@ fn main() { let t1_started_pair = t1_started_pair.clone(); let t1_continue_mutex = t1_continue_mutex.clone(); spawn(move || { + eprintln!("Thread 1 starting, will block on mutex"); let (mutex, condvar) = &*t1_started_pair; *mutex.lock().unwrap() = true; condvar.notify_one(); @@ -36,6 +42,16 @@ fn main() { panic!("panic in thread 1"); }) }; + + // Wait for thread 1 to signal it has started. + let (t1_started_mutex, t1_started_condvar) = &*t1_started_pair; + let mut t1_started_guard = t1_started_mutex.lock().unwrap(); + while !*t1_started_guard { + t1_started_guard = t1_started_condvar.wait(t1_started_guard).unwrap(); + } + eprintln!("Thread 1 reported it has started"); + // Thread 1 should now be blocked waiting on t1_continue_mutex. + let t2 = { let t2_started_pair = t2_started_pair.clone(); let block_on_drop = BlockOnDrop::new(t1); @@ -50,24 +66,18 @@ fn main() { }) }; - // Wait for thread 1 to signal it has started. - let (t1_started_mutex, t1_started_condvar) = &*t1_started_pair; - let mut t1_started_guard = t1_started_mutex.lock().unwrap(); - while !*t1_started_guard { - t1_started_guard = t1_started_condvar.wait(t1_started_guard).unwrap(); - } - // Thread 1 should now be blocked waiting on t1_continue_mutex. - // Wait for thread 2 to signal it has started. let (t2_started_mutex, t2_started_condvar) = &*t2_started_pair; let mut t2_started_guard = t2_started_mutex.lock().unwrap(); while !*t2_started_guard { t2_started_guard = t2_started_condvar.wait(t2_started_guard).unwrap(); } + eprintln!("Thread 2 reported it has started"); // Thread 2 should now have already panicked and be in the middle of // unwinding. It should now be blocked on joining thread 1. // Unlock t1_continue_mutex, and allow thread 1 to proceed. + eprintln!("Unlocking mutex"); drop(t1_continue_guard); // Thread 1 will panic the next time it is scheduled. This will test the // behavior of interest to this test, whether Miri properly handles @@ -77,4 +87,5 @@ fn main() { // already be blocked on joining thread 1, so thread 1 will be scheduled // to run next, as it is the only ready thread. assert!(t2.join().is_err()); + eprintln!("Thread 2 has exited"); } diff --git a/tests/run-pass/panic/concurrent-panic.stderr b/tests/run-pass/panic/concurrent-panic.stderr index 6652137c9659..d538efdb0e88 100644 --- a/tests/run-pass/panic/concurrent-panic.stderr +++ b/tests/run-pass/panic/concurrent-panic.stderr @@ -1,4 +1,11 @@ warning: thread support is experimental. For example, Miri does not detect data races yet. -thread '' panicked at 'panic in thread 2', $DIR/concurrent-panic.rs:49:13 -thread '' panicked at 'panic in thread 1', $DIR/concurrent-panic.rs:36:13 +Thread 1 starting, will block on mutex +Thread 1 reported it has started +thread '' panicked at 'panic in thread 2', $DIR/concurrent-panic.rs:65:13 +Thread 2 blocking on thread 1 +Thread 2 reported it has started +Unlocking mutex +thread '' panicked at 'panic in thread 1', $DIR/concurrent-panic.rs:42:13 +Thread 1 has exited +Thread 2 has exited From 34664623066a762235004c08d0b9a188c0d65d2a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 1 Sep 2020 10:55:09 +0200 Subject: [PATCH 2255/5092] rustup, fix test --- rust-version | 2 +- tests/run-pass/stacked-borrows/interior_mutability.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index f5fb70874020..6e9f26cbe410 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -18b0585b52741ca158dfebef7968326e2704352e +d9cd4a33f53689bc0847775669a14f666a138fd7 diff --git a/tests/run-pass/stacked-borrows/interior_mutability.rs b/tests/run-pass/stacked-borrows/interior_mutability.rs index bd19f153deeb..17e628a09f23 100644 --- a/tests/run-pass/stacked-borrows/interior_mutability.rs +++ b/tests/run-pass/stacked-borrows/interior_mutability.rs @@ -54,7 +54,7 @@ fn into_interior_mutability() { let mut x: MaybeUninit<(Cell, u32)> = MaybeUninit::uninit(); x.as_ptr(); x.write((Cell::new(0), 1)); - let ptr = unsafe { x.get_ref() }; + let ptr = unsafe { x.assume_init_ref() }; assert_eq!(ptr.1, 1); } From 7a2c6812b94f5a96fa3a3b16ee4fbc885fc8676c Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 31 Aug 2020 21:29:09 -0500 Subject: [PATCH 2256/5092] Per-thread errno storage --- src/eval.rs | 6 ------ src/helpers.rs | 23 +++++++++++++++++++---- src/machine.rs | 4 ---- src/shims/posix/linux/foreign_items.rs | 2 +- src/shims/posix/macos/foreign_items.rs | 2 +- src/thread.rs | 10 ++++++++++ tests/run-pass/libc.rs | 20 ++++++++++++++++++++ tests/run-pass/libc.stderr | 2 ++ 8 files changed, 53 insertions(+), 16 deletions(-) create mode 100644 tests/run-pass/libc.stderr diff --git a/src/eval.rs b/src/eval.rs index 8e4604c3360a..e36a0019cdcb 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -193,12 +193,6 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( StackPopCleanup::None { cleanup: true }, )?; - // Set the last_error to 0 - let errno_layout = ecx.machine.layouts.u32; - let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Machine.into()); - ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?; - ecx.machine.last_error = Some(errno_place); - Ok((ecx, ret_place)) } diff --git a/src/helpers.rs b/src/helpers.rs index 0426115773d9..f56818726235 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -394,17 +394,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) } + /// Get last error variable as a place, lazily allocating thread-local storage for it if + /// necessary. + fn last_error_place(&mut self) -> InterpResult<'tcx, MPlaceTy<'tcx, Tag>> { + let this = self.eval_context_mut(); + if let Some(errno_place) = this.active_thread_ref().last_error { + Ok(errno_place) + } else { + let errno_layout = this.machine.layouts.u32; + let errno_place = this.allocate(errno_layout, MiriMemoryKind::Machine.into()); + this.write_scalar(Scalar::from_u32(0), errno_place.into())?; + this.active_thread_mut().last_error = Some(errno_place); + Ok(errno_place) + } + } + /// Sets the last error variable. fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let errno_place = this.machine.last_error.unwrap(); + let errno_place = this.last_error_place()?; this.write_scalar(scalar, errno_place.into()) } /// Gets the last error variable. - fn get_last_error(&self) -> InterpResult<'tcx, Scalar> { - let this = self.eval_context_ref(); - let errno_place = this.machine.last_error.unwrap(); + fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + let errno_place = this.last_error_place()?; this.read_scalar(errno_place.into())?.check_init() } diff --git a/src/machine.rs b/src/machine.rs index ebe3c509ad87..6defb2d053aa 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -236,9 +236,6 @@ pub struct Evaluator<'mir, 'tcx> { pub(crate) argv: Option>, pub(crate) cmd_line: Option>, - /// Last OS error location in memory. It is a 32-bit integer. - pub(crate) last_error: Option>, - /// TLS state. pub(crate) tls: TlsData<'tcx>, @@ -280,7 +277,6 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { argc: None, argv: None, cmd_line: None, - last_error: None, tls: TlsData::default(), communicate, validate, diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index ccb0ef8226e6..357c55c926f1 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -21,7 +21,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // errno "__errno_location" => { let &[] = check_arg_count(args)?; - let errno_place = this.machine.last_error.unwrap(); + let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index 2e7258c800ac..72ec7a5d9702 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -20,7 +20,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // errno "__error" => { let &[] = check_arg_count(args)?; - let errno_place = this.machine.last_error.unwrap(); + let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } diff --git a/src/thread.rs b/src/thread.rs index a542d0895b25..eeaee7dc44d5 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -120,6 +120,9 @@ pub struct Thread<'mir, 'tcx> { /// the call to `miri_start_panic` (the panic payload) when unwinding. /// This is pointer-sized, and matches the `Payload` type in `src/libpanic_unwind/miri.rs`. pub(crate) panic_payload: Option>, + + /// Last OS error location in memory. It is a 32-bit integer. + pub(crate) last_error: Option>, } impl<'mir, 'tcx> Thread<'mir, 'tcx> { @@ -159,6 +162,7 @@ impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> { stack: Vec::new(), join_status: ThreadJoinStatus::Joinable, panic_payload: None, + last_error: None, } } } @@ -583,6 +587,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.threads.active_thread_mut() } + #[inline] + fn active_thread_ref(&self) -> &Thread<'mir, 'tcx> { + let this = self.eval_context_ref(); + this.machine.threads.active_thread_ref() + } + #[inline] fn get_total_thread_count(&self) -> usize { let this = self.eval_context_ref(); diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index 6f30cb5a9150..ab9a690fe1d7 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -212,6 +212,24 @@ fn test_prctl_thread_name() { } } +/// Tests whether each thread has its own `__errno_location`. +fn test_thread_local_errno() { + #[cfg(not(target_os = "macos"))] + use libc::__errno_location; + #[cfg(target_os = "macos")] + use libc::__error as __errno_location; + + unsafe { + *__errno_location() = 0xBEEF; + std::thread::spawn(|| { + assert_eq!(*__errno_location(), 0); + *__errno_location() = 0xBAD1DEA; + assert_eq!(*__errno_location(), 0xBAD1DEA); + }).join().unwrap(); + assert_eq!(*__errno_location(), 0xBEEF); + } +} + fn main() { #[cfg(target_os = "linux")] test_posix_fadvise(); @@ -229,4 +247,6 @@ fn main() { #[cfg(target_os = "linux")] test_prctl_thread_name(); + + test_thread_local_errno(); } diff --git a/tests/run-pass/libc.stderr b/tests/run-pass/libc.stderr new file mode 100644 index 000000000000..2dbfb7721d36 --- /dev/null +++ b/tests/run-pass/libc.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental. For example, Miri does not detect data races yet. + From a6746ad893c7f6cbcb367276534e329110e75d83 Mon Sep 17 00:00:00 2001 From: David Cook Date: Wed, 2 Sep 2020 20:58:41 -0500 Subject: [PATCH 2257/5092] Add comment --- src/helpers.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/helpers.rs b/src/helpers.rs index f56818726235..39af9d3143aa 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -401,6 +401,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(errno_place) = this.active_thread_ref().last_error { Ok(errno_place) } else { + // Allocate new place, set initial value to 0. let errno_layout = this.machine.layouts.u32; let errno_place = this.allocate(errno_layout, MiriMemoryKind::Machine.into()); this.write_scalar(Scalar::from_u32(0), errno_place.into())?; From 4f2f87b2dff5b586d3130737716fcbb3d3086d57 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Fri, 4 Sep 2020 22:03:45 +0200 Subject: [PATCH 2258/5092] Change `ty.kind` -> `ty.kind()` --- rust-version | 2 +- src/helpers.rs | 2 +- src/shims/intrinsics.rs | 8 ++++---- src/stacked_borrows.rs | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rust-version b/rust-version index 6e9f26cbe410..797f6e825a74 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d9cd4a33f53689bc0847775669a14f666a138fd7 +d2454643e137bde519786ee9e650c455d7ad6f34 diff --git a/src/helpers.rs b/src/helpers.rs index 39af9d3143aa..d3fcb1c53dba 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -280,7 +280,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Hook to detect `UnsafeCell`. fn visit_value(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty); - let is_unsafe_cell = match v.layout.ty.kind { + let is_unsafe_cell = match v.layout.ty.kind() { ty::Adt(adt, _) => Some(adt.did) == self.ecx.tcx.lang_items().unsafe_cell_type(), _ => false, diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 53d4d08eba0d..4d8801f17887 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -299,7 +299,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[val] = check_arg_count(args)?; let val = this.read_immediate(val)?; - let res = match val.layout.ty.kind { + let res = match val.layout.ty.kind() { ty::Float(FloatTy::F32) => { this.float_to_int_unchecked(val.to_scalar()?.to_f32()?, dest.layout.ty)? } @@ -528,10 +528,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let f = f.round_to_integral(Round::TowardZero).value; // Step 2: Cast the truncated float to the target integer type and see if we lose any information in this step. - Ok(match dest_ty.kind { + Ok(match dest_ty.kind() { // Unsigned ty::Uint(t) => { - let size = Integer::from_attr(this, attr::IntType::UnsignedInt(t)).size(); + let size = Integer::from_attr(this, attr::IntType::UnsignedInt(*t)).size(); let res = f.to_u128(size.bits_usize()); if res.status.is_empty() { // No status flags means there was no further rounding or other loss of precision. @@ -546,7 +546,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Signed ty::Int(t) => { - let size = Integer::from_attr(this, attr::IntType::SignedInt(t)).size(); + let size = Integer::from_attr(this, attr::IntType::SignedInt(*t)).size(); let res = f.to_i128(size.bits_usize()); if res.status.is_empty() { // No status flags means there was no further rounding or other loss of precision. diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index cefe334574b4..817ed99d2bb2 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -623,7 +623,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Cannot use `builtin_deref` because that reports *immutable* for `Box`, // making it useless. fn qualify(ty: ty::Ty<'_>, kind: RetagKind) -> Option<(RefKind, bool)> { - match ty.kind { + match ty.kind() { // References are simple. ty::Ref(_, _, Mutability::Mut) => Some(( RefKind::Unique { two_phase: kind == RetagKind::TwoPhase }, From 6d323e10324298a8fc7c268079c7999794525a7a Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 6 Sep 2020 17:08:41 -0500 Subject: [PATCH 2259/5092] Refactor timespec parsing, improve error handling --- src/helpers.rs | 37 ++++++++++++++++++ src/shims/posix/sync.rs | 39 ++++++++----------- .../run-pass/concurrency/libc_pthread_cond.rs | 20 ++++++++++ 3 files changed, 74 insertions(+), 22 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index d3fcb1c53dba..f8bf9598c14f 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,6 +1,7 @@ use std::convert::{TryFrom, TryInto}; use std::mem; use std::num::NonZeroUsize; +use std::time::Duration; use log::trace; @@ -41,6 +42,9 @@ fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option: crate::MiriEvalContextExt<'mir, 'tcx> { /// Gets an instance for a path. fn resolve_path(&self, path: &[&str]) -> ty::Instance<'tcx> { @@ -512,6 +516,39 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; this.write_scalar(value, value_place.into()) } + + /// Parse a `timespec` struct and return it as a `std::time::Duration`. The outer `Result` is + /// for interpreter errors encountered while reading memory, and the inner `Result` indicates + /// whether the value in the `timespec` struct is invalid. Some libc functions will return + /// `EINVAL` if the struct's value is invalid. + fn read_timespec( + &mut self, + timespec_ptr_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, Result> { + let this = self.eval_context_mut(); + let tp = this.deref_operand(timespec_ptr_op)?; + let seconds_place = this.mplace_field(tp, 0)?; + let seconds_scalar = this.read_scalar(seconds_place.into())?; + let seconds = seconds_scalar.to_machine_isize(this)?; + let nanoseconds_place = this.mplace_field(tp, 1)?; + let nanoseconds_scalar = this.read_scalar(nanoseconds_place.into())?; + let nanoseconds = nanoseconds_scalar.to_machine_isize(this)?; + + let seconds: u64 = if let Ok(s) = seconds.try_into() { + s + } else { + return Ok(Err(TimespecError)); + }; + let nanoseconds: u32 = if let Ok(ns) = nanoseconds.try_into() { + if ns >= 1_000_000_000 { + return Ok(Err(TimespecError)); + } + ns + } else { + return Ok(Err(TimespecError)); + }; + Ok(Ok(Duration::new(seconds, nanoseconds))) + } } /// Check that the number of args is what we expect. diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 28a45b194771..94704bff32ac 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -1,11 +1,10 @@ -use std::convert::TryInto; -use std::time::{Duration, SystemTime}; +use std::time::SystemTime; use crate::*; +use helpers::TimespecError; use stacked_borrows::Tag; use thread::Time; - // pthread_mutexattr_t is either 4 or 8 bytes, depending on the platform. // Our chosen memory layout for emulation (does not have to match the platform layout!): @@ -698,25 +697,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mutex_id = mutex_get_or_create_id(this, mutex_op)?; let active_thread = this.get_active_thread(); - release_cond_mutex_and_block(this, active_thread, mutex_id)?; - this.condvar_wait(id, active_thread, mutex_id); - - // We return success for now and override it in the timeout callback. - this.write_scalar(Scalar::from_i32(0), dest)?; - // Extract the timeout. let clock_id = cond_get_clock_id(this, cond_op)?.to_i32()?; - let duration = { - let tp = this.deref_operand(abstime_op)?; - let seconds_place = this.mplace_field(tp, 0)?; - let seconds = this.read_scalar(seconds_place.into())?; - let nanoseconds_place = this.mplace_field(tp, 1)?; - let nanoseconds = this.read_scalar(nanoseconds_place.into())?; - let (seconds, nanoseconds) = ( - seconds.to_machine_usize(this)?, - nanoseconds.to_machine_usize(this)?.try_into().unwrap(), - ); - Duration::new(seconds, nanoseconds) + let duration = match this.read_timespec(abstime_op)? { + Ok(duration) => duration, + Err(TimespecError) => { + let einval = this.eval_libc("EINVAL")?; + this.write_scalar(einval, dest)?; + return Ok(()); + } }; let timeout_time = if clock_id == this.eval_libc_i32("CLOCK_REALTIME")? { @@ -727,6 +716,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("unsupported clock id: {}", clock_id); }; + release_cond_mutex_and_block(this, active_thread, mutex_id)?; + this.condvar_wait(id, active_thread, mutex_id); + + // We return success for now and override it in the timeout callback. + this.write_scalar(Scalar::from_i32(0), dest)?; + // Register the timeout callback. this.register_timeout_callback( active_thread, @@ -740,8 +735,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ecx.condvar_remove_waiter(id, active_thread); // Set the return value: we timed out. - let timeout = ecx.eval_libc_i32("ETIMEDOUT")?; - ecx.write_scalar(Scalar::from_i32(timeout), dest)?; + let etimedout = ecx.eval_libc("ETIMEDOUT")?; + ecx.write_scalar(etimedout, dest)?; Ok(()) }), diff --git a/tests/run-pass/concurrency/libc_pthread_cond.rs b/tests/run-pass/concurrency/libc_pthread_cond.rs index 8aa3b210f4b0..e1ca63f9ca43 100644 --- a/tests/run-pass/concurrency/libc_pthread_cond.rs +++ b/tests/run-pass/concurrency/libc_pthread_cond.rs @@ -37,6 +37,26 @@ fn test_timed_wait_timeout(clock_id: i32) { ); let elapsed_time = current_time.elapsed().as_millis(); assert!(900 <= elapsed_time && elapsed_time <= 1300); + + let invalid_timeout_1 = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: 1_000_000_000 }; + assert_eq!( + libc::pthread_cond_timedwait( + &mut cond as *mut _, + &mut mutex as *mut _, + &invalid_timeout_1 + ), + libc::EINVAL + ); + let invalid_timeout_2 = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: -1 }; + assert_eq!( + libc::pthread_cond_timedwait( + &mut cond as *mut _, + &mut mutex as *mut _, + &invalid_timeout_2 + ), + libc::EINVAL + ); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); assert_eq!(libc::pthread_cond_destroy(&mut cond as *mut _), 0); From 417ac2939a87b84c70f4c8b3c2a343c253a5c5d1 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 6 Sep 2020 17:09:24 -0500 Subject: [PATCH 2260/5092] Implement libc::nanosleep shim --- src/shims/posix/foreign_items.rs | 5 ++++ src/shims/time.rs | 39 +++++++++++++++++++++++++++++++- tests/run-pass/time.rs | 11 +++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 151ab95f1e3c..26c743b360e0 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -382,6 +382,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.sched_yield()?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "nanosleep" => { + let &[req, rem] = check_arg_count(args)?; + let result = this.nanosleep(req, rem)?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } // Miscellaneous "isatty" => { diff --git a/src/shims/time.rs b/src/shims/time.rs index 193c87f7f099..32c1ce888ed0 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -3,7 +3,8 @@ use std::convert::TryFrom; use crate::stacked_borrows::Tag; use crate::*; -use helpers::{immty_from_int_checked, immty_from_uint_checked}; +use helpers::{immty_from_int_checked, immty_from_uint_checked, TimespecError}; +use thread::Time; /// Returns the time elapsed between the provided time and the unix epoch as a `Duration`. pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Duration> { @@ -177,4 +178,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_packed_immediates(info, &imms)?; Ok(0) // KERN_SUCCESS } + + fn nanosleep( + &mut self, + req_op: OpTy<'tcx, Tag>, + _rem: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + // Signal handlers are not supported, so rem will never be written to. + + let this = self.eval_context_mut(); + + this.check_no_isolation("nanosleep")?; + + let duration = match this.read_timespec(req_op)? { + Ok(duration) => duration, + Err(TimespecError) => { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + return Ok(-1); + } + }; + let timeout_time = Time::RealTime(SystemTime::now().checked_add(duration).unwrap()); + + let active_thread = this.get_active_thread(); + this.block_thread(active_thread); + + this.register_timeout_callback( + active_thread, + timeout_time, + Box::new(move |ecx| { + ecx.unblock_thread(active_thread); + Ok(()) + }), + ); + + Ok(0) + } } diff --git a/tests/run-pass/time.rs b/tests/run-pass/time.rs index d430062a1533..ae287234d177 100644 --- a/tests/run-pass/time.rs +++ b/tests/run-pass/time.rs @@ -8,6 +8,14 @@ fn duration_sanity(diff: Duration) { assert!(diff.as_millis() < 500); } +#[cfg(unix)] +fn test_sleep() { + let before = Instant::now(); + std::thread::sleep(Duration::from_millis(100)); + let after = Instant::now(); + assert!((after - before).as_millis() >= 100); +} + fn main() { // Check `SystemTime`. let now1 = SystemTime::now(); @@ -36,4 +44,7 @@ fn main() { assert_eq!(now1 + diff, now2); assert_eq!(now2 - diff, now1); duration_sanity(diff); + + #[cfg(unix)] + test_sleep(); } From 210f18d6c7962ae5125947e89d38cac34c65b6a8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Sep 2020 10:24:04 +0200 Subject: [PATCH 2261/5092] work around rustc optimizations becoming too smart --- ci.sh | 2 +- rust-version | 2 +- tests/compile-fail/invalid_bool.rs | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/ci.sh b/ci.sh index c2c36e1efc1f..a1d0a38c4fb8 100755 --- a/ci.sh +++ b/ci.sh @@ -25,7 +25,7 @@ function run_tests { ./miri test --locked if ! [ -n "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with MIR optimizations - # FIXME:only testing level 1 because of . + # FIXME: only testing level 1 because of . MIRI_TEST_FLAGS="-Z mir-opt-level=1" ./miri test --locked fi # "miri test" has built the sysroot for us, now this should pass without diff --git a/rust-version b/rust-version index 797f6e825a74..d2cf18f80f17 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d2454643e137bde519786ee9e650c455d7ad6f34 +e114d6228b948ce056de0bcdec2603c8e89d3727 diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index 6dee9ec3c91a..933ee91c7d4d 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -2,7 +2,9 @@ // Make sure we find these even with many checks disabled. // compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +fn dont_optimize(x: T) -> T { x } + fn main() { let b = unsafe { std::mem::transmute::(2) }; - let _x = b == true; //~ ERROR interpreting an invalid 8-bit value as a bool: 0x02 + let _x = b == dont_optimize(true); //~ ERROR interpreting an invalid 8-bit value as a bool: 0x02 } From d9bc19a7b078e75052167496fff3c4d91c7bbd66 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Sep 2020 10:35:39 +0200 Subject: [PATCH 2262/5092] test opt-level 2 --- ci.sh | 4 ++-- tests/run-pass/float.rs | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ci.sh b/ci.sh index a1d0a38c4fb8..915a4cf2fd3d 100755 --- a/ci.sh +++ b/ci.sh @@ -25,8 +25,8 @@ function run_tests { ./miri test --locked if ! [ -n "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with MIR optimizations - # FIXME: only testing level 1 because of . - MIRI_TEST_FLAGS="-Z mir-opt-level=1" ./miri test --locked + # FIXME: only testing level 2 because of . + MIRI_TEST_FLAGS="-Z mir-opt-level=2" ./miri test --locked fi # "miri test" has built the sysroot for us, now this should pass without # any interactive questions. diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index 0b89f11b0609..ea6269c22fb9 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmir-opt-level=0 +// FIXME: Using opt-level 2 here makes the test take forever (https://github.com/rust-lang/rust/issues/76433). #![feature(stmt_expr_attributes)] use std::fmt::Debug; From 088af66f85ef5e885202ad258670936f8edc3c53 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Sep 2020 11:16:16 +0200 Subject: [PATCH 2263/5092] better optimization suppression Co-authored-by: bjorn3 --- tests/compile-fail/invalid_bool.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index 933ee91c7d4d..8d8cce1c7e50 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -2,6 +2,7 @@ // Make sure we find these even with many checks disabled. // compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +#[inline(never)] fn dont_optimize(x: T) -> T { x } fn main() { From 029c851d7c0eee03178c96c890ec974262b2ee21 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Sep 2020 11:22:49 +0200 Subject: [PATCH 2264/5092] another optimization work-around --- tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs index 169e98abf311..a9db5ff7df39 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs @@ -2,8 +2,8 @@ // compile-flags: -Zmiri-disable-validation fn main() { - for _ in 0..10 { // Try many times as this might work by chance. - let x = 2u8; + for i in 0..10 { // Try many times as this might work by chance. + let x = i as u8; let x = &x as *const _ as *const [u32; 0]; // This must fail because alignment is violated. Test specifically for loading ZST. let _x = unsafe { *x }; //~ERROR alignment 4 is required From 3ba1035d279e0acfc3aaf68e8bd055f2d1ffb205 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Sep 2020 11:26:24 +0200 Subject: [PATCH 2265/5092] use standard black_box function --- tests/compile-fail/invalid_bool.rs | 6 ++---- tests/run-pass/float.rs | 7 ++----- tests/run-pass/u128.rs | 3 ++- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index 8d8cce1c7e50..796d8220dc19 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -1,11 +1,9 @@ // Validation makes this fail in the wrong place // Make sure we find these even with many checks disabled. // compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation - -#[inline(never)] -fn dont_optimize(x: T) -> T { x } +#![feature(test)] fn main() { let b = unsafe { std::mem::transmute::(2) }; - let _x = b == dont_optimize(true); //~ ERROR interpreting an invalid 8-bit value as a bool: 0x02 + let _x = b == std::hint::black_box(true); //~ ERROR interpreting an invalid 8-bit value as a bool: 0x02 } diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index ea6269c22fb9..327ea17731a8 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -1,7 +1,8 @@ // compile-flags: -Zmir-opt-level=0 // FIXME: Using opt-level 2 here makes the test take forever (https://github.com/rust-lang/rust/issues/76433). -#![feature(stmt_expr_attributes)] +#![feature(stmt_expr_attributes, test)] use std::fmt::Debug; +use std::hint::black_box; // Helper function to avoid promotion so that this tests "run-time" casts, not CTFE. // Doesn't make a big difference when running this in Miri, but it means we can compare this @@ -341,10 +342,6 @@ fn ops() { /// Tests taken from rustc test suite. /// -// Poor-man's black-box -#[inline(never)] -fn black_box(x: T) -> T { x } - macro_rules! test { ($val:expr, $src_ty:ident -> $dest_ty:ident, $expected:expr) => ( // black_box disables constant evaluation to test run-time conversions: diff --git a/tests/run-pass/u128.rs b/tests/run-pass/u128.rs index a2ca7746b1c0..bbc667c5ddeb 100644 --- a/tests/run-pass/u128.rs +++ b/tests/run-pass/u128.rs @@ -1,4 +1,5 @@ -fn b(t: T) -> T { t } +#![feature(test)] +use std::hint::black_box as b; fn main() { let x: u128 = 0xFFFF_FFFF_FFFF_FFFF__FFFF_FFFF_FFFF_FFFF; From 3fdbc0fd3f4e0117d708cac58b35fa841eed19af Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Sep 2020 13:10:31 +0200 Subject: [PATCH 2266/5092] fix referenced issue --- tests/run-pass/float.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index 327ea17731a8..88f841eae74d 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -1,5 +1,5 @@ // compile-flags: -Zmir-opt-level=0 -// FIXME: Using opt-level 2 here makes the test take forever (https://github.com/rust-lang/rust/issues/76433). +// FIXME: Using opt-level 2 here makes the test take forever (https://github.com/rust-lang/rust/issues/73717). #![feature(stmt_expr_attributes, test)] use std::fmt::Debug; use std::hint::black_box; From 33e928c9ca456f36ac662657333d6ca046be17bd Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 7 Sep 2020 10:54:39 -0500 Subject: [PATCH 2267/5092] Review comments --- src/helpers.rs | 23 +++++++++---------- src/shims/posix/sync.rs | 5 ++-- src/shims/time.rs | 8 +++---- .../run-pass/concurrency/libc_pthread_cond.rs | 12 ++++++++++ tests/run-pass/time.rs | 1 + 5 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index f8bf9598c14f..f5094b169f9e 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -42,9 +42,6 @@ fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option: crate::MiriEvalContextExt<'mir, 'tcx> { /// Gets an instance for a path. fn resolve_path(&self, path: &[&str]) -> ty::Instance<'tcx> { @@ -517,14 +514,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(value, value_place.into()) } - /// Parse a `timespec` struct and return it as a `std::time::Duration`. The outer `Result` is - /// for interpreter errors encountered while reading memory, and the inner `Result` indicates - /// whether the value in the `timespec` struct is invalid. Some libc functions will return - /// `EINVAL` if the struct's value is invalid. + /// Parse a `timespec` struct and return it as a `std::time::Duration`. It returns `None` + /// if the value in the `timespec` struct is invalid. Some libc functions will return + /// `EINVAL` in this case. fn read_timespec( &mut self, timespec_ptr_op: OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, Result> { + ) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); let tp = this.deref_operand(timespec_ptr_op)?; let seconds_place = this.mplace_field(tp, 0)?; @@ -537,17 +533,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let seconds: u64 = if let Ok(s) = seconds.try_into() { s } else { - return Ok(Err(TimespecError)); + // tv_sec must be non-negative. + return Ok(None); }; let nanoseconds: u32 = if let Ok(ns) = nanoseconds.try_into() { if ns >= 1_000_000_000 { - return Ok(Err(TimespecError)); + // tv_nsec must not be greater than 999,999,999. + return Ok(None); } ns } else { - return Ok(Err(TimespecError)); + // tv_nsec must be non-negative. + return Ok(None); }; - Ok(Ok(Duration::new(seconds, nanoseconds))) + Ok(Some(Duration::new(seconds, nanoseconds))) } } diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 94704bff32ac..6918fb7fd7ec 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -1,7 +1,6 @@ use std::time::SystemTime; use crate::*; -use helpers::TimespecError; use stacked_borrows::Tag; use thread::Time; @@ -700,8 +699,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Extract the timeout. let clock_id = cond_get_clock_id(this, cond_op)?.to_i32()?; let duration = match this.read_timespec(abstime_op)? { - Ok(duration) => duration, - Err(TimespecError) => { + Some(duration) => duration, + None => { let einval = this.eval_libc("EINVAL")?; this.write_scalar(einval, dest)?; return Ok(()); diff --git a/src/shims/time.rs b/src/shims/time.rs index 32c1ce888ed0..9d6d6ed38daa 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -3,7 +3,7 @@ use std::convert::TryFrom; use crate::stacked_borrows::Tag; use crate::*; -use helpers::{immty_from_int_checked, immty_from_uint_checked, TimespecError}; +use helpers::{immty_from_int_checked, immty_from_uint_checked}; use thread::Time; /// Returns the time elapsed between the provided time and the unix epoch as a `Duration`. @@ -191,14 +191,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("nanosleep")?; let duration = match this.read_timespec(req_op)? { - Ok(duration) => duration, - Err(TimespecError) => { + Some(duration) => duration, + None => { let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; return Ok(-1); } }; - let timeout_time = Time::RealTime(SystemTime::now().checked_add(duration).unwrap()); + let timeout_time = Time::Monotonic(Instant::now().checked_add(duration).unwrap()); let active_thread = this.get_active_thread(); this.block_thread(active_thread); diff --git a/tests/run-pass/concurrency/libc_pthread_cond.rs b/tests/run-pass/concurrency/libc_pthread_cond.rs index e1ca63f9ca43..d4e52bb3a97b 100644 --- a/tests/run-pass/concurrency/libc_pthread_cond.rs +++ b/tests/run-pass/concurrency/libc_pthread_cond.rs @@ -38,6 +38,8 @@ fn test_timed_wait_timeout(clock_id: i32) { let elapsed_time = current_time.elapsed().as_millis(); assert!(900 <= elapsed_time && elapsed_time <= 1300); + // Test that invalid nanosecond values (above 10^9 or negative) are rejected with the + // correct error code. let invalid_timeout_1 = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: 1_000_000_000 }; assert_eq!( libc::pthread_cond_timedwait( @@ -56,6 +58,16 @@ fn test_timed_wait_timeout(clock_id: i32) { ), libc::EINVAL ); + // Test that invalid second values (negative) are rejected with the correct error code. + let invalid_timeout_3 = libc::timespec { tv_sec: -1, tv_nsec: 0 }; + assert_eq!( + libc::pthread_cond_timedwait( + &mut cond as *mut _, + &mut mutex as *mut _, + &invalid_timeout_3 + ), + libc::EINVAL + ); assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); diff --git a/tests/run-pass/time.rs b/tests/run-pass/time.rs index ae287234d177..e76c8573c516 100644 --- a/tests/run-pass/time.rs +++ b/tests/run-pass/time.rs @@ -8,6 +8,7 @@ fn duration_sanity(diff: Duration) { assert!(diff.as_millis() < 500); } +// Thus far, only `libc::nanosleep`, is implemented, not `c::Sleep`. #[cfg(unix)] fn test_sleep() { let before = Instant::now(); From 597360f49995c3c79f955ff7d61a52082382a412 Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 7 Sep 2020 11:31:28 -0500 Subject: [PATCH 2268/5092] Simplify read_timespec error handling --- src/helpers.rs | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index f5094b169f9e..9e4bc21ab1b3 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -530,23 +530,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let nanoseconds_scalar = this.read_scalar(nanoseconds_place.into())?; let nanoseconds = nanoseconds_scalar.to_machine_isize(this)?; - let seconds: u64 = if let Ok(s) = seconds.try_into() { - s - } else { + Ok((move || { // tv_sec must be non-negative. - return Ok(None); - }; - let nanoseconds: u32 = if let Ok(ns) = nanoseconds.try_into() { - if ns >= 1_000_000_000 { - // tv_nsec must not be greater than 999,999,999. - return Ok(None); - } - ns - } else { + let seconds: u64 = seconds.try_into().ok()?; // tv_nsec must be non-negative. - return Ok(None); - }; - Ok(Some(Duration::new(seconds, nanoseconds))) + let nanoseconds: u32 = nanoseconds.try_into().ok()?; + if nanoseconds >= 1_000_000_000 { + // tv_nsec must not be greater than 999,999,999. + return None; + } + Some(Duration::new(seconds, nanoseconds)) + })()) } } From 06aaea1d6bd94bb715e558c9a5c9c8af27be8895 Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 7 Sep 2020 15:05:26 -0500 Subject: [PATCH 2269/5092] Update comment --- tests/run-pass/time.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/time.rs b/tests/run-pass/time.rs index e76c8573c516..cce29003e567 100644 --- a/tests/run-pass/time.rs +++ b/tests/run-pass/time.rs @@ -8,7 +8,7 @@ fn duration_sanity(diff: Duration) { assert!(diff.as_millis() < 500); } -// Thus far, only `libc::nanosleep`, is implemented, not `c::Sleep`. +// Sleeping on Windows is not supported yet. #[cfg(unix)] fn test_sleep() { let before = Instant::now(); From b06f0d16a9dc66654b4e41f4e57be26e6ef4e302 Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 7 Sep 2020 15:09:34 -0500 Subject: [PATCH 2270/5092] Use try block instead of closure --- src/helpers.rs | 8 ++++---- src/lib.rs | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 9e4bc21ab1b3..5bb620b563d3 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -530,17 +530,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let nanoseconds_scalar = this.read_scalar(nanoseconds_place.into())?; let nanoseconds = nanoseconds_scalar.to_machine_isize(this)?; - Ok((move || { + Ok(try { // tv_sec must be non-negative. let seconds: u64 = seconds.try_into().ok()?; // tv_nsec must be non-negative. let nanoseconds: u32 = nanoseconds.try_into().ok()?; if nanoseconds >= 1_000_000_000 { // tv_nsec must not be greater than 999,999,999. - return None; + None? } - Some(Duration::new(seconds, nanoseconds)) - })()) + Duration::new(seconds, nanoseconds) + }) } } diff --git a/src/lib.rs b/src/lib.rs index 1b66d5ff6f31..77eac9a6324a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ #![feature(map_first_last)] #![feature(never_type)] #![feature(or_patterns)] +#![feature(try_blocks)] #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] From 563fb8e43d4c236faeeb9b611294a82ecff93712 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Sat, 15 Aug 2020 14:15:31 +0530 Subject: [PATCH 2271/5092] Implement dup and close for stdin/stdout/stderr Support F_DUPFD on stdin/stdout/stderr Enable `close`-ing stdin/stdout/stderr For `dup`, check if FD is `File` first If not, clone the appropriate standard IO stream Merge POSIX `close` and `dup` tests into same module Also, add assertion that `write` on a closed FD returns an error. Add `dup` as FileDescriptor trait fn Also: - Fix `close` so it drops `self` instead of reference to it - Remove FD clamping in insert_fd_with_min_fd, since FDs 0-2 can be closed Fix fs_libc tests Make error message when closing stdin/out/err more specific Return io::Result from `FileDescriptor::dup` Change error message when closing stdin/out/err Refactor `FileDescriptor::dup` impl for `FileHandle` Remove empty line --- src/shims/posix/fs.rs | 115 ++++++++++++++++---------- tests/compile-fail/fs/close_stdout.rs | 14 ++++ tests/run-pass/fs_libc.rs | 20 +++++ tests/run-pass/fs_libc.stderr | 1 + tests/run-pass/fs_libc.stdout | 1 + 5 files changed, 109 insertions(+), 42 deletions(-) create mode 100644 tests/compile-fail/fs/close_stdout.rs create mode 100644 tests/run-pass/fs_libc.rs create mode 100644 tests/run-pass/fs_libc.stderr create mode 100644 tests/run-pass/fs_libc.stdout diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index b4719c25baee..c50b41b75ef9 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -28,6 +28,9 @@ trait FileDescriptor : std::fmt::Debug { fn read<'tcx>(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result>; fn write<'tcx>(&mut self, communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result>; fn seek<'tcx>(&mut self, communicate_allowed: bool, offset: SeekFrom) -> InterpResult<'tcx, io::Result>; + fn close<'tcx>(self: Box, _communicate_allowed: bool) -> InterpResult<'tcx, io::Result>; + + fn dup<'tcx>(&mut self) -> io::Result>; } impl FileDescriptor for FileHandle { @@ -49,6 +52,34 @@ impl FileDescriptor for FileHandle { assert!(communicate_allowed, "isolation should have prevented even opening a file"); Ok(self.file.seek(offset)) } + + fn close<'tcx>(self: Box, communicate_allowed: bool) -> InterpResult<'tcx, io::Result> { + assert!(communicate_allowed, "isolation should have prevented even opening a file"); + // We sync the file if it was opened in a mode different than read-only. + if self.writable { + // `File::sync_all` does the checks that are done when closing a file. We do this to + // to handle possible errors correctly. + let result = self.file.sync_all().map(|_| 0i32); + // Now we actually close the file. + drop(self); + // And return the result. + Ok(result) + } else { + // We drop the file, this closes it but ignores any errors + // produced when closing it. This is done because + // `File::sync_all` cannot be done over files like + // `/dev/urandom` which are read-only. Check + // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439 + // for a deeper discussion. + drop(self); + Ok(Ok(0)) + } + } + + fn dup<'tcx>(&mut self) -> io::Result> { + let duplicated = self.file.try_clone()?; + Ok(Box::new(FileHandle { file: duplicated, writable: self.writable })) + } } impl FileDescriptor for io::Stdin { @@ -71,6 +102,14 @@ impl FileDescriptor for io::Stdin { fn seek<'tcx>(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot seek on stdin"); } + + fn close<'tcx>(self: Box, _communicate_allowed: bool) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("stdin cannot be closed"); + } + + fn dup<'tcx>(&mut self) -> io::Result> { + Ok(Box::new(io::stdin())) + } } impl FileDescriptor for io::Stdout { @@ -98,6 +137,14 @@ impl FileDescriptor for io::Stdout { fn seek<'tcx>(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot seek on stdout"); } + + fn close<'tcx>(self: Box, _communicate_allowed: bool) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("stdout cannot be closed"); + } + + fn dup<'tcx>(&mut self) -> io::Result> { + Ok(Box::new(io::stdout())) + } } impl FileDescriptor for io::Stderr { @@ -118,6 +165,14 @@ impl FileDescriptor for io::Stderr { fn seek<'tcx>(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot seek on stderr"); } + + fn close<'tcx>(self: Box, _communicate_allowed: bool) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("stderr cannot be closed"); + } + + fn dup<'tcx>(&mut self) -> io::Result> { + Ok(Box::new(io::stderr())) + } } #[derive(Debug)] @@ -137,18 +192,12 @@ impl<'tcx> Default for FileHandler { } } - -// fd numbers 0, 1, and 2 are reserved for stdin, stdout, and stderr -const MIN_NORMAL_FILE_FD: i32 = 3; - impl<'tcx> FileHandler { - fn insert_fd(&mut self, file_handle: FileHandle) -> i32 { + fn insert_fd(&mut self, file_handle: Box) -> i32 { self.insert_fd_with_min_fd(file_handle, 0) } - fn insert_fd_with_min_fd(&mut self, file_handle: FileHandle, min_fd: i32) -> i32 { - let min_fd = std::cmp::max(min_fd, MIN_NORMAL_FILE_FD); - + fn insert_fd_with_min_fd(&mut self, file_handle: Box, min_fd: i32) -> i32 { // Find the lowest unused FD, starting from min_fd. If the first such unused FD is in // between used FDs, the find_map combinator will return it. If the first such unused FD // is after all other used FDs, the find_map combinator will return None, and we will use @@ -173,7 +222,7 @@ impl<'tcx> FileHandler { self.handles.last_key_value().map(|(fd, _)| fd.checked_add(1).unwrap()).unwrap_or(min_fd) }); - self.handles.insert(new_fd, Box::new(file_handle)).unwrap_none(); + self.handles.insert(new_fd, file_handle).unwrap_none(); new_fd } } @@ -449,7 +498,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = options.open(&path).map(|file| { let fh = &mut this.machine.file_handler; - fh.insert_fd(FileHandle { file, writable }) + fh.insert_fd(Box::new(FileHandle { file, writable })) }); this.try_unwrap_io_result(fd) @@ -489,22 +538,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // thus they can share the same implementation here. let &[_, _, start] = check_arg_count(args)?; let start = this.read_scalar(start)?.to_i32()?; - if fd < MIN_NORMAL_FILE_FD { - throw_unsup_format!("duplicating file descriptors for stdin, stdout, or stderr is not supported") - } + let fh = &mut this.machine.file_handler; - let (file_result, writable) = match fh.handles.get(&fd) { + + match fh.handles.get_mut(&fd) { Some(file_descriptor) => { - // FIXME: Support "dup" for all FDs(stdin, etc) - let FileHandle { file, writable } = file_descriptor.as_file_handle()?; - (file.try_clone(), *writable) + let dup_result = file_descriptor.dup(); + match dup_result { + Ok(dup_fd) => Ok(fh.insert_fd_with_min_fd(dup_fd, start)), + Err(e) => { + this.set_last_error_from_io_error(e)?; + Ok(-1) + } + } }, None => return this.handle_not_found(), - }; - let fd_result = file_result.map(|duplicated| { - fh.insert_fd_with_min_fd(FileHandle { file: duplicated, writable }, start) - }); - this.try_unwrap_io_result(fd_result) + } } else if this.tcx.sess.target.target.target_os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC")? { @@ -530,26 +579,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.remove(&fd) { - // FIXME: Support `close` for all FDs(stdin, etc) - let FileHandle { file, writable } = file_descriptor.as_file_handle()?; - // We sync the file if it was opened in a mode different than read-only. - if *writable { - // `File::sync_all` does the checks that are done when closing a file. We do this to - // to handle possible errors correctly. - let result = this.try_unwrap_io_result(file.sync_all().map(|_| 0i32)); - // Now we actually close the file. - drop(file); - // And return the result. - result - } else { - // We drop the file, this closes it but ignores any errors produced when closing - // it. This is done because `File::sync_all` cannot be done over files like - // `/dev/urandom` which are read-only. Check - // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439 for a deeper - // discussion. - drop(file); - Ok(0) - } + let result = file_descriptor.close(this.machine.communicate)?; + this.try_unwrap_io_result(result) } else { this.handle_not_found() } diff --git a/tests/compile-fail/fs/close_stdout.rs b/tests/compile-fail/fs/close_stdout.rs new file mode 100644 index 000000000000..4f10d5e0c990 --- /dev/null +++ b/tests/compile-fail/fs/close_stdout.rs @@ -0,0 +1,14 @@ +// ignore-windows: No libc on Windows +// compile-flags: -Zmiri-disable-isolation + +// FIXME: standard handles cannot be closed (https://github.com/rust-lang/rust/issues/40032) + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + unsafe { + libc::close(1); //~ ERROR stdout cannot be closed + } +} diff --git a/tests/run-pass/fs_libc.rs b/tests/run-pass/fs_libc.rs new file mode 100644 index 000000000000..e3deb7a5bcd8 --- /dev/null +++ b/tests/run-pass/fs_libc.rs @@ -0,0 +1,20 @@ +// ignore-windows +// compile-flags: -Zmiri-disable-isolation + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + dup_stdout_stderr_test(); +} + +fn dup_stdout_stderr_test() { + let bytes = b"hello dup fd\n"; + unsafe { + let new_stdout = libc::fcntl(1, libc::F_DUPFD, 0); + let new_stderr = libc::fcntl(2, libc::F_DUPFD, 0); + libc::write(new_stdout, bytes.as_ptr() as *const libc::c_void, bytes.len()); + libc::write(new_stderr, bytes.as_ptr() as *const libc::c_void, bytes.len()); + } +} diff --git a/tests/run-pass/fs_libc.stderr b/tests/run-pass/fs_libc.stderr new file mode 100644 index 000000000000..b6fa69e3d5d2 --- /dev/null +++ b/tests/run-pass/fs_libc.stderr @@ -0,0 +1 @@ +hello dup fd diff --git a/tests/run-pass/fs_libc.stdout b/tests/run-pass/fs_libc.stdout new file mode 100644 index 000000000000..b6fa69e3d5d2 --- /dev/null +++ b/tests/run-pass/fs_libc.stdout @@ -0,0 +1 @@ +hello dup fd From bea2d7bb55775a9eb81a32d72938eeaaf90f279f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 10 Sep 2020 08:38:30 +0200 Subject: [PATCH 2272/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index d2cf18f80f17..8e33b80ff68f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e114d6228b948ce056de0bcdec2603c8e89d3727 +a1894e4afe1a39f718cc27232a5a2f0d02b501f6 From e61be0b8b8c0409ea2c7afac50bfd6afc09cf811 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 10 Sep 2020 08:38:43 +0200 Subject: [PATCH 2273/5092] expand collection tests --- ...zed-binary-heap-push.rs => binary-heap.rs} | 21 ++++++++++++++- tests/run-pass/btreemap.rs | 27 +++++++++++++++---- tests/run-pass/hashmap.rs | 16 +++++++++++ tests/run-pass/linked-list.rs | 19 ++++++++++++- tests/run-pass/vec.rs | 16 +++++++++++ 5 files changed, 92 insertions(+), 7 deletions(-) rename tests/run-pass/{zero-sized-binary-heap-push.rs => binary-heap.rs} (58%) diff --git a/tests/run-pass/zero-sized-binary-heap-push.rs b/tests/run-pass/binary-heap.rs similarity index 58% rename from tests/run-pass/zero-sized-binary-heap-push.rs rename to tests/run-pass/binary-heap.rs index c9312d79bfda..8b8fa6458e65 100644 --- a/tests/run-pass/zero-sized-binary-heap-push.rs +++ b/tests/run-pass/binary-heap.rs @@ -1,7 +1,7 @@ use std::collections::BinaryHeap; use std::iter::Iterator; -fn main() { +fn zero_sized_push() { const N: usize = 8; for len in 0..N { @@ -16,3 +16,22 @@ fn main() { tester.clear(); } } + +fn drain() { + let mut heap = (0..128i32).collect::>(); + + assert!(!heap.is_empty()); + + let mut sum = 0; + for x in heap.drain() { + sum += x; + } + assert_eq!(sum, 127*128/2); + + assert!(heap.is_empty()); +} + +fn main() { + zero_sized_push(); + drain(); +} diff --git a/tests/run-pass/btreemap.rs b/tests/run-pass/btreemap.rs index e2049d948032..603674cc4503 100644 --- a/tests/run-pass/btreemap.rs +++ b/tests/run-pass/btreemap.rs @@ -7,6 +7,20 @@ pub enum Foo { _C, } +// Gather all references from a mutable iterator and make sure Miri notices if +// using them is dangerous. +fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { + // Gather all those references. + let mut refs: Vec<&mut T> = iter.collect(); + // Use them all. Twice, to be sure we got all interleavings. + for r in refs.iter_mut() { + std::mem::swap(dummy, r); + } + for r in refs { + std::mem::swap(dummy, r); + } +} + pub fn main() { let mut b = BTreeSet::new(); b.insert(Foo::A("\'")); @@ -19,11 +33,14 @@ pub fn main() { // Also test a lower-alignment type, where the NodeHeader overlaps with // the keys. let mut b = BTreeSet::new(); - b.insert(1024); - b.insert(7); + b.insert(1024u16); + b.insert(7u16); let mut b = BTreeMap::new(); - b.insert("bar", 1024); - b.insert("baz", 7); - for _val in b.iter_mut() {} + b.insert(format!("bar"), 1024); + b.insert(format!("baz"), 7); + for i in 0..60 { + b.insert(format!("key{}", i), i); + } + test_all_refs(&mut 13, b.values_mut()); } diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass/hashmap.rs index 488fe6afe65e..215f762efcc9 100644 --- a/tests/run-pass/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -1,6 +1,20 @@ use std::collections::HashMap; use std::hash::BuildHasher; +// Gather all references from a mutable iterator and make sure Miri notices if +// using them is dangerous. +fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { + // Gather all those references. + let mut refs: Vec<&mut T> = iter.collect(); + // Use them all. Twice, to be sure we got all interleavings. + for r in refs.iter_mut() { + std::mem::swap(dummy, r); + } + for r in refs { + std::mem::swap(dummy, r); + } +} + fn smoketest_map(mut map: HashMap) { map.insert(0, 0); assert_eq!(map.values().fold(0, |x, y| x+y), 0); @@ -16,6 +30,8 @@ fn smoketest_map(mut map: HashMap) { map.insert(i, num-1-i); } assert_eq!(map.values().fold(0, |x, y| x+y), num*(num-1)/2); + + test_all_refs(&mut 13, map.values_mut()); } fn main() { diff --git a/tests/run-pass/linked-list.rs b/tests/run-pass/linked-list.rs index 976a35da6061..0ed9d6032d0e 100644 --- a/tests/run-pass/linked-list.rs +++ b/tests/run-pass/linked-list.rs @@ -4,7 +4,21 @@ use std::collections::LinkedList; fn list_from(v: &[T]) -> LinkedList { v.iter().cloned().collect() } - + +// Gather all references from a mutable iterator and make sure Miri notices if +// using them is dangerous. +fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { + // Gather all those references. + let mut refs: Vec<&mut T> = iter.collect(); + // Use them all. Twice, to be sure we got all interleavings. + for r in refs.iter_mut() { + std::mem::swap(dummy, r); + } + for r in refs { + std::mem::swap(dummy, r); + } +} + fn main() { let mut m = list_from(&[0, 2, 4, 6, 8]); let len = m.len(); @@ -30,6 +44,9 @@ fn main() { } assert_eq!(m.len(), 3 + len * 2); + let mut m2 = m.clone(); assert_eq!(m.into_iter().collect::>(), [-10, -2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 99]); + + test_all_refs(&mut 13, m2.iter_mut()); } diff --git a/tests/run-pass/vec.rs b/tests/run-pass/vec.rs index 731358564b8a..5fea4a9147a0 100644 --- a/tests/run-pass/vec.rs +++ b/tests/run-pass/vec.rs @@ -1,3 +1,17 @@ +// Gather all references from a mutable iterator and make sure Miri notices if +// using them is dangerous. +fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { + // Gather all those references. + let mut refs: Vec<&mut T> = iter.collect(); + // Use them all. Twice, to be sure we got all interleavings. + for r in refs.iter_mut() { + std::mem::swap(dummy, r); + } + for r in refs { + std::mem::swap(dummy, r); + } +} + fn make_vec() -> Vec { let mut v = Vec::with_capacity(4); v.push(1); @@ -53,6 +67,8 @@ fn vec_iter_and_mut() { *i += 1; } assert_eq!(v.iter().sum::(), 2+3+4+5); + + test_all_refs(&mut 13, v.iter_mut()); } fn vec_iter_and_mut_rev() { From bc548d30041a3ac247d264d6b49904b25f232f7a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 11 Sep 2020 12:20:08 +0200 Subject: [PATCH 2274/5092] test BTreeMap::drain_filter for leaks --- tests/run-pass/btreemap.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/run-pass/btreemap.rs b/tests/run-pass/btreemap.rs index 603674cc4503..e639ba6225ca 100644 --- a/tests/run-pass/btreemap.rs +++ b/tests/run-pass/btreemap.rs @@ -1,4 +1,6 @@ +#![feature(btree_drain_filter)] use std::collections::{BTreeMap, BTreeSet}; +use std::mem; #[derive(PartialEq, Eq, PartialOrd, Ord)] pub enum Foo { @@ -43,4 +45,9 @@ pub fn main() { b.insert(format!("key{}", i), i); } test_all_refs(&mut 13, b.values_mut()); + + // Test forgetting the drain. + let mut d = b.drain_filter(|_, i| *i < 30); + d.next().unwrap(); + mem::forget(d); } From ebc3b718818c27a5061c2f2da31f9ef7e4d6851d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 13 Sep 2020 21:10:29 +0200 Subject: [PATCH 2275/5092] also detect Azure CI environments --- cargo-miri/bin.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 98304d247f98..12c5d1c32553 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -207,7 +207,10 @@ fn xargo_version() -> Option<(u32, u32, u32)> { fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { // Disable interactive prompts in CI (GitHub Actions, Travis, AppVeyor, etc). - if ask && env::var_os("CI").is_none() { + // Azure doesn't set `CI` though (nothing to see here, just Microsoft being Microsoft), + // so we also check their `TF_BUILD`. + let is_ci = env::var_os("CI").is_some() || env::var_os("TF_BUILD").is_some(); + if ask && !is_ci { let mut buf = String::new(); print!("I will run `{:?}` to {}. Proceed? [Y/n] ", cmd, text); io::stdout().flush().unwrap(); From 93c31e7790368ba062da93189c241d996a9ae172 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 17 Sep 2020 09:39:52 -0400 Subject: [PATCH 2276/5092] Enable some panic tests on Windows --- test-cargo-miri/tests/test.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 68d5426802b4..e38dc7a926c9 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -42,22 +42,15 @@ fn num_cpus() { assert_eq!(num_cpus::get(), 1); } - -// FIXME: Remove this `cfg` once we fix https://github.com/rust-lang/miri/issues/1059. -// We cfg-gate the `should_panic` attribute and the `panic!` itself, so that the test -// stdout does not depend on the target. #[test] -#[cfg_attr(not(windows), should_panic(expected="Explicit panic"))] +#[should_panic(expected="Explicit panic")] fn do_panic() { // In large, friendly letters :) - #[cfg(not(windows))] panic!("Explicit panic from test!"); } -// FIXME: see above #[test] #[allow(unconditional_panic)] -#[cfg_attr(not(windows), should_panic(expected="the len is 0 but the index is 42"))] +#[should_panic(expected="the len is 0 but the index is 42")] fn fail_index_check() { - #[cfg(not(windows))] [][42] } From 2b3b83eb2c01d82cd1fce9285e50bae1c2cb9b54 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 6 Sep 2020 19:28:29 +0200 Subject: [PATCH 2277/5092] canonicalize miri's directory --- miri | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/miri b/miri index 37e87ec79861..f53c21ff115c 100755 --- a/miri +++ b/miri @@ -39,6 +39,7 @@ EOF TARGET=$(rustc --version --verbose | grep "^host:" | cut -d ' ' -f 2) SYSROOT=$(rustc --print sysroot) LIBDIR=$SYSROOT/lib/rustlib/$TARGET/lib +MIRIDIR=$(readlink -e "$(dirname "$0")") if ! test -d "$LIBDIR"; then echo "Something went wrong determining the library dir." echo "I got $LIBDIR but that does not exist." @@ -51,7 +52,7 @@ if [ -z "$CARGO_INCREMENTAL" ]; then fi if [ -z "$CARGO_TARGET_DIR" ]; then # Share target dir between `miri` and `cargo-miri`. - export CARGO_TARGET_DIR="$(dirname "$0")"/target + export CARGO_TARGET_DIR="$MIRIDIR/target" fi # We set the rpath so that Miri finds the private rustc libraries it needs. # We enable debug-assertions to get tracing. @@ -63,9 +64,9 @@ export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR -C debug-assertions -C debugin # Build a sysroot and set MIRI_SYSROOT to use it. Arguments are passed to `cargo miri setup`. build_sysroot() { # Build once, for the user to see. - cargo run $CARGO_BUILD_FLAGS --manifest-path "$(dirname "$0")"/cargo-miri/Cargo.toml -- miri setup "$@" + cargo run $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -- miri setup "$@" # Call again, to just set env var. - export MIRI_SYSROOT="$(cargo run $CARGO_BUILD_FLAGS --manifest-path "$(dirname "$0")"/cargo-miri/Cargo.toml -q -- miri setup --print-sysroot "$@")" + export MIRI_SYSROOT="$(cargo run $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -q -- miri setup --print-sysroot "$@")" } # Prepare and set MIRI_SYSROOT. Respects `MIRI_TEST_TARGET` and takes into account @@ -108,18 +109,18 @@ case "$COMMAND" in install|install-debug) # "--locked" to respect the Cargo.lock file if it exists, # "--offline" to avoid querying the registry (for yanked packages). - cargo install $CARGO_INSTALL_FLAGS --path "$(dirname "$0")" --force --locked --offline "$@" - cargo install $CARGO_INSTALL_FLAGS --path "$(dirname "$0")"/cargo-miri --force --locked --offline "$@" + cargo install $CARGO_INSTALL_FLAGS --path "$MIRIDIR" --force --locked --offline "$@" + cargo install $CARGO_INSTALL_FLAGS --path "$MIRIDIR"/cargo-miri --force --locked --offline "$@" ;; check|check-debug) # Check, and let caller control flags. - cargo check $CARGO_BUILD_FLAGS --manifest-path "$(dirname "$0")"/Cargo.toml "$@" - cargo check $CARGO_BUILD_FLAGS --manifest-path "$(dirname "$0")"/cargo-miri/Cargo.toml "$@" + cargo check $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" + cargo check $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" ;; build|build-debug) # Build, and let caller control flags. - cargo build $CARGO_BUILD_FLAGS --manifest-path "$(dirname "$0")"/Cargo.toml "$@" - cargo build $CARGO_BUILD_FLAGS --manifest-path "$(dirname "$0")"/cargo-miri/Cargo.toml "$@" + cargo build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" + cargo build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" ;; test|test-debug) # First build and get a sysroot. From 16afe1a2343de58c29480ab0d90490b58eee00d8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 6 Sep 2020 19:28:58 +0200 Subject: [PATCH 2278/5092] towards letting cargo do binary selection: wrappers and runners set up --- cargo-miri/Cargo.lock | 24 +-- cargo-miri/Cargo.toml | 1 - cargo-miri/bin.rs | 334 +++++++++++++----------------------------- 3 files changed, 104 insertions(+), 255 deletions(-) diff --git a/cargo-miri/Cargo.lock b/cargo-miri/Cargo.lock index 0052bfa183d0..bb3b05db03a4 100644 --- a/cargo-miri/Cargo.lock +++ b/cargo-miri/Cargo.lock @@ -45,7 +45,6 @@ dependencies = [ name = "cargo-miri" version = "0.1.0" dependencies = [ - "cargo_metadata", "directories", "rustc-workspace-hack", "rustc_version", @@ -54,17 +53,6 @@ dependencies = [ "vergen", ] -[[package]] -name = "cargo_metadata" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89fec17b16f1ac67908af82e47d0a90a7afd0e1827b181cd77504323d3263d35" -dependencies = [ - "semver 0.10.0", - "serde", - "serde_json", -] - [[package]] name = "cfg-if" version = "0.1.10" @@ -228,7 +216,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" dependencies = [ - "semver 0.9.0", + "semver", ] [[package]] @@ -246,16 +234,6 @@ dependencies = [ "semver-parser", ] -[[package]] -name = "semver" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "394cec28fa623e00903caf7ba4fa6fb9a0e260280bb8cdbbba029611108a0190" -dependencies = [ - "semver-parser", - "serde", -] - [[package]] name = "semver-parser" version = "0.7.0" diff --git a/cargo-miri/Cargo.toml b/cargo-miri/Cargo.toml index 91c478369484..2de581c1c2e2 100644 --- a/cargo-miri/Cargo.toml +++ b/cargo-miri/Cargo.toml @@ -14,7 +14,6 @@ test = false # we have no unit tests doctest = false # and no doc tests [dependencies] -cargo_metadata = "0.11" directories = "2.0" rustc_version = "0.2.3" serde_json = "1.0.40" diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 12c5d1c32553..f3a2a511517f 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -116,50 +116,6 @@ fn xargo_check() -> Command { Command::new(env::var_os("XARGO_CHECK").unwrap_or_else(|| OsString::from("xargo-check"))) } -fn list_targets() -> impl Iterator { - // We need to get the manifest, and then the metadata, to enumerate targets. - let manifest_path = - get_arg_flag_value("--manifest-path").map(|m| Path::new(&m).canonicalize().unwrap()); - - let mut cmd = cargo_metadata::MetadataCommand::new(); - if let Some(manifest_path) = &manifest_path { - cmd.manifest_path(manifest_path); - } - let mut metadata = if let Ok(metadata) = cmd.exec() { - metadata - } else { - show_error(format!("Could not obtain Cargo metadata; likely an ill-formed manifest")); - }; - - let current_dir = std::env::current_dir(); - - let package_index = metadata - .packages - .iter() - .position(|package| { - let package_manifest_path = Path::new(&package.manifest_path); - if let Some(manifest_path) = &manifest_path { - package_manifest_path == manifest_path - } else { - let current_dir = current_dir.as_ref().expect("could not read current directory"); - let package_manifest_directory = package_manifest_path - .parent() - .expect("could not find parent directory of package manifest"); - package_manifest_directory == current_dir - } - }) - .unwrap_or_else(|| { - show_error(format!( - "this seems to be a workspace, which is not supported by `cargo miri`.\n\ - Try to `cd` into the crate you want to test, and re-run `cargo miri` there." - )) - }); - let package = metadata.packages.remove(package_index); - - // Finally we got the list of targets to build - package.targets.into_iter() -} - fn xargo_version() -> Option<(u32, u32, u32)> { let out = xargo_check().arg("--version").output().ok()?; if !out.status.success() { @@ -381,173 +337,77 @@ path = "lib.rs" } } -enum CargoTargets { - All, - Filtered { lib: bool, bin: Vec, test: Vec }, -} - -impl CargoTargets { - fn matches(&self, kind: &str, name: &str) -> bool { - match self { - CargoTargets::All => true, - CargoTargets::Filtered { lib, bin, test } => match kind { - "lib" => *lib, - "bin" => bin.iter().any(|n| n == name), - "test" => test.iter().any(|n| n == name), - _ => false, - }, - } - } -} - -fn parse_cargo_miri_args( - mut args: impl Iterator, -) -> (CargoTargets, Vec, Vec) { - let mut lib_present = false; - let mut bin_targets = Vec::new(); - let mut test_targets = Vec::new(); - let mut additional_args = Vec::new(); - while let Some(arg) = args.next() { - match arg { - arg if arg == "--" => { - // Miri arguments begin after the first "--". - break; - } - arg if arg == "--lib" => lib_present = true, - arg if arg == "--bin" => { - if let Some(binary) = args.next() { - if binary == "--" { - show_error(format!("\"--bin\" takes one argument.")); - } else { - bin_targets.push(binary) - } - } else { - show_error(format!("\"--bin\" takes one argument.")); - } - } - arg if arg.starts_with("--bin=") => bin_targets.push((&arg["--bin=".len()..]).to_string()), - arg if arg == "--test" => { - if let Some(test) = args.next() { - if test == "--" { - show_error(format!("\"--test\" takes one argument.")); - } else { - test_targets.push(test) - } - } else { - show_error(format!("\"--test\" takes one argument.")); - } - } - arg if arg.starts_with("--test=") => test_targets.push((&arg["--test=".len()..]).to_string()), - other => additional_args.push(other), - } - } - let targets = if !lib_present && bin_targets.len() == 0 && test_targets.len() == 0 { - CargoTargets::All - } else { - CargoTargets::Filtered { lib: lib_present, bin: bin_targets, test: test_targets } - }; - (targets, additional_args, args.collect()) -} - -fn in_cargo_miri() { - let (subcommand, skip) = match std::env::args().nth(2).as_deref() { - Some("test") => (MiriCommand::Test, 3), - Some("run") => (MiriCommand::Run, 3), - Some("setup") => (MiriCommand::Setup, 3), - // Default command, if there is an option or nothing. - Some(s) if s.starts_with("-") => (MiriCommand::Run, 2), - None => (MiriCommand::Run, 2), +fn phase_cargo_miri(mut args: env::Args) { + // Require a subcommand before any flags. + // We cannot know which of those flags take arguments and which do not, + // so we cannot detect subcommands later. + let subcommand = match args.next().as_deref() { + Some("test") => MiriCommand::Test, + Some("run") => MiriCommand::Run, + Some("setup") => MiriCommand::Setup, // Invalid command. - Some(s) => show_error(format!("Unknown command `{}`", s)), + None => show_error(format!("`cargo miri` must be immediately followed by `test`, `run`, or `setup`.")), + Some(s) => show_error(format!("unknown command `{}`", s)), }; let verbose = has_arg_flag("-v"); // We always setup. setup(subcommand); - if subcommand == MiriCommand::Setup { - // Stop here. - return; + + // Invoke actual cargo for the job, but with different flags. + let miri_path = std::env::current_exe().expect("current executable path invalid"); + let cargo_cmd = match subcommand { + MiriCommand::Test => "test", + MiriCommand::Run => "run", + MiriCommand::Setup => return, // `cargo miri setup` stops here. + }; + let mut cmd = cargo(); + cmd.arg(cargo_cmd); + + // Make sure we know the build target, and cargo does, too. + // This is needed to make the `CARGO_TARGET_*_RUNNER` env var do something, + // and it later helps us detect which crates are proc-macro/build-script + // (host crates) and which crates are needed for the program itself. + let target = if let Some(target) = get_arg_flag_value("--target") { + target + } else { + // No target given. Pick default and tell cargo about it. + let host = version_info().host; + cmd.arg("--target"); + cmd.arg(&host); + host + }; + + // Forward all further arguments. + cmd.args(args); + + // Set `RUSTC_WRAPPER` to ourselves. Cargo will prepend that binary to its usual invocation, + // i.e., the first argument is `rustc` -- which is what we use in `main` to distinguish + // the two codepaths. (That extra argument is why we prefer this over setting `RUSTC`.) + if env::var_os("RUSTC_WRAPPER").is_some() { + println!("WARNING: Ignoring `RUSTC_WRAPPER` environment variable, Miri does not support wrapping."); + } + cmd.env("RUSTC_WRAPPER", &miri_path); + if verbose { + eprintln!("+ RUSTC_WRAPPER={:?}", miri_path); } - // FIXME: this accepts --test, --lib, and multiple --bin for `cargo miri run`. - let (target_filters, cargo_args, miri_args) = - parse_cargo_miri_args(std::env::args().skip(skip)); + // Set the runner for the current target to us as well, so we can interpret the binaries. + let runner_env_name = format!("CARGO_TARGET_{}_RUNNER", target.to_uppercase().replace('-', "_")); + cmd.env(runner_env_name, &miri_path); - // Now run the command. - for target in list_targets() { - let kind = target - .kind - .get(0) - .expect("badly formatted cargo metadata: target::kind is an empty array"); - if !target_filters.matches(kind, &target.name) { - continue; - } - // Now we run `cargo check $FLAGS $ARGS`, giving the user the - // change to add additional arguments. `FLAGS` is set to identify - // this target. The user gets to control what gets actually passed to Miri. - let mut cmd = cargo(); - cmd.arg("check"); - match (subcommand, kind.as_str()) { - (MiriCommand::Run, "bin") => { - // FIXME: we default to running all binaries here. - cmd.arg("--bin").arg(target.name); - } - (MiriCommand::Test, "test") => { - cmd.arg("--test").arg(target.name); - } - (MiriCommand::Test, "lib") => { - // There can be only one lib. - cmd.arg("--lib").arg("--profile").arg("test"); - } - (MiriCommand::Test, "bin") => { - cmd.arg("--bin").arg(target.name).arg("--profile").arg("test"); - } - // The remaining targets we do not even want to build. - _ => continue, - } - // Forward further `cargo` args. - for arg in cargo_args.iter() { - cmd.arg(arg); - } - // We want to always run `cargo` with `--target`. This later helps us detect - // which crates are proc-macro/build-script (host crates) and which crates are - // needed for the program itself. - if get_arg_flag_value("--target").is_none() { - // When no `--target` is given, default to the host. - cmd.arg("--target"); - cmd.arg(version_info().host); - } - - // Serialize the remaining args into a special environemt variable. - // This will be read by `inside_cargo_rustc` when we go to invoke - // our actual target crate (the binary or the test we are running). - // Since we're using "cargo check", we have no other way of passing - // these arguments. - cmd.env("MIRI_ARGS", serde_json::to_string(&miri_args).expect("failed to serialize args")); - - // Set `RUSTC_WRAPPER` to ourselves. Cargo will prepend that binary to its usual invocation, - // i.e., the first argument is `rustc` -- which is what we use in `main` to distinguish - // the two codepaths. (That extra argument is why we prefer this over setting `RUSTC`.) - if env::var_os("RUSTC_WRAPPER").is_some() { - println!("WARNING: Ignoring existing `RUSTC_WRAPPER` environment variable, Miri does not support wrapping."); - } - let path = std::env::current_exe().expect("current executable path invalid"); - cmd.env("RUSTC_WRAPPER", path); - if verbose { - cmd.env("MIRI_VERBOSE", ""); // this makes `inside_cargo_rustc` verbose. - eprintln!("+ {:?}", cmd); - } - - let exit_status = - cmd.spawn().expect("could not run cargo").wait().expect("failed to wait for cargo?"); - - if !exit_status.success() { - std::process::exit(exit_status.code().unwrap_or(-1)) - } + // Run cargo. + if verbose { + cmd.env("MIRI_VERBOSE", ""); // this makes `inside_cargo_rustc` verbose. + eprintln!("+ {:?}", cmd); } + let exit_status = + cmd.spawn().expect("could not run cargo").wait().expect("failed to wait for cargo?"); + + std::process::exit(exit_status.code().unwrap_or(-1)) } -fn inside_cargo_rustc() { +fn phase_cargo_rustc(mut args: env::Args) { /// Determines if we are being invoked (as rustc) to build a crate for /// the "target" architecture, in contrast to the "host" architecture. /// Host crates are for build scripts and proc macros and still need to @@ -569,15 +429,35 @@ fn inside_cargo_rustc() { fn is_runnable_crate() -> bool { let is_bin = get_arg_flag_value("--crate-type").as_deref() == Some("bin"); let is_test = has_arg_flag("--test"); - is_bin || is_test + let print = get_arg_flag_value("--print").is_some(); + (is_bin || is_test) && !print } let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); let target_crate = is_target_crate(); + if target_crate && is_runnable_crate() { + // This is the binary or test crate that we want to interpret under Miri. + // But we cannot run it here, as cargo invoked us as a compiler -- our stdin and stdout are not + // like we want them. + // Instead of compiling, we write JSON into the output file with all the relevant command-line flags + // and environment variables; this is sued alter when cargo calls us again in the CARGO_TARGET_RUNNER phase. + let filename = format!( + "{}/{}{}", + get_arg_flag_value("--out-dir").unwrap(), + get_arg_flag_value("--crate-name").unwrap(), + // This is technically a `-C` flag but the prefix seems unique enough... + // (and cargo passes this before the filename so it should be unique) + get_arg_flag_value("extra-filename").unwrap_or(String::new()), + ); + eprintln!("Miri is supposed to run {}", filename); + return; + } + let mut cmd = miri(); // Forward arguments. - cmd.args(std::env::args().skip(2)); // skip `cargo-miri rustc` + cmd.args(args); + // FIXME: Make the build check-only! // We make sure to only specify our custom Xargo sysroot for target crates - that is, // crates which are needed for interpretation by Miri. proc-macros and build scripts @@ -589,23 +469,9 @@ fn inside_cargo_rustc() { cmd.arg(sysroot); } - // If this is a runnable target crate, we want Miri to start interpretation; - // otherwise we want Miri to behave like rustc and build the crate as usual. - if target_crate && is_runnable_crate() { - // This is the binary or test crate that we want to interpret under Miri. - // (Testing `target_crate` is needed to exclude build scripts.) - // We deserialize the arguments that are meant for Miri from the special environment - // variable "MIRI_ARGS", and feed them to the 'miri' binary. - // - // `env::var` is okay here, well-formed JSON is always UTF-8. - let magic = std::env::var("MIRI_ARGS").expect("missing MIRI_ARGS"); - let miri_args: Vec = - serde_json::from_str(&magic).expect("failed to deserialize MIRI_ARGS"); - cmd.args(miri_args); - } else { - // We want to compile, not interpret. - cmd.env("MIRI_BE_RUSTC", "1"); - }; + // We want to compile, not interpret. We still use Miri to make sure the compiler version etc + // are the exact same as what is used for interpretation. + cmd.env("MIRI_BE_RUSTC", "1"); // Run it. if verbose { @@ -620,6 +486,10 @@ fn inside_cargo_rustc() { } } +fn phase_cargo_runner(binary: &str, args: env::Args) { + eprintln!("Asked to execute {}, args: {:?}", binary, args.collect::>()); +} + fn main() { // Check for version and help flags even when invoked as `cargo-miri`. if has_arg_flag("--help") || has_arg_flag("-h") { @@ -631,18 +501,20 @@ fn main() { return; } - if let Some("miri") = std::env::args().nth(1).as_deref() { - // This arm is for when `cargo miri` is called. We call `cargo check` for each applicable target, - // but with the `RUSTC` env var set to the `cargo-miri` binary so that we come back in the other branch, - // and dispatch the invocations to `rustc` and `miri`, respectively. - in_cargo_miri(); - } else if let Some("rustc") = std::env::args().nth(1).as_deref() { - // This arm is executed when `cargo-miri` runs `cargo check` with the `RUSTC_WRAPPER` env var set to itself: - // dependencies get dispatched to `rustc`, the final test/binary to `miri`. - inside_cargo_rustc(); - } else { - show_error(format!( - "`cargo-miri` must be called with either `miri` or `rustc` as first argument." - )) + let mut args = std::env::args(); + // Skip binary name. + args.next().unwrap(); + + // Dispatch to `cargo-miri` phase. There are three phases: + // - When we are called via `cargo miri`, we run as the frontend and invoke the underlying + // cargo. We set RUSTC_WRAPPER and CARGO_TARGET_RUNNER to ourselves. + // - When we are executed due to RUSTC_WRAPPER, we build crates or store the flags of + // binary crates for later interpretation. + // - When we are executed due to CARGO_TARGET_RUNNER, we start interpretation based on the + // flags that were stored earlier. + match &*args.next().unwrap() { + "miri" => phase_cargo_miri(args), + "rustc" => phase_cargo_rustc(args), + binary => phase_cargo_runner(binary, args), } } From e2119dc94dee5afe4a0ccd30530f9d4b824a3504 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Sep 2020 20:19:45 +0200 Subject: [PATCH 2279/5092] stub JSON information flow from cargo-build-time to run-time --- cargo-miri/bin.rs | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index f3a2a511517f..fee485ec9044 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -1,10 +1,13 @@ use std::env; use std::ffi::OsString; use std::fs::{self, File}; -use std::io::{self, BufRead, Write}; +use std::io::{self, BufRead, BufReader, BufWriter, Write}; use std::ops::Not; use std::path::{Path, PathBuf}; use std::process::Command; +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; use rustc_version::VersionMeta; @@ -41,6 +44,15 @@ enum MiriCommand { Setup, } +/// The inforamtion Miri needs to run a crate. Stored as JSON when the crate is "compiled". +#[derive(Serialize, Deserialize)] +struct CrateRunInfo { + /// The command-line arguments. + args: Vec, + /// The environment. + env: HashMap, +} + fn show_help() { println!("{}", CARGO_MIRI_HELP); } @@ -442,15 +454,24 @@ fn phase_cargo_rustc(mut args: env::Args) { // like we want them. // Instead of compiling, we write JSON into the output file with all the relevant command-line flags // and environment variables; this is sued alter when cargo calls us again in the CARGO_TARGET_RUNNER phase. - let filename = format!( - "{}/{}{}", - get_arg_flag_value("--out-dir").unwrap(), + let info = CrateRunInfo { args: Vec::new(), env: HashMap::new() }; + + let mut path = PathBuf::from(get_arg_flag_value("--out-dir").unwrap()); + path.push(format!( + "{}{}", get_arg_flag_value("--crate-name").unwrap(), // This is technically a `-C` flag but the prefix seems unique enough... // (and cargo passes this before the filename so it should be unique) get_arg_flag_value("extra-filename").unwrap_or(String::new()), - ); - eprintln!("Miri is supposed to run {}", filename); + )); + eprintln!("Miri is supposed to run {}", path.display()); + + let file = File::create(&path) + .unwrap_or_else(|_| show_error(format!("Cannot create {}", path.display()))); + let file = BufWriter::new(file); + serde_json::ser::to_writer(file, &info) + .unwrap_or_else(|_| show_error(format!("Cannot write to {}", path.display()))); + return; } @@ -488,6 +509,13 @@ fn phase_cargo_rustc(mut args: env::Args) { fn phase_cargo_runner(binary: &str, args: env::Args) { eprintln!("Asked to execute {}, args: {:?}", binary, args.collect::>()); + + let file = File::open(binary) + .unwrap_or_else(|_| show_error(format!("File {:?} not found, or cargo-miri invoked incorrectly", binary))); + let file = BufReader::new(file); + let info: CrateRunInfo = serde_json::from_reader(file) + .unwrap_or_else(|_| show_error(format!("File {:?} does not contain valid JSON", binary))); + // FIXME: remove the file. } fn main() { From 7ee2729824f1922d361c54a8d43e04190b513fc5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Sep 2020 21:12:51 +0200 Subject: [PATCH 2280/5092] it actually runs tests now! --- cargo-miri/bin.rs | 70 ++++++++++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index fee485ec9044..57c0ec985ab8 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -5,7 +5,6 @@ use std::io::{self, BufRead, BufReader, BufWriter, Write}; use std::ops::Not; use std::path::{Path, PathBuf}; use std::process::Command; -use std::collections::HashMap; use serde::{Deserialize, Serialize}; @@ -50,7 +49,16 @@ struct CrateRunInfo { /// The command-line arguments. args: Vec, /// The environment. - env: HashMap, + env: Vec<(OsString, OsString)>, +} + +impl CrateRunInfo { + /// Gather all the information we need. + fn collect(args: env::ArgsOs) -> Self { + let args = args.collect(); + let env = env::vars_os().collect(); + CrateRunInfo { args, env } + } } fn show_help() { @@ -128,6 +136,11 @@ fn xargo_check() -> Command { Command::new(env::var_os("XARGO_CHECK").unwrap_or_else(|| OsString::from("xargo-check"))) } +fn exec(mut cmd: Command) -> ! { + let exit_status = cmd.status().expect("failed to run command"); + std::process::exit(exit_status.code().unwrap_or(-1)) +} + fn xargo_version() -> Option<(u32, u32, u32)> { let out = xargo_check().arg("--version").output().ok()?; if !out.status.success() { @@ -349,17 +362,16 @@ path = "lib.rs" } } -fn phase_cargo_miri(mut args: env::Args) { +fn phase_cargo_miri(mut args: env::ArgsOs) { // Require a subcommand before any flags. // We cannot know which of those flags take arguments and which do not, // so we cannot detect subcommands later. - let subcommand = match args.next().as_deref() { + let subcommand = match args.next().as_deref().and_then(|s| s.to_str()) { Some("test") => MiriCommand::Test, Some("run") => MiriCommand::Run, Some("setup") => MiriCommand::Setup, // Invalid command. - None => show_error(format!("`cargo miri` must be immediately followed by `test`, `run`, or `setup`.")), - Some(s) => show_error(format!("unknown command `{}`", s)), + _ => show_error(format!("`cargo miri` must be immediately followed by `test`, `run`, or `setup`.")), }; let verbose = has_arg_flag("-v"); @@ -413,13 +425,10 @@ fn phase_cargo_miri(mut args: env::Args) { cmd.env("MIRI_VERBOSE", ""); // this makes `inside_cargo_rustc` verbose. eprintln!("+ {:?}", cmd); } - let exit_status = - cmd.spawn().expect("could not run cargo").wait().expect("failed to wait for cargo?"); - - std::process::exit(exit_status.code().unwrap_or(-1)) + exec(cmd) } -fn phase_cargo_rustc(mut args: env::Args) { +fn phase_cargo_rustc(args: env::ArgsOs) { /// Determines if we are being invoked (as rustc) to build a crate for /// the "target" architecture, in contrast to the "host" architecture. /// Host crates are for build scripts and proc macros and still need to @@ -454,7 +463,7 @@ fn phase_cargo_rustc(mut args: env::Args) { // like we want them. // Instead of compiling, we write JSON into the output file with all the relevant command-line flags // and environment variables; this is sued alter when cargo calls us again in the CARGO_TARGET_RUNNER phase. - let info = CrateRunInfo { args: Vec::new(), env: HashMap::new() }; + let info = CrateRunInfo::collect(args); let mut path = PathBuf::from(get_arg_flag_value("--out-dir").unwrap()); path.push(format!( @@ -464,14 +473,12 @@ fn phase_cargo_rustc(mut args: env::Args) { // (and cargo passes this before the filename so it should be unique) get_arg_flag_value("extra-filename").unwrap_or(String::new()), )); - eprintln!("Miri is supposed to run {}", path.display()); let file = File::create(&path) .unwrap_or_else(|_| show_error(format!("Cannot create {}", path.display()))); let file = BufWriter::new(file); serde_json::ser::to_writer(file, &info) .unwrap_or_else(|_| show_error(format!("Cannot write to {}", path.display()))); - return; } @@ -498,17 +505,11 @@ fn phase_cargo_rustc(mut args: env::Args) { if verbose { eprintln!("+ {:?}", cmd); } - match cmd.status() { - Ok(exit) => - if !exit.success() { - std::process::exit(exit.code().unwrap_or(42)); - }, - Err(e) => panic!("error running {:?}:\n{:?}", cmd, e), - } + exec(cmd) } -fn phase_cargo_runner(binary: &str, args: env::Args) { - eprintln!("Asked to execute {}, args: {:?}", binary, args.collect::>()); +fn phase_cargo_runner(binary: &str, args: env::ArgsOs) { + let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); let file = File::open(binary) .unwrap_or_else(|_| show_error(format!("File {:?} not found, or cargo-miri invoked incorrectly", binary))); @@ -516,6 +517,24 @@ fn phase_cargo_runner(binary: &str, args: env::Args) { let info: CrateRunInfo = serde_json::from_reader(file) .unwrap_or_else(|_| show_error(format!("File {:?} does not contain valid JSON", binary))); // FIXME: remove the file. + + let mut cmd = miri(); + // Forward rustc arguments,with our sysroot. + cmd.args(info.args); + let sysroot = + env::var_os("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); + cmd.arg("--sysroot"); + cmd.arg(sysroot); + + // Then pass binary arguments. + cmd.arg("--"); + cmd.args(args); + + // Run it. + if verbose { + eprintln!("+ {:?}", cmd); + } + exec(cmd) } fn main() { @@ -529,7 +548,7 @@ fn main() { return; } - let mut args = std::env::args(); + let mut args = std::env::args_os(); // Skip binary name. args.next().unwrap(); @@ -540,7 +559,8 @@ fn main() { // binary crates for later interpretation. // - When we are executed due to CARGO_TARGET_RUNNER, we start interpretation based on the // flags that were stored earlier. - match &*args.next().unwrap() { + // FIXME: report errors for these unwraps. + match &*args.next().unwrap().to_str().unwrap() { "miri" => phase_cargo_miri(args), "rustc" => phase_cargo_rustc(args), binary => phase_cargo_runner(binary, args), From c41a039c56de183468fc5b428e61e2522991fd35 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Sep 2020 08:58:29 +0200 Subject: [PATCH 2281/5092] patch --extern and --emit; test suite passes now! --- cargo-miri/bin.rs | 98 ++++++++++++++++++++++++--------- test-cargo-miri/run-test.py | 25 +++++---- test-cargo-miri/test.stdout.ref | 12 +--- 3 files changed, 90 insertions(+), 45 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 57c0ec985ab8..bf27195d5392 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -47,14 +47,14 @@ enum MiriCommand { #[derive(Serialize, Deserialize)] struct CrateRunInfo { /// The command-line arguments. - args: Vec, + args: Vec, /// The environment. env: Vec<(OsString, OsString)>, } impl CrateRunInfo { /// Gather all the information we need. - fn collect(args: env::ArgsOs) -> Self { + fn collect(args: env::Args) -> Self { let args = args.collect(); let env = env::vars_os().collect(); CrateRunInfo { args, env } @@ -362,11 +362,11 @@ path = "lib.rs" } } -fn phase_cargo_miri(mut args: env::ArgsOs) { +fn phase_cargo_miri(mut args: env::Args) { // Require a subcommand before any flags. // We cannot know which of those flags take arguments and which do not, // so we cannot detect subcommands later. - let subcommand = match args.next().as_deref().and_then(|s| s.to_str()) { + let subcommand = match args.next().as_deref() { Some("test") => MiriCommand::Test, Some("run") => MiriCommand::Run, Some("setup") => MiriCommand::Setup, @@ -423,12 +423,12 @@ fn phase_cargo_miri(mut args: env::ArgsOs) { // Run cargo. if verbose { cmd.env("MIRI_VERBOSE", ""); // this makes `inside_cargo_rustc` verbose. - eprintln!("+ {:?}", cmd); + eprintln!("[cargo-miri miri] {:?}", cmd); } exec(cmd) } -fn phase_cargo_rustc(args: env::ArgsOs) { +fn phase_cargo_rustc(args: env::Args) { /// Determines if we are being invoked (as rustc) to build a crate for /// the "target" architecture, in contrast to the "host" architecture. /// Host crates are for build scripts and proc macros and still need to @@ -473,19 +473,41 @@ fn phase_cargo_rustc(args: env::ArgsOs) { // (and cargo passes this before the filename so it should be unique) get_arg_flag_value("extra-filename").unwrap_or(String::new()), )); + if verbose { + eprintln!("[cargo-miri rustc] writing run info to {:?}", path.display()); + } let file = File::create(&path) - .unwrap_or_else(|_| show_error(format!("Cannot create {}", path.display()))); + .unwrap_or_else(|_| show_error(format!("Cannot create {:?}", path.display()))); let file = BufWriter::new(file); serde_json::ser::to_writer(file, &info) - .unwrap_or_else(|_| show_error(format!("Cannot write to {}", path.display()))); + .unwrap_or_else(|_| show_error(format!("Cannot write to {:?}", path.display()))); return; } let mut cmd = miri(); - // Forward arguments. - cmd.args(args); - // FIXME: Make the build check-only! + // Forward arguments, but (only for target crates!) remove "link" from "--emit" to make this a check-only build. + let emit_flag = "--emit"; + for arg in args { + if target_crate && arg.starts_with(emit_flag) { + // Patch this argument. First, extract its value. + let val = &arg[emit_flag.len()..]; + assert!(val.starts_with("="), "`cargo` should pass `--emit=X` as one argument"); + let val = &val[1..]; + let mut val: Vec<_> = val.split(',').collect(); + // Now make sure "link" is not in there, but "metadata" is. + if let Some(i) = val.iter().position(|&s| s == "link") { + val.remove(i); + if !val.iter().any(|&s| s == "metadata") { + val.push("metadata"); + } + } + cmd.arg(format!("{}={}", emit_flag, val.join(","))); + // FIXME: due to this, the `.rlib` file does not get created and cargo re-triggers the build each time. + } else { + cmd.arg(arg); + } + } // We make sure to only specify our custom Xargo sysroot for target crates - that is, // crates which are needed for interpretation by Miri. proc-macros and build scripts @@ -503,36 +525,60 @@ fn phase_cargo_rustc(args: env::ArgsOs) { // Run it. if verbose { - eprintln!("+ {:?}", cmd); + eprintln!("[cargo-miri rustc] {:?}", cmd); } exec(cmd) } -fn phase_cargo_runner(binary: &str, args: env::ArgsOs) { +fn phase_cargo_runner(binary: &str, binary_args: env::Args) { let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); let file = File::open(binary) - .unwrap_or_else(|_| show_error(format!("File {:?} not found, or cargo-miri invoked incorrectly", binary))); + .unwrap_or_else(|_| show_error(format!("File {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary))); let file = BufReader::new(file); let info: CrateRunInfo = serde_json::from_reader(file) .unwrap_or_else(|_| show_error(format!("File {:?} does not contain valid JSON", binary))); - // FIXME: remove the file. + fs::remove_file(binary) + .unwrap_or_else(|_| show_error(format!("Unable to remove file {:?}", binary))); let mut cmd = miri(); - // Forward rustc arguments,with our sysroot. - cmd.args(info.args); + // Forward rustc arguments. We need to patch "--extern" filenames because + // we forced a check-only build without cargo knowing about that: replace `.rlib` suffix by `.rmeta`. + let mut args = info.args.into_iter(); + let extern_flag = "--extern"; + while let Some(arg) = args.next() { + if arg == extern_flag { + let next_arg = args.next().expect("`--extern` should be followed by a filename"); + let next_arg = next_arg.strip_suffix(".rlib").expect("all extern filenames should end in `.rlib`"); + cmd.arg(extern_flag); + cmd.arg(format!("{}.rmeta", next_arg)); + } else { + cmd.arg(arg); + } + } + // Set sysroot. let sysroot = env::var_os("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); cmd.arg("--sysroot"); cmd.arg(sysroot); + // Respect `MIRIFLAGS`. + if let Ok(a) = env::var("MIRIFLAGS") { + // This code is taken from `RUSTFLAGS` handling in cargo. + let args = a + .split(' ') + .map(str::trim) + .filter(|s| !s.is_empty()) + .map(str::to_string); + cmd.args(args); + } // Then pass binary arguments. cmd.arg("--"); - cmd.args(args); + cmd.args(binary_args); // Run it. if verbose { - eprintln!("+ {:?}", cmd); + eprintln!("[cargo-miri runner] {:?}", cmd); } exec(cmd) } @@ -548,7 +594,9 @@ fn main() { return; } - let mut args = std::env::args_os(); + // Rustc does not support non-UTF-8 arguments so we make no attempt either. + // (We do support non-UTF-8 environment variables though.) + let mut args = std::env::args(); // Skip binary name. args.next().unwrap(); @@ -559,10 +607,10 @@ fn main() { // binary crates for later interpretation. // - When we are executed due to CARGO_TARGET_RUNNER, we start interpretation based on the // flags that were stored earlier. - // FIXME: report errors for these unwraps. - match &*args.next().unwrap().to_str().unwrap() { - "miri" => phase_cargo_miri(args), - "rustc" => phase_cargo_rustc(args), - binary => phase_cargo_runner(binary, args), + match args.next().as_deref() { + Some("miri") => phase_cargo_miri(args), + Some("rustc") => phase_cargo_rustc(args), + Some(binary) => phase_cargo_runner(binary, args), + _ => show_error(format!("`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`")), } } diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index a258c7f73c2d..6a28f1b403e8 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -21,13 +21,16 @@ def cargo_miri(cmd): args += ["--target", os.environ['MIRI_TEST_TARGET']] return args -def test(name, cmd, stdout_ref, stderr_ref): +def test(name, cmd, stdout_ref, stderr_ref, env={}): print("==> Testing `{}` <==".format(name)) ## Call `cargo miri`, capture all output + p_env = os.environ.copy() + p_env.update(env) p = subprocess.Popen( cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE + stderr=subprocess.PIPE, + env=p_env, ) (stdout, stderr) = p.communicate() stdout = stdout.decode("UTF-8") @@ -55,29 +58,31 @@ def test_cargo_miri_run(): "stdout.ref", "stderr.ref" ) test("cargo miri run (with arguments)", - cargo_miri("run") + ["--", "--", "hello world", '"hello world"'], + cargo_miri("run") + ["--", "hello world", '"hello world"'], "stdout.ref", "stderr.ref2" ) def test_cargo_miri_test(): test("cargo miri test", - cargo_miri("test") + ["--", "-Zmiri-seed=feed"], - "test.stdout.ref", "test.stderr.ref" + cargo_miri("test"), + "test.stdout.ref", "test.stderr.ref", + env={'MIRIFLAGS': "-Zmiri-seed=feed"}, ) test("cargo miri test (with filter)", - cargo_miri("test") + ["--", "--", "le1"], + cargo_miri("test") + ["--", "--format=pretty", "le1"], "test.stdout.ref2", "test.stderr.ref" ) test("cargo miri test (without isolation)", - cargo_miri("test") + ["--", "-Zmiri-disable-isolation", "--", "num_cpus"], - "test.stdout.ref3", "test.stderr.ref" + cargo_miri("test") + ["--", "--format=pretty", "num_cpus"], + "test.stdout.ref3", "test.stderr.ref", + env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) test("cargo miri test (test target)", - cargo_miri("test") + ["--test", "test"], + cargo_miri("test") + ["--test", "test", "--", "--format=pretty"], "test.stdout.ref4", "test.stderr.ref" ) test("cargo miri test (bin target)", - cargo_miri("test") + ["--bin", "cargo-miri-test"], + cargo_miri("test") + ["--bin", "cargo-miri-test", "--", "--format=pretty"], "test.stdout.ref5", "test.stderr.ref" ) diff --git a/test-cargo-miri/test.stdout.ref b/test-cargo-miri/test.stdout.ref index 4260f5b3cb78..fa78cd354878 100644 --- a/test-cargo-miri/test.stdout.ref +++ b/test-cargo-miri/test.stdout.ref @@ -1,18 +1,10 @@ running 1 test -test test::rng ... ok - +. test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out running 7 tests -test do_panic ... ok -test does_not_work_on_miri ... ignored -test entropy_rng ... ok -test fail_index_check ... ok -test num_cpus ... ok -test simple1 ... ok -test simple2 ... ok - +.i..... test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out From ee7d5895302d621fdef40590f072cbed940d204e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 8 Sep 2020 09:56:21 +0200 Subject: [PATCH 2282/5092] test respecting 'test=false', and what happens with doctests --- test-cargo-miri/Cargo.toml | 4 ++++ test-cargo-miri/src/lib.rs | 7 +++++++ 2 files changed, 11 insertions(+) create mode 100644 test-cargo-miri/src/lib.rs diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 3abb437049f0..68970d7d1662 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -10,3 +10,7 @@ byteorder = "1.0" [dev-dependencies] rand = { version = "0.7", features = ["small_rng"] } num_cpus = "1.10.1" + +[lib] +test = false +doctest = false # FIXME: doctests should be skipped automatically until we can run them... diff --git a/test-cargo-miri/src/lib.rs b/test-cargo-miri/src/lib.rs new file mode 100644 index 000000000000..064954ba9800 --- /dev/null +++ b/test-cargo-miri/src/lib.rs @@ -0,0 +1,7 @@ +/// Doc-test test +/// ```rust +/// assert!(true); +/// ``` +pub fn make_true() -> bool { + true +} From 9a9988a4b04622805ae5060dcafc123964da2c3d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 8 Sep 2020 10:01:18 +0200 Subject: [PATCH 2283/5092] update docs, and also use MIRIFLAGS for the test suite --- README.md | 16 ++++++++-------- ci.sh | 2 +- tests/compiletest.rs | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index d8474868703d..67161974b184 100644 --- a/README.md +++ b/README.md @@ -83,11 +83,10 @@ Now you can run your project in Miri: The first time you run Miri, it will perform some extra setup and install some dependencies. It will ask you for confirmation before installing anything. -You can pass arguments to Miri after the first `--`, and pass arguments to the -interpreted program or test suite after the second `--`. For example, `cargo -miri run -- -Zmiri-disable-stacked-borrows` runs the program without checking -the aliasing of references. To filter the tests being run, use `cargo miri test --- -- filter`. +`cargo miri run/test` supports the exact same flags as `cargo run/test`. You +can pass arguments to Miri via `MIRIFLAGS`. For example, +`MIRIFLAGS="-Zmiri-disable-stacked-borrows" cargo miri run` runs the program +without checking the aliasing of references. Miri supports cross-execution: if you want to run the program as if it was a Linux program, you can do `cargo miri run --target x86_64-unknown-linux-gnu`. @@ -163,7 +162,8 @@ up the sysroot. If you are using `miri` (the Miri driver) directly, see the ## Miri `-Z` flags and environment variables [miri-flags]: #miri--z-flags-and-environment-variables -Miri adds its own set of `-Z` flags: +Miri adds its own set of `-Z` flags, which are usually set via the `MIRIFLAGS` +environment variable: * `-Zmiri-disable-alignment-check` disables checking pointer alignment, so you can focus on other failures, but it means Miri can miss bugs in your program. @@ -229,14 +229,14 @@ Moreover, Miri recognizes some environment variables: * `MIRI_LOG`, `MIRI_BACKTRACE` control logging and backtrace printing during Miri executions, also [see above][testing-miri]. +* `MIRIFLAGS` (recognized by `cargo miri` and the test suite) defines extra + flags to be passed to Miri. * `MIRI_SYSROOT` (recognized by `cargo miri` and the test suite) indicates the sysroot to use. To do the same thing with `miri` directly, use the `--sysroot` flag. * `MIRI_TEST_TARGET` (recognized by the test suite) indicates which target architecture to test against. `miri` and `cargo miri` accept the `--target` flag for the same purpose. -* `MIRI_TEST_FLAGS` (recognized by the test suite) defines extra flags to be - passed to Miri. The following environment variables are internal, but used to communicate between different Miri binaries, and as such worth documenting: diff --git a/ci.sh b/ci.sh index 915a4cf2fd3d..12683a2fccbe 100755 --- a/ci.sh +++ b/ci.sh @@ -26,7 +26,7 @@ function run_tests { if ! [ -n "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with MIR optimizations # FIXME: only testing level 2 because of . - MIRI_TEST_FLAGS="-Z mir-opt-level=2" ./miri test --locked + MIRIFLAGS="-Z mir-opt-level=2" ./miri test --locked fi # "miri test" has built the sysroot for us, now this should pass without # any interactive questions. diff --git a/tests/compiletest.rs b/tests/compiletest.rs index a64f0edb9464..35c1de3399c0 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -27,7 +27,7 @@ fn run_tests(mode: &str, path: &str, target: &str) { if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") { flags.push(format!("--sysroot {}", sysroot)); } - if let Ok(extra_flags) = std::env::var("MIRI_TEST_FLAGS") { + if let Ok(extra_flags) = std::env::var("MIRIFLAGS") { flags.push(extra_flags); } From 0019fe2459eb353688c8578459eded7d17359d22 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 8 Sep 2020 11:08:46 +0200 Subject: [PATCH 2284/5092] fix typo Co-authored-by: Oli Scherer --- cargo-miri/bin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index bf27195d5392..f5c402de7276 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -462,7 +462,7 @@ fn phase_cargo_rustc(args: env::Args) { // But we cannot run it here, as cargo invoked us as a compiler -- our stdin and stdout are not // like we want them. // Instead of compiling, we write JSON into the output file with all the relevant command-line flags - // and environment variables; this is sued alter when cargo calls us again in the CARGO_TARGET_RUNNER phase. + // and environment variables; this is used when cargo calls us again in the CARGO_TARGET_RUNNER phase. let info = CrateRunInfo::collect(args); let mut path = PathBuf::from(get_arg_flag_value("--out-dir").unwrap()); From 147330cc3603260d17085f3abcf7e62ca01b44ef Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 8 Sep 2020 20:08:11 +0200 Subject: [PATCH 2285/5092] even when not linking, create stub .rlib files to fool cargo --- cargo-miri/bin.rs | 105 ++++++++++++++++++++++++++++------------------ 1 file changed, 64 insertions(+), 41 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index f5c402de7276..1aa1d4d87e44 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -136,9 +136,13 @@ fn xargo_check() -> Command { Command::new(env::var_os("XARGO_CHECK").unwrap_or_else(|| OsString::from("xargo-check"))) } -fn exec(mut cmd: Command) -> ! { +/// Execute the command if it fails, fail this process with the same exit code. +/// Otherwise, continue. +fn exec(mut cmd: Command) { let exit_status = cmd.status().expect("failed to run command"); - std::process::exit(exit_status.code().unwrap_or(-1)) + if exit_status.success().not() { + std::process::exit(exit_status.code().unwrap_or(-1)) + } } fn xargo_version() -> Option<(u32, u32, u32)> { @@ -454,6 +458,20 @@ fn phase_cargo_rustc(args: env::Args) { (is_bin || is_test) && !print } + fn out_filename(prefix: &str, suffix: &str) -> PathBuf { + let mut path = PathBuf::from(get_arg_flag_value("--out-dir").unwrap()); + path.push(format!( + "{}{}{}{}", + prefix, + get_arg_flag_value("--crate-name").unwrap(), + // This is technically a `-C` flag but the prefix seems unique enough... + // (and cargo passes this before the filename so it should be unique) + get_arg_flag_value("extra-filename").unwrap_or(String::new()), + suffix, + )); + path + } + let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); let target_crate = is_target_crate(); @@ -464,59 +482,57 @@ fn phase_cargo_rustc(args: env::Args) { // Instead of compiling, we write JSON into the output file with all the relevant command-line flags // and environment variables; this is used when cargo calls us again in the CARGO_TARGET_RUNNER phase. let info = CrateRunInfo::collect(args); + // FIXME: Windows might need a ".exe" suffix. + let filename = out_filename("", ""); - let mut path = PathBuf::from(get_arg_flag_value("--out-dir").unwrap()); - path.push(format!( - "{}{}", - get_arg_flag_value("--crate-name").unwrap(), - // This is technically a `-C` flag but the prefix seems unique enough... - // (and cargo passes this before the filename so it should be unique) - get_arg_flag_value("extra-filename").unwrap_or(String::new()), - )); if verbose { - eprintln!("[cargo-miri rustc] writing run info to {:?}", path.display()); + eprintln!("[cargo-miri rustc] writing run info to {:?}", filename.display()); } - let file = File::create(&path) - .unwrap_or_else(|_| show_error(format!("Cannot create {:?}", path.display()))); + let file = File::create(&filename) + .unwrap_or_else(|_| show_error(format!("Cannot create {:?}", filename.display()))); let file = BufWriter::new(file); serde_json::ser::to_writer(file, &info) - .unwrap_or_else(|_| show_error(format!("Cannot write to {:?}", path.display()))); + .unwrap_or_else(|_| show_error(format!("Cannot write to {:?}", filename.display()))); return; } let mut cmd = miri(); - // Forward arguments, but (only for target crates!) remove "link" from "--emit" to make this a check-only build. - let emit_flag = "--emit"; - for arg in args { - if target_crate && arg.starts_with(emit_flag) { - // Patch this argument. First, extract its value. - let val = &arg[emit_flag.len()..]; - assert!(val.starts_with("="), "`cargo` should pass `--emit=X` as one argument"); - let val = &val[1..]; - let mut val: Vec<_> = val.split(',').collect(); - // Now make sure "link" is not in there, but "metadata" is. - if let Some(i) = val.iter().position(|&s| s == "link") { - val.remove(i); - if !val.iter().any(|&s| s == "metadata") { - val.push("metadata"); - } - } - cmd.arg(format!("{}={}", emit_flag, val.join(","))); - // FIXME: due to this, the `.rlib` file does not get created and cargo re-triggers the build each time. - } else { - cmd.arg(arg); - } - } - - // We make sure to only specify our custom Xargo sysroot for target crates - that is, - // crates which are needed for interpretation by Miri. proc-macros and build scripts - // should use the default sysroot. + let mut emit_link_hack = false; + // Arguments are treated very differently depending on whether this crate is + // for interpretation by Miri, or for use by a build script / proc macro. if target_crate { + // Forward arguments, butremove "link" from "--emit" to make this a check-only build. + let emit_flag = "--emit"; + for arg in args { + if arg.starts_with(emit_flag) { + // Patch this argument. First, extract its value. + let val = &arg[emit_flag.len()..]; + assert!(val.starts_with("="), "`cargo` should pass `--emit=X` as one argument"); + let val = &val[1..]; + let mut val: Vec<_> = val.split(',').collect(); + // Now make sure "link" is not in there, but "metadata" is. + if let Some(i) = val.iter().position(|&s| s == "link") { + emit_link_hack = true; + val.remove(i); + if !val.iter().any(|&s| s == "metadata") { + val.push("metadata"); + } + } + cmd.arg(format!("{}={}", emit_flag, val.join(","))); + } else { + cmd.arg(arg); + } + } + + // Use our custom sysroot. let sysroot = env::var_os("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); cmd.arg("--sysroot"); cmd.arg(sysroot); + } else { + // For host crates, just forward everything. + cmd.args(args); } // We want to compile, not interpret. We still use Miri to make sure the compiler version etc @@ -527,7 +543,14 @@ fn phase_cargo_rustc(args: env::Args) { if verbose { eprintln!("[cargo-miri rustc] {:?}", cmd); } - exec(cmd) + exec(cmd); + + // Create a stub .rlib file if "link" was requested by cargo. + if emit_link_hack { + // FIXME: is "lib" always right? + let filename = out_filename("lib", ".rlib"); + File::create(filename).expect("Failed to create rlib file"); + } } fn phase_cargo_runner(binary: &str, binary_args: env::Args) { From 53eab7195a8b4c68e3b51e928ffed4b4580c9cf2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 8 Sep 2020 20:18:08 +0200 Subject: [PATCH 2286/5092] make our filename handling work better across platforms --- cargo-miri/bin.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 1aa1d4d87e44..3e42cf1f7722 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -486,14 +486,14 @@ fn phase_cargo_rustc(args: env::Args) { let filename = out_filename("", ""); if verbose { - eprintln!("[cargo-miri rustc] writing run info to {:?}", filename.display()); + eprintln!("[cargo-miri rustc] writing run info to `{}`", filename.display()); } let file = File::create(&filename) - .unwrap_or_else(|_| show_error(format!("Cannot create {:?}", filename.display()))); + .unwrap_or_else(|_| show_error(format!("Cannot create `{}`", filename.display()))); let file = BufWriter::new(file); serde_json::ser::to_writer(file, &info) - .unwrap_or_else(|_| show_error(format!("Cannot write to {:?}", filename.display()))); + .unwrap_or_else(|_| show_error(format!("Cannot write to `{}`", filename.display()))); return; } @@ -502,7 +502,7 @@ fn phase_cargo_rustc(args: env::Args) { // Arguments are treated very differently depending on whether this crate is // for interpretation by Miri, or for use by a build script / proc macro. if target_crate { - // Forward arguments, butremove "link" from "--emit" to make this a check-only build. + // Forward arguments, but remove "link" from "--emit" to make this a check-only build. let emit_flag = "--emit"; for arg in args { if arg.starts_with(emit_flag) { @@ -547,21 +547,26 @@ fn phase_cargo_rustc(args: env::Args) { // Create a stub .rlib file if "link" was requested by cargo. if emit_link_hack { - // FIXME: is "lib" always right? + // Some platforms prepend "lib", some do not... let's just create both files. let filename = out_filename("lib", ".rlib"); File::create(filename).expect("Failed to create rlib file"); + let filename = out_filename("", ".rlib"); + File::create(filename).expect("Failed to create rlib file"); } } fn phase_cargo_runner(binary: &str, binary_args: env::Args) { let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); - let file = File::open(binary) + // Strip extension from binary name (Windows adds ".exe"). + let mut filename = PathBuf::from(binary); + filename.set_extension(""); + let file = File::open(&filename) .unwrap_or_else(|_| show_error(format!("File {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary))); let file = BufReader::new(file); let info: CrateRunInfo = serde_json::from_reader(file) .unwrap_or_else(|_| show_error(format!("File {:?} does not contain valid JSON", binary))); - fs::remove_file(binary) + fs::remove_file(&filename) .unwrap_or_else(|_| show_error(format!("Unable to remove file {:?}", binary))); let mut cmd = miri(); From c793d6036a33eb6df5d523aeb6f5fbe375d8b3c7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Sep 2020 01:00:09 +0200 Subject: [PATCH 2287/5092] handle binary suffices (for Windows); stop deleting fake binary --- cargo-miri/bin.rs | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 3e42cf1f7722..537f071c9d46 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -59,6 +59,14 @@ impl CrateRunInfo { let env = env::vars_os().collect(); CrateRunInfo { args, env } } + + fn store(&self, filename: &Path) { + let file = File::create(filename) + .unwrap_or_else(|_| show_error(format!("Cannot create `{}`", filename.display()))); + let file = BufWriter::new(file); + serde_json::ser::to_writer(file, self) + .unwrap_or_else(|_| show_error(format!("Cannot write to `{}`", filename.display()))); + } } fn show_help() { @@ -482,18 +490,16 @@ fn phase_cargo_rustc(args: env::Args) { // Instead of compiling, we write JSON into the output file with all the relevant command-line flags // and environment variables; this is used when cargo calls us again in the CARGO_TARGET_RUNNER phase. let info = CrateRunInfo::collect(args); - // FIXME: Windows might need a ".exe" suffix. let filename = out_filename("", ""); - if verbose { eprintln!("[cargo-miri rustc] writing run info to `{}`", filename.display()); } - let file = File::create(&filename) - .unwrap_or_else(|_| show_error(format!("Cannot create `{}`", filename.display()))); - let file = BufWriter::new(file); - serde_json::ser::to_writer(file, &info) - .unwrap_or_else(|_| show_error(format!("Cannot write to `{}`", filename.display()))); + info.store(&filename); + // For Windows, do the same thing again with `.exe` appended to the filename. + // (Need to do this here as cargo moves that "binary" to a different place before running it.) + info.store(&out_filename("", ".exe")); + return; } @@ -558,16 +564,11 @@ fn phase_cargo_rustc(args: env::Args) { fn phase_cargo_runner(binary: &str, binary_args: env::Args) { let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); - // Strip extension from binary name (Windows adds ".exe"). - let mut filename = PathBuf::from(binary); - filename.set_extension(""); - let file = File::open(&filename) + let file = File::open(&binary) .unwrap_or_else(|_| show_error(format!("File {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary))); let file = BufReader::new(file); let info: CrateRunInfo = serde_json::from_reader(file) .unwrap_or_else(|_| show_error(format!("File {:?} does not contain valid JSON", binary))); - fs::remove_file(&filename) - .unwrap_or_else(|_| show_error(format!("Unable to remove file {:?}", binary))); let mut cmd = miri(); // Forward rustc arguments. We need to patch "--extern" filenames because @@ -593,10 +594,10 @@ fn phase_cargo_runner(binary: &str, binary_args: env::Args) { if let Ok(a) = env::var("MIRIFLAGS") { // This code is taken from `RUSTFLAGS` handling in cargo. let args = a - .split(' ') - .map(str::trim) - .filter(|s| !s.is_empty()) - .map(str::to_string); + .split(' ') + .map(str::trim) + .filter(|s| !s.is_empty()) + .map(str::to_string); cmd.args(args); } From 10f58b3eabf641151c7a02aadf8a2911ad24f281 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Sep 2020 08:40:06 +0200 Subject: [PATCH 2288/5092] fix Miri script on macOS --- miri | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/miri b/miri index f53c21ff115c..aef61b6dd68d 100755 --- a/miri +++ b/miri @@ -39,7 +39,11 @@ EOF TARGET=$(rustc --version --verbose | grep "^host:" | cut -d ' ' -f 2) SYSROOT=$(rustc --print sysroot) LIBDIR=$SYSROOT/lib/rustlib/$TARGET/lib -MIRIDIR=$(readlink -e "$(dirname "$0")") +MIRIDIR=$(dirname "$0") +if readlink -e . >/dev/null; then + # This platform supports `readlink -e`. + MIRIDIR=$(readlink -e "$MIRIDIR") +fi if ! test -d "$LIBDIR"; then echo "Something went wrong determining the library dir." echo "I got $LIBDIR but that does not exist." From 119bf4d6073e0675714c1ee1f3f4f9b655b83544 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Sep 2020 08:51:41 +0200 Subject: [PATCH 2289/5092] forward build-time env vars to binary, and test that we do --- cargo-miri/bin.rs | 27 +++++++++++++++++---------- test-cargo-miri/test.stdout.ref | 6 +++--- test-cargo-miri/test.stdout.ref2 | 2 +- test-cargo-miri/test.stdout.ref3 | 2 +- test-cargo-miri/test.stdout.ref4 | 5 +++-- test-cargo-miri/tests/test.rs | 6 ++++++ 6 files changed, 31 insertions(+), 17 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 537f071c9d46..7ae3c7fe6cfd 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -375,6 +375,16 @@ path = "lib.rs" } fn phase_cargo_miri(mut args: env::Args) { + // Check for version and help flags even when invoked as `cargo-miri`. + if has_arg_flag("--help") || has_arg_flag("-h") { + show_help(); + return; + } + if has_arg_flag("--version") || has_arg_flag("-V") { + show_version(); + return; + } + // Require a subcommand before any flags. // We cannot know which of those flags take arguments and which do not, // so we cannot detect subcommands later. @@ -570,6 +580,13 @@ fn phase_cargo_runner(binary: &str, binary_args: env::Args) { let info: CrateRunInfo = serde_json::from_reader(file) .unwrap_or_else(|_| show_error(format!("File {:?} does not contain valid JSON", binary))); + // Set missing env vars. + for (name, val) in info.env { + if env::var_os(&name).is_none() { + env::set_var(name, val); + } + } + let mut cmd = miri(); // Forward rustc arguments. We need to patch "--extern" filenames because // we forced a check-only build without cargo knowing about that: replace `.rlib` suffix by `.rmeta`. @@ -613,16 +630,6 @@ fn phase_cargo_runner(binary: &str, binary_args: env::Args) { } fn main() { - // Check for version and help flags even when invoked as `cargo-miri`. - if has_arg_flag("--help") || has_arg_flag("-h") { - show_help(); - return; - } - if has_arg_flag("--version") || has_arg_flag("-V") { - show_version(); - return; - } - // Rustc does not support non-UTF-8 arguments so we make no attempt either. // (We do support non-UTF-8 environment variables though.) let mut args = std::env::args(); diff --git a/test-cargo-miri/test.stdout.ref b/test-cargo-miri/test.stdout.ref index fa78cd354878..1eb18fe88768 100644 --- a/test-cargo-miri/test.stdout.ref +++ b/test-cargo-miri/test.stdout.ref @@ -4,7 +4,7 @@ running 1 test test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out -running 7 tests -.i..... -test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out +running 8 tests +..i..... +test result: ok. 7 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/test.stdout.ref2 b/test-cargo-miri/test.stdout.ref2 index 37efb8c3ee89..d426bdf6db63 100644 --- a/test-cargo-miri/test.stdout.ref2 +++ b/test-cargo-miri/test.stdout.ref2 @@ -7,5 +7,5 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out running 1 test test simple1 ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 7 filtered out diff --git a/test-cargo-miri/test.stdout.ref3 b/test-cargo-miri/test.stdout.ref3 index c5c39de109d2..bc4a7c47e9f5 100644 --- a/test-cargo-miri/test.stdout.ref3 +++ b/test-cargo-miri/test.stdout.ref3 @@ -7,5 +7,5 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out running 1 test test num_cpus ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 7 filtered out diff --git a/test-cargo-miri/test.stdout.ref4 b/test-cargo-miri/test.stdout.ref4 index b6403bf6c091..32bbcf9bf275 100644 --- a/test-cargo-miri/test.stdout.ref4 +++ b/test-cargo-miri/test.stdout.ref4 @@ -1,5 +1,6 @@ -running 7 tests +running 8 tests +test cargo_env ... ok test do_panic ... ok test does_not_work_on_miri ... ignored test entropy_rng ... ok @@ -8,5 +9,5 @@ test num_cpus ... ok test simple1 ... ok test simple2 ... ok -test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out +test result: ok. 7 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index e38dc7a926c9..35e05368803a 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -42,6 +42,12 @@ fn num_cpus() { assert_eq!(num_cpus::get(), 1); } +#[test] +fn cargo_env() { + assert_eq!(env!("CARGO_PKG_NAME"), "cargo-miri-test"); + env!("CARGO_BIN_EXE_cargo-miri-test"); // Asserts that this exists. +} + #[test] #[should_panic(expected="Explicit panic")] fn do_panic() { // In large, friendly letters :) From 74fdb5cf2cbd069ad2890ee642d66fc59b3ddc0e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Sep 2020 09:12:26 +0200 Subject: [PATCH 2290/5092] patch away --error-format and --json so that errors are rendered properly --- cargo-miri/bin.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 7ae3c7fe6cfd..bac38e3c8018 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -588,16 +588,32 @@ fn phase_cargo_runner(binary: &str, binary_args: env::Args) { } let mut cmd = miri(); - // Forward rustc arguments. We need to patch "--extern" filenames because - // we forced a check-only build without cargo knowing about that: replace `.rlib` suffix by `.rmeta`. + // Forward rustc arguments. + // We need to patch "--extern" filenames because we forced a check-only + // build without cargo knowing about that: replace `.rlib` suffix by + // `.rmeta`. + // We also need to remove `--error-format` as cargo specifies that to be JSON, + // but when we run here, cargo does not interpret the JSON any more. `--json` + // then also nees to be dropped. let mut args = info.args.into_iter(); let extern_flag = "--extern"; + let error_format_flag = "--error-format"; + let json_flag = "--json"; while let Some(arg) = args.next() { if arg == extern_flag { + // `--extern` is always passed as a separate argument by cargo. let next_arg = args.next().expect("`--extern` should be followed by a filename"); let next_arg = next_arg.strip_suffix(".rlib").expect("all extern filenames should end in `.rlib`"); cmd.arg(extern_flag); cmd.arg(format!("{}.rmeta", next_arg)); + } else if arg.starts_with(error_format_flag) { + let suffix = &arg[error_format_flag.len()..]; + assert!(suffix.starts_with('=')); + // Drop this argument. + } else if arg.starts_with(json_flag) { + let suffix = &arg[json_flag.len()..]; + assert!(suffix.starts_with('=')); + // Drop this argument. } else { cmd.arg(arg); } From 504c617cd4d1f67e8f472b559d32ab081b9c804e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Sep 2020 09:18:10 +0200 Subject: [PATCH 2291/5092] test reading from stdin --- test-cargo-miri/run-test.py | 19 +++++++++---------- test-cargo-miri/src/main.rs | 18 ++++++++++++++++++ test-cargo-miri/stdout.ref | 2 ++ test-cargo-miri/stdout.ref2 | 1 + 4 files changed, 30 insertions(+), 10 deletions(-) create mode 100644 test-cargo-miri/stdout.ref2 diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 6a28f1b403e8..877a2a570619 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -21,18 +21,19 @@ def cargo_miri(cmd): args += ["--target", os.environ['MIRI_TEST_TARGET']] return args -def test(name, cmd, stdout_ref, stderr_ref, env={}): +def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): print("==> Testing `{}` <==".format(name)) ## Call `cargo miri`, capture all output p_env = os.environ.copy() p_env.update(env) p = subprocess.Popen( cmd, + stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=p_env, ) - (stdout, stderr) = p.communicate() + (stdout, stderr) = p.communicate(input=stdin) stdout = stdout.decode("UTF-8") stderr = stderr.decode("UTF-8") # Show output @@ -51,15 +52,13 @@ def test(name, cmd, stdout_ref, stderr_ref, env={}): def test_cargo_miri_run(): test("cargo miri run", cargo_miri("run"), - "stdout.ref", "stderr.ref" + "stdout.ref", "stderr.ref", + stdin=b'12\n21\n', + env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) - test("cargo miri run (with target)", - cargo_miri("run") + ["--bin", "cargo-miri-test"], - "stdout.ref", "stderr.ref" - ) - test("cargo miri run (with arguments)", - cargo_miri("run") + ["--", "hello world", '"hello world"'], - "stdout.ref", "stderr.ref2" + test("cargo miri run (with arguments and target)", + cargo_miri("run") + ["--bin", "cargo-miri-test", "--", "hello world", '"hello world"'], + "stdout.ref2", "stderr.ref2" ) def test_cargo_miri_test(): diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index d3663ec849d3..0079328ff605 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -1,4 +1,6 @@ use byteorder::{BigEndian, ByteOrder}; +#[cfg(unix)] +use std::io::{self, BufRead}; fn main() { // Exercise external crate, printing to stdout. @@ -11,6 +13,22 @@ fn main() { for arg in std::env::args() { eprintln!("{}", arg); } + + // If there were no arguments, access stdin. + if std::env::args().len() <= 1 { + #[cfg(unix)] + for line in io::stdin().lock().lines() { + let num: i32 = line.unwrap().parse().unwrap(); + println!("{}", 2*num); + } + // On non-Unix, reading from stdin is not support. So we hard-code the right answer. + #[cfg(not(unix))] + { + println!("24"); + println!("42"); + } + } + } #[cfg(test)] diff --git a/test-cargo-miri/stdout.ref b/test-cargo-miri/stdout.ref index 6710f307cb26..2eab8df967d5 100644 --- a/test-cargo-miri/stdout.ref +++ b/test-cargo-miri/stdout.ref @@ -1 +1,3 @@ 0x01020304 +24 +42 diff --git a/test-cargo-miri/stdout.ref2 b/test-cargo-miri/stdout.ref2 new file mode 100644 index 000000000000..6710f307cb26 --- /dev/null +++ b/test-cargo-miri/stdout.ref2 @@ -0,0 +1 @@ +0x01020304 From ba3b354af98e07805168398f28d62f526b0471ad Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Sep 2020 11:48:44 +0200 Subject: [PATCH 2292/5092] update comment Co-authored-by: Oli Scherer --- cargo-miri/bin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index bac38e3c8018..70f8888676f3 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -444,7 +444,7 @@ fn phase_cargo_miri(mut args: env::Args) { // Run cargo. if verbose { - cmd.env("MIRI_VERBOSE", ""); // this makes `inside_cargo_rustc` verbose. + cmd.env("MIRI_VERBOSE", ""); // This makes the other phases verbose. eprintln!("[cargo-miri miri] {:?}", cmd); } exec(cmd) From 2205ed5bbb2fb8fb6c3b6a619815513f9d4c8038 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 11 Sep 2020 15:05:05 +0200 Subject: [PATCH 2293/5092] show proper warning about not running doctests --- cargo-miri/bin.rs | 22 ++++++++++++++++++++-- test-cargo-miri/Cargo.toml | 3 +-- test-cargo-miri/run-test.py | 4 ++-- test-cargo-miri/test.stderr.ref | 1 + test-cargo-miri/test.stderr.ref2 | 0 5 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 test-cargo-miri/test.stderr.ref2 diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 70f8888676f3..6dbaa9791df4 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -442,6 +442,9 @@ fn phase_cargo_miri(mut args: env::Args) { let runner_env_name = format!("CARGO_TARGET_{}_RUNNER", target.to_uppercase().replace('-', "_")); cmd.env(runner_env_name, &miri_path); + // Set rustdoc to us as well, so we can make it do nothing (see issue #584). + cmd.env("RUSTDOC", &miri_path); + // Run cargo. if verbose { cmd.env("MIRI_VERBOSE", ""); // This makes the other phases verbose. @@ -571,7 +574,7 @@ fn phase_cargo_rustc(args: env::Args) { } } -fn phase_cargo_runner(binary: &str, binary_args: env::Args) { +fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); let file = File::open(&binary) @@ -659,10 +662,25 @@ fn main() { // binary crates for later interpretation. // - When we are executed due to CARGO_TARGET_RUNNER, we start interpretation based on the // flags that were stored earlier. + // On top of that, we are also called as RUSTDOC, but that is just a stub currently. match args.next().as_deref() { Some("miri") => phase_cargo_miri(args), Some("rustc") => phase_cargo_rustc(args), - Some(binary) => phase_cargo_runner(binary, args), + Some(arg) => { + // We have to distinguish the "runner" and "rustfmt" cases. + // As runner, the first argument is the binary (a file that should exist, with an absolute path); + // as rustfmt, the first argument is a flag (`--something`). + let binary = Path::new(arg); + if binary.exists() { + assert!(!arg.starts_with("--")); // not a flag + phase_cargo_runner(binary, args); + } else if arg.starts_with("--") { + // We are rustdoc. + eprintln!("Running doctests is not currently supported by Miri.") + } else { + show_error(format!("`cargo-miri` called with unexpected first argument `{}`; please only invoke this binary through `cargo miri`", arg)); + } + } _ => show_error(format!("`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`")), } } diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 68970d7d1662..6bc11ef0cc5a 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -12,5 +12,4 @@ rand = { version = "0.7", features = ["small_rng"] } num_cpus = "1.10.1" [lib] -test = false -doctest = false # FIXME: doctests should be skipped automatically until we can run them... +test = false # test that this is respected (will show in the output) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 877a2a570619..82b3b88a6332 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -78,11 +78,11 @@ def test_cargo_miri_test(): ) test("cargo miri test (test target)", cargo_miri("test") + ["--test", "test", "--", "--format=pretty"], - "test.stdout.ref4", "test.stderr.ref" + "test.stdout.ref4", "test.stderr.ref2" ) test("cargo miri test (bin target)", cargo_miri("test") + ["--bin", "cargo-miri-test", "--", "--format=pretty"], - "test.stdout.ref5", "test.stderr.ref" + "test.stdout.ref5", "test.stderr.ref2" ) os.chdir(os.path.dirname(os.path.realpath(__file__))) diff --git a/test-cargo-miri/test.stderr.ref b/test-cargo-miri/test.stderr.ref index e69de29bb2d1..a310169e305e 100644 --- a/test-cargo-miri/test.stderr.ref +++ b/test-cargo-miri/test.stderr.ref @@ -0,0 +1 @@ +Running doctests is not currently supported by Miri. diff --git a/test-cargo-miri/test.stderr.ref2 b/test-cargo-miri/test.stderr.ref2 new file mode 100644 index 000000000000..e69de29bb2d1 From 93bedd0a0920be8c26704a27ea0b0c754e438a4f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 11 Sep 2020 18:20:41 +0200 Subject: [PATCH 2294/5092] fix cargo-miri-test for cross-runs --- test-cargo-miri/run-test.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 82b3b88a6332..c7694f3854c8 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -62,18 +62,22 @@ def test_cargo_miri_run(): ) def test_cargo_miri_test(): + # rustdoc is not run on foreign targets + is_foreign = 'MIRI_TEST_TARGET' in os.environ + rustdoc_ref = "test.stderr.ref2" if is_foreign else "test.stderr.ref" + test("cargo miri test", cargo_miri("test"), - "test.stdout.ref", "test.stderr.ref", + "test.stdout.ref",rustdoc_ref, env={'MIRIFLAGS': "-Zmiri-seed=feed"}, ) test("cargo miri test (with filter)", cargo_miri("test") + ["--", "--format=pretty", "le1"], - "test.stdout.ref2", "test.stderr.ref" + "test.stdout.ref2", rustdoc_ref ) test("cargo miri test (without isolation)", cargo_miri("test") + ["--", "--format=pretty", "num_cpus"], - "test.stdout.ref3", "test.stderr.ref", + "test.stdout.ref3", rustdoc_ref, env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) test("cargo miri test (test target)", From 174a92c39ae67243a775953781ad60044054b12f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Sep 2020 12:41:23 +0200 Subject: [PATCH 2295/5092] detect when the user passes Miri's flags the old way, and support this for now --- cargo-miri/bin.rs | 61 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 6dbaa9791df4..deb5733485d7 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -12,28 +12,21 @@ use rustc_version::VersionMeta; const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 22); -const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and tests in Miri +const CARGO_MIRI_HELP: &str = r#"Runs binary crates and tests in Miri Usage: - cargo miri [subcommand] [...] [--] [...] [--] [...] + cargo miri [subcommand] [...] [--] [...] Subcommands: - run Run binaries (default) + run Run binaries test Run tests setup Only perform automatic setup, but without asking questions (for getting a proper libstd) -Common options: - -h, --help Print this message - --features Features to compile for the package - -V, --version Print version info and exit - -Other [options] are the same as `cargo check`. Everything after the first "--" is -passed verbatim to Miri, which will pass everything after the second "--" verbatim -to the interpreted program. +The cargo options are exactly the same as for `cargo run` and `cargo test`, respectively. Examples: - cargo miri run -- -Zmiri-disable-stacked-borrows - cargo miri test -- -- test-suite-filter + cargo miri run + cargo miri test -- test-suite-filter "#; #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -393,7 +386,7 @@ fn phase_cargo_miri(mut args: env::Args) { Some("run") => MiriCommand::Run, Some("setup") => MiriCommand::Setup, // Invalid command. - _ => show_error(format!("`cargo miri` must be immediately followed by `test`, `run`, or `setup`.")), + _ => show_error(format!("`cargo miri` supports the following subcommands: `run`, `test`, and `setup`.")), }; let verbose = has_arg_flag("-v"); @@ -424,8 +417,44 @@ fn phase_cargo_miri(mut args: env::Args) { host }; - // Forward all further arguments. - cmd.args(args); + // Forward all further arguments. We do some processing here because we want to + // detect people still using the old way of passing flags to Miri + // (`cargo miri -- -Zmiri-foo`). + while let Some(arg) = args.next() { + cmd.arg(&arg); + if arg == "--" { + // Check if the next argument starts with `-Zmiri`. If yes, we assume + // this is an old-style invocation. + if let Some(next_arg) = args.next() { + if next_arg.starts_with("-Zmiri") { + eprintln!( + "WARNING: it seems like you are setting Miri's flags in `cargo miri` the old way,\n\ + i.e., by passing them after the first `--`. This style is deprecated; please set\n\ + the MIRIFLAGS environment variable instead. `cargo miri run/test` now interprets\n\ + arguments the exact same way as `cargo run/test`." + ); + // Old-style invocation. Turn these into MIRIFLAGS. + let mut miriflags = env::var("MIRIFLAGS").unwrap_or_default(); + miriflags.push(' '); + miriflags.push_str(&next_arg); + while let Some(further_arg) = args.next() { + if further_arg == "--" { + // End of the Miri flags! + break; + } + miriflags.push(' '); + miriflags.push_str(&further_arg); + } + env::set_var("MIRIFLAGS", miriflags); + // Pass the remaining flags to cargo. + cmd.args(args); + break; + } + // Not a Miri argument after all, make sure we pass it to cargo. + cmd.arg(next_arg); + } + } + } // Set `RUSTC_WRAPPER` to ourselves. Cargo will prepend that binary to its usual invocation, // i.e., the first argument is `rustc` -- which is what we use in `main` to distinguish From 33c669679efdeec9f9a6e6bbb7404fdb1d2d5fd6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Sep 2020 12:52:14 +0200 Subject: [PATCH 2296/5092] test 'harness=false' tests --- cargo-miri/bin.rs | 2 +- test-cargo-miri/Cargo.toml | 4 ++++ test-cargo-miri/run-test.py | 22 +++++++++---------- test-cargo-miri/src/main.rs | 1 - test-cargo-miri/{stderr.ref => stderr.ref1} | 0 test-cargo-miri/{stdout.ref => stdout.ref1} | 0 .../{test.stderr.ref => test.stderr.ref1} | 0 .../{test.stdout.ref => test.stdout.ref1} | 1 + test-cargo-miri/test.stdout.ref2 | 1 + test-cargo-miri/test.stdout.ref3 | 1 + test-cargo-miri/tests/no-harness.rs | 3 +++ 11 files changed, 22 insertions(+), 13 deletions(-) rename test-cargo-miri/{stderr.ref => stderr.ref1} (100%) rename test-cargo-miri/{stdout.ref => stdout.ref1} (100%) rename test-cargo-miri/{test.stderr.ref => test.stderr.ref1} (100%) rename test-cargo-miri/{test.stdout.ref => test.stdout.ref1} (92%) create mode 100644 test-cargo-miri/tests/no-harness.rs diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index deb5733485d7..f514f4e3e5c3 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -502,7 +502,7 @@ fn phase_cargo_rustc(args: env::Args) { /// Cargo does not give us this information directly, so we need to check /// various command-line flags. fn is_runnable_crate() -> bool { - let is_bin = get_arg_flag_value("--crate-type").as_deref() == Some("bin"); + let is_bin = get_arg_flag_value("--crate-type").as_deref().unwrap_or("bin") == "bin"; let is_test = has_arg_flag("--test"); let print = get_arg_flag_value("--print").is_some(); (is_bin || is_test) && !print diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 6bc11ef0cc5a..f4847270ba40 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -13,3 +13,7 @@ num_cpus = "1.10.1" [lib] test = false # test that this is respected (will show in the output) + +[[test]] +name = "no-harness" +harness = false diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index c7694f3854c8..665e9834e8e5 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -22,7 +22,7 @@ def cargo_miri(cmd): return args def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): - print("==> Testing `{}` <==".format(name)) + print("==> Testing {} <==".format(name)) ## Call `cargo miri`, capture all output p_env = os.environ.copy() p_env.update(env) @@ -50,13 +50,13 @@ def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): fail("stderr does not match reference") def test_cargo_miri_run(): - test("cargo miri run", + test("`cargo miri run`", cargo_miri("run"), - "stdout.ref", "stderr.ref", + "stdout.ref1", "stderr.ref1", stdin=b'12\n21\n', env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) - test("cargo miri run (with arguments and target)", + test("`cargo miri run` (with arguments and target)", cargo_miri("run") + ["--bin", "cargo-miri-test", "--", "hello world", '"hello world"'], "stdout.ref2", "stderr.ref2" ) @@ -64,27 +64,27 @@ def test_cargo_miri_run(): def test_cargo_miri_test(): # rustdoc is not run on foreign targets is_foreign = 'MIRI_TEST_TARGET' in os.environ - rustdoc_ref = "test.stderr.ref2" if is_foreign else "test.stderr.ref" + rustdoc_ref = "test.stderr.ref2" if is_foreign else "test.stderr.ref1" - test("cargo miri test", + test("`cargo miri test`", cargo_miri("test"), - "test.stdout.ref",rustdoc_ref, + "test.stdout.ref1",rustdoc_ref, env={'MIRIFLAGS': "-Zmiri-seed=feed"}, ) - test("cargo miri test (with filter)", + test("`cargo miri test` (with filter)", cargo_miri("test") + ["--", "--format=pretty", "le1"], "test.stdout.ref2", rustdoc_ref ) - test("cargo miri test (without isolation)", + test("`cargo miri test` (without isolation)", cargo_miri("test") + ["--", "--format=pretty", "num_cpus"], "test.stdout.ref3", rustdoc_ref, env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) - test("cargo miri test (test target)", + test("`cargo miri test` (test target)", cargo_miri("test") + ["--test", "test", "--", "--format=pretty"], "test.stdout.ref4", "test.stderr.ref2" ) - test("cargo miri test (bin target)", + test("`cargo miri test` (bin target)", cargo_miri("test") + ["--bin", "cargo-miri-test", "--", "--format=pretty"], "test.stdout.ref5", "test.stderr.ref2" ) diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index 0079328ff605..17808f57061e 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -28,7 +28,6 @@ fn main() { println!("42"); } } - } #[cfg(test)] diff --git a/test-cargo-miri/stderr.ref b/test-cargo-miri/stderr.ref1 similarity index 100% rename from test-cargo-miri/stderr.ref rename to test-cargo-miri/stderr.ref1 diff --git a/test-cargo-miri/stdout.ref b/test-cargo-miri/stdout.ref1 similarity index 100% rename from test-cargo-miri/stdout.ref rename to test-cargo-miri/stdout.ref1 diff --git a/test-cargo-miri/test.stderr.ref b/test-cargo-miri/test.stderr.ref1 similarity index 100% rename from test-cargo-miri/test.stderr.ref rename to test-cargo-miri/test.stderr.ref1 diff --git a/test-cargo-miri/test.stdout.ref b/test-cargo-miri/test.stdout.ref1 similarity index 92% rename from test-cargo-miri/test.stdout.ref rename to test-cargo-miri/test.stdout.ref1 index 1eb18fe88768..76144513c548 100644 --- a/test-cargo-miri/test.stdout.ref +++ b/test-cargo-miri/test.stdout.ref1 @@ -3,6 +3,7 @@ running 1 test . test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +no-harness test running 8 tests ..i..... diff --git a/test-cargo-miri/test.stdout.ref2 b/test-cargo-miri/test.stdout.ref2 index d426bdf6db63..1264c6da7ff8 100644 --- a/test-cargo-miri/test.stdout.ref2 +++ b/test-cargo-miri/test.stdout.ref2 @@ -3,6 +3,7 @@ running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out +no-harness test running 1 test test simple1 ... ok diff --git a/test-cargo-miri/test.stdout.ref3 b/test-cargo-miri/test.stdout.ref3 index bc4a7c47e9f5..a5edee2c5f13 100644 --- a/test-cargo-miri/test.stdout.ref3 +++ b/test-cargo-miri/test.stdout.ref3 @@ -3,6 +3,7 @@ running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out +no-harness test running 1 test test num_cpus ... ok diff --git a/test-cargo-miri/tests/no-harness.rs b/test-cargo-miri/tests/no-harness.rs new file mode 100644 index 000000000000..8d1c5c346266 --- /dev/null +++ b/test-cargo-miri/tests/no-harness.rs @@ -0,0 +1,3 @@ +fn main() { + println!("no-harness test"); +} From 113a335c3eae30c0e7e2d691ccbba66bd1d1e75e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Sep 2020 13:10:23 +0200 Subject: [PATCH 2297/5092] test propagating env vars from build.rs to binary --- cargo-miri/bin.rs | 4 +++- test-cargo-miri/build.rs | 2 ++ test-cargo-miri/run-test.py | 7 +++++-- test-cargo-miri/src/main.rs | 3 +++ 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index f514f4e3e5c3..d35940897191 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -612,7 +612,9 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { let info: CrateRunInfo = serde_json::from_reader(file) .unwrap_or_else(|_| show_error(format!("File {:?} does not contain valid JSON", binary))); - // Set missing env vars. + // Set missing env vars. Looks like `build.rs` vars are still set at run-time, but + // `CARGO_BIN_EXE_*` are not. This means we can give the run-time environment precedence, + // to rather do too little than too much. for (name, val) in info.env { if env::var_os(&name).is_none() { env::set_var(name, val); diff --git a/test-cargo-miri/build.rs b/test-cargo-miri/build.rs index b1f5fc172620..9851ccf39f3f 100644 --- a/test-cargo-miri/build.rs +++ b/test-cargo-miri/build.rs @@ -12,4 +12,6 @@ fn not_in_miri() -> i32 { fn main() { not_in_miri(); println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-env-changed=MIRITESTVAR"); + println!("cargo:rustc-env=MIRITESTVAR=testval"); } diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 665e9834e8e5..2250835c9998 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -50,11 +50,14 @@ def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): fail("stderr does not match reference") def test_cargo_miri_run(): - test("`cargo miri run`", + test("`cargo miri run` (without isolation)", cargo_miri("run"), "stdout.ref1", "stderr.ref1", stdin=b'12\n21\n', - env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, + env={ + 'MIRIFLAGS': "-Zmiri-disable-isolation", + 'MIRITESTVAR': "wrongval", # make sure the build.rs value takes precedence + }, ) test("`cargo miri run` (with arguments and target)", cargo_miri("run") + ["--bin", "cargo-miri-test", "--", "hello world", '"hello world"'], diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index 17808f57061e..b36b0c725f85 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -3,6 +3,9 @@ use byteorder::{BigEndian, ByteOrder}; use std::io::{self, BufRead}; fn main() { + // Check env var set by `build.rs`. + assert_eq!(env!("MIRITESTVAR"), "testval"); + // Exercise external crate, printing to stdout. let buf = &[1,2,3,4]; let n = ::read_u32(buf); From c99fb102b8db55c09400c46d097d8fbb9dcde580 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Sep 2020 13:33:30 +0200 Subject: [PATCH 2298/5092] test 'cargo miri run' CWD, also for subcrate in a workspace --- test-cargo-miri/Cargo.lock | 72 +++++++++++++++-------------- test-cargo-miri/Cargo.toml | 5 +- test-cargo-miri/run-test.py | 5 ++ test-cargo-miri/src/main.rs | 8 +++- test-cargo-miri/stderr.ref3 | 0 test-cargo-miri/stdout.ref3 | 1 + test-cargo-miri/subcrate/Cargo.toml | 9 ++++ test-cargo-miri/subcrate/main.rs | 11 +++++ 8 files changed, 74 insertions(+), 37 deletions(-) create mode 100644 test-cargo-miri/stderr.ref3 create mode 100644 test-cargo-miri/stdout.ref3 create mode 100644 test-cargo-miri/subcrate/Cargo.toml create mode 100644 test-cargo-miri/subcrate/main.rs diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index ecf71a5f437a..6bc70135a898 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -4,120 +4,122 @@ name = "byteorder" version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" [[package]] name = "cargo-miri-test" version = "0.1.0" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "num_cpus", + "rand", ] [[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "getrandom" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "wasi", ] [[package]] name = "hermit-abi" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" dependencies = [ - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "libc" version = "0.2.68" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" [[package]] name = "num_cpus" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" dependencies = [ - "hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi", + "libc", ] [[package]] name = "ppv-lite86" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" [[package]] name = "rand" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", + "libc", + "rand_chacha", + "rand_core", + "rand_hc", + "rand_pcg", ] [[package]] name = "rand_chacha" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" dependencies = [ - "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86", + "rand_core", ] [[package]] name = "rand_core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", ] [[package]] name = "rand_hc" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" dependencies = [ - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core", ] [[package]] name = "rand_pcg" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" dependencies = [ - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core", ] +[[package]] +name = "subcrate" +version = "0.1.0" + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" -"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" -"checksum hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" -"checksum libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" -"checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" -"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" -"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -"checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -"checksum rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index f4847270ba40..131e18498539 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -1,7 +1,10 @@ +[workspace] +members = ["subcrate"] + [package] name = "cargo-miri-test" version = "0.1.0" -authors = ["Oliver Schneider "] +authors = ["Miri Team"] edition = "2018" [dependencies] diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 2250835c9998..430c8a75830d 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -63,6 +63,11 @@ def test_cargo_miri_run(): cargo_miri("run") + ["--bin", "cargo-miri-test", "--", "hello world", '"hello world"'], "stdout.ref2", "stderr.ref2" ) + test("`cargo miri run` (subcrate)", + cargo_miri("run") + ["-p", "subcrate"], + "stdout.ref3", "stderr.ref3", + env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, + ) def test_cargo_miri_test(): # rustdoc is not run on foreign targets diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index b36b0c725f85..5f311441bfaf 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -1,4 +1,6 @@ use byteorder::{BigEndian, ByteOrder}; +use std::env; +use std::path::PathBuf; #[cfg(unix)] use std::io::{self, BufRead}; @@ -17,8 +19,12 @@ fn main() { eprintln!("{}", arg); } - // If there were no arguments, access stdin. + // If there were no arguments, access stdin and test working dir. if std::env::args().len() <= 1 { + let env_dir = env::current_dir().unwrap(); + let crate_dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()); + assert_eq!(env_dir, crate_dir); + #[cfg(unix)] for line in io::stdin().lock().lines() { let num: i32 = line.unwrap().parse().unwrap(); diff --git a/test-cargo-miri/stderr.ref3 b/test-cargo-miri/stderr.ref3 new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/test-cargo-miri/stdout.ref3 b/test-cargo-miri/stdout.ref3 new file mode 100644 index 000000000000..53340a502381 --- /dev/null +++ b/test-cargo-miri/stdout.ref3 @@ -0,0 +1 @@ +subcrate running diff --git a/test-cargo-miri/subcrate/Cargo.toml b/test-cargo-miri/subcrate/Cargo.toml new file mode 100644 index 000000000000..13e9aa4c1af2 --- /dev/null +++ b/test-cargo-miri/subcrate/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "subcrate" +version = "0.1.0" +authors = ["Miri Team"] +edition = "2018" + +[[bin]] +name = "subcrate" +path = "main.rs" diff --git a/test-cargo-miri/subcrate/main.rs b/test-cargo-miri/subcrate/main.rs new file mode 100644 index 000000000000..db8ea7eb1855 --- /dev/null +++ b/test-cargo-miri/subcrate/main.rs @@ -0,0 +1,11 @@ +use std::env; +use std::path::PathBuf; + +fn main() { + println!("subcrate running"); + + let env_dir = env::current_dir().unwrap(); + let crate_dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()); + // CWD should be workspace root, i.e., one level up from crate root. + assert_eq!(env_dir, crate_dir.parent().unwrap()); +} From b244a2ddaa5bbc7eb0b50c018e0e578c0b230283 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Sep 2020 13:52:05 +0200 Subject: [PATCH 2299/5092] make sure subcrate tests have the right cwd --- README.md | 4 ++++ cargo-miri/bin.rs | 10 +++++++++- src/bin/miri.rs | 5 +++++ test-cargo-miri/Cargo.toml | 4 ---- test-cargo-miri/run-test.py | 29 +++++++++++++++++------------ test-cargo-miri/subcrate/Cargo.toml | 5 +++++ test-cargo-miri/subcrate/test.rs | 11 +++++++++++ test-cargo-miri/test.stdout.ref1 | 1 - test-cargo-miri/test.stdout.ref2 | 1 - test-cargo-miri/test.stdout.ref3 | 17 +++++++++-------- test-cargo-miri/test.stdout.ref4 | 13 +++---------- test-cargo-miri/test.stdout.ref5 | 6 +++--- test-cargo-miri/tests/no-harness.rs | 3 --- 13 files changed, 66 insertions(+), 43 deletions(-) create mode 100644 test-cargo-miri/subcrate/test.rs delete mode 100644 test-cargo-miri/tests/no-harness.rs diff --git a/README.md b/README.md index 67161974b184..6654de10abff 100644 --- a/README.md +++ b/README.md @@ -244,6 +244,10 @@ different Miri binaries, and as such worth documenting: * `MIRI_BE_RUSTC` when set to any value tells the Miri driver to actually not interpret the code but compile it like rustc would. This is useful to be sure that the compiled `rlib`s are compatible with Miri. +* `MIRI_CWD` when set to any value tells the Miri driver to change to the given + directory after loading all the source files, but before commencing + interpretation. This is useful if the interpreted program wants a different + working directory at run-time than at build-time. ## Miri `extern` functions diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index d35940897191..a4898e1a2cff 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -43,6 +43,8 @@ struct CrateRunInfo { args: Vec, /// The environment. env: Vec<(OsString, OsString)>, + /// The current working directory. + current_dir: OsString, } impl CrateRunInfo { @@ -50,7 +52,8 @@ impl CrateRunInfo { fn collect(args: env::Args) -> Self { let args = args.collect(); let env = env::vars_os().collect(); - CrateRunInfo { args, env } + let current_dir = env::current_dir().unwrap().into_os_string(); + CrateRunInfo { args, env, current_dir } } fn store(&self, filename: &Path) { @@ -672,6 +675,11 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { cmd.arg("--"); cmd.args(binary_args); + // Make sure we use the build-time working directory for interpreting Miri/rustc arguments. + // But then we need to switch to the run-time one, which we instruct Miri do do by setting `MIRI_CWD`. + cmd.current_dir(info.current_dir); + cmd.env("MIRI_CWD", env::current_dir().unwrap()); + // Run it. if verbose { eprintln!("[cargo-miri runner] {:?}", cmd); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 134702047522..4363f9a150a7 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -45,6 +45,11 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { // Add filename to `miri` arguments. config.args.insert(0, compiler.input().filestem().to_string()); + // Adjust working directory for interpretation. + if let Some(cwd) = env::var_os("MIRI_CWD") { + env::set_current_dir(cwd).unwrap(); + } + if let Some(return_code) = miri::eval_main(tcx, entry_def_id.to_def_id(), config) { std::process::exit( i32::try_from(return_code).expect("Return value was too large!"), diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 131e18498539..4900ce9675d6 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -16,7 +16,3 @@ num_cpus = "1.10.1" [lib] test = false # test that this is respected (will show in the output) - -[[test]] -name = "no-harness" -harness = false diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 430c8a75830d..78b10d1f2bfb 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -50,7 +50,7 @@ def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): fail("stderr does not match reference") def test_cargo_miri_run(): - test("`cargo miri run` (without isolation)", + test("`cargo miri run` (no isolation)", cargo_miri("run"), "stdout.ref1", "stderr.ref1", stdin=b'12\n21\n', @@ -61,9 +61,9 @@ def test_cargo_miri_run(): ) test("`cargo miri run` (with arguments and target)", cargo_miri("run") + ["--bin", "cargo-miri-test", "--", "hello world", '"hello world"'], - "stdout.ref2", "stderr.ref2" + "stdout.ref2", "stderr.ref2", ) - test("`cargo miri run` (subcrate)", + test("`cargo miri run` (subcrate, no ioslation)", cargo_miri("run") + ["-p", "subcrate"], "stdout.ref3", "stderr.ref3", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, @@ -76,25 +76,30 @@ def test_cargo_miri_test(): test("`cargo miri test`", cargo_miri("test"), - "test.stdout.ref1",rustdoc_ref, + "test.stdout.ref1", rustdoc_ref, env={'MIRIFLAGS': "-Zmiri-seed=feed"}, ) + test("`cargo miri test` (no isolation)", + cargo_miri("test"), + "test.stdout.ref1", rustdoc_ref, + env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, + ) test("`cargo miri test` (with filter)", cargo_miri("test") + ["--", "--format=pretty", "le1"], - "test.stdout.ref2", rustdoc_ref - ) - test("`cargo miri test` (without isolation)", - cargo_miri("test") + ["--", "--format=pretty", "num_cpus"], - "test.stdout.ref3", rustdoc_ref, - env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, + "test.stdout.ref2", rustdoc_ref, ) test("`cargo miri test` (test target)", cargo_miri("test") + ["--test", "test", "--", "--format=pretty"], - "test.stdout.ref4", "test.stderr.ref2" + "test.stdout.ref3", "test.stderr.ref2", ) test("`cargo miri test` (bin target)", cargo_miri("test") + ["--bin", "cargo-miri-test", "--", "--format=pretty"], - "test.stdout.ref5", "test.stderr.ref2" + "test.stdout.ref4", "test.stderr.ref2", + ) + test("`cargo miri test` (subcrate)", + cargo_miri("test") + ["-p", "subcrate"], + "test.stdout.ref5", "test.stderr.ref2", + env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) os.chdir(os.path.dirname(os.path.realpath(__file__))) diff --git a/test-cargo-miri/subcrate/Cargo.toml b/test-cargo-miri/subcrate/Cargo.toml index 13e9aa4c1af2..78552e6aedf0 100644 --- a/test-cargo-miri/subcrate/Cargo.toml +++ b/test-cargo-miri/subcrate/Cargo.toml @@ -7,3 +7,8 @@ edition = "2018" [[bin]] name = "subcrate" path = "main.rs" + +[[test]] +name = "subtest" +path = "test.rs" +harness = false diff --git a/test-cargo-miri/subcrate/test.rs b/test-cargo-miri/subcrate/test.rs new file mode 100644 index 000000000000..16c63411ce84 --- /dev/null +++ b/test-cargo-miri/subcrate/test.rs @@ -0,0 +1,11 @@ +use std::env; +use std::path::PathBuf; + +fn main() { + println!("subcrate testing"); + + let env_dir = env::current_dir().unwrap(); + let crate_dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()); + // CWD should be crate root. + assert_eq!(env_dir, crate_dir); +} diff --git a/test-cargo-miri/test.stdout.ref1 b/test-cargo-miri/test.stdout.ref1 index 76144513c548..1eb18fe88768 100644 --- a/test-cargo-miri/test.stdout.ref1 +++ b/test-cargo-miri/test.stdout.ref1 @@ -3,7 +3,6 @@ running 1 test . test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out -no-harness test running 8 tests ..i..... diff --git a/test-cargo-miri/test.stdout.ref2 b/test-cargo-miri/test.stdout.ref2 index 1264c6da7ff8..d426bdf6db63 100644 --- a/test-cargo-miri/test.stdout.ref2 +++ b/test-cargo-miri/test.stdout.ref2 @@ -3,7 +3,6 @@ running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out -no-harness test running 1 test test simple1 ... ok diff --git a/test-cargo-miri/test.stdout.ref3 b/test-cargo-miri/test.stdout.ref3 index a5edee2c5f13..32bbcf9bf275 100644 --- a/test-cargo-miri/test.stdout.ref3 +++ b/test-cargo-miri/test.stdout.ref3 @@ -1,12 +1,13 @@ -running 0 tests - -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out - -no-harness test - -running 1 test +running 8 tests +test cargo_env ... ok +test do_panic ... ok +test does_not_work_on_miri ... ignored +test entropy_rng ... ok +test fail_index_check ... ok test num_cpus ... ok +test simple1 ... ok +test simple2 ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 7 filtered out +test result: ok. 7 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/test.stdout.ref4 b/test-cargo-miri/test.stdout.ref4 index 32bbcf9bf275..4caa30a7f0e5 100644 --- a/test-cargo-miri/test.stdout.ref4 +++ b/test-cargo-miri/test.stdout.ref4 @@ -1,13 +1,6 @@ -running 8 tests -test cargo_env ... ok -test do_panic ... ok -test does_not_work_on_miri ... ignored -test entropy_rng ... ok -test fail_index_check ... ok -test num_cpus ... ok -test simple1 ... ok -test simple2 ... ok +running 1 test +test test::rng ... ok -test result: ok. 7 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/test.stdout.ref5 b/test-cargo-miri/test.stdout.ref5 index 4caa30a7f0e5..67e5c7f8e920 100644 --- a/test-cargo-miri/test.stdout.ref5 +++ b/test-cargo-miri/test.stdout.ref5 @@ -1,6 +1,6 @@ -running 1 test -test test::rng ... ok +running 0 tests -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +subcrate testing diff --git a/test-cargo-miri/tests/no-harness.rs b/test-cargo-miri/tests/no-harness.rs deleted file mode 100644 index 8d1c5c346266..000000000000 --- a/test-cargo-miri/tests/no-harness.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("no-harness test"); -} From 192b535adc32d96795ad4e39cc199ab68a28a60b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Sep 2020 13:57:49 +0200 Subject: [PATCH 2300/5092] cleaner output for cargo-miri-test harness --- test-cargo-miri/run-test.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 78b10d1f2bfb..bbb8df9059ac 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -22,7 +22,7 @@ def cargo_miri(cmd): return args def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): - print("==> Testing {} <==".format(name)) + print("Testing {}...".format(name)) ## Call `cargo miri`, capture all output p_env = os.environ.copy() p_env.update(env) @@ -36,18 +36,17 @@ def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): (stdout, stderr) = p.communicate(input=stdin) stdout = stdout.decode("UTF-8") stderr = stderr.decode("UTF-8") + if p.returncode == 0 and stdout == open(stdout_ref).read() and stderr == open(stderr_ref).read(): + # All good! + return # Show output - print("=> captured stdout <=") + print("--- BEGIN stdout ---") print(stdout, end="") - print("=> captured stderr <=") + print("--- END stdout ---") + print("--- BEGIN stderr ---") print(stderr, end="") - # Test for failures - if p.returncode != 0: - fail("Non-zero exit status") - if stdout != open(stdout_ref).read(): - fail("stdout does not match reference") - if stderr != open(stderr_ref).read(): - fail("stderr does not match reference") + print("--- END stderr ---") + fail("exit code was {}".format(p.returncode)) def test_cargo_miri_run(): test("`cargo miri run` (no isolation)", @@ -96,7 +95,7 @@ def test_cargo_miri_test(): cargo_miri("test") + ["--bin", "cargo-miri-test", "--", "--format=pretty"], "test.stdout.ref4", "test.stderr.ref2", ) - test("`cargo miri test` (subcrate)", + test("`cargo miri test` (subcrate, no isolation)", cargo_miri("test") + ["-p", "subcrate"], "test.stdout.ref5", "test.stderr.ref2", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, From f7612f71bcc10ceab30623850098a5c03459be28 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Sep 2020 14:02:08 +0200 Subject: [PATCH 2301/5092] more consistent error capitalization --- cargo-miri/bin.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index a4898e1a2cff..ab0c70fc86d1 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -58,10 +58,10 @@ impl CrateRunInfo { fn store(&self, filename: &Path) { let file = File::create(filename) - .unwrap_or_else(|_| show_error(format!("Cannot create `{}`", filename.display()))); + .unwrap_or_else(|_| show_error(format!("cannot create `{}`", filename.display()))); let file = BufWriter::new(file); serde_json::ser::to_writer(file, self) - .unwrap_or_else(|_| show_error(format!("Cannot write to `{}`", filename.display()))); + .unwrap_or_else(|_| show_error(format!("cannot write to `{}`", filename.display()))); } } @@ -207,15 +207,15 @@ fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { match buf.trim().to_lowercase().as_ref() { // Proceed. "" | "y" | "yes" => {} - "n" | "no" => show_error(format!("Aborting as per your request")), - a => show_error(format!("I do not understand `{}`", a)), + "n" | "no" => show_error(format!("aborting as per your request")), + a => show_error(format!("invalid answer `{}`", a)), }; } else { println!("Running `{:?}` to {}.", cmd, text); } if cmd.status().expect(&format!("failed to execute {:?}", cmd)).success().not() { - show_error(format!("Failed to {}", text)); + show_error(format!("failed to {}", text)); } } @@ -238,7 +238,7 @@ fn setup(subcommand: MiriCommand) { if xargo_version().map_or(true, |v| v < XARGO_MIN_VERSION) { if std::env::var_os("XARGO_CHECK").is_some() { // The user manually gave us a xargo binary; don't do anything automatically. - show_error(format!("Your xargo is too old; please upgrade to the latest version")) + show_error(format!("xargo is too old; please upgrade to the latest version")) } let mut cmd = cargo(); cmd.args(&["install", "xargo", "-f"]); @@ -278,7 +278,7 @@ fn setup(subcommand: MiriCommand) { } }; if !rust_src.exists() { - show_error(format!("Given Rust source directory `{}` does not exist.", rust_src.display())); + show_error(format!("given Rust source directory `{}` does not exist.", rust_src.display())); } // Next, we need our own libstd. Prepare a xargo project for that purpose. @@ -352,7 +352,7 @@ path = "lib.rs" command.env_remove("RUSTFLAGS"); // Finally run it! if command.status().expect("failed to run xargo").success().not() { - show_error(format!("Failed to run xargo")); + show_error(format!("failed to run xargo")); } // That should be it! But we need to figure out where xargo built stuff. @@ -578,7 +578,7 @@ fn phase_cargo_rustc(args: env::Args) { // Use our custom sysroot. let sysroot = - env::var_os("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); + env::var_os("MIRI_SYSROOT").expect("the wrapper should have set MIRI_SYSROOT"); cmd.arg("--sysroot"); cmd.arg(sysroot); } else { @@ -600,9 +600,9 @@ fn phase_cargo_rustc(args: env::Args) { if emit_link_hack { // Some platforms prepend "lib", some do not... let's just create both files. let filename = out_filename("lib", ".rlib"); - File::create(filename).expect("Failed to create rlib file"); + File::create(filename).expect("failed to create rlib file"); let filename = out_filename("", ".rlib"); - File::create(filename).expect("Failed to create rlib file"); + File::create(filename).expect("failed to create rlib file"); } } @@ -610,10 +610,10 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); let file = File::open(&binary) - .unwrap_or_else(|_| show_error(format!("File {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary))); + .unwrap_or_else(|_| show_error(format!("file {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary))); let file = BufReader::new(file); let info: CrateRunInfo = serde_json::from_reader(file) - .unwrap_or_else(|_| show_error(format!("File {:?} does not contain valid JSON", binary))); + .unwrap_or_else(|_| show_error(format!("file {:?} contains outdated or invalid JSON; try `cargo clean`", binary))); // Set missing env vars. Looks like `build.rs` vars are still set at run-time, but // `CARGO_BIN_EXE_*` are not. This means we can give the run-time environment precedence, @@ -657,7 +657,7 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { } // Set sysroot. let sysroot = - env::var_os("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); + env::var_os("MIRI_SYSROOT").expect("the wrapper should have set MIRI_SYSROOT"); cmd.arg("--sysroot"); cmd.arg(sysroot); // Respect `MIRIFLAGS`. From 18483b4d5e36237f1939903e008ec2c7bb4e8035 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Sep 2020 14:09:43 +0200 Subject: [PATCH 2302/5092] make (not yet actually used) doctest actually use the crate, and fix a comment --- cargo-miri/bin.rs | 2 +- test-cargo-miri/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index ab0c70fc86d1..871478d330cc 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -140,7 +140,7 @@ fn xargo_check() -> Command { Command::new(env::var_os("XARGO_CHECK").unwrap_or_else(|| OsString::from("xargo-check"))) } -/// Execute the command if it fails, fail this process with the same exit code. +/// Execute the command. If it fails, fail this process with the same exit code. /// Otherwise, continue. fn exec(mut cmd: Command) { let exit_status = cmd.status().expect("failed to run command"); diff --git a/test-cargo-miri/src/lib.rs b/test-cargo-miri/src/lib.rs index 064954ba9800..4e2c8b572c77 100644 --- a/test-cargo-miri/src/lib.rs +++ b/test-cargo-miri/src/lib.rs @@ -1,6 +1,6 @@ /// Doc-test test /// ```rust -/// assert!(true); +/// assert!(cargo_miri_test::make_true()); /// ``` pub fn make_true() -> bool { true From 05f5c3d0783cfda72562373599eb1976f384e14e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Sep 2020 14:24:56 +0200 Subject: [PATCH 2303/5092] make sure tests pass even with RUST_TEST_NOCAPTURE set --- test-cargo-miri/run-test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index bbb8df9059ac..e7c341a1f040 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -102,6 +102,7 @@ def test_cargo_miri_test(): ) os.chdir(os.path.dirname(os.path.realpath(__file__))) +os.environ["RUST_TEST_NOCAPTURE"] = "0" # this affects test output, so make sure it is not set target_str = " for target {}".format(os.environ['MIRI_TEST_TARGET']) if 'MIRI_TEST_TARGET' in os.environ else "" print(CGREEN + CBOLD + "## Running `cargo miri` tests{}".format(target_str) + CEND) From db067f4a3e611002b3b2b9cea9b2b65a2edb7385 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Sep 2020 16:01:33 +0200 Subject: [PATCH 2304/5092] test-cargo-miri: normalize slashes before comparing paths --- test-cargo-miri/src/main.rs | 7 +++++-- test-cargo-miri/subcrate/main.rs | 11 ++++++++--- test-cargo-miri/subcrate/test.rs | 8 +++++--- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index 5f311441bfaf..43b507e9c9aa 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -1,6 +1,5 @@ use byteorder::{BigEndian, ByteOrder}; use std::env; -use std::path::PathBuf; #[cfg(unix)] use std::io::{self, BufRead}; @@ -21,8 +20,12 @@ fn main() { // If there were no arguments, access stdin and test working dir. if std::env::args().len() <= 1 { + // CWD should be crate root. + // We have to normalize slashes, as the env var might be set for a different target's conventions. let env_dir = env::current_dir().unwrap(); - let crate_dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()); + let env_dir = env_dir.to_string_lossy().replace("\\", "/"); + let crate_dir = env::var_os("CARGO_MANIFEST_DIR").unwrap(); + let crate_dir = crate_dir.to_string_lossy().replace("\\", "/"); assert_eq!(env_dir, crate_dir); #[cfg(unix)] diff --git a/test-cargo-miri/subcrate/main.rs b/test-cargo-miri/subcrate/main.rs index db8ea7eb1855..4ce80b370722 100644 --- a/test-cargo-miri/subcrate/main.rs +++ b/test-cargo-miri/subcrate/main.rs @@ -4,8 +4,13 @@ use std::path::PathBuf; fn main() { println!("subcrate running"); - let env_dir = env::current_dir().unwrap(); - let crate_dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()); // CWD should be workspace root, i.e., one level up from crate root. - assert_eq!(env_dir, crate_dir.parent().unwrap()); + // We have to normalize slashes, as the env var might be set for a different target's conventions. + let env_dir = env::current_dir().unwrap(); + let env_dir = env_dir.to_string_lossy().replace("\\", "/"); + let crate_dir = env::var_os("CARGO_MANIFEST_DIR").unwrap(); + let crate_dir = crate_dir.to_string_lossy().replace("\\", "/"); + let crate_dir = PathBuf::from(crate_dir); + let crate_dir = crate_dir.parent().unwrap().to_string_lossy(); + assert_eq!(env_dir, crate_dir); } diff --git a/test-cargo-miri/subcrate/test.rs b/test-cargo-miri/subcrate/test.rs index 16c63411ce84..0fd26059a1d3 100644 --- a/test-cargo-miri/subcrate/test.rs +++ b/test-cargo-miri/subcrate/test.rs @@ -1,11 +1,13 @@ use std::env; -use std::path::PathBuf; fn main() { println!("subcrate testing"); - let env_dir = env::current_dir().unwrap(); - let crate_dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()); // CWD should be crate root. + // We have to normalize slashes, as the env var might be set for a different target's conventions. + let env_dir = env::current_dir().unwrap(); + let env_dir = env_dir.to_string_lossy().replace("\\", "/"); + let crate_dir = env::var_os("CARGO_MANIFEST_DIR").unwrap(); + let crate_dir = crate_dir.to_string_lossy().replace("\\", "/"); assert_eq!(env_dir, crate_dir); } From ae859c3f7be2fe63ebb96dc5cba3c635b81da65b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 16 Sep 2020 19:54:52 +0200 Subject: [PATCH 2305/5092] add comment mentioning alternative approach --- cargo-miri/bin.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 871478d330cc..522570626d09 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -397,6 +397,11 @@ fn phase_cargo_miri(mut args: env::Args) { setup(subcommand); // Invoke actual cargo for the job, but with different flags. + // We re-use `cargo test` and `cargo run`, which makes target and binary handling very easy but + // requires some extra work to make the build check-only (see all the `--emit` hacks below). + // describes an alternative + // approach that uses `cargo check`, making that part easier but target and binary handling + // harder. let miri_path = std::env::current_exe().expect("current executable path invalid"); let cargo_cmd = match subcommand { MiriCommand::Test => "test", From 3163242ff1eb5c827cc92ad90211869273bed4bd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 17 Sep 2020 17:42:52 +0200 Subject: [PATCH 2306/5092] rustup; no need to special-case the guaranteed_eq/ne intrinsics any more --- rust-version | 2 +- src/shims/intrinsics.rs | 11 ++--------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/rust-version b/rust-version index 8e33b80ff68f..d8673b921164 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a1894e4afe1a39f718cc27232a5a2f0d02b501f6 +7bdb5dee7bac15458b10b148e9e24968e633053e diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 4d8801f17887..6051ad482e51 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -8,7 +8,6 @@ use rustc_middle::{mir, ty}; use rustc_middle::ty::layout::IntegerExt; use rustc_apfloat::{Float, Round}; use rustc_target::abi::{Align, Integer, LayoutOf}; -use rustc_span::symbol::sym; use crate::*; use helpers::check_arg_count; @@ -23,19 +22,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _unwind: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let intrinsic_name = this.tcx.item_name(instance.def_id()); - // We want to overwrite some of the intrinsic implementations that CTFE uses. - let prefer_miri_intrinsic = match intrinsic_name { - sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => true, - _ => false, - }; - if !prefer_miri_intrinsic && this.emulate_intrinsic(instance, args, ret)? { + if this.emulate_intrinsic(instance, args, ret)? { return Ok(()); } // All supported intrinsics have a return place. - let intrinsic_name = &*intrinsic_name.as_str(); + let intrinsic_name = &*this.tcx.item_name(instance.def_id()).as_str(); let (dest, ret) = match ret { None => throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name), Some(p) => p, From e9e67c97cc7b8d242042051d81e97eea6482ce48 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 17 Sep 2020 20:08:18 +0200 Subject: [PATCH 2307/5092] cargo update main crates --- Cargo.lock | 129 +++++++++++++++++++++--------------------- cargo-miri/Cargo.lock | 100 +++++++++++++++++--------------- 2 files changed, 117 insertions(+), 112 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d09ec19af652..4cf2b62006f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,18 +2,18 @@ # It is not intended for manual editing. [[package]] name = "aho-corasick" -version = "0.7.10" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" +checksum = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86" dependencies = [ "memchr", ] [[package]] name = "anyhow" -version = "1.0.28" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9a60d744a80c30fcb657dfe2c1b22bcb3e814c1a1e3674f32bf5820b570fbff" +checksum = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b" [[package]] name = "arrayref" @@ -40,15 +40,15 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "base64" -version = "0.11.0" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" [[package]] name = "blake2b_simd" @@ -135,11 +135,10 @@ dependencies = [ [[package]] name = "dirs-sys" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" +checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a" dependencies = [ - "cfg-if", "libc", "redox_users", "winapi", @@ -160,9 +159,9 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.9" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f59efc38004c988e4201d11d263b8171f49a2e7ec0bdbb71773433f271504a5e" +checksum = "3ed85775dcc68644b5c950ac06a2b23768d3bc9390464151aaf27136998dcf9e" dependencies = [ "cfg-if", "libc", @@ -181,9 +180,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" dependencies = [ "cfg-if", "libc", @@ -192,9 +191,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.10" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" +checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" dependencies = [ "libc", ] @@ -216,9 +215,9 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" +checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" [[package]] name = "lazy_static" @@ -228,15 +227,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.68" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" +checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" [[package]] name = "log" -version = "0.4.8" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" dependencies = [ "cfg-if", ] @@ -249,9 +248,9 @@ checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" [[package]] name = "miow" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226" +checksum = "07b88fb9795d4d36d62a012dfbf49a8f5cf12751f36d31a9dbe66d528e58979e" dependencies = [ "socket2", "winapi", @@ -276,15 +275,15 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.6" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" +checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" [[package]] name = "proc-macro2" -version = "1.0.10" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3" +checksum = "36e28516df94f3dd551a587da5357459d9b36d945a7c37c3557928c1c2ff2a2c" dependencies = [ "unicode-xid", ] @@ -297,9 +296,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.3" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" +checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" dependencies = [ "proc-macro2", ] @@ -347,15 +346,15 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.1.56" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" [[package]] name = "redox_users" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" +checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" dependencies = [ "getrandom", "redox_syscall", @@ -364,9 +363,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.3.6" +version = "1.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6946991529684867e47d86474e3a6d0c0ab9b82d5821e314b1ede31fa3a4b3" +checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" dependencies = [ "aho-corasick", "memchr", @@ -376,24 +375,24 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.17" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae" +checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" [[package]] name = "remove_dir_all" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" dependencies = [ "winapi", ] [[package]] name = "rust-argon2" -version = "0.7.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" +checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19" dependencies = [ "base64", "blake2b_simd", @@ -430,9 +429,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.3" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "535622e6be132bccd223f4bb2b8ac8d53cda3c7a6394944d3b2b33fb974f9d76" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "semver" @@ -451,18 +450,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.106" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399" +checksum = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.106" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c" +checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" dependencies = [ "proc-macro2", "quote", @@ -471,9 +470,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.51" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da07b57ee2623368351e9a0488bb0b261322a15a6e0ae53e243cbdc0f4208da9" +checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c" dependencies = [ "itoa", "ryu", @@ -482,15 +481,15 @@ dependencies = [ [[package]] name = "shell-escape" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9" +checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" [[package]] name = "socket2" -version = "0.3.12" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" +checksum = "b1fa70dc5c8104ec096f4fe7ede7a221d35ae13dcd19ba1ad9a81d2cab9a1c44" dependencies = [ "cfg-if", "libc", @@ -500,9 +499,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.17" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" +checksum = "6690e3e9f692504b941dc6c3b188fd28df054f7fb8469ab40680df52fdcc842b" dependencies = [ "proc-macro2", "quote", @@ -564,15 +563,15 @@ dependencies = [ [[package]] name = "unicode-width" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" [[package]] name = "unicode-xid" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" [[package]] name = "wasi" @@ -582,9 +581,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "winapi" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", @@ -598,9 +597,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa515c5163a99cc82bab70fd3bfdd36d827be85de63737b40fcef2ce084a436e" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ "winapi", ] diff --git a/cargo-miri/Cargo.lock b/cargo-miri/Cargo.lock index bb3b05db03a4..4053bfbcc46e 100644 --- a/cargo-miri/Cargo.lock +++ b/cargo-miri/Cargo.lock @@ -14,15 +14,15 @@ checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" [[package]] name = "autocfg" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "base64" -version = "0.11.0" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" [[package]] name = "bitflags" @@ -61,9 +61,9 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "chrono" -version = "0.4.11" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" +checksum = "942f72db697d8767c22d46a598e01f2d3b475501ea43d0db4f16d90259182d0b" dependencies = [ "num-integer", "num-traits", @@ -99,11 +99,10 @@ dependencies = [ [[package]] name = "dirs-sys" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" +checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a" dependencies = [ - "cfg-if", "libc", "redox_users", "winapi", @@ -111,20 +110,20 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.9.0+wasi-snapshot-preview1", ] [[package]] name = "itoa" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" +checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" [[package]] name = "lazy_static" @@ -134,15 +133,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.70" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3baa92041a6fec78c687fa0cc2b3fae8884f743d672cf551bed1d6dac6988d0f" +checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" [[package]] name = "num-integer" -version = "0.1.42" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" +checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b" dependencies = [ "autocfg", "num-traits", @@ -150,42 +149,42 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" +checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" dependencies = [ "autocfg", ] [[package]] name = "proc-macro2" -version = "1.0.13" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53f5ffe53a6b28e37c9c1ce74893477864d64f74778a93a4beb43c8fa167f639" +checksum = "36e28516df94f3dd551a587da5357459d9b36d945a7c37c3557928c1c2ff2a2c" dependencies = [ "unicode-xid", ] [[package]] name = "quote" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea" +checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" -version = "0.1.56" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" [[package]] name = "redox_users" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" +checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" dependencies = [ "getrandom", "redox_syscall", @@ -194,9 +193,9 @@ dependencies = [ [[package]] name = "rust-argon2" -version = "0.7.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" +checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19" dependencies = [ "base64", "blake2b_simd", @@ -221,9 +220,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed3d612bc64430efeb3f7ee6ef26d590dce0c43249217bddc62112540c7941e1" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "semver" @@ -242,18 +241,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.110" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99e7b308464d16b56eba9964e4972a3eee817760ab60d88c3f86e1fecb08204c" +checksum = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.110" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "818fbf6bfa9a42d3bfcaca148547aa00c7b915bec71d1757aa2d44ca68771984" +checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" dependencies = [ "proc-macro2", "quote", @@ -262,9 +261,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.53" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "993948e75b189211a9b31a7528f950c6adc21f9720b6438ff80a7fa2f864cea2" +checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c" dependencies = [ "itoa", "ryu", @@ -273,9 +272,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.23" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95b5f192649e48a5302a13f2feb224df883b98933222369e4b3b0fe2a5447269" +checksum = "6690e3e9f692504b941dc6c3b188fd28df054f7fb8469ab40680df52fdcc842b" dependencies = [ "proc-macro2", "quote", @@ -284,19 +283,20 @@ dependencies = [ [[package]] name = "time" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ "libc", + "wasi 0.10.0+wasi-snapshot-preview1", "winapi", ] [[package]] name = "unicode-xid" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" [[package]] name = "vergen" @@ -315,10 +315,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] -name = "winapi" -version = "0.3.8" +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", From 055e90dd6f912ebb7746c23da56f139c958aaac1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 18 Sep 2020 12:12:02 +0200 Subject: [PATCH 2308/5092] 'cargo update' test-cargo-miri --- test-cargo-miri/Cargo.lock | 24 +++++++++++++----------- test-cargo-miri/Cargo.toml | 1 - test-cargo-miri/src/main.rs | 3 ++- test-cargo-miri/subcrate/Cargo.toml | 3 +++ test-cargo-miri/subcrate/test.rs | 3 +++ test-cargo-miri/test.stdout.ref1 | 6 +++--- test-cargo-miri/test.stdout.ref2 | 2 +- test-cargo-miri/test.stdout.ref3 | 5 ++--- test-cargo-miri/tests/test.rs | 5 ----- 9 files changed, 27 insertions(+), 25 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 6bc70135a898..8ea88fbb828d 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -11,7 +11,6 @@ name = "cargo-miri-test" version = "0.1.0" dependencies = [ "byteorder", - "num_cpus", "rand", ] @@ -23,9 +22,9 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "getrandom" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" dependencies = [ "cfg-if", "libc", @@ -34,24 +33,24 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.10" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" +checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" dependencies = [ "libc", ] [[package]] name = "libc" -version = "0.2.68" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" +checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" [[package]] name = "num_cpus" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" dependencies = [ "hermit-abi", "libc", @@ -59,9 +58,9 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.6" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" +checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" [[package]] name = "rand" @@ -117,6 +116,9 @@ dependencies = [ [[package]] name = "subcrate" version = "0.1.0" +dependencies = [ + "num_cpus", +] [[package]] name = "wasi" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 4900ce9675d6..b2a1612ffadf 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -12,7 +12,6 @@ byteorder = "1.0" [dev-dependencies] rand = { version = "0.7", features = ["small_rng"] } -num_cpus = "1.10.1" [lib] test = false # test that this is respected (will show in the output) diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index 43b507e9c9aa..16b173b287ca 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -19,6 +19,7 @@ fn main() { } // If there were no arguments, access stdin and test working dir. + // (We rely on the test runner to always disable isolation when passing no arguments.) if std::env::args().len() <= 1 { // CWD should be crate root. // We have to normalize slashes, as the env var might be set for a different target's conventions. @@ -33,7 +34,7 @@ fn main() { let num: i32 = line.unwrap().parse().unwrap(); println!("{}", 2*num); } - // On non-Unix, reading from stdin is not support. So we hard-code the right answer. + // On non-Unix, reading from stdin is not supported. So we hard-code the right answer. #[cfg(not(unix))] { println!("24"); diff --git a/test-cargo-miri/subcrate/Cargo.toml b/test-cargo-miri/subcrate/Cargo.toml index 78552e6aedf0..be27f88ad9a1 100644 --- a/test-cargo-miri/subcrate/Cargo.toml +++ b/test-cargo-miri/subcrate/Cargo.toml @@ -12,3 +12,6 @@ path = "main.rs" name = "subtest" path = "test.rs" harness = false + +[dev-dependencies] +num_cpus = "1.10.1" diff --git a/test-cargo-miri/subcrate/test.rs b/test-cargo-miri/subcrate/test.rs index 0fd26059a1d3..fdab9402813b 100644 --- a/test-cargo-miri/subcrate/test.rs +++ b/test-cargo-miri/subcrate/test.rs @@ -10,4 +10,7 @@ fn main() { let crate_dir = env::var_os("CARGO_MANIFEST_DIR").unwrap(); let crate_dir = crate_dir.to_string_lossy().replace("\\", "/"); assert_eq!(env_dir, crate_dir); + + // Make sure we can call `num_cpus`. + num_cpus::get(); } diff --git a/test-cargo-miri/test.stdout.ref1 b/test-cargo-miri/test.stdout.ref1 index 1eb18fe88768..7079798e42fe 100644 --- a/test-cargo-miri/test.stdout.ref1 +++ b/test-cargo-miri/test.stdout.ref1 @@ -4,7 +4,7 @@ running 1 test test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out -running 8 tests -..i..... -test result: ok. 7 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out +running 7 tests +..i.... +test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/test.stdout.ref2 b/test-cargo-miri/test.stdout.ref2 index d426bdf6db63..37efb8c3ee89 100644 --- a/test-cargo-miri/test.stdout.ref2 +++ b/test-cargo-miri/test.stdout.ref2 @@ -7,5 +7,5 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out running 1 test test simple1 ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 7 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out diff --git a/test-cargo-miri/test.stdout.ref3 b/test-cargo-miri/test.stdout.ref3 index 32bbcf9bf275..893e52e87774 100644 --- a/test-cargo-miri/test.stdout.ref3 +++ b/test-cargo-miri/test.stdout.ref3 @@ -1,13 +1,12 @@ -running 8 tests +running 7 tests test cargo_env ... ok test do_panic ... ok test does_not_work_on_miri ... ignored test entropy_rng ... ok test fail_index_check ... ok -test num_cpus ... ok test simple1 ... ok test simple2 ... ok -test result: ok. 7 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out +test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 35e05368803a..436e919e050d 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -37,11 +37,6 @@ fn entropy_rng() { let _val = rng.gen::(); } -#[test] -fn num_cpus() { - assert_eq!(num_cpus::get(), 1); -} - #[test] fn cargo_env() { assert_eq!(env!("CARGO_PKG_NAME"), "cargo-miri-test"); From 6be8761e4717ae9b3810cf6a9ce70afa952142e3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 18 Sep 2020 12:17:09 +0200 Subject: [PATCH 2309/5092] update for major version bumps --- Cargo.lock | 23 +++++++++++++++++------ Cargo.toml | 4 ++-- cargo-miri/Cargo.lock | 5 ++--- cargo-miri/Cargo.toml | 2 +- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4cf2b62006f8..8c73cb05535c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -69,9 +69,9 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "colored" -version = "1.9.3" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" dependencies = [ "atty", "lazy_static", @@ -189,6 +189,17 @@ dependencies = [ "wasi", ] +[[package]] +name = "getrandom" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "hermit-abi" version = "0.1.15" @@ -263,7 +274,7 @@ dependencies = [ "colored", "compiletest_rs", "env_logger", - "getrandom", + "getrandom 0.2.0", "hex", "libc", "log", @@ -309,7 +320,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom", + "getrandom 0.1.15", "libc", "rand_chacha", "rand_core", @@ -332,7 +343,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom", + "getrandom 0.1.15", ] [[package]] @@ -356,7 +367,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" dependencies = [ - "getrandom", + "getrandom 0.1.15", "redox_syscall", "rust-argon2", ] diff --git a/Cargo.toml b/Cargo.toml index 89f568146e07..c36a97bb0a1a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ doctest = false # and no doc tests required-features = ["rustc_tests"] [dependencies] -getrandom = { version = "0.1.8", features = ["std"] } +getrandom = { version = "0.2", features = ["std"] } env_logger = "0.7.1" log = "0.4" shell-escape = "0.1.4" @@ -44,7 +44,7 @@ libc = "0.2" [dev-dependencies] compiletest_rs = { version = "0.5", features = ["tmp"] } rustc_version = "0.2.3" -colored = "1.6" +colored = "2" [features] rustc_tests = [] diff --git a/cargo-miri/Cargo.lock b/cargo-miri/Cargo.lock index 4053bfbcc46e..54472947b691 100644 --- a/cargo-miri/Cargo.lock +++ b/cargo-miri/Cargo.lock @@ -89,11 +89,10 @@ dependencies = [ [[package]] name = "directories" -version = "2.0.2" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c" +checksum = "f8fed639d60b58d0f53498ab13d26f621fd77569cc6edb031f4cc36a2ad9da0f" dependencies = [ - "cfg-if", "dirs-sys", ] diff --git a/cargo-miri/Cargo.toml b/cargo-miri/Cargo.toml index 2de581c1c2e2..8233c5c24f83 100644 --- a/cargo-miri/Cargo.toml +++ b/cargo-miri/Cargo.toml @@ -14,7 +14,7 @@ test = false # we have no unit tests doctest = false # and no doc tests [dependencies] -directories = "2.0" +directories = "3" rustc_version = "0.2.3" serde_json = "1.0.40" From 32cdb7131b275c00f6a711e2c0f71d5ae76b67d5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 18 Sep 2020 13:10:18 +0200 Subject: [PATCH 2310/5092] support panic=abort --- README.md | 2 + cargo-miri/bin.rs | 48 ++++++++++++++++++------ src/shims/foreign_items.rs | 18 +++++---- src/shims/panic.rs | 2 + tests/compile-fail/panic/panic_abort1.rs | 5 ++- tests/compile-fail/panic/panic_abort2.rs | 4 +- tests/compile-fail/panic/panic_abort3.rs | 4 +- tests/compile-fail/panic/panic_abort4.rs | 4 +- 8 files changed, 59 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 6654de10abff..22823f5bf8bf 100644 --- a/README.md +++ b/README.md @@ -244,6 +244,8 @@ different Miri binaries, and as such worth documenting: * `MIRI_BE_RUSTC` when set to any value tells the Miri driver to actually not interpret the code but compile it like rustc would. This is useful to be sure that the compiled `rlib`s are compatible with Miri. + When set while running `cargo-miri`, it indicates that we are part of a sysroot + build (for which some crates need special treatment). * `MIRI_CWD` when set to any value tells the Miri driver to change to the given directory after loading all the source files, but before commencing interpretation. This is useful if the interpreted program wants a different diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 522570626d09..2eefc105abb7 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -295,8 +295,7 @@ fn setup(subcommand: MiriCommand) { br#" [dependencies.std] default_features = false -# We need the `panic_unwind` feature because we use the `unwind` panic strategy. -# Using `abort` works for libstd, but then libtest will not compile. +# We support unwinding, so enable that panic runtime. features = ["panic_unwind"] [dependencies.test] @@ -338,10 +337,14 @@ path = "lib.rs" // because we still need bootstrap to distinguish between host and target crates. // In that case we overwrite `RUSTC_REAL` instead which determines the rustc used // for target crates. + // We set ourselves (`cargo-miri`) instead of Miri directly to be able to patch the flags + // for `libpanic_abort` (usually this is done by bootstrap but we have to do it ourselves). + // The `MIRI_BE_RUSTC` will mean we dispatch to `phase_setup_rustc`. + let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); if env::var_os("RUSTC_STAGE").is_some() { - command.env("RUSTC_REAL", find_miri()); + command.env("RUSTC_REAL", &cargo_miri_path); } else { - command.env("RUSTC", find_miri()); + command.env("RUSTC", &cargo_miri_path); } command.env("MIRI_BE_RUSTC", "1"); // Make sure there are no other wrappers or flags getting in our way @@ -370,6 +373,21 @@ path = "lib.rs" } } +fn phase_setup_rustc(args: env::Args) { + // Mostly we just forward everything. + // `MIRI_BE_RUST` is already set. + let mut cmd = miri(); + cmd.args(args); + + // Patch the panic runtime for `libpanic_abort` (mirroring what bootstrap usually does). + if get_arg_flag_value("--crate-name").as_deref() == Some("panic_abort") { + cmd.arg("-C").arg("panic=abort"); + } + + // Run it! + exec(cmd); +} + fn phase_cargo_miri(mut args: env::Args) { // Check for version and help flags even when invoked as `cargo-miri`. if has_arg_flag("--help") || has_arg_flag("-h") { @@ -402,7 +420,7 @@ fn phase_cargo_miri(mut args: env::Args) { // describes an alternative // approach that uses `cargo check`, making that part easier but target and binary handling // harder. - let miri_path = std::env::current_exe().expect("current executable path invalid"); + let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); let cargo_cmd = match subcommand { MiriCommand::Test => "test", MiriCommand::Run => "run", @@ -470,22 +488,22 @@ fn phase_cargo_miri(mut args: env::Args) { if env::var_os("RUSTC_WRAPPER").is_some() { println!("WARNING: Ignoring `RUSTC_WRAPPER` environment variable, Miri does not support wrapping."); } - cmd.env("RUSTC_WRAPPER", &miri_path); - if verbose { - eprintln!("+ RUSTC_WRAPPER={:?}", miri_path); - } + cmd.env("RUSTC_WRAPPER", &cargo_miri_path); // Set the runner for the current target to us as well, so we can interpret the binaries. let runner_env_name = format!("CARGO_TARGET_{}_RUNNER", target.to_uppercase().replace('-', "_")); - cmd.env(runner_env_name, &miri_path); + cmd.env(&runner_env_name, &cargo_miri_path); // Set rustdoc to us as well, so we can make it do nothing (see issue #584). - cmd.env("RUSTDOC", &miri_path); + cmd.env("RUSTDOC", &cargo_miri_path); // Run cargo. if verbose { - cmd.env("MIRI_VERBOSE", ""); // This makes the other phases verbose. + eprintln!("[cargo-miri miri] RUSTC_WRAPPER={:?}", cargo_miri_path); + eprintln!("[cargo-miri miri] {}={:?}", runner_env_name, cargo_miri_path); + eprintln!("[cargo-miri miri] RUSTDOC={:?}", cargo_miri_path); eprintln!("[cargo-miri miri] {:?}", cmd); + cmd.env("MIRI_VERBOSE", ""); // This makes the other phases verbose. } exec(cmd) } @@ -699,6 +717,12 @@ fn main() { // Skip binary name. args.next().unwrap(); + // Dispatch running as part of sysroot compilation. + if env::var_os("MIRI_BE_RUSTC").is_some() { + phase_setup_rustc(args); + return; + } + // Dispatch to `cargo-miri` phase. There are three phases: // - When we are called via `cargo miri`, we run as the frontend and invoke the underlying // cargo. We set RUSTC_WRAPPER and CARGO_TARGET_RUNNER to ourselves. diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 355801eb8ffb..a2ff39d0b4e9 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -4,7 +4,7 @@ use log::trace; use rustc_hir::def_id::DefId; use rustc_middle::{mir, ty}; -use rustc_target::abi::{Align, Size}; +use rustc_target::{abi::{Align, Size}, spec::PanicStrategy}; use rustc_apfloat::Float; use rustc_span::symbol::sym; @@ -146,6 +146,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let code = this.read_scalar(code)?.to_i32()?; throw_machine_stop!(TerminationInfo::Exit(code.into())); } + "abort" => { + throw_machine_stop!(TerminationInfo::Abort(None)) + } _ => throw_unsup_format!("can't call (diverging) foreign function: {}", link_name), }, Some(p) => p, @@ -160,13 +163,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Normally, this will be either `libpanic_unwind` or `libpanic_abort`, but it could // also be a custom user-provided implementation via `#![feature(panic_runtime)]` "__rust_start_panic" | "__rust_panic_cleanup"=> { - // FIXME we might want to cache this... but it's not really performance-critical. - let panic_runtime = tcx - .crates() - .iter() - .find(|cnum| tcx.is_panic_runtime(**cnum)) - .expect("No panic runtime found!"); - let panic_runtime = tcx.crate_name(*panic_runtime); + // This replicates some of the logic in `inject_panic_runtime`. + // FIXME: is there a way to reuse that logic? + let panic_runtime = match this.tcx.sess.panic_strategy() { + PanicStrategy::Unwind => sym::panic_unwind, + PanicStrategy::Abort => sym::panic_abort, + }; let start_panic_instance = this.resolve_path(&[&*panic_runtime.as_str(), link_name]); return Ok(Some(&*this.load_mir(start_panic_instance.def, None)?)); diff --git a/src/shims/panic.rs b/src/shims/panic.rs index f907b76b679c..52d27a1bb5c2 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -44,6 +44,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); trace!("miri_start_panic: {:?}", this.frame().instance); + // Make sure we only start unwinding when this matches our panic strategy. + assert_eq!(this.tcx.sess.panic_strategy(), PanicStrategy::Unwind); // Get the raw pointer stored in arg[0] (the panic payload). let &[payload] = check_arg_count(args)?; diff --git a/tests/compile-fail/panic/panic_abort1.rs b/tests/compile-fail/panic/panic_abort1.rs index 4a1bb11483ca..ee1d5b312d54 100644 --- a/tests/compile-fail/panic/panic_abort1.rs +++ b/tests/compile-fail/panic/panic_abort1.rs @@ -1,6 +1,7 @@ -// ignore-test: Abort panics are not yet supported -// error-pattern: the evaluated program panicked +// error-pattern: the evaluated program aborted execution // compile-flags: -C panic=abort +// ignore-windows: windows panics via inline assembly (FIXME) + fn main() { std::panic!("panicking from libstd"); } diff --git a/tests/compile-fail/panic/panic_abort2.rs b/tests/compile-fail/panic/panic_abort2.rs index ce4471c0effc..4c08ab4ddcb7 100644 --- a/tests/compile-fail/panic/panic_abort2.rs +++ b/tests/compile-fail/panic/panic_abort2.rs @@ -1,6 +1,6 @@ -// ignore-test: Abort panics are not yet supported -// error-pattern: the evaluated program panicked +// error-pattern: the evaluated program aborted execution // compile-flags: -C panic=abort +// ignore-windows: windows panics via inline assembly (FIXME) fn main() { std::panic!("{}-panicking from libstd", 42); diff --git a/tests/compile-fail/panic/panic_abort3.rs b/tests/compile-fail/panic/panic_abort3.rs index 842a0f5435b7..81a603d5e369 100644 --- a/tests/compile-fail/panic/panic_abort3.rs +++ b/tests/compile-fail/panic/panic_abort3.rs @@ -1,6 +1,6 @@ -// ignore-test: Abort panics are not yet supported -//error-pattern: the evaluated program panicked +// error-pattern: the evaluated program aborted execution // compile-flags: -C panic=abort +// ignore-windows: windows panics via inline assembly (FIXME) fn main() { core::panic!("panicking from libcore"); diff --git a/tests/compile-fail/panic/panic_abort4.rs b/tests/compile-fail/panic/panic_abort4.rs index 816cc90cfabd..d015316ef263 100644 --- a/tests/compile-fail/panic/panic_abort4.rs +++ b/tests/compile-fail/panic/panic_abort4.rs @@ -1,6 +1,6 @@ -// ignore-test: Abort panics are not yet supported -//error-pattern: the evaluated program panicked +// error-pattern: the evaluated program aborted execution // compile-flags: -C panic=abort +// ignore-windows: windows panics via inline assembly (FIXME) fn main() { core::panic!("{}-panicking from libcore", 42); From 97a71c0c777fa5873aca866a9a8f4adfab48feef Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 18 Sep 2020 13:34:25 +0200 Subject: [PATCH 2311/5092] fmt Co-authored-by: Oli Scherer --- src/shims/foreign_items.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index a2ff39d0b4e9..5bcbd797ca3c 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -162,7 +162,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We forward this to the underlying *implementation* in the panic runtime crate. // Normally, this will be either `libpanic_unwind` or `libpanic_abort`, but it could // also be a custom user-provided implementation via `#![feature(panic_runtime)]` - "__rust_start_panic" | "__rust_panic_cleanup"=> { + "__rust_start_panic" | "__rust_panic_cleanup" => { // This replicates some of the logic in `inject_panic_runtime`. // FIXME: is there a way to reuse that logic? let panic_runtime = match this.tcx.sess.panic_strategy() { From 5652052e23d16a0c56d5d95a2b2f42ecd48c042f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 19 Sep 2020 11:37:56 +0200 Subject: [PATCH 2312/5092] list two more aliasing problems we found in BTreeMap and VecDeque --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 22823f5bf8bf..657ea096e6c8 100644 --- a/README.md +++ b/README.md @@ -330,9 +330,9 @@ Definite bugs found: Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): -* [`VecDeque` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/56161) -* [`BTreeMap` creating mutable references that overlap with shared references](https://github.com/rust-lang/rust/pull/58431) -* [`LinkedList` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/60072) +* [`VecDeque::drain` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/56161) +* [`BTreeMap` iterators creating mutable references that overlap with shared references](https://github.com/rust-lang/rust/pull/58431) +* [`LinkedList` cursor insertion creating overlapping mutable references](https://github.com/rust-lang/rust/pull/60072) * [`Vec::push` invalidating existing references into the vector](https://github.com/rust-lang/rust/issues/60847) * [`align_to_mut` violating uniqueness of mutable references](https://github.com/rust-lang/rust/issues/68549) * [`sized-chunks` creating aliasing mutable references](https://github.com/bodil/sized-chunks/issues/8) @@ -341,6 +341,8 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [ink! creating overlapping mutable references](https://github.com/rust-lang/miri/issues/1364) * [TiKV creating overlapping mutable reference and raw pointer](https://github.com/tikv/tikv/pull/7709) * [Windows `Env` iterator creating `*const T` from `&T` to read memory outside of `T`](https://github.com/rust-lang/rust/pull/70479) +* [`BTreeMap::iter_mut` creating overlapping mutable references](https://github.com/rust-lang/rust/issues/73915) +* [`VecDeque::iter_mut` creating overlapping mutable references](https://github.com/rust-lang/rust/issues/74029) ## License From 83a339e5a9cdb9efce75e6c0ed90d630fd4eaf85 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 20 Sep 2020 10:26:22 +0200 Subject: [PATCH 2313/5092] rustup; make sure the iterator moves even with smarter optimizations --- rust-version | 2 +- tests/compile-fail/generator-pinned-moved.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index d8673b921164..37be5591da6e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7bdb5dee7bac15458b10b148e9e24968e633053e +a3bc0e752fad96f537b73f4e9bc805a73d404f7b diff --git a/tests/compile-fail/generator-pinned-moved.rs b/tests/compile-fail/generator-pinned-moved.rs index 8f873f37a5f8..e0ce5cb7333a 100644 --- a/tests/compile-fail/generator-pinned-moved.rs +++ b/tests/compile-fail/generator-pinned-moved.rs @@ -34,10 +34,10 @@ where fn main() { let mut generator_iterator_2 = { - let mut generator_iterator = GeneratorIteratorAdapter(firstn()); + let mut generator_iterator = Box::new(GeneratorIteratorAdapter(firstn())); generator_iterator.next(); // pin it - generator_iterator // move it + Box::new(*generator_iterator) // move it }; // *deallocate* generator_iterator generator_iterator_2.next(); // and use moved value From 08e076c658f0c42071c278bf35695e30273bed93 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 20 Sep 2020 12:02:04 +0200 Subject: [PATCH 2314/5092] account for mir-opts masking more errors --- tests/compile-fail/storage_dead_dangling.rs | 4 ++-- tests/compile-fail/validity/transmute_through_ptr.rs | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/compile-fail/storage_dead_dangling.rs b/tests/compile-fail/storage_dead_dangling.rs index bf2503917ccb..ad8e05537e1a 100644 --- a/tests/compile-fail/storage_dead_dangling.rs +++ b/tests/compile-fail/storage_dead_dangling.rs @@ -1,5 +1,5 @@ -// This should fail even without validation -// compile-flags: -Zmiri-disable-validation +// This should fail even without validation, but some MIR opts mask the error +// compile-flags: -Zmiri-disable-validation -Zmir-opt-level=0 static mut LEAK: usize = 0; diff --git a/tests/compile-fail/validity/transmute_through_ptr.rs b/tests/compile-fail/validity/transmute_through_ptr.rs index 6a88fdaea1ee..0ef69efb86e6 100644 --- a/tests/compile-fail/validity/transmute_through_ptr.rs +++ b/tests/compile-fail/validity/transmute_through_ptr.rs @@ -1,4 +1,5 @@ #[repr(u32)] +#[derive(Debug)] enum Bool { True } fn evil(x: &mut Bool) { @@ -9,6 +10,7 @@ fn evil(x: &mut Bool) { fn main() { let mut x = Bool::True; evil(&mut x); - let _y = x; // reading this ought to be enough to trigger validation + let y = x; // reading this ought to be enough to trigger validation //~^ ERROR encountered 0x0000002c at ., but expected a valid enum tag + println!("{:?}", y); // make sure it is used (and not optimized away) } From b0baa151b29d59b7bc6d7917503774a2416a5b4c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 20 Sep 2020 13:13:57 +0200 Subject: [PATCH 2315/5092] rustup --- rust-version | 2 +- src/helpers.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 37be5591da6e..3126a8a9128d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a3bc0e752fad96f537b73f4e9bc805a73d404f7b +5e449b9adff463455743291b0c1f76feec092992 diff --git a/src/helpers.rs b/src/helpers.rs index 5bb620b563d3..abf128ff3e2d 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -59,7 +59,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let instance = this.resolve_path(path); let cid = GlobalId { instance, promoted: None }; - let const_val = this.const_eval_raw(cid)?; + let const_val = this.eval_to_allocation(cid)?; let const_val = this.read_scalar(const_val.into())?; return Ok(const_val); } From 4b5e78052a030783a609ea0d9c5ad401261fc44d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 20 Sep 2020 15:55:36 +0200 Subject: [PATCH 2316/5092] rustup; support panic=abort on Windows --- rust-version | 2 +- tests/compile-fail/panic/panic_abort1.rs | 1 - tests/compile-fail/panic/panic_abort2.rs | 1 - tests/compile-fail/panic/panic_abort3.rs | 1 - tests/compile-fail/panic/panic_abort4.rs | 1 - 5 files changed, 1 insertion(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 3126a8a9128d..92bdd16b2be6 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -5e449b9adff463455743291b0c1f76feec092992 +41507ed0d57eba71adc20a021a19b64322162f04 diff --git a/tests/compile-fail/panic/panic_abort1.rs b/tests/compile-fail/panic/panic_abort1.rs index ee1d5b312d54..02f8f25880f3 100644 --- a/tests/compile-fail/panic/panic_abort1.rs +++ b/tests/compile-fail/panic/panic_abort1.rs @@ -1,6 +1,5 @@ // error-pattern: the evaluated program aborted execution // compile-flags: -C panic=abort -// ignore-windows: windows panics via inline assembly (FIXME) fn main() { std::panic!("panicking from libstd"); diff --git a/tests/compile-fail/panic/panic_abort2.rs b/tests/compile-fail/panic/panic_abort2.rs index 4c08ab4ddcb7..0d6808dd22e0 100644 --- a/tests/compile-fail/panic/panic_abort2.rs +++ b/tests/compile-fail/panic/panic_abort2.rs @@ -1,6 +1,5 @@ // error-pattern: the evaluated program aborted execution // compile-flags: -C panic=abort -// ignore-windows: windows panics via inline assembly (FIXME) fn main() { std::panic!("{}-panicking from libstd", 42); diff --git a/tests/compile-fail/panic/panic_abort3.rs b/tests/compile-fail/panic/panic_abort3.rs index 81a603d5e369..6640a56c0be2 100644 --- a/tests/compile-fail/panic/panic_abort3.rs +++ b/tests/compile-fail/panic/panic_abort3.rs @@ -1,6 +1,5 @@ // error-pattern: the evaluated program aborted execution // compile-flags: -C panic=abort -// ignore-windows: windows panics via inline assembly (FIXME) fn main() { core::panic!("panicking from libcore"); diff --git a/tests/compile-fail/panic/panic_abort4.rs b/tests/compile-fail/panic/panic_abort4.rs index d015316ef263..d39b1794e676 100644 --- a/tests/compile-fail/panic/panic_abort4.rs +++ b/tests/compile-fail/panic/panic_abort4.rs @@ -1,6 +1,5 @@ // error-pattern: the evaluated program aborted execution // compile-flags: -C panic=abort -// ignore-windows: windows panics via inline assembly (FIXME) fn main() { core::panic!("{}-panicking from libcore", 42); From 88b9c2173e71a02731b1e79e7b7a64783784e0ed Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Sep 2020 09:10:04 +0200 Subject: [PATCH 2317/5092] also support old 'cargo miri run -- -- args' style --- cargo-miri/bin.rs | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 2eefc105abb7..bc5738f01d15 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -452,26 +452,28 @@ fn phase_cargo_miri(mut args: env::Args) { // Check if the next argument starts with `-Zmiri`. If yes, we assume // this is an old-style invocation. if let Some(next_arg) = args.next() { - if next_arg.starts_with("-Zmiri") { + if next_arg.starts_with("-Zmiri") || next_arg == "--" { eprintln!( "WARNING: it seems like you are setting Miri's flags in `cargo miri` the old way,\n\ i.e., by passing them after the first `--`. This style is deprecated; please set\n\ the MIRIFLAGS environment variable instead. `cargo miri run/test` now interprets\n\ arguments the exact same way as `cargo run/test`." ); - // Old-style invocation. Turn these into MIRIFLAGS. - let mut miriflags = env::var("MIRIFLAGS").unwrap_or_default(); - miriflags.push(' '); - miriflags.push_str(&next_arg); - while let Some(further_arg) = args.next() { - if further_arg == "--" { - // End of the Miri flags! - break; - } + // Old-style invocation. Turn these into MIRIFLAGS, if there are any. + if next_arg != "--" { + let mut miriflags = env::var("MIRIFLAGS").unwrap_or_default(); miriflags.push(' '); - miriflags.push_str(&further_arg); + miriflags.push_str(&next_arg); + while let Some(further_arg) = args.next() { + if further_arg == "--" { + // End of the Miri flags! + break; + } + miriflags.push(' '); + miriflags.push_str(&further_arg); + } + env::set_var("MIRIFLAGS", miriflags); } - env::set_var("MIRIFLAGS", miriflags); // Pass the remaining flags to cargo. cmd.args(args); break; From 4dda2ad5b49cb64d2413c3a0b5f19e1b66e5db69 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Sep 2020 12:46:18 +0200 Subject: [PATCH 2318/5092] support non-rlib extern files --- cargo-miri/bin.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index bc5738f01d15..5731a9a591f9 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -663,11 +663,16 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { let json_flag = "--json"; while let Some(arg) = args.next() { if arg == extern_flag { + cmd.arg(extern_flag); // always forward flag, but adjust filename // `--extern` is always passed as a separate argument by cargo. let next_arg = args.next().expect("`--extern` should be followed by a filename"); - let next_arg = next_arg.strip_suffix(".rlib").expect("all extern filenames should end in `.rlib`"); - cmd.arg(extern_flag); - cmd.arg(format!("{}.rmeta", next_arg)); + if let Some(next_lib) = next_arg.strip_suffix(".rlib") { + // If this is an rlib, make it an rmeta. + cmd.arg(format!("{}.rmeta", next_lib)); + } else { + // Some other extern file (e.g., a `.so`). Forward unchanged. + cmd.arg(next_arg); + } } else if arg.starts_with(error_format_flag) { let suffix = &arg[error_format_flag.len()..]; assert!(suffix.starts_with('=')); From 0c67ec205723561fe9f7442185e4d62aed0adb10 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Sep 2020 15:47:09 +0200 Subject: [PATCH 2319/5092] test formerly broken serde_derive dependency --- test-cargo-miri/Cargo.lock | 47 ++++++++++++++++++++++++++++++++++++++ test-cargo-miri/Cargo.toml | 1 + 2 files changed, 48 insertions(+) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 8ea88fbb828d..b03347d9f0de 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -12,6 +12,7 @@ version = "0.1.0" dependencies = [ "byteorder", "rand", + "serde_derive", ] [[package]] @@ -62,6 +63,24 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" +[[package]] +name = "proc-macro2" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36e28516df94f3dd551a587da5357459d9b36d945a7c37c3557928c1c2ff2a2c" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +dependencies = [ + "proc-macro2", +] + [[package]] name = "rand" version = "0.7.3" @@ -113,6 +132,17 @@ dependencies = [ "rand_core", ] +[[package]] +name = "serde_derive" +version = "1.0.116" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "subcrate" version = "0.1.0" @@ -120,6 +150,23 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "syn" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6690e3e9f692504b941dc6c3b188fd28df054f7fb8469ab40680df52fdcc842b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index b2a1612ffadf..54a03f5f5ded 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -12,6 +12,7 @@ byteorder = "1.0" [dev-dependencies] rand = { version = "0.7", features = ["small_rng"] } +serde_derive = "1.0" # not actually used, but exercises some unique code path (`--extern` .so file) [lib] test = false # test that this is respected (will show in the output) From dae575c38f0d46e6a3b9144fa223384beddc8cc2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 23 Sep 2020 22:13:13 +0200 Subject: [PATCH 2320/5092] opt-level 3 is clean again :) --- ci.sh | 3 +-- rust-version | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/ci.sh b/ci.sh index 12683a2fccbe..56a6f1228ab5 100755 --- a/ci.sh +++ b/ci.sh @@ -25,8 +25,7 @@ function run_tests { ./miri test --locked if ! [ -n "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with MIR optimizations - # FIXME: only testing level 2 because of . - MIRIFLAGS="-Z mir-opt-level=2" ./miri test --locked + MIRIFLAGS="-Z mir-opt-level=3" ./miri test --locked fi # "miri test" has built the sysroot for us, now this should pass without # any interactive questions. diff --git a/rust-version b/rust-version index 92bdd16b2be6..16a773193d14 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -41507ed0d57eba71adc20a021a19b64322162f04 +a6008fac97f81a3fc51668b0c7fa0e2e6f2a599b From 67c5067a2fa80ce5609ec4dbb833460efeacd30a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 24 Sep 2020 09:19:03 +0200 Subject: [PATCH 2321/5092] rustup; fix tests --- rust-version | 2 +- tests/compile-fail/alloc/deallocate-bad-alignment.rs | 2 +- tests/compile-fail/alloc/deallocate-bad-size.rs | 2 +- tests/compile-fail/alloc/reallocate-bad-size.rs | 2 +- tests/compile-fail/alloc/stack_free.rs | 2 +- tests/run-pass/heap_allocator.rs | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rust-version b/rust-version index 16a773193d14..835708a42baa 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a6008fac97f81a3fc51668b0c7fa0e2e6f2a599b +78a089487b5f6d5e4205ac4500410b442857bced diff --git a/tests/compile-fail/alloc/deallocate-bad-alignment.rs b/tests/compile-fail/alloc/deallocate-bad-alignment.rs index 621c05344b4a..852a0660217e 100644 --- a/tests/compile-fail/alloc/deallocate-bad-alignment.rs +++ b/tests/compile-fail/alloc/deallocate-bad-alignment.rs @@ -1,6 +1,6 @@ use std::alloc::{alloc, dealloc, Layout}; -// error-pattern: allocation has size 1 and alignment 1, but gave size 1 and alignment 2 +// error-pattern: has size 1 and alignment 1, but gave size 1 and alignment 2 fn main() { unsafe { diff --git a/tests/compile-fail/alloc/deallocate-bad-size.rs b/tests/compile-fail/alloc/deallocate-bad-size.rs index 386bb56b9091..167cc015c2da 100644 --- a/tests/compile-fail/alloc/deallocate-bad-size.rs +++ b/tests/compile-fail/alloc/deallocate-bad-size.rs @@ -1,6 +1,6 @@ use std::alloc::{alloc, dealloc, Layout}; -// error-pattern: allocation has size 1 and alignment 1, but gave size 2 and alignment 1 +// error-pattern: has size 1 and alignment 1, but gave size 2 and alignment 1 fn main() { unsafe { diff --git a/tests/compile-fail/alloc/reallocate-bad-size.rs b/tests/compile-fail/alloc/reallocate-bad-size.rs index 7826f26f9b8c..80239015dc1d 100644 --- a/tests/compile-fail/alloc/reallocate-bad-size.rs +++ b/tests/compile-fail/alloc/reallocate-bad-size.rs @@ -1,6 +1,6 @@ use std::alloc::{alloc, realloc, Layout}; -// error-pattern: allocation has size 1 and alignment 1, but gave size 2 and alignment 1 +// error-pattern: has size 1 and alignment 1, but gave size 2 and alignment 1 fn main() { unsafe { diff --git a/tests/compile-fail/alloc/stack_free.rs b/tests/compile-fail/alloc/stack_free.rs index 50a590e448a6..d854fa993a79 100644 --- a/tests/compile-fail/alloc/stack_free.rs +++ b/tests/compile-fail/alloc/stack_free.rs @@ -1,7 +1,7 @@ // Validation/SB changes why we fail // compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -// error-pattern: deallocating stack variable memory using Rust heap deallocation operation +// error-pattern: which is stack variable memory, using Rust heap deallocation operation fn main() { let x = 42; diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index cf9a2f4b6925..5d89243b86a9 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -4,7 +4,7 @@ use std::ptr::NonNull; use std::alloc::{Global, AllocRef, Layout, System}; use std::slice; -fn check_alloc(mut allocator: T) { unsafe { +fn check_alloc(allocator: T) { unsafe { for &align in &[4, 8, 16, 32] { let layout_20 = Layout::from_size_align(20, align).unwrap(); let layout_40 = Layout::from_size_align(40, 4*align).unwrap(); @@ -42,7 +42,7 @@ fn check_alloc(mut allocator: T) { unsafe { } } } -fn check_align_requests(mut allocator: T) { +fn check_align_requests(allocator: T) { for &size in &[2, 8, 64] { // size less than and bigger than alignment for &align in &[4, 8, 16, 32] { // Be sure to cover less than and bigger than `MIN_ALIGN` for all architectures let iterations = 32; From 56ea94dfa36e853ad7bf3b3d94718dc4c30f1596 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 27 Sep 2020 10:00:06 +0700 Subject: [PATCH 2322/5092] Remove assume intrinsic from EvalContextExt It has been moved to rustc_mir. --- rust-version | 2 +- src/shims/intrinsics.rs | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/rust-version b/rust-version index 835708a42baa..362f89b5d1fe 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -78a089487b5f6d5e4205ac4500410b442857bced +1ec980d225fff2346a1a631a7ffc88b37e9e18af diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 6051ad482e51..b401bd8adaee 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -478,14 +478,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Other - "assume" => { - let &[cond] = check_arg_count(args)?; - let cond = this.read_scalar(cond)?.check_init()?.to_bool()?; - if !cond { - throw_ub_format!("`assume` intrinsic called with `false`"); - } - } - "exact_div" => { let &[num, denom] = check_arg_count(args)?; this.exact_div(this.read_immediate(num)?, this.read_immediate(denom)?, dest)?; From 22f1eb01ee42c8dcfe5e7d7c981bba82aad1bbea Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 2 Dec 2019 21:15:58 -0500 Subject: [PATCH 2323/5092] Add API for capturing backtrace This PR adds two new Miri-defined extern functions: `miri_get_backtrace` and `miri_resolve_frame`, which are documented in the README. Together, they allow obtaining a backtrace for the currently executing program. I've added a test showing how these APIs are used. I've also prepared a companion PR `backtrace-rs`, which will allow `backtrace::Backtrace::new()` to work automatically under Miri. Once these two PRs are merged, we will be able to print backtraces from the normal Rust panic hook (since libstd is now using backtrace-rs). A few notes: * Resolving the backtrace frames is *very* slow - you can actually see each line being printed out one at a time. Some local testing showed that this is not (primrary) caused by resolving a `Span` - it seems to be just Miri being slow. * For the first time, we now interact directly with a user-defined struct (instead of just executing the user-provided MIR that manipulates the struct). To allow for future changes, I've added a 'version' parameter (currently required to be 0). This should allow us to change the `MiriFrame` struct should the need ever arise. * I used the approach suggested by @oli-obk - a returned backtrace pointer consists of a base function allocation, with the 'offset' used to encode the `Span.lo`. This allows losslessly reconstructing the location information in `miri_resolve_frame`. * There are a few quirks on the `backtrace-rs` side: * `backtrace-rs` calls `getcwd()` by default to try to simplify the filename. This results in an isolation error by default, which could be annoying when printing a backtrace from libstd. * `backtrace-rs` tries to remove 'internal' frames (everything between the call to `Backtrace::new()` and the internal API call made by backtrace-rs) by comparing the returned frame pointer value to a Rust function pointer. This doesn't work due to the way we construct the frame pointers passed to the caller. We could attempt to support this kind of comparison, or just add a `#[cfg(miri)]` and ignore the frames ourselves. --- README.md | 26 ++++++ src/shims/foreign_items.rs | 88 ++++++++++++++++++- .../backtrace/bad-backtrace-decl.rs | 13 +++ .../backtrace/bad-backtrace-ptr.rs | 9 ++ .../backtrace/bad-backtrace-version.rs | 9 ++ tests/run-pass/backtrace-api.rs | 24 +++++ tests/run-pass/backtrace-api.stderr | 10 +++ 7 files changed, 178 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/backtrace/bad-backtrace-decl.rs create mode 100644 tests/compile-fail/backtrace/bad-backtrace-ptr.rs create mode 100644 tests/compile-fail/backtrace/bad-backtrace-version.rs create mode 100644 tests/run-pass/backtrace-api.rs create mode 100644 tests/run-pass/backtrace-api.stderr diff --git a/README.md b/README.md index 657ea096e6c8..524c8e10cf36 100644 --- a/README.md +++ b/README.md @@ -266,6 +266,32 @@ extern "Rust" { /// `ptr` has to point to the beginning of an allocated block. fn miri_static_root(ptr: *const u8); + /// Miri-provided extern function to obtain a backtrace of the current call stack. + /// This returns a boxed slice of pointers - each pointer is an opaque value + /// that is only useful when passed to `miri_resolve_frame` + fn miri_get_backtrace() -> Box<[*mut ()]>; + + /// Miri-provided extern function to resolve a frame pointer obtained + /// from `miri_get_backtrace`. The `version` argument must be `0`, + /// and `MiriFrame` should be declared as follows: + /// + /// ```rust + /// struct MiriFrame { + /// // The name of the function being executed, encoded in UTF-8 + /// name: Box<[u8]>, + /// // The filename of the function being executed, encoded in UTF-8 + /// filename: Box<[u8]>, + /// // The line number currently being executed in `filename`, starting from '1'. + /// lineno: u32, + /// // The column number currently being executed in `filename`, starting from '1'. + /// colno: u32, + /// } + /// ``` + /// + /// The fields must be declared in exactly the same order as they appear in `MiriFrame` above. + /// This function can be called on any thread (not just the one which obtained `frame`) + fn miri_resolve_frame(version: u8, frame: *mut ()) -> MiriFrame; + /// Miri-provided extern function to begin unwinding with the given payload. /// /// This is internal and unstable and should not be used; we give it here diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 5bcbd797ca3c..4d1ead8f0f82 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -3,10 +3,13 @@ use std::{convert::{TryInto, TryFrom}, iter}; use log::trace; use rustc_hir::def_id::DefId; -use rustc_middle::{mir, ty}; +use rustc_middle::mir; use rustc_target::{abi::{Align, Size}, spec::PanicStrategy}; +use rustc_middle::ty::{self, ParamEnv, TypeAndMut}; +use rustc_ast::ast::Mutability; use rustc_apfloat::Float; use rustc_span::symbol::sym; +use rustc_span::BytePos; use crate::*; use helpers::check_arg_count; @@ -211,6 +214,89 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.static_roots.push(ptr.alloc_id); } + // Obtains a Miri backtrace. See the README for details. + "miri_get_backtrace" => { + let tcx = this.tcx; + let mut data = Vec::new(); + for frame in this.active_thread_stack().iter().rev() { + data.push((frame.instance, frame.current_span().lo())); + } + + let ptrs: Vec<_> = data.into_iter().map(|(instance, pos)| { + let mut fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(instance)); + fn_ptr.offset = Size::from_bytes(pos.0); + Scalar::Ptr(fn_ptr) + }).collect(); + + let len = ptrs.len(); + + let ptr_ty = tcx.mk_ptr(TypeAndMut { + ty: tcx.types.unit, + mutbl: Mutability::Mut + }); + + let array_ty = tcx.mk_array(ptr_ty, ptrs.len().try_into().unwrap()); + let array_ty_and_env = ParamEnv::empty().and(array_ty); + + // Write pointers into array + let alloc = this.allocate(tcx.layout_of(array_ty_and_env).unwrap(), MiriMemoryKind::Rust.into()); + for (i, ptr) in ptrs.into_iter().enumerate() { + let place = this.mplace_index(alloc, i as u64)?; + this.write_immediate_to_mplace(ptr.into(), place)?; + } + + this.write_immediate(Immediate::new_slice(alloc.ptr.into(), len.try_into().unwrap(), this), dest)?; + } + + // Resolves a Miri backtrace frame. See the README for details. + "miri_resolve_frame" => { + let tcx = this.tcx; + let &[version, ptr] = check_arg_count(args)?; + + let version = this.read_scalar(version)?.to_u8()?; + if version != 0 { + throw_ub_format!("Unknown `miri_resolve_frame` version {}", version); + } + + let ptr = match this.read_scalar(ptr)?.check_init()? { + Scalar::Ptr(ptr) => ptr, + Scalar::Raw { .. } => throw_ub_format!("Expected a pointer in `rust_miri_resolve_frame`, found {:?}", ptr) + }; + + let fn_instance = if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(ptr.alloc_id) { + instance + } else { + throw_ub_format!("Expect function pointer, found {:?}", ptr); + }; + + if dest.layout.layout.fields.count() != 4 { + throw_ub_format!("Bad declaration of miri_resolve_frame - should return a struct with 4 fields"); + } + + let pos = BytePos(ptr.offset.bytes().try_into().unwrap()); + let name = fn_instance.to_string(); + + let lo = tcx.sess.source_map().lookup_char_pos(pos); + + let filename = lo.file.name.to_string(); + let lineno: u32 = lo.line as u32; + // `lo.col` is 0-based - add 1 to make it 1-based for the caller. + let colno: u32 = lo.col.0 as u32 + 1; + + let name_alloc = this.allocate_str(&name, MiriMemoryKind::Rust.into()); + let filename_alloc = this.allocate_str(&filename, MiriMemoryKind::Rust.into()); + let lineno_alloc = Scalar::from_u32(lineno); + let colno_alloc = Scalar::from_u32(colno); + + let dest = this.force_allocation_maybe_sized(dest, MemPlaceMeta::None)?.0; + + this.write_immediate(name_alloc.to_ref(), this.mplace_field(dest, 0)?.into())?; + this.write_immediate(filename_alloc.to_ref(), this.mplace_field(dest, 1)?.into())?; + this.write_scalar(lineno_alloc, this.mplace_field(dest, 2)?.into())?; + this.write_scalar(colno_alloc, this.mplace_field(dest, 3)?.into())?; + } + + // Standard C allocation "malloc" => { let &[size] = check_arg_count(args)?; diff --git a/tests/compile-fail/backtrace/bad-backtrace-decl.rs b/tests/compile-fail/backtrace/bad-backtrace-decl.rs new file mode 100644 index 000000000000..7c250fbbe3a4 --- /dev/null +++ b/tests/compile-fail/backtrace/bad-backtrace-decl.rs @@ -0,0 +1,13 @@ +extern "Rust" { + fn miri_get_backtrace() -> Box<[*mut ()]>; + fn miri_resolve_frame(version: u8, ptr: *mut ()); +} + +fn main() { + let frames = unsafe { miri_get_backtrace() }; + for frame in frames.into_iter() { + unsafe { + miri_resolve_frame(0, *frame); //~ ERROR Undefined Behavior: Bad declaration of miri_resolve_frame - should return a struct with 4 fields + } + } +} diff --git a/tests/compile-fail/backtrace/bad-backtrace-ptr.rs b/tests/compile-fail/backtrace/bad-backtrace-ptr.rs new file mode 100644 index 000000000000..49b8ac88494d --- /dev/null +++ b/tests/compile-fail/backtrace/bad-backtrace-ptr.rs @@ -0,0 +1,9 @@ +extern "Rust" { + fn miri_resolve_frame(version: u8, ptr: *mut ()); +} + +fn main() { + unsafe { + miri_resolve_frame(0, 0 as *mut _); //~ ERROR Undefined Behavior: Expected a pointer + } +} diff --git a/tests/compile-fail/backtrace/bad-backtrace-version.rs b/tests/compile-fail/backtrace/bad-backtrace-version.rs new file mode 100644 index 000000000000..b0183ca99e94 --- /dev/null +++ b/tests/compile-fail/backtrace/bad-backtrace-version.rs @@ -0,0 +1,9 @@ +extern "Rust" { + fn miri_resolve_frame(version: u8, ptr: *mut ()); +} + +fn main() { + unsafe { + miri_resolve_frame(1, 0 as *mut _); //~ ERROR Undefined Behavior: Unknown `miri_resolve_frame` version 1 + } +} diff --git a/tests/run-pass/backtrace-api.rs b/tests/run-pass/backtrace-api.rs new file mode 100644 index 000000000000..fa86debf17d5 --- /dev/null +++ b/tests/run-pass/backtrace-api.rs @@ -0,0 +1,24 @@ +// normalize-stderr-test ".*rustlib" -> "RUSTLIB" + +extern "Rust" { + fn miri_get_backtrace() -> Box<[*mut ()]>; + fn miri_resolve_frame(version: u8, ptr: *mut ()) -> MiriFrame; +} + +#[derive(Debug)] +struct MiriFrame { + name: Box<[u8]>, + filename: Box<[u8]>, + lineno: u32, + colno: u32 +} + +fn main() { + let frames = unsafe { miri_get_backtrace() }; + for frame in frames.into_iter() { + let miri_frame = unsafe { miri_resolve_frame(0, *frame) }; + let name = String::from_utf8(miri_frame.name.into()).unwrap(); + let filename = String::from_utf8(miri_frame.filename.into()).unwrap(); + eprintln!("{}:{}:{} ({})", filename, miri_frame.lineno, miri_frame.colno, name); + } +} diff --git a/tests/run-pass/backtrace-api.stderr b/tests/run-pass/backtrace-api.stderr new file mode 100644 index 000000000000..91a99070eb64 --- /dev/null +++ b/tests/run-pass/backtrace-api.stderr @@ -0,0 +1,10 @@ +$DIR/backtrace-api.rs:17:27 (main) +RUSTLIB/src/rust/library/core/src/ops/function.rs:227:5 (>::call_once - shim(fn())) +RUSTLIB/src/rust/library/std/src/sys_common/backtrace.rs:137:18 (std::sys_common::backtrace::__rust_begin_short_backtrace::) +RUSTLIB/src/rust/library/std/src/rt.rs:66:18 (std::rt::lang_start::<()>::{{closure}}#0) +RUSTLIB/src/rust/library/core/src/ops/function.rs:259:13 (std::ops::function::impls:: for &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>::call_once) +RUSTLIB/src/rust/library/std/src/panicking.rs:381:40 (std::panicking::r#try::do_call::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>) +RUSTLIB/src/rust/library/std/src/panicking.rs:345:19 (std::panicking::r#try:: i32 + std::marker::Sync + std::panic::RefUnwindSafe>) +RUSTLIB/src/rust/library/std/src/panic.rs:382:14 (std::panic::catch_unwind::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>) +RUSTLIB/src/rust/library/std/src/rt.rs:51:25 (std::rt::lang_start_internal) +RUSTLIB/src/rust/library/std/src/rt.rs:65:5 (std::rt::lang_start::<()>) From ae18659d52821d95bf028f424b57f87a3465bf57 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 22 Sep 2020 10:58:18 -0400 Subject: [PATCH 2324/5092] Normalize line and column numbers from the sysroot --- tests/run-pass/backtrace-api.rs | 1 + tests/run-pass/backtrace-api.stderr | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/tests/run-pass/backtrace-api.rs b/tests/run-pass/backtrace-api.rs index fa86debf17d5..51da6cf9c4dc 100644 --- a/tests/run-pass/backtrace-api.rs +++ b/tests/run-pass/backtrace-api.rs @@ -1,4 +1,5 @@ // normalize-stderr-test ".*rustlib" -> "RUSTLIB" +// normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL " extern "Rust" { fn miri_get_backtrace() -> Box<[*mut ()]>; diff --git a/tests/run-pass/backtrace-api.stderr b/tests/run-pass/backtrace-api.stderr index 91a99070eb64..042ca843d0e1 100644 --- a/tests/run-pass/backtrace-api.stderr +++ b/tests/run-pass/backtrace-api.stderr @@ -1,10 +1,10 @@ -$DIR/backtrace-api.rs:17:27 (main) -RUSTLIB/src/rust/library/core/src/ops/function.rs:227:5 (>::call_once - shim(fn())) -RUSTLIB/src/rust/library/std/src/sys_common/backtrace.rs:137:18 (std::sys_common::backtrace::__rust_begin_short_backtrace::) -RUSTLIB/src/rust/library/std/src/rt.rs:66:18 (std::rt::lang_start::<()>::{{closure}}#0) -RUSTLIB/src/rust/library/core/src/ops/function.rs:259:13 (std::ops::function::impls:: for &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>::call_once) -RUSTLIB/src/rust/library/std/src/panicking.rs:381:40 (std::panicking::r#try::do_call::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>) -RUSTLIB/src/rust/library/std/src/panicking.rs:345:19 (std::panicking::r#try:: i32 + std::marker::Sync + std::panic::RefUnwindSafe>) -RUSTLIB/src/rust/library/std/src/panic.rs:382:14 (std::panic::catch_unwind::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>) -RUSTLIB/src/rust/library/std/src/rt.rs:51:25 (std::rt::lang_start_internal) -RUSTLIB/src/rust/library/std/src/rt.rs:65:5 (std::rt::lang_start::<()>) +$DIR/backtrace-api.rs:18:27 (main) +RUSTLIB/src/rust/library/core/src/ops/function.rs:LL:COL (>::call_once - shim(fn())) +RUSTLIB/src/rust/library/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace::) +RUSTLIB/src/rust/library/std/src/rt.rs:LL:COL (std::rt::lang_start::<()>::{{closure}}#0) +RUSTLIB/src/rust/library/core/src/ops/function.rs:LL:COL (std::ops::function::impls:: for &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>::call_once) +RUSTLIB/src/rust/library/std/src/panicking.rs:LL:COL (std::panicking::r#try::do_call::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>) +RUSTLIB/src/rust/library/std/src/panicking.rs:LL:COL (std::panicking::r#try:: i32 + std::marker::Sync + std::panic::RefUnwindSafe>) +RUSTLIB/src/rust/library/std/src/panic.rs:LL:COL (std::panic::catch_unwind::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>) +RUSTLIB/src/rust/library/std/src/rt.rs:LL:COL (std::rt::lang_start_internal) +RUSTLIB/src/rust/library/std/src/rt.rs:LL:COL (std::rt::lang_start::<()>) From ef43c5a614fe1b9556e4291f7f11cbe0e3d9a125 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 24 Sep 2020 14:18:47 -0400 Subject: [PATCH 2325/5092] Use a 'flags' parameter instead of 'version' --- README.md | 2 +- src/shims/foreign_items.rs | 8 ++++---- tests/compile-fail/backtrace/bad-backtrace-decl.rs | 4 ++-- tests/compile-fail/backtrace/bad-backtrace-ptr.rs | 4 ++-- tests/compile-fail/backtrace/bad-backtrace-version.rs | 4 ++-- tests/run-pass/backtrace-api.rs | 4 ++-- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 524c8e10cf36..55d3bef727f3 100644 --- a/README.md +++ b/README.md @@ -290,7 +290,7 @@ extern "Rust" { /// /// The fields must be declared in exactly the same order as they appear in `MiriFrame` above. /// This function can be called on any thread (not just the one which obtained `frame`) - fn miri_resolve_frame(version: u8, frame: *mut ()) -> MiriFrame; + fn miri_resolve_frame(frame: *mut (), flags: u64) -> MiriFrame; /// Miri-provided extern function to begin unwinding with the given payload. /// diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 4d1ead8f0f82..b1a02a8eb65b 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -251,11 +251,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Resolves a Miri backtrace frame. See the README for details. "miri_resolve_frame" => { let tcx = this.tcx; - let &[version, ptr] = check_arg_count(args)?; + let &[ptr, flags] = check_arg_count(args)?; - let version = this.read_scalar(version)?.to_u8()?; - if version != 0 { - throw_ub_format!("Unknown `miri_resolve_frame` version {}", version); + let flags = this.read_scalar(flags)?.to_u64()?; + if flags != 0 { + throw_ub_format!("Unknown `miri_resolve_frame` flags {}", flags); } let ptr = match this.read_scalar(ptr)?.check_init()? { diff --git a/tests/compile-fail/backtrace/bad-backtrace-decl.rs b/tests/compile-fail/backtrace/bad-backtrace-decl.rs index 7c250fbbe3a4..c55a1c6d3808 100644 --- a/tests/compile-fail/backtrace/bad-backtrace-decl.rs +++ b/tests/compile-fail/backtrace/bad-backtrace-decl.rs @@ -1,13 +1,13 @@ extern "Rust" { fn miri_get_backtrace() -> Box<[*mut ()]>; - fn miri_resolve_frame(version: u8, ptr: *mut ()); + fn miri_resolve_frame(ptr: *mut (), flags: u64); } fn main() { let frames = unsafe { miri_get_backtrace() }; for frame in frames.into_iter() { unsafe { - miri_resolve_frame(0, *frame); //~ ERROR Undefined Behavior: Bad declaration of miri_resolve_frame - should return a struct with 4 fields + miri_resolve_frame(*frame, 0); //~ ERROR Undefined Behavior: Bad declaration of miri_resolve_frame - should return a struct with 4 fields } } } diff --git a/tests/compile-fail/backtrace/bad-backtrace-ptr.rs b/tests/compile-fail/backtrace/bad-backtrace-ptr.rs index 49b8ac88494d..3f672eb2dcad 100644 --- a/tests/compile-fail/backtrace/bad-backtrace-ptr.rs +++ b/tests/compile-fail/backtrace/bad-backtrace-ptr.rs @@ -1,9 +1,9 @@ extern "Rust" { - fn miri_resolve_frame(version: u8, ptr: *mut ()); + fn miri_resolve_frame(ptr: *mut (), flags: u64); } fn main() { unsafe { - miri_resolve_frame(0, 0 as *mut _); //~ ERROR Undefined Behavior: Expected a pointer + miri_resolve_frame(0 as *mut _, 0); //~ ERROR Undefined Behavior: Expected a pointer } } diff --git a/tests/compile-fail/backtrace/bad-backtrace-version.rs b/tests/compile-fail/backtrace/bad-backtrace-version.rs index b0183ca99e94..d6743ae8fff9 100644 --- a/tests/compile-fail/backtrace/bad-backtrace-version.rs +++ b/tests/compile-fail/backtrace/bad-backtrace-version.rs @@ -1,9 +1,9 @@ extern "Rust" { - fn miri_resolve_frame(version: u8, ptr: *mut ()); + fn miri_resolve_frame(ptr: *mut (), flags: u64); } fn main() { unsafe { - miri_resolve_frame(1, 0 as *mut _); //~ ERROR Undefined Behavior: Unknown `miri_resolve_frame` version 1 + miri_resolve_frame(0 as *mut _, 1); //~ ERROR Undefined Behavior: Unknown `miri_resolve_frame` flags 1 } } diff --git a/tests/run-pass/backtrace-api.rs b/tests/run-pass/backtrace-api.rs index 51da6cf9c4dc..231b718cd3eb 100644 --- a/tests/run-pass/backtrace-api.rs +++ b/tests/run-pass/backtrace-api.rs @@ -3,7 +3,7 @@ extern "Rust" { fn miri_get_backtrace() -> Box<[*mut ()]>; - fn miri_resolve_frame(version: u8, ptr: *mut ()) -> MiriFrame; + fn miri_resolve_frame(ptr: *mut (), flags: u64) -> MiriFrame; } #[derive(Debug)] @@ -17,7 +17,7 @@ struct MiriFrame { fn main() { let frames = unsafe { miri_get_backtrace() }; for frame in frames.into_iter() { - let miri_frame = unsafe { miri_resolve_frame(0, *frame) }; + let miri_frame = unsafe { miri_resolve_frame(*frame, 0) }; let name = String::from_utf8(miri_frame.name.into()).unwrap(); let filename = String::from_utf8(miri_frame.filename.into()).unwrap(); eprintln!("{}:{}:{} ({})", filename, miri_frame.lineno, miri_frame.colno, name); From 9fc384fcf9e8d028aec1dd11da15c702667e4205 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 24 Sep 2020 15:05:50 -0400 Subject: [PATCH 2326/5092] Print non-std frames to stdout in `backtrace-api` test --- tests/run-pass/backtrace-api.rs | 18 ++++++++++++++++-- tests/run-pass/backtrace-api.stderr | 5 ++++- tests/run-pass/backtrace-api.stdout | 4 ++++ 3 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 tests/run-pass/backtrace-api.stdout diff --git a/tests/run-pass/backtrace-api.rs b/tests/run-pass/backtrace-api.rs index 231b718cd3eb..73a3f6242d5b 100644 --- a/tests/run-pass/backtrace-api.rs +++ b/tests/run-pass/backtrace-api.rs @@ -14,12 +14,26 @@ struct MiriFrame { colno: u32 } +fn func_a() -> Box<[*mut ()]> { func_b::() } +fn func_b() -> Box<[*mut ()]> { func_c() } +fn func_c() -> Box<[*mut ()]> { unsafe { miri_get_backtrace() } } + fn main() { - let frames = unsafe { miri_get_backtrace() }; + let mut seen_main = false; + let frames = func_a(); for frame in frames.into_iter() { let miri_frame = unsafe { miri_resolve_frame(*frame, 0) }; let name = String::from_utf8(miri_frame.name.into()).unwrap(); let filename = String::from_utf8(miri_frame.filename.into()).unwrap(); - eprintln!("{}:{}:{} ({})", filename, miri_frame.lineno, miri_frame.colno, name); + + // Print every frame to stderr. + let out = format!("{}:{}:{} ({})", filename, miri_frame.lineno, miri_frame.colno, name); + eprintln!("{}", out); + // Print the 'main' frame (and everything before it) to stdout, skipping + // the printing of internal (and possibly fragile) libstd frames. + if !seen_main { + println!("{}", out); + seen_main = name == "main"; + } } } diff --git a/tests/run-pass/backtrace-api.stderr b/tests/run-pass/backtrace-api.stderr index 042ca843d0e1..b96def8093a4 100644 --- a/tests/run-pass/backtrace-api.stderr +++ b/tests/run-pass/backtrace-api.stderr @@ -1,4 +1,7 @@ -$DIR/backtrace-api.rs:18:27 (main) +$DIR/backtrace-api.rs:19:42 (func_c) +$DIR/backtrace-api.rs:18:36 (func_b::) +$DIR/backtrace-api.rs:17:33 (func_a) +$DIR/backtrace-api.rs:23:18 (main) RUSTLIB/src/rust/library/core/src/ops/function.rs:LL:COL (>::call_once - shim(fn())) RUSTLIB/src/rust/library/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace::) RUSTLIB/src/rust/library/std/src/rt.rs:LL:COL (std::rt::lang_start::<()>::{{closure}}#0) diff --git a/tests/run-pass/backtrace-api.stdout b/tests/run-pass/backtrace-api.stdout new file mode 100644 index 000000000000..0d8aaa7a3261 --- /dev/null +++ b/tests/run-pass/backtrace-api.stdout @@ -0,0 +1,4 @@ +$DIR/backtrace-api.rs:19:42 (func_c) +$DIR/backtrace-api.rs:18:36 (func_b::) +$DIR/backtrace-api.rs:17:33 (func_a) +$DIR/backtrace-api.rs:23:18 (main) From b89f6561e52d458522e640ef5777126c410fd4ca Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 24 Sep 2020 18:52:17 -0400 Subject: [PATCH 2327/5092] Move things around --- src/shims/backtrace.rs | 110 ++++++++++++++++++ src/shims/foreign_items.rs | 81 +------------ src/shims/mod.rs | 2 +- .../backtrace/bad-backtrace-decl.rs | 4 +- .../backtrace/bad-backtrace-version.rs | 2 +- tests/run-pass/backtrace-api.rs | 4 +- 6 files changed, 120 insertions(+), 83 deletions(-) create mode 100644 src/shims/backtrace.rs diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs new file mode 100644 index 000000000000..2b360cb85a6e --- /dev/null +++ b/src/shims/backtrace.rs @@ -0,0 +1,110 @@ +use crate::*; +use helpers::check_arg_count; +use rustc_middle::ty::TypeAndMut; +use rustc_ast::ast::Mutability; +use rustc_span::BytePos; +use rustc_target::abi::Size; +use std::convert::TryInto as _; +use crate::rustc_target::abi::LayoutOf as _; + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + + fn handle_miri_get_backtrace( + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag> + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let tcx = this.tcx; + let &[flags] = check_arg_count(args)?; + + let flags = this.read_scalar(flags)?.to_u64()?; + if flags != 0 { + throw_unsup_format!("unknown `miri_get_backtrace` flags {}", flags); + } + + let mut data = Vec::new(); + for frame in this.active_thread_stack().iter().rev() { + data.push((frame.instance, frame.current_span().lo())); + } + + let ptrs: Vec<_> = data.into_iter().map(|(instance, pos)| { + let mut fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(instance)); + fn_ptr.offset = Size::from_bytes(pos.0); + Scalar::Ptr(fn_ptr) + }).collect(); + + let len = ptrs.len(); + + let ptr_ty = tcx.mk_ptr(TypeAndMut { + ty: tcx.types.unit, + mutbl: Mutability::Mut + }); + + let array_ty = tcx.mk_array(ptr_ty, ptrs.len().try_into().unwrap()); + + // Write pointers into array + let alloc = this.allocate(this.layout_of(array_ty).unwrap(), MiriMemoryKind::Rust.into()); + for (i, ptr) in ptrs.into_iter().enumerate() { + let place = this.mplace_index(alloc, i as u64)?; + this.write_immediate_to_mplace(ptr.into(), place)?; + } + + this.write_immediate(Immediate::new_slice(alloc.ptr.into(), len.try_into().unwrap(), this), dest)?; + Ok(()) + } + + fn handle_miri_resolve_frame( + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag> + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let tcx = this.tcx; + let &[ptr, flags] = check_arg_count(args)?; + + let flags = this.read_scalar(flags)?.to_u64()?; + if flags != 0 { + throw_unsup_format!("unknown `miri_resolve_frame` flags {}", flags); + } + + let ptr = match this.read_scalar(ptr)?.check_init()? { + Scalar::Ptr(ptr) => ptr, + Scalar::Raw { .. } => throw_ub_format!("Expected a pointer in `rust_miri_resolve_frame`, found {:?}", ptr) + }; + + let fn_instance = if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(ptr.alloc_id) { + instance + } else { + throw_ub_format!("expected function pointer, found {:?}", ptr); + }; + + if dest.layout.layout.fields.count() != 4 { + throw_ub_format!("Bad declaration of miri_resolve_frame - should return a struct with 4 fields"); + } + + let pos = BytePos(ptr.offset.bytes().try_into().unwrap()); + let name = fn_instance.to_string(); + + let lo = tcx.sess.source_map().lookup_char_pos(pos); + + let filename = lo.file.name.to_string(); + let lineno: u32 = lo.line as u32; + // `lo.col` is 0-based - add 1 to make it 1-based for the caller. + let colno: u32 = lo.col.0 as u32 + 1; + + let name_alloc = this.allocate_str(&name, MiriMemoryKind::Rust.into()); + let filename_alloc = this.allocate_str(&filename, MiriMemoryKind::Rust.into()); + let lineno_alloc = Scalar::from_u32(lineno); + let colno_alloc = Scalar::from_u32(colno); + + let dest = this.force_allocation_maybe_sized(dest, MemPlaceMeta::None)?.0; + + this.write_immediate(name_alloc.to_ref(), this.mplace_field(dest, 0)?.into())?; + this.write_immediate(filename_alloc.to_ref(), this.mplace_field(dest, 1)?.into())?; + this.write_scalar(lineno_alloc, this.mplace_field(dest, 2)?.into())?; + this.write_scalar(colno_alloc, this.mplace_field(dest, 3)?.into())?; + Ok(()) + } +} diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index b1a02a8eb65b..7118fbda2403 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -5,13 +5,12 @@ use log::trace; use rustc_hir::def_id::DefId; use rustc_middle::mir; use rustc_target::{abi::{Align, Size}, spec::PanicStrategy}; -use rustc_middle::ty::{self, ParamEnv, TypeAndMut}; -use rustc_ast::ast::Mutability; +use rustc_middle::ty; use rustc_apfloat::Float; use rustc_span::symbol::sym; -use rustc_span::BytePos; use crate::*; +use super::backtrace::EvalContextExt as _; use helpers::check_arg_count; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -216,84 +215,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Obtains a Miri backtrace. See the README for details. "miri_get_backtrace" => { - let tcx = this.tcx; - let mut data = Vec::new(); - for frame in this.active_thread_stack().iter().rev() { - data.push((frame.instance, frame.current_span().lo())); - } - - let ptrs: Vec<_> = data.into_iter().map(|(instance, pos)| { - let mut fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(instance)); - fn_ptr.offset = Size::from_bytes(pos.0); - Scalar::Ptr(fn_ptr) - }).collect(); - - let len = ptrs.len(); - - let ptr_ty = tcx.mk_ptr(TypeAndMut { - ty: tcx.types.unit, - mutbl: Mutability::Mut - }); - - let array_ty = tcx.mk_array(ptr_ty, ptrs.len().try_into().unwrap()); - let array_ty_and_env = ParamEnv::empty().and(array_ty); - - // Write pointers into array - let alloc = this.allocate(tcx.layout_of(array_ty_and_env).unwrap(), MiriMemoryKind::Rust.into()); - for (i, ptr) in ptrs.into_iter().enumerate() { - let place = this.mplace_index(alloc, i as u64)?; - this.write_immediate_to_mplace(ptr.into(), place)?; - } - - this.write_immediate(Immediate::new_slice(alloc.ptr.into(), len.try_into().unwrap(), this), dest)?; + this.handle_miri_get_backtrace(args, dest)?; } // Resolves a Miri backtrace frame. See the README for details. "miri_resolve_frame" => { - let tcx = this.tcx; - let &[ptr, flags] = check_arg_count(args)?; - - let flags = this.read_scalar(flags)?.to_u64()?; - if flags != 0 { - throw_ub_format!("Unknown `miri_resolve_frame` flags {}", flags); - } - - let ptr = match this.read_scalar(ptr)?.check_init()? { - Scalar::Ptr(ptr) => ptr, - Scalar::Raw { .. } => throw_ub_format!("Expected a pointer in `rust_miri_resolve_frame`, found {:?}", ptr) - }; - - let fn_instance = if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(ptr.alloc_id) { - instance - } else { - throw_ub_format!("Expect function pointer, found {:?}", ptr); - }; - - if dest.layout.layout.fields.count() != 4 { - throw_ub_format!("Bad declaration of miri_resolve_frame - should return a struct with 4 fields"); - } - - let pos = BytePos(ptr.offset.bytes().try_into().unwrap()); - let name = fn_instance.to_string(); - - let lo = tcx.sess.source_map().lookup_char_pos(pos); - - let filename = lo.file.name.to_string(); - let lineno: u32 = lo.line as u32; - // `lo.col` is 0-based - add 1 to make it 1-based for the caller. - let colno: u32 = lo.col.0 as u32 + 1; - - let name_alloc = this.allocate_str(&name, MiriMemoryKind::Rust.into()); - let filename_alloc = this.allocate_str(&filename, MiriMemoryKind::Rust.into()); - let lineno_alloc = Scalar::from_u32(lineno); - let colno_alloc = Scalar::from_u32(colno); - - let dest = this.force_allocation_maybe_sized(dest, MemPlaceMeta::None)?.0; - - this.write_immediate(name_alloc.to_ref(), this.mplace_field(dest, 0)?.into())?; - this.write_immediate(filename_alloc.to_ref(), this.mplace_field(dest, 1)?.into())?; - this.write_scalar(lineno_alloc, this.mplace_field(dest, 2)?.into())?; - this.write_scalar(colno_alloc, this.mplace_field(dest, 3)?.into())?; + this.handle_miri_resolve_frame(args, dest)?; } diff --git a/src/shims/mod.rs b/src/shims/mod.rs index eab27496cb28..90dcc4d8ff1e 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -1,4 +1,4 @@ - +mod backtrace; pub mod foreign_items; pub mod intrinsics; pub mod posix; diff --git a/tests/compile-fail/backtrace/bad-backtrace-decl.rs b/tests/compile-fail/backtrace/bad-backtrace-decl.rs index c55a1c6d3808..bccc7063af71 100644 --- a/tests/compile-fail/backtrace/bad-backtrace-decl.rs +++ b/tests/compile-fail/backtrace/bad-backtrace-decl.rs @@ -1,10 +1,10 @@ extern "Rust" { - fn miri_get_backtrace() -> Box<[*mut ()]>; + fn miri_get_backtrace(flags: u64) -> Box<[*mut ()]>; fn miri_resolve_frame(ptr: *mut (), flags: u64); } fn main() { - let frames = unsafe { miri_get_backtrace() }; + let frames = unsafe { miri_get_backtrace(0) }; for frame in frames.into_iter() { unsafe { miri_resolve_frame(*frame, 0); //~ ERROR Undefined Behavior: Bad declaration of miri_resolve_frame - should return a struct with 4 fields diff --git a/tests/compile-fail/backtrace/bad-backtrace-version.rs b/tests/compile-fail/backtrace/bad-backtrace-version.rs index d6743ae8fff9..4579b5d0ade8 100644 --- a/tests/compile-fail/backtrace/bad-backtrace-version.rs +++ b/tests/compile-fail/backtrace/bad-backtrace-version.rs @@ -4,6 +4,6 @@ extern "Rust" { fn main() { unsafe { - miri_resolve_frame(0 as *mut _, 1); //~ ERROR Undefined Behavior: Unknown `miri_resolve_frame` flags 1 + miri_resolve_frame(0 as *mut _, 1); //~ ERROR unsupported operation: unknown `miri_resolve_frame` flags 1 } } diff --git a/tests/run-pass/backtrace-api.rs b/tests/run-pass/backtrace-api.rs index 73a3f6242d5b..655a52c7fc7d 100644 --- a/tests/run-pass/backtrace-api.rs +++ b/tests/run-pass/backtrace-api.rs @@ -2,7 +2,7 @@ // normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL " extern "Rust" { - fn miri_get_backtrace() -> Box<[*mut ()]>; + fn miri_get_backtrace(flags: u64) -> Box<[*mut ()]>; fn miri_resolve_frame(ptr: *mut (), flags: u64) -> MiriFrame; } @@ -16,7 +16,7 @@ struct MiriFrame { fn func_a() -> Box<[*mut ()]> { func_b::() } fn func_b() -> Box<[*mut ()]> { func_c() } -fn func_c() -> Box<[*mut ()]> { unsafe { miri_get_backtrace() } } +fn func_c() -> Box<[*mut ()]> { unsafe { miri_get_backtrace(0) } } fn main() { let mut seen_main = false; From f756e3a93f53d72eceb2367a36f91b7f809752d6 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 24 Sep 2020 19:06:39 -0400 Subject: [PATCH 2328/5092] Explain encoding scheme --- src/shims/backtrace.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 2b360cb85a6e..2c031f179d08 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -30,6 +30,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let ptrs: Vec<_> = data.into_iter().map(|(instance, pos)| { + // We represent a frame pointer by using the `span.lo` value + // as an offset into the function's allocation. This gives us an + // opaque pointer that we can return to user code, and allows us + // to reconstruct the needed frame information in `handle_miri_resolve_frame`. + // Note that we never actually read or write anything from/to this pointer - + // all of the data is represented by the pointer value itself. let mut fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(instance)); fn_ptr.offset = Size::from_bytes(pos.0); Scalar::Ptr(fn_ptr) From e1bce19ca953873dc9ff90d2fede9e35449dc2ea Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 24 Sep 2020 19:10:02 -0400 Subject: [PATCH 2329/5092] Make some error messages lowercase --- src/shims/backtrace.rs | 4 ++-- tests/compile-fail/backtrace/bad-backtrace-decl.rs | 2 +- tests/compile-fail/backtrace/bad-backtrace-ptr.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 2c031f179d08..57d59dd4c098 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -77,7 +77,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = match this.read_scalar(ptr)?.check_init()? { Scalar::Ptr(ptr) => ptr, - Scalar::Raw { .. } => throw_ub_format!("Expected a pointer in `rust_miri_resolve_frame`, found {:?}", ptr) + Scalar::Raw { .. } => throw_ub_format!("expected a pointer in `rust_miri_resolve_frame`, found {:?}", ptr) }; let fn_instance = if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(ptr.alloc_id) { @@ -87,7 +87,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; if dest.layout.layout.fields.count() != 4 { - throw_ub_format!("Bad declaration of miri_resolve_frame - should return a struct with 4 fields"); + throw_ub_format!("bad declaration of miri_resolve_frame - should return a struct with 4 fields"); } let pos = BytePos(ptr.offset.bytes().try_into().unwrap()); diff --git a/tests/compile-fail/backtrace/bad-backtrace-decl.rs b/tests/compile-fail/backtrace/bad-backtrace-decl.rs index bccc7063af71..b9f1c779ae23 100644 --- a/tests/compile-fail/backtrace/bad-backtrace-decl.rs +++ b/tests/compile-fail/backtrace/bad-backtrace-decl.rs @@ -7,7 +7,7 @@ fn main() { let frames = unsafe { miri_get_backtrace(0) }; for frame in frames.into_iter() { unsafe { - miri_resolve_frame(*frame, 0); //~ ERROR Undefined Behavior: Bad declaration of miri_resolve_frame - should return a struct with 4 fields + miri_resolve_frame(*frame, 0); //~ ERROR Undefined Behavior: bad declaration of miri_resolve_frame - should return a struct with 4 fields } } } diff --git a/tests/compile-fail/backtrace/bad-backtrace-ptr.rs b/tests/compile-fail/backtrace/bad-backtrace-ptr.rs index 3f672eb2dcad..5e245952e9b2 100644 --- a/tests/compile-fail/backtrace/bad-backtrace-ptr.rs +++ b/tests/compile-fail/backtrace/bad-backtrace-ptr.rs @@ -4,6 +4,6 @@ extern "Rust" { fn main() { unsafe { - miri_resolve_frame(0 as *mut _, 0); //~ ERROR Undefined Behavior: Expected a pointer + miri_resolve_frame(0 as *mut _, 0); //~ ERROR Undefined Behavior: expected a pointer } } From 11e2dbd51c3241d890c8a980a011c0fa3e099011 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 24 Sep 2020 19:10:09 -0400 Subject: [PATCH 2330/5092] Update README --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 55d3bef727f3..1ebacfc26bef 100644 --- a/README.md +++ b/README.md @@ -269,10 +269,11 @@ extern "Rust" { /// Miri-provided extern function to obtain a backtrace of the current call stack. /// This returns a boxed slice of pointers - each pointer is an opaque value /// that is only useful when passed to `miri_resolve_frame` - fn miri_get_backtrace() -> Box<[*mut ()]>; + /// The `flags` argument must be `0`. + fn miri_get_backtrace(flags: u64) -> Box<[*mut ()]>; /// Miri-provided extern function to resolve a frame pointer obtained - /// from `miri_get_backtrace`. The `version` argument must be `0`, + /// from `miri_get_backtrace`. The `flags` argument must be `0`, /// and `MiriFrame` should be declared as follows: /// /// ```rust From dba7f135495a4358472bac6c2704703e957ac68d Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 24 Sep 2020 23:00:32 -0400 Subject: [PATCH 2331/5092] Apply #[inline(never)] to functions that we want in the backtrace --- tests/run-pass/backtrace-api.rs | 6 +++--- tests/run-pass/backtrace-api.stderr | 6 +++--- tests/run-pass/backtrace-api.stdout | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/run-pass/backtrace-api.rs b/tests/run-pass/backtrace-api.rs index 655a52c7fc7d..1322e15fc962 100644 --- a/tests/run-pass/backtrace-api.rs +++ b/tests/run-pass/backtrace-api.rs @@ -14,9 +14,9 @@ struct MiriFrame { colno: u32 } -fn func_a() -> Box<[*mut ()]> { func_b::() } -fn func_b() -> Box<[*mut ()]> { func_c() } -fn func_c() -> Box<[*mut ()]> { unsafe { miri_get_backtrace(0) } } +#[inline(never)] fn func_a() -> Box<[*mut ()]> { func_b::() } +#[inline(never)] fn func_b() -> Box<[*mut ()]> { func_c() } +#[inline(never)] fn func_c() -> Box<[*mut ()]> { unsafe { miri_get_backtrace(0) } } fn main() { let mut seen_main = false; diff --git a/tests/run-pass/backtrace-api.stderr b/tests/run-pass/backtrace-api.stderr index b96def8093a4..d94a7ce4aec2 100644 --- a/tests/run-pass/backtrace-api.stderr +++ b/tests/run-pass/backtrace-api.stderr @@ -1,6 +1,6 @@ -$DIR/backtrace-api.rs:19:42 (func_c) -$DIR/backtrace-api.rs:18:36 (func_b::) -$DIR/backtrace-api.rs:17:33 (func_a) +$DIR/backtrace-api.rs:19:59 (func_c) +$DIR/backtrace-api.rs:18:53 (func_b::) +$DIR/backtrace-api.rs:17:50 (func_a) $DIR/backtrace-api.rs:23:18 (main) RUSTLIB/src/rust/library/core/src/ops/function.rs:LL:COL (>::call_once - shim(fn())) RUSTLIB/src/rust/library/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace::) diff --git a/tests/run-pass/backtrace-api.stdout b/tests/run-pass/backtrace-api.stdout index 0d8aaa7a3261..0353f98ed76a 100644 --- a/tests/run-pass/backtrace-api.stdout +++ b/tests/run-pass/backtrace-api.stdout @@ -1,4 +1,4 @@ -$DIR/backtrace-api.rs:19:42 (func_c) -$DIR/backtrace-api.rs:18:36 (func_b::) -$DIR/backtrace-api.rs:17:33 (func_a) +$DIR/backtrace-api.rs:19:59 (func_c) +$DIR/backtrace-api.rs:18:53 (func_b::) +$DIR/backtrace-api.rs:17:50 (func_a) $DIR/backtrace-api.rs:23:18 (main) From 5571bcfc4fd3e986027e537ed57a4c4321af53ec Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 26 Sep 2020 14:40:41 -0400 Subject: [PATCH 2332/5092] Require #[repr(C)] on MiriFrame --- README.md | 1 + src/shims/backtrace.rs | 9 +++++++-- tests/run-pass/backtrace-api.rs | 1 + tests/run-pass/backtrace-api.stderr | 8 ++++---- tests/run-pass/backtrace-api.stdout | 8 ++++---- 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 1ebacfc26bef..b84102598c15 100644 --- a/README.md +++ b/README.md @@ -277,6 +277,7 @@ extern "Rust" { /// and `MiriFrame` should be declared as follows: /// /// ```rust + /// #[repr(C)] /// struct MiriFrame { /// // The name of the function being executed, encoded in UTF-8 /// name: Box<[u8]>, diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 57d59dd4c098..75cd61b0f59e 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -1,6 +1,6 @@ use crate::*; use helpers::check_arg_count; -use rustc_middle::ty::TypeAndMut; +use rustc_middle::ty::{self, TypeAndMut}; use rustc_ast::ast::Mutability; use rustc_span::BytePos; use rustc_target::abi::Size; @@ -105,7 +105,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let lineno_alloc = Scalar::from_u32(lineno); let colno_alloc = Scalar::from_u32(colno); - let dest = this.force_allocation_maybe_sized(dest, MemPlaceMeta::None)?.0; + let dest = this.force_allocation(dest)?; + if let ty::Adt(adt, _) = dest.layout.ty.kind() { + if !adt.repr.c() { + throw_ub_format!("miri_resolve_frame must be declared with a `#[repr(C)]` return type"); + } + } this.write_immediate(name_alloc.to_ref(), this.mplace_field(dest, 0)?.into())?; this.write_immediate(filename_alloc.to_ref(), this.mplace_field(dest, 1)?.into())?; diff --git a/tests/run-pass/backtrace-api.rs b/tests/run-pass/backtrace-api.rs index 1322e15fc962..a58fb83d92f7 100644 --- a/tests/run-pass/backtrace-api.rs +++ b/tests/run-pass/backtrace-api.rs @@ -7,6 +7,7 @@ extern "Rust" { } #[derive(Debug)] +#[repr(C)] struct MiriFrame { name: Box<[u8]>, filename: Box<[u8]>, diff --git a/tests/run-pass/backtrace-api.stderr b/tests/run-pass/backtrace-api.stderr index d94a7ce4aec2..92c5331d6143 100644 --- a/tests/run-pass/backtrace-api.stderr +++ b/tests/run-pass/backtrace-api.stderr @@ -1,7 +1,7 @@ -$DIR/backtrace-api.rs:19:59 (func_c) -$DIR/backtrace-api.rs:18:53 (func_b::) -$DIR/backtrace-api.rs:17:50 (func_a) -$DIR/backtrace-api.rs:23:18 (main) +$DIR/backtrace-api.rs:20:59 (func_c) +$DIR/backtrace-api.rs:19:53 (func_b::) +$DIR/backtrace-api.rs:18:50 (func_a) +$DIR/backtrace-api.rs:24:18 (main) RUSTLIB/src/rust/library/core/src/ops/function.rs:LL:COL (>::call_once - shim(fn())) RUSTLIB/src/rust/library/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace::) RUSTLIB/src/rust/library/std/src/rt.rs:LL:COL (std::rt::lang_start::<()>::{{closure}}#0) diff --git a/tests/run-pass/backtrace-api.stdout b/tests/run-pass/backtrace-api.stdout index 0353f98ed76a..e4130ade62e0 100644 --- a/tests/run-pass/backtrace-api.stdout +++ b/tests/run-pass/backtrace-api.stdout @@ -1,4 +1,4 @@ -$DIR/backtrace-api.rs:19:59 (func_c) -$DIR/backtrace-api.rs:18:53 (func_b::) -$DIR/backtrace-api.rs:17:50 (func_a) -$DIR/backtrace-api.rs:23:18 (main) +$DIR/backtrace-api.rs:20:59 (func_c) +$DIR/backtrace-api.rs:19:53 (func_b::) +$DIR/backtrace-api.rs:18:50 (func_a) +$DIR/backtrace-api.rs:24:18 (main) From b1837d0bc9b8bab3bada98c655b39055fc5d8750 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 28 Sep 2020 19:34:18 +0200 Subject: [PATCH 2333/5092] fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b84102598c15..2b015104828e 100644 --- a/README.md +++ b/README.md @@ -291,7 +291,7 @@ extern "Rust" { /// ``` /// /// The fields must be declared in exactly the same order as they appear in `MiriFrame` above. - /// This function can be called on any thread (not just the one which obtained `frame`) + /// This function can be called on any thread (not just the one which obtained `frame`). fn miri_resolve_frame(frame: *mut (), flags: u64) -> MiriFrame; /// Miri-provided extern function to begin unwinding with the given payload. From 7fba3c2cf2058519b784de59605804899e0fe670 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 28 Sep 2020 13:55:23 -0400 Subject: [PATCH 2334/5092] Normalize out generic arguments in backtrace-api stderr --- tests/run-pass/backtrace-api.rs | 1 + tests/run-pass/backtrace-api.stderr | 22 +++++++++++----------- tests/run-pass/backtrace-api.stdout | 8 ++++---- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/tests/run-pass/backtrace-api.rs b/tests/run-pass/backtrace-api.rs index a58fb83d92f7..be1971efe28d 100644 --- a/tests/run-pass/backtrace-api.rs +++ b/tests/run-pass/backtrace-api.rs @@ -1,5 +1,6 @@ // normalize-stderr-test ".*rustlib" -> "RUSTLIB" // normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL " +// normalize-stderr-test "::<.*>" -> "" extern "Rust" { fn miri_get_backtrace(flags: u64) -> Box<[*mut ()]>; diff --git a/tests/run-pass/backtrace-api.stderr b/tests/run-pass/backtrace-api.stderr index 92c5331d6143..ea25267a1b14 100644 --- a/tests/run-pass/backtrace-api.stderr +++ b/tests/run-pass/backtrace-api.stderr @@ -1,13 +1,13 @@ -$DIR/backtrace-api.rs:20:59 (func_c) -$DIR/backtrace-api.rs:19:53 (func_b::) -$DIR/backtrace-api.rs:18:50 (func_a) -$DIR/backtrace-api.rs:24:18 (main) +$DIR/backtrace-api.rs:21:59 (func_c) +$DIR/backtrace-api.rs:20:53 (func_b) +$DIR/backtrace-api.rs:19:50 (func_a) +$DIR/backtrace-api.rs:25:18 (main) RUSTLIB/src/rust/library/core/src/ops/function.rs:LL:COL (>::call_once - shim(fn())) -RUSTLIB/src/rust/library/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace::) -RUSTLIB/src/rust/library/std/src/rt.rs:LL:COL (std::rt::lang_start::<()>::{{closure}}#0) -RUSTLIB/src/rust/library/core/src/ops/function.rs:LL:COL (std::ops::function::impls:: for &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>::call_once) -RUSTLIB/src/rust/library/std/src/panicking.rs:LL:COL (std::panicking::r#try::do_call::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>) -RUSTLIB/src/rust/library/std/src/panicking.rs:LL:COL (std::panicking::r#try:: i32 + std::marker::Sync + std::panic::RefUnwindSafe>) -RUSTLIB/src/rust/library/std/src/panic.rs:LL:COL (std::panic::catch_unwind::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>) +RUSTLIB/src/rust/library/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace) +RUSTLIB/src/rust/library/std/src/rt.rs:LL:COL (std::rt::lang_start::{closure#0}) +RUSTLIB/src/rust/library/core/src/ops/function.rs:LL:COL (std::ops::function::impls::call_once) +RUSTLIB/src/rust/library/std/src/panicking.rs:LL:COL (std::panicking::r#try::do_call) +RUSTLIB/src/rust/library/std/src/panicking.rs:LL:COL (std::panicking::r#try) +RUSTLIB/src/rust/library/std/src/panic.rs:LL:COL (std::panic::catch_unwind) RUSTLIB/src/rust/library/std/src/rt.rs:LL:COL (std::rt::lang_start_internal) -RUSTLIB/src/rust/library/std/src/rt.rs:LL:COL (std::rt::lang_start::<()>) +RUSTLIB/src/rust/library/std/src/rt.rs:LL:COL (std::rt::lang_start) diff --git a/tests/run-pass/backtrace-api.stdout b/tests/run-pass/backtrace-api.stdout index e4130ade62e0..453cf0b774a1 100644 --- a/tests/run-pass/backtrace-api.stdout +++ b/tests/run-pass/backtrace-api.stdout @@ -1,4 +1,4 @@ -$DIR/backtrace-api.rs:20:59 (func_c) -$DIR/backtrace-api.rs:19:53 (func_b::) -$DIR/backtrace-api.rs:18:50 (func_a) -$DIR/backtrace-api.rs:24:18 (main) +$DIR/backtrace-api.rs:21:59 (func_c) +$DIR/backtrace-api.rs:20:53 (func_b::) +$DIR/backtrace-api.rs:19:50 (func_a) +$DIR/backtrace-api.rs:25:18 (main) From eaf56c57e55503a3aa47333aac73162de6049a51 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 29 Sep 2020 10:31:41 +0200 Subject: [PATCH 2335/5092] rustup; adjust for rustc_driver changes --- benches/helpers/miri_helper.rs | 2 +- rust-version | 2 +- src/bin/miri-rustc-tests.rs | 1 + src/bin/miri.rs | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 2e71c7eb8b1d..a77f914c1c6b 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -55,5 +55,5 @@ pub fn run(filename: &str, bencher: &mut Bencher) { "--sysroot".to_string(), find_sysroot(), ]; - rustc_driver::run_compiler(args, &mut MiriCompilerCalls { bencher }, None, None).unwrap() + rustc_driver::run_compiler(args, &mut MiriCompilerCalls { bencher }, None, None, None).unwrap() } diff --git a/rust-version b/rust-version index 362f89b5d1fe..049d0f2c8782 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1ec980d225fff2346a1a631a7ffc88b37e9e18af +26373fb4baa9c5b8a7a1e2821fcfa930a85d327d diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 56d19e62749e..7c9dfbb277b9 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -145,6 +145,7 @@ fn main() { &mut MiriCompilerCalls { host_target }, None, Some(Box::new(buf)), + None, ); }); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 4363f9a150a7..e3317d0d4d68 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -157,7 +157,7 @@ fn run_compiler(mut args: Vec, callbacks: &mut (dyn rustc_driver::Callba // Invoke compiler, and handle return code. let exit_code = rustc_driver::catch_with_exit_code(move || { - rustc_driver::run_compiler(&args, callbacks, None, None) + rustc_driver::run_compiler(&args, callbacks, None, None, None) }); std::process::exit(exit_code) } From 17e16aad62ad06ea1f8bc1bac81c73528f48a3d3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 30 Sep 2020 09:59:28 +0200 Subject: [PATCH 2336/5092] normalize backtrace stderr even more --- rust-version | 2 +- tests/run-pass/backtrace-api.rs | 2 +- tests/run-pass/backtrace-api.stderr | 18 +++++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/rust-version b/rust-version index 049d0f2c8782..1b85e41c8ba2 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -26373fb4baa9c5b8a7a1e2821fcfa930a85d327d +c0127e4dbf3a9d3a67ddb1da19f8441019aab8f8 diff --git a/tests/run-pass/backtrace-api.rs b/tests/run-pass/backtrace-api.rs index be1971efe28d..80e64c2e1c8b 100644 --- a/tests/run-pass/backtrace-api.rs +++ b/tests/run-pass/backtrace-api.rs @@ -1,4 +1,4 @@ -// normalize-stderr-test ".*rustlib" -> "RUSTLIB" +// normalize-stderr-test ".*/(rust|checkout)/library/" -> "RUSTLIB/" // normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL " // normalize-stderr-test "::<.*>" -> "" diff --git a/tests/run-pass/backtrace-api.stderr b/tests/run-pass/backtrace-api.stderr index ea25267a1b14..15851a1cc725 100644 --- a/tests/run-pass/backtrace-api.stderr +++ b/tests/run-pass/backtrace-api.stderr @@ -2,12 +2,12 @@ $DIR/backtrace-api.rs:21:59 (func_c) $DIR/backtrace-api.rs:20:53 (func_b) $DIR/backtrace-api.rs:19:50 (func_a) $DIR/backtrace-api.rs:25:18 (main) -RUSTLIB/src/rust/library/core/src/ops/function.rs:LL:COL (>::call_once - shim(fn())) -RUSTLIB/src/rust/library/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace) -RUSTLIB/src/rust/library/std/src/rt.rs:LL:COL (std::rt::lang_start::{closure#0}) -RUSTLIB/src/rust/library/core/src/ops/function.rs:LL:COL (std::ops::function::impls::call_once) -RUSTLIB/src/rust/library/std/src/panicking.rs:LL:COL (std::panicking::r#try::do_call) -RUSTLIB/src/rust/library/std/src/panicking.rs:LL:COL (std::panicking::r#try) -RUSTLIB/src/rust/library/std/src/panic.rs:LL:COL (std::panic::catch_unwind) -RUSTLIB/src/rust/library/std/src/rt.rs:LL:COL (std::rt::lang_start_internal) -RUSTLIB/src/rust/library/std/src/rt.rs:LL:COL (std::rt::lang_start) +RUSTLIB/core/src/ops/function.rs:LL:COL (>::call_once - shim(fn())) +RUSTLIB/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace) +RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start::{closure#0}) +RUSTLIB/core/src/ops/function.rs:LL:COL (std::ops::function::impls::call_once) +RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try::do_call) +RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try) +RUSTLIB/std/src/panic.rs:LL:COL (std::panic::catch_unwind) +RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start_internal) +RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start) From 1ffc5bb5633dd9bf3a38766fbf78ddc76d8b0bc8 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 1 Oct 2020 20:47:31 +0200 Subject: [PATCH 2337/5092] Implement futex_wait and futex_wake. This does not support futex_wait with a timeout yet. --- src/shims/posix/linux/foreign_items.rs | 67 ++++++++++++++++++++++++++ src/sync.rs | 27 +++++++++++ 2 files changed, 94 insertions(+) diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 357c55c926f1..8434d7bfa806 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -1,4 +1,5 @@ use rustc_middle::mir; +use rustc_target::abi::{Align, Size}; use crate::*; use crate::helpers::check_arg_count; @@ -120,6 +121,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .eval_libc("SYS_statx")? .to_machine_usize(this)?; + let sys_futex = this + .eval_libc("SYS_futex")? + .to_machine_usize(this)?; + if args.is_empty() { throw_ub_format!("incorrect number of arguments for syscall: got 0, expected at least 1"); } @@ -139,6 +144,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.linux_statx(dirfd, pathname, flags, mask, statxbuf)?; this.write_scalar(Scalar::from_machine_isize(result.into(), this), dest)?; } + // `futex` is used by some synchonization primitives. + id if id == sys_futex => { + futex(this, args, dest)?; + } id => throw_unsup_format!("miri does not support syscall ID {}", id), } } @@ -192,3 +201,61 @@ fn getrandom<'tcx>( this.write_scalar(Scalar::from_machine_usize(len, this), dest)?; Ok(()) } + +fn futex<'tcx>( + this: &mut MiriEvalContext<'_, 'tcx>, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag>, +) -> InterpResult<'tcx> { + if args.len() < 4 { + throw_ub_format!("incorrect number of arguments for futex syscall: got {}, expected at least 4", args.len()); + } + let addr = this.read_scalar(args[1])?.check_init()?; + let op = this.read_scalar(args[2])?.to_i32()?; + let val = this.read_scalar(args[3])?.to_i32()?; + + this.memory.check_ptr_access(addr, Size::from_bytes(4), Align::from_bytes(4).unwrap())?; + + let addr = addr.assert_ptr(); + + let thread = this.get_active_thread(); + + let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?; + let futex_wait = this.eval_libc_i32("FUTEX_WAIT")?; + let futex_wake = this.eval_libc_i32("FUTEX_WAKE")?; + + match op & !futex_private { + op if op == futex_wait => { + if args.len() < 5 { + throw_ub_format!("incorrect number of arguments for FUTEX_WAIT syscall: got {}, expected at least 5", args.len()); + } + let timeout = this.read_scalar(args[4])?.check_init()?; + if !this.is_null(timeout)? { + throw_ub_format!("miri does not support timeouts for futex operations"); + } + let futex_val = this.read_scalar_at_offset(args[1], 0, this.machine.layouts.i32)?.to_i32()?; + if val == futex_val { + this.block_thread(thread); + this.futex_wait(addr, thread); + } else { + let eagain = this.eval_libc("EAGAIN")?; + this.set_last_error(eagain)?; + } + } + op if op == futex_wake => { + let mut n = 0; + for _ in 0..val { + if let Some(thread) = this.futex_wake(addr) { + this.unblock_thread(thread); + n += 1; + } else { + break; + } + } + this.write_scalar(Scalar::from_i32(n), dest)?; + } + op => throw_unsup_format!("miri does not support SYS_futex operation {}", op), + } + + Ok(()) +} diff --git a/src/sync.rs b/src/sync.rs index 7e3c27b386df..d5594fb9eca4 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -96,12 +96,26 @@ struct Condvar { waiters: VecDeque, } +/// The futex state. +#[derive(Default, Debug)] +struct Futex { + waiters: VecDeque, +} + +/// A thread waiting on a futex. +#[derive(Debug)] +struct FutexWaiter { + /// The thread that is waiting on this futex. + thread: ThreadId, +} + /// The state of all synchronization variables. #[derive(Default, Debug)] pub(super) struct SynchronizationState { mutexes: IndexVec, rwlocks: IndexVec, condvars: IndexVec, + futexes: HashMap, Futex>, } // Private extension trait for local helper methods @@ -403,4 +417,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.machine.threads.sync.condvars[id].waiters.retain(|waiter| waiter.thread != thread); } + + fn futex_wait(&mut self, addr: Pointer, thread: ThreadId) { + let this = self.eval_context_mut(); + let waiters = &mut this.machine.threads.sync.futexes.entry(addr).or_default().waiters; + assert!(waiters.iter().all(|waiter| waiter.thread != thread), "thread is already waiting"); + waiters.push_back(FutexWaiter { thread }); + } + + fn futex_wake(&mut self, addr: Pointer) -> Option { + let this = self.eval_context_mut(); + let waiters = &mut this.machine.threads.sync.futexes.get_mut(&addr)?.waiters; + waiters.pop_front().map(|waiter| waiter.thread) + } } From 281a5382262af7f6d5d9caf677b4c7f2315dd359 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 1 Oct 2020 21:03:36 +0200 Subject: [PATCH 2338/5092] Move futex syscall to its own file. --- src/shims/posix/linux/foreign_items.rs | 60 +------------------------ src/shims/posix/linux/mod.rs | 1 + src/shims/posix/linux/sync.rs | 61 ++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 59 deletions(-) create mode 100644 src/shims/posix/linux/sync.rs diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 8434d7bfa806..2241b8d4b3b1 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -1,9 +1,9 @@ use rustc_middle::mir; -use rustc_target::abi::{Align, Size}; use crate::*; use crate::helpers::check_arg_count; use shims::posix::fs::EvalContextExt as _; +use shims::posix::linux::sync::futex; use shims::posix::sync::EvalContextExt as _; use shims::posix::thread::EvalContextExt as _; @@ -201,61 +201,3 @@ fn getrandom<'tcx>( this.write_scalar(Scalar::from_machine_usize(len, this), dest)?; Ok(()) } - -fn futex<'tcx>( - this: &mut MiriEvalContext<'_, 'tcx>, - args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag>, -) -> InterpResult<'tcx> { - if args.len() < 4 { - throw_ub_format!("incorrect number of arguments for futex syscall: got {}, expected at least 4", args.len()); - } - let addr = this.read_scalar(args[1])?.check_init()?; - let op = this.read_scalar(args[2])?.to_i32()?; - let val = this.read_scalar(args[3])?.to_i32()?; - - this.memory.check_ptr_access(addr, Size::from_bytes(4), Align::from_bytes(4).unwrap())?; - - let addr = addr.assert_ptr(); - - let thread = this.get_active_thread(); - - let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?; - let futex_wait = this.eval_libc_i32("FUTEX_WAIT")?; - let futex_wake = this.eval_libc_i32("FUTEX_WAKE")?; - - match op & !futex_private { - op if op == futex_wait => { - if args.len() < 5 { - throw_ub_format!("incorrect number of arguments for FUTEX_WAIT syscall: got {}, expected at least 5", args.len()); - } - let timeout = this.read_scalar(args[4])?.check_init()?; - if !this.is_null(timeout)? { - throw_ub_format!("miri does not support timeouts for futex operations"); - } - let futex_val = this.read_scalar_at_offset(args[1], 0, this.machine.layouts.i32)?.to_i32()?; - if val == futex_val { - this.block_thread(thread); - this.futex_wait(addr, thread); - } else { - let eagain = this.eval_libc("EAGAIN")?; - this.set_last_error(eagain)?; - } - } - op if op == futex_wake => { - let mut n = 0; - for _ in 0..val { - if let Some(thread) = this.futex_wake(addr) { - this.unblock_thread(thread); - n += 1; - } else { - break; - } - } - this.write_scalar(Scalar::from_i32(n), dest)?; - } - op => throw_unsup_format!("miri does not support SYS_futex operation {}", op), - } - - Ok(()) -} diff --git a/src/shims/posix/linux/mod.rs b/src/shims/posix/linux/mod.rs index cadd6a8ea384..eba4a517cf5d 100644 --- a/src/shims/posix/linux/mod.rs +++ b/src/shims/posix/linux/mod.rs @@ -1,2 +1,3 @@ pub mod foreign_items; pub mod dlsym; +pub mod sync; diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs new file mode 100644 index 000000000000..f9cfb3b8a2b0 --- /dev/null +++ b/src/shims/posix/linux/sync.rs @@ -0,0 +1,61 @@ +use crate::*; +use rustc_target::abi::{Align, Size}; + +/// Implementation of the SYS_futex syscall. +pub fn futex<'tcx>( + this: &mut MiriEvalContext<'_, 'tcx>, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag>, +) -> InterpResult<'tcx> { + if args.len() < 4 { + throw_ub_format!("incorrect number of arguments for futex syscall: got {}, expected at least 4", args.len()); + } + let addr = this.read_scalar(args[1])?.check_init()?; + let op = this.read_scalar(args[2])?.to_i32()?; + let val = this.read_scalar(args[3])?.to_i32()?; + + this.memory.check_ptr_access(addr, Size::from_bytes(4), Align::from_bytes(4).unwrap())?; + + let addr = addr.assert_ptr(); + + let thread = this.get_active_thread(); + + let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?; + let futex_wait = this.eval_libc_i32("FUTEX_WAIT")?; + let futex_wake = this.eval_libc_i32("FUTEX_WAKE")?; + + match op & !futex_private { + op if op == futex_wait => { + if args.len() < 5 { + throw_ub_format!("incorrect number of arguments for FUTEX_WAIT syscall: got {}, expected at least 5", args.len()); + } + let timeout = this.read_scalar(args[4])?.check_init()?; + if !this.is_null(timeout)? { + throw_ub_format!("miri does not support timeouts for futex operations"); + } + let futex_val = this.read_scalar_at_offset(args[1], 0, this.machine.layouts.i32)?.to_i32()?; + if val == futex_val { + this.block_thread(thread); + this.futex_wait(addr, thread); + } else { + let eagain = this.eval_libc("EAGAIN")?; + this.set_last_error(eagain)?; + } + } + op if op == futex_wake => { + let mut n = 0; + for _ in 0..val { + if let Some(thread) = this.futex_wake(addr) { + this.unblock_thread(thread); + n += 1; + } else { + break; + } + } + this.write_scalar(Scalar::from_i32(n), dest)?; + } + op => throw_unsup_format!("miri does not support SYS_futex operation {}", op), + } + + Ok(()) +} From 6c2f36eb6b6f35f94bc006c663d1622ebd71ff87 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 1 Oct 2020 21:06:16 +0200 Subject: [PATCH 2339/5092] Erase tag from futex pointers. --- src/shims/posix/linux/sync.rs | 2 +- src/sync.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index f9cfb3b8a2b0..23d3330c74e9 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -16,7 +16,7 @@ pub fn futex<'tcx>( this.memory.check_ptr_access(addr, Size::from_bytes(4), Align::from_bytes(4).unwrap())?; - let addr = addr.assert_ptr(); + let addr = addr.assert_ptr().erase_tag(); let thread = this.get_active_thread(); diff --git a/src/sync.rs b/src/sync.rs index d5594fb9eca4..986857221b62 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -115,7 +115,7 @@ pub(super) struct SynchronizationState { mutexes: IndexVec, rwlocks: IndexVec, condvars: IndexVec, - futexes: HashMap, Futex>, + futexes: HashMap, } // Private extension trait for local helper methods @@ -418,14 +418,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.threads.sync.condvars[id].waiters.retain(|waiter| waiter.thread != thread); } - fn futex_wait(&mut self, addr: Pointer, thread: ThreadId) { + fn futex_wait(&mut self, addr: Pointer, thread: ThreadId) { let this = self.eval_context_mut(); let waiters = &mut this.machine.threads.sync.futexes.entry(addr).or_default().waiters; assert!(waiters.iter().all(|waiter| waiter.thread != thread), "thread is already waiting"); waiters.push_back(FutexWaiter { thread }); } - fn futex_wake(&mut self, addr: Pointer) -> Option { + fn futex_wake(&mut self, addr: Pointer) -> Option { let this = self.eval_context_mut(); let waiters = &mut this.machine.threads.sync.futexes.get_mut(&addr)?.waiters; waiters.pop_front().map(|waiter| waiter.thread) From 69cea1dc92695d317145fa057529f8c679e3cfc0 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 1 Oct 2020 22:57:27 +0200 Subject: [PATCH 2340/5092] Only check futex pointer in futex_wait and not in futex_wake. futex_wake doesn't access the futex itself, so should accept pointers to memory that's no longer there. --- src/shims/posix/linux/sync.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 23d3330c74e9..d92fc0441c49 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -10,14 +10,12 @@ pub fn futex<'tcx>( if args.len() < 4 { throw_ub_format!("incorrect number of arguments for futex syscall: got {}, expected at least 4", args.len()); } - let addr = this.read_scalar(args[1])?.check_init()?; + let addr = args[1]; + let addr_scalar = this.read_scalar(addr)?.check_init()?; + let futex_ptr = this.force_ptr(addr_scalar)?.erase_tag(); let op = this.read_scalar(args[2])?.to_i32()?; let val = this.read_scalar(args[3])?.to_i32()?; - this.memory.check_ptr_access(addr, Size::from_bytes(4), Align::from_bytes(4).unwrap())?; - - let addr = addr.assert_ptr().erase_tag(); - let thread = this.get_active_thread(); let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?; @@ -33,10 +31,11 @@ pub fn futex<'tcx>( if !this.is_null(timeout)? { throw_ub_format!("miri does not support timeouts for futex operations"); } + this.memory.check_ptr_access(addr_scalar, Size::from_bytes(4), Align::from_bytes(4).unwrap())?; let futex_val = this.read_scalar_at_offset(args[1], 0, this.machine.layouts.i32)?.to_i32()?; if val == futex_val { this.block_thread(thread); - this.futex_wait(addr, thread); + this.futex_wait(futex_ptr, thread); } else { let eagain = this.eval_libc("EAGAIN")?; this.set_last_error(eagain)?; @@ -45,7 +44,7 @@ pub fn futex<'tcx>( op if op == futex_wake => { let mut n = 0; for _ in 0..val { - if let Some(thread) = this.futex_wake(addr) { + if let Some(thread) = this.futex_wake(futex_ptr) { this.unblock_thread(thread); n += 1; } else { From 1c582e7c967577d2760e05dee39cf57ea72c3606 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 2 Oct 2020 01:49:20 +0200 Subject: [PATCH 2341/5092] Return correct value from futex_wait. --- src/shims/posix/linux/sync.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index d92fc0441c49..0892eab46739 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -36,9 +36,11 @@ pub fn futex<'tcx>( if val == futex_val { this.block_thread(thread); this.futex_wait(futex_ptr, thread); + this.write_scalar(Scalar::from_i32(0), dest)?; } else { let eagain = this.eval_libc("EAGAIN")?; this.set_last_error(eagain)?; + this.write_scalar(Scalar::from_i32(-1), dest)?; } } op if op == futex_wake => { From c2fa27c3b8bfd99240bda23fff1b09bb78c5e7fa Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 2 Oct 2020 10:46:57 +0200 Subject: [PATCH 2342/5092] Check maximum amount of arguments to SYS_futex. --- src/shims/posix/linux/sync.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 0892eab46739..a891a7dd9946 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -7,8 +7,11 @@ pub fn futex<'tcx>( args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { - if args.len() < 4 { - throw_ub_format!("incorrect number of arguments for futex syscall: got {}, expected at least 4", args.len()); + // The amount of arguments used depends on the type of futex operation. + // Some users always pass all arguments, even the unused ones, due to how they wrap this syscall in their code base. + // Some other users pass only the arguments the operation actually needs. So we don't use `check_arg_count` here. + if !(4..=7).contains(&args.len()) { + throw_ub_format!("incorrect number of arguments for futex syscall: got {}, expected between 4 and 7 (inclusive)", args.len()); } let addr = args[1]; let addr_scalar = this.read_scalar(addr)?.check_init()?; From 712e8006b3c3a055b53326196081df11da123d38 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 2 Oct 2020 10:47:36 +0200 Subject: [PATCH 2343/5092] Improve handling of the `addr` argument in SYS_futex. --- src/shims/posix/linux/sync.rs | 18 +++++++++++++----- src/sync.rs | 8 ++++---- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index a891a7dd9946..2b31961559d1 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -13,12 +13,18 @@ pub fn futex<'tcx>( if !(4..=7).contains(&args.len()) { throw_ub_format!("incorrect number of arguments for futex syscall: got {}, expected between 4 and 7 (inclusive)", args.len()); } - let addr = args[1]; - let addr_scalar = this.read_scalar(addr)?.check_init()?; - let futex_ptr = this.force_ptr(addr_scalar)?.erase_tag(); + + // The first three arguments (after the syscall number itself) are the same to all futex operations: + // (int *addr, int op, int val). + // Although note that the first one is often passed as a different pointer type, e.g. `*const AtomicU32` or `*mut u32`. + let addr = this.deref_operand(args[1])?; let op = this.read_scalar(args[2])?.to_i32()?; let val = this.read_scalar(args[3])?.to_i32()?; + // The raw pointer value is used to identify the mutex. + // Not all mutex operations actually read from this address or even require this address to exist. + let futex_ptr = addr.ptr.assert_ptr(); + let thread = this.get_active_thread(); let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?; @@ -34,8 +40,10 @@ pub fn futex<'tcx>( if !this.is_null(timeout)? { throw_ub_format!("miri does not support timeouts for futex operations"); } - this.memory.check_ptr_access(addr_scalar, Size::from_bytes(4), Align::from_bytes(4).unwrap())?; - let futex_val = this.read_scalar_at_offset(args[1], 0, this.machine.layouts.i32)?.to_i32()?; + // Check the pointer for alignment. Atomic operations are only available for fully aligned values. + this.memory.check_ptr_access(addr.ptr.into(), Size::from_bytes(4), Align::from_bytes(4).unwrap())?; + // Read an `i32` through the pointer, regardless of any wrapper types (e.g. `AtomicI32`). + let futex_val = this.read_scalar(addr.offset(Size::ZERO, MemPlaceMeta::None, this.machine.layouts.i32, this)?.into())?.to_i32()?; if val == futex_val { this.block_thread(thread); this.futex_wait(futex_ptr, thread); diff --git a/src/sync.rs b/src/sync.rs index 986857221b62..f8b6f99f1e03 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -418,16 +418,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.threads.sync.condvars[id].waiters.retain(|waiter| waiter.thread != thread); } - fn futex_wait(&mut self, addr: Pointer, thread: ThreadId) { + fn futex_wait(&mut self, addr: Pointer, thread: ThreadId) { let this = self.eval_context_mut(); - let waiters = &mut this.machine.threads.sync.futexes.entry(addr).or_default().waiters; + let waiters = &mut this.machine.threads.sync.futexes.entry(addr.erase_tag()).or_default().waiters; assert!(waiters.iter().all(|waiter| waiter.thread != thread), "thread is already waiting"); waiters.push_back(FutexWaiter { thread }); } - fn futex_wake(&mut self, addr: Pointer) -> Option { + fn futex_wake(&mut self, addr: Pointer) -> Option { let this = self.eval_context_mut(); - let waiters = &mut this.machine.threads.sync.futexes.get_mut(&addr)?.waiters; + let waiters = &mut this.machine.threads.sync.futexes.get_mut(&addr.erase_tag())?.waiters; waiters.pop_front().map(|waiter| waiter.thread) } } From ee3eb4b223f823b5bf7df7ece97621aa36315fdc Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 2 Oct 2020 10:47:53 +0200 Subject: [PATCH 2344/5092] Add comments that document SYS_futex better. --- src/shims/posix/linux/sync.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 2b31961559d1..8da6921653ce 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -31,13 +31,20 @@ pub fn futex<'tcx>( let futex_wait = this.eval_libc_i32("FUTEX_WAIT")?; let futex_wake = this.eval_libc_i32("FUTEX_WAKE")?; + // FUTEX_PRIVATE enables an optimization that stops it from working across processes. + // Miri doesn't support that anyway, so we ignore that flag. match op & !futex_private { + // FUTEX_WAIT: (int *addr, int op = FUTEX_WAIT, int val, const timespec *timeout) + // Blocks the thread if *addr still equals val. Wakes up when FUTEX_WAKE is called on the same address, + // or *timeout expires. `timeout == null` for an infinite timeout. op if op == futex_wait => { if args.len() < 5 { throw_ub_format!("incorrect number of arguments for FUTEX_WAIT syscall: got {}, expected at least 5", args.len()); } let timeout = this.read_scalar(args[4])?.check_init()?; if !this.is_null(timeout)? { + // FIXME: Implement timeouts. The condvar waiting code is probably a good example to start with. + // Note that a triggered timeout should have this syscall return with -1 and errno set to ETIMEOUT. throw_ub_format!("miri does not support timeouts for futex operations"); } // Check the pointer for alignment. Atomic operations are only available for fully aligned values. @@ -45,15 +52,23 @@ pub fn futex<'tcx>( // Read an `i32` through the pointer, regardless of any wrapper types (e.g. `AtomicI32`). let futex_val = this.read_scalar(addr.offset(Size::ZERO, MemPlaceMeta::None, this.machine.layouts.i32, this)?.into())?.to_i32()?; if val == futex_val { + // The value still matches, so we block the trait make it wait for FUTEX_WAKE. this.block_thread(thread); this.futex_wait(futex_ptr, thread); + // Succesfully waking up from FUTEX_WAIT always returns zero. this.write_scalar(Scalar::from_i32(0), dest)?; } else { + // The futex value doesn't match the expected value, so we return failure + // right away without sleeping: -1 and errno set to EAGAIN. let eagain = this.eval_libc("EAGAIN")?; this.set_last_error(eagain)?; this.write_scalar(Scalar::from_i32(-1), dest)?; } } + // FUTEX_WAKE: (int *addr, int op = FUTEX_WAKE, int val) + // Wakes at most `val` threads waiting on the futex at `addr`. + // Returns the amount of threads woken up. + // Does not access the futex value at *addr. op if op == futex_wake => { let mut n = 0; for _ in 0..val { From dabd98056778238e9e1b9f0668183c7cb635d2b1 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 2 Oct 2020 20:53:31 +0200 Subject: [PATCH 2345/5092] Update note about number of arguments to SYS_futex. --- src/shims/posix/linux/sync.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 8da6921653ce..ae9058368670 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -8,8 +8,13 @@ pub fn futex<'tcx>( dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { // The amount of arguments used depends on the type of futex operation. - // Some users always pass all arguments, even the unused ones, due to how they wrap this syscall in their code base. - // Some other users pass only the arguments the operation actually needs. So we don't use `check_arg_count` here. + // The full futex syscall takes six arguments (excluding the syscall + // number), which is also the maximum amount of arguments a linux syscall + // can take on most architectures. + // However, not all futex operations use all six arguments. The unused ones + // may or may not be left out from the `syscall()` call. + // Therefore we don't use `check_arg_count` here, but only check for the + // number of arguments to fall within a range. if !(4..=7).contains(&args.len()) { throw_ub_format!("incorrect number of arguments for futex syscall: got {}, expected between 4 and 7 (inclusive)", args.len()); } From 422b5053a9a8730de46b6c22997a04afdd2d4d08 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 2 Oct 2020 20:56:01 +0200 Subject: [PATCH 2346/5092] Add note about arguments in futex implementation. Co-authored-by: Ralf Jung --- src/shims/posix/linux/sync.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index ae9058368670..e01e716879a8 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -21,6 +21,7 @@ pub fn futex<'tcx>( // The first three arguments (after the syscall number itself) are the same to all futex operations: // (int *addr, int op, int val). + // We checked above that these definitely exist. // Although note that the first one is often passed as a different pointer type, e.g. `*const AtomicU32` or `*mut u32`. let addr = this.deref_operand(args[1])?; let op = this.read_scalar(args[2])?.to_i32()?; From d5b3f54b46125a3da9af7e466e004b6905bc2f26 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 2 Oct 2020 21:59:11 +0200 Subject: [PATCH 2347/5092] Use force_ptr in futex implementation. --- src/shims/posix/linux/sync.rs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index e01e716879a8..1cfcb65bdc19 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -22,15 +22,17 @@ pub fn futex<'tcx>( // The first three arguments (after the syscall number itself) are the same to all futex operations: // (int *addr, int op, int val). // We checked above that these definitely exist. - // Although note that the first one is often passed as a different pointer type, e.g. `*const AtomicU32` or `*mut u32`. - let addr = this.deref_operand(args[1])?; + // + // `addr` is used to identify the mutex, but note that not all futex + // operations actually read from this addres or even require this address + // to exist. Also, the type of `addr` is not consistent. The API requires + // it to be a 4-byte aligned pointer, and will use the 4 bytes at the given + // address as an (atomic) i32. It's not uncommon for `addr` to be passed as + // another type than `*mut i32`, such as `*const AtomicI32`. + let addr = this.force_ptr(this.read_scalar(args[1])?.check_init()?)?; let op = this.read_scalar(args[2])?.to_i32()?; let val = this.read_scalar(args[3])?.to_i32()?; - // The raw pointer value is used to identify the mutex. - // Not all mutex operations actually read from this address or even require this address to exist. - let futex_ptr = addr.ptr.assert_ptr(); - let thread = this.get_active_thread(); let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?; @@ -53,14 +55,15 @@ pub fn futex<'tcx>( // Note that a triggered timeout should have this syscall return with -1 and errno set to ETIMEOUT. throw_ub_format!("miri does not support timeouts for futex operations"); } - // Check the pointer for alignment. Atomic operations are only available for fully aligned values. - this.memory.check_ptr_access(addr.ptr.into(), Size::from_bytes(4), Align::from_bytes(4).unwrap())?; + // Check the pointer for alignment and validity. + // Atomic operations are only available for fully aligned values. + this.memory.check_ptr_access(addr.into(), Size::from_bytes(4), Align::from_bytes(4).unwrap())?; // Read an `i32` through the pointer, regardless of any wrapper types (e.g. `AtomicI32`). - let futex_val = this.read_scalar(addr.offset(Size::ZERO, MemPlaceMeta::None, this.machine.layouts.i32, this)?.into())?.to_i32()?; + let futex_val = this.memory.get_raw(addr.alloc_id)?.read_scalar(this, addr, Size::from_bytes(4))?.to_i32()?; if val == futex_val { // The value still matches, so we block the trait make it wait for FUTEX_WAKE. this.block_thread(thread); - this.futex_wait(futex_ptr, thread); + this.futex_wait(addr, thread); // Succesfully waking up from FUTEX_WAIT always returns zero. this.write_scalar(Scalar::from_i32(0), dest)?; } else { @@ -78,7 +81,7 @@ pub fn futex<'tcx>( op if op == futex_wake => { let mut n = 0; for _ in 0..val { - if let Some(thread) = this.futex_wake(futex_ptr) { + if let Some(thread) = this.futex_wake(addr) { this.unblock_thread(thread); n += 1; } else { From e64ead2f46144963bc18ba34477422f39577f7f6 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 2 Oct 2020 23:34:14 +0200 Subject: [PATCH 2348/5092] Implement timeouts for FUTEX_WAIT. --- src/shims/posix/linux/sync.rs | 47 +++++++++++++++++++++++++++++------ src/sync.rs | 7 ++++++ 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 1cfcb65bdc19..4201ef3f4790 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -1,5 +1,7 @@ +use crate::thread::Time; use crate::*; use rustc_target::abi::{Align, Size}; +use std::time::{Instant, SystemTime}; /// Implementation of the SYS_futex syscall. pub fn futex<'tcx>( @@ -38,6 +40,7 @@ pub fn futex<'tcx>( let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?; let futex_wait = this.eval_libc_i32("FUTEX_WAIT")?; let futex_wake = this.eval_libc_i32("FUTEX_WAKE")?; + let futex_realtime = this.eval_libc_i32("FUTEX_CLOCK_REALTIME")?; // FUTEX_PRIVATE enables an optimization that stops it from working across processes. // Miri doesn't support that anyway, so we ignore that flag. @@ -45,16 +48,29 @@ pub fn futex<'tcx>( // FUTEX_WAIT: (int *addr, int op = FUTEX_WAIT, int val, const timespec *timeout) // Blocks the thread if *addr still equals val. Wakes up when FUTEX_WAKE is called on the same address, // or *timeout expires. `timeout == null` for an infinite timeout. - op if op == futex_wait => { + op if op & !futex_realtime == futex_wait => { if args.len() < 5 { throw_ub_format!("incorrect number of arguments for FUTEX_WAIT syscall: got {}, expected at least 5", args.len()); } - let timeout = this.read_scalar(args[4])?.check_init()?; - if !this.is_null(timeout)? { - // FIXME: Implement timeouts. The condvar waiting code is probably a good example to start with. - // Note that a triggered timeout should have this syscall return with -1 and errno set to ETIMEOUT. - throw_ub_format!("miri does not support timeouts for futex operations"); - } + let timeout = args[4]; + let timeout_time = if this.is_null(this.read_scalar(timeout)?.check_init()?)? { + None + } else { + let duration = match this.read_timespec(timeout)? { + Some(duration) => duration, + None => { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + this.write_scalar(Scalar::from_i32(-1), dest)?; + return Ok(()); + } + }; + Some(if op & futex_realtime != 0 { + Time::RealTime(SystemTime::now().checked_add(duration).unwrap()) + } else { + Time::Monotonic(Instant::now().checked_add(duration).unwrap()) + }) + }; // Check the pointer for alignment and validity. // Atomic operations are only available for fully aligned values. this.memory.check_ptr_access(addr.into(), Size::from_bytes(4), Align::from_bytes(4).unwrap())?; @@ -66,6 +82,22 @@ pub fn futex<'tcx>( this.futex_wait(addr, thread); // Succesfully waking up from FUTEX_WAIT always returns zero. this.write_scalar(Scalar::from_i32(0), dest)?; + // Register a timeout callback if a timeout was specified. + // This callback will override the return value when the timeout triggers. + if let Some(timeout_time) = timeout_time { + this.register_timeout_callback( + thread, + timeout_time, + Box::new(move |this| { + this.unblock_thread(thread); + this.futex_remove_waiter(addr, thread); + let etimedout = this.eval_libc("ETIMEDOUT")?; + this.set_last_error(etimedout)?; + this.write_scalar(Scalar::from_i32(-1), dest)?; + Ok(()) + }), + ); + } } else { // The futex value doesn't match the expected value, so we return failure // right away without sleeping: -1 and errno set to EAGAIN. @@ -83,6 +115,7 @@ pub fn futex<'tcx>( for _ in 0..val { if let Some(thread) = this.futex_wake(addr) { this.unblock_thread(thread); + this.unregister_timeout_callback_if_exists(thread); n += 1; } else { break; diff --git a/src/sync.rs b/src/sync.rs index f8b6f99f1e03..0c12da8d6845 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -430,4 +430,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let waiters = &mut this.machine.threads.sync.futexes.get_mut(&addr.erase_tag())?.waiters; waiters.pop_front().map(|waiter| waiter.thread) } + + fn futex_remove_waiter(&mut self, addr: Pointer, thread: ThreadId) { + let this = self.eval_context_mut(); + if let Some(futex) = this.machine.threads.sync.futexes.get_mut(&addr.erase_tag()) { + futex.waiters.retain(|waiter| waiter.thread != thread); + } + } } From 81138825b370e112714d1f16e8f76835d57d8fdf Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 2 Oct 2020 23:35:00 +0200 Subject: [PATCH 2349/5092] Add park/park_timeout/unpark test. --- tests/run-pass/concurrency/parking.rs | 37 +++++++++++++++++++++++ tests/run-pass/concurrency/parking.stderr | 2 ++ 2 files changed, 39 insertions(+) create mode 100644 tests/run-pass/concurrency/parking.rs create mode 100644 tests/run-pass/concurrency/parking.stderr diff --git a/tests/run-pass/concurrency/parking.rs b/tests/run-pass/concurrency/parking.rs new file mode 100644 index 000000000000..1ed742931fe6 --- /dev/null +++ b/tests/run-pass/concurrency/parking.rs @@ -0,0 +1,37 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-isolation + +use std::thread; +use std::time::{Duration, Instant}; + +// Normally, waiting in park/park_timeout may spuriously wake up early, but we +// know Miri's timed synchronization primitives do not do that. + +fn park_timeout() { + let start = Instant::now(); + + thread::park_timeout(Duration::from_millis(200)); + + assert!((200..500).contains(&start.elapsed().as_millis())); +} + +fn park_unpark() { + let t1 = thread::current(); + let t2 = thread::spawn(move || { + thread::park(); + thread::sleep(Duration::from_millis(200)); + t1.unpark(); + }); + + let start = Instant::now(); + + t2.thread().unpark(); + thread::park(); + + assert!((200..500).contains(&start.elapsed().as_millis())); +} + +fn main() { + park_timeout(); + park_unpark(); +} diff --git a/tests/run-pass/concurrency/parking.stderr b/tests/run-pass/concurrency/parking.stderr new file mode 100644 index 000000000000..2dbfb7721d36 --- /dev/null +++ b/tests/run-pass/concurrency/parking.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental. For example, Miri does not detect data races yet. + From c9627b25fb840adfd860aa9e417cc089bd7dc264 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 3 Oct 2020 00:40:53 +0200 Subject: [PATCH 2350/5092] Use correct return type for syscall(SYS_futex). --- src/shims/posix/linux/sync.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 4201ef3f4790..17fd5f0eefb7 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -61,7 +61,7 @@ pub fn futex<'tcx>( None => { let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; - this.write_scalar(Scalar::from_i32(-1), dest)?; + this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?; return Ok(()); } }; @@ -81,7 +81,7 @@ pub fn futex<'tcx>( this.block_thread(thread); this.futex_wait(addr, thread); // Succesfully waking up from FUTEX_WAIT always returns zero. - this.write_scalar(Scalar::from_i32(0), dest)?; + this.write_scalar(Scalar::from_machine_isize(0, this), dest)?; // Register a timeout callback if a timeout was specified. // This callback will override the return value when the timeout triggers. if let Some(timeout_time) = timeout_time { @@ -93,7 +93,7 @@ pub fn futex<'tcx>( this.futex_remove_waiter(addr, thread); let etimedout = this.eval_libc("ETIMEDOUT")?; this.set_last_error(etimedout)?; - this.write_scalar(Scalar::from_i32(-1), dest)?; + this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?; Ok(()) }), ); @@ -103,7 +103,7 @@ pub fn futex<'tcx>( // right away without sleeping: -1 and errno set to EAGAIN. let eagain = this.eval_libc("EAGAIN")?; this.set_last_error(eagain)?; - this.write_scalar(Scalar::from_i32(-1), dest)?; + this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?; } } // FUTEX_WAKE: (int *addr, int op = FUTEX_WAKE, int val) @@ -121,7 +121,7 @@ pub fn futex<'tcx>( break; } } - this.write_scalar(Scalar::from_i32(n), dest)?; + this.write_scalar(Scalar::from_machine_isize(n, this), dest)?; } op => throw_unsup_format!("miri does not support SYS_futex operation {}", op), } From 924fd56944bbd9138e8e1b59a1a8d5a329ddeb1d Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 3 Oct 2020 11:35:13 +0200 Subject: [PATCH 2351/5092] Only allow FUTEX_WAIT with timeout when isoloation is disabled. --- src/shims/posix/linux/sync.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 17fd5f0eefb7..386678508337 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -65,6 +65,7 @@ pub fn futex<'tcx>( return Ok(()); } }; + this.check_no_isolation("FUTEX_WAIT with timeout")?; Some(if op & futex_realtime != 0 { Time::RealTime(SystemTime::now().checked_add(duration).unwrap()) } else { From 66282754ff8d279c11dd946e84f1cd18cae8a24c Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 3 Oct 2020 11:38:16 +0200 Subject: [PATCH 2352/5092] Remove backtics from isolation error. Otherwise `FUTEX_WAIT with timeout` will look weird. --- src/helpers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers.rs b/src/helpers.rs index abf128ff3e2d..23bc54e76bb0 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -555,7 +555,7 @@ pub fn check_arg_count<'a, 'tcx, const N: usize>(args: &'a [OpTy<'tcx, Tag>]) -> pub fn isolation_error(name: &str) -> InterpResult<'static> { throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!( - "`{}` not available when isolation is enabled", + "{} not available when isolation is enabled", name, ))) } From 5880e7d809d20246ce160710ebf7160e4d0c56c1 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 3 Oct 2020 12:00:29 +0200 Subject: [PATCH 2353/5092] Update expected error messages in tests. --- tests/compile-fail/fs/isolated_file.rs | 2 +- tests/compile-fail/fs/isolated_stdin.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/compile-fail/fs/isolated_file.rs b/tests/compile-fail/fs/isolated_file.rs index 5b7270f18931..4c6adc8bf406 100644 --- a/tests/compile-fail/fs/isolated_file.rs +++ b/tests/compile-fail/fs/isolated_file.rs @@ -1,5 +1,5 @@ // ignore-windows: File handling is not implemented yet -// error-pattern: `open` not available when isolation is enabled +// error-pattern: open not available when isolation is enabled fn main() { let _file = std::fs::File::open("file.txt").unwrap(); diff --git a/tests/compile-fail/fs/isolated_stdin.rs b/tests/compile-fail/fs/isolated_stdin.rs index 6c467a2d1f14..19ce064089aa 100644 --- a/tests/compile-fail/fs/isolated_stdin.rs +++ b/tests/compile-fail/fs/isolated_stdin.rs @@ -7,7 +7,7 @@ extern crate libc; fn main() -> std::io::Result<()> { let mut bytes = [0u8; 512]; unsafe { - libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512); //~ ERROR `read` not available when isolation is enabled + libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512); //~ ERROR read not available when isolation is enabled } Ok(()) } From 6df54c47a7ac0a0788d68c12198f1369b559b93e Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 3 Oct 2020 12:11:24 +0200 Subject: [PATCH 2354/5092] Use read_scalar_at_offset in futex_wait instead of memory.get_raw. --- src/shims/posix/linux/sync.rs | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 386678508337..cc09b33ba684 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -24,17 +24,14 @@ pub fn futex<'tcx>( // The first three arguments (after the syscall number itself) are the same to all futex operations: // (int *addr, int op, int val). // We checked above that these definitely exist. - // - // `addr` is used to identify the mutex, but note that not all futex - // operations actually read from this addres or even require this address - // to exist. Also, the type of `addr` is not consistent. The API requires - // it to be a 4-byte aligned pointer, and will use the 4 bytes at the given - // address as an (atomic) i32. It's not uncommon for `addr` to be passed as - // another type than `*mut i32`, such as `*const AtomicI32`. - let addr = this.force_ptr(this.read_scalar(args[1])?.check_init()?)?; + let addr = this.read_immediate(args[1])?; let op = this.read_scalar(args[2])?.to_i32()?; let val = this.read_scalar(args[3])?.to_i32()?; + // The raw pointer value is used to identify the mutex. + // Not all mutex operations actually read from this address or even require this address to exist. + let futex_ptr = this.force_ptr(addr.to_scalar()?)?; + let thread = this.get_active_thread(); let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?; @@ -73,14 +70,16 @@ pub fn futex<'tcx>( }) }; // Check the pointer for alignment and validity. - // Atomic operations are only available for fully aligned values. - this.memory.check_ptr_access(addr.into(), Size::from_bytes(4), Align::from_bytes(4).unwrap())?; - // Read an `i32` through the pointer, regardless of any wrapper types (e.g. `AtomicI32`). - let futex_val = this.memory.get_raw(addr.alloc_id)?.read_scalar(this, addr, Size::from_bytes(4))?.to_i32()?; + // The API requires `addr` to be a 4-byte aligned pointer, and will + // use the 4 bytes at the given address as an (atomic) i32. + this.memory.check_ptr_access(addr.to_scalar()?, Size::from_bytes(4), Align::from_bytes(4).unwrap())?; + // Read an `i32` through the pointer, regardless of any wrapper types. + // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`. + let futex_val = this.read_scalar_at_offset(addr.into(), 0, this.machine.layouts.i32)?.to_i32()?; if val == futex_val { // The value still matches, so we block the trait make it wait for FUTEX_WAKE. this.block_thread(thread); - this.futex_wait(addr, thread); + this.futex_wait(futex_ptr, thread); // Succesfully waking up from FUTEX_WAIT always returns zero. this.write_scalar(Scalar::from_machine_isize(0, this), dest)?; // Register a timeout callback if a timeout was specified. @@ -91,7 +90,7 @@ pub fn futex<'tcx>( timeout_time, Box::new(move |this| { this.unblock_thread(thread); - this.futex_remove_waiter(addr, thread); + this.futex_remove_waiter(futex_ptr, thread); let etimedout = this.eval_libc("ETIMEDOUT")?; this.set_last_error(etimedout)?; this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?; @@ -114,7 +113,7 @@ pub fn futex<'tcx>( op if op == futex_wake => { let mut n = 0; for _ in 0..val { - if let Some(thread) = this.futex_wake(addr) { + if let Some(thread) = this.futex_wake(futex_ptr) { this.unblock_thread(thread); this.unregister_timeout_callback_if_exists(thread); n += 1; From 9d764c57502c1f6badb71684b5d5b5ee081f4dda Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 3 Oct 2020 12:18:38 +0200 Subject: [PATCH 2355/5092] Add FIXME note about variadic syscall(). --- src/shims/posix/linux/foreign_items.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 2241b8d4b3b1..328280d459a1 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -113,6 +113,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamically invoked syscalls "syscall" => { + // FIXME: The libc syscall() function is a variadic function. + // It's valid to call it with more arguments than a syscall + // needs, so none of these syscalls should use check_arg_count. + // However, depending on the calling convention it might depend + // on the type and size of the arguments whether a call with + // the wrong number of arguments (or types) is valid or not. + // So this needs to be researched first. let sys_getrandom = this .eval_libc("SYS_getrandom")? .to_machine_usize(this)?; From dc36988f388258f8ff10441f04f6b9fb30578165 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 3 Oct 2020 13:09:11 +0200 Subject: [PATCH 2356/5092] Add test for futex syscall. --- tests/run-pass/concurrency/linux-futex.rs | 132 ++++++++++++++++++ tests/run-pass/concurrency/linux-futex.stderr | 2 + 2 files changed, 134 insertions(+) create mode 100644 tests/run-pass/concurrency/linux-futex.rs create mode 100644 tests/run-pass/concurrency/linux-futex.stderr diff --git a/tests/run-pass/concurrency/linux-futex.rs b/tests/run-pass/concurrency/linux-futex.rs new file mode 100644 index 000000000000..391e9524324a --- /dev/null +++ b/tests/run-pass/concurrency/linux-futex.rs @@ -0,0 +1,132 @@ +// Unfortunately, the test framework does not support 'only-linux', +// so we need to ignore Windows and macOS instead. +// ignore-macos: Uses Linux-only APIs +// ignore-windows: Uses Linux-only APIs +// compile-flags: -Zmiri-disable-isolation + +#![feature(rustc_private)] +extern crate libc; + +use std::ptr; +use std::thread; +use std::time::{Duration, Instant}; + +fn wake_nobody() { + let futex = 0; + + // Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting. + unsafe { + assert_eq!(libc::syscall( + libc::SYS_futex, + &futex as *const i32, + libc::FUTEX_WAKE, + 1, + ), 0); + } + + // Same, but without omitting the unused arguments. + unsafe { + assert_eq!(libc::syscall( + libc::SYS_futex, + &futex as *const i32, + libc::FUTEX_WAKE, + 1, + 0, + 0, + 0, + ), 0); + } +} + +fn wake_dangling() { + let futex = Box::new(0); + let ptr: *const i32 = &*futex; + drop(futex); + + // Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting. + unsafe { + assert_eq!(libc::syscall( + libc::SYS_futex, + ptr, + libc::FUTEX_WAKE, + 1, + ), 0); + } +} + +fn wait_wrong_val() { + let futex: i32 = 123; + + // Only wait if the futex value is 456. + unsafe { + assert_eq!(libc::syscall( + libc::SYS_futex, + &futex as *const i32, + libc::FUTEX_WAIT, + 456, + ptr::null::(), + ), -1); + assert_eq!(*libc::__errno_location(), libc::EAGAIN); + } +} + +fn wait_timeout() { + let start = Instant::now(); + + let futex: i32 = 123; + + // Wait for 200ms, with nobody waking us up early. + unsafe { + assert_eq!(libc::syscall( + libc::SYS_futex, + &futex as *const i32, + libc::FUTEX_WAIT, + 123, + &libc::timespec { + tv_sec: 0, + tv_nsec: 200_000_000, + }, + ), -1); + assert_eq!(*libc::__errno_location(), libc::ETIMEDOUT); + } + + assert!((200..500).contains(&start.elapsed().as_millis())); +} + +fn wait_wake() { + let start = Instant::now(); + + static FUTEX: i32 = 0; + + thread::spawn(move || { + thread::sleep(Duration::from_millis(200)); + unsafe { + assert_eq!(libc::syscall( + libc::SYS_futex, + &FUTEX as *const i32, + libc::FUTEX_WAKE, + 10, // Wake up at most 10 threads. + ), 1); // Woken up one thread. + } + }); + + unsafe { + assert_eq!(libc::syscall( + libc::SYS_futex, + &FUTEX as *const i32, + libc::FUTEX_WAIT, + 0, + ptr::null::(), + ), 0); + } + + assert!((200..500).contains(&start.elapsed().as_millis())); +} + +fn main() { + wake_nobody(); + wake_dangling(); + wait_wrong_val(); + wait_timeout(); + wait_wake(); +} diff --git a/tests/run-pass/concurrency/linux-futex.stderr b/tests/run-pass/concurrency/linux-futex.stderr new file mode 100644 index 000000000000..2dbfb7721d36 --- /dev/null +++ b/tests/run-pass/concurrency/linux-futex.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental. For example, Miri does not detect data races yet. + From dfcb46a4e04743c38a5ef355062bad8764b93ff5 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 3 Oct 2020 13:39:16 +0200 Subject: [PATCH 2357/5092] Update syscall FIXME to include note about 'wrong' types. --- src/shims/posix/linux/foreign_items.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 328280d459a1..364cfde6c072 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -116,10 +116,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: The libc syscall() function is a variadic function. // It's valid to call it with more arguments than a syscall // needs, so none of these syscalls should use check_arg_count. - // However, depending on the calling convention it might depend - // on the type and size of the arguments whether a call with - // the wrong number of arguments (or types) is valid or not. + // It's even valid to call it with the wrong type of arguments, + // as long as they'd end up in the same place with the calling + // convention used. (E.g. using a `usize` instead of a pointer.) + // It's not directly clear which number, size, and type of arguments + // are acceptable in which cases and which aren't. (E.g. some + // types might take up the space of two registers.) // So this needs to be researched first. + let sys_getrandom = this .eval_libc("SYS_getrandom")? .to_machine_usize(this)?; From c268ee2bcbffeef4f0c0e8ef121188729933078b Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 3 Oct 2020 14:21:37 +0200 Subject: [PATCH 2358/5092] Add note about use of force_ptr in futex implementation. Co-authored-by: Ralf Jung --- src/shims/posix/linux/sync.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index cc09b33ba684..09558554aa22 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -30,6 +30,8 @@ pub fn futex<'tcx>( // The raw pointer value is used to identify the mutex. // Not all mutex operations actually read from this address or even require this address to exist. + // This will make FUTEX_WAKE fail on an integer cast to a pointer. But FUTEX_WAIT on + // such a pointer can never work anyway, so that seems fine. let futex_ptr = this.force_ptr(addr.to_scalar()?)?; let thread = this.get_active_thread(); From 68776d292196f4e890f860c1464ecc83af80859f Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 3 Oct 2020 14:32:30 +0200 Subject: [PATCH 2359/5092] Add FIXME about type of `addr` in futex implementation. Co-authored-by: Ralf Jung --- src/shims/posix/linux/sync.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 09558554aa22..d7ecb45279de 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -77,6 +77,7 @@ pub fn futex<'tcx>( this.memory.check_ptr_access(addr.to_scalar()?, Size::from_bytes(4), Align::from_bytes(4).unwrap())?; // Read an `i32` through the pointer, regardless of any wrapper types. // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`. + // FIXME: this fails if `addr` is not a pointer type. let futex_val = this.read_scalar_at_offset(addr.into(), 0, this.machine.layouts.i32)?.to_i32()?; if val == futex_val { // The value still matches, so we block the trait make it wait for FUTEX_WAKE. From 044c9ca206e642aa11d6f0937427740cdb6c2fc6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Oct 2020 15:19:57 +0200 Subject: [PATCH 2360/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 1b85e41c8ba2..9b4e14902aff 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c0127e4dbf3a9d3a67ddb1da19f8441019aab8f8 +6f56fbdc1c58992a9db630f5cd2ba9882d32e84b From b350c80a314b0b1a94fbfa2bb5d391df98388992 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Oct 2020 15:20:16 +0200 Subject: [PATCH 2361/5092] add backtics back in isolation error message --- src/shims/env.rs | 8 ++--- src/shims/posix/fs.rs | 42 ++++++++++++------------- src/shims/posix/linux/sync.rs | 2 +- src/shims/posix/sync.rs | 2 +- src/shims/time.rs | 16 +++++----- tests/compile-fail/fs/isolated_file.rs | 2 +- tests/compile-fail/fs/isolated_stdin.rs | 2 +- 7 files changed, 36 insertions(+), 38 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index d7474dbf87ef..42fd6e3dced8 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -293,7 +293,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let target_os = &this.tcx.sess.target.target.target_os; assert!(target_os == "linux" || target_os == "macos", "`getcwd` is only available for the UNIX target family"); - this.check_no_isolation("getcwd")?; + this.check_no_isolation("`getcwd`")?; let buf = this.read_scalar(buf_op)?.check_init()?; let size = this.read_scalar(size_op)?.to_machine_usize(&*this.tcx)?; @@ -320,7 +320,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("windows", "GetCurrentDirectoryW"); - this.check_no_isolation("GetCurrentDirectoryW")?; + this.check_no_isolation("`GetCurrentDirectoryW`")?; let size = u64::from(this.read_scalar(size_op)?.to_u32()?); let buf = this.read_scalar(buf_op)?.check_init()?; @@ -339,7 +339,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let target_os = &this.tcx.sess.target.target.target_os; assert!(target_os == "linux" || target_os == "macos", "`getcwd` is only available for the UNIX target family"); - this.check_no_isolation("chdir")?; + this.check_no_isolation("`chdir`")?; let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?; @@ -360,7 +360,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("windows", "SetCurrentDirectoryW"); - this.check_no_isolation("SetCurrentDirectoryW")?; + this.check_no_isolation("`SetCurrentDirectoryW`")?; let path = this.read_path_from_wide_str(this.read_scalar(path_op)?.check_init()?)?; diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index c50b41b75ef9..88597b4a3981 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -90,7 +90,7 @@ impl FileDescriptor for io::Stdin { fn read<'tcx>(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { if !communicate_allowed { // We want isolation mode to be deterministic, so we have to disallow all reads, even stdin. - helpers::isolation_error("read")?; + helpers::isolation_error("`read` from stdin")?; } Ok(Read::read(self, bytes)) } @@ -417,7 +417,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("open")?; + this.check_no_isolation("`open`")?; let flag = this.read_scalar(flag_op)?.to_i32()?; @@ -510,7 +510,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("fcntl")?; + this.check_no_isolation("`fcntl`")?; if args.len() < 2 { throw_ub_format!("incorrect number of arguments for fcntl: got {}, expected at least 2", args.len()); @@ -574,8 +574,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn close(&mut self, fd_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("close")?; - let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.remove(&fd) { @@ -709,7 +707,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn unlink(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("unlink")?; + this.check_no_isolation("`unlink`")?; let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?; @@ -739,7 +737,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); - this.check_no_isolation("symlink")?; + this.check_no_isolation("`symlink`")?; let target = this.read_path_from_c_str(this.read_scalar(target_op)?.check_init()?)?; let linkpath = this.read_path_from_c_str(this.read_scalar(linkpath_op)?.check_init()?)?; @@ -755,7 +753,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("macos", "stat"); - this.check_no_isolation("stat")?; + this.check_no_isolation("`stat`")?; // `stat` always follows symlinks. this.macos_stat_or_lstat(true, path_op, buf_op) } @@ -768,7 +766,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("macos", "lstat"); - this.check_no_isolation("lstat")?; + this.check_no_isolation("`lstat`")?; this.macos_stat_or_lstat(false, path_op, buf_op) } @@ -780,7 +778,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("macos", "fstat"); - this.check_no_isolation("fstat")?; + this.check_no_isolation("`fstat`")?; let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -802,7 +800,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("linux", "statx"); - this.check_no_isolation("statx")?; + this.check_no_isolation("`statx`")?; let statxbuf_scalar = this.read_scalar(statxbuf_op)?.check_init()?; let pathname_scalar = this.read_scalar(pathname_op)?.check_init()?; @@ -961,7 +959,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("rename")?; + this.check_no_isolation("`rename`")?; let oldpath_scalar = this.read_scalar(oldpath_op)?.check_init()?; let newpath_scalar = this.read_scalar(newpath_op)?.check_init()?; @@ -987,7 +985,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("mkdir")?; + this.check_no_isolation("`mkdir`")?; #[cfg_attr(not(unix), allow(unused_variables))] let mode = if this.tcx.sess.target.target.target_os == "macos" { @@ -1020,7 +1018,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("rmdir")?; + this.check_no_isolation("`rmdir`")?; let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?; @@ -1032,7 +1030,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn opendir(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - this.check_no_isolation("opendir")?; + this.check_no_isolation("`opendir`")?; let name = this.read_path_from_c_str(this.read_scalar(name_op)?.check_init()?)?; @@ -1063,7 +1061,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("linux", "readdir64_r"); - this.check_no_isolation("readdir64_r")?; + this.check_no_isolation("`readdir64_r`")?; let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; @@ -1150,7 +1148,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("macos", "readdir_r"); - this.check_no_isolation("readdir_r")?; + this.check_no_isolation("`readdir_r`")?; let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; @@ -1233,7 +1231,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn closedir(&mut self, dirp_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("closedir")?; + this.check_no_isolation("`closedir`")?; let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; @@ -1252,7 +1250,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("ftruncate64")?; + this.check_no_isolation("`ftruncate64`")?; let fd = this.read_scalar(fd_op)?.to_i32()?; let length = this.read_scalar(length_op)?.to_i64()?; @@ -1287,7 +1285,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); - this.check_no_isolation("fsync")?; + this.check_no_isolation("`fsync`")?; let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { @@ -1303,7 +1301,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn fdatasync(&mut self, fd_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("fdatasync")?; + this.check_no_isolation("`fdatasync`")?; let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { @@ -1325,7 +1323,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("sync_file_range")?; + this.check_no_isolation("`sync_file_range`")?; let fd = this.read_scalar(fd_op)?.to_i32()?; let offset = this.read_scalar(offset_op)?.to_i64()?; diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index d7ecb45279de..ef172fa2a671 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -55,6 +55,7 @@ pub fn futex<'tcx>( let timeout_time = if this.is_null(this.read_scalar(timeout)?.check_init()?)? { None } else { + this.check_no_isolation("`syscall(SYS_FUTEX, op=FUTEX_WAIT)` with timeout")?; let duration = match this.read_timespec(timeout)? { Some(duration) => duration, None => { @@ -64,7 +65,6 @@ pub fn futex<'tcx>( return Ok(()); } }; - this.check_no_isolation("FUTEX_WAIT with timeout")?; Some(if op & futex_realtime != 0 { Time::RealTime(SystemTime::now().checked_add(duration).unwrap()) } else { diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 6918fb7fd7ec..a0b5db42ed06 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -690,7 +690,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.check_no_isolation("pthread_cond_timedwait")?; + this.check_no_isolation("`pthread_cond_timedwait`")?; let id = cond_get_or_create_id(this, cond_op)?; let mutex_id = mutex_get_or_create_id(this, mutex_op)?; diff --git a/src/shims/time.rs b/src/shims/time.rs index 9d6d6ed38daa..806fa65d1564 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -22,7 +22,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("linux", "clock_gettime"); - this.check_no_isolation("clock_gettime")?; + this.check_no_isolation("`clock_gettime`")?; let clk_id = this.read_scalar(clk_id_op)?.to_i32()?; let tp = this.deref_operand(tp_op)?; @@ -60,7 +60,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("macos", "gettimeofday"); - this.check_no_isolation("gettimeofday")?; + this.check_no_isolation("`gettimeofday`")?; // Using tz is obsolete and should always be null let tz = this.read_scalar(tz_op)?.check_init()?; @@ -91,7 +91,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("windows", "GetSystemTimeAsFileTime"); - this.check_no_isolation("GetSystemTimeAsFileTime")?; + this.check_no_isolation("`GetSystemTimeAsFileTime`")?; let NANOS_PER_SEC = this.eval_windows_u64("time", "NANOS_PER_SEC")?; let INTERVALS_PER_SEC = this.eval_windows_u64("time", "INTERVALS_PER_SEC")?; @@ -119,7 +119,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("windows", "QueryPerformanceCounter"); - this.check_no_isolation("QueryPerformanceCounter")?; + this.check_no_isolation("`QueryPerformanceCounter`")?; // QueryPerformanceCounter uses a hardware counter as its basis. // Miri will emulate a counter with a resolution of 1 nanosecond. @@ -135,7 +135,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("windows", "QueryPerformanceFrequency"); - this.check_no_isolation("QueryPerformanceFrequency")?; + this.check_no_isolation("`QueryPerformanceFrequency`")?; // Retrieves the frequency of the hardware performance counter. // The frequency of the performance counter is fixed at system boot and @@ -150,7 +150,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); this.assert_target_os("macos", "mach_absolute_time"); - this.check_no_isolation("mach_absolute_time")?; + this.check_no_isolation("`mach_absolute_time`")?; // This returns a u64, with time units determined dynamically by `mach_timebase_info`. // We return plain nanoseconds. @@ -163,7 +163,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("macos", "mach_timebase_info"); - this.check_no_isolation("mach_timebase_info")?; + this.check_no_isolation("`mach_timebase_info`")?; let info = this.deref_operand(info_op)?; @@ -188,7 +188,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); - this.check_no_isolation("nanosleep")?; + this.check_no_isolation("`nanosleep`")?; let duration = match this.read_timespec(req_op)? { Some(duration) => duration, diff --git a/tests/compile-fail/fs/isolated_file.rs b/tests/compile-fail/fs/isolated_file.rs index 4c6adc8bf406..5b7270f18931 100644 --- a/tests/compile-fail/fs/isolated_file.rs +++ b/tests/compile-fail/fs/isolated_file.rs @@ -1,5 +1,5 @@ // ignore-windows: File handling is not implemented yet -// error-pattern: open not available when isolation is enabled +// error-pattern: `open` not available when isolation is enabled fn main() { let _file = std::fs::File::open("file.txt").unwrap(); diff --git a/tests/compile-fail/fs/isolated_stdin.rs b/tests/compile-fail/fs/isolated_stdin.rs index 19ce064089aa..4098a104761e 100644 --- a/tests/compile-fail/fs/isolated_stdin.rs +++ b/tests/compile-fail/fs/isolated_stdin.rs @@ -7,7 +7,7 @@ extern crate libc; fn main() -> std::io::Result<()> { let mut bytes = [0u8; 512]; unsafe { - libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512); //~ ERROR read not available when isolation is enabled + libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512); //~ ERROR `read` from stdin not available when isolation is enabled } Ok(()) } From a4cbbddc8e45ea4271636bc42fea8baf8bc51523 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Oct 2020 15:27:23 +0200 Subject: [PATCH 2362/5092] merge parking test into general synchronization test --- tests/run-pass/concurrency/parking.rs | 37 ----------------------- tests/run-pass/concurrency/parking.stderr | 2 -- tests/run-pass/concurrency/sync.rs | 30 ++++++++++++++++++ 3 files changed, 30 insertions(+), 39 deletions(-) delete mode 100644 tests/run-pass/concurrency/parking.rs delete mode 100644 tests/run-pass/concurrency/parking.stderr diff --git a/tests/run-pass/concurrency/parking.rs b/tests/run-pass/concurrency/parking.rs deleted file mode 100644 index 1ed742931fe6..000000000000 --- a/tests/run-pass/concurrency/parking.rs +++ /dev/null @@ -1,37 +0,0 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation - -use std::thread; -use std::time::{Duration, Instant}; - -// Normally, waiting in park/park_timeout may spuriously wake up early, but we -// know Miri's timed synchronization primitives do not do that. - -fn park_timeout() { - let start = Instant::now(); - - thread::park_timeout(Duration::from_millis(200)); - - assert!((200..500).contains(&start.elapsed().as_millis())); -} - -fn park_unpark() { - let t1 = thread::current(); - let t2 = thread::spawn(move || { - thread::park(); - thread::sleep(Duration::from_millis(200)); - t1.unpark(); - }); - - let start = Instant::now(); - - t2.thread().unpark(); - thread::park(); - - assert!((200..500).contains(&start.elapsed().as_millis())); -} - -fn main() { - park_timeout(); - park_unpark(); -} diff --git a/tests/run-pass/concurrency/parking.stderr b/tests/run-pass/concurrency/parking.stderr deleted file mode 100644 index 2dbfb7721d36..000000000000 --- a/tests/run-pass/concurrency/parking.stderr +++ /dev/null @@ -1,2 +0,0 @@ -warning: thread support is experimental. For example, Miri does not detect data races yet. - diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index b36ad27ebe19..69943e5495e2 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -312,6 +312,34 @@ fn check_rwlock_unlock_bug2() { h.join().unwrap(); } +fn park_timeout() { + let start = Instant::now(); + + thread::park_timeout(Duration::from_millis(200)); + // Normally, waiting in park/park_timeout may spuriously wake up early, but we + // know Miri's timed synchronization primitives do not do that. + + assert!((200..500).contains(&start.elapsed().as_millis())); +} + +fn park_unpark() { + let t1 = thread::current(); + let t2 = thread::spawn(move || { + thread::park(); + thread::sleep(Duration::from_millis(200)); + t1.unpark(); + }); + + let start = Instant::now(); + + t2.thread().unpark(); + thread::park(); + // Normally, waiting in park/park_timeout may spuriously wake up early, but we + // know Miri's timed synchronization primitives do not do that. + + assert!((200..500).contains(&start.elapsed().as_millis())); +} + fn main() { check_barriers(); check_conditional_variables_notify_one(); @@ -327,4 +355,6 @@ fn main() { check_once(); check_rwlock_unlock_bug1(); check_rwlock_unlock_bug2(); + park_timeout(); + park_unpark(); } From 2b2a3a0cc11c40a8fd6d8015d0b7fb11b30d8156 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Oct 2020 16:01:53 +0200 Subject: [PATCH 2363/5092] check that all syscall arguments are scalars --- src/bin/miri.rs | 2 +- src/shims/posix/linux/foreign_items.rs | 32 ++++++++++++++------------ src/shims/posix/linux/sync.rs | 10 ++++---- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index e3317d0d4d68..7b417990af86 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -221,7 +221,7 @@ fn main() { ), FromHexError::OddLength => panic!("-Zmiri-seed should have an even number of digits"), - err => panic!("Unknown error decoding -Zmiri-seed as hex: {:?}", err), + err => panic!("unknown error decoding -Zmiri-seed as hex: {:?}", err), }); if seed_raw.len() > 8 { panic!(format!( diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 364cfde6c072..04efa79b9d93 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -113,16 +113,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamically invoked syscalls "syscall" => { - // FIXME: The libc syscall() function is a variadic function. - // It's valid to call it with more arguments than a syscall - // needs, so none of these syscalls should use check_arg_count. - // It's even valid to call it with the wrong type of arguments, - // as long as they'd end up in the same place with the calling - // convention used. (E.g. using a `usize` instead of a pointer.) - // It's not directly clear which number, size, and type of arguments - // are acceptable in which cases and which aren't. (E.g. some - // types might take up the space of two registers.) - // So this needs to be researched first. + // The syscall variadic function is legal to call with more arguments than needed, + // extra arguments are simply ignored. However, all arguments need to be scalars; + // other types might be treated differently by the calling convention. + for arg in args { + if !matches!(arg.layout.abi, rustc_target::abi::Abi::Scalar(_)) { + throw_ub_format!("`syscall` arguments must all have scalar layout, but {} does not", arg.layout.ty); + } + } let sys_getrandom = this .eval_libc("SYS_getrandom")? @@ -144,22 +142,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // is called if a `HashMap` is created the regular way (e.g. HashMap). id if id == sys_getrandom => { // The first argument is the syscall id, so skip over it. - let &[_, ptr, len, flags] = check_arg_count(args)?; - getrandom(this, ptr, len, flags, dest)?; + if args.len() < 4 { + throw_ub_format!("incorrect number of arguments for `getrandom` syscall: got {}, expected at least 4", args.len()); + } + getrandom(this, args[1], args[2], args[3], dest)?; } // `statx` is used by `libstd` to retrieve metadata information on `linux` // instead of using `stat`,`lstat` or `fstat` as on `macos`. id if id == sys_statx => { // The first argument is the syscall id, so skip over it. - let &[_, dirfd, pathname, flags, mask, statxbuf] = check_arg_count(args)?; - let result = this.linux_statx(dirfd, pathname, flags, mask, statxbuf)?; + if args.len() < 6 { + throw_ub_format!("incorrect number of arguments for `statx` syscall: got {}, expected at least 6", args.len()); + } + let result = this.linux_statx(args[1], args[2], args[3], args[4], args[5])?; this.write_scalar(Scalar::from_machine_isize(result.into(), this), dest)?; } // `futex` is used by some synchonization primitives. id if id == sys_futex => { futex(this, args, dest)?; } - id => throw_unsup_format!("miri does not support syscall ID {}", id), + id => throw_unsup_format!("Miri does not support syscall ID {}", id), } } diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index ef172fa2a671..9d124872f5cc 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -17,8 +17,8 @@ pub fn futex<'tcx>( // may or may not be left out from the `syscall()` call. // Therefore we don't use `check_arg_count` here, but only check for the // number of arguments to fall within a range. - if !(4..=7).contains(&args.len()) { - throw_ub_format!("incorrect number of arguments for futex syscall: got {}, expected between 4 and 7 (inclusive)", args.len()); + if args.len() < 4 { + throw_ub_format!("incorrect number of arguments for `futex` syscall: got {}, expected at least 4", args.len()); } // The first three arguments (after the syscall number itself) are the same to all futex operations: @@ -49,13 +49,13 @@ pub fn futex<'tcx>( // or *timeout expires. `timeout == null` for an infinite timeout. op if op & !futex_realtime == futex_wait => { if args.len() < 5 { - throw_ub_format!("incorrect number of arguments for FUTEX_WAIT syscall: got {}, expected at least 5", args.len()); + throw_ub_format!("incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT`: got {}, expected at least 5", args.len()); } let timeout = args[4]; let timeout_time = if this.is_null(this.read_scalar(timeout)?.check_init()?)? { None } else { - this.check_no_isolation("`syscall(SYS_FUTEX, op=FUTEX_WAIT)` with timeout")?; + this.check_no_isolation("`futex` syscall with `op=FUTEX_WAIT` and non-null timeout")?; let duration = match this.read_timespec(timeout)? { Some(duration) => duration, None => { @@ -126,7 +126,7 @@ pub fn futex<'tcx>( } this.write_scalar(Scalar::from_machine_isize(n, this), dest)?; } - op => throw_unsup_format!("miri does not support SYS_futex operation {}", op), + op => throw_unsup_format!("Miri does not support `futex` syscall with op={}", op), } Ok(()) From 1c9db025082283c963f129a747bcb10b532feebb Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 4 Oct 2020 18:53:13 +0700 Subject: [PATCH 2364/5092] Add a dummy actions template to enable it on CI --- .github/workflows/ci.yml | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000000..101618d1a7aa --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,35 @@ +name: CI + +on: + push: + # Run in PRs and for bors, but not on master. + branches: + - 'auto' + - 'try' + pull_request: + branches: + - 'master' + schedule: + # Use to conveniently edit cron schedule. + - cron: "0 7 * * *" # At 07:00 UTC every day. + +jobs: + build: + runs-on: ${{ matrix.os }} + env: + RUST_BACKTRACE: 1 + strategy: + matrix: + build: [linux64, macos, win32] + include: + - build: linux64 + os: ubuntu-latest + host_target: x86_64-unknown-linux-gnu + - build: macos + os: macos-latest + host_target: x86_64-apple-darwin + - build: win32 + os: windows-latest + host_target: i686-pc-windows-msvc + steps: + - uses: actions/checkout@v2 From 78bc89b4fc3713869e421048a439e4ca7c6c1bfe Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 28 Sep 2020 15:02:54 -0400 Subject: [PATCH 2365/5092] Implement `readlink` Due to the truncating behavior of `readlink`, I was not able to directly use any of the existing C-cstring helper functions. --- src/shims/os_str.rs | 33 ++++++++++++----------- src/shims/posix/foreign_items.rs | 5 ++++ src/shims/posix/fs.rs | 33 +++++++++++++++++++++++ tests/run-pass/fs.rs | 45 +++++++++++++++++++++++++++++++- 4 files changed, 100 insertions(+), 16 deletions(-) diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 73dc9119a820..b3d40392ac68 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -118,22 +118,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx scalar: Scalar, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { - #[cfg(unix)] - fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - Ok(os_str.as_bytes()) - } - #[cfg(not(unix))] - fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the - // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually - // valid. - os_str - .to_str() - .map(|s| s.as_bytes()) - .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) - } - let bytes = os_str_to_bytes(os_str)?; + let bytes = self.os_str_to_bytes(os_str)?; // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null // terminator to memory using the `ptr` pointer would cause an out-of-bounds access. let string_length = u64::try_from(bytes.len()).unwrap(); @@ -265,4 +251,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let os_str = convert_path_separator(Cow::Borrowed(path.as_os_str()), &this.tcx.sess.target.target.target_os, Pathconversion::HostToTarget); this.write_os_str_to_wide_str(&os_str, scalar, size) } + + #[cfg(unix)] + fn os_str_to_bytes<'a>(&mut self, os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + Ok(os_str.as_bytes()) + } + + #[cfg(not(unix))] + fn os_str_to_bytes<'a>(&mut self, os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the + // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually + // valid. + os_str + .to_str() + .map(|s| s.as_bytes()) + .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) + } + } diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 26c743b360e0..177678f03d74 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -123,6 +123,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.fdatasync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "readlink" => { + let &[pathname, buf, bufsize] = check_arg_count(args)?; + let result = this.readlink(pathname, buf, bufsize)?; + this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; + } // Allocation "posix_memalign" => { diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 88597b4a3981..a5b9642d0604 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -1353,6 +1353,39 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.handle_not_found() } } + + fn readlink( + &mut self, + pathname_op: OpTy<'tcx, Tag>, + buf_op: OpTy<'tcx, Tag>, + bufsize_op: OpTy<'tcx, Tag> + ) -> InterpResult<'tcx, i64> { + let this = self.eval_context_mut(); + + this.check_no_isolation("readlink")?; + + let pathname = this.read_path_from_c_str(this.read_scalar(pathname_op)?.check_init()?)?; + let buf = this.read_scalar(buf_op)?.check_init()?; + let bufsize = this.read_scalar(bufsize_op)?.to_machine_usize(this)?; + + let result = std::fs::read_link(pathname); + match result { + Ok(resolved) => { + let mut path_bytes = this.os_str_to_bytes(resolved.as_ref())?; + if path_bytes.len() > bufsize as usize { + path_bytes = &path_bytes[..(bufsize as usize)] + } + // 'readlink' truncates the resolved path if + // the provided buffer is not large enough + this.memory.write_bytes(buf, path_bytes.iter().copied())?; + Ok(path_bytes.len() as i64) + } + Err(e) => { + this.set_last_error_from_io_error(e)?; + Ok(-1) + } + } + } } /// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch when diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index caa9bffc2bc8..8f750847b203 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -1,12 +1,18 @@ // ignore-windows: File handling is not implemented yet // compile-flags: -Zmiri-disable-isolation +#![feature(rustc_private)] + use std::fs::{ File, create_dir, OpenOptions, read_dir, remove_dir, remove_dir_all, remove_file, rename, }; -use std::io::{Read, Write, ErrorKind, Result, Seek, SeekFrom}; +use std::ffi::CString; +use std::io::{Read, Write, Error, ErrorKind, Result, Seek, SeekFrom}; use std::path::{PathBuf, Path}; +extern crate libc; + + fn main() { test_file(); test_file_clone(); @@ -215,6 +221,43 @@ fn test_symlink() { let mut contents = Vec::new(); symlink_file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); + + + #[cfg(unix)] + { + use std::os::unix::ffi::OsStrExt; + + let expected_path = path.as_os_str().as_bytes(); + + // Test that the expected string gets written to a buffer of proper + // length, and that a trailing null byte is not written + let symlink_c_str = CString::new(symlink_path.as_os_str().as_bytes()).unwrap(); + let symlink_c_ptr = symlink_c_str.as_ptr(); + + // Make the buf one byte larger than it needs to be, + // and check that the last byte is not overwritten + let mut large_buf = vec![0xFF; expected_path.len() + 1]; + let res = unsafe { libc::readlink(symlink_c_ptr, large_buf.as_mut_ptr().cast(), large_buf.len()) }; + assert_eq!(res, large_buf.len() as isize - 1); + // Check that the resovled path was properly written into the buf + assert_eq!(&large_buf[..(large_buf.len() - 1)], expected_path); + assert_eq!(large_buf.last(), Some(&0xFF)); + + // Test that the resolved path is truncated if the provided buffer + // is too small. + let mut small_buf = [0u8; 2]; + let res = unsafe { libc::readlink(symlink_c_ptr, small_buf.as_mut_ptr().cast(), small_buf.len()) }; + assert_eq!(res, small_buf.len() as isize); + assert_eq!(small_buf, &expected_path[..small_buf.len()]); + + // Test that we report a proper error for a missing path. + let bad_path = CString::new("MIRI_MISSING_FILE_NAME").unwrap(); + let res = unsafe { libc::readlink(bad_path.as_ptr(), small_buf.as_mut_ptr().cast(), small_buf.len()) }; + assert_eq!(res, -1); + assert_eq!(Error::last_os_error().kind(), ErrorKind::NotFound); + } + + // Test that metadata of a symbolic link is correct. check_metadata(bytes, &symlink_path).unwrap(); // Test that the metadata of a symbolic link is correct when not following it. From 186d59a3ecc59e2994f28b1bd2f1110be20c51c1 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 3 Oct 2020 12:51:46 -0400 Subject: [PATCH 2366/5092] Move some helper functions around --- src/shims/os_str.rs | 58 ++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index b3d40392ac68..bb5e7078291f 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -62,6 +62,18 @@ fn convert_path_separator<'a>( impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + + #[cfg(unix)] + fn bytes_to_os_str<'a>(&self, bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { + Ok(OsStr::from_bytes(bytes)) + } + #[cfg(not(unix))] + fn bytes_to_os_str<'a>(&self, bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { + let s = std::str::from_utf8(bytes) + .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; + Ok(OsStr::new(s)) + } + /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. fn read_os_str_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, &'a OsStr> @@ -69,20 +81,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx 'tcx: 'a, 'mir: 'a, { - #[cfg(unix)] - fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { - Ok(OsStr::from_bytes(bytes)) - } - #[cfg(not(unix))] - fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { - let s = std::str::from_utf8(bytes) - .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; - Ok(OsStr::new(s)) - } - let this = self.eval_context_ref(); let bytes = this.memory.read_c_str(scalar)?; - bytes_to_os_str(bytes) + self.bytes_to_os_str(bytes) } /// Helper function to read an OsString from a 0x0000-terminated sequence of u16, @@ -107,6 +108,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx u16vec_to_osstring(u16_vec) } + #[cfg(unix)] + fn os_str_to_bytes<'a>(&self, os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + Ok(os_str.as_bytes()) + } + + #[cfg(not(unix))] + fn os_str_to_bytes<'a>(&self, os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the + // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually + // valid. + os_str + .to_str() + .map(|s| s.as_bytes()) + .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) + } + /// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. This function returns `Ok((false, length))` without trying /// to write if `size` is not large enough to fit the contents of `os_string` plus a null @@ -251,21 +268,4 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let os_str = convert_path_separator(Cow::Borrowed(path.as_os_str()), &this.tcx.sess.target.target.target_os, Pathconversion::HostToTarget); this.write_os_str_to_wide_str(&os_str, scalar, size) } - - #[cfg(unix)] - fn os_str_to_bytes<'a>(&mut self, os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - Ok(os_str.as_bytes()) - } - - #[cfg(not(unix))] - fn os_str_to_bytes<'a>(&mut self, os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the - // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually - // valid. - os_str - .to_str() - .map(|s| s.as_bytes()) - .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) - } - } From 8b89c7e1da6231b998addb8d0dab43f68c1975f0 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 3 Oct 2020 12:52:06 -0400 Subject: [PATCH 2367/5092] Use panicking coversions instead of `as` --- src/shims/posix/fs.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index a5b9642d0604..1ca05a461bfb 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -1372,13 +1372,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match result { Ok(resolved) => { let mut path_bytes = this.os_str_to_bytes(resolved.as_ref())?; - if path_bytes.len() > bufsize as usize { - path_bytes = &path_bytes[..(bufsize as usize)] + let bufsize: usize = bufsize.try_into().unwrap(); + if path_bytes.len() > bufsize { + path_bytes = &path_bytes[..bufsize] } // 'readlink' truncates the resolved path if // the provided buffer is not large enough this.memory.write_bytes(buf, path_bytes.iter().copied())?; - Ok(path_bytes.len() as i64) + Ok(path_bytes.len().try_into().unwrap()) } Err(e) => { this.set_last_error_from_io_error(e)?; From 0e59b6f6731d80151dfcf3572e93ea52430d8d9c Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 3 Oct 2020 12:56:32 -0400 Subject: [PATCH 2368/5092] Merge `fs` and `fs_libc` tests --- tests/run-pass/fs.rs | 11 +++++++++++ tests/run-pass/{fs_libc.stderr => fs.stderr} | 0 tests/run-pass/{fs_libc.stdout => fs.stdout} | 0 tests/run-pass/fs_libc.rs | 20 -------------------- 4 files changed, 11 insertions(+), 20 deletions(-) rename tests/run-pass/{fs_libc.stderr => fs.stderr} (100%) rename tests/run-pass/{fs_libc.stdout => fs.stdout} (100%) delete mode 100644 tests/run-pass/fs_libc.rs diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 8f750847b203..ca3c6a6d2917 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -25,6 +25,7 @@ fn main() { test_errors(); test_rename(); test_directory(); + test_dup_stdout_stderr(); } fn tmp() -> PathBuf { @@ -335,3 +336,13 @@ fn test_directory() { // Reading the metadata of a non-existent directory should fail with a "not found" error. assert_eq!(ErrorKind::NotFound, check_metadata(&[], &dir_path).unwrap_err().kind()); } + +fn test_dup_stdout_stderr() { + let bytes = b"hello dup fd\n"; + unsafe { + let new_stdout = libc::fcntl(1, libc::F_DUPFD, 0); + let new_stderr = libc::fcntl(2, libc::F_DUPFD, 0); + libc::write(new_stdout, bytes.as_ptr() as *const libc::c_void, bytes.len()); + libc::write(new_stderr, bytes.as_ptr() as *const libc::c_void, bytes.len()); + } +} diff --git a/tests/run-pass/fs_libc.stderr b/tests/run-pass/fs.stderr similarity index 100% rename from tests/run-pass/fs_libc.stderr rename to tests/run-pass/fs.stderr diff --git a/tests/run-pass/fs_libc.stdout b/tests/run-pass/fs.stdout similarity index 100% rename from tests/run-pass/fs_libc.stdout rename to tests/run-pass/fs.stdout diff --git a/tests/run-pass/fs_libc.rs b/tests/run-pass/fs_libc.rs deleted file mode 100644 index e3deb7a5bcd8..000000000000 --- a/tests/run-pass/fs_libc.rs +++ /dev/null @@ -1,20 +0,0 @@ -// ignore-windows -// compile-flags: -Zmiri-disable-isolation - -#![feature(rustc_private)] - -extern crate libc; - -fn main() { - dup_stdout_stderr_test(); -} - -fn dup_stdout_stderr_test() { - let bytes = b"hello dup fd\n"; - unsafe { - let new_stdout = libc::fcntl(1, libc::F_DUPFD, 0); - let new_stderr = libc::fcntl(2, libc::F_DUPFD, 0); - libc::write(new_stdout, bytes.as_ptr() as *const libc::c_void, bytes.len()); - libc::write(new_stderr, bytes.as_ptr() as *const libc::c_void, bytes.len()); - } -} From 5fc5490bc84d02408c8fbcc6bf8edd49af06c9a4 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 3 Oct 2020 12:59:23 -0400 Subject: [PATCH 2369/5092] Add trailing punctuation Co-authored-by: Ralf Jung --- tests/run-pass/fs.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index ca3c6a6d2917..7cccf900a1bf 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -231,16 +231,16 @@ fn test_symlink() { let expected_path = path.as_os_str().as_bytes(); // Test that the expected string gets written to a buffer of proper - // length, and that a trailing null byte is not written + // length, and that a trailing null byte is not written. let symlink_c_str = CString::new(symlink_path.as_os_str().as_bytes()).unwrap(); let symlink_c_ptr = symlink_c_str.as_ptr(); // Make the buf one byte larger than it needs to be, - // and check that the last byte is not overwritten + // and check that the last byte is not overwritten. let mut large_buf = vec![0xFF; expected_path.len() + 1]; let res = unsafe { libc::readlink(symlink_c_ptr, large_buf.as_mut_ptr().cast(), large_buf.len()) }; assert_eq!(res, large_buf.len() as isize - 1); - // Check that the resovled path was properly written into the buf + // Check that the resovled path was properly written into the buf. assert_eq!(&large_buf[..(large_buf.len() - 1)], expected_path); assert_eq!(large_buf.last(), Some(&0xFF)); From 462f58298a3a75c15509bf57d8935c3954be6685 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Oct 2020 08:00:26 -0400 Subject: [PATCH 2370/5092] Make helper functions freestanding --- src/shims/os_str.rs | 59 ++++++++++++++++++++++--------------------- src/shims/posix/fs.rs | 2 +- 2 files changed, 31 insertions(+), 30 deletions(-) diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index bb5e7078291f..56dcbb9e32f7 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -60,20 +60,36 @@ fn convert_path_separator<'a>( }; } +#[cfg(unix)] +pub fn os_str_to_bytes<'a, 'tcx>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + Ok(os_str.as_bytes()) +} + +#[cfg(not(unix))] +pub fn os_str_to_bytes<'a, 'tcx>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the + // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually + // valid. + os_str + .to_str() + .map(|s| s.as_bytes()) + .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) +} + +#[cfg(unix)] +pub fn bytes_to_os_str<'a, 'tcx>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { + Ok(OsStr::from_bytes(bytes)) +} +#[cfg(not(unix))] +pub fn bytes_to_os_str<'a, 'tcx>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { + let s = std::str::from_utf8(bytes) + .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; + Ok(OsStr::new(s)) +} + impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - #[cfg(unix)] - fn bytes_to_os_str<'a>(&self, bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { - Ok(OsStr::from_bytes(bytes)) - } - #[cfg(not(unix))] - fn bytes_to_os_str<'a>(&self, bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { - let s = std::str::from_utf8(bytes) - .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; - Ok(OsStr::new(s)) - } - /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. fn read_os_str_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, &'a OsStr> @@ -83,7 +99,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx { let this = self.eval_context_ref(); let bytes = this.memory.read_c_str(scalar)?; - self.bytes_to_os_str(bytes) + bytes_to_os_str(bytes) } /// Helper function to read an OsString from a 0x0000-terminated sequence of u16, @@ -108,22 +124,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx u16vec_to_osstring(u16_vec) } - #[cfg(unix)] - fn os_str_to_bytes<'a>(&self, os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - Ok(os_str.as_bytes()) - } - - #[cfg(not(unix))] - fn os_str_to_bytes<'a>(&self, os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the - // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually - // valid. - os_str - .to_str() - .map(|s| s.as_bytes()) - .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) - } - /// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. This function returns `Ok((false, length))` without trying /// to write if `size` is not large enough to fit the contents of `os_string` plus a null @@ -136,7 +136,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { - let bytes = self.os_str_to_bytes(os_str)?; + let bytes = os_str_to_bytes(os_str)?; // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null // terminator to memory using the `ptr` pointer would cause an out-of-bounds access. let string_length = u64::try_from(bytes.len()).unwrap(); @@ -269,3 +269,4 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_os_str_to_wide_str(&os_str, scalar, size) } } + diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 1ca05a461bfb..0247c9df006f 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -1371,7 +1371,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = std::fs::read_link(pathname); match result { Ok(resolved) => { - let mut path_bytes = this.os_str_to_bytes(resolved.as_ref())?; + let mut path_bytes = crate::shims::os_str::os_str_to_bytes(resolved.as_ref())?; let bufsize: usize = bufsize.try_into().unwrap(); if path_bytes.len() > bufsize { path_bytes = &path_bytes[..bufsize] From bbba87ce5450eb0145e4aec0d50b546effc054ff Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Oct 2020 09:41:15 -0400 Subject: [PATCH 2371/5092] Swap order of assertions for easier debugging --- tests/run-pass/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 7cccf900a1bf..947c650197cc 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -239,17 +239,17 @@ fn test_symlink() { // and check that the last byte is not overwritten. let mut large_buf = vec![0xFF; expected_path.len() + 1]; let res = unsafe { libc::readlink(symlink_c_ptr, large_buf.as_mut_ptr().cast(), large_buf.len()) }; - assert_eq!(res, large_buf.len() as isize - 1); // Check that the resovled path was properly written into the buf. assert_eq!(&large_buf[..(large_buf.len() - 1)], expected_path); assert_eq!(large_buf.last(), Some(&0xFF)); + assert_eq!(res, large_buf.len() as isize - 1); // Test that the resolved path is truncated if the provided buffer // is too small. let mut small_buf = [0u8; 2]; let res = unsafe { libc::readlink(symlink_c_ptr, small_buf.as_mut_ptr().cast(), small_buf.len()) }; - assert_eq!(res, small_buf.len() as isize); assert_eq!(small_buf, &expected_path[..small_buf.len()]); + assert_eq!(res, small_buf.len() as isize); // Test that we report a proper error for a missing path. let bad_path = CString::new("MIRI_MISSING_FILE_NAME").unwrap(); From 9e6320f1017a5af43b8f1726ff68c8c494d3e8bc Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Oct 2020 12:34:13 -0400 Subject: [PATCH 2372/5092] Move `convert_path_separator` to trait and use it in `readlink` --- src/shims/os_str.rs | 93 ++++++++++++++++++++++--------------------- src/shims/posix/fs.rs | 2 + 2 files changed, 49 insertions(+), 46 deletions(-) diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 56dcbb9e32f7..df3c7a5ad99c 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -14,52 +14,11 @@ use rustc_target::abi::LayoutOf; use crate::*; /// Represent how path separator conversion should be done. -enum Pathconversion { +pub enum Pathconversion { HostToTarget, TargetToHost, } -/// Perform path separator conversion if needed. -fn convert_path_separator<'a>( - os_str: Cow<'a, OsStr>, - target_os: &str, - direction: Pathconversion, -) -> Cow<'a, OsStr> { - #[cfg(windows)] - return if target_os == "windows" { - // Windows-on-Windows, all fine. - os_str - } else { - // Unix target, Windows host. - let (from, to) = match direction { - Pathconversion::HostToTarget => ('\\', '/'), - Pathconversion::TargetToHost => ('/', '\\'), - }; - let converted = os_str - .encode_wide() - .map(|wchar| if wchar == from as u16 { to as u16 } else { wchar }) - .collect::>(); - Cow::Owned(OsString::from_wide(&converted)) - }; - #[cfg(unix)] - return if target_os == "windows" { - // Windows target, Unix host. - let (from, to) = match direction { - Pathconversion::HostToTarget => ('/', '\\'), - Pathconversion::TargetToHost => ('\\', '/'), - }; - let converted = os_str - .as_bytes() - .iter() - .map(|&wchar| if wchar == from as u8 { to as u8 } else { wchar }) - .collect::>(); - Cow::Owned(OsString::from_vec(converted)) - } else { - // Unix-on-Unix, all is fine. - os_str - }; -} - #[cfg(unix)] pub fn os_str_to_bytes<'a, 'tcx>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { Ok(os_str.as_bytes()) @@ -229,7 +188,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); let os_str = this.read_os_str_from_c_str(scalar)?; - Ok(match convert_path_separator(Cow::Borrowed(os_str), &this.tcx.sess.target.target.target_os, Pathconversion::TargetToHost) { + Ok(match this.convert_path_separator(Cow::Borrowed(os_str), Pathconversion::TargetToHost) { Cow::Borrowed(x) => Cow::Borrowed(Path::new(x)), Cow::Owned(y) => Cow::Owned(PathBuf::from(y)), }) @@ -240,7 +199,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); let os_str = this.read_os_str_from_wide_str(scalar)?; - Ok(convert_path_separator(Cow::Owned(os_str), &this.tcx.sess.target.target.target_os, Pathconversion::TargetToHost).into_owned().into()) + Ok(this.convert_path_separator(Cow::Owned(os_str), Pathconversion::TargetToHost).into_owned().into()) } /// Write a Path to the machine memory (as a null-terminated sequence of bytes), @@ -252,7 +211,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = convert_path_separator(Cow::Borrowed(path.as_os_str()), &this.tcx.sess.target.target.target_os, Pathconversion::HostToTarget); + let os_str = this.convert_path_separator(Cow::Borrowed(path.as_os_str()), Pathconversion::HostToTarget); this.write_os_str_to_c_str(&os_str, scalar, size) } @@ -265,8 +224,50 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = convert_path_separator(Cow::Borrowed(path.as_os_str()), &this.tcx.sess.target.target.target_os, Pathconversion::HostToTarget); + let os_str = this.convert_path_separator(Cow::Borrowed(path.as_os_str()), Pathconversion::HostToTarget); this.write_os_str_to_wide_str(&os_str, scalar, size) } + + fn convert_path_separator<'a>( + &self, + os_str: Cow<'a, OsStr>, + direction: Pathconversion, + ) -> Cow<'a, OsStr> { + let this = self.eval_context_ref(); + let target_os = &this.tcx.sess.target.target.target_os; + #[cfg(windows)] + return if target_os == "windows" { + // Windows-on-Windows, all fine. + os_str + } else { + // Unix target, Windows host. + let (from, to) = match direction { + Pathconversion::HostToTarget => ('\\', '/'), + Pathconversion::TargetToHost => ('/', '\\'), + }; + let converted = os_str + .encode_wide() + .map(|wchar| if wchar == from as u16 { to as u16 } else { wchar }) + .collect::>(); + Cow::Owned(OsString::from_wide(&converted)) + }; + #[cfg(unix)] + return if target_os == "windows" { + // Windows target, Unix host. + let (from, to) = match direction { + Pathconversion::HostToTarget => ('/', '\\'), + Pathconversion::TargetToHost => ('\\', '/'), + }; + let converted = os_str + .as_bytes() + .iter() + .map(|&wchar| if wchar == from as u8 { to as u8 } else { wchar }) + .collect::>(); + Cow::Owned(OsString::from_vec(converted)) + } else { + // Unix-on-Unix, all is fine. + os_str + }; + } } diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 0247c9df006f..e84731a5ef73 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -4,6 +4,7 @@ use std::fs::{read_dir, remove_dir, remove_file, rename, DirBuilder, File, FileT use std::io::{self, Read, Seek, SeekFrom, Write}; use std::path::Path; use std::time::SystemTime; +use std::borrow::Cow; use log::trace; @@ -1371,6 +1372,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = std::fs::read_link(pathname); match result { Ok(resolved) => { + let resolved = this.convert_path_separator(Cow::Borrowed(resolved.as_ref()), crate::shims::os_str::Pathconversion::HostToTarget); let mut path_bytes = crate::shims::os_str::os_str_to_bytes(resolved.as_ref())?; let bufsize: usize = bufsize.try_into().unwrap(); if path_bytes.len() > bufsize { From 02257870a6b53b25238b5345d17c01fbfc366769 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Oct 2020 18:56:51 +0200 Subject: [PATCH 2373/5092] rustup; test NaN conversion issue --- rust-version | 2 +- tests/run-pass/float.rs | 29 ++++++++++++++++++++++------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/rust-version b/rust-version index 9b4e14902aff..622fa14d1c29 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6f56fbdc1c58992a9db630f5cd2ba9882d32e84b +a835b483fe0418b48ca44afb65cd0dd6bad4eb9b diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index 88f841eae74d..62d9c6076608 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -4,6 +4,14 @@ use std::fmt::Debug; use std::hint::black_box; +fn main() { + basic(); + casts(); + more_casts(); + ops(); + nan_casts(); +} + // Helper function to avoid promotion so that this tests "run-time" casts, not CTFE. // Doesn't make a big difference when running this in Miri, but it means we can compare this // with the LLVM backend by running `rustc -Zmir-opt-level=0 -Zsaturating-float-casts`. @@ -78,13 +86,6 @@ fn test_both_cast(x: F, y: I) assert_eq!(unsafe { x.cast_unchecked() }, y); } -fn main() { - basic(); - casts(); - more_casts(); - ops(); -} - fn basic() { // basic arithmetic assert_eq(6.0_f32*6.0_f32, 36.0_f32); @@ -444,3 +445,17 @@ fn more_casts() { const SECOND_LARGEST_F32: f32 = 340282326356119256160033759537265639424.; test!(SECOND_LARGEST_F32, f32 -> u128, 0xfffffe00000000000000000000000000); } + +fn nan_casts() { + let nan1 = f64::from_bits(0x7FF0_0001_0000_0001u64); + let nan2 = f64::from_bits(0x7FF0_0000_0000_0001u64); + + assert!(nan1.is_nan()); + assert!(nan2.is_nan()); + + let nan1_32 = nan1 as f32; + let nan2_32 = nan2 as f32; + + assert!(nan1_32.is_nan()); + assert!(nan2_32.is_nan()); +} From 4eea02e725052a8941abd728cb1da98e4d9770a8 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Oct 2020 16:26:09 -0400 Subject: [PATCH 2374/5092] Normalize MIRI_TEMP before using it --- tests/run-pass/fs.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 947c650197cc..f74d1c9a36b1 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -29,7 +29,19 @@ fn main() { } fn tmp() -> PathBuf { - std::env::var("MIRI_TEMP").map(PathBuf::from).unwrap_or_else(|_| std::env::temp_dir()) + std::env::var("MIRI_TEMP") + .map(|tmp| { + // MIRI_TEMP is set outside of our emulated + // program, so it may have path separators that don't + // correspond to our target platform. We normalize them here + // before constructing a `PathBuf` + + #[cfg(windows)] + return PathBuf::from(tmp.replace("/", "\\")); + + #[cfg(not(windows))] + return PathBuf::from(tmp.replace("\\", "/")); + }).unwrap_or_else(|_| std::env::temp_dir()) } /// Prepare: compute filename and make sure the file does not exist. From c1c82c2503d1fcc581e230129f84523e59835c13 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Oct 2020 16:28:09 -0400 Subject: [PATCH 2375/5092] Properly capitalize PathConversion --- src/shims/os_str.rs | 20 ++++++++++---------- src/shims/posix/fs.rs | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index df3c7a5ad99c..7635047064f1 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -14,7 +14,7 @@ use rustc_target::abi::LayoutOf; use crate::*; /// Represent how path separator conversion should be done. -pub enum Pathconversion { +pub enum PathConversion { HostToTarget, TargetToHost, } @@ -188,7 +188,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); let os_str = this.read_os_str_from_c_str(scalar)?; - Ok(match this.convert_path_separator(Cow::Borrowed(os_str), Pathconversion::TargetToHost) { + Ok(match this.convert_path_separator(Cow::Borrowed(os_str), PathConversion::TargetToHost) { Cow::Borrowed(x) => Cow::Borrowed(Path::new(x)), Cow::Owned(y) => Cow::Owned(PathBuf::from(y)), }) @@ -199,7 +199,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); let os_str = this.read_os_str_from_wide_str(scalar)?; - Ok(this.convert_path_separator(Cow::Owned(os_str), Pathconversion::TargetToHost).into_owned().into()) + Ok(this.convert_path_separator(Cow::Owned(os_str), PathConversion::TargetToHost).into_owned().into()) } /// Write a Path to the machine memory (as a null-terminated sequence of bytes), @@ -211,7 +211,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = this.convert_path_separator(Cow::Borrowed(path.as_os_str()), Pathconversion::HostToTarget); + let os_str = this.convert_path_separator(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); this.write_os_str_to_c_str(&os_str, scalar, size) } @@ -224,14 +224,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = this.convert_path_separator(Cow::Borrowed(path.as_os_str()), Pathconversion::HostToTarget); + let os_str = this.convert_path_separator(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); this.write_os_str_to_wide_str(&os_str, scalar, size) } fn convert_path_separator<'a>( &self, os_str: Cow<'a, OsStr>, - direction: Pathconversion, + direction: PathConversion, ) -> Cow<'a, OsStr> { let this = self.eval_context_ref(); let target_os = &this.tcx.sess.target.target.target_os; @@ -242,8 +242,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { // Unix target, Windows host. let (from, to) = match direction { - Pathconversion::HostToTarget => ('\\', '/'), - Pathconversion::TargetToHost => ('/', '\\'), + PathConversion::HostToTarget => ('\\', '/'), + PathConversion::TargetToHost => ('/', '\\'), }; let converted = os_str .encode_wide() @@ -255,8 +255,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return if target_os == "windows" { // Windows target, Unix host. let (from, to) = match direction { - Pathconversion::HostToTarget => ('/', '\\'), - Pathconversion::TargetToHost => ('\\', '/'), + PathConversion::HostToTarget => ('/', '\\'), + PathConversion::TargetToHost => ('\\', '/'), }; let converted = os_str .as_bytes() diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index e84731a5ef73..4e8d38a977c5 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -1372,7 +1372,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = std::fs::read_link(pathname); match result { Ok(resolved) => { - let resolved = this.convert_path_separator(Cow::Borrowed(resolved.as_ref()), crate::shims::os_str::Pathconversion::HostToTarget); + let resolved = this.convert_path_separator(Cow::Borrowed(resolved.as_ref()), crate::shims::os_str::PathConversion::HostToTarget); let mut path_bytes = crate::shims::os_str::os_str_to_bytes(resolved.as_ref())?; let bufsize: usize = bufsize.try_into().unwrap(); if path_bytes.len() > bufsize { From 3aaab3dd9809aa8f9576b77122ba2601fb3ddd52 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Oct 2020 23:07:19 +0200 Subject: [PATCH 2376/5092] more punctuation --- src/shims/posix/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 4e8d38a977c5..ebf7e16a1534 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -1379,7 +1379,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx path_bytes = &path_bytes[..bufsize] } // 'readlink' truncates the resolved path if - // the provided buffer is not large enough + // the provided buffer is not large enough. this.memory.write_bytes(buf, path_bytes.iter().copied())?; Ok(path_bytes.len().try_into().unwrap()) } From 808032a0edc4614079c47d114769e11ceca26a62 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Oct 2020 10:22:41 +0200 Subject: [PATCH 2377/5092] rustup; disable opt level >=2 tests due to ICE --- ci.sh | 3 ++- rust-version | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ci.sh b/ci.sh index 56a6f1228ab5..a6daa8064530 100755 --- a/ci.sh +++ b/ci.sh @@ -25,7 +25,8 @@ function run_tests { ./miri test --locked if ! [ -n "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with MIR optimizations - MIRIFLAGS="-Z mir-opt-level=3" ./miri test --locked + #FIXME: Only testing opt level 1 due to . + MIRIFLAGS="-Z mir-opt-level=1" ./miri test --locked fi # "miri test" has built the sysroot for us, now this should pass without # any interactive questions. diff --git a/rust-version b/rust-version index 622fa14d1c29..b0644a3d7319 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a835b483fe0418b48ca44afb65cd0dd6bad4eb9b +efbaa413061c2a6e52f06f00a60ee7830fcf3ea5 From 8e8828259ac1433dd3981fcec9670d7394c2ade5 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 5 Oct 2020 17:29:55 -0400 Subject: [PATCH 2378/5092] Use macro callsite spans in backtrace This mirrors what we do in the debuginfo used for runtime backtraces. --- src/shims/backtrace.rs | 8 +++++++- tests/run-pass/backtrace-api.rs | 8 +++++++- tests/run-pass/backtrace-api.stderr | 5 +++-- tests/run-pass/backtrace-api.stdout | 5 +++-- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 75cd61b0f59e..bd36587116a0 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -26,7 +26,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut data = Vec::new(); for frame in this.active_thread_stack().iter().rev() { - data.push((frame.instance, frame.current_span().lo())); + let mut span = frame.current_span(); + // Match the behavior of runtime backtrace spans + // by using a non-macro span in our backtrace. See `FunctionCx::debug_loc`. + if span.from_expansion() && !tcx.sess.opts.debugging_opts.debug_macros { + span = rustc_span::hygiene::walk_chain(span, frame.body.span.ctxt()) + } + data.push((frame.instance, span.lo())); } let ptrs: Vec<_> = data.into_iter().map(|(instance, pos)| { diff --git a/tests/run-pass/backtrace-api.rs b/tests/run-pass/backtrace-api.rs index 80e64c2e1c8b..eaf29abfd9f4 100644 --- a/tests/run-pass/backtrace-api.rs +++ b/tests/run-pass/backtrace-api.rs @@ -18,7 +18,13 @@ struct MiriFrame { #[inline(never)] fn func_a() -> Box<[*mut ()]> { func_b::() } #[inline(never)] fn func_b() -> Box<[*mut ()]> { func_c() } -#[inline(never)] fn func_c() -> Box<[*mut ()]> { unsafe { miri_get_backtrace(0) } } + +macro_rules! invoke_func_d { + () => { func_d() } +} + +#[inline(never)] fn func_c() -> Box<[*mut ()]> { invoke_func_d!() } +#[inline(never)] fn func_d() -> Box<[*mut ()]> { unsafe { miri_get_backtrace(0) } } fn main() { let mut seen_main = false; diff --git a/tests/run-pass/backtrace-api.stderr b/tests/run-pass/backtrace-api.stderr index 15851a1cc725..02e7a7e1eaf9 100644 --- a/tests/run-pass/backtrace-api.stderr +++ b/tests/run-pass/backtrace-api.stderr @@ -1,7 +1,8 @@ -$DIR/backtrace-api.rs:21:59 (func_c) +$DIR/backtrace-api.rs:27:59 (func_d) +$DIR/backtrace-api.rs:26:50 (func_c) $DIR/backtrace-api.rs:20:53 (func_b) $DIR/backtrace-api.rs:19:50 (func_a) -$DIR/backtrace-api.rs:25:18 (main) +$DIR/backtrace-api.rs:31:18 (main) RUSTLIB/core/src/ops/function.rs:LL:COL (>::call_once - shim(fn())) RUSTLIB/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace) RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start::{closure#0}) diff --git a/tests/run-pass/backtrace-api.stdout b/tests/run-pass/backtrace-api.stdout index 453cf0b774a1..90ab4bb96e62 100644 --- a/tests/run-pass/backtrace-api.stdout +++ b/tests/run-pass/backtrace-api.stdout @@ -1,4 +1,5 @@ -$DIR/backtrace-api.rs:21:59 (func_c) +$DIR/backtrace-api.rs:27:59 (func_d) +$DIR/backtrace-api.rs:26:50 (func_c) $DIR/backtrace-api.rs:20:53 (func_b::) $DIR/backtrace-api.rs:19:50 (func_a) -$DIR/backtrace-api.rs:25:18 (main) +$DIR/backtrace-api.rs:31:18 (main) From c3a122523326c3002524f86ae5186592467958d1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 6 Oct 2020 11:11:14 +0200 Subject: [PATCH 2379/5092] add bors notification jobs --- .github/workflows/ci.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 101618d1a7aa..0e7d6e1cd616 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,3 +33,25 @@ jobs: host_target: i686-pc-windows-msvc steps: - uses: actions/checkout@v2 + + # These jobs doesn't actually test anything, but they're only used to tell + # bors the build completed, as there is no practical way to detect when a + # workflow is successful listening to webhooks only. + # + # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! + end-success: + name: bors build finished + runs-on: ubuntu-latest + needs: [build] + if: github.event.pusher.name == 'bors' && success() + steps: + - name: mark the job as a success + run: exit 0 + end-failure: + name: bors build finished + runs-on: ubuntu-latest + needs: [build] + if: github.event.pusher.name == 'bors' && (failure() || cancelled()) + steps: + - name: mark the job as a failure + run: exit 1 From 3e655665b76e5771d74b6b2af9de1eaef5f43b60 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 19 Sep 2020 11:33:16 +0200 Subject: [PATCH 2380/5092] test VecDeque::iter_mut aliasing --- tests/run-pass/vecdeque.rs | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/vecdeque.rs b/tests/run-pass/vecdeque.rs index 9c9909802e20..34f32ee1d9c1 100644 --- a/tests/run-pass/vecdeque.rs +++ b/tests/run-pass/vecdeque.rs @@ -1,5 +1,17 @@ use std::collections::VecDeque; +fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { + // Gather all those references. + let mut refs: Vec<&mut T> = iter.collect(); + // Use them all. Twice, to be sure we got all interleavings. + for r in refs.iter_mut() { + std::mem::swap(dummy, r); + } + for r in refs { + std::mem::swap(dummy, r); + } +} + fn main() { let mut dst = VecDeque::new(); dst.push_front(Box::new(1)); @@ -18,6 +30,21 @@ fn main() { println!("{:?}", VecDeque::::new().iter()); for a in dst { - assert_eq!(*a, 2); + assert_eq!(*a, 2); } + + // # Aliasing tests. + let mut v = std::collections::VecDeque::new(); + v.push_back(1); + v.push_back(2); + + // Test `fold` bad aliasing. + let mut it = v.iter_mut(); + let ref0 = it.next().unwrap(); + let sum = it.fold(0, |x, y| x + *y); + assert_eq!(*ref0 + sum, 3); + + // Test general iterator aliasing. + v.push_front(0); + test_all_refs(&mut 0, v.iter_mut()); } From 63a0f04ed05af0b0822bfe000511e37489b71662 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Oct 2020 09:05:18 +0200 Subject: [PATCH 2381/5092] rustup; bring back mir-opt-level 3 --- ci.sh | 3 +-- rust-version | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/ci.sh b/ci.sh index a6daa8064530..56a6f1228ab5 100755 --- a/ci.sh +++ b/ci.sh @@ -25,8 +25,7 @@ function run_tests { ./miri test --locked if ! [ -n "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with MIR optimizations - #FIXME: Only testing opt level 1 due to . - MIRIFLAGS="-Z mir-opt-level=1" ./miri test --locked + MIRIFLAGS="-Z mir-opt-level=3" ./miri test --locked fi # "miri test" has built the sysroot for us, now this should pass without # any interactive questions. diff --git a/rust-version b/rust-version index b0644a3d7319..79ba8eebc192 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -efbaa413061c2a6e52f06f00a60ee7830fcf3ea5 +c9ced8523bbb90561385aab305232f2167228a83 From 5058ec18f161c075e2b754c8a6df131cfeaf6f6a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Oct 2020 19:42:33 +0200 Subject: [PATCH 2382/5092] fix for rlib/cdylib crates in dependency tree --- cargo-miri/bin.rs | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 5731a9a591f9..72c873b229e9 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -532,8 +532,7 @@ fn phase_cargo_rustc(args: env::Args) { fn is_runnable_crate() -> bool { let is_bin = get_arg_flag_value("--crate-type").as_deref().unwrap_or("bin") == "bin"; let is_test = has_arg_flag("--test"); - let print = get_arg_flag_value("--print").is_some(); - (is_bin || is_test) && !print + is_bin || is_test } fn out_filename(prefix: &str, suffix: &str) -> PathBuf { @@ -552,8 +551,21 @@ fn phase_cargo_rustc(args: env::Args) { let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); let target_crate = is_target_crate(); + let print = get_arg_flag_value("--print").is_some(); // whether this is cargo passing `--print` to get some infos - if target_crate && is_runnable_crate() { + // rlib and cdylib are just skipped, we cannot interpret them and do not need them + // for the rest of the build either. + match get_arg_flag_value("--crate-type").as_deref() { + Some("rlib") | Some("cdylib") => { + if verbose { + eprint!("[cargo-miri rustc] (rlib/cdylib skipped)"); + } + return; + } + _ => {}, + } + + if !print && target_crate && is_runnable_crate() { // This is the binary or test crate that we want to interpret under Miri. // But we cannot run it here, as cargo invoked us as a compiler -- our stdin and stdout are not // like we want them. @@ -577,7 +589,7 @@ fn phase_cargo_rustc(args: env::Args) { let mut emit_link_hack = false; // Arguments are treated very differently depending on whether this crate is // for interpretation by Miri, or for use by a build script / proc macro. - if target_crate { + if !print && target_crate { // Forward arguments, but remove "link" from "--emit" to make this a check-only build. let emit_flag = "--emit"; for arg in args { @@ -607,7 +619,7 @@ fn phase_cargo_rustc(args: env::Args) { cmd.arg("--sysroot"); cmd.arg(sysroot); } else { - // For host crates, just forward everything. + // For host crates or when we are printing, just forward everything. cmd.args(args); } From e6665109e0708675563d391ede46b2bdf24e8ecc Mon Sep 17 00:00:00 2001 From: Yonggang Luo Date: Fri, 9 Oct 2020 13:16:03 +0800 Subject: [PATCH 2383/5092] Update README.md Note however that [leak checking is currently disabled on Windows targets](https://github.com/rust-lang/miri/issues/1302). Windows issue are fixed --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 2b015104828e..ceaf993924ef 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,7 @@ for example: On top of that, Miri will also tell you about memory leaks: when there is memory still allocated at the end of the execution, and that memory is not reachable -from a global `static`, Miri will raise an error. Note however that -[leak checking is currently disabled on Windows targets](https://github.com/rust-lang/miri/issues/1302). +from a global `static`, Miri will raise an error. Miri has already discovered some [real-world bugs](#bugs-found-by-miri). If you found a bug with Miri, we'd appreciate if you tell us and we'll add it to the From be51e6bd07c10ff350350fe05f2888c4ce3a08a0 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 10 Oct 2020 13:07:57 -0400 Subject: [PATCH 2384/5092] Add an `fn_ptr` field to `MiriFrame` The `backtrace-rs` crate can use this to implement `Frame::symbol_address`, which is used to skip frames above the call to `Backtrace::capture` on the stack. The function pointer will not be useable for comparison purposes if the function is generic, as CTFE creates a new function pointer for each cast of a (monomorphized) generic function. However, this already affects code running under Miri, and isn't a problem for `backtrace-rs` (which only casts a non-generic function). I've added logic to allow `MiriFrame` to have either 4 or 5 fields - if a 5th field is present, we write the function pointer to it. --- README.md | 4 ++ src/shims/backtrace.rs | 19 +++++++++- .../backtrace/bad-backtrace-decl.rs | 2 +- tests/run-pass/backtrace-api.rs | 37 ++++++++++++------- tests/run-pass/backtrace-api.stderr | 10 ++--- tests/run-pass/backtrace-api.stdout | 10 ++--- 6 files changed, 55 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index ceaf993924ef..747afb9c4e93 100644 --- a/README.md +++ b/README.md @@ -286,6 +286,10 @@ extern "Rust" { /// lineno: u32, /// // The column number currently being executed in `filename`, starting from '1'. /// colno: u32, + /// // The function pointer to the function currently being executed. + /// // This can be compared against function pointers obtained by + /// // casting a function (e.g. `my_fn as *mut ()`) + /// fn_ptr: *mut () /// } /// ``` /// diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index bd36587116a0..9b396c718493 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -92,8 +92,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_ub_format!("expected function pointer, found {:?}", ptr); }; - if dest.layout.layout.fields.count() != 4 { - throw_ub_format!("bad declaration of miri_resolve_frame - should return a struct with 4 fields"); + // Reconstruct the original function pointer, + // which we pass to user code. + let mut fn_ptr = ptr; + fn_ptr.offset = Size::from_bytes(0); + let fn_ptr = Scalar::Ptr(fn_ptr); + + let num_fields = dest.layout.layout.fields.count(); + + if num_fields != 4 && num_fields != 5 { + // Always mention 5 fields, since the 4-field struct is only supported + // for backwards compatiblity. New code should declare 5 fields + throw_ub_format!("bad declaration of miri_resolve_frame - should return a struct with 5 fields"); } let pos = BytePos(ptr.offset.bytes().try_into().unwrap()); @@ -122,6 +132,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_immediate(filename_alloc.to_ref(), this.mplace_field(dest, 1)?.into())?; this.write_scalar(lineno_alloc, this.mplace_field(dest, 2)?.into())?; this.write_scalar(colno_alloc, this.mplace_field(dest, 3)?.into())?; + + if num_fields == 5 { + this.write_scalar(fn_ptr, this.mplace_field(dest, 4)?.into())?; + } + Ok(()) } } diff --git a/tests/compile-fail/backtrace/bad-backtrace-decl.rs b/tests/compile-fail/backtrace/bad-backtrace-decl.rs index b9f1c779ae23..23379992d5ec 100644 --- a/tests/compile-fail/backtrace/bad-backtrace-decl.rs +++ b/tests/compile-fail/backtrace/bad-backtrace-decl.rs @@ -7,7 +7,7 @@ fn main() { let frames = unsafe { miri_get_backtrace(0) }; for frame in frames.into_iter() { unsafe { - miri_resolve_frame(*frame, 0); //~ ERROR Undefined Behavior: bad declaration of miri_resolve_frame - should return a struct with 4 fields + miri_resolve_frame(*frame, 0); //~ ERROR Undefined Behavior: bad declaration of miri_resolve_frame - should return a struct with 5 fields } } } diff --git a/tests/run-pass/backtrace-api.rs b/tests/run-pass/backtrace-api.rs index eaf29abfd9f4..19169060038e 100644 --- a/tests/run-pass/backtrace-api.rs +++ b/tests/run-pass/backtrace-api.rs @@ -2,20 +2,6 @@ // normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL " // normalize-stderr-test "::<.*>" -> "" -extern "Rust" { - fn miri_get_backtrace(flags: u64) -> Box<[*mut ()]>; - fn miri_resolve_frame(ptr: *mut (), flags: u64) -> MiriFrame; -} - -#[derive(Debug)] -#[repr(C)] -struct MiriFrame { - name: Box<[u8]>, - filename: Box<[u8]>, - lineno: u32, - colno: u32 -} - #[inline(never)] fn func_a() -> Box<[*mut ()]> { func_b::() } #[inline(never)] fn func_b() -> Box<[*mut ()]> { func_c() } @@ -34,6 +20,10 @@ fn main() { let name = String::from_utf8(miri_frame.name.into()).unwrap(); let filename = String::from_utf8(miri_frame.filename.into()).unwrap(); + if name == "func_a" { + assert_eq!(func_a as *mut (), miri_frame.fn_ptr); + } + // Print every frame to stderr. let out = format!("{}:{}:{} ({})", filename, miri_frame.lineno, miri_frame.colno, name); eprintln!("{}", out); @@ -45,3 +35,22 @@ fn main() { } } } + +// This goes at the bottom of the file so that we can change it +// without disturbing line numbers of the functions in the backtrace. + +extern "Rust" { + fn miri_get_backtrace(flags: u64) -> Box<[*mut ()]>; + fn miri_resolve_frame(ptr: *mut (), flags: u64) -> MiriFrame; +} + +#[derive(Debug)] +#[repr(C)] +struct MiriFrame { + name: Box<[u8]>, + filename: Box<[u8]>, + lineno: u32, + colno: u32, + fn_ptr: *mut (), +} + diff --git a/tests/run-pass/backtrace-api.stderr b/tests/run-pass/backtrace-api.stderr index 02e7a7e1eaf9..a5208221da40 100644 --- a/tests/run-pass/backtrace-api.stderr +++ b/tests/run-pass/backtrace-api.stderr @@ -1,8 +1,8 @@ -$DIR/backtrace-api.rs:27:59 (func_d) -$DIR/backtrace-api.rs:26:50 (func_c) -$DIR/backtrace-api.rs:20:53 (func_b) -$DIR/backtrace-api.rs:19:50 (func_a) -$DIR/backtrace-api.rs:31:18 (main) +$DIR/backtrace-api.rs:13:59 (func_d) +$DIR/backtrace-api.rs:12:50 (func_c) +$DIR/backtrace-api.rs:6:53 (func_b) +$DIR/backtrace-api.rs:5:50 (func_a) +$DIR/backtrace-api.rs:17:18 (main) RUSTLIB/core/src/ops/function.rs:LL:COL (>::call_once - shim(fn())) RUSTLIB/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace) RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start::{closure#0}) diff --git a/tests/run-pass/backtrace-api.stdout b/tests/run-pass/backtrace-api.stdout index 90ab4bb96e62..175ff3b82946 100644 --- a/tests/run-pass/backtrace-api.stdout +++ b/tests/run-pass/backtrace-api.stdout @@ -1,5 +1,5 @@ -$DIR/backtrace-api.rs:27:59 (func_d) -$DIR/backtrace-api.rs:26:50 (func_c) -$DIR/backtrace-api.rs:20:53 (func_b::) -$DIR/backtrace-api.rs:19:50 (func_a) -$DIR/backtrace-api.rs:31:18 (main) +$DIR/backtrace-api.rs:13:59 (func_d) +$DIR/backtrace-api.rs:12:50 (func_c) +$DIR/backtrace-api.rs:6:53 (func_b::) +$DIR/backtrace-api.rs:5:50 (func_a) +$DIR/backtrace-api.rs:17:18 (main) From 71e0e59b63a5476e8a215d76014efb51335e2151 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 11 Oct 2020 10:48:34 +0200 Subject: [PATCH 2385/5092] README: make our cross-interpretation feature stand out more --- README.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index ceaf993924ef..66f4801fc605 100644 --- a/README.md +++ b/README.md @@ -87,11 +87,6 @@ can pass arguments to Miri via `MIRIFLAGS`. For example, `MIRIFLAGS="-Zmiri-disable-stacked-borrows" cargo miri run` runs the program without checking the aliasing of references. -Miri supports cross-execution: if you want to run the program as if it was a -Linux program, you can do `cargo miri run --target x86_64-unknown-linux-gnu`. -This is particularly useful if you are using Windows, as the Linux target is -much better supported than Windows targets. - When compiling code via `cargo miri`, the `cfg(miri)` config flag is set. You can use this to ignore test cases that fail under Miri because they do things Miri does not support: @@ -116,6 +111,19 @@ error: unsupported operation: can't call foreign function: bind performed an operation that the interpreter does not support ``` +### Cross-interpretation: running for different targets + +Miri cannot just run a binary or test suite for your host target, it can also +perform cross-interpretation for arbitrary foreign targets: `cargo miri run +--target x86_64-unknown-linux-gnu` will run your program as if it was a Linux +program, no matter your host OS. This is particularly useful if you are using +Windows, as the Linux target is much better supported than Windows targets. + +You can also use this to test platforms with different properties than your host +platform. For example `cargo miri test --target mips64-unknown-linux-gnuabi64` +will run your test suite on a big-endian target, which is useful for testing +endian-sensitive code. + ### Running Miri on CI To run Miri on CI, make sure that you handle the case where the latest nightly From 6acde94931c5a7ac0f8b2abb38a91139d89c0675 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 4 Oct 2020 22:01:10 +0700 Subject: [PATCH 2386/5092] Add a working github actions template --- .appveyor.yml | 7 +++-- .github/workflows/ci.yml | 60 +++++++++++++++++++++++++++++++++++++++- .travis.yml | 9 ++++-- README.md | 8 +++++- ci.sh | 46 ++++++++++++++++++------------ 5 files changed, 105 insertions(+), 25 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 5cb5267a6da5..82c668f0e75d 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -3,7 +3,7 @@ environment: global: PROJECT_NAME: miri matrix: - - TARGET: i686-pc-windows-msvc + - HOST_TARGET: i686-pc-windows-msvc matrix: fast_finish: true # Immediately finish build once one of the jobs fails. cache: @@ -23,7 +23,7 @@ install: # Install Rust. We use the "stable" toolchain for better caching, it is just used to build `rustup-toolchain-install-master`. # But we also need to take into account that the build cache might have a different, outdated default. - curl -sSf --retry 3 -o rustup-init.exe https://win.rustup.rs/ -- rustup-init.exe -y --default-host %TARGET% --default-toolchain none --profile minimal +- rustup-init.exe -y --default-host %HOST_TARGET% --default-toolchain none --profile minimal - set PATH=%USERPROFILE%\.cargo\bin;%PATH% - rustup default stable - rustup toolchain uninstall beta nightly @@ -36,7 +36,8 @@ install: - cargo --version test_script: -- set PYTHON=C:\msys64\mingw64\bin\python3.exe +# Add python3 path: https://www.appveyor.com/docs/windows-images-software/#python +- set PATH=C:\Python35-x64;%PATH% - bash ci.sh after_test: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0e7d6e1cd616..b5ef3d861ead 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,13 +11,14 @@ on: - 'master' schedule: # Use to conveniently edit cron schedule. - - cron: "0 7 * * *" # At 07:00 UTC every day. + - cron: '0 7 * * *' # At 07:00 UTC every day. jobs: build: runs-on: ${{ matrix.os }} env: RUST_BACKTRACE: 1 + HOST_TARGET: ${{ matrix.host_target }} strategy: matrix: build: [linux64, macos, win32] @@ -34,6 +35,63 @@ jobs: steps: - uses: actions/checkout@v2 + # We install gnu-tar because BSD tar is buggy on macOS builders of GHA. + # See . + - name: Install GNU tar + if: runner.os == 'macOS' + run: | + brew install gnu-tar + echo "/usr/local/opt/gnu-tar/libexec/gnubin" >> $GITHUB_PATH + + # Cache the global cargo directory, but NOT the local `target` directory which + # we cannot reuse anyway when the nightly changes (and it grows quite large + # over time). + - name: Add cache for cargo + uses: actions/cache@v2 + with: + path: | + # Taken from . + ~/.cargo/bin + ~/.cargo/registry/index + ~/.cargo/registry/cache + ~/.cargo/git/db + # contains package information of crates installed via `cargo install`. + ~/.cargo/.crates.toml + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: ${{ runner.os }}-cargo + + - name: Install rustup-toolchain-install-master and xargo + run: | + cargo install rustup-toolchain-install-master + cargo install xargo + shell: bash + + - name: Install "master" toolchain + run: | + if [[ ${{ github.event_name }} == 'schedule' ]]; then + RUSTC_HASH=$(git ls-remote https://github.com/rust-lang/rust.git master | awk '{print $1}') + else + RUSTC_HASH=$(< rust-version) + fi + rustup-toolchain-install-master \ + -f \ + -n master "$RUSTC_HASH" \ + -c rust-src \ + -c rustc-dev \ + -c llvm-tools \ + --host ${{ matrix.host_target }} + rustup default master + shell: bash + + - name: Show Rust version + run: | + rustup show + rustc -Vv + cargo -V + + - name: Test + run: bash ./ci.sh + # These jobs doesn't actually test anything, but they're only used to tell # bors the build completed, as there is no practical way to detect when a # workflow is successful listening to webhooks only. diff --git a/.travis.yml b/.travis.yml index fcef17b124dd..86dcf78435b2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,10 @@ language: generic -os: -- linux -- osx +jobs: + include: + - os: linux + env: HOST_TARGET=x86_64-unknown-linux-gnu + - os: osx + env: HOST_TARGET=x86_64-apple-darwin dist: xenial cache: # Cache the global cargo directory, but NOT the local `target` directory which diff --git a/README.md b/README.md index 2b015104828e..418b7a1ee301 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,11 @@ -# Miri [![Build Status](https://travis-ci.com/rust-lang/miri.svg?branch=master)](https://travis-ci.com/rust-lang/miri) [![Windows build status](https://ci.appveyor.com/api/projects/status/github/rust-lang/miri?svg=true)](https://ci.appveyor.com/project/rust-lang-libs/miri) +# Miri +[![Actions build status][actions-badge]][actions-url] +[![Travis build status](https://travis-ci.com/rust-lang/miri.svg?branch=master)](https://travis-ci.com/rust-lang/miri) +[![Appveyor Windows build status](https://ci.appveyor.com/api/projects/status/github/rust-lang/miri?svg=true)](https://ci.appveyor.com/project/rust-lang-libs/miri) + +[actions-badge]: https://github.com/rust-lang/miri/workflows/CI/badge.svg?branch=master +[actions-url]: https://github.com/rust-lang/miri/actions An experimental interpreter for [Rust][rust]'s [mid-level intermediate representation][mir] (MIR). It can run binaries and diff --git a/ci.sh b/ci.sh index a6daa8064530..8827c90d3bdf 100755 --- a/ci.sh +++ b/ci.sh @@ -23,32 +23,44 @@ function run_tests { fi ./miri test --locked - if ! [ -n "${MIRI_TEST_TARGET+exists}" ]; then + if [ -z "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with MIR optimizations #FIXME: Only testing opt level 1 due to . MIRIFLAGS="-Z mir-opt-level=1" ./miri test --locked fi + + # On Windows, there is always "python", not "python3" or "python2". + if command -v python3 > /dev/null; then + PYTHON=python3 + else + PYTHON=python + fi + # "miri test" has built the sysroot for us, now this should pass without # any interactive questions. - ${PYTHON:-python3} test-cargo-miri/run-test.py - + ${PYTHON} test-cargo-miri/run-test.py echo } # host run_tests -if [ "${TRAVIS_OS_NAME:-}" == linux ]; then - MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests - MIRI_TEST_TARGET=x86_64-apple-darwin run_tests - MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests -elif [ "${TRAVIS_OS_NAME:-}" == osx ]; then - MIRI_TEST_TARGET=mips64-unknown-linux-gnuabi64 run_tests # big-endian architecture - MIRI_TEST_TARGET=x86_64-pc-windows-msvc run_tests -elif [ "${CI_WINDOWS:-}" == True ]; then - MIRI_TEST_TARGET=x86_64-unknown-linux-gnu run_tests - MIRI_TEST_TARGET=x86_64-apple-darwin run_tests -else - echo "FATAL: unknown CI platform" - exit 1 -fi +case $HOST_TARGET in + x86_64-unknown-linux-gnu) + MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests + MIRI_TEST_TARGET=x86_64-apple-darwin run_tests + MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests + ;; + x86_64-apple-darwin) + MIRI_TEST_TARGET=mips64-unknown-linux-gnuabi64 run_tests # big-endian architecture + MIRI_TEST_TARGET=x86_64-pc-windows-msvc run_tests + ;; + i686-pc-windows-msvc) + MIRI_TEST_TARGET=x86_64-unknown-linux-gnu run_tests + MIRI_TEST_TARGET=x86_64-apple-darwin run_tests + ;; + *) + echo "FATAL: unknown OS" + exit 1 + ;; +esac From 6a6767fa2aa87567ec7dfa82f3cecaf773b0b1d0 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 11 Oct 2020 11:05:14 -0400 Subject: [PATCH 2387/5092] Apply suggestions from code review Co-authored-by: Ralf Jung --- src/shims/backtrace.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 9b396c718493..74edce612a29 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -100,9 +100,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let num_fields = dest.layout.layout.fields.count(); - if num_fields != 4 && num_fields != 5 { + if !(4..=5).contains(&num_fields) { // Always mention 5 fields, since the 4-field struct is only supported - // for backwards compatiblity. New code should declare 5 fields + // for backwards compatiblity. New code should declare 5 fields. throw_ub_format!("bad declaration of miri_resolve_frame - should return a struct with 5 fields"); } From 0893ea1973b479198722556ec2115af21e3b097c Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 11 Oct 2020 17:05:40 -0400 Subject: [PATCH 2388/5092] Rustup This gets Miri building again after the `run_compiler` changes --- benches/helpers/miri_helper.rs | 2 +- rust-version | 2 +- src/bin/miri-rustc-tests.rs | 11 ++++------- src/bin/miri.rs | 2 +- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index a77f914c1c6b..261be48aa0a3 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -55,5 +55,5 @@ pub fn run(filename: &str, bencher: &mut Bencher) { "--sysroot".to_string(), find_sysroot(), ]; - rustc_driver::run_compiler(args, &mut MiriCompilerCalls { bencher }, None, None, None).unwrap() + rustc_driver::RunCompiler::new(args, &mut MiriCompilerCalls { bencher }).run().unwrap() } diff --git a/rust-version b/rust-version index 79ba8eebc192..6c876993b798 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c9ced8523bbb90561385aab305232f2167228a83 +06a079c43efb062e335e6e6c9dabd3c750619980 diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 7c9dfbb277b9..7c2419dde3f4 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -140,13 +140,10 @@ fn main() { let buf = BufWriter::default(); let output = buf.clone(); let result = std::panic::catch_unwind(|| { - let _ = rustc_driver::run_compiler( - &args, - &mut MiriCompilerCalls { host_target }, - None, - Some(Box::new(buf)), - None, - ); + let mut callbacks = MiriCompilerCalls { host_target }; + let mut run = rustc_driver::RunCompiler::new(&args, &mut callbacks); + run.set_emitter(Some(Box::new(buf))); + let _ = run.run(); }); match result { diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 7b417990af86..71d561b9f7da 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -157,7 +157,7 @@ fn run_compiler(mut args: Vec, callbacks: &mut (dyn rustc_driver::Callba // Invoke compiler, and handle return code. let exit_code = rustc_driver::catch_with_exit_code(move || { - rustc_driver::run_compiler(&args, callbacks, None, None, None) + rustc_driver::RunCompiler::new(&args, callbacks).run() }); std::process::exit(exit_code) } From c889eba4b27e9b365a8824969aa3deb0525fa0c0 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 11 Oct 2020 17:57:49 -0400 Subject: [PATCH 2389/5092] Add comment about deprecation --- src/shims/backtrace.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 74edce612a29..8cf7ac207528 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -101,8 +101,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let num_fields = dest.layout.layout.fields.count(); if !(4..=5).contains(&num_fields) { - // Always mention 5 fields, since the 4-field struct is only supported - // for backwards compatiblity. New code should declare 5 fields. + // Always mention 5 fields, since the 4-field struct + // is deprecated and slated for removal. throw_ub_format!("bad declaration of miri_resolve_frame - should return a struct with 5 fields"); } @@ -133,6 +133,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(lineno_alloc, this.mplace_field(dest, 2)?.into())?; this.write_scalar(colno_alloc, this.mplace_field(dest, 3)?.into())?; + // Support a 4-field struct for now - this is deprecated + // and slated for removal. if num_fields == 5 { this.write_scalar(fn_ptr, this.mplace_field(dest, 4)?.into())?; } From 3bdf2bccaed5fa6fb21125f4563aef22810d4ef0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Oct 2020 00:15:01 +0200 Subject: [PATCH 2390/5092] Improve wording Co-authored-by: Aaron Hill --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 66f4801fc605..be0df81f7943 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ error: unsupported operation: can't call foreign function: bind ### Cross-interpretation: running for different targets -Miri cannot just run a binary or test suite for your host target, it can also +Miri can not only run a binary or test suite for your host target, it can also perform cross-interpretation for arbitrary foreign targets: `cargo miri run --target x86_64-unknown-linux-gnu` will run your program as if it was a Linux program, no matter your host OS. This is particularly useful if you are using From 1ae157bc9e066c0228d826720babc4d09154e682 Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 14 Oct 2020 19:16:00 +0200 Subject: [PATCH 2391/5092] Replace target.target with target Rustc removed the target wrapper and exposed the target directly. Result of running: find . -type f -exec sed -i -e 's/target\.target\([)\.,;]\)/target\1/g' {} \; Plus one manual edit of the rust-version file --- rust-version | 2 +- src/helpers.rs | 4 ++-- src/machine.rs | 2 +- src/shims/env.rs | 12 ++++++------ src/shims/foreign_items.rs | 6 +++--- src/shims/os_str.rs | 2 +- src/shims/posix/foreign_items.rs | 4 ++-- src/shims/posix/fs.rs | 4 ++-- src/shims/posix/linux/dlsym.rs | 2 +- src/shims/posix/macos/dlsym.rs | 2 +- src/shims/tls.rs | 2 +- src/shims/windows/dlsym.rs | 2 +- src/shims/windows/foreign_items.rs | 2 +- 13 files changed, 23 insertions(+), 23 deletions(-) diff --git a/rust-version b/rust-version index 6c876993b798..e00bba686766 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -06a079c43efb062e335e6e6c9dabd3c750619980 +b5c9e2448c9ace53ad5c11585803894651b18b0a diff --git a/src/helpers.rs b/src/helpers.rs index 23bc54e76bb0..a13d9b4519bd 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -387,7 +387,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// if this is not the case. fn assert_target_os(&self, target_os: &str, name: &str) { assert_eq!( - self.eval_context_ref().tcx.sess.target.target.target_os, + self.eval_context_ref().tcx.sess.target.target_os, target_os, "`{}` is only available on the `{}` target OS", name, @@ -430,7 +430,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn set_last_error_from_io_error(&mut self, e: std::io::Error) -> InterpResult<'tcx> { use std::io::ErrorKind::*; let this = self.eval_context_mut(); - let target = &this.tcx.sess.target.target; + let target = &this.tcx.sess.target; let target_os = &target.target_os; let last_error = if target.options.target_family == Some("unix".to_owned()) { this.eval_libc(match e.kind() { diff --git a/src/machine.rs b/src/machine.rs index 6defb2d053aa..544f4667e846 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -173,7 +173,7 @@ impl MemoryExtra { pub fn init_extern_statics<'tcx, 'mir>( this: &mut MiriEvalContext<'mir, 'tcx>, ) -> InterpResult<'tcx> { - match this.tcx.sess.target.target.target_os.as_str() { + match this.tcx.sess.target.target_os.as_str() { "linux" => { // "__cxa_thread_atexit_impl" // This should be all-zero, pointer-sized. diff --git a/src/shims/env.rs b/src/shims/env.rs index 42fd6e3dced8..2db64ad5a14c 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -38,7 +38,7 @@ impl<'tcx> EnvVars<'tcx> { ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, mut excluded_env_vars: Vec, ) -> InterpResult<'tcx> { - let target_os = ecx.tcx.sess.target.target.target_os.as_str(); + let target_os = ecx.tcx.sess.target.target_os.as_str(); if target_os == "windows" { // Temporary hack: Exclude `TERM` var to avoid terminfo trying to open the termcap file. // Can be removed once https://github.com/rust-lang/miri/issues/1013 is resolved. @@ -101,7 +101,7 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn getenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.target.target_os; + let target_os = &this.tcx.sess.target.target_os; assert!(target_os == "linux" || target_os == "macos", "`getenv` is only available for the UNIX target family"); let name_ptr = this.read_scalar(name_op)?.check_init()?; @@ -185,7 +185,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx value_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let mut this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.target.target_os; + let target_os = &this.tcx.sess.target.target_os; assert!(target_os == "linux" || target_os == "macos", "`setenv` is only available for the UNIX target family"); let name_ptr = this.read_scalar(name_op)?.check_init()?; @@ -258,7 +258,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn unsetenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.target.target_os; + let target_os = &this.tcx.sess.target.target_os; assert!(target_os == "linux" || target_os == "macos", "`unsetenv` is only available for the UNIX target family"); let name_ptr = this.read_scalar(name_op)?.check_init()?; @@ -290,7 +290,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.target.target_os; + let target_os = &this.tcx.sess.target.target_os; assert!(target_os == "linux" || target_os == "macos", "`getcwd` is only available for the UNIX target family"); this.check_no_isolation("`getcwd`")?; @@ -336,7 +336,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn chdir(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.target.target_os; + let target_os = &this.tcx.sess.target.target_os; assert!(target_os == "linux" || target_os == "macos", "`getcwd` is only available for the UNIX target family"); this.check_no_isolation("`chdir`")?; diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 7118fbda2403..cd6024444fa5 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -19,7 +19,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn min_align(&self, size: u64, kind: MiriMemoryKind) -> Align { let this = self.eval_context_ref(); // List taken from `libstd/sys_common/alloc.rs`. - let min_align = match this.tcx.sess.target.target.arch.as_str() { + let min_align = match this.tcx.sess.target.arch.as_str() { "x86" | "arm" | "mips" | "powerpc" | "powerpc64" | "asmjs" | "wasm32" => 8, "x86_64" | "aarch64" | "mips64" | "s390x" | "sparc64" => 16, arch => bug!("Unsupported target architecture: {}", arch), @@ -480,13 +480,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Architecture-specific shims - "llvm.x86.sse2.pause" if this.tcx.sess.target.target.arch == "x86" || this.tcx.sess.target.target.arch == "x86_64" => { + "llvm.x86.sse2.pause" if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" => { let &[] = check_arg_count(args)?; this.yield_active_thread(); } // Platform-specific shims - _ => match this.tcx.sess.target.target.target_os.as_str() { + _ => match this.tcx.sess.target.target_os.as_str() { "linux" | "macos" => return shims::posix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), target => throw_unsup_format!("the target `{}` is not supported", target), diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 7635047064f1..268b0902e9c2 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -234,7 +234,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx direction: PathConversion, ) -> Cow<'a, OsStr> { let this = self.eval_context_ref(); - let target_os = &this.tcx.sess.target.target.target_os; + let target_os = &this.tcx.sess.target.target_os; #[cfg(windows)] return if target_os == "windows" { // Windows-on-Windows, all fine. diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 177678f03d74..c527fa0d064a 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -165,7 +165,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.read_scalar(handle)?.to_machine_usize(this)?; let symbol = this.read_scalar(symbol)?.check_init()?; let symbol_name = this.memory.read_c_str(symbol)?; - if let Some(dlsym) = Dlsym::from_str(symbol_name, &this.tcx.sess.target.target.target_os)? { + if let Some(dlsym) = Dlsym::from_str(symbol_name, &this.tcx.sess.target.target_os)? { let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); this.write_scalar(Scalar::from(ptr), dest)?; } else { @@ -452,7 +452,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Platform-specific shims _ => { - match this.tcx.sess.target.target.target_os.as_str() { + match this.tcx.sess.target.target_os.as_str() { "linux" => return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), "macos" => return shims::posix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), _ => unreachable!(), diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index ebf7e16a1534..a9d102912ab2 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -555,7 +555,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }, None => return this.handle_not_found(), } - } else if this.tcx.sess.target.target.target_os == "macos" + } else if this.tcx.sess.target.target_os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC")? { let &[_, _] = check_arg_count(args)?; @@ -989,7 +989,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("`mkdir`")?; #[cfg_attr(not(unix), allow(unused_variables))] - let mode = if this.tcx.sess.target.target.target_os == "macos" { + let mode = if this.tcx.sess.target.target_os == "macos" { u32::from(this.read_scalar(mode_op)?.check_init()?.to_u16()?) } else { this.read_scalar(mode_op)?.to_u32()? diff --git a/src/shims/posix/linux/dlsym.rs b/src/shims/posix/linux/dlsym.rs index 9be300edf495..af5f5a20e445 100644 --- a/src/shims/posix/linux/dlsym.rs +++ b/src/shims/posix/linux/dlsym.rs @@ -27,7 +27,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (_dest, _ret) = ret.expect("we don't support any diverging dlsym"); - assert!(this.tcx.sess.target.target.target_os == "linux"); + assert!(this.tcx.sess.target.target_os == "linux"); match dlsym {} } diff --git a/src/shims/posix/macos/dlsym.rs b/src/shims/posix/macos/dlsym.rs index c9f57090ff8a..82d8b16ad66a 100644 --- a/src/shims/posix/macos/dlsym.rs +++ b/src/shims/posix/macos/dlsym.rs @@ -32,7 +32,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (dest, ret) = ret.expect("we don't support any diverging dlsym"); - assert!(this.tcx.sess.target.target.target_os == "macos"); + assert!(this.tcx.sess.target.target_os == "macos"); match dlsym { Dlsym::getentropy => { diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 2ba0782f7054..7b4d8fa56ae4 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -340,7 +340,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This is the first time we got asked to schedule a destructor. The // Windows schedule destructor function must be called exactly once, // this is why it is in this block. - if this.tcx.sess.target.target.target_os == "windows" { + if this.tcx.sess.target.target_os == "windows" { // On Windows, we signal that the thread quit by starting the // relevant function, reenabling the thread, and going back to // the scheduler. diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 91bfedff8db6..5454a00f14d5 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -44,7 +44,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (dest, ret) = ret.expect("we don't support any diverging dlsym"); - assert!(this.tcx.sess.target.target.target_os == "windows"); + assert!(this.tcx.sess.target.target_os == "windows"); match dlsym { Dlsym::AcquireSRWLockExclusive => { diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index fc1093b64fb4..d141fa57e13a 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -213,7 +213,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[hModule, lpProcName] = check_arg_count(args)?; this.read_scalar(hModule)?.to_machine_isize(this)?; let name = this.memory.read_c_str(this.read_scalar(lpProcName)?.check_init()?)?; - if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.target.target_os)? { + if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.target_os)? { let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); this.write_scalar(Scalar::from(ptr), dest)?; } else { From 67cf6c21761a778d45784bc1189bdba7618a6ff1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 Oct 2020 00:49:52 +0200 Subject: [PATCH 2392/5092] rustup; the bad compile times for the float test are fixed --- rust-version | 2 +- tests/run-pass/float.rs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/rust-version b/rust-version index e00bba686766..13526a3fac9b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -b5c9e2448c9ace53ad5c11585803894651b18b0a +043eca7f0b34d12e61c44206beca740628647080 diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index 62d9c6076608..d0df13490f0c 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -1,5 +1,3 @@ -// compile-flags: -Zmir-opt-level=0 -// FIXME: Using opt-level 2 here makes the test take forever (https://github.com/rust-lang/rust/issues/73717). #![feature(stmt_expr_attributes, test)] use std::fmt::Debug; use std::hint::black_box; From 8b10dbfeaab5826fb3d179bb94454a80182a9c3a Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 17 Oct 2020 15:36:05 -0400 Subject: [PATCH 2393/5092] Test std::backtrace::Backtrace Fixes #1578 --- tests/run-pass/backtrace-std.rs | 22 ++++++++++++++++++++++ tests/run-pass/backtrace-std.stderr | 28 ++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 tests/run-pass/backtrace-std.rs create mode 100644 tests/run-pass/backtrace-std.stderr diff --git a/tests/run-pass/backtrace-std.rs b/tests/run-pass/backtrace-std.rs new file mode 100644 index 000000000000..579b4f32e7cc --- /dev/null +++ b/tests/run-pass/backtrace-std.rs @@ -0,0 +1,22 @@ +// normalize-stderr-test ".*/(rust|checkout)/library/" -> "RUSTLIB/" +// normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL " +// normalize-stderr-test "::<.*>" -> "" +// compile-flags: -Zmiri-disable-isolation + +#![feature(backtrace)] + +use std::backtrace::Backtrace; + +#[inline(never)] fn func_a() -> Backtrace { func_b::() } +#[inline(never)] fn func_b() -> Backtrace { func_c() } + +macro_rules! invoke_func_d { + () => { func_d() } +} + +#[inline(never)] fn func_c() -> Backtrace { invoke_func_d!() } +#[inline(never)] fn func_d() -> Backtrace { Backtrace::capture() } + +fn main() { + eprint!("{}", func_a()); +} diff --git a/tests/run-pass/backtrace-std.stderr b/tests/run-pass/backtrace-std.stderr new file mode 100644 index 000000000000..d14735c0405f --- /dev/null +++ b/tests/run-pass/backtrace-std.stderr @@ -0,0 +1,28 @@ + 0: func_d + at $DIR/backtrace-std.rs:18 + 1: func_c + at $DIR/backtrace-std.rs:17 + 2: func_b + at $DIR/backtrace-std.rs:11 + 3: func_a + at $DIR/backtrace-std.rs:10 + 4: main + at $DIR/backtrace-std.rs:21 + 5: >::call_once - shim(fn()) +RUSTLIB/core/src/ops/function.rs:227 + 6: std::sys_common::backtrace::__rust_begin_short_backtrace +RUSTLIB/std/src/sys_common/backtrace.rs:125 + 7: std::rt::lang_start::{closure#0} +RUSTLIB/std/src/rt.rs:66 + 8: std::ops::function::impls::call_once +RUSTLIB/core/src/ops/function.rs:259 + 9: std::panicking::r#try::do_call +RUSTLIB/std/src/panicking.rs:381 + 10: std::panicking::r#try +RUSTLIB/std/src/panicking.rs:345 + 11: std::panic::catch_unwind +RUSTLIB/std/src/panic.rs:382 + 12: std::rt::lang_start_internal +RUSTLIB/std/src/rt.rs:51 + 13: std::rt::lang_start +RUSTLIB/std/src/rt.rs:65 From 5df6d8bec6155e5300d28454a1fff7b52e7c7748 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 Oct 2020 11:22:09 +0200 Subject: [PATCH 2394/5092] test new available_concurrency function --- rust-version | 2 +- tests/run-pass/available-concurrency.rs | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 tests/run-pass/available-concurrency.rs diff --git a/rust-version b/rust-version index 13526a3fac9b..d5ddd1d0371e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -043eca7f0b34d12e61c44206beca740628647080 +c38ddb8040edce1b05bc09a0e8439472e9f67623 diff --git a/tests/run-pass/available-concurrency.rs b/tests/run-pass/available-concurrency.rs new file mode 100644 index 000000000000..5f3121ca8a63 --- /dev/null +++ b/tests/run-pass/available-concurrency.rs @@ -0,0 +1,5 @@ +#![feature(available_concurrency)] + +fn main() { + assert_eq!(std::thread::available_concurrency().unwrap().get(), 1); +} From 8462558b6c819e4dc9c82981f101fcb3e2853811 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Tue, 20 Oct 2020 12:26:30 +0700 Subject: [PATCH 2395/5092] build: Gate only on GHA: remove travis and appveyor ci config --- .appveyor.yml | 50 ------------------------------------------ .travis.yml | 60 --------------------------------------------------- 2 files changed, 110 deletions(-) delete mode 100644 .appveyor.yml delete mode 100644 .travis.yml diff --git a/.appveyor.yml b/.appveyor.yml deleted file mode 100644 index 82c668f0e75d..000000000000 --- a/.appveyor.yml +++ /dev/null @@ -1,50 +0,0 @@ -build: off # No Visual Studio auto-build. -environment: - global: - PROJECT_NAME: miri - matrix: - - HOST_TARGET: i686-pc-windows-msvc -matrix: - fast_finish: true # Immediately finish build once one of the jobs fails. -cache: -- '%USERPROFILE%\.cargo' -- '%USERPROFILE%\.rustup' - -# branches to build -branches: - # whitelist - only: - - auto - - try - -install: -# Compute the Rust version we use. -- set /p RUSTC_HASH= Date: Tue, 20 Oct 2020 13:27:58 -0400 Subject: [PATCH 2396/5092] Enable `backtrace` feature in the generated `Xargo.toml` This allows the normal std panic hook to print a backtrace if `RUST_BACKTRACE=1` and `-Z miri-disable-isolation` are set --- README.md | 13 ++++++++++ cargo-miri/bin.rs | 2 +- tests/run-pass/concurrency/simple.stderr | 1 + tests/run-pass/panic/catch_panic.stderr | 1 + tests/run-pass/panic/concurrent-panic.stderr | 1 + tests/run-pass/panic/div-by-zero-2.stderr | 1 + .../run-pass/panic/overflowing-lsh-neg.stderr | 1 + tests/run-pass/panic/overflowing-rsh-1.stderr | 1 + tests/run-pass/panic/overflowing-rsh-2.stderr | 1 + tests/run-pass/panic/panic1.rs | 6 +++++ tests/run-pass/panic/panic1.stderr | 24 ++++++++++++++++++- tests/run-pass/panic/panic2.stderr | 1 + tests/run-pass/panic/panic3.stderr | 1 + tests/run-pass/panic/panic4.stderr | 1 + tests/run-pass/transmute_fat2.stderr | 1 + 15 files changed, 54 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d8f0ef583f11..d41dc862e599 100644 --- a/README.md +++ b/README.md @@ -152,6 +152,19 @@ cargo miri test When using the above instructions, you may encounter a number of confusing compiler errors. +### "note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace" + +You may see this when trying to get Miri to display a backtrace. By default, Miri +doesn't expose any environment to the program, so running +`RUST_BACKTRACE=1 cargo miri test` will not do what you expect. + +To get a backtrace, you need to disable isolation +[using `-Zmiri-disable-isolation`](#miri-flags): + +```sh +RUST_BACKTRACE=1 MIRIFLAGS="-Zmiri-disable-isolation" cargo miri test +``` + #### "found possibly newer version of crate `std` which `` depends on" Your build directory may contain artifacts from an earlier build that have/have diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 72c873b229e9..62fb9299c456 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -296,7 +296,7 @@ fn setup(subcommand: MiriCommand) { [dependencies.std] default_features = false # We support unwinding, so enable that panic runtime. -features = ["panic_unwind"] +features = ["panic_unwind", "backtrace"] [dependencies.test] "#, diff --git a/tests/run-pass/concurrency/simple.stderr b/tests/run-pass/concurrency/simple.stderr index e52d07cdc73f..7060411278e6 100644 --- a/tests/run-pass/concurrency/simple.stderr +++ b/tests/run-pass/concurrency/simple.stderr @@ -1,4 +1,5 @@ warning: thread support is experimental. For example, Miri does not detect data races yet. thread '' panicked at 'Hello!', $DIR/simple.rs:54:9 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace thread 'childthread' panicked at 'Hello, world!', $DIR/simple.rs:64:9 diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr index c31f54aac729..30c7767b5642 100644 --- a/tests/run-pass/panic/catch_panic.stderr +++ b/tests/run-pass/panic/catch_panic.stderr @@ -1,4 +1,5 @@ thread 'main' panicked at 'Hello from panic: std', $DIR/catch_panic.rs:LL:27 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace Caught panic message (&str): Hello from panic: std thread 'main' panicked at 'Hello from panic: 1', $DIR/catch_panic.rs:LL:26 Caught panic message (String): Hello from panic: 1 diff --git a/tests/run-pass/panic/concurrent-panic.stderr b/tests/run-pass/panic/concurrent-panic.stderr index d538efdb0e88..eb5b5f59a0cb 100644 --- a/tests/run-pass/panic/concurrent-panic.stderr +++ b/tests/run-pass/panic/concurrent-panic.stderr @@ -3,6 +3,7 @@ warning: thread support is experimental. For example, Miri does not detect data Thread 1 starting, will block on mutex Thread 1 reported it has started thread '' panicked at 'panic in thread 2', $DIR/concurrent-panic.rs:65:13 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace Thread 2 blocking on thread 1 Thread 2 reported it has started Unlocking mutex diff --git a/tests/run-pass/panic/div-by-zero-2.stderr b/tests/run-pass/panic/div-by-zero-2.stderr index d255811be2a9..60ff33c8bfcd 100644 --- a/tests/run-pass/panic/div-by-zero-2.stderr +++ b/tests/run-pass/panic/div-by-zero-2.stderr @@ -1 +1,2 @@ thread 'main' panicked at 'attempt to divide by zero', $DIR/div-by-zero-2.rs:4:14 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/panic/overflowing-lsh-neg.stderr b/tests/run-pass/panic/overflowing-lsh-neg.stderr index 04d98a0a2f15..64959da0faea 100644 --- a/tests/run-pass/panic/overflowing-lsh-neg.stderr +++ b/tests/run-pass/panic/overflowing-lsh-neg.stderr @@ -1 +1,2 @@ thread 'main' panicked at 'attempt to shift left with overflow', $DIR/overflowing-lsh-neg.rs:4:14 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/panic/overflowing-rsh-1.stderr b/tests/run-pass/panic/overflowing-rsh-1.stderr index a9a72f46222d..bd8843f8d603 100644 --- a/tests/run-pass/panic/overflowing-rsh-1.stderr +++ b/tests/run-pass/panic/overflowing-rsh-1.stderr @@ -1 +1,2 @@ thread 'main' panicked at 'attempt to shift right with overflow', $DIR/overflowing-rsh-1.rs:4:14 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/panic/overflowing-rsh-2.stderr b/tests/run-pass/panic/overflowing-rsh-2.stderr index 24b61194565d..c43090ea7037 100644 --- a/tests/run-pass/panic/overflowing-rsh-2.stderr +++ b/tests/run-pass/panic/overflowing-rsh-2.stderr @@ -1 +1,2 @@ thread 'main' panicked at 'attempt to shift right with overflow', $DIR/overflowing-rsh-2.rs:5:14 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/panic/panic1.rs b/tests/run-pass/panic/panic1.rs index 9d9ad28df5a7..4500c916ad6a 100644 --- a/tests/run-pass/panic/panic1.rs +++ b/tests/run-pass/panic/panic1.rs @@ -1,3 +1,9 @@ +// rustc-env: RUST_BACKTRACE=1 +// compile-flags: -Zmiri-disable-isolation +// normalize-stderr-test ".*/(rust|checkout)/library/" -> "RUSTLIB/" +// normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL " +// normalize-stderr-test "::<.*>" -> "" + fn main() { std::panic!("panicking from libstd"); } diff --git a/tests/run-pass/panic/panic1.stderr b/tests/run-pass/panic/panic1.stderr index 954b8799a082..e06ec1b9ce32 100644 --- a/tests/run-pass/panic/panic1.stderr +++ b/tests/run-pass/panic/panic1.stderr @@ -1 +1,23 @@ -thread 'main' panicked at 'panicking from libstd', $DIR/panic1.rs:2:5 +thread 'main' panicked at 'panicking from libstd', $DIR/panic1.rs:8:5 +stack backtrace: + 0: std::rt::begin_panic +RUSTLIB/std/src/panicking.rs:505:12 + 1: main + at $DIR/panic1.rs:8:5 + 2: >::call_once - shim(fn()) +RUSTLIB/core/src/ops/function.rs:227:5 + 3: std::rt::lang_start::{closure#0} +RUSTLIB/std/src/rt.rs:66:18 + 4: std::ops::function::impls::call_once +RUSTLIB/core/src/ops/function.rs:259:13 + 5: std::panicking::r#try::do_call +RUSTLIB/std/src/panicking.rs:381:40 + 6: std::panicking::r#try +RUSTLIB/std/src/panicking.rs:345:19 + 7: std::panic::catch_unwind +RUSTLIB/std/src/panic.rs:382:14 + 8: std::rt::lang_start_internal +RUSTLIB/std/src/rt.rs:51:25 + 9: std::rt::lang_start +RUSTLIB/std/src/rt.rs:65:5 +note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. diff --git a/tests/run-pass/panic/panic2.stderr b/tests/run-pass/panic/panic2.stderr index e90e3502cbfb..c0415b4e70f0 100644 --- a/tests/run-pass/panic/panic2.stderr +++ b/tests/run-pass/panic/panic2.stderr @@ -1 +1,2 @@ thread 'main' panicked at '42-panicking from libstd', $DIR/panic2.rs:2:5 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/panic/panic3.stderr b/tests/run-pass/panic/panic3.stderr index 0a3c191b282e..8aa8761aebf7 100644 --- a/tests/run-pass/panic/panic3.stderr +++ b/tests/run-pass/panic/panic3.stderr @@ -1 +1,2 @@ thread 'main' panicked at 'panicking from libcore', $DIR/panic3.rs:2:5 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/panic/panic4.stderr b/tests/run-pass/panic/panic4.stderr index 946059b1e49f..a71d25b74c43 100644 --- a/tests/run-pass/panic/panic4.stderr +++ b/tests/run-pass/panic/panic4.stderr @@ -1 +1,2 @@ thread 'main' panicked at '42-panicking from libcore', $DIR/panic4.rs:2:5 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/transmute_fat2.stderr b/tests/run-pass/transmute_fat2.stderr index c8298a6c23c6..54ccdfb5e465 100644 --- a/tests/run-pass/transmute_fat2.stderr +++ b/tests/run-pass/transmute_fat2.stderr @@ -1 +1,2 @@ thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', $DIR/transmute_fat2.rs:15:5 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace From 0835ac6ec3d071440cc4fa7490a884615dad862d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 Oct 2020 12:50:45 +0200 Subject: [PATCH 2397/5092] another TiKV bug for the trophy case :) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d8f0ef583f11..8c908149998d 100644 --- a/README.md +++ b/README.md @@ -372,6 +372,7 @@ Definite bugs found: * [`servo_arc` creating a dangling shared reference](https://github.com/servo/servo/issues/26357) * [TiKV constructing out-of-bounds pointers (and overlapping mutable references)](https://github.com/tikv/tikv/pull/7751) * [`encoding_rs` doing out-of-bounds pointer arithmetic](https://github.com/hsivonen/encoding_rs/pull/53) +* [TiKV using `Vec::from_raw_parts` incorrectly](https://github.com/tikv/agatedb/pull/24) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From ad07b2bd4479f75ae58b0f9aeaae1c951c3ecc92 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 22 Oct 2020 09:47:02 +0200 Subject: [PATCH 2398/5092] rustup; increase slack for timing tests --- rust-version | 2 +- tests/run-pass/concurrency/sync.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index d5ddd1d0371e..d661d821503b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c38ddb8040edce1b05bc09a0e8439472e9f67623 +8f0fa9d51ff4ad2c0869e660856cd327e79915e9 diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index 69943e5495e2..bdbc4b90f6ed 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -319,7 +319,7 @@ fn park_timeout() { // Normally, waiting in park/park_timeout may spuriously wake up early, but we // know Miri's timed synchronization primitives do not do that. - assert!((200..500).contains(&start.elapsed().as_millis())); + assert!((200..1000).contains(&start.elapsed().as_millis())); } fn park_unpark() { @@ -337,7 +337,7 @@ fn park_unpark() { // Normally, waiting in park/park_timeout may spuriously wake up early, but we // know Miri's timed synchronization primitives do not do that. - assert!((200..500).contains(&start.elapsed().as_millis())); + assert!((200..1000).contains(&start.elapsed().as_millis())); } fn main() { From 80c4b5d6741745803f86c8a96389001e3cf617ca Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 22 Oct 2020 10:36:01 +0200 Subject: [PATCH 2399/5092] fix './miri test' --- tests/compiletest.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 35c1de3399c0..ac44c48d6214 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -24,10 +24,10 @@ fn run_tests(mode: &str, path: &str, target: &str) { } else { flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs } - if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") { + if let Ok(sysroot) = env::var("MIRI_SYSROOT") { flags.push(format!("--sysroot {}", sysroot)); } - if let Ok(extra_flags) = std::env::var("MIRIFLAGS") { + if let Ok(extra_flags) = env::var("MIRIFLAGS") { flags.push(extra_flags); } @@ -80,14 +80,16 @@ fn get_host() -> String { } fn get_target() -> String { - std::env::var("MIRI_TEST_TARGET").unwrap_or_else(|_| get_host()) + env::var("MIRI_TEST_TARGET").unwrap_or_else(|_| get_host()) } fn test_runner(_tests: &[&()]) { // Add a test env var to do environment communication tests. - std::env::set_var("MIRI_ENV_VAR_TEST", "0"); + env::set_var("MIRI_ENV_VAR_TEST", "0"); // Let the tests know where to store temp files (they might run for a different target, which can make this hard to find). - std::env::set_var("MIRI_TEMP", std::env::temp_dir()); + env::set_var("MIRI_TEMP", env::temp_dir()); + // Panic tests expect backtraces to be printed. + env::set_var("RUST_BACKTRACE", "1"); let target = get_target(); miri_pass("tests/run-pass", &target); From e9b8693aaae84d317d92de7c6438c3117af83122 Mon Sep 17 00:00:00 2001 From: Camelid Date: Fri, 23 Oct 2020 11:48:34 -0700 Subject: [PATCH 2400/5092] Don't force-install xargo Previously miri used `cargo install xargo -f` which shouldn't be necessary anymore since `cargo install` will now upgrade without `-f`. The only reason I can see to use `-f` is from the cargo docs: > This is also useful if something has changed on the system that you > want to rebuild with, such as a newer version of `rustc`. See the [discussion on Zulip](https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/why.20does.20miri.20require.20xargo/near/214351239). --- cargo-miri/bin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 62fb9299c456..a13e689cad20 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -241,7 +241,7 @@ fn setup(subcommand: MiriCommand) { show_error(format!("xargo is too old; please upgrade to the latest version")) } let mut cmd = cargo(); - cmd.args(&["install", "xargo", "-f"]); + cmd.args(&["install", "xargo"]); ask_to_run(cmd, ask_user, "install a recent enough xargo"); } From 8df239b020694b6d150de1a719a80490337cdd55 Mon Sep 17 00:00:00 2001 From: Camelid Date: Fri, 23 Oct 2020 11:53:34 -0700 Subject: [PATCH 2401/5092] Fix README --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 078e5a8acc09..b638c3bca1ce 100644 --- a/README.md +++ b/README.md @@ -406,10 +406,13 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows ## License Licensed under either of + * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) * MIT license ([LICENSE-MIT](LICENSE-MIT) or - http://opensource.org/licenses/MIT) at your option. + http://opensource.org/licenses/MIT) + +at your option. ### Contribution From 60a2c9b1f823259bf1fa0ce238b09d1064066dd8 Mon Sep 17 00:00:00 2001 From: Camelid Date: Fri, 23 Oct 2020 13:00:33 -0700 Subject: [PATCH 2402/5092] Hide readlink error in `./miri` `./miri` is just testing whether the platform supports `readlink -e`, but it didn't hide properly hide the stderr output. This fixes that. --- miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri b/miri index aef61b6dd68d..161276c52b9c 100755 --- a/miri +++ b/miri @@ -40,7 +40,7 @@ TARGET=$(rustc --version --verbose | grep "^host:" | cut -d ' ' -f 2) SYSROOT=$(rustc --print sysroot) LIBDIR=$SYSROOT/lib/rustlib/$TARGET/lib MIRIDIR=$(dirname "$0") -if readlink -e . >/dev/null; then +if readlink -e . &>/dev/null; then # This platform supports `readlink -e`. MIRIDIR=$(readlink -e "$MIRIDIR") fi From 05e9ae042c83345d00d6abba2e4f567b163a90f7 Mon Sep 17 00:00:00 2001 From: Camelid Date: Sat, 24 Oct 2020 12:46:02 -0700 Subject: [PATCH 2403/5092] Make `miri_default_args()` a constant --- src/bin/miri-rustc-tests.rs | 2 +- src/bin/miri.rs | 2 +- src/lib.rs | 16 +++++++--------- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 7c2419dde3f4..cef71a9889f1 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -109,7 +109,7 @@ fn main() { } }) .collect(); - args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string)); + args.splice(1..1, miri::MIRI_DEFAULT_ARGS.iter().map(ToString::to_string)); // file to process args.push(path.display().to_string()); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 71d561b9f7da..5769590ad094 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -153,7 +153,7 @@ fn run_compiler(mut args: Vec, callbacks: &mut (dyn rustc_driver::Callba // Some options have different defaults in Miri than in plain rustc; apply those by making // them the first arguments after the binary name (but later arguments can overwrite them). - args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string)); + args.splice(1..1, miri::MIRI_DEFAULT_ARGS.iter().map(ToString::to_string)); // Invoke compiler, and handle return code. let exit_code = rustc_driver::catch_with_exit_code(move || { diff --git a/src/lib.rs b/src/lib.rs index 77eac9a6324a..d4802f3b11fa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -77,12 +77,10 @@ pub use crate::sync::{ /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. -pub fn miri_default_args() -> &'static [&'static str] { - &[ - "-Zalways-encode-mir", - "-Zmir-emit-retag", - "-Zmir-opt-level=0", - "--cfg=miri", - "-Cdebug-assertions=on", - ] -} +pub const MIRI_DEFAULT_ARGS: &[&str] = &[ + "-Zalways-encode-mir", + "-Zmir-emit-retag", + "-Zmir-opt-level=0", + "--cfg=miri", + "-Cdebug-assertions=on", +]; From ddcc4f241e1e9987b050067f4303d0449774b36e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Oct 2020 10:00:50 +0100 Subject: [PATCH 2404/5092] rustup; make panic output less dependent on stdlib internals --- rust-version | 2 +- tests/run-pass/backtrace-std.rs | 4 ++-- tests/run-pass/backtrace-std.stderr | 18 +++++++++--------- tests/run-pass/panic/catch_panic.stderr | 8 ++++---- tests/run-pass/panic/panic1.rs | 4 ++-- tests/run-pass/panic/panic1.stderr | 18 +++++++++--------- 6 files changed, 27 insertions(+), 27 deletions(-) diff --git a/rust-version b/rust-version index d661d821503b..44e9a77940d6 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8f0fa9d51ff4ad2c0869e660856cd327e79915e9 +17cc9b6256c95c31944591aec683884fead4e3b6 diff --git a/tests/run-pass/backtrace-std.rs b/tests/run-pass/backtrace-std.rs index 579b4f32e7cc..fb596b1d2020 100644 --- a/tests/run-pass/backtrace-std.rs +++ b/tests/run-pass/backtrace-std.rs @@ -1,5 +1,5 @@ -// normalize-stderr-test ".*/(rust|checkout)/library/" -> "RUSTLIB/" -// normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL " +// normalize-stderr-test "at .*/(rust|checkout)/library/" -> "at RUSTLIB/" +// normalize-stderr-test "RUSTLIB/(.*):\d+"-> "RUSTLIB/$1:LL" // normalize-stderr-test "::<.*>" -> "" // compile-flags: -Zmiri-disable-isolation diff --git a/tests/run-pass/backtrace-std.stderr b/tests/run-pass/backtrace-std.stderr index d14735c0405f..45c46acc331c 100644 --- a/tests/run-pass/backtrace-std.stderr +++ b/tests/run-pass/backtrace-std.stderr @@ -9,20 +9,20 @@ 4: main at $DIR/backtrace-std.rs:21 5: >::call_once - shim(fn()) -RUSTLIB/core/src/ops/function.rs:227 + at RUSTLIB/core/src/ops/function.rs:LL 6: std::sys_common::backtrace::__rust_begin_short_backtrace -RUSTLIB/std/src/sys_common/backtrace.rs:125 + at RUSTLIB/std/src/sys_common/backtrace.rs:LL 7: std::rt::lang_start::{closure#0} -RUSTLIB/std/src/rt.rs:66 + at RUSTLIB/std/src/rt.rs:LL 8: std::ops::function::impls::call_once -RUSTLIB/core/src/ops/function.rs:259 + at RUSTLIB/core/src/ops/function.rs:LL 9: std::panicking::r#try::do_call -RUSTLIB/std/src/panicking.rs:381 + at RUSTLIB/std/src/panicking.rs:LL 10: std::panicking::r#try -RUSTLIB/std/src/panicking.rs:345 + at RUSTLIB/std/src/panicking.rs:LL 11: std::panic::catch_unwind -RUSTLIB/std/src/panic.rs:382 + at RUSTLIB/std/src/panic.rs:LL 12: std::rt::lang_start_internal -RUSTLIB/std/src/rt.rs:51 + at RUSTLIB/std/src/rt.rs:LL 13: std::rt::lang_start -RUSTLIB/std/src/rt.rs:65 + at RUSTLIB/std/src/rt.rs:LL diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr index 30c7767b5642..c4c04fece901 100644 --- a/tests/run-pass/panic/catch_panic.stderr +++ b/tests/run-pass/panic/catch_panic.stderr @@ -8,7 +8,7 @@ Caught panic message (String): Hello from panic: 2 thread 'main' panicked at 'Box', $DIR/catch_panic.rs:LL:27 Failed to get caught panic message. thread 'main' panicked at 'Hello from panic: core', $DIR/catch_panic.rs:LL:27 -Caught panic message (String): Hello from panic: core +Caught panic message (&str): Hello from panic: core thread 'main' panicked at 'Hello from panic: 5', $DIR/catch_panic.rs:LL:26 Caught panic message (String): Hello from panic: 5 thread 'main' panicked at 'Hello from panic: 6', $DIR/catch_panic.rs:LL:26 @@ -16,13 +16,13 @@ Caught panic message (String): Hello from panic: 6 thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4', $DIR/catch_panic.rs:LL:33 Caught panic message (String): index out of bounds: the len is 3 but the index is 4 thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:LL:33 -Caught panic message (String): attempt to divide by zero +Caught panic message (&str): attempt to divide by zero thread 'main' panicked at 'align_offset: align is not a power-of-two', $LOC -Caught panic message (String): align_offset: align is not a power-of-two +Caught panic message (&str): align_offset: align is not a power-of-two thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:LL:29 Caught panic message (&str): assertion failed: false thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:LL:29 Caught panic message (&str): assertion failed: false thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', $LOC -Caught panic message (String): called `Option::unwrap()` on a `None` value +Caught panic message (&str): called `Option::unwrap()` on a `None` value Success! diff --git a/tests/run-pass/panic/panic1.rs b/tests/run-pass/panic/panic1.rs index 4500c916ad6a..08ac3a072852 100644 --- a/tests/run-pass/panic/panic1.rs +++ b/tests/run-pass/panic/panic1.rs @@ -1,9 +1,9 @@ // rustc-env: RUST_BACKTRACE=1 // compile-flags: -Zmiri-disable-isolation -// normalize-stderr-test ".*/(rust|checkout)/library/" -> "RUSTLIB/" -// normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL " +// normalize-stderr-test "at .*/(rust|checkout)/library/.*" -> "at RUSTLIB/$$FILE:LL:COL" // normalize-stderr-test "::<.*>" -> "" + fn main() { std::panic!("panicking from libstd"); } diff --git a/tests/run-pass/panic/panic1.stderr b/tests/run-pass/panic/panic1.stderr index e06ec1b9ce32..e0f1aa5dad70 100644 --- a/tests/run-pass/panic/panic1.stderr +++ b/tests/run-pass/panic/panic1.stderr @@ -1,23 +1,23 @@ thread 'main' panicked at 'panicking from libstd', $DIR/panic1.rs:8:5 stack backtrace: 0: std::rt::begin_panic -RUSTLIB/std/src/panicking.rs:505:12 + at RUSTLIB/$FILE:LL:COL 1: main at $DIR/panic1.rs:8:5 2: >::call_once - shim(fn()) -RUSTLIB/core/src/ops/function.rs:227:5 + at RUSTLIB/$FILE:LL:COL 3: std::rt::lang_start::{closure#0} -RUSTLIB/std/src/rt.rs:66:18 + at RUSTLIB/$FILE:LL:COL 4: std::ops::function::impls::call_once -RUSTLIB/core/src/ops/function.rs:259:13 + at RUSTLIB/$FILE:LL:COL 5: std::panicking::r#try::do_call -RUSTLIB/std/src/panicking.rs:381:40 + at RUSTLIB/$FILE:LL:COL 6: std::panicking::r#try -RUSTLIB/std/src/panicking.rs:345:19 + at RUSTLIB/$FILE:LL:COL 7: std::panic::catch_unwind -RUSTLIB/std/src/panic.rs:382:14 + at RUSTLIB/$FILE:LL:COL 8: std::rt::lang_start_internal -RUSTLIB/std/src/rt.rs:51:25 + at RUSTLIB/$FILE:LL:COL 9: std::rt::lang_start -RUSTLIB/std/src/rt.rs:65:5 + at RUSTLIB/$FILE:LL:COL note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. From 16491aef42d386a9e721b913b9b4d8361a127a5a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Oct 2020 14:21:59 +0100 Subject: [PATCH 2405/5092] Use bash to make sure &> works --- miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri b/miri index 161276c52b9c..337b2a496de8 100755 --- a/miri +++ b/miri @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash set -e USAGE=$(cat <<"EOF" COMMANDS From 086e9c49a95ab30380954cc3bca632145786cee2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Oct 2020 14:22:29 +0100 Subject: [PATCH 2406/5092] pointer tag tracking: also show when tag is being created --- src/diagnostics.rs | 4 ++++ src/stacked_borrows.rs | 3 +++ 2 files changed, 7 insertions(+) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 81cd04921722..12ad93a5289e 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -1,5 +1,6 @@ use std::cell::RefCell; use std::fmt; +use std::num::NonZeroU64; use log::trace; @@ -41,6 +42,7 @@ impl MachineStopType for TerminationInfo {} /// Miri specific diagnostics pub enum NonHaltingDiagnostic { + CreatedPointerTag(NonZeroU64), PoppedPointerTag(Item), CreatedCallId(CallId), CreatedAlloc(AllocId), @@ -266,6 +268,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx for e in diagnostics.drain(..) { use NonHaltingDiagnostic::*; let msg = match e { + CreatedPointerTag(tag) => + format!("created tag {:?}", tag), PoppedPointerTag(item) => format!("popped tracked tag for item {:?}", item), CreatedCallId(id) => diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 817ed99d2bb2..257208056d76 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -168,6 +168,9 @@ impl GlobalState { fn new_ptr(&mut self) -> PtrId { let id = self.next_ptr_id; + if Some(id) == self.tracked_pointer_tag { + register_diagnostic(NonHaltingDiagnostic::CreatedPointerTag(id)); + } self.next_ptr_id = NonZeroU64::new(id.get() + 1).unwrap(); id } From ecf330f39eaed1f798445ae018cfb645517078bc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Oct 2020 16:58:08 +0100 Subject: [PATCH 2407/5092] test Box::into_raw aliasing --- tests/run-pass/box-pair-to-vec.rs | 28 --------- tests/run-pass/box.rs | 60 +++++++++++++++++++ .../{box-pair-to-vec.stdout => box.stdout} | 0 3 files changed, 60 insertions(+), 28 deletions(-) delete mode 100644 tests/run-pass/box-pair-to-vec.rs create mode 100644 tests/run-pass/box.rs rename tests/run-pass/{box-pair-to-vec.stdout => box.stdout} (100%) diff --git a/tests/run-pass/box-pair-to-vec.rs b/tests/run-pass/box-pair-to-vec.rs deleted file mode 100644 index 353afb9d3210..000000000000 --- a/tests/run-pass/box-pair-to-vec.rs +++ /dev/null @@ -1,28 +0,0 @@ -#[repr(C)] -#[derive(Debug)] -struct PairFoo { - fst: Foo, - snd: Foo, -} - -#[derive(Debug)] -struct Foo(u64); -fn reinterstruct(box_pair: Box) -> Vec { - let ref_pair = Box::leak(box_pair) as *mut PairFoo; - let ptr_foo = unsafe { &mut (*ref_pair).fst as *mut Foo }; - unsafe { - Vec::from_raw_parts(ptr_foo, 2, 2) - } -} - -fn main() { - let pair_foo = Box::new(PairFoo { - fst: Foo(42), - snd: Foo(1337), - }); - println!("pair_foo = {:?}", pair_foo); - for (n, foo) in reinterstruct(pair_foo).into_iter().enumerate() { - println!("foo #{} = {:?}", n, foo); - } -} - diff --git a/tests/run-pass/box.rs b/tests/run-pass/box.rs new file mode 100644 index 000000000000..b89c0ac1286e --- /dev/null +++ b/tests/run-pass/box.rs @@ -0,0 +1,60 @@ +#![feature(ptr_internals)] + +fn main() { + into_raw(); + into_unique(); + boxed_pair_to_vec(); +} + +fn into_raw() { unsafe { + let b = Box::new(4i32); + let r = Box::into_raw(b); + + // "lose the tag" + let r2 = ((r as usize)+0) as *mut i32; + *(&mut *r2) = 7; + + // Use original ptr again + *(&mut *r) = 17; + drop(Box::from_raw(r)); +}} + +fn into_unique() { unsafe { + let b = Box::new(4i32); + let u = Box::into_unique(b); + + // "lose the tag" + let r = ((u.as_ptr() as usize)+0) as *mut i32; + *(&mut *r) = 7; + + // Use original ptr again. + drop(Box::from_raw(u.as_ptr())); +}} + +fn boxed_pair_to_vec() { + #[repr(C)] + #[derive(Debug)] + struct PairFoo { + fst: Foo, + snd: Foo, + } + + #[derive(Debug)] + struct Foo(u64); + fn reinterstruct(box_pair: Box) -> Vec { + let ref_pair = Box::leak(box_pair) as *mut PairFoo; + let ptr_foo = unsafe { &mut (*ref_pair).fst as *mut Foo }; + unsafe { + Vec::from_raw_parts(ptr_foo, 2, 2) + } + } + + let pair_foo = Box::new(PairFoo { + fst: Foo(42), + snd: Foo(1337), + }); + println!("pair_foo = {:?}", pair_foo); + for (n, foo) in reinterstruct(pair_foo).into_iter().enumerate() { + println!("foo #{} = {:?}", n, foo); + } +} diff --git a/tests/run-pass/box-pair-to-vec.stdout b/tests/run-pass/box.stdout similarity index 100% rename from tests/run-pass/box-pair-to-vec.stdout rename to tests/run-pass/box.stdout From 39f7b35327cd4747da1a20a187fbaf220ee4a09c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Oct 2020 12:04:39 +0100 Subject: [PATCH 2408/5092] Stacked Borrows: print affected memory location on errors --- src/range_map.rs | 30 ++++++++++++---------- src/stacked_borrows.rs | 56 ++++++++++++++++++++---------------------- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/src/range_map.rs b/src/range_map.rs index 16ad5fd7c2b2..607c830530e1 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -61,7 +61,9 @@ impl RangeMap { /// Provides read-only iteration over everything in the given range. This does /// *not* split items if they overlap with the edges. Do not use this to mutate /// through interior mutability. - pub fn iter<'a>(&'a self, offset: Size, len: Size) -> impl Iterator + 'a { + /// + /// The iterator also provides the offset of the given element. + pub fn iter<'a>(&'a self, offset: Size, len: Size) -> impl Iterator + 'a { let offset = offset.bytes(); let len = len.bytes(); // Compute a slice starting with the elements we care about. @@ -75,7 +77,7 @@ impl RangeMap { }; // The first offset that is not included any more. let end = offset + len; - slice.iter().take_while(move |elem| elem.range.start < end).map(|elem| &elem.data) + slice.iter().take_while(move |elem| elem.range.start < end).map(|elem| (Size::from_bytes(elem.range.start), &elem.data)) } pub fn iter_mut_all<'a>(&'a mut self) -> impl Iterator + 'a { @@ -112,11 +114,13 @@ impl RangeMap { /// this will split entries in the map that are only partially hit by the given range, /// to make sure that when they are mutated, the effect is constrained to the given range. /// Moreover, this will opportunistically merge neighbouring equal blocks. + /// + /// The iterator also provides the offset of the given element. pub fn iter_mut<'a>( &'a mut self, offset: Size, len: Size, - ) -> impl Iterator + 'a + ) -> impl Iterator + 'a where T: Clone + PartialEq, { @@ -197,7 +201,7 @@ impl RangeMap { // Now we yield the slice. `end` is inclusive. &mut self.v[first_idx..=end_idx] }; - slice.iter_mut().map(|elem| &mut elem.data) + slice.iter_mut().map(|elem| (Size::from_bytes(elem.range.start), &mut elem.data)) } } @@ -209,7 +213,7 @@ mod tests { fn to_vec(map: &RangeMap, offset: u64, len: u64) -> Vec { (offset..offset + len) .into_iter() - .map(|i| map.iter(Size::from_bytes(i), Size::from_bytes(1)).next().map(|&t| t).unwrap()) + .map(|i| map.iter(Size::from_bytes(i), Size::from_bytes(1)).next().map(|(_, &t)| t).unwrap()) .collect() } @@ -217,7 +221,7 @@ mod tests { fn basic_insert() { let mut map = RangeMap::::new(Size::from_bytes(20), -1); // Insert. - for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(1)) { + for (_, x) in map.iter_mut(Size::from_bytes(10), Size::from_bytes(1)) { *x = 42; } // Check. @@ -225,10 +229,10 @@ mod tests { assert_eq!(map.v.len(), 3); // Insert with size 0. - for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(0)) { + for (_, x) in map.iter_mut(Size::from_bytes(10), Size::from_bytes(0)) { *x = 19; } - for x in map.iter_mut(Size::from_bytes(11), Size::from_bytes(0)) { + for (_, x) in map.iter_mut(Size::from_bytes(11), Size::from_bytes(0)) { *x = 19; } assert_eq!(to_vec(&map, 10, 2), vec![42, -1]); @@ -238,16 +242,16 @@ mod tests { #[test] fn gaps() { let mut map = RangeMap::::new(Size::from_bytes(20), -1); - for x in map.iter_mut(Size::from_bytes(11), Size::from_bytes(1)) { + for (_, x) in map.iter_mut(Size::from_bytes(11), Size::from_bytes(1)) { *x = 42; } - for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(1)) { + for (_, x) in map.iter_mut(Size::from_bytes(15), Size::from_bytes(1)) { *x = 43; } assert_eq!(map.v.len(), 5); assert_eq!(to_vec(&map, 10, 10), vec![-1, 42, -1, -1, -1, 43, -1, -1, -1, -1]); - for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(10)) { + for (_, x) in map.iter_mut(Size::from_bytes(10), Size::from_bytes(10)) { if *x < 42 { *x = 23; } @@ -256,14 +260,14 @@ mod tests { assert_eq!(to_vec(&map, 10, 10), vec![23, 42, 23, 23, 23, 43, 23, 23, 23, 23]); assert_eq!(to_vec(&map, 13, 5), vec![23, 23, 43, 23, 23]); - for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(5)) { + for (_, x) in map.iter_mut(Size::from_bytes(15), Size::from_bytes(5)) { *x = 19; } assert_eq!(map.v.len(), 6); assert_eq!(to_vec(&map, 10, 10), vec![23, 42, 23, 23, 23, 19, 19, 19, 19, 19]); // Should be seeing two blocks with 19. assert_eq!( - map.iter(Size::from_bytes(15), Size::from_bytes(2)).map(|&t| t).collect::>(), + map.iter(Size::from_bytes(15), Size::from_bytes(2)).map(|(_, &t)| t).collect::>(), vec![19, 19] ); diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 257208056d76..cf5b31597daa 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -309,14 +309,14 @@ impl<'tcx> Stack { /// Test if a memory `access` using pointer tagged `tag` is granted. /// If yes, return the index of the item that granted it. - fn access(&mut self, access: AccessKind, tag: Tag, global: &GlobalState) -> InterpResult<'tcx> { + fn access(&mut self, access: AccessKind, ptr: Pointer, global: &GlobalState) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. - let granting_idx = self.find_granting(access, tag).ok_or_else(|| { + let granting_idx = self.find_granting(access, ptr.tag).ok_or_else(|| { err_sb_ub(format!( - "no item granting {} to tag {:?} found in borrow stack.", - access, tag + "no item granting {} to tag {:?} at {} found in borrow stack.", + access, ptr.tag, ptr.erase_tag(), )) })?; @@ -328,7 +328,7 @@ impl<'tcx> Stack { let first_incompatible_idx = self.find_first_write_incompatible(granting_idx); for item in self.borrows.drain(first_incompatible_idx..).rev() { trace!("access: popping item {:?}", item); - Stack::check_protector(&item, Some(tag), global)?; + Stack::check_protector(&item, Some(ptr.tag), global)?; } } else { // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses. @@ -343,7 +343,7 @@ impl<'tcx> Stack { let item = &mut self.borrows[idx]; if item.perm == Permission::Unique { trace!("access: disabling item {:?}", item); - Stack::check_protector(item, Some(tag), global)?; + Stack::check_protector(item, Some(ptr.tag), global)?; item.perm = Permission::Disabled; } } @@ -355,12 +355,12 @@ impl<'tcx> Stack { /// Deallocate a location: Like a write access, but also there must be no /// active protectors at all because we will remove all items. - fn dealloc(&mut self, tag: Tag, global: &GlobalState) -> InterpResult<'tcx> { + fn dealloc(&mut self, ptr: Pointer, global: &GlobalState) -> InterpResult<'tcx> { // Step 1: Find granting item. - self.find_granting(AccessKind::Write, tag).ok_or_else(|| { + self.find_granting(AccessKind::Write, ptr.tag).ok_or_else(|| { err_sb_ub(format!( - "no item granting write access for deallocation to tag {:?} found in borrow stack", - tag, + "no item granting write access for deallocation to tag {:?} at {} found in borrow stack", + ptr.tag, ptr.erase_tag(), )) })?; @@ -372,20 +372,20 @@ impl<'tcx> Stack { Ok(()) } - /// Derived a new pointer from one with the given tag. + /// Derive a new pointer from one with the given tag. /// `weak` controls whether this operation is weak or strong: weak granting does not act as /// an access, and they add the new item directly on top of the one it is derived /// from instead of all the way at the top of the stack. - fn grant(&mut self, derived_from: Tag, new: Item, global: &GlobalState) -> InterpResult<'tcx> { + fn grant(&mut self, derived_from: Pointer, new: Item, global: &GlobalState) -> InterpResult<'tcx> { // Figure out which access `perm` corresponds to. let access = if new.perm.grants(AccessKind::Write) { AccessKind::Write } else { AccessKind::Read }; // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. - let granting_idx = self.find_granting(access, derived_from) + let granting_idx = self.find_granting(access, derived_from.tag) .ok_or_else(|| err_sb_ub(format!( - "trying to reborrow for {:?}, but parent tag {:?} does not have an appropriate item in the borrow stack", - new.perm, derived_from, + "trying to reborrow for {:?} at {}, but parent tag {:?} does not have an appropriate item in the borrow stack", + new.perm, derived_from.erase_tag(), derived_from.tag, )))?; // Compute where to put the new item. @@ -443,12 +443,14 @@ impl<'tcx> Stacks { &self, ptr: Pointer, size: Size, - f: impl Fn(&mut Stack, &GlobalState) -> InterpResult<'tcx>, + f: impl Fn(Pointer, &mut Stack, &GlobalState) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { let global = self.global.borrow(); let mut stacks = self.stacks.borrow_mut(); - for stack in stacks.iter_mut(ptr.offset, size) { - f(stack, &*global)?; + for (offset, stack) in stacks.iter_mut(ptr.offset, size) { + let mut cur_ptr = ptr; + cur_ptr.offset = offset; + f(cur_ptr, stack, &*global)?; } Ok(()) } @@ -487,19 +489,13 @@ impl Stacks { #[inline(always)] pub fn memory_read<'tcx>(&self, ptr: Pointer, size: Size) -> InterpResult<'tcx> { trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - self.for_each(ptr, size, |stack, global| { - stack.access(AccessKind::Read, ptr.tag, global)?; - Ok(()) - }) + self.for_each(ptr, size, |ptr, stack, global| stack.access(AccessKind::Read, ptr, global)) } #[inline(always)] pub fn memory_written<'tcx>(&mut self, ptr: Pointer, size: Size) -> InterpResult<'tcx> { trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - self.for_each(ptr, size, |stack, global| { - stack.access(AccessKind::Write, ptr.tag, global)?; - Ok(()) - }) + self.for_each(ptr, size, |ptr, stack, global| stack.access(AccessKind::Write, ptr, global)) } #[inline(always)] @@ -509,7 +505,7 @@ impl Stacks { size: Size, ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - self.for_each(ptr, size, |stack, global| stack.dealloc(ptr.tag, global)) + self.for_each(ptr, size, |ptr, stack, global| stack.dealloc(ptr, global)) } } @@ -561,14 +557,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Permission::SharedReadWrite }; let item = Item { perm, tag: new_tag, protector }; - stacked_borrows.for_each(cur_ptr, size, |stack, global| { - stack.grant(cur_ptr.tag, item, global) + stacked_borrows.for_each(cur_ptr, size, |cur_ptr, stack, global| { + stack.grant(cur_ptr, item, global) }) }); } }; let item = Item { perm, tag: new_tag, protector }; - stacked_borrows.for_each(ptr, size, |stack, global| stack.grant(ptr.tag, item, global)) + stacked_borrows.for_each(ptr, size, |ptr, stack, global| stack.grant(ptr, item, global)) } /// Retags an indidual pointer, returning the retagged version. From 194451345dc6b7d269a5ded6fde49883cb862d75 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Oct 2020 12:23:35 +0100 Subject: [PATCH 2409/5092] add an option to track raw pointer tags in Stacked Borrows --- README.md | 10 +++++++--- src/bin/miri.rs | 3 +++ src/eval.rs | 14 ++++---------- src/machine.rs | 23 +++++++++++------------ src/stacked_borrows.rs | 32 ++++++++++++++++++-------------- 5 files changed, 43 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index b638c3bca1ce..0aa22a81ad5c 100644 --- a/README.md +++ b/README.md @@ -232,13 +232,17 @@ environment variable: * `-Zmiri-track-alloc-id=` shows a backtrace when the given allocation is being allocated or freed. This helps in debugging memory leaks and use after free bugs. +* `-Zmiri-track-call-id=` shows a backtrace when the given call id is + assigned to a stack frame. This helps in debugging UB related to Stacked + Borrows "protectors". * `-Zmiri-track-pointer-tag=` shows a backtrace when the given pointer tag is popped from a borrow stack (which is where the tag becomes invalid and any future use of it will error). This helps you in finding out why UB is happening and where in your code would be a good place to look for it. -* `-Zmiri-track-call-id=` shows a backtrace when the given call id is - assigned to a stack frame. This helps in debugging UB related to Stacked - Borrows "protectors". +* `-Zmiri-track-raw-pointers` makes Stacked Borrows track a pointer tag even for + raw pointers. This can make valid code fail to pass the checks (when + integer-pointer casts are involved), but also can help identify latent + aliasing issues in code that Miri accepts by default. Some native rustc `-Z` flags are also very relevant for Miri: diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 5769590ad094..ef1429a35020 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -207,6 +207,9 @@ fn main() { "-Zmiri-ignore-leaks" => { miri_config.ignore_leaks = true; } + "-Zmiri-track-raw-pointers" => { + miri_config.track_raw = true; + } "--" => { after_dashdash = true; } diff --git a/src/eval.rs b/src/eval.rs index e36a0019cdcb..54d06feec36d 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -3,8 +3,6 @@ use std::convert::TryFrom; use std::ffi::OsStr; -use rand::rngs::StdRng; -use rand::SeedableRng; use log::info; use rustc_hir::def_id::DefId; @@ -48,6 +46,8 @@ pub struct MiriConfig { pub tracked_call_id: Option, /// The allocation id to report about. pub tracked_alloc_id: Option, + /// Whether to track raw pointers in stacked borrows. + pub track_raw: bool, } impl Default for MiriConfig { @@ -64,6 +64,7 @@ impl Default for MiriConfig { tracked_pointer_tag: None, tracked_call_id: None, tracked_alloc_id: None, + track_raw: false, } } } @@ -84,14 +85,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( rustc_span::source_map::DUMMY_SP, param_env, Evaluator::new(config.communicate, config.validate, layout_cx), - MemoryExtra::new( - StdRng::seed_from_u64(config.seed.unwrap_or(0)), - config.stacked_borrows, - config.tracked_pointer_tag, - config.tracked_call_id, - config.tracked_alloc_id, - config.check_alignment, - ), + MemoryExtra::new(&config), ); // Complete initialization. EnvVars::init(&mut ecx, config.excluded_env_vars)?; diff --git a/src/machine.rs b/src/machine.rs index 544f4667e846..e9f9298e566c 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -10,6 +10,7 @@ use std::fmt; use log::trace; use rand::rngs::StdRng; +use rand::SeedableRng; use rustc_data_structures::fx::FxHashMap; use rustc_middle::{ @@ -132,16 +133,14 @@ pub struct MemoryExtra { } impl MemoryExtra { - pub fn new( - rng: StdRng, - stacked_borrows: bool, - tracked_pointer_tag: Option, - tracked_call_id: Option, - tracked_alloc_id: Option, - check_alignment: AlignmentCheck, - ) -> Self { - let stacked_borrows = if stacked_borrows { - Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(tracked_pointer_tag, tracked_call_id)))) + pub fn new(config: &MiriConfig) -> Self { + let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0)); + let stacked_borrows = if config.stacked_borrows { + Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new( + config.tracked_pointer_tag, + config.tracked_call_id, + config.track_raw, + )))) } else { None }; @@ -150,8 +149,8 @@ impl MemoryExtra { intptrcast: Default::default(), extern_statics: FxHashMap::default(), rng: RefCell::new(rng), - tracked_alloc_id, - check_alignment, + tracked_alloc_id: config.tracked_alloc_id, + check_alignment: config.check_alignment, } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index cf5b31597daa..616950eb0a0a 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -108,6 +108,8 @@ pub struct GlobalState { tracked_pointer_tag: Option, /// The call id to trace tracked_call_id: Option, + /// Whether to track raw pointers. + track_raw: bool, } /// Memory extra state gives us interior mutable access to the global state. pub type MemoryExtra = Rc>; @@ -155,7 +157,7 @@ impl fmt::Display for RefKind { /// Utilities for initialization and ID generation impl GlobalState { - pub fn new(tracked_pointer_tag: Option, tracked_call_id: Option) -> Self { + pub fn new(tracked_pointer_tag: Option, tracked_call_id: Option, track_raw: bool) -> Self { GlobalState { next_ptr_id: NonZeroU64::new(1).unwrap(), base_ptr_ids: FxHashMap::default(), @@ -163,6 +165,7 @@ impl GlobalState { active_calls: FxHashSet::default(), tracked_pointer_tag, tracked_call_id, + track_raw, } } @@ -479,9 +482,12 @@ impl Stacks { // The base pointer is not unique, so the base permission is `SharedReadWrite`. MemoryKind::Machine(MiriMemoryKind::Global | MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls | MiriMemoryKind::Env) => (extra.borrow_mut().global_base_ptr(id), Permission::SharedReadWrite), - // Everything else we handle entirely untagged for now. - // FIXME: experiment with more precise tracking. - _ => (Tag::Untagged, Permission::SharedReadWrite), + // Everything else we handle like raw pointers for now. + _ => { + let mut extra = extra.borrow_mut(); + let tag = if extra.track_raw { Tag::Tagged(extra.new_ptr()) } else { Tag::Untagged }; + (tag, Permission::SharedReadWrite) + } }; (Stacks::new(size, perm, tag, extra), tag) } @@ -593,16 +599,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Compute new borrow. - let new_tag = match kind { - // Give up tracking for raw pointers. - // FIXME: Experiment with more precise tracking. Blocked on `&raw` - // because `Rc::into_raw` currently creates intermediate references, - // breaking `Rc::from_raw`. - RefKind::Raw { .. } => Tag::Untagged, - // All other pointesr are properly tracked. - _ => Tag::Tagged( - this.memory.extra.stacked_borrows.as_ref().unwrap().borrow_mut().new_ptr(), - ), + let new_tag = { + let mut mem_extra = this.memory.extra.stacked_borrows.as_ref().unwrap().borrow_mut(); + match kind { + // Give up tracking for raw pointers. + RefKind::Raw { .. } if !mem_extra.track_raw => Tag::Untagged, + // All other pointers are properly tracked. + _ => Tag::Tagged(mem_extra.new_ptr()), + } }; // Reborrow. From 19e78a65d95d03b6d7ac670075231837cc00edf4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Oct 2020 12:35:05 +0100 Subject: [PATCH 2410/5092] run some tests with raw pointer tracking --- tests/run-pass/format.rs | 2 ++ tests/run-pass/slices.rs | 1 + tests/run-pass/vec.rs | 1 + tests/run-pass/vecdeque.rs | 1 + 4 files changed, 5 insertions(+) diff --git a/tests/run-pass/format.rs b/tests/run-pass/format.rs index 053cce36130c..3893efcb26a1 100644 --- a/tests/run-pass/format.rs +++ b/tests/run-pass/format.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-track-raw-pointers + fn main() { println!("Hello {}", 13); println!("{:0(dummy: &mut T, iter: impl Iterator) { diff --git a/tests/run-pass/vecdeque.rs b/tests/run-pass/vecdeque.rs index 34f32ee1d9c1..54aeb89ec83f 100644 --- a/tests/run-pass/vecdeque.rs +++ b/tests/run-pass/vecdeque.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-track-raw-pointers use std::collections::VecDeque; fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { From 1044099c196ced6108234fe2450fcd2f7f969fa7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Oct 2020 10:48:33 +0100 Subject: [PATCH 2411/5092] disable debug assertions in the standard library --- cargo-miri/bin.rs | 2 ++ tests/run-pass/panic/catch_panic.rs | 1 - tests/run-pass/panic/catch_panic.stderr | 2 -- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index a13e689cad20..6eff5f795e7c 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -353,6 +353,8 @@ path = "lib.rs" // to the sysroot either. command.env_remove("RUSTC_WRAPPER"); command.env_remove("RUSTFLAGS"); + // Disable debug assertions in the standard library -- Miri is already slow enough. + command.env("RUSTFLAGS", "-Cdebug-assertions=off"); // Finally run it! if command.status().expect("failed to run xargo").success().not() { show_error(format!("failed to run xargo")); diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index 3afff1d36d36..941f79c7ad90 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -78,7 +78,6 @@ fn main() { // Assertion and debug assertion test(None, |_old_val| { assert!(false); loop {} }); test(None, |_old_val| { debug_assert!(false); loop {} }); - test(None, |_old_val| { unsafe { std::char::from_u32_unchecked(0xFD10000); } loop {} }); // trigger debug-assertion in libstd eprintln!("Success!"); // Make sure we get this in stderr } diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr index c4c04fece901..696dbc1f8181 100644 --- a/tests/run-pass/panic/catch_panic.stderr +++ b/tests/run-pass/panic/catch_panic.stderr @@ -23,6 +23,4 @@ thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:LL:29 Caught panic message (&str): assertion failed: false thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:LL:29 Caught panic message (&str): assertion failed: false -thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', $LOC -Caught panic message (&str): called `Option::unwrap()` on a `None` value Success! From 00c4869d560e108a9b8298c7d1861c7320be45c6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Oct 2020 12:57:41 +0100 Subject: [PATCH 2412/5092] remove outdated CI badges --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index b638c3bca1ce..1de1c2e4c1b1 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ # Miri [![Actions build status][actions-badge]][actions-url] -[![Travis build status](https://travis-ci.com/rust-lang/miri.svg?branch=master)](https://travis-ci.com/rust-lang/miri) -[![Appveyor Windows build status](https://ci.appveyor.com/api/projects/status/github/rust-lang/miri?svg=true)](https://ci.appveyor.com/project/rust-lang-libs/miri) [actions-badge]: https://github.com/rust-lang/miri/workflows/CI/badge.svg?branch=master [actions-url]: https://github.com/rust-lang/miri/actions From 70af7aed88456b8c478e06d1d28b0d8523a46b38 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Oct 2020 12:51:25 +0100 Subject: [PATCH 2413/5092] expand flag docs --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0aa22a81ad5c..0c280edec0ce 100644 --- a/README.md +++ b/README.md @@ -240,9 +240,12 @@ environment variable: future use of it will error). This helps you in finding out why UB is happening and where in your code would be a good place to look for it. * `-Zmiri-track-raw-pointers` makes Stacked Borrows track a pointer tag even for - raw pointers. This can make valid code fail to pass the checks (when - integer-pointer casts are involved), but also can help identify latent - aliasing issues in code that Miri accepts by default. + raw pointers. This can make valid code fail to pass the checks, but also can + help identify latent aliasing issues in code that Miri accepts by default. You + can recognize false positives by "" occurring in the message -- this + indicates a pointer that was cast from an integer, so Miri was unable to track + this pointer. Make sure to use a non-Windows target with this flag, as the + Windows runtime makes use of integer-pointer casts. Some native rustc `-Z` flags are also very relevant for Miri: From bf54607ba03cf12a015e7027be6d5ffdf08cc3ca Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Oct 2020 13:50:27 +0100 Subject: [PATCH 2414/5092] test raw pointer tracking; we cannot track raw pointers on Windows --- tests/compile-fail/stacked_borrows/raw_tracking.rs | 13 +++++++++++++ tests/run-pass/format.rs | 2 -- tests/run-pass/slices.rs | 1 - tests/run-pass/vec.rs | 1 + tests/run-pass/vecdeque.rs | 1 + 5 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 tests/compile-fail/stacked_borrows/raw_tracking.rs diff --git a/tests/compile-fail/stacked_borrows/raw_tracking.rs b/tests/compile-fail/stacked_borrows/raw_tracking.rs new file mode 100644 index 000000000000..b9ddee328f7a --- /dev/null +++ b/tests/compile-fail/stacked_borrows/raw_tracking.rs @@ -0,0 +1,13 @@ +// compile-flags: -Zmiri-track-raw-pointers +// ignore-windows (FIXME: tracking raw pointers does not work on Windows) +//! This demonstrates a provenance problem that requires tracking of raw pointers to be detected. + +fn main() { + let mut l = 13; + let raw1 = &mut l as *mut _; + let raw2 = &mut l as *mut _; // invalidates raw1 + // Without raw pointer tracking, Stacked Borrows cannot distinguish raw1 and raw2, and thus + // fails to realize that raw1 should not be used any more. + unsafe { *raw1 = 13; } //~ ERROR no item granting write access to tag + unsafe { *raw2 = 13; } +} diff --git a/tests/run-pass/format.rs b/tests/run-pass/format.rs index 3893efcb26a1..053cce36130c 100644 --- a/tests/run-pass/format.rs +++ b/tests/run-pass/format.rs @@ -1,5 +1,3 @@ -// compile-flags: -Zmiri-track-raw-pointers - fn main() { println!("Hello {}", 13); println!("{:0(dummy: &mut T, iter: impl Iterator) { diff --git a/tests/run-pass/vecdeque.rs b/tests/run-pass/vecdeque.rs index 54aeb89ec83f..55b47f622fde 100644 --- a/tests/run-pass/vecdeque.rs +++ b/tests/run-pass/vecdeque.rs @@ -1,4 +1,5 @@ // compile-flags: -Zmiri-track-raw-pointers +// ignore-windows (FIXME: tracking raw pointers does not work on Windows) use std::collections::VecDeque; fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { From 2589b482516941c109c1ab2f98dd446e23ca6887 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Oct 2020 14:05:37 +0100 Subject: [PATCH 2415/5092] update trophy case --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1de1c2e4c1b1..15dfddd65896 100644 --- a/README.md +++ b/README.md @@ -388,7 +388,10 @@ Definite bugs found: Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): * [`VecDeque::drain` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/56161) -* [`BTreeMap` iterators creating mutable references that overlap with shared references](https://github.com/rust-lang/rust/pull/58431) +* Various `BTreeMap` problems + * [`BTreeMap` iterators creating mutable references that overlap with shared references](https://github.com/rust-lang/rust/pull/58431) + * [`BTreeMap::iter_mut` creating overlapping mutable references](https://github.com/rust-lang/rust/issues/73915) + * [`BTreeMap` node insertion using raw pointers outside their valid memory area](https://github.com/rust-lang/rust/issues/78477) * [`LinkedList` cursor insertion creating overlapping mutable references](https://github.com/rust-lang/rust/pull/60072) * [`Vec::push` invalidating existing references into the vector](https://github.com/rust-lang/rust/issues/60847) * [`align_to_mut` violating uniqueness of mutable references](https://github.com/rust-lang/rust/issues/68549) @@ -397,9 +400,9 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [`ryu` using raw pointers outside their valid memory area](https://github.com/dtolnay/ryu/issues/24) * [ink! creating overlapping mutable references](https://github.com/rust-lang/miri/issues/1364) * [TiKV creating overlapping mutable reference and raw pointer](https://github.com/tikv/tikv/pull/7709) -* [Windows `Env` iterator creating `*const T` from `&T` to read memory outside of `T`](https://github.com/rust-lang/rust/pull/70479) -* [`BTreeMap::iter_mut` creating overlapping mutable references](https://github.com/rust-lang/rust/issues/73915) +* [Windows `Env` iterator using a raw pointer outside its valid memory area](https://github.com/rust-lang/rust/pull/70479) * [`VecDeque::iter_mut` creating overlapping mutable references](https://github.com/rust-lang/rust/issues/74029) +* [Standard library `SipHasher` using a raw pointer outside its valid memory area](https://github.com/rust-lang/rust/pull/78484) ## License From 1ad827c511bdde7ddca7010da7320f2051fc58d4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 29 Oct 2020 20:57:38 +0100 Subject: [PATCH 2416/5092] rustup --- rust-version | 2 +- tests/run-pass/box.rs | 2 +- tests/run-pass/dyn-traits.rs | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 44e9a77940d6..40aa78ae9a9c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -17cc9b6256c95c31944591aec683884fead4e3b6 +a53fb30e3bf2655b0563da6d561c23cda5f3ec11 diff --git a/tests/run-pass/box.rs b/tests/run-pass/box.rs index b89c0ac1286e..c29a83507677 100644 --- a/tests/run-pass/box.rs +++ b/tests/run-pass/box.rs @@ -21,7 +21,7 @@ fn into_raw() { unsafe { fn into_unique() { unsafe { let b = Box::new(4i32); - let u = Box::into_unique(b); + let u = Box::into_unique(b).0; // "lose the tag" let r = ((u.as_ptr() as usize)+0) as *mut i32; diff --git a/tests/run-pass/dyn-traits.rs b/tests/run-pass/dyn-traits.rs index 33d1f4fc1cf0..51c2130bcd3f 100644 --- a/tests/run-pass/dyn-traits.rs +++ b/tests/run-pass/dyn-traits.rs @@ -1,4 +1,5 @@ -#![feature(unsized_locals)] +#![feature(unsized_locals, unsized_fn_params)] +#![allow(incomplete_features)] fn ref_box_dyn() { struct Struct(i32); From 02af2a38acc9c96e6012f8647d063669b19c0a32 Mon Sep 17 00:00:00 2001 From: Camelid Date: Thu, 29 Oct 2020 16:14:54 -0700 Subject: [PATCH 2417/5092] Fix link in README --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ebc740bf3f03..4b09d1586ad4 100644 --- a/README.md +++ b/README.md @@ -259,7 +259,7 @@ Some native rustc `-Z` flags are also very relevant for Miri: Moreover, Miri recognizes some environment variables: * `MIRI_LOG`, `MIRI_BACKTRACE` control logging and backtrace printing during - Miri executions, also [see above][testing-miri]. + Miri executions, also [see "Testing the Miri driver" in `CONTRIBUTING.md`][testing-miri]. * `MIRIFLAGS` (recognized by `cargo miri` and the test suite) defines extra flags to be passed to Miri. * `MIRI_SYSROOT` (recognized by `cargo miri` and the test suite) @@ -281,6 +281,8 @@ different Miri binaries, and as such worth documenting: directory after loading all the source files, but before commencing interpretation. This is useful if the interpreted program wants a different working directory at run-time than at build-time. + +[testing-miri]: CONTRIBUTING.md#testing-the-miri-driver ## Miri `extern` functions From 1496462a89977afdf328b5ecd4d5912344ad863a Mon Sep 17 00:00:00 2001 From: Camelid Date: Thu, 29 Oct 2020 17:00:12 -0700 Subject: [PATCH 2418/5092] Update locally-built rustc instructions --- CONTRIBUTING.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a143190d5bdb..a4a589156169 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -141,19 +141,22 @@ tracing) enabled. The setup for a local rustc works as follows: ```sh +# Clone the rust-lang/rust repo. git clone https://github.com/rust-lang/rust/ rustc cd rustc cp config.toml.example config.toml # Now edit `config.toml` and set `debug-assertions = true`. -# This step can take 30 minutes and more. -./x.py build src/rustc + +# Build a stage 2 rustc. +# This step can take 30 minutes or more. +./x.py build --stage 2 compiler/rustc # If you change something, you can get a faster rebuild by doing -./x.py --keep-stage 0 build src/rustc +./x.py build --keep-stage 0 --stage 2 compiler/rustc # You may have to change the architecture in the next command rustup toolchain link custom build/x86_64-unknown-linux-gnu/stage2 # Now cd to your Miri directory, then configure rustup rustup override set custom ``` -With this, you should now have a working development setup! See +With this, you should now have a working development setup! See [above](#building-and-testing-miri) for how to proceed working on Miri. From 2a4faf638bb65d26a92cf9d8047818f6105dd078 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 30 Oct 2020 18:59:58 +0100 Subject: [PATCH 2419/5092] increase timeout to avoid spurious test failures --- tests/run-pass/concurrency/sync.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index bdbc4b90f6ed..e97da415cbb1 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -109,7 +109,7 @@ fn check_conditional_variables_timed_wait_notimeout() { cvar.notify_one(); }); - let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(200)).unwrap(); + let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(500)).unwrap(); assert!(!timeout.timed_out()); handle.join().unwrap(); } From bb59980b2da10437ce1ee4d53bdb3feb1f4a9c5f Mon Sep 17 00:00:00 2001 From: Camelid Date: Fri, 30 Oct 2020 14:33:12 -0700 Subject: [PATCH 2420/5092] CONTRIBUTING.md: Use `build --stage 1` instead of `build --stage 2` It seems to work fine with `--stage 1` and it should be faster. --- CONTRIBUTING.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a4a589156169..20f01f151a65 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -142,20 +142,20 @@ tracing) enabled. The setup for a local rustc works as follows: ```sh # Clone the rust-lang/rust repo. -git clone https://github.com/rust-lang/rust/ rustc +git clone https://github.com/rust-lang/rust rustc cd rustc cp config.toml.example config.toml # Now edit `config.toml` and set `debug-assertions = true`. -# Build a stage 2 rustc. +# Build a stage 1 rustc. # This step can take 30 minutes or more. -./x.py build --stage 2 compiler/rustc +./x.py build --stage 1 compiler/rustc # If you change something, you can get a faster rebuild by doing -./x.py build --keep-stage 0 --stage 2 compiler/rustc +./x.py build --keep-stage 0 --stage 1 compiler/rustc # You may have to change the architecture in the next command -rustup toolchain link custom build/x86_64-unknown-linux-gnu/stage2 +rustup toolchain link stage1 build/x86_64-unknown-linux-gnu/stage1 # Now cd to your Miri directory, then configure rustup -rustup override set custom +rustup override set stage1 ``` With this, you should now have a working development setup! See From e7246be4f0d6cbaf714f6e695cd50fc7f0688a95 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 31 Oct 2020 13:47:42 +0100 Subject: [PATCH 2421/5092] backtrace tests: support more ways of checking out Rust locally --- tests/run-pass/backtrace-api.rs | 2 +- tests/run-pass/backtrace-std.rs | 2 +- tests/run-pass/panic/panic1.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/run-pass/backtrace-api.rs b/tests/run-pass/backtrace-api.rs index 19169060038e..cb3706e9f513 100644 --- a/tests/run-pass/backtrace-api.rs +++ b/tests/run-pass/backtrace-api.rs @@ -1,4 +1,4 @@ -// normalize-stderr-test ".*/(rust|checkout)/library/" -> "RUSTLIB/" +// normalize-stderr-test ".*/(rust[^/]*|checkout)/library/" -> "RUSTLIB/" // normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL " // normalize-stderr-test "::<.*>" -> "" diff --git a/tests/run-pass/backtrace-std.rs b/tests/run-pass/backtrace-std.rs index fb596b1d2020..7a793e092a81 100644 --- a/tests/run-pass/backtrace-std.rs +++ b/tests/run-pass/backtrace-std.rs @@ -1,4 +1,4 @@ -// normalize-stderr-test "at .*/(rust|checkout)/library/" -> "at RUSTLIB/" +// normalize-stderr-test "at .*/(rust[^/]*|checkout)/library/" -> "at RUSTLIB/" // normalize-stderr-test "RUSTLIB/(.*):\d+"-> "RUSTLIB/$1:LL" // normalize-stderr-test "::<.*>" -> "" // compile-flags: -Zmiri-disable-isolation diff --git a/tests/run-pass/panic/panic1.rs b/tests/run-pass/panic/panic1.rs index 08ac3a072852..da300ecb59f6 100644 --- a/tests/run-pass/panic/panic1.rs +++ b/tests/run-pass/panic/panic1.rs @@ -1,6 +1,6 @@ // rustc-env: RUST_BACKTRACE=1 // compile-flags: -Zmiri-disable-isolation -// normalize-stderr-test "at .*/(rust|checkout)/library/.*" -> "at RUSTLIB/$$FILE:LL:COL" +// normalize-stderr-test "at .*/(rust[^/]*|checkout)/library/.*" -> "at RUSTLIB/$$FILE:LL:COL" // normalize-stderr-test "::<.*>" -> "" From 80a0a12b07e4c3346cbacf70dcea810779ca0574 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 31 Oct 2020 13:56:46 +0100 Subject: [PATCH 2422/5092] Stacked Borrows: test raw-ref-to-field with raw ptr tracking --- tests/run-pass/stacked-borrows/int-to-ptr.rs | 13 +++++++ .../stacked-borrows/stacked-borrows.rs | 36 +++++++++++++------ 2 files changed, 38 insertions(+), 11 deletions(-) create mode 100644 tests/run-pass/stacked-borrows/int-to-ptr.rs diff --git a/tests/run-pass/stacked-borrows/int-to-ptr.rs b/tests/run-pass/stacked-borrows/int-to-ptr.rs new file mode 100644 index 000000000000..efba0da1b935 --- /dev/null +++ b/tests/run-pass/stacked-borrows/int-to-ptr.rs @@ -0,0 +1,13 @@ +fn main() { + ref_raw_int_raw(); +} + +// Just to make sure that casting a ref to raw, to int and back to raw +// and only then using it works. This rules out ideas like "do escape-to-raw lazily"; +// after casting to int and back, we lost the tag that could have let us do that. +fn ref_raw_int_raw() { + let mut x = 3; + let xref = &mut x; + let xraw = xref as *mut i32 as usize as *mut i32; + assert_eq!(unsafe { *xraw }, 3); +} diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index 765c6188b6e1..ad1877fc019b 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -1,8 +1,12 @@ +// compile-flags: -Zmiri-track-raw-pointers +// ignore-windows (FIXME: tracking raw pointers does not work on Windows) +#![feature(raw_ref_macros)] +use std::ptr; + // Test various stacked-borrows-related things. fn main() { read_does_not_invalidate1(); read_does_not_invalidate2(); - ref_raw_int_raw(); mut_raw_then_mut_shr(); mut_shr_then_mut_raw(); mut_raw_mut(); @@ -12,6 +16,7 @@ fn main() { two_raw(); shr_and_raw(); disjoint_mutable_subborrows(); + raw_ref_to_part(); } // Make sure that reading from an `&mut` does, like reborrowing to `&`, @@ -37,16 +42,6 @@ fn read_does_not_invalidate2() { assert_eq!(*foo(&mut (1, 2)), 2); } -// Just to make sure that casting a ref to raw, to int and back to raw -// and only then using it works. This rules out ideas like "do escape-to-raw lazily"; -// after casting to int and back, we lost the tag that could have let us do that. -fn ref_raw_int_raw() { - let mut x = 3; - let xref = &mut x; - let xraw = xref as *mut i32 as usize as *mut i32; - assert_eq!(unsafe { *xraw }, 3); -} - // Escape a mut to raw, then share the same mut and use the share, then the raw. // That should work. fn mut_raw_then_mut_shr() { @@ -162,3 +157,22 @@ fn disjoint_mutable_subborrows() { a.push_str(" world"); eprintln!("{:?} {:?}", a, b); } + +fn raw_ref_to_part() { + struct Part { + _lame: i32, + } + + #[repr(C)] + struct Whole { + part: Part, + extra: i32, + } + + let it = Box::new(Whole { part: Part { _lame: 0 }, extra: 42 }); + let whole = ptr::raw_mut!(*Box::leak(it)); + let part = unsafe { ptr::raw_mut!((*whole).part) }; + let typed = unsafe { &mut *(part as *mut Whole) }; + assert!(typed.extra == 42); + drop(unsafe { Box::from_raw(whole) }); +} From f936bc6b92dbee4e94988b9c46298f59481bd2ea Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 31 Oct 2020 16:22:16 +0100 Subject: [PATCH 2423/5092] fix writing to read-only raw pointer in thread-local test --- tests/run-pass/thread-local.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/thread-local.rs b/tests/run-pass/thread-local.rs index 1aa442edad3b..72ab973b0f08 100644 --- a/tests/run-pass/thread-local.rs +++ b/tests/run-pass/thread-local.rs @@ -58,7 +58,7 @@ fn main() { // Initialize the keys we use to check destructor ordering for (key, global) in KEYS.iter_mut().zip(GLOBALS.iter_mut()) { *key = create(Some(mem::transmute(dtor as unsafe extern fn(*mut u64)))); - set(*key, global as *const _ as *mut _); + set(*key, global as *mut _ as *mut u8); } // Initialize cannary From 00bc944eeac0eaa12a1facf2e623f7832f402e57 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 31 Oct 2020 16:23:41 +0100 Subject: [PATCH 2424/5092] test Rc with raw pointer tracking --- tests/run-pass/rc.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index 3dc61fe1f00d..47f29992c459 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-track-raw-pointers +// ignore-windows (FIXME: tracking raw pointers does not work on Windows) #![feature(new_uninit)] #![feature(get_mut_unchecked)] From 7eaba6684cab6247a791cd5620710773e5308c33 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 31 Oct 2020 16:28:56 +0100 Subject: [PATCH 2425/5092] fix trophy case URL --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4b09d1586ad4..578ca0251c5e 100644 --- a/README.md +++ b/README.md @@ -411,7 +411,7 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [TiKV creating overlapping mutable reference and raw pointer](https://github.com/tikv/tikv/pull/7709) * [Windows `Env` iterator using a raw pointer outside its valid memory area](https://github.com/rust-lang/rust/pull/70479) * [`VecDeque::iter_mut` creating overlapping mutable references](https://github.com/rust-lang/rust/issues/74029) -* [Standard library `SipHasher` using a raw pointer outside its valid memory area](https://github.com/rust-lang/rust/pull/78484) +* [Various standard library aliasing issues involving raw pointers](https://github.com/rust-lang/rust/pull/78602) ## License From 89814f1b3f6c239f472dea4798a1189a30d7efa2 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Mon, 2 Nov 2020 00:23:27 +0000 Subject: [PATCH 2426/5092] Initial data-race detector, passes all current tests but additional tests are required --- Cargo.lock | 7 + Cargo.toml | 1 + src/data_race.rs | 1406 +++++++++++++++++++++++++++++++++++++ src/lib.rs | 5 + src/machine.rs | 11 +- src/shims/intrinsics.rs | 411 +++++++---- src/shims/posix/sync.rs | 16 +- src/shims/posix/thread.rs | 17 +- src/sync.rs | 64 +- src/thread.rs | 30 +- 10 files changed, 1795 insertions(+), 173 deletions(-) create mode 100644 src/data_race.rs diff --git a/Cargo.lock b/Cargo.lock index 8c73cb05535c..78838acb2a5f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -282,6 +282,7 @@ dependencies = [ "rustc-workspace-hack", "rustc_version", "shell-escape", + "smallvec", ] [[package]] @@ -496,6 +497,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" +[[package]] +name = "smallvec" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252" + [[package]] name = "socket2" version = "0.3.15" diff --git a/Cargo.toml b/Cargo.toml index c36a97bb0a1a..4413dab321e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ log = "0.4" shell-escape = "0.1.4" hex = "0.4.0" rand = "0.7" +smallvec = "1.4.2" # A noop dependency that changes in the Rust repository, it's a bit of a hack. # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` diff --git a/src/data_race.rs b/src/data_race.rs new file mode 100644 index 000000000000..59526063945a --- /dev/null +++ b/src/data_race.rs @@ -0,0 +1,1406 @@ +//! Implementation of a data-race detector +//! uses Lamport Timestamps / Vector-clocks +//! base on the Dyamic Race Detection for C++: +//! - https://www.doc.ic.ac.uk/~afd/homepages/papers/pdfs/2017/POPL.pdf +//! to extend data-race detection to work correctly with fences +//! and RMW operations +//! This does not explore weak memory orders and so can still miss data-races +//! but should not report false-positives + +use std::{fmt::{self, Debug}, cmp::Ordering, rc::Rc, cell::{Cell, RefCell, Ref, RefMut}, ops::Index}; + +use rustc_index::vec::{Idx, IndexVec}; +use rustc_target::abi::Size; +use rustc_middle::ty::layout::TyAndLayout; +use rustc_data_structures::fx::FxHashMap; + +use smallvec::SmallVec; + +use crate::*; + +pub type AllocExtra = VClockAlloc; +pub type MemoryExtra = Rc; + +/// Valid atomic read-write operations, alias of atomic::Ordering (not non-exhaustive) +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum AtomicRWOp { + Relaxed, + Acquire, + Release, + AcqRel, + SeqCst, +} + +/// Valid atomic read operations, subset of atomic::Ordering +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum AtomicReadOp { + Relaxed, + Acquire, + SeqCst, +} + +/// Valid atomic write operations, subset of atomic::Ordering +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum AtomicWriteOp { + Relaxed, + Release, + SeqCst, +} + + +/// Valid atomic fence operations, subset of atomic::Ordering +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum AtomicFenceOp { + Acquire, + Release, + AcqRel, + SeqCst, +} + +/// Evaluation context extensions +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + + /// Variant of `read_immediate` that does not perform `data-race` checks. + fn read_immediate_racy(&self, op: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { + let this = self.eval_context_ref(); + let data_race = &*this.memory.extra.data_race; + let old = data_race.multi_threaded.get(); + + data_race.multi_threaded.set(false); + let res = this.read_immediate(op.into()); + + data_race.multi_threaded.set(old); + res + } + + /// Variant of `write_immediate` that does not perform `data-race` checks. + fn write_immediate_racy( + &mut self, src: Immediate, dest: MPlaceTy<'tcx, Tag> + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let data_race = &*this.memory.extra.data_race; + let old = data_race.multi_threaded.get(); + + data_race.multi_threaded.set(false); + let imm = this.write_immediate(src, dest.into()); + + let data_race = &*this.memory.extra.data_race; + data_race.multi_threaded.set(old); + imm + } + + /// Variant of `read_scalar` that does not perform data-race checks. + fn read_scalar_racy( + &self, op: MPlaceTy<'tcx, Tag> + )-> InterpResult<'tcx, ScalarMaybeUninit> { + Ok(self.read_immediate_racy(op)?.to_scalar_or_uninit()) + } + + /// Variant of `write_scalar` that does not perform data-race checks. + fn write_scalar_racy( + &mut self, val: ScalarMaybeUninit, dest: MPlaceTy<'tcx, Tag> + ) -> InterpResult<'tcx> { + self.write_immediate_racy(Immediate::Scalar(val.into()), dest) + } + + /// Variant of `read_scalar_at_offset` helper function that does not perform + /// `data-race checks. + fn read_scalar_at_offset_racy( + &self, + op: OpTy<'tcx, Tag>, + offset: u64, + layout: TyAndLayout<'tcx>, + ) -> InterpResult<'tcx, ScalarMaybeUninit> { + let this = self.eval_context_ref(); + let op_place = this.deref_operand(op)?; + let offset = Size::from_bytes(offset); + // Ensure that the following read at an offset is within bounds + assert!(op_place.layout.size >= offset + layout.size); + let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; + this.read_scalar_racy(value_place.into()) + } + + /// Variant of `write_scalar_at_offfset` helper function that does not perform + /// data-race checks. + fn write_scalar_at_offset_racy( + &mut self, + op: OpTy<'tcx, Tag>, + offset: u64, + value: impl Into>, + layout: TyAndLayout<'tcx>, + ) -> InterpResult<'tcx, ()> { + let this = self.eval_context_mut(); + let op_place = this.deref_operand(op)?; + let offset = Size::from_bytes(offset); + // Ensure that the following read at an offset is within bounds + assert!(op_place.layout.size >= offset + layout.size); + let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; + this.write_scalar_racy(value.into(), value_place.into()) + } + + /// Load the data race allocation state for a given memory place + /// also returns the size and the offset of the result in the allocation + /// metadata + fn load_data_race_state<'a>( + &'a mut self, place: MPlaceTy<'tcx, Tag> + ) -> InterpResult<'tcx, (&'a mut VClockAlloc, Size, Size)> where 'mir: 'a { + let this = self.eval_context_mut(); + + let ptr = place.ptr.assert_ptr(); + let size = place.layout.size; + let data_race = &mut this.memory.get_raw_mut(ptr.alloc_id)?.extra.data_race; + + Ok((data_race, size, ptr.offset)) + } + + /// Update the data-race detector for an atomic read occuring at the + /// associated memory-place and on the current thread + fn validate_atomic_load( + &mut self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicReadOp + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let data_race = &*this.memory.extra.data_race; + if data_race.multi_threaded.get() { + data_race.advance_vector_clock(); + + let ( + alloc, size, offset + ) = this.load_data_race_state(place)?; + log::trace!( + "Atomic load on {:?} with ordering {:?}, in memory({:?}, offset={}, size={})", + alloc.global.current_thread(), atomic, + place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes() + ); + + let mut current_state = alloc.global.current_thread_state_mut(); + if atomic == AtomicReadOp::Relaxed { + // Perform relaxed atomic load + for range in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { + range.load_relaxed(&mut *current_state); + } + }else{ + // Perform acquire(or seq-cst) atomic load + for range in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { + range.acquire(&mut *current_state); + } + } + + // Log changes to atomic memory + if log::log_enabled!(log::Level::Trace) { + for range in alloc.alloc_ranges.get_mut().iter(offset, size) { + log::trace!( + " updated atomic memory({:?}, offset={}, size={}) to {:#?}", + place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes(), + range.atomic_ops + ); + } + } + + std::mem::drop(current_state); + let data_race = &*this.memory.extra.data_race; + data_race.advance_vector_clock(); + } + Ok(()) + } + + /// Update the data-race detector for an atomic write occuring at the + /// associated memory-place and on the current thread + fn validate_atomic_store( + &mut self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicWriteOp + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let data_race = &*this.memory.extra.data_race; + if data_race.multi_threaded.get() { + data_race.advance_vector_clock(); + + let ( + alloc, size, offset + ) = this.load_data_race_state(place)?; + let current_thread = alloc.global.current_thread(); + let mut current_state = alloc.global.current_thread_state_mut(); + log::trace!( + "Atomic store on {:?} with ordering {:?}, in memory({:?}, offset={}, size={})", + current_thread, atomic, + place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes() + ); + + if atomic == AtomicWriteOp::Relaxed { + // Perform relaxed atomic store + for range in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { + range.store_relaxed(&mut *current_state, current_thread); + } + }else{ + // Perform release(or seq-cst) atomic store + for range in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { + range.release(&mut *current_state, current_thread); + } + } + + // Log changes to atomic memory + if log::log_enabled!(log::Level::Trace) { + for range in alloc.alloc_ranges.get_mut().iter(offset, size) { + log::trace!( + " updated atomic memory({:?}, offset={}, size={}) to {:#?}", + place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes(), + range.atomic_ops + ); + } + } + + std::mem::drop(current_state); + let data_race = &*this.memory.extra.data_race; + data_race.advance_vector_clock(); + } + Ok(()) + } + + /// Update the data-race detector for an atomic read-modify-write occuring + /// at the associated memory place and on the current thread + fn validate_atomic_rmw( + &mut self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicRWOp + ) -> InterpResult<'tcx> { + use AtomicRWOp::*; + let this = self.eval_context_mut(); + let data_race = &*this.memory.extra.data_race; + if data_race.multi_threaded.get() { + data_race.advance_vector_clock(); + + let ( + alloc, size, offset + ) = this.load_data_race_state(place)?; + let current_thread = alloc.global.current_thread(); + let mut current_state = alloc.global.current_thread_state_mut(); + log::trace!( + "Atomic RMW on {:?} with ordering {:?}, in memory({:?}, offset={}, size={})", + current_thread, atomic, + place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes() + ); + + let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); + let release = matches!(atomic, Release | AcqRel | SeqCst); + for range in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { + //FIXME: this is probably still slightly wrong due to the quirks + // in the c++11 memory model + if acquire { + // Atomic RW-Op acquire + range.acquire(&mut *current_state); + }else{ + range.load_relaxed(&mut *current_state); + } + if release { + // Atomic RW-Op release + range.rmw_release(&mut *current_state, current_thread); + }else{ + range.rmw_relaxed(&mut *current_state); + } + } + + // Log changes to atomic memory + if log::log_enabled!(log::Level::Trace) { + for range in alloc.alloc_ranges.get_mut().iter(offset, size) { + log::trace!( + " updated atomic memory({:?}, offset={}, size={}) to {:#?}", + place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes(), + range.atomic_ops + ); + } + } + + std::mem::drop(current_state); + let data_race = &*this.memory.extra.data_race; + data_race.advance_vector_clock(); + } + Ok(()) + } + + /// Update the data-race detector for an atomic fence on the current thread + fn validate_atomic_fence(&mut self, atomic: AtomicFenceOp) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let data_race = &*this.memory.extra.data_race; + if data_race.multi_threaded.get() { + data_race.advance_vector_clock(); + + log::trace!("Atomic fence on {:?} with ordering {:?}", data_race.current_thread(), atomic); + // Apply data-race detection for the current fences + // this treats AcqRel and SeqCst as the same as a acquire + // and release fence applied in the same timestamp. + if atomic != AtomicFenceOp::Release { + // Either Acquire | AcqRel | SeqCst + data_race.current_thread_state_mut().apply_acquire_fence(); + } + if atomic != AtomicFenceOp::Acquire { + // Either Release | AcqRel | SeqCst + data_race.current_thread_state_mut().apply_release_fence(); + } + + data_race.advance_vector_clock(); + } + Ok(()) + } +} + +/// Handle for locks to express their +/// acquire-release semantics +#[derive(Clone, Debug, Default)] +pub struct DataRaceLockHandle { + + /// Internal acquire-release clock + /// to express the acquire release sync + /// found in concurrency primitives + clock: VClock, +} +impl DataRaceLockHandle { + pub fn set_values(&mut self, other: &Self) { + self.clock.set_values(&other.clock) + } + pub fn reset(&mut self) { + self.clock.set_zero_vector(); + } +} + + +/// Avoid an atomic allocation for the common +/// case with atomic operations where the number +/// of active release sequences is small +#[derive(Clone, PartialEq, Eq)] +enum AtomicReleaseSequences { + + /// Contains one or no values + /// if empty: (None, reset vector clock) + /// if one: (Some(thread), thread_clock) + ReleaseOneOrEmpty(Option, VClock), + + /// Contains two or more values + /// stored in a hash-map of thread id to + /// vector clocks + ReleaseMany(FxHashMap) +} +impl AtomicReleaseSequences { + + /// Return an empty set of atomic release sequences + #[inline] + fn new() -> AtomicReleaseSequences { + Self::ReleaseOneOrEmpty(None, VClock::default()) + } + + /// Remove all values except for the value stored at `thread` and set + /// the vector clock to the associated `clock` value + #[inline] + fn clear_and_set(&mut self, thread: ThreadId, clock: &VClock) { + match self { + Self::ReleaseOneOrEmpty(id, rel_clock) => { + *id = Some(thread); + rel_clock.set_values(clock); + } + Self::ReleaseMany(_) => { + *self = Self::ReleaseOneOrEmpty(Some(thread), clock.clone()); + } + } + } + + /// Remove all values except for the value stored at `thread` + #[inline] + fn clear_and_retain(&mut self, thread: ThreadId) { + match self { + Self::ReleaseOneOrEmpty(id, rel_clock) => { + // Keep or forget depending on id + if *id == Some(thread) { + *id = None; + rel_clock.set_zero_vector(); + } + }, + Self::ReleaseMany(hash_map) => { + // Retain only the thread element, so reduce to size + // of 1 or 0, and move to smaller format + if let Some(clock) = hash_map.remove(&thread) { + *self = Self::ReleaseOneOrEmpty(Some(thread), clock); + }else{ + *self = Self::new(); + } + } + } + } + + /// Insert a release sequence at `thread` with values `clock` + fn insert(&mut self, thread: ThreadId, clock: &VClock) { + match self { + Self::ReleaseOneOrEmpty(id, rel_clock) => { + if id.map_or(true, |id| id == thread) { + *id = Some(thread); + rel_clock.set_values(clock); + }else{ + let mut hash_map = FxHashMap::default(); + hash_map.insert(thread, clock.clone()); + hash_map.insert(id.unwrap(), rel_clock.clone()); + *self = Self::ReleaseMany(hash_map); + } + }, + Self::ReleaseMany(hash_map) => { + hash_map.insert(thread, clock.clone()); + } + } + } + + /// Return the release sequence at `thread` if one exists + #[inline] + fn load(&self, thread: ThreadId) -> Option<&VClock> { + match self { + Self::ReleaseOneOrEmpty(id, clock) => { + if *id == Some(thread) { + Some(clock) + }else{ + None + } + }, + Self::ReleaseMany(hash_map) => { + hash_map.get(&thread) + } + } + } +} + +/// Custom debug implementation to correctly +/// print debug as a logical mapping from threads +/// to vector-clocks +impl Debug for AtomicReleaseSequences { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::ReleaseOneOrEmpty(None,_) => { + f.debug_map().finish() + }, + Self::ReleaseOneOrEmpty(Some(id), clock) => { + f.debug_map().entry(&id, &clock).finish() + }, + Self::ReleaseMany(hash_map) => { + Debug::fmt(hash_map, f) + } + } + } +} + +/// Externally stored memory cell clocks +/// explicitly to reduce memory usage for the +/// common case where no atomic operations +/// exists on the memory cell +#[derive(Clone, PartialEq, Eq, Debug)] +struct AtomicMemoryCellClocks { + + /// Synchronization vector for acquire-release semantics + sync_vector: VClock, + + /// The Hash-Map of all threads for which a release + /// sequence exists in the memory cell + release_sequences: AtomicReleaseSequences, +} + +/// Memory Cell vector clock metadata +/// for data-race detection +#[derive(Clone, PartialEq, Eq, Debug)] +struct MemoryCellClocks { + + /// The vector-clock of the last write + write: Timestamp, + + /// The id of the thread that performed the last write to this memory location + write_thread: ThreadId, + + /// The vector-clock of the set of previous reads + /// each index is set to the timestamp that the associated + /// thread last read this value. + read: VClock, + + /// Atomic acquire & release sequence tracking clocks + /// for non-atomic memory in the common case this + /// value is set to None + atomic_ops: Option>, +} + +/// Create a default memory cell clocks instance +/// for uninitialized memory +impl Default for MemoryCellClocks { + fn default() -> Self { + MemoryCellClocks { + read: VClock::default(), + write: 0, + write_thread: ThreadId::new(u32::MAX as usize), + atomic_ops: None + } + } +} + +impl MemoryCellClocks { + + /// Load the internal atomic memory cells if they exist + #[inline] + fn atomic(&mut self) -> Option<&AtomicMemoryCellClocks> { + match &self.atomic_ops { + Some(op) => Some(&*op), + None => None + } + } + + /// Load or create the internal atomic memory metadata + /// if it does not exist + #[inline] + fn atomic_mut(&mut self) -> &mut AtomicMemoryCellClocks { + self.atomic_ops.get_or_insert_with(|| { + Box::new(AtomicMemoryCellClocks { + sync_vector: VClock::default(), + release_sequences: AtomicReleaseSequences::new() + }) + }) + } + + /// Update memory cell data-race tracking for atomic + /// load acquire semantics, is a no-op if this memory was + /// not used previously as atomic memory + fn acquire(&mut self, clocks: &mut ThreadClockSet) { + if let Some(atomic) = self.atomic() { + clocks.clock.join(&atomic.sync_vector); + } + } + /// Update memory cell data-race tracking for atomic + /// load relaxed semantics, is a no-op if this memory was + /// not used previously as atomic memory + fn load_relaxed(&mut self, clocks: &mut ThreadClockSet) { + if let Some(atomic) = self.atomic() { + clocks.fence_acquire.join(&atomic.sync_vector); + } + } + + + /// Update the memory cell data-race tracking for atomic + /// store release semantics + fn release(&mut self, clocks: &ThreadClockSet, thread: ThreadId) { + let atomic = self.atomic_mut(); + atomic.sync_vector.set_values(&clocks.clock); + atomic.release_sequences.clear_and_set(thread, &clocks.clock); + } + /// Update the memory cell data-race tracking for atomic + /// store relaxed semantics + fn store_relaxed(&mut self, clocks: &ThreadClockSet, thread: ThreadId) { + let atomic = self.atomic_mut(); + atomic.sync_vector.set_values(&clocks.fence_release); + if let Some(release) = atomic.release_sequences.load(thread) { + atomic.sync_vector.join(release); + } + atomic.release_sequences.clear_and_retain(thread); + } + /// Update the memory cell data-race tracking for atomic + /// store release semantics for RMW operations + fn rmw_release(&mut self, clocks: &ThreadClockSet, thread: ThreadId) { + let atomic = self.atomic_mut(); + atomic.sync_vector.join(&clocks.clock); + atomic.release_sequences.insert(thread, &clocks.clock); + } + /// Update the memory cell data-race tracking for atomic + /// store relaxed semantics for RMW operations + fn rmw_relaxed(&mut self, clocks: &ThreadClockSet) { + let atomic = self.atomic_mut(); + atomic.sync_vector.join(&clocks.fence_release); + } + + + + /// Detect races for non-atomic read operations at the current memory cell + /// returns true if a data-race is detected + fn read_race_detect(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> bool { + if self.write <= clocks.clock[self.write_thread] { + self.read.set_at_thread(&clocks.clock, thread); + false + }else{ + true + } + } + + /// Detect races for non-atomic write operations at the current memory cell + /// returns true if a data-race is detected + fn write_race_detect(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> bool { + if self.write <= clocks.clock[self.write_thread] && self.read <= clocks.clock { + self.write = clocks.clock[thread]; + self.write_thread = thread; + self.read.set_zero_vector(); + false + }else{ + true + } + } +} + +/// Vector clock metadata for a logical memory allocation +#[derive(Debug, Clone)] +pub struct VClockAlloc { + + /// Range of Vector clocks, mapping to the vector-clock + /// index of the last write to the bytes in this allocation + alloc_ranges: RefCell>, + + // Pointer to global state + global: MemoryExtra, +} + +impl VClockAlloc { + + /// Create a new data-race allocation detector + pub fn new_allocation(global: &MemoryExtra, len: Size) -> VClockAlloc { + VClockAlloc { + global: Rc::clone(global), + alloc_ranges: RefCell::new( + RangeMap::new(len, MemoryCellClocks::default()) + ) + } + } + + /// Report a data-race found in the program + /// this finds the two racing threads and the type + /// of data-race that occured, this will also + /// return info about the memory location the data-race + /// occured in + #[cold] + #[inline(never)] + fn report_data_race<'tcx>( + global: &MemoryExtra, range: &MemoryCellClocks, action: &str, + pointer: Pointer, len: Size + ) -> InterpResult<'tcx> { + let current_thread = global.current_thread(); + let current_state = global.current_thread_state(); + let mut write_clock = VClock::default(); + let ( + other_action, other_thread, other_clock + ) = if range.write > current_state.clock[range.write_thread] { + + // Create effective write-clock that the data-race occured with + let wclock = write_clock.get_mut_with_min_len( + current_state.clock.as_slice().len() + .max(range.write_thread.to_u32() as usize + 1) + ); + wclock[range.write_thread.to_u32() as usize] = range.write; + ("WRITE", range.write_thread, write_clock.as_slice()) + }else{ + + // Find index in the read-clock that the data-race occured with + let read_slice = range.read.as_slice(); + let clock_slice = current_state.clock.as_slice(); + let conflicting_index = read_slice.iter() + .zip(clock_slice.iter()) + .enumerate().find_map(|(idx,(&read, &clock))| { + if read > clock { + Some(idx) + }else{ + None + } + }).unwrap_or_else(|| { + assert!(read_slice.len() > clock_slice.len(), "BUG: cannot find read race yet reported data-race"); + let rest_read = &read_slice[clock_slice.len()..]; + rest_read.iter().enumerate().find_map(|(idx, &val)| { + if val > 0 { + Some(idx + clock_slice.len()) + }else{ + None + } + }).expect("Invariant broken for read-slice, no 0 element at the tail") + }); + ("READ", ThreadId::new(conflicting_index), range.read.as_slice()) + }; + + let current_thread_info = global.print_thread_metadata(current_thread); + let other_thread_info = global.print_thread_metadata(other_thread); + + // Throw the data-race detection + throw_ub_format!( + "Data race detected between {} on {} and {} on {}, memory({:?},offset={},size={})\ + \n\t\t -current vector clock = {:?}\ + \n\t\t -conflicting timestamp = {:?}", + action, current_thread_info, + other_action, other_thread_info, + pointer.alloc_id, pointer.offset.bytes(), len.bytes(), + current_state.clock, + other_clock + ) + } + + /// Detect data-races for an unsychronized read operation, will not perform + /// data-race threads if `multi-threaded` is false, either due to no threads + /// being created or if it is temporarily disabled during a racy read or write + /// operation + pub fn read<'tcx>(&self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { + if self.global.multi_threaded.get() { + let current_thread = self.global.current_thread(); + let current_state = self.global.current_thread_state(); + + // The alloc-ranges are not split, however changes are not going to be made + // to the ranges being tested, so this is ok + let mut alloc_ranges = self.alloc_ranges.borrow_mut(); + for range in alloc_ranges.iter_mut(pointer.offset, len) { + if range.read_race_detect(&*current_state, current_thread) { + // Report data-race + return Self::report_data_race( + &self.global,range, "READ", pointer, len + ); + } + } + Ok(()) + }else{ + Ok(()) + } + } + /// Detect data-races for an unsychronized write operation, will not perform + /// data-race threads if `multi-threaded` is false, either due to no threads + /// being created or if it is temporarily disabled during a racy read or write + /// operation + pub fn write<'tcx>(&mut self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { + if self.global.multi_threaded.get() { + let current_thread = self.global.current_thread(); + let current_state = self.global.current_thread_state(); + for range in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { + if range.write_race_detect(&*current_state, current_thread) { + // Report data-race + return Self::report_data_race( + &self.global, range, "WRITE", pointer, len + ); + } + } + Ok(()) + }else{ + Ok(()) + } + } + /// Detect data-races for an unsychronized deallocate operation, will not perform + /// data-race threads if `multi-threaded` is false, either due to no threads + /// being created or if it is temporarily disabled during a racy read or write + /// operation + pub fn deallocate<'tcx>(&mut self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { + if self.global.multi_threaded.get() { + let current_thread = self.global.current_thread(); + let current_state = self.global.current_thread_state(); + for range in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { + if range.write_race_detect(&*current_state, current_thread) { + // Report data-race + return Self::report_data_race( + &self.global, range, "DEALLOCATE", pointer, len + ); + } + } + Ok(()) + }else{ + Ok(()) + } + } +} + +/// The current set of vector clocks describing the state +/// of a thread, contains the happens-before clock and +/// additional metadata to model atomic fence operations +#[derive(Clone, Default, Debug)] +struct ThreadClockSet { + /// The increasing clock representing timestamps + /// that happen-before this thread. + clock: VClock, + + /// The set of timestamps that will happen-before this + /// thread once it performs an acquire fence + fence_acquire: VClock, + + /// The last timesamp of happens-before relations that + /// have been released by this thread by a fence + fence_release: VClock, +} + +impl ThreadClockSet { + + /// Apply the effects of a release fence to this + /// set of thread vector clocks + #[inline] + fn apply_release_fence(&mut self) { + self.fence_release.set_values(&self.clock); + } + + /// Apply the effects of a acquire fence to this + /// set of thread vector clocks + #[inline] + fn apply_acquire_fence(&mut self) { + self.clock.join(&self.fence_acquire); + } + + /// Increment the happens-before clock at a + /// known index + #[inline] + fn increment_clock(&mut self, thread: ThreadId) { + self.clock.increment_thread(thread); + } + + /// Join the happens-before clock with that of + /// another thread, used to model thread join + /// operations + fn join_with(&mut self, other: &ThreadClockSet) { + self.clock.join(&other.clock); + } +} + +/// Global data-race detection state, contains the currently +/// executing thread as well as the vector-clocks associated +/// with each of the threads. +#[derive(Debug, Clone)] +pub struct GlobalState { + + /// Set to true once the first additional + /// thread has launched, due to the dependency + /// between before and after a thread launch + /// Any data-races must be recorded after this + /// so concurrent execution can ignore recording + /// any data-races + multi_threaded: Cell, + + /// The current vector clock for all threads + /// this includes threads that have terminated + /// execution + thread_clocks: RefCell>, + + /// Thread name cache for better diagnostics on the reporting + /// of a data-race + thread_names: RefCell>>>, + + /// The current thread being executed, + /// this is mirrored from the scheduler since + /// it is required for loading the current vector + /// clock for data-race detection + current_thread_id: Cell, +} +impl GlobalState { + + /// Create a new global state, setup with just thread-id=0 + /// advanced to timestamp = 1 + pub fn new() -> Self { + let mut vec = IndexVec::new(); + let thread_id = vec.push(ThreadClockSet::default()); + vec[thread_id].increment_clock(thread_id); + GlobalState { + multi_threaded: Cell::new(false), + thread_clocks: RefCell::new(vec), + thread_names: RefCell::new(IndexVec::new()), + current_thread_id: Cell::new(thread_id), + } + } + + + // Hook for thread creation, enabled multi-threaded execution and marks + // the current thread timestamp as happening-before the current thread + #[inline] + pub fn thread_created(&self, thread: ThreadId) { + + // Enable multi-threaded execution mode now that there are at least + // two threads + self.multi_threaded.set(true); + let current_thread = self.current_thread_id.get(); + let mut vectors = self.thread_clocks.borrow_mut(); + vectors.ensure_contains_elem(thread, Default::default); + let (current, created) = vectors.pick2_mut(current_thread, thread); + + // Pre increment clocks before atomic operation + current.increment_clock(current_thread); + + // The current thread happens-before the created thread + // so update the created vector clock + created.join_with(current); + + // Post increment clocks after atomic operation + current.increment_clock(current_thread); + created.increment_clock(thread); + } + + /// Hook on a thread join to update the implicit happens-before relation + /// between the joined thead and the current thread + #[inline] + pub fn thread_joined(&self, current_thread: ThreadId, join_thread: ThreadId) { + let mut vectors = self.thread_clocks.borrow_mut(); + let (current, join) = vectors.pick2_mut(current_thread, join_thread); + + // Pre increment clocks before atomic operation + current.increment_clock(current_thread); + join.increment_clock(join_thread); + + // The join thread happens-before the current thread + // so update the current vector clock + current.join_with(join); + + // Post increment clocks after atomic operation + current.increment_clock(current_thread); + join.increment_clock(join_thread); + } + + /// Hook for updating the local tracker of the currently + /// enabled thread, should always be updated whenever + /// `active_thread` in thread.rs is updated + #[inline] + pub fn thread_set_active(&self, thread: ThreadId) { + self.current_thread_id.set(thread); + } + + /// Hook for updating the local tracker of the threads name + /// this should always mirror the local value in thread.rs + /// the thread name is used for improved diagnostics + /// during a data-race + #[inline] + pub fn thread_set_name(&self, name: String) { + let name = name.into_boxed_str(); + let mut names = self.thread_names.borrow_mut(); + let thread = self.current_thread_id.get(); + names.ensure_contains_elem(thread, Default::default); + names[thread] = Some(name); + } + + + /// Advance the vector clock for a thread + /// this is called before and after any atomic/synchronizing operations + /// that may manipulate state + #[inline] + fn advance_vector_clock(&self) { + let thread = self.current_thread_id.get(); + let mut vectors = self.thread_clocks.borrow_mut(); + vectors[thread].increment_clock(thread); + + // Log the increment in the atomic vector clock + log::trace!("Atomic vector clock increase for {:?} to {:?}",thread, vectors[thread].clock); + } + + + /// Internal utility to identify a thread stored internally + /// returns the id and the name for better diagnostics + fn print_thread_metadata(&self, thread: ThreadId) -> String { + if let Some(Some(name)) = self.thread_names.borrow().get(thread) { + let name: &str = name; + format!("Thread(id = {:?}, name = {:?})", thread.to_u32(), &*name) + }else{ + format!("Thread(id = {:?})", thread.to_u32()) + } + } + + + /// Acquire a lock, express that the previous call of + /// `validate_lock_release` must happen before this + pub fn validate_lock_acquire(&self, lock: &DataRaceLockHandle, thread: ThreadId) { + let mut ref_vector = self.thread_clocks.borrow_mut(); + ref_vector[thread].increment_clock(thread); + + let clocks = &mut ref_vector[thread]; + clocks.clock.join(&lock.clock); + + ref_vector[thread].increment_clock(thread); + } + + /// Release a lock handle, express that this happens-before + /// any subsequent calls to `validate_lock_acquire` + pub fn validate_lock_release(&self, lock: &mut DataRaceLockHandle, thread: ThreadId) { + let mut ref_vector = self.thread_clocks.borrow_mut(); + ref_vector[thread].increment_clock(thread); + + let clocks = &ref_vector[thread]; + lock.clock.set_values(&clocks.clock); + + ref_vector[thread].increment_clock(thread); + } + + /// Release a lock handle, express that this happens-before + /// any subsequent calls to `validate_lock_acquire` as well + /// as any previous calls to this function after any + /// `validate_lock_release` calls + pub fn validate_lock_release_shared(&self, lock: &mut DataRaceLockHandle, thread: ThreadId) { + let mut ref_vector = self.thread_clocks.borrow_mut(); + ref_vector[thread].increment_clock(thread); + + let clocks = &ref_vector[thread]; + lock.clock.join(&clocks.clock); + + ref_vector[thread].increment_clock(thread); + } + + /// Load the thread clock set associated with the current thread + #[inline] + fn current_thread_state(&self) -> Ref<'_, ThreadClockSet> { + let ref_vector = self.thread_clocks.borrow(); + let thread = self.current_thread_id.get(); + Ref::map(ref_vector, |vector| &vector[thread]) + } + + /// Load the thread clock set associated with the current thread + /// mutably for modification + #[inline] + fn current_thread_state_mut(&self) -> RefMut<'_, ThreadClockSet> { + let ref_vector = self.thread_clocks.borrow_mut(); + let thread = self.current_thread_id.get(); + RefMut::map(ref_vector, |vector| &mut vector[thread]) + } + + /// Return the current thread, should be the same + /// as the data-race active thread + #[inline] + fn current_thread(&self) -> ThreadId { + self.current_thread_id.get() + } +} + + +/// The size of the vector-clock to store inline +/// clock vectors larger than this will be stored on the heap +const SMALL_VECTOR: usize = 4; + +/// The type of the time-stamps recorded in the data-race detector +/// set to a type of unsigned integer +type Timestamp = u32; + +/// A vector clock for detecting data-races +/// invariants: +/// - the last element in a VClock must not be 0 +/// -- this means that derive(PartialEq & Eq) is correct +/// -- as there is no implicit zero tail that might be equal +/// -- also simplifies the implementation of PartialOrd +#[derive(Clone, PartialEq, Eq, Default, Debug)] +pub struct VClock(SmallVec<[Timestamp; SMALL_VECTOR]>); + +impl VClock { + + /// Load the backing slice behind the clock vector. + #[inline] + fn as_slice(&self) -> &[Timestamp] { + self.0.as_slice() + } + + /// Get a mutable slice to the internal vector with minimum `min_len` + /// elements, to preserve invariants this vector must modify + /// the `min_len`-1 nth element to a non-zero value + #[inline] + fn get_mut_with_min_len(&mut self, min_len: usize) -> &mut [Timestamp] { + if self.0.len() < min_len { + self.0.resize(min_len, 0); + } + assert!(self.0.len() >= min_len); + self.0.as_mut_slice() + } + + /// Increment the vector clock at a known index + #[inline] + fn increment_index(&mut self, idx: usize) { + let mut_slice = self.get_mut_with_min_len(idx + 1); + let idx_ref = &mut mut_slice[idx]; + *idx_ref = idx_ref.checked_add(1).expect("Vector clock overflow") + } + + // Increment the vector element representing the progress + // of execution in the given thread + #[inline] + pub fn increment_thread(&mut self, thread: ThreadId) { + self.increment_index(thread.to_u32() as usize); + } + + // Join the two vector-clocks together, this + // sets each vector-element to the maximum value + // of that element in either of the two source elements. + pub fn join(&mut self, other: &Self) { + let rhs_slice = other.as_slice(); + let lhs_slice = self.get_mut_with_min_len(rhs_slice.len()); + + // Element-wise set to maximum. + for (l, &r) in lhs_slice.iter_mut().zip(rhs_slice.iter()) { + *l = r.max(*l); + } + } + + /// Joins with a thread at a known index + fn set_at_index(&mut self, other: &Self, idx: usize){ + let mut_slice = self.get_mut_with_min_len(idx + 1); + let slice = other.as_slice(); + mut_slice[idx] = slice[idx]; + } + + /// Join with a threads vector clock only at the desired index + /// returns true if the value updated + #[inline] + pub fn set_at_thread(&mut self, other: &Self, thread: ThreadId){ + self.set_at_index(other, thread.to_u32() as usize); + } + + /// Clear the vector to all zeros, stored as an empty internal + /// vector + #[inline] + pub fn set_zero_vector(&mut self) { + self.0.clear(); + } + + /// Set the values stored in this vector clock + /// to the values stored in another. + pub fn set_values(&mut self, new_value: &VClock) { + let new_slice = new_value.as_slice(); + self.0.resize(new_slice.len(), 0); + self.0.copy_from_slice(new_slice); + } +} + + +impl PartialOrd for VClock { + fn partial_cmp(&self, other: &VClock) -> Option { + + // Load the values as slices + let lhs_slice = self.as_slice(); + let rhs_slice = other.as_slice(); + + // Iterate through the combined vector slice + // keeping track of the order that is currently possible to satisfy. + // If an ordering relation is detected to be impossible, then bail and + // directly return None + let mut iter = lhs_slice.iter().zip(rhs_slice.iter()); + let mut order = match iter.next() { + Some((lhs, rhs)) => lhs.cmp(rhs), + None => Ordering::Equal + }; + for (l, r) in iter { + match order { + Ordering::Equal => order = l.cmp(r), + Ordering::Less => if l > r { + return None + }, + Ordering::Greater => if l < r { + return None + } + } + } + + //Now test if either left or right have trailing elements + // by the invariant the trailing elements have at least 1 + // non zero value, so no additional calculation is required + // to determine the result of the PartialOrder + let l_len = lhs_slice.len(); + let r_len = rhs_slice.len(); + match l_len.cmp(&r_len) { + // Equal has no additional elements: return current order + Ordering::Equal => Some(order), + // Right has at least 1 element > than the implicit 0, + // so the only valid values are Ordering::Less or None + Ordering::Less => match order { + Ordering::Less | Ordering::Equal => Some(Ordering::Less), + Ordering::Greater => None + } + // Left has at least 1 element > than the implicit 0, + // so the only valid values are Ordering::Greater or None + Ordering::Greater => match order { + Ordering::Greater | Ordering::Equal => Some(Ordering::Greater), + Ordering::Less => None + } + } + } + + fn lt(&self, other: &VClock) -> bool { + // Load the values as slices + let lhs_slice = self.as_slice(); + let rhs_slice = other.as_slice(); + + // If l_len > r_len then at least one element + // in l_len is > than r_len, therefore the result + // is either Some(Greater) or None, so return false + // early. + let l_len = lhs_slice.len(); + let r_len = rhs_slice.len(); + if l_len <= r_len { + // If any elements on the left are greater than the right + // then the result is None or Some(Greater), both of which + // return false, the earlier test asserts that no elements in the + // extended tail violate this assumption. Otherwise l <= r, finally + // the case where the values are potentially equal needs to be considered + // and false returned as well + let mut equal = l_len == r_len; + for (&l, &r) in lhs_slice.iter().zip(rhs_slice.iter()) { + if l > r { + return false + }else if l < r { + equal = false; + } + } + !equal + }else{ + false + } + } + + fn le(&self, other: &VClock) -> bool { + // Load the values as slices + let lhs_slice = self.as_slice(); + let rhs_slice = other.as_slice(); + + // If l_len > r_len then at least one element + // in l_len is > than r_len, therefore the result + // is either Some(Greater) or None, so return false + // early. + let l_len = lhs_slice.len(); + let r_len = rhs_slice.len(); + if l_len <= r_len { + // If any elements on the left are greater than the right + // then the result is None or Some(Greater), both of which + // return false, the earlier test asserts that no elements in the + // extended tail violate this assumption. Otherwise l <= r + !lhs_slice.iter().zip(rhs_slice.iter()).any(|(&l, &r)| l > r) + }else{ + false + } + } + + fn gt(&self, other: &VClock) -> bool { + // Load the values as slices + let lhs_slice = self.as_slice(); + let rhs_slice = other.as_slice(); + + // If r_len > l_len then at least one element + // in r_len is > than l_len, therefore the result + // is either Some(Less) or None, so return false + // early. + let l_len = lhs_slice.len(); + let r_len = rhs_slice.len(); + if l_len >= r_len { + // If any elements on the left are less than the right + // then the result is None or Some(Less), both of which + // return false, the earlier test asserts that no elements in the + // extended tail violate this assumption. Otherwise l >=, finally + // the case where the values are potentially equal needs to be considered + // and false returned as well + let mut equal = l_len == r_len; + for (&l, &r) in lhs_slice.iter().zip(rhs_slice.iter()) { + if l < r { + return false + }else if l > r { + equal = false; + } + } + !equal + }else{ + false + } + } + + fn ge(&self, other: &VClock) -> bool { + // Load the values as slices + let lhs_slice = self.as_slice(); + let rhs_slice = other.as_slice(); + + // If r_len > l_len then at least one element + // in r_len is > than l_len, therefore the result + // is either Some(Less) or None, so return false + // early. + let l_len = lhs_slice.len(); + let r_len = rhs_slice.len(); + if l_len >= r_len { + // If any elements on the left are less than the right + // then the result is None or Some(Less), both of which + // return false, the earlier test asserts that no elements in the + // extended tail violate this assumption. Otherwise l >= r + !lhs_slice.iter().zip(rhs_slice.iter()).any(|(&l, &r)| l < r) + }else{ + false + } + } +} + +impl Index for VClock { + type Output = Timestamp; + + #[inline] + fn index(&self, index: ThreadId) -> &Timestamp { + self.as_slice().get(index.to_u32() as usize).unwrap_or(&0) + } +} + + +/// Test vector clock ordering operations +/// data-race detection is tested in the external +/// test suite +#[cfg(test)] +mod tests { + use super::{VClock, Timestamp}; + use std::cmp::Ordering; + + #[test] + fn test_equal() { + let mut c1 = VClock::default(); + let mut c2 = VClock::default(); + assert_eq!(c1, c2); + c1.increment_index(5); + assert_ne!(c1, c2); + c2.increment_index(53); + assert_ne!(c1, c2); + c1.increment_index(53); + assert_ne!(c1, c2); + c2.increment_index(5); + assert_eq!(c1, c2); + } + + #[test] + fn test_partial_order() { + // Small test + assert_order(&[1], &[1], Some(Ordering::Equal)); + assert_order(&[1], &[2], Some(Ordering::Less)); + assert_order(&[2], &[1], Some(Ordering::Greater)); + assert_order(&[1], &[1,2], Some(Ordering::Less)); + assert_order(&[2], &[1,2], None); + + // Misc tests + assert_order(&[400], &[0, 1], None); + + // Large test + assert_order(&[0,1,2,3,4,5,6,7,8,9,10], &[0,1,2,3,4,5,6,7,8,9,10,0,0,0], Some(Ordering::Equal)); + assert_order(&[0,1,2,3,4,5,6,7,8,9,10], &[0,1,2,3,4,5,6,7,8,9,10,0,1,0], Some(Ordering::Less)); + assert_order(&[0,1,2,3,4,5,6,7,8,9,11], &[0,1,2,3,4,5,6,7,8,9,10,0,0,0], Some(Ordering::Greater)); + assert_order(&[0,1,2,3,4,5,6,7,8,9,11], &[0,1,2,3,4,5,6,7,8,9,10,0,1,0], None); + assert_order(&[0,1,2,3,4,5,6,7,8,9,9 ], &[0,1,2,3,4,5,6,7,8,9,10,0,0,0], Some(Ordering::Less)); + assert_order(&[0,1,2,3,4,5,6,7,8,9,9 ], &[0,1,2,3,4,5,6,7,8,9,10,0,1,0], Some(Ordering::Less)); + } + + fn from_slice(mut slice: &[Timestamp]) -> VClock { + while let Some(0) = slice.last() { + slice = &slice[..slice.len() - 1] + } + VClock(smallvec::SmallVec::from_slice(slice)) + } + + fn assert_order(l: &[Timestamp], r: &[Timestamp], o: Option) { + let l = from_slice(l); + let r = from_slice(r); + + //Test partial_cmp + let compare = l.partial_cmp(&r); + assert_eq!(compare, o, "Invalid comparison\n l: {:?}\n r: {:?}",l,r); + let alt_compare = r.partial_cmp(&l); + assert_eq!(alt_compare, o.map(Ordering::reverse), "Invalid alt comparison\n l: {:?}\n r: {:?}",l,r); + + //Test operatorsm with faster implementations + assert_eq!( + matches!(compare,Some(Ordering::Less)), l < r, + "Invalid (<):\n l: {:?}\n r: {:?}",l,r + ); + assert_eq!( + matches!(compare,Some(Ordering::Less) | Some(Ordering::Equal)), l <= r, + "Invalid (<=):\n l: {:?}\n r: {:?}",l,r + ); + assert_eq!( + matches!(compare,Some(Ordering::Greater)), l > r, + "Invalid (>):\n l: {:?}\n r: {:?}",l,r + ); + assert_eq!( + matches!(compare,Some(Ordering::Greater) | Some(Ordering::Equal)), l >= r, + "Invalid (>=):\n l: {:?}\n r: {:?}",l,r + ); + assert_eq!( + matches!(alt_compare,Some(Ordering::Less)), r < l, + "Invalid alt (<):\n l: {:?}\n r: {:?}",l,r + ); + assert_eq!( + matches!(alt_compare,Some(Ordering::Less) | Some(Ordering::Equal)), r <= l, + "Invalid alt (<=):\n l: {:?}\n r: {:?}",l,r + ); + assert_eq!( + matches!(alt_compare,Some(Ordering::Greater)), r > l, + "Invalid alt (>):\n l: {:?}\n r: {:?}",l,r + ); + assert_eq!( + matches!(alt_compare,Some(Ordering::Greater) | Some(Ordering::Equal)), r >= l, + "Invalid alt (>=):\n l: {:?}\n r: {:?}",l,r + ); + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index d4802f3b11fa..f384787e4c68 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,6 +22,7 @@ extern crate rustc_mir; extern crate rustc_span; extern crate rustc_target; +mod data_race; mod diagnostics; mod eval; mod helpers; @@ -52,6 +53,10 @@ pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _}; pub use crate::shims::tls::{EvalContextExt as _, TlsData}; pub use crate::shims::EvalContextExt as _; +pub use crate::data_race::{ + AtomicReadOp, AtomicWriteOp, AtomicRWOp, AtomicFenceOp, DataRaceLockHandle, + EvalContextExt as DataRaceEvalContextExt +}; pub use crate::diagnostics::{ register_diagnostic, report_error, EvalContextExt as DiagnosticsEvalContextExt, TerminationInfo, NonHaltingDiagnostic, diff --git a/src/machine.rs b/src/machine.rs index e9f9298e566c..363513f636c9 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -109,12 +109,15 @@ impl fmt::Display for MiriMemoryKind { pub struct AllocExtra { /// Stacked Borrows state is only added if it is enabled. pub stacked_borrows: Option, + /// Data race detection via the use of a vector-clock. + pub data_race: data_race::AllocExtra, } /// Extra global memory data #[derive(Clone, Debug)] pub struct MemoryExtra { pub stacked_borrows: Option, + pub data_race: data_race::MemoryExtra, pub intptrcast: intptrcast::MemoryExtra, /// Mapping extern static names to their canonical allocation. @@ -144,8 +147,10 @@ impl MemoryExtra { } else { None }; + let data_race = Rc::new(data_race::GlobalState::new()); MemoryExtra { stacked_borrows, + data_race, intptrcast: Default::default(), extern_statics: FxHashMap::default(), rng: RefCell::new(rng), @@ -467,6 +472,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { // No stacks, no tag. (None, Tag::Untagged) }; + let race_alloc = data_race::AllocExtra::new_allocation(&memory_extra.data_race, alloc.size); let mut stacked_borrows = memory_extra.stacked_borrows.as_ref().map(|sb| sb.borrow_mut()); let alloc: Allocation = alloc.with_tags_and_extra( |alloc| { @@ -478,7 +484,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { Tag::Untagged } }, - AllocExtra { stacked_borrows: stacks }, + AllocExtra { stacked_borrows: stacks, data_race: race_alloc }, ); (Cow::Owned(alloc), base_tag) } @@ -584,6 +590,7 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { + alloc.extra.data_race.read(ptr, size)?; if let Some(stacked_borrows) = &alloc.extra.stacked_borrows { stacked_borrows.memory_read(ptr, size) } else { @@ -597,6 +604,7 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { + alloc.extra.data_race.write(ptr, size)?; if let Some(stacked_borrows) = &mut alloc.extra.stacked_borrows { stacked_borrows.memory_written(ptr, size) } else { @@ -610,6 +618,7 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { + alloc.extra.data_race.deallocate(ptr, size)?; if let Some(stacked_borrows) = &mut alloc.extra.stacked_borrows { stacked_borrows.memory_deallocated(ptr, size) } else { diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index b401bd8adaee..2bb15e712c5f 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -4,7 +4,7 @@ use log::trace; use rustc_attr as attr; use rustc_ast::ast::FloatTy; -use rustc_middle::{mir, ty}; +use rustc_middle::{mir, mir::BinOp, ty}; use rustc_middle::ty::layout::IntegerExt; use rustc_apfloat::{Float, Round}; use rustc_target::abi::{Align, Integer, LayoutOf}; @@ -306,157 +306,117 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Atomic operations - #[rustfmt::skip] - | "atomic_load" - | "atomic_load_relaxed" - | "atomic_load_acq" - => { - let &[place] = check_arg_count(args)?; - let place = this.deref_operand(place)?; - let val = this.read_scalar(place.into())?; // make sure it fits into a scalar; otherwise it cannot be atomic + "atomic_load" => this.atomic_load(args, dest, AtomicReadOp::SeqCst)?, + "atomic_load_relaxed" => this.atomic_load(args, dest, AtomicReadOp::Relaxed)?, + "atomic_load_acq" => this.atomic_load(args, dest, AtomicReadOp::Acquire)?, - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + "atomic_store" => this.atomic_store(args, AtomicWriteOp::SeqCst)?, + "atomic_store_relaxed" => this.atomic_store(args, AtomicWriteOp::Relaxed)?, + "atomic_store_rel" => this.atomic_store(args, AtomicWriteOp::Release)?, - this.write_scalar(val, dest)?; - } + "atomic_fence_acq" => this.atomic_fence(args, AtomicFenceOp::Acquire)?, + "atomic_fence_rel" => this.atomic_fence(args, AtomicFenceOp::Release)?, + "atomic_fence_acqrel" => this.atomic_fence(args, AtomicFenceOp::AcqRel)?, + "atomic_fence" => this.atomic_fence(args, AtomicFenceOp::SeqCst)?, - #[rustfmt::skip] - | "atomic_store" - | "atomic_store_relaxed" - | "atomic_store_rel" - => { - let &[place, val] = check_arg_count(args)?; - let place = this.deref_operand(place)?; - let val = this.read_scalar(val)?; // make sure it fits into a scalar; otherwise it cannot be atomic + "atomic_singlethreadfence_acq" => this.compiler_fence(args, AtomicFenceOp::Acquire)?, + "atomic_singlethreadfence_rel" => this.compiler_fence(args, AtomicFenceOp::Release)?, + "atomic_singlethreadfence_acqrel" => this.compiler_fence(args, AtomicFenceOp::AcqRel)?, + "atomic_singlethreadfence" => this.compiler_fence(args, AtomicFenceOp::SeqCst)?, - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + "atomic_xchg" => this.atomic_exchange(args, dest, AtomicRWOp::SeqCst)?, + "atomic_xchg_acq" => this.atomic_exchange(args, dest, AtomicRWOp::Acquire)?, + "atomic_xchg_rel" => this.atomic_exchange(args, dest, AtomicRWOp::Release)?, + "atomic_xchg_acqrel" => this.atomic_exchange(args, dest, AtomicRWOp::AcqRel)?, + "atomic_xchg_relaxed" => this.atomic_exchange(args, dest, AtomicRWOp::Relaxed)?, - this.write_scalar(val, place.into())?; - } + "atomic_cxchg" => this.atomic_compare_exchange( + args, dest, AtomicRWOp::SeqCst, AtomicReadOp::SeqCst + )?, + "atomic_cxchg_acq" => this.atomic_compare_exchange( + args, dest, AtomicRWOp::Acquire, AtomicReadOp::Acquire + )?, + "atomic_cxchg_rel" => this.atomic_compare_exchange( + args, dest, AtomicRWOp::Release, AtomicReadOp::Relaxed + )?, + "atomic_cxchg_acqrel" => this.atomic_compare_exchange + (args, dest, AtomicRWOp::AcqRel, AtomicReadOp::Acquire + )?, + "atomic_cxchg_relaxed" => this.atomic_compare_exchange( + args, dest, AtomicRWOp::Relaxed, AtomicReadOp::Relaxed + )?, + "atomic_cxchg_acq_failrelaxed" => this.atomic_compare_exchange( + args, dest, AtomicRWOp::Acquire, AtomicReadOp::Relaxed + )?, + "atomic_cxchg_acqrel_failrelaxed" => this.atomic_compare_exchange( + args, dest, AtomicRWOp::AcqRel, AtomicReadOp::Relaxed + )?, + "atomic_cxchg_failrelaxed" => this.atomic_compare_exchange( + args, dest, AtomicRWOp::SeqCst, AtomicReadOp::Relaxed + )?, + "atomic_cxchg_failacq" => this.atomic_compare_exchange( + args, dest, AtomicRWOp::SeqCst, AtomicReadOp::Acquire + )?, - #[rustfmt::skip] - | "atomic_fence_acq" - | "atomic_fence_rel" - | "atomic_fence_acqrel" - | "atomic_fence" - | "atomic_singlethreadfence_acq" - | "atomic_singlethreadfence_rel" - | "atomic_singlethreadfence_acqrel" - | "atomic_singlethreadfence" - => { - let &[] = check_arg_count(args)?; - // FIXME: this will become relevant once we try to detect data races. - } + "atomic_cxchgweak" => this.atomic_compare_exchange_weak( + args, dest, AtomicRWOp::SeqCst, AtomicReadOp::SeqCst + )?, + "atomic_cxchgweak_acq" => this.atomic_compare_exchange_weak( + args, dest, AtomicRWOp::Acquire, AtomicReadOp::Acquire + )?, + "atomic_cxchgweak_rel" => this.atomic_compare_exchange_weak( + args, dest, AtomicRWOp::Release, AtomicReadOp::Relaxed + )?, + "atomic_cxchgweak_acqrel" => this.atomic_compare_exchange_weak( + args, dest, AtomicRWOp::AcqRel, AtomicReadOp::Acquire + )?, + "atomic_cxchgweak_relaxed" => this.atomic_compare_exchange_weak( + args, dest, AtomicRWOp::Relaxed, AtomicReadOp::Relaxed + )?, + "atomic_cxchgweak_acq_failrelaxed" => this.atomic_compare_exchange_weak( + args, dest, AtomicRWOp::Acquire, AtomicReadOp::Relaxed + )?, + "atomic_cxchgweak_acqrel_failrelaxed" => this.atomic_compare_exchange_weak( + args, dest, AtomicRWOp::AcqRel, AtomicReadOp::Relaxed + )?, + "atomic_cxchgweak_failrelaxed" => this.atomic_compare_exchange_weak( + args, dest, AtomicRWOp::SeqCst, AtomicReadOp::Relaxed + )?, + "atomic_cxchgweak_failacq" => this.atomic_compare_exchange_weak( + args, dest, AtomicRWOp::SeqCst, AtomicReadOp::Acquire + )?, - _ if intrinsic_name.starts_with("atomic_xchg") => { - let &[place, new] = check_arg_count(args)?; - let place = this.deref_operand(place)?; - let new = this.read_scalar(new)?; - let old = this.read_scalar(place.into())?; + "atomic_or" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRWOp::SeqCst)?, + "atomic_or_acq" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRWOp::Acquire)?, + "atomic_or_rel" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRWOp::Release)?, + "atomic_or_acqrel" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRWOp::AcqRel)?, + "atomic_or_relaxed" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRWOp::Relaxed)?, + "atomic_xor" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRWOp::SeqCst)?, + "atomic_xor_acq" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRWOp::Acquire)?, + "atomic_xor_rel" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRWOp::Release)?, + "atomic_xor_acqrel" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRWOp::AcqRel)?, + "atomic_xor_relaxed" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRWOp::Relaxed)?, + "atomic_and" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRWOp::SeqCst)?, + "atomic_and_acq" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRWOp::Acquire)?, + "atomic_and_rel" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRWOp::Release)?, + "atomic_and_acqrel" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRWOp::AcqRel)?, + "atomic_and_relaxed" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRWOp::Relaxed)?, + "atomic_nand" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRWOp::SeqCst)?, + "atomic_nand_acq" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRWOp::Acquire)?, + "atomic_nand_rel" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRWOp::Release)?, + "atomic_nand_acqrel" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRWOp::AcqRel)?, + "atomic_nand_relaxed" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRWOp::Relaxed)?, + "atomic_xadd" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRWOp::SeqCst)?, + "atomic_xadd_acq" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRWOp::Acquire)?, + "atomic_xadd_rel" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRWOp::Release)?, + "atomic_xadd_acqrel" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRWOp::AcqRel)?, + "atomic_xadd_relaxed" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRWOp::Relaxed)?, + "atomic_xsub" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRWOp::SeqCst)?, + "atomic_xsub_acq" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRWOp::Acquire)?, + "atomic_xsub_rel" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRWOp::Release)?, + "atomic_xsub_acqrel" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRWOp::AcqRel)?, + "atomic_xsub_relaxed" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRWOp::Relaxed)?, - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; - - this.write_scalar(old, dest)?; // old value is returned - this.write_scalar(new, place.into())?; - } - - _ if intrinsic_name.starts_with("atomic_cxchg") => { - let &[place, expect_old, new] = check_arg_count(args)?; - let place = this.deref_operand(place)?; - let expect_old = this.read_immediate(expect_old)?; // read as immediate for the sake of `binary_op()` - let new = this.read_scalar(new)?; - let old = this.read_immediate(place.into())?; // read as immediate for the sake of `binary_op()` - - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; - - // `binary_op` will bail if either of them is not a scalar. - let eq = this.overflowing_binary_op(mir::BinOp::Eq, old, expect_old)?.0; - let res = Immediate::ScalarPair(old.to_scalar_or_uninit(), eq.into()); - // Return old value. - this.write_immediate(res, dest)?; - // Update ptr depending on comparison. - if eq.to_bool()? { - this.write_scalar(new, place.into())?; - } - } - - #[rustfmt::skip] - | "atomic_or" - | "atomic_or_acq" - | "atomic_or_rel" - | "atomic_or_acqrel" - | "atomic_or_relaxed" - | "atomic_xor" - | "atomic_xor_acq" - | "atomic_xor_rel" - | "atomic_xor_acqrel" - | "atomic_xor_relaxed" - | "atomic_and" - | "atomic_and_acq" - | "atomic_and_rel" - | "atomic_and_acqrel" - | "atomic_and_relaxed" - | "atomic_nand" - | "atomic_nand_acq" - | "atomic_nand_rel" - | "atomic_nand_acqrel" - | "atomic_nand_relaxed" - | "atomic_xadd" - | "atomic_xadd_acq" - | "atomic_xadd_rel" - | "atomic_xadd_acqrel" - | "atomic_xadd_relaxed" - | "atomic_xsub" - | "atomic_xsub_acq" - | "atomic_xsub_rel" - | "atomic_xsub_acqrel" - | "atomic_xsub_relaxed" - => { - let &[place, rhs] = check_arg_count(args)?; - let place = this.deref_operand(place)?; - if !place.layout.ty.is_integral() { - bug!("Atomic arithmetic operations only work on integer types"); - } - let rhs = this.read_immediate(rhs)?; - let old = this.read_immediate(place.into())?; - - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; - - this.write_immediate(*old, dest)?; // old value is returned - let (op, neg) = match intrinsic_name.split('_').nth(1).unwrap() { - "or" => (mir::BinOp::BitOr, false), - "xor" => (mir::BinOp::BitXor, false), - "and" => (mir::BinOp::BitAnd, false), - "xadd" => (mir::BinOp::Add, false), - "xsub" => (mir::BinOp::Sub, false), - "nand" => (mir::BinOp::BitAnd, true), - _ => bug!(), - }; - // Atomics wrap around on overflow. - let val = this.binary_op(op, old, rhs)?; - let val = if neg { this.unary_op(mir::UnOp::Not, val)? } else { val }; - this.write_immediate(*val, place.into())?; - } // Query type information "assert_inhabited" | @@ -498,6 +458,169 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } + fn atomic_load( + &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, + atomic: AtomicReadOp + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + + let &[place] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + + // make sure it fits into a scalar; otherwise it cannot be atomic + let val = this.read_scalar_racy(place)?; + this.validate_atomic_load(place, atomic)?; + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + this.write_scalar(val, dest)?; + Ok(()) + } + + fn atomic_store(&mut self, args: &[OpTy<'tcx, Tag>], atomic: AtomicWriteOp) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let &[place, val] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + let val = this.read_scalar(val)?; // make sure it fits into a scalar; otherwise it cannot be atomic + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + + // Perform atomic store + this.write_scalar_racy(val, place)?; + + this.validate_atomic_store(place, atomic)?; + Ok(()) + } + + fn compiler_fence(&mut self, args: &[OpTy<'tcx, Tag>], atomic: AtomicFenceOp) -> InterpResult<'tcx> { + let &[] = check_arg_count(args)?; + let _ = atomic; + //FIXME: compiler fences are currently ignored + Ok(()) + } + + fn atomic_fence(&mut self, args: &[OpTy<'tcx, Tag>], atomic: AtomicFenceOp) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let &[] = check_arg_count(args)?; + this.validate_atomic_fence(atomic)?; + Ok(()) + } + + fn atomic_op( + &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, + op: mir::BinOp, neg: bool, atomic: AtomicRWOp + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let &[place, rhs] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + if !place.layout.ty.is_integral() { + bug!("Atomic arithmetic operations only work on integer types"); + } + let rhs = this.read_immediate(rhs)?; + let old = this.read_immediate_racy(place)?; + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + this.write_immediate(*old, dest)?; // old value is returned + + // Atomics wrap around on overflow. + let val = this.binary_op(op, old, rhs)?; + let val = if neg { this.unary_op(mir::UnOp::Not, val)? } else { val }; + this.write_immediate_racy(*val, place)?; + + this.validate_atomic_rmw(place, atomic)?; + Ok(()) + } + + fn atomic_exchange( + &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, atomic: AtomicRWOp + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let &[place, new] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + let new = this.read_scalar(new)?; + let old = this.read_scalar_racy(place)?; + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + + this.write_scalar(old, dest)?; // old value is returned + this.write_scalar_racy(new, place)?; + + this.validate_atomic_rmw(place, atomic)?; + Ok(()) + } + + fn atomic_compare_exchange( + &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, + success: AtomicRWOp, fail: AtomicReadOp + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let &[place, expect_old, new] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + let expect_old = this.read_immediate(expect_old)?; // read as immediate for the sake of `binary_op()` + let new = this.read_scalar(new)?; + + // Failure ordering cannot be stronger than success ordering, therefore first attempt + // to read with the failure ordering and if successfull then try again with the success + // read ordering and write in the success case. + // Read as immediate for the sake of `binary_op()` + let old = this.read_immediate_racy(place)?; + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + + // `binary_op` will bail if either of them is not a scalar. + let eq = this.overflowing_binary_op(mir::BinOp::Eq, old, expect_old)?.0; + let res = Immediate::ScalarPair(old.to_scalar_or_uninit(), eq.into()); + + // Return old value. + this.write_immediate(res, dest)?; + + // Update ptr depending on comparison. + // if successful, perform a full rw-atomic validation + // otherwise treat this as an atomic load with the fail ordering + if eq.to_bool()? { + this.write_scalar_racy(new, place)?; + this.validate_atomic_rmw(place, success)?; + } else { + this.validate_atomic_load(place, fail)?; + } + + Ok(()) + } + + fn atomic_compare_exchange_weak( + &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, + success: AtomicRWOp, fail: AtomicReadOp + ) -> InterpResult<'tcx> { + + // FIXME: the weak part of this is currently not modelled, + // it is assumed to always succeed unconditionally. + self.atomic_compare_exchange(args, dest, success, fail) + } + fn float_to_int_unchecked( &self, f: F, diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index a0b5db42ed06..332e79071a0a 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -62,7 +62,7 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>( mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - ecx.read_scalar_at_offset(mutex_op, offset, ecx.machine.layouts.i32) + ecx.read_scalar_at_offset_racy(mutex_op, offset, ecx.machine.layouts.i32) } fn mutex_set_kind<'mir, 'tcx: 'mir>( @@ -71,14 +71,14 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( kind: impl Into>, ) -> InterpResult<'tcx, ()> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - ecx.write_scalar_at_offset(mutex_op, offset, kind, ecx.machine.layouts.i32) + ecx.write_scalar_at_offset_racy(mutex_op, offset, kind, ecx.machine.layouts.i32) } fn mutex_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - ecx.read_scalar_at_offset(mutex_op, 4, ecx.machine.layouts.u32) + ecx.read_scalar_at_offset_racy(mutex_op, 4, ecx.machine.layouts.u32) } fn mutex_set_id<'mir, 'tcx: 'mir>( @@ -86,7 +86,7 @@ fn mutex_set_id<'mir, 'tcx: 'mir>( mutex_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { - ecx.write_scalar_at_offset(mutex_op, 4, id, ecx.machine.layouts.u32) + ecx.write_scalar_at_offset_racy(mutex_op, 4, id, ecx.machine.layouts.u32) } fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( @@ -116,7 +116,7 @@ fn rwlock_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - ecx.read_scalar_at_offset(rwlock_op, 4, ecx.machine.layouts.u32) + ecx.read_scalar_at_offset_racy(rwlock_op, 4, ecx.machine.layouts.u32) } fn rwlock_set_id<'mir, 'tcx: 'mir>( @@ -124,7 +124,7 @@ fn rwlock_set_id<'mir, 'tcx: 'mir>( rwlock_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { - ecx.write_scalar_at_offset(rwlock_op, 4, id, ecx.machine.layouts.u32) + ecx.write_scalar_at_offset_racy(rwlock_op, 4, id, ecx.machine.layouts.u32) } fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( @@ -177,7 +177,7 @@ fn cond_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, cond_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - ecx.read_scalar_at_offset(cond_op, 4, ecx.machine.layouts.u32) + ecx.read_scalar_at_offset_racy(cond_op, 4, ecx.machine.layouts.u32) } fn cond_set_id<'mir, 'tcx: 'mir>( @@ -185,7 +185,7 @@ fn cond_set_id<'mir, 'tcx: 'mir>( cond_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { - ecx.write_scalar_at_offset(cond_op, 4, id, ecx.machine.layouts.u32) + ecx.write_scalar_at_offset_racy(cond_op, 4, id, ecx.machine.layouts.u32) } fn cond_get_or_create_id<'mir, 'tcx: 'mir>( diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index 7c9c489e6fb4..e420457765b2 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -19,21 +19,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx For example, Miri does not detect data races yet.", ); + // Create the new thread let new_thread_id = this.create_thread(); - // Also switch to new thread so that we can push the first stackframe. - let old_thread_id = this.set_active_thread(new_thread_id); + // Write the current thread-id, switch to the next thread later + // to treat this write operation as occuring on this thread index let thread_info_place = this.deref_operand(thread)?; this.write_scalar( Scalar::from_uint(new_thread_id.to_u32(), thread_info_place.layout.size), thread_info_place.into(), )?; + // Read the function argument that will be sent to the new thread + // again perform the read before the thread starts executing. let fn_ptr = this.read_scalar(start_routine)?.check_init()?; - let instance = this.memory.get_fn(fn_ptr)?.as_instance()?; - let func_arg = this.read_immediate(arg)?; + // Also switch to new thread so that we can push the first stackframe. + // after this all accesses will be treated as occuring in the new thread + let old_thread_id = this.set_active_thread(new_thread_id); + + // Perform the function pointer load in the new thread frame + let instance = this.memory.get_fn(fn_ptr)?.as_instance()?; + // Note: the returned value is currently ignored (see the FIXME in // pthread_join below) because the Rust standard library does not use // it. @@ -47,6 +55,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx StackPopCleanup::None { cleanup: true }, )?; + // Restore the old active thread frame this.set_active_thread(old_thread_id); Ok(0) diff --git a/src/sync.rs b/src/sync.rs index 0c12da8d6845..3469afdcd276 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -61,6 +61,8 @@ struct Mutex { lock_count: usize, /// The queue of threads waiting for this mutex. queue: VecDeque, + /// Data race handle + data_race: DataRaceLockHandle } declare_id!(RwLockId); @@ -77,6 +79,10 @@ struct RwLock { writer_queue: VecDeque, /// The queue of reader threads waiting for this lock. reader_queue: VecDeque, + /// Data race handle for writers + data_race: DataRaceLockHandle, + /// Data race handle for readers + data_race_reader: DataRaceLockHandle, } declare_id!(CondvarId); @@ -94,12 +100,14 @@ struct CondvarWaiter { #[derive(Default, Debug)] struct Condvar { waiters: VecDeque, + data_race: DataRaceLockHandle, } /// The futex state. #[derive(Default, Debug)] struct Futex { waiters: VecDeque, + data_race: DataRaceLockHandle, } /// A thread waiting on a futex. @@ -205,6 +213,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex.owner = Some(thread); } mutex.lock_count = mutex.lock_count.checked_add(1).unwrap(); + this.memory.extra.data_race.validate_lock_acquire(&mutex.data_race, thread); } /// Try unlocking by decreasing the lock count and returning the old lock @@ -232,6 +241,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex.owner = None; // The mutex is completely unlocked. Try transfering ownership // to another thread. + this.memory.extra.data_race.validate_lock_release(&mut mutex.data_race, current_owner); this.mutex_dequeue_and_lock(id); } Some(old_lock_count) @@ -284,15 +294,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); assert!(!this.rwlock_is_write_locked(id), "the lock is write locked"); trace!("rwlock_reader_lock: {:?} now also held (one more time) by {:?}", id, reader); - let count = this.machine.threads.sync.rwlocks[id].readers.entry(reader).or_insert(0); + let rwlock = &mut this.machine.threads.sync.rwlocks[id]; + let count = rwlock.readers.entry(reader).or_insert(0); *count = count.checked_add(1).expect("the reader counter overflowed"); + this.memory.extra.data_race.validate_lock_acquire(&rwlock.data_race, reader); } /// Try read-unlock the lock for `reader` and potentially give the lock to a new owner. /// Returns `true` if succeeded, `false` if this `reader` did not hold the lock. fn rwlock_reader_unlock(&mut self, id: RwLockId, reader: ThreadId) -> bool { let this = self.eval_context_mut(); - match this.machine.threads.sync.rwlocks[id].readers.entry(reader) { + let rwlock = &mut this.machine.threads.sync.rwlocks[id]; + match rwlock.readers.entry(reader) { Entry::Occupied(mut entry) => { let count = entry.get_mut(); assert!(*count > 0, "rwlock locked with count == 0"); @@ -306,8 +319,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Entry::Vacant(_) => return false, // we did not even own this lock } + this.memory.extra.data_race.validate_lock_release_shared(&mut rwlock.data_race_reader, reader); + // The thread was a reader. If the lock is not held any more, give it to a writer. if this.rwlock_is_locked(id).not() { + + // All the readers are finished, so set the writer data-race handle to the value + // of the union of all reader data race handles, since the set of readers + // happen-before the writers + let rwlock = &mut this.machine.threads.sync.rwlocks[id]; + rwlock.data_race.set_values(&rwlock.data_race_reader); this.rwlock_dequeue_and_lock_writer(id); } true @@ -332,7 +353,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); assert!(!this.rwlock_is_locked(id), "the rwlock is already locked"); trace!("rwlock_writer_lock: {:?} now held by {:?}", id, writer); - this.machine.threads.sync.rwlocks[id].writer = Some(writer); + let rwlock = &mut this.machine.threads.sync.rwlocks[id]; + rwlock.writer = Some(writer); + this.memory.extra.data_race.validate_lock_acquire(&rwlock.data_race, writer); } #[inline] @@ -347,6 +370,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } rwlock.writer = None; trace!("rwlock_writer_unlock: {:?} unlocked by {:?}", id, expected_writer); + // Release memory to both reader and writer vector clocks + // since this writer happens-before both the union of readers once they are finished + // and the next writer + this.memory.extra.data_race.validate_lock_release(&mut rwlock.data_race, current_writer); + this.memory.extra.data_race.validate_lock_release(&mut rwlock.data_race_reader, current_writer); // The thread was a writer. // // We are prioritizing writers here against the readers. As a @@ -405,10 +433,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// variable. fn condvar_signal(&mut self, id: CondvarId) -> Option<(ThreadId, MutexId)> { let this = self.eval_context_mut(); - this.machine.threads.sync.condvars[id] - .waiters + let current_thread = this.get_active_thread(); + let condvar = &mut this.machine.threads.sync.condvars[id]; + let data_race = &mut this.memory.extra.data_race; + + // Each condvar signal happens-before the end of the condvar wake + data_race.validate_lock_release(&mut condvar.data_race, current_thread); + condvar.waiters .pop_front() - .map(|waiter| (waiter.thread, waiter.mutex)) + .map(|waiter| { + data_race.validate_lock_acquire(&mut condvar.data_race, waiter.thread); + (waiter.thread, waiter.mutex) + }) } #[inline] @@ -420,15 +456,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn futex_wait(&mut self, addr: Pointer, thread: ThreadId) { let this = self.eval_context_mut(); - let waiters = &mut this.machine.threads.sync.futexes.entry(addr.erase_tag()).or_default().waiters; + let futex = &mut this.machine.threads.sync.futexes.entry(addr.erase_tag()).or_default(); + let waiters = &mut futex.waiters; assert!(waiters.iter().all(|waiter| waiter.thread != thread), "thread is already waiting"); waiters.push_back(FutexWaiter { thread }); } fn futex_wake(&mut self, addr: Pointer) -> Option { let this = self.eval_context_mut(); - let waiters = &mut this.machine.threads.sync.futexes.get_mut(&addr.erase_tag())?.waiters; - waiters.pop_front().map(|waiter| waiter.thread) + let current_thread = this.get_active_thread(); + let futex = &mut this.machine.threads.sync.futexes.get_mut(&addr.erase_tag())?; + let data_race = &mut this.memory.extra.data_race; + + // Each futex-wake happens-before the end of the futex wait + data_race.validate_lock_release(&mut futex.data_race, current_thread); + let res = futex.waiters.pop_front().map(|waiter| { + data_race.validate_lock_acquire(&futex.data_race, waiter.thread); + waiter.thread + }); + res } fn futex_remove_waiter(&mut self, addr: Pointer, thread: ThreadId) { diff --git a/src/thread.rs b/src/thread.rs index eeaee7dc44d5..08aeaa4fd095 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -327,7 +327,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Mark that the active thread tries to join the thread with `joined_thread_id`. - fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> { + fn join_thread(&mut self, joined_thread_id: ThreadId, data_race: &data_race::GlobalState) -> InterpResult<'tcx> { if self.threads[joined_thread_id].join_status != ThreadJoinStatus::Joinable { throw_ub_format!("trying to join a detached or already joined thread"); } @@ -351,6 +351,9 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { self.active_thread, joined_thread_id ); + }else{ + // The thread has already terminated - mark join happens-before + data_race.thread_joined(self.active_thread, joined_thread_id); } Ok(()) } @@ -425,7 +428,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Wakes up threads joining on the active one and deallocates thread-local statics. /// The `AllocId` that can now be freed is returned. - fn thread_terminated(&mut self) -> Vec { + fn thread_terminated(&mut self, data_race: &data_race::GlobalState) -> Vec { let mut free_tls_statics = Vec::new(); { let mut thread_local_statics = self.thread_local_alloc_ids.borrow_mut(); @@ -443,6 +446,8 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { // Check if we need to unblock any threads. for (i, thread) in self.threads.iter_enumerated_mut() { if thread.state == ThreadState::BlockedOnJoin(self.active_thread) { + // The thread has terminated, mark happens-before edge to joining thread + data_race.thread_joined(i, self.active_thread); trace!("unblocking {:?} because {:?} terminated", i, self.active_thread); thread.state = ThreadState::Enabled; } @@ -456,7 +461,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// used in stateless model checkers such as Loom: run the active thread as /// long as we can and switch only when we have to (the active thread was /// blocked, terminated, or has explicitly asked to be preempted). - fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { + fn schedule(&mut self, data_race: &data_race::GlobalState) -> InterpResult<'tcx, SchedulingAction> { // Check whether the thread has **just** terminated (`check_terminated` // checks whether the thread has popped all its stack and if yes, sets // the thread state to terminated). @@ -501,6 +506,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { if thread.state == ThreadState::Enabled { if !self.yield_active_thread || id != self.active_thread { self.active_thread = id; + data_race.thread_set_active(self.active_thread); break; } } @@ -554,7 +560,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn create_thread(&mut self) -> ThreadId { let this = self.eval_context_mut(); - this.machine.threads.create_thread() + let id = this.machine.threads.create_thread(); + this.memory.extra.data_race.thread_created(id); + id } #[inline] @@ -566,12 +574,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.machine.threads.join_thread(joined_thread_id) + let data_race = &*this.memory.extra.data_race; + this.machine.threads.join_thread(joined_thread_id, data_race)?; + Ok(()) } #[inline] fn set_active_thread(&mut self, thread_id: ThreadId) -> ThreadId { let this = self.eval_context_mut(); + this.memory.extra.data_race.thread_set_active(thread_id); this.machine.threads.set_active_thread_id(thread_id) } @@ -626,6 +637,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn set_active_thread_name(&mut self, new_thread_name: Vec) { let this = self.eval_context_mut(); + if let Ok(string) = String::from_utf8(new_thread_name.clone()) { + this.memory.extra.data_race.thread_set_name(string); + } this.machine.threads.set_thread_name(new_thread_name); } @@ -695,7 +709,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { let this = self.eval_context_mut(); - this.machine.threads.schedule() + let data_race = &*this.memory.extra.data_race; + this.machine.threads.schedule(data_race) } /// Handles thread termination of the active thread: wakes up threads joining on this one, @@ -705,7 +720,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn thread_terminated(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - for alloc_id in this.machine.threads.thread_terminated() { + let data_race = &*this.memory.extra.data_race; + for alloc_id in this.machine.threads.thread_terminated(data_race) { let ptr = this.memory.global_base_pointer(alloc_id.into())?; this.memory.deallocate(ptr, None, MiriMemoryKind::Tls.into())?; } From ed32b260f9243b1ebb08c033acd3d5079407a309 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Mon, 2 Nov 2020 01:46:42 +0000 Subject: [PATCH 2427/5092] Add tests, and fix bug in atomic RMW relaxed stores --- src/data_race.rs | 5 +- src/shims/posix/thread.rs | 3 +- .../compile-fail/data_race/read_write_race.rs | 26 ++++ .../data_race/relax_acquire_race.rs | 42 +++++++ .../data_race/release_seq_race.rs | 46 +++++++ tests/compile-fail/data_race/rmw_race.rs | 43 +++++++ .../data_race/write_write_race.rs | 26 ++++ tests/run-pass/concurrency/data_race.rs | 119 ++++++++++++++++++ tests/run-pass/concurrency/data_race.stderr | 2 + tests/run-pass/concurrency/linux-futex.stderr | 2 +- tests/run-pass/concurrency/simple.stderr | 2 +- tests/run-pass/concurrency/sync.stderr | 2 +- .../run-pass/concurrency/thread_locals.stderr | 2 +- .../run-pass/concurrency/tls_lib_drop.stderr | 2 +- tests/run-pass/libc.stderr | 2 +- tests/run-pass/panic/concurrent-panic.stderr | 2 +- 16 files changed, 315 insertions(+), 11 deletions(-) create mode 100644 tests/compile-fail/data_race/read_write_race.rs create mode 100644 tests/compile-fail/data_race/relax_acquire_race.rs create mode 100644 tests/compile-fail/data_race/release_seq_race.rs create mode 100644 tests/compile-fail/data_race/rmw_race.rs create mode 100644 tests/compile-fail/data_race/write_write_race.rs create mode 100644 tests/run-pass/concurrency/data_race.rs create mode 100644 tests/run-pass/concurrency/data_race.stderr diff --git a/src/data_race.rs b/src/data_race.rs index 59526063945a..ac928071bef1 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -404,8 +404,9 @@ impl AtomicReleaseSequences { fn clear_and_retain(&mut self, thread: ThreadId) { match self { Self::ReleaseOneOrEmpty(id, rel_clock) => { - // Keep or forget depending on id - if *id == Some(thread) { + // If the id is the same, then reatin the value + // otherwise delete and clear the release vector clock + if *id != Some(thread) { *id = None; rel_clock.set_zero_vector(); } diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index e420457765b2..e823a7d88d6a 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -15,8 +15,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.tcx.sess.warn( - "thread support is experimental. \ - For example, Miri does not detect data races yet.", + "thread support is experimental.", ); // Create the new thread diff --git a/tests/compile-fail/data_race/read_write_race.rs b/tests/compile-fail/data_race/read_write_race.rs new file mode 100644 index 000000000000..ece99b4a87a1 --- /dev/null +++ b/tests/compile-fail/data_race/read_write_race.rs @@ -0,0 +1,26 @@ + +use std::thread::spawn; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + let mut a = 0u32; + let b = &mut a as *mut u32; + let c = EvilSend(b); + unsafe { + let j1 = spawn(move || { + *c.0 + }); + + let j2 = spawn(move || { + *c.0 = 64; //~ ERROR Data race + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} \ No newline at end of file diff --git a/tests/compile-fail/data_race/relax_acquire_race.rs b/tests/compile-fail/data_race/relax_acquire_race.rs new file mode 100644 index 000000000000..cc96083546a2 --- /dev/null +++ b/tests/compile-fail/data_race/relax_acquire_race.rs @@ -0,0 +1,42 @@ + +use std::thread::spawn; +use std::sync::atomic::{AtomicUsize, Ordering}; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +static SYNC: AtomicUsize = AtomicUsize::new(0); + +pub fn main() { + let mut a = 0u32; + let b = &mut a as *mut u32; + let c = EvilSend(b); + + unsafe { + let j1 = spawn(move || { + *c.0 = 1; + SYNC.store(1, Ordering::Release); + }); + + let j2 = spawn(move || { + if SYNC.load(Ordering::Acquire) == 1 { + SYNC.store(2, Ordering::Relaxed); + } + }); + + let j3 = spawn(move || { + if SYNC.load(Ordering::Acquire) == 2 { + *c.0 //~ ERROR Data race + }else{ + 0 + } + }); + + j1.join().unwrap(); + j2.join().unwrap(); + j3.join().unwrap(); + } +} \ No newline at end of file diff --git a/tests/compile-fail/data_race/release_seq_race.rs b/tests/compile-fail/data_race/release_seq_race.rs new file mode 100644 index 000000000000..8b3ffbcd9dd8 --- /dev/null +++ b/tests/compile-fail/data_race/release_seq_race.rs @@ -0,0 +1,46 @@ +// compile-flags: -Zmiri-disable-isolation + +use std::thread::{spawn, sleep}; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::time::Duration; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +static SYNC: AtomicUsize = AtomicUsize::new(0); + +pub fn main() { + let mut a = 0u32; + let b = &mut a as *mut u32; + let c = EvilSend(b); + + unsafe { + let j1 = spawn(move || { + *c.0 = 1; + SYNC.store(1, Ordering::Release); + sleep(Duration::from_millis(100)); + SYNC.store(3, Ordering::Relaxed); + }); + + let j2 = spawn(move || { + // Blocks the acquire-release sequence + SYNC.store(2, Ordering::Relaxed); + }); + + let j3 = spawn(move || { + sleep(Duration::from_millis(1000)); + if SYNC.load(Ordering::Acquire) == 3 { + *c.0 //~ ERROR Data race + }else{ + 0 + } + }); + + j1.join().unwrap(); + j2.join().unwrap(); + j3.join().unwrap(); + } +} \ No newline at end of file diff --git a/tests/compile-fail/data_race/rmw_race.rs b/tests/compile-fail/data_race/rmw_race.rs new file mode 100644 index 000000000000..9c31c79ebf13 --- /dev/null +++ b/tests/compile-fail/data_race/rmw_race.rs @@ -0,0 +1,43 @@ + +use std::thread::spawn; +use std::sync::atomic::{AtomicUsize, Ordering}; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +static SYNC: AtomicUsize = AtomicUsize::new(0); + +pub fn main() { + let mut a = 0u32; + let b = &mut a as *mut u32; + let c = EvilSend(b); + + unsafe { + let j1 = spawn(move || { + *c.0 = 1; + SYNC.store(1, Ordering::Release); + }); + + let j2 = spawn(move || { + if SYNC.swap(2, Ordering::Relaxed) == 1 { + // Blocks the acquire-release sequence + SYNC.store(3, Ordering::Relaxed); + } + }); + + let j3 = spawn(move || { + if SYNC.load(Ordering::Acquire) == 3 { + *c.0 //~ ERROR Data race + }else{ + 0 + } + }); + + j1.join().unwrap(); + j2.join().unwrap(); + j3.join().unwrap(); + } +} \ No newline at end of file diff --git a/tests/compile-fail/data_race/write_write_race.rs b/tests/compile-fail/data_race/write_write_race.rs new file mode 100644 index 000000000000..22caf5f0f7f3 --- /dev/null +++ b/tests/compile-fail/data_race/write_write_race.rs @@ -0,0 +1,26 @@ + +use std::thread::spawn; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + let mut a = 0u32; + let b = &mut a as *mut u32; + let c = EvilSend(b); + unsafe { + let j1 = spawn(move || { + *c.0 = 32; + }); + + let j2 = spawn(move || { + *c.0 = 64; //~ ERROR Data race + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} \ No newline at end of file diff --git a/tests/run-pass/concurrency/data_race.rs b/tests/run-pass/concurrency/data_race.rs new file mode 100644 index 000000000000..bc4a4e30e891 --- /dev/null +++ b/tests/run-pass/concurrency/data_race.rs @@ -0,0 +1,119 @@ +use std::sync::atomic::{AtomicUsize, fence, Ordering}; +use std::thread::spawn; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +static SYNC: AtomicUsize = AtomicUsize::new(0); + +fn test_fence_sync() { + let mut var = 0u32; + let ptr = &mut var as *mut u32; + let evil_ptr = EvilSend(ptr); + + + let j1 = spawn(move || { + unsafe { *evil_ptr.0 = 1; } + fence(Ordering::Release); + SYNC.store(1, Ordering::Relaxed) + }); + + let j2 = spawn(move || { + if SYNC.load(Ordering::Relaxed) == 1 { + fence(Ordering::Acquire); + unsafe { *evil_ptr.0 } + }else{ + 0 + } + }); + + j1.join().unwrap(); + j2.join().unwrap(); +} + + +fn test_multiple_reads() { + let mut var = 42u32; + let ptr = &mut var as *mut u32; + let evil_ptr = EvilSend(ptr); + + let j1 = spawn(move || unsafe {*evil_ptr.0}); + let j2 = spawn(move || unsafe {*evil_ptr.0}); + let j3 = spawn(move || unsafe {*evil_ptr.0}); + let j4 = spawn(move || unsafe {*evil_ptr.0}); + + assert_eq!(j1.join().unwrap(), 42); + assert_eq!(j2.join().unwrap(), 42); + assert_eq!(j3.join().unwrap(), 42); + assert_eq!(j4.join().unwrap(), 42); + + var = 10; + assert_eq!(var, 10); +} + +pub fn test_rmw_no_block() { + let mut a = 0u32; + let b = &mut a as *mut u32; + let c = EvilSend(b); + + unsafe { + let j1 = spawn(move || { + *c.0 = 1; + SYNC.store(1, Ordering::Release); + }); + + let j2 = spawn(move || { + if SYNC.swap(2, Ordering::Relaxed) == 1 { + //No op, blocking store removed + } + }); + + let j3 = spawn(move || { + if SYNC.load(Ordering::Acquire) == 2 { + *c.0 + }else{ + 0 + } + }); + + j1.join().unwrap(); + j2.join().unwrap(); + let v = j3.join().unwrap(); + assert!(v == 1 || v == 2); + } +} + +pub fn test_release_no_block() { + let mut a = 0u32; + let b = &mut a as *mut u32; + let c = EvilSend(b); + + unsafe { + let j1 = spawn(move || { + *c.0 = 1; + SYNC.store(1, Ordering::Release); + SYNC.store(3, Ordering::Relaxed); + }); + + let j2 = spawn(move || { + if SYNC.load(Ordering::Acquire) == 3 { + *c.0 + }else{ + 0 + } + }); + + j1.join().unwrap(); + assert_eq!(j2.join().unwrap(),1); + } +} + +pub fn main() { + test_fence_sync(); + test_multiple_reads(); + test_rmw_no_block(); + test_release_no_block(); +} \ No newline at end of file diff --git a/tests/run-pass/concurrency/data_race.stderr b/tests/run-pass/concurrency/data_race.stderr new file mode 100644 index 000000000000..b01247aea4e0 --- /dev/null +++ b/tests/run-pass/concurrency/data_race.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental. + diff --git a/tests/run-pass/concurrency/linux-futex.stderr b/tests/run-pass/concurrency/linux-futex.stderr index 2dbfb7721d36..b01247aea4e0 100644 --- a/tests/run-pass/concurrency/linux-futex.stderr +++ b/tests/run-pass/concurrency/linux-futex.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental. For example, Miri does not detect data races yet. +warning: thread support is experimental. diff --git a/tests/run-pass/concurrency/simple.stderr b/tests/run-pass/concurrency/simple.stderr index 7060411278e6..f1550dd25aa0 100644 --- a/tests/run-pass/concurrency/simple.stderr +++ b/tests/run-pass/concurrency/simple.stderr @@ -1,4 +1,4 @@ -warning: thread support is experimental. For example, Miri does not detect data races yet. +warning: thread support is experimental. thread '' panicked at 'Hello!', $DIR/simple.rs:54:9 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/concurrency/sync.stderr b/tests/run-pass/concurrency/sync.stderr index 2dbfb7721d36..b01247aea4e0 100644 --- a/tests/run-pass/concurrency/sync.stderr +++ b/tests/run-pass/concurrency/sync.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental. For example, Miri does not detect data races yet. +warning: thread support is experimental. diff --git a/tests/run-pass/concurrency/thread_locals.stderr b/tests/run-pass/concurrency/thread_locals.stderr index 2dbfb7721d36..b01247aea4e0 100644 --- a/tests/run-pass/concurrency/thread_locals.stderr +++ b/tests/run-pass/concurrency/thread_locals.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental. For example, Miri does not detect data races yet. +warning: thread support is experimental. diff --git a/tests/run-pass/concurrency/tls_lib_drop.stderr b/tests/run-pass/concurrency/tls_lib_drop.stderr index 2dbfb7721d36..b01247aea4e0 100644 --- a/tests/run-pass/concurrency/tls_lib_drop.stderr +++ b/tests/run-pass/concurrency/tls_lib_drop.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental. For example, Miri does not detect data races yet. +warning: thread support is experimental. diff --git a/tests/run-pass/libc.stderr b/tests/run-pass/libc.stderr index 2dbfb7721d36..b01247aea4e0 100644 --- a/tests/run-pass/libc.stderr +++ b/tests/run-pass/libc.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental. For example, Miri does not detect data races yet. +warning: thread support is experimental. diff --git a/tests/run-pass/panic/concurrent-panic.stderr b/tests/run-pass/panic/concurrent-panic.stderr index eb5b5f59a0cb..ca6031e57b40 100644 --- a/tests/run-pass/panic/concurrent-panic.stderr +++ b/tests/run-pass/panic/concurrent-panic.stderr @@ -1,4 +1,4 @@ -warning: thread support is experimental. For example, Miri does not detect data races yet. +warning: thread support is experimental. Thread 1 starting, will block on mutex Thread 1 reported it has started From cae4302003f32e808b822b1b7b351894548c6c0e Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Mon, 2 Nov 2020 03:06:30 +0000 Subject: [PATCH 2428/5092] Fix & rebase --- src/data_race.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index ac928071bef1..35898f1d937f 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -176,19 +176,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut current_state = alloc.global.current_thread_state_mut(); if atomic == AtomicReadOp::Relaxed { // Perform relaxed atomic load - for range in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { + for (_,range) in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { range.load_relaxed(&mut *current_state); } }else{ // Perform acquire(or seq-cst) atomic load - for range in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { + for (_,range) in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { range.acquire(&mut *current_state); } } // Log changes to atomic memory if log::log_enabled!(log::Level::Trace) { - for range in alloc.alloc_ranges.get_mut().iter(offset, size) { + for (_,range) in alloc.alloc_ranges.get_mut().iter(offset, size) { log::trace!( " updated atomic memory({:?}, offset={}, size={}) to {:#?}", place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes(), @@ -227,19 +227,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if atomic == AtomicWriteOp::Relaxed { // Perform relaxed atomic store - for range in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { + for (_,range) in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { range.store_relaxed(&mut *current_state, current_thread); } }else{ // Perform release(or seq-cst) atomic store - for range in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { + for (_,range) in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { range.release(&mut *current_state, current_thread); } } // Log changes to atomic memory if log::log_enabled!(log::Level::Trace) { - for range in alloc.alloc_ranges.get_mut().iter(offset, size) { + for (_,range) in alloc.alloc_ranges.get_mut().iter(offset, size) { log::trace!( " updated atomic memory({:?}, offset={}, size={}) to {:#?}", place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes(), @@ -279,7 +279,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); let release = matches!(atomic, Release | AcqRel | SeqCst); - for range in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { + for (_,range) in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { //FIXME: this is probably still slightly wrong due to the quirks // in the c++11 memory model if acquire { @@ -298,7 +298,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Log changes to atomic memory if log::log_enabled!(log::Level::Trace) { - for range in alloc.alloc_ranges.get_mut().iter(offset, size) { + for (_,range) in alloc.alloc_ranges.get_mut().iter(offset, size) { log::trace!( " updated atomic memory({:?}, offset={}, size={}) to {:#?}", place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes(), @@ -733,7 +733,7 @@ impl VClockAlloc { // The alloc-ranges are not split, however changes are not going to be made // to the ranges being tested, so this is ok let mut alloc_ranges = self.alloc_ranges.borrow_mut(); - for range in alloc_ranges.iter_mut(pointer.offset, len) { + for (_,range) in alloc_ranges.iter_mut(pointer.offset, len) { if range.read_race_detect(&*current_state, current_thread) { // Report data-race return Self::report_data_race( @@ -754,7 +754,7 @@ impl VClockAlloc { if self.global.multi_threaded.get() { let current_thread = self.global.current_thread(); let current_state = self.global.current_thread_state(); - for range in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { + for (_,range) in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { if range.write_race_detect(&*current_state, current_thread) { // Report data-race return Self::report_data_race( @@ -775,7 +775,7 @@ impl VClockAlloc { if self.global.multi_threaded.get() { let current_thread = self.global.current_thread(); let current_state = self.global.current_thread_state(); - for range in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { + for (_,range) in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { if range.write_race_detect(&*current_state, current_thread) { // Report data-race return Self::report_data_race( From 2e75de5ac9c2805d25f6b5452d8397f99ee5e342 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Mon, 2 Nov 2020 12:40:12 +0000 Subject: [PATCH 2429/5092] Mark all new tests as disabled on windows --- tests/compile-fail/data_race/read_write_race.rs | 1 + tests/compile-fail/data_race/relax_acquire_race.rs | 1 + tests/compile-fail/data_race/release_seq_race.rs | 1 + tests/compile-fail/data_race/rmw_race.rs | 1 + tests/compile-fail/data_race/write_write_race.rs | 1 + tests/run-pass/concurrency/data_race.rs | 3 +++ 6 files changed, 8 insertions(+) diff --git a/tests/compile-fail/data_race/read_write_race.rs b/tests/compile-fail/data_race/read_write_race.rs index ece99b4a87a1..6a5f3f7d2076 100644 --- a/tests/compile-fail/data_race/read_write_race.rs +++ b/tests/compile-fail/data_race/read_write_race.rs @@ -1,3 +1,4 @@ +// ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/compile-fail/data_race/relax_acquire_race.rs b/tests/compile-fail/data_race/relax_acquire_race.rs index cc96083546a2..753d30b8f570 100644 --- a/tests/compile-fail/data_race/relax_acquire_race.rs +++ b/tests/compile-fail/data_race/relax_acquire_race.rs @@ -1,3 +1,4 @@ +// ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/compile-fail/data_race/release_seq_race.rs b/tests/compile-fail/data_race/release_seq_race.rs index 8b3ffbcd9dd8..44360f70d5d6 100644 --- a/tests/compile-fail/data_race/release_seq_race.rs +++ b/tests/compile-fail/data_race/release_seq_race.rs @@ -1,3 +1,4 @@ +// ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-disable-isolation use std::thread::{spawn, sleep}; diff --git a/tests/compile-fail/data_race/rmw_race.rs b/tests/compile-fail/data_race/rmw_race.rs index 9c31c79ebf13..9dfa2751d587 100644 --- a/tests/compile-fail/data_race/rmw_race.rs +++ b/tests/compile-fail/data_race/rmw_race.rs @@ -1,3 +1,4 @@ +// ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/compile-fail/data_race/write_write_race.rs b/tests/compile-fail/data_race/write_write_race.rs index 22caf5f0f7f3..0c46e5c92515 100644 --- a/tests/compile-fail/data_race/write_write_race.rs +++ b/tests/compile-fail/data_race/write_write_race.rs @@ -1,3 +1,4 @@ +// ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/run-pass/concurrency/data_race.rs b/tests/run-pass/concurrency/data_race.rs index bc4a4e30e891..40a7c162a0c1 100644 --- a/tests/run-pass/concurrency/data_race.rs +++ b/tests/run-pass/concurrency/data_race.rs @@ -1,3 +1,6 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + + use std::sync::atomic::{AtomicUsize, fence, Ordering}; use std::thread::spawn; From fe2e857cc3744a69b1d1dc2fe77f94da10978091 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Mon, 2 Nov 2020 13:08:09 +0000 Subject: [PATCH 2430/5092] Add newlines at end of file + use replace. add dangling thread variant of one of the benchmarks --- .../mse_and_dangling_thread/Cargo.toml | 7 +++++ .../mse_and_dangling_thread/src/main.rs | 30 +++++++++++++++++++ src/data_race.rs | 10 +++---- .../compile-fail/data_race/read_write_race.rs | 2 +- .../data_race/relax_acquire_race.rs | 2 +- .../data_race/release_seq_race.rs | 2 +- tests/compile-fail/data_race/rmw_race.rs | 2 +- .../data_race/write_write_race.rs | 2 +- tests/run-pass/concurrency/data_race.rs | 2 +- 9 files changed, 47 insertions(+), 12 deletions(-) create mode 100644 bench-cargo-miri/mse_and_dangling_thread/Cargo.toml create mode 100644 bench-cargo-miri/mse_and_dangling_thread/src/main.rs diff --git a/bench-cargo-miri/mse_and_dangling_thread/Cargo.toml b/bench-cargo-miri/mse_and_dangling_thread/Cargo.toml new file mode 100644 index 000000000000..7b4c2dc758fa --- /dev/null +++ b/bench-cargo-miri/mse_and_dangling_thread/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "mse" +version = "0.1.0" +authors = ["Ralf Jung "] +edition = "2018" + +[dependencies] diff --git a/bench-cargo-miri/mse_and_dangling_thread/src/main.rs b/bench-cargo-miri/mse_and_dangling_thread/src/main.rs new file mode 100644 index 000000000000..008e9c80eff1 --- /dev/null +++ b/bench-cargo-miri/mse_and_dangling_thread/src/main.rs @@ -0,0 +1,30 @@ +static EXPECTED: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 254, 255, 0, 0, 254, 255, 0, 0, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 255, 255, 1, 0, 255, 255, 1, 0, 0, 0, 1, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 0, 0, 254, 255, 0, 0, 254, 255, 0, 0, 254, 255, 255, 255, 254, 255, 254, 255, 254, 255, 253, 255, 253, 255, 253, 255, 253, 255, 252, 255, 254, 255, 251, 255, 254, 255, 251, 255, 254, 255, 252, 255, 255, 255, 252, 255, 0, 0, 252, 255, 0, 0, 252, 255, 1, 0, 252, 255, 1, 0, 252, 255, 2, 0, 252, 255, 2, 0, 252, 255, 2, 0, 252, 255, 2, 0, 252, 255, 2, 0, 253, 255, 1, 0, 252, 255, 0, 0, 252, 255, 255, 255, 251, 255, 0, 0, 251, 255, 0, 0, 251, 255, 0, 0, 252, 255, 2, 0, 252, 255, 3, 0, 252, 255, 4, 0, 253, 255, 5, 0, 254, 255, 5, 0, 253, 255, 6, 0, 253, 255, 6, 0, 253, 255, 5, 0, 253, 255, 5, 0, 254, 255, 4, 0, 254, 255, 3, 0, 251, 255, 0, 0, 250, 255, 255, 255, 253, 255, 254, 255, 252, 255, 252, 255, 247, 255, 251, 255, 247, 255, 252, 255, 252, 255, 254, 255, 252, 255, 254, 255, 252, 255, 255, 255, 254, 255, 1, 0, 1, 0, 1, 0, 4, 0, 2, 0, 8, 0, 2, 0, 12, 0, 1, 0, 13, 0, 0, 0, 12, 0, 0, 0, 11, 0, 255, 255, 8, 0, 254, 255, 7, 0, 0, 0, 7, 0, 253, 255, 11, 0, 248, 255, 15, 0, 247, 255, 17, 0, 250, 255, 17, 0, 251, 255, 13, 0, 253, 255, 7, 0, 255, 255, 3, 0, 255, 255, 254, 255, 255, 255, 252, 255, 255, 255, 252, 255, 254, 255, 250, 255, 255, 255, 242, 255, 254, 255, 239, 255, 252, 255, 248, 255, 255, 255, 249, 255, 5, 0, 239, 255, 7, 0, 238, 255, 10, 0, 249, 255, 18, 0, 254, 255, 25, 0, 253, 255, 27, 0, 0, 0, 31, 0, 4, 0, 34, 0, 4, 0, 34, 0, 8, 0, 36, 0, 8, 0, 37, 0, 2, 0, 36, 0, 4, 0, 34, 0, 8, 0, 28, 0, 3, 0, 15, 0, 255, 255, 11, 0, 0, 0, 12, 0, 251, 255, 8, 0, 252, 255, 10, 0, 0, 0, 23, 0, 252, 255, 31, 0, 248, 255, 30, 0, 254, 255, 30, 0, 255, 255, 26, 0, 250, 255, 22, 0, 250, 255, 20, 0, 244, 255, 15, 0, 237, 255, 10, 0, 246, 255, 13, 0, 242, 255, 6, 0, 213, 255, 243, 255, 213, 255, 240, 255, 247, 255, 244, 255, 246, 255, 227, 255, 214, 255, 216, 255, 219, 255, 228, 255, 251, 255, 235, 255, 1, 0, 232, 255, 248, 255, 236, 255, 4, 0, 238, 255, 26, 0, 232, 255, 44, 0, 230, 255, 66, 0, 226, 255, 86, 0, 219, 255, 88, 0, 215, 255, 72, 0, 210, 255, 50, 0, 225, 255, 28, 0, 23, 0, 14, 0, 64, 0, 16, 0, 51, 0, 26, 0, 32, 0, 34, 0, 39, 0, 42, 0, 48, 0, 35, 0, 58, 0, 255, 255, 72, 0, 220, 255, 69, 0, 197, 255, 58, 0, 158, 255, 54, 0, 132, 255, 36, 0, 153, 255, 12, 0, 146, 255, 5, 0, 83, 255, 237, 255, 110, 255, 197, 255, 252, 255, 214, 255, 51, 0, 1, 0, 233, 255, 250, 255, 226, 255, 250, 255, 45, 0, 46, 0, 47, 0, 70, 0, 6, 0, 55, 0, 19, 0, 60, 0, 38, 0, 62, 0, 42, 0, 47, 0, 61, 0, 46, 0, 40, 0, 42, 0, 237, 255, 22, 0, 222, 255, 6, 0, 221, 255, 206, 255, 195, 255, 115, 255, 219, 255, 85, 255, 17, 0, 93, 255, 26, 0, 76, 255, 46, 0, 102, 255, 80, 0, 193, 255, 48, 0, 252, 255, 18, 0, 20, 0, 50, 0, 47, 0, 58, 0, 53, 0, 44, 0, 61, 0, 57, 0, 85, 0, 37, 0, 80, 0, 0, 0, 86, 0, 248, 255, 106, 0, 161, 255, 49, 0, 43, 255, 248, 255, 125, 255, 47, 0, 49, 0, 63, 0, 40, 0, 217, 255, 187, 255, 182, 255, 219, 255, 236, 255, 63, 0, 244, 255, 58, 0, 242, 255, 244, 255, 25, 0, 225, 255, 41, 0, 11, 0, 45, 0, 76, 0, 47, 0, 167, 0, 5, 0, 5, 1, 219, 255, 21, 1, 173, 255, 183, 0, 84, 255, 35, 0, 134, 255, 177, 255, 138, 0, 186, 255, 10, 1, 69, 0, 124, 0, 228, 0, 0, 0, 135, 1, 227, 255, 82, 2, 172, 255, 190, 2, 178, 255, 115, 2, 248, 255, 39, 2, 243, 255, 253, 1, 13, 0, 116, 1, 120, 0, 96, 1, 125, 0, 110, 2, 127, 0, 179, 2, 223, 0, 106, 1, 126, 0, 130, 1, 223, 255, 147, 3, 198, 0, 190, 3, 201, 1, 200, 1, 42, 1, 244, 1, 233, 0, 3, 4, 213, 1, 72, 4, 170, 1, 150, 3, 160, 0, 43, 4, 141, 0, 196, 4, 189, 0, 221, 4, 164, 0, 95, 5, 41, 1, 98, 5, 247, 1, 19, 5, 190, 2, 14, 6, 161, 3, 7, 7, 87, 3, 216, 6, 35, 2, 38, 7, 90, 2, 136, 7, 64, 3, 200, 6, 28, 3, 199, 6, 165, 3, 169, 7, 105, 5, 143, 7, 26, 6, 57, 8, 205, 5, 156, 10, 169, 5, 132, 11, 25, 5, 208, 10, 181, 4, 156, 10, 66, 5, 227, 9, 170, 5, 166, 9, 117, 6, 45, 12, 63, 8, 42, 13, 128, 8, 136, 10, 155, 7, 109, 11, 1, 9, 6, 15, 98, 10, 121, 9, 136, 8, 147, 252, 189, 7, 43, 247, 63, 10, 147, 249, 92, 11, 172, 248, 172, 10, 112, 245, 137, 11, 76, 246, 44, 12, 184, 247, 138, 11, 118, 246, 144, 12, 94, 246, 171, 13, 112, 247, 162, 12, 168, 246, 33, 13, 63, 246, 29, 15, 226, 247, 188, 14, 190, 248, 75, 15, 238, 247, 86, 17, 19, 247, 118, 11, 10, 247, 232, 254, 238, 247, 30, 249, 56, 248, 124, 250, 6, 247, 1, 250, 161, 246, 3, 249, 81, 247, 117, 250, 60, 247, 202, 250, 212, 247, 60, 250, 15, 249, 140, 250, 34, 248, 221, 249, 105, 247, 218, 249, 205, 248, 113, 251, 138, 248, 90, 250, 41, 248, 230, 248]; +static PCM: &[i16] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1, 0, 1, 0, 0, -2, 0, -2, 0, -2, 0, -2, -2, -2, -3, -3, -3, -3, -4, -2, -5, -2, -5, -2, -4, 0, -4, 0, -4, 0, -4, 1, -4, 1, -4, 2, -4, 2, -4, 2, -4, 2, -4, 2, -3, 1, -4, 0, -4, 0, -5, 0, -5, 0, -5, 0, -4, 2, -4, 3, -4, 4, -3, 5, -2, 5, -3, 6, -3, 6, -3, 5, -3, 5, -2, 4, -2, 3, -5, 0, -6, 0, -3, -2, -4, -4, -9, -5, -9, -4, -4, -2, -4, -2, -4, 0, -2, 1, 1, 1, 4, 2, 8, 2, 12, 1, 13, 0, 12, 0, 11, 0, 8, -2, 7, 0, 7, -3, 11, -8, 15, -9, 17, -6, 17, -5, 13, -3, 7, 0, 3, 0, -2, 0, -4, 0, -4, -2, -6, 0, -14, -2, -17, -4, -8, 0, -7, 5, -17, 7, -18, 10, -7, 18, -2, 25, -3, 27, 0, 31, 4, 34, 4, 34, 8, 36, 8, 37, 2, 36, 4, 34, 8, 28, 3, 15, 0, 11, 0, 12, -5, 8, -4, 10, 0, 23, -4, 31, -8, 30, -2, 30, 0, 26, -6, 22, -6, 20, -12, 15, -19, 10, -10, 13, -14, 6, -43, -13, -43, -16, -9, -12, -10, -29, -42, -40, -37, -28, -5, -21, 1, -24, -8, -20, 4, -18, 26, -24, 44, -26, 66, -30, 86, -37, 88, -41, 72, -46, 50, -31, 28, 23, 14, 64, 16, 51, 26, 32, 34, 39, 42, 48, 35, 58, 0, 72, -36, 69, -59, 58, -98, 54, -124, 36, -103, 12, -110, 5, -173, -19, -146, -59, -4, -42, 51, 1, -23, -6, -30, -6, 45, 46, 47, 70, 6, 55, 19, 60, 38, 62, 42, 47, 61, 46, 40, 42, -19, 22, -34, 6, -35, -50, -61, -141, -37, -171, 17, -163, 26, -180, 46, -154, 80, -63, 48, -4, 18, 20, 50, 47, 58, 53, 44, 61, 57, 85, 37, 80, 0, 86, -8, 106, -95, 49, -213, -8, -131, 47, 49, 63, 40, -39, -69, -74, -37, -20, 63, -12, 58, -14, -12, 25, -31, 41, 11, 45, 76, 47, 167, 5, 261, -37, 277, -83, 183, -172, 35, -122, -79, 138, -70, 266, 69, 124, 228, 0, 391, -29, 594, -84, 702, -78, 627, -8, 551, -13, 509, 13, 372, 120, 352, 125, 622, 127, 691, 223, 362, 126, 386, -33, 915, 198, 958, 457, 456, 298, 500, 233, 1027, 469, 1096, 426, 918, 160, 1067, 141, 1220, 189, 1245, 164, 1375, 297, 1378, 503, 1299, 702, 1550, 929, 1799, 855, 1752, 547, 1830, 602, 1928, 832, 1736, 796, 1735, 933, 1961, 1385, 1935, 1562, 2105, 1485, 2716, 1449, 2948, 1305, 2768, 1205, 2716, 1346, 2531, 1450, 2470, 1653, 3117, 2111, 3370, 2176, 2696, 1947, 2925, 2305, 3846, 2658, 2425, 2184, -877, 1981, -2261, 2623, -1645, 2908, -1876, 2732, -2704, 2953, -2484, 3116, -2120, 2954, -2442, 3216, -2466, 3499, -2192, 3234, -2392, 3361, -2497, 3869, -2078, 3772, -1858, 3915, -2066, 4438, -2285, 2934, -2294, -280, -2066, -1762, -1992, -1412, -2298, -1535, -2399, -1789, -2223, -1419, -2244, -1334, -2092, -1476, -1777, -1396, -2014, -1571, -2199, -1574, -1843, -1167, -1910, -1446, -2007, -1818]; + +fn main() { + let thread = std::thread::spawn(|| 4); + for _ in 0..2 { + mse(PCM.len(), PCM, EXPECTED); + } + assert_eq!(4, thread.join().unwrap()); +} + +fn read_i16(buffer: &[u8], index: usize) -> i16 { + const SIZE: usize = std::mem::size_of::(); + let mut bytes: [u8; SIZE] = [0u8; SIZE]; + bytes.copy_from_slice(&buffer[(index * SIZE)..(index * SIZE + SIZE)]); + unsafe { std::mem::transmute(bytes) } +} + +fn mse(samples: usize, frame_buf: &[i16], buf_ref: &[u8]) -> f64 { + let mut mse = 0.0; + let max_samples = std::cmp::min(buf_ref.len() / 2, samples as usize); + for i in 0..max_samples { + let ref_res = read_i16(buf_ref, i); + let info_res = frame_buf[i as usize]; + let diff = (ref_res - info_res).abs(); + mse += f64::from(diff.pow(2)); + } + mse / max_samples as f64 +} + diff --git a/src/data_race.rs b/src/data_race.rs index 35898f1d937f..bd75299af490 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -65,12 +65,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn read_immediate_racy(&self, op: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let this = self.eval_context_ref(); let data_race = &*this.memory.extra.data_race; - let old = data_race.multi_threaded.get(); - data_race.multi_threaded.set(false); + let old = data_race.multi_threaded.replace(false); let res = this.read_immediate(op.into()); - data_race.multi_threaded.set(old); + res } @@ -80,9 +79,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let data_race = &*this.memory.extra.data_race; - let old = data_race.multi_threaded.get(); + let old = data_race.multi_threaded.replace(false); - data_race.multi_threaded.set(false); let imm = this.write_immediate(src, dest.into()); let data_race = &*this.memory.extra.data_race; @@ -1404,4 +1402,4 @@ mod tests { "Invalid alt (>=):\n l: {:?}\n r: {:?}",l,r ); } -} \ No newline at end of file +} diff --git a/tests/compile-fail/data_race/read_write_race.rs b/tests/compile-fail/data_race/read_write_race.rs index 6a5f3f7d2076..42fd7a51ffbd 100644 --- a/tests/compile-fail/data_race/read_write_race.rs +++ b/tests/compile-fail/data_race/read_write_race.rs @@ -24,4 +24,4 @@ pub fn main() { j1.join().unwrap(); j2.join().unwrap(); } -} \ No newline at end of file +} diff --git a/tests/compile-fail/data_race/relax_acquire_race.rs b/tests/compile-fail/data_race/relax_acquire_race.rs index 753d30b8f570..f7d44c30b66b 100644 --- a/tests/compile-fail/data_race/relax_acquire_race.rs +++ b/tests/compile-fail/data_race/relax_acquire_race.rs @@ -40,4 +40,4 @@ pub fn main() { j2.join().unwrap(); j3.join().unwrap(); } -} \ No newline at end of file +} diff --git a/tests/compile-fail/data_race/release_seq_race.rs b/tests/compile-fail/data_race/release_seq_race.rs index 44360f70d5d6..dc852cdb4d81 100644 --- a/tests/compile-fail/data_race/release_seq_race.rs +++ b/tests/compile-fail/data_race/release_seq_race.rs @@ -44,4 +44,4 @@ pub fn main() { j2.join().unwrap(); j3.join().unwrap(); } -} \ No newline at end of file +} diff --git a/tests/compile-fail/data_race/rmw_race.rs b/tests/compile-fail/data_race/rmw_race.rs index 9dfa2751d587..bebd01efa171 100644 --- a/tests/compile-fail/data_race/rmw_race.rs +++ b/tests/compile-fail/data_race/rmw_race.rs @@ -41,4 +41,4 @@ pub fn main() { j2.join().unwrap(); j3.join().unwrap(); } -} \ No newline at end of file +} diff --git a/tests/compile-fail/data_race/write_write_race.rs b/tests/compile-fail/data_race/write_write_race.rs index 0c46e5c92515..aca19a46c13d 100644 --- a/tests/compile-fail/data_race/write_write_race.rs +++ b/tests/compile-fail/data_race/write_write_race.rs @@ -24,4 +24,4 @@ pub fn main() { j1.join().unwrap(); j2.join().unwrap(); } -} \ No newline at end of file +} diff --git a/tests/run-pass/concurrency/data_race.rs b/tests/run-pass/concurrency/data_race.rs index 40a7c162a0c1..75e56e8c8d2a 100644 --- a/tests/run-pass/concurrency/data_race.rs +++ b/tests/run-pass/concurrency/data_race.rs @@ -119,4 +119,4 @@ pub fn main() { test_multiple_reads(); test_rmw_no_block(); test_release_no_block(); -} \ No newline at end of file +} From 571b48cc47a7a4826f16766a4668168dd090a6f8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 3 Nov 2020 20:07:19 +0100 Subject: [PATCH 2431/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 40aa78ae9a9c..efb6b94d3b40 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a53fb30e3bf2655b0563da6d561c23cda5f3ec11 +5cdf5b882da9e8b7c73b5cadeb7745cb68f6ff63 From 95c99b2044a75f27e691308ebbb7ed0d4e2cbf3b Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Wed, 4 Nov 2020 21:35:48 +0000 Subject: [PATCH 2432/5092] Detect races between atomic and non-atomic accesses of a variable, previously only data races between two non-atomic accesses were detected. --- src/data_race.rs | 350 ++++++++++++++---- src/shims/posix/linux/sync.rs | 5 +- .../data_race/atomic_read_write_race.rs | 31 ++ .../data_race/atomic_read_write_race_alt.rs | 31 ++ .../data_race/atomic_write_read_race.rs | 31 ++ .../data_race/atomic_write_read_race_alt.rs | 31 ++ .../data_race/atomic_write_write_race.rs | 31 ++ .../data_race/atomic_write_write_race_alt.rs | 31 ++ 8 files changed, 463 insertions(+), 78 deletions(-) create mode 100644 tests/compile-fail/data_race/atomic_read_write_race.rs create mode 100644 tests/compile-fail/data_race/atomic_read_write_race_alt.rs create mode 100644 tests/compile-fail/data_race/atomic_write_read_race.rs create mode 100644 tests/compile-fail/data_race/atomic_write_read_race_alt.rs create mode 100644 tests/compile-fail/data_race/atomic_write_write_race.rs create mode 100644 tests/compile-fail/data_race/atomic_write_write_race_alt.rs diff --git a/src/data_race.rs b/src/data_race.rs index bd75299af490..8e7a3548f5cf 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -6,8 +6,16 @@ //! and RMW operations //! This does not explore weak memory orders and so can still miss data-races //! but should not report false-positives +//! Data-race definiton from(https://en.cppreference.com/w/cpp/language/memory_model#Threads_and_data_races): +//! - if a memory location is accessed by twice is a data-race unless: +//! - both operations execute on the same thread/signal-handler +//! - both conflicting operations are atomic operations (1 atomic and 1 non-atomic race) +//! - 1 of the operations happens-before the other operation (see link for definition) -use std::{fmt::{self, Debug}, cmp::Ordering, rc::Rc, cell::{Cell, RefCell, Ref, RefMut}, ops::Index}; +use std::{ + fmt::{self, Debug}, cmp::Ordering, rc::Rc, + cell::{Cell, RefCell, Ref, RefMut}, ops::Index, mem +}; use rustc_index::vec::{Idx, IndexVec}; use rustc_target::abi::Size; @@ -16,7 +24,11 @@ use rustc_data_structures::fx::FxHashMap; use smallvec::SmallVec; -use crate::*; +use crate::{ + MiriEvalContext, ThreadId, Tag, MiriEvalContextExt, RangeMap, + MPlaceTy, ImmTy, InterpResult, Pointer, ScalarMaybeUninit, + OpTy, Immediate, MemPlaceMeta +}; pub type AllocExtra = VClockAlloc; pub type MemoryExtra = Rc; @@ -58,8 +70,8 @@ pub enum AtomicFenceOp { } /// Evaluation context extensions -impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} -pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// Variant of `read_immediate` that does not perform `data-race` checks. fn read_immediate_racy(&self, op: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { @@ -119,6 +131,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.read_scalar_racy(value_place.into()) } + /// Variant of `write_scalar_at_offfset` helper function that performs + /// an atomic load operation with verification instead + fn read_scalar_at_offset_atomic( + &mut self, + op: OpTy<'tcx, Tag>, + offset: u64, + layout: TyAndLayout<'tcx>, + atomic: AtomicReadOp + ) -> InterpResult<'tcx, ScalarMaybeUninit> { + let this = self.eval_context_mut(); + let op_place = this.deref_operand(op)?; + let offset = Size::from_bytes(offset); + // Ensure that the following read at an offset is within bounds + assert!(op_place.layout.size >= offset + layout.size); + let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; + let res = this.read_scalar_racy(value_place.into())?; + this.validate_atomic_load(value_place, atomic)?; + Ok(res) + } + /// Variant of `write_scalar_at_offfset` helper function that does not perform /// data-race checks. fn write_scalar_at_offset_racy( @@ -137,10 +169,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar_racy(value.into(), value_place.into()) } + /// Load the data race allocation state for a given memory place + /// also returns the size and offset of the result in the allocation + /// metadata + /// This is used for atomic loads since unconditionally requesteing + /// mutable access causes issues for read-only memory, which will + /// fail validation on mutable access + fn load_data_race_state_ref<'a>( + &'a self, place: MPlaceTy<'tcx, Tag> + ) -> InterpResult<'tcx, (&'a VClockAlloc, Size, Size)> where 'mir: 'a { + let this = self.eval_context_ref(); + + let ptr = place.ptr.assert_ptr(); + let size = place.layout.size; + let data_race = &this.memory.get_raw(ptr.alloc_id)?.extra.data_race; + + Ok((data_race, size, ptr.offset)) + } + /// Load the data race allocation state for a given memory place /// also returns the size and the offset of the result in the allocation /// metadata - fn load_data_race_state<'a>( + fn load_data_race_state_mut<'a>( &'a mut self, place: MPlaceTy<'tcx, Tag> ) -> InterpResult<'tcx, (&'a mut VClockAlloc, Size, Size)> where 'mir: 'a { let this = self.eval_context_mut(); @@ -164,29 +214,42 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ( alloc, size, offset - ) = this.load_data_race_state(place)?; + ) = this.load_data_race_state_ref(place)?; log::trace!( "Atomic load on {:?} with ordering {:?}, in memory({:?}, offset={}, size={})", alloc.global.current_thread(), atomic, place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes() ); + let current_thread = alloc.global.current_thread(); let mut current_state = alloc.global.current_thread_state_mut(); if atomic == AtomicReadOp::Relaxed { // Perform relaxed atomic load - for (_,range) in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { - range.load_relaxed(&mut *current_state); + for (_,range) in alloc.alloc_ranges.borrow_mut().iter_mut(offset, size) { + if range.load_relaxed(&mut *current_state, current_thread) == Err(DataRace) { + mem::drop(current_state); + return VClockAlloc::report_data_race( + &alloc.global, range, "ATOMIC_LOAD", true, + place.ptr.assert_ptr(), size + ); + } } }else{ // Perform acquire(or seq-cst) atomic load - for (_,range) in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { - range.acquire(&mut *current_state); + for (_,range) in alloc.alloc_ranges.borrow_mut().iter_mut(offset, size) { + if range.acquire(&mut *current_state, current_thread) == Err(DataRace) { + mem::drop(current_state); + return VClockAlloc::report_data_race( + &alloc.global, range, "ATOMIC_LOAD", true, + place.ptr.assert_ptr(), size + ); + } } } // Log changes to atomic memory if log::log_enabled!(log::Level::Trace) { - for (_,range) in alloc.alloc_ranges.get_mut().iter(offset, size) { + for (_,range) in alloc.alloc_ranges.borrow_mut().iter(offset, size) { log::trace!( " updated atomic memory({:?}, offset={}, size={}) to {:#?}", place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes(), @@ -195,7 +258,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - std::mem::drop(current_state); + mem::drop(current_state); let data_race = &*this.memory.extra.data_race; data_race.advance_vector_clock(); } @@ -214,7 +277,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ( alloc, size, offset - ) = this.load_data_race_state(place)?; + ) = this.load_data_race_state_mut(place)?; let current_thread = alloc.global.current_thread(); let mut current_state = alloc.global.current_thread_state_mut(); log::trace!( @@ -226,12 +289,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if atomic == AtomicWriteOp::Relaxed { // Perform relaxed atomic store for (_,range) in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { - range.store_relaxed(&mut *current_state, current_thread); + if range.store_relaxed(&mut *current_state, current_thread) == Err(DataRace) { + mem::drop(current_state); + return VClockAlloc::report_data_race( + &alloc.global, range, "ATOMIC_STORE", true, + place.ptr.assert_ptr(), size + ); + } } }else{ // Perform release(or seq-cst) atomic store for (_,range) in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { - range.release(&mut *current_state, current_thread); + if range.release(&mut *current_state, current_thread) == Err(DataRace) { + mem::drop(current_state); + return VClockAlloc::report_data_race( + &alloc.global, range, "ATOMIC_STORE", true, + place.ptr.assert_ptr(), size + ); + } } } @@ -246,7 +321,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - std::mem::drop(current_state); + mem::drop(current_state); let data_race = &*this.memory.extra.data_race; data_race.advance_vector_clock(); } @@ -266,7 +341,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ( alloc, size, offset - ) = this.load_data_race_state(place)?; + ) = this.load_data_race_state_mut(place)?; let current_thread = alloc.global.current_thread(); let mut current_state = alloc.global.current_thread_state_mut(); log::trace!( @@ -280,17 +355,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx for (_,range) in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { //FIXME: this is probably still slightly wrong due to the quirks // in the c++11 memory model - if acquire { + let maybe_race = if acquire { // Atomic RW-Op acquire - range.acquire(&mut *current_state); + range.acquire(&mut *current_state, current_thread) }else{ - range.load_relaxed(&mut *current_state); + range.load_relaxed(&mut *current_state, current_thread) + }; + if maybe_race == Err(DataRace) { + mem::drop(current_state); + return VClockAlloc::report_data_race( + &alloc.global, range, "ATOMIC_RMW(LOAD)", true, + place.ptr.assert_ptr(), size + ); } - if release { + let maybe_race = if release { // Atomic RW-Op release - range.rmw_release(&mut *current_state, current_thread); + range.rmw_release(&mut *current_state, current_thread) }else{ - range.rmw_relaxed(&mut *current_state); + range.rmw_relaxed(&mut *current_state, current_thread) + }; + if maybe_race == Err(DataRace) { + mem::drop(current_state); + return VClockAlloc::report_data_race( + &alloc.global, range, "ATOMIC_RMW(STORE)", true, + place.ptr.assert_ptr(), size + ); } } @@ -305,7 +394,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - std::mem::drop(current_state); + mem::drop(current_state); let data_race = &*this.memory.extra.data_race; data_race.advance_vector_clock(); } @@ -478,6 +567,11 @@ impl Debug for AtomicReleaseSequences { } } +/// Error returned by finding a data race +/// should be elaborated upon +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub struct DataRace; + /// Externally stored memory cell clocks /// explicitly to reduce memory usage for the /// common case where no atomic operations @@ -485,11 +579,26 @@ impl Debug for AtomicReleaseSequences { #[derive(Clone, PartialEq, Eq, Debug)] struct AtomicMemoryCellClocks { + /// The clock-vector for the set of atomic read operations + /// used for detecting data-races with non-atomic write + /// operations + read_vector: VClock, + + /// The clock-vector for the set of atomic write operations + /// used for detecting data-races with non-atomic read or + /// write operations + write_vector: VClock, + /// Synchronization vector for acquire-release semantics + /// contains the vector of timestamps that will + /// happen-before a thread if an acquire-load is + /// performed on the data sync_vector: VClock, /// The Hash-Map of all threads for which a release - /// sequence exists in the memory cell + /// sequence exists in the memory cell, required + /// since read-modify-write operations do not + /// invalidate existing release sequences release_sequences: AtomicReleaseSequences, } @@ -498,10 +607,12 @@ struct AtomicMemoryCellClocks { #[derive(Clone, PartialEq, Eq, Debug)] struct MemoryCellClocks { - /// The vector-clock of the last write + /// The vector-clock of the last write, only one value is stored + /// since all previous writes happened-before the current write write: Timestamp, - /// The id of the thread that performed the last write to this memory location + /// The identifier of the thread that performed the last write + /// operation write_thread: ThreadId, /// The vector-clock of the set of previous reads @@ -532,7 +643,7 @@ impl MemoryCellClocks { /// Load the internal atomic memory cells if they exist #[inline] - fn atomic(&mut self) -> Option<&AtomicMemoryCellClocks> { + fn atomic(&self) -> Option<&AtomicMemoryCellClocks> { match &self.atomic_ops { Some(op) => Some(&*op), None => None @@ -545,6 +656,8 @@ impl MemoryCellClocks { fn atomic_mut(&mut self) -> &mut AtomicMemoryCellClocks { self.atomic_ops.get_or_insert_with(|| { Box::new(AtomicMemoryCellClocks { + read_vector: VClock::default(), + write_vector: VClock::default(), sync_vector: VClock::default(), release_sequences: AtomicReleaseSequences::new() }) @@ -554,75 +667,131 @@ impl MemoryCellClocks { /// Update memory cell data-race tracking for atomic /// load acquire semantics, is a no-op if this memory was /// not used previously as atomic memory - fn acquire(&mut self, clocks: &mut ThreadClockSet) { + fn acquire(&mut self, clocks: &mut ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { + self.atomic_read_detect(clocks, thread)?; if let Some(atomic) = self.atomic() { clocks.clock.join(&atomic.sync_vector); } + Ok(()) } /// Update memory cell data-race tracking for atomic /// load relaxed semantics, is a no-op if this memory was /// not used previously as atomic memory - fn load_relaxed(&mut self, clocks: &mut ThreadClockSet) { + fn load_relaxed(&mut self, clocks: &mut ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { + self.atomic_read_detect(clocks, thread)?; if let Some(atomic) = self.atomic() { clocks.fence_acquire.join(&atomic.sync_vector); } + Ok(()) } /// Update the memory cell data-race tracking for atomic /// store release semantics - fn release(&mut self, clocks: &ThreadClockSet, thread: ThreadId) { + fn release(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { + self.atomic_write_detect(clocks, thread)?; let atomic = self.atomic_mut(); atomic.sync_vector.set_values(&clocks.clock); atomic.release_sequences.clear_and_set(thread, &clocks.clock); + Ok(()) } /// Update the memory cell data-race tracking for atomic /// store relaxed semantics - fn store_relaxed(&mut self, clocks: &ThreadClockSet, thread: ThreadId) { + fn store_relaxed(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { + self.atomic_write_detect(clocks, thread)?; let atomic = self.atomic_mut(); atomic.sync_vector.set_values(&clocks.fence_release); if let Some(release) = atomic.release_sequences.load(thread) { atomic.sync_vector.join(release); } atomic.release_sequences.clear_and_retain(thread); + Ok(()) } /// Update the memory cell data-race tracking for atomic /// store release semantics for RMW operations - fn rmw_release(&mut self, clocks: &ThreadClockSet, thread: ThreadId) { + fn rmw_release(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { + self.atomic_write_detect(clocks, thread)?; let atomic = self.atomic_mut(); atomic.sync_vector.join(&clocks.clock); atomic.release_sequences.insert(thread, &clocks.clock); + Ok(()) } /// Update the memory cell data-race tracking for atomic /// store relaxed semantics for RMW operations - fn rmw_relaxed(&mut self, clocks: &ThreadClockSet) { + fn rmw_relaxed(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { + self.atomic_write_detect(clocks, thread)?; let atomic = self.atomic_mut(); atomic.sync_vector.join(&clocks.fence_release); + Ok(()) } - + /// Detect data-races with an atomic read, caused by a non-atomic write that does + /// not happen-before the atomic-read + fn atomic_read_detect(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { + log::trace!("Atomic read with vectors: {:#?} :: {:#?}", self, clocks); + if self.write <= clocks.clock[self.write_thread] { + let atomic = self.atomic_mut(); + atomic.read_vector.set_at_thread(&clocks.clock, thread); + Ok(()) + }else{ + Err(DataRace) + } + } + + /// Detect data-races with an atomic write, either with a non-atomic read or with + /// a non-atomic write: + fn atomic_write_detect(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { + log::trace!("Atomic write with vectors: {:#?} :: {:#?}", self, clocks); + if self.write <= clocks.clock[self.write_thread] && self.read <= clocks.clock { + let atomic = self.atomic_mut(); + atomic.write_vector.set_at_thread(&clocks.clock, thread); + Ok(()) + }else{ + Err(DataRace) + } + } /// Detect races for non-atomic read operations at the current memory cell /// returns true if a data-race is detected - fn read_race_detect(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> bool { + fn read_race_detect(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { + log::trace!("Unsynchronized read with vectors: {:#?} :: {:#?}", self, clocks); if self.write <= clocks.clock[self.write_thread] { - self.read.set_at_thread(&clocks.clock, thread); - false + let race_free = if let Some(atomic) = self.atomic() { + atomic.write_vector <= clocks.clock + }else{ + true + }; + if race_free { + self.read.set_at_thread(&clocks.clock, thread); + Ok(()) + }else{ + Err(DataRace) + } }else{ - true + Err(DataRace) } } /// Detect races for non-atomic write operations at the current memory cell /// returns true if a data-race is detected - fn write_race_detect(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> bool { + fn write_race_detect(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { + log::trace!("Unsynchronized write with vectors: {:#?} :: {:#?}", self, clocks); if self.write <= clocks.clock[self.write_thread] && self.read <= clocks.clock { - self.write = clocks.clock[thread]; - self.write_thread = thread; - self.read.set_zero_vector(); - false + let race_free = if let Some(atomic) = self.atomic() { + atomic.write_vector <= clocks.clock && atomic.read_vector <= clocks.clock + }else{ + true + }; + if race_free { + self.write = clocks.clock[thread]; + self.write_thread = thread; + self.read.set_zero_vector(); + Ok(()) + }else{ + Err(DataRace) + } }else{ - true + Err(DataRace) } } } @@ -651,6 +820,33 @@ impl VClockAlloc { } } + // Find an index, if one exists where the value + // in `l` is greater than the value in `r` + fn find_gt_index(l: &VClock, r: &VClock) -> Option { + let l_slice = l.as_slice(); + let r_slice = r.as_slice(); + l_slice.iter().zip(r_slice.iter()) + .enumerate() + .find_map(|(idx, (&l, &r))| { + if l > r { Some(idx) } else { None } + }).or_else(|| { + if l_slice.len() > r_slice.len() { + // By invariant, if l_slice is longer + // then one element must be larger + // This just validates that this is true + // and reports earlier elements first + let l_remainder_slice = &l_slice[r_slice.len()..]; + let idx = l_remainder_slice.iter().enumerate() + .find_map(|(idx, &r)| { + if r == 0 { None } else { Some(idx) } + }).expect("Invalid VClock Invariant"); + Some(idx) + }else{ + None + } + }) + } + /// Report a data-race found in the program /// this finds the two racing threads and the type /// of data-race that occured, this will also @@ -659,7 +855,8 @@ impl VClockAlloc { #[cold] #[inline(never)] fn report_data_race<'tcx>( - global: &MemoryExtra, range: &MemoryCellClocks, action: &str, + global: &MemoryExtra, range: &MemoryCellClocks, + action: &str, is_atomic: bool, pointer: Pointer, len: Size ) -> InterpResult<'tcx> { let current_thread = global.current_thread(); @@ -669,40 +866,39 @@ impl VClockAlloc { other_action, other_thread, other_clock ) = if range.write > current_state.clock[range.write_thread] { - // Create effective write-clock that the data-race occured with + // Convert the write action into the vector clock it + // represents for diagnostic purposes let wclock = write_clock.get_mut_with_min_len( current_state.clock.as_slice().len() .max(range.write_thread.to_u32() as usize + 1) ); wclock[range.write_thread.to_u32() as usize] = range.write; ("WRITE", range.write_thread, write_clock.as_slice()) + }else if let Some(idx) = Self::find_gt_index( + &range.read, ¤t_state.clock + ){ + ("READ", ThreadId::new(idx), range.read.as_slice()) + }else if !is_atomic { + if let Some(atomic) = range.atomic() { + if let Some(idx) = Self::find_gt_index( + &atomic.write_vector, ¤t_state.clock + ) { + ("ATOMIC_STORE", ThreadId::new(idx), atomic.write_vector.as_slice()) + }else if let Some(idx) = Self::find_gt_index( + &atomic.read_vector, ¤t_state.clock + ) { + ("ATOMIC_LOAD", ThreadId::new(idx), atomic.read_vector.as_slice()) + }else{ + unreachable!("Failed to find report data-race for non-atomic operation: no race found") + } + }else{ + unreachable!("Failed to report data-race for non-atomic operation: no atomic component") + } }else{ - - // Find index in the read-clock that the data-race occured with - let read_slice = range.read.as_slice(); - let clock_slice = current_state.clock.as_slice(); - let conflicting_index = read_slice.iter() - .zip(clock_slice.iter()) - .enumerate().find_map(|(idx,(&read, &clock))| { - if read > clock { - Some(idx) - }else{ - None - } - }).unwrap_or_else(|| { - assert!(read_slice.len() > clock_slice.len(), "BUG: cannot find read race yet reported data-race"); - let rest_read = &read_slice[clock_slice.len()..]; - rest_read.iter().enumerate().find_map(|(idx, &val)| { - if val > 0 { - Some(idx + clock_slice.len()) - }else{ - None - } - }).expect("Invariant broken for read-slice, no 0 element at the tail") - }); - ("READ", ThreadId::new(conflicting_index), range.read.as_slice()) + unreachable!("Failed to report data-race for atomic operation") }; + // Load elaborated thread information about the racing thread actions let current_thread_info = global.print_thread_metadata(current_thread); let other_thread_info = global.print_thread_metadata(other_thread); @@ -732,10 +928,10 @@ impl VClockAlloc { // to the ranges being tested, so this is ok let mut alloc_ranges = self.alloc_ranges.borrow_mut(); for (_,range) in alloc_ranges.iter_mut(pointer.offset, len) { - if range.read_race_detect(&*current_state, current_thread) { + if range.read_race_detect(&*current_state, current_thread) == Err(DataRace) { // Report data-race return Self::report_data_race( - &self.global,range, "READ", pointer, len + &self.global,range, "READ", false, pointer, len ); } } @@ -753,10 +949,10 @@ impl VClockAlloc { let current_thread = self.global.current_thread(); let current_state = self.global.current_thread_state(); for (_,range) in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { - if range.write_race_detect(&*current_state, current_thread) { + if range.write_race_detect(&*current_state, current_thread) == Err(DataRace) { // Report data-race return Self::report_data_race( - &self.global, range, "WRITE", pointer, len + &self.global, range, "WRITE", false, pointer, len ); } } @@ -774,10 +970,10 @@ impl VClockAlloc { let current_thread = self.global.current_thread(); let current_state = self.global.current_thread_state(); for (_,range) in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { - if range.write_race_detect(&*current_state, current_thread) { + if range.write_race_detect(&*current_state, current_thread) == Err(DataRace) { // Report data-race return Self::report_data_race( - &self.global, range, "DEALLOCATE", pointer, len + &self.global, range, "DEALLOCATE", false, pointer, len ); } } diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 9d124872f5cc..67cea5507737 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -78,7 +78,10 @@ pub fn futex<'tcx>( // Read an `i32` through the pointer, regardless of any wrapper types. // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`. // FIXME: this fails if `addr` is not a pointer type. - let futex_val = this.read_scalar_at_offset(addr.into(), 0, this.machine.layouts.i32)?.to_i32()?; + // FIXME: what form of atomic operation should the `futex` use to load the value? + let futex_val = this.read_scalar_at_offset_atomic( + addr.into(), 0, this.machine.layouts.i32, AtomicReadOp::Acquire + )?.to_i32()?; if val == futex_val { // The value still matches, so we block the trait make it wait for FUTEX_WAKE. this.block_thread(thread); diff --git a/tests/compile-fail/data_race/atomic_read_write_race.rs b/tests/compile-fail/data_race/atomic_read_write_race.rs new file mode 100644 index 000000000000..0b9610edc64b --- /dev/null +++ b/tests/compile-fail/data_race/atomic_read_write_race.rs @@ -0,0 +1,31 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +#![feature(core_intrinsics)] + +use std::thread::spawn; +use std::sync::atomic::AtomicUsize; +use std::intrinsics::atomic_load; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + let mut a = AtomicUsize::new(0); + let b = &mut a as *mut AtomicUsize; + let c = EvilSend(b); + unsafe { + let j1 = spawn(move || { + *(c.0 as *mut usize) = 32; + }); + + let j2 = spawn(move || { + //Equivalent to: (&*c.0).load(Ordering::SeqCst) + atomic_load(c.0 as *mut usize) //~ ERROR Data race + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/compile-fail/data_race/atomic_read_write_race_alt.rs b/tests/compile-fail/data_race/atomic_read_write_race_alt.rs new file mode 100644 index 000000000000..779babefd8e6 --- /dev/null +++ b/tests/compile-fail/data_race/atomic_read_write_race_alt.rs @@ -0,0 +1,31 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +use std::thread::spawn; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + let mut a = AtomicUsize::new(0); + let b = &mut a as *mut AtomicUsize; + let c = EvilSend(b); + unsafe { + let j1 = spawn(move || { + let atomic_ref = &mut *c.0; + atomic_ref.load(Ordering::SeqCst) + }); + + let j2 = spawn(move || { + let atomic_ref = &mut *c.0; + *atomic_ref.get_mut() = 32; //~ ERROR Data race + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/compile-fail/data_race/atomic_write_read_race.rs b/tests/compile-fail/data_race/atomic_write_read_race.rs new file mode 100644 index 000000000000..3211a5ae5344 --- /dev/null +++ b/tests/compile-fail/data_race/atomic_write_read_race.rs @@ -0,0 +1,31 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +use std::thread::spawn; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + let mut a = AtomicUsize::new(0); + let b = &mut a as *mut AtomicUsize; + let c = EvilSend(b); + unsafe { + let j1 = spawn(move || { + let atomic_ref = &mut *c.0; + atomic_ref.store(32, Ordering::SeqCst) + }); + + let j2 = spawn(move || { + let atomic_ref = &mut *c.0; + *atomic_ref.get_mut() //~ ERROR Data race + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/compile-fail/data_race/atomic_write_read_race_alt.rs b/tests/compile-fail/data_race/atomic_write_read_race_alt.rs new file mode 100644 index 000000000000..131d4e07b829 --- /dev/null +++ b/tests/compile-fail/data_race/atomic_write_read_race_alt.rs @@ -0,0 +1,31 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +#![feature(core_intrinsics)] + +use std::thread::spawn; +use std::sync::atomic::AtomicUsize; +use std::intrinsics::atomic_store; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + let mut a = AtomicUsize::new(0); + let b = &mut a as *mut AtomicUsize; + let c = EvilSend(b); + unsafe { + let j1 = spawn(move || { + *(c.0 as *mut usize) + }); + + let j2 = spawn(move || { + //Equivalent to: (&*c.0).store(32, Ordering::SeqCst) + atomic_store(c.0 as *mut usize, 32); //~ ERROR Data race + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/compile-fail/data_race/atomic_write_write_race.rs b/tests/compile-fail/data_race/atomic_write_write_race.rs new file mode 100644 index 000000000000..74adf7ae4b8d --- /dev/null +++ b/tests/compile-fail/data_race/atomic_write_write_race.rs @@ -0,0 +1,31 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +#![feature(core_intrinsics)] + +use std::thread::spawn; +use std::sync::atomic::AtomicUsize; +use std::intrinsics::atomic_store; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + let mut a = AtomicUsize::new(0); + let b = &mut a as *mut AtomicUsize; + let c = EvilSend(b); + unsafe { + let j1 = spawn(move || { + *(c.0 as *mut usize) = 32; + }); + + let j2 = spawn(move || { + //Equivalent to: (&*c.0).store(64, Ordering::SeqCst) + atomic_store(c.0 as *mut usize, 64); //~ ERROR Data race + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/compile-fail/data_race/atomic_write_write_race_alt.rs b/tests/compile-fail/data_race/atomic_write_write_race_alt.rs new file mode 100644 index 000000000000..75ad755fbd2c --- /dev/null +++ b/tests/compile-fail/data_race/atomic_write_write_race_alt.rs @@ -0,0 +1,31 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +use std::thread::spawn; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + let mut a = AtomicUsize::new(0); + let b = &mut a as *mut AtomicUsize; + let c = EvilSend(b); + unsafe { + let j1 = spawn(move || { + let atomic_ref = &mut *c.0; + atomic_ref.store(64, Ordering::SeqCst); + }); + + let j2 = spawn(move || { + let atomic_ref = &mut *c.0; + *atomic_ref.get_mut() = 32; //~ ERROR Data race + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} From 9cb6b8da3f6ca2da1139c91754d520bf2d354f31 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Thu, 5 Nov 2020 03:54:39 +0000 Subject: [PATCH 2433/5092] Split out vector_clock to separate file, general tidy up of some of the code & add support for vector index re-use for multiple threads after termination. --- src/data_race.rs | 1333 +++++++++++++-------------------------- src/lib.rs | 4 + src/shims/intrinsics.rs | 31 +- src/shims/posix/sync.rs | 39 +- src/thread.rs | 4 +- src/vector_clock.rs | 602 ++++++++++++++++++ 6 files changed, 1084 insertions(+), 929 deletions(-) create mode 100644 src/vector_clock.rs diff --git a/src/data_race.rs b/src/data_race.rs index 8e7a3548f5cf..e992c5a1d589 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -13,21 +13,21 @@ //! - 1 of the operations happens-before the other operation (see link for definition) use std::{ - fmt::{self, Debug}, cmp::Ordering, rc::Rc, - cell::{Cell, RefCell, Ref, RefMut}, ops::Index, mem + fmt::Debug, rc::Rc, + cell::{Cell, RefCell, Ref, RefMut}, mem }; use rustc_index::vec::{Idx, IndexVec}; use rustc_target::abi::Size; use rustc_middle::ty::layout::TyAndLayout; -use rustc_data_structures::fx::FxHashMap; - -use smallvec::SmallVec; +use rustc_data_structures::fx::FxHashSet; use crate::{ - MiriEvalContext, ThreadId, Tag, MiriEvalContextExt, RangeMap, - MPlaceTy, ImmTy, InterpResult, Pointer, ScalarMaybeUninit, - OpTy, Immediate, MemPlaceMeta + MiriEvalContext, MiriEvalContextExt, + ThreadId, Tag, RangeMap, + InterpResult, Pointer, ScalarMaybeUninit, + MPlaceTy, OpTy, MemPlaceMeta, + VClock, VSmallClockSet, VectorIdx, VTimestamp }; pub type AllocExtra = VClockAlloc; @@ -73,194 +73,136 @@ pub enum AtomicFenceOp { impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { - /// Variant of `read_immediate` that does not perform `data-race` checks. - fn read_immediate_racy(&self, op: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { + // Temporarily allow data-races to occur, this should only be + // used if either one of the appropiate `validate_atomic` functions + // will be called to treat a memory access as atomic or if the memory + // being accessed should be treated as internal state, that cannot be + // accessed by the interpreted program. + #[inline] + fn allow_data_races_ref(&self, op: impl FnOnce(&MiriEvalContext<'mir, 'tcx>) -> R) -> R { let this = self.eval_context_ref(); let data_race = &*this.memory.extra.data_race; - let old = data_race.multi_threaded.replace(false); - let res = this.read_immediate(op.into()); + let result = op(this); data_race.multi_threaded.set(old); - - res + result } - - /// Variant of `write_immediate` that does not perform `data-race` checks. - fn write_immediate_racy( - &mut self, src: Immediate, dest: MPlaceTy<'tcx, Tag> - ) -> InterpResult<'tcx> { + + /// Same as `allow_data_races_ref`, this temporarily disables any data-race detection and + /// so should only be used for atomic operations or internal state that the program cannot + /// access + #[inline] + fn allow_data_races_mut(&mut self, op: impl FnOnce(&mut MiriEvalContext<'mir, 'tcx>) -> R) -> R { let this = self.eval_context_mut(); let data_race = &*this.memory.extra.data_race; let old = data_race.multi_threaded.replace(false); - - let imm = this.write_immediate(src, dest.into()); - + let result = op(this); let data_race = &*this.memory.extra.data_race; data_race.multi_threaded.set(old); - imm + result } - /// Variant of `read_scalar` that does not perform data-race checks. - fn read_scalar_racy( - &self, op: MPlaceTy<'tcx, Tag> - )-> InterpResult<'tcx, ScalarMaybeUninit> { - Ok(self.read_immediate_racy(op)?.to_scalar_or_uninit()) - } - /// Variant of `write_scalar` that does not perform data-race checks. - fn write_scalar_racy( - &mut self, val: ScalarMaybeUninit, dest: MPlaceTy<'tcx, Tag> - ) -> InterpResult<'tcx> { - self.write_immediate_racy(Immediate::Scalar(val.into()), dest) - } - - /// Variant of `read_scalar_at_offset` helper function that does not perform - /// `data-race checks. - fn read_scalar_at_offset_racy( - &self, - op: OpTy<'tcx, Tag>, - offset: u64, - layout: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { - let this = self.eval_context_ref(); - let op_place = this.deref_operand(op)?; - let offset = Size::from_bytes(offset); - // Ensure that the following read at an offset is within bounds - assert!(op_place.layout.size >= offset + layout.size); - let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; - this.read_scalar_racy(value_place.into()) - } - - /// Variant of `write_scalar_at_offfset` helper function that performs - /// an atomic load operation with verification instead fn read_scalar_at_offset_atomic( - &mut self, + &self, op: OpTy<'tcx, Tag>, offset: u64, layout: TyAndLayout<'tcx>, atomic: AtomicReadOp ) -> InterpResult<'tcx, ScalarMaybeUninit> { - let this = self.eval_context_mut(); + let this = self.eval_context_ref(); let op_place = this.deref_operand(op)?; let offset = Size::from_bytes(offset); // Ensure that the following read at an offset is within bounds assert!(op_place.layout.size >= offset + layout.size); let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; - let res = this.read_scalar_racy(value_place.into())?; - this.validate_atomic_load(value_place, atomic)?; - Ok(res) + this.read_scalar_atomic(value_place, atomic) } - - /// Variant of `write_scalar_at_offfset` helper function that does not perform - /// data-race checks. - fn write_scalar_at_offset_racy( + fn write_scalar_at_offset_atomic( &mut self, op: OpTy<'tcx, Tag>, offset: u64, value: impl Into>, layout: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, ()> { + atomic: AtomicWriteOp + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let op_place = this.deref_operand(op)?; let offset = Size::from_bytes(offset); // Ensure that the following read at an offset is within bounds assert!(op_place.layout.size >= offset + layout.size); let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; - this.write_scalar_racy(value.into(), value_place.into()) + this.write_scalar_atomic(value.into(), value_place, atomic) } - - /// Load the data race allocation state for a given memory place - /// also returns the size and offset of the result in the allocation - /// metadata - /// This is used for atomic loads since unconditionally requesteing - /// mutable access causes issues for read-only memory, which will - /// fail validation on mutable access - fn load_data_race_state_ref<'a>( - &'a self, place: MPlaceTy<'tcx, Tag> - ) -> InterpResult<'tcx, (&'a VClockAlloc, Size, Size)> where 'mir: 'a { - let this = self.eval_context_ref(); - - let ptr = place.ptr.assert_ptr(); - let size = place.layout.size; - let data_race = &this.memory.get_raw(ptr.alloc_id)?.extra.data_race; - - Ok((data_race, size, ptr.offset)) + fn read_scalar_atomic( + &self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicReadOp + ) -> InterpResult<'tcx, ScalarMaybeUninit> { + let scalar = self.allow_data_races_ref(move |this| { + this.read_scalar(place.into()) + })?; + self.validate_atomic_load(place, atomic)?; + Ok(scalar) } - - /// Load the data race allocation state for a given memory place - /// also returns the size and the offset of the result in the allocation - /// metadata - fn load_data_race_state_mut<'a>( - &'a mut self, place: MPlaceTy<'tcx, Tag> - ) -> InterpResult<'tcx, (&'a mut VClockAlloc, Size, Size)> where 'mir: 'a { - let this = self.eval_context_mut(); - - let ptr = place.ptr.assert_ptr(); - let size = place.layout.size; - let data_race = &mut this.memory.get_raw_mut(ptr.alloc_id)?.extra.data_race; - - Ok((data_race, size, ptr.offset)) + fn write_scalar_atomic( + &mut self, val: ScalarMaybeUninit, dest: MPlaceTy<'tcx, Tag>, + atomic: AtomicWriteOp + ) -> InterpResult<'tcx> { + self.allow_data_races_mut(move |this| { + this.write_scalar(val, dest.into()) + })?; + self.validate_atomic_store(dest, atomic) } /// Update the data-race detector for an atomic read occuring at the /// associated memory-place and on the current thread fn validate_atomic_load( - &mut self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicReadOp + &self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicReadOp ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); + let this = self.eval_context_ref(); let data_race = &*this.memory.extra.data_race; if data_race.multi_threaded.get() { - data_race.advance_vector_clock(); - let ( - alloc, size, offset - ) = this.load_data_race_state_ref(place)?; + // Load an log the atomic operation + // the memory access has to be `get_raw` since otherwise this despite only + // mutating MemoryExtra will still trigger errors on read-only memory + let place_ptr = place.ptr.assert_ptr(); + let size = place.layout.size; + let alloc_meta = &this.memory.get_raw(place_ptr.alloc_id)?.extra.data_race; log::trace!( - "Atomic load on {:?} with ordering {:?}, in memory({:?}, offset={}, size={})", - alloc.global.current_thread(), atomic, - place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes() + "Atomic op({}) with ordering {:?} on memory({:?}, offset={}, size={})", + "Atomic load", &atomic, place_ptr.alloc_id, place_ptr.offset.bytes(), size.bytes() ); - let current_thread = alloc.global.current_thread(); - let mut current_state = alloc.global.current_thread_state_mut(); - if atomic == AtomicReadOp::Relaxed { - // Perform relaxed atomic load - for (_,range) in alloc.alloc_ranges.borrow_mut().iter_mut(offset, size) { - if range.load_relaxed(&mut *current_state, current_thread) == Err(DataRace) { - mem::drop(current_state); + // Perform the atomic operation + let data_race = &alloc_meta.global; + data_race.maybe_perform_sync_operation(move |index, mut clocks| { + for (_,range) in alloc_meta.alloc_ranges.borrow_mut().iter_mut(place_ptr.offset, size) { + let res = if atomic == AtomicReadOp::Relaxed { + range.load_relaxed(&mut *clocks, index) + }else{ + range.acquire(&mut *clocks, index) + }; + if let Err(DataRace) = res { + mem::drop(clocks); return VClockAlloc::report_data_race( - &alloc.global, range, "ATOMIC_LOAD", true, - place.ptr.assert_ptr(), size + &alloc_meta.global, range, "Atomic load", true, + place_ptr, size ); } } - }else{ - // Perform acquire(or seq-cst) atomic load - for (_,range) in alloc.alloc_ranges.borrow_mut().iter_mut(offset, size) { - if range.acquire(&mut *current_state, current_thread) == Err(DataRace) { - mem::drop(current_state); - return VClockAlloc::report_data_race( - &alloc.global, range, "ATOMIC_LOAD", true, - place.ptr.assert_ptr(), size - ); - } - } - } + Ok(()) + })?; // Log changes to atomic memory if log::log_enabled!(log::Level::Trace) { - for (_,range) in alloc.alloc_ranges.borrow_mut().iter(offset, size) { + for (_,range) in alloc_meta.alloc_ranges.borrow().iter(place_ptr.offset, size) { log::trace!( - " updated atomic memory({:?}, offset={}, size={}) to {:#?}", - place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes(), + "Updated atomic memory({:?}, offset={}, size={}) to {:#?}", + place.ptr.assert_ptr().alloc_id, place_ptr.offset.bytes(), size.bytes(), range.atomic_ops ); } } - - mem::drop(current_state); - let data_race = &*this.memory.extra.data_race; - data_race.advance_vector_clock(); } Ok(()) } @@ -271,61 +213,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { &mut self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicWriteOp ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let data_race = &*this.memory.extra.data_race; - if data_race.multi_threaded.get() { - data_race.advance_vector_clock(); - - let ( - alloc, size, offset - ) = this.load_data_race_state_mut(place)?; - let current_thread = alloc.global.current_thread(); - let mut current_state = alloc.global.current_thread_state_mut(); - log::trace!( - "Atomic store on {:?} with ordering {:?}, in memory({:?}, offset={}, size={})", - current_thread, atomic, - place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes() - ); - - if atomic == AtomicWriteOp::Relaxed { - // Perform relaxed atomic store - for (_,range) in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { - if range.store_relaxed(&mut *current_state, current_thread) == Err(DataRace) { - mem::drop(current_state); - return VClockAlloc::report_data_race( - &alloc.global, range, "ATOMIC_STORE", true, - place.ptr.assert_ptr(), size - ); - } - } - }else{ - // Perform release(or seq-cst) atomic store - for (_,range) in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { - if range.release(&mut *current_state, current_thread) == Err(DataRace) { - mem::drop(current_state); - return VClockAlloc::report_data_race( - &alloc.global, range, "ATOMIC_STORE", true, - place.ptr.assert_ptr(), size - ); - } + this.validate_atomic_op_mut( + place, atomic, "Atomic Store", + move |memory, clocks, index, atomic| { + if atomic == AtomicWriteOp::Relaxed { + memory.store_relaxed(clocks, index) + }else{ + memory.release(clocks, index) } } - - // Log changes to atomic memory - if log::log_enabled!(log::Level::Trace) { - for (_,range) in alloc.alloc_ranges.get_mut().iter(offset, size) { - log::trace!( - " updated atomic memory({:?}, offset={}, size={}) to {:#?}", - place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes(), - range.atomic_ops - ); - } - } - - mem::drop(current_state); - let data_race = &*this.memory.extra.data_race; - data_race.advance_vector_clock(); - } - Ok(()) + ) } /// Update the data-race detector for an atomic read-modify-write occuring @@ -334,97 +231,104 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { &mut self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicRWOp ) -> InterpResult<'tcx> { use AtomicRWOp::*; + let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); + let release = matches!(atomic, Release | AcqRel | SeqCst); let this = self.eval_context_mut(); - let data_race = &*this.memory.extra.data_race; - if data_race.multi_threaded.get() { - data_race.advance_vector_clock(); - - let ( - alloc, size, offset - ) = this.load_data_race_state_mut(place)?; - let current_thread = alloc.global.current_thread(); - let mut current_state = alloc.global.current_thread_state_mut(); - log::trace!( - "Atomic RMW on {:?} with ordering {:?}, in memory({:?}, offset={}, size={})", - current_thread, atomic, - place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes() - ); - - let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); - let release = matches!(atomic, Release | AcqRel | SeqCst); - for (_,range) in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { - //FIXME: this is probably still slightly wrong due to the quirks - // in the c++11 memory model - let maybe_race = if acquire { - // Atomic RW-Op acquire - range.acquire(&mut *current_state, current_thread) + this.validate_atomic_op_mut( + place, atomic, "Atomic RMW", + move |memory, clocks, index, _| { + if acquire { + memory.acquire(clocks, index)?; }else{ - range.load_relaxed(&mut *current_state, current_thread) - }; - if maybe_race == Err(DataRace) { - mem::drop(current_state); - return VClockAlloc::report_data_race( - &alloc.global, range, "ATOMIC_RMW(LOAD)", true, - place.ptr.assert_ptr(), size - ); + memory.load_relaxed(clocks, index)?; } - let maybe_race = if release { - // Atomic RW-Op release - range.rmw_release(&mut *current_state, current_thread) + if release { + memory.rmw_release(clocks, index) }else{ - range.rmw_relaxed(&mut *current_state, current_thread) - }; - if maybe_race == Err(DataRace) { - mem::drop(current_state); - return VClockAlloc::report_data_race( - &alloc.global, range, "ATOMIC_RMW(STORE)", true, - place.ptr.assert_ptr(), size - ); + memory.rmw_relaxed(clocks, index) } } - - // Log changes to atomic memory - if log::log_enabled!(log::Level::Trace) { - for (_,range) in alloc.alloc_ranges.get_mut().iter(offset, size) { - log::trace!( - " updated atomic memory({:?}, offset={}, size={}) to {:#?}", - place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes(), - range.atomic_ops - ); - } - } - - mem::drop(current_state); - let data_race = &*this.memory.extra.data_race; - data_race.advance_vector_clock(); - } - Ok(()) + ) } /// Update the data-race detector for an atomic fence on the current thread fn validate_atomic_fence(&mut self, atomic: AtomicFenceOp) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let data_race = &*this.memory.extra.data_race; - if data_race.multi_threaded.get() { - data_race.advance_vector_clock(); - - log::trace!("Atomic fence on {:?} with ordering {:?}", data_race.current_thread(), atomic); + data_race.maybe_perform_sync_operation(move |index, mut clocks| { + log::trace!("Atomic fence on {:?} with ordering {:?}", index, atomic); // Apply data-race detection for the current fences // this treats AcqRel and SeqCst as the same as a acquire // and release fence applied in the same timestamp. if atomic != AtomicFenceOp::Release { // Either Acquire | AcqRel | SeqCst - data_race.current_thread_state_mut().apply_acquire_fence(); + clocks.apply_acquire_fence(); } if atomic != AtomicFenceOp::Acquire { // Either Release | AcqRel | SeqCst - data_race.current_thread_state_mut().apply_release_fence(); + clocks.apply_release_fence(); } + Ok(()) + }) + } +} - data_race.advance_vector_clock(); +impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} +trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { + + /// Generic atomic operation implementation, this however + /// cannot be used for the atomic read operation since + /// that requires non mutable memory access to not trigger + /// the writing to read-only memory errors during `get_raw_mut` + fn validate_atomic_op_mut( + &mut self, place: MPlaceTy<'tcx, Tag>, + atomic: A, description: &str, + mut op: impl FnMut( + &mut MemoryCellClocks, &mut ThreadClockSet, VectorIdx, A + ) -> Result<(), DataRace> + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let data_race = &*this.memory.extra.data_race; + if data_race.multi_threaded.get() { + + // Load an log the atomic operation + let place_ptr = place.ptr.assert_ptr(); + let size = place.layout.size; + let alloc_meta = &mut this.memory.get_raw_mut(place_ptr.alloc_id)?.extra.data_race; + log::trace!( + "Atomic op({}) with ordering {:?} on memory({:?}, offset={}, size={})", + description, &atomic, place_ptr.alloc_id, place_ptr.offset.bytes(), size.bytes() + ); + + // Perform the atomic operation + let data_race = &alloc_meta.global; + data_race.maybe_perform_sync_operation(|index, mut clocks| { + for (_,range) in alloc_meta.alloc_ranges.borrow_mut().iter_mut(place_ptr.offset, size) { + if let Err(DataRace) = op(range, &mut *clocks, index, atomic) { + mem::drop(clocks); + return VClockAlloc::report_data_race( + &alloc_meta.global, range, description, true, + place_ptr, size + ); + } + } + Ok(()) + })?; + + // Log changes to atomic memory + if log::log_enabled!(log::Level::Trace) { + for (_,range) in alloc_meta.alloc_ranges.borrow().iter(place_ptr.offset, size) { + log::trace!( + "Updated atomic memory({:?}, offset={}, size={}) to {:#?}", + place.ptr.assert_ptr().alloc_id, place_ptr.offset.bytes(), size.bytes(), + range.atomic_ops + ); + } + } } Ok(()) } + } /// Handle for locks to express their @@ -439,7 +343,7 @@ pub struct DataRaceLockHandle { } impl DataRaceLockHandle { pub fn set_values(&mut self, other: &Self) { - self.clock.set_values(&other.clock) + self.clock.clone_from(&other.clock) } pub fn reset(&mut self) { self.clock.set_zero_vector(); @@ -447,126 +351,6 @@ impl DataRaceLockHandle { } -/// Avoid an atomic allocation for the common -/// case with atomic operations where the number -/// of active release sequences is small -#[derive(Clone, PartialEq, Eq)] -enum AtomicReleaseSequences { - - /// Contains one or no values - /// if empty: (None, reset vector clock) - /// if one: (Some(thread), thread_clock) - ReleaseOneOrEmpty(Option, VClock), - - /// Contains two or more values - /// stored in a hash-map of thread id to - /// vector clocks - ReleaseMany(FxHashMap) -} -impl AtomicReleaseSequences { - - /// Return an empty set of atomic release sequences - #[inline] - fn new() -> AtomicReleaseSequences { - Self::ReleaseOneOrEmpty(None, VClock::default()) - } - - /// Remove all values except for the value stored at `thread` and set - /// the vector clock to the associated `clock` value - #[inline] - fn clear_and_set(&mut self, thread: ThreadId, clock: &VClock) { - match self { - Self::ReleaseOneOrEmpty(id, rel_clock) => { - *id = Some(thread); - rel_clock.set_values(clock); - } - Self::ReleaseMany(_) => { - *self = Self::ReleaseOneOrEmpty(Some(thread), clock.clone()); - } - } - } - - /// Remove all values except for the value stored at `thread` - #[inline] - fn clear_and_retain(&mut self, thread: ThreadId) { - match self { - Self::ReleaseOneOrEmpty(id, rel_clock) => { - // If the id is the same, then reatin the value - // otherwise delete and clear the release vector clock - if *id != Some(thread) { - *id = None; - rel_clock.set_zero_vector(); - } - }, - Self::ReleaseMany(hash_map) => { - // Retain only the thread element, so reduce to size - // of 1 or 0, and move to smaller format - if let Some(clock) = hash_map.remove(&thread) { - *self = Self::ReleaseOneOrEmpty(Some(thread), clock); - }else{ - *self = Self::new(); - } - } - } - } - - /// Insert a release sequence at `thread` with values `clock` - fn insert(&mut self, thread: ThreadId, clock: &VClock) { - match self { - Self::ReleaseOneOrEmpty(id, rel_clock) => { - if id.map_or(true, |id| id == thread) { - *id = Some(thread); - rel_clock.set_values(clock); - }else{ - let mut hash_map = FxHashMap::default(); - hash_map.insert(thread, clock.clone()); - hash_map.insert(id.unwrap(), rel_clock.clone()); - *self = Self::ReleaseMany(hash_map); - } - }, - Self::ReleaseMany(hash_map) => { - hash_map.insert(thread, clock.clone()); - } - } - } - - /// Return the release sequence at `thread` if one exists - #[inline] - fn load(&self, thread: ThreadId) -> Option<&VClock> { - match self { - Self::ReleaseOneOrEmpty(id, clock) => { - if *id == Some(thread) { - Some(clock) - }else{ - None - } - }, - Self::ReleaseMany(hash_map) => { - hash_map.get(&thread) - } - } - } -} - -/// Custom debug implementation to correctly -/// print debug as a logical mapping from threads -/// to vector-clocks -impl Debug for AtomicReleaseSequences { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::ReleaseOneOrEmpty(None,_) => { - f.debug_map().finish() - }, - Self::ReleaseOneOrEmpty(Some(id), clock) => { - f.debug_map().entry(&id, &clock).finish() - }, - Self::ReleaseMany(hash_map) => { - Debug::fmt(hash_map, f) - } - } - } -} - /// Error returned by finding a data race /// should be elaborated upon #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] @@ -576,7 +360,7 @@ pub struct DataRace; /// explicitly to reduce memory usage for the /// common case where no atomic operations /// exists on the memory cell -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq, Default, Debug)] struct AtomicMemoryCellClocks { /// The clock-vector for the set of atomic read operations @@ -599,7 +383,7 @@ struct AtomicMemoryCellClocks { /// sequence exists in the memory cell, required /// since read-modify-write operations do not /// invalidate existing release sequences - release_sequences: AtomicReleaseSequences, + release_sequences: VSmallClockSet, } /// Memory Cell vector clock metadata @@ -609,11 +393,11 @@ struct MemoryCellClocks { /// The vector-clock of the last write, only one value is stored /// since all previous writes happened-before the current write - write: Timestamp, + write: VTimestamp, /// The identifier of the thread that performed the last write /// operation - write_thread: ThreadId, + write_index: VectorIdx, /// The vector-clock of the set of previous reads /// each index is set to the timestamp that the associated @@ -633,7 +417,7 @@ impl Default for MemoryCellClocks { MemoryCellClocks { read: VClock::default(), write: 0, - write_thread: ThreadId::new(u32::MAX as usize), + write_index: VectorIdx::MAX_INDEX, atomic_ops: None } } @@ -654,21 +438,14 @@ impl MemoryCellClocks { /// if it does not exist #[inline] fn atomic_mut(&mut self) -> &mut AtomicMemoryCellClocks { - self.atomic_ops.get_or_insert_with(|| { - Box::new(AtomicMemoryCellClocks { - read_vector: VClock::default(), - write_vector: VClock::default(), - sync_vector: VClock::default(), - release_sequences: AtomicReleaseSequences::new() - }) - }) + self.atomic_ops.get_or_insert_with(Default::default) } /// Update memory cell data-race tracking for atomic /// load acquire semantics, is a no-op if this memory was /// not used previously as atomic memory - fn acquire(&mut self, clocks: &mut ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { - self.atomic_read_detect(clocks, thread)?; + fn acquire(&mut self, clocks: &mut ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { + self.atomic_read_detect(clocks, index)?; if let Some(atomic) = self.atomic() { clocks.clock.join(&atomic.sync_vector); } @@ -677,8 +454,8 @@ impl MemoryCellClocks { /// Update memory cell data-race tracking for atomic /// load relaxed semantics, is a no-op if this memory was /// not used previously as atomic memory - fn load_relaxed(&mut self, clocks: &mut ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { - self.atomic_read_detect(clocks, thread)?; + fn load_relaxed(&mut self, clocks: &mut ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { + self.atomic_read_detect(clocks, index)?; if let Some(atomic) = self.atomic() { clocks.fence_acquire.join(&atomic.sync_vector); } @@ -688,38 +465,39 @@ impl MemoryCellClocks { /// Update the memory cell data-race tracking for atomic /// store release semantics - fn release(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { - self.atomic_write_detect(clocks, thread)?; + fn release(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { + self.atomic_write_detect(clocks, index)?; let atomic = self.atomic_mut(); - atomic.sync_vector.set_values(&clocks.clock); - atomic.release_sequences.clear_and_set(thread, &clocks.clock); + atomic.sync_vector.clone_from(&clocks.clock); + atomic.release_sequences.clear(); + atomic.release_sequences.insert(index, &clocks.clock); Ok(()) } /// Update the memory cell data-race tracking for atomic /// store relaxed semantics - fn store_relaxed(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { - self.atomic_write_detect(clocks, thread)?; + fn store_relaxed(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { + self.atomic_write_detect(clocks, index)?; let atomic = self.atomic_mut(); - atomic.sync_vector.set_values(&clocks.fence_release); - if let Some(release) = atomic.release_sequences.load(thread) { + atomic.sync_vector.clone_from(&clocks.fence_release); + if let Some(release) = atomic.release_sequences.get(index) { atomic.sync_vector.join(release); } - atomic.release_sequences.clear_and_retain(thread); + atomic.release_sequences.retain_index(index); Ok(()) } /// Update the memory cell data-race tracking for atomic /// store release semantics for RMW operations - fn rmw_release(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { - self.atomic_write_detect(clocks, thread)?; + fn rmw_release(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { + self.atomic_write_detect(clocks, index)?; let atomic = self.atomic_mut(); atomic.sync_vector.join(&clocks.clock); - atomic.release_sequences.insert(thread, &clocks.clock); + atomic.release_sequences.insert(index, &clocks.clock); Ok(()) } /// Update the memory cell data-race tracking for atomic /// store relaxed semantics for RMW operations - fn rmw_relaxed(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { - self.atomic_write_detect(clocks, thread)?; + fn rmw_relaxed(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { + self.atomic_write_detect(clocks, index)?; let atomic = self.atomic_mut(); atomic.sync_vector.join(&clocks.fence_release); Ok(()) @@ -727,11 +505,11 @@ impl MemoryCellClocks { /// Detect data-races with an atomic read, caused by a non-atomic write that does /// not happen-before the atomic-read - fn atomic_read_detect(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { + fn atomic_read_detect(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { log::trace!("Atomic read with vectors: {:#?} :: {:#?}", self, clocks); - if self.write <= clocks.clock[self.write_thread] { + if self.write <= clocks.clock[self.write_index] { let atomic = self.atomic_mut(); - atomic.read_vector.set_at_thread(&clocks.clock, thread); + atomic.read_vector.set_at_index(&clocks.clock, index); Ok(()) }else{ Err(DataRace) @@ -740,11 +518,11 @@ impl MemoryCellClocks { /// Detect data-races with an atomic write, either with a non-atomic read or with /// a non-atomic write: - fn atomic_write_detect(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { + fn atomic_write_detect(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { log::trace!("Atomic write with vectors: {:#?} :: {:#?}", self, clocks); - if self.write <= clocks.clock[self.write_thread] && self.read <= clocks.clock { + if self.write <= clocks.clock[self.write_index] && self.read <= clocks.clock { let atomic = self.atomic_mut(); - atomic.write_vector.set_at_thread(&clocks.clock, thread); + atomic.write_vector.set_at_index(&clocks.clock, index); Ok(()) }else{ Err(DataRace) @@ -753,16 +531,16 @@ impl MemoryCellClocks { /// Detect races for non-atomic read operations at the current memory cell /// returns true if a data-race is detected - fn read_race_detect(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { + fn read_race_detect(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { log::trace!("Unsynchronized read with vectors: {:#?} :: {:#?}", self, clocks); - if self.write <= clocks.clock[self.write_thread] { + if self.write <= clocks.clock[self.write_index] { let race_free = if let Some(atomic) = self.atomic() { atomic.write_vector <= clocks.clock }else{ true }; if race_free { - self.read.set_at_thread(&clocks.clock, thread); + self.read.set_at_index(&clocks.clock, index); Ok(()) }else{ Err(DataRace) @@ -774,17 +552,17 @@ impl MemoryCellClocks { /// Detect races for non-atomic write operations at the current memory cell /// returns true if a data-race is detected - fn write_race_detect(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { + fn write_race_detect(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { log::trace!("Unsynchronized write with vectors: {:#?} :: {:#?}", self, clocks); - if self.write <= clocks.clock[self.write_thread] && self.read <= clocks.clock { + if self.write <= clocks.clock[self.write_index] && self.read <= clocks.clock { let race_free = if let Some(atomic) = self.atomic() { atomic.write_vector <= clocks.clock && atomic.read_vector <= clocks.clock }else{ true }; if race_free { - self.write = clocks.clock[thread]; - self.write_thread = thread; + self.write = clocks.clock[index]; + self.write_index = index; self.read.set_zero_vector(); Ok(()) }else{ @@ -822,7 +600,7 @@ impl VClockAlloc { // Find an index, if one exists where the value // in `l` is greater than the value in `r` - fn find_gt_index(l: &VClock, r: &VClock) -> Option { + fn find_gt_index(l: &VClock, r: &VClock) -> Option { let l_slice = l.as_slice(); let r_slice = r.as_slice(); l_slice.iter().zip(r_slice.iter()) @@ -844,7 +622,7 @@ impl VClockAlloc { }else{ None } - }) + }).map(|idx| VectorIdx::new(idx)) } /// Report a data-race found in the program @@ -859,35 +637,29 @@ impl VClockAlloc { action: &str, is_atomic: bool, pointer: Pointer, len: Size ) -> InterpResult<'tcx> { - let current_thread = global.current_thread(); - let current_state = global.current_thread_state(); - let mut write_clock = VClock::default(); + let (current_index, current_clocks) = global.current_thread_state(); + let write_clock; let ( other_action, other_thread, other_clock - ) = if range.write > current_state.clock[range.write_thread] { - + ) = if range.write > current_clocks.clock[range.write_index] { // Convert the write action into the vector clock it // represents for diagnostic purposes - let wclock = write_clock.get_mut_with_min_len( - current_state.clock.as_slice().len() - .max(range.write_thread.to_u32() as usize + 1) - ); - wclock[range.write_thread.to_u32() as usize] = range.write; - ("WRITE", range.write_thread, write_clock.as_slice()) + write_clock = VClock::new_with_index(range.write_index, range.write); + ("WRITE", range.write_index, &write_clock) }else if let Some(idx) = Self::find_gt_index( - &range.read, ¤t_state.clock + &range.read, ¤t_clocks.clock ){ - ("READ", ThreadId::new(idx), range.read.as_slice()) + ("READ", idx, &range.read) }else if !is_atomic { if let Some(atomic) = range.atomic() { if let Some(idx) = Self::find_gt_index( - &atomic.write_vector, ¤t_state.clock + &atomic.write_vector, ¤t_clocks.clock ) { - ("ATOMIC_STORE", ThreadId::new(idx), atomic.write_vector.as_slice()) + ("ATOMIC_STORE", idx, &atomic.write_vector) }else if let Some(idx) = Self::find_gt_index( - &atomic.read_vector, ¤t_state.clock + &atomic.read_vector, ¤t_clocks.clock ) { - ("ATOMIC_LOAD", ThreadId::new(idx), atomic.read_vector.as_slice()) + ("ATOMIC_LOAD", idx, &atomic.read_vector) }else{ unreachable!("Failed to find report data-race for non-atomic operation: no race found") } @@ -899,7 +671,7 @@ impl VClockAlloc { }; // Load elaborated thread information about the racing thread actions - let current_thread_info = global.print_thread_metadata(current_thread); + let current_thread_info = global.print_thread_metadata(current_index); let other_thread_info = global.print_thread_metadata(other_thread); // Throw the data-race detection @@ -910,7 +682,7 @@ impl VClockAlloc { action, current_thread_info, other_action, other_thread_info, pointer.alloc_id, pointer.offset.bytes(), len.bytes(), - current_state.clock, + current_clocks.clock, other_clock ) } @@ -921,14 +693,10 @@ impl VClockAlloc { /// operation pub fn read<'tcx>(&self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { if self.global.multi_threaded.get() { - let current_thread = self.global.current_thread(); - let current_state = self.global.current_thread_state(); - - // The alloc-ranges are not split, however changes are not going to be made - // to the ranges being tested, so this is ok + let (index, clocks) = self.global.current_thread_state(); let mut alloc_ranges = self.alloc_ranges.borrow_mut(); for (_,range) in alloc_ranges.iter_mut(pointer.offset, len) { - if range.read_race_detect(&*current_state, current_thread) == Err(DataRace) { + if range.read_race_detect(&*clocks, index) == Err(DataRace) { // Report data-race return Self::report_data_race( &self.global,range, "READ", false, pointer, len @@ -946,10 +714,9 @@ impl VClockAlloc { /// operation pub fn write<'tcx>(&mut self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { if self.global.multi_threaded.get() { - let current_thread = self.global.current_thread(); - let current_state = self.global.current_thread_state(); + let (index, clocks) = self.global.current_thread_state(); for (_,range) in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { - if range.write_race_detect(&*current_state, current_thread) == Err(DataRace) { + if range.write_race_detect(&*clocks, index) == Err(DataRace) { // Report data-race return Self::report_data_race( &self.global, range, "WRITE", false, pointer, len @@ -967,10 +734,9 @@ impl VClockAlloc { /// operation pub fn deallocate<'tcx>(&mut self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { if self.global.multi_threaded.get() { - let current_thread = self.global.current_thread(); - let current_state = self.global.current_thread_state(); + let (index, clocks) = self.global.current_thread_state(); for (_,range) in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { - if range.write_race_detect(&*current_state, current_thread) == Err(DataRace) { + if range.write_race_detect(&*clocks, index) == Err(DataRace) { // Report data-race return Self::report_data_race( &self.global, range, "DEALLOCATE", false, pointer, len @@ -989,6 +755,7 @@ impl VClockAlloc { /// additional metadata to model atomic fence operations #[derive(Clone, Default, Debug)] struct ThreadClockSet { + /// The increasing clock representing timestamps /// that happen-before this thread. clock: VClock, @@ -1008,7 +775,7 @@ impl ThreadClockSet { /// set of thread vector clocks #[inline] fn apply_release_fence(&mut self) { - self.fence_release.set_values(&self.clock); + self.fence_release.clone_from(&self.clock); } /// Apply the effects of a acquire fence to this @@ -1021,8 +788,8 @@ impl ThreadClockSet { /// Increment the happens-before clock at a /// known index #[inline] - fn increment_clock(&mut self, thread: ThreadId) { - self.clock.increment_thread(thread); + fn increment_clock(&mut self, index: VectorIdx) { + self.clock.increment_index(index); } /// Join the happens-before clock with that of @@ -1047,81 +814,178 @@ pub struct GlobalState { /// any data-races multi_threaded: Cell, - /// The current vector clock for all threads - /// this includes threads that have terminated - /// execution - thread_clocks: RefCell>, + /// Mapping of a vector index to a known set of thread + /// clocks, this is not directly mapping from a thread id + /// since it may refer to multiple threads + vector_clocks: RefCell>, - /// Thread name cache for better diagnostics on the reporting - /// of a data-race - thread_names: RefCell>>>, + /// Mapping of a given vector index to the current thread + /// that the execution is representing, this may change + /// if a vector index is re-assigned to a new thread + vector_info: RefCell>, //FIXME: make option - /// The current thread being executed, - /// this is mirrored from the scheduler since - /// it is required for loading the current vector - /// clock for data-race detection - current_thread_id: Cell, + /// The mapping of a given thread to a known vector clock + thread_info: RefCell, Option>)>>, + + /// The current vector index being executed + current_index: Cell, + + /// Potential vector indices that could be re-used on thread creation + /// values are inserted here on thread join events, and can be + /// re-used once the vector clocks of all current threads + /// are equal to the vector clock of the joined thread + reuse_candidates: RefCell>, } impl GlobalState { /// Create a new global state, setup with just thread-id=0 /// advanced to timestamp = 1 pub fn new() -> Self { - let mut vec = IndexVec::new(); - let thread_id = vec.push(ThreadClockSet::default()); - vec[thread_id].increment_clock(thread_id); - GlobalState { + let global_state = GlobalState { multi_threaded: Cell::new(false), - thread_clocks: RefCell::new(vec), - thread_names: RefCell::new(IndexVec::new()), - current_thread_id: Cell::new(thread_id), - } + vector_clocks: RefCell::new(IndexVec::new()), + vector_info: RefCell::new(IndexVec::new()), + thread_info: RefCell::new(IndexVec::new()), + current_index: Cell::new(VectorIdx::new(0)), + reuse_candidates: RefCell::new(FxHashSet::default()), + }; + + // Setup the main-thread since it is not explicitly created: + // uses vector index and thread-id 0, also the rust runtime gives + // the main-thread a name of "main". + let index = global_state.vector_clocks.borrow_mut().push(ThreadClockSet::default()); + global_state.vector_info.borrow_mut().push(ThreadId::new(0)); + global_state.thread_info.borrow_mut().push( + (Some(index), Some("main".to_string().into_boxed_str()) + )); + + global_state } + // Try to find vector index values that can potentially be re-used + // by a new thread instead of a new vector index being created + fn find_vector_index_reuse_candidate(&self) -> Option { + let mut reuse = self.reuse_candidates.borrow_mut(); + let vector_clocks = self.vector_clocks.borrow(); + for &candidate in reuse.iter() { + let target_timestamp = vector_clocks[candidate].clock[candidate]; + if vector_clocks.iter().all(|clock| { + clock.clock[candidate] == target_timestamp + }) { + // All vector clocks for each vector index are equal to + // the target timestamp, therefore since the thread has + // terminated and cannot update the vector clock. + // No more data-races involving this vector index are possible + // so it can be re-used + assert!(reuse.remove(&candidate)); + return Some(candidate) + } + } + None + } // Hook for thread creation, enabled multi-threaded execution and marks // the current thread timestamp as happening-before the current thread #[inline] pub fn thread_created(&self, thread: ThreadId) { + let current_index = self.current_index(); - // Enable multi-threaded execution mode now that there are at least - // two threads + // Enable multi-threaded execution, there are now two threads + // so data-races are now possible. self.multi_threaded.set(true); - let current_thread = self.current_thread_id.get(); - let mut vectors = self.thread_clocks.borrow_mut(); - vectors.ensure_contains_elem(thread, Default::default); - let (current, created) = vectors.pick2_mut(current_thread, thread); - // Pre increment clocks before atomic operation - current.increment_clock(current_thread); + // Load and setup the associated thread metadata + let mut thread_info = self.thread_info.borrow_mut(); + thread_info.ensure_contains_elem(thread, Default::default); - // The current thread happens-before the created thread - // so update the created vector clock + // Assign a vector index for the thread, attempting to re-use an old + // vector index that can no longer report any data-races if possible + let created_index = if let Some( + reuse_index + ) = self.find_vector_index_reuse_candidate() { + // Now re-configure the re-use candidate, increment the clock + // for the new sync use of the vector + let mut vector_clocks = self.vector_clocks.borrow_mut(); + vector_clocks[reuse_index].increment_clock(reuse_index); + + // Locate the old thread the vector was associated with and update + // it to represent the new thread instead + let mut vector_info = self.vector_info.borrow_mut(); + let old_thread = vector_info[reuse_index]; + vector_info[reuse_index] = thread; + + // Mark the thread the vector index was associated with as no longer + // representing a thread index + thread_info[old_thread].0 = None; + + reuse_index + }else{ + // No vector re-use candidates available, instead create + // a new vector index + let mut vector_info = self.vector_info.borrow_mut(); + vector_info.push(thread) + }; + + // Mark the chosen vector index as in use by the thread + thread_info[thread].0 = Some(created_index); + + // Create a thread clock set if applicable + let mut vector_clocks = self.vector_clocks.borrow_mut(); + if created_index == vector_clocks.next_index() { + vector_clocks.push(ThreadClockSet::default()); + } + + // Now load the two clocks and configure the initial state + let (current, created) = vector_clocks.pick2_mut(current_index, created_index); + + // Advance the current thread before the synchronized operation + current.increment_clock(current_index); + + // Join the created with current, since the current threads + // previous actions happen-before the created thread created.join_with(current); - // Post increment clocks after atomic operation - current.increment_clock(current_thread); - created.increment_clock(thread); + // Advance both threads after the synchronized operation + current.increment_clock(current_index); + created.increment_clock(created_index); } /// Hook on a thread join to update the implicit happens-before relation - /// between the joined thead and the current thread + /// between the joined thead and the current thread. + /// Called after the join has occured, and hence implicitly also states + /// that the thread must have terminated as well #[inline] pub fn thread_joined(&self, current_thread: ThreadId, join_thread: ThreadId) { - let mut vectors = self.thread_clocks.borrow_mut(); - let (current, join) = vectors.pick2_mut(current_thread, join_thread); + let (current_index, join_index) = { + let thread_info = self.thread_info.borrow(); + let current_index = thread_info[current_thread].0 + .expect("Joining into thread with no assigned vector"); + let join_index = thread_info[join_thread].0 + .expect("Joining thread with no assigned vector"); + (current_index, join_index) + }; + let mut clocks_vec = self.vector_clocks.borrow_mut(); + let (current, join) = clocks_vec.pick2_mut(current_index, join_index); // Pre increment clocks before atomic operation - current.increment_clock(current_thread); - join.increment_clock(join_thread); + current.increment_clock(current_index); + join.increment_clock(join_index); // The join thread happens-before the current thread // so update the current vector clock current.join_with(join); // Post increment clocks after atomic operation - current.increment_clock(current_thread); - join.increment_clock(join_thread); + current.increment_clock(current_index); + join.increment_clock(join_index); + + // The joined thread vector clock is a potential candidate + // for re-use given sufficient time, mark as available once + // threads have been created. This is because this function + // is called once join_thread has terminated and such cannot + // update any-more + let mut reuse = self.reuse_candidates.borrow_mut(); + reuse.insert(join_index); } /// Hook for updating the local tracker of the currently @@ -1129,7 +993,10 @@ impl GlobalState { /// `active_thread` in thread.rs is updated #[inline] pub fn thread_set_active(&self, thread: ThreadId) { - self.current_thread_id.set(thread); + let thread_info = self.thread_info.borrow(); + let vector_idx = thread_info[thread].0 + .expect("Setting thread active with no assigned vector"); + self.current_index.set(vector_idx); } /// Hook for updating the local tracker of the threads name @@ -1137,33 +1004,40 @@ impl GlobalState { /// the thread name is used for improved diagnostics /// during a data-race #[inline] - pub fn thread_set_name(&self, name: String) { + pub fn thread_set_name(&self, thread: ThreadId, name: String) { let name = name.into_boxed_str(); - let mut names = self.thread_names.borrow_mut(); - let thread = self.current_thread_id.get(); - names.ensure_contains_elem(thread, Default::default); - names[thread] = Some(name); + let mut thread_info = self.thread_info.borrow_mut(); + thread_info[thread].1 = Some(name); } - /// Advance the vector clock for a thread - /// this is called before and after any atomic/synchronizing operations - /// that may manipulate state - #[inline] - fn advance_vector_clock(&self) { - let thread = self.current_thread_id.get(); - let mut vectors = self.thread_clocks.borrow_mut(); - vectors[thread].increment_clock(thread); - - // Log the increment in the atomic vector clock - log::trace!("Atomic vector clock increase for {:?} to {:?}",thread, vectors[thread].clock); + /// Attempt to perform a synchronized operation, this + /// will perform no operation if multi-threading is + /// not currently enabled. + /// Otherwise it will increment the clock for the current + /// vector before and after the operation for data-race + /// detection between any happens-before edges the + /// operation may create + fn maybe_perform_sync_operation<'tcx>( + &self, op: impl FnOnce(VectorIdx, RefMut<'_,ThreadClockSet>) -> InterpResult<'tcx>, + ) -> InterpResult<'tcx> { + if self.multi_threaded.get() { + let (index, mut clocks) = self.current_thread_state_mut(); + clocks.increment_clock(index); + op(index, clocks)?; + let (_, mut clocks) = self.current_thread_state_mut(); + clocks.increment_clock(index); + } + Ok(()) } /// Internal utility to identify a thread stored internally /// returns the id and the name for better diagnostics - fn print_thread_metadata(&self, thread: ThreadId) -> String { - if let Some(Some(name)) = self.thread_names.borrow().get(thread) { + fn print_thread_metadata(&self, vector: VectorIdx) -> String { + let thread = self.vector_info.borrow()[vector]; + let thread_name = &self.thread_info.borrow()[thread].1; + if let Some(name) = thread_name { let name: &str = name; format!("Thread(id = {:?}, name = {:?})", thread.to_u32(), &*name) }else{ @@ -1175,25 +1049,19 @@ impl GlobalState { /// Acquire a lock, express that the previous call of /// `validate_lock_release` must happen before this pub fn validate_lock_acquire(&self, lock: &DataRaceLockHandle, thread: ThreadId) { - let mut ref_vector = self.thread_clocks.borrow_mut(); - ref_vector[thread].increment_clock(thread); - - let clocks = &mut ref_vector[thread]; + let (index, mut clocks) = self.load_thread_state_mut(thread); + clocks.increment_clock(index); clocks.clock.join(&lock.clock); - - ref_vector[thread].increment_clock(thread); + clocks.increment_clock(index); } /// Release a lock handle, express that this happens-before /// any subsequent calls to `validate_lock_acquire` pub fn validate_lock_release(&self, lock: &mut DataRaceLockHandle, thread: ThreadId) { - let mut ref_vector = self.thread_clocks.borrow_mut(); - ref_vector[thread].increment_clock(thread); - - let clocks = &ref_vector[thread]; - lock.clock.set_values(&clocks.clock); - - ref_vector[thread].increment_clock(thread); + let (index, mut clocks) = self.load_thread_state_mut(thread); + clocks.increment_clock(index); + lock.clock.clone_from(&clocks.clock); + clocks.increment_clock(index); } /// Release a lock handle, express that this happens-before @@ -1201,401 +1069,48 @@ impl GlobalState { /// as any previous calls to this function after any /// `validate_lock_release` calls pub fn validate_lock_release_shared(&self, lock: &mut DataRaceLockHandle, thread: ThreadId) { - let mut ref_vector = self.thread_clocks.borrow_mut(); - ref_vector[thread].increment_clock(thread); - - let clocks = &ref_vector[thread]; + let (index, mut clocks) = self.load_thread_state_mut(thread); + clocks.increment_clock(index); lock.clock.join(&clocks.clock); - - ref_vector[thread].increment_clock(thread); + clocks.increment_clock(index); } - /// Load the thread clock set associated with the current thread + /// Load the vector index used by the given thread as well as the set of vector clocks + /// used by the thread #[inline] - fn current_thread_state(&self) -> Ref<'_, ThreadClockSet> { - let ref_vector = self.thread_clocks.borrow(); - let thread = self.current_thread_id.get(); - Ref::map(ref_vector, |vector| &vector[thread]) + fn load_thread_state_mut(&self, thread: ThreadId) -> (VectorIdx, RefMut<'_, ThreadClockSet>) { + let index = self.thread_info.borrow()[thread].0 + .expect("Loading thread state for thread with no assigned vector"); + let ref_vector = self.vector_clocks.borrow_mut(); + let clocks = RefMut::map(ref_vector, |vec| &mut vec[index]); + (index, clocks) } - /// Load the thread clock set associated with the current thread - /// mutably for modification + /// Load the current vector clock in use and the current set of thread clocks + /// in use for the vector #[inline] - fn current_thread_state_mut(&self) -> RefMut<'_, ThreadClockSet> { - let ref_vector = self.thread_clocks.borrow_mut(); - let thread = self.current_thread_id.get(); - RefMut::map(ref_vector, |vector| &mut vector[thread]) + fn current_thread_state(&self) -> (VectorIdx, Ref<'_, ThreadClockSet>) { + let index = self.current_index(); + let ref_vector = self.vector_clocks.borrow(); + let clocks = Ref::map(ref_vector, |vec| &vec[index]); + (index, clocks) + } + + /// Load the current vector clock in use and the current set of thread clocks + /// in use for the vector mutably for modification + #[inline] + fn current_thread_state_mut(&self) -> (VectorIdx, RefMut<'_, ThreadClockSet>) { + let index = self.current_index(); + let ref_vector = self.vector_clocks.borrow_mut(); + let clocks = RefMut::map(ref_vector, |vec| &mut vec[index]); + (index, clocks) } /// Return the current thread, should be the same /// as the data-race active thread #[inline] - fn current_thread(&self) -> ThreadId { - self.current_thread_id.get() + fn current_index(&self) -> VectorIdx { + self.current_index.get() } } - -/// The size of the vector-clock to store inline -/// clock vectors larger than this will be stored on the heap -const SMALL_VECTOR: usize = 4; - -/// The type of the time-stamps recorded in the data-race detector -/// set to a type of unsigned integer -type Timestamp = u32; - -/// A vector clock for detecting data-races -/// invariants: -/// - the last element in a VClock must not be 0 -/// -- this means that derive(PartialEq & Eq) is correct -/// -- as there is no implicit zero tail that might be equal -/// -- also simplifies the implementation of PartialOrd -#[derive(Clone, PartialEq, Eq, Default, Debug)] -pub struct VClock(SmallVec<[Timestamp; SMALL_VECTOR]>); - -impl VClock { - - /// Load the backing slice behind the clock vector. - #[inline] - fn as_slice(&self) -> &[Timestamp] { - self.0.as_slice() - } - - /// Get a mutable slice to the internal vector with minimum `min_len` - /// elements, to preserve invariants this vector must modify - /// the `min_len`-1 nth element to a non-zero value - #[inline] - fn get_mut_with_min_len(&mut self, min_len: usize) -> &mut [Timestamp] { - if self.0.len() < min_len { - self.0.resize(min_len, 0); - } - assert!(self.0.len() >= min_len); - self.0.as_mut_slice() - } - - /// Increment the vector clock at a known index - #[inline] - fn increment_index(&mut self, idx: usize) { - let mut_slice = self.get_mut_with_min_len(idx + 1); - let idx_ref = &mut mut_slice[idx]; - *idx_ref = idx_ref.checked_add(1).expect("Vector clock overflow") - } - - // Increment the vector element representing the progress - // of execution in the given thread - #[inline] - pub fn increment_thread(&mut self, thread: ThreadId) { - self.increment_index(thread.to_u32() as usize); - } - - // Join the two vector-clocks together, this - // sets each vector-element to the maximum value - // of that element in either of the two source elements. - pub fn join(&mut self, other: &Self) { - let rhs_slice = other.as_slice(); - let lhs_slice = self.get_mut_with_min_len(rhs_slice.len()); - - // Element-wise set to maximum. - for (l, &r) in lhs_slice.iter_mut().zip(rhs_slice.iter()) { - *l = r.max(*l); - } - } - - /// Joins with a thread at a known index - fn set_at_index(&mut self, other: &Self, idx: usize){ - let mut_slice = self.get_mut_with_min_len(idx + 1); - let slice = other.as_slice(); - mut_slice[idx] = slice[idx]; - } - - /// Join with a threads vector clock only at the desired index - /// returns true if the value updated - #[inline] - pub fn set_at_thread(&mut self, other: &Self, thread: ThreadId){ - self.set_at_index(other, thread.to_u32() as usize); - } - - /// Clear the vector to all zeros, stored as an empty internal - /// vector - #[inline] - pub fn set_zero_vector(&mut self) { - self.0.clear(); - } - - /// Set the values stored in this vector clock - /// to the values stored in another. - pub fn set_values(&mut self, new_value: &VClock) { - let new_slice = new_value.as_slice(); - self.0.resize(new_slice.len(), 0); - self.0.copy_from_slice(new_slice); - } -} - - -impl PartialOrd for VClock { - fn partial_cmp(&self, other: &VClock) -> Option { - - // Load the values as slices - let lhs_slice = self.as_slice(); - let rhs_slice = other.as_slice(); - - // Iterate through the combined vector slice - // keeping track of the order that is currently possible to satisfy. - // If an ordering relation is detected to be impossible, then bail and - // directly return None - let mut iter = lhs_slice.iter().zip(rhs_slice.iter()); - let mut order = match iter.next() { - Some((lhs, rhs)) => lhs.cmp(rhs), - None => Ordering::Equal - }; - for (l, r) in iter { - match order { - Ordering::Equal => order = l.cmp(r), - Ordering::Less => if l > r { - return None - }, - Ordering::Greater => if l < r { - return None - } - } - } - - //Now test if either left or right have trailing elements - // by the invariant the trailing elements have at least 1 - // non zero value, so no additional calculation is required - // to determine the result of the PartialOrder - let l_len = lhs_slice.len(); - let r_len = rhs_slice.len(); - match l_len.cmp(&r_len) { - // Equal has no additional elements: return current order - Ordering::Equal => Some(order), - // Right has at least 1 element > than the implicit 0, - // so the only valid values are Ordering::Less or None - Ordering::Less => match order { - Ordering::Less | Ordering::Equal => Some(Ordering::Less), - Ordering::Greater => None - } - // Left has at least 1 element > than the implicit 0, - // so the only valid values are Ordering::Greater or None - Ordering::Greater => match order { - Ordering::Greater | Ordering::Equal => Some(Ordering::Greater), - Ordering::Less => None - } - } - } - - fn lt(&self, other: &VClock) -> bool { - // Load the values as slices - let lhs_slice = self.as_slice(); - let rhs_slice = other.as_slice(); - - // If l_len > r_len then at least one element - // in l_len is > than r_len, therefore the result - // is either Some(Greater) or None, so return false - // early. - let l_len = lhs_slice.len(); - let r_len = rhs_slice.len(); - if l_len <= r_len { - // If any elements on the left are greater than the right - // then the result is None or Some(Greater), both of which - // return false, the earlier test asserts that no elements in the - // extended tail violate this assumption. Otherwise l <= r, finally - // the case where the values are potentially equal needs to be considered - // and false returned as well - let mut equal = l_len == r_len; - for (&l, &r) in lhs_slice.iter().zip(rhs_slice.iter()) { - if l > r { - return false - }else if l < r { - equal = false; - } - } - !equal - }else{ - false - } - } - - fn le(&self, other: &VClock) -> bool { - // Load the values as slices - let lhs_slice = self.as_slice(); - let rhs_slice = other.as_slice(); - - // If l_len > r_len then at least one element - // in l_len is > than r_len, therefore the result - // is either Some(Greater) or None, so return false - // early. - let l_len = lhs_slice.len(); - let r_len = rhs_slice.len(); - if l_len <= r_len { - // If any elements on the left are greater than the right - // then the result is None or Some(Greater), both of which - // return false, the earlier test asserts that no elements in the - // extended tail violate this assumption. Otherwise l <= r - !lhs_slice.iter().zip(rhs_slice.iter()).any(|(&l, &r)| l > r) - }else{ - false - } - } - - fn gt(&self, other: &VClock) -> bool { - // Load the values as slices - let lhs_slice = self.as_slice(); - let rhs_slice = other.as_slice(); - - // If r_len > l_len then at least one element - // in r_len is > than l_len, therefore the result - // is either Some(Less) or None, so return false - // early. - let l_len = lhs_slice.len(); - let r_len = rhs_slice.len(); - if l_len >= r_len { - // If any elements on the left are less than the right - // then the result is None or Some(Less), both of which - // return false, the earlier test asserts that no elements in the - // extended tail violate this assumption. Otherwise l >=, finally - // the case where the values are potentially equal needs to be considered - // and false returned as well - let mut equal = l_len == r_len; - for (&l, &r) in lhs_slice.iter().zip(rhs_slice.iter()) { - if l < r { - return false - }else if l > r { - equal = false; - } - } - !equal - }else{ - false - } - } - - fn ge(&self, other: &VClock) -> bool { - // Load the values as slices - let lhs_slice = self.as_slice(); - let rhs_slice = other.as_slice(); - - // If r_len > l_len then at least one element - // in r_len is > than l_len, therefore the result - // is either Some(Less) or None, so return false - // early. - let l_len = lhs_slice.len(); - let r_len = rhs_slice.len(); - if l_len >= r_len { - // If any elements on the left are less than the right - // then the result is None or Some(Less), both of which - // return false, the earlier test asserts that no elements in the - // extended tail violate this assumption. Otherwise l >= r - !lhs_slice.iter().zip(rhs_slice.iter()).any(|(&l, &r)| l < r) - }else{ - false - } - } -} - -impl Index for VClock { - type Output = Timestamp; - - #[inline] - fn index(&self, index: ThreadId) -> &Timestamp { - self.as_slice().get(index.to_u32() as usize).unwrap_or(&0) - } -} - - -/// Test vector clock ordering operations -/// data-race detection is tested in the external -/// test suite -#[cfg(test)] -mod tests { - use super::{VClock, Timestamp}; - use std::cmp::Ordering; - - #[test] - fn test_equal() { - let mut c1 = VClock::default(); - let mut c2 = VClock::default(); - assert_eq!(c1, c2); - c1.increment_index(5); - assert_ne!(c1, c2); - c2.increment_index(53); - assert_ne!(c1, c2); - c1.increment_index(53); - assert_ne!(c1, c2); - c2.increment_index(5); - assert_eq!(c1, c2); - } - - #[test] - fn test_partial_order() { - // Small test - assert_order(&[1], &[1], Some(Ordering::Equal)); - assert_order(&[1], &[2], Some(Ordering::Less)); - assert_order(&[2], &[1], Some(Ordering::Greater)); - assert_order(&[1], &[1,2], Some(Ordering::Less)); - assert_order(&[2], &[1,2], None); - - // Misc tests - assert_order(&[400], &[0, 1], None); - - // Large test - assert_order(&[0,1,2,3,4,5,6,7,8,9,10], &[0,1,2,3,4,5,6,7,8,9,10,0,0,0], Some(Ordering::Equal)); - assert_order(&[0,1,2,3,4,5,6,7,8,9,10], &[0,1,2,3,4,5,6,7,8,9,10,0,1,0], Some(Ordering::Less)); - assert_order(&[0,1,2,3,4,5,6,7,8,9,11], &[0,1,2,3,4,5,6,7,8,9,10,0,0,0], Some(Ordering::Greater)); - assert_order(&[0,1,2,3,4,5,6,7,8,9,11], &[0,1,2,3,4,5,6,7,8,9,10,0,1,0], None); - assert_order(&[0,1,2,3,4,5,6,7,8,9,9 ], &[0,1,2,3,4,5,6,7,8,9,10,0,0,0], Some(Ordering::Less)); - assert_order(&[0,1,2,3,4,5,6,7,8,9,9 ], &[0,1,2,3,4,5,6,7,8,9,10,0,1,0], Some(Ordering::Less)); - } - - fn from_slice(mut slice: &[Timestamp]) -> VClock { - while let Some(0) = slice.last() { - slice = &slice[..slice.len() - 1] - } - VClock(smallvec::SmallVec::from_slice(slice)) - } - - fn assert_order(l: &[Timestamp], r: &[Timestamp], o: Option) { - let l = from_slice(l); - let r = from_slice(r); - - //Test partial_cmp - let compare = l.partial_cmp(&r); - assert_eq!(compare, o, "Invalid comparison\n l: {:?}\n r: {:?}",l,r); - let alt_compare = r.partial_cmp(&l); - assert_eq!(alt_compare, o.map(Ordering::reverse), "Invalid alt comparison\n l: {:?}\n r: {:?}",l,r); - - //Test operatorsm with faster implementations - assert_eq!( - matches!(compare,Some(Ordering::Less)), l < r, - "Invalid (<):\n l: {:?}\n r: {:?}",l,r - ); - assert_eq!( - matches!(compare,Some(Ordering::Less) | Some(Ordering::Equal)), l <= r, - "Invalid (<=):\n l: {:?}\n r: {:?}",l,r - ); - assert_eq!( - matches!(compare,Some(Ordering::Greater)), l > r, - "Invalid (>):\n l: {:?}\n r: {:?}",l,r - ); - assert_eq!( - matches!(compare,Some(Ordering::Greater) | Some(Ordering::Equal)), l >= r, - "Invalid (>=):\n l: {:?}\n r: {:?}",l,r - ); - assert_eq!( - matches!(alt_compare,Some(Ordering::Less)), r < l, - "Invalid alt (<):\n l: {:?}\n r: {:?}",l,r - ); - assert_eq!( - matches!(alt_compare,Some(Ordering::Less) | Some(Ordering::Equal)), r <= l, - "Invalid alt (<=):\n l: {:?}\n r: {:?}",l,r - ); - assert_eq!( - matches!(alt_compare,Some(Ordering::Greater)), r > l, - "Invalid alt (>):\n l: {:?}\n r: {:?}",l,r - ); - assert_eq!( - matches!(alt_compare,Some(Ordering::Greater) | Some(Ordering::Equal)), r >= l, - "Invalid alt (>=):\n l: {:?}\n r: {:?}",l,r - ); - } -} diff --git a/src/lib.rs b/src/lib.rs index f384787e4c68..c8c9e70ec3de 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,6 +35,7 @@ mod shims; mod stacked_borrows; mod sync; mod thread; +mod vector_clock; // Establish a "crate-wide prelude": we often import `crate::*`. @@ -79,6 +80,9 @@ pub use crate::thread::{ pub use crate::sync::{ EvalContextExt as SyncEvalContextExt, CondvarId, MutexId, RwLockId }; +pub use crate::vector_clock::{ + VClock, VSmallClockSet, VectorIdx, VTimestamp +}; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 2bb15e712c5f..50f97af8453e 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -469,8 +469,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let place = this.deref_operand(place)?; // make sure it fits into a scalar; otherwise it cannot be atomic - let val = this.read_scalar_racy(place)?; - this.validate_atomic_load(place, atomic)?; + let val = this.read_scalar_atomic(place, atomic)?; // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must @@ -495,9 +494,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; // Perform atomic store - this.write_scalar_racy(val, place)?; - - this.validate_atomic_store(place, atomic)?; + this.write_scalar_atomic(val, place, atomic)?; Ok(()) } @@ -527,7 +524,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx bug!("Atomic arithmetic operations only work on integer types"); } let rhs = this.read_immediate(rhs)?; - let old = this.read_immediate_racy(place)?; + let old = this.allow_data_races_mut(|this| { + this.read_immediate(place. into()) + })?; // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must @@ -539,7 +538,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Atomics wrap around on overflow. let val = this.binary_op(op, old, rhs)?; let val = if neg { this.unary_op(mir::UnOp::Not, val)? } else { val }; - this.write_immediate_racy(*val, place)?; + this.allow_data_races_mut(|this| { + this.write_immediate(*val, place.into()) + })?; this.validate_atomic_rmw(place, atomic)?; Ok(()) @@ -553,7 +554,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[place, new] = check_arg_count(args)?; let place = this.deref_operand(place)?; let new = this.read_scalar(new)?; - let old = this.read_scalar_racy(place)?; + let old = this.allow_data_races_mut(|this| { + this.read_scalar(place.into()) + })?; // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must @@ -562,7 +565,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; this.write_scalar(old, dest)?; // old value is returned - this.write_scalar_racy(new, place)?; + this.allow_data_races_mut(|this| { + this.write_scalar(new, place.into()) + })?; this.validate_atomic_rmw(place, atomic)?; Ok(()) @@ -583,7 +588,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // to read with the failure ordering and if successfull then try again with the success // read ordering and write in the success case. // Read as immediate for the sake of `binary_op()` - let old = this.read_immediate_racy(place)?; + let old = this.allow_data_races_mut(|this| { + this.read_immediate(place.into()) + })?; // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must @@ -602,7 +609,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // if successful, perform a full rw-atomic validation // otherwise treat this as an atomic load with the fail ordering if eq.to_bool()? { - this.write_scalar_racy(new, place)?; + this.allow_data_races_mut(|this| { + this.write_scalar(new, place.into()) + })?; this.validate_atomic_rmw(place, success)?; } else { this.validate_atomic_load(place, fail)?; diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 332e79071a0a..d741ef346e94 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -62,7 +62,10 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>( mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - ecx.read_scalar_at_offset_racy(mutex_op, offset, ecx.machine.layouts.i32) + ecx.read_scalar_at_offset_atomic( + mutex_op, offset, ecx.machine.layouts.i32, + AtomicReadOp::SeqCst + ) } fn mutex_set_kind<'mir, 'tcx: 'mir>( @@ -71,14 +74,19 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( kind: impl Into>, ) -> InterpResult<'tcx, ()> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - ecx.write_scalar_at_offset_racy(mutex_op, offset, kind, ecx.machine.layouts.i32) + ecx.write_scalar_at_offset_atomic( + mutex_op, offset, kind, ecx.machine.layouts.i32, + AtomicWriteOp::SeqCst + ) } fn mutex_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - ecx.read_scalar_at_offset_racy(mutex_op, 4, ecx.machine.layouts.u32) + ecx.read_scalar_at_offset_atomic( + mutex_op, 4, ecx.machine.layouts.u32, AtomicReadOp::SeqCst + ) } fn mutex_set_id<'mir, 'tcx: 'mir>( @@ -86,7 +94,10 @@ fn mutex_set_id<'mir, 'tcx: 'mir>( mutex_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { - ecx.write_scalar_at_offset_racy(mutex_op, 4, id, ecx.machine.layouts.u32) + ecx.write_scalar_at_offset_atomic( + mutex_op, 4, id, ecx.machine.layouts.u32, + AtomicWriteOp::SeqCst + ) } fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( @@ -116,7 +127,10 @@ fn rwlock_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - ecx.read_scalar_at_offset_racy(rwlock_op, 4, ecx.machine.layouts.u32) + ecx.read_scalar_at_offset_atomic( + rwlock_op, 4, ecx.machine.layouts.u32, + AtomicReadOp::SeqCst + ) } fn rwlock_set_id<'mir, 'tcx: 'mir>( @@ -124,7 +138,10 @@ fn rwlock_set_id<'mir, 'tcx: 'mir>( rwlock_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { - ecx.write_scalar_at_offset_racy(rwlock_op, 4, id, ecx.machine.layouts.u32) + ecx.write_scalar_at_offset_atomic( + rwlock_op, 4, id, ecx.machine.layouts.u32, + AtomicWriteOp::SeqCst + ) } fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( @@ -177,7 +194,10 @@ fn cond_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, cond_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - ecx.read_scalar_at_offset_racy(cond_op, 4, ecx.machine.layouts.u32) + ecx.read_scalar_at_offset_atomic( + cond_op, 4, ecx.machine.layouts.u32, + AtomicReadOp::SeqCst + ) } fn cond_set_id<'mir, 'tcx: 'mir>( @@ -185,7 +205,10 @@ fn cond_set_id<'mir, 'tcx: 'mir>( cond_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { - ecx.write_scalar_at_offset_racy(cond_op, 4, id, ecx.machine.layouts.u32) + ecx.write_scalar_at_offset_atomic( + cond_op, 4, id, ecx.machine.layouts.u32, + AtomicWriteOp::SeqCst + ) } fn cond_get_or_create_id<'mir, 'tcx: 'mir>( diff --git a/src/thread.rs b/src/thread.rs index 08aeaa4fd095..f94805ae022a 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -638,7 +638,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn set_active_thread_name(&mut self, new_thread_name: Vec) { let this = self.eval_context_mut(); if let Ok(string) = String::from_utf8(new_thread_name.clone()) { - this.memory.extra.data_race.thread_set_name(string); + this.memory.extra.data_race.thread_set_name( + this.machine.threads.active_thread, string + ); } this.machine.threads.set_thread_name(new_thread_name); } diff --git a/src/vector_clock.rs b/src/vector_clock.rs new file mode 100644 index 000000000000..8d05eb1b992b --- /dev/null +++ b/src/vector_clock.rs @@ -0,0 +1,602 @@ +use std::{ + fmt::{self, Debug}, cmp::Ordering, ops::Index, + num::TryFromIntError, convert::TryFrom, mem +}; +use smallvec::SmallVec; +use rustc_index::vec::Idx; +use rustc_data_structures::fx::FxHashMap; + +/// A vector clock index, this is associated with a thread id +/// but in some cases one vector index may be shared with +/// multiple thread ids. +#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] +pub struct VectorIdx(u32); + +impl VectorIdx{ + pub fn to_u32(self) -> u32 { + self.0 + } + pub const MAX_INDEX: VectorIdx = VectorIdx(u32::MAX); +} + +impl Idx for VectorIdx { + fn new(idx: usize) -> Self { + VectorIdx(u32::try_from(idx).unwrap()) + } + + fn index(self) -> usize { + usize::try_from(self.0).unwrap() + } +} + +impl TryFrom for VectorIdx { + type Error = TryFromIntError; + fn try_from(id: u64) -> Result { + u32::try_from(id).map(|id_u32| Self(id_u32)) + } +} + +impl From for VectorIdx { + fn from(id: u32) -> Self { + Self(id) + } +} + + +/// A sparse set of vector clocks, where each vector index +/// is associated with a vector clock. +/// This treats all vector clocks that have not been assigned +/// as equal to the all zero vector clocks +/// Is optimized for the common case where only 1 element is stored +/// in the set and the rest can be ignored, falling-back to +/// using an internal hash-map once more than 1 element is assigned +/// at any one time +#[derive(Clone)] +pub struct VSmallClockSet(VSmallClockSetInner); + +#[derive(Clone)] +enum VSmallClockSetInner { + /// Zero or 1 vector elements, common + /// case for the sparse set. + /// The all zero vector clock is treated + /// as equal to the empty element + Small(VectorIdx, VClock), + + /// Hash-map of vector clocks + Large(FxHashMap) +} + +impl VSmallClockSet { + + /// Remove all clock vectors from the map, setting them + /// to the zero vector + pub fn clear(&mut self) { + match &mut self.0 { + VSmallClockSetInner::Small(_, clock) => { + clock.set_zero_vector() + } + VSmallClockSetInner::Large(hash_map) => { + hash_map.clear(); + } + } + } + + /// Remove all clock vectors except for the clock vector + /// stored at the given index, which is retained + pub fn retain_index(&mut self, index: VectorIdx) { + match &mut self.0 { + VSmallClockSetInner::Small(small_idx, clock) => { + if index != *small_idx { + // The zero-vector is considered to equal + // the empty element + clock.set_zero_vector() + } + }, + VSmallClockSetInner::Large(hash_map) => { + hash_map.retain(|idx,_| { + *idx == index + }); + } + } + } + + /// Insert the vector clock into the associated vector + /// index + pub fn insert(&mut self, index: VectorIdx, clock: &VClock) { + match &mut self.0 { + VSmallClockSetInner::Small(small_idx, small_clock) => { + if small_clock.is_zero_vector() { + *small_idx = index; + small_clock.clone_from(clock); + }else if !clock.is_zero_vector() { + let mut hash_map = FxHashMap::default(); + hash_map.insert(*small_idx, mem::take(small_clock)); + hash_map.insert(index, clock.clone()); + self.0 = VSmallClockSetInner::Large(hash_map); + } + }, + VSmallClockSetInner::Large(hash_map) => { + if !clock.is_zero_vector() { + hash_map.insert(index, clock.clone()); + } + } + } + } + + /// Try to load the vector clock associated with the current + /// vector index. + pub fn get(&self, index: VectorIdx) -> Option<&VClock> { + match &self.0 { + VSmallClockSetInner::Small(small_idx, small_clock) => { + if *small_idx == index && !small_clock.is_zero_vector() { + Some(small_clock) + }else{ + None + } + }, + VSmallClockSetInner::Large(hash_map) => { + hash_map.get(&index) + } + } + } +} + +impl Default for VSmallClockSet { + #[inline] + fn default() -> Self { + VSmallClockSet( + VSmallClockSetInner::Small(VectorIdx::new(0), VClock::default()) + ) + } +} + +impl Debug for VSmallClockSet { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Print the contents of the small vector clock set as the map + // of vector index to vector clock that they represent + let mut map = f.debug_map(); + match &self.0 { + VSmallClockSetInner::Small(small_idx, small_clock) => { + if !small_clock.is_zero_vector() { + map.entry(&small_idx, &small_clock); + } + }, + VSmallClockSetInner::Large(hash_map) => { + for (idx, elem) in hash_map.iter() { + map.entry(idx, elem); + } + } + } + map.finish() + } +} +impl PartialEq for VSmallClockSet { + fn eq(&self, other: &Self) -> bool { + use VSmallClockSetInner::*; + match (&self.0, &other.0) { + (Small(i1, c1), Small(i2, c2)) => { + if c1.is_zero_vector() { + // Either they are both zero or they are non-equal + c2.is_zero_vector() + }else{ + // At least one is non-zero, so the full comparison is correct + i1 == i2 && c1 == c2 + } + } + (VSmallClockSetInner::Small(idx, clock), VSmallClockSetInner::Large(hash_map)) | + (VSmallClockSetInner::Large(hash_map), VSmallClockSetInner::Small(idx, clock)) => { + if hash_map.len() == 0 { + // Equal to the empty hash-map + clock.is_zero_vector() + }else if hash_map.len() == 1 { + // Equal to the hash-map with one element + let (hash_idx, hash_clock) = hash_map.iter().next().unwrap(); + hash_idx == idx && hash_clock == clock + }else{ + false + } + } + (Large(map1), Large(map2)) => { + map1 == map2 + } + } + } +} +impl Eq for VSmallClockSet {} + + + +/// The size of the vector-clock to store inline +/// clock vectors larger than this will be stored on the heap +const SMALL_VECTOR: usize = 4; + +/// The type of the time-stamps recorded in the data-race detector +/// set to a type of unsigned integer +pub type VTimestamp = u32; + +/// A vector clock for detecting data-races +/// invariants: +/// - the last element in a VClock must not be 0 +/// -- this means that derive(PartialEq & Eq) is correct +/// -- as there is no implicit zero tail that might be equal +/// -- also simplifies the implementation of PartialOrd +#[derive(PartialEq, Eq, Default, Debug)] +pub struct VClock(SmallVec<[VTimestamp; SMALL_VECTOR]>); + +impl VClock { + + /// Create a new vector-clock containing all zeros except + /// for a value at the given index + pub fn new_with_index(index: VectorIdx, timestamp: VTimestamp) -> VClock { + let len = index.index() + 1; + let mut vec = smallvec::smallvec![0; len]; + vec[index.index()] = timestamp; + VClock(vec) + } + + /// Load the internal timestamp slice in the vector clock + #[inline] + pub fn as_slice(&self) -> &[VTimestamp] { + self.0.as_slice() + } + + /// Get a mutable slice to the internal vector with minimum `min_len` + /// elements, to preserve invariants this vector must modify + /// the `min_len`-1 nth element to a non-zero value + #[inline] + fn get_mut_with_min_len(&mut self, min_len: usize) -> &mut [VTimestamp] { + if self.0.len() < min_len { + self.0.resize(min_len, 0); + } + assert!(self.0.len() >= min_len); + self.0.as_mut_slice() + } + + /// Increment the vector clock at a known index + /// this will panic if the vector index overflows + #[inline] + pub fn increment_index(&mut self, idx: VectorIdx) { + let idx = idx.index(); + let mut_slice = self.get_mut_with_min_len(idx + 1); + let idx_ref = &mut mut_slice[idx]; + *idx_ref = idx_ref.checked_add(1).expect("Vector clock overflow") + } + + // Join the two vector-clocks together, this + // sets each vector-element to the maximum value + // of that element in either of the two source elements. + pub fn join(&mut self, other: &Self) { + let rhs_slice = other.as_slice(); + let lhs_slice = self.get_mut_with_min_len(rhs_slice.len()); + for (l, &r) in lhs_slice.iter_mut().zip(rhs_slice.iter()) { + *l = r.max(*l); + } + } + + /// Set the element at the current index of the vector + pub fn set_at_index(&mut self, other: &Self, idx: VectorIdx) { + let idx = idx.index(); + let mut_slice = self.get_mut_with_min_len(idx + 1); + let slice = other.as_slice(); + mut_slice[idx] = slice[idx]; + } + + /// Set the vector to the all-zero vector + #[inline] + pub fn set_zero_vector(&mut self) { + self.0.clear(); + } + + /// Return if this vector is the all-zero vector + pub fn is_zero_vector(&self) -> bool { + self.0.is_empty() + } +} + +impl Clone for VClock { + fn clone(&self) -> Self { + VClock(self.0.clone()) + } + fn clone_from(&mut self, source: &Self) { + let source_slice = source.as_slice(); + self.0.clear(); + self.0.extend_from_slice(source_slice); + } +} + +impl PartialOrd for VClock { + fn partial_cmp(&self, other: &VClock) -> Option { + + // Load the values as slices + let lhs_slice = self.as_slice(); + let rhs_slice = other.as_slice(); + + // Iterate through the combined vector slice + // keeping track of the order that is currently possible to satisfy. + // If an ordering relation is detected to be impossible, then bail and + // directly return None + let mut iter = lhs_slice.iter().zip(rhs_slice.iter()); + let mut order = match iter.next() { + Some((lhs, rhs)) => lhs.cmp(rhs), + None => Ordering::Equal + }; + for (l, r) in iter { + match order { + Ordering::Equal => order = l.cmp(r), + Ordering::Less => if l > r { + return None + }, + Ordering::Greater => if l < r { + return None + } + } + } + + //Now test if either left or right have trailing elements + // by the invariant the trailing elements have at least 1 + // non zero value, so no additional calculation is required + // to determine the result of the PartialOrder + let l_len = lhs_slice.len(); + let r_len = rhs_slice.len(); + match l_len.cmp(&r_len) { + // Equal has no additional elements: return current order + Ordering::Equal => Some(order), + // Right has at least 1 element > than the implicit 0, + // so the only valid values are Ordering::Less or None + Ordering::Less => match order { + Ordering::Less | Ordering::Equal => Some(Ordering::Less), + Ordering::Greater => None + } + // Left has at least 1 element > than the implicit 0, + // so the only valid values are Ordering::Greater or None + Ordering::Greater => match order { + Ordering::Greater | Ordering::Equal => Some(Ordering::Greater), + Ordering::Less => None + } + } + } + + fn lt(&self, other: &VClock) -> bool { + // Load the values as slices + let lhs_slice = self.as_slice(); + let rhs_slice = other.as_slice(); + + // If l_len > r_len then at least one element + // in l_len is > than r_len, therefore the result + // is either Some(Greater) or None, so return false + // early. + let l_len = lhs_slice.len(); + let r_len = rhs_slice.len(); + if l_len <= r_len { + // If any elements on the left are greater than the right + // then the result is None or Some(Greater), both of which + // return false, the earlier test asserts that no elements in the + // extended tail violate this assumption. Otherwise l <= r, finally + // the case where the values are potentially equal needs to be considered + // and false returned as well + let mut equal = l_len == r_len; + for (&l, &r) in lhs_slice.iter().zip(rhs_slice.iter()) { + if l > r { + return false + }else if l < r { + equal = false; + } + } + !equal + }else{ + false + } + } + + fn le(&self, other: &VClock) -> bool { + // Load the values as slices + let lhs_slice = self.as_slice(); + let rhs_slice = other.as_slice(); + + // If l_len > r_len then at least one element + // in l_len is > than r_len, therefore the result + // is either Some(Greater) or None, so return false + // early. + let l_len = lhs_slice.len(); + let r_len = rhs_slice.len(); + if l_len <= r_len { + // If any elements on the left are greater than the right + // then the result is None or Some(Greater), both of which + // return false, the earlier test asserts that no elements in the + // extended tail violate this assumption. Otherwise l <= r + !lhs_slice.iter().zip(rhs_slice.iter()).any(|(&l, &r)| l > r) + }else{ + false + } + } + + fn gt(&self, other: &VClock) -> bool { + // Load the values as slices + let lhs_slice = self.as_slice(); + let rhs_slice = other.as_slice(); + + // If r_len > l_len then at least one element + // in r_len is > than l_len, therefore the result + // is either Some(Less) or None, so return false + // early. + let l_len = lhs_slice.len(); + let r_len = rhs_slice.len(); + if l_len >= r_len { + // If any elements on the left are less than the right + // then the result is None or Some(Less), both of which + // return false, the earlier test asserts that no elements in the + // extended tail violate this assumption. Otherwise l >=, finally + // the case where the values are potentially equal needs to be considered + // and false returned as well + let mut equal = l_len == r_len; + for (&l, &r) in lhs_slice.iter().zip(rhs_slice.iter()) { + if l < r { + return false + }else if l > r { + equal = false; + } + } + !equal + }else{ + false + } + } + + fn ge(&self, other: &VClock) -> bool { + // Load the values as slices + let lhs_slice = self.as_slice(); + let rhs_slice = other.as_slice(); + + // If r_len > l_len then at least one element + // in r_len is > than l_len, therefore the result + // is either Some(Less) or None, so return false + // early. + let l_len = lhs_slice.len(); + let r_len = rhs_slice.len(); + if l_len >= r_len { + // If any elements on the left are less than the right + // then the result is None or Some(Less), both of which + // return false, the earlier test asserts that no elements in the + // extended tail violate this assumption. Otherwise l >= r + !lhs_slice.iter().zip(rhs_slice.iter()).any(|(&l, &r)| l < r) + }else{ + false + } + } +} + +impl Index for VClock { + type Output = VTimestamp; + + #[inline] + fn index(&self, index: VectorIdx) -> &VTimestamp { + self.as_slice().get(index.to_u32() as usize).unwrap_or(&0) + } +} + + +/// Test vector clock ordering operations +/// data-race detection is tested in the external +/// test suite +#[cfg(test)] +mod tests { + use super::{VClock, VTimestamp, VectorIdx, VSmallClockSet}; + use std::cmp::Ordering; + + #[test] + fn test_equal() { + let mut c1 = VClock::default(); + let mut c2 = VClock::default(); + assert_eq!(c1, c2); + c1.increment_index(VectorIdx(5)); + assert_ne!(c1, c2); + c2.increment_index(VectorIdx(53)); + assert_ne!(c1, c2); + c1.increment_index(VectorIdx(53)); + assert_ne!(c1, c2); + c2.increment_index(VectorIdx(5)); + assert_eq!(c1, c2); + } + + #[test] + fn test_partial_order() { + // Small test + assert_order(&[1], &[1], Some(Ordering::Equal)); + assert_order(&[1], &[2], Some(Ordering::Less)); + assert_order(&[2], &[1], Some(Ordering::Greater)); + assert_order(&[1], &[1,2], Some(Ordering::Less)); + assert_order(&[2], &[1,2], None); + + // Misc tests + assert_order(&[400], &[0, 1], None); + + // Large test + assert_order(&[0,1,2,3,4,5,6,7,8,9,10], &[0,1,2,3,4,5,6,7,8,9,10,0,0,0], Some(Ordering::Equal)); + assert_order(&[0,1,2,3,4,5,6,7,8,9,10], &[0,1,2,3,4,5,6,7,8,9,10,0,1,0], Some(Ordering::Less)); + assert_order(&[0,1,2,3,4,5,6,7,8,9,11], &[0,1,2,3,4,5,6,7,8,9,10,0,0,0], Some(Ordering::Greater)); + assert_order(&[0,1,2,3,4,5,6,7,8,9,11], &[0,1,2,3,4,5,6,7,8,9,10,0,1,0], None); + assert_order(&[0,1,2,3,4,5,6,7,8,9,9 ], &[0,1,2,3,4,5,6,7,8,9,10,0,0,0], Some(Ordering::Less)); + assert_order(&[0,1,2,3,4,5,6,7,8,9,9 ], &[0,1,2,3,4,5,6,7,8,9,10,0,1,0], Some(Ordering::Less)); + } + + fn from_slice(mut slice: &[VTimestamp]) -> VClock { + while let Some(0) = slice.last() { + slice = &slice[..slice.len() - 1] + } + VClock(smallvec::SmallVec::from_slice(slice)) + } + + fn assert_order(l: &[VTimestamp], r: &[VTimestamp], o: Option) { + let l = from_slice(l); + let r = from_slice(r); + + //Test partial_cmp + let compare = l.partial_cmp(&r); + assert_eq!(compare, o, "Invalid comparison\n l: {:?}\n r: {:?}",l,r); + let alt_compare = r.partial_cmp(&l); + assert_eq!(alt_compare, o.map(Ordering::reverse), "Invalid alt comparison\n l: {:?}\n r: {:?}",l,r); + + //Test operatorsm with faster implementations + assert_eq!( + matches!(compare,Some(Ordering::Less)), l < r, + "Invalid (<):\n l: {:?}\n r: {:?}",l,r + ); + assert_eq!( + matches!(compare,Some(Ordering::Less) | Some(Ordering::Equal)), l <= r, + "Invalid (<=):\n l: {:?}\n r: {:?}",l,r + ); + assert_eq!( + matches!(compare,Some(Ordering::Greater)), l > r, + "Invalid (>):\n l: {:?}\n r: {:?}",l,r + ); + assert_eq!( + matches!(compare,Some(Ordering::Greater) | Some(Ordering::Equal)), l >= r, + "Invalid (>=):\n l: {:?}\n r: {:?}",l,r + ); + assert_eq!( + matches!(alt_compare,Some(Ordering::Less)), r < l, + "Invalid alt (<):\n l: {:?}\n r: {:?}",l,r + ); + assert_eq!( + matches!(alt_compare,Some(Ordering::Less) | Some(Ordering::Equal)), r <= l, + "Invalid alt (<=):\n l: {:?}\n r: {:?}",l,r + ); + assert_eq!( + matches!(alt_compare,Some(Ordering::Greater)), r > l, + "Invalid alt (>):\n l: {:?}\n r: {:?}",l,r + ); + assert_eq!( + matches!(alt_compare,Some(Ordering::Greater) | Some(Ordering::Equal)), r >= l, + "Invalid alt (>=):\n l: {:?}\n r: {:?}",l,r + ); + } + + #[test] + pub fn test_vclock_set() { + let mut set = VSmallClockSet::default(); + let v1 = from_slice(&[3,0,1]); + let v2 = from_slice(&[4,2,3]); + let v3 = from_slice(&[4,8,3]); + set.insert(VectorIdx(0), &v1); + assert_eq!(set.get(VectorIdx(0)), Some(&v1)); + set.insert(VectorIdx(5), &v2); + assert_eq!(set.get(VectorIdx(0)), Some(&v1)); + assert_eq!(set.get(VectorIdx(5)), Some(&v2)); + set.insert(VectorIdx(53), &v3); + assert_eq!(set.get(VectorIdx(0)), Some(&v1)); + assert_eq!(set.get(VectorIdx(5)), Some(&v2)); + assert_eq!(set.get(VectorIdx(53)), Some(&v3)); + set.retain_index(VectorIdx(53)); + assert_eq!(set.get(VectorIdx(0)), None); + assert_eq!(set.get(VectorIdx(5)), None); + assert_eq!(set.get(VectorIdx(53)), Some(&v3)); + set.clear(); + assert_eq!(set.get(VectorIdx(0)), None); + assert_eq!(set.get(VectorIdx(5)), None); + assert_eq!(set.get(VectorIdx(53)), None); + set.insert(VectorIdx(53), &v3); + assert_eq!(set.get(VectorIdx(0)), None); + assert_eq!(set.get(VectorIdx(5)), None); + assert_eq!(set.get(VectorIdx(53)), Some(&v3)); + } +} From c70bbea257d43242fa9f700d099c4a8a8eae2971 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Thu, 5 Nov 2020 14:18:28 +0000 Subject: [PATCH 2434/5092] Move to use of thread termination hook for vector re-use, convert validate atomic op to use shared reference and get_raw instead of get_raw_mut so it can be used for validate_atomic_load as well --- src/data_race.rs | 175 ++++++++++++++++++++++++----------------------- src/thread.rs | 1 + 2 files changed, 91 insertions(+), 85 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index e992c5a1d589..153e63b77dfd 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -159,52 +159,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { &self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicReadOp ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); - let data_race = &*this.memory.extra.data_race; - if data_race.multi_threaded.get() { - - // Load an log the atomic operation - // the memory access has to be `get_raw` since otherwise this despite only - // mutating MemoryExtra will still trigger errors on read-only memory - let place_ptr = place.ptr.assert_ptr(); - let size = place.layout.size; - let alloc_meta = &this.memory.get_raw(place_ptr.alloc_id)?.extra.data_race; - log::trace!( - "Atomic op({}) with ordering {:?} on memory({:?}, offset={}, size={})", - "Atomic load", &atomic, place_ptr.alloc_id, place_ptr.offset.bytes(), size.bytes() - ); - - // Perform the atomic operation - let data_race = &alloc_meta.global; - data_race.maybe_perform_sync_operation(move |index, mut clocks| { - for (_,range) in alloc_meta.alloc_ranges.borrow_mut().iter_mut(place_ptr.offset, size) { - let res = if atomic == AtomicReadOp::Relaxed { - range.load_relaxed(&mut *clocks, index) - }else{ - range.acquire(&mut *clocks, index) - }; - if let Err(DataRace) = res { - mem::drop(clocks); - return VClockAlloc::report_data_race( - &alloc_meta.global, range, "Atomic load", true, - place_ptr, size - ); - } - } - Ok(()) - })?; - - // Log changes to atomic memory - if log::log_enabled!(log::Level::Trace) { - for (_,range) in alloc_meta.alloc_ranges.borrow().iter(place_ptr.offset, size) { - log::trace!( - "Updated atomic memory({:?}, offset={}, size={}) to {:#?}", - place.ptr.assert_ptr().alloc_id, place_ptr.offset.bytes(), size.bytes(), - range.atomic_ops - ); + this.validate_atomic_op( + place, atomic, "Atomic Load", + move |memory, clocks, index, atomic| { + if atomic == AtomicReadOp::Relaxed { + memory.load_relaxed(&mut *clocks, index) + }else{ + memory.acquire(&mut *clocks, index) } } - } - Ok(()) + ) } /// Update the data-race detector for an atomic write occuring at the @@ -212,8 +176,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { fn validate_atomic_store( &mut self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicWriteOp ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - this.validate_atomic_op_mut( + let this = self.eval_context_ref(); + this.validate_atomic_op( place, atomic, "Atomic Store", move |memory, clocks, index, atomic| { if atomic == AtomicWriteOp::Relaxed { @@ -233,8 +197,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { use AtomicRWOp::*; let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); let release = matches!(atomic, Release | AcqRel | SeqCst); - let this = self.eval_context_mut(); - this.validate_atomic_op_mut( + let this = self.eval_context_ref(); + this.validate_atomic_op( place, atomic, "Atomic RMW", move |memory, clocks, index, _| { if acquire { @@ -276,25 +240,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { - /// Generic atomic operation implementation, this however - /// cannot be used for the atomic read operation since - /// that requires non mutable memory access to not trigger - /// the writing to read-only memory errors during `get_raw_mut` - fn validate_atomic_op_mut( - &mut self, place: MPlaceTy<'tcx, Tag>, + /// Generic atomic operation implementation, + /// this accesses memory via get_raw instead of + /// get_raw_mut, due to issues calling get_raw_mut + /// for atomic loads from read-only memory + /// FIXME: is this valid, or should get_raw_mut be used for + /// atomic-stores/atomic-rmw? + fn validate_atomic_op( + &self, place: MPlaceTy<'tcx, Tag>, atomic: A, description: &str, mut op: impl FnMut( &mut MemoryCellClocks, &mut ThreadClockSet, VectorIdx, A ) -> Result<(), DataRace> ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); + let this = self.eval_context_ref(); let data_race = &*this.memory.extra.data_race; if data_race.multi_threaded.get() { // Load an log the atomic operation let place_ptr = place.ptr.assert_ptr(); let size = place.layout.size; - let alloc_meta = &mut this.memory.get_raw_mut(place_ptr.alloc_id)?.extra.data_race; + let alloc_meta = &this.memory.get_raw(place_ptr.alloc_id)?.extra.data_race; log::trace!( "Atomic op({}) with ordering {:?} on memory({:?}, offset={}, size={})", description, &atomic, place_ptr.alloc_id, place_ptr.offset.bytes(), size.bytes() @@ -800,6 +766,29 @@ impl ThreadClockSet { } } +/// Extra metadata associated with a thread +#[derive(Debug, Clone, Default)] +struct ThreadExtraState { + + /// The current vector index in use by the + /// thread currently, this is set to None + /// after the vector index has been re-used + vector_index: Option, + + /// The name of the thread, updated for better + /// diagnostics when reporting detected data + /// races + thread_name: Option>, + + /// Thread termination vector clock, this + /// is set on thread termination and is used + /// for joining on threads that have already + /// terminated. This should be used first + /// on joining as there is the possibility + /// that `vector_index` is None in some cases + termination_vector_clock: Option, +} + /// Global data-race detection state, contains the currently /// executing thread as well as the vector-clocks associated /// with each of the threads. @@ -822,18 +811,18 @@ pub struct GlobalState { /// Mapping of a given vector index to the current thread /// that the execution is representing, this may change /// if a vector index is re-assigned to a new thread - vector_info: RefCell>, //FIXME: make option + vector_info: RefCell>, - /// The mapping of a given thread to a known vector clock - thread_info: RefCell, Option>)>>, + /// The mapping of a given thread to assocaited thread metadata + thread_info: RefCell>, /// The current vector index being executed current_index: Cell, /// Potential vector indices that could be re-used on thread creation - /// values are inserted here on thread join events, and can be - /// re-used once the vector clocks of all current threads - /// are equal to the vector clock of the joined thread + /// values are inserted here on thread termination, vector index values + /// are then re-used once all the termination event happens-before all + /// existing thread-clocks reuse_candidates: RefCell>, } impl GlobalState { @@ -856,8 +845,12 @@ impl GlobalState { let index = global_state.vector_clocks.borrow_mut().push(ThreadClockSet::default()); global_state.vector_info.borrow_mut().push(ThreadId::new(0)); global_state.thread_info.borrow_mut().push( - (Some(index), Some("main".to_string().into_boxed_str()) - )); + ThreadExtraState { + vector_index: Some(index), + thread_name: Some("main".to_string().into_boxed_str()), + termination_vector_clock: None + } + ); global_state } @@ -873,10 +866,9 @@ impl GlobalState { clock.clock[candidate] == target_timestamp }) { // All vector clocks for each vector index are equal to - // the target timestamp, therefore since the thread has - // terminated and cannot update the vector clock. - // No more data-races involving this vector index are possible - // so it can be re-used + // the target timestamp, and the thread is known to have + // terminated, therefore this vector clock index cannot + // report any more data-races assert!(reuse.remove(&candidate)); return Some(candidate) } @@ -916,7 +908,7 @@ impl GlobalState { // Mark the thread the vector index was associated with as no longer // representing a thread index - thread_info[old_thread].0 = None; + thread_info[old_thread].vector_index = None; reuse_index }else{ @@ -927,7 +919,7 @@ impl GlobalState { }; // Mark the chosen vector index as in use by the thread - thread_info[thread].0 = Some(created_index); + thread_info[thread].vector_index = Some(created_index); // Create a thread clock set if applicable let mut vector_clocks = self.vector_clocks.borrow_mut(); @@ -952,15 +944,13 @@ impl GlobalState { /// Hook on a thread join to update the implicit happens-before relation /// between the joined thead and the current thread. - /// Called after the join has occured, and hence implicitly also states - /// that the thread must have terminated as well #[inline] pub fn thread_joined(&self, current_thread: ThreadId, join_thread: ThreadId) { let (current_index, join_index) = { let thread_info = self.thread_info.borrow(); - let current_index = thread_info[current_thread].0 + let current_index = thread_info[current_thread].vector_index .expect("Joining into thread with no assigned vector"); - let join_index = thread_info[join_thread].0 + let join_index = thread_info[join_thread].vector_index .expect("Joining thread with no assigned vector"); (current_index, join_index) }; @@ -976,16 +966,31 @@ impl GlobalState { current.join_with(join); // Post increment clocks after atomic operation + // the join clock is not incremented, since there will + // be no future events, also if it was incremented + // the thread re-use condition would never pass current.increment_clock(current_index); - join.increment_clock(join_index); + } - // The joined thread vector clock is a potential candidate - // for re-use given sufficient time, mark as available once - // threads have been created. This is because this function - // is called once join_thread has terminated and such cannot - // update any-more + /// On thread termination, the vector-clock may re-used + /// in the future once all remaining thread-clocks catch + /// up with the time index of the terminated thread + #[inline] + pub fn thread_terminated(&self, terminated_thread: ThreadId) { + let mut thread_info = self.thread_info.borrow_mut(); + let termination_meta = &mut thread_info[terminated_thread]; + + // Find the terminated index & setup the termination vector-clock + // in case thread join is called in the future after the thread + // has been re-used + let terminated_index = termination_meta.vector_index + .expect("Joining into thread with no assigned vector"); + let vector_clocks = self.vector_clocks.borrow(); + termination_meta.termination_vector_clock = Some(vector_clocks[terminated_index].clock.clone()); + + // Add this thread as a candidate for re-use let mut reuse = self.reuse_candidates.borrow_mut(); - reuse.insert(join_index); + reuse.insert(terminated_index); } /// Hook for updating the local tracker of the currently @@ -994,7 +999,7 @@ impl GlobalState { #[inline] pub fn thread_set_active(&self, thread: ThreadId) { let thread_info = self.thread_info.borrow(); - let vector_idx = thread_info[thread].0 + let vector_idx = thread_info[thread].vector_index .expect("Setting thread active with no assigned vector"); self.current_index.set(vector_idx); } @@ -1007,7 +1012,7 @@ impl GlobalState { pub fn thread_set_name(&self, thread: ThreadId, name: String) { let name = name.into_boxed_str(); let mut thread_info = self.thread_info.borrow_mut(); - thread_info[thread].1 = Some(name); + thread_info[thread].thread_name = Some(name); } @@ -1036,7 +1041,7 @@ impl GlobalState { /// returns the id and the name for better diagnostics fn print_thread_metadata(&self, vector: VectorIdx) -> String { let thread = self.vector_info.borrow()[vector]; - let thread_name = &self.thread_info.borrow()[thread].1; + let thread_name = &self.thread_info.borrow()[thread].thread_name; if let Some(name) = thread_name { let name: &str = name; format!("Thread(id = {:?}, name = {:?})", thread.to_u32(), &*name) @@ -1079,7 +1084,7 @@ impl GlobalState { /// used by the thread #[inline] fn load_thread_state_mut(&self, thread: ThreadId) -> (VectorIdx, RefMut<'_, ThreadClockSet>) { - let index = self.thread_info.borrow()[thread].0 + let index = self.thread_info.borrow()[thread].vector_index .expect("Loading thread state for thread with no assigned vector"); let ref_vector = self.vector_clocks.borrow_mut(); let clocks = RefMut::map(ref_vector, |vec| &mut vec[index]); diff --git a/src/thread.rs b/src/thread.rs index f94805ae022a..976ac816a048 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -452,6 +452,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { thread.state = ThreadState::Enabled; } } + data_race.thread_terminated(self.active_thread); return free_tls_statics; } From f31f00d5af9b5e6ec445c8a61349831182f90d53 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 5 Nov 2020 17:09:44 +0100 Subject: [PATCH 2435/5092] rustup --- rust-version | 2 +- src/shims/backtrace.rs | 5 +---- tests/compile-fail/backtrace/bad-backtrace-ptr.rs | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index efb6b94d3b40..514517267a01 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -5cdf5b882da9e8b7c73b5cadeb7745cb68f6ff63 +89631663b7ad2d46d3e4f52bcfa7bee2be9eb82b diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 8cf7ac207528..a599ee70efae 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -81,10 +81,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("unknown `miri_resolve_frame` flags {}", flags); } - let ptr = match this.read_scalar(ptr)?.check_init()? { - Scalar::Ptr(ptr) => ptr, - Scalar::Raw { .. } => throw_ub_format!("expected a pointer in `rust_miri_resolve_frame`, found {:?}", ptr) - }; + let ptr = this.force_ptr(this.read_scalar(ptr)?.check_init()?)?; let fn_instance = if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(ptr.alloc_id) { instance diff --git a/tests/compile-fail/backtrace/bad-backtrace-ptr.rs b/tests/compile-fail/backtrace/bad-backtrace-ptr.rs index 5e245952e9b2..0c49a527bc16 100644 --- a/tests/compile-fail/backtrace/bad-backtrace-ptr.rs +++ b/tests/compile-fail/backtrace/bad-backtrace-ptr.rs @@ -4,6 +4,6 @@ extern "Rust" { fn main() { unsafe { - miri_resolve_frame(0 as *mut _, 0); //~ ERROR Undefined Behavior: expected a pointer + miri_resolve_frame(0 as *mut _, 0); //~ ERROR 0x0 is not a valid pointer } } From 2a40d9b7a07f9a770455de26e46b766bdb395206 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Fri, 6 Nov 2020 17:29:54 +0000 Subject: [PATCH 2436/5092] More aggressive vector index re-use, and added some tests. --- src/data_race.rs | 190 ++++++++++++------ src/thread.rs | 3 +- .../data_race/dangling_thread_async_race.rs | 44 ++++ .../data_race/dangling_thread_race.rs | 41 ++++ .../data_race/enable_after_join_to_main.rs | 38 ++++ 5 files changed, 254 insertions(+), 62 deletions(-) create mode 100644 tests/compile-fail/data_race/dangling_thread_async_race.rs create mode 100644 tests/compile-fail/data_race/dangling_thread_race.rs create mode 100644 tests/compile-fail/data_race/enable_after_join_to_main.rs diff --git a/src/data_race.rs b/src/data_race.rs index 153e63b77dfd..57f09146d6f8 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -20,7 +20,7 @@ use std::{ use rustc_index::vec::{Idx, IndexVec}; use rustc_target::abi::Size; use rustc_middle::ty::layout::TyAndLayout; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use crate::{ MiriEvalContext, MiriEvalContextExt, @@ -662,7 +662,7 @@ impl VClockAlloc { let (index, clocks) = self.global.current_thread_state(); let mut alloc_ranges = self.alloc_ranges.borrow_mut(); for (_,range) in alloc_ranges.iter_mut(pointer.offset, len) { - if range.read_race_detect(&*clocks, index) == Err(DataRace) { + if let Err(DataRace) = range.read_race_detect(&*clocks, index) { // Report data-race return Self::report_data_race( &self.global,range, "READ", false, pointer, len @@ -674,18 +674,17 @@ impl VClockAlloc { Ok(()) } } - /// Detect data-races for an unsychronized write operation, will not perform - /// data-race threads if `multi-threaded` is false, either due to no threads - /// being created or if it is temporarily disabled during a racy read or write - /// operation - pub fn write<'tcx>(&mut self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { + + + // Shared code for detecting data-races on unique access to a section of memory + fn unique_access<'tcx>(&mut self, pointer: Pointer, len: Size, action: &str) -> InterpResult<'tcx> { if self.global.multi_threaded.get() { let (index, clocks) = self.global.current_thread_state(); for (_,range) in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { - if range.write_race_detect(&*clocks, index) == Err(DataRace) { + if let Err(DataRace) = range.write_race_detect(&*clocks, index) { // Report data-race return Self::report_data_race( - &self.global, range, "WRITE", false, pointer, len + &self.global, range, action, false, pointer, len ); } } @@ -694,25 +693,20 @@ impl VClockAlloc { Ok(()) } } + + /// Detect data-races for an unsychronized write operation, will not perform + /// data-race threads if `multi-threaded` is false, either due to no threads + /// being created or if it is temporarily disabled during a racy read or write + /// operation + pub fn write<'tcx>(&mut self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { + self.unique_access(pointer, len, "Write") + } /// Detect data-races for an unsychronized deallocate operation, will not perform /// data-race threads if `multi-threaded` is false, either due to no threads /// being created or if it is temporarily disabled during a racy read or write /// operation pub fn deallocate<'tcx>(&mut self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { - if self.global.multi_threaded.get() { - let (index, clocks) = self.global.current_thread_state(); - for (_,range) in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { - if range.write_race_detect(&*clocks, index) == Err(DataRace) { - // Report data-race - return Self::report_data_race( - &self.global, range, "DEALLOCATE", false, pointer, len - ); - } - } - Ok(()) - }else{ - Ok(()) - } + self.unique_access(pointer, len, "Deallocate") } } @@ -773,6 +767,8 @@ struct ThreadExtraState { /// The current vector index in use by the /// thread currently, this is set to None /// after the vector index has been re-used + /// and hence the value will never need to be + /// read during data-race reporting vector_index: Option, /// The name of the thread, updated for better @@ -782,10 +778,8 @@ struct ThreadExtraState { /// Thread termination vector clock, this /// is set on thread termination and is used - /// for joining on threads that have already - /// terminated. This should be used first - /// on joining as there is the possibility - /// that `vector_index` is None in some cases + /// for joining on threads since the vector_index + /// may be re-used when the join operation occurs termination_vector_clock: Option, } @@ -820,10 +814,26 @@ pub struct GlobalState { current_index: Cell, /// Potential vector indices that could be re-used on thread creation - /// values are inserted here on thread termination, vector index values - /// are then re-used once all the termination event happens-before all - /// existing thread-clocks + /// values are inserted here on after the thread has terminated and + /// been joined with, and hence may potentially become free + /// for use as the index for a new thread. + /// Elements in this set may still require the vector index to + /// report data-races, and can only be re-used after all + /// active vector-clocks catch up with the threads timestamp. reuse_candidates: RefCell>, + + /// Counts the number of threads that are currently active + /// if the number of active threads reduces to 1 and then + /// a join operation occures with the remaining main thread + /// then multi-threaded execution may be disabled + active_thread_count: Cell, + + /// This contains threads that have terminated, but not yet joined + /// and so cannot become re-use candidates until a join operation + /// occurs. + /// The associated vector index will be moved into re-use candidates + /// after the join operation occurs + terminated_threads: RefCell>, } impl GlobalState { @@ -836,7 +846,9 @@ impl GlobalState { vector_info: RefCell::new(IndexVec::new()), thread_info: RefCell::new(IndexVec::new()), current_index: Cell::new(VectorIdx::new(0)), + active_thread_count: Cell::new(1), reuse_candidates: RefCell::new(FxHashSet::default()), + terminated_threads: RefCell::new(FxHashMap::default()) }; // Setup the main-thread since it is not explicitly created: @@ -860,10 +872,24 @@ impl GlobalState { fn find_vector_index_reuse_candidate(&self) -> Option { let mut reuse = self.reuse_candidates.borrow_mut(); let vector_clocks = self.vector_clocks.borrow(); + let vector_info = self.vector_info.borrow(); + let terminated_threads = self.terminated_threads.borrow(); for &candidate in reuse.iter() { let target_timestamp = vector_clocks[candidate].clock[candidate]; - if vector_clocks.iter().all(|clock| { - clock.clock[candidate] == target_timestamp + if vector_clocks.iter_enumerated().all(|(clock_idx, clock)| { + // The thread happens before the clock, and hence cannot report + // a data-race with this the candidate index + let no_data_race = clock.clock[candidate] >= target_timestamp; + + // The vector represents a thread that has terminated and hence cannot + // report a data-race with the candidate index + let thread_id = vector_info[clock_idx]; + let vector_terminated = reuse.contains(&clock_idx) + || terminated_threads.contains_key(&thread_id); + + // The vector index cannot report a race with the candidate index + // and hence allows the candidate index to be re-used + no_data_race || vector_terminated }) { // All vector clocks for each vector index are equal to // the target timestamp, and the thread is known to have @@ -882,6 +908,10 @@ impl GlobalState { pub fn thread_created(&self, thread: ThreadId) { let current_index = self.current_index(); + // Increment the number of active threads + let active_threads = self.active_thread_count.get(); + self.active_thread_count.set(active_threads + 1); + // Enable multi-threaded execution, there are now two threads // so data-races are now possible. self.multi_threaded.set(true); @@ -946,51 +976,90 @@ impl GlobalState { /// between the joined thead and the current thread. #[inline] pub fn thread_joined(&self, current_thread: ThreadId, join_thread: ThreadId) { - let (current_index, join_index) = { - let thread_info = self.thread_info.borrow(); - let current_index = thread_info[current_thread].vector_index - .expect("Joining into thread with no assigned vector"); - let join_index = thread_info[join_thread].vector_index - .expect("Joining thread with no assigned vector"); - (current_index, join_index) - }; let mut clocks_vec = self.vector_clocks.borrow_mut(); - let (current, join) = clocks_vec.pick2_mut(current_index, join_index); + let thread_info = self.thread_info.borrow(); + + // Load the vector clock of the current thread + let current_index = thread_info[current_thread].vector_index + .expect("Performed thread join on thread with no assigned vector"); + let current = &mut clocks_vec[current_index]; + + // Load the associated vector clock for the terminated thread + let join_clock = thread_info[join_thread].termination_vector_clock + .as_ref().expect("Joined with thread but thread has not terminated"); // Pre increment clocks before atomic operation current.increment_clock(current_index); - join.increment_clock(join_index); // The join thread happens-before the current thread // so update the current vector clock - current.join_with(join); + current.clock.join(join_clock); // Post increment clocks after atomic operation - // the join clock is not incremented, since there will - // be no future events, also if it was incremented - // the thread re-use condition would never pass current.increment_clock(current_index); + + // Check the number of active threads, if the value is 1 + // then test for potentially disabling multi-threaded execution + let active_threads = self.active_thread_count.get(); + if active_threads == 1 { + // May potentially be able to disable multi-threaded execution + let current_clock = &clocks_vec[current_index]; + if clocks_vec.iter_enumerated().all(|(idx, clocks)| { + clocks.clock[idx] <= current_clock.clock[idx] + }) { + // The all thread termations happen-before the current clock + // therefore no data-races can be reported until a new thread + // is created, so disable multi-threaded execution + self.multi_threaded.set(false); + } + } + + // If the thread is marked as terminated but not joined + // then move the thread to the re-use set + let mut termination = self.terminated_threads.borrow_mut(); + if let Some(index) = termination.remove(&join_thread) { + let mut reuse = self.reuse_candidates.borrow_mut(); + reuse.insert(index); + } } /// On thread termination, the vector-clock may re-used /// in the future once all remaining thread-clocks catch - /// up with the time index of the terminated thread + /// up with the time index of the terminated thread. + /// This assiges thread termination with a unique index + /// which will be used to join the thread + /// This should be called strictly before any calls to + /// `thread_joined` #[inline] - pub fn thread_terminated(&self, terminated_thread: ThreadId) { + pub fn thread_terminated(&self) { + let current_index = self.current_index(); + + // Increment the clock to a unique termination timestamp + let mut vector_clocks = self.vector_clocks.borrow_mut(); + let current_clocks = &mut vector_clocks[current_index]; + current_clocks.increment_clock(current_index); + + // Load the current thread id for the executing vector + let vector_info = self.vector_info.borrow(); + let current_thread = vector_info[current_index]; + + // Load the current thread metadata, and move to a terminated + // vector state. Setting up the vector clock all join operations + // will use. let mut thread_info = self.thread_info.borrow_mut(); - let termination_meta = &mut thread_info[terminated_thread]; + let current = &mut thread_info[current_thread]; + current.termination_vector_clock = Some(current_clocks.clock.clone()); - // Find the terminated index & setup the termination vector-clock - // in case thread join is called in the future after the thread - // has been re-used - let terminated_index = termination_meta.vector_index - .expect("Joining into thread with no assigned vector"); - let vector_clocks = self.vector_clocks.borrow(); - termination_meta.termination_vector_clock = Some(vector_clocks[terminated_index].clock.clone()); - - // Add this thread as a candidate for re-use - let mut reuse = self.reuse_candidates.borrow_mut(); - reuse.insert(terminated_index); + // Add this thread as a candidate for re-use after a thread join + // occurs + let mut termination = self.terminated_threads.borrow_mut(); + termination.insert(current_thread, current_index); + + // Reduce the number of active threads, now that a thread has + // terminated + let mut active_threads = self.active_thread_count.get(); + active_threads -= 1; + self.active_thread_count.set(active_threads); } /// Hook for updating the local tracker of the currently @@ -1118,4 +1187,3 @@ impl GlobalState { self.current_index.get() } } - diff --git a/src/thread.rs b/src/thread.rs index 976ac816a048..40cfd04d7923 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -443,6 +443,8 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { return false; }); } + // Set the thread into a terminated state in the data-race detector + data_race.thread_terminated(); // Check if we need to unblock any threads. for (i, thread) in self.threads.iter_enumerated_mut() { if thread.state == ThreadState::BlockedOnJoin(self.active_thread) { @@ -452,7 +454,6 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { thread.state = ThreadState::Enabled; } } - data_race.thread_terminated(self.active_thread); return free_tls_statics; } diff --git a/tests/compile-fail/data_race/dangling_thread_async_race.rs b/tests/compile-fail/data_race/dangling_thread_async_race.rs new file mode 100644 index 000000000000..6af5706835e3 --- /dev/null +++ b/tests/compile-fail/data_race/dangling_thread_async_race.rs @@ -0,0 +1,44 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-isolation + +use std::thread::{spawn, sleep}; +use std::time::Duration; +use std::mem; + + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + + +fn main() { + let mut a = 0u32; + let b = &mut a as *mut u32; + let c = EvilSend(b); + + let join = unsafe { + spawn(move || { + *c.0 = 32; + }) + }; + + // Detatch the thread and sleep until it terminates + mem::drop(join); + sleep(Duration::from_millis(100)); + + // Spawn and immediately join a thread + // to execute the join code-path + // and ensure that data-race detection + // remains enabled + spawn(|| ()).join().unwrap(); + + let join2 = unsafe { + spawn(move || { + *c.0 = 64; //~ ERROR Data race + }) + }; + + join2.join().unwrap(); +} diff --git a/tests/compile-fail/data_race/dangling_thread_race.rs b/tests/compile-fail/data_race/dangling_thread_race.rs new file mode 100644 index 000000000000..c37f303bbab2 --- /dev/null +++ b/tests/compile-fail/data_race/dangling_thread_race.rs @@ -0,0 +1,41 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-isolation + +use std::thread::{spawn, sleep}; +use std::time::Duration; +use std::mem; + + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + + +fn main() { + let mut a = 0u32; + let b = &mut a as *mut u32; + let c = EvilSend(b); + + let join = unsafe { + spawn(move || { + *c.0 = 32; + }) + }; + + // Detatch the thread and sleep until it terminates + mem::drop(join); + sleep(Duration::from_millis(100)); + + // Spawn and immediately join a thread + // to execute the join code-path + // and ensure that data-race detection + // remains enabled + spawn(|| ()).join().unwrap(); + + + unsafe { + *c.0 = 64; //~ ERROR Data race + } +} diff --git a/tests/compile-fail/data_race/enable_after_join_to_main.rs b/tests/compile-fail/data_race/enable_after_join_to_main.rs new file mode 100644 index 000000000000..fba7ba4841cc --- /dev/null +++ b/tests/compile-fail/data_race/enable_after_join_to_main.rs @@ -0,0 +1,38 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +use std::thread::spawn; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + // Enable and the join with multiple threads + let t1 = spawn(|| ()); + let t2 = spawn(|| ()); + let t3 = spawn(|| ()); + let t4 = spawn(|| ()); + t1.join().unwrap(); + t2.join().unwrap(); + t3.join().unwrap(); + t4.join().unwrap(); + + // Perform write-write data race detection + let mut a = 0u32; + let b = &mut a as *mut u32; + let c = EvilSend(b); + unsafe { + let j1 = spawn(move || { + *c.0 = 32; + }); + + let j2 = spawn(move || { + *c.0 = 64; //~ ERROR Data race + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} From 330ec0acdbdff74be1fa75e86aab561302bf5700 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 7 Nov 2020 15:56:25 +0100 Subject: [PATCH 2437/5092] enable overflow checks in the standard library --- cargo-miri/bin.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 6eff5f795e7c..d18e9608cf50 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -354,7 +354,8 @@ path = "lib.rs" command.env_remove("RUSTC_WRAPPER"); command.env_remove("RUSTFLAGS"); // Disable debug assertions in the standard library -- Miri is already slow enough. - command.env("RUSTFLAGS", "-Cdebug-assertions=off"); + // But keep the overflow checks, they are cheap. + command.env("RUSTFLAGS", "-Cdebug-assertions=off -Coverflow-checks=on"); // Finally run it! if command.status().expect("failed to run xargo").success().not() { show_error(format!("failed to run xargo")); From 6a475c3ddf8ee0868f0723683aa2720e8f87d44a Mon Sep 17 00:00:00 2001 From: Camelid Date: Sat, 7 Nov 2020 11:26:41 -0800 Subject: [PATCH 2438/5092] CONTRIBUTING.md: Update comment Co-authored-by: Ralf Jung --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 20f01f151a65..08dcd541f7bf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -147,7 +147,7 @@ cd rustc cp config.toml.example config.toml # Now edit `config.toml` and set `debug-assertions = true`. -# Build a stage 1 rustc. +# Build a stage 1 rustc, and build the rustc libraries with that rustc. # This step can take 30 minutes or more. ./x.py build --stage 1 compiler/rustc # If you change something, you can get a faster rebuild by doing From 43ce2c2844ebe1918716a1e599b159a0eb5885cd Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 31 Oct 2020 15:06:06 -0400 Subject: [PATCH 2439/5092] Improve contributing instructions - Fix incorrect comment - Recommend `x.py setup` over manually editing config.toml - Link to rustc-dev-guide --- CONTRIBUTING.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 08dcd541f7bf..bbfcb7638f38 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -144,8 +144,9 @@ The setup for a local rustc works as follows: # Clone the rust-lang/rust repo. git clone https://github.com/rust-lang/rust rustc cd rustc -cp config.toml.example config.toml -# Now edit `config.toml` and set `debug-assertions = true`. +# Create a config.toml with defaults for working on miri. +./x.py setup compiler + # Now edit `config.toml` and under `[rust]` set `debug-assertions = true`. # Build a stage 1 rustc, and build the rustc libraries with that rustc. # This step can take 30 minutes or more. @@ -158,5 +159,8 @@ rustup toolchain link stage1 build/x86_64-unknown-linux-gnu/stage1 rustup override set stage1 ``` +For more information about building and configuring a local compiler, +see . + With this, you should now have a working development setup! See [above](#building-and-testing-miri) for how to proceed working on Miri. From 737ecef376925f77500495d431a22cfbaecddcbe Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 10 Nov 2020 16:47:56 +0100 Subject: [PATCH 2440/5092] rustup and update test --- rust-version | 2 +- tests/run-pass/concurrency/sync_singlethread.rs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 514517267a01..c6a3130a5a49 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -89631663b7ad2d46d3e4f52bcfa7bee2be9eb82b +cf9cf7c923eb01146971429044f216a3ca905e06 diff --git a/tests/run-pass/concurrency/sync_singlethread.rs b/tests/run-pass/concurrency/sync_singlethread.rs index 749db855e296..ab0203906d36 100644 --- a/tests/run-pass/concurrency/sync_singlethread.rs +++ b/tests/run-pass/concurrency/sync_singlethread.rs @@ -1,5 +1,3 @@ -#![feature(rustc_private, renamed_spin_loop)] - use std::sync::{Mutex, TryLockError}; use std::sync::atomic; use std::hint; From db718d72aef42618343cbefb0350ac95b1f80af0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 10 Nov 2020 16:51:07 +0100 Subject: [PATCH 2441/5092] remove some unnecessary feature flags --- tests/compile-fail/check_arg_count_too_few_args.rs | 1 - tests/compile-fail/check_arg_count_too_many_args.rs | 1 - tests/compile-fail/shim_arg_size.rs | 2 -- tests/run-pass/calloc.rs | 4 ++-- tests/run-pass/fs.rs | 4 ++-- tests/run-pass/malloc.rs | 4 ++-- tests/run-pass/regions-mock-trans.rs | 1 + 7 files changed, 7 insertions(+), 10 deletions(-) diff --git a/tests/compile-fail/check_arg_count_too_few_args.rs b/tests/compile-fail/check_arg_count_too_few_args.rs index c6c19e042dd4..f8d11832683b 100644 --- a/tests/compile-fail/check_arg_count_too_few_args.rs +++ b/tests/compile-fail/check_arg_count_too_few_args.rs @@ -1,5 +1,4 @@ #![feature(core_intrinsics)] -#![feature(rustc_private)] fn main() { extern "C" { diff --git a/tests/compile-fail/check_arg_count_too_many_args.rs b/tests/compile-fail/check_arg_count_too_many_args.rs index cca03e53ec10..5163d223fa42 100644 --- a/tests/compile-fail/check_arg_count_too_many_args.rs +++ b/tests/compile-fail/check_arg_count_too_many_args.rs @@ -1,5 +1,4 @@ #![feature(core_intrinsics)] -#![feature(rustc_private)] fn main() { extern "C" { diff --git a/tests/compile-fail/shim_arg_size.rs b/tests/compile-fail/shim_arg_size.rs index dd8d6dac51de..556195d6e905 100644 --- a/tests/compile-fail/shim_arg_size.rs +++ b/tests/compile-fail/shim_arg_size.rs @@ -1,5 +1,3 @@ -#![feature(rustc_private)] - fn main() { extern "C" { // Use the wrong type(ie. not the pointer width) for the `size` diff --git a/tests/run-pass/calloc.rs b/tests/run-pass/calloc.rs index 6793f86c116c..9f614ce971ba 100644 --- a/tests/run-pass/calloc.rs +++ b/tests/run-pass/calloc.rs @@ -2,10 +2,10 @@ #![feature(rustc_private)] -use core::slice; - extern crate libc; +use core::slice; + fn main() { unsafe { let p1 = libc::calloc(0, 0); diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index f74d1c9a36b1..1261dbf1768d 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -3,6 +3,8 @@ #![feature(rustc_private)] +extern crate libc; + use std::fs::{ File, create_dir, OpenOptions, read_dir, remove_dir, remove_dir_all, remove_file, rename, }; @@ -10,8 +12,6 @@ use std::ffi::CString; use std::io::{Read, Write, Error, ErrorKind, Result, Seek, SeekFrom}; use std::path::{PathBuf, Path}; -extern crate libc; - fn main() { test_file(); diff --git a/tests/run-pass/malloc.rs b/tests/run-pass/malloc.rs index 8e0d9ac62932..b8eb7b50d340 100644 --- a/tests/run-pass/malloc.rs +++ b/tests/run-pass/malloc.rs @@ -2,10 +2,10 @@ #![feature(rustc_private)] -use core::{slice, ptr}; - extern crate libc; +use core::{slice, ptr}; + fn main() { // Test that small allocations sometimes *are* not very aligned. let saw_unaligned = (0..64).any(|_| unsafe { diff --git a/tests/run-pass/regions-mock-trans.rs b/tests/run-pass/regions-mock-trans.rs index 0b2433d84fa8..23ec91461db5 100644 --- a/tests/run-pass/regions-mock-trans.rs +++ b/tests/run-pass/regions-mock-trans.rs @@ -3,6 +3,7 @@ #![feature(rustc_private)] extern crate libc; + use std::mem; struct Arena(()); From df0de77fd1b5debc1e9aff4ddfcd73d24e21006f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 10 Nov 2020 16:51:55 +0100 Subject: [PATCH 2442/5092] test btreemap with raw ptr tracking --- tests/run-pass/btreemap.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/run-pass/btreemap.rs b/tests/run-pass/btreemap.rs index e639ba6225ca..ca548a03703e 100644 --- a/tests/run-pass/btreemap.rs +++ b/tests/run-pass/btreemap.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-track-raw-pointers +// ignore-windows (FIXME: tracking raw pointers does not work on Windows) #![feature(btree_drain_filter)] use std::collections::{BTreeMap, BTreeSet}; use std::mem; From 43673d9a87200f55423c01e85e108c2c9cfcefcb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Nov 2020 10:29:10 +0100 Subject: [PATCH 2443/5092] rustup --- rust-version | 2 +- src/helpers.rs | 6 +++--- src/machine.rs | 2 +- src/shims/env.rs | 12 ++++++------ src/shims/foreign_items.rs | 2 +- src/shims/os_str.rs | 2 +- src/shims/posix/foreign_items.rs | 4 ++-- src/shims/posix/fs.rs | 4 ++-- src/shims/posix/linux/dlsym.rs | 2 +- src/shims/posix/macos/dlsym.rs | 2 +- src/shims/tls.rs | 2 +- src/shims/windows/dlsym.rs | 2 +- src/shims/windows/foreign_items.rs | 2 +- 13 files changed, 22 insertions(+), 22 deletions(-) diff --git a/rust-version b/rust-version index c6a3130a5a49..e19cca38c040 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -cf9cf7c923eb01146971429044f216a3ca905e06 +38030ffb4e735b26260848b744c0910a5641e1db diff --git a/src/helpers.rs b/src/helpers.rs index a13d9b4519bd..4c989db0170b 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -387,7 +387,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// if this is not the case. fn assert_target_os(&self, target_os: &str, name: &str) { assert_eq!( - self.eval_context_ref().tcx.sess.target.target_os, + self.eval_context_ref().tcx.sess.target.os, target_os, "`{}` is only available on the `{}` target OS", name, @@ -431,8 +431,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx use std::io::ErrorKind::*; let this = self.eval_context_mut(); let target = &this.tcx.sess.target; - let target_os = &target.target_os; - let last_error = if target.options.target_family == Some("unix".to_owned()) { + let target_os = &target.os; + let last_error = if target.os_family == Some("unix".to_owned()) { this.eval_libc(match e.kind() { ConnectionRefused => "ECONNREFUSED", ConnectionReset => "ECONNRESET", diff --git a/src/machine.rs b/src/machine.rs index e9f9298e566c..2537956228ad 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -172,7 +172,7 @@ impl MemoryExtra { pub fn init_extern_statics<'tcx, 'mir>( this: &mut MiriEvalContext<'mir, 'tcx>, ) -> InterpResult<'tcx> { - match this.tcx.sess.target.target_os.as_str() { + match this.tcx.sess.target.os.as_str() { "linux" => { // "__cxa_thread_atexit_impl" // This should be all-zero, pointer-sized. diff --git a/src/shims/env.rs b/src/shims/env.rs index 2db64ad5a14c..12d1cda96da0 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -38,7 +38,7 @@ impl<'tcx> EnvVars<'tcx> { ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, mut excluded_env_vars: Vec, ) -> InterpResult<'tcx> { - let target_os = ecx.tcx.sess.target.target_os.as_str(); + let target_os = ecx.tcx.sess.target.os.as_str(); if target_os == "windows" { // Temporary hack: Exclude `TERM` var to avoid terminfo trying to open the termcap file. // Can be removed once https://github.com/rust-lang/miri/issues/1013 is resolved. @@ -101,7 +101,7 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn getenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.target_os; + let target_os = &this.tcx.sess.target.os; assert!(target_os == "linux" || target_os == "macos", "`getenv` is only available for the UNIX target family"); let name_ptr = this.read_scalar(name_op)?.check_init()?; @@ -185,7 +185,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx value_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let mut this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.target_os; + let target_os = &this.tcx.sess.target.os; assert!(target_os == "linux" || target_os == "macos", "`setenv` is only available for the UNIX target family"); let name_ptr = this.read_scalar(name_op)?.check_init()?; @@ -258,7 +258,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn unsetenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.target_os; + let target_os = &this.tcx.sess.target.os; assert!(target_os == "linux" || target_os == "macos", "`unsetenv` is only available for the UNIX target family"); let name_ptr = this.read_scalar(name_op)?.check_init()?; @@ -290,7 +290,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.target_os; + let target_os = &this.tcx.sess.target.os; assert!(target_os == "linux" || target_os == "macos", "`getcwd` is only available for the UNIX target family"); this.check_no_isolation("`getcwd`")?; @@ -336,7 +336,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn chdir(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.target_os; + let target_os = &this.tcx.sess.target.os; assert!(target_os == "linux" || target_os == "macos", "`getcwd` is only available for the UNIX target family"); this.check_no_isolation("`chdir`")?; diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index cd6024444fa5..24fa119446e8 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -486,7 +486,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Platform-specific shims - _ => match this.tcx.sess.target.target_os.as_str() { + _ => match this.tcx.sess.target.os.as_str() { "linux" | "macos" => return shims::posix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), target => throw_unsup_format!("the target `{}` is not supported", target), diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 268b0902e9c2..21b5a876463e 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -234,7 +234,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx direction: PathConversion, ) -> Cow<'a, OsStr> { let this = self.eval_context_ref(); - let target_os = &this.tcx.sess.target.target_os; + let target_os = &this.tcx.sess.target.os; #[cfg(windows)] return if target_os == "windows" { // Windows-on-Windows, all fine. diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index c527fa0d064a..aac164b709b2 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -165,7 +165,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.read_scalar(handle)?.to_machine_usize(this)?; let symbol = this.read_scalar(symbol)?.check_init()?; let symbol_name = this.memory.read_c_str(symbol)?; - if let Some(dlsym) = Dlsym::from_str(symbol_name, &this.tcx.sess.target.target_os)? { + if let Some(dlsym) = Dlsym::from_str(symbol_name, &this.tcx.sess.target.os)? { let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); this.write_scalar(Scalar::from(ptr), dest)?; } else { @@ -452,7 +452,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Platform-specific shims _ => { - match this.tcx.sess.target.target_os.as_str() { + match this.tcx.sess.target.os.as_str() { "linux" => return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), "macos" => return shims::posix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), _ => unreachable!(), diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index a9d102912ab2..50589ca322db 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -555,7 +555,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }, None => return this.handle_not_found(), } - } else if this.tcx.sess.target.target_os == "macos" + } else if this.tcx.sess.target.os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC")? { let &[_, _] = check_arg_count(args)?; @@ -989,7 +989,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("`mkdir`")?; #[cfg_attr(not(unix), allow(unused_variables))] - let mode = if this.tcx.sess.target.target_os == "macos" { + let mode = if this.tcx.sess.target.os == "macos" { u32::from(this.read_scalar(mode_op)?.check_init()?.to_u16()?) } else { this.read_scalar(mode_op)?.to_u32()? diff --git a/src/shims/posix/linux/dlsym.rs b/src/shims/posix/linux/dlsym.rs index af5f5a20e445..ca5cf3ffe8f3 100644 --- a/src/shims/posix/linux/dlsym.rs +++ b/src/shims/posix/linux/dlsym.rs @@ -27,7 +27,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (_dest, _ret) = ret.expect("we don't support any diverging dlsym"); - assert!(this.tcx.sess.target.target_os == "linux"); + assert!(this.tcx.sess.target.os == "linux"); match dlsym {} } diff --git a/src/shims/posix/macos/dlsym.rs b/src/shims/posix/macos/dlsym.rs index 82d8b16ad66a..5b59cf27ee3b 100644 --- a/src/shims/posix/macos/dlsym.rs +++ b/src/shims/posix/macos/dlsym.rs @@ -32,7 +32,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (dest, ret) = ret.expect("we don't support any diverging dlsym"); - assert!(this.tcx.sess.target.target_os == "macos"); + assert!(this.tcx.sess.target.os == "macos"); match dlsym { Dlsym::getentropy => { diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 7b4d8fa56ae4..2ca860367eff 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -340,7 +340,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This is the first time we got asked to schedule a destructor. The // Windows schedule destructor function must be called exactly once, // this is why it is in this block. - if this.tcx.sess.target.target_os == "windows" { + if this.tcx.sess.target.os == "windows" { // On Windows, we signal that the thread quit by starting the // relevant function, reenabling the thread, and going back to // the scheduler. diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 5454a00f14d5..415299c51fc6 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -44,7 +44,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (dest, ret) = ret.expect("we don't support any diverging dlsym"); - assert!(this.tcx.sess.target.target_os == "windows"); + assert!(this.tcx.sess.target.os == "windows"); match dlsym { Dlsym::AcquireSRWLockExclusive => { diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index d141fa57e13a..12b714880b35 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -213,7 +213,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[hModule, lpProcName] = check_arg_count(args)?; this.read_scalar(hModule)?.to_machine_isize(this)?; let name = this.memory.read_c_str(this.read_scalar(lpProcName)?.check_init()?)?; - if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.target_os)? { + if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.os)? { let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); this.write_scalar(Scalar::from(ptr), dest)?; } else { From 915d091973214c4379409fed7ed36b26c9d7750a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Nov 2020 16:50:24 +0100 Subject: [PATCH 2444/5092] rustup; less strict timing tests --- rust-version | 2 +- tests/run-pass/concurrency/linux-futex.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index e19cca38c040..3b96c994a782 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -38030ffb4e735b26260848b744c0910a5641e1db +12f0dba618e761c987142474435dff95ab177f3c diff --git a/tests/run-pass/concurrency/linux-futex.rs b/tests/run-pass/concurrency/linux-futex.rs index 391e9524324a..0f2a0236326b 100644 --- a/tests/run-pass/concurrency/linux-futex.rs +++ b/tests/run-pass/concurrency/linux-futex.rs @@ -90,7 +90,7 @@ fn wait_timeout() { assert_eq!(*libc::__errno_location(), libc::ETIMEDOUT); } - assert!((200..500).contains(&start.elapsed().as_millis())); + assert!((200..1000).contains(&start.elapsed().as_millis())); } fn wait_wake() { @@ -120,7 +120,7 @@ fn wait_wake() { ), 0); } - assert!((200..500).contains(&start.elapsed().as_millis())); + assert!((200..1000).contains(&start.elapsed().as_millis())); } fn main() { From 69fb6413ddc5b7fd5d9cb0a68ebf58ee513bf9d5 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Sun, 15 Nov 2020 18:30:26 +0000 Subject: [PATCH 2445/5092] Tidy up comments and function layout, should fix most of the review notes. --- src/bin/miri.rs | 3 + src/data_race.rs | 1128 +++++++++-------- src/eval.rs | 3 + src/lib.rs | 4 +- src/machine.rs | 31 +- src/shims/intrinsics.rs | 166 +-- src/shims/posix/linux/sync.rs | 12 +- src/shims/posix/sync.rs | 16 +- src/shims/posix/thread.rs | 15 +- src/sync.rs | 58 +- src/thread.rs | 49 +- src/vector_clock.rs | 321 +++-- tests/run-pass/concurrency/data_race.stderr | 2 +- tests/run-pass/concurrency/linux-futex.stderr | 2 +- tests/run-pass/concurrency/simple.stderr | 2 +- tests/run-pass/concurrency/sync.stderr | 2 +- .../run-pass/concurrency/thread_locals.stderr | 2 +- .../run-pass/concurrency/tls_lib_drop.stderr | 2 +- tests/run-pass/libc.stderr | 2 +- tests/run-pass/panic/concurrent-panic.stderr | 2 +- 20 files changed, 1016 insertions(+), 806 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index ef1429a35020..1117b69116a5 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -195,6 +195,9 @@ fn main() { "-Zmiri-disable-stacked-borrows" => { miri_config.stacked_borrows = false; } + "-Zmiri-disable-data-race-detector" => { + miri_config.data_race_detector = false; + } "-Zmiri-disable-alignment-check" => { miri_config.check_alignment = miri::AlignmentCheck::None; } diff --git a/src/data_race.rs b/src/data_race.rs index 57f09146d6f8..822ceab8fa04 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -1,16 +1,36 @@ -//! Implementation of a data-race detector -//! uses Lamport Timestamps / Vector-clocks -//! base on the Dyamic Race Detection for C++: -//! - https://www.doc.ic.ac.uk/~afd/homepages/papers/pdfs/2017/POPL.pdf -//! to extend data-race detection to work correctly with fences -//! and RMW operations +//! Implementation of a data-race detector using Lamport Timestamps / Vector-clocks +//! based on the Dyamic Race Detection for C++: +//! https://www.doc.ic.ac.uk/~afd/homepages/papers/pdfs/2017/POPL.pdf +//! which does not report false-positives when fences are used, and gives better +//! accuracy in presence of read-modify-write operations. +//! //! This does not explore weak memory orders and so can still miss data-races -//! but should not report false-positives +//! but should not report false-positives +//! //! Data-race definiton from(https://en.cppreference.com/w/cpp/language/memory_model#Threads_and_data_races): -//! - if a memory location is accessed by twice is a data-race unless: -//! - both operations execute on the same thread/signal-handler -//! - both conflicting operations are atomic operations (1 atomic and 1 non-atomic race) -//! - 1 of the operations happens-before the other operation (see link for definition) +//! a data race occurs between two memory accesses if they are on different threads, at least one operation +//! is non-atomic, at least one operation is a write and neither access happens-before the other. Read the link +//! for full definition. +//! +//! This re-uses vector indexes for threads that are known to be unable to report data-races, this is valid +//! because it only re-uses vector indexes once all currently-active (not-terminated) threads have an internal +//! vector clock that happens-after the join operation of the candidate thread. Threads that have not been joined +//! on are not considered. Since the thread's vector clock will only increase and a data-race implies that +//! there is some index x where clock[x] > thread_clock, when this is true clock[candidate-idx] > thread_clock +//! can never hold and hence a data-race can never be reported in that vector index again. +//! This means that the thread-index can be safely re-used, starting on the next timestamp for the newly created +//! thread. +//! +//! The sequentially consistant ordering corresponds to the ordering that the threads +//! are currently scheduled, this means that the data-race detector has no additional +//! logic for sequentially consistent accesses at the moment since they are indistinguishable +//! from acquire/release operations. If weak memory orderings are explored then this +//! may need to change or be updated accordingly. +//! +//! FIXME: +//! currently we have our own local copy of the currently active thread index and names, this is due +//! in part to the inability to access the current location of threads.active_thread inside the AllocExtra +//! read, write and deallocate functions and should be cleaned up in the future. use std::{ fmt::Debug, rc::Rc, @@ -19,23 +39,23 @@ use std::{ use rustc_index::vec::{Idx, IndexVec}; use rustc_target::abi::Size; -use rustc_middle::ty::layout::TyAndLayout; +use rustc_middle::{mir, ty::layout::TyAndLayout}; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use crate::{ MiriEvalContext, MiriEvalContextExt, ThreadId, Tag, RangeMap, InterpResult, Pointer, ScalarMaybeUninit, - MPlaceTy, OpTy, MemPlaceMeta, - VClock, VSmallClockSet, VectorIdx, VTimestamp + MPlaceTy, OpTy, MemPlaceMeta, ImmTy, Immediate, + VClock, VSmallClockMap, VectorIdx, VTimestamp }; pub type AllocExtra = VClockAlloc; pub type MemoryExtra = Rc; -/// Valid atomic read-write operations, alias of atomic::Ordering (not non-exhaustive) +/// Valid atomic read-write operations, alias of atomic::Ordering (not non-exhaustive). #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum AtomicRWOp { +pub enum AtomicRwOp { Relaxed, Acquire, Release, @@ -43,7 +63,7 @@ pub enum AtomicRWOp { SeqCst, } -/// Valid atomic read operations, subset of atomic::Ordering +/// Valid atomic read operations, subset of atomic::Ordering. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum AtomicReadOp { Relaxed, @@ -51,7 +71,7 @@ pub enum AtomicReadOp { SeqCst, } -/// Valid atomic write operations, subset of atomic::Ordering +/// Valid atomic write operations, subset of atomic::Ordering. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum AtomicWriteOp { Relaxed, @@ -60,7 +80,7 @@ pub enum AtomicWriteOp { } -/// Valid atomic fence operations, subset of atomic::Ordering +/// Valid atomic fence operations, subset of atomic::Ordering. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum AtomicFenceOp { Acquire, @@ -69,315 +89,124 @@ pub enum AtomicFenceOp { SeqCst, } -/// Evaluation context extensions -impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} -pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { - - // Temporarily allow data-races to occur, this should only be - // used if either one of the appropiate `validate_atomic` functions - // will be called to treat a memory access as atomic or if the memory - // being accessed should be treated as internal state, that cannot be - // accessed by the interpreted program. - #[inline] - fn allow_data_races_ref(&self, op: impl FnOnce(&MiriEvalContext<'mir, 'tcx>) -> R) -> R { - let this = self.eval_context_ref(); - let data_race = &*this.memory.extra.data_race; - let old = data_race.multi_threaded.replace(false); - let result = op(this); - data_race.multi_threaded.set(old); - result - } - - /// Same as `allow_data_races_ref`, this temporarily disables any data-race detection and - /// so should only be used for atomic operations or internal state that the program cannot - /// access - #[inline] - fn allow_data_races_mut(&mut self, op: impl FnOnce(&mut MiriEvalContext<'mir, 'tcx>) -> R) -> R { - let this = self.eval_context_mut(); - let data_race = &*this.memory.extra.data_race; - let old = data_race.multi_threaded.replace(false); - let result = op(this); - let data_race = &*this.memory.extra.data_race; - data_race.multi_threaded.set(old); - result - } - fn read_scalar_at_offset_atomic( - &self, - op: OpTy<'tcx, Tag>, - offset: u64, - layout: TyAndLayout<'tcx>, - atomic: AtomicReadOp - ) -> InterpResult<'tcx, ScalarMaybeUninit> { - let this = self.eval_context_ref(); - let op_place = this.deref_operand(op)?; - let offset = Size::from_bytes(offset); - // Ensure that the following read at an offset is within bounds - assert!(op_place.layout.size >= offset + layout.size); - let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; - this.read_scalar_atomic(value_place, atomic) - } - fn write_scalar_at_offset_atomic( - &mut self, - op: OpTy<'tcx, Tag>, - offset: u64, - value: impl Into>, - layout: TyAndLayout<'tcx>, - atomic: AtomicWriteOp - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - let op_place = this.deref_operand(op)?; - let offset = Size::from_bytes(offset); - // Ensure that the following read at an offset is within bounds - assert!(op_place.layout.size >= offset + layout.size); - let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; - this.write_scalar_atomic(value.into(), value_place, atomic) - } - fn read_scalar_atomic( - &self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicReadOp - ) -> InterpResult<'tcx, ScalarMaybeUninit> { - let scalar = self.allow_data_races_ref(move |this| { - this.read_scalar(place.into()) - })?; - self.validate_atomic_load(place, atomic)?; - Ok(scalar) - } - fn write_scalar_atomic( - &mut self, val: ScalarMaybeUninit, dest: MPlaceTy<'tcx, Tag>, - atomic: AtomicWriteOp - ) -> InterpResult<'tcx> { - self.allow_data_races_mut(move |this| { - this.write_scalar(val, dest.into()) - })?; - self.validate_atomic_store(dest, atomic) - } - - /// Update the data-race detector for an atomic read occuring at the - /// associated memory-place and on the current thread - fn validate_atomic_load( - &self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicReadOp - ) -> InterpResult<'tcx> { - let this = self.eval_context_ref(); - this.validate_atomic_op( - place, atomic, "Atomic Load", - move |memory, clocks, index, atomic| { - if atomic == AtomicReadOp::Relaxed { - memory.load_relaxed(&mut *clocks, index) - }else{ - memory.acquire(&mut *clocks, index) - } - } - ) - } +/// The current set of vector clocks describing the state +/// of a thread, contains the happens-before clock and +/// additional metadata to model atomic fence operations. +#[derive(Clone, Default, Debug)] +struct ThreadClockSet { - /// Update the data-race detector for an atomic write occuring at the - /// associated memory-place and on the current thread - fn validate_atomic_store( - &mut self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicWriteOp - ) -> InterpResult<'tcx> { - let this = self.eval_context_ref(); - this.validate_atomic_op( - place, atomic, "Atomic Store", - move |memory, clocks, index, atomic| { - if atomic == AtomicWriteOp::Relaxed { - memory.store_relaxed(clocks, index) - }else{ - memory.release(clocks, index) - } - } - ) - } - - /// Update the data-race detector for an atomic read-modify-write occuring - /// at the associated memory place and on the current thread - fn validate_atomic_rmw( - &mut self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicRWOp - ) -> InterpResult<'tcx> { - use AtomicRWOp::*; - let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); - let release = matches!(atomic, Release | AcqRel | SeqCst); - let this = self.eval_context_ref(); - this.validate_atomic_op( - place, atomic, "Atomic RMW", - move |memory, clocks, index, _| { - if acquire { - memory.acquire(clocks, index)?; - }else{ - memory.load_relaxed(clocks, index)?; - } - if release { - memory.rmw_release(clocks, index) - }else{ - memory.rmw_relaxed(clocks, index) - } - } - ) - } - - /// Update the data-race detector for an atomic fence on the current thread - fn validate_atomic_fence(&mut self, atomic: AtomicFenceOp) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - let data_race = &*this.memory.extra.data_race; - data_race.maybe_perform_sync_operation(move |index, mut clocks| { - log::trace!("Atomic fence on {:?} with ordering {:?}", index, atomic); - // Apply data-race detection for the current fences - // this treats AcqRel and SeqCst as the same as a acquire - // and release fence applied in the same timestamp. - if atomic != AtomicFenceOp::Release { - // Either Acquire | AcqRel | SeqCst - clocks.apply_acquire_fence(); - } - if atomic != AtomicFenceOp::Acquire { - // Either Release | AcqRel | SeqCst - clocks.apply_release_fence(); - } - Ok(()) - }) - } -} - -impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} -trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { - - /// Generic atomic operation implementation, - /// this accesses memory via get_raw instead of - /// get_raw_mut, due to issues calling get_raw_mut - /// for atomic loads from read-only memory - /// FIXME: is this valid, or should get_raw_mut be used for - /// atomic-stores/atomic-rmw? - fn validate_atomic_op( - &self, place: MPlaceTy<'tcx, Tag>, - atomic: A, description: &str, - mut op: impl FnMut( - &mut MemoryCellClocks, &mut ThreadClockSet, VectorIdx, A - ) -> Result<(), DataRace> - ) -> InterpResult<'tcx> { - let this = self.eval_context_ref(); - let data_race = &*this.memory.extra.data_race; - if data_race.multi_threaded.get() { - - // Load an log the atomic operation - let place_ptr = place.ptr.assert_ptr(); - let size = place.layout.size; - let alloc_meta = &this.memory.get_raw(place_ptr.alloc_id)?.extra.data_race; - log::trace!( - "Atomic op({}) with ordering {:?} on memory({:?}, offset={}, size={})", - description, &atomic, place_ptr.alloc_id, place_ptr.offset.bytes(), size.bytes() - ); - - // Perform the atomic operation - let data_race = &alloc_meta.global; - data_race.maybe_perform_sync_operation(|index, mut clocks| { - for (_,range) in alloc_meta.alloc_ranges.borrow_mut().iter_mut(place_ptr.offset, size) { - if let Err(DataRace) = op(range, &mut *clocks, index, atomic) { - mem::drop(clocks); - return VClockAlloc::report_data_race( - &alloc_meta.global, range, description, true, - place_ptr, size - ); - } - } - Ok(()) - })?; - - // Log changes to atomic memory - if log::log_enabled!(log::Level::Trace) { - for (_,range) in alloc_meta.alloc_ranges.borrow().iter(place_ptr.offset, size) { - log::trace!( - "Updated atomic memory({:?}, offset={}, size={}) to {:#?}", - place.ptr.assert_ptr().alloc_id, place_ptr.offset.bytes(), size.bytes(), - range.atomic_ops - ); - } - } - } - Ok(()) - } - -} - -/// Handle for locks to express their -/// acquire-release semantics -#[derive(Clone, Debug, Default)] -pub struct DataRaceLockHandle { - - /// Internal acquire-release clock - /// to express the acquire release sync - /// found in concurrency primitives + /// The increasing clock representing timestamps + /// that happen-before this thread. clock: VClock, + + /// The set of timestamps that will happen-before this + /// thread once it performs an acquire fence. + fence_acquire: VClock, + + /// The last timesamp of happens-before relations that + /// have been released by this thread by a fence. + fence_release: VClock, } -impl DataRaceLockHandle { - pub fn set_values(&mut self, other: &Self) { - self.clock.clone_from(&other.clock) + + +impl ThreadClockSet { + + /// Apply the effects of a release fence to this + /// set of thread vector clocks. + #[inline] + fn apply_release_fence(&mut self) { + self.fence_release.clone_from(&self.clock); } - pub fn reset(&mut self) { - self.clock.set_zero_vector(); + + /// Apply the effects of a acquire fence to this + /// set of thread vector clocks. + #[inline] + fn apply_acquire_fence(&mut self) { + self.clock.join(&self.fence_acquire); + } + + /// Increment the happens-before clock at a + /// known index. + #[inline] + fn increment_clock(&mut self, index: VectorIdx) { + self.clock.increment_index(index); + } + + /// Join the happens-before clock with that of + /// another thread, used to model thread join + /// operations. + fn join_with(&mut self, other: &ThreadClockSet) { + self.clock.join(&other.clock); } } /// Error returned by finding a data race -/// should be elaborated upon +/// should be elaborated upon. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] pub struct DataRace; /// Externally stored memory cell clocks -/// explicitly to reduce memory usage for the -/// common case where no atomic operations -/// exists on the memory cell +/// explicitly to reduce memory usage for the +/// common case where no atomic operations +/// exists on the memory cell. #[derive(Clone, PartialEq, Eq, Default, Debug)] struct AtomicMemoryCellClocks { - /// The clock-vector for the set of atomic read operations - /// used for detecting data-races with non-atomic write - /// operations + /// The clock-vector of the timestamp of the last atomic + /// read operation performed by each thread. + /// This detects potential data-races between atomic read + /// and non-atomic write operations. read_vector: VClock, - /// The clock-vector for the set of atomic write operations - /// used for detecting data-races with non-atomic read or - /// write operations + /// The clock-vector of the timestamp of the last atomic + /// write operation performed by each thread. + /// This detects potential data-races between atomic write + /// and non-atomic read or write operations. write_vector: VClock, /// Synchronization vector for acquire-release semantics - /// contains the vector of timestamps that will - /// happen-before a thread if an acquire-load is - /// performed on the data + /// contains the vector of timestamps that will + /// happen-before a thread if an acquire-load is + /// performed on the data. sync_vector: VClock, /// The Hash-Map of all threads for which a release - /// sequence exists in the memory cell, required - /// since read-modify-write operations do not - /// invalidate existing release sequences - release_sequences: VSmallClockSet, + /// sequence exists in the memory cell, required + /// since read-modify-write operations do not + /// invalidate existing release sequences. + /// See page 6 of linked paper. + release_sequences: VSmallClockMap, } /// Memory Cell vector clock metadata -/// for data-race detection +/// for data-race detection. #[derive(Clone, PartialEq, Eq, Debug)] struct MemoryCellClocks { - /// The vector-clock of the last write, only one value is stored - /// since all previous writes happened-before the current write + /// The vector-clock timestamp of the last write + /// corresponding to the writing threads timestamp. write: VTimestamp, - /// The identifier of the thread that performed the last write - /// operation + /// The identifier of the vector index, corresponding to a thread + /// that performed the last write operation. write_index: VectorIdx, - /// The vector-clock of the set of previous reads - /// each index is set to the timestamp that the associated - /// thread last read this value. + /// The vector-clock of the timestamp of the last read operation + /// performed by a thread since the last write operation occured. read: VClock, - /// Atomic acquire & release sequence tracking clocks - /// for non-atomic memory in the common case this - /// value is set to None + /// Atomic acquire & release sequence tracking clocks. + /// For non-atomic memory in the common case this + /// value is set to None. atomic_ops: Option>, } + /// Create a default memory cell clocks instance -/// for uninitialized memory +/// for uninitialized memory. impl Default for MemoryCellClocks { fn default() -> Self { MemoryCellClocks { @@ -389,9 +218,10 @@ impl Default for MemoryCellClocks { } } + impl MemoryCellClocks { - /// Load the internal atomic memory cells if they exist + /// Load the internal atomic memory cells if they exist. #[inline] fn atomic(&self) -> Option<&AtomicMemoryCellClocks> { match &self.atomic_ops { @@ -401,25 +231,26 @@ impl MemoryCellClocks { } /// Load or create the internal atomic memory metadata - /// if it does not exist + /// if it does not exist. #[inline] fn atomic_mut(&mut self) -> &mut AtomicMemoryCellClocks { self.atomic_ops.get_or_insert_with(Default::default) } /// Update memory cell data-race tracking for atomic - /// load acquire semantics, is a no-op if this memory was - /// not used previously as atomic memory - fn acquire(&mut self, clocks: &mut ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { + /// load acquire semantics, is a no-op if this memory was + /// not used previously as atomic memory. + fn load_acquire(&mut self, clocks: &mut ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { self.atomic_read_detect(clocks, index)?; if let Some(atomic) = self.atomic() { clocks.clock.join(&atomic.sync_vector); } Ok(()) } + /// Update memory cell data-race tracking for atomic - /// load relaxed semantics, is a no-op if this memory was - /// not used previously as atomic memory + /// load relaxed semantics, is a no-op if this memory was + /// not used previously as atomic memory. fn load_relaxed(&mut self, clocks: &mut ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { self.atomic_read_detect(clocks, index)?; if let Some(atomic) = self.atomic() { @@ -430,8 +261,8 @@ impl MemoryCellClocks { /// Update the memory cell data-race tracking for atomic - /// store release semantics - fn release(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { + /// store release semantics. + fn store_release(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { self.atomic_write_detect(clocks, index)?; let atomic = self.atomic_mut(); atomic.sync_vector.clone_from(&clocks.clock); @@ -439,8 +270,9 @@ impl MemoryCellClocks { atomic.release_sequences.insert(index, &clocks.clock); Ok(()) } + /// Update the memory cell data-race tracking for atomic - /// store relaxed semantics + /// store relaxed semantics. fn store_relaxed(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { self.atomic_write_detect(clocks, index)?; let atomic = self.atomic_mut(); @@ -451,8 +283,9 @@ impl MemoryCellClocks { atomic.release_sequences.retain_index(index); Ok(()) } + /// Update the memory cell data-race tracking for atomic - /// store release semantics for RMW operations + /// store release semantics for RMW operations. fn rmw_release(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { self.atomic_write_detect(clocks, index)?; let atomic = self.atomic_mut(); @@ -460,8 +293,9 @@ impl MemoryCellClocks { atomic.release_sequences.insert(index, &clocks.clock); Ok(()) } + /// Update the memory cell data-race tracking for atomic - /// store relaxed semantics for RMW operations + /// store relaxed semantics for RMW operations. fn rmw_relaxed(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { self.atomic_write_detect(clocks, index)?; let atomic = self.atomic_mut(); @@ -470,60 +304,60 @@ impl MemoryCellClocks { } /// Detect data-races with an atomic read, caused by a non-atomic write that does - /// not happen-before the atomic-read + /// not happen-before the atomic-read. fn atomic_read_detect(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { log::trace!("Atomic read with vectors: {:#?} :: {:#?}", self, clocks); if self.write <= clocks.clock[self.write_index] { let atomic = self.atomic_mut(); atomic.read_vector.set_at_index(&clocks.clock, index); Ok(()) - }else{ + } else { Err(DataRace) } } /// Detect data-races with an atomic write, either with a non-atomic read or with - /// a non-atomic write: + /// a non-atomic write. fn atomic_write_detect(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { log::trace!("Atomic write with vectors: {:#?} :: {:#?}", self, clocks); if self.write <= clocks.clock[self.write_index] && self.read <= clocks.clock { let atomic = self.atomic_mut(); atomic.write_vector.set_at_index(&clocks.clock, index); Ok(()) - }else{ + } else { Err(DataRace) } } /// Detect races for non-atomic read operations at the current memory cell - /// returns true if a data-race is detected + /// returns true if a data-race is detected. fn read_race_detect(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { log::trace!("Unsynchronized read with vectors: {:#?} :: {:#?}", self, clocks); if self.write <= clocks.clock[self.write_index] { let race_free = if let Some(atomic) = self.atomic() { atomic.write_vector <= clocks.clock - }else{ + } else { true }; if race_free { self.read.set_at_index(&clocks.clock, index); Ok(()) - }else{ + } else { Err(DataRace) } - }else{ + } else { Err(DataRace) } } /// Detect races for non-atomic write operations at the current memory cell - /// returns true if a data-race is detected + /// returns true if a data-race is detected. fn write_race_detect(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { log::trace!("Unsynchronized write with vectors: {:#?} :: {:#?}", self, clocks); if self.write <= clocks.clock[self.write_index] && self.read <= clocks.clock { let race_free = if let Some(atomic) = self.atomic() { atomic.write_vector <= clocks.clock && atomic.read_vector <= clocks.clock - }else{ + } else { true }; if race_free { @@ -531,30 +365,269 @@ impl MemoryCellClocks { self.write_index = index; self.read.set_zero_vector(); Ok(()) - }else{ + } else { Err(DataRace) } - }else{ + } else { Err(DataRace) } } } -/// Vector clock metadata for a logical memory allocation + +/// Evaluation context extensions. +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { + + /// Atomic variant of read_scalar_at_offset. + fn read_scalar_at_offset_atomic( + &self, + op: OpTy<'tcx, Tag>, + offset: u64, + layout: TyAndLayout<'tcx>, + atomic: AtomicReadOp + ) -> InterpResult<'tcx, ScalarMaybeUninit> { + let this = self.eval_context_ref(); + let op_place = this.deref_operand(op)?; + let offset = Size::from_bytes(offset); + + // Ensure that the following read at an offset is within bounds. + assert!(op_place.layout.size >= offset + layout.size); + let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; + this.read_scalar_atomic(value_place, atomic) + } + + /// Atomic variant of write_scalar_at_offset. + fn write_scalar_at_offset_atomic( + &mut self, + op: OpTy<'tcx, Tag>, + offset: u64, + value: impl Into>, + layout: TyAndLayout<'tcx>, + atomic: AtomicWriteOp + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let op_place = this.deref_operand(op)?; + let offset = Size::from_bytes(offset); + + // Ensure that the following read at an offset is within bounds. + assert!(op_place.layout.size >= offset + layout.size); + let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; + this.write_scalar_atomic(value.into(), value_place, atomic) + } + + /// Perform an atomic read operation at the memory location. + fn read_scalar_atomic( + &self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicReadOp + ) -> InterpResult<'tcx, ScalarMaybeUninit> { + let this = self.eval_context_ref(); + let scalar = this.allow_data_races_ref(move |this| { + this.read_scalar(place.into()) + })?; + self.validate_atomic_load(place, atomic)?; + Ok(scalar) + } + + /// Perform an atomic write operation at the memory location. + fn write_scalar_atomic( + &mut self, val: ScalarMaybeUninit, dest: MPlaceTy<'tcx, Tag>, + atomic: AtomicWriteOp + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + this.allow_data_races_mut(move |this| { + this.write_scalar(val, dest.into()) + })?; + self.validate_atomic_store(dest, atomic) + } + + /// Perform a atomic operation on a memory location. + fn atomic_op_immediate( + &mut self, + place: MPlaceTy<'tcx, Tag>, rhs: ImmTy<'tcx, Tag>, + op: mir::BinOp, neg: bool, atomic: AtomicRwOp + ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { + let this = self.eval_context_mut(); + + let old = this.allow_data_races_mut(|this| { + this.read_immediate(place. into()) + })?; + + // Atomics wrap around on overflow. + let val = this.binary_op(op, old, rhs)?; + let val = if neg { this.unary_op(mir::UnOp::Not, val)? } else { val }; + this.allow_data_races_mut(|this| { + this.write_immediate(*val, place.into()) + })?; + + this.validate_atomic_rmw(place, atomic)?; + Ok(old) + } + + /// Perform an atomic exchange with a memory place and a new + /// scalar value, the old value is returned. + fn atomic_exchange_scalar( + &mut self, + place: MPlaceTy<'tcx, Tag>, new: ScalarMaybeUninit, + atomic: AtomicRwOp + ) -> InterpResult<'tcx, ScalarMaybeUninit> { + let this = self.eval_context_mut(); + + let old = this.allow_data_races_mut(|this| { + this.read_scalar(place.into()) + })?; + this.allow_data_races_mut(|this| { + this.write_scalar(new, place.into()) + })?; + this.validate_atomic_rmw(place, atomic)?; + Ok(old) + } + + /// Perform an atomic compare and exchange at a given memory location + /// on success an atomic RMW operation is performed and on failure + /// only an atomic read occurs. + fn atomic_compare_exchange_scalar( + &mut self, place: MPlaceTy<'tcx, Tag>, + expect_old: ImmTy<'tcx, Tag>, new: ScalarMaybeUninit, + success: AtomicRwOp, fail: AtomicReadOp + ) -> InterpResult<'tcx, Immediate> { + let this = self.eval_context_mut(); + + // Failure ordering cannot be stronger than success ordering, therefore first attempt + // to read with the failure ordering and if successfull then try again with the success + // read ordering and write in the success case. + // Read as immediate for the sake of `binary_op()` + let old = this.allow_data_races_mut(|this| { + this.read_immediate(place.into()) + })?; + + // `binary_op` will bail if either of them is not a scalar. + let eq = this.overflowing_binary_op(mir::BinOp::Eq, old, expect_old)?.0; + let res = Immediate::ScalarPair(old.to_scalar_or_uninit(), eq.into()); + + // Update ptr depending on comparison. + // if successful, perform a full rw-atomic validation + // otherwise treat this as an atomic load with the fail ordering. + if eq.to_bool()? { + this.allow_data_races_mut(|this| { + this.write_scalar(new, place.into()) + })?; + this.validate_atomic_rmw(place, success)?; + } else { + this.validate_atomic_load(place, fail)?; + } + + // Return the old value. + Ok(res) + } + + + /// Update the data-race detector for an atomic read occuring at the + /// associated memory-place and on the current thread. + fn validate_atomic_load( + &self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicReadOp + ) -> InterpResult<'tcx> { + let this = self.eval_context_ref(); + this.validate_atomic_op( + place, atomic, "Atomic Load", + move |memory, clocks, index, atomic| { + if atomic == AtomicReadOp::Relaxed { + memory.load_relaxed(&mut *clocks, index) + } else { + memory.load_acquire(&mut *clocks, index) + } + } + ) + } + + /// Update the data-race detector for an atomic write occuring at the + /// associated memory-place and on the current thread. + fn validate_atomic_store( + &mut self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicWriteOp + ) -> InterpResult<'tcx> { + let this = self.eval_context_ref(); + this.validate_atomic_op( + place, atomic, "Atomic Store", + move |memory, clocks, index, atomic| { + if atomic == AtomicWriteOp::Relaxed { + memory.store_relaxed(clocks, index) + } else { + memory.store_release(clocks, index) + } + } + ) + } + + /// Update the data-race detector for an atomic read-modify-write occuring + /// at the associated memory place and on the current thread. + fn validate_atomic_rmw( + &mut self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicRwOp + ) -> InterpResult<'tcx> { + use AtomicRwOp::*; + let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); + let release = matches!(atomic, Release | AcqRel | SeqCst); + let this = self.eval_context_ref(); + this.validate_atomic_op( + place, atomic, "Atomic RMW", + move |memory, clocks, index, _| { + if acquire { + memory.load_acquire(clocks, index)?; + } else { + memory.load_relaxed(clocks, index)?; + } + if release { + memory.rmw_release(clocks, index) + } else { + memory.rmw_relaxed(clocks, index) + } + } + ) + } + + /// Update the data-race detector for an atomic fence on the current thread. + fn validate_atomic_fence(&mut self, atomic: AtomicFenceOp) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + if let Some(data_race) = &this.memory.extra.data_race { + data_race.maybe_perform_sync_operation(move |index, mut clocks| { + log::trace!("Atomic fence on {:?} with ordering {:?}", index, atomic); + + // Apply data-race detection for the current fences + // this treats AcqRel and SeqCst as the same as a acquire + // and release fence applied in the same timestamp. + if atomic != AtomicFenceOp::Release { + // Either Acquire | AcqRel | SeqCst + clocks.apply_acquire_fence(); + } + if atomic != AtomicFenceOp::Acquire { + // Either Release | AcqRel | SeqCst + clocks.apply_release_fence(); + } + Ok(()) + }) + } else { + Ok(()) + } + } +} + + + +/// Vector clock metadata for a logical memory allocation. #[derive(Debug, Clone)] pub struct VClockAlloc { - /// Range of Vector clocks, mapping to the vector-clock - /// index of the last write to the bytes in this allocation + /// Range of Vector clocks, this gives each byte a potentially + /// unqiue set of vector clocks, but merges identical information + /// together for improved efficiency. alloc_ranges: RefCell>, - // Pointer to global state + // Pointer to global state. global: MemoryExtra, } + impl VClockAlloc { - /// Create a new data-race allocation detector + /// Create a new data-race allocation detector. pub fn new_allocation(global: &MemoryExtra, len: Size) -> VClockAlloc { VClockAlloc { global: Rc::clone(global), @@ -565,7 +638,7 @@ impl VClockAlloc { } // Find an index, if one exists where the value - // in `l` is greater than the value in `r` + // in `l` is greater than the value in `r`. fn find_gt_index(l: &VClock, r: &VClock) -> Option { let l_slice = l.as_slice(); let r_slice = r.as_slice(); @@ -575,27 +648,28 @@ impl VClockAlloc { if l > r { Some(idx) } else { None } }).or_else(|| { if l_slice.len() > r_slice.len() { + // By invariant, if l_slice is longer - // then one element must be larger + // then one element must be larger. // This just validates that this is true - // and reports earlier elements first + // and reports earlier elements first. let l_remainder_slice = &l_slice[r_slice.len()..]; let idx = l_remainder_slice.iter().enumerate() .find_map(|(idx, &r)| { if r == 0 { None } else { Some(idx) } }).expect("Invalid VClock Invariant"); Some(idx) - }else{ + } else { None } }).map(|idx| VectorIdx::new(idx)) } - /// Report a data-race found in the program - /// this finds the two racing threads and the type - /// of data-race that occured, this will also - /// return info about the memory location the data-race - /// occured in + /// Report a data-race found in the program. + /// This finds the two racing threads and the type + /// of data-race that occured. This will also + /// return info about the memory location the data-race + /// occured in. #[cold] #[inline(never)] fn report_data_race<'tcx>( @@ -608,39 +682,40 @@ impl VClockAlloc { let ( other_action, other_thread, other_clock ) = if range.write > current_clocks.clock[range.write_index] { + // Convert the write action into the vector clock it - // represents for diagnostic purposes + // represents for diagnostic purposes. write_clock = VClock::new_with_index(range.write_index, range.write); ("WRITE", range.write_index, &write_clock) - }else if let Some(idx) = Self::find_gt_index( + } else if let Some(idx) = Self::find_gt_index( &range.read, ¤t_clocks.clock ){ ("READ", idx, &range.read) - }else if !is_atomic { + } else if !is_atomic { if let Some(atomic) = range.atomic() { if let Some(idx) = Self::find_gt_index( &atomic.write_vector, ¤t_clocks.clock ) { ("ATOMIC_STORE", idx, &atomic.write_vector) - }else if let Some(idx) = Self::find_gt_index( + } else if let Some(idx) = Self::find_gt_index( &atomic.read_vector, ¤t_clocks.clock ) { ("ATOMIC_LOAD", idx, &atomic.read_vector) - }else{ - unreachable!("Failed to find report data-race for non-atomic operation: no race found") + } else { + unreachable!("Failed to report data-race for non-atomic operation: no race found") } - }else{ + } else { unreachable!("Failed to report data-race for non-atomic operation: no atomic component") } - }else{ + } else { unreachable!("Failed to report data-race for atomic operation") }; - // Load elaborated thread information about the racing thread actions + // Load elaborated thread information about the racing thread actions. let current_thread_info = global.print_thread_metadata(current_index); let other_thread_info = global.print_thread_metadata(other_thread); - // Throw the data-race detection + // Throw the data-race detection. throw_ub_format!( "Data race detected between {} on {} and {} on {}, memory({:?},offset={},size={})\ \n\t\t -current vector clock = {:?}\ @@ -654,23 +729,25 @@ impl VClockAlloc { } /// Detect data-races for an unsychronized read operation, will not perform - /// data-race threads if `multi-threaded` is false, either due to no threads - /// being created or if it is temporarily disabled during a racy read or write - /// operation + /// data-race detection if `multi-threaded` is false, either due to no threads + /// being created or if it is temporarily disabled during a racy read or write + /// operation for which data-race detection is handled separately, for example + /// atomic read operations. pub fn read<'tcx>(&self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { if self.global.multi_threaded.get() { let (index, clocks) = self.global.current_thread_state(); let mut alloc_ranges = self.alloc_ranges.borrow_mut(); for (_,range) in alloc_ranges.iter_mut(pointer.offset, len) { if let Err(DataRace) = range.read_race_detect(&*clocks, index) { - // Report data-race + + // Report data-race. return Self::report_data_race( &self.global,range, "READ", false, pointer, len ); } } Ok(()) - }else{ + } else { Ok(()) } } @@ -682,6 +759,7 @@ impl VClockAlloc { let (index, clocks) = self.global.current_thread_state(); for (_,range) in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { if let Err(DataRace) = range.write_race_detect(&*clocks, index) { + // Report data-race return Self::report_data_race( &self.global, range, action, false, pointer, len @@ -689,156 +767,208 @@ impl VClockAlloc { } } Ok(()) - }else{ + } else { Ok(()) } } /// Detect data-races for an unsychronized write operation, will not perform - /// data-race threads if `multi-threaded` is false, either due to no threads - /// being created or if it is temporarily disabled during a racy read or write - /// operation + /// data-race threads if `multi-threaded` is false, either due to no threads + /// being created or if it is temporarily disabled during a racy read or write + /// operation pub fn write<'tcx>(&mut self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { self.unique_access(pointer, len, "Write") } + /// Detect data-races for an unsychronized deallocate operation, will not perform - /// data-race threads if `multi-threaded` is false, either due to no threads - /// being created or if it is temporarily disabled during a racy read or write - /// operation + /// data-race threads if `multi-threaded` is false, either due to no threads + /// being created or if it is temporarily disabled during a racy read or write + /// operation pub fn deallocate<'tcx>(&mut self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { self.unique_access(pointer, len, "Deallocate") } } -/// The current set of vector clocks describing the state -/// of a thread, contains the happens-before clock and -/// additional metadata to model atomic fence operations -#[derive(Clone, Default, Debug)] -struct ThreadClockSet { +impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} +trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { - /// The increasing clock representing timestamps - /// that happen-before this thread. - clock: VClock, + // Temporarily allow data-races to occur, this should only be + // used if either one of the appropiate `validate_atomic` functions + // will be called to treat a memory access as atomic or if the memory + // being accessed should be treated as internal state, that cannot be + // accessed by the interpreted program. + #[inline] + fn allow_data_races_ref(&self, op: impl FnOnce(&MiriEvalContext<'mir, 'tcx>) -> R) -> R { + let this = self.eval_context_ref(); + let old = if let Some(data_race) = &this.memory.extra.data_race { + data_race.multi_threaded.replace(false) + } else { + false + }; + let result = op(this); + if let Some(data_race) = &this.memory.extra.data_race { + data_race.multi_threaded.set(old); + } + result + } - /// The set of timestamps that will happen-before this - /// thread once it performs an acquire fence - fence_acquire: VClock, + /// Same as `allow_data_races_ref`, this temporarily disables any data-race detection and + /// so should only be used for atomic operations or internal state that the program cannot + /// access. + #[inline] + fn allow_data_races_mut(&mut self, op: impl FnOnce(&mut MiriEvalContext<'mir, 'tcx>) -> R) -> R { + let this = self.eval_context_mut(); + let old = if let Some(data_race) = &this.memory.extra.data_race { + data_race.multi_threaded.replace(false) + } else { + false + }; + let result = op(this); + if let Some(data_race) = &this.memory.extra.data_race { + data_race.multi_threaded.set(old); + } + result + } + + /// Generic atomic operation implementation, + /// this accesses memory via get_raw instead of + /// get_raw_mut, due to issues calling get_raw_mut + /// for atomic loads from read-only memory. + /// FIXME: is this valid, or should get_raw_mut be used for + /// atomic-stores/atomic-rmw? + fn validate_atomic_op( + &self, place: MPlaceTy<'tcx, Tag>, + atomic: A, description: &str, + mut op: impl FnMut( + &mut MemoryCellClocks, &mut ThreadClockSet, VectorIdx, A + ) -> Result<(), DataRace> + ) -> InterpResult<'tcx> { + let this = self.eval_context_ref(); + if let Some(data_race) = &this.memory.extra.data_race { + if data_race.multi_threaded.get() { + + // Load and log the atomic operation. + let place_ptr = place.ptr.assert_ptr(); + let size = place.layout.size; + let alloc_meta = &this.memory.get_raw(place_ptr.alloc_id)?.extra.data_race.as_ref().unwrap(); + log::trace!( + "Atomic op({}) with ordering {:?} on memory({:?}, offset={}, size={})", + description, &atomic, place_ptr.alloc_id, place_ptr.offset.bytes(), size.bytes() + ); + + // Perform the atomic operation. + let data_race = &alloc_meta.global; + data_race.maybe_perform_sync_operation(|index, mut clocks| { + for (_,range) in alloc_meta.alloc_ranges.borrow_mut().iter_mut(place_ptr.offset, size) { + if let Err(DataRace) = op(range, &mut *clocks, index, atomic) { + mem::drop(clocks); + return VClockAlloc::report_data_race( + &alloc_meta.global, range, description, true, + place_ptr, size + ); + } + } + Ok(()) + })?; + + // Log changes to atomic memory. + if log::log_enabled!(log::Level::Trace) { + for (_,range) in alloc_meta.alloc_ranges.borrow().iter(place_ptr.offset, size) { + log::trace!( + "Updated atomic memory({:?}, offset={}, size={}) to {:#?}", + place.ptr.assert_ptr().alloc_id, place_ptr.offset.bytes(), size.bytes(), + range.atomic_ops + ); + } + } + } + } + Ok(()) + } - /// The last timesamp of happens-before relations that - /// have been released by this thread by a fence - fence_release: VClock, } -impl ThreadClockSet { - /// Apply the effects of a release fence to this - /// set of thread vector clocks - #[inline] - fn apply_release_fence(&mut self) { - self.fence_release.clone_from(&self.clock); - } - - /// Apply the effects of a acquire fence to this - /// set of thread vector clocks - #[inline] - fn apply_acquire_fence(&mut self) { - self.clock.join(&self.fence_acquire); - } - - /// Increment the happens-before clock at a - /// known index - #[inline] - fn increment_clock(&mut self, index: VectorIdx) { - self.clock.increment_index(index); - } - - /// Join the happens-before clock with that of - /// another thread, used to model thread join - /// operations - fn join_with(&mut self, other: &ThreadClockSet) { - self.clock.join(&other.clock); - } -} - -/// Extra metadata associated with a thread +/// Extra metadata associated with a thread. #[derive(Debug, Clone, Default)] struct ThreadExtraState { /// The current vector index in use by the - /// thread currently, this is set to None - /// after the vector index has been re-used - /// and hence the value will never need to be - /// read during data-race reporting + /// thread currently, this is set to None + /// after the vector index has been re-used + /// and hence the value will never need to be + /// read during data-race reporting. vector_index: Option, /// The name of the thread, updated for better - /// diagnostics when reporting detected data - /// races + /// diagnostics when reporting detected data + /// races. thread_name: Option>, /// Thread termination vector clock, this - /// is set on thread termination and is used - /// for joining on threads since the vector_index - /// may be re-used when the join operation occurs + /// is set on thread termination and is used + /// for joining on threads since the vector_index + /// may be re-used when the join operation occurs. termination_vector_clock: Option, } /// Global data-race detection state, contains the currently -/// executing thread as well as the vector-clocks associated -/// with each of the threads. +/// executing thread as well as the vector-clocks associated +/// with each of the threads. #[derive(Debug, Clone)] pub struct GlobalState { /// Set to true once the first additional - /// thread has launched, due to the dependency - /// between before and after a thread launch + /// thread has launched, due to the dependency + /// between before and after a thread launch. /// Any data-races must be recorded after this - /// so concurrent execution can ignore recording - /// any data-races + /// so concurrent execution can ignore recording + /// any data-races. multi_threaded: Cell, /// Mapping of a vector index to a known set of thread - /// clocks, this is not directly mapping from a thread id - /// since it may refer to multiple threads + /// clocks, this is not directly mapping from a thread id + /// since it may refer to multiple threads. vector_clocks: RefCell>, /// Mapping of a given vector index to the current thread - /// that the execution is representing, this may change - /// if a vector index is re-assigned to a new thread + /// that the execution is representing, this may change + /// if a vector index is re-assigned to a new thread. vector_info: RefCell>, - /// The mapping of a given thread to assocaited thread metadata + /// The mapping of a given thread to assocaited thread metadata. thread_info: RefCell>, - /// The current vector index being executed + /// The current vector index being executed. current_index: Cell, /// Potential vector indices that could be re-used on thread creation - /// values are inserted here on after the thread has terminated and - /// been joined with, and hence may potentially become free - /// for use as the index for a new thread. + /// values are inserted here on after the thread has terminated and + /// been joined with, and hence may potentially become free + /// for use as the index for a new thread. /// Elements in this set may still require the vector index to - /// report data-races, and can only be re-used after all - /// active vector-clocks catch up with the threads timestamp. + /// report data-races, and can only be re-used after all + /// active vector-clocks catch up with the threads timestamp. reuse_candidates: RefCell>, /// Counts the number of threads that are currently active - /// if the number of active threads reduces to 1 and then - /// a join operation occures with the remaining main thread - /// then multi-threaded execution may be disabled + /// if the number of active threads reduces to 1 and then + /// a join operation occures with the remaining main thread + /// then multi-threaded execution may be disabled. active_thread_count: Cell, /// This contains threads that have terminated, but not yet joined - /// and so cannot become re-use candidates until a join operation - /// occurs. + /// and so cannot become re-use candidates until a join operation + /// occurs. /// The associated vector index will be moved into re-use candidates - /// after the join operation occurs + /// after the join operation occurs. terminated_threads: RefCell>, } + impl GlobalState { /// Create a new global state, setup with just thread-id=0 - /// advanced to timestamp = 1 + /// advanced to timestamp = 1. pub fn new() -> Self { let global_state = GlobalState { multi_threaded: Cell::new(false), @@ -852,8 +982,8 @@ impl GlobalState { }; // Setup the main-thread since it is not explicitly created: - // uses vector index and thread-id 0, also the rust runtime gives - // the main-thread a name of "main". + // uses vector index and thread-id 0, also the rust runtime gives + // the main-thread a name of "main". let index = global_state.vector_clocks.borrow_mut().push(ThreadClockSet::default()); global_state.vector_info.borrow_mut().push(ThreadId::new(0)); global_state.thread_info.borrow_mut().push( @@ -868,7 +998,7 @@ impl GlobalState { } // Try to find vector index values that can potentially be re-used - // by a new thread instead of a new vector index being created + // by a new thread instead of a new vector index being created. fn find_vector_index_reuse_candidate(&self) -> Option { let mut reuse = self.reuse_candidates.borrow_mut(); let vector_clocks = self.vector_clocks.borrow(); @@ -877,24 +1007,26 @@ impl GlobalState { for &candidate in reuse.iter() { let target_timestamp = vector_clocks[candidate].clock[candidate]; if vector_clocks.iter_enumerated().all(|(clock_idx, clock)| { + // The thread happens before the clock, and hence cannot report - // a data-race with this the candidate index + // a data-race with this the candidate index. let no_data_race = clock.clock[candidate] >= target_timestamp; // The vector represents a thread that has terminated and hence cannot - // report a data-race with the candidate index + // report a data-race with the candidate index. let thread_id = vector_info[clock_idx]; let vector_terminated = reuse.contains(&clock_idx) || terminated_threads.contains_key(&thread_id); // The vector index cannot report a race with the candidate index - // and hence allows the candidate index to be re-used + // and hence allows the candidate index to be re-used. no_data_race || vector_terminated }) { + // All vector clocks for each vector index are equal to - // the target timestamp, and the thread is known to have - // terminated, therefore this vector clock index cannot - // report any more data-races + // the target timestamp, and the thread is known to have + // terminated, therefore this vector clock index cannot + // report any more data-races. assert!(reuse.remove(&candidate)); return Some(candidate) } @@ -903,17 +1035,17 @@ impl GlobalState { } // Hook for thread creation, enabled multi-threaded execution and marks - // the current thread timestamp as happening-before the current thread + // the current thread timestamp as happening-before the current thread. #[inline] pub fn thread_created(&self, thread: ThreadId) { let current_index = self.current_index(); - // Increment the number of active threads + // Increment the number of active threads. let active_threads = self.active_thread_count.get(); self.active_thread_count.set(active_threads + 1); // Enable multi-threaded execution, there are now two threads - // so data-races are now possible. + // so data-races are now possible. self.multi_threaded.set(true); // Load and setup the associated thread metadata @@ -921,101 +1053,105 @@ impl GlobalState { thread_info.ensure_contains_elem(thread, Default::default); // Assign a vector index for the thread, attempting to re-use an old - // vector index that can no longer report any data-races if possible + // vector index that can no longer report any data-races if possible. let created_index = if let Some( reuse_index ) = self.find_vector_index_reuse_candidate() { + // Now re-configure the re-use candidate, increment the clock - // for the new sync use of the vector + // for the new sync use of the vector. let mut vector_clocks = self.vector_clocks.borrow_mut(); vector_clocks[reuse_index].increment_clock(reuse_index); // Locate the old thread the vector was associated with and update - // it to represent the new thread instead + // it to represent the new thread instead. let mut vector_info = self.vector_info.borrow_mut(); let old_thread = vector_info[reuse_index]; vector_info[reuse_index] = thread; // Mark the thread the vector index was associated with as no longer - // representing a thread index + // representing a thread index. thread_info[old_thread].vector_index = None; reuse_index - }else{ + } else { + // No vector re-use candidates available, instead create - // a new vector index + // a new vector index. let mut vector_info = self.vector_info.borrow_mut(); vector_info.push(thread) }; - // Mark the chosen vector index as in use by the thread + // Mark the chosen vector index as in use by the thread. thread_info[thread].vector_index = Some(created_index); - // Create a thread clock set if applicable + // Create a thread clock set if applicable. let mut vector_clocks = self.vector_clocks.borrow_mut(); if created_index == vector_clocks.next_index() { vector_clocks.push(ThreadClockSet::default()); } - // Now load the two clocks and configure the initial state + // Now load the two clocks and configure the initial state. let (current, created) = vector_clocks.pick2_mut(current_index, created_index); - // Advance the current thread before the synchronized operation + // Advance the current thread before the synchronized operation. current.increment_clock(current_index); // Join the created with current, since the current threads - // previous actions happen-before the created thread + // previous actions happen-before the created thread. created.join_with(current); - // Advance both threads after the synchronized operation + // Advance both threads after the synchronized operation. current.increment_clock(current_index); created.increment_clock(created_index); } /// Hook on a thread join to update the implicit happens-before relation - /// between the joined thead and the current thread. + /// between the joined thead and the current thread. #[inline] pub fn thread_joined(&self, current_thread: ThreadId, join_thread: ThreadId) { let mut clocks_vec = self.vector_clocks.borrow_mut(); let thread_info = self.thread_info.borrow(); - // Load the vector clock of the current thread + // Load the vector clock of the current thread. let current_index = thread_info[current_thread].vector_index .expect("Performed thread join on thread with no assigned vector"); let current = &mut clocks_vec[current_index]; - // Load the associated vector clock for the terminated thread + // Load the associated vector clock for the terminated thread. let join_clock = thread_info[join_thread].termination_vector_clock .as_ref().expect("Joined with thread but thread has not terminated"); - // Pre increment clocks before atomic operation + // Pre increment clocks before atomic operation. current.increment_clock(current_index); // The join thread happens-before the current thread - // so update the current vector clock + // so update the current vector clock. current.clock.join(join_clock); - // Post increment clocks after atomic operation + // Post increment clocks after atomic operation. current.increment_clock(current_index); // Check the number of active threads, if the value is 1 - // then test for potentially disabling multi-threaded execution + // then test for potentially disabling multi-threaded execution. let active_threads = self.active_thread_count.get(); if active_threads == 1 { - // May potentially be able to disable multi-threaded execution + + // May potentially be able to disable multi-threaded execution. let current_clock = &clocks_vec[current_index]; if clocks_vec.iter_enumerated().all(|(idx, clocks)| { clocks.clock[idx] <= current_clock.clock[idx] }) { + // The all thread termations happen-before the current clock - // therefore no data-races can be reported until a new thread - // is created, so disable multi-threaded execution + // therefore no data-races can be reported until a new thread + // is created, so disable multi-threaded execution. self.multi_threaded.set(false); } } // If the thread is marked as terminated but not joined - // then move the thread to the re-use set + // then move the thread to the re-use set. let mut termination = self.terminated_threads.borrow_mut(); if let Some(index) = termination.remove(&join_thread) { let mut reuse = self.reuse_candidates.borrow_mut(); @@ -1024,47 +1160,47 @@ impl GlobalState { } /// On thread termination, the vector-clock may re-used - /// in the future once all remaining thread-clocks catch - /// up with the time index of the terminated thread. + /// in the future once all remaining thread-clocks catch + /// up with the time index of the terminated thread. /// This assiges thread termination with a unique index - /// which will be used to join the thread + /// which will be used to join the thread /// This should be called strictly before any calls to - /// `thread_joined` + /// `thread_joined`. #[inline] pub fn thread_terminated(&self) { let current_index = self.current_index(); - // Increment the clock to a unique termination timestamp + // Increment the clock to a unique termination timestamp. let mut vector_clocks = self.vector_clocks.borrow_mut(); let current_clocks = &mut vector_clocks[current_index]; current_clocks.increment_clock(current_index); - // Load the current thread id for the executing vector + // Load the current thread id for the executing vector. let vector_info = self.vector_info.borrow(); let current_thread = vector_info[current_index]; // Load the current thread metadata, and move to a terminated - // vector state. Setting up the vector clock all join operations - // will use. + // vector state. Setting up the vector clock all join operations + // will use. let mut thread_info = self.thread_info.borrow_mut(); let current = &mut thread_info[current_thread]; current.termination_vector_clock = Some(current_clocks.clock.clone()); // Add this thread as a candidate for re-use after a thread join - // occurs + // occurs. let mut termination = self.terminated_threads.borrow_mut(); termination.insert(current_thread, current_index); // Reduce the number of active threads, now that a thread has - // terminated + // terminated. let mut active_threads = self.active_thread_count.get(); active_threads -= 1; self.active_thread_count.set(active_threads); } /// Hook for updating the local tracker of the currently - /// enabled thread, should always be updated whenever - /// `active_thread` in thread.rs is updated + /// enabled thread, should always be updated whenever + /// `active_thread` in thread.rs is updated. #[inline] pub fn thread_set_active(&self, thread: ThreadId) { let thread_info = self.thread_info.borrow(); @@ -1074,9 +1210,9 @@ impl GlobalState { } /// Hook for updating the local tracker of the threads name - /// this should always mirror the local value in thread.rs - /// the thread name is used for improved diagnostics - /// during a data-race + /// this should always mirror the local value in thread.rs + /// the thread name is used for improved diagnostics + /// during a data-race. #[inline] pub fn thread_set_name(&self, thread: ThreadId, name: String) { let name = name.into_boxed_str(); @@ -1086,12 +1222,12 @@ impl GlobalState { /// Attempt to perform a synchronized operation, this - /// will perform no operation if multi-threading is - /// not currently enabled. + /// will perform no operation if multi-threading is + /// not currently enabled. /// Otherwise it will increment the clock for the current - /// vector before and after the operation for data-race - /// detection between any happens-before edges the - /// operation may create + /// vector before and after the operation for data-race + /// detection between any happens-before edges the + /// operation may create. fn maybe_perform_sync_operation<'tcx>( &self, op: impl FnOnce(VectorIdx, RefMut<'_,ThreadClockSet>) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { @@ -1107,50 +1243,50 @@ impl GlobalState { /// Internal utility to identify a thread stored internally - /// returns the id and the name for better diagnostics + /// returns the id and the name for better diagnostics. fn print_thread_metadata(&self, vector: VectorIdx) -> String { let thread = self.vector_info.borrow()[vector]; let thread_name = &self.thread_info.borrow()[thread].thread_name; if let Some(name) = thread_name { let name: &str = name; format!("Thread(id = {:?}, name = {:?})", thread.to_u32(), &*name) - }else{ + } else { format!("Thread(id = {:?})", thread.to_u32()) } } /// Acquire a lock, express that the previous call of - /// `validate_lock_release` must happen before this - pub fn validate_lock_acquire(&self, lock: &DataRaceLockHandle, thread: ThreadId) { + /// `validate_lock_release` must happen before this. + pub fn validate_lock_acquire(&self, lock: &VClock, thread: ThreadId) { let (index, mut clocks) = self.load_thread_state_mut(thread); clocks.increment_clock(index); - clocks.clock.join(&lock.clock); + clocks.clock.join(&lock); clocks.increment_clock(index); } /// Release a lock handle, express that this happens-before - /// any subsequent calls to `validate_lock_acquire` - pub fn validate_lock_release(&self, lock: &mut DataRaceLockHandle, thread: ThreadId) { + /// any subsequent calls to `validate_lock_acquire`. + pub fn validate_lock_release(&self, lock: &mut VClock, thread: ThreadId) { let (index, mut clocks) = self.load_thread_state_mut(thread); clocks.increment_clock(index); - lock.clock.clone_from(&clocks.clock); + lock.clone_from(&clocks.clock); clocks.increment_clock(index); } /// Release a lock handle, express that this happens-before - /// any subsequent calls to `validate_lock_acquire` as well - /// as any previous calls to this function after any - /// `validate_lock_release` calls - pub fn validate_lock_release_shared(&self, lock: &mut DataRaceLockHandle, thread: ThreadId) { + /// any subsequent calls to `validate_lock_acquire` as well + /// as any previous calls to this function after any + /// `validate_lock_release` calls. + pub fn validate_lock_release_shared(&self, lock: &mut VClock, thread: ThreadId) { let (index, mut clocks) = self.load_thread_state_mut(thread); clocks.increment_clock(index); - lock.clock.join(&clocks.clock); + lock.join(&clocks.clock); clocks.increment_clock(index); } /// Load the vector index used by the given thread as well as the set of vector clocks - /// used by the thread + /// used by the thread. #[inline] fn load_thread_state_mut(&self, thread: ThreadId) -> (VectorIdx, RefMut<'_, ThreadClockSet>) { let index = self.thread_info.borrow()[thread].vector_index @@ -1161,7 +1297,7 @@ impl GlobalState { } /// Load the current vector clock in use and the current set of thread clocks - /// in use for the vector + /// in use for the vector. #[inline] fn current_thread_state(&self) -> (VectorIdx, Ref<'_, ThreadClockSet>) { let index = self.current_index(); @@ -1171,7 +1307,7 @@ impl GlobalState { } /// Load the current vector clock in use and the current set of thread clocks - /// in use for the vector mutably for modification + /// in use for the vector mutably for modification. #[inline] fn current_thread_state_mut(&self) -> (VectorIdx, RefMut<'_, ThreadClockSet>) { let index = self.current_index(); @@ -1181,7 +1317,7 @@ impl GlobalState { } /// Return the current thread, should be the same - /// as the data-race active thread + /// as the data-race active thread. #[inline] fn current_index(&self) -> VectorIdx { self.current_index.get() diff --git a/src/eval.rs b/src/eval.rs index 54d06feec36d..0a62f14dd3a1 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -48,6 +48,8 @@ pub struct MiriConfig { pub tracked_alloc_id: Option, /// Whether to track raw pointers in stacked borrows. pub track_raw: bool, + /// Determine if data race detection should be enabled + pub data_race_detector: bool, } impl Default for MiriConfig { @@ -65,6 +67,7 @@ impl Default for MiriConfig { tracked_call_id: None, tracked_alloc_id: None, track_raw: false, + data_race_detector: true, } } } diff --git a/src/lib.rs b/src/lib.rs index c8c9e70ec3de..87effe9c6885 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,7 +55,7 @@ pub use crate::shims::tls::{EvalContextExt as _, TlsData}; pub use crate::shims::EvalContextExt as _; pub use crate::data_race::{ - AtomicReadOp, AtomicWriteOp, AtomicRWOp, AtomicFenceOp, DataRaceLockHandle, + AtomicReadOp, AtomicWriteOp, AtomicRwOp, AtomicFenceOp, EvalContextExt as DataRaceEvalContextExt }; pub use crate::diagnostics::{ @@ -81,7 +81,7 @@ pub use crate::sync::{ EvalContextExt as SyncEvalContextExt, CondvarId, MutexId, RwLockId }; pub use crate::vector_clock::{ - VClock, VSmallClockSet, VectorIdx, VTimestamp + VClock, VSmallClockMap, VectorIdx, VTimestamp }; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be diff --git a/src/machine.rs b/src/machine.rs index 363513f636c9..9612d9e19110 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -109,15 +109,16 @@ impl fmt::Display for MiriMemoryKind { pub struct AllocExtra { /// Stacked Borrows state is only added if it is enabled. pub stacked_borrows: Option, - /// Data race detection via the use of a vector-clock. - pub data_race: data_race::AllocExtra, + /// Data race detection via the use of a vector-clock, + /// this is only added if it is enabled. + pub data_race: Option, } /// Extra global memory data #[derive(Clone, Debug)] pub struct MemoryExtra { pub stacked_borrows: Option, - pub data_race: data_race::MemoryExtra, + pub data_race: Option, pub intptrcast: intptrcast::MemoryExtra, /// Mapping extern static names to their canonical allocation. @@ -147,7 +148,11 @@ impl MemoryExtra { } else { None }; - let data_race = Rc::new(data_race::GlobalState::new()); + let data_race = if config.data_race_detector { + Some(Rc::new(data_race::GlobalState::new())) + }else{ + None + }; MemoryExtra { stacked_borrows, data_race, @@ -472,7 +477,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { // No stacks, no tag. (None, Tag::Untagged) }; - let race_alloc = data_race::AllocExtra::new_allocation(&memory_extra.data_race, alloc.size); + let race_alloc = if let Some(data_race) = &memory_extra.data_race { + Some(data_race::AllocExtra::new_allocation(&data_race, alloc.size)) + } else { + None + }; let mut stacked_borrows = memory_extra.stacked_borrows.as_ref().map(|sb| sb.borrow_mut()); let alloc: Allocation = alloc.with_tags_and_extra( |alloc| { @@ -590,7 +599,9 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - alloc.extra.data_race.read(ptr, size)?; + if let Some(data_race) = &alloc.extra.data_race { + data_race.read(ptr, size)?; + } if let Some(stacked_borrows) = &alloc.extra.stacked_borrows { stacked_borrows.memory_read(ptr, size) } else { @@ -604,7 +615,9 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - alloc.extra.data_race.write(ptr, size)?; + if let Some(data_race) = &mut alloc.extra.data_race { + data_race.write(ptr, size)?; + } if let Some(stacked_borrows) = &mut alloc.extra.stacked_borrows { stacked_borrows.memory_written(ptr, size) } else { @@ -618,7 +631,9 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - alloc.extra.data_race.deallocate(ptr, size)?; + if let Some(data_race) = &mut alloc.extra.data_race { + data_race.deallocate(ptr, size)?; + } if let Some(stacked_borrows) = &mut alloc.extra.stacked_borrows { stacked_borrows.memory_deallocated(ptr, size) } else { diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 50f97af8453e..8f7ae6bebb52 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -324,98 +324,98 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_singlethreadfence_acqrel" => this.compiler_fence(args, AtomicFenceOp::AcqRel)?, "atomic_singlethreadfence" => this.compiler_fence(args, AtomicFenceOp::SeqCst)?, - "atomic_xchg" => this.atomic_exchange(args, dest, AtomicRWOp::SeqCst)?, - "atomic_xchg_acq" => this.atomic_exchange(args, dest, AtomicRWOp::Acquire)?, - "atomic_xchg_rel" => this.atomic_exchange(args, dest, AtomicRWOp::Release)?, - "atomic_xchg_acqrel" => this.atomic_exchange(args, dest, AtomicRWOp::AcqRel)?, - "atomic_xchg_relaxed" => this.atomic_exchange(args, dest, AtomicRWOp::Relaxed)?, + "atomic_xchg" => this.atomic_exchange(args, dest, AtomicRwOp::SeqCst)?, + "atomic_xchg_acq" => this.atomic_exchange(args, dest, AtomicRwOp::Acquire)?, + "atomic_xchg_rel" => this.atomic_exchange(args, dest, AtomicRwOp::Release)?, + "atomic_xchg_acqrel" => this.atomic_exchange(args, dest, AtomicRwOp::AcqRel)?, + "atomic_xchg_relaxed" => this.atomic_exchange(args, dest, AtomicRwOp::Relaxed)?, "atomic_cxchg" => this.atomic_compare_exchange( - args, dest, AtomicRWOp::SeqCst, AtomicReadOp::SeqCst + args, dest, AtomicRwOp::SeqCst, AtomicReadOp::SeqCst )?, "atomic_cxchg_acq" => this.atomic_compare_exchange( - args, dest, AtomicRWOp::Acquire, AtomicReadOp::Acquire + args, dest, AtomicRwOp::Acquire, AtomicReadOp::Acquire )?, "atomic_cxchg_rel" => this.atomic_compare_exchange( - args, dest, AtomicRWOp::Release, AtomicReadOp::Relaxed + args, dest, AtomicRwOp::Release, AtomicReadOp::Relaxed )?, "atomic_cxchg_acqrel" => this.atomic_compare_exchange - (args, dest, AtomicRWOp::AcqRel, AtomicReadOp::Acquire + (args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Acquire )?, "atomic_cxchg_relaxed" => this.atomic_compare_exchange( - args, dest, AtomicRWOp::Relaxed, AtomicReadOp::Relaxed + args, dest, AtomicRwOp::Relaxed, AtomicReadOp::Relaxed )?, "atomic_cxchg_acq_failrelaxed" => this.atomic_compare_exchange( - args, dest, AtomicRWOp::Acquire, AtomicReadOp::Relaxed + args, dest, AtomicRwOp::Acquire, AtomicReadOp::Relaxed )?, "atomic_cxchg_acqrel_failrelaxed" => this.atomic_compare_exchange( - args, dest, AtomicRWOp::AcqRel, AtomicReadOp::Relaxed + args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Relaxed )?, "atomic_cxchg_failrelaxed" => this.atomic_compare_exchange( - args, dest, AtomicRWOp::SeqCst, AtomicReadOp::Relaxed + args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Relaxed )?, "atomic_cxchg_failacq" => this.atomic_compare_exchange( - args, dest, AtomicRWOp::SeqCst, AtomicReadOp::Acquire + args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Acquire )?, "atomic_cxchgweak" => this.atomic_compare_exchange_weak( - args, dest, AtomicRWOp::SeqCst, AtomicReadOp::SeqCst + args, dest, AtomicRwOp::SeqCst, AtomicReadOp::SeqCst )?, "atomic_cxchgweak_acq" => this.atomic_compare_exchange_weak( - args, dest, AtomicRWOp::Acquire, AtomicReadOp::Acquire + args, dest, AtomicRwOp::Acquire, AtomicReadOp::Acquire )?, "atomic_cxchgweak_rel" => this.atomic_compare_exchange_weak( - args, dest, AtomicRWOp::Release, AtomicReadOp::Relaxed + args, dest, AtomicRwOp::Release, AtomicReadOp::Relaxed )?, "atomic_cxchgweak_acqrel" => this.atomic_compare_exchange_weak( - args, dest, AtomicRWOp::AcqRel, AtomicReadOp::Acquire + args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Acquire )?, "atomic_cxchgweak_relaxed" => this.atomic_compare_exchange_weak( - args, dest, AtomicRWOp::Relaxed, AtomicReadOp::Relaxed + args, dest, AtomicRwOp::Relaxed, AtomicReadOp::Relaxed )?, "atomic_cxchgweak_acq_failrelaxed" => this.atomic_compare_exchange_weak( - args, dest, AtomicRWOp::Acquire, AtomicReadOp::Relaxed + args, dest, AtomicRwOp::Acquire, AtomicReadOp::Relaxed )?, "atomic_cxchgweak_acqrel_failrelaxed" => this.atomic_compare_exchange_weak( - args, dest, AtomicRWOp::AcqRel, AtomicReadOp::Relaxed + args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Relaxed )?, "atomic_cxchgweak_failrelaxed" => this.atomic_compare_exchange_weak( - args, dest, AtomicRWOp::SeqCst, AtomicReadOp::Relaxed + args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Relaxed )?, "atomic_cxchgweak_failacq" => this.atomic_compare_exchange_weak( - args, dest, AtomicRWOp::SeqCst, AtomicReadOp::Acquire + args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Acquire )?, - "atomic_or" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRWOp::SeqCst)?, - "atomic_or_acq" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRWOp::Acquire)?, - "atomic_or_rel" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRWOp::Release)?, - "atomic_or_acqrel" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRWOp::AcqRel)?, - "atomic_or_relaxed" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRWOp::Relaxed)?, - "atomic_xor" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRWOp::SeqCst)?, - "atomic_xor_acq" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRWOp::Acquire)?, - "atomic_xor_rel" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRWOp::Release)?, - "atomic_xor_acqrel" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRWOp::AcqRel)?, - "atomic_xor_relaxed" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRWOp::Relaxed)?, - "atomic_and" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRWOp::SeqCst)?, - "atomic_and_acq" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRWOp::Acquire)?, - "atomic_and_rel" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRWOp::Release)?, - "atomic_and_acqrel" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRWOp::AcqRel)?, - "atomic_and_relaxed" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRWOp::Relaxed)?, - "atomic_nand" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRWOp::SeqCst)?, - "atomic_nand_acq" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRWOp::Acquire)?, - "atomic_nand_rel" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRWOp::Release)?, - "atomic_nand_acqrel" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRWOp::AcqRel)?, - "atomic_nand_relaxed" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRWOp::Relaxed)?, - "atomic_xadd" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRWOp::SeqCst)?, - "atomic_xadd_acq" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRWOp::Acquire)?, - "atomic_xadd_rel" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRWOp::Release)?, - "atomic_xadd_acqrel" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRWOp::AcqRel)?, - "atomic_xadd_relaxed" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRWOp::Relaxed)?, - "atomic_xsub" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRWOp::SeqCst)?, - "atomic_xsub_acq" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRWOp::Acquire)?, - "atomic_xsub_rel" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRWOp::Release)?, - "atomic_xsub_acqrel" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRWOp::AcqRel)?, - "atomic_xsub_relaxed" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRWOp::Relaxed)?, + "atomic_or" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::SeqCst)?, + "atomic_or_acq" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::Acquire)?, + "atomic_or_rel" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::Release)?, + "atomic_or_acqrel" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::AcqRel)?, + "atomic_or_relaxed" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::Relaxed)?, + "atomic_xor" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::SeqCst)?, + "atomic_xor_acq" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::Acquire)?, + "atomic_xor_rel" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::Release)?, + "atomic_xor_acqrel" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::AcqRel)?, + "atomic_xor_relaxed" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::Relaxed)?, + "atomic_and" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::SeqCst)?, + "atomic_and_acq" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::Acquire)?, + "atomic_and_rel" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::Release)?, + "atomic_and_acqrel" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::AcqRel)?, + "atomic_and_relaxed" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::Relaxed)?, + "atomic_nand" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::SeqCst)?, + "atomic_nand_acq" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::Acquire)?, + "atomic_nand_rel" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::Release)?, + "atomic_nand_acqrel" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::AcqRel)?, + "atomic_nand_relaxed" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::Relaxed)?, + "atomic_xadd" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::SeqCst)?, + "atomic_xadd_acq" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::Acquire)?, + "atomic_xadd_rel" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::Release)?, + "atomic_xadd_acqrel" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::AcqRel)?, + "atomic_xadd_relaxed" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::Relaxed)?, + "atomic_xsub" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::SeqCst)?, + "atomic_xsub_acq" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::Acquire)?, + "atomic_xsub_rel" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::Release)?, + "atomic_xsub_acqrel" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::AcqRel)?, + "atomic_xsub_relaxed" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::Relaxed)?, // Query type information @@ -514,7 +514,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn atomic_op( &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, - op: mir::BinOp, neg: bool, atomic: AtomicRWOp + op: mir::BinOp, neg: bool, atomic: AtomicRwOp ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -524,39 +524,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx bug!("Atomic arithmetic operations only work on integer types"); } let rhs = this.read_immediate(rhs)?; - let old = this.allow_data_races_mut(|this| { - this.read_immediate(place. into()) - })?; // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + + let old = this.atomic_op_immediate(place, rhs, op, neg, atomic)?; this.write_immediate(*old, dest)?; // old value is returned - - // Atomics wrap around on overflow. - let val = this.binary_op(op, old, rhs)?; - let val = if neg { this.unary_op(mir::UnOp::Not, val)? } else { val }; - this.allow_data_races_mut(|this| { - this.write_immediate(*val, place.into()) - })?; - - this.validate_atomic_rmw(place, atomic)?; Ok(()) } fn atomic_exchange( - &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, atomic: AtomicRWOp + &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, atomic: AtomicRwOp ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let &[place, new] = check_arg_count(args)?; let place = this.deref_operand(place)?; let new = this.read_scalar(new)?; - let old = this.allow_data_races_mut(|this| { - this.read_scalar(place.into()) - })?; // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must @@ -564,18 +551,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + let old = this.atomic_exchange_scalar(place, new, atomic)?; this.write_scalar(old, dest)?; // old value is returned - this.allow_data_races_mut(|this| { - this.write_scalar(new, place.into()) - })?; - - this.validate_atomic_rmw(place, atomic)?; Ok(()) } fn atomic_compare_exchange( &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, - success: AtomicRWOp, fail: AtomicReadOp + success: AtomicRwOp, fail: AtomicReadOp ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -584,13 +567,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let expect_old = this.read_immediate(expect_old)?; // read as immediate for the sake of `binary_op()` let new = this.read_scalar(new)?; - // Failure ordering cannot be stronger than success ordering, therefore first attempt - // to read with the failure ordering and if successfull then try again with the success - // read ordering and write in the success case. - // Read as immediate for the sake of `binary_op()` - let old = this.allow_data_races_mut(|this| { - this.read_immediate(place.into()) - })?; // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must @@ -598,31 +574,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; - // `binary_op` will bail if either of them is not a scalar. - let eq = this.overflowing_binary_op(mir::BinOp::Eq, old, expect_old)?.0; - let res = Immediate::ScalarPair(old.to_scalar_or_uninit(), eq.into()); + + let old = this.atomic_compare_exchange_scalar( + place, expect_old, new, success, fail + )?; // Return old value. - this.write_immediate(res, dest)?; - - // Update ptr depending on comparison. - // if successful, perform a full rw-atomic validation - // otherwise treat this as an atomic load with the fail ordering - if eq.to_bool()? { - this.allow_data_races_mut(|this| { - this.write_scalar(new, place.into()) - })?; - this.validate_atomic_rmw(place, success)?; - } else { - this.validate_atomic_load(place, fail)?; - } - + this.write_immediate(old, dest)?; Ok(()) } fn atomic_compare_exchange_weak( &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, - success: AtomicRWOp, fail: AtomicReadOp + success: AtomicRwOp, fail: AtomicReadOp ) -> InterpResult<'tcx> { // FIXME: the weak part of this is currently not modelled, diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 67cea5507737..78244ab7b879 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -78,7 +78,17 @@ pub fn futex<'tcx>( // Read an `i32` through the pointer, regardless of any wrapper types. // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`. // FIXME: this fails if `addr` is not a pointer type. - // FIXME: what form of atomic operation should the `futex` use to load the value? + // The atomic ordering for futex(https://man7.org/linux/man-pages/man2/futex.2.html): + // "The load of the value of the futex word is an + // atomic memory access (i.e., using atomic machine instructions + // of the respective architecture). This load, the comparison + // with the expected value, and starting to sleep are performed + // atomically and totally ordered with respect to other futex + // operations on the same futex word." + // SeqCst is total order over all operations, so uses acquire, + // either are equal under the current implementation. + // FIXME: is Acquire correct or should some additional ordering constraints be observed? + // FIXME: use RMW or similar? let futex_val = this.read_scalar_at_offset_atomic( addr.into(), 0, this.machine.layouts.i32, AtomicReadOp::Acquire )?.to_i32()?; diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index d741ef346e94..64308d06139f 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -64,7 +64,7 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>( let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; ecx.read_scalar_at_offset_atomic( mutex_op, offset, ecx.machine.layouts.i32, - AtomicReadOp::SeqCst + AtomicReadOp::Acquire ) } @@ -76,7 +76,7 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; ecx.write_scalar_at_offset_atomic( mutex_op, offset, kind, ecx.machine.layouts.i32, - AtomicWriteOp::SeqCst + AtomicWriteOp::Release ) } @@ -85,7 +85,7 @@ fn mutex_get_id<'mir, 'tcx: 'mir>( mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset_atomic( - mutex_op, 4, ecx.machine.layouts.u32, AtomicReadOp::SeqCst + mutex_op, 4, ecx.machine.layouts.u32, AtomicReadOp::Acquire ) } @@ -96,7 +96,7 @@ fn mutex_set_id<'mir, 'tcx: 'mir>( ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset_atomic( mutex_op, 4, id, ecx.machine.layouts.u32, - AtomicWriteOp::SeqCst + AtomicWriteOp::Release ) } @@ -129,7 +129,7 @@ fn rwlock_get_id<'mir, 'tcx: 'mir>( ) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset_atomic( rwlock_op, 4, ecx.machine.layouts.u32, - AtomicReadOp::SeqCst + AtomicReadOp::Acquire ) } @@ -140,7 +140,7 @@ fn rwlock_set_id<'mir, 'tcx: 'mir>( ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset_atomic( rwlock_op, 4, id, ecx.machine.layouts.u32, - AtomicWriteOp::SeqCst + AtomicWriteOp::Release ) } @@ -196,7 +196,7 @@ fn cond_get_id<'mir, 'tcx: 'mir>( ) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset_atomic( cond_op, 4, ecx.machine.layouts.u32, - AtomicReadOp::SeqCst + AtomicReadOp::Acquire ) } @@ -207,7 +207,7 @@ fn cond_set_id<'mir, 'tcx: 'mir>( ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset_atomic( cond_op, 4, id, ecx.machine.layouts.u32, - AtomicWriteOp::SeqCst + AtomicWriteOp::Release ) } diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index e823a7d88d6a..847d083bfa9f 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -15,14 +15,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.tcx.sess.warn( - "thread support is experimental.", + "thread support is experimental, no weak memory effects are currently emulated.", ); // Create the new thread let new_thread_id = this.create_thread(); // Write the current thread-id, switch to the next thread later - // to treat this write operation as occuring on this thread index + // to treat this write operation as occuring on the current thread. let thread_info_place = this.deref_operand(thread)?; this.write_scalar( Scalar::from_uint(new_thread_id.to_u32(), thread_info_place.layout.size), @@ -30,15 +30,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; // Read the function argument that will be sent to the new thread - // again perform the read before the thread starts executing. + // before the thread starts executing since reading after the + // context switch will incorrectly report a data-race. let fn_ptr = this.read_scalar(start_routine)?.check_init()?; let func_arg = this.read_immediate(arg)?; - // Also switch to new thread so that we can push the first stackframe. - // after this all accesses will be treated as occuring in the new thread + // Finally switch to new thread so that we can push the first stackframe. + // After this all accesses will be treated as occuring in the new thread. let old_thread_id = this.set_active_thread(new_thread_id); - // Perform the function pointer load in the new thread frame + // Perform the function pointer load in the new thread frame. let instance = this.memory.get_fn(fn_ptr)?.as_instance()?; // Note: the returned value is currently ignored (see the FIXME in @@ -54,7 +55,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx StackPopCleanup::None { cleanup: true }, )?; - // Restore the old active thread frame + // Restore the old active thread frame. this.set_active_thread(old_thread_id); Ok(0) diff --git a/src/sync.rs b/src/sync.rs index 3469afdcd276..828268c06ccf 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -62,7 +62,7 @@ struct Mutex { /// The queue of threads waiting for this mutex. queue: VecDeque, /// Data race handle - data_race: DataRaceLockHandle + data_race: VClock } declare_id!(RwLockId); @@ -80,9 +80,9 @@ struct RwLock { /// The queue of reader threads waiting for this lock. reader_queue: VecDeque, /// Data race handle for writers - data_race: DataRaceLockHandle, + data_race: VClock, /// Data race handle for readers - data_race_reader: DataRaceLockHandle, + data_race_reader: VClock, } declare_id!(CondvarId); @@ -100,14 +100,14 @@ struct CondvarWaiter { #[derive(Default, Debug)] struct Condvar { waiters: VecDeque, - data_race: DataRaceLockHandle, + data_race: VClock, } /// The futex state. #[derive(Default, Debug)] struct Futex { waiters: VecDeque, - data_race: DataRaceLockHandle, + data_race: VClock, } /// A thread waiting on a futex. @@ -213,7 +213,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex.owner = Some(thread); } mutex.lock_count = mutex.lock_count.checked_add(1).unwrap(); - this.memory.extra.data_race.validate_lock_acquire(&mutex.data_race, thread); + if let Some(data_race) = &this.memory.extra.data_race { + data_race.validate_lock_acquire(&mutex.data_race, thread); + } } /// Try unlocking by decreasing the lock count and returning the old lock @@ -241,7 +243,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex.owner = None; // The mutex is completely unlocked. Try transfering ownership // to another thread. - this.memory.extra.data_race.validate_lock_release(&mut mutex.data_race, current_owner); + if let Some(data_race) = &this.memory.extra.data_race { + data_race.validate_lock_release(&mut mutex.data_race, current_owner); + } this.mutex_dequeue_and_lock(id); } Some(old_lock_count) @@ -297,7 +301,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let rwlock = &mut this.machine.threads.sync.rwlocks[id]; let count = rwlock.readers.entry(reader).or_insert(0); *count = count.checked_add(1).expect("the reader counter overflowed"); - this.memory.extra.data_race.validate_lock_acquire(&rwlock.data_race, reader); + if let Some(data_race) = &this.memory.extra.data_race { + data_race.validate_lock_acquire(&rwlock.data_race, reader); + } } /// Try read-unlock the lock for `reader` and potentially give the lock to a new owner. @@ -319,7 +325,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Entry::Vacant(_) => return false, // we did not even own this lock } - this.memory.extra.data_race.validate_lock_release_shared(&mut rwlock.data_race_reader, reader); + if let Some(data_race) = &this.memory.extra.data_race { + data_race.validate_lock_release_shared(&mut rwlock.data_race_reader, reader); + } // The thread was a reader. If the lock is not held any more, give it to a writer. if this.rwlock_is_locked(id).not() { @@ -328,7 +336,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // of the union of all reader data race handles, since the set of readers // happen-before the writers let rwlock = &mut this.machine.threads.sync.rwlocks[id]; - rwlock.data_race.set_values(&rwlock.data_race_reader); + rwlock.data_race.clone_from(&rwlock.data_race_reader); this.rwlock_dequeue_and_lock_writer(id); } true @@ -355,7 +363,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("rwlock_writer_lock: {:?} now held by {:?}", id, writer); let rwlock = &mut this.machine.threads.sync.rwlocks[id]; rwlock.writer = Some(writer); - this.memory.extra.data_race.validate_lock_acquire(&rwlock.data_race, writer); + if let Some(data_race) = &this.memory.extra.data_race { + data_race.validate_lock_acquire(&rwlock.data_race, writer); + } } #[inline] @@ -373,8 +383,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Release memory to both reader and writer vector clocks // since this writer happens-before both the union of readers once they are finished // and the next writer - this.memory.extra.data_race.validate_lock_release(&mut rwlock.data_race, current_writer); - this.memory.extra.data_race.validate_lock_release(&mut rwlock.data_race_reader, current_writer); + if let Some(data_race) = &this.memory.extra.data_race { + data_race.validate_lock_release(&mut rwlock.data_race, current_writer); + data_race.validate_lock_release(&mut rwlock.data_race_reader, current_writer); + } // The thread was a writer. // // We are prioritizing writers here against the readers. As a @@ -435,14 +447,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let current_thread = this.get_active_thread(); let condvar = &mut this.machine.threads.sync.condvars[id]; - let data_race = &mut this.memory.extra.data_race; + let data_race = &this.memory.extra.data_race; // Each condvar signal happens-before the end of the condvar wake - data_race.validate_lock_release(&mut condvar.data_race, current_thread); + if let Some(data_race) = data_race { + data_race.validate_lock_release(&mut condvar.data_race, current_thread); + } condvar.waiters .pop_front() .map(|waiter| { - data_race.validate_lock_acquire(&mut condvar.data_race, waiter.thread); + if let Some(data_race) = data_race { + data_race.validate_lock_acquire(&mut condvar.data_race, waiter.thread); + } (waiter.thread, waiter.mutex) }) } @@ -466,12 +482,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let current_thread = this.get_active_thread(); let futex = &mut this.machine.threads.sync.futexes.get_mut(&addr.erase_tag())?; - let data_race = &mut this.memory.extra.data_race; + let data_race = &this.memory.extra.data_race; // Each futex-wake happens-before the end of the futex wait - data_race.validate_lock_release(&mut futex.data_race, current_thread); + if let Some(data_race) = data_race { + data_race.validate_lock_release(&mut futex.data_race, current_thread); + } let res = futex.waiters.pop_front().map(|waiter| { - data_race.validate_lock_acquire(&futex.data_race, waiter.thread); + if let Some(data_race) = data_race { + data_race.validate_lock_acquire(&futex.data_race, waiter.thread); + } waiter.thread }); res diff --git a/src/thread.rs b/src/thread.rs index 40cfd04d7923..5d783430417b 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -3,6 +3,7 @@ use std::cell::RefCell; use std::collections::hash_map::Entry; use std::convert::TryFrom; +use std::rc::Rc; use std::num::TryFromIntError; use std::time::{Duration, Instant, SystemTime}; @@ -327,7 +328,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Mark that the active thread tries to join the thread with `joined_thread_id`. - fn join_thread(&mut self, joined_thread_id: ThreadId, data_race: &data_race::GlobalState) -> InterpResult<'tcx> { + fn join_thread(&mut self, joined_thread_id: ThreadId, data_race: &Option>) -> InterpResult<'tcx> { if self.threads[joined_thread_id].join_status != ThreadJoinStatus::Joinable { throw_ub_format!("trying to join a detached or already joined thread"); } @@ -351,9 +352,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { self.active_thread, joined_thread_id ); - }else{ + } else { // The thread has already terminated - mark join happens-before - data_race.thread_joined(self.active_thread, joined_thread_id); + if let Some(data_race) = data_race { + data_race.thread_joined(self.active_thread, joined_thread_id); + } } Ok(()) } @@ -428,7 +431,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Wakes up threads joining on the active one and deallocates thread-local statics. /// The `AllocId` that can now be freed is returned. - fn thread_terminated(&mut self, data_race: &data_race::GlobalState) -> Vec { + fn thread_terminated(&mut self, data_race: &Option>) -> Vec { let mut free_tls_statics = Vec::new(); { let mut thread_local_statics = self.thread_local_alloc_ids.borrow_mut(); @@ -444,12 +447,16 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { }); } // Set the thread into a terminated state in the data-race detector - data_race.thread_terminated(); + if let Some(data_race) = data_race { + data_race.thread_terminated(); + } // Check if we need to unblock any threads. for (i, thread) in self.threads.iter_enumerated_mut() { if thread.state == ThreadState::BlockedOnJoin(self.active_thread) { // The thread has terminated, mark happens-before edge to joining thread - data_race.thread_joined(i, self.active_thread); + if let Some(data_race) = data_race { + data_race.thread_joined(i, self.active_thread); + } trace!("unblocking {:?} because {:?} terminated", i, self.active_thread); thread.state = ThreadState::Enabled; } @@ -463,7 +470,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// used in stateless model checkers such as Loom: run the active thread as /// long as we can and switch only when we have to (the active thread was /// blocked, terminated, or has explicitly asked to be preempted). - fn schedule(&mut self, data_race: &data_race::GlobalState) -> InterpResult<'tcx, SchedulingAction> { + fn schedule(&mut self, data_race: &Option>) -> InterpResult<'tcx, SchedulingAction> { // Check whether the thread has **just** terminated (`check_terminated` // checks whether the thread has popped all its stack and if yes, sets // the thread state to terminated). @@ -508,7 +515,9 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { if thread.state == ThreadState::Enabled { if !self.yield_active_thread || id != self.active_thread { self.active_thread = id; - data_race.thread_set_active(self.active_thread); + if let Some(data_race) = data_race { + data_race.thread_set_active(self.active_thread); + } break; } } @@ -563,7 +572,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn create_thread(&mut self) -> ThreadId { let this = self.eval_context_mut(); let id = this.machine.threads.create_thread(); - this.memory.extra.data_race.thread_created(id); + if let Some(data_race) = &this.memory.extra.data_race { + data_race.thread_created(id); + } id } @@ -576,7 +587,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let data_race = &*this.memory.extra.data_race; + let data_race = &this.memory.extra.data_race; this.machine.threads.join_thread(joined_thread_id, data_race)?; Ok(()) } @@ -584,7 +595,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn set_active_thread(&mut self, thread_id: ThreadId) -> ThreadId { let this = self.eval_context_mut(); - this.memory.extra.data_race.thread_set_active(thread_id); + if let Some(data_race) = &this.memory.extra.data_race { + data_race.thread_set_active(thread_id); + } this.machine.threads.set_active_thread_id(thread_id) } @@ -639,10 +652,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn set_active_thread_name(&mut self, new_thread_name: Vec) { let this = self.eval_context_mut(); - if let Ok(string) = String::from_utf8(new_thread_name.clone()) { - this.memory.extra.data_race.thread_set_name( - this.machine.threads.active_thread, string - ); + if let Some(data_race) = &this.memory.extra.data_race { + if let Ok(string) = String::from_utf8(new_thread_name.clone()) { + data_race.thread_set_name( + this.machine.threads.active_thread, string + ); + } } this.machine.threads.set_thread_name(new_thread_name); } @@ -713,7 +728,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { let this = self.eval_context_mut(); - let data_race = &*this.memory.extra.data_race; + let data_race = &this.memory.extra.data_race; this.machine.threads.schedule(data_race) } @@ -724,7 +739,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn thread_terminated(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let data_race = &*this.memory.extra.data_race; + let data_race = &this.memory.extra.data_race; for alloc_id in this.machine.threads.thread_terminated(data_race) { let ptr = this.memory.global_base_pointer(alloc_id.into())?; this.memory.deallocate(ptr, None, MiriMemoryKind::Tls.into())?; diff --git a/src/vector_clock.rs b/src/vector_clock.rs index 8d05eb1b992b..110b278852d5 100644 --- a/src/vector_clock.rs +++ b/src/vector_clock.rs @@ -1,121 +1,132 @@ use std::{ fmt::{self, Debug}, cmp::Ordering, ops::Index, - num::TryFromIntError, convert::TryFrom, mem + convert::TryFrom, mem }; use smallvec::SmallVec; use rustc_index::vec::Idx; use rustc_data_structures::fx::FxHashMap; /// A vector clock index, this is associated with a thread id -/// but in some cases one vector index may be shared with -/// multiple thread ids. +/// but in some cases one vector index may be shared with +/// multiple thread ids id it safe to do so. #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] pub struct VectorIdx(u32); -impl VectorIdx{ +impl VectorIdx { + + #[inline(always)] pub fn to_u32(self) -> u32 { self.0 } + pub const MAX_INDEX: VectorIdx = VectorIdx(u32::MAX); + } impl Idx for VectorIdx { + + #[inline] fn new(idx: usize) -> Self { VectorIdx(u32::try_from(idx).unwrap()) } + #[inline] fn index(self) -> usize { usize::try_from(self.0).unwrap() } -} -impl TryFrom for VectorIdx { - type Error = TryFromIntError; - fn try_from(id: u64) -> Result { - u32::try_from(id).map(|id_u32| Self(id_u32)) - } } impl From for VectorIdx { + + #[inline] fn from(id: u32) -> Self { Self(id) } + } - -/// A sparse set of vector clocks, where each vector index -/// is associated with a vector clock. -/// This treats all vector clocks that have not been assigned -/// as equal to the all zero vector clocks -/// Is optimized for the common case where only 1 element is stored -/// in the set and the rest can be ignored, falling-back to -/// using an internal hash-map once more than 1 element is assigned -/// at any one time +/// A sparse mapping of vector index values to vector clocks, this +/// is optimized for the common case with only one element stored +/// inside the map. +/// This is used to store the set of currently active release +/// sequences at a given memory location, since RMW operations +/// allow for multiple release sequences to be active at once +/// and to be collapsed back to one active release sequence +/// once a non RMW atomic store operation occurs. +/// An all zero vector is considered to be equal to no +/// element stored internally since it will never be +/// stored and has no meaning as a release sequence +/// vector clock. #[derive(Clone)] -pub struct VSmallClockSet(VSmallClockSetInner); +pub struct VSmallClockMap(VSmallClockMapInner); #[derive(Clone)] -enum VSmallClockSetInner { +enum VSmallClockMapInner { + /// Zero or 1 vector elements, common - /// case for the sparse set. + /// case for the sparse set. /// The all zero vector clock is treated - /// as equal to the empty element + /// as equal to the empty element. Small(VectorIdx, VClock), - /// Hash-map of vector clocks + /// Hash-map of vector clocks. Large(FxHashMap) } -impl VSmallClockSet { +impl VSmallClockMap { /// Remove all clock vectors from the map, setting them - /// to the zero vector + /// to the zero vector. pub fn clear(&mut self) { match &mut self.0 { - VSmallClockSetInner::Small(_, clock) => { + VSmallClockMapInner::Small(_, clock) => { clock.set_zero_vector() } - VSmallClockSetInner::Large(hash_map) => { + VSmallClockMapInner::Large(hash_map) => { hash_map.clear(); } } } /// Remove all clock vectors except for the clock vector - /// stored at the given index, which is retained + /// stored at the given index, which is retained. pub fn retain_index(&mut self, index: VectorIdx) { match &mut self.0 { - VSmallClockSetInner::Small(small_idx, clock) => { + VSmallClockMapInner::Small(small_idx, clock) => { if index != *small_idx { + // The zero-vector is considered to equal - // the empty element + // the empty element. clock.set_zero_vector() } }, - VSmallClockSetInner::Large(hash_map) => { - hash_map.retain(|idx,_| { - *idx == index - }); + VSmallClockMapInner::Large(hash_map) => { + let value = hash_map.remove(&index).unwrap_or_default(); + self.0 = VSmallClockMapInner::Small(index, value); } } } /// Insert the vector clock into the associated vector - /// index + /// index. pub fn insert(&mut self, index: VectorIdx, clock: &VClock) { match &mut self.0 { - VSmallClockSetInner::Small(small_idx, small_clock) => { + VSmallClockMapInner::Small(small_idx, small_clock) => { if small_clock.is_zero_vector() { + *small_idx = index; small_clock.clone_from(clock); - }else if !clock.is_zero_vector() { + } else if !clock.is_zero_vector() { + + // Convert to using the hash-map representation. let mut hash_map = FxHashMap::default(); hash_map.insert(*small_idx, mem::take(small_clock)); hash_map.insert(index, clock.clone()); - self.0 = VSmallClockSetInner::Large(hash_map); + self.0 = VSmallClockMapInner::Large(hash_map); } }, - VSmallClockSetInner::Large(hash_map) => { + VSmallClockMapInner::Large(hash_map) => { if !clock.is_zero_vector() { hash_map.insert(index, clock.clone()); } @@ -127,41 +138,44 @@ impl VSmallClockSet { /// vector index. pub fn get(&self, index: VectorIdx) -> Option<&VClock> { match &self.0 { - VSmallClockSetInner::Small(small_idx, small_clock) => { + VSmallClockMapInner::Small(small_idx, small_clock) => { if *small_idx == index && !small_clock.is_zero_vector() { Some(small_clock) - }else{ + } else { None } }, - VSmallClockSetInner::Large(hash_map) => { + VSmallClockMapInner::Large(hash_map) => { hash_map.get(&index) } } } } -impl Default for VSmallClockSet { +impl Default for VSmallClockMap { + #[inline] fn default() -> Self { - VSmallClockSet( - VSmallClockSetInner::Small(VectorIdx::new(0), VClock::default()) + VSmallClockMap( + VSmallClockMapInner::Small(VectorIdx::new(0), VClock::default()) ) } + } -impl Debug for VSmallClockSet { +impl Debug for VSmallClockMap { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Print the contents of the small vector clock set as the map - // of vector index to vector clock that they represent + // of vector index to vector clock that they represent. let mut map = f.debug_map(); match &self.0 { - VSmallClockSetInner::Small(small_idx, small_clock) => { + VSmallClockMapInner::Small(small_idx, small_clock) => { if !small_clock.is_zero_vector() { map.entry(&small_idx, &small_clock); } }, - VSmallClockSetInner::Large(hash_map) => { + VSmallClockMapInner::Large(hash_map) => { for (idx, elem) in hash_map.iter() { map.entry(idx, elem); } @@ -169,30 +183,35 @@ impl Debug for VSmallClockSet { } map.finish() } + } -impl PartialEq for VSmallClockSet { + + +impl PartialEq for VSmallClockMap { + fn eq(&self, other: &Self) -> bool { - use VSmallClockSetInner::*; + use VSmallClockMapInner::*; match (&self.0, &other.0) { (Small(i1, c1), Small(i2, c2)) => { if c1.is_zero_vector() { // Either they are both zero or they are non-equal c2.is_zero_vector() - }else{ + } else { // At least one is non-zero, so the full comparison is correct i1 == i2 && c1 == c2 } } - (VSmallClockSetInner::Small(idx, clock), VSmallClockSetInner::Large(hash_map)) | - (VSmallClockSetInner::Large(hash_map), VSmallClockSetInner::Small(idx, clock)) => { + (Small(idx, clock), Large(hash_map)) | + (Large(hash_map), Small(idx, clock)) => { + if hash_map.len() == 0 { // Equal to the empty hash-map clock.is_zero_vector() - }else if hash_map.len() == 1 { + } else if hash_map.len() == 1 { // Equal to the hash-map with one element let (hash_idx, hash_clock) = hash_map.iter().next().unwrap(); hash_idx == idx && hash_clock == clock - }else{ + } else { false } } @@ -201,32 +220,38 @@ impl PartialEq for VSmallClockSet { } } } + } -impl Eq for VSmallClockSet {} + +impl Eq for VSmallClockMap {} /// The size of the vector-clock to store inline -/// clock vectors larger than this will be stored on the heap +/// clock vectors larger than this will be stored on the heap const SMALL_VECTOR: usize = 4; /// The type of the time-stamps recorded in the data-race detector -/// set to a type of unsigned integer +/// set to a type of unsigned integer pub type VTimestamp = u32; -/// A vector clock for detecting data-races -/// invariants: -/// - the last element in a VClock must not be 0 -/// -- this means that derive(PartialEq & Eq) is correct -/// -- as there is no implicit zero tail that might be equal -/// -- also simplifies the implementation of PartialOrd +/// A vector clock for detecting data-races, this is conceptually +/// a map from a vector index (and thus a thread id) to a timestamp. +/// The compare operations require that the invariant that the last +/// element in the internal timestamp slice must not be a 0, hence +/// all zero vector clocks are always represented by the empty slice; +/// and allows for the implementation of compare operations to short +/// circuit the calculation and return the correct result faster, +/// also this means that there is only one unique valid length +/// for each set of vector clock values and hence the PartialEq +// and Eq derivations are correct. #[derive(PartialEq, Eq, Default, Debug)] pub struct VClock(SmallVec<[VTimestamp; SMALL_VECTOR]>); impl VClock { /// Create a new vector-clock containing all zeros except - /// for a value at the given index + /// for a value at the given index pub fn new_with_index(index: VectorIdx, timestamp: VTimestamp) -> VClock { let len = index.index() + 1; let mut vec = smallvec::smallvec![0; len]; @@ -241,8 +266,8 @@ impl VClock { } /// Get a mutable slice to the internal vector with minimum `min_len` - /// elements, to preserve invariants this vector must modify - /// the `min_len`-1 nth element to a non-zero value + /// elements, to preserve invariants this vector must modify + /// the `min_len`-1 nth element to a non-zero value #[inline] fn get_mut_with_min_len(&mut self, min_len: usize) -> &mut [VTimestamp] { if self.0.len() < min_len { @@ -253,7 +278,7 @@ impl VClock { } /// Increment the vector clock at a known index - /// this will panic if the vector index overflows + /// this will panic if the vector index overflows #[inline] pub fn increment_index(&mut self, idx: VectorIdx) { let idx = idx.index(); @@ -263,8 +288,8 @@ impl VClock { } // Join the two vector-clocks together, this - // sets each vector-element to the maximum value - // of that element in either of the two source elements. + // sets each vector-element to the maximum value + // of that element in either of the two source elements. pub fn join(&mut self, other: &Self) { let rhs_slice = other.as_slice(); let lhs_slice = self.get_mut_with_min_len(rhs_slice.len()); @@ -291,30 +316,43 @@ impl VClock { pub fn is_zero_vector(&self) -> bool { self.0.is_empty() } + } impl Clone for VClock { + fn clone(&self) -> Self { VClock(self.0.clone()) } + + // Optimized clone-from, can be removed + // and replaced with a derive once a similar + // optimization is inserted into SmallVec's + // clone implementation. fn clone_from(&mut self, source: &Self) { let source_slice = source.as_slice(); self.0.clear(); self.0.extend_from_slice(source_slice); } + } impl PartialOrd for VClock { + fn partial_cmp(&self, other: &VClock) -> Option { // Load the values as slices let lhs_slice = self.as_slice(); let rhs_slice = other.as_slice(); - // Iterate through the combined vector slice - // keeping track of the order that is currently possible to satisfy. - // If an ordering relation is detected to be impossible, then bail and - // directly return None + // Iterate through the combined vector slice continuously updating + // the value of `order` to the current comparison of the vector from + // index 0 to the currently checked index. + // An Equal ordering can be converted into Less or Greater ordering + // on finding an element that is less than or greater than the other + // but if one Greater and one Less element-wise comparison is found + // then no ordering is possible and so directly return an ordering + // of None. let mut iter = lhs_slice.iter().zip(rhs_slice.iter()); let mut order = match iter.next() { Some((lhs, rhs)) => lhs.cmp(rhs), @@ -332,23 +370,23 @@ impl PartialOrd for VClock { } } - //Now test if either left or right have trailing elements + // Now test if either left or right have trailing elements, // by the invariant the trailing elements have at least 1 // non zero value, so no additional calculation is required - // to determine the result of the PartialOrder + // to determine the result of the PartialOrder. let l_len = lhs_slice.len(); let r_len = rhs_slice.len(); match l_len.cmp(&r_len) { - // Equal has no additional elements: return current order + // Equal means no additional elements: return current order Ordering::Equal => Some(order), // Right has at least 1 element > than the implicit 0, - // so the only valid values are Ordering::Less or None + // so the only valid values are Ordering::Less or None. Ordering::Less => match order { Ordering::Less | Ordering::Equal => Some(Ordering::Less), Ordering::Greater => None } // Left has at least 1 element > than the implicit 0, - // so the only valid values are Ordering::Greater or None + // so the only valid values are Ordering::Greater or None. Ordering::Greater => match order { Ordering::Greater | Ordering::Equal => Some(Ordering::Greater), Ordering::Less => None @@ -362,28 +400,28 @@ impl PartialOrd for VClock { let rhs_slice = other.as_slice(); // If l_len > r_len then at least one element - // in l_len is > than r_len, therefore the result - // is either Some(Greater) or None, so return false - // early. + // in l_len is > than r_len, therefore the result + // is either Some(Greater) or None, so return false + // early. let l_len = lhs_slice.len(); let r_len = rhs_slice.len(); if l_len <= r_len { // If any elements on the left are greater than the right - // then the result is None or Some(Greater), both of which - // return false, the earlier test asserts that no elements in the - // extended tail violate this assumption. Otherwise l <= r, finally - // the case where the values are potentially equal needs to be considered - // and false returned as well + // then the result is None or Some(Greater), both of which + // return false, the earlier test asserts that no elements in the + // extended tail violate this assumption. Otherwise l <= r, finally + // the case where the values are potentially equal needs to be considered + // and false returned as well let mut equal = l_len == r_len; for (&l, &r) in lhs_slice.iter().zip(rhs_slice.iter()) { if l > r { return false - }else if l < r { + } else if l < r { equal = false; } } !equal - }else{ + } else { false } } @@ -394,18 +432,18 @@ impl PartialOrd for VClock { let rhs_slice = other.as_slice(); // If l_len > r_len then at least one element - // in l_len is > than r_len, therefore the result - // is either Some(Greater) or None, so return false - // early. + // in l_len is > than r_len, therefore the result + // is either Some(Greater) or None, so return false + // early. let l_len = lhs_slice.len(); let r_len = rhs_slice.len(); if l_len <= r_len { // If any elements on the left are greater than the right - // then the result is None or Some(Greater), both of which - // return false, the earlier test asserts that no elements in the - // extended tail violate this assumption. Otherwise l <= r + // then the result is None or Some(Greater), both of which + // return false, the earlier test asserts that no elements in the + // extended tail violate this assumption. Otherwise l <= r !lhs_slice.iter().zip(rhs_slice.iter()).any(|(&l, &r)| l > r) - }else{ + } else { false } } @@ -416,28 +454,28 @@ impl PartialOrd for VClock { let rhs_slice = other.as_slice(); // If r_len > l_len then at least one element - // in r_len is > than l_len, therefore the result - // is either Some(Less) or None, so return false - // early. + // in r_len is > than l_len, therefore the result + // is either Some(Less) or None, so return false + // early. let l_len = lhs_slice.len(); let r_len = rhs_slice.len(); if l_len >= r_len { // If any elements on the left are less than the right - // then the result is None or Some(Less), both of which - // return false, the earlier test asserts that no elements in the - // extended tail violate this assumption. Otherwise l >=, finally - // the case where the values are potentially equal needs to be considered - // and false returned as well + // then the result is None or Some(Less), both of which + // return false, the earlier test asserts that no elements in the + // extended tail violate this assumption. Otherwise l >=, finally + // the case where the values are potentially equal needs to be considered + // and false returned as well let mut equal = l_len == r_len; for (&l, &r) in lhs_slice.iter().zip(rhs_slice.iter()) { if l < r { return false - }else if l > r { + } else if l > r { equal = false; } } !equal - }else{ + } else { false } } @@ -448,30 +486,33 @@ impl PartialOrd for VClock { let rhs_slice = other.as_slice(); // If r_len > l_len then at least one element - // in r_len is > than l_len, therefore the result - // is either Some(Less) or None, so return false - // early. + // in r_len is > than l_len, therefore the result + // is either Some(Less) or None, so return false + // early. let l_len = lhs_slice.len(); let r_len = rhs_slice.len(); if l_len >= r_len { // If any elements on the left are less than the right - // then the result is None or Some(Less), both of which - // return false, the earlier test asserts that no elements in the - // extended tail violate this assumption. Otherwise l >= r + // then the result is None or Some(Less), both of which + // return false, the earlier test asserts that no elements in the + // extended tail violate this assumption. Otherwise l >= r !lhs_slice.iter().zip(rhs_slice.iter()).any(|(&l, &r)| l < r) - }else{ + } else { false } } + } impl Index for VClock { + type Output = VTimestamp; #[inline] fn index(&self, index: VectorIdx) -> &VTimestamp { self.as_slice().get(index.to_u32() as usize).unwrap_or(&0) } + } @@ -480,7 +521,8 @@ impl Index for VClock { /// test suite #[cfg(test)] mod tests { - use super::{VClock, VTimestamp, VectorIdx, VSmallClockSet}; + + use super::{VClock, VTimestamp, VectorIdx, VSmallClockMap}; use std::cmp::Ordering; #[test] @@ -536,7 +578,7 @@ mod tests { let alt_compare = r.partial_cmp(&l); assert_eq!(alt_compare, o.map(Ordering::reverse), "Invalid alt comparison\n l: {:?}\n r: {:?}",l,r); - //Test operatorsm with faster implementations + //Test operators with faster implementations assert_eq!( matches!(compare,Some(Ordering::Less)), l < r, "Invalid (<):\n l: {:?}\n r: {:?}",l,r @@ -573,30 +615,31 @@ mod tests { #[test] pub fn test_vclock_set() { - let mut set = VSmallClockSet::default(); + let mut map = VSmallClockMap::default(); let v1 = from_slice(&[3,0,1]); let v2 = from_slice(&[4,2,3]); let v3 = from_slice(&[4,8,3]); - set.insert(VectorIdx(0), &v1); - assert_eq!(set.get(VectorIdx(0)), Some(&v1)); - set.insert(VectorIdx(5), &v2); - assert_eq!(set.get(VectorIdx(0)), Some(&v1)); - assert_eq!(set.get(VectorIdx(5)), Some(&v2)); - set.insert(VectorIdx(53), &v3); - assert_eq!(set.get(VectorIdx(0)), Some(&v1)); - assert_eq!(set.get(VectorIdx(5)), Some(&v2)); - assert_eq!(set.get(VectorIdx(53)), Some(&v3)); - set.retain_index(VectorIdx(53)); - assert_eq!(set.get(VectorIdx(0)), None); - assert_eq!(set.get(VectorIdx(5)), None); - assert_eq!(set.get(VectorIdx(53)), Some(&v3)); - set.clear(); - assert_eq!(set.get(VectorIdx(0)), None); - assert_eq!(set.get(VectorIdx(5)), None); - assert_eq!(set.get(VectorIdx(53)), None); - set.insert(VectorIdx(53), &v3); - assert_eq!(set.get(VectorIdx(0)), None); - assert_eq!(set.get(VectorIdx(5)), None); - assert_eq!(set.get(VectorIdx(53)), Some(&v3)); + map.insert(VectorIdx(0), &v1); + assert_eq!(map.get(VectorIdx(0)), Some(&v1)); + map.insert(VectorIdx(5), &v2); + assert_eq!(map.get(VectorIdx(0)), Some(&v1)); + assert_eq!(map.get(VectorIdx(5)), Some(&v2)); + map.insert(VectorIdx(53), &v3); + assert_eq!(map.get(VectorIdx(0)), Some(&v1)); + assert_eq!(map.get(VectorIdx(5)), Some(&v2)); + assert_eq!(map.get(VectorIdx(53)), Some(&v3)); + map.retain_index(VectorIdx(53)); + assert_eq!(map.get(VectorIdx(0)), None); + assert_eq!(map.get(VectorIdx(5)), None); + assert_eq!(map.get(VectorIdx(53)), Some(&v3)); + map.clear(); + assert_eq!(map.get(VectorIdx(0)), None); + assert_eq!(map.get(VectorIdx(5)), None); + assert_eq!(map.get(VectorIdx(53)), None); + map.insert(VectorIdx(53), &v3); + assert_eq!(map.get(VectorIdx(0)), None); + assert_eq!(map.get(VectorIdx(5)), None); + assert_eq!(map.get(VectorIdx(53)), Some(&v3)); } + } diff --git a/tests/run-pass/concurrency/data_race.stderr b/tests/run-pass/concurrency/data_race.stderr index b01247aea4e0..7ba8087a9b4b 100644 --- a/tests/run-pass/concurrency/data_race.stderr +++ b/tests/run-pass/concurrency/data_race.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental. +warning: thread support is experimental, no weak memory effects are currently emulated. diff --git a/tests/run-pass/concurrency/linux-futex.stderr b/tests/run-pass/concurrency/linux-futex.stderr index b01247aea4e0..7ba8087a9b4b 100644 --- a/tests/run-pass/concurrency/linux-futex.stderr +++ b/tests/run-pass/concurrency/linux-futex.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental. +warning: thread support is experimental, no weak memory effects are currently emulated. diff --git a/tests/run-pass/concurrency/simple.stderr b/tests/run-pass/concurrency/simple.stderr index f1550dd25aa0..24444fdc17c1 100644 --- a/tests/run-pass/concurrency/simple.stderr +++ b/tests/run-pass/concurrency/simple.stderr @@ -1,4 +1,4 @@ -warning: thread support is experimental. +warning: thread support is experimental, no weak memory effects are currently emulated. thread '' panicked at 'Hello!', $DIR/simple.rs:54:9 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/concurrency/sync.stderr b/tests/run-pass/concurrency/sync.stderr index b01247aea4e0..7ba8087a9b4b 100644 --- a/tests/run-pass/concurrency/sync.stderr +++ b/tests/run-pass/concurrency/sync.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental. +warning: thread support is experimental, no weak memory effects are currently emulated. diff --git a/tests/run-pass/concurrency/thread_locals.stderr b/tests/run-pass/concurrency/thread_locals.stderr index b01247aea4e0..7ba8087a9b4b 100644 --- a/tests/run-pass/concurrency/thread_locals.stderr +++ b/tests/run-pass/concurrency/thread_locals.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental. +warning: thread support is experimental, no weak memory effects are currently emulated. diff --git a/tests/run-pass/concurrency/tls_lib_drop.stderr b/tests/run-pass/concurrency/tls_lib_drop.stderr index b01247aea4e0..7ba8087a9b4b 100644 --- a/tests/run-pass/concurrency/tls_lib_drop.stderr +++ b/tests/run-pass/concurrency/tls_lib_drop.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental. +warning: thread support is experimental, no weak memory effects are currently emulated. diff --git a/tests/run-pass/libc.stderr b/tests/run-pass/libc.stderr index b01247aea4e0..7ba8087a9b4b 100644 --- a/tests/run-pass/libc.stderr +++ b/tests/run-pass/libc.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental. +warning: thread support is experimental, no weak memory effects are currently emulated. diff --git a/tests/run-pass/panic/concurrent-panic.stderr b/tests/run-pass/panic/concurrent-panic.stderr index ca6031e57b40..885385a8dd93 100644 --- a/tests/run-pass/panic/concurrent-panic.stderr +++ b/tests/run-pass/panic/concurrent-panic.stderr @@ -1,4 +1,4 @@ -warning: thread support is experimental. +warning: thread support is experimental, no weak memory effects are currently emulated. Thread 1 starting, will block on mutex Thread 1 reported it has started From 4a1f7ac1f153c7b0df8d7603b4852cc24b22c039 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Sun, 15 Nov 2020 19:50:38 +0000 Subject: [PATCH 2446/5092] Convert extra benchmark program into cfg option. --- bench-cargo-miri/mse/src/main.rs | 3 ++ .../mse_and_dangling_thread/Cargo.toml | 7 ----- .../mse_and_dangling_thread/src/main.rs | 30 ------------------- 3 files changed, 3 insertions(+), 37 deletions(-) delete mode 100644 bench-cargo-miri/mse_and_dangling_thread/Cargo.toml delete mode 100644 bench-cargo-miri/mse_and_dangling_thread/src/main.rs diff --git a/bench-cargo-miri/mse/src/main.rs b/bench-cargo-miri/mse/src/main.rs index b4ad1575104e..57e286071055 100644 --- a/bench-cargo-miri/mse/src/main.rs +++ b/bench-cargo-miri/mse/src/main.rs @@ -2,6 +2,9 @@ static EXPECTED: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, static PCM: &[i16] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1, 0, 1, 0, 0, -2, 0, -2, 0, -2, 0, -2, -2, -2, -3, -3, -3, -3, -4, -2, -5, -2, -5, -2, -4, 0, -4, 0, -4, 0, -4, 1, -4, 1, -4, 2, -4, 2, -4, 2, -4, 2, -4, 2, -3, 1, -4, 0, -4, 0, -5, 0, -5, 0, -5, 0, -4, 2, -4, 3, -4, 4, -3, 5, -2, 5, -3, 6, -3, 6, -3, 5, -3, 5, -2, 4, -2, 3, -5, 0, -6, 0, -3, -2, -4, -4, -9, -5, -9, -4, -4, -2, -4, -2, -4, 0, -2, 1, 1, 1, 4, 2, 8, 2, 12, 1, 13, 0, 12, 0, 11, 0, 8, -2, 7, 0, 7, -3, 11, -8, 15, -9, 17, -6, 17, -5, 13, -3, 7, 0, 3, 0, -2, 0, -4, 0, -4, -2, -6, 0, -14, -2, -17, -4, -8, 0, -7, 5, -17, 7, -18, 10, -7, 18, -2, 25, -3, 27, 0, 31, 4, 34, 4, 34, 8, 36, 8, 37, 2, 36, 4, 34, 8, 28, 3, 15, 0, 11, 0, 12, -5, 8, -4, 10, 0, 23, -4, 31, -8, 30, -2, 30, 0, 26, -6, 22, -6, 20, -12, 15, -19, 10, -10, 13, -14, 6, -43, -13, -43, -16, -9, -12, -10, -29, -42, -40, -37, -28, -5, -21, 1, -24, -8, -20, 4, -18, 26, -24, 44, -26, 66, -30, 86, -37, 88, -41, 72, -46, 50, -31, 28, 23, 14, 64, 16, 51, 26, 32, 34, 39, 42, 48, 35, 58, 0, 72, -36, 69, -59, 58, -98, 54, -124, 36, -103, 12, -110, 5, -173, -19, -146, -59, -4, -42, 51, 1, -23, -6, -30, -6, 45, 46, 47, 70, 6, 55, 19, 60, 38, 62, 42, 47, 61, 46, 40, 42, -19, 22, -34, 6, -35, -50, -61, -141, -37, -171, 17, -163, 26, -180, 46, -154, 80, -63, 48, -4, 18, 20, 50, 47, 58, 53, 44, 61, 57, 85, 37, 80, 0, 86, -8, 106, -95, 49, -213, -8, -131, 47, 49, 63, 40, -39, -69, -74, -37, -20, 63, -12, 58, -14, -12, 25, -31, 41, 11, 45, 76, 47, 167, 5, 261, -37, 277, -83, 183, -172, 35, -122, -79, 138, -70, 266, 69, 124, 228, 0, 391, -29, 594, -84, 702, -78, 627, -8, 551, -13, 509, 13, 372, 120, 352, 125, 622, 127, 691, 223, 362, 126, 386, -33, 915, 198, 958, 457, 456, 298, 500, 233, 1027, 469, 1096, 426, 918, 160, 1067, 141, 1220, 189, 1245, 164, 1375, 297, 1378, 503, 1299, 702, 1550, 929, 1799, 855, 1752, 547, 1830, 602, 1928, 832, 1736, 796, 1735, 933, 1961, 1385, 1935, 1562, 2105, 1485, 2716, 1449, 2948, 1305, 2768, 1205, 2716, 1346, 2531, 1450, 2470, 1653, 3117, 2111, 3370, 2176, 2696, 1947, 2925, 2305, 3846, 2658, 2425, 2184, -877, 1981, -2261, 2623, -1645, 2908, -1876, 2732, -2704, 2953, -2484, 3116, -2120, 2954, -2442, 3216, -2466, 3499, -2192, 3234, -2392, 3361, -2497, 3869, -2078, 3772, -1858, 3915, -2066, 4438, -2285, 2934, -2294, -280, -2066, -1762, -1992, -1412, -2298, -1535, -2399, -1789, -2223, -1419, -2244, -1334, -2092, -1476, -1777, -1396, -2014, -1571, -2199, -1574, -1843, -1167, -1910, -1446, -2007, -1818]; fn main() { + #[cfg(increase_thread_usage)] + let thread = std::thread::spawn(|| 4); + for _ in 0..2 { mse(PCM.len(), PCM, EXPECTED); } diff --git a/bench-cargo-miri/mse_and_dangling_thread/Cargo.toml b/bench-cargo-miri/mse_and_dangling_thread/Cargo.toml deleted file mode 100644 index 7b4c2dc758fa..000000000000 --- a/bench-cargo-miri/mse_and_dangling_thread/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "mse" -version = "0.1.0" -authors = ["Ralf Jung "] -edition = "2018" - -[dependencies] diff --git a/bench-cargo-miri/mse_and_dangling_thread/src/main.rs b/bench-cargo-miri/mse_and_dangling_thread/src/main.rs deleted file mode 100644 index 008e9c80eff1..000000000000 --- a/bench-cargo-miri/mse_and_dangling_thread/src/main.rs +++ /dev/null @@ -1,30 +0,0 @@ -static EXPECTED: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 254, 255, 0, 0, 254, 255, 0, 0, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 255, 255, 1, 0, 255, 255, 1, 0, 0, 0, 1, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 0, 0, 254, 255, 0, 0, 254, 255, 0, 0, 254, 255, 255, 255, 254, 255, 254, 255, 254, 255, 253, 255, 253, 255, 253, 255, 253, 255, 252, 255, 254, 255, 251, 255, 254, 255, 251, 255, 254, 255, 252, 255, 255, 255, 252, 255, 0, 0, 252, 255, 0, 0, 252, 255, 1, 0, 252, 255, 1, 0, 252, 255, 2, 0, 252, 255, 2, 0, 252, 255, 2, 0, 252, 255, 2, 0, 252, 255, 2, 0, 253, 255, 1, 0, 252, 255, 0, 0, 252, 255, 255, 255, 251, 255, 0, 0, 251, 255, 0, 0, 251, 255, 0, 0, 252, 255, 2, 0, 252, 255, 3, 0, 252, 255, 4, 0, 253, 255, 5, 0, 254, 255, 5, 0, 253, 255, 6, 0, 253, 255, 6, 0, 253, 255, 5, 0, 253, 255, 5, 0, 254, 255, 4, 0, 254, 255, 3, 0, 251, 255, 0, 0, 250, 255, 255, 255, 253, 255, 254, 255, 252, 255, 252, 255, 247, 255, 251, 255, 247, 255, 252, 255, 252, 255, 254, 255, 252, 255, 254, 255, 252, 255, 255, 255, 254, 255, 1, 0, 1, 0, 1, 0, 4, 0, 2, 0, 8, 0, 2, 0, 12, 0, 1, 0, 13, 0, 0, 0, 12, 0, 0, 0, 11, 0, 255, 255, 8, 0, 254, 255, 7, 0, 0, 0, 7, 0, 253, 255, 11, 0, 248, 255, 15, 0, 247, 255, 17, 0, 250, 255, 17, 0, 251, 255, 13, 0, 253, 255, 7, 0, 255, 255, 3, 0, 255, 255, 254, 255, 255, 255, 252, 255, 255, 255, 252, 255, 254, 255, 250, 255, 255, 255, 242, 255, 254, 255, 239, 255, 252, 255, 248, 255, 255, 255, 249, 255, 5, 0, 239, 255, 7, 0, 238, 255, 10, 0, 249, 255, 18, 0, 254, 255, 25, 0, 253, 255, 27, 0, 0, 0, 31, 0, 4, 0, 34, 0, 4, 0, 34, 0, 8, 0, 36, 0, 8, 0, 37, 0, 2, 0, 36, 0, 4, 0, 34, 0, 8, 0, 28, 0, 3, 0, 15, 0, 255, 255, 11, 0, 0, 0, 12, 0, 251, 255, 8, 0, 252, 255, 10, 0, 0, 0, 23, 0, 252, 255, 31, 0, 248, 255, 30, 0, 254, 255, 30, 0, 255, 255, 26, 0, 250, 255, 22, 0, 250, 255, 20, 0, 244, 255, 15, 0, 237, 255, 10, 0, 246, 255, 13, 0, 242, 255, 6, 0, 213, 255, 243, 255, 213, 255, 240, 255, 247, 255, 244, 255, 246, 255, 227, 255, 214, 255, 216, 255, 219, 255, 228, 255, 251, 255, 235, 255, 1, 0, 232, 255, 248, 255, 236, 255, 4, 0, 238, 255, 26, 0, 232, 255, 44, 0, 230, 255, 66, 0, 226, 255, 86, 0, 219, 255, 88, 0, 215, 255, 72, 0, 210, 255, 50, 0, 225, 255, 28, 0, 23, 0, 14, 0, 64, 0, 16, 0, 51, 0, 26, 0, 32, 0, 34, 0, 39, 0, 42, 0, 48, 0, 35, 0, 58, 0, 255, 255, 72, 0, 220, 255, 69, 0, 197, 255, 58, 0, 158, 255, 54, 0, 132, 255, 36, 0, 153, 255, 12, 0, 146, 255, 5, 0, 83, 255, 237, 255, 110, 255, 197, 255, 252, 255, 214, 255, 51, 0, 1, 0, 233, 255, 250, 255, 226, 255, 250, 255, 45, 0, 46, 0, 47, 0, 70, 0, 6, 0, 55, 0, 19, 0, 60, 0, 38, 0, 62, 0, 42, 0, 47, 0, 61, 0, 46, 0, 40, 0, 42, 0, 237, 255, 22, 0, 222, 255, 6, 0, 221, 255, 206, 255, 195, 255, 115, 255, 219, 255, 85, 255, 17, 0, 93, 255, 26, 0, 76, 255, 46, 0, 102, 255, 80, 0, 193, 255, 48, 0, 252, 255, 18, 0, 20, 0, 50, 0, 47, 0, 58, 0, 53, 0, 44, 0, 61, 0, 57, 0, 85, 0, 37, 0, 80, 0, 0, 0, 86, 0, 248, 255, 106, 0, 161, 255, 49, 0, 43, 255, 248, 255, 125, 255, 47, 0, 49, 0, 63, 0, 40, 0, 217, 255, 187, 255, 182, 255, 219, 255, 236, 255, 63, 0, 244, 255, 58, 0, 242, 255, 244, 255, 25, 0, 225, 255, 41, 0, 11, 0, 45, 0, 76, 0, 47, 0, 167, 0, 5, 0, 5, 1, 219, 255, 21, 1, 173, 255, 183, 0, 84, 255, 35, 0, 134, 255, 177, 255, 138, 0, 186, 255, 10, 1, 69, 0, 124, 0, 228, 0, 0, 0, 135, 1, 227, 255, 82, 2, 172, 255, 190, 2, 178, 255, 115, 2, 248, 255, 39, 2, 243, 255, 253, 1, 13, 0, 116, 1, 120, 0, 96, 1, 125, 0, 110, 2, 127, 0, 179, 2, 223, 0, 106, 1, 126, 0, 130, 1, 223, 255, 147, 3, 198, 0, 190, 3, 201, 1, 200, 1, 42, 1, 244, 1, 233, 0, 3, 4, 213, 1, 72, 4, 170, 1, 150, 3, 160, 0, 43, 4, 141, 0, 196, 4, 189, 0, 221, 4, 164, 0, 95, 5, 41, 1, 98, 5, 247, 1, 19, 5, 190, 2, 14, 6, 161, 3, 7, 7, 87, 3, 216, 6, 35, 2, 38, 7, 90, 2, 136, 7, 64, 3, 200, 6, 28, 3, 199, 6, 165, 3, 169, 7, 105, 5, 143, 7, 26, 6, 57, 8, 205, 5, 156, 10, 169, 5, 132, 11, 25, 5, 208, 10, 181, 4, 156, 10, 66, 5, 227, 9, 170, 5, 166, 9, 117, 6, 45, 12, 63, 8, 42, 13, 128, 8, 136, 10, 155, 7, 109, 11, 1, 9, 6, 15, 98, 10, 121, 9, 136, 8, 147, 252, 189, 7, 43, 247, 63, 10, 147, 249, 92, 11, 172, 248, 172, 10, 112, 245, 137, 11, 76, 246, 44, 12, 184, 247, 138, 11, 118, 246, 144, 12, 94, 246, 171, 13, 112, 247, 162, 12, 168, 246, 33, 13, 63, 246, 29, 15, 226, 247, 188, 14, 190, 248, 75, 15, 238, 247, 86, 17, 19, 247, 118, 11, 10, 247, 232, 254, 238, 247, 30, 249, 56, 248, 124, 250, 6, 247, 1, 250, 161, 246, 3, 249, 81, 247, 117, 250, 60, 247, 202, 250, 212, 247, 60, 250, 15, 249, 140, 250, 34, 248, 221, 249, 105, 247, 218, 249, 205, 248, 113, 251, 138, 248, 90, 250, 41, 248, 230, 248]; -static PCM: &[i16] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1, 0, 1, 0, 0, -2, 0, -2, 0, -2, 0, -2, -2, -2, -3, -3, -3, -3, -4, -2, -5, -2, -5, -2, -4, 0, -4, 0, -4, 0, -4, 1, -4, 1, -4, 2, -4, 2, -4, 2, -4, 2, -4, 2, -3, 1, -4, 0, -4, 0, -5, 0, -5, 0, -5, 0, -4, 2, -4, 3, -4, 4, -3, 5, -2, 5, -3, 6, -3, 6, -3, 5, -3, 5, -2, 4, -2, 3, -5, 0, -6, 0, -3, -2, -4, -4, -9, -5, -9, -4, -4, -2, -4, -2, -4, 0, -2, 1, 1, 1, 4, 2, 8, 2, 12, 1, 13, 0, 12, 0, 11, 0, 8, -2, 7, 0, 7, -3, 11, -8, 15, -9, 17, -6, 17, -5, 13, -3, 7, 0, 3, 0, -2, 0, -4, 0, -4, -2, -6, 0, -14, -2, -17, -4, -8, 0, -7, 5, -17, 7, -18, 10, -7, 18, -2, 25, -3, 27, 0, 31, 4, 34, 4, 34, 8, 36, 8, 37, 2, 36, 4, 34, 8, 28, 3, 15, 0, 11, 0, 12, -5, 8, -4, 10, 0, 23, -4, 31, -8, 30, -2, 30, 0, 26, -6, 22, -6, 20, -12, 15, -19, 10, -10, 13, -14, 6, -43, -13, -43, -16, -9, -12, -10, -29, -42, -40, -37, -28, -5, -21, 1, -24, -8, -20, 4, -18, 26, -24, 44, -26, 66, -30, 86, -37, 88, -41, 72, -46, 50, -31, 28, 23, 14, 64, 16, 51, 26, 32, 34, 39, 42, 48, 35, 58, 0, 72, -36, 69, -59, 58, -98, 54, -124, 36, -103, 12, -110, 5, -173, -19, -146, -59, -4, -42, 51, 1, -23, -6, -30, -6, 45, 46, 47, 70, 6, 55, 19, 60, 38, 62, 42, 47, 61, 46, 40, 42, -19, 22, -34, 6, -35, -50, -61, -141, -37, -171, 17, -163, 26, -180, 46, -154, 80, -63, 48, -4, 18, 20, 50, 47, 58, 53, 44, 61, 57, 85, 37, 80, 0, 86, -8, 106, -95, 49, -213, -8, -131, 47, 49, 63, 40, -39, -69, -74, -37, -20, 63, -12, 58, -14, -12, 25, -31, 41, 11, 45, 76, 47, 167, 5, 261, -37, 277, -83, 183, -172, 35, -122, -79, 138, -70, 266, 69, 124, 228, 0, 391, -29, 594, -84, 702, -78, 627, -8, 551, -13, 509, 13, 372, 120, 352, 125, 622, 127, 691, 223, 362, 126, 386, -33, 915, 198, 958, 457, 456, 298, 500, 233, 1027, 469, 1096, 426, 918, 160, 1067, 141, 1220, 189, 1245, 164, 1375, 297, 1378, 503, 1299, 702, 1550, 929, 1799, 855, 1752, 547, 1830, 602, 1928, 832, 1736, 796, 1735, 933, 1961, 1385, 1935, 1562, 2105, 1485, 2716, 1449, 2948, 1305, 2768, 1205, 2716, 1346, 2531, 1450, 2470, 1653, 3117, 2111, 3370, 2176, 2696, 1947, 2925, 2305, 3846, 2658, 2425, 2184, -877, 1981, -2261, 2623, -1645, 2908, -1876, 2732, -2704, 2953, -2484, 3116, -2120, 2954, -2442, 3216, -2466, 3499, -2192, 3234, -2392, 3361, -2497, 3869, -2078, 3772, -1858, 3915, -2066, 4438, -2285, 2934, -2294, -280, -2066, -1762, -1992, -1412, -2298, -1535, -2399, -1789, -2223, -1419, -2244, -1334, -2092, -1476, -1777, -1396, -2014, -1571, -2199, -1574, -1843, -1167, -1910, -1446, -2007, -1818]; - -fn main() { - let thread = std::thread::spawn(|| 4); - for _ in 0..2 { - mse(PCM.len(), PCM, EXPECTED); - } - assert_eq!(4, thread.join().unwrap()); -} - -fn read_i16(buffer: &[u8], index: usize) -> i16 { - const SIZE: usize = std::mem::size_of::(); - let mut bytes: [u8; SIZE] = [0u8; SIZE]; - bytes.copy_from_slice(&buffer[(index * SIZE)..(index * SIZE + SIZE)]); - unsafe { std::mem::transmute(bytes) } -} - -fn mse(samples: usize, frame_buf: &[i16], buf_ref: &[u8]) -> f64 { - let mut mse = 0.0; - let max_samples = std::cmp::min(buf_ref.len() / 2, samples as usize); - for i in 0..max_samples { - let ref_res = read_i16(buf_ref, i); - let info_res = frame_buf[i as usize]; - let diff = (ref_res - info_res).abs(); - mse += f64::from(diff.pow(2)); - } - mse / max_samples as f64 -} - From a3b7839bbdde0c5856720dc885250752aefd4207 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Sun, 15 Nov 2020 20:12:58 +0000 Subject: [PATCH 2447/5092] Add comment regarding seq-cst ordering & add test for disabling the data-race detector. --- src/data_race.rs | 11 ++++++++ .../concurrency/disable_data_race_detector.rs | 28 +++++++++++++++++++ .../disable_data_race_detector.stderr | 2 ++ 3 files changed, 41 insertions(+) create mode 100644 tests/run-pass/concurrency/disable_data_race_detector.rs create mode 100644 tests/run-pass/concurrency/disable_data_race_detector.stderr diff --git a/src/data_race.rs b/src/data_race.rs index 822ceab8fa04..bad757bc70e5 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -27,6 +27,16 @@ //! from acquire/release operations. If weak memory orderings are explored then this //! may need to change or be updated accordingly. //! +//! Per the C++ spec for the memory model a sequentially consistent operation: +//! "A load operation with this memory order performs an acquire operation, +//! a store performs a release operation, and read-modify-write performs +//! both an acquire operation and a release operation, plus a single total +//! order exists in which all threads observe all modifications in the same +//! order (see Sequentially-consistent ordering below) " +//! So in the absence of weak memory effects a seq-cst load & a seq-cst store is identical +//! to a acquire load and a release store given the global sequentially consistent order +//! of the schedule. +//! //! FIXME: //! currently we have our own local copy of the currently active thread index and names, this is due //! in part to the inability to access the current location of threads.active_thread inside the AllocExtra @@ -196,6 +206,7 @@ struct MemoryCellClocks { /// The vector-clock of the timestamp of the last read operation /// performed by a thread since the last write operation occured. + /// It is reset to zero on each write operation. read: VClock, /// Atomic acquire & release sequence tracking clocks. diff --git a/tests/run-pass/concurrency/disable_data_race_detector.rs b/tests/run-pass/concurrency/disable_data_race_detector.rs new file mode 100644 index 000000000000..e47a2079c205 --- /dev/null +++ b/tests/run-pass/concurrency/disable_data_race_detector.rs @@ -0,0 +1,28 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-data-race-detector + +use std::thread::spawn; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + let mut a = 0u32; + let b = &mut a as *mut u32; + let c = EvilSend(b); + unsafe { + let j1 = spawn(move || { + *c.0 = 32; + }); + + let j2 = spawn(move || { + *c.0 = 64; //~ ERROR Data race + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/run-pass/concurrency/disable_data_race_detector.stderr b/tests/run-pass/concurrency/disable_data_race_detector.stderr new file mode 100644 index 000000000000..7ba8087a9b4b --- /dev/null +++ b/tests/run-pass/concurrency/disable_data_race_detector.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental, no weak memory effects are currently emulated. + From 0b0264fc820d12d6c5e6f9f702bc33e8921bb110 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Sun, 15 Nov 2020 20:19:34 +0000 Subject: [PATCH 2448/5092] Run rustfmt on vector_clock.rs and data_race.rs --- src/data_race.rs | 431 ++++++++++++++++++++++++-------------------- src/vector_clock.rs | 235 +++++++++++++----------- 2 files changed, 357 insertions(+), 309 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index bad757bc70e5..b9542f6e2d62 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -11,7 +11,7 @@ //! a data race occurs between two memory accesses if they are on different threads, at least one operation //! is non-atomic, at least one operation is a write and neither access happens-before the other. Read the link //! for full definition. -//! +//! //! This re-uses vector indexes for threads that are known to be unable to report data-races, this is valid //! because it only re-uses vector indexes once all currently-active (not-terminated) threads have an internal //! vector clock that happens-after the join operation of the candidate thread. Threads that have not been joined @@ -43,21 +43,21 @@ //! read, write and deallocate functions and should be cleaned up in the future. use std::{ - fmt::Debug, rc::Rc, - cell::{Cell, RefCell, Ref, RefMut}, mem + cell::{Cell, Ref, RefCell, RefMut}, + fmt::Debug, + mem, + rc::Rc, }; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::vec::{Idx, IndexVec}; -use rustc_target::abi::Size; use rustc_middle::{mir, ty::layout::TyAndLayout}; -use rustc_data_structures::fx::{FxHashSet, FxHashMap}; +use rustc_target::abi::Size; use crate::{ - MiriEvalContext, MiriEvalContextExt, - ThreadId, Tag, RangeMap, - InterpResult, Pointer, ScalarMaybeUninit, - MPlaceTy, OpTy, MemPlaceMeta, ImmTy, Immediate, - VClock, VSmallClockMap, VectorIdx, VTimestamp + ImmTy, Immediate, InterpResult, MPlaceTy, MemPlaceMeta, MiriEvalContext, MiriEvalContextExt, + OpTy, Pointer, RangeMap, ScalarMaybeUninit, Tag, ThreadId, VClock, VSmallClockMap, VTimestamp, + VectorIdx, }; pub type AllocExtra = VClockAlloc; @@ -89,7 +89,6 @@ pub enum AtomicWriteOp { SeqCst, } - /// Valid atomic fence operations, subset of atomic::Ordering. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum AtomicFenceOp { @@ -99,14 +98,11 @@ pub enum AtomicFenceOp { SeqCst, } - - /// The current set of vector clocks describing the state /// of a thread, contains the happens-before clock and /// additional metadata to model atomic fence operations. #[derive(Clone, Default, Debug)] struct ThreadClockSet { - /// The increasing clock representing timestamps /// that happen-before this thread. clock: VClock, @@ -120,9 +116,7 @@ struct ThreadClockSet { fence_release: VClock, } - impl ThreadClockSet { - /// Apply the effects of a release fence to this /// set of thread vector clocks. #[inline] @@ -152,7 +146,6 @@ impl ThreadClockSet { } } - /// Error returned by finding a data race /// should be elaborated upon. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] @@ -164,7 +157,6 @@ pub struct DataRace; /// exists on the memory cell. #[derive(Clone, PartialEq, Eq, Default, Debug)] struct AtomicMemoryCellClocks { - /// The clock-vector of the timestamp of the last atomic /// read operation performed by each thread. /// This detects potential data-races between atomic read @@ -179,7 +171,7 @@ struct AtomicMemoryCellClocks { /// Synchronization vector for acquire-release semantics /// contains the vector of timestamps that will - /// happen-before a thread if an acquire-load is + /// happen-before a thread if an acquire-load is /// performed on the data. sync_vector: VClock, @@ -195,7 +187,6 @@ struct AtomicMemoryCellClocks { /// for data-race detection. #[derive(Clone, PartialEq, Eq, Debug)] struct MemoryCellClocks { - /// The vector-clock timestamp of the last write /// corresponding to the writing threads timestamp. write: VTimestamp, @@ -215,7 +206,6 @@ struct MemoryCellClocks { atomic_ops: Option>, } - /// Create a default memory cell clocks instance /// for uninitialized memory. impl Default for MemoryCellClocks { @@ -224,20 +214,18 @@ impl Default for MemoryCellClocks { read: VClock::default(), write: 0, write_index: VectorIdx::MAX_INDEX, - atomic_ops: None + atomic_ops: None, } } } - impl MemoryCellClocks { - /// Load the internal atomic memory cells if they exist. #[inline] fn atomic(&self) -> Option<&AtomicMemoryCellClocks> { match &self.atomic_ops { Some(op) => Some(&*op), - None => None + None => None, } } @@ -251,7 +239,11 @@ impl MemoryCellClocks { /// Update memory cell data-race tracking for atomic /// load acquire semantics, is a no-op if this memory was /// not used previously as atomic memory. - fn load_acquire(&mut self, clocks: &mut ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { + fn load_acquire( + &mut self, + clocks: &mut ThreadClockSet, + index: VectorIdx, + ) -> Result<(), DataRace> { self.atomic_read_detect(clocks, index)?; if let Some(atomic) = self.atomic() { clocks.clock.join(&atomic.sync_vector); @@ -262,7 +254,11 @@ impl MemoryCellClocks { /// Update memory cell data-race tracking for atomic /// load relaxed semantics, is a no-op if this memory was /// not used previously as atomic memory. - fn load_relaxed(&mut self, clocks: &mut ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { + fn load_relaxed( + &mut self, + clocks: &mut ThreadClockSet, + index: VectorIdx, + ) -> Result<(), DataRace> { self.atomic_read_detect(clocks, index)?; if let Some(atomic) = self.atomic() { clocks.fence_acquire.join(&atomic.sync_vector); @@ -270,7 +266,6 @@ impl MemoryCellClocks { Ok(()) } - /// Update the memory cell data-race tracking for atomic /// store release semantics. fn store_release(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { @@ -313,10 +308,14 @@ impl MemoryCellClocks { atomic.sync_vector.join(&clocks.fence_release); Ok(()) } - + /// Detect data-races with an atomic read, caused by a non-atomic write that does /// not happen-before the atomic-read. - fn atomic_read_detect(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { + fn atomic_read_detect( + &mut self, + clocks: &ThreadClockSet, + index: VectorIdx, + ) -> Result<(), DataRace> { log::trace!("Atomic read with vectors: {:#?} :: {:#?}", self, clocks); if self.write <= clocks.clock[self.write_index] { let atomic = self.atomic_mut(); @@ -329,7 +328,11 @@ impl MemoryCellClocks { /// Detect data-races with an atomic write, either with a non-atomic read or with /// a non-atomic write. - fn atomic_write_detect(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { + fn atomic_write_detect( + &mut self, + clocks: &ThreadClockSet, + index: VectorIdx, + ) -> Result<(), DataRace> { log::trace!("Atomic write with vectors: {:#?} :: {:#?}", self, clocks); if self.write <= clocks.clock[self.write_index] && self.read <= clocks.clock { let atomic = self.atomic_mut(); @@ -342,7 +345,11 @@ impl MemoryCellClocks { /// Detect races for non-atomic read operations at the current memory cell /// returns true if a data-race is detected. - fn read_race_detect(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { + fn read_race_detect( + &mut self, + clocks: &ThreadClockSet, + index: VectorIdx, + ) -> Result<(), DataRace> { log::trace!("Unsynchronized read with vectors: {:#?} :: {:#?}", self, clocks); if self.write <= clocks.clock[self.write_index] { let race_free = if let Some(atomic) = self.atomic() { @@ -363,7 +370,11 @@ impl MemoryCellClocks { /// Detect races for non-atomic write operations at the current memory cell /// returns true if a data-race is detected. - fn write_race_detect(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { + fn write_race_detect( + &mut self, + clocks: &ThreadClockSet, + index: VectorIdx, + ) -> Result<(), DataRace> { log::trace!("Unsynchronized write with vectors: {:#?} :: {:#?}", self, clocks); if self.write <= clocks.clock[self.write_index] && self.read <= clocks.clock { let race_free = if let Some(atomic) = self.atomic() { @@ -385,18 +396,16 @@ impl MemoryCellClocks { } } - /// Evaluation context extensions. impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { - /// Atomic variant of read_scalar_at_offset. fn read_scalar_at_offset_atomic( &self, op: OpTy<'tcx, Tag>, offset: u64, layout: TyAndLayout<'tcx>, - atomic: AtomicReadOp + atomic: AtomicReadOp, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_ref(); let op_place = this.deref_operand(op)?; @@ -415,7 +424,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { offset: u64, value: impl Into>, layout: TyAndLayout<'tcx>, - atomic: AtomicWriteOp + atomic: AtomicWriteOp, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let op_place = this.deref_operand(op)?; @@ -429,46 +438,45 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// Perform an atomic read operation at the memory location. fn read_scalar_atomic( - &self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicReadOp + &self, + place: MPlaceTy<'tcx, Tag>, + atomic: AtomicReadOp, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_ref(); - let scalar = this.allow_data_races_ref(move |this| { - this.read_scalar(place.into()) - })?; + let scalar = this.allow_data_races_ref(move |this| this.read_scalar(place.into()))?; self.validate_atomic_load(place, atomic)?; Ok(scalar) } /// Perform an atomic write operation at the memory location. fn write_scalar_atomic( - &mut self, val: ScalarMaybeUninit, dest: MPlaceTy<'tcx, Tag>, - atomic: AtomicWriteOp + &mut self, + val: ScalarMaybeUninit, + dest: MPlaceTy<'tcx, Tag>, + atomic: AtomicWriteOp, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.allow_data_races_mut(move |this| { - this.write_scalar(val, dest.into()) - })?; + this.allow_data_races_mut(move |this| this.write_scalar(val, dest.into()))?; self.validate_atomic_store(dest, atomic) } /// Perform a atomic operation on a memory location. fn atomic_op_immediate( &mut self, - place: MPlaceTy<'tcx, Tag>, rhs: ImmTy<'tcx, Tag>, - op: mir::BinOp, neg: bool, atomic: AtomicRwOp + place: MPlaceTy<'tcx, Tag>, + rhs: ImmTy<'tcx, Tag>, + op: mir::BinOp, + neg: bool, + atomic: AtomicRwOp, ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let this = self.eval_context_mut(); - let old = this.allow_data_races_mut(|this| { - this.read_immediate(place. into()) - })?; + let old = this.allow_data_races_mut(|this| this.read_immediate(place.into()))?; // Atomics wrap around on overflow. let val = this.binary_op(op, old, rhs)?; let val = if neg { this.unary_op(mir::UnOp::Not, val)? } else { val }; - this.allow_data_races_mut(|this| { - this.write_immediate(*val, place.into()) - })?; + this.allow_data_races_mut(|this| this.write_immediate(*val, place.into()))?; this.validate_atomic_rmw(place, atomic)?; Ok(old) @@ -478,17 +486,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// scalar value, the old value is returned. fn atomic_exchange_scalar( &mut self, - place: MPlaceTy<'tcx, Tag>, new: ScalarMaybeUninit, - atomic: AtomicRwOp + place: MPlaceTy<'tcx, Tag>, + new: ScalarMaybeUninit, + atomic: AtomicRwOp, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_mut(); - let old = this.allow_data_races_mut(|this| { - this.read_scalar(place.into()) - })?; - this.allow_data_races_mut(|this| { - this.write_scalar(new, place.into()) - })?; + let old = this.allow_data_races_mut(|this| this.read_scalar(place.into()))?; + this.allow_data_races_mut(|this| this.write_scalar(new, place.into()))?; this.validate_atomic_rmw(place, atomic)?; Ok(old) } @@ -497,9 +502,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// on success an atomic RMW operation is performed and on failure /// only an atomic read occurs. fn atomic_compare_exchange_scalar( - &mut self, place: MPlaceTy<'tcx, Tag>, - expect_old: ImmTy<'tcx, Tag>, new: ScalarMaybeUninit, - success: AtomicRwOp, fail: AtomicReadOp + &mut self, + place: MPlaceTy<'tcx, Tag>, + expect_old: ImmTy<'tcx, Tag>, + new: ScalarMaybeUninit, + success: AtomicRwOp, + fail: AtomicReadOp, ) -> InterpResult<'tcx, Immediate> { let this = self.eval_context_mut(); @@ -507,9 +515,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // to read with the failure ordering and if successfull then try again with the success // read ordering and write in the success case. // Read as immediate for the sake of `binary_op()` - let old = this.allow_data_races_mut(|this| { - this.read_immediate(place.into()) - })?; + let old = this.allow_data_races_mut(|this| this.read_immediate(place.into()))?; // `binary_op` will bail if either of them is not a scalar. let eq = this.overflowing_binary_op(mir::BinOp::Eq, old, expect_old)?.0; @@ -519,9 +525,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // if successful, perform a full rw-atomic validation // otherwise treat this as an atomic load with the fail ordering. if eq.to_bool()? { - this.allow_data_races_mut(|this| { - this.write_scalar(new, place.into()) - })?; + this.allow_data_races_mut(|this| this.write_scalar(new, place.into()))?; this.validate_atomic_rmw(place, success)?; } else { this.validate_atomic_load(place, fail)?; @@ -530,68 +534,74 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // Return the old value. Ok(res) } - - + /// Update the data-race detector for an atomic read occuring at the /// associated memory-place and on the current thread. fn validate_atomic_load( - &self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicReadOp + &self, + place: MPlaceTy<'tcx, Tag>, + atomic: AtomicReadOp, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); this.validate_atomic_op( - place, atomic, "Atomic Load", + place, + atomic, + "Atomic Load", move |memory, clocks, index, atomic| { if atomic == AtomicReadOp::Relaxed { memory.load_relaxed(&mut *clocks, index) } else { memory.load_acquire(&mut *clocks, index) } - } + }, ) } /// Update the data-race detector for an atomic write occuring at the /// associated memory-place and on the current thread. fn validate_atomic_store( - &mut self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicWriteOp + &mut self, + place: MPlaceTy<'tcx, Tag>, + atomic: AtomicWriteOp, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); this.validate_atomic_op( - place, atomic, "Atomic Store", + place, + atomic, + "Atomic Store", move |memory, clocks, index, atomic| { if atomic == AtomicWriteOp::Relaxed { memory.store_relaxed(clocks, index) } else { memory.store_release(clocks, index) } - } + }, ) } /// Update the data-race detector for an atomic read-modify-write occuring /// at the associated memory place and on the current thread. fn validate_atomic_rmw( - &mut self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicRwOp + &mut self, + place: MPlaceTy<'tcx, Tag>, + atomic: AtomicRwOp, ) -> InterpResult<'tcx> { use AtomicRwOp::*; let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); let release = matches!(atomic, Release | AcqRel | SeqCst); let this = self.eval_context_ref(); - this.validate_atomic_op( - place, atomic, "Atomic RMW", - move |memory, clocks, index, _| { - if acquire { - memory.load_acquire(clocks, index)?; - } else { - memory.load_relaxed(clocks, index)?; - } - if release { - memory.rmw_release(clocks, index) - } else { - memory.rmw_relaxed(clocks, index) - } + this.validate_atomic_op(place, atomic, "Atomic RMW", move |memory, clocks, index, _| { + if acquire { + memory.load_acquire(clocks, index)?; + } else { + memory.load_relaxed(clocks, index)?; } - ) + if release { + memory.rmw_release(clocks, index) + } else { + memory.rmw_relaxed(clocks, index) + } + }) } /// Update the data-race detector for an atomic fence on the current thread. @@ -620,12 +630,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { } } - - /// Vector clock metadata for a logical memory allocation. #[derive(Debug, Clone)] pub struct VClockAlloc { - /// Range of Vector clocks, this gives each byte a potentially /// unqiue set of vector clocks, but merges identical information /// together for improved efficiency. @@ -635,16 +642,12 @@ pub struct VClockAlloc { global: MemoryExtra, } - impl VClockAlloc { - /// Create a new data-race allocation detector. pub fn new_allocation(global: &MemoryExtra, len: Size) -> VClockAlloc { VClockAlloc { global: Rc::clone(global), - alloc_ranges: RefCell::new( - RangeMap::new(len, MemoryCellClocks::default()) - ) + alloc_ranges: RefCell::new(RangeMap::new(len, MemoryCellClocks::default())), } } @@ -653,27 +656,29 @@ impl VClockAlloc { fn find_gt_index(l: &VClock, r: &VClock) -> Option { let l_slice = l.as_slice(); let r_slice = r.as_slice(); - l_slice.iter().zip(r_slice.iter()) + l_slice + .iter() + .zip(r_slice.iter()) .enumerate() - .find_map(|(idx, (&l, &r))| { - if l > r { Some(idx) } else { None } - }).or_else(|| { + .find_map(|(idx, (&l, &r))| if l > r { Some(idx) } else { None }) + .or_else(|| { if l_slice.len() > r_slice.len() { - // By invariant, if l_slice is longer // then one element must be larger. // This just validates that this is true // and reports earlier elements first. let l_remainder_slice = &l_slice[r_slice.len()..]; - let idx = l_remainder_slice.iter().enumerate() - .find_map(|(idx, &r)| { - if r == 0 { None } else { Some(idx) } - }).expect("Invalid VClock Invariant"); + let idx = l_remainder_slice + .iter() + .enumerate() + .find_map(|(idx, &r)| if r == 0 { None } else { Some(idx) }) + .expect("Invalid VClock Invariant"); Some(idx) } else { None } - }).map(|idx| VectorIdx::new(idx)) + }) + .map(|idx| VectorIdx::new(idx)) } /// Report a data-race found in the program. @@ -684,39 +689,42 @@ impl VClockAlloc { #[cold] #[inline(never)] fn report_data_race<'tcx>( - global: &MemoryExtra, range: &MemoryCellClocks, - action: &str, is_atomic: bool, - pointer: Pointer, len: Size + global: &MemoryExtra, + range: &MemoryCellClocks, + action: &str, + is_atomic: bool, + pointer: Pointer, + len: Size, ) -> InterpResult<'tcx> { let (current_index, current_clocks) = global.current_thread_state(); let write_clock; - let ( - other_action, other_thread, other_clock - ) = if range.write > current_clocks.clock[range.write_index] { - + let (other_action, other_thread, other_clock) = if range.write + > current_clocks.clock[range.write_index] + { // Convert the write action into the vector clock it // represents for diagnostic purposes. write_clock = VClock::new_with_index(range.write_index, range.write); ("WRITE", range.write_index, &write_clock) - } else if let Some(idx) = Self::find_gt_index( - &range.read, ¤t_clocks.clock - ){ + } else if let Some(idx) = Self::find_gt_index(&range.read, ¤t_clocks.clock) { ("READ", idx, &range.read) } else if !is_atomic { if let Some(atomic) = range.atomic() { - if let Some(idx) = Self::find_gt_index( - &atomic.write_vector, ¤t_clocks.clock - ) { + if let Some(idx) = Self::find_gt_index(&atomic.write_vector, ¤t_clocks.clock) + { ("ATOMIC_STORE", idx, &atomic.write_vector) - } else if let Some(idx) = Self::find_gt_index( - &atomic.read_vector, ¤t_clocks.clock - ) { + } else if let Some(idx) = + Self::find_gt_index(&atomic.read_vector, ¤t_clocks.clock) + { ("ATOMIC_LOAD", idx, &atomic.read_vector) } else { - unreachable!("Failed to report data-race for non-atomic operation: no race found") + unreachable!( + "Failed to report data-race for non-atomic operation: no race found" + ) } } else { - unreachable!("Failed to report data-race for non-atomic operation: no atomic component") + unreachable!( + "Failed to report data-race for non-atomic operation: no atomic component" + ) } } else { unreachable!("Failed to report data-race for atomic operation") @@ -725,15 +733,19 @@ impl VClockAlloc { // Load elaborated thread information about the racing thread actions. let current_thread_info = global.print_thread_metadata(current_index); let other_thread_info = global.print_thread_metadata(other_thread); - + // Throw the data-race detection. throw_ub_format!( "Data race detected between {} on {} and {} on {}, memory({:?},offset={},size={})\ \n\t\t -current vector clock = {:?}\ \n\t\t -conflicting timestamp = {:?}", - action, current_thread_info, - other_action, other_thread_info, - pointer.alloc_id, pointer.offset.bytes(), len.bytes(), + action, + current_thread_info, + other_action, + other_thread_info, + pointer.alloc_id, + pointer.offset.bytes(), + len.bytes(), current_clocks.clock, other_clock ) @@ -748,12 +760,16 @@ impl VClockAlloc { if self.global.multi_threaded.get() { let (index, clocks) = self.global.current_thread_state(); let mut alloc_ranges = self.alloc_ranges.borrow_mut(); - for (_,range) in alloc_ranges.iter_mut(pointer.offset, len) { + for (_, range) in alloc_ranges.iter_mut(pointer.offset, len) { if let Err(DataRace) = range.read_race_detect(&*clocks, index) { - // Report data-race. return Self::report_data_race( - &self.global,range, "READ", false, pointer, len + &self.global, + range, + "READ", + false, + pointer, + len, ); } } @@ -763,17 +779,25 @@ impl VClockAlloc { } } - // Shared code for detecting data-races on unique access to a section of memory - fn unique_access<'tcx>(&mut self, pointer: Pointer, len: Size, action: &str) -> InterpResult<'tcx> { + fn unique_access<'tcx>( + &mut self, + pointer: Pointer, + len: Size, + action: &str, + ) -> InterpResult<'tcx> { if self.global.multi_threaded.get() { let (index, clocks) = self.global.current_thread_state(); - for (_,range) in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { + for (_, range) in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { if let Err(DataRace) = range.write_race_detect(&*clocks, index) { - // Report data-race return Self::report_data_race( - &self.global, range, action, false, pointer, len + &self.global, + range, + action, + false, + pointer, + len, ); } } @@ -802,7 +826,6 @@ impl VClockAlloc { impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { - // Temporarily allow data-races to occur, this should only be // used if either one of the appropiate `validate_atomic` functions // will be called to treat a memory access as atomic or if the memory @@ -827,7 +850,10 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// so should only be used for atomic operations or internal state that the program cannot /// access. #[inline] - fn allow_data_races_mut(&mut self, op: impl FnOnce(&mut MiriEvalContext<'mir, 'tcx>) -> R) -> R { + fn allow_data_races_mut( + &mut self, + op: impl FnOnce(&mut MiriEvalContext<'mir, 'tcx>) -> R, + ) -> R { let this = self.eval_context_mut(); let old = if let Some(data_race) = &this.memory.extra.data_race { data_race.multi_threaded.replace(false) @@ -848,34 +874,49 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// FIXME: is this valid, or should get_raw_mut be used for /// atomic-stores/atomic-rmw? fn validate_atomic_op( - &self, place: MPlaceTy<'tcx, Tag>, - atomic: A, description: &str, + &self, + place: MPlaceTy<'tcx, Tag>, + atomic: A, + description: &str, mut op: impl FnMut( - &mut MemoryCellClocks, &mut ThreadClockSet, VectorIdx, A - ) -> Result<(), DataRace> + &mut MemoryCellClocks, + &mut ThreadClockSet, + VectorIdx, + A, + ) -> Result<(), DataRace>, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); if let Some(data_race) = &this.memory.extra.data_race { if data_race.multi_threaded.get() { - // Load and log the atomic operation. let place_ptr = place.ptr.assert_ptr(); let size = place.layout.size; - let alloc_meta = &this.memory.get_raw(place_ptr.alloc_id)?.extra.data_race.as_ref().unwrap(); + let alloc_meta = + &this.memory.get_raw(place_ptr.alloc_id)?.extra.data_race.as_ref().unwrap(); log::trace!( "Atomic op({}) with ordering {:?} on memory({:?}, offset={}, size={})", - description, &atomic, place_ptr.alloc_id, place_ptr.offset.bytes(), size.bytes() + description, + &atomic, + place_ptr.alloc_id, + place_ptr.offset.bytes(), + size.bytes() ); // Perform the atomic operation. let data_race = &alloc_meta.global; data_race.maybe_perform_sync_operation(|index, mut clocks| { - for (_,range) in alloc_meta.alloc_ranges.borrow_mut().iter_mut(place_ptr.offset, size) { + for (_, range) in + alloc_meta.alloc_ranges.borrow_mut().iter_mut(place_ptr.offset, size) + { if let Err(DataRace) = op(range, &mut *clocks, index, atomic) { mem::drop(clocks); return VClockAlloc::report_data_race( - &alloc_meta.global, range, description, true, - place_ptr, size + &alloc_meta.global, + range, + description, + true, + place_ptr, + size, ); } } @@ -884,10 +925,13 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // Log changes to atomic memory. if log::log_enabled!(log::Level::Trace) { - for (_,range) in alloc_meta.alloc_ranges.borrow().iter(place_ptr.offset, size) { + for (_, range) in alloc_meta.alloc_ranges.borrow().iter(place_ptr.offset, size) + { log::trace!( "Updated atomic memory({:?}, offset={}, size={}) to {:#?}", - place.ptr.assert_ptr().alloc_id, place_ptr.offset.bytes(), size.bytes(), + place.ptr.assert_ptr().alloc_id, + place_ptr.offset.bytes(), + size.bytes(), range.atomic_ops ); } @@ -896,14 +940,11 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { } Ok(()) } - } - /// Extra metadata associated with a thread. #[derive(Debug, Clone, Default)] struct ThreadExtraState { - /// The current vector index in use by the /// thread currently, this is set to None /// after the vector index has been re-used @@ -915,7 +956,7 @@ struct ThreadExtraState { /// diagnostics when reporting detected data /// races. thread_name: Option>, - + /// Thread termination vector clock, this /// is set on thread termination and is used /// for joining on threads since the vector_index @@ -928,7 +969,6 @@ struct ThreadExtraState { /// with each of the threads. #[derive(Debug, Clone)] pub struct GlobalState { - /// Set to true once the first additional /// thread has launched, due to the dependency /// between before and after a thread launch. @@ -966,7 +1006,7 @@ pub struct GlobalState { /// if the number of active threads reduces to 1 and then /// a join operation occures with the remaining main thread /// then multi-threaded execution may be disabled. - active_thread_count: Cell, + active_thread_count: Cell, /// This contains threads that have terminated, but not yet joined /// and so cannot become re-use candidates until a join operation @@ -977,7 +1017,6 @@ pub struct GlobalState { } impl GlobalState { - /// Create a new global state, setup with just thread-id=0 /// advanced to timestamp = 1. pub fn new() -> Self { @@ -989,7 +1028,7 @@ impl GlobalState { current_index: Cell::new(VectorIdx::new(0)), active_thread_count: Cell::new(1), reuse_candidates: RefCell::new(FxHashSet::default()), - terminated_threads: RefCell::new(FxHashMap::default()) + terminated_threads: RefCell::new(FxHashMap::default()), }; // Setup the main-thread since it is not explicitly created: @@ -997,17 +1036,15 @@ impl GlobalState { // the main-thread a name of "main". let index = global_state.vector_clocks.borrow_mut().push(ThreadClockSet::default()); global_state.vector_info.borrow_mut().push(ThreadId::new(0)); - global_state.thread_info.borrow_mut().push( - ThreadExtraState { - vector_index: Some(index), - thread_name: Some("main".to_string().into_boxed_str()), - termination_vector_clock: None - } - ); + global_state.thread_info.borrow_mut().push(ThreadExtraState { + vector_index: Some(index), + thread_name: Some("main".to_string().into_boxed_str()), + termination_vector_clock: None, + }); global_state } - + // Try to find vector index values that can potentially be re-used // by a new thread instead of a new vector index being created. fn find_vector_index_reuse_candidate(&self) -> Option { @@ -1015,10 +1052,9 @@ impl GlobalState { let vector_clocks = self.vector_clocks.borrow(); let vector_info = self.vector_info.borrow(); let terminated_threads = self.terminated_threads.borrow(); - for &candidate in reuse.iter() { + for &candidate in reuse.iter() { let target_timestamp = vector_clocks[candidate].clock[candidate]; if vector_clocks.iter_enumerated().all(|(clock_idx, clock)| { - // The thread happens before the clock, and hence cannot report // a data-race with this the candidate index. let no_data_race = clock.clock[candidate] >= target_timestamp; @@ -1026,20 +1062,19 @@ impl GlobalState { // The vector represents a thread that has terminated and hence cannot // report a data-race with the candidate index. let thread_id = vector_info[clock_idx]; - let vector_terminated = reuse.contains(&clock_idx) - || terminated_threads.contains_key(&thread_id); + let vector_terminated = + reuse.contains(&clock_idx) || terminated_threads.contains_key(&thread_id); // The vector index cannot report a race with the candidate index // and hence allows the candidate index to be re-used. no_data_race || vector_terminated }) { - // All vector clocks for each vector index are equal to // the target timestamp, and the thread is known to have // terminated, therefore this vector clock index cannot // report any more data-races. assert!(reuse.remove(&candidate)); - return Some(candidate) + return Some(candidate); } } None @@ -1065,10 +1100,7 @@ impl GlobalState { // Assign a vector index for the thread, attempting to re-use an old // vector index that can no longer report any data-races if possible. - let created_index = if let Some( - reuse_index - ) = self.find_vector_index_reuse_candidate() { - + let created_index = if let Some(reuse_index) = self.find_vector_index_reuse_candidate() { // Now re-configure the re-use candidate, increment the clock // for the new sync use of the vector. let mut vector_clocks = self.vector_clocks.borrow_mut(); @@ -1086,7 +1118,6 @@ impl GlobalState { reuse_index } else { - // No vector re-use candidates available, instead create // a new vector index. let mut vector_info = self.vector_info.borrow_mut(); @@ -1125,13 +1156,16 @@ impl GlobalState { let thread_info = self.thread_info.borrow(); // Load the vector clock of the current thread. - let current_index = thread_info[current_thread].vector_index + let current_index = thread_info[current_thread] + .vector_index .expect("Performed thread join on thread with no assigned vector"); let current = &mut clocks_vec[current_index]; // Load the associated vector clock for the terminated thread. - let join_clock = thread_info[join_thread].termination_vector_clock - .as_ref().expect("Joined with thread but thread has not terminated"); + let join_clock = thread_info[join_thread] + .termination_vector_clock + .as_ref() + .expect("Joined with thread but thread has not terminated"); // Pre increment clocks before atomic operation. current.increment_clock(current_index); @@ -1147,13 +1181,12 @@ impl GlobalState { // then test for potentially disabling multi-threaded execution. let active_threads = self.active_thread_count.get(); if active_threads == 1 { - // May potentially be able to disable multi-threaded execution. let current_clock = &clocks_vec[current_index]; - if clocks_vec.iter_enumerated().all(|(idx, clocks)| { - clocks.clock[idx] <= current_clock.clock[idx] - }) { - + if clocks_vec + .iter_enumerated() + .all(|(idx, clocks)| clocks.clock[idx] <= current_clock.clock[idx]) + { // The all thread termations happen-before the current clock // therefore no data-races can be reported until a new thread // is created, so disable multi-threaded execution. @@ -1180,7 +1213,7 @@ impl GlobalState { #[inline] pub fn thread_terminated(&self) { let current_index = self.current_index(); - + // Increment the clock to a unique termination timestamp. let mut vector_clocks = self.vector_clocks.borrow_mut(); let current_clocks = &mut vector_clocks[current_index]; @@ -1201,7 +1234,7 @@ impl GlobalState { // occurs. let mut termination = self.terminated_threads.borrow_mut(); termination.insert(current_thread, current_index); - + // Reduce the number of active threads, now that a thread has // terminated. let mut active_threads = self.active_thread_count.get(); @@ -1215,7 +1248,8 @@ impl GlobalState { #[inline] pub fn thread_set_active(&self, thread: ThreadId) { let thread_info = self.thread_info.borrow(); - let vector_idx = thread_info[thread].vector_index + let vector_idx = thread_info[thread] + .vector_index .expect("Setting thread active with no assigned vector"); self.current_index.set(vector_idx); } @@ -1231,7 +1265,6 @@ impl GlobalState { thread_info[thread].thread_name = Some(name); } - /// Attempt to perform a synchronized operation, this /// will perform no operation if multi-threading is /// not currently enabled. @@ -1240,7 +1273,8 @@ impl GlobalState { /// detection between any happens-before edges the /// operation may create. fn maybe_perform_sync_operation<'tcx>( - &self, op: impl FnOnce(VectorIdx, RefMut<'_,ThreadClockSet>) -> InterpResult<'tcx>, + &self, + op: impl FnOnce(VectorIdx, RefMut<'_, ThreadClockSet>) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { if self.multi_threaded.get() { let (index, mut clocks) = self.current_thread_state_mut(); @@ -1251,7 +1285,6 @@ impl GlobalState { } Ok(()) } - /// Internal utility to identify a thread stored internally /// returns the id and the name for better diagnostics. @@ -1266,7 +1299,6 @@ impl GlobalState { } } - /// Acquire a lock, express that the previous call of /// `validate_lock_release` must happen before this. pub fn validate_lock_acquire(&self, lock: &VClock, thread: ThreadId) { @@ -1300,7 +1332,8 @@ impl GlobalState { /// used by the thread. #[inline] fn load_thread_state_mut(&self, thread: ThreadId) -> (VectorIdx, RefMut<'_, ThreadClockSet>) { - let index = self.thread_info.borrow()[thread].vector_index + let index = self.thread_info.borrow()[thread] + .vector_index .expect("Loading thread state for thread with no assigned vector"); let ref_vector = self.vector_clocks.borrow_mut(); let clocks = RefMut::map(ref_vector, |vec| &mut vec[index]); diff --git a/src/vector_clock.rs b/src/vector_clock.rs index 110b278852d5..ddee98bcf624 100644 --- a/src/vector_clock.rs +++ b/src/vector_clock.rs @@ -1,10 +1,13 @@ -use std::{ - fmt::{self, Debug}, cmp::Ordering, ops::Index, - convert::TryFrom, mem -}; -use smallvec::SmallVec; -use rustc_index::vec::Idx; use rustc_data_structures::fx::FxHashMap; +use rustc_index::vec::Idx; +use smallvec::SmallVec; +use std::{ + cmp::Ordering, + convert::TryFrom, + fmt::{self, Debug}, + mem, + ops::Index, +}; /// A vector clock index, this is associated with a thread id /// but in some cases one vector index may be shared with @@ -13,18 +16,15 @@ use rustc_data_structures::fx::FxHashMap; pub struct VectorIdx(u32); impl VectorIdx { - #[inline(always)] pub fn to_u32(self) -> u32 { self.0 } pub const MAX_INDEX: VectorIdx = VectorIdx(u32::MAX); - } impl Idx for VectorIdx { - #[inline] fn new(idx: usize) -> Self { VectorIdx(u32::try_from(idx).unwrap()) @@ -34,16 +34,13 @@ impl Idx for VectorIdx { fn index(self) -> usize { usize::try_from(self.0).unwrap() } - } impl From for VectorIdx { - #[inline] fn from(id: u32) -> Self { Self(id) } - } /// A sparse mapping of vector index values to vector clocks, this @@ -52,7 +49,7 @@ impl From for VectorIdx { /// This is used to store the set of currently active release /// sequences at a given memory location, since RMW operations /// allow for multiple release sequences to be active at once -/// and to be collapsed back to one active release sequence +/// and to be collapsed back to one active release sequence /// once a non RMW atomic store operation occurs. /// An all zero vector is considered to be equal to no /// element stored internally since it will never be @@ -63,7 +60,6 @@ pub struct VSmallClockMap(VSmallClockMapInner); #[derive(Clone)] enum VSmallClockMapInner { - /// Zero or 1 vector elements, common /// case for the sparse set. /// The all zero vector clock is treated @@ -71,18 +67,15 @@ enum VSmallClockMapInner { Small(VectorIdx, VClock), /// Hash-map of vector clocks. - Large(FxHashMap) + Large(FxHashMap), } impl VSmallClockMap { - /// Remove all clock vectors from the map, setting them /// to the zero vector. pub fn clear(&mut self) { match &mut self.0 { - VSmallClockMapInner::Small(_, clock) => { - clock.set_zero_vector() - } + VSmallClockMapInner::Small(_, clock) => clock.set_zero_vector(), VSmallClockMapInner::Large(hash_map) => { hash_map.clear(); } @@ -95,12 +88,11 @@ impl VSmallClockMap { match &mut self.0 { VSmallClockMapInner::Small(small_idx, clock) => { if index != *small_idx { - // The zero-vector is considered to equal // the empty element. clock.set_zero_vector() } - }, + } VSmallClockMapInner::Large(hash_map) => { let value = hash_map.remove(&index).unwrap_or_default(); self.0 = VSmallClockMapInner::Small(index, value); @@ -114,23 +106,20 @@ impl VSmallClockMap { match &mut self.0 { VSmallClockMapInner::Small(small_idx, small_clock) => { if small_clock.is_zero_vector() { - *small_idx = index; small_clock.clone_from(clock); } else if !clock.is_zero_vector() { - // Convert to using the hash-map representation. let mut hash_map = FxHashMap::default(); hash_map.insert(*small_idx, mem::take(small_clock)); hash_map.insert(index, clock.clone()); self.0 = VSmallClockMapInner::Large(hash_map); } - }, - VSmallClockMapInner::Large(hash_map) => { + } + VSmallClockMapInner::Large(hash_map) => if !clock.is_zero_vector() { hash_map.insert(index, clock.clone()); - } - } + }, } } @@ -144,51 +133,39 @@ impl VSmallClockMap { } else { None } - }, - VSmallClockMapInner::Large(hash_map) => { - hash_map.get(&index) } + VSmallClockMapInner::Large(hash_map) => hash_map.get(&index), } } } impl Default for VSmallClockMap { - #[inline] fn default() -> Self { - VSmallClockMap( - VSmallClockMapInner::Small(VectorIdx::new(0), VClock::default()) - ) + VSmallClockMap(VSmallClockMapInner::Small(VectorIdx::new(0), VClock::default())) } - } impl Debug for VSmallClockMap { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Print the contents of the small vector clock set as the map // of vector index to vector clock that they represent. let mut map = f.debug_map(); match &self.0 { - VSmallClockMapInner::Small(small_idx, small_clock) => { + VSmallClockMapInner::Small(small_idx, small_clock) => if !small_clock.is_zero_vector() { map.entry(&small_idx, &small_clock); - } - }, - VSmallClockMapInner::Large(hash_map) => { + }, + VSmallClockMapInner::Large(hash_map) => for (idx, elem) in hash_map.iter() { map.entry(idx, elem); - } - } + }, } map.finish() } - } - impl PartialEq for VSmallClockMap { - fn eq(&self, other: &Self) -> bool { use VSmallClockMapInner::*; match (&self.0, &other.0) { @@ -201,9 +178,7 @@ impl PartialEq for VSmallClockMap { i1 == i2 && c1 == c2 } } - (Small(idx, clock), Large(hash_map)) | - (Large(hash_map), Small(idx, clock)) => { - + (Small(idx, clock), Large(hash_map)) | (Large(hash_map), Small(idx, clock)) => { if hash_map.len() == 0 { // Equal to the empty hash-map clock.is_zero_vector() @@ -215,18 +190,13 @@ impl PartialEq for VSmallClockMap { false } } - (Large(map1), Large(map2)) => { - map1 == map2 - } + (Large(map1), Large(map2)) => map1 == map2, } } - } impl Eq for VSmallClockMap {} - - /// The size of the vector-clock to store inline /// clock vectors larger than this will be stored on the heap const SMALL_VECTOR: usize = 4; @@ -249,7 +219,6 @@ pub type VTimestamp = u32; pub struct VClock(SmallVec<[VTimestamp; SMALL_VECTOR]>); impl VClock { - /// Create a new vector-clock containing all zeros except /// for a value at the given index pub fn new_with_index(index: VectorIdx, timestamp: VTimestamp) -> VClock { @@ -316,11 +285,9 @@ impl VClock { pub fn is_zero_vector(&self) -> bool { self.0.is_empty() } - } impl Clone for VClock { - fn clone(&self) -> Self { VClock(self.0.clone()) } @@ -334,13 +301,10 @@ impl Clone for VClock { self.0.clear(); self.0.extend_from_slice(source_slice); } - } impl PartialOrd for VClock { - fn partial_cmp(&self, other: &VClock) -> Option { - // Load the values as slices let lhs_slice = self.as_slice(); let rhs_slice = other.as_slice(); @@ -356,17 +320,19 @@ impl PartialOrd for VClock { let mut iter = lhs_slice.iter().zip(rhs_slice.iter()); let mut order = match iter.next() { Some((lhs, rhs)) => lhs.cmp(rhs), - None => Ordering::Equal + None => Ordering::Equal, }; for (l, r) in iter { match order { Ordering::Equal => order = l.cmp(r), - Ordering::Less => if l > r { - return None - }, - Ordering::Greater => if l < r { - return None - } + Ordering::Less => + if l > r { + return None; + }, + Ordering::Greater => + if l < r { + return None; + }, } } @@ -383,14 +349,14 @@ impl PartialOrd for VClock { // so the only valid values are Ordering::Less or None. Ordering::Less => match order { Ordering::Less | Ordering::Equal => Some(Ordering::Less), - Ordering::Greater => None - } + Ordering::Greater => None, + }, // Left has at least 1 element > than the implicit 0, // so the only valid values are Ordering::Greater or None. Ordering::Greater => match order { Ordering::Greater | Ordering::Equal => Some(Ordering::Greater), - Ordering::Less => None - } + Ordering::Less => None, + }, } } @@ -415,13 +381,13 @@ impl PartialOrd for VClock { let mut equal = l_len == r_len; for (&l, &r) in lhs_slice.iter().zip(rhs_slice.iter()) { if l > r { - return false + return false; } else if l < r { equal = false; } } !equal - } else { + } else { false } } @@ -469,7 +435,7 @@ impl PartialOrd for VClock { let mut equal = l_len == r_len; for (&l, &r) in lhs_slice.iter().zip(rhs_slice.iter()) { if l < r { - return false + return false; } else if l > r { equal = false; } @@ -501,28 +467,24 @@ impl PartialOrd for VClock { false } } - } impl Index for VClock { - type Output = VTimestamp; #[inline] fn index(&self, index: VectorIdx) -> &VTimestamp { - self.as_slice().get(index.to_u32() as usize).unwrap_or(&0) + self.as_slice().get(index.to_u32() as usize).unwrap_or(&0) } - } - /// Test vector clock ordering operations /// data-race detection is tested in the external /// test suite #[cfg(test)] mod tests { - use super::{VClock, VTimestamp, VectorIdx, VSmallClockMap}; + use super::{VClock, VSmallClockMap, VTimestamp, VectorIdx}; use std::cmp::Ordering; #[test] @@ -546,19 +508,43 @@ mod tests { assert_order(&[1], &[1], Some(Ordering::Equal)); assert_order(&[1], &[2], Some(Ordering::Less)); assert_order(&[2], &[1], Some(Ordering::Greater)); - assert_order(&[1], &[1,2], Some(Ordering::Less)); - assert_order(&[2], &[1,2], None); + assert_order(&[1], &[1, 2], Some(Ordering::Less)); + assert_order(&[2], &[1, 2], None); // Misc tests assert_order(&[400], &[0, 1], None); // Large test - assert_order(&[0,1,2,3,4,5,6,7,8,9,10], &[0,1,2,3,4,5,6,7,8,9,10,0,0,0], Some(Ordering::Equal)); - assert_order(&[0,1,2,3,4,5,6,7,8,9,10], &[0,1,2,3,4,5,6,7,8,9,10,0,1,0], Some(Ordering::Less)); - assert_order(&[0,1,2,3,4,5,6,7,8,9,11], &[0,1,2,3,4,5,6,7,8,9,10,0,0,0], Some(Ordering::Greater)); - assert_order(&[0,1,2,3,4,5,6,7,8,9,11], &[0,1,2,3,4,5,6,7,8,9,10,0,1,0], None); - assert_order(&[0,1,2,3,4,5,6,7,8,9,9 ], &[0,1,2,3,4,5,6,7,8,9,10,0,0,0], Some(Ordering::Less)); - assert_order(&[0,1,2,3,4,5,6,7,8,9,9 ], &[0,1,2,3,4,5,6,7,8,9,10,0,1,0], Some(Ordering::Less)); + assert_order( + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, 0], + Some(Ordering::Equal), + ); + assert_order( + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 1, 0], + Some(Ordering::Less), + ); + assert_order( + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11], + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, 0], + Some(Ordering::Greater), + ); + assert_order( + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11], + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 1, 0], + None, + ); + assert_order( + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9], + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, 0], + Some(Ordering::Less), + ); + assert_order( + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9], + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 1, 0], + Some(Ordering::Less), + ); } fn from_slice(mut slice: &[VTimestamp]) -> VClock { @@ -574,51 +560,81 @@ mod tests { //Test partial_cmp let compare = l.partial_cmp(&r); - assert_eq!(compare, o, "Invalid comparison\n l: {:?}\n r: {:?}",l,r); + assert_eq!(compare, o, "Invalid comparison\n l: {:?}\n r: {:?}", l, r); let alt_compare = r.partial_cmp(&l); - assert_eq!(alt_compare, o.map(Ordering::reverse), "Invalid alt comparison\n l: {:?}\n r: {:?}",l,r); + assert_eq!( + alt_compare, + o.map(Ordering::reverse), + "Invalid alt comparison\n l: {:?}\n r: {:?}", + l, + r + ); //Test operators with faster implementations assert_eq!( - matches!(compare,Some(Ordering::Less)), l < r, - "Invalid (<):\n l: {:?}\n r: {:?}",l,r + matches!(compare, Some(Ordering::Less)), + l < r, + "Invalid (<):\n l: {:?}\n r: {:?}", + l, + r ); assert_eq!( - matches!(compare,Some(Ordering::Less) | Some(Ordering::Equal)), l <= r, - "Invalid (<=):\n l: {:?}\n r: {:?}",l,r + matches!(compare, Some(Ordering::Less) | Some(Ordering::Equal)), + l <= r, + "Invalid (<=):\n l: {:?}\n r: {:?}", + l, + r ); assert_eq!( - matches!(compare,Some(Ordering::Greater)), l > r, - "Invalid (>):\n l: {:?}\n r: {:?}",l,r + matches!(compare, Some(Ordering::Greater)), + l > r, + "Invalid (>):\n l: {:?}\n r: {:?}", + l, + r ); assert_eq!( - matches!(compare,Some(Ordering::Greater) | Some(Ordering::Equal)), l >= r, - "Invalid (>=):\n l: {:?}\n r: {:?}",l,r + matches!(compare, Some(Ordering::Greater) | Some(Ordering::Equal)), + l >= r, + "Invalid (>=):\n l: {:?}\n r: {:?}", + l, + r ); assert_eq!( - matches!(alt_compare,Some(Ordering::Less)), r < l, - "Invalid alt (<):\n l: {:?}\n r: {:?}",l,r + matches!(alt_compare, Some(Ordering::Less)), + r < l, + "Invalid alt (<):\n l: {:?}\n r: {:?}", + l, + r ); assert_eq!( - matches!(alt_compare,Some(Ordering::Less) | Some(Ordering::Equal)), r <= l, - "Invalid alt (<=):\n l: {:?}\n r: {:?}",l,r + matches!(alt_compare, Some(Ordering::Less) | Some(Ordering::Equal)), + r <= l, + "Invalid alt (<=):\n l: {:?}\n r: {:?}", + l, + r ); assert_eq!( - matches!(alt_compare,Some(Ordering::Greater)), r > l, - "Invalid alt (>):\n l: {:?}\n r: {:?}",l,r + matches!(alt_compare, Some(Ordering::Greater)), + r > l, + "Invalid alt (>):\n l: {:?}\n r: {:?}", + l, + r ); assert_eq!( - matches!(alt_compare,Some(Ordering::Greater) | Some(Ordering::Equal)), r >= l, - "Invalid alt (>=):\n l: {:?}\n r: {:?}",l,r + matches!(alt_compare, Some(Ordering::Greater) | Some(Ordering::Equal)), + r >= l, + "Invalid alt (>=):\n l: {:?}\n r: {:?}", + l, + r ); } #[test] pub fn test_vclock_set() { let mut map = VSmallClockMap::default(); - let v1 = from_slice(&[3,0,1]); - let v2 = from_slice(&[4,2,3]); - let v3 = from_slice(&[4,8,3]); + let v1 = from_slice(&[3, 0, 1]); + let v2 = from_slice(&[4, 2, 3]); + let v3 = from_slice(&[4, 8, 3]); map.insert(VectorIdx(0), &v1); assert_eq!(map.get(VectorIdx(0)), Some(&v1)); map.insert(VectorIdx(5), &v2); @@ -641,5 +657,4 @@ mod tests { assert_eq!(map.get(VectorIdx(5)), None); assert_eq!(map.get(VectorIdx(53)), Some(&v3)); } - } From a37cfed062bd4106fb1462a0a1e13010307bd262 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 19 Nov 2020 09:21:03 +0100 Subject: [PATCH 2449/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 3b96c994a782..5d44fe9e4b83 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -12f0dba618e761c987142474435dff95ab177f3c +bf469eb6c20ccea05400a1942c70343f36705e1c From 4de113acba482ecee67a2098e9e1ba6068304ccc Mon Sep 17 00:00:00 2001 From: est31 Date: Sun, 15 Nov 2020 05:01:10 +0100 Subject: [PATCH 2450/5092] Normalize column numbers --- tests/run-pass/backtrace-std.rs | 2 +- tests/run-pass/backtrace-std.stderr | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/run-pass/backtrace-std.rs b/tests/run-pass/backtrace-std.rs index 7a793e092a81..9b61aabab3b2 100644 --- a/tests/run-pass/backtrace-std.rs +++ b/tests/run-pass/backtrace-std.rs @@ -1,5 +1,5 @@ // normalize-stderr-test "at .*/(rust[^/]*|checkout)/library/" -> "at RUSTLIB/" -// normalize-stderr-test "RUSTLIB/(.*):\d+"-> "RUSTLIB/$1:LL" +// normalize-stderr-test "RUSTLIB/([^:]*):\d+:\d+"-> "RUSTLIB/$1:LL:CC" // normalize-stderr-test "::<.*>" -> "" // compile-flags: -Zmiri-disable-isolation diff --git a/tests/run-pass/backtrace-std.stderr b/tests/run-pass/backtrace-std.stderr index 45c46acc331c..09f035b9724e 100644 --- a/tests/run-pass/backtrace-std.stderr +++ b/tests/run-pass/backtrace-std.stderr @@ -1,28 +1,28 @@ 0: func_d - at $DIR/backtrace-std.rs:18 + at $DIR/backtrace-std.rs:18:45 1: func_c - at $DIR/backtrace-std.rs:17 + at $DIR/backtrace-std.rs:17:45 2: func_b - at $DIR/backtrace-std.rs:11 + at $DIR/backtrace-std.rs:11:48 3: func_a - at $DIR/backtrace-std.rs:10 + at $DIR/backtrace-std.rs:10:45 4: main - at $DIR/backtrace-std.rs:21 + at $DIR/backtrace-std.rs:21:19 5: >::call_once - shim(fn()) - at RUSTLIB/core/src/ops/function.rs:LL + at RUSTLIB/core/src/ops/function.rs:LL:CC 6: std::sys_common::backtrace::__rust_begin_short_backtrace - at RUSTLIB/std/src/sys_common/backtrace.rs:LL + at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC 7: std::rt::lang_start::{closure#0} - at RUSTLIB/std/src/rt.rs:LL + at RUSTLIB/std/src/rt.rs:LL:CC 8: std::ops::function::impls::call_once - at RUSTLIB/core/src/ops/function.rs:LL + at RUSTLIB/core/src/ops/function.rs:LL:CC 9: std::panicking::r#try::do_call - at RUSTLIB/std/src/panicking.rs:LL + at RUSTLIB/std/src/panicking.rs:LL:CC 10: std::panicking::r#try - at RUSTLIB/std/src/panicking.rs:LL + at RUSTLIB/std/src/panicking.rs:LL:CC 11: std::panic::catch_unwind - at RUSTLIB/std/src/panic.rs:LL + at RUSTLIB/std/src/panic.rs:LL:CC 12: std::rt::lang_start_internal - at RUSTLIB/std/src/rt.rs:LL + at RUSTLIB/std/src/rt.rs:LL:CC 13: std::rt::lang_start - at RUSTLIB/std/src/rt.rs:LL + at RUSTLIB/std/src/rt.rs:LL:CC From cdb7adb4b32168b79a44f332ceace67aee727c42 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 18 Nov 2020 23:15:32 +0100 Subject: [PATCH 2451/5092] Make weak syscalls in std work. std now looks up `getrandom` and `statx` with `dlsym` before attempting to use `syscall(SYS_.., ..)`. It also now passes all arguments as a machine-sized word, instead of their original types. --- src/shims/posix/linux/dlsym.rs | 2 ++ src/shims/posix/linux/foreign_items.rs | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/shims/posix/linux/dlsym.rs b/src/shims/posix/linux/dlsym.rs index ca5cf3ffe8f3..2685a93726d8 100644 --- a/src/shims/posix/linux/dlsym.rs +++ b/src/shims/posix/linux/dlsym.rs @@ -12,6 +12,8 @@ impl Dlsym { pub fn from_str(name: &str) -> InterpResult<'static, Option> { Ok(match &*name { "__pthread_get_minstack" => None, + "getrandom" => None, // std falls back to syscall(SYS_getrandom, ...) when this is NULL. + "statx" => None, // std falls back to syscall(SYS_statx, ...) when this is NULL. _ => throw_unsup_format!("unsupported Linux dlsym: {}", name), }) } diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 04efa79b9d93..21d765621f73 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -208,7 +208,11 @@ fn getrandom<'tcx>( // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, // neither of which have any effect on our current PRNG. - this.read_scalar(flags)?.to_i32()?; + let flags = this.read_scalar(flags)?; + // Either `i32` or `isize` is fine. + if flags.to_machine_isize(this).is_err() { + flags.to_i32()?; + } this.gen_random(ptr, len)?; this.write_scalar(Scalar::from_machine_usize(len, this), dest)?; From 517728bf97b5be2f609a9c539c7fdade2c601555 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 19 Nov 2020 09:36:06 +0100 Subject: [PATCH 2452/5092] avoid fallback logic (and we do not need the flag value currently anyway) --- src/shims/posix/linux/foreign_items.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 21d765621f73..23dc02a6affd 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -208,11 +208,9 @@ fn getrandom<'tcx>( // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, // neither of which have any effect on our current PRNG. - let flags = this.read_scalar(flags)?; - // Either `i32` or `isize` is fine. - if flags.to_machine_isize(this).is_err() { - flags.to_i32()?; - } + let _flags = this.read_scalar(flags)?; + // FIXME: Check that this is an integer type of the right size. + // Currently, some callers pass i32 and some usize, is that even allowed? this.gen_random(ptr, len)?; this.write_scalar(Scalar::from_machine_usize(len, this), dest)?; From 697f6e36bd747fe0a2850324f39dadd1008e4592 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 20 Nov 2020 14:07:52 +0100 Subject: [PATCH 2453/5092] rustup --- rust-version | 2 +- src/shims/posix/fs.rs | 13 +++---------- src/shims/posix/linux/foreign_items.rs | 5 ++--- 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/rust-version b/rust-version index 5d44fe9e4b83..0260e9beab17 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -bf469eb6c20ccea05400a1942c70343f36705e1c +172acf8f61018df3719e42e633ffd62ebecaa1e7 diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 50589ca322db..10f0c9109792 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -831,17 +831,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; let path = this.read_path_from_c_str(pathname_scalar)?.into_owned(); - // `flags` should be a `c_int` but the `syscall` function provides an `isize`. - let flags: i32 = - this.read_scalar(flags_op)?.to_machine_isize(&*this.tcx)?.try_into().map_err(|e| { - err_unsup_format!("failed to convert pointer sized operand to integer: {}", e) - })?; + // See for a discussion of argument sizes. + let flags = this.read_scalar(flags_op)?.to_i32()?; let empty_path_flag = flags & this.eval_libc("AT_EMPTY_PATH")?.to_i32()? != 0; - // `dirfd` should be a `c_int` but the `syscall` function provides an `isize`. - let dirfd: i32 = - this.read_scalar(dirfd_op)?.to_machine_isize(&*this.tcx)?.try_into().map_err(|e| { - err_unsup_format!("failed to convert pointer sized operand to integer: {}", e) - })?; + let dirfd = this.read_scalar(dirfd_op)?.to_i32()?; // We only support: // * interpreting `path` as an absolute directory, // * interpreting `path` as a path relative to `dirfd` when the latter is `AT_FDCWD`, or diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 23dc02a6affd..45afbd05efc2 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -208,9 +208,8 @@ fn getrandom<'tcx>( // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, // neither of which have any effect on our current PRNG. - let _flags = this.read_scalar(flags)?; - // FIXME: Check that this is an integer type of the right size. - // Currently, some callers pass i32 and some usize, is that even allowed? + // See for a discussion of argument sizes. + let _flags = this.read_scalar(flags)?.to_i32(); this.gen_random(ptr, len)?; this.write_scalar(Scalar::from_machine_usize(len, this), dest)?; From 7a2c2f8dde970723bf83bae346965ad3a8198f99 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Nov 2020 18:08:57 +0100 Subject: [PATCH 2454/5092] rustup; test sorting for provenance-correctness --- rust-version | 2 +- tests/run-pass/vec.rs | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 0260e9beab17..c3173f6245b6 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -172acf8f61018df3719e42e633ffd62ebecaa1e7 +828461b4b27c4a955587887936e54057efc5e2c1 diff --git a/tests/run-pass/vec.rs b/tests/run-pass/vec.rs index ad6c5363ac1f..f243aa45a1a6 100644 --- a/tests/run-pass/vec.rs +++ b/tests/run-pass/vec.rs @@ -130,6 +130,12 @@ fn push_str_ptr_stable() { assert_eq!(format!("{}", hello), "hello"); } +fn sort() { + let mut v = vec![1; 20]; + v.push(0); + v.sort(); +} + fn main() { assert_eq!(vec_reallocate().len(), 5); @@ -154,4 +160,6 @@ fn main() { vec_extend_ptr_stable(); vec_truncate_ptr_stable(); push_str_ptr_stable(); + + sort(); } From 3268f56a97f2ac7fbcdf6f23e31445a29c529674 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Sun, 22 Nov 2020 17:28:12 +0000 Subject: [PATCH 2455/5092] Fix review changes --- src/machine.rs | 2 +- src/shims/posix/linux/sync.rs | 8 ++--- src/sync.rs | 35 +++++++++++++++++-- src/vector_clock.rs | 2 +- .../data_race/relax_acquire_race.rs | 2 +- .../data_race/release_seq_race.rs | 2 +- tests/compile-fail/data_race/rmw_race.rs | 2 +- tests/run-pass/concurrency/data_race.rs | 6 ++-- 8 files changed, 43 insertions(+), 16 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 9612d9e19110..02c66915564d 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -150,7 +150,7 @@ impl MemoryExtra { }; let data_race = if config.data_race_detector { Some(Rc::new(data_race::GlobalState::new())) - }else{ + } else { None }; MemoryExtra { diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 78244ab7b879..5243431194eb 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -85,12 +85,10 @@ pub fn futex<'tcx>( // with the expected value, and starting to sleep are performed // atomically and totally ordered with respect to other futex // operations on the same futex word." - // SeqCst is total order over all operations, so uses acquire, - // either are equal under the current implementation. - // FIXME: is Acquire correct or should some additional ordering constraints be observed? - // FIXME: use RMW or similar? + // SeqCst is total order over all operations. + // FIXME: check if this should be changed when weak memory orders are added. let futex_val = this.read_scalar_at_offset_atomic( - addr.into(), 0, this.machine.layouts.i32, AtomicReadOp::Acquire + addr.into(), 0, this.machine.layouts.i32, AtomicReadOp::SeqCst )?.to_i32()?; if val == futex_val { // The value still matches, so we block the trait make it wait for FUTEX_WAKE. diff --git a/src/sync.rs b/src/sync.rs index 828268c06ccf..4d488565faf3 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -61,7 +61,11 @@ struct Mutex { lock_count: usize, /// The queue of threads waiting for this mutex. queue: VecDeque, - /// Data race handle + /// Data race handle, this tracks the happens-before + /// relationship between each mutex access. It is + /// released to during unlock and acquired from during + /// locking, and therefore stores the clock of the last + /// thread to release this mutex. data_race: VClock } @@ -79,9 +83,24 @@ struct RwLock { writer_queue: VecDeque, /// The queue of reader threads waiting for this lock. reader_queue: VecDeque, - /// Data race handle for writers + /// Data race handle for writers, tracks the happens-before + /// ordering between each write access to a rwlock and is updated + /// after a sequence of concurrent readers to track the happens- + /// before ordering between the set of previous readers and + /// the current writer. + /// Contains the clock of the last thread to release a writer + /// lock or the joined clock of the set of last threads to release + /// shared reader locks. data_race: VClock, - /// Data race handle for readers + /// Data race handle for readers, this is temporary storage + /// for the combined happens-before ordering for between all + /// concurrent readers and the next writer, and the value + /// is stored to the main data_race variable once all + /// readers are finished. + /// Has to be stored separately since reader lock acquires + /// must load the clock of the last write and must not + /// add happens-before orderings between shared reader + /// locks. data_race_reader: VClock, } @@ -100,6 +119,11 @@ struct CondvarWaiter { #[derive(Default, Debug)] struct Condvar { waiters: VecDeque, + /// Tracks the happens-before relationship + /// between a cond-var signal and a cond-var + /// wait during a non-suprious signal event. + /// Contains the clock of the last thread to + /// perform a futex-signal. data_race: VClock, } @@ -107,6 +131,11 @@ struct Condvar { #[derive(Default, Debug)] struct Futex { waiters: VecDeque, + /// Tracks the happens-before relationship + /// between a futex-wake and a futex-wait + /// during a non-spurious wake event. + /// Contains the clock of the last thread to + /// perform a futex-wake. data_race: VClock, } diff --git a/src/vector_clock.rs b/src/vector_clock.rs index ddee98bcf624..6840d7e6cb99 100644 --- a/src/vector_clock.rs +++ b/src/vector_clock.rs @@ -11,7 +11,7 @@ use std::{ /// A vector clock index, this is associated with a thread id /// but in some cases one vector index may be shared with -/// multiple thread ids id it safe to do so. +/// multiple thread ids if it safe to do so. #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] pub struct VectorIdx(u32); diff --git a/tests/compile-fail/data_race/relax_acquire_race.rs b/tests/compile-fail/data_race/relax_acquire_race.rs index f7d44c30b66b..4b736e57208a 100644 --- a/tests/compile-fail/data_race/relax_acquire_race.rs +++ b/tests/compile-fail/data_race/relax_acquire_race.rs @@ -31,7 +31,7 @@ pub fn main() { let j3 = spawn(move || { if SYNC.load(Ordering::Acquire) == 2 { *c.0 //~ ERROR Data race - }else{ + } else { 0 } }); diff --git a/tests/compile-fail/data_race/release_seq_race.rs b/tests/compile-fail/data_race/release_seq_race.rs index dc852cdb4d81..0278e9864353 100644 --- a/tests/compile-fail/data_race/release_seq_race.rs +++ b/tests/compile-fail/data_race/release_seq_race.rs @@ -35,7 +35,7 @@ pub fn main() { sleep(Duration::from_millis(1000)); if SYNC.load(Ordering::Acquire) == 3 { *c.0 //~ ERROR Data race - }else{ + } else { 0 } }); diff --git a/tests/compile-fail/data_race/rmw_race.rs b/tests/compile-fail/data_race/rmw_race.rs index bebd01efa171..c533f595f160 100644 --- a/tests/compile-fail/data_race/rmw_race.rs +++ b/tests/compile-fail/data_race/rmw_race.rs @@ -32,7 +32,7 @@ pub fn main() { let j3 = spawn(move || { if SYNC.load(Ordering::Acquire) == 3 { *c.0 //~ ERROR Data race - }else{ + } else { 0 } }); diff --git a/tests/run-pass/concurrency/data_race.rs b/tests/run-pass/concurrency/data_race.rs index 75e56e8c8d2a..64e90024ed49 100644 --- a/tests/run-pass/concurrency/data_race.rs +++ b/tests/run-pass/concurrency/data_race.rs @@ -28,7 +28,7 @@ fn test_fence_sync() { if SYNC.load(Ordering::Relaxed) == 1 { fence(Ordering::Acquire); unsafe { *evil_ptr.0 } - }else{ + } else { 0 } }); @@ -77,7 +77,7 @@ pub fn test_rmw_no_block() { let j3 = spawn(move || { if SYNC.load(Ordering::Acquire) == 2 { *c.0 - }else{ + } else { 0 } }); @@ -104,7 +104,7 @@ pub fn test_release_no_block() { let j2 = spawn(move || { if SYNC.load(Ordering::Acquire) == 3 { *c.0 - }else{ + } else { 0 } }); From 55fc552d9900e2f53ad4302da9387da32d7bcf8d Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Fri, 27 Nov 2020 19:26:06 +0000 Subject: [PATCH 2456/5092] Apply review changes, incrementing the clocks twice is an unnecessary hold-over from earlier versions so fixed. --- src/data_race.rs | 40 +++++++++++++------ src/shims/posix/sync.rs | 35 +++++++++++----- src/shims/posix/thread.rs | 2 +- ..._race.rs => atomic_read_na_write_race1.rs} | 0 ...e_alt.rs => atomic_read_na_write_race2.rs} | 0 ..._race.rs => atomic_write_na_read_race1.rs} | 0 ...e_alt.rs => atomic_write_na_read_race2.rs} | 0 ...race.rs => atomic_write_na_write_race1.rs} | 0 ..._alt.rs => atomic_write_na_write_race2.rs} | 0 .../data_race/dangling_thread_async_race.rs | 6 +-- .../data_race/dangling_thread_race.rs | 6 +-- .../data_race/enable_after_join_to_main.rs | 4 +- .../data_race/relax_acquire_race.rs | 7 ++++ .../data_race/release_seq_race.rs | 8 ++++ tests/compile-fail/data_race/rmw_race.rs | 7 ++++ tests/run-pass/concurrency/data_race.stderr | 2 +- .../concurrency/disable_data_race_detector.rs | 2 +- .../disable_data_race_detector.stderr | 2 +- tests/run-pass/concurrency/linux-futex.stderr | 2 +- tests/run-pass/concurrency/simple.stderr | 2 +- tests/run-pass/concurrency/sync.stderr | 2 +- .../run-pass/concurrency/thread_locals.stderr | 2 +- .../run-pass/concurrency/tls_lib_drop.stderr | 2 +- tests/run-pass/libc.stderr | 2 +- tests/run-pass/panic/concurrent-panic.stderr | 2 +- 25 files changed, 95 insertions(+), 40 deletions(-) rename tests/compile-fail/data_race/{atomic_read_write_race.rs => atomic_read_na_write_race1.rs} (100%) rename tests/compile-fail/data_race/{atomic_read_write_race_alt.rs => atomic_read_na_write_race2.rs} (100%) rename tests/compile-fail/data_race/{atomic_write_read_race.rs => atomic_write_na_read_race1.rs} (100%) rename tests/compile-fail/data_race/{atomic_write_read_race_alt.rs => atomic_write_na_read_race2.rs} (100%) rename tests/compile-fail/data_race/{atomic_write_write_race.rs => atomic_write_na_write_race1.rs} (100%) rename tests/compile-fail/data_race/{atomic_write_write_race_alt.rs => atomic_write_na_write_race2.rs} (100%) diff --git a/src/data_race.rs b/src/data_race.rs index b9542f6e2d62..3f70631d1362 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -37,6 +37,24 @@ //! to a acquire load and a release store given the global sequentially consistent order //! of the schedule. //! +//! The timestamps used in the data-race detector assign each sequence of non-atomic operations +//! followed by a single atomic or concurrent operation a single timestamp. +//! Write, Read, Write, ThreadJoin will be represented by a single timestamp value on a thread +//! This is because extra increment operations between the operations in the sequence are not +//! required for accurate reporting of data-race values. +//! +//! If the timestamp was not incremented after the atomic operation, then data-races would not be detected: +//! Example - this should report a data-race but does not: +//! t1: (x,0), atomic[release A], t1=(x+1, 0 ), write(var B), +//! t2: (0,y) , atomic[acquire A], t2=(x+1, y+1), ,write(var B) +//! +//! The timestamp is not incremented before an atomic operation, since the result is indistinguishable +//! from the value not being incremented. +//! t: (x, 0), atomic[release _], (x + 1, 0) || (0, y), atomic[acquire _], (x, _) +//! vs t: (x, 0), atomic[release _], (x + 1, 0) || (0, y), atomic[acquire _], (x+1, _) +//! Both result in the sequence on thread x up to and including the atomic release as happening +//! before the acquire. +//! //! FIXME: //! currently we have our own local copy of the currently active thread index and names, this is due //! in part to the inability to access the current location of threads.active_thread inside the AllocExtra @@ -499,7 +517,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { } /// Perform an atomic compare and exchange at a given memory location - /// on success an atomic RMW operation is performed and on failure + /// On success an atomic RMW operation is performed and on failure /// only an atomic read occurs. fn atomic_compare_exchange_scalar( &mut self, @@ -1136,9 +1154,6 @@ impl GlobalState { // Now load the two clocks and configure the initial state. let (current, created) = vector_clocks.pick2_mut(current_index, created_index); - // Advance the current thread before the synchronized operation. - current.increment_clock(current_index); - // Join the created with current, since the current threads // previous actions happen-before the created thread. created.join_with(current); @@ -1167,14 +1182,12 @@ impl GlobalState { .as_ref() .expect("Joined with thread but thread has not terminated"); - // Pre increment clocks before atomic operation. - current.increment_clock(current_index); // The join thread happens-before the current thread // so update the current vector clock. current.clock.join(join_clock); - // Post increment clocks after atomic operation. + // Increment clocks after atomic operation. current.increment_clock(current_index); // Check the number of active threads, if the value is 1 @@ -1277,8 +1290,7 @@ impl GlobalState { op: impl FnOnce(VectorIdx, RefMut<'_, ThreadClockSet>) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { if self.multi_threaded.get() { - let (index, mut clocks) = self.current_thread_state_mut(); - clocks.increment_clock(index); + let (index, clocks) = self.current_thread_state_mut(); op(index, clocks)?; let (_, mut clocks) = self.current_thread_state_mut(); clocks.increment_clock(index); @@ -1303,16 +1315,18 @@ impl GlobalState { /// `validate_lock_release` must happen before this. pub fn validate_lock_acquire(&self, lock: &VClock, thread: ThreadId) { let (index, mut clocks) = self.load_thread_state_mut(thread); - clocks.increment_clock(index); clocks.clock.join(&lock); clocks.increment_clock(index); } /// Release a lock handle, express that this happens-before /// any subsequent calls to `validate_lock_acquire`. + /// For normal locks this should be equivalent to `validate_lock_release_shared` + /// since an acquire operation should have occured before, however + /// for futex & cond-var operations this is not the case and this + /// operation must be used. pub fn validate_lock_release(&self, lock: &mut VClock, thread: ThreadId) { let (index, mut clocks) = self.load_thread_state_mut(thread); - clocks.increment_clock(index); lock.clone_from(&clocks.clock); clocks.increment_clock(index); } @@ -1321,9 +1335,11 @@ impl GlobalState { /// any subsequent calls to `validate_lock_acquire` as well /// as any previous calls to this function after any /// `validate_lock_release` calls. + /// For normal locks this should be equivalent to `validate_lock_release` + /// this function only exists for joining over the set of concurrent readers + /// in a read-write lock and should not be used for anything else. pub fn validate_lock_release_shared(&self, lock: &mut VClock, thread: ThreadId) { let (index, mut clocks) = self.load_thread_state_mut(thread); - clocks.increment_clock(index); lock.join(&clocks.clock); clocks.increment_clock(index); } diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 64308d06139f..efa441299194 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -62,9 +62,11 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>( mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; + //FIXME: this has been made atomic to fix data-race reporting inside the internal + // mutex implementation, it may not need to be atomic. ecx.read_scalar_at_offset_atomic( mutex_op, offset, ecx.machine.layouts.i32, - AtomicReadOp::Acquire + AtomicReadOp::Relaxed ) } @@ -74,9 +76,11 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( kind: impl Into>, ) -> InterpResult<'tcx, ()> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; + //FIXME: this has been made atomic to fix data-race reporting inside the internal + // mutex implementation, it may not need to be atomic. ecx.write_scalar_at_offset_atomic( - mutex_op, offset, kind, ecx.machine.layouts.i32, - AtomicWriteOp::Release + mutex_op, offset, kind, ecx.machine.layouts.i32, + AtomicWriteOp::Relaxed ) } @@ -84,8 +88,11 @@ fn mutex_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { + //FIXME: this has been made atomic to fix data-race reporting inside the internal + // mutex implementation, it may not need to be atomic. ecx.read_scalar_at_offset_atomic( - mutex_op, 4, ecx.machine.layouts.u32, AtomicReadOp::Acquire + mutex_op, 4, ecx.machine.layouts.u32, + AtomicReadOp::Relaxed ) } @@ -94,9 +101,11 @@ fn mutex_set_id<'mir, 'tcx: 'mir>( mutex_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { + //FIXME: this has been made atomic to fix data-race reporting inside the internal + // mutex implementation, it may not need to be atomic. ecx.write_scalar_at_offset_atomic( mutex_op, 4, id, ecx.machine.layouts.u32, - AtomicWriteOp::Release + AtomicWriteOp::Relaxed ) } @@ -126,10 +135,12 @@ fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( fn rwlock_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, + //FIXME: this has been made atomic to fix data-race reporting inside the internal + // rw-lock implementation, it may not need to be atomic. ) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset_atomic( rwlock_op, 4, ecx.machine.layouts.u32, - AtomicReadOp::Acquire + AtomicReadOp::Relaxed ) } @@ -138,9 +149,11 @@ fn rwlock_set_id<'mir, 'tcx: 'mir>( rwlock_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { + //FIXME: this has been made atomic to fix data-race reporting inside the internal + // rw-lock implementation, it may not need to be atomic. ecx.write_scalar_at_offset_atomic( rwlock_op, 4, id, ecx.machine.layouts.u32, - AtomicWriteOp::Release + AtomicWriteOp::Relaxed ) } @@ -194,9 +207,11 @@ fn cond_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, cond_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { + //FIXME: this has been made atomic to fix data-race reporting inside the internal + // cond-var implementation, it may not need to be atomic. ecx.read_scalar_at_offset_atomic( cond_op, 4, ecx.machine.layouts.u32, - AtomicReadOp::Acquire + AtomicReadOp::Relaxed ) } @@ -205,9 +220,11 @@ fn cond_set_id<'mir, 'tcx: 'mir>( cond_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { + //FIXME: this has been made atomic to fix data-race reporting inside the internal + // cond-var implementation, it may not need to be atomic. ecx.write_scalar_at_offset_atomic( cond_op, 4, id, ecx.machine.layouts.u32, - AtomicWriteOp::Release + AtomicWriteOp::Relaxed ) } diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index 847d083bfa9f..0ea20cdff6cb 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -15,7 +15,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.tcx.sess.warn( - "thread support is experimental, no weak memory effects are currently emulated.", + "thread support is experimental and incomplete: weak memory effects are not emulated." ); // Create the new thread diff --git a/tests/compile-fail/data_race/atomic_read_write_race.rs b/tests/compile-fail/data_race/atomic_read_na_write_race1.rs similarity index 100% rename from tests/compile-fail/data_race/atomic_read_write_race.rs rename to tests/compile-fail/data_race/atomic_read_na_write_race1.rs diff --git a/tests/compile-fail/data_race/atomic_read_write_race_alt.rs b/tests/compile-fail/data_race/atomic_read_na_write_race2.rs similarity index 100% rename from tests/compile-fail/data_race/atomic_read_write_race_alt.rs rename to tests/compile-fail/data_race/atomic_read_na_write_race2.rs diff --git a/tests/compile-fail/data_race/atomic_write_read_race.rs b/tests/compile-fail/data_race/atomic_write_na_read_race1.rs similarity index 100% rename from tests/compile-fail/data_race/atomic_write_read_race.rs rename to tests/compile-fail/data_race/atomic_write_na_read_race1.rs diff --git a/tests/compile-fail/data_race/atomic_write_read_race_alt.rs b/tests/compile-fail/data_race/atomic_write_na_read_race2.rs similarity index 100% rename from tests/compile-fail/data_race/atomic_write_read_race_alt.rs rename to tests/compile-fail/data_race/atomic_write_na_read_race2.rs diff --git a/tests/compile-fail/data_race/atomic_write_write_race.rs b/tests/compile-fail/data_race/atomic_write_na_write_race1.rs similarity index 100% rename from tests/compile-fail/data_race/atomic_write_write_race.rs rename to tests/compile-fail/data_race/atomic_write_na_write_race1.rs diff --git a/tests/compile-fail/data_race/atomic_write_write_race_alt.rs b/tests/compile-fail/data_race/atomic_write_na_write_race2.rs similarity index 100% rename from tests/compile-fail/data_race/atomic_write_write_race_alt.rs rename to tests/compile-fail/data_race/atomic_write_na_write_race2.rs diff --git a/tests/compile-fail/data_race/dangling_thread_async_race.rs b/tests/compile-fail/data_race/dangling_thread_async_race.rs index 6af5706835e3..d8b5d82f8304 100644 --- a/tests/compile-fail/data_race/dangling_thread_async_race.rs +++ b/tests/compile-fail/data_race/dangling_thread_async_race.rs @@ -29,9 +29,9 @@ fn main() { sleep(Duration::from_millis(100)); // Spawn and immediately join a thread - // to execute the join code-path - // and ensure that data-race detection - // remains enabled + // to execute the join code-path + // and ensure that data-race detection + // remains enabled nevertheless. spawn(|| ()).join().unwrap(); let join2 = unsafe { diff --git a/tests/compile-fail/data_race/dangling_thread_race.rs b/tests/compile-fail/data_race/dangling_thread_race.rs index c37f303bbab2..172b05bd4f0b 100644 --- a/tests/compile-fail/data_race/dangling_thread_race.rs +++ b/tests/compile-fail/data_race/dangling_thread_race.rs @@ -29,9 +29,9 @@ fn main() { sleep(Duration::from_millis(100)); // Spawn and immediately join a thread - // to execute the join code-path - // and ensure that data-race detection - // remains enabled + // to execute the join code-path + // and ensure that data-race detection + // remains enabled nevertheless. spawn(|| ()).join().unwrap(); diff --git a/tests/compile-fail/data_race/enable_after_join_to_main.rs b/tests/compile-fail/data_race/enable_after_join_to_main.rs index fba7ba4841cc..c29431777137 100644 --- a/tests/compile-fail/data_race/enable_after_join_to_main.rs +++ b/tests/compile-fail/data_race/enable_after_join_to_main.rs @@ -9,7 +9,7 @@ unsafe impl Send for EvilSend {} unsafe impl Sync for EvilSend {} pub fn main() { - // Enable and the join with multiple threads + // Enable and then join with multiple threads. let t1 = spawn(|| ()); let t2 = spawn(|| ()); let t3 = spawn(|| ()); @@ -19,7 +19,7 @@ pub fn main() { t3.join().unwrap(); t4.join().unwrap(); - // Perform write-write data race detection + // Perform write-write data race detection. let mut a = 0u32; let b = &mut a as *mut u32; let c = EvilSend(b); diff --git a/tests/compile-fail/data_race/relax_acquire_race.rs b/tests/compile-fail/data_race/relax_acquire_race.rs index 4b736e57208a..2ae0aacbcf77 100644 --- a/tests/compile-fail/data_race/relax_acquire_race.rs +++ b/tests/compile-fail/data_race/relax_acquire_race.rs @@ -16,6 +16,13 @@ pub fn main() { let b = &mut a as *mut u32; let c = EvilSend(b); + // Note: this is scheduler-dependent + // the operations need to occur in + // order: + // 1. store release : 1 + // 2. load acquire : 1 + // 3. store relaxed : 2 + // 4. load acquire : 2 unsafe { let j1 = spawn(move || { *c.0 = 1; diff --git a/tests/compile-fail/data_race/release_seq_race.rs b/tests/compile-fail/data_race/release_seq_race.rs index 0278e9864353..59263cb71204 100644 --- a/tests/compile-fail/data_race/release_seq_race.rs +++ b/tests/compile-fail/data_race/release_seq_race.rs @@ -18,6 +18,14 @@ pub fn main() { let b = &mut a as *mut u32; let c = EvilSend(b); + // Note: this is scheduler-dependent + // the operations need to occur in + // order, the sleep operations currently + // force the desired ordering: + // 1. store release : 1 + // 2. store relaxed : 2 + // 3. store relaxed : 3 + // 4. load acquire : 3 unsafe { let j1 = spawn(move || { *c.0 = 1; diff --git a/tests/compile-fail/data_race/rmw_race.rs b/tests/compile-fail/data_race/rmw_race.rs index c533f595f160..e523f8b374cc 100644 --- a/tests/compile-fail/data_race/rmw_race.rs +++ b/tests/compile-fail/data_race/rmw_race.rs @@ -16,6 +16,13 @@ pub fn main() { let b = &mut a as *mut u32; let c = EvilSend(b); + // Note: this is scheduler-dependent + // the operations need to occur in + // order: + // 1. store release : 1 + // 2. RMW relaxed : 1 -> 2 + // 3. store relaxed : 3 + // 4. load acquire : 3 unsafe { let j1 = spawn(move || { *c.0 = 1; diff --git a/tests/run-pass/concurrency/data_race.stderr b/tests/run-pass/concurrency/data_race.stderr index 7ba8087a9b4b..03676519d4f1 100644 --- a/tests/run-pass/concurrency/data_race.stderr +++ b/tests/run-pass/concurrency/data_race.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental, no weak memory effects are currently emulated. +warning: thread support is experimental and incomplete: weak memory effects are not emulated. diff --git a/tests/run-pass/concurrency/disable_data_race_detector.rs b/tests/run-pass/concurrency/disable_data_race_detector.rs index e47a2079c205..8b2d180f11d4 100644 --- a/tests/run-pass/concurrency/disable_data_race_detector.rs +++ b/tests/run-pass/concurrency/disable_data_race_detector.rs @@ -19,7 +19,7 @@ pub fn main() { }); let j2 = spawn(move || { - *c.0 = 64; //~ ERROR Data race + *c.0 = 64; //~ ERROR Data race (but not detected as the detector is disabled) }); j1.join().unwrap(); diff --git a/tests/run-pass/concurrency/disable_data_race_detector.stderr b/tests/run-pass/concurrency/disable_data_race_detector.stderr index 7ba8087a9b4b..03676519d4f1 100644 --- a/tests/run-pass/concurrency/disable_data_race_detector.stderr +++ b/tests/run-pass/concurrency/disable_data_race_detector.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental, no weak memory effects are currently emulated. +warning: thread support is experimental and incomplete: weak memory effects are not emulated. diff --git a/tests/run-pass/concurrency/linux-futex.stderr b/tests/run-pass/concurrency/linux-futex.stderr index 7ba8087a9b4b..03676519d4f1 100644 --- a/tests/run-pass/concurrency/linux-futex.stderr +++ b/tests/run-pass/concurrency/linux-futex.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental, no weak memory effects are currently emulated. +warning: thread support is experimental and incomplete: weak memory effects are not emulated. diff --git a/tests/run-pass/concurrency/simple.stderr b/tests/run-pass/concurrency/simple.stderr index 24444fdc17c1..f46b1442d749 100644 --- a/tests/run-pass/concurrency/simple.stderr +++ b/tests/run-pass/concurrency/simple.stderr @@ -1,4 +1,4 @@ -warning: thread support is experimental, no weak memory effects are currently emulated. +warning: thread support is experimental and incomplete: weak memory effects are not emulated. thread '' panicked at 'Hello!', $DIR/simple.rs:54:9 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/concurrency/sync.stderr b/tests/run-pass/concurrency/sync.stderr index 7ba8087a9b4b..03676519d4f1 100644 --- a/tests/run-pass/concurrency/sync.stderr +++ b/tests/run-pass/concurrency/sync.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental, no weak memory effects are currently emulated. +warning: thread support is experimental and incomplete: weak memory effects are not emulated. diff --git a/tests/run-pass/concurrency/thread_locals.stderr b/tests/run-pass/concurrency/thread_locals.stderr index 7ba8087a9b4b..03676519d4f1 100644 --- a/tests/run-pass/concurrency/thread_locals.stderr +++ b/tests/run-pass/concurrency/thread_locals.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental, no weak memory effects are currently emulated. +warning: thread support is experimental and incomplete: weak memory effects are not emulated. diff --git a/tests/run-pass/concurrency/tls_lib_drop.stderr b/tests/run-pass/concurrency/tls_lib_drop.stderr index 7ba8087a9b4b..03676519d4f1 100644 --- a/tests/run-pass/concurrency/tls_lib_drop.stderr +++ b/tests/run-pass/concurrency/tls_lib_drop.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental, no weak memory effects are currently emulated. +warning: thread support is experimental and incomplete: weak memory effects are not emulated. diff --git a/tests/run-pass/libc.stderr b/tests/run-pass/libc.stderr index 7ba8087a9b4b..03676519d4f1 100644 --- a/tests/run-pass/libc.stderr +++ b/tests/run-pass/libc.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental, no weak memory effects are currently emulated. +warning: thread support is experimental and incomplete: weak memory effects are not emulated. diff --git a/tests/run-pass/panic/concurrent-panic.stderr b/tests/run-pass/panic/concurrent-panic.stderr index 885385a8dd93..1ee688c1d32c 100644 --- a/tests/run-pass/panic/concurrent-panic.stderr +++ b/tests/run-pass/panic/concurrent-panic.stderr @@ -1,4 +1,4 @@ -warning: thread support is experimental, no weak memory effects are currently emulated. +warning: thread support is experimental and incomplete: weak memory effects are not emulated. Thread 1 starting, will block on mutex Thread 1 reported it has started From 6c5722933e5233b4b64134680baae1f48e1e47ea Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Sat, 28 Nov 2020 17:17:07 +0000 Subject: [PATCH 2457/5092] Fix typos - looked into the papers handling of timestamps, after looking into it again, it seems the paper only increments the timestamp after release operations, so changed to approximation of that implementation. --- src/data_race.rs | 56 +++++++++++++++++++---------------------- src/shims/posix/sync.rs | 16 ------------ 2 files changed, 26 insertions(+), 46 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index 3f70631d1362..49332721fcbd 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -39,21 +39,14 @@ //! //! The timestamps used in the data-race detector assign each sequence of non-atomic operations //! followed by a single atomic or concurrent operation a single timestamp. -//! Write, Read, Write, ThreadJoin will be represented by a single timestamp value on a thread +//! Write, Read, Write, ThreadJoin will be represented by a single timestamp value on a thread. //! This is because extra increment operations between the operations in the sequence are not //! required for accurate reporting of data-race values. //! -//! If the timestamp was not incremented after the atomic operation, then data-races would not be detected: -//! Example - this should report a data-race but does not: -//! t1: (x,0), atomic[release A], t1=(x+1, 0 ), write(var B), -//! t2: (0,y) , atomic[acquire A], t2=(x+1, y+1), ,write(var B) -//! -//! The timestamp is not incremented before an atomic operation, since the result is indistinguishable -//! from the value not being incremented. -//! t: (x, 0), atomic[release _], (x + 1, 0) || (0, y), atomic[acquire _], (x, _) -//! vs t: (x, 0), atomic[release _], (x + 1, 0) || (0, y), atomic[acquire _], (x+1, _) -//! Both result in the sequence on thread x up to and including the atomic release as happening -//! before the acquire. +//! As per the paper a threads timestamp is only incremented after a release operation is performed +//! so some atomic operations that only perform acquires do not increment the timestamp, due to shared +//! code some atomic operations may increment the timestamp when not necessary but this has no effect +//! on the data-race detection code. //! //! FIXME: //! currently we have our own local copy of the currently active thread index and names, this is due @@ -516,7 +509,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { Ok(old) } - /// Perform an atomic compare and exchange at a given memory location + /// Perform an atomic compare and exchange at a given memory location. /// On success an atomic RMW operation is performed and on failure /// only an atomic read occurs. fn atomic_compare_exchange_scalar( @@ -640,7 +633,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // Either Release | AcqRel | SeqCst clocks.apply_release_fence(); } - Ok(()) + + // Increment timestamp if hase release semantics + Ok(atomic != AtomicFenceOp::Acquire) }) } else { Ok(()) @@ -651,9 +646,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// Vector clock metadata for a logical memory allocation. #[derive(Debug, Clone)] pub struct VClockAlloc { - /// Range of Vector clocks, this gives each byte a potentially - /// unqiue set of vector clocks, but merges identical information - /// together for improved efficiency. + /// Assigning each byte a MemoryCellClocks. alloc_ranges: RefCell>, // Pointer to global state. @@ -935,10 +928,12 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { true, place_ptr, size, - ); + ).map(|_| true); } } - Ok(()) + + // This conservatively assumes all operations have release semantics + Ok(true) })?; // Log changes to atomic memory. @@ -1159,6 +1154,7 @@ impl GlobalState { created.join_with(current); // Advance both threads after the synchronized operation. + // Both operations are considered to have release semantics. current.increment_clock(current_index); created.increment_clock(created_index); } @@ -1185,11 +1181,9 @@ impl GlobalState { // The join thread happens-before the current thread // so update the current vector clock. + // Is not a release operation so the clock is not incremented. current.clock.join(join_clock); - // Increment clocks after atomic operation. - current.increment_clock(current_index); - // Check the number of active threads, if the value is 1 // then test for potentially disabling multi-threaded execution. let active_threads = self.active_thread_count.get(); @@ -1287,13 +1281,14 @@ impl GlobalState { /// operation may create. fn maybe_perform_sync_operation<'tcx>( &self, - op: impl FnOnce(VectorIdx, RefMut<'_, ThreadClockSet>) -> InterpResult<'tcx>, + op: impl FnOnce(VectorIdx, RefMut<'_, ThreadClockSet>) -> InterpResult<'tcx, bool>, ) -> InterpResult<'tcx> { if self.multi_threaded.get() { let (index, clocks) = self.current_thread_state_mut(); - op(index, clocks)?; - let (_, mut clocks) = self.current_thread_state_mut(); - clocks.increment_clock(index); + if op(index, clocks)? { + let (_, mut clocks) = self.current_thread_state_mut(); + clocks.increment_clock(index); + } } Ok(()) } @@ -1313,10 +1308,11 @@ impl GlobalState { /// Acquire a lock, express that the previous call of /// `validate_lock_release` must happen before this. + /// As this is an acquire operation, the thread timestamp is not + /// incremented. pub fn validate_lock_acquire(&self, lock: &VClock, thread: ThreadId) { - let (index, mut clocks) = self.load_thread_state_mut(thread); + let (_, mut clocks) = self.load_thread_state_mut(thread); clocks.clock.join(&lock); - clocks.increment_clock(index); } /// Release a lock handle, express that this happens-before @@ -1335,8 +1331,8 @@ impl GlobalState { /// any subsequent calls to `validate_lock_acquire` as well /// as any previous calls to this function after any /// `validate_lock_release` calls. - /// For normal locks this should be equivalent to `validate_lock_release` - /// this function only exists for joining over the set of concurrent readers + /// For normal locks this should be equivalent to `validate_lock_release`. + /// This function only exists for joining over the set of concurrent readers /// in a read-write lock and should not be used for anything else. pub fn validate_lock_release_shared(&self, lock: &mut VClock, thread: ThreadId) { let (index, mut clocks) = self.load_thread_state_mut(thread); diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index efa441299194..868c72289a1a 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -62,8 +62,6 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>( mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - //FIXME: this has been made atomic to fix data-race reporting inside the internal - // mutex implementation, it may not need to be atomic. ecx.read_scalar_at_offset_atomic( mutex_op, offset, ecx.machine.layouts.i32, AtomicReadOp::Relaxed @@ -76,8 +74,6 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( kind: impl Into>, ) -> InterpResult<'tcx, ()> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - //FIXME: this has been made atomic to fix data-race reporting inside the internal - // mutex implementation, it may not need to be atomic. ecx.write_scalar_at_offset_atomic( mutex_op, offset, kind, ecx.machine.layouts.i32, AtomicWriteOp::Relaxed @@ -88,8 +84,6 @@ fn mutex_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - //FIXME: this has been made atomic to fix data-race reporting inside the internal - // mutex implementation, it may not need to be atomic. ecx.read_scalar_at_offset_atomic( mutex_op, 4, ecx.machine.layouts.u32, AtomicReadOp::Relaxed @@ -101,8 +95,6 @@ fn mutex_set_id<'mir, 'tcx: 'mir>( mutex_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { - //FIXME: this has been made atomic to fix data-race reporting inside the internal - // mutex implementation, it may not need to be atomic. ecx.write_scalar_at_offset_atomic( mutex_op, 4, id, ecx.machine.layouts.u32, AtomicWriteOp::Relaxed @@ -135,8 +127,6 @@ fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( fn rwlock_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, - //FIXME: this has been made atomic to fix data-race reporting inside the internal - // rw-lock implementation, it may not need to be atomic. ) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset_atomic( rwlock_op, 4, ecx.machine.layouts.u32, @@ -149,8 +139,6 @@ fn rwlock_set_id<'mir, 'tcx: 'mir>( rwlock_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { - //FIXME: this has been made atomic to fix data-race reporting inside the internal - // rw-lock implementation, it may not need to be atomic. ecx.write_scalar_at_offset_atomic( rwlock_op, 4, id, ecx.machine.layouts.u32, AtomicWriteOp::Relaxed @@ -207,8 +195,6 @@ fn cond_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, cond_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - //FIXME: this has been made atomic to fix data-race reporting inside the internal - // cond-var implementation, it may not need to be atomic. ecx.read_scalar_at_offset_atomic( cond_op, 4, ecx.machine.layouts.u32, AtomicReadOp::Relaxed @@ -220,8 +206,6 @@ fn cond_set_id<'mir, 'tcx: 'mir>( cond_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { - //FIXME: this has been made atomic to fix data-race reporting inside the internal - // cond-var implementation, it may not need to be atomic. ecx.write_scalar_at_offset_atomic( cond_op, 4, id, ecx.machine.layouts.u32, AtomicWriteOp::Relaxed From cbb695f782dceca959661e9c57d7aeb120cbc1d8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 Nov 2020 19:43:44 +0100 Subject: [PATCH 2458/5092] fix some typos --- src/data_race.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index 49332721fcbd..aca735e6f222 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -44,7 +44,7 @@ //! required for accurate reporting of data-race values. //! //! As per the paper a threads timestamp is only incremented after a release operation is performed -//! so some atomic operations that only perform acquires do not increment the timestamp, due to shared +//! so some atomic operations that only perform acquires do not increment the timestamp. Due to shared //! code some atomic operations may increment the timestamp when not necessary but this has no effect //! on the data-race detection code. //! @@ -634,7 +634,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { clocks.apply_release_fence(); } - // Increment timestamp if hase release semantics + // Increment timestamp in case of release semantics. Ok(atomic != AtomicFenceOp::Acquire) }) } else { From d697de7538c2ec33968663ab4ed8756bfcc17c6e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 Nov 2020 20:54:56 +0100 Subject: [PATCH 2459/5092] update README --- README.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 578ca0251c5e..02a64b3d5f7d 100644 --- a/README.md +++ b/README.md @@ -43,16 +43,15 @@ in your program, and cannot run all programs: still run fine in Miri -- but might break (including causing UB) on different compiler versions or different platforms. * Program execution is non-deterministic when it depends, for example, on where - exactly in memory allocations end up. Miri tests one of many possible - executions of your program. If your code is sensitive to allocation base - addresses or other non-deterministic data, try running Miri with different - values for `-Zmiri-seed` to test different executions. + exactly in memory allocations end up, or on the exact interleaving of + concurrent threads. Miri tests one of many possible executions of your + program. You can alleviate this to some extend by running Miri with different + values for `-Zmiri-seed`, but that will still by far not explore all possible + executions. * Miri runs the program as a platform-independent interpreter, so the program has no access to most platform-specific APIs or FFI. A few APIs have been implemented (such as printing to stdout) but most have not: for example, Miri currently does not support SIMD or networking. -* Miri currently does not check for data-races and most other concurrency-related - issues. [rust]: https://www.rust-lang.org/ [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md From 6145709bfc5b0a298d957a7f705a3c64d63421a5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 Nov 2020 21:00:50 +0100 Subject: [PATCH 2460/5092] remove miri-rustc-tests --- Cargo.toml | 9 -- rust-version | 2 +- src/bin/miri-rustc-tests.rs | 260 ------------------------------------ 3 files changed, 1 insertion(+), 270 deletions(-) delete mode 100644 src/bin/miri-rustc-tests.rs diff --git a/Cargo.toml b/Cargo.toml index 4413dab321e7..7580d140b55f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,12 +17,6 @@ name = "miri" test = false # we have no unit tests doctest = false # and no doc tests -[[bin]] -name = "miri-rustc-tests" -test = false # we have no unit tests -doctest = false # and no doc tests -required-features = ["rustc_tests"] - [dependencies] getrandom = { version = "0.2", features = ["std"] } env_logger = "0.7.1" @@ -46,6 +40,3 @@ libc = "0.2" compiletest_rs = { version = "0.5", features = ["tmp"] } rustc_version = "0.2.3" colored = "2" - -[features] -rustc_tests = [] diff --git a/rust-version b/rust-version index c3173f6245b6..485cc2dd4b9f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -828461b4b27c4a955587887936e54057efc5e2c1 +88b81970ba7a989a728b32039dd075dc206f1360 diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs deleted file mode 100644 index cef71a9889f1..000000000000 --- a/src/bin/miri-rustc-tests.rs +++ /dev/null @@ -1,260 +0,0 @@ -#![feature(rustc_private)] - -extern crate rustc_middle; -extern crate rustc_driver; -extern crate rustc_hir; -extern crate rustc_interface; -extern crate rustc_span; - -use std::io; -use std::io::Write; -use std::path::Path; -use std::sync::{Arc, Mutex}; - -use rustc_middle::ty::TyCtxt; -use rustc_driver::Compilation; -use rustc_hir as hir; -use rustc_hir::def_id::LOCAL_CRATE; -use rustc_hir::itemlikevisit; -use rustc_interface::{interface, Queries}; - -struct MiriCompilerCalls { - /// whether we are building for the host - host_target: bool, -} - -impl rustc_driver::Callbacks for MiriCompilerCalls { - fn after_analysis<'tcx>( - &mut self, - compiler: &interface::Compiler, - queries: &'tcx Queries<'tcx>, - ) -> Compilation { - compiler.session().abort_if_errors(); - queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { - if std::env::args().any(|arg| arg == "--test") { - struct Visitor<'tcx>(TyCtxt<'tcx>); - impl<'tcx, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'tcx> { - fn visit_item(&mut self, i: &'hir hir::Item) { - if let hir::ItemKind::Fn(.., body_id) = i.kind { - if i.attrs - .iter() - .any(|attr| self.0.sess.check_name(attr, rustc_span::symbol::sym::test)) - { - let config = miri::MiriConfig::default(); - let did = self.0.hir().body_owner_def_id(body_id).to_def_id(); - println!("running test: {}", self.0.def_path_debug_str(did)); - miri::eval_main(self.0, did, config); - self.0.sess.abort_if_errors(); - } - } - } - fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {} - fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {} - } - tcx.hir().krate().visit_all_item_likes(&mut Visitor(tcx)); - } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { - let config = miri::MiriConfig::default(); - miri::eval_main(tcx, entry_def_id.to_def_id(), config); - - compiler.session().abort_if_errors(); - } else { - println!("no main function found, assuming auxiliary build"); - } - }); - - // Continue execution on host target - if self.host_target { Compilation::Continue } else { Compilation::Stop } - } -} - -fn main() { - let path = option_env!("MIRI_RUSTC_TEST").map(String::from).unwrap_or_else(|| { - std::env::var("MIRI_RUSTC_TEST") - .expect("need to set MIRI_RUSTC_TEST to path of rustc tests") - }); - - let mut mir_not_found = Vec::new(); - let mut crate_not_found = Vec::new(); - let mut success = 0; - let mut failed = Vec::new(); - let mut c_abi_fns = Vec::new(); - let mut abi = Vec::new(); - let mut unsupported = Vec::new(); - let mut unimplemented_intrinsic = Vec::new(); - let mut limits = Vec::new(); - let mut files: Vec<_> = std::fs::read_dir(path).unwrap().collect(); - while let Some(file) = files.pop() { - let file = file.unwrap(); - let path = file.path(); - if file.metadata().unwrap().is_dir() { - if !path.to_str().unwrap().ends_with("auxiliary") { - // add subdirs recursively - files.extend(std::fs::read_dir(path).unwrap()); - } - continue; - } - if !file.metadata().unwrap().is_file() || !path.to_str().unwrap().ends_with(".rs") { - continue; - } - let stderr = std::io::stderr(); - write!(stderr.lock(), "test [miri-pass] {} ... ", path.display()).unwrap(); - let mut host_target = false; - let mut args: Vec = std::env::args() - .filter(|arg| { - if arg == "--miri_host_target" { - host_target = true; - false // remove the flag, rustc doesn't know it - } else { - true - } - }) - .collect(); - args.splice(1..1, miri::MIRI_DEFAULT_ARGS.iter().map(ToString::to_string)); - // file to process - args.push(path.display().to_string()); - - let sysroot_flag = String::from("--sysroot"); - if !args.contains(&sysroot_flag) { - args.push(sysroot_flag); - args.push( - Path::new(&std::env::var("HOME").unwrap()) - .join(".xargo") - .join("HOST") - .display() - .to_string(), - ); - } - - // A threadsafe buffer for writing. - #[derive(Default, Clone)] - struct BufWriter(Arc>>); - - impl Write for BufWriter { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.lock().unwrap().write(buf) - } - fn flush(&mut self) -> io::Result<()> { - self.0.lock().unwrap().flush() - } - } - let buf = BufWriter::default(); - let output = buf.clone(); - let result = std::panic::catch_unwind(|| { - let mut callbacks = MiriCompilerCalls { host_target }; - let mut run = rustc_driver::RunCompiler::new(&args, &mut callbacks); - run.set_emitter(Some(Box::new(buf))); - let _ = run.run(); - }); - - match result { - Ok(()) => { - success += 1; - writeln!(stderr.lock(), "ok").unwrap() - } - Err(_) => { - let output = output.0.lock().unwrap(); - let output_err = std::str::from_utf8(&output).unwrap(); - if let Some(text) = output_err.splitn(2, "no mir for `").nth(1) { - let end = text.find('`').unwrap(); - mir_not_found.push(text[..end].to_string()); - writeln!(stderr.lock(), "NO MIR FOR `{}`", &text[..end]).unwrap(); - } else if let Some(text) = output_err.splitn(2, "can't find crate for `").nth(1) { - let end = text.find('`').unwrap(); - crate_not_found.push(text[..end].to_string()); - writeln!(stderr.lock(), "CAN'T FIND CRATE FOR `{}`", &text[..end]).unwrap(); - } else { - for text in output_err.split("error: ").skip(1) { - let end = text.find('\n').unwrap_or(text.len()); - let c_abi = "can't call C ABI function: "; - let unimplemented_intrinsic_s = "unimplemented intrinsic: "; - let unsupported_s = "miri does not support "; - let abi_s = "can't handle function with "; - let limit_s = "reached the configured maximum "; - if text.starts_with(c_abi) { - c_abi_fns.push(text[c_abi.len()..end].to_string()); - } else if text.starts_with(unimplemented_intrinsic_s) { - unimplemented_intrinsic - .push(text[unimplemented_intrinsic_s.len()..end].to_string()); - } else if text.starts_with(unsupported_s) { - unsupported.push(text[unsupported_s.len()..end].to_string()); - } else if text.starts_with(abi_s) { - abi.push(text[abi_s.len()..end].to_string()); - } else if text.starts_with(limit_s) { - limits.push(text[limit_s.len()..end].to_string()); - } else if text.find("aborting").is_none() { - failed.push(text[..end].to_string()); - } - } - writeln!(stderr.lock(), "stderr: \n {}", output_err).unwrap(); - } - } - } - } - let stderr = std::io::stderr(); - let mut stderr = stderr.lock(); - writeln!( - stderr, - "{} success, {} no mir, {} crate not found, {} failed, {} C fn, {} ABI, {} unsupported, {} intrinsic", - success, - mir_not_found.len(), - crate_not_found.len(), - failed.len(), - c_abi_fns.len(), - abi.len(), - unsupported.len(), - unimplemented_intrinsic.len() - ) - .unwrap(); - writeln!(stderr, "# The \"other reasons\" errors").unwrap(); - writeln!(stderr, "(sorted, deduplicated)").unwrap(); - print_vec(&mut stderr, failed); - - writeln!(stderr, "# can't call C ABI function").unwrap(); - print_vec(&mut stderr, c_abi_fns); - - writeln!(stderr, "# unsupported ABI").unwrap(); - print_vec(&mut stderr, abi); - - writeln!(stderr, "# unsupported").unwrap(); - print_vec(&mut stderr, unsupported); - - writeln!(stderr, "# unimplemented intrinsics").unwrap(); - print_vec(&mut stderr, unimplemented_intrinsic); - - writeln!(stderr, "# mir not found").unwrap(); - print_vec(&mut stderr, mir_not_found); - - writeln!(stderr, "# crate not found").unwrap(); - print_vec(&mut stderr, crate_not_found); -} - -fn print_vec(stderr: &mut W, v: Vec) { - writeln!(stderr, "```").unwrap(); - for (n, s) in vec_to_hist(v).into_iter().rev() { - writeln!(stderr, "{:4} {}", n, s).unwrap(); - } - writeln!(stderr, "```").unwrap(); -} - -fn vec_to_hist(mut v: Vec) -> Vec<(usize, T)> { - v.sort(); - let mut v = v.into_iter(); - let mut result = Vec::new(); - let mut current = v.next(); - 'outer: while let Some(current_val) = current { - let mut n = 1; - for next in &mut v { - if next == current_val { - n += 1; - } else { - result.push((n, current_val)); - current = Some(next); - continue 'outer; - } - } - result.push((n, current_val)); - break; - } - result.sort(); - result -} From de5b26d7f03208f4fb18872772da4a7ff52f57df Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 4 Dec 2020 23:52:13 +0100 Subject: [PATCH 2461/5092] Use new std::alloc::Allocator interface. This was changed in core. --- rust-version | 2 +- tests/run-pass/heap_allocator.rs | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/rust-version b/rust-version index 485cc2dd4b9f..58948e2fc69a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -88b81970ba7a989a728b32039dd075dc206f1360 +3ff10e74a74ed093fcabac1de27fe1cd65bbbb4a diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index 5d89243b86a9..e428868af78b 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -1,22 +1,22 @@ #![feature(allocator_api, slice_ptr_get)] use std::ptr::NonNull; -use std::alloc::{Global, AllocRef, Layout, System}; +use std::alloc::{Global, Allocator, Layout, System}; use std::slice; -fn check_alloc(allocator: T) { unsafe { +fn check_alloc(allocator: T) { unsafe { for &align in &[4, 8, 16, 32] { let layout_20 = Layout::from_size_align(20, align).unwrap(); let layout_40 = Layout::from_size_align(40, 4*align).unwrap(); let layout_10 = Layout::from_size_align(10, align/2).unwrap(); for _ in 0..32 { - let a = allocator.alloc(layout_20).unwrap().as_non_null_ptr(); + let a = allocator.allocate(layout_20).unwrap().as_non_null_ptr(); assert_eq!(a.as_ptr() as usize % layout_20.align(), 0, "pointer is incorrectly aligned"); - allocator.dealloc(a, layout_20); + allocator.deallocate(a, layout_20); } - let p1 = allocator.alloc_zeroed(layout_20).unwrap().as_non_null_ptr(); + let p1 = allocator.allocate_zeroed(layout_20).unwrap().as_non_null_ptr(); assert_eq!(p1.as_ptr() as usize % layout_20.align(), 0, "pointer is incorrectly aligned"); assert_eq!(*p1.as_ptr(), 0); @@ -38,17 +38,17 @@ fn check_alloc(allocator: T) { unsafe { let slice = slice::from_raw_parts(p4.as_ptr(), 10); assert_eq!(&slice, &[0_u8; 10]); - allocator.dealloc(p4, layout_10); + allocator.deallocate(p4, layout_10); } } } -fn check_align_requests(allocator: T) { +fn check_align_requests(allocator: T) { for &size in &[2, 8, 64] { // size less than and bigger than alignment for &align in &[4, 8, 16, 32] { // Be sure to cover less than and bigger than `MIN_ALIGN` for all architectures let iterations = 32; unsafe { let pointers: Vec<_> = (0..iterations).map(|_| { - allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap().as_non_null_ptr() + allocator.allocate(Layout::from_size_align(size, align).unwrap()).unwrap().as_non_null_ptr() }).collect(); for &ptr in &pointers { assert_eq!((ptr.as_ptr() as usize) % align, 0, @@ -57,7 +57,7 @@ fn check_align_requests(allocator: T) { // Clean up. for &ptr in &pointers { - allocator.dealloc(ptr, Layout::from_size_align(size, align).unwrap()) + allocator.deallocate(ptr, Layout::from_size_align(size, align).unwrap()) } } } @@ -69,7 +69,7 @@ fn global_to_box() { let l = Layout::new::(); // allocate manually with global allocator, then turn into Box and free there unsafe { - let ptr = Global.alloc(l).unwrap().as_non_null_ptr().as_ptr() as *mut T; + let ptr = Global.allocate(l).unwrap().as_non_null_ptr().as_ptr() as *mut T; let b = Box::from_raw(ptr); drop(b); } @@ -82,7 +82,7 @@ fn box_to_global() { unsafe { let b = Box::new(T::default()); let ptr = Box::into_raw(b); - Global.dealloc(NonNull::new(ptr as *mut u8).unwrap(), l); + Global.deallocate(NonNull::new(ptr as *mut u8).unwrap(), l); } } From 7fb012fdb2608c51f2eba7f2ec00525b4d3cd6ad Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Dec 2020 12:14:52 +0100 Subject: [PATCH 2462/5092] readme: mention data races, and mention cross-interpretation already in the intro --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 02a64b3d5f7d..3a8524ec01d3 100644 --- a/README.md +++ b/README.md @@ -20,11 +20,18 @@ for example: or an invalid enum discriminant) * **Experimental**: Violations of the [Stacked Borrows] rules governing aliasing for reference types +* **Experimental**: Data races (but no weak memory effects) On top of that, Miri will also tell you about memory leaks: when there is memory still allocated at the end of the execution, and that memory is not reachable from a global `static`, Miri will raise an error. +You can use Miri to emulate programs on other targets, e.g. to ensure that +byte-level data manipulation works correctly both on little-endian and +big-endian systems. See +[cross-interpretation](#cross-interpretation-running-for-different-targets) +below. + Miri has already discovered some [real-world bugs](#bugs-found-by-miri). If you found a bug with Miri, we'd appreciate if you tell us and we'll add it to the list! From 4cf614ef3301a5c9f93a4e51b8b603b4d0b0b5ad Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Sun, 6 Dec 2020 16:58:32 +0000 Subject: [PATCH 2463/5092] Update release sequence handling to C++20 semantics. --- src/data_race.rs | 71 ++++--- src/lib.rs | 2 +- src/vector_clock.rs | 189 +----------------- .../data_race/release_seq_race_same_thread.rs | 49 +++++ tests/run-pass/concurrency/data_race.rs | 7 +- 5 files changed, 89 insertions(+), 229 deletions(-) create mode 100644 tests/compile-fail/data_race/release_seq_race_same_thread.rs diff --git a/src/data_race.rs b/src/data_race.rs index aca735e6f222..d4438984a284 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -1,13 +1,18 @@ //! Implementation of a data-race detector using Lamport Timestamps / Vector-clocks -//! based on the Dyamic Race Detection for C++: +//! based on the Dynamic Race Detection for C++: //! https://www.doc.ic.ac.uk/~afd/homepages/papers/pdfs/2017/POPL.pdf //! which does not report false-positives when fences are used, and gives better //! accuracy in presence of read-modify-write operations. //! +//! The implementation contains modifications to correctly model the changes to the memory model in C++20 +//! regarding the weakening of release sequences: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0982r1.html. +//! Relaxed stores now unconditionally block all currently active release sequences and so per-thread tracking of release +//! sequences is not needed. +//! //! This does not explore weak memory orders and so can still miss data-races //! but should not report false-positives //! -//! Data-race definiton from(https://en.cppreference.com/w/cpp/language/memory_model#Threads_and_data_races): +//! Data-race definition from(https://en.cppreference.com/w/cpp/language/memory_model#Threads_and_data_races): //! a data race occurs between two memory accesses if they are on different threads, at least one operation //! is non-atomic, at least one operation is a write and neither access happens-before the other. Read the link //! for full definition. @@ -21,7 +26,7 @@ //! This means that the thread-index can be safely re-used, starting on the next timestamp for the newly created //! thread. //! -//! The sequentially consistant ordering corresponds to the ordering that the threads +//! The sequentially consistent ordering corresponds to the ordering that the threads //! are currently scheduled, this means that the data-race detector has no additional //! logic for sequentially consistent accesses at the moment since they are indistinguishable //! from acquire/release operations. If weak memory orderings are explored then this @@ -67,7 +72,7 @@ use rustc_target::abi::Size; use crate::{ ImmTy, Immediate, InterpResult, MPlaceTy, MemPlaceMeta, MiriEvalContext, MiriEvalContextExt, - OpTy, Pointer, RangeMap, ScalarMaybeUninit, Tag, ThreadId, VClock, VSmallClockMap, VTimestamp, + OpTy, Pointer, RangeMap, ScalarMaybeUninit, Tag, ThreadId, VClock, VTimestamp, VectorIdx, }; @@ -122,7 +127,7 @@ struct ThreadClockSet { /// thread once it performs an acquire fence. fence_acquire: VClock, - /// The last timesamp of happens-before relations that + /// The last timestamp of happens-before relations that /// have been released by this thread by a fence. fence_release: VClock, } @@ -185,13 +190,6 @@ struct AtomicMemoryCellClocks { /// happen-before a thread if an acquire-load is /// performed on the data. sync_vector: VClock, - - /// The Hash-Map of all threads for which a release - /// sequence exists in the memory cell, required - /// since read-modify-write operations do not - /// invalidate existing release sequences. - /// See page 6 of linked paper. - release_sequences: VSmallClockMap, } /// Memory Cell vector clock metadata @@ -207,7 +205,7 @@ struct MemoryCellClocks { write_index: VectorIdx, /// The vector-clock of the timestamp of the last read operation - /// performed by a thread since the last write operation occured. + /// performed by a thread since the last write operation occurred. /// It is reset to zero on each write operation. read: VClock, @@ -231,6 +229,7 @@ impl Default for MemoryCellClocks { } impl MemoryCellClocks { + /// Load the internal atomic memory cells if they exist. #[inline] fn atomic(&self) -> Option<&AtomicMemoryCellClocks> { @@ -283,8 +282,6 @@ impl MemoryCellClocks { self.atomic_write_detect(clocks, index)?; let atomic = self.atomic_mut(); atomic.sync_vector.clone_from(&clocks.clock); - atomic.release_sequences.clear(); - atomic.release_sequences.insert(index, &clocks.clock); Ok(()) } @@ -292,12 +289,13 @@ impl MemoryCellClocks { /// store relaxed semantics. fn store_relaxed(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { self.atomic_write_detect(clocks, index)?; + + // The handling of release sequences was changed in C++20 and so + // the code here is different to the paper since now all relaxed + // stored block release sequences, the exception for same-thread + // relaxed stores has been removed. let atomic = self.atomic_mut(); atomic.sync_vector.clone_from(&clocks.fence_release); - if let Some(release) = atomic.release_sequences.get(index) { - atomic.sync_vector.join(release); - } - atomic.release_sequences.retain_index(index); Ok(()) } @@ -307,7 +305,6 @@ impl MemoryCellClocks { self.atomic_write_detect(clocks, index)?; let atomic = self.atomic_mut(); atomic.sync_vector.join(&clocks.clock); - atomic.release_sequences.insert(index, &clocks.clock); Ok(()) } @@ -523,7 +520,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let this = self.eval_context_mut(); // Failure ordering cannot be stronger than success ordering, therefore first attempt - // to read with the failure ordering and if successfull then try again with the success + // to read with the failure ordering and if successful then try again with the success // read ordering and write in the success case. // Read as immediate for the sake of `binary_op()` let old = this.allow_data_races_mut(|this| this.read_immediate(place.into()))?; @@ -546,7 +543,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { Ok(res) } - /// Update the data-race detector for an atomic read occuring at the + /// Update the data-race detector for an atomic read occurring at the /// associated memory-place and on the current thread. fn validate_atomic_load( &self, @@ -568,7 +565,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) } - /// Update the data-race detector for an atomic write occuring at the + /// Update the data-race detector for an atomic write occurring at the /// associated memory-place and on the current thread. fn validate_atomic_store( &mut self, @@ -590,7 +587,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) } - /// Update the data-race detector for an atomic read-modify-write occuring + /// Update the data-race detector for an atomic read-modify-write occurring /// at the associated memory place and on the current thread. fn validate_atomic_rmw( &mut self, @@ -694,9 +691,9 @@ impl VClockAlloc { /// Report a data-race found in the program. /// This finds the two racing threads and the type - /// of data-race that occured. This will also + /// of data-race that occurred. This will also /// return info about the memory location the data-race - /// occured in. + /// occurred in. #[cold] #[inline(never)] fn report_data_race<'tcx>( @@ -762,7 +759,7 @@ impl VClockAlloc { ) } - /// Detect data-races for an unsychronized read operation, will not perform + /// Detect data-races for an unsynchronized read operation, will not perform /// data-race detection if `multi-threaded` is false, either due to no threads /// being created or if it is temporarily disabled during a racy read or write /// operation for which data-race detection is handled separately, for example @@ -818,7 +815,7 @@ impl VClockAlloc { } } - /// Detect data-races for an unsychronized write operation, will not perform + /// Detect data-races for an unsynchronized write operation, will not perform /// data-race threads if `multi-threaded` is false, either due to no threads /// being created or if it is temporarily disabled during a racy read or write /// operation @@ -826,7 +823,7 @@ impl VClockAlloc { self.unique_access(pointer, len, "Write") } - /// Detect data-races for an unsychronized deallocate operation, will not perform + /// Detect data-races for an unsynchronized deallocate operation, will not perform /// data-race threads if `multi-threaded` is false, either due to no threads /// being created or if it is temporarily disabled during a racy read or write /// operation @@ -838,7 +835,7 @@ impl VClockAlloc { impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // Temporarily allow data-races to occur, this should only be - // used if either one of the appropiate `validate_atomic` functions + // used if either one of the appropriate `validate_atomic` functions // will be called to treat a memory access as atomic or if the memory // being accessed should be treated as internal state, that cannot be // accessed by the interpreted program. @@ -1000,7 +997,7 @@ pub struct GlobalState { /// if a vector index is re-assigned to a new thread. vector_info: RefCell>, - /// The mapping of a given thread to assocaited thread metadata. + /// The mapping of a given thread to associated thread metadata. thread_info: RefCell>, /// The current vector index being executed. @@ -1017,7 +1014,7 @@ pub struct GlobalState { /// Counts the number of threads that are currently active /// if the number of active threads reduces to 1 and then - /// a join operation occures with the remaining main thread + /// a join operation occurs with the remaining main thread /// then multi-threaded execution may be disabled. active_thread_count: Cell, @@ -1160,7 +1157,7 @@ impl GlobalState { } /// Hook on a thread join to update the implicit happens-before relation - /// between the joined thead and the current thread. + /// between the joined thread and the current thread. #[inline] pub fn thread_joined(&self, current_thread: ThreadId, join_thread: ThreadId) { let mut clocks_vec = self.vector_clocks.borrow_mut(); @@ -1194,7 +1191,7 @@ impl GlobalState { .iter_enumerated() .all(|(idx, clocks)| clocks.clock[idx] <= current_clock.clock[idx]) { - // The all thread termations happen-before the current clock + // All thread terminations happen-before the current clock // therefore no data-races can be reported until a new thread // is created, so disable multi-threaded execution. self.multi_threaded.set(false); @@ -1213,7 +1210,7 @@ impl GlobalState { /// On thread termination, the vector-clock may re-used /// in the future once all remaining thread-clocks catch /// up with the time index of the terminated thread. - /// This assiges thread termination with a unique index + /// This assigns thread termination with a unique index /// which will be used to join the thread /// This should be called strictly before any calls to /// `thread_joined`. @@ -1318,8 +1315,8 @@ impl GlobalState { /// Release a lock handle, express that this happens-before /// any subsequent calls to `validate_lock_acquire`. /// For normal locks this should be equivalent to `validate_lock_release_shared` - /// since an acquire operation should have occured before, however - /// for futex & cond-var operations this is not the case and this + /// since an acquire operation should have occurred before, however + /// for futex & condvar operations this is not the case and this /// operation must be used. pub fn validate_lock_release(&self, lock: &mut VClock, thread: ThreadId) { let (index, mut clocks) = self.load_thread_state_mut(thread); diff --git a/src/lib.rs b/src/lib.rs index 87effe9c6885..581da0976e51 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -81,7 +81,7 @@ pub use crate::sync::{ EvalContextExt as SyncEvalContextExt, CondvarId, MutexId, RwLockId }; pub use crate::vector_clock::{ - VClock, VSmallClockMap, VectorIdx, VTimestamp + VClock, VectorIdx, VTimestamp }; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be diff --git a/src/vector_clock.rs b/src/vector_clock.rs index 6840d7e6cb99..1ce6511ee4ae 100644 --- a/src/vector_clock.rs +++ b/src/vector_clock.rs @@ -1,11 +1,9 @@ -use rustc_data_structures::fx::FxHashMap; use rustc_index::vec::Idx; use smallvec::SmallVec; use std::{ cmp::Ordering, convert::TryFrom, - fmt::{self, Debug}, - mem, + fmt::Debug, ops::Index, }; @@ -43,160 +41,6 @@ impl From for VectorIdx { } } -/// A sparse mapping of vector index values to vector clocks, this -/// is optimized for the common case with only one element stored -/// inside the map. -/// This is used to store the set of currently active release -/// sequences at a given memory location, since RMW operations -/// allow for multiple release sequences to be active at once -/// and to be collapsed back to one active release sequence -/// once a non RMW atomic store operation occurs. -/// An all zero vector is considered to be equal to no -/// element stored internally since it will never be -/// stored and has no meaning as a release sequence -/// vector clock. -#[derive(Clone)] -pub struct VSmallClockMap(VSmallClockMapInner); - -#[derive(Clone)] -enum VSmallClockMapInner { - /// Zero or 1 vector elements, common - /// case for the sparse set. - /// The all zero vector clock is treated - /// as equal to the empty element. - Small(VectorIdx, VClock), - - /// Hash-map of vector clocks. - Large(FxHashMap), -} - -impl VSmallClockMap { - /// Remove all clock vectors from the map, setting them - /// to the zero vector. - pub fn clear(&mut self) { - match &mut self.0 { - VSmallClockMapInner::Small(_, clock) => clock.set_zero_vector(), - VSmallClockMapInner::Large(hash_map) => { - hash_map.clear(); - } - } - } - - /// Remove all clock vectors except for the clock vector - /// stored at the given index, which is retained. - pub fn retain_index(&mut self, index: VectorIdx) { - match &mut self.0 { - VSmallClockMapInner::Small(small_idx, clock) => { - if index != *small_idx { - // The zero-vector is considered to equal - // the empty element. - clock.set_zero_vector() - } - } - VSmallClockMapInner::Large(hash_map) => { - let value = hash_map.remove(&index).unwrap_or_default(); - self.0 = VSmallClockMapInner::Small(index, value); - } - } - } - - /// Insert the vector clock into the associated vector - /// index. - pub fn insert(&mut self, index: VectorIdx, clock: &VClock) { - match &mut self.0 { - VSmallClockMapInner::Small(small_idx, small_clock) => { - if small_clock.is_zero_vector() { - *small_idx = index; - small_clock.clone_from(clock); - } else if !clock.is_zero_vector() { - // Convert to using the hash-map representation. - let mut hash_map = FxHashMap::default(); - hash_map.insert(*small_idx, mem::take(small_clock)); - hash_map.insert(index, clock.clone()); - self.0 = VSmallClockMapInner::Large(hash_map); - } - } - VSmallClockMapInner::Large(hash_map) => - if !clock.is_zero_vector() { - hash_map.insert(index, clock.clone()); - }, - } - } - - /// Try to load the vector clock associated with the current - /// vector index. - pub fn get(&self, index: VectorIdx) -> Option<&VClock> { - match &self.0 { - VSmallClockMapInner::Small(small_idx, small_clock) => { - if *small_idx == index && !small_clock.is_zero_vector() { - Some(small_clock) - } else { - None - } - } - VSmallClockMapInner::Large(hash_map) => hash_map.get(&index), - } - } -} - -impl Default for VSmallClockMap { - #[inline] - fn default() -> Self { - VSmallClockMap(VSmallClockMapInner::Small(VectorIdx::new(0), VClock::default())) - } -} - -impl Debug for VSmallClockMap { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // Print the contents of the small vector clock set as the map - // of vector index to vector clock that they represent. - let mut map = f.debug_map(); - match &self.0 { - VSmallClockMapInner::Small(small_idx, small_clock) => - if !small_clock.is_zero_vector() { - map.entry(&small_idx, &small_clock); - }, - VSmallClockMapInner::Large(hash_map) => - for (idx, elem) in hash_map.iter() { - map.entry(idx, elem); - }, - } - map.finish() - } -} - -impl PartialEq for VSmallClockMap { - fn eq(&self, other: &Self) -> bool { - use VSmallClockMapInner::*; - match (&self.0, &other.0) { - (Small(i1, c1), Small(i2, c2)) => { - if c1.is_zero_vector() { - // Either they are both zero or they are non-equal - c2.is_zero_vector() - } else { - // At least one is non-zero, so the full comparison is correct - i1 == i2 && c1 == c2 - } - } - (Small(idx, clock), Large(hash_map)) | (Large(hash_map), Small(idx, clock)) => { - if hash_map.len() == 0 { - // Equal to the empty hash-map - clock.is_zero_vector() - } else if hash_map.len() == 1 { - // Equal to the hash-map with one element - let (hash_idx, hash_clock) = hash_map.iter().next().unwrap(); - hash_idx == idx && hash_clock == clock - } else { - false - } - } - (Large(map1), Large(map2)) => map1 == map2, - } - } -} - -impl Eq for VSmallClockMap {} - /// The size of the vector-clock to store inline /// clock vectors larger than this will be stored on the heap const SMALL_VECTOR: usize = 4; @@ -484,7 +328,7 @@ impl Index for VClock { #[cfg(test)] mod tests { - use super::{VClock, VSmallClockMap, VTimestamp, VectorIdx}; + use super::{VClock, VTimestamp, VectorIdx}; use std::cmp::Ordering; #[test] @@ -628,33 +472,4 @@ mod tests { r ); } - - #[test] - pub fn test_vclock_set() { - let mut map = VSmallClockMap::default(); - let v1 = from_slice(&[3, 0, 1]); - let v2 = from_slice(&[4, 2, 3]); - let v3 = from_slice(&[4, 8, 3]); - map.insert(VectorIdx(0), &v1); - assert_eq!(map.get(VectorIdx(0)), Some(&v1)); - map.insert(VectorIdx(5), &v2); - assert_eq!(map.get(VectorIdx(0)), Some(&v1)); - assert_eq!(map.get(VectorIdx(5)), Some(&v2)); - map.insert(VectorIdx(53), &v3); - assert_eq!(map.get(VectorIdx(0)), Some(&v1)); - assert_eq!(map.get(VectorIdx(5)), Some(&v2)); - assert_eq!(map.get(VectorIdx(53)), Some(&v3)); - map.retain_index(VectorIdx(53)); - assert_eq!(map.get(VectorIdx(0)), None); - assert_eq!(map.get(VectorIdx(5)), None); - assert_eq!(map.get(VectorIdx(53)), Some(&v3)); - map.clear(); - assert_eq!(map.get(VectorIdx(0)), None); - assert_eq!(map.get(VectorIdx(5)), None); - assert_eq!(map.get(VectorIdx(53)), None); - map.insert(VectorIdx(53), &v3); - assert_eq!(map.get(VectorIdx(0)), None); - assert_eq!(map.get(VectorIdx(5)), None); - assert_eq!(map.get(VectorIdx(53)), Some(&v3)); - } } diff --git a/tests/compile-fail/data_race/release_seq_race_same_thread.rs b/tests/compile-fail/data_race/release_seq_race_same_thread.rs new file mode 100644 index 000000000000..a7cae5574dd3 --- /dev/null +++ b/tests/compile-fail/data_race/release_seq_race_same_thread.rs @@ -0,0 +1,49 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-isolation + +use std::thread::spawn; +use std::sync::atomic::{AtomicUsize, Ordering}; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +static SYNC: AtomicUsize = AtomicUsize::new(0); + +pub fn main() { + let mut a = 0u32; + let b = &mut a as *mut u32; + let c = EvilSend(b); + + // Note: this is scheduler-dependent + // the operations need to occur in + // order, the sleep operations currently + // force the desired ordering: + // 1. store release : 1 + // 2. store relaxed : 2 + // 3. load acquire : 2 + unsafe { + let j1 = spawn(move || { + *c.0 = 1; + SYNC.store(1, Ordering::Release); + + // C++20 update to release sequences + // makes this block the release sequence + // despite the same thread. + SYNC.store(2, Ordering::Relaxed); + }); + + let j2 = spawn(move || { + if SYNC.load(Ordering::Acquire) == 2 { + *c.0 //~ ERROR Data race + } else { + 0 + } + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/run-pass/concurrency/data_race.rs b/tests/run-pass/concurrency/data_race.rs index 64e90024ed49..b53acc2691ff 100644 --- a/tests/run-pass/concurrency/data_race.rs +++ b/tests/run-pass/concurrency/data_race.rs @@ -89,7 +89,7 @@ pub fn test_rmw_no_block() { } } -pub fn test_release_no_block() { +pub fn test_simple_release() { let mut a = 0u32; let b = &mut a as *mut u32; let c = EvilSend(b); @@ -98,11 +98,10 @@ pub fn test_release_no_block() { let j1 = spawn(move || { *c.0 = 1; SYNC.store(1, Ordering::Release); - SYNC.store(3, Ordering::Relaxed); }); let j2 = spawn(move || { - if SYNC.load(Ordering::Acquire) == 3 { + if SYNC.load(Ordering::Acquire) == 1 { *c.0 } else { 0 @@ -118,5 +117,5 @@ pub fn main() { test_fence_sync(); test_multiple_reads(); test_rmw_no_block(); - test_release_no_block(); + test_simple_release(); } From a6f377e48e57e43683fef86d8b84cf26ba989b83 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Sun, 6 Dec 2020 17:11:24 +0000 Subject: [PATCH 2464/5092] Fix typo --- tests/compile-fail/data_race/release_seq_race_same_thread.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/compile-fail/data_race/release_seq_race_same_thread.rs b/tests/compile-fail/data_race/release_seq_race_same_thread.rs index a7cae5574dd3..d64b80dbd84c 100644 --- a/tests/compile-fail/data_race/release_seq_race_same_thread.rs +++ b/tests/compile-fail/data_race/release_seq_race_same_thread.rs @@ -31,7 +31,8 @@ pub fn main() { // C++20 update to release sequences // makes this block the release sequence - // despite the same thread. + // despite the being on the same thread + // as the release store. SYNC.store(2, Ordering::Relaxed); }); From 6db821537f6900bfce2d46911c5243043d5700a0 Mon Sep 17 00:00:00 2001 From: JCTyblaidd Date: Sun, 6 Dec 2020 17:59:49 +0000 Subject: [PATCH 2465/5092] Fix caps Co-authored-by: Ralf Jung --- src/data_race.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data_race.rs b/src/data_race.rs index d4438984a284..aec22dadc1b6 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -292,7 +292,7 @@ impl MemoryCellClocks { // The handling of release sequences was changed in C++20 and so // the code here is different to the paper since now all relaxed - // stored block release sequences, the exception for same-thread + // stores block release sequences. The exception for same-thread // relaxed stores has been removed. let atomic = self.atomic_mut(); atomic.sync_vector.clone_from(&clocks.fence_release); From 789c8a006ba02ddad05513f47226406735ed33a5 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Sun, 6 Dec 2020 17:54:59 -0800 Subject: [PATCH 2466/5092] Fix README.md typo "extend" -> "extent" Just something I noticed while reading --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3a8524ec01d3..7c6b09968f47 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ in your program, and cannot run all programs: * Program execution is non-deterministic when it depends, for example, on where exactly in memory allocations end up, or on the exact interleaving of concurrent threads. Miri tests one of many possible executions of your - program. You can alleviate this to some extend by running Miri with different + program. You can alleviate this to some extent by running Miri with different values for `-Zmiri-seed`, but that will still by far not explore all possible executions. * Miri runs the program as a platform-independent interpreter, so the program From 2f0d7d38b44351525be19b14d73043468950cd71 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 10 Dec 2020 00:09:52 +0100 Subject: [PATCH 2467/5092] rustup; test AtomicPtr leak checker --- rust-version | 2 +- tests/run-pass/leak-in-static.rs | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 58948e2fc69a..ac50cd77052c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -3ff10e74a74ed093fcabac1de27fe1cd65bbbb4a +f0f68778f798d6d34649745b41770829b17ba5b8 diff --git a/tests/run-pass/leak-in-static.rs b/tests/run-pass/leak-in-static.rs index b12cbbf6e64f..2914b1149c06 100644 --- a/tests/run-pass/leak-in-static.rs +++ b/tests/run-pass/leak-in-static.rs @@ -1,3 +1,5 @@ +use std::{ptr, sync::atomic::{AtomicPtr, Ordering}}; + static mut LEAKER: Option>> = None; fn main() { @@ -5,4 +7,10 @@ fn main() { unsafe { LEAKER = Some(Box::new(vec![0; 42])); } + + // Make sure this is allowed even when `AtomicPtr` is used. + { + static LEAK: AtomicPtr = AtomicPtr::new(ptr::null_mut()); + LEAK.store(Box::into_raw(Box::new(0usize)), Ordering::SeqCst); + } } From 7bbd6bca7778210f6cddf8cc668d34bbd46f00dc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 10 Dec 2020 19:53:45 +0100 Subject: [PATCH 2468/5092] rustup --- rust-version | 2 +- src/diagnostics.rs | 8 +++----- src/machine.rs | 4 ++-- src/shims/foreign_items.rs | 2 +- src/shims/intrinsics.rs | 8 ++++---- tests/compile-fail/abort-terminator.rs | 2 +- tests/compile-fail/intrinsics/uninit_uninhabited_type.rs | 2 +- tests/compile-fail/intrinsics/zero_fn_ptr.rs | 2 +- tests/compile-fail/panic/double_panic.rs | 2 +- tests/compile-fail/panic/panic_abort1.rs | 2 +- tests/compile-fail/panic/panic_abort2.rs | 2 +- tests/compile-fail/panic/panic_abort3.rs | 2 +- tests/compile-fail/panic/panic_abort4.rs | 2 +- 13 files changed, 19 insertions(+), 21 deletions(-) diff --git a/rust-version b/rust-version index ac50cd77052c..84526eacb7d8 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -f0f68778f798d6d34649745b41770829b17ba5b8 +39b841dfe36f90a7cd111e7f0c55f32594f6e578 diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 12ad93a5289e..3f1f67218fdb 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -12,7 +12,7 @@ use crate::*; /// Details of premature program termination. pub enum TerminationInfo { Exit(i64), - Abort(Option), + Abort(String), UnsupportedInIsolation(String), ExperimentalUb { msg: String, url: String }, Deadlock, @@ -24,10 +24,8 @@ impl fmt::Display for TerminationInfo { match self { Exit(code) => write!(f, "the evaluated program completed with exit code {}", code), - Abort(None) => - write!(f, "the evaluated program aborted execution"), - Abort(Some(msg)) => - write!(f, "the evaluated program aborted execution: {}", msg), + Abort(msg) => + write!(f, "{}", msg), UnsupportedInIsolation(msg) => write!(f, "{}", msg), ExperimentalUb { msg, .. } => diff --git a/src/machine.rs b/src/machine.rs index 70f4bd722df7..4b9cad8420db 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -391,8 +391,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } #[inline(always)] - fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, !> { - throw_machine_stop!(TerminationInfo::Abort(None)) + fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: String) -> InterpResult<'tcx, !> { + throw_machine_stop!(TerminationInfo::Abort(msg)) } #[inline(always)] diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 24fa119446e8..d588e2962a15 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -149,7 +149,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_machine_stop!(TerminationInfo::Exit(code.into())); } "abort" => { - throw_machine_stop!(TerminationInfo::Abort(None)) + throw_machine_stop!(TerminationInfo::Abort("the program aborted execution".to_owned())) } _ => throw_unsup_format!("can't call (diverging) foreign function: {}", link_name), }, diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 8f7ae6bebb52..956f3b5bde4f 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -419,7 +419,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Query type information - "assert_inhabited" | "assert_zero_valid" | "assert_uninit_valid" => { let &[] = check_arg_count(args)?; @@ -427,13 +426,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let layout = this.layout_of(ty)?; // Abort here because the caller might not be panic safe. if layout.abi.is_uninhabited() { - throw_machine_stop!(TerminationInfo::Abort(Some(format!("attempted to instantiate uninhabited type `{}`", ty)))) + // Use this message even for the other intrinsics, as that's what codegen does + throw_machine_stop!(TerminationInfo::Abort(format!("aborted execution: attempted to instantiate uninhabited type `{}`", ty))) } if intrinsic_name == "assert_zero_valid" && !layout.might_permit_raw_init(this, /*zero:*/ true).unwrap() { - throw_machine_stop!(TerminationInfo::Abort(Some(format!("attempted to zero-initialize type `{}`, which is invalid", ty)))) + throw_machine_stop!(TerminationInfo::Abort(format!("aborted execution: attempted to zero-initialize type `{}`, which is invalid", ty))) } if intrinsic_name == "assert_uninit_valid" && !layout.might_permit_raw_init(this, /*zero:*/ false).unwrap() { - throw_machine_stop!(TerminationInfo::Abort(Some(format!("attempted to leave type `{}` uninitialized, which is invalid", ty)))) + throw_machine_stop!(TerminationInfo::Abort(format!("aborted execution: attempted to leave type `{}` uninitialized, which is invalid", ty))) } } diff --git a/tests/compile-fail/abort-terminator.rs b/tests/compile-fail/abort-terminator.rs index 1bfa289a52b4..73286a1759ba 100644 --- a/tests/compile-fail/abort-terminator.rs +++ b/tests/compile-fail/abort-terminator.rs @@ -1,4 +1,4 @@ -// error-pattern: the evaluated program aborted +// error-pattern: the program aborted #![feature(unwind_attributes)] #[unwind(aborts)] diff --git a/tests/compile-fail/intrinsics/uninit_uninhabited_type.rs b/tests/compile-fail/intrinsics/uninit_uninhabited_type.rs index deb3586c781e..2337ff0f6c26 100644 --- a/tests/compile-fail/intrinsics/uninit_uninhabited_type.rs +++ b/tests/compile-fail/intrinsics/uninit_uninhabited_type.rs @@ -1,4 +1,4 @@ -// error-pattern: the evaluated program aborted execution: attempted to instantiate uninhabited type `!` +// error-pattern: attempted to instantiate uninhabited type `!` #![feature(never_type)] #[allow(deprecated, invalid_value)] diff --git a/tests/compile-fail/intrinsics/zero_fn_ptr.rs b/tests/compile-fail/intrinsics/zero_fn_ptr.rs index 81dbf6c429b3..098a8e01347f 100644 --- a/tests/compile-fail/intrinsics/zero_fn_ptr.rs +++ b/tests/compile-fail/intrinsics/zero_fn_ptr.rs @@ -1,4 +1,4 @@ -// error-pattern: the evaluated program aborted execution: attempted to zero-initialize type `fn()`, which is invalid +// error-pattern: attempted to zero-initialize type `fn()`, which is invalid #[allow(deprecated, invalid_value)] fn main() { diff --git a/tests/compile-fail/panic/double_panic.rs b/tests/compile-fail/panic/double_panic.rs index 80d74f026232..b42c1aff1032 100644 --- a/tests/compile-fail/panic/double_panic.rs +++ b/tests/compile-fail/panic/double_panic.rs @@ -1,4 +1,4 @@ -// error-pattern: the evaluated program aborted +// error-pattern: the program aborted struct Foo; impl Drop for Foo { diff --git a/tests/compile-fail/panic/panic_abort1.rs b/tests/compile-fail/panic/panic_abort1.rs index 02f8f25880f3..095d9e3d75b0 100644 --- a/tests/compile-fail/panic/panic_abort1.rs +++ b/tests/compile-fail/panic/panic_abort1.rs @@ -1,4 +1,4 @@ -// error-pattern: the evaluated program aborted execution +// error-pattern: the program aborted execution // compile-flags: -C panic=abort fn main() { diff --git a/tests/compile-fail/panic/panic_abort2.rs b/tests/compile-fail/panic/panic_abort2.rs index 0d6808dd22e0..de177bc4e716 100644 --- a/tests/compile-fail/panic/panic_abort2.rs +++ b/tests/compile-fail/panic/panic_abort2.rs @@ -1,4 +1,4 @@ -// error-pattern: the evaluated program aborted execution +// error-pattern: the program aborted execution // compile-flags: -C panic=abort fn main() { diff --git a/tests/compile-fail/panic/panic_abort3.rs b/tests/compile-fail/panic/panic_abort3.rs index 6640a56c0be2..2d65da4fe341 100644 --- a/tests/compile-fail/panic/panic_abort3.rs +++ b/tests/compile-fail/panic/panic_abort3.rs @@ -1,4 +1,4 @@ -// error-pattern: the evaluated program aborted execution +// error-pattern: the program aborted execution // compile-flags: -C panic=abort fn main() { diff --git a/tests/compile-fail/panic/panic_abort4.rs b/tests/compile-fail/panic/panic_abort4.rs index d39b1794e676..41d32a604fed 100644 --- a/tests/compile-fail/panic/panic_abort4.rs +++ b/tests/compile-fail/panic/panic_abort4.rs @@ -1,4 +1,4 @@ -// error-pattern: the evaluated program aborted execution +// error-pattern: the program aborted execution // compile-flags: -C panic=abort fn main() { From 27a518e166f778d6c0d4727c9917a0db8454958e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 10 Dec 2020 00:11:00 +0100 Subject: [PATCH 2469/5092] enable track-raw-ptr tests on Windows --- README.md | 3 +-- tests/compile-fail/stacked_borrows/raw_tracking.rs | 1 - tests/run-pass/btreemap.rs | 1 - tests/run-pass/rc.rs | 1 - tests/run-pass/stacked-borrows/stacked-borrows.rs | 1 - tests/run-pass/vec.rs | 1 - tests/run-pass/vecdeque.rs | 1 - 7 files changed, 1 insertion(+), 8 deletions(-) diff --git a/README.md b/README.md index 7c6b09968f47..38663b408a3d 100644 --- a/README.md +++ b/README.md @@ -248,8 +248,7 @@ environment variable: help identify latent aliasing issues in code that Miri accepts by default. You can recognize false positives by "" occurring in the message -- this indicates a pointer that was cast from an integer, so Miri was unable to track - this pointer. Make sure to use a non-Windows target with this flag, as the - Windows runtime makes use of integer-pointer casts. + this pointer. Some native rustc `-Z` flags are also very relevant for Miri: diff --git a/tests/compile-fail/stacked_borrows/raw_tracking.rs b/tests/compile-fail/stacked_borrows/raw_tracking.rs index b9ddee328f7a..975aec945c7f 100644 --- a/tests/compile-fail/stacked_borrows/raw_tracking.rs +++ b/tests/compile-fail/stacked_borrows/raw_tracking.rs @@ -1,5 +1,4 @@ // compile-flags: -Zmiri-track-raw-pointers -// ignore-windows (FIXME: tracking raw pointers does not work on Windows) //! This demonstrates a provenance problem that requires tracking of raw pointers to be detected. fn main() { diff --git a/tests/run-pass/btreemap.rs b/tests/run-pass/btreemap.rs index ca548a03703e..b704b89fd050 100644 --- a/tests/run-pass/btreemap.rs +++ b/tests/run-pass/btreemap.rs @@ -1,5 +1,4 @@ // compile-flags: -Zmiri-track-raw-pointers -// ignore-windows (FIXME: tracking raw pointers does not work on Windows) #![feature(btree_drain_filter)] use std::collections::{BTreeMap, BTreeSet}; use std::mem; diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index 47f29992c459..69bd1f8d9ae2 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -1,5 +1,4 @@ // compile-flags: -Zmiri-track-raw-pointers -// ignore-windows (FIXME: tracking raw pointers does not work on Windows) #![feature(new_uninit)] #![feature(get_mut_unchecked)] diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index ad1877fc019b..99bd0fb9d805 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -1,5 +1,4 @@ // compile-flags: -Zmiri-track-raw-pointers -// ignore-windows (FIXME: tracking raw pointers does not work on Windows) #![feature(raw_ref_macros)] use std::ptr; diff --git a/tests/run-pass/vec.rs b/tests/run-pass/vec.rs index f243aa45a1a6..8d83f6380b8f 100644 --- a/tests/run-pass/vec.rs +++ b/tests/run-pass/vec.rs @@ -1,5 +1,4 @@ // compile-flags: -Zmiri-track-raw-pointers -// ignore-windows (FIXME: tracking raw pointers does not work on Windows) // Gather all references from a mutable iterator and make sure Miri notices if // using them is dangerous. fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { diff --git a/tests/run-pass/vecdeque.rs b/tests/run-pass/vecdeque.rs index 55b47f622fde..54aeb89ec83f 100644 --- a/tests/run-pass/vecdeque.rs +++ b/tests/run-pass/vecdeque.rs @@ -1,5 +1,4 @@ // compile-flags: -Zmiri-track-raw-pointers -// ignore-windows (FIXME: tracking raw pointers does not work on Windows) use std::collections::VecDeque; fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { From 19d3d9e313af703fae223e06ba317fbd51a12bbd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 11 Dec 2020 11:36:17 +0100 Subject: [PATCH 2470/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 84526eacb7d8..a11d33b3d336 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -39b841dfe36f90a7cd111e7f0c55f32594f6e578 +a2e29d67c26bdf8f278c98ee02d6cc77a279ed2e From c45b1b16be9ce362f5e23bd5335cffac6679ea59 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Mon, 7 Dec 2020 18:16:06 +0000 Subject: [PATCH 2471/5092] More tests, fix issue 1643 and detect races with allocation. --- src/data_race.rs | 75 ++++++++++++++----- src/machine.rs | 19 ++++- .../compile-fail/data_race/alloc_read_race.rs | 45 +++++++++++ .../data_race/alloc_write_race.rs | 45 +++++++++++ .../data_race/dealloc_read_race.rs | 32 ++++++++ .../data_race/dealloc_read_race_stack.rs | 52 +++++++++++++ .../data_race/dealloc_read_race_stack_drop.rs | 53 +++++++++++++ .../data_race/dealloc_write_race.rs | 31 ++++++++ .../data_race/dealloc_write_race_stack.rs | 52 +++++++++++++ .../dealloc_write_race_stack_drop.rs | 52 +++++++++++++ .../data_race/read_write_race_stack.rs | 55 ++++++++++++++ .../data_race/write_write_race_stack.rs | 57 ++++++++++++++ tests/run-pass/concurrency/issue1643.rs | 14 ++++ tests/run-pass/concurrency/issue1643.stderr | 2 + 14 files changed, 564 insertions(+), 20 deletions(-) create mode 100644 tests/compile-fail/data_race/alloc_read_race.rs create mode 100644 tests/compile-fail/data_race/alloc_write_race.rs create mode 100644 tests/compile-fail/data_race/dealloc_read_race.rs create mode 100644 tests/compile-fail/data_race/dealloc_read_race_stack.rs create mode 100644 tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs create mode 100644 tests/compile-fail/data_race/dealloc_write_race.rs create mode 100644 tests/compile-fail/data_race/dealloc_write_race_stack.rs create mode 100644 tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs create mode 100644 tests/compile-fail/data_race/read_write_race_stack.rs create mode 100644 tests/compile-fail/data_race/write_write_race_stack.rs create mode 100644 tests/run-pass/concurrency/issue1643.rs create mode 100644 tests/run-pass/concurrency/issue1643.stderr diff --git a/src/data_race.rs b/src/data_race.rs index aec22dadc1b6..a70c4a4e4c70 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -192,6 +192,25 @@ struct AtomicMemoryCellClocks { sync_vector: VClock, } +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum WriteType { + /// Allocate memory. + Allocate, + /// Standard unsynchronized write. + Write, + /// Deallocate memory + Deallocate, +} +impl WriteType { + fn get_descriptor(self) -> &'static str { + match self { + WriteType::Allocate => "ALLOCATE", + WriteType::Write => "WRITE", + WriteType::Deallocate => "DEALLOCATE", + } + } +} + /// Memory Cell vector clock metadata /// for data-race detection. #[derive(Clone, PartialEq, Eq, Debug)] @@ -204,6 +223,11 @@ struct MemoryCellClocks { /// that performed the last write operation. write_index: VectorIdx, + /// The type of operation that the write index represents, + /// either newly allocated memory, a non-atomic write or + /// a deallocation of memory. + write_type: WriteType, + /// The vector-clock of the timestamp of the last read operation /// performed by a thread since the last write operation occurred. /// It is reset to zero on each write operation. @@ -215,20 +239,19 @@ struct MemoryCellClocks { atomic_ops: Option>, } -/// Create a default memory cell clocks instance -/// for uninitialized memory. -impl Default for MemoryCellClocks { - fn default() -> Self { +impl MemoryCellClocks { + + /// Create a new set of clocks representing memory allocated + /// at a given vector timestamp and index. + fn new(alloc: VTimestamp, alloc_index: VectorIdx) -> Self { MemoryCellClocks { read: VClock::default(), - write: 0, - write_index: VectorIdx::MAX_INDEX, + write: alloc, + write_index: alloc_index, + write_type: WriteType::Allocate, atomic_ops: None, } } -} - -impl MemoryCellClocks { /// Load the internal atomic memory cells if they exist. #[inline] @@ -382,6 +405,7 @@ impl MemoryCellClocks { &mut self, clocks: &ThreadClockSet, index: VectorIdx, + write_type: WriteType, ) -> Result<(), DataRace> { log::trace!("Unsynchronized write with vectors: {:#?} :: {:#?}", self, clocks); if self.write <= clocks.clock[self.write_index] && self.read <= clocks.clock { @@ -393,6 +417,7 @@ impl MemoryCellClocks { if race_free { self.write = clocks.clock[index]; self.write_index = index; + self.write_type = write_type; self.read.set_zero_vector(); Ok(()) } else { @@ -646,16 +671,28 @@ pub struct VClockAlloc { /// Assigning each byte a MemoryCellClocks. alloc_ranges: RefCell>, - // Pointer to global state. + /// Pointer to global state. global: MemoryExtra, } impl VClockAlloc { - /// Create a new data-race allocation detector. - pub fn new_allocation(global: &MemoryExtra, len: Size) -> VClockAlloc { + + /// Create a new data-race detector for newly allocated memory. + pub fn new_allocation(global: &MemoryExtra, len: Size, track_alloc: bool) -> VClockAlloc { + //FIXME: stack allocations are currently ignored due to the lazy nature of stack + // allocation, this results in data-races being missed. + let (alloc_timestamp, alloc_index) = if !track_alloc { + (0, VectorIdx::MAX_INDEX) + }else{ + let (alloc_index, clocks) = global.current_thread_state(); + let alloc_timestamp = clocks.clock[alloc_index]; + (alloc_timestamp, alloc_index) + }; VClockAlloc { global: Rc::clone(global), - alloc_ranges: RefCell::new(RangeMap::new(len, MemoryCellClocks::default())), + alloc_ranges: RefCell::new(RangeMap::new( + len, MemoryCellClocks::new(alloc_timestamp, alloc_index) + )), } } @@ -712,7 +749,7 @@ impl VClockAlloc { // Convert the write action into the vector clock it // represents for diagnostic purposes. write_clock = VClock::new_with_index(range.write_index, range.write); - ("WRITE", range.write_index, &write_clock) + (range.write_type.get_descriptor(), range.write_index, &write_clock) } else if let Some(idx) = Self::find_gt_index(&range.read, ¤t_clocks.clock) { ("READ", idx, &range.read) } else if !is_atomic { @@ -792,17 +829,17 @@ impl VClockAlloc { &mut self, pointer: Pointer, len: Size, - action: &str, + write_type: WriteType, ) -> InterpResult<'tcx> { if self.global.multi_threaded.get() { let (index, clocks) = self.global.current_thread_state(); for (_, range) in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { - if let Err(DataRace) = range.write_race_detect(&*clocks, index) { + if let Err(DataRace) = range.write_race_detect(&*clocks, index, write_type) { // Report data-race return Self::report_data_race( &self.global, range, - action, + write_type.get_descriptor(), false, pointer, len, @@ -820,7 +857,7 @@ impl VClockAlloc { /// being created or if it is temporarily disabled during a racy read or write /// operation pub fn write<'tcx>(&mut self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { - self.unique_access(pointer, len, "Write") + self.unique_access(pointer, len, WriteType::Write) } /// Detect data-races for an unsynchronized deallocate operation, will not perform @@ -828,7 +865,7 @@ impl VClockAlloc { /// being created or if it is temporarily disabled during a racy read or write /// operation pub fn deallocate<'tcx>(&mut self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { - self.unique_access(pointer, len, "Deallocate") + self.unique_access(pointer, len, WriteType::Deallocate) } } diff --git a/src/machine.rs b/src/machine.rs index 4b9cad8420db..159e08c87d3f 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -478,7 +478,24 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { (None, Tag::Untagged) }; let race_alloc = if let Some(data_race) = &memory_extra.data_race { - Some(data_race::AllocExtra::new_allocation(&data_race, alloc.size)) + match kind { + // V-Table generation is lazy and so racy, so do not track races. + // Also V-Tables are read only so no data races can be detected. + MemoryKind::Vtable => None, + // User allocated and stack memory should track allocation. + MemoryKind::Machine( + MiriMemoryKind::Rust | MiriMemoryKind::C | MiriMemoryKind::WinHeap + ) | MemoryKind::Stack => Some( + data_race::AllocExtra::new_allocation(&data_race, alloc.size, true) + ), + // Other global memory should trace races but be allocated at the 0 timestamp. + MemoryKind::Machine( + MiriMemoryKind::Global | MiriMemoryKind::Machine | MiriMemoryKind::Env | + MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls + ) | MemoryKind::CallerLocation => Some( + data_race::AllocExtra::new_allocation(&data_race, alloc.size, false) + ) + } } else { None }; diff --git a/tests/compile-fail/data_race/alloc_read_race.rs b/tests/compile-fail/data_race/alloc_read_race.rs new file mode 100644 index 000000000000..53b3866a2ed3 --- /dev/null +++ b/tests/compile-fail/data_race/alloc_read_race.rs @@ -0,0 +1,45 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +use std::thread::spawn; +use std::ptr::null_mut; +use std::sync::atomic::{Ordering, AtomicPtr}; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + // Shared atomic pointer + let pointer = AtomicPtr::new(null_mut::()); + let ptr = EvilSend(&pointer as *const AtomicPtr); + + // Note: this is scheduler-dependent + // the operations need to occur in + // order, otherwise the allocation is + // not visible to the other-thread to + // detect the race: + // 1. alloc + // 2. write + unsafe { + let j1 = spawn(move || { + //Concurrent allocate the memory. + //Uses relaxed semantics to not generate + //a release sequence. + let pointer = &*ptr.0; + pointer.store(Box::into_raw(Box::new(0usize)), Ordering::Relaxed); + }); + + let j2 = spawn(move || { + let pointer = &*ptr.0; + *pointer.load(Ordering::Relaxed) //~ ERROR Data race + }); + + j1.join().unwrap(); + j2.join().unwrap(); + + // Clean up memory, will never be executed + drop(Box::from_raw(pointer.load(Ordering::Relaxed))); + } +} diff --git a/tests/compile-fail/data_race/alloc_write_race.rs b/tests/compile-fail/data_race/alloc_write_race.rs new file mode 100644 index 000000000000..e84ffa9dfef3 --- /dev/null +++ b/tests/compile-fail/data_race/alloc_write_race.rs @@ -0,0 +1,45 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +use std::thread::spawn; +use std::ptr::null_mut; +use std::sync::atomic::{Ordering, AtomicPtr}; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + // Shared atomic pointer + let pointer = AtomicPtr::new(null_mut::()); + let ptr = EvilSend(&pointer as *const AtomicPtr); + + // Note: this is scheduler-dependent + // the operations need to occur in + // order, otherwise the allocation is + // not visible to the other-thread to + // detect the race: + // 1. alloc + // 2. write + unsafe { + let j1 = spawn(move || { + //Concurrent allocate the memory. + //Uses relaxed semantics to not generate + //a release sequence. + let pointer = &*ptr.0; + pointer.store(Box::into_raw(Box::new(0usize)), Ordering::Relaxed); + }); + + let j2 = spawn(move || { + let pointer = &*ptr.0; + *pointer.load(Ordering::Relaxed) = 2; //~ ERROR Data race + }); + + j1.join().unwrap(); + j2.join().unwrap(); + + // Clean up memory, will never be executed + drop(Box::from_raw(pointer.load(Ordering::Relaxed))); + } +} diff --git a/tests/compile-fail/data_race/dealloc_read_race.rs b/tests/compile-fail/data_race/dealloc_read_race.rs new file mode 100644 index 000000000000..f6479d246f8d --- /dev/null +++ b/tests/compile-fail/data_race/dealloc_read_race.rs @@ -0,0 +1,32 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +use std::thread::spawn; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +extern "Rust" { + fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); +} + +pub fn main() { + // Shared atomic pointer + let pointer: *mut usize = Box::into_raw(Box::new(0usize)); + let ptr = EvilSend(pointer); + + unsafe { + let j1 = spawn(move || { + *ptr.0 + }); + + let j2 = spawn(move || { + __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()); //~ ERROR Data race + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack.rs b/tests/compile-fail/data_race/dealloc_read_race_stack.rs new file mode 100644 index 000000000000..67eda4d431e6 --- /dev/null +++ b/tests/compile-fail/data_race/dealloc_read_race_stack.rs @@ -0,0 +1,52 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-isolation + +use std::thread::{spawn, sleep}; +use std::ptr::null_mut; +use std::sync::atomic::{Ordering, AtomicPtr}; +use std::time::Duration; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + // Shared atomic pointer + let pointer = AtomicPtr::new(null_mut::()); + let ptr = EvilSend(&pointer as *const AtomicPtr); + + // Note: this is scheduler-dependent + // the operations need to occur in + // order, otherwise the allocation is + // not visible to the other-thread to + // detect the race: + // 1. stack-allocate + // 2. read + // 3. stack-deallocate + unsafe { + let j1 = spawn(move || { + //Concurrent allocate the memory. + //Uses relaxed semantics to not generate + //a release sequence. + let pointer = &*ptr.0; + { + let mut stack_var = 0usize; + + pointer.store(&mut stack_var as *mut _, Ordering::Release); + + sleep(Duration::from_millis(100)); + + } //~ ERROR Data race + }); + + let j2 = spawn(move || { + let pointer = &*ptr.0; + *pointer.load(Ordering::Acquire) + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs b/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs new file mode 100644 index 000000000000..81ad50c44a05 --- /dev/null +++ b/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs @@ -0,0 +1,53 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-isolation + +use std::thread::{spawn, sleep}; +use std::ptr::null_mut; +use std::sync::atomic::{Ordering, AtomicPtr}; +use std::time::Duration; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + // Shared atomic pointer + let pointer = AtomicPtr::new(null_mut::()); + let ptr = EvilSend(&pointer as *const AtomicPtr); + + // Note: this is scheduler-dependent + // the operations need to occur in + // order, otherwise the allocation is + // not visible to the other-thread to + // detect the race: + // 1. stack-allocate + // 2. read + // 3. stack-deallocate + unsafe { + let j1 = spawn(move || { + //Concurrent allocate the memory. + //Uses relaxed semantics to not generate + //a release sequence. + let pointer = &*ptr.0; + + let mut stack_var = 0usize; + + pointer.store(&mut stack_var as *mut _, Ordering::Release); + + sleep(Duration::from_millis(100)); + + // NOTE: the race is also detected with thread 0, and so reported for thread 0 instead of 2, unsure of the cause. + drop(stack_var); + }); //~ ERROR Data race detected between DEALLOCATE on Thread(id = 1) and READ on Thread(id = 0, name = "main") + + let j2 = spawn(move || { + let pointer = &*ptr.0; + *pointer.load(Ordering::Acquire) + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/compile-fail/data_race/dealloc_write_race.rs b/tests/compile-fail/data_race/dealloc_write_race.rs new file mode 100644 index 000000000000..e2527f6e9045 --- /dev/null +++ b/tests/compile-fail/data_race/dealloc_write_race.rs @@ -0,0 +1,31 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +use std::thread::spawn; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +extern "Rust" { + fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); +} +pub fn main() { + // Shared atomic pointer + let pointer: *mut usize = Box::into_raw(Box::new(0usize)); + let ptr = EvilSend(pointer); + + unsafe { + let j1 = spawn(move || { + *ptr.0 = 2; + }); + + let j2 = spawn(move || { + __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()); //~ ERROR Data race + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack.rs b/tests/compile-fail/data_race/dealloc_write_race_stack.rs new file mode 100644 index 000000000000..cda6e317aaeb --- /dev/null +++ b/tests/compile-fail/data_race/dealloc_write_race_stack.rs @@ -0,0 +1,52 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-isolation + +use std::thread::{spawn, sleep}; +use std::ptr::null_mut; +use std::sync::atomic::{Ordering, AtomicPtr}; +use std::time::Duration; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + // Shared atomic pointer + let pointer = AtomicPtr::new(null_mut::()); + let ptr = EvilSend(&pointer as *const AtomicPtr); + + // Note: this is scheduler-dependent + // the operations need to occur in + // order, otherwise the allocation is + // not visible to the other-thread to + // detect the race: + // 1. stack-allocate + // 2. read + // 3. stack-deallocate + unsafe { + let j1 = spawn(move || { + //Concurrent allocate the memory. + //Uses relaxed semantics to not generate + //a release sequence. + let pointer = &*ptr.0; + { + let mut stack_var = 0usize; + + pointer.store(&mut stack_var as *mut _, Ordering::Release); + + sleep(Duration::from_millis(100)); + + } //~ ERROR Data race + }); + + let j2 = spawn(move || { + let pointer = &*ptr.0; + *pointer.load(Ordering::Acquire) = 3; + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs b/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs new file mode 100644 index 000000000000..9a633518a214 --- /dev/null +++ b/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs @@ -0,0 +1,52 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-isolation + +use std::thread::{spawn, sleep}; +use std::ptr::null_mut; +use std::sync::atomic::{Ordering, AtomicPtr}; +use std::time::Duration; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + // Shared atomic pointer + let pointer = AtomicPtr::new(null_mut::()); + let ptr = EvilSend(&pointer as *const AtomicPtr); + + // Note: this is scheduler-dependent + // the operations need to occur in + // order, otherwise the allocation is + // not visible to the other-thread to + // detect the race: + // 1. stack-allocate + // 2. read + // 3. stack-deallocate + unsafe { + let j1 = spawn(move || { + //Concurrent allocate the memory. + //Uses relaxed semantics to not generate + //a release sequence. + let pointer = &*ptr.0; + + let mut stack_var = 0usize; + + pointer.store(&mut stack_var as *mut _, Ordering::Release); + + sleep(Duration::from_millis(100)); + + drop(stack_var); //~ ERROR Data race + }); + + let j2 = spawn(move || { + let pointer = &*ptr.0; + *pointer.load(Ordering::Acquire) = 3; + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/compile-fail/data_race/read_write_race_stack.rs b/tests/compile-fail/data_race/read_write_race_stack.rs new file mode 100644 index 000000000000..1762e12c28f0 --- /dev/null +++ b/tests/compile-fail/data_race/read_write_race_stack.rs @@ -0,0 +1,55 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-isolation + +use std::thread::{spawn, sleep}; +use std::ptr::null_mut; +use std::sync::atomic::{Ordering, AtomicPtr}; +use std::time::Duration; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + // Shared atomic pointer + let pointer = AtomicPtr::new(null_mut::()); + let ptr = EvilSend(&pointer as *const AtomicPtr); + + // Note: this is scheduler-dependent + // the operations need to occur in + // order, otherwise the allocation is + // not visible to the other-thread to + // detect the race: + // 1. stack-allocate + // 2. atomic_store + // 3. atomic_load + // 4. write-value + // 5. read-value + unsafe { + let j1 = spawn(move || { + //Concurrent allocate the memory. + //Uses relaxed semantics to not generate + //a release sequence. + let pointer = &*ptr.0; + + let mut stack_var = 0usize; + + pointer.store(&mut stack_var as *mut _, Ordering::Release); + + sleep(Duration::from_millis(100)); + + //read + stack_var //~ ERROR Data race + }); + + let j2 = spawn(move || { + let pointer = &*ptr.0; + *pointer.load(Ordering::Acquire) = 3; + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/compile-fail/data_race/write_write_race_stack.rs b/tests/compile-fail/data_race/write_write_race_stack.rs new file mode 100644 index 000000000000..9acc26685d89 --- /dev/null +++ b/tests/compile-fail/data_race/write_write_race_stack.rs @@ -0,0 +1,57 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-isolation + +use std::thread::{spawn, sleep}; +use std::ptr::null_mut; +use std::sync::atomic::{Ordering, AtomicPtr}; +use std::time::Duration; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + // Shared atomic pointer + let pointer = AtomicPtr::new(null_mut::()); + let ptr = EvilSend(&pointer as *const AtomicPtr); + + // Note: this is scheduler-dependent + // the operations need to occur in + // order, otherwise the allocation is + // not visible to the other-thread to + // detect the race: + // 1. stack-allocate + // 2. atomic_store + // 3. atomic_load + // 4. write-value + // 5. write-value + unsafe { + let j1 = spawn(move || { + //Concurrent allocate the memory. + //Uses relaxed semantics to not generate + //a release sequence. + let pointer = &*ptr.0; + + let mut stack_var = 0usize; + + pointer.store(&mut stack_var as *mut _, Ordering::Release); + + sleep(Duration::from_millis(100)); + + stack_var = 1usize; //~ ERROR Data race + + // read to silence errors + stack_var + }); + + let j2 = spawn(move || { + let pointer = &*ptr.0; + *pointer.load(Ordering::Acquire) = 3; + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/run-pass/concurrency/issue1643.rs b/tests/run-pass/concurrency/issue1643.rs new file mode 100644 index 000000000000..c0956569ad8f --- /dev/null +++ b/tests/run-pass/concurrency/issue1643.rs @@ -0,0 +1,14 @@ +use std::thread::spawn; + +fn initialize() { + initialize_inner(&mut || false) +} + +fn initialize_inner(_init: &mut dyn FnMut() -> bool) {} + +fn main() { + let j1 = spawn(initialize); + let j2 = spawn(initialize); + j1.join().unwrap(); + j2.join().unwrap(); +} diff --git a/tests/run-pass/concurrency/issue1643.stderr b/tests/run-pass/concurrency/issue1643.stderr new file mode 100644 index 000000000000..03676519d4f1 --- /dev/null +++ b/tests/run-pass/concurrency/issue1643.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + From 1ded6d328aa0c1a93f81491ea7821e9b6a7e0d12 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Mon, 7 Dec 2020 18:21:12 +0000 Subject: [PATCH 2472/5092] Remove old FIXME --- src/data_race.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index a70c4a4e4c70..382a87e2f515 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -679,14 +679,12 @@ impl VClockAlloc { /// Create a new data-race detector for newly allocated memory. pub fn new_allocation(global: &MemoryExtra, len: Size, track_alloc: bool) -> VClockAlloc { - //FIXME: stack allocations are currently ignored due to the lazy nature of stack - // allocation, this results in data-races being missed. - let (alloc_timestamp, alloc_index) = if !track_alloc { - (0, VectorIdx::MAX_INDEX) - }else{ + let (alloc_timestamp, alloc_index) = if track_alloc { let (alloc_index, clocks) = global.current_thread_state(); let alloc_timestamp = clocks.clock[alloc_index]; (alloc_timestamp, alloc_index) + }else{ + (0, VectorIdx::MAX_INDEX) }; VClockAlloc { global: Rc::clone(global), From f4bcef11136922e17eb7d202ebe76d28e6b4e7d4 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Mon, 7 Dec 2020 18:58:31 +0000 Subject: [PATCH 2473/5092] Increase sleep times for the scheduler --- tests/compile-fail/data_race/dangling_thread_async_race.rs | 2 +- tests/compile-fail/data_race/dangling_thread_race.rs | 2 +- tests/compile-fail/data_race/dealloc_read_race_stack.rs | 2 +- tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs | 2 +- tests/compile-fail/data_race/dealloc_write_race_stack.rs | 2 +- tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs | 2 +- tests/compile-fail/data_race/read_write_race_stack.rs | 2 +- tests/compile-fail/data_race/release_seq_race.rs | 4 ++-- tests/compile-fail/data_race/write_write_race_stack.rs | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/compile-fail/data_race/dangling_thread_async_race.rs b/tests/compile-fail/data_race/dangling_thread_async_race.rs index d8b5d82f8304..ece831685287 100644 --- a/tests/compile-fail/data_race/dangling_thread_async_race.rs +++ b/tests/compile-fail/data_race/dangling_thread_async_race.rs @@ -26,7 +26,7 @@ fn main() { // Detatch the thread and sleep until it terminates mem::drop(join); - sleep(Duration::from_millis(100)); + sleep(Duration::from_millis(1000)); // Spawn and immediately join a thread // to execute the join code-path diff --git a/tests/compile-fail/data_race/dangling_thread_race.rs b/tests/compile-fail/data_race/dangling_thread_race.rs index 172b05bd4f0b..873d10b788f1 100644 --- a/tests/compile-fail/data_race/dangling_thread_race.rs +++ b/tests/compile-fail/data_race/dangling_thread_race.rs @@ -26,7 +26,7 @@ fn main() { // Detatch the thread and sleep until it terminates mem::drop(join); - sleep(Duration::from_millis(100)); + sleep(Duration::from_millis(1000)); // Spawn and immediately join a thread // to execute the join code-path diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack.rs b/tests/compile-fail/data_race/dealloc_read_race_stack.rs index 67eda4d431e6..95d7acea2660 100644 --- a/tests/compile-fail/data_race/dealloc_read_race_stack.rs +++ b/tests/compile-fail/data_race/dealloc_read_race_stack.rs @@ -36,7 +36,7 @@ pub fn main() { pointer.store(&mut stack_var as *mut _, Ordering::Release); - sleep(Duration::from_millis(100)); + sleep(Duration::from_millis(1000)); } //~ ERROR Data race }); diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs b/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs index 81ad50c44a05..ecdd841965e9 100644 --- a/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs +++ b/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs @@ -36,7 +36,7 @@ pub fn main() { pointer.store(&mut stack_var as *mut _, Ordering::Release); - sleep(Duration::from_millis(100)); + sleep(Duration::from_millis(1000)); // NOTE: the race is also detected with thread 0, and so reported for thread 0 instead of 2, unsure of the cause. drop(stack_var); diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack.rs b/tests/compile-fail/data_race/dealloc_write_race_stack.rs index cda6e317aaeb..8008b6cdb91e 100644 --- a/tests/compile-fail/data_race/dealloc_write_race_stack.rs +++ b/tests/compile-fail/data_race/dealloc_write_race_stack.rs @@ -36,7 +36,7 @@ pub fn main() { pointer.store(&mut stack_var as *mut _, Ordering::Release); - sleep(Duration::from_millis(100)); + sleep(Duration::from_millis(1000)); } //~ ERROR Data race }); diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs b/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs index 9a633518a214..733cdb7b1f04 100644 --- a/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs +++ b/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs @@ -36,7 +36,7 @@ pub fn main() { pointer.store(&mut stack_var as *mut _, Ordering::Release); - sleep(Duration::from_millis(100)); + sleep(Duration::from_millis(1000)); drop(stack_var); //~ ERROR Data race }); diff --git a/tests/compile-fail/data_race/read_write_race_stack.rs b/tests/compile-fail/data_race/read_write_race_stack.rs index 1762e12c28f0..fcd8a0606bae 100644 --- a/tests/compile-fail/data_race/read_write_race_stack.rs +++ b/tests/compile-fail/data_race/read_write_race_stack.rs @@ -38,7 +38,7 @@ pub fn main() { pointer.store(&mut stack_var as *mut _, Ordering::Release); - sleep(Duration::from_millis(100)); + sleep(Duration::from_millis(1000)); //read stack_var //~ ERROR Data race diff --git a/tests/compile-fail/data_race/release_seq_race.rs b/tests/compile-fail/data_race/release_seq_race.rs index 59263cb71204..d0d625a6ce17 100644 --- a/tests/compile-fail/data_race/release_seq_race.rs +++ b/tests/compile-fail/data_race/release_seq_race.rs @@ -30,7 +30,7 @@ pub fn main() { let j1 = spawn(move || { *c.0 = 1; SYNC.store(1, Ordering::Release); - sleep(Duration::from_millis(100)); + sleep(Duration::from_millis(1000)); SYNC.store(3, Ordering::Relaxed); }); @@ -40,7 +40,7 @@ pub fn main() { }); let j3 = spawn(move || { - sleep(Duration::from_millis(1000)); + sleep(Duration::from_millis(5000)); if SYNC.load(Ordering::Acquire) == 3 { *c.0 //~ ERROR Data race } else { diff --git a/tests/compile-fail/data_race/write_write_race_stack.rs b/tests/compile-fail/data_race/write_write_race_stack.rs index 9acc26685d89..46d0911be189 100644 --- a/tests/compile-fail/data_race/write_write_race_stack.rs +++ b/tests/compile-fail/data_race/write_write_race_stack.rs @@ -38,7 +38,7 @@ pub fn main() { pointer.store(&mut stack_var as *mut _, Ordering::Release); - sleep(Duration::from_millis(100)); + sleep(Duration::from_millis(1000)); stack_var = 1usize; //~ ERROR Data race From c4ccd0b6a1dbf52a98fa3e086919346213f87f6e Mon Sep 17 00:00:00 2001 From: JCTyblaidd Date: Mon, 7 Dec 2020 19:10:01 +0000 Subject: [PATCH 2474/5092] Fix nits Co-authored-by: bjorn3 --- src/data_race.rs | 2 -- tests/compile-fail/data_race/alloc_read_race.rs | 6 +++--- tests/compile-fail/data_race/alloc_write_race.rs | 6 +++--- tests/compile-fail/data_race/dealloc_read_race_stack.rs | 6 +++--- .../compile-fail/data_race/dealloc_read_race_stack_drop.rs | 6 +++--- tests/compile-fail/data_race/dealloc_write_race_stack.rs | 6 +++--- .../compile-fail/data_race/dealloc_write_race_stack_drop.rs | 6 +++--- tests/compile-fail/data_race/read_write_race_stack.rs | 6 +++--- tests/compile-fail/data_race/write_write_race_stack.rs | 6 +++--- 9 files changed, 24 insertions(+), 26 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index 382a87e2f515..052b92453082 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -240,7 +240,6 @@ struct MemoryCellClocks { } impl MemoryCellClocks { - /// Create a new set of clocks representing memory allocated /// at a given vector timestamp and index. fn new(alloc: VTimestamp, alloc_index: VectorIdx) -> Self { @@ -676,7 +675,6 @@ pub struct VClockAlloc { } impl VClockAlloc { - /// Create a new data-race detector for newly allocated memory. pub fn new_allocation(global: &MemoryExtra, len: Size, track_alloc: bool) -> VClockAlloc { let (alloc_timestamp, alloc_index) = if track_alloc { diff --git a/tests/compile-fail/data_race/alloc_read_race.rs b/tests/compile-fail/data_race/alloc_read_race.rs index 53b3866a2ed3..9ebb793c71ba 100644 --- a/tests/compile-fail/data_race/alloc_read_race.rs +++ b/tests/compile-fail/data_race/alloc_read_race.rs @@ -24,9 +24,9 @@ pub fn main() { // 2. write unsafe { let j1 = spawn(move || { - //Concurrent allocate the memory. - //Uses relaxed semantics to not generate - //a release sequence. + // Concurrent allocate the memory. + // Uses relaxed semantics to not generate + // a release sequence. let pointer = &*ptr.0; pointer.store(Box::into_raw(Box::new(0usize)), Ordering::Relaxed); }); diff --git a/tests/compile-fail/data_race/alloc_write_race.rs b/tests/compile-fail/data_race/alloc_write_race.rs index e84ffa9dfef3..229d3cea2c93 100644 --- a/tests/compile-fail/data_race/alloc_write_race.rs +++ b/tests/compile-fail/data_race/alloc_write_race.rs @@ -24,9 +24,9 @@ pub fn main() { // 2. write unsafe { let j1 = spawn(move || { - //Concurrent allocate the memory. - //Uses relaxed semantics to not generate - //a release sequence. + // Concurrent allocate the memory. + // Uses relaxed semantics to not generate + // a release sequence. let pointer = &*ptr.0; pointer.store(Box::into_raw(Box::new(0usize)), Ordering::Relaxed); }); diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack.rs b/tests/compile-fail/data_race/dealloc_read_race_stack.rs index 95d7acea2660..275d1d1cccf0 100644 --- a/tests/compile-fail/data_race/dealloc_read_race_stack.rs +++ b/tests/compile-fail/data_race/dealloc_read_race_stack.rs @@ -27,9 +27,9 @@ pub fn main() { // 3. stack-deallocate unsafe { let j1 = spawn(move || { - //Concurrent allocate the memory. - //Uses relaxed semantics to not generate - //a release sequence. + // Concurrent allocate the memory. + // Uses relaxed semantics to not generate + // a release sequence. let pointer = &*ptr.0; { let mut stack_var = 0usize; diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs b/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs index ecdd841965e9..d5131687d78b 100644 --- a/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs +++ b/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs @@ -27,9 +27,9 @@ pub fn main() { // 3. stack-deallocate unsafe { let j1 = spawn(move || { - //Concurrent allocate the memory. - //Uses relaxed semantics to not generate - //a release sequence. + // Concurrent allocate the memory. + // Uses relaxed semantics to not generate + // a release sequence. let pointer = &*ptr.0; let mut stack_var = 0usize; diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack.rs b/tests/compile-fail/data_race/dealloc_write_race_stack.rs index 8008b6cdb91e..3fcbe7661ff4 100644 --- a/tests/compile-fail/data_race/dealloc_write_race_stack.rs +++ b/tests/compile-fail/data_race/dealloc_write_race_stack.rs @@ -27,9 +27,9 @@ pub fn main() { // 3. stack-deallocate unsafe { let j1 = spawn(move || { - //Concurrent allocate the memory. - //Uses relaxed semantics to not generate - //a release sequence. + // Concurrent allocate the memory. + // Uses relaxed semantics to not generate + // a release sequence. let pointer = &*ptr.0; { let mut stack_var = 0usize; diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs b/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs index 733cdb7b1f04..5483be9f788f 100644 --- a/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs +++ b/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs @@ -27,9 +27,9 @@ pub fn main() { // 3. stack-deallocate unsafe { let j1 = spawn(move || { - //Concurrent allocate the memory. - //Uses relaxed semantics to not generate - //a release sequence. + // Concurrent allocate the memory. + // Uses relaxed semantics to not generate + // a release sequence. let pointer = &*ptr.0; let mut stack_var = 0usize; diff --git a/tests/compile-fail/data_race/read_write_race_stack.rs b/tests/compile-fail/data_race/read_write_race_stack.rs index fcd8a0606bae..7f2dbcc6ed5d 100644 --- a/tests/compile-fail/data_race/read_write_race_stack.rs +++ b/tests/compile-fail/data_race/read_write_race_stack.rs @@ -29,9 +29,9 @@ pub fn main() { // 5. read-value unsafe { let j1 = spawn(move || { - //Concurrent allocate the memory. - //Uses relaxed semantics to not generate - //a release sequence. + // Concurrent allocate the memory. + // Uses relaxed semantics to not generate + // a release sequence. let pointer = &*ptr.0; let mut stack_var = 0usize; diff --git a/tests/compile-fail/data_race/write_write_race_stack.rs b/tests/compile-fail/data_race/write_write_race_stack.rs index 46d0911be189..51bf0120d69f 100644 --- a/tests/compile-fail/data_race/write_write_race_stack.rs +++ b/tests/compile-fail/data_race/write_write_race_stack.rs @@ -29,9 +29,9 @@ pub fn main() { // 5. write-value unsafe { let j1 = spawn(move || { - //Concurrent allocate the memory. - //Uses relaxed semantics to not generate - //a release sequence. + // Concurrent allocate the memory. + // Uses relaxed semantics to not generate + // a release sequence. let pointer = &*ptr.0; let mut stack_var = 0usize; From fbe7fbb8900a93cbe080db35e68f35fd515fa87d Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Mon, 7 Dec 2020 21:13:11 +0000 Subject: [PATCH 2475/5092] Add concurrent caller location test --- .../concurrency/concurrent_caller_location.rs | 17 +++++++++++++++++ .../concurrent_caller_location.stderr | 2 ++ 2 files changed, 19 insertions(+) create mode 100644 tests/run-pass/concurrency/concurrent_caller_location.rs create mode 100644 tests/run-pass/concurrency/concurrent_caller_location.stderr diff --git a/tests/run-pass/concurrency/concurrent_caller_location.rs b/tests/run-pass/concurrency/concurrent_caller_location.rs new file mode 100644 index 000000000000..e3e2f9ac60ae --- /dev/null +++ b/tests/run-pass/concurrency/concurrent_caller_location.rs @@ -0,0 +1,17 @@ +use std::thread::spawn; +use std::panic::Location; + +fn initialize() { + let _ignore = initialize_inner(); +} + +fn initialize_inner() -> &'static Location<'static> { + Location::caller() +} + +fn main() { + let j1 = spawn(initialize); + let j2 = spawn(initialize); + j1.join().unwrap(); + j2.join().unwrap(); +} diff --git a/tests/run-pass/concurrency/concurrent_caller_location.stderr b/tests/run-pass/concurrency/concurrent_caller_location.stderr new file mode 100644 index 000000000000..03676519d4f1 --- /dev/null +++ b/tests/run-pass/concurrency/concurrent_caller_location.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + From 296ba8b1c84f65d123fa5b35f6f2e47e73710b08 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Mon, 7 Dec 2020 23:18:57 +0000 Subject: [PATCH 2476/5092] Fix bug with reporting wrong thread for races with reads & add thread ids to data-race tests --- src/data_race.rs | 19 +++++++++++-------- .../compile-fail/data_race/alloc_read_race.rs | 4 +++- .../data_race/alloc_write_race.rs | 11 ++++++++--- .../data_race/atomic_read_na_write_race1.rs | 2 +- .../data_race/atomic_read_na_write_race2.rs | 2 +- .../data_race/atomic_write_na_read_race1.rs | 2 +- .../data_race/atomic_write_na_read_race2.rs | 2 +- .../data_race/atomic_write_na_write_race1.rs | 2 +- .../data_race/atomic_write_na_write_race2.rs | 2 +- .../data_race/dangling_thread_async_race.rs | 4 ++-- .../data_race/dangling_thread_race.rs | 2 +- .../data_race/dealloc_read_race.rs | 2 +- .../data_race/dealloc_read_race_stack.rs | 2 +- .../data_race/dealloc_read_race_stack_drop.rs | 3 +-- .../data_race/dealloc_write_race.rs | 2 +- .../data_race/dealloc_write_race_stack.rs | 2 +- .../dealloc_write_race_stack_drop.rs | 3 ++- .../data_race/enable_after_join_to_main.rs | 2 +- .../compile-fail/data_race/read_write_race.rs | 2 +- .../data_race/read_write_race_stack.rs | 2 +- .../data_race/relax_acquire_race.rs | 2 +- .../data_race/release_seq_race.rs | 2 +- .../data_race/release_seq_race_same_thread.rs | 2 +- tests/compile-fail/data_race/rmw_race.rs | 2 +- .../data_race/write_write_race.rs | 2 +- .../data_race/write_write_race_stack.rs | 2 +- 26 files changed, 47 insertions(+), 37 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index 052b92453082..7211f3176350 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -204,9 +204,9 @@ enum WriteType { impl WriteType { fn get_descriptor(self) -> &'static str { match self { - WriteType::Allocate => "ALLOCATE", - WriteType::Write => "WRITE", - WriteType::Deallocate => "DEALLOCATE", + WriteType::Allocate => "Allocate", + WriteType::Write => "Write", + WriteType::Deallocate => "Deallocate", } } } @@ -695,6 +695,7 @@ impl VClockAlloc { // Find an index, if one exists where the value // in `l` is greater than the value in `r`. fn find_gt_index(l: &VClock, r: &VClock) -> Option { + log::info!("Find index where not {:?} <= {:?}", l, r); let l_slice = l.as_slice(); let r_slice = r.as_slice(); l_slice @@ -714,7 +715,7 @@ impl VClockAlloc { .enumerate() .find_map(|(idx, &r)| if r == 0 { None } else { Some(idx) }) .expect("Invalid VClock Invariant"); - Some(idx) + Some(idx + r_slice.len()) } else { None } @@ -747,16 +748,16 @@ impl VClockAlloc { write_clock = VClock::new_with_index(range.write_index, range.write); (range.write_type.get_descriptor(), range.write_index, &write_clock) } else if let Some(idx) = Self::find_gt_index(&range.read, ¤t_clocks.clock) { - ("READ", idx, &range.read) + ("Read", idx, &range.read) } else if !is_atomic { if let Some(atomic) = range.atomic() { if let Some(idx) = Self::find_gt_index(&atomic.write_vector, ¤t_clocks.clock) { - ("ATOMIC_STORE", idx, &atomic.write_vector) + ("Atomic Store", idx, &atomic.write_vector) } else if let Some(idx) = Self::find_gt_index(&atomic.read_vector, ¤t_clocks.clock) { - ("ATOMIC_LOAD", idx, &atomic.read_vector) + ("Atomic Load", idx, &atomic.read_vector) } else { unreachable!( "Failed to report data-race for non-atomic operation: no race found" @@ -807,7 +808,7 @@ impl VClockAlloc { return Self::report_data_race( &self.global, range, - "READ", + "Read", false, pointer, len, @@ -1167,6 +1168,8 @@ impl GlobalState { vector_info.push(thread) }; + log::info!("Creating thread = {:?} with vector index = {:?}", thread, created_index); + // Mark the chosen vector index as in use by the thread. thread_info[thread].vector_index = Some(created_index); diff --git a/tests/compile-fail/data_race/alloc_read_race.rs b/tests/compile-fail/data_race/alloc_read_race.rs index 9ebb793c71ba..620a019b65c7 100644 --- a/tests/compile-fail/data_race/alloc_read_race.rs +++ b/tests/compile-fail/data_race/alloc_read_race.rs @@ -33,7 +33,9 @@ pub fn main() { let j2 = spawn(move || { let pointer = &*ptr.0; - *pointer.load(Ordering::Relaxed) //~ ERROR Data race + + //Note detects with write due to the initialization of memory + *pointer.load(Ordering::Relaxed) //~ ERROR Data race detected between Read on Thread(id = 2) and Write on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/compile-fail/data_race/alloc_write_race.rs b/tests/compile-fail/data_race/alloc_write_race.rs index 229d3cea2c93..d9f5af396a2d 100644 --- a/tests/compile-fail/data_race/alloc_write_race.rs +++ b/tests/compile-fail/data_race/alloc_write_race.rs @@ -10,6 +10,11 @@ struct EvilSend(pub T); unsafe impl Send for EvilSend {} unsafe impl Sync for EvilSend {} +extern "C" { + fn malloc(size: usize) -> *mut u8; + fn free(ptr: *mut u8); +} + pub fn main() { // Shared atomic pointer let pointer = AtomicPtr::new(null_mut::()); @@ -28,18 +33,18 @@ pub fn main() { // Uses relaxed semantics to not generate // a release sequence. let pointer = &*ptr.0; - pointer.store(Box::into_raw(Box::new(0usize)), Ordering::Relaxed); + pointer.store(malloc(std::mem::size_of::()) as *mut usize, Ordering::Relaxed); }); let j2 = spawn(move || { let pointer = &*ptr.0; - *pointer.load(Ordering::Relaxed) = 2; //~ ERROR Data race + *pointer.load(Ordering::Relaxed) = 2; //~ ERROR Data race detected between Write on Thread(id = 2) and Allocate on Thread(id = 1) }); j1.join().unwrap(); j2.join().unwrap(); // Clean up memory, will never be executed - drop(Box::from_raw(pointer.load(Ordering::Relaxed))); + free(pointer.load(Ordering::Relaxed) as *mut _); } } diff --git a/tests/compile-fail/data_race/atomic_read_na_write_race1.rs b/tests/compile-fail/data_race/atomic_read_na_write_race1.rs index 0b9610edc64b..44860ee62800 100644 --- a/tests/compile-fail/data_race/atomic_read_na_write_race1.rs +++ b/tests/compile-fail/data_race/atomic_read_na_write_race1.rs @@ -22,7 +22,7 @@ pub fn main() { let j2 = spawn(move || { //Equivalent to: (&*c.0).load(Ordering::SeqCst) - atomic_load(c.0 as *mut usize) //~ ERROR Data race + atomic_load(c.0 as *mut usize) //~ ERROR Data race detected between Atomic Load on Thread(id = 2) and Write on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/compile-fail/data_race/atomic_read_na_write_race2.rs b/tests/compile-fail/data_race/atomic_read_na_write_race2.rs index 779babefd8e6..6d28e18886cd 100644 --- a/tests/compile-fail/data_race/atomic_read_na_write_race2.rs +++ b/tests/compile-fail/data_race/atomic_read_na_write_race2.rs @@ -22,7 +22,7 @@ pub fn main() { let j2 = spawn(move || { let atomic_ref = &mut *c.0; - *atomic_ref.get_mut() = 32; //~ ERROR Data race + *atomic_ref.get_mut() = 32; //~ ERROR Data race detected between Write on Thread(id = 2) and Atomic Load on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/compile-fail/data_race/atomic_write_na_read_race1.rs b/tests/compile-fail/data_race/atomic_write_na_read_race1.rs index 3211a5ae5344..0b753f6710a5 100644 --- a/tests/compile-fail/data_race/atomic_write_na_read_race1.rs +++ b/tests/compile-fail/data_race/atomic_write_na_read_race1.rs @@ -22,7 +22,7 @@ pub fn main() { let j2 = spawn(move || { let atomic_ref = &mut *c.0; - *atomic_ref.get_mut() //~ ERROR Data race + *atomic_ref.get_mut() //~ ERROR Data race detected between Read on Thread(id = 2) and Atomic Store on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/compile-fail/data_race/atomic_write_na_read_race2.rs b/tests/compile-fail/data_race/atomic_write_na_read_race2.rs index 131d4e07b829..a9f5fb2fe5bc 100644 --- a/tests/compile-fail/data_race/atomic_write_na_read_race2.rs +++ b/tests/compile-fail/data_race/atomic_write_na_read_race2.rs @@ -22,7 +22,7 @@ pub fn main() { let j2 = spawn(move || { //Equivalent to: (&*c.0).store(32, Ordering::SeqCst) - atomic_store(c.0 as *mut usize, 32); //~ ERROR Data race + atomic_store(c.0 as *mut usize, 32); //~ ERROR Data race detected between Atomic Store on Thread(id = 2) and Read on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/compile-fail/data_race/atomic_write_na_write_race1.rs b/tests/compile-fail/data_race/atomic_write_na_write_race1.rs index 74adf7ae4b8d..d5a828fa6e41 100644 --- a/tests/compile-fail/data_race/atomic_write_na_write_race1.rs +++ b/tests/compile-fail/data_race/atomic_write_na_write_race1.rs @@ -22,7 +22,7 @@ pub fn main() { let j2 = spawn(move || { //Equivalent to: (&*c.0).store(64, Ordering::SeqCst) - atomic_store(c.0 as *mut usize, 64); //~ ERROR Data race + atomic_store(c.0 as *mut usize, 64); //~ ERROR Data race detected between Atomic Store on Thread(id = 2) and Write on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/compile-fail/data_race/atomic_write_na_write_race2.rs b/tests/compile-fail/data_race/atomic_write_na_write_race2.rs index 75ad755fbd2c..9812dcd79920 100644 --- a/tests/compile-fail/data_race/atomic_write_na_write_race2.rs +++ b/tests/compile-fail/data_race/atomic_write_na_write_race2.rs @@ -22,7 +22,7 @@ pub fn main() { let j2 = spawn(move || { let atomic_ref = &mut *c.0; - *atomic_ref.get_mut() = 32; //~ ERROR Data race + *atomic_ref.get_mut() = 32; //~ ERROR Data race detected between Write on Thread(id = 2) and Atomic Store on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/compile-fail/data_race/dangling_thread_async_race.rs b/tests/compile-fail/data_race/dangling_thread_async_race.rs index ece831685287..61587dc6384a 100644 --- a/tests/compile-fail/data_race/dangling_thread_async_race.rs +++ b/tests/compile-fail/data_race/dangling_thread_async_race.rs @@ -24,7 +24,7 @@ fn main() { }) }; - // Detatch the thread and sleep until it terminates + // Detach the thread and sleep until it terminates mem::drop(join); sleep(Duration::from_millis(1000)); @@ -36,7 +36,7 @@ fn main() { let join2 = unsafe { spawn(move || { - *c.0 = 64; //~ ERROR Data race + *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 3) and Write on Thread(id = 1) }) }; diff --git a/tests/compile-fail/data_race/dangling_thread_race.rs b/tests/compile-fail/data_race/dangling_thread_race.rs index 873d10b788f1..c14b68080cc8 100644 --- a/tests/compile-fail/data_race/dangling_thread_race.rs +++ b/tests/compile-fail/data_race/dangling_thread_race.rs @@ -36,6 +36,6 @@ fn main() { unsafe { - *c.0 = 64; //~ ERROR Data race + *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) } } diff --git a/tests/compile-fail/data_race/dealloc_read_race.rs b/tests/compile-fail/data_race/dealloc_read_race.rs index f6479d246f8d..14b02e95cc23 100644 --- a/tests/compile-fail/data_race/dealloc_read_race.rs +++ b/tests/compile-fail/data_race/dealloc_read_race.rs @@ -23,7 +23,7 @@ pub fn main() { }); let j2 = spawn(move || { - __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()); //~ ERROR Data race + __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()); //~ ERROR Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack.rs b/tests/compile-fail/data_race/dealloc_read_race_stack.rs index 275d1d1cccf0..8a770563c753 100644 --- a/tests/compile-fail/data_race/dealloc_read_race_stack.rs +++ b/tests/compile-fail/data_race/dealloc_read_race_stack.rs @@ -38,7 +38,7 @@ pub fn main() { sleep(Duration::from_millis(1000)); - } //~ ERROR Data race + } //~ ERROR Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2) }); let j2 = spawn(move || { diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs b/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs index d5131687d78b..315d5eef3f01 100644 --- a/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs +++ b/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs @@ -38,9 +38,8 @@ pub fn main() { sleep(Duration::from_millis(1000)); - // NOTE: the race is also detected with thread 0, and so reported for thread 0 instead of 2, unsure of the cause. drop(stack_var); - }); //~ ERROR Data race detected between DEALLOCATE on Thread(id = 1) and READ on Thread(id = 0, name = "main") + }); //~ ERROR Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2) let j2 = spawn(move || { let pointer = &*ptr.0; diff --git a/tests/compile-fail/data_race/dealloc_write_race.rs b/tests/compile-fail/data_race/dealloc_write_race.rs index e2527f6e9045..edcdfffdb5f5 100644 --- a/tests/compile-fail/data_race/dealloc_write_race.rs +++ b/tests/compile-fail/data_race/dealloc_write_race.rs @@ -22,7 +22,7 @@ pub fn main() { }); let j2 = spawn(move || { - __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()); //~ ERROR Data race + __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()); //~ ERROR Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack.rs b/tests/compile-fail/data_race/dealloc_write_race_stack.rs index 3fcbe7661ff4..a245522b06f3 100644 --- a/tests/compile-fail/data_race/dealloc_write_race_stack.rs +++ b/tests/compile-fail/data_race/dealloc_write_race_stack.rs @@ -38,7 +38,7 @@ pub fn main() { sleep(Duration::from_millis(1000)); - } //~ ERROR Data race + } //~ ERROR Data race detected between Deallocate on Thread(id = 1) and Write on Thread(id = 2) }); let j2 = spawn(move || { diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs b/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs index 5483be9f788f..db0bb2527763 100644 --- a/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs +++ b/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs @@ -38,7 +38,8 @@ pub fn main() { sleep(Duration::from_millis(1000)); - drop(stack_var); //~ ERROR Data race + // FIXME: find cause of implicit read event + drop(stack_var); //~ ERROR Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) }); let j2 = spawn(move || { diff --git a/tests/compile-fail/data_race/enable_after_join_to_main.rs b/tests/compile-fail/data_race/enable_after_join_to_main.rs index c29431777137..832158a34a6a 100644 --- a/tests/compile-fail/data_race/enable_after_join_to_main.rs +++ b/tests/compile-fail/data_race/enable_after_join_to_main.rs @@ -29,7 +29,7 @@ pub fn main() { }); let j2 = spawn(move || { - *c.0 = 64; //~ ERROR Data race + *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 6) and Write on Thread(id = 5) }); j1.join().unwrap(); diff --git a/tests/compile-fail/data_race/read_write_race.rs b/tests/compile-fail/data_race/read_write_race.rs index 42fd7a51ffbd..0df66d66ad07 100644 --- a/tests/compile-fail/data_race/read_write_race.rs +++ b/tests/compile-fail/data_race/read_write_race.rs @@ -18,7 +18,7 @@ pub fn main() { }); let j2 = spawn(move || { - *c.0 = 64; //~ ERROR Data race + *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 2) and Read on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/compile-fail/data_race/read_write_race_stack.rs b/tests/compile-fail/data_race/read_write_race_stack.rs index 7f2dbcc6ed5d..43270e0e915d 100644 --- a/tests/compile-fail/data_race/read_write_race_stack.rs +++ b/tests/compile-fail/data_race/read_write_race_stack.rs @@ -41,7 +41,7 @@ pub fn main() { sleep(Duration::from_millis(1000)); //read - stack_var //~ ERROR Data race + stack_var //~ ERROR Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) }); let j2 = spawn(move || { diff --git a/tests/compile-fail/data_race/relax_acquire_race.rs b/tests/compile-fail/data_race/relax_acquire_race.rs index 2ae0aacbcf77..8b8616431f37 100644 --- a/tests/compile-fail/data_race/relax_acquire_race.rs +++ b/tests/compile-fail/data_race/relax_acquire_race.rs @@ -37,7 +37,7 @@ pub fn main() { let j3 = spawn(move || { if SYNC.load(Ordering::Acquire) == 2 { - *c.0 //~ ERROR Data race + *c.0 //~ ERROR Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) } else { 0 } diff --git a/tests/compile-fail/data_race/release_seq_race.rs b/tests/compile-fail/data_race/release_seq_race.rs index d0d625a6ce17..91235280d210 100644 --- a/tests/compile-fail/data_race/release_seq_race.rs +++ b/tests/compile-fail/data_race/release_seq_race.rs @@ -42,7 +42,7 @@ pub fn main() { let j3 = spawn(move || { sleep(Duration::from_millis(5000)); if SYNC.load(Ordering::Acquire) == 3 { - *c.0 //~ ERROR Data race + *c.0 //~ ERROR Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) } else { 0 } diff --git a/tests/compile-fail/data_race/release_seq_race_same_thread.rs b/tests/compile-fail/data_race/release_seq_race_same_thread.rs index d64b80dbd84c..54b9f49937c8 100644 --- a/tests/compile-fail/data_race/release_seq_race_same_thread.rs +++ b/tests/compile-fail/data_race/release_seq_race_same_thread.rs @@ -38,7 +38,7 @@ pub fn main() { let j2 = spawn(move || { if SYNC.load(Ordering::Acquire) == 2 { - *c.0 //~ ERROR Data race + *c.0 //~ ERROR Data race detected between Read on Thread(id = 2) and Write on Thread(id = 1) } else { 0 } diff --git a/tests/compile-fail/data_race/rmw_race.rs b/tests/compile-fail/data_race/rmw_race.rs index e523f8b374cc..fcf683a65d8e 100644 --- a/tests/compile-fail/data_race/rmw_race.rs +++ b/tests/compile-fail/data_race/rmw_race.rs @@ -38,7 +38,7 @@ pub fn main() { let j3 = spawn(move || { if SYNC.load(Ordering::Acquire) == 3 { - *c.0 //~ ERROR Data race + *c.0 //~ ERROR Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) } else { 0 } diff --git a/tests/compile-fail/data_race/write_write_race.rs b/tests/compile-fail/data_race/write_write_race.rs index aca19a46c13d..61909eda8633 100644 --- a/tests/compile-fail/data_race/write_write_race.rs +++ b/tests/compile-fail/data_race/write_write_race.rs @@ -18,7 +18,7 @@ pub fn main() { }); let j2 = spawn(move || { - *c.0 = 64; //~ ERROR Data race + *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 2) and Write on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/compile-fail/data_race/write_write_race_stack.rs b/tests/compile-fail/data_race/write_write_race_stack.rs index 51bf0120d69f..91ac51787fbe 100644 --- a/tests/compile-fail/data_race/write_write_race_stack.rs +++ b/tests/compile-fail/data_race/write_write_race_stack.rs @@ -40,7 +40,7 @@ pub fn main() { sleep(Duration::from_millis(1000)); - stack_var = 1usize; //~ ERROR Data race + stack_var = 1usize; //~ ERROR Data race detected between Write on Thread(id = 1) and Write on Thread(id = 2) // read to silence errors stack_var From 8676c60f87b299fdcfa1a9f5d97ebd6340a09913 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Mon, 7 Dec 2020 23:21:58 +0000 Subject: [PATCH 2477/5092] Update note --- tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs b/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs index db0bb2527763..e936a2154ad1 100644 --- a/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs +++ b/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs @@ -38,7 +38,7 @@ pub fn main() { sleep(Duration::from_millis(1000)); - // FIXME: find cause of implicit read event + // Note: Implicit read for drop(_) races with write, would detect race with deallocate after. drop(stack_var); //~ ERROR Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) }); From a30105df0ba441649817f6c952d5863f730c67d5 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Mon, 7 Dec 2020 23:30:55 +0000 Subject: [PATCH 2478/5092] Defeat the mir-opt=3 optimizer. --- tests/compile-fail/data_race/read_write_race_stack.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/compile-fail/data_race/read_write_race_stack.rs b/tests/compile-fail/data_race/read_write_race_stack.rs index 43270e0e915d..d3d0bfdfc480 100644 --- a/tests/compile-fail/data_race/read_write_race_stack.rs +++ b/tests/compile-fail/data_race/read_write_race_stack.rs @@ -40,8 +40,9 @@ pub fn main() { sleep(Duration::from_millis(1000)); - //read - stack_var //~ ERROR Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) + // Read, the add 1 fixes -Z mir-opt-level=3 from removing the read via dest-prop and breaking + // the test. + stack_var + 1 //~ ERROR Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) }); let j2 = spawn(move || { From 3df67141e67a289bf410742ace2b6d5b86ce07ae Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Mon, 7 Dec 2020 23:43:19 +0000 Subject: [PATCH 2479/5092] Disable tests in windows --- tests/run-pass/concurrency/concurrent_caller_location.rs | 2 ++ tests/run-pass/concurrency/issue1643.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tests/run-pass/concurrency/concurrent_caller_location.rs b/tests/run-pass/concurrency/concurrent_caller_location.rs index e3e2f9ac60ae..d509d1b3f797 100644 --- a/tests/run-pass/concurrency/concurrent_caller_location.rs +++ b/tests/run-pass/concurrency/concurrent_caller_location.rs @@ -1,3 +1,5 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + use std::thread::spawn; use std::panic::Location; diff --git a/tests/run-pass/concurrency/issue1643.rs b/tests/run-pass/concurrency/issue1643.rs index c0956569ad8f..1238a1bd6f5e 100644 --- a/tests/run-pass/concurrency/issue1643.rs +++ b/tests/run-pass/concurrency/issue1643.rs @@ -1,3 +1,5 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + use std::thread::spawn; fn initialize() { From 4e74f9f013f6093a4f1cb601667a07aadac75b42 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Tue, 8 Dec 2020 14:16:39 +0000 Subject: [PATCH 2480/5092] Change to disable mir-opt in compile-flags --- tests/compile-fail/data_race/read_write_race_stack.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/compile-fail/data_race/read_write_race_stack.rs b/tests/compile-fail/data_race/read_write_race_stack.rs index d3d0bfdfc480..0fc45c8fafc7 100644 --- a/tests/compile-fail/data_race/read_write_race_stack.rs +++ b/tests/compile-fail/data_race/read_write_race_stack.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation +// compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 use std::thread::{spawn, sleep}; use std::ptr::null_mut; @@ -40,9 +40,7 @@ pub fn main() { sleep(Duration::from_millis(1000)); - // Read, the add 1 fixes -Z mir-opt-level=3 from removing the read via dest-prop and breaking - // the test. - stack_var + 1 //~ ERROR Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) + stack_var //~ ERROR Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) }); let j2 = spawn(move || { From aaf8ca4c770f7e18b3191e9f0124ac2e60542e42 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Wed, 9 Dec 2020 13:35:42 +0000 Subject: [PATCH 2481/5092] Fix review changes --- src/data_race.rs | 20 ++++++++--- src/machine.rs | 5 ++- .../compile-fail/data_race/alloc_read_race.rs | 11 +++--- .../data_race/dangling_thread_async_race.rs | 2 +- .../data_race/dangling_thread_race.rs | 4 +-- ...loc_read_race.rs => dealloc_read_race1.rs} | 0 .../data_race/dealloc_read_race2.rs | 34 +++++++++++++++++++ .../data_race/dealloc_read_race_stack.rs | 2 +- .../data_race/dealloc_read_race_stack_drop.rs | 2 +- ...c_write_race.rs => dealloc_write_race1.rs} | 0 .../data_race/dealloc_write_race2.rs | 33 ++++++++++++++++++ .../data_race/dealloc_write_race_stack.rs | 2 +- .../dealloc_write_race_stack_drop.rs | 2 +- .../data_race/read_write_race_stack.rs | 5 ++- .../data_race/release_seq_race.rs | 4 +-- .../data_race/write_write_race_stack.rs | 2 +- 16 files changed, 107 insertions(+), 21 deletions(-) rename tests/compile-fail/data_race/{dealloc_read_race.rs => dealloc_read_race1.rs} (100%) create mode 100644 tests/compile-fail/data_race/dealloc_read_race2.rs rename tests/compile-fail/data_race/{dealloc_write_race.rs => dealloc_write_race1.rs} (100%) create mode 100644 tests/compile-fail/data_race/dealloc_write_race2.rs diff --git a/src/data_race.rs b/src/data_race.rs index 7211f3176350..2fff13a80661 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -9,6 +9,9 @@ //! Relaxed stores now unconditionally block all currently active release sequences and so per-thread tracking of release //! sequences is not needed. //! +//! The implementation also models races with memory allocation and deallocation via treating allocation and +//! deallocation as a type of write internally for detecting data-races. +//! //! This does not explore weak memory orders and so can still miss data-races //! but should not report false-positives //! @@ -192,13 +195,22 @@ struct AtomicMemoryCellClocks { sync_vector: VClock, } +/// Type of write operation: allocating memory +/// non-atomic writes and deallocating memory +/// are all treated as writes for the purpose +/// of the data-race detector. #[derive(Copy, Clone, PartialEq, Eq, Debug)] enum WriteType { /// Allocate memory. Allocate, + /// Standard unsynchronized write. Write, - /// Deallocate memory + + /// Deallocate memory. + /// Some races with deallocation will be missed and instead + /// reported as invalid accesses of freed memory due to + /// the order of checks. Deallocate, } impl WriteType { @@ -681,7 +693,7 @@ impl VClockAlloc { let (alloc_index, clocks) = global.current_thread_state(); let alloc_timestamp = clocks.clock[alloc_index]; (alloc_timestamp, alloc_index) - }else{ + } else { (0, VectorIdx::MAX_INDEX) }; VClockAlloc { @@ -695,7 +707,7 @@ impl VClockAlloc { // Find an index, if one exists where the value // in `l` is greater than the value in `r`. fn find_gt_index(l: &VClock, r: &VClock) -> Option { - log::info!("Find index where not {:?} <= {:?}", l, r); + log::trace!("Find index where not {:?} <= {:?}", l, r); let l_slice = l.as_slice(); let r_slice = r.as_slice(); l_slice @@ -1168,7 +1180,7 @@ impl GlobalState { vector_info.push(thread) }; - log::info!("Creating thread = {:?} with vector index = {:?}", thread, created_index); + log::trace!("Creating thread = {:?} with vector index = {:?}", thread, created_index); // Mark the chosen vector index as in use by the thread. thread_info[thread].vector_index = Some(created_index); diff --git a/src/machine.rs b/src/machine.rs index 159e08c87d3f..9825467a2cae 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -480,7 +480,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { let race_alloc = if let Some(data_race) = &memory_extra.data_race { match kind { // V-Table generation is lazy and so racy, so do not track races. - // Also V-Tables are read only so no data races can be detected. + // Also V-Tables are read only so no data races can be occur. + // Must be disabled since V-Tables are initialized via interpreter + // writes on demand and can incorrectly cause the data-race detector + // to trigger. MemoryKind::Vtable => None, // User allocated and stack memory should track allocation. MemoryKind::Machine( diff --git a/tests/compile-fail/data_race/alloc_read_race.rs b/tests/compile-fail/data_race/alloc_read_race.rs index 620a019b65c7..fc1e9d30e637 100644 --- a/tests/compile-fail/data_race/alloc_read_race.rs +++ b/tests/compile-fail/data_race/alloc_read_race.rs @@ -3,6 +3,7 @@ use std::thread::spawn; use std::ptr::null_mut; use std::sync::atomic::{Ordering, AtomicPtr}; +use std::mem::MaybeUninit; #[derive(Copy, Clone)] struct EvilSend(pub T); @@ -12,8 +13,8 @@ unsafe impl Sync for EvilSend {} pub fn main() { // Shared atomic pointer - let pointer = AtomicPtr::new(null_mut::()); - let ptr = EvilSend(&pointer as *const AtomicPtr); + let pointer = AtomicPtr::new(null_mut::>()); + let ptr = EvilSend(&pointer as *const AtomicPtr>); // Note: this is scheduler-dependent // the operations need to occur in @@ -28,14 +29,14 @@ pub fn main() { // Uses relaxed semantics to not generate // a release sequence. let pointer = &*ptr.0; - pointer.store(Box::into_raw(Box::new(0usize)), Ordering::Relaxed); + pointer.store(Box::into_raw(Box::new(MaybeUninit::uninit())), Ordering::Relaxed); }); let j2 = spawn(move || { let pointer = &*ptr.0; - //Note detects with write due to the initialization of memory - *pointer.load(Ordering::Relaxed) //~ ERROR Data race detected between Read on Thread(id = 2) and Write on Thread(id = 1) + // Note: could also error due to reading uninitialized memory, but the data-race detector triggers first. + *pointer.load(Ordering::Relaxed) //~ ERROR Data race detected between Read on Thread(id = 2) and Allocate on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/compile-fail/data_race/dangling_thread_async_race.rs b/tests/compile-fail/data_race/dangling_thread_async_race.rs index 61587dc6384a..ad539ec5b083 100644 --- a/tests/compile-fail/data_race/dangling_thread_async_race.rs +++ b/tests/compile-fail/data_race/dangling_thread_async_race.rs @@ -26,7 +26,7 @@ fn main() { // Detach the thread and sleep until it terminates mem::drop(join); - sleep(Duration::from_millis(1000)); + sleep(Duration::from_millis(200)); // Spawn and immediately join a thread // to execute the join code-path diff --git a/tests/compile-fail/data_race/dangling_thread_race.rs b/tests/compile-fail/data_race/dangling_thread_race.rs index c14b68080cc8..755ba8efdae9 100644 --- a/tests/compile-fail/data_race/dangling_thread_race.rs +++ b/tests/compile-fail/data_race/dangling_thread_race.rs @@ -24,9 +24,9 @@ fn main() { }) }; - // Detatch the thread and sleep until it terminates + // Detach the thread and sleep until it terminates mem::drop(join); - sleep(Duration::from_millis(1000)); + sleep(Duration::from_millis(200)); // Spawn and immediately join a thread // to execute the join code-path diff --git a/tests/compile-fail/data_race/dealloc_read_race.rs b/tests/compile-fail/data_race/dealloc_read_race1.rs similarity index 100% rename from tests/compile-fail/data_race/dealloc_read_race.rs rename to tests/compile-fail/data_race/dealloc_read_race1.rs diff --git a/tests/compile-fail/data_race/dealloc_read_race2.rs b/tests/compile-fail/data_race/dealloc_read_race2.rs new file mode 100644 index 000000000000..a4bf210ef439 --- /dev/null +++ b/tests/compile-fail/data_race/dealloc_read_race2.rs @@ -0,0 +1,34 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +use std::thread::spawn; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +extern "Rust" { + fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); +} + +pub fn main() { + // Shared atomic pointer + let pointer: *mut usize = Box::into_raw(Box::new(0usize)); + let ptr = EvilSend(pointer); + + unsafe { + let j1 = spawn(move || { + __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()) + }); + + let j2 = spawn(move || { + // Also an error of the form: Data race detected between Read on Thread(id = 2) and Deallocate on Thread(id = 1) + // but the invalid allocation is detected first. + *ptr.0 //~ ERROR dereferenced after this allocation got freed + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack.rs b/tests/compile-fail/data_race/dealloc_read_race_stack.rs index 8a770563c753..31960fb2162b 100644 --- a/tests/compile-fail/data_race/dealloc_read_race_stack.rs +++ b/tests/compile-fail/data_race/dealloc_read_race_stack.rs @@ -36,7 +36,7 @@ pub fn main() { pointer.store(&mut stack_var as *mut _, Ordering::Release); - sleep(Duration::from_millis(1000)); + sleep(Duration::from_millis(200)); } //~ ERROR Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2) }); diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs b/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs index 315d5eef3f01..44950a34db2f 100644 --- a/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs +++ b/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs @@ -36,7 +36,7 @@ pub fn main() { pointer.store(&mut stack_var as *mut _, Ordering::Release); - sleep(Duration::from_millis(1000)); + sleep(Duration::from_millis(200)); drop(stack_var); }); //~ ERROR Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2) diff --git a/tests/compile-fail/data_race/dealloc_write_race.rs b/tests/compile-fail/data_race/dealloc_write_race1.rs similarity index 100% rename from tests/compile-fail/data_race/dealloc_write_race.rs rename to tests/compile-fail/data_race/dealloc_write_race1.rs diff --git a/tests/compile-fail/data_race/dealloc_write_race2.rs b/tests/compile-fail/data_race/dealloc_write_race2.rs new file mode 100644 index 000000000000..20c05fa8f17b --- /dev/null +++ b/tests/compile-fail/data_race/dealloc_write_race2.rs @@ -0,0 +1,33 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +use std::thread::spawn; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +extern "Rust" { + fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); +} +pub fn main() { + // Shared atomic pointer + let pointer: *mut usize = Box::into_raw(Box::new(0usize)); + let ptr = EvilSend(pointer); + + unsafe { + let j1 = spawn(move || { + __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()); + }); + + let j2 = spawn(move || { + // Also an error of the form: Data race detected between Write on Thread(id = 2) and Deallocate on Thread(id = 1) + // but the invalid allocation is detected first. + *ptr.0 = 2; //~ ERROR dereferenced after this allocation got freed + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack.rs b/tests/compile-fail/data_race/dealloc_write_race_stack.rs index a245522b06f3..25dea65fe7e0 100644 --- a/tests/compile-fail/data_race/dealloc_write_race_stack.rs +++ b/tests/compile-fail/data_race/dealloc_write_race_stack.rs @@ -36,7 +36,7 @@ pub fn main() { pointer.store(&mut stack_var as *mut _, Ordering::Release); - sleep(Duration::from_millis(1000)); + sleep(Duration::from_millis(200)); } //~ ERROR Data race detected between Deallocate on Thread(id = 1) and Write on Thread(id = 2) }); diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs b/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs index e936a2154ad1..1d239e9eb74d 100644 --- a/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs +++ b/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs @@ -36,7 +36,7 @@ pub fn main() { pointer.store(&mut stack_var as *mut _, Ordering::Release); - sleep(Duration::from_millis(1000)); + sleep(Duration::from_millis(200)); // Note: Implicit read for drop(_) races with write, would detect race with deallocate after. drop(stack_var); //~ ERROR Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) diff --git a/tests/compile-fail/data_race/read_write_race_stack.rs b/tests/compile-fail/data_race/read_write_race_stack.rs index 0fc45c8fafc7..0cf915cdef2b 100644 --- a/tests/compile-fail/data_race/read_write_race_stack.rs +++ b/tests/compile-fail/data_race/read_write_race_stack.rs @@ -1,6 +1,9 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 +// Note: mir-opt-level set to 0 to prevent the read of stack_var in thread 1 +// from being optimized away and preventing the detection of the data-race. + use std::thread::{spawn, sleep}; use std::ptr::null_mut; use std::sync::atomic::{Ordering, AtomicPtr}; @@ -38,7 +41,7 @@ pub fn main() { pointer.store(&mut stack_var as *mut _, Ordering::Release); - sleep(Duration::from_millis(1000)); + sleep(Duration::from_millis(200)); stack_var //~ ERROR Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) }); diff --git a/tests/compile-fail/data_race/release_seq_race.rs b/tests/compile-fail/data_race/release_seq_race.rs index 91235280d210..29c428b388d4 100644 --- a/tests/compile-fail/data_race/release_seq_race.rs +++ b/tests/compile-fail/data_race/release_seq_race.rs @@ -30,7 +30,7 @@ pub fn main() { let j1 = spawn(move || { *c.0 = 1; SYNC.store(1, Ordering::Release); - sleep(Duration::from_millis(1000)); + sleep(Duration::from_millis(200)); SYNC.store(3, Ordering::Relaxed); }); @@ -40,7 +40,7 @@ pub fn main() { }); let j3 = spawn(move || { - sleep(Duration::from_millis(5000)); + sleep(Duration::from_millis(500)); if SYNC.load(Ordering::Acquire) == 3 { *c.0 //~ ERROR Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) } else { diff --git a/tests/compile-fail/data_race/write_write_race_stack.rs b/tests/compile-fail/data_race/write_write_race_stack.rs index 91ac51787fbe..aa1428f8a74b 100644 --- a/tests/compile-fail/data_race/write_write_race_stack.rs +++ b/tests/compile-fail/data_race/write_write_race_stack.rs @@ -38,7 +38,7 @@ pub fn main() { pointer.store(&mut stack_var as *mut _, Ordering::Release); - sleep(Duration::from_millis(1000)); + sleep(Duration::from_millis(200)); stack_var = 1usize; //~ ERROR Data race detected between Write on Thread(id = 1) and Write on Thread(id = 2) From 81c4eb7d74624d41b5fdddffa2d239d35c32f4b4 Mon Sep 17 00:00:00 2001 From: JCTyblaidd Date: Thu, 10 Dec 2020 16:56:09 +0000 Subject: [PATCH 2482/5092] Update src/data_race.rs Co-authored-by: Ralf Jung --- src/data_race.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index 2fff13a80661..d16391d0d432 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -208,9 +208,9 @@ enum WriteType { Write, /// Deallocate memory. - /// Some races with deallocation will be missed and instead - /// reported as invalid accesses of freed memory due to - /// the order of checks. + /// Note that when memory is deallocated first, later non-atomic accesses + /// will be reported as use-after-free, not as data races. + /// (Same for `Allocate` above.) Deallocate, } impl WriteType { From e73579632b6d5598406fdb15f32dd0c64d58bebc Mon Sep 17 00:00:00 2001 From: JCTyblaidd Date: Fri, 11 Dec 2020 19:32:25 +0000 Subject: [PATCH 2483/5092] Rework to work with machine hook. --- src/data_race.rs | 38 ++++++++++++++++++++++++++++++++++++-- src/machine.rs | 34 +++++++++++++--------------------- 2 files changed, 49 insertions(+), 23 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index d16391d0d432..ceb715613beb 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -76,7 +76,7 @@ use rustc_target::abi::Size; use crate::{ ImmTy, Immediate, InterpResult, MPlaceTy, MemPlaceMeta, MiriEvalContext, MiriEvalContextExt, OpTy, Pointer, RangeMap, ScalarMaybeUninit, Tag, ThreadId, VClock, VTimestamp, - VectorIdx, + VectorIdx, MemoryKind, MiriMemoryKind }; pub type AllocExtra = VClockAlloc; @@ -674,6 +674,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { Ok(()) } } + + fn reset_vector_clocks( + &mut self, + ptr: Pointer, + size: Size + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + if let Some(data_race) = &mut this.memory.extra.data_race { + if data_race.multi_threaded.get() { + let alloc_meta = this.memory.get_raw_mut(ptr.alloc_id)?.extra.data_race.as_mut().unwrap(); + alloc_meta.reset_clocks(ptr.offset, size); + } + } + Ok(()) + } } /// Vector clock metadata for a logical memory allocation. @@ -688,7 +703,18 @@ pub struct VClockAlloc { impl VClockAlloc { /// Create a new data-race detector for newly allocated memory. - pub fn new_allocation(global: &MemoryExtra, len: Size, track_alloc: bool) -> VClockAlloc { + pub fn new_allocation(global: &MemoryExtra, len: Size, kind: MemoryKind) -> VClockAlloc { + let track_alloc = match kind { + // User allocated and stack memory should track allocation. + MemoryKind::Machine( + MiriMemoryKind::Rust | MiriMemoryKind::C | MiriMemoryKind::WinHeap + ) | MemoryKind::Stack => true, + // Other global memory should trace races but be allocated at the 0 timestamp. + MemoryKind::Machine( + MiriMemoryKind::Global | MiriMemoryKind::Machine | MiriMemoryKind::Env | + MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls + ) | MemoryKind::CallerLocation | MemoryKind::Vtable => false + }; let (alloc_timestamp, alloc_index) = if track_alloc { let (alloc_index, clocks) = global.current_thread_state(); let alloc_timestamp = clocks.clock[alloc_index]; @@ -704,6 +730,14 @@ impl VClockAlloc { } } + fn reset_clocks(&mut self, offset: Size, len: Size) { + let mut alloc_ranges = self.alloc_ranges.borrow_mut(); + for (_, range) in alloc_ranges.iter_mut(offset, len) { + // Reset the portion of the range + *range = MemoryCellClocks::new(0, VectorIdx::MAX_INDEX); + } + } + // Find an index, if one exists where the value // in `l` is greater than the value in `r`. fn find_gt_index(l: &VClock, r: &VClock) -> Option { diff --git a/src/machine.rs b/src/machine.rs index 9825467a2cae..e639bf450ada 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -478,27 +478,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { (None, Tag::Untagged) }; let race_alloc = if let Some(data_race) = &memory_extra.data_race { - match kind { - // V-Table generation is lazy and so racy, so do not track races. - // Also V-Tables are read only so no data races can be occur. - // Must be disabled since V-Tables are initialized via interpreter - // writes on demand and can incorrectly cause the data-race detector - // to trigger. - MemoryKind::Vtable => None, - // User allocated and stack memory should track allocation. - MemoryKind::Machine( - MiriMemoryKind::Rust | MiriMemoryKind::C | MiriMemoryKind::WinHeap - ) | MemoryKind::Stack => Some( - data_race::AllocExtra::new_allocation(&data_race, alloc.size, true) - ), - // Other global memory should trace races but be allocated at the 0 timestamp. - MemoryKind::Machine( - MiriMemoryKind::Global | MiriMemoryKind::Machine | MiriMemoryKind::Env | - MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls - ) | MemoryKind::CallerLocation => Some( - data_race::AllocExtra::new_allocation(&data_race, alloc.size, false) - ) - } + Some(data_race::AllocExtra::new_allocation(&data_race, alloc.size, kind)) } else { None }; @@ -530,6 +510,18 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { Ok(()) } + + fn after_static_mem_initialized( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + ptr: Pointer, + size: Size, + ) -> InterpResult<'tcx> { + if ecx.memory.extra.data_race.is_some() { + ecx.reset_vector_clocks(ptr, size)?; + } + Ok(()) + } + #[inline(always)] fn tag_global_base_pointer(memory_extra: &MemoryExtra, id: AllocId) -> Self::PointerTag { if let Some(stacked_borrows) = &memory_extra.stacked_borrows { From aa4e5b26e6cebac766ea5e06dfee0ca5a34df01d Mon Sep 17 00:00:00 2001 From: JCTyblaidd Date: Sun, 13 Dec 2020 11:08:19 +0000 Subject: [PATCH 2484/5092] Update rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index a11d33b3d336..3b6723b94437 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a2e29d67c26bdf8f278c98ee02d6cc77a279ed2e +12813159a985d87a98578e05cc39200e4e8c2102 From c13aabcb456c54f3f5ecfb48b874293ba1a46b46 Mon Sep 17 00:00:00 2001 From: JCTyblaidd Date: Sun, 13 Dec 2020 11:14:41 +0000 Subject: [PATCH 2485/5092] Tidy new_allocation --- src/data_race.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index ceb715613beb..44cce5395777 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -704,23 +704,22 @@ pub struct VClockAlloc { impl VClockAlloc { /// Create a new data-race detector for newly allocated memory. pub fn new_allocation(global: &MemoryExtra, len: Size, kind: MemoryKind) -> VClockAlloc { - let track_alloc = match kind { + let (alloc_timestamp, alloc_index) = match kind { // User allocated and stack memory should track allocation. MemoryKind::Machine( MiriMemoryKind::Rust | MiriMemoryKind::C | MiriMemoryKind::WinHeap - ) | MemoryKind::Stack => true, + ) | MemoryKind::Stack => { + let (alloc_index, clocks) = global.current_thread_state(); + let alloc_timestamp = clocks.clock[alloc_index]; + (alloc_timestamp, alloc_index) + } // Other global memory should trace races but be allocated at the 0 timestamp. MemoryKind::Machine( MiriMemoryKind::Global | MiriMemoryKind::Machine | MiriMemoryKind::Env | MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls - ) | MemoryKind::CallerLocation | MemoryKind::Vtable => false - }; - let (alloc_timestamp, alloc_index) = if track_alloc { - let (alloc_index, clocks) = global.current_thread_state(); - let alloc_timestamp = clocks.clock[alloc_index]; - (alloc_timestamp, alloc_index) - } else { - (0, VectorIdx::MAX_INDEX) + ) | MemoryKind::CallerLocation | MemoryKind::Vtable => { + (0, VectorIdx::MAX_INDEX) + } }; VClockAlloc { global: Rc::clone(global), From 46162ecb690e956beb2dea7faf43790b6f66f4b7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 17 Dec 2020 12:53:10 +0100 Subject: [PATCH 2486/5092] rustup + cargo update --- Cargo.lock | 115 +++++++++++++++++++++++++++------------------------ rust-version | 2 +- 2 files changed, 61 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 78838acb2a5f..102d29a80435 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,18 +2,18 @@ # It is not intended for manual editing. [[package]] name = "aho-corasick" -version = "0.7.13" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86" +checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" dependencies = [ "memchr", ] [[package]] name = "anyhow" -version = "1.0.32" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b" +checksum = "2c0df63cb2955042487fad3aefd2c6e3ae7389ac5dc1beb28921de0b69f779d4" [[package]] name = "arrayref" @@ -23,9 +23,9 @@ checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" [[package]] name = "arrayvec" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "atty" @@ -46,15 +46,15 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "base64" -version = "0.12.3" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] name = "blake2b_simd" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" +checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" dependencies = [ "arrayref", "arrayvec", @@ -67,6 +67,12 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "colored" version = "2.0.0" @@ -108,12 +114,12 @@ checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" [[package]] name = "crossbeam-utils" -version = "0.7.2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d" dependencies = [ "autocfg", - "cfg-if", + "cfg-if 1.0.0", "lazy_static", ] @@ -129,7 +135,7 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "dirs-sys", ] @@ -159,11 +165,11 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed85775dcc68644b5c950ac06a2b23768d3bc9390464151aaf27136998dcf9e" +checksum = "0c122a393ea57648015bf06fbd3d372378992e86b9ff5a7a497b076a28c79efe" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "redox_syscall", "winapi", @@ -184,7 +190,7 @@ version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "wasi", ] @@ -195,16 +201,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "wasi", ] [[package]] name = "hermit-abi" -version = "0.1.15" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" +checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" dependencies = [ "libc", ] @@ -238,9 +244,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.77" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" +checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" [[package]] name = "log" @@ -248,20 +254,20 @@ version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", ] [[package]] name = "memchr" -version = "2.3.3" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" [[package]] name = "miow" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07b88fb9795d4d36d62a012dfbf49a8f5cf12751f36d31a9dbe66d528e58979e" +checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897" dependencies = [ "socket2", "winapi", @@ -287,15 +293,15 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "proc-macro2" -version = "1.0.21" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36e28516df94f3dd551a587da5357459d9b36d945a7c37c3557928c1c2ff2a2c" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" dependencies = [ "unicode-xid", ] @@ -375,9 +381,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.3.9" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" +checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c" dependencies = [ "aho-corasick", "memchr", @@ -387,9 +393,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.18" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" +checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189" [[package]] name = "remove_dir_all" @@ -402,9 +408,9 @@ dependencies = [ [[package]] name = "rust-argon2" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19" +checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" dependencies = [ "base64", "blake2b_simd", @@ -462,18 +468,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.116" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5" +checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.116" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" +checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" dependencies = [ "proc-macro2", "quote", @@ -482,9 +488,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.57" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c" +checksum = "1500e84d27fe482ed1dc791a56eddc2f230046a040fa908c08bda1d9fb615779" dependencies = [ "itoa", "ryu", @@ -499,27 +505,26 @@ checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" [[package]] name = "smallvec" -version = "1.4.2" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252" +checksum = "ae524f056d7d770e174287294f562e95044c68e88dec909a00d2094805db9d75" [[package]] name = "socket2" -version = "0.3.15" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1fa70dc5c8104ec096f4fe7ede7a221d35ae13dcd19ba1ad9a81d2cab9a1c44" +checksum = "97e0e9fd577458a4f61fb91fcb559ea2afecc54c934119421f9f5d3d5b1a1057" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", - "redox_syscall", "winapi", ] [[package]] name = "syn" -version = "1.0.41" +version = "1.0.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6690e3e9f692504b941dc6c3b188fd28df054f7fb8469ab40680df52fdcc842b" +checksum = "9a2af957a63d6bd42255c359c93d9bfdb97076bd3b820897ce55ffbfbf107f44" dependencies = [ "proc-macro2", "quote", @@ -532,7 +537,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "rand", "redox_syscall", @@ -552,9 +557,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" dependencies = [ "winapi-util", ] diff --git a/rust-version b/rust-version index 3b6723b94437..177c1ee97d6e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -12813159a985d87a98578e05cc39200e4e8c2102 +bdd0a78582efd17f588b35e3e227a65617d5afec From ba0d229752152f67467fc3cbd5c35c3937c46d04 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Dec 2020 10:53:55 +0100 Subject: [PATCH 2487/5092] rustup + cargo-miri 'cargo update' --- cargo-miri/Cargo.lock | 74 +++++++++++++++++++++----------------- rust-version | 2 +- test-cargo-miri/Cargo.lock | 28 +++++++-------- 3 files changed, 56 insertions(+), 48 deletions(-) diff --git a/cargo-miri/Cargo.lock b/cargo-miri/Cargo.lock index 54472947b691..b6abfb1031e6 100644 --- a/cargo-miri/Cargo.lock +++ b/cargo-miri/Cargo.lock @@ -8,9 +8,9 @@ checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" [[package]] name = "arrayvec" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "autocfg" @@ -20,9 +20,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "base64" -version = "0.12.3" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] name = "bitflags" @@ -32,9 +32,9 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "blake2b_simd" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" +checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" dependencies = [ "arrayref", "arrayvec", @@ -60,14 +60,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] -name = "chrono" -version = "0.4.15" +name = "cfg-if" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942f72db697d8767c22d46a598e01f2d3b475501ea43d0db4f16d90259182d0b" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" dependencies = [ + "libc", "num-integer", "num-traits", "time", + "winapi", ] [[package]] @@ -78,12 +86,12 @@ checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" [[package]] name = "crossbeam-utils" -version = "0.7.2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d" dependencies = [ "autocfg", - "cfg-if", + "cfg-if 1.0.0", "lazy_static", ] @@ -113,7 +121,7 @@ version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "wasi 0.9.0+wasi-snapshot-preview1", ] @@ -132,15 +140,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.77" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" +checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" [[package]] name = "num-integer" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" dependencies = [ "autocfg", "num-traits", @@ -148,27 +156,27 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ "autocfg", ] [[package]] name = "proc-macro2" -version = "1.0.21" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36e28516df94f3dd551a587da5357459d9b36d945a7c37c3557928c1c2ff2a2c" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" dependencies = [ "unicode-xid", ] [[package]] name = "quote" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" dependencies = [ "proc-macro2", ] @@ -192,9 +200,9 @@ dependencies = [ [[package]] name = "rust-argon2" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19" +checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" dependencies = [ "base64", "blake2b_simd", @@ -240,18 +248,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.116" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5" +checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.116" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" +checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" dependencies = [ "proc-macro2", "quote", @@ -260,9 +268,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.57" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c" +checksum = "1500e84d27fe482ed1dc791a56eddc2f230046a040fa908c08bda1d9fb615779" dependencies = [ "itoa", "ryu", @@ -271,9 +279,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.41" +version = "1.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6690e3e9f692504b941dc6c3b188fd28df054f7fb8469ab40680df52fdcc842b" +checksum = "a571a711dddd09019ccc628e1b17fe87c59b09d513c06c026877aa708334f37a" dependencies = [ "proc-macro2", "quote", diff --git a/rust-version b/rust-version index 177c1ee97d6e..ec1eb6932417 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -bdd0a78582efd17f588b35e3e227a65617d5afec +15d1f811963649c2f18a88c8e0b39958ec02fd70 diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index b03347d9f0de..8c287098d323 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -34,18 +34,18 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.15" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" +checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" dependencies = [ "libc", ] [[package]] name = "libc" -version = "0.2.77" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" +checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" [[package]] name = "num_cpus" @@ -59,24 +59,24 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "proc-macro2" -version = "1.0.21" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36e28516df94f3dd551a587da5357459d9b36d945a7c37c3557928c1c2ff2a2c" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" dependencies = [ "unicode-xid", ] [[package]] name = "quote" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" dependencies = [ "proc-macro2", ] @@ -134,9 +134,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.116" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" +checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" dependencies = [ "proc-macro2", "quote", @@ -152,9 +152,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.41" +version = "1.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6690e3e9f692504b941dc6c3b188fd28df054f7fb8469ab40680df52fdcc842b" +checksum = "a571a711dddd09019ccc628e1b17fe87c59b09d513c06c026877aa708334f37a" dependencies = [ "proc-macro2", "quote", From 05fcf86f11099b8a416b29ae6d37b870de371041 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Dec 2020 11:29:49 +0100 Subject: [PATCH 2488/5092] rename test ref files for proper names --- test-cargo-miri/run-test.py | 20 +++++++++---------- .../{stderr.ref2 => run.args.stderr.ref} | 0 .../{stdout.ref2 => run.args.stdout.ref} | 0 .../{stderr.ref1 => run.default.stderr.ref} | 0 .../{stdout.ref1 => run.default.stdout.ref} | 0 .../{stderr.ref3 => run.subcrate.stderr.ref} | 0 .../{stdout.ref3 => run.subcrate.stdout.ref} | 0 ...stdout.ref4 => test.bin-target.stdout.ref} | 0 ...st.stdout.ref1 => test.default.stdout.ref} | 0 ...est.stdout.ref2 => test.filter.stdout.ref} | 0 ...test.stderr.ref2 => test.stderr-empty.ref} | 0 ...st.stderr.ref1 => test.stderr-rustdoc.ref} | 0 ...t.stdout.ref5 => test.subcrate.stdout.ref} | 0 ...tdout.ref3 => test.test-target.stdout.ref} | 0 14 files changed, 10 insertions(+), 10 deletions(-) rename test-cargo-miri/{stderr.ref2 => run.args.stderr.ref} (100%) rename test-cargo-miri/{stdout.ref2 => run.args.stdout.ref} (100%) rename test-cargo-miri/{stderr.ref1 => run.default.stderr.ref} (100%) rename test-cargo-miri/{stdout.ref1 => run.default.stdout.ref} (100%) rename test-cargo-miri/{stderr.ref3 => run.subcrate.stderr.ref} (100%) rename test-cargo-miri/{stdout.ref3 => run.subcrate.stdout.ref} (100%) rename test-cargo-miri/{test.stdout.ref4 => test.bin-target.stdout.ref} (100%) rename test-cargo-miri/{test.stdout.ref1 => test.default.stdout.ref} (100%) rename test-cargo-miri/{test.stdout.ref2 => test.filter.stdout.ref} (100%) rename test-cargo-miri/{test.stderr.ref2 => test.stderr-empty.ref} (100%) rename test-cargo-miri/{test.stderr.ref1 => test.stderr-rustdoc.ref} (100%) rename test-cargo-miri/{test.stdout.ref5 => test.subcrate.stdout.ref} (100%) rename test-cargo-miri/{test.stdout.ref3 => test.test-target.stdout.ref} (100%) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index e7c341a1f040..636f4b3bf5f5 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -51,7 +51,7 @@ def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): def test_cargo_miri_run(): test("`cargo miri run` (no isolation)", cargo_miri("run"), - "stdout.ref1", "stderr.ref1", + "run.default.stdout.ref", "run.default.stderr.ref", stdin=b'12\n21\n', env={ 'MIRIFLAGS': "-Zmiri-disable-isolation", @@ -60,44 +60,44 @@ def test_cargo_miri_run(): ) test("`cargo miri run` (with arguments and target)", cargo_miri("run") + ["--bin", "cargo-miri-test", "--", "hello world", '"hello world"'], - "stdout.ref2", "stderr.ref2", + "run.args.stdout.ref", "run.args.stderr.ref", ) test("`cargo miri run` (subcrate, no ioslation)", cargo_miri("run") + ["-p", "subcrate"], - "stdout.ref3", "stderr.ref3", + "run.subcrate.stdout.ref", "run.subcrate.stderr.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) def test_cargo_miri_test(): # rustdoc is not run on foreign targets is_foreign = 'MIRI_TEST_TARGET' in os.environ - rustdoc_ref = "test.stderr.ref2" if is_foreign else "test.stderr.ref1" + rustdoc_ref = "test.stderr-empty.ref" if is_foreign else "test.stderr-rustdoc.ref" test("`cargo miri test`", cargo_miri("test"), - "test.stdout.ref1", rustdoc_ref, + "test.default.stdout.ref", rustdoc_ref, env={'MIRIFLAGS': "-Zmiri-seed=feed"}, ) test("`cargo miri test` (no isolation)", cargo_miri("test"), - "test.stdout.ref1", rustdoc_ref, + "test.default.stdout.ref", rustdoc_ref, env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) test("`cargo miri test` (with filter)", cargo_miri("test") + ["--", "--format=pretty", "le1"], - "test.stdout.ref2", rustdoc_ref, + "test.filter.stdout.ref", rustdoc_ref, ) test("`cargo miri test` (test target)", cargo_miri("test") + ["--test", "test", "--", "--format=pretty"], - "test.stdout.ref3", "test.stderr.ref2", + "test.test-target.stdout.ref", "test.stderr-empty.ref", ) test("`cargo miri test` (bin target)", cargo_miri("test") + ["--bin", "cargo-miri-test", "--", "--format=pretty"], - "test.stdout.ref4", "test.stderr.ref2", + "test.bin-target.stdout.ref", "test.stderr-empty.ref", ) test("`cargo miri test` (subcrate, no isolation)", cargo_miri("test") + ["-p", "subcrate"], - "test.stdout.ref5", "test.stderr.ref2", + "test.subcrate.stdout.ref", "test.stderr-empty.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) diff --git a/test-cargo-miri/stderr.ref2 b/test-cargo-miri/run.args.stderr.ref similarity index 100% rename from test-cargo-miri/stderr.ref2 rename to test-cargo-miri/run.args.stderr.ref diff --git a/test-cargo-miri/stdout.ref2 b/test-cargo-miri/run.args.stdout.ref similarity index 100% rename from test-cargo-miri/stdout.ref2 rename to test-cargo-miri/run.args.stdout.ref diff --git a/test-cargo-miri/stderr.ref1 b/test-cargo-miri/run.default.stderr.ref similarity index 100% rename from test-cargo-miri/stderr.ref1 rename to test-cargo-miri/run.default.stderr.ref diff --git a/test-cargo-miri/stdout.ref1 b/test-cargo-miri/run.default.stdout.ref similarity index 100% rename from test-cargo-miri/stdout.ref1 rename to test-cargo-miri/run.default.stdout.ref diff --git a/test-cargo-miri/stderr.ref3 b/test-cargo-miri/run.subcrate.stderr.ref similarity index 100% rename from test-cargo-miri/stderr.ref3 rename to test-cargo-miri/run.subcrate.stderr.ref diff --git a/test-cargo-miri/stdout.ref3 b/test-cargo-miri/run.subcrate.stdout.ref similarity index 100% rename from test-cargo-miri/stdout.ref3 rename to test-cargo-miri/run.subcrate.stdout.ref diff --git a/test-cargo-miri/test.stdout.ref4 b/test-cargo-miri/test.bin-target.stdout.ref similarity index 100% rename from test-cargo-miri/test.stdout.ref4 rename to test-cargo-miri/test.bin-target.stdout.ref diff --git a/test-cargo-miri/test.stdout.ref1 b/test-cargo-miri/test.default.stdout.ref similarity index 100% rename from test-cargo-miri/test.stdout.ref1 rename to test-cargo-miri/test.default.stdout.ref diff --git a/test-cargo-miri/test.stdout.ref2 b/test-cargo-miri/test.filter.stdout.ref similarity index 100% rename from test-cargo-miri/test.stdout.ref2 rename to test-cargo-miri/test.filter.stdout.ref diff --git a/test-cargo-miri/test.stderr.ref2 b/test-cargo-miri/test.stderr-empty.ref similarity index 100% rename from test-cargo-miri/test.stderr.ref2 rename to test-cargo-miri/test.stderr-empty.ref diff --git a/test-cargo-miri/test.stderr.ref1 b/test-cargo-miri/test.stderr-rustdoc.ref similarity index 100% rename from test-cargo-miri/test.stderr.ref1 rename to test-cargo-miri/test.stderr-rustdoc.ref diff --git a/test-cargo-miri/test.stdout.ref5 b/test-cargo-miri/test.subcrate.stdout.ref similarity index 100% rename from test-cargo-miri/test.stdout.ref5 rename to test-cargo-miri/test.subcrate.stdout.ref diff --git a/test-cargo-miri/test.stdout.ref3 b/test-cargo-miri/test.test-target.stdout.ref similarity index 100% rename from test-cargo-miri/test.stdout.ref3 rename to test-cargo-miri/test.test-target.stdout.ref From 3d151c8b62dbb9b4234387fcd6e4a6eb87a07ef0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Dec 2020 11:33:46 +0100 Subject: [PATCH 2489/5092] leak checker: also test AtomicPtr stored via 'swap' --- tests/run-pass/leak-in-static.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/run-pass/leak-in-static.rs b/tests/run-pass/leak-in-static.rs index 2914b1149c06..a20577125e73 100644 --- a/tests/run-pass/leak-in-static.rs +++ b/tests/run-pass/leak-in-static.rs @@ -12,5 +12,9 @@ fn main() { { static LEAK: AtomicPtr = AtomicPtr::new(ptr::null_mut()); LEAK.store(Box::into_raw(Box::new(0usize)), Ordering::SeqCst); + + static LEAK2: AtomicPtr = AtomicPtr::new(ptr::null_mut()); + // Make sure this also works when using 'swap'. + LEAK2.swap(Box::into_raw(Box::new(0usize)), Ordering::SeqCst); } } From 6dc353c0915c8d85218e984d1064a52c0711d2e2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Dec 2020 11:34:27 +0100 Subject: [PATCH 2490/5092] test test suite harness with raw-ptr tracking --- test-cargo-miri/run-test.py | 5 +++++ test-cargo-miri/test.raw-ptr-track.stdout.ref | 10 ++++++++++ 2 files changed, 15 insertions(+) create mode 100644 test-cargo-miri/test.raw-ptr-track.stdout.ref diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 636f4b3bf5f5..8eeafc4ed674 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -83,6 +83,11 @@ def test_cargo_miri_test(): "test.default.stdout.ref", rustdoc_ref, env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) + test("`cargo miri test` (raw-ptr tracking)", + cargo_miri("test") + ["--", "-Zunstable-options", "--exclude-should-panic"], + "test.raw-ptr-track.stdout.ref", rustdoc_ref, + env={'MIRIFLAGS': "-Zmiri-track-raw-pointers"}, + ) test("`cargo miri test` (with filter)", cargo_miri("test") + ["--", "--format=pretty", "le1"], "test.filter.stdout.ref", rustdoc_ref, diff --git a/test-cargo-miri/test.raw-ptr-track.stdout.ref b/test-cargo-miri/test.raw-ptr-track.stdout.ref new file mode 100644 index 000000000000..c9678beac8f4 --- /dev/null +++ b/test-cargo-miri/test.raw-ptr-track.stdout.ref @@ -0,0 +1,10 @@ + +running 1 test +. +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out + + +running 5 tests +.i... +test result: ok. 4 passed; 0 failed; 1 ignored; 0 measured; 2 filtered out + From e204c0fbaba21ba3771cdbfbbbd2aab9abfc4864 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Dec 2020 14:39:18 +0100 Subject: [PATCH 2491/5092] link to our shiny new Zulip stream --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 38663b408a3d..fdf45951c6f2 100644 --- a/README.md +++ b/README.md @@ -350,9 +350,9 @@ If you want to contribute to Miri, great! Please check out our [contribution guide](CONTRIBUTING.md). For help with running Miri, you can open an issue here on -GitHub or contact us (`oli-obk` and `RalfJ`) on the [Rust Zulip]. +GitHub or use the [Miri stream on the Rust Zulip][zulip]. -[Rust Zulip]: https://rust-lang.zulipchat.com +[zulip]: https://rust-lang.zulipchat.com/#narrow/stream/269128-miri ## History From 65f5c27d61a401f7429a1b3b52026118e1050def Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 22 Dec 2020 12:47:59 +0100 Subject: [PATCH 2492/5092] remove intrinsic that is now implemented in the rustc side --- src/shims/intrinsics.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 956f3b5bde4f..47a642564e45 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -443,11 +443,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.exact_div(this.read_immediate(num)?, this.read_immediate(denom)?, dest)?; } - "forget" => { - // We get an argument... and forget about it. - let &[_] = check_arg_count(args)?; - } - "try" => return this.handle_try(args, dest, ret), name => throw_unsup_format!("unimplemented intrinsic: {}", name), From a81ebd8fe3f60ef93dfbe85e30c9a7d005befd69 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 29 Dec 2020 19:27:23 +0100 Subject: [PATCH 2493/5092] rustup; add an interesting alias test case --- rust-version | 2 +- tests/compile-fail/box-cell-alias.rs | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/box-cell-alias.rs diff --git a/rust-version b/rust-version index ec1eb6932417..e261b13e8183 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -15d1f811963649c2f18a88c8e0b39958ec02fd70 +158f8d034b15e65ba8dc0d066358dd0632bfcd6e diff --git a/tests/compile-fail/box-cell-alias.rs b/tests/compile-fail/box-cell-alias.rs new file mode 100644 index 000000000000..5d63fc1d44a5 --- /dev/null +++ b/tests/compile-fail/box-cell-alias.rs @@ -0,0 +1,18 @@ +// compile-flags: -Zmiri-track-raw-pointers + +// Taken from . + +use std::cell::Cell; + +fn helper(val: Box>, ptr: *const Cell) -> u8 { + val.set(10); + unsafe { (*ptr).set(20); } //~ ERROR does not have an appropriate item in the borrow stack + val.get() +} + +fn main() { + let val: Box> = Box::new(Cell::new(25)); + let ptr: *const Cell = &*val; + let res = helper(val, ptr); + assert_eq!(res, 20); +} From 7e198147df98fa09b09bb1f878a4989754915106 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 31 Dec 2020 00:17:08 +0100 Subject: [PATCH 2494/5092] panicing now works with -Zmiri-track-raw-pointers --- rust-version | 2 +- test-cargo-miri/run-test.py | 4 ++-- test-cargo-miri/test.raw-ptr-track.stdout.ref | 10 ---------- tests/run-pass/dyn-lcsit.rs | 2 +- tests/run-pass/intrinsics.rs | 2 +- 5 files changed, 5 insertions(+), 15 deletions(-) delete mode 100644 test-cargo-miri/test.raw-ptr-track.stdout.ref diff --git a/rust-version b/rust-version index e261b13e8183..9d755c730934 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -158f8d034b15e65ba8dc0d066358dd0632bfcd6e +507bff92fadf1f25a830da5065a5a87113345163 diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 8eeafc4ed674..60924d4f8ddc 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -84,8 +84,8 @@ def test_cargo_miri_test(): env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) test("`cargo miri test` (raw-ptr tracking)", - cargo_miri("test") + ["--", "-Zunstable-options", "--exclude-should-panic"], - "test.raw-ptr-track.stdout.ref", rustdoc_ref, + cargo_miri("test"), + "test.default.stdout.ref", rustdoc_ref, env={'MIRIFLAGS': "-Zmiri-track-raw-pointers"}, ) test("`cargo miri test` (with filter)", diff --git a/test-cargo-miri/test.raw-ptr-track.stdout.ref b/test-cargo-miri/test.raw-ptr-track.stdout.ref deleted file mode 100644 index c9678beac8f4..000000000000 --- a/test-cargo-miri/test.raw-ptr-track.stdout.ref +++ /dev/null @@ -1,10 +0,0 @@ - -running 1 test -. -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out - - -running 5 tests -.i... -test result: ok. 4 passed; 0 failed; 1 ignored; 0 measured; 2 filtered out - diff --git a/tests/run-pass/dyn-lcsit.rs b/tests/run-pass/dyn-lcsit.rs index fa11e9a2a318..e7a5f13923a8 100644 --- a/tests/run-pass/dyn-lcsit.rs +++ b/tests/run-pass/dyn-lcsit.rs @@ -32,7 +32,7 @@ const cdef_et3: &dyn Tr1>>> impl Tr1 for A { type As1 = core::ops::Range; fn mk(&self) -> Self::As1 { 0..10 } - }; + } &A }; pub fn use_et3() { diff --git a/tests/run-pass/intrinsics.rs b/tests/run-pass/intrinsics.rs index 8f7dbac67064..00c966b049c4 100644 --- a/tests/run-pass/intrinsics.rs +++ b/tests/run-pass/intrinsics.rs @@ -24,7 +24,7 @@ fn main() { assert_eq!(intrinsics::likely(false), false); assert_eq!(intrinsics::unlikely(true), true); - unsafe { intrinsics::forget(Bomb); } + intrinsics::forget(Bomb); let _v = intrinsics::discriminant_value(&Some(())); let _v = intrinsics::discriminant_value(&0); From 82c6c77b9a1288ecc955282c9e0de19b96db5203 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 31 Dec 2020 13:11:34 +0100 Subject: [PATCH 2495/5092] test Weak into_raw/from_raw on dangling ptrs --- rust-version | 2 +- tests/run-pass/intrinsics.rs | 6 +++++- tests/run-pass/rc.rs | 8 +++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 9d755c730934..1cdca76aa6cb 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -507bff92fadf1f25a830da5065a5a87113345163 +8b002d5c3489a21db2c16e5af63cf5d234f6972c diff --git a/tests/run-pass/intrinsics.rs b/tests/run-pass/intrinsics.rs index 00c966b049c4..6885641c02ea 100644 --- a/tests/run-pass/intrinsics.rs +++ b/tests/run-pass/intrinsics.rs @@ -1,7 +1,8 @@ #![feature(core_intrinsics, const_raw_ptr_comparison)] +#![feature(layout_for_ptr)] use std::intrinsics; -use std::mem::{size_of, size_of_val}; +use std::mem::{size_of, size_of_val, size_of_val_raw}; struct Bomb; @@ -19,6 +20,9 @@ fn main() { assert_eq!(size_of_val(&[1, 2, 3] as &[i32]), 12); assert_eq!(size_of_val("foobar"), 6); + unsafe { assert_eq!(size_of_val_raw(&[1] as &[i32] as *const [i32]), 4); } + unsafe { assert_eq!(size_of_val_raw(0x100 as *const i32), 4); } + assert_eq!(intrinsics::type_name::>(), "core::option::Option"); assert_eq!(intrinsics::likely(false), false); diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index 69bd1f8d9ae2..91de20ae2b7f 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -4,7 +4,7 @@ use std::cell::{Cell, RefCell}; use std::rc::{Rc, Weak}; -use std::sync::Arc; +use std::sync::{Arc, Weak as ArcWeak}; use std::fmt::Debug; fn rc_refcell() { @@ -48,6 +48,9 @@ fn arc() { a } assert_eq!(*test(), 42); + + let raw = ArcWeak::into_raw(ArcWeak::::new()); + drop(unsafe { ArcWeak::from_raw(raw) }); } // Make sure this Rc doesn't fall apart when touched @@ -84,6 +87,9 @@ fn weak_into_raw() { drop(unsafe { Weak::from_raw(raw) }); assert_eq!(0, Rc::weak_count(&strong)); + + let raw = Weak::into_raw(Weak::::new()); + drop(unsafe { Weak::from_raw(raw) }); } /// Taken from the `Weak::from_raw` doctest. From 333d7bb2c5f197c21922e5505384ee0c24f7c931 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 Jan 2021 19:12:11 +0100 Subject: [PATCH 2496/5092] send Zulip notification when cron job fails --- .github/workflows/ci.yml | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b5ef3d861ead..fd6258693af6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -61,15 +61,17 @@ jobs: restore-keys: ${{ runner.os }}-cargo - name: Install rustup-toolchain-install-master and xargo + shell: bash run: | cargo install rustup-toolchain-install-master cargo install xargo - shell: bash - name: Install "master" toolchain + shell: bash run: | if [[ ${{ github.event_name }} == 'schedule' ]]; then RUSTC_HASH=$(git ls-remote https://github.com/rust-lang/rust.git master | awk '{print $1}') + exit 1 # just to test cron notifications else RUSTC_HASH=$(< rust-version) fi @@ -81,7 +83,6 @@ jobs: -c llvm-tools \ --host ${{ matrix.host_target }} rustup default master - shell: bash - name: Show Rust version run: | @@ -113,3 +114,22 @@ jobs: steps: - name: mark the job as a failure run: exit 1 + + # Send a Zulip notification when a cron job fails + cron-fail-notify: + name: cronjob failure notification + runs-on: ubuntu-latest + needs: [build] + if: github.event_name == 'schedule' && (failure() || cancelled()) + steps: + - name: Install zulip-send + run: pip3 install zulip + - name: Send Zulip notification + shell: bash + env: + ZULIP_BOT_EMAIL: ${{ secrets.ZULIP_BOT_EMAIL }} + ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }} + run: | + zulip-send --stream miri --subject "Cron Job Failure" \ + --message '@**RalfJ** @**oli** the Miri cron job build failed. Please investigate!' \ + --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN From 6c112e045956a3c3758cf2225cf0ec0a3a922944 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 11 Jan 2021 12:09:55 +0100 Subject: [PATCH 2497/5092] fix zulip-send path --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fd6258693af6..ba26a7772d17 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -130,6 +130,6 @@ jobs: ZULIP_BOT_EMAIL: ${{ secrets.ZULIP_BOT_EMAIL }} ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }} run: | - zulip-send --stream miri --subject "Cron Job Failure" \ + ~/.local/bin/zulip-send --stream miri --subject "Cron Job Failure" \ --message '@**RalfJ** @**oli** the Miri cron job build failed. Please investigate!' \ --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN From 8e15f3221e98b1bb96e4e8df080c15b4b7424ade Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 11 Jan 2021 12:35:13 +0100 Subject: [PATCH 2498/5092] rustup --- rust-version | 2 +- src/machine.rs | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 1cdca76aa6cb..3c44be9d9a76 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8b002d5c3489a21db2c16e5af63cf5d234f6972c +a2cd91ceb0f156cb442d75e12dc77c3d064cdde4 diff --git a/src/machine.rs b/src/machine.rs index e639bf450ada..d28aa34c75e8 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -24,6 +24,7 @@ use rustc_middle::{ use rustc_span::symbol::{sym, Symbol}; use rustc_span::def_id::DefId; use rustc_target::abi::{LayoutOf, Size}; +use rustc_target::spec::abi::Abi; use crate::*; @@ -352,6 +353,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn find_mir_or_eval_fn( ecx: &mut InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, + _abi: Abi, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, @@ -363,6 +365,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn call_extra_fn( ecx: &mut InterpCx<'mir, 'tcx, Self>, fn_val: Dlsym, + _abi: Abi, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, _unwind: Option, From d6b5ead0bae68b5c72a9db657f299aa304e30dc4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 15 Jan 2021 15:23:20 +0100 Subject: [PATCH 2499/5092] add Zulip site information --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ba26a7772d17..2119d245b9c8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -132,4 +132,4 @@ jobs: run: | ~/.local/bin/zulip-send --stream miri --subject "Cron Job Failure" \ --message '@**RalfJ** @**oli** the Miri cron job build failed. Please investigate!' \ - --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN + --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com From 4a035103dc4afe952bc89bec3aa2f78d50027778 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 15 Jan 2021 16:41:14 +0100 Subject: [PATCH 2500/5092] rustup; make tests pass again --- rust-version | 2 +- src/data_race.rs | 3 +-- tests/run-pass/concurrency/sync_singlethread.rs | 1 + 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 3c44be9d9a76..0ff7406c5613 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a2cd91ceb0f156cb442d75e12dc77c3d064cdde4 +4e208f6a3afb42528878b0f3464e337c4bf3bbc8 diff --git a/src/data_race.rs b/src/data_race.rs index 44cce5395777..d204d60f1565 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -824,8 +824,7 @@ impl VClockAlloc { // Throw the data-race detection. throw_ub_format!( "Data race detected between {} on {} and {} on {}, memory({:?},offset={},size={})\ - \n\t\t -current vector clock = {:?}\ - \n\t\t -conflicting timestamp = {:?}", + \n(current vector clock = {:?}, conflicting timestamp = {:?})", action, current_thread_info, other_action, diff --git a/tests/run-pass/concurrency/sync_singlethread.rs b/tests/run-pass/concurrency/sync_singlethread.rs index ab0203906d36..2474fe6633c3 100644 --- a/tests/run-pass/concurrency/sync_singlethread.rs +++ b/tests/run-pass/concurrency/sync_singlethread.rs @@ -50,6 +50,7 @@ impl TryLockErrorExt for TryLockError { } fn test_spin_loop_hint() { + #[allow(deprecated)] atomic::spin_loop_hint(); hint::spin_loop(); } From 0b9ee1624899758fc4575cecfa60bb32d36138c6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 16 Jan 2021 10:29:37 +0100 Subject: [PATCH 2501/5092] undo cronjob deliberate failure --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2119d245b9c8..818e3a9038f7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -71,7 +71,6 @@ jobs: run: | if [[ ${{ github.event_name }} == 'schedule' ]]; then RUSTC_HASH=$(git ls-remote https://github.com/rust-lang/rust.git master | awk '{print $1}') - exit 1 # just to test cron notifications else RUSTC_HASH=$(< rust-version) fi From 7125b86c338a623bbaff5d4e86c73f19e4653c0a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 16 Jan 2021 18:27:10 +0100 Subject: [PATCH 2502/5092] remove some unnecessary feature gates --- tests/compile-fail/check_arg_count_too_few_args.rs | 2 -- tests/compile-fail/check_arg_count_too_many_args.rs | 2 -- 2 files changed, 4 deletions(-) diff --git a/tests/compile-fail/check_arg_count_too_few_args.rs b/tests/compile-fail/check_arg_count_too_few_args.rs index f8d11832683b..e1cea99eb90b 100644 --- a/tests/compile-fail/check_arg_count_too_few_args.rs +++ b/tests/compile-fail/check_arg_count_too_few_args.rs @@ -1,5 +1,3 @@ -#![feature(core_intrinsics)] - fn main() { extern "C" { fn malloc() -> *mut std::ffi::c_void; diff --git a/tests/compile-fail/check_arg_count_too_many_args.rs b/tests/compile-fail/check_arg_count_too_many_args.rs index 5163d223fa42..c4028b940ff0 100644 --- a/tests/compile-fail/check_arg_count_too_many_args.rs +++ b/tests/compile-fail/check_arg_count_too_many_args.rs @@ -1,5 +1,3 @@ -#![feature(core_intrinsics)] - fn main() { extern "C" { fn malloc(_: i32, _: i32) -> *mut std::ffi::c_void; From 9949d9e417ff563c3cf7fbadb3ae6d865ab08c53 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 17 Jan 2021 23:09:04 +0800 Subject: [PATCH 2503/5092] Remove `#![feature(const_generics)]` and `#![allow(incomplete_features)]` --- src/lib.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 581da0976e51..aadbb0270de4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,9 +8,6 @@ #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] -#![allow(incomplete_features)] -#![feature(const_generics)] - extern crate rustc_attr; extern crate rustc_apfloat; extern crate rustc_ast; From a4a643e7cbd364e72b27f580750da61dbd607047 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sun, 17 Jan 2021 21:26:24 +0100 Subject: [PATCH 2504/5092] Teach the miri cronjobs to speak politely --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 818e3a9038f7..43a964280d5a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -130,5 +130,5 @@ jobs: ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }} run: | ~/.local/bin/zulip-send --stream miri --subject "Cron Job Failure" \ - --message '@**RalfJ** @**oli** the Miri cron job build failed. Please investigate!' \ + --message 'Dear @**RalfJ** and @**oli**\n\nIt would appear that the Miri cron job build failed. Would you mind investigating this issue?\n\nThanks in advance!\nSincerely,\nThe Miri Cronjobs Bot' \ --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com From 3d01ba11c0741a76a562c4b49246deea090d7c03 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Jan 2021 12:55:30 +0100 Subject: [PATCH 2505/5092] rustup; remove some intrinsics that are gone or moved to rustc --- rust-version | 2 +- src/shims/intrinsics.rs | 33 --------------------------------- 2 files changed, 1 insertion(+), 34 deletions(-) diff --git a/rust-version b/rust-version index 0ff7406c5613..6da6e700194d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4e208f6a3afb42528878b0f3464e337c4bf3bbc8 +0677d9729318441a1cdb0c74812ec4140fa4d35f diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 47a642564e45..840dd9f14336 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -51,39 +51,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Raw memory accesses - #[rustfmt::skip] - | "copy" - | "copy_nonoverlapping" - => { - let &[src, dest, count] = check_arg_count(args)?; - let elem_ty = instance.substs.type_at(0); - let elem_layout = this.layout_of(elem_ty)?; - let count = this.read_scalar(count)?.to_machine_usize(this)?; - let elem_align = elem_layout.align.abi; - - let size = elem_layout.size.checked_mul(count, this) - .ok_or_else(|| err_ub_format!("overflow computing total size of `{}`", intrinsic_name))?; - let src = this.read_scalar(src)?.check_init()?; - let src = this.memory.check_ptr_access(src, size, elem_align)?; - let dest = this.read_scalar(dest)?.check_init()?; - let dest = this.memory.check_ptr_access(dest, size, elem_align)?; - - if let (Some(src), Some(dest)) = (src, dest) { - this.memory.copy( - src, - dest, - size, - intrinsic_name.ends_with("_nonoverlapping"), - )?; - } - } - - "move_val_init" => { - let &[place, dest] = check_arg_count(args)?; - let place = this.deref_operand(place)?; - this.copy_op(dest, place.into())?; - } - "volatile_load" => { let &[place] = check_arg_count(args)?; let place = this.deref_operand(place)?; From eae95693d8ae5416cc24153a4055661116100467 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Mon, 18 Jan 2021 18:17:25 +0800 Subject: [PATCH 2506/5092] Add `ArgFlagValueIter` --- cargo-miri/bin.rs | 61 +++++++++++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index d18e9608cf50..c312a581621a 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -2,6 +2,7 @@ use std::env; use std::ffi::OsString; use std::fs::{self, File}; use std::io::{self, BufRead, BufReader, BufWriter, Write}; +use std::iter::TakeWhile; use std::ops::Not; use std::path::{Path, PathBuf}; use std::process::Command; @@ -89,31 +90,49 @@ fn has_arg_flag(name: &str) -> bool { args.any(|val| val == name) } -/// Gets the value of a `--flag`. -fn get_arg_flag_value(name: &str) -> Option { - // Stop searching at `--`. - let mut args = std::env::args().take_while(|val| val != "--"); - loop { - let arg = match args.next() { - Some(arg) => arg, - None => return None, - }; - if !arg.starts_with(name) { - continue; - } - // Strip leading `name`. - let suffix = &arg[name.len()..]; - if suffix.is_empty() { - // This argument is exactly `name`; the next one is the value. - return args.next(); - } else if suffix.starts_with('=') { - // This argument is `name=value`; get the value. - // Strip leading `=`. - return Some(suffix[1..].to_owned()); +struct ArgFlagValueIter<'a> { + args: TakeWhile bool>, + name: &'a str, +} + +impl<'a> ArgFlagValueIter<'a> { + fn new(name: &'a str) -> Self { + Self { + // Stop searching at `--`. + args: env::args().take_while(|val| val != "--"), + name, } } } +impl Iterator for ArgFlagValueIter<'_> { + type Item = String; + + fn next(&mut self) -> Option { + loop { + let arg = self.args.next()?; + if !arg.starts_with(self.name) { + continue; + } + // Strip leading `name`. + let suffix = &arg[self.name.len()..]; + if suffix.is_empty() { + // This argument is exactly `name`; the next one is the value. + return self.args.next(); + } else if suffix.starts_with('=') { + // This argument is `name=value`; get the value. + // Strip leading `=`. + return Some(suffix[1..].to_owned()); + } + } + } +} + +/// Gets the value of a `--flag`. +fn get_arg_flag_value(name: &str) -> Option { + ArgFlagValueIter::new(name).next() +} + /// Returns the path to the `miri` binary fn find_miri() -> PathBuf { if let Some(path) = env::var_os("MIRI") { From 3990debf824925230abca279661d7630fd859409 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 22 Jan 2021 09:22:53 +0100 Subject: [PATCH 2507/5092] rustup; test swap of element with itself --- rust-version | 2 +- tests/run-pass/vec.rs | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 6da6e700194d..25ee0983ab43 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0677d9729318441a1cdb0c74812ec4140fa4d35f +dc1eee2f256efbd1d3b50b6b090232f81cac6d72 diff --git a/tests/run-pass/vec.rs b/tests/run-pass/vec.rs index 8d83f6380b8f..5676f9b676bf 100644 --- a/tests/run-pass/vec.rs +++ b/tests/run-pass/vec.rs @@ -135,6 +135,11 @@ fn sort() { v.sort(); } +fn swap() { + let mut v = vec![1, 2, 3, 4]; + v.swap(2, 2); +} + fn main() { assert_eq!(vec_reallocate().len(), 5); @@ -161,4 +166,5 @@ fn main() { push_str_ptr_stable(); sort(); + swap(); } From 2aedbf0993737939fdff3eb9ded7c8630144f1bc Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 22 Jan 2021 09:16:27 -0500 Subject: [PATCH 2508/5092] Add shim for libc::sysconf(libc::_SC_NPROCESSORS_CONF) --- src/shims/posix/foreign_items.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index aac164b709b2..f92242f56d9e 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -180,6 +180,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let sysconfs = &[ ("_SC_PAGESIZE", Scalar::from_int(PAGE_SIZE, this.pointer_size())), + ("_SC_NPROCESSORS_CONF", Scalar::from_int(NUM_CPUS, this.pointer_size())), ("_SC_NPROCESSORS_ONLN", Scalar::from_int(NUM_CPUS, this.pointer_size())), ]; let mut result = None; From 225e255cfe6995ef241c67dd3eb2264f9b62cbbc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jan 2021 16:51:29 +0100 Subject: [PATCH 2509/5092] prefer build-time env vars over run-time values --- cargo-miri/bin.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index d18e9608cf50..b413a0b222e5 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -655,16 +655,21 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { let info: CrateRunInfo = serde_json::from_reader(file) .unwrap_or_else(|_| show_error(format!("file {:?} contains outdated or invalid JSON; try `cargo clean`", binary))); - // Set missing env vars. Looks like `build.rs` vars are still set at run-time, but - // `CARGO_BIN_EXE_*` are not. This means we can give the run-time environment precedence, - // to rather do too little than too much. + let mut cmd = miri(); + + // Set missing env vars. We prefer build-time env vars over run-time ones; see + // for the kind of issue that fixes. for (name, val) in info.env { - if env::var_os(&name).is_none() { - env::set_var(name, val); + if verbose { + if let Some(old_val) = env::var_os(&name) { + if old_val != val { + eprintln!("[cargo-miri runner] Overwriting run-time env var {:?}={:?} with build-time value {:?}", name, old_val, val); + } + } } + cmd.env(name, val); } - let mut cmd = miri(); // Forward rustc arguments. // We need to patch "--extern" filenames because we forced a check-only // build without cargo knowing about that: replace `.rlib` suffix by From 36ce77699743802bd4ebb2f783df15f25e412e0b Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 23 Jan 2021 10:51:36 -0500 Subject: [PATCH 2510/5092] Test aarch64-apple-darwin --- ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index 17bc8df83e18..a1f4a0013946 100755 --- a/ci.sh +++ b/ci.sh @@ -47,7 +47,7 @@ run_tests case $HOST_TARGET in x86_64-unknown-linux-gnu) MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests - MIRI_TEST_TARGET=x86_64-apple-darwin run_tests + MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests ;; x86_64-apple-darwin) From 4a13f24839b2e0fdbf356530d5569a8e322c39d7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jan 2021 16:54:00 +0100 Subject: [PATCH 2511/5092] expand README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index fdf45951c6f2..f4a762937ecd 100644 --- a/README.md +++ b/README.md @@ -286,6 +286,8 @@ different Miri binaries, and as such worth documenting: directory after loading all the source files, but before commencing interpretation. This is useful if the interpreted program wants a different working directory at run-time than at build-time. +* `MIRI_VERBOSE` when set to any value tells the various `cargo-miri` phases to + perform verbose logging. [testing-miri]: CONTRIBUTING.md#testing-the-miri-driver From 848be1bf824dfbdaa99c016019ef3d60234590ed Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jan 2021 18:11:01 +0100 Subject: [PATCH 2512/5092] implement aarch64 hint 'intrinsic' --- src/shims/foreign_items.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index d588e2962a15..237fb27d9222 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -484,6 +484,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[] = check_arg_count(args)?; this.yield_active_thread(); } + "llvm.aarch64.hint" if this.tcx.sess.target.arch == "aarch64" => { + let &[hint] = check_arg_count(args)?; + let hint = this.read_scalar(hint)?.to_i32()?; + match hint { + 1 => { // HINT_YIELD + this.yield_active_thread(); + } + _ => { + throw_unsup_format!("unsupported llvm.aarch64.hint argument {}", hint); + } + } + } // Platform-specific shims _ => match this.tcx.sess.target.os.as_str() { From 7d8f8c405ff069a5e8e3347b8af8e73b8224a911 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jan 2021 18:14:57 +0100 Subject: [PATCH 2513/5092] macos: support aarch64 link names --- src/shims/posix/macos/foreign_items.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index 72ec7a5d9702..a4b0ce524df2 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -25,32 +25,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // File related shims - "close$NOCANCEL" => { + "close" | "close$NOCANCEL" => { let &[result] = check_arg_count(args)?; let result = this.close(result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "stat$INODE64" => { + "stat" | "stat$INODE64" => { let &[path, buf] = check_arg_count(args)?; let result = this.macos_stat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "lstat$INODE64" => { + "lstat" | "lstat$INODE64" => { let &[path, buf] = check_arg_count(args)?; let result = this.macos_lstat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "fstat$INODE64" => { + "fstat" | "fstat$INODE64" => { let &[fd, buf] = check_arg_count(args)?; let result = this.macos_fstat(fd, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "opendir$INODE64" => { + "opendir" | "opendir$INODE64" => { let &[name] = check_arg_count(args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } - "readdir_r$INODE64" => { + "readdir_r" | "readdir_r$INODE64" => { let &[dirp, entry, result] = check_arg_count(args)?; let result = this.macos_readdir_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; From 056016571fbcbe3f1f8d14f2595aa941108328d8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 Jan 2021 15:58:37 +0100 Subject: [PATCH 2514/5092] add -Zmiri-disable-data-race-detector to readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index f4a762937ecd..b2f0babfc9bc 100644 --- a/README.md +++ b/README.md @@ -198,6 +198,8 @@ environment variable: * `-Zmiri-disable-alignment-check` disables checking pointer alignment, so you can focus on other failures, but it means Miri can miss bugs in your program. Using this flag is **unsound**. +* `-Zmiri-disable-data-race-detector` disables checking for data races. Using + this flag is **unsound**. * `-Zmiri-disable-stacked-borrows` disables checking the experimental [Stacked Borrows] aliasing rules. This can make Miri run faster, but it also means no aliasing violations will be detected. Using this flag is **unsound** From ecab8a4fae3668f9f06e1524345732f194573e9d Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Mon, 18 Jan 2021 23:50:10 +0800 Subject: [PATCH 2515/5092] Skip unit tests of `proc-macro` crates --- cargo-miri/bin.rs | 84 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 62 insertions(+), 22 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index c312a581621a..b968b9df5918 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -37,9 +37,9 @@ enum MiriCommand { Setup, } -/// The inforamtion Miri needs to run a crate. Stored as JSON when the crate is "compiled". +/// The information to run a crate with the given environment. #[derive(Serialize, Deserialize)] -struct CrateRunInfo { +struct CrateRunEnv { /// The command-line arguments. args: Vec, /// The environment. @@ -48,13 +48,22 @@ struct CrateRunInfo { current_dir: OsString, } +/// The information Miri needs to run a crate. Stored as JSON when the crate is "compiled". +#[derive(Serialize, Deserialize)] +enum CrateRunInfo { + /// Run it with the given environment. + RunWith(CrateRunEnv), + /// Skip it as Miri does not support interpreting such kind of crates. + SkipProcMacroTest, +} + impl CrateRunInfo { /// Gather all the information we need. fn collect(args: env::Args) -> Self { let args = args.collect(); let env = env::vars_os().collect(); let current_dir = env::current_dir().unwrap().into_os_string(); - CrateRunInfo { args, env, current_dir } + Self::RunWith(CrateRunEnv { args, env, current_dir }) } fn store(&self, filename: &Path) { @@ -90,6 +99,7 @@ fn has_arg_flag(name: &str) -> bool { args.any(|val| val == name) } +/// Yields all values of command line flag `name`. struct ArgFlagValueIter<'a> { args: TakeWhile bool>, name: &'a str, @@ -455,14 +465,15 @@ fn phase_cargo_miri(mut args: env::Args) { // This is needed to make the `CARGO_TARGET_*_RUNNER` env var do something, // and it later helps us detect which crates are proc-macro/build-script // (host crates) and which crates are needed for the program itself. - let target = if let Some(target) = get_arg_flag_value("--target") { + let host = version_info().host; + let target = get_arg_flag_value("--target"); + let target = if let Some(ref target) = target { target } else { // No target given. Pick default and tell cargo about it. - let host = version_info().host; cmd.arg("--target"); cmd.arg(&host); - host + &host }; // Forward all further arguments. We do some processing here because we want to @@ -514,9 +525,16 @@ fn phase_cargo_miri(mut args: env::Args) { } cmd.env("RUSTC_WRAPPER", &cargo_miri_path); - // Set the runner for the current target to us as well, so we can interpret the binaries. - let runner_env_name = format!("CARGO_TARGET_{}_RUNNER", target.to_uppercase().replace('-', "_")); - cmd.env(&runner_env_name, &cargo_miri_path); + let runner_env_name = |triple: &str| { + format!("CARGO_TARGET_{}_RUNNER", triple.to_uppercase().replace('-', "_")) + }; + let host_runner_env_name = runner_env_name(&host); + let target_runner_env_name = runner_env_name(target); + // Set the target runner to us, so we can interpret the binaries. + cmd.env(&target_runner_env_name, &cargo_miri_path); + // Unit tests of `proc-macro` crates are run on the host, so we set the host runner to + // us in order to skip them. + cmd.env(&host_runner_env_name, &cargo_miri_path); // Set rustdoc to us as well, so we can make it do nothing (see issue #584). cmd.env("RUSTDOC", &cargo_miri_path); @@ -524,7 +542,10 @@ fn phase_cargo_miri(mut args: env::Args) { // Run cargo. if verbose { eprintln!("[cargo-miri miri] RUSTC_WRAPPER={:?}", cargo_miri_path); - eprintln!("[cargo-miri miri] {}={:?}", runner_env_name, cargo_miri_path); + eprintln!("[cargo-miri miri] {}={:?}", target_runner_env_name, cargo_miri_path); + if *target != host { + eprintln!("[cargo-miri miri] {}={:?}", host_runner_env_name, cargo_miri_path); + } eprintln!("[cargo-miri miri] RUSTDOC={:?}", cargo_miri_path); eprintln!("[cargo-miri miri] {:?}", cmd); cmd.env("MIRI_VERBOSE", ""); // This makes the other phases verbose. @@ -587,23 +608,34 @@ fn phase_cargo_rustc(args: env::Args) { _ => {}, } - if !print && target_crate && is_runnable_crate() { + let store_json = |info: CrateRunInfo| { + let filename = out_filename("", ""); + if verbose { + eprintln!("[cargo-miri rustc] writing run info to `{}`", filename.display()); + } + info.store(&filename); + // For Windows, do the same thing again with `.exe` appended to the filename. + // (Need to do this here as cargo moves that "binary" to a different place before running it.) + info.store(&out_filename("", ".exe")); + }; + + let runnable_crate = !print && is_runnable_crate(); + + if runnable_crate && target_crate { // This is the binary or test crate that we want to interpret under Miri. // But we cannot run it here, as cargo invoked us as a compiler -- our stdin and stdout are not // like we want them. // Instead of compiling, we write JSON into the output file with all the relevant command-line flags // and environment variables; this is used when cargo calls us again in the CARGO_TARGET_RUNNER phase. - let info = CrateRunInfo::collect(args); - let filename = out_filename("", ""); - if verbose { - eprintln!("[cargo-miri rustc] writing run info to `{}`", filename.display()); - } - - info.store(&filename); - // For Windows, do the same thing again with `.exe` appended to the filename. - // (Need to do this here as cargo moves that "binary" to a different place before running it.) - info.store(&out_filename("", ".exe")); + store_json(CrateRunInfo::collect(args)); + return; + } + if runnable_crate && ArgFlagValueIter::new("--extern").any(|krate| krate == "proc_macro") { + // This is a "runnable" `proc-macro` crate (unit tests). We do not support + // interpreting that under Miri now, so we write a JSON file to (display a + // helpful message and) skip it in the runner phase. + store_json(CrateRunInfo::SkipProcMacroTest); return; } @@ -671,8 +703,16 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { let file = File::open(&binary) .unwrap_or_else(|_| show_error(format!("file {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary))); let file = BufReader::new(file); - let info: CrateRunInfo = serde_json::from_reader(file) + + let info = serde_json::from_reader(file) .unwrap_or_else(|_| show_error(format!("file {:?} contains outdated or invalid JSON; try `cargo clean`", binary))); + let info = match info { + CrateRunInfo::RunWith(info) => info, + CrateRunInfo::SkipProcMacroTest => { + eprintln!("Running unit tests of `proc-macro` crates is not currently supported by Miri."); + return; + } + }; // Set missing env vars. Looks like `build.rs` vars are still set at run-time, but // `CARGO_BIN_EXE_*` are not. This means we can give the run-time environment precedence, From 28577924e7de574ae41f7bd99591da280cb57a15 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Tue, 19 Jan 2021 00:26:15 +0800 Subject: [PATCH 2516/5092] Add a test for unit test of `proc-macro` crate --- test-cargo-miri/run-test.py | 2 +- test-cargo-miri/subcrate/Cargo.toml | 4 ++++ test-cargo-miri/subcrate/src/lib.rs | 2 ++ test-cargo-miri/test.stderr-proc-macro.ref | 1 + 4 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 test-cargo-miri/subcrate/src/lib.rs create mode 100644 test-cargo-miri/test.stderr-proc-macro.ref diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 60924d4f8ddc..8edd947c3b0f 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -102,7 +102,7 @@ def test_cargo_miri_test(): ) test("`cargo miri test` (subcrate, no isolation)", cargo_miri("test") + ["-p", "subcrate"], - "test.subcrate.stdout.ref", "test.stderr-empty.ref", + "test.subcrate.stdout.ref", "test.stderr-proc-macro.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) diff --git a/test-cargo-miri/subcrate/Cargo.toml b/test-cargo-miri/subcrate/Cargo.toml index be27f88ad9a1..ea2936d52a05 100644 --- a/test-cargo-miri/subcrate/Cargo.toml +++ b/test-cargo-miri/subcrate/Cargo.toml @@ -4,6 +4,10 @@ version = "0.1.0" authors = ["Miri Team"] edition = "2018" +[lib] +proc-macro = true +doctest = false + [[bin]] name = "subcrate" path = "main.rs" diff --git a/test-cargo-miri/subcrate/src/lib.rs b/test-cargo-miri/subcrate/src/lib.rs new file mode 100644 index 000000000000..706e368017c0 --- /dev/null +++ b/test-cargo-miri/subcrate/src/lib.rs @@ -0,0 +1,2 @@ +#[cfg(test)] +compile_error!("Miri should not touch me"); diff --git a/test-cargo-miri/test.stderr-proc-macro.ref b/test-cargo-miri/test.stderr-proc-macro.ref new file mode 100644 index 000000000000..4983250917b5 --- /dev/null +++ b/test-cargo-miri/test.stderr-proc-macro.ref @@ -0,0 +1 @@ +Running unit tests of `proc-macro` crates is not currently supported by Miri. From a5d7ae5816e22dcd37989e45ca3d36e6366e1c53 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Mon, 25 Jan 2021 16:10:28 +0800 Subject: [PATCH 2517/5092] Fix `\n` in Zulip message https://rust-lang.zulipchat.com/#narrow/stream/269128-miri/topic/Cron.20Job.20Failure/near/223865005 --- .github/workflows/ci.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 43a964280d5a..a55cd8212517 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -130,5 +130,11 @@ jobs: ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }} run: | ~/.local/bin/zulip-send --stream miri --subject "Cron Job Failure" \ - --message 'Dear @**RalfJ** and @**oli**\n\nIt would appear that the Miri cron job build failed. Would you mind investigating this issue?\n\nThanks in advance!\nSincerely,\nThe Miri Cronjobs Bot' \ + --message 'Dear @**RalfJ** and @**oli** + + It would appear that the Miri cron job build failed. Would you mind investigating this issue? + + Thanks in advance! + Sincerely, + The Miri Cronjobs Bot' \ --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com From 13dd513254f92e5faa3f4ac7d41fc084c11fbb85 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 Jan 2021 09:46:10 +0100 Subject: [PATCH 2518/5092] adjust Windows shims for stdlib changes (Windows XP removal) --- rust-version | 2 +- src/shims/windows/dlsym.rs | 1 - src/shims/windows/foreign_items.rs | 35 ++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 25ee0983ab43..2064258addf6 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -dc1eee2f256efbd1d3b50b6b090232f81cac6d72 +9a9477fada5baf69d693e717d6df902e411a73d6 diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 415299c51fc6..c88a16461153 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -27,7 +27,6 @@ impl Dlsym { "AcquireSRWLockShared" => Some(Dlsym::AcquireSRWLockShared), "ReleaseSRWLockShared" => Some(Dlsym::ReleaseSRWLockShared), "TryAcquireSRWLockShared" => Some(Dlsym::TryAcquireSRWLockShared), - "SetThreadStackGuarantee" => None, "GetSystemTimePreciseAsFileTime" => None, _ => throw_unsup_format!("unsupported Windows dlsym: {}", name), }) diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 12b714880b35..17d566d18eea 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -5,6 +5,7 @@ use rustc_target::abi::Size; use crate::*; use helpers::check_arg_count; +use shims::windows::sync::EvalContextExt as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -207,6 +208,34 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } + // Synchronization primitives + "AcquireSRWLockExclusive" => { + let &[ptr] = check_arg_count(args)?; + this.AcquireSRWLockExclusive(ptr)?; + } + "ReleaseSRWLockExclusive" => { + let &[ptr] = check_arg_count(args)?; + this.ReleaseSRWLockExclusive(ptr)?; + } + "TryAcquireSRWLockExclusive" => { + let &[ptr] = check_arg_count(args)?; + let ret = this.TryAcquireSRWLockExclusive(ptr)?; + this.write_scalar(Scalar::from_u8(ret), dest)?; + } + "AcquireSRWLockShared" => { + let &[ptr] = check_arg_count(args)?; + this.AcquireSRWLockShared(ptr)?; + } + "ReleaseSRWLockShared" => { + let &[ptr] = check_arg_count(args)?; + this.ReleaseSRWLockShared(ptr)?; + } + "TryAcquireSRWLockShared" => { + let &[ptr] = check_arg_count(args)?; + let ret = this.TryAcquireSRWLockShared(ptr)?; + this.write_scalar(Scalar::from_u8(ret), dest)?; + } + // Dynamic symbol loading "GetProcAddress" => { #[allow(non_snake_case)] @@ -285,6 +314,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_machine_usize(1, this), dest)?; } + "SetThreadStackGuarantee" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + #[allow(non_snake_case)] + let &[_StackSizeInBytes] = check_arg_count(args)?; + // Any non zero value works for the stdlib. This is just used for stack overflows anyway. + this.write_scalar(Scalar::from_u32(1), dest)?; + } | "InitializeCriticalSection" | "EnterCriticalSection" | "LeaveCriticalSection" From c678bd722ea6fe8d1827787d5ecd411a77f411ca Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Sun, 24 Jan 2021 13:45:45 -0800 Subject: [PATCH 2519/5092] Add random failures to compare_exchange_weak --- src/data_race.rs | 21 ++++++++++++++++----- src/shims/intrinsics.rs | 18 +++++++++++------- tests/run-pass/atomic.rs | 26 ++++++++++++++++++-------- 3 files changed, 45 insertions(+), 20 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index d204d60f1565..31a167af8899 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -75,7 +75,7 @@ use rustc_target::abi::Size; use crate::{ ImmTy, Immediate, InterpResult, MPlaceTy, MemPlaceMeta, MiriEvalContext, MiriEvalContextExt, - OpTy, Pointer, RangeMap, ScalarMaybeUninit, Tag, ThreadId, VClock, VTimestamp, + OpTy, Pointer, RangeMap, Scalar, ScalarMaybeUninit, Tag, ThreadId, VClock, VTimestamp, VectorIdx, MemoryKind, MiriMemoryKind }; @@ -544,7 +544,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// Perform an atomic compare and exchange at a given memory location. /// On success an atomic RMW operation is performed and on failure - /// only an atomic read occurs. + /// only an atomic read occurs. If `can_fail_spuriously` is true, + /// then we treat it as a "compare_exchange_weak" operation, and + /// some portion of the time fail even when the values are actually + /// identical. fn atomic_compare_exchange_scalar( &mut self, place: MPlaceTy<'tcx, Tag>, @@ -552,7 +555,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { new: ScalarMaybeUninit, success: AtomicRwOp, fail: AtomicReadOp, + can_fail_spuriously: bool, ) -> InterpResult<'tcx, Immediate> { + use rand::Rng as _; let this = self.eval_context_mut(); // Failure ordering cannot be stronger than success ordering, therefore first attempt @@ -560,15 +565,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // read ordering and write in the success case. // Read as immediate for the sake of `binary_op()` let old = this.allow_data_races_mut(|this| this.read_immediate(place.into()))?; - // `binary_op` will bail if either of them is not a scalar. let eq = this.overflowing_binary_op(mir::BinOp::Eq, old, expect_old)?.0; - let res = Immediate::ScalarPair(old.to_scalar_or_uninit(), eq.into()); + // If the operation would succeed, but is "weak", fail 50% of the time. + // FIXME: this is quite arbitrary. + let cmpxchg_success = eq.to_bool()? + && (!can_fail_spuriously || this.memory.extra.rng.borrow_mut().gen_range(0, 2) == 0); + let res = Immediate::ScalarPair( + old.to_scalar_or_uninit(), + Scalar::from_bool(cmpxchg_success).into(), + ); // Update ptr depending on comparison. // if successful, perform a full rw-atomic validation // otherwise treat this as an atomic load with the fail ordering. - if eq.to_bool()? { + if cmpxchg_success { this.allow_data_races_mut(|this| this.write_scalar(new, place.into()))?; this.validate_atomic_rmw(place, success)?; } else { diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 840dd9f14336..73419a9f9764 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -518,9 +518,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - fn atomic_compare_exchange( + fn atomic_compare_exchange_impl( &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, - success: AtomicRwOp, fail: AtomicReadOp + success: AtomicRwOp, fail: AtomicReadOp, can_fail_spuriously: bool ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -538,7 +538,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let old = this.atomic_compare_exchange_scalar( - place, expect_old, new, success, fail + place, expect_old, new, success, fail, can_fail_spuriously )?; // Return old value. @@ -546,14 +546,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } + fn atomic_compare_exchange( + &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, + success: AtomicRwOp, fail: AtomicReadOp + ) -> InterpResult<'tcx> { + self.atomic_compare_exchange_impl(args, dest, success, fail, false) + } + fn atomic_compare_exchange_weak( &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, success: AtomicRwOp, fail: AtomicReadOp ) -> InterpResult<'tcx> { - - // FIXME: the weak part of this is currently not modelled, - // it is assumed to always succeed unconditionally. - self.atomic_compare_exchange(args, dest, success, fail) + self.atomic_compare_exchange_impl(args, dest, success, fail, true) } fn float_to_int_unchecked( diff --git a/tests/run-pass/atomic.rs b/tests/run-pass/atomic.rs index b03a8c8901e1..4ebca71c7cf3 100644 --- a/tests/run-pass/atomic.rs +++ b/tests/run-pass/atomic.rs @@ -24,7 +24,20 @@ fn atomic_bool() { assert_eq!(*ATOMIC.get_mut(), false); } } - +// There isn't a trait to use to make this generic, so just use a macro +macro_rules! compare_exchange_weak_loop { + ($atom:expr, $from:expr, $to:expr, $succ_order:expr, $fail_order:expr) => { + loop { + match $atom.compare_exchange_weak($from, $to, $succ_order, $fail_order) { + Ok(n) => { + assert_eq!(n, $from); + break; + } + Err(n) => assert_eq!(n, $from), + } + } + }; +} fn atomic_isize() { static ATOMIC: AtomicIsize = AtomicIsize::new(0); @@ -40,11 +53,11 @@ fn atomic_isize() { ATOMIC.compare_exchange(0, 1, SeqCst, SeqCst).ok(); ATOMIC.store(0, SeqCst); - - assert_eq!(ATOMIC.compare_exchange_weak(0, 1, Relaxed, Relaxed), Ok(0)); + compare_exchange_weak_loop!(ATOMIC, 0, 1, Relaxed, Relaxed); assert_eq!(ATOMIC.compare_exchange_weak(0, 2, Acquire, Relaxed), Err(1)); assert_eq!(ATOMIC.compare_exchange_weak(0, 1, Release, Relaxed), Err(1)); - assert_eq!(ATOMIC.compare_exchange_weak(1, 0, AcqRel, Relaxed), Ok(1)); + compare_exchange_weak_loop!(ATOMIC, 1, 0, AcqRel, Relaxed); + assert_eq!(ATOMIC.load(Relaxed), 0); ATOMIC.compare_exchange_weak(0, 1, AcqRel, Relaxed).ok(); ATOMIC.compare_exchange_weak(0, 1, SeqCst, Relaxed).ok(); ATOMIC.compare_exchange_weak(0, 1, Acquire, Acquire).ok(); @@ -58,10 +71,7 @@ fn atomic_u64() { ATOMIC.store(1, SeqCst); assert_eq!(ATOMIC.compare_exchange(0, 0x100, AcqRel, Acquire), Err(1)); - assert_eq!( - ATOMIC.compare_exchange_weak(1, 0x100, AcqRel, Acquire), - Ok(1) - ); + compare_exchange_weak_loop!(ATOMIC, 1, 0x100, AcqRel, Acquire); assert_eq!(ATOMIC.load(Relaxed), 0x100); } From b6eccc6482ba9524b0ad7f0561bc0e77adcd5d24 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Mon, 25 Jan 2021 02:41:03 -0800 Subject: [PATCH 2520/5092] Test that _weak atomics sometimes fail --- tests/run-pass/atomic.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/run-pass/atomic.rs b/tests/run-pass/atomic.rs index 4ebca71c7cf3..4871aa9fe0f6 100644 --- a/tests/run-pass/atomic.rs +++ b/tests/run-pass/atomic.rs @@ -5,6 +5,7 @@ fn main() { atomic_isize(); atomic_u64(); atomic_fences(); + weak_sometimes_fails(); } fn atomic_bool() { @@ -85,3 +86,17 @@ fn atomic_fences() { compiler_fence(Acquire); compiler_fence(AcqRel); } + +fn weak_sometimes_fails() { + static ATOMIC: AtomicBool = AtomicBool::new(false); + let tries = 20; + for _ in 0..tries { + let cur = ATOMIC.load(Relaxed); + // Try (weakly) to flip the flag. + if ATOMIC.compare_exchange_weak(cur, !cur, Relaxed, Relaxed).is_err() { + // We succeeded, so return and skip the panic. + return; + } + } + panic!("compare_exchange_weak succeeded {} tries in a row", tries); +} From efd2d55e001de2a069d9ad45687abb5834f227da Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Mon, 25 Jan 2021 02:52:55 -0800 Subject: [PATCH 2521/5092] review nits --- tests/run-pass/atomic.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/run-pass/atomic.rs b/tests/run-pass/atomic.rs index 4871aa9fe0f6..66d25ca01ea9 100644 --- a/tests/run-pass/atomic.rs +++ b/tests/run-pass/atomic.rs @@ -88,13 +88,13 @@ fn atomic_fences() { } fn weak_sometimes_fails() { - static ATOMIC: AtomicBool = AtomicBool::new(false); + let atomic = AtomicBool::new(false); let tries = 20; for _ in 0..tries { - let cur = ATOMIC.load(Relaxed); + let cur = atomic.load(Relaxed); // Try (weakly) to flip the flag. - if ATOMIC.compare_exchange_weak(cur, !cur, Relaxed, Relaxed).is_err() { - // We succeeded, so return and skip the panic. + if atomic.compare_exchange_weak(cur, !cur, Relaxed, Relaxed).is_err() { + // We failed, so return and skip the panic. return; } } From d4b592ed17471622d27deeab8a1d8d89bc5c17d1 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Mon, 25 Jan 2021 02:59:12 -0800 Subject: [PATCH 2522/5092] Fail 80% of the time on weak cmpxchg, not 50% --- src/data_race.rs | 4 ++-- tests/run-pass/atomic.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index 31a167af8899..dd0dccd0e950 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -567,10 +567,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let old = this.allow_data_races_mut(|this| this.read_immediate(place.into()))?; // `binary_op` will bail if either of them is not a scalar. let eq = this.overflowing_binary_op(mir::BinOp::Eq, old, expect_old)?.0; - // If the operation would succeed, but is "weak", fail 50% of the time. + // If the operation would succeed, but is "weak", fail 80% of the time. // FIXME: this is quite arbitrary. let cmpxchg_success = eq.to_bool()? - && (!can_fail_spuriously || this.memory.extra.rng.borrow_mut().gen_range(0, 2) == 0); + && (!can_fail_spuriously || this.memory.extra.rng.borrow_mut().gen_range(0, 10) < 8); let res = Immediate::ScalarPair( old.to_scalar_or_uninit(), Scalar::from_bool(cmpxchg_success).into(), diff --git a/tests/run-pass/atomic.rs b/tests/run-pass/atomic.rs index 66d25ca01ea9..4f27c2bd54d6 100644 --- a/tests/run-pass/atomic.rs +++ b/tests/run-pass/atomic.rs @@ -89,7 +89,7 @@ fn atomic_fences() { fn weak_sometimes_fails() { let atomic = AtomicBool::new(false); - let tries = 20; + let tries = 100; for _ in 0..tries { let cur = atomic.load(Relaxed); // Try (weakly) to flip the flag. From d310620c11bb61156d9198b7c5c3c574846ff73d Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Tue, 26 Jan 2021 00:07:43 -0800 Subject: [PATCH 2523/5092] Allow configuring the failure rate with -Zmiri-compare-exchange-weak-failure-rate --- src/bin/miri.rs | 8 ++++++++ src/data_race.rs | 7 ++++--- src/eval.rs | 4 ++++ src/machine.rs | 4 ++++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 1117b69116a5..bd3bc8dbb412 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -282,6 +282,14 @@ fn main() { }; miri_config.tracked_alloc_id = Some(miri::AllocId(id)); } + arg if arg.starts_with("-Zmiri-compare-exchange-weak-failure-rate=") => { + let rate = match arg.strip_prefix("-Zmiri-compare-exchange-weak-failure-rate=").unwrap().parse::() { + Ok(rate) if rate >= 0.0 && rate <= 1.0 => rate, + Ok(_) => panic!("-Zmiri-compare-exchange-weak-failure-rate must be between `0.0` and `1.0`"), + Err(err) => panic!("-Zmiri-compare-exchange-weak-failure-rate requires a `f64` between `0.0` and `1.0`: {}", err), + }; + miri_config.cmpxchg_weak_failure_rate = rate; + } _ => { // Forward to rustc. rustc_args.push(arg); diff --git a/src/data_race.rs b/src/data_race.rs index dd0dccd0e950..f79775e12fe7 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -567,10 +567,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let old = this.allow_data_races_mut(|this| this.read_immediate(place.into()))?; // `binary_op` will bail if either of them is not a scalar. let eq = this.overflowing_binary_op(mir::BinOp::Eq, old, expect_old)?.0; - // If the operation would succeed, but is "weak", fail 80% of the time. - // FIXME: this is quite arbitrary. + // If the operation would succeed, but is "weak", fail some portion + // of the time, based on `rate`. + let rate = this.memory.extra.cmpxchg_weak_failure_rate; let cmpxchg_success = eq.to_bool()? - && (!can_fail_spuriously || this.memory.extra.rng.borrow_mut().gen_range(0, 10) < 8); + && (!can_fail_spuriously || this.memory.extra.rng.borrow_mut().gen::() < rate); let res = Immediate::ScalarPair( old.to_scalar_or_uninit(), Scalar::from_bool(cmpxchg_success).into(), diff --git a/src/eval.rs b/src/eval.rs index 0a62f14dd3a1..b6d4fa05e1e5 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -50,6 +50,9 @@ pub struct MiriConfig { pub track_raw: bool, /// Determine if data race detection should be enabled pub data_race_detector: bool, + /// Rate of spurious failures for compare_exchange_weak atomic operations, + /// between 0.0 and 1.0, defaulting to 0.8 (80% chance of failure). + pub cmpxchg_weak_failure_rate: f64, } impl Default for MiriConfig { @@ -68,6 +71,7 @@ impl Default for MiriConfig { tracked_alloc_id: None, track_raw: false, data_race_detector: true, + cmpxchg_weak_failure_rate: 0.8, } } } diff --git a/src/machine.rs b/src/machine.rs index d28aa34c75e8..60a6dae0f81b 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -135,6 +135,9 @@ pub struct MemoryExtra { /// Controls whether alignment of memory accesses is being checked. pub(crate) check_alignment: AlignmentCheck, + + /// Failure rate of compare_exchange_weak, between 0.0 and 1.0 + pub(crate) cmpxchg_weak_failure_rate: f64, } impl MemoryExtra { @@ -162,6 +165,7 @@ impl MemoryExtra { rng: RefCell::new(rng), tracked_alloc_id: config.tracked_alloc_id, check_alignment: config.check_alignment, + cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate, } } From d38e861f1e0afc7f9853935d41c92f91d8c3cf78 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 26 Jan 2021 11:43:39 +0100 Subject: [PATCH 2524/5092] rustup; allow some lints --- rust-version | 2 +- tests/run-pass/float.rs | 1 + tests/run-pass/integer-ops.rs | 10 +--------- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/rust-version b/rust-version index 2064258addf6..d4006f955da5 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9a9477fada5baf69d693e717d6df902e411a73d6 +a8f707553276a15565860af3d415aae18428aa96 diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index d0df13490f0c..d9dba770dabd 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -1,4 +1,5 @@ #![feature(stmt_expr_attributes, test)] +#![allow(arithmetic_overflow)] use std::fmt::Debug; use std::hint::black_box; diff --git a/tests/run-pass/integer-ops.rs b/tests/run-pass/integer-ops.rs index 4ae42df59200..36bd5797177a 100644 --- a/tests/run-pass/integer-ops.rs +++ b/tests/run-pass/integer-ops.rs @@ -1,12 +1,4 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. +#![allow(arithmetic_overflow)] pub fn main() { // This tests that do (not) do sign extension properly when loading integers From 0e56bff5f92a557113d92758b0a4570455286a3d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 26 Jan 2021 11:48:11 +0100 Subject: [PATCH 2525/5092] erroneous_const span now changes with inlining --- tests/compile-fail/erroneous_const.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/compile-fail/erroneous_const.rs b/tests/compile-fail/erroneous_const.rs index 287e07358141..7f1a81820890 100644 --- a/tests/compile-fail/erroneous_const.rs +++ b/tests/compile-fail/erroneous_const.rs @@ -1,5 +1,7 @@ //! Make sure we detect erroneous constants post-monomorphization even when they are unused. //! (https://github.com/rust-lang/miri/issues/1382) +// Inlining changes the error location +// compile-flags: -Zmir-opt-level=0 #![feature(const_panic)] #![feature(never_type)] #![warn(warnings, const_err)] From e308eeb3f13b6ee8665f9d10a3b184383431fdeb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 27 Jan 2021 10:43:59 +0100 Subject: [PATCH 2526/5092] rustup; more slack for timing tests --- rust-version | 2 +- tests/run-pass/concurrency/sync.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index d4006f955da5..af4bc45869dc 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a8f707553276a15565860af3d415aae18428aa96 +78e22069d018e83915201c8a218a0a94227f6420 diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index e97da415cbb1..88187d64e604 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -92,7 +92,7 @@ fn check_conditional_variables_timed_wait_timeout() { let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap(); assert!(timeout.timed_out()); let elapsed_time = now.elapsed().as_millis(); - assert!(100 <= elapsed_time && elapsed_time <= 300); + assert!(100 <= elapsed_time && elapsed_time <= 500); } /// Test that signaling a conditional variable when waiting with a timeout works From de4eea9d49b5d4d5e10e67e1ae2754bbb720564c Mon Sep 17 00:00:00 2001 From: Nym Seddon Date: Fri, 22 Jan 2021 02:45:39 +0000 Subject: [PATCH 2527/5092] Add ABI check for shims --- src/helpers.rs | 10 ++++++++ src/machine.rs | 8 +++--- src/shims/dlsym.rs | 6 +++-- src/shims/foreign_items.rs | 39 ++++++++++++++++++++++++++---- src/shims/mod.rs | 4 ++- src/shims/posix/dlsym.rs | 4 +++ src/shims/posix/foreign_items.rs | 6 ++++- src/shims/windows/dlsym.rs | 6 ++++- src/shims/windows/foreign_items.rs | 6 ++++- 9 files changed, 74 insertions(+), 15 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 4c989db0170b..6a12a8f6ba35 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -9,6 +9,7 @@ use rustc_middle::mir; use rustc_middle::ty::{self, List, TyCtxt, layout::TyAndLayout}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_target::abi::{LayoutOf, Size, FieldsShape, Variants}; +use rustc_target::spec::abi::Abi; use rand::RngCore; @@ -553,6 +554,15 @@ pub fn check_arg_count<'a, 'tcx, const N: usize>(args: &'a [OpTy<'tcx, Tag>]) -> throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N) } +/// Check that the ABI is what we expect. +pub fn check_abi<'a>(abi: Abi, exp_abi: Abi) -> InterpResult<'a, ()> { + if abi == exp_abi { + Ok(()) + } else { + throw_ub_format!("calling a function with ABI {:?} using caller ABI {:?}", exp_abi, abi) + } +} + pub fn isolation_error(name: &str) -> InterpResult<'static> { throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!( "{} not available when isolation is enabled", diff --git a/src/machine.rs b/src/machine.rs index d28aa34c75e8..ab7abebaeabc 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -353,24 +353,24 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn find_mir_or_eval_fn( ecx: &mut InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, - _abi: Abi, + abi: Abi, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { - ecx.find_mir_or_eval_fn(instance, args, ret, unwind) + ecx.find_mir_or_eval_fn(instance, abi, args, ret, unwind) } #[inline(always)] fn call_extra_fn( ecx: &mut InterpCx<'mir, 'tcx, Self>, fn_val: Dlsym, - _abi: Abi, + abi: Abi, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, _unwind: Option, ) -> InterpResult<'tcx> { - ecx.call_dlsym(fn_val, args, ret) + ecx.call_dlsym(fn_val, abi, args, ret) } #[inline(always)] diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 9b15cb9ac9a3..a87d8a017573 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -1,4 +1,5 @@ use rustc_middle::mir; +use rustc_target::spec::abi::Abi; use crate::*; use shims::posix::dlsym as posix; @@ -29,13 +30,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn call_dlsym( &mut self, dlsym: Dlsym, + abi: Abi, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); match dlsym { - Dlsym::Posix(dlsym) => posix::EvalContextExt::call_dlsym(this, dlsym, args, ret), - Dlsym::Windows(dlsym) => windows::EvalContextExt::call_dlsym(this, dlsym, args, ret), + Dlsym::Posix(dlsym) => posix::EvalContextExt::call_dlsym(this, dlsym, abi, args, ret), + Dlsym::Windows(dlsym) => windows::EvalContextExt::call_dlsym(this, dlsym, abi, args, ret), } } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 237fb27d9222..628e9b69e174 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -4,14 +4,14 @@ use log::trace; use rustc_hir::def_id::DefId; use rustc_middle::mir; -use rustc_target::{abi::{Align, Size}, spec::PanicStrategy}; +use rustc_target::{abi::{Align, Size}, spec::{PanicStrategy, abi::Abi}}; use rustc_middle::ty; use rustc_apfloat::Float; use rustc_span::symbol::sym; use crate::*; use super::backtrace::EvalContextExt as _; -use helpers::check_arg_count; +use helpers::{check_abi, check_arg_count}; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -112,6 +112,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_foreign_item( &mut self, def_id: DefId, + abi: Abi, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, @@ -130,12 +131,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (dest, ret) = match ret { None => match link_name { "miri_start_panic" => { + check_abi(abi, Abi::Rust)?; this.handle_miri_start_panic(args, unwind)?; return Ok(None); } // This matches calls to the foreign item `panic_impl`. // The implementation is provided by the function with the `#[panic_handler]` attribute. "panic_impl" => { + check_abi(abi, Abi::Rust)?; let panic_impl_id = tcx.lang_items().panic_impl().unwrap(); let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id); return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); @@ -143,12 +146,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "exit" | "ExitProcess" => { + check_abi(abi, if link_name == "exit" { Abi::C } else { Abi::System })?; let &[code] = check_arg_count(args)?; // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway let code = this.read_scalar(code)?.to_i32()?; throw_machine_stop!(TerminationInfo::Exit(code.into())); } "abort" => { + check_abi(abi, Abi::C)?; throw_machine_stop!(TerminationInfo::Abort("the program aborted execution".to_owned())) } _ => throw_unsup_format!("can't call (diverging) foreign function: {}", link_name), @@ -165,6 +170,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Normally, this will be either `libpanic_unwind` or `libpanic_abort`, but it could // also be a custom user-provided implementation via `#![feature(panic_runtime)]` "__rust_start_panic" | "__rust_panic_cleanup" => { + check_abi(abi, Abi::C)?; // This replicates some of the logic in `inject_panic_runtime`. // FIXME: is there a way to reuse that logic? let panic_runtime = match this.tcx.sess.panic_strategy() { @@ -179,7 +185,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Third: functions that return. - if this.emulate_foreign_item_by_name(link_name, args, dest, ret)? { + if this.emulate_foreign_item_by_name(link_name, abi, args, dest, ret)? { trace!("{:?}", this.dump_place(*dest)); this.go_to_block(ret); } @@ -193,6 +199,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_foreign_item_by_name( &mut self, link_name: &str, + abi: Abi, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, ret: mir::BasicBlock, @@ -204,6 +211,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Miri-specific extern functions "miri_static_root" => { + check_abi(abi, Abi::Rust)?; let &[ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let ptr = this.force_ptr(ptr)?; @@ -215,23 +223,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Obtains a Miri backtrace. See the README for details. "miri_get_backtrace" => { + check_abi(abi, Abi::Rust)?; this.handle_miri_get_backtrace(args, dest)?; } // Resolves a Miri backtrace frame. See the README for details. "miri_resolve_frame" => { + check_abi(abi, Abi::Rust)?; this.handle_miri_resolve_frame(args, dest)?; } // Standard C allocation "malloc" => { + check_abi(abi, Abi::C)?; let &[size] = check_arg_count(args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C); this.write_scalar(res, dest)?; } "calloc" => { + check_abi(abi, Abi::C)?; let &[items, len] = check_arg_count(args)?; let items = this.read_scalar(items)?.to_machine_usize(this)?; let len = this.read_scalar(len)?.to_machine_usize(this)?; @@ -241,11 +253,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } "free" => { + check_abi(abi, Abi::C)?; let &[ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; this.free(ptr, MiriMemoryKind::C)?; } "realloc" => { + check_abi(abi, Abi::C)?; let &[old_ptr, new_size] = check_arg_count(args)?; let old_ptr = this.read_scalar(old_ptr)?.check_init()?; let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; @@ -257,6 +271,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // (Usually these would be forwarded to to `#[global_allocator]`; we instead implement a generic // allocation that also checks that all conditions are met, such as not permitting zero-sized allocations.) "__rust_alloc" => { + check_abi(abi, Abi::Rust)?; let &[size, align] = check_arg_count(args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -269,6 +284,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "__rust_alloc_zeroed" => { + check_abi(abi, Abi::Rust)?; let &[size, align] = check_arg_count(args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -283,6 +299,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "__rust_dealloc" => { + check_abi(abi, Abi::Rust)?; let &[ptr, old_size, align] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; @@ -296,6 +313,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; } "__rust_realloc" => { + check_abi(abi, Abi::Rust)?; let &[ptr, old_size, align, new_size] = check_arg_count(args)?; let ptr = this.force_ptr(this.read_scalar(ptr)?.check_init()?)?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; @@ -316,6 +334,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // C memory handling functions "memcmp" => { + check_abi(abi, Abi::C)?; let &[left, right, n] = check_arg_count(args)?; let left = this.read_scalar(left)?.check_init()?; let right = this.read_scalar(right)?.check_init()?; @@ -336,6 +355,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "memrchr" => { + check_abi(abi, Abi::C)?; let &[ptr, val, num] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; @@ -354,6 +374,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "memchr" => { + check_abi(abi, Abi::C)?; let &[ptr, val, num] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; @@ -371,6 +392,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "strlen" => { + check_abi(abi, Abi::C)?; let &[ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let n = this.memory.read_c_str(ptr)?.len(); @@ -386,6 +408,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asinf" | "atanf" => { + check_abi(abi, Abi::C)?; let &[f] = check_arg_count(args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); @@ -405,6 +428,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypotf" | "atan2f" => { + check_abi(abi, Abi::C)?; let &[f1, f2] = check_arg_count(args)?; // underscore case for windows, here and below // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) @@ -426,6 +450,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asin" | "atan" => { + check_abi(abi, Abi::C)?; let &[f] = check_arg_count(args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); @@ -445,6 +470,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypot" | "atan2" => { + check_abi(abi, Abi::C)?; let &[f1, f2] = check_arg_count(args)?; // FIXME: Using host floats. let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?); @@ -460,6 +486,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "ldexp" | "scalbn" => { + check_abi(abi, Abi::C)?; let &[x, exp] = check_arg_count(args)?; // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. let x = this.read_scalar(x)?.to_f64()?; @@ -481,10 +508,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Architecture-specific shims "llvm.x86.sse2.pause" if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" => { + check_abi(abi, Abi::C)?; let &[] = check_arg_count(args)?; this.yield_active_thread(); } "llvm.aarch64.hint" if this.tcx.sess.target.arch == "aarch64" => { + check_abi(abi, Abi::C)?; let &[hint] = check_arg_count(args)?; let hint = this.read_scalar(hint)?.to_i32()?; match hint { @@ -499,8 +528,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Platform-specific shims _ => match this.tcx.sess.target.os.as_str() { - "linux" | "macos" => return shims::posix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), - "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), + "linux" | "macos" => return shims::posix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), + "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), target => throw_unsup_format!("the target `{}` is not supported", target), } }; diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 90dcc4d8ff1e..c2b8809efbb6 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -16,6 +16,7 @@ pub mod tls; use log::trace; use rustc_middle::{mir, ty}; +use rustc_target::spec::abi::Abi; use crate::*; use helpers::check_arg_count; @@ -25,6 +26,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn find_mir_or_eval_fn( &mut self, instance: ty::Instance<'tcx>, + abi: Abi, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, @@ -48,7 +50,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // to run extra MIR), and Ok(Some(body)) if we found MIR to run for the // foreign function // Any needed call to `goto_block` will be performed by `emulate_foreign_item`. - return this.emulate_foreign_item(instance.def_id(), args, ret, unwind); + return this.emulate_foreign_item(instance.def_id(), abi, args, ret, unwind); } // Otherwise, load the MIR. diff --git a/src/shims/posix/dlsym.rs b/src/shims/posix/dlsym.rs index 52d9844bed51..e05419f47e93 100644 --- a/src/shims/posix/dlsym.rs +++ b/src/shims/posix/dlsym.rs @@ -1,6 +1,8 @@ use rustc_middle::mir; +use rustc_target::spec::abi::Abi; use crate::*; +use helpers::check_abi; use shims::posix::linux::dlsym as linux; use shims::posix::macos::dlsym as macos; @@ -27,10 +29,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn call_dlsym( &mut self, dlsym: Dlsym, + abi: Abi, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + check_abi(abi, Abi::C)?; match dlsym { Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, ret), Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, args, ret), diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index f92242f56d9e..e576c6f32e90 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -2,9 +2,10 @@ use log::trace; use rustc_middle::mir; use rustc_target::abi::{Align, LayoutOf, Size}; +use rustc_target::spec::abi::Abi; use crate::*; -use helpers::check_arg_count; +use helpers::{check_abi, check_arg_count}; use shims::posix::fs::EvalContextExt as _; use shims::posix::sync::EvalContextExt as _; use shims::posix::thread::EvalContextExt as _; @@ -14,12 +15,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_foreign_item_by_name( &mut self, link_name: &str, + abi: Abi, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, ret: mir::BasicBlock, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); + check_abi(abi, Abi::C)?; + match link_name { // Environment related shims "getenv" => { diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index c88a16461153..ce119d1090b1 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -1,9 +1,10 @@ use rustc_middle::mir; +use rustc_target::spec::abi::Abi; use log::trace; use crate::*; -use helpers::check_arg_count; +use helpers::{check_abi, check_arg_count}; use shims::windows::sync::EvalContextExt as _; #[derive(Debug, Copy, Clone)] @@ -38,6 +39,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn call_dlsym( &mut self, dlsym: Dlsym, + abi: Abi, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, ) -> InterpResult<'tcx> { @@ -45,6 +47,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (dest, ret) = ret.expect("we don't support any diverging dlsym"); assert!(this.tcx.sess.target.os == "windows"); + check_abi(abi, Abi::System)?; + match dlsym { Dlsym::AcquireSRWLockExclusive => { let &[ptr] = check_arg_count(args)?; diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 17d566d18eea..52b68b9f1bc3 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -2,9 +2,10 @@ use std::iter; use rustc_middle::mir; use rustc_target::abi::Size; +use rustc_target::spec::abi::Abi; use crate::*; -use helpers::check_arg_count; +use helpers::{check_abi, check_arg_count}; use shims::windows::sync::EvalContextExt as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -12,12 +13,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_foreign_item_by_name( &mut self, link_name: &str, + abi: Abi, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, _ret: mir::BasicBlock, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); + check_abi(abi, Abi::System)?; + // Windows API stubs. // HANDLE = isize // DWORD = ULONG = u32 From 35ece43ef79b1b472ed13b6eb353fb38a2c4a544 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 28 Jan 2021 10:58:33 +0100 Subject: [PATCH 2528/5092] Document -Zmiri-compare-exchange-weak-failure-rate --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index b2f0babfc9bc..72e69d45033b 100644 --- a/README.md +++ b/README.md @@ -251,6 +251,10 @@ environment variable: can recognize false positives by "" occurring in the message -- this indicates a pointer that was cast from an integer, so Miri was unable to track this pointer. +* `-Zmiri-compare-exchange-weak-failure-rate=` changes the failure rate of + weak atomic operations. The default is `0.8` (so 4 out of 5 weak ops will fail. + You can change it to any value between `0.0` and `1.0`, where `1.0` means it + will always fail and `0.0` means it will never fail. Some native rustc `-Z` flags are also very relevant for Miri: From 53612ece7c167395719b03a3e60d8105fa1babd1 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Thu, 28 Jan 2021 21:30:36 +0900 Subject: [PATCH 2529/5092] Rustup for rust-lang/rust#79951 --- rust-version | 2 +- src/lib.rs | 1 - src/shims/intrinsics.rs | 8 +++----- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/rust-version b/rust-version index af4bc45869dc..5752b651d2a2 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -78e22069d018e83915201c8a218a0a94227f6420 +0e190206e2ff0c13d64701d9b4145bf89a2d0cab diff --git a/src/lib.rs b/src/lib.rs index aadbb0270de4..5ed3d8950d04 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,6 @@ #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] -extern crate rustc_attr; extern crate rustc_apfloat; extern crate rustc_ast; #[macro_use] extern crate rustc_middle; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 73419a9f9764..fc859bc53020 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -2,9 +2,7 @@ use std::iter; use log::trace; -use rustc_attr as attr; -use rustc_ast::ast::FloatTy; -use rustc_middle::{mir, mir::BinOp, ty}; +use rustc_middle::{mir, mir::BinOp, ty, ty::FloatTy}; use rustc_middle::ty::layout::IntegerExt; use rustc_apfloat::{Float, Round}; use rustc_target::abi::{Align, Integer, LayoutOf}; @@ -578,7 +576,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(match dest_ty.kind() { // Unsigned ty::Uint(t) => { - let size = Integer::from_attr(this, attr::IntType::UnsignedInt(*t)).size(); + let size = Integer::from_uint_ty(this, *t).size(); let res = f.to_u128(size.bits_usize()); if res.status.is_empty() { // No status flags means there was no further rounding or other loss of precision. @@ -593,7 +591,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Signed ty::Int(t) => { - let size = Integer::from_attr(this, attr::IntType::SignedInt(*t)).size(); + let size = Integer::from_int_ty(this, *t).size(); let res = f.to_i128(size.bits_usize()); if res.status.is_empty() { // No status flags means there was no further rounding or other loss of precision. From 9d777d84109ab6ef7b36d9ef42c94a1ff6c7d65c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 29 Jan 2021 21:16:17 +0100 Subject: [PATCH 2530/5092] add test for caller ABI check --- tests/compile-fail/check_arg_abi.rs | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/compile-fail/check_arg_abi.rs diff --git a/tests/compile-fail/check_arg_abi.rs b/tests/compile-fail/check_arg_abi.rs new file mode 100644 index 000000000000..5656c7a0e4cb --- /dev/null +++ b/tests/compile-fail/check_arg_abi.rs @@ -0,0 +1,9 @@ +fn main() { + extern "Rust" { + fn malloc(size: usize) -> *mut std::ffi::c_void; + } + + unsafe { + let _ = malloc(0); //~ ERROR calling a function with ABI C using caller ABI Rust + }; +} From bd04091a16156f4702118b371e02ef1460b9e0b8 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Sat, 30 Jan 2021 20:05:21 +0100 Subject: [PATCH 2531/5092] Update README.md Co-authored-by: Ralf Jung --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 72e69d45033b..d742d7558c4d 100644 --- a/README.md +++ b/README.md @@ -252,7 +252,7 @@ environment variable: indicates a pointer that was cast from an integer, so Miri was unable to track this pointer. * `-Zmiri-compare-exchange-weak-failure-rate=` changes the failure rate of - weak atomic operations. The default is `0.8` (so 4 out of 5 weak ops will fail. + `compare_exchange_weak` operations. The default is `0.8` (so 4 out of 5 weak ops will fail). You can change it to any value between `0.0` and `1.0`, where `1.0` means it will always fail and `0.0` means it will never fail. From 397443093de127ada63ec74bd048394050aa1a10 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Sat, 30 Jan 2021 20:06:05 +0100 Subject: [PATCH 2532/5092] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d742d7558c4d..ae70c80d5f0a 100644 --- a/README.md +++ b/README.md @@ -195,6 +195,10 @@ up the sysroot. If you are using `miri` (the Miri driver) directly, see the Miri adds its own set of `-Z` flags, which are usually set via the `MIRIFLAGS` environment variable: +* `-Zmiri-compare-exchange-weak-failure-rate=` changes the failure rate of + `compare_exchange_weak` operations. The default is `0.8` (so 4 out of 5 weak ops will fail). + You can change it to any value between `0.0` and `1.0`, where `1.0` means it + will always fail and `0.0` means it will never fail. * `-Zmiri-disable-alignment-check` disables checking pointer alignment, so you can focus on other failures, but it means Miri can miss bugs in your program. Using this flag is **unsound**. @@ -251,10 +255,6 @@ environment variable: can recognize false positives by "" occurring in the message -- this indicates a pointer that was cast from an integer, so Miri was unable to track this pointer. -* `-Zmiri-compare-exchange-weak-failure-rate=` changes the failure rate of - `compare_exchange_weak` operations. The default is `0.8` (so 4 out of 5 weak ops will fail). - You can change it to any value between `0.0` and `1.0`, where `1.0` means it - will always fail and `0.0` means it will never fail. Some native rustc `-Z` flags are also very relevant for Miri: From 6f5a91f70a3f0b4966dfd5e06dbd69b87f363afd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 31 Jan 2021 13:12:25 +0100 Subject: [PATCH 2533/5092] rustup --- rust-version | 2 +- .../dangling_pointers/dangling_pointer_addr_of.rs | 3 +-- tests/compile-fail/extern_static.rs | 3 +-- .../unaligned_pointers/unaligned_ptr_addr_of.rs | 3 +-- tests/run-pass/issue-73223.rs | 1 + tests/run-pass/many_shr_bor.rs | 1 + tests/run-pass/packed_struct.rs | 8 +++----- tests/run-pass/stacked-borrows/stacked-borrows.rs | 5 ++--- 8 files changed, 11 insertions(+), 15 deletions(-) diff --git a/rust-version b/rust-version index 5752b651d2a2..e9314ffced05 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0e190206e2ff0c13d64701d9b4145bf89a2d0cab +9b3242982202707be2485b1e4cf5f3b34466a38d diff --git a/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.rs b/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.rs index 5df5b324f457..5de413871171 100644 --- a/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.rs +++ b/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.rs @@ -1,6 +1,5 @@ // Make sure we find these even with many checks disabled. // compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation -#![feature(raw_ref_macros)] use std::ptr; fn main() { @@ -8,6 +7,6 @@ fn main() { let b = Box::new(42); &*b as *const i32 }; - let x = unsafe { ptr::raw_const!(*p) }; //~ ERROR dereferenced after this allocation got freed + let x = unsafe { ptr::addr_of!(*p) }; //~ ERROR dereferenced after this allocation got freed panic!("this should never print: {:?}", x); } diff --git a/tests/compile-fail/extern_static.rs b/tests/compile-fail/extern_static.rs index 650dfd0ac787..f3466d5e7180 100644 --- a/tests/compile-fail/extern_static.rs +++ b/tests/compile-fail/extern_static.rs @@ -1,4 +1,3 @@ -#![feature(raw_ref_op)] //! Even referencing an unknown `extern static` already triggers an error. extern "C" { @@ -6,5 +5,5 @@ extern "C" { } fn main() { - let _val = unsafe { &raw const FOO }; //~ ERROR is not supported by Miri + let _val = unsafe { std::ptr::addr_of!(FOO) }; //~ ERROR is not supported by Miri } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs index 88e2634efaf6..e33f3c8598f3 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs @@ -1,6 +1,5 @@ // This should fail even without validation or Stacked Borrows. // compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -#![feature(raw_ref_macros)] use std::ptr; fn main() { @@ -9,6 +8,6 @@ fn main() { let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. // The deref is UB even if we just put the result into a raw pointer. - let _x = unsafe { ptr::raw_const!(*x) }; //~ ERROR memory with alignment 2, but alignment 4 is required + let _x = unsafe { ptr::addr_of!(*x) }; //~ ERROR memory with alignment 2, but alignment 4 is required } } diff --git a/tests/run-pass/issue-73223.rs b/tests/run-pass/issue-73223.rs index 3a32d970d637..df13787aad69 100644 --- a/tests/run-pass/issue-73223.rs +++ b/tests/run-pass/issue-73223.rs @@ -4,6 +4,7 @@ fn main() { assert_eq!(state.rest(path), "some/more"); } +#[allow(unused)] struct State { prev: Option, next: Option, diff --git a/tests/run-pass/many_shr_bor.rs b/tests/run-pass/many_shr_bor.rs index d4901abb808f..ba2f9b61b1f3 100644 --- a/tests/run-pass/many_shr_bor.rs +++ b/tests/run-pass/many_shr_bor.rs @@ -1,6 +1,7 @@ // Make sure validation can handle many overlapping shared borrows for different parts of a data structure use std::cell::RefCell; +#[allow(unused)] struct Test { a: u32, b: u32, diff --git a/tests/run-pass/packed_struct.rs b/tests/run-pass/packed_struct.rs index 43419695ba04..dd95d660d75e 100644 --- a/tests/run-pass/packed_struct.rs +++ b/tests/run-pass/packed_struct.rs @@ -1,4 +1,4 @@ -#![feature(unsize, coerce_unsized, raw_ref_op, raw_ref_macros)] +#![feature(unsize, coerce_unsized)] use std::collections::hash_map::DefaultHasher; use std::hash::Hash; @@ -45,10 +45,8 @@ fn test_basic() { assert_eq!({x.a}, 42); assert_eq!({x.b}, 99); // but we *can* take a raw pointer! - assert_eq!(unsafe { (&raw const x.a).read_unaligned() }, 42); - assert_eq!(unsafe { ptr::raw_const!(x.a).read_unaligned() }, 42); - assert_eq!(unsafe { (&raw const x.b).read_unaligned() }, 99); - assert_eq!(unsafe { ptr::raw_const!(x.b).read_unaligned() }, 99); + assert_eq!(unsafe { ptr::addr_of!(x.a).read_unaligned() }, 42); + assert_eq!(unsafe { ptr::addr_of!(x.b).read_unaligned() }, 99); x.b = 77; assert_eq!({x.b}, 77); diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index 99bd0fb9d805..f76d4e64c6c9 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -1,5 +1,4 @@ // compile-flags: -Zmiri-track-raw-pointers -#![feature(raw_ref_macros)] use std::ptr; // Test various stacked-borrows-related things. @@ -169,8 +168,8 @@ fn raw_ref_to_part() { } let it = Box::new(Whole { part: Part { _lame: 0 }, extra: 42 }); - let whole = ptr::raw_mut!(*Box::leak(it)); - let part = unsafe { ptr::raw_mut!((*whole).part) }; + let whole = ptr::addr_of_mut!(*Box::leak(it)); + let part = unsafe { ptr::addr_of_mut!((*whole).part) }; let typed = unsafe { &mut *(part as *mut Whole) }; assert!(typed.extra == 42); drop(unsafe { Box::from_raw(whole) }); From 052cd3bff7c0008cedb153abc38f12b3938c7f0c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 31 Jan 2021 14:23:49 +0100 Subject: [PATCH 2534/5092] rustup; remove some no-longer-needed Windows shims --- rust-version | 2 +- src/shims/posix/dlsym.rs | 2 ++ src/shims/windows/dlsym.rs | 54 +++--------------------------- src/shims/windows/foreign_items.rs | 6 ---- 4 files changed, 7 insertions(+), 57 deletions(-) diff --git a/rust-version b/rust-version index e9314ffced05..1aa101dca141 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9b3242982202707be2485b1e4cf5f3b34466a38d +0e63af5da3400ace48a0345117980473fd21ad73 diff --git a/src/shims/posix/dlsym.rs b/src/shims/posix/dlsym.rs index e05419f47e93..660c6dc0ebae 100644 --- a/src/shims/posix/dlsym.rs +++ b/src/shims/posix/dlsym.rs @@ -34,7 +34,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + check_abi(abi, Abi::C)?; + match dlsym { Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, ret), Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, args, ret), diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index ce119d1090b1..57766bd344a4 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -1,20 +1,11 @@ use rustc_middle::mir; use rustc_target::spec::abi::Abi; -use log::trace; - use crate::*; -use helpers::{check_abi, check_arg_count}; -use shims::windows::sync::EvalContextExt as _; +use helpers::check_abi; #[derive(Debug, Copy, Clone)] pub enum Dlsym { - AcquireSRWLockExclusive, - ReleaseSRWLockExclusive, - TryAcquireSRWLockExclusive, - AcquireSRWLockShared, - ReleaseSRWLockShared, - TryAcquireSRWLockShared, } impl Dlsym { @@ -22,12 +13,6 @@ impl Dlsym { // should become a NULL pointer (pretend it does not exist). pub fn from_str(name: &str) -> InterpResult<'static, Option> { Ok(match name { - "AcquireSRWLockExclusive" => Some(Dlsym::AcquireSRWLockExclusive), - "ReleaseSRWLockExclusive" => Some(Dlsym::ReleaseSRWLockExclusive), - "TryAcquireSRWLockExclusive" => Some(Dlsym::TryAcquireSRWLockExclusive), - "AcquireSRWLockShared" => Some(Dlsym::AcquireSRWLockShared), - "ReleaseSRWLockShared" => Some(Dlsym::ReleaseSRWLockShared), - "TryAcquireSRWLockShared" => Some(Dlsym::TryAcquireSRWLockShared), "GetSystemTimePreciseAsFileTime" => None, _ => throw_unsup_format!("unsupported Windows dlsym: {}", name), }) @@ -40,46 +25,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, dlsym: Dlsym, abi: Abi, - args: &[OpTy<'tcx, Tag>], + _args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let (dest, ret) = ret.expect("we don't support any diverging dlsym"); + let (_dest, _ret) = ret.expect("we don't support any diverging dlsym"); assert!(this.tcx.sess.target.os == "windows"); check_abi(abi, Abi::System)?; - match dlsym { - Dlsym::AcquireSRWLockExclusive => { - let &[ptr] = check_arg_count(args)?; - this.AcquireSRWLockExclusive(ptr)?; - } - Dlsym::ReleaseSRWLockExclusive => { - let &[ptr] = check_arg_count(args)?; - this.ReleaseSRWLockExclusive(ptr)?; - } - Dlsym::TryAcquireSRWLockExclusive => { - let &[ptr] = check_arg_count(args)?; - let ret = this.TryAcquireSRWLockExclusive(ptr)?; - this.write_scalar(Scalar::from_u8(ret), dest)?; - } - Dlsym::AcquireSRWLockShared => { - let &[ptr] = check_arg_count(args)?; - this.AcquireSRWLockShared(ptr)?; - } - Dlsym::ReleaseSRWLockShared => { - let &[ptr] = check_arg_count(args)?; - this.ReleaseSRWLockShared(ptr)?; - } - Dlsym::TryAcquireSRWLockShared => { - let &[ptr] = check_arg_count(args)?; - let ret = this.TryAcquireSRWLockShared(ptr)?; - this.write_scalar(Scalar::from_u8(ret), dest)?; - } - } - - trace!("{:?}", this.dump_place(*dest)); - this.go_to_block(ret); - Ok(()) + match dlsym {} } } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 52b68b9f1bc3..0eeec08901db 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -300,12 +300,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Just fake a HANDLE this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } - "GetModuleHandleW" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - #[allow(non_snake_case)] - let &[_lpModuleName] = check_arg_count(args)?; - // Pretend this does not exist / nothing happened, by returning zero. - this.write_null(dest)?; - } "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] let &[_hConsoleOutput, _wAttribute] = check_arg_count(args)?; From c5bb29141e6deb4b3eb758da60f5767a662c888b Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 2 Feb 2021 21:40:30 +0100 Subject: [PATCH 2535/5092] Remove unnecessary `format!()` in `panic!()`. --- src/bin/miri.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index bd3bc8dbb412..8256bbd8f847 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -230,10 +230,10 @@ fn main() { err => panic!("unknown error decoding -Zmiri-seed as hex: {:?}", err), }); if seed_raw.len() > 8 { - panic!(format!( + panic!( "-Zmiri-seed must be at most 8 bytes, was {}", seed_raw.len() - )); + ); } let mut bytes = [0; 8]; From d3098043953626e2a2517523788d1949e5b6e80f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Feb 2021 23:37:40 +0100 Subject: [PATCH 2536/5092] rustup --- rust-version | 2 +- tests/compile-fail/erroneous_const.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 1aa101dca141..555bac8c190a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0e63af5da3400ace48a0345117980473fd21ad73 +120b2a704a60d4341286bd82f6e638c65ca169b6 diff --git a/tests/compile-fail/erroneous_const.rs b/tests/compile-fail/erroneous_const.rs index 7f1a81820890..49dcea62a243 100644 --- a/tests/compile-fail/erroneous_const.rs +++ b/tests/compile-fail/erroneous_const.rs @@ -9,6 +9,7 @@ struct PrintName(T); impl PrintName { const VOID: ! = panic!(); //~WARN any use of this value will cause an error + //~^ WARN this was previously accepted } fn no_codegen() { From 7fc24442bd6e35a0d7a7f025da41870506490605 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 5 Feb 2021 10:02:47 +0100 Subject: [PATCH 2537/5092] Update rust version. - Allow new non_fmt_panic lint in test. - Remove stabilized feature(wake_trait). --- rust-version | 2 +- tests/run-pass/async-fn.rs | 1 - tests/run-pass/panic/catch_panic.rs | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 555bac8c190a..3fb38bf7383b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -120b2a704a60d4341286bd82f6e638c65ca169b6 +6a388dcfbb07b3ca3d4ad3fd3902ac7e3b11b5f6 diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index b0a979123343..d03c2cf282b8 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -1,5 +1,4 @@ #![feature(never_type)] -#![feature(wake_trait)] use std::{future::Future, pin::Pin, task::Poll}; use std::task::{Wake, Waker, Context}; diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index 941f79c7ad90..9f9a2b493cef 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -3,7 +3,7 @@ // We test the `align_offset` panic below, make sure we test the interpreter impl and not the "real" one. // compile-flags: -Zmiri-symbolic-alignment-check #![feature(never_type)] -#![allow(unconditional_panic)] +#![allow(unconditional_panic, non_fmt_panic)] use std::panic::{catch_unwind, AssertUnwindSafe}; use std::cell::Cell; From dd81fb3f10f24859442ab9cc7b51d1cd5a31b04d Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Mon, 8 Feb 2021 00:16:22 -0500 Subject: [PATCH 2538/5092] Remove non-power-of-two SIMD vectors --- tests/run-pass/simd-intrinsic-generic-elements.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/run-pass/simd-intrinsic-generic-elements.rs b/tests/run-pass/simd-intrinsic-generic-elements.rs index e8fba6707db1..32de27a96233 100644 --- a/tests/run-pass/simd-intrinsic-generic-elements.rs +++ b/tests/run-pass/simd-intrinsic-generic-elements.rs @@ -7,10 +7,6 @@ struct i32x2(i32, i32); #[repr(simd)] #[derive(Copy, Clone, Debug, PartialEq)] #[allow(non_camel_case_types)] -struct i32x3(i32, i32, i32); -#[repr(simd)] -#[derive(Copy, Clone, Debug, PartialEq)] -#[allow(non_camel_case_types)] struct i32x4(i32, i32, i32, i32); #[repr(simd)] #[derive(Copy, Clone, Debug, PartialEq)] @@ -20,12 +16,10 @@ struct i32x8(i32, i32, i32, i32, fn main() { let _x2 = i32x2(20, 21); - let _x3 = i32x3(30, 31, 32); let _x4 = i32x4(40, 41, 42, 43); let _x8 = i32x8(80, 81, 82, 83, 84, 85, 86, 87); let _y2 = i32x2(120, 121); - let _y3 = i32x3(130, 131, 132); let _y4 = i32x4(140, 141, 142, 143); let _y8 = i32x8(180, 181, 182, 183, 184, 185, 186, 187); From 053124aa52aed422e7928db60817cd3216d9de6f Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Mon, 8 Feb 2021 23:11:33 -0500 Subject: [PATCH 2539/5092] Update rust-version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 3fb38bf7383b..26199e0b483c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6a388dcfbb07b3ca3d4ad3fd3902ac7e3b11b5f6 +bb587b1a1737738658d2eaecd4c8c1cab555257a From b3757d0e514e4bcac5b783daade1bed3c99220bc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 13 Feb 2021 19:39:03 +0100 Subject: [PATCH 2540/5092] add regression test for #1567 --- test-cargo-miri/Cargo.lock | 8 ++++++++ test-cargo-miri/Cargo.toml | 3 ++- test-cargo-miri/issue-1567/Cargo.toml | 13 +++++++++++++ test-cargo-miri/issue-1567/src/lib.rs | 5 +++++ 4 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 test-cargo-miri/issue-1567/Cargo.toml create mode 100644 test-cargo-miri/issue-1567/src/lib.rs diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 8c287098d323..e02439df5d5c 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -11,6 +11,7 @@ name = "cargo-miri-test" version = "0.1.0" dependencies = [ "byteorder", + "issue_1567", "rand", "serde_derive", ] @@ -41,6 +42,13 @@ dependencies = [ "libc", ] +[[package]] +name = "issue_1567" +version = "0.1.0" +dependencies = [ + "byteorder", +] + [[package]] name = "libc" version = "0.2.81" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 54a03f5f5ded..1613f067ed34 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["subcrate"] +members = ["subcrate", "issue-1567"] [package] name = "cargo-miri-test" @@ -9,6 +9,7 @@ edition = "2018" [dependencies] byteorder = "1.0" +issue_1567 = { path ="issue-1567" } [dev-dependencies] rand = { version = "0.7", features = ["small_rng"] } diff --git a/test-cargo-miri/issue-1567/Cargo.toml b/test-cargo-miri/issue-1567/Cargo.toml new file mode 100644 index 000000000000..6a6e09036a01 --- /dev/null +++ b/test-cargo-miri/issue-1567/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "issue_1567" +version = "0.1.0" +authors = ["Miri Team"] +edition = "2018" + +[lib] +# Regression test for https://github.com/rust-lang/miri/issues/1567: crate must have this crate-type set. +# It must also depend on some other crate and use that dependency (we use byteorder). +crate-type = ["cdylib", "rlib"] + +[dependencies] +byteorder = "1.0" diff --git a/test-cargo-miri/issue-1567/src/lib.rs b/test-cargo-miri/issue-1567/src/lib.rs new file mode 100644 index 000000000000..568617c3ba3c --- /dev/null +++ b/test-cargo-miri/issue-1567/src/lib.rs @@ -0,0 +1,5 @@ +use byteorder::{BigEndian, ByteOrder}; + +pub fn use_the_dependency() { + let _n = ::read_u32(&[1,2,3,4]); +} From 80112820fdb887eaff93a811e33e985e0c93c36a Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 14 Feb 2021 02:02:21 +0800 Subject: [PATCH 2541/5092] [cargo-miri] Don't skip `rlib` crates --- cargo-miri/bin.rs | 13 +++++-------- test-cargo-miri/Cargo.lock | 7 +++++++ test-cargo-miri/Cargo.toml | 1 + test-cargo-miri/rlib-dep/Cargo.toml | 8 ++++++++ test-cargo-miri/rlib-dep/src/lib.rs | 3 +++ test-cargo-miri/src/lib.rs | 2 +- 6 files changed, 25 insertions(+), 9 deletions(-) create mode 100644 test-cargo-miri/rlib-dep/Cargo.toml create mode 100644 test-cargo-miri/rlib-dep/src/lib.rs diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 21a6b68c6197..f38e79732b27 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -596,16 +596,13 @@ fn phase_cargo_rustc(args: env::Args) { let target_crate = is_target_crate(); let print = get_arg_flag_value("--print").is_some(); // whether this is cargo passing `--print` to get some infos - // rlib and cdylib are just skipped, we cannot interpret them and do not need them + // cdylib is just skipped, we cannot interpret it and do not need it // for the rest of the build either. - match get_arg_flag_value("--crate-type").as_deref() { - Some("rlib") | Some("cdylib") => { - if verbose { - eprint!("[cargo-miri rustc] (rlib/cdylib skipped)"); - } - return; + if get_arg_flag_value("--crate-type").as_deref() == Some("cdylib") { + if verbose { + eprint!("[cargo-miri rustc] (cdylib skipped)"); } - _ => {}, + return; } let store_json = |info: CrateRunInfo| { diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index e02439df5d5c..84b69f57333e 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "byteorder" version = "1.3.4" @@ -13,6 +15,7 @@ dependencies = [ "byteorder", "issue_1567", "rand", + "rlib-dep", "serde_derive", ] @@ -140,6 +143,10 @@ dependencies = [ "rand_core", ] +[[package]] +name = "rlib-dep" +version = "0.1.0" + [[package]] name = "serde_derive" version = "1.0.118" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 1613f067ed34..ab44f6b304a7 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -9,6 +9,7 @@ edition = "2018" [dependencies] byteorder = "1.0" +rlib-dep.path = "rlib-dep" issue_1567 = { path ="issue-1567" } [dev-dependencies] diff --git a/test-cargo-miri/rlib-dep/Cargo.toml b/test-cargo-miri/rlib-dep/Cargo.toml new file mode 100644 index 000000000000..c12653e9c839 --- /dev/null +++ b/test-cargo-miri/rlib-dep/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "rlib-dep" +version = "0.1.0" +authors = ["Miri Team"] +edition = "2018" + +[lib] +crate-type = ["rlib"] diff --git a/test-cargo-miri/rlib-dep/src/lib.rs b/test-cargo-miri/rlib-dep/src/lib.rs new file mode 100644 index 000000000000..efde2b58e199 --- /dev/null +++ b/test-cargo-miri/rlib-dep/src/lib.rs @@ -0,0 +1,3 @@ +pub fn use_me() -> bool { + true +} diff --git a/test-cargo-miri/src/lib.rs b/test-cargo-miri/src/lib.rs index 4e2c8b572c77..46d76bce1277 100644 --- a/test-cargo-miri/src/lib.rs +++ b/test-cargo-miri/src/lib.rs @@ -3,5 +3,5 @@ /// assert!(cargo_miri_test::make_true()); /// ``` pub fn make_true() -> bool { - true + rlib_dep::use_me() } From 304cd3e4104551b990644265caf2954908679cd5 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 14 Feb 2021 19:08:47 +0800 Subject: [PATCH 2542/5092] Make the test more consistent with other tests --- test-cargo-miri/Cargo.lock | 10 +++++----- test-cargo-miri/Cargo.toml | 4 ++-- test-cargo-miri/{rlib-dep => issue-1691}/Cargo.toml | 2 +- test-cargo-miri/{rlib-dep => issue-1691}/src/lib.rs | 0 test-cargo-miri/src/lib.rs | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) rename test-cargo-miri/{rlib-dep => issue-1691}/Cargo.toml (83%) rename test-cargo-miri/{rlib-dep => issue-1691}/src/lib.rs (100%) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 84b69f57333e..63e03b37cca5 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -14,8 +14,8 @@ version = "0.1.0" dependencies = [ "byteorder", "issue_1567", + "issue_1691", "rand", - "rlib-dep", "serde_derive", ] @@ -52,6 +52,10 @@ dependencies = [ "byteorder", ] +[[package]] +name = "issue_1691" +version = "0.1.0" + [[package]] name = "libc" version = "0.2.81" @@ -143,10 +147,6 @@ dependencies = [ "rand_core", ] -[[package]] -name = "rlib-dep" -version = "0.1.0" - [[package]] name = "serde_derive" version = "1.0.118" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index ab44f6b304a7..c42d6753e8e0 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -9,8 +9,8 @@ edition = "2018" [dependencies] byteorder = "1.0" -rlib-dep.path = "rlib-dep" -issue_1567 = { path ="issue-1567" } +issue_1567 = { path = "issue-1567" } +issue_1691 = { path = "issue-1691" } [dev-dependencies] rand = { version = "0.7", features = ["small_rng"] } diff --git a/test-cargo-miri/rlib-dep/Cargo.toml b/test-cargo-miri/issue-1691/Cargo.toml similarity index 83% rename from test-cargo-miri/rlib-dep/Cargo.toml rename to test-cargo-miri/issue-1691/Cargo.toml index c12653e9c839..3100cc6a60b5 100644 --- a/test-cargo-miri/rlib-dep/Cargo.toml +++ b/test-cargo-miri/issue-1691/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "rlib-dep" +name = "issue_1691" version = "0.1.0" authors = ["Miri Team"] edition = "2018" diff --git a/test-cargo-miri/rlib-dep/src/lib.rs b/test-cargo-miri/issue-1691/src/lib.rs similarity index 100% rename from test-cargo-miri/rlib-dep/src/lib.rs rename to test-cargo-miri/issue-1691/src/lib.rs diff --git a/test-cargo-miri/src/lib.rs b/test-cargo-miri/src/lib.rs index 46d76bce1277..b50dfbe51eb3 100644 --- a/test-cargo-miri/src/lib.rs +++ b/test-cargo-miri/src/lib.rs @@ -3,5 +3,5 @@ /// assert!(cargo_miri_test::make_true()); /// ``` pub fn make_true() -> bool { - rlib_dep::use_me() + issue_1691::use_me() } From 0737de86f760a35408088f19c45c0617ffed21d0 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 14 Feb 2021 19:09:22 +0800 Subject: [PATCH 2543/5092] Revert the lock file version change --- test-cargo-miri/Cargo.lock | 2 -- 1 file changed, 2 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 63e03b37cca5..a3a708c6b544 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -1,7 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 - [[package]] name = "byteorder" version = "1.3.4" From 56250ccbf20babae5b110ddae60598defdd1e328 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Mon, 15 Feb 2021 00:52:18 +0800 Subject: [PATCH 2544/5092] Extract `--extern` filenames patching code to `forward_patched_extern_arg()` Co-authored-by: Tristan Dannenberg --- cargo-miri/bin.rs | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index f38e79732b27..7edd46c24ba4 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -143,6 +143,18 @@ fn get_arg_flag_value(name: &str) -> Option { ArgFlagValueIter::new(name).next() } +fn forward_patched_extern_arg(args: &mut impl Iterator, cmd: &mut Command) { + cmd.arg("--extern"); // always forward flag, but adjust filename: + let path = args.next().expect("`--extern` should be followed by a filename"); + if let Some(lib) = path.strip_suffix(".rlib") { + // If this is an rlib, make it an rmeta. + cmd.arg(format!("{}.rmeta", lib)); + } else { + // Some other extern file (e.g. a `.so`). Forward unchanged. + cmd.arg(path); + } +} + /// Returns the path to the `miri` binary fn find_miri() -> PathBuf { if let Some(path) = env::var_os("MIRI") { @@ -734,21 +746,11 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { // but when we run here, cargo does not interpret the JSON any more. `--json` // then also nees to be dropped. let mut args = info.args.into_iter(); - let extern_flag = "--extern"; let error_format_flag = "--error-format"; let json_flag = "--json"; while let Some(arg) = args.next() { - if arg == extern_flag { - cmd.arg(extern_flag); // always forward flag, but adjust filename - // `--extern` is always passed as a separate argument by cargo. - let next_arg = args.next().expect("`--extern` should be followed by a filename"); - if let Some(next_lib) = next_arg.strip_suffix(".rlib") { - // If this is an rlib, make it an rmeta. - cmd.arg(format!("{}.rmeta", next_lib)); - } else { - // Some other extern file (e.g., a `.so`). Forward unchanged. - cmd.arg(next_arg); - } + if arg == "--extern" { + forward_patched_extern_arg(&mut args, &mut cmd); } else if arg.starts_with(error_format_flag) { let suffix = &arg[error_format_flag.len()..]; assert!(suffix.starts_with('=')); From c0eb13ba2af21239617fb7b7a8ad7f129656812a Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 14 Feb 2021 18:12:33 +0800 Subject: [PATCH 2545/5092] Patch `--extern` arguments in `phase_cargo_rustc` as well --- cargo-miri/bin.rs | 8 ++++++-- test-cargo-miri/Cargo.lock | 8 ++++++++ test-cargo-miri/Cargo.toml | 1 + test-cargo-miri/issue-1705/Cargo.toml | 11 +++++++++++ test-cargo-miri/issue-1705/src/lib.rs | 5 +++++ test-cargo-miri/src/lib.rs | 1 + 6 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 test-cargo-miri/issue-1705/Cargo.toml create mode 100644 test-cargo-miri/issue-1705/src/lib.rs diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 7edd46c24ba4..77ccaea4bf69 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -565,7 +565,7 @@ fn phase_cargo_miri(mut args: env::Args) { exec(cmd) } -fn phase_cargo_rustc(args: env::Args) { +fn phase_cargo_rustc(mut args: env::Args) { /// Determines if we are being invoked (as rustc) to build a crate for /// the "target" architecture, in contrast to the "host" architecture. /// Host crates are for build scripts and proc macros and still need to @@ -655,7 +655,7 @@ fn phase_cargo_rustc(args: env::Args) { if !print && target_crate { // Forward arguments, but remove "link" from "--emit" to make this a check-only build. let emit_flag = "--emit"; - for arg in args { + while let Some(arg) = args.next() { if arg.starts_with(emit_flag) { // Patch this argument. First, extract its value. let val = &arg[emit_flag.len()..]; @@ -671,6 +671,10 @@ fn phase_cargo_rustc(args: env::Args) { } } cmd.arg(format!("{}={}", emit_flag, val.join(","))); + } else if arg == "--extern" { + // Patch `--extern` filenames, since Cargo sometimes passes stub `.rlib` files: + // https://github.com/rust-lang/miri/issues/1705 + forward_patched_extern_arg(&mut args, &mut cmd); } else { cmd.arg(arg); } diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index a3a708c6b544..eff36026defe 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -13,6 +13,7 @@ dependencies = [ "byteorder", "issue_1567", "issue_1691", + "issue_1705", "rand", "serde_derive", ] @@ -54,6 +55,13 @@ dependencies = [ name = "issue_1691" version = "0.1.0" +[[package]] +name = "issue_1705" +version = "0.1.0" +dependencies = [ + "byteorder", +] + [[package]] name = "libc" version = "0.2.81" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index c42d6753e8e0..4bc5d121ac79 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -11,6 +11,7 @@ edition = "2018" byteorder = "1.0" issue_1567 = { path = "issue-1567" } issue_1691 = { path = "issue-1691" } +issue_1705 = { path = "issue-1705" } [dev-dependencies] rand = { version = "0.7", features = ["small_rng"] } diff --git a/test-cargo-miri/issue-1705/Cargo.toml b/test-cargo-miri/issue-1705/Cargo.toml new file mode 100644 index 000000000000..ae63647a8881 --- /dev/null +++ b/test-cargo-miri/issue-1705/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "issue_1705" +version = "0.1.0" +authors = ["Miri Team"] +edition = "2018" + +[lib] +crate-type = ["lib", "staticlib", "cdylib"] + +[dependencies] +byteorder = "1.0" diff --git a/test-cargo-miri/issue-1705/src/lib.rs b/test-cargo-miri/issue-1705/src/lib.rs new file mode 100644 index 000000000000..ef24d3f1a06d --- /dev/null +++ b/test-cargo-miri/issue-1705/src/lib.rs @@ -0,0 +1,5 @@ +use byteorder::{LittleEndian, ByteOrder}; + +pub fn use_the_dependency() { + let _n = ::read_u32(&[1,2,3,4]); +} diff --git a/test-cargo-miri/src/lib.rs b/test-cargo-miri/src/lib.rs index b50dfbe51eb3..1da169bd51cf 100644 --- a/test-cargo-miri/src/lib.rs +++ b/test-cargo-miri/src/lib.rs @@ -3,5 +3,6 @@ /// assert!(cargo_miri_test::make_true()); /// ``` pub fn make_true() -> bool { + issue_1705::use_the_dependency(); issue_1691::use_me() } From eec5423aa738b55e4541324ad490507e30d2cf38 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 14 Feb 2021 21:57:31 +0800 Subject: [PATCH 2546/5092] Stop skipping `cdylib` --- cargo-miri/bin.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 77ccaea4bf69..cb003c0f3e8b 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -608,15 +608,6 @@ fn phase_cargo_rustc(mut args: env::Args) { let target_crate = is_target_crate(); let print = get_arg_flag_value("--print").is_some(); // whether this is cargo passing `--print` to get some infos - // cdylib is just skipped, we cannot interpret it and do not need it - // for the rest of the build either. - if get_arg_flag_value("--crate-type").as_deref() == Some("cdylib") { - if verbose { - eprint!("[cargo-miri rustc] (cdylib skipped)"); - } - return; - } - let store_json = |info: CrateRunInfo| { let filename = out_filename("", ""); if verbose { From 51c6f51c36b95420d9748b0d9d372ccbbaafc93d Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 14 Feb 2021 22:38:56 +0800 Subject: [PATCH 2547/5092] Use the `issue-1567` dependency in the test --- test-cargo-miri/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/test-cargo-miri/src/lib.rs b/test-cargo-miri/src/lib.rs index 1da169bd51cf..33bbd8c966e5 100644 --- a/test-cargo-miri/src/lib.rs +++ b/test-cargo-miri/src/lib.rs @@ -3,6 +3,7 @@ /// assert!(cargo_miri_test::make_true()); /// ``` pub fn make_true() -> bool { + issue_1567::use_the_dependency(); issue_1705::use_the_dependency(); issue_1691::use_me() } From 1923044705b2e9d54f7fa8f40e1c0bab5ea081ff Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 14 Feb 2021 23:33:24 +0800 Subject: [PATCH 2548/5092] Add a `cdylib`-only crate test --- test-cargo-miri/Cargo.lock | 8 ++++++++ test-cargo-miri/Cargo.toml | 1 + test-cargo-miri/cdylib/Cargo.toml | 12 ++++++++++++ test-cargo-miri/cdylib/src/lib.rs | 6 ++++++ 4 files changed, 27 insertions(+) create mode 100644 test-cargo-miri/cdylib/Cargo.toml create mode 100644 test-cargo-miri/cdylib/src/lib.rs diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index eff36026defe..1f1541b92a56 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -11,6 +11,7 @@ name = "cargo-miri-test" version = "0.1.0" dependencies = [ "byteorder", + "cdylib", "issue_1567", "issue_1691", "issue_1705", @@ -18,6 +19,13 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "cdylib" +version = "0.1.0" +dependencies = [ + "byteorder", +] + [[package]] name = "cfg-if" version = "0.1.10" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 4bc5d121ac79..7ffe7d04ea47 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -9,6 +9,7 @@ edition = "2018" [dependencies] byteorder = "1.0" +cdylib = { path = "cdylib" } issue_1567 = { path = "issue-1567" } issue_1691 = { path = "issue-1691" } issue_1705 = { path = "issue-1705" } diff --git a/test-cargo-miri/cdylib/Cargo.toml b/test-cargo-miri/cdylib/Cargo.toml new file mode 100644 index 000000000000..4e5b5601a56c --- /dev/null +++ b/test-cargo-miri/cdylib/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "cdylib" +version = "0.1.0" +authors = ["Miri Team"] +edition = "2018" + +[lib] +# cargo-miri used to handle `cdylib` crate-type specially (https://github.com/rust-lang/miri/pull/1577). +crate-type = ["cdylib"] + +[dependencies] +byteorder = "1.0" diff --git a/test-cargo-miri/cdylib/src/lib.rs b/test-cargo-miri/cdylib/src/lib.rs new file mode 100644 index 000000000000..dd89048284de --- /dev/null +++ b/test-cargo-miri/cdylib/src/lib.rs @@ -0,0 +1,6 @@ +use byteorder::{BigEndian, ByteOrder}; + +#[no_mangle] +extern "C" fn use_the_dependency() { + let _n = ::read_u64(&[1,2,3,4,5,6,7,8]); +} From 0b3dba8e702fa7f4a0135098dfe77c98db45490a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Feb 2021 09:51:53 +0100 Subject: [PATCH 2549/5092] rustup and temporarily disable broken tests --- rust-version | 2 +- tests/compile-fail/validity/execute_memory.rs | 1 + tests/compile-fail/validity/invalid_fnptr_uninit.rs | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 26199e0b483c..0c82a59c6d1d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -bb587b1a1737738658d2eaecd4c8c1cab555257a +42a4673fbd40b09a99d057eaa9b3e5579b54c184 diff --git a/tests/compile-fail/validity/execute_memory.rs b/tests/compile-fail/validity/execute_memory.rs index 5230e7fdf529..4be80fe39d01 100644 --- a/tests/compile-fail/validity/execute_memory.rs +++ b/tests/compile-fail/validity/execute_memory.rs @@ -1,3 +1,4 @@ +// ignore-test FIXME (Miri issue #1711) #![feature(box_syntax)] fn main() { diff --git a/tests/compile-fail/validity/invalid_fnptr_uninit.rs b/tests/compile-fail/validity/invalid_fnptr_uninit.rs index dbd6711dc65a..ab0e870b420b 100644 --- a/tests/compile-fail/validity/invalid_fnptr_uninit.rs +++ b/tests/compile-fail/validity/invalid_fnptr_uninit.rs @@ -1,3 +1,4 @@ +// ignore-test FIXME (Miri issue #1711) #![allow(invalid_value)] union MyUninit { From 4c867feeb637e0172f4c72a3732f9beb5e4f922d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Feb 2021 09:55:44 +0100 Subject: [PATCH 2550/5092] add test by @eddyb --- .../branchless-select-i128-pointer.rs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/compile-fail/branchless-select-i128-pointer.rs diff --git a/tests/compile-fail/branchless-select-i128-pointer.rs b/tests/compile-fail/branchless-select-i128-pointer.rs new file mode 100644 index 000000000000..61fd57f8f050 --- /dev/null +++ b/tests/compile-fail/branchless-select-i128-pointer.rs @@ -0,0 +1,20 @@ +use std::mem::transmute; + +#[cfg(target_pointer_width = "32")] +type TwoPtrs = i64; +#[cfg(target_pointer_width = "64")] +type TwoPtrs = i128; + +fn main() { + for &my_bool in &[true, false] { + let mask = -(my_bool as TwoPtrs); // false -> 0, true -> -1 aka !0 + // This is branchless code to select one or the other pointer. + // For now, Miri brafs on it, but if this code ever passes we better make sure it behaves correctly. + let val = unsafe { + transmute::<_, &str>( + !mask & transmute::<_, TwoPtrs>("false !") | mask & transmute::<_, TwoPtrs>("true !"), //~ERROR encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes + ) + }; + println!("{}", val); + } +} From a5a751e7957e043faa1a8c080a1c51dee712faae Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Feb 2021 09:37:21 +0100 Subject: [PATCH 2551/5092] rustup --- rust-version | 2 +- tests/compile-fail/validity/execute_memory.rs | 1 - tests/compile-fail/validity/invalid_fnptr_uninit.rs | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 0c82a59c6d1d..208d29f79704 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -42a4673fbd40b09a99d057eaa9b3e5579b54c184 +a143517d44cac50b20cbd3a0b579addab40dd399 diff --git a/tests/compile-fail/validity/execute_memory.rs b/tests/compile-fail/validity/execute_memory.rs index 4be80fe39d01..5230e7fdf529 100644 --- a/tests/compile-fail/validity/execute_memory.rs +++ b/tests/compile-fail/validity/execute_memory.rs @@ -1,4 +1,3 @@ -// ignore-test FIXME (Miri issue #1711) #![feature(box_syntax)] fn main() { diff --git a/tests/compile-fail/validity/invalid_fnptr_uninit.rs b/tests/compile-fail/validity/invalid_fnptr_uninit.rs index ab0e870b420b..dbd6711dc65a 100644 --- a/tests/compile-fail/validity/invalid_fnptr_uninit.rs +++ b/tests/compile-fail/validity/invalid_fnptr_uninit.rs @@ -1,4 +1,3 @@ -// ignore-test FIXME (Miri issue #1711) #![allow(invalid_value)] union MyUninit { From 2672baafe1d52cdcb0b7b84f77c9950771be7332 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Feb 2021 10:34:32 +0100 Subject: [PATCH 2552/5092] rustup --- rust-version | 2 +- src/diagnostics.rs | 10 +++++----- src/eval.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rust-version b/rust-version index 208d29f79704..189317a54a35 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a143517d44cac50b20cbd3a0b579addab40dd399 +d1462d8558cf4551608457f63d9b999185ebf3bf diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 3f1f67218fdb..45c0996355bf 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -54,7 +54,7 @@ pub fn report_error<'tcx, 'mir>( ) -> Option { use InterpError::*; - let (title, helps) = match &e.kind { + let (title, helps) = match &e.kind() { MachineStop(info) => { let info = info.downcast_ref::().expect("invalid MachineStop payload"); use TerminationInfo::*; @@ -81,7 +81,7 @@ pub fn report_error<'tcx, 'mir>( (title, helps) } _ => { - let title = match e.kind { + let title = match e.kind() { Unsupported(_) => "unsupported operation", UndefinedBehavior(_) => @@ -93,11 +93,11 @@ pub fn report_error<'tcx, 'mir>( _ => bug!("This error should be impossible in Miri: {}", e), }; - let helps = match e.kind { + let helps = match e.kind() { Unsupported(UnsupportedOpInfo::NoMirFor(..)) => vec![format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`")], Unsupported(UnsupportedOpInfo::ReadBytesAsPointer | UnsupportedOpInfo::ThreadLocalStatic(_) | UnsupportedOpInfo::ReadExternStatic(_)) => - panic!("Error should never be raised by Miri: {:?}", e.kind), + panic!("Error should never be raised by Miri: {:?}", e.kind()), Unsupported(_) => vec![format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support")], UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. }) @@ -133,7 +133,7 @@ pub fn report_error<'tcx, 'mir>( } // Extra output to help debug specific issues. - match e.kind { + match e.kind() { UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some(access))) => { eprintln!( "Uninitialized read occurred at offsets 0x{:x}..0x{:x} into this allocation:", diff --git a/src/eval.rs b/src/eval.rs index b6d4fa05e1e5..16fe5d5f20a1 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -208,7 +208,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Ok(v) => v, Err(err) => { err.print_backtrace(); - panic!("Miri initialization error: {}", err.kind) + panic!("Miri initialization error: {}", err.kind()) } }; From 0eb341417cc2261a664a83f26b6c04bf1e16e295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Sat, 20 Feb 2021 00:00:00 +0000 Subject: [PATCH 2553/5092] rustup to e7c23ab933ebc1f205c3b59f4ebc85d40f67d404 --- rust-version | 2 +- src/data_race.rs | 52 +++++------ src/eval.rs | 16 ++-- src/helpers.rs | 50 +++++----- src/machine.rs | 18 ++-- src/operator.rs | 10 +- src/shims/backtrace.rs | 22 ++--- src/shims/dlsym.rs | 2 +- src/shims/env.rs | 46 ++++----- src/shims/foreign_items.rs | 46 ++++----- src/shims/intrinsics.rs | 84 ++++++++--------- src/shims/mod.rs | 12 +-- src/shims/panic.rs | 18 ++-- src/shims/posix/dlsym.rs | 2 +- src/shims/posix/foreign_items.rs | 118 +++++++++++------------ src/shims/posix/fs.rs | 124 ++++++++++++------------- src/shims/posix/linux/dlsym.rs | 2 +- src/shims/posix/linux/foreign_items.rs | 48 +++++----- src/shims/posix/linux/sync.rs | 15 +-- src/shims/posix/macos/dlsym.rs | 6 +- src/shims/posix/macos/foreign_items.rs | 30 +++--- src/shims/posix/sync.rs | 106 ++++++++++----------- src/shims/posix/thread.rs | 30 +++--- src/shims/time.rs | 32 +++---- src/shims/tls.rs | 6 +- src/shims/windows/dlsym.rs | 2 +- src/shims/windows/foreign_items.rs | 72 +++++++------- src/shims/windows/sync.rs | 14 +-- src/stacked_borrows.rs | 22 ++--- 29 files changed, 505 insertions(+), 502 deletions(-) diff --git a/rust-version b/rust-version index 189317a54a35..6c6212ec839c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d1462d8558cf4551608457f63d9b999185ebf3bf +e7c23ab933ebc1f205c3b59f4ebc85d40f67d404 diff --git a/src/data_race.rs b/src/data_race.rs index f79775e12fe7..dcff896c1f16 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -446,7 +446,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// Atomic variant of read_scalar_at_offset. fn read_scalar_at_offset_atomic( &self, - op: OpTy<'tcx, Tag>, + op: &OpTy<'tcx, Tag>, offset: u64, layout: TyAndLayout<'tcx>, atomic: AtomicReadOp, @@ -458,13 +458,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // Ensure that the following read at an offset is within bounds. assert!(op_place.layout.size >= offset + layout.size); let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; - this.read_scalar_atomic(value_place, atomic) + this.read_scalar_atomic(&value_place, atomic) } /// Atomic variant of write_scalar_at_offset. fn write_scalar_at_offset_atomic( &mut self, - op: OpTy<'tcx, Tag>, + op: &OpTy<'tcx, Tag>, offset: u64, value: impl Into>, layout: TyAndLayout<'tcx>, @@ -477,17 +477,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // Ensure that the following read at an offset is within bounds. assert!(op_place.layout.size >= offset + layout.size); let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; - this.write_scalar_atomic(value.into(), value_place, atomic) + this.write_scalar_atomic(value.into(), &value_place, atomic) } /// Perform an atomic read operation at the memory location. fn read_scalar_atomic( &self, - place: MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Tag>, atomic: AtomicReadOp, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_ref(); - let scalar = this.allow_data_races_ref(move |this| this.read_scalar(place.into()))?; + let scalar = this.allow_data_races_ref(move |this| this.read_scalar(&place.into()))?; self.validate_atomic_load(place, atomic)?; Ok(scalar) } @@ -496,31 +496,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { fn write_scalar_atomic( &mut self, val: ScalarMaybeUninit, - dest: MPlaceTy<'tcx, Tag>, + dest: &MPlaceTy<'tcx, Tag>, atomic: AtomicWriteOp, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.allow_data_races_mut(move |this| this.write_scalar(val, dest.into()))?; + this.allow_data_races_mut(move |this| this.write_scalar(val, &(*dest).into()))?; self.validate_atomic_store(dest, atomic) } /// Perform a atomic operation on a memory location. fn atomic_op_immediate( &mut self, - place: MPlaceTy<'tcx, Tag>, - rhs: ImmTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Tag>, + rhs: &ImmTy<'tcx, Tag>, op: mir::BinOp, neg: bool, atomic: AtomicRwOp, ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let this = self.eval_context_mut(); - let old = this.allow_data_races_mut(|this| this.read_immediate(place.into()))?; + let old = this.allow_data_races_mut(|this| this.read_immediate(&place.into()))?; // Atomics wrap around on overflow. - let val = this.binary_op(op, old, rhs)?; - let val = if neg { this.unary_op(mir::UnOp::Not, val)? } else { val }; - this.allow_data_races_mut(|this| this.write_immediate(*val, place.into()))?; + let val = this.binary_op(op, &old, rhs)?; + let val = if neg { this.unary_op(mir::UnOp::Not, &val)? } else { val }; + this.allow_data_races_mut(|this| this.write_immediate(*val, &(*place).into()))?; this.validate_atomic_rmw(place, atomic)?; Ok(old) @@ -530,14 +530,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// scalar value, the old value is returned. fn atomic_exchange_scalar( &mut self, - place: MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Tag>, new: ScalarMaybeUninit, atomic: AtomicRwOp, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_mut(); - let old = this.allow_data_races_mut(|this| this.read_scalar(place.into()))?; - this.allow_data_races_mut(|this| this.write_scalar(new, place.into()))?; + let old = this.allow_data_races_mut(|this| this.read_scalar(&place.into()))?; + this.allow_data_races_mut(|this| this.write_scalar(new, &(*place).into()))?; this.validate_atomic_rmw(place, atomic)?; Ok(old) } @@ -550,8 +550,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// identical. fn atomic_compare_exchange_scalar( &mut self, - place: MPlaceTy<'tcx, Tag>, - expect_old: ImmTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Tag>, + expect_old: &ImmTy<'tcx, Tag>, new: ScalarMaybeUninit, success: AtomicRwOp, fail: AtomicReadOp, @@ -564,9 +564,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // to read with the failure ordering and if successful then try again with the success // read ordering and write in the success case. // Read as immediate for the sake of `binary_op()` - let old = this.allow_data_races_mut(|this| this.read_immediate(place.into()))?; + let old = this.allow_data_races_mut(|this| this.read_immediate(&(place.into())))?; // `binary_op` will bail if either of them is not a scalar. - let eq = this.overflowing_binary_op(mir::BinOp::Eq, old, expect_old)?.0; + let eq = this.overflowing_binary_op(mir::BinOp::Eq, &old, expect_old)?.0; // If the operation would succeed, but is "weak", fail some portion // of the time, based on `rate`. let rate = this.memory.extra.cmpxchg_weak_failure_rate; @@ -581,7 +581,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // if successful, perform a full rw-atomic validation // otherwise treat this as an atomic load with the fail ordering. if cmpxchg_success { - this.allow_data_races_mut(|this| this.write_scalar(new, place.into()))?; + this.allow_data_races_mut(|this| this.write_scalar(new, &(*place).into()))?; this.validate_atomic_rmw(place, success)?; } else { this.validate_atomic_load(place, fail)?; @@ -595,7 +595,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// associated memory-place and on the current thread. fn validate_atomic_load( &self, - place: MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Tag>, atomic: AtomicReadOp, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); @@ -617,7 +617,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// associated memory-place and on the current thread. fn validate_atomic_store( &mut self, - place: MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Tag>, atomic: AtomicWriteOp, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); @@ -639,7 +639,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// at the associated memory place and on the current thread. fn validate_atomic_rmw( &mut self, - place: MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Tag>, atomic: AtomicRwOp, ) -> InterpResult<'tcx> { use AtomicRwOp::*; @@ -973,7 +973,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// atomic-stores/atomic-rmw? fn validate_atomic_op( &self, - place: MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Tag>, atomic: A, description: &str, mut op: impl FnMut( diff --git a/src/eval.rs b/src/eval.rs index 16fe5d5f20a1..7a29d91d2d8e 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -138,8 +138,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ecx.layout_of(tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), u64::try_from(argvs.len()).unwrap()))?; let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into()); for (idx, arg) in argvs.into_iter().enumerate() { - let place = ecx.mplace_field(argvs_place, idx)?; - ecx.write_scalar(arg, place.into())?; + let place = ecx.mplace_field(&argvs_place, idx)?; + ecx.write_scalar(arg, &place.into())?; } ecx.memory.mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?; // A pointer to that place is the 3rd argument for main. @@ -148,14 +148,14 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( { let argc_place = ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into()); - ecx.write_scalar(argc, argc_place.into())?; + ecx.write_scalar(argc, &argc_place.into())?; ecx.machine.argc = Some(argc_place.ptr); let argv_place = ecx.allocate( ecx.layout_of(tcx.mk_imm_ptr(tcx.types.unit))?, MiriMemoryKind::Machine.into(), ); - ecx.write_scalar(argv, argv_place.into())?; + ecx.write_scalar(argv, &argv_place.into())?; ecx.machine.argv = Some(argv_place.ptr); } // Store command line as UTF-16 for Windows `GetCommandLineW`. @@ -177,8 +177,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ecx.machine.cmd_line = Some(cmd_place.ptr); // Store the UTF-16 string. We just allocated so we know the bounds are fine. for (idx, &c) in cmd_utf16.iter().enumerate() { - let place = ecx.mplace_field(cmd_place, idx)?; - ecx.write_scalar(Scalar::from_u16(c), place.into())?; + let place = ecx.mplace_field(&cmd_place, idx)?; + ecx.write_scalar(Scalar::from_u16(c), &place.into())?; } } argv @@ -190,7 +190,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ecx.call_function( start_instance, &[main_ptr.into(), argc.into(), argv.into()], - Some(ret_place.into()), + Some(&ret_place.into()), StackPopCleanup::None { cleanup: true }, )?; @@ -239,7 +239,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> } ecx.process_diagnostics(info); } - let return_code = ecx.read_scalar(ret_place.into())?.check_init()?.to_machine_isize(&ecx)?; + let return_code = ecx.read_scalar(&ret_place.into())?.check_init()?.to_machine_isize(&ecx)?; Ok(return_code) })(); diff --git a/src/helpers.rs b/src/helpers.rs index 6a12a8f6ba35..2baaebb0ae20 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -61,7 +61,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let instance = this.resolve_path(path); let cid = GlobalId { instance, promoted: None }; let const_val = this.eval_to_allocation(cid)?; - let const_val = this.read_scalar(const_val.into())?; + let const_val = this.read_scalar(&const_val.into())?; return Ok(const_val); } @@ -106,7 +106,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Write a 0 of the appropriate size to `dest`. - fn write_null(&mut self, dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn write_null(&mut self, dest: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest) } @@ -162,7 +162,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, f: ty::Instance<'tcx>, args: &[Immediate], - dest: Option>, + dest: Option<&PlaceTy<'tcx, Tag>>, stack_pop: StackPopCleanup, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -177,7 +177,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let callee_arg = this.local_place( callee_args.next().expect("callee has fewer arguments than expected"), )?; - this.write_immediate(*arg, callee_arg)?; + this.write_immediate(*arg, &callee_arg)?; } callee_args.next().expect_none("callee has more arguments than expected"); @@ -188,7 +188,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// will be true if this is frozen, false if this is in an `UnsafeCell`. fn visit_freeze_sensitive( &self, - place: MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Tag>, size: Size, mut action: impl FnMut(Pointer, Size, bool) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { @@ -237,7 +237,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("unsafe_cell_action on {:?}", place.ptr); // We need a size to go on. let unsafe_cell_size = this - .size_and_align_of_mplace(place)? + .size_and_align_of_mplace(&place)? .map(|(size, _)| size) // for extern types, just cover what we can .unwrap_or_else(|| place.layout.size); @@ -261,7 +261,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// whether we are inside an `UnsafeCell` or not. struct UnsafeCellVisitor<'ecx, 'mir, 'tcx, F> where - F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>, + F: FnMut(&MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>, { ecx: &'ecx MiriEvalContext<'mir, 'tcx>, unsafe_cell_action: F, @@ -270,7 +270,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx impl<'ecx, 'mir, 'tcx: 'mir, F> ValueVisitor<'mir, 'tcx, Evaluator<'mir, 'tcx>> for UnsafeCellVisitor<'ecx, 'mir, 'tcx, F> where - F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>, + F: FnMut(&MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>, { type V = MPlaceTy<'tcx, Tag>; @@ -280,7 +280,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Hook to detect `UnsafeCell`. - fn visit_value(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn visit_value(&mut self, v: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty); let is_unsafe_cell = match v.layout.ty.kind() { ty::Adt(adt, _) => @@ -323,7 +323,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Make sure we visit aggregrates in increasing offset order. fn visit_aggregate( &mut self, - place: MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Tag>, fields: impl Iterator>>, ) -> InterpResult<'tcx> { match place.layout.fields { @@ -346,7 +346,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn visit_union(&mut self, _v: MPlaceTy<'tcx, Tag>, _fields: NonZeroUsize) -> InterpResult<'tcx> { + fn visit_union(&mut self, _v: &MPlaceTy<'tcx, Tag>, _fields: NonZeroUsize) -> InterpResult<'tcx> { bug!("we should have already handled unions in `visit_value`") } } @@ -356,7 +356,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // different values into a struct. fn write_packed_immediates( &mut self, - place: MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Tag>, imms: &[ImmTy<'tcx, Tag>], ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -366,7 +366,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx for &imm in imms { this.write_immediate_to_mplace( *imm, - place.offset(offset, MemPlaceMeta::None, imm.layout, &*this.tcx)?, + &place.offset(offset, MemPlaceMeta::None, imm.layout, &*this.tcx)?, )?; offset += imm.layout.size; } @@ -406,7 +406,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Allocate new place, set initial value to 0. let errno_layout = this.machine.layouts.u32; let errno_place = this.allocate(errno_layout, MiriMemoryKind::Machine.into()); - this.write_scalar(Scalar::from_u32(0), errno_place.into())?; + this.write_scalar(Scalar::from_u32(0), &errno_place.into())?; this.active_thread_mut().last_error = Some(errno_place); Ok(errno_place) } @@ -416,14 +416,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let errno_place = this.last_error_place()?; - this.write_scalar(scalar, errno_place.into()) + this.write_scalar(scalar, &errno_place.into()) } /// Gets the last error variable. fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let errno_place = this.last_error_place()?; - this.read_scalar(errno_place.into())?.check_init() + this.read_scalar(&errno_place.into())?.check_init() } /// Sets the last OS error using a `std::io::Error`. This function tries to produce the most @@ -486,7 +486,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn read_scalar_at_offset( &self, - op: OpTy<'tcx, Tag>, + op: &OpTy<'tcx, Tag>, offset: u64, layout: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { @@ -496,12 +496,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Ensure that the following read at an offset is within bounds assert!(op_place.layout.size >= offset + layout.size); let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; - this.read_scalar(value_place.into()) + this.read_scalar(&value_place.into()) } fn write_scalar_at_offset( &mut self, - op: OpTy<'tcx, Tag>, + op: &OpTy<'tcx, Tag>, offset: u64, value: impl Into>, layout: TyAndLayout<'tcx>, @@ -512,7 +512,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Ensure that the following read at an offset is within bounds assert!(op_place.layout.size >= offset + layout.size); let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; - this.write_scalar(value, value_place.into()) + this.write_scalar(value, &value_place.into()) } /// Parse a `timespec` struct and return it as a `std::time::Duration`. It returns `None` @@ -520,15 +520,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// `EINVAL` in this case. fn read_timespec( &mut self, - timespec_ptr_op: OpTy<'tcx, Tag>, + timespec_ptr_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); let tp = this.deref_operand(timespec_ptr_op)?; - let seconds_place = this.mplace_field(tp, 0)?; - let seconds_scalar = this.read_scalar(seconds_place.into())?; + let seconds_place = this.mplace_field(&tp, 0)?; + let seconds_scalar = this.read_scalar(&seconds_place.into())?; let seconds = seconds_scalar.to_machine_isize(this)?; - let nanoseconds_place = this.mplace_field(tp, 1)?; - let nanoseconds_scalar = this.read_scalar(nanoseconds_place.into())?; + let nanoseconds_place = this.mplace_field(&tp, 1)?; + let nanoseconds_scalar = this.read_scalar(&nanoseconds_place.into())?; let nanoseconds = nanoseconds_scalar.to_machine_isize(this)?; Ok(try { diff --git a/src/machine.rs b/src/machine.rs index dd7d0dd3b647..32aae4a8c8e5 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -193,7 +193,7 @@ impl MemoryExtra { // This should be all-zero, pointer-sized. let layout = this.machine.layouts.usize; let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into()); - this.write_scalar(Scalar::from_machine_usize(0, this), place.into())?; + this.write_scalar(Scalar::from_machine_usize(0, this), &place.into())?; Self::add_extern_static(this, "__cxa_thread_atexit_impl", place.ptr); // "environ" Self::add_extern_static(this, "environ", this.machine.env_vars.environ.unwrap().ptr); @@ -203,7 +203,7 @@ impl MemoryExtra { // This is some obscure hack that is part of the Windows TLS story. It's a `u8`. let layout = this.machine.layouts.u8; let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into()); - this.write_scalar(Scalar::from_u8(0), place.into())?; + this.write_scalar(Scalar::from_u8(0), &place.into())?; Self::add_extern_static(this, "_tls_used", place.ptr); } _ => {} // No "extern statics" supported on this target @@ -359,7 +359,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { instance: ty::Instance<'tcx>, abi: Abi, args: &[OpTy<'tcx, Tag>], - ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { ecx.find_mir_or_eval_fn(instance, abi, args, ret, unwind) @@ -371,7 +371,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn_val: Dlsym, abi: Abi, args: &[OpTy<'tcx, Tag>], - ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, _unwind: Option, ) -> InterpResult<'tcx> { ecx.call_dlsym(fn_val, abi, args, ret) @@ -382,7 +382,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx: &mut rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], - ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, ) -> InterpResult<'tcx> { ecx.call_intrinsic(instance, args, ret, unwind) @@ -406,15 +406,15 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn binary_ptr_op( ecx: &rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>, bin_op: mir::BinOp, - left: ImmTy<'tcx, Tag>, - right: ImmTy<'tcx, Tag>, + left: &ImmTy<'tcx, Tag>, + right: &ImmTy<'tcx, Tag>, ) -> InterpResult<'tcx, (Scalar, bool, ty::Ty<'tcx>)> { ecx.binary_ptr_op(bin_op, left, right) } fn box_alloc( ecx: &mut InterpCx<'mir, 'tcx, Self>, - dest: PlaceTy<'tcx, Tag>, + dest: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { trace!("box_alloc for {:?}", dest.layout.ty); let layout = ecx.layout_of(dest.layout.ty.builtin_deref(false).unwrap().ty)?; @@ -542,7 +542,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn retag( ecx: &mut InterpCx<'mir, 'tcx, Self>, kind: mir::RetagKind, - place: PlaceTy<'tcx, Tag>, + place: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { if ecx.memory.extra.stacked_borrows.is_some() { ecx.retag(kind, place) diff --git a/src/operator.rs b/src/operator.rs index 5b86b9a76f6b..cf92aed9ccb2 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -8,8 +8,8 @@ pub trait EvalContextExt<'tcx> { fn binary_ptr_op( &self, bin_op: mir::BinOp, - left: ImmTy<'tcx, Tag>, - right: ImmTy<'tcx, Tag>, + left: &ImmTy<'tcx, Tag>, + right: &ImmTy<'tcx, Tag>, ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)>; fn ptr_eq(&self, left: Scalar, right: Scalar) -> InterpResult<'tcx, bool>; @@ -19,8 +19,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { fn binary_ptr_op( &self, bin_op: mir::BinOp, - left: ImmTy<'tcx, Tag>, - right: ImmTy<'tcx, Tag>, + left: &ImmTy<'tcx, Tag>, + right: &ImmTy<'tcx, Tag>, ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { use rustc_middle::mir::BinOp::*; @@ -30,7 +30,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { Eq | Ne => { // This supports fat pointers. #[rustfmt::skip] - let eq = match (*left, *right) { + let eq = match (**left, **right) { (Immediate::Scalar(left), Immediate::Scalar(right)) => { self.ptr_eq(left.check_init()?, right.check_init()?)? } diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index a599ee70efae..159a0bc1f8cd 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -13,11 +13,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn handle_miri_get_backtrace( &mut self, args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag> + dest: &PlaceTy<'tcx, Tag> ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let tcx = this.tcx; - let &[flags] = check_arg_count(args)?; + let &[ref flags] = check_arg_count(args)?; let flags = this.read_scalar(flags)?.to_u64()?; if flags != 0 { @@ -59,8 +59,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Write pointers into array let alloc = this.allocate(this.layout_of(array_ty).unwrap(), MiriMemoryKind::Rust.into()); for (i, ptr) in ptrs.into_iter().enumerate() { - let place = this.mplace_index(alloc, i as u64)?; - this.write_immediate_to_mplace(ptr.into(), place)?; + let place = this.mplace_index(&alloc, i as u64)?; + this.write_immediate_to_mplace(ptr.into(), &place)?; } this.write_immediate(Immediate::new_slice(alloc.ptr.into(), len.try_into().unwrap(), this), dest)?; @@ -70,11 +70,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn handle_miri_resolve_frame( &mut self, args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag> + dest: &PlaceTy<'tcx, Tag> ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let tcx = this.tcx; - let &[ptr, flags] = check_arg_count(args)?; + let &[ref ptr, ref flags] = check_arg_count(args)?; let flags = this.read_scalar(flags)?.to_u64()?; if flags != 0 { @@ -125,15 +125,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - this.write_immediate(name_alloc.to_ref(), this.mplace_field(dest, 0)?.into())?; - this.write_immediate(filename_alloc.to_ref(), this.mplace_field(dest, 1)?.into())?; - this.write_scalar(lineno_alloc, this.mplace_field(dest, 2)?.into())?; - this.write_scalar(colno_alloc, this.mplace_field(dest, 3)?.into())?; + this.write_immediate(name_alloc.to_ref(), &this.mplace_field(&dest, 0)?.into())?; + this.write_immediate(filename_alloc.to_ref(), &this.mplace_field(&dest, 1)?.into())?; + this.write_scalar(lineno_alloc, &this.mplace_field(&dest, 2)?.into())?; + this.write_scalar(colno_alloc, &this.mplace_field(&dest, 3)?.into())?; // Support a 4-field struct for now - this is deprecated // and slated for removal. if num_fields == 5 { - this.write_scalar(fn_ptr, this.mplace_field(dest, 4)?.into())?; + this.write_scalar(fn_ptr, &this.mplace_field(&dest, 4)?.into())?; } Ok(()) diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index a87d8a017573..e45556f9a1d1 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -32,7 +32,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dlsym: Dlsym, abi: Abi, args: &[OpTy<'tcx, Tag>], - ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); match dlsym { diff --git a/src/shims/env.rs b/src/shims/env.rs index 12d1cda96da0..53770fd4f05b 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -69,7 +69,7 @@ impl<'tcx> EnvVars<'tcx> { } // Deallocate environ var list. let environ = ecx.machine.env_vars.environ.unwrap(); - let old_vars_ptr = ecx.read_scalar(environ.into())?.check_init()?; + let old_vars_ptr = ecx.read_scalar(&environ.into())?.check_init()?; ecx.memory.deallocate(ecx.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Env.into())?; Ok(()) } @@ -99,7 +99,7 @@ fn alloc_env_var_as_wide_str<'mir, 'tcx>( impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn getenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { + fn getenv(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let target_os = &this.tcx.sess.target.os; assert!(target_os == "linux" || target_os == "macos", "`getenv` is only available for the UNIX target family"); @@ -118,9 +118,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn GetEnvironmentVariableW( &mut self, - name_op: OpTy<'tcx, Tag>, // LPCWSTR - buf_op: OpTy<'tcx, Tag>, // LPWSTR - size_op: OpTy<'tcx, Tag>, // DWORD + name_op: &OpTy<'tcx, Tag>, // LPCWSTR + buf_op: &OpTy<'tcx, Tag>, // LPWSTR + size_op: &OpTy<'tcx, Tag>, // DWORD ) -> InterpResult<'tcx, u32> { // Returns DWORD (u32 in Windows) let this = self.eval_context_mut(); this.assert_target_os("windows", "GetEnvironmentVariableW"); @@ -169,7 +169,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn FreeEnvironmentStringsW(&mut self, env_block_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn FreeEnvironmentStringsW(&mut self, env_block_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("windows", "FreeEnvironmentStringsW"); @@ -181,8 +181,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn setenv( &mut self, - name_op: OpTy<'tcx, Tag>, - value_op: OpTy<'tcx, Tag>, + name_op: &OpTy<'tcx, Tag>, + value_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let mut this = self.eval_context_mut(); let target_os = &this.tcx.sess.target.os; @@ -218,8 +218,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn SetEnvironmentVariableW( &mut self, - name_op: OpTy<'tcx, Tag>, // LPCWSTR - value_op: OpTy<'tcx, Tag>, // LPCWSTR + name_op: &OpTy<'tcx, Tag>, // LPCWSTR + value_op: &OpTy<'tcx, Tag>, // LPCWSTR ) -> InterpResult<'tcx, i32> { let mut this = self.eval_context_mut(); this.assert_target_os("windows", "SetEnvironmentVariableW"); @@ -256,7 +256,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn unsetenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn unsetenv(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let target_os = &this.tcx.sess.target.os; assert!(target_os == "linux" || target_os == "macos", "`unsetenv` is only available for the UNIX target family"); @@ -286,8 +286,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn getcwd( &mut self, - buf_op: OpTy<'tcx, Tag>, - size_op: OpTy<'tcx, Tag>, + buf_op: &OpTy<'tcx, Tag>, + size_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let target_os = &this.tcx.sess.target.os; @@ -295,8 +295,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("`getcwd`")?; - let buf = this.read_scalar(buf_op)?.check_init()?; - let size = this.read_scalar(size_op)?.to_machine_usize(&*this.tcx)?; + let buf = this.read_scalar(&buf_op)?.check_init()?; + let size = this.read_scalar(&size_op)?.to_machine_usize(&*this.tcx)?; // If we cannot get the current directory, we return null match env::current_dir() { Ok(cwd) => { @@ -314,8 +314,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn GetCurrentDirectoryW( &mut self, - size_op: OpTy<'tcx, Tag>, // DWORD - buf_op: OpTy<'tcx, Tag>, // LPTSTR + size_op: &OpTy<'tcx, Tag>, // DWORD + buf_op: &OpTy<'tcx, Tag>, // LPTSTR ) -> InterpResult<'tcx, u32> { let this = self.eval_context_mut(); this.assert_target_os("windows", "GetCurrentDirectoryW"); @@ -334,7 +334,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn chdir(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn chdir(&mut self, path_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let target_os = &this.tcx.sess.target.os; assert!(target_os == "linux" || target_os == "macos", "`getcwd` is only available for the UNIX target family"); @@ -355,7 +355,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn SetCurrentDirectoryW ( &mut self, - path_op: OpTy<'tcx, Tag> // LPCTSTR + path_op: &OpTy<'tcx, Tag> // LPCTSTR ) -> InterpResult<'tcx, i32> { // Returns BOOL (i32 in Windows) let this = self.eval_context_mut(); this.assert_target_os("windows", "SetCurrentDirectoryW"); @@ -379,7 +379,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); // Deallocate the old environ list, if any. if let Some(environ) = this.machine.env_vars.environ { - let old_vars_ptr = this.read_scalar(environ.into())?.check_init()?; + let old_vars_ptr = this.read_scalar(&environ.into())?.check_init()?; this.memory.deallocate(this.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Env.into())?; } else { // No `environ` allocated yet, let's do that. @@ -399,12 +399,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.layout_of(tcx.mk_array(tcx.types.usize, u64::try_from(vars.len()).unwrap()))?; let vars_place = this.allocate(vars_layout, MiriMemoryKind::Env.into()); for (idx, var) in vars.into_iter().enumerate() { - let place = this.mplace_field(vars_place, idx)?; - this.write_scalar(var, place.into())?; + let place = this.mplace_field(&vars_place, idx)?; + this.write_scalar(var, &place.into())?; } this.write_scalar( vars_place.ptr, - this.machine.env_vars.environ.unwrap().into(), + &this.machine.env_vars.environ.unwrap().into(), )?; Ok(()) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 628e9b69e174..9203aafd5767 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -114,7 +114,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx def_id: DefId, abi: Abi, args: &[OpTy<'tcx, Tag>], - ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); @@ -147,7 +147,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "ExitProcess" => { check_abi(abi, if link_name == "exit" { Abi::C } else { Abi::System })?; - let &[code] = check_arg_count(args)?; + let &[ref code] = check_arg_count(args)?; // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway let code = this.read_scalar(code)?.to_i32()?; throw_machine_stop!(TerminationInfo::Exit(code.into())); @@ -186,7 +186,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Third: functions that return. if this.emulate_foreign_item_by_name(link_name, abi, args, dest, ret)? { - trace!("{:?}", this.dump_place(*dest)); + trace!("{:?}", this.dump_place(**dest)); this.go_to_block(ret); } @@ -201,7 +201,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx link_name: &str, abi: Abi, args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag>, + dest: &PlaceTy<'tcx, Tag>, ret: mir::BasicBlock, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); @@ -212,7 +212,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miri-specific extern functions "miri_static_root" => { check_abi(abi, Abi::Rust)?; - let &[ptr] = check_arg_count(args)?; + let &[ref ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let ptr = this.force_ptr(ptr)?; if ptr.offset != Size::ZERO { @@ -237,14 +237,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Standard C allocation "malloc" => { check_abi(abi, Abi::C)?; - let &[size] = check_arg_count(args)?; + let &[ref size] = check_arg_count(args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C); this.write_scalar(res, dest)?; } "calloc" => { check_abi(abi, Abi::C)?; - let &[items, len] = check_arg_count(args)?; + let &[ref items, ref len] = check_arg_count(args)?; let items = this.read_scalar(items)?.to_machine_usize(this)?; let len = this.read_scalar(len)?.to_machine_usize(this)?; let size = @@ -254,13 +254,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "free" => { check_abi(abi, Abi::C)?; - let &[ptr] = check_arg_count(args)?; + let &[ref ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; this.free(ptr, MiriMemoryKind::C)?; } "realloc" => { check_abi(abi, Abi::C)?; - let &[old_ptr, new_size] = check_arg_count(args)?; + let &[ref old_ptr, ref new_size] = check_arg_count(args)?; let old_ptr = this.read_scalar(old_ptr)?.check_init()?; let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; let res = this.realloc(old_ptr, new_size, MiriMemoryKind::C)?; @@ -272,7 +272,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // allocation that also checks that all conditions are met, such as not permitting zero-sized allocations.) "__rust_alloc" => { check_abi(abi, Abi::Rust)?; - let &[size, align] = check_arg_count(args)?; + let &[ref size, ref align] = check_arg_count(args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; Self::check_alloc_request(size, align)?; @@ -285,7 +285,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "__rust_alloc_zeroed" => { check_abi(abi, Abi::Rust)?; - let &[size, align] = check_arg_count(args)?; + let &[ref size, ref align] = check_arg_count(args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; Self::check_alloc_request(size, align)?; @@ -300,7 +300,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "__rust_dealloc" => { check_abi(abi, Abi::Rust)?; - let &[ptr, old_size, align] = check_arg_count(args)?; + let &[ref ptr, ref old_size, ref align] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -314,7 +314,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "__rust_realloc" => { check_abi(abi, Abi::Rust)?; - let &[ptr, old_size, align, new_size] = check_arg_count(args)?; + let &[ref ptr, ref old_size, ref align, ref new_size] = check_arg_count(args)?; let ptr = this.force_ptr(this.read_scalar(ptr)?.check_init()?)?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -335,7 +335,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // C memory handling functions "memcmp" => { check_abi(abi, Abi::C)?; - let &[left, right, n] = check_arg_count(args)?; + let &[ref left, ref right, ref n] = check_arg_count(args)?; let left = this.read_scalar(left)?.check_init()?; let right = this.read_scalar(right)?.check_init()?; let n = Size::from_bytes(this.read_scalar(n)?.to_machine_usize(this)?); @@ -356,7 +356,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "memrchr" => { check_abi(abi, Abi::C)?; - let &[ptr, val, num] = check_arg_count(args)?; + let &[ref ptr, ref val, ref num] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; @@ -375,7 +375,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "memchr" => { check_abi(abi, Abi::C)?; - let &[ptr, val, num] = check_arg_count(args)?; + let &[ref ptr, ref val, ref num] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; @@ -393,7 +393,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "strlen" => { check_abi(abi, Abi::C)?; - let &[ptr] = check_arg_count(args)?; + let &[ref ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let n = this.memory.read_c_str(ptr)?.len(); this.write_scalar(Scalar::from_machine_usize(u64::try_from(n).unwrap(), this), dest)?; @@ -409,7 +409,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "atanf" => { check_abi(abi, Abi::C)?; - let &[f] = check_arg_count(args)?; + let &[ref f] = check_arg_count(args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let f = match link_name { @@ -429,7 +429,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "atan2f" => { check_abi(abi, Abi::C)?; - let &[f1, f2] = check_arg_count(args)?; + let &[ref f1, ref f2] = check_arg_count(args)?; // underscore case for windows, here and below // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) // FIXME: Using host floats. @@ -451,7 +451,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "atan" => { check_abi(abi, Abi::C)?; - let &[f] = check_arg_count(args)?; + let &[ref f] = check_arg_count(args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let f = match link_name { @@ -471,7 +471,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "atan2" => { check_abi(abi, Abi::C)?; - let &[f1, f2] = check_arg_count(args)?; + let &[ref f1, ref f2] = check_arg_count(args)?; // FIXME: Using host floats. let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?); let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?); @@ -487,7 +487,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "scalbn" => { check_abi(abi, Abi::C)?; - let &[x, exp] = check_arg_count(args)?; + let &[ref x, ref exp] = check_arg_count(args)?; // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. let x = this.read_scalar(x)?.to_f64()?; let exp = this.read_scalar(exp)?.to_i32()?; @@ -514,7 +514,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "llvm.aarch64.hint" if this.tcx.sess.target.arch == "aarch64" => { check_abi(abi, Abi::C)?; - let &[hint] = check_arg_count(args)?; + let &[ref hint] = check_arg_count(args)?; let hint = this.read_scalar(hint)?.to_i32()?; match hint { 1 => { // HINT_YIELD diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index fc859bc53020..33aa7b28bb5b 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -16,7 +16,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], - ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, _unwind: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -36,32 +36,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match intrinsic_name { // Miri overwriting CTFE intrinsics. "ptr_guaranteed_eq" => { - let &[left, right] = check_arg_count(args)?; + let &[ref left, ref right] = check_arg_count(args)?; let left = this.read_immediate(left)?; let right = this.read_immediate(right)?; - this.binop_ignore_overflow(mir::BinOp::Eq, left, right, dest)?; + this.binop_ignore_overflow(mir::BinOp::Eq, &left, &right, dest)?; } "ptr_guaranteed_ne" => { - let &[left, right] = check_arg_count(args)?; + let &[ref left, ref right] = check_arg_count(args)?; let left = this.read_immediate(left)?; let right = this.read_immediate(right)?; - this.binop_ignore_overflow(mir::BinOp::Ne, left, right, dest)?; + this.binop_ignore_overflow(mir::BinOp::Ne, &left, &right, dest)?; } // Raw memory accesses "volatile_load" => { - let &[place] = check_arg_count(args)?; + let &[ref place] = check_arg_count(args)?; let place = this.deref_operand(place)?; - this.copy_op(place.into(), dest)?; + this.copy_op(&place.into(), dest)?; } "volatile_store" => { - let &[place, dest] = check_arg_count(args)?; + let &[ref place, ref dest] = check_arg_count(args)?; let place = this.deref_operand(place)?; - this.copy_op(dest, place.into())?; + this.copy_op(dest, &place.into())?; } "write_bytes" => { - let &[ptr, val_byte, count] = check_arg_count(args)?; + let &[ref ptr, ref val_byte, ref count] = check_arg_count(args)?; let ty = instance.substs.type_at(0); let ty_layout = this.layout_of(ty)?; let val_byte = this.read_scalar(val_byte)?.to_u8()?; @@ -89,7 +89,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "truncf32" | "roundf32" => { - let &[f] = check_arg_count(args)?; + let &[ref f] = check_arg_count(args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let f = match intrinsic_name { @@ -126,7 +126,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "truncf64" | "roundf64" => { - let &[f] = check_arg_count(args)?; + let &[ref f] = check_arg_count(args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let f = match intrinsic_name { @@ -155,7 +155,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "fdiv_fast" | "frem_fast" => { - let &[a, b] = check_arg_count(args)?; + let &[ref a, ref b] = check_arg_count(args)?; let a = this.read_immediate(a)?; let b = this.read_immediate(b)?; let op = match intrinsic_name { @@ -166,7 +166,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "frem_fast" => mir::BinOp::Rem, _ => bug!(), }; - this.binop_ignore_overflow(op, a, b, dest)?; + this.binop_ignore_overflow(op, &a, &b, dest)?; } #[rustfmt::skip] @@ -174,7 +174,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "maxnumf32" | "copysignf32" => { - let &[a, b] = check_arg_count(args)?; + let &[ref a, ref b] = check_arg_count(args)?; let a = this.read_scalar(a)?.to_f32()?; let b = this.read_scalar(b)?.to_f32()?; let res = match intrinsic_name { @@ -191,7 +191,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "maxnumf64" | "copysignf64" => { - let &[a, b] = check_arg_count(args)?; + let &[ref a, ref b] = check_arg_count(args)?; let a = this.read_scalar(a)?.to_f64()?; let b = this.read_scalar(b)?.to_f64()?; let res = match intrinsic_name { @@ -204,7 +204,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "powf32" => { - let &[f, f2] = check_arg_count(args)?; + let &[ref f, ref f2] = check_arg_count(args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let f2 = f32::from_bits(this.read_scalar(f2)?.to_u32()?); @@ -212,7 +212,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "powf64" => { - let &[f, f2] = check_arg_count(args)?; + let &[ref f, ref f2] = check_arg_count(args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?); @@ -220,7 +220,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "fmaf32" => { - let &[a, b, c] = check_arg_count(args)?; + let &[ref a, ref b, ref c] = check_arg_count(args)?; let a = this.read_scalar(a)?.to_f32()?; let b = this.read_scalar(b)?.to_f32()?; let c = this.read_scalar(c)?.to_f32()?; @@ -229,7 +229,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "fmaf64" => { - let &[a, b, c] = check_arg_count(args)?; + let &[ref a, ref b, ref c] = check_arg_count(args)?; let a = this.read_scalar(a)?.to_f64()?; let b = this.read_scalar(b)?.to_f64()?; let c = this.read_scalar(c)?.to_f64()?; @@ -238,7 +238,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "powif32" => { - let &[f, i] = check_arg_count(args)?; + let &[ref f, ref i] = check_arg_count(args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let i = this.read_scalar(i)?.to_i32()?; @@ -246,7 +246,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "powif64" => { - let &[f, i] = check_arg_count(args)?; + let &[ref f, ref i] = check_arg_count(args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let i = this.read_scalar(i)?.to_i32()?; @@ -254,7 +254,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "float_to_int_unchecked" => { - let &[val] = check_arg_count(args)?; + let &[ref val] = check_arg_count(args)?; let val = this.read_immediate(val)?; let res = match val.layout.ty.kind() { @@ -404,8 +404,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Other "exact_div" => { - let &[num, denom] = check_arg_count(args)?; - this.exact_div(this.read_immediate(num)?, this.read_immediate(denom)?, dest)?; + let &[ref num, ref denom] = check_arg_count(args)?; + this.exact_div(&this.read_immediate(num)?, &this.read_immediate(denom)?, dest)?; } "try" => return this.handle_try(args, dest, ret), @@ -413,23 +413,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name => throw_unsup_format!("unimplemented intrinsic: {}", name), } - trace!("{:?}", this.dump_place(*dest)); + trace!("{:?}", this.dump_place(**dest)); this.go_to_block(ret); Ok(()) } fn atomic_load( - &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, + &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, atomic: AtomicReadOp ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[place] = check_arg_count(args)?; + let &[ref place] = check_arg_count(args)?; let place = this.deref_operand(place)?; // make sure it fits into a scalar; otherwise it cannot be atomic - let val = this.read_scalar_atomic(place, atomic)?; + let val = this.read_scalar_atomic(&place, atomic)?; // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must @@ -443,7 +443,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn atomic_store(&mut self, args: &[OpTy<'tcx, Tag>], atomic: AtomicWriteOp) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[place, val] = check_arg_count(args)?; + let &[ref place, ref val] = check_arg_count(args)?; let place = this.deref_operand(place)?; let val = this.read_scalar(val)?; // make sure it fits into a scalar; otherwise it cannot be atomic @@ -454,7 +454,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; // Perform atomic store - this.write_scalar_atomic(val, place, atomic)?; + this.write_scalar_atomic(val, &place, atomic)?; Ok(()) } @@ -473,12 +473,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } fn atomic_op( - &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, + &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, op: mir::BinOp, neg: bool, atomic: AtomicRwOp ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[place, rhs] = check_arg_count(args)?; + let &[ref place, ref rhs] = check_arg_count(args)?; let place = this.deref_operand(place)?; if !place.layout.ty.is_integral() { bug!("Atomic arithmetic operations only work on integer types"); @@ -491,17 +491,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; - let old = this.atomic_op_immediate(place, rhs, op, neg, atomic)?; + let old = this.atomic_op_immediate(&place, &rhs, op, neg, atomic)?; this.write_immediate(*old, dest)?; // old value is returned Ok(()) } fn atomic_exchange( - &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, atomic: AtomicRwOp + &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, atomic: AtomicRwOp ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[place, new] = check_arg_count(args)?; + let &[ref place, ref new] = check_arg_count(args)?; let place = this.deref_operand(place)?; let new = this.read_scalar(new)?; @@ -511,18 +511,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; - let old = this.atomic_exchange_scalar(place, new, atomic)?; + let old = this.atomic_exchange_scalar(&place, new, atomic)?; this.write_scalar(old, dest)?; // old value is returned Ok(()) } fn atomic_compare_exchange_impl( - &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, + &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, success: AtomicRwOp, fail: AtomicReadOp, can_fail_spuriously: bool ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[place, expect_old, new] = check_arg_count(args)?; + let &[ref place, ref expect_old, ref new] = check_arg_count(args)?; let place = this.deref_operand(place)?; let expect_old = this.read_immediate(expect_old)?; // read as immediate for the sake of `binary_op()` let new = this.read_scalar(new)?; @@ -536,7 +536,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let old = this.atomic_compare_exchange_scalar( - place, expect_old, new, success, fail, can_fail_spuriously + &place, &expect_old, new, success, fail, can_fail_spuriously )?; // Return old value. @@ -545,14 +545,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } fn atomic_compare_exchange( - &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, + &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, success: AtomicRwOp, fail: AtomicReadOp ) -> InterpResult<'tcx> { self.atomic_compare_exchange_impl(args, dest, success, fail, false) } fn atomic_compare_exchange_weak( - &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, + &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, success: AtomicRwOp, fail: AtomicReadOp ) -> InterpResult<'tcx> { self.atomic_compare_exchange_impl(args, dest, success, fail, true) diff --git a/src/shims/mod.rs b/src/shims/mod.rs index c2b8809efbb6..1605ea2f6a89 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -28,15 +28,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx instance: ty::Instance<'tcx>, abi: Abi, args: &[OpTy<'tcx, Tag>], - ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); - trace!("eval_fn_call: {:#?}, {:?}", instance, ret.map(|p| *p.0)); + trace!("eval_fn_call: {:#?}, {:?}", instance, ret.map(|p| p.0)); // There are some more lang items we want to hook that CTFE does not hook (yet). if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { - let &[ptr, align] = check_arg_count(args)?; + let &[ref ptr, ref align] = check_arg_count(args)?; if this.align_offset(ptr, align, ret, unwind)? { return Ok(None); } @@ -61,9 +61,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// the actual MIR of `align_offset`. fn align_offset( &mut self, - ptr_op: OpTy<'tcx, Tag>, - align_op: OpTy<'tcx, Tag>, - ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ptr_op: &OpTy<'tcx, Tag>, + align_op: &OpTy<'tcx, Tag>, + ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 52d27a1bb5c2..abc7aa2ad1bd 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -48,7 +48,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert_eq!(this.tcx.sess.panic_strategy(), PanicStrategy::Unwind); // Get the raw pointer stored in arg[0] (the panic payload). - let &[payload] = check_arg_count(args)?; + let &[ref payload] = check_arg_count(args)?; let payload = this.read_scalar(payload)?.check_init()?; let thread = this.active_thread_mut(); assert!( @@ -66,7 +66,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn handle_try( &mut self, args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag>, + dest: &PlaceTy<'tcx, Tag>, ret: mir::BasicBlock, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -83,7 +83,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // a pointer to `Box`. // Get all the arguments. - let &[try_fn, data, catch_fn] = check_arg_count(args)?; + let &[ref try_fn, ref data, ref catch_fn] = check_arg_count(args)?; let try_fn = this.read_scalar(try_fn)?.check_init()?; let data = this.read_scalar(data)?.check_init()?; let catch_fn = this.read_scalar(catch_fn)?.check_init()?; @@ -95,7 +95,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.call_function( f_instance, &[data.into()], - Some(ret_place), + Some(&ret_place), // Directly return to caller. StackPopCleanup::Goto { ret: Some(ret), unwind: None }, )?; @@ -107,7 +107,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This lets `handle_stack_pop` (below) know that we should stop unwinding // when we pop this frame. if this.tcx.sess.panic_strategy() == PanicStrategy::Unwind { - this.frame_mut().extra.catch_unwind = Some(CatchUnwindData { catch_fn, data, dest, ret }); + this.frame_mut().extra.catch_unwind = Some(CatchUnwindData { catch_fn, data, dest: *dest, ret }); } return Ok(()); @@ -133,7 +133,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("unwinding: found catch_panic frame during unwinding: {:?}", this.frame().instance); // We set the return value of `try` to 1, since there was a panic. - this.write_scalar(Scalar::from_i32(1), catch_unwind.dest)?; + this.write_scalar(Scalar::from_i32(1), &catch_unwind.dest)?; // The Thread's `panic_payload` holds what was passed to `miri_start_panic`. // This is exactly the second argument we need to pass to `catch_fn`. @@ -146,7 +146,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.call_function( f_instance, &[catch_unwind.data.into(), payload.into()], - Some(ret_place), + Some(&ret_place), // Directly return to caller of `try`. StackPopCleanup::Goto { ret: Some(catch_unwind.ret), unwind: None }, )?; @@ -193,9 +193,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Forward to `panic_bounds_check` lang item. // First arg: index. - let index = this.read_scalar(this.eval_operand(index, None)?)?; + let index = this.read_scalar(&this.eval_operand(index, None)?)?; // Second arg: len. - let len = this.read_scalar(this.eval_operand(len, None)?)?; + let len = this.read_scalar(&this.eval_operand(len, None)?)?; // Call the lang item. let panic_bounds_check = this.tcx.lang_items().panic_bounds_check_fn().unwrap(); diff --git a/src/shims/posix/dlsym.rs b/src/shims/posix/dlsym.rs index 660c6dc0ebae..e1eccc680883 100644 --- a/src/shims/posix/dlsym.rs +++ b/src/shims/posix/dlsym.rs @@ -31,7 +31,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dlsym: Dlsym, abi: Abi, args: &[OpTy<'tcx, Tag>], - ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index e576c6f32e90..21b5ed62bbb5 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -17,7 +17,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx link_name: &str, abi: Abi, args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag>, + dest: &PlaceTy<'tcx, Tag>, ret: mir::BasicBlock, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); @@ -27,35 +27,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Environment related shims "getenv" => { - let &[name] = check_arg_count(args)?; + let &[ref name] = check_arg_count(args)?; let result = this.getenv(name)?; this.write_scalar(result, dest)?; } "unsetenv" => { - let &[name] = check_arg_count(args)?; + let &[ref name] = check_arg_count(args)?; let result = this.unsetenv(name)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "setenv" => { - let &[name, value, overwrite] = check_arg_count(args)?; + let &[ref name, ref value, ref overwrite] = check_arg_count(args)?; this.read_scalar(overwrite)?.to_i32()?; let result = this.setenv(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "getcwd" => { - let &[buf, size] = check_arg_count(args)?; + let &[ref buf, ref size] = check_arg_count(args)?; let result = this.getcwd(buf, size)?; this.write_scalar(result, dest)?; } "chdir" => { - let &[path] = check_arg_count(args)?; + let &[ref path] = check_arg_count(args)?; let result = this.chdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // File related shims "open" | "open64" => { - let &[path, flag, mode] = check_arg_count(args)?; + let &[ref path, ref flag, ref mode] = check_arg_count(args)?; let result = this.open(path, flag, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -64,7 +64,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "read" => { - let &[fd, buf, count] = check_arg_count(args)?; + let &[ref fd, ref buf, ref count] = check_arg_count(args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.check_init()?; let count = this.read_scalar(count)?.to_machine_usize(this)?; @@ -72,7 +72,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "write" => { - let &[fd, buf, n] = check_arg_count(args)?; + let &[ref fd, ref buf, ref n] = check_arg_count(args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.check_init()?; let count = this.read_scalar(n)?.to_machine_usize(this)?; @@ -82,60 +82,60 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "unlink" => { - let &[path] = check_arg_count(args)?; + let &[ref path] = check_arg_count(args)?; let result = this.unlink(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "symlink" => { - let &[target, linkpath] = check_arg_count(args)?; + let &[ref target, ref linkpath] = check_arg_count(args)?; let result = this.symlink(target, linkpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rename" => { - let &[oldpath, newpath] = check_arg_count(args)?; + let &[ref oldpath, ref newpath] = check_arg_count(args)?; let result = this.rename(oldpath, newpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mkdir" => { - let &[path, mode] = check_arg_count(args)?; + let &[ref path, ref mode] = check_arg_count(args)?; let result = this.mkdir(path, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rmdir" => { - let &[path] = check_arg_count(args)?; + let &[ref path] = check_arg_count(args)?; let result = this.rmdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "closedir" => { - let &[dirp] = check_arg_count(args)?; + let &[ref dirp] = check_arg_count(args)?; let result = this.closedir(dirp)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lseek" | "lseek64" => { - let &[fd, offset, whence] = check_arg_count(args)?; + let &[ref fd, ref offset, ref whence] = check_arg_count(args)?; let result = this.lseek64(fd, offset, whence)?; // "lseek" is only used on macOS which is 64bit-only, so `i64` always works. this.write_scalar(Scalar::from_i64(result), dest)?; } "fsync" => { - let &[fd] = check_arg_count(args)?; + let &[ref fd] = check_arg_count(args)?; let result = this.fsync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fdatasync" => { - let &[fd] = check_arg_count(args)?; + let &[ref fd] = check_arg_count(args)?; let result = this.fdatasync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "readlink" => { - let &[pathname, buf, bufsize] = check_arg_count(args)?; + let &[ref pathname, ref buf, ref bufsize] = check_arg_count(args)?; let result = this.readlink(pathname, buf, bufsize)?; this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } // Allocation "posix_memalign" => { - let &[ret, align, size] = check_arg_count(args)?; + let &[ref ret, ref align, ref size] = check_arg_count(args)?; let ret = this.deref_operand(ret)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; @@ -151,21 +151,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } if size == 0 { - this.write_null(ret.into())?; + this.write_null(&ret.into())?; } else { let ptr = this.memory.allocate( Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::C.into(), ); - this.write_scalar(ptr, ret.into())?; + this.write_scalar(ptr, &ret.into())?; } this.write_null(dest)?; } // Dynamic symbol loading "dlsym" => { - let &[handle, symbol] = check_arg_count(args)?; + let &[ref handle, ref symbol] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_usize(this)?; let symbol = this.read_scalar(symbol)?.check_init()?; let symbol_name = this.memory.read_c_str(symbol)?; @@ -179,7 +179,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "sysconf" => { - let &[name] = check_arg_count(args)?; + let &[ref name] = check_arg_count(args)?; let name = this.read_scalar(name)?.to_i32()?; let sysconfs = &[ @@ -204,7 +204,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "pthread_key_create" => { - let &[key, dtor] = check_arg_count(args)?; + let &[ref key, ref dtor] = check_arg_count(args)?; let key_place = this.deref_operand(key)?; let dtor = this.read_scalar(dtor)?.check_init()?; @@ -226,27 +226,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Create key and write it into the memory where `key_ptr` wants it. let key = this.machine.tls.create_tls_key(dtor, key_layout.size)?; - this.write_scalar(Scalar::from_uint(key, key_layout.size), key_place.into())?; + this.write_scalar(Scalar::from_uint(key, key_layout.size), &key_place.into())?; // Return success (`0`). this.write_null(dest)?; } "pthread_key_delete" => { - let &[key] = check_arg_count(args)?; + let &[ref key] = check_arg_count(args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; this.machine.tls.delete_tls_key(key)?; // Return success (0) this.write_null(dest)?; } "pthread_getspecific" => { - let &[key] = check_arg_count(args)?; + let &[ref key] = check_arg_count(args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { - let &[key, new_ptr] = check_arg_count(args)?; + let &[ref key, ref new_ptr] = check_arg_count(args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); let new_ptr = this.read_scalar(new_ptr)?.check_init()?; @@ -258,128 +258,128 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Synchronization primitives "pthread_mutexattr_init" => { - let &[attr] = check_arg_count(args)?; + let &[ref attr] = check_arg_count(args)?; let result = this.pthread_mutexattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_settype" => { - let &[attr, kind] = check_arg_count(args)?; + let &[ref attr, ref kind] = check_arg_count(args)?; let result = this.pthread_mutexattr_settype(attr, kind)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_destroy" => { - let &[attr] = check_arg_count(args)?; + let &[ref attr] = check_arg_count(args)?; let result = this.pthread_mutexattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_init" => { - let &[mutex, attr] = check_arg_count(args)?; + let &[ref mutex, ref attr] = check_arg_count(args)?; let result = this.pthread_mutex_init(mutex, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_lock" => { - let &[mutex] = check_arg_count(args)?; + let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_lock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_trylock" => { - let &[mutex] = check_arg_count(args)?; + let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_trylock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_unlock" => { - let &[mutex] = check_arg_count(args)?; + let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_unlock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_destroy" => { - let &[mutex] = check_arg_count(args)?; + let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_destroy(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_rdlock" => { - let &[rwlock] = check_arg_count(args)?; + let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_rdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_tryrdlock" => { - let &[rwlock] = check_arg_count(args)?; + let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_tryrdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_wrlock" => { - let &[rwlock] = check_arg_count(args)?; + let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_wrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_trywrlock" => { - let &[rwlock] = check_arg_count(args)?; + let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_trywrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_unlock" => { - let &[rwlock] = check_arg_count(args)?; + let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_unlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_destroy" => { - let &[rwlock] = check_arg_count(args)?; + let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_destroy(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_init" => { - let &[attr] = check_arg_count(args)?; + let &[ref attr] = check_arg_count(args)?; let result = this.pthread_condattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_destroy" => { - let &[attr] = check_arg_count(args)?; + let &[ref attr] = check_arg_count(args)?; let result = this.pthread_condattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_init" => { - let &[cond, attr] = check_arg_count(args)?; + let &[ref cond, ref attr] = check_arg_count(args)?; let result = this.pthread_cond_init(cond, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_signal" => { - let &[cond] = check_arg_count(args)?; + let &[ref cond] = check_arg_count(args)?; let result = this.pthread_cond_signal(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_broadcast" => { - let &[cond] = check_arg_count(args)?; + let &[ref cond] = check_arg_count(args)?; let result = this.pthread_cond_broadcast(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_wait" => { - let &[cond, mutex] = check_arg_count(args)?; + let &[ref cond, ref mutex] = check_arg_count(args)?; let result = this.pthread_cond_wait(cond, mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_timedwait" => { - let &[cond, mutex, abstime] = check_arg_count(args)?; + let &[ref cond, ref mutex, ref abstime] = check_arg_count(args)?; this.pthread_cond_timedwait(cond, mutex, abstime, dest)?; } "pthread_cond_destroy" => { - let &[cond] = check_arg_count(args)?; + let &[ref cond] = check_arg_count(args)?; let result = this.pthread_cond_destroy(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Threading "pthread_create" => { - let &[thread, attr, start, arg] = check_arg_count(args)?; + let &[ref thread, ref attr, ref start, ref arg] = check_arg_count(args)?; let result = this.pthread_create(thread, attr, start, arg)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_join" => { - let &[thread, retval] = check_arg_count(args)?; + let &[ref thread, ref retval] = check_arg_count(args)?; let result = this.pthread_join(thread, retval)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_detach" => { - let &[thread] = check_arg_count(args)?; + let &[ref thread] = check_arg_count(args)?; let result = this.pthread_detach(thread)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -393,14 +393,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "nanosleep" => { - let &[req, rem] = check_arg_count(args)?; + let &[ref req, ref rem] = check_arg_count(args)?; let result = this.nanosleep(req, rem)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Miscellaneous "isatty" => { - let &[fd] = check_arg_count(args)?; + let &[ref fd] = check_arg_count(args)?; this.read_scalar(fd)?.to_i32()?; // "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error" // FIXME: we just say nothing is a terminal. @@ -409,7 +409,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_atfork" => { - let &[prepare, parent, child] = check_arg_count(args)?; + let &[ref prepare, ref parent, ref child] = check_arg_count(args)?; this.force_bits(this.read_scalar(prepare)?.check_init()?, this.memory.pointer_size())?; this.force_bits(this.read_scalar(parent)?.check_init()?, this.memory.pointer_size())?; this.force_bits(this.read_scalar(child)?.check_init()?, this.memory.pointer_size())?; @@ -421,10 +421,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These shims are enabled only when the caller is in the standard library. "pthread_attr_getguardsize" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - let &[_attr, guard_size] = check_arg_count(args)?; + let &[ref _attr, ref guard_size] = check_arg_count(args)?; let guard_size = this.deref_operand(guard_size)?; let guard_size_layout = this.libc_ty_layout("size_t")?; - this.write_scalar(Scalar::from_uint(crate::PAGE_SIZE, guard_size_layout.size), guard_size.into())?; + this.write_scalar(Scalar::from_uint(crate::PAGE_SIZE, guard_size_layout.size), &guard_size.into())?; // Return success (`0`). this.write_null(dest)?; diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 10f0c9109792..2f1efee8c893 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -237,8 +237,8 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' fn macos_stat_or_lstat( &mut self, follow_symlink: bool, - path_op: OpTy<'tcx, Tag>, - buf_op: OpTy<'tcx, Tag>, + path_op: &OpTy<'tcx, Tag>, + buf_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -255,7 +255,7 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' fn macos_stat_write_buf( &mut self, metadata: FileMetadata, - buf_op: OpTy<'tcx, Tag>, + buf_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -303,7 +303,7 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' ]; let buf = this.deref_operand(buf_op)?; - this.write_packed_immediates(buf, &imms)?; + this.write_packed_immediates(&buf, &imms)?; Ok(0) } @@ -412,9 +412,9 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn open( &mut self, - path_op: OpTy<'tcx, Tag>, - flag_op: OpTy<'tcx, Tag>, - mode_op: OpTy<'tcx, Tag>, + path_op: &OpTy<'tcx, Tag>, + flag_op: &OpTy<'tcx, Tag>, + mode_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -516,8 +516,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if args.len() < 2 { throw_ub_format!("incorrect number of arguments for fcntl: got {}, expected at least 2", args.len()); } - let fd = this.read_scalar(args[0])?.to_i32()?; - let cmd = this.read_scalar(args[1])?.to_i32()?; + let fd = this.read_scalar(&args[0])?.to_i32()?; + let cmd = this.read_scalar(&args[1])?.to_i32()?; // We only support getting the flags for a descriptor. if cmd == this.eval_libc_i32("F_GETFD")? { // Currently this is the only flag that `F_GETFD` returns. It is OK to just return the @@ -537,7 +537,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // because exec() isn't supported. The F_DUPFD and F_DUPFD_CLOEXEC commands only // differ in whether the FD_CLOEXEC flag is pre-set on the new file descriptor, // thus they can share the same implementation here. - let &[_, _, start] = check_arg_count(args)?; + let &[_, _, ref start] = check_arg_count(args)?; let start = this.read_scalar(start)?.to_i32()?; let fh = &mut this.machine.file_handler; @@ -572,7 +572,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn close(&mut self, fd_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn close(&mut self, fd_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -671,9 +671,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn lseek64( &mut self, - fd_op: OpTy<'tcx, Tag>, - offset_op: OpTy<'tcx, Tag>, - whence_op: OpTy<'tcx, Tag>, + fd_op: &OpTy<'tcx, Tag>, + offset_op: &OpTy<'tcx, Tag>, + whence_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); @@ -705,7 +705,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn unlink(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn unlink(&mut self, path_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.check_no_isolation("`unlink`")?; @@ -718,8 +718,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn symlink( &mut self, - target_op: OpTy<'tcx, Tag>, - linkpath_op: OpTy<'tcx, Tag> + target_op: &OpTy<'tcx, Tag>, + linkpath_op: &OpTy<'tcx, Tag> ) -> InterpResult<'tcx, i32> { #[cfg(unix)] fn create_link(src: &Path, dst: &Path) -> std::io::Result<()> { @@ -749,8 +749,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn macos_stat( &mut self, - path_op: OpTy<'tcx, Tag>, - buf_op: OpTy<'tcx, Tag>, + path_op: &OpTy<'tcx, Tag>, + buf_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("macos", "stat"); @@ -762,8 +762,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `lstat` is used to get symlink metadata. fn macos_lstat( &mut self, - path_op: OpTy<'tcx, Tag>, - buf_op: OpTy<'tcx, Tag>, + path_op: &OpTy<'tcx, Tag>, + buf_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("macos", "lstat"); @@ -773,8 +773,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn macos_fstat( &mut self, - fd_op: OpTy<'tcx, Tag>, - buf_op: OpTy<'tcx, Tag>, + fd_op: &OpTy<'tcx, Tag>, + buf_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -792,11 +792,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn linux_statx( &mut self, - dirfd_op: OpTy<'tcx, Tag>, // Should be an `int` - pathname_op: OpTy<'tcx, Tag>, // Should be a `const char *` - flags_op: OpTy<'tcx, Tag>, // Should be an `int` - _mask_op: OpTy<'tcx, Tag>, // Should be an `unsigned int` - statxbuf_op: OpTy<'tcx, Tag>, // Should be a `struct statx *` + dirfd_op: &OpTy<'tcx, Tag>, // Should be an `int` + pathname_op: &OpTy<'tcx, Tag>, // Should be a `const char *` + flags_op: &OpTy<'tcx, Tag>, // Should be an `int` + _mask_op: &OpTy<'tcx, Tag>, // Should be an `unsigned int` + statxbuf_op: &OpTy<'tcx, Tag>, // Should be a `struct statx *` ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -827,7 +827,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let statxbuf_ty = this.tcx.mk_mut_ptr(statx_ty); let statxbuf_layout = this.layout_of(statxbuf_ty)?; let statxbuf_imm = ImmTy::from_scalar(statxbuf_scalar, statxbuf_layout); - this.ref_to_mplace(statxbuf_imm)? + this.ref_to_mplace(&statxbuf_imm)? }; let path = this.read_path_from_c_str(pathname_scalar)?.into_owned(); @@ -941,15 +941,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(0u128, __u64_layout)?, // stx_dev_minor ]; - this.write_packed_immediates(statxbuf_place, &imms)?; + this.write_packed_immediates(&statxbuf_place, &imms)?; Ok(0) } fn rename( &mut self, - oldpath_op: OpTy<'tcx, Tag>, - newpath_op: OpTy<'tcx, Tag>, + oldpath_op: &OpTy<'tcx, Tag>, + newpath_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -974,8 +974,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn mkdir( &mut self, - path_op: OpTy<'tcx, Tag>, - mode_op: OpTy<'tcx, Tag>, + path_op: &OpTy<'tcx, Tag>, + mode_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -1008,7 +1008,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn rmdir( &mut self, - path_op: OpTy<'tcx, Tag>, + path_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -1021,7 +1021,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.try_unwrap_io_result(result) } - fn opendir(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { + fn opendir(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.check_no_isolation("`opendir`")?; @@ -1048,9 +1048,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn linux_readdir64_r( &mut self, - dirp_op: OpTy<'tcx, Tag>, - entry_op: OpTy<'tcx, Tag>, - result_op: OpTy<'tcx, Tag>, + dirp_op: &OpTy<'tcx, Tag>, + entry_op: &OpTy<'tcx, Tag>, + result_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -1078,7 +1078,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // } let entry_place = this.deref_operand(entry_op)?; - let name_place = this.mplace_field(entry_place, 4)?; + let name_place = this.mplace_field(&entry_place, 4)?; let file_name = dir_entry.file_name(); // not a Path as there are no separators! let (name_fits, _) = this.write_os_str_to_c_str( @@ -1111,16 +1111,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(0u128, c_ushort_layout)?, // d_reclen immty_from_int_checked(file_type, c_uchar_layout)?, // d_type ]; - this.write_packed_immediates(entry_place, &imms)?; + this.write_packed_immediates(&entry_place, &imms)?; let result_place = this.deref_operand(result_op)?; - this.write_scalar(this.read_scalar(entry_op)?, result_place.into())?; + this.write_scalar(this.read_scalar(entry_op)?, &result_place.into())?; Ok(0) } None => { // end of stream: return 0, assign *result=NULL - this.write_null(this.deref_operand(result_op)?.into())?; + this.write_null(&this.deref_operand(result_op)?.into())?; Ok(0) } Some(Err(e)) => match e.raw_os_error() { @@ -1135,9 +1135,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn macos_readdir_r( &mut self, - dirp_op: OpTy<'tcx, Tag>, - entry_op: OpTy<'tcx, Tag>, - result_op: OpTy<'tcx, Tag>, + dirp_op: &OpTy<'tcx, Tag>, + entry_op: &OpTy<'tcx, Tag>, + result_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -1166,7 +1166,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // } let entry_place = this.deref_operand(entry_op)?; - let name_place = this.mplace_field(entry_place, 5)?; + let name_place = this.mplace_field(&entry_place, 5)?; let file_name = dir_entry.file_name(); // not a Path as there are no separators! let (name_fits, file_name_len) = this.write_os_str_to_c_str( @@ -1200,16 +1200,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(file_name_len, c_ushort_layout)?, // d_namlen immty_from_int_checked(file_type, c_uchar_layout)?, // d_type ]; - this.write_packed_immediates(entry_place, &imms)?; + this.write_packed_immediates(&entry_place, &imms)?; let result_place = this.deref_operand(result_op)?; - this.write_scalar(this.read_scalar(entry_op)?, result_place.into())?; + this.write_scalar(this.read_scalar(entry_op)?, &result_place.into())?; Ok(0) } None => { // end of stream: return 0, assign *result=NULL - this.write_null(this.deref_operand(result_op)?.into())?; + this.write_null(&this.deref_operand(result_op)?.into())?; Ok(0) } Some(Err(e)) => match e.raw_os_error() { @@ -1222,7 +1222,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn closedir(&mut self, dirp_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn closedir(&mut self, dirp_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.check_no_isolation("`closedir`")?; @@ -1239,8 +1239,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn ftruncate64( &mut self, - fd_op: OpTy<'tcx, Tag>, - length_op: OpTy<'tcx, Tag>, + fd_op: &OpTy<'tcx, Tag>, + length_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -1271,7 +1271,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn fsync(&mut self, fd_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn fsync(&mut self, fd_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { // On macOS, `fsync` (unlike `fcntl(F_FULLFSYNC)`) does not wait for the // underlying disk to finish writing. In the interest of host compatibility, // we conservatively implement this with `sync_all`, which @@ -1292,7 +1292,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn fdatasync(&mut self, fd_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn fdatasync(&mut self, fd_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.check_no_isolation("`fdatasync`")?; @@ -1310,10 +1310,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn sync_file_range( &mut self, - fd_op: OpTy<'tcx, Tag>, - offset_op: OpTy<'tcx, Tag>, - nbytes_op: OpTy<'tcx, Tag>, - flags_op: OpTy<'tcx, Tag>, + fd_op: &OpTy<'tcx, Tag>, + offset_op: &OpTy<'tcx, Tag>, + nbytes_op: &OpTy<'tcx, Tag>, + flags_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -1350,9 +1350,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn readlink( &mut self, - pathname_op: OpTy<'tcx, Tag>, - buf_op: OpTy<'tcx, Tag>, - bufsize_op: OpTy<'tcx, Tag> + pathname_op: &OpTy<'tcx, Tag>, + buf_op: &OpTy<'tcx, Tag>, + bufsize_op: &OpTy<'tcx, Tag> ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); diff --git a/src/shims/posix/linux/dlsym.rs b/src/shims/posix/linux/dlsym.rs index 2685a93726d8..e7ffb68ff2ec 100644 --- a/src/shims/posix/linux/dlsym.rs +++ b/src/shims/posix/linux/dlsym.rs @@ -25,7 +25,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, dlsym: Dlsym, _args: &[OpTy<'tcx, Tag>], - ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (_dest, _ret) = ret.expect("we don't support any diverging dlsym"); diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 45afbd05efc2..2a3b512bcdb9 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -13,7 +13,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, link_name: &str, args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag>, + dest: &PlaceTy<'tcx, Tag>, _ret: mir::BasicBlock, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); @@ -30,28 +30,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These symbols have different names on Linux and macOS, which is the only reason they are not // in the `posix` module. "close" => { - let &[fd] = check_arg_count(args)?; + let &[ref fd] = check_arg_count(args)?; let result = this.close(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" => { - let &[name] = check_arg_count(args)?; + let &[ref name] = check_arg_count(args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir64_r" => { - let &[dirp, entry, result] = check_arg_count(args)?; + let &[ref dirp, ref entry, ref result] = check_arg_count(args)?; let result = this.linux_readdir64_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate64" => { - let &[fd, length] = check_arg_count(args)?; + let &[ref fd, ref length] = check_arg_count(args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Linux-only "posix_fadvise" => { - let &[fd, offset, len, advice] = check_arg_count(args)?; + let &[ref fd, ref offset, ref len, ref advice] = check_arg_count(args)?; this.read_scalar(fd)?.to_i32()?; this.read_scalar(offset)?.to_machine_isize(this)?; this.read_scalar(len)?.to_machine_isize(this)?; @@ -60,7 +60,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "sync_file_range" => { - let &[fd, offset, nbytes, flags] = check_arg_count(args)?; + let &[ref fd, ref offset, ref nbytes, ref flags] = check_arg_count(args)?; let result = this.sync_file_range(fd, offset, nbytes, flags)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -68,7 +68,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "clock_gettime" => { // This is a POSIX function but it has only been tested on linux. - let &[clk_id, tp] = check_arg_count(args)?; + let &[ref clk_id, ref tp] = check_arg_count(args)?; let result = this.clock_gettime(clk_id, tp)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -76,18 +76,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_attr_getstack" => { // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. - let &[attr_place, addr_place, size_place] = check_arg_count(args)?; + let &[ref attr_place, ref addr_place, ref size_place] = check_arg_count(args)?; this.deref_operand(attr_place)?; let addr_place = this.deref_operand(addr_place)?; let size_place = this.deref_operand(size_place)?; this.write_scalar( Scalar::from_uint(STACK_ADDR, this.pointer_size()), - addr_place.into(), + &addr_place.into(), )?; this.write_scalar( Scalar::from_uint(STACK_SIZE, this.pointer_size()), - size_place.into(), + &size_place.into(), )?; // Return success (`0`). @@ -96,17 +96,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "prctl" => { - let &[option, arg2, arg3, arg4, arg5] = check_arg_count(args)?; + let &[ref option, ref arg2, ref arg3, ref arg4, ref arg5] = check_arg_count(args)?; let result = this.prctl(option, arg2, arg3, arg4, arg5)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_setclock" => { - let &[attr, clock_id] = check_arg_count(args)?; + let &[ref attr, ref clock_id] = check_arg_count(args)?; let result = this.pthread_condattr_setclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_getclock" => { - let &[attr, clock_id] = check_arg_count(args)?; + let &[ref attr, ref clock_id] = check_arg_count(args)?; let result = this.pthread_condattr_getclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -137,7 +137,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if args.is_empty() { throw_ub_format!("incorrect number of arguments for syscall: got 0, expected at least 1"); } - match this.read_scalar(args[0])?.to_machine_usize(this)? { + match this.read_scalar(&args[0])?.to_machine_usize(this)? { // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` // is called if a `HashMap` is created the regular way (e.g. HashMap). id if id == sys_getrandom => { @@ -145,7 +145,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if args.len() < 4 { throw_ub_format!("incorrect number of arguments for `getrandom` syscall: got {}, expected at least 4", args.len()); } - getrandom(this, args[1], args[2], args[3], dest)?; + getrandom(this, &args[1], &args[2], &args[3], dest)?; } // `statx` is used by `libstd` to retrieve metadata information on `linux` // instead of using `stat`,`lstat` or `fstat` as on `macos`. @@ -154,7 +154,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if args.len() < 6 { throw_ub_format!("incorrect number of arguments for `statx` syscall: got {}, expected at least 6", args.len()); } - let result = this.linux_statx(args[1], args[2], args[3], args[4], args[5])?; + let result = this.linux_statx(&args[1], &args[2], &args[3], &args[4], &args[5])?; this.write_scalar(Scalar::from_machine_isize(result.into(), this), dest)?; } // `futex` is used by some synchonization primitives. @@ -167,11 +167,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscelanneous "getrandom" => { - let &[ptr, len, flags] = check_arg_count(args)?; + let &[ref ptr, ref len, ref flags] = check_arg_count(args)?; getrandom(this, ptr, len, flags, dest)?; } "sched_getaffinity" => { - let &[pid, cpusetsize, mask] = check_arg_count(args)?; + let &[ref pid, ref cpusetsize, ref mask] = check_arg_count(args)?; this.read_scalar(pid)?.to_i32()?; this.read_scalar(cpusetsize)?.to_machine_usize(this)?; this.deref_operand(mask)?; @@ -184,7 +184,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "pthread_getattr_np" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - let &[_thread, _attr] = check_arg_count(args)?; + let &[ref _thread, ref _attr] = check_arg_count(args)?; this.write_null(dest)?; } @@ -198,10 +198,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Shims the linux `getrandom` syscall. fn getrandom<'tcx>( this: &mut MiriEvalContext<'_, 'tcx>, - ptr: OpTy<'tcx, Tag>, - len: OpTy<'tcx, Tag>, - flags: OpTy<'tcx, Tag>, - dest: PlaceTy<'tcx, Tag>, + ptr: &OpTy<'tcx, Tag>, + len: &OpTy<'tcx, Tag>, + flags: &OpTy<'tcx, Tag>, + dest: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_machine_usize(this)?; diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 5243431194eb..fdd11fd73e40 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -7,7 +7,7 @@ use std::time::{Instant, SystemTime}; pub fn futex<'tcx>( this: &mut MiriEvalContext<'_, 'tcx>, args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag>, + dest: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { // The amount of arguments used depends on the type of futex operation. // The full futex syscall takes six arguments (excluding the syscall @@ -24,9 +24,9 @@ pub fn futex<'tcx>( // The first three arguments (after the syscall number itself) are the same to all futex operations: // (int *addr, int op, int val). // We checked above that these definitely exist. - let addr = this.read_immediate(args[1])?; - let op = this.read_scalar(args[2])?.to_i32()?; - let val = this.read_scalar(args[3])?.to_i32()?; + let addr = this.read_immediate(&args[1])?; + let op = this.read_scalar(&args[2])?.to_i32()?; + let val = this.read_scalar(&args[3])?.to_i32()?; // The raw pointer value is used to identify the mutex. // Not all mutex operations actually read from this address or even require this address to exist. @@ -51,7 +51,7 @@ pub fn futex<'tcx>( if args.len() < 5 { throw_ub_format!("incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT`: got {}, expected at least 5", args.len()); } - let timeout = args[4]; + let timeout = &args[4]; let timeout_time = if this.is_null(this.read_scalar(timeout)?.check_init()?)? { None } else { @@ -88,7 +88,7 @@ pub fn futex<'tcx>( // SeqCst is total order over all operations. // FIXME: check if this should be changed when weak memory orders are added. let futex_val = this.read_scalar_at_offset_atomic( - addr.into(), 0, this.machine.layouts.i32, AtomicReadOp::SeqCst + &addr.into(), 0, this.machine.layouts.i32, AtomicReadOp::SeqCst )?.to_i32()?; if val == futex_val { // The value still matches, so we block the trait make it wait for FUTEX_WAKE. @@ -98,6 +98,7 @@ pub fn futex<'tcx>( this.write_scalar(Scalar::from_machine_isize(0, this), dest)?; // Register a timeout callback if a timeout was specified. // This callback will override the return value when the timeout triggers. + let dest = *dest; if let Some(timeout_time) = timeout_time { this.register_timeout_callback( thread, @@ -107,7 +108,7 @@ pub fn futex<'tcx>( this.futex_remove_waiter(futex_ptr, thread); let etimedout = this.eval_libc("ETIMEDOUT")?; this.set_last_error(etimedout)?; - this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?; + this.write_scalar(Scalar::from_machine_isize(-1, this), &dest)?; Ok(()) }), ); diff --git a/src/shims/posix/macos/dlsym.rs b/src/shims/posix/macos/dlsym.rs index 5b59cf27ee3b..7f3958797449 100644 --- a/src/shims/posix/macos/dlsym.rs +++ b/src/shims/posix/macos/dlsym.rs @@ -28,7 +28,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, dlsym: Dlsym, args: &[OpTy<'tcx, Tag>], - ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (dest, ret) = ret.expect("we don't support any diverging dlsym"); @@ -36,7 +36,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match dlsym { Dlsym::getentropy => { - let &[ptr, len] = check_arg_count(args)?; + let &[ref ptr, ref len] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_machine_usize(this)?; this.gen_random(ptr, len)?; @@ -44,7 +44,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - trace!("{:?}", this.dump_place(*dest)); + trace!("{:?}", this.dump_place(**dest)); this.go_to_block(ret); Ok(()) } diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index a4b0ce524df2..1ea12148303e 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -11,7 +11,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, link_name: &str, args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag>, + dest: &PlaceTy<'tcx, Tag>, _ret: mir::BasicBlock, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); @@ -26,37 +26,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "close" | "close$NOCANCEL" => { - let &[result] = check_arg_count(args)?; + let &[ref result] = check_arg_count(args)?; let result = this.close(result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "stat" | "stat$INODE64" => { - let &[path, buf] = check_arg_count(args)?; + let &[ref path, ref buf] = check_arg_count(args)?; let result = this.macos_stat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lstat" | "lstat$INODE64" => { - let &[path, buf] = check_arg_count(args)?; + let &[ref path, ref buf] = check_arg_count(args)?; let result = this.macos_lstat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fstat" | "fstat$INODE64" => { - let &[fd, buf] = check_arg_count(args)?; + let &[ref fd, ref buf] = check_arg_count(args)?; let result = this.macos_fstat(fd, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" | "opendir$INODE64" => { - let &[name] = check_arg_count(args)?; + let &[ref name] = check_arg_count(args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir_r" | "readdir_r$INODE64" => { - let &[dirp, entry, result] = check_arg_count(args)?; + let &[ref dirp, ref entry, ref result] = check_arg_count(args)?; let result = this.macos_readdir_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate" => { - let &[fd, length] = check_arg_count(args)?; + let &[ref fd, ref length] = check_arg_count(args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -69,7 +69,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "gettimeofday" => { - let &[tv, tz] = check_arg_count(args)?; + let &[ref tv, ref tz] = check_arg_count(args)?; let result = this.gettimeofday(tv, tz)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -80,7 +80,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "mach_timebase_info" => { - let &[info] = check_arg_count(args)?; + let &[ref info] = check_arg_count(args)?; let result = this.mach_timebase_info(info)?; this.write_scalar(Scalar::from_i32(result), dest)?; }, @@ -97,7 +97,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "_tlv_atexit" => { - let &[dtor, data] = check_arg_count(args)?; + let &[ref dtor, ref data] = check_arg_count(args)?; let dtor = this.read_scalar(dtor)?.check_init()?; let dtor = this.memory.get_fn(dtor)?.as_instance()?; let data = this.read_scalar(data)?.check_init()?; @@ -107,13 +107,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_get_stackaddr_np" => { - let &[thread] = check_arg_count(args)?; + let &[ref thread] = check_arg_count(args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size()); this.write_scalar(stack_addr, dest)?; } "pthread_get_stacksize_np" => { - let &[thread] = check_arg_count(args)?; + let &[ref thread] = check_arg_count(args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size()); this.write_scalar(stack_size, dest)?; @@ -121,7 +121,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_setname_np" => { - let &[name] = check_arg_count(args)?; + let &[ref name] = check_arg_count(args)?; let name = this.read_scalar(name)?.check_init()?; this.pthread_setname_np(name)?; } @@ -130,7 +130,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These shims are enabled only when the caller is in the standard library. "mmap" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. - let &[addr, _, _, _, _, _] = check_arg_count(args)?; + let &[ref addr, _, _, _, _, _] = check_arg_count(args)?; let addr = this.read_scalar(addr)?.check_init()?; this.write_scalar(addr, dest)?; } diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 868c72289a1a..0688614a383d 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -35,14 +35,14 @@ fn is_mutex_kind_normal<'mir, 'tcx: 'mir>( fn mutexattr_get_kind<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, - attr_op: OpTy<'tcx, Tag>, + attr_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset(attr_op, 0, ecx.machine.layouts.i32) } fn mutexattr_set_kind<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - attr_op: OpTy<'tcx, Tag>, + attr_op: &OpTy<'tcx, Tag>, kind: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset(attr_op, 0, kind, ecx.machine.layouts.i32) @@ -59,7 +59,7 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( fn mutex_get_kind<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - mutex_op: OpTy<'tcx, Tag>, + mutex_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; ecx.read_scalar_at_offset_atomic( @@ -70,7 +70,7 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>( fn mutex_set_kind<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - mutex_op: OpTy<'tcx, Tag>, + mutex_op: &OpTy<'tcx, Tag>, kind: impl Into>, ) -> InterpResult<'tcx, ()> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; @@ -82,7 +82,7 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( fn mutex_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, - mutex_op: OpTy<'tcx, Tag>, + mutex_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset_atomic( mutex_op, 4, ecx.machine.layouts.u32, @@ -92,7 +92,7 @@ fn mutex_get_id<'mir, 'tcx: 'mir>( fn mutex_set_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - mutex_op: OpTy<'tcx, Tag>, + mutex_op: &OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset_atomic( @@ -103,7 +103,7 @@ fn mutex_set_id<'mir, 'tcx: 'mir>( fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - mutex_op: OpTy<'tcx, Tag>, + mutex_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, MutexId> { let id = mutex_get_id(ecx, mutex_op)?.to_u32()?; if id == 0 { @@ -126,7 +126,7 @@ fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( fn rwlock_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, - rwlock_op: OpTy<'tcx, Tag>, + rwlock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset_atomic( rwlock_op, 4, ecx.machine.layouts.u32, @@ -136,7 +136,7 @@ fn rwlock_get_id<'mir, 'tcx: 'mir>( fn rwlock_set_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - rwlock_op: OpTy<'tcx, Tag>, + rwlock_op: &OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset_atomic( @@ -147,7 +147,7 @@ fn rwlock_set_id<'mir, 'tcx: 'mir>( fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - rwlock_op: OpTy<'tcx, Tag>, + rwlock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, RwLockId> { let id = rwlock_get_id(ecx, rwlock_op)?.to_u32()?; if id == 0 { @@ -169,14 +169,14 @@ fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( fn condattr_get_clock_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, - attr_op: OpTy<'tcx, Tag>, + attr_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset(attr_op, 0, ecx.machine.layouts.i32) } fn condattr_set_clock_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - attr_op: OpTy<'tcx, Tag>, + attr_op: &OpTy<'tcx, Tag>, clock_id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset(attr_op, 0, clock_id, ecx.machine.layouts.i32) @@ -193,7 +193,7 @@ fn condattr_set_clock_id<'mir, 'tcx: 'mir>( fn cond_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, - cond_op: OpTy<'tcx, Tag>, + cond_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset_atomic( cond_op, 4, ecx.machine.layouts.u32, @@ -203,7 +203,7 @@ fn cond_get_id<'mir, 'tcx: 'mir>( fn cond_set_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - cond_op: OpTy<'tcx, Tag>, + cond_op: &OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset_atomic( @@ -214,7 +214,7 @@ fn cond_set_id<'mir, 'tcx: 'mir>( fn cond_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - cond_op: OpTy<'tcx, Tag>, + cond_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, CondvarId> { let id = cond_get_id(ecx, cond_op)?.to_u32()?; if id == 0 { @@ -230,14 +230,14 @@ fn cond_get_or_create_id<'mir, 'tcx: 'mir>( fn cond_get_clock_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, - cond_op: OpTy<'tcx, Tag>, + cond_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset(cond_op, 8, ecx.machine.layouts.i32) } fn cond_set_clock_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - cond_op: OpTy<'tcx, Tag>, + cond_op: &OpTy<'tcx, Tag>, clock_id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset(cond_op, 8, clock_id, ecx.machine.layouts.i32) @@ -294,7 +294,7 @@ fn release_cond_mutex_and_block<'mir, 'tcx: 'mir>( impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn pthread_mutexattr_init(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_mutexattr_init(&mut self, attr_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let default_kind = this.eval_libc("PTHREAD_MUTEX_DEFAULT")?; @@ -305,8 +305,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutexattr_settype( &mut self, - attr_op: OpTy<'tcx, Tag>, - kind_op: OpTy<'tcx, Tag>, + attr_op: &OpTy<'tcx, Tag>, + kind_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -344,7 +344,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_mutexattr_destroy(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_mutexattr_destroy(&mut self, attr_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); mutexattr_set_kind(this, attr_op, ScalarMaybeUninit::Uninit)?; @@ -354,8 +354,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_init( &mut self, - mutex_op: OpTy<'tcx, Tag>, - attr_op: OpTy<'tcx, Tag>, + mutex_op: &OpTy<'tcx, Tag>, + attr_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -374,7 +374,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_mutex_lock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_mutex_lock(&mut self, mutex_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let kind = mutex_get_kind(this, mutex_op)?.check_init()?; @@ -411,7 +411,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn pthread_mutex_trylock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_mutex_trylock(&mut self, mutex_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let kind = mutex_get_kind(this, mutex_op)?.check_init()?; @@ -444,7 +444,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn pthread_mutex_unlock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_mutex_unlock(&mut self, mutex_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let kind = mutex_get_kind(this, mutex_op)?.check_init()?; @@ -476,7 +476,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn pthread_mutex_destroy(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_mutex_destroy(&mut self, mutex_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = mutex_get_or_create_id(this, mutex_op)?; @@ -492,7 +492,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_rwlock_rdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_rdlock(&mut self, rwlock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; @@ -507,7 +507,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; @@ -521,7 +521,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn pthread_rwlock_wrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_wrlock(&mut self, rwlock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; @@ -548,7 +548,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_rwlock_trywrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_trywrlock(&mut self, rwlock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; @@ -562,7 +562,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn pthread_rwlock_unlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_unlock(&mut self, rwlock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; @@ -577,7 +577,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn pthread_rwlock_destroy(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_destroy(&mut self, rwlock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; @@ -592,7 +592,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_condattr_init(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_condattr_init(&mut self, attr_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); // The default value of the clock attribute shall refer to the system @@ -606,8 +606,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_condattr_setclock( &mut self, - attr_op: OpTy<'tcx, Tag>, - clock_id_op: OpTy<'tcx, Tag>, + attr_op: &OpTy<'tcx, Tag>, + clock_id_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -626,18 +626,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_condattr_getclock( &mut self, - attr_op: OpTy<'tcx, Tag>, - clk_id_op: OpTy<'tcx, Tag>, + attr_op: &OpTy<'tcx, Tag>, + clk_id_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let clock_id = condattr_get_clock_id(this, attr_op)?; - this.write_scalar(clock_id, this.deref_operand(clk_id_op)?.into())?; + this.write_scalar(clock_id, &this.deref_operand(clk_id_op)?.into())?; Ok(0) } - fn pthread_condattr_destroy(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_condattr_destroy(&mut self, attr_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); condattr_set_clock_id(this, attr_op, ScalarMaybeUninit::Uninit)?; @@ -647,8 +647,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_cond_init( &mut self, - cond_op: OpTy<'tcx, Tag>, - attr_op: OpTy<'tcx, Tag>, + cond_op: &OpTy<'tcx, Tag>, + attr_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -667,7 +667,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_cond_signal(&mut self, cond_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_cond_signal(&mut self, cond_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = cond_get_or_create_id(this, cond_op)?; if let Some((thread, mutex)) = this.condvar_signal(id) { @@ -677,7 +677,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_cond_broadcast(&mut self, cond_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_cond_broadcast(&mut self, cond_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = cond_get_or_create_id(this, cond_op)?; @@ -690,8 +690,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_cond_wait( &mut self, - cond_op: OpTy<'tcx, Tag>, - mutex_op: OpTy<'tcx, Tag>, + cond_op: &OpTy<'tcx, Tag>, + mutex_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -707,10 +707,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_cond_timedwait( &mut self, - cond_op: OpTy<'tcx, Tag>, - mutex_op: OpTy<'tcx, Tag>, - abstime_op: OpTy<'tcx, Tag>, - dest: PlaceTy<'tcx, Tag>, + cond_op: &OpTy<'tcx, Tag>, + mutex_op: &OpTy<'tcx, Tag>, + abstime_op: &OpTy<'tcx, Tag>, + dest: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -745,6 +745,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We return success for now and override it in the timeout callback. this.write_scalar(Scalar::from_i32(0), dest)?; + let dest = *dest; + // Register the timeout callback. this.register_timeout_callback( active_thread, @@ -759,7 +761,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Set the return value: we timed out. let etimedout = ecx.eval_libc("ETIMEDOUT")?; - ecx.write_scalar(etimedout, dest)?; + ecx.write_scalar(etimedout, &dest)?; Ok(()) }), @@ -768,7 +770,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - fn pthread_cond_destroy(&mut self, cond_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_cond_destroy(&mut self, cond_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = cond_get_or_create_id(this, cond_op)?; diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index 0ea20cdff6cb..40663326b465 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -7,10 +7,10 @@ impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tc pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn pthread_create( &mut self, - thread: OpTy<'tcx, Tag>, - _attr: OpTy<'tcx, Tag>, - start_routine: OpTy<'tcx, Tag>, - arg: OpTy<'tcx, Tag>, + thread: &OpTy<'tcx, Tag>, + _attr: &OpTy<'tcx, Tag>, + start_routine: &OpTy<'tcx, Tag>, + arg: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -26,7 +26,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let thread_info_place = this.deref_operand(thread)?; this.write_scalar( Scalar::from_uint(new_thread_id.to_u32(), thread_info_place.layout.size), - thread_info_place.into(), + &thread_info_place.into(), )?; // Read the function argument that will be sent to the new thread @@ -51,7 +51,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.call_function( instance, &[*func_arg], - Some(ret_place.into()), + Some(&ret_place.into()), StackPopCleanup::None { cleanup: true }, )?; @@ -63,8 +63,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_join( &mut self, - thread: OpTy<'tcx, Tag>, - retval: OpTy<'tcx, Tag>, + thread: &OpTy<'tcx, Tag>, + retval: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -79,7 +79,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_detach(&mut self, thread: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_detach(&mut self, thread: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let thread_id = this.read_scalar(thread)?.to_machine_usize(this)?; @@ -88,7 +88,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_self(&mut self, dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn pthread_self(&mut self, dest: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let thread_id = this.get_active_thread(); @@ -97,11 +97,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn prctl( &mut self, - option: OpTy<'tcx, Tag>, - arg2: OpTy<'tcx, Tag>, - _arg3: OpTy<'tcx, Tag>, - _arg4: OpTy<'tcx, Tag>, - _arg5: OpTy<'tcx, Tag>, + option: &OpTy<'tcx, Tag>, + arg2: &OpTy<'tcx, Tag>, + _arg3: &OpTy<'tcx, Tag>, + _arg4: &OpTy<'tcx, Tag>, + _arg5: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("linux", "prctl"); diff --git a/src/shims/time.rs b/src/shims/time.rs index 806fa65d1564..5af2e5ab67e7 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -16,8 +16,8 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn clock_gettime( &mut self, - clk_id_op: OpTy<'tcx, Tag>, - tp_op: OpTy<'tcx, Tag>, + clk_id_op: &OpTy<'tcx, Tag>, + tp_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -47,15 +47,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_int_checked(tv_nsec, this.libc_ty_layout("c_long")?)?, ]; - this.write_packed_immediates(tp, &imms)?; + this.write_packed_immediates(&tp, &imms)?; Ok(0) } fn gettimeofday( &mut self, - tv_op: OpTy<'tcx, Tag>, - tz_op: OpTy<'tcx, Tag>, + tv_op: &OpTy<'tcx, Tag>, + tz_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -81,13 +81,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_int_checked(tv_usec, this.libc_ty_layout("suseconds_t")?)?, ]; - this.write_packed_immediates(tv, &imms)?; + this.write_packed_immediates(&tv, &imms)?; Ok(0) } #[allow(non_snake_case)] - fn GetSystemTimeAsFileTime(&mut self, LPFILETIME_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn GetSystemTimeAsFileTime(&mut self, LPFILETIME_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.assert_target_os("windows", "GetSystemTimeAsFileTime"); @@ -110,12 +110,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(dwLowDateTime, DWORD_tylayout)?, immty_from_uint_checked(dwHighDateTime, DWORD_tylayout)?, ]; - this.write_packed_immediates(this.deref_operand(LPFILETIME_op)?, &imms)?; + this.write_packed_immediates(&this.deref_operand(LPFILETIME_op)?, &imms)?; Ok(()) } #[allow(non_snake_case)] - fn QueryPerformanceCounter(&mut self, lpPerformanceCount_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn QueryPerformanceCounter(&mut self, lpPerformanceCount_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("windows", "QueryPerformanceCounter"); @@ -126,12 +126,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let duration = Instant::now().duration_since(this.machine.time_anchor); let qpc = i64::try_from(duration.as_nanos()) .map_err(|_| err_unsup_format!("programs running longer than 2^63 nanoseconds are not supported"))?; - this.write_scalar(Scalar::from_i64(qpc), this.deref_operand(lpPerformanceCount_op)?.into())?; + this.write_scalar(Scalar::from_i64(qpc), &this.deref_operand(lpPerformanceCount_op)?.into())?; Ok(-1) // return non-zero on success } #[allow(non_snake_case)] - fn QueryPerformanceFrequency(&mut self, lpFrequency_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn QueryPerformanceFrequency(&mut self, lpFrequency_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("windows", "QueryPerformanceFrequency"); @@ -142,7 +142,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // is consistent across all processors. // Miri emulates a "hardware" performance counter with a resolution of 1ns, // and thus 10^9 counts per second. - this.write_scalar(Scalar::from_i64(1_000_000_000), this.deref_operand(lpFrequency_op)?.into())?; + this.write_scalar(Scalar::from_i64(1_000_000_000), &this.deref_operand(lpFrequency_op)?.into())?; Ok(-1) // Return non-zero on success } @@ -159,7 +159,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .map_err(|_| err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported").into()) } - fn mach_timebase_info(&mut self, info_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn mach_timebase_info(&mut self, info_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("macos", "mach_timebase_info"); @@ -175,14 +175,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_int_checked(denom, this.machine.layouts.u32)? ]; - this.write_packed_immediates(info, &imms)?; + this.write_packed_immediates(&info, &imms)?; Ok(0) // KERN_SUCCESS } fn nanosleep( &mut self, - req_op: OpTy<'tcx, Tag>, - _rem: OpTy<'tcx, Tag>, + req_op: &OpTy<'tcx, Tag>, + _rem: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { // Signal handlers are not supported, so rem will never be written to. diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 2ca860367eff..7f19fd167366 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -245,7 +245,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.call_function( thread_callback, &[Scalar::null_ptr(this).into(), reason.into(), Scalar::null_ptr(this).into()], - Some(ret_place), + Some(&ret_place), StackPopCleanup::None { cleanup: true }, )?; @@ -267,7 +267,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.call_function( instance, &[data.into()], - Some(ret_place), + Some(&ret_place), StackPopCleanup::None { cleanup: true }, )?; @@ -307,7 +307,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.call_function( instance, &[ptr.into()], - Some(ret_place), + Some(&ret_place), StackPopCleanup::None { cleanup: true }, )?; diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 57766bd344a4..1f136060259a 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -26,7 +26,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dlsym: Dlsym, abi: Abi, _args: &[OpTy<'tcx, Tag>], - ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (_dest, _ret) = ret.expect("we don't support any diverging dlsym"); diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 0eeec08901db..f8d62f6b323b 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -15,7 +15,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx link_name: &str, abi: Abi, args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag>, + dest: &PlaceTy<'tcx, Tag>, _ret: mir::BasicBlock, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); @@ -30,12 +30,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Environment related shims "GetEnvironmentVariableW" => { - let &[name, buf, size] = check_arg_count(args)?; + let &[ref name, ref buf, ref size] = check_arg_count(args)?; let result = this.GetEnvironmentVariableW(name, buf, size)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetEnvironmentVariableW" => { - let &[name, value] = check_arg_count(args)?; + let &[ref name, ref value] = check_arg_count(args)?; let result = this.SetEnvironmentVariableW(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -45,38 +45,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(result, dest)?; } "FreeEnvironmentStringsW" => { - let &[env_block] = check_arg_count(args)?; + let &[ref env_block] = check_arg_count(args)?; let result = this.FreeEnvironmentStringsW(env_block)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetCurrentDirectoryW" => { - let &[size, buf] = check_arg_count(args)?; + let &[ref size, ref buf] = check_arg_count(args)?; let result = this.GetCurrentDirectoryW(size, buf)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetCurrentDirectoryW" => { - let &[path] = check_arg_count(args)?; + let &[ref path] = check_arg_count(args)?; let result = this.SetCurrentDirectoryW(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // File related shims "GetStdHandle" => { - let &[which] = check_arg_count(args)?; + let &[ref which] = check_arg_count(args)?; let which = this.read_scalar(which)?.to_i32()?; // We just make this the identity function, so we know later in `WriteFile` // which one it is. this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?; } "WriteFile" => { - let &[handle, buf, n, written_ptr, overlapped] = check_arg_count(args)?; + let &[ref handle, ref buf, ref n, ref written_ptr, ref overlapped] = check_arg_count(args)?; this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore let handle = this.read_scalar(handle)?.to_machine_isize(this)?; let buf = this.read_scalar(buf)?.check_init()?; let n = this.read_scalar(n)?.to_u32()?; let written_place = this.deref_operand(written_ptr)?; // Spec says to always write `0` first. - this.write_null(written_place.into())?; + this.write_null(&written_place.into())?; let written = if handle == -11 || handle == -12 { // stdout/stderr use std::io::{self, Write}; @@ -93,7 +93,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // If there was no error, write back how much was written. if let Some(n) = written { - this.write_scalar(Scalar::from_u32(n), written_place.into())?; + this.write_scalar(Scalar::from_u32(n), &written_place.into())?; } // Return whether this was a success. this.write_scalar( @@ -104,7 +104,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Allocation "HeapAlloc" => { - let &[handle, flags, size] = check_arg_count(args)?; + let &[ref handle, ref flags, ref size] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; let flags = this.read_scalar(flags)?.to_u32()?; let size = this.read_scalar(size)?.to_machine_usize(this)?; @@ -113,7 +113,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } "HeapFree" => { - let &[handle, flags, ptr] = check_arg_count(args)?; + let &[ref handle, ref flags, ref ptr] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; let ptr = this.read_scalar(ptr)?.check_init()?; @@ -121,7 +121,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(1), dest)?; } "HeapReAlloc" => { - let &[handle, flags, ptr, size] = check_arg_count(args)?; + let &[ref handle, ref flags, ref ptr, ref size] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; let ptr = this.read_scalar(ptr)?.check_init()?; @@ -132,7 +132,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // errno "SetLastError" => { - let &[error] = check_arg_count(args)?; + let &[ref error] = check_arg_count(args)?; let error = this.read_scalar(error)?.check_init()?; this.set_last_error(error)?; } @@ -144,7 +144,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "GetSystemInfo" => { - let &[system_info] = check_arg_count(args)?; + let &[ref system_info] = check_arg_count(args)?; let system_info = this.deref_operand(system_info)?; // Initialize with `0`. this.memory.write_bytes( @@ -153,8 +153,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; // Set number of processors. let dword_size = Size::from_bytes(4); - let num_cpus = this.mplace_field(system_info, 6)?; - this.write_scalar(Scalar::from_int(NUM_CPUS, dword_size), num_cpus.into())?; + let num_cpus = this.mplace_field(&system_info, 6)?; + this.write_scalar(Scalar::from_int(NUM_CPUS, dword_size), &num_cpus.into())?; } // Thread-local storage @@ -167,14 +167,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { - let &[key] = check_arg_count(args)?; + let &[ref key] = check_arg_count(args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "TlsSetValue" => { - let &[key, new_ptr] = check_arg_count(args)?; + let &[ref key, ref new_ptr] = check_arg_count(args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); let new_ptr = this.read_scalar(new_ptr)?.check_init()?; @@ -196,46 +196,46 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "GetSystemTimeAsFileTime" => { #[allow(non_snake_case)] - let &[LPFILETIME] = check_arg_count(args)?; + let &[ref LPFILETIME] = check_arg_count(args)?; this.GetSystemTimeAsFileTime(LPFILETIME)?; } "QueryPerformanceCounter" => { #[allow(non_snake_case)] - let &[lpPerformanceCount] = check_arg_count(args)?; + let &[ref lpPerformanceCount] = check_arg_count(args)?; let result = this.QueryPerformanceCounter(lpPerformanceCount)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "QueryPerformanceFrequency" => { #[allow(non_snake_case)] - let &[lpFrequency] = check_arg_count(args)?; + let &[ref lpFrequency] = check_arg_count(args)?; let result = this.QueryPerformanceFrequency(lpFrequency)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Synchronization primitives "AcquireSRWLockExclusive" => { - let &[ptr] = check_arg_count(args)?; + let &[ref ptr] = check_arg_count(args)?; this.AcquireSRWLockExclusive(ptr)?; } "ReleaseSRWLockExclusive" => { - let &[ptr] = check_arg_count(args)?; + let &[ref ptr] = check_arg_count(args)?; this.ReleaseSRWLockExclusive(ptr)?; } "TryAcquireSRWLockExclusive" => { - let &[ptr] = check_arg_count(args)?; + let &[ref ptr] = check_arg_count(args)?; let ret = this.TryAcquireSRWLockExclusive(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; } "AcquireSRWLockShared" => { - let &[ptr] = check_arg_count(args)?; + let &[ref ptr] = check_arg_count(args)?; this.AcquireSRWLockShared(ptr)?; } "ReleaseSRWLockShared" => { - let &[ptr] = check_arg_count(args)?; + let &[ref ptr] = check_arg_count(args)?; this.ReleaseSRWLockShared(ptr)?; } "TryAcquireSRWLockShared" => { - let &[ptr] = check_arg_count(args)?; + let &[ref ptr] = check_arg_count(args)?; let ret = this.TryAcquireSRWLockShared(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; } @@ -243,7 +243,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamic symbol loading "GetProcAddress" => { #[allow(non_snake_case)] - let &[hModule, lpProcName] = check_arg_count(args)?; + let &[ref hModule, ref lpProcName] = check_arg_count(args)?; this.read_scalar(hModule)?.to_machine_isize(this)?; let name = this.memory.read_c_str(this.read_scalar(lpProcName)?.check_init()?)?; if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.os)? { @@ -257,7 +257,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscellaneous "SystemFunction036" => { // The actual name of 'RtlGenRandom' - let &[ptr, len] = check_arg_count(args)?; + let &[ref ptr, ref len] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_u32()?; this.gen_random(ptr, len.into())?; @@ -265,7 +265,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "GetConsoleScreenBufferInfo" => { // `term` needs this, so we fake it. - let &[console, buffer_info] = check_arg_count(args)?; + let &[ref console, ref buffer_info] = check_arg_count(args)?; this.read_scalar(console)?.to_machine_isize(this)?; this.deref_operand(buffer_info)?; // Indicate an error. @@ -274,7 +274,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "GetConsoleMode" => { // Windows "isatty" (in libtest) needs this, so we fake it. - let &[console, mode] = check_arg_count(args)?; + let &[ref console, ref mode] = check_arg_count(args)?; this.read_scalar(console)?.to_machine_isize(this)?; this.deref_operand(mode)?; // Indicate an error. @@ -302,13 +302,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] - let &[_hConsoleOutput, _wAttribute] = check_arg_count(args)?; + let &[ref _hConsoleOutput, ref _wAttribute] = check_arg_count(args)?; // Pretend these does not exist / nothing happened, by returning zero. this.write_null(dest)?; } "AddVectoredExceptionHandler" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] - let &[_First, _Handler] = check_arg_count(args)?; + let &[ref _First, ref _Handler] = check_arg_count(args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_machine_usize(1, this), dest)?; } @@ -324,7 +324,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "DeleteCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] - let &[_lpCriticalSection] = check_arg_count(args)?; + let &[ref _lpCriticalSection] = check_arg_count(args)?; assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); // Nothing to do, not even a return value. // (Windows locks are reentrant, and we have only 1 thread, @@ -333,7 +333,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "TryEnterCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] - let &[_lpCriticalSection] = check_arg_count(args)?; + let &[ref _lpCriticalSection] = check_arg_count(args)?; assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); // There is only one thread, so this always succeeds and returns TRUE. this.write_scalar(Scalar::from_i32(1), dest)?; diff --git a/src/shims/windows/sync.rs b/src/shims/windows/sync.rs index 7bad3c08a598..caf8942afd93 100644 --- a/src/shims/windows/sync.rs +++ b/src/shims/windows/sync.rs @@ -5,7 +5,7 @@ use crate::*; fn srwlock_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - lock_op: OpTy<'tcx, Tag>, + lock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, RwLockId> { let id = ecx.read_scalar_at_offset(lock_op, 0, ecx.machine.layouts.u32)?.to_u32()?; if id == 0 { @@ -24,7 +24,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn AcquireSRWLockExclusive( &mut self, - lock_op: OpTy<'tcx, Tag>, + lock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; @@ -49,7 +49,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn TryAcquireSRWLockExclusive( &mut self, - lock_op: OpTy<'tcx, Tag>, + lock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, u8> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; @@ -67,7 +67,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn ReleaseSRWLockExclusive( &mut self, - lock_op: OpTy<'tcx, Tag>, + lock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; @@ -84,7 +84,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn AcquireSRWLockShared( &mut self, - lock_op: OpTy<'tcx, Tag>, + lock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; @@ -102,7 +102,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn TryAcquireSRWLockShared( &mut self, - lock_op: OpTy<'tcx, Tag>, + lock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, u8> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; @@ -119,7 +119,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn ReleaseSRWLockShared( &mut self, - lock_op: OpTy<'tcx, Tag>, + lock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 616950eb0a0a..52f4ddbc386c 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -521,7 +521,7 @@ impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for crate::MiriEvalContext trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn reborrow( &mut self, - place: MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Tag>, size: Size, kind: RefKind, new_tag: Tag, @@ -577,7 +577,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// `mutbl` can be `None` to make this a raw pointer. fn retag_reference( &mut self, - val: ImmTy<'tcx, Tag>, + val: &ImmTy<'tcx, Tag>, kind: RefKind, protect: bool, ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { @@ -585,7 +585,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We want a place for where the ptr *points to*, so we get one. let place = this.ref_to_mplace(val)?; let size = this - .size_and_align_of_mplace(place)? + .size_and_align_of_mplace(&place)? .map(|(size, _)| size) .unwrap_or_else(|| place.layout.size); // `reborrow` relies on getting a `Pointer` and everything being in-bounds, @@ -595,7 +595,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let place = this.mplace_access_checked(place, Some(Align::from_bytes(1).unwrap()))?; // Nothing to do for ZSTs. if size == Size::ZERO { - return Ok(val); + return Ok(*val); } // Compute new borrow. @@ -610,7 +610,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Reborrow. - this.reborrow(place, size, kind, new_tag, protect)?; + this.reborrow(&place, size, kind, new_tag, protect)?; let new_place = place.replace_tag(new_tag); // Return new pointer. @@ -620,7 +620,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn retag(&mut self, kind: RetagKind, place: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn retag(&mut self, kind: RetagKind, place: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); // Determine mutability and whether to add a protector. // Cannot use `builtin_deref` because that reports *immutable* for `Box`, @@ -649,8 +649,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // but might also cost us optimization and analyses. We will have to experiment more with this. if let Some((mutbl, protector)) = qualify(place.layout.ty, kind) { // Fast path. - let val = this.read_immediate(this.place_to_op(place)?)?; - let val = this.retag_reference(val, mutbl, protector)?; + let val = this.read_immediate(&this.place_to_op(place)?)?; + let val = this.retag_reference(&val, mutbl, protector)?; this.write_immediate(*val, place)?; } @@ -675,16 +675,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(()); } // We need this to be in-memory to use tagged pointers. - let return_place = this.force_allocation(return_place)?; + let return_place = this.force_allocation(&return_place)?; // We have to turn the place into a pointer to use the existing code. // (The pointer type does not matter, so we use a raw pointer.) let ptr_layout = this.layout_of(this.tcx.mk_mut_ptr(return_place.layout.ty))?; let val = ImmTy::from_immediate(return_place.to_ref(), ptr_layout); // Reborrow it. - let val = this.retag_reference(val, RefKind::Unique { two_phase: false }, /*protector*/ true)?; + let val = this.retag_reference(&val, RefKind::Unique { two_phase: false }, /*protector*/ true)?; // And use reborrowed pointer for return place. - let return_place = this.ref_to_mplace(val)?; + let return_place = this.ref_to_mplace(&val)?; this.frame_mut().return_place = Some(return_place.into()); Ok(()) From c003fd0157e0b19f0fba8d3491423d6bf678d873 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Feb 2021 09:23:49 +0100 Subject: [PATCH 2554/5092] rustup --- rust-version | 2 +- tests/compile-fail/transmute-pair-uninit.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 6c6212ec839c..f76caa2c0f33 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e7c23ab933ebc1f205c3b59f4ebc85d40f67d404 +a4e595db8f12f9ee926256745d757004b850703f diff --git a/tests/compile-fail/transmute-pair-uninit.rs b/tests/compile-fail/transmute-pair-uninit.rs index 0f02697f2615..42aa7a969278 100644 --- a/tests/compile-fail/transmute-pair-uninit.rs +++ b/tests/compile-fail/transmute-pair-uninit.rs @@ -17,6 +17,6 @@ fn main() { assert_eq!(byte, 0); } let v = unsafe { *z.offset(first_undef) }; - if v == 0 {} + if v == 0 { println!("it is zero"); } //~^ ERROR this operation requires initialized memory } From f85bb0fb09a1932cdc17ebb0dcd13b81c93346f7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Feb 2021 12:24:58 +0100 Subject: [PATCH 2555/5092] test for unnecessary rebuilds in 'cargo miri run' --- test-cargo-miri/run-test.py | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 8edd947c3b0f..0505b422d95f 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -15,8 +15,10 @@ def fail(msg): print("\nTEST FAIL: {}".format(msg)) sys.exit(1) -def cargo_miri(cmd): - args = ["cargo", "miri", cmd, "-q"] +def cargo_miri(cmd, quiet = True): + args = ["cargo", "miri", cmd] + if quiet: + args += ["-q"] if 'MIRI_TEST_TARGET' in os.environ: args += ["--target", os.environ['MIRI_TEST_TARGET']] return args @@ -48,6 +50,25 @@ def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): print("--- END stderr ---") fail("exit code was {}".format(p.returncode)) +def test_rebuild(name, cmd, rebuild_count_expected): + print("Testing {}...".format(name)) + p = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + (stdout, stderr) = p.communicate() + stdout = stdout.decode("UTF-8") + stderr = stderr.decode("UTF-8") + if p.returncode != 0: + fail("rebuild failed"); + rebuild_count = stderr.count(" Compiling "); + if rebuild_count != rebuild_count_expected: + print("--- BEGIN stderr ---") + print(stderr, end="") + print("--- END stderr ---") + fail("Expected {} rebuild(s), but got {}".format(rebuild_count_expected, rebuild_count)); + def test_cargo_miri_run(): test("`cargo miri run` (no isolation)", cargo_miri("run"), @@ -67,6 +88,11 @@ def test_cargo_miri_run(): "run.subcrate.stdout.ref", "run.subcrate.stderr.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) + # Special test: run it again *without* `-q` to make sure nothing is being rebuilt (Miri issue #1722) + test_rebuild("`cargo miri run` (clean rebuild)", + cargo_miri("run", quiet=False) + ["--", ""], + rebuild_count_expected=1, + ) def test_cargo_miri_test(): # rustdoc is not run on foreign targets From 3e987e127c9865189af59f7878e172b9f1297de5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Feb 2021 12:32:06 +0100 Subject: [PATCH 2556/5092] create more fake files for cdylibs and staticlibs --- cargo-miri/bin.rs | 13 +++++++++---- test-cargo-miri/run-test.py | 13 +++++++------ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index cb003c0f3e8b..051f3dd3b6fc 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -692,12 +692,17 @@ fn phase_cargo_rustc(mut args: env::Args) { exec(cmd); // Create a stub .rlib file if "link" was requested by cargo. + // This is necessary to prevent cargo from doing rebuilds all the time. if emit_link_hack { // Some platforms prepend "lib", some do not... let's just create both files. - let filename = out_filename("lib", ".rlib"); - File::create(filename).expect("failed to create rlib file"); - let filename = out_filename("", ".rlib"); - File::create(filename).expect("failed to create rlib file"); + File::create(out_filename("lib", ".rlib")).expect("failed to create fake .rlib file"); + File::create(out_filename("", ".rlib")).expect("failed to create fake .rlib file"); + // Just in case this is a cdylib or staticlib, also create those fake files. + File::create(out_filename("lib", ".so")).expect("failed to create fake .so file"); + File::create(out_filename("lib", ".a")).expect("failed to create fake .a file"); + File::create(out_filename("lib", ".dylib")).expect("failed to create fake .dylib file"); + File::create(out_filename("", ".dll")).expect("failed to create fake .dll file"); + File::create(out_filename("", ".lib")).expect("failed to create fake .lib file"); } } diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 0505b422d95f..b9259b7d0d22 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -50,7 +50,7 @@ def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): print("--- END stderr ---") fail("exit code was {}".format(p.returncode)) -def test_rebuild(name, cmd, rebuild_count_expected): +def test_no_rebuild(name, cmd): print("Testing {}...".format(name)) p = subprocess.Popen( cmd, @@ -62,12 +62,12 @@ def test_rebuild(name, cmd, rebuild_count_expected): stderr = stderr.decode("UTF-8") if p.returncode != 0: fail("rebuild failed"); - rebuild_count = stderr.count(" Compiling "); - if rebuild_count != rebuild_count_expected: + # Also check for 'Running' as a sanity check. + if stderr.count(" Compiling ") > 0 or stderr.count(" Running ") == 0: print("--- BEGIN stderr ---") print(stderr, end="") print("--- END stderr ---") - fail("Expected {} rebuild(s), but got {}".format(rebuild_count_expected, rebuild_count)); + fail("Something was being rebuilt when it should not be (or we got no output)"); def test_cargo_miri_run(): test("`cargo miri run` (no isolation)", @@ -89,9 +89,10 @@ def test_cargo_miri_run(): env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) # Special test: run it again *without* `-q` to make sure nothing is being rebuilt (Miri issue #1722) - test_rebuild("`cargo miri run` (clean rebuild)", + # FIXME: move this test up to right after the first `test` + # (currently that fails, only the 3rd and later runs are really clean... see Miri issue #1722) + test_no_rebuild("`cargo miri run` (no rebuild)", cargo_miri("run", quiet=False) + ["--", ""], - rebuild_count_expected=1, ) def test_cargo_miri_test(): From 48f7c8e2e6a42b441aa21068ae526ec5affd0c40 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Feb 2021 20:03:51 +0100 Subject: [PATCH 2557/5092] fix reborrowing of tagged ZST references --- src/stacked_borrows.rs | 16 ++++++++++++---- tests/compile-fail/stacked_borrows/zst_slice.rs | 11 +++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 tests/compile-fail/stacked_borrows/zst_slice.rs diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 52f4ddbc386c..cfaf8a9005ca 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -586,15 +586,23 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let place = this.ref_to_mplace(val)?; let size = this .size_and_align_of_mplace(&place)? - .map(|(size, _)| size) - .unwrap_or_else(|| place.layout.size); + .map(|(size, _)| size); + // FIXME: If we cannot determine the size (because the unsized tail is an `extern type`), + // bail out -- we cannot reasonably figure out which memory range to reborrow. + // See https://github.com/rust-lang/unsafe-code-guidelines/issues/276. + let size = match size { + Some(size) => size, + None => return Ok(*val), + }; // `reborrow` relies on getting a `Pointer` and everything being in-bounds, // so let's ensure that. However, we do not care about alignment. // We can see dangling ptrs in here e.g. after a Box's `Unique` was // updated using "self.0 = ..." (can happen in Box::from_raw) so we cannot ICE; see miri#1050. let place = this.mplace_access_checked(place, Some(Align::from_bytes(1).unwrap()))?; - // Nothing to do for ZSTs. - if size == Size::ZERO { + // Nothing to do for ZSTs. We use `is_bits` here because we *do* need to retag even ZSTs + // when there actually is a tag (to avoid inheriting a tag that would let us access more + // than 0 bytes). + if size == Size::ZERO && place.ptr.is_bits() { return Ok(*val); } diff --git a/tests/compile-fail/stacked_borrows/zst_slice.rs b/tests/compile-fail/stacked_borrows/zst_slice.rs new file mode 100644 index 000000000000..0804f7303082 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/zst_slice.rs @@ -0,0 +1,11 @@ +// compile-flags: -Zmiri-track-raw-pointers +// error-pattern: does not have an appropriate item in the borrow stack + +fn main() { + unsafe { + let a = [1, 2, 3]; + let s = &a[0..0]; + assert_eq!(s.len(), 0); + assert_eq!(*s.get_unchecked(1), 2); + } +} From 49cd383537580861f6bfd2daa6765409ca15b119 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 28 Feb 2021 04:52:27 +0800 Subject: [PATCH 2558/5092] Create stub .d files --- cargo-miri/bin.rs | 8 ++++++++ test-cargo-miri/run-test.py | 25 ++++++++++++++----------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 051f3dd3b6fc..535acf36df73 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -609,6 +609,14 @@ fn phase_cargo_rustc(mut args: env::Args) { let print = get_arg_flag_value("--print").is_some(); // whether this is cargo passing `--print` to get some infos let store_json = |info: CrateRunInfo| { + // Create a stub .d file to stop Cargo from "rebuilding" the crate: + // https://github.com/rust-lang/miri/issues/1724#issuecomment-787115693 + // As we store a JSON file instead of building the crate here, an empty file is fine. + let dep_info_name = out_filename("", ".d"); + if verbose { + eprintln!("[cargo-miri rustc] writing dep-info to `{}`", dep_info_name.display()); + } + File::create(dep_info_name).expect("failed to create fake .d file"); let filename = out_filename("", ""); if verbose { eprintln!("[cargo-miri rustc] writing run info to `{}`", filename.display()); diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index b9259b7d0d22..3a8a32db1ede 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -50,12 +50,15 @@ def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): print("--- END stderr ---") fail("exit code was {}".format(p.returncode)) -def test_no_rebuild(name, cmd): +def test_no_rebuild(name, cmd, env={}): print("Testing {}...".format(name)) + p_env = os.environ.copy() + p_env.update(env) p = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, + env=p_env, ) (stdout, stderr) = p.communicate() stdout = stdout.decode("UTF-8") @@ -70,14 +73,20 @@ def test_no_rebuild(name, cmd): fail("Something was being rebuilt when it should not be (or we got no output)"); def test_cargo_miri_run(): + default_env={ + 'MIRIFLAGS': "-Zmiri-disable-isolation", + 'MIRITESTVAR': "wrongval", # make sure the build.rs value takes precedence + } test("`cargo miri run` (no isolation)", cargo_miri("run"), "run.default.stdout.ref", "run.default.stderr.ref", stdin=b'12\n21\n', - env={ - 'MIRIFLAGS': "-Zmiri-disable-isolation", - 'MIRITESTVAR': "wrongval", # make sure the build.rs value takes precedence - }, + env=default_env, + ) + # Special test: run it again *without* `-q` to make sure nothing is being rebuilt (Miri issue #1722) + test_no_rebuild("`cargo miri run` (no rebuild, no isolation)", + cargo_miri("run", quiet=False) + ["--", ""], + env=default_env, ) test("`cargo miri run` (with arguments and target)", cargo_miri("run") + ["--bin", "cargo-miri-test", "--", "hello world", '"hello world"'], @@ -88,12 +97,6 @@ def test_cargo_miri_run(): "run.subcrate.stdout.ref", "run.subcrate.stderr.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) - # Special test: run it again *without* `-q` to make sure nothing is being rebuilt (Miri issue #1722) - # FIXME: move this test up to right after the first `test` - # (currently that fails, only the 3rd and later runs are really clean... see Miri issue #1722) - test_no_rebuild("`cargo miri run` (no rebuild)", - cargo_miri("run", quiet=False) + ["--", ""], - ) def test_cargo_miri_test(): # rustdoc is not run on foreign targets From 9c1342b152a124c4f0e8869f626bb1a6b1ef072f Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 28 Feb 2021 15:57:49 +0800 Subject: [PATCH 2559/5092] Clarify that the "dep-info" is fake and add a newline --- cargo-miri/bin.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 535acf36df73..2cd0c0c972f5 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -614,9 +614,10 @@ fn phase_cargo_rustc(mut args: env::Args) { // As we store a JSON file instead of building the crate here, an empty file is fine. let dep_info_name = out_filename("", ".d"); if verbose { - eprintln!("[cargo-miri rustc] writing dep-info to `{}`", dep_info_name.display()); + eprintln!("[cargo-miri rustc] writing stub dep-info to `{}`", dep_info_name.display()); } File::create(dep_info_name).expect("failed to create fake .d file"); + let filename = out_filename("", ""); if verbose { eprintln!("[cargo-miri rustc] writing run info to `{}`", filename.display()); From 46af1890a51db4b7f6ca122123704fef65980a5c Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 28 Feb 2021 16:10:35 +0800 Subject: [PATCH 2560/5092] Drop MIRIFLAGS from "no rebuild" test --- test-cargo-miri/run-test.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 3a8a32db1ede..36c6af87d894 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -73,20 +73,19 @@ def test_no_rebuild(name, cmd, env={}): fail("Something was being rebuilt when it should not be (or we got no output)"); def test_cargo_miri_run(): - default_env={ - 'MIRIFLAGS': "-Zmiri-disable-isolation", - 'MIRITESTVAR': "wrongval", # make sure the build.rs value takes precedence - } test("`cargo miri run` (no isolation)", cargo_miri("run"), "run.default.stdout.ref", "run.default.stderr.ref", stdin=b'12\n21\n', - env=default_env, + env={ + 'MIRIFLAGS': "-Zmiri-disable-isolation", + 'MIRITESTVAR': "wrongval", # make sure the build.rs value takes precedence + }, ) # Special test: run it again *without* `-q` to make sure nothing is being rebuilt (Miri issue #1722) test_no_rebuild("`cargo miri run` (no rebuild, no isolation)", cargo_miri("run", quiet=False) + ["--", ""], - env=default_env, + env={'MIRITESTVAR': "wrongval"}, ) test("`cargo miri run` (with arguments and target)", cargo_miri("run") + ["--bin", "cargo-miri-test", "--", "hello world", '"hello world"'], From 6d5ce21c92de3bb2bfb9976cf278e7ae11f69d6b Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 28 Feb 2021 18:13:17 +0800 Subject: [PATCH 2561/5092] Cleanup test-cargo-miri/run-test.py --- test-cargo-miri/run-test.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 36c6af87d894..81f589705dc3 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -83,9 +83,10 @@ def test_cargo_miri_run(): }, ) # Special test: run it again *without* `-q` to make sure nothing is being rebuilt (Miri issue #1722) - test_no_rebuild("`cargo miri run` (no rebuild, no isolation)", + test_no_rebuild("`cargo miri run` (no rebuild)", cargo_miri("run", quiet=False) + ["--", ""], - env={'MIRITESTVAR': "wrongval"}, + env={'MIRITESTVAR': "wrongval"}, # changing the env var causes a rebuild (re-runs build.rs), + # so keep it set ) test("`cargo miri run` (with arguments and target)", cargo_miri("run") + ["--bin", "cargo-miri-test", "--", "hello world", '"hello world"'], From df2d498a05ab0b250b468e5bce54ee2a43f641e2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Mar 2021 10:16:44 +0100 Subject: [PATCH 2562/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index f76caa2c0f33..059dfeb2e6d3 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a4e595db8f12f9ee926256745d757004b850703f +d2731d8e9338d8fe844e19d3fbb39617753e65f4 From 7acf80d2bb7c50c2f60807cb3f543955e7fef677 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Mar 2021 10:44:06 +0100 Subject: [PATCH 2563/5092] rustup; fix tests for new MIR optimization --- rust-version | 2 +- .../data_race/dealloc_read_race_stack.rs | 8 +-- .../data_race/dealloc_read_race_stack_drop.rs | 52 ------------------ .../data_race/dealloc_write_race_stack.rs | 8 +-- .../dealloc_write_race_stack_drop.rs | 53 ------------------- ...lock_read_write_deadlock_single_thread.rs} | 3 +- ...wlock_write_read_deadlock_single_thread.rs | 3 +- ...lock_write_write_deadlock_single_thread.rs | 3 +- 8 files changed, 15 insertions(+), 117 deletions(-) delete mode 100644 tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs delete mode 100644 tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs rename tests/compile-fail/sync/{libc_pthread_rwlock_read_write_deadlock.rs => libc_pthread_rwlock_read_write_deadlock_single_thread.rs} (77%) diff --git a/rust-version b/rust-version index 059dfeb2e6d3..65644e75d977 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d2731d8e9338d8fe844e19d3fbb39617753e65f4 +09db05762b283bed62d4f92729cfee4646519833 diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack.rs b/tests/compile-fail/data_race/dealloc_read_race_stack.rs index 31960fb2162b..281aff863146 100644 --- a/tests/compile-fail/data_race/dealloc_read_race_stack.rs +++ b/tests/compile-fail/data_race/dealloc_read_race_stack.rs @@ -1,5 +1,6 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation +// compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 +// With optimizations (in particular #78360), the span becomes much worse, so we disable them. use std::thread::{spawn, sleep}; use std::ptr::null_mut; @@ -27,9 +28,6 @@ pub fn main() { // 3. stack-deallocate unsafe { let j1 = spawn(move || { - // Concurrent allocate the memory. - // Uses relaxed semantics to not generate - // a release sequence. let pointer = &*ptr.0; { let mut stack_var = 0usize; @@ -38,6 +36,8 @@ pub fn main() { sleep(Duration::from_millis(200)); + // Now `stack_var` gets deallocated. + } //~ ERROR Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2) }); diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs b/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs deleted file mode 100644 index 44950a34db2f..000000000000 --- a/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs +++ /dev/null @@ -1,52 +0,0 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation - -use std::thread::{spawn, sleep}; -use std::ptr::null_mut; -use std::sync::atomic::{Ordering, AtomicPtr}; -use std::time::Duration; - -#[derive(Copy, Clone)] -struct EvilSend(pub T); - -unsafe impl Send for EvilSend {} -unsafe impl Sync for EvilSend {} - -pub fn main() { - // Shared atomic pointer - let pointer = AtomicPtr::new(null_mut::()); - let ptr = EvilSend(&pointer as *const AtomicPtr); - - // Note: this is scheduler-dependent - // the operations need to occur in - // order, otherwise the allocation is - // not visible to the other-thread to - // detect the race: - // 1. stack-allocate - // 2. read - // 3. stack-deallocate - unsafe { - let j1 = spawn(move || { - // Concurrent allocate the memory. - // Uses relaxed semantics to not generate - // a release sequence. - let pointer = &*ptr.0; - - let mut stack_var = 0usize; - - pointer.store(&mut stack_var as *mut _, Ordering::Release); - - sleep(Duration::from_millis(200)); - - drop(stack_var); - }); //~ ERROR Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2) - - let j2 = spawn(move || { - let pointer = &*ptr.0; - *pointer.load(Ordering::Acquire) - }); - - j1.join().unwrap(); - j2.join().unwrap(); - } -} diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack.rs b/tests/compile-fail/data_race/dealloc_write_race_stack.rs index 25dea65fe7e0..55aaa0c1635a 100644 --- a/tests/compile-fail/data_race/dealloc_write_race_stack.rs +++ b/tests/compile-fail/data_race/dealloc_write_race_stack.rs @@ -1,5 +1,6 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation +// compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 +// With optimizations (in particular #78360), the span becomes much worse, so we disable them. use std::thread::{spawn, sleep}; use std::ptr::null_mut; @@ -27,9 +28,6 @@ pub fn main() { // 3. stack-deallocate unsafe { let j1 = spawn(move || { - // Concurrent allocate the memory. - // Uses relaxed semantics to not generate - // a release sequence. let pointer = &*ptr.0; { let mut stack_var = 0usize; @@ -38,6 +36,8 @@ pub fn main() { sleep(Duration::from_millis(200)); + // Now `stack_var` gets deallocated. + } //~ ERROR Data race detected between Deallocate on Thread(id = 1) and Write on Thread(id = 2) }); diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs b/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs deleted file mode 100644 index 1d239e9eb74d..000000000000 --- a/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs +++ /dev/null @@ -1,53 +0,0 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation - -use std::thread::{spawn, sleep}; -use std::ptr::null_mut; -use std::sync::atomic::{Ordering, AtomicPtr}; -use std::time::Duration; - -#[derive(Copy, Clone)] -struct EvilSend(pub T); - -unsafe impl Send for EvilSend {} -unsafe impl Sync for EvilSend {} - -pub fn main() { - // Shared atomic pointer - let pointer = AtomicPtr::new(null_mut::()); - let ptr = EvilSend(&pointer as *const AtomicPtr); - - // Note: this is scheduler-dependent - // the operations need to occur in - // order, otherwise the allocation is - // not visible to the other-thread to - // detect the race: - // 1. stack-allocate - // 2. read - // 3. stack-deallocate - unsafe { - let j1 = spawn(move || { - // Concurrent allocate the memory. - // Uses relaxed semantics to not generate - // a release sequence. - let pointer = &*ptr.0; - - let mut stack_var = 0usize; - - pointer.store(&mut stack_var as *mut _, Ordering::Release); - - sleep(Duration::from_millis(200)); - - // Note: Implicit read for drop(_) races with write, would detect race with deallocate after. - drop(stack_var); //~ ERROR Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) - }); - - let j2 = spawn(move || { - let pointer = &*ptr.0; - *pointer.load(Ordering::Acquire) = 3; - }); - - j1.join().unwrap(); - j2.join().unwrap(); - } -} diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock.rs b/tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs similarity index 77% rename from tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock.rs rename to tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs index dd4707d60e4c..da45d062d03b 100644 --- a/tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock.rs +++ b/tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs @@ -1,4 +1,5 @@ // ignore-windows: No libc on Windows +// error-pattern: deadlock #![feature(rustc_private)] @@ -8,6 +9,6 @@ fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); - libc::pthread_rwlock_wrlock(rw.get()); //~ ERROR: deadlock + libc::pthread_rwlock_wrlock(rw.get()); } } diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs b/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs index 1b460e7174d2..ee2e57a9ab37 100644 --- a/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs +++ b/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs @@ -1,4 +1,5 @@ // ignore-windows: No libc on Windows +// error-pattern: deadlock #![feature(rustc_private)] @@ -8,6 +9,6 @@ fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); - libc::pthread_rwlock_rdlock(rw.get()); //~ ERROR: deadlock + libc::pthread_rwlock_rdlock(rw.get()); } } diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs b/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs index cc327ec46bc2..f0404f202e56 100644 --- a/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs +++ b/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs @@ -1,4 +1,5 @@ // ignore-windows: No libc on Windows +// error-pattern: deadlock #![feature(rustc_private)] @@ -8,6 +9,6 @@ fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); - libc::pthread_rwlock_wrlock(rw.get()); //~ ERROR: deadlock + libc::pthread_rwlock_wrlock(rw.get()); } } From 97e45e0699e2fc8397b1e2cfb55743365d749b6e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Mar 2021 11:04:35 +0100 Subject: [PATCH 2564/5092] make optimized-test-run a bit more like what cargo does --- ci.sh | 5 +++-- tests/compile-fail/data_race/dealloc_read_race_stack.rs | 3 +-- tests/compile-fail/data_race/dealloc_write_race_stack.rs | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ci.sh b/ci.sh index a1f4a0013946..3484040119ca 100755 --- a/ci.sh +++ b/ci.sh @@ -24,8 +24,9 @@ function run_tests { ./miri test --locked if [ -z "${MIRI_TEST_TARGET+exists}" ]; then - # Only for host architecture: tests with MIR optimizations - MIRIFLAGS="-Z mir-opt-level=3" ./miri test --locked + # Only for host architecture: tests with optimizations (`-O` is what cargo passes, but crank MIR + # optimizations up all the way). + MIRIFLAGS="-O -Zmir-opt-level=3" ./miri test --locked fi # On Windows, there is always "python", not "python3" or "python2". diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack.rs b/tests/compile-fail/data_race/dealloc_read_race_stack.rs index 281aff863146..6b573121e599 100644 --- a/tests/compile-fail/data_race/dealloc_read_race_stack.rs +++ b/tests/compile-fail/data_race/dealloc_read_race_stack.rs @@ -1,6 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 -// With optimizations (in particular #78360), the span becomes much worse, so we disable them. +// compile-flags: -Zmiri-disable-isolation use std::thread::{spawn, sleep}; use std::ptr::null_mut; diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack.rs b/tests/compile-fail/data_race/dealloc_write_race_stack.rs index 55aaa0c1635a..34a16b00b83d 100644 --- a/tests/compile-fail/data_race/dealloc_write_race_stack.rs +++ b/tests/compile-fail/data_race/dealloc_write_race_stack.rs @@ -1,6 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 -// With optimizations (in particular #78360), the span becomes much worse, so we disable them. +// compile-flags: -Zmiri-disable-isolation use std::thread::{spawn, sleep}; use std::ptr::null_mut; From 2902ad91deb5593dca3ee98b8bfa869747240e65 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Mar 2021 11:09:06 +0100 Subject: [PATCH 2565/5092] add date to Zulip notification subject --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a55cd8212517..d3d5d65bb94e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -129,7 +129,7 @@ jobs: ZULIP_BOT_EMAIL: ${{ secrets.ZULIP_BOT_EMAIL }} ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }} run: | - ~/.local/bin/zulip-send --stream miri --subject "Cron Job Failure" \ + ~/.local/bin/zulip-send --stream miri --subject "Cron Job Failure $(date -uI)" \ --message 'Dear @**RalfJ** and @**oli** It would appear that the Miri cron job build failed. Would you mind investigating this issue? From 47ec9b878e7d9bb308e7991b69a76d98641c793f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Mar 2021 11:24:56 +0100 Subject: [PATCH 2566/5092] adjust CI test flags --- ci.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/ci.sh b/ci.sh index a1f4a0013946..8b0280b25787 100755 --- a/ci.sh +++ b/ci.sh @@ -2,8 +2,6 @@ set -euo pipefail # Determine configuration -export RUST_TEST_NOCAPTURE=1 -export RUST_BACKTRACE=1 export RUSTFLAGS="-D warnings" export CARGO_INCREMENTAL=0 export CARGO_EXTRA_FLAGS="--all-features" From 7d1531f3c134859fc4f733ebddcfd38a8987d5cf Mon Sep 17 00:00:00 2001 From: Henry Boisdequin <65845077+henryboisdequin@users.noreply.github.com> Date: Tue, 2 Mar 2021 18:06:12 +0530 Subject: [PATCH 2567/5092] fmt data_race.rs and intrinsics.rs --- src/data_race.rs | 6 +- src/shims/intrinsics.rs | 297 +++++++++++++++++++++++++++------------- 2 files changed, 205 insertions(+), 98 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index dcff896c1f16..c7bafb60a619 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -263,7 +263,7 @@ impl MemoryCellClocks { atomic_ops: None, } } - + /// Load the internal atomic memory cells if they exist. #[inline] fn atomic(&self) -> Option<&AtomicMemoryCellClocks> { @@ -323,7 +323,7 @@ impl MemoryCellClocks { /// store relaxed semantics. fn store_relaxed(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { self.atomic_write_detect(clocks, index)?; - + // The handling of release sequences was changed in C++20 and so // the code here is different to the paper since now all relaxed // stores block release sequences. The exception for same-thread @@ -678,7 +678,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // Either Release | AcqRel | SeqCst clocks.apply_release_fence(); } - + // Increment timestamp in case of release semantics. Ok(atomic != AtomicFenceOp::Acquire) }) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 33aa7b28bb5b..f9ec62d7514d 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -2,9 +2,9 @@ use std::iter; use log::trace; -use rustc_middle::{mir, mir::BinOp, ty, ty::FloatTy}; -use rustc_middle::ty::layout::IntegerExt; use rustc_apfloat::{Float, Round}; +use rustc_middle::ty::layout::IntegerExt; +use rustc_middle::{mir, mir::BinOp, ty, ty::FloatTy}; use rustc_target::abi::{Align, Integer, LayoutOf}; use crate::*; @@ -67,8 +67,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val_byte = this.read_scalar(val_byte)?.to_u8()?; let ptr = this.read_scalar(ptr)?.check_init()?; let count = this.read_scalar(count)?.to_machine_usize(this)?; - let byte_count = ty_layout.size.checked_mul(count, this) - .ok_or_else(|| err_ub_format!("overflow computing total size of `write_bytes`"))?; + let byte_count = ty_layout.size.checked_mul(count, this).ok_or_else(|| { + err_ub_format!("overflow computing total size of `write_bytes`") + })?; this.memory .write_bytes(ptr, iter::repeat(val_byte).take(byte_count.bytes() as usize))?; } @@ -258,13 +259,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val = this.read_immediate(val)?; let res = match val.layout.ty.kind() { - ty::Float(FloatTy::F32) => { - this.float_to_int_unchecked(val.to_scalar()?.to_f32()?, dest.layout.ty)? - } - ty::Float(FloatTy::F64) => { - this.float_to_int_unchecked(val.to_scalar()?.to_f64()?, dest.layout.ty)? - } - _ => bug!("`float_to_int_unchecked` called with non-float input type {:?}", val.layout.ty), + ty::Float(FloatTy::F32) => + this.float_to_int_unchecked(val.to_scalar()?.to_f32()?, dest.layout.ty)?, + ty::Float(FloatTy::F64) => + this.float_to_int_unchecked(val.to_scalar()?.to_f64()?, dest.layout.ty)?, + _ => bug!( + "`float_to_int_unchecked` called with non-float input type {:?}", + val.layout.ty + ), }; this.write_scalar(res, dest)?; @@ -286,7 +288,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_singlethreadfence_acq" => this.compiler_fence(args, AtomicFenceOp::Acquire)?, "atomic_singlethreadfence_rel" => this.compiler_fence(args, AtomicFenceOp::Release)?, - "atomic_singlethreadfence_acqrel" => this.compiler_fence(args, AtomicFenceOp::AcqRel)?, + "atomic_singlethreadfence_acqrel" => + this.compiler_fence(args, AtomicFenceOp::AcqRel)?, "atomic_singlethreadfence" => this.compiler_fence(args, AtomicFenceOp::SeqCst)?, "atomic_xchg" => this.atomic_exchange(args, dest, AtomicRwOp::SeqCst)?, @@ -295,110 +298,179 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_xchg_acqrel" => this.atomic_exchange(args, dest, AtomicRwOp::AcqRel)?, "atomic_xchg_relaxed" => this.atomic_exchange(args, dest, AtomicRwOp::Relaxed)?, - "atomic_cxchg" => this.atomic_compare_exchange( - args, dest, AtomicRwOp::SeqCst, AtomicReadOp::SeqCst - )?, + "atomic_cxchg" => + this.atomic_compare_exchange(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::SeqCst)?, "atomic_cxchg_acq" => this.atomic_compare_exchange( - args, dest, AtomicRwOp::Acquire, AtomicReadOp::Acquire + args, + dest, + AtomicRwOp::Acquire, + AtomicReadOp::Acquire, )?, "atomic_cxchg_rel" => this.atomic_compare_exchange( - args, dest, AtomicRwOp::Release, AtomicReadOp::Relaxed - )?, - "atomic_cxchg_acqrel" => this.atomic_compare_exchange - (args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Acquire + args, + dest, + AtomicRwOp::Release, + AtomicReadOp::Relaxed, )?, + "atomic_cxchg_acqrel" => + this.atomic_compare_exchange(args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Acquire)?, "atomic_cxchg_relaxed" => this.atomic_compare_exchange( - args, dest, AtomicRwOp::Relaxed, AtomicReadOp::Relaxed + args, + dest, + AtomicRwOp::Relaxed, + AtomicReadOp::Relaxed, )?, "atomic_cxchg_acq_failrelaxed" => this.atomic_compare_exchange( - args, dest, AtomicRwOp::Acquire, AtomicReadOp::Relaxed - )?, - "atomic_cxchg_acqrel_failrelaxed" => this.atomic_compare_exchange( - args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Relaxed - )?, - "atomic_cxchg_failrelaxed" => this.atomic_compare_exchange( - args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Relaxed - )?, - "atomic_cxchg_failacq" => this.atomic_compare_exchange( - args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Acquire + args, + dest, + AtomicRwOp::Acquire, + AtomicReadOp::Relaxed, )?, + "atomic_cxchg_acqrel_failrelaxed" => + this.atomic_compare_exchange(args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Relaxed)?, + "atomic_cxchg_failrelaxed" => + this.atomic_compare_exchange(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Relaxed)?, + "atomic_cxchg_failacq" => + this.atomic_compare_exchange(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Acquire)?, "atomic_cxchgweak" => this.atomic_compare_exchange_weak( - args, dest, AtomicRwOp::SeqCst, AtomicReadOp::SeqCst + args, + dest, + AtomicRwOp::SeqCst, + AtomicReadOp::SeqCst, )?, "atomic_cxchgweak_acq" => this.atomic_compare_exchange_weak( - args, dest, AtomicRwOp::Acquire, AtomicReadOp::Acquire + args, + dest, + AtomicRwOp::Acquire, + AtomicReadOp::Acquire, )?, "atomic_cxchgweak_rel" => this.atomic_compare_exchange_weak( - args, dest, AtomicRwOp::Release, AtomicReadOp::Relaxed + args, + dest, + AtomicRwOp::Release, + AtomicReadOp::Relaxed, )?, "atomic_cxchgweak_acqrel" => this.atomic_compare_exchange_weak( - args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Acquire + args, + dest, + AtomicRwOp::AcqRel, + AtomicReadOp::Acquire, )?, "atomic_cxchgweak_relaxed" => this.atomic_compare_exchange_weak( - args, dest, AtomicRwOp::Relaxed, AtomicReadOp::Relaxed + args, + dest, + AtomicRwOp::Relaxed, + AtomicReadOp::Relaxed, )?, "atomic_cxchgweak_acq_failrelaxed" => this.atomic_compare_exchange_weak( - args, dest, AtomicRwOp::Acquire, AtomicReadOp::Relaxed + args, + dest, + AtomicRwOp::Acquire, + AtomicReadOp::Relaxed, )?, "atomic_cxchgweak_acqrel_failrelaxed" => this.atomic_compare_exchange_weak( - args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Relaxed + args, + dest, + AtomicRwOp::AcqRel, + AtomicReadOp::Relaxed, )?, "atomic_cxchgweak_failrelaxed" => this.atomic_compare_exchange_weak( - args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Relaxed + args, + dest, + AtomicRwOp::SeqCst, + AtomicReadOp::Relaxed, )?, "atomic_cxchgweak_failacq" => this.atomic_compare_exchange_weak( - args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Acquire + args, + dest, + AtomicRwOp::SeqCst, + AtomicReadOp::Acquire, )?, "atomic_or" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::SeqCst)?, - "atomic_or_acq" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::Acquire)?, - "atomic_or_rel" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::Release)?, - "atomic_or_acqrel" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::AcqRel)?, - "atomic_or_relaxed" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::Relaxed)?, + "atomic_or_acq" => + this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::Acquire)?, + "atomic_or_rel" => + this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::Release)?, + "atomic_or_acqrel" => + this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::AcqRel)?, + "atomic_or_relaxed" => + this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::Relaxed)?, "atomic_xor" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::SeqCst)?, - "atomic_xor_acq" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::Acquire)?, - "atomic_xor_rel" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::Release)?, - "atomic_xor_acqrel" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::AcqRel)?, - "atomic_xor_relaxed" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::Relaxed)?, + "atomic_xor_acq" => + this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::Acquire)?, + "atomic_xor_rel" => + this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::Release)?, + "atomic_xor_acqrel" => + this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::AcqRel)?, + "atomic_xor_relaxed" => + this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::Relaxed)?, "atomic_and" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::SeqCst)?, - "atomic_and_acq" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::Acquire)?, - "atomic_and_rel" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::Release)?, - "atomic_and_acqrel" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::AcqRel)?, - "atomic_and_relaxed" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::Relaxed)?, + "atomic_and_acq" => + this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::Acquire)?, + "atomic_and_rel" => + this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::Release)?, + "atomic_and_acqrel" => + this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::AcqRel)?, + "atomic_and_relaxed" => + this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::Relaxed)?, "atomic_nand" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::SeqCst)?, - "atomic_nand_acq" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::Acquire)?, - "atomic_nand_rel" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::Release)?, - "atomic_nand_acqrel" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::AcqRel)?, - "atomic_nand_relaxed" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::Relaxed)?, + "atomic_nand_acq" => + this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::Acquire)?, + "atomic_nand_rel" => + this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::Release)?, + "atomic_nand_acqrel" => + this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::AcqRel)?, + "atomic_nand_relaxed" => + this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::Relaxed)?, "atomic_xadd" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::SeqCst)?, - "atomic_xadd_acq" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::Acquire)?, - "atomic_xadd_rel" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::Release)?, - "atomic_xadd_acqrel" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::AcqRel)?, - "atomic_xadd_relaxed" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::Relaxed)?, + "atomic_xadd_acq" => + this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::Acquire)?, + "atomic_xadd_rel" => + this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::Release)?, + "atomic_xadd_acqrel" => + this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::AcqRel)?, + "atomic_xadd_relaxed" => + this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::Relaxed)?, "atomic_xsub" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::SeqCst)?, - "atomic_xsub_acq" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::Acquire)?, - "atomic_xsub_rel" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::Release)?, - "atomic_xsub_acqrel" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::AcqRel)?, - "atomic_xsub_relaxed" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::Relaxed)?, - + "atomic_xsub_acq" => + this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::Acquire)?, + "atomic_xsub_rel" => + this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::Release)?, + "atomic_xsub_acqrel" => + this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::AcqRel)?, + "atomic_xsub_relaxed" => + this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::Relaxed)?, // Query type information - "assert_zero_valid" | - "assert_uninit_valid" => { + "assert_zero_valid" | "assert_uninit_valid" => { let &[] = check_arg_count(args)?; let ty = instance.substs.type_at(0); let layout = this.layout_of(ty)?; // Abort here because the caller might not be panic safe. if layout.abi.is_uninhabited() { // Use this message even for the other intrinsics, as that's what codegen does - throw_machine_stop!(TerminationInfo::Abort(format!("aborted execution: attempted to instantiate uninhabited type `{}`", ty))) + throw_machine_stop!(TerminationInfo::Abort(format!( + "aborted execution: attempted to instantiate uninhabited type `{}`", + ty + ))) } - if intrinsic_name == "assert_zero_valid" && !layout.might_permit_raw_init(this, /*zero:*/ true).unwrap() { - throw_machine_stop!(TerminationInfo::Abort(format!("aborted execution: attempted to zero-initialize type `{}`, which is invalid", ty))) + if intrinsic_name == "assert_zero_valid" + && !layout.might_permit_raw_init(this, /*zero:*/ true).unwrap() + { + throw_machine_stop!(TerminationInfo::Abort(format!( + "aborted execution: attempted to zero-initialize type `{}`, which is invalid", + ty + ))) } - if intrinsic_name == "assert_uninit_valid" && !layout.might_permit_raw_init(this, /*zero:*/ false).unwrap() { - throw_machine_stop!(TerminationInfo::Abort(format!("aborted execution: attempted to leave type `{}` uninitialized, which is invalid", ty))) + if intrinsic_name == "assert_uninit_valid" + && !layout.might_permit_raw_init(this, /*zero:*/ false).unwrap() + { + throw_machine_stop!(TerminationInfo::Abort(format!( + "aborted execution: attempted to leave type `{}` uninitialized, which is invalid", + ty + ))) } } @@ -419,12 +491,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } fn atomic_load( - &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - atomic: AtomicReadOp + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + atomic: AtomicReadOp, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[ref place] = check_arg_count(args)?; let place = this.deref_operand(place)?; @@ -440,7 +513,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - fn atomic_store(&mut self, args: &[OpTy<'tcx, Tag>], atomic: AtomicWriteOp) -> InterpResult<'tcx> { + fn atomic_store( + &mut self, + args: &[OpTy<'tcx, Tag>], + atomic: AtomicWriteOp, + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let &[ref place, ref val] = check_arg_count(args)?; @@ -458,14 +535,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - fn compiler_fence(&mut self, args: &[OpTy<'tcx, Tag>], atomic: AtomicFenceOp) -> InterpResult<'tcx> { + fn compiler_fence( + &mut self, + args: &[OpTy<'tcx, Tag>], + atomic: AtomicFenceOp, + ) -> InterpResult<'tcx> { let &[] = check_arg_count(args)?; let _ = atomic; //FIXME: compiler fences are currently ignored Ok(()) } - fn atomic_fence(&mut self, args: &[OpTy<'tcx, Tag>], atomic: AtomicFenceOp) -> InterpResult<'tcx> { + fn atomic_fence( + &mut self, + args: &[OpTy<'tcx, Tag>], + atomic: AtomicFenceOp, + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let &[] = check_arg_count(args)?; this.validate_atomic_fence(atomic)?; @@ -473,8 +558,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } fn atomic_op( - &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - op: mir::BinOp, neg: bool, atomic: AtomicRwOp + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + op: mir::BinOp, + neg: bool, + atomic: AtomicRwOp, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -490,14 +579,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; - + let old = this.atomic_op_immediate(&place, &rhs, op, neg, atomic)?; this.write_immediate(*old, dest)?; // old value is returned Ok(()) } - + fn atomic_exchange( - &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, atomic: AtomicRwOp + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + atomic: AtomicRwOp, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -517,8 +609,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } fn atomic_compare_exchange_impl( - &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - success: AtomicRwOp, fail: AtomicReadOp, can_fail_spuriously: bool + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + success: AtomicRwOp, + fail: AtomicReadOp, + can_fail_spuriously: bool, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -527,16 +623,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let expect_old = this.read_immediate(expect_old)?; // read as immediate for the sake of `binary_op()` let new = this.read_scalar(new)?; - // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; - let old = this.atomic_compare_exchange_scalar( - &place, &expect_old, new, success, fail, can_fail_spuriously + &place, + &expect_old, + new, + success, + fail, + can_fail_spuriously, )?; // Return old value. @@ -545,15 +644,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } fn atomic_compare_exchange( - &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - success: AtomicRwOp, fail: AtomicReadOp + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + success: AtomicRwOp, + fail: AtomicReadOp, ) -> InterpResult<'tcx> { self.atomic_compare_exchange_impl(args, dest, success, fail, false) } fn atomic_compare_exchange_weak( - &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - success: AtomicRwOp, fail: AtomicReadOp + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + success: AtomicRwOp, + fail: AtomicReadOp, ) -> InterpResult<'tcx> { self.atomic_compare_exchange_impl(args, dest, success, fail, true) } @@ -564,7 +669,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest_ty: ty::Ty<'tcx>, ) -> InterpResult<'tcx, Scalar> where - F: Float + Into> + F: Float + Into>, { let this = self.eval_context_ref(); @@ -585,7 +690,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `f` was not representable in this integer type. throw_ub_format!( "`float_to_int_unchecked` intrinsic called on {} which cannot be represented in target type `{:?}`", - f, dest_ty, + f, + dest_ty, ); } } @@ -600,7 +706,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `f` was not representable in this integer type. throw_ub_format!( "`float_to_int_unchecked` intrinsic called on {} which cannot be represented in target type `{:?}`", - f, dest_ty, + f, + dest_ty, ); } } From f8440d6c998b6f30fa04d6ed6f1e4f19242283af Mon Sep 17 00:00:00 2001 From: Henry Boisdequin <65845077+henryboisdequin@users.noreply.github.com> Date: Tue, 2 Mar 2021 18:10:27 +0530 Subject: [PATCH 2568/5092] Add in `atomic_{min,max}_x` intrinsics Co-authored-by: Greg Bowyer --- src/data_race.rs | 74 +++++++--- src/shims/intrinsics.rs | 306 +++++++++++++++++++++++++++++++-------- tests/run-pass/atomic.rs | 14 ++ 3 files changed, 314 insertions(+), 80 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index c7bafb60a619..e8071845c7d7 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -74,9 +74,9 @@ use rustc_middle::{mir, ty::layout::TyAndLayout}; use rustc_target::abi::Size; use crate::{ - ImmTy, Immediate, InterpResult, MPlaceTy, MemPlaceMeta, MiriEvalContext, MiriEvalContextExt, - OpTy, Pointer, RangeMap, Scalar, ScalarMaybeUninit, Tag, ThreadId, VClock, VTimestamp, - VectorIdx, MemoryKind, MiriMemoryKind + ImmTy, Immediate, InterpResult, MPlaceTy, MemPlaceMeta, MemoryKind, MiriEvalContext, + MiriEvalContextExt, MiriMemoryKind, OpTy, Pointer, RangeMap, Scalar, ScalarMaybeUninit, Tag, + ThreadId, VClock, VTimestamp, VectorIdx, }; pub type AllocExtra = VClockAlloc; @@ -542,6 +542,34 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { Ok(old) } + /// Perform an conditional atomic exchange with a memory place and a new + /// scalar value, the old value is returned. + fn atomic_min_max_scalar( + &mut self, + place: &MPlaceTy<'tcx, Tag>, + rhs: ImmTy<'tcx, Tag>, + min: bool, + atomic: AtomicRwOp, + ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { + let this = self.eval_context_mut(); + + let old = this.allow_data_races_mut(|this| this.read_immediate(&place.into()))?; + let lt = this.overflowing_binary_op(mir::BinOp::Lt, &old, &rhs)?.0.to_bool()?; + + let new_val = if min { + if lt { &old } else { &rhs } + } else { + if lt { &rhs } else { &old } + }; + + this.allow_data_races_mut(|this| this.write_immediate_to_mplace(**new_val, place))?; + + this.validate_atomic_rmw(&place, atomic)?; + + // Return the old value. + Ok(old) + } + /// Perform an atomic compare and exchange at a given memory location. /// On success an atomic RMW operation is performed and on failure /// only an atomic read occurs. If `can_fail_spuriously` is true, @@ -687,15 +715,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { } } - fn reset_vector_clocks( - &mut self, - ptr: Pointer, - size: Size - ) -> InterpResult<'tcx> { + fn reset_vector_clocks(&mut self, ptr: Pointer, size: Size) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if let Some(data_race) = &mut this.memory.extra.data_race { if data_race.multi_threaded.get() { - let alloc_meta = this.memory.get_raw_mut(ptr.alloc_id)?.extra.data_race.as_mut().unwrap(); + let alloc_meta = + this.memory.get_raw_mut(ptr.alloc_id)?.extra.data_race.as_mut().unwrap(); alloc_meta.reset_clocks(ptr.offset, size); } } @@ -715,28 +740,37 @@ pub struct VClockAlloc { impl VClockAlloc { /// Create a new data-race detector for newly allocated memory. - pub fn new_allocation(global: &MemoryExtra, len: Size, kind: MemoryKind) -> VClockAlloc { + pub fn new_allocation( + global: &MemoryExtra, + len: Size, + kind: MemoryKind, + ) -> VClockAlloc { let (alloc_timestamp, alloc_index) = match kind { // User allocated and stack memory should track allocation. MemoryKind::Machine( - MiriMemoryKind::Rust | MiriMemoryKind::C | MiriMemoryKind::WinHeap - ) | MemoryKind::Stack => { + MiriMemoryKind::Rust | MiriMemoryKind::C | MiriMemoryKind::WinHeap, + ) + | MemoryKind::Stack => { let (alloc_index, clocks) = global.current_thread_state(); let alloc_timestamp = clocks.clock[alloc_index]; (alloc_timestamp, alloc_index) } // Other global memory should trace races but be allocated at the 0 timestamp. MemoryKind::Machine( - MiriMemoryKind::Global | MiriMemoryKind::Machine | MiriMemoryKind::Env | - MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls - ) | MemoryKind::CallerLocation | MemoryKind::Vtable => { - (0, VectorIdx::MAX_INDEX) - } + MiriMemoryKind::Global + | MiriMemoryKind::Machine + | MiriMemoryKind::Env + | MiriMemoryKind::ExternStatic + | MiriMemoryKind::Tls, + ) + | MemoryKind::CallerLocation + | MemoryKind::Vtable => (0, VectorIdx::MAX_INDEX), }; VClockAlloc { global: Rc::clone(global), alloc_ranges: RefCell::new(RangeMap::new( - len, MemoryCellClocks::new(alloc_timestamp, alloc_index) + len, + MemoryCellClocks::new(alloc_timestamp, alloc_index), )), } } @@ -1015,7 +1049,8 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { true, place_ptr, size, - ).map(|_| true); + ) + .map(|_| true); } } @@ -1267,7 +1302,6 @@ impl GlobalState { .as_ref() .expect("Joined with thread but thread has not terminated"); - // The join thread happens-before the current thread // so update the current vector clock. // Is not a release operation so the clock is not incremented. diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index f9ec62d7514d..66ba42c5a017 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -10,6 +10,12 @@ use rustc_target::abi::{Align, Integer, LayoutOf}; use crate::*; use helpers::check_arg_count; +pub enum AtomicOp { + MirOp(mir::BinOp, bool), + Max, + Min, +} + impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn call_intrinsic( @@ -388,60 +394,226 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx AtomicReadOp::Acquire, )?, - "atomic_or" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::SeqCst)?, - "atomic_or_acq" => - this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::Acquire)?, - "atomic_or_rel" => - this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::Release)?, - "atomic_or_acqrel" => - this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::AcqRel)?, - "atomic_or_relaxed" => - this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::Relaxed)?, - "atomic_xor" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::SeqCst)?, - "atomic_xor_acq" => - this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::Acquire)?, - "atomic_xor_rel" => - this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::Release)?, - "atomic_xor_acqrel" => - this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::AcqRel)?, - "atomic_xor_relaxed" => - this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::Relaxed)?, - "atomic_and" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::SeqCst)?, - "atomic_and_acq" => - this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::Acquire)?, - "atomic_and_rel" => - this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::Release)?, - "atomic_and_acqrel" => - this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::AcqRel)?, - "atomic_and_relaxed" => - this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::Relaxed)?, - "atomic_nand" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::SeqCst)?, - "atomic_nand_acq" => - this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::Acquire)?, - "atomic_nand_rel" => - this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::Release)?, - "atomic_nand_acqrel" => - this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::AcqRel)?, - "atomic_nand_relaxed" => - this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::Relaxed)?, - "atomic_xadd" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::SeqCst)?, - "atomic_xadd_acq" => - this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::Acquire)?, - "atomic_xadd_rel" => - this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::Release)?, - "atomic_xadd_acqrel" => - this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::AcqRel)?, - "atomic_xadd_relaxed" => - this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::Relaxed)?, - "atomic_xsub" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::SeqCst)?, - "atomic_xsub_acq" => - this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::Acquire)?, - "atomic_xsub_rel" => - this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::Release)?, - "atomic_xsub_acqrel" => - this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::AcqRel)?, - "atomic_xsub_relaxed" => - this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::Relaxed)?, + "atomic_or" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitOr, false), + AtomicRwOp::SeqCst, + )?, + "atomic_or_acq" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitOr, false), + AtomicRwOp::Acquire, + )?, + "atomic_or_rel" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitOr, false), + AtomicRwOp::Release, + )?, + "atomic_or_acqrel" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitOr, false), + AtomicRwOp::AcqRel, + )?, + "atomic_or_relaxed" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitOr, false), + AtomicRwOp::Relaxed, + )?, + "atomic_xor" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitXor, false), + AtomicRwOp::SeqCst, + )?, + "atomic_xor_acq" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitXor, false), + AtomicRwOp::Acquire, + )?, + "atomic_xor_rel" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitXor, false), + AtomicRwOp::Release, + )?, + "atomic_xor_acqrel" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitXor, false), + AtomicRwOp::AcqRel, + )?, + "atomic_xor_relaxed" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitXor, false), + AtomicRwOp::Relaxed, + )?, + "atomic_and" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitAnd, false), + AtomicRwOp::SeqCst, + )?, + "atomic_and_acq" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitAnd, false), + AtomicRwOp::Acquire, + )?, + "atomic_and_rel" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitAnd, false), + AtomicRwOp::Release, + )?, + "atomic_and_acqrel" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitAnd, false), + AtomicRwOp::AcqRel, + )?, + "atomic_and_relaxed" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitAnd, false), + AtomicRwOp::Relaxed, + )?, + "atomic_nand" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitAnd, true), + AtomicRwOp::SeqCst, + )?, + "atomic_nand_acq" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitAnd, true), + AtomicRwOp::Acquire, + )?, + "atomic_nand_rel" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitAnd, true), + AtomicRwOp::Release, + )?, + "atomic_nand_acqrel" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitAnd, true), + AtomicRwOp::AcqRel, + )?, + "atomic_nand_relaxed" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitAnd, true), + AtomicRwOp::Relaxed, + )?, + "atomic_xadd" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::Add, false), + AtomicRwOp::SeqCst, + )?, + "atomic_xadd_acq" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::Add, false), + AtomicRwOp::Acquire, + )?, + "atomic_xadd_rel" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::Add, false), + AtomicRwOp::Release, + )?, + "atomic_xadd_acqrel" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::Add, false), + AtomicRwOp::AcqRel, + )?, + "atomic_xadd_relaxed" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::Add, false), + AtomicRwOp::Relaxed, + )?, + "atomic_xsub" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::Sub, false), + AtomicRwOp::SeqCst, + )?, + "atomic_xsub_acq" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::Sub, false), + AtomicRwOp::Acquire, + )?, + "atomic_xsub_rel" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::Sub, false), + AtomicRwOp::Release, + )?, + "atomic_xsub_acqrel" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::Sub, false), + AtomicRwOp::AcqRel, + )?, + "atomic_xsub_relaxed" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::Sub, false), + AtomicRwOp::Relaxed, + )?, + "atomic_min" => + this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, + "atomic_min_acq" => + this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, + "atomic_min_rel" => + this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, + "atomic_min_acqrel" => + this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, + "atomic_min_relaxed" => + this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::Relaxed)?, + "atomic_max" => + this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, + "atomic_max_acq" => + this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, + "atomic_max_rel" => + this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, + "atomic_max_acqrel" => + this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, + "atomic_max_relaxed" => + this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::Relaxed)?, + "atomic_umin" => + this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, + "atomic_umin_acq" => + this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, + "atomic_umin_rel" => + this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, + "atomic_umin_acqrel" => + this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, + "atomic_umin_relaxed" => + this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::Relaxed)?, + "atomic_umax" => + this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, + "atomic_umax_acq" => + this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, + "atomic_umax_rel" => + this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, + "atomic_umax_acqrel" => + this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, + "atomic_umax_relaxed" => + this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::Relaxed)?, // Query type information "assert_zero_valid" | "assert_uninit_valid" => { @@ -557,18 +729,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - fn atomic_op( + fn atomic_op_min_max( &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - op: mir::BinOp, - neg: bool, + atomic_op: AtomicOp, atomic: AtomicRwOp, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let &[ref place, ref rhs] = check_arg_count(args)?; let place = this.deref_operand(place)?; + if !place.layout.ty.is_integral() { bug!("Atomic arithmetic operations only work on integer types"); } @@ -580,9 +752,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; - let old = this.atomic_op_immediate(&place, &rhs, op, neg, atomic)?; - this.write_immediate(*old, dest)?; // old value is returned - Ok(()) + match atomic_op { + AtomicOp::Min => { + let old = this.atomic_min_max_scalar(&place, rhs, true, atomic)?; + this.write_immediate(*old, &dest)?; // old value is returned + Ok(()) + } + AtomicOp::Max => { + let old = this.atomic_min_max_scalar(&place, rhs, false, atomic)?; + this.write_immediate(*old, &dest)?; // old value is returned + Ok(()) + } + AtomicOp::MirOp(op, neg) => { + let old = this.atomic_op_immediate(&place, &rhs, op, neg, atomic)?; + this.write_immediate(*old, dest)?; // old value is returned + Ok(()) + } + } } fn atomic_exchange( diff --git a/tests/run-pass/atomic.rs b/tests/run-pass/atomic.rs index 4f27c2bd54d6..9a9e852ecf50 100644 --- a/tests/run-pass/atomic.rs +++ b/tests/run-pass/atomic.rs @@ -74,6 +74,20 @@ fn atomic_u64() { assert_eq!(ATOMIC.compare_exchange(0, 0x100, AcqRel, Acquire), Err(1)); compare_exchange_weak_loop!(ATOMIC, 1, 0x100, AcqRel, Acquire); assert_eq!(ATOMIC.load(Relaxed), 0x100); + + assert_eq!(ATOMIC.fetch_max(0x10, SeqCst), 0x100); + assert_eq!(ATOMIC.fetch_max(0x100, SeqCst), 0x100); + assert_eq!(ATOMIC.fetch_max(0x1000, SeqCst), 0x100); + assert_eq!(ATOMIC.fetch_max(0x1000, SeqCst), 0x1000); + assert_eq!(ATOMIC.fetch_max(0x2000, SeqCst), 0x1000); + assert_eq!(ATOMIC.fetch_max(0x2000, SeqCst), 0x2000); + + assert_eq!(ATOMIC.fetch_min(0x2000, SeqCst), 0x2000); + assert_eq!(ATOMIC.fetch_min(0x2000, SeqCst), 0x2000); + assert_eq!(ATOMIC.fetch_min(0x1000, SeqCst), 0x2000); + assert_eq!(ATOMIC.fetch_min(0x1000, SeqCst), 0x1000); + assert_eq!(ATOMIC.fetch_min(0x100, SeqCst), 0x1000); + assert_eq!(ATOMIC.fetch_min(0x10, SeqCst), 0x100); } fn atomic_fences() { From 9f3dbad5d073f764a28e9c3c1397b4b39d6a3fc2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Mar 2021 19:54:45 +0100 Subject: [PATCH 2569/5092] rename atomic_op_min_max -> atomic_op --- src/shims/intrinsics.rs | 102 ++++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 66ba42c5a017..d7e025f02384 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -394,226 +394,226 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx AtomicReadOp::Acquire, )?, - "atomic_or" => this.atomic_op_min_max( + "atomic_or" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::SeqCst, )?, - "atomic_or_acq" => this.atomic_op_min_max( + "atomic_or_acq" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::Acquire, )?, - "atomic_or_rel" => this.atomic_op_min_max( + "atomic_or_rel" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::Release, )?, - "atomic_or_acqrel" => this.atomic_op_min_max( + "atomic_or_acqrel" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::AcqRel, )?, - "atomic_or_relaxed" => this.atomic_op_min_max( + "atomic_or_relaxed" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::Relaxed, )?, - "atomic_xor" => this.atomic_op_min_max( + "atomic_xor" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::SeqCst, )?, - "atomic_xor_acq" => this.atomic_op_min_max( + "atomic_xor_acq" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::Acquire, )?, - "atomic_xor_rel" => this.atomic_op_min_max( + "atomic_xor_rel" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::Release, )?, - "atomic_xor_acqrel" => this.atomic_op_min_max( + "atomic_xor_acqrel" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::AcqRel, )?, - "atomic_xor_relaxed" => this.atomic_op_min_max( + "atomic_xor_relaxed" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::Relaxed, )?, - "atomic_and" => this.atomic_op_min_max( + "atomic_and" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::SeqCst, )?, - "atomic_and_acq" => this.atomic_op_min_max( + "atomic_and_acq" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::Acquire, )?, - "atomic_and_rel" => this.atomic_op_min_max( + "atomic_and_rel" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::Release, )?, - "atomic_and_acqrel" => this.atomic_op_min_max( + "atomic_and_acqrel" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::AcqRel, )?, - "atomic_and_relaxed" => this.atomic_op_min_max( + "atomic_and_relaxed" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::Relaxed, )?, - "atomic_nand" => this.atomic_op_min_max( + "atomic_nand" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::SeqCst, )?, - "atomic_nand_acq" => this.atomic_op_min_max( + "atomic_nand_acq" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::Acquire, )?, - "atomic_nand_rel" => this.atomic_op_min_max( + "atomic_nand_rel" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::Release, )?, - "atomic_nand_acqrel" => this.atomic_op_min_max( + "atomic_nand_acqrel" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::AcqRel, )?, - "atomic_nand_relaxed" => this.atomic_op_min_max( + "atomic_nand_relaxed" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::Relaxed, )?, - "atomic_xadd" => this.atomic_op_min_max( + "atomic_xadd" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::SeqCst, )?, - "atomic_xadd_acq" => this.atomic_op_min_max( + "atomic_xadd_acq" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::Acquire, )?, - "atomic_xadd_rel" => this.atomic_op_min_max( + "atomic_xadd_rel" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::Release, )?, - "atomic_xadd_acqrel" => this.atomic_op_min_max( + "atomic_xadd_acqrel" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::AcqRel, )?, - "atomic_xadd_relaxed" => this.atomic_op_min_max( + "atomic_xadd_relaxed" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::Relaxed, )?, - "atomic_xsub" => this.atomic_op_min_max( + "atomic_xsub" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::SeqCst, )?, - "atomic_xsub_acq" => this.atomic_op_min_max( + "atomic_xsub_acq" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::Acquire, )?, - "atomic_xsub_rel" => this.atomic_op_min_max( + "atomic_xsub_rel" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::Release, )?, - "atomic_xsub_acqrel" => this.atomic_op_min_max( + "atomic_xsub_acqrel" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::AcqRel, )?, - "atomic_xsub_relaxed" => this.atomic_op_min_max( + "atomic_xsub_relaxed" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::Relaxed, )?, "atomic_min" => - this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, "atomic_min_acq" => - this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, "atomic_min_rel" => - this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, "atomic_min_acqrel" => - this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, "atomic_min_relaxed" => - this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::Relaxed)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Relaxed)?, "atomic_max" => - this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, "atomic_max_acq" => - this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, "atomic_max_rel" => - this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, "atomic_max_acqrel" => - this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, "atomic_max_relaxed" => - this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::Relaxed)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Relaxed)?, "atomic_umin" => - this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, "atomic_umin_acq" => - this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, "atomic_umin_rel" => - this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, "atomic_umin_acqrel" => - this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, "atomic_umin_relaxed" => - this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::Relaxed)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Relaxed)?, "atomic_umax" => - this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, "atomic_umax_acq" => - this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, "atomic_umax_rel" => - this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, "atomic_umax_acqrel" => - this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, "atomic_umax_relaxed" => - this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::Relaxed)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Relaxed)?, // Query type information "assert_zero_valid" | "assert_uninit_valid" => { @@ -729,7 +729,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - fn atomic_op_min_max( + fn atomic_op( &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, From 26e97ec54f665d5d7e35f61fe6f5a6deac5afe7f Mon Sep 17 00:00:00 2001 From: Smitty Date: Thu, 4 Mar 2021 07:48:28 -0500 Subject: [PATCH 2570/5092] Support breakpoint intrinsic --- src/shims/intrinsics.rs | 5 +++++ tests/compile-fail/breakpoint.rs | 7 +++++++ 2 files changed, 12 insertions(+) create mode 100644 tests/compile-fail/breakpoint.rs diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index d7e025f02384..c5f1f58f7068 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -654,6 +654,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "try" => return this.handle_try(args, dest, ret), + "breakpoint" => { + // normally this would raise a SIGTRAP, which aborts if no debugger is connected + throw_machine_stop!(TerminationInfo::Abort("Trace/breakpoint trap".to_string())) + } + name => throw_unsup_format!("unimplemented intrinsic: {}", name), } diff --git a/tests/compile-fail/breakpoint.rs b/tests/compile-fail/breakpoint.rs new file mode 100644 index 000000000000..d0a0239eb933 --- /dev/null +++ b/tests/compile-fail/breakpoint.rs @@ -0,0 +1,7 @@ +#![feature(core_intrinsics)] + +fn main() { + unsafe { + core::intrinsics::breakpoint() //~ ERROR Trace/breakpoint trap + }; +} From 8d43d727f42e918a7aeb76b4596f0726c0e8e0ae Mon Sep 17 00:00:00 2001 From: Smittyvb Date: Fri, 5 Mar 2021 07:16:50 -0500 Subject: [PATCH 2571/5092] Check arg count Co-authored-by: Ralf Jung --- src/shims/intrinsics.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index c5f1f58f7068..64c6e0a540f8 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -655,6 +655,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "try" => return this.handle_try(args, dest, ret), "breakpoint" => { + let &[] = check_arg_count(args)?; // normally this would raise a SIGTRAP, which aborts if no debugger is connected throw_machine_stop!(TerminationInfo::Abort("Trace/breakpoint trap".to_string())) } From 5bd5ea21ea97800e4173a8793beebc424d45358b Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 8 Mar 2021 16:57:09 +0100 Subject: [PATCH 2572/5092] Remove unwrap_none as it won't be stabilized. This upgrades to the latest rustc to be able to use try_insert() instead. --- rust-version | 2 +- src/helpers.rs | 2 +- src/lib.rs | 2 +- src/machine.rs | 4 ++-- src/shims/posix/fs.rs | 4 ++-- src/shims/tls.rs | 2 +- src/stacked_borrows.rs | 2 +- src/thread.rs | 8 ++++---- tests/run-pass/panic/std-panic-locations.rs | 5 ----- 9 files changed, 13 insertions(+), 18 deletions(-) diff --git a/rust-version b/rust-version index 65644e75d977..e518870d5b77 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -09db05762b283bed62d4f92729cfee4646519833 +1d6b0f626aad4ee9f2eaec4d5582f45620ccab80 diff --git a/src/helpers.rs b/src/helpers.rs index 2baaebb0ae20..07356ab02032 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -179,7 +179,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; this.write_immediate(*arg, &callee_arg)?; } - callee_args.next().expect_none("callee has more arguments than expected"); + assert_eq!(callee_args.next(), None, "callee has more arguments than expected"); Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index 5ed3d8950d04..7fc080a937f0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ #![feature(rustc_private)] -#![feature(option_expect_none, option_unwrap_none)] #![feature(map_first_last)] +#![feature(map_try_insert)] #![feature(never_type)] #![feature(or_patterns)] #![feature(try_blocks)] diff --git a/src/machine.rs b/src/machine.rs index 32aae4a8c8e5..1415f7506a4e 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -179,8 +179,8 @@ impl MemoryExtra { this.memory .extra .extern_statics - .insert(Symbol::intern(name), ptr.alloc_id) - .unwrap_none(); + .try_insert(Symbol::intern(name), ptr.alloc_id) + .unwrap(); } /// Sets up the "extern statics" for this machine. diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 2f1efee8c893..def2aca292a5 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -223,7 +223,7 @@ impl<'tcx> FileHandler { self.handles.last_key_value().map(|(fd, _)| fd.checked_add(1).unwrap()).unwrap_or(min_fd) }); - self.handles.insert(new_fd, file_handle).unwrap_none(); + self.handles.try_insert(new_fd, file_handle).unwrap(); new_fd } } @@ -381,7 +381,7 @@ impl DirHandler { fn insert_new(&mut self, read_dir: ReadDir) -> u64 { let id = self.next_id; self.next_id += 1; - self.streams.insert(id, read_dir).unwrap_none(); + self.streams.try_insert(id, read_dir).unwrap(); id } } diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 7f19fd167366..36bae2af9cd0 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -65,7 +65,7 @@ impl<'tcx> TlsData<'tcx> { pub fn create_tls_key(&mut self, dtor: Option>, max_size: Size) -> InterpResult<'tcx, TlsKey> { let new_key = self.next_key; self.next_key += 1; - self.keys.insert(new_key, TlsEntry { data: Default::default(), dtor }).unwrap_none(); + self.keys.try_insert(new_key, TlsEntry { data: Default::default(), dtor }).unwrap(); trace!("New TLS key allocated: {} with dtor {:?}", new_key, dtor); if max_size.bits() < 128 && new_key >= (1u128 << max_size.bits() as u128) { diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index cfaf8a9005ca..fbcd265baa11 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -201,7 +201,7 @@ impl GlobalState { self.base_ptr_ids.get(&id).copied().unwrap_or_else(|| { let tag = Tag::Tagged(self.new_ptr()); trace!("New allocation {:?} has base tag {:?}", id, tag); - self.base_ptr_ids.insert(id, tag).unwrap_none(); + self.base_ptr_ids.try_insert(id, tag).unwrap(); tag }) } diff --git a/src/thread.rs b/src/thread.rs index 5d783430417b..4fe44ef9d4a7 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -257,8 +257,8 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { fn set_thread_local_alloc_id(&self, def_id: DefId, new_alloc_id: AllocId) { self.thread_local_alloc_ids .borrow_mut() - .insert((def_id, self.active_thread), new_alloc_id) - .unwrap_none(); + .try_insert((def_id, self.active_thread), new_alloc_id) + .unwrap(); } /// Borrow the stack of the active thread. @@ -404,8 +404,8 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { callback: TimeoutCallback<'mir, 'tcx>, ) { self.timeout_callbacks - .insert(thread, TimeoutCallbackInfo { call_time, callback }) - .unwrap_none(); + .try_insert(thread, TimeoutCallbackInfo { call_time, callback }) + .unwrap(); } /// Unregister the callback for the `thread`. diff --git a/tests/run-pass/panic/std-panic-locations.rs b/tests/run-pass/panic/std-panic-locations.rs index ac2e8d5305df..e3050ad11835 100644 --- a/tests/run-pass/panic/std-panic-locations.rs +++ b/tests/run-pass/panic/std-panic-locations.rs @@ -1,4 +1,3 @@ -#![feature(option_expect_none, option_unwrap_none)] //! Test that panic locations for `#[track_caller]` functions in std have the correct //! location reported. @@ -25,10 +24,6 @@ fn main() { assert_panicked(|| nope.unwrap()); assert_panicked(|| nope.expect("")); - let yep: Option<()> = Some(()); - assert_panicked(|| yep.unwrap_none()); - assert_panicked(|| yep.expect_none("")); - let oops: Result<(), ()> = Err(()); assert_panicked(|| oops.unwrap()); assert_panicked(|| oops.expect("")); From 90e218ad90a04d8a014811372188d3e85ec8480f Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 8 Mar 2021 17:06:50 +0100 Subject: [PATCH 2573/5092] Fix panic test. --- tests/run-pass/panic/std-panic-locations.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/panic/std-panic-locations.rs b/tests/run-pass/panic/std-panic-locations.rs index e3050ad11835..8781a371d51f 100644 --- a/tests/run-pass/panic/std-panic-locations.rs +++ b/tests/run-pass/panic/std-panic-locations.rs @@ -35,5 +35,5 @@ fn main() { // Cleanup: reset to default hook. drop(std::panic::take_hook()); - assert_eq!(HOOK_COUNT.load(Ordering::Relaxed), 8); + assert_eq!(HOOK_COUNT.load(Ordering::Relaxed), 6); } From 1e19150d1eb6bd799e5d066adff83ce69df69e34 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Mon, 8 Mar 2021 17:28:52 +0000 Subject: [PATCH 2574/5092] Opt-in to rustc_private for `rust-analyzer` rust-analyzer/rust-analyzer#7891 --- Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 7580d140b55f..123594afe56c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,3 +40,7 @@ libc = "0.2" compiletest_rs = { version = "0.5", features = ["tmp"] } rustc_version = "0.2.3" colored = "2" + +[package.metadata.rust-analyzer] +# This crate uses #[feature(rustc_private)] +rustc_private = true From 38da1fab787edc090f068a4226c07373dfa2f5b7 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 9 Mar 2021 14:50:38 +0100 Subject: [PATCH 2575/5092] mir-opt-level 4 is the new 3 --- ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index 6dae2cfd46c6..a86c5ca490a4 100755 --- a/ci.sh +++ b/ci.sh @@ -24,7 +24,7 @@ function run_tests { if [ -z "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with optimizations (`-O` is what cargo passes, but crank MIR # optimizations up all the way). - MIRIFLAGS="-O -Zmir-opt-level=3" ./miri test --locked + MIRIFLAGS="-O -Zmir-opt-level=4" ./miri test --locked fi # On Windows, there is always "python", not "python3" or "python2". From 6106ee214c467450bd5b028e3cd64a675a710a6e Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Tue, 9 Mar 2021 18:27:22 +0000 Subject: [PATCH 2576/5092] Add link to pr for documentation --- Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 123594afe56c..5f9e93f2347b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,5 +42,6 @@ rustc_version = "0.2.3" colored = "2" [package.metadata.rust-analyzer] -# This crate uses #[feature(rustc_private)] +# This crate uses #[feature(rustc_private)]. +# See https://github.com/rust-analyzer/rust-analyzer/pull/7891 rustc_private = true From 7a7f7b1a7a2361354bc82870aab2875951d5a6e4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 10 Mar 2021 15:21:12 +0100 Subject: [PATCH 2577/5092] rustup --- rust-version | 2 +- tests/compile-fail/intrinsics/copy_overflow.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index e518870d5b77..53ac7c54983b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1d6b0f626aad4ee9f2eaec4d5582f45620ccab80 +a4d9624242df6bfe6c0a298867dd2bd527263424 diff --git a/tests/compile-fail/intrinsics/copy_overflow.rs b/tests/compile-fail/intrinsics/copy_overflow.rs index c75cf6917b10..b09aedcf7470 100644 --- a/tests/compile-fail/intrinsics/copy_overflow.rs +++ b/tests/compile-fail/intrinsics/copy_overflow.rs @@ -1,4 +1,4 @@ -// error-pattern: overflow computing total size of `copy` +// error-pattern: overflow computing total size use std::mem; fn main() { From 98f28ac9c8f29b12a0aa56ea13720db5d469fb2a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Mar 2021 09:07:05 +0100 Subject: [PATCH 2578/5092] rustup --- rust-version | 2 +- src/helpers.rs | 2 +- src/shims/foreign_items.rs | 36 +++++++++---------- src/shims/posix/dlsym.rs | 2 +- src/shims/posix/foreign_items.rs | 2 +- src/shims/windows/dlsym.rs | 2 +- src/shims/windows/foreign_items.rs | 2 +- .../concurrency/unwind_top_of_stack.rs | 7 ++-- 8 files changed, 29 insertions(+), 26 deletions(-) diff --git a/rust-version b/rust-version index 53ac7c54983b..f064064db14c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a4d9624242df6bfe6c0a298867dd2bd527263424 +b3ac52646f7591a811fa9bf55995b24fd17ece08 diff --git a/src/helpers.rs b/src/helpers.rs index 07356ab02032..e98488b9bf61 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -559,7 +559,7 @@ pub fn check_abi<'a>(abi: Abi, exp_abi: Abi) -> InterpResult<'a, ()> { if abi == exp_abi { Ok(()) } else { - throw_ub_format!("calling a function with ABI {:?} using caller ABI {:?}", exp_abi, abi) + throw_ub_format!("calling a function with ABI {} using caller ABI {}", exp_abi.name(), abi.name()) } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 9203aafd5767..373d5299618d 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -146,14 +146,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "exit" | "ExitProcess" => { - check_abi(abi, if link_name == "exit" { Abi::C } else { Abi::System })?; + check_abi(abi, if link_name == "exit" { Abi::C { unwind: false } } else { Abi::System { unwind: false } })?; let &[ref code] = check_arg_count(args)?; // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway let code = this.read_scalar(code)?.to_i32()?; throw_machine_stop!(TerminationInfo::Exit(code.into())); } "abort" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; throw_machine_stop!(TerminationInfo::Abort("the program aborted execution".to_owned())) } _ => throw_unsup_format!("can't call (diverging) foreign function: {}", link_name), @@ -170,7 +170,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Normally, this will be either `libpanic_unwind` or `libpanic_abort`, but it could // also be a custom user-provided implementation via `#![feature(panic_runtime)]` "__rust_start_panic" | "__rust_panic_cleanup" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; // This replicates some of the logic in `inject_panic_runtime`. // FIXME: is there a way to reuse that logic? let panic_runtime = match this.tcx.sess.panic_strategy() { @@ -236,14 +236,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Standard C allocation "malloc" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[ref size] = check_arg_count(args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C); this.write_scalar(res, dest)?; } "calloc" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[ref items, ref len] = check_arg_count(args)?; let items = this.read_scalar(items)?.to_machine_usize(this)?; let len = this.read_scalar(len)?.to_machine_usize(this)?; @@ -253,13 +253,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } "free" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; this.free(ptr, MiriMemoryKind::C)?; } "realloc" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[ref old_ptr, ref new_size] = check_arg_count(args)?; let old_ptr = this.read_scalar(old_ptr)?.check_init()?; let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; @@ -334,7 +334,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // C memory handling functions "memcmp" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[ref left, ref right, ref n] = check_arg_count(args)?; let left = this.read_scalar(left)?.check_init()?; let right = this.read_scalar(right)?.check_init()?; @@ -355,7 +355,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "memrchr" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[ref ptr, ref val, ref num] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; @@ -374,7 +374,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "memchr" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[ref ptr, ref val, ref num] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; @@ -392,7 +392,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "strlen" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let n = this.memory.read_c_str(ptr)?.len(); @@ -408,7 +408,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asinf" | "atanf" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[ref f] = check_arg_count(args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); @@ -428,7 +428,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypotf" | "atan2f" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[ref f1, ref f2] = check_arg_count(args)?; // underscore case for windows, here and below // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) @@ -450,7 +450,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asin" | "atan" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[ref f] = check_arg_count(args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); @@ -470,7 +470,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypot" | "atan2" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[ref f1, ref f2] = check_arg_count(args)?; // FIXME: Using host floats. let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?); @@ -486,7 +486,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "ldexp" | "scalbn" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[ref x, ref exp] = check_arg_count(args)?; // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. let x = this.read_scalar(x)?.to_f64()?; @@ -508,12 +508,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Architecture-specific shims "llvm.x86.sse2.pause" if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.yield_active_thread(); } "llvm.aarch64.hint" if this.tcx.sess.target.arch == "aarch64" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[ref hint] = check_arg_count(args)?; let hint = this.read_scalar(hint)?.to_i32()?; match hint { diff --git a/src/shims/posix/dlsym.rs b/src/shims/posix/dlsym.rs index e1eccc680883..df9e945f29f7 100644 --- a/src/shims/posix/dlsym.rs +++ b/src/shims/posix/dlsym.rs @@ -35,7 +35,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; match dlsym { Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, ret), diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 21b5ed62bbb5..fdbe88cd7d61 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -22,7 +22,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; match link_name { // Environment related shims diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 1f136060259a..704b8872a4b0 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -32,7 +32,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (_dest, _ret) = ret.expect("we don't support any diverging dlsym"); assert!(this.tcx.sess.target.os == "windows"); - check_abi(abi, Abi::System)?; + check_abi(abi, Abi::System { unwind: false })?; match dlsym {} } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index f8d62f6b323b..d9c5ce7896f6 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -20,7 +20,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - check_abi(abi, Abi::System)?; + check_abi(abi, Abi::System { unwind: false })?; // Windows API stubs. // HANDLE = isize diff --git a/tests/compile-fail/concurrency/unwind_top_of_stack.rs b/tests/compile-fail/concurrency/unwind_top_of_stack.rs index 93b15202fc38..c13a2ac8bb04 100644 --- a/tests/compile-fail/concurrency/unwind_top_of_stack.rs +++ b/tests/compile-fail/concurrency/unwind_top_of_stack.rs @@ -3,13 +3,13 @@ //! Unwinding past the top frame of a stack is Undefined Behavior. -#![feature(rustc_private)] +#![feature(rustc_private, c_unwind)] extern crate libc; use std::{mem, ptr}; -extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { +extern "C-unwind" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { panic!() } @@ -18,6 +18,9 @@ fn main() { let mut native: libc::pthread_t = mem::zeroed(); let attr: libc::pthread_attr_t = mem::zeroed(); // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented. + // Cast to avoid inserting abort-on-unwind. + let thread_start: extern "C-unwind" fn(*mut libc::c_void) -> *mut libc::c_void = thread_start; + let thread_start: extern "C" fn(*mut libc::c_void) -> *mut libc::c_void = mem::transmute(thread_start); assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0); assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); } From 893843fd455aa515a5d05cc8e70a970a84dab35d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Mar 2021 15:30:37 +0100 Subject: [PATCH 2579/5092] when Miri calls a function ptr, make sure it has the right ABI --- src/eval.rs | 2 ++ src/helpers.rs | 6 ++++++ src/machine.rs | 1 + src/shims/panic.rs | 5 +++++ src/shims/posix/thread.rs | 2 ++ src/shims/tls.rs | 4 ++++ tests/compile-fail/concurrency/unwind_top_of_stack.rs | 5 ++++- 7 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/eval.rs b/src/eval.rs index 7a29d91d2d8e..bd1aebe00de8 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -8,6 +8,7 @@ use log::info; use rustc_hir::def_id::DefId; use rustc_middle::ty::{self, layout::LayoutCx, TyCtxt}; use rustc_target::abi::LayoutOf; +use rustc_target::spec::abi::Abi; use crate::*; @@ -189,6 +190,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Call start function. ecx.call_function( start_instance, + Abi::Rust, &[main_ptr.into(), argc.into(), argv.into()], Some(&ret_place.into()), StackPopCleanup::None { cleanup: true }, diff --git a/src/helpers.rs b/src/helpers.rs index e98488b9bf61..1f1c9922754c 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -161,11 +161,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn call_function( &mut self, f: ty::Instance<'tcx>, + caller_abi: Abi, args: &[Immediate], dest: Option<&PlaceTy<'tcx, Tag>>, stack_pop: StackPopCleanup, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + let param_env = ty::ParamEnv::reveal_all(); // in Miri this is always the param_env we use... and this.param_env is private. + let callee_abi = f.ty(*this.tcx, param_env).fn_sig(*this.tcx).abi(); + if callee_abi != caller_abi { + throw_ub_format!("calling a function with ABI {} using caller ABI {}", callee_abi.name(), caller_abi.name()) + } // Push frame. let mir = &*this.load_mir(f.def, None)?; diff --git a/src/machine.rs b/src/machine.rs index 1415f7506a4e..99cb3bf2b29c 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -430,6 +430,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { let malloc = ty::Instance::mono(ecx.tcx.tcx, malloc); ecx.call_function( malloc, + Abi::Rust, &[size.into(), align.into()], Some(dest), // Don't do anything when we are done. The `statement()` function will increment diff --git a/src/shims/panic.rs b/src/shims/panic.rs index abc7aa2ad1bd..2c6d31549c35 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -15,6 +15,7 @@ use log::trace; use rustc_middle::{mir, ty}; use rustc_target::spec::PanicStrategy; +use rustc_target::spec::abi::Abi; use crate::*; use helpers::check_arg_count; @@ -94,6 +95,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); this.call_function( f_instance, + Abi::Rust, &[data.into()], Some(&ret_place), // Directly return to caller. @@ -145,6 +147,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); this.call_function( f_instance, + Abi::Rust, &[catch_unwind.data.into(), payload.into()], Some(&ret_place), // Directly return to caller of `try`. @@ -174,6 +177,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let panic = ty::Instance::mono(this.tcx.tcx, panic); this.call_function( panic, + Abi::Rust, &[msg.to_ref()], None, StackPopCleanup::Goto { ret: None, unwind }, @@ -202,6 +206,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let panic_bounds_check = ty::Instance::mono(this.tcx.tcx, panic_bounds_check); this.call_function( panic_bounds_check, + Abi::Rust, &[index.into(), len.into()], None, StackPopCleanup::Goto { ret: None, unwind }, diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index 40663326b465..fb1c018fc34b 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -2,6 +2,7 @@ use std::convert::TryInto; use crate::*; use rustc_target::abi::LayoutOf; +use rustc_target::spec::abi::Abi; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -50,6 +51,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.call_function( instance, + Abi::C { unwind: false }, &[*func_arg], Some(&ret_place.into()), StackPopCleanup::None { cleanup: true }, diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 36bae2af9cd0..ef77949efada 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -9,6 +9,7 @@ use log::trace; use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty; use rustc_target::abi::{Size, HasDataLayout}; +use rustc_target::spec::abi::Abi; use crate::*; @@ -244,6 +245,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); this.call_function( thread_callback, + Abi::System { unwind: false }, &[Scalar::null_ptr(this).into(), reason.into(), Scalar::null_ptr(this).into()], Some(&ret_place), StackPopCleanup::None { cleanup: true }, @@ -266,6 +268,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); this.call_function( instance, + Abi::C { unwind: false }, &[data.into()], Some(&ret_place), StackPopCleanup::None { cleanup: true }, @@ -306,6 +309,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); this.call_function( instance, + Abi::C { unwind: false }, &[ptr.into()], Some(&ret_place), StackPopCleanup::None { cleanup: true }, diff --git a/tests/compile-fail/concurrency/unwind_top_of_stack.rs b/tests/compile-fail/concurrency/unwind_top_of_stack.rs index c13a2ac8bb04..8f3bb17470b5 100644 --- a/tests/compile-fail/concurrency/unwind_top_of_stack.rs +++ b/tests/compile-fail/concurrency/unwind_top_of_stack.rs @@ -1,7 +1,10 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// error-pattern: unwinding past the topmost frame of the stack +// error-pattern: calling a function with ABI C-unwind using caller ABI C //! Unwinding past the top frame of a stack is Undefined Behavior. +//! However, it is impossible to do that in pure Rust since one cannot write an unwinding +//! function with `C` ABI... so let's instead test that we are indeed correctly checking +//! the callee ABI in `pthread_create`. #![feature(rustc_private, c_unwind)] From d1dec9cd233bf28f2bab14126c3d9df93683ae17 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Mar 2021 15:38:22 +0100 Subject: [PATCH 2580/5092] don't ICE when callee has the wrong number of arguments --- src/helpers.rs | 8 ++++-- .../compile-fail/concurrency/too_few_args.rs | 26 +++++++++++++++++++ .../compile-fail/concurrency/too_many_args.rs | 26 +++++++++++++++++++ 3 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 tests/compile-fail/concurrency/too_few_args.rs create mode 100644 tests/compile-fail/concurrency/too_many_args.rs diff --git a/src/helpers.rs b/src/helpers.rs index 1f1c9922754c..7fe0ae0a97c4 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -181,11 +181,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut callee_args = this.frame().body.args_iter(); for arg in args { let callee_arg = this.local_place( - callee_args.next().expect("callee has fewer arguments than expected"), + callee_args.next().ok_or_else(|| + err_ub_format!("callee has fewer arguments than expected") + )? )?; this.write_immediate(*arg, &callee_arg)?; } - assert_eq!(callee_args.next(), None, "callee has more arguments than expected"); + if callee_args.next().is_some() { + throw_ub_format!("callee has more arguments than expected"); + } Ok(()) } diff --git a/tests/compile-fail/concurrency/too_few_args.rs b/tests/compile-fail/concurrency/too_few_args.rs new file mode 100644 index 000000000000..e2dfa33af898 --- /dev/null +++ b/tests/compile-fail/concurrency/too_few_args.rs @@ -0,0 +1,26 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// error-pattern: callee has fewer arguments than expected + +//! The thread function must have exactly one argument. + +#![feature(rustc_private)] + +extern crate libc; + +use std::{mem, ptr}; + +extern "C" fn thread_start() -> *mut libc::c_void { + panic!() +} + +fn main() { + unsafe { + let mut native: libc::pthread_t = mem::zeroed(); + let attr: libc::pthread_attr_t = mem::zeroed(); + // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented. + let thread_start: extern "C" fn() -> *mut libc::c_void = thread_start; + let thread_start: extern "C" fn(*mut libc::c_void) -> *mut libc::c_void = mem::transmute(thread_start); + assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0); + assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); + } +} diff --git a/tests/compile-fail/concurrency/too_many_args.rs b/tests/compile-fail/concurrency/too_many_args.rs new file mode 100644 index 000000000000..0ef12b07073f --- /dev/null +++ b/tests/compile-fail/concurrency/too_many_args.rs @@ -0,0 +1,26 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// error-pattern: callee has more arguments than expected + +//! The thread function must have exactly one argument. + +#![feature(rustc_private)] + +extern crate libc; + +use std::{mem, ptr}; + +extern "C" fn thread_start(_null: *mut libc::c_void, _x: i32) -> *mut libc::c_void { + panic!() +} + +fn main() { + unsafe { + let mut native: libc::pthread_t = mem::zeroed(); + let attr: libc::pthread_attr_t = mem::zeroed(); + // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented. + let thread_start: extern "C" fn(*mut libc::c_void, i32) -> *mut libc::c_void = thread_start; + let thread_start: extern "C" fn(*mut libc::c_void) -> *mut libc::c_void = mem::transmute(thread_start); + assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0); + assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); + } +} From c9ff02f549cf30cf9f3007b34fde89dcf0f46ac2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Mar 2021 17:03:20 +0100 Subject: [PATCH 2581/5092] ensure we catch incorrectly unwinding calls --- tests/compile-fail/panic/bad_unwind.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tests/compile-fail/panic/bad_unwind.rs diff --git a/tests/compile-fail/panic/bad_unwind.rs b/tests/compile-fail/panic/bad_unwind.rs new file mode 100644 index 000000000000..fde2c19af07d --- /dev/null +++ b/tests/compile-fail/panic/bad_unwind.rs @@ -0,0 +1,16 @@ +// error-pattern: calling a function with ABI C-unwind using caller ABI C +#![feature(c_unwind)] + +//! Unwinding when the caller ABI is "C" (without "-unwind") is UB. +//! Currently we detect the ABI mismatch; we could probably allow such calls in principle one day +//! but then we have to detect the unexpected unwinding. + +extern "C-unwind" fn unwind() { + panic!(); +} + +fn main() { + let unwind: extern "C-unwind" fn() = unwind; + let unwind: extern "C" fn() = unsafe { std::mem::transmute(unwind) }; + std::panic::catch_unwind(|| unwind()).unwrap_err(); +} From 15465a58812f7af4f5d27eb87da191b344d281b5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Mar 2021 17:10:45 +0100 Subject: [PATCH 2582/5092] don't ICE when we unwind despite panic=abort --- src/shims/panic.rs | 4 +++- tests/compile-fail/panic/unwind_panic_abort.rs | 11 +++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/panic/unwind_panic_abort.rs diff --git a/src/shims/panic.rs b/src/shims/panic.rs index abc7aa2ad1bd..8f06e5276f52 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -45,7 +45,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("miri_start_panic: {:?}", this.frame().instance); // Make sure we only start unwinding when this matches our panic strategy. - assert_eq!(this.tcx.sess.panic_strategy(), PanicStrategy::Unwind); + if this.tcx.sess.panic_strategy() != PanicStrategy::Unwind { + throw_ub_format!("unwinding despite panic=abort"); + } // Get the raw pointer stored in arg[0] (the panic payload). let &[ref payload] = check_arg_count(args)?; diff --git a/tests/compile-fail/panic/unwind_panic_abort.rs b/tests/compile-fail/panic/unwind_panic_abort.rs new file mode 100644 index 000000000000..05284eb770b2 --- /dev/null +++ b/tests/compile-fail/panic/unwind_panic_abort.rs @@ -0,0 +1,11 @@ +// compile-flags: -Cpanic=abort + +//! Unwinding despite `-C panic=abort` is an error. + +extern "Rust" { + fn miri_start_panic(payload: *mut u8) -> !; +} + +fn main() { + unsafe { miri_start_panic(&mut 0); } //~ ERROR unwinding despite panic=abort +} From 1c7d7471dae217810f48e594baca2e143a38da10 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Wed, 17 Mar 2021 00:40:53 +0800 Subject: [PATCH 2583/5092] Don't duplicate `check_abi()` --- src/helpers.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 7fe0ae0a97c4..fe4766d87700 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -169,9 +169,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let param_env = ty::ParamEnv::reveal_all(); // in Miri this is always the param_env we use... and this.param_env is private. let callee_abi = f.ty(*this.tcx, param_env).fn_sig(*this.tcx).abi(); - if callee_abi != caller_abi { - throw_ub_format!("calling a function with ABI {} using caller ABI {}", callee_abi.name(), caller_abi.name()) - } + check_abi(caller_abi, callee_abi)?; // Push frame. let mir = &*this.load_mir(f.def, None)?; From bbc348539bce27627c60b4a27d6a822643f1c002 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Wed, 17 Mar 2021 04:21:17 +0800 Subject: [PATCH 2584/5092] Unsupported foreign non-"C"/"system"-ABI function calls are not UB --- src/shims/foreign_items.rs | 30 +++++++++++++++++++ src/shims/posix/foreign_items.rs | 12 ++++---- src/shims/posix/linux/foreign_items.rs | 6 ++-- src/shims/posix/macos/foreign_items.rs | 8 +++-- src/shims/windows/foreign_items.rs | 8 ++--- .../unsupported_foreign_function.rs | 9 ++++++ tests/compile-fail/unsupported_posix_dlsym.rs | 14 +++++++++ .../compile-fail/unsupported_windows_dlsym.rs | 18 +++++++++++ 8 files changed, 88 insertions(+), 17 deletions(-) create mode 100644 tests/compile-fail/unsupported_foreign_function.rs create mode 100644 tests/compile-fail/unsupported_posix_dlsym.rs create mode 100644 tests/compile-fail/unsupported_windows_dlsym.rs diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 373d5299618d..599d7268a305 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -13,6 +13,36 @@ use crate::*; use super::backtrace::EvalContextExt as _; use helpers::{check_abi, check_arg_count}; +/// This macro behaves just like `match $link_name { ... }`, but inserts a +/// `$crate::helpers::check_abi($abi, $exp_abi)?` call at each match arm +/// except the wildcard one. +#[macro_export] +macro_rules! match_with_abi_check { + ($link_name:expr, $abi:expr, $exp_abi:expr, { + $(|)? $($pattern:pat)|+ $(if $guard:expr)? => $shim_impl:block + $($remaining:tt)+ + }) => { + match ($link_name, $abi, $exp_abi) { + ($($pattern)|+, abi, exp_abi) $(if $guard)? => { + $crate::helpers::check_abi(abi, exp_abi)?; + $shim_impl + } + (link_name, abi, exp_abi) => match_with_abi_check!( + link_name, + abi, + exp_abi, + { $($remaining)* } + ), + } + }; + ($link_name:ident, $abi:ident, $exp_abi:ident, { + _ => $fallback:expr $(,)? + }) => ({ + let _ = ($link_name, $abi, $exp_abi); + $fallback + }); +} + impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Returns the minimum alignment for the target architecture for allocations of the given size. diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index fdbe88cd7d61..e773c8bcf360 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -5,7 +5,7 @@ use rustc_target::abi::{Align, LayoutOf, Size}; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::{check_abi, check_arg_count}; +use helpers::check_arg_count; use shims::posix::fs::EvalContextExt as _; use shims::posix::sync::EvalContextExt as _; use shims::posix::thread::EvalContextExt as _; @@ -22,9 +22,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - check_abi(abi, Abi::C { unwind: false })?; - - match link_name { + match_with_abi_check!(link_name, abi, Abi::C { unwind: false }, { // Environment related shims "getenv" => { let &[ref name] = check_arg_count(args)?; @@ -458,12 +456,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Platform-specific shims _ => { match this.tcx.sess.target.os.as_str() { - "linux" => return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), - "macos" => return shims::posix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), + "linux" => return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), + "macos" => return shims::posix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), _ => unreachable!(), } } - }; + }); Ok(true) } diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 2a3b512bcdb9..f61e37284e41 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -1,4 +1,5 @@ use rustc_middle::mir; +use rustc_target::spec::abi::Abi; use crate::*; use crate::helpers::check_arg_count; @@ -12,13 +13,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_foreign_item_by_name( &mut self, link_name: &str, + abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, _ret: mir::BasicBlock, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - match link_name { + match_with_abi_check!(link_name, abi, Abi::C { unwind: false }, { // errno "__errno_location" => { let &[] = check_arg_count(args)?; @@ -189,7 +191,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } _ => throw_unsup_format!("can't call foreign function: {}", link_name), - }; + }); Ok(true) } diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index 1ea12148303e..cb57c4d2f6a1 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -1,4 +1,5 @@ use rustc_middle::mir; +use rustc_target::spec::abi::Abi; use crate::*; use helpers::check_arg_count; @@ -10,13 +11,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_foreign_item_by_name( &mut self, link_name: &str, + abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, _ret: mir::BasicBlock, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - match link_name { + match_with_abi_check!(link_name, abi, Abi::C { unwind: false }, { // errno "__error" => { let &[] = check_arg_count(args)?; @@ -83,7 +85,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[ref info] = check_arg_count(args)?; let result = this.mach_timebase_info(info)?; this.write_scalar(Scalar::from_i32(result), dest)?; - }, + } // Access to command-line arguments "_NSGetArgc" => { @@ -136,7 +138,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } _ => throw_unsup_format!("can't call foreign function: {}", link_name), - }; + }); Ok(true) } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index d9c5ce7896f6..9e8e6b58985e 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -5,7 +5,7 @@ use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::{check_abi, check_arg_count}; +use helpers::check_arg_count; use shims::windows::sync::EvalContextExt as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -20,14 +20,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - check_abi(abi, Abi::System { unwind: false })?; - // Windows API stubs. // HANDLE = isize // DWORD = ULONG = u32 // BOOL = i32 // BOOLEAN = u8 - match link_name { + match_with_abi_check!(link_name, abi, Abi::System { unwind: false }, { // Environment related shims "GetEnvironmentVariableW" => { let &[ref name, ref buf, ref size] = check_arg_count(args)?; @@ -340,7 +338,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } _ => throw_unsup_format!("can't call foreign function: {}", link_name), - } + }); Ok(true) } diff --git a/tests/compile-fail/unsupported_foreign_function.rs b/tests/compile-fail/unsupported_foreign_function.rs new file mode 100644 index 000000000000..b7f4d9038ec6 --- /dev/null +++ b/tests/compile-fail/unsupported_foreign_function.rs @@ -0,0 +1,9 @@ +fn main() { + extern "Rust" { + fn foo(); + } + + unsafe { + foo(); //~ ERROR unsupported operation: can't call foreign function: foo + } +} diff --git a/tests/compile-fail/unsupported_posix_dlsym.rs b/tests/compile-fail/unsupported_posix_dlsym.rs new file mode 100644 index 000000000000..07859b311811 --- /dev/null +++ b/tests/compile-fail/unsupported_posix_dlsym.rs @@ -0,0 +1,14 @@ +// ignore-windows: No dlsym() on Windows + +#![feature(rustc_private)] + +extern crate libc; + +use std::ptr; + +fn main() { + unsafe { + libc::dlsym(ptr::null_mut(), b"foo\0".as_ptr().cast()); + //~^ ERROR unsupported operation: unsupported + } +} diff --git a/tests/compile-fail/unsupported_windows_dlsym.rs b/tests/compile-fail/unsupported_windows_dlsym.rs new file mode 100644 index 000000000000..757eb815920e --- /dev/null +++ b/tests/compile-fail/unsupported_windows_dlsym.rs @@ -0,0 +1,18 @@ +// ignore-linux: GetProcAddress() is not available on Linux +// ignore-macos: GetProcAddress() is not available on macOS + +use std::{ffi::c_void, os::raw::c_char, ptr}; + +extern "system" { + fn GetProcAddress( + hModule: *mut c_void, + lpProcName: *const c_char, + ) -> extern "system" fn() -> isize; +} + +fn main() { + unsafe { + GetProcAddress(ptr::null_mut(), b"foo\0".as_ptr().cast()); + //~^ ERROR unsupported operation: unsupported Windows dlsym: foo + } +} From 3ee865461f3fa128835f3d79ea5f396e6ebdf6c1 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Wed, 17 Mar 2021 21:51:07 +0800 Subject: [PATCH 2585/5092] Revert "Don't duplicate `check_abi()`" This reverts commit 1c7d7471dae217810f48e594baca2e143a38da10. --- src/helpers.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/helpers.rs b/src/helpers.rs index fe4766d87700..7fe0ae0a97c4 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -169,7 +169,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let param_env = ty::ParamEnv::reveal_all(); // in Miri this is always the param_env we use... and this.param_env is private. let callee_abi = f.ty(*this.tcx, param_env).fn_sig(*this.tcx).abi(); - check_abi(caller_abi, callee_abi)?; + if callee_abi != caller_abi { + throw_ub_format!("calling a function with ABI {} using caller ABI {}", callee_abi.name(), caller_abi.name()) + } // Push frame. let mir = &*this.load_mir(f.def, None)?; From 633ac2a22226b27981b52ce6ed5af47fcc251746 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Wed, 17 Mar 2021 21:55:45 +0800 Subject: [PATCH 2586/5092] Remove meaningless tests --- tests/compile-fail/unsupported_posix_dlsym.rs | 14 -------------- .../compile-fail/unsupported_windows_dlsym.rs | 18 ------------------ 2 files changed, 32 deletions(-) delete mode 100644 tests/compile-fail/unsupported_posix_dlsym.rs delete mode 100644 tests/compile-fail/unsupported_windows_dlsym.rs diff --git a/tests/compile-fail/unsupported_posix_dlsym.rs b/tests/compile-fail/unsupported_posix_dlsym.rs deleted file mode 100644 index 07859b311811..000000000000 --- a/tests/compile-fail/unsupported_posix_dlsym.rs +++ /dev/null @@ -1,14 +0,0 @@ -// ignore-windows: No dlsym() on Windows - -#![feature(rustc_private)] - -extern crate libc; - -use std::ptr; - -fn main() { - unsafe { - libc::dlsym(ptr::null_mut(), b"foo\0".as_ptr().cast()); - //~^ ERROR unsupported operation: unsupported - } -} diff --git a/tests/compile-fail/unsupported_windows_dlsym.rs b/tests/compile-fail/unsupported_windows_dlsym.rs deleted file mode 100644 index 757eb815920e..000000000000 --- a/tests/compile-fail/unsupported_windows_dlsym.rs +++ /dev/null @@ -1,18 +0,0 @@ -// ignore-linux: GetProcAddress() is not available on Linux -// ignore-macos: GetProcAddress() is not available on macOS - -use std::{ffi::c_void, os::raw::c_char, ptr}; - -extern "system" { - fn GetProcAddress( - hModule: *mut c_void, - lpProcName: *const c_char, - ) -> extern "system" fn() -> isize; -} - -fn main() { - unsafe { - GetProcAddress(ptr::null_mut(), b"foo\0".as_ptr().cast()); - //~^ ERROR unsupported operation: unsupported Windows dlsym: foo - } -} From 7ec919daa4c3e211dd2ef56014a11f967c583013 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Wed, 17 Mar 2021 22:12:08 +0800 Subject: [PATCH 2587/5092] Remove the macro and expand it manually --- src/shims/foreign_items.rs | 30 ------------ src/shims/posix/foreign_items.rs | 67 ++++++++++++++++++++++++-- src/shims/posix/linux/foreign_items.rs | 22 +++++++-- src/shims/posix/macos/foreign_items.rs | 27 +++++++++-- src/shims/windows/foreign_items.rs | 45 +++++++++++++++-- 5 files changed, 148 insertions(+), 43 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 599d7268a305..373d5299618d 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -13,36 +13,6 @@ use crate::*; use super::backtrace::EvalContextExt as _; use helpers::{check_abi, check_arg_count}; -/// This macro behaves just like `match $link_name { ... }`, but inserts a -/// `$crate::helpers::check_abi($abi, $exp_abi)?` call at each match arm -/// except the wildcard one. -#[macro_export] -macro_rules! match_with_abi_check { - ($link_name:expr, $abi:expr, $exp_abi:expr, { - $(|)? $($pattern:pat)|+ $(if $guard:expr)? => $shim_impl:block - $($remaining:tt)+ - }) => { - match ($link_name, $abi, $exp_abi) { - ($($pattern)|+, abi, exp_abi) $(if $guard)? => { - $crate::helpers::check_abi(abi, exp_abi)?; - $shim_impl - } - (link_name, abi, exp_abi) => match_with_abi_check!( - link_name, - abi, - exp_abi, - { $($remaining)* } - ), - } - }; - ($link_name:ident, $abi:ident, $exp_abi:ident, { - _ => $fallback:expr $(,)? - }) => ({ - let _ = ($link_name, $abi, $exp_abi); - $fallback - }); -} - impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Returns the minimum alignment for the target architecture for allocations of the given size. diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index e773c8bcf360..b3d53cdc10de 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -5,7 +5,7 @@ use rustc_target::abi::{Align, LayoutOf, Size}; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::check_arg_count; +use helpers::{check_abi, check_arg_count}; use shims::posix::fs::EvalContextExt as _; use shims::posix::sync::EvalContextExt as _; use shims::posix::thread::EvalContextExt as _; @@ -22,30 +22,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - match_with_abi_check!(link_name, abi, Abi::C { unwind: false }, { + match link_name { // Environment related shims "getenv" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let result = this.getenv(name)?; this.write_scalar(result, dest)?; } "unsetenv" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let result = this.unsetenv(name)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "setenv" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref name, ref value, ref overwrite] = check_arg_count(args)?; this.read_scalar(overwrite)?.to_i32()?; let result = this.setenv(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "getcwd" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref buf, ref size] = check_arg_count(args)?; let result = this.getcwd(buf, size)?; this.write_scalar(result, dest)?; } "chdir" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref path] = check_arg_count(args)?; let result = this.chdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -53,15 +58,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "open" | "open64" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref path, ref flag, ref mode] = check_arg_count(args)?; let result = this.open(path, flag, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fcntl" => { + check_abi(abi, Abi::C { unwind: false })?; let result = this.fcntl(args)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "read" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref buf, ref count] = check_arg_count(args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.check_init()?; @@ -70,6 +78,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "write" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref buf, ref n] = check_arg_count(args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.check_init()?; @@ -80,52 +89,62 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "unlink" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref path] = check_arg_count(args)?; let result = this.unlink(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "symlink" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref target, ref linkpath] = check_arg_count(args)?; let result = this.symlink(target, linkpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rename" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref oldpath, ref newpath] = check_arg_count(args)?; let result = this.rename(oldpath, newpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mkdir" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref path, ref mode] = check_arg_count(args)?; let result = this.mkdir(path, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rmdir" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref path] = check_arg_count(args)?; let result = this.rmdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "closedir" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref dirp] = check_arg_count(args)?; let result = this.closedir(dirp)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lseek" | "lseek64" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref offset, ref whence] = check_arg_count(args)?; let result = this.lseek64(fd, offset, whence)?; // "lseek" is only used on macOS which is 64bit-only, so `i64` always works. this.write_scalar(Scalar::from_i64(result), dest)?; } "fsync" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref fd] = check_arg_count(args)?; let result = this.fsync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fdatasync" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref fd] = check_arg_count(args)?; let result = this.fdatasync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "readlink" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref pathname, ref buf, ref bufsize] = check_arg_count(args)?; let result = this.readlink(pathname, buf, bufsize)?; this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; @@ -133,6 +152,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Allocation "posix_memalign" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref ret, ref align, ref size] = check_arg_count(args)?; let ret = this.deref_operand(ret)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -163,6 +183,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamic symbol loading "dlsym" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref handle, ref symbol] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_usize(this)?; let symbol = this.read_scalar(symbol)?.check_init()?; @@ -177,6 +198,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "sysconf" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let name = this.read_scalar(name)?.to_i32()?; @@ -202,6 +224,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "pthread_key_create" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref key, ref dtor] = check_arg_count(args)?; let key_place = this.deref_operand(key)?; let dtor = this.read_scalar(dtor)?.check_init()?; @@ -230,6 +253,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_key_delete" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref key] = check_arg_count(args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; this.machine.tls.delete_tls_key(key)?; @@ -237,6 +261,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_getspecific" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref key] = check_arg_count(args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); @@ -244,6 +269,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref key, ref new_ptr] = check_arg_count(args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); @@ -256,110 +282,132 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Synchronization primitives "pthread_mutexattr_init" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref attr] = check_arg_count(args)?; let result = this.pthread_mutexattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_settype" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref attr, ref kind] = check_arg_count(args)?; let result = this.pthread_mutexattr_settype(attr, kind)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_destroy" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref attr] = check_arg_count(args)?; let result = this.pthread_mutexattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_init" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref mutex, ref attr] = check_arg_count(args)?; let result = this.pthread_mutex_init(mutex, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_lock" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_lock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_trylock" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_trylock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_unlock" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_unlock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_destroy" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_destroy(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_rdlock" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_rdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_tryrdlock" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_tryrdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_wrlock" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_wrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_trywrlock" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_trywrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_unlock" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_unlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_destroy" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_destroy(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_init" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref attr] = check_arg_count(args)?; let result = this.pthread_condattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_destroy" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref attr] = check_arg_count(args)?; let result = this.pthread_condattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_init" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref cond, ref attr] = check_arg_count(args)?; let result = this.pthread_cond_init(cond, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_signal" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref cond] = check_arg_count(args)?; let result = this.pthread_cond_signal(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_broadcast" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref cond] = check_arg_count(args)?; let result = this.pthread_cond_broadcast(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_wait" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref cond, ref mutex] = check_arg_count(args)?; let result = this.pthread_cond_wait(cond, mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_timedwait" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref cond, ref mutex, ref abstime] = check_arg_count(args)?; this.pthread_cond_timedwait(cond, mutex, abstime, dest)?; } "pthread_cond_destroy" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref cond] = check_arg_count(args)?; let result = this.pthread_cond_destroy(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -367,30 +415,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_create" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref thread, ref attr, ref start, ref arg] = check_arg_count(args)?; let result = this.pthread_create(thread, attr, start, arg)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_join" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref thread, ref retval] = check_arg_count(args)?; let result = this.pthread_join(thread, retval)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_detach" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref thread] = check_arg_count(args)?; let result = this.pthread_detach(thread)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_self" => { + check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.pthread_self(dest)?; } "sched_yield" => { + check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; let result = this.sched_yield()?; this.write_scalar(Scalar::from_i32(result), dest)?; } "nanosleep" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref req, ref rem] = check_arg_count(args)?; let result = this.nanosleep(req, rem)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -398,6 +452,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscellaneous "isatty" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref fd] = check_arg_count(args)?; this.read_scalar(fd)?.to_i32()?; // "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error" @@ -407,6 +462,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_atfork" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref prepare, ref parent, ref child] = check_arg_count(args)?; this.force_bits(this.read_scalar(prepare)?.check_init()?, this.memory.pointer_size())?; this.force_bits(this.read_scalar(parent)?.check_init()?, this.memory.pointer_size())?; @@ -419,6 +475,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These shims are enabled only when the caller is in the standard library. "pthread_attr_getguardsize" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref _attr, ref guard_size] = check_arg_count(args)?; let guard_size = this.deref_operand(guard_size)?; let guard_size_layout = this.libc_ty_layout("size_t")?; @@ -431,11 +488,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "pthread_attr_init" | "pthread_attr_destroy" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + check_abi(abi, Abi::C { unwind: false })?; let &[_] = check_arg_count(args)?; this.write_null(dest)?; } | "pthread_attr_setstacksize" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + check_abi(abi, Abi::C { unwind: false })?; let &[_, _] = check_arg_count(args)?; this.write_null(dest)?; } @@ -443,12 +502,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "signal" | "sigaltstack" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + check_abi(abi, Abi::C { unwind: false })?; let &[_, _] = check_arg_count(args)?; this.write_null(dest)?; } | "sigaction" | "mprotect" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + check_abi(abi, Abi::C { unwind: false })?; let &[_, _, _] = check_arg_count(args)?; this.write_null(dest)?; } @@ -461,7 +522,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => unreachable!(), } } - }); + }; Ok(true) } diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index f61e37284e41..fe989b5924df 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -2,7 +2,7 @@ use rustc_middle::mir; use rustc_target::spec::abi::Abi; use crate::*; -use crate::helpers::check_arg_count; +use crate::helpers::{check_abi, check_arg_count}; use shims::posix::fs::EvalContextExt as _; use shims::posix::linux::sync::futex; use shims::posix::sync::EvalContextExt as _; @@ -20,9 +20,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - match_with_abi_check!(link_name, abi, Abi::C { unwind: false }, { + match link_name { // errno "__errno_location" => { + check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; @@ -32,27 +33,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These symbols have different names on Linux and macOS, which is the only reason they are not // in the `posix` module. "close" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref fd] = check_arg_count(args)?; let result = this.close(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir64_r" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref dirp, ref entry, ref result] = check_arg_count(args)?; let result = this.linux_readdir64_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate64" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref length] = check_arg_count(args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Linux-only "posix_fadvise" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref offset, ref len, ref advice] = check_arg_count(args)?; this.read_scalar(fd)?.to_i32()?; this.read_scalar(offset)?.to_machine_isize(this)?; @@ -62,6 +68,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "sync_file_range" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref offset, ref nbytes, ref flags] = check_arg_count(args)?; let result = this.sync_file_range(fd, offset, nbytes, flags)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -69,6 +76,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "clock_gettime" => { + check_abi(abi, Abi::C { unwind: false })?; // This is a POSIX function but it has only been tested on linux. let &[ref clk_id, ref tp] = check_arg_count(args)?; let result = this.clock_gettime(clk_id, tp)?; @@ -77,6 +85,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_attr_getstack" => { + check_abi(abi, Abi::C { unwind: false })?; // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. let &[ref attr_place, ref addr_place, ref size_place] = check_arg_count(args)?; this.deref_operand(attr_place)?; @@ -98,16 +107,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "prctl" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref option, ref arg2, ref arg3, ref arg4, ref arg5] = check_arg_count(args)?; let result = this.prctl(option, arg2, arg3, arg4, arg5)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_setclock" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref attr, ref clock_id] = check_arg_count(args)?; let result = this.pthread_condattr_setclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_getclock" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref attr, ref clock_id] = check_arg_count(args)?; let result = this.pthread_condattr_getclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -115,6 +127,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamically invoked syscalls "syscall" => { + check_abi(abi, Abi::C { unwind: false })?; // The syscall variadic function is legal to call with more arguments than needed, // extra arguments are simply ignored. However, all arguments need to be scalars; // other types might be treated differently by the calling convention. @@ -169,10 +182,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscelanneous "getrandom" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref ptr, ref len, ref flags] = check_arg_count(args)?; getrandom(this, ptr, len, flags, dest)?; } "sched_getaffinity" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref pid, ref cpusetsize, ref mask] = check_arg_count(args)?; this.read_scalar(pid)?.to_i32()?; this.read_scalar(cpusetsize)?.to_machine_usize(this)?; @@ -186,12 +201,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "pthread_getattr_np" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref _thread, ref _attr] = check_arg_count(args)?; this.write_null(dest)?; } _ => throw_unsup_format!("can't call foreign function: {}", link_name), - }); + }; Ok(true) } diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index cb57c4d2f6a1..dce9eea668e6 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -2,7 +2,7 @@ use rustc_middle::mir; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::check_arg_count; +use helpers::{check_abi, check_arg_count}; use shims::posix::fs::EvalContextExt as _; use shims::posix::thread::EvalContextExt as _; @@ -18,9 +18,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - match_with_abi_check!(link_name, abi, Abi::C { unwind: false }, { + match link_name { // errno "__error" => { + check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; @@ -28,36 +29,43 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "close" | "close$NOCANCEL" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref result] = check_arg_count(args)?; let result = this.close(result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "stat" | "stat$INODE64" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref path, ref buf] = check_arg_count(args)?; let result = this.macos_stat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lstat" | "lstat$INODE64" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref path, ref buf] = check_arg_count(args)?; let result = this.macos_lstat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fstat" | "fstat$INODE64" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref buf] = check_arg_count(args)?; let result = this.macos_fstat(fd, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" | "opendir$INODE64" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir_r" | "readdir_r$INODE64" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref dirp, ref entry, ref result] = check_arg_count(args)?; let result = this.macos_readdir_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref length] = check_arg_count(args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -65,40 +73,47 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Environment related shims "_NSGetEnviron" => { + check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.write_scalar(this.machine.env_vars.environ.unwrap().ptr, dest)?; } // Time related shims "gettimeofday" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref tv, ref tz] = check_arg_count(args)?; let result = this.gettimeofday(tv, tz)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mach_absolute_time" => { + check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; let result = this.mach_absolute_time()?; this.write_scalar(Scalar::from_u64(result), dest)?; } "mach_timebase_info" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref info] = check_arg_count(args)?; let result = this.mach_timebase_info(info)?; this.write_scalar(Scalar::from_i32(result), dest)?; - } + }, // Access to command-line arguments "_NSGetArgc" => { + check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?; } "_NSGetArgv" => { + check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; } // Thread-local storage "_tlv_atexit" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref dtor, ref data] = check_arg_count(args)?; let dtor = this.read_scalar(dtor)?.check_init()?; let dtor = this.memory.get_fn(dtor)?.as_instance()?; @@ -109,12 +124,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_get_stackaddr_np" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref thread] = check_arg_count(args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size()); this.write_scalar(stack_addr, dest)?; } "pthread_get_stacksize_np" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref thread] = check_arg_count(args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size()); @@ -123,6 +140,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_setname_np" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let name = this.read_scalar(name)?.check_init()?; this.pthread_setname_np(name)?; @@ -131,6 +149,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "mmap" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + check_abi(abi, Abi::C { unwind: false })?; // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. let &[ref addr, _, _, _, _, _] = check_arg_count(args)?; let addr = this.read_scalar(addr)?.check_init()?; @@ -138,7 +157,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } _ => throw_unsup_format!("can't call foreign function: {}", link_name), - }); + }; Ok(true) } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 9e8e6b58985e..72b776380b99 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -5,7 +5,7 @@ use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::check_arg_count; +use helpers::{check_abi, check_arg_count}; use shims::windows::sync::EvalContextExt as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -25,34 +25,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // DWORD = ULONG = u32 // BOOL = i32 // BOOLEAN = u8 - match_with_abi_check!(link_name, abi, Abi::System { unwind: false }, { + match link_name { // Environment related shims "GetEnvironmentVariableW" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref name, ref buf, ref size] = check_arg_count(args)?; let result = this.GetEnvironmentVariableW(name, buf, size)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetEnvironmentVariableW" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref name, ref value] = check_arg_count(args)?; let result = this.SetEnvironmentVariableW(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetEnvironmentStringsW" => { + check_abi(abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; let result = this.GetEnvironmentStringsW()?; this.write_scalar(result, dest)?; } "FreeEnvironmentStringsW" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref env_block] = check_arg_count(args)?; let result = this.FreeEnvironmentStringsW(env_block)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetCurrentDirectoryW" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref size, ref buf] = check_arg_count(args)?; let result = this.GetCurrentDirectoryW(size, buf)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetCurrentDirectoryW" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref path] = check_arg_count(args)?; let result = this.SetCurrentDirectoryW(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -60,6 +66,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "GetStdHandle" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref which] = check_arg_count(args)?; let which = this.read_scalar(which)?.to_i32()?; // We just make this the identity function, so we know later in `WriteFile` @@ -67,6 +74,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?; } "WriteFile" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref handle, ref buf, ref n, ref written_ptr, ref overlapped] = check_arg_count(args)?; this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore let handle = this.read_scalar(handle)?.to_machine_isize(this)?; @@ -102,6 +110,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Allocation "HeapAlloc" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref handle, ref flags, ref size] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; let flags = this.read_scalar(flags)?.to_u32()?; @@ -111,6 +120,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } "HeapFree" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref handle, ref flags, ref ptr] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; @@ -119,6 +129,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(1), dest)?; } "HeapReAlloc" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref handle, ref flags, ref ptr, ref size] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; @@ -130,11 +141,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // errno "SetLastError" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref error] = check_arg_count(args)?; let error = this.read_scalar(error)?.check_init()?; this.set_last_error(error)?; } "GetLastError" => { + check_abi(abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; let last_error = this.get_last_error()?; this.write_scalar(last_error, dest)?; @@ -142,6 +155,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "GetSystemInfo" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref system_info] = check_arg_count(args)?; let system_info = this.deref_operand(system_info)?; // Initialize with `0`. @@ -157,6 +171,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "TlsAlloc" => { + check_abi(abi, Abi::System { unwind: false })?; // This just creates a key; Windows does not natively support TLS destructors. // Create key and return it. @@ -165,6 +180,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref key] = check_arg_count(args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); @@ -172,6 +188,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "TlsSetValue" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref key, ref new_ptr] = check_arg_count(args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); @@ -184,6 +201,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Access to command-line arguments "GetCommandLineW" => { + check_abi(abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; this.write_scalar( this.machine.cmd_line.expect("machine must be initialized"), @@ -193,17 +211,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "GetSystemTimeAsFileTime" => { + check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref LPFILETIME] = check_arg_count(args)?; this.GetSystemTimeAsFileTime(LPFILETIME)?; } "QueryPerformanceCounter" => { + check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref lpPerformanceCount] = check_arg_count(args)?; let result = this.QueryPerformanceCounter(lpPerformanceCount)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "QueryPerformanceFrequency" => { + check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref lpFrequency] = check_arg_count(args)?; let result = this.QueryPerformanceFrequency(lpFrequency)?; @@ -212,27 +233,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Synchronization primitives "AcquireSRWLockExclusive" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; this.AcquireSRWLockExclusive(ptr)?; } "ReleaseSRWLockExclusive" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; this.ReleaseSRWLockExclusive(ptr)?; } "TryAcquireSRWLockExclusive" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; let ret = this.TryAcquireSRWLockExclusive(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; } "AcquireSRWLockShared" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; this.AcquireSRWLockShared(ptr)?; } "ReleaseSRWLockShared" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; this.ReleaseSRWLockShared(ptr)?; } "TryAcquireSRWLockShared" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; let ret = this.TryAcquireSRWLockShared(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; @@ -240,6 +267,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamic symbol loading "GetProcAddress" => { + check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref hModule, ref lpProcName] = check_arg_count(args)?; this.read_scalar(hModule)?.to_machine_isize(this)?; @@ -254,6 +282,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscellaneous "SystemFunction036" => { + check_abi(abi, Abi::System { unwind: false })?; // The actual name of 'RtlGenRandom' let &[ref ptr, ref len] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; @@ -262,6 +291,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_bool(true), dest)?; } "GetConsoleScreenBufferInfo" => { + check_abi(abi, Abi::System { unwind: false })?; // `term` needs this, so we fake it. let &[ref console, ref buffer_info] = check_arg_count(args)?; this.read_scalar(console)?.to_machine_isize(this)?; @@ -271,6 +301,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "GetConsoleMode" => { + check_abi(abi, Abi::System { unwind: false })?; // Windows "isatty" (in libtest) needs this, so we fake it. let &[ref console, ref mode] = check_arg_count(args)?; this.read_scalar(console)?.to_machine_isize(this)?; @@ -280,6 +311,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "SwitchToThread" => { + check_abi(abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; // Note that once Miri supports concurrency, this will need to return a nonzero // value if this call does result in switching to another thread. @@ -288,29 +320,34 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Better error for attempts to create a thread "CreateThread" => { + check_abi(abi, Abi::System { unwind: false })?; throw_unsup_format!("Miri does not support concurrency on Windows"); } // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "GetProcessHeap" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + check_abi(abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; // Just fake a HANDLE this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _hConsoleOutput, ref _wAttribute] = check_arg_count(args)?; // Pretend these does not exist / nothing happened, by returning zero. this.write_null(dest)?; } "AddVectoredExceptionHandler" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _First, ref _Handler] = check_arg_count(args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_machine_usize(1, this), dest)?; } "SetThreadStackGuarantee" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[_StackSizeInBytes] = check_arg_count(args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. @@ -321,6 +358,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "LeaveCriticalSection" | "DeleteCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _lpCriticalSection] = check_arg_count(args)?; assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); @@ -330,6 +368,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "TryEnterCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _lpCriticalSection] = check_arg_count(args)?; assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); @@ -338,7 +377,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } _ => throw_unsup_format!("can't call foreign function: {}", link_name), - }); + } Ok(true) } From 4f899ce9acb3827cc45fd4a8672372b1ff64b8b2 Mon Sep 17 00:00:00 2001 From: bstrie <865233+bstrie@users.noreply.github.com> Date: Wed, 17 Mar 2021 18:34:44 -0400 Subject: [PATCH 2588/5092] Replace deprecated `collections::Bound` --- src/shims/tls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index ef77949efada..3339e3bee199 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -174,7 +174,7 @@ impl<'tcx> TlsData<'tcx> { key: Option, thread_id: ThreadId, ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { - use std::collections::Bound::*; + use std::ops::Bound::*; let thread_local = &mut self.keys; let start = match key { From fc88c6ccca6849b1e7909f8d10a8968e12bcbb29 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Mar 2021 00:19:53 +0100 Subject: [PATCH 2589/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index f064064db14c..bd571f788acb 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -b3ac52646f7591a811fa9bf55995b24fd17ece08 +36f1f04f18b89ba4a999bcfd6584663fd6fc1c5d From 263be25484b6df50e71702e46798881f1ccae5f6 Mon Sep 17 00:00:00 2001 From: Johnathan Van Why Date: Fri, 19 Mar 2021 09:27:36 -0700 Subject: [PATCH 2590/5092] Improvements to the README item on `-Zmiri-track-raw-pointers`. 1. The double quotes around are changed to backspaces, so will render correctly in markdown. 2. Clarify that -Zmiri-track-raw-pointers will never accept code that Miri would not have accepted without -Zmiri-track-raw-pointers. --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ae70c80d5f0a..59f7b970546e 100644 --- a/README.md +++ b/README.md @@ -252,9 +252,10 @@ environment variable: * `-Zmiri-track-raw-pointers` makes Stacked Borrows track a pointer tag even for raw pointers. This can make valid code fail to pass the checks, but also can help identify latent aliasing issues in code that Miri accepts by default. You - can recognize false positives by "" occurring in the message -- this + can recognize false positives by `` occurring in the message -- this indicates a pointer that was cast from an integer, so Miri was unable to track - this pointer. + this pointer. It does not have false negatives; code that works with + `-Zmiri-track-raw-pointers` will work without `-Zmiri-track-raw-pointers`. Some native rustc `-Z` flags are also very relevant for Miri: From b4b048cc86efbb6c64b038fc8c943565aca76c4e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Mar 2021 12:35:30 +0100 Subject: [PATCH 2591/5092] rustup; better comment in storage_dead_dangling test --- rust-version | 2 +- tests/compile-fail/storage_dead_dangling.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index bd571f788acb..f2c3c6ff5462 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -36f1f04f18b89ba4a999bcfd6584663fd6fc1c5d +2b8fbe6b0b6db7960828bd2c9a50e52c9a5d0aef diff --git a/tests/compile-fail/storage_dead_dangling.rs b/tests/compile-fail/storage_dead_dangling.rs index ad8e05537e1a..4d91498eac16 100644 --- a/tests/compile-fail/storage_dead_dangling.rs +++ b/tests/compile-fail/storage_dead_dangling.rs @@ -18,5 +18,7 @@ fn main() { fill(&mut x); _y = x; } + // Now we use a pointer to `x` which is no longer in scope, and thus dead (even though the + // `main` stack frame still exists). evil(); } From 03be4138ed134370979aec04ff5fe23cab6bcf74 Mon Sep 17 00:00:00 2001 From: Johnathan Van Why Date: Mon, 22 Mar 2021 15:35:18 -0700 Subject: [PATCH 2592/5092] `-Zmiri-track-raw-pointers` doc correction: it is not strictly more restrictive than Stacked Borrows. This change is based on the following comment: https://github.com/rust-lang/miri/pull/1748#issuecomment-803279473 --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 59f7b970546e..5e5b82b36547 100644 --- a/README.md +++ b/README.md @@ -254,8 +254,9 @@ environment variable: help identify latent aliasing issues in code that Miri accepts by default. You can recognize false positives by `` occurring in the message -- this indicates a pointer that was cast from an integer, so Miri was unable to track - this pointer. It does not have false negatives; code that works with - `-Zmiri-track-raw-pointers` will work without `-Zmiri-track-raw-pointers`. + this pointer. Note that it is not currently guaranteed that code that works + with `-Zmiri-track-raw-pointers` also works without + `-Zmiri-track-raw-pointers`. Some native rustc `-Z` flags are also very relevant for Miri: From 4eed6107230fa14930bff8c8e091aa18bcc1e072 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Tue, 23 Mar 2021 16:41:53 +0800 Subject: [PATCH 2593/5092] Remove `#![feature(or_patterns)]` --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 7fc080a937f0..6a5e7af23726 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,6 @@ #![feature(map_first_last)] #![feature(map_try_insert)] #![feature(never_type)] -#![feature(or_patterns)] #![feature(try_blocks)] #![warn(rust_2018_idioms)] From 08aef5a8aa889a11e5ce36f795182082d9ba742e Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Tue, 23 Mar 2021 16:55:46 +0800 Subject: [PATCH 2594/5092] Update `rust-version` --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index f2c3c6ff5462..3b05153d81cb 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -2b8fbe6b0b6db7960828bd2c9a50e52c9a5d0aef +5d04957a4b4714f71d38326fc96a0b0ef6dc5800 From 12005612ab7f2c84d4ceca8132dd7483bd892061 Mon Sep 17 00:00:00 2001 From: Johnathan Van Why Date: Wed, 24 Mar 2021 16:20:54 -0700 Subject: [PATCH 2595/5092] README.md: Apply RalfJung's suggestion `-Zmiri-track-raw-pointers` isn't *much* more restrictive than normal Stacked Borrows. Co-authored-by: Ralf Jung --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5e5b82b36547..8a0c5180e002 100644 --- a/README.md +++ b/README.md @@ -256,7 +256,7 @@ environment variable: indicates a pointer that was cast from an integer, so Miri was unable to track this pointer. Note that it is not currently guaranteed that code that works with `-Zmiri-track-raw-pointers` also works without - `-Zmiri-track-raw-pointers`. + `-Zmiri-track-raw-pointers`, but for the vast majority of code, this will be the case. Some native rustc `-Z` flags are also very relevant for Miri: From 726495f48965b81ff5462e535bb1a5a4c2b0c0a5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 25 Mar 2021 12:17:02 +0100 Subject: [PATCH 2596/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 3b05153d81cb..fe5d17a963bf 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -5d04957a4b4714f71d38326fc96a0b0ef6dc5800 +372afcf93bf60e1a9334b107cc3d72f1b0a4b1f4 From 585e51aabdcab2ec0b43fabfdd169d4a81ff39fa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 25 Mar 2021 12:44:30 +0100 Subject: [PATCH 2597/5092] disable MIR opts for ZST-related tests --- tests/compile-fail/dangling_pointers/dangling_zst_deref.rs | 3 ++- .../dangling_pointers/maybe_null_pointer_deref_zst.rs | 3 +++ .../dangling_pointers/maybe_null_pointer_write_zst.rs | 3 +++ tests/compile-fail/null_pointer_deref_zst.rs | 3 +++ tests/compile-fail/null_pointer_write_zst.rs | 3 +++ tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs | 3 ++- tests/compile-fail/zst2.rs | 3 +++ tests/compile-fail/zst3.rs | 3 +++ 8 files changed, 22 insertions(+), 2 deletions(-) diff --git a/tests/compile-fail/dangling_pointers/dangling_zst_deref.rs b/tests/compile-fail/dangling_pointers/dangling_zst_deref.rs index f1b5149dabb4..01e864213df7 100644 --- a/tests/compile-fail/dangling_pointers/dangling_zst_deref.rs +++ b/tests/compile-fail/dangling_pointers/dangling_zst_deref.rs @@ -1,5 +1,6 @@ // Make sure we find these even with many checks disabled. -// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +// Some optimizations remove ZST accesses, thus masking this UB. +// compile-flags: -Zmir-opt-level=0 -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation fn main() { let p = { diff --git a/tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.rs b/tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.rs index d9f5ad4c696e..9db8a7dcba98 100644 --- a/tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.rs +++ b/tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.rs @@ -1,3 +1,6 @@ +// Some optimizations remove ZST accesses, thus masking this UB. +// compile-flags: -Zmir-opt-level=0 + fn main() { // This pointer *could* be NULL so we cannot load from it, not even at ZST let ptr = (&0u8 as *const u8).wrapping_sub(0x800) as *const (); diff --git a/tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.rs b/tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.rs index ef46a469c3ad..79eff2507ceb 100644 --- a/tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.rs +++ b/tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.rs @@ -1,3 +1,6 @@ +// Some optimizations remove ZST accesses, thus masking this UB. +// compile-flags: -Zmir-opt-level=0 + fn main() { // This pointer *could* be NULL so we cannot load from it, not even at ZST. // Not using the () type here, as writes of that type do not even have MIR generated. diff --git a/tests/compile-fail/null_pointer_deref_zst.rs b/tests/compile-fail/null_pointer_deref_zst.rs index cfd3a75e3b8c..d0f21a04d364 100644 --- a/tests/compile-fail/null_pointer_deref_zst.rs +++ b/tests/compile-fail/null_pointer_deref_zst.rs @@ -1,3 +1,6 @@ +// Some optimizations remove ZST accesses, thus masking this UB. +// compile-flags: -Zmir-opt-level=0 + fn main() { let x: () = unsafe { *std::ptr::null() }; //~ ERROR memory access failed: 0x0 is not a valid pointer panic!("this should never print: {:?}", x); diff --git a/tests/compile-fail/null_pointer_write_zst.rs b/tests/compile-fail/null_pointer_write_zst.rs index 0f7244ba25cc..1ee1a4b8a303 100644 --- a/tests/compile-fail/null_pointer_write_zst.rs +++ b/tests/compile-fail/null_pointer_write_zst.rs @@ -1,3 +1,6 @@ +// Some optimizations remove ZST accesses, thus masking this UB. +// compile-flags: -Zmir-opt-level=0 + fn main() { // Not using the () type here, as writes of that type do not even have MIR generated. // Also not assigning directly as that's array initialization, not assignment. diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs index a9db5ff7df39..27403c11abc7 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs @@ -1,5 +1,6 @@ // This should fail even without validation -// compile-flags: -Zmiri-disable-validation +// Some optimizations remove ZST accesses, thus masking this UB. +// compile-flags: -Zmir-opt-level=0 -Zmiri-disable-validation fn main() { for i in 0..10 { // Try many times as this might work by chance. diff --git a/tests/compile-fail/zst2.rs b/tests/compile-fail/zst2.rs index 907337dcdb2b..a602cb731e40 100644 --- a/tests/compile-fail/zst2.rs +++ b/tests/compile-fail/zst2.rs @@ -1,3 +1,6 @@ +// Some optimizations remove ZST accesses, thus masking this UB. +// compile-flags: -Zmir-opt-level=0 + fn main() { // Not using the () type here, as writes of that type do not even have MIR generated. // Also not assigning directly as that's array initialization, not assignment. diff --git a/tests/compile-fail/zst3.rs b/tests/compile-fail/zst3.rs index c94591174ec5..734c4b8ac4b8 100644 --- a/tests/compile-fail/zst3.rs +++ b/tests/compile-fail/zst3.rs @@ -1,3 +1,6 @@ +// Some optimizations remove ZST accesses, thus masking this UB. +// compile-flags: -Zmir-opt-level=0 + fn main() { // Not using the () type here, as writes of that type do not even have MIR generated. // Also not assigning directly as that's array initialization, not assignment. From de0f3f930b800ff672b373bd6ab0af9fba3b3a05 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 28 Mar 2021 01:36:41 +0100 Subject: [PATCH 2598/5092] rustup --- rust-version | 2 +- tests/compile-fail/unaligned_pointers/reference_to_packed.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index fe5d17a963bf..8fadf6f9a3b2 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -372afcf93bf60e1a9334b107cc3d72f1b0a4b1f4 +9b0edb7fddacd6a60a380c1ce59159de597ab270 diff --git a/tests/compile-fail/unaligned_pointers/reference_to_packed.rs b/tests/compile-fail/unaligned_pointers/reference_to_packed.rs index 6fa952118535..b376859d22c1 100644 --- a/tests/compile-fail/unaligned_pointers/reference_to_packed.rs +++ b/tests/compile-fail/unaligned_pointers/reference_to_packed.rs @@ -1,7 +1,7 @@ // This should fail even without validation/SB // compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -#![allow(dead_code, unused_variables)] +#![allow(dead_code, unused_variables, unaligned_references)] #[repr(packed)] struct Foo { @@ -15,7 +15,7 @@ fn main() { x: 42, y: 99, }; - let p = unsafe { &foo.x }; + let p = &foo.x; let i = *p; //~ERROR alignment 4 is required } } From 650411492c138912e5972cee8d953331540ac457 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Apr 2021 11:09:40 +0200 Subject: [PATCH 2599/5092] also test getrandom directly --- test-cargo-miri/Cargo.lock | 34 ++++++++++++++++++++++++++++++---- test-cargo-miri/Cargo.toml | 1 + test-cargo-miri/tests/test.rs | 4 ++++ 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 1f1541b92a56..3473d86c486b 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "byteorder" version = "1.3.4" @@ -12,6 +14,7 @@ version = "0.1.0" dependencies = [ "byteorder", "cdylib", + "getrandom 0.2.2", "issue_1567", "issue_1691", "issue_1705", @@ -32,15 +35,32 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "getrandom" version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", - "wasi", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.10.2+wasi-snapshot-preview1", ] [[package]] @@ -116,7 +136,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom", + "getrandom 0.1.15", "libc", "rand_chacha", "rand_core", @@ -140,7 +160,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom", + "getrandom 0.1.15", ] [[package]] @@ -201,3 +221,9 @@ name = "wasi" version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 7ffe7d04ea47..c9619b6b4baa 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -16,6 +16,7 @@ issue_1705 = { path = "issue-1705" } [dev-dependencies] rand = { version = "0.7", features = ["small_rng"] } +getrandom = { version = "0.2" } serde_derive = "1.0" # not actually used, but exercises some unique code path (`--extern` .so file) [lib] diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 436e919e050d..33b814eeeeeb 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -24,6 +24,10 @@ fn does_not_work_on_miri() { #[test] fn entropy_rng() { + // Test `getrandom` directly. + let mut data = vec![0; 16]; + getrandom::getrandom(&mut data).unwrap(); + // Try seeding with "real" entropy. let mut rng = SmallRng::from_entropy(); let _val = rng.gen::(); From 0f7c01527af7ee5b39c279c99cef437ab5715580 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Apr 2021 11:11:19 +0200 Subject: [PATCH 2600/5092] 'cargo update' all the things --- Cargo.lock | 209 ++++++++++++++++++++++--------------- cargo-miri/Cargo.lock | 109 ++++++++++++------- test-cargo-miri/Cargo.lock | 46 ++++---- 3 files changed, 219 insertions(+), 145 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 102d29a80435..fdac5d4542e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "aho-corasick" version = "0.7.15" @@ -11,9 +13,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.35" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c0df63cb2955042487fad3aefd2c6e3ae7389ac5dc1beb28921de0b69f779d4" +checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" [[package]] name = "arrayref" @@ -50,6 +52,12 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + [[package]] name = "blake2b_simd" version = "0.5.11" @@ -114,9 +122,9 @@ checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" [[package]] name = "crossbeam-utils" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d" +checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" dependencies = [ "autocfg", "cfg-if 1.0.0", @@ -165,13 +173,13 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c122a393ea57648015bf06fbd3d372378992e86b9ff5a7a497b076a28c79efe" +checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall", + "redox_syscall 0.2.5", "winapi", ] @@ -186,40 +194,40 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "libc", - "wasi", + "wasi 0.9.0+wasi-snapshot-preview1", ] [[package]] name = "getrandom" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4" +checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "libc", - "wasi", + "wasi 0.10.2+wasi-snapshot-preview1", ] [[package]] name = "hermit-abi" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" dependencies = [ "libc", ] [[package]] name = "hex" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "humantime" @@ -232,9 +240,9 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" [[package]] name = "lazy_static" @@ -244,17 +252,17 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.81" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" +checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714" [[package]] name = "log" -version = "0.4.11" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", ] [[package]] @@ -265,11 +273,10 @@ checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" [[package]] name = "miow" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" dependencies = [ - "socket2", "winapi", ] @@ -280,11 +287,11 @@ dependencies = [ "colored", "compiletest_rs", "env_logger", - "getrandom 0.2.0", + "getrandom 0.2.2", "hex", "libc", "log", - "rand", + "rand 0.7.3", "rustc-workspace-hack", "rustc_version", "shell-escape", @@ -299,9 +306,9 @@ checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "proc-macro2" -version = "1.0.24" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" dependencies = [ "unicode-xid", ] @@ -314,9 +321,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ "proc-macro2", ] @@ -327,11 +334,23 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom 0.1.15", + "getrandom 0.1.16", "libc", - "rand_chacha", - "rand_core", - "rand_hc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc 0.2.0", +] + +[[package]] +name = "rand" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +dependencies = [ + "libc", + "rand_chacha 0.3.0", + "rand_core 0.6.2", + "rand_hc 0.3.0", ] [[package]] @@ -341,7 +360,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.2", ] [[package]] @@ -350,7 +379,16 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom 0.1.15", + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" +dependencies = [ + "getrandom 0.2.2", ] [[package]] @@ -359,7 +397,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" dependencies = [ - "rand_core", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_hc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +dependencies = [ + "rand_core 0.6.2", ] [[package]] @@ -368,34 +415,42 @@ version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" +[[package]] +name = "redox_syscall" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" +dependencies = [ + "bitflags", +] + [[package]] name = "redox_users" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" dependencies = [ - "getrandom 0.1.15", - "redox_syscall", + "getrandom 0.1.16", + "redox_syscall 0.1.57", "rust-argon2", ] [[package]] name = "regex" -version = "1.4.2" +version = "1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c" +checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19" dependencies = [ "aho-corasick", "memchr", "regex-syntax", - "thread_local", ] [[package]] name = "regex-syntax" -version = "0.6.21" +version = "0.6.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189" +checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548" [[package]] name = "remove_dir_all" @@ -468,18 +523,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.118" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" +checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.118" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" +checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" dependencies = [ "proc-macro2", "quote", @@ -488,9 +543,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.60" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1500e84d27fe482ed1dc791a56eddc2f230046a040fa908c08bda1d9fb615779" +checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" dependencies = [ "itoa", "ryu", @@ -505,26 +560,15 @@ checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" [[package]] name = "smallvec" -version = "1.5.1" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae524f056d7d770e174287294f562e95044c68e88dec909a00d2094805db9d75" - -[[package]] -name = "socket2" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97e0e9fd577458a4f61fb91fcb559ea2afecc54c934119421f9f5d3d5b1a1057" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "winapi", -] +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "syn" -version = "1.0.54" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2af957a63d6bd42255c359c93d9bfdb97076bd3b820897ce55ffbfbf107f44" +checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87" dependencies = [ "proc-macro2", "quote", @@ -533,14 +577,14 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" +checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "libc", - "rand", - "redox_syscall", + "rand 0.8.3", + "redox_syscall 0.2.5", "remove_dir_all", "winapi", ] @@ -575,15 +619,6 @@ dependencies = [ "term", ] -[[package]] -name = "thread_local" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" -dependencies = [ - "lazy_static", -] - [[package]] name = "unicode-width" version = "0.1.8" @@ -602,6 +637,12 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + [[package]] name = "winapi" version = "0.3.9" diff --git a/cargo-miri/Cargo.lock b/cargo-miri/Cargo.lock index b6abfb1031e6..36daae33d35b 100644 --- a/cargo-miri/Cargo.lock +++ b/cargo-miri/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "arrayref" version = "0.3.6" @@ -47,18 +49,12 @@ version = "0.1.0" dependencies = [ "directories", "rustc-workspace-hack", - "rustc_version", + "rustc_version 0.2.3", "serde", "serde_json", "vergen", ] -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -86,12 +82,12 @@ checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" [[package]] name = "crossbeam-utils" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d" +checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" dependencies = [ "autocfg", - "cfg-if 1.0.0", + "cfg-if", "lazy_static", ] @@ -117,20 +113,20 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", "libc", "wasi 0.9.0+wasi-snapshot-preview1", ] [[package]] name = "itoa" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" [[package]] name = "lazy_static" @@ -140,9 +136,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.81" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" +checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714" [[package]] name = "num-integer" @@ -164,19 +160,28 @@ dependencies = [ ] [[package]] -name = "proc-macro2" -version = "1.0.24" +name = "pest" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +dependencies = [ + "ucd-trie", +] + +[[package]] +name = "proc-macro2" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" dependencies = [ "unicode-xid", ] [[package]] name = "quote" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ "proc-macro2", ] @@ -222,7 +227,16 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" dependencies = [ - "semver", + "semver 0.9.0", +] + +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", ] [[package]] @@ -237,7 +251,16 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" dependencies = [ - "semver-parser", + "semver-parser 0.7.0", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser 0.10.2", ] [[package]] @@ -247,19 +270,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] -name = "serde" -version = "1.0.118" +name = "semver-parser" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + +[[package]] +name = "serde" +version = "1.0.125" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.118" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" +checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" dependencies = [ "proc-macro2", "quote", @@ -268,9 +300,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.60" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1500e84d27fe482ed1dc791a56eddc2f230046a040fa908c08bda1d9fb615779" +checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" dependencies = [ "itoa", "ryu", @@ -279,9 +311,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.55" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a571a711dddd09019ccc628e1b17fe87c59b09d513c06c026877aa708334f37a" +checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87" dependencies = [ "proc-macro2", "quote", @@ -299,6 +331,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "ucd-trie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" + [[package]] name = "unicode-xid" version = "0.2.1" @@ -307,12 +345,13 @@ checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" [[package]] name = "vergen" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ce50d8996df1f85af15f2cd8d33daae6e479575123ef4314a51a70a230739cb" +checksum = "e7141e445af09c8919f1d5f8a20dae0b20c3b57a45dee0d5823c6ed5d237f15a" dependencies = [ "bitflags", "chrono", + "rustc_version 0.3.3", ] [[package]] diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 3473d86c486b..e7d594964498 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "byteorder" -version = "1.3.4" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cargo-miri-test" @@ -29,12 +29,6 @@ dependencies = [ "byteorder", ] -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -43,11 +37,11 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "getrandom" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", "libc", "wasi 0.9.0+wasi-snapshot-preview1", ] @@ -58,16 +52,16 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "wasi 0.10.2+wasi-snapshot-preview1", ] [[package]] name = "hermit-abi" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" dependencies = [ "libc", ] @@ -92,9 +86,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.81" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" +checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714" [[package]] name = "num_cpus" @@ -114,18 +108,18 @@ checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "proc-macro2" -version = "1.0.24" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" dependencies = [ "unicode-xid", ] [[package]] name = "quote" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ "proc-macro2", ] @@ -136,7 +130,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom 0.1.15", + "getrandom 0.1.16", "libc", "rand_chacha", "rand_core", @@ -160,7 +154,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom 0.1.15", + "getrandom 0.1.16", ] [[package]] @@ -183,9 +177,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.118" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" +checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" dependencies = [ "proc-macro2", "quote", @@ -201,9 +195,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.55" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a571a711dddd09019ccc628e1b17fe87c59b09d513c06c026877aa708334f37a" +checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87" dependencies = [ "proc-macro2", "quote", From 20e31dbdad67080eb83aa3b5330dfe2f116f9900 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Apr 2021 11:41:04 +0200 Subject: [PATCH 2601/5092] fix newer getrandom on Windows --- src/shims/windows/foreign_items.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 72b776380b99..47f9544066bc 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -282,14 +282,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscellaneous "SystemFunction036" => { + // This is really 'RtlGenRandom'. check_abi(abi, Abi::System { unwind: false })?; - // The actual name of 'RtlGenRandom' let &[ref ptr, ref len] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_u32()?; this.gen_random(ptr, len.into())?; this.write_scalar(Scalar::from_bool(true), dest)?; } + "BCryptGenRandom" => { + check_abi(abi, Abi::System { unwind: false })?; + let &[ref algorithm, ref ptr, ref len, ref flags] = check_arg_count(args)?; + let algorithm = this.read_scalar(algorithm)?; + let ptr = this.read_scalar(ptr)?.check_init()?; + let len = this.read_scalar(len)?.to_u32()?; + let flags = this.read_scalar(flags)?.to_u32()?; + if flags != 2 { // BCRYPT_USE_SYSTEM_PREFERRED_RNG + throw_unsup_format!("BCryptGenRandom is supported only with the BCRYPT_USE_SYSTEM_PREFERRED_RNG flag"); + } + if algorithm.to_machine_usize(this)? != 0 { + throw_unsup_format!("BCryptGenRandom algorithm must be NULL when the flag is BCRYPT_USE_SYSTEM_PREFERRED_RNG"); + } + this.gen_random(ptr, len.into())?; + this.write_null(dest)?; // STATUS_SUCCESS + } "GetConsoleScreenBufferInfo" => { check_abi(abi, Abi::System { unwind: false })?; // `term` needs this, so we fake it. From 31bd77c7d82dda48f7c77ecc2314bc15219969c9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Apr 2021 11:45:09 +0200 Subject: [PATCH 2602/5092] bump miri dependencies --- Cargo.lock | 272 +++++++++++++------------------------------ Cargo.toml | 8 +- src/intptrcast.rs | 2 +- tests/compiletest.rs | 2 +- 4 files changed, 89 insertions(+), 195 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fdac5d4542e7..69cc1966a6f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,18 +17,6 @@ version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" -[[package]] -name = "arrayref" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" - -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - [[package]] name = "atty" version = "0.2.14" @@ -40,41 +28,12 @@ dependencies = [ "winapi", ] -[[package]] -name = "autocfg" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" - -[[package]] -name = "base64" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" - [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -[[package]] -name = "blake2b_simd" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" -dependencies = [ - "arrayref", - "arrayvec", - "constant_time_eq", -] - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -94,13 +53,14 @@ dependencies = [ [[package]] name = "compiletest_rs" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f737835bfbbe29ed1ff82d5137520338d7ed5bf1a1d4b9c1c7c58bb45b8fa29" +checksum = "0086d6ad78cf409c3061618cd98e2789d5c9ce598fc9651611cf62eae0a599cb" dependencies = [ "diff", "filetime", "getopts", + "lazy_static", "libc", "log", "miow", @@ -114,23 +74,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "crossbeam-utils" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" -dependencies = [ - "autocfg", - "cfg-if 1.0.0", - "lazy_static", -] - [[package]] name = "diff" version = "0.1.12" @@ -138,20 +81,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" [[package]] -name = "dirs" -version = "2.0.2" +name = "dirs-next" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" dependencies = [ - "cfg-if 0.1.10", - "dirs-sys", + "cfg-if", + "dirs-sys-next", ] [[package]] -name = "dirs-sys" -version = "0.3.5" +name = "dirs-sys-next" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", "redox_users", @@ -160,9 +103,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.7.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +checksum = "17392a012ea30ef05a610aa97dfb49496e71c9f676b27879922ea5bdf60d9d3f" dependencies = [ "atty", "humantime", @@ -177,9 +120,9 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", - "redox_syscall 0.2.5", + "redox_syscall", "winapi", ] @@ -192,26 +135,15 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", - "wasi 0.10.2+wasi-snapshot-preview1", + "wasi", ] [[package]] @@ -231,12 +163,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "humantime" -version = "1.3.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -dependencies = [ - "quick-error", -] +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "itoa" @@ -262,7 +191,7 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -287,17 +216,36 @@ dependencies = [ "colored", "compiletest_rs", "env_logger", - "getrandom 0.2.2", + "getrandom", "hex", "libc", "log", - "rand 0.7.3", + "rand", "rustc-workspace-hack", "rustc_version", "shell-escape", "smallvec", ] +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "pest" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +dependencies = [ + "ucd-trie", +] + [[package]] name = "ppv-lite86" version = "0.2.10" @@ -313,12 +261,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - [[package]] name = "quote" version = "1.0.9" @@ -328,19 +270,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc 0.2.0", -] - [[package]] name = "rand" version = "0.8.3" @@ -348,19 +277,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" dependencies = [ "libc", - "rand_chacha 0.3.0", - "rand_core 0.6.2", - "rand_hc 0.3.0", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", + "rand_chacha", + "rand_core", + "rand_hc", ] [[package]] @@ -370,16 +289,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" dependencies = [ "ppv-lite86", - "rand_core 0.6.2", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", + "rand_core", ] [[package]] @@ -388,16 +298,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" dependencies = [ - "getrandom 0.2.2", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", + "getrandom", ] [[package]] @@ -406,15 +307,9 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" dependencies = [ - "rand_core 0.6.2", + "rand_core", ] -[[package]] -name = "redox_syscall" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" - [[package]] name = "redox_syscall" version = "0.2.5" @@ -426,13 +321,12 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.3.5" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ - "getrandom 0.1.16", - "redox_syscall 0.1.57", - "rust-argon2", + "getrandom", + "redox_syscall", ] [[package]] @@ -461,18 +355,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "rust-argon2" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" -dependencies = [ - "base64", - "blake2b_simd", - "constant_time_eq", - "crossbeam-utils", -] - [[package]] name = "rustc-workspace-hack" version = "1.0.0" @@ -481,9 +363,9 @@ checksum = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" [[package]] name = "rustc_version" -version = "0.2.3" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" dependencies = [ "semver", ] @@ -500,6 +382,12 @@ dependencies = [ "serde_json", ] +[[package]] +name = "rustversion" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb5d2a036dc6d2d8fd16fde3498b04306e29bd193bf306a57427019b823d5acd" + [[package]] name = "ryu" version = "1.0.5" @@ -508,18 +396,21 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "semver" -version = "0.9.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" dependencies = [ "semver-parser", ] [[package]] name = "semver-parser" -version = "0.7.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] [[package]] name = "serde" @@ -581,21 +472,22 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", - "rand 0.8.3", - "redox_syscall 0.2.5", + "rand", + "redox_syscall", "remove_dir_all", "winapi", ] [[package]] name = "term" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" dependencies = [ - "dirs", + "dirs-next", + "rustversion", "winapi", ] @@ -610,15 +502,23 @@ dependencies = [ [[package]] name = "tester" -version = "0.7.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee72ec31009a42b53de9a6b7d8f462b493ab3b1e4767bda1fcdbb52127f13b6c" +checksum = "0639d10d8f4615f223a57275cf40f9bdb7cfbb806bcb7f7cc56e3beb55a576eb" dependencies = [ + "cfg-if", "getopts", "libc", + "num_cpus", "term", ] +[[package]] +name = "ucd-trie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" + [[package]] name = "unicode-width" version = "0.1.8" @@ -631,12 +531,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index 5f9e93f2347b..2483cb2c8129 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,11 +19,11 @@ doctest = false # and no doc tests [dependencies] getrandom = { version = "0.2", features = ["std"] } -env_logger = "0.7.1" +env_logger = "0.8" log = "0.4" shell-escape = "0.1.4" hex = "0.4.0" -rand = "0.7" +rand = "0.8" smallvec = "1.4.2" # A noop dependency that changes in the Rust repository, it's a bit of a hack. @@ -37,8 +37,8 @@ rustc-workspace-hack = "1.0.0" libc = "0.2" [dev-dependencies] -compiletest_rs = { version = "0.5", features = ["tmp"] } -rustc_version = "0.2.3" +compiletest_rs = { version = "0.6", features = ["tmp"] } +rustc_version = "0.3" colored = "2" [package.metadata.rust-analyzer] diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 188ff94861bd..0e6a9f69aeba 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -92,7 +92,7 @@ impl<'mir, 'tcx> GlobalState { let slack = { let mut rng = memory.extra.rng.borrow_mut(); // This means that `(global_state.next_base_addr + slack) % 16` is uniformly distributed. - rng.gen_range(0, 16) + rng.gen_range(0..16) }; // From next_base_addr + slack, round up to adjust for alignment. let base_addr = global_state.next_base_addr.checked_add(slack).unwrap(); diff --git a/tests/compiletest.rs b/tests/compiletest.rs index ac44c48d6214..5de5dfb4c675 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -42,7 +42,7 @@ fn run_tests(mode: &str, path: &str, target: &str) { config.run_lib_path = PathBuf::from(lib_path); config.compile_lib_path = PathBuf::from(lib_path); } - config.filter = env::args().nth(1); + config.filters = env::args().nth(1).into_iter().collect(); config.host = get_host(); config.src_base = PathBuf::from(path); config.target = target.to_owned(); From 8e661cc47e8ee50fdd60060f693ec9498fbc2a75 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Apr 2021 12:01:32 +0200 Subject: [PATCH 2603/5092] bump cargo-miri dependencies --- cargo-miri/Cargo.lock | 294 +++++++++++++++++++++++++++++++++++++----- cargo-miri/Cargo.toml | 4 +- cargo-miri/bin.rs | 4 +- cargo-miri/build.rs | 8 +- 4 files changed, 271 insertions(+), 39 deletions(-) diff --git a/cargo-miri/Cargo.lock b/cargo-miri/Cargo.lock index 36daae33d35b..cf536ecbb20f 100644 --- a/cargo-miri/Cargo.lock +++ b/cargo-miri/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "anyhow" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" + [[package]] name = "arrayref" version = "0.3.6" @@ -49,12 +55,21 @@ version = "0.1.0" dependencies = [ "directories", "rustc-workspace-hack", - "rustc_version 0.2.3", + "rustc_version", "serde", "serde_json", "vergen", ] +[[package]] +name = "cc" +version = "1.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" +dependencies = [ + "jobserver", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -111,6 +126,36 @@ dependencies = [ "winapi", ] +[[package]] +name = "enum-iterator" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c79a6321a1197d7730510c7e3f6cb80432dfefecb32426de8cea0aa19b4bb8d7" +dependencies = [ + "enum-iterator-derive", +] + +[[package]] +name = "enum-iterator-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e94aa31f7c0dc764f57896dc615ddd76fc13b0d5dca7eb6cc5e018a5a09ec06" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + [[package]] name = "getrandom" version = "0.1.16" @@ -122,12 +167,57 @@ dependencies = [ "wasi 0.9.0+wasi-snapshot-preview1", ] +[[package]] +name = "getset" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24b328c01a4d71d2d8173daa93562a73ab0fe85616876f02500f53d82948c504" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "git2" +version = "0.13.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d250f5f82326884bd39c2853577e70a121775db76818ffa452ed1e80de12986" +dependencies = [ + "bitflags", + "libc", + "libgit2-sys", + "log", + "url", +] + +[[package]] +name = "idna" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89829a5d69c23d348314a7ac337fe39173b61149a9864deabd260983aed48c21" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "itoa" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +[[package]] +name = "jobserver" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c71313ebb9439f74b00d9d2dcec36440beaf57a6aa0623068441dd7cd81a7f2" +dependencies = [ + "libc", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -140,6 +230,45 @@ version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714" +[[package]] +name = "libgit2-sys" +version = "0.12.18+1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3da6a42da88fc37ee1ecda212ffa254c25713532980005d5f7c0b0fbe7e6e885" +dependencies = [ + "cc", + "libc", + "libz-sys", + "pkg-config", +] + +[[package]] +name = "libz-sys" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "602113192b08db8f38796c4e85c39e960c145965140e918018bcde1952429655" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "matches" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" + [[package]] name = "num-integer" version = "0.1.44" @@ -159,6 +288,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + [[package]] name = "pest" version = "2.1.3" @@ -168,6 +303,36 @@ dependencies = [ "ucd-trie", ] +[[package]] +name = "pkg-config" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.26" @@ -221,54 +386,36 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver 0.9.0", -] - [[package]] name = "rustc_version" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" dependencies = [ - "semver 0.11.0", + "semver", ] +[[package]] +name = "rustversion" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb5d2a036dc6d2d8fd16fde3498b04306e29bd193bf306a57427019b823d5acd" + [[package]] name = "ryu" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser 0.7.0", -] - [[package]] name = "semver" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" dependencies = [ - "semver-parser 0.10.2", + "semver-parser", ] -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - [[package]] name = "semver-parser" version = "0.10.2" @@ -320,6 +467,26 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "thiserror" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "time" version = "0.1.44" @@ -331,12 +498,45 @@ dependencies = [ "winapi", ] +[[package]] +name = "tinyvec" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317cca572a0e89c3ce0ca1f1bdc9369547fe318a683418e42ac8f59d14701023" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + [[package]] name = "ucd-trie" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" +[[package]] +name = "unicode-bidi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" +dependencies = [ + "matches", +] + +[[package]] +name = "unicode-normalization" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef" +dependencies = [ + "tinyvec", +] + [[package]] name = "unicode-xid" version = "0.2.1" @@ -344,16 +544,44 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" [[package]] -name = "vergen" -version = "3.2.0" +name = "url" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7141e445af09c8919f1d5f8a20dae0b20c3b57a45dee0d5823c6ed5d237f15a" +checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b" dependencies = [ - "bitflags", - "chrono", - "rustc_version 0.3.3", + "form_urlencoded", + "idna", + "matches", + "percent-encoding", ] +[[package]] +name = "vcpkg" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" + +[[package]] +name = "vergen" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbc87f9a7a9d61b15d51d1d3547284f67b6b4f1494ce3fc5814c101f35a5183" +dependencies = [ + "anyhow", + "chrono", + "enum-iterator", + "getset", + "git2", + "rustversion", + "thiserror", +] + +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" diff --git a/cargo-miri/Cargo.toml b/cargo-miri/Cargo.toml index 8233c5c24f83..f0ef30eabcf7 100644 --- a/cargo-miri/Cargo.toml +++ b/cargo-miri/Cargo.toml @@ -15,7 +15,7 @@ doctest = false # and no doc tests [dependencies] directories = "3" -rustc_version = "0.2.3" +rustc_version = "0.3" serde_json = "1.0.40" # A noop dependency that changes in the Rust repository, it's a bit of a hack. @@ -28,4 +28,4 @@ rustc-workspace-hack = "1.0.0" serde = { version = "*", features = ["derive"] } [build-dependencies] -vergen = "3" +vergen = { version = "5", default_features = false, features = ["git"] } diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 2cd0c0c972f5..af1dbad32a9a 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -83,8 +83,8 @@ fn show_version() { println!( "miri {} ({} {})", env!("CARGO_PKG_VERSION"), - env!("VERGEN_SHA_SHORT"), - env!("VERGEN_COMMIT_DATE") + env!("VERGEN_GIT_SHA_SHORT"), + env!("VERGEN_GIT_COMMIT_DATE") ); } diff --git a/cargo-miri/build.rs b/cargo-miri/build.rs index 56956920e2e2..cff135fe49c0 100644 --- a/cargo-miri/build.rs +++ b/cargo-miri/build.rs @@ -1,7 +1,11 @@ +use vergen::vergen; + fn main() { // Don't rebuild miri when nothing changed. println!("cargo:rerun-if-changed=build.rs"); // vergen - vergen::generate_cargo_keys(vergen::ConstantsFlags::all()) - .expect("Unable to generate vergen keys!"); + let mut gen_config = vergen::Config::default(); + *gen_config.git_mut().sha_kind_mut() = vergen::ShaKind::Short; + *gen_config.git_mut().commit_timestamp_kind_mut() = vergen::TimestampKind::DateOnly; + vergen(gen_config).expect("Unable to generate vergen keys!"); } From 3d15e4744151b339afc38b1bc5c01caf8da2b943 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Apr 2021 12:03:52 +0200 Subject: [PATCH 2604/5092] bump test-cargo-miri dependencies --- test-cargo-miri/Cargo.lock | 50 +++++++++----------------------------- test-cargo-miri/Cargo.toml | 2 +- 2 files changed, 12 insertions(+), 40 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index e7d594964498..c9e3126c4292 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -14,7 +14,7 @@ version = "0.1.0" dependencies = [ "byteorder", "cdylib", - "getrandom 0.2.2", + "getrandom", "issue_1567", "issue_1691", "issue_1705", @@ -35,17 +35,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.2" @@ -54,7 +43,7 @@ checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" dependencies = [ "cfg-if", "libc", - "wasi 0.10.2+wasi-snapshot-preview1", + "wasi", ] [[package]] @@ -126,23 +115,21 @@ dependencies = [ [[package]] name = "rand" -version = "0.7.3" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" dependencies = [ - "getrandom 0.1.16", "libc", "rand_chacha", "rand_core", "rand_hc", - "rand_pcg", ] [[package]] name = "rand_chacha" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" dependencies = [ "ppv-lite86", "rand_core", @@ -150,27 +137,18 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.5.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" dependencies = [ - "getrandom 0.1.16", + "getrandom", ] [[package]] name = "rand_hc" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core", -] - -[[package]] -name = "rand_pcg" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" +checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" dependencies = [ "rand_core", ] @@ -210,12 +188,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index c9619b6b4baa..76d88bc0c750 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -15,7 +15,7 @@ issue_1691 = { path = "issue-1691" } issue_1705 = { path = "issue-1705" } [dev-dependencies] -rand = { version = "0.7", features = ["small_rng"] } +rand = { version = "0.8", features = ["small_rng"] } getrandom = { version = "0.2" } serde_derive = "1.0" # not actually used, but exercises some unique code path (`--extern` .so file) From 84f44900f45e5572e1d3209f204a3a856f48b07c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Apr 2021 15:35:19 +0200 Subject: [PATCH 2605/5092] also test old getrandom --- test-cargo-miri/Cargo.lock | 24 +++++++++++++++++++++--- test-cargo-miri/Cargo.toml | 3 ++- test-cargo-miri/tests/test.rs | 5 +++-- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index c9e3126c4292..45ec195843dc 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -14,7 +14,8 @@ version = "0.1.0" dependencies = [ "byteorder", "cdylib", - "getrandom", + "getrandom 0.1.16", + "getrandom 0.2.2", "issue_1567", "issue_1691", "issue_1705", @@ -35,6 +36,17 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + [[package]] name = "getrandom" version = "0.2.2" @@ -43,7 +55,7 @@ checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.10.2+wasi-snapshot-preview1", ] [[package]] @@ -141,7 +153,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" dependencies = [ - "getrandom", + "getrandom 0.2.2", ] [[package]] @@ -188,6 +200,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 76d88bc0c750..08470539727a 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -16,7 +16,8 @@ issue_1705 = { path = "issue-1705" } [dev-dependencies] rand = { version = "0.8", features = ["small_rng"] } -getrandom = { version = "0.2" } +getrandom_1 = { package = "getrandom", version = "0.1" } +getrandom_2 = { package = "getrandom", version = "0.2" } serde_derive = "1.0" # not actually used, but exercises some unique code path (`--extern` .so file) [lib] diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 33b814eeeeeb..f0ff10ff6c0d 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -24,9 +24,10 @@ fn does_not_work_on_miri() { #[test] fn entropy_rng() { - // Test `getrandom` directly. + // Test `getrandom` directly (in multiple different versions). let mut data = vec![0; 16]; - getrandom::getrandom(&mut data).unwrap(); + getrandom_1::getrandom(&mut data).unwrap(); + getrandom_2::getrandom(&mut data).unwrap(); // Try seeding with "real" entropy. let mut rng = SmallRng::from_entropy(); From 4fccde54acc986a7446ae487cb028fec59fadcb4 Mon Sep 17 00:00:00 2001 From: Tristan Dannenberg Date: Tue, 12 Jan 2021 22:16:48 +0100 Subject: [PATCH 2606/5092] make cargo-miri run doc-tests --- README.md | 4 + cargo-miri/bin.rs | 211 ++++++++++++++++-- test-cargo-miri/run-test.py | 19 +- test-cargo-miri/test.cross-target.stdout.ref | 10 + test-cargo-miri/test.default.stdout.ref | 6 + .../test.filter.cross-target.stdout.ref | 11 + test-cargo-miri/test.filter.stdout.ref | 5 + test-cargo-miri/test.stderr-rustdoc.ref | 1 - 8 files changed, 239 insertions(+), 28 deletions(-) create mode 100644 test-cargo-miri/test.cross-target.stdout.ref create mode 100644 test-cargo-miri/test.filter.cross-target.stdout.ref delete mode 100644 test-cargo-miri/test.stderr-rustdoc.ref diff --git a/README.md b/README.md index 8a0c5180e002..8a80a57e2d9f 100644 --- a/README.md +++ b/README.md @@ -290,6 +290,10 @@ different Miri binaries, and as such worth documenting: that the compiled `rlib`s are compatible with Miri. When set while running `cargo-miri`, it indicates that we are part of a sysroot build (for which some crates need special treatment). +* `MIRI_CALLED_FROM_RUSTDOC` when set to any value tells `cargo-miri` that it is + running as a child process of `rustdoc`, which invokes it twice for each doc-test + and requires special treatment, most notably a check-only build before interpretation. + This is set by `cargo-miri` itself when running as a `rustdoc`-wrapper. * `MIRI_CWD` when set to any value tells the Miri driver to change to the given directory after loading all the source files, but before commencing interpretation. This is useful if the interpreted program wants a different diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index af1dbad32a9a..1f749b077ab9 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -1,8 +1,8 @@ use std::env; use std::ffi::OsString; use std::fs::{self, File}; -use std::io::{self, BufRead, BufReader, BufWriter, Write}; use std::iter::TakeWhile; +use std::io::{self, BufRead, BufReader, BufWriter, Read, Write}; use std::ops::Not; use std::path::{Path, PathBuf}; use std::process::Command; @@ -46,6 +46,8 @@ struct CrateRunEnv { env: Vec<(OsString, OsString)>, /// The current working directory. current_dir: OsString, + /// The contents passed via standard input. + stdin: Vec, } /// The information Miri needs to run a crate. Stored as JSON when the crate is "compiled". @@ -63,7 +65,13 @@ impl CrateRunInfo { let args = args.collect(); let env = env::vars_os().collect(); let current_dir = env::current_dir().unwrap().into_os_string(); - Self::RunWith(CrateRunEnv { args, env, current_dir }) + + let mut stdin = Vec::new(); + if env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some() { + std::io::stdin().lock().read_to_end(&mut stdin).expect("cannot read stdin"); + } + + Self::RunWith(CrateRunEnv { args, env, current_dir, stdin }) } fn store(&self, filename: &Path) { @@ -190,6 +198,22 @@ fn exec(mut cmd: Command) { } } +/// Execute the command and pipe `input` into its stdin. +/// If it fails, fail this process with the same exit code. +/// Otherwise, continue. +fn exec_with_pipe(mut cmd: Command, input: &[u8]) { + cmd.stdin(std::process::Stdio::piped()); + let mut child = cmd.spawn().expect("failed to spawn process"); + { + let stdin = child.stdin.as_mut().expect("failed to open stdin"); + stdin.write_all(input).expect("failed to write out test source"); + } + let exit_status = child.wait().expect("failed to run command"); + if exit_status.success().not() { + std::process::exit(exit_status.code().unwrap_or(-1)) + } +} + fn xargo_version() -> Option<(u32, u32, u32)> { let out = xargo_check().arg("--version").output().ok()?; if !out.status.success() { @@ -591,24 +615,29 @@ fn phase_cargo_rustc(mut args: env::Args) { } fn out_filename(prefix: &str, suffix: &str) -> PathBuf { - let mut path = PathBuf::from(get_arg_flag_value("--out-dir").unwrap()); - path.push(format!( - "{}{}{}{}", - prefix, - get_arg_flag_value("--crate-name").unwrap(), - // This is technically a `-C` flag but the prefix seems unique enough... - // (and cargo passes this before the filename so it should be unique) - get_arg_flag_value("extra-filename").unwrap_or(String::new()), - suffix, - )); - path + if let Some(out_dir) = get_arg_flag_value("--out-dir") { + let mut path = PathBuf::from(out_dir); + path.push(format!( + "{}{}{}{}", + prefix, + get_arg_flag_value("--crate-name").unwrap(), + // This is technically a `-C` flag but the prefix seems unique enough... + // (and cargo passes this before the filename so it should be unique) + get_arg_flag_value("extra-filename").unwrap_or(String::new()), + suffix, + )); + path + } else { + let out_file = get_arg_flag_value("-o").unwrap(); + PathBuf::from(out_file) + } } let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); let target_crate = is_target_crate(); let print = get_arg_flag_value("--print").is_some(); // whether this is cargo passing `--print` to get some infos - let store_json = |info: CrateRunInfo| { + let store_json = |info: &CrateRunInfo| { // Create a stub .d file to stop Cargo from "rebuilding" the crate: // https://github.com/rust-lang/miri/issues/1724#issuecomment-787115693 // As we store a JSON file instead of building the crate here, an empty file is fine. @@ -636,7 +665,47 @@ fn phase_cargo_rustc(mut args: env::Args) { // like we want them. // Instead of compiling, we write JSON into the output file with all the relevant command-line flags // and environment variables; this is used when cargo calls us again in the CARGO_TARGET_RUNNER phase. - store_json(CrateRunInfo::collect(args)); + let info = CrateRunInfo::collect(args); + store_json(&info); + + // Rustdoc expects us to exit with an error code if the test is marked as `compile_fail`, + // just creating the JSON file is not enough: we need to detect syntax errors, + // so we need to run Miri with `MIRI_BE_RUSTC` for a check-only build. + if std::env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some() { + let mut cmd = miri(); + let env = if let CrateRunInfo::RunWith(env) = info { + env + } else { + return; + }; + + // use our own sysroot + if !has_arg_flag("--sysroot") { + let sysroot = env::var_os("MIRI_SYSROOT") + .expect("the wrapper should have set MIRI_SYSROOT"); + cmd.arg("--sysroot").arg(sysroot); + } + + // ensure --emit argument for a check-only build is present + if let Some(i) = env.args.iter().position(|arg| arg.starts_with("--emit=")) { + // We need to make sure we're not producing a binary that overwrites the JSON file. + // rustdoc should only ever pass an --emit=metadata argument for tests marked as `no_run`: + assert_eq!(env.args[i], "--emit=metadata"); + } else { + cmd.arg("--emit=dep-info,metadata"); + } + + cmd.args(env.args); + cmd.env("MIRI_BE_RUSTC", "1"); + + if verbose { + eprintln!("[cargo-miri rustc] captured input:\n{}", std::str::from_utf8(&env.stdin).unwrap()); + eprintln!("[cargo-miri rustc] {:?}", cmd); + } + + exec_with_pipe(cmd, &env.stdin); + } + return; } @@ -644,7 +713,7 @@ fn phase_cargo_rustc(mut args: env::Args) { // This is a "runnable" `proc-macro` crate (unit tests). We do not support // interpreting that under Miri now, so we write a JSON file to (display a // helpful message and) skip it in the runner phase. - store_json(CrateRunInfo::SkipProcMacroTest); + store_json(&CrateRunInfo::SkipProcMacroTest); return; } @@ -715,6 +784,18 @@ fn phase_cargo_rustc(mut args: env::Args) { } } +fn forward_patched_extern_arg(args: &mut impl Iterator, cmd: &mut Command) { + cmd.arg("--extern"); // always forward flag, but adjust filename: + let path = args.next().expect("`--extern` should be followed by a filename"); + if let Some(lib) = path.strip_suffix(".rlib") { + // If this is an rlib, make it an rmeta. + cmd.arg(format!("{}.rmeta", lib)); + } else { + // Some other extern file (e.g. a `.so`). Forward unchanged. + cmd.arg(path); + } +} + fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); @@ -801,6 +882,73 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { if verbose { eprintln!("[cargo-miri runner] {:?}", cmd); } + + if std::env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some() { + exec_with_pipe(cmd, &info.stdin) + } else { + exec(cmd) + } +} + +fn phase_cargo_rustdoc(fst_arg: &str, mut args: env::Args) { + let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); + + // phase_cargo_miri sets the RUSTDOC env var to ourselves, so we can't use that here; + // just default to a straight-forward invocation for now: + let mut cmd = Command::new(OsString::from("rustdoc")); + + // Because of the way the main function is structured, we have to take the first argument spearately + // from the rest; to simplify the following argument patching loop, we'll just skip that one. + // This is fine for now, because cargo will never pass --extern arguments in the first position, + // but we should defensively assert that this will work. + let extern_flag = "--extern"; + assert!(fst_arg != extern_flag); + cmd.arg(fst_arg); + + let runtool_flag = "--runtool"; + let mut crossmode = fst_arg == runtool_flag; + while let Some(arg) = args.next() { + if arg == extern_flag { + // Patch --extern arguments to use *.rmeta files, since phase_cargo_rustc only creates stub *.rlib files. + forward_patched_extern_arg(&mut args, &mut cmd); + } else if arg == runtool_flag { + // An existing --runtool flag indicates cargo is running in cross-target mode, which we don't support. + // Note that this is only passed when cargo is run with the unstable -Zdoctest-xcompile flag; + // otherwise, we won't be called as rustdoc at all. + crossmode = true; + break; + } else { + cmd.arg(arg); + } + } + + if crossmode { + eprintln!("Cross-interpreting doc-tests is not currently supported by Miri."); + return; + } + + // For each doc-test, rustdoc starts two child processes: first the test is compiled, + // then the produced executable is invoked. We want to reroute both of these to cargo-miri, + // such that the first time we'll enter phase_cargo_rustc, and phase_cargo_runner second. + // + // rustdoc invokes the test-builder by forwarding most of its own arguments, which makes + // it difficult to determine when phase_cargo_rustc should run instead of phase_cargo_rustdoc. + // Furthermore, the test code is passed via stdin, rather than a temporary file, so we need + // to let phase_cargo_rustc know to expect that. We'll use this environment variable as a flag: + cmd.env("MIRI_CALLED_FROM_RUSTDOC", "1"); + + // The `--test-builder` and `--runtool` arguments are unstable rustdoc features, + // which are disabled by default. We first need to enable them explicitly: + cmd.arg("-Z").arg("unstable-options"); + + let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); + cmd.arg("--test-builder").arg(&cargo_miri_path); // invoked by forwarding most arguments + cmd.arg("--runtool").arg(&cargo_miri_path); // invoked with just a single path argument + + if verbose { + eprintln!("[cargo-miri rustdoc] {:?}", cmd); + } + exec(cmd) } @@ -817,6 +965,30 @@ fn main() { return; } + // The way rustdoc invokes rustc is indistuingishable from the way cargo invokes rustdoc + // by the arguments alone, and we can't take from the args iterator in this case. + // phase_cargo_rustdoc sets this environment variable to let us disambiguate here + let invoked_by_rustdoc = env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some(); + if invoked_by_rustdoc { + // ...however, we then also see this variable when rustdoc invokes us as the testrunner! + // The runner is invoked as `$runtool ($runtool-arg)* output_file`; + // since we don't specify any runtool-args, and rustdoc supplies multiple arguments to + // the test-builder unconditionally, we can just check the number of remaining arguments: + if args.len() == 1 { + let arg = args.next().unwrap(); + let binary = Path::new(&arg); + if binary.exists() { + phase_cargo_runner(binary, args); + } else { + show_error(format!("`cargo-miri` called with non-existing path argument `{}` in rustdoc mode; please invoke this binary through `cargo miri`", arg)); + } + } else { + phase_cargo_rustc(args); + } + + return; + } + // Dispatch to `cargo-miri` phase. There are three phases: // - When we are called via `cargo miri`, we run as the frontend and invoke the underlying // cargo. We set RUSTC_WRAPPER and CARGO_TARGET_RUNNER to ourselves. @@ -829,16 +1001,15 @@ fn main() { Some("miri") => phase_cargo_miri(args), Some("rustc") => phase_cargo_rustc(args), Some(arg) => { - // We have to distinguish the "runner" and "rustfmt" cases. + // We have to distinguish the "runner" and "rustdoc" cases. // As runner, the first argument is the binary (a file that should exist, with an absolute path); - // as rustfmt, the first argument is a flag (`--something`). + // as rustdoc, the first argument is a flag (`--something`). let binary = Path::new(arg); if binary.exists() { assert!(!arg.starts_with("--")); // not a flag phase_cargo_runner(binary, args); } else if arg.starts_with("--") { - // We are rustdoc. - eprintln!("Running doctests is not currently supported by Miri.") + phase_cargo_rustdoc(arg, args); } else { show_error(format!("`cargo-miri` called with unexpected first argument `{}`; please only invoke this binary through `cargo miri`", arg)); } diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 81f589705dc3..c8b85316bb64 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -5,7 +5,7 @@ Assumes the `MIRI_SYSROOT` env var to be set appropriately, and the working directory to contain the cargo-miri-test project. ''' -import sys, subprocess, os +import sys, subprocess, os, re CGREEN = '\33[32m' CBOLD = '\33[1m' @@ -23,6 +23,10 @@ def cargo_miri(cmd, quiet = True): args += ["--target", os.environ['MIRI_TEST_TARGET']] return args +def normalize_stdout(str): + str = str.replace("src\\", "src/") # normalize paths across platforms + return re.sub("finished in \d+\.\d\ds", "finished in $TIME", str) + def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): print("Testing {}...".format(name)) ## Call `cargo miri`, capture all output @@ -38,7 +42,7 @@ def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): (stdout, stderr) = p.communicate(input=stdin) stdout = stdout.decode("UTF-8") stderr = stderr.decode("UTF-8") - if p.returncode == 0 and stdout == open(stdout_ref).read() and stderr == open(stderr_ref).read(): + if p.returncode == 0 and normalize_stdout(stdout) == open(stdout_ref).read() and stderr == open(stderr_ref).read(): # All good! return # Show output @@ -101,26 +105,27 @@ def test_cargo_miri_run(): def test_cargo_miri_test(): # rustdoc is not run on foreign targets is_foreign = 'MIRI_TEST_TARGET' in os.environ - rustdoc_ref = "test.stderr-empty.ref" if is_foreign else "test.stderr-rustdoc.ref" + default_ref = "test.cross-target.stdout.ref" if is_foreign else "test.default.stdout.ref" + filter_ref = "test.filter.cross-target.stdout.ref" if is_foreign else "test.filter.stdout.ref" test("`cargo miri test`", cargo_miri("test"), - "test.default.stdout.ref", rustdoc_ref, + default_ref, "test.stderr-empty.ref", env={'MIRIFLAGS': "-Zmiri-seed=feed"}, ) test("`cargo miri test` (no isolation)", cargo_miri("test"), - "test.default.stdout.ref", rustdoc_ref, + default_ref, "test.stderr-empty.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) test("`cargo miri test` (raw-ptr tracking)", cargo_miri("test"), - "test.default.stdout.ref", rustdoc_ref, + default_ref, "test.stderr-empty.ref", env={'MIRIFLAGS': "-Zmiri-track-raw-pointers"}, ) test("`cargo miri test` (with filter)", cargo_miri("test") + ["--", "--format=pretty", "le1"], - "test.filter.stdout.ref", rustdoc_ref, + filter_ref, "test.stderr-empty.ref", ) test("`cargo miri test` (test target)", cargo_miri("test") + ["--test", "test", "--", "--format=pretty"], diff --git a/test-cargo-miri/test.cross-target.stdout.ref b/test-cargo-miri/test.cross-target.stdout.ref new file mode 100644 index 000000000000..7079798e42fe --- /dev/null +++ b/test-cargo-miri/test.cross-target.stdout.ref @@ -0,0 +1,10 @@ + +running 1 test +. +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out + + +running 7 tests +..i.... +test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out + diff --git a/test-cargo-miri/test.default.stdout.ref b/test-cargo-miri/test.default.stdout.ref index 7079798e42fe..7ed0b2dbaead 100644 --- a/test-cargo-miri/test.default.stdout.ref +++ b/test-cargo-miri/test.default.stdout.ref @@ -8,3 +8,9 @@ running 7 tests ..i.... test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out + +running 1 test +test src/lib.rs - make_true (line 2) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/test-cargo-miri/test.filter.cross-target.stdout.ref b/test-cargo-miri/test.filter.cross-target.stdout.ref new file mode 100644 index 000000000000..37efb8c3ee89 --- /dev/null +++ b/test-cargo-miri/test.filter.cross-target.stdout.ref @@ -0,0 +1,11 @@ + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out + + +running 1 test +test simple1 ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out + diff --git a/test-cargo-miri/test.filter.stdout.ref b/test-cargo-miri/test.filter.stdout.ref index 37efb8c3ee89..18174cadd20d 100644 --- a/test-cargo-miri/test.filter.stdout.ref +++ b/test-cargo-miri/test.filter.stdout.ref @@ -9,3 +9,8 @@ test simple1 ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out; finished in $TIME + diff --git a/test-cargo-miri/test.stderr-rustdoc.ref b/test-cargo-miri/test.stderr-rustdoc.ref deleted file mode 100644 index a310169e305e..000000000000 --- a/test-cargo-miri/test.stderr-rustdoc.ref +++ /dev/null @@ -1 +0,0 @@ -Running doctests is not currently supported by Miri. From dd393f21c7f6a6b997d241e82a8dc89ee42cd6e8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Apr 2021 11:46:20 +0200 Subject: [PATCH 2607/5092] make attempt to cross-interpret a hard error --- cargo-miri/bin.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 1f749b077ab9..f4f18929ba88 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -923,8 +923,7 @@ fn phase_cargo_rustdoc(fst_arg: &str, mut args: env::Args) { } if crossmode { - eprintln!("Cross-interpreting doc-tests is not currently supported by Miri."); - return; + show_error(format!("cross-interpreting doc-tests is not currently supported by Miri.")); } // For each doc-test, rustdoc starts two child processes: first the test is compiled, From 9083e00b2c27145551a24dbd06d2ca40986b0592 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Apr 2021 11:55:53 +0200 Subject: [PATCH 2608/5092] resolve semantic conflicts --- cargo-miri/bin.rs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index f4f18929ba88..bb6d4b8789cd 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -572,7 +572,7 @@ fn phase_cargo_miri(mut args: env::Args) { // us in order to skip them. cmd.env(&host_runner_env_name, &cargo_miri_path); - // Set rustdoc to us as well, so we can make it do nothing (see issue #584). + // Set rustdoc to us as well, so we can run doctests. cmd.env("RUSTDOC", &cargo_miri_path); // Run cargo. @@ -784,18 +784,6 @@ fn phase_cargo_rustc(mut args: env::Args) { } } -fn forward_patched_extern_arg(args: &mut impl Iterator, cmd: &mut Command) { - cmd.arg("--extern"); // always forward flag, but adjust filename: - let path = args.next().expect("`--extern` should be followed by a filename"); - if let Some(lib) = path.strip_suffix(".rlib") { - // If this is an rlib, make it an rmeta. - cmd.arg(format!("{}.rmeta", lib)); - } else { - // Some other extern file (e.g. a `.so`). Forward unchanged. - cmd.arg(path); - } -} - fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); From 65597951b7e51473dc27cdbc5699f8d165197d01 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 14 Feb 2021 18:57:03 +0800 Subject: [PATCH 2609/5092] Fix sysroot for rustdoc --- cargo-miri/bin.rs | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index bb6d4b8789cd..350efbf1826d 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -685,7 +685,7 @@ fn phase_cargo_rustc(mut args: env::Args) { .expect("the wrapper should have set MIRI_SYSROOT"); cmd.arg("--sysroot").arg(sysroot); } - + // ensure --emit argument for a check-only build is present if let Some(i) = env.args.iter().position(|arg| arg.starts_with("--emit=")) { // We need to make sure we're not producing a binary that overwrites the JSON file. @@ -702,7 +702,7 @@ fn phase_cargo_rustc(mut args: env::Args) { eprintln!("[cargo-miri rustc] captured input:\n{}", std::str::from_utf8(&env.stdin).unwrap()); eprintln!("[cargo-miri rustc] {:?}", cmd); } - + exec_with_pipe(cmd, &env.stdin); } @@ -841,11 +841,13 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { cmd.arg(arg); } } - // Set sysroot. - let sysroot = - env::var_os("MIRI_SYSROOT").expect("the wrapper should have set MIRI_SYSROOT"); - cmd.arg("--sysroot"); - cmd.arg(sysroot); + if env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_none() { + // Set sysroot. + let sysroot = + env::var_os("MIRI_SYSROOT").expect("the wrapper should have set MIRI_SYSROOT"); + cmd.arg("--sysroot"); + cmd.arg(sysroot); + } // Respect `MIRIFLAGS`. if let Ok(a) = env::var("MIRIFLAGS") { // This code is taken from `RUSTFLAGS` handling in cargo. @@ -892,7 +894,7 @@ fn phase_cargo_rustdoc(fst_arg: &str, mut args: env::Args) { let extern_flag = "--extern"; assert!(fst_arg != extern_flag); cmd.arg(fst_arg); - + let runtool_flag = "--runtool"; let mut crossmode = fst_arg == runtool_flag; while let Some(arg) = args.next() { @@ -917,21 +919,27 @@ fn phase_cargo_rustdoc(fst_arg: &str, mut args: env::Args) { // For each doc-test, rustdoc starts two child processes: first the test is compiled, // then the produced executable is invoked. We want to reroute both of these to cargo-miri, // such that the first time we'll enter phase_cargo_rustc, and phase_cargo_runner second. - // + // // rustdoc invokes the test-builder by forwarding most of its own arguments, which makes // it difficult to determine when phase_cargo_rustc should run instead of phase_cargo_rustdoc. // Furthermore, the test code is passed via stdin, rather than a temporary file, so we need // to let phase_cargo_rustc know to expect that. We'll use this environment variable as a flag: cmd.env("MIRI_CALLED_FROM_RUSTDOC", "1"); - + // The `--test-builder` and `--runtool` arguments are unstable rustdoc features, // which are disabled by default. We first need to enable them explicitly: cmd.arg("-Z").arg("unstable-options"); - + + // Use our custom sysroot. + let sysroot = + env::var_os("MIRI_SYSROOT").expect("the wrapper should have set MIRI_SYSROOT"); + cmd.arg("--sysroot"); + cmd.arg(sysroot); + let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); cmd.arg("--test-builder").arg(&cargo_miri_path); // invoked by forwarding most arguments cmd.arg("--runtool").arg(&cargo_miri_path); // invoked with just a single path argument - + if verbose { eprintln!("[cargo-miri rustdoc] {:?}", cmd); } From 29bc8a57b09f3259ae83b844c6c29e01f1ba00c6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Apr 2021 12:16:31 +0200 Subject: [PATCH 2610/5092] add test for compile_fail; de-duplicate sysroot forwarding --- cargo-miri/bin.rs | 34 ++++++++++--------------- test-cargo-miri/src/lib.rs | 3 +++ test-cargo-miri/test.default.stdout.ref | 5 ++-- 3 files changed, 19 insertions(+), 23 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 350efbf1826d..1127cef593cc 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -163,6 +163,13 @@ fn forward_patched_extern_arg(args: &mut impl Iterator, cmd: &mut } } +fn forward_miri_sysroot(cmd: &mut Command) { + let sysroot = + env::var_os("MIRI_SYSROOT").expect("the wrapper should have set MIRI_SYSROOT"); + cmd.arg("--sysroot"); + cmd.arg(sysroot); +} + /// Returns the path to the `miri` binary fn find_miri() -> PathBuf { if let Some(path) = env::var_os("MIRI") { @@ -679,13 +686,6 @@ fn phase_cargo_rustc(mut args: env::Args) { return; }; - // use our own sysroot - if !has_arg_flag("--sysroot") { - let sysroot = env::var_os("MIRI_SYSROOT") - .expect("the wrapper should have set MIRI_SYSROOT"); - cmd.arg("--sysroot").arg(sysroot); - } - // ensure --emit argument for a check-only build is present if let Some(i) = env.args.iter().position(|arg| arg.starts_with("--emit=")) { // We need to make sure we're not producing a binary that overwrites the JSON file. @@ -750,10 +750,7 @@ fn phase_cargo_rustc(mut args: env::Args) { } // Use our custom sysroot. - let sysroot = - env::var_os("MIRI_SYSROOT").expect("the wrapper should have set MIRI_SYSROOT"); - cmd.arg("--sysroot"); - cmd.arg(sysroot); + forward_miri_sysroot(&mut cmd); } else { // For host crates or when we are printing, just forward everything. cmd.args(args); @@ -842,11 +839,8 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { } } if env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_none() { - // Set sysroot. - let sysroot = - env::var_os("MIRI_SYSROOT").expect("the wrapper should have set MIRI_SYSROOT"); - cmd.arg("--sysroot"); - cmd.arg(sysroot); + // Set sysroot (if we are inside rustdoc, we already did that in `phase_cargo_rustdoc`). + forward_miri_sysroot(&mut cmd); } // Respect `MIRIFLAGS`. if let Ok(a) = env::var("MIRIFLAGS") { @@ -930,12 +924,10 @@ fn phase_cargo_rustdoc(fst_arg: &str, mut args: env::Args) { // which are disabled by default. We first need to enable them explicitly: cmd.arg("-Z").arg("unstable-options"); - // Use our custom sysroot. - let sysroot = - env::var_os("MIRI_SYSROOT").expect("the wrapper should have set MIRI_SYSROOT"); - cmd.arg("--sysroot"); - cmd.arg(sysroot); + // rustdoc needs to know the right sysroot. + forward_miri_sysroot(&mut cmd); + // Make rustdoc call us back. let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); cmd.arg("--test-builder").arg(&cargo_miri_path); // invoked by forwarding most arguments cmd.arg("--runtool").arg(&cargo_miri_path); // invoked with just a single path argument diff --git a/test-cargo-miri/src/lib.rs b/test-cargo-miri/src/lib.rs index 33bbd8c966e5..45973522f72f 100644 --- a/test-cargo-miri/src/lib.rs +++ b/test-cargo-miri/src/lib.rs @@ -2,6 +2,9 @@ /// ```rust /// assert!(cargo_miri_test::make_true()); /// ``` +/// ```rust,compile_fail +/// assert!(cargo_miri_test::make_true() == 5); +/// ``` pub fn make_true() -> bool { issue_1567::use_the_dependency(); issue_1705::use_the_dependency(); diff --git a/test-cargo-miri/test.default.stdout.ref b/test-cargo-miri/test.default.stdout.ref index 7ed0b2dbaead..893350ae6e62 100644 --- a/test-cargo-miri/test.default.stdout.ref +++ b/test-cargo-miri/test.default.stdout.ref @@ -9,8 +9,9 @@ running 7 tests test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out -running 1 test +running 2 tests +test src/lib.rs - make_true (line 5) ... ok test src/lib.rs - make_true (line 2) ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME From e66a89c8afe8da0c784943502343c8620c156366 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Apr 2021 12:26:27 +0200 Subject: [PATCH 2611/5092] avoid some dead code and test no_run tests --- cargo-miri/bin.rs | 56 ++++++++++++------------- test-cargo-miri/src/lib.rs | 3 ++ test-cargo-miri/test.default.stdout.ref | 5 ++- test-cargo-miri/test.filter.stdout.ref | 2 +- 4 files changed, 34 insertions(+), 32 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 1127cef593cc..5d2759deea3d 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -38,7 +38,7 @@ enum MiriCommand { } /// The information to run a crate with the given environment. -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Clone)] struct CrateRunEnv { /// The command-line arguments. args: Vec, @@ -50,6 +50,22 @@ struct CrateRunEnv { stdin: Vec, } +impl CrateRunEnv { + /// Gather all the information we need. + fn collect(args: env::Args) -> Self { + let args = args.collect(); + let env = env::vars_os().collect(); + let current_dir = env::current_dir().unwrap().into_os_string(); + + let mut stdin = Vec::new(); + if env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some() { + std::io::stdin().lock().read_to_end(&mut stdin).expect("cannot read stdin"); + } + + CrateRunEnv { args, env, current_dir, stdin } + } +} + /// The information Miri needs to run a crate. Stored as JSON when the crate is "compiled". #[derive(Serialize, Deserialize)] enum CrateRunInfo { @@ -60,20 +76,6 @@ enum CrateRunInfo { } impl CrateRunInfo { - /// Gather all the information we need. - fn collect(args: env::Args) -> Self { - let args = args.collect(); - let env = env::vars_os().collect(); - let current_dir = env::current_dir().unwrap().into_os_string(); - - let mut stdin = Vec::new(); - if env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some() { - std::io::stdin().lock().read_to_end(&mut stdin).expect("cannot read stdin"); - } - - Self::RunWith(CrateRunEnv { args, env, current_dir, stdin }) - } - fn store(&self, filename: &Path) { let file = File::create(filename) .unwrap_or_else(|_| show_error(format!("cannot create `{}`", filename.display()))); @@ -644,7 +646,7 @@ fn phase_cargo_rustc(mut args: env::Args) { let target_crate = is_target_crate(); let print = get_arg_flag_value("--print").is_some(); // whether this is cargo passing `--print` to get some infos - let store_json = |info: &CrateRunInfo| { + let store_json = |info: CrateRunInfo| { // Create a stub .d file to stop Cargo from "rebuilding" the crate: // https://github.com/rust-lang/miri/issues/1724#issuecomment-787115693 // As we store a JSON file instead of building the crate here, an empty file is fine. @@ -672,30 +674,24 @@ fn phase_cargo_rustc(mut args: env::Args) { // like we want them. // Instead of compiling, we write JSON into the output file with all the relevant command-line flags // and environment variables; this is used when cargo calls us again in the CARGO_TARGET_RUNNER phase. - let info = CrateRunInfo::collect(args); - store_json(&info); + let env = CrateRunEnv::collect(args); // Rustdoc expects us to exit with an error code if the test is marked as `compile_fail`, // just creating the JSON file is not enough: we need to detect syntax errors, // so we need to run Miri with `MIRI_BE_RUSTC` for a check-only build. if std::env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some() { let mut cmd = miri(); - let env = if let CrateRunInfo::RunWith(env) = info { - env - } else { - return; - }; - // ensure --emit argument for a check-only build is present + // Ensure --emit argument for a check-only build is present. if let Some(i) = env.args.iter().position(|arg| arg.starts_with("--emit=")) { - // We need to make sure we're not producing a binary that overwrites the JSON file. - // rustdoc should only ever pass an --emit=metadata argument for tests marked as `no_run`: + // For `no_run` tests, rustdoc passes a `--emit` flag; make sure it has the right shape. assert_eq!(env.args[i], "--emit=metadata"); } else { - cmd.arg("--emit=dep-info,metadata"); + // For all other kinds of tests, we can just add our flag. + cmd.arg("--emit=metadata"); } - cmd.args(env.args); + cmd.args(&env.args); cmd.env("MIRI_BE_RUSTC", "1"); if verbose { @@ -706,6 +702,8 @@ fn phase_cargo_rustc(mut args: env::Args) { exec_with_pipe(cmd, &env.stdin); } + store_json(CrateRunInfo::RunWith(env)); + return; } @@ -713,7 +711,7 @@ fn phase_cargo_rustc(mut args: env::Args) { // This is a "runnable" `proc-macro` crate (unit tests). We do not support // interpreting that under Miri now, so we write a JSON file to (display a // helpful message and) skip it in the runner phase. - store_json(&CrateRunInfo::SkipProcMacroTest); + store_json(CrateRunInfo::SkipProcMacroTest); return; } diff --git a/test-cargo-miri/src/lib.rs b/test-cargo-miri/src/lib.rs index 45973522f72f..0c268a18f63c 100644 --- a/test-cargo-miri/src/lib.rs +++ b/test-cargo-miri/src/lib.rs @@ -2,6 +2,9 @@ /// ```rust /// assert!(cargo_miri_test::make_true()); /// ``` +/// ```rust,no_run +/// assert!(cargo_miri_test::make_true()); +/// ``` /// ```rust,compile_fail /// assert!(cargo_miri_test::make_true() == 5); /// ``` diff --git a/test-cargo-miri/test.default.stdout.ref b/test-cargo-miri/test.default.stdout.ref index 893350ae6e62..72ae7e94a146 100644 --- a/test-cargo-miri/test.default.stdout.ref +++ b/test-cargo-miri/test.default.stdout.ref @@ -9,9 +9,10 @@ running 7 tests test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out -running 2 tests +running 3 tests test src/lib.rs - make_true (line 5) ... ok +test src/lib.rs - make_true (line 8) ... ok test src/lib.rs - make_true (line 2) ... ok -test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/test-cargo-miri/test.filter.stdout.ref b/test-cargo-miri/test.filter.stdout.ref index 18174cadd20d..11e47e8ff816 100644 --- a/test-cargo-miri/test.filter.stdout.ref +++ b/test-cargo-miri/test.filter.stdout.ref @@ -12,5 +12,5 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out; finished in $TIME +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 3 filtered out; finished in $TIME From f9bd6b0756c12e9f33223bd0a8460cd1129160a6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Apr 2021 12:46:36 +0200 Subject: [PATCH 2612/5092] nits; test running no doctests --- cargo-miri/bin.rs | 9 +++++---- test-cargo-miri/run-test.py | 6 +++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 5d2759deea3d..b9c46ff41cb5 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -683,6 +683,7 @@ fn phase_cargo_rustc(mut args: env::Args) { let mut cmd = miri(); // Ensure --emit argument for a check-only build is present. + // We cannot use the usual helpers since we need to check specifically in `env.args`. if let Some(i) = env.args.iter().position(|arg| arg.starts_with("--emit=")) { // For `no_run` tests, rustdoc passes a `--emit` flag; make sure it has the right shape. assert_eq!(env.args[i], "--emit=metadata"); @@ -877,7 +878,7 @@ fn phase_cargo_rustdoc(fst_arg: &str, mut args: env::Args) { // phase_cargo_miri sets the RUSTDOC env var to ourselves, so we can't use that here; // just default to a straight-forward invocation for now: - let mut cmd = Command::new(OsString::from("rustdoc")); + let mut cmd = Command::new("rustdoc"); // Because of the way the main function is structured, we have to take the first argument spearately // from the rest; to simplify the following argument patching loop, we'll just skip that one. @@ -888,6 +889,7 @@ fn phase_cargo_rustdoc(fst_arg: &str, mut args: env::Args) { cmd.arg(fst_arg); let runtool_flag = "--runtool"; + // `crossmode` records if *any* argument matches `runtool_flag`; here we check the first one. let mut crossmode = fst_arg == runtool_flag; while let Some(arg) = args.next() { if arg == extern_flag { @@ -950,9 +952,8 @@ fn main() { return; } - // The way rustdoc invokes rustc is indistuingishable from the way cargo invokes rustdoc - // by the arguments alone, and we can't take from the args iterator in this case. - // phase_cargo_rustdoc sets this environment variable to let us disambiguate here + // The way rustdoc invokes rustc is indistuingishable from the way cargo invokes rustdoc by the + // arguments alone. `phase_cargo_rustdoc` sets this environment variable to let us disambiguate. let invoked_by_rustdoc = env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some(); if invoked_by_rustdoc { // ...however, we then also see this variable when rustdoc invokes us as the testrunner! diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index c8b85316bb64..84c4a129ad3e 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -113,9 +113,9 @@ def test_cargo_miri_test(): default_ref, "test.stderr-empty.ref", env={'MIRIFLAGS': "-Zmiri-seed=feed"}, ) - test("`cargo miri test` (no isolation)", - cargo_miri("test"), - default_ref, "test.stderr-empty.ref", + test("`cargo miri test` (no isolation, no doctests)", + cargo_miri("test") + ["--bins", "--tests"], # no `--lib`, we disabled that in `Cargo.toml` + "test.cross-target.stdout.ref", "test.stderr-empty.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) test("`cargo miri test` (raw-ptr tracking)", From 2f6dff6da81e4bf351f82c648b79fbfddd175b3e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Apr 2021 13:18:59 +0200 Subject: [PATCH 2613/5092] nits and fix non-deterministic test output --- cargo-miri/bin.rs | 11 ++++++----- test-cargo-miri/run-test.py | 1 + test-cargo-miri/test.default.stdout.ref | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index b9c46ff41cb5..b70d95c60402 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -38,7 +38,7 @@ enum MiriCommand { } /// The information to run a crate with the given environment. -#[derive(Serialize, Deserialize, Clone)] +#[derive(Serialize, Deserialize)] struct CrateRunEnv { /// The command-line arguments. args: Vec, @@ -52,13 +52,13 @@ struct CrateRunEnv { impl CrateRunEnv { /// Gather all the information we need. - fn collect(args: env::Args) -> Self { + fn collect(args: env::Args, capture_stdin: bool) -> Self { let args = args.collect(); let env = env::vars_os().collect(); let current_dir = env::current_dir().unwrap().into_os_string(); let mut stdin = Vec::new(); - if env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some() { + if capture_stdin { std::io::stdin().lock().read_to_end(&mut stdin).expect("cannot read stdin"); } @@ -669,17 +669,18 @@ fn phase_cargo_rustc(mut args: env::Args) { let runnable_crate = !print && is_runnable_crate(); if runnable_crate && target_crate { + let inside_rustdoc = env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some(); // This is the binary or test crate that we want to interpret under Miri. // But we cannot run it here, as cargo invoked us as a compiler -- our stdin and stdout are not // like we want them. // Instead of compiling, we write JSON into the output file with all the relevant command-line flags // and environment variables; this is used when cargo calls us again in the CARGO_TARGET_RUNNER phase. - let env = CrateRunEnv::collect(args); + let env = CrateRunEnv::collect(args, inside_rustdoc); // Rustdoc expects us to exit with an error code if the test is marked as `compile_fail`, // just creating the JSON file is not enough: we need to detect syntax errors, // so we need to run Miri with `MIRI_BE_RUSTC` for a check-only build. - if std::env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some() { + if inside_rustdoc { let mut cmd = miri(); // Ensure --emit argument for a check-only build is present. diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 84c4a129ad3e..9185c2507b6f 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -143,6 +143,7 @@ def test_cargo_miri_test(): os.chdir(os.path.dirname(os.path.realpath(__file__))) os.environ["RUST_TEST_NOCAPTURE"] = "0" # this affects test output, so make sure it is not set +os.environ["RUST_TEST_THREADS"] = "1" # avoid non-deterministic output due to concurrent test runs target_str = " for target {}".format(os.environ['MIRI_TEST_TARGET']) if 'MIRI_TEST_TARGET' in os.environ else "" print(CGREEN + CBOLD + "## Running `cargo miri` tests{}".format(target_str) + CEND) diff --git a/test-cargo-miri/test.default.stdout.ref b/test-cargo-miri/test.default.stdout.ref index 72ae7e94a146..6e35c374e192 100644 --- a/test-cargo-miri/test.default.stdout.ref +++ b/test-cargo-miri/test.default.stdout.ref @@ -10,9 +10,9 @@ test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out running 3 tests +test src/lib.rs - make_true (line 2) ... ok test src/lib.rs - make_true (line 5) ... ok test src/lib.rs - make_true (line 8) ... ok -test src/lib.rs - make_true (line 2) ... ok test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME From a760aab828c9279fbdc5615fd23e0c499fb1f549 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Apr 2021 10:07:03 +0200 Subject: [PATCH 2614/5092] mention 'cargo miri test filter' in README --- README.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 8a80a57e2d9f..fd6110aafa78 100644 --- a/README.md +++ b/README.md @@ -83,21 +83,24 @@ determine a nightly version that comes with Miri and install that using Now you can run your project in Miri: -1. Run `cargo clean` to eliminate any cached dependencies. Miri needs your +1. Run `cargo clean` to eliminate any cached dependencies. Miri needs your dependencies to be compiled the right way, that would not happen if they have previously already been compiled. 2. To run all tests in your project through Miri, use `cargo miri test`. 3. If you have a binary project, you can run it through Miri using `cargo miri run`. The first time you run Miri, it will perform some extra setup and install some -dependencies. It will ask you for confirmation before installing anything. +dependencies. It will ask you for confirmation before installing anything. -`cargo miri run/test` supports the exact same flags as `cargo run/test`. You -can pass arguments to Miri via `MIRIFLAGS`. For example, +`cargo miri run/test` supports the exact same flags as `cargo run/test`. For +example, `cargo miri test filter` only runs the tests containing `filter` in +their name. + +You can pass arguments to Miri via `MIRIFLAGS`. For example, `MIRIFLAGS="-Zmiri-disable-stacked-borrows" cargo miri run` runs the program without checking the aliasing of references. -When compiling code via `cargo miri`, the `cfg(miri)` config flag is set. You +When compiling code via `cargo miri`, the `cfg(miri)` config flag is set. You can use this to ignore test cases that fail under Miri because they do things Miri does not support: @@ -105,9 +108,7 @@ Miri does not support: #[test] #[cfg_attr(miri, ignore)] fn does_not_work_on_miri() { - std::thread::spawn(|| println!("Hello Thread!")) - .join() - .unwrap(); + tokio::run(futures::future::ok::<_, ()>(())); } ``` @@ -126,11 +127,11 @@ error: unsupported operation: can't call foreign function: bind Miri can not only run a binary or test suite for your host target, it can also perform cross-interpretation for arbitrary foreign targets: `cargo miri run --target x86_64-unknown-linux-gnu` will run your program as if it was a Linux -program, no matter your host OS. This is particularly useful if you are using +program, no matter your host OS. This is particularly useful if you are using Windows, as the Linux target is much better supported than Windows targets. You can also use this to test platforms with different properties than your host -platform. For example `cargo miri test --target mips64-unknown-linux-gnuabi64` +platform. For example `cargo miri test --target mips64-unknown-linux-gnuabi64` will run your test suite on a big-endian target, which is useful for testing endian-sensitive code. From 3dff1d4fcd29f9f4cc258cb1b971c95a38ee5924 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Wed, 7 Apr 2021 20:46:20 +0800 Subject: [PATCH 2615/5092] Don't use `MIRI_DEFAULT_ARGS` to compile host crates --- README.md | 14 +++++++----- cargo-miri/bin.rs | 8 ++++--- src/bin/miri.rs | 33 +++++++++++++++++++++------ test-cargo-miri/Cargo.lock | 5 ++++ test-cargo-miri/Cargo.toml | 1 + test-cargo-miri/build.rs | 8 +++++++ test-cargo-miri/issue-1760/Cargo.toml | 8 +++++++ test-cargo-miri/issue-1760/build.rs | 10 ++++++++ test-cargo-miri/issue-1760/src/lib.rs | 9 ++++++++ test-cargo-miri/src/lib.rs | 1 + tests/run-pass/cfg_miri.rs | 3 +++ 11 files changed, 84 insertions(+), 16 deletions(-) create mode 100644 test-cargo-miri/issue-1760/Cargo.toml create mode 100644 test-cargo-miri/issue-1760/build.rs create mode 100644 test-cargo-miri/issue-1760/src/lib.rs create mode 100644 tests/run-pass/cfg_miri.rs diff --git a/README.md b/README.md index fd6110aafa78..11bb31dc74dc 100644 --- a/README.md +++ b/README.md @@ -100,9 +100,9 @@ You can pass arguments to Miri via `MIRIFLAGS`. For example, `MIRIFLAGS="-Zmiri-disable-stacked-borrows" cargo miri run` runs the program without checking the aliasing of references. -When compiling code via `cargo miri`, the `cfg(miri)` config flag is set. You -can use this to ignore test cases that fail under Miri because they do things -Miri does not support: +When compiling code via `cargo miri`, the `cfg(miri)` config flag is set for code +that will be interpret under Miri. You can use this to ignore test cases that fail +under Miri because they do things Miri does not support: ```rust #[test] @@ -286,9 +286,11 @@ Moreover, Miri recognizes some environment variables: The following environment variables are internal, but used to communicate between different Miri binaries, and as such worth documenting: -* `MIRI_BE_RUSTC` when set to any value tells the Miri driver to actually not - interpret the code but compile it like rustc would. This is useful to be sure - that the compiled `rlib`s are compatible with Miri. +* `MIRI_BE_RUSTC` can be set to `host` or `target`. It tells the Miri driver to + actually not interpret the code but compile it like rustc would. With `target`, Miri sets + some compiler flags to prepare the code for interpretation; with `host`, this is not done. + This environment variable is useful to be sure that the compiled `rlib`s are compatible + with Miri. When set while running `cargo-miri`, it indicates that we are part of a sysroot build (for which some crates need special treatment). * `MIRI_CALLED_FROM_RUSTDOC` when set to any value tells `cargo-miri` that it is diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index b70d95c60402..bdf7e0052d19 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -420,7 +420,7 @@ path = "lib.rs" } else { command.env("RUSTC", &cargo_miri_path); } - command.env("MIRI_BE_RUSTC", "1"); + command.env("MIRI_BE_RUSTC", "target"); // Make sure there are no other wrappers or flags getting in our way // (Cc https://github.com/rust-lang/miri/issues/1421). // This is consistent with normal `cargo build` that does not apply `RUSTFLAGS` @@ -694,7 +694,7 @@ fn phase_cargo_rustc(mut args: env::Args) { } cmd.args(&env.args); - cmd.env("MIRI_BE_RUSTC", "1"); + cmd.env("MIRI_BE_RUSTC", "target"); if verbose { eprintln!("[cargo-miri rustc] captured input:\n{}", std::str::from_utf8(&env.stdin).unwrap()); @@ -758,7 +758,9 @@ fn phase_cargo_rustc(mut args: env::Args) { // We want to compile, not interpret. We still use Miri to make sure the compiler version etc // are the exact same as what is used for interpretation. - cmd.env("MIRI_BE_RUSTC", "1"); + // MIRI_DEFAULT_ARGS should not be used to build host crates, hence setting "target" or "host" + // as the value here to help Miri differentiate them. + cmd.env("MIRI_BE_RUSTC", if target_crate { "target" } else { "host" }); // Run it. if verbose { diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 8256bbd8f847..23a58cf2d8c6 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -135,7 +135,11 @@ fn compile_time_sysroot() -> Option { } /// Execute a compiler with the given CLI arguments and callbacks. -fn run_compiler(mut args: Vec, callbacks: &mut (dyn rustc_driver::Callbacks + Send)) -> ! { +fn run_compiler( + mut args: Vec, + callbacks: &mut (dyn rustc_driver::Callbacks + Send), + insert_default_args: bool, +) -> ! { // Make sure we use the right default sysroot. The default sysroot is wrong, // because `get_or_default_sysroot` in `librustc_session` bases that on `current_exe`. // @@ -151,9 +155,11 @@ fn run_compiler(mut args: Vec, callbacks: &mut (dyn rustc_driver::Callba } } - // Some options have different defaults in Miri than in plain rustc; apply those by making - // them the first arguments after the binary name (but later arguments can overwrite them). - args.splice(1..1, miri::MIRI_DEFAULT_ARGS.iter().map(ToString::to_string)); + if insert_default_args { + // Some options have different defaults in Miri than in plain rustc; apply those by making + // them the first arguments after the binary name (but later arguments can overwrite them). + args.splice(1..1, miri::MIRI_DEFAULT_ARGS.iter().map(ToString::to_string)); + } // Invoke compiler, and handle return code. let exit_code = rustc_driver::catch_with_exit_code(move || { @@ -166,11 +172,24 @@ fn main() { rustc_driver::install_ice_hook(); // If the environment asks us to actually be rustc, then do that. - if env::var_os("MIRI_BE_RUSTC").is_some() { + if let Some(crate_kind) = env::var_os("MIRI_BE_RUSTC") { rustc_driver::init_rustc_env_logger(); + + // Don't insert `MIRI_DEFAULT_ARGS`, in particular, `--cfg=miri`, if we are building a + // "host" crate. That may cause procedural macros (and probably build scripts) to depend + // on Miri-only symbols, such as `miri_resolve_frame`: + // https://github.com/rust-lang/miri/issues/1760 + let insert_default_args = if crate_kind == "target" { + true + } else if crate_kind == "host" { + false + } else { + panic!("invalid `MIRI_BE_RUSTC` value: {:?}", crate_kind) + }; + // We cannot use `rustc_driver::main` as we need to adjust the CLI arguments. let mut callbacks = rustc_driver::TimePassesCallbacks::default(); - run_compiler(env::args().collect(), &mut callbacks) + run_compiler(env::args().collect(), &mut callbacks, insert_default_args) } // Init loggers the Miri way. @@ -300,5 +319,5 @@ fn main() { debug!("rustc arguments: {:?}", rustc_args); debug!("crate arguments: {:?}", miri_config.args); - run_compiler(rustc_args, &mut MiriCompilerCalls { miri_config }) + run_compiler(rustc_args, &mut MiriCompilerCalls { miri_config }, /* insert_default_args: */ true) } diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 45ec195843dc..403b9327930a 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -19,6 +19,7 @@ dependencies = [ "issue_1567", "issue_1691", "issue_1705", + "issue_1760", "rand", "serde_derive", ] @@ -85,6 +86,10 @@ dependencies = [ "byteorder", ] +[[package]] +name = "issue_1760" +version = "0.1.0" + [[package]] name = "libc" version = "0.2.92" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 08470539727a..ae46ebc02a36 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -13,6 +13,7 @@ cdylib = { path = "cdylib" } issue_1567 = { path = "issue-1567" } issue_1691 = { path = "issue-1691" } issue_1705 = { path = "issue-1705" } +issue_1760 = { path = "issue-1760" } [dev-dependencies] rand = { version = "0.8", features = ["small_rng"] } diff --git a/test-cargo-miri/build.rs b/test-cargo-miri/build.rs index 9851ccf39f3f..3e84d69eec80 100644 --- a/test-cargo-miri/build.rs +++ b/test-cargo-miri/build.rs @@ -1,5 +1,10 @@ #![feature(llvm_asm)] +use std::env; + +#[cfg(miri)] +compile_error!("`miri` cfg should not be set in build script"); + fn not_in_miri() -> i32 { // Inline assembly definitely does not work in Miri. let dummy = 42; @@ -11,6 +16,9 @@ fn not_in_miri() -> i32 { fn main() { not_in_miri(); + // Cargo calls `miri --print=cfg` to populate the `CARGO_CFG_*` env vars. + // Make sure that the "miri" flag is set. + assert!(env::var_os("CARGO_CFG_MIRI").is_some()); println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-env-changed=MIRITESTVAR"); println!("cargo:rustc-env=MIRITESTVAR=testval"); diff --git a/test-cargo-miri/issue-1760/Cargo.toml b/test-cargo-miri/issue-1760/Cargo.toml new file mode 100644 index 000000000000..80925c747463 --- /dev/null +++ b/test-cargo-miri/issue-1760/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "issue_1760" +version = "0.1.0" +authors = ["Miri Team"] +edition = "2018" + +[lib] +proc-macro = true diff --git a/test-cargo-miri/issue-1760/build.rs b/test-cargo-miri/issue-1760/build.rs new file mode 100644 index 000000000000..08427fd7164f --- /dev/null +++ b/test-cargo-miri/issue-1760/build.rs @@ -0,0 +1,10 @@ +use std::env; + +#[cfg(miri)] +compile_error!("`miri` cfg should not be set in build script"); + +fn main() { + // Cargo calls `miri --print=cfg` to populate the `CARGO_CFG_*` env vars. + // Make sure that the "miri" flag is not set since we are building a procedural macro crate. + assert!(env::var_os("CARGO_CFG_MIRI").is_none()); +} diff --git a/test-cargo-miri/issue-1760/src/lib.rs b/test-cargo-miri/issue-1760/src/lib.rs new file mode 100644 index 000000000000..b4f6274af444 --- /dev/null +++ b/test-cargo-miri/issue-1760/src/lib.rs @@ -0,0 +1,9 @@ +use proc_macro::TokenStream; + +#[cfg(miri)] +compile_error!("`miri` cfg should not be set in proc-macro"); + +#[proc_macro] +pub fn use_the_dependency(_: TokenStream) -> TokenStream { + TokenStream::new() +} diff --git a/test-cargo-miri/src/lib.rs b/test-cargo-miri/src/lib.rs index 0c268a18f63c..b11a64da13b4 100644 --- a/test-cargo-miri/src/lib.rs +++ b/test-cargo-miri/src/lib.rs @@ -11,5 +11,6 @@ pub fn make_true() -> bool { issue_1567::use_the_dependency(); issue_1705::use_the_dependency(); + issue_1760::use_the_dependency!(); issue_1691::use_me() } diff --git a/tests/run-pass/cfg_miri.rs b/tests/run-pass/cfg_miri.rs new file mode 100644 index 000000000000..558b9a4f50db --- /dev/null +++ b/tests/run-pass/cfg_miri.rs @@ -0,0 +1,3 @@ +fn main() { + assert!(cfg!(miri)); +} From 0a7a41f6ad5e782e5ea60bed6beae6dc025c5c06 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Apr 2021 11:24:33 +0200 Subject: [PATCH 2616/5092] fix typo in README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fd6110aafa78..aa38a45529ac 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [actions-url]: https://github.com/rust-lang/miri/actions An experimental interpreter for [Rust][rust]'s -[mid-level intermediate representation][mir] (MIR). It can run binaries and +[mid-level intermediate representation][mir] (MIR). It can run binaries and test suites of cargo projects and detect certain classes of [undefined behavior](https://doc.rust-lang.org/reference/behavior-considered-undefined.html), for example: @@ -32,7 +32,7 @@ big-endian systems. See [cross-interpretation](#cross-interpretation-running-for-different-targets) below. -Miri has already discovered some [real-world bugs](#bugs-found-by-miri). If you +Miri has already discovered some [real-world bugs](#bugs-found-by-miri). If you found a bug with Miri, we'd appreciate if you tell us and we'll add it to the list! @@ -41,7 +41,7 @@ in your program, and cannot run all programs: * There are still plenty of open questions around the basic invariants for some types and when these invariants even have to hold. Miri tries to avoid false - positives here, so if you program runs fine in Miri right now that is by no + positives here, so if your program runs fine in Miri right now that is by no means a guarantee that it is UB-free when these questions get answered. In particular, Miri does currently not check that integers/floats are From aa3bc06f0f1f0c45ca5d84d030400bb052f51e73 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 Apr 2021 11:00:41 +0200 Subject: [PATCH 2617/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 8fadf6f9a3b2..00d749fbbfd7 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9b0edb7fddacd6a60a380c1ce59159de597ab270 +481598b26db6144c580dc113f4d78b4151b5a1bc From 21968aa53b9161969a9c28e9a4deac95e0d91cc2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 Apr 2021 12:09:10 +0200 Subject: [PATCH 2618/5092] add test to detect dropped temporary --- .../dangling_pointers/stack_temporary.rs | 14 ++++++++++++++ .../storage_dead_dangling.rs | 0 2 files changed, 14 insertions(+) create mode 100644 tests/compile-fail/dangling_pointers/stack_temporary.rs rename tests/compile-fail/{ => dangling_pointers}/storage_dead_dangling.rs (100%) diff --git a/tests/compile-fail/dangling_pointers/stack_temporary.rs b/tests/compile-fail/dangling_pointers/stack_temporary.rs new file mode 100644 index 000000000000..cbd788bbf414 --- /dev/null +++ b/tests/compile-fail/dangling_pointers/stack_temporary.rs @@ -0,0 +1,14 @@ +// This should fail even without validation, but some MIR opts mask the error +// compile-flags: -Zmiri-disable-validation -Zmir-opt-level=0 + +unsafe fn make_ref<'a>(x: *mut i32) -> &'a mut i32 { + &mut *x +} + +fn main() { + unsafe { + let x = make_ref(&mut 0); // The temporary storing "0" is deallocated at the ";"! + let val = *x; //~ ERROR dereferenced after this allocation got freed + println!("{}", val); + } +} diff --git a/tests/compile-fail/storage_dead_dangling.rs b/tests/compile-fail/dangling_pointers/storage_dead_dangling.rs similarity index 100% rename from tests/compile-fail/storage_dead_dangling.rs rename to tests/compile-fail/dangling_pointers/storage_dead_dangling.rs From 87882f2c6a2fa754e8c948145e17b5bafb6dec75 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 Apr 2021 12:33:18 +0200 Subject: [PATCH 2619/5092] add the bad doctests we found to the trophy case --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 168c4bc1a24d..7e7966be46f1 100644 --- a/README.md +++ b/README.md @@ -415,6 +415,7 @@ Definite bugs found: * [TiKV constructing out-of-bounds pointers (and overlapping mutable references)](https://github.com/tikv/tikv/pull/7751) * [`encoding_rs` doing out-of-bounds pointer arithmetic](https://github.com/hsivonen/encoding_rs/pull/53) * [TiKV using `Vec::from_raw_parts` incorrectly](https://github.com/tikv/agatedb/pull/24) +* Incorrect doctests for [`AtomicPtr`](https://github.com/rust-lang/rust/pull/84052) and [`Box::from_raw_in`](https://github.com/rust-lang/rust/pull/84053) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From eaba4b2d2a9faf4a9dfa9529913499c3a2ae03bb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 Apr 2021 14:07:46 +0200 Subject: [PATCH 2620/5092] remove compatibility code for passing miri flags via cargo arguments --- cargo-miri/bin.rs | 42 ++---------------------------------------- 1 file changed, 2 insertions(+), 40 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index bdf7e0052d19..151c952c390c 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -521,46 +521,8 @@ fn phase_cargo_miri(mut args: env::Args) { &host }; - // Forward all further arguments. We do some processing here because we want to - // detect people still using the old way of passing flags to Miri - // (`cargo miri -- -Zmiri-foo`). - while let Some(arg) = args.next() { - cmd.arg(&arg); - if arg == "--" { - // Check if the next argument starts with `-Zmiri`. If yes, we assume - // this is an old-style invocation. - if let Some(next_arg) = args.next() { - if next_arg.starts_with("-Zmiri") || next_arg == "--" { - eprintln!( - "WARNING: it seems like you are setting Miri's flags in `cargo miri` the old way,\n\ - i.e., by passing them after the first `--`. This style is deprecated; please set\n\ - the MIRIFLAGS environment variable instead. `cargo miri run/test` now interprets\n\ - arguments the exact same way as `cargo run/test`." - ); - // Old-style invocation. Turn these into MIRIFLAGS, if there are any. - if next_arg != "--" { - let mut miriflags = env::var("MIRIFLAGS").unwrap_or_default(); - miriflags.push(' '); - miriflags.push_str(&next_arg); - while let Some(further_arg) = args.next() { - if further_arg == "--" { - // End of the Miri flags! - break; - } - miriflags.push(' '); - miriflags.push_str(&further_arg); - } - env::set_var("MIRIFLAGS", miriflags); - } - // Pass the remaining flags to cargo. - cmd.args(args); - break; - } - // Not a Miri argument after all, make sure we pass it to cargo. - cmd.arg(next_arg); - } - } - } + // Forward all further arguments to cargo. + cmd.args(args); // Set `RUSTC_WRAPPER` to ourselves. Cargo will prepend that binary to its usual invocation, // i.e., the first argument is `rustc` -- which is what we use in `main` to distinguish From 2decc78db93fe88fc498bff17dc4a215ef92f9d7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 Apr 2021 14:20:06 +0200 Subject: [PATCH 2621/5092] make sure that we truly do not run no_run doctests --- test-cargo-miri/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-cargo-miri/src/lib.rs b/test-cargo-miri/src/lib.rs index b11a64da13b4..5b84c454c362 100644 --- a/test-cargo-miri/src/lib.rs +++ b/test-cargo-miri/src/lib.rs @@ -3,7 +3,7 @@ /// assert!(cargo_miri_test::make_true()); /// ``` /// ```rust,no_run -/// assert!(cargo_miri_test::make_true()); +/// assert!(!cargo_miri_test::make_true()); /// ``` /// ```rust,compile_fail /// assert!(cargo_miri_test::make_true() == 5); From 72ca2a7a85dd7b87d1a0cad54ce5b513c7cde2d2 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sat, 10 Apr 2021 20:23:32 +0200 Subject: [PATCH 2622/5092] Attempt to fix #1763 by asking the scheduler to retry choosing an operation. --- src/thread.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/thread.rs b/src/thread.rs index 4fe44ef9d4a7..e744ac519dd0 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -711,7 +711,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn run_timeout_callback(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (thread, callback) = - this.machine.threads.get_ready_callback().expect("no callback found"); + if let Some((thread, callback)) = this.machine.threads.get_ready_callback() { + (thread, callback) + } else { + // get_ready_callback can return None if the computer's clock was + // shifted after calling the scheduler and before the call + // to get_ready_callback. In this case, just do nothing, which + // effectively just returns to the scheduler. + return Ok(()); + }; // This back-and-forth with `set_active_thread` is here because of two // design decisions: // 1. Make the caller and not the callback responsible for changing From bda328e26ab638b54d8f11ff967becf7f574f98e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 11 Apr 2021 13:23:37 +0200 Subject: [PATCH 2623/5092] only check timeouts when a thread yields --- src/thread.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/thread.rs b/src/thread.rs index 4fe44ef9d4a7..0f373e4cd31e 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -477,6 +477,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { if self.threads[self.active_thread].check_terminated() { return Ok(SchedulingAction::ExecuteDtors); } + // If we get here again and the thread is *still* terminated, there are no more dtors to run. if self.threads[MAIN_THREAD].state == ThreadState::Terminated { // The main thread terminated; stop the program. if self.threads.iter().any(|thread| thread.state != ThreadState::Terminated) { @@ -490,26 +491,25 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } return Ok(SchedulingAction::Stop); } - // At least for `pthread_cond_timedwait` we need to report timeout when - // the function is called already after the specified time even if a - // signal is received before the thread gets scheduled. Therefore, we - // need to schedule all timeout callbacks before we continue regular - // execution. - // - // Documentation: - // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html# - let potential_sleep_time = - self.timeout_callbacks.values().map(|info| info.call_time.get_wait_time()).min(); - if potential_sleep_time == Some(Duration::new(0, 0)) { - return Ok(SchedulingAction::ExecuteTimeoutCallback); - } - // No callbacks scheduled, pick a regular thread to execute. + // This thread and the program can keep going. if self.threads[self.active_thread].state == ThreadState::Enabled && !self.yield_active_thread { // The currently active thread is still enabled, just continue with it. return Ok(SchedulingAction::ExecuteStep); } + // The active thread yielded. Let's see if there are any timeouts to take care of. We do + // this *before* running any other thread, to ensure that timeouts "in the past" fire before + // any other thread can take an action. This ensures that for `pthread_cond_timedwait`, "an + // error is returned if [...] the absolute time specified by abstime has already been passed + // at the time of the call". + // + let potential_sleep_time = + self.timeout_callbacks.values().map(|info| info.call_time.get_wait_time()).min(); + if potential_sleep_time == Some(Duration::new(0, 0)) { + return Ok(SchedulingAction::ExecuteTimeoutCallback); + } + // No callbacks scheduled, pick a regular thread to execute. // We need to pick a new thread for execution. for (id, thread) in self.threads.iter_enumerated() { if thread.state == ThreadState::Enabled { From 50f68dce2182c9c53d3531e809ac5a0725a48c15 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 11 Apr 2021 13:39:03 +0200 Subject: [PATCH 2624/5092] Reference issue 1763 in the comment. --- src/thread.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/thread.rs b/src/thread.rs index e744ac519dd0..0d4fcbd49ff6 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -714,10 +714,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some((thread, callback)) = this.machine.threads.get_ready_callback() { (thread, callback) } else { - // get_ready_callback can return None if the computer's clock was - // shifted after calling the scheduler and before the call - // to get_ready_callback. In this case, just do nothing, which - // effectively just returns to the scheduler. + // get_ready_callback can return None if the computer's clock + // was shifted after calling the scheduler and before the call + // to get_ready_callback (see issue + // https://github.com/rust-lang/miri/issues/1763). In this case, + // just do nothing, which effectively just returns to the + // scheduler. return Ok(()); }; // This back-and-forth with `set_active_thread` is here because of two From 0674d439b620495480f126e96a4b97ae779d1ae7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 11 Apr 2021 14:21:42 +0200 Subject: [PATCH 2625/5092] test calling pthread_cond_timedwait with an already elapsed timeout --- tests/run-pass/concurrency/libc_pthread_cond.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/run-pass/concurrency/libc_pthread_cond.rs b/tests/run-pass/concurrency/libc_pthread_cond.rs index d4e52bb3a97b..a545c922db1a 100644 --- a/tests/run-pass/concurrency/libc_pthread_cond.rs +++ b/tests/run-pass/concurrency/libc_pthread_cond.rs @@ -38,6 +38,12 @@ fn test_timed_wait_timeout(clock_id: i32) { let elapsed_time = current_time.elapsed().as_millis(); assert!(900 <= elapsed_time && elapsed_time <= 1300); + // Test calling `pthread_cond_timedwait` again with an already elapsed timeout. + assert_eq!( + libc::pthread_cond_timedwait(&mut cond as *mut _, &mut mutex as *mut _, &timeout), + libc::ETIMEDOUT + ); + // Test that invalid nanosecond values (above 10^9 or negative) are rejected with the // correct error code. let invalid_timeout_1 = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: 1_000_000_000 }; From 67b8844628b47e132ffbebe75d259a430a5fbd82 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Apr 2021 19:01:10 +0200 Subject: [PATCH 2626/5092] fix CONTRIBUTING example --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bbfcb7638f38..9edd63dae315 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -74,7 +74,7 @@ You can get a trace of which MIR statements are being executed by setting the `MIRI_LOG` environment variable. For example: ```sh -MIRI_LOG=info ./miri run tests/run-pass/vecs.rs +MIRI_LOG=info ./miri run tests/run-pass/vec.rs ``` Setting `MIRI_LOG` like this will configure logging for Miri itself as well as @@ -83,7 +83,7 @@ can also do more targeted configuration, e.g. the following helps debug the stacked borrows implementation: ```sh -MIRI_LOG=rustc_mir::interpret=info,miri::stacked_borrows ./miri run tests/run-pass/vecs.rs +MIRI_LOG=rustc_mir::interpret=info,miri::stacked_borrows ./miri run tests/run-pass/vec.rs ``` In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an From 648638976af2f7331a61921997b0703edb2f4212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=C3=A9nore=20Bouttefeux?= Date: Thu, 15 Apr 2021 10:00:39 +0200 Subject: [PATCH 2627/5092] allow deref of null ptr in test --- tests/compile-fail/null_pointer_deref.rs | 1 + tests/compile-fail/null_pointer_deref_zst.rs | 1 + tests/compile-fail/null_pointer_write.rs | 1 + tests/compile-fail/null_pointer_write_zst.rs | 1 + 4 files changed, 4 insertions(+) diff --git a/tests/compile-fail/null_pointer_deref.rs b/tests/compile-fail/null_pointer_deref.rs index bd4758f737e7..ab415d8746d1 100644 --- a/tests/compile-fail/null_pointer_deref.rs +++ b/tests/compile-fail/null_pointer_deref.rs @@ -1,3 +1,4 @@ +#[allow(deref_nullptr)] fn main() { let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR inbounds test failed: 0x0 is not a valid pointer panic!("this should never print: {}", x); diff --git a/tests/compile-fail/null_pointer_deref_zst.rs b/tests/compile-fail/null_pointer_deref_zst.rs index d0f21a04d364..45925f3586c4 100644 --- a/tests/compile-fail/null_pointer_deref_zst.rs +++ b/tests/compile-fail/null_pointer_deref_zst.rs @@ -1,6 +1,7 @@ // Some optimizations remove ZST accesses, thus masking this UB. // compile-flags: -Zmir-opt-level=0 +#[allow(deref_nullptr)] fn main() { let x: () = unsafe { *std::ptr::null() }; //~ ERROR memory access failed: 0x0 is not a valid pointer panic!("this should never print: {:?}", x); diff --git a/tests/compile-fail/null_pointer_write.rs b/tests/compile-fail/null_pointer_write.rs index 97c9ee8b1f52..599d2ff7fd5b 100644 --- a/tests/compile-fail/null_pointer_write.rs +++ b/tests/compile-fail/null_pointer_write.rs @@ -1,3 +1,4 @@ +#[allow(deref_nullptr)] fn main() { unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR inbounds test failed: 0x0 is not a valid pointer } diff --git a/tests/compile-fail/null_pointer_write_zst.rs b/tests/compile-fail/null_pointer_write_zst.rs index 1ee1a4b8a303..595011fcd6a7 100644 --- a/tests/compile-fail/null_pointer_write_zst.rs +++ b/tests/compile-fail/null_pointer_write_zst.rs @@ -1,6 +1,7 @@ // Some optimizations remove ZST accesses, thus masking this UB. // compile-flags: -Zmir-opt-level=0 +#[allow(deref_nullptr)] fn main() { // Not using the () type here, as writes of that type do not even have MIR generated. // Also not assigning directly as that's array initialization, not assignment. From 64d07ea217d4c0a449afba904ed0d15545af7052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=C3=A9nore=20Bouttefeux?= Date: Thu, 15 Apr 2021 10:17:54 +0200 Subject: [PATCH 2628/5092] change rust version to head --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 00d749fbbfd7..0bfc150a4fc4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -481598b26db6144c580dc113f4d78b4151b5a1bc +043d9160769a330df5d8a21e846785e2c89f357d From 85f7dd613183c8ee884053c6c5ace48bd8fc0579 Mon Sep 17 00:00:00 2001 From: Charles Lew Date: Fri, 16 Apr 2021 22:22:01 +0800 Subject: [PATCH 2629/5092] Remove `main_fn.rs` test. --- rust-version | 2 +- tests/run-pass/main_fn.rs | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) delete mode 100644 tests/run-pass/main_fn.rs diff --git a/rust-version b/rust-version index 0bfc150a4fc4..46567849e07b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -043d9160769a330df5d8a21e846785e2c89f357d +3833636446b670ee905fba5f8d18881b1739814e diff --git a/tests/run-pass/main_fn.rs b/tests/run-pass/main_fn.rs deleted file mode 100644 index 91d183ee6af7..000000000000 --- a/tests/run-pass/main_fn.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![feature(main)] - -#[main] -fn foo() { -} From d512ba2ae244079f0d57f7032db06c12ee3b590c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 Apr 2021 10:57:56 +0200 Subject: [PATCH 2630/5092] test thread_local_const_init --- tests/run-pass/concurrency/tls_lib_drop.rs | 6 ++++++ tests/run-pass/concurrency/tls_lib_drop.stdout | 1 + tests/run-pass/concurrency/tls_lib_drop_single_thread.rs | 7 +++++++ .../run-pass/concurrency/tls_lib_drop_single_thread.stderr | 1 + .../tls_pthread_drop_order.rs} | 0 5 files changed, 15 insertions(+) rename tests/run-pass/{thread-local.rs => concurrency/tls_pthread_drop_order.rs} (100%) diff --git a/tests/run-pass/concurrency/tls_lib_drop.rs b/tests/run-pass/concurrency/tls_lib_drop.rs index 46f59ef6204f..00a12599ce99 100644 --- a/tests/run-pass/concurrency/tls_lib_drop.rs +++ b/tests/run-pass/concurrency/tls_lib_drop.rs @@ -1,4 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. +#![feature(thread_local_const_init)] use std::cell::RefCell; use std::thread; @@ -16,6 +17,7 @@ impl Drop for TestCell { thread_local! { static A: TestCell = TestCell { value: RefCell::new(0) }; + static A_CONST: TestCell = const { TestCell { value: RefCell::new(10) } }; } /// Check that destructors of the library thread locals are executed immediately @@ -26,6 +28,10 @@ fn check_destructors() { assert_eq!(*f.value.borrow(), 0); *f.value.borrow_mut() = 5; }); + A_CONST.with(|f| { + assert_eq!(*f.value.borrow(), 10); + *f.value.borrow_mut() = 15; + }); }) .join() .unwrap(); diff --git a/tests/run-pass/concurrency/tls_lib_drop.stdout b/tests/run-pass/concurrency/tls_lib_drop.stdout index 484979b04ca7..9cd7e049d1a0 100644 --- a/tests/run-pass/concurrency/tls_lib_drop.stdout +++ b/tests/run-pass/concurrency/tls_lib_drop.stdout @@ -1,4 +1,5 @@ Dropping: 5 (should be before 'Continue main 1'). +Dropping: 15 (should be before 'Continue main 1'). Continue main 1. Joining: 7 (should be before 'Continue main 2'). Continue main 2. diff --git a/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs b/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs index f232cee5bdd1..7d8e84e33f16 100644 --- a/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs +++ b/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs @@ -1,4 +1,6 @@ +// compile-flags: -Zmiri-track-raw-pointers //! Check that destructors of the thread locals are executed on all OSes. +#![feature(thread_local_const_init)] use std::cell::RefCell; @@ -14,6 +16,7 @@ impl Drop for TestCell { thread_local! { static A: TestCell = TestCell { value: RefCell::new(0) }; + static A_CONST: TestCell = const { TestCell { value: RefCell::new(10) } }; } fn main() { @@ -21,5 +24,9 @@ fn main() { assert_eq!(*f.value.borrow(), 0); *f.value.borrow_mut() = 5; }); + A_CONST.with(|f| { + assert_eq!(*f.value.borrow(), 10); + *f.value.borrow_mut() = 15; + }); eprintln!("Continue main.") } diff --git a/tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr b/tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr index a9d705e5b9a2..e59dd284bd80 100644 --- a/tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr +++ b/tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr @@ -1,2 +1,3 @@ Continue main. Dropping: 5 +Dropping: 15 diff --git a/tests/run-pass/thread-local.rs b/tests/run-pass/concurrency/tls_pthread_drop_order.rs similarity index 100% rename from tests/run-pass/thread-local.rs rename to tests/run-pass/concurrency/tls_pthread_drop_order.rs From 6834944fd321deeb412838e9c8fedfb717b4f67c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 Apr 2021 12:29:31 +0200 Subject: [PATCH 2631/5092] fix MIRI_BE_RUSTC value during sysroot build --- README.md | 9 ++--- cargo-miri/bin.rs | 91 +++++++++++++++++++++++++++-------------------- 2 files changed, 57 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 7e7966be46f1..e0fbd9fafbb2 100644 --- a/README.md +++ b/README.md @@ -283,16 +283,17 @@ Moreover, Miri recognizes some environment variables: architecture to test against. `miri` and `cargo miri` accept the `--target` flag for the same purpose. -The following environment variables are internal, but used to communicate between -different Miri binaries, and as such worth documenting: +The following environment variables are *internal* and must not be used by +anyone but Miri itself. They are used to communicate between different Miri +binaries, and as such worth documenting: * `MIRI_BE_RUSTC` can be set to `host` or `target`. It tells the Miri driver to actually not interpret the code but compile it like rustc would. With `target`, Miri sets some compiler flags to prepare the code for interpretation; with `host`, this is not done. This environment variable is useful to be sure that the compiled `rlib`s are compatible with Miri. - When set while running `cargo-miri`, it indicates that we are part of a sysroot - build (for which some crates need special treatment). +* `MIRI_CALLED_FROM_XARGO` is set during the Miri-induced `xargo` sysroot build, + which will re-invoke `cargo-miri` as the `rustc` to use for this build. * `MIRI_CALLED_FROM_RUSTDOC` when set to any value tells `cargo-miri` that it is running as a child process of `rustdoc`, which invokes it twice for each doc-test and requires special treatment, most notably a check-only build before interpretation. diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index bdf7e0052d19..01b445ee7eb4 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -413,14 +413,14 @@ path = "lib.rs" // for target crates. // We set ourselves (`cargo-miri`) instead of Miri directly to be able to patch the flags // for `libpanic_abort` (usually this is done by bootstrap but we have to do it ourselves). - // The `MIRI_BE_RUSTC` will mean we dispatch to `phase_setup_rustc`. + // The `MIRI_CALLED_FROM_XARGO` will mean we dispatch to `phase_setup_rustc`. let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); if env::var_os("RUSTC_STAGE").is_some() { command.env("RUSTC_REAL", &cargo_miri_path); } else { command.env("RUSTC", &cargo_miri_path); } - command.env("MIRI_BE_RUSTC", "target"); + command.env("MIRI_CALLED_FROM_XARGO", "1"); // Make sure there are no other wrappers or flags getting in our way // (Cc https://github.com/rust-lang/miri/issues/1421). // This is consistent with normal `cargo build` that does not apply `RUSTFLAGS` @@ -450,21 +450,6 @@ path = "lib.rs" } } -fn phase_setup_rustc(args: env::Args) { - // Mostly we just forward everything. - // `MIRI_BE_RUST` is already set. - let mut cmd = miri(); - cmd.args(args); - - // Patch the panic runtime for `libpanic_abort` (mirroring what bootstrap usually does). - if get_arg_flag_value("--crate-name").as_deref() == Some("panic_abort") { - cmd.arg("-C").arg("panic=abort"); - } - - // Run it! - exec(cmd); -} - fn phase_cargo_miri(mut args: env::Args) { // Check for version and help flags even when invoked as `cargo-miri`. if has_arg_flag("--help") || has_arg_flag("-h") { @@ -598,7 +583,17 @@ fn phase_cargo_miri(mut args: env::Args) { exec(cmd) } -fn phase_cargo_rustc(mut args: env::Args) { +#[derive(Debug, Copy, Clone, PartialEq)] +enum RustcPhase { + /// `rustc` called via `xargo` for sysroot build. + Setup, + /// `rustc` called by `cargo` for regular build. + Build, + /// `rustc` called by `rustdoc` for doctest. + Rustdoc, +} + +fn phase_rustc(mut args: env::Args, phase: RustcPhase) { /// Determines if we are being invoked (as rustc) to build a crate for /// the "target" architecture, in contrast to the "host" architecture. /// Host crates are for build scripts and proc macros and still need to @@ -644,7 +639,7 @@ fn phase_cargo_rustc(mut args: env::Args) { let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); let target_crate = is_target_crate(); - let print = get_arg_flag_value("--print").is_some(); // whether this is cargo passing `--print` to get some infos + let print = get_arg_flag_value("--print").is_some() || has_arg_flag("-vV"); // whether this is cargo/xargo invoking rustc to get some infos let store_json = |info: CrateRunInfo| { // Create a stub .d file to stop Cargo from "rebuilding" the crate: @@ -669,7 +664,8 @@ fn phase_cargo_rustc(mut args: env::Args) { let runnable_crate = !print && is_runnable_crate(); if runnable_crate && target_crate { - let inside_rustdoc = env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some(); + assert!(phase != RustcPhase::Setup, "there should be no interpretation during sysroot build"); + let inside_rustdoc = phase == RustcPhase::Rustdoc; // This is the binary or test crate that we want to interpret under Miri. // But we cannot run it here, as cargo invoked us as a compiler -- our stdin and stdout are not // like we want them. @@ -749,8 +745,15 @@ fn phase_cargo_rustc(mut args: env::Args) { } } - // Use our custom sysroot. - forward_miri_sysroot(&mut cmd); + // Use our custom sysroot (but not if that is what we are currently building). + if phase != RustcPhase::Setup { + forward_miri_sysroot(&mut cmd); + } + + // During setup, patch the panic runtime for `libpanic_abort` (mirroring what bootstrap usually does). + if phase == RustcPhase::Setup && get_arg_flag_value("--crate-name").as_deref() == Some("panic_abort") { + cmd.arg("-C").arg("panic=abort"); + } } else { // For host crates or when we are printing, just forward everything. cmd.args(args); @@ -783,7 +786,15 @@ fn phase_cargo_rustc(mut args: env::Args) { } } -fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { +#[derive(Debug, Copy, Clone, PartialEq)] +enum RunnerPhase { + /// `cargo` is running a binary + Cargo, + /// `rustdoc` is running a binary + Rustdoc, +} + +fn phase_runner(binary: &Path, binary_args: env::Args, phase: RunnerPhase) { let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); let file = File::open(&binary) @@ -840,8 +851,8 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { cmd.arg(arg); } } - if env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_none() { - // Set sysroot (if we are inside rustdoc, we already did that in `phase_cargo_rustdoc`). + // Set sysroot (if we are inside rustdoc, we already did that in `phase_cargo_rustdoc`). + if phase != RunnerPhase::Rustdoc { forward_miri_sysroot(&mut cmd); } // Respect `MIRIFLAGS`. @@ -869,14 +880,17 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { eprintln!("[cargo-miri runner] {:?}", cmd); } - if std::env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some() { - exec_with_pipe(cmd, &info.stdin) - } else { - exec(cmd) + match phase { + RunnerPhase::Rustdoc => { + exec_with_pipe(cmd, &info.stdin) + } + RunnerPhase::Cargo => { + exec(cmd) + } } } -fn phase_cargo_rustdoc(fst_arg: &str, mut args: env::Args) { +fn phase_rustdoc(fst_arg: &str, mut args: env::Args) { let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); // phase_cargo_miri sets the RUSTDOC env var to ourselves, so we can't use that here; @@ -950,15 +964,14 @@ fn main() { args.next().unwrap(); // Dispatch running as part of sysroot compilation. - if env::var_os("MIRI_BE_RUSTC").is_some() { - phase_setup_rustc(args); + if env::var_os("MIRI_CALLED_FROM_XARGO").is_some() { + phase_rustc(args, RustcPhase::Setup); return; } // The way rustdoc invokes rustc is indistuingishable from the way cargo invokes rustdoc by the // arguments alone. `phase_cargo_rustdoc` sets this environment variable to let us disambiguate. - let invoked_by_rustdoc = env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some(); - if invoked_by_rustdoc { + if env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some() { // ...however, we then also see this variable when rustdoc invokes us as the testrunner! // The runner is invoked as `$runtool ($runtool-arg)* output_file`; // since we don't specify any runtool-args, and rustdoc supplies multiple arguments to @@ -967,12 +980,12 @@ fn main() { let arg = args.next().unwrap(); let binary = Path::new(&arg); if binary.exists() { - phase_cargo_runner(binary, args); + phase_runner(binary, args, RunnerPhase::Rustdoc); } else { show_error(format!("`cargo-miri` called with non-existing path argument `{}` in rustdoc mode; please invoke this binary through `cargo miri`", arg)); } } else { - phase_cargo_rustc(args); + phase_rustc(args, RustcPhase::Rustdoc); } return; @@ -988,7 +1001,7 @@ fn main() { // On top of that, we are also called as RUSTDOC, but that is just a stub currently. match args.next().as_deref() { Some("miri") => phase_cargo_miri(args), - Some("rustc") => phase_cargo_rustc(args), + Some("rustc") => phase_rustc(args, RustcPhase::Build), Some(arg) => { // We have to distinguish the "runner" and "rustdoc" cases. // As runner, the first argument is the binary (a file that should exist, with an absolute path); @@ -996,9 +1009,9 @@ fn main() { let binary = Path::new(arg); if binary.exists() { assert!(!arg.starts_with("--")); // not a flag - phase_cargo_runner(binary, args); + phase_runner(binary, args, RunnerPhase::Cargo); } else if arg.starts_with("--") { - phase_cargo_rustdoc(arg, args); + phase_rustdoc(arg, args); } else { show_error(format!("`cargo-miri` called with unexpected first argument `{}`; please only invoke this binary through `cargo miri`", arg)); } From f73cc11f3fcfa7f480297eb82a0fcd072a1d963d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 Apr 2021 09:40:18 +0200 Subject: [PATCH 2632/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 46567849e07b..29fc4efbeab8 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -3833636446b670ee905fba5f8d18881b1739814e +b2c20b51ed838368d3f2bdccb63f401bcddb7e1c From 2ae699c56db7366a14c5e0d517743084a184ffe1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 Apr 2021 09:59:26 +0200 Subject: [PATCH 2633/5092] make TLS-drop-test more cross-platform --- tests/run-pass/concurrency/tls_lib_drop_single_thread.rs | 2 +- tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs b/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs index 7d8e84e33f16..cd1bd6480bcf 100644 --- a/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs +++ b/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs @@ -26,7 +26,7 @@ fn main() { }); A_CONST.with(|f| { assert_eq!(*f.value.borrow(), 10); - *f.value.borrow_mut() = 15; + *f.value.borrow_mut() = 5; // Same value as above since the drop order is different on different platforms }); eprintln!("Continue main.") } diff --git a/tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr b/tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr index e59dd284bd80..09ec1c3c2c51 100644 --- a/tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr +++ b/tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr @@ -1,3 +1,3 @@ Continue main. Dropping: 5 -Dropping: 15 +Dropping: 5 From 4c741e5fb2c6e73d654aa7485ab8985882d6bc05 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Apr 2021 16:57:48 +0200 Subject: [PATCH 2634/5092] rustup --- rust-version | 2 +- tests/compile-fail/invalid_bool.rs | 2 +- tests/run-pass/float.rs | 2 +- tests/run-pass/u128.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index 29fc4efbeab8..d1505e9d8418 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -b2c20b51ed838368d3f2bdccb63f401bcddb7e1c +06f0adb34570ba83fee391abeb0bec0eec28a234 diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index 796d8220dc19..22b9de5776fe 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -1,7 +1,7 @@ // Validation makes this fail in the wrong place // Make sure we find these even with many checks disabled. // compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation -#![feature(test)] +#![feature(bench_black_box)] fn main() { let b = unsafe { std::mem::transmute::(2) }; diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index d9dba770dabd..e40ea919dca1 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -1,4 +1,4 @@ -#![feature(stmt_expr_attributes, test)] +#![feature(stmt_expr_attributes, bench_black_box)] #![allow(arithmetic_overflow)] use std::fmt::Debug; use std::hint::black_box; diff --git a/tests/run-pass/u128.rs b/tests/run-pass/u128.rs index bbc667c5ddeb..fae73476275b 100644 --- a/tests/run-pass/u128.rs +++ b/tests/run-pass/u128.rs @@ -1,4 +1,4 @@ -#![feature(test)] +#![feature(bench_black_box)] use std::hint::black_box as b; fn main() { From b30c5fef5b3654ada90856067240e7b451b8b973 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Fri, 30 Apr 2021 18:50:40 +0800 Subject: [PATCH 2635/5092] Rustup for rust-lang/rust#84401 --- benches/helpers/miri_helper.rs | 2 +- rust-version | 2 +- src/bin/miri.rs | 2 +- test-cargo-miri/Cargo.toml | 4 ++++ test-cargo-miri/src/lib.rs | 4 ++++ test-cargo-miri/test.cross-target.stdout.ref | 1 + test-cargo-miri/test.default.stdout.ref | 1 + test-cargo-miri/test.filter.cross-target.stdout.ref | 1 + test-cargo-miri/test.filter.stdout.ref | 1 + test-cargo-miri/tests/main.rs | 3 +++ tests/run-pass/main_fn.rs | 7 +++++++ 11 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 test-cargo-miri/tests/main.rs create mode 100644 tests/run-pass/main_fn.rs diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 261be48aa0a3..8397fde946c5 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -26,7 +26,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { self.bencher.iter(|| { let config = miri::MiriConfig::default(); - miri::eval_main(tcx, entry_def_id.to_def_id(), config); + miri::eval_main(tcx, entry_def_id, config); }); }); diff --git a/rust-version b/rust-version index d1505e9d8418..1f61617e119f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -06f0adb34570ba83fee391abeb0bec0eec28a234 +bcd696d722c04a0f8c34d884aa4ed2322f55cdd8 diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 23a58cf2d8c6..41776090be44 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -50,7 +50,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { env::set_current_dir(cwd).unwrap(); } - if let Some(return_code) = miri::eval_main(tcx, entry_def_id.to_def_id(), config) { + if let Some(return_code) = miri::eval_main(tcx, entry_def_id, config) { std::process::exit( i32::try_from(return_code).expect("Return value was too large!"), ); diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index ae46ebc02a36..4dbe1aeff23a 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -23,3 +23,7 @@ serde_derive = "1.0" # not actually used, but exercises some unique code path (` [lib] test = false # test that this is respected (will show in the output) + +[[test]] +name = "main" +harness = false diff --git a/test-cargo-miri/src/lib.rs b/test-cargo-miri/src/lib.rs index 5b84c454c362..9d8eb067d6fa 100644 --- a/test-cargo-miri/src/lib.rs +++ b/test-cargo-miri/src/lib.rs @@ -14,3 +14,7 @@ pub fn make_true() -> bool { issue_1760::use_the_dependency!(); issue_1691::use_me() } + +pub fn main() { + println!("imported main"); +} diff --git a/test-cargo-miri/test.cross-target.stdout.ref b/test-cargo-miri/test.cross-target.stdout.ref index 7079798e42fe..e36abd870663 100644 --- a/test-cargo-miri/test.cross-target.stdout.ref +++ b/test-cargo-miri/test.cross-target.stdout.ref @@ -3,6 +3,7 @@ running 1 test . test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +imported main running 7 tests ..i.... diff --git a/test-cargo-miri/test.default.stdout.ref b/test-cargo-miri/test.default.stdout.ref index 6e35c374e192..470e5b36fc51 100644 --- a/test-cargo-miri/test.default.stdout.ref +++ b/test-cargo-miri/test.default.stdout.ref @@ -3,6 +3,7 @@ running 1 test . test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +imported main running 7 tests ..i.... diff --git a/test-cargo-miri/test.filter.cross-target.stdout.ref b/test-cargo-miri/test.filter.cross-target.stdout.ref index 37efb8c3ee89..fb722c5e7123 100644 --- a/test-cargo-miri/test.filter.cross-target.stdout.ref +++ b/test-cargo-miri/test.filter.cross-target.stdout.ref @@ -3,6 +3,7 @@ running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out +imported main running 1 test test simple1 ... ok diff --git a/test-cargo-miri/test.filter.stdout.ref b/test-cargo-miri/test.filter.stdout.ref index 11e47e8ff816..cf1b309a1278 100644 --- a/test-cargo-miri/test.filter.stdout.ref +++ b/test-cargo-miri/test.filter.stdout.ref @@ -3,6 +3,7 @@ running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out +imported main running 1 test test simple1 ... ok diff --git a/test-cargo-miri/tests/main.rs b/test-cargo-miri/tests/main.rs new file mode 100644 index 000000000000..bb94c8f37876 --- /dev/null +++ b/test-cargo-miri/tests/main.rs @@ -0,0 +1,3 @@ +#![feature(imported_main)] + +use cargo_miri_test::main; diff --git a/tests/run-pass/main_fn.rs b/tests/run-pass/main_fn.rs new file mode 100644 index 000000000000..3b84d1abe6f3 --- /dev/null +++ b/tests/run-pass/main_fn.rs @@ -0,0 +1,7 @@ +#![feature(imported_main)] + +mod foo { + pub(crate) fn bar() {} +} + +use foo::bar as main; From 2da6bedaec3f072daae18b7d59e45dd090d48428 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Fri, 30 Apr 2021 17:22:24 +0800 Subject: [PATCH 2636/5092] Use `harness = false` instead of `#![feature(custom_test_frameworks)]` --- Cargo.toml | 4 ++++ tests/compiletest.rs | 6 +----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2483cb2c8129..ab7d88e66934 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,3 +45,7 @@ colored = "2" # This crate uses #[feature(rustc_private)]. # See https://github.com/rust-analyzer/rust-analyzer/pull/7891 rustc_private = true + +[[test]] +name = "compiletest" +harness = false diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 5de5dfb4c675..a0d49c9ddcf4 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -1,7 +1,3 @@ -#![feature(custom_test_frameworks)] -// Custom test runner, to avoid libtest being wrapped around compiletest which wraps libtest. -#![test_runner(test_runner)] - use std::env; use std::path::PathBuf; @@ -83,7 +79,7 @@ fn get_target() -> String { env::var("MIRI_TEST_TARGET").unwrap_or_else(|_| get_host()) } -fn test_runner(_tests: &[&()]) { +fn main() { // Add a test env var to do environment communication tests. env::set_var("MIRI_ENV_VAR_TEST", "0"); // Let the tests know where to store temp files (they might run for a different target, which can make this hard to find). From e591b83185ba60cec09225d5ed6b41325a7a331f Mon Sep 17 00:00:00 2001 From: Smitty Date: Sun, 2 May 2021 12:25:00 -0400 Subject: [PATCH 2637/5092] UB if f*_fast intrinsic called with nonfinite value --- src/shims/intrinsics.rs | 30 ++++++++++++++++++++++++++ tests/compile-fail/fast_math_both.rs | 7 ++++++ tests/compile-fail/fast_math_first.rs | 7 ++++++ tests/compile-fail/fast_math_second.rs | 7 ++++++ 4 files changed, 51 insertions(+) create mode 100644 tests/compile-fail/fast_math_both.rs create mode 100644 tests/compile-fail/fast_math_first.rs create mode 100644 tests/compile-fail/fast_math_second.rs diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 64c6e0a540f8..cae9c813c179 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -173,6 +173,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "frem_fast" => mir::BinOp::Rem, _ => bug!(), }; + let a_valid = match a.layout.ty.kind() { + ty::Float(FloatTy::F32) => a.to_scalar()?.to_f32()?.is_finite(), + ty::Float(FloatTy::F64) => a.to_scalar()?.to_f64()?.is_finite(), + _ => bug!( + "`{}` called with non-float input type {:?}", + intrinsic_name, + a.layout.ty + ), + }; + if !a_valid { + throw_ub_format!( + "`{}` intrinsic called with non-finite value as first parameter", + intrinsic_name, + ); + } + let b_valid = match b.layout.ty.kind() { + ty::Float(FloatTy::F32) => b.to_scalar()?.to_f32()?.is_finite(), + ty::Float(FloatTy::F64) => b.to_scalar()?.to_f64()?.is_finite(), + _ => bug!( + "`{}` called with non-float input type {:?}", + intrinsic_name, + b.layout.ty + ), + }; + if !b_valid { + throw_ub_format!( + "`{}` intrinsic called with non-finite value as second parameter", + intrinsic_name, + ); + } this.binop_ignore_overflow(op, &a, &b, dest)?; } diff --git a/tests/compile-fail/fast_math_both.rs b/tests/compile-fail/fast_math_both.rs new file mode 100644 index 000000000000..470ebe620050 --- /dev/null +++ b/tests/compile-fail/fast_math_both.rs @@ -0,0 +1,7 @@ +#![feature(core_intrinsics)] + +fn main() { + unsafe { + let _x: f32 = core::intrinsics::frem_fast(f32::NAN, 3.2); //~ ERROR `frem_fast` intrinsic called with non-finite value as first parameter + } +} diff --git a/tests/compile-fail/fast_math_first.rs b/tests/compile-fail/fast_math_first.rs new file mode 100644 index 000000000000..184476a47417 --- /dev/null +++ b/tests/compile-fail/fast_math_first.rs @@ -0,0 +1,7 @@ +#![feature(core_intrinsics)] + +fn main() { + unsafe { + let _x: f32 = core::intrinsics::fsub_fast(f32::NAN, f32::NAN); //~ ERROR `fsub_fast` intrinsic called with non-finite value as first parameter + } +} diff --git a/tests/compile-fail/fast_math_second.rs b/tests/compile-fail/fast_math_second.rs new file mode 100644 index 000000000000..114197d75793 --- /dev/null +++ b/tests/compile-fail/fast_math_second.rs @@ -0,0 +1,7 @@ +#![feature(core_intrinsics)] + +fn main() { + unsafe { + let _x: f32 = core::intrinsics::fmul_fast(3.4f32, f32::NAN); //~ ERROR `fmul_fast` intrinsic called with non-finite value as second parameter + } +} From aac6e2ad3e800153b6552d639e291b2b232881f4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 3 May 2021 09:57:13 +0200 Subject: [PATCH 2638/5092] fix checking os_family --- rust-version | 2 +- src/helpers.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 1f61617e119f..464ab46b924f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -bcd696d722c04a0f8c34d884aa4ed2322f55cdd8 +59f551a2dcf57c0d3d96ac5ef60e000524210469 diff --git a/src/helpers.rs b/src/helpers.rs index 7fe0ae0a97c4..8a7657745b64 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -443,7 +443,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let target = &this.tcx.sess.target; let target_os = &target.os; - let last_error = if target.os_family == Some("unix".to_owned()) { + let last_error = if target.families.contains(&"unix".to_owned()) { this.eval_libc(match e.kind() { ConnectionRefused => "ECONNREFUSED", ConnectionReset => "ECONNRESET", @@ -463,7 +463,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("io error {} cannot be transformed into a raw os error", e) } })? - } else if target_os == "windows" { + } else if target.families.contains(&"windows".to_owned()) { // FIXME: we have to finish implementing the Windows equivalent of this. this.eval_windows("c", match e.kind() { NotFound => "ERROR_FILE_NOT_FOUND", From c3ae8a6f90830fe01a2bdd43cbc5ea7161893e64 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 3 May 2021 11:25:05 +0200 Subject: [PATCH 2639/5092] adjust for different 'yield' hint on aarch64 --- src/shims/foreign_items.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 373d5299618d..75a7505e73de 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -512,16 +512,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[] = check_arg_count(args)?; this.yield_active_thread(); } - "llvm.aarch64.hint" if this.tcx.sess.target.arch == "aarch64" => { + "llvm.aarch64.isb" if this.tcx.sess.target.arch == "aarch64" => { check_abi(abi, Abi::C { unwind: false })?; - let &[ref hint] = check_arg_count(args)?; - let hint = this.read_scalar(hint)?.to_i32()?; - match hint { - 1 => { // HINT_YIELD + let &[ref arg] = check_arg_count(args)?; + let arg = this.read_scalar(arg)?.to_i32()?; + match arg { + 15 => { // SY ("full system scope") this.yield_active_thread(); } _ => { - throw_unsup_format!("unsupported llvm.aarch64.hint argument {}", hint); + throw_unsup_format!("unsupported llvm.aarch64.isb argument {}", arg); } } } From 68d29554a8bf100d1a6c95eefb4cd258b4fd1605 Mon Sep 17 00:00:00 2001 From: Smitty Date: Mon, 3 May 2021 09:56:51 -0400 Subject: [PATCH 2640/5092] test for infinite value in f*_fast --- tests/compile-fail/fast_math_second.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile-fail/fast_math_second.rs b/tests/compile-fail/fast_math_second.rs index 114197d75793..e8d70a4a79e7 100644 --- a/tests/compile-fail/fast_math_second.rs +++ b/tests/compile-fail/fast_math_second.rs @@ -2,6 +2,6 @@ fn main() { unsafe { - let _x: f32 = core::intrinsics::fmul_fast(3.4f32, f32::NAN); //~ ERROR `fmul_fast` intrinsic called with non-finite value as second parameter + let _x: f32 = core::intrinsics::fmul_fast(3.4f32, f32::INFINITY); //~ ERROR `fmul_fast` intrinsic called with non-finite value as second parameter } } From e0e59f60205f08486225d0703e666c5cf896fd21 Mon Sep 17 00:00:00 2001 From: Smitty Date: Mon, 3 May 2021 10:08:42 -0400 Subject: [PATCH 2641/5092] Simplify finiteness checking --- src/shims/intrinsics.rs | 42 ++++++++++++--------------- tests/compile-fail/fast_math_both.rs | 2 +- tests/compile-fail/fast_math_first.rs | 2 +- 3 files changed, 21 insertions(+), 25 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index cae9c813c179..b33b9666f712 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -173,35 +173,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "frem_fast" => mir::BinOp::Rem, _ => bug!(), }; - let a_valid = match a.layout.ty.kind() { - ty::Float(FloatTy::F32) => a.to_scalar()?.to_f32()?.is_finite(), - ty::Float(FloatTy::F64) => a.to_scalar()?.to_f64()?.is_finite(), - _ => bug!( - "`{}` called with non-float input type {:?}", - intrinsic_name, - a.layout.ty - ), + let float_finite = |x: ImmTy<'tcx, _>| -> InterpResult<'tcx, bool> { + Ok(match x.layout.ty.kind() { + ty::Float(FloatTy::F32) => x.to_scalar()?.to_f32()?.is_finite(), + ty::Float(FloatTy::F64) => x.to_scalar()?.to_f64()?.is_finite(), + _ => bug!( + "`{}` called with non-float input type {:?}", + intrinsic_name, + x.layout.ty + ), + }) }; - if !a_valid { - throw_ub_format!( + match (float_finite(a)?, float_finite(b)?) { + (false, false) => throw_ub_format!( + "`{}` intrinsic called with non-finite value as both parameters", + intrinsic_name, + ), + (false, _) => throw_ub_format!( "`{}` intrinsic called with non-finite value as first parameter", intrinsic_name, - ); - } - let b_valid = match b.layout.ty.kind() { - ty::Float(FloatTy::F32) => b.to_scalar()?.to_f32()?.is_finite(), - ty::Float(FloatTy::F64) => b.to_scalar()?.to_f64()?.is_finite(), - _ => bug!( - "`{}` called with non-float input type {:?}", - intrinsic_name, - b.layout.ty ), - }; - if !b_valid { - throw_ub_format!( + (_, false) => throw_ub_format!( "`{}` intrinsic called with non-finite value as second parameter", intrinsic_name, - ); + ), + _ => {} } this.binop_ignore_overflow(op, &a, &b, dest)?; } diff --git a/tests/compile-fail/fast_math_both.rs b/tests/compile-fail/fast_math_both.rs index 470ebe620050..844e4e95211f 100644 --- a/tests/compile-fail/fast_math_both.rs +++ b/tests/compile-fail/fast_math_both.rs @@ -2,6 +2,6 @@ fn main() { unsafe { - let _x: f32 = core::intrinsics::frem_fast(f32::NAN, 3.2); //~ ERROR `frem_fast` intrinsic called with non-finite value as first parameter + let _x: f32 = core::intrinsics::fsub_fast(f32::NAN, f32::NAN); //~ ERROR `fsub_fast` intrinsic called with non-finite value as both parameters } } diff --git a/tests/compile-fail/fast_math_first.rs b/tests/compile-fail/fast_math_first.rs index 184476a47417..470ebe620050 100644 --- a/tests/compile-fail/fast_math_first.rs +++ b/tests/compile-fail/fast_math_first.rs @@ -2,6 +2,6 @@ fn main() { unsafe { - let _x: f32 = core::intrinsics::fsub_fast(f32::NAN, f32::NAN); //~ ERROR `fsub_fast` intrinsic called with non-finite value as first parameter + let _x: f32 = core::intrinsics::frem_fast(f32::NAN, 3.2); //~ ERROR `frem_fast` intrinsic called with non-finite value as first parameter } } From 67ec0a5ce371e997a4bd18b026e7e6a17f9770c8 Mon Sep 17 00:00:00 2001 From: Diana <5275194+DianaNites@users.noreply.github.com> Date: Mon, 3 May 2021 22:52:09 -0400 Subject: [PATCH 2642/5092] Fix dead self-link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e0fbd9fafbb2..547e2e15dadc 100644 --- a/README.md +++ b/README.md @@ -164,7 +164,7 @@ doesn't expose any environment to the program, so running `RUST_BACKTRACE=1 cargo miri test` will not do what you expect. To get a backtrace, you need to disable isolation -[using `-Zmiri-disable-isolation`](#miri-flags): +[using `-Zmiri-disable-isolation`][miri-flags]: ```sh RUST_BACKTRACE=1 MIRIFLAGS="-Zmiri-disable-isolation" cargo miri test From 47c5b6eb087f4ff88d350da8e5901346e816e0ab Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Tue, 4 May 2021 15:53:19 +0800 Subject: [PATCH 2643/5092] `encountered a NULL reference` -> `encountered a null reference` --- rust-version | 2 +- tests/compile-fail/validity/cast_fn_ptr1.rs | 2 +- tests/compile-fail/validity/cast_fn_ptr2.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 464ab46b924f..a6374bf120c9 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -59f551a2dcf57c0d3d96ac5ef60e000524210469 +0309953232d9957aef4c7c5a24fcb30735b2066b diff --git a/tests/compile-fail/validity/cast_fn_ptr1.rs b/tests/compile-fail/validity/cast_fn_ptr1.rs index eb94ba256beb..d755c163bba0 100644 --- a/tests/compile-fail/validity/cast_fn_ptr1.rs +++ b/tests/compile-fail/validity/cast_fn_ptr1.rs @@ -7,5 +7,5 @@ fn main() { let g: fn(*const i32) = unsafe { std::mem::transmute(f as fn(&i32)) }; g(0usize as *const i32) - //~^ ERROR encountered a NULL reference + //~^ ERROR encountered a null reference } diff --git a/tests/compile-fail/validity/cast_fn_ptr2.rs b/tests/compile-fail/validity/cast_fn_ptr2.rs index a3faa84f1de0..d78d56b5b6d6 100644 --- a/tests/compile-fail/validity/cast_fn_ptr2.rs +++ b/tests/compile-fail/validity/cast_fn_ptr2.rs @@ -7,5 +7,5 @@ fn main() { let g: fn() -> &'static i32 = unsafe { std::mem::transmute(f as fn() -> *const i32) }; let _x = g(); - //~^ ERROR encountered a NULL reference + //~^ ERROR encountered a null reference } From a2b227f95aca2897c983df327932d0fbdf3c13c1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 7 May 2021 09:24:33 +0200 Subject: [PATCH 2644/5092] stacked borrows: ensure array-to-elem casts behave correctly --- rust-version | 2 +- tests/run-pass/stacked-borrows/stacked-borrows.rs | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index a6374bf120c9..74b2e148f839 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0309953232d9957aef4c7c5a24fcb30735b2066b +1773f14a24c49356b384e45ebb45643bc9bef2c4 diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index f76d4e64c6c9..0401a6640fd3 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -15,6 +15,7 @@ fn main() { shr_and_raw(); disjoint_mutable_subborrows(); raw_ref_to_part(); + array_casts(); } // Make sure that reading from an `&mut` does, like reborrowing to `&`, @@ -174,3 +175,14 @@ fn raw_ref_to_part() { assert!(typed.extra == 42); drop(unsafe { Box::from_raw(whole) }); } + +/// When casting an array reference to a raw element ptr, that should cover the whole array. +fn array_casts() { + let mut x: [usize; 2] = [0, 0]; + let p = &mut x as *mut usize; + unsafe { *p.add(1) = 1; } + + let x: [usize; 2] = [0, 1]; + let p = &x as *const usize; + assert_eq!(unsafe { *p.add(1) }, 1); +} From 1ab9fd50a4bbf6e8f7a3bf00579804aa5a6c4b38 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sat, 8 May 2021 15:33:27 +0800 Subject: [PATCH 2645/5092] Update pointer error messages --- rust-version | 2 +- tests/compile-fail/backtrace/bad-backtrace-ptr.rs | 2 +- tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs | 2 +- tests/compile-fail/dangling_pointers/wild_pointer_deref.rs | 2 +- tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs | 2 +- tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs | 2 +- tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs | 2 +- tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs | 2 +- tests/compile-fail/null_pointer_deref.rs | 2 +- tests/compile-fail/null_pointer_write.rs | 2 +- tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/rust-version b/rust-version index 74b2e148f839..e679a6c32287 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1773f14a24c49356b384e45ebb45643bc9bef2c4 +e002ac7e8a1eb04961a722c44b3ffbad575a6caa diff --git a/tests/compile-fail/backtrace/bad-backtrace-ptr.rs b/tests/compile-fail/backtrace/bad-backtrace-ptr.rs index 0c49a527bc16..c83bf1eb382e 100644 --- a/tests/compile-fail/backtrace/bad-backtrace-ptr.rs +++ b/tests/compile-fail/backtrace/bad-backtrace-ptr.rs @@ -4,6 +4,6 @@ extern "Rust" { fn main() { unsafe { - miri_resolve_frame(0 as *mut _, 0); //~ ERROR 0x0 is not a valid pointer + miri_resolve_frame(0 as *mut _, 0); //~ ERROR null pointer is not a valid pointer for this operation } } diff --git a/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs b/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs index 6aa93e714721..87071d8b4591 100644 --- a/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs +++ b/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs @@ -3,5 +3,5 @@ fn main() { let x = 16usize as *const u32; - let _y = unsafe { &*x as *const u32 }; //~ ERROR inbounds test failed: 0x10 is not a valid pointer + let _y = unsafe { &*x as *const u32 }; //~ ERROR 0x10 is not a valid pointer } diff --git a/tests/compile-fail/dangling_pointers/wild_pointer_deref.rs b/tests/compile-fail/dangling_pointers/wild_pointer_deref.rs index 371e72d2822d..2749ccfc0a02 100644 --- a/tests/compile-fail/dangling_pointers/wild_pointer_deref.rs +++ b/tests/compile-fail/dangling_pointers/wild_pointer_deref.rs @@ -1,5 +1,5 @@ fn main() { let p = 44 as *const i32; - let x = unsafe { *p }; //~ ERROR inbounds test failed: 0x2c is not a valid pointer + let x = unsafe { *p }; //~ ERROR 0x2c is not a valid pointer panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs b/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs index 94ff3327123b..299fd5ae49e0 100644 --- a/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs +++ b/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs @@ -6,5 +6,5 @@ fn main() { std::mem::transmute::(42) }; - g(42) //~ ERROR inbounds test failed: 0x2a is not a valid pointer + g(42) //~ ERROR 0x2a is not a valid pointer } diff --git a/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs b/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs index d6cf3d65f296..d8a8f66e7aee 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs +++ b/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs @@ -1,4 +1,4 @@ -// error-pattern: inbounds test failed: 0x0 is not a valid pointer +// error-pattern: pointer arithmetic failed: 0x0 is not a valid pointer fn main() { let x = 0 as *mut i32; diff --git a/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs b/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs index 4bee2fec6b7b..ea6bef151e1c 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs +++ b/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs @@ -1,4 +1,4 @@ -// error-pattern: inbounds test failed: 0x1 is not a valid pointer +// error-pattern: 0x1 is not a valid pointer fn main() { // Can't offset an integer pointer by non-zero offset. diff --git a/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs b/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs index 892dbca1128f..8ff5c3596ef6 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs +++ b/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs @@ -1,4 +1,4 @@ -// error-pattern: inbounds test failed: 0x1 is not a valid pointer +// error-pattern: 0x1 is not a valid pointer fn main() { let ptr = Box::into_raw(Box::new(0u32)); diff --git a/tests/compile-fail/null_pointer_deref.rs b/tests/compile-fail/null_pointer_deref.rs index ab415d8746d1..076b2df609ab 100644 --- a/tests/compile-fail/null_pointer_deref.rs +++ b/tests/compile-fail/null_pointer_deref.rs @@ -1,5 +1,5 @@ #[allow(deref_nullptr)] fn main() { - let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR inbounds test failed: 0x0 is not a valid pointer + let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR null pointer is not a valid pointer for this operation panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/null_pointer_write.rs b/tests/compile-fail/null_pointer_write.rs index 599d2ff7fd5b..5294e60c025f 100644 --- a/tests/compile-fail/null_pointer_write.rs +++ b/tests/compile-fail/null_pointer_write.rs @@ -1,4 +1,4 @@ #[allow(deref_nullptr)] fn main() { - unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR inbounds test failed: 0x0 is not a valid pointer + unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR null pointer is not a valid pointer for this operation } diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs b/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs index c40d8de21dd7..30cbf0b339a1 100644 --- a/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs +++ b/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs @@ -1,4 +1,4 @@ -// error-pattern: inbounds test failed: 0x4 is not a valid pointer +// error-pattern: 0x4 is not a valid pointer use std::ptr::NonNull; fn main() { unsafe { From 7af7e9e4f3526eefedb0d7456b519b5f8d36c2f6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 11 May 2021 15:32:05 +0200 Subject: [PATCH 2646/5092] rustup --- rust-version | 2 +- tests/run-pass/calls.rs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/rust-version b/rust-version index e679a6c32287..f543240677e5 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e002ac7e8a1eb04961a722c44b3ffbad575a6caa +506e75cbf8cb5305e49a41326307004ca3976029 diff --git a/tests/run-pass/calls.rs b/tests/run-pass/calls.rs index c4ba4a9b701f..4cbd7ada69e6 100644 --- a/tests/run-pass/calls.rs +++ b/tests/run-pass/calls.rs @@ -1,5 +1,3 @@ -#![feature(const_fn)] - fn call() -> i32 { fn increment(x: i32) -> i32 { x + 1 From 0d2278c6c6c215f0268c15946cb89a3fe9284fd3 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Wed, 12 May 2021 14:38:50 +0100 Subject: [PATCH 2647/5092] Prefer remapped filename in backtrace to match rustc behaviour --- src/shims/backtrace.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 159a0bc1f8cd..224d8182b159 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -108,7 +108,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let lo = tcx.sess.source_map().lookup_char_pos(pos); - let filename = lo.file.name.to_string(); + let filename = lo.file.name.prefer_remapped().to_string(); let lineno: u32 = lo.line as u32; // `lo.col` is 0-based - add 1 to make it 1-based for the caller. let colno: u32 = lo.col.0 as u32 + 1; From 5b88045bfa18dcfa17c9f4a4de2c1c7ad4b3ced9 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Wed, 12 May 2021 14:45:12 +0100 Subject: [PATCH 2648/5092] Update rust commit sha --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index f543240677e5..645e69c5163b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -506e75cbf8cb5305e49a41326307004ca3976029 +e1ff91f439bc09f566da211c6449821b4e949279 \ No newline at end of file From 64f128c45687d18d64fc6856a30fde585b007e00 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 15 May 2021 14:17:30 +0200 Subject: [PATCH 2649/5092] support building Miri outside a git repo --- cargo-miri/bin.rs | 14 ++++++++------ cargo-miri/build.rs | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index e29bdc771719..84447b3a1a20 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -6,6 +6,7 @@ use std::io::{self, BufRead, BufReader, BufWriter, Read, Write}; use std::ops::Not; use std::path::{Path, PathBuf}; use std::process::Command; +use std::fmt::{Write as _}; use serde::{Deserialize, Serialize}; @@ -90,12 +91,13 @@ fn show_help() { } fn show_version() { - println!( - "miri {} ({} {})", - env!("CARGO_PKG_VERSION"), - env!("VERGEN_GIT_SHA_SHORT"), - env!("VERGEN_GIT_COMMIT_DATE") - ); + let mut version = format!("miri {}", env!("CARGO_PKG_VERSION")); + // Only use `option_env` on vergen variables to ensure the build succeeds + // when vergen failed to find the git info. + if let Some(sha) = option_env!("VERGEN_GIT_SHA_SHORT") { + write!(&mut version, " ({} {})", sha, option_env!("VERGEN_GIT_COMMIT_DATE").unwrap()).unwrap(); + } + println!("{}", version); } fn show_error(msg: String) -> ! { diff --git a/cargo-miri/build.rs b/cargo-miri/build.rs index cff135fe49c0..ebd8e7003d5f 100644 --- a/cargo-miri/build.rs +++ b/cargo-miri/build.rs @@ -7,5 +7,5 @@ fn main() { let mut gen_config = vergen::Config::default(); *gen_config.git_mut().sha_kind_mut() = vergen::ShaKind::Short; *gen_config.git_mut().commit_timestamp_kind_mut() = vergen::TimestampKind::DateOnly; - vergen(gen_config).expect("Unable to generate vergen keys!"); + vergen(gen_config).ok(); // Ignore failure (in case we are built outside a git repo) } From e824321aa4ecb973f93539c187c7e63b73230aa8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 15 May 2021 15:14:19 +0200 Subject: [PATCH 2650/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 645e69c5163b..0495fc97f7f7 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e1ff91f439bc09f566da211c6449821b4e949279 \ No newline at end of file +c6dd87a6b4a62cf5d2cb6207b1dcea652ea1aa60 From 7b3566096c1013ac5e011b47d09298db8c838913 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 May 2021 11:10:27 +0200 Subject: [PATCH 2651/5092] configure rustfmt; fmt cargo-miri --- cargo-miri/bin.rs | 82 +++++++++++++++++++++++++++++------------------ rustfmt.toml | 3 +- 2 files changed, 53 insertions(+), 32 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 84447b3a1a20..295acd6638a2 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -1,12 +1,12 @@ use std::env; use std::ffi::OsString; +use std::fmt::Write as _; use std::fs::{self, File}; -use std::iter::TakeWhile; use std::io::{self, BufRead, BufReader, BufWriter, Read, Write}; +use std::iter::TakeWhile; use std::ops::Not; use std::path::{Path, PathBuf}; use std::process::Command; -use std::fmt::{Write as _}; use serde::{Deserialize, Serialize}; @@ -95,7 +95,8 @@ fn show_version() { // Only use `option_env` on vergen variables to ensure the build succeeds // when vergen failed to find the git info. if let Some(sha) = option_env!("VERGEN_GIT_SHA_SHORT") { - write!(&mut version, " ({} {})", sha, option_env!("VERGEN_GIT_COMMIT_DATE").unwrap()).unwrap(); + write!(&mut version, " ({} {})", sha, option_env!("VERGEN_GIT_COMMIT_DATE").unwrap()) + .unwrap(); } println!("{}", version); } @@ -168,8 +169,7 @@ fn forward_patched_extern_arg(args: &mut impl Iterator, cmd: &mut } fn forward_miri_sysroot(cmd: &mut Command) { - let sysroot = - env::var_os("MIRI_SYSROOT").expect("the wrapper should have set MIRI_SYSROOT"); + let sysroot = env::var_os("MIRI_SYSROOT").expect("the wrapper should have set MIRI_SYSROOT"); cmd.arg("--sysroot"); cmd.arg(sysroot); } @@ -471,7 +471,9 @@ fn phase_cargo_miri(mut args: env::Args) { Some("run") => MiriCommand::Run, Some("setup") => MiriCommand::Setup, // Invalid command. - _ => show_error(format!("`cargo miri` supports the following subcommands: `run`, `test`, and `setup`.")), + _ => show_error(format!( + "`cargo miri` supports the following subcommands: `run`, `test`, and `setup`." + )), }; let verbose = has_arg_flag("-v"); @@ -515,13 +517,14 @@ fn phase_cargo_miri(mut args: env::Args) { // i.e., the first argument is `rustc` -- which is what we use in `main` to distinguish // the two codepaths. (That extra argument is why we prefer this over setting `RUSTC`.) if env::var_os("RUSTC_WRAPPER").is_some() { - println!("WARNING: Ignoring `RUSTC_WRAPPER` environment variable, Miri does not support wrapping."); + println!( + "WARNING: Ignoring `RUSTC_WRAPPER` environment variable, Miri does not support wrapping." + ); } cmd.env("RUSTC_WRAPPER", &cargo_miri_path); - let runner_env_name = |triple: &str| { - format!("CARGO_TARGET_{}_RUNNER", triple.to_uppercase().replace('-', "_")) - }; + let runner_env_name = + |triple: &str| format!("CARGO_TARGET_{}_RUNNER", triple.to_uppercase().replace('-', "_")); let host_runner_env_name = runner_env_name(&host); let target_runner_env_name = runner_env_name(target); // Set the target runner to us, so we can interpret the binaries. @@ -628,7 +631,10 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { let runnable_crate = !print && is_runnable_crate(); if runnable_crate && target_crate { - assert!(phase != RustcPhase::Setup, "there should be no interpretation during sysroot build"); + assert!( + phase != RustcPhase::Setup, + "there should be no interpretation during sysroot build" + ); let inside_rustdoc = phase == RustcPhase::Rustdoc; // This is the binary or test crate that we want to interpret under Miri. // But we cannot run it here, as cargo invoked us as a compiler -- our stdin and stdout are not @@ -657,7 +663,10 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { cmd.env("MIRI_BE_RUSTC", "target"); if verbose { - eprintln!("[cargo-miri rustc] captured input:\n{}", std::str::from_utf8(&env.stdin).unwrap()); + eprintln!( + "[cargo-miri rustc] captured input:\n{}", + std::str::from_utf8(&env.stdin).unwrap() + ); eprintln!("[cargo-miri rustc] {:?}", cmd); } @@ -715,7 +724,9 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { } // During setup, patch the panic runtime for `libpanic_abort` (mirroring what bootstrap usually does). - if phase == RustcPhase::Setup && get_arg_flag_value("--crate-name").as_deref() == Some("panic_abort") { + if phase == RustcPhase::Setup + && get_arg_flag_value("--crate-name").as_deref() == Some("panic_abort") + { cmd.arg("-C").arg("panic=abort"); } } else { @@ -765,12 +776,18 @@ fn phase_runner(binary: &Path, binary_args: env::Args, phase: RunnerPhase) { .unwrap_or_else(|_| show_error(format!("file {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary))); let file = BufReader::new(file); - let info = serde_json::from_reader(file) - .unwrap_or_else(|_| show_error(format!("file {:?} contains outdated or invalid JSON; try `cargo clean`", binary))); + let info = serde_json::from_reader(file).unwrap_or_else(|_| { + show_error(format!( + "file {:?} contains outdated or invalid JSON; try `cargo clean`", + binary + )) + }); let info = match info { CrateRunInfo::RunWith(info) => info, CrateRunInfo::SkipProcMacroTest => { - eprintln!("Running unit tests of `proc-macro` crates is not currently supported by Miri."); + eprintln!( + "Running unit tests of `proc-macro` crates is not currently supported by Miri." + ); return; } }; @@ -783,7 +800,10 @@ fn phase_runner(binary: &Path, binary_args: env::Args, phase: RunnerPhase) { if verbose { if let Some(old_val) = env::var_os(&name) { if old_val != val { - eprintln!("[cargo-miri runner] Overwriting run-time env var {:?}={:?} with build-time value {:?}", name, old_val, val); + eprintln!( + "[cargo-miri runner] Overwriting run-time env var {:?}={:?} with build-time value {:?}", + name, old_val, val + ); } } } @@ -822,11 +842,7 @@ fn phase_runner(binary: &Path, binary_args: env::Args, phase: RunnerPhase) { // Respect `MIRIFLAGS`. if let Ok(a) = env::var("MIRIFLAGS") { // This code is taken from `RUSTFLAGS` handling in cargo. - let args = a - .split(' ') - .map(str::trim) - .filter(|s| !s.is_empty()) - .map(str::to_string); + let args = a.split(' ').map(str::trim).filter(|s| !s.is_empty()).map(str::to_string); cmd.args(args); } @@ -845,12 +861,8 @@ fn phase_runner(binary: &Path, binary_args: env::Args, phase: RunnerPhase) { } match phase { - RunnerPhase::Rustdoc => { - exec_with_pipe(cmd, &info.stdin) - } - RunnerPhase::Cargo => { - exec(cmd) - } + RunnerPhase::Rustdoc => exec_with_pipe(cmd, &info.stdin), + RunnerPhase::Cargo => exec(cmd), } } @@ -946,7 +958,10 @@ fn main() { if binary.exists() { phase_runner(binary, args, RunnerPhase::Rustdoc); } else { - show_error(format!("`cargo-miri` called with non-existing path argument `{}` in rustdoc mode; please invoke this binary through `cargo miri`", arg)); + show_error(format!( + "`cargo-miri` called with non-existing path argument `{}` in rustdoc mode; please invoke this binary through `cargo miri`", + arg + )); } } else { phase_rustc(args, RustcPhase::Rustdoc); @@ -977,9 +992,14 @@ fn main() { } else if arg.starts_with("--") { phase_rustdoc(arg, args); } else { - show_error(format!("`cargo-miri` called with unexpected first argument `{}`; please only invoke this binary through `cargo miri`", arg)); + show_error(format!( + "`cargo-miri` called with unexpected first argument `{}`; please only invoke this binary through `cargo miri`", + arg + )); } } - _ => show_error(format!("`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`")), + _ => show_error(format!( + "`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`" + )), } } diff --git a/rustfmt.toml b/rustfmt.toml index a0d494b335a8..373caafd106b 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,3 +1,4 @@ -use_small_heuristics = "Max" version = "Two" +use_small_heuristics = "Max" match_arm_blocks = false +match_arm_leading_pipes = "Preserve" From 4e231bab5ef620073c3c29b9b1f507f4a8f8c448 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 May 2021 11:28:01 +0200 Subject: [PATCH 2652/5092] format much of Miri --- benches/helpers/miri_helper.rs | 2 +- src/bin/miri.rs | 76 ++++--- src/eval.rs | 14 +- src/helpers.rs | 79 ++++--- src/intptrcast.rs | 2 +- src/lib.rs | 22 +- src/machine.rs | 56 ++--- src/range_map.rs | 13 +- src/shims/backtrace.rs | 56 +++-- src/shims/dlsym.rs | 3 +- src/shims/env.rs | 105 ++++++--- src/shims/foreign_items.rs | 14 +- src/shims/mod.rs | 4 +- src/shims/os_str.rs | 14 +- src/shims/panic.rs | 21 +- src/shims/posix/fs.rs | 293 ++++++++++++++++--------- src/shims/posix/linux/dlsym.rs | 5 +- src/shims/posix/linux/foreign_items.rs | 40 ++-- src/shims/posix/linux/mod.rs | 2 +- src/shims/posix/linux/sync.rs | 31 ++- src/shims/posix/macos/foreign_items.rs | 3 +- src/shims/posix/macos/mod.rs | 2 +- src/shims/posix/mod.rs | 2 +- src/shims/posix/sync.rs | 49 +++-- src/shims/posix/thread.rs | 9 +- src/shims/time.rs | 40 +++- src/shims/tls.rs | 48 ++-- src/shims/windows/dlsym.rs | 3 +- src/shims/windows/foreign_items.rs | 58 +++-- src/shims/windows/mod.rs | 2 +- src/shims/windows/sync.rs | 38 +--- src/stacked_borrows.rs | 58 +++-- src/sync.rs | 47 ++-- src/thread.rs | 44 ++-- src/vector_clock.rs | 7 +- 35 files changed, 750 insertions(+), 512 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 8397fde946c5..7642018c08cb 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -2,8 +2,8 @@ extern crate rustc_driver; extern crate rustc_hir; extern crate rustc_interface; -use rustc_hir::def_id::LOCAL_CRATE; use rustc_driver::Compilation; +use rustc_hir::def_id::LOCAL_CRATE; use rustc_interface::{interface, Queries}; use crate::test::Bencher; diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 41776090be44..0e9a6ffe8050 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -1,11 +1,11 @@ #![feature(rustc_private)] -extern crate rustc_middle; extern crate rustc_driver; +extern crate rustc_errors; extern crate rustc_hir; extern crate rustc_interface; +extern crate rustc_middle; extern crate rustc_session; -extern crate rustc_errors; use std::convert::TryFrom; use std::env; @@ -14,11 +14,11 @@ use std::str::FromStr; use hex::FromHexError; use log::debug; -use rustc_session::{CtfeBacktrace, config::ErrorOutputType}; -use rustc_errors::emitter::{HumanReadableErrorType, ColorConfig}; use rustc_driver::Compilation; +use rustc_errors::emitter::{ColorConfig, HumanReadableErrorType}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::ty::TyCtxt; +use rustc_session::{config::ErrorOutputType, CtfeBacktrace}; struct MiriCompilerCalls { miri_config: miri::MiriConfig, @@ -37,8 +37,13 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { let (entry_def_id, _) = if let Some((entry_def, x)) = tcx.entry_fn(LOCAL_CRATE) { (entry_def, x) } else { - let output_ty = ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto)); - rustc_session::early_error(output_ty, "miri can only run programs that have a main function"); + let output_ty = ErrorOutputType::HumanReadable(HumanReadableErrorType::Default( + ColorConfig::Auto, + )); + rustc_session::early_error( + output_ty, + "miri can only run programs that have a main function", + ); }; let mut config = self.miri_config.clone(); @@ -249,10 +254,7 @@ fn main() { err => panic!("unknown error decoding -Zmiri-seed as hex: {:?}", err), }); if seed_raw.len() > 8 { - panic!( - "-Zmiri-seed must be at most 8 bytes, was {}", - seed_raw.len() - ); + panic!("-Zmiri-seed must be at most 8 bytes, was {}", seed_raw.len()); } let mut bytes = [0; 8]; @@ -260,17 +262,19 @@ fn main() { miri_config.seed = Some(u64::from_be_bytes(bytes)); } arg if arg.starts_with("-Zmiri-env-exclude=") => { - miri_config.excluded_env_vars + miri_config + .excluded_env_vars .push(arg.strip_prefix("-Zmiri-env-exclude=").unwrap().to_owned()); } arg if arg.starts_with("-Zmiri-track-pointer-tag=") => { - let id: u64 = match arg.strip_prefix("-Zmiri-track-pointer-tag=").unwrap().parse() { - Ok(id) => id, - Err(err) => panic!( - "-Zmiri-track-pointer-tag requires a valid `u64` argument: {}", - err - ), - }; + let id: u64 = + match arg.strip_prefix("-Zmiri-track-pointer-tag=").unwrap().parse() { + Ok(id) => id, + Err(err) => panic!( + "-Zmiri-track-pointer-tag requires a valid `u64` argument: {}", + err + ), + }; if let Some(id) = miri::PtrId::new(id) { miri_config.tracked_pointer_tag = Some(id); } else { @@ -280,10 +284,8 @@ fn main() { arg if arg.starts_with("-Zmiri-track-call-id=") => { let id: u64 = match arg.strip_prefix("-Zmiri-track-call-id=").unwrap().parse() { Ok(id) => id, - Err(err) => panic!( - "-Zmiri-track-call-id requires a valid `u64` argument: {}", - err - ), + Err(err) => + panic!("-Zmiri-track-call-id requires a valid `u64` argument: {}", err), }; if let Some(id) = miri::CallId::new(id) { miri_config.tracked_call_id = Some(id); @@ -292,20 +294,28 @@ fn main() { } } arg if arg.starts_with("-Zmiri-track-alloc-id=") => { - let id: u64 = match arg.strip_prefix("-Zmiri-track-alloc-id=").unwrap().parse() { + let id: u64 = match arg.strip_prefix("-Zmiri-track-alloc-id=").unwrap().parse() + { Ok(id) => id, - Err(err) => panic!( - "-Zmiri-track-alloc-id requires a valid `u64` argument: {}", - err - ), + Err(err) => + panic!("-Zmiri-track-alloc-id requires a valid `u64` argument: {}", err), }; miri_config.tracked_alloc_id = Some(miri::AllocId(id)); } arg if arg.starts_with("-Zmiri-compare-exchange-weak-failure-rate=") => { - let rate = match arg.strip_prefix("-Zmiri-compare-exchange-weak-failure-rate=").unwrap().parse::() { + let rate = match arg + .strip_prefix("-Zmiri-compare-exchange-weak-failure-rate=") + .unwrap() + .parse::() + { Ok(rate) if rate >= 0.0 && rate <= 1.0 => rate, - Ok(_) => panic!("-Zmiri-compare-exchange-weak-failure-rate must be between `0.0` and `1.0`"), - Err(err) => panic!("-Zmiri-compare-exchange-weak-failure-rate requires a `f64` between `0.0` and `1.0`: {}", err), + Ok(_) => panic!( + "-Zmiri-compare-exchange-weak-failure-rate must be between `0.0` and `1.0`" + ), + Err(err) => panic!( + "-Zmiri-compare-exchange-weak-failure-rate requires a `f64` between `0.0` and `1.0`: {}", + err + ), }; miri_config.cmpxchg_weak_failure_rate = rate; } @@ -319,5 +329,9 @@ fn main() { debug!("rustc arguments: {:?}", rustc_args); debug!("crate arguments: {:?}", miri_config.args); - run_compiler(rustc_args, &mut MiriCompilerCalls { miri_config }, /* insert_default_args: */ true) + run_compiler( + rustc_args, + &mut MiriCompilerCalls { miri_config }, + /* insert_default_args: */ true, + ) } diff --git a/src/eval.rs b/src/eval.rs index bd1aebe00de8..1e46015f87a8 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -135,8 +135,9 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( argvs.push(arg_place.ptr); } // Make an array with all these pointers, in the Miri memory. - let argvs_layout = - ecx.layout_of(tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), u64::try_from(argvs.len()).unwrap()))?; + let argvs_layout = ecx.layout_of( + tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), u64::try_from(argvs.len()).unwrap()), + )?; let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into()); for (idx, arg) in argvs.into_iter().enumerate() { let place = ecx.mplace_field(&argvs_place, idx)?; @@ -224,9 +225,11 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> assert!(ecx.step()?, "a terminated thread was scheduled for execution"); } SchedulingAction::ExecuteTimeoutCallback => { - assert!(ecx.machine.communicate, + assert!( + ecx.machine.communicate, "scheduler callbacks require disabled isolation, but the code \ - that created the callback did not check it"); + that created the callback did not check it" + ); ecx.run_timeout_callback()?; } SchedulingAction::ExecuteDtors => { @@ -241,7 +244,8 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> } ecx.process_diagnostics(info); } - let return_code = ecx.read_scalar(&ret_place.into())?.check_init()?.to_machine_isize(&ecx)?; + let return_code = + ecx.read_scalar(&ret_place.into())?.check_init()?.to_machine_isize(&ecx)?; Ok(return_code) })(); diff --git a/src/helpers.rs b/src/helpers.rs index 8a7657745b64..7215cb4b0c7b 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -5,10 +5,10 @@ use std::time::Duration; use log::trace; -use rustc_middle::mir; -use rustc_middle::ty::{self, List, TyCtxt, layout::TyAndLayout}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; -use rustc_target::abi::{LayoutOf, Size, FieldsShape, Variants}; +use rustc_middle::mir; +use rustc_middle::ty::{self, layout::TyAndLayout, List, TyCtxt}; +use rustc_target::abi::{FieldsShape, LayoutOf, Size, Variants}; use rustc_target::spec::abi::Abi; use rand::RngCore; @@ -19,10 +19,8 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi /// Gets an instance for a path. fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option { - tcx.crates() - .iter() - .find(|&&krate| tcx.original_crate_name(krate).as_str() == path[0]) - .and_then(|krate| { + tcx.crates().iter().find(|&&krate| tcx.original_crate_name(krate).as_str() == path[0]).and_then( + |krate| { let krate = DefId { krate: *krate, index: CRATE_DEF_INDEX }; let mut items = tcx.item_children(krate); let mut path_it = path.iter().skip(1).peekable(); @@ -40,7 +38,8 @@ fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -53,10 +52,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Evaluates the scalar at the specified path. Returns Some(val) /// if the path could be resolved, and None otherwise - fn eval_path_scalar( - &mut self, - path: &[&str], - ) -> InterpResult<'tcx, ScalarMaybeUninit> { + fn eval_path_scalar(&mut self, path: &[&str]) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_mut(); let instance = this.resolve_path(path); let cid = GlobalId { instance, promoted: None }; @@ -67,9 +63,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function to get a `libc` constant as a `Scalar`. fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar> { - self.eval_context_mut() - .eval_path_scalar(&["libc", name])? - .check_init() + self.eval_context_mut().eval_path_scalar(&["libc", name])?.check_init() } /// Helper function to get a `libc` constant as an `i32`. @@ -101,7 +95,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function to get the `TyAndLayout` of a `windows` type fn windows_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> { let this = self.eval_context_mut(); - let ty = this.resolve_path(&["std", "sys", "windows", "c", name]).ty(*this.tcx, ty::ParamEnv::reveal_all()); + let ty = this + .resolve_path(&["std", "sys", "windows", "c", name]) + .ty(*this.tcx, ty::ParamEnv::reveal_all()); this.layout_of(ty) } @@ -170,7 +166,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let param_env = ty::ParamEnv::reveal_all(); // in Miri this is always the param_env we use... and this.param_env is private. let callee_abi = f.ty(*this.tcx, param_env).fn_sig(*this.tcx).abi(); if callee_abi != caller_abi { - throw_ub_format!("calling a function with ABI {} using caller ABI {}", callee_abi.name(), caller_abi.name()) + throw_ub_format!( + "calling a function with ABI {} using caller ABI {}", + callee_abi.name(), + caller_abi.name() + ) } // Push frame. @@ -181,9 +181,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut callee_args = this.frame().body.args_iter(); for arg in args { let callee_arg = this.local_place( - callee_args.next().ok_or_else(|| - err_ub_format!("callee has fewer arguments than expected") - )? + callee_args + .next() + .ok_or_else(|| err_ub_format!("callee has fewer arguments than expected"))?, )?; this.write_immediate(*arg, &callee_arg)?; } @@ -356,7 +356,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn visit_union(&mut self, _v: &MPlaceTy<'tcx, Tag>, _fields: NonZeroUsize) -> InterpResult<'tcx> { + fn visit_union( + &mut self, + _v: &MPlaceTy<'tcx, Tag>, + _fields: NonZeroUsize, + ) -> InterpResult<'tcx> { bug!("we should have already handled unions in `visit_value`") } } @@ -465,12 +469,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx })? } else if target.families.contains(&"windows".to_owned()) { // FIXME: we have to finish implementing the Windows equivalent of this. - this.eval_windows("c", match e.kind() { - NotFound => "ERROR_FILE_NOT_FOUND", - _ => throw_unsup_format!("io error {} cannot be transformed into a raw os error", e) - })? + this.eval_windows( + "c", + match e.kind() { + NotFound => "ERROR_FILE_NOT_FOUND", + _ => throw_unsup_format!( + "io error {} cannot be transformed into a raw os error", + e + ), + }, + )? } else { - throw_unsup_format!("setting the last OS error from an io::Error is unsupported for {}.", target_os) + throw_unsup_format!( + "setting the last OS error from an io::Error is unsupported for {}.", + target_os + ) }; this.set_last_error(last_error) } @@ -556,8 +569,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Check that the number of args is what we expect. -pub fn check_arg_count<'a, 'tcx, const N: usize>(args: &'a [OpTy<'tcx, Tag>]) -> InterpResult<'tcx, &'a [OpTy<'tcx, Tag>; N]> - where &'a [OpTy<'tcx, Tag>; N]: TryFrom<&'a [OpTy<'tcx, Tag>]> { +pub fn check_arg_count<'a, 'tcx, const N: usize>( + args: &'a [OpTy<'tcx, Tag>], +) -> InterpResult<'tcx, &'a [OpTy<'tcx, Tag>; N]> +where + &'a [OpTy<'tcx, Tag>; N]: TryFrom<&'a [OpTy<'tcx, Tag>]>, +{ if let Ok(ops) = args.try_into() { return Ok(ops); } @@ -569,7 +586,11 @@ pub fn check_abi<'a>(abi: Abi, exp_abi: Abi) -> InterpResult<'a, ()> { if abi == exp_abi { Ok(()) } else { - throw_ub_format!("calling a function with ABI {} using caller ABI {}", exp_abi.name(), abi.name()) + throw_ub_format!( + "calling a function with ABI {} using caller ABI {}", + exp_abi.name(), + abi.name() + ) } } diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 0e6a9f69aeba..b5a77b08ff52 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -6,7 +6,7 @@ use log::trace; use rand::Rng; use rustc_data_structures::fx::FxHashMap; -use rustc_target::abi::{Size, HasDataLayout}; +use rustc_target::abi::{HasDataLayout, Size}; use crate::*; diff --git a/src/lib.rs b/src/lib.rs index 6a5e7af23726..c9645d12fad1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,13 +3,13 @@ #![feature(map_try_insert)] #![feature(never_type)] #![feature(try_blocks)] - #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] extern crate rustc_apfloat; extern crate rustc_ast; -#[macro_use] extern crate rustc_middle; +#[macro_use] +extern crate rustc_middle; extern crate rustc_data_structures; extern crate rustc_hir; extern crate rustc_index; @@ -44,18 +44,18 @@ pub use crate::shims::env::{EnvVars, EvalContextExt as _}; pub use crate::shims::foreign_items::EvalContextExt as _; pub use crate::shims::intrinsics::EvalContextExt as _; pub use crate::shims::os_str::EvalContextExt as _; -pub use crate::shims::time::EvalContextExt as _; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _}; +pub use crate::shims::time::EvalContextExt as _; pub use crate::shims::tls::{EvalContextExt as _, TlsData}; pub use crate::shims::EvalContextExt as _; pub use crate::data_race::{ - AtomicReadOp, AtomicWriteOp, AtomicRwOp, AtomicFenceOp, - EvalContextExt as DataRaceEvalContextExt + AtomicFenceOp, AtomicReadOp, AtomicRwOp, AtomicWriteOp, + EvalContextExt as DataRaceEvalContextExt, }; pub use crate::diagnostics::{ register_diagnostic, report_error, EvalContextExt as DiagnosticsEvalContextExt, - TerminationInfo, NonHaltingDiagnostic, + NonHaltingDiagnostic, TerminationInfo, }; pub use crate::eval::{create_ecx, eval_main, AlignmentCheck, MiriConfig}; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; @@ -67,17 +67,13 @@ pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ - EvalContextExt as StackedBorEvalContextExt, Item, Permission, CallId, PtrId, Stack, Stacks, Tag, + CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, Stack, Stacks, Tag, }; +pub use crate::sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId}; pub use crate::thread::{ EvalContextExt as ThreadsEvalContextExt, SchedulingAction, ThreadId, ThreadManager, ThreadState, }; -pub use crate::sync::{ - EvalContextExt as SyncEvalContextExt, CondvarId, MutexId, RwLockId -}; -pub use crate::vector_clock::{ - VClock, VectorIdx, VTimestamp -}; +pub use crate::vector_clock::{VClock, VTimestamp, VectorIdx}; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. diff --git a/src/machine.rs b/src/machine.rs index 99cb3bf2b29c..635f3297b4e9 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -3,10 +3,10 @@ use std::borrow::Cow; use std::cell::RefCell; +use std::fmt; use std::num::NonZeroU64; use std::rc::Rc; use std::time::Instant; -use std::fmt; use log::trace; use rand::rngs::StdRng; @@ -21,8 +21,8 @@ use rustc_middle::{ TyCtxt, }, }; -use rustc_span::symbol::{sym, Symbol}; use rustc_span::def_id::DefId; +use rustc_span::symbol::{sym, Symbol}; use rustc_target::abi::{LayoutOf, Size}; use rustc_target::spec::abi::Abi; @@ -100,7 +100,7 @@ impl fmt::Display for MiriMemoryKind { Env => write!(f, "environment variable"), Global => write!(f, "global (static or const)"), ExternStatic => write!(f, "extern static"), - Tls => write!(f, "thread-local static"), + Tls => write!(f, "thread-local static"), } } } @@ -176,11 +176,7 @@ impl MemoryExtra { ) { let ptr = ptr.assert_ptr(); assert_eq!(ptr.offset, Size::ZERO); - this.memory - .extra - .extern_statics - .try_insert(Symbol::intern(name), ptr.alloc_id) - .unwrap(); + this.memory.extra.extern_statics.try_insert(Symbol::intern(name), ptr.alloc_id).unwrap(); } /// Sets up the "extern statics" for this machine. @@ -196,7 +192,11 @@ impl MemoryExtra { this.write_scalar(Scalar::from_machine_usize(0, this), &place.into())?; Self::add_extern_static(this, "__cxa_thread_atexit_impl", place.ptr); // "environ" - Self::add_extern_static(this, "environ", this.machine.env_vars.environ.unwrap().ptr); + Self::add_extern_static( + this, + "environ", + this.machine.env_vars.environ.unwrap().ptr, + ); } "windows" => { // "_tls_used" @@ -282,8 +282,8 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { validate: bool, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>, ) -> Self { - let layouts = PrimitiveLayouts::new(layout_cx) - .expect("Couldn't get layouts of primitive types"); + let layouts = + PrimitiveLayouts::new(layout_cx).expect("Couldn't get layouts of primitive types"); Evaluator { // `env_vars` could be initialized properly here if `Memory` were available before // calling this method. @@ -476,15 +476,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); - let (stacks, base_tag) = - if let Some(stacked_borrows) = &memory_extra.stacked_borrows { - let (stacks, base_tag) = - Stacks::new_allocation(id, alloc.size, Rc::clone(stacked_borrows), kind); - (Some(stacks), base_tag) - } else { - // No stacks, no tag. - (None, Tag::Untagged) - }; + let (stacks, base_tag) = if let Some(stacked_borrows) = &memory_extra.stacked_borrows { + let (stacks, base_tag) = + Stacks::new_allocation(id, alloc.size, Rc::clone(stacked_borrows), kind); + (Some(stacks), base_tag) + } else { + // No stacks, no tag. + (None, Tag::Untagged) + }; let race_alloc = if let Some(data_race) = &memory_extra.data_race { Some(data_race::AllocExtra::new_allocation(&data_race, alloc.size, kind)) } else { @@ -518,7 +517,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { Ok(()) } - fn after_static_mem_initialized( ecx: &mut InterpCx<'mir, 'tcx, Self>, ptr: Pointer, @@ -545,11 +543,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { kind: mir::RetagKind, place: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { - if ecx.memory.extra.stacked_borrows.is_some() { - ecx.retag(kind, place) - } else { - Ok(()) - } + if ecx.memory.extra.stacked_borrows.is_some() { ecx.retag(kind, place) } else { Ok(()) } } #[inline(always)] @@ -566,24 +560,20 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } fn stack<'a>( - ecx: &'a InterpCx<'mir, 'tcx, Self> + ecx: &'a InterpCx<'mir, 'tcx, Self>, ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] { ecx.active_thread_stack() } fn stack_mut<'a>( - ecx: &'a mut InterpCx<'mir, 'tcx, Self> + ecx: &'a mut InterpCx<'mir, 'tcx, Self>, ) -> &'a mut Vec> { ecx.active_thread_stack_mut() } #[inline(always)] fn after_stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { - if ecx.memory.extra.stacked_borrows.is_some() { - ecx.retag_return_place() - } else { - Ok(()) - } + if ecx.memory.extra.stacked_borrows.is_some() { ecx.retag_return_place() } else { Ok(()) } } #[inline(always)] diff --git a/src/range_map.rs b/src/range_map.rs index 607c830530e1..8b5a3af5bac5 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -77,7 +77,10 @@ impl RangeMap { }; // The first offset that is not included any more. let end = offset + len; - slice.iter().take_while(move |elem| elem.range.start < end).map(|elem| (Size::from_bytes(elem.range.start), &elem.data)) + slice + .iter() + .take_while(move |elem| elem.range.start < end) + .map(|elem| (Size::from_bytes(elem.range.start), &elem.data)) } pub fn iter_mut_all<'a>(&'a mut self) -> impl Iterator + 'a { @@ -213,7 +216,9 @@ mod tests { fn to_vec(map: &RangeMap, offset: u64, len: u64) -> Vec { (offset..offset + len) .into_iter() - .map(|i| map.iter(Size::from_bytes(i), Size::from_bytes(1)).next().map(|(_, &t)| t).unwrap()) + .map(|i| { + map.iter(Size::from_bytes(i), Size::from_bytes(1)).next().map(|(_, &t)| t).unwrap() + }) .collect() } @@ -267,7 +272,9 @@ mod tests { assert_eq!(to_vec(&map, 10, 10), vec![23, 42, 23, 23, 23, 19, 19, 19, 19, 19]); // Should be seeing two blocks with 19. assert_eq!( - map.iter(Size::from_bytes(15), Size::from_bytes(2)).map(|(_, &t)| t).collect::>(), + map.iter(Size::from_bytes(15), Size::from_bytes(2)) + .map(|(_, &t)| t) + .collect::>(), vec![19, 19] ); diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 224d8182b159..f936913114c4 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -1,19 +1,18 @@ +use crate::rustc_target::abi::LayoutOf as _; use crate::*; use helpers::check_arg_count; -use rustc_middle::ty::{self, TypeAndMut}; use rustc_ast::ast::Mutability; +use rustc_middle::ty::{self, TypeAndMut}; use rustc_span::BytePos; use rustc_target::abi::Size; use std::convert::TryInto as _; -use crate::rustc_target::abi::LayoutOf as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn handle_miri_get_backtrace( &mut self, args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag> + dest: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let tcx = this.tcx; @@ -35,24 +34,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx data.push((frame.instance, span.lo())); } - let ptrs: Vec<_> = data.into_iter().map(|(instance, pos)| { - // We represent a frame pointer by using the `span.lo` value - // as an offset into the function's allocation. This gives us an - // opaque pointer that we can return to user code, and allows us - // to reconstruct the needed frame information in `handle_miri_resolve_frame`. - // Note that we never actually read or write anything from/to this pointer - - // all of the data is represented by the pointer value itself. - let mut fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(instance)); - fn_ptr.offset = Size::from_bytes(pos.0); - Scalar::Ptr(fn_ptr) - }).collect(); + let ptrs: Vec<_> = data + .into_iter() + .map(|(instance, pos)| { + // We represent a frame pointer by using the `span.lo` value + // as an offset into the function's allocation. This gives us an + // opaque pointer that we can return to user code, and allows us + // to reconstruct the needed frame information in `handle_miri_resolve_frame`. + // Note that we never actually read or write anything from/to this pointer - + // all of the data is represented by the pointer value itself. + let mut fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(instance)); + fn_ptr.offset = Size::from_bytes(pos.0); + Scalar::Ptr(fn_ptr) + }) + .collect(); let len = ptrs.len(); - let ptr_ty = tcx.mk_ptr(TypeAndMut { - ty: tcx.types.unit, - mutbl: Mutability::Mut - }); + let ptr_ty = tcx.mk_ptr(TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Mut }); let array_ty = tcx.mk_array(ptr_ty, ptrs.len().try_into().unwrap()); @@ -63,14 +62,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_immediate_to_mplace(ptr.into(), &place)?; } - this.write_immediate(Immediate::new_slice(alloc.ptr.into(), len.try_into().unwrap(), this), dest)?; + this.write_immediate( + Immediate::new_slice(alloc.ptr.into(), len.try_into().unwrap(), this), + dest, + )?; Ok(()) } fn handle_miri_resolve_frame( &mut self, args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag> + dest: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let tcx = this.tcx; @@ -83,7 +85,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.force_ptr(this.read_scalar(ptr)?.check_init()?)?; - let fn_instance = if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(ptr.alloc_id) { + let fn_instance = if let Some(GlobalAlloc::Function(instance)) = + this.tcx.get_global_alloc(ptr.alloc_id) + { instance } else { throw_ub_format!("expected function pointer, found {:?}", ptr); @@ -100,7 +104,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if !(4..=5).contains(&num_fields) { // Always mention 5 fields, since the 4-field struct // is deprecated and slated for removal. - throw_ub_format!("bad declaration of miri_resolve_frame - should return a struct with 5 fields"); + throw_ub_format!( + "bad declaration of miri_resolve_frame - should return a struct with 5 fields" + ); } let pos = BytePos(ptr.offset.bytes().try_into().unwrap()); @@ -121,7 +127,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dest = this.force_allocation(dest)?; if let ty::Adt(adt, _) = dest.layout.ty.kind() { if !adt.repr.c() { - throw_ub_format!("miri_resolve_frame must be declared with a `#[repr(C)]` return type"); + throw_ub_format!( + "miri_resolve_frame must be declared with a `#[repr(C)]` return type" + ); } } diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index e45556f9a1d1..1855d65d6c50 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -37,7 +37,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); match dlsym { Dlsym::Posix(dlsym) => posix::EvalContextExt::call_dlsym(this, dlsym, abi, args, ret), - Dlsym::Windows(dlsym) => windows::EvalContextExt::call_dlsym(this, dlsym, abi, args, ret), + Dlsym::Windows(dlsym) => + windows::EvalContextExt::call_dlsym(this, dlsym, abi, args, ret), } } } diff --git a/src/shims/env.rs b/src/shims/env.rs index 53770fd4f05b..a09169753223 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,10 +1,10 @@ -use std::ffi::{OsString, OsStr}; -use std::env; use std::convert::TryFrom; +use std::env; +use std::ffi::{OsStr, OsString}; -use rustc_target::abi::{Size, LayoutOf}; use rustc_data_structures::fx::FxHashMap; use rustc_mir::interpret::Pointer; +use rustc_target::abi::{LayoutOf, Size}; use crate::*; @@ -49,9 +49,13 @@ impl<'tcx> EnvVars<'tcx> { for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { let var_ptr = match target_os { - "linux" | "macos" => alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx)?, + "linux" | "macos" => + alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx)?, "windows" => alloc_env_var_as_wide_str(name.as_ref(), value.as_ref(), ecx)?, - unsupported => throw_unsup_format!("environment support for target OS `{}` not yet available", unsupported), + unsupported => throw_unsup_format!( + "environment support for target OS `{}` not yet available", + unsupported + ), }; ecx.machine.env_vars.map.insert(OsString::from(name), var_ptr); } @@ -102,14 +106,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn getenv(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let target_os = &this.tcx.sess.target.os; - assert!(target_os == "linux" || target_os == "macos", "`getenv` is only available for the UNIX target family"); + assert!( + target_os == "linux" || target_os == "macos", + "`getenv` is only available for the UNIX target family" + ); let name_ptr = this.read_scalar(name_op)?.check_init()?; let name = this.read_os_str_from_c_str(name_ptr)?; Ok(match this.machine.env_vars.map.get(name) { Some(var_ptr) => { // The offset is used to strip the "{name}=" part of the string. - Scalar::from(var_ptr.offset(Size::from_bytes(u64::try_from(name.len()).unwrap().checked_add(1).unwrap()), this)?) + Scalar::from(var_ptr.offset( + Size::from_bytes(u64::try_from(name.len()).unwrap().checked_add(1).unwrap()), + this, + )?) } None => Scalar::null_ptr(&*this.tcx), }) @@ -118,10 +128,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn GetEnvironmentVariableW( &mut self, - name_op: &OpTy<'tcx, Tag>, // LPCWSTR - buf_op: &OpTy<'tcx, Tag>, // LPWSTR - size_op: &OpTy<'tcx, Tag>, // DWORD - ) -> InterpResult<'tcx, u32> { // Returns DWORD (u32 in Windows) + name_op: &OpTy<'tcx, Tag>, // LPCWSTR + buf_op: &OpTy<'tcx, Tag>, // LPWSTR + size_op: &OpTy<'tcx, Tag>, // DWORD + ) -> InterpResult<'tcx, u32> { + // ^ Returns DWORD (u32 on Windows) + let this = self.eval_context_mut(); this.assert_target_os("windows", "GetEnvironmentVariableW"); @@ -130,9 +142,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(match this.machine.env_vars.map.get(&name) { Some(var_ptr) => { // The offset is used to strip the "{name}=" part of the string. - let name_offset_bytes = - u64::try_from(name.len()).unwrap().checked_add(1).unwrap().checked_mul(2).unwrap(); - let var_ptr = Scalar::from(var_ptr.offset(Size::from_bytes(name_offset_bytes), this)?); + #[rustfmt::skip] + let name_offset_bytes = u64::try_from(name.len()).unwrap() + .checked_add(1).unwrap() + .checked_mul(2).unwrap(); + let var_ptr = + Scalar::from(var_ptr.offset(Size::from_bytes(name_offset_bytes), this)?); let var = this.read_os_str_from_wide_str(var_ptr)?; let buf_ptr = this.read_scalar(buf_op)?.check_init()?; @@ -169,12 +184,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn FreeEnvironmentStringsW(&mut self, env_block_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn FreeEnvironmentStringsW( + &mut self, + env_block_op: &OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("windows", "FreeEnvironmentStringsW"); let env_block_ptr = this.read_scalar(env_block_op)?.check_init()?; - let result = this.memory.deallocate(this.force_ptr(env_block_ptr)?, None, MiriMemoryKind::Env.into()); + let result = this.memory.deallocate( + this.force_ptr(env_block_ptr)?, + None, + MiriMemoryKind::Env.into(), + ); // If the function succeeds, the return value is nonzero. Ok(result.is_ok() as i32) } @@ -186,7 +208,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let mut this = self.eval_context_mut(); let target_os = &this.tcx.sess.target.os; - assert!(target_os == "linux" || target_os == "macos", "`setenv` is only available for the UNIX target family"); + assert!( + target_os == "linux" || target_os == "macos", + "`setenv` is only available for the UNIX target family" + ); let name_ptr = this.read_scalar(name_op)?.check_init()?; let value_ptr = this.read_scalar(value_op)?.check_init()?; @@ -202,8 +227,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some((name, value)) = new { let var_ptr = alloc_env_var_as_c_str(&name, &value, &mut this)?; if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { - this.memory - .deallocate(var, None, MiriMemoryKind::Env.into())?; + this.memory.deallocate(var, None, MiriMemoryKind::Env.into())?; } this.update_environ()?; Ok(0) // return zero on success @@ -248,8 +272,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let value = this.read_os_str_from_wide_str(value_ptr)?; let var_ptr = alloc_env_var_as_wide_str(&name, &value, &mut this)?; if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { - this.memory - .deallocate(var, None, MiriMemoryKind::Env.into())?; + this.memory.deallocate(var, None, MiriMemoryKind::Env.into())?; } this.update_environ()?; Ok(1) // return non-zero on success @@ -259,7 +282,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn unsetenv(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let target_os = &this.tcx.sess.target.os; - assert!(target_os == "linux" || target_os == "macos", "`unsetenv` is only available for the UNIX target family"); + assert!( + target_os == "linux" || target_os == "macos", + "`unsetenv` is only available for the UNIX target family" + ); let name_ptr = this.read_scalar(name_op)?.check_init()?; let mut success = None; @@ -271,8 +297,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } if let Some(old) = success { if let Some(var) = old { - this.memory - .deallocate(var, None, MiriMemoryKind::Env.into())?; + this.memory.deallocate(var, None, MiriMemoryKind::Env.into())?; } this.update_environ()?; Ok(0) @@ -291,7 +316,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let target_os = &this.tcx.sess.target.os; - assert!(target_os == "linux" || target_os == "macos", "`getcwd` is only available for the UNIX target family"); + assert!( + target_os == "linux" || target_os == "macos", + "`getcwd` is only available for the UNIX target family" + ); this.check_no_isolation("`getcwd`")?; @@ -337,7 +365,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn chdir(&mut self, path_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let target_os = &this.tcx.sess.target.os; - assert!(target_os == "linux" || target_os == "macos", "`getcwd` is only available for the UNIX target family"); + assert!( + target_os == "linux" || target_os == "macos", + "`getcwd` is only available for the UNIX target family" + ); this.check_no_isolation("`chdir`")?; @@ -353,10 +384,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn SetCurrentDirectoryW ( + fn SetCurrentDirectoryW( &mut self, - path_op: &OpTy<'tcx, Tag> // LPCTSTR - ) -> InterpResult<'tcx, i32> { // Returns BOOL (i32 in Windows) + path_op: &OpTy<'tcx, Tag>, // LPCTSTR + ) -> InterpResult<'tcx, i32> { + // ^ Returns BOOL (i32 on Windows) + let this = self.eval_context_mut(); this.assert_target_os("windows", "SetCurrentDirectoryW"); @@ -380,7 +413,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Deallocate the old environ list, if any. if let Some(environ) = this.machine.env_vars.environ { let old_vars_ptr = this.read_scalar(&environ.into())?.check_init()?; - this.memory.deallocate(this.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Env.into())?; + this.memory.deallocate( + this.force_ptr(old_vars_ptr)?, + None, + MiriMemoryKind::Env.into(), + )?; } else { // No `environ` allocated yet, let's do that. // This is memory backing an extern static, hence `ExternStatic`, not `Env`. @@ -390,7 +427,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Collect all the pointers to each variable in a vector. - let mut vars: Vec> = this.machine.env_vars.map.values().map(|&ptr| ptr.into()).collect(); + let mut vars: Vec> = + this.machine.env_vars.map.values().map(|&ptr| ptr.into()).collect(); // Add the trailing null pointer. vars.push(Scalar::null_ptr(this)); // Make an array with all these pointers inside Miri. @@ -402,10 +440,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let place = this.mplace_field(&vars_place, idx)?; this.write_scalar(var, &place.into())?; } - this.write_scalar( - vars_place.ptr, - &this.machine.env_vars.environ.unwrap().into(), - )?; + this.write_scalar(vars_place.ptr, &this.machine.env_vars.environ.unwrap().into())?; Ok(()) } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 75a7505e73de..371a50f0e4b2 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -1,16 +1,22 @@ -use std::{convert::{TryInto, TryFrom}, iter}; +use std::{ + convert::{TryFrom, TryInto}, + iter, +}; use log::trace; +use rustc_apfloat::Float; use rustc_hir::def_id::DefId; use rustc_middle::mir; -use rustc_target::{abi::{Align, Size}, spec::{PanicStrategy, abi::Abi}}; use rustc_middle::ty; -use rustc_apfloat::Float; use rustc_span::symbol::sym; +use rustc_target::{ + abi::{Align, Size}, + spec::{abi::Abi, PanicStrategy}, +}; -use crate::*; use super::backtrace::EvalContextExt as _; +use crate::*; use helpers::{check_abi, check_arg_count}; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 1605ea2f6a89..13ea14b4b9d4 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -74,8 +74,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(false); } - let req_align = this - .force_bits(this.read_scalar(align_op)?.check_init()?, this.pointer_size())?; + let req_align = + this.force_bits(this.read_scalar(align_op)?.check_init()?, this.pointer_size())?; // Stop if the alignment is not a power of two. if !req_align.is_power_of_two() { diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 21b5a876463e..22e3806ad334 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -48,7 +48,6 @@ pub fn bytes_to_os_str<'a, 'tcx>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsSt impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. fn read_os_str_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, &'a OsStr> @@ -94,7 +93,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx scalar: Scalar, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { - let bytes = os_str_to_bytes(os_str)?; // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null // terminator to memory using the `ptr` pointer would cause an out-of-bounds access. @@ -199,7 +197,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); let os_str = this.read_os_str_from_wide_str(scalar)?; - Ok(this.convert_path_separator(Cow::Owned(os_str), PathConversion::TargetToHost).into_owned().into()) + Ok(this + .convert_path_separator(Cow::Owned(os_str), PathConversion::TargetToHost) + .into_owned() + .into()) } /// Write a Path to the machine memory (as a null-terminated sequence of bytes), @@ -211,7 +212,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = this.convert_path_separator(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); + let os_str = this + .convert_path_separator(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); this.write_os_str_to_c_str(&os_str, scalar, size) } @@ -224,7 +226,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = this.convert_path_separator(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); + let os_str = this + .convert_path_separator(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); this.write_os_str_to_wide_str(&os_str, scalar, size) } @@ -270,4 +273,3 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; } } - diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 3a43e5e3596f..b60da058e2cb 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -14,8 +14,8 @@ use log::trace; use rustc_middle::{mir, ty}; -use rustc_target::spec::PanicStrategy; use rustc_target::spec::abi::Abi; +use rustc_target::spec::PanicStrategy; use crate::*; use helpers::check_arg_count; @@ -54,10 +54,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[ref payload] = check_arg_count(args)?; let payload = this.read_scalar(payload)?.check_init()?; let thread = this.active_thread_mut(); - assert!( - thread.panic_payload.is_none(), - "the panic runtime should avoid double-panics" - ); + assert!(thread.panic_payload.is_none(), "the panic runtime should avoid double-panics"); thread.panic_payload = Some(payload); // Jump to the unwind block to begin unwinding. @@ -111,7 +108,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This lets `handle_stack_pop` (below) know that we should stop unwinding // when we pop this frame. if this.tcx.sess.panic_strategy() == PanicStrategy::Unwind { - this.frame_mut().extra.catch_unwind = Some(CatchUnwindData { catch_fn, data, dest: *dest, ret }); + this.frame_mut().extra.catch_unwind = + Some(CatchUnwindData { catch_fn, data, dest: *dest, ret }); } return Ok(()); @@ -134,7 +132,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let (true, Some(catch_unwind)) = (unwinding, extra.catch_unwind.take()) { // We've just popped a frame that was pushed by `try`, // and we are unwinding, so we should catch that. - trace!("unwinding: found catch_panic frame during unwinding: {:?}", this.frame().instance); + trace!( + "unwinding: found catch_panic frame during unwinding: {:?}", + this.frame().instance + ); // We set the return value of `try` to 1, since there was a panic. this.write_scalar(Scalar::from_i32(1), &catch_unwind.dest)?; @@ -164,11 +165,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Starta a panic in the interpreter with the given message as payload. - fn start_panic( - &mut self, - msg: &str, - unwind: Option, - ) -> InterpResult<'tcx> { + fn start_panic(&mut self, msg: &str, unwind: Option) -> InterpResult<'tcx> { let this = self.eval_context_mut(); // First arg: message. diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index def2aca292a5..234f03ff462c 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -1,21 +1,23 @@ +use std::borrow::Cow; use std::collections::BTreeMap; use std::convert::{TryFrom, TryInto}; -use std::fs::{read_dir, remove_dir, remove_file, rename, DirBuilder, File, FileType, OpenOptions, ReadDir}; +use std::fs::{ + read_dir, remove_dir, remove_file, rename, DirBuilder, File, FileType, OpenOptions, ReadDir, +}; use std::io::{self, Read, Seek, SeekFrom, Write}; use std::path::Path; use std::time::SystemTime; -use std::borrow::Cow; use log::trace; use rustc_data_structures::fx::FxHashMap; -use rustc_target::abi::{Align, LayoutOf, Size}; use rustc_middle::ty; +use rustc_target::abi::{Align, LayoutOf, Size}; use crate::*; -use stacked_borrows::Tag; use helpers::{check_arg_count, immty_from_int_checked, immty_from_uint_checked}; use shims::time::system_time_to_duration; +use stacked_borrows::Tag; #[derive(Debug)] struct FileHandle { @@ -23,13 +25,28 @@ struct FileHandle { writable: bool, } -trait FileDescriptor : std::fmt::Debug { +trait FileDescriptor: std::fmt::Debug { fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle>; - fn read<'tcx>(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result>; - fn write<'tcx>(&mut self, communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result>; - fn seek<'tcx>(&mut self, communicate_allowed: bool, offset: SeekFrom) -> InterpResult<'tcx, io::Result>; - fn close<'tcx>(self: Box, _communicate_allowed: bool) -> InterpResult<'tcx, io::Result>; + fn read<'tcx>( + &mut self, + communicate_allowed: bool, + bytes: &mut [u8], + ) -> InterpResult<'tcx, io::Result>; + fn write<'tcx>( + &mut self, + communicate_allowed: bool, + bytes: &[u8], + ) -> InterpResult<'tcx, io::Result>; + fn seek<'tcx>( + &mut self, + communicate_allowed: bool, + offset: SeekFrom, + ) -> InterpResult<'tcx, io::Result>; + fn close<'tcx>( + self: Box, + _communicate_allowed: bool, + ) -> InterpResult<'tcx, io::Result>; fn dup<'tcx>(&mut self) -> io::Result>; } @@ -39,22 +56,37 @@ impl FileDescriptor for FileHandle { Ok(&self) } - fn read<'tcx>(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + fn read<'tcx>( + &mut self, + communicate_allowed: bool, + bytes: &mut [u8], + ) -> InterpResult<'tcx, io::Result> { assert!(communicate_allowed, "isolation should have prevented even opening a file"); Ok(self.file.read(bytes)) } - fn write<'tcx>(&mut self, communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + fn write<'tcx>( + &mut self, + communicate_allowed: bool, + bytes: &[u8], + ) -> InterpResult<'tcx, io::Result> { assert!(communicate_allowed, "isolation should have prevented even opening a file"); Ok(self.file.write(bytes)) } - fn seek<'tcx>(&mut self, communicate_allowed: bool, offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + fn seek<'tcx>( + &mut self, + communicate_allowed: bool, + offset: SeekFrom, + ) -> InterpResult<'tcx, io::Result> { assert!(communicate_allowed, "isolation should have prevented even opening a file"); Ok(self.file.seek(offset)) } - fn close<'tcx>(self: Box, communicate_allowed: bool) -> InterpResult<'tcx, io::Result> { + fn close<'tcx>( + self: Box, + communicate_allowed: bool, + ) -> InterpResult<'tcx, io::Result> { assert!(communicate_allowed, "isolation should have prevented even opening a file"); // We sync the file if it was opened in a mode different than read-only. if self.writable { @@ -88,7 +120,11 @@ impl FileDescriptor for io::Stdin { throw_unsup_format!("stdin cannot be used as FileHandle"); } - fn read<'tcx>(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + fn read<'tcx>( + &mut self, + communicate_allowed: bool, + bytes: &mut [u8], + ) -> InterpResult<'tcx, io::Result> { if !communicate_allowed { // We want isolation mode to be deterministic, so we have to disallow all reads, even stdin. helpers::isolation_error("`read` from stdin")?; @@ -96,15 +132,26 @@ impl FileDescriptor for io::Stdin { Ok(Read::read(self, bytes)) } - fn write<'tcx>(&mut self, _communicate_allowed: bool, _bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + fn write<'tcx>( + &mut self, + _communicate_allowed: bool, + _bytes: &[u8], + ) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot write to stdin"); } - fn seek<'tcx>(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + fn seek<'tcx>( + &mut self, + _communicate_allowed: bool, + _offset: SeekFrom, + ) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot seek on stdin"); } - fn close<'tcx>(self: Box, _communicate_allowed: bool) -> InterpResult<'tcx, io::Result> { + fn close<'tcx>( + self: Box, + _communicate_allowed: bool, + ) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("stdin cannot be closed"); } @@ -118,11 +165,19 @@ impl FileDescriptor for io::Stdout { throw_unsup_format!("stdout cannot be used as FileHandle"); } - fn read<'tcx>(&mut self, _communicate_allowed: bool, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + fn read<'tcx>( + &mut self, + _communicate_allowed: bool, + _bytes: &mut [u8], + ) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot read from stdout"); } - fn write<'tcx>(&mut self, _communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + fn write<'tcx>( + &mut self, + _communicate_allowed: bool, + bytes: &[u8], + ) -> InterpResult<'tcx, io::Result> { // We allow writing to stderr even with isolation enabled. let result = Write::write(self, bytes); // Stdout is buffered, flush to make sure it appears on the @@ -135,11 +190,18 @@ impl FileDescriptor for io::Stdout { Ok(result) } - fn seek<'tcx>(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + fn seek<'tcx>( + &mut self, + _communicate_allowed: bool, + _offset: SeekFrom, + ) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot seek on stdout"); } - fn close<'tcx>(self: Box, _communicate_allowed: bool) -> InterpResult<'tcx, io::Result> { + fn close<'tcx>( + self: Box, + _communicate_allowed: bool, + ) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("stdout cannot be closed"); } @@ -153,21 +215,36 @@ impl FileDescriptor for io::Stderr { throw_unsup_format!("stderr cannot be used as FileHandle"); } - fn read<'tcx>(&mut self, _communicate_allowed: bool, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + fn read<'tcx>( + &mut self, + _communicate_allowed: bool, + _bytes: &mut [u8], + ) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot read from stderr"); } - fn write<'tcx>(&mut self, _communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + fn write<'tcx>( + &mut self, + _communicate_allowed: bool, + bytes: &[u8], + ) -> InterpResult<'tcx, io::Result> { // We allow writing to stderr even with isolation enabled. // No need to flush, stderr is not buffered. Ok(Write::write(self, bytes)) } - fn seek<'tcx>(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + fn seek<'tcx>( + &mut self, + _communicate_allowed: bool, + _offset: SeekFrom, + ) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot seek on stderr"); } - fn close<'tcx>(self: Box, _communicate_allowed: bool) -> InterpResult<'tcx, io::Result> { + fn close<'tcx>( + self: Box, + _communicate_allowed: bool, + ) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("stderr cannot be closed"); } @@ -187,9 +264,7 @@ impl<'tcx> Default for FileHandler { handles.insert(0i32, Box::new(io::stdin())); handles.insert(1i32, Box::new(io::stdout())); handles.insert(2i32, Box::new(io::stderr())); - FileHandler { - handles - } + FileHandler { handles } } } @@ -203,11 +278,8 @@ impl<'tcx> FileHandler { // between used FDs, the find_map combinator will return it. If the first such unused FD // is after all other used FDs, the find_map combinator will return None, and we will use // the FD following the greatest FD thus far. - let candidate_new_fd = self - .handles - .range(min_fd..) - .zip(min_fd..) - .find_map(|((fd, _fh), counter)| { + let candidate_new_fd = + self.handles.range(min_fd..).zip(min_fd..).find_map(|((fd, _fh), counter)| { if *fd != counter { // There was a gap in the fds stored, return the first unused one // (note that this relies on BTreeMap iterating in key order) @@ -220,7 +292,10 @@ impl<'tcx> FileHandler { let new_fd = candidate_new_fd.unwrap_or_else(|| { // find_map ran out of BTreeMap entries before finding a free fd, use one plus the // maximum fd in the map - self.handles.last_key_value().map(|(fd, _)| fd.checked_add(1).unwrap()).unwrap_or(min_fd) + self.handles + .last_key_value() + .map(|(fd, _)| fd.checked_add(1).unwrap()) + .unwrap_or(min_fd) }); self.handles.try_insert(new_fd, file_handle).unwrap(); @@ -292,7 +367,7 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' immty_from_uint_checked(modified_sec, time_t_layout)?, // st_mtime immty_from_uint_checked(modified_nsec, long_layout)?, // st_mtime_nsec immty_from_uint_checked(0u128, time_t_layout)?, // st_ctime - immty_from_uint_checked(0u128, long_layout)?, // st_ctime_nsec + immty_from_uint_checked(0u128, long_layout)?, // st_ctime_nsec immty_from_uint_checked(created_sec, time_t_layout)?, // st_birthtime immty_from_uint_checked(created_nsec, long_layout)?, // st_birthtime_nsec immty_from_uint_checked(metadata.size, off_t_layout)?, // st_size @@ -319,7 +394,10 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' Ok((-1).into()) } - fn file_type_to_d_type(&mut self, file_type: std::io::Result) -> InterpResult<'tcx, i32> { + fn file_type_to_d_type( + &mut self, + file_type: std::io::Result, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); match file_type { Ok(file_type) => { @@ -353,10 +431,14 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' Ok(this.eval_libc("DT_UNKNOWN")?.to_u8()?.into()) } } - Err(e) => return match e.raw_os_error() { - Some(error) => Ok(error), - None => throw_unsup_format!("the error {} couldn't be converted to a return value", e), - } + Err(e) => + return match e.raw_os_error() { + Some(error) => Ok(error), + None => throw_unsup_format!( + "the error {} couldn't be converted to a return value", + e + ), + }, } } } @@ -396,7 +478,11 @@ impl Default for DirHandler { } } -fn maybe_sync_file(file: &File, writable: bool, operation: fn(&File) -> std::io::Result<()>) -> std::io::Result { +fn maybe_sync_file( + file: &File, + writable: bool, + operation: fn(&File) -> std::io::Result<()>, +) -> std::io::Result { if !writable && cfg!(windows) { // sync_all() and sync_data() will return an error on Windows hosts if the file is not opened // for writing. (FlushFileBuffers requires that the file handle have the @@ -505,16 +591,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.try_unwrap_io_result(fd) } - fn fcntl( - &mut self, - args: &[OpTy<'tcx, Tag>], - ) -> InterpResult<'tcx, i32> { + fn fcntl(&mut self, args: &[OpTy<'tcx, Tag>]) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.check_no_isolation("`fcntl`")?; if args.len() < 2 { - throw_ub_format!("incorrect number of arguments for fcntl: got {}, expected at least 2", args.len()); + throw_ub_format!( + "incorrect number of arguments for fcntl: got {}, expected at least 2", + args.len() + ); } let fd = this.read_scalar(&args[0])?.to_i32()?; let cmd = this.read_scalar(&args[1])?.to_i32()?; @@ -552,12 +638,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(-1) } } - }, + } None => return this.handle_not_found(), } - } else if this.tcx.sess.target.os == "macos" - && cmd == this.eval_libc_i32("F_FULLFSYNC")? - { + } else if this.tcx.sess.target.os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC")? { let &[_, _] = check_arg_count(args)?; if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support fullfsync for all FDs @@ -585,12 +669,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn read( - &mut self, - fd: i32, - buf: Scalar, - count: u64, - ) -> InterpResult<'tcx, i64> { + fn read(&mut self, fd: i32, buf: Scalar, count: u64) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); // Isolation check is done via `FileDescriptor` trait. @@ -637,12 +716,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn write( - &mut self, - fd: i32, - buf: Scalar, - count: u64, - ) -> InterpResult<'tcx, i64> { + fn write(&mut self, fd: i32, buf: Scalar, count: u64) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); // Isolation check is done via `FileDescriptor` trait. @@ -719,7 +793,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn symlink( &mut self, target_op: &OpTy<'tcx, Tag>, - linkpath_op: &OpTy<'tcx, Tag> + linkpath_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { #[cfg(unix)] fn create_link(src: &Path, dst: &Path) -> std::io::Result<()> { @@ -729,11 +803,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[cfg(windows)] fn create_link(src: &Path, dst: &Path) -> std::io::Result<()> { use std::os::windows::fs; - if src.is_dir() { - fs::symlink_dir(src, dst) - } else { - fs::symlink_file(src, dst) - } + if src.is_dir() { fs::symlink_dir(src, dst) } else { fs::symlink_file(src, dst) } } let this = self.eval_context_mut(); @@ -842,11 +912,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // set. // Other behaviors cannot be tested from `libstd` and thus are not implemented. If you // found this error, please open an issue reporting it. - if !( - path.is_absolute() || - dirfd == this.eval_libc_i32("AT_FDCWD")? || - (path.as_os_str().is_empty() && empty_path_flag) - ) { + if !(path.is_absolute() + || dirfd == this.eval_libc_i32("AT_FDCWD")? + || (path.as_os_str().is_empty() && empty_path_flag)) + { throw_unsup_format!( "using statx is only supported with absolute paths, relative paths with the file \ descriptor `AT_FDCWD`, and empty paths with the `AT_EMPTY_PATH` flag set and any \ @@ -889,20 +958,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We need to set the corresponding bits of `mask` if the access, creation and modification // times were available. Otherwise we let them be zero. - let (access_sec, access_nsec) = metadata.accessed.map(|tup| { - mask |= this.eval_libc("STATX_ATIME")?.to_u32()?; - InterpResult::Ok(tup) - }).unwrap_or(Ok((0, 0)))?; + let (access_sec, access_nsec) = metadata + .accessed + .map(|tup| { + mask |= this.eval_libc("STATX_ATIME")?.to_u32()?; + InterpResult::Ok(tup) + }) + .unwrap_or(Ok((0, 0)))?; - let (created_sec, created_nsec) = metadata.created.map(|tup| { - mask |= this.eval_libc("STATX_BTIME")?.to_u32()?; - InterpResult::Ok(tup) - }).unwrap_or(Ok((0, 0)))?; + let (created_sec, created_nsec) = metadata + .created + .map(|tup| { + mask |= this.eval_libc("STATX_BTIME")?.to_u32()?; + InterpResult::Ok(tup) + }) + .unwrap_or(Ok((0, 0)))?; - let (modified_sec, modified_nsec) = metadata.modified.map(|tup| { - mask |= this.eval_libc("STATX_MTIME")?.to_u32()?; - InterpResult::Ok(tup) - }).unwrap_or(Ok((0, 0)))?; + let (modified_sec, modified_nsec) = metadata + .modified + .map(|tup| { + mask |= this.eval_libc("STATX_MTIME")?.to_u32()?; + InterpResult::Ok(tup) + }) + .unwrap_or(Ok((0, 0)))?; let __u32_layout = this.libc_ty_layout("__u32")?; let __u64_layout = this.libc_ty_layout("__u64")?; @@ -1006,10 +1084,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.try_unwrap_io_result(result) } - fn rmdir( - &mut self, - path_op: &OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, i32> { + fn rmdir(&mut self, path_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.check_no_isolation("`rmdir`")?; @@ -1087,7 +1162,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name_place.layout.size.bytes(), )?; if !name_fits { - throw_unsup_format!("a directory entry had a name too large to fit in libc::dirent64"); + throw_unsup_format!( + "a directory entry had a name too large to fit in libc::dirent64" + ); } let entry_place = this.deref_operand(entry_op)?; @@ -1175,7 +1252,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name_place.layout.size.bytes(), )?; if !name_fits { - throw_unsup_format!("a directory entry had a name too large to fit in libc::dirent"); + throw_unsup_format!( + "a directory entry had a name too large to fit in libc::dirent" + ); } let entry_place = this.deref_operand(entry_op)?; @@ -1194,8 +1273,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let file_type = this.file_type_to_d_type(dir_entry.file_type())?; let imms = [ - immty_from_uint_checked(ino, ino_t_layout)?, // d_ino - immty_from_uint_checked(0u128, off_t_layout)?, // d_seekoff + immty_from_uint_checked(ino, ino_t_layout)?, // d_ino + immty_from_uint_checked(0u128, off_t_layout)?, // d_seekoff immty_from_uint_checked(0u128, c_ushort_layout)?, // d_reclen immty_from_uint_checked(file_name_len, c_ushort_layout)?, // d_namlen immty_from_int_checked(file_type, c_uchar_layout)?, // d_type @@ -1352,7 +1431,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, pathname_op: &OpTy<'tcx, Tag>, buf_op: &OpTy<'tcx, Tag>, - bufsize_op: &OpTy<'tcx, Tag> + bufsize_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); @@ -1365,7 +1444,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = std::fs::read_link(pathname); match result { Ok(resolved) => { - let resolved = this.convert_path_separator(Cow::Borrowed(resolved.as_ref()), crate::shims::os_str::PathConversion::HostToTarget); + let resolved = this.convert_path_separator( + Cow::Borrowed(resolved.as_ref()), + crate::shims::os_str::PathConversion::HostToTarget, + ); let mut path_bytes = crate::shims::os_str::os_str_to_bytes(resolved.as_ref())?; let bufsize: usize = bufsize.try_into().unwrap(); if path_bytes.len() > bufsize { @@ -1388,12 +1470,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// `time` is Ok. Returns `None` if `time` is an error. Fails if `time` happens before the unix /// epoch. fn extract_sec_and_nsec<'tcx>( - time: std::io::Result + time: std::io::Result, ) -> InterpResult<'tcx, Option<(u64, u32)>> { - time.ok().map(|time| { - let duration = system_time_to_duration(&time)?; - Ok((duration.as_secs(), duration.subsec_nanos())) - }).transpose() + time.ok() + .map(|time| { + let duration = system_time_to_duration(&time)?; + Ok((duration.as_secs(), duration.subsec_nanos())) + }) + .transpose() } /// Stores a file's metadata in order to avoid code duplication in the different metadata related @@ -1410,13 +1494,10 @@ impl FileMetadata { fn from_path<'tcx, 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, path: &Path, - follow_symlink: bool + follow_symlink: bool, ) -> InterpResult<'tcx, Option> { - let metadata = if follow_symlink { - std::fs::metadata(path) - } else { - std::fs::symlink_metadata(path) - }; + let metadata = + if follow_symlink { std::fs::metadata(path) } else { std::fs::symlink_metadata(path) }; FileMetadata::from_meta(ecx, metadata) } diff --git a/src/shims/posix/linux/dlsym.rs b/src/shims/posix/linux/dlsym.rs index e7ffb68ff2ec..1b7ac2754af7 100644 --- a/src/shims/posix/linux/dlsym.rs +++ b/src/shims/posix/linux/dlsym.rs @@ -3,8 +3,7 @@ use rustc_middle::mir; use crate::*; #[derive(Debug, Copy, Clone)] -pub enum Dlsym { -} +pub enum Dlsym {} impl Dlsym { // Returns an error for unsupported symbols, and None if this symbol @@ -13,7 +12,7 @@ impl Dlsym { Ok(match &*name { "__pthread_get_minstack" => None, "getrandom" => None, // std falls back to syscall(SYS_getrandom, ...) when this is NULL. - "statx" => None, // std falls back to syscall(SYS_statx, ...) when this is NULL. + "statx" => None, // std falls back to syscall(SYS_statx, ...) when this is NULL. _ => throw_unsup_format!("unsupported Linux dlsym: {}", name), }) } diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index fe989b5924df..f7d7706e3f5e 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -1,8 +1,8 @@ use rustc_middle::mir; use rustc_target::spec::abi::Abi; -use crate::*; use crate::helpers::{check_abi, check_arg_count}; +use crate::*; use shims::posix::fs::EvalContextExt as _; use shims::posix::linux::sync::futex; use shims::posix::sync::EvalContextExt as _; @@ -133,24 +133,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // other types might be treated differently by the calling convention. for arg in args { if !matches!(arg.layout.abi, rustc_target::abi::Abi::Scalar(_)) { - throw_ub_format!("`syscall` arguments must all have scalar layout, but {} does not", arg.layout.ty); + throw_ub_format!( + "`syscall` arguments must all have scalar layout, but {} does not", + arg.layout.ty + ); } } - let sys_getrandom = this - .eval_libc("SYS_getrandom")? - .to_machine_usize(this)?; + let sys_getrandom = this.eval_libc("SYS_getrandom")?.to_machine_usize(this)?; - let sys_statx = this - .eval_libc("SYS_statx")? - .to_machine_usize(this)?; + let sys_statx = this.eval_libc("SYS_statx")?.to_machine_usize(this)?; - let sys_futex = this - .eval_libc("SYS_futex")? - .to_machine_usize(this)?; + let sys_futex = this.eval_libc("SYS_futex")?.to_machine_usize(this)?; if args.is_empty() { - throw_ub_format!("incorrect number of arguments for syscall: got 0, expected at least 1"); + throw_ub_format!( + "incorrect number of arguments for syscall: got 0, expected at least 1" + ); } match this.read_scalar(&args[0])?.to_machine_usize(this)? { // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` @@ -158,7 +157,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx id if id == sys_getrandom => { // The first argument is the syscall id, so skip over it. if args.len() < 4 { - throw_ub_format!("incorrect number of arguments for `getrandom` syscall: got {}, expected at least 4", args.len()); + throw_ub_format!( + "incorrect number of arguments for `getrandom` syscall: got {}, expected at least 4", + args.len() + ); } getrandom(this, &args[1], &args[2], &args[3], dest)?; } @@ -167,9 +169,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx id if id == sys_statx => { // The first argument is the syscall id, so skip over it. if args.len() < 6 { - throw_ub_format!("incorrect number of arguments for `statx` syscall: got {}, expected at least 6", args.len()); + throw_ub_format!( + "incorrect number of arguments for `statx` syscall: got {}, expected at least 6", + args.len() + ); } - let result = this.linux_statx(&args[1], &args[2], &args[3], &args[4], &args[5])?; + let result = + this.linux_statx(&args[1], &args[2], &args[3], &args[4], &args[5])?; this.write_scalar(Scalar::from_machine_isize(result.into(), this), dest)?; } // `futex` is used by some synchonization primitives. @@ -200,7 +206,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. - "pthread_getattr_np" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + "pthread_getattr_np" + if this.frame().instance.to_string().starts_with("std::sys::unix::") => + { check_abi(abi, Abi::C { unwind: false })?; let &[ref _thread, ref _attr] = check_arg_count(args)?; this.write_null(dest)?; diff --git a/src/shims/posix/linux/mod.rs b/src/shims/posix/linux/mod.rs index eba4a517cf5d..498eb57c57fe 100644 --- a/src/shims/posix/linux/mod.rs +++ b/src/shims/posix/linux/mod.rs @@ -1,3 +1,3 @@ -pub mod foreign_items; pub mod dlsym; +pub mod foreign_items; pub mod sync; diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index fdd11fd73e40..c5101203eb46 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -18,7 +18,10 @@ pub fn futex<'tcx>( // Therefore we don't use `check_arg_count` here, but only check for the // number of arguments to fall within a range. if args.len() < 4 { - throw_ub_format!("incorrect number of arguments for `futex` syscall: got {}, expected at least 4", args.len()); + throw_ub_format!( + "incorrect number of arguments for `futex` syscall: got {}, expected at least 4", + args.len() + ); } // The first three arguments (after the syscall number itself) are the same to all futex operations: @@ -49,13 +52,18 @@ pub fn futex<'tcx>( // or *timeout expires. `timeout == null` for an infinite timeout. op if op & !futex_realtime == futex_wait => { if args.len() < 5 { - throw_ub_format!("incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT`: got {}, expected at least 5", args.len()); + throw_ub_format!( + "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT`: got {}, expected at least 5", + args.len() + ); } let timeout = &args[4]; let timeout_time = if this.is_null(this.read_scalar(timeout)?.check_init()?)? { None } else { - this.check_no_isolation("`futex` syscall with `op=FUTEX_WAIT` and non-null timeout")?; + this.check_no_isolation( + "`futex` syscall with `op=FUTEX_WAIT` and non-null timeout", + )?; let duration = match this.read_timespec(timeout)? { Some(duration) => duration, None => { @@ -74,7 +82,11 @@ pub fn futex<'tcx>( // Check the pointer for alignment and validity. // The API requires `addr` to be a 4-byte aligned pointer, and will // use the 4 bytes at the given address as an (atomic) i32. - this.memory.check_ptr_access(addr.to_scalar()?, Size::from_bytes(4), Align::from_bytes(4).unwrap())?; + this.memory.check_ptr_access( + addr.to_scalar()?, + Size::from_bytes(4), + Align::from_bytes(4).unwrap(), + )?; // Read an `i32` through the pointer, regardless of any wrapper types. // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`. // FIXME: this fails if `addr` is not a pointer type. @@ -87,9 +99,14 @@ pub fn futex<'tcx>( // operations on the same futex word." // SeqCst is total order over all operations. // FIXME: check if this should be changed when weak memory orders are added. - let futex_val = this.read_scalar_at_offset_atomic( - &addr.into(), 0, this.machine.layouts.i32, AtomicReadOp::SeqCst - )?.to_i32()?; + let futex_val = this + .read_scalar_at_offset_atomic( + &addr.into(), + 0, + this.machine.layouts.i32, + AtomicReadOp::SeqCst, + )? + .to_i32()?; if val == futex_val { // The value still matches, so we block the trait make it wait for FUTEX_WAKE. this.block_thread(thread); diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index dce9eea668e6..9a7d3be1eb9a 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -97,7 +97,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[ref info] = check_arg_count(args)?; let result = this.mach_timebase_info(info)?; this.write_scalar(Scalar::from_i32(result), dest)?; - }, + } // Access to command-line arguments "_NSGetArgc" => { @@ -162,4 +162,3 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(true) } } - diff --git a/src/shims/posix/macos/mod.rs b/src/shims/posix/macos/mod.rs index cadd6a8ea384..434f5f30b5a5 100644 --- a/src/shims/posix/macos/mod.rs +++ b/src/shims/posix/macos/mod.rs @@ -1,2 +1,2 @@ -pub mod foreign_items; pub mod dlsym; +pub mod foreign_items; diff --git a/src/shims/posix/mod.rs b/src/shims/posix/mod.rs index 9916c65be0fb..f40dfaefb92a 100644 --- a/src/shims/posix/mod.rs +++ b/src/shims/posix/mod.rs @@ -1,5 +1,5 @@ -pub mod foreign_items; pub mod dlsym; +pub mod foreign_items; mod fs; mod sync; diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 0688614a383d..3b68e4eee440 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -63,8 +63,10 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>( ) -> InterpResult<'tcx, ScalarMaybeUninit> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; ecx.read_scalar_at_offset_atomic( - mutex_op, offset, ecx.machine.layouts.i32, - AtomicReadOp::Relaxed + mutex_op, + offset, + ecx.machine.layouts.i32, + AtomicReadOp::Relaxed, ) } @@ -75,8 +77,11 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( ) -> InterpResult<'tcx, ()> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; ecx.write_scalar_at_offset_atomic( - mutex_op, offset, kind, ecx.machine.layouts.i32, - AtomicWriteOp::Relaxed + mutex_op, + offset, + kind, + ecx.machine.layouts.i32, + AtomicWriteOp::Relaxed, ) } @@ -84,10 +89,7 @@ fn mutex_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - ecx.read_scalar_at_offset_atomic( - mutex_op, 4, ecx.machine.layouts.u32, - AtomicReadOp::Relaxed - ) + ecx.read_scalar_at_offset_atomic(mutex_op, 4, ecx.machine.layouts.u32, AtomicReadOp::Relaxed) } fn mutex_set_id<'mir, 'tcx: 'mir>( @@ -96,8 +98,11 @@ fn mutex_set_id<'mir, 'tcx: 'mir>( id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset_atomic( - mutex_op, 4, id, ecx.machine.layouts.u32, - AtomicWriteOp::Relaxed + mutex_op, + 4, + id, + ecx.machine.layouts.u32, + AtomicWriteOp::Relaxed, ) } @@ -128,10 +133,7 @@ fn rwlock_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - ecx.read_scalar_at_offset_atomic( - rwlock_op, 4, ecx.machine.layouts.u32, - AtomicReadOp::Relaxed - ) + ecx.read_scalar_at_offset_atomic(rwlock_op, 4, ecx.machine.layouts.u32, AtomicReadOp::Relaxed) } fn rwlock_set_id<'mir, 'tcx: 'mir>( @@ -140,8 +142,11 @@ fn rwlock_set_id<'mir, 'tcx: 'mir>( id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset_atomic( - rwlock_op, 4, id, ecx.machine.layouts.u32, - AtomicWriteOp::Relaxed + rwlock_op, + 4, + id, + ecx.machine.layouts.u32, + AtomicWriteOp::Relaxed, ) } @@ -195,10 +200,7 @@ fn cond_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, cond_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - ecx.read_scalar_at_offset_atomic( - cond_op, 4, ecx.machine.layouts.u32, - AtomicReadOp::Relaxed - ) + ecx.read_scalar_at_offset_atomic(cond_op, 4, ecx.machine.layouts.u32, AtomicReadOp::Relaxed) } fn cond_set_id<'mir, 'tcx: 'mir>( @@ -207,8 +209,11 @@ fn cond_set_id<'mir, 'tcx: 'mir>( id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset_atomic( - cond_op, 4, id, ecx.machine.layouts.u32, - AtomicWriteOp::Relaxed + cond_op, + 4, + id, + ecx.machine.layouts.u32, + AtomicWriteOp::Relaxed, ) } diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index fb1c018fc34b..214a2ce411d6 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -16,7 +16,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.tcx.sess.warn( - "thread support is experimental and incomplete: weak memory effects are not emulated." + "thread support is experimental and incomplete: weak memory effects are not emulated.", ); // Create the new thread @@ -31,7 +31,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; // Read the function argument that will be sent to the new thread - // before the thread starts executing since reading after the + // before the thread starts executing since reading after the // context switch will incorrectly report a data-race. let fn_ptr = this.read_scalar(start_routine)?.check_init()?; let func_arg = this.read_immediate(arg)?; @@ -130,10 +130,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_setname_np( - &mut self, - name: Scalar, - ) -> InterpResult<'tcx> { + fn pthread_setname_np(&mut self, name: Scalar) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.assert_target_os("macos", "pthread_setname_np"); diff --git a/src/shims/time.rs b/src/shims/time.rs index 5af2e5ab67e7..d293e4d12774 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -1,5 +1,5 @@ -use std::time::{Duration, SystemTime, Instant}; use std::convert::TryFrom; +use std::time::{Duration, Instant, SystemTime}; use crate::stacked_borrows::Tag; use crate::*; @@ -99,7 +99,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let NANOS_PER_INTERVAL = NANOS_PER_SEC / INTERVALS_PER_SEC; let SECONDS_TO_UNIX_EPOCH = INTERVALS_TO_UNIX_EPOCH / INTERVALS_PER_SEC; - let duration = system_time_to_duration(&SystemTime::now())? + Duration::from_secs(SECONDS_TO_UNIX_EPOCH); + let duration = system_time_to_duration(&SystemTime::now())? + + Duration::from_secs(SECONDS_TO_UNIX_EPOCH); let duration_ticks = u64::try_from(duration.as_nanos() / u128::from(NANOS_PER_INTERVAL)) .map_err(|_| err_unsup_format!("programs running more than 2^64 Windows ticks after the Windows epoch are not supported"))?; @@ -115,7 +116,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn QueryPerformanceCounter(&mut self, lpPerformanceCount_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn QueryPerformanceCounter( + &mut self, + lpPerformanceCount_op: &OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("windows", "QueryPerformanceCounter"); @@ -124,14 +128,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // QueryPerformanceCounter uses a hardware counter as its basis. // Miri will emulate a counter with a resolution of 1 nanosecond. let duration = Instant::now().duration_since(this.machine.time_anchor); - let qpc = i64::try_from(duration.as_nanos()) - .map_err(|_| err_unsup_format!("programs running longer than 2^63 nanoseconds are not supported"))?; - this.write_scalar(Scalar::from_i64(qpc), &this.deref_operand(lpPerformanceCount_op)?.into())?; + let qpc = i64::try_from(duration.as_nanos()).map_err(|_| { + err_unsup_format!("programs running longer than 2^63 nanoseconds are not supported") + })?; + this.write_scalar( + Scalar::from_i64(qpc), + &this.deref_operand(lpPerformanceCount_op)?.into(), + )?; Ok(-1) // return non-zero on success } #[allow(non_snake_case)] - fn QueryPerformanceFrequency(&mut self, lpFrequency_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn QueryPerformanceFrequency( + &mut self, + lpFrequency_op: &OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("windows", "QueryPerformanceFrequency"); @@ -142,7 +153,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // is consistent across all processors. // Miri emulates a "hardware" performance counter with a resolution of 1ns, // and thus 10^9 counts per second. - this.write_scalar(Scalar::from_i64(1_000_000_000), &this.deref_operand(lpFrequency_op)?.into())?; + this.write_scalar( + Scalar::from_i64(1_000_000_000), + &this.deref_operand(lpFrequency_op)?.into(), + )?; Ok(-1) // Return non-zero on success } @@ -155,8 +169,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This returns a u64, with time units determined dynamically by `mach_timebase_info`. // We return plain nanoseconds. let duration = Instant::now().duration_since(this.machine.time_anchor); - u64::try_from(duration.as_nanos()) - .map_err(|_| err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported").into()) + u64::try_from(duration.as_nanos()).map_err(|_| { + err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported") + .into() + }) } fn mach_timebase_info(&mut self, info_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { @@ -169,10 +185,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Since our emulated ticks in `mach_absolute_time` *are* nanoseconds, // no scaling needs to happen. - let (numer, denom) = (1,1); + let (numer, denom) = (1, 1); let imms = [ immty_from_int_checked(numer, this.machine.layouts.u32)?, - immty_from_int_checked(denom, this.machine.layouts.u32)? + immty_from_int_checked(denom, this.machine.layouts.u32)?, ]; this.write_packed_immediates(&info, &imms)?; diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 3339e3bee199..239364508e08 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -1,14 +1,14 @@ //! Implement thread-local storage. -use std::collections::BTreeMap; use std::collections::btree_map::Entry as BTreeEntry; use std::collections::hash_map::Entry as HashMapEntry; +use std::collections::BTreeMap; use log::trace; use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty; -use rustc_target::abi::{Size, HasDataLayout}; +use rustc_target::abi::{HasDataLayout, Size}; use rustc_target::spec::abi::Abi; use crate::*; @@ -63,7 +63,11 @@ impl<'tcx> Default for TlsData<'tcx> { impl<'tcx> TlsData<'tcx> { /// Generate a new TLS key with the given destructor. /// `max_size` determines the integer size the key has to fit in. - pub fn create_tls_key(&mut self, dtor: Option>, max_size: Size) -> InterpResult<'tcx, TlsKey> { + pub fn create_tls_key( + &mut self, + dtor: Option>, + max_size: Size, + ) -> InterpResult<'tcx, TlsKey> { let new_key = self.next_key; self.next_key += 1; self.keys.try_insert(new_key, TlsEntry { data: Default::default(), dtor }).unwrap(); @@ -105,7 +109,7 @@ impl<'tcx> TlsData<'tcx> { &mut self, key: TlsKey, thread_id: ThreadId, - new_data: Option> + new_data: Option>, ) -> InterpResult<'tcx> { match self.keys.get_mut(&key) { Some(TlsEntry { data, .. }) => { @@ -138,14 +142,18 @@ impl<'tcx> TlsData<'tcx> { &mut self, thread: ThreadId, dtor: ty::Instance<'tcx>, - data: Scalar + data: Scalar, ) -> InterpResult<'tcx> { if self.dtors_running.contains_key(&thread) { // UB, according to libstd docs. - throw_ub_format!("setting thread's local storage destructor while destructors are already running"); + throw_ub_format!( + "setting thread's local storage destructor while destructors are already running" + ); } if self.macos_thread_dtors.insert(thread, (dtor, data)).is_some() { - throw_unsup_format!("setting more than one thread local storage destructor for the same thread is not supported"); + throw_unsup_format!( + "setting more than one thread local storage destructor for the same thread is not supported" + ); } Ok(()) } @@ -181,9 +189,7 @@ impl<'tcx> TlsData<'tcx> { Some(key) => Excluded(key), None => Unbounded, }; - for (&key, TlsEntry { data, dtor }) in - thread_local.range_mut((start, Unbounded)) - { + for (&key, TlsEntry { data, dtor }) in thread_local.range_mut((start, Unbounded)) { match data.entry(thread_id) { BTreeEntry::Occupied(entry) => { if let Some(dtor) = dtor { @@ -237,7 +243,13 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'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. - let thread_callback = this.eval_path_scalar(&["std", "sys", "windows", "thread_local_key", "p_thread_callback"])?; + let thread_callback = this.eval_path_scalar(&[ + "std", + "sys", + "windows", + "thread_local_key", + "p_thread_callback", + ])?; let thread_callback = this.memory.get_fn(thread_callback.check_init()?)?.as_instance()?; // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. @@ -297,12 +309,11 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dtor = match this.machine.tls.fetch_tls_dtor(last_key, active_thread) { dtor @ Some(_) => dtor, // We ran each dtor once, start over from the beginning. - None => { - this.machine.tls.fetch_tls_dtor(None, active_thread) - } + None => this.machine.tls.fetch_tls_dtor(None, active_thread), }; if let Some((instance, ptr, key)) = dtor { - this.machine.tls.dtors_running.get_mut(&active_thread).unwrap().last_dtor_key = Some(key); + this.machine.tls.dtors_running.get_mut(&active_thread).unwrap().last_dtor_key = + Some(key); trace!("Running TLS dtor {:?} on {:?} at {:?}", instance, ptr, active_thread); assert!(!this.is_null(ptr).unwrap(), "data can't be NULL when dtor is called!"); @@ -326,7 +337,6 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// Schedule an active thread's TLS destructor to run on the active thread. /// Note that this function does not run the destructors itself, it just /// schedules them one by one each time it is called and reenables the @@ -349,7 +359,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // relevant function, reenabling the thread, and going back to // the scheduler. this.schedule_windows_tls_dtors()?; - return Ok(()) + return Ok(()); } } // The remaining dtors make some progress each time around the scheduler loop, @@ -361,12 +371,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We have scheduled a MacOS dtor to run on the thread. Execute it // to completion and come back here. Scheduling a destructor // destroys it, so we will not enter this branch again. - return Ok(()) + return Ok(()); } if this.schedule_next_pthread_tls_dtor()? { // We have scheduled a pthread destructor and removed it from the // destructors list. Run it to completion and come back here. - return Ok(()) + return Ok(()); } // All dtors done! diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 704b8872a4b0..ace6c4674ae9 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -5,8 +5,7 @@ use crate::*; use helpers::check_abi; #[derive(Debug, Copy, Clone)] -pub enum Dlsym { -} +pub enum Dlsym {} impl Dlsym { // Returns an error for unsupported symbols, and None if this symbol diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 47f9544066bc..655f6b08c2c3 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -75,7 +75,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "WriteFile" => { check_abi(abi, Abi::System { unwind: false })?; - let &[ref handle, ref buf, ref n, ref written_ptr, ref overlapped] = check_arg_count(args)?; + let &[ref handle, ref buf, ref n, ref written_ptr, ref overlapped] = + check_arg_count(args)?; this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore let handle = this.read_scalar(handle)?.to_machine_isize(this)?; let buf = this.read_scalar(buf)?.check_init()?; @@ -95,17 +96,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; res.ok().map(|n| n as u32) } else { - throw_unsup_format!("on Windows, writing to anything except stdout/stderr is not supported") + throw_unsup_format!( + "on Windows, writing to anything except stdout/stderr is not supported" + ) }; // If there was no error, write back how much was written. if let Some(n) = written { this.write_scalar(Scalar::from_u32(n), &written_place.into())?; } // Return whether this was a success. - this.write_scalar( - Scalar::from_i32(if written.is_some() { 1 } else { 0 }), - dest, - )?; + this.write_scalar(Scalar::from_i32(if written.is_some() { 1 } else { 0 }), dest)?; } // Allocation @@ -297,11 +297,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_u32()?; let flags = this.read_scalar(flags)?.to_u32()?; - if flags != 2 { // BCRYPT_USE_SYSTEM_PREFERRED_RNG - throw_unsup_format!("BCryptGenRandom is supported only with the BCRYPT_USE_SYSTEM_PREFERRED_RNG flag"); + if flags != 2 { + // BCRYPT_USE_SYSTEM_PREFERRED_RNG + throw_unsup_format!( + "BCryptGenRandom is supported only with the BCRYPT_USE_SYSTEM_PREFERRED_RNG flag" + ); } if algorithm.to_machine_usize(this)? != 0 { - throw_unsup_format!("BCryptGenRandom algorithm must be NULL when the flag is BCRYPT_USE_SYSTEM_PREFERRED_RNG"); + throw_unsup_format!( + "BCryptGenRandom algorithm must be NULL when the flag is BCRYPT_USE_SYSTEM_PREFERRED_RNG" + ); } this.gen_random(ptr, len.into())?; this.write_null(dest)?; // STATUS_SUCCESS @@ -342,27 +347,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. - "GetProcessHeap" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + "GetProcessHeap" + if this.frame().instance.to_string().starts_with("std::sys::windows::") => + { check_abi(abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; // Just fake a HANDLE this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } - "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + "SetConsoleTextAttribute" + if this.frame().instance.to_string().starts_with("std::sys::windows::") => + { check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _hConsoleOutput, ref _wAttribute] = check_arg_count(args)?; // Pretend these does not exist / nothing happened, by returning zero. this.write_null(dest)?; } - "AddVectoredExceptionHandler" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + "AddVectoredExceptionHandler" + if this.frame().instance.to_string().starts_with("std::sys::windows::") => + { check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _First, ref _Handler] = check_arg_count(args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_machine_usize(1, this), dest)?; } - "SetThreadStackGuarantee" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + "SetThreadStackGuarantee" + if this.frame().instance.to_string().starts_with("std::sys::windows::") => + { check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[_StackSizeInBytes] = check_arg_count(args)?; @@ -373,21 +386,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "EnterCriticalSection" | "LeaveCriticalSection" | "DeleteCriticalSection" - if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + if this.frame().instance.to_string().starts_with("std::sys::windows::") => + { check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _lpCriticalSection] = check_arg_count(args)?; - assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); + assert_eq!( + this.get_total_thread_count(), + 1, + "concurrency on Windows is not supported" + ); // Nothing to do, not even a return value. // (Windows locks are reentrant, and we have only 1 thread, // so not doing any futher checks here is at least not incorrect.) } "TryEnterCriticalSection" - if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + if this.frame().instance.to_string().starts_with("std::sys::windows::") => + { check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _lpCriticalSection] = check_arg_count(args)?; - assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); + assert_eq!( + this.get_total_thread_count(), + 1, + "concurrency on Windows is not supported" + ); // There is only one thread, so this always succeeds and returns TRUE. this.write_scalar(Scalar::from_i32(1), dest)?; } @@ -398,4 +421,3 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(true) } } - diff --git a/src/shims/windows/mod.rs b/src/shims/windows/mod.rs index 04f9ace8e799..668d69966bc4 100644 --- a/src/shims/windows/mod.rs +++ b/src/shims/windows/mod.rs @@ -1,4 +1,4 @@ -pub mod foreign_items; pub mod dlsym; +pub mod foreign_items; mod sync; diff --git a/src/shims/windows/sync.rs b/src/shims/windows/sync.rs index caf8942afd93..78458dc6c997 100644 --- a/src/shims/windows/sync.rs +++ b/src/shims/windows/sync.rs @@ -22,10 +22,7 @@ fn srwlock_get_or_create_id<'mir, 'tcx: 'mir>( impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { #[allow(non_snake_case)] - fn AcquireSRWLockExclusive( - &mut self, - lock_op: &OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { + fn AcquireSRWLockExclusive(&mut self, lock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; let active_thread = this.get_active_thread(); @@ -47,10 +44,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn TryAcquireSRWLockExclusive( - &mut self, - lock_op: &OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, u8> { + fn TryAcquireSRWLockExclusive(&mut self, lock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, u8> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; let active_thread = this.get_active_thread(); @@ -65,27 +59,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn ReleaseSRWLockExclusive( - &mut self, - lock_op: &OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { + fn ReleaseSRWLockExclusive(&mut self, lock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; let active_thread = this.get_active_thread(); if !this.rwlock_writer_unlock(id, active_thread) { // The docs do not say anything about this case, but it seems better to not allow it. - throw_ub_format!("calling ReleaseSRWLockExclusive on an SRWLock that is not exclusively locked by the current thread"); + throw_ub_format!( + "calling ReleaseSRWLockExclusive on an SRWLock that is not exclusively locked by the current thread" + ); } Ok(()) } #[allow(non_snake_case)] - fn AcquireSRWLockShared( - &mut self, - lock_op: &OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { + fn AcquireSRWLockShared(&mut self, lock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; let active_thread = this.get_active_thread(); @@ -100,10 +90,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn TryAcquireSRWLockShared( - &mut self, - lock_op: &OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, u8> { + fn TryAcquireSRWLockShared(&mut self, lock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, u8> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; let active_thread = this.get_active_thread(); @@ -117,17 +104,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn ReleaseSRWLockShared( - &mut self, - lock_op: &OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { + fn ReleaseSRWLockShared(&mut self, lock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; let active_thread = this.get_active_thread(); if !this.rwlock_reader_unlock(id, active_thread) { // The docs do not say anything about this case, but it seems better to not allow it. - throw_ub_format!("calling ReleaseSRWLockShared on an SRWLock that is not locked by the current thread"); + throw_ub_format!( + "calling ReleaseSRWLockShared on an SRWLock that is not locked by the current thread" + ); } Ok(()) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index fbcd265baa11..88f42efd13cf 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -9,10 +9,10 @@ use std::rc::Rc; use log::trace; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_hir::Mutability; use rustc_middle::mir::RetagKind; use rustc_middle::ty; use rustc_target::abi::{Align, LayoutOf, Size}; -use rustc_hir::Mutability; use crate::*; @@ -157,7 +157,11 @@ impl fmt::Display for RefKind { /// Utilities for initialization and ID generation impl GlobalState { - pub fn new(tracked_pointer_tag: Option, tracked_call_id: Option, track_raw: bool) -> Self { + pub fn new( + tracked_pointer_tag: Option, + tracked_call_id: Option, + track_raw: bool, + ) -> Self { GlobalState { next_ptr_id: NonZeroU64::new(1).unwrap(), base_ptr_ids: FxHashMap::default(), @@ -211,7 +215,9 @@ impl GlobalState { fn err_sb_ub(msg: String) -> InterpError<'static> { err_machine_stop!(TerminationInfo::ExperimentalUb { msg, - url: format!("https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md"), + url: format!( + "https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md" + ), }) } @@ -300,10 +306,7 @@ impl<'tcx> Stack { tag, item )))? } else { - Err(err_sb_ub(format!( - "deallocating while item is protected: {:?}", - item - )))? + Err(err_sb_ub(format!("deallocating while item is protected: {:?}", item)))? } } } @@ -312,14 +315,21 @@ impl<'tcx> Stack { /// Test if a memory `access` using pointer tagged `tag` is granted. /// If yes, return the index of the item that granted it. - fn access(&mut self, access: AccessKind, ptr: Pointer, global: &GlobalState) -> InterpResult<'tcx> { + fn access( + &mut self, + access: AccessKind, + ptr: Pointer, + global: &GlobalState, + ) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. let granting_idx = self.find_granting(access, ptr.tag).ok_or_else(|| { err_sb_ub(format!( "no item granting {} to tag {:?} at {} found in borrow stack.", - access, ptr.tag, ptr.erase_tag(), + access, + ptr.tag, + ptr.erase_tag(), )) })?; @@ -379,7 +389,12 @@ impl<'tcx> Stack { /// `weak` controls whether this operation is weak or strong: weak granting does not act as /// an access, and they add the new item directly on top of the one it is derived /// from instead of all the way at the top of the stack. - fn grant(&mut self, derived_from: Pointer, new: Item, global: &GlobalState) -> InterpResult<'tcx> { + fn grant( + &mut self, + derived_from: Pointer, + new: Item, + global: &GlobalState, + ) -> InterpResult<'tcx> { // Figure out which access `perm` corresponds to. let access = if new.perm.grants(AccessKind::Write) { AccessKind::Write } else { AccessKind::Read }; @@ -480,12 +495,17 @@ impl Stacks { // `ExternStatic` is used for extern statics, and thus must also be listed here. // `Env` we list because we can get away with precise tracking there. // The base pointer is not unique, so the base permission is `SharedReadWrite`. - MemoryKind::Machine(MiriMemoryKind::Global | MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls | MiriMemoryKind::Env) => - (extra.borrow_mut().global_base_ptr(id), Permission::SharedReadWrite), + MemoryKind::Machine( + MiriMemoryKind::Global + | MiriMemoryKind::ExternStatic + | MiriMemoryKind::Tls + | MiriMemoryKind::Env, + ) => (extra.borrow_mut().global_base_ptr(id), Permission::SharedReadWrite), // Everything else we handle like raw pointers for now. _ => { let mut extra = extra.borrow_mut(); - let tag = if extra.track_raw { Tag::Tagged(extra.new_ptr()) } else { Tag::Untagged }; + let tag = + if extra.track_raw { Tag::Tagged(extra.new_ptr()) } else { Tag::Untagged }; (tag, Permission::SharedReadWrite) } }; @@ -584,9 +604,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); // We want a place for where the ptr *points to*, so we get one. let place = this.ref_to_mplace(val)?; - let size = this - .size_and_align_of_mplace(&place)? - .map(|(size, _)| size); + let size = this.size_and_align_of_mplace(&place)?.map(|(size, _)| size); // FIXME: If we cannot determine the size (because the unsized tail is an `extern type`), // bail out -- we cannot reasonably figure out which memory range to reborrow. // See https://github.com/rust-lang/unsafe-code-guidelines/issues/276. @@ -667,7 +685,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// After a stack frame got pushed, retag the return place so that we are sure /// it does not alias with anything. - /// + /// /// This is a HACK because there is nothing in MIR that would make the retag /// explicit. Also see https://github.com/rust-lang/rust/issues/71117. fn retag_return_place(&mut self) -> InterpResult<'tcx> { @@ -690,7 +708,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr_layout = this.layout_of(this.tcx.mk_mut_ptr(return_place.layout.ty))?; let val = ImmTy::from_immediate(return_place.to_ref(), ptr_layout); // Reborrow it. - let val = this.retag_reference(&val, RefKind::Unique { two_phase: false }, /*protector*/ true)?; + let val = this.retag_reference( + &val, + RefKind::Unique { two_phase: false }, + /*protector*/ true, + )?; // And use reborrowed pointer for return place. let return_place = this.ref_to_mplace(&val)?; this.frame_mut().return_place = Some(return_place.into()); diff --git a/src/sync.rs b/src/sync.rs index 4d488565faf3..b53af0aeb24a 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -66,7 +66,7 @@ struct Mutex { /// released to during unlock and acquired from during /// locking, and therefore stores the clock of the last /// thread to release this mutex. - data_race: VClock + data_race: VClock, } declare_id!(RwLockId); @@ -98,7 +98,7 @@ struct RwLock { /// is stored to the main data_race variable once all /// readers are finished. /// Has to be stored separately since reader lock acquires - /// must load the clock of the last write and must not + /// must load the clock of the last write and must not /// add happens-before orderings between shared reader /// locks. data_race_reader: VClock, @@ -251,11 +251,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// count. If the lock count reaches 0, release the lock and potentially /// give to a new owner. If the lock was not locked by `expected_owner`, /// return `None`. - fn mutex_unlock( - &mut self, - id: MutexId, - expected_owner: ThreadId, - ) -> Option { + fn mutex_unlock(&mut self, id: MutexId, expected_owner: ThreadId) -> Option { let this = self.eval_context_mut(); let mutex = &mut this.machine.threads.sync.mutexes[id]; if let Some(current_owner) = mutex.owner { @@ -307,9 +303,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let rwlock = &this.machine.threads.sync.rwlocks[id]; trace!( "rwlock_is_locked: {:?} writer is {:?} and there are {} reader threads (some of which could hold multiple read locks)", - id, rwlock.writer, rwlock.readers.len(), + id, + rwlock.writer, + rwlock.readers.len(), ); - rwlock.writer.is_some()|| rwlock.readers.is_empty().not() + rwlock.writer.is_some() || rwlock.readers.is_empty().not() } #[inline] @@ -360,7 +358,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // The thread was a reader. If the lock is not held any more, give it to a writer. if this.rwlock_is_locked(id).not() { - // All the readers are finished, so set the writer data-race handle to the value // of the union of all reader data race handles, since the set of readers // happen-before the writers @@ -373,11 +370,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] /// Put the reader in the queue waiting for the lock and block it. - fn rwlock_enqueue_and_block_reader( - &mut self, - id: RwLockId, - reader: ThreadId, - ) { + fn rwlock_enqueue_and_block_reader(&mut self, id: RwLockId, reader: ThreadId) { let this = self.eval_context_mut(); assert!(this.rwlock_is_write_locked(id), "read-queueing on not write locked rwlock"); this.machine.threads.sync.rwlocks[id].reader_queue.push_back(reader); @@ -437,11 +430,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] /// Put the writer in the queue waiting for the lock. - fn rwlock_enqueue_and_block_writer( - &mut self, - id: RwLockId, - writer: ThreadId, - ) { + fn rwlock_enqueue_and_block_writer(&mut self, id: RwLockId, writer: ThreadId) { let this = self.eval_context_mut(); assert!(this.rwlock_is_locked(id), "write-queueing on unlocked rwlock"); this.machine.threads.sync.rwlocks[id].writer_queue.push_back(writer); @@ -482,14 +471,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(data_race) = data_race { data_race.validate_lock_release(&mut condvar.data_race, current_thread); } - condvar.waiters - .pop_front() - .map(|waiter| { - if let Some(data_race) = data_race { - data_race.validate_lock_acquire(&mut condvar.data_race, waiter.thread); - } - (waiter.thread, waiter.mutex) - }) + condvar.waiters.pop_front().map(|waiter| { + if let Some(data_race) = data_race { + data_race.validate_lock_acquire(&mut condvar.data_race, waiter.thread); + } + (waiter.thread, waiter.mutex) + }) } #[inline] @@ -511,7 +498,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let current_thread = this.get_active_thread(); let futex = &mut this.machine.threads.sync.futexes.get_mut(&addr.erase_tag())?; - let data_race = &this.memory.extra.data_race; + let data_race = &this.memory.extra.data_race; // Each futex-wake happens-before the end of the futex wait if let Some(data_race) = data_race { @@ -519,7 +506,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let res = futex.waiters.pop_front().map(|waiter| { if let Some(data_race) = data_race { - data_race.validate_lock_acquire(&futex.data_race, waiter.thread); + data_race.validate_lock_acquire(&futex.data_race, waiter.thread); } waiter.thread }); diff --git a/src/thread.rs b/src/thread.rs index 8b1787132cbc..7d6fe8041e98 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -3,8 +3,8 @@ use std::cell::RefCell; use std::collections::hash_map::Entry; use std::convert::TryFrom; -use std::rc::Rc; use std::num::TryFromIntError; +use std::rc::Rc; use std::time::{Duration, Instant, SystemTime}; use log::trace; @@ -141,17 +141,19 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> { /// Get the name of the current thread, or `` if it was not set. fn thread_name(&self) -> &[u8] { - if let Some(ref thread_name) = self.thread_name { - thread_name - } else { - b"" - } + if let Some(ref thread_name) = self.thread_name { thread_name } else { b"" } } } impl<'mir, 'tcx> std::fmt::Debug for Thread<'mir, 'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}({:?}, {:?})", String::from_utf8_lossy(self.thread_name()), self.state, self.join_status) + write!( + f, + "{}({:?}, {:?})", + String::from_utf8_lossy(self.thread_name()), + self.state, + self.join_status + ) } } @@ -328,7 +330,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Mark that the active thread tries to join the thread with `joined_thread_id`. - fn join_thread(&mut self, joined_thread_id: ThreadId, data_race: &Option>) -> InterpResult<'tcx> { + fn join_thread( + &mut self, + joined_thread_id: ThreadId, + data_race: &Option>, + ) -> InterpResult<'tcx> { if self.threads[joined_thread_id].join_status != ThreadJoinStatus::Joinable { throw_ub_format!("trying to join a detached or already joined thread"); } @@ -431,7 +437,10 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Wakes up threads joining on the active one and deallocates thread-local statics. /// The `AllocId` that can now be freed is returned. - fn thread_terminated(&mut self, data_race: &Option>) -> Vec { + fn thread_terminated( + &mut self, + data_race: &Option>, + ) -> Vec { let mut free_tls_statics = Vec::new(); { let mut thread_local_statics = self.thread_local_alloc_ids.borrow_mut(); @@ -470,7 +479,10 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// used in stateless model checkers such as Loom: run the active thread as /// long as we can and switch only when we have to (the active thread was /// blocked, terminated, or has explicitly asked to be preempted). - fn schedule(&mut self, data_race: &Option>) -> InterpResult<'tcx, SchedulingAction> { + fn schedule( + &mut self, + data_race: &Option>, + ) -> InterpResult<'tcx, SchedulingAction> { // Check whether the thread has **just** terminated (`check_terminated` // checks whether the thread has popped all its stack and if yes, sets // the thread state to terminated). @@ -546,7 +558,10 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Get a thread-specific allocation id for the given thread-local static. /// If needed, allocate a new one. - fn get_or_create_thread_local_alloc_id(&mut self, def_id: DefId) -> InterpResult<'tcx, AllocId> { + fn get_or_create_thread_local_alloc_id( + &mut self, + def_id: DefId, + ) -> InterpResult<'tcx, AllocId> { let this = self.eval_context_mut(); let tcx = this.tcx; if let Some(new_alloc_id) = this.machine.threads.get_thread_local_alloc_id(def_id) { @@ -562,7 +577,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let allocation = tcx.eval_static_initializer(def_id)?; // Create a fresh allocation with this content. - let new_alloc_id = this.memory.allocate_with(allocation.clone(), MiriMemoryKind::Tls.into()).alloc_id; + let new_alloc_id = + this.memory.allocate_with(allocation.clone(), MiriMemoryKind::Tls.into()).alloc_id; this.machine.threads.set_thread_local_alloc_id(def_id, new_alloc_id); Ok(new_alloc_id) } @@ -654,9 +670,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); if let Some(data_race) = &this.memory.extra.data_race { if let Ok(string) = String::from_utf8(new_thread_name.clone()) { - data_race.thread_set_name( - this.machine.threads.active_thread, string - ); + data_race.thread_set_name(this.machine.threads.active_thread, string); } } this.machine.threads.set_thread_name(new_thread_name); diff --git a/src/vector_clock.rs b/src/vector_clock.rs index 1ce6511ee4ae..a2e235858d83 100644 --- a/src/vector_clock.rs +++ b/src/vector_clock.rs @@ -1,11 +1,6 @@ use rustc_index::vec::Idx; use smallvec::SmallVec; -use std::{ - cmp::Ordering, - convert::TryFrom, - fmt::Debug, - ops::Index, -}; +use std::{cmp::Ordering, convert::TryFrom, fmt::Debug, ops::Index}; /// A vector clock index, this is associated with a thread id /// but in some cases one vector index may be shared with From d6fdfaa0475833171756d4b4236114c2af066395 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 May 2021 11:48:08 +0200 Subject: [PATCH 2653/5092] hand-held formatting for remaining files --- src/diagnostics.rs | 70 +++--- src/shims/foreign_items.rs | 15 +- src/shims/intrinsics.rs | 434 +++++++++++++------------------------ 3 files changed, 200 insertions(+), 319 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 45c0996355bf..f074cfd4911b 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -22,16 +22,11 @@ impl fmt::Display for TerminationInfo { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use TerminationInfo::*; match self { - Exit(code) => - write!(f, "the evaluated program completed with exit code {}", code), - Abort(msg) => - write!(f, "{}", msg), - UnsupportedInIsolation(msg) => - write!(f, "{}", msg), - ExperimentalUb { msg, .. } => - write!(f, "{}", msg), - Deadlock => - write!(f, "the evaluated program deadlocked"), + Exit(code) => write!(f, "the evaluated program completed with exit code {}", code), + Abort(msg) => write!(f, "{}", msg), + UnsupportedInIsolation(msg) => write!(f, "{}", msg), + ExperimentalUb { msg, .. } => write!(f, "{}", msg), + Deadlock => write!(f, "the evaluated program deadlocked"), } } } @@ -60,14 +55,12 @@ pub fn report_error<'tcx, 'mir>( use TerminationInfo::*; let title = match info { Exit(code) => return Some(*code), - Abort(_) => - "abnormal termination", - UnsupportedInIsolation(_) => - "unsupported operation", - ExperimentalUb { .. } => - "Undefined Behavior", + Abort(_) => "abnormal termination", + UnsupportedInIsolation(_) => "unsupported operation", + ExperimentalUb { .. } => "Undefined Behavior", Deadlock => "deadlock", }; + #[rustfmt::skip] let helps = match info { UnsupportedInIsolation(_) => vec![format!("pass the flag `-Zmiri-disable-isolation` to disable isolation")], @@ -81,6 +74,7 @@ pub fn report_error<'tcx, 'mir>( (title, helps) } _ => { + #[rustfmt::skip] let title = match e.kind() { Unsupported(_) => "unsupported operation", @@ -93,6 +87,7 @@ pub fn report_error<'tcx, 'mir>( _ => bug!("This error should be impossible in Miri: {}", e), }; + #[rustfmt::skip] let helps = match e.kind() { Unsupported(UnsupportedOpInfo::NoMirFor(..)) => vec![format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`")], @@ -120,7 +115,14 @@ pub fn report_error<'tcx, 'mir>( e.print_backtrace(); let msg = e.to_string(); - report_msg(*ecx.tcx, /*error*/true, &format!("{}: {}", title, msg), msg, helps, &ecx.generate_stacktrace()); + report_msg( + *ecx.tcx, + /*error*/ true, + &format!("{}: {}", title, msg), + msg, + helps, + &ecx.generate_stacktrace(), + ); // Debug-dump all locals. for (i, frame) in ecx.active_thread_stack().iter().enumerate() { @@ -249,7 +251,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Add popped frame back. if stacktrace.len() < info.stack_size { - assert!(stacktrace.len() == info.stack_size-1, "we should never pop more than one frame at once"); + assert!( + stacktrace.len() == info.stack_size - 1, + "we should never pop more than one frame at once" + ); let frame_info = FrameInfo { instance: info.instance.unwrap(), span: info.span, @@ -259,25 +264,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if let Some(instance) = info.instance { // Adjust topmost frame. stacktrace[0].span = info.span; - assert_eq!(stacktrace[0].instance, instance, "we should not pop and push a frame in one step"); + assert_eq!( + stacktrace[0].instance, instance, + "we should not pop and push a frame in one step" + ); } // Show diagnostics. for e in diagnostics.drain(..) { use NonHaltingDiagnostic::*; let msg = match e { - CreatedPointerTag(tag) => - format!("created tag {:?}", tag), - PoppedPointerTag(item) => - format!("popped tracked tag for item {:?}", item), - CreatedCallId(id) => - format!("function call with id {}", id), - CreatedAlloc(AllocId(id)) => - format!("created allocation with id {}", id), - FreedAlloc(AllocId(id)) => - format!("freed allocation with id {}", id), + CreatedPointerTag(tag) => format!("created tag {:?}", tag), + PoppedPointerTag(item) => format!("popped tracked tag for item {:?}", item), + CreatedCallId(id) => format!("function call with id {}", id), + CreatedAlloc(AllocId(id)) => format!("created allocation with id {}", id), + FreedAlloc(AllocId(id)) => format!("freed allocation with id {}", id), }; - report_msg(*this.tcx, /*error*/false, "tracking was triggered", msg, vec![], &stacktrace); + report_msg( + *this.tcx, + /*error*/ false, + "tracking was triggered", + msg, + vec![], + &stacktrace, + ); } }); } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 371a50f0e4b2..6867871794a8 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -114,7 +114,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// by this function. /// Returns Ok(Some(body)) if processing the foreign item /// is delegated to another function. - #[rustfmt::skip] fn emulate_foreign_item( &mut self, def_id: DefId, @@ -149,6 +148,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id); return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); } + #[rustfmt::skip] | "exit" | "ExitProcess" => { @@ -160,7 +160,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "abort" => { check_abi(abi, Abi::C { unwind: false })?; - throw_machine_stop!(TerminationInfo::Abort("the program aborted execution".to_owned())) + throw_machine_stop!(TerminationInfo::Abort( + "the program aborted execution".to_owned() + )) } _ => throw_unsup_format!("can't call (diverging) foreign function: {}", link_name), }, @@ -175,7 +177,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We forward this to the underlying *implementation* in the panic runtime crate. // Normally, this will be either `libpanic_unwind` or `libpanic_abort`, but it could // also be a custom user-provided implementation via `#![feature(panic_runtime)]` - "__rust_start_panic" | "__rust_panic_cleanup" => { + #[rustfmt::skip] + "__rust_start_panic" | + "__rust_panic_cleanup" => { check_abi(abi, Abi::C { unwind: false })?; // This replicates some of the logic in `inject_panic_runtime`. // FIXME: is there a way to reuse that logic? @@ -406,6 +410,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // math functions + #[rustfmt::skip] | "cbrtf" | "coshf" | "sinhf" @@ -430,6 +435,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?; } + #[rustfmt::skip] | "_hypotf" | "hypotf" | "atan2f" @@ -448,6 +454,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; this.write_scalar(Scalar::from_u32(n.to_bits()), dest)?; } + #[rustfmt::skip] | "cbrt" | "cosh" | "sinh" @@ -472,6 +479,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; this.write_scalar(Scalar::from_u64(f.to_bits()), dest)?; } + #[rustfmt::skip] | "_hypot" | "hypot" | "atan2" @@ -488,6 +496,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?; } + #[rustfmt::skip] | "_ldexp" | "ldexp" | "scalbn" diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index b33b9666f712..ee0e833f9e5f 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -330,312 +330,174 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_xchg_acqrel" => this.atomic_exchange(args, dest, AtomicRwOp::AcqRel)?, "atomic_xchg_relaxed" => this.atomic_exchange(args, dest, AtomicRwOp::Relaxed)?, + #[rustfmt::skip] "atomic_cxchg" => this.atomic_compare_exchange(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::SeqCst)?, - "atomic_cxchg_acq" => this.atomic_compare_exchange( - args, - dest, - AtomicRwOp::Acquire, - AtomicReadOp::Acquire, - )?, - "atomic_cxchg_rel" => this.atomic_compare_exchange( - args, - dest, - AtomicRwOp::Release, - AtomicReadOp::Relaxed, - )?, + #[rustfmt::skip] + "atomic_cxchg_acq" => + this.atomic_compare_exchange(args, dest, AtomicRwOp::Acquire, AtomicReadOp::Acquire)?, + #[rustfmt::skip] + "atomic_cxchg_rel" => + this.atomic_compare_exchange(args, dest, AtomicRwOp::Release, AtomicReadOp::Relaxed)?, + #[rustfmt::skip] "atomic_cxchg_acqrel" => this.atomic_compare_exchange(args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Acquire)?, - "atomic_cxchg_relaxed" => this.atomic_compare_exchange( - args, - dest, - AtomicRwOp::Relaxed, - AtomicReadOp::Relaxed, - )?, - "atomic_cxchg_acq_failrelaxed" => this.atomic_compare_exchange( - args, - dest, - AtomicRwOp::Acquire, - AtomicReadOp::Relaxed, - )?, + #[rustfmt::skip] + "atomic_cxchg_relaxed" => + this.atomic_compare_exchange(args, dest, AtomicRwOp::Relaxed, AtomicReadOp::Relaxed)?, + #[rustfmt::skip] + "atomic_cxchg_acq_failrelaxed" => + this.atomic_compare_exchange(args, dest, AtomicRwOp::Acquire, AtomicReadOp::Relaxed)?, + #[rustfmt::skip] "atomic_cxchg_acqrel_failrelaxed" => this.atomic_compare_exchange(args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Relaxed)?, + #[rustfmt::skip] "atomic_cxchg_failrelaxed" => this.atomic_compare_exchange(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Relaxed)?, + #[rustfmt::skip] "atomic_cxchg_failacq" => this.atomic_compare_exchange(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Acquire)?, - "atomic_cxchgweak" => this.atomic_compare_exchange_weak( - args, - dest, - AtomicRwOp::SeqCst, - AtomicReadOp::SeqCst, - )?, - "atomic_cxchgweak_acq" => this.atomic_compare_exchange_weak( - args, - dest, - AtomicRwOp::Acquire, - AtomicReadOp::Acquire, - )?, - "atomic_cxchgweak_rel" => this.atomic_compare_exchange_weak( - args, - dest, - AtomicRwOp::Release, - AtomicReadOp::Relaxed, - )?, - "atomic_cxchgweak_acqrel" => this.atomic_compare_exchange_weak( - args, - dest, - AtomicRwOp::AcqRel, - AtomicReadOp::Acquire, - )?, - "atomic_cxchgweak_relaxed" => this.atomic_compare_exchange_weak( - args, - dest, - AtomicRwOp::Relaxed, - AtomicReadOp::Relaxed, - )?, - "atomic_cxchgweak_acq_failrelaxed" => this.atomic_compare_exchange_weak( - args, - dest, - AtomicRwOp::Acquire, - AtomicReadOp::Relaxed, - )?, - "atomic_cxchgweak_acqrel_failrelaxed" => this.atomic_compare_exchange_weak( - args, - dest, - AtomicRwOp::AcqRel, - AtomicReadOp::Relaxed, - )?, - "atomic_cxchgweak_failrelaxed" => this.atomic_compare_exchange_weak( - args, - dest, - AtomicRwOp::SeqCst, - AtomicReadOp::Relaxed, - )?, - "atomic_cxchgweak_failacq" => this.atomic_compare_exchange_weak( - args, - dest, - AtomicRwOp::SeqCst, - AtomicReadOp::Acquire, - )?, + #[rustfmt::skip] + "atomic_cxchgweak" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::SeqCst)?, + #[rustfmt::skip] + "atomic_cxchgweak_acq" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::Acquire, AtomicReadOp::Acquire)?, + #[rustfmt::skip] + "atomic_cxchgweak_rel" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::Release, AtomicReadOp::Relaxed)?, + #[rustfmt::skip] + "atomic_cxchgweak_acqrel" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Acquire)?, + #[rustfmt::skip] + "atomic_cxchgweak_relaxed" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::Relaxed, AtomicReadOp::Relaxed)?, + #[rustfmt::skip] + "atomic_cxchgweak_acq_failrelaxed" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::Acquire, AtomicReadOp::Relaxed)?, + #[rustfmt::skip] + "atomic_cxchgweak_acqrel_failrelaxed" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Relaxed)?, + #[rustfmt::skip] + "atomic_cxchgweak_failrelaxed" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Relaxed)?, + #[rustfmt::skip] + "atomic_cxchgweak_failacq" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Acquire)?, - "atomic_or" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitOr, false), - AtomicRwOp::SeqCst, - )?, - "atomic_or_acq" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitOr, false), - AtomicRwOp::Acquire, - )?, - "atomic_or_rel" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitOr, false), - AtomicRwOp::Release, - )?, - "atomic_or_acqrel" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitOr, false), - AtomicRwOp::AcqRel, - )?, - "atomic_or_relaxed" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitOr, false), - AtomicRwOp::Relaxed, - )?, - "atomic_xor" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitXor, false), - AtomicRwOp::SeqCst, - )?, - "atomic_xor_acq" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitXor, false), - AtomicRwOp::Acquire, - )?, - "atomic_xor_rel" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitXor, false), - AtomicRwOp::Release, - )?, - "atomic_xor_acqrel" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitXor, false), - AtomicRwOp::AcqRel, - )?, - "atomic_xor_relaxed" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitXor, false), - AtomicRwOp::Relaxed, - )?, - "atomic_and" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitAnd, false), - AtomicRwOp::SeqCst, - )?, - "atomic_and_acq" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitAnd, false), - AtomicRwOp::Acquire, - )?, - "atomic_and_rel" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitAnd, false), - AtomicRwOp::Release, - )?, - "atomic_and_acqrel" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitAnd, false), - AtomicRwOp::AcqRel, - )?, - "atomic_and_relaxed" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitAnd, false), - AtomicRwOp::Relaxed, - )?, - "atomic_nand" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitAnd, true), - AtomicRwOp::SeqCst, - )?, - "atomic_nand_acq" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitAnd, true), - AtomicRwOp::Acquire, - )?, - "atomic_nand_rel" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitAnd, true), - AtomicRwOp::Release, - )?, - "atomic_nand_acqrel" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitAnd, true), - AtomicRwOp::AcqRel, - )?, - "atomic_nand_relaxed" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitAnd, true), - AtomicRwOp::Relaxed, - )?, - "atomic_xadd" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::Add, false), - AtomicRwOp::SeqCst, - )?, - "atomic_xadd_acq" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::Add, false), - AtomicRwOp::Acquire, - )?, - "atomic_xadd_rel" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::Add, false), - AtomicRwOp::Release, - )?, - "atomic_xadd_acqrel" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::Add, false), - AtomicRwOp::AcqRel, - )?, - "atomic_xadd_relaxed" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::Add, false), - AtomicRwOp::Relaxed, - )?, - "atomic_xsub" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::Sub, false), - AtomicRwOp::SeqCst, - )?, - "atomic_xsub_acq" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::Sub, false), - AtomicRwOp::Acquire, - )?, - "atomic_xsub_rel" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::Sub, false), - AtomicRwOp::Release, - )?, - "atomic_xsub_acqrel" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::Sub, false), - AtomicRwOp::AcqRel, - )?, - "atomic_xsub_relaxed" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::Sub, false), - AtomicRwOp::Relaxed, - )?, - "atomic_min" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, - "atomic_min_acq" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, - "atomic_min_rel" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, - "atomic_min_acqrel" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, + #[rustfmt::skip] + "atomic_or" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::SeqCst)?, + #[rustfmt::skip] + "atomic_or_acq" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::Acquire)?, + #[rustfmt::skip] + "atomic_or_rel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::Release)?, + #[rustfmt::skip] + "atomic_or_acqrel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::AcqRel)?, + #[rustfmt::skip] + "atomic_or_relaxed" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::Relaxed)?, + #[rustfmt::skip] + "atomic_xor" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::SeqCst)?, + #[rustfmt::skip] + "atomic_xor_acq" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::Acquire)?, + #[rustfmt::skip] + "atomic_xor_rel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::Release)?, + #[rustfmt::skip] + "atomic_xor_acqrel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::AcqRel)?, + #[rustfmt::skip] + "atomic_xor_relaxed" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::Relaxed)?, + #[rustfmt::skip] + "atomic_and" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::SeqCst)?, + #[rustfmt::skip] + "atomic_and_acq" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::Acquire)?, + #[rustfmt::skip] + "atomic_and_rel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::Release)?, + #[rustfmt::skip] + "atomic_and_acqrel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::AcqRel)?, + #[rustfmt::skip] + "atomic_and_relaxed" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::Relaxed)?, + #[rustfmt::skip] + "atomic_nand" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::SeqCst)?, + #[rustfmt::skip] + "atomic_nand_acq" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::Acquire)?, + #[rustfmt::skip] + "atomic_nand_rel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::Release)?, + #[rustfmt::skip] + "atomic_nand_acqrel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::AcqRel)?, + #[rustfmt::skip] + "atomic_nand_relaxed" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::Relaxed)?, + #[rustfmt::skip] + "atomic_xadd" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::SeqCst)?, + #[rustfmt::skip] + "atomic_xadd_acq" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::Acquire)?, + #[rustfmt::skip] + "atomic_xadd_rel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::Release)?, + #[rustfmt::skip] + "atomic_xadd_acqrel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::AcqRel)?, + #[rustfmt::skip] + "atomic_xadd_relaxed" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::Relaxed)?, + #[rustfmt::skip] + "atomic_xsub" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::SeqCst)?, + #[rustfmt::skip] + "atomic_xsub_acq" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::Acquire)?, + #[rustfmt::skip] + "atomic_xsub_rel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::Release)?, + #[rustfmt::skip] + "atomic_xsub_acqrel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::AcqRel)?, + #[rustfmt::skip] + "atomic_xsub_relaxed" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::Relaxed)?, + "atomic_min" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, + "atomic_min_acq" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, + "atomic_min_rel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, + "atomic_min_acqrel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, "atomic_min_relaxed" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Relaxed)?, - "atomic_max" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, - "atomic_max_acq" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, - "atomic_max_rel" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, - "atomic_max_acqrel" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, + "atomic_max" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, + "atomic_max_acq" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, + "atomic_max_rel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, + "atomic_max_acqrel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, "atomic_max_relaxed" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Relaxed)?, - "atomic_umin" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, - "atomic_umin_acq" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, - "atomic_umin_rel" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, + "atomic_umin" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, + "atomic_umin_acq" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, + "atomic_umin_rel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, "atomic_umin_acqrel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, "atomic_umin_relaxed" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Relaxed)?, - "atomic_umax" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, - "atomic_umax_acq" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, - "atomic_umax_rel" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, + "atomic_umax" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, + "atomic_umax_acq" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, + "atomic_umax_rel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, "atomic_umax_acqrel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, "atomic_umax_relaxed" => From cf3376e541bea322370a9b0c521d292551a00642 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 May 2021 09:34:39 +0200 Subject: [PATCH 2654/5092] rustup --- benches/helpers/miri_helper.rs | 3 +-- rust-version | 2 +- src/bin/miri.rs | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 7642018c08cb..144ddc11968c 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -3,7 +3,6 @@ extern crate rustc_hir; extern crate rustc_interface; use rustc_driver::Compilation; -use rustc_hir::def_id::LOCAL_CRATE; use rustc_interface::{interface, Queries}; use crate::test::Bencher; @@ -22,7 +21,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { let (entry_def_id, _) = - tcx.entry_fn(LOCAL_CRATE).expect("no main or start function found"); + tcx.entry_fn(()).expect("no main or start function found"); self.bencher.iter(|| { let config = miri::MiriConfig::default(); diff --git a/rust-version b/rust-version index 0495fc97f7f7..600ef9d5a6e3 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c6dd87a6b4a62cf5d2cb6207b1dcea652ea1aa60 +3396a383bb1d1fdad8ceeb74f16cf08e0bd62a1b diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 0e9a6ffe8050..4a1ea3a54286 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -16,7 +16,6 @@ use log::debug; use rustc_driver::Compilation; use rustc_errors::emitter::{ColorConfig, HumanReadableErrorType}; -use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::ty::TyCtxt; use rustc_session::{config::ErrorOutputType, CtfeBacktrace}; @@ -34,7 +33,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { init_late_loggers(tcx); - let (entry_def_id, _) = if let Some((entry_def, x)) = tcx.entry_fn(LOCAL_CRATE) { + let (entry_def_id, _) = if let Some((entry_def, x)) = tcx.entry_fn(()) { (entry_def, x) } else { let output_ty = ErrorOutputType::HumanReadable(HumanReadableErrorType::Default( From 78f74c69e340a93ed75b04619437cc02b5af0587 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 May 2021 10:57:21 +0200 Subject: [PATCH 2655/5092] fix rustfmt fallout --- src/shims/windows/foreign_items.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 655f6b08c2c3..f29870ff7cb7 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -298,7 +298,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let len = this.read_scalar(len)?.to_u32()?; let flags = this.read_scalar(flags)?.to_u32()?; if flags != 2 { - // BCRYPT_USE_SYSTEM_PREFERRED_RNG + // ^ BCRYPT_USE_SYSTEM_PREFERRED_RNG throw_unsup_format!( "BCryptGenRandom is supported only with the BCRYPT_USE_SYSTEM_PREFERRED_RNG flag" ); From 4f171d7fe3cc9e24adb5917f226b00f287466771 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 May 2021 14:31:59 +0200 Subject: [PATCH 2656/5092] stop relying on c_str/wide_str helpers in rustc --- src/helpers.rs | 45 +++++++++++++++++++++++++ src/shims/foreign_items.rs | 2 +- src/shims/os_str.rs | 54 ++++++++++++++++++------------ src/shims/posix/foreign_items.rs | 2 +- src/shims/posix/thread.rs | 4 +-- src/shims/windows/foreign_items.rs | 2 +- 6 files changed, 83 insertions(+), 26 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 7215cb4b0c7b..ef5ea9447808 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -566,6 +566,51 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Duration::new(seconds, nanoseconds) }) } + + fn read_c_str<'a>(&'a self, sptr: Scalar) -> InterpResult<'tcx, &'a [u8]> + where + 'tcx: 'a, + 'mir: 'a, + { + let this = self.eval_context_ref(); + let size1 = Size::from_bytes(1); + let ptr = this.force_ptr(sptr)?; // We need to read at least 1 byte, so we can eagerly get a ptr. + + // Step 1: determine the length. + let alloc = this.memory.get_raw(ptr.alloc_id)?; + let mut len = Size::ZERO; + loop { + let byte = alloc.read_scalar(this, ptr.offset(len, this)?, size1)?.to_u8()?; + if byte == 0 { + break; + } else { + len = len + size1; + } + } + + // Step 2: get the bytes. + this.memory.read_bytes(ptr.into(), len) + } + + fn read_wide_str(&self, sptr: Scalar) -> InterpResult<'tcx, Vec> { + let this = self.eval_context_ref(); + let size2 = Size::from_bytes(2); + + let mut ptr = this.force_ptr(sptr)?; // We need to read at least 1 wchar, so we can eagerly get a ptr. + let mut wchars = Vec::new(); + let alloc = this.memory.get_raw(ptr.alloc_id)?; + loop { + let wchar = alloc.read_scalar(this, ptr, size2)?.to_u16()?; + if wchar == 0 { + break; + } else { + wchars.push(wchar); + ptr = ptr.offset(size2, this)?; + } + } + + Ok(wchars) + } } /// Check that the number of args is what we expect. diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 6867871794a8..47d939e69722 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -405,7 +405,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx check_abi(abi, Abi::C { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; - let n = this.memory.read_c_str(ptr)?.len(); + let n = this.read_c_str(ptr)?.len(); this.write_scalar(Scalar::from_machine_usize(u64::try_from(n).unwrap(), this), dest)?; } diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 22e3806ad334..f1f14fa828f8 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -9,7 +9,7 @@ use std::os::unix::ffi::{OsStrExt, OsStringExt}; #[cfg(windows)] use std::os::windows::ffi::{OsStrExt, OsStringExt}; -use rustc_target::abi::LayoutOf; +use rustc_target::abi::{LayoutOf, Size}; use crate::*; @@ -50,19 +50,19 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. - fn read_os_str_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, &'a OsStr> + fn read_os_str_from_c_str<'a>(&'a self, sptr: Scalar) -> InterpResult<'tcx, &'a OsStr> where 'tcx: 'a, 'mir: 'a, { let this = self.eval_context_ref(); - let bytes = this.memory.read_c_str(scalar)?; + let bytes = this.read_c_str(sptr)?; bytes_to_os_str(bytes) } /// Helper function to read an OsString from a 0x0000-terminated sequence of u16, /// which is what the Windows APIs usually handle. - fn read_os_str_from_wide_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, OsString> + fn read_os_str_from_wide_str<'a>(&'a self, sptr: Scalar) -> InterpResult<'tcx, OsString> where 'tcx: 'a, 'mir: 'a, @@ -78,7 +78,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(s.into()) } - let u16_vec = self.eval_context_ref().memory.read_wide_str(scalar)?; + let u16_vec = self.eval_context_ref().read_wide_str(sptr)?; u16vec_to_osstring(u16_vec) } @@ -90,7 +90,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_os_str_to_c_str( &mut self, os_str: &OsStr, - scalar: Scalar, + sptr: Scalar, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let bytes = os_str_to_bytes(os_str)?; @@ -102,7 +102,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } self.eval_context_mut() .memory - .write_bytes(scalar, bytes.iter().copied().chain(iter::once(0u8)))?; + .write_bytes(sptr, bytes.iter().copied().chain(iter::once(0u8)))?; Ok((true, string_length)) } @@ -114,7 +114,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_os_str_to_wide_str( &mut self, os_str: &OsStr, - scalar: Scalar, + sptr: Scalar, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { #[cfg(windows)] @@ -136,15 +136,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required // 0x0000 terminator to memory would cause an out-of-bounds access. let string_length = u64::try_from(u16_vec.len()).unwrap(); - if size <= string_length { + let string_length = string_length.checked_add(1).unwrap(); + if size < string_length { return Ok((false, string_length)); } // Store the UTF-16 string. - self.eval_context_mut() - .memory - .write_u16s(scalar, u16_vec.into_iter().chain(iter::once(0x0000)))?; - Ok((true, string_length)) + let size2 = Size::from_bytes(2); + let this = self.eval_context_mut(); + let tcx = &*this.tcx; + let ptr = this.force_ptr(sptr)?; // we need to write at least the 0 terminator + let alloc = this.memory.get_raw_mut(ptr.alloc_id)?; + for (offset, wchar) in u16_vec.into_iter().chain(iter::once(0x0000)).enumerate() { + let offset = u64::try_from(offset).unwrap(); + alloc.write_scalar( + tcx, + ptr.offset(size2 * offset, tcx)?, + Scalar::from_u16(wchar).into(), + size2, + )?; + } + Ok((true, string_length - 1)) } /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes. @@ -178,13 +190,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Read a null-terminated sequence of bytes, and perform path separator conversion if needed. - fn read_path_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, Cow<'a, Path>> + fn read_path_from_c_str<'a>(&'a self, sptr: Scalar) -> InterpResult<'tcx, Cow<'a, Path>> where 'tcx: 'a, 'mir: 'a, { let this = self.eval_context_ref(); - let os_str = this.read_os_str_from_c_str(scalar)?; + let os_str = this.read_os_str_from_c_str(sptr)?; Ok(match this.convert_path_separator(Cow::Borrowed(os_str), PathConversion::TargetToHost) { Cow::Borrowed(x) => Cow::Borrowed(Path::new(x)), @@ -193,9 +205,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Read a null-terminated sequence of `u16`s, and perform path separator conversion if needed. - fn read_path_from_wide_str(&self, scalar: Scalar) -> InterpResult<'tcx, PathBuf> { + fn read_path_from_wide_str(&self, sptr: Scalar) -> InterpResult<'tcx, PathBuf> { let this = self.eval_context_ref(); - let os_str = this.read_os_str_from_wide_str(scalar)?; + let os_str = this.read_os_str_from_wide_str(sptr)?; Ok(this .convert_path_separator(Cow::Owned(os_str), PathConversion::TargetToHost) @@ -208,13 +220,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_path_to_c_str( &mut self, path: &Path, - scalar: Scalar, + sptr: Scalar, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); let os_str = this .convert_path_separator(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); - this.write_os_str_to_c_str(&os_str, scalar, size) + this.write_os_str_to_c_str(&os_str, sptr, size) } /// Write a Path to the machine memory (as a null-terminated sequence of `u16`s), @@ -222,13 +234,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_path_to_wide_str( &mut self, path: &Path, - scalar: Scalar, + sptr: Scalar, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); let os_str = this .convert_path_separator(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); - this.write_os_str_to_wide_str(&os_str, scalar, size) + this.write_os_str_to_wide_str(&os_str, sptr, size) } fn convert_path_separator<'a>( diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index b3d53cdc10de..52b41b49bd5e 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -187,7 +187,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[ref handle, ref symbol] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_usize(this)?; let symbol = this.read_scalar(symbol)?.check_init()?; - let symbol_name = this.memory.read_c_str(symbol)?; + let symbol_name = this.read_c_str(symbol)?; if let Some(dlsym) = Dlsym::from_str(symbol_name, &this.tcx.sess.target.os)? { let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); this.write_scalar(Scalar::from(ptr), dest)?; diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index 214a2ce411d6..1e4597848914 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -111,7 +111,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let option = this.read_scalar(option)?.to_i32()?; if option == this.eval_libc_i32("PR_SET_NAME")? { let address = this.read_scalar(arg2)?.check_init()?; - let mut name = this.memory.read_c_str(address)?.to_owned(); + let mut name = this.read_c_str(address)?.to_owned(); // The name should be no more than 16 bytes, including the null // byte. Since `read_c_str` returns the string without the null // byte, we need to truncate to 15. @@ -134,7 +134,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("macos", "pthread_setname_np"); - let name = this.memory.read_c_str(name)?.to_owned(); + let name = this.read_c_str(name)?.to_owned(); this.set_active_thread_name(name); Ok(()) diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index f29870ff7cb7..b246ccc33cf7 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -271,7 +271,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] let &[ref hModule, ref lpProcName] = check_arg_count(args)?; this.read_scalar(hModule)?.to_machine_isize(this)?; - let name = this.memory.read_c_str(this.read_scalar(lpProcName)?.check_init()?)?; + let name = this.read_c_str(this.read_scalar(lpProcName)?.check_init()?)?; if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.os)? { let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); this.write_scalar(Scalar::from(ptr), dest)?; From 1bfd9ac56cc19b7a5e91e47fb6685ea57d50e20e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 May 2021 00:11:05 +0200 Subject: [PATCH 2657/5092] rustup --- rust-version | 2 +- src/machine.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 600ef9d5a6e3..3482331f593e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -3396a383bb1d1fdad8ceeb74f16cf08e0bd62a1b +3e99439f4dacc8ba0d2ca48d221694362d587927 diff --git a/src/machine.rs b/src/machine.rs index 635f3297b4e9..51e0d8f6a6fc 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -478,14 +478,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { let alloc = alloc.into_owned(); let (stacks, base_tag) = if let Some(stacked_borrows) = &memory_extra.stacked_borrows { let (stacks, base_tag) = - Stacks::new_allocation(id, alloc.size, Rc::clone(stacked_borrows), kind); + Stacks::new_allocation(id, alloc.size(), Rc::clone(stacked_borrows), kind); (Some(stacks), base_tag) } else { // No stacks, no tag. (None, Tag::Untagged) }; let race_alloc = if let Some(data_race) = &memory_extra.data_race { - Some(data_race::AllocExtra::new_allocation(&data_race, alloc.size, kind)) + Some(data_race::AllocExtra::new_allocation(&data_race, alloc.size(), kind)) } else { None }; From 952066f545c67c2c384ac0197dbf815b551f3720 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 May 2021 10:47:17 +0200 Subject: [PATCH 2658/5092] add (bors-ignored) formatting check job --- .github/workflows/ci.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d3d5d65bb94e..b99d8499d05d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -92,11 +92,34 @@ jobs: - name: Test run: bash ./ci.sh + fmt: + name: Check formatting (ignored by bors) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install latest nightly + uses: actions-rs/toolchain@v1 + with: + toolchain: nightly + components: rustfmt + override: true + - name: Check formatting (miri) + uses: actions-rs/cargo@v1 + with: + command: fmt + args: --all -- --check + - name: Check formatting (cargo-miri) + uses: actions-rs/cargo@v1 + with: + command: fmt + args: --manifest-path cargo-miri/Cargo.toml --all -- --check + # These jobs doesn't actually test anything, but they're only used to tell # bors the build completed, as there is no practical way to detect when a # workflow is successful listening to webhooks only. # # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! + # (`fmt` is deliberately not listed, we want bors to ignore it.) end-success: name: bors build finished runs-on: ubuntu-latest From 6f3ad27416b45acc7c947962f4585665d56fda30 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 May 2021 10:50:51 +0200 Subject: [PATCH 2659/5092] fmt --- benches/helpers/miri_helper.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 144ddc11968c..b26705cb704f 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -20,8 +20,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { compiler.session().abort_if_errors(); queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { - let (entry_def_id, _) = - tcx.entry_fn(()).expect("no main or start function found"); + let (entry_def_id, _) = tcx.entry_fn(()).expect("no main or start function found"); self.bencher.iter(|| { let config = miri::MiriConfig::default(); From 74ae89e6caf72f604fbcdd9be7d09038a2120a44 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 May 2021 10:57:38 +0200 Subject: [PATCH 2660/5092] over 'default' instead of 'override' (consistent with main build job) --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b99d8499d05d..889c584ba7c1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -93,7 +93,7 @@ jobs: run: bash ./ci.sh fmt: - name: Check formatting (ignored by bors) + name: check formatting (ignored by bors) runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 @@ -102,7 +102,7 @@ jobs: with: toolchain: nightly components: rustfmt - override: true + default: true - name: Check formatting (miri) uses: actions-rs/cargo@v1 with: From 801a1744cd6e509fb5aed5517a38238b7e987573 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 May 2021 13:50:45 +0200 Subject: [PATCH 2661/5092] update for Memory API changes --- src/data_race.rs | 4 +- src/diagnostics.rs | 8 +- src/helpers.rs | 15 ++- src/machine.rs | 104 ++++++++---------- src/shims/intrinsics.rs | 11 +- src/shims/os_str.rs | 17 ++- src/shims/posix/fs.rs | 10 +- src/shims/posix/linux/sync.rs | 3 +- src/stacked_borrows.rs | 2 +- .../compile-fail/data_race/alloc_read_race.rs | 3 +- 10 files changed, 88 insertions(+), 89 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index e8071845c7d7..bcc2e1765431 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -720,7 +720,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { if let Some(data_race) = &mut this.memory.extra.data_race { if data_race.multi_threaded.get() { let alloc_meta = - this.memory.get_raw_mut(ptr.alloc_id)?.extra.data_race.as_mut().unwrap(); + this.memory.get_alloc_extra_mut(ptr.alloc_id)?.data_race.as_mut().unwrap(); alloc_meta.reset_clocks(ptr.offset, size); } } @@ -1024,7 +1024,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let place_ptr = place.ptr.assert_ptr(); let size = place.layout.size; let alloc_meta = - &this.memory.get_raw(place_ptr.alloc_id)?.extra.data_race.as_ref().unwrap(); + &this.memory.get_alloc_extra(place_ptr.alloc_id)?.data_race.as_ref().unwrap(); log::trace!( "Atomic op({}) with ordering {:?} on memory({:?}, offset={}, size={})", description, diff --git a/src/diagnostics.rs b/src/diagnostics.rs index f074cfd4911b..ae50b5086022 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -136,13 +136,13 @@ pub fn report_error<'tcx, 'mir>( // Extra output to help debug specific issues. match e.kind() { - UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some(access))) => { + UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) => { eprintln!( "Uninitialized read occurred at offsets 0x{:x}..0x{:x} into this allocation:", - access.uninit_ptr.offset.bytes(), - access.uninit_ptr.offset.bytes() + access.uninit_size.bytes(), + access.uninit_offset.bytes(), + access.uninit_offset.bytes() + access.uninit_size.bytes(), ); - eprintln!("{:?}", ecx.memory.dump_alloc(access.uninit_ptr.alloc_id)); + eprintln!("{:?}", ecx.memory.dump_alloc(*alloc_id)); } _ => {} } diff --git a/src/helpers.rs b/src/helpers.rs index ef5ea9447808..45a5a8d4170b 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -8,7 +8,7 @@ use log::trace; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_middle::mir; use rustc_middle::ty::{self, layout::TyAndLayout, List, TyCtxt}; -use rustc_target::abi::{FieldsShape, LayoutOf, Size, Variants}; +use rustc_target::abi::{Align, FieldsShape, LayoutOf, Size, Variants}; use rustc_target::spec::abi::Abi; use rand::RngCore; @@ -577,10 +577,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.force_ptr(sptr)?; // We need to read at least 1 byte, so we can eagerly get a ptr. // Step 1: determine the length. - let alloc = this.memory.get_raw(ptr.alloc_id)?; let mut len = Size::ZERO; loop { - let byte = alloc.read_scalar(this, ptr.offset(len, this)?, size1)?.to_u8()?; + // FIXME: We are re-getting the allocation each time around the loop. + // Would be nice if we could somehow "extend" an existing AllocRange. + let alloc = this.memory.get(ptr.offset(len, this)?.into(), size1, Align::ONE)?.unwrap(); // not a ZST, so we will get a result + let byte = alloc.read_scalar(alloc_range(Size::ZERO, size1))?.to_u8()?; if byte == 0 { break; } else { @@ -595,12 +597,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn read_wide_str(&self, sptr: Scalar) -> InterpResult<'tcx, Vec> { let this = self.eval_context_ref(); let size2 = Size::from_bytes(2); + let align2 = Align::from_bytes(2).unwrap(); let mut ptr = this.force_ptr(sptr)?; // We need to read at least 1 wchar, so we can eagerly get a ptr. let mut wchars = Vec::new(); - let alloc = this.memory.get_raw(ptr.alloc_id)?; loop { - let wchar = alloc.read_scalar(this, ptr, size2)?.to_u16()?; + // FIXME: We are re-getting the allocation each time around the loop. + // Would be nice if we could somehow "extend" an existing AllocRange. + let alloc = this.memory.get(ptr.into(), size2, align2)?.unwrap(); // not a ZST, so we will get a result + let wchar = alloc.read_scalar(alloc_range(Size::ZERO, size2))?.to_u16()?; if wchar == 0 { break; } else { diff --git a/src/machine.rs b/src/machine.rs index 51e0d8f6a6fc..7ed8147753d2 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -506,15 +506,57 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } #[inline(always)] - fn before_deallocation( - memory_extra: &mut Self::MemoryExtra, - id: AllocId, + fn memory_read( + _memory_extra: &Self::MemoryExtra, + alloc: &Allocation, + ptr: Pointer, + size: Size, ) -> InterpResult<'tcx> { - if Some(id) == memory_extra.tracked_alloc_id { - register_diagnostic(NonHaltingDiagnostic::FreedAlloc(id)); + if let Some(data_race) = &alloc.extra.data_race { + data_race.read(ptr, size)?; } + if let Some(stacked_borrows) = &alloc.extra.stacked_borrows { + stacked_borrows.memory_read(ptr, size) + } else { + Ok(()) + } + } - Ok(()) + #[inline(always)] + fn memory_written( + _memory_extra: &mut Self::MemoryExtra, + alloc: &mut Allocation, + ptr: Pointer, + size: Size, + ) -> InterpResult<'tcx> { + if let Some(data_race) = &mut alloc.extra.data_race { + data_race.write(ptr, size)?; + } + if let Some(stacked_borrows) = &mut alloc.extra.stacked_borrows { + stacked_borrows.memory_written(ptr, size) + } else { + Ok(()) + } + } + + #[inline(always)] + fn memory_deallocated( + memory_extra: &mut Self::MemoryExtra, + alloc: &mut Allocation, + ptr: Pointer, + ) -> InterpResult<'tcx> { + let size = alloc.size(); + if Some(ptr.alloc_id) == memory_extra.tracked_alloc_id { + register_diagnostic(NonHaltingDiagnostic::FreedAlloc(ptr.alloc_id)); + } + if let Some(data_race) = &mut alloc.extra.data_race { + data_race.deallocate(ptr, size)?; + } + if let Some(stacked_borrows) = &mut alloc.extra.stacked_borrows { + stacked_borrows.memory_deallocated(ptr, size) + } else { + Ok(()) + } } fn after_static_mem_initialized( @@ -601,53 +643,3 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { intptrcast::GlobalState::ptr_to_int(ptr, memory) } } - -impl AllocationExtra for AllocExtra { - #[inline(always)] - fn memory_read<'tcx>( - alloc: &Allocation, - ptr: Pointer, - size: Size, - ) -> InterpResult<'tcx> { - if let Some(data_race) = &alloc.extra.data_race { - data_race.read(ptr, size)?; - } - if let Some(stacked_borrows) = &alloc.extra.stacked_borrows { - stacked_borrows.memory_read(ptr, size) - } else { - Ok(()) - } - } - - #[inline(always)] - fn memory_written<'tcx>( - alloc: &mut Allocation, - ptr: Pointer, - size: Size, - ) -> InterpResult<'tcx> { - if let Some(data_race) = &mut alloc.extra.data_race { - data_race.write(ptr, size)?; - } - if let Some(stacked_borrows) = &mut alloc.extra.stacked_borrows { - stacked_borrows.memory_written(ptr, size) - } else { - Ok(()) - } - } - - #[inline(always)] - fn memory_deallocated<'tcx>( - alloc: &mut Allocation, - ptr: Pointer, - size: Size, - ) -> InterpResult<'tcx> { - if let Some(data_race) = &mut alloc.extra.data_race { - data_race.deallocate(ptr, size)?; - } - if let Some(stacked_borrows) = &mut alloc.extra.stacked_borrows { - stacked_borrows.memory_deallocated(ptr, size) - } else { - Ok(()) - } - } -} diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index ee0e833f9e5f..3284d40bca62 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -574,7 +574,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + this.memory.check_ptr_access_align(place.ptr, place.layout.size, align, CheckInAllocMsg::MemoryAccessTest)?; + // Perform regular access. this.write_scalar(val, dest)?; Ok(()) } @@ -594,7 +595,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + this.memory.check_ptr_access_align(place.ptr, place.layout.size, align, CheckInAllocMsg::MemoryAccessTest)?; // Perform atomic store this.write_scalar_atomic(val, &place, atomic)?; @@ -644,7 +645,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + this.memory.check_ptr_access_align(place.ptr, place.layout.size, align, CheckInAllocMsg::MemoryAccessTest)?; match atomic_op { AtomicOp::Min => { @@ -681,7 +682,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + this.memory.check_ptr_access_align(place.ptr, place.layout.size, align, CheckInAllocMsg::MemoryAccessTest)?; let old = this.atomic_exchange_scalar(&place, new, atomic)?; this.write_scalar(old, dest)?; // old value is returned @@ -707,7 +708,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + this.memory.check_ptr_access_align(place.ptr, place.layout.size, align, CheckInAllocMsg::MemoryAccessTest)?; let old = this.atomic_compare_exchange_scalar( &place, diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index f1f14fa828f8..efcdc7b473a4 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -9,7 +9,7 @@ use std::os::unix::ffi::{OsStrExt, OsStringExt}; #[cfg(windows)] use std::os::windows::ffi::{OsStrExt, OsStringExt}; -use rustc_target::abi::{LayoutOf, Size}; +use rustc_target::abi::{Align, LayoutOf, Size}; use crate::*; @@ -144,17 +144,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Store the UTF-16 string. let size2 = Size::from_bytes(2); let this = self.eval_context_mut(); - let tcx = &*this.tcx; - let ptr = this.force_ptr(sptr)?; // we need to write at least the 0 terminator - let alloc = this.memory.get_raw_mut(ptr.alloc_id)?; + let mut alloc = this + .memory + .get_mut(sptr, Size::from_bytes(string_length), Align::from_bytes(2).unwrap())? + .unwrap(); // not a ZST, so we will get a result for (offset, wchar) in u16_vec.into_iter().chain(iter::once(0x0000)).enumerate() { let offset = u64::try_from(offset).unwrap(); - alloc.write_scalar( - tcx, - ptr.offset(size2 * offset, tcx)?, - Scalar::from_u16(wchar).into(), - size2, - )?; + alloc + .write_scalar(alloc_range(size2 * offset, size2), Scalar::from_u16(wchar).into())?; } Ok((true, string_length - 1)) } diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 234f03ff462c..06594e5ca1d6 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -677,10 +677,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("Reading from FD {}, size {}", fd, count); // Check that the *entire* buffer is actually valid memory. - this.memory.check_ptr_access( + this.memory.check_ptr_access_align( buf, Size::from_bytes(count), - Align::from_bytes(1).unwrap(), + Align::ONE, + CheckInAllocMsg::MemoryAccessTest, )?; // We cap the number of read bytes to the largest value that we are able to fit in both the @@ -722,10 +723,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Isolation check is done via `FileDescriptor` trait. // Check that the *entire* buffer is actually valid memory. - this.memory.check_ptr_access( + this.memory.check_ptr_access_align( buf, Size::from_bytes(count), - Align::from_bytes(1).unwrap(), + Align::ONE, + CheckInAllocMsg::MemoryAccessTest, )?; // We cap the number of written bytes to the largest value that we are able to fit in both the diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index c5101203eb46..fda70d815de2 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -82,10 +82,11 @@ pub fn futex<'tcx>( // Check the pointer for alignment and validity. // The API requires `addr` to be a 4-byte aligned pointer, and will // use the 4 bytes at the given address as an (atomic) i32. - this.memory.check_ptr_access( + this.memory.check_ptr_access_align( addr.to_scalar()?, Size::from_bytes(4), Align::from_bytes(4).unwrap(), + CheckInAllocMsg::MemoryAccessTest, )?; // Read an `i32` through the pointer, regardless of any wrapper types. // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`. diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 88f42efd13cf..1139e21e0f13 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -561,7 +561,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. - let extra = &this.memory.get_raw(ptr.alloc_id)?.extra; + let extra = this.memory.get_alloc_extra(ptr.alloc_id)?; let stacked_borrows = extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); // Update the stacks. diff --git a/tests/compile-fail/data_race/alloc_read_race.rs b/tests/compile-fail/data_race/alloc_read_race.rs index fc1e9d30e637..093c9024f202 100644 --- a/tests/compile-fail/data_race/alloc_read_race.rs +++ b/tests/compile-fail/data_race/alloc_read_race.rs @@ -1,4 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. +#![feature(new_uninit)] use std::thread::spawn; use std::ptr::null_mut; @@ -29,7 +30,7 @@ pub fn main() { // Uses relaxed semantics to not generate // a release sequence. let pointer = &*ptr.0; - pointer.store(Box::into_raw(Box::new(MaybeUninit::uninit())), Ordering::Relaxed); + pointer.store(Box::into_raw(Box::new_uninit()), Ordering::Relaxed); }); let j2 = spawn(move || { From dd404cc92e5fe967064fb43360e26db247410734 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 May 2021 13:56:00 +0200 Subject: [PATCH 2662/5092] avoid importing C functions in alloc_write_race test --- tests/compile-fail/data_race/alloc_write_race.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/tests/compile-fail/data_race/alloc_write_race.rs b/tests/compile-fail/data_race/alloc_write_race.rs index d9f5af396a2d..becebe6a122a 100644 --- a/tests/compile-fail/data_race/alloc_write_race.rs +++ b/tests/compile-fail/data_race/alloc_write_race.rs @@ -1,4 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. +#![feature(new_uninit)] use std::thread::spawn; use std::ptr::null_mut; @@ -10,11 +11,6 @@ struct EvilSend(pub T); unsafe impl Send for EvilSend {} unsafe impl Sync for EvilSend {} -extern "C" { - fn malloc(size: usize) -> *mut u8; - fn free(ptr: *mut u8); -} - pub fn main() { // Shared atomic pointer let pointer = AtomicPtr::new(null_mut::()); @@ -33,7 +29,7 @@ pub fn main() { // Uses relaxed semantics to not generate // a release sequence. let pointer = &*ptr.0; - pointer.store(malloc(std::mem::size_of::()) as *mut usize, Ordering::Relaxed); + pointer.store(Box::into_raw(Box::::new_uninit()) as *mut usize, Ordering::Relaxed); }); let j2 = spawn(move || { @@ -45,6 +41,6 @@ pub fn main() { j2.join().unwrap(); // Clean up memory, will never be executed - free(pointer.load(Ordering::Relaxed) as *mut _); + drop(Box::from_raw(pointer.load(Ordering::Relaxed))); } } From d1e5eeebdfdf92c9b5afe9552e7532624b1603da Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 May 2021 15:58:05 +0200 Subject: [PATCH 2663/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 3482331f593e..143d077e3c20 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -3e99439f4dacc8ba0d2ca48d221694362d587927 +3e827cc21e0734edd26170e8d1481f0d66a1426b From e4a27150cb201fbe5aedda3748b08d3428bba5e0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 May 2021 16:10:28 +0200 Subject: [PATCH 2664/5092] fmt --- src/shims/intrinsics.rs | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 3284d40bca62..f2979a3c69d8 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -574,7 +574,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access_align(place.ptr, place.layout.size, align, CheckInAllocMsg::MemoryAccessTest)?; + this.memory.check_ptr_access_align( + place.ptr, + place.layout.size, + align, + CheckInAllocMsg::MemoryAccessTest, + )?; // Perform regular access. this.write_scalar(val, dest)?; Ok(()) @@ -595,7 +600,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access_align(place.ptr, place.layout.size, align, CheckInAllocMsg::MemoryAccessTest)?; + this.memory.check_ptr_access_align( + place.ptr, + place.layout.size, + align, + CheckInAllocMsg::MemoryAccessTest, + )?; // Perform atomic store this.write_scalar_atomic(val, &place, atomic)?; @@ -645,7 +655,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access_align(place.ptr, place.layout.size, align, CheckInAllocMsg::MemoryAccessTest)?; + this.memory.check_ptr_access_align( + place.ptr, + place.layout.size, + align, + CheckInAllocMsg::MemoryAccessTest, + )?; match atomic_op { AtomicOp::Min => { @@ -682,7 +697,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access_align(place.ptr, place.layout.size, align, CheckInAllocMsg::MemoryAccessTest)?; + this.memory.check_ptr_access_align( + place.ptr, + place.layout.size, + align, + CheckInAllocMsg::MemoryAccessTest, + )?; let old = this.atomic_exchange_scalar(&place, new, atomic)?; this.write_scalar(old, dest)?; // old value is returned @@ -708,7 +728,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access_align(place.ptr, place.layout.size, align, CheckInAllocMsg::MemoryAccessTest)?; + this.memory.check_ptr_access_align( + place.ptr, + place.layout.size, + align, + CheckInAllocMsg::MemoryAccessTest, + )?; let old = this.atomic_compare_exchange_scalar( &place, From aba96b82b4a9600ea8d01934c799f0539def356b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 May 2021 16:34:14 +0200 Subject: [PATCH 2665/5092] fix write_os_str_to_wide_str --- src/shims/os_str.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index efcdc7b473a4..8a3f5677706e 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -146,7 +146,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let mut alloc = this .memory - .get_mut(sptr, Size::from_bytes(string_length), Align::from_bytes(2).unwrap())? + .get_mut(sptr, size2 * string_length, Align::from_bytes(2).unwrap())? .unwrap(); // not a ZST, so we will get a result for (offset, wchar) in u16_vec.into_iter().chain(iter::once(0x0000)).enumerate() { let offset = u64::try_from(offset).unwrap(); From c151af5cf597d66251d4ab56cffc67a2f0507365 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 20 May 2021 13:32:18 +0200 Subject: [PATCH 2666/5092] rustup --- rust-version | 2 +- src/machine.rs | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/rust-version b/rust-version index 143d077e3c20..7004235a38f0 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -3e827cc21e0734edd26170e8d1481f0d66a1426b +35bab923c8e5a1e8291735e7630539002eb80d7b diff --git a/src/machine.rs b/src/machine.rs index 7ed8147753d2..2f407dd09a91 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -508,14 +508,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn memory_read( _memory_extra: &Self::MemoryExtra, - alloc: &Allocation, + alloc_extra: &AllocExtra, ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - if let Some(data_race) = &alloc.extra.data_race { + if let Some(data_race) = &alloc_extra.data_race { data_race.read(ptr, size)?; } - if let Some(stacked_borrows) = &alloc.extra.stacked_borrows { + if let Some(stacked_borrows) = &alloc_extra.stacked_borrows { stacked_borrows.memory_read(ptr, size) } else { Ok(()) @@ -525,14 +525,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn memory_written( _memory_extra: &mut Self::MemoryExtra, - alloc: &mut Allocation, + alloc_extra: &mut AllocExtra, ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - if let Some(data_race) = &mut alloc.extra.data_race { + if let Some(data_race) = &mut alloc_extra.data_race { data_race.write(ptr, size)?; } - if let Some(stacked_borrows) = &mut alloc.extra.stacked_borrows { + if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { stacked_borrows.memory_written(ptr, size) } else { Ok(()) @@ -542,17 +542,17 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn memory_deallocated( memory_extra: &mut Self::MemoryExtra, - alloc: &mut Allocation, + alloc_extra: &mut AllocExtra, ptr: Pointer, + size: Size, ) -> InterpResult<'tcx> { - let size = alloc.size(); if Some(ptr.alloc_id) == memory_extra.tracked_alloc_id { register_diagnostic(NonHaltingDiagnostic::FreedAlloc(ptr.alloc_id)); } - if let Some(data_race) = &mut alloc.extra.data_race { + if let Some(data_race) = &mut alloc_extra.data_race { data_race.deallocate(ptr, size)?; } - if let Some(stacked_borrows) = &mut alloc.extra.stacked_borrows { + if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { stacked_borrows.memory_deallocated(ptr, size) } else { Ok(()) From ca7283d746012397faa266b39dee78609b74ed64 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 22 May 2021 13:24:08 +0200 Subject: [PATCH 2667/5092] get rid of Rc in Stacked Borrows --- src/machine.rs | 18 +++++++++--------- src/stacked_borrows.rs | 41 ++++++++++++++++++++--------------------- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 2f407dd09a91..0e0f3ad1568b 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -116,7 +116,7 @@ pub struct AllocExtra { } /// Extra global memory data -#[derive(Clone, Debug)] +#[derive(Debug)] pub struct MemoryExtra { pub stacked_borrows: Option, pub data_race: Option, @@ -144,11 +144,11 @@ impl MemoryExtra { pub fn new(config: &MiriConfig) -> Self { let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0)); let stacked_borrows = if config.stacked_borrows { - Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new( + Some(RefCell::new(stacked_borrows::GlobalState::new( config.tracked_pointer_tag, config.tracked_call_id, config.track_raw, - )))) + ))) } else { None }; @@ -478,7 +478,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { let alloc = alloc.into_owned(); let (stacks, base_tag) = if let Some(stacked_borrows) = &memory_extra.stacked_borrows { let (stacks, base_tag) = - Stacks::new_allocation(id, alloc.size(), Rc::clone(stacked_borrows), kind); + Stacks::new_allocation(id, alloc.size(), stacked_borrows, kind); (Some(stacks), base_tag) } else { // No stacks, no tag. @@ -507,7 +507,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn memory_read( - _memory_extra: &Self::MemoryExtra, + memory_extra: &Self::MemoryExtra, alloc_extra: &AllocExtra, ptr: Pointer, size: Size, @@ -516,7 +516,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { data_race.read(ptr, size)?; } if let Some(stacked_borrows) = &alloc_extra.stacked_borrows { - stacked_borrows.memory_read(ptr, size) + stacked_borrows.memory_read(ptr, size, memory_extra.stacked_borrows.as_ref().unwrap()) } else { Ok(()) } @@ -524,7 +524,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn memory_written( - _memory_extra: &mut Self::MemoryExtra, + memory_extra: &mut Self::MemoryExtra, alloc_extra: &mut AllocExtra, ptr: Pointer, size: Size, @@ -533,7 +533,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { data_race.write(ptr, size)?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { - stacked_borrows.memory_written(ptr, size) + stacked_borrows.memory_written(ptr, size, memory_extra.stacked_borrows.as_mut().unwrap()) } else { Ok(()) } @@ -553,7 +553,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { data_race.deallocate(ptr, size)?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { - stacked_borrows.memory_deallocated(ptr, size) + stacked_borrows.memory_deallocated(ptr, size, memory_extra.stacked_borrows.as_mut().unwrap()) } else { Ok(()) } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 1139e21e0f13..87f8e4886933 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -4,8 +4,6 @@ use std::cell::RefCell; use std::fmt; use std::num::NonZeroU64; -use std::rc::Rc; - use log::trace; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -87,8 +85,6 @@ pub struct Stack { pub struct Stacks { // Even reading memory can have effects on the stack, so we need a `RefCell` here. stacks: RefCell>, - // Pointer to global state - global: MemoryExtra, } /// Extra global state, available to the memory access hooks. @@ -112,7 +108,7 @@ pub struct GlobalState { track_raw: bool, } /// Memory extra state gives us interior mutable access to the global state. -pub type MemoryExtra = Rc>; +pub type MemoryExtra = RefCell; /// Indicates which kind of access is being performed. #[derive(Copy, Clone, Hash, PartialEq, Eq)] @@ -449,11 +445,11 @@ impl<'tcx> Stack { /// Map per-stack operations to higher-level per-location-range operations. impl<'tcx> Stacks { /// Creates new stack with initial tag. - fn new(size: Size, perm: Permission, tag: Tag, extra: MemoryExtra) -> Self { + fn new(size: Size, perm: Permission, tag: Tag) -> Self { let item = Item { perm, tag, protector: None }; let stack = Stack { borrows: vec![item] }; - Stacks { stacks: RefCell::new(RangeMap::new(size, stack)), global: extra } + Stacks { stacks: RefCell::new(RangeMap::new(size, stack)) } } /// Call `f` on every stack in the range. @@ -461,9 +457,9 @@ impl<'tcx> Stacks { &self, ptr: Pointer, size: Size, + global: &GlobalState, f: impl Fn(Pointer, &mut Stack, &GlobalState) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { - let global = self.global.borrow(); let mut stacks = self.stacks.borrow_mut(); for (offset, stack) in stacks.iter_mut(ptr.offset, size) { let mut cur_ptr = ptr; @@ -479,16 +475,17 @@ impl Stacks { pub fn new_allocation( id: AllocId, size: Size, - extra: MemoryExtra, + extra: &MemoryExtra, kind: MemoryKind, ) -> (Self, Tag) { + let mut extra = extra.borrow_mut(); let (tag, perm) = match kind { // New unique borrow. This tag is not accessible by the program, // so it will only ever be used when using the local directly (i.e., // not through a pointer). That is, whenever we directly write to a local, this will pop // everything else off the stack, invalidating all previous pointers, // and in particular, *all* raw pointers. - MemoryKind::Stack => (Tag::Tagged(extra.borrow_mut().new_ptr()), Permission::Unique), + MemoryKind::Stack => (Tag::Tagged(extra.new_ptr()), Permission::Unique), // `Global` memory can be referenced by global pointers from `tcx`. // Thus we call `global_base_ptr` such that the global pointers get the same tag // as what we use here. @@ -500,28 +497,27 @@ impl Stacks { | MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls | MiriMemoryKind::Env, - ) => (extra.borrow_mut().global_base_ptr(id), Permission::SharedReadWrite), + ) => (extra.global_base_ptr(id), Permission::SharedReadWrite), // Everything else we handle like raw pointers for now. _ => { - let mut extra = extra.borrow_mut(); let tag = if extra.track_raw { Tag::Tagged(extra.new_ptr()) } else { Tag::Untagged }; (tag, Permission::SharedReadWrite) } }; - (Stacks::new(size, perm, tag, extra), tag) + (Stacks::new(size, perm, tag), tag) } #[inline(always)] - pub fn memory_read<'tcx>(&self, ptr: Pointer, size: Size) -> InterpResult<'tcx> { + pub fn memory_read<'tcx>(&self, ptr: Pointer, size: Size, extra: &MemoryExtra) -> InterpResult<'tcx> { trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - self.for_each(ptr, size, |ptr, stack, global| stack.access(AccessKind::Read, ptr, global)) + self.for_each(ptr, size, &*extra.borrow(), |ptr, stack, global| stack.access(AccessKind::Read, ptr, global)) } #[inline(always)] - pub fn memory_written<'tcx>(&mut self, ptr: Pointer, size: Size) -> InterpResult<'tcx> { + pub fn memory_written<'tcx>(&mut self, ptr: Pointer, size: Size, extra: &mut MemoryExtra) -> InterpResult<'tcx> { trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - self.for_each(ptr, size, |ptr, stack, global| stack.access(AccessKind::Write, ptr, global)) + self.for_each(ptr, size, extra.get_mut(), |ptr, stack, global| stack.access(AccessKind::Write, ptr, global)) } #[inline(always)] @@ -529,9 +525,10 @@ impl Stacks { &mut self, ptr: Pointer, size: Size, + extra: &mut MemoryExtra, ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - self.for_each(ptr, size, |ptr, stack, global| stack.dealloc(ptr, global)) + self.for_each(ptr, size, extra.get_mut(), |ptr, stack, global| stack.dealloc(ptr, global)) } } @@ -560,10 +557,12 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size.bytes() ); - // Get the allocation. It might not be mutable, so we cannot use `get_mut`. + // Get the allocation. We need both the allocation and the MemoryExtra, so we cannot use `&mut`. + // FIXME: make `get_alloc_extra_mut` also return `&mut MemoryExtra`. let extra = this.memory.get_alloc_extra(ptr.alloc_id)?; let stacked_borrows = extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); + let global = this.memory.extra.stacked_borrows.as_ref().unwrap().borrow(); // Update the stacks. // Make sure that raw pointers and mutable shared references are reborrowed "weak": // There could be existing unique pointers reborrowed from them that should remain valid! @@ -583,14 +582,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Permission::SharedReadWrite }; let item = Item { perm, tag: new_tag, protector }; - stacked_borrows.for_each(cur_ptr, size, |cur_ptr, stack, global| { + stacked_borrows.for_each(cur_ptr, size, &*global, |cur_ptr, stack, global| { stack.grant(cur_ptr, item, global) }) }); } }; let item = Item { perm, tag: new_tag, protector }; - stacked_borrows.for_each(ptr, size, |ptr, stack, global| stack.grant(ptr, item, global)) + stacked_borrows.for_each(ptr, size, &*global, |ptr, stack, global| stack.grant(ptr, item, global)) } /// Retags an indidual pointer, returning the retagged version. From 1bbd6e609cb1fef17e7454bb6ced66a37f743ded Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 22 May 2021 14:47:14 +0200 Subject: [PATCH 2668/5092] get rid of Rc in data_race --- src/data_race.rs | 37 ++++++++++++++++--------------------- src/machine.rs | 9 ++++----- src/thread.rs | 7 +++---- 3 files changed, 23 insertions(+), 30 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index bcc2e1765431..ff6c720740a1 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -65,7 +65,6 @@ use std::{ cell::{Cell, Ref, RefCell, RefMut}, fmt::Debug, mem, - rc::Rc, }; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -80,7 +79,7 @@ use crate::{ }; pub type AllocExtra = VClockAlloc; -pub type MemoryExtra = Rc; +pub type MemoryExtra = GlobalState; /// Valid atomic read-write operations, alias of atomic::Ordering (not non-exhaustive). #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -488,7 +487,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_ref(); let scalar = this.allow_data_races_ref(move |this| this.read_scalar(&place.into()))?; - self.validate_atomic_load(place, atomic)?; + this.validate_atomic_load(place, atomic)?; Ok(scalar) } @@ -501,7 +500,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.allow_data_races_mut(move |this| this.write_scalar(val, &(*dest).into()))?; - self.validate_atomic_store(dest, atomic) + this.validate_atomic_store(dest, atomic) } /// Perform a atomic operation on a memory location. @@ -733,9 +732,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { pub struct VClockAlloc { /// Assigning each byte a MemoryCellClocks. alloc_ranges: RefCell>, - - /// Pointer to global state. - global: MemoryExtra, } impl VClockAlloc { @@ -767,7 +763,6 @@ impl VClockAlloc { | MemoryKind::Vtable => (0, VectorIdx::MAX_INDEX), }; VClockAlloc { - global: Rc::clone(global), alloc_ranges: RefCell::new(RangeMap::new( len, MemoryCellClocks::new(alloc_timestamp, alloc_index), @@ -888,15 +883,15 @@ impl VClockAlloc { /// being created or if it is temporarily disabled during a racy read or write /// operation for which data-race detection is handled separately, for example /// atomic read operations. - pub fn read<'tcx>(&self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { - if self.global.multi_threaded.get() { - let (index, clocks) = self.global.current_thread_state(); + pub fn read<'tcx>(&self, pointer: Pointer, len: Size, global: &GlobalState) -> InterpResult<'tcx> { + if global.multi_threaded.get() { + let (index, clocks) = global.current_thread_state(); let mut alloc_ranges = self.alloc_ranges.borrow_mut(); for (_, range) in alloc_ranges.iter_mut(pointer.offset, len) { if let Err(DataRace) = range.read_race_detect(&*clocks, index) { // Report data-race. return Self::report_data_race( - &self.global, + global, range, "Read", false, @@ -917,14 +912,15 @@ impl VClockAlloc { pointer: Pointer, len: Size, write_type: WriteType, + global: &mut GlobalState, ) -> InterpResult<'tcx> { - if self.global.multi_threaded.get() { - let (index, clocks) = self.global.current_thread_state(); + if global.multi_threaded.get() { + let (index, clocks) = global.current_thread_state(); for (_, range) in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { if let Err(DataRace) = range.write_race_detect(&*clocks, index, write_type) { // Report data-race return Self::report_data_race( - &self.global, + global, range, write_type.get_descriptor(), false, @@ -943,16 +939,16 @@ impl VClockAlloc { /// data-race threads if `multi-threaded` is false, either due to no threads /// being created or if it is temporarily disabled during a racy read or write /// operation - pub fn write<'tcx>(&mut self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { - self.unique_access(pointer, len, WriteType::Write) + pub fn write<'tcx>(&mut self, pointer: Pointer, len: Size, global: &mut GlobalState) -> InterpResult<'tcx> { + self.unique_access(pointer, len, WriteType::Write, global) } /// Detect data-races for an unsynchronized deallocate operation, will not perform /// data-race threads if `multi-threaded` is false, either due to no threads /// being created or if it is temporarily disabled during a racy read or write /// operation - pub fn deallocate<'tcx>(&mut self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { - self.unique_access(pointer, len, WriteType::Deallocate) + pub fn deallocate<'tcx>(&mut self, pointer: Pointer, len: Size, global: &mut GlobalState) -> InterpResult<'tcx> { + self.unique_access(pointer, len, WriteType::Deallocate, global) } } @@ -1035,7 +1031,6 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ); // Perform the atomic operation. - let data_race = &alloc_meta.global; data_race.maybe_perform_sync_operation(|index, mut clocks| { for (_, range) in alloc_meta.alloc_ranges.borrow_mut().iter_mut(place_ptr.offset, size) @@ -1043,7 +1038,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { if let Err(DataRace) = op(range, &mut *clocks, index, atomic) { mem::drop(clocks); return VClockAlloc::report_data_race( - &alloc_meta.global, + data_race, range, description, true, diff --git a/src/machine.rs b/src/machine.rs index 0e0f3ad1568b..ce4b96ad4a46 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -5,7 +5,6 @@ use std::borrow::Cow; use std::cell::RefCell; use std::fmt; use std::num::NonZeroU64; -use std::rc::Rc; use std::time::Instant; use log::trace; @@ -153,7 +152,7 @@ impl MemoryExtra { None }; let data_race = if config.data_race_detector { - Some(Rc::new(data_race::GlobalState::new())) + Some(data_race::GlobalState::new()) } else { None }; @@ -513,7 +512,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { size: Size, ) -> InterpResult<'tcx> { if let Some(data_race) = &alloc_extra.data_race { - data_race.read(ptr, size)?; + data_race.read(ptr, size, memory_extra.data_race.as_ref().unwrap())?; } if let Some(stacked_borrows) = &alloc_extra.stacked_borrows { stacked_borrows.memory_read(ptr, size, memory_extra.stacked_borrows.as_ref().unwrap()) @@ -530,7 +529,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { size: Size, ) -> InterpResult<'tcx> { if let Some(data_race) = &mut alloc_extra.data_race { - data_race.write(ptr, size)?; + data_race.write(ptr, size, memory_extra.data_race.as_mut().unwrap())?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { stacked_borrows.memory_written(ptr, size, memory_extra.stacked_borrows.as_mut().unwrap()) @@ -550,7 +549,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { register_diagnostic(NonHaltingDiagnostic::FreedAlloc(ptr.alloc_id)); } if let Some(data_race) = &mut alloc_extra.data_race { - data_race.deallocate(ptr, size)?; + data_race.deallocate(ptr, size, memory_extra.data_race.as_mut().unwrap())?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { stacked_borrows.memory_deallocated(ptr, size, memory_extra.stacked_borrows.as_mut().unwrap()) diff --git a/src/thread.rs b/src/thread.rs index 7d6fe8041e98..8aaeb7e349c6 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -4,7 +4,6 @@ use std::cell::RefCell; use std::collections::hash_map::Entry; use std::convert::TryFrom; use std::num::TryFromIntError; -use std::rc::Rc; use std::time::{Duration, Instant, SystemTime}; use log::trace; @@ -333,7 +332,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { fn join_thread( &mut self, joined_thread_id: ThreadId, - data_race: &Option>, + data_race: &Option, ) -> InterpResult<'tcx> { if self.threads[joined_thread_id].join_status != ThreadJoinStatus::Joinable { throw_ub_format!("trying to join a detached or already joined thread"); @@ -439,7 +438,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// The `AllocId` that can now be freed is returned. fn thread_terminated( &mut self, - data_race: &Option>, + data_race: &Option, ) -> Vec { let mut free_tls_statics = Vec::new(); { @@ -481,7 +480,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// blocked, terminated, or has explicitly asked to be preempted). fn schedule( &mut self, - data_race: &Option>, + data_race: &Option, ) -> InterpResult<'tcx, SchedulingAction> { // Check whether the thread has **just** terminated (`check_terminated` // checks whether the thread has popped all its stack and if yes, sets From c73f8b1097e9e5d01baa56df9bb4cd93f3828fd4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 22 May 2021 14:55:33 +0200 Subject: [PATCH 2669/5092] fmt --- src/data_race.rs | 30 +++++++++++++++++++----------- src/machine.rs | 19 ++++++++++++------- src/stacked_borrows.rs | 27 +++++++++++++++++++++------ src/thread.rs | 5 +---- 4 files changed, 53 insertions(+), 28 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index ff6c720740a1..16ab03ace222 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -883,21 +883,19 @@ impl VClockAlloc { /// being created or if it is temporarily disabled during a racy read or write /// operation for which data-race detection is handled separately, for example /// atomic read operations. - pub fn read<'tcx>(&self, pointer: Pointer, len: Size, global: &GlobalState) -> InterpResult<'tcx> { + pub fn read<'tcx>( + &self, + pointer: Pointer, + len: Size, + global: &GlobalState, + ) -> InterpResult<'tcx> { if global.multi_threaded.get() { let (index, clocks) = global.current_thread_state(); let mut alloc_ranges = self.alloc_ranges.borrow_mut(); for (_, range) in alloc_ranges.iter_mut(pointer.offset, len) { if let Err(DataRace) = range.read_race_detect(&*clocks, index) { // Report data-race. - return Self::report_data_race( - global, - range, - "Read", - false, - pointer, - len, - ); + return Self::report_data_race(global, range, "Read", false, pointer, len); } } Ok(()) @@ -939,7 +937,12 @@ impl VClockAlloc { /// data-race threads if `multi-threaded` is false, either due to no threads /// being created or if it is temporarily disabled during a racy read or write /// operation - pub fn write<'tcx>(&mut self, pointer: Pointer, len: Size, global: &mut GlobalState) -> InterpResult<'tcx> { + pub fn write<'tcx>( + &mut self, + pointer: Pointer, + len: Size, + global: &mut GlobalState, + ) -> InterpResult<'tcx> { self.unique_access(pointer, len, WriteType::Write, global) } @@ -947,7 +950,12 @@ impl VClockAlloc { /// data-race threads if `multi-threaded` is false, either due to no threads /// being created or if it is temporarily disabled during a racy read or write /// operation - pub fn deallocate<'tcx>(&mut self, pointer: Pointer, len: Size, global: &mut GlobalState) -> InterpResult<'tcx> { + pub fn deallocate<'tcx>( + &mut self, + pointer: Pointer, + len: Size, + global: &mut GlobalState, + ) -> InterpResult<'tcx> { self.unique_access(pointer, len, WriteType::Deallocate, global) } } diff --git a/src/machine.rs b/src/machine.rs index ce4b96ad4a46..fb2d877c3803 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -151,11 +151,8 @@ impl MemoryExtra { } else { None }; - let data_race = if config.data_race_detector { - Some(data_race::GlobalState::new()) - } else { - None - }; + let data_race = + if config.data_race_detector { Some(data_race::GlobalState::new()) } else { None }; MemoryExtra { stacked_borrows, data_race, @@ -532,7 +529,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { data_race.write(ptr, size, memory_extra.data_race.as_mut().unwrap())?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { - stacked_borrows.memory_written(ptr, size, memory_extra.stacked_borrows.as_mut().unwrap()) + stacked_borrows.memory_written( + ptr, + size, + memory_extra.stacked_borrows.as_mut().unwrap(), + ) } else { Ok(()) } @@ -552,7 +553,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { data_race.deallocate(ptr, size, memory_extra.data_race.as_mut().unwrap())?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { - stacked_borrows.memory_deallocated(ptr, size, memory_extra.stacked_borrows.as_mut().unwrap()) + stacked_borrows.memory_deallocated( + ptr, + size, + memory_extra.stacked_borrows.as_mut().unwrap(), + ) } else { Ok(()) } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 87f8e4886933..a9c030c87de4 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -1,10 +1,10 @@ //! Implements "Stacked Borrows". See //! for further information. +use log::trace; use std::cell::RefCell; use std::fmt; use std::num::NonZeroU64; -use log::trace; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::Mutability; @@ -509,15 +509,29 @@ impl Stacks { } #[inline(always)] - pub fn memory_read<'tcx>(&self, ptr: Pointer, size: Size, extra: &MemoryExtra) -> InterpResult<'tcx> { + pub fn memory_read<'tcx>( + &self, + ptr: Pointer, + size: Size, + extra: &MemoryExtra, + ) -> InterpResult<'tcx> { trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - self.for_each(ptr, size, &*extra.borrow(), |ptr, stack, global| stack.access(AccessKind::Read, ptr, global)) + self.for_each(ptr, size, &*extra.borrow(), |ptr, stack, global| { + stack.access(AccessKind::Read, ptr, global) + }) } #[inline(always)] - pub fn memory_written<'tcx>(&mut self, ptr: Pointer, size: Size, extra: &mut MemoryExtra) -> InterpResult<'tcx> { + pub fn memory_written<'tcx>( + &mut self, + ptr: Pointer, + size: Size, + extra: &mut MemoryExtra, + ) -> InterpResult<'tcx> { trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - self.for_each(ptr, size, extra.get_mut(), |ptr, stack, global| stack.access(AccessKind::Write, ptr, global)) + self.for_each(ptr, size, extra.get_mut(), |ptr, stack, global| { + stack.access(AccessKind::Write, ptr, global) + }) } #[inline(always)] @@ -589,7 +603,8 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } }; let item = Item { perm, tag: new_tag, protector }; - stacked_borrows.for_each(ptr, size, &*global, |ptr, stack, global| stack.grant(ptr, item, global)) + stacked_borrows + .for_each(ptr, size, &*global, |ptr, stack, global| stack.grant(ptr, item, global)) } /// Retags an indidual pointer, returning the retagged version. diff --git a/src/thread.rs b/src/thread.rs index 8aaeb7e349c6..3418e8c7d2bf 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -436,10 +436,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Wakes up threads joining on the active one and deallocates thread-local statics. /// The `AllocId` that can now be freed is returned. - fn thread_terminated( - &mut self, - data_race: &Option, - ) -> Vec { + fn thread_terminated(&mut self, data_race: &Option) -> Vec { let mut free_tls_statics = Vec::new(); { let mut thread_local_statics = self.thread_local_alloc_ids.borrow_mut(); From d77d95d0a8ea90e87cbc872cacdd89540e11142c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 May 2021 12:39:27 +0200 Subject: [PATCH 2670/5092] rustup --- rust-version | 2 +- src/data_race.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 7004235a38f0..bc7ef53b3037 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -35bab923c8e5a1e8291735e7630539002eb80d7b +6e92fb409816c65cd0a78a1fbcc71e2fbabdf50a diff --git a/src/data_race.rs b/src/data_race.rs index 16ab03ace222..fb6bf8f89295 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -719,7 +719,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { if let Some(data_race) = &mut this.memory.extra.data_race { if data_race.multi_threaded.get() { let alloc_meta = - this.memory.get_alloc_extra_mut(ptr.alloc_id)?.data_race.as_mut().unwrap(); + this.memory.get_alloc_extra_mut(ptr.alloc_id)?.0.data_race.as_mut().unwrap(); alloc_meta.reset_clocks(ptr.offset, size); } } From 543777acbd9797118c5992e308335ab21dcd1fbb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 May 2021 10:47:29 +0200 Subject: [PATCH 2671/5092] avoid unnecessary RefCell calls in Stacked Borrows --- src/stacked_borrows.rs | 60 +++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index a9c030c87de4..b1ab34b1f346 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -457,14 +457,29 @@ impl<'tcx> Stacks { &self, ptr: Pointer, size: Size, - global: &GlobalState, - f: impl Fn(Pointer, &mut Stack, &GlobalState) -> InterpResult<'tcx>, + f: impl Fn(Pointer, &mut Stack) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { let mut stacks = self.stacks.borrow_mut(); for (offset, stack) in stacks.iter_mut(ptr.offset, size) { let mut cur_ptr = ptr; cur_ptr.offset = offset; - f(cur_ptr, stack, &*global)?; + f(cur_ptr, stack)?; + } + Ok(()) + } + + /// Call `f` on every stack in the range. + fn for_each_mut( + &mut self, + ptr: Pointer, + size: Size, + f: impl Fn(Pointer, &mut Stack) -> InterpResult<'tcx>, + ) -> InterpResult<'tcx> { + let stacks = self.stacks.get_mut(); + for (offset, stack) in stacks.iter_mut(ptr.offset, size) { + let mut cur_ptr = ptr; + cur_ptr.offset = offset; + f(cur_ptr, stack)?; } Ok(()) } @@ -516,9 +531,8 @@ impl Stacks { extra: &MemoryExtra, ) -> InterpResult<'tcx> { trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - self.for_each(ptr, size, &*extra.borrow(), |ptr, stack, global| { - stack.access(AccessKind::Read, ptr, global) - }) + let global = &*extra.borrow(); + self.for_each(ptr, size, move |ptr, stack| stack.access(AccessKind::Read, ptr, global)) } #[inline(always)] @@ -529,9 +543,8 @@ impl Stacks { extra: &mut MemoryExtra, ) -> InterpResult<'tcx> { trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - self.for_each(ptr, size, extra.get_mut(), |ptr, stack, global| { - stack.access(AccessKind::Write, ptr, global) - }) + let global = extra.get_mut(); + self.for_each_mut(ptr, size, move |ptr, stack| stack.access(AccessKind::Write, ptr, global)) } #[inline(always)] @@ -542,7 +555,8 @@ impl Stacks { extra: &mut MemoryExtra, ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - self.for_each(ptr, size, extra.get_mut(), |ptr, stack, global| stack.dealloc(ptr, global)) + let global = extra.get_mut(); + self.for_each_mut(ptr, size, move |ptr, stack| stack.dealloc(ptr, global)) } } @@ -571,12 +585,6 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size.bytes() ); - // Get the allocation. We need both the allocation and the MemoryExtra, so we cannot use `&mut`. - // FIXME: make `get_alloc_extra_mut` also return `&mut MemoryExtra`. - let extra = this.memory.get_alloc_extra(ptr.alloc_id)?; - let stacked_borrows = - extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); - let global = this.memory.extra.stacked_borrows.as_ref().unwrap().borrow(); // Update the stacks. // Make sure that raw pointers and mutable shared references are reborrowed "weak": // There could be existing unique pointers reborrowed from them that should remain valid! @@ -588,6 +596,12 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Shared references and *const are a whole different kind of game, the // permission is not uniform across the entire range! // We need a frozen-sensitive reborrow. + // We have to use shared references to alloc/memory_extra here since + // `visit_freeze_sensitive` needs to access the global state. + let extra = this.memory.get_alloc_extra(ptr.alloc_id)?; + let stacked_borrows = + extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); + let global = this.memory.extra.stacked_borrows.as_ref().unwrap().borrow(); return this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { // We are only ever `SharedReadOnly` inside the frozen bits. let perm = if frozen { @@ -596,15 +610,19 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Permission::SharedReadWrite }; let item = Item { perm, tag: new_tag, protector }; - stacked_borrows.for_each(cur_ptr, size, &*global, |cur_ptr, stack, global| { - stack.grant(cur_ptr, item, global) + stacked_borrows.for_each(cur_ptr, size, |cur_ptr, stack| { + stack.grant(cur_ptr, item, &*global) }) }); } }; + // Here we can avoid `borrow()` calls because we have mutable references. + let (alloc_extra, memory_extra) = this.memory.get_alloc_extra_mut(ptr.alloc_id)?; + let stacked_borrows = + alloc_extra.stacked_borrows.as_mut().expect("we should have Stacked Borrows data"); + let global = memory_extra.stacked_borrows.as_mut().unwrap().get_mut(); let item = Item { perm, tag: new_tag, protector }; - stacked_borrows - .for_each(ptr, size, &*global, |ptr, stack, global| stack.grant(ptr, item, global)) + stacked_borrows.for_each_mut(ptr, size, |ptr, stack| stack.grant(ptr, item, global)) } /// Retags an indidual pointer, returning the retagged version. @@ -640,7 +658,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Compute new borrow. let new_tag = { - let mut mem_extra = this.memory.extra.stacked_borrows.as_ref().unwrap().borrow_mut(); + let mem_extra = this.memory.extra.stacked_borrows.as_mut().unwrap().get_mut(); match kind { // Give up tracking for raw pointers. RefKind::Raw { .. } if !mem_extra.track_raw => Tag::Untagged, From e09c571eec1fff99632f96eb1f74a7e177fcf2b0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 May 2021 11:00:25 +0200 Subject: [PATCH 2672/5092] avoid some borrow_mut calls in data_race --- src/data_race.rs | 54 +++++++++++++++++++++-------------------- src/shims/posix/sync.rs | 2 +- src/thread.rs | 22 +++++++++-------- 3 files changed, 41 insertions(+), 37 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index fb6bf8f89295..45159ef4c07c 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -598,7 +598,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // of the time, based on `rate`. let rate = this.memory.extra.cmpxchg_weak_failure_rate; let cmpxchg_success = eq.to_bool()? - && (!can_fail_spuriously || this.memory.extra.rng.borrow_mut().gen::() < rate); + && (!can_fail_spuriously || this.memory.extra.rng.get_mut().gen::() < rate); let res = Immediate::ScalarPair( old.to_scalar_or_uninit(), Scalar::from_bool(cmpxchg_success).into(), @@ -647,7 +647,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { place: &MPlaceTy<'tcx, Tag>, atomic: AtomicWriteOp, ) -> InterpResult<'tcx> { - let this = self.eval_context_ref(); + let this = self.eval_context_mut(); this.validate_atomic_op( place, atomic, @@ -672,7 +672,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { use AtomicRwOp::*; let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); let release = matches!(atomic, Release | AcqRel | SeqCst); - let this = self.eval_context_ref(); + let this = self.eval_context_mut(); this.validate_atomic_op(place, atomic, "Atomic RMW", move |memory, clocks, index, _| { if acquire { memory.load_acquire(clocks, index)?; @@ -690,7 +690,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// Update the data-race detector for an atomic fence on the current thread. fn validate_atomic_fence(&mut self, atomic: AtomicFenceOp) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - if let Some(data_race) = &this.memory.extra.data_race { + if let Some(data_race) = &mut this.memory.extra.data_race { data_race.maybe_perform_sync_operation(move |index, mut clocks| { log::trace!("Atomic fence on {:?} with ordering {:?}", index, atomic); @@ -771,7 +771,7 @@ impl VClockAlloc { } fn reset_clocks(&mut self, offset: Size, len: Size) { - let mut alloc_ranges = self.alloc_ranges.borrow_mut(); + let alloc_ranges = self.alloc_ranges.get_mut(); for (_, range) in alloc_ranges.iter_mut(offset, len) { // Reset the portion of the range *range = MemoryCellClocks::new(0, VectorIdx::MAX_INDEX); @@ -1025,6 +1025,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { if let Some(data_race) = &this.memory.extra.data_race { if data_race.multi_threaded.get() { // Load and log the atomic operation. + // Note that atomic loads are possible even from read-only allocations, so `get_alloc_extra_mut` is not an option. let place_ptr = place.ptr.assert_ptr(); let size = place.layout.size; let alloc_meta = @@ -1105,6 +1106,7 @@ struct ThreadExtraState { /// Global data-race detection state, contains the currently /// executing thread as well as the vector-clocks associated /// with each of the threads. +// FIXME: it is probably better to have one large RefCell, than to have so many small ones. #[derive(Debug, Clone)] pub struct GlobalState { /// Set to true once the first additional @@ -1158,7 +1160,7 @@ impl GlobalState { /// Create a new global state, setup with just thread-id=0 /// advanced to timestamp = 1. pub fn new() -> Self { - let global_state = GlobalState { + let mut global_state = GlobalState { multi_threaded: Cell::new(false), vector_clocks: RefCell::new(IndexVec::new()), vector_info: RefCell::new(IndexVec::new()), @@ -1172,9 +1174,9 @@ impl GlobalState { // Setup the main-thread since it is not explicitly created: // uses vector index and thread-id 0, also the rust runtime gives // the main-thread a name of "main". - let index = global_state.vector_clocks.borrow_mut().push(ThreadClockSet::default()); - global_state.vector_info.borrow_mut().push(ThreadId::new(0)); - global_state.thread_info.borrow_mut().push(ThreadExtraState { + let index = global_state.vector_clocks.get_mut().push(ThreadClockSet::default()); + global_state.vector_info.get_mut().push(ThreadId::new(0)); + global_state.thread_info.get_mut().push(ThreadExtraState { vector_index: Some(index), thread_name: Some("main".to_string().into_boxed_str()), termination_vector_clock: None, @@ -1221,7 +1223,7 @@ impl GlobalState { // Hook for thread creation, enabled multi-threaded execution and marks // the current thread timestamp as happening-before the current thread. #[inline] - pub fn thread_created(&self, thread: ThreadId) { + pub fn thread_created(&mut self, thread: ThreadId) { let current_index = self.current_index(); // Increment the number of active threads. @@ -1241,12 +1243,12 @@ impl GlobalState { let created_index = if let Some(reuse_index) = self.find_vector_index_reuse_candidate() { // Now re-configure the re-use candidate, increment the clock // for the new sync use of the vector. - let mut vector_clocks = self.vector_clocks.borrow_mut(); + let vector_clocks = self.vector_clocks.get_mut(); vector_clocks[reuse_index].increment_clock(reuse_index); // Locate the old thread the vector was associated with and update // it to represent the new thread instead. - let mut vector_info = self.vector_info.borrow_mut(); + let vector_info = self.vector_info.get_mut(); let old_thread = vector_info[reuse_index]; vector_info[reuse_index] = thread; @@ -1258,7 +1260,7 @@ impl GlobalState { } else { // No vector re-use candidates available, instead create // a new vector index. - let mut vector_info = self.vector_info.borrow_mut(); + let vector_info = self.vector_info.get_mut(); vector_info.push(thread) }; @@ -1268,7 +1270,7 @@ impl GlobalState { thread_info[thread].vector_index = Some(created_index); // Create a thread clock set if applicable. - let mut vector_clocks = self.vector_clocks.borrow_mut(); + let vector_clocks = self.vector_clocks.get_mut(); if created_index == vector_clocks.next_index() { vector_clocks.push(ThreadClockSet::default()); } @@ -1289,9 +1291,9 @@ impl GlobalState { /// Hook on a thread join to update the implicit happens-before relation /// between the joined thread and the current thread. #[inline] - pub fn thread_joined(&self, current_thread: ThreadId, join_thread: ThreadId) { - let mut clocks_vec = self.vector_clocks.borrow_mut(); - let thread_info = self.thread_info.borrow(); + pub fn thread_joined(&mut self, current_thread: ThreadId, join_thread: ThreadId) { + let clocks_vec = self.vector_clocks.get_mut(); + let thread_info = self.thread_info.get_mut(); // Load the vector clock of the current thread. let current_index = thread_info[current_thread] @@ -1329,9 +1331,9 @@ impl GlobalState { // If the thread is marked as terminated but not joined // then move the thread to the re-use set. - let mut termination = self.terminated_threads.borrow_mut(); + let termination = self.terminated_threads.get_mut(); if let Some(index) = termination.remove(&join_thread) { - let mut reuse = self.reuse_candidates.borrow_mut(); + let reuse = self.reuse_candidates.get_mut(); reuse.insert(index); } } @@ -1344,28 +1346,28 @@ impl GlobalState { /// This should be called strictly before any calls to /// `thread_joined`. #[inline] - pub fn thread_terminated(&self) { + pub fn thread_terminated(&mut self) { let current_index = self.current_index(); // Increment the clock to a unique termination timestamp. - let mut vector_clocks = self.vector_clocks.borrow_mut(); + let vector_clocks = self.vector_clocks.get_mut(); let current_clocks = &mut vector_clocks[current_index]; current_clocks.increment_clock(current_index); // Load the current thread id for the executing vector. - let vector_info = self.vector_info.borrow(); + let vector_info = self.vector_info.get_mut(); let current_thread = vector_info[current_index]; // Load the current thread metadata, and move to a terminated // vector state. Setting up the vector clock all join operations // will use. - let mut thread_info = self.thread_info.borrow_mut(); + let thread_info = self.thread_info.get_mut(); let current = &mut thread_info[current_thread]; current.termination_vector_clock = Some(current_clocks.clock.clone()); // Add this thread as a candidate for re-use after a thread join // occurs. - let mut termination = self.terminated_threads.borrow_mut(); + let termination = self.terminated_threads.get_mut(); termination.insert(current_thread, current_index); // Reduce the number of active threads, now that a thread has @@ -1392,9 +1394,9 @@ impl GlobalState { /// the thread name is used for improved diagnostics /// during a data-race. #[inline] - pub fn thread_set_name(&self, thread: ThreadId, name: String) { + pub fn thread_set_name(&mut self, thread: ThreadId, name: String) { let name = name.into_boxed_str(); - let mut thread_info = self.thread_info.borrow_mut(); + let thread_info = self.thread_info.get_mut(); thread_info[thread].thread_name = Some(name); } diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 3b68e4eee440..4725cd9fc3c8 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -58,7 +58,7 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( // (the kind has to be at its offset for compatibility with static initializer macros) fn mutex_get_kind<'mir, 'tcx: 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, + ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; diff --git a/src/thread.rs b/src/thread.rs index 3418e8c7d2bf..7ee18bb7f80e 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -332,7 +332,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { fn join_thread( &mut self, joined_thread_id: ThreadId, - data_race: &Option, + data_race: Option<&mut data_race::GlobalState>, ) -> InterpResult<'tcx> { if self.threads[joined_thread_id].join_status != ThreadJoinStatus::Joinable { throw_ub_format!("trying to join a detached or already joined thread"); @@ -436,7 +436,10 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Wakes up threads joining on the active one and deallocates thread-local statics. /// The `AllocId` that can now be freed is returned. - fn thread_terminated(&mut self, data_race: &Option) -> Vec { + fn thread_terminated( + &mut self, + mut data_race: Option<&mut data_race::GlobalState>, + ) -> Vec { let mut free_tls_statics = Vec::new(); { let mut thread_local_statics = self.thread_local_alloc_ids.borrow_mut(); @@ -452,14 +455,14 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { }); } // Set the thread into a terminated state in the data-race detector - if let Some(data_race) = data_race { + if let Some(ref mut data_race) = data_race { data_race.thread_terminated(); } // Check if we need to unblock any threads. for (i, thread) in self.threads.iter_enumerated_mut() { if thread.state == ThreadState::BlockedOnJoin(self.active_thread) { // The thread has terminated, mark happens-before edge to joining thread - if let Some(data_race) = data_race { + if let Some(ref mut data_race) = data_race { data_race.thread_joined(i, self.active_thread); } trace!("unblocking {:?} because {:?} terminated", i, self.active_thread); @@ -584,7 +587,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn create_thread(&mut self) -> ThreadId { let this = self.eval_context_mut(); let id = this.machine.threads.create_thread(); - if let Some(data_race) = &this.memory.extra.data_race { + if let Some(data_race) = &mut this.memory.extra.data_race { data_race.thread_created(id); } id @@ -599,8 +602,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let data_race = &this.memory.extra.data_race; - this.machine.threads.join_thread(joined_thread_id, data_race)?; + this.machine.threads.join_thread(joined_thread_id, this.memory.extra.data_race.as_mut())?; Ok(()) } @@ -664,7 +666,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn set_active_thread_name(&mut self, new_thread_name: Vec) { let this = self.eval_context_mut(); - if let Some(data_race) = &this.memory.extra.data_race { + if let Some(data_race) = &mut this.memory.extra.data_race { if let Ok(string) = String::from_utf8(new_thread_name.clone()) { data_race.thread_set_name(this.machine.threads.active_thread, string); } @@ -759,8 +761,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn thread_terminated(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let data_race = &this.memory.extra.data_race; - for alloc_id in this.machine.threads.thread_terminated(data_race) { + for alloc_id in this.machine.threads.thread_terminated(this.memory.extra.data_race.as_mut()) + { let ptr = this.memory.global_base_pointer(alloc_id.into())?; this.memory.deallocate(ptr, None, MiriMemoryKind::Tls.into())?; } From 9e0e9386a64c4dfa9875a2f3e8be265eaae394f4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 May 2021 11:52:41 +0200 Subject: [PATCH 2673/5092] better approach to skip ZST reborrows --- src/stacked_borrows.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index b1ab34b1f346..3e176d94b990 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -572,6 +572,18 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx new_tag: Tag, protect: bool, ) -> InterpResult<'tcx> { + // Nothing to do for ZSTs. + if size == Size::ZERO { + trace!( + "reborrow of size 0: {} reference {:?} derived from {:?} (pointee {})", + kind, + new_tag, + place.ptr, + place.layout.ty, + ); + return Ok(()); + } + let this = self.eval_context_mut(); let protector = if protect { Some(this.frame().extra.call_id) } else { None }; let ptr = place.ptr.assert_ptr(); @@ -617,6 +629,8 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } }; // Here we can avoid `borrow()` calls because we have mutable references. + // Note that this asserts that the allocation is mutable -- but since we are creating a + // mutable pointer, that seems reasonable. let (alloc_extra, memory_extra) = this.memory.get_alloc_extra_mut(ptr.alloc_id)?; let stacked_borrows = alloc_extra.stacked_borrows.as_mut().expect("we should have Stacked Borrows data"); @@ -649,12 +663,6 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We can see dangling ptrs in here e.g. after a Box's `Unique` was // updated using "self.0 = ..." (can happen in Box::from_raw) so we cannot ICE; see miri#1050. let place = this.mplace_access_checked(place, Some(Align::from_bytes(1).unwrap()))?; - // Nothing to do for ZSTs. We use `is_bits` here because we *do* need to retag even ZSTs - // when there actually is a tag (to avoid inheriting a tag that would let us access more - // than 0 bytes). - if size == Size::ZERO && place.ptr.is_bits() { - return Ok(*val); - } // Compute new borrow. let new_tag = { From c60efa0c69786cf6e7f05d83ebd1a94c65788c25 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 May 2021 12:26:37 +0200 Subject: [PATCH 2674/5092] allocate backtrace strings mutably --- src/shims/backtrace.rs | 6 ++++-- src/shims/panic.rs | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index f936913114c4..e866868d729f 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -119,8 +119,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `lo.col` is 0-based - add 1 to make it 1-based for the caller. let colno: u32 = lo.col.0 as u32 + 1; - let name_alloc = this.allocate_str(&name, MiriMemoryKind::Rust.into()); - let filename_alloc = this.allocate_str(&filename, MiriMemoryKind::Rust.into()); + // These are "mutable" allocations as we consider them to be owned by the callee. + let name_alloc = this.allocate_str(&name, MiriMemoryKind::Rust.into(), Mutability::Mut); + let filename_alloc = + this.allocate_str(&filename, MiriMemoryKind::Rust.into(), Mutability::Mut); let lineno_alloc = Scalar::from_u32(lineno); let colno_alloc = Scalar::from_u32(colno); diff --git a/src/shims/panic.rs b/src/shims/panic.rs index b60da058e2cb..06a434727b5f 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -13,6 +13,7 @@ use log::trace; +use rustc_ast::Mutability; use rustc_middle::{mir, ty}; use rustc_target::spec::abi::Abi; use rustc_target::spec::PanicStrategy; @@ -169,7 +170,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); // First arg: message. - let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into()); + let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into(), Mutability::Not); // Call the lang item. let panic = this.tcx.lang_items().panic_fn().unwrap(); From 393ce98b32ced200fc443ca411edcb3383bcdef9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 May 2021 12:37:52 +0200 Subject: [PATCH 2675/5092] fix a Stacked Borrows test whose output changed --- .../compile-fail/stacked_borrows/static_memory_modification.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile-fail/stacked_borrows/static_memory_modification.rs b/tests/compile-fail/stacked_borrows/static_memory_modification.rs index 88ac16494766..55a7f816c034 100644 --- a/tests/compile-fail/stacked_borrows/static_memory_modification.rs +++ b/tests/compile-fail/stacked_borrows/static_memory_modification.rs @@ -3,6 +3,6 @@ static X: usize = 5; #[allow(mutable_transmutes)] fn main() { let _x = unsafe { - std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR borrow stack + std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR writing to alloc0 which is read-only }; } From a03f700fc9380e881d95c62a1e5fd7b49f1dc743 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 May 2021 18:05:50 +0200 Subject: [PATCH 2676/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index bc7ef53b3037..31d26ea43e46 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6e92fb409816c65cd0a78a1fbcc71e2fbabdf50a +0f8cd43ee8c3614e04b5c624dd8a45758d7023da From f42a6d1026fc2350766be9a755d124ab49e28138 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Thu, 27 May 2021 06:40:47 +0800 Subject: [PATCH 2677/5092] Skip doctests of `proc-macro` crates --- cargo-miri/bin.rs | 7 +++++++ test-cargo-miri/run-test.py | 4 ++++ test-cargo-miri/subcrate/src/lib.rs | 3 +++ test-cargo-miri/test.stderr-proc-macro-doctest.ref | 1 + test-cargo-miri/test.stdout-empty.ref | 0 5 files changed, 15 insertions(+) create mode 100644 test-cargo-miri/test.stderr-proc-macro-doctest.ref create mode 100644 test-cargo-miri/test.stdout-empty.ref diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 295acd6638a2..19d235cf67d7 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -903,6 +903,13 @@ fn phase_rustdoc(fst_arg: &str, mut args: env::Args) { show_error(format!("cross-interpreting doc-tests is not currently supported by Miri.")); } + // Doc-tests of `proc-macro` crates (and their dependencies) are always built for the host, + // so we are not able to run them in Miri. + if ArgFlagValueIter::new("--crate-type").any(|crate_type| crate_type == "proc-macro") { + eprintln!("Running doc-tests of `proc-macro` crates is not currently supported by Miri."); + return; + } + // For each doc-test, rustdoc starts two child processes: first the test is compiled, // then the produced executable is invoked. We want to reroute both of these to cargo-miri, // such that the first time we'll enter phase_cargo_rustc, and phase_cargo_runner second. diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 9185c2507b6f..c850e7d14591 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -140,6 +140,10 @@ def test_cargo_miri_test(): "test.subcrate.stdout.ref", "test.stderr-proc-macro.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) + test("`cargo miri test` (subcrate, doctests)", + cargo_miri("test") + ["-p", "subcrate", "--doc"], + "test.stdout-empty.ref", "test.stderr-proc-macro-doctest.ref", + ) os.chdir(os.path.dirname(os.path.realpath(__file__))) os.environ["RUST_TEST_NOCAPTURE"] = "0" # this affects test output, so make sure it is not set diff --git a/test-cargo-miri/subcrate/src/lib.rs b/test-cargo-miri/subcrate/src/lib.rs index 706e368017c0..07ed1acb7a05 100644 --- a/test-cargo-miri/subcrate/src/lib.rs +++ b/test-cargo-miri/subcrate/src/lib.rs @@ -1,2 +1,5 @@ +#[cfg(doctest)] +use num_cpus as _; + #[cfg(test)] compile_error!("Miri should not touch me"); diff --git a/test-cargo-miri/test.stderr-proc-macro-doctest.ref b/test-cargo-miri/test.stderr-proc-macro-doctest.ref new file mode 100644 index 000000000000..55d0f7cf54af --- /dev/null +++ b/test-cargo-miri/test.stderr-proc-macro-doctest.ref @@ -0,0 +1 @@ +Running doc-tests of `proc-macro` crates is not currently supported by Miri. diff --git a/test-cargo-miri/test.stdout-empty.ref b/test-cargo-miri/test.stdout-empty.ref new file mode 100644 index 000000000000..e69de29bb2d1 From 97b2824ada1a6f7128ec1355b48376b0f43455ce Mon Sep 17 00:00:00 2001 From: scottmcm Date: Thu, 27 May 2021 00:14:13 +0000 Subject: [PATCH 2678/5092] Add `copy_within` to the SB trophy case --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 547e2e15dadc..469263115dd7 100644 --- a/README.md +++ b/README.md @@ -436,6 +436,7 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [Windows `Env` iterator using a raw pointer outside its valid memory area](https://github.com/rust-lang/rust/pull/70479) * [`VecDeque::iter_mut` creating overlapping mutable references](https://github.com/rust-lang/rust/issues/74029) * [Various standard library aliasing issues involving raw pointers](https://github.com/rust-lang/rust/pull/78602) +* [`<[T]>::copy_within` using a loan after invalidating it](https://github.com/rust-lang/rust/pull/85610) ## License From 773eb1e97094a1c0da6adae0bc537f60d5a6467d Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Thu, 27 May 2021 18:34:38 +0800 Subject: [PATCH 2679/5092] "doc-tests" -> "doctests" --- cargo-miri/bin.rs | 2 +- test-cargo-miri/test.stderr-proc-macro-doctest.ref | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 19d235cf67d7..a43e028219c3 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -906,7 +906,7 @@ fn phase_rustdoc(fst_arg: &str, mut args: env::Args) { // Doc-tests of `proc-macro` crates (and their dependencies) are always built for the host, // so we are not able to run them in Miri. if ArgFlagValueIter::new("--crate-type").any(|crate_type| crate_type == "proc-macro") { - eprintln!("Running doc-tests of `proc-macro` crates is not currently supported by Miri."); + eprintln!("Running doctests of `proc-macro` crates is not currently supported by Miri."); return; } diff --git a/test-cargo-miri/test.stderr-proc-macro-doctest.ref b/test-cargo-miri/test.stderr-proc-macro-doctest.ref index 55d0f7cf54af..ca5e3a2392db 100644 --- a/test-cargo-miri/test.stderr-proc-macro-doctest.ref +++ b/test-cargo-miri/test.stderr-proc-macro-doctest.ref @@ -1 +1 @@ -Running doc-tests of `proc-macro` crates is not currently supported by Miri. +Running doctests of `proc-macro` crates is not currently supported by Miri. From ffff7ff8a6e0a54443e5bef3eb3c8f4b7aeaf1c6 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Thu, 27 May 2021 19:22:42 +0800 Subject: [PATCH 2680/5092] Use `compile_error!` instead of `use num_cpus` --- test-cargo-miri/subcrate/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-cargo-miri/subcrate/src/lib.rs b/test-cargo-miri/subcrate/src/lib.rs index 07ed1acb7a05..2ccb6704b05e 100644 --- a/test-cargo-miri/subcrate/src/lib.rs +++ b/test-cargo-miri/subcrate/src/lib.rs @@ -1,5 +1,5 @@ #[cfg(doctest)] -use num_cpus as _; +compile_error!("rustdoc should not touch me"); #[cfg(test)] compile_error!("Miri should not touch me"); From 43db2aa5a91778de579c271524f0fa1bad767072 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Thu, 27 May 2021 19:44:48 +0800 Subject: [PATCH 2681/5092] Change "Doc-tests" in the comment to "Doctests" --- cargo-miri/bin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index a43e028219c3..8eaf3d36c69d 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -903,7 +903,7 @@ fn phase_rustdoc(fst_arg: &str, mut args: env::Args) { show_error(format!("cross-interpreting doc-tests is not currently supported by Miri.")); } - // Doc-tests of `proc-macro` crates (and their dependencies) are always built for the host, + // Doctests of `proc-macro` crates (and their dependencies) are always built for the host, // so we are not able to run them in Miri. if ArgFlagValueIter::new("--crate-type").any(|crate_type| crate_type == "proc-macro") { eprintln!("Running doctests of `proc-macro` crates is not currently supported by Miri."); From d1de0843ed56eb663f9df9668ede39e58da778ec Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Thu, 27 May 2021 19:48:07 +0800 Subject: [PATCH 2682/5092] Change preexisting "doc-test" to "doctest" --- cargo-miri/bin.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 8eaf3d36c69d..7836b26ea5f9 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -900,7 +900,7 @@ fn phase_rustdoc(fst_arg: &str, mut args: env::Args) { } if crossmode { - show_error(format!("cross-interpreting doc-tests is not currently supported by Miri.")); + show_error(format!("cross-interpreting doctests is not currently supported by Miri.")); } // Doctests of `proc-macro` crates (and their dependencies) are always built for the host, @@ -910,7 +910,7 @@ fn phase_rustdoc(fst_arg: &str, mut args: env::Args) { return; } - // For each doc-test, rustdoc starts two child processes: first the test is compiled, + // For each doctest, rustdoc starts two child processes: first the test is compiled, // then the produced executable is invoked. We want to reroute both of these to cargo-miri, // such that the first time we'll enter phase_cargo_rustc, and phase_cargo_runner second. // From 9b2d42587f1b12188c1430bd79c058f4590f0ded Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sat, 22 May 2021 22:45:00 +0800 Subject: [PATCH 2683/5092] `unwind` is no longer `Option` --- rust-version | 2 +- src/machine.rs | 6 ++-- src/shims/foreign_items.rs | 2 +- src/shims/intrinsics.rs | 2 +- src/shims/mod.rs | 4 +-- src/shims/panic.rs | 30 ++++++++++++------- .../compile-fail/panic/unwind_panic_abort.rs | 2 +- 7 files changed, 28 insertions(+), 20 deletions(-) diff --git a/rust-version b/rust-version index 31d26ea43e46..7fc12e477e28 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0f8cd43ee8c3614e04b5c624dd8a45758d7023da +ce0d64e03ef9875e0935bb60e989542b7ec29579 diff --git a/src/machine.rs b/src/machine.rs index fb2d877c3803..467696e83976 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -356,7 +356,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { abi: Abi, args: &[OpTy<'tcx, Tag>], ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, - unwind: Option, + unwind: StackPopUnwind, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { ecx.find_mir_or_eval_fn(instance, abi, args, ret, unwind) } @@ -368,7 +368,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { abi: Abi, args: &[OpTy<'tcx, Tag>], ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, - _unwind: Option, + _unwind: StackPopUnwind, ) -> InterpResult<'tcx> { ecx.call_dlsym(fn_val, abi, args, ret) } @@ -379,7 +379,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, - unwind: Option, + unwind: StackPopUnwind, ) -> InterpResult<'tcx> { ecx.call_intrinsic(instance, args, ret, unwind) } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 47d939e69722..4c96c99eeeaf 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -120,7 +120,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx abi: Abi, args: &[OpTy<'tcx, Tag>], ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, - unwind: Option, + unwind: StackPopUnwind, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index f2979a3c69d8..c018dd873810 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -23,7 +23,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, - _unwind: Option, + _unwind: StackPopUnwind, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 13ea14b4b9d4..bb8d0bb8db90 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -29,7 +29,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx abi: Abi, args: &[OpTy<'tcx, Tag>], ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, - unwind: Option, + unwind: StackPopUnwind, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); trace!("eval_fn_call: {:#?}, {:?}", instance, ret.map(|p| p.0)); @@ -64,7 +64,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ptr_op: &OpTy<'tcx, Tag>, align_op: &OpTy<'tcx, Tag>, ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, - unwind: Option, + unwind: StackPopUnwind, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); let (dest, ret) = ret.unwrap(); diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 06a434727b5f..b1da7f340fce 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -41,15 +41,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn handle_miri_start_panic( &mut self, args: &[OpTy<'tcx, Tag>], - unwind: Option, + unwind: StackPopUnwind, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); trace!("miri_start_panic: {:?}", this.frame().instance); - // Make sure we only start unwinding when this matches our panic strategy. - if this.tcx.sess.panic_strategy() != PanicStrategy::Unwind { - throw_ub_format!("unwinding despite panic=abort"); - } // Get the raw pointer stored in arg[0] (the panic payload). let &[ref payload] = check_arg_count(args)?; @@ -59,7 +55,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx thread.panic_payload = Some(payload); // Jump to the unwind block to begin unwinding. - this.unwind_to_block(unwind); + this.unwind_to_block(unwind)?; return Ok(()); } @@ -99,7 +95,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &[data.into()], Some(&ret_place), // Directly return to caller. - StackPopCleanup::Goto { ret: Some(ret), unwind: None }, + StackPopCleanup::Goto { ret: Some(ret), unwind: StackPopUnwind::Skip }, )?; // We ourselves will return `0`, eventually (will be overwritten if we catch a panic). @@ -155,7 +151,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &[catch_unwind.data.into(), payload.into()], Some(&ret_place), // Directly return to caller of `try`. - StackPopCleanup::Goto { ret: Some(catch_unwind.ret), unwind: None }, + StackPopCleanup::Goto { ret: Some(catch_unwind.ret), unwind: StackPopUnwind::Skip }, )?; // We pushed a new stack frame, the engine should not do any jumping now! @@ -166,7 +162,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Starta a panic in the interpreter with the given message as payload. - fn start_panic(&mut self, msg: &str, unwind: Option) -> InterpResult<'tcx> { + fn start_panic(&mut self, msg: &str, unwind: StackPopUnwind) -> InterpResult<'tcx> { let this = self.eval_context_mut(); // First arg: message. @@ -209,12 +205,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Abi::Rust, &[index.into(), len.into()], None, - StackPopCleanup::Goto { ret: None, unwind }, + StackPopCleanup::Goto { + ret: None, + unwind: match unwind { + Some(cleanup) => StackPopUnwind::Cleanup(cleanup), + None => StackPopUnwind::Skip, + }, + }, )?; } _ => { // Forward everything else to `panic` lang item. - this.start_panic(msg.description(), unwind)?; + this.start_panic( + msg.description(), + match unwind { + Some(cleanup) => StackPopUnwind::Cleanup(cleanup), + None => StackPopUnwind::Skip, + }, + )?; } } Ok(()) diff --git a/tests/compile-fail/panic/unwind_panic_abort.rs b/tests/compile-fail/panic/unwind_panic_abort.rs index 05284eb770b2..a333a4b0ded8 100644 --- a/tests/compile-fail/panic/unwind_panic_abort.rs +++ b/tests/compile-fail/panic/unwind_panic_abort.rs @@ -7,5 +7,5 @@ extern "Rust" { } fn main() { - unsafe { miri_start_panic(&mut 0); } //~ ERROR unwinding despite panic=abort + unsafe { miri_start_panic(&mut 0); } //~ ERROR unwinding past a stack frame that does not allow unwinding } From 7e9da8d30eb07093c09fd90276aeca4a469a0432 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 8 May 2021 12:20:51 -0400 Subject: [PATCH 2684/5092] Add `measureme` integration for profiling the interpreted program This PR uses the `measureme` crate to profile the call stack of the program being interpreted by Miri. This is accomplished by starting a measureme 'event' when we enter a function call, and ending the event when we exit the call. The `measureme` tooling can be used to produce a call stack from the generated profile data. Limitations: * We currently record every single entry/exit. This might generate very large profile outputs for programs with a large number of function calls. In follow-up work, we might want to explore sampling (e.g. only recording every N function calls). * This does not integrate very well with Miri's concurrency support. Each event we record starts when we push a frame, and ends when we pop a frame. As a result, switching between virtual threads will cause events from different threads to be interleaved. Additionally, the recorded for a particular frame will include all of the work Miri does before that frame completes, including executing another thread. The `measureme` integration is off by default, and must be enabled via `-Zmiri-measureme=` --- Cargo.lock | 87 ++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + README.md | 4 +++ src/bin/miri.rs | 4 +++ src/eval.rs | 6 +++- src/machine.rs | 50 +++++++++++++++++++++----- src/shims/panic.rs | 1 - 7 files changed, 143 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 69cc1966a6f8..3ae270032180 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -167,6 +167,15 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "instant" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +dependencies = [ + "cfg-if", +] + [[package]] name = "itoa" version = "0.4.7" @@ -185,6 +194,15 @@ version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714" +[[package]] +name = "lock_api" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3c91c24eae6777794bb1997ad98bbb87daf92890acab859f7eaa4320333176" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" version = "0.4.14" @@ -194,12 +212,34 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "measureme" +version = "9.1.1" +source = "git+https://github.com/rust-lang/measureme?rev=501d6a3c192beee5e633a6c5f79130bedfdadcb5#501d6a3c192beee5e633a6c5f79130bedfdadcb5" +dependencies = [ + "log", + "memmap2", + "parking_lot", + "perf-event-open-sys", + "rustc-hash", + "smallvec", +] + [[package]] name = "memchr" version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" +[[package]] +name = "memmap2" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "397d1a6d6d0563c0f5462bbdae662cf6c784edf5e828e40c7257f85d82bf56dd" +dependencies = [ + "libc", +] + [[package]] name = "miow" version = "0.3.7" @@ -220,6 +260,7 @@ dependencies = [ "hex", "libc", "log", + "measureme", "rand", "rustc-workspace-hack", "rustc_version", @@ -237,6 +278,40 @@ dependencies = [ "libc", ] +[[package]] +name = "parking_lot" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "perf-event-open-sys" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce9bedf5da2c234fdf2391ede2b90fabf585355f33100689bc364a3ea558561a" +dependencies = [ + "libc", +] + [[package]] name = "pest" version = "2.1.3" @@ -355,6 +430,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc-workspace-hack" version = "1.0.0" @@ -394,6 +475,12 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "semver" version = "0.11.0" diff --git a/Cargo.toml b/Cargo.toml index ab7d88e66934..fd212e43047e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ test = false # we have no unit tests doctest = false # and no doc tests [dependencies] +measureme = { git = "https://github.com/rust-lang/measureme", rev = "501d6a3c192beee5e633a6c5f79130bedfdadcb5" } getrandom = { version = "0.2", features = ["std"] } env_logger = "0.8" log = "0.4" diff --git a/README.md b/README.md index 469263115dd7..87f6b87c6626 100644 --- a/README.md +++ b/README.md @@ -258,6 +258,10 @@ environment variable: this pointer. Note that it is not currently guaranteed that code that works with `-Zmiri-track-raw-pointers` also works without `-Zmiri-track-raw-pointers`, but for the vast majority of code, this will be the case. +* `-Zmiri-measureme=` enables `measureme` profiling for the interpreted program. + This can be used to find which parts of your program are executing slowly under Miri. + The profile is written out to a file with the prefix ``, and can be processed + using the tools in the repository https://github.com/rust-lang/measureme Some native rustc `-Z` flags are also very relevant for Miri: diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 4a1ea3a54286..47cde5c353e1 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -318,6 +318,10 @@ fn main() { }; miri_config.cmpxchg_weak_failure_rate = rate; } + arg if arg.starts_with("-Zmiri-measureme=") => { + let measureme_out = arg.strip_prefix("-Zmiri-measureme=").unwrap(); + miri_config.measureme_out = Some(measureme_out.to_string()); + } _ => { // Forward to rustc. rustc_args.push(arg); diff --git a/src/eval.rs b/src/eval.rs index 1e46015f87a8..a5268b58a2d1 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -54,6 +54,9 @@ pub struct MiriConfig { /// Rate of spurious failures for compare_exchange_weak atomic operations, /// between 0.0 and 1.0, defaulting to 0.8 (80% chance of failure). pub cmpxchg_weak_failure_rate: f64, + /// If `Some`, enable the `measureme` profiler, writing results to the specified + /// directory. + pub measureme_out: Option, } impl Default for MiriConfig { @@ -73,6 +76,7 @@ impl Default for MiriConfig { track_raw: false, data_race_detector: true, cmpxchg_weak_failure_rate: 0.8, + measureme_out: None, } } } @@ -92,7 +96,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( tcx, rustc_span::source_map::DUMMY_SP, param_env, - Evaluator::new(config.communicate, config.validate, layout_cx), + Evaluator::new(&config, layout_cx), MemoryExtra::new(&config), ); // Complete initialization. diff --git a/src/machine.rs b/src/machine.rs index 467696e83976..77c606a83f47 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -10,6 +10,8 @@ use std::time::Instant; use log::trace; use rand::rngs::StdRng; use rand::SeedableRng; +use std::collections::hash_map::Entry; +use measureme::{Profiler, StringId, EventId, DetachedTiming}; use rustc_data_structures::fx::FxHashMap; use rustc_middle::{ @@ -34,7 +36,6 @@ pub const STACK_SIZE: u64 = 16 * PAGE_SIZE; // whatever pub const NUM_CPUS: u64 = 1; /// Extra data stored with each stack frame -#[derive(Debug)] pub struct FrameData<'tcx> { /// Extra data for Stacked Borrows. pub call_id: stacked_borrows::CallId, @@ -43,6 +44,8 @@ pub struct FrameData<'tcx> { /// called by `try`). When this frame is popped during unwinding a panic, /// we stop unwinding, use the `CatchUnwindData` to handle catching. pub catch_unwind: Option>, + + pub timing: Option, } /// Extra memory kinds @@ -270,16 +273,21 @@ pub struct Evaluator<'mir, 'tcx> { /// Allocations that are considered roots of static memory (that may leak). pub(crate) static_roots: Vec, + + profiler: Option, + string_cache: FxHashMap, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { pub(crate) fn new( - communicate: bool, - validate: bool, + config: &MiriConfig, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>, ) -> Self { let layouts = PrimitiveLayouts::new(layout_cx).expect("Couldn't get layouts of primitive types"); + let profiler = config.measureme_out.as_ref().map(|out| { + Profiler::new(out).expect("Couldn't create `measureme` profiler") + }); Evaluator { // `env_vars` could be initialized properly here if `Memory` were available before // calling this method. @@ -288,14 +296,16 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { argv: None, cmd_line: None, tls: TlsData::default(), - communicate, - validate, + communicate: config.communicate, + validate: config.validate, file_handler: Default::default(), dir_handler: Default::default(), time_anchor: Instant::now(), layouts, threads: ThreadManager::default(), static_roots: Vec::new(), + profiler, + string_cache: Default::default(), } } } @@ -601,7 +611,26 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { let call_id = stacked_borrows.map_or(NonZeroU64::new(1).unwrap(), |stacked_borrows| { stacked_borrows.borrow_mut().new_call() }); - let extra = FrameData { call_id, catch_unwind: None }; + let timing = if let Some(profiler) = ecx.machine.profiler.as_ref() { + let fn_name = frame.instance.to_string(); + let entry = ecx.machine.string_cache.entry(fn_name.clone()); + let name = match entry { + Entry::Occupied(e) => *e.get(), + Entry::Vacant(e) => { + *e.insert(profiler.alloc_string(&*fn_name)) + } + }; + + Some(profiler.start_recording_interval_event_detached( + name, + EventId::from_label(name), + 0 + )) + } else { + None + }; + + let extra = FrameData { call_id, catch_unwind: None, timing }; Ok(frame.with_extra(extra)) } @@ -625,10 +654,15 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn after_stack_pop( ecx: &mut InterpCx<'mir, 'tcx, Self>, - frame: Frame<'mir, 'tcx, Tag, FrameData<'tcx>>, + mut frame: Frame<'mir, 'tcx, Tag, FrameData<'tcx>>, unwinding: bool, ) -> InterpResult<'tcx, StackPopJump> { - ecx.handle_stack_pop(frame.extra, unwinding) + let timing = frame.extra.timing.take(); + let res = ecx.handle_stack_pop(frame.extra, unwinding); + if let Some(profiler) = ecx.machine.profiler.as_ref() { + profiler.finish_recording_interval_event(timing.unwrap()); + } + res } #[inline(always)] diff --git a/src/shims/panic.rs b/src/shims/panic.rs index b1da7f340fce..6b08ee8e1840 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -119,7 +119,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, StackPopJump> { let this = self.eval_context_mut(); - trace!("handle_stack_pop(extra = {:?}, unwinding = {})", extra, unwinding); if let Some(stacked_borrows) = &this.memory.extra.stacked_borrows { stacked_borrows.borrow_mut().end_call(extra.call_id); } From 2166eaed90a9f94e5078bd470b5cd8cbdccc7543 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 8 May 2021 13:17:58 -0400 Subject: [PATCH 2685/5092] Use active thread id --- src/machine.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine.rs b/src/machine.rs index 77c606a83f47..7a26a609bb6d 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -624,7 +624,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { Some(profiler.start_recording_interval_event_detached( name, EventId::from_label(name), - 0 + ecx.get_active_thread().to_u32() )) } else { None From 16f469280ee8dfea1ca4f24a272f44865896006e Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 29 May 2021 17:09:46 -0500 Subject: [PATCH 2686/5092] Address review comments --- Cargo.lock | 5 +++-- Cargo.toml | 2 +- README.md | 8 ++++---- src/eval.rs | 4 ++-- src/machine.rs | 33 +++++++++++++++++++-------------- 5 files changed, 29 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3ae270032180..e728dc07b928 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -214,8 +214,9 @@ dependencies = [ [[package]] name = "measureme" -version = "9.1.1" -source = "git+https://github.com/rust-lang/measureme?rev=501d6a3c192beee5e633a6c5f79130bedfdadcb5#501d6a3c192beee5e633a6c5f79130bedfdadcb5" +version = "9.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78f7a41bc6f856a2cf0e95094ad5121f82500e2d9a0f3c0171d98f6566d8117d" dependencies = [ "log", "memmap2", diff --git a/Cargo.toml b/Cargo.toml index fd212e43047e..7ee96f7e99e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,6 @@ test = false # we have no unit tests doctest = false # and no doc tests [dependencies] -measureme = { git = "https://github.com/rust-lang/measureme", rev = "501d6a3c192beee5e633a6c5f79130bedfdadcb5" } getrandom = { version = "0.2", features = ["std"] } env_logger = "0.8" log = "0.4" @@ -31,6 +30,7 @@ smallvec = "1.4.2" # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` # for more information. rustc-workspace-hack = "1.0.0" +measureme = "9.1.2" # Enable some feature flags that dev-dependencies need but dependencies # do not. This makes `./miri install` after `./miri build` faster. diff --git a/README.md b/README.md index 87f6b87c6626..b214ab6d09c1 100644 --- a/README.md +++ b/README.md @@ -222,6 +222,10 @@ environment variable: times to exclude several variables. On Windows, the `TERM` environment variable is excluded by default. * `-Zmiri-ignore-leaks` disables the memory leak checker. +* `-Zmiri-measureme=` enables `measureme` profiling for the interpreted program. + This can be used to find which parts of your program are executing slowly under Miri. + The profile is written out to a file with the prefix ``, and can be processed + using the tools in the repository https://github.com/rust-lang/measureme. * `-Zmiri-seed=` configures the seed of the RNG that Miri uses to resolve non-determinism. This RNG is used to pick base addresses for allocations. When isolation is enabled (the default), this is also used to emulate system @@ -258,10 +262,6 @@ environment variable: this pointer. Note that it is not currently guaranteed that code that works with `-Zmiri-track-raw-pointers` also works without `-Zmiri-track-raw-pointers`, but for the vast majority of code, this will be the case. -* `-Zmiri-measureme=` enables `measureme` profiling for the interpreted program. - This can be used to find which parts of your program are executing slowly under Miri. - The profile is written out to a file with the prefix ``, and can be processed - using the tools in the repository https://github.com/rust-lang/measureme Some native rustc `-Z` flags are also very relevant for Miri: diff --git a/src/eval.rs b/src/eval.rs index a5268b58a2d1..52e554f57d7e 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -54,8 +54,8 @@ pub struct MiriConfig { /// Rate of spurious failures for compare_exchange_weak atomic operations, /// between 0.0 and 1.0, defaulting to 0.8 (80% chance of failure). pub cmpxchg_weak_failure_rate: f64, - /// If `Some`, enable the `measureme` profiler, writing results to the specified - /// directory. + /// If `Some`, enable the `measureme` profiler, writing results to a file + /// with the specified prefix. pub measureme_out: Option, } diff --git a/src/machine.rs b/src/machine.rs index 7a26a609bb6d..4ed2fba43c14 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -10,7 +10,6 @@ use std::time::Instant; use log::trace; use rand::rngs::StdRng; use rand::SeedableRng; -use std::collections::hash_map::Entry; use measureme::{Profiler, StringId, EventId, DetachedTiming}; use rustc_data_structures::fx::FxHashMap; @@ -45,6 +44,9 @@ pub struct FrameData<'tcx> { /// we stop unwinding, use the `CatchUnwindData` to handle catching. pub catch_unwind: Option>, + /// If `measureme` profiling is enabled, holds timing information + /// for the start of this frame. When we finish executing this frame, + /// we use this to register a completed event with `measureme`. pub timing: Option, } @@ -274,7 +276,11 @@ pub struct Evaluator<'mir, 'tcx> { /// Allocations that are considered roots of static memory (that may leak). pub(crate) static_roots: Vec, + /// The `measureme` profiler used to record timing information about + /// the emulated program. profiler: Option, + /// Used with `profiler` to cache the `StringId`s for event names + /// uesd with `measureme`. string_cache: FxHashMap, } @@ -607,29 +613,28 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx: &mut InterpCx<'mir, 'tcx, Self>, frame: Frame<'mir, 'tcx, Tag>, ) -> InterpResult<'tcx, Frame<'mir, 'tcx, Tag, FrameData<'tcx>>> { - let stacked_borrows = ecx.memory.extra.stacked_borrows.as_ref(); - let call_id = stacked_borrows.map_or(NonZeroU64::new(1).unwrap(), |stacked_borrows| { - stacked_borrows.borrow_mut().new_call() - }); + // Start recording our event before doing anything else let timing = if let Some(profiler) = ecx.machine.profiler.as_ref() { let fn_name = frame.instance.to_string(); let entry = ecx.machine.string_cache.entry(fn_name.clone()); - let name = match entry { - Entry::Occupied(e) => *e.get(), - Entry::Vacant(e) => { - *e.insert(profiler.alloc_string(&*fn_name)) - } - }; + let name = entry.or_insert_with(|| { + profiler.alloc_string(&*fn_name) + }); Some(profiler.start_recording_interval_event_detached( - name, - EventId::from_label(name), - ecx.get_active_thread().to_u32() + *name, + EventId::from_label(*name), + ecx.get_active_thread().to_u32(), )) } else { None }; + let stacked_borrows = ecx.memory.extra.stacked_borrows.as_ref(); + let call_id = stacked_borrows.map_or(NonZeroU64::new(1).unwrap(), |stacked_borrows| { + stacked_borrows.borrow_mut().new_call() + }); + let extra = FrameData { call_id, catch_unwind: None, timing }; Ok(frame.with_extra(extra)) } From 20f1b2a969f6d61f5f8bf4d7877d30c66e22e70f Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 29 May 2021 17:16:12 -0500 Subject: [PATCH 2687/5092] Run fmt --- src/machine.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 4ed2fba43c14..1a01ece6c9a8 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -8,9 +8,9 @@ use std::num::NonZeroU64; use std::time::Instant; use log::trace; +use measureme::{DetachedTiming, EventId, Profiler, StringId}; use rand::rngs::StdRng; use rand::SeedableRng; -use measureme::{Profiler, StringId, EventId, DetachedTiming}; use rustc_data_structures::fx::FxHashMap; use rustc_middle::{ @@ -285,15 +285,13 @@ pub struct Evaluator<'mir, 'tcx> { } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { - pub(crate) fn new( - config: &MiriConfig, - layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>, - ) -> Self { + pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Self { let layouts = PrimitiveLayouts::new(layout_cx).expect("Couldn't get layouts of primitive types"); - let profiler = config.measureme_out.as_ref().map(|out| { - Profiler::new(out).expect("Couldn't create `measureme` profiler") - }); + let profiler = config + .measureme_out + .as_ref() + .map(|out| Profiler::new(out).expect("Couldn't create `measureme` profiler")); Evaluator { // `env_vars` could be initialized properly here if `Memory` were available before // calling this method. @@ -617,9 +615,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { let timing = if let Some(profiler) = ecx.machine.profiler.as_ref() { let fn_name = frame.instance.to_string(); let entry = ecx.machine.string_cache.entry(fn_name.clone()); - let name = entry.or_insert_with(|| { - profiler.alloc_string(&*fn_name) - }); + let name = entry.or_insert_with(|| profiler.alloc_string(&*fn_name)); Some(profiler.start_recording_interval_event_detached( *name, From 0317e5bfd60246c224071303f0ffa6a12a2096ab Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 30 May 2021 10:04:57 -0500 Subject: [PATCH 2688/5092] Address more review comments --- src/machine.rs | 25 ++++++++++++++++--------- src/shims/panic.rs | 1 + 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 1a01ece6c9a8..ed633b5e17f4 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -8,7 +8,6 @@ use std::num::NonZeroU64; use std::time::Instant; use log::trace; -use measureme::{DetachedTiming, EventId, Profiler, StringId}; use rand::rngs::StdRng; use rand::SeedableRng; @@ -47,7 +46,16 @@ pub struct FrameData<'tcx> { /// If `measureme` profiling is enabled, holds timing information /// for the start of this frame. When we finish executing this frame, /// we use this to register a completed event with `measureme`. - pub timing: Option, + pub timing: Option, +} + +impl<'tcx> std::fmt::Debug for FrameData<'tcx> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("FrameData") + .field("call_id", &self.call_id) + .field("catch_unwind", &self.catch_unwind) + .finish() + } } /// Extra memory kinds @@ -278,20 +286,19 @@ pub struct Evaluator<'mir, 'tcx> { /// The `measureme` profiler used to record timing information about /// the emulated program. - profiler: Option, + profiler: Option, /// Used with `profiler` to cache the `StringId`s for event names /// uesd with `measureme`. - string_cache: FxHashMap, + string_cache: FxHashMap, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Self { let layouts = PrimitiveLayouts::new(layout_cx).expect("Couldn't get layouts of primitive types"); - let profiler = config - .measureme_out - .as_ref() - .map(|out| Profiler::new(out).expect("Couldn't create `measureme` profiler")); + let profiler = config.measureme_out.as_ref().map(|out| { + measureme::Profiler::new(out).expect("Couldn't create `measureme` profiler") + }); Evaluator { // `env_vars` could be initialized properly here if `Memory` were available before // calling this method. @@ -619,7 +626,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { Some(profiler.start_recording_interval_event_detached( *name, - EventId::from_label(*name), + measureme::EventId::from_label(*name), ecx.get_active_thread().to_u32(), )) } else { diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 6b08ee8e1840..b1da7f340fce 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -119,6 +119,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, StackPopJump> { let this = self.eval_context_mut(); + trace!("handle_stack_pop(extra = {:?}, unwinding = {})", extra, unwinding); if let Some(stacked_borrows) = &this.memory.extra.stacked_borrows { stacked_borrows.borrow_mut().end_call(extra.call_id); } From c89a5d62ee4100018d8422ebdcddb47ed6290fcd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 May 2021 17:13:49 +0200 Subject: [PATCH 2689/5092] add comment to debug impl --- src/machine.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/machine.rs b/src/machine.rs index ed633b5e17f4..4f643e7f5091 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -51,6 +51,7 @@ pub struct FrameData<'tcx> { impl<'tcx> std::fmt::Debug for FrameData<'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // Omitting `timing`, it does not support `Debug`. f.debug_struct("FrameData") .field("call_id", &self.call_id) .field("catch_unwind", &self.catch_unwind) From 71f41405500cec42be22f0080bf3f83f97bfa768 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 30 May 2021 01:36:06 +0800 Subject: [PATCH 2690/5092] Add `-Zmiri-disable-abi-check` --- README.md | 4 + src/bin/miri.rs | 3 + src/eval.rs | 3 + src/helpers.rs | 13 +- src/machine.rs | 9 ++ src/shims/foreign_items.rs | 54 ++++---- src/shims/posix/dlsym.rs | 2 +- src/shims/posix/foreign_items.rs | 122 +++++++++--------- src/shims/posix/linux/foreign_items.rs | 32 ++--- src/shims/posix/macos/foreign_items.rs | 38 +++--- src/shims/windows/dlsym.rs | 2 +- src/shims/windows/foreign_items.rs | 80 ++++++------ tests/compile-fail/check_callback_abi.rs | 15 +++ .../concurrency/unwind_top_of_stack.rs | 6 +- tests/compile-fail/panic/bad_unwind.rs | 2 + tests/run-pass/disable_abi_check.rs | 24 ++++ 16 files changed, 235 insertions(+), 174 deletions(-) create mode 100644 tests/compile-fail/check_callback_abi.rs create mode 100644 tests/run-pass/disable_abi_check.rs diff --git a/README.md b/README.md index b214ab6d09c1..f87a7e989d97 100644 --- a/README.md +++ b/README.md @@ -214,6 +214,8 @@ environment variable: as out-of-bounds accesses) first. Setting this flag means Miri can miss bugs in your program. However, this can also help to make Miri run faster. Using this flag is **unsound**. +* `-Zmiri-disable-abi-check` disables checking [function ABI]. Using this flag + is **unsound**. * `-Zmiri-disable-isolation` disables host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness. @@ -263,6 +265,8 @@ environment variable: with `-Zmiri-track-raw-pointers` also works without `-Zmiri-track-raw-pointers`, but for the vast majority of code, this will be the case. +[function ABI]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier + Some native rustc `-Z` flags are also very relevant for Miri: * `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 47cde5c353e1..e921407f63fb 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -227,6 +227,9 @@ fn main() { "-Zmiri-symbolic-alignment-check" => { miri_config.check_alignment = miri::AlignmentCheck::Symbolic; } + "-Zmiri-disable-abi-check" => { + miri_config.check_abi = false; + } "-Zmiri-disable-isolation" => { miri_config.communicate = true; } diff --git a/src/eval.rs b/src/eval.rs index 52e554f57d7e..6646783d349c 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -31,6 +31,8 @@ pub struct MiriConfig { pub stacked_borrows: bool, /// Controls alignment checking. pub check_alignment: AlignmentCheck, + /// Controls function [ABI](Abi) checking. + pub check_abi: bool, /// Determines if communication with the host environment is enabled. pub communicate: bool, /// Determines if memory leaks should be ignored. @@ -65,6 +67,7 @@ impl Default for MiriConfig { validate: true, stacked_borrows: true, check_alignment: AlignmentCheck::Int, + check_abi: true, communicate: false, ignore_leaks: false, excluded_env_vars: vec![], diff --git a/src/helpers.rs b/src/helpers.rs index 45a5a8d4170b..af6985ccebdb 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -165,7 +165,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let param_env = ty::ParamEnv::reveal_all(); // in Miri this is always the param_env we use... and this.param_env is private. let callee_abi = f.ty(*this.tcx, param_env).fn_sig(*this.tcx).abi(); - if callee_abi != caller_abi { + if this.machine.enforce_abi && callee_abi != caller_abi { throw_ub_format!( "calling a function with ABI {} using caller ABI {}", callee_abi.name(), @@ -632,16 +632,19 @@ where } /// Check that the ABI is what we expect. -pub fn check_abi<'a>(abi: Abi, exp_abi: Abi) -> InterpResult<'a, ()> { - if abi == exp_abi { - Ok(()) - } else { +pub fn check_abi<'a>( + this: &MiriEvalContext<'_, '_>, + abi: Abi, + exp_abi: Abi, +) -> InterpResult<'a, ()> { + if this.machine.enforce_abi && abi != exp_abi { throw_ub_format!( "calling a function with ABI {} using caller ABI {}", exp_abi.name(), abi.name() ) } + Ok(()) } pub fn isolation_error(name: &str) -> InterpResult<'static> { diff --git a/src/machine.rs b/src/machine.rs index 4f643e7f5091..175396ed119c 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -270,6 +270,9 @@ pub struct Evaluator<'mir, 'tcx> { /// Whether to enforce the validity invariant. pub(crate) validate: bool, + /// Whether to enforce [ABI](Abi) of function calls. + pub(crate) enforce_abi: bool, + pub(crate) file_handler: shims::posix::FileHandler, pub(crate) dir_handler: shims::posix::DirHandler, @@ -310,6 +313,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { tls: TlsData::default(), communicate: config.communicate, validate: config.validate, + enforce_abi: config.check_abi, file_handler: Default::default(), dir_handler: Default::default(), time_anchor: Instant::now(), @@ -371,6 +375,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx.machine.validate } + #[inline(always)] + fn enforce_abi(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + ecx.machine.enforce_abi + } + #[inline(always)] fn find_mir_or_eval_fn( ecx: &mut InterpCx<'mir, 'tcx, Self>, diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 4c96c99eeeaf..2afa1a867128 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -136,14 +136,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (dest, ret) = match ret { None => match link_name { "miri_start_panic" => { - check_abi(abi, Abi::Rust)?; + check_abi(this, abi, Abi::Rust)?; this.handle_miri_start_panic(args, unwind)?; return Ok(None); } // This matches calls to the foreign item `panic_impl`. // The implementation is provided by the function with the `#[panic_handler]` attribute. "panic_impl" => { - check_abi(abi, Abi::Rust)?; + check_abi(this, abi, Abi::Rust)?; let panic_impl_id = tcx.lang_items().panic_impl().unwrap(); let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id); return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); @@ -152,14 +152,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "exit" | "ExitProcess" => { - check_abi(abi, if link_name == "exit" { Abi::C { unwind: false } } else { Abi::System { unwind: false } })?; + check_abi(this, abi, if link_name == "exit" { Abi::C { unwind: false } } else { Abi::System { unwind: false } })?; let &[ref code] = check_arg_count(args)?; // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway let code = this.read_scalar(code)?.to_i32()?; throw_machine_stop!(TerminationInfo::Exit(code.into())); } "abort" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; throw_machine_stop!(TerminationInfo::Abort( "the program aborted execution".to_owned() )) @@ -180,7 +180,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[rustfmt::skip] "__rust_start_panic" | "__rust_panic_cleanup" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; // This replicates some of the logic in `inject_panic_runtime`. // FIXME: is there a way to reuse that logic? let panic_runtime = match this.tcx.sess.panic_strategy() { @@ -221,7 +221,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Miri-specific extern functions "miri_static_root" => { - check_abi(abi, Abi::Rust)?; + check_abi(this, abi, Abi::Rust)?; let &[ref ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let ptr = this.force_ptr(ptr)?; @@ -233,27 +233,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Obtains a Miri backtrace. See the README for details. "miri_get_backtrace" => { - check_abi(abi, Abi::Rust)?; + check_abi(this, abi, Abi::Rust)?; this.handle_miri_get_backtrace(args, dest)?; } // Resolves a Miri backtrace frame. See the README for details. "miri_resolve_frame" => { - check_abi(abi, Abi::Rust)?; + check_abi(this, abi, Abi::Rust)?; this.handle_miri_resolve_frame(args, dest)?; } // Standard C allocation "malloc" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref size] = check_arg_count(args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C); this.write_scalar(res, dest)?; } "calloc" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref items, ref len] = check_arg_count(args)?; let items = this.read_scalar(items)?.to_machine_usize(this)?; let len = this.read_scalar(len)?.to_machine_usize(this)?; @@ -263,13 +263,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } "free" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; this.free(ptr, MiriMemoryKind::C)?; } "realloc" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref old_ptr, ref new_size] = check_arg_count(args)?; let old_ptr = this.read_scalar(old_ptr)?.check_init()?; let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; @@ -281,7 +281,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // (Usually these would be forwarded to to `#[global_allocator]`; we instead implement a generic // allocation that also checks that all conditions are met, such as not permitting zero-sized allocations.) "__rust_alloc" => { - check_abi(abi, Abi::Rust)?; + check_abi(this, abi, Abi::Rust)?; let &[ref size, ref align] = check_arg_count(args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -294,7 +294,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "__rust_alloc_zeroed" => { - check_abi(abi, Abi::Rust)?; + check_abi(this, abi, Abi::Rust)?; let &[ref size, ref align] = check_arg_count(args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -309,7 +309,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "__rust_dealloc" => { - check_abi(abi, Abi::Rust)?; + check_abi(this, abi, Abi::Rust)?; let &[ref ptr, ref old_size, ref align] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; @@ -323,7 +323,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; } "__rust_realloc" => { - check_abi(abi, Abi::Rust)?; + check_abi(this, abi, Abi::Rust)?; let &[ref ptr, ref old_size, ref align, ref new_size] = check_arg_count(args)?; let ptr = this.force_ptr(this.read_scalar(ptr)?.check_init()?)?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; @@ -344,7 +344,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // C memory handling functions "memcmp" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref left, ref right, ref n] = check_arg_count(args)?; let left = this.read_scalar(left)?.check_init()?; let right = this.read_scalar(right)?.check_init()?; @@ -365,7 +365,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "memrchr" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref ptr, ref val, ref num] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; @@ -384,7 +384,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "memchr" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref ptr, ref val, ref num] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; @@ -402,7 +402,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "strlen" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let n = this.read_c_str(ptr)?.len(); @@ -419,7 +419,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asinf" | "atanf" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref f] = check_arg_count(args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); @@ -440,7 +440,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypotf" | "atan2f" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref f1, ref f2] = check_arg_count(args)?; // underscore case for windows, here and below // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) @@ -463,7 +463,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asin" | "atan" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref f] = check_arg_count(args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); @@ -484,7 +484,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypot" | "atan2" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref f1, ref f2] = check_arg_count(args)?; // FIXME: Using host floats. let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?); @@ -501,7 +501,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "ldexp" | "scalbn" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref x, ref exp] = check_arg_count(args)?; // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. let x = this.read_scalar(x)?.to_f64()?; @@ -523,12 +523,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Architecture-specific shims "llvm.x86.sse2.pause" if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.yield_active_thread(); } "llvm.aarch64.isb" if this.tcx.sess.target.arch == "aarch64" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref arg] = check_arg_count(args)?; let arg = this.read_scalar(arg)?.to_i32()?; match arg { diff --git a/src/shims/posix/dlsym.rs b/src/shims/posix/dlsym.rs index df9e945f29f7..5f420ac5363b 100644 --- a/src/shims/posix/dlsym.rs +++ b/src/shims/posix/dlsym.rs @@ -35,7 +35,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; match dlsym { Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, ret), diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 52b41b49bd5e..5eb731d09c86 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -25,32 +25,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Environment related shims "getenv" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let result = this.getenv(name)?; this.write_scalar(result, dest)?; } "unsetenv" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let result = this.unsetenv(name)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "setenv" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref name, ref value, ref overwrite] = check_arg_count(args)?; this.read_scalar(overwrite)?.to_i32()?; let result = this.setenv(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "getcwd" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref buf, ref size] = check_arg_count(args)?; let result = this.getcwd(buf, size)?; this.write_scalar(result, dest)?; } "chdir" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref path] = check_arg_count(args)?; let result = this.chdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -58,18 +58,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "open" | "open64" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref path, ref flag, ref mode] = check_arg_count(args)?; let result = this.open(path, flag, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fcntl" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let result = this.fcntl(args)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "read" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref fd, ref buf, ref count] = check_arg_count(args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.check_init()?; @@ -78,7 +78,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "write" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref fd, ref buf, ref n] = check_arg_count(args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.check_init()?; @@ -89,62 +89,62 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "unlink" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref path] = check_arg_count(args)?; let result = this.unlink(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "symlink" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref target, ref linkpath] = check_arg_count(args)?; let result = this.symlink(target, linkpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rename" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref oldpath, ref newpath] = check_arg_count(args)?; let result = this.rename(oldpath, newpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mkdir" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref path, ref mode] = check_arg_count(args)?; let result = this.mkdir(path, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rmdir" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref path] = check_arg_count(args)?; let result = this.rmdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "closedir" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref dirp] = check_arg_count(args)?; let result = this.closedir(dirp)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lseek" | "lseek64" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref fd, ref offset, ref whence] = check_arg_count(args)?; let result = this.lseek64(fd, offset, whence)?; // "lseek" is only used on macOS which is 64bit-only, so `i64` always works. this.write_scalar(Scalar::from_i64(result), dest)?; } "fsync" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref fd] = check_arg_count(args)?; let result = this.fsync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fdatasync" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref fd] = check_arg_count(args)?; let result = this.fdatasync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "readlink" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref pathname, ref buf, ref bufsize] = check_arg_count(args)?; let result = this.readlink(pathname, buf, bufsize)?; this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; @@ -152,7 +152,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Allocation "posix_memalign" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref ret, ref align, ref size] = check_arg_count(args)?; let ret = this.deref_operand(ret)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -183,7 +183,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamic symbol loading "dlsym" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref handle, ref symbol] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_usize(this)?; let symbol = this.read_scalar(symbol)?.check_init()?; @@ -198,7 +198,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "sysconf" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let name = this.read_scalar(name)?.to_i32()?; @@ -224,7 +224,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "pthread_key_create" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref key, ref dtor] = check_arg_count(args)?; let key_place = this.deref_operand(key)?; let dtor = this.read_scalar(dtor)?.check_init()?; @@ -253,7 +253,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_key_delete" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref key] = check_arg_count(args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; this.machine.tls.delete_tls_key(key)?; @@ -261,7 +261,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_getspecific" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref key] = check_arg_count(args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); @@ -269,7 +269,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref key, ref new_ptr] = check_arg_count(args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); @@ -282,132 +282,132 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Synchronization primitives "pthread_mutexattr_init" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref attr] = check_arg_count(args)?; let result = this.pthread_mutexattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_settype" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref attr, ref kind] = check_arg_count(args)?; let result = this.pthread_mutexattr_settype(attr, kind)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_destroy" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref attr] = check_arg_count(args)?; let result = this.pthread_mutexattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_init" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref mutex, ref attr] = check_arg_count(args)?; let result = this.pthread_mutex_init(mutex, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_lock" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_lock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_trylock" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_trylock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_unlock" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_unlock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_destroy" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_destroy(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_rdlock" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_rdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_tryrdlock" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_tryrdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_wrlock" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_wrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_trywrlock" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_trywrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_unlock" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_unlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_destroy" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_destroy(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_init" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref attr] = check_arg_count(args)?; let result = this.pthread_condattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_destroy" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref attr] = check_arg_count(args)?; let result = this.pthread_condattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_init" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref cond, ref attr] = check_arg_count(args)?; let result = this.pthread_cond_init(cond, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_signal" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref cond] = check_arg_count(args)?; let result = this.pthread_cond_signal(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_broadcast" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref cond] = check_arg_count(args)?; let result = this.pthread_cond_broadcast(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_wait" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref cond, ref mutex] = check_arg_count(args)?; let result = this.pthread_cond_wait(cond, mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_timedwait" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref cond, ref mutex, ref abstime] = check_arg_count(args)?; this.pthread_cond_timedwait(cond, mutex, abstime, dest)?; } "pthread_cond_destroy" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref cond] = check_arg_count(args)?; let result = this.pthread_cond_destroy(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -415,36 +415,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_create" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref thread, ref attr, ref start, ref arg] = check_arg_count(args)?; let result = this.pthread_create(thread, attr, start, arg)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_join" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref thread, ref retval] = check_arg_count(args)?; let result = this.pthread_join(thread, retval)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_detach" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref thread] = check_arg_count(args)?; let result = this.pthread_detach(thread)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_self" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.pthread_self(dest)?; } "sched_yield" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; let result = this.sched_yield()?; this.write_scalar(Scalar::from_i32(result), dest)?; } "nanosleep" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref req, ref rem] = check_arg_count(args)?; let result = this.nanosleep(req, rem)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -452,7 +452,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscellaneous "isatty" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref fd] = check_arg_count(args)?; this.read_scalar(fd)?.to_i32()?; // "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error" @@ -462,7 +462,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_atfork" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref prepare, ref parent, ref child] = check_arg_count(args)?; this.force_bits(this.read_scalar(prepare)?.check_init()?, this.memory.pointer_size())?; this.force_bits(this.read_scalar(parent)?.check_init()?, this.memory.pointer_size())?; @@ -475,7 +475,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These shims are enabled only when the caller is in the standard library. "pthread_attr_getguardsize" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref _attr, ref guard_size] = check_arg_count(args)?; let guard_size = this.deref_operand(guard_size)?; let guard_size_layout = this.libc_ty_layout("size_t")?; @@ -488,13 +488,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "pthread_attr_init" | "pthread_attr_destroy" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[_] = check_arg_count(args)?; this.write_null(dest)?; } | "pthread_attr_setstacksize" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[_, _] = check_arg_count(args)?; this.write_null(dest)?; } @@ -502,14 +502,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "signal" | "sigaltstack" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[_, _] = check_arg_count(args)?; this.write_null(dest)?; } | "sigaction" | "mprotect" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[_, _, _] = check_arg_count(args)?; this.write_null(dest)?; } diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index f7d7706e3f5e..d16c740ffc54 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -23,7 +23,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // errno "__errno_location" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; @@ -33,32 +33,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These symbols have different names on Linux and macOS, which is the only reason they are not // in the `posix` module. "close" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref fd] = check_arg_count(args)?; let result = this.close(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir64_r" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref dirp, ref entry, ref result] = check_arg_count(args)?; let result = this.linux_readdir64_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate64" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref fd, ref length] = check_arg_count(args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Linux-only "posix_fadvise" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref fd, ref offset, ref len, ref advice] = check_arg_count(args)?; this.read_scalar(fd)?.to_i32()?; this.read_scalar(offset)?.to_machine_isize(this)?; @@ -68,7 +68,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "sync_file_range" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref fd, ref offset, ref nbytes, ref flags] = check_arg_count(args)?; let result = this.sync_file_range(fd, offset, nbytes, flags)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -76,7 +76,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "clock_gettime" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; // This is a POSIX function but it has only been tested on linux. let &[ref clk_id, ref tp] = check_arg_count(args)?; let result = this.clock_gettime(clk_id, tp)?; @@ -85,7 +85,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_attr_getstack" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. let &[ref attr_place, ref addr_place, ref size_place] = check_arg_count(args)?; this.deref_operand(attr_place)?; @@ -107,19 +107,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "prctl" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref option, ref arg2, ref arg3, ref arg4, ref arg5] = check_arg_count(args)?; let result = this.prctl(option, arg2, arg3, arg4, arg5)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_setclock" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref attr, ref clock_id] = check_arg_count(args)?; let result = this.pthread_condattr_setclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_getclock" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref attr, ref clock_id] = check_arg_count(args)?; let result = this.pthread_condattr_getclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -127,7 +127,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamically invoked syscalls "syscall" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; // The syscall variadic function is legal to call with more arguments than needed, // extra arguments are simply ignored. However, all arguments need to be scalars; // other types might be treated differently by the calling convention. @@ -188,12 +188,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscelanneous "getrandom" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref ptr, ref len, ref flags] = check_arg_count(args)?; getrandom(this, ptr, len, flags, dest)?; } "sched_getaffinity" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref pid, ref cpusetsize, ref mask] = check_arg_count(args)?; this.read_scalar(pid)?.to_i32()?; this.read_scalar(cpusetsize)?.to_machine_usize(this)?; @@ -209,7 +209,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "pthread_getattr_np" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref _thread, ref _attr] = check_arg_count(args)?; this.write_null(dest)?; } diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index 9a7d3be1eb9a..de4ed56633cb 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -21,7 +21,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // errno "__error" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; @@ -29,43 +29,43 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "close" | "close$NOCANCEL" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref result] = check_arg_count(args)?; let result = this.close(result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "stat" | "stat$INODE64" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref path, ref buf] = check_arg_count(args)?; let result = this.macos_stat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lstat" | "lstat$INODE64" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref path, ref buf] = check_arg_count(args)?; let result = this.macos_lstat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fstat" | "fstat$INODE64" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref fd, ref buf] = check_arg_count(args)?; let result = this.macos_fstat(fd, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" | "opendir$INODE64" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir_r" | "readdir_r$INODE64" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref dirp, ref entry, ref result] = check_arg_count(args)?; let result = this.macos_readdir_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref fd, ref length] = check_arg_count(args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -73,27 +73,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Environment related shims "_NSGetEnviron" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.write_scalar(this.machine.env_vars.environ.unwrap().ptr, dest)?; } // Time related shims "gettimeofday" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref tv, ref tz] = check_arg_count(args)?; let result = this.gettimeofday(tv, tz)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mach_absolute_time" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; let result = this.mach_absolute_time()?; this.write_scalar(Scalar::from_u64(result), dest)?; } "mach_timebase_info" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref info] = check_arg_count(args)?; let result = this.mach_timebase_info(info)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -101,19 +101,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Access to command-line arguments "_NSGetArgc" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?; } "_NSGetArgv" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; } // Thread-local storage "_tlv_atexit" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref dtor, ref data] = check_arg_count(args)?; let dtor = this.read_scalar(dtor)?.check_init()?; let dtor = this.memory.get_fn(dtor)?.as_instance()?; @@ -124,14 +124,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_get_stackaddr_np" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref thread] = check_arg_count(args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size()); this.write_scalar(stack_addr, dest)?; } "pthread_get_stacksize_np" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref thread] = check_arg_count(args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size()); @@ -140,7 +140,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_setname_np" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let name = this.read_scalar(name)?.check_init()?; this.pthread_setname_np(name)?; @@ -149,7 +149,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "mmap" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. let &[ref addr, _, _, _, _, _] = check_arg_count(args)?; let addr = this.read_scalar(addr)?.check_init()?; diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index ace6c4674ae9..18e2ed3db59b 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -31,7 +31,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (_dest, _ret) = ret.expect("we don't support any diverging dlsym"); assert!(this.tcx.sess.target.os == "windows"); - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; match dlsym {} } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index b246ccc33cf7..d7b86fff7327 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -28,37 +28,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Environment related shims "GetEnvironmentVariableW" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref name, ref buf, ref size] = check_arg_count(args)?; let result = this.GetEnvironmentVariableW(name, buf, size)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetEnvironmentVariableW" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref name, ref value] = check_arg_count(args)?; let result = this.SetEnvironmentVariableW(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetEnvironmentStringsW" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; let result = this.GetEnvironmentStringsW()?; this.write_scalar(result, dest)?; } "FreeEnvironmentStringsW" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref env_block] = check_arg_count(args)?; let result = this.FreeEnvironmentStringsW(env_block)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetCurrentDirectoryW" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref size, ref buf] = check_arg_count(args)?; let result = this.GetCurrentDirectoryW(size, buf)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetCurrentDirectoryW" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref path] = check_arg_count(args)?; let result = this.SetCurrentDirectoryW(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -66,7 +66,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "GetStdHandle" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref which] = check_arg_count(args)?; let which = this.read_scalar(which)?.to_i32()?; // We just make this the identity function, so we know later in `WriteFile` @@ -74,7 +74,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?; } "WriteFile" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref handle, ref buf, ref n, ref written_ptr, ref overlapped] = check_arg_count(args)?; this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore @@ -110,7 +110,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Allocation "HeapAlloc" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref handle, ref flags, ref size] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; let flags = this.read_scalar(flags)?.to_u32()?; @@ -120,7 +120,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } "HeapFree" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref handle, ref flags, ref ptr] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; @@ -129,7 +129,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(1), dest)?; } "HeapReAlloc" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref handle, ref flags, ref ptr, ref size] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; @@ -141,13 +141,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // errno "SetLastError" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref error] = check_arg_count(args)?; let error = this.read_scalar(error)?.check_init()?; this.set_last_error(error)?; } "GetLastError" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; let last_error = this.get_last_error()?; this.write_scalar(last_error, dest)?; @@ -155,7 +155,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "GetSystemInfo" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref system_info] = check_arg_count(args)?; let system_info = this.deref_operand(system_info)?; // Initialize with `0`. @@ -171,7 +171,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "TlsAlloc" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; // This just creates a key; Windows does not natively support TLS destructors. // Create key and return it. @@ -180,7 +180,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref key] = check_arg_count(args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); @@ -188,7 +188,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "TlsSetValue" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref key, ref new_ptr] = check_arg_count(args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); @@ -201,7 +201,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Access to command-line arguments "GetCommandLineW" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; this.write_scalar( this.machine.cmd_line.expect("machine must be initialized"), @@ -211,20 +211,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "GetSystemTimeAsFileTime" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref LPFILETIME] = check_arg_count(args)?; this.GetSystemTimeAsFileTime(LPFILETIME)?; } "QueryPerformanceCounter" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref lpPerformanceCount] = check_arg_count(args)?; let result = this.QueryPerformanceCounter(lpPerformanceCount)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "QueryPerformanceFrequency" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref lpFrequency] = check_arg_count(args)?; let result = this.QueryPerformanceFrequency(lpFrequency)?; @@ -233,33 +233,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Synchronization primitives "AcquireSRWLockExclusive" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; this.AcquireSRWLockExclusive(ptr)?; } "ReleaseSRWLockExclusive" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; this.ReleaseSRWLockExclusive(ptr)?; } "TryAcquireSRWLockExclusive" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; let ret = this.TryAcquireSRWLockExclusive(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; } "AcquireSRWLockShared" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; this.AcquireSRWLockShared(ptr)?; } "ReleaseSRWLockShared" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; this.ReleaseSRWLockShared(ptr)?; } "TryAcquireSRWLockShared" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; let ret = this.TryAcquireSRWLockShared(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; @@ -267,7 +267,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamic symbol loading "GetProcAddress" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref hModule, ref lpProcName] = check_arg_count(args)?; this.read_scalar(hModule)?.to_machine_isize(this)?; @@ -283,7 +283,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscellaneous "SystemFunction036" => { // This is really 'RtlGenRandom'. - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref ptr, ref len] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_u32()?; @@ -291,7 +291,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_bool(true), dest)?; } "BCryptGenRandom" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref algorithm, ref ptr, ref len, ref flags] = check_arg_count(args)?; let algorithm = this.read_scalar(algorithm)?; let ptr = this.read_scalar(ptr)?.check_init()?; @@ -312,7 +312,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; // STATUS_SUCCESS } "GetConsoleScreenBufferInfo" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; // `term` needs this, so we fake it. let &[ref console, ref buffer_info] = check_arg_count(args)?; this.read_scalar(console)?.to_machine_isize(this)?; @@ -322,7 +322,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "GetConsoleMode" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; // Windows "isatty" (in libtest) needs this, so we fake it. let &[ref console, ref mode] = check_arg_count(args)?; this.read_scalar(console)?.to_machine_isize(this)?; @@ -332,7 +332,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "SwitchToThread" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; // Note that once Miri supports concurrency, this will need to return a nonzero // value if this call does result in switching to another thread. @@ -341,7 +341,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Better error for attempts to create a thread "CreateThread" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; throw_unsup_format!("Miri does not support concurrency on Windows"); } @@ -350,7 +350,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "GetProcessHeap" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; // Just fake a HANDLE this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; @@ -358,7 +358,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _hConsoleOutput, ref _wAttribute] = check_arg_count(args)?; // Pretend these does not exist / nothing happened, by returning zero. @@ -367,7 +367,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "AddVectoredExceptionHandler" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _First, ref _Handler] = check_arg_count(args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. @@ -376,7 +376,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "SetThreadStackGuarantee" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[_StackSizeInBytes] = check_arg_count(args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. @@ -388,7 +388,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "DeleteCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _lpCriticalSection] = check_arg_count(args)?; assert_eq!( @@ -403,7 +403,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "TryEnterCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _lpCriticalSection] = check_arg_count(args)?; assert_eq!( diff --git a/tests/compile-fail/check_callback_abi.rs b/tests/compile-fail/check_callback_abi.rs new file mode 100644 index 000000000000..69dfc0359831 --- /dev/null +++ b/tests/compile-fail/check_callback_abi.rs @@ -0,0 +1,15 @@ +#![feature(core_intrinsics)] + +extern "C" fn try_fn(_: *mut u8) { + unreachable!(); +} + +fn main() { + unsafe { + std::intrinsics::r#try( //~ ERROR calling a function with ABI C using caller ABI Rust + std::mem::transmute::(try_fn), + std::ptr::null_mut(), + |_, _| unreachable!(), + ); + } +} diff --git a/tests/compile-fail/concurrency/unwind_top_of_stack.rs b/tests/compile-fail/concurrency/unwind_top_of_stack.rs index 8f3bb17470b5..138a43d9d731 100644 --- a/tests/compile-fail/concurrency/unwind_top_of_stack.rs +++ b/tests/compile-fail/concurrency/unwind_top_of_stack.rs @@ -1,10 +1,8 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// error-pattern: calling a function with ABI C-unwind using caller ABI C +// compile-flags: -Zmiri-disable-abi-check +// error-pattern: unwinding past the topmost frame of the stack //! Unwinding past the top frame of a stack is Undefined Behavior. -//! However, it is impossible to do that in pure Rust since one cannot write an unwinding -//! function with `C` ABI... so let's instead test that we are indeed correctly checking -//! the callee ABI in `pthread_create`. #![feature(rustc_private, c_unwind)] diff --git a/tests/compile-fail/panic/bad_unwind.rs b/tests/compile-fail/panic/bad_unwind.rs index fde2c19af07d..cfb109cb8b56 100644 --- a/tests/compile-fail/panic/bad_unwind.rs +++ b/tests/compile-fail/panic/bad_unwind.rs @@ -4,6 +4,8 @@ //! Unwinding when the caller ABI is "C" (without "-unwind") is UB. //! Currently we detect the ABI mismatch; we could probably allow such calls in principle one day //! but then we have to detect the unexpected unwinding. +//! FIXME: `-Zmiri-disable-abi-check` does not work for this test because function pointers are +//! always allowed to unwind. extern "C-unwind" fn unwind() { panic!(); diff --git a/tests/run-pass/disable_abi_check.rs b/tests/run-pass/disable_abi_check.rs new file mode 100644 index 000000000000..1f8554741376 --- /dev/null +++ b/tests/run-pass/disable_abi_check.rs @@ -0,0 +1,24 @@ +// compile-flags: -Zmiri-disable-abi-check +#![feature(core_intrinsics)] + +fn main() { + fn foo() {} + + extern "C" fn try_fn(ptr: *mut u8) { + assert!(ptr.is_null()); + } + + extern "Rust" { + fn malloc(size: usize) -> *mut std::ffi::c_void; + } + + unsafe { + let _ = malloc(0); + std::mem::transmute::(foo)(); + std::intrinsics::r#try( + std::mem::transmute::(try_fn), + std::ptr::null_mut(), + |_, _| unreachable!(), + ); + } +} From 41f33a64f878cb28567c2773906859ce8a0614e5 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Fri, 16 Apr 2021 05:19:23 +0800 Subject: [PATCH 2691/5092] Implement calls to exported symbols --- src/bin/miri.rs | 80 +++++++-- src/diagnostics.rs | 64 ++++--- src/lib.rs | 2 + src/machine.rs | 6 +- src/shims/foreign_items.rs | 159 +++++++++++++----- src/shims/posix/foreign_items.rs | 5 +- src/shims/posix/linux/foreign_items.rs | 7 +- src/shims/posix/macos/foreign_items.rs | 7 +- src/shims/windows/foreign_items.rs | 7 +- test-cargo-miri/Cargo.lock | 12 ++ test-cargo-miri/Cargo.toml | 3 +- .../exported-symbol-dep/Cargo.toml | 5 + .../exported-symbol-dep/src/lib.rs | 4 + test-cargo-miri/exported-symbol/Cargo.toml | 11 ++ test-cargo-miri/exported-symbol/src/lib.rs | 1 + test-cargo-miri/src/lib.rs | 16 ++ test-cargo-miri/test.default.stdout.ref | 11 +- test-cargo-miri/test.filter.stdout.ref | 2 +- .../{ => function_calls}/check_arg_abi.rs | 0 .../check_arg_count_too_few_args.rs | 0 .../check_arg_count_too_many_args.rs | 0 .../check_callback_abi.rs | 0 .../exported_symbol_abi_mismatch.rs | 22 +++ .../exported_symbol_bad_unwind1.rs | 15 ++ .../exported_symbol_bad_unwind2.rs | 19 +++ .../exported_symbol_bad_unwind3.rs | 16 ++ .../exported_symbol_clashing.rs | 15 ++ .../exported_symbol_wrong_arguments.rs | 9 + .../exported_symbol_wrong_type.rs | 9 + .../panic/bad_miri_start_panic.rs | 10 ++ .../panic/rustc_allocator_nounwind.rs | 10 ++ .../{ => function_calls}/disable_abi_check.rs | 0 .../function_calls/exported_symbol.rs | 44 +++++ .../exported_symbol_good_unwind.rs | 49 ++++++ .../exported_symbol_good_unwind.stderr | 5 + .../exported_symbol_unwind_allowed.rs | 15 ++ .../exported_symbol_unwind_allowed.stderr | 2 + tests/run-pass/panic/good_unwind.rs | 27 +++ tests/run-pass/panic/good_unwind.stderr | 5 + 39 files changed, 584 insertions(+), 90 deletions(-) create mode 100644 test-cargo-miri/exported-symbol-dep/Cargo.toml create mode 100644 test-cargo-miri/exported-symbol-dep/src/lib.rs create mode 100644 test-cargo-miri/exported-symbol/Cargo.toml create mode 100644 test-cargo-miri/exported-symbol/src/lib.rs rename tests/compile-fail/{ => function_calls}/check_arg_abi.rs (100%) rename tests/compile-fail/{ => function_calls}/check_arg_count_too_few_args.rs (100%) rename tests/compile-fail/{ => function_calls}/check_arg_count_too_many_args.rs (100%) rename tests/compile-fail/{ => function_calls}/check_callback_abi.rs (100%) create mode 100644 tests/compile-fail/function_calls/exported_symbol_abi_mismatch.rs create mode 100644 tests/compile-fail/function_calls/exported_symbol_bad_unwind1.rs create mode 100644 tests/compile-fail/function_calls/exported_symbol_bad_unwind2.rs create mode 100644 tests/compile-fail/function_calls/exported_symbol_bad_unwind3.rs create mode 100644 tests/compile-fail/function_calls/exported_symbol_clashing.rs create mode 100644 tests/compile-fail/function_calls/exported_symbol_wrong_arguments.rs create mode 100644 tests/compile-fail/function_calls/exported_symbol_wrong_type.rs create mode 100644 tests/compile-fail/panic/bad_miri_start_panic.rs create mode 100644 tests/compile-fail/panic/rustc_allocator_nounwind.rs rename tests/run-pass/{ => function_calls}/disable_abi_check.rs (100%) create mode 100644 tests/run-pass/function_calls/exported_symbol.rs create mode 100644 tests/run-pass/function_calls/exported_symbol_good_unwind.rs create mode 100644 tests/run-pass/function_calls/exported_symbol_good_unwind.stderr create mode 100644 tests/run-pass/function_calls/exported_symbol_unwind_allowed.rs create mode 100644 tests/run-pass/function_calls/exported_symbol_unwind_allowed.stderr create mode 100644 tests/run-pass/panic/good_unwind.rs create mode 100644 tests/run-pass/panic/good_unwind.stderr diff --git a/src/bin/miri.rs b/src/bin/miri.rs index e921407f63fb..7368d4b253ba 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -1,14 +1,17 @@ -#![feature(rustc_private)] +#![feature(rustc_private, bool_to_option, stmt_expr_attributes)] extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_hir; extern crate rustc_interface; +extern crate rustc_metadata; extern crate rustc_middle; extern crate rustc_session; use std::convert::TryFrom; use std::env; +use std::path::PathBuf; +use std::rc::Rc; use std::str::FromStr; use hex::FromHexError; @@ -16,14 +19,34 @@ use log::debug; use rustc_driver::Compilation; use rustc_errors::emitter::{ColorConfig, HumanReadableErrorType}; -use rustc_middle::ty::TyCtxt; -use rustc_session::{config::ErrorOutputType, CtfeBacktrace}; +use rustc_hir::def_id::LOCAL_CRATE; +use rustc_interface::interface::Config; +use rustc_middle::{ + middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}, + ty::{query::Providers, TyCtxt}, +}; +use rustc_session::{config::ErrorOutputType, search_paths::PathKind, CtfeBacktrace}; struct MiriCompilerCalls { miri_config: miri::MiriConfig, } impl rustc_driver::Callbacks for MiriCompilerCalls { + fn config(&mut self, config: &mut Config) { + config.override_queries = Some(|_, _, external_providers| { + external_providers.used_crate_source = |tcx, cnum| { + let mut providers = Providers::default(); + rustc_metadata::provide_extern(&mut providers); + let mut crate_source = (providers.used_crate_source)(tcx, cnum); + // HACK: rustc will emit "crate ... required to be available in rlib format, but + // was not found in this form" errors once we use `tcx.dependency_formats()` if + // there's no rlib provided, so setting a dummy path here to workaround those errors. + Rc::make_mut(&mut crate_source).rlib = Some((PathBuf::new(), PathKind::All)); + crate_source + }; + }); + } + fn after_analysis<'tcx>( &mut self, compiler: &rustc_interface::interface::Compiler, @@ -67,6 +90,39 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { } } +struct MiriBeRustCompilerCalls { + target_crate: bool, +} + +impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { + fn config(&mut self, config: &mut Config) { + if config.opts.prints.is_empty() && self.target_crate { + // Queries overriden here affects the data stored in `rmeta` files of dependencies, + // which will be used later in non-`MIRI_BE_RUSTC` mode. + config.override_queries = Some(|_, local_providers, _| { + // `exported_symbols()` provided by rustc always returns empty result if + // `tcx.sess.opts.output_types.should_codegen()` is false. + local_providers.exported_symbols = |tcx, cnum| { + assert_eq!(cnum, LOCAL_CRATE); + tcx.arena.alloc_from_iter( + // This is based on: + // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L62-L63 + // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L174 + tcx.reachable_set(()).iter().filter_map(|&local_def_id| { + tcx.codegen_fn_attrs(local_def_id) + .contains_extern_indicator() + .then_some(( + ExportedSymbol::NonGeneric(local_def_id.to_def_id()), + SymbolExportLevel::C, + )) + }), + ) + } + }); + } + } +} + fn init_early_loggers() { // Note that our `extern crate log` is *not* the same as rustc's; as a result, we have to // initialize them both, and we always initialize `miri`'s first. @@ -179,11 +235,7 @@ fn main() { if let Some(crate_kind) = env::var_os("MIRI_BE_RUSTC") { rustc_driver::init_rustc_env_logger(); - // Don't insert `MIRI_DEFAULT_ARGS`, in particular, `--cfg=miri`, if we are building a - // "host" crate. That may cause procedural macros (and probably build scripts) to depend - // on Miri-only symbols, such as `miri_resolve_frame`: - // https://github.com/rust-lang/miri/issues/1760 - let insert_default_args = if crate_kind == "target" { + let target_crate = if crate_kind == "target" { true } else if crate_kind == "host" { false @@ -192,8 +244,16 @@ fn main() { }; // We cannot use `rustc_driver::main` as we need to adjust the CLI arguments. - let mut callbacks = rustc_driver::TimePassesCallbacks::default(); - run_compiler(env::args().collect(), &mut callbacks, insert_default_args) + run_compiler( + env::args().collect(), + &mut MiriBeRustCompilerCalls { target_crate }, + // Don't insert `MIRI_DEFAULT_ARGS`, in particular, `--cfg=miri`, if we are building + // a "host" crate. That may cause procedural macros (and probably build scripts) to + // depend on Miri-only symbols, such as `miri_resolve_frame`: + // https://github.com/rust-lang/miri/issues/1760 + #[rustfmt::skip] + /* insert_default_args: */ target_crate, + ) } // Init loggers the Miri way. diff --git a/src/diagnostics.rs b/src/diagnostics.rs index ae50b5086022..55702fb3c96b 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -5,7 +5,7 @@ use std::num::NonZeroU64; use log::trace; use rustc_middle::ty::{self, TyCtxt}; -use rustc_span::{source_map::DUMMY_SP, Span}; +use rustc_span::{source_map::DUMMY_SP, Span, SpanData, Symbol}; use crate::*; @@ -14,8 +14,18 @@ pub enum TerminationInfo { Exit(i64), Abort(String), UnsupportedInIsolation(String), - ExperimentalUb { msg: String, url: String }, + ExperimentalUb { + msg: String, + url: String, + }, Deadlock, + MultipleSymbolDefinitions { + link_name: Symbol, + first: SpanData, + first_crate: Symbol, + second: SpanData, + second_crate: Symbol, + }, } impl fmt::Display for TerminationInfo { @@ -27,6 +37,8 @@ impl fmt::Display for TerminationInfo { UnsupportedInIsolation(msg) => write!(f, "{}", msg), ExperimentalUb { msg, .. } => write!(f, "{}", msg), Deadlock => write!(f, "the evaluated program deadlocked"), + MultipleSymbolDefinitions { link_name, .. } => + write!(f, "multiple definitions of symbol `{}`", link_name), } } } @@ -55,19 +67,25 @@ pub fn report_error<'tcx, 'mir>( use TerminationInfo::*; let title = match info { Exit(code) => return Some(*code), - Abort(_) => "abnormal termination", - UnsupportedInIsolation(_) => "unsupported operation", - ExperimentalUb { .. } => "Undefined Behavior", - Deadlock => "deadlock", + Abort(_) => Some("abnormal termination"), + UnsupportedInIsolation(_) => Some("unsupported operation"), + ExperimentalUb { .. } => Some("Undefined Behavior"), + Deadlock => Some("deadlock"), + MultipleSymbolDefinitions { .. } => None, }; #[rustfmt::skip] let helps = match info { UnsupportedInIsolation(_) => - vec![format!("pass the flag `-Zmiri-disable-isolation` to disable isolation")], + vec![(None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation"))], ExperimentalUb { url, .. } => vec![ - format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental"), - format!("see {} for further information", url), + (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental")), + (None, format!("see {} for further information", url)), + ], + MultipleSymbolDefinitions { first, first_crate, second, second_crate, .. } => + vec![ + (Some(*first), format!("it's first defined here, in crate `{}`", first_crate)), + (Some(*second), format!("then it's defined here again, in crate `{}`", second_crate)), ], _ => vec![], }; @@ -90,26 +108,26 @@ pub fn report_error<'tcx, 'mir>( #[rustfmt::skip] let helps = match e.kind() { Unsupported(UnsupportedOpInfo::NoMirFor(..)) => - vec![format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`")], + vec![(None, format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`"))], Unsupported(UnsupportedOpInfo::ReadBytesAsPointer | UnsupportedOpInfo::ThreadLocalStatic(_) | UnsupportedOpInfo::ReadExternStatic(_)) => panic!("Error should never be raised by Miri: {:?}", e.kind()), Unsupported(_) => - vec![format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support")], + vec![(None, format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"))], UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. }) if ecx.memory.extra.check_alignment == AlignmentCheck::Symbolic => vec![ - format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior"), - format!("but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives"), + (None, format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior")), + (None, format!("but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives")), ], UndefinedBehavior(_) => vec![ - format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior"), - format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information"), + (None, format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior")), + (None, format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information")), ], _ => vec![], }; - (title, helps) + (Some(title), helps) } }; @@ -118,7 +136,7 @@ pub fn report_error<'tcx, 'mir>( report_msg( *ecx.tcx, /*error*/ true, - &format!("{}: {}", title, msg), + &if let Some(title) = title { format!("{}: {}", title, msg) } else { msg.clone() }, msg, helps, &ecx.generate_stacktrace(), @@ -157,7 +175,7 @@ fn report_msg<'tcx>( error: bool, title: &str, span_msg: String, - mut helps: Vec, + mut helps: Vec<(Option, String)>, stacktrace: &[FrameInfo<'tcx>], ) { let span = stacktrace.first().map_or(DUMMY_SP, |fi| fi.span); @@ -177,9 +195,13 @@ fn report_msg<'tcx>( // Show help messages. if !helps.is_empty() { // Add visual separator before backtrace. - helps.last_mut().unwrap().push_str("\n"); - for help in helps { - err.help(&help); + helps.last_mut().unwrap().1.push_str("\n"); + for (span_data, help) in helps { + if let Some(span_data) = span_data { + err.span_help(span_data.span(), &help); + } else { + err.help(&help); + } } } // Add backtrace diff --git a/src/lib.rs b/src/lib.rs index c9645d12fad1..25806b472b60 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ #![feature(map_try_insert)] #![feature(never_type)] #![feature(try_blocks)] +#![feature(bool_to_option)] #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] @@ -14,6 +15,7 @@ extern crate rustc_data_structures; extern crate rustc_hir; extern crate rustc_index; extern crate rustc_mir; +extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; diff --git a/src/machine.rs b/src/machine.rs index 175396ed119c..9c49575ded32 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -17,7 +17,7 @@ use rustc_middle::{ ty::{ self, layout::{LayoutCx, LayoutError, TyAndLayout}, - TyCtxt, + Instance, TyCtxt, }, }; use rustc_span::def_id::DefId; @@ -294,6 +294,9 @@ pub struct Evaluator<'mir, 'tcx> { /// Used with `profiler` to cache the `StringId`s for event names /// uesd with `measureme`. string_cache: FxHashMap, + + /// Cache of `Instance` exported under the given `Symbol` name. + pub(crate) exported_symbols_cache: FxHashMap>, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { @@ -322,6 +325,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { static_roots: Vec::new(), profiler, string_cache: Default::default(), + exported_symbols_cache: FxHashMap::default(), } } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 2afa1a867128..2269b41d576f 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -6,19 +6,37 @@ use std::{ use log::trace; use rustc_apfloat::Float; -use rustc_hir::def_id::DefId; +use rustc_hir::{ + def::DefKind, + def_id::{CrateNum, DefId, LOCAL_CRATE}, +}; +use rustc_middle::middle::{ + codegen_fn_attrs::CodegenFnAttrFlags, dependency_format::Linkage, + exported_symbols::ExportedSymbol, +}; use rustc_middle::mir; use rustc_middle::ty; -use rustc_span::symbol::sym; +use rustc_session::config::CrateType; +use rustc_span::{symbol::sym, Symbol}; use rustc_target::{ abi::{Align, Size}, - spec::{abi::Abi, PanicStrategy}, + spec::abi::Abi, }; use super::backtrace::EvalContextExt as _; use crate::*; use helpers::{check_abi, check_arg_count}; +/// Returned by `emulate_foreign_item_by_name`. +pub enum EmulateByNameResult { + /// The caller is expected to jump to the return block. + NeedsJumping, + /// Jumping has already been taken care of. + AlreadyJumped, + /// The item is not supported. + NotSupported, +} + impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Returns the minimum alignment for the target architecture for allocations of the given size. @@ -108,6 +126,76 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + /// Lookup the body of a function that has `link_name` as the symbol name. + fn lookup_exported_symbol( + &mut self, + link_name: Symbol, + ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { + let this = self.eval_context_mut(); + let tcx = this.tcx.tcx; + + // If the result was cached, just return it. + if let Some(instance) = this.machine.exported_symbols_cache.get(&link_name) { + return Ok(Some(this.load_mir(instance.def, None)?)); + } + + // Find it if it was not cached. + let mut instance_and_crate: Option<(ty::Instance<'_>, CrateNum)> = None; + // `dependency_formats` includes all the transitive informations needed to link a crate, + // which is what we need here since we need to dig out `exported_symbols` from all transitive + // dependencies. + let dependency_formats = tcx.dependency_formats(()); + let dependency_format = dependency_formats + .iter() + .find(|(crate_type, _)| *crate_type == CrateType::Executable) + .expect("interpreting a non-executable crate"); + for cnum in + iter::once(LOCAL_CRATE).chain(dependency_format.1.iter().enumerate().filter_map( + |(num, &linkage)| (linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1)), + )) + { + // FIXME: Do we need to check `SymbolExportLevel` (the `_` below)? + for &(symbol, _) in tcx.exported_symbols(cnum) { + if let ExportedSymbol::NonGeneric(def_id) = symbol { + let attrs = tcx.codegen_fn_attrs(def_id); + let symbol_name = if let Some(export_name) = attrs.export_name { + export_name + } else if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) { + tcx.item_name(def_id) + } else { + // Skip over items without an explicitly defined symbol name. + continue; + }; + if symbol_name == link_name { + if let Some((instance, original_cnum)) = instance_and_crate { + throw_machine_stop!(TerminationInfo::MultipleSymbolDefinitions { + link_name, + first: tcx.def_span(instance.def_id()).data(), + first_crate: tcx.crate_name(original_cnum), + second: tcx.def_span(def_id).data(), + second_crate: tcx.crate_name(cnum), + }); + } + if tcx.def_kind(def_id) != DefKind::Fn { + throw_ub_format!( + "attempt to call an exported symbol that is not defined as a function" + ); + } + instance_and_crate = Some((ty::Instance::mono(tcx, def_id), cnum)); + } + } + } + } + + // Cache it and load its MIR, if found. + instance_and_crate + .map(|(instance, _)| { + this.machine.exported_symbols_cache.insert(link_name, instance); + this.load_mir(instance.def, None) + }) + .transpose() + } + /// Emulates calling a foreign item, failing if the item is not supported. /// This function will handle `goto_block` if needed. /// Returns Ok(None) if the foreign item was completely handled @@ -124,10 +212,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); - let link_name = match this.tcx.sess.first_attr_value_str_by_name(&attrs, sym::link_name) { - Some(name) => name.as_str(), - None => this.tcx.item_name(def_id).as_str(), + let link_name_sym = match this.tcx.sess.first_attr_value_str_by_name(&attrs, sym::link_name) + { + Some(name) => name, + None => this.tcx.item_name(def_id), }; + let link_name = link_name_sym.as_str(); // Strip linker suffixes (seen on 32-bit macOS). let link_name = link_name.trim_end_matches("$UNIX2003"); let tcx = this.tcx.tcx; @@ -164,48 +254,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "the program aborted execution".to_owned() )) } - _ => throw_unsup_format!("can't call (diverging) foreign function: {}", link_name), + _ => { + if let Some(body) = this.lookup_exported_symbol(link_name_sym)? { + return Ok(Some(body)); + } + throw_unsup_format!("can't call (diverging) foreign function: {}", link_name); + } }, Some(p) => p, }; - // Second: some functions that we forward to MIR implementations. - match link_name { - // This matches calls to the foreign item `__rust_start_panic`, that is, - // calls to `extern "Rust" { fn __rust_start_panic(...) }` - // (and `__rust_panic_cleanup`, respectively). - // We forward this to the underlying *implementation* in the panic runtime crate. - // Normally, this will be either `libpanic_unwind` or `libpanic_abort`, but it could - // also be a custom user-provided implementation via `#![feature(panic_runtime)]` - #[rustfmt::skip] - "__rust_start_panic" | - "__rust_panic_cleanup" => { - check_abi(this, abi, Abi::C { unwind: false })?; - // This replicates some of the logic in `inject_panic_runtime`. - // FIXME: is there a way to reuse that logic? - let panic_runtime = match this.tcx.sess.panic_strategy() { - PanicStrategy::Unwind => sym::panic_unwind, - PanicStrategy::Abort => sym::panic_abort, - }; - let start_panic_instance = - this.resolve_path(&[&*panic_runtime.as_str(), link_name]); - return Ok(Some(&*this.load_mir(start_panic_instance.def, None)?)); + // Second: functions that return. + match this.emulate_foreign_item_by_name(link_name, abi, args, dest, ret)? { + EmulateByNameResult::NeedsJumping => { + trace!("{:?}", this.dump_place(**dest)); + this.go_to_block(ret); + } + EmulateByNameResult::AlreadyJumped => (), + EmulateByNameResult::NotSupported => { + if let Some(body) = this.lookup_exported_symbol(link_name_sym)? { + return Ok(Some(body)); + } + throw_unsup_format!("can't call foreign function: {}", link_name); } - _ => {} - } - - // Third: functions that return. - if this.emulate_foreign_item_by_name(link_name, abi, args, dest, ret)? { - trace!("{:?}", this.dump_place(**dest)); - this.go_to_block(ret); } Ok(None) } - /// Emulates calling a foreign item using its name, failing if the item is not supported. - /// Returns `true` if the caller is expected to jump to the return block, and `false` if - /// jumping has already been taken care of. + /// Emulates calling a foreign item using its name. fn emulate_foreign_item_by_name( &mut self, link_name: &str, @@ -213,7 +290,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, ret: mir::BasicBlock, - ) -> InterpResult<'tcx, bool> { + ) -> InterpResult<'tcx, EmulateByNameResult> { let this = self.eval_context_mut(); // Here we dispatch all the shims for foreign functions. If you have a platform specific @@ -549,7 +626,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } }; - Ok(true) + // We only fall through to here if we did *not* hit the `_` arm above, + // i.e., if we actually emulated the function. + Ok(EmulateByNameResult::NeedsJumping) } /// Check some basic requirements for this allocation request: diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 5eb731d09c86..f153098cac85 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -6,6 +6,7 @@ use rustc_target::spec::abi::Abi; use crate::*; use helpers::{check_abi, check_arg_count}; +use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; use shims::posix::sync::EvalContextExt as _; use shims::posix::thread::EvalContextExt as _; @@ -19,7 +20,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, ret: mir::BasicBlock, - ) -> InterpResult<'tcx, bool> { + ) -> InterpResult<'tcx, EmulateByNameResult> { let this = self.eval_context_mut(); match link_name { @@ -524,6 +525,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } }; - Ok(true) + Ok(EmulateByNameResult::NeedsJumping) } } diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index d16c740ffc54..47ffad56d122 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -3,6 +3,7 @@ use rustc_target::spec::abi::Abi; use crate::helpers::{check_abi, check_arg_count}; use crate::*; +use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; use shims::posix::linux::sync::futex; use shims::posix::sync::EvalContextExt as _; @@ -17,7 +18,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, _ret: mir::BasicBlock, - ) -> InterpResult<'tcx, bool> { + ) -> InterpResult<'tcx, EmulateByNameResult> { let this = self.eval_context_mut(); match link_name { @@ -214,10 +215,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - _ => throw_unsup_format!("can't call foreign function: {}", link_name), + _ => return Ok(EmulateByNameResult::NotSupported), }; - Ok(true) + Ok(EmulateByNameResult::NeedsJumping) } } diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index de4ed56633cb..15a073dd04ef 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -3,6 +3,7 @@ use rustc_target::spec::abi::Abi; use crate::*; use helpers::{check_abi, check_arg_count}; +use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; use shims::posix::thread::EvalContextExt as _; @@ -15,7 +16,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, _ret: mir::BasicBlock, - ) -> InterpResult<'tcx, bool> { + ) -> InterpResult<'tcx, EmulateByNameResult> { let this = self.eval_context_mut(); match link_name { @@ -156,9 +157,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(addr, dest)?; } - _ => throw_unsup_format!("can't call foreign function: {}", link_name), + _ => return Ok(EmulateByNameResult::NotSupported), }; - Ok(true) + Ok(EmulateByNameResult::NeedsJumping) } } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index d7b86fff7327..0f9e3899b85a 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -6,6 +6,7 @@ use rustc_target::spec::abi::Abi; use crate::*; use helpers::{check_abi, check_arg_count}; +use shims::foreign_items::EmulateByNameResult; use shims::windows::sync::EvalContextExt as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -17,7 +18,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, _ret: mir::BasicBlock, - ) -> InterpResult<'tcx, bool> { + ) -> InterpResult<'tcx, EmulateByNameResult> { let this = self.eval_context_mut(); // Windows API stubs. @@ -415,9 +416,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(1), dest)?; } - _ => throw_unsup_format!("can't call foreign function: {}", link_name), + _ => return Ok(EmulateByNameResult::NotSupported), } - Ok(true) + Ok(EmulateByNameResult::NeedsJumping) } } diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 403b9327930a..9a9fa4797bf2 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -14,6 +14,7 @@ version = "0.1.0" dependencies = [ "byteorder", "cdylib", + "exported_symbol", "getrandom 0.1.16", "getrandom 0.2.2", "issue_1567", @@ -37,6 +38,17 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "exported_symbol" +version = "0.1.0" +dependencies = [ + "exported_symbol_dep", +] + +[[package]] +name = "exported_symbol_dep" +version = "0.1.0" + [[package]] name = "getrandom" version = "0.1.16" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 4dbe1aeff23a..cf557bd60ef3 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["subcrate", "issue-1567"] +members = ["subcrate", "issue-1567", "exported-symbol-dep"] [package] name = "cargo-miri-test" @@ -10,6 +10,7 @@ edition = "2018" [dependencies] byteorder = "1.0" cdylib = { path = "cdylib" } +exported_symbol = { path = "exported-symbol" } issue_1567 = { path = "issue-1567" } issue_1691 = { path = "issue-1691" } issue_1705 = { path = "issue-1705" } diff --git a/test-cargo-miri/exported-symbol-dep/Cargo.toml b/test-cargo-miri/exported-symbol-dep/Cargo.toml new file mode 100644 index 000000000000..00c41172c3af --- /dev/null +++ b/test-cargo-miri/exported-symbol-dep/Cargo.toml @@ -0,0 +1,5 @@ +[package] +name = "exported_symbol_dep" +version = "0.1.0" +authors = ["Miri Team"] +edition = "2018" diff --git a/test-cargo-miri/exported-symbol-dep/src/lib.rs b/test-cargo-miri/exported-symbol-dep/src/lib.rs new file mode 100644 index 000000000000..4cc18fb9b2fb --- /dev/null +++ b/test-cargo-miri/exported-symbol-dep/src/lib.rs @@ -0,0 +1,4 @@ +#[no_mangle] +fn exported_symbol() -> i32 { + 123456 +} diff --git a/test-cargo-miri/exported-symbol/Cargo.toml b/test-cargo-miri/exported-symbol/Cargo.toml new file mode 100644 index 000000000000..7c01be1a85f9 --- /dev/null +++ b/test-cargo-miri/exported-symbol/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "exported_symbol" +version = "0.1.0" +authors = ["Miri Team"] +edition = "2018" + +[dependencies] +# This will become a transitive dependency of doctests in `test-cargo-miri/src/lib.rs`, +# and the purpose of the test is to make sure Miri can find a `#[no_mangle]` function in a +# transitive dependency like `exported_symbol_dep`. +exported_symbol_dep = { path = "../exported-symbol-dep" } diff --git a/test-cargo-miri/exported-symbol/src/lib.rs b/test-cargo-miri/exported-symbol/src/lib.rs new file mode 100644 index 000000000000..de55eb2a1a5a --- /dev/null +++ b/test-cargo-miri/exported-symbol/src/lib.rs @@ -0,0 +1 @@ +extern crate exported_symbol_dep; diff --git a/test-cargo-miri/src/lib.rs b/test-cargo-miri/src/lib.rs index 9d8eb067d6fa..6397d072e89e 100644 --- a/test-cargo-miri/src/lib.rs +++ b/test-cargo-miri/src/lib.rs @@ -1,6 +1,21 @@ +extern crate exported_symbol; + /// Doc-test test /// ```rust /// assert!(cargo_miri_test::make_true()); +/// // Repeat calls to make sure the `Instance` cache is not broken. +/// for _ in 0..3 { +/// extern "Rust" { +/// fn exported_symbol() -> i32; +/// fn make_true() -> bool; +/// } +/// assert_eq!(unsafe { exported_symbol() }, 123456); +/// assert!(unsafe { make_true() }); +/// } +/// ``` +/// ```compile_fail +/// // Make sure `exported_symbol_dep` is not a direct dependency for doctests. +/// use exported_symbol_dep; /// ``` /// ```rust,no_run /// assert!(!cargo_miri_test::make_true()); @@ -8,6 +23,7 @@ /// ```rust,compile_fail /// assert!(cargo_miri_test::make_true() == 5); /// ``` +#[no_mangle] pub fn make_true() -> bool { issue_1567::use_the_dependency(); issue_1705::use_the_dependency(); diff --git a/test-cargo-miri/test.default.stdout.ref b/test-cargo-miri/test.default.stdout.ref index 470e5b36fc51..e97119f217f7 100644 --- a/test-cargo-miri/test.default.stdout.ref +++ b/test-cargo-miri/test.default.stdout.ref @@ -10,10 +10,11 @@ running 7 tests test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out -running 3 tests -test src/lib.rs - make_true (line 2) ... ok -test src/lib.rs - make_true (line 5) ... ok -test src/lib.rs - make_true (line 8) ... ok +running 4 tests +test src/lib.rs - make_true (line 16) ... ok +test src/lib.rs - make_true (line 20) ... ok +test src/lib.rs - make_true (line 23) ... ok +test src/lib.rs - make_true (line 4) ... ok -test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/test-cargo-miri/test.filter.stdout.ref b/test-cargo-miri/test.filter.stdout.ref index cf1b309a1278..61565a4c1e4a 100644 --- a/test-cargo-miri/test.filter.stdout.ref +++ b/test-cargo-miri/test.filter.stdout.ref @@ -13,5 +13,5 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 3 filtered out; finished in $TIME +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 4 filtered out; finished in $TIME diff --git a/tests/compile-fail/check_arg_abi.rs b/tests/compile-fail/function_calls/check_arg_abi.rs similarity index 100% rename from tests/compile-fail/check_arg_abi.rs rename to tests/compile-fail/function_calls/check_arg_abi.rs diff --git a/tests/compile-fail/check_arg_count_too_few_args.rs b/tests/compile-fail/function_calls/check_arg_count_too_few_args.rs similarity index 100% rename from tests/compile-fail/check_arg_count_too_few_args.rs rename to tests/compile-fail/function_calls/check_arg_count_too_few_args.rs diff --git a/tests/compile-fail/check_arg_count_too_many_args.rs b/tests/compile-fail/function_calls/check_arg_count_too_many_args.rs similarity index 100% rename from tests/compile-fail/check_arg_count_too_many_args.rs rename to tests/compile-fail/function_calls/check_arg_count_too_many_args.rs diff --git a/tests/compile-fail/check_callback_abi.rs b/tests/compile-fail/function_calls/check_callback_abi.rs similarity index 100% rename from tests/compile-fail/check_callback_abi.rs rename to tests/compile-fail/function_calls/check_callback_abi.rs diff --git a/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.rs b/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.rs new file mode 100644 index 000000000000..d62cb2e8b7ad --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.rs @@ -0,0 +1,22 @@ +// revisions: no_cache cache + +#[no_mangle] +fn foo() {} + +fn main() { + #[cfg(cache)] + { + // `Instance` caching should not suppress ABI check. + extern "Rust" { + fn foo(); + } + unsafe { foo() } + } + #[cfg_attr(cache, allow(clashing_extern_declarations))] + extern "C" { + fn foo(); + } + unsafe { foo() } + //[no_cache]~^ ERROR Undefined Behavior: calling a function with ABI Rust using caller ABI C + //[cache]~^^ ERROR Undefined Behavior: calling a function with ABI Rust using caller ABI C +} diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind1.rs b/tests/compile-fail/function_calls/exported_symbol_bad_unwind1.rs new file mode 100644 index 000000000000..91b0e8fc03f2 --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_bad_unwind1.rs @@ -0,0 +1,15 @@ +// compile-flags: -Zmiri-disable-abi-check +#![feature(c_unwind)] + +#[no_mangle] +extern "C-unwind" fn unwind() { + panic!(); +} + +fn main() { + extern "C" { + fn unwind(); + } + unsafe { unwind() } + //~^ ERROR unwinding past a stack frame that does not allow unwinding +} diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.rs b/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.rs new file mode 100644 index 000000000000..85cca8f1a6bd --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.rs @@ -0,0 +1,19 @@ +// revisions: extern_block definition both +#![feature(rustc_attrs, c_unwind)] + +#[cfg_attr(any(definition, both), rustc_allocator_nounwind)] +#[no_mangle] +extern "C-unwind" fn nounwind() { + panic!(); +} + +fn main() { + extern "C-unwind" { + #[cfg_attr(any(extern_block, both), rustc_allocator_nounwind)] + fn nounwind(); + } + unsafe { nounwind() } + //[extern_block]~^ ERROR unwinding past a stack frame that does not allow unwinding + //[definition]~^^ ERROR unwinding past a stack frame that does not allow unwinding + //[both]~^^^ ERROR unwinding past a stack frame that does not allow unwinding +} diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind3.rs b/tests/compile-fail/function_calls/exported_symbol_bad_unwind3.rs new file mode 100644 index 000000000000..dfb378cef523 --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_bad_unwind3.rs @@ -0,0 +1,16 @@ +#![feature(unwind_attributes)] +#![feature(c_unwind)] // make sure it doesn't insert abort-on-unwind for the `#[unwind(allowed)]` function + +#[unwind(allowed)] +#[no_mangle] +extern "C" fn unwind() { + panic!(); +} + +fn main() { + extern "C" { + fn unwind(); + } + unsafe { unwind() } + //~^ ERROR unwinding past a stack frame that does not allow unwinding +} diff --git a/tests/compile-fail/function_calls/exported_symbol_clashing.rs b/tests/compile-fail/function_calls/exported_symbol_clashing.rs new file mode 100644 index 000000000000..105d98fc10a9 --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_clashing.rs @@ -0,0 +1,15 @@ +#[no_mangle] +fn foo() {} +//~^ HELP then it's defined here again, in crate `exported_symbol_clashing` + +#[export_name = "foo"] +fn bar() {} +//~^ HELP it's first defined here, in crate `exported_symbol_clashing` + +fn main() { + extern "Rust" { + fn foo(); + } + unsafe { foo() } + //~^ ERROR multiple definitions of symbol `foo` +} diff --git a/tests/compile-fail/function_calls/exported_symbol_wrong_arguments.rs b/tests/compile-fail/function_calls/exported_symbol_wrong_arguments.rs new file mode 100644 index 000000000000..8fb364bb9bd1 --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_wrong_arguments.rs @@ -0,0 +1,9 @@ +#[no_mangle] +fn foo() {} + +fn main() { + extern "Rust" { + fn foo(_: i32); + } + unsafe { foo(1) } //~ ERROR calling a function with more arguments than it expected +} diff --git a/tests/compile-fail/function_calls/exported_symbol_wrong_type.rs b/tests/compile-fail/function_calls/exported_symbol_wrong_type.rs new file mode 100644 index 000000000000..3ffd506c94bb --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_wrong_type.rs @@ -0,0 +1,9 @@ +#[no_mangle] +static FOO: () = (); + +fn main() { + extern "C" { + fn FOO(); + } + unsafe { FOO() } //~ ERROR attempt to call an exported symbol that is not defined as a function +} diff --git a/tests/compile-fail/panic/bad_miri_start_panic.rs b/tests/compile-fail/panic/bad_miri_start_panic.rs new file mode 100644 index 000000000000..f77f892abc1c --- /dev/null +++ b/tests/compile-fail/panic/bad_miri_start_panic.rs @@ -0,0 +1,10 @@ +// compile-flags: -Zmiri-disable-abi-check + +extern "C" { + fn miri_start_panic(payload: *mut u8) -> !; +} + +fn main() { + unsafe { miri_start_panic(&mut 0) } + //~^ ERROR unwinding past a stack frame that does not allow unwinding +} diff --git a/tests/compile-fail/panic/rustc_allocator_nounwind.rs b/tests/compile-fail/panic/rustc_allocator_nounwind.rs new file mode 100644 index 000000000000..7261b6658753 --- /dev/null +++ b/tests/compile-fail/panic/rustc_allocator_nounwind.rs @@ -0,0 +1,10 @@ +#![feature(rustc_attrs, c_unwind)] + +#[rustc_allocator_nounwind] +extern "C-unwind" fn nounwind() { + panic!(); +} + +fn main() { + nounwind(); //~ ERROR unwinding past a stack frame that does not allow unwinding +} diff --git a/tests/run-pass/disable_abi_check.rs b/tests/run-pass/function_calls/disable_abi_check.rs similarity index 100% rename from tests/run-pass/disable_abi_check.rs rename to tests/run-pass/function_calls/disable_abi_check.rs diff --git a/tests/run-pass/function_calls/exported_symbol.rs b/tests/run-pass/function_calls/exported_symbol.rs new file mode 100644 index 000000000000..7f359e80219f --- /dev/null +++ b/tests/run-pass/function_calls/exported_symbol.rs @@ -0,0 +1,44 @@ +#![feature(rustc_attrs)] + +#[no_mangle] +extern "C" fn foo() -> i32 { + -1 +} + +#[export_name = "bar"] +fn bar() -> i32 { + -2 +} + +#[rustc_std_internal_symbol] +fn baz() -> i32 { + -3 +} + +// Make sure shims take precedence. +#[no_mangle] +extern "C" fn exit(_: i32) -> ! { + unreachable!() +} + +#[no_mangle] +extern "C" fn ExitProcess(_: u32) -> ! { + unreachable!() +} + +fn main() { + // Repeat calls to make sure the `Instance` cache is not broken. + for _ in 0..3 { + extern "C" { + fn foo() -> i32; + } + assert_eq!(unsafe { foo() }, -1); + assert_eq!(unsafe { foo() }, -1); + extern "Rust" { + fn bar() -> i32; + fn baz() -> i32; + } + assert_eq!(unsafe { bar() }, -2); + assert_eq!(unsafe { baz() }, -3); + } +} diff --git a/tests/run-pass/function_calls/exported_symbol_good_unwind.rs b/tests/run-pass/function_calls/exported_symbol_good_unwind.rs new file mode 100644 index 000000000000..73192707f1e4 --- /dev/null +++ b/tests/run-pass/function_calls/exported_symbol_good_unwind.rs @@ -0,0 +1,49 @@ +// Make sure the workaround for "crate ... required to be available in rlib format, but was not +// found in this form" errors works without `-C prefer-dynamic` (`panic!` calls foreign function +// foreign function `__rust_start_panic`). +// no-prefer-dynamic +#![feature(c_unwind, unboxed_closures, unwind_attributes)] + +use std::panic; + +#[no_mangle] +#[unwind(allowed)] +extern "C" fn good_unwind_allowed() { + panic!(); +} + +#[no_mangle] +extern "C-unwind" fn good_unwind_c() { + panic!(); +} + +#[no_mangle] +fn good_unwind_rust() { + panic!(); +} + +// Diverging function calls are on a different code path. +#[no_mangle] +extern "rust-call" fn good_unwind_rust_call(_: ()) -> ! { + panic!(); +} + +fn main() -> ! { + extern "C" { + #[unwind(allowed)] + fn good_unwind_allowed(); + } + panic::catch_unwind(|| unsafe { good_unwind_allowed() }).unwrap_err(); + extern "C-unwind" { + fn good_unwind_c(); + } + panic::catch_unwind(|| unsafe { good_unwind_c() }).unwrap_err(); + extern "Rust" { + fn good_unwind_rust(); + } + panic::catch_unwind(|| unsafe { good_unwind_rust() }).unwrap_err(); + extern "rust-call" { + fn good_unwind_rust_call(_: ()) -> !; + } + unsafe { good_unwind_rust_call(()) } +} diff --git a/tests/run-pass/function_calls/exported_symbol_good_unwind.stderr b/tests/run-pass/function_calls/exported_symbol_good_unwind.stderr new file mode 100644 index 000000000000..3347f00b65ea --- /dev/null +++ b/tests/run-pass/function_calls/exported_symbol_good_unwind.stderr @@ -0,0 +1,5 @@ +thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:12:5 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:17:5 +thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:22:5 +thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:28:5 diff --git a/tests/run-pass/function_calls/exported_symbol_unwind_allowed.rs b/tests/run-pass/function_calls/exported_symbol_unwind_allowed.rs new file mode 100644 index 000000000000..0e4ec5739a8a --- /dev/null +++ b/tests/run-pass/function_calls/exported_symbol_unwind_allowed.rs @@ -0,0 +1,15 @@ +// compile-flags: -Zmiri-disable-abi-check +#![feature(unwind_attributes, c_unwind)] + +#[no_mangle] +extern "C-unwind" fn unwind() { + panic!(); +} + +fn main() { + extern "C" { + #[unwind(allowed)] + fn unwind(); + } + unsafe { unwind() } +} diff --git a/tests/run-pass/function_calls/exported_symbol_unwind_allowed.stderr b/tests/run-pass/function_calls/exported_symbol_unwind_allowed.stderr new file mode 100644 index 000000000000..14ee43950cec --- /dev/null +++ b/tests/run-pass/function_calls/exported_symbol_unwind_allowed.stderr @@ -0,0 +1,2 @@ +thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_unwind_allowed.rs:6:5 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/panic/good_unwind.rs b/tests/run-pass/panic/good_unwind.rs new file mode 100644 index 000000000000..dbc1c1631f13 --- /dev/null +++ b/tests/run-pass/panic/good_unwind.rs @@ -0,0 +1,27 @@ +#![feature(c_unwind, unboxed_closures, unwind_attributes)] + +use std::panic; + +extern "C-unwind" fn good_unwind_c() { + panic!(); +} + +#[unwind(allowed)] +extern "C" fn good_unwind_allowed() { + panic!(); +} + +fn good_unwind_rust() { + panic!(); +} + +extern "rust-call" fn good_unwind_rust_call(_: ()) { + panic!(); +} + +fn main() { + panic::catch_unwind(|| good_unwind_c()).unwrap_err(); + panic::catch_unwind(|| good_unwind_allowed()).unwrap_err(); + panic::catch_unwind(|| good_unwind_rust()).unwrap_err(); + good_unwind_rust_call(()); +} diff --git a/tests/run-pass/panic/good_unwind.stderr b/tests/run-pass/panic/good_unwind.stderr new file mode 100644 index 000000000000..1cd361790b66 --- /dev/null +++ b/tests/run-pass/panic/good_unwind.stderr @@ -0,0 +1,5 @@ +thread 'main' panicked at 'explicit panic', $DIR/good_unwind.rs:6:5 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +thread 'main' panicked at 'explicit panic', $DIR/good_unwind.rs:11:5 +thread 'main' panicked at 'explicit panic', $DIR/good_unwind.rs:15:5 +thread 'main' panicked at 'explicit panic', $DIR/good_unwind.rs:19:5 From ddc2ee9db6d3d00528ab52f5fcf9a76338b35088 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 30 May 2021 20:30:00 +0800 Subject: [PATCH 2692/5092] Move `-Zmiri-disable-abi-check` in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f87a7e989d97..f0e14a9125c6 100644 --- a/README.md +++ b/README.md @@ -200,6 +200,8 @@ environment variable: `compare_exchange_weak` operations. The default is `0.8` (so 4 out of 5 weak ops will fail). You can change it to any value between `0.0` and `1.0`, where `1.0` means it will always fail and `0.0` means it will never fail. +* `-Zmiri-disable-abi-check` disables checking [function ABI]. Using this flag + is **unsound**. * `-Zmiri-disable-alignment-check` disables checking pointer alignment, so you can focus on other failures, but it means Miri can miss bugs in your program. Using this flag is **unsound**. @@ -214,8 +216,6 @@ environment variable: as out-of-bounds accesses) first. Setting this flag means Miri can miss bugs in your program. However, this can also help to make Miri run faster. Using this flag is **unsound**. -* `-Zmiri-disable-abi-check` disables checking [function ABI]. Using this flag - is **unsound**. * `-Zmiri-disable-isolation` disables host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness. From 382295cd4745cdf2f52794a16fd7083fef01d0b8 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 30 May 2021 20:38:52 +0800 Subject: [PATCH 2693/5092] Move `check_abi()` into `EvalContextExt` --- src/helpers.rs | 28 +++--- src/shims/foreign_items.rs | 54 +++++------ src/shims/posix/dlsym.rs | 3 +- src/shims/posix/foreign_items.rs | 124 ++++++++++++------------- src/shims/posix/linux/foreign_items.rs | 34 +++---- src/shims/posix/macos/foreign_items.rs | 40 ++++---- src/shims/windows/dlsym.rs | 3 +- src/shims/windows/foreign_items.rs | 82 ++++++++-------- 8 files changed, 181 insertions(+), 187 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index af6985ccebdb..12d18799ebcd 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -616,6 +616,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(wchars) } + + /// Check that the ABI is what we expect. + fn check_abi<'a>(&self, abi: Abi, exp_abi: Abi) -> InterpResult<'a, ()> { + if self.eval_context_ref().machine.enforce_abi && abi != exp_abi { + throw_ub_format!( + "calling a function with ABI {} using caller ABI {}", + exp_abi.name(), + abi.name() + ) + } + Ok(()) + } } /// Check that the number of args is what we expect. @@ -631,22 +643,6 @@ where throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N) } -/// Check that the ABI is what we expect. -pub fn check_abi<'a>( - this: &MiriEvalContext<'_, '_>, - abi: Abi, - exp_abi: Abi, -) -> InterpResult<'a, ()> { - if this.machine.enforce_abi && abi != exp_abi { - throw_ub_format!( - "calling a function with ABI {} using caller ABI {}", - exp_abi.name(), - abi.name() - ) - } - Ok(()) -} - pub fn isolation_error(name: &str) -> InterpResult<'static> { throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!( "{} not available when isolation is enabled", diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 2269b41d576f..70de55c5be75 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -25,7 +25,7 @@ use rustc_target::{ use super::backtrace::EvalContextExt as _; use crate::*; -use helpers::{check_abi, check_arg_count}; +use helpers::check_arg_count; /// Returned by `emulate_foreign_item_by_name`. pub enum EmulateByNameResult { @@ -226,14 +226,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (dest, ret) = match ret { None => match link_name { "miri_start_panic" => { - check_abi(this, abi, Abi::Rust)?; + this.check_abi(abi, Abi::Rust)?; this.handle_miri_start_panic(args, unwind)?; return Ok(None); } // This matches calls to the foreign item `panic_impl`. // The implementation is provided by the function with the `#[panic_handler]` attribute. "panic_impl" => { - check_abi(this, abi, Abi::Rust)?; + this.check_abi(abi, Abi::Rust)?; let panic_impl_id = tcx.lang_items().panic_impl().unwrap(); let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id); return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); @@ -242,14 +242,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "exit" | "ExitProcess" => { - check_abi(this, abi, if link_name == "exit" { Abi::C { unwind: false } } else { Abi::System { unwind: false } })?; + this.check_abi(abi, if link_name == "exit" { Abi::C { unwind: false } } else { Abi::System { unwind: false } })?; let &[ref code] = check_arg_count(args)?; // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway let code = this.read_scalar(code)?.to_i32()?; throw_machine_stop!(TerminationInfo::Exit(code.into())); } "abort" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; throw_machine_stop!(TerminationInfo::Abort( "the program aborted execution".to_owned() )) @@ -298,7 +298,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Miri-specific extern functions "miri_static_root" => { - check_abi(this, abi, Abi::Rust)?; + this.check_abi(abi, Abi::Rust)?; let &[ref ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let ptr = this.force_ptr(ptr)?; @@ -310,27 +310,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Obtains a Miri backtrace. See the README for details. "miri_get_backtrace" => { - check_abi(this, abi, Abi::Rust)?; + this.check_abi(abi, Abi::Rust)?; this.handle_miri_get_backtrace(args, dest)?; } // Resolves a Miri backtrace frame. See the README for details. "miri_resolve_frame" => { - check_abi(this, abi, Abi::Rust)?; + this.check_abi(abi, Abi::Rust)?; this.handle_miri_resolve_frame(args, dest)?; } // Standard C allocation "malloc" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref size] = check_arg_count(args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C); this.write_scalar(res, dest)?; } "calloc" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref items, ref len] = check_arg_count(args)?; let items = this.read_scalar(items)?.to_machine_usize(this)?; let len = this.read_scalar(len)?.to_machine_usize(this)?; @@ -340,13 +340,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } "free" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; this.free(ptr, MiriMemoryKind::C)?; } "realloc" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref old_ptr, ref new_size] = check_arg_count(args)?; let old_ptr = this.read_scalar(old_ptr)?.check_init()?; let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; @@ -358,7 +358,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // (Usually these would be forwarded to to `#[global_allocator]`; we instead implement a generic // allocation that also checks that all conditions are met, such as not permitting zero-sized allocations.) "__rust_alloc" => { - check_abi(this, abi, Abi::Rust)?; + this.check_abi(abi, Abi::Rust)?; let &[ref size, ref align] = check_arg_count(args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -371,7 +371,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "__rust_alloc_zeroed" => { - check_abi(this, abi, Abi::Rust)?; + this.check_abi(abi, Abi::Rust)?; let &[ref size, ref align] = check_arg_count(args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -386,7 +386,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "__rust_dealloc" => { - check_abi(this, abi, Abi::Rust)?; + this.check_abi(abi, Abi::Rust)?; let &[ref ptr, ref old_size, ref align] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; @@ -400,7 +400,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; } "__rust_realloc" => { - check_abi(this, abi, Abi::Rust)?; + this.check_abi(abi, Abi::Rust)?; let &[ref ptr, ref old_size, ref align, ref new_size] = check_arg_count(args)?; let ptr = this.force_ptr(this.read_scalar(ptr)?.check_init()?)?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; @@ -421,7 +421,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // C memory handling functions "memcmp" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref left, ref right, ref n] = check_arg_count(args)?; let left = this.read_scalar(left)?.check_init()?; let right = this.read_scalar(right)?.check_init()?; @@ -442,7 +442,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "memrchr" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref ptr, ref val, ref num] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; @@ -461,7 +461,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "memchr" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref ptr, ref val, ref num] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; @@ -479,7 +479,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "strlen" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let n = this.read_c_str(ptr)?.len(); @@ -496,7 +496,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asinf" | "atanf" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref f] = check_arg_count(args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); @@ -517,7 +517,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypotf" | "atan2f" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref f1, ref f2] = check_arg_count(args)?; // underscore case for windows, here and below // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) @@ -540,7 +540,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asin" | "atan" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref f] = check_arg_count(args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); @@ -561,7 +561,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypot" | "atan2" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref f1, ref f2] = check_arg_count(args)?; // FIXME: Using host floats. let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?); @@ -578,7 +578,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "ldexp" | "scalbn" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref x, ref exp] = check_arg_count(args)?; // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. let x = this.read_scalar(x)?.to_f64()?; @@ -600,12 +600,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Architecture-specific shims "llvm.x86.sse2.pause" if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.yield_active_thread(); } "llvm.aarch64.isb" if this.tcx.sess.target.arch == "aarch64" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref arg] = check_arg_count(args)?; let arg = this.read_scalar(arg)?.to_i32()?; match arg { diff --git a/src/shims/posix/dlsym.rs b/src/shims/posix/dlsym.rs index 5f420ac5363b..b07bf91a69a5 100644 --- a/src/shims/posix/dlsym.rs +++ b/src/shims/posix/dlsym.rs @@ -2,7 +2,6 @@ use rustc_middle::mir; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::check_abi; use shims::posix::linux::dlsym as linux; use shims::posix::macos::dlsym as macos; @@ -35,7 +34,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; match dlsym { Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, ret), diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index f153098cac85..a756256aab41 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -5,7 +5,7 @@ use rustc_target::abi::{Align, LayoutOf, Size}; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::{check_abi, check_arg_count}; +use helpers::check_arg_count; use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; use shims::posix::sync::EvalContextExt as _; @@ -26,32 +26,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Environment related shims "getenv" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let result = this.getenv(name)?; this.write_scalar(result, dest)?; } "unsetenv" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let result = this.unsetenv(name)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "setenv" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref name, ref value, ref overwrite] = check_arg_count(args)?; this.read_scalar(overwrite)?.to_i32()?; let result = this.setenv(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "getcwd" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref buf, ref size] = check_arg_count(args)?; let result = this.getcwd(buf, size)?; this.write_scalar(result, dest)?; } "chdir" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref path] = check_arg_count(args)?; let result = this.chdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -59,18 +59,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "open" | "open64" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref path, ref flag, ref mode] = check_arg_count(args)?; let result = this.open(path, flag, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fcntl" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let result = this.fcntl(args)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "read" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref buf, ref count] = check_arg_count(args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.check_init()?; @@ -79,7 +79,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "write" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref buf, ref n] = check_arg_count(args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.check_init()?; @@ -90,62 +90,62 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "unlink" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref path] = check_arg_count(args)?; let result = this.unlink(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "symlink" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref target, ref linkpath] = check_arg_count(args)?; let result = this.symlink(target, linkpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rename" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref oldpath, ref newpath] = check_arg_count(args)?; let result = this.rename(oldpath, newpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mkdir" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref path, ref mode] = check_arg_count(args)?; let result = this.mkdir(path, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rmdir" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref path] = check_arg_count(args)?; let result = this.rmdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "closedir" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref dirp] = check_arg_count(args)?; let result = this.closedir(dirp)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lseek" | "lseek64" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref offset, ref whence] = check_arg_count(args)?; let result = this.lseek64(fd, offset, whence)?; // "lseek" is only used on macOS which is 64bit-only, so `i64` always works. this.write_scalar(Scalar::from_i64(result), dest)?; } "fsync" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref fd] = check_arg_count(args)?; let result = this.fsync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fdatasync" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref fd] = check_arg_count(args)?; let result = this.fdatasync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "readlink" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref pathname, ref buf, ref bufsize] = check_arg_count(args)?; let result = this.readlink(pathname, buf, bufsize)?; this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; @@ -153,7 +153,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Allocation "posix_memalign" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref ret, ref align, ref size] = check_arg_count(args)?; let ret = this.deref_operand(ret)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -184,7 +184,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamic symbol loading "dlsym" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref handle, ref symbol] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_usize(this)?; let symbol = this.read_scalar(symbol)?.check_init()?; @@ -199,7 +199,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "sysconf" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let name = this.read_scalar(name)?.to_i32()?; @@ -225,7 +225,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "pthread_key_create" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref key, ref dtor] = check_arg_count(args)?; let key_place = this.deref_operand(key)?; let dtor = this.read_scalar(dtor)?.check_init()?; @@ -254,7 +254,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_key_delete" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref key] = check_arg_count(args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; this.machine.tls.delete_tls_key(key)?; @@ -262,7 +262,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_getspecific" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref key] = check_arg_count(args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); @@ -270,7 +270,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref key, ref new_ptr] = check_arg_count(args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); @@ -283,132 +283,132 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Synchronization primitives "pthread_mutexattr_init" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref attr] = check_arg_count(args)?; let result = this.pthread_mutexattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_settype" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref attr, ref kind] = check_arg_count(args)?; let result = this.pthread_mutexattr_settype(attr, kind)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_destroy" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref attr] = check_arg_count(args)?; let result = this.pthread_mutexattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_init" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref mutex, ref attr] = check_arg_count(args)?; let result = this.pthread_mutex_init(mutex, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_lock" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_lock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_trylock" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_trylock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_unlock" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_unlock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_destroy" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_destroy(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_rdlock" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_rdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_tryrdlock" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_tryrdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_wrlock" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_wrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_trywrlock" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_trywrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_unlock" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_unlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_destroy" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_destroy(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_init" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref attr] = check_arg_count(args)?; let result = this.pthread_condattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_destroy" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref attr] = check_arg_count(args)?; let result = this.pthread_condattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_init" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref cond, ref attr] = check_arg_count(args)?; let result = this.pthread_cond_init(cond, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_signal" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref cond] = check_arg_count(args)?; let result = this.pthread_cond_signal(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_broadcast" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref cond] = check_arg_count(args)?; let result = this.pthread_cond_broadcast(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_wait" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref cond, ref mutex] = check_arg_count(args)?; let result = this.pthread_cond_wait(cond, mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_timedwait" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref cond, ref mutex, ref abstime] = check_arg_count(args)?; this.pthread_cond_timedwait(cond, mutex, abstime, dest)?; } "pthread_cond_destroy" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref cond] = check_arg_count(args)?; let result = this.pthread_cond_destroy(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -416,36 +416,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_create" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref thread, ref attr, ref start, ref arg] = check_arg_count(args)?; let result = this.pthread_create(thread, attr, start, arg)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_join" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref thread, ref retval] = check_arg_count(args)?; let result = this.pthread_join(thread, retval)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_detach" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref thread] = check_arg_count(args)?; let result = this.pthread_detach(thread)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_self" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.pthread_self(dest)?; } "sched_yield" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; let result = this.sched_yield()?; this.write_scalar(Scalar::from_i32(result), dest)?; } "nanosleep" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref req, ref rem] = check_arg_count(args)?; let result = this.nanosleep(req, rem)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -453,7 +453,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscellaneous "isatty" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref fd] = check_arg_count(args)?; this.read_scalar(fd)?.to_i32()?; // "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error" @@ -463,7 +463,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_atfork" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref prepare, ref parent, ref child] = check_arg_count(args)?; this.force_bits(this.read_scalar(prepare)?.check_init()?, this.memory.pointer_size())?; this.force_bits(this.read_scalar(parent)?.check_init()?, this.memory.pointer_size())?; @@ -476,7 +476,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These shims are enabled only when the caller is in the standard library. "pthread_attr_getguardsize" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref _attr, ref guard_size] = check_arg_count(args)?; let guard_size = this.deref_operand(guard_size)?; let guard_size_layout = this.libc_ty_layout("size_t")?; @@ -489,13 +489,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "pthread_attr_init" | "pthread_attr_destroy" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[_] = check_arg_count(args)?; this.write_null(dest)?; } | "pthread_attr_setstacksize" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[_, _] = check_arg_count(args)?; this.write_null(dest)?; } @@ -503,14 +503,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "signal" | "sigaltstack" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[_, _] = check_arg_count(args)?; this.write_null(dest)?; } | "sigaction" | "mprotect" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[_, _, _] = check_arg_count(args)?; this.write_null(dest)?; } diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 47ffad56d122..598d89fe1f34 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -1,7 +1,7 @@ use rustc_middle::mir; use rustc_target::spec::abi::Abi; -use crate::helpers::{check_abi, check_arg_count}; +use crate::helpers::check_arg_count; use crate::*; use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; @@ -24,7 +24,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // errno "__errno_location" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; @@ -34,32 +34,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These symbols have different names on Linux and macOS, which is the only reason they are not // in the `posix` module. "close" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref fd] = check_arg_count(args)?; let result = this.close(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir64_r" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref dirp, ref entry, ref result] = check_arg_count(args)?; let result = this.linux_readdir64_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate64" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref length] = check_arg_count(args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Linux-only "posix_fadvise" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref offset, ref len, ref advice] = check_arg_count(args)?; this.read_scalar(fd)?.to_i32()?; this.read_scalar(offset)?.to_machine_isize(this)?; @@ -69,7 +69,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "sync_file_range" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref offset, ref nbytes, ref flags] = check_arg_count(args)?; let result = this.sync_file_range(fd, offset, nbytes, flags)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -77,7 +77,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "clock_gettime" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; // This is a POSIX function but it has only been tested on linux. let &[ref clk_id, ref tp] = check_arg_count(args)?; let result = this.clock_gettime(clk_id, tp)?; @@ -86,7 +86,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_attr_getstack" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. let &[ref attr_place, ref addr_place, ref size_place] = check_arg_count(args)?; this.deref_operand(attr_place)?; @@ -108,19 +108,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "prctl" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref option, ref arg2, ref arg3, ref arg4, ref arg5] = check_arg_count(args)?; let result = this.prctl(option, arg2, arg3, arg4, arg5)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_setclock" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref attr, ref clock_id] = check_arg_count(args)?; let result = this.pthread_condattr_setclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_getclock" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref attr, ref clock_id] = check_arg_count(args)?; let result = this.pthread_condattr_getclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -128,7 +128,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamically invoked syscalls "syscall" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; // The syscall variadic function is legal to call with more arguments than needed, // extra arguments are simply ignored. However, all arguments need to be scalars; // other types might be treated differently by the calling convention. @@ -189,12 +189,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscelanneous "getrandom" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref ptr, ref len, ref flags] = check_arg_count(args)?; getrandom(this, ptr, len, flags, dest)?; } "sched_getaffinity" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref pid, ref cpusetsize, ref mask] = check_arg_count(args)?; this.read_scalar(pid)?.to_i32()?; this.read_scalar(cpusetsize)?.to_machine_usize(this)?; @@ -210,7 +210,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "pthread_getattr_np" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref _thread, ref _attr] = check_arg_count(args)?; this.write_null(dest)?; } diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index 15a073dd04ef..d54e1bfbe819 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -2,7 +2,7 @@ use rustc_middle::mir; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::{check_abi, check_arg_count}; +use helpers::check_arg_count; use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; use shims::posix::thread::EvalContextExt as _; @@ -22,7 +22,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // errno "__error" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; @@ -30,43 +30,43 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "close" | "close$NOCANCEL" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref result] = check_arg_count(args)?; let result = this.close(result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "stat" | "stat$INODE64" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref path, ref buf] = check_arg_count(args)?; let result = this.macos_stat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lstat" | "lstat$INODE64" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref path, ref buf] = check_arg_count(args)?; let result = this.macos_lstat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fstat" | "fstat$INODE64" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref buf] = check_arg_count(args)?; let result = this.macos_fstat(fd, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" | "opendir$INODE64" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir_r" | "readdir_r$INODE64" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref dirp, ref entry, ref result] = check_arg_count(args)?; let result = this.macos_readdir_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref length] = check_arg_count(args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -74,27 +74,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Environment related shims "_NSGetEnviron" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.write_scalar(this.machine.env_vars.environ.unwrap().ptr, dest)?; } // Time related shims "gettimeofday" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref tv, ref tz] = check_arg_count(args)?; let result = this.gettimeofday(tv, tz)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mach_absolute_time" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; let result = this.mach_absolute_time()?; this.write_scalar(Scalar::from_u64(result), dest)?; } "mach_timebase_info" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref info] = check_arg_count(args)?; let result = this.mach_timebase_info(info)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -102,19 +102,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Access to command-line arguments "_NSGetArgc" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?; } "_NSGetArgv" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; } // Thread-local storage "_tlv_atexit" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref dtor, ref data] = check_arg_count(args)?; let dtor = this.read_scalar(dtor)?.check_init()?; let dtor = this.memory.get_fn(dtor)?.as_instance()?; @@ -125,14 +125,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_get_stackaddr_np" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref thread] = check_arg_count(args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size()); this.write_scalar(stack_addr, dest)?; } "pthread_get_stacksize_np" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref thread] = check_arg_count(args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size()); @@ -141,7 +141,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_setname_np" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let name = this.read_scalar(name)?.check_init()?; this.pthread_setname_np(name)?; @@ -150,7 +150,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "mmap" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. let &[ref addr, _, _, _, _, _] = check_arg_count(args)?; let addr = this.read_scalar(addr)?.check_init()?; diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 18e2ed3db59b..325100bdb3a7 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -2,7 +2,6 @@ use rustc_middle::mir; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::check_abi; #[derive(Debug, Copy, Clone)] pub enum Dlsym {} @@ -31,7 +30,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (_dest, _ret) = ret.expect("we don't support any diverging dlsym"); assert!(this.tcx.sess.target.os == "windows"); - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; match dlsym {} } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 0f9e3899b85a..3c7451352dfd 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -5,7 +5,7 @@ use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::{check_abi, check_arg_count}; +use helpers::check_arg_count; use shims::foreign_items::EmulateByNameResult; use shims::windows::sync::EvalContextExt as _; @@ -29,37 +29,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Environment related shims "GetEnvironmentVariableW" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref name, ref buf, ref size] = check_arg_count(args)?; let result = this.GetEnvironmentVariableW(name, buf, size)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetEnvironmentVariableW" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref name, ref value] = check_arg_count(args)?; let result = this.SetEnvironmentVariableW(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetEnvironmentStringsW" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; let result = this.GetEnvironmentStringsW()?; this.write_scalar(result, dest)?; } "FreeEnvironmentStringsW" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref env_block] = check_arg_count(args)?; let result = this.FreeEnvironmentStringsW(env_block)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetCurrentDirectoryW" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref size, ref buf] = check_arg_count(args)?; let result = this.GetCurrentDirectoryW(size, buf)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetCurrentDirectoryW" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref path] = check_arg_count(args)?; let result = this.SetCurrentDirectoryW(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -67,7 +67,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "GetStdHandle" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref which] = check_arg_count(args)?; let which = this.read_scalar(which)?.to_i32()?; // We just make this the identity function, so we know later in `WriteFile` @@ -75,7 +75,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?; } "WriteFile" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref handle, ref buf, ref n, ref written_ptr, ref overlapped] = check_arg_count(args)?; this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore @@ -111,7 +111,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Allocation "HeapAlloc" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref handle, ref flags, ref size] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; let flags = this.read_scalar(flags)?.to_u32()?; @@ -121,7 +121,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } "HeapFree" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref handle, ref flags, ref ptr] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; @@ -130,7 +130,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(1), dest)?; } "HeapReAlloc" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref handle, ref flags, ref ptr, ref size] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; @@ -142,13 +142,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // errno "SetLastError" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref error] = check_arg_count(args)?; let error = this.read_scalar(error)?.check_init()?; this.set_last_error(error)?; } "GetLastError" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; let last_error = this.get_last_error()?; this.write_scalar(last_error, dest)?; @@ -156,7 +156,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "GetSystemInfo" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref system_info] = check_arg_count(args)?; let system_info = this.deref_operand(system_info)?; // Initialize with `0`. @@ -172,7 +172,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "TlsAlloc" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; // This just creates a key; Windows does not natively support TLS destructors. // Create key and return it. @@ -181,7 +181,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref key] = check_arg_count(args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); @@ -189,7 +189,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "TlsSetValue" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref key, ref new_ptr] = check_arg_count(args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); @@ -202,7 +202,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Access to command-line arguments "GetCommandLineW" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; this.write_scalar( this.machine.cmd_line.expect("machine must be initialized"), @@ -212,20 +212,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "GetSystemTimeAsFileTime" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref LPFILETIME] = check_arg_count(args)?; this.GetSystemTimeAsFileTime(LPFILETIME)?; } "QueryPerformanceCounter" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref lpPerformanceCount] = check_arg_count(args)?; let result = this.QueryPerformanceCounter(lpPerformanceCount)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "QueryPerformanceFrequency" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref lpFrequency] = check_arg_count(args)?; let result = this.QueryPerformanceFrequency(lpFrequency)?; @@ -234,33 +234,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Synchronization primitives "AcquireSRWLockExclusive" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; this.AcquireSRWLockExclusive(ptr)?; } "ReleaseSRWLockExclusive" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; this.ReleaseSRWLockExclusive(ptr)?; } "TryAcquireSRWLockExclusive" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; let ret = this.TryAcquireSRWLockExclusive(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; } "AcquireSRWLockShared" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; this.AcquireSRWLockShared(ptr)?; } "ReleaseSRWLockShared" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; this.ReleaseSRWLockShared(ptr)?; } "TryAcquireSRWLockShared" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; let ret = this.TryAcquireSRWLockShared(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; @@ -268,7 +268,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamic symbol loading "GetProcAddress" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref hModule, ref lpProcName] = check_arg_count(args)?; this.read_scalar(hModule)?.to_machine_isize(this)?; @@ -284,7 +284,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscellaneous "SystemFunction036" => { // This is really 'RtlGenRandom'. - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref ptr, ref len] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_u32()?; @@ -292,7 +292,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_bool(true), dest)?; } "BCryptGenRandom" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref algorithm, ref ptr, ref len, ref flags] = check_arg_count(args)?; let algorithm = this.read_scalar(algorithm)?; let ptr = this.read_scalar(ptr)?.check_init()?; @@ -313,7 +313,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; // STATUS_SUCCESS } "GetConsoleScreenBufferInfo" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; // `term` needs this, so we fake it. let &[ref console, ref buffer_info] = check_arg_count(args)?; this.read_scalar(console)?.to_machine_isize(this)?; @@ -323,7 +323,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "GetConsoleMode" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; // Windows "isatty" (in libtest) needs this, so we fake it. let &[ref console, ref mode] = check_arg_count(args)?; this.read_scalar(console)?.to_machine_isize(this)?; @@ -333,7 +333,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "SwitchToThread" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; // Note that once Miri supports concurrency, this will need to return a nonzero // value if this call does result in switching to another thread. @@ -342,7 +342,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Better error for attempts to create a thread "CreateThread" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; throw_unsup_format!("Miri does not support concurrency on Windows"); } @@ -351,7 +351,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "GetProcessHeap" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; // Just fake a HANDLE this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; @@ -359,7 +359,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _hConsoleOutput, ref _wAttribute] = check_arg_count(args)?; // Pretend these does not exist / nothing happened, by returning zero. @@ -368,7 +368,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "AddVectoredExceptionHandler" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _First, ref _Handler] = check_arg_count(args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. @@ -377,7 +377,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "SetThreadStackGuarantee" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[_StackSizeInBytes] = check_arg_count(args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. @@ -389,7 +389,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "DeleteCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _lpCriticalSection] = check_arg_count(args)?; assert_eq!( @@ -404,7 +404,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "TryEnterCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _lpCriticalSection] = check_arg_count(args)?; assert_eq!( From b054a19f9448c7a916b361b19d708c64df980edd Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 30 May 2021 20:49:44 +0800 Subject: [PATCH 2694/5092] We don't need to check `SymbolExportLevel` --- src/shims/foreign_items.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 70de55c5be75..27f4bafdb0cb 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -154,8 +154,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx |(num, &linkage)| (linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1)), )) { - // FIXME: Do we need to check `SymbolExportLevel` (the `_` below)? - for &(symbol, _) in tcx.exported_symbols(cnum) { + // We can ignore `_export_level` here: we are a Rust crate, and everything is exported + // from a Rust crate. + for &(symbol, _export_level) in tcx.exported_symbols(cnum) { if let ExportedSymbol::NonGeneric(def_id) = symbol { let attrs = tcx.codegen_fn_attrs(def_id); let symbol_name = if let Some(export_name) = attrs.export_name { From e026ad584d99c88af335edef96b93d1a0d7a071c Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 30 May 2021 21:01:40 +0800 Subject: [PATCH 2695/5092] Use `unwrap_or_else()` --- src/shims/foreign_items.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 27f4bafdb0cb..c838c136c3f4 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -213,11 +213,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); - let link_name_sym = match this.tcx.sess.first_attr_value_str_by_name(&attrs, sym::link_name) - { - Some(name) => name, - None => this.tcx.item_name(def_id), - }; + let link_name_sym = this + .tcx + .sess + .first_attr_value_str_by_name(&attrs, sym::link_name) + .unwrap_or_else(|| this.tcx.item_name(def_id)); let link_name = link_name_sym.as_str(); // Strip linker suffixes (seen on 32-bit macOS). let link_name = link_name.trim_end_matches("$UNIX2003"); From 45832d4031df76120bd8b7787c8c715a32b52653 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 30 May 2021 21:06:40 +0800 Subject: [PATCH 2696/5092] Remove duplicated "foreign function" --- tests/run-pass/function_calls/exported_symbol_good_unwind.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/function_calls/exported_symbol_good_unwind.rs b/tests/run-pass/function_calls/exported_symbol_good_unwind.rs index 73192707f1e4..3dd3b8f22de5 100644 --- a/tests/run-pass/function_calls/exported_symbol_good_unwind.rs +++ b/tests/run-pass/function_calls/exported_symbol_good_unwind.rs @@ -1,6 +1,6 @@ // Make sure the workaround for "crate ... required to be available in rlib format, but was not // found in this form" errors works without `-C prefer-dynamic` (`panic!` calls foreign function -// foreign function `__rust_start_panic`). +// `__rust_start_panic`). // no-prefer-dynamic #![feature(c_unwind, unboxed_closures, unwind_attributes)] From 160bc68cae213dc204037880c529125442557205 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Mon, 31 May 2021 07:59:51 +0800 Subject: [PATCH 2697/5092] Move the test to `src/main.rs` --- test-cargo-miri/src/lib.rs | 15 --------------- test-cargo-miri/src/main.rs | 16 ++++++++++++++++ test-cargo-miri/test.bin-target.stdout.ref | 5 +++-- test-cargo-miri/test.cross-target.stdout.ref | 6 +++--- test-cargo-miri/test.default.stdout.ref | 17 ++++++++--------- .../test.filter.cross-target.stdout.ref | 2 +- test-cargo-miri/test.filter.stdout.ref | 4 ++-- 7 files changed, 33 insertions(+), 32 deletions(-) diff --git a/test-cargo-miri/src/lib.rs b/test-cargo-miri/src/lib.rs index 6397d072e89e..6d9158c54ef4 100644 --- a/test-cargo-miri/src/lib.rs +++ b/test-cargo-miri/src/lib.rs @@ -1,21 +1,6 @@ -extern crate exported_symbol; - /// Doc-test test /// ```rust /// assert!(cargo_miri_test::make_true()); -/// // Repeat calls to make sure the `Instance` cache is not broken. -/// for _ in 0..3 { -/// extern "Rust" { -/// fn exported_symbol() -> i32; -/// fn make_true() -> bool; -/// } -/// assert_eq!(unsafe { exported_symbol() }, 123456); -/// assert!(unsafe { make_true() }); -/// } -/// ``` -/// ```compile_fail -/// // Make sure `exported_symbol_dep` is not a direct dependency for doctests. -/// use exported_symbol_dep; /// ``` /// ```rust,no_run /// assert!(!cargo_miri_test::make_true()); diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index 16b173b287ca..a5669ef3087c 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -57,4 +57,20 @@ mod test { assert_ne!(x as usize, y); assert_ne!(y as u128, z); } + + #[test] + fn exported_symbol() { + extern crate cargo_miri_test; + extern crate exported_symbol; + // Test calling exported symbols in (transitive) dependencies. + // Repeat calls to make sure the `Instance` cache is not broken. + for _ in 0..3 { + extern "Rust" { + fn exported_symbol() -> i32; + fn make_true() -> bool; + } + assert_eq!(unsafe { exported_symbol() }, 123456); + assert!(unsafe { make_true() }); + } + } } diff --git a/test-cargo-miri/test.bin-target.stdout.ref b/test-cargo-miri/test.bin-target.stdout.ref index 4caa30a7f0e5..62cfd1d37a17 100644 --- a/test-cargo-miri/test.bin-target.stdout.ref +++ b/test-cargo-miri/test.bin-target.stdout.ref @@ -1,6 +1,7 @@ -running 1 test +running 2 tests +test test::exported_symbol ... ok test test::rng ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/test.cross-target.stdout.ref b/test-cargo-miri/test.cross-target.stdout.ref index e36abd870663..aa4a5839b145 100644 --- a/test-cargo-miri/test.cross-target.stdout.ref +++ b/test-cargo-miri/test.cross-target.stdout.ref @@ -1,7 +1,7 @@ -running 1 test -. -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +running 2 tests +.. +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out imported main diff --git a/test-cargo-miri/test.default.stdout.ref b/test-cargo-miri/test.default.stdout.ref index e97119f217f7..6c7d284a84ac 100644 --- a/test-cargo-miri/test.default.stdout.ref +++ b/test-cargo-miri/test.default.stdout.ref @@ -1,7 +1,7 @@ -running 1 test -. -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +running 2 tests +.. +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out imported main @@ -10,11 +10,10 @@ running 7 tests test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out -running 4 tests -test src/lib.rs - make_true (line 16) ... ok -test src/lib.rs - make_true (line 20) ... ok -test src/lib.rs - make_true (line 23) ... ok -test src/lib.rs - make_true (line 4) ... ok +running 3 tests +test src/lib.rs - make_true (line 2) ... ok +test src/lib.rs - make_true (line 5) ... ok +test src/lib.rs - make_true (line 8) ... ok -test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/test-cargo-miri/test.filter.cross-target.stdout.ref b/test-cargo-miri/test.filter.cross-target.stdout.ref index fb722c5e7123..b38aac9aa868 100644 --- a/test-cargo-miri/test.filter.cross-target.stdout.ref +++ b/test-cargo-miri/test.filter.cross-target.stdout.ref @@ -1,7 +1,7 @@ running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out imported main diff --git a/test-cargo-miri/test.filter.stdout.ref b/test-cargo-miri/test.filter.stdout.ref index 61565a4c1e4a..6b26e17ff8bb 100644 --- a/test-cargo-miri/test.filter.stdout.ref +++ b/test-cargo-miri/test.filter.stdout.ref @@ -1,7 +1,7 @@ running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out imported main @@ -13,5 +13,5 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 4 filtered out; finished in $TIME +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 3 filtered out; finished in $TIME From a952787163af999bbbcb4ed6de53a52563c23c28 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Mon, 31 May 2021 11:05:04 +0800 Subject: [PATCH 2698/5092] Improve tests --- .../function_calls/check_callback_abi.rs | 2 ++ .../exported_symbol_abi_mismatch.rs | 27 ++++++++++------ .../exported_symbol_bad_unwind3.rs | 1 - .../function_calls/exported_symbol.rs | 31 ++++++++++++++++++- 4 files changed, 49 insertions(+), 12 deletions(-) diff --git a/tests/compile-fail/function_calls/check_callback_abi.rs b/tests/compile-fail/function_calls/check_callback_abi.rs index 69dfc0359831..e36bfe1c5783 100644 --- a/tests/compile-fail/function_calls/check_callback_abi.rs +++ b/tests/compile-fail/function_calls/check_callback_abi.rs @@ -6,6 +6,8 @@ extern "C" fn try_fn(_: *mut u8) { fn main() { unsafe { + // Make sure we check the ABI when Miri itself invokes a function + // as part of a shim implementation. std::intrinsics::r#try( //~ ERROR calling a function with ABI C using caller ABI Rust std::mem::transmute::(try_fn), std::ptr::null_mut(), diff --git a/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.rs b/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.rs index d62cb2e8b7ad..f92fae5d2935 100644 --- a/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.rs +++ b/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.rs @@ -1,22 +1,29 @@ -// revisions: no_cache cache +// revisions: no_cache cache fn_ptr #[no_mangle] fn foo() {} fn main() { + #[cfg(any(cache, fn_ptr))] + extern "Rust" { + fn foo(); + } + + #[cfg(fn_ptr)] + unsafe { std::mem::transmute::(foo)() } + //[fn_ptr]~^ ERROR calling a function with ABI Rust using caller ABI C + + // `Instance` caching should not suppress ABI check. #[cfg(cache)] + unsafe { foo() } + { - // `Instance` caching should not suppress ABI check. - extern "Rust" { + #[cfg_attr(any(cache, fn_ptr), allow(clashing_extern_declarations))] + extern "C" { fn foo(); } unsafe { foo() } + //[no_cache]~^ ERROR calling a function with ABI Rust using caller ABI C + //[cache]~^^ ERROR calling a function with ABI Rust using caller ABI C } - #[cfg_attr(cache, allow(clashing_extern_declarations))] - extern "C" { - fn foo(); - } - unsafe { foo() } - //[no_cache]~^ ERROR Undefined Behavior: calling a function with ABI Rust using caller ABI C - //[cache]~^^ ERROR Undefined Behavior: calling a function with ABI Rust using caller ABI C } diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind3.rs b/tests/compile-fail/function_calls/exported_symbol_bad_unwind3.rs index dfb378cef523..bbbe677d3651 100644 --- a/tests/compile-fail/function_calls/exported_symbol_bad_unwind3.rs +++ b/tests/compile-fail/function_calls/exported_symbol_bad_unwind3.rs @@ -1,5 +1,4 @@ #![feature(unwind_attributes)] -#![feature(c_unwind)] // make sure it doesn't insert abort-on-unwind for the `#[unwind(allowed)]` function #[unwind(allowed)] #[no_mangle] diff --git a/tests/run-pass/function_calls/exported_symbol.rs b/tests/run-pass/function_calls/exported_symbol.rs index 7f359e80219f..96bf8170c6eb 100644 --- a/tests/run-pass/function_calls/exported_symbol.rs +++ b/tests/run-pass/function_calls/exported_symbol.rs @@ -32,13 +32,42 @@ fn main() { extern "C" { fn foo() -> i32; } + assert_eq!(unsafe { foo() }, -1); - assert_eq!(unsafe { foo() }, -1); + extern "Rust" { fn bar() -> i32; fn baz() -> i32; } + assert_eq!(unsafe { bar() }, -2); assert_eq!(unsafe { baz() }, -3); + + #[allow(clashing_extern_declarations)] + { + extern "Rust" { + fn foo() -> i32; + } + + assert_eq!( + unsafe { + std::mem::transmute:: i32, unsafe extern "C" fn() -> i32>(foo)() + }, + -1 + ); + + extern "C" { + fn bar() -> i32; + fn baz() -> i32; + } + + unsafe { + let transmute = |f| { + std::mem::transmute:: i32, unsafe fn() -> i32>(f) + }; + assert_eq!(transmute(bar)(), -2); + assert_eq!(transmute(baz)(), -3); + } + } } } From 73700bc01c25c4bdf08a99803eee09ea4ca32fac Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 31 May 2021 10:50:25 -0500 Subject: [PATCH 2699/5092] Rustup for const_err changes --- rust-version | 2 +- src/diagnostics.rs | 6 ++++-- tests/compile-fail/erroneous_const.rs | 5 ++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index 7fc12e477e28..089b4f55511b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -ce0d64e03ef9875e0935bb60e989542b7ec29579 +d9feaaa548ce380159a1de68f4f6e605db9a9fc5 diff --git a/src/diagnostics.rs b/src/diagnostics.rs index ae50b5086022..456b6fb4d419 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -84,8 +84,10 @@ pub fn report_error<'tcx, 'mir>( "resource exhaustion", InvalidProgram(InvalidProgramInfo::ReferencedConstant) => "post-monomorphization error", - _ => - bug!("This error should be impossible in Miri: {}", e), + InvalidProgram(InvalidProgramInfo::AlreadyReported(_)) => + "error occurred", + kind => + bug!("This error should be impossible in Miri: {:?}", kind), }; #[rustfmt::skip] let helps = match e.kind() { diff --git a/tests/compile-fail/erroneous_const.rs b/tests/compile-fail/erroneous_const.rs index 49dcea62a243..f193dee94ebc 100644 --- a/tests/compile-fail/erroneous_const.rs +++ b/tests/compile-fail/erroneous_const.rs @@ -8,13 +8,12 @@ struct PrintName(T); impl PrintName { - const VOID: ! = panic!(); //~WARN any use of this value will cause an error - //~^ WARN this was previously accepted + const VOID: ! = panic!(); //~ERROR any use of this value will cause an error } fn no_codegen() { if false { - let _ = PrintName::::VOID; //~ERROR referenced constant has errors + let _ = PrintName::::VOID; //~ERROR error occurred: encountered constant } } fn main() { From b8aba11de3422b5b0ea7be727c2da2b856db3076 Mon Sep 17 00:00:00 2001 From: Pointerbender Date: Wed, 26 May 2021 21:30:43 +0200 Subject: [PATCH 2700/5092] regression tests for pointer invalidation in core library slice methods --- rust-version | 2 +- tests/run-pass/slices.rs | 54 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 089b4f55511b..7b2fc1f00d67 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d9feaaa548ce380159a1de68f4f6e605db9a9fc5 +d9feaaa548ce380159a1de68f4f6e605db9a9fc5 \ No newline at end of file diff --git a/tests/run-pass/slices.rs b/tests/run-pass/slices.rs index 41e7b2d36c7c..113f3faa9ad2 100644 --- a/tests/run-pass/slices.rs +++ b/tests/run-pass/slices.rs @@ -1,4 +1,6 @@ #![feature(new_uninit)] +#![feature(slice_as_chunks)] +#![feature(slice_partition_dedup)] use std::slice; @@ -186,8 +188,60 @@ fn uninit_slice() { assert_eq!(values.iter().map(|x| **x).collect::>(), vec![1, 2, 3]) } +/// Regression tests for slice methods in the Rust core library where raw pointers are obtained +/// from mutable references. +fn test_for_invalidated_pointers() { + let mut buffer = [0usize; 64]; + let len = buffer.len(); + + // These regression tests (indirectly) call every slice method which contains a `buffer.as_mut_ptr()`. + // `<[T]>::as_mut_ptr(&mut self)` takes a mutable reference (tagged Unique), which will invalidate all + // the other pointers that were previously derived from it according to the Stacked Borrows model. + // An example of where this could go wrong is a prior bug inside `<[T]>::copy_within`: + // + // unsafe { + // core::ptr::copy(self.as_ptr().add(src_start), self.as_mut_ptr().add(dest), count); + // } + // + // The arguments to `core::ptr::copy` are evaluated from left to right. `self.as_ptr()` creates + // an immutable reference (which is tagged as `SharedReadOnly` by Stacked Borrows) to the array + // and derives a valid `*const` pointer from it. When jumping to the next argument, + // `self.as_mut_ptr()` creates a mutable reference (tagged as `Unique`) to the array, which + // invalidates the existing `SharedReadOnly` reference and any pointers derived from it. + // The invalidated `*const` pointer (the first argument to `core::ptr::copy`) is then used + // after the fact when `core::ptr::copy` is called, which triggers undefined behavior. + + unsafe { assert_eq!(0, *buffer.as_mut_ptr_range().start ); } + // Check that the pointer range is in-bounds, while we're at it + let range = buffer.as_mut_ptr_range(); + unsafe { assert_eq!(*range.start, *range.end.sub(len)); } + + buffer.reverse(); + + // Calls `fn as_chunks_unchecked_mut` internally (requires unstable `#![feature(slice_as_chunks)]`): + assert_eq!(2, buffer.as_chunks_mut::<32>().0.len()); + + // Calls `fn split_at_mut_unchecked` internally: + let split_mut = buffer.split_at_mut(32); + assert_eq!(split_mut.0, split_mut.1); + + // Calls `fn partition_dedup_by` internally (requires unstable `#![feature(slice_partition_dedup)]`): + assert_eq!(1, buffer.partition_dedup().0.len()); + + buffer.rotate_left(8); + buffer.rotate_right(16); + + buffer.copy_from_slice(&[1usize; 64]); + buffer.swap_with_slice(&mut [2usize; 64]); + + assert_eq!(0, unsafe { buffer.align_to_mut::().1[1] }); + + buffer.copy_within(1.., 0); +} + fn main() { slice_of_zst(); test_iter_ref_consistency(); uninit_slice(); + test_for_invalidated_pointers(); } From c6dbe5cdcabaa3eb677519a7193b0d03254aa3b9 Mon Sep 17 00:00:00 2001 From: Pointerbender Date: Wed, 2 Jun 2021 15:31:50 +0200 Subject: [PATCH 2701/5092] use references so that potential aliasing bugs are triggered during regression test --- tests/run-pass/slices.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/slices.rs b/tests/run-pass/slices.rs index 113f3faa9ad2..83d9ff115188 100644 --- a/tests/run-pass/slices.rs +++ b/tests/run-pass/slices.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-track-raw-pointers #![feature(new_uninit)] #![feature(slice_as_chunks)] #![feature(slice_partition_dedup)] @@ -220,13 +221,23 @@ fn test_for_invalidated_pointers() { // Calls `fn as_chunks_unchecked_mut` internally (requires unstable `#![feature(slice_as_chunks)]`): assert_eq!(2, buffer.as_chunks_mut::<32>().0.len()); + for chunk in buffer.as_chunks_mut::<32>().0 { + for elem in chunk { + *elem += 1; + } + } // Calls `fn split_at_mut_unchecked` internally: let split_mut = buffer.split_at_mut(32); assert_eq!(split_mut.0, split_mut.1); // Calls `fn partition_dedup_by` internally (requires unstable `#![feature(slice_partition_dedup)]`): - assert_eq!(1, buffer.partition_dedup().0.len()); + let partition_dedup = buffer.partition_dedup(); + assert_eq!(1, partition_dedup.0.len()); + partition_dedup.0[0] += 1; + for elem in partition_dedup.1 { + *elem += 1; + } buffer.rotate_left(8); buffer.rotate_right(16); From e21dae71c8f331cc2c1cd29f90447508fb1caa2b Mon Sep 17 00:00:00 2001 From: Pointerbender Date: Wed, 2 Jun 2021 15:38:12 +0200 Subject: [PATCH 2702/5092] removed unintentional file change due to whitespace --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 7b2fc1f00d67..089b4f55511b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d9feaaa548ce380159a1de68f4f6e605db9a9fc5 \ No newline at end of file +d9feaaa548ce380159a1de68f4f6e605db9a9fc5 From 647ee17b405cc137572e56894a348d97717b3491 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Thu, 3 Jun 2021 10:22:31 +0800 Subject: [PATCH 2703/5092] `original_crate_name` -> `crate_name` --- rust-version | 2 +- src/helpers.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 089b4f55511b..bc007cfbe3e2 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d9feaaa548ce380159a1de68f4f6e605db9a9fc5 +da865095cf378fbfd07145c25fe5837ea091efeb diff --git a/src/helpers.rs b/src/helpers.rs index 45a5a8d4170b..29fde55d86dd 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -19,7 +19,7 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi /// Gets an instance for a path. fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option { - tcx.crates().iter().find(|&&krate| tcx.original_crate_name(krate).as_str() == path[0]).and_then( + 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.item_children(krate); From e4e6c25f678ac7aa70dcf61bb34beb59c95bb235 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Thu, 3 Jun 2021 13:39:33 +0800 Subject: [PATCH 2704/5092] Remove FIXME in `tests/compile-fail/panic/bad_unwind.rs` --- tests/compile-fail/panic/bad_unwind.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/compile-fail/panic/bad_unwind.rs b/tests/compile-fail/panic/bad_unwind.rs index cfb109cb8b56..fde2c19af07d 100644 --- a/tests/compile-fail/panic/bad_unwind.rs +++ b/tests/compile-fail/panic/bad_unwind.rs @@ -4,8 +4,6 @@ //! Unwinding when the caller ABI is "C" (without "-unwind") is UB. //! Currently we detect the ABI mismatch; we could probably allow such calls in principle one day //! but then we have to detect the unexpected unwinding. -//! FIXME: `-Zmiri-disable-abi-check` does not work for this test because function pointers are -//! always allowed to unwind. extern "C-unwind" fn unwind() { panic!(); From ba3b11fa42467d0e8871a34a4a46edf04753acd6 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Thu, 3 Jun 2021 14:16:58 +0800 Subject: [PATCH 2705/5092] Remove some tests --- .../panic/rustc_allocator_nounwind.rs | 10 ------- tests/run-pass/panic/good_unwind.rs | 27 ------------------- tests/run-pass/panic/good_unwind.stderr | 5 ---- 3 files changed, 42 deletions(-) delete mode 100644 tests/compile-fail/panic/rustc_allocator_nounwind.rs delete mode 100644 tests/run-pass/panic/good_unwind.rs delete mode 100644 tests/run-pass/panic/good_unwind.stderr diff --git a/tests/compile-fail/panic/rustc_allocator_nounwind.rs b/tests/compile-fail/panic/rustc_allocator_nounwind.rs deleted file mode 100644 index 7261b6658753..000000000000 --- a/tests/compile-fail/panic/rustc_allocator_nounwind.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![feature(rustc_attrs, c_unwind)] - -#[rustc_allocator_nounwind] -extern "C-unwind" fn nounwind() { - panic!(); -} - -fn main() { - nounwind(); //~ ERROR unwinding past a stack frame that does not allow unwinding -} diff --git a/tests/run-pass/panic/good_unwind.rs b/tests/run-pass/panic/good_unwind.rs deleted file mode 100644 index dbc1c1631f13..000000000000 --- a/tests/run-pass/panic/good_unwind.rs +++ /dev/null @@ -1,27 +0,0 @@ -#![feature(c_unwind, unboxed_closures, unwind_attributes)] - -use std::panic; - -extern "C-unwind" fn good_unwind_c() { - panic!(); -} - -#[unwind(allowed)] -extern "C" fn good_unwind_allowed() { - panic!(); -} - -fn good_unwind_rust() { - panic!(); -} - -extern "rust-call" fn good_unwind_rust_call(_: ()) { - panic!(); -} - -fn main() { - panic::catch_unwind(|| good_unwind_c()).unwrap_err(); - panic::catch_unwind(|| good_unwind_allowed()).unwrap_err(); - panic::catch_unwind(|| good_unwind_rust()).unwrap_err(); - good_unwind_rust_call(()); -} diff --git a/tests/run-pass/panic/good_unwind.stderr b/tests/run-pass/panic/good_unwind.stderr deleted file mode 100644 index 1cd361790b66..000000000000 --- a/tests/run-pass/panic/good_unwind.stderr +++ /dev/null @@ -1,5 +0,0 @@ -thread 'main' panicked at 'explicit panic', $DIR/good_unwind.rs:6:5 -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -thread 'main' panicked at 'explicit panic', $DIR/good_unwind.rs:11:5 -thread 'main' panicked at 'explicit panic', $DIR/good_unwind.rs:15:5 -thread 'main' panicked at 'explicit panic', $DIR/good_unwind.rs:19:5 From 386863ac537d8f0cab87eff21ac7056c8935263e Mon Sep 17 00:00:00 2001 From: Pointerbender Date: Thu, 3 Jun 2021 17:24:10 +0200 Subject: [PATCH 2706/5092] added a strings.rs regression test case for potential future UB --- tests/run-pass/strings.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/run-pass/strings.rs b/tests/run-pass/strings.rs index fa692ba3de1b..b009e8bc6c4a 100644 --- a/tests/run-pass/strings.rs +++ b/tests/run-pass/strings.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-track-raw-pointers + fn empty() -> &'static str { "" } @@ -23,6 +25,32 @@ fn str_indexing() { let _v = &mut x[..3]; // Test IndexMut on String. } +fn unique_aliasing() { + // This is a regression test for the aliasing rules of a `Unique` pointer. + // At the time of writing this test case, Miri does not treat `Unique` + // pointers as a special case, these are treated like any other raw pointer. + // However, there are existing Github issues which may lead to `Unique` + // becoming a special case through asserting unique ownership over the pointee: + // - https://github.com/rust-lang/unsafe-code-guidelines/issues/258 + // - https://github.com/rust-lang/unsafe-code-guidelines/issues/262 + // Below, the calls to `String::remove` and `String::insert[_str]` follow + // code paths that would trigger undefined behavior in case `Unique` + // would ever assert semantic ownership over the pointee. Internally, + // these methods call `self.vec.as_ptr()` and `self.vec.as_mut_ptr()` on + // the vector of bytes that are backing the `String`. That `Vec` holds a + // `Unique` internally. The second call to `Vec::as_mut_ptr(&mut self)` + // would then invalidate the pointers derived from `Vec::as_ptr(&self)`. + // Note that as long as `Unique` is treated like any other raw pointer, + // this test case should pass. It is merely here as a canary test for + // potential future undefined behavior. + let mut x = String::from("Hello"); + assert_eq!(x.remove(0), 'H'); + x.insert(0, 'H'); + assert_eq!(x, "Hello"); + x.insert_str(x.len(), ", world!"); + assert_eq!(x, "Hello, world!"); +} + fn main() { assert_eq!(empty(), ""); assert_eq!(hello(), "Hello, world!"); @@ -31,4 +59,5 @@ fn main() { fat_pointer_on_32_bit(); // Should run without crashing. str_indexing(); + unique_aliasing(); } From 57e4f1d285c53d8826a6911c84230a46720c7498 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 3 Jun 2021 17:47:34 +0200 Subject: [PATCH 2707/5092] fix typo --- src/bin/miri.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 7368d4b253ba..514e5b0aebe9 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -97,7 +97,7 @@ struct MiriBeRustCompilerCalls { impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { fn config(&mut self, config: &mut Config) { if config.opts.prints.is_empty() && self.target_crate { - // Queries overriden here affects the data stored in `rmeta` files of dependencies, + // Queries overriden here affect the data stored in `rmeta` files of dependencies, // which will be used later in non-`MIRI_BE_RUSTC` mode. config.override_queries = Some(|_, local_providers, _| { // `exported_symbols()` provided by rustc always returns empty result if From 879000b133aed8cc1893c84eb5319b491a4756d9 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Thu, 3 Jun 2021 17:58:24 +0800 Subject: [PATCH 2708/5092] Detect `std` by checking if the crate defines `#[lang = "start"]` rather than string comparison --- src/helpers.rs | 6 +++ src/shims/posix/foreign_items.rs | 10 ++--- src/shims/posix/linux/foreign_items.rs | 4 +- src/shims/posix/macos/foreign_items.rs | 2 +- src/shims/windows/foreign_items.rs | 22 +++-------- .../unsupported_get_process_heap.rs | 12 ++++++ tests/compile-fail/unsupported_signal.rs | 12 ++++++ tests/run-pass/extern_crate_std_in_main.rs | 5 +++ tests/run-pass/rename_std.rs | 5 +++ tests/run-pass/std_only_foreign_function.rs | 39 +++++++++++++++++++ 10 files changed, 92 insertions(+), 25 deletions(-) create mode 100644 tests/compile-fail/unsupported_get_process_heap.rs create mode 100644 tests/compile-fail/unsupported_signal.rs create mode 100644 tests/run-pass/extern_crate_std_in_main.rs create mode 100644 tests/run-pass/rename_std.rs create mode 100644 tests/run-pass/std_only_foreign_function.rs diff --git a/src/helpers.rs b/src/helpers.rs index b71f830b2b10..7f99aa199706 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -628,6 +628,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(()) } + + fn in_std(&self) -> bool { + let this = self.eval_context_ref(); + this.tcx.def_path(this.frame().instance.def_id()).krate + == this.tcx.def_path(this.tcx.lang_items().start_fn().unwrap()).krate + } } /// Check that the number of args is what we expect. diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index a756256aab41..bbd46af52a9b 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -475,7 +475,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "pthread_attr_getguardsize" - if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + if this.in_std() => { this.check_abi(abi, Abi::C { unwind: false })?; let &[ref _attr, ref guard_size] = check_arg_count(args)?; let guard_size = this.deref_operand(guard_size)?; @@ -488,13 +488,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "pthread_attr_init" | "pthread_attr_destroy" - if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + if this.in_std() => { this.check_abi(abi, Abi::C { unwind: false })?; let &[_] = check_arg_count(args)?; this.write_null(dest)?; } | "pthread_attr_setstacksize" - if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + if this.in_std() => { this.check_abi(abi, Abi::C { unwind: false })?; let &[_, _] = check_arg_count(args)?; this.write_null(dest)?; @@ -502,14 +502,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "signal" | "sigaltstack" - if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + if this.in_std() => { this.check_abi(abi, Abi::C { unwind: false })?; let &[_, _] = check_arg_count(args)?; this.write_null(dest)?; } | "sigaction" | "mprotect" - if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + if this.in_std() => { this.check_abi(abi, Abi::C { unwind: false })?; let &[_, _, _] = check_arg_count(args)?; this.write_null(dest)?; diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 598d89fe1f34..9b0576662f47 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -207,9 +207,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. - "pthread_getattr_np" - if this.frame().instance.to_string().starts_with("std::sys::unix::") => - { + "pthread_getattr_np" if this.in_std() => { this.check_abi(abi, Abi::C { unwind: false })?; let &[ref _thread, ref _attr] = check_arg_count(args)?; this.write_null(dest)?; diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index d54e1bfbe819..1467a95a0d3e 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -149,7 +149,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. - "mmap" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + "mmap" if this.in_std() => { this.check_abi(abi, Abi::C { unwind: false })?; // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. let &[ref addr, _, _, _, _, _] = check_arg_count(args)?; diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 3c7451352dfd..fd845cde3112 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -348,35 +348,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. - "GetProcessHeap" - if this.frame().instance.to_string().starts_with("std::sys::windows::") => - { + "GetProcessHeap" if this.in_std() => { this.check_abi(abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; // Just fake a HANDLE this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } - "SetConsoleTextAttribute" - if this.frame().instance.to_string().starts_with("std::sys::windows::") => - { + "SetConsoleTextAttribute" if this.in_std() => { this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _hConsoleOutput, ref _wAttribute] = check_arg_count(args)?; // Pretend these does not exist / nothing happened, by returning zero. this.write_null(dest)?; } - "AddVectoredExceptionHandler" - if this.frame().instance.to_string().starts_with("std::sys::windows::") => - { + "AddVectoredExceptionHandler" if this.in_std() => { this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _First, ref _Handler] = check_arg_count(args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_machine_usize(1, this), dest)?; } - "SetThreadStackGuarantee" - if this.frame().instance.to_string().starts_with("std::sys::windows::") => - { + "SetThreadStackGuarantee" if this.in_std() => { this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[_StackSizeInBytes] = check_arg_count(args)?; @@ -387,7 +379,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "EnterCriticalSection" | "LeaveCriticalSection" | "DeleteCriticalSection" - if this.frame().instance.to_string().starts_with("std::sys::windows::") => + if this.in_std() => { this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] @@ -401,9 +393,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // (Windows locks are reentrant, and we have only 1 thread, // so not doing any futher checks here is at least not incorrect.) } - "TryEnterCriticalSection" - if this.frame().instance.to_string().starts_with("std::sys::windows::") => - { + "TryEnterCriticalSection" if this.in_std() => { this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _lpCriticalSection] = check_arg_count(args)?; diff --git a/tests/compile-fail/unsupported_get_process_heap.rs b/tests/compile-fail/unsupported_get_process_heap.rs new file mode 100644 index 000000000000..4fd5f4b7d885 --- /dev/null +++ b/tests/compile-fail/unsupported_get_process_heap.rs @@ -0,0 +1,12 @@ +//! `GetProcessHeap()` is special on Windows that it's only supported within libstd. +//! (On Linux and macOS, it's just always unsupported.) + +fn main() { + extern "system" { + fn GetProcessHeap() -> *mut std::ffi::c_void; + } + unsafe { + GetProcessHeap(); + //~^ ERROR unsupported operation: can't call foreign function: GetProcessHeap + } +} diff --git a/tests/compile-fail/unsupported_signal.rs b/tests/compile-fail/unsupported_signal.rs new file mode 100644 index 000000000000..7931747e0aa8 --- /dev/null +++ b/tests/compile-fail/unsupported_signal.rs @@ -0,0 +1,12 @@ +//! `signal()` is special on Linux and macOS that it's only supported within libstd. +// ignore-windows: No libc on Windows +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + unsafe { + libc::signal(libc::SIGPIPE, libc::SIG_IGN); + //~^ ERROR unsupported operation: can't call foreign function: signal + } +} diff --git a/tests/run-pass/extern_crate_std_in_main.rs b/tests/run-pass/extern_crate_std_in_main.rs new file mode 100644 index 000000000000..8f71e613375e --- /dev/null +++ b/tests/run-pass/extern_crate_std_in_main.rs @@ -0,0 +1,5 @@ +#![no_std] + +fn main() { + extern crate std; +} diff --git a/tests/run-pass/rename_std.rs b/tests/run-pass/rename_std.rs new file mode 100644 index 000000000000..7e82e53e6be8 --- /dev/null +++ b/tests/run-pass/rename_std.rs @@ -0,0 +1,5 @@ +#![no_std] + +extern crate std as foo; + +fn main() {} diff --git a/tests/run-pass/std_only_foreign_function.rs b/tests/run-pass/std_only_foreign_function.rs new file mode 100644 index 000000000000..959103ee5c8e --- /dev/null +++ b/tests/run-pass/std_only_foreign_function.rs @@ -0,0 +1,39 @@ +//! Make sure we can call foreign functions that are only allowed within libstd if we are "libstd" +//! (defining the `start` lang item). +#![feature(lang_items, rustc_private, core_intrinsics)] +#![no_std] + +use core::{intrinsics, panic::PanicInfo}; + +#[lang = "eh_personality"] +fn rust_eh_personality() {} + +#[panic_handler] +fn panic_handler(_: &PanicInfo<'_>) -> ! { + intrinsics::abort() +} + +#[lang = "start"] +fn start(main: fn(), _argc: isize, _argv: *const *const u8) -> isize { + main(); + 0 +} + +fn main() { + #[cfg(unix)] + unsafe { + extern crate libc; + assert_eq!(libc::signal(libc::SIGPIPE, libc::SIG_IGN), 0); + } + #[cfg(windows)] + unsafe { + extern "system" { + fn GetProcessHeap() -> *mut core::ffi::c_void; + fn ExitProcess(code: u32) -> !; + } + assert_eq!(GetProcessHeap() as usize, 1); + // Early exit to avoid the requirement of + // `std::sys::windows::thread_local_key::p_thread_callback`. + ExitProcess(0); + } +} From 545101040df050dcc412d714640c95f417194600 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Thu, 3 Jun 2021 21:26:11 +0800 Subject: [PATCH 2709/5092] Don't `unwrap()` in `in_std()` --- src/helpers.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 7f99aa199706..a9cafd2a9e39 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -631,8 +631,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn in_std(&self) -> bool { let this = self.eval_context_ref(); - this.tcx.def_path(this.frame().instance.def_id()).krate - == this.tcx.def_path(this.tcx.lang_items().start_fn().unwrap()).krate + this.tcx.lang_items().start_fn().map_or(false, |start_fn| { + this.tcx.def_path(this.frame().instance.def_id()).krate + == this.tcx.def_path(start_fn).krate + }) } } From 3871c493b24b00c2b3d11af5aef8bb0045dd7469 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 6 Jun 2021 11:21:20 +0800 Subject: [PATCH 2710/5092] `in_std` -> `frame_in_std` --- src/helpers.rs | 2 +- src/shims/posix/foreign_items.rs | 10 +++++----- src/shims/posix/linux/foreign_items.rs | 2 +- src/shims/posix/macos/foreign_items.rs | 2 +- src/shims/windows/foreign_items.rs | 12 ++++++------ 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index a9cafd2a9e39..52176342057e 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -629,7 +629,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - fn in_std(&self) -> bool { + fn frame_in_std(&self) -> bool { let this = self.eval_context_ref(); this.tcx.lang_items().start_fn().map_or(false, |start_fn| { this.tcx.def_path(this.frame().instance.def_id()).krate diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index bbd46af52a9b..2ecea4d9f41e 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -475,7 +475,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "pthread_attr_getguardsize" - if this.in_std() => { + if this.frame_in_std() => { this.check_abi(abi, Abi::C { unwind: false })?; let &[ref _attr, ref guard_size] = check_arg_count(args)?; let guard_size = this.deref_operand(guard_size)?; @@ -488,13 +488,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "pthread_attr_init" | "pthread_attr_destroy" - if this.in_std() => { + if this.frame_in_std() => { this.check_abi(abi, Abi::C { unwind: false })?; let &[_] = check_arg_count(args)?; this.write_null(dest)?; } | "pthread_attr_setstacksize" - if this.in_std() => { + if this.frame_in_std() => { this.check_abi(abi, Abi::C { unwind: false })?; let &[_, _] = check_arg_count(args)?; this.write_null(dest)?; @@ -502,14 +502,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "signal" | "sigaltstack" - if this.in_std() => { + if this.frame_in_std() => { this.check_abi(abi, Abi::C { unwind: false })?; let &[_, _] = check_arg_count(args)?; this.write_null(dest)?; } | "sigaction" | "mprotect" - if this.in_std() => { + if this.frame_in_std() => { this.check_abi(abi, Abi::C { unwind: false })?; let &[_, _, _] = check_arg_count(args)?; this.write_null(dest)?; diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 9b0576662f47..9017dc368b69 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -207,7 +207,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. - "pthread_getattr_np" if this.in_std() => { + "pthread_getattr_np" if this.frame_in_std() => { this.check_abi(abi, Abi::C { unwind: false })?; let &[ref _thread, ref _attr] = check_arg_count(args)?; this.write_null(dest)?; diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index 1467a95a0d3e..313d38c80b6f 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -149,7 +149,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. - "mmap" if this.in_std() => { + "mmap" if this.frame_in_std() => { this.check_abi(abi, Abi::C { unwind: false })?; // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. let &[ref addr, _, _, _, _, _] = check_arg_count(args)?; diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index fd845cde3112..76657a535541 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -348,27 +348,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. - "GetProcessHeap" if this.in_std() => { + "GetProcessHeap" if this.frame_in_std() => { this.check_abi(abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; // Just fake a HANDLE this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } - "SetConsoleTextAttribute" if this.in_std() => { + "SetConsoleTextAttribute" if this.frame_in_std() => { this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _hConsoleOutput, ref _wAttribute] = check_arg_count(args)?; // Pretend these does not exist / nothing happened, by returning zero. this.write_null(dest)?; } - "AddVectoredExceptionHandler" if this.in_std() => { + "AddVectoredExceptionHandler" if this.frame_in_std() => { this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _First, ref _Handler] = check_arg_count(args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_machine_usize(1, this), dest)?; } - "SetThreadStackGuarantee" if this.in_std() => { + "SetThreadStackGuarantee" if this.frame_in_std() => { this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[_StackSizeInBytes] = check_arg_count(args)?; @@ -379,7 +379,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "EnterCriticalSection" | "LeaveCriticalSection" | "DeleteCriticalSection" - if this.in_std() => + if this.frame_in_std() => { this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] @@ -393,7 +393,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // (Windows locks are reentrant, and we have only 1 thread, // so not doing any futher checks here is at least not incorrect.) } - "TryEnterCriticalSection" if this.in_std() => { + "TryEnterCriticalSection" if this.frame_in_std() => { this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _lpCriticalSection] = check_arg_count(args)?; From d7aff960538bf3cadd66556ecedc87fa685492d5 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 6 Jun 2021 11:22:25 +0800 Subject: [PATCH 2711/5092] Remove 2 tests --- .../unsupported_get_process_heap.rs | 12 ------ tests/run-pass/std_only_foreign_function.rs | 39 ------------------- 2 files changed, 51 deletions(-) delete mode 100644 tests/compile-fail/unsupported_get_process_heap.rs delete mode 100644 tests/run-pass/std_only_foreign_function.rs diff --git a/tests/compile-fail/unsupported_get_process_heap.rs b/tests/compile-fail/unsupported_get_process_heap.rs deleted file mode 100644 index 4fd5f4b7d885..000000000000 --- a/tests/compile-fail/unsupported_get_process_heap.rs +++ /dev/null @@ -1,12 +0,0 @@ -//! `GetProcessHeap()` is special on Windows that it's only supported within libstd. -//! (On Linux and macOS, it's just always unsupported.) - -fn main() { - extern "system" { - fn GetProcessHeap() -> *mut std::ffi::c_void; - } - unsafe { - GetProcessHeap(); - //~^ ERROR unsupported operation: can't call foreign function: GetProcessHeap - } -} diff --git a/tests/run-pass/std_only_foreign_function.rs b/tests/run-pass/std_only_foreign_function.rs deleted file mode 100644 index 959103ee5c8e..000000000000 --- a/tests/run-pass/std_only_foreign_function.rs +++ /dev/null @@ -1,39 +0,0 @@ -//! Make sure we can call foreign functions that are only allowed within libstd if we are "libstd" -//! (defining the `start` lang item). -#![feature(lang_items, rustc_private, core_intrinsics)] -#![no_std] - -use core::{intrinsics, panic::PanicInfo}; - -#[lang = "eh_personality"] -fn rust_eh_personality() {} - -#[panic_handler] -fn panic_handler(_: &PanicInfo<'_>) -> ! { - intrinsics::abort() -} - -#[lang = "start"] -fn start(main: fn(), _argc: isize, _argv: *const *const u8) -> isize { - main(); - 0 -} - -fn main() { - #[cfg(unix)] - unsafe { - extern crate libc; - assert_eq!(libc::signal(libc::SIGPIPE, libc::SIG_IGN), 0); - } - #[cfg(windows)] - unsafe { - extern "system" { - fn GetProcessHeap() -> *mut core::ffi::c_void; - fn ExitProcess(code: u32) -> !; - } - assert_eq!(GetProcessHeap() as usize, 1); - // Early exit to avoid the requirement of - // `std::sys::windows::thread_local_key::p_thread_callback`. - ExitProcess(0); - } -} From 0ece55d748a04aba9c4950937de226c259630719 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 6 Jun 2021 10:33:46 +0200 Subject: [PATCH 2712/5092] expand comment --- tests/compile-fail/unsupported_signal.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/compile-fail/unsupported_signal.rs b/tests/compile-fail/unsupported_signal.rs index 7931747e0aa8..3e76d1c3f384 100644 --- a/tests/compile-fail/unsupported_signal.rs +++ b/tests/compile-fail/unsupported_signal.rs @@ -1,4 +1,5 @@ //! `signal()` is special on Linux and macOS that it's only supported within libstd. +//! The implementation is not complete enough to permit user code to call it. // ignore-windows: No libc on Windows #![feature(rustc_private)] From 9549faa81cc389ef2f05ea8bff5246388314f277 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Mon, 7 Jun 2021 16:49:00 +0800 Subject: [PATCH 2713/5092] Update `cargo-miri` tests --- rust-version | 2 +- test-cargo-miri/test.default.stdout.ref | 4 ++-- test-cargo-miri/test.test-target.stdout.ref | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index bc007cfbe3e2..81334a8d5a08 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -da865095cf378fbfd07145c25fe5837ea091efeb +cc9610bf5af1d5c54968db0dd899595ca12307a0 diff --git a/test-cargo-miri/test.default.stdout.ref b/test-cargo-miri/test.default.stdout.ref index 6c7d284a84ac..4edcb7ba7d91 100644 --- a/test-cargo-miri/test.default.stdout.ref +++ b/test-cargo-miri/test.default.stdout.ref @@ -12,8 +12,8 @@ test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out running 3 tests test src/lib.rs - make_true (line 2) ... ok -test src/lib.rs - make_true (line 5) ... ok -test src/lib.rs - make_true (line 8) ... ok +test src/lib.rs - make_true (line 5) - compile ... ok +test src/lib.rs - make_true (line 8) - compile fail ... ok test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/test-cargo-miri/test.test-target.stdout.ref b/test-cargo-miri/test.test-target.stdout.ref index 893e52e87774..6655eb840929 100644 --- a/test-cargo-miri/test.test-target.stdout.ref +++ b/test-cargo-miri/test.test-target.stdout.ref @@ -1,10 +1,10 @@ running 7 tests test cargo_env ... ok -test do_panic ... ok +test do_panic - should panic ... ok test does_not_work_on_miri ... ignored test entropy_rng ... ok -test fail_index_check ... ok +test fail_index_check - should panic ... ok test simple1 ... ok test simple2 ... ok From ae237098f8af22bd44ee3808cce97f1782eb4e18 Mon Sep 17 00:00:00 2001 From: Lander Brandt Date: Wed, 26 May 2021 16:29:01 -0700 Subject: [PATCH 2714/5092] Add support for panicking in the emulated application when unsupported syscalls are encountered --- README.md | 5 +++++ src/bin/miri.rs | 3 +++ src/eval.rs | 3 +++ src/helpers.rs | 17 +++++++++++++++++ src/machine.rs | 6 ++++++ src/shims/foreign_items.rs | 10 ++++++++-- src/shims/panic.rs | 2 +- src/shims/posix/linux/foreign_items.rs | 5 ++++- src/shims/windows/foreign_items.rs | 4 +++- tests/compile-fail/concurrency/thread-spawn.rs | 2 +- .../panic/unsupported_foreign_function.rs | 11 +++++++++++ .../panic/unsupported_foreign_function.stderr | 2 ++ 12 files changed, 64 insertions(+), 6 deletions(-) create mode 100644 tests/run-pass/panic/unsupported_foreign_function.rs create mode 100644 tests/run-pass/panic/unsupported_foreign_function.stderr diff --git a/README.md b/README.md index f0e14a9125c6..2e24402450fd 100644 --- a/README.md +++ b/README.md @@ -228,6 +228,11 @@ environment variable: This can be used to find which parts of your program are executing slowly under Miri. The profile is written out to a file with the prefix ``, and can be processed using the tools in the repository https://github.com/rust-lang/measureme. +* `-Zmiri-panic-on-unsupported` will makes some forms of unsupported functionality, + such as FFI and unsupported syscalls, panic within the context of the emulated + application instead of raising an error within the context of Miri (and halting + execution). Note that code might not expect these operations to ever panic, so + this flag can lead to strange (mis)behavior. * `-Zmiri-seed=` configures the seed of the RNG that Miri uses to resolve non-determinism. This RNG is used to pick base addresses for allocations. When isolation is enabled (the default), this is also used to emulate system diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 514e5b0aebe9..7fd6d85cffde 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -296,6 +296,9 @@ fn main() { "-Zmiri-ignore-leaks" => { miri_config.ignore_leaks = true; } + "-Zmiri-panic-on-unsupported" => { + miri_config.panic_on_unsupported = true; + } "-Zmiri-track-raw-pointers" => { miri_config.track_raw = true; } diff --git a/src/eval.rs b/src/eval.rs index 6646783d349c..8d5876d77718 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -59,6 +59,8 @@ pub struct MiriConfig { /// If `Some`, enable the `measureme` profiler, writing results to a file /// with the specified prefix. pub measureme_out: Option, + /// Panic when unsupported functionality is encountered + pub panic_on_unsupported: bool, } impl Default for MiriConfig { @@ -80,6 +82,7 @@ impl Default for MiriConfig { data_race_detector: true, cmpxchg_weak_failure_rate: 0.8, measureme_out: None, + panic_on_unsupported: false, } } } diff --git a/src/helpers.rs b/src/helpers.rs index 52176342057e..c8e1d6c88022 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -636,6 +636,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx == this.tcx.def_path(start_fn).krate }) } + + /// Handler that should be called when unsupported functionality is encountered. + /// This function will either panic within the context of the emulated application + /// or return an error in the Miri process context + /// + /// Return value of `Ok(bool)` indicates whether execution should continue. + fn handle_unsupported>(&mut self, error_msg: S) -> InterpResult<'tcx, ()> { + let this = self.eval_context_mut(); + if this.machine.panic_on_unsupported { + // message is slightly different here to make automated analysis easier + let error_msg = format!("unsupported Miri functionality: {}", error_msg.as_ref()); + this.start_panic(error_msg.as_ref(), StackPopUnwind::Skip)?; + return Ok(()); + } else { + throw_unsup_format!("{}", error_msg.as_ref()); + } + } } /// Check that the number of args is what we expect. diff --git a/src/machine.rs b/src/machine.rs index 9c49575ded32..f25c1b9720dc 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -297,6 +297,11 @@ pub struct Evaluator<'mir, 'tcx> { /// Cache of `Instance` exported under the given `Symbol` name. pub(crate) exported_symbols_cache: FxHashMap>, + + /// Whether to raise a panic in the context of the evaluated process when unsupported + /// functionality is encountered. If `false`, an error is propagated in the Miri application context + /// instead (default behavior) + pub(crate) panic_on_unsupported: bool, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { @@ -326,6 +331,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { profiler, string_cache: Default::default(), exported_symbols_cache: FxHashMap::default(), + panic_on_unsupported: config.panic_on_unsupported, } } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index c838c136c3f4..8f3dfdc4f81f 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -259,7 +259,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(body) = this.lookup_exported_symbol(link_name_sym)? { return Ok(Some(body)); } - throw_unsup_format!("can't call (diverging) foreign function: {}", link_name); + this.handle_unsupported(format!( + "can't call (diverging) foreign function: {}", + link_name + ))?; + return Ok(None); } }, Some(p) => p, @@ -276,7 +280,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(body) = this.lookup_exported_symbol(link_name_sym)? { return Ok(Some(body)); } - throw_unsup_format!("can't call foreign function: {}", link_name); + + this.handle_unsupported(format!("can't call foreign function: {}", link_name))?; + return Ok(None); } } diff --git a/src/shims/panic.rs b/src/shims/panic.rs index b1da7f340fce..15620c73f0da 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -161,7 +161,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - /// Starta a panic in the interpreter with the given message as payload. + /// Start a panic in the interpreter with the given message as payload. fn start_panic(&mut self, msg: &str, unwind: StackPopUnwind) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 9017dc368b69..68ae704fb04f 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -183,7 +183,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx id if id == sys_futex => { futex(this, args, dest)?; } - id => throw_unsup_format!("Miri does not support syscall ID {}", id), + id => { + this.handle_unsupported(format!("can't execute syscall with ID {}", id))?; + return Ok(EmulateByNameResult::NotSupported); + } } } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 76657a535541..02f9bb8fff20 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -343,7 +343,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Better error for attempts to create a thread "CreateThread" => { this.check_abi(abi, Abi::System { unwind: false })?; - throw_unsup_format!("Miri does not support concurrency on Windows"); + + this.handle_unsupported("can't create threads on Windows")?; + return Ok(EmulateByNameResult::AlreadyJumped); } // Incomplete shims that we "stub out" just to get pre-main initialization code to work. diff --git a/tests/compile-fail/concurrency/thread-spawn.rs b/tests/compile-fail/concurrency/thread-spawn.rs index 27760eed8dba..6f07d083a0e5 100644 --- a/tests/compile-fail/concurrency/thread-spawn.rs +++ b/tests/compile-fail/concurrency/thread-spawn.rs @@ -3,7 +3,7 @@ use std::thread; -// error-pattern: Miri does not support concurrency on Windows +// error-pattern: can't create threads on Windows fn main() { thread::spawn(|| {}); diff --git a/tests/run-pass/panic/unsupported_foreign_function.rs b/tests/run-pass/panic/unsupported_foreign_function.rs new file mode 100644 index 000000000000..bc3d02c5f279 --- /dev/null +++ b/tests/run-pass/panic/unsupported_foreign_function.rs @@ -0,0 +1,11 @@ +// compile-flags: -Zmiri-panic-on-unsupported + +fn main() { + extern "Rust" { + fn foo(); + } + + unsafe { + foo(); + } +} diff --git a/tests/run-pass/panic/unsupported_foreign_function.stderr b/tests/run-pass/panic/unsupported_foreign_function.stderr new file mode 100644 index 000000000000..bd7f3490d809 --- /dev/null +++ b/tests/run-pass/panic/unsupported_foreign_function.stderr @@ -0,0 +1,2 @@ +thread 'main' panicked at 'unsupported Miri functionality: can't call foreign function: foo', $DIR/unsupported_foreign_function.rs:9:9 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace From 23c0495ebd64f91629a05eaabbd05f76259f7621 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Tue, 8 Jun 2021 22:17:23 +0800 Subject: [PATCH 2715/5092] Update `Box` to `Box` in `catch_panic.stderr` --- rust-version | 2 +- tests/run-pass/panic/catch_panic.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 81334a8d5a08..7d2e8afafacb 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -cc9610bf5af1d5c54968db0dd899595ca12307a0 +a50d72158e08e02cfc051b863017bdbd2c45b637 diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr index 696dbc1f8181..0f43ab2520a5 100644 --- a/tests/run-pass/panic/catch_panic.stderr +++ b/tests/run-pass/panic/catch_panic.stderr @@ -5,7 +5,7 @@ thread 'main' panicked at 'Hello from panic: 1', $DIR/catch_panic.rs:LL:26 Caught panic message (String): Hello from panic: 1 thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:LL:26 Caught panic message (String): Hello from panic: 2 -thread 'main' panicked at 'Box', $DIR/catch_panic.rs:LL:27 +thread 'main' panicked at 'Box', $DIR/catch_panic.rs:LL:27 Failed to get caught panic message. thread 'main' panicked at 'Hello from panic: core', $DIR/catch_panic.rs:LL:27 Caught panic message (&str): Hello from panic: core From c6bcb4d3c02c3dd6d0f9570d60ca67b8d1fc12f5 Mon Sep 17 00:00:00 2001 From: Kitsu Date: Wed, 9 Jun 2021 10:48:43 +0300 Subject: [PATCH 2716/5092] Specify miri toolchain for CI example --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f0e14a9125c6..21ab49bc1f89 100644 --- a/README.md +++ b/README.md @@ -146,7 +146,7 @@ nightly that *does* come with Miri: MIRI_NIGHTLY=nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/miri) echo "Installing latest nightly with Miri: $MIRI_NIGHTLY" rustup set profile minimal -rustup default "$MIRI_NIGHTLY" +rustup override set "$MIRI_NIGHTLY" rustup component add miri cargo miri test From 892f706ce55d38bf8a6c80fec5d08e785d2240ac Mon Sep 17 00:00:00 2001 From: Smit Soni Date: Thu, 13 May 2021 23:40:07 -0700 Subject: [PATCH 2717/5092] Add a support to execute isolated op without halting In user interface, added a new flag `-Zmiri-isolation-error` which takes one of the four values -- hide, warn, warn-nobacktrace, and abort. This option can be used to configure Miri to either abort or return an error code upon executing isolated op. If not aborted, Miri prints a warning, whose verbosity can be configured using this flag. In implementation, added a new enum `IsolatedOp` to capture all the settings related to ops requiring communication with the host. Old `communicate` flag in both miri configs and machine stats is replaced with a new helper function `communicate()` which checks `isolated_op` internally. Added a new helper function `reject_in_isolation` which can be called by shims to reject ops according to the reject_with settings. Use miri specific diagnostics function `report_msg` to print backtrace in the warning. Update it to take an enum value instead of a bool, indicating the level of diagnostics. Updated shims related to current dir to use the new APIs. Added a new test for current dir ops in isolation without halting machine. --- README.md | 7 ++++ src/bin/miri.rs | 35 +++++++++++++++- src/diagnostics.rs | 41 ++++++++++++------- src/eval.rs | 37 +++++++++++++++-- src/helpers.rs | 28 +++++++++++-- src/lib.rs | 4 +- src/machine.rs | 13 ++++-- src/shims/env.rs | 34 ++++++++++++--- src/shims/posix/fs.rs | 19 +++++---- tests/run-pass/current_dir_with_isolation.rs | 20 +++++++++ .../current_dir_with_isolation.stderr | 4 ++ 11 files changed, 199 insertions(+), 43 deletions(-) create mode 100644 tests/run-pass/current_dir_with_isolation.rs create mode 100644 tests/run-pass/current_dir_with_isolation.stderr diff --git a/README.md b/README.md index 21ab49bc1f89..f6b46ce3a95c 100644 --- a/README.md +++ b/README.md @@ -219,6 +219,13 @@ environment variable: * `-Zmiri-disable-isolation` disables host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness. +* `-Zmiri-isolation-error=` configures Miri's response to operations + requiring host access while isolation is enabled. `abort`, `hide`, `warn`, + and `warn-nobacktrace` are the supported actions. Default action is `abort` + which halts the machine. Rest of the actions configure it to return an error + code for the op and continue executing. `warn` prints backtrace that could + be used to trace the call. `warn-nobacktrace` is less verbose without + backtrace. `hide` hides the warning. * `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from the host so that it cannot be accessed by the program. Can be used multiple times to exclude several variables. On Windows, the `TERM` environment diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 514e5b0aebe9..677836d7e972 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -263,6 +263,9 @@ fn main() { let mut miri_config = miri::MiriConfig::default(); let mut rustc_args = vec![]; let mut after_dashdash = false; + + // If user has explicitly enabled/disabled isolation + let mut isolation_enabled: Option = None; for arg in env::args() { if rustc_args.is_empty() { // Very first arg: binary name. @@ -291,7 +294,37 @@ fn main() { miri_config.check_abi = false; } "-Zmiri-disable-isolation" => { - miri_config.communicate = true; + if matches!(isolation_enabled, Some(true)) { + panic!( + "-Zmiri-disable-isolation cannot be used along with -Zmiri-isolation-error" + ); + } else { + isolation_enabled = Some(false); + } + miri_config.isolated_op = miri::IsolatedOp::Allow; + } + arg if arg.starts_with("-Zmiri-isolation-error=") => { + if matches!(isolation_enabled, Some(false)) { + panic!( + "-Zmiri-isolation-error cannot be used along with -Zmiri-disable-isolation" + ); + } else { + isolation_enabled = Some(true); + } + + miri_config.isolated_op = match arg + .strip_prefix("-Zmiri-isolation-error=") + .unwrap() + { + "abort" => miri::IsolatedOp::Reject(miri::RejectOpWith::Abort), + "hide" => miri::IsolatedOp::Reject(miri::RejectOpWith::NoWarning), + "warn" => miri::IsolatedOp::Reject(miri::RejectOpWith::Warning), + "warn-nobacktrace" => + miri::IsolatedOp::Reject(miri::RejectOpWith::WarningWithoutBacktrace), + _ => panic!( + "-Zmiri-isolation-error must be `abort`, `hide`, `warn`, or `warn-nobacktrace`" + ), + }; } "-Zmiri-ignore-leaks" => { miri_config.ignore_leaks = true; diff --git a/src/diagnostics.rs b/src/diagnostics.rs index f273cf04203d..2b17e83bee69 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -52,6 +52,14 @@ pub enum NonHaltingDiagnostic { CreatedCallId(CallId), CreatedAlloc(AllocId), FreedAlloc(AllocId), + RejectedIsolatedOp(String), +} + +/// Level of Miri specific diagnostics +enum DiagLevel { + Error, + Warning, + Note, } /// Emit a custom diagnostic without going through the miri-engine machinery @@ -76,7 +84,7 @@ pub fn report_error<'tcx, 'mir>( #[rustfmt::skip] let helps = match info { UnsupportedInIsolation(_) => - vec![(None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation"))], + vec![(None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation; or pass `-Zmiri-isolation-error=warn to configure Miri to return an error code from isolated operations and continue with a warning"))], ExperimentalUb { url, .. } => vec![ (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental")), @@ -137,7 +145,7 @@ pub fn report_error<'tcx, 'mir>( let msg = e.to_string(); report_msg( *ecx.tcx, - /*error*/ true, + DiagLevel::Error, &if let Some(title) = title { format!("{}: {}", title, msg) } else { msg.clone() }, msg, helps, @@ -174,18 +182,19 @@ pub fn report_error<'tcx, 'mir>( /// Also emits a full stacktrace of the interpreter stack. fn report_msg<'tcx>( tcx: TyCtxt<'tcx>, - error: bool, + diag_level: DiagLevel, title: &str, span_msg: String, mut helps: Vec<(Option, String)>, stacktrace: &[FrameInfo<'tcx>], ) { let span = stacktrace.first().map_or(DUMMY_SP, |fi| fi.span); - let mut err = if error { - tcx.sess.struct_span_err(span, title) - } else { - tcx.sess.diagnostic().span_note_diag(span, title) + let mut err = match diag_level { + DiagLevel::Error => tcx.sess.struct_span_err(span, title), + DiagLevel::Warning => tcx.sess.struct_span_warn(span, title), + DiagLevel::Note => tcx.sess.diagnostic().span_note_diag(span, title), }; + // Show main message. if span != DUMMY_SP { err.span_label(span, span_msg); @@ -303,15 +312,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx CreatedCallId(id) => format!("function call with id {}", id), CreatedAlloc(AllocId(id)) => format!("created allocation with id {}", id), FreedAlloc(AllocId(id)) => format!("freed allocation with id {}", id), + RejectedIsolatedOp(ref op) => + format!("`{}` was made to return an error due to isolation", op), }; - report_msg( - *this.tcx, - /*error*/ false, - "tracking was triggered", - msg, - vec![], - &stacktrace, - ); + + let (title, diag_level) = match e { + RejectedIsolatedOp(_) => + ("operation rejected by isolation", DiagLevel::Warning), + _ => ("tracking was triggered", DiagLevel::Note), + }; + + report_msg(*this.tcx, diag_level, title, msg, vec![], &stacktrace); } }); } diff --git a/src/eval.rs b/src/eval.rs index 6646783d349c..f1fbeafd3cd7 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -22,6 +22,35 @@ pub enum AlignmentCheck { Int, } +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum RejectOpWith { + /// Isolated op is rejected with an abort of the machine. + Abort, + + /// If not Abort, miri returns an error for an isolated op. + /// Following options determine if user should be warned about such error. + /// Do not print warning about rejected isolated op. + NoWarning, + + /// Print a warning about rejected isolated op, with backtrace. + Warning, + + /// Print a warning about rejected isolated op, without backtrace. + WarningWithoutBacktrace, +} + +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum IsolatedOp { + /// Reject an op requiring communication with the host. By + /// default, miri rejects the op with an abort. If not, it returns + /// an error code, and prints a warning about it. Warning levels + /// are controlled by `RejectOpWith` enum. + Reject(RejectOpWith), + + /// Execute op requiring communication with the host, i.e. disable isolation. + Allow, +} + /// Configuration needed to spawn a Miri instance. #[derive(Clone)] pub struct MiriConfig { @@ -33,8 +62,8 @@ pub struct MiriConfig { pub check_alignment: AlignmentCheck, /// Controls function [ABI](Abi) checking. pub check_abi: bool, - /// Determines if communication with the host environment is enabled. - pub communicate: bool, + /// Action for an op requiring communication with the host. + pub isolated_op: IsolatedOp, /// Determines if memory leaks should be ignored. pub ignore_leaks: bool, /// Environment variables that should always be isolated from the host. @@ -68,7 +97,7 @@ impl Default for MiriConfig { stacked_borrows: true, check_alignment: AlignmentCheck::Int, check_abi: true, - communicate: false, + isolated_op: IsolatedOp::Reject(RejectOpWith::Abort), ignore_leaks: false, excluded_env_vars: vec![], args: vec![], @@ -233,7 +262,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> } SchedulingAction::ExecuteTimeoutCallback => { assert!( - ecx.machine.communicate, + ecx.machine.communicate(), "scheduler callbacks require disabled isolation, but the code \ that created the callback did not check it" ); diff --git a/src/helpers.rs b/src/helpers.rs index 52176342057e..e9bedd1a1187 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -140,7 +140,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut data = vec![0; usize::try_from(len).unwrap()]; - if this.machine.communicate { + if this.machine.communicate() { // Fill the buffer using the host's rng. getrandom::getrandom(&mut data) .map_err(|err| err_unsup_format!("host getrandom failed: {}", err))?; @@ -391,12 +391,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// disabled. It returns an error using the `name` of the foreign function if this is not the /// case. fn check_no_isolation(&self, name: &str) -> InterpResult<'tcx> { - if !self.eval_context_ref().machine.communicate { - isolation_error(name)?; + if !self.eval_context_ref().machine.communicate() { + self.reject_in_isolation(name, RejectOpWith::Abort)?; } Ok(()) } + /// Helper function used inside the shims of foreign functions which reject the op + /// when isolation is enabled. It is used to print a warning/backtrace about the rejection. + fn reject_in_isolation(&self, op_name: &str, reject_with: RejectOpWith) -> InterpResult<'tcx> { + let this = self.eval_context_ref(); + match reject_with { + RejectOpWith::Abort => isolation_abort_error(op_name), + RejectOpWith::WarningWithoutBacktrace => { + this.tcx + .sess + .warn(&format!("`{}` was made to return an error due to isolation", op_name)); + Ok(()) + } + RejectOpWith::Warning => { + register_diagnostic(NonHaltingDiagnostic::RejectedIsolatedOp(op_name.to_string())); + Ok(()) + } + RejectOpWith::NoWarning => Ok(()), // no warning + } + } + /// Helper function used inside the shims of foreign functions to assert that the target OS /// is `target_os`. It panics showing a message with the `name` of the foreign function /// if this is not the case. @@ -651,7 +671,7 @@ where throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N) } -pub fn isolation_error(name: &str) -> InterpResult<'static> { +pub fn isolation_abort_error(name: &str) -> InterpResult<'static> { throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!( "{} not available when isolation is enabled", name, diff --git a/src/lib.rs b/src/lib.rs index 25806b472b60..8c0a19b6dfbd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -59,7 +59,9 @@ pub use crate::diagnostics::{ register_diagnostic, report_error, EvalContextExt as DiagnosticsEvalContextExt, NonHaltingDiagnostic, TerminationInfo, }; -pub use crate::eval::{create_ecx, eval_main, AlignmentCheck, MiriConfig}; +pub use crate::eval::{ + create_ecx, eval_main, AlignmentCheck, IsolatedOp, MiriConfig, RejectOpWith, +}; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; pub use crate::machine::{ AllocExtra, Evaluator, FrameData, MemoryExtra, MiriEvalContext, MiriEvalContextExt, diff --git a/src/machine.rs b/src/machine.rs index 9c49575ded32..752d21344825 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -263,9 +263,10 @@ pub struct Evaluator<'mir, 'tcx> { /// TLS state. pub(crate) tls: TlsData<'tcx>, - /// If enabled, the `env_vars` field is populated with the host env vars during initialization - /// and random number generation is delegated to the host. - pub(crate) communicate: bool, + /// What should Miri do when an op requires communicating with the host, + /// such as accessing host env vars, random number generation, and + /// file system access. + pub(crate) isolated_op: IsolatedOp, /// Whether to enforce the validity invariant. pub(crate) validate: bool, @@ -314,7 +315,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { argv: None, cmd_line: None, tls: TlsData::default(), - communicate: config.communicate, + isolated_op: config.isolated_op, validate: config.validate, enforce_abi: config.check_abi, file_handler: Default::default(), @@ -328,6 +329,10 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { exported_symbols_cache: FxHashMap::default(), } } + + pub(crate) fn communicate(&self) -> bool { + self.isolated_op == IsolatedOp::Allow + } } /// A rustc InterpCx for Miri. diff --git a/src/shims/env.rs b/src/shims/env.rs index a09169753223..9a68cf7bd539 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,6 +1,7 @@ use std::convert::TryFrom; use std::env; use std::ffi::{OsStr, OsString}; +use std::io::{Error, ErrorKind}; use rustc_data_structures::fx::FxHashMap; use rustc_mir::interpret::Pointer; @@ -45,7 +46,7 @@ impl<'tcx> EnvVars<'tcx> { excluded_env_vars.push("TERM".to_owned()); } - if ecx.machine.communicate { + if ecx.machine.communicate() { for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { let var_ptr = match target_os { @@ -321,7 +322,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "`getcwd` is only available for the UNIX target family" ); - this.check_no_isolation("`getcwd`")?; + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("getcwd", reject_with)?; + let err = Error::new(ErrorKind::NotFound, "rejected due to isolation"); + this.set_last_error_from_io_error(err)?; + return Ok(Scalar::null_ptr(&*this.tcx)); + } let buf = this.read_scalar(&buf_op)?.check_init()?; let size = this.read_scalar(&size_op)?.to_machine_usize(&*this.tcx)?; @@ -336,6 +342,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Err(e) => this.set_last_error_from_io_error(e)?, } + Ok(Scalar::null_ptr(&*this.tcx)) } @@ -348,7 +355,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("windows", "GetCurrentDirectoryW"); - this.check_no_isolation("`GetCurrentDirectoryW`")?; + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("GetCurrentDirectoryW", reject_with)?; + let err = Error::new(ErrorKind::NotFound, "rejected due to isolation"); + this.set_last_error_from_io_error(err)?; + return Ok(0); + } let size = u64::from(this.read_scalar(size_op)?.to_u32()?); let buf = this.read_scalar(buf_op)?.check_init()?; @@ -370,7 +382,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "`getcwd` is only available for the UNIX target family" ); - this.check_no_isolation("`chdir`")?; + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("chdir", reject_with)?; + let err = Error::new(ErrorKind::NotFound, "rejected due to isolation"); + this.set_last_error_from_io_error(err)?; + + return Ok(-1); + } let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?; @@ -393,7 +411,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("windows", "SetCurrentDirectoryW"); - this.check_no_isolation("`SetCurrentDirectoryW`")?; + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("SetCurrentDirectoryW", reject_with)?; + let err = Error::new(ErrorKind::NotFound, "rejected due to isolation"); + this.set_last_error_from_io_error(err)?; + + return Ok(0); + } let path = this.read_path_from_wide_str(this.read_scalar(path_op)?.check_init()?)?; diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 06594e5ca1d6..ca7a91a0f94e 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -127,7 +127,7 @@ impl FileDescriptor for io::Stdin { ) -> InterpResult<'tcx, io::Result> { if !communicate_allowed { // We want isolation mode to be deterministic, so we have to disallow all reads, even stdin. - helpers::isolation_error("`read` from stdin")?; + helpers::isolation_abort_error("`read` from stdin")?; } Ok(Read::read(self, bytes)) } @@ -662,7 +662,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.remove(&fd) { - let result = file_descriptor.close(this.machine.communicate)?; + let result = file_descriptor.close(this.machine.communicate())?; this.try_unwrap_io_result(result) } else { this.handle_not_found() @@ -687,6 +687,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We cap the number of read bytes to the largest value that we are able to fit in both the // host's and target's `isize`. This saves us from having to handle overflows later. let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64); + let communicate = this.machine.communicate(); if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { trace!("read: FD mapped to {:?}", file_descriptor); @@ -696,9 +697,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut bytes = vec![0; count as usize]; // `File::read` never returns a value larger than `count`, // so this cannot fail. - let result = file_descriptor - .read(this.machine.communicate, &mut bytes)? - .map(|c| i64::try_from(c).unwrap()); + let result = + file_descriptor.read(communicate, &mut bytes)?.map(|c| i64::try_from(c).unwrap()); match result { Ok(read_bytes) => { @@ -733,12 +733,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We cap the number of written bytes to the largest value that we are able to fit in both the // host's and target's `isize`. This saves us from having to handle overflows later. let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64); + let communicate = this.machine.communicate(); if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; - let result = file_descriptor - .write(this.machine.communicate, &bytes)? - .map(|c| i64::try_from(c).unwrap()); + let result = + file_descriptor.write(communicate, &bytes)?.map(|c| i64::try_from(c).unwrap()); this.try_unwrap_io_result(result) } else { this.handle_not_found() @@ -771,9 +771,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); }; + let communicate = this.machine.communicate(); if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { let result = file_descriptor - .seek(this.machine.communicate, seek_from)? + .seek(communicate, seek_from)? .map(|offset| i64::try_from(offset).unwrap()); this.try_unwrap_io_result(result) } else { diff --git a/tests/run-pass/current_dir_with_isolation.rs b/tests/run-pass/current_dir_with_isolation.rs new file mode 100644 index 000000000000..ea891c899834 --- /dev/null +++ b/tests/run-pass/current_dir_with_isolation.rs @@ -0,0 +1,20 @@ +// compile-flags: -Zmiri-isolation-error=warn-nobacktrace +// normalize-stderr-test "(getcwd|GetCurrentDirectoryW)" -> "$$GET" +// normalize-stderr-test "(chdir|SetCurrentDirectoryW)" -> "$$SET" + +use std::env; +use std::io::ErrorKind; + +fn main() { + // Test that current dir operations return a proper error instead + // of stopping the machine in isolation mode + assert_eq!(env::current_dir().unwrap_err().kind(), ErrorKind::NotFound); + for _i in 0..3 { + assert_eq!(env::current_dir().unwrap_err().kind(), ErrorKind::NotFound); + } + + assert_eq!(env::set_current_dir("..").unwrap_err().kind(), ErrorKind::NotFound); + for _i in 0..3 { + assert_eq!(env::set_current_dir("..").unwrap_err().kind(), ErrorKind::NotFound); + } +} diff --git a/tests/run-pass/current_dir_with_isolation.stderr b/tests/run-pass/current_dir_with_isolation.stderr new file mode 100644 index 000000000000..cc0975230de6 --- /dev/null +++ b/tests/run-pass/current_dir_with_isolation.stderr @@ -0,0 +1,4 @@ +warning: `$GET` was made to return an error due to isolation + +warning: `$SET` was made to return an error due to isolation + From ba64f485c881052c980648bed0b4ce29fb6dc19c Mon Sep 17 00:00:00 2001 From: Smit Soni Date: Wed, 9 Jun 2021 06:28:35 -0700 Subject: [PATCH 2718/5092] Fix parameter of io error helper function `set_last_error_from_io_error` works with only the error kind, and discards the payload. Fix its signature to make it explicit. --- src/helpers.rs | 19 +++++++++++-------- src/shims/env.rs | 22 +++++++++------------- src/shims/posix/fs.rs | 10 +++++----- 3 files changed, 25 insertions(+), 26 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index e9bedd1a1187..8bfc65111d49 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -460,15 +460,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.read_scalar(&errno_place.into())?.check_init() } - /// Sets the last OS error using a `std::io::Error`. This function tries to produce the most + /// Sets the last OS error using a `std::io::ErrorKind`. This function tries to produce the most /// similar OS error from the `std::io::ErrorKind` and sets it as the last OS error. - fn set_last_error_from_io_error(&mut self, e: std::io::Error) -> InterpResult<'tcx> { + fn set_last_error_from_io_error(&mut self, err_kind: std::io::ErrorKind) -> InterpResult<'tcx> { use std::io::ErrorKind::*; let this = self.eval_context_mut(); let target = &this.tcx.sess.target; let target_os = &target.os; let last_error = if target.families.contains(&"unix".to_owned()) { - this.eval_libc(match e.kind() { + this.eval_libc(match err_kind { ConnectionRefused => "ECONNREFUSED", ConnectionReset => "ECONNRESET", PermissionDenied => "EPERM", @@ -484,18 +484,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx AlreadyExists => "EEXIST", WouldBlock => "EWOULDBLOCK", _ => { - throw_unsup_format!("io error {} cannot be transformed into a raw os error", e) + throw_unsup_format!( + "io error {:?} cannot be transformed into a raw os error", + err_kind + ) } })? } else if target.families.contains(&"windows".to_owned()) { // FIXME: we have to finish implementing the Windows equivalent of this. this.eval_windows( "c", - match e.kind() { + match err_kind { NotFound => "ERROR_FILE_NOT_FOUND", _ => throw_unsup_format!( - "io error {} cannot be transformed into a raw os error", - e + "io error {:?} cannot be transformed into a raw os error", + err_kind ), }, )? @@ -521,7 +524,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match result { Ok(ok) => Ok(ok), Err(e) => { - self.eval_context_mut().set_last_error_from_io_error(e)?; + self.eval_context_mut().set_last_error_from_io_error(e.kind())?; Ok((-1).into()) } } diff --git a/src/shims/env.rs b/src/shims/env.rs index 9a68cf7bd539..2ce0fbfdc949 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,7 +1,7 @@ use std::convert::TryFrom; use std::env; use std::ffi::{OsStr, OsString}; -use std::io::{Error, ErrorKind}; +use std::io::ErrorKind; use rustc_data_structures::fx::FxHashMap; use rustc_mir::interpret::Pointer; @@ -324,8 +324,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("getcwd", reject_with)?; - let err = Error::new(ErrorKind::NotFound, "rejected due to isolation"); - this.set_last_error_from_io_error(err)?; + this.set_last_error_from_io_error(ErrorKind::NotFound)?; return Ok(Scalar::null_ptr(&*this.tcx)); } @@ -340,7 +339,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let erange = this.eval_libc("ERANGE")?; this.set_last_error(erange)?; } - Err(e) => this.set_last_error_from_io_error(e)?, + Err(e) => this.set_last_error_from_io_error(e.kind())?, } Ok(Scalar::null_ptr(&*this.tcx)) @@ -357,8 +356,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("GetCurrentDirectoryW", reject_with)?; - let err = Error::new(ErrorKind::NotFound, "rejected due to isolation"); - this.set_last_error_from_io_error(err)?; + this.set_last_error_from_io_error(ErrorKind::NotFound)?; return Ok(0); } @@ -369,7 +367,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match env::current_dir() { Ok(cwd) => return Ok(windows_check_buffer_size(this.write_path_to_wide_str(&cwd, buf, size)?)), - Err(e) => this.set_last_error_from_io_error(e)?, + Err(e) => this.set_last_error_from_io_error(e.kind())?, } Ok(0) } @@ -384,8 +382,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("chdir", reject_with)?; - let err = Error::new(ErrorKind::NotFound, "rejected due to isolation"); - this.set_last_error_from_io_error(err)?; + this.set_last_error_from_io_error(ErrorKind::NotFound)?; return Ok(-1); } @@ -395,7 +392,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match env::set_current_dir(path) { Ok(()) => Ok(0), Err(e) => { - this.set_last_error_from_io_error(e)?; + this.set_last_error_from_io_error(e.kind())?; Ok(-1) } } @@ -413,8 +410,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("SetCurrentDirectoryW", reject_with)?; - let err = Error::new(ErrorKind::NotFound, "rejected due to isolation"); - this.set_last_error_from_io_error(err)?; + this.set_last_error_from_io_error(ErrorKind::NotFound)?; return Ok(0); } @@ -424,7 +420,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match env::set_current_dir(path) { Ok(()) => Ok(1), Err(e) => { - this.set_last_error_from_io_error(e)?; + this.set_last_error_from_io_error(e.kind())?; Ok(0) } } diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index ca7a91a0f94e..fbef9f304071 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -634,7 +634,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match dup_result { Ok(dup_fd) => Ok(fh.insert_fd_with_min_fd(dup_fd, start)), Err(e) => { - this.set_last_error_from_io_error(e)?; + this.set_last_error_from_io_error(e.kind())?; Ok(-1) } } @@ -707,7 +707,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(read_bytes) } Err(e) => { - this.set_last_error_from_io_error(e)?; + this.set_last_error_from_io_error(e.kind())?; Ok(-1) } } @@ -1118,7 +1118,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(Scalar::from_machine_usize(id, this)) } Err(e) => { - this.set_last_error_from_io_error(e)?; + this.set_last_error_from_io_error(e.kind())?; Ok(Scalar::null_ptr(this)) } } @@ -1462,7 +1462,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(path_bytes.len().try_into().unwrap()) } Err(e) => { - this.set_last_error_from_io_error(e)?; + this.set_last_error_from_io_error(e.kind())?; Ok(-1) } } @@ -1526,7 +1526,7 @@ impl FileMetadata { let metadata = match metadata { Ok(metadata) => metadata, Err(e) => { - ecx.set_last_error_from_io_error(e)?; + ecx.set_last_error_from_io_error(e.kind())?; return Ok(None); } }; From a38f02c44c56c2b6378e18ae238f4178db7eafd9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Jun 2021 18:21:23 +0200 Subject: [PATCH 2719/5092] isolated operations return EPERM; tweak isolation hint --- src/diagnostics.rs | 5 ++++- src/helpers.rs | 5 +++-- src/shims/env.rs | 8 ++++---- tests/run-pass/current_dir_with_isolation.rs | 13 +++++++------ tests/run-pass/current_dir_with_isolation.stderr | 4 ++-- 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 2b17e83bee69..1687297bde7c 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -84,7 +84,10 @@ pub fn report_error<'tcx, 'mir>( #[rustfmt::skip] let helps = match info { UnsupportedInIsolation(_) => - vec![(None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation; or pass `-Zmiri-isolation-error=warn to configure Miri to return an error code from isolated operations and continue with a warning"))], + vec![ + (None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation;")), + (None, format!("or pass `-Zmiri-isolation-error=warn to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning")), + ], ExperimentalUb { url, .. } => vec![ (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental")), diff --git a/src/helpers.rs b/src/helpers.rs index 8bfc65111d49..8586d732dce6 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -485,7 +485,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx WouldBlock => "EWOULDBLOCK", _ => { throw_unsup_format!( - "io error {:?} cannot be transformed into a raw os error", + "io error {:?} cannot be translated into a raw os error", err_kind ) } @@ -496,8 +496,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "c", match err_kind { NotFound => "ERROR_FILE_NOT_FOUND", + PermissionDenied => "ERROR_ACCESS_DENIED", _ => throw_unsup_format!( - "io error {:?} cannot be transformed into a raw os error", + "io error {:?} cannot be translated into a raw os error", err_kind ), }, diff --git a/src/shims/env.rs b/src/shims/env.rs index 2ce0fbfdc949..0c42daa2446a 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -324,7 +324,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("getcwd", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::NotFound)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; return Ok(Scalar::null_ptr(&*this.tcx)); } @@ -356,7 +356,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("GetCurrentDirectoryW", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::NotFound)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; return Ok(0); } @@ -382,7 +382,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("chdir", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::NotFound)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; return Ok(-1); } @@ -410,7 +410,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("SetCurrentDirectoryW", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::NotFound)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; return Ok(0); } diff --git a/tests/run-pass/current_dir_with_isolation.rs b/tests/run-pass/current_dir_with_isolation.rs index ea891c899834..b5fe6114b2f3 100644 --- a/tests/run-pass/current_dir_with_isolation.rs +++ b/tests/run-pass/current_dir_with_isolation.rs @@ -1,6 +1,6 @@ // compile-flags: -Zmiri-isolation-error=warn-nobacktrace -// normalize-stderr-test "(getcwd|GetCurrentDirectoryW)" -> "$$GET" -// normalize-stderr-test "(chdir|SetCurrentDirectoryW)" -> "$$SET" +// normalize-stderr-test "(getcwd|GetCurrentDirectoryW)" -> "$$GETCWD" +// normalize-stderr-test "(chdir|SetCurrentDirectoryW)" -> "$$SETCWD" use std::env; use std::io::ErrorKind; @@ -8,13 +8,14 @@ use std::io::ErrorKind; fn main() { // Test that current dir operations return a proper error instead // of stopping the machine in isolation mode - assert_eq!(env::current_dir().unwrap_err().kind(), ErrorKind::NotFound); + assert_eq!(env::current_dir().unwrap_err().kind(), ErrorKind::PermissionDenied); for _i in 0..3 { - assert_eq!(env::current_dir().unwrap_err().kind(), ErrorKind::NotFound); + // Ensure we get no repeated warnings when doing this multiple times. + assert_eq!(env::current_dir().unwrap_err().kind(), ErrorKind::PermissionDenied); } - assert_eq!(env::set_current_dir("..").unwrap_err().kind(), ErrorKind::NotFound); + assert_eq!(env::set_current_dir("..").unwrap_err().kind(), ErrorKind::PermissionDenied); for _i in 0..3 { - assert_eq!(env::set_current_dir("..").unwrap_err().kind(), ErrorKind::NotFound); + assert_eq!(env::set_current_dir("..").unwrap_err().kind(), ErrorKind::PermissionDenied); } } diff --git a/tests/run-pass/current_dir_with_isolation.stderr b/tests/run-pass/current_dir_with_isolation.stderr index cc0975230de6..589ca65a1e47 100644 --- a/tests/run-pass/current_dir_with_isolation.stderr +++ b/tests/run-pass/current_dir_with_isolation.stderr @@ -1,4 +1,4 @@ -warning: `$GET` was made to return an error due to isolation +warning: `$GETCWD` was made to return an error due to isolation -warning: `$SET` was made to return an error due to isolation +warning: `$SETCWD` was made to return an error due to isolation From 87f2073c80c9cdec9e0b4c87ec54a531f2abb4df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Jun 2021 21:09:17 +0200 Subject: [PATCH 2720/5092] tweak isolation-error message in README --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f6b46ce3a95c..cf4689d08fb6 100644 --- a/README.md +++ b/README.md @@ -221,11 +221,11 @@ environment variable: systems, and randomness. * `-Zmiri-isolation-error=` configures Miri's response to operations requiring host access while isolation is enabled. `abort`, `hide`, `warn`, - and `warn-nobacktrace` are the supported actions. Default action is `abort` - which halts the machine. Rest of the actions configure it to return an error - code for the op and continue executing. `warn` prints backtrace that could - be used to trace the call. `warn-nobacktrace` is less verbose without - backtrace. `hide` hides the warning. + and `warn-nobacktrace` are the supported actions. The default is to `abort`, + which halts the machine. Some (but not all) operations also support continuing + execution with a "permission denied" error being returned to the program. + `warn` prints a full backtrace when that happen; `warn-nobacktrace` is less + verbose. `hide` hides the warning entirely. * `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from the host so that it cannot be accessed by the program. Can be used multiple times to exclude several variables. On Windows, the `TERM` environment From 4f3718ef85199da1ce5016a5df382ee396552290 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Fri, 11 Jun 2021 11:13:16 +0800 Subject: [PATCH 2721/5092] Fix the wrong `EmulateByNameResult::NotSupported` in `syscall` shim --- src/shims/posix/linux/foreign_items.rs | 2 +- tests/run-pass/panic/unsupported_syscall.rs | 12 ++++++++++++ tests/run-pass/panic/unsupported_syscall.stderr | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 tests/run-pass/panic/unsupported_syscall.rs create mode 100644 tests/run-pass/panic/unsupported_syscall.stderr diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 68ae704fb04f..178b82f61311 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -185,7 +185,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } id => { this.handle_unsupported(format!("can't execute syscall with ID {}", id))?; - return Ok(EmulateByNameResult::NotSupported); + return Ok(EmulateByNameResult::AlreadyJumped); } } } diff --git a/tests/run-pass/panic/unsupported_syscall.rs b/tests/run-pass/panic/unsupported_syscall.rs new file mode 100644 index 000000000000..854f179392c4 --- /dev/null +++ b/tests/run-pass/panic/unsupported_syscall.rs @@ -0,0 +1,12 @@ +// ignore-windows: No libc on Windows +// ignore-macos: `syscall` is not supported on macOS +// compile-flags: -Zmiri-panic-on-unsupported +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + unsafe { + libc::syscall(0); + } +} diff --git a/tests/run-pass/panic/unsupported_syscall.stderr b/tests/run-pass/panic/unsupported_syscall.stderr new file mode 100644 index 000000000000..49796ee2021f --- /dev/null +++ b/tests/run-pass/panic/unsupported_syscall.stderr @@ -0,0 +1,2 @@ +thread 'main' panicked at 'unsupported Miri functionality: can't execute syscall with ID 0', $DIR/unsupported_syscall.rs:10:9 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace From 6aef1d687d6330fedb468e77e28940a6ea6ddb8b Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Tue, 8 Jun 2021 20:36:21 +0800 Subject: [PATCH 2722/5092] Remove erroneous `exit()` and `ExitProcess()` in `tests/run-pass/function_calls/exported_symbol.rs` --- tests/run-pass/function_calls/exported_symbol.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/tests/run-pass/function_calls/exported_symbol.rs b/tests/run-pass/function_calls/exported_symbol.rs index 96bf8170c6eb..c141f557e1d7 100644 --- a/tests/run-pass/function_calls/exported_symbol.rs +++ b/tests/run-pass/function_calls/exported_symbol.rs @@ -15,17 +15,6 @@ fn baz() -> i32 { -3 } -// Make sure shims take precedence. -#[no_mangle] -extern "C" fn exit(_: i32) -> ! { - unreachable!() -} - -#[no_mangle] -extern "C" fn ExitProcess(_: u32) -> ! { - unreachable!() -} - fn main() { // Repeat calls to make sure the `Instance` cache is not broken. for _ in 0..3 { From ce7040075adea348beae45e9aa2af2a2f25dfc18 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 6 Jun 2021 15:25:16 +0800 Subject: [PATCH 2723/5092] Disallow `#[no_mangle]`/`#[export_name = ...]` functions that have the same symbol name as built-in shims --- src/diagnostics.rs | 13 +- src/helpers.rs | 31 +++ src/shims/backtrace.rs | 13 +- src/shims/foreign_items.rs | 88 ++++---- src/shims/panic.rs | 5 +- src/shims/posix/foreign_items.rs | 189 ++++++------------ src/shims/posix/linux/foreign_items.rs | 64 +++--- src/shims/posix/macos/foreign_items.rs | 74 ++++--- src/shims/windows/foreign_items.rs | 164 +++++++-------- .../exported_symbol_shim_clashing.rs | 15 ++ 10 files changed, 320 insertions(+), 336 deletions(-) create mode 100644 tests/compile-fail/function_calls/exported_symbol_shim_clashing.rs diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 1687297bde7c..887b2ac4b378 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -26,6 +26,10 @@ pub enum TerminationInfo { second: SpanData, second_crate: Symbol, }, + SymbolShimClashing { + link_name: Symbol, + span: SpanData, + }, } impl fmt::Display for TerminationInfo { @@ -39,6 +43,11 @@ impl fmt::Display for TerminationInfo { Deadlock => write!(f, "the evaluated program deadlocked"), MultipleSymbolDefinitions { link_name, .. } => write!(f, "multiple definitions of symbol `{}`", link_name), + SymbolShimClashing { link_name, .. } => write!( + f, + "found `{}` symbol definition that clashes with a built-in shim", + link_name + ), } } } @@ -79,7 +88,7 @@ pub fn report_error<'tcx, 'mir>( UnsupportedInIsolation(_) => Some("unsupported operation"), ExperimentalUb { .. } => Some("Undefined Behavior"), Deadlock => Some("deadlock"), - MultipleSymbolDefinitions { .. } => None, + MultipleSymbolDefinitions { .. } | SymbolShimClashing { .. } => None, }; #[rustfmt::skip] let helps = match info { @@ -98,6 +107,8 @@ pub fn report_error<'tcx, 'mir>( (Some(*first), format!("it's first defined here, in crate `{}`", first_crate)), (Some(*second), format!("then it's defined here again, in crate `{}`", second_crate)), ], + SymbolShimClashing { link_name, span } => + vec![(Some(*span), format!("the `{}` symbol is defined here", link_name))], _ => vec![], }; (title, helps) diff --git a/src/helpers.rs b/src/helpers.rs index e0f273be3435..b99a446577ac 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -8,6 +8,7 @@ use log::trace; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_middle::mir; use rustc_middle::ty::{self, layout::TyAndLayout, List, TyCtxt}; +use rustc_span::Symbol; use rustc_target::abi::{Align, FieldsShape, LayoutOf, Size, Variants}; use rustc_target::spec::abi::Abi; @@ -677,6 +678,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("{}", error_msg.as_ref()); } } + + fn check_abi_and_shim_symbol_clash( + &mut self, + abi: Abi, + exp_abi: Abi, + link_name: Symbol, + ) -> InterpResult<'tcx, ()> { + self.check_abi(abi, exp_abi)?; + if let Some(body) = self.eval_context_mut().lookup_exported_symbol(link_name)? { + throw_machine_stop!(TerminationInfo::SymbolShimClashing { + link_name, + span: body.span.data(), + }) + } + Ok(()) + } + + fn check_shim<'a, const N: usize>( + &mut self, + abi: Abi, + exp_abi: Abi, + link_name: Symbol, + args: &'a [OpTy<'tcx, Tag>], + ) -> InterpResult<'tcx, &'a [OpTy<'tcx, Tag>; N]> + where + &'a [OpTy<'tcx, Tag>; N]: TryFrom<&'a [OpTy<'tcx, Tag>]>, + { + self.check_abi_and_shim_symbol_clash(abi, exp_abi, link_name)?; + check_arg_count(args) + } } /// Check that the number of args is what we expect. diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index e866868d729f..4ea374344c0d 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -1,22 +1,23 @@ use crate::rustc_target::abi::LayoutOf as _; use crate::*; -use helpers::check_arg_count; use rustc_ast::ast::Mutability; use rustc_middle::ty::{self, TypeAndMut}; -use rustc_span::BytePos; -use rustc_target::abi::Size; +use rustc_span::{BytePos, Symbol}; +use rustc_target::{abi::Size, spec::abi::Abi}; use std::convert::TryInto as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn handle_miri_get_backtrace( &mut self, + abi: Abi, + link_name: Symbol, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let tcx = this.tcx; - let &[ref flags] = check_arg_count(args)?; + let &[ref flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; let flags = this.read_scalar(flags)?.to_u64()?; if flags != 0 { @@ -71,12 +72,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn handle_miri_resolve_frame( &mut self, + abi: Abi, + link_name: Symbol, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let tcx = this.tcx; - let &[ref ptr, ref flags] = check_arg_count(args)?; + let &[ref ptr, ref flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; let flags = this.read_scalar(flags)?.to_u64()?; if flags != 0 { diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 8f3dfdc4f81f..f193751518e1 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -25,7 +25,6 @@ use rustc_target::{ use super::backtrace::EvalContextExt as _; use crate::*; -use helpers::check_arg_count; /// Returned by `emulate_foreign_item_by_name`. pub enum EmulateByNameResult { @@ -227,14 +226,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (dest, ret) = match ret { None => match link_name { "miri_start_panic" => { - this.check_abi(abi, Abi::Rust)?; - this.handle_miri_start_panic(args, unwind)?; + this.handle_miri_start_panic(abi, link_name_sym, args, unwind)?; return Ok(None); } // This matches calls to the foreign item `panic_impl`. // The implementation is provided by the function with the `#[panic_handler]` attribute. "panic_impl" => { - this.check_abi(abi, Abi::Rust)?; + this.check_abi_and_shim_symbol_clash(abi, Abi::Rust, link_name_sym)?; let panic_impl_id = tcx.lang_items().panic_impl().unwrap(); let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id); return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); @@ -243,14 +241,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "exit" | "ExitProcess" => { - this.check_abi(abi, if link_name == "exit" { Abi::C { unwind: false } } else { Abi::System { unwind: false } })?; - let &[ref code] = check_arg_count(args)?; + let &[ref code] = this.check_shim(abi, if link_name == "exit" { Abi::C { unwind: false } } else { Abi::System { unwind: false } }, link_name_sym, args)?; // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway let code = this.read_scalar(code)?.to_i32()?; throw_machine_stop!(TerminationInfo::Exit(code.into())); } "abort" => { - this.check_abi(abi, Abi::C { unwind: false })?; + this.check_abi_and_shim_symbol_clash( + abi, + Abi::C { unwind: false }, + link_name_sym, + )?; throw_machine_stop!(TerminationInfo::Abort( "the program aborted execution".to_owned() )) @@ -270,7 +271,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Second: functions that return. - match this.emulate_foreign_item_by_name(link_name, abi, args, dest, ret)? { + match this.emulate_foreign_item_by_name(link_name, link_name_sym, abi, args, dest, ret)? { EmulateByNameResult::NeedsJumping => { trace!("{:?}", this.dump_place(**dest)); this.go_to_block(ret); @@ -293,6 +294,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_foreign_item_by_name( &mut self, link_name: &str, + link_name_sym: Symbol, abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, @@ -305,8 +307,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Miri-specific extern functions "miri_static_root" => { - this.check_abi(abi, Abi::Rust)?; - let &[ref ptr] = check_arg_count(args)?; + let &[ref ptr] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let ptr = this.force_ptr(ptr)?; if ptr.offset != Size::ZERO { @@ -317,28 +318,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Obtains a Miri backtrace. See the README for details. "miri_get_backtrace" => { - this.check_abi(abi, Abi::Rust)?; - this.handle_miri_get_backtrace(args, dest)?; + this.handle_miri_get_backtrace(abi, link_name_sym, args, dest)?; } // Resolves a Miri backtrace frame. See the README for details. "miri_resolve_frame" => { - this.check_abi(abi, Abi::Rust)?; - this.handle_miri_resolve_frame(args, dest)?; + this.handle_miri_resolve_frame(abi, link_name_sym, args, dest)?; } // Standard C allocation "malloc" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref size] = check_arg_count(args)?; + let &[ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C); this.write_scalar(res, dest)?; } "calloc" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref items, ref len] = check_arg_count(args)?; + let &[ref items, ref len] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let items = this.read_scalar(items)?.to_machine_usize(this)?; let len = this.read_scalar(len)?.to_machine_usize(this)?; let size = @@ -347,14 +344,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } "free" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref ptr] = check_arg_count(args)?; + let &[ref ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; this.free(ptr, MiriMemoryKind::C)?; } "realloc" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref old_ptr, ref new_size] = check_arg_count(args)?; + let &[ref old_ptr, ref new_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let old_ptr = this.read_scalar(old_ptr)?.check_init()?; let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; let res = this.realloc(old_ptr, new_size, MiriMemoryKind::C)?; @@ -365,8 +360,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // (Usually these would be forwarded to to `#[global_allocator]`; we instead implement a generic // allocation that also checks that all conditions are met, such as not permitting zero-sized allocations.) "__rust_alloc" => { - this.check_abi(abi, Abi::Rust)?; - let &[ref size, ref align] = check_arg_count(args)?; + let &[ref size, ref align] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; Self::check_alloc_request(size, align)?; @@ -378,8 +372,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "__rust_alloc_zeroed" => { - this.check_abi(abi, Abi::Rust)?; - let &[ref size, ref align] = check_arg_count(args)?; + let &[ref size, ref align] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; Self::check_alloc_request(size, align)?; @@ -393,8 +386,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "__rust_dealloc" => { - this.check_abi(abi, Abi::Rust)?; - let &[ref ptr, ref old_size, ref align] = check_arg_count(args)?; + let &[ref ptr, ref old_size, ref align] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -407,8 +399,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; } "__rust_realloc" => { - this.check_abi(abi, Abi::Rust)?; - let &[ref ptr, ref old_size, ref align, ref new_size] = check_arg_count(args)?; + let &[ref ptr, ref old_size, ref align, ref new_size] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?; let ptr = this.force_ptr(this.read_scalar(ptr)?.check_init()?)?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -428,8 +419,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // C memory handling functions "memcmp" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref left, ref right, ref n] = check_arg_count(args)?; + let &[ref left, ref right, ref n] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let left = this.read_scalar(left)?.check_init()?; let right = this.read_scalar(right)?.check_init()?; let n = Size::from_bytes(this.read_scalar(n)?.to_machine_usize(this)?); @@ -449,8 +439,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "memrchr" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref ptr, ref val, ref num] = check_arg_count(args)?; + let &[ref ptr, ref val, ref num] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; @@ -468,8 +457,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "memchr" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref ptr, ref val, ref num] = check_arg_count(args)?; + let &[ref ptr, ref val, ref num] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; @@ -486,8 +474,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "strlen" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref ptr] = check_arg_count(args)?; + let &[ref ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let n = this.read_c_str(ptr)?.len(); this.write_scalar(Scalar::from_machine_usize(u64::try_from(n).unwrap(), this), dest)?; @@ -503,8 +490,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asinf" | "atanf" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref f] = check_arg_count(args)?; + let &[ref f] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let f = match link_name { @@ -524,8 +510,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypotf" | "atan2f" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref f1, ref f2] = check_arg_count(args)?; + let &[ref f1, ref f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; // underscore case for windows, here and below // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) // FIXME: Using host floats. @@ -547,8 +532,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asin" | "atan" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref f] = check_arg_count(args)?; + let &[ref f] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let f = match link_name { @@ -568,8 +552,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypot" | "atan2" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref f1, ref f2] = check_arg_count(args)?; + let &[ref f1, ref f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; // FIXME: Using host floats. let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?); let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?); @@ -585,8 +568,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "ldexp" | "scalbn" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref x, ref exp] = check_arg_count(args)?; + let &[ref x, ref exp] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. let x = this.read_scalar(x)?.to_f64()?; let exp = this.read_scalar(exp)?.to_i32()?; @@ -607,13 +589,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Architecture-specific shims "llvm.x86.sse2.pause" if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.yield_active_thread(); } "llvm.aarch64.isb" if this.tcx.sess.target.arch == "aarch64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref arg] = check_arg_count(args)?; + let &[ref arg] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let arg = this.read_scalar(arg)?.to_i32()?; match arg { 15 => { // SY ("full system scope") @@ -627,8 +607,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Platform-specific shims _ => match this.tcx.sess.target.os.as_str() { - "linux" | "macos" => return shims::posix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), - "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), + "linux" | "macos" => return shims::posix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, link_name_sym, abi, args, dest, ret), + "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, link_name_sym, abi, args, dest, ret), target => throw_unsup_format!("the target `{}` is not supported", target), } }; diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 15620c73f0da..68b648f32718 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -15,6 +15,7 @@ use log::trace; use rustc_ast::Mutability; use rustc_middle::{mir, ty}; +use rustc_span::Symbol; use rustc_target::spec::abi::Abi; use rustc_target::spec::PanicStrategy; @@ -40,6 +41,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// by libpanic_unwind to delegate the actual unwinding process to Miri. fn handle_miri_start_panic( &mut self, + abi: Abi, + link_name: Symbol, args: &[OpTy<'tcx, Tag>], unwind: StackPopUnwind, ) -> InterpResult<'tcx> { @@ -48,7 +51,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("miri_start_panic: {:?}", this.frame().instance); // Get the raw pointer stored in arg[0] (the panic payload). - let &[ref payload] = check_arg_count(args)?; + let &[ref payload] = this.check_shim(abi, Abi::Rust, link_name, args)?; let payload = this.read_scalar(payload)?.check_init()?; let thread = this.active_thread_mut(); assert!(thread.panic_payload.is_none(), "the panic runtime should avoid double-panics"); diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 2ecea4d9f41e..45e3d502a290 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -1,11 +1,11 @@ use log::trace; use rustc_middle::mir; +use rustc_span::Symbol; use rustc_target::abi::{Align, LayoutOf, Size}; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::check_arg_count; use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; use shims::posix::sync::EvalContextExt as _; @@ -16,6 +16,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_foreign_item_by_name( &mut self, link_name: &str, + link_name_sym: Symbol, abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, @@ -26,52 +27,45 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Environment related shims "getenv" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref name] = check_arg_count(args)?; + let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.getenv(name)?; this.write_scalar(result, dest)?; } "unsetenv" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref name] = check_arg_count(args)?; + let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.unsetenv(name)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "setenv" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref name, ref value, ref overwrite] = check_arg_count(args)?; + let &[ref name, ref value, ref overwrite] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.read_scalar(overwrite)?.to_i32()?; let result = this.setenv(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "getcwd" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref buf, ref size] = check_arg_count(args)?; + let &[ref buf, ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.getcwd(buf, size)?; this.write_scalar(result, dest)?; } "chdir" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref path] = check_arg_count(args)?; + let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.chdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // File related shims "open" | "open64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref path, ref flag, ref mode] = check_arg_count(args)?; + let &[ref path, ref flag, ref mode] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.open(path, flag, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fcntl" => { - this.check_abi(abi, Abi::C { unwind: false })?; + this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name_sym)?; let result = this.fcntl(args)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "read" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd, ref buf, ref count] = check_arg_count(args)?; + let &[ref fd, ref buf, ref count] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.check_init()?; let count = this.read_scalar(count)?.to_machine_usize(this)?; @@ -79,8 +73,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "write" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd, ref buf, ref n] = check_arg_count(args)?; + let &[ref fd, ref buf, ref n] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.check_init()?; let count = this.read_scalar(n)?.to_machine_usize(this)?; @@ -90,71 +83,60 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "unlink" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref path] = check_arg_count(args)?; + let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.unlink(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "symlink" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref target, ref linkpath] = check_arg_count(args)?; + let &[ref target, ref linkpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.symlink(target, linkpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rename" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref oldpath, ref newpath] = check_arg_count(args)?; + let &[ref oldpath, ref newpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.rename(oldpath, newpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mkdir" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref path, ref mode] = check_arg_count(args)?; + let &[ref path, ref mode] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.mkdir(path, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rmdir" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref path] = check_arg_count(args)?; + let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.rmdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "closedir" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref dirp] = check_arg_count(args)?; + let &[ref dirp] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.closedir(dirp)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lseek" | "lseek64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd, ref offset, ref whence] = check_arg_count(args)?; + let &[ref fd, ref offset, ref whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.lseek64(fd, offset, whence)?; // "lseek" is only used on macOS which is 64bit-only, so `i64` always works. this.write_scalar(Scalar::from_i64(result), dest)?; } "fsync" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd] = check_arg_count(args)?; + let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.fsync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fdatasync" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd] = check_arg_count(args)?; + let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.fdatasync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "readlink" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref pathname, ref buf, ref bufsize] = check_arg_count(args)?; + let &[ref pathname, ref buf, ref bufsize] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.readlink(pathname, buf, bufsize)?; this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } // Allocation "posix_memalign" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref ret, ref align, ref size] = check_arg_count(args)?; + let &[ref ret, ref align, ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let ret = this.deref_operand(ret)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; @@ -184,8 +166,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamic symbol loading "dlsym" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref handle, ref symbol] = check_arg_count(args)?; + let &[ref handle, ref symbol] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.read_scalar(handle)?.to_machine_usize(this)?; let symbol = this.read_scalar(symbol)?.check_init()?; let symbol_name = this.read_c_str(symbol)?; @@ -199,8 +180,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "sysconf" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref name] = check_arg_count(args)?; + let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let name = this.read_scalar(name)?.to_i32()?; let sysconfs = &[ @@ -225,8 +205,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "pthread_key_create" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref key, ref dtor] = check_arg_count(args)?; + let &[ref key, ref dtor] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let key_place = this.deref_operand(key)?; let dtor = this.read_scalar(dtor)?.check_init()?; @@ -254,24 +233,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_key_delete" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref key] = check_arg_count(args)?; + let &[ref key] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; this.machine.tls.delete_tls_key(key)?; // Return success (0) this.write_null(dest)?; } "pthread_getspecific" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref key] = check_arg_count(args)?; + let &[ref key] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref key, ref new_ptr] = check_arg_count(args)?; + let &[ref key, ref new_ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); let new_ptr = this.read_scalar(new_ptr)?.check_init()?; @@ -283,178 +259,149 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Synchronization primitives "pthread_mutexattr_init" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref attr] = check_arg_count(args)?; + let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_mutexattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_settype" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref attr, ref kind] = check_arg_count(args)?; + let &[ref attr, ref kind] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_mutexattr_settype(attr, kind)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_destroy" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref attr] = check_arg_count(args)?; + let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_mutexattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_init" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref mutex, ref attr] = check_arg_count(args)?; + let &[ref mutex, ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_mutex_init(mutex, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_lock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref mutex] = check_arg_count(args)?; + let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_mutex_lock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_trylock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref mutex] = check_arg_count(args)?; + let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_mutex_trylock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_unlock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref mutex] = check_arg_count(args)?; + let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_mutex_unlock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_destroy" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref mutex] = check_arg_count(args)?; + let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_mutex_destroy(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_rdlock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref rwlock] = check_arg_count(args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_rwlock_rdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_tryrdlock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref rwlock] = check_arg_count(args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_rwlock_tryrdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_wrlock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref rwlock] = check_arg_count(args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_rwlock_wrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_trywrlock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref rwlock] = check_arg_count(args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_rwlock_trywrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_unlock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref rwlock] = check_arg_count(args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_rwlock_unlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_destroy" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref rwlock] = check_arg_count(args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_rwlock_destroy(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_init" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref attr] = check_arg_count(args)?; + let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_condattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_destroy" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref attr] = check_arg_count(args)?; + let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_condattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_init" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref cond, ref attr] = check_arg_count(args)?; + let &[ref cond, ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_cond_init(cond, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_signal" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref cond] = check_arg_count(args)?; + let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_cond_signal(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_broadcast" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref cond] = check_arg_count(args)?; + let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_cond_broadcast(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_wait" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref cond, ref mutex] = check_arg_count(args)?; + let &[ref cond, ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_cond_wait(cond, mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_timedwait" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref cond, ref mutex, ref abstime] = check_arg_count(args)?; + let &[ref cond, ref mutex, ref abstime] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.pthread_cond_timedwait(cond, mutex, abstime, dest)?; } "pthread_cond_destroy" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref cond] = check_arg_count(args)?; + let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_cond_destroy(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Threading "pthread_create" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref thread, ref attr, ref start, ref arg] = check_arg_count(args)?; + let &[ref thread, ref attr, ref start, ref arg] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_create(thread, attr, start, arg)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_join" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref thread, ref retval] = check_arg_count(args)?; + let &[ref thread, ref retval] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_join(thread, retval)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_detach" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref thread] = check_arg_count(args)?; + let &[ref thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_detach(thread)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_self" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.pthread_self(dest)?; } "sched_yield" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.sched_yield()?; this.write_scalar(Scalar::from_i32(result), dest)?; } "nanosleep" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref req, ref rem] = check_arg_count(args)?; + let &[ref req, ref rem] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.nanosleep(req, rem)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Miscellaneous "isatty" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd] = check_arg_count(args)?; + let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.read_scalar(fd)?.to_i32()?; // "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error" // FIXME: we just say nothing is a terminal. @@ -463,8 +410,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_atfork" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref prepare, ref parent, ref child] = check_arg_count(args)?; + let &[ref prepare, ref parent, ref child] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.force_bits(this.read_scalar(prepare)?.check_init()?, this.memory.pointer_size())?; this.force_bits(this.read_scalar(parent)?.check_init()?, this.memory.pointer_size())?; this.force_bits(this.read_scalar(child)?.check_init()?, this.memory.pointer_size())?; @@ -476,8 +422,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These shims are enabled only when the caller is in the standard library. "pthread_attr_getguardsize" if this.frame_in_std() => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref _attr, ref guard_size] = check_arg_count(args)?; + let &[ref _attr, ref guard_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let guard_size = this.deref_operand(guard_size)?; let guard_size_layout = this.libc_ty_layout("size_t")?; this.write_scalar(Scalar::from_uint(crate::PAGE_SIZE, guard_size_layout.size), &guard_size.into())?; @@ -489,37 +434,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "pthread_attr_init" | "pthread_attr_destroy" if this.frame_in_std() => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[_] = check_arg_count(args)?; + let &[_] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.write_null(dest)?; } | "pthread_attr_setstacksize" if this.frame_in_std() => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[_, _] = check_arg_count(args)?; + let &[_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.write_null(dest)?; } | "signal" | "sigaltstack" if this.frame_in_std() => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[_, _] = check_arg_count(args)?; + let &[_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.write_null(dest)?; } | "sigaction" | "mprotect" if this.frame_in_std() => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[_, _, _] = check_arg_count(args)?; + let &[_, _, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.write_null(dest)?; } // Platform-specific shims _ => { match this.tcx.sess.target.os.as_str() { - "linux" => return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), - "macos" => return shims::posix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), + "linux" => return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, link_name_sym, abi, args, dest, ret), + "macos" => return shims::posix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, link_name_sym, abi, args, dest, ret), _ => unreachable!(), } } diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 68ae704fb04f..9af97103e07e 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -1,7 +1,7 @@ use rustc_middle::mir; +use rustc_span::Symbol; use rustc_target::spec::abi::Abi; -use crate::helpers::check_arg_count; use crate::*; use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; @@ -14,6 +14,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_foreign_item_by_name( &mut self, link_name: &str, + link_name_sym: Symbol, abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, @@ -24,8 +25,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // errno "__errno_location" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } @@ -34,33 +34,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These symbols have different names on Linux and macOS, which is the only reason they are not // in the `posix` module. "close" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd] = check_arg_count(args)?; + let &[ref fd] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.close(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref name] = check_arg_count(args)?; + let &[ref name] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir64_r" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref dirp, ref entry, ref result] = check_arg_count(args)?; + let &[ref dirp, ref entry, ref result] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.linux_readdir64_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd, ref length] = check_arg_count(args)?; + let &[ref fd, ref length] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Linux-only "posix_fadvise" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd, ref offset, ref len, ref advice] = check_arg_count(args)?; + let &[ref fd, ref offset, ref len, ref advice] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.read_scalar(fd)?.to_i32()?; this.read_scalar(offset)?.to_machine_isize(this)?; this.read_scalar(len)?.to_machine_isize(this)?; @@ -69,26 +69,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "sync_file_range" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd, ref offset, ref nbytes, ref flags] = check_arg_count(args)?; + let &[ref fd, ref offset, ref nbytes, ref flags] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.sync_file_range(fd, offset, nbytes, flags)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Time related shims "clock_gettime" => { - this.check_abi(abi, Abi::C { unwind: false })?; // This is a POSIX function but it has only been tested on linux. - let &[ref clk_id, ref tp] = check_arg_count(args)?; + let &[ref clk_id, ref tp] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.clock_gettime(clk_id, tp)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Querying system information "pthread_attr_getstack" => { - this.check_abi(abi, Abi::C { unwind: false })?; // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. - let &[ref attr_place, ref addr_place, ref size_place] = check_arg_count(args)?; + let &[ref attr_place, ref addr_place, ref size_place] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.deref_operand(attr_place)?; let addr_place = this.deref_operand(addr_place)?; let size_place = this.deref_operand(size_place)?; @@ -108,27 +108,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "prctl" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref option, ref arg2, ref arg3, ref arg4, ref arg5] = check_arg_count(args)?; + let &[ref option, ref arg2, ref arg3, ref arg4, ref arg5] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.prctl(option, arg2, arg3, arg4, arg5)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_setclock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref attr, ref clock_id] = check_arg_count(args)?; + let &[ref attr, ref clock_id] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_condattr_setclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_getclock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref attr, ref clock_id] = check_arg_count(args)?; + let &[ref attr, ref clock_id] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_condattr_getclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Dynamically invoked syscalls "syscall" => { - this.check_abi(abi, Abi::C { unwind: false })?; + this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name_sym)?; // The syscall variadic function is legal to call with more arguments than needed, // extra arguments are simply ignored. However, all arguments need to be scalars; // other types might be treated differently by the calling convention. @@ -192,13 +192,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscelanneous "getrandom" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref ptr, ref len, ref flags] = check_arg_count(args)?; + let &[ref ptr, ref len, ref flags] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; getrandom(this, ptr, len, flags, dest)?; } "sched_getaffinity" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref pid, ref cpusetsize, ref mask] = check_arg_count(args)?; + let &[ref pid, ref cpusetsize, ref mask] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.read_scalar(pid)?.to_i32()?; this.read_scalar(cpusetsize)?.to_machine_usize(this)?; this.deref_operand(mask)?; @@ -211,8 +211,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "pthread_getattr_np" if this.frame_in_std() => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref _thread, ref _attr] = check_arg_count(args)?; + let &[ref _thread, ref _attr] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.write_null(dest)?; } diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index 313d38c80b6f..37de757e9b8d 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -1,8 +1,8 @@ use rustc_middle::mir; +use rustc_span::Symbol; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::check_arg_count; use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; use shims::posix::thread::EvalContextExt as _; @@ -12,6 +12,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_foreign_item_by_name( &mut self, link_name: &str, + link_name_sym: Symbol, abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, @@ -22,100 +23,95 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // errno "__error" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } // File related shims "close" | "close$NOCANCEL" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref result] = check_arg_count(args)?; + let &[ref result] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.close(result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "stat" | "stat$INODE64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref path, ref buf] = check_arg_count(args)?; + let &[ref path, ref buf] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.macos_stat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lstat" | "lstat$INODE64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref path, ref buf] = check_arg_count(args)?; + let &[ref path, ref buf] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.macos_lstat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fstat" | "fstat$INODE64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd, ref buf] = check_arg_count(args)?; + let &[ref fd, ref buf] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.macos_fstat(fd, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" | "opendir$INODE64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref name] = check_arg_count(args)?; + let &[ref name] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir_r" | "readdir_r$INODE64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref dirp, ref entry, ref result] = check_arg_count(args)?; + let &[ref dirp, ref entry, ref result] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.macos_readdir_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd, ref length] = check_arg_count(args)?; + let &[ref fd, ref length] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Environment related shims "_NSGetEnviron" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.write_scalar(this.machine.env_vars.environ.unwrap().ptr, dest)?; } // Time related shims "gettimeofday" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref tv, ref tz] = check_arg_count(args)?; + let &[ref tv, ref tz] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.gettimeofday(tv, tz)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mach_absolute_time" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.mach_absolute_time()?; this.write_scalar(Scalar::from_u64(result), dest)?; } "mach_timebase_info" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref info] = check_arg_count(args)?; + let &[ref info] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.mach_timebase_info(info)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Access to command-line arguments "_NSGetArgc" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?; } "_NSGetArgv" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; } // Thread-local storage "_tlv_atexit" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref dtor, ref data] = check_arg_count(args)?; + let &[ref dtor, ref data] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let dtor = this.read_scalar(dtor)?.check_init()?; let dtor = this.memory.get_fn(dtor)?.as_instance()?; let data = this.read_scalar(data)?.check_init()?; @@ -125,15 +121,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_get_stackaddr_np" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref thread] = check_arg_count(args)?; + let &[ref thread] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size()); this.write_scalar(stack_addr, dest)?; } "pthread_get_stacksize_np" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref thread] = check_arg_count(args)?; + let &[ref thread] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size()); this.write_scalar(stack_size, dest)?; @@ -141,8 +137,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_setname_np" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref name] = check_arg_count(args)?; + let &[ref name] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let name = this.read_scalar(name)?.check_init()?; this.pthread_setname_np(name)?; } @@ -150,9 +146,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "mmap" if this.frame_in_std() => { - this.check_abi(abi, Abi::C { unwind: false })?; // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. - let &[ref addr, _, _, _, _, _] = check_arg_count(args)?; + let &[ref addr, _, _, _, _, _] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let addr = this.read_scalar(addr)?.check_init()?; this.write_scalar(addr, dest)?; } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 02f9bb8fff20..eaf1136669f1 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -1,11 +1,11 @@ use std::iter; use rustc_middle::mir; +use rustc_span::Symbol; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::check_arg_count; use shims::foreign_items::EmulateByNameResult; use shims::windows::sync::EvalContextExt as _; @@ -14,6 +14,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_foreign_item_by_name( &mut self, link_name: &str, + link_name_sym: Symbol, abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, @@ -29,55 +30,54 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Environment related shims "GetEnvironmentVariableW" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref name, ref buf, ref size] = check_arg_count(args)?; + let &[ref name, ref buf, ref size] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let result = this.GetEnvironmentVariableW(name, buf, size)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetEnvironmentVariableW" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref name, ref value] = check_arg_count(args)?; + let &[ref name, ref value] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let result = this.SetEnvironmentVariableW(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetEnvironmentStringsW" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let result = this.GetEnvironmentStringsW()?; this.write_scalar(result, dest)?; } "FreeEnvironmentStringsW" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref env_block] = check_arg_count(args)?; + let &[ref env_block] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let result = this.FreeEnvironmentStringsW(env_block)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetCurrentDirectoryW" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref size, ref buf] = check_arg_count(args)?; + let &[ref size, ref buf] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let result = this.GetCurrentDirectoryW(size, buf)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetCurrentDirectoryW" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref path] = check_arg_count(args)?; + let &[ref path] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let result = this.SetCurrentDirectoryW(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // File related shims "GetStdHandle" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref which] = check_arg_count(args)?; + let &[ref which] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let which = this.read_scalar(which)?.to_i32()?; // We just make this the identity function, so we know later in `WriteFile` // which one it is. this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?; } "WriteFile" => { - this.check_abi(abi, Abi::System { unwind: false })?; let &[ref handle, ref buf, ref n, ref written_ptr, ref overlapped] = - check_arg_count(args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore let handle = this.read_scalar(handle)?.to_machine_isize(this)?; let buf = this.read_scalar(buf)?.check_init()?; @@ -111,8 +111,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Allocation "HeapAlloc" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref handle, ref flags, ref size] = check_arg_count(args)?; + let &[ref handle, ref flags, ref size] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.read_scalar(handle)?.to_machine_isize(this)?; let flags = this.read_scalar(flags)?.to_u32()?; let size = this.read_scalar(size)?.to_machine_usize(this)?; @@ -121,8 +121,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } "HeapFree" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref handle, ref flags, ref ptr] = check_arg_count(args)?; + let &[ref handle, ref flags, ref ptr] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; let ptr = this.read_scalar(ptr)?.check_init()?; @@ -130,8 +130,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(1), dest)?; } "HeapReAlloc" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref handle, ref flags, ref ptr, ref size] = check_arg_count(args)?; + let &[ref handle, ref flags, ref ptr, ref size] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; let ptr = this.read_scalar(ptr)?.check_init()?; @@ -142,22 +142,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // errno "SetLastError" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref error] = check_arg_count(args)?; + let &[ref error] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let error = this.read_scalar(error)?.check_init()?; this.set_last_error(error)?; } "GetLastError" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let last_error = this.get_last_error()?; this.write_scalar(last_error, dest)?; } // Querying system information "GetSystemInfo" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref system_info] = check_arg_count(args)?; + let &[ref system_info] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let system_info = this.deref_operand(system_info)?; // Initialize with `0`. this.memory.write_bytes( @@ -172,25 +172,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "TlsAlloc" => { - this.check_abi(abi, Abi::System { unwind: false })?; // This just creates a key; Windows does not natively support TLS destructors. // Create key and return it. - let &[] = check_arg_count(args)?; + let &[] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let key = this.machine.tls.create_tls_key(None, dest.layout.size)?; this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref key] = check_arg_count(args)?; + let &[ref key] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "TlsSetValue" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref key, ref new_ptr] = check_arg_count(args)?; + let &[ref key, ref new_ptr] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); let new_ptr = this.read_scalar(new_ptr)?.check_init()?; @@ -202,8 +202,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Access to command-line arguments "GetCommandLineW" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.write_scalar( this.machine.cmd_line.expect("machine must be initialized"), dest, @@ -212,65 +212,65 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "GetSystemTimeAsFileTime" => { - this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] - let &[ref LPFILETIME] = check_arg_count(args)?; + let &[ref LPFILETIME] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.GetSystemTimeAsFileTime(LPFILETIME)?; } "QueryPerformanceCounter" => { - this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] - let &[ref lpPerformanceCount] = check_arg_count(args)?; + let &[ref lpPerformanceCount] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let result = this.QueryPerformanceCounter(lpPerformanceCount)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "QueryPerformanceFrequency" => { - this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] - let &[ref lpFrequency] = check_arg_count(args)?; + let &[ref lpFrequency] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let result = this.QueryPerformanceFrequency(lpFrequency)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Synchronization primitives "AcquireSRWLockExclusive" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref ptr] = check_arg_count(args)?; + let &[ref ptr] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.AcquireSRWLockExclusive(ptr)?; } "ReleaseSRWLockExclusive" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref ptr] = check_arg_count(args)?; + let &[ref ptr] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.ReleaseSRWLockExclusive(ptr)?; } "TryAcquireSRWLockExclusive" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref ptr] = check_arg_count(args)?; + let &[ref ptr] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let ret = this.TryAcquireSRWLockExclusive(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; } "AcquireSRWLockShared" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref ptr] = check_arg_count(args)?; + let &[ref ptr] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.AcquireSRWLockShared(ptr)?; } "ReleaseSRWLockShared" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref ptr] = check_arg_count(args)?; + let &[ref ptr] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.ReleaseSRWLockShared(ptr)?; } "TryAcquireSRWLockShared" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref ptr] = check_arg_count(args)?; + let &[ref ptr] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let ret = this.TryAcquireSRWLockShared(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; } // Dynamic symbol loading "GetProcAddress" => { - this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] - let &[ref hModule, ref lpProcName] = check_arg_count(args)?; + let &[ref hModule, ref lpProcName] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.read_scalar(hModule)?.to_machine_isize(this)?; let name = this.read_c_str(this.read_scalar(lpProcName)?.check_init()?)?; if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.os)? { @@ -284,16 +284,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscellaneous "SystemFunction036" => { // This is really 'RtlGenRandom'. - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref ptr, ref len] = check_arg_count(args)?; + let &[ref ptr, ref len] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_u32()?; this.gen_random(ptr, len.into())?; this.write_scalar(Scalar::from_bool(true), dest)?; } "BCryptGenRandom" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref algorithm, ref ptr, ref len, ref flags] = check_arg_count(args)?; + let &[ref algorithm, ref ptr, ref len, ref flags] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let algorithm = this.read_scalar(algorithm)?; let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_u32()?; @@ -313,9 +313,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; // STATUS_SUCCESS } "GetConsoleScreenBufferInfo" => { - this.check_abi(abi, Abi::System { unwind: false })?; // `term` needs this, so we fake it. - let &[ref console, ref buffer_info] = check_arg_count(args)?; + let &[ref console, ref buffer_info] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.read_scalar(console)?.to_machine_isize(this)?; this.deref_operand(buffer_info)?; // Indicate an error. @@ -323,9 +323,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "GetConsoleMode" => { - this.check_abi(abi, Abi::System { unwind: false })?; // Windows "isatty" (in libtest) needs this, so we fake it. - let &[ref console, ref mode] = check_arg_count(args)?; + let &[ref console, ref mode] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.read_scalar(console)?.to_machine_isize(this)?; this.deref_operand(mode)?; // Indicate an error. @@ -333,8 +333,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "SwitchToThread" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; // Note that once Miri supports concurrency, this will need to return a nonzero // value if this call does result in switching to another thread. this.write_null(dest)?; @@ -342,7 +342,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Better error for attempts to create a thread "CreateThread" => { - this.check_abi(abi, Abi::System { unwind: false })?; + this.check_abi_and_shim_symbol_clash( + abi, + Abi::System { unwind: false }, + link_name_sym, + )?; this.handle_unsupported("can't create threads on Windows")?; return Ok(EmulateByNameResult::AlreadyJumped); @@ -351,29 +355,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "GetProcessHeap" if this.frame_in_std() => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; // Just fake a HANDLE this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } "SetConsoleTextAttribute" if this.frame_in_std() => { - this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] - let &[ref _hConsoleOutput, ref _wAttribute] = check_arg_count(args)?; + let &[ref _hConsoleOutput, ref _wAttribute] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; // Pretend these does not exist / nothing happened, by returning zero. this.write_null(dest)?; } "AddVectoredExceptionHandler" if this.frame_in_std() => { - this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] - let &[ref _First, ref _Handler] = check_arg_count(args)?; + let &[ref _First, ref _Handler] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_machine_usize(1, this), dest)?; } "SetThreadStackGuarantee" if this.frame_in_std() => { - this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] - let &[_StackSizeInBytes] = check_arg_count(args)?; + let &[_StackSizeInBytes] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_u32(1), dest)?; } @@ -383,9 +387,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "DeleteCriticalSection" if this.frame_in_std() => { - this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] - let &[ref _lpCriticalSection] = check_arg_count(args)?; + let &[ref _lpCriticalSection] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; assert_eq!( this.get_total_thread_count(), 1, @@ -396,9 +400,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // so not doing any futher checks here is at least not incorrect.) } "TryEnterCriticalSection" if this.frame_in_std() => { - this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] - let &[ref _lpCriticalSection] = check_arg_count(args)?; + let &[ref _lpCriticalSection] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; assert_eq!( this.get_total_thread_count(), 1, diff --git a/tests/compile-fail/function_calls/exported_symbol_shim_clashing.rs b/tests/compile-fail/function_calls/exported_symbol_shim_clashing.rs new file mode 100644 index 000000000000..c46d57cee0dd --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_shim_clashing.rs @@ -0,0 +1,15 @@ +#[no_mangle] +extern "C" fn malloc(_: usize) -> *mut std::ffi::c_void { + //~^ HELP the `malloc` symbol is defined here + unreachable!() +} + +fn main() { + extern "C" { + fn malloc(_: usize) -> *mut std::ffi::c_void; + } + unsafe { + malloc(0); + //~^ ERROR found `malloc` symbol definition that clashes with a built-in shim + } +} From c822ec59aa817a5018b8058cc66c98e6effb7e9c Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Tue, 8 Jun 2021 20:36:57 +0800 Subject: [PATCH 2724/5092] Implement cache for not found symbols --- src/machine.rs | 3 ++- src/shims/foreign_items.rs | 11 ++++------- tests/run-pass/function_calls/exported_symbol.rs | 5 +++++ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 61871e745894..91a83a8acf40 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -297,7 +297,8 @@ pub struct Evaluator<'mir, 'tcx> { string_cache: FxHashMap, /// Cache of `Instance` exported under the given `Symbol` name. - pub(crate) exported_symbols_cache: FxHashMap>, + /// `None` means no `Instance` exported under the given name is found. + pub(crate) exported_symbols_cache: FxHashMap>>, /// Whether to raise a panic in the context of the evaluated process when unsupported /// functionality is encountered. If `false`, an error is propagated in the Miri application context diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index f193751518e1..380ddac6c86a 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -135,7 +135,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If the result was cached, just return it. if let Some(instance) = this.machine.exported_symbols_cache.get(&link_name) { - return Ok(Some(this.load_mir(instance.def, None)?)); + return instance.map(|instance| this.load_mir(instance.def, None)).transpose(); } // Find it if it was not cached. @@ -187,13 +187,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + let instance = instance_and_crate.map(|ic| ic.0); // Cache it and load its MIR, if found. - instance_and_crate - .map(|(instance, _)| { - this.machine.exported_symbols_cache.insert(link_name, instance); - this.load_mir(instance.def, None) - }) - .transpose() + this.machine.exported_symbols_cache.insert(link_name, instance); + instance.map(|instance| this.load_mir(instance.def, None)).transpose() } /// Emulates calling a foreign item, failing if the item is not supported. diff --git a/tests/run-pass/function_calls/exported_symbol.rs b/tests/run-pass/function_calls/exported_symbol.rs index c141f557e1d7..58115542332f 100644 --- a/tests/run-pass/function_calls/exported_symbol.rs +++ b/tests/run-pass/function_calls/exported_symbol.rs @@ -20,10 +20,15 @@ fn main() { for _ in 0..3 { extern "C" { fn foo() -> i32; + fn free(_: *mut std::ffi::c_void); } assert_eq!(unsafe { foo() }, -1); + // `free()` is a built-in shim, so calling it will add ("free", None) to the cache. + // Test that the cache is not broken with ("free", None). + unsafe { free(std::ptr::null_mut()) } + extern "Rust" { fn bar() -> i32; fn baz() -> i32; From e46aab5816e32316c33962939aa6e2bbcebd4c8c Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Fri, 11 Jun 2021 15:47:12 +0800 Subject: [PATCH 2725/5092] Use `check_shim()` for `abort` --- src/shims/foreign_items.rs | 7 ++----- .../function_calls/check_arg_count_abort.rs | 10 ++++++++++ 2 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 tests/compile-fail/function_calls/check_arg_count_abort.rs diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 380ddac6c86a..23824305c980 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -244,11 +244,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_machine_stop!(TerminationInfo::Exit(code.into())); } "abort" => { - this.check_abi_and_shim_symbol_clash( - abi, - Abi::C { unwind: false }, - link_name_sym, - )?; + let &[] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; throw_machine_stop!(TerminationInfo::Abort( "the program aborted execution".to_owned() )) diff --git a/tests/compile-fail/function_calls/check_arg_count_abort.rs b/tests/compile-fail/function_calls/check_arg_count_abort.rs new file mode 100644 index 000000000000..85e1b9deeb36 --- /dev/null +++ b/tests/compile-fail/function_calls/check_arg_count_abort.rs @@ -0,0 +1,10 @@ +fn main() { + extern "C" { + fn abort(_: i32) -> !; + } + + unsafe { + abort(1); + //~^ ERROR Undefined Behavior: incorrect number of arguments: got 1, expected 0 + } +} From 49a8f002a017a324bd3419950d26244cfe949e2f Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Fri, 11 Jun 2021 15:53:01 +0800 Subject: [PATCH 2726/5092] `let`-bind `exp_abi` of `"exit" | "ExitProcess"` --- src/shims/foreign_items.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 23824305c980..96edfcc9cf74 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -238,7 +238,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "exit" | "ExitProcess" => { - let &[ref code] = this.check_shim(abi, if link_name == "exit" { Abi::C { unwind: false } } else { Abi::System { unwind: false } }, link_name_sym, args)?; + let exp_abi = if link_name == "exit" { + Abi::C { unwind: false } + } else { + Abi::System { unwind: false } + }; + let &[ref code] = this.check_shim(abi, exp_abi, link_name_sym, args)?; // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway let code = this.read_scalar(code)?.to_i32()?; throw_machine_stop!(TerminationInfo::Exit(code.into())); From 99467349f2eb730ee90fabf758bc8068720ef392 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 13 Jun 2021 23:30:08 +0800 Subject: [PATCH 2727/5092] Do not return `DefId` that doesn't have exported symbol in `exported_symbols` --- src/bin/miri.rs | 29 ++++++++++++++++----- test-cargo-miri/Cargo.lock | 5 ++++ test-cargo-miri/Cargo.toml | 1 + test-cargo-miri/issue-rust-86261/Cargo.toml | 5 ++++ test-cargo-miri/issue-rust-86261/src/lib.rs | 23 ++++++++++++++++ 5 files changed, 56 insertions(+), 7 deletions(-) create mode 100644 test-cargo-miri/issue-rust-86261/Cargo.toml create mode 100644 test-cargo-miri/issue-rust-86261/src/lib.rs diff --git a/src/bin/miri.rs b/src/bin/miri.rs index fae45d9fc0ef..d593f24c71ab 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -19,7 +19,7 @@ use log::debug; use rustc_driver::Compilation; use rustc_errors::emitter::{ColorConfig, HumanReadableErrorType}; -use rustc_hir::def_id::LOCAL_CRATE; +use rustc_hir::{self as hir, def_id::LOCAL_CRATE, Node}; use rustc_interface::interface::Config; use rustc_middle::{ middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}, @@ -109,12 +109,27 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L62-L63 // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L174 tcx.reachable_set(()).iter().filter_map(|&local_def_id| { - tcx.codegen_fn_attrs(local_def_id) - .contains_extern_indicator() - .then_some(( - ExportedSymbol::NonGeneric(local_def_id.to_def_id()), - SymbolExportLevel::C, - )) + // Do the same filtering that rustc does: + // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L84-L102 + // Otherwise it may cause unexpected behaviours and ICEs + // (https://github.com/rust-lang/rust/issues/86261). + let is_reachable_non_generic = matches!( + tcx.hir().get(tcx.hir().local_def_id_to_hir_id(local_def_id)), + Node::Item(&hir::Item { + kind: hir::ItemKind::Static(..) | hir::ItemKind::Fn(..), + .. + }) | Node::ImplItem(&hir::ImplItem { + kind: hir::ImplItemKind::Fn(..), + .. + }) + if !tcx.generics_of(local_def_id).requires_monomorphization(tcx) + ); + (is_reachable_non_generic + && tcx.codegen_fn_attrs(local_def_id).contains_extern_indicator()) + .then_some(( + ExportedSymbol::NonGeneric(local_def_id.to_def_id()), + SymbolExportLevel::C, + )) }), ) } diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 9a9fa4797bf2..7f06fdf28dec 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -21,6 +21,7 @@ dependencies = [ "issue_1691", "issue_1705", "issue_1760", + "issue_rust_86261", "rand", "serde_derive", ] @@ -102,6 +103,10 @@ dependencies = [ name = "issue_1760" version = "0.1.0" +[[package]] +name = "issue_rust_86261" +version = "0.1.0" + [[package]] name = "libc" version = "0.2.92" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index cf557bd60ef3..39ce1757f0e4 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -15,6 +15,7 @@ issue_1567 = { path = "issue-1567" } issue_1691 = { path = "issue-1691" } issue_1705 = { path = "issue-1705" } issue_1760 = { path = "issue-1760" } +issue_rust_86261 = { path = "issue-rust-86261" } [dev-dependencies] rand = { version = "0.8", features = ["small_rng"] } diff --git a/test-cargo-miri/issue-rust-86261/Cargo.toml b/test-cargo-miri/issue-rust-86261/Cargo.toml new file mode 100644 index 000000000000..a6b65ebb5318 --- /dev/null +++ b/test-cargo-miri/issue-rust-86261/Cargo.toml @@ -0,0 +1,5 @@ +[package] +name = "issue_rust_86261" +version = "0.1.0" +authors = ["Miri Team"] +edition = "2018" diff --git a/test-cargo-miri/issue-rust-86261/src/lib.rs b/test-cargo-miri/issue-rust-86261/src/lib.rs new file mode 100644 index 000000000000..db725fdb64ed --- /dev/null +++ b/test-cargo-miri/issue-rust-86261/src/lib.rs @@ -0,0 +1,23 @@ +#![allow(unused_imports, unused_attributes, no_mangle_generic_items)] + +// Regression test for https://github.com/rust-lang/rust/issues/86261: +// `#[no_mangle]` on a `use` item. +#[no_mangle] +use std::{thread,panic, io, boxed, any, string}; + +// `#[no_mangle]` on a struct has a similar problem. +#[no_mangle] +pub struct NoMangleStruct; + +// If `#[no_mangle]` has effect on the `struct` above, calling `NoMangleStruct` will fail with +// "multiple definitions of symbol `NoMangleStruct`" error. +#[export_name = "NoMangleStruct"] +fn no_mangle_struct() {} + +// `#[no_mangle]` on a generic function can also cause ICEs. +#[no_mangle] +fn no_mangle_generic() {} + +// Same as `no_mangle_struct()` but for the `no_mangle_generic()` generic function. +#[export_name = "no_mangle_generic"] +fn no_mangle_generic2() {} From da2ed6f768452777c467a0d1e1a77fb92d9165c0 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Mon, 14 Jun 2021 20:56:03 +0800 Subject: [PATCH 2728/5092] Don't report UB for `#[no_mangle]` on associated functions --- src/shims/foreign_items.rs | 2 +- test-cargo-miri/exported-symbol-dep/src/lib.rs | 9 +++++++++ test-cargo-miri/src/main.rs | 7 +++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 8f3dfdc4f81f..bcb2d262e858 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -177,7 +177,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx second_crate: tcx.crate_name(cnum), }); } - if tcx.def_kind(def_id) != DefKind::Fn { + if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) { throw_ub_format!( "attempt to call an exported symbol that is not defined as a function" ); diff --git a/test-cargo-miri/exported-symbol-dep/src/lib.rs b/test-cargo-miri/exported-symbol-dep/src/lib.rs index 4cc18fb9b2fb..db257dcb22c4 100644 --- a/test-cargo-miri/exported-symbol-dep/src/lib.rs +++ b/test-cargo-miri/exported-symbol-dep/src/lib.rs @@ -2,3 +2,12 @@ fn exported_symbol() -> i32 { 123456 } + +pub struct AssocFn; + +impl AssocFn { + #[no_mangle] + pub fn assoc_fn_as_exported_symbol() -> i32 { + -123456 + } +} diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index a5669ef3087c..cb1512d05020 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -62,15 +62,22 @@ mod test { fn exported_symbol() { extern crate cargo_miri_test; extern crate exported_symbol; + extern crate issue_rust_86261; // Test calling exported symbols in (transitive) dependencies. // Repeat calls to make sure the `Instance` cache is not broken. for _ in 0..3 { extern "Rust" { fn exported_symbol() -> i32; + fn assoc_fn_as_exported_symbol() -> i32; fn make_true() -> bool; + fn NoMangleStruct(); + fn no_mangle_generic(); } assert_eq!(unsafe { exported_symbol() }, 123456); + assert_eq!(unsafe { assoc_fn_as_exported_symbol() }, -123456); assert!(unsafe { make_true() }); + unsafe { NoMangleStruct() } + unsafe { no_mangle_generic() } } } } From 89c722ac325a440bdd5f34befe2d28e23ec29d25 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Mon, 14 Jun 2021 22:53:17 +0800 Subject: [PATCH 2729/5092] Add some comments about `check_shim` --- src/shims/foreign_items.rs | 6 ++++++ src/shims/posix/foreign_items.rs | 2 ++ src/shims/posix/linux/foreign_items.rs | 2 ++ 3 files changed, 10 insertions(+) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 96edfcc9cf74..87906d877f8f 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -223,12 +223,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (dest, ret) = match ret { None => match link_name { "miri_start_panic" => { + // `check_shim` happens inside `handle_miri_start_panic`. this.handle_miri_start_panic(abi, link_name_sym, args, unwind)?; return Ok(None); } // This matches calls to the foreign item `panic_impl`. // The implementation is provided by the function with the `#[panic_handler]` attribute. "panic_impl" => { + // We don't use `check_shim` here because we are just forwarding to the lang + // item. Argument count checking will be performed when the returned `Body` is + // called. this.check_abi_and_shim_symbol_clash(abi, Abi::Rust, link_name_sym)?; let panic_impl_id = tcx.lang_items().panic_impl().unwrap(); let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id); @@ -317,11 +321,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Obtains a Miri backtrace. See the README for details. "miri_get_backtrace" => { + // `check_shim` happens inside `handle_miri_get_backtrace`. this.handle_miri_get_backtrace(abi, link_name_sym, args, dest)?; } // Resolves a Miri backtrace frame. See the README for details. "miri_resolve_frame" => { + // `check_shim` happens inside `handle_miri_resolve_frame`. this.handle_miri_resolve_frame(abi, link_name_sym, args, dest)?; } diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 45e3d502a290..2b8ea78bf3f1 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -60,6 +60,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "fcntl" => { + // `fcntl` is variadic. The argument count is checked based on the first argument + // in`this.fcntl()`, so we do not use `check_shim` here. this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name_sym)?; let result = this.fcntl(args)?; this.write_scalar(Scalar::from_i32(result), dest)?; diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 9af97103e07e..07d764a68e91 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -128,6 +128,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamically invoked syscalls "syscall" => { + // We do not use `check_shim` here because `syscall` is variadic. The argument + // count is checked bellow. this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name_sym)?; // The syscall variadic function is legal to call with more arguments than needed, // extra arguments are simply ignored. However, all arguments need to be scalars; From d1e72d0854587f3175c1720cda8180fd7878b4d0 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Mon, 14 Jun 2021 23:01:06 +0800 Subject: [PATCH 2730/5092] Check argument count for `CreateThread` --- src/shims/windows/foreign_items.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index eaf1136669f1..f12e4df8cdfe 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -342,11 +342,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Better error for attempts to create a thread "CreateThread" => { - this.check_abi_and_shim_symbol_clash( - abi, - Abi::System { unwind: false }, - link_name_sym, - )?; + let &[_, _, _, _, _, _] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.handle_unsupported("can't create threads on Windows")?; return Ok(EmulateByNameResult::AlreadyJumped); From 34603e586fc7fca3bb8e630be26e42350f758291 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Mon, 14 Jun 2021 23:38:15 +0800 Subject: [PATCH 2731/5092] Add whitespace --- src/shims/posix/foreign_items.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 2b8ea78bf3f1..ac26b39757a1 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -61,7 +61,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "fcntl" => { // `fcntl` is variadic. The argument count is checked based on the first argument - // in`this.fcntl()`, so we do not use `check_shim` here. + // in `this.fcntl()`, so we do not use `check_shim` here. this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name_sym)?; let result = this.fcntl(args)?; this.write_scalar(Scalar::from_i32(result), dest)?; From a67a65359f812a6970fc381bdd794b8f7792ce56 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Tue, 15 Jun 2021 00:43:15 +0800 Subject: [PATCH 2732/5092] Only pass `Symbol` to `emulate_foreign_item_by_name` --- src/helpers.rs | 5 + src/shims/foreign_items.rs | 69 ++++++------- src/shims/posix/foreign_items.rs | 132 ++++++++++++------------- src/shims/posix/linux/foreign_items.rs | 39 ++++---- src/shims/posix/macos/foreign_items.rs | 44 ++++----- src/shims/windows/foreign_items.rs | 92 ++++++++--------- 6 files changed, 190 insertions(+), 191 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index b99a446577ac..1a12d19e124e 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -723,6 +723,11 @@ where throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N) } +/// Strip linker suffixes (seen on 32-bit macOS). +pub fn strip_linker_suffix(link_name: &str) -> &str { + link_name.trim_end_matches("$UNIX2003") +} + pub fn isolation_abort_error(name: &str) -> InterpResult<'static> { throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!( "{} not available when isolation is enabled", diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 87906d877f8f..36d075e32dff 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -25,6 +25,7 @@ use rustc_target::{ use super::backtrace::EvalContextExt as _; use crate::*; +use helpers::strip_linker_suffix; /// Returned by `emulate_foreign_item_by_name`. pub enum EmulateByNameResult { @@ -215,8 +216,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .first_attr_value_str_by_name(&attrs, sym::link_name) .unwrap_or_else(|| this.tcx.item_name(def_id)); let link_name = link_name_sym.as_str(); - // Strip linker suffixes (seen on 32-bit macOS). - let link_name = link_name.trim_end_matches("$UNIX2003"); + let link_name = strip_linker_suffix(&link_name); let tcx = this.tcx.tcx; // First: functions that diverge. @@ -274,7 +274,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Second: functions that return. - match this.emulate_foreign_item_by_name(link_name, link_name_sym, abi, args, dest, ret)? { + match this.emulate_foreign_item_by_name(link_name_sym, abi, args, dest, ret)? { EmulateByNameResult::NeedsJumping => { trace!("{:?}", this.dump_place(**dest)); this.go_to_block(ret); @@ -296,8 +296,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Emulates calling a foreign item using its name. fn emulate_foreign_item_by_name( &mut self, - link_name: &str, - link_name_sym: Symbol, + link_name: Symbol, abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, @@ -307,10 +306,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Here we dispatch all the shims for foreign functions. If you have a platform specific // shim, add it to the corresponding submodule. - match link_name { + let shim_name = link_name.as_str(); + let shim_name = strip_linker_suffix(&shim_name); + match shim_name { // Miri-specific extern functions "miri_static_root" => { - let &[ref ptr] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?; + let &[ref ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let ptr = this.force_ptr(ptr)?; if ptr.offset != Size::ZERO { @@ -322,25 +323,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Obtains a Miri backtrace. See the README for details. "miri_get_backtrace" => { // `check_shim` happens inside `handle_miri_get_backtrace`. - this.handle_miri_get_backtrace(abi, link_name_sym, args, dest)?; + this.handle_miri_get_backtrace(abi, link_name, args, dest)?; } // Resolves a Miri backtrace frame. See the README for details. "miri_resolve_frame" => { // `check_shim` happens inside `handle_miri_resolve_frame`. - this.handle_miri_resolve_frame(abi, link_name_sym, args, dest)?; + this.handle_miri_resolve_frame(abi, link_name, args, dest)?; } // Standard C allocation "malloc" => { - let &[ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C); this.write_scalar(res, dest)?; } "calloc" => { - let &[ref items, ref len] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref items, ref len] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let items = this.read_scalar(items)?.to_machine_usize(this)?; let len = this.read_scalar(len)?.to_machine_usize(this)?; let size = @@ -349,12 +350,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } "free" => { - let &[ref ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; this.free(ptr, MiriMemoryKind::C)?; } "realloc" => { - let &[ref old_ptr, ref new_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref old_ptr, ref new_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let old_ptr = this.read_scalar(old_ptr)?.check_init()?; let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; let res = this.realloc(old_ptr, new_size, MiriMemoryKind::C)?; @@ -365,7 +366,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // (Usually these would be forwarded to to `#[global_allocator]`; we instead implement a generic // allocation that also checks that all conditions are met, such as not permitting zero-sized allocations.) "__rust_alloc" => { - let &[ref size, ref align] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?; + let &[ref size, ref align] = this.check_shim(abi, Abi::Rust, link_name, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; Self::check_alloc_request(size, align)?; @@ -377,7 +378,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "__rust_alloc_zeroed" => { - let &[ref size, ref align] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?; + let &[ref size, ref align] = this.check_shim(abi, Abi::Rust, link_name, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; Self::check_alloc_request(size, align)?; @@ -391,7 +392,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "__rust_dealloc" => { - let &[ref ptr, ref old_size, ref align] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?; + let &[ref ptr, ref old_size, ref align] = this.check_shim(abi, Abi::Rust, link_name, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -404,7 +405,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; } "__rust_realloc" => { - let &[ref ptr, ref old_size, ref align, ref new_size] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?; + let &[ref ptr, ref old_size, ref align, ref new_size] = this.check_shim(abi, Abi::Rust, link_name, args)?; let ptr = this.force_ptr(this.read_scalar(ptr)?.check_init()?)?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -424,7 +425,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // C memory handling functions "memcmp" => { - let &[ref left, ref right, ref n] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref left, ref right, ref n] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let left = this.read_scalar(left)?.check_init()?; let right = this.read_scalar(right)?.check_init()?; let n = Size::from_bytes(this.read_scalar(n)?.to_machine_usize(this)?); @@ -444,7 +445,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "memrchr" => { - let &[ref ptr, ref val, ref num] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref ptr, ref val, ref num] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; @@ -462,7 +463,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "memchr" => { - let &[ref ptr, ref val, ref num] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref ptr, ref val, ref num] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; @@ -479,7 +480,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "strlen" => { - let &[ref ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let n = this.read_c_str(ptr)?.len(); this.write_scalar(Scalar::from_machine_usize(u64::try_from(n).unwrap(), this), dest)?; @@ -495,10 +496,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asinf" | "atanf" => { - let &[ref f] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); - let f = match link_name { + let f = match shim_name { "cbrtf" => f.cbrt(), "coshf" => f.cosh(), "sinhf" => f.sinh(), @@ -515,13 +516,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypotf" | "atan2f" => { - let &[ref f1, ref f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref f1, ref f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // underscore case for windows, here and below // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) // FIXME: Using host floats. let f1 = f32::from_bits(this.read_scalar(f1)?.to_u32()?); let f2 = f32::from_bits(this.read_scalar(f2)?.to_u32()?); - let n = match link_name { + let n = match shim_name { "_hypotf" | "hypotf" => f1.hypot(f2), "atan2f" => f1.atan2(f2), _ => bug!(), @@ -537,10 +538,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asin" | "atan" => { - let &[ref f] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); - let f = match link_name { + let f = match shim_name { "cbrt" => f.cbrt(), "cosh" => f.cosh(), "sinh" => f.sinh(), @@ -557,11 +558,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypot" | "atan2" => { - let &[ref f1, ref f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref f1, ref f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?); let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?); - let n = match link_name { + let n = match shim_name { "_hypot" | "hypot" => f1.hypot(f2), "atan2" => f1.atan2(f2), _ => bug!(), @@ -573,7 +574,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "ldexp" | "scalbn" => { - let &[ref x, ref exp] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref x, ref exp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. let x = this.read_scalar(x)?.to_f64()?; let exp = this.read_scalar(exp)?.to_i32()?; @@ -594,11 +595,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Architecture-specific shims "llvm.x86.sse2.pause" if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.yield_active_thread(); } "llvm.aarch64.isb" if this.tcx.sess.target.arch == "aarch64" => { - let &[ref arg] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref arg] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let arg = this.read_scalar(arg)?.to_i32()?; match arg { 15 => { // SY ("full system scope") @@ -612,8 +613,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Platform-specific shims _ => match this.tcx.sess.target.os.as_str() { - "linux" | "macos" => return shims::posix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, link_name_sym, abi, args, dest, ret), - "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, link_name_sym, abi, args, dest, ret), + "linux" | "macos" => return shims::posix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), + "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), target => throw_unsup_format!("the target `{}` is not supported", target), } }; diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index ac26b39757a1..2585b562f230 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -6,6 +6,7 @@ use rustc_target::abi::{Align, LayoutOf, Size}; use rustc_target::spec::abi::Abi; use crate::*; +use helpers::strip_linker_suffix; use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; use shims::posix::sync::EvalContextExt as _; @@ -15,8 +16,7 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn emulate_foreign_item_by_name( &mut self, - link_name: &str, - link_name_sym: Symbol, + link_name: Symbol, abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, @@ -24,50 +24,50 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult> { let this = self.eval_context_mut(); - match link_name { + match strip_linker_suffix(&link_name.as_str()) { // Environment related shims "getenv" => { - let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.getenv(name)?; this.write_scalar(result, dest)?; } "unsetenv" => { - let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.unsetenv(name)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "setenv" => { - let &[ref name, ref value, ref overwrite] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref name, ref value, ref overwrite] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(overwrite)?.to_i32()?; let result = this.setenv(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "getcwd" => { - let &[ref buf, ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref buf, ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.getcwd(buf, size)?; this.write_scalar(result, dest)?; } "chdir" => { - let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.chdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // File related shims "open" | "open64" => { - let &[ref path, ref flag, ref mode] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref path, ref flag, ref mode] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.open(path, flag, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fcntl" => { // `fcntl` is variadic. The argument count is checked based on the first argument // in `this.fcntl()`, so we do not use `check_shim` here. - this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name_sym)?; + this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?; let result = this.fcntl(args)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "read" => { - let &[ref fd, ref buf, ref count] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref fd, ref buf, ref count] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.check_init()?; let count = this.read_scalar(count)?.to_machine_usize(this)?; @@ -75,7 +75,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "write" => { - let &[ref fd, ref buf, ref n] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref fd, ref buf, ref n] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.check_init()?; let count = this.read_scalar(n)?.to_machine_usize(this)?; @@ -85,60 +85,60 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "unlink" => { - let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.unlink(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "symlink" => { - let &[ref target, ref linkpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref target, ref linkpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.symlink(target, linkpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rename" => { - let &[ref oldpath, ref newpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref oldpath, ref newpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.rename(oldpath, newpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mkdir" => { - let &[ref path, ref mode] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref path, ref mode] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.mkdir(path, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rmdir" => { - let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.rmdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "closedir" => { - let &[ref dirp] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref dirp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.closedir(dirp)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lseek" | "lseek64" => { - let &[ref fd, ref offset, ref whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref fd, ref offset, ref whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.lseek64(fd, offset, whence)?; // "lseek" is only used on macOS which is 64bit-only, so `i64` always works. this.write_scalar(Scalar::from_i64(result), dest)?; } "fsync" => { - let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.fsync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fdatasync" => { - let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.fdatasync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "readlink" => { - let &[ref pathname, ref buf, ref bufsize] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref pathname, ref buf, ref bufsize] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.readlink(pathname, buf, bufsize)?; this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } // Allocation "posix_memalign" => { - let &[ref ret, ref align, ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref ret, ref align, ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let ret = this.deref_operand(ret)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; @@ -168,7 +168,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamic symbol loading "dlsym" => { - let &[ref handle, ref symbol] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref handle, ref symbol] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(handle)?.to_machine_usize(this)?; let symbol = this.read_scalar(symbol)?.check_init()?; let symbol_name = this.read_c_str(symbol)?; @@ -182,7 +182,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "sysconf" => { - let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let name = this.read_scalar(name)?.to_i32()?; let sysconfs = &[ @@ -207,7 +207,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "pthread_key_create" => { - let &[ref key, ref dtor] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref key, ref dtor] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let key_place = this.deref_operand(key)?; let dtor = this.read_scalar(dtor)?.check_init()?; @@ -235,21 +235,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_key_delete" => { - let &[ref key] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref key] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; this.machine.tls.delete_tls_key(key)?; // Return success (0) this.write_null(dest)?; } "pthread_getspecific" => { - let &[ref key] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref key] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { - let &[ref key, ref new_ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref key, ref new_ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); let new_ptr = this.read_scalar(new_ptr)?.check_init()?; @@ -261,149 +261,149 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Synchronization primitives "pthread_mutexattr_init" => { - let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutexattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_settype" => { - let &[ref attr, ref kind] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref attr, ref kind] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutexattr_settype(attr, kind)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_destroy" => { - let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutexattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_init" => { - let &[ref mutex, ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref mutex, ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutex_init(mutex, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_lock" => { - let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutex_lock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_trylock" => { - let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutex_trylock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_unlock" => { - let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutex_unlock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_destroy" => { - let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutex_destroy(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_rdlock" => { - let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_rwlock_rdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_tryrdlock" => { - let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_rwlock_tryrdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_wrlock" => { - let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_rwlock_wrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_trywrlock" => { - let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_rwlock_trywrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_unlock" => { - let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_rwlock_unlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_destroy" => { - let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_rwlock_destroy(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_init" => { - let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_condattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_destroy" => { - let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_condattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_init" => { - let &[ref cond, ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref cond, ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_cond_init(cond, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_signal" => { - let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_cond_signal(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_broadcast" => { - let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_cond_broadcast(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_wait" => { - let &[ref cond, ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref cond, ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_cond_wait(cond, mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_timedwait" => { - let &[ref cond, ref mutex, ref abstime] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref cond, ref mutex, ref abstime] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.pthread_cond_timedwait(cond, mutex, abstime, dest)?; } "pthread_cond_destroy" => { - let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_cond_destroy(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Threading "pthread_create" => { - let &[ref thread, ref attr, ref start, ref arg] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref thread, ref attr, ref start, ref arg] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_create(thread, attr, start, arg)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_join" => { - let &[ref thread, ref retval] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref thread, ref retval] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_join(thread, retval)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_detach" => { - let &[ref thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_detach(thread)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_self" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.pthread_self(dest)?; } "sched_yield" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.sched_yield()?; this.write_scalar(Scalar::from_i32(result), dest)?; } "nanosleep" => { - let &[ref req, ref rem] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref req, ref rem] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.nanosleep(req, rem)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Miscellaneous "isatty" => { - let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(fd)?.to_i32()?; // "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error" // FIXME: we just say nothing is a terminal. @@ -412,7 +412,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_atfork" => { - let &[ref prepare, ref parent, ref child] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref prepare, ref parent, ref child] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.force_bits(this.read_scalar(prepare)?.check_init()?, this.memory.pointer_size())?; this.force_bits(this.read_scalar(parent)?.check_init()?, this.memory.pointer_size())?; this.force_bits(this.read_scalar(child)?.check_init()?, this.memory.pointer_size())?; @@ -424,7 +424,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These shims are enabled only when the caller is in the standard library. "pthread_attr_getguardsize" if this.frame_in_std() => { - let &[ref _attr, ref guard_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref _attr, ref guard_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let guard_size = this.deref_operand(guard_size)?; let guard_size_layout = this.libc_ty_layout("size_t")?; this.write_scalar(Scalar::from_uint(crate::PAGE_SIZE, guard_size_layout.size), &guard_size.into())?; @@ -436,33 +436,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "pthread_attr_init" | "pthread_attr_destroy" if this.frame_in_std() => { - let &[_] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[_] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_null(dest)?; } | "pthread_attr_setstacksize" if this.frame_in_std() => { - let &[_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_null(dest)?; } | "signal" | "sigaltstack" if this.frame_in_std() => { - let &[_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_null(dest)?; } | "sigaction" | "mprotect" if this.frame_in_std() => { - let &[_, _, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[_, _, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_null(dest)?; } // Platform-specific shims _ => { match this.tcx.sess.target.os.as_str() { - "linux" => return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, link_name_sym, abi, args, dest, ret), - "macos" => return shims::posix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, link_name_sym, abi, args, dest, ret), + "linux" => return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), + "macos" => return shims::posix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), _ => unreachable!(), } } diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 07d764a68e91..160e27f395e5 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -3,6 +3,7 @@ use rustc_span::Symbol; use rustc_target::spec::abi::Abi; use crate::*; +use helpers::strip_linker_suffix; use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; use shims::posix::linux::sync::futex; @@ -13,8 +14,7 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn emulate_foreign_item_by_name( &mut self, - link_name: &str, - link_name_sym: Symbol, + link_name: Symbol, abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, @@ -22,10 +22,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult> { let this = self.eval_context_mut(); - match link_name { + match strip_linker_suffix(&link_name.as_str()) { // errno "__errno_location" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } @@ -34,33 +34,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These symbols have different names on Linux and macOS, which is the only reason they are not // in the `posix` module. "close" => { - let &[ref fd] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.close(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" => { let &[ref name] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir64_r" => { let &[ref dirp, ref entry, ref result] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.linux_readdir64_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate64" => { let &[ref fd, ref length] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Linux-only "posix_fadvise" => { let &[ref fd, ref offset, ref len, ref advice] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(fd)?.to_i32()?; this.read_scalar(offset)?.to_machine_isize(this)?; this.read_scalar(len)?.to_machine_isize(this)?; @@ -70,7 +69,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "sync_file_range" => { let &[ref fd, ref offset, ref nbytes, ref flags] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.sync_file_range(fd, offset, nbytes, flags)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -79,7 +78,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "clock_gettime" => { // This is a POSIX function but it has only been tested on linux. let &[ref clk_id, ref tp] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.clock_gettime(clk_id, tp)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -88,7 +87,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "pthread_attr_getstack" => { // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. let &[ref attr_place, ref addr_place, ref size_place] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.deref_operand(attr_place)?; let addr_place = this.deref_operand(addr_place)?; let size_place = this.deref_operand(size_place)?; @@ -109,19 +108,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "prctl" => { let &[ref option, ref arg2, ref arg3, ref arg4, ref arg5] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.prctl(option, arg2, arg3, arg4, arg5)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_setclock" => { let &[ref attr, ref clock_id] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_condattr_setclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_getclock" => { let &[ref attr, ref clock_id] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_condattr_getclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -130,7 +129,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "syscall" => { // We do not use `check_shim` here because `syscall` is variadic. The argument // count is checked bellow. - this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name_sym)?; + this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?; // The syscall variadic function is legal to call with more arguments than needed, // extra arguments are simply ignored. However, all arguments need to be scalars; // other types might be treated differently by the calling convention. @@ -195,12 +194,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscelanneous "getrandom" => { let &[ref ptr, ref len, ref flags] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; getrandom(this, ptr, len, flags, dest)?; } "sched_getaffinity" => { let &[ref pid, ref cpusetsize, ref mask] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(pid)?.to_i32()?; this.read_scalar(cpusetsize)?.to_machine_usize(this)?; this.deref_operand(mask)?; @@ -214,7 +213,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These shims are enabled only when the caller is in the standard library. "pthread_getattr_np" if this.frame_in_std() => { let &[ref _thread, ref _attr] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_null(dest)?; } diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index 37de757e9b8d..45d6f5b44953 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -3,6 +3,7 @@ use rustc_span::Symbol; use rustc_target::spec::abi::Abi; use crate::*; +use helpers::strip_linker_suffix; use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; use shims::posix::thread::EvalContextExt as _; @@ -11,8 +12,7 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn emulate_foreign_item_by_name( &mut self, - link_name: &str, - link_name_sym: Symbol, + link_name: Symbol, abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, @@ -20,10 +20,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult> { let this = self.eval_context_mut(); - match link_name { + match strip_linker_suffix(&link_name.as_str()) { // errno "__error" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } @@ -31,87 +31,87 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "close" | "close$NOCANCEL" => { let &[ref result] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.close(result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "stat" | "stat$INODE64" => { let &[ref path, ref buf] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_stat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lstat" | "lstat$INODE64" => { let &[ref path, ref buf] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_lstat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fstat" | "fstat$INODE64" => { let &[ref fd, ref buf] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_fstat(fd, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" | "opendir$INODE64" => { let &[ref name] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir_r" | "readdir_r$INODE64" => { let &[ref dirp, ref entry, ref result] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_readdir_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate" => { let &[ref fd, ref length] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Environment related shims "_NSGetEnviron" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_scalar(this.machine.env_vars.environ.unwrap().ptr, dest)?; } // Time related shims "gettimeofday" => { let &[ref tv, ref tz] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.gettimeofday(tv, tz)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mach_absolute_time" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.mach_absolute_time()?; this.write_scalar(Scalar::from_u64(result), dest)?; } "mach_timebase_info" => { let &[ref info] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.mach_timebase_info(info)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Access to command-line arguments "_NSGetArgc" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?; } "_NSGetArgv" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; } // Thread-local storage "_tlv_atexit" => { let &[ref dtor, ref data] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let dtor = this.read_scalar(dtor)?.check_init()?; let dtor = this.memory.get_fn(dtor)?.as_instance()?; let data = this.read_scalar(data)?.check_init()?; @@ -122,14 +122,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_get_stackaddr_np" => { let &[ref thread] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size()); this.write_scalar(stack_addr, dest)?; } "pthread_get_stacksize_np" => { let &[ref thread] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size()); this.write_scalar(stack_size, dest)?; @@ -138,7 +138,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_setname_np" => { let &[ref name] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let name = this.read_scalar(name)?.check_init()?; this.pthread_setname_np(name)?; } @@ -148,7 +148,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "mmap" if this.frame_in_std() => { // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. let &[ref addr, _, _, _, _, _] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let addr = this.read_scalar(addr)?.check_init()?; this.write_scalar(addr, dest)?; } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index f12e4df8cdfe..77f807536141 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -6,6 +6,7 @@ use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; use crate::*; +use helpers::strip_linker_suffix; use shims::foreign_items::EmulateByNameResult; use shims::windows::sync::EvalContextExt as _; @@ -13,8 +14,7 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn emulate_foreign_item_by_name( &mut self, - link_name: &str, - link_name_sym: Symbol, + link_name: Symbol, abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, @@ -27,41 +27,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // DWORD = ULONG = u32 // BOOL = i32 // BOOLEAN = u8 - match link_name { + match strip_linker_suffix(&link_name.as_str()) { // Environment related shims "GetEnvironmentVariableW" => { let &[ref name, ref buf, ref size] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.GetEnvironmentVariableW(name, buf, size)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetEnvironmentVariableW" => { let &[ref name, ref value] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.SetEnvironmentVariableW(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetEnvironmentStringsW" => { - let &[] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.GetEnvironmentStringsW()?; this.write_scalar(result, dest)?; } "FreeEnvironmentStringsW" => { let &[ref env_block] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.FreeEnvironmentStringsW(env_block)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetCurrentDirectoryW" => { let &[ref size, ref buf] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.GetCurrentDirectoryW(size, buf)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetCurrentDirectoryW" => { let &[ref path] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.SetCurrentDirectoryW(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -69,7 +68,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "GetStdHandle" => { let &[ref which] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let which = this.read_scalar(which)?.to_i32()?; // We just make this the identity function, so we know later in `WriteFile` // which one it is. @@ -77,7 +76,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "WriteFile" => { let &[ref handle, ref buf, ref n, ref written_ptr, ref overlapped] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore let handle = this.read_scalar(handle)?.to_machine_isize(this)?; let buf = this.read_scalar(buf)?.check_init()?; @@ -112,7 +111,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Allocation "HeapAlloc" => { let &[ref handle, ref flags, ref size] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(handle)?.to_machine_isize(this)?; let flags = this.read_scalar(flags)?.to_u32()?; let size = this.read_scalar(size)?.to_machine_usize(this)?; @@ -122,7 +121,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "HeapFree" => { let &[ref handle, ref flags, ref ptr] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; let ptr = this.read_scalar(ptr)?.check_init()?; @@ -131,7 +130,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "HeapReAlloc" => { let &[ref handle, ref flags, ref ptr, ref size] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; let ptr = this.read_scalar(ptr)?.check_init()?; @@ -143,13 +142,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // errno "SetLastError" => { let &[ref error] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let error = this.read_scalar(error)?.check_init()?; this.set_last_error(error)?; } "GetLastError" => { - let &[] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let last_error = this.get_last_error()?; this.write_scalar(last_error, dest)?; } @@ -157,7 +155,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "GetSystemInfo" => { let &[ref system_info] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let system_info = this.deref_operand(system_info)?; // Initialize with `0`. this.memory.write_bytes( @@ -175,14 +173,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This just creates a key; Windows does not natively support TLS destructors. // Create key and return it. - let &[] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let key = this.machine.tls.create_tls_key(None, dest.layout.size)?; this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { let &[ref key] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; @@ -190,7 +187,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "TlsSetValue" => { let &[ref key, ref new_ptr] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); let new_ptr = this.read_scalar(new_ptr)?.check_init()?; @@ -202,8 +199,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Access to command-line arguments "GetCommandLineW" => { - let &[] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.write_scalar( this.machine.cmd_line.expect("machine must be initialized"), dest, @@ -214,20 +210,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "GetSystemTimeAsFileTime" => { #[allow(non_snake_case)] let &[ref LPFILETIME] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.GetSystemTimeAsFileTime(LPFILETIME)?; } "QueryPerformanceCounter" => { #[allow(non_snake_case)] let &[ref lpPerformanceCount] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.QueryPerformanceCounter(lpPerformanceCount)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "QueryPerformanceFrequency" => { #[allow(non_snake_case)] let &[ref lpFrequency] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.QueryPerformanceFrequency(lpFrequency)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -235,33 +231,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Synchronization primitives "AcquireSRWLockExclusive" => { let &[ref ptr] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.AcquireSRWLockExclusive(ptr)?; } "ReleaseSRWLockExclusive" => { let &[ref ptr] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.ReleaseSRWLockExclusive(ptr)?; } "TryAcquireSRWLockExclusive" => { let &[ref ptr] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let ret = this.TryAcquireSRWLockExclusive(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; } "AcquireSRWLockShared" => { let &[ref ptr] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.AcquireSRWLockShared(ptr)?; } "ReleaseSRWLockShared" => { let &[ref ptr] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.ReleaseSRWLockShared(ptr)?; } "TryAcquireSRWLockShared" => { let &[ref ptr] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let ret = this.TryAcquireSRWLockShared(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; } @@ -270,7 +266,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "GetProcAddress" => { #[allow(non_snake_case)] let &[ref hModule, ref lpProcName] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(hModule)?.to_machine_isize(this)?; let name = this.read_c_str(this.read_scalar(lpProcName)?.check_init()?)?; if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.os)? { @@ -285,7 +281,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "SystemFunction036" => { // This is really 'RtlGenRandom'. let &[ref ptr, ref len] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_u32()?; this.gen_random(ptr, len.into())?; @@ -293,7 +289,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "BCryptGenRandom" => { let &[ref algorithm, ref ptr, ref len, ref flags] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let algorithm = this.read_scalar(algorithm)?; let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_u32()?; @@ -315,7 +311,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "GetConsoleScreenBufferInfo" => { // `term` needs this, so we fake it. let &[ref console, ref buffer_info] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(console)?.to_machine_isize(this)?; this.deref_operand(buffer_info)?; // Indicate an error. @@ -325,7 +321,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "GetConsoleMode" => { // Windows "isatty" (in libtest) needs this, so we fake it. let &[ref console, ref mode] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(console)?.to_machine_isize(this)?; this.deref_operand(mode)?; // Indicate an error. @@ -333,8 +329,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "SwitchToThread" => { - let &[] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; // Note that once Miri supports concurrency, this will need to return a nonzero // value if this call does result in switching to another thread. this.write_null(dest)?; @@ -343,7 +338,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Better error for attempts to create a thread "CreateThread" => { let &[_, _, _, _, _, _] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.handle_unsupported("can't create threads on Windows")?; return Ok(EmulateByNameResult::AlreadyJumped); @@ -352,29 +347,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "GetProcessHeap" if this.frame_in_std() => { - let &[] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; // Just fake a HANDLE this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } "SetConsoleTextAttribute" if this.frame_in_std() => { #[allow(non_snake_case)] let &[ref _hConsoleOutput, ref _wAttribute] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; // Pretend these does not exist / nothing happened, by returning zero. this.write_null(dest)?; } "AddVectoredExceptionHandler" if this.frame_in_std() => { #[allow(non_snake_case)] let &[ref _First, ref _Handler] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_machine_usize(1, this), dest)?; } "SetThreadStackGuarantee" if this.frame_in_std() => { #[allow(non_snake_case)] let &[_StackSizeInBytes] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_u32(1), dest)?; } @@ -386,7 +380,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx { #[allow(non_snake_case)] let &[ref _lpCriticalSection] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; assert_eq!( this.get_total_thread_count(), 1, @@ -399,7 +393,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "TryEnterCriticalSection" if this.frame_in_std() => { #[allow(non_snake_case)] let &[ref _lpCriticalSection] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; assert_eq!( this.get_total_thread_count(), 1, From 9011524454aff19110a3efc1cd3bb68657a0f8ee Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Tue, 15 Jun 2021 01:16:38 +0800 Subject: [PATCH 2733/5092] Remove `strip_linker_suffix` --- src/helpers.rs | 5 ----- src/shims/foreign_items.rs | 16 ++++++---------- src/shims/posix/foreign_items.rs | 3 +-- src/shims/posix/linux/foreign_items.rs | 3 +-- src/shims/posix/macos/foreign_items.rs | 3 +-- src/shims/windows/foreign_items.rs | 3 +-- 6 files changed, 10 insertions(+), 23 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 1a12d19e124e..b99a446577ac 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -723,11 +723,6 @@ where throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N) } -/// Strip linker suffixes (seen on 32-bit macOS). -pub fn strip_linker_suffix(link_name: &str) -> &str { - link_name.trim_end_matches("$UNIX2003") -} - pub fn isolation_abort_error(name: &str) -> InterpResult<'static> { throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!( "{} not available when isolation is enabled", diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 36d075e32dff..3745b8cf2fa1 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -25,7 +25,6 @@ use rustc_target::{ use super::backtrace::EvalContextExt as _; use crate::*; -use helpers::strip_linker_suffix; /// Returned by `emulate_foreign_item_by_name`. pub enum EmulateByNameResult { @@ -216,12 +215,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .first_attr_value_str_by_name(&attrs, sym::link_name) .unwrap_or_else(|| this.tcx.item_name(def_id)); let link_name = link_name_sym.as_str(); - let link_name = strip_linker_suffix(&link_name); let tcx = this.tcx.tcx; // First: functions that diverge. let (dest, ret) = match ret { - None => match link_name { + None => match &*link_name { "miri_start_panic" => { // `check_shim` happens inside `handle_miri_start_panic`. this.handle_miri_start_panic(abi, link_name_sym, args, unwind)?; @@ -306,9 +304,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Here we dispatch all the shims for foreign functions. If you have a platform specific // shim, add it to the corresponding submodule. - let shim_name = link_name.as_str(); - let shim_name = strip_linker_suffix(&shim_name); - match shim_name { + match &*link_name.as_str() { // Miri-specific extern functions "miri_static_root" => { let &[ref ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?; @@ -499,7 +495,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[ref f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); - let f = match shim_name { + let f = match &*link_name.as_str() { "cbrtf" => f.cbrt(), "coshf" => f.cosh(), "sinhf" => f.sinh(), @@ -522,7 +518,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: Using host floats. let f1 = f32::from_bits(this.read_scalar(f1)?.to_u32()?); let f2 = f32::from_bits(this.read_scalar(f2)?.to_u32()?); - let n = match shim_name { + let n = match &*link_name.as_str() { "_hypotf" | "hypotf" => f1.hypot(f2), "atan2f" => f1.atan2(f2), _ => bug!(), @@ -541,7 +537,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[ref f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); - let f = match shim_name { + let f = match &*link_name.as_str() { "cbrt" => f.cbrt(), "cosh" => f.cosh(), "sinh" => f.sinh(), @@ -562,7 +558,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: Using host floats. let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?); let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?); - let n = match shim_name { + let n = match &*link_name.as_str() { "_hypot" | "hypot" => f1.hypot(f2), "atan2" => f1.atan2(f2), _ => bug!(), diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 2585b562f230..4035deff63ef 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -6,7 +6,6 @@ use rustc_target::abi::{Align, LayoutOf, Size}; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::strip_linker_suffix; use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; use shims::posix::sync::EvalContextExt as _; @@ -24,7 +23,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult> { let this = self.eval_context_mut(); - match strip_linker_suffix(&link_name.as_str()) { + match &*link_name.as_str() { // Environment related shims "getenv" => { let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 160e27f395e5..33889963bc44 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -3,7 +3,6 @@ use rustc_span::Symbol; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::strip_linker_suffix; use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; use shims::posix::linux::sync::futex; @@ -22,7 +21,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult> { let this = self.eval_context_mut(); - match strip_linker_suffix(&link_name.as_str()) { + match &*link_name.as_str() { // errno "__errno_location" => { let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index 45d6f5b44953..47a860b96a87 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -3,7 +3,6 @@ use rustc_span::Symbol; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::strip_linker_suffix; use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; use shims::posix::thread::EvalContextExt as _; @@ -20,7 +19,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult> { let this = self.eval_context_mut(); - match strip_linker_suffix(&link_name.as_str()) { + match &*link_name.as_str() { // errno "__error" => { let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 77f807536141..1921af359423 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -6,7 +6,6 @@ use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::strip_linker_suffix; use shims::foreign_items::EmulateByNameResult; use shims::windows::sync::EvalContextExt as _; @@ -27,7 +26,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // DWORD = ULONG = u32 // BOOL = i32 // BOOLEAN = u8 - match strip_linker_suffix(&link_name.as_str()) { + match &*link_name.as_str() { // Environment related shims "GetEnvironmentVariableW" => { let &[ref name, ref buf, ref size] = From aaaa142dc18ecae15bb357584b1de35395e3bdb8 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Tue, 15 Jun 2021 01:24:09 +0800 Subject: [PATCH 2734/5092] Rename all `link_name_sym` to `link_name` and remove the only remaining `let link_name = link_name_sym.as_str()` --- src/shims/foreign_items.rs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 3745b8cf2fa1..596f6c33d647 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -209,20 +209,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); - let link_name_sym = this + let link_name = this .tcx .sess .first_attr_value_str_by_name(&attrs, sym::link_name) .unwrap_or_else(|| this.tcx.item_name(def_id)); - let link_name = link_name_sym.as_str(); let tcx = this.tcx.tcx; // First: functions that diverge. let (dest, ret) = match ret { - None => match &*link_name { + None => match &*link_name.as_str() { "miri_start_panic" => { // `check_shim` happens inside `handle_miri_start_panic`. - this.handle_miri_start_panic(abi, link_name_sym, args, unwind)?; + this.handle_miri_start_panic(abi, link_name, args, unwind)?; return Ok(None); } // This matches calls to the foreign item `panic_impl`. @@ -231,7 +230,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We don't use `check_shim` here because we are just forwarding to the lang // item. Argument count checking will be performed when the returned `Body` is // called. - this.check_abi_and_shim_symbol_clash(abi, Abi::Rust, link_name_sym)?; + this.check_abi_and_shim_symbol_clash(abi, Abi::Rust, link_name)?; let panic_impl_id = tcx.lang_items().panic_impl().unwrap(); let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id); return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); @@ -240,25 +239,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "exit" | "ExitProcess" => { - let exp_abi = if link_name == "exit" { + let exp_abi = if link_name.as_str() == "exit" { Abi::C { unwind: false } } else { Abi::System { unwind: false } }; - let &[ref code] = this.check_shim(abi, exp_abi, link_name_sym, args)?; + let &[ref code] = this.check_shim(abi, exp_abi, link_name, args)?; // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway let code = this.read_scalar(code)?.to_i32()?; throw_machine_stop!(TerminationInfo::Exit(code.into())); } "abort" => { - let &[] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; throw_machine_stop!(TerminationInfo::Abort( "the program aborted execution".to_owned() )) } _ => { - if let Some(body) = this.lookup_exported_symbol(link_name_sym)? { + if let Some(body) = this.lookup_exported_symbol(link_name)? { return Ok(Some(body)); } this.handle_unsupported(format!( @@ -272,14 +270,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Second: functions that return. - match this.emulate_foreign_item_by_name(link_name_sym, abi, args, dest, ret)? { + match this.emulate_foreign_item_by_name(link_name, abi, args, dest, ret)? { EmulateByNameResult::NeedsJumping => { trace!("{:?}", this.dump_place(**dest)); this.go_to_block(ret); } EmulateByNameResult::AlreadyJumped => (), EmulateByNameResult::NotSupported => { - if let Some(body) = this.lookup_exported_symbol(link_name_sym)? { + if let Some(body) = this.lookup_exported_symbol(link_name)? { return Ok(Some(body)); } From dfd7a6d5aae8e03a0149eb5134f4b5dd763036d5 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Tue, 15 Jun 2021 16:11:49 +0800 Subject: [PATCH 2735/5092] Rustup --- rust-version | 2 +- tests/compile-fail/validity/invalid_enum_tag.rs | 2 +- .../validity/invalid_enum_tag_256variants_uninit.rs | 2 +- tests/compile-fail/validity/transmute_through_ptr.rs | 2 +- tests/run-pass/stacked-borrows/interior_mutability.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 7d2e8afafacb..18cfda63a53e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a50d72158e08e02cfc051b863017bdbd2c45b637 +d74b36ea2f814b720c39d7b60aecaefe512a056b diff --git a/tests/compile-fail/validity/invalid_enum_tag.rs b/tests/compile-fail/validity/invalid_enum_tag.rs index 39e8eed683a3..d4ee3cc8a34a 100644 --- a/tests/compile-fail/validity/invalid_enum_tag.rs +++ b/tests/compile-fail/validity/invalid_enum_tag.rs @@ -4,5 +4,5 @@ pub enum Foo { } fn main() { - let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR encountered 0x0000002a at ., but expected a valid enum tag + let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR type validation failed at .: encountered 0x0000002a, but expected a valid enum tag } diff --git a/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs b/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs index 74e24491e610..ccf97b416c69 100644 --- a/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs +++ b/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs @@ -266,5 +266,5 @@ union MyUninit { } fn main() { - let _a = unsafe { MyUninit { init: () }.uninit }; //~ ERROR encountered uninitialized bytes at ., but expected a valid enum tag + let _a = unsafe { MyUninit { init: () }.uninit }; //~ ERROR type validation failed at .: encountered uninitialized bytes, but expected a valid enum tag } diff --git a/tests/compile-fail/validity/transmute_through_ptr.rs b/tests/compile-fail/validity/transmute_through_ptr.rs index 0ef69efb86e6..cd354eac4aef 100644 --- a/tests/compile-fail/validity/transmute_through_ptr.rs +++ b/tests/compile-fail/validity/transmute_through_ptr.rs @@ -11,6 +11,6 @@ fn main() { let mut x = Bool::True; evil(&mut x); let y = x; // reading this ought to be enough to trigger validation - //~^ ERROR encountered 0x0000002c at ., but expected a valid enum tag + //~^ ERROR type validation failed at .: encountered 0x0000002c, but expected a valid enum tag println!("{:?}", y); // make sure it is used (and not optimized away) } diff --git a/tests/run-pass/stacked-borrows/interior_mutability.rs b/tests/run-pass/stacked-borrows/interior_mutability.rs index 17e628a09f23..87624e520db1 100644 --- a/tests/run-pass/stacked-borrows/interior_mutability.rs +++ b/tests/run-pass/stacked-borrows/interior_mutability.rs @@ -1,4 +1,4 @@ -#![feature(maybe_uninit_extra, maybe_uninit_ref)] +#![feature(maybe_uninit_extra)] use std::mem::MaybeUninit; use std::cell::{Cell, RefCell, UnsafeCell}; From 7f3dd37f1e43e66162162bc6e2b51c9faa0daeae Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 17 Jun 2021 20:52:35 +0200 Subject: [PATCH 2736/5092] rustup --- rust-version | 2 +- tests/compile-fail/erroneous_const.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 18cfda63a53e..33ad4403bb68 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d74b36ea2f814b720c39d7b60aecaefe512a056b +4d3ce2e7dac840d6ac7d658a5506eb31492fb3ef diff --git a/tests/compile-fail/erroneous_const.rs b/tests/compile-fail/erroneous_const.rs index f193dee94ebc..199439ccbd2e 100644 --- a/tests/compile-fail/erroneous_const.rs +++ b/tests/compile-fail/erroneous_const.rs @@ -8,7 +8,7 @@ struct PrintName(T); impl PrintName { - const VOID: ! = panic!(); //~ERROR any use of this value will cause an error + const VOID: ! = panic!(); //~ERROR evaluation of `PrintName::::VOID` failed } fn no_codegen() { From 26446470533320204e7b7eb0c1b12598fbe1d59f Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 20 Jun 2021 15:12:11 +0800 Subject: [PATCH 2737/5092] Update backtraces --- rust-version | 2 +- tests/run-pass/backtrace-api.stderr | 4 ++++ tests/run-pass/backtrace-std.stderr | 12 ++++++++++-- tests/run-pass/panic/panic1.stderr | 12 ++++++++++-- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 33ad4403bb68..128548fd922b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4d3ce2e7dac840d6ac7d658a5506eb31492fb3ef +192920c22bc8433ab14706ee0829e707d119b74f diff --git a/tests/run-pass/backtrace-api.stderr b/tests/run-pass/backtrace-api.stderr index a5208221da40..bd5908ba2979 100644 --- a/tests/run-pass/backtrace-api.stderr +++ b/tests/run-pass/backtrace-api.stderr @@ -10,5 +10,9 @@ RUSTLIB/core/src/ops/function.rs:LL:COL (std::ops::function::impls::call_once) RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try::do_call) RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try) RUSTLIB/std/src/panic.rs:LL:COL (std::panic::catch_unwind) +RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start_internal::{closure#2}) +RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try::do_call) +RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try) +RUSTLIB/std/src/panic.rs:LL:COL (std::panic::catch_unwind) RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start_internal) RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start) diff --git a/tests/run-pass/backtrace-std.stderr b/tests/run-pass/backtrace-std.stderr index 09f035b9724e..64386085c775 100644 --- a/tests/run-pass/backtrace-std.stderr +++ b/tests/run-pass/backtrace-std.stderr @@ -22,7 +22,15 @@ at RUSTLIB/std/src/panicking.rs:LL:CC 11: std::panic::catch_unwind at RUSTLIB/std/src/panic.rs:LL:CC - 12: std::rt::lang_start_internal + 12: std::rt::lang_start_internal::{closure#2} at RUSTLIB/std/src/rt.rs:LL:CC - 13: std::rt::lang_start + 13: std::panicking::r#try::do_call + at RUSTLIB/std/src/panicking.rs:LL:CC + 14: std::panicking::r#try + at RUSTLIB/std/src/panicking.rs:LL:CC + 15: std::panic::catch_unwind + at RUSTLIB/std/src/panic.rs:LL:CC + 16: std::rt::lang_start_internal + at RUSTLIB/std/src/rt.rs:LL:CC + 17: std::rt::lang_start at RUSTLIB/std/src/rt.rs:LL:CC diff --git a/tests/run-pass/panic/panic1.stderr b/tests/run-pass/panic/panic1.stderr index e0f1aa5dad70..0b59b2a523b3 100644 --- a/tests/run-pass/panic/panic1.stderr +++ b/tests/run-pass/panic/panic1.stderr @@ -16,8 +16,16 @@ stack backtrace: at RUSTLIB/$FILE:LL:COL 7: std::panic::catch_unwind at RUSTLIB/$FILE:LL:COL - 8: std::rt::lang_start_internal + 8: std::rt::lang_start_internal::{closure#2} at RUSTLIB/$FILE:LL:COL - 9: std::rt::lang_start + 9: std::panicking::r#try::do_call + at RUSTLIB/$FILE:LL:COL + 10: std::panicking::r#try + at RUSTLIB/$FILE:LL:COL + 11: std::panic::catch_unwind + at RUSTLIB/$FILE:LL:COL + 12: std::rt::lang_start_internal + at RUSTLIB/$FILE:LL:COL + 13: std::rt::lang_start at RUSTLIB/$FILE:LL:COL note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. From 7b2d2cfa462fac0824faf9060848d4b423f70b19 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 20 Jun 2021 19:33:05 +0200 Subject: [PATCH 2738/5092] use exhaustive struct match for manual Debug impl --- src/machine.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 91a83a8acf40..7ec510d0506f 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -52,9 +52,10 @@ pub struct FrameData<'tcx> { impl<'tcx> std::fmt::Debug for FrameData<'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // Omitting `timing`, it does not support `Debug`. + let FrameData { call_id, catch_unwind, timing: _ } = self; f.debug_struct("FrameData") - .field("call_id", &self.call_id) - .field("catch_unwind", &self.catch_unwind) + .field("call_id", call_id) + .field("catch_unwind", catch_unwind) .finish() } } From 2d17b5a550fd204892ed3e757b044d5cbcb595dd Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Thu, 24 Jun 2021 02:35:08 +0800 Subject: [PATCH 2739/5092] Use `miri` inside the target directory used by rustc as Miri's target directory --- .github/workflows/ci.yml | 6 + cargo-miri/bin.rs | 115 ++++++++++++++---- test-cargo-miri/.gitignore | 3 + test-cargo-miri/run-test.py | 19 +++ .../run.custom-target-dir.stderr.ref | 2 + 5 files changed, 123 insertions(+), 22 deletions(-) create mode 100644 test-cargo-miri/run.custom-target-dir.stderr.ref diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 889c584ba7c1..28cab45be405 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -83,6 +83,12 @@ jobs: --host ${{ matrix.host_target }} rustup default master + # We need a nightly Cargo to run tests that depend on unstable Cargo features. + - name: Install latest nightly + uses: actions-rs/toolchain@v1 + with: + toolchain: nightly + - name: Show Rust version run: | rustup show diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 7836b26ea5f9..6195a917cb8d 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -6,7 +6,7 @@ use std::io::{self, BufRead, BufReader, BufWriter, Read, Write}; use std::iter::TakeWhile; use std::ops::Not; use std::path::{Path, PathBuf}; -use std::process::Command; +use std::process::{Command, Stdio}; use serde::{Deserialize, Serialize}; @@ -112,40 +112,60 @@ fn has_arg_flag(name: &str) -> bool { args.any(|val| val == name) } -/// Yields all values of command line flag `name`. -struct ArgFlagValueIter<'a> { - args: TakeWhile bool>, +/// Yields all values of command line flag `name` as `Ok(arg)`, and all other arguments except +/// the flag as `Err(arg)`. +struct ArgFlagValueWithOtherArgsIter<'a, I> { + args: TakeWhile bool>, name: &'a str, } -impl<'a> ArgFlagValueIter<'a> { - fn new(name: &'a str) -> Self { +impl<'a, I: Iterator> ArgFlagValueWithOtherArgsIter<'a, I> { + fn new(args: I, name: &'a str) -> Self { Self { // Stop searching at `--`. - args: env::args().take_while(|val| val != "--"), + args: args.take_while(|val| val != "--"), name, } } } +impl> Iterator for ArgFlagValueWithOtherArgsIter<'_, I> { + type Item = Result; + + fn next(&mut self) -> Option { + let arg = self.args.next()?; + if arg.starts_with(self.name) { + // Strip leading `name`. + let suffix = &arg[self.name.len()..]; + if suffix.is_empty() { + // This argument is exactly `name`; the next one is the value. + return self.args.next().map(Ok); + } else if suffix.starts_with('=') { + // This argument is `name=value`; get the value. + // Strip leading `=`. + return Some(Ok(suffix[1..].to_owned())); + } + } + Some(Err(arg)) + } +} + +/// Yields all values of command line flag `name`. +struct ArgFlagValueIter<'a>(ArgFlagValueWithOtherArgsIter<'a, env::Args>); + +impl<'a> ArgFlagValueIter<'a> { + fn new(name: &'a str) -> Self { + Self(ArgFlagValueWithOtherArgsIter::new(env::args(), name)) + } +} + impl Iterator for ArgFlagValueIter<'_> { type Item = String; fn next(&mut self) -> Option { loop { - let arg = self.args.next()?; - if !arg.starts_with(self.name) { - continue; - } - // Strip leading `name`. - let suffix = &arg[self.name.len()..]; - if suffix.is_empty() { - // This argument is exactly `name`; the next one is the value. - return self.args.next(); - } else if suffix.starts_with('=') { - // This argument is `name=value`; get the value. - // Strip leading `=`. - return Some(suffix[1..].to_owned()); + if let Ok(value) = self.0.next()? { + return Some(value); } } } @@ -510,8 +530,59 @@ fn phase_cargo_miri(mut args: env::Args) { &host }; - // Forward all further arguments to cargo. - cmd.args(args); + let mut target_dir = None; + + // Forward all arguments before `--` other than `--target-dir` and its value to Cargo. + for arg in ArgFlagValueWithOtherArgsIter::new(&mut args, "--target-dir") { + match arg { + Ok(value) => target_dir = Some(value.into()), + Err(arg) => drop(cmd.arg(arg)), + } + } + + // Detect the target directory if it's not specified via `--target-dir`. + let target_dir = target_dir.get_or_insert_with(|| { + #[derive(Deserialize)] + struct Metadata { + target_directory: PathBuf, + } + let mut cmd = cargo(); + // `-Zunstable-options` is required by `--config`. + cmd.args(["metadata", "--no-deps", "--format-version=1", "-Zunstable-options"]); + // The `build.target-dir` config can by passed by `--config` flags, so forward them to + // `cargo metadata`. + let config_flag = "--config"; + for arg in ArgFlagValueWithOtherArgsIter::new( + env::args().skip(3), // skip the program name, "miri" and "run" / "test" + config_flag, + ) { + if let Ok(config) = arg { + cmd.arg(config_flag).arg(config); + } + } + let mut child = cmd + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .spawn() + .expect("failed ro run `cargo metadata`"); + // Check this `Result` after `status.success()` is checked, so we don't print the error + // to stderr if `cargo metadata` is also printing to stderr. + let metadata: Result = serde_json::from_reader(child.stdout.take().unwrap()); + let status = child.wait().expect("failed to wait `cargo metadata` to exit"); + if !status.success() { + std::process::exit(status.code().unwrap_or(-1)); + } + metadata + .unwrap_or_else(|e| show_error(format!("invalid `cargo metadata` output: {}", e))) + .target_directory + }); + + // Set `--target-dir` to `miri` inside the original target directory. + target_dir.push("miri"); + cmd.arg("--target-dir").arg(target_dir); + + // Forward all further arguments after `--` to cargo. + cmd.arg("--").args(args); // Set `RUSTC_WRAPPER` to ourselves. Cargo will prepend that binary to its usual invocation, // i.e., the first argument is `rustc` -- which is what we use in `main` to distinguish diff --git a/test-cargo-miri/.gitignore b/test-cargo-miri/.gitignore index 56f307a7fb13..af5854e0c3fd 100644 --- a/test-cargo-miri/.gitignore +++ b/test-cargo-miri/.gitignore @@ -1 +1,4 @@ *.real +custom-run +custom-test +config-cli diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index c850e7d14591..369941787a14 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -101,6 +101,11 @@ def test_cargo_miri_run(): "run.subcrate.stdout.ref", "run.subcrate.stderr.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) + test("`cargo miri run` (custom target dir)", + # Attempt to confuse the argument parser. + cargo_miri("run") + ["--target-dir=custom-run", "--", "--target-dir=target/custom-run"], + "run.args.stdout.ref", "run.custom-target-dir.stderr.ref", + ) def test_cargo_miri_test(): # rustdoc is not run on foreign targets @@ -144,8 +149,18 @@ def test_cargo_miri_test(): cargo_miri("test") + ["-p", "subcrate", "--doc"], "test.stdout-empty.ref", "test.stderr-proc-macro-doctest.ref", ) + test("`cargo miri test` (custom target dir)", + cargo_miri("test") + ["--target-dir=custom-test"], + default_ref, "test.stderr-empty.ref", + ) + del os.environ["CARGO_TARGET_DIR"] # this overrides `build.target-dir` passed by `--config`, so unset it + test("`cargo miri test` (config-cli)", + cargo_miri("test") + ["--config=build.target-dir=\"config-cli\"", "-Zunstable-options"], + default_ref, "test.stderr-empty.ref", + ) os.chdir(os.path.dirname(os.path.realpath(__file__))) +os.environ["CARGO_TARGET_DIR"] = "target" # this affects the location of the target directory that we need to check os.environ["RUST_TEST_NOCAPTURE"] = "0" # this affects test output, so make sure it is not set os.environ["RUST_TEST_THREADS"] = "1" # avoid non-deterministic output due to concurrent test runs @@ -158,6 +173,10 @@ if not 'MIRI_SYSROOT' in os.environ: subprocess.run(cargo_miri("setup"), check=True) test_cargo_miri_run() test_cargo_miri_test() +for target_dir in ["target", "custom-run", "custom-test", "config-cli"]: + if os.listdir(target_dir) != ["miri"]: + fail(f"`{target_dir}` contains unexpected files") + os.access(os.path.join(target_dir, "miri", "debug", "deps"), os.F_OK) print("\nTEST SUCCESSFUL!") sys.exit(0) diff --git a/test-cargo-miri/run.custom-target-dir.stderr.ref b/test-cargo-miri/run.custom-target-dir.stderr.ref new file mode 100644 index 000000000000..4395ff8879b9 --- /dev/null +++ b/test-cargo-miri/run.custom-target-dir.stderr.ref @@ -0,0 +1,2 @@ +main +--target-dir=target/custom-run From c3ad18256dab981000bcade9ad21420c63d044f9 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sat, 26 Jun 2021 21:24:01 +0800 Subject: [PATCH 2740/5092] long closure -> function --- cargo-miri/bin.rs | 73 ++++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 6195a917cb8d..c87325614bbe 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -472,6 +472,43 @@ path = "lib.rs" } } +/// Detect the target directory by calling `cargo metadata`. +fn detect_target_dir() -> PathBuf { + #[derive(Deserialize)] + struct Metadata { + target_directory: PathBuf, + } + let mut cmd = cargo(); + // `-Zunstable-options` is required by `--config`. + cmd.args(["metadata", "--no-deps", "--format-version=1", "-Zunstable-options"]); + // The `build.target-dir` config can by passed by `--config` flags, so forward them to + // `cargo metadata`. + let config_flag = "--config"; + for arg in ArgFlagValueWithOtherArgsIter::new( + env::args().skip(3), // skip the program name, "miri" and "run" / "test" + config_flag, + ) { + if let Ok(config) = arg { + cmd.arg(config_flag).arg(config); + } + } + let mut child = cmd + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .spawn() + .expect("failed ro run `cargo metadata`"); + // Check this `Result` after `status.success()` is checked, so we don't print the error + // to stderr if `cargo metadata` is also printing to stderr. + let metadata: Result = serde_json::from_reader(child.stdout.take().unwrap()); + let status = child.wait().expect("failed to wait `cargo metadata` to exit"); + if !status.success() { + std::process::exit(status.code().unwrap_or(-1)); + } + metadata + .unwrap_or_else(|e| show_error(format!("invalid `cargo metadata` output: {}", e))) + .target_directory +} + fn phase_cargo_miri(mut args: env::Args) { // Check for version and help flags even when invoked as `cargo-miri`. if has_arg_flag("--help") || has_arg_flag("-h") { @@ -541,41 +578,7 @@ fn phase_cargo_miri(mut args: env::Args) { } // Detect the target directory if it's not specified via `--target-dir`. - let target_dir = target_dir.get_or_insert_with(|| { - #[derive(Deserialize)] - struct Metadata { - target_directory: PathBuf, - } - let mut cmd = cargo(); - // `-Zunstable-options` is required by `--config`. - cmd.args(["metadata", "--no-deps", "--format-version=1", "-Zunstable-options"]); - // The `build.target-dir` config can by passed by `--config` flags, so forward them to - // `cargo metadata`. - let config_flag = "--config"; - for arg in ArgFlagValueWithOtherArgsIter::new( - env::args().skip(3), // skip the program name, "miri" and "run" / "test" - config_flag, - ) { - if let Ok(config) = arg { - cmd.arg(config_flag).arg(config); - } - } - let mut child = cmd - .stdin(Stdio::null()) - .stdout(Stdio::piped()) - .spawn() - .expect("failed ro run `cargo metadata`"); - // Check this `Result` after `status.success()` is checked, so we don't print the error - // to stderr if `cargo metadata` is also printing to stderr. - let metadata: Result = serde_json::from_reader(child.stdout.take().unwrap()); - let status = child.wait().expect("failed to wait `cargo metadata` to exit"); - if !status.success() { - std::process::exit(status.code().unwrap_or(-1)); - } - metadata - .unwrap_or_else(|e| show_error(format!("invalid `cargo metadata` output: {}", e))) - .target_directory - }); + let target_dir = target_dir.get_or_insert_with(detect_target_dir); // Set `--target-dir` to `miri` inside the original target directory. target_dir.push("miri"); From 59408b68dd79b54cda6b1d31dc6ef0b6048a6555 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sat, 26 Jun 2021 21:45:38 +0800 Subject: [PATCH 2741/5092] Add some comments in `test-cargo-miri/run-tests.py` --- test-cargo-miri/run-test.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 369941787a14..51433d98a2ed 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -173,9 +173,11 @@ if not 'MIRI_SYSROOT' in os.environ: subprocess.run(cargo_miri("setup"), check=True) test_cargo_miri_run() test_cargo_miri_test() +# Ensure we did not create anything outside the expected target dir. for target_dir in ["target", "custom-run", "custom-test", "config-cli"]: if os.listdir(target_dir) != ["miri"]: fail(f"`{target_dir}` contains unexpected files") + # Ensure something exists inside that target dir. os.access(os.path.join(target_dir, "miri", "debug", "deps"), os.F_OK) print("\nTEST SUCCESSFUL!") From 2ced7ecb9f54e2798989ff5e5946c73f4b740afe Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sat, 26 Jun 2021 21:49:56 +0800 Subject: [PATCH 2742/5092] `ArgFlagValueWithOtherArgsIter` -> `ArgSplitFlagValue` --- cargo-miri/bin.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index c87325614bbe..939ea5ac507f 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -114,12 +114,12 @@ fn has_arg_flag(name: &str) -> bool { /// Yields all values of command line flag `name` as `Ok(arg)`, and all other arguments except /// the flag as `Err(arg)`. -struct ArgFlagValueWithOtherArgsIter<'a, I> { +struct ArgSplitFlagValue<'a, I> { args: TakeWhile bool>, name: &'a str, } -impl<'a, I: Iterator> ArgFlagValueWithOtherArgsIter<'a, I> { +impl<'a, I: Iterator> ArgSplitFlagValue<'a, I> { fn new(args: I, name: &'a str) -> Self { Self { // Stop searching at `--`. @@ -129,7 +129,7 @@ impl<'a, I: Iterator> ArgFlagValueWithOtherArgsIter<'a, I> { } } -impl> Iterator for ArgFlagValueWithOtherArgsIter<'_, I> { +impl> Iterator for ArgSplitFlagValue<'_, I> { type Item = Result; fn next(&mut self) -> Option { @@ -151,11 +151,11 @@ impl> Iterator for ArgFlagValueWithOtherArgsIter<'_, } /// Yields all values of command line flag `name`. -struct ArgFlagValueIter<'a>(ArgFlagValueWithOtherArgsIter<'a, env::Args>); +struct ArgFlagValueIter<'a>(ArgSplitFlagValue<'a, env::Args>); impl<'a> ArgFlagValueIter<'a> { fn new(name: &'a str) -> Self { - Self(ArgFlagValueWithOtherArgsIter::new(env::args(), name)) + Self(ArgSplitFlagValue::new(env::args(), name)) } } @@ -484,7 +484,7 @@ fn detect_target_dir() -> PathBuf { // The `build.target-dir` config can by passed by `--config` flags, so forward them to // `cargo metadata`. let config_flag = "--config"; - for arg in ArgFlagValueWithOtherArgsIter::new( + for arg in ArgSplitFlagValue::new( env::args().skip(3), // skip the program name, "miri" and "run" / "test" config_flag, ) { @@ -570,7 +570,7 @@ fn phase_cargo_miri(mut args: env::Args) { let mut target_dir = None; // Forward all arguments before `--` other than `--target-dir` and its value to Cargo. - for arg in ArgFlagValueWithOtherArgsIter::new(&mut args, "--target-dir") { + for arg in ArgSplitFlagValue::new(&mut args, "--target-dir") { match arg { Ok(value) => target_dir = Some(value.into()), Err(arg) => drop(cmd.arg(arg)), From 8f87903ec91499f8e3f68ed3386b70c5d069cf8d Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sat, 26 Jun 2021 22:22:40 +0800 Subject: [PATCH 2743/5092] Fix typo --- cargo-miri/bin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 939ea5ac507f..e9596e56f742 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -481,7 +481,7 @@ fn detect_target_dir() -> PathBuf { let mut cmd = cargo(); // `-Zunstable-options` is required by `--config`. cmd.args(["metadata", "--no-deps", "--format-version=1", "-Zunstable-options"]); - // The `build.target-dir` config can by passed by `--config` flags, so forward them to + // The `build.target-dir` config can be passed by `--config` flags, so forward them to // `cargo metadata`. let config_flag = "--config"; for arg in ArgSplitFlagValue::new( From 16929329667c5ada59e98543f55e188b611413d5 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sat, 26 Jun 2021 22:36:05 +0800 Subject: [PATCH 2744/5092] Show error if `--target-dir` is provided more than once --- cargo-miri/bin.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index e9596e56f742..aac945d2d780 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -572,7 +572,12 @@ fn phase_cargo_miri(mut args: env::Args) { // Forward all arguments before `--` other than `--target-dir` and its value to Cargo. for arg in ArgSplitFlagValue::new(&mut args, "--target-dir") { match arg { - Ok(value) => target_dir = Some(value.into()), + Ok(value) => { + if target_dir.is_some() { + show_error(format!("`--target-dir` is provided more than once")); + } + target_dir = Some(value.into()); + } Err(arg) => drop(cmd.arg(arg)), } } From 34217bdc8e088051e831de7baa33c377724af3e0 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sat, 26 Jun 2021 20:43:31 +0800 Subject: [PATCH 2745/5092] Use `rustup-toolchain-install-master` to install Cargo --- .github/workflows/ci.yml | 7 +------ rustup-toolchain | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 28cab45be405..487632136905 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -77,18 +77,13 @@ jobs: rustup-toolchain-install-master \ -f \ -n master "$RUSTC_HASH" \ + -c cargo \ -c rust-src \ -c rustc-dev \ -c llvm-tools \ --host ${{ matrix.host_target }} rustup default master - # We need a nightly Cargo to run tests that depend on unstable Cargo features. - - name: Install latest nightly - uses: actions-rs/toolchain@v1 - with: - toolchain: nightly - - name: Show Rust version run: | rustup show diff --git a/rustup-toolchain b/rustup-toolchain index 3fbebe1565f7..5b7e8f7fcd63 100755 --- a/rustup-toolchain +++ b/rustup-toolchain @@ -39,7 +39,7 @@ fi # Install and setup new toolchain. rustup toolchain uninstall miri -rustup-toolchain-install-master -n miri -c rust-src -c rustc-dev -c llvm-tools -- "$NEW_COMMIT" +rustup-toolchain-install-master -n miri -c cargo -c rust-src -c rustc-dev -c llvm-tools -- "$NEW_COMMIT" rustup override set miri # Cleanup. From e751eeb1973424d831cbee2cad3f8f3258cedbb4 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 27 Jun 2021 23:07:15 +0800 Subject: [PATCH 2746/5092] `drop(cmd.arg(arg))` -> `cmd.arg(arg);` --- cargo-miri/bin.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index aac945d2d780..4f0ffacf96a3 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -578,7 +578,9 @@ fn phase_cargo_miri(mut args: env::Args) { } target_dir = Some(value.into()); } - Err(arg) => drop(cmd.arg(arg)), + Err(arg) => { + cmd.arg(arg); + } } } From 7d310aa8365d27526182424ce23a6d3ee5f0b813 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 27 Jun 2021 23:08:38 +0800 Subject: [PATCH 2747/5092] Fix `.expect()` message --- cargo-miri/bin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 4f0ffacf96a3..d0ab82732427 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -500,7 +500,7 @@ fn detect_target_dir() -> PathBuf { // Check this `Result` after `status.success()` is checked, so we don't print the error // to stderr if `cargo metadata` is also printing to stderr. let metadata: Result = serde_json::from_reader(child.stdout.take().unwrap()); - let status = child.wait().expect("failed to wait `cargo metadata` to exit"); + let status = child.wait().expect("failed to wait for `cargo metadata` to exit"); if !status.success() { std::process::exit(status.code().unwrap_or(-1)); } From 08236912a70c24dcf11d157fbe4dbc1e1ae00366 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 27 Jun 2021 23:09:10 +0800 Subject: [PATCH 2748/5092] Improve doc comment --- cargo-miri/bin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index d0ab82732427..8d2065c8eeb4 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -113,7 +113,7 @@ fn has_arg_flag(name: &str) -> bool { } /// Yields all values of command line flag `name` as `Ok(arg)`, and all other arguments except -/// the flag as `Err(arg)`. +/// the flag as `Err(arg)`. (The flag `name` itself is not yielded at all, only its values are.) struct ArgSplitFlagValue<'a, I> { args: TakeWhile bool>, name: &'a str, From e33bf695db921a08e89bf8efb7572a51a0c86917 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 29 Jun 2021 20:47:28 +0200 Subject: [PATCH 2749/5092] rustup --- rust-version | 2 +- src/data_race.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 128548fd922b..a8a75e9f046c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -192920c22bc8433ab14706ee0829e707d119b74f +e98897e5dc9898707bf4331c43b2e76ab7e282fe diff --git a/src/data_race.rs b/src/data_race.rs index 45159ef4c07c..cb7b1fc6dbe0 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -759,8 +759,7 @@ impl VClockAlloc { | MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls, ) - | MemoryKind::CallerLocation - | MemoryKind::Vtable => (0, VectorIdx::MAX_INDEX), + | MemoryKind::CallerLocation => (0, VectorIdx::MAX_INDEX), }; VClockAlloc { alloc_ranges: RefCell::new(RangeMap::new( From 76fe48543cfbbed38567135093159f17b442dc0c Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Fri, 2 Jul 2021 16:08:27 +0800 Subject: [PATCH 2750/5092] Update for `TyCtxt::crates()` change --- rust-version | 2 +- src/helpers.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index a8a75e9f046c..9890818ee952 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e98897e5dc9898707bf4331c43b2e76ab7e282fe +46ae6ee65df19c6a3fb683499c1203e749975e60 diff --git a/src/helpers.rs b/src/helpers.rs index b99a446577ac..d53b2969fb55 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -20,7 +20,7 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi /// Gets an instance for a path. fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option { - tcx.crates().iter().find(|&&krate| tcx.crate_name(krate).as_str() == path[0]).and_then( + 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.item_children(krate); From c504e3dee0f85e344dbe8e4cc268e317ef9ff3a2 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Fri, 2 Jul 2021 16:20:55 +0800 Subject: [PATCH 2751/5092] Add a comment in `.github/workflows/ci.yml` --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 487632136905..ce13647fa586 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -74,6 +74,7 @@ jobs: else RUSTC_HASH=$(< rust-version) fi + # We need a nightly cargo for parts of the cargo miri test suite. rustup-toolchain-install-master \ -f \ -n master "$RUSTC_HASH" \ From e3fca9b3f13e14aa25634d7ffb818818e5720401 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Fri, 2 Jul 2021 16:22:59 +0800 Subject: [PATCH 2752/5092] Import `std::process::self` --- cargo-miri/bin.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 8d2065c8eeb4..1a7552c5d9e0 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -6,7 +6,7 @@ use std::io::{self, BufRead, BufReader, BufWriter, Read, Write}; use std::iter::TakeWhile; use std::ops::Not; use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; +use std::process::{self, Command}; use serde::{Deserialize, Serialize}; @@ -233,7 +233,7 @@ fn exec(mut cmd: Command) { /// If it fails, fail this process with the same exit code. /// Otherwise, continue. fn exec_with_pipe(mut cmd: Command, input: &[u8]) { - cmd.stdin(std::process::Stdio::piped()); + cmd.stdin(process::Stdio::piped()); let mut child = cmd.spawn().expect("failed to spawn process"); { let stdin = child.stdin.as_mut().expect("failed to open stdin"); @@ -493,8 +493,8 @@ fn detect_target_dir() -> PathBuf { } } let mut child = cmd - .stdin(Stdio::null()) - .stdout(Stdio::piped()) + .stdin(process::Stdio::null()) + .stdout(process::Stdio::piped()) .spawn() .expect("failed ro run `cargo metadata`"); // Check this `Result` after `status.success()` is checked, so we don't print the error From d19376985d84e54e452c8b26548d0f239dce9cc0 Mon Sep 17 00:00:00 2001 From: Smitty Date: Sun, 4 Jul 2021 09:59:55 -0400 Subject: [PATCH 2753/5092] Make work after mir-alloc-oom --- rust-version | 2 +- src/eval.rs | 14 ++++++++------ src/helpers.rs | 2 +- src/machine.rs | 6 ++++-- src/shims/backtrace.rs | 3 ++- src/shims/env.rs | 10 +++++----- src/shims/foreign_items.rs | 23 ++++++++++++++--------- src/shims/os_str.rs | 12 ++++++------ src/shims/posix/foreign_items.rs | 2 +- src/shims/posix/thread.rs | 2 +- src/shims/windows/foreign_items.rs | 2 +- 11 files changed, 44 insertions(+), 34 deletions(-) diff --git a/rust-version b/rust-version index 9890818ee952..23819ebc24e4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -46ae6ee65df19c6a3fb683499c1203e749975e60 +39e20f1ae5f13451eb35247808d6a2527cb7d060 diff --git a/src/eval.rs b/src/eval.rs index 95cdcb1b5a59..f728248c3a72 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -169,7 +169,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Make space for `0` terminator. let size = u64::try_from(arg.len()).unwrap().checked_add(1).unwrap(); let arg_type = tcx.mk_array(tcx.types.u8, size); - let arg_place = ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Machine.into()); + let arg_place = + ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Machine.into())?; ecx.write_os_str_to_c_str(OsStr::new(arg), arg_place.ptr, size)?; argvs.push(arg_place.ptr); } @@ -177,7 +178,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let argvs_layout = ecx.layout_of( tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), u64::try_from(argvs.len()).unwrap()), )?; - let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into()); + let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into())?; for (idx, arg) in argvs.into_iter().enumerate() { let place = ecx.mplace_field(&argvs_place, idx)?; ecx.write_scalar(arg, &place.into())?; @@ -188,14 +189,14 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`. { let argc_place = - ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into()); + ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into())?; ecx.write_scalar(argc, &argc_place.into())?; ecx.machine.argc = Some(argc_place.ptr); let argv_place = ecx.allocate( ecx.layout_of(tcx.mk_imm_ptr(tcx.types.unit))?, MiriMemoryKind::Machine.into(), - ); + )?; ecx.write_scalar(argv, &argv_place.into())?; ecx.machine.argv = Some(argv_place.ptr); } @@ -214,7 +215,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let cmd_utf16: Vec = cmd.encode_utf16().collect(); let cmd_type = tcx.mk_array(tcx.types.u16, u64::try_from(cmd_utf16.len()).unwrap()); - let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Machine.into()); + let cmd_place = + ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Machine.into())?; ecx.machine.cmd_line = Some(cmd_place.ptr); // Store the UTF-16 string. We just allocated so we know the bounds are fine. for (idx, &c) in cmd_utf16.iter().enumerate() { @@ -226,7 +228,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( }; // Return place (in static memory so that it does not count as leak). - let ret_place = ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into()); + let ret_place = ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into())?; // Call start function. ecx.call_function( start_instance, diff --git a/src/helpers.rs b/src/helpers.rs index d53b2969fb55..a6e66c3dbd38 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -440,7 +440,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { // Allocate new place, set initial value to 0. let errno_layout = this.machine.layouts.u32; - let errno_place = this.allocate(errno_layout, MiriMemoryKind::Machine.into()); + let errno_place = this.allocate(errno_layout, MiriMemoryKind::Machine.into())?; this.write_scalar(Scalar::from_u32(0), &errno_place.into())?; this.active_thread_mut().last_error = Some(errno_place); Ok(errno_place) diff --git a/src/machine.rs b/src/machine.rs index 7ec510d0506f..999e21796d30 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -199,7 +199,7 @@ impl MemoryExtra { // "__cxa_thread_atexit_impl" // This should be all-zero, pointer-sized. let layout = this.machine.layouts.usize; - let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into()); + let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; this.write_scalar(Scalar::from_machine_usize(0, this), &place.into())?; Self::add_extern_static(this, "__cxa_thread_atexit_impl", place.ptr); // "environ" @@ -213,7 +213,7 @@ impl MemoryExtra { // "_tls_used" // This is some obscure hack that is part of the Windows TLS story. It's a `u8`. let layout = this.machine.layouts.u8; - let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into()); + let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; this.write_scalar(Scalar::from_u8(0), &place.into())?; Self::add_extern_static(this, "_tls_used", place.ptr); } @@ -377,6 +377,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { const GLOBAL_KIND: Option = Some(MiriMemoryKind::Global); + const PANIC_ON_ALLOC_FAIL: bool = false; + #[inline(always)] fn enforce_alignment(memory_extra: &MemoryExtra) -> bool { memory_extra.check_alignment != AlignmentCheck::None diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 4ea374344c0d..ec29fef6368f 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -57,7 +57,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let array_ty = tcx.mk_array(ptr_ty, ptrs.len().try_into().unwrap()); // Write pointers into array - let alloc = this.allocate(this.layout_of(array_ty).unwrap(), MiriMemoryKind::Rust.into()); + let alloc = + this.allocate(this.layout_of(array_ty).unwrap(), MiriMemoryKind::Rust.into())?; for (i, ptr) in ptrs.into_iter().enumerate() { let place = this.mplace_index(&alloc, i as u64)?; this.write_immediate_to_mplace(ptr.into(), &place)?; diff --git a/src/shims/env.rs b/src/shims/env.rs index 0c42daa2446a..d99ffb31b5cf 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -88,7 +88,7 @@ fn alloc_env_var_as_c_str<'mir, 'tcx>( let mut name_osstring = name.to_os_string(); name_osstring.push("="); name_osstring.push(value); - Ok(ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Env.into())) + ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Env.into()) } fn alloc_env_var_as_wide_str<'mir, 'tcx>( @@ -99,7 +99,7 @@ fn alloc_env_var_as_wide_str<'mir, 'tcx>( let mut name_osstring = name.to_os_string(); name_osstring.push("="); name_osstring.push(value); - Ok(ecx.alloc_os_str_as_wide_str(name_osstring.as_os_str(), MiriMemoryKind::Env.into())) + ecx.alloc_os_str_as_wide_str(name_osstring.as_os_str(), MiriMemoryKind::Env.into()) } impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -179,7 +179,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Allocate environment block & Store environment variables to environment block. // Final null terminator(block terminator) is added by `alloc_os_str_to_wide_str`. - let envblock_ptr = this.alloc_os_str_as_wide_str(&env_vars, MiriMemoryKind::Env.into()); + let envblock_ptr = this.alloc_os_str_as_wide_str(&env_vars, MiriMemoryKind::Env.into())?; // If the function succeeds, the return value is a pointer to the environment block of the current process. Ok(envblock_ptr.into()) } @@ -442,7 +442,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // No `environ` allocated yet, let's do that. // This is memory backing an extern static, hence `ExternStatic`, not `Env`. let layout = this.machine.layouts.usize; - let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into()); + let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; this.machine.env_vars.environ = Some(place); } @@ -455,7 +455,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tcx = this.tcx; let vars_layout = this.layout_of(tcx.mk_array(tcx.types.usize, u64::try_from(vars.len()).unwrap()))?; - let vars_place = this.allocate(vars_layout, MiriMemoryKind::Env.into()); + let vars_place = this.allocate(vars_layout, MiriMemoryKind::Env.into())?; for (idx, var) in vars.into_iter().enumerate() { let place = this.mplace_field(&vars_place, idx)?; this.write_scalar(var, &place.into())?; diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 5b241a2fb3c1..5d46f3c05c33 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -67,18 +67,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Align::from_bytes(prev_power_of_two(size)).unwrap() } - fn malloc(&mut self, size: u64, zero_init: bool, kind: MiriMemoryKind) -> Scalar { + fn malloc( + &mut self, + size: u64, + zero_init: bool, + kind: MiriMemoryKind, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); if size == 0 { - Scalar::null_ptr(this) + Ok(Scalar::null_ptr(this)) } else { let align = this.min_align(size, kind); - let ptr = this.memory.allocate(Size::from_bytes(size), align, kind.into()); + let ptr = this.memory.allocate(Size::from_bytes(size), align, kind.into())?; if zero_init { // We just allocated this, the access is definitely in-bounds. this.memory.write_bytes(ptr.into(), iter::repeat(0u8).take(size as usize)).unwrap(); } - Scalar::Ptr(ptr) + Ok(Scalar::Ptr(ptr)) } } @@ -104,7 +109,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(Scalar::null_ptr(this)) } else { let new_ptr = - this.memory.allocate(Size::from_bytes(new_size), new_align, kind.into()); + this.memory.allocate(Size::from_bytes(new_size), new_align, kind.into())?; Ok(Scalar::Ptr(new_ptr)) } } else { @@ -331,7 +336,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "malloc" => { let &[ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; - let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C); + let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C)?; this.write_scalar(res, dest)?; } "calloc" => { @@ -340,7 +345,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let len = this.read_scalar(len)?.to_machine_usize(this)?; let size = items.checked_mul(len).ok_or_else(|| err_ub_format!("overflow during calloc size computation"))?; - let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C); + let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C)?; this.write_scalar(res, dest)?; } "free" => { @@ -368,7 +373,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into(), - ); + )?; this.write_scalar(ptr, dest)?; } "__rust_alloc_zeroed" => { @@ -380,7 +385,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into(), - ); + )?; // We just allocated this, the access is definitely in-bounds. this.memory.write_bytes(ptr.into(), iter::repeat(0u8).take(usize::try_from(size).unwrap())).unwrap(); this.write_scalar(ptr, dest)?; diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 8a3f5677706e..ea99921c0b67 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -161,14 +161,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, os_str: &OsStr, memkind: MemoryKind, - ) -> Pointer { + ) -> InterpResult<'tcx, Pointer> { let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0` terminator. let this = self.eval_context_mut(); let arg_type = this.tcx.mk_array(this.tcx.types.u8, size); - let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind); + let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?; assert!(self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap().0); - arg_place.ptr.assert_ptr() + Ok(arg_place.ptr.assert_ptr()) } /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of `u16`. @@ -176,14 +176,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, os_str: &OsStr, memkind: MemoryKind, - ) -> Pointer { + ) -> InterpResult<'tcx, Pointer> { let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0x0000` terminator. let this = self.eval_context_mut(); let arg_type = this.tcx.mk_array(this.tcx.types.u16, size); - let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind); + let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?; assert!(self.write_os_str_to_wide_str(os_str, arg_place.ptr, size).unwrap().0); - arg_place.ptr.assert_ptr() + Ok(arg_place.ptr.assert_ptr()) } /// Read a null-terminated sequence of bytes, and perform path separator conversion if needed. diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 4035deff63ef..1cfc3f0a4e79 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -159,7 +159,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::C.into(), - ); + )?; this.write_scalar(ptr, &ret.into())?; } this.write_null(dest)?; diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index 1e4597848914..ce1c817cf3ba 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -47,7 +47,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // pthread_join below) because the Rust standard library does not use // it. let ret_place = - this.allocate(this.layout_of(this.tcx.types.usize)?, MiriMemoryKind::Machine.into()); + this.allocate(this.layout_of(this.tcx.types.usize)?, MiriMemoryKind::Machine.into())?; this.call_function( instance, diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 1921af359423..b5324576273c 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -115,7 +115,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let flags = this.read_scalar(flags)?.to_u32()?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY - let res = this.malloc(size, zero_init, MiriMemoryKind::WinHeap); + let res = this.malloc(size, zero_init, MiriMemoryKind::WinHeap)?; this.write_scalar(res, dest)?; } "HeapFree" => { From ca782dfc1c7b3865a40466a09dbcaab67fc148a6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Jul 2021 19:34:08 +0200 Subject: [PATCH 2754/5092] sync license files with rustc repo --- LICENSE-APACHE | 25 ------------------------- LICENSE-MIT | 2 -- 2 files changed, 27 deletions(-) diff --git a/LICENSE-APACHE b/LICENSE-APACHE index a32595fa70bc..1b5ec8b78e23 100644 --- a/LICENSE-APACHE +++ b/LICENSE-APACHE @@ -174,28 +174,3 @@ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright 2016 The Miri Developers - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/LICENSE-MIT b/LICENSE-MIT index 1f9d89a5862b..31aa79387f27 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,5 +1,3 @@ -Copyright (c) 2016 The Miri Developers - Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the From efd582c6d8f14ffd730c5911101789e40eccec31 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 6 Jul 2021 10:04:16 +0200 Subject: [PATCH 2755/5092] explicitly list memory kinds for stacked borrows --- src/stacked_borrows.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 3e176d94b990..32cecf855d49 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -513,8 +513,14 @@ impl Stacks { | MiriMemoryKind::Tls | MiriMemoryKind::Env, ) => (extra.global_base_ptr(id), Permission::SharedReadWrite), - // Everything else we handle like raw pointers for now. - _ => { + // Everything else we only track precisely when raw pointers are tagged, for now. + MemoryKind::CallerLocation + | MemoryKind::Machine( + MiriMemoryKind::Rust + | MiriMemoryKind::C + | MiriMemoryKind::WinHeap + | MiriMemoryKind::Machine, + ) => { let tag = if extra.track_raw { Tag::Tagged(extra.new_ptr()) } else { Tag::Untagged }; (tag, Permission::SharedReadWrite) From 9b57313a4d91d9b66d237151a852955a9e450160 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 6 Jul 2021 10:07:48 +0200 Subject: [PATCH 2756/5092] also treat CallerLocation and Machine memory as properly tagged --- src/stacked_borrows.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 32cecf855d49..d5bd300959df 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -504,22 +504,23 @@ impl Stacks { // `Global` memory can be referenced by global pointers from `tcx`. // Thus we call `global_base_ptr` such that the global pointers get the same tag // as what we use here. - // `ExternStatic` is used for extern statics, and thus must also be listed here. - // `Env` we list because we can get away with precise tracking there. + // `ExternStatic` is used for extern statics, so the same reasoning applies. + // The others are various forms of machine-managed special global memory, and we can get + // away with precise tracking there. // The base pointer is not unique, so the base permission is `SharedReadWrite`. - MemoryKind::Machine( + MemoryKind::CallerLocation + | MemoryKind::Machine( MiriMemoryKind::Global | MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls - | MiriMemoryKind::Env, + | MiriMemoryKind::Env + | MiriMemoryKind::Machine, ) => (extra.global_base_ptr(id), Permission::SharedReadWrite), - // Everything else we only track precisely when raw pointers are tagged, for now. - MemoryKind::CallerLocation - | MemoryKind::Machine( + // Heap allocations we only track precisely when raw pointers are tagged, for now. + MemoryKind::Machine( MiriMemoryKind::Rust | MiriMemoryKind::C - | MiriMemoryKind::WinHeap - | MiriMemoryKind::Machine, + | MiriMemoryKind::WinHeap, ) => { let tag = if extra.track_raw { Tag::Tagged(extra.new_ptr()) } else { Tag::Untagged }; From 340267525c9bfdd0b7bdca51f4a36e7857a05b25 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 6 Jul 2021 10:09:53 +0200 Subject: [PATCH 2757/5092] exported_symbols_cache: ensure we do not overwrite anything --- src/shims/foreign_items.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 5d46f3c05c33..2de0baf29474 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -194,7 +194,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let instance = instance_and_crate.map(|ic| ic.0); // Cache it and load its MIR, if found. - this.machine.exported_symbols_cache.insert(link_name, instance); + this.machine.exported_symbols_cache.try_insert(link_name, instance).unwrap(); instance.map(|instance| this.load_mir(instance.def, None)).transpose() } From 447f23c71b1bedc8ba363eeeb0c24affc79f89a0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 6 Jul 2021 10:13:30 +0200 Subject: [PATCH 2758/5092] fmt --- src/stacked_borrows.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index d5bd300959df..0b92817c9728 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -518,9 +518,7 @@ impl Stacks { ) => (extra.global_base_ptr(id), Permission::SharedReadWrite), // Heap allocations we only track precisely when raw pointers are tagged, for now. MemoryKind::Machine( - MiriMemoryKind::Rust - | MiriMemoryKind::C - | MiriMemoryKind::WinHeap, + MiriMemoryKind::Rust | MiriMemoryKind::C | MiriMemoryKind::WinHeap, ) => { let tag = if extra.track_raw { Tag::Tagged(extra.new_ptr()) } else { Tag::Untagged }; From 833dff994f68612cab173f159346c27b0dc0e247 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Jul 2021 09:32:58 +0200 Subject: [PATCH 2759/5092] rustup --- rust-version | 2 +- tests/run-pass/panic/catch_panic.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 23819ebc24e4..8856f7d0852c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -39e20f1ae5f13451eb35247808d6a2527cb7d060 +c5e344f7747dbd7e7d4b209e3c480deb5979a56f diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index 9f9a2b493cef..63a3c9a47648 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -3,7 +3,7 @@ // We test the `align_offset` panic below, make sure we test the interpreter impl and not the "real" one. // compile-flags: -Zmiri-symbolic-alignment-check #![feature(never_type)] -#![allow(unconditional_panic, non_fmt_panic)] +#![allow(unconditional_panic, non_fmt_panics)] use std::panic::{catch_unwind, AssertUnwindSafe}; use std::cell::Cell; From 811423e76126c7c60651ced211241dd2cc796a05 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 10 Jul 2021 11:51:00 -0500 Subject: [PATCH 2760/5092] Rustup for `#[track_caller]` trait object changes Change test to assert that we get the correct location even through a trait object call. --- rust-version | 2 +- tests/run-pass/track-caller-attribute.rs | 24 ++++++++++++++++-------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/rust-version b/rust-version index 8856f7d0852c..aee5d6ee3ba2 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c5e344f7747dbd7e7d4b209e3c480deb5979a56f +3982eb35cabe3a99194d768d34a92347967c3fa2 diff --git a/tests/run-pass/track-caller-attribute.rs b/tests/run-pass/track-caller-attribute.rs index a9cfd2e0ebde..d1115faa8f75 100644 --- a/tests/run-pass/track-caller-attribute.rs +++ b/tests/run-pass/track-caller-attribute.rs @@ -38,23 +38,31 @@ fn test_fn_ptr() { fn test_trait_obj() { trait Tracked { #[track_caller] - fn handle(&self) { // `fn` here is what the `location` should point at. - let location = std::panic::Location::caller(); - assert_eq!(location.file(), file!()); - // we only call this via trait object, so the def site should *always* be returned - assert_eq!(location.line(), line!() - 4); - assert_eq!(location.column(), 9); + fn handle(&self) -> &'static Location<'static> { + std::panic::Location::caller() } } impl Tracked for () {} impl Tracked for u8 {} + // Test that we get the correct location + // even with a call through a trait object + let tracked: &dyn Tracked = &5u8; - tracked.handle(); + let location = tracked.handle(); + let expected_line = line!() - 1; + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), expected_line); + assert_eq!(location.column(), 28); const TRACKED: &dyn Tracked = &(); - TRACKED.handle(); + let location = TRACKED.handle(); + let expected_line = line!() - 1; + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), expected_line); + assert_eq!(location.column(), 28); + } fn main() { From 0341b8ac846c2846fc2aa20aaabe161cb5a0bae9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 11 Jul 2021 14:18:44 +0200 Subject: [PATCH 2761/5092] fmt: set force_multiline_blocks=true --- benches/helpers/miri_helper.rs | 7 +-- rustfmt.toml | 1 + src/bin/miri.rs | 41 +++++++++------ src/diagnostics.rs | 11 ++-- src/helpers.rs | 9 ++-- src/shims/env.rs | 9 ++-- src/shims/foreign_items.rs | 96 +++++++++++++++++----------------- src/shims/intrinsics.rs | 9 ++-- src/shims/posix/fs.rs | 45 +++++++++------- src/stacked_borrows.rs | 9 ++-- src/vector_clock.rs | 18 ++++--- 11 files changed, 141 insertions(+), 114 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index b26705cb704f..2d27616a3613 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -40,9 +40,10 @@ fn find_sysroot() -> String { let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); match (home, toolchain) { (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain), - _ => option_env!("RUST_SYSROOT") - .expect("need to specify RUST_SYSROOT env var or use rustup or multirust") - .to_owned(), + _ => + option_env!("RUST_SYSROOT") + .expect("need to specify RUST_SYSROOT env var or use rustup or multirust") + .to_owned(), } } diff --git a/rustfmt.toml b/rustfmt.toml index 373caafd106b..be5af7379eae 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -2,3 +2,4 @@ version = "Two" use_small_heuristics = "Max" match_arm_blocks = false match_arm_leading_pipes = "Preserve" +force_multiline_blocks = true diff --git a/src/bin/miri.rs b/src/bin/miri.rs index d593f24c71ab..9dbd5e24aeba 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -203,9 +203,12 @@ fn compile_time_sysroot() -> Option { let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); Some(match (home, toolchain) { (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain), - _ => option_env!("RUST_SYSROOT") - .expect("To build Miri without rustup, set the `RUST_SYSROOT` env var at build time") - .to_owned(), + _ => + option_env!("RUST_SYSROOT") + .expect( + "To build Miri without rustup, set the `RUST_SYSROOT` env var at build time", + ) + .to_owned(), }) } @@ -336,9 +339,10 @@ fn main() { "warn" => miri::IsolatedOp::Reject(miri::RejectOpWith::Warning), "warn-nobacktrace" => miri::IsolatedOp::Reject(miri::RejectOpWith::WarningWithoutBacktrace), - _ => panic!( - "-Zmiri-isolation-error must be `abort`, `hide`, `warn`, or `warn-nobacktrace`" - ), + _ => + panic!( + "-Zmiri-isolation-error must be `abort`, `hide`, `warn`, or `warn-nobacktrace`" + ), }; } "-Zmiri-ignore-leaks" => { @@ -383,10 +387,11 @@ fn main() { let id: u64 = match arg.strip_prefix("-Zmiri-track-pointer-tag=").unwrap().parse() { Ok(id) => id, - Err(err) => panic!( - "-Zmiri-track-pointer-tag requires a valid `u64` argument: {}", - err - ), + Err(err) => + panic!( + "-Zmiri-track-pointer-tag requires a valid `u64` argument: {}", + err + ), }; if let Some(id) = miri::PtrId::new(id) { miri_config.tracked_pointer_tag = Some(id); @@ -422,13 +427,15 @@ fn main() { .parse::() { Ok(rate) if rate >= 0.0 && rate <= 1.0 => rate, - Ok(_) => panic!( - "-Zmiri-compare-exchange-weak-failure-rate must be between `0.0` and `1.0`" - ), - Err(err) => panic!( - "-Zmiri-compare-exchange-weak-failure-rate requires a `f64` between `0.0` and `1.0`: {}", - err - ), + Ok(_) => + panic!( + "-Zmiri-compare-exchange-weak-failure-rate must be between `0.0` and `1.0`" + ), + Err(err) => + panic!( + "-Zmiri-compare-exchange-weak-failure-rate requires a `f64` between `0.0` and `1.0`: {}", + err + ), }; miri_config.cmpxchg_weak_failure_rate = rate; } diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 887b2ac4b378..4476ce237ff4 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -43,11 +43,12 @@ impl fmt::Display for TerminationInfo { Deadlock => write!(f, "the evaluated program deadlocked"), MultipleSymbolDefinitions { link_name, .. } => write!(f, "multiple definitions of symbol `{}`", link_name), - SymbolShimClashing { link_name, .. } => write!( - f, - "found `{}` symbol definition that clashes with a built-in shim", - link_name - ), + SymbolShimClashing { link_name, .. } => + write!( + f, + "found `{}` symbol definition that clashes with a built-in shim", + link_name + ), } } } diff --git a/src/helpers.rs b/src/helpers.rs index a6e66c3dbd38..057684562fdb 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -498,10 +498,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match err_kind { NotFound => "ERROR_FILE_NOT_FOUND", PermissionDenied => "ERROR_ACCESS_DENIED", - _ => throw_unsup_format!( - "io error {:?} cannot be translated into a raw os error", - err_kind - ), + _ => + throw_unsup_format!( + "io error {:?} cannot be translated into a raw os error", + err_kind + ), }, )? } else { diff --git a/src/shims/env.rs b/src/shims/env.rs index d99ffb31b5cf..59322b91d679 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -53,10 +53,11 @@ impl<'tcx> EnvVars<'tcx> { "linux" | "macos" => alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx)?, "windows" => alloc_env_var_as_wide_str(name.as_ref(), value.as_ref(), ecx)?, - unsupported => throw_unsup_format!( - "environment support for target OS `{}` not yet available", - unsupported - ), + unsupported => + throw_unsup_format!( + "environment support for target OS `{}` not yet available", + unsupported + ), }; ecx.machine.env_vars.map.insert(OsString::from(name), var_ptr); } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 2de0baf29474..61dca93f0ed4 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -223,54 +223,56 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // First: functions that diverge. let (dest, ret) = match ret { - None => match &*link_name.as_str() { - "miri_start_panic" => { - // `check_shim` happens inside `handle_miri_start_panic`. - this.handle_miri_start_panic(abi, link_name, args, unwind)?; - return Ok(None); - } - // This matches calls to the foreign item `panic_impl`. - // The implementation is provided by the function with the `#[panic_handler]` attribute. - "panic_impl" => { - // We don't use `check_shim` here because we are just forwarding to the lang - // item. Argument count checking will be performed when the returned `Body` is - // called. - this.check_abi_and_shim_symbol_clash(abi, Abi::Rust, link_name)?; - let panic_impl_id = tcx.lang_items().panic_impl().unwrap(); - let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id); - return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); - } - #[rustfmt::skip] - | "exit" - | "ExitProcess" - => { - let exp_abi = if link_name.as_str() == "exit" { - Abi::C { unwind: false } - } else { - Abi::System { unwind: false } - }; - let &[ref code] = this.check_shim(abi, exp_abi, link_name, args)?; - // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway - let code = this.read_scalar(code)?.to_i32()?; - throw_machine_stop!(TerminationInfo::Exit(code.into())); - } - "abort" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - throw_machine_stop!(TerminationInfo::Abort( - "the program aborted execution".to_owned() - )) - } - _ => { - if let Some(body) = this.lookup_exported_symbol(link_name)? { - return Ok(Some(body)); + None => + match &*link_name.as_str() { + "miri_start_panic" => { + // `check_shim` happens inside `handle_miri_start_panic`. + this.handle_miri_start_panic(abi, link_name, args, unwind)?; + return Ok(None); } - this.handle_unsupported(format!( - "can't call (diverging) foreign function: {}", - link_name - ))?; - return Ok(None); - } - }, + // This matches calls to the foreign item `panic_impl`. + // The implementation is provided by the function with the `#[panic_handler]` attribute. + "panic_impl" => { + // We don't use `check_shim` here because we are just forwarding to the lang + // item. Argument count checking will be performed when the returned `Body` is + // called. + this.check_abi_and_shim_symbol_clash(abi, Abi::Rust, link_name)?; + let panic_impl_id = tcx.lang_items().panic_impl().unwrap(); + let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id); + return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); + } + #[rustfmt::skip] + | "exit" + | "ExitProcess" + => { + let exp_abi = if link_name.as_str() == "exit" { + Abi::C { unwind: false } + } else { + Abi::System { unwind: false } + }; + let &[ref code] = this.check_shim(abi, exp_abi, link_name, args)?; + // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway + let code = this.read_scalar(code)?.to_i32()?; + throw_machine_stop!(TerminationInfo::Exit(code.into())); + } + "abort" => { + let &[] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + throw_machine_stop!(TerminationInfo::Abort( + "the program aborted execution".to_owned() + )) + } + _ => { + if let Some(body) = this.lookup_exported_symbol(link_name)? { + return Ok(Some(body)); + } + this.handle_unsupported(format!( + "can't call (diverging) foreign function: {}", + link_name + ))?; + return Ok(None); + } + }, Some(p) => p, }; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index c018dd873810..caef57df8dd2 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -295,10 +295,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.float_to_int_unchecked(val.to_scalar()?.to_f32()?, dest.layout.ty)?, ty::Float(FloatTy::F64) => this.float_to_int_unchecked(val.to_scalar()?.to_f64()?, dest.layout.ty)?, - _ => bug!( - "`float_to_int_unchecked` called with non-float input type {:?}", - val.layout.ty - ), + _ => + bug!( + "`float_to_int_unchecked` called with non-float input type {:?}", + val.layout.ty + ), }; this.write_scalar(res, dest)?; diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index fbef9f304071..bfc6195b3af3 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -434,10 +434,11 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' Err(e) => return match e.raw_os_error() { Some(error) => Ok(error), - None => throw_unsup_format!( - "the error {} couldn't be converted to a return value", - e - ), + None => + throw_unsup_format!( + "the error {} couldn't be converted to a return value", + e + ), }, } } @@ -1203,13 +1204,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(&this.deref_operand(result_op)?.into())?; Ok(0) } - Some(Err(e)) => match e.raw_os_error() { - // return positive error number on error - Some(error) => Ok(error), - None => { - throw_unsup_format!("the error {} couldn't be converted to a return value", e) - } - }, + Some(Err(e)) => + match e.raw_os_error() { + // return positive error number on error + Some(error) => Ok(error), + None => { + throw_unsup_format!( + "the error {} couldn't be converted to a return value", + e + ) + } + }, } } @@ -1294,13 +1299,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(&this.deref_operand(result_op)?.into())?; Ok(0) } - Some(Err(e)) => match e.raw_os_error() { - // return positive error number on error - Some(error) => Ok(error), - None => { - throw_unsup_format!("the error {} couldn't be converted to a return value", e) - } - }, + Some(Err(e)) => + match e.raw_os_error() { + // return positive error number on error + Some(error) => Ok(error), + None => { + throw_unsup_format!( + "the error {} couldn't be converted to a return value", + e + ) + } + }, } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 0b92817c9728..0365e9ca00ed 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -699,10 +699,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn qualify(ty: ty::Ty<'_>, kind: RetagKind) -> Option<(RefKind, bool)> { match ty.kind() { // References are simple. - ty::Ref(_, _, Mutability::Mut) => Some(( - RefKind::Unique { two_phase: kind == RetagKind::TwoPhase }, - kind == RetagKind::FnEntry, - )), + ty::Ref(_, _, Mutability::Mut) => + Some(( + RefKind::Unique { two_phase: kind == RetagKind::TwoPhase }, + kind == RetagKind::FnEntry, + )), ty::Ref(_, _, Mutability::Not) => Some((RefKind::Shared, kind == RetagKind::FnEntry)), // Raw pointers need to be enabled. diff --git a/src/vector_clock.rs b/src/vector_clock.rs index a2e235858d83..74180f25b3bb 100644 --- a/src/vector_clock.rs +++ b/src/vector_clock.rs @@ -186,16 +186,18 @@ impl PartialOrd for VClock { Ordering::Equal => Some(order), // Right has at least 1 element > than the implicit 0, // so the only valid values are Ordering::Less or None. - Ordering::Less => match order { - Ordering::Less | Ordering::Equal => Some(Ordering::Less), - Ordering::Greater => None, - }, + Ordering::Less => + match order { + Ordering::Less | Ordering::Equal => Some(Ordering::Less), + Ordering::Greater => None, + }, // Left has at least 1 element > than the implicit 0, // so the only valid values are Ordering::Greater or None. - Ordering::Greater => match order { - Ordering::Greater | Ordering::Equal => Some(Ordering::Greater), - Ordering::Less => None, - }, + Ordering::Greater => + match order { + Ordering::Greater | Ordering::Equal => Some(Ordering::Greater), + Ordering::Less => None, + }, } } From cffa1d325c7c5a0d9e28f0419d05cf0afe1d3504 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 11 Jul 2021 14:27:07 +0200 Subject: [PATCH 2762/5092] fmt cargo-miri --- cargo-miri/bin.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 1a7552c5d9e0..23546988daa8 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -528,9 +528,10 @@ fn phase_cargo_miri(mut args: env::Args) { Some("run") => MiriCommand::Run, Some("setup") => MiriCommand::Setup, // Invalid command. - _ => show_error(format!( - "`cargo miri` supports the following subcommands: `run`, `test`, and `setup`." - )), + _ => + show_error(format!( + "`cargo miri` supports the following subcommands: `run`, `test`, and `setup`." + )), }; let verbose = has_arg_flag("-v"); @@ -1086,8 +1087,9 @@ fn main() { )); } } - _ => show_error(format!( - "`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`" - )), + _ => + show_error(format!( + "`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`" + )), } } From a1233a721d0832071a2c1b1a95895cc0b924b553 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 15 Jul 2021 20:33:08 +0200 Subject: [PATCH 2763/5092] adjust Miri to Pointer type overhaul --- src/bin/miri.rs | 14 +- src/data_race.rs | 105 ++++----- src/diagnostics.rs | 2 +- src/eval.rs | 27 ++- src/helpers.rs | 98 ++++---- src/intptrcast.rs | 99 ++++---- src/lib.rs | 5 +- src/machine.rs | 199 ++++++++-------- src/mono_hash_map.rs | 24 +- src/operator.rs | 14 +- src/shims/backtrace.rs | 42 ++-- src/shims/env.rs | 102 ++++---- src/shims/foreign_items.rs | 73 +++--- src/shims/intrinsics.rs | 2 +- src/shims/mod.rs | 14 +- src/shims/os_str.rs | 49 ++-- src/shims/panic.rs | 11 +- src/shims/posix/foreign_items.rs | 39 ++-- src/shims/posix/fs.rs | 51 ++-- src/shims/posix/linux/foreign_items.rs | 4 +- src/shims/posix/linux/sync.rs | 23 +- src/shims/posix/macos/dlsym.rs | 2 +- src/shims/posix/macos/foreign_items.rs | 21 +- src/shims/posix/sync.rs | 11 +- src/shims/posix/thread.rs | 10 +- src/shims/time.rs | 7 +- src/shims/tls.rs | 33 +-- src/shims/windows/foreign_items.rs | 28 +-- src/stacked_borrows.rs | 217 +++++++++++------- src/sync.rs | 14 +- src/thread.rs | 36 ++- .../deref-partially-dangling.rs | 2 +- .../dangling_pointers/dyn_size.rs | 2 +- .../maybe_null_pointer_deref_zst.rs | 2 +- .../maybe_null_pointer_write_zst.rs | 2 +- .../dangling_pointers/out_of_bounds_read1.rs | 2 +- .../dangling_pointers/out_of_bounds_read2.rs | 2 +- .../intrinsics/out_of_bounds_ptr_1.rs | 2 +- .../intrinsics/out_of_bounds_ptr_2.rs | 2 +- .../intrinsics/ptr_offset_ptr_plus_0.rs | 2 +- tests/compile-fail/null_pointer_deref_zst.rs | 2 +- tests/compile-fail/null_pointer_write_zst.rs | 3 +- .../stacked_borrows/issue-miri-1050-1.rs | 2 +- .../static_memory_modification.rs | 2 +- tests/compile-fail/zst1.rs | 2 +- tests/compile-fail/zst3.rs | 2 +- 46 files changed, 749 insertions(+), 658 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 9dbd5e24aeba..5a8f07263f35 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -10,6 +10,7 @@ extern crate rustc_session; use std::convert::TryFrom; use std::env; +use std::num::NonZeroU64; use std::path::PathBuf; use std::rc::Rc; use std::str::FromStr; @@ -412,11 +413,16 @@ fn main() { } } arg if arg.starts_with("-Zmiri-track-alloc-id=") => { - let id: u64 = match arg.strip_prefix("-Zmiri-track-alloc-id=").unwrap().parse() + let id = match arg + .strip_prefix("-Zmiri-track-alloc-id=") + .unwrap() + .parse() + .ok() + .and_then(NonZeroU64::new) { - Ok(id) => id, - Err(err) => - panic!("-Zmiri-track-alloc-id requires a valid `u64` argument: {}", err), + Some(id) => id, + None => + panic!("-Zmiri-track-alloc-id requires a valid non-zero `u64` argument"), }; miri_config.tracked_alloc_id = Some(miri::AllocId(id)); } diff --git a/src/data_race.rs b/src/data_race.rs index cb7b1fc6dbe0..6a64c1cb6936 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -73,9 +73,9 @@ use rustc_middle::{mir, ty::layout::TyAndLayout}; use rustc_target::abi::Size; use crate::{ - ImmTy, Immediate, InterpResult, MPlaceTy, MemPlaceMeta, MemoryKind, MiriEvalContext, - MiriEvalContextExt, MiriMemoryKind, OpTy, Pointer, RangeMap, Scalar, ScalarMaybeUninit, Tag, - ThreadId, VClock, VTimestamp, VectorIdx, + AllocId, AllocRange, ImmTy, Immediate, InterpResult, MPlaceTy, MemPlaceMeta, MemoryKind, + MiriEvalContext, MiriEvalContextExt, MiriMemoryKind, OpTy, Pointer, RangeMap, Scalar, + ScalarMaybeUninit, Tag, ThreadId, VClock, VTimestamp, VectorIdx, }; pub type AllocExtra = VClockAlloc; @@ -561,7 +561,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { if lt { &rhs } else { &old } }; - this.allow_data_races_mut(|this| this.write_immediate_to_mplace(**new_val, place))?; + this.allow_data_races_mut(|this| this.write_immediate(**new_val, &(*place).into()))?; this.validate_atomic_rmw(&place, atomic)?; @@ -713,18 +713,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { Ok(()) } } - - fn reset_vector_clocks(&mut self, ptr: Pointer, size: Size) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - if let Some(data_race) = &mut this.memory.extra.data_race { - if data_race.multi_threaded.get() { - let alloc_meta = - this.memory.get_alloc_extra_mut(ptr.alloc_id)?.0.data_race.as_mut().unwrap(); - alloc_meta.reset_clocks(ptr.offset, size); - } - } - Ok(()) - } } /// Vector clock metadata for a logical memory allocation. @@ -769,14 +757,6 @@ impl VClockAlloc { } } - fn reset_clocks(&mut self, offset: Size, len: Size) { - let alloc_ranges = self.alloc_ranges.get_mut(); - for (_, range) in alloc_ranges.iter_mut(offset, len) { - // Reset the portion of the range - *range = MemoryCellClocks::new(0, VectorIdx::MAX_INDEX); - } - } - // Find an index, if one exists where the value // in `l` is greater than the value in `r`. fn find_gt_index(l: &VClock, r: &VClock) -> Option { @@ -820,8 +800,7 @@ impl VClockAlloc { range: &MemoryCellClocks, action: &str, is_atomic: bool, - pointer: Pointer, - len: Size, + ptr_dbg: Pointer, ) -> InterpResult<'tcx> { let (current_index, current_clocks) = global.current_thread_state(); let write_clock; @@ -863,15 +842,12 @@ impl VClockAlloc { // Throw the data-race detection. throw_ub_format!( - "Data race detected between {} on {} and {} on {}, memory({:?},offset={},size={})\ - \n(current vector clock = {:?}, conflicting timestamp = {:?})", + "Data race detected between {} on {} and {} on {} at {:?} (current vector clock = {:?}, conflicting timestamp = {:?})", action, current_thread_info, other_action, other_thread_info, - pointer.alloc_id, - pointer.offset.bytes(), - len.bytes(), + ptr_dbg, current_clocks.clock, other_clock ) @@ -884,17 +860,23 @@ impl VClockAlloc { /// atomic read operations. pub fn read<'tcx>( &self, - pointer: Pointer, - len: Size, + alloc_id: AllocId, + range: AllocRange, global: &GlobalState, ) -> InterpResult<'tcx> { if global.multi_threaded.get() { let (index, clocks) = global.current_thread_state(); let mut alloc_ranges = self.alloc_ranges.borrow_mut(); - for (_, range) in alloc_ranges.iter_mut(pointer.offset, len) { + for (offset, range) in alloc_ranges.iter_mut(range.start, range.size) { if let Err(DataRace) = range.read_race_detect(&*clocks, index) { // Report data-race. - return Self::report_data_race(global, range, "Read", false, pointer, len); + return Self::report_data_race( + global, + range, + "Read", + false, + Pointer::new(alloc_id, offset), + ); } } Ok(()) @@ -906,14 +888,14 @@ impl VClockAlloc { // Shared code for detecting data-races on unique access to a section of memory fn unique_access<'tcx>( &mut self, - pointer: Pointer, - len: Size, + alloc_id: AllocId, + range: AllocRange, write_type: WriteType, global: &mut GlobalState, ) -> InterpResult<'tcx> { if global.multi_threaded.get() { let (index, clocks) = global.current_thread_state(); - for (_, range) in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { + for (offset, range) in self.alloc_ranges.get_mut().iter_mut(range.start, range.size) { if let Err(DataRace) = range.write_race_detect(&*clocks, index, write_type) { // Report data-race return Self::report_data_race( @@ -921,8 +903,7 @@ impl VClockAlloc { range, write_type.get_descriptor(), false, - pointer, - len, + Pointer::new(alloc_id, offset), ); } } @@ -938,11 +919,11 @@ impl VClockAlloc { /// operation pub fn write<'tcx>( &mut self, - pointer: Pointer, - len: Size, + alloc_id: AllocId, + range: AllocRange, global: &mut GlobalState, ) -> InterpResult<'tcx> { - self.unique_access(pointer, len, WriteType::Write, global) + self.unique_access(alloc_id, range, WriteType::Write, global) } /// Detect data-races for an unsynchronized deallocate operation, will not perform @@ -951,11 +932,11 @@ impl VClockAlloc { /// operation pub fn deallocate<'tcx>( &mut self, - pointer: Pointer, - len: Size, + alloc_id: AllocId, + range: AllocRange, global: &mut GlobalState, ) -> InterpResult<'tcx> { - self.unique_access(pointer, len, WriteType::Deallocate, global) + self.unique_access(alloc_id, range, WriteType::Deallocate, global) } } @@ -1002,12 +983,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { result } - /// Generic atomic operation implementation, - /// this accesses memory via get_raw instead of - /// get_raw_mut, due to issues calling get_raw_mut - /// for atomic loads from read-only memory. - /// FIXME: is this valid, or should get_raw_mut be used for - /// atomic-stores/atomic-rmw? + /// Generic atomic operation implementation fn validate_atomic_op( &self, place: &MPlaceTy<'tcx, Tag>, @@ -1023,25 +999,24 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let this = self.eval_context_ref(); if let Some(data_race) = &this.memory.extra.data_race { if data_race.multi_threaded.get() { + let size = place.layout.size; + let (alloc_id, base_offset, ptr) = this.memory.ptr_get_alloc(place.ptr)?; // Load and log the atomic operation. // Note that atomic loads are possible even from read-only allocations, so `get_alloc_extra_mut` is not an option. - let place_ptr = place.ptr.assert_ptr(); - let size = place.layout.size; let alloc_meta = - &this.memory.get_alloc_extra(place_ptr.alloc_id)?.data_race.as_ref().unwrap(); + &this.memory.get_alloc_extra(alloc_id)?.data_race.as_ref().unwrap(); log::trace!( - "Atomic op({}) with ordering {:?} on memory({:?}, offset={}, size={})", + "Atomic op({}) with ordering {:?} on {:?} (size={})", description, &atomic, - place_ptr.alloc_id, - place_ptr.offset.bytes(), + ptr, size.bytes() ); // Perform the atomic operation. data_race.maybe_perform_sync_operation(|index, mut clocks| { - for (_, range) in - alloc_meta.alloc_ranges.borrow_mut().iter_mut(place_ptr.offset, size) + for (offset, range) in + alloc_meta.alloc_ranges.borrow_mut().iter_mut(base_offset, size) { if let Err(DataRace) = op(range, &mut *clocks, index, atomic) { mem::drop(clocks); @@ -1050,8 +1025,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { range, description, true, - place_ptr, - size, + Pointer::new(alloc_id, offset), ) .map(|_| true); } @@ -1063,12 +1037,11 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // Log changes to atomic memory. if log::log_enabled!(log::Level::Trace) { - for (_, range) in alloc_meta.alloc_ranges.borrow().iter(place_ptr.offset, size) + for (_offset, range) in alloc_meta.alloc_ranges.borrow().iter(base_offset, size) { log::trace!( - "Updated atomic memory({:?}, offset={}, size={}) to {:#?}", - place.ptr.assert_ptr().alloc_id, - place_ptr.offset.bytes(), + "Updated atomic memory({:?}, size={}) to {:#?}", + ptr, size.bytes(), range.atomic_ops ); diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 4476ce237ff4..b5b75a7fc318 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -134,7 +134,7 @@ pub fn report_error<'tcx, 'mir>( let helps = match e.kind() { Unsupported(UnsupportedOpInfo::NoMirFor(..)) => vec![(None, format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`"))], - Unsupported(UnsupportedOpInfo::ReadBytesAsPointer | UnsupportedOpInfo::ThreadLocalStatic(_) | UnsupportedOpInfo::ReadExternStatic(_)) => + Unsupported(UnsupportedOpInfo::ThreadLocalStatic(_) | UnsupportedOpInfo::ReadExternStatic(_)) => panic!("Error should never be raised by Miri: {:?}", e.kind()), Unsupported(_) => vec![(None, format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"))], diff --git a/src/eval.rs b/src/eval.rs index f728248c3a72..ae9ff9c1f5a4 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -164,7 +164,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Third argument (`argv`): created from `config.args`. let argv = { // Put each argument in memory, collect pointers. - let mut argvs = Vec::>::new(); + let mut argvs = Vec::>::new(); for arg in config.args.iter() { // Make space for `0` terminator. let size = u64::try_from(arg.len()).unwrap().checked_add(1).unwrap(); @@ -172,7 +172,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let arg_place = ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Machine.into())?; ecx.write_os_str_to_c_str(OsStr::new(arg), arg_place.ptr, size)?; - argvs.push(arg_place.ptr); + ecx.mark_immutable(&*arg_place); + argvs.push(arg_place.to_ref(&ecx)); } // Make an array with all these pointers, in the Miri memory. let argvs_layout = ecx.layout_of( @@ -181,24 +182,26 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into())?; for (idx, arg) in argvs.into_iter().enumerate() { let place = ecx.mplace_field(&argvs_place, idx)?; - ecx.write_scalar(arg, &place.into())?; + ecx.write_immediate(arg, &place.into())?; } - ecx.memory.mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?; + ecx.mark_immutable(&*argvs_place); // A pointer to that place is the 3rd argument for main. - let argv = argvs_place.ptr; + let argv = argvs_place.to_ref(&ecx); // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`. { let argc_place = ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into())?; ecx.write_scalar(argc, &argc_place.into())?; - ecx.machine.argc = Some(argc_place.ptr); + ecx.mark_immutable(&*argc_place); + ecx.machine.argc = Some(*argc_place); let argv_place = ecx.allocate( ecx.layout_of(tcx.mk_imm_ptr(tcx.types.unit))?, MiriMemoryKind::Machine.into(), )?; - ecx.write_scalar(argv, &argv_place.into())?; - ecx.machine.argv = Some(argv_place.ptr); + ecx.write_immediate(argv, &argv_place.into())?; + ecx.mark_immutable(&*argv_place); + ecx.machine.argv = Some(*argv_place); } // Store command line as UTF-16 for Windows `GetCommandLineW`. { @@ -217,12 +220,13 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let cmd_type = tcx.mk_array(tcx.types.u16, u64::try_from(cmd_utf16.len()).unwrap()); let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Machine.into())?; - ecx.machine.cmd_line = Some(cmd_place.ptr); + ecx.machine.cmd_line = Some(*cmd_place); // Store the UTF-16 string. We just allocated so we know the bounds are fine. for (idx, &c) in cmd_utf16.iter().enumerate() { let place = ecx.mplace_field(&cmd_place, idx)?; ecx.write_scalar(Scalar::from_u16(c), &place.into())?; } + ecx.mark_immutable(&*cmd_place); } argv }; @@ -233,7 +237,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ecx.call_function( start_instance, Abi::Rust, - &[main_ptr.into(), argc.into(), argv.into()], + &[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv], Some(&ret_place.into()), StackPopCleanup::None { cleanup: true }, )?; @@ -285,8 +289,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> } ecx.process_diagnostics(info); } - let return_code = - ecx.read_scalar(&ret_place.into())?.check_init()?.to_machine_isize(&ecx)?; + let return_code = ecx.read_scalar(&ret_place.into())?.to_machine_isize(&ecx)?; Ok(return_code) })(); diff --git a/src/helpers.rs b/src/helpers.rs index 057684562fdb..363aefa62d2f 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -53,18 +53,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Evaluates the scalar at the specified path. Returns Some(val) /// if the path could be resolved, and None otherwise - fn eval_path_scalar(&mut self, path: &[&str]) -> InterpResult<'tcx, ScalarMaybeUninit> { + fn eval_path_scalar(&mut self, path: &[&str]) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let instance = this.resolve_path(path); let cid = GlobalId { instance, promoted: None }; let const_val = this.eval_to_allocation(cid)?; let const_val = this.read_scalar(&const_val.into())?; - return Ok(const_val); + return Ok(const_val.check_init()?); } /// Helper function to get a `libc` constant as a `Scalar`. fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar> { - self.eval_context_mut().eval_path_scalar(&["libc", name])?.check_init() + self.eval_context_mut().eval_path_scalar(&["libc", name]) } /// Helper function to get a `libc` constant as an `i32`. @@ -75,9 +75,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function to get a `windows` constant as a `Scalar`. fn eval_windows(&mut self, module: &str, name: &str) -> InterpResult<'tcx, Scalar> { - self.eval_context_mut() - .eval_path_scalar(&["std", "sys", "windows", module, name])? - .check_init() + self.eval_context_mut().eval_path_scalar(&["std", "sys", "windows", module, name]) } /// Helper function to get a `windows` constant as an `u64`. @@ -107,17 +105,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest) } - /// Test if this immediate equals 0. - fn is_null(&self, val: Scalar) -> InterpResult<'tcx, bool> { + /// Test if this pointer equals 0. + fn ptr_is_null(&self, ptr: Pointer>) -> InterpResult<'tcx, bool> { let this = self.eval_context_ref(); let null = Scalar::null_ptr(this); - this.ptr_eq(val, null) - } - - /// Turn a Scalar into an Option - fn test_null(&self, val: Scalar) -> InterpResult<'tcx, Option>> { - let this = self.eval_context_ref(); - Ok(if this.is_null(val)? { None } else { Some(val) }) + this.ptr_eq(Scalar::from_maybe_pointer(ptr, this), null) } /// Get the `Place` for a local @@ -128,7 +120,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Generate some random bytes, and write them to `dest`. - fn gen_random(&mut self, ptr: Scalar, len: u64) -> InterpResult<'tcx> { + fn gen_random(&mut self, ptr: Pointer>, len: u64) -> InterpResult<'tcx> { // Some programs pass in a null pointer and a length of 0 // to their platform's random-generation function (e.g. getrandom()) // on Linux. For compatibility with these programs, we don't perform @@ -195,13 +187,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - /// Visits the memory covered by `place`, sensitive to freezing: the 3rd parameter - /// will be true if this is frozen, false if this is in an `UnsafeCell`. + /// Visits the memory covered by `place`, sensitive to freezing: the 2nd parameter + /// of `action` will be true if this is frozen, false if this is in an `UnsafeCell`. + /// The range is relative to `place`. + /// + /// Assumes that the `place` has a proper pointer in it. fn visit_freeze_sensitive( &self, place: &MPlaceTy<'tcx, Tag>, size: Size, - mut action: impl FnMut(Pointer, Size, bool) -> InterpResult<'tcx>, + mut action: impl FnMut(AllocRange, bool) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); trace!("visit_frozen(place={:?}, size={:?})", *place, size); @@ -214,29 +209,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Store how far we proceeded into the place so far. Everything to the left of // this offset has already been handled, in the sense that the frozen parts // have had `action` called on them. - let mut end_ptr = place.ptr.assert_ptr(); + let ptr = place.ptr.into_pointer_or_addr().unwrap(); + let start_offset = ptr.into_parts().1 as Size; // we just compare offsets, the abs. value never matters + let mut cur_offset = start_offset; // Called when we detected an `UnsafeCell` at the given offset and size. - // Calls `action` and advances `end_ptr`. - let mut unsafe_cell_action = |unsafe_cell_ptr: Scalar, unsafe_cell_size: Size| { - let unsafe_cell_ptr = unsafe_cell_ptr.assert_ptr(); - debug_assert_eq!(unsafe_cell_ptr.alloc_id, end_ptr.alloc_id); - debug_assert_eq!(unsafe_cell_ptr.tag, end_ptr.tag); + // Calls `action` and advances `cur_ptr`. + let mut unsafe_cell_action = |unsafe_cell_ptr: Pointer>, + unsafe_cell_size: Size| { + let unsafe_cell_ptr = unsafe_cell_ptr.into_pointer_or_addr().unwrap(); + debug_assert_eq!(unsafe_cell_ptr.provenance, ptr.provenance); // We assume that we are given the fields in increasing offset order, // and nothing else changes. - let unsafe_cell_offset = unsafe_cell_ptr.offset; - let end_offset = end_ptr.offset; - assert!(unsafe_cell_offset >= end_offset); - let frozen_size = unsafe_cell_offset - end_offset; - // Everything between the end_ptr and this `UnsafeCell` is frozen. + let unsafe_cell_offset = unsafe_cell_ptr.into_parts().1 as Size; // we just compare offsets, the abs. value never matters + assert!(unsafe_cell_offset >= cur_offset); + let frozen_size = unsafe_cell_offset - cur_offset; + // Everything between the cur_ptr and this `UnsafeCell` is frozen. if frozen_size != Size::ZERO { - action(end_ptr, frozen_size, /*frozen*/ true)?; + action(alloc_range(cur_offset - start_offset, frozen_size), /*frozen*/ true)?; } + cur_offset += frozen_size; // This `UnsafeCell` is NOT frozen. if unsafe_cell_size != Size::ZERO { - action(unsafe_cell_ptr, unsafe_cell_size, /*frozen*/ false)?; + action( + alloc_range(cur_offset - start_offset, unsafe_cell_size), + /*frozen*/ false, + )?; } - // Update end end_ptr. - end_ptr = unsafe_cell_ptr.wrapping_offset(unsafe_cell_size, this); + cur_offset += unsafe_cell_size; // Done Ok(()) }; @@ -264,7 +263,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // The part between the end_ptr and the end of the place is also frozen. // So pretend there is a 0-sized `UnsafeCell` at the end. - unsafe_cell_action(place.ptr.ptr_wrapping_offset(size, this), Size::ZERO)?; + unsafe_cell_action(place.ptr.wrapping_offset(size, this), Size::ZERO)?; // Done! return Ok(()); @@ -347,7 +346,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Gather the subplaces and sort them before visiting. let mut places = fields.collect::>>>()?; - places.sort_by_key(|place| place.ptr.assert_ptr().offset); + // we just compare offsets, the abs. value never matters + places.sort_by_key(|place| { + place.ptr.into_pointer_or_addr().unwrap().into_parts().1 as Size + }); self.walk_aggregate(place, places.into_iter().map(Ok)) } FieldsShape::Union { .. } | FieldsShape::Primitive => { @@ -379,9 +381,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut offset = Size::from_bytes(0); for &imm in imms { - this.write_immediate_to_mplace( + this.write_immediate( *imm, - &place.offset(offset, MemPlaceMeta::None, imm.layout, &*this.tcx)?, + &place.offset(offset, MemPlaceMeta::None, imm.layout, &*this.tcx)?.into(), )?; offset += imm.layout.size; } @@ -567,12 +569,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Parse a `timespec` struct and return it as a `std::time::Duration`. It returns `None` /// if the value in the `timespec` struct is invalid. Some libc functions will return /// `EINVAL` in this case. - fn read_timespec( - &mut self, - timespec_ptr_op: &OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, Option> { + fn read_timespec(&mut self, tp: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); - let tp = this.deref_operand(timespec_ptr_op)?; let seconds_place = this.mplace_field(&tp, 0)?; let seconds_scalar = this.read_scalar(&seconds_place.into())?; let seconds = seconds_scalar.to_machine_isize(this)?; @@ -593,14 +591,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) } - fn read_c_str<'a>(&'a self, sptr: Scalar) -> InterpResult<'tcx, &'a [u8]> + fn read_c_str<'a>(&'a self, ptr: Pointer>) -> InterpResult<'tcx, &'a [u8]> where 'tcx: 'a, 'mir: 'a, { let this = self.eval_context_ref(); let size1 = Size::from_bytes(1); - let ptr = this.force_ptr(sptr)?; // We need to read at least 1 byte, so we can eagerly get a ptr. // Step 1: determine the length. let mut len = Size::ZERO; @@ -620,12 +617,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.memory.read_bytes(ptr.into(), len) } - fn read_wide_str(&self, sptr: Scalar) -> InterpResult<'tcx, Vec> { + fn read_wide_str(&self, mut ptr: Pointer>) -> InterpResult<'tcx, Vec> { let this = self.eval_context_ref(); let size2 = Size::from_bytes(2); let align2 = Align::from_bytes(2).unwrap(); - let mut ptr = this.force_ptr(sptr)?; // We need to read at least 1 wchar, so we can eagerly get a ptr. let mut wchars = Vec::new(); loop { // FIXME: We are re-getting the allocation each time around the loop. @@ -709,6 +705,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx self.check_abi_and_shim_symbol_clash(abi, exp_abi, link_name)?; check_arg_count(args) } + + /// Mark a machine allocation that was just created as immutable. + fn mark_immutable(&mut self, mplace: &MemPlace) { + let this = self.eval_context_mut(); + this.memory + .mark_immutable(mplace.ptr.into_pointer_or_addr().unwrap().provenance.alloc_id) + .unwrap(); + } } /// Check that the number of args is what we expect. diff --git a/src/intptrcast.rs b/src/intptrcast.rs index b5a77b08ff52..665a13418401 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -38,55 +38,55 @@ impl Default for GlobalState { } impl<'mir, 'tcx> GlobalState { - pub fn int_to_ptr( - int: u64, + pub fn ptr_from_addr( + addr: u64, memory: &Memory<'mir, 'tcx, Evaluator<'mir, 'tcx>>, - ) -> InterpResult<'tcx, Pointer> { + ) -> Pointer> { + trace!("Casting 0x{:x} to a pointer", addr); let global_state = memory.extra.intptrcast.borrow(); - let pos = global_state.int_to_ptr_map.binary_search_by_key(&int, |(addr, _)| *addr); + let pos = global_state.int_to_ptr_map.binary_search_by_key(&addr, |(addr, _)| *addr); - // The int must be in-bounds after being cast to a pointer, so we error - // with `CheckInAllocMsg::InboundsTest`. - Ok(match pos { - Ok(pos) => { - let (_, alloc_id) = global_state.int_to_ptr_map[pos]; - // `int` is equal to the starting address for an allocation, the offset should be - // zero. The pointer is untagged because it was created from a cast - Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged) - } - Err(0) => throw_ub!(DanglingIntPointer(int, CheckInAllocMsg::InboundsTest)), + let alloc_id = match pos { + Ok(pos) => Some(global_state.int_to_ptr_map[pos].1), + Err(0) => None, Err(pos) => { // This is the largest of the adresses smaller than `int`, // i.e. the greatest lower bound (glb) let (glb, alloc_id) = global_state.int_to_ptr_map[pos - 1]; - // This never overflows because `int >= glb` - let offset = int - glb; - // If the offset exceeds the size of the allocation, this access is illegal - if offset <= memory.get_size_and_align(alloc_id, AllocCheck::MaybeDead)?.0.bytes() { - // This pointer is untagged because it was created from a cast - Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged) + // This never overflows because `addr >= glb` + let offset = addr - glb; + // If the offset exceeds the size of the allocation, don't use this `alloc_id`. + if offset + <= memory.get_size_and_align(alloc_id, AllocCheck::MaybeDead).unwrap().0.bytes() + { + Some(alloc_id) } else { - throw_ub!(DanglingIntPointer(int, CheckInAllocMsg::InboundsTest)) + None } } - }) + }; + // Pointers created from integers are untagged. + Pointer::new( + alloc_id.map(|alloc_id| Tag { alloc_id, sb: SbTag::Untagged }), + Size::from_bytes(addr), + ) } - pub fn ptr_to_int( - ptr: Pointer, + fn alloc_base_addr( memory: &Memory<'mir, 'tcx, Evaluator<'mir, 'tcx>>, - ) -> InterpResult<'tcx, u64> { + alloc_id: AllocId, + ) -> u64 { let mut global_state = memory.extra.intptrcast.borrow_mut(); let global_state = &mut *global_state; - let id = ptr.alloc_id; - // There is nothing wrong with a raw pointer being cast to an integer only after - // it became dangling. Hence `MaybeDead`. - let (size, align) = memory.get_size_and_align(id, AllocCheck::MaybeDead)?; - - let base_addr = match global_state.base_addr.entry(id) { + match global_state.base_addr.entry(alloc_id) { Entry::Occupied(entry) => *entry.get(), Entry::Vacant(entry) => { + // There is nothing wrong with a raw pointer being cast to an integer only after + // it became dangling. Hence `MaybeDead`. + let (size, align) = + memory.get_size_and_align(alloc_id, AllocCheck::MaybeDead).unwrap(); + // This allocation does not have a base address yet, pick one. // Leave some space to the previous allocation, to give it some chance to be less aligned. let slack = { @@ -99,11 +99,12 @@ impl<'mir, 'tcx> GlobalState { let base_addr = Self::align_addr(base_addr, align.bytes()); entry.insert(base_addr); trace!( - "Assigning base address {:#x} to allocation {:?} (slack: {}, align: {})", + "Assigning base address {:#x} to allocation {:?} (size: {}, align: {}, slack: {})", base_addr, - id, - slack, + alloc_id, + size.bytes(), align.bytes(), + slack, ); // Remember next base address. If this allocation is zero-sized, leave a gap @@ -111,17 +112,37 @@ impl<'mir, 'tcx> GlobalState { global_state.next_base_addr = base_addr.checked_add(max(size.bytes(), 1)).unwrap(); // Given that `next_base_addr` increases in each allocation, pushing the // corresponding tuple keeps `int_to_ptr_map` sorted - global_state.int_to_ptr_map.push((base_addr, id)); + global_state.int_to_ptr_map.push((base_addr, alloc_id)); base_addr } - }; + } + } + + /// Convert a relative (tcx) pointer to an absolute address. + pub fn rel_ptr_to_addr( + memory: &Memory<'mir, 'tcx, Evaluator<'mir, 'tcx>>, + ptr: Pointer, + ) -> u64 { + let (alloc_id, offset) = ptr.into_parts(); // offset is relative + let base_addr = GlobalState::alloc_base_addr(memory, alloc_id); - // Sanity check that the base address is aligned. - debug_assert_eq!(base_addr % align.bytes(), 0); // Add offset with the right kind of pointer-overflowing arithmetic. let dl = memory.data_layout(); - Ok(dl.overflowing_offset(base_addr, ptr.offset.bytes()).0) + dl.overflowing_offset(base_addr, offset.bytes()).0 + } + + pub fn abs_ptr_to_rel( + memory: &Memory<'mir, 'tcx, Evaluator<'mir, 'tcx>>, + ptr: Pointer, + ) -> Size { + let (tag, addr) = ptr.into_parts(); // addr is absolute + let base_addr = GlobalState::alloc_base_addr(memory, tag.alloc_id); + + // Wrapping "addr - base_addr" + let dl = memory.data_layout(); + let neg_base_addr = (base_addr as i64).wrapping_neg(); + Size::from_bytes(dl.overflowing_signed_offset(addr.bytes(), neg_base_addr).0) } /// Shifts `addr` to make it aligned with `align` by rounding `addr` to the smallest multiple diff --git a/src/lib.rs b/src/lib.rs index 8c0a19b6dfbd..f8d8aacce3c9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,13 +65,14 @@ pub use crate::eval::{ pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; pub use crate::machine::{ AllocExtra, Evaluator, FrameData, MemoryExtra, MiriEvalContext, MiriEvalContextExt, - MiriMemoryKind, NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, + MiriMemoryKind, Tag, NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, }; pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ - CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, Stack, Stacks, Tag, + CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, SbTag, Stack, + Stacks, }; pub use crate::sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId}; pub use crate::thread::{ diff --git a/src/machine.rs b/src/machine.rs index 999e21796d30..90e3d06aba99 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -119,6 +119,35 @@ impl fmt::Display for MiriMemoryKind { } } +/// Pointer provenance (tag). +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Tag { + pub alloc_id: AllocId, + // Stacked Borrows tag. + pub sb: SbTag, +} + +impl Provenance for Tag { + const OFFSET_IS_ADDR: bool = true; + + fn fmt(ptr: &Pointer, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let (tag, addr) = ptr.into_parts(); // address is absolute + write!(f, "0x{:x}", addr.bytes())?; + // Forward `alternate` flag to `alloc_id` printing. + if f.alternate() { + write!(f, "[{:#?}]", tag.alloc_id)?; + } else { + write!(f, "[{:?}]", tag.alloc_id)?; + } + // Print Stacked Borrows tag. + write!(f, "{:?}", tag.sb) + } + + fn get_alloc_id(self) -> AllocId { + self.alloc_id + } +} + /// Extra per-allocation data #[derive(Debug, Clone)] pub struct AllocExtra { @@ -136,8 +165,8 @@ pub struct MemoryExtra { pub data_race: Option, pub intptrcast: intptrcast::MemoryExtra, - /// Mapping extern static names to their canonical allocation. - extern_statics: FxHashMap, + /// Mapping extern static names to their base pointer. + extern_statics: FxHashMap>, /// The random number generator used for resolving non-determinism. /// Needs to be queried by ptr_to_int, hence needs interior mutability. @@ -183,11 +212,10 @@ impl MemoryExtra { fn add_extern_static<'tcx, 'mir>( this: &mut MiriEvalContext<'mir, 'tcx>, name: &str, - ptr: Scalar, + ptr: Pointer>, ) { - let ptr = ptr.assert_ptr(); - assert_eq!(ptr.offset, Size::ZERO); - this.memory.extra.extern_statics.try_insert(Symbol::intern(name), ptr.alloc_id).unwrap(); + let ptr = ptr.into_pointer_or_addr().unwrap(); + this.memory.extra.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap(); } /// Sets up the "extern statics" for this machine. @@ -257,9 +285,9 @@ pub struct Evaluator<'mir, 'tcx> { /// Program arguments (`Option` because we can only initialize them after creating the ecx). /// These are *pointers* to argc/argv because macOS. /// We also need the full command line as one string because of Windows. - pub(crate) argc: Option>, - pub(crate) argv: Option>, - pub(crate) cmd_line: Option>, + pub(crate) argc: Option>, + pub(crate) argv: Option>, + pub(crate) cmd_line: Option>, /// TLS state. pub(crate) tls: TlsData<'tcx>, @@ -487,82 +515,107 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { Ok(()) } - fn thread_local_static_alloc_id( + fn thread_local_static_base_pointer( ecx: &mut InterpCx<'mir, 'tcx, Self>, def_id: DefId, - ) -> InterpResult<'tcx, AllocId> { - ecx.get_or_create_thread_local_alloc_id(def_id) + ) -> InterpResult<'tcx, Pointer> { + ecx.get_or_create_thread_local_alloc(def_id) } - fn extern_static_alloc_id( + fn extern_static_base_pointer( memory: &Memory<'mir, 'tcx, Self>, def_id: DefId, - ) -> InterpResult<'tcx, AllocId> { + ) -> InterpResult<'tcx, Pointer> { let attrs = memory.tcx.get_attrs(def_id); let link_name = match memory.tcx.sess.first_attr_value_str_by_name(&attrs, sym::link_name) { Some(name) => name, None => memory.tcx.item_name(def_id), }; - if let Some(&id) = memory.extra.extern_statics.get(&link_name) { - Ok(id) + if let Some(&ptr) = memory.extra.extern_statics.get(&link_name) { + Ok(ptr) } else { throw_unsup_format!("`extern` static {:?} is not supported by Miri", def_id) } } fn init_allocation_extra<'b>( - memory_extra: &MemoryExtra, + mem: &Memory<'mir, 'tcx, Self>, id: AllocId, alloc: Cow<'b, Allocation>, kind: Option>, - ) -> (Cow<'b, Allocation>, Self::PointerTag) { - if Some(id) == memory_extra.tracked_alloc_id { + ) -> Cow<'b, Allocation> { + if Some(id) == mem.extra.tracked_alloc_id { register_diagnostic(NonHaltingDiagnostic::CreatedAlloc(id)); } let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); - let (stacks, base_tag) = if let Some(stacked_borrows) = &memory_extra.stacked_borrows { - let (stacks, base_tag) = - Stacks::new_allocation(id, alloc.size(), stacked_borrows, kind); - (Some(stacks), base_tag) + let stacks = if let Some(stacked_borrows) = &mem.extra.stacked_borrows { + Some(Stacks::new_allocation(id, alloc.size(), stacked_borrows, kind)) } else { - // No stacks, no tag. - (None, Tag::Untagged) + None }; - let race_alloc = if let Some(data_race) = &memory_extra.data_race { + let race_alloc = if let Some(data_race) = &mem.extra.data_race { Some(data_race::AllocExtra::new_allocation(&data_race, alloc.size(), kind)) } else { None }; - let mut stacked_borrows = memory_extra.stacked_borrows.as_ref().map(|sb| sb.borrow_mut()); - let alloc: Allocation = alloc.with_tags_and_extra( - |alloc| { - if let Some(stacked_borrows) = &mut stacked_borrows { - // Only globals may already contain pointers at this point - assert_eq!(kind, MiriMemoryKind::Global.into()); - stacked_borrows.global_base_ptr(alloc) - } else { - Tag::Untagged - } - }, + let alloc: Allocation = alloc.convert_tag_add_extra( + &mem.tcx, AllocExtra { stacked_borrows: stacks, data_race: race_alloc }, + |ptr| Evaluator::tag_alloc_base_pointer(mem, ptr), ); - (Cow::Owned(alloc), base_tag) + Cow::Owned(alloc) + } + + fn tag_alloc_base_pointer( + mem: &Memory<'mir, 'tcx, Self>, + ptr: Pointer, + ) -> Pointer { + let absolute_addr = intptrcast::GlobalState::rel_ptr_to_addr(&mem, ptr); + let sb_tag = if let Some(stacked_borrows) = &mem.extra.stacked_borrows { + stacked_borrows.borrow_mut().base_tag(ptr.provenance) + } else { + SbTag::Untagged + }; + Pointer::new(Tag { alloc_id: ptr.provenance, sb: sb_tag }, Size::from_bytes(absolute_addr)) + } + + #[inline(always)] + fn ptr_from_addr( + mem: &Memory<'mir, 'tcx, Self>, + addr: u64, + ) -> Pointer> { + intptrcast::GlobalState::ptr_from_addr(addr, mem) + } + + /// Convert a pointer with provenance into an allocation-offset pair, + /// or a `None` with an absolute address if that conversion is not possible. + fn ptr_get_alloc( + mem: &Memory<'mir, 'tcx, Self>, + ptr: Pointer, + ) -> (AllocId, Size) { + let rel = intptrcast::GlobalState::abs_ptr_to_rel(mem, ptr); + (ptr.provenance.alloc_id, rel) } #[inline(always)] fn memory_read( memory_extra: &Self::MemoryExtra, alloc_extra: &AllocExtra, - ptr: Pointer, - size: Size, + tag: Tag, + range: AllocRange, ) -> InterpResult<'tcx> { if let Some(data_race) = &alloc_extra.data_race { - data_race.read(ptr, size, memory_extra.data_race.as_ref().unwrap())?; + data_race.read(tag.alloc_id, range, memory_extra.data_race.as_ref().unwrap())?; } if let Some(stacked_borrows) = &alloc_extra.stacked_borrows { - stacked_borrows.memory_read(ptr, size, memory_extra.stacked_borrows.as_ref().unwrap()) + stacked_borrows.memory_read( + tag.alloc_id, + tag.sb, + range, + memory_extra.stacked_borrows.as_ref().unwrap(), + ) } else { Ok(()) } @@ -572,16 +625,17 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn memory_written( memory_extra: &mut Self::MemoryExtra, alloc_extra: &mut AllocExtra, - ptr: Pointer, - size: Size, + tag: Tag, + range: AllocRange, ) -> InterpResult<'tcx> { if let Some(data_race) = &mut alloc_extra.data_race { - data_race.write(ptr, size, memory_extra.data_race.as_mut().unwrap())?; + data_race.write(tag.alloc_id, range, memory_extra.data_race.as_mut().unwrap())?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { stacked_borrows.memory_written( - ptr, - size, + tag.alloc_id, + tag.sb, + range, memory_extra.stacked_borrows.as_mut().unwrap(), ) } else { @@ -593,19 +647,20 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn memory_deallocated( memory_extra: &mut Self::MemoryExtra, alloc_extra: &mut AllocExtra, - ptr: Pointer, - size: Size, + tag: Tag, + range: AllocRange, ) -> InterpResult<'tcx> { - if Some(ptr.alloc_id) == memory_extra.tracked_alloc_id { - register_diagnostic(NonHaltingDiagnostic::FreedAlloc(ptr.alloc_id)); + if Some(tag.alloc_id) == memory_extra.tracked_alloc_id { + register_diagnostic(NonHaltingDiagnostic::FreedAlloc(tag.alloc_id)); } if let Some(data_race) = &mut alloc_extra.data_race { - data_race.deallocate(ptr, size, memory_extra.data_race.as_mut().unwrap())?; + data_race.deallocate(tag.alloc_id, range, memory_extra.data_race.as_mut().unwrap())?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { stacked_borrows.memory_deallocated( - ptr, - size, + tag.alloc_id, + tag.sb, + range, memory_extra.stacked_borrows.as_mut().unwrap(), ) } else { @@ -613,26 +668,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } } - fn after_static_mem_initialized( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - ptr: Pointer, - size: Size, - ) -> InterpResult<'tcx> { - if ecx.memory.extra.data_race.is_some() { - ecx.reset_vector_clocks(ptr, size)?; - } - Ok(()) - } - - #[inline(always)] - fn tag_global_base_pointer(memory_extra: &MemoryExtra, id: AllocId) -> Self::PointerTag { - if let Some(stacked_borrows) = &memory_extra.stacked_borrows { - stacked_borrows.borrow_mut().global_base_ptr(id) - } else { - Tag::Untagged - } - } - #[inline(always)] fn retag( ecx: &mut InterpCx<'mir, 'tcx, Self>, @@ -701,20 +736,4 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } res } - - #[inline(always)] - fn int_to_ptr( - memory: &Memory<'mir, 'tcx, Self>, - int: u64, - ) -> InterpResult<'tcx, Pointer> { - intptrcast::GlobalState::int_to_ptr(int, memory) - } - - #[inline(always)] - fn ptr_to_int( - memory: &Memory<'mir, 'tcx, Self>, - ptr: Pointer, - ) -> InterpResult<'tcx, u64> { - intptrcast::GlobalState::ptr_to_int(ptr, memory) - } } diff --git a/src/mono_hash_map.rs b/src/mono_hash_map.rs index fb0169920ee2..1ae2083d5661 100644 --- a/src/mono_hash_map.rs +++ b/src/mono_hash_map.rs @@ -72,15 +72,31 @@ impl AllocMap for MonoHashMap { /// returns owned data, that is put into the map and returned. #[inline(always)] fn get_or(&self, k: K, vacant: impl FnOnce() -> Result) -> Result<&V, E> { - let val: *const V = match self.0.borrow_mut().entry(k) { - Entry::Occupied(entry) => &**entry.get(), - Entry::Vacant(entry) => &**entry.insert(Box::new(vacant()?)), - }; + // We cannot hold borrow_mut while calling `vacant`, since that might have to do lookups in this very map. + if let Some(v) = self.0.borrow().get(&k) { + let val: *const V = &**v; + // This is safe because `val` points into a `Box`, that we know will not move and + // will also not be dropped as long as the shared reference `self` is live. + return unsafe { Ok(&*val) }; + } + let new_val = Box::new(vacant()?); + let val: *const V = &**self.0.borrow_mut().try_insert(k, new_val).ok().unwrap(); // This is safe because `val` points into a `Box`, that we know will not move and // will also not be dropped as long as the shared reference `self` is live. unsafe { Ok(&*val) } } + /// Read-only lookup (avoid read-acquiring the RefCell). + fn get(&self, k: K) -> Option<&V> { + let val: *const V = match self.0.borrow().get(&k) { + Some(v) => &**v, + None => return None, + }; + // This is safe because `val` points into a `Box`, that we know will not move and + // will also not be dropped as long as the shared reference `self` is live. + unsafe { Some(&*val) } + } + #[inline(always)] fn get_mut_or(&mut self, k: K, vacant: impl FnOnce() -> Result) -> Result<&mut V, E> { match self.0.get_mut().entry(k) { diff --git a/src/operator.rs b/src/operator.rs index cf92aed9ccb2..59099469a332 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -45,9 +45,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { Lt | Le | Gt | Ge => { // Just compare the integers. - // TODO: Do we really want to *always* do that, even when comparing two live in-bounds pointers? - let left = self.force_bits(left.to_scalar()?, left.layout.size)?; - let right = self.force_bits(right.to_scalar()?, right.layout.size)?; + let left = left.to_scalar()?.to_bits(left.layout.size)?; + let right = right.to_scalar()?.to_bits(right.layout.size)?; let res = match bin_op { Lt => left < right, Le => left <= right, @@ -62,11 +61,11 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { let pointee_ty = left.layout.ty.builtin_deref(true).expect("Offset called on non-ptr type").ty; let ptr = self.ptr_offset_inbounds( - left.to_scalar()?, + self.scalar_to_ptr(left.to_scalar()?), pointee_ty, right.to_scalar()?.to_machine_isize(self)?, )?; - (ptr, false, left.layout.ty) + (Scalar::from_maybe_pointer(ptr, self), false, left.layout.ty) } _ => bug!("Invalid operator on pointers: {:?}", bin_op), @@ -76,9 +75,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { fn ptr_eq(&self, left: Scalar, right: Scalar) -> InterpResult<'tcx, bool> { let size = self.pointer_size(); // Just compare the integers. - // TODO: Do we really want to *always* do that, even when comparing two live in-bounds pointers? - let left = self.force_bits(left, size)?; - let right = self.force_bits(right, size)?; + let left = left.to_bits(size)?; + let right = right.to_bits(size)?; Ok(left == right) } } diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index ec29fef6368f..1ac3a22f7ed3 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -44,9 +44,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // to reconstruct the needed frame information in `handle_miri_resolve_frame`. // Note that we never actually read or write anything from/to this pointer - // all of the data is represented by the pointer value itself. - let mut fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(instance)); - fn_ptr.offset = Size::from_bytes(pos.0); - Scalar::Ptr(fn_ptr) + let fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(instance)); + fn_ptr.wrapping_offset(Size::from_bytes(pos.0), this) }) .collect(); @@ -61,11 +60,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.allocate(this.layout_of(array_ty).unwrap(), MiriMemoryKind::Rust.into())?; for (i, ptr) in ptrs.into_iter().enumerate() { let place = this.mplace_index(&alloc, i as u64)?; - this.write_immediate_to_mplace(ptr.into(), &place)?; + this.write_pointer(ptr, &place.into())?; } this.write_immediate( - Immediate::new_slice(alloc.ptr.into(), len.try_into().unwrap(), this), + Immediate::new_slice( + Scalar::from_maybe_pointer(alloc.ptr, this), + len.try_into().unwrap(), + this, + ), dest, )?; Ok(()) @@ -87,21 +90,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("unknown `miri_resolve_frame` flags {}", flags); } - let ptr = this.force_ptr(this.read_scalar(ptr)?.check_init()?)?; + let ptr = this.read_pointer(ptr)?; + // Take apart the pointer, we need its pieces. + let (alloc_id, offset, ptr) = this.memory.ptr_get_alloc(ptr)?; - let fn_instance = if let Some(GlobalAlloc::Function(instance)) = - this.tcx.get_global_alloc(ptr.alloc_id) - { - instance - } else { - throw_ub_format!("expected function pointer, found {:?}", ptr); - }; + let fn_instance = + if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(alloc_id) { + instance + } else { + throw_ub_format!("expected function pointer, found {:?}", ptr); + }; // Reconstruct the original function pointer, // which we pass to user code. - let mut fn_ptr = ptr; - fn_ptr.offset = Size::from_bytes(0); - let fn_ptr = Scalar::Ptr(fn_ptr); + let fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(fn_instance)); let num_fields = dest.layout.layout.fields.count(); @@ -113,7 +115,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); } - let pos = BytePos(ptr.offset.bytes().try_into().unwrap()); + let pos = BytePos(offset.bytes().try_into().unwrap()); let name = fn_instance.to_string(); let lo = tcx.sess.source_map().lookup_char_pos(pos); @@ -139,15 +141,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - this.write_immediate(name_alloc.to_ref(), &this.mplace_field(&dest, 0)?.into())?; - this.write_immediate(filename_alloc.to_ref(), &this.mplace_field(&dest, 1)?.into())?; + this.write_immediate(name_alloc.to_ref(this), &this.mplace_field(&dest, 0)?.into())?; + this.write_immediate(filename_alloc.to_ref(this), &this.mplace_field(&dest, 1)?.into())?; this.write_scalar(lineno_alloc, &this.mplace_field(&dest, 2)?.into())?; this.write_scalar(colno_alloc, &this.mplace_field(&dest, 3)?.into())?; // Support a 4-field struct for now - this is deprecated // and slated for removal. if num_fields == 5 { - this.write_scalar(fn_ptr, &this.mplace_field(&dest, 4)?.into())?; + this.write_pointer(fn_ptr, &this.mplace_field(&dest, 4)?.into())?; } Ok(()) diff --git a/src/shims/env.rs b/src/shims/env.rs index 59322b91d679..ddd2b6158898 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -28,7 +28,7 @@ fn windows_check_buffer_size((success, len): (bool, u64)) -> u32 { pub struct EnvVars<'tcx> { /// Stores pointers to the environment variables. These variables must be stored as /// null-terminated target strings (c_str or wide_str) with the `"{name}={value}"` format. - map: FxHashMap>, + map: FxHashMap>>, /// Place where the `environ` static is stored. Lazily initialized, but then never changes. pub(crate) environ: Option>, @@ -75,8 +75,8 @@ impl<'tcx> EnvVars<'tcx> { } // Deallocate environ var list. let environ = ecx.machine.env_vars.environ.unwrap(); - let old_vars_ptr = ecx.read_scalar(&environ.into())?.check_init()?; - ecx.memory.deallocate(ecx.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Env.into())?; + let old_vars_ptr = ecx.read_pointer(&environ.into())?; + ecx.memory.deallocate(old_vars_ptr, None, MiriMemoryKind::Env.into())?; Ok(()) } } @@ -85,7 +85,7 @@ fn alloc_env_var_as_c_str<'mir, 'tcx>( name: &OsStr, value: &OsStr, ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, -) -> InterpResult<'tcx, Pointer> { +) -> InterpResult<'tcx, Pointer>> { let mut name_osstring = name.to_os_string(); name_osstring.push("="); name_osstring.push(value); @@ -96,7 +96,7 @@ fn alloc_env_var_as_wide_str<'mir, 'tcx>( name: &OsStr, value: &OsStr, ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, -) -> InterpResult<'tcx, Pointer> { +) -> InterpResult<'tcx, Pointer>> { let mut name_osstring = name.to_os_string(); name_osstring.push("="); name_osstring.push(value); @@ -105,7 +105,7 @@ fn alloc_env_var_as_wide_str<'mir, 'tcx>( impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn getenv(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { + fn getenv(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, Pointer>> { let this = self.eval_context_mut(); let target_os = &this.tcx.sess.target.os; assert!( @@ -113,17 +113,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "`getenv` is only available for the UNIX target family" ); - let name_ptr = this.read_scalar(name_op)?.check_init()?; + let name_ptr = this.read_pointer(name_op)?; let name = this.read_os_str_from_c_str(name_ptr)?; Ok(match this.machine.env_vars.map.get(name) { Some(var_ptr) => { // The offset is used to strip the "{name}=" part of the string. - Scalar::from(var_ptr.offset( + var_ptr.offset( Size::from_bytes(u64::try_from(name.len()).unwrap().checked_add(1).unwrap()), this, - )?) + )? } - None => Scalar::null_ptr(&*this.tcx), + None => Pointer::null(), }) } @@ -139,7 +139,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("windows", "GetEnvironmentVariableW"); - let name_ptr = this.read_scalar(name_op)?.check_init()?; + let name_ptr = this.read_pointer(name_op)?; let name = this.read_os_str_from_wide_str(name_ptr)?; Ok(match this.machine.env_vars.map.get(&name) { Some(var_ptr) => { @@ -148,11 +148,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_offset_bytes = u64::try_from(name.len()).unwrap() .checked_add(1).unwrap() .checked_mul(2).unwrap(); - let var_ptr = - Scalar::from(var_ptr.offset(Size::from_bytes(name_offset_bytes), this)?); + let var_ptr = var_ptr.offset(Size::from_bytes(name_offset_bytes), this)?; let var = this.read_os_str_from_wide_str(var_ptr)?; - let buf_ptr = this.read_scalar(buf_op)?.check_init()?; + let buf_ptr = this.read_pointer(buf_op)?; // `buf_size` represents the size in characters. let buf_size = u64::from(this.read_scalar(size_op)?.to_u32()?); windows_check_buffer_size(this.write_os_str_to_wide_str(&var, buf_ptr, buf_size)?) @@ -166,7 +165,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn GetEnvironmentStringsW(&mut self) -> InterpResult<'tcx, Scalar> { + fn GetEnvironmentStringsW(&mut self) -> InterpResult<'tcx, Pointer>> { let this = self.eval_context_mut(); this.assert_target_os("windows", "GetEnvironmentStringsW"); @@ -174,7 +173,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // https://docs.microsoft.com/en-us/windows/win32/procthread/environment-variables let mut env_vars = std::ffi::OsString::new(); for &item in this.machine.env_vars.map.values() { - let env_var = this.read_os_str_from_wide_str(Scalar::from(item))?; + let env_var = this.read_os_str_from_wide_str(item)?; env_vars.push(env_var); env_vars.push("\0"); } @@ -182,7 +181,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Final null terminator(block terminator) is added by `alloc_os_str_to_wide_str`. let envblock_ptr = this.alloc_os_str_as_wide_str(&env_vars, MiriMemoryKind::Env.into())?; // If the function succeeds, the return value is a pointer to the environment block of the current process. - Ok(envblock_ptr.into()) + Ok(envblock_ptr) } #[allow(non_snake_case)] @@ -193,12 +192,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("windows", "FreeEnvironmentStringsW"); - let env_block_ptr = this.read_scalar(env_block_op)?.check_init()?; - let result = this.memory.deallocate( - this.force_ptr(env_block_ptr)?, - None, - MiriMemoryKind::Env.into(), - ); + let env_block_ptr = this.read_pointer(env_block_op)?; + let result = this.memory.deallocate(env_block_ptr, None, MiriMemoryKind::Env.into()); // If the function succeeds, the return value is nonzero. Ok(result.is_ok() as i32) } @@ -215,11 +210,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "`setenv` is only available for the UNIX target family" ); - let name_ptr = this.read_scalar(name_op)?.check_init()?; - let value_ptr = this.read_scalar(value_op)?.check_init()?; + let name_ptr = this.read_pointer(name_op)?; + let value_ptr = this.read_pointer(value_op)?; let mut new = None; - if !this.is_null(name_ptr)? { + if !this.ptr_is_null(name_ptr)? { let name = this.read_os_str_from_c_str(name_ptr)?; if !name.is_empty() && !name.to_string_lossy().contains('=') { let value = this.read_os_str_from_c_str(value_ptr)?; @@ -250,10 +245,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut this = self.eval_context_mut(); this.assert_target_os("windows", "SetEnvironmentVariableW"); - let name_ptr = this.read_scalar(name_op)?.check_init()?; - let value_ptr = this.read_scalar(value_op)?.check_init()?; + let name_ptr = this.read_pointer(name_op)?; + let value_ptr = this.read_pointer(value_op)?; - if this.is_null(name_ptr)? { + if this.ptr_is_null(name_ptr)? { // ERROR CODE is not clearly explained in docs.. For now, throw UB instead. throw_ub_format!("pointer to environment variable name is NULL"); } @@ -263,7 +258,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("environment variable name is an empty string"); } else if name.to_string_lossy().contains('=') { throw_unsup_format!("environment variable name contains '='"); - } else if this.is_null(value_ptr)? { + } else if this.ptr_is_null(value_ptr)? { // Delete environment variable `{name}` if let Some(var) = this.machine.env_vars.map.remove(&name) { this.memory.deallocate(var, None, MiriMemoryKind::Env.into())?; @@ -289,9 +284,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "`unsetenv` is only available for the UNIX target family" ); - let name_ptr = this.read_scalar(name_op)?.check_init()?; + let name_ptr = this.read_pointer(name_op)?; let mut success = None; - if !this.is_null(name_ptr)? { + if !this.ptr_is_null(name_ptr)? { let name = this.read_os_str_from_c_str(name_ptr)?.to_owned(); if !name.is_empty() && !name.to_string_lossy().contains('=') { success = Some(this.machine.env_vars.map.remove(&name)); @@ -315,7 +310,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, buf_op: &OpTy<'tcx, Tag>, size_op: &OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, Scalar> { + ) -> InterpResult<'tcx, Pointer>> { let this = self.eval_context_mut(); let target_os = &this.tcx.sess.target.os; assert!( @@ -323,14 +318,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "`getcwd` is only available for the UNIX target family" ); + let buf = this.read_pointer(&buf_op)?; + let size = this.read_scalar(&size_op)?.to_machine_usize(&*this.tcx)?; + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("getcwd", reject_with)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; - return Ok(Scalar::null_ptr(&*this.tcx)); + return Ok(Pointer::null()); } - let buf = this.read_scalar(&buf_op)?.check_init()?; - let size = this.read_scalar(&size_op)?.to_machine_usize(&*this.tcx)?; // If we cannot get the current directory, we return null match env::current_dir() { Ok(cwd) => { @@ -343,7 +339,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Err(e) => this.set_last_error_from_io_error(e.kind())?, } - Ok(Scalar::null_ptr(&*this.tcx)) + Ok(Pointer::null()) } #[allow(non_snake_case)] @@ -355,15 +351,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("windows", "GetCurrentDirectoryW"); + let size = u64::from(this.read_scalar(size_op)?.to_u32()?); + let buf = this.read_pointer(buf_op)?; + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("GetCurrentDirectoryW", reject_with)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; return Ok(0); } - let size = u64::from(this.read_scalar(size_op)?.to_u32()?); - let buf = this.read_scalar(buf_op)?.check_init()?; - // If we cannot get the current directory, we return 0 match env::current_dir() { Ok(cwd) => @@ -381,6 +377,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "`getcwd` is only available for the UNIX target family" ); + let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("chdir", reject_with)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; @@ -388,8 +386,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } - let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?; - match env::set_current_dir(path) { Ok(()) => Ok(0), Err(e) => { @@ -409,6 +405,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("windows", "SetCurrentDirectoryW"); + let path = this.read_path_from_wide_str(this.read_pointer(path_op)?)?; + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("SetCurrentDirectoryW", reject_with)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; @@ -416,8 +414,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(0); } - let path = this.read_path_from_wide_str(this.read_scalar(path_op)?.check_init()?)?; - match env::set_current_dir(path) { Ok(()) => Ok(1), Err(e) => { @@ -433,12 +429,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); // Deallocate the old environ list, if any. if let Some(environ) = this.machine.env_vars.environ { - let old_vars_ptr = this.read_scalar(&environ.into())?.check_init()?; - this.memory.deallocate( - this.force_ptr(old_vars_ptr)?, - None, - MiriMemoryKind::Env.into(), - )?; + let old_vars_ptr = this.read_pointer(&environ.into())?; + this.memory.deallocate(old_vars_ptr, None, MiriMemoryKind::Env.into())?; } else { // No `environ` allocated yet, let's do that. // This is memory backing an extern static, hence `ExternStatic`, not `Env`. @@ -448,10 +440,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Collect all the pointers to each variable in a vector. - let mut vars: Vec> = - this.machine.env_vars.map.values().map(|&ptr| ptr.into()).collect(); + let mut vars: Vec>> = + this.machine.env_vars.map.values().copied().collect(); // Add the trailing null pointer. - vars.push(Scalar::null_ptr(this)); + vars.push(Pointer::null()); // Make an array with all these pointers inside Miri. let tcx = this.tcx; let vars_layout = @@ -459,9 +451,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let vars_place = this.allocate(vars_layout, MiriMemoryKind::Env.into())?; for (idx, var) in vars.into_iter().enumerate() { let place = this.mplace_field(&vars_place, idx)?; - this.write_scalar(var, &place.into())?; + this.write_pointer(var, &place.into())?; } - this.write_scalar(vars_place.ptr, &this.machine.env_vars.environ.unwrap().into())?; + this.write_pointer(vars_place.ptr, &this.machine.env_vars.environ.unwrap().into())?; Ok(()) } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 61dca93f0ed4..35c151b72f60 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -72,10 +72,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, zero_init: bool, kind: MiriMemoryKind, - ) -> InterpResult<'tcx, Scalar> { + ) -> InterpResult<'tcx, Pointer>> { let this = self.eval_context_mut(); if size == 0 { - Ok(Scalar::null_ptr(this)) + Ok(Pointer::null()) } else { let align = this.min_align(size, kind); let ptr = this.memory.allocate(Size::from_bytes(size), align, kind.into())?; @@ -83,14 +83,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We just allocated this, the access is definitely in-bounds. this.memory.write_bytes(ptr.into(), iter::repeat(0u8).take(size as usize)).unwrap(); } - Ok(Scalar::Ptr(ptr)) + Ok(ptr.into()) } } - fn free(&mut self, ptr: Scalar, kind: MiriMemoryKind) -> InterpResult<'tcx> { + fn free(&mut self, ptr: Pointer>, kind: MiriMemoryKind) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - if !this.is_null(ptr)? { - let ptr = this.force_ptr(ptr)?; + if !this.ptr_is_null(ptr)? { this.memory.deallocate(ptr, None, kind.into())?; } Ok(()) @@ -98,25 +97,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn realloc( &mut self, - old_ptr: Scalar, + old_ptr: Pointer>, new_size: u64, kind: MiriMemoryKind, - ) -> InterpResult<'tcx, Scalar> { + ) -> InterpResult<'tcx, Pointer>> { let this = self.eval_context_mut(); let new_align = this.min_align(new_size, kind); - if this.is_null(old_ptr)? { + if this.ptr_is_null(old_ptr)? { if new_size == 0 { - Ok(Scalar::null_ptr(this)) + Ok(Pointer::null()) } else { let new_ptr = this.memory.allocate(Size::from_bytes(new_size), new_align, kind.into())?; - Ok(Scalar::Ptr(new_ptr)) + Ok(new_ptr.into()) } } else { - let old_ptr = this.force_ptr(old_ptr)?; if new_size == 0 { this.memory.deallocate(old_ptr, None, kind.into())?; - Ok(Scalar::null_ptr(this)) + Ok(Pointer::null()) } else { let new_ptr = this.memory.reallocate( old_ptr, @@ -125,7 +123,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx new_align, kind.into(), )?; - Ok(Scalar::Ptr(new_ptr)) + Ok(new_ptr.into()) } } } @@ -313,12 +311,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miri-specific extern functions "miri_static_root" => { let &[ref ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?; - let ptr = this.read_scalar(ptr)?.check_init()?; - let ptr = this.force_ptr(ptr)?; - if ptr.offset != Size::ZERO { + let ptr = this.read_pointer(ptr)?; + let (alloc_id, offset, _) = this.memory.ptr_get_alloc(ptr)?; + if offset != Size::ZERO { throw_unsup_format!("pointer passed to miri_static_root must point to beginning of an allocated block"); } - this.machine.static_roots.push(ptr.alloc_id); + this.machine.static_roots.push(alloc_id); } // Obtains a Miri backtrace. See the README for details. @@ -339,7 +337,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C)?; - this.write_scalar(res, dest)?; + this.write_pointer(res, dest)?; } "calloc" => { let &[ref items, ref len] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; @@ -348,19 +346,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let size = items.checked_mul(len).ok_or_else(|| err_ub_format!("overflow during calloc size computation"))?; let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C)?; - this.write_scalar(res, dest)?; + this.write_pointer(res, dest)?; } "free" => { let &[ref ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let ptr = this.read_scalar(ptr)?.check_init()?; + let ptr = this.read_pointer(ptr)?; this.free(ptr, MiriMemoryKind::C)?; } "realloc" => { let &[ref old_ptr, ref new_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let old_ptr = this.read_scalar(old_ptr)?.check_init()?; + let old_ptr = this.read_pointer(old_ptr)?; let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; let res = this.realloc(old_ptr, new_size, MiriMemoryKind::C)?; - this.write_scalar(res, dest)?; + this.write_pointer(res, dest)?; } // Rust allocation @@ -376,7 +374,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into(), )?; - this.write_scalar(ptr, dest)?; + this.write_pointer(ptr, dest)?; } "__rust_alloc_zeroed" => { let &[ref size, ref align] = this.check_shim(abi, Abi::Rust, link_name, args)?; @@ -390,15 +388,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; // We just allocated this, the access is definitely in-bounds. this.memory.write_bytes(ptr.into(), iter::repeat(0u8).take(usize::try_from(size).unwrap())).unwrap(); - this.write_scalar(ptr, dest)?; + this.write_pointer(ptr, dest)?; } "__rust_dealloc" => { let &[ref ptr, ref old_size, ref align] = this.check_shim(abi, Abi::Rust, link_name, args)?; - let ptr = this.read_scalar(ptr)?.check_init()?; + let ptr = this.read_pointer(ptr)?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; // No need to check old_size/align; we anyway check that they match the allocation. - let ptr = this.force_ptr(ptr)?; this.memory.deallocate( ptr, Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())), @@ -407,7 +404,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "__rust_realloc" => { let &[ref ptr, ref old_size, ref align, ref new_size] = this.check_shim(abi, Abi::Rust, link_name, args)?; - let ptr = this.force_ptr(this.read_scalar(ptr)?.check_init()?)?; + let ptr = this.read_pointer(ptr)?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; @@ -421,14 +418,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx align, MiriMemoryKind::Rust.into(), )?; - this.write_scalar(new_ptr, dest)?; + this.write_pointer(new_ptr, dest)?; } // C memory handling functions "memcmp" => { let &[ref left, ref right, ref n] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let left = this.read_scalar(left)?.check_init()?; - let right = this.read_scalar(right)?.check_init()?; + let left = this.read_pointer(left)?; + let right = this.read_pointer(right)?; let n = Size::from_bytes(this.read_scalar(n)?.to_machine_usize(this)?); let result = { @@ -447,7 +444,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "memrchr" => { let &[ref ptr, ref val, ref num] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let ptr = this.read_scalar(ptr)?.check_init()?; + let ptr = this.read_pointer(ptr)?; let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; if let Some(idx) = this @@ -457,15 +454,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .rev() .position(|&c| c == val) { - let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), this)?; - this.write_scalar(new_ptr, dest)?; + let new_ptr = ptr.offset(Size::from_bytes(num - idx as u64 - 1), this)?; + this.write_pointer(new_ptr, dest)?; } else { this.write_null(dest)?; } } "memchr" => { let &[ref ptr, ref val, ref num] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let ptr = this.read_scalar(ptr)?.check_init()?; + let ptr = this.read_pointer(ptr)?; let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; let idx = this @@ -474,15 +471,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .iter() .position(|&c| c == val); if let Some(idx) = idx { - let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), this)?; - this.write_scalar(new_ptr, dest)?; + let new_ptr = ptr.offset(Size::from_bytes(idx as u64), this)?; + this.write_pointer(new_ptr, dest)?; } else { this.write_null(dest)?; } } "strlen" => { let &[ref ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let ptr = this.read_scalar(ptr)?.check_init()?; + let ptr = this.read_pointer(ptr)?; let n = this.read_c_str(ptr)?.len(); this.write_scalar(Scalar::from_machine_usize(u64::try_from(n).unwrap(), this), dest)?; } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index caef57df8dd2..5a3a782382dd 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -71,7 +71,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ty = instance.substs.type_at(0); let ty_layout = this.layout_of(ty)?; let val_byte = this.read_scalar(val_byte)?.to_u8()?; - let ptr = this.read_scalar(ptr)?.check_init()?; + let ptr = this.read_pointer(ptr)?; let count = this.read_scalar(count)?.to_machine_usize(this)?; let byte_count = ty_layout.size.checked_mul(count, this).ok_or_else(|| { err_ub_format!("overflow computing total size of `write_bytes`") diff --git a/src/shims/mod.rs b/src/shims/mod.rs index bb8d0bb8db90..b05fa76a934f 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -74,8 +74,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(false); } - let req_align = - this.force_bits(this.read_scalar(align_op)?.check_init()?, this.pointer_size())?; + let req_align = this.read_scalar(align_op)?.to_machine_usize(this)?; // Stop if the alignment is not a power of two. if !req_align.is_power_of_two() { @@ -83,13 +82,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(true); // nothing left to do } - let ptr_scalar = this.read_scalar(ptr_op)?.check_init()?; - - if let Ok(ptr) = this.force_ptr(ptr_scalar) { + let ptr = this.read_pointer(ptr_op)?; + if let Ok(ptr) = ptr.into_pointer_or_addr() { // Only do anything if we can identify the allocation this goes to. - let cur_align = - this.memory.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead)?.1.bytes(); - if u128::from(cur_align) >= req_align { + let (_, cur_align) = + this.memory.get_size_and_align(ptr.provenance.alloc_id, AllocCheck::MaybeDead)?; + if cur_align.bytes() >= req_align { // If the allocation alignment is at least the required alignment we use the // real implementation. return Ok(false); diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index ea99921c0b67..83bb344982c2 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -50,19 +50,25 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. - fn read_os_str_from_c_str<'a>(&'a self, sptr: Scalar) -> InterpResult<'tcx, &'a OsStr> + fn read_os_str_from_c_str<'a>( + &'a self, + ptr: Pointer>, + ) -> InterpResult<'tcx, &'a OsStr> where 'tcx: 'a, 'mir: 'a, { let this = self.eval_context_ref(); - let bytes = this.read_c_str(sptr)?; + let bytes = this.read_c_str(ptr)?; bytes_to_os_str(bytes) } /// Helper function to read an OsString from a 0x0000-terminated sequence of u16, /// which is what the Windows APIs usually handle. - fn read_os_str_from_wide_str<'a>(&'a self, sptr: Scalar) -> InterpResult<'tcx, OsString> + fn read_os_str_from_wide_str<'a>( + &'a self, + ptr: Pointer>, + ) -> InterpResult<'tcx, OsString> where 'tcx: 'a, 'mir: 'a, @@ -78,7 +84,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(s.into()) } - let u16_vec = self.eval_context_ref().read_wide_str(sptr)?; + let u16_vec = self.eval_context_ref().read_wide_str(ptr)?; u16vec_to_osstring(u16_vec) } @@ -90,7 +96,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_os_str_to_c_str( &mut self, os_str: &OsStr, - sptr: Scalar, + ptr: Pointer>, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let bytes = os_str_to_bytes(os_str)?; @@ -102,7 +108,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } self.eval_context_mut() .memory - .write_bytes(sptr, bytes.iter().copied().chain(iter::once(0u8)))?; + .write_bytes(ptr, bytes.iter().copied().chain(iter::once(0u8)))?; Ok((true, string_length)) } @@ -114,7 +120,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_os_str_to_wide_str( &mut self, os_str: &OsStr, - sptr: Scalar, + ptr: Pointer>, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { #[cfg(windows)] @@ -146,7 +152,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let mut alloc = this .memory - .get_mut(sptr, size2 * string_length, Align::from_bytes(2).unwrap())? + .get_mut(ptr, size2 * string_length, Align::from_bytes(2).unwrap())? .unwrap(); // not a ZST, so we will get a result for (offset, wchar) in u16_vec.into_iter().chain(iter::once(0x0000)).enumerate() { let offset = u64::try_from(offset).unwrap(); @@ -161,14 +167,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, os_str: &OsStr, memkind: MemoryKind, - ) -> InterpResult<'tcx, Pointer> { + ) -> InterpResult<'tcx, Pointer>> { let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0` terminator. let this = self.eval_context_mut(); let arg_type = this.tcx.mk_array(this.tcx.types.u8, size); let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?; assert!(self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap().0); - Ok(arg_place.ptr.assert_ptr()) + Ok(arg_place.ptr) } /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of `u16`. @@ -176,24 +182,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, os_str: &OsStr, memkind: MemoryKind, - ) -> InterpResult<'tcx, Pointer> { + ) -> InterpResult<'tcx, Pointer>> { let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0x0000` terminator. let this = self.eval_context_mut(); let arg_type = this.tcx.mk_array(this.tcx.types.u16, size); let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?; assert!(self.write_os_str_to_wide_str(os_str, arg_place.ptr, size).unwrap().0); - Ok(arg_place.ptr.assert_ptr()) + Ok(arg_place.ptr) } /// Read a null-terminated sequence of bytes, and perform path separator conversion if needed. - fn read_path_from_c_str<'a>(&'a self, sptr: Scalar) -> InterpResult<'tcx, Cow<'a, Path>> + fn read_path_from_c_str<'a>( + &'a self, + ptr: Pointer>, + ) -> InterpResult<'tcx, Cow<'a, Path>> where 'tcx: 'a, 'mir: 'a, { let this = self.eval_context_ref(); - let os_str = this.read_os_str_from_c_str(sptr)?; + let os_str = this.read_os_str_from_c_str(ptr)?; Ok(match this.convert_path_separator(Cow::Borrowed(os_str), PathConversion::TargetToHost) { Cow::Borrowed(x) => Cow::Borrowed(Path::new(x)), @@ -202,9 +211,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Read a null-terminated sequence of `u16`s, and perform path separator conversion if needed. - fn read_path_from_wide_str(&self, sptr: Scalar) -> InterpResult<'tcx, PathBuf> { + fn read_path_from_wide_str(&self, ptr: Pointer>) -> InterpResult<'tcx, PathBuf> { let this = self.eval_context_ref(); - let os_str = this.read_os_str_from_wide_str(sptr)?; + let os_str = this.read_os_str_from_wide_str(ptr)?; Ok(this .convert_path_separator(Cow::Owned(os_str), PathConversion::TargetToHost) @@ -217,13 +226,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_path_to_c_str( &mut self, path: &Path, - sptr: Scalar, + ptr: Pointer>, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); let os_str = this .convert_path_separator(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); - this.write_os_str_to_c_str(&os_str, sptr, size) + this.write_os_str_to_c_str(&os_str, ptr, size) } /// Write a Path to the machine memory (as a null-terminated sequence of `u16`s), @@ -231,13 +240,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_path_to_wide_str( &mut self, path: &Path, - sptr: Scalar, + ptr: Pointer>, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); let os_str = this .convert_path_separator(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); - this.write_os_str_to_wide_str(&os_str, sptr, size) + this.write_os_str_to_wide_str(&os_str, ptr, size) } fn convert_path_separator<'a>( diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 68b648f32718..04a8e9063f9a 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -84,14 +84,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Get all the arguments. let &[ref try_fn, ref data, ref catch_fn] = check_arg_count(args)?; - let try_fn = this.read_scalar(try_fn)?.check_init()?; + let try_fn = this.read_pointer(try_fn)?; let data = this.read_scalar(data)?.check_init()?; let catch_fn = this.read_scalar(catch_fn)?.check_init()?; // Now we make a function call, and pass `data` as first and only argument. let f_instance = this.memory.get_fn(try_fn)?.as_instance()?; trace!("try_fn: {:?}", f_instance); - let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); + let ret_place = MPlaceTy::dangling(this.machine.layouts.unit).into(); this.call_function( f_instance, Abi::Rust, @@ -145,9 +145,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let payload = this.active_thread_mut().panic_payload.take().unwrap(); // Push the `catch_fn` stackframe. - let f_instance = this.memory.get_fn(catch_unwind.catch_fn)?.as_instance()?; + let f_instance = + this.memory.get_fn(this.scalar_to_ptr(catch_unwind.catch_fn))?.as_instance()?; trace!("catch_fn: {:?}", f_instance); - let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); + let ret_place = MPlaceTy::dangling(this.machine.layouts.unit).into(); this.call_function( f_instance, Abi::Rust, @@ -177,7 +178,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.call_function( panic, Abi::Rust, - &[msg.to_ref()], + &[msg.to_ref(this)], None, StackPopCleanup::Goto { ret: None, unwind }, ) diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 1cfc3f0a4e79..09dd7d9c7b86 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -28,7 +28,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "getenv" => { let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.getenv(name)?; - this.write_scalar(result, dest)?; + this.write_pointer(result, dest)?; } "unsetenv" => { let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; @@ -44,7 +44,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "getcwd" => { let &[ref buf, ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.getcwd(buf, size)?; - this.write_scalar(result, dest)?; + this.write_pointer(result, dest)?; } "chdir" => { let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; @@ -68,7 +68,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "read" => { let &[ref fd, ref buf, ref count] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; - let buf = this.read_scalar(buf)?.check_init()?; + let buf = this.read_pointer(buf)?; let count = this.read_scalar(count)?.to_machine_usize(this)?; let result = this.read(fd, buf, count)?; this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; @@ -76,7 +76,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "write" => { let &[ref fd, ref buf, ref n] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; - let buf = this.read_scalar(buf)?.check_init()?; + let buf = this.read_pointer(buf)?; let count = this.read_scalar(n)?.to_machine_usize(this)?; trace!("Called write({:?}, {:?}, {:?})", fd, buf, count); let result = this.write(fd, buf, count)?; @@ -160,7 +160,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Align::from_bytes(align).unwrap(), MiriMemoryKind::C.into(), )?; - this.write_scalar(ptr, &ret.into())?; + this.write_pointer(ptr, &ret.into())?; } this.write_null(dest)?; } @@ -169,11 +169,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "dlsym" => { let &[ref handle, ref symbol] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(handle)?.to_machine_usize(this)?; - let symbol = this.read_scalar(symbol)?.check_init()?; + let symbol = this.read_pointer(symbol)?; let symbol_name = this.read_c_str(symbol)?; if let Some(dlsym) = Dlsym::from_str(symbol_name, &this.tcx.sess.target.os)? { let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); - this.write_scalar(Scalar::from(ptr), dest)?; + this.write_pointer(ptr, dest)?; } else { this.write_null(dest)?; } @@ -208,12 +208,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "pthread_key_create" => { let &[ref key, ref dtor] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let key_place = this.deref_operand(key)?; - let dtor = this.read_scalar(dtor)?.check_init()?; + let dtor = this.read_pointer(dtor)?; // Extract the function type out of the signature (that seems easier than constructing it ourselves). - let dtor = match this.test_null(dtor)? { - Some(dtor_ptr) => Some(this.memory.get_fn(dtor_ptr)?.as_instance()?), - None => None, + let dtor = if !this.ptr_is_null(dtor)? { + Some(this.memory.get_fn(dtor)?.as_instance()?) + } else { + None }; // Figure out how large a pthread TLS key actually is. @@ -235,24 +236,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "pthread_key_delete" => { let &[ref key] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; + let key = this.read_scalar(key)?.check_init()?.to_bits(key.layout.size)?; this.machine.tls.delete_tls_key(key)?; // Return success (0) this.write_null(dest)?; } "pthread_getspecific" => { let &[ref key] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; + let key = this.read_scalar(key)?.check_init()?.to_bits(key.layout.size)?; let active_thread = this.get_active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { let &[ref key, ref new_ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; + let key = this.read_scalar(key)?.check_init()?.to_bits(key.layout.size)?; let active_thread = this.get_active_thread(); - let new_ptr = this.read_scalar(new_ptr)?.check_init()?; - this.machine.tls.store_tls(key, active_thread, this.test_null(new_ptr)?)?; + let new_data = this.read_scalar(new_ptr)?; + this.machine.tls.store_tls(key, active_thread, new_data.check_init()?, &*this.tcx)?; // Return success (`0`). this.write_null(dest)?; @@ -412,9 +413,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "pthread_atfork" => { let &[ref prepare, ref parent, ref child] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - this.force_bits(this.read_scalar(prepare)?.check_init()?, this.memory.pointer_size())?; - this.force_bits(this.read_scalar(parent)?.check_init()?, this.memory.pointer_size())?; - this.force_bits(this.read_scalar(child)?.check_init()?, this.memory.pointer_size())?; + this.read_pointer(prepare)?; + this.read_pointer(parent)?; + this.read_pointer(child)?; // We do not support forking, so there is nothing to do here. this.write_null(dest)?; } diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index bfc6195b3af3..a14a9c907eed 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -17,7 +17,6 @@ use rustc_target::abi::{Align, LayoutOf, Size}; use crate::*; use helpers::{check_arg_count, immty_from_int_checked, immty_from_uint_checked}; use shims::time::system_time_to_duration; -use stacked_borrows::Tag; #[derive(Debug)] struct FileHandle { @@ -317,7 +316,7 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let path_scalar = this.read_scalar(path_op)?.check_init()?; + let path_scalar = this.read_pointer(path_op)?; let path = this.read_path_from_c_str(path_scalar)?.into_owned(); let metadata = match FileMetadata::from_path(this, &path, follow_symlink)? { @@ -582,7 +581,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("unsupported flags {:#x}", flag & !mirror); } - let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?; + let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; let fd = options.open(&path).map(|file| { let fh = &mut this.machine.file_handler; @@ -670,7 +669,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn read(&mut self, fd: i32, buf: Scalar, count: u64) -> InterpResult<'tcx, i64> { + fn read(&mut self, fd: i32, buf: Pointer>, count: u64) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); // Isolation check is done via `FileDescriptor` trait. @@ -718,7 +717,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn write(&mut self, fd: i32, buf: Scalar, count: u64) -> InterpResult<'tcx, i64> { + fn write(&mut self, fd: i32, buf: Pointer>, count: u64) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); // Isolation check is done via `FileDescriptor` trait. @@ -788,7 +787,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("`unlink`")?; - let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?; + let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; let result = remove_file(path).map(|_| 0); this.try_unwrap_io_result(result) @@ -814,8 +813,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("`symlink`")?; - let target = this.read_path_from_c_str(this.read_scalar(target_op)?.check_init()?)?; - let linkpath = this.read_path_from_c_str(this.read_scalar(linkpath_op)?.check_init()?)?; + let target = this.read_path_from_c_str(this.read_pointer(target_op)?)?; + let linkpath = this.read_path_from_c_str(this.read_pointer(linkpath_op)?)?; let result = create_link(&target, &linkpath).map(|_| 0); this.try_unwrap_io_result(result) @@ -877,11 +876,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.assert_target_os("linux", "statx"); this.check_no_isolation("`statx`")?; - let statxbuf_scalar = this.read_scalar(statxbuf_op)?.check_init()?; - let pathname_scalar = this.read_scalar(pathname_op)?.check_init()?; + let statxbuf_ptr = this.read_pointer(statxbuf_op)?; + let pathname_ptr = this.read_pointer(pathname_op)?; // If the statxbuf or pathname pointers are null, the function fails with `EFAULT`. - if this.is_null(statxbuf_scalar)? || this.is_null(pathname_scalar)? { + if this.ptr_is_null(statxbuf_ptr)? || this.ptr_is_null(pathname_ptr)? { let efault = this.eval_libc("EFAULT")?; this.set_last_error(efault)?; return Ok(-1); @@ -898,13 +897,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let statx_ty = this .resolve_path(&["libc", "unix", "linux_like", "linux", "gnu", "statx"]) .ty(*this.tcx, ty::ParamEnv::reveal_all()); - let statxbuf_ty = this.tcx.mk_mut_ptr(statx_ty); - let statxbuf_layout = this.layout_of(statxbuf_ty)?; - let statxbuf_imm = ImmTy::from_scalar(statxbuf_scalar, statxbuf_layout); - this.ref_to_mplace(&statxbuf_imm)? + let statx_layout = this.layout_of(statx_ty)?; + MPlaceTy::from_aligned_ptr(statxbuf_ptr, statx_layout) }; - let path = this.read_path_from_c_str(pathname_scalar)?.into_owned(); + let path = this.read_path_from_c_str(pathname_ptr)?.into_owned(); // See for a discussion of argument sizes. let flags = this.read_scalar(flags_op)?.to_i32()?; let empty_path_flag = flags & this.eval_libc("AT_EMPTY_PATH")?.to_i32()? != 0; @@ -1037,17 +1034,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("`rename`")?; - let oldpath_scalar = this.read_scalar(oldpath_op)?.check_init()?; - let newpath_scalar = this.read_scalar(newpath_op)?.check_init()?; + let oldpath_ptr = this.read_pointer(oldpath_op)?; + let newpath_ptr = this.read_pointer(newpath_op)?; - if this.is_null(oldpath_scalar)? || this.is_null(newpath_scalar)? { + if this.ptr_is_null(oldpath_ptr)? || this.ptr_is_null(newpath_ptr)? { let efault = this.eval_libc("EFAULT")?; this.set_last_error(efault)?; return Ok(-1); } - let oldpath = this.read_path_from_c_str(oldpath_scalar)?; - let newpath = this.read_path_from_c_str(newpath_scalar)?; + let oldpath = this.read_path_from_c_str(oldpath_ptr)?; + let newpath = this.read_path_from_c_str(newpath_ptr)?; let result = rename(oldpath, newpath).map(|_| 0); @@ -1065,12 +1062,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[cfg_attr(not(unix), allow(unused_variables))] let mode = if this.tcx.sess.target.os == "macos" { - u32::from(this.read_scalar(mode_op)?.check_init()?.to_u16()?) + u32::from(this.read_scalar(mode_op)?.to_u16()?) } else { this.read_scalar(mode_op)?.to_u32()? }; - let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?; + let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; #[cfg_attr(not(unix), allow(unused_mut))] let mut builder = DirBuilder::new(); @@ -1093,7 +1090,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("`rmdir`")?; - let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?; + let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; let result = remove_dir(path).map(|_| 0i32); @@ -1105,7 +1102,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("`opendir`")?; - let name = this.read_path_from_c_str(this.read_scalar(name_op)?.check_init()?)?; + let name = this.read_path_from_c_str(this.read_pointer(name_op)?)?; let result = read_dir(name); @@ -1449,8 +1446,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("readlink")?; - let pathname = this.read_path_from_c_str(this.read_scalar(pathname_op)?.check_init()?)?; - let buf = this.read_scalar(buf_op)?.check_init()?; + let pathname = this.read_path_from_c_str(this.read_pointer(pathname_op)?)?; + let buf = this.read_pointer(buf_op)?; let bufsize = this.read_scalar(bufsize_op)?.to_machine_usize(this)?; let result = std::fs::read_link(pathname); diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 1d551b9fa1ea..0a9939fedd4c 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -26,7 +26,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "__errno_location" => { let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let errno_place = this.last_error_place()?; - this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; + this.write_scalar(errno_place.to_ref(this).to_scalar()?, dest)?; } // File related shims (but also see "syscall" below for statx) @@ -231,7 +231,7 @@ fn getrandom<'tcx>( flags: &OpTy<'tcx, Tag>, dest: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { - let ptr = this.read_scalar(ptr)?.check_init()?; + let ptr = this.read_pointer(ptr)?; let len = this.read_scalar(len)?.to_machine_usize(this)?; // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index fda70d815de2..17ddca879e68 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -31,13 +31,8 @@ pub fn futex<'tcx>( let op = this.read_scalar(&args[2])?.to_i32()?; let val = this.read_scalar(&args[3])?.to_i32()?; - // The raw pointer value is used to identify the mutex. - // Not all mutex operations actually read from this address or even require this address to exist. - // This will make FUTEX_WAKE fail on an integer cast to a pointer. But FUTEX_WAIT on - // such a pointer can never work anyway, so that seems fine. - let futex_ptr = this.force_ptr(addr.to_scalar()?)?; - let thread = this.get_active_thread(); + let addr_scalar = addr.to_scalar()?; let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?; let futex_wait = this.eval_libc_i32("FUTEX_WAIT")?; @@ -57,14 +52,16 @@ pub fn futex<'tcx>( args.len() ); } - let timeout = &args[4]; - let timeout_time = if this.is_null(this.read_scalar(timeout)?.check_init()?)? { + + // `deref_operand` but not actually dereferencing the ptr yet (it might be NULL!). + let timeout = this.ref_to_mplace(&this.read_immediate(&args[4])?)?; + let timeout_time = if this.ptr_is_null(timeout.ptr)? { None } else { this.check_no_isolation( "`futex` syscall with `op=FUTEX_WAIT` and non-null timeout", )?; - let duration = match this.read_timespec(timeout)? { + let duration = match this.read_timespec(&timeout)? { Some(duration) => duration, None => { let einval = this.eval_libc("EINVAL")?; @@ -83,7 +80,7 @@ pub fn futex<'tcx>( // The API requires `addr` to be a 4-byte aligned pointer, and will // use the 4 bytes at the given address as an (atomic) i32. this.memory.check_ptr_access_align( - addr.to_scalar()?, + this.scalar_to_ptr(addr_scalar), Size::from_bytes(4), Align::from_bytes(4).unwrap(), CheckInAllocMsg::MemoryAccessTest, @@ -111,7 +108,7 @@ pub fn futex<'tcx>( if val == futex_val { // The value still matches, so we block the trait make it wait for FUTEX_WAKE. this.block_thread(thread); - this.futex_wait(futex_ptr, thread); + this.futex_wait(addr_scalar.to_machine_usize(this)?, thread); // Succesfully waking up from FUTEX_WAIT always returns zero. this.write_scalar(Scalar::from_machine_isize(0, this), dest)?; // Register a timeout callback if a timeout was specified. @@ -123,7 +120,7 @@ pub fn futex<'tcx>( timeout_time, Box::new(move |this| { this.unblock_thread(thread); - this.futex_remove_waiter(futex_ptr, thread); + this.futex_remove_waiter(addr_scalar.to_machine_usize(this)?, thread); let etimedout = this.eval_libc("ETIMEDOUT")?; this.set_last_error(etimedout)?; this.write_scalar(Scalar::from_machine_isize(-1, this), &dest)?; @@ -146,7 +143,7 @@ pub fn futex<'tcx>( op if op == futex_wake => { let mut n = 0; for _ in 0..val { - if let Some(thread) = this.futex_wake(futex_ptr) { + if let Some(thread) = this.futex_wake(addr_scalar.to_machine_usize(this)?) { this.unblock_thread(thread); this.unregister_timeout_callback_if_exists(thread); n += 1; diff --git a/src/shims/posix/macos/dlsym.rs b/src/shims/posix/macos/dlsym.rs index 7f3958797449..d5996cc6a9ed 100644 --- a/src/shims/posix/macos/dlsym.rs +++ b/src/shims/posix/macos/dlsym.rs @@ -37,7 +37,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match dlsym { Dlsym::getentropy => { let &[ref ptr, ref len] = check_arg_count(args)?; - let ptr = this.read_scalar(ptr)?.check_init()?; + let ptr = this.read_pointer(ptr)?; let len = this.read_scalar(len)?.to_machine_usize(this)?; this.gen_random(ptr, len)?; this.write_null(dest)?; diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index 47a860b96a87..2f79b337ce38 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -24,7 +24,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "__error" => { let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let errno_place = this.last_error_place()?; - this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; + this.write_scalar(errno_place.to_ref(this).to_scalar()?, dest)?; } // File related shims @@ -74,7 +74,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Environment related shims "_NSGetEnviron" => { let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - this.write_scalar(this.machine.env_vars.environ.unwrap().ptr, dest)?; + this.write_pointer( + this.machine.env_vars.environ.expect("machine must be initialized").ptr, + dest, + )?; } // Time related shims @@ -100,18 +103,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Access to command-line arguments "_NSGetArgc" => { let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?; + this.write_pointer( + this.machine.argc.expect("machine must be initialized").ptr, + dest, + )?; } "_NSGetArgv" => { let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; + this.write_pointer( + this.machine.argv.expect("machine must be initialized").ptr, + dest, + )?; } // Thread-local storage "_tlv_atexit" => { let &[ref dtor, ref data] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let dtor = this.read_scalar(dtor)?.check_init()?; + let dtor = this.read_pointer(dtor)?; let dtor = this.memory.get_fn(dtor)?.as_instance()?; let data = this.read_scalar(data)?.check_init()?; let active_thread = this.get_active_thread(); @@ -138,7 +147,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "pthread_setname_np" => { let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let name = this.read_scalar(name)?.check_init()?; + let name = this.read_pointer(name)?; this.pthread_setname_np(name)?; } diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 4725cd9fc3c8..782765c7784b 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -1,7 +1,6 @@ use std::time::SystemTime; use crate::*; -use stacked_borrows::Tag; use thread::Time; // pthread_mutexattr_t is either 4 or 8 bytes, depending on the platform. @@ -364,8 +363,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let attr = this.read_scalar(attr_op)?.check_init()?; - let kind = if this.is_null(attr)? { + let attr = this.read_pointer(attr_op)?; + let kind = if this.ptr_is_null(attr)? { this.eval_libc("PTHREAD_MUTEX_DEFAULT")? } else { mutexattr_get_kind(this, attr_op)?.check_init()? @@ -657,8 +656,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let attr = this.read_scalar(attr_op)?.check_init()?; - let clock_id = if this.is_null(attr)? { + let attr = this.read_pointer(attr_op)?; + let clock_id = if this.ptr_is_null(attr)? { this.eval_libc("CLOCK_REALTIME")? } else { condattr_get_clock_id(this, attr_op)?.check_init()? @@ -727,7 +726,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Extract the timeout. let clock_id = cond_get_clock_id(this, cond_op)?.to_i32()?; - let duration = match this.read_timespec(abstime_op)? { + let duration = match this.read_timespec(&this.deref_operand(abstime_op)?)? { Some(duration) => duration, None => { let einval = this.eval_libc("EINVAL")?; diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index ce1c817cf3ba..9926c36c49ac 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -33,7 +33,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Read the function argument that will be sent to the new thread // before the thread starts executing since reading after the // context switch will incorrectly report a data-race. - let fn_ptr = this.read_scalar(start_routine)?.check_init()?; + let fn_ptr = this.read_pointer(start_routine)?; let func_arg = this.read_immediate(arg)?; // Finally switch to new thread so that we can push the first stackframe. @@ -70,7 +70,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if !this.is_null(this.read_scalar(retval)?.check_init()?)? { + if !this.ptr_is_null(this.read_pointer(retval)?)? { // FIXME: implement reading the thread function's return place. throw_unsup_format!("Miri supports pthread_join only with retval==NULL"); } @@ -110,7 +110,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let option = this.read_scalar(option)?.to_i32()?; if option == this.eval_libc_i32("PR_SET_NAME")? { - let address = this.read_scalar(arg2)?.check_init()?; + let address = this.read_pointer(arg2)?; let mut name = this.read_c_str(address)?.to_owned(); // The name should be no more than 16 bytes, including the null // byte. Since `read_c_str` returns the string without the null @@ -118,7 +118,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name.truncate(15); this.set_active_thread_name(name); } else if option == this.eval_libc_i32("PR_GET_NAME")? { - let address = this.read_scalar(arg2)?.check_init()?; + let address = this.read_pointer(arg2)?; let mut name = this.get_active_thread_name().to_vec(); name.push(0u8); assert!(name.len() <= 16); @@ -130,7 +130,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_setname_np(&mut self, name: Scalar) -> InterpResult<'tcx> { + fn pthread_setname_np(&mut self, name: Pointer>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.assert_target_os("macos", "pthread_setname_np"); diff --git a/src/shims/time.rs b/src/shims/time.rs index d293e4d12774..1db9d85debdc 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -1,7 +1,6 @@ use std::convert::TryFrom; use std::time::{Duration, Instant, SystemTime}; -use crate::stacked_borrows::Tag; use crate::*; use helpers::{immty_from_int_checked, immty_from_uint_checked}; use thread::Time; @@ -63,8 +62,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("`gettimeofday`")?; // Using tz is obsolete and should always be null - let tz = this.read_scalar(tz_op)?.check_init()?; - if !this.is_null(tz)? { + let tz = this.read_pointer(tz_op)?; + if !this.ptr_is_null(tz)? { let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; return Ok(-1); @@ -206,7 +205,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("`nanosleep`")?; - let duration = match this.read_timespec(req_op)? { + let duration = match this.read_timespec(&this.deref_operand(req_op)?)? { Some(duration) => duration, None => { let einval = this.eval_libc("EINVAL")?; diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 239364508e08..cf8b8e3e1b88 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -109,19 +109,17 @@ impl<'tcx> TlsData<'tcx> { &mut self, key: TlsKey, thread_id: ThreadId, - new_data: Option>, + new_data: Scalar, + cx: &impl HasDataLayout, ) -> InterpResult<'tcx> { match self.keys.get_mut(&key) { Some(TlsEntry { data, .. }) => { - match new_data { - Some(scalar) => { - trace!("TLS key {} for thread {:?} stored: {:?}", key, thread_id, scalar); - data.insert(thread_id, scalar); - } - None => { - trace!("TLS key {} for thread {:?} removed", key, thread_id); - data.remove(&thread_id); - } + if new_data.to_machine_usize(cx)? != 0 { + trace!("TLS key {} for thread {:?} stored: {:?}", key, thread_id, new_data); + data.insert(thread_id, new_data); + } else { + trace!("TLS key {} for thread {:?} removed", key, thread_id); + data.remove(&thread_id); } Ok(()) } @@ -250,11 +248,12 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "thread_local_key", "p_thread_callback", ])?; - let thread_callback = this.memory.get_fn(thread_callback.check_init()?)?.as_instance()?; + let thread_callback = + this.memory.get_fn(this.scalar_to_ptr(thread_callback))?.as_instance()?; // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. let reason = this.eval_path_scalar(&["std", "sys", "windows", "c", "DLL_THREAD_DETACH"])?; - let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); + let ret_place = MPlaceTy::dangling(this.machine.layouts.unit).into(); this.call_function( thread_callback, Abi::System { unwind: false }, @@ -277,7 +276,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some((instance, data)) = this.machine.tls.macos_thread_dtors.remove(&thread_id) { trace!("Running macos dtor {:?} on {:?} at {:?}", instance, data, thread_id); - let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); + let ret_place = MPlaceTy::dangling(this.machine.layouts.unit).into(); this.call_function( instance, Abi::C { unwind: false }, @@ -315,9 +314,12 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.tls.dtors_running.get_mut(&active_thread).unwrap().last_dtor_key = Some(key); trace!("Running TLS dtor {:?} on {:?} at {:?}", instance, ptr, active_thread); - assert!(!this.is_null(ptr).unwrap(), "data can't be NULL when dtor is called!"); + assert!( + !ptr.to_machine_usize(this).unwrap() != 0, + "data can't be NULL when dtor is called!" + ); - let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); + let ret_place = MPlaceTy::dangling(this.machine.layouts.unit).into(); this.call_function( instance, Abi::C { unwind: false }, @@ -349,6 +351,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn schedule_next_tls_dtor_for_active_thread(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let active_thread = this.get_active_thread(); + trace!("schedule_next_tls_dtor_for_active_thread on thread {:?}", active_thread); if !this.machine.tls.set_dtors_running_for_thread(active_thread) { // This is the first time we got asked to schedule a destructor. The diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index b5324576273c..0eebd6aca5bd 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -43,7 +43,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "GetEnvironmentStringsW" => { let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.GetEnvironmentStringsW()?; - this.write_scalar(result, dest)?; + this.write_pointer(result, dest)?; } "FreeEnvironmentStringsW" => { let &[ref env_block] = @@ -78,7 +78,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore let handle = this.read_scalar(handle)?.to_machine_isize(this)?; - let buf = this.read_scalar(buf)?.check_init()?; + let buf = this.read_pointer(buf)?; let n = this.read_scalar(n)?.to_u32()?; let written_place = this.deref_operand(written_ptr)?; // Spec says to always write `0` first. @@ -116,14 +116,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let size = this.read_scalar(size)?.to_machine_usize(this)?; let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY let res = this.malloc(size, zero_init, MiriMemoryKind::WinHeap)?; - this.write_scalar(res, dest)?; + this.write_pointer(res, dest)?; } "HeapFree" => { let &[ref handle, ref flags, ref ptr] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; - let ptr = this.read_scalar(ptr)?.check_init()?; + let ptr = this.read_pointer(ptr)?; this.free(ptr, MiriMemoryKind::WinHeap)?; this.write_scalar(Scalar::from_i32(1), dest)?; } @@ -132,10 +132,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; - let ptr = this.read_scalar(ptr)?.check_init()?; + let ptr = this.read_pointer(ptr)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let res = this.realloc(ptr, size, MiriMemoryKind::WinHeap)?; - this.write_scalar(res, dest)?; + this.write_pointer(res, dest)?; } // errno @@ -189,8 +189,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); - let new_ptr = this.read_scalar(new_ptr)?.check_init()?; - this.machine.tls.store_tls(key, active_thread, this.test_null(new_ptr)?)?; + let new_data = this.read_scalar(new_ptr)?.check_init()?; + this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?; // Return success (`1`). this.write_scalar(Scalar::from_i32(1), dest)?; @@ -199,8 +199,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Access to command-line arguments "GetCommandLineW" => { let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - this.write_scalar( - this.machine.cmd_line.expect("machine must be initialized"), + this.write_pointer( + this.machine.cmd_line.expect("machine must be initialized").ptr, dest, )?; } @@ -267,10 +267,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[ref hModule, ref lpProcName] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(hModule)?.to_machine_isize(this)?; - let name = this.read_c_str(this.read_scalar(lpProcName)?.check_init()?)?; + let name = this.read_c_str(this.read_pointer(lpProcName)?)?; if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.os)? { let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); - this.write_scalar(Scalar::from(ptr), dest)?; + this.write_pointer(ptr, dest)?; } else { this.write_null(dest)?; } @@ -281,7 +281,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This is really 'RtlGenRandom'. let &[ref ptr, ref len] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - let ptr = this.read_scalar(ptr)?.check_init()?; + let ptr = this.read_pointer(ptr)?; let len = this.read_scalar(len)?.to_u32()?; this.gen_random(ptr, len.into())?; this.write_scalar(Scalar::from_bool(true), dest)?; @@ -290,7 +290,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[ref algorithm, ref ptr, ref len, ref flags] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let algorithm = this.read_scalar(algorithm)?; - let ptr = this.read_scalar(ptr)?.check_init()?; + let ptr = this.read_pointer(ptr)?; let len = this.read_scalar(len)?.to_u32()?; let flags = this.read_scalar(flags)?.to_u32()?; if flags != 2 { diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 0365e9ca00ed..ddfbfd426680 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -10,7 +10,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::Mutability; use rustc_middle::mir::RetagKind; use rustc_middle::ty; -use rustc_target::abi::{Align, LayoutOf, Size}; +use rustc_target::abi::{LayoutOf, Size}; use crate::*; @@ -20,16 +20,16 @@ pub type AllocExtra = Stacks; /// Tracking pointer provenance #[derive(Copy, Clone, Hash, PartialEq, Eq)] -pub enum Tag { +pub enum SbTag { Tagged(PtrId), Untagged, } -impl fmt::Debug for Tag { +impl fmt::Debug for SbTag { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Tag::Tagged(id) => write!(f, "<{}>", id), - Tag::Untagged => write!(f, ""), + SbTag::Tagged(id) => write!(f, "<{}>", id), + SbTag::Untagged => write!(f, ""), } } } @@ -54,7 +54,7 @@ pub struct Item { /// The permission this item grants. perm: Permission, /// The pointers the permission is granted to. - tag: Tag, + tag: SbTag, /// An optional protector, ensuring the item cannot get popped until `CallId` is over. protector: Option, } @@ -95,7 +95,7 @@ pub struct GlobalState { /// Table storing the "base" tag for each allocation. /// The base tag is the one used for the initial pointer. /// We need this in a separate table to handle cyclic statics. - base_ptr_ids: FxHashMap, + base_ptr_ids: FxHashMap, /// Next unused call ID (for protectors). next_call_id: CallId, /// Those call IDs corresponding to functions that are still running. @@ -197,14 +197,22 @@ impl GlobalState { self.active_calls.contains(&id) } - pub fn global_base_ptr(&mut self, id: AllocId) -> Tag { + pub fn base_tag(&mut self, id: AllocId) -> SbTag { self.base_ptr_ids.get(&id).copied().unwrap_or_else(|| { - let tag = Tag::Tagged(self.new_ptr()); + let tag = SbTag::Tagged(self.new_ptr()); trace!("New allocation {:?} has base tag {:?}", id, tag); self.base_ptr_ids.try_insert(id, tag).unwrap(); tag }) } + + pub fn base_tag_untagged(&mut self, id: AllocId) -> SbTag { + trace!("New allocation {:?} has no base tag (untagged)", id); + let tag = SbTag::Untagged; + // This must only be done on new allocations. + self.base_ptr_ids.try_insert(id, tag).unwrap(); + tag + } } /// Error reporting @@ -247,7 +255,7 @@ impl Permission { impl<'tcx> Stack { /// Find the item granting the given kind of access to the given tag, and return where /// it is on the stack. - fn find_granting(&self, access: AccessKind, tag: Tag) -> Option { + fn find_granting(&self, access: AccessKind, tag: SbTag) -> Option { self.borrows .iter() .enumerate() // we also need to know *where* in the stack @@ -288,8 +296,12 @@ impl<'tcx> Stack { } /// Check if the given item is protected. - fn check_protector(item: &Item, tag: Option, global: &GlobalState) -> InterpResult<'tcx> { - if let Tag::Tagged(id) = item.tag { + fn check_protector( + item: &Item, + tag: Option, + global: &GlobalState, + ) -> InterpResult<'tcx> { + if let SbTag::Tagged(id) = item.tag { if Some(id) == global.tracked_pointer_tag { register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag(item.clone())); } @@ -314,18 +326,17 @@ impl<'tcx> Stack { fn access( &mut self, access: AccessKind, - ptr: Pointer, + tag: SbTag, + dbg_ptr: Pointer, // just for debug printing amd error messages global: &GlobalState, ) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. - let granting_idx = self.find_granting(access, ptr.tag).ok_or_else(|| { + let granting_idx = self.find_granting(access, tag).ok_or_else(|| { err_sb_ub(format!( - "no item granting {} to tag {:?} at {} found in borrow stack.", - access, - ptr.tag, - ptr.erase_tag(), + "no item granting {} to tag {:?} at {:?} found in borrow stack.", + access, tag, dbg_ptr, )) })?; @@ -337,7 +348,7 @@ impl<'tcx> Stack { let first_incompatible_idx = self.find_first_write_incompatible(granting_idx); for item in self.borrows.drain(first_incompatible_idx..).rev() { trace!("access: popping item {:?}", item); - Stack::check_protector(&item, Some(ptr.tag), global)?; + Stack::check_protector(&item, Some(tag), global)?; } } else { // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses. @@ -352,7 +363,7 @@ impl<'tcx> Stack { let item = &mut self.borrows[idx]; if item.perm == Permission::Unique { trace!("access: disabling item {:?}", item); - Stack::check_protector(item, Some(ptr.tag), global)?; + Stack::check_protector(item, Some(tag), global)?; item.perm = Permission::Disabled; } } @@ -364,12 +375,17 @@ impl<'tcx> Stack { /// Deallocate a location: Like a write access, but also there must be no /// active protectors at all because we will remove all items. - fn dealloc(&mut self, ptr: Pointer, global: &GlobalState) -> InterpResult<'tcx> { + fn dealloc( + &mut self, + tag: SbTag, + dbg_ptr: Pointer, // just for debug printing amd error messages + global: &GlobalState, + ) -> InterpResult<'tcx> { // Step 1: Find granting item. - self.find_granting(AccessKind::Write, ptr.tag).ok_or_else(|| { + self.find_granting(AccessKind::Write, tag).ok_or_else(|| { err_sb_ub(format!( - "no item granting write access for deallocation to tag {:?} at {} found in borrow stack", - ptr.tag, ptr.erase_tag(), + "no item granting write access for deallocation to tag {:?} at {:?} found in borrow stack", + tag, dbg_ptr, )) })?; @@ -387,8 +403,9 @@ impl<'tcx> Stack { /// from instead of all the way at the top of the stack. fn grant( &mut self, - derived_from: Pointer, + derived_from: SbTag, new: Item, + dbg_ptr: Pointer, global: &GlobalState, ) -> InterpResult<'tcx> { // Figure out which access `perm` corresponds to. @@ -396,10 +413,10 @@ impl<'tcx> Stack { if new.perm.grants(AccessKind::Write) { AccessKind::Write } else { AccessKind::Read }; // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. - let granting_idx = self.find_granting(access, derived_from.tag) + let granting_idx = self.find_granting(access, derived_from) .ok_or_else(|| err_sb_ub(format!( - "trying to reborrow for {:?} at {}, but parent tag {:?} does not have an appropriate item in the borrow stack", - new.perm, derived_from.erase_tag(), derived_from.tag, + "trying to reborrow for {:?} at {:?}, but parent tag {:?} does not have an appropriate item in the borrow stack", + new.perm, dbg_ptr, derived_from, )))?; // Compute where to put the new item. @@ -419,7 +436,7 @@ impl<'tcx> Stack { // A "safe" reborrow for a pointer that actually expects some aliasing guarantees. // Here, creating a reference actually counts as an access. // This ensures F2b for `Unique`, by removing offending `SharedReadOnly`. - self.access(access, derived_from, global)?; + self.access(access, derived_from, dbg_ptr, global)?; // We insert "as far up as possible": We know only compatible items are remaining // on top of `derived_from`, and we want the new item at the top so that we @@ -445,7 +462,7 @@ impl<'tcx> Stack { /// Map per-stack operations to higher-level per-location-range operations. impl<'tcx> Stacks { /// Creates new stack with initial tag. - fn new(size: Size, perm: Permission, tag: Tag) -> Self { + fn new(size: Size, perm: Permission, tag: SbTag) -> Self { let item = Item { perm, tag, protector: None }; let stack = Stack { borrows: vec![item] }; @@ -455,15 +472,12 @@ impl<'tcx> Stacks { /// Call `f` on every stack in the range. fn for_each( &self, - ptr: Pointer, - size: Size, - f: impl Fn(Pointer, &mut Stack) -> InterpResult<'tcx>, + range: AllocRange, + f: impl Fn(Size, &mut Stack) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { let mut stacks = self.stacks.borrow_mut(); - for (offset, stack) in stacks.iter_mut(ptr.offset, size) { - let mut cur_ptr = ptr; - cur_ptr.offset = offset; - f(cur_ptr, stack)?; + for (offset, stack) in stacks.iter_mut(range.start, range.size) { + f(offset, stack)?; } Ok(()) } @@ -471,15 +485,12 @@ impl<'tcx> Stacks { /// Call `f` on every stack in the range. fn for_each_mut( &mut self, - ptr: Pointer, - size: Size, - f: impl Fn(Pointer, &mut Stack) -> InterpResult<'tcx>, + range: AllocRange, + f: impl Fn(Size, &mut Stack) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { let stacks = self.stacks.get_mut(); - for (offset, stack) in stacks.iter_mut(ptr.offset, size) { - let mut cur_ptr = ptr; - cur_ptr.offset = offset; - f(cur_ptr, stack)?; + for (offset, stack) in stacks.iter_mut(range.start, range.size) { + f(offset, stack)?; } Ok(()) } @@ -492,15 +503,15 @@ impl Stacks { size: Size, extra: &MemoryExtra, kind: MemoryKind, - ) -> (Self, Tag) { + ) -> Self { let mut extra = extra.borrow_mut(); - let (tag, perm) = match kind { + let (base_tag, perm) = match kind { // New unique borrow. This tag is not accessible by the program, // so it will only ever be used when using the local directly (i.e., // not through a pointer). That is, whenever we directly write to a local, this will pop // everything else off the stack, invalidating all previous pointers, // and in particular, *all* raw pointers. - MemoryKind::Stack => (Tag::Tagged(extra.new_ptr()), Permission::Unique), + MemoryKind::Stack => (extra.base_tag(id), Permission::Unique), // `Global` memory can be referenced by global pointers from `tcx`. // Thus we call `global_base_ptr` such that the global pointers get the same tag // as what we use here. @@ -515,53 +526,72 @@ impl Stacks { | MiriMemoryKind::Tls | MiriMemoryKind::Env | MiriMemoryKind::Machine, - ) => (extra.global_base_ptr(id), Permission::SharedReadWrite), + ) => (extra.base_tag(id), Permission::SharedReadWrite), // Heap allocations we only track precisely when raw pointers are tagged, for now. MemoryKind::Machine( MiriMemoryKind::Rust | MiriMemoryKind::C | MiriMemoryKind::WinHeap, ) => { let tag = - if extra.track_raw { Tag::Tagged(extra.new_ptr()) } else { Tag::Untagged }; + if extra.track_raw { extra.base_tag(id) } else { extra.base_tag_untagged(id) }; (tag, Permission::SharedReadWrite) } }; - (Stacks::new(size, perm, tag), tag) + Stacks::new(size, perm, base_tag) } #[inline(always)] pub fn memory_read<'tcx>( &self, - ptr: Pointer, - size: Size, + alloc_id: AllocId, + tag: SbTag, + range: AllocRange, extra: &MemoryExtra, ) -> InterpResult<'tcx> { - trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); + trace!( + "read access with tag {:?}: {:?}, size {}", + tag, + Pointer::new(alloc_id, range.start), + range.size.bytes() + ); let global = &*extra.borrow(); - self.for_each(ptr, size, move |ptr, stack| stack.access(AccessKind::Read, ptr, global)) + self.for_each(range, move |offset, stack| { + stack.access(AccessKind::Read, tag, Pointer::new(alloc_id, offset), global) + }) } #[inline(always)] pub fn memory_written<'tcx>( &mut self, - ptr: Pointer, - size: Size, + alloc_id: AllocId, + tag: SbTag, + range: AllocRange, extra: &mut MemoryExtra, ) -> InterpResult<'tcx> { - trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); + trace!( + "write access with tag {:?}: {:?}, size {}", + tag, + Pointer::new(alloc_id, range.start), + range.size.bytes() + ); let global = extra.get_mut(); - self.for_each_mut(ptr, size, move |ptr, stack| stack.access(AccessKind::Write, ptr, global)) + self.for_each_mut(range, move |offset, stack| { + stack.access(AccessKind::Write, tag, Pointer::new(alloc_id, offset), global) + }) } #[inline(always)] pub fn memory_deallocated<'tcx>( &mut self, - ptr: Pointer, - size: Size, + alloc_id: AllocId, + tag: SbTag, + range: AllocRange, extra: &mut MemoryExtra, ) -> InterpResult<'tcx> { - trace!("deallocation with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); + trace!("deallocation with tag {:?}: {:?}, size {}", tag, alloc_id, range.size.bytes()); let global = extra.get_mut(); - self.for_each_mut(ptr, size, move |ptr, stack| stack.dealloc(ptr, global)) + self.for_each_mut(range, move |offset, stack| { + stack.dealloc(tag, Pointer::new(alloc_id, offset), global) + }) } } @@ -574,11 +604,12 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx place: &MPlaceTy<'tcx, Tag>, size: Size, kind: RefKind, - new_tag: Tag, + new_tag: SbTag, protect: bool, ) -> InterpResult<'tcx> { - // Nothing to do for ZSTs. + let this = self.eval_context_mut(); if size == Size::ZERO { + // Nothing to do for zero-sized accesses. trace!( "reborrow of size 0: {} reference {:?} derived from {:?} (pointee {})", kind, @@ -588,17 +619,30 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); return Ok(()); } + let (alloc_id, base_offset, ptr) = this.memory.ptr_get_alloc(place.ptr)?; + let orig_tag = ptr.provenance.sb; + + // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). + let (allocation_size, _) = + this.memory.get_size_and_align(alloc_id, AllocCheck::Dereferenceable)?; + if base_offset + size > allocation_size { + throw_ub!(PointerOutOfBounds { + alloc_id, + offset: base_offset, + size, + allocation_size, + msg: CheckInAllocMsg::InboundsTest + }); + } - let this = self.eval_context_mut(); let protector = if protect { Some(this.frame().extra.call_id) } else { None }; - let ptr = place.ptr.assert_ptr(); trace!( "reborrow: {} reference {:?} derived from {:?} (pointee {}): {:?}, size {}", kind, new_tag, - ptr.tag, + orig_tag, place.layout.ty, - ptr.erase_tag(), + Pointer::new(alloc_id, base_offset), size.bytes() ); @@ -615,11 +659,13 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We need a frozen-sensitive reborrow. // We have to use shared references to alloc/memory_extra here since // `visit_freeze_sensitive` needs to access the global state. - let extra = this.memory.get_alloc_extra(ptr.alloc_id)?; + let extra = this.memory.get_alloc_extra(alloc_id)?; let stacked_borrows = extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); let global = this.memory.extra.stacked_borrows.as_ref().unwrap().borrow(); - return this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { + this.visit_freeze_sensitive(place, size, |mut range, frozen| { + // Adjust range. + range.start += base_offset; // We are only ever `SharedReadOnly` inside the frozen bits. let perm = if frozen { Permission::SharedReadOnly @@ -627,21 +673,25 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Permission::SharedReadWrite }; let item = Item { perm, tag: new_tag, protector }; - stacked_borrows.for_each(cur_ptr, size, |cur_ptr, stack| { - stack.grant(cur_ptr, item, &*global) + stacked_borrows.for_each(range, |offset, stack| { + stack.grant(orig_tag, item, Pointer::new(alloc_id, offset), &*global) }) - }); + })?; + return Ok(()); } }; // Here we can avoid `borrow()` calls because we have mutable references. // Note that this asserts that the allocation is mutable -- but since we are creating a // mutable pointer, that seems reasonable. - let (alloc_extra, memory_extra) = this.memory.get_alloc_extra_mut(ptr.alloc_id)?; + let (alloc_extra, memory_extra) = this.memory.get_alloc_extra_mut(alloc_id)?; let stacked_borrows = alloc_extra.stacked_borrows.as_mut().expect("we should have Stacked Borrows data"); let global = memory_extra.stacked_borrows.as_mut().unwrap().get_mut(); let item = Item { perm, tag: new_tag, protector }; - stacked_borrows.for_each_mut(ptr, size, |ptr, stack| stack.grant(ptr, item, global)) + stacked_borrows.for_each_mut(alloc_range(base_offset, size), |offset, stack| { + stack.grant(orig_tag, item, Pointer::new(alloc_id, offset), global) + })?; + Ok(()) } /// Retags an indidual pointer, returning the retagged version. @@ -663,29 +713,26 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(size) => size, None => return Ok(*val), }; - // `reborrow` relies on getting a `Pointer` and everything being in-bounds, - // so let's ensure that. However, we do not care about alignment. - // We can see dangling ptrs in here e.g. after a Box's `Unique` was - // updated using "self.0 = ..." (can happen in Box::from_raw) so we cannot ICE; see miri#1050. - let place = this.mplace_access_checked(place, Some(Align::from_bytes(1).unwrap()))?; // Compute new borrow. let new_tag = { let mem_extra = this.memory.extra.stacked_borrows.as_mut().unwrap().get_mut(); match kind { // Give up tracking for raw pointers. - RefKind::Raw { .. } if !mem_extra.track_raw => Tag::Untagged, + RefKind::Raw { .. } if !mem_extra.track_raw => SbTag::Untagged, // All other pointers are properly tracked. - _ => Tag::Tagged(mem_extra.new_ptr()), + _ => SbTag::Tagged(mem_extra.new_ptr()), } }; // Reborrow. this.reborrow(&place, size, kind, new_tag, protect)?; - let new_place = place.replace_tag(new_tag); + + // Adjust pointer. + let new_place = place.map_provenance(|p| p.map(|t| Tag { sb: new_tag, ..t })); // Return new pointer. - Ok(ImmTy::from_immediate(new_place.to_ref(), val.layout)) + Ok(ImmTy::from_immediate(new_place.to_ref(this), val.layout)) } } @@ -752,7 +799,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We have to turn the place into a pointer to use the existing code. // (The pointer type does not matter, so we use a raw pointer.) let ptr_layout = this.layout_of(this.tcx.mk_mut_ptr(return_place.layout.ty))?; - let val = ImmTy::from_immediate(return_place.to_ref(), ptr_layout); + let val = ImmTy::from_immediate(return_place.to_ref(this), ptr_layout); // Reborrow it. let val = this.retag_reference( &val, diff --git a/src/sync.rs b/src/sync.rs index b53af0aeb24a..0e4e9695d81d 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -152,7 +152,7 @@ pub(super) struct SynchronizationState { mutexes: IndexVec, rwlocks: IndexVec, condvars: IndexVec, - futexes: HashMap, + futexes: HashMap, } // Private extension trait for local helper methods @@ -486,18 +486,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.threads.sync.condvars[id].waiters.retain(|waiter| waiter.thread != thread); } - fn futex_wait(&mut self, addr: Pointer, thread: ThreadId) { + fn futex_wait(&mut self, addr: u64, thread: ThreadId) { let this = self.eval_context_mut(); - let futex = &mut this.machine.threads.sync.futexes.entry(addr.erase_tag()).or_default(); + let futex = &mut this.machine.threads.sync.futexes.entry(addr).or_default(); let waiters = &mut futex.waiters; assert!(waiters.iter().all(|waiter| waiter.thread != thread), "thread is already waiting"); waiters.push_back(FutexWaiter { thread }); } - fn futex_wake(&mut self, addr: Pointer) -> Option { + fn futex_wake(&mut self, addr: u64) -> Option { let this = self.eval_context_mut(); let current_thread = this.get_active_thread(); - let futex = &mut this.machine.threads.sync.futexes.get_mut(&addr.erase_tag())?; + let futex = &mut this.machine.threads.sync.futexes.get_mut(&addr)?; let data_race = &this.memory.extra.data_race; // Each futex-wake happens-before the end of the futex wait @@ -513,9 +513,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx res } - fn futex_remove_waiter(&mut self, addr: Pointer, thread: ThreadId) { + fn futex_remove_waiter(&mut self, addr: u64, thread: ThreadId) { let this = self.eval_context_mut(); - if let Some(futex) = this.machine.threads.sync.futexes.get_mut(&addr.erase_tag()) { + if let Some(futex) = this.machine.threads.sync.futexes.get_mut(&addr) { futex.waiters.retain(|waiter| waiter.thread != thread); } } diff --git a/src/thread.rs b/src/thread.rs index 7ee18bb7f80e..de8e41224b20 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -218,7 +218,7 @@ pub struct ThreadManager<'mir, 'tcx> { pub(crate) sync: SynchronizationState, /// A mapping from a thread-local static to an allocation id of a thread /// specific allocation. - thread_local_alloc_ids: RefCell>, + thread_local_alloc_ids: RefCell>>, /// A flag that indicates that we should change the active thread. yield_active_thread: bool, /// Callbacks that are called once the specified time passes. @@ -247,18 +247,18 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Check if we have an allocation for the given thread local static for the /// active thread. - fn get_thread_local_alloc_id(&self, def_id: DefId) -> Option { + fn get_thread_local_alloc_id(&self, def_id: DefId) -> Option> { self.thread_local_alloc_ids.borrow().get(&(def_id, self.active_thread)).cloned() } - /// Set the allocation id as the allocation id of the given thread local + /// Set the pointer for the allocation of the given thread local /// static for the active thread. /// /// Panics if a thread local is initialized twice for the same thread. - fn set_thread_local_alloc_id(&self, def_id: DefId, new_alloc_id: AllocId) { + fn set_thread_local_alloc(&self, def_id: DefId, ptr: Pointer) { self.thread_local_alloc_ids .borrow_mut() - .try_insert((def_id, self.active_thread), new_alloc_id) + .try_insert((def_id, self.active_thread), ptr) .unwrap(); } @@ -435,11 +435,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Wakes up threads joining on the active one and deallocates thread-local statics. - /// The `AllocId` that can now be freed is returned. + /// The `AllocId` that can now be freed are returned. fn thread_terminated( &mut self, mut data_race: Option<&mut data_race::GlobalState>, - ) -> Vec { + ) -> Vec> { let mut free_tls_statics = Vec::new(); { let mut thread_local_statics = self.thread_local_alloc_ids.borrow_mut(); @@ -557,16 +557,16 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Get a thread-specific allocation id for the given thread-local static. /// If needed, allocate a new one. - fn get_or_create_thread_local_alloc_id( + fn get_or_create_thread_local_alloc( &mut self, def_id: DefId, - ) -> InterpResult<'tcx, AllocId> { + ) -> InterpResult<'tcx, Pointer> { let this = self.eval_context_mut(); let tcx = this.tcx; - if let Some(new_alloc_id) = this.machine.threads.get_thread_local_alloc_id(def_id) { + if let Some(old_alloc) = this.machine.threads.get_thread_local_alloc_id(def_id) { // We already have a thread-specific allocation id for this // thread-local static. - Ok(new_alloc_id) + Ok(old_alloc) } else { // We need to allocate a thread-specific allocation id for this // thread-local static. @@ -576,10 +576,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let allocation = tcx.eval_static_initializer(def_id)?; // Create a fresh allocation with this content. - let new_alloc_id = - this.memory.allocate_with(allocation.clone(), MiriMemoryKind::Tls.into()).alloc_id; - this.machine.threads.set_thread_local_alloc_id(def_id, new_alloc_id); - Ok(new_alloc_id) + let new_alloc = + this.memory.allocate_with(allocation.clone(), MiriMemoryKind::Tls.into()); + this.machine.threads.set_thread_local_alloc(def_id, new_alloc); + Ok(new_alloc) } } @@ -761,10 +761,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn thread_terminated(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - for alloc_id in this.machine.threads.thread_terminated(this.memory.extra.data_race.as_mut()) - { - let ptr = this.memory.global_base_pointer(alloc_id.into())?; - this.memory.deallocate(ptr, None, MiriMemoryKind::Tls.into())?; + for ptr in this.machine.threads.thread_terminated(this.memory.extra.data_race.as_mut()) { + this.memory.deallocate(ptr.into(), None, MiriMemoryKind::Tls.into())?; } Ok(()) } diff --git a/tests/compile-fail/dangling_pointers/deref-partially-dangling.rs b/tests/compile-fail/dangling_pointers/deref-partially-dangling.rs index a6d3aae414de..b7fcf4559e0a 100644 --- a/tests/compile-fail/dangling_pointers/deref-partially-dangling.rs +++ b/tests/compile-fail/dangling_pointers/deref-partially-dangling.rs @@ -3,6 +3,6 @@ fn main() { let x = (1, 13); let xptr = &x as *const _ as *const (i32, i32, i32); - let val = unsafe { (*xptr).1 }; //~ ERROR pointer must be in-bounds at offset 12, but is outside bounds of alloc + let val = unsafe { (*xptr).1 }; //~ ERROR pointer to 12 bytes starting at offset 0 is out-of-bounds assert_eq!(val, 13); } diff --git a/tests/compile-fail/dangling_pointers/dyn_size.rs b/tests/compile-fail/dangling_pointers/dyn_size.rs index 39a091387c6c..56de3970f1bb 100644 --- a/tests/compile-fail/dangling_pointers/dyn_size.rs +++ b/tests/compile-fail/dangling_pointers/dyn_size.rs @@ -9,5 +9,5 @@ fn main() { // That should be UB, as the reference is not fully dereferencable. let ptr: *const SliceWithHead = unsafe { std::mem::transmute((&buf, 4usize)) }; // Re-borrow that. This should be UB. - let _ptr = unsafe { &*ptr }; //~ ERROR pointer must be in-bounds at offset 5 + let _ptr = unsafe { &*ptr }; //~ ERROR pointer to 5 bytes starting at offset 0 is out-of-bounds } diff --git a/tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.rs b/tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.rs index 9db8a7dcba98..357eadf91c7f 100644 --- a/tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.rs +++ b/tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.rs @@ -4,5 +4,5 @@ fn main() { // This pointer *could* be NULL so we cannot load from it, not even at ZST let ptr = (&0u8 as *const u8).wrapping_sub(0x800) as *const (); - let _x: () = unsafe { *ptr }; //~ ERROR outside bounds + let _x: () = unsafe { *ptr }; //~ ERROR out-of-bounds } diff --git a/tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.rs b/tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.rs index 79eff2507ceb..7f50b9827d94 100644 --- a/tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.rs +++ b/tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.rs @@ -7,5 +7,5 @@ fn main() { // Also not assigning directly as that's array initialization, not assignment. let zst_val = [1u8; 0]; let ptr = (&0u8 as *const u8).wrapping_sub(0x800) as *mut [u8; 0]; - unsafe { *ptr = zst_val; } //~ ERROR outside bounds + unsafe { *ptr = zst_val; } //~ ERROR out-of-bounds } diff --git a/tests/compile-fail/dangling_pointers/out_of_bounds_read1.rs b/tests/compile-fail/dangling_pointers/out_of_bounds_read1.rs index 0c175af5266b..ef5cdeec9967 100644 --- a/tests/compile-fail/dangling_pointers/out_of_bounds_read1.rs +++ b/tests/compile-fail/dangling_pointers/out_of_bounds_read1.rs @@ -1,5 +1,5 @@ fn main() { let v: Vec = vec![1, 2]; - let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR outside bounds of alloc + let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR out-of-bounds panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/dangling_pointers/out_of_bounds_read2.rs b/tests/compile-fail/dangling_pointers/out_of_bounds_read2.rs index 0c175af5266b..ef5cdeec9967 100644 --- a/tests/compile-fail/dangling_pointers/out_of_bounds_read2.rs +++ b/tests/compile-fail/dangling_pointers/out_of_bounds_read2.rs @@ -1,5 +1,5 @@ fn main() { let v: Vec = vec![1, 2]; - let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR outside bounds of alloc + let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR out-of-bounds panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_1.rs b/tests/compile-fail/intrinsics/out_of_bounds_ptr_1.rs index 20bcc36f049d..d200b3eb0297 100644 --- a/tests/compile-fail/intrinsics/out_of_bounds_ptr_1.rs +++ b/tests/compile-fail/intrinsics/out_of_bounds_ptr_1.rs @@ -1,4 +1,4 @@ -// error-pattern: must be in-bounds at offset 5, but is outside bounds of alloc +// error-pattern: pointer to 5 bytes starting at offset 0 is out-of-bounds fn main() { let v = [0i8; 4]; let x = &v as *const i8; diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_2.rs b/tests/compile-fail/intrinsics/out_of_bounds_ptr_2.rs index 1e4759ddc46d..52b385b8e3b4 100644 --- a/tests/compile-fail/intrinsics/out_of_bounds_ptr_2.rs +++ b/tests/compile-fail/intrinsics/out_of_bounds_ptr_2.rs @@ -2,6 +2,6 @@ fn main() { let v = [0i8; 4]; let x = &v as *const i8; - let x = unsafe { x.offset(-1) }; + let x = unsafe { x.offset(isize::MIN) }; panic!("this should never print: {:?}", x); } diff --git a/tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.rs b/tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.rs index d07ecc4dc7f3..8760345409c8 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.rs +++ b/tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.rs @@ -1,4 +1,4 @@ -// error-pattern: outside bounds of alloc +// error-pattern: pointer at offset 32 is out-of-bounds fn main() { let x = Box::into_raw(Box::new(0u32)); diff --git a/tests/compile-fail/null_pointer_deref_zst.rs b/tests/compile-fail/null_pointer_deref_zst.rs index 45925f3586c4..04617c58f3ce 100644 --- a/tests/compile-fail/null_pointer_deref_zst.rs +++ b/tests/compile-fail/null_pointer_deref_zst.rs @@ -3,6 +3,6 @@ #[allow(deref_nullptr)] fn main() { - let x: () = unsafe { *std::ptr::null() }; //~ ERROR memory access failed: 0x0 is not a valid pointer + let x: () = unsafe { *std::ptr::null() }; //~ ERROR dereferencing pointer failed: 0x0 is not a valid pointer panic!("this should never print: {:?}", x); } diff --git a/tests/compile-fail/null_pointer_write_zst.rs b/tests/compile-fail/null_pointer_write_zst.rs index 595011fcd6a7..46a8345b1b45 100644 --- a/tests/compile-fail/null_pointer_write_zst.rs +++ b/tests/compile-fail/null_pointer_write_zst.rs @@ -1,10 +1,11 @@ // Some optimizations remove ZST accesses, thus masking this UB. // compile-flags: -Zmir-opt-level=0 +// error-pattern: memory access failed: 0x0 is not a valid pointer #[allow(deref_nullptr)] fn main() { // Not using the () type here, as writes of that type do not even have MIR generated. // Also not assigning directly as that's array initialization, not assignment. let zst_val = [1u8; 0]; - unsafe { *std::ptr::null_mut() = zst_val }; //~ ERROR memory access failed: 0x0 is not a valid pointer + unsafe { std::ptr::null_mut::<[u8; 0]>().write(zst_val) }; } diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-1.rs b/tests/compile-fail/stacked_borrows/issue-miri-1050-1.rs index 24df70a8179f..852eb69968ed 100644 --- a/tests/compile-fail/stacked_borrows/issue-miri-1050-1.rs +++ b/tests/compile-fail/stacked_borrows/issue-miri-1050-1.rs @@ -1,4 +1,4 @@ -// error-pattern: pointer must be in-bounds +// error-pattern: pointer to 4 bytes starting at offset 0 is out-of-bounds fn main() { unsafe { let ptr = Box::into_raw(Box::new(0u16)); diff --git a/tests/compile-fail/stacked_borrows/static_memory_modification.rs b/tests/compile-fail/stacked_borrows/static_memory_modification.rs index 55a7f816c034..417a03bb0335 100644 --- a/tests/compile-fail/stacked_borrows/static_memory_modification.rs +++ b/tests/compile-fail/stacked_borrows/static_memory_modification.rs @@ -3,6 +3,6 @@ static X: usize = 5; #[allow(mutable_transmutes)] fn main() { let _x = unsafe { - std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR writing to alloc0 which is read-only + std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR writing to alloc1 which is read-only }; } diff --git a/tests/compile-fail/zst1.rs b/tests/compile-fail/zst1.rs index e4ce7b8ecdf8..d400fba5d0c2 100644 --- a/tests/compile-fail/zst1.rs +++ b/tests/compile-fail/zst1.rs @@ -1,5 +1,5 @@ fn main() { // make sure ZST locals cannot be accessed let x = &() as *const () as *const i8; - let _val = unsafe { *x }; //~ ERROR pointer must be in-bounds + let _val = unsafe { *x }; //~ ERROR out-of-bounds } diff --git a/tests/compile-fail/zst3.rs b/tests/compile-fail/zst3.rs index 734c4b8ac4b8..7ecb8c7dca9d 100644 --- a/tests/compile-fail/zst3.rs +++ b/tests/compile-fail/zst3.rs @@ -14,5 +14,5 @@ fn main() { unsafe { *(x as *mut [u8; 0]) = zst_val; } // One byte further is OOB. let x = x.wrapping_offset(1); - unsafe { *(x as *mut [u8; 0]) = zst_val; } //~ ERROR pointer must be in-bounds + unsafe { *(x as *mut [u8; 0]) = zst_val; } //~ ERROR out-of-bounds } From bf8b2aa8dc201c25181992ae3e194b76dbb2e274 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Jul 2021 13:59:58 +0200 Subject: [PATCH 2764/5092] add test for better ptr handling in enum niches --- tests/run-pass/enum_discriminant_ptr_value.rs | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/run-pass/enum_discriminant_ptr_value.rs diff --git a/tests/run-pass/enum_discriminant_ptr_value.rs b/tests/run-pass/enum_discriminant_ptr_value.rs new file mode 100644 index 000000000000..618d503cd5f2 --- /dev/null +++ b/tests/run-pass/enum_discriminant_ptr_value.rs @@ -0,0 +1,9 @@ +// A niche-optimized enum where the discriminant is a pointer value -- relies on ptr-to-int casts in +// the niche handling code. +// compile-flags: -Zmiri-disable-stacked-borrows -Zmiri-disable-validation + +fn main() { + let x = 42; + let val: Option<&i32> = unsafe { std::mem::transmute((&x as *const i32).wrapping_offset(2)) }; + assert!(val.is_some()); +} From 0d65d500c67f65a54ed7caeb907bfa1095d43e0f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Jul 2021 20:24:57 +0200 Subject: [PATCH 2765/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index aee5d6ee3ba2..b5742bc7a004 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -3982eb35cabe3a99194d768d34a92347967c3fa2 +c78ebb7bdcfc924a20fd069891ffe1364d6814e7 From 6ce77164c19dc42c5f58cd5f0fff001a2f2f23f4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 Jul 2021 12:18:59 +0200 Subject: [PATCH 2766/5092] rustup --- rust-version | 2 +- tests/run-pass/dyn-lcsit.rs | 68 ------------------------------------- 2 files changed, 1 insertion(+), 69 deletions(-) delete mode 100644 tests/run-pass/dyn-lcsit.rs diff --git a/rust-version b/rust-version index b5742bc7a004..dc2d4398c48a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c78ebb7bdcfc924a20fd069891ffe1364d6814e7 +a72c360a30f9a8160e4f40340cecc9b1ce979cd7 diff --git a/tests/run-pass/dyn-lcsit.rs b/tests/run-pass/dyn-lcsit.rs deleted file mode 100644 index e7a5f13923a8..000000000000 --- a/tests/run-pass/dyn-lcsit.rs +++ /dev/null @@ -1,68 +0,0 @@ -// Taken from the rustc test suite; this triggers an interesting case in unsizing. - -#![allow(non_upper_case_globals, incomplete_features)] -#![feature(associated_type_bounds)] -#![feature(impl_trait_in_bindings)] - -use std::ops::Add; - -trait Tr1 { type As1; fn mk(&self) -> Self::As1; } -trait Tr2<'a> { fn tr2(self) -> &'a Self; } - -fn assert_copy(x: T) { let _x = x; let _x = x; } -fn assert_static(_: T) {} -fn assert_forall_tr2 Tr2<'a>>(_: T) {} - -#[derive(Copy, Clone)] -struct S1; -#[derive(Copy, Clone)] -struct S2; -impl Tr1 for S1 { type As1 = S2; fn mk(&self) -> Self::As1 { S2 } } - -const cdef_et1: &dyn Tr1 = &S1; -const sdef_et1: &dyn Tr1 = &S1; -pub fn use_et1() { assert_copy(cdef_et1.mk()); assert_copy(sdef_et1.mk()); } - -const cdef_et2: &(dyn Tr1 + Sync) = &S1; -static sdef_et2: &(dyn Tr1 + Sync) = &S1; -pub fn use_et2() { assert_static(cdef_et2.mk()); assert_static(sdef_et2.mk()); } - -const cdef_et3: &dyn Tr1>>> = { - struct A; - impl Tr1 for A { - type As1 = core::ops::Range; - fn mk(&self) -> Self::As1 { 0..10 } - } - &A -}; -pub fn use_et3() { - let _0 = cdef_et3.mk().clone(); - let mut s = 0u8; - for _1 in _0 { - let _2 = _1 + 1u8; - s += _2.into(); - } - assert_eq!(s, (0..10).map(|x| x + 1).sum()); -} - -const cdef_et4: &(dyn Tr1 Tr2<'a>> + Sync) = { - #[derive(Copy, Clone)] - struct A; - impl Tr1 for A { - type As1 = A; - fn mk(&self) -> A { A } - } - impl<'a> Tr2<'a> for A { - fn tr2(self) -> &'a Self { &A } - } - &A -}; -static sdef_et4: &(dyn Tr1 Tr2<'a>> + Sync) = cdef_et4; -pub fn use_et4() { assert_forall_tr2(cdef_et4.mk()); assert_forall_tr2(sdef_et4.mk()); } - -fn main() { - let _ = use_et1(); - let _ = use_et2(); - let _ = use_et3(); - let _ = use_et4(); -} From 46ed39ec200a3bd0e402c994203a9d67d62b0c6c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Jul 2021 14:43:23 +0200 Subject: [PATCH 2767/5092] adjust for PointerOutOfBounds change --- src/stacked_borrows.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index ddfbfd426680..e04de65ac3fd 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -623,14 +623,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let orig_tag = ptr.provenance.sb; // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). - let (allocation_size, _) = + let (alloc_size, _) = this.memory.get_size_and_align(alloc_id, AllocCheck::Dereferenceable)?; - if base_offset + size > allocation_size { + if base_offset + size > alloc_size { throw_ub!(PointerOutOfBounds { alloc_id, - offset: base_offset, - size, - allocation_size, + alloc_size, + ptr_offset: this.machine_usize_to_isize(base_offset.bytes()), + ptr_size: size, msg: CheckInAllocMsg::InboundsTest }); } From cf26458376f47c659c663b1735c395a94a475e5f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Jul 2021 14:43:32 +0200 Subject: [PATCH 2768/5092] test for negative offsets --- tests/compile-fail/intrinsics/out_of_bounds_ptr_3.rs | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/compile-fail/intrinsics/out_of_bounds_ptr_3.rs diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_3.rs b/tests/compile-fail/intrinsics/out_of_bounds_ptr_3.rs new file mode 100644 index 000000000000..cd0861efe5d9 --- /dev/null +++ b/tests/compile-fail/intrinsics/out_of_bounds_ptr_3.rs @@ -0,0 +1,7 @@ +// error-pattern: pointer to 1 byte starting at offset -1 is out-of-bounds +fn main() { + let v = [0i8; 4]; + let x = &v as *const i8; + let x = unsafe { x.offset(-1) }; + panic!("this should never print: {:?}", x); +} From 63286771d32344fb1a6adc256c3291c84bea7a3c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 Jul 2021 13:38:52 +0200 Subject: [PATCH 2769/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index dc2d4398c48a..fb2d0bf8f682 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a72c360a30f9a8160e4f40340cecc9b1ce979cd7 +718d53b0cb7dde93499cb92950d60b412f5a3d05 From a1cabac72707020e30a787f44740b855583fc341 Mon Sep 17 00:00:00 2001 From: Smit Soni Date: Tue, 15 Jun 2021 17:33:18 -0700 Subject: [PATCH 2770/5092] Fix use of deprecated `check_no_isolation` in posix fs ops Update posix fs shims to use new API `reject_in_isolation`, which allows rejection with error code instead of always forcing abort. Error code chosen for each op is the most appropriate one from the list in corresponding syscall's manual. Updated helper APIs to not use quotes (`) around input name while preparing the message. This allows callers to pass multi-word string like -- "`read` from stdin". --- src/diagnostics.rs | 2 +- src/helpers.rs | 2 +- src/shims/env.rs | 8 +-- src/shims/posix/fs.rs | 155 ++++++++++++++++++++++++++++++++++++------ 4 files changed, 140 insertions(+), 27 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index b5b75a7fc318..f66f66e0088f 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -328,7 +328,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx CreatedAlloc(AllocId(id)) => format!("created allocation with id {}", id), FreedAlloc(AllocId(id)) => format!("freed allocation with id {}", id), RejectedIsolatedOp(ref op) => - format!("`{}` was made to return an error due to isolation", op), + format!("{} was made to return an error due to isolation", op), }; let (title, diag_level) = match e { diff --git a/src/helpers.rs b/src/helpers.rs index 363aefa62d2f..e09ef2865fb2 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -409,7 +409,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx RejectOpWith::WarningWithoutBacktrace => { this.tcx .sess - .warn(&format!("`{}` was made to return an error due to isolation", op_name)); + .warn(&format!("{} was made to return an error due to isolation", op_name)); Ok(()) } RejectOpWith::Warning => { diff --git a/src/shims/env.rs b/src/shims/env.rs index ddd2b6158898..9290ec022b57 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -322,7 +322,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let size = this.read_scalar(&size_op)?.to_machine_usize(&*this.tcx)?; if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("getcwd", reject_with)?; + this.reject_in_isolation("`getcwd`", reject_with)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; return Ok(Pointer::null()); } @@ -355,7 +355,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.read_pointer(buf_op)?; if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("GetCurrentDirectoryW", reject_with)?; + this.reject_in_isolation("`GetCurrentDirectoryW`", reject_with)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; return Ok(0); } @@ -380,7 +380,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("chdir", reject_with)?; + this.reject_in_isolation("`chdir`", reject_with)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; return Ok(-1); @@ -408,7 +408,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let path = this.read_path_from_wide_str(this.read_pointer(path_op)?)?; if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("SetCurrentDirectoryW", reject_with)?; + this.reject_in_isolation("`SetCurrentDirectoryW`", reject_with)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; return Ok(0); diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index a14a9c907eed..3653fc43ebb1 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -4,7 +4,7 @@ use std::convert::{TryFrom, TryInto}; use std::fs::{ read_dir, remove_dir, remove_file, rename, DirBuilder, File, FileType, OpenOptions, ReadDir, }; -use std::io::{self, Read, Seek, SeekFrom, Write}; +use std::io::{self, ErrorKind, Read, Seek, SeekFrom, Write}; use std::path::Path; use std::time::SystemTime; @@ -504,7 +504,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("`open`")?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`open`", reject_with)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + return Ok(-1); + } let flag = this.read_scalar(flag_op)?.to_i32()?; @@ -594,7 +599,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn fcntl(&mut self, args: &[OpTy<'tcx, Tag>]) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("`fcntl`")?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`fcntl`", reject_with)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + return Ok(-1); + } if args.len() < 2 { throw_ub_format!( @@ -785,7 +795,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn unlink(&mut self, path_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("`unlink`")?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`unlink`", reject_with)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + return Ok(-1); + } let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; @@ -811,7 +826,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); - this.check_no_isolation("`symlink`")?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`symlink`", reject_with)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + return Ok(-1); + } let target = this.read_path_from_c_str(this.read_pointer(target_op)?)?; let linkpath = this.read_path_from_c_str(this.read_pointer(linkpath_op)?)?; @@ -827,7 +847,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("macos", "stat"); - this.check_no_isolation("`stat`")?; + + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`stat`", reject_with)?; + // macos stat never sets "EPERM". Set error code "ENOENT". + this.set_last_error_from_io_error(ErrorKind::NotFound)?; + return Ok(-1); + } + // `stat` always follows symlinks. this.macos_stat_or_lstat(true, path_op, buf_op) } @@ -840,7 +868,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("macos", "lstat"); - this.check_no_isolation("`lstat`")?; + + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`lstat`", reject_with)?; + // macos lstat never sets "EPERM". Set error code "ENOENT". + this.set_last_error_from_io_error(ErrorKind::NotFound)?; + return Ok(-1); + } + this.macos_stat_or_lstat(false, path_op, buf_op) } @@ -852,7 +888,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("macos", "fstat"); - this.check_no_isolation("`fstat`")?; + + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`fstat`", reject_with)?; + // Set error code as "EBADF" (bad fd) + return this.handle_not_found(); + } let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -874,7 +916,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("linux", "statx"); - this.check_no_isolation("`statx`")?; + + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`statx`", reject_with)?; + // statx never sets "EPERM". Set error code "ENOENT". + this.set_last_error_from_io_error(ErrorKind::NotFound)?; + return Ok(-1); + } let statxbuf_ptr = this.read_pointer(statxbuf_op)?; let pathname_ptr = this.read_pointer(pathname_op)?; @@ -1032,7 +1081,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("`rename`")?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`rename`", reject_with)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + return Ok(-1); + } let oldpath_ptr = this.read_pointer(oldpath_op)?; let newpath_ptr = this.read_pointer(newpath_op)?; @@ -1058,7 +1112,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("`mkdir`")?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`mkdir`", reject_with)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + return Ok(-1); + } #[cfg_attr(not(unix), allow(unused_variables))] let mode = if this.tcx.sess.target.os == "macos" { @@ -1088,7 +1147,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn rmdir(&mut self, path_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("`rmdir`")?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`rmdir`", reject_with)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + return Ok(-1); + } let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; @@ -1100,7 +1164,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn opendir(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - this.check_no_isolation("`opendir`")?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`opendir`", reject_with)?; + // opendir function never sets "EPERM". Set "ENOENT". + this.set_last_error_from_io_error(ErrorKind::NotFound)?; + return Ok(Scalar::null_ptr(this)); + } let name = this.read_path_from_c_str(this.read_pointer(name_op)?)?; @@ -1131,7 +1201,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("linux", "readdir64_r"); - this.check_no_isolation("`readdir64_r`")?; + + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`readdir64_r`", reject_with)?; + // Set error code as "EBADF" (bad fd) + return this.handle_not_found(); + } let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; @@ -1224,7 +1300,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("macos", "readdir_r"); - this.check_no_isolation("`readdir_r`")?; + + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`readdir_r`", reject_with)?; + // Set error code as "EBADF" (bad fd) + return this.handle_not_found(); + } let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; @@ -1313,7 +1395,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn closedir(&mut self, dirp_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("`closedir`")?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`closedir`", reject_with)?; + // Set error code as "EBADF" (bad fd) + return this.handle_not_found(); + } let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; @@ -1332,7 +1419,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("`ftruncate64`")?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`ftruncate64`", reject_with)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + return Ok(-1); + } let fd = this.read_scalar(fd_op)?.to_i32()?; let length = this.read_scalar(length_op)?.to_i64()?; @@ -1367,7 +1459,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); - this.check_no_isolation("`fsync`")?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`fsync`", reject_with)?; + // Set error code as "EBADF" (bad fd) + return this.handle_not_found(); + } let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { @@ -1383,7 +1480,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn fdatasync(&mut self, fd_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("`fdatasync`")?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`fdatasync`", reject_with)?; + // Set error code as "EBADF" (bad fd) + return this.handle_not_found(); + } let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { @@ -1405,7 +1507,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("`sync_file_range`")?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`sync_file_range`", reject_with)?; + // Set error code as "EBADF" (bad fd) + return this.handle_not_found(); + } let fd = this.read_scalar(fd_op)?.to_i32()?; let offset = this.read_scalar(offset_op)?.to_i64()?; @@ -1444,7 +1551,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); - this.check_no_isolation("readlink")?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`readlink`", reject_with)?; + // readlink never sets "EPERM". Set "ENOENT". + this.set_last_error_from_io_error(ErrorKind::NotFound)?; + return Ok(-1); + } let pathname = this.read_path_from_c_str(this.read_pointer(pathname_op)?)?; let buf = this.read_pointer(buf_op)?; From da6880427ac6bf2735019e34448c43900a5fc6df Mon Sep 17 00:00:00 2001 From: Smit Soni Date: Sun, 18 Jul 2021 14:40:59 -0700 Subject: [PATCH 2771/5092] Update error code for fs ops in isolation Change the code to either `EACCES` (if the op is performed on the path), or `EBADF` (if the op is performed the fd) Updated ops: `stat`, `opendir`, `ftruncate64`, and `readlink` Add a new test for fs ops in isolation. --- src/shims/posix/fs.rs | 44 +++++++++++--------- tests/run-pass/fs_with_isolation.rs | 54 +++++++++++++++++++++++++ tests/run-pass/fs_with_isolation.stderr | 20 +++++++++ 3 files changed, 100 insertions(+), 18 deletions(-) create mode 100644 tests/run-pass/fs_with_isolation.rs create mode 100644 tests/run-pass/fs_with_isolation.stderr diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 3653fc43ebb1..2693dc096286 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -851,8 +851,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`stat`", reject_with)?; - // macos stat never sets "EPERM". Set error code "ENOENT". - this.set_last_error_from_io_error(ErrorKind::NotFound)?; + let eacc = this.eval_libc("EACCES")?; + this.set_last_error(eacc)?; return Ok(-1); } @@ -872,8 +872,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`lstat`", reject_with)?; - // macos lstat never sets "EPERM". Set error code "ENOENT". - this.set_last_error_from_io_error(ErrorKind::NotFound)?; + let eacc = this.eval_libc("EACCES")?; + this.set_last_error(eacc)?; return Ok(-1); } @@ -917,14 +917,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.assert_target_os("linux", "statx"); - // Reject if isolation is enabled. - if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("`statx`", reject_with)?; - // statx never sets "EPERM". Set error code "ENOENT". - this.set_last_error_from_io_error(ErrorKind::NotFound)?; - return Ok(-1); - } - let statxbuf_ptr = this.read_pointer(statxbuf_op)?; let pathname_ptr = this.read_pointer(pathname_op)?; @@ -973,6 +965,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) } + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`statx`", reject_with)?; + let ecode = if path.is_absolute() || dirfd == this.eval_libc_i32("AT_FDCWD")? { + // since `path` is provided, either absolute or + // relative to CWD, `EACCES` is the most relevant. + this.eval_libc("EACCES")? + } else { + // `dirfd` is set to target file, and `path` is + // empty. `EACCES` would violate the spec. + this.eval_libc("EBADF")? + }; + this.set_last_error(ecode)?; + return Ok(-1); + } + // the `_mask_op` paramter specifies the file information that the caller requested. // However `statx` is allowed to return information that was not requested or to not // return information that was requested. This `mask` represents the information we can @@ -1167,8 +1175,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`opendir`", reject_with)?; - // opendir function never sets "EPERM". Set "ENOENT". - this.set_last_error_from_io_error(ErrorKind::NotFound)?; + let eacc = this.eval_libc("EACCES")?; + this.set_last_error(eacc)?; return Ok(Scalar::null_ptr(this)); } @@ -1422,8 +1430,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`ftruncate64`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; - return Ok(-1); + // Set error code as "EBADF" (bad fd) + return this.handle_not_found(); } let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -1554,8 +1562,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`readlink`", reject_with)?; - // readlink never sets "EPERM". Set "ENOENT". - this.set_last_error_from_io_error(ErrorKind::NotFound)?; + let eacc = this.eval_libc("EACCES")?; + this.set_last_error(eacc)?; return Ok(-1); } diff --git a/tests/run-pass/fs_with_isolation.rs b/tests/run-pass/fs_with_isolation.rs new file mode 100644 index 000000000000..a9e1e5094fa5 --- /dev/null +++ b/tests/run-pass/fs_with_isolation.rs @@ -0,0 +1,54 @@ +// ignore-windows: File handling is not implemented yet +// compile-flags: -Zmiri-isolation-error=warn-nobacktrace +// normalize-stderr-test "(stat(x)?)" -> "$$STAT" + +#![feature(rustc_private)] + +extern crate libc; + +use std::ffi::CString; +use std::os::unix; +use std::fs::{self, File}; +use std::io::{Error, ErrorKind}; + +fn main() { + // test `open` + assert_eq!(File::create("foo.txt").unwrap_err().kind(), ErrorKind::PermissionDenied); + + // test `fcntl` + unsafe { + assert_eq!(libc::fcntl(1, libc::F_DUPFD, 0), -1); + assert_eq!(Error::last_os_error().raw_os_error(), Some(libc::EPERM)); + } + + // test `unlink` + assert_eq!(fs::remove_file("foo.txt").unwrap_err().kind(), ErrorKind::PermissionDenied); + + // test `symlink` + assert_eq!(unix::fs::symlink("foo.txt", "foo_link.txt").unwrap_err().kind(), ErrorKind::PermissionDenied); + + // test `readlink` + let symlink_c_str = CString::new("foo.txt").unwrap(); + let mut buf = vec![0; "foo_link.txt".len() + 1]; + unsafe { + assert_eq!(libc::readlink(symlink_c_str.as_ptr(), buf.as_mut_ptr(), buf.len()), -1); + assert_eq!(Error::last_os_error().raw_os_error(), Some(libc::EACCES)); + } + + // test `stat` + assert_eq!(fs::metadata("foo.txt").unwrap_err().kind(), ErrorKind::PermissionDenied); + assert_eq!(Error::last_os_error().raw_os_error(), Some(libc::EACCES)); + + // test `rename` + assert_eq!(fs::rename("a.txt", "b.txt").unwrap_err().kind(), ErrorKind::PermissionDenied); + + // test `mkdir` + assert_eq!(fs::create_dir("foo/bar").unwrap_err().kind(), ErrorKind::PermissionDenied); + + // test `rmdir` + assert_eq!(fs::remove_dir("foo/bar").unwrap_err().kind(), ErrorKind::PermissionDenied); + + // test `opendir` + assert_eq!(fs::read_dir("foo/bar").unwrap_err().kind(), ErrorKind::PermissionDenied); + assert_eq!(Error::last_os_error().raw_os_error(), Some(libc::EACCES)); +} diff --git a/tests/run-pass/fs_with_isolation.stderr b/tests/run-pass/fs_with_isolation.stderr new file mode 100644 index 000000000000..ad75e42831b0 --- /dev/null +++ b/tests/run-pass/fs_with_isolation.stderr @@ -0,0 +1,20 @@ +warning: `open` was made to return an error due to isolation + +warning: `fcntl` was made to return an error due to isolation + +warning: `unlink` was made to return an error due to isolation + +warning: `symlink` was made to return an error due to isolation + +warning: `readlink` was made to return an error due to isolation + +warning: `$STAT` was made to return an error due to isolation + +warning: `rename` was made to return an error due to isolation + +warning: `mkdir` was made to return an error due to isolation + +warning: `rmdir` was made to return an error due to isolation + +warning: `opendir` was made to return an error due to isolation + From 46d31f92303c3dd8905aef1b71150acbd46e88c1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 24 Jul 2021 14:02:09 +0200 Subject: [PATCH 2772/5092] show proper error when using a sysroot without MIR --- src/diagnostics.rs | 2 -- src/eval.rs | 6 ++++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index b5b75a7fc318..cad08a2831a3 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -132,8 +132,6 @@ pub fn report_error<'tcx, 'mir>( }; #[rustfmt::skip] let helps = match e.kind() { - Unsupported(UnsupportedOpInfo::NoMirFor(..)) => - vec![(None, format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`"))], Unsupported(UnsupportedOpInfo::ThreadLocalStatic(_) | UnsupportedOpInfo::ReadExternStatic(_)) => panic!("Error should never be raised by Miri: {:?}", e.kind()), Unsupported(_) => diff --git a/src/eval.rs b/src/eval.rs index ae9ff9c1f5a4..02feae4a3503 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -138,6 +138,12 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( EnvVars::init(&mut ecx, config.excluded_env_vars)?; MemoryExtra::init_extern_statics(&mut ecx)?; + // Make sure we have MIR. We check MIR for some stable monomorphic function in libcore. + let sentinel = ecx.resolve_path(&["core", "ascii", "escape_default"]); + if !tcx.is_mir_available(sentinel.def.def_id()) { + tcx.sess.fatal("the current sysroot was built without `-Zalways-encode-mir`. Use `cargo miri setup` to prepare a sysroot that is suitable for Miri."); + } + // Setup first stack-frame let main_instance = ty::Instance::mono(tcx, main_id); let main_mir = ecx.load_mir(main_instance.def, None)?; From 20d0f2ee2607a1eecf095223250ca07307b9dbb0 Mon Sep 17 00:00:00 2001 From: Smit Soni Date: Tue, 20 Jul 2021 22:27:33 -0700 Subject: [PATCH 2773/5092] Move shim argument checks before isolation check This allows catching extremely incorrect arguments before rejecting due to isolation. --- src/shims/posix/fs.rs | 171 +++++++++++++++++++++--------------------- 1 file changed, 85 insertions(+), 86 deletions(-) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 2693dc096286..ac6e878da962 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -304,28 +304,6 @@ impl<'tcx> FileHandler { impl<'mir, 'tcx: 'mir> EvalContextExtPrivate<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// Emulate `stat` or `lstat` on `macos`. This function is not intended to be - /// called directly from `emulate_foreign_item_by_name`, so it does not check if isolation is - /// disabled or if the target OS is the correct one. Please use `macos_stat` or - /// `macos_lstat` instead. - fn macos_stat_or_lstat( - &mut self, - follow_symlink: bool, - path_op: &OpTy<'tcx, Tag>, - buf_op: &OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, i32> { - let this = self.eval_context_mut(); - - let path_scalar = this.read_pointer(path_op)?; - let path = this.read_path_from_c_str(path_scalar)?.into_owned(); - - let metadata = match FileMetadata::from_path(this, &path, follow_symlink)? { - Some(metadata) => metadata, - None => return Ok(-1), - }; - this.macos_stat_write_buf(metadata, buf_op) - } - fn macos_stat_write_buf( &mut self, metadata: FileMetadata, @@ -504,13 +482,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Reject if isolation is enabled. - if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("`open`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; - return Ok(-1); - } - let flag = this.read_scalar(flag_op)?.to_i32()?; // Get the mode. On macOS, the argument type `mode_t` is actually `u16`, but @@ -588,6 +559,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`open`", reject_with)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + return Ok(-1); + } + let fd = options.open(&path).map(|file| { let fh = &mut this.machine.file_handler; fh.insert_fd(Box::new(FileHandle { file, writable })) @@ -599,13 +577,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn fcntl(&mut self, args: &[OpTy<'tcx, Tag>]) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Reject if isolation is enabled. - if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("`fcntl`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; - return Ok(-1); - } - if args.len() < 2 { throw_ub_format!( "incorrect number of arguments for fcntl: got {}, expected at least 2", @@ -614,6 +585,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let fd = this.read_scalar(&args[0])?.to_i32()?; let cmd = this.read_scalar(&args[1])?.to_i32()?; + + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`fcntl`", reject_with)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + return Ok(-1); + } + // We only support getting the flags for a descriptor. if cmd == this.eval_libc_i32("F_GETFD")? { // Currently this is the only flag that `F_GETFD` returns. It is OK to just return the @@ -795,6 +774,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn unlink(&mut self, path_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; + // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`unlink`", reject_with)?; @@ -802,8 +783,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } - let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; - let result = remove_file(path).map(|_| 0); this.try_unwrap_io_result(result) } @@ -825,6 +804,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let this = self.eval_context_mut(); + let target = this.read_path_from_c_str(this.read_pointer(target_op)?)?; + let linkpath = this.read_path_from_c_str(this.read_pointer(linkpath_op)?)?; // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { @@ -833,9 +814,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } - let target = this.read_path_from_c_str(this.read_pointer(target_op)?)?; - let linkpath = this.read_path_from_c_str(this.read_pointer(linkpath_op)?)?; - let result = create_link(&target, &linkpath).map(|_| 0); this.try_unwrap_io_result(result) } @@ -848,6 +826,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("macos", "stat"); + let path_scalar = this.read_pointer(path_op)?; + let path = this.read_path_from_c_str(path_scalar)?.into_owned(); + // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`stat`", reject_with)?; @@ -857,7 +838,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // `stat` always follows symlinks. - this.macos_stat_or_lstat(true, path_op, buf_op) + let metadata = match FileMetadata::from_path(this, &path, true)? { + Some(metadata) => metadata, + None => return Ok(-1), + }; + + this.macos_stat_write_buf(metadata, buf_op) } // `lstat` is used to get symlink metadata. @@ -869,6 +855,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("macos", "lstat"); + let path_scalar = this.read_pointer(path_op)?; + let path = this.read_path_from_c_str(path_scalar)?.into_owned(); + // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`lstat`", reject_with)?; @@ -877,7 +866,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } - this.macos_stat_or_lstat(false, path_op, buf_op) + let metadata = match FileMetadata::from_path(this, &path, false)? { + Some(metadata) => metadata, + None => return Ok(-1), + }; + + this.macos_stat_write_buf(metadata, buf_op) } fn macos_fstat( @@ -889,6 +883,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.assert_target_os("macos", "fstat"); + let fd = this.read_scalar(fd_op)?.to_i32()?; + // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`fstat`", reject_with)?; @@ -896,8 +892,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return this.handle_not_found(); } - let fd = this.read_scalar(fd_op)?.to_i32()?; - let metadata = match FileMetadata::from_fd(this, fd)? { Some(metadata) => metadata, None => return Ok(-1), @@ -973,8 +967,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // relative to CWD, `EACCES` is the most relevant. this.eval_libc("EACCES")? } else { - // `dirfd` is set to target file, and `path` is - // empty. `EACCES` would violate the spec. + // `dirfd` is set to target file, and `path` is empty + // (or we would have hit the `throw_unsup_format` + // above). `EACCES` would violate the spec. + assert!(empty_path_flag); this.eval_libc("EBADF")? }; this.set_last_error(ecode)?; @@ -1089,13 +1085,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Reject if isolation is enabled. - if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("`rename`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; - return Ok(-1); - } - let oldpath_ptr = this.read_pointer(oldpath_op)?; let newpath_ptr = this.read_pointer(newpath_op)?; @@ -1108,6 +1097,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let oldpath = this.read_path_from_c_str(oldpath_ptr)?; let newpath = this.read_path_from_c_str(newpath_ptr)?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`rename`", reject_with)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + return Ok(-1); + } + let result = rename(oldpath, newpath).map(|_| 0); this.try_unwrap_io_result(result) @@ -1120,13 +1116,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Reject if isolation is enabled. - if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("`mkdir`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; - return Ok(-1); - } - #[cfg_attr(not(unix), allow(unused_variables))] let mode = if this.tcx.sess.target.os == "macos" { u32::from(this.read_scalar(mode_op)?.to_u16()?) @@ -1136,6 +1125,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`mkdir`", reject_with)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + return Ok(-1); + } + #[cfg_attr(not(unix), allow(unused_mut))] let mut builder = DirBuilder::new(); @@ -1155,6 +1151,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn rmdir(&mut self, path_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; + // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`rmdir`", reject_with)?; @@ -1162,8 +1160,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } - let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; - let result = remove_dir(path).map(|_| 0i32); this.try_unwrap_io_result(result) @@ -1172,6 +1168,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn opendir(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); + let name = this.read_path_from_c_str(this.read_pointer(name_op)?)?; + // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`opendir`", reject_with)?; @@ -1180,8 +1178,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(Scalar::null_ptr(this)); } - let name = this.read_path_from_c_str(this.read_pointer(name_op)?)?; - let result = read_dir(name); match result { @@ -1210,6 +1206,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.assert_target_os("linux", "readdir64_r"); + let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; + // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`readdir64_r`", reject_with)?; @@ -1217,8 +1215,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return this.handle_not_found(); } - let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; - let dir_iter = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { err_unsup_format!("the DIR pointer passed to readdir64_r did not come from opendir") })?; @@ -1309,6 +1305,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.assert_target_os("macos", "readdir_r"); + let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; + // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`readdir_r`", reject_with)?; @@ -1316,8 +1314,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return this.handle_not_found(); } - let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; - let dir_iter = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { err_unsup_format!("the DIR pointer passed to readdir_r did not come from opendir") })?; @@ -1403,6 +1399,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn closedir(&mut self, dirp_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; + // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`closedir`", reject_with)?; @@ -1410,8 +1408,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return this.handle_not_found(); } - let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; - if let Some(dir_iter) = this.machine.dir_handler.streams.remove(&dirp) { drop(dir_iter); Ok(0) @@ -1427,6 +1423,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + let fd = this.read_scalar(fd_op)?.to_i32()?; + let length = this.read_scalar(length_op)?.to_i64()?; + // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`ftruncate64`", reject_with)?; @@ -1434,8 +1433,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return this.handle_not_found(); } - let fd = this.read_scalar(fd_op)?.to_i32()?; - let length = this.read_scalar(length_op)?.to_i64()?; if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { // FIXME: Support ftruncate64 for all FDs let FileHandle { file, writable } = file_descriptor.as_file_handle()?; @@ -1467,6 +1464,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); + let fd = this.read_scalar(fd_op)?.to_i32()?; + // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`fsync`", reject_with)?; @@ -1474,7 +1473,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return this.handle_not_found(); } - let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support fsync for all FDs let FileHandle { file, writable } = file_descriptor.as_file_handle()?; @@ -1488,6 +1486,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn fdatasync(&mut self, fd_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + let fd = this.read_scalar(fd_op)?.to_i32()?; + // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`fdatasync`", reject_with)?; @@ -1495,7 +1495,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return this.handle_not_found(); } - let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support fdatasync for all FDs let FileHandle { file, writable } = file_descriptor.as_file_handle()?; @@ -1515,13 +1514,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Reject if isolation is enabled. - if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("`sync_file_range`", reject_with)?; - // Set error code as "EBADF" (bad fd) - return this.handle_not_found(); - } - let fd = this.read_scalar(fd_op)?.to_i32()?; let offset = this.read_scalar(offset_op)?.to_i64()?; let nbytes = this.read_scalar(nbytes_op)?.to_i64()?; @@ -1541,6 +1533,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`sync_file_range`", reject_with)?; + // Set error code as "EBADF" (bad fd) + return this.handle_not_found(); + } + if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support sync_data_range for all FDs let FileHandle { file, writable } = file_descriptor.as_file_handle()?; @@ -1559,6 +1558,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); + let pathname = this.read_path_from_c_str(this.read_pointer(pathname_op)?)?; + let buf = this.read_pointer(buf_op)?; + let bufsize = this.read_scalar(bufsize_op)?.to_machine_usize(this)?; + // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`readlink`", reject_with)?; @@ -1567,10 +1570,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } - let pathname = this.read_path_from_c_str(this.read_pointer(pathname_op)?)?; - let buf = this.read_pointer(buf_op)?; - let bufsize = this.read_scalar(bufsize_op)?.to_machine_usize(this)?; - let result = std::fs::read_link(pathname); match result { Ok(resolved) => { From 71efd950d17faabc4025acb460c4000bf97978f7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Jul 2021 14:08:12 +0200 Subject: [PATCH 2774/5092] also ignore 'thread leaks' with -Zmiri-ignore-leaks --- README.md | 3 ++- src/eval.rs | 6 +++++ src/thread.rs | 21 +++++++++------- .../libc_pthread_create_main_terminate.rs | 4 ++-- tests/run-pass/threadleak_ignored.rs | 24 +++++++++++++++++++ tests/run-pass/threadleak_ignored.stderr | 3 +++ 6 files changed, 49 insertions(+), 12 deletions(-) create mode 100644 tests/run-pass/threadleak_ignored.rs create mode 100644 tests/run-pass/threadleak_ignored.stderr diff --git a/README.md b/README.md index cbac48db5ea8..7cd802762bff 100644 --- a/README.md +++ b/README.md @@ -230,7 +230,8 @@ environment variable: the host so that it cannot be accessed by the program. Can be used multiple times to exclude several variables. On Windows, the `TERM` environment variable is excluded by default. -* `-Zmiri-ignore-leaks` disables the memory leak checker. +* `-Zmiri-ignore-leaks` disables the memory leak checker, and also allows some + remaining threads to exist when the main thread exits. * `-Zmiri-measureme=` enables `measureme` profiling for the interpreted program. This can be used to find which parts of your program are executing slowly under Miri. The profile is written out to a file with the prefix ``, and can be processed diff --git a/src/eval.rs b/src/eval.rs index ae9ff9c1f5a4..9531a2d78aba 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -300,6 +300,12 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> match res { Ok(return_code) => { if !ignore_leaks { + // Check for thread leaks. + if !ecx.have_all_terminated() { + tcx.sess.err("the main thread terminated without waiting for all remaining threads"); + return None; + } + // Check for memory leaks. info!("Additonal static roots: {:?}", ecx.machine.static_roots); let leaks = ecx.memory.leak_report(&ecx.machine.static_roots); if leaks != 0 { diff --git a/src/thread.rs b/src/thread.rs index de8e41224b20..a5deceb6e71d 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -302,6 +302,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { self.threads[thread_id].state == ThreadState::Terminated } + /// Have all threads terminated? + fn have_all_terminated(&self) -> bool { + self.threads.iter().all(|thread| thread.state == ThreadState::Terminated) + } + /// Enable the thread for execution. The thread must be terminated. fn enable_thread(&mut self, thread_id: ThreadId) { assert!(self.has_terminated(thread_id)); @@ -491,15 +496,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { // If we get here again and the thread is *still* terminated, there are no more dtors to run. if self.threads[MAIN_THREAD].state == ThreadState::Terminated { // The main thread terminated; stop the program. - if self.threads.iter().any(|thread| thread.state != ThreadState::Terminated) { - // FIXME: This check should be either configurable or just emit - // a warning. For example, it seems normal for a program to - // terminate without waiting for its detached threads to - // terminate. However, this case is not trivial to support - // because we also probably do not want to consider the memory - // owned by these threads as leaked. - throw_unsup_format!("the main thread terminated without waiting for other threads"); - } + // We do *not* run TLS dtors of remaining threads, which seems to match rustc behavior. return Ok(SchedulingAction::Stop); } // This thread and the program can keep going. @@ -645,6 +642,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.threads.has_terminated(thread_id) } + #[inline] + fn have_all_terminated(&self) -> bool { + let this = self.eval_context_ref(); + this.machine.threads.have_all_terminated() + } + #[inline] fn enable_thread(&mut self, thread_id: ThreadId) { let this = self.eval_context_mut(); diff --git a/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs b/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs index 35ee03242d11..9b576bbb0868 100644 --- a/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs +++ b/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs @@ -1,5 +1,5 @@ // ignore-windows: No libc on Windows -// error-pattern: unsupported operation: the main thread terminated without waiting for other threads +// error-pattern: the main thread terminated without waiting for all remaining threads // Check that we terminate the program when the main thread terminates. @@ -10,7 +10,7 @@ extern crate libc; use std::{mem, ptr}; extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { - ptr::null_mut() + loop {} } fn main() { diff --git a/tests/run-pass/threadleak_ignored.rs b/tests/run-pass/threadleak_ignored.rs new file mode 100644 index 000000000000..14a7449f3392 --- /dev/null +++ b/tests/run-pass/threadleak_ignored.rs @@ -0,0 +1,24 @@ +// compile-flags: -Zmiri-ignore-leaks + +//! Test that leaking threads works, and that their destructors are not executed. + +use std::cell::RefCell; + +struct LoudDrop(i32); +impl Drop for LoudDrop { + fn drop(&mut self) { + eprintln!("Dropping {}", self.0); + } +} + +thread_local! { + static X: RefCell> = RefCell::new(None); +} + +fn main() { + X.with(|x| *x.borrow_mut() = Some(LoudDrop(0))); + + let _detached = std::thread::spawn(|| { + X.with(|x| *x.borrow_mut() = Some(LoudDrop(1))); + }); +} diff --git a/tests/run-pass/threadleak_ignored.stderr b/tests/run-pass/threadleak_ignored.stderr new file mode 100644 index 000000000000..aa037511853b --- /dev/null +++ b/tests/run-pass/threadleak_ignored.stderr @@ -0,0 +1,3 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +Dropping 0 From df9d481989dee1dcbe9a3f886dcbb030deb2144b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Jul 2021 14:19:57 +0200 Subject: [PATCH 2775/5092] tell users how to disable the leak check --- src/eval.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/eval.rs b/src/eval.rs index 9531a2d78aba..e559dfedf933 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -302,7 +302,10 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> if !ignore_leaks { // Check for thread leaks. if !ecx.have_all_terminated() { - tcx.sess.err("the main thread terminated without waiting for all remaining threads"); + tcx.sess.err( + "the main thread terminated without waiting for all remaining threads", + ); + tcx.sess.note_without_error("pass `-Zmiri-ignore-leaks` to disable this check"); return None; } // Check for memory leaks. @@ -310,6 +313,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> let leaks = ecx.memory.leak_report(&ecx.machine.static_roots); if leaks != 0 { tcx.sess.err("the evaluated program leaked memory"); + tcx.sess.note_without_error("pass `-Zmiri-ignore-leaks` to disable this check"); // Ignore the provided return code - let the reported error // determine the return code. return None; From 24fa9deddc8d5bf940ee89672cb819e802b39d43 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Jul 2021 14:33:41 +0200 Subject: [PATCH 2776/5092] add test for mixing up System and Global memory --- tests/compile-fail/alloc/global_system_mixup.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tests/compile-fail/alloc/global_system_mixup.rs diff --git a/tests/compile-fail/alloc/global_system_mixup.rs b/tests/compile-fail/alloc/global_system_mixup.rs new file mode 100644 index 000000000000..afe9d5cc8254 --- /dev/null +++ b/tests/compile-fail/alloc/global_system_mixup.rs @@ -0,0 +1,13 @@ +// Make sure we detect when the `Global` and `System` allocators are mixed +// (even when the default `Global` uses `System`). +// error-pattern: which is Rust heap memory, using + +#![feature(allocator_api, slice_ptr_get)] + +use std::alloc::{Allocator, Global, System, Layout}; + +fn main() { + let l = Layout::from_size_align(1, 1).unwrap(); + let ptr = Global.allocate(l).unwrap().as_non_null_ptr(); + unsafe { System.deallocate(ptr, l); } +} From 679d10f98b765294aefbce61b525de407fc2cea4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Jul 2021 14:38:02 +0200 Subject: [PATCH 2777/5092] no concurrency on windows --- tests/run-pass/threadleak_ignored.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-pass/threadleak_ignored.rs b/tests/run-pass/threadleak_ignored.rs index 14a7449f3392..840fbc1ebcbc 100644 --- a/tests/run-pass/threadleak_ignored.rs +++ b/tests/run-pass/threadleak_ignored.rs @@ -1,3 +1,4 @@ +// ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-ignore-leaks //! Test that leaking threads works, and that their destructors are not executed. From 66aa3d0247fd47051077f005d2d1462316c83fe1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 26 Jul 2021 21:54:28 +0200 Subject: [PATCH 2778/5092] make the loop infinite --- tests/run-pass/threadleak_ignored.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-pass/threadleak_ignored.rs b/tests/run-pass/threadleak_ignored.rs index 840fbc1ebcbc..4fc52cdb8d7d 100644 --- a/tests/run-pass/threadleak_ignored.rs +++ b/tests/run-pass/threadleak_ignored.rs @@ -21,5 +21,6 @@ fn main() { let _detached = std::thread::spawn(|| { X.with(|x| *x.borrow_mut() = Some(LoudDrop(1))); + loop {} }); } From 78bcd12b17ae32fb74815cb2908a5149d5713415 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Jul 2021 14:05:37 +0200 Subject: [PATCH 2779/5092] make sure we only terminate main thread once TLS is initialized --- tests/run-pass/threadleak_ignored.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/threadleak_ignored.rs b/tests/run-pass/threadleak_ignored.rs index 4fc52cdb8d7d..7bb51d2dea61 100644 --- a/tests/run-pass/threadleak_ignored.rs +++ b/tests/run-pass/threadleak_ignored.rs @@ -18,9 +18,20 @@ thread_local! { fn main() { X.with(|x| *x.borrow_mut() = Some(LoudDrop(0))); + + // Set up a channel so that we can learn when the other thread initialized `X` + // (so that we are sure there is something to drop). + let (send, recv) = std::sync::mpsc::channel::<()>(); - let _detached = std::thread::spawn(|| { + let _detached = std::thread::spawn(move || { X.with(|x| *x.borrow_mut() = Some(LoudDrop(1))); + send.send(()).unwrap(); + std::thread::yield_now(); loop {} }); + + std::thread::yield_now(); + + // Wait until child thread has initialized its `X`. + let () = recv.recv().unwrap(); } From c76fa2138e82eb5d93ac843102c5eea6e37830f0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Jul 2021 18:38:35 +0200 Subject: [PATCH 2780/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index fb2d0bf8f682..9b74f391bc9e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -718d53b0cb7dde93499cb92950d60b412f5a3d05 +3bc9dd0dd293ab82945e35888ed6d7ab802761ef From a789b49e4c0e7d742cc39713484596293d844537 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Fri, 30 Jul 2021 21:28:34 +0800 Subject: [PATCH 2781/5092] Use `Lrc` instead of `Rc` in `MiriCompilerCalls::config()` --- src/bin/miri.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 5a8f07263f35..18c393815ca5 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -1,5 +1,6 @@ #![feature(rustc_private, bool_to_option, stmt_expr_attributes)] +extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_hir; @@ -12,12 +13,12 @@ use std::convert::TryFrom; use std::env; use std::num::NonZeroU64; use std::path::PathBuf; -use std::rc::Rc; use std::str::FromStr; use hex::FromHexError; use log::debug; +use rustc_data_structures::sync::Lrc; use rustc_driver::Compilation; use rustc_errors::emitter::{ColorConfig, HumanReadableErrorType}; use rustc_hir::{self as hir, def_id::LOCAL_CRATE, Node}; @@ -42,7 +43,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { // HACK: rustc will emit "crate ... required to be available in rlib format, but // was not found in this form" errors once we use `tcx.dependency_formats()` if // there's no rlib provided, so setting a dummy path here to workaround those errors. - Rc::make_mut(&mut crate_source).rlib = Some((PathBuf::new(), PathKind::All)); + Lrc::make_mut(&mut crate_source).rlib = Some((PathBuf::new(), PathKind::All)); crate_source }; }); From 5338a16018878f27ac15bb353a7d1d719b3ddcd6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 Jul 2021 12:47:04 +0200 Subject: [PATCH 2782/5092] adjust for ERR_ON_PARTIAL_PTR_OVERWRITE --- src/machine.rs | 4 ++++ ..._makes_the_rest_uninit.rs => pointer_partial_overwrite.rs} | 3 +++ .../{pointer_byte_read.rs => pointer_partial_read.rs} | 2 ++ 3 files changed, 9 insertions(+) rename tests/compile-fail/{overwriting_part_of_relocation_makes_the_rest_uninit.rs => pointer_partial_overwrite.rs} (82%) rename tests/compile-fail/{pointer_byte_read.rs => pointer_partial_read.rs} (67%) diff --git a/src/machine.rs b/src/machine.rs index 90e3d06aba99..03f53033b798 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -128,8 +128,12 @@ pub struct Tag { } impl Provenance for Tag { + // We use absolute addresses in the `offset` of a `Pointer`. const OFFSET_IS_ADDR: bool = true; + // We cannot err on partial overwrites, it happens too often in practice (due to unions). + const ERR_ON_PARTIAL_PTR_OVERWRITE: bool = false; + fn fmt(ptr: &Pointer, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (tag, addr) = ptr.into_parts(); // address is absolute write!(f, "0x{:x}", addr.bytes())?; diff --git a/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_uninit.rs b/tests/compile-fail/pointer_partial_overwrite.rs similarity index 82% rename from tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_uninit.rs rename to tests/compile-fail/pointer_partial_overwrite.rs index 3eab4c0f3d5e..8bee58d20a59 100644 --- a/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_uninit.rs +++ b/tests/compile-fail/pointer_partial_overwrite.rs @@ -1,6 +1,9 @@ // Make sure we find these even with many checks disabled. // compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +// Test what happens when we overwrite parts of a pointer. +// Also see . + fn main() { let mut p = &42; unsafe { diff --git a/tests/compile-fail/pointer_byte_read.rs b/tests/compile-fail/pointer_partial_read.rs similarity index 67% rename from tests/compile-fail/pointer_byte_read.rs rename to tests/compile-fail/pointer_partial_read.rs index dcb0fd3fb906..a4a5071f5da0 100644 --- a/tests/compile-fail/pointer_byte_read.rs +++ b/tests/compile-fail/pointer_partial_read.rs @@ -1,3 +1,5 @@ +// Test what happens when we read parts of a pointer. +// Related to . fn main() { let x = 13; let y = &x; From 257e9cef66666cfce885fb44ca8f1edad2c79ac6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 Jul 2021 15:22:09 +0200 Subject: [PATCH 2783/5092] docify some comments --- src/machine.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 03f53033b798..62c1a93079cb 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -123,15 +123,15 @@ impl fmt::Display for MiriMemoryKind { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Tag { pub alloc_id: AllocId, - // Stacked Borrows tag. + /// Stacked Borrows tag. pub sb: SbTag, } impl Provenance for Tag { - // We use absolute addresses in the `offset` of a `Pointer`. + /// We use absolute addresses in the `offset` of a `Pointer`. const OFFSET_IS_ADDR: bool = true; - // We cannot err on partial overwrites, it happens too often in practice (due to unions). + /// We cannot err on partial overwrites, it happens too often in practice (due to unions). const ERR_ON_PARTIAL_PTR_OVERWRITE: bool = false; fn fmt(ptr: &Pointer, f: &mut fmt::Formatter<'_>) -> fmt::Result { From 3a922286e31801a03ed52a31151f7b5f9f8ae4aa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Aug 2021 17:59:48 +0200 Subject: [PATCH 2784/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 9b74f391bc9e..ebcec429d18e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -3bc9dd0dd293ab82945e35888ed6d7ab802761ef +3227e35765bab6d02c581928e26ad1d34bacf394 From dced6b8518485aa8b6b069c09878d39bbb0ae22b Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Wed, 4 Aug 2021 16:46:11 +0800 Subject: [PATCH 2785/5092] Update cargo-miri test --- rust-version | 2 +- test-cargo-miri/test.default.stdout.ref | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index ebcec429d18e..c8725ea02252 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -3227e35765bab6d02c581928e26ad1d34bacf394 +71ff9b41e9ebd3e336019513917a7a8868d1cc66 diff --git a/test-cargo-miri/test.default.stdout.ref b/test-cargo-miri/test.default.stdout.ref index 4edcb7ba7d91..d2f94bb5950d 100644 --- a/test-cargo-miri/test.default.stdout.ref +++ b/test-cargo-miri/test.default.stdout.ref @@ -11,9 +11,6 @@ test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out running 3 tests -test src/lib.rs - make_true (line 2) ... ok -test src/lib.rs - make_true (line 5) - compile ... ok -test src/lib.rs - make_true (line 8) - compile fail ... ok - +... test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME From d12d4050aeaff674457f111c67a21d37e8911b40 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 4 Aug 2021 11:25:33 +0200 Subject: [PATCH 2786/5092] improve test-cargo-miri output --- test-cargo-miri/run-test.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 51433d98a2ed..81a1b1b3f8a7 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -46,12 +46,13 @@ def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): # All good! return # Show output - print("--- BEGIN stdout ---") + print("Test stdout or stderr did not match reference!") + print("--- BEGIN test stdout ---") print(stdout, end="") - print("--- END stdout ---") - print("--- BEGIN stderr ---") + print("--- END test stdout ---") + print("--- BEGIN test stderr ---") print(stderr, end="") - print("--- END stderr ---") + print("--- END test stderr ---") fail("exit code was {}".format(p.returncode)) def test_no_rebuild(name, cmd, env={}): From af7eb369b1eef147032e570d81dfc5c4e341b0ea Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Thu, 5 Aug 2021 17:10:30 +0800 Subject: [PATCH 2787/5092] Fix tests for `C-unwind` ABI changes --- rust-version | 2 +- tests/compile-fail/abort-terminator.rs | 5 ++--- .../function_calls/exported_symbol_bad_unwind2.rs | 4 ++-- .../function_calls/exported_symbol_bad_unwind3.rs | 15 --------------- tests/compile-fail/panic/bad_miri_start_panic.rs | 2 ++ .../function_calls/exported_symbol_good_unwind.rs | 13 +------------ .../exported_symbol_good_unwind.stderr | 5 ++--- .../exported_symbol_unwind_allowed.rs | 15 --------------- .../exported_symbol_unwind_allowed.stderr | 2 -- 9 files changed, 10 insertions(+), 53 deletions(-) delete mode 100644 tests/compile-fail/function_calls/exported_symbol_bad_unwind3.rs delete mode 100644 tests/run-pass/function_calls/exported_symbol_unwind_allowed.rs delete mode 100644 tests/run-pass/function_calls/exported_symbol_unwind_allowed.stderr diff --git a/rust-version b/rust-version index c8725ea02252..e40ae69e2877 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -71ff9b41e9ebd3e336019513917a7a8868d1cc66 +996ff2e0a0f911f52bb1de6bdd0cfd5704de1fc9 diff --git a/tests/compile-fail/abort-terminator.rs b/tests/compile-fail/abort-terminator.rs index 73286a1759ba..8e6e2a766007 100644 --- a/tests/compile-fail/abort-terminator.rs +++ b/tests/compile-fail/abort-terminator.rs @@ -1,8 +1,7 @@ // error-pattern: the program aborted -#![feature(unwind_attributes)] +#![feature(c_unwind)] -#[unwind(aborts)] -fn panic_abort() { panic!() } +extern "C" fn panic_abort() { panic!() } fn main() { panic_abort(); diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.rs b/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.rs index 85cca8f1a6bd..e80a79d1028d 100644 --- a/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.rs +++ b/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.rs @@ -4,6 +4,8 @@ #[cfg_attr(any(definition, both), rustc_allocator_nounwind)] #[no_mangle] extern "C-unwind" fn nounwind() { + //[definition]~^ ERROR abnormal termination: the program aborted execution + //[both]~^^ ERROR abnormal termination: the program aborted execution panic!(); } @@ -14,6 +16,4 @@ fn main() { } unsafe { nounwind() } //[extern_block]~^ ERROR unwinding past a stack frame that does not allow unwinding - //[definition]~^^ ERROR unwinding past a stack frame that does not allow unwinding - //[both]~^^^ ERROR unwinding past a stack frame that does not allow unwinding } diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind3.rs b/tests/compile-fail/function_calls/exported_symbol_bad_unwind3.rs deleted file mode 100644 index bbbe677d3651..000000000000 --- a/tests/compile-fail/function_calls/exported_symbol_bad_unwind3.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![feature(unwind_attributes)] - -#[unwind(allowed)] -#[no_mangle] -extern "C" fn unwind() { - panic!(); -} - -fn main() { - extern "C" { - fn unwind(); - } - unsafe { unwind() } - //~^ ERROR unwinding past a stack frame that does not allow unwinding -} diff --git a/tests/compile-fail/panic/bad_miri_start_panic.rs b/tests/compile-fail/panic/bad_miri_start_panic.rs index f77f892abc1c..089cd86f1b8f 100644 --- a/tests/compile-fail/panic/bad_miri_start_panic.rs +++ b/tests/compile-fail/panic/bad_miri_start_panic.rs @@ -1,4 +1,6 @@ // compile-flags: -Zmiri-disable-abi-check +// This feature is required to trigger the error using the "C" ABI. +#![feature(c_unwind)] extern "C" { fn miri_start_panic(payload: *mut u8) -> !; diff --git a/tests/run-pass/function_calls/exported_symbol_good_unwind.rs b/tests/run-pass/function_calls/exported_symbol_good_unwind.rs index 3dd3b8f22de5..71b799a1f12b 100644 --- a/tests/run-pass/function_calls/exported_symbol_good_unwind.rs +++ b/tests/run-pass/function_calls/exported_symbol_good_unwind.rs @@ -2,16 +2,10 @@ // found in this form" errors works without `-C prefer-dynamic` (`panic!` calls foreign function // `__rust_start_panic`). // no-prefer-dynamic -#![feature(c_unwind, unboxed_closures, unwind_attributes)] +#![feature(c_unwind, unboxed_closures)] use std::panic; -#[no_mangle] -#[unwind(allowed)] -extern "C" fn good_unwind_allowed() { - panic!(); -} - #[no_mangle] extern "C-unwind" fn good_unwind_c() { panic!(); @@ -29,11 +23,6 @@ extern "rust-call" fn good_unwind_rust_call(_: ()) -> ! { } fn main() -> ! { - extern "C" { - #[unwind(allowed)] - fn good_unwind_allowed(); - } - panic::catch_unwind(|| unsafe { good_unwind_allowed() }).unwrap_err(); extern "C-unwind" { fn good_unwind_c(); } diff --git a/tests/run-pass/function_calls/exported_symbol_good_unwind.stderr b/tests/run-pass/function_calls/exported_symbol_good_unwind.stderr index 3347f00b65ea..40a8f39509fa 100644 --- a/tests/run-pass/function_calls/exported_symbol_good_unwind.stderr +++ b/tests/run-pass/function_calls/exported_symbol_good_unwind.stderr @@ -1,5 +1,4 @@ -thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:12:5 +thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:11:5 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:17:5 +thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:16:5 thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:22:5 -thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:28:5 diff --git a/tests/run-pass/function_calls/exported_symbol_unwind_allowed.rs b/tests/run-pass/function_calls/exported_symbol_unwind_allowed.rs deleted file mode 100644 index 0e4ec5739a8a..000000000000 --- a/tests/run-pass/function_calls/exported_symbol_unwind_allowed.rs +++ /dev/null @@ -1,15 +0,0 @@ -// compile-flags: -Zmiri-disable-abi-check -#![feature(unwind_attributes, c_unwind)] - -#[no_mangle] -extern "C-unwind" fn unwind() { - panic!(); -} - -fn main() { - extern "C" { - #[unwind(allowed)] - fn unwind(); - } - unsafe { unwind() } -} diff --git a/tests/run-pass/function_calls/exported_symbol_unwind_allowed.stderr b/tests/run-pass/function_calls/exported_symbol_unwind_allowed.stderr deleted file mode 100644 index 14ee43950cec..000000000000 --- a/tests/run-pass/function_calls/exported_symbol_unwind_allowed.stderr +++ /dev/null @@ -1,2 +0,0 @@ -thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_unwind_allowed.rs:6:5 -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace From 78b4c7bf79cec9f2cef04a5dbb35609f83c8286c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 14 Aug 2021 14:47:57 +0200 Subject: [PATCH 2788/5092] rustup --- rust-version | 2 +- tests/compile-fail/function_calls/exported_symbol_wrong_type.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index e40ae69e2877..1cf2fb4b0ff9 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -996ff2e0a0f911f52bb1de6bdd0cfd5704de1fc9 +fa2692990c05652c7823c8d2afae501a00a69050 diff --git a/tests/compile-fail/function_calls/exported_symbol_wrong_type.rs b/tests/compile-fail/function_calls/exported_symbol_wrong_type.rs index 3ffd506c94bb..0a493e35a7ce 100644 --- a/tests/compile-fail/function_calls/exported_symbol_wrong_type.rs +++ b/tests/compile-fail/function_calls/exported_symbol_wrong_type.rs @@ -5,5 +5,5 @@ fn main() { extern "C" { fn FOO(); } - unsafe { FOO() } //~ ERROR attempt to call an exported symbol that is not defined as a function + unsafe { FOO() } //~ ERROR unsupported operation: can't call foreign function: FOO } From 838ed1d75412f8c4ccb3750da6e67687af427520 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 15 Aug 2021 17:18:00 +0800 Subject: [PATCH 2789/5092] Update tests for `#[no_mangle]` associated functions --- test-cargo-miri/exported-symbol-dep/src/lib.rs | 4 ++-- tests/run-pass/function_calls/exported_symbol.rs | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/test-cargo-miri/exported-symbol-dep/src/lib.rs b/test-cargo-miri/exported-symbol-dep/src/lib.rs index db257dcb22c4..5b8a314ae732 100644 --- a/test-cargo-miri/exported-symbol-dep/src/lib.rs +++ b/test-cargo-miri/exported-symbol-dep/src/lib.rs @@ -3,11 +3,11 @@ fn exported_symbol() -> i32 { 123456 } -pub struct AssocFn; +struct AssocFn; impl AssocFn { #[no_mangle] - pub fn assoc_fn_as_exported_symbol() -> i32 { + fn assoc_fn_as_exported_symbol() -> i32 { -123456 } } diff --git a/tests/run-pass/function_calls/exported_symbol.rs b/tests/run-pass/function_calls/exported_symbol.rs index 58115542332f..ff56bb78a218 100644 --- a/tests/run-pass/function_calls/exported_symbol.rs +++ b/tests/run-pass/function_calls/exported_symbol.rs @@ -15,6 +15,16 @@ fn baz() -> i32 { -3 } +struct AssocFn; + +impl AssocFn { + #[no_mangle] + fn qux() -> i32 { + -4 + } +} + + fn main() { // Repeat calls to make sure the `Instance` cache is not broken. for _ in 0..3 { @@ -32,10 +42,12 @@ fn main() { extern "Rust" { fn bar() -> i32; fn baz() -> i32; + fn qux() -> i32; } assert_eq!(unsafe { bar() }, -2); assert_eq!(unsafe { baz() }, -3); + assert_eq!(unsafe { qux() }, -4); #[allow(clashing_extern_declarations)] { @@ -53,6 +65,7 @@ fn main() { extern "C" { fn bar() -> i32; fn baz() -> i32; + fn qux() -> i32; } unsafe { @@ -61,6 +74,7 @@ fn main() { }; assert_eq!(transmute(bar)(), -2); assert_eq!(transmute(baz)(), -3); + assert_eq!(transmute(qux)(), -4); } } } From 9a6a5119fc3d6b40eeca8b6ec869af665fbe8ade Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 16 Aug 2021 17:09:21 +0200 Subject: [PATCH 2790/5092] rustup --- rust-version | 2 +- tests/compile-fail/function_calls/exported_symbol_wrong_type.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 1cf2fb4b0ff9..6b176cc97bdb 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -fa2692990c05652c7823c8d2afae501a00a69050 +73d96b090bb68065cd3a469b27cbd568e39bf0e7 diff --git a/tests/compile-fail/function_calls/exported_symbol_wrong_type.rs b/tests/compile-fail/function_calls/exported_symbol_wrong_type.rs index 0a493e35a7ce..3ffd506c94bb 100644 --- a/tests/compile-fail/function_calls/exported_symbol_wrong_type.rs +++ b/tests/compile-fail/function_calls/exported_symbol_wrong_type.rs @@ -5,5 +5,5 @@ fn main() { extern "C" { fn FOO(); } - unsafe { FOO() } //~ ERROR unsupported operation: can't call foreign function: FOO + unsafe { FOO() } //~ ERROR attempt to call an exported symbol that is not defined as a function } From 2c14bab76f8779fd629bec1ffa737f68ea19115f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 16 Aug 2021 17:34:48 +0200 Subject: [PATCH 2791/5092] =?UTF-8?q?llvm=5Fasm=20=E2=86=92=20asm?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test-cargo-miri/build.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test-cargo-miri/build.rs b/test-cargo-miri/build.rs index 3e84d69eec80..31d251bc6789 100644 --- a/test-cargo-miri/build.rs +++ b/test-cargo-miri/build.rs @@ -1,4 +1,4 @@ -#![feature(llvm_asm)] +#![feature(asm)] use std::env; @@ -7,9 +7,9 @@ compile_error!("`miri` cfg should not be set in build script"); fn not_in_miri() -> i32 { // Inline assembly definitely does not work in Miri. - let dummy = 42; + let mut dummy = 42; unsafe { - llvm_asm!("" : : "r"(&dummy)); + asm!("/* {} */", in(reg) &mut dummy); } return dummy; } From a0d4372ff9bf773a64c9dc7c51ef0392817c27ee Mon Sep 17 00:00:00 2001 From: Frank Steffahn Date: Sun, 22 Aug 2021 14:28:05 +0200 Subject: [PATCH 2792/5092] =?UTF-8?q?Fix=20typos=20=E2=80=9Ca=E2=80=9D?= =?UTF-8?q?=E2=86=92=E2=80=9Can=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/data_race.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index 6a64c1cb6936..9e5dfd9dbaf0 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -42,7 +42,7 @@ //! order exists in which all threads observe all modifications in the same //! order (see Sequentially-consistent ordering below) " //! So in the absence of weak memory effects a seq-cst load & a seq-cst store is identical -//! to a acquire load and a release store given the global sequentially consistent order +//! to an acquire load and a release store given the global sequentially consistent order //! of the schedule. //! //! The timestamps used in the data-race detector assign each sequence of non-atomic operations @@ -142,7 +142,7 @@ impl ThreadClockSet { self.fence_release.clone_from(&self.clock); } - /// Apply the effects of a acquire fence to this + /// Apply the effects of an acquire fence to this /// set of thread vector clocks. #[inline] fn apply_acquire_fence(&mut self) { @@ -503,7 +503,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { this.validate_atomic_store(dest, atomic) } - /// Perform a atomic operation on a memory location. + /// Perform an atomic operation on a memory location. fn atomic_op_immediate( &mut self, place: &MPlaceTy<'tcx, Tag>, @@ -695,7 +695,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { log::trace!("Atomic fence on {:?} with ordering {:?}", index, atomic); // Apply data-race detection for the current fences - // this treats AcqRel and SeqCst as the same as a acquire + // this treats AcqRel and SeqCst as the same as an acquire // and release fence applied in the same timestamp. if atomic != AtomicFenceOp::Release { // Either Acquire | AcqRel | SeqCst From 32c2df87be28205eb87a12362b085917a2a58dc5 Mon Sep 17 00:00:00 2001 From: niluxv Date: Sun, 22 Aug 2021 17:48:31 +0200 Subject: [PATCH 2793/5092] Add support for the `volatile_set_memory` intrinsic Runtime behaviour and soundness requirements are identical to `write_bytes`. --- src/shims/intrinsics.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 5a3a782382dd..317bba859295 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -66,7 +66,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.copy_op(dest, &place.into())?; } - "write_bytes" => { + "write_bytes" | "volatile_set_memory" => { let &[ref ptr, ref val_byte, ref count] = check_arg_count(args)?; let ty = instance.substs.type_at(0); let ty_layout = this.layout_of(ty)?; @@ -74,7 +74,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.read_pointer(ptr)?; let count = this.read_scalar(count)?.to_machine_usize(this)?; let byte_count = ty_layout.size.checked_mul(count, this).ok_or_else(|| { - err_ub_format!("overflow computing total size of `write_bytes`") + err_ub_format!("overflow computing total size of `{}`", intrinsic_name) })?; this.memory .write_bytes(ptr, iter::repeat(val_byte).take(byte_count.bytes() as usize))?; From c79f6dd5a0769aa753bf04442cf70e1af98f0962 Mon Sep 17 00:00:00 2001 From: Frank Steffahn Date: Sun, 22 Aug 2021 18:07:01 +0200 Subject: [PATCH 2794/5092] =?UTF-8?q?Fix=20a=20typo=20=E2=80=9Can=E2=80=9D?= =?UTF-8?q?=E2=86=92=E2=80=9Ca=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/helpers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers.rs b/src/helpers.rs index e09ef2865fb2..1b6831690235 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -78,7 +78,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx self.eval_context_mut().eval_path_scalar(&["std", "sys", "windows", module, name]) } - /// Helper function to get a `windows` constant as an `u64`. + /// Helper function to get a `windows` constant as a `u64`. fn eval_windows_u64(&mut self, module: &str, name: &str) -> InterpResult<'tcx, u64> { // TODO: Cache the result. self.eval_windows(module, name)?.to_u64() From 083e5e604c304d8743a942ef33def704fa4b6012 Mon Sep 17 00:00:00 2001 From: niluxv Date: Mon, 23 Aug 2021 12:42:13 +0200 Subject: [PATCH 2795/5092] Add test for `volatile_set_memory` --- tests/run-pass/write-bytes.rs | 40 +++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/run-pass/write-bytes.rs b/tests/run-pass/write-bytes.rs index 7c9a38fca696..b2050c5393e2 100644 --- a/tests/run-pass/write-bytes.rs +++ b/tests/run-pass/write-bytes.rs @@ -1,3 +1,5 @@ +#![feature(core_intrinsics)] // for `volatile_set_memory` + #[repr(C)] #[derive(Copy, Clone)] struct Foo { @@ -42,4 +44,42 @@ fn main() { assert_eq!(w[idx].b, 0xcdcdcdcdcdcdcdcd); assert_eq!(w[idx].c, 0xcdcdcdcdcdcdcdcd); } + + // ----- + // `std::intrinsics::volatile_set_memory` should behave identically + + let mut v: [u64; LENGTH] = [0; LENGTH]; + + for idx in 0..LENGTH { + assert_eq!(v[idx], 0); + } + + unsafe { + let p = v.as_mut_ptr(); + ::std::intrinsics::volatile_set_memory(p, 0xab, LENGTH); + } + + for idx in 0..LENGTH { + assert_eq!(v[idx], 0xabababababababab); + } + + // ----- + + let mut w: [Foo; LENGTH] = [Foo { a: 0, b: 0, c: 0 }; LENGTH]; + for idx in 0..LENGTH { + assert_eq!(w[idx].a, 0); + assert_eq!(w[idx].b, 0); + assert_eq!(w[idx].c, 0); + } + + unsafe { + let p = w.as_mut_ptr(); + ::std::intrinsics::volatile_set_memory(p, 0xcd, LENGTH); + } + + for idx in 0..LENGTH { + assert_eq!(w[idx].a, 0xcdcdcdcdcdcdcdcd); + assert_eq!(w[idx].b, 0xcdcdcdcdcdcdcdcd); + assert_eq!(w[idx].c, 0xcdcdcdcdcdcdcdcd); + } } From 33a67c6b33e91b5de01b9421a59a2f92233643a0 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Tue, 24 Aug 2021 18:42:43 +0800 Subject: [PATCH 2796/5092] Add `#[allow(unreachable_code)]` to `drop(x)` in `tests/run-pass/generator.rs` --- rust-version | 2 +- tests/run-pass/generator.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 6b176cc97bdb..2805654a75e3 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -73d96b090bb68065cd3a469b27cbd568e39bf0e7 +f66e825f73d2bd7f8a763b723983850f891985b0 diff --git a/tests/run-pass/generator.rs b/tests/run-pass/generator.rs index 18eaf5e55c15..b2039e555f51 100644 --- a/tests/run-pass/generator.rs +++ b/tests/run-pass/generator.rs @@ -94,6 +94,7 @@ fn basic() { #[allow(unused)] let x = never(); yield 2; + #[allow(unreachable_code)] drop(x); }); From 450e110b5088cf7f48f8301732ccdeda8dc1b315 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 24 Aug 2021 15:03:36 +0000 Subject: [PATCH 2797/5092] Try out gitpod --- .gitpod.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .gitpod.yml diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 000000000000..36bd991740a8 --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,9 @@ +image: ubuntu:latest + +tasks: + - before: echo "..." + init: | + cargo install rustup-toolchain-install-master + ./rustup-toolchain + ./miri build + command: echo "Run tests with ./miri test" \ No newline at end of file From 7301fe118a35ad52e23cb217ce4e12e207e9ec31 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Thu, 26 Aug 2021 16:16:43 +0800 Subject: [PATCH 2798/5092] Move `#[allow(unreachable_code)]` in `tests/run-pass/generator.rs` --- rust-version | 2 +- tests/run-pass/generator.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 2805654a75e3..2cce8290c913 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -f66e825f73d2bd7f8a763b723983850f891985b0 +c4be230b4a30eb74e3a3908455731ebc2f731d3d diff --git a/tests/run-pass/generator.rs b/tests/run-pass/generator.rs index b2039e555f51..9d786edc5ae2 100644 --- a/tests/run-pass/generator.rs +++ b/tests/run-pass/generator.rs @@ -93,8 +93,8 @@ fn basic() { if b { return; } #[allow(unused)] let x = never(); - yield 2; #[allow(unreachable_code)] + yield 2; drop(x); }); From 35b64447f385b1908b1de2eb7dc673f1fd3817ba Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 Aug 2021 10:35:34 -0400 Subject: [PATCH 2799/5092] rustup --- rust-version | 2 +- src/shims/intrinsics.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 2cce8290c913..4dab723fbddc 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c4be230b4a30eb74e3a3908455731ebc2f731d3d +6cfa773583bb5123e630668f5bfe466716225546 diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 317bba859295..fd1a3f3e598b 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -518,7 +518,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ))) } if intrinsic_name == "assert_zero_valid" - && !layout.might_permit_raw_init(this, /*zero:*/ true).unwrap() + && !layout.might_permit_raw_init(this, /*zero:*/ true) { throw_machine_stop!(TerminationInfo::Abort(format!( "aborted execution: attempted to zero-initialize type `{}`, which is invalid", @@ -526,7 +526,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ))) } if intrinsic_name == "assert_uninit_valid" - && !layout.might_permit_raw_init(this, /*zero:*/ false).unwrap() + && !layout.might_permit_raw_init(this, /*zero:*/ false) { throw_machine_stop!(TerminationInfo::Abort(format!( "aborted execution: attempted to leave type `{}` uninitialized, which is invalid", From 8d797fb15481b467d721de9222b0cfa35ce0b14a Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius III" Date: Wed, 1 Sep 2021 08:53:51 -0400 Subject: [PATCH 2800/5092] Update compiletest_rs dependency --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e728dc07b928..0dbd1b865689 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -53,9 +53,9 @@ dependencies = [ [[package]] name = "compiletest_rs" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0086d6ad78cf409c3061618cd98e2789d5c9ce598fc9651611cf62eae0a599cb" +checksum = "64698e5e2435db061a85e6320af12c30c5fd88eb84b35d2c1e03ce4f143255ca" dependencies = [ "diff", "filetime", diff --git a/Cargo.toml b/Cargo.toml index 7ee96f7e99e6..82962c6b98aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ measureme = "9.1.2" libc = "0.2" [dev-dependencies] -compiletest_rs = { version = "0.6", features = ["tmp"] } +compiletest_rs = { version = "0.7", features = ["tmp"] } rustc_version = "0.3" colored = "2" From 84b058ac47e2ea5f29887a4ed5ae286e37b22194 Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Thu, 2 Sep 2021 15:41:10 -0700 Subject: [PATCH 2801/5092] add support for #[start] --- benches/helpers/miri_helper.rs | 5 +- src/bin/miri.rs | 6 +-- src/eval.rs | 90 +++++++++++++++++++++++----------- src/lib.rs | 2 +- tests/run-pass/start.rs | 8 +++ tests/run-pass/start.stdout | 1 + 6 files changed, 78 insertions(+), 34 deletions(-) create mode 100644 tests/run-pass/start.rs create mode 100644 tests/run-pass/start.stdout diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 2d27616a3613..be542c2bc0a6 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -20,11 +20,12 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { compiler.session().abort_if_errors(); queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { - let (entry_def_id, _) = tcx.entry_fn(()).expect("no main or start function found"); + let (entry_def_id, entry_type) = + tcx.entry_fn(()).expect("no main or start function found"); self.bencher.iter(|| { let config = miri::MiriConfig::default(); - miri::eval_main(tcx, entry_def_id, config); + miri::eval_entry(tcx, entry_def_id, entry_type, config); }); }); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 18c393815ca5..fbc87148ec7b 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -58,8 +58,8 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { init_late_loggers(tcx); - let (entry_def_id, _) = if let Some((entry_def, x)) = tcx.entry_fn(()) { - (entry_def, x) + let (entry_def_id, entry_type) = if let Some(entry_def) = tcx.entry_fn(()) { + entry_def } else { let output_ty = ErrorOutputType::HumanReadable(HumanReadableErrorType::Default( ColorConfig::Auto, @@ -79,7 +79,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { env::set_current_dir(cwd).unwrap(); } - if let Some(return_code) = miri::eval_main(tcx, entry_def_id, config) { + if let Some(return_code) = miri::eval_entry(tcx, entry_def_id, entry_type, config) { std::process::exit( i32::try_from(return_code).expect("Return value was too large!"), ); diff --git a/src/eval.rs b/src/eval.rs index 2b8fc0f5adee..f90a77fafd5a 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -10,6 +10,8 @@ use rustc_middle::ty::{self, layout::LayoutCx, TyCtxt}; use rustc_target::abi::LayoutOf; use rustc_target::spec::abi::Abi; +use rustc_session::config::EntryFnType; + use crate::*; #[derive(Copy, Clone, Debug, PartialEq)] @@ -117,12 +119,13 @@ impl Default for MiriConfig { } /// Returns a freshly created `InterpCx`, along with an `MPlaceTy` representing -/// the location where the return value of the `start` lang item will be +/// the location where the return value of the `start` function will be /// written to. /// Public because this is also used by `priroda`. pub fn create_ecx<'mir, 'tcx: 'mir>( tcx: TyCtxt<'tcx>, - main_id: DefId, + entry_id: DefId, + entry_type: EntryFnType, config: MiriConfig, ) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, MPlaceTy<'tcx, Tag>)> { let param_env = ty::ParamEnv::reveal_all(); @@ -145,26 +148,14 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } // Setup first stack-frame - let main_instance = ty::Instance::mono(tcx, main_id); - let main_mir = ecx.load_mir(main_instance.def, None)?; + let entry_instance = ty::Instance::mono(tcx, entry_id); + /*let entry_mir = ecx.load_mir(entry_instance.def, None)?; if main_mir.arg_count != 0 { bug!("main function must not take any arguments"); - } + }*/ - let start_id = tcx.lang_items().start_fn().unwrap(); - let main_ret_ty = tcx.fn_sig(main_id).output(); - let main_ret_ty = main_ret_ty.no_bound_vars().unwrap(); - let start_instance = ty::Instance::resolve( - tcx, - ty::ParamEnv::reveal_all(), - start_id, - tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))), - ) - .unwrap() - .unwrap(); + // First argument is constructed later, because its skipped if the entry function uses #[start] - // First argument: pointer to `main()`. - let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(main_instance)); // Second argument (argc): length of `config.args`. let argc = Scalar::from_machine_usize(u64::try_from(config.args.len()).unwrap(), &ecx); // Third argument (`argv`): created from `config.args`. @@ -237,28 +228,71 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( argv }; + /*let args: &[_] = match entry_type { + EntryFnType::Main => { + // First argument: pointer to `main()`. + let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(main_instance)); + + &[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv] + } + EntryFnType::Start => &[argc.into(), argv], + };*/ + // Return place (in static memory so that it does not count as leak). let ret_place = ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into())?; // Call start function. - ecx.call_function( - start_instance, - Abi::Rust, - &[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv], - Some(&ret_place.into()), - StackPopCleanup::None { cleanup: true }, - )?; + + match entry_type { + EntryFnType::Main => { + let start_id = tcx.lang_items().start_fn().unwrap(); + let main_ret_ty = tcx.fn_sig(entry_id).output(); + let main_ret_ty = main_ret_ty.no_bound_vars().unwrap(); + let start_instance = ty::Instance::resolve( + tcx, + ty::ParamEnv::reveal_all(), + start_id, + tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))), + ) + .unwrap() + .unwrap(); + + let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(entry_instance)); + + ecx.call_function( + start_instance, + Abi::Rust, + &[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv], + Some(&ret_place.into()), + StackPopCleanup::None { cleanup: true }, + )?; + } + EntryFnType::Start => { + ecx.call_function( + entry_instance, + Abi::Rust, + &[argc.into(), argv], + Some(&ret_place.into()), + StackPopCleanup::None { cleanup: true }, + )?; + } + } Ok((ecx, ret_place)) } -/// Evaluates the main function specified by `main_id`. +/// Evaluates the entry function specified by `entry_id`. /// Returns `Some(return_code)` if program executed completed. /// Returns `None` if an evaluation error occured. -pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option { +pub fn eval_entry<'tcx>( + tcx: TyCtxt<'tcx>, + entry_id: DefId, + entry_type: EntryFnType, + config: MiriConfig, +) -> Option { // Copy setting before we move `config`. let ignore_leaks = config.ignore_leaks; - let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) { + let (mut ecx, ret_place) = match create_ecx(tcx, entry_id, entry_type, config) { Ok(v) => v, Err(err) => { err.print_backtrace(); diff --git a/src/lib.rs b/src/lib.rs index f8d8aacce3c9..7ed915b6d1d4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -60,7 +60,7 @@ pub use crate::diagnostics::{ NonHaltingDiagnostic, TerminationInfo, }; pub use crate::eval::{ - create_ecx, eval_main, AlignmentCheck, IsolatedOp, MiriConfig, RejectOpWith, + create_ecx, eval_entry, AlignmentCheck, IsolatedOp, MiriConfig, RejectOpWith, }; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; pub use crate::machine::{ diff --git a/tests/run-pass/start.rs b/tests/run-pass/start.rs new file mode 100644 index 000000000000..f25d62fa8c33 --- /dev/null +++ b/tests/run-pass/start.rs @@ -0,0 +1,8 @@ +#![feature(start)] + +#[start] +fn start(_: isize, _: *const *const u8) -> isize { + println!("Hello from start!"); + + 0 +} diff --git a/tests/run-pass/start.stdout b/tests/run-pass/start.stdout new file mode 100644 index 000000000000..d7f627d237c3 --- /dev/null +++ b/tests/run-pass/start.stdout @@ -0,0 +1 @@ +Hello from start! From 1ec28f78f3c9c68a850ac943a6d2100266782dc1 Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Thu, 2 Sep 2021 15:45:52 -0700 Subject: [PATCH 2802/5092] remove commented out code --- src/eval.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index f90a77fafd5a..151243f29a92 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -149,10 +149,6 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Setup first stack-frame let entry_instance = ty::Instance::mono(tcx, entry_id); - /*let entry_mir = ecx.load_mir(entry_instance.def, None)?; - if main_mir.arg_count != 0 { - bug!("main function must not take any arguments"); - }*/ // First argument is constructed later, because its skipped if the entry function uses #[start] @@ -228,16 +224,6 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( argv }; - /*let args: &[_] = match entry_type { - EntryFnType::Main => { - // First argument: pointer to `main()`. - let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(main_instance)); - - &[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv] - } - EntryFnType::Start => &[argc.into(), argv], - };*/ - // Return place (in static memory so that it does not count as leak). let ret_place = ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into())?; // Call start function. From 78c031204d2602916fafd0012c240556cd0ee296 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sun, 5 Sep 2021 10:05:43 -0700 Subject: [PATCH 2803/5092] Stage 2 seems to be required after all Reverts most of bb59980b2da10437ce1ee4d53bdb3feb1f4a9c5f. --- CONTRIBUTING.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9edd63dae315..eea97863d3e2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -148,15 +148,15 @@ cd rustc ./x.py setup compiler # Now edit `config.toml` and under `[rust]` set `debug-assertions = true`. -# Build a stage 1 rustc, and build the rustc libraries with that rustc. +# Build a stage 2 rustc, and build the rustc libraries with that rustc. # This step can take 30 minutes or more. -./x.py build --stage 1 compiler/rustc +./x.py build --stage 2 compiler/rustc # If you change something, you can get a faster rebuild by doing -./x.py build --keep-stage 0 --stage 1 compiler/rustc +./x.py build --keep-stage 0 --stage 2 compiler/rustc # You may have to change the architecture in the next command -rustup toolchain link stage1 build/x86_64-unknown-linux-gnu/stage1 +rustup toolchain link stage2 build/x86_64-unknown-linux-gnu/stage2 # Now cd to your Miri directory, then configure rustup -rustup override set stage1 +rustup override set stage2 ``` For more information about building and configuring a local compiler, From 3fedc7b249fd5f9450b6c2d2df28a5b828166ac9 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Mon, 6 Sep 2021 23:05:48 +0800 Subject: [PATCH 2804/5092] `rustc_target::abi::LayoutOf` -> `rustc_middle::ty::layout::LayoutOf` --- rust-version | 2 +- src/eval.rs | 7 +++++-- src/helpers.rs | 8 ++++++-- src/machine.rs | 4 ++-- src/shims/backtrace.rs | 2 +- src/shims/env.rs | 3 ++- src/shims/intrinsics.rs | 4 ++-- src/shims/os_str.rs | 3 ++- src/shims/posix/foreign_items.rs | 3 ++- src/shims/posix/fs.rs | 4 ++-- src/shims/posix/thread.rs | 2 +- src/stacked_borrows.rs | 4 ++-- 12 files changed, 28 insertions(+), 18 deletions(-) diff --git a/rust-version b/rust-version index 4dab723fbddc..33be6b9182b8 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6cfa773583bb5123e630668f5bfe466716225546 +1c858ba5bf7bd06c1a970efbf77053c8380b3151 diff --git a/src/eval.rs b/src/eval.rs index 2b8fc0f5adee..f6adbd48cd5c 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -6,8 +6,11 @@ use std::ffi::OsStr; use log::info; use rustc_hir::def_id::DefId; -use rustc_middle::ty::{self, layout::LayoutCx, TyCtxt}; -use rustc_target::abi::LayoutOf; +use rustc_middle::ty::{ + self, + layout::{LayoutCx, LayoutOf}, + TyCtxt, +}; use rustc_target::spec::abi::Abi; use crate::*; diff --git a/src/helpers.rs b/src/helpers.rs index 1b6831690235..081712dddc83 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -7,9 +7,13 @@ use log::trace; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_middle::mir; -use rustc_middle::ty::{self, layout::TyAndLayout, List, TyCtxt}; +use rustc_middle::ty::{ + self, + layout::{LayoutOf, TyAndLayout}, + List, TyCtxt, +}; use rustc_span::Symbol; -use rustc_target::abi::{Align, FieldsShape, LayoutOf, Size, Variants}; +use rustc_target::abi::{Align, FieldsShape, Size, Variants}; use rustc_target::spec::abi::Abi; use rand::RngCore; diff --git a/src/machine.rs b/src/machine.rs index 62c1a93079cb..fb39503b5385 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -16,13 +16,13 @@ use rustc_middle::{ mir, ty::{ self, - layout::{LayoutCx, LayoutError, TyAndLayout}, + layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout}, Instance, TyCtxt, }, }; use rustc_span::def_id::DefId; use rustc_span::symbol::{sym, Symbol}; -use rustc_target::abi::{LayoutOf, Size}; +use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; use crate::*; diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 1ac3a22f7ed3..eb25cfd9935f 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -1,6 +1,6 @@ -use crate::rustc_target::abi::LayoutOf as _; use crate::*; use rustc_ast::ast::Mutability; +use rustc_middle::ty::layout::LayoutOf as _; use rustc_middle::ty::{self, TypeAndMut}; use rustc_span::{BytePos, Symbol}; use rustc_target::{abi::Size, spec::abi::Abi}; diff --git a/src/shims/env.rs b/src/shims/env.rs index 9290ec022b57..74c0b56e467b 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -4,8 +4,9 @@ use std::ffi::{OsStr, OsString}; use std::io::ErrorKind; use rustc_data_structures::fx::FxHashMap; +use rustc_middle::ty::layout::LayoutOf; use rustc_mir::interpret::Pointer; -use rustc_target::abi::{LayoutOf, Size}; +use rustc_target::abi::Size; use crate::*; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index fd1a3f3e598b..f2f046a3ada1 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -3,9 +3,9 @@ use std::iter; use log::trace; use rustc_apfloat::{Float, Round}; -use rustc_middle::ty::layout::IntegerExt; +use rustc_middle::ty::layout::{IntegerExt, LayoutOf}; use rustc_middle::{mir, mir::BinOp, ty, ty::FloatTy}; -use rustc_target::abi::{Align, Integer, LayoutOf}; +use rustc_target::abi::{Align, Integer}; use crate::*; use helpers::check_arg_count; diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 83bb344982c2..ede29d04d6bc 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -9,7 +9,8 @@ use std::os::unix::ffi::{OsStrExt, OsStringExt}; #[cfg(windows)] use std::os::windows::ffi::{OsStrExt, OsStringExt}; -use rustc_target::abi::{Align, LayoutOf, Size}; +use rustc_middle::ty::layout::LayoutOf; +use rustc_target::abi::{Align, Size}; use crate::*; diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 09dd7d9c7b86..6d417fd09671 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -1,8 +1,9 @@ use log::trace; use rustc_middle::mir; +use rustc_middle::ty::layout::LayoutOf; use rustc_span::Symbol; -use rustc_target::abi::{Align, LayoutOf, Size}; +use rustc_target::abi::{Align, Size}; use rustc_target::spec::abi::Abi; use crate::*; diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index ac6e878da962..36c076037708 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -11,8 +11,8 @@ use std::time::SystemTime; use log::trace; use rustc_data_structures::fx::FxHashMap; -use rustc_middle::ty; -use rustc_target::abi::{Align, LayoutOf, Size}; +use rustc_middle::ty::{self, layout::LayoutOf}; +use rustc_target::abi::{Align, Size}; use crate::*; use helpers::{check_arg_count, immty_from_int_checked, immty_from_uint_checked}; diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index 9926c36c49ac..e64ef3b23c6f 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -1,7 +1,7 @@ use std::convert::TryInto; use crate::*; -use rustc_target::abi::LayoutOf; +use rustc_middle::ty::layout::LayoutOf; use rustc_target::spec::abi::Abi; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index e04de65ac3fd..65678b6f01fe 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -9,8 +9,8 @@ use std::num::NonZeroU64; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::Mutability; use rustc_middle::mir::RetagKind; -use rustc_middle::ty; -use rustc_target::abi::{LayoutOf, Size}; +use rustc_middle::ty::{self, layout::LayoutOf}; +use rustc_target::abi::Size; use crate::*; From 9c62b6454e46b440eaf704213738ab8e819ecced Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Thu, 9 Sep 2021 17:36:39 +0800 Subject: [PATCH 2805/5092] `rustc_mir` -> `rustc_const_eval` --- rust-version | 2 +- src/bin/miri.rs | 7 +++++-- src/lib.rs | 6 +++--- src/machine.rs | 4 ++-- src/shims/env.rs | 2 +- 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/rust-version b/rust-version index 33be6b9182b8..c3b3aed9a426 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1c858ba5bf7bd06c1a970efbf77053c8380b3151 +c5cbf7852a7692c7c51df64c09a59e7838b55202 diff --git a/src/bin/miri.rs b/src/bin/miri.rs index fbc87148ec7b..36e7f1bfddaa 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -164,11 +164,14 @@ fn init_late_loggers(tcx: TyCtxt<'_>) { // used for everything, we only apply it to the parts of rustc that are // CTFE-related. Otherwise, we use it verbatim for `RUSTC_LOG`. // This way, if you set `MIRI_LOG=trace`, you get only the right parts of - // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_mir::interpret=debug`. + // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_const_eval::interpret=debug`. if log::Level::from_str(&var).is_ok() { env::set_var( "RUSTC_LOG", - &format!("rustc_middle::mir::interpret={0},rustc_mir::interpret={0}", var), + &format!( + "rustc_middle::mir::interpret={0},rustc_const_eval::interpret={0}", + var + ), ); } else { env::set_var("RUSTC_LOG", &var); diff --git a/src/lib.rs b/src/lib.rs index 7ed915b6d1d4..c786487d4a14 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,10 +11,10 @@ extern crate rustc_apfloat; extern crate rustc_ast; #[macro_use] extern crate rustc_middle; +extern crate rustc_const_eval; extern crate rustc_data_structures; extern crate rustc_hir; extern crate rustc_index; -extern crate rustc_mir; extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; @@ -37,9 +37,9 @@ mod vector_clock; // Establish a "crate-wide prelude": we often import `crate::*`. // Make all those symbols available in the same place as our own. -pub use rustc_mir::interpret::*; +pub use rustc_const_eval::interpret::*; // Resolve ambiguity. -pub use rustc_mir::interpret::{self, AllocMap, PlaceTy}; +pub use rustc_const_eval::interpret::{self, AllocMap, PlaceTy}; pub use crate::shims::dlsym::{Dlsym, EvalContextExt as _}; pub use crate::shims::env::{EnvVars, EvalContextExt as _}; diff --git a/src/machine.rs b/src/machine.rs index fb39503b5385..23278a4891fb 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -457,7 +457,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn call_intrinsic( - ecx: &mut rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>, + ecx: &mut rustc_const_eval::interpret::InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, @@ -482,7 +482,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn binary_ptr_op( - ecx: &rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>, + ecx: &rustc_const_eval::interpret::InterpCx<'mir, 'tcx, Self>, bin_op: mir::BinOp, left: &ImmTy<'tcx, Tag>, right: &ImmTy<'tcx, Tag>, diff --git a/src/shims/env.rs b/src/shims/env.rs index 74c0b56e467b..4d297fd935d5 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -3,9 +3,9 @@ use std::env; use std::ffi::{OsStr, OsString}; use std::io::ErrorKind; +use rustc_const_eval::interpret::Pointer; use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::layout::LayoutOf; -use rustc_mir::interpret::Pointer; use rustc_target::abi::Size; use crate::*; From 9a877b80fe46671cca93582856c6b6867c10770b Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sat, 11 Sep 2021 18:58:57 +0800 Subject: [PATCH 2806/5092] Add `#[allow(dead_code)]` in some tests --- rust-version | 2 +- tests/compile-fail/validity/invalid_wide_raw.rs | 1 + tests/run-pass/issue-3794.rs | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index c3b3aed9a426..26d88f5b07b5 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c5cbf7852a7692c7c51df64c09a59e7838b55202 +4e880f8cbc191374ce7db335962489f41d6d4e3e diff --git a/tests/compile-fail/validity/invalid_wide_raw.rs b/tests/compile-fail/validity/invalid_wide_raw.rs index 6e0809b15ca4..ac2d79b5a92a 100644 --- a/tests/compile-fail/validity/invalid_wide_raw.rs +++ b/tests/compile-fail/validity/invalid_wide_raw.rs @@ -4,6 +4,7 @@ fn main() { trait T { } #[derive(Debug)] struct S { + #[allow(dead_code)] x: * mut dyn T } dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); //~ ERROR: encountered dangling vtable pointer in wide pointer diff --git a/tests/run-pass/issue-3794.rs b/tests/run-pass/issue-3794.rs index fb1c19b04e99..5b5b22b54948 100644 --- a/tests/run-pass/issue-3794.rs +++ b/tests/run-pass/issue-3794.rs @@ -6,6 +6,7 @@ trait T { #[derive(Debug)] struct S { + #[allow(dead_code)] s: isize, } From 5aecd2811e65f3d238e68ced6bf9fddac7bb25c2 Mon Sep 17 00:00:00 2001 From: Smitty Date: Sat, 11 Sep 2021 12:00:59 -0400 Subject: [PATCH 2807/5092] One character aliases for cargo-miri run/test The main `cargo` command supports `cargo r` as an alias for `cargo run`, and `cargo t` as an alias for `cargo test`. This adds support to them in cargo-miri for consistency. --- cargo-miri/bin.rs | 8 ++++---- test-cargo-miri/run-test.py | 10 ++++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 23546988daa8..21f53a45e41f 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -20,8 +20,8 @@ Usage: cargo miri [subcommand] [...] [--] [...] Subcommands: - run Run binaries - test Run tests + run, r Run binaries + test, t Run tests setup Only perform automatic setup, but without asking questions (for getting a proper libstd) The cargo options are exactly the same as for `cargo run` and `cargo test`, respectively. @@ -524,8 +524,8 @@ fn phase_cargo_miri(mut args: env::Args) { // We cannot know which of those flags take arguments and which do not, // so we cannot detect subcommands later. let subcommand = match args.next().as_deref() { - Some("test") => MiriCommand::Test, - Some("run") => MiriCommand::Run, + Some("test" | "t") => MiriCommand::Test, + Some("run" | "r") => MiriCommand::Run, Some("setup") => MiriCommand::Setup, // Invalid command. _ => diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 81a1b1b3f8a7..db8f6049900e 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -102,6 +102,11 @@ def test_cargo_miri_run(): "run.subcrate.stdout.ref", "run.subcrate.stderr.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) + test("`cargo miri r` (subcrate, no ioslation)", + cargo_miri("r") + ["-p", "subcrate"], + "run.subcrate.stdout.ref", "run.subcrate.stderr.ref", + env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, + ) test("`cargo miri run` (custom target dir)", # Attempt to confuse the argument parser. cargo_miri("run") + ["--target-dir=custom-run", "--", "--target-dir=target/custom-run"], @@ -146,6 +151,11 @@ def test_cargo_miri_test(): "test.subcrate.stdout.ref", "test.stderr-proc-macro.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) + test("`cargo miri t` (subcrate, no isolation)", + cargo_miri("t") + ["-p", "subcrate"], + "test.subcrate.stdout.ref", "test.stderr-proc-macro.ref", + env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, + ) test("`cargo miri test` (subcrate, doctests)", cargo_miri("test") + ["-p", "subcrate", "--doc"], "test.stdout-empty.ref", "test.stderr-proc-macro-doctest.ref", From 4df931405aa754c55a5a48eca116f82ba48f75d1 Mon Sep 17 00:00:00 2001 From: Smitty Date: Mon, 13 Sep 2021 18:05:01 -0400 Subject: [PATCH 2808/5092] Don't use seperate alias test --- test-cargo-miri/run-test.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index db8f6049900e..3bc37b236b34 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -97,12 +97,7 @@ def test_cargo_miri_run(): cargo_miri("run") + ["--bin", "cargo-miri-test", "--", "hello world", '"hello world"'], "run.args.stdout.ref", "run.args.stderr.ref", ) - test("`cargo miri run` (subcrate, no ioslation)", - cargo_miri("run") + ["-p", "subcrate"], - "run.subcrate.stdout.ref", "run.subcrate.stderr.ref", - env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, - ) - test("`cargo miri r` (subcrate, no ioslation)", + test("`cargo miri r` (subcrate, no isolation)", cargo_miri("r") + ["-p", "subcrate"], "run.subcrate.stdout.ref", "run.subcrate.stderr.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, @@ -146,11 +141,6 @@ def test_cargo_miri_test(): cargo_miri("test") + ["--bin", "cargo-miri-test", "--", "--format=pretty"], "test.bin-target.stdout.ref", "test.stderr-empty.ref", ) - test("`cargo miri test` (subcrate, no isolation)", - cargo_miri("test") + ["-p", "subcrate"], - "test.subcrate.stdout.ref", "test.stderr-proc-macro.ref", - env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, - ) test("`cargo miri t` (subcrate, no isolation)", cargo_miri("t") + ["-p", "subcrate"], "test.subcrate.stdout.ref", "test.stderr-proc-macro.ref", From f6cedbc744155b168e51b63a873fff98790757f6 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sat, 18 Sep 2021 16:57:31 +0100 Subject: [PATCH 2809/5092] Correct Windows argument handling Previously the command line string would have been incorrectly constructed if argv[0] contained a doublequote (`"`) or ended in a trailing backslash (`\`). This is a very rare edge case because, by convention, argv[0] is the path to the application and Windows file names cannot contain doublequotes. Fixes #1881 --- src/eval.rs | 85 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 75 insertions(+), 10 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 311b930cd9dd..e389ac7ed488 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -2,6 +2,7 @@ use std::convert::TryFrom; use std::ffi::OsStr; +use std::iter; use log::info; @@ -202,17 +203,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Store command line as UTF-16 for Windows `GetCommandLineW`. { // Construct a command string with all the aguments. - let mut cmd = String::new(); - for arg in config.args.iter() { - if !cmd.is_empty() { - cmd.push(' '); - } - cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into())); - } - // Don't forget `0` terminator. - cmd.push(std::char::from_u32(0).unwrap()); + let cmd_utf16: Vec = args_to_utf16_command_string(config.args.iter()); - let cmd_utf16: Vec = cmd.encode_utf16().collect(); let cmd_type = tcx.mk_array(tcx.types.u16, u64::try_from(cmd_utf16.len()).unwrap()); let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Machine.into())?; @@ -353,3 +345,76 @@ pub fn eval_entry<'tcx>( Err(e) => report_error(&ecx, e), } } + +/// Turns an array of arguments into a Windows command line string. +/// +/// The string will be UTF-16 encoded and NUL terminated. +/// +/// Panics if the zeroth argument contains the `"` character because doublequotes +/// in argv[0] cannot be encoded using the standard command line parsing rules. +fn args_to_utf16_command_string(mut args: I) -> Vec +where + I: Iterator, + T: AsRef, +{ + // Parse argv[0]. Slashes aren't escaped. Literal double quotes are not allowed. + let mut cmd = if let Some(arg0) = args.next() { + let arg0 = arg0.as_ref(); + if arg0.is_empty() { + "\"\"".into() + } else if arg0.contains('"') { + panic!("argv[0] cannot contain a doublequote (\") character"); + } else { + // Always surround argv[0] with quotes. + let mut s = String::new(); + s.push('"'); + s.push_str(arg0); + s.push('"'); + s + } + } else { + return vec![0]; + }; + + // Build the other arguments. + for arg in args { + let arg = arg.as_ref(); + cmd.push(' '); + if arg.is_empty() { + cmd.push_str("\"\""); + } else if !arg.bytes().any(|c| matches!(c, b'"' | b'\t' | b' ')) { + cmd.push_str(arg); + } else { + cmd.push('"'); + let mut chars = arg.chars().peekable(); + loop { + let mut nslashes = 0; + while let Some(&'\\') = chars.peek() { + chars.next(); + nslashes += 1; + } + + match chars.next() { + Some('"') => { + cmd.extend(iter::repeat('\\').take(nslashes * 2 + 1)); + cmd.push('"'); + } + Some(c) => { + cmd.extend(iter::repeat('\\').take(nslashes)); + cmd.push(c); + } + None => { + cmd.extend(iter::repeat('\\').take(nslashes * 2)); + break; + } + } + } + cmd.push('"'); + } + } + + if cmd.contains('\0') { + panic!("interior null in command line arguments"); + } + cmd.encode_utf16().chain(iter::once(0)).collect() +} From cfd1316e60c901bd61f5ccc1006e32d75f3f7ab2 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 22 Sep 2021 20:46:20 +0100 Subject: [PATCH 2810/5092] Apply review changes --- src/eval.rs | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index e389ac7ed488..c7ce51a83f4c 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -352,17 +352,24 @@ pub fn eval_entry<'tcx>( /// /// Panics if the zeroth argument contains the `"` character because doublequotes /// in argv[0] cannot be encoded using the standard command line parsing rules. +/// +/// Further reading: +/// * [Parsing C++ command-line arguments](https://docs.microsoft.com/en-us/cpp/cpp/main-function-command-line-args?view=msvc-160#parsing-c-command-line-arguments) +/// * [The C/C++ Parameter Parsing Rules](https://daviddeley.com/autohotkey/parameters/parameters.htm#WINCRULES) fn args_to_utf16_command_string(mut args: I) -> Vec where I: Iterator, T: AsRef, { // Parse argv[0]. Slashes aren't escaped. Literal double quotes are not allowed. - let mut cmd = if let Some(arg0) = args.next() { + let mut cmd = { + let arg0 = if let Some(arg0) = args.next() { + arg0 + } else { + return vec![0]; + }; let arg0 = arg0.as_ref(); - if arg0.is_empty() { - "\"\"".into() - } else if arg0.contains('"') { + if arg0.contains('"') { panic!("argv[0] cannot contain a doublequote (\") character"); } else { // Always surround argv[0] with quotes. @@ -372,8 +379,6 @@ where s.push('"'); s } - } else { - return vec![0]; }; // Build the other arguments. @@ -383,8 +388,15 @@ where if arg.is_empty() { cmd.push_str("\"\""); } else if !arg.bytes().any(|c| matches!(c, b'"' | b'\t' | b' ')) { + // No quote, tab, or space -- no escaping required. cmd.push_str(arg); } else { + // Spaces and tabs are escaped by surrounding them in quotes. + // Quotes are themselves escaped by using backslashes when in a + // quoted block. + // Backslashes only need to be escaped when one or more are directly + // followed by a quote. Otherwise they are taken literally. + cmd.push('"'); let mut chars = arg.chars().peekable(); loop { @@ -418,3 +430,21 @@ where } cmd.encode_utf16().chain(iter::once(0)).collect() } + +#[cfg(test)] +mod tests { + use super::*; + #[test] + #[should_panic(expected = "argv[0] cannot contain a doublequote (\") character")] + fn windows_argv0_panic_on_quote() { + args_to_utf16_command_string(["\""].iter()); + } + #[test] + fn windows_argv0_no_escape() { + // Ensure that a trailing backslash in argv[0] is not escaped. + let cmd = String::from_utf16_lossy(&args_to_utf16_command_string( + [r"C:\Program Files\", "arg1"].iter(), + )); + assert_eq!(cmd.trim_end_matches("\0"), r#""C:\Program Files\" arg1"#); + } +} From 405de0217d9775e2f343373c65b722ecfa291c28 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 24 Sep 2021 10:13:29 -0400 Subject: [PATCH 2811/5092] some more Windows argument passing tests --- src/eval.rs | 4 ++-- test-cargo-miri/run-test.py | 2 +- test-cargo-miri/run.args.stderr.ref | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index c7ce51a83f4c..5d8d332fcd9c 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -443,8 +443,8 @@ mod tests { fn windows_argv0_no_escape() { // Ensure that a trailing backslash in argv[0] is not escaped. let cmd = String::from_utf16_lossy(&args_to_utf16_command_string( - [r"C:\Program Files\", "arg1"].iter(), + [r"C:\Program Files\", "arg1", "arg 2", "arg \" 3"].iter(), )); - assert_eq!(cmd.trim_end_matches("\0"), r#""C:\Program Files\" arg1"#); + assert_eq!(cmd.trim_end_matches("\0"), r#""C:\Program Files\" arg1 "arg 2" "arg \" 3""#); } } diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 3bc37b236b34..18671b2e29da 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -94,7 +94,7 @@ def test_cargo_miri_run(): # so keep it set ) test("`cargo miri run` (with arguments and target)", - cargo_miri("run") + ["--bin", "cargo-miri-test", "--", "hello world", '"hello world"'], + cargo_miri("run") + ["--bin", "cargo-miri-test", "--", "hello world", '"hello world"', r'he\\llo\"world'], "run.args.stdout.ref", "run.args.stderr.ref", ) test("`cargo miri r` (subcrate, no isolation)", diff --git a/test-cargo-miri/run.args.stderr.ref b/test-cargo-miri/run.args.stderr.ref index 8226b1b7cdec..01bb8952322b 100644 --- a/test-cargo-miri/run.args.stderr.ref +++ b/test-cargo-miri/run.args.stderr.ref @@ -1,3 +1,4 @@ main hello world "hello world" +he\\llo\"world From 5f825ae895adbd2cfeff2fb0fc1a2e411bcac91a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Sep 2021 15:59:18 -0400 Subject: [PATCH 2812/5092] rustup --- rust-version | 2 +- src/shims/foreign_items.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 26d88f5b07b5..65591aa7ebd9 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4e880f8cbc191374ce7db335962489f41d6d4e3e +2b6ed3b675475abc01ce7e68bb75b457f0c85684 diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 35c151b72f60..6dfdc316ac47 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -597,7 +597,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.yield_active_thread(); } "llvm.aarch64.isb" if this.tcx.sess.target.arch == "aarch64" => { - let &[ref arg] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let &[ref arg] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; let arg = this.read_scalar(arg)?.to_i32()?; match arg { 15 => { // SY ("full system scope") From e6a27a68fa8a919ff7e4d18f2cd0e256a749b85a Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Thu, 2 Sep 2021 20:43:56 -0700 Subject: [PATCH 2813/5092] implement `#[global_allocator]` --- src/shims/foreign_items.rs | 121 ++++++++++++------ src/shims/posix/foreign_items.rs | 2 +- src/shims/posix/linux/foreign_items.rs | 2 +- src/shims/posix/macos/foreign_items.rs | 2 +- src/shims/windows/foreign_items.rs | 2 +- .../compile-fail/alloc/no_global_allocator.rs | 25 ++++ tests/run-pass/global_allocator.rs | 41 ++++++ tests/run-pass/global_allocator.stdout | 2 + 8 files changed, 157 insertions(+), 40 deletions(-) create mode 100644 tests/compile-fail/alloc/no_global_allocator.rs create mode 100644 tests/run-pass/global_allocator.rs create mode 100644 tests/run-pass/global_allocator.stdout diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 35c151b72f60..1b577688c33b 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -6,6 +6,7 @@ use std::{ use log::trace; use rustc_apfloat::Float; +use rustc_ast::expand::allocator::AllocatorKind; use rustc_hir::{ def::DefKind, def_id::{CrateNum, DefId, LOCAL_CRATE}, @@ -27,11 +28,13 @@ use super::backtrace::EvalContextExt as _; use crate::*; /// Returned by `emulate_foreign_item_by_name`. -pub enum EmulateByNameResult { +pub enum EmulateByNameResult<'mir, 'tcx> { /// The caller is expected to jump to the return block. NeedsJumping, /// Jumping has already been taken care of. AlreadyJumped, + /// A MIR body has been found for the function + MirBody(&'mir mir::Body<'tcx>), /// The item is not supported. NotSupported, } @@ -281,6 +284,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.go_to_block(ret); } EmulateByNameResult::AlreadyJumped => (), + EmulateByNameResult::MirBody(mir) => return Ok(Some(mir)), EmulateByNameResult::NotSupported => { if let Some(body) = this.lookup_exported_symbol(link_name)? { return Ok(Some(body)); @@ -294,6 +298,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(None) } + /// Emulates calling the internal __rust_* allocator functions + fn emulate_allocator( + &mut self, + symbol: Symbol, + default: impl FnOnce(&mut MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx>, + ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { + let this = self.eval_context_mut(); + + let allocator_kind = if let Some(allocator_kind) = this.tcx.allocator_kind(()) { + allocator_kind + } else { + // in real code, this symbol does not exist without an allocator + return Ok(EmulateByNameResult::NotSupported); + }; + + match allocator_kind { + AllocatorKind::Global => { + let body = this + .lookup_exported_symbol(symbol)? + .expect("symbol should be present if there is a global allocator"); + + Ok(EmulateByNameResult::MirBody(body)) + } + AllocatorKind::Default => { + default(this)?; + Ok(EmulateByNameResult::NeedsJumping) + } + } + } + /// Emulates calling a foreign item using its name. fn emulate_foreign_item_by_name( &mut self, @@ -302,7 +336,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, ret: mir::BasicBlock, - ) -> InterpResult<'tcx, EmulateByNameResult> { + ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); // Here we dispatch all the shims for foreign functions. If you have a platform specific @@ -362,45 +396,56 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Rust allocation - // (Usually these would be forwarded to to `#[global_allocator]`; we instead implement a generic - // allocation that also checks that all conditions are met, such as not permitting zero-sized allocations.) "__rust_alloc" => { let &[ref size, ref align] = this.check_shim(abi, Abi::Rust, link_name, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; - Self::check_alloc_request(size, align)?; - let ptr = this.memory.allocate( - Size::from_bytes(size), - Align::from_bytes(align).unwrap(), - MiriMemoryKind::Rust.into(), - )?; - this.write_pointer(ptr, dest)?; + + return this.emulate_allocator(Symbol::intern("__rg_alloc"), |this| { + Self::check_alloc_request(size, align)?; + + let ptr = this.memory.allocate( + Size::from_bytes(size), + Align::from_bytes(align).unwrap(), + MiriMemoryKind::Rust.into(), + )?; + + this.write_pointer(ptr, dest) + }); } "__rust_alloc_zeroed" => { let &[ref size, ref align] = this.check_shim(abi, Abi::Rust, link_name, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; - Self::check_alloc_request(size, align)?; - let ptr = this.memory.allocate( - Size::from_bytes(size), - Align::from_bytes(align).unwrap(), - MiriMemoryKind::Rust.into(), - )?; - // We just allocated this, the access is definitely in-bounds. - this.memory.write_bytes(ptr.into(), iter::repeat(0u8).take(usize::try_from(size).unwrap())).unwrap(); - this.write_pointer(ptr, dest)?; + + return this.emulate_allocator(Symbol::intern("__rg_alloc_zeroed"), |this| { + Self::check_alloc_request(size, align)?; + + let ptr = this.memory.allocate( + Size::from_bytes(size), + Align::from_bytes(align).unwrap(), + MiriMemoryKind::Rust.into(), + )?; + + // We just allocated this, the access is definitely in-bounds. + this.memory.write_bytes(ptr.into(), iter::repeat(0u8).take(usize::try_from(size).unwrap())).unwrap(); + this.write_pointer(ptr, dest) + }); } "__rust_dealloc" => { let &[ref ptr, ref old_size, ref align] = this.check_shim(abi, Abi::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; - // No need to check old_size/align; we anyway check that they match the allocation. - this.memory.deallocate( - ptr, - Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())), - MiriMemoryKind::Rust.into(), - )?; + + return this.emulate_allocator(Symbol::intern("__rg_dealloc"), |this| { + // No need to check old_size/align; we anyway check that they match the allocation. + this.memory.deallocate( + ptr, + Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())), + MiriMemoryKind::Rust.into(), + ) + }); } "__rust_realloc" => { let &[ref ptr, ref old_size, ref align, ref new_size] = this.check_shim(abi, Abi::Rust, link_name, args)?; @@ -408,17 +453,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; - Self::check_alloc_request(new_size, align)?; // No need to check old_size; we anyway check that they match the allocation. - let align = Align::from_bytes(align).unwrap(); - let new_ptr = this.memory.reallocate( - ptr, - Some((Size::from_bytes(old_size), align)), - Size::from_bytes(new_size), - align, - MiriMemoryKind::Rust.into(), - )?; - this.write_pointer(new_ptr, dest)?; + + return this.emulate_allocator(Symbol::intern("__rg_realloc"), |this| { + Self::check_alloc_request(new_size, align)?; + + let align = Align::from_bytes(align).unwrap(); + let new_ptr = this.memory.reallocate( + ptr, + Some((Size::from_bytes(old_size), align)), + Size::from_bytes(new_size), + align, + MiriMemoryKind::Rust.into(), + )?; + this.write_pointer(new_ptr, dest) + }); } // C memory handling functions diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 6d417fd09671..83b4032cd98a 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -21,7 +21,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, ret: mir::BasicBlock, - ) -> InterpResult<'tcx, EmulateByNameResult> { + ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); match &*link_name.as_str() { diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 0a9939fedd4c..8d0f8487f5e1 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -18,7 +18,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, _ret: mir::BasicBlock, - ) -> InterpResult<'tcx, EmulateByNameResult> { + ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); match &*link_name.as_str() { diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index 2f79b337ce38..8147b1442907 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -16,7 +16,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, _ret: mir::BasicBlock, - ) -> InterpResult<'tcx, EmulateByNameResult> { + ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); match &*link_name.as_str() { diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 0eebd6aca5bd..61a1759ffee5 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -18,7 +18,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, _ret: mir::BasicBlock, - ) -> InterpResult<'tcx, EmulateByNameResult> { + ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); // Windows API stubs. diff --git a/tests/compile-fail/alloc/no_global_allocator.rs b/tests/compile-fail/alloc/no_global_allocator.rs new file mode 100644 index 000000000000..fb0e7986bb5e --- /dev/null +++ b/tests/compile-fail/alloc/no_global_allocator.rs @@ -0,0 +1,25 @@ +// Make sure we pretend the allocation symbols don't exist when there is no allocator + +#![feature(lang_items, start)] +#![no_std] + +extern "Rust" { + fn __rust_alloc(size: usize, align: usize) -> *mut u8; +} + +#[start] +fn start(_: isize, _: *const *const u8) -> isize { + unsafe { + __rust_alloc(1, 1); //~ERROR: unsupported operation: can't call foreign function: __rust_alloc + } + + 0 +} + +#[panic_handler] +fn panic_handler(_: &core::panic::PanicInfo) -> ! { + loop {} +} + +#[lang = "eh_personality"] +fn eh_personality() {} diff --git a/tests/run-pass/global_allocator.rs b/tests/run-pass/global_allocator.rs new file mode 100644 index 000000000000..24a56c663f06 --- /dev/null +++ b/tests/run-pass/global_allocator.rs @@ -0,0 +1,41 @@ +#![feature(allocator_api, slice_ptr_get)] + +use std::alloc::{Allocator as _, Global, GlobalAlloc, Layout, System}; + +#[global_allocator] +static ALLOCATOR: Allocator = Allocator; + +struct Allocator; + +unsafe impl GlobalAlloc for Allocator { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + // use specific size to avoid getting triggered by rt + if layout.size() == 123 { + println!("Allocated!") + } + + System.alloc(layout) + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + if layout.size() == 123 { + println!("Dellocated!") + } + + System.dealloc(ptr, layout) + } +} + +fn main() { + // Only okay because we explicitly set a global allocator that uses the system allocator! + let l = Layout::from_size_align(123, 1).unwrap(); + let ptr = Global.allocate(l).unwrap().as_non_null_ptr(); // allocating with Global... + unsafe { + System.deallocate(ptr, l); + } // ... and deallocating with System. + + let ptr = System.allocate(l).unwrap().as_non_null_ptr(); // allocating with System... + unsafe { + Global.deallocate(ptr, l); + } // ... and deallocating with Global. +} diff --git a/tests/run-pass/global_allocator.stdout b/tests/run-pass/global_allocator.stdout new file mode 100644 index 000000000000..411a4cdd1467 --- /dev/null +++ b/tests/run-pass/global_allocator.stdout @@ -0,0 +1,2 @@ +Allocated! +Dellocated! From 0424554080ac1be93e572ed73ab1278e3762ee3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Fri, 1 Oct 2021 23:08:58 +0200 Subject: [PATCH 2814/5092] Update dependencies --- Cargo.lock | 43 ++++++++----------------------------------- Cargo.toml | 6 +++--- 2 files changed, 11 insertions(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0dbd1b865689..24593d333284 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -103,9 +103,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.8.3" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17392a012ea30ef05a610aa97dfb49496e71c9f676b27879922ea5bdf60d9d3f" +checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" dependencies = [ "atty", "humantime", @@ -313,15 +313,6 @@ dependencies = [ "libc", ] -[[package]] -name = "pest" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" -dependencies = [ - "ucd-trie", -] - [[package]] name = "ppv-lite86" version = "0.2.10" @@ -445,9 +436,9 @@ checksum = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" [[package]] name = "rustc_version" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ "semver", ] @@ -484,21 +475,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "semver" -version = "0.11.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" -dependencies = [ - "pest", -] +checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" [[package]] name = "serde" @@ -539,9 +518,9 @@ checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" [[package]] name = "smallvec" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" +checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" [[package]] name = "syn" @@ -601,12 +580,6 @@ dependencies = [ "term", ] -[[package]] -name = "ucd-trie" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" - [[package]] name = "unicode-width" version = "0.1.8" diff --git a/Cargo.toml b/Cargo.toml index 82962c6b98aa..a4d85e39e65d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,12 +19,12 @@ doctest = false # and no doc tests [dependencies] getrandom = { version = "0.2", features = ["std"] } -env_logger = "0.8" +env_logger = "0.9" log = "0.4" shell-escape = "0.1.4" hex = "0.4.0" rand = "0.8" -smallvec = "1.4.2" +smallvec = "1.7" # A noop dependency that changes in the Rust repository, it's a bit of a hack. # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` @@ -39,7 +39,7 @@ libc = "0.2" [dev-dependencies] compiletest_rs = { version = "0.7", features = ["tmp"] } -rustc_version = "0.3" +rustc_version = "0.4" colored = "2" [package.metadata.rust-analyzer] From 9af75a824f0d1d07e111ef68c3198568a2b6a513 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Tue, 5 Oct 2021 13:13:06 -0700 Subject: [PATCH 2815/5092] rustup Update to the `HEAD` commit of rust-lang/rust and fix test failure. --- rust-version | 2 +- tests/compile-fail/erroneous_const.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 65591aa7ebd9..0423627269b2 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -2b6ed3b675475abc01ce7e68bb75b457f0c85684 +25ec8273855fde2d72ae877b397e054de5300e10 diff --git a/tests/compile-fail/erroneous_const.rs b/tests/compile-fail/erroneous_const.rs index 199439ccbd2e..2592483fe65a 100644 --- a/tests/compile-fail/erroneous_const.rs +++ b/tests/compile-fail/erroneous_const.rs @@ -2,7 +2,6 @@ //! (https://github.com/rust-lang/miri/issues/1382) // Inlining changes the error location // compile-flags: -Zmir-opt-level=0 -#![feature(const_panic)] #![feature(never_type)] #![warn(warnings, const_err)] From e751c7b04e2378a1055278c12ddf7ac44634042a Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 7 Oct 2021 11:52:11 -0700 Subject: [PATCH 2816/5092] rustup --- rust-version | 2 +- tests/run-pass/available-concurrency.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 0423627269b2..fdd83d708142 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -25ec8273855fde2d72ae877b397e054de5300e10 +0157cc977fd71297ce73e2f249321f5ba2555d42 diff --git a/tests/run-pass/available-concurrency.rs b/tests/run-pass/available-concurrency.rs index 5f3121ca8a63..422046c62d62 100644 --- a/tests/run-pass/available-concurrency.rs +++ b/tests/run-pass/available-concurrency.rs @@ -1,5 +1,5 @@ -#![feature(available_concurrency)] +#![feature(available_parallelism)] fn main() { - assert_eq!(std::thread::available_concurrency().unwrap().get(), 1); + assert_eq!(std::thread::available_parallelism().unwrap().get(), 1); } From 0309de73dca88009d67993d0f59f9c5c958ae823 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Habov=C5=A1tiak?= Date: Sat, 9 Oct 2021 22:19:14 +0200 Subject: [PATCH 2817/5092] Document threading support a bit more This adds a few known limitations around threading to the README and suggests the users to look into GitHub issues to learn more. --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 7cd802762bff..49a0c3c1f507 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,11 @@ in your program, and cannot run all programs: has no access to most platform-specific APIs or FFI. A few APIs have been implemented (such as printing to stdout) but most have not: for example, Miri currently does not support SIMD or networking. +* Threading support is not finished yet. E.g. weak memory effects are not + emulated and spin loops (without syscalls) just loop forever. There's no + threading support on Windows. + +Consider looking into GitHub isues for more information about the limitations. [rust]: https://www.rust-lang.org/ [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md From 31ed3a7120d3d64389d9e0835ca25d6e1076db43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Habov=C5=A1tiak?= Date: Tue, 12 Oct 2021 11:09:43 +0200 Subject: [PATCH 2818/5092] Typo fixes Co-authored-by: Ralf Jung --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 49a0c3c1f507..aa016fc07934 100644 --- a/README.md +++ b/README.md @@ -59,8 +59,8 @@ in your program, and cannot run all programs: has no access to most platform-specific APIs or FFI. A few APIs have been implemented (such as printing to stdout) but most have not: for example, Miri currently does not support SIMD or networking. -* Threading support is not finished yet. E.g. weak memory effects are not - emulated and spin loops (without syscalls) just loop forever. There's no +* Threading support is not finished yet. E.g., weak memory effects are not + emulated and spin loops (without syscalls) just loop forever. There is no threading support on Windows. Consider looking into GitHub isues for more information about the limitations. From f040413af8a8e25deb245bd752a47281284a993e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 12 Oct 2021 11:39:06 -0400 Subject: [PATCH 2819/5092] rustup --- rust-version | 2 +- tests/run-pass/too-large-primval-write-problem.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index fdd83d708142..a51e57fd461b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0157cc977fd71297ce73e2f249321f5ba2555d42 +9475e609b8458fff9e444934a6017d2e590642cf diff --git a/tests/run-pass/too-large-primval-write-problem.rs b/tests/run-pass/too-large-primval-write-problem.rs index ebd6dbb61ee4..f4c418bd78a9 100644 --- a/tests/run-pass/too-large-primval-write-problem.rs +++ b/tests/run-pass/too-large-primval-write-problem.rs @@ -16,7 +16,7 @@ fn main() { let bad = unsafe { transmute::(-x) }; // Force it through the Memory::write_primval code. - Box::new(bad); + drop(Box::new(bad)); } #[cfg(not(target_pointer_width = "32"))] From 782085adcd9d3434db20e59585ee20d86e703211 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Habov=C5=A1tiak?= Date: Tue, 12 Oct 2021 18:46:23 +0200 Subject: [PATCH 2820/5092] Remove vague statement from README Addresses https://github.com/rust-lang/miri/pull/1898#discussion_r727274293 --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index aa016fc07934..0c5b591e72d5 100644 --- a/README.md +++ b/README.md @@ -63,8 +63,6 @@ in your program, and cannot run all programs: emulated and spin loops (without syscalls) just loop forever. There is no threading support on Windows. -Consider looking into GitHub isues for more information about the limitations. - [rust]: https://www.rust-lang.org/ [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md [`unreachable_unchecked`]: https://doc.rust-lang.org/stable/std/hint/fn.unreachable_unchecked.html From 4a44c33976f8d8037b761c1182c3be9fcd895b61 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Oct 2021 14:04:14 -0400 Subject: [PATCH 2821/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index a51e57fd461b..faba8395d147 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9475e609b8458fff9e444934a6017d2e590642cf +81117ff930fbf3792b4f9504e3c6bccc87b10823 From a6b12c229b6f81716f30e8f6ba7b1a6e5485a1cd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Oct 2021 09:49:19 -0400 Subject: [PATCH 2822/5092] rustup; add swap_remove test --- rust-version | 2 +- tests/run-pass/vec.rs | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index faba8395d147..7fb789d83db8 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -81117ff930fbf3792b4f9504e3c6bccc87b10823 +e015ef5b2633960e7653b744d7a1c3d1d336313a diff --git a/tests/run-pass/vec.rs b/tests/run-pass/vec.rs index 5676f9b676bf..8ed81a5e343f 100644 --- a/tests/run-pass/vec.rs +++ b/tests/run-pass/vec.rs @@ -140,6 +140,14 @@ fn swap() { v.swap(2, 2); } +fn swap_remove() { + let mut a = 0; + let mut b = 1; + let mut vec = vec![&mut a, &mut b]; + + vec.swap_remove(1); +} + fn main() { assert_eq!(vec_reallocate().len(), 5); @@ -167,4 +175,5 @@ fn main() { sort(); swap(); + swap_remove(); } From 9944a2daf3ec5714becc61ad9694578663b37784 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 26 Oct 2021 13:42:03 +0200 Subject: [PATCH 2823/5092] rustup --- rust-version | 2 +- src/bin/miri.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 7fb789d83db8..b5e272cc4dd1 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e015ef5b2633960e7653b744d7a1c3d1d336313a +c7a30c8b6860d1f3459086f7a91074db1b54bc37 diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 36e7f1bfddaa..84e66db2a7d9 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -25,7 +25,7 @@ use rustc_hir::{self as hir, def_id::LOCAL_CRATE, Node}; use rustc_interface::interface::Config; use rustc_middle::{ middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}, - ty::{query::Providers, TyCtxt}, + ty::{query::ExternProviders, TyCtxt}, }; use rustc_session::{config::ErrorOutputType, search_paths::PathKind, CtfeBacktrace}; @@ -37,7 +37,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { fn config(&mut self, config: &mut Config) { config.override_queries = Some(|_, _, external_providers| { external_providers.used_crate_source = |tcx, cnum| { - let mut providers = Providers::default(); + let mut providers = ExternProviders::default(); rustc_metadata::provide_extern(&mut providers); let mut crate_source = (providers.used_crate_source)(tcx, cnum); // HACK: rustc will emit "crate ... required to be available in rlib format, but From 141bf38f23d2737bde70a38a23bbe90fa062c450 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Mon, 25 Oct 2021 18:55:40 -0700 Subject: [PATCH 2824/5092] Add instructions for using rust-analyzer for Miri development --- CONTRIBUTING.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index eea97863d3e2..caed6e3226d8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -107,6 +107,41 @@ There's a test for the cargo wrapper in the `test-cargo-miri` directory; run `./run-test.py` in there to execute it. Like `./miri test`, this respects the `MIRI_TEST_TARGET` environment variable to execute the test for another target. +## Configuring `rust-analyzer` + +To configure `rust-analyzer` and VS Code for working on Miri, save the following +to `.vscode/settings.json` in your local Miri clone: + +```json +{ + "rust-analyzer.checkOnSave.overrideCommand": [ + "./miri", + "check", + "--message-format=json" + ], + "rust-analyzer.rustfmt.extraArgs": [ + "+nightly" + ], + "rust-analyzer.rustcSource": "discover", + "rust-analyzer.linkedProjects": [ + "./Cargo.toml", + "./cargo-miri/Cargo.toml" + ] +} +``` + +> #### Note +> +> If you are [building Miri with a locally built rustc][], set +> `rust-analyzer.rustcSource` to the relative path from your Miri clone to the +> root `Cargo.toml` of the locally built rustc. For example, the path might look +> like `../rust/Cargo.toml`. + +See the rustc-dev-guide's docs on ["Configuring `rust-analyzer` for `rustc`"][rdg-r-a] +for more information about configuring VS Code and `rust-analyzer`. + +[rdg-r-a]: https://rustc-dev-guide.rust-lang.org/building/suggested.html#configuring-rust-analyzer-for-rustc + ## Advanced topic: other build environments We described above the simplest way to get a working build environment for Miri, @@ -132,6 +167,8 @@ rustc. This avoids blocking all Miri development on landing a big PR. ### Building Miri with a locally built rustc +[building Miri with a locally built rustc]: #building-miri-with-a-locally-built-rustc + A big part of the Miri driver lives in rustc, so working on Miri will sometimes require using a locally built rustc. The bug you want to fix may actually be on the rustc side, or you just need to get more detailed trace of the execution From 6d1d8c69a094a6d64d26a2a15c5a2fb250ce17c1 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Mon, 1 Nov 2021 15:31:37 -0700 Subject: [PATCH 2825/5092] rustup --- rust-version | 2 +- tests/compile-fail/alloc/reallocate-bad-size.rs | 2 +- tests/compile-fail/alloc/reallocate-change-alloc.rs | 2 +- tests/compile-fail/alloc/reallocate-dangling.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index b5e272cc4dd1..fd8c69e11238 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c7a30c8b6860d1f3459086f7a91074db1b54bc37 +db062de72b0a064f45b6f86894cbdc7c0ec68844 diff --git a/tests/compile-fail/alloc/reallocate-bad-size.rs b/tests/compile-fail/alloc/reallocate-bad-size.rs index 80239015dc1d..d6a27c930a28 100644 --- a/tests/compile-fail/alloc/reallocate-bad-size.rs +++ b/tests/compile-fail/alloc/reallocate-bad-size.rs @@ -5,6 +5,6 @@ use std::alloc::{alloc, realloc, Layout}; fn main() { unsafe { let x = alloc(Layout::from_size_align_unchecked(1, 1)); - realloc(x, Layout::from_size_align_unchecked(2, 1), 1); + let _y = realloc(x, Layout::from_size_align_unchecked(2, 1), 1); } } diff --git a/tests/compile-fail/alloc/reallocate-change-alloc.rs b/tests/compile-fail/alloc/reallocate-change-alloc.rs index 297029676962..14d05e745751 100644 --- a/tests/compile-fail/alloc/reallocate-change-alloc.rs +++ b/tests/compile-fail/alloc/reallocate-change-alloc.rs @@ -3,7 +3,7 @@ use std::alloc::{alloc, realloc, Layout}; fn main() { unsafe { let x = alloc(Layout::from_size_align_unchecked(1, 1)); - realloc(x, Layout::from_size_align_unchecked(1, 1), 1); + let _y = realloc(x, Layout::from_size_align_unchecked(1, 1), 1); let _z = *x; //~ ERROR dereferenced after this allocation got freed } } diff --git a/tests/compile-fail/alloc/reallocate-dangling.rs b/tests/compile-fail/alloc/reallocate-dangling.rs index 702ddc0724a3..62eb7582a2f7 100644 --- a/tests/compile-fail/alloc/reallocate-dangling.rs +++ b/tests/compile-fail/alloc/reallocate-dangling.rs @@ -6,6 +6,6 @@ fn main() { unsafe { let x = alloc(Layout::from_size_align_unchecked(1, 1)); dealloc(x, Layout::from_size_align_unchecked(1, 1)); - realloc(x, Layout::from_size_align_unchecked(1, 1), 1); + let _z = realloc(x, Layout::from_size_align_unchecked(1, 1), 1); } } From e6a9b2ce6878f7944f8b414d511afdb5240965b0 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sun, 3 Oct 2021 16:28:41 -0700 Subject: [PATCH 2826/5092] Update Miri for detecting uninitialized numbers This commit adds a `-Zmiri-check-number-initialization` flag to check that integers and floats are initialized. This commit also changes some shims to write at type `MaybeUninit<...>` in order to prevent spurious errors from the uninit check. --- src/bin/miri.rs | 3 +++ src/eval.rs | 3 +++ src/machine.rs | 9 +++++++++ src/shims/posix/sync.rs | 29 +++++++++++++++++++++++------ 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 84e66db2a7d9..cf32e6332269 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -313,6 +313,9 @@ fn main() { "-Zmiri-symbolic-alignment-check" => { miri_config.check_alignment = miri::AlignmentCheck::Symbolic; } + "-Zmiri-check-number-validity" => { + miri_config.check_number_validity = true; + } "-Zmiri-disable-abi-check" => { miri_config.check_abi = false; } diff --git a/src/eval.rs b/src/eval.rs index 5d8d332fcd9c..ac32af30c1de 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -66,6 +66,8 @@ pub struct MiriConfig { pub stacked_borrows: bool, /// Controls alignment checking. pub check_alignment: AlignmentCheck, + /// Controls integer and float validity (e.g., initialization) checking. + pub check_number_validity: bool, /// Controls function [ABI](Abi) checking. pub check_abi: bool, /// Action for an op requiring communication with the host. @@ -104,6 +106,7 @@ impl Default for MiriConfig { validate: true, stacked_borrows: true, check_alignment: AlignmentCheck::Int, + check_number_validity: false, check_abi: true, isolated_op: IsolatedOp::Reject(RejectOpWith::Abort), ignore_leaks: false, diff --git a/src/machine.rs b/src/machine.rs index 23278a4891fb..0ead28b36c75 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -304,6 +304,9 @@ pub struct Evaluator<'mir, 'tcx> { /// Whether to enforce the validity invariant. pub(crate) validate: bool, + /// Whether to enforce validity (e.g., initialization) of integers and floats. + pub(crate) enforce_number_validity: bool, + /// Whether to enforce [ABI](Abi) of function calls. pub(crate) enforce_abi: bool, @@ -356,6 +359,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { tls: TlsData::default(), isolated_op: config.isolated_op, validate: config.validate, + enforce_number_validity: config.check_number_validity, enforce_abi: config.check_abi, file_handler: Default::default(), dir_handler: Default::default(), @@ -426,6 +430,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx.machine.validate } + #[inline(always)] + fn enforce_number_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + ecx.machine.enforce_number_validity + } + #[inline(always)] fn enforce_abi(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { ecx.machine.enforce_abi diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 782765c7784b..606f58a207e5 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -1,5 +1,8 @@ use std::time::SystemTime; +use rustc_hir::LangItem; +use rustc_middle::ty::{layout::TyAndLayout, query::TyCtxtAt, subst::Subst, Ty}; + use crate::*; use thread::Time; @@ -44,7 +47,7 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( attr_op: &OpTy<'tcx, Tag>, kind: impl Into>, ) -> InterpResult<'tcx, ()> { - ecx.write_scalar_at_offset(attr_op, 0, kind, ecx.machine.layouts.i32) + ecx.write_scalar_at_offset(attr_op, 0, kind, layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.i32)) } // pthread_mutex_t is between 24 and 48 bytes, depending on the platform. @@ -79,7 +82,7 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( mutex_op, offset, kind, - ecx.machine.layouts.i32, + layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.i32), AtomicWriteOp::Relaxed, ) } @@ -100,7 +103,7 @@ fn mutex_set_id<'mir, 'tcx: 'mir>( mutex_op, 4, id, - ecx.machine.layouts.u32, + layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.u32), AtomicWriteOp::Relaxed, ) } @@ -144,7 +147,7 @@ fn rwlock_set_id<'mir, 'tcx: 'mir>( rwlock_op, 4, id, - ecx.machine.layouts.u32, + layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.u32), AtomicWriteOp::Relaxed, ) } @@ -211,7 +214,7 @@ fn cond_set_id<'mir, 'tcx: 'mir>( cond_op, 4, id, - ecx.machine.layouts.u32, + layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.u32), AtomicWriteOp::Relaxed, ) } @@ -244,7 +247,12 @@ fn cond_set_clock_id<'mir, 'tcx: 'mir>( cond_op: &OpTy<'tcx, Tag>, clock_id: impl Into>, ) -> InterpResult<'tcx, ()> { - ecx.write_scalar_at_offset(cond_op, 8, clock_id, ecx.machine.layouts.i32) + ecx.write_scalar_at_offset( + cond_op, + 8, + clock_id, + layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.i32), + ) } /// Try to reacquire the mutex associated with the condition variable after we @@ -788,3 +796,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } } + +fn layout_of_maybe_uninit<'tcx>(tcx: TyCtxtAt<'tcx>, param: Ty<'tcx>) -> TyAndLayout<'tcx> { + let def_id = tcx.require_lang_item(LangItem::MaybeUninit, None); + let def_ty = tcx.type_of(def_id); + let ty = def_ty.subst(*tcx, &[param.into()]); + + let param_env = tcx.param_env(def_id); + tcx.layout_of(param_env.and(ty)).unwrap() +} From 1659ef42069c53595dc41a530839a5fc04c5988b Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Fri, 29 Oct 2021 16:36:41 -0700 Subject: [PATCH 2827/5092] Add docs for `-Zmiri-check-number-validity` --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 0c5b591e72d5..504759eabd24 100644 --- a/README.md +++ b/README.md @@ -199,6 +199,10 @@ up the sysroot. If you are using `miri` (the Miri driver) directly, see the Miri adds its own set of `-Z` flags, which are usually set via the `MIRIFLAGS` environment variable: +* `-Zmiri-check-number-validity` enables checking of integer and float validity + (e.g., they must be initialized and not carry pointer provenance) as part of + enforcing validity invariants. This has no effect when + `-Zmiri-disable-validation` is present. * `-Zmiri-compare-exchange-weak-failure-rate=` changes the failure rate of `compare_exchange_weak` operations. The default is `0.8` (so 4 out of 5 weak ops will fail). You can change it to any value between `0.0` and `1.0`, where `1.0` means it From b3be6b44b6a19b36ea7c579f757fb5764e83663b Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sun, 24 Oct 2021 13:43:47 -0700 Subject: [PATCH 2828/5092] Add tests for `-Zmiri-check-number-validity` --- tests/compile-fail/uninit_float.rs | 8 ++++++++ tests/compile-fail/uninit_integer.rs | 8 ++++++++ tests/compile-fail/uninit_integer_signed.rs | 8 ++++++++ tests/run-pass/uninit_number_ignored.rs | 8 ++++++++ 4 files changed, 32 insertions(+) create mode 100644 tests/compile-fail/uninit_float.rs create mode 100644 tests/compile-fail/uninit_integer.rs create mode 100644 tests/compile-fail/uninit_integer_signed.rs create mode 100644 tests/run-pass/uninit_number_ignored.rs diff --git a/tests/compile-fail/uninit_float.rs b/tests/compile-fail/uninit_float.rs new file mode 100644 index 000000000000..06953e1ced96 --- /dev/null +++ b/tests/compile-fail/uninit_float.rs @@ -0,0 +1,8 @@ +// compile-flags: -Zmiri-check-number-validity + +// This test is adapted from https://github.com/rust-lang/miri/issues/1340#issue-600900312. + +fn main() { + let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + //~^ ERROR type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes +} diff --git a/tests/compile-fail/uninit_integer.rs b/tests/compile-fail/uninit_integer.rs new file mode 100644 index 000000000000..757f69c050fe --- /dev/null +++ b/tests/compile-fail/uninit_integer.rs @@ -0,0 +1,8 @@ +// compile-flags: -Zmiri-check-number-validity + +// This test is from https://github.com/rust-lang/miri/issues/1340#issue-600900312. + +fn main() { + let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + //~^ ERROR type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes +} diff --git a/tests/compile-fail/uninit_integer_signed.rs b/tests/compile-fail/uninit_integer_signed.rs new file mode 100644 index 000000000000..bb5d7314a7c1 --- /dev/null +++ b/tests/compile-fail/uninit_integer_signed.rs @@ -0,0 +1,8 @@ +// compile-flags: -Zmiri-check-number-validity + +// This test is adapted from https://github.com/rust-lang/miri/issues/1340#issue-600900312. + +fn main() { + let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + //~^ ERROR type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes +} diff --git a/tests/run-pass/uninit_number_ignored.rs b/tests/run-pass/uninit_number_ignored.rs new file mode 100644 index 000000000000..77d6af6e99cf --- /dev/null +++ b/tests/run-pass/uninit_number_ignored.rs @@ -0,0 +1,8 @@ +// This test is adapted from https://github.com/rust-lang/miri/issues/1340#issue-600900312. +// This test passes because -Zmiri-check-number-validity is not passed. + +fn main() { + let _val1 = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + let _val2 = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + let _val3 = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; +} From 1cca2acf9553e0993a79e0e1a5443cac3ead6a03 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Fri, 29 Oct 2021 16:40:20 -0700 Subject: [PATCH 2829/5092] Add test for uninit raw ptrs --- tests/compile-fail/uninit_raw_ptr.rs | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 tests/compile-fail/uninit_raw_ptr.rs diff --git a/tests/compile-fail/uninit_raw_ptr.rs b/tests/compile-fail/uninit_raw_ptr.rs new file mode 100644 index 000000000000..beb9ad127094 --- /dev/null +++ b/tests/compile-fail/uninit_raw_ptr.rs @@ -0,0 +1,4 @@ +fn main() { + let _val = unsafe { std::mem::MaybeUninit::<*const u8>::uninit().assume_init() }; + //~^ ERROR type validation failed at .value: encountered uninitialized raw pointer +} From 6dd10820dd207d392f58b36ff919b8b17cfa1261 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Wed, 10 Nov 2021 11:38:35 -0800 Subject: [PATCH 2830/5092] rustup So that we get rust-lang/rust#88670. --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index fd8c69e11238..d43b9e8197bb 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -db062de72b0a064f45b6f86894cbdc7c0ec68844 +68ca579406f2fa9ec62710e4a4d5d3e07a168d3c From d8bee92aee3394d2fd9a0b83516651ee7141b032 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 13 Nov 2021 15:40:26 -0500 Subject: [PATCH 2831/5092] rename track-raw-pointers flag to tag-raw-pointers --- README.md | 15 +++++++-------- src/bin/miri.rs | 8 +++++++- src/eval.rs | 4 ++-- src/machine.rs | 2 +- src/stacked_borrows.rs | 10 +++++----- test-cargo-miri/run-test.py | 2 +- tests/compile-fail/box-cell-alias.rs | 2 +- .../compile-fail/stacked_borrows/raw_tracking.rs | 2 +- tests/compile-fail/stacked_borrows/zst_slice.rs | 2 +- tests/run-pass/btreemap.rs | 2 +- .../concurrency/tls_lib_drop_single_thread.rs | 2 +- tests/run-pass/rc.rs | 2 +- tests/run-pass/slices.rs | 2 +- tests/run-pass/stacked-borrows/stacked-borrows.rs | 2 +- tests/run-pass/strings.rs | 2 +- tests/run-pass/vec.rs | 2 +- tests/run-pass/vecdeque.rs | 2 +- 17 files changed, 34 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 504759eabd24..487f8aeb2baf 100644 --- a/README.md +++ b/README.md @@ -276,14 +276,13 @@ environment variable: is popped from a borrow stack (which is where the tag becomes invalid and any future use of it will error). This helps you in finding out why UB is happening and where in your code would be a good place to look for it. -* `-Zmiri-track-raw-pointers` makes Stacked Borrows track a pointer tag even for - raw pointers. This can make valid code fail to pass the checks, but also can - help identify latent aliasing issues in code that Miri accepts by default. You - can recognize false positives by `` occurring in the message -- this - indicates a pointer that was cast from an integer, so Miri was unable to track - this pointer. Note that it is not currently guaranteed that code that works - with `-Zmiri-track-raw-pointers` also works without - `-Zmiri-track-raw-pointers`, but for the vast majority of code, this will be the case. +* `-Zmiri-tag-raw-pointers` makes Stacked Borrows assign proper tags even for raw pointers. This can + make valid code using int-to-ptr casts fail to pass the checks, but also can help identify latent + aliasing issues in code that Miri accepts by default. You can recognize false positives by + `` occurring in the message -- this indicates a pointer that was cast from an integer, + so Miri was unable to track this pointer. Note that it is not currently guaranteed that code that + works with `-Zmiri-tag-raw-pointers` also works without `-Zmiri-tag-raw-pointers`, but for the + vast majority of code, this will be the case. [function ABI]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier diff --git a/src/bin/miri.rs b/src/bin/miri.rs index cf32e6332269..672c7e8c9675 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -359,8 +359,14 @@ fn main() { "-Zmiri-panic-on-unsupported" => { miri_config.panic_on_unsupported = true; } + "-Zmiri-tag-raw-pointers" => { + miri_config.tag_raw = true; + } "-Zmiri-track-raw-pointers" => { - miri_config.track_raw = true; + eprintln!( + "WARNING: -Zmiri-track-raw-pointers has been renamed to -Zmiri-tag-raw-pointers, the old name is deprecated." + ); + miri_config.tag_raw = true; } "--" => { after_dashdash = true; diff --git a/src/eval.rs b/src/eval.rs index ac32af30c1de..e3f252b50a92 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -87,7 +87,7 @@ pub struct MiriConfig { /// The allocation id to report about. pub tracked_alloc_id: Option, /// Whether to track raw pointers in stacked borrows. - pub track_raw: bool, + pub tag_raw: bool, /// Determine if data race detection should be enabled pub data_race_detector: bool, /// Rate of spurious failures for compare_exchange_weak atomic operations, @@ -116,7 +116,7 @@ impl Default for MiriConfig { tracked_pointer_tag: None, tracked_call_id: None, tracked_alloc_id: None, - track_raw: false, + tag_raw: false, data_race_detector: true, cmpxchg_weak_failure_rate: 0.8, measureme_out: None, diff --git a/src/machine.rs b/src/machine.rs index 0ead28b36c75..201854e76fa4 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -194,7 +194,7 @@ impl MemoryExtra { Some(RefCell::new(stacked_borrows::GlobalState::new( config.tracked_pointer_tag, config.tracked_call_id, - config.track_raw, + config.tag_raw, ))) } else { None diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 65678b6f01fe..57c09ea40b68 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -105,7 +105,7 @@ pub struct GlobalState { /// The call id to trace tracked_call_id: Option, /// Whether to track raw pointers. - track_raw: bool, + tag_raw: bool, } /// Memory extra state gives us interior mutable access to the global state. pub type MemoryExtra = RefCell; @@ -156,7 +156,7 @@ impl GlobalState { pub fn new( tracked_pointer_tag: Option, tracked_call_id: Option, - track_raw: bool, + tag_raw: bool, ) -> Self { GlobalState { next_ptr_id: NonZeroU64::new(1).unwrap(), @@ -165,7 +165,7 @@ impl GlobalState { active_calls: FxHashSet::default(), tracked_pointer_tag, tracked_call_id, - track_raw, + tag_raw, } } @@ -532,7 +532,7 @@ impl Stacks { MiriMemoryKind::Rust | MiriMemoryKind::C | MiriMemoryKind::WinHeap, ) => { let tag = - if extra.track_raw { extra.base_tag(id) } else { extra.base_tag_untagged(id) }; + if extra.tag_raw { extra.base_tag(id) } else { extra.base_tag_untagged(id) }; (tag, Permission::SharedReadWrite) } }; @@ -719,7 +719,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mem_extra = this.memory.extra.stacked_borrows.as_mut().unwrap().get_mut(); match kind { // Give up tracking for raw pointers. - RefKind::Raw { .. } if !mem_extra.track_raw => SbTag::Untagged, + RefKind::Raw { .. } if !mem_extra.tag_raw => SbTag::Untagged, // All other pointers are properly tracked. _ => SbTag::Tagged(mem_extra.new_ptr()), } diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 18671b2e29da..19965639489b 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -127,7 +127,7 @@ def test_cargo_miri_test(): test("`cargo miri test` (raw-ptr tracking)", cargo_miri("test"), default_ref, "test.stderr-empty.ref", - env={'MIRIFLAGS': "-Zmiri-track-raw-pointers"}, + env={'MIRIFLAGS': "-Zmiri-tag-raw-pointers"}, ) test("`cargo miri test` (with filter)", cargo_miri("test") + ["--", "--format=pretty", "le1"], diff --git a/tests/compile-fail/box-cell-alias.rs b/tests/compile-fail/box-cell-alias.rs index 5d63fc1d44a5..58fc3530d7bf 100644 --- a/tests/compile-fail/box-cell-alias.rs +++ b/tests/compile-fail/box-cell-alias.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-track-raw-pointers +// compile-flags: -Zmiri-tag-raw-pointers // Taken from . diff --git a/tests/compile-fail/stacked_borrows/raw_tracking.rs b/tests/compile-fail/stacked_borrows/raw_tracking.rs index 975aec945c7f..0d6d0198fbe9 100644 --- a/tests/compile-fail/stacked_borrows/raw_tracking.rs +++ b/tests/compile-fail/stacked_borrows/raw_tracking.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-track-raw-pointers +// compile-flags: -Zmiri-tag-raw-pointers //! This demonstrates a provenance problem that requires tracking of raw pointers to be detected. fn main() { diff --git a/tests/compile-fail/stacked_borrows/zst_slice.rs b/tests/compile-fail/stacked_borrows/zst_slice.rs index 0804f7303082..14d5d77a2bb6 100644 --- a/tests/compile-fail/stacked_borrows/zst_slice.rs +++ b/tests/compile-fail/stacked_borrows/zst_slice.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-track-raw-pointers +// compile-flags: -Zmiri-tag-raw-pointers // error-pattern: does not have an appropriate item in the borrow stack fn main() { diff --git a/tests/run-pass/btreemap.rs b/tests/run-pass/btreemap.rs index b704b89fd050..842ba0f4a874 100644 --- a/tests/run-pass/btreemap.rs +++ b/tests/run-pass/btreemap.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-track-raw-pointers +// compile-flags: -Zmiri-tag-raw-pointers #![feature(btree_drain_filter)] use std::collections::{BTreeMap, BTreeSet}; use std::mem; diff --git a/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs b/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs index cd1bd6480bcf..16ca8a0d2eff 100644 --- a/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs +++ b/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-track-raw-pointers +// compile-flags: -Zmiri-tag-raw-pointers //! Check that destructors of the thread locals are executed on all OSes. #![feature(thread_local_const_init)] diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index 91de20ae2b7f..e00d9df32eec 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-track-raw-pointers +// compile-flags: -Zmiri-tag-raw-pointers #![feature(new_uninit)] #![feature(get_mut_unchecked)] diff --git a/tests/run-pass/slices.rs b/tests/run-pass/slices.rs index 83d9ff115188..9d98c44741b4 100644 --- a/tests/run-pass/slices.rs +++ b/tests/run-pass/slices.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-track-raw-pointers +// compile-flags: -Zmiri-tag-raw-pointers #![feature(new_uninit)] #![feature(slice_as_chunks)] #![feature(slice_partition_dedup)] diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index 0401a6640fd3..8aea945f9093 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-track-raw-pointers +// compile-flags: -Zmiri-tag-raw-pointers use std::ptr; // Test various stacked-borrows-related things. diff --git a/tests/run-pass/strings.rs b/tests/run-pass/strings.rs index b009e8bc6c4a..6998ec6e59b9 100644 --- a/tests/run-pass/strings.rs +++ b/tests/run-pass/strings.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-track-raw-pointers +// compile-flags: -Zmiri-tag-raw-pointers fn empty() -> &'static str { "" diff --git a/tests/run-pass/vec.rs b/tests/run-pass/vec.rs index 8ed81a5e343f..c0cf42134527 100644 --- a/tests/run-pass/vec.rs +++ b/tests/run-pass/vec.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-track-raw-pointers +// compile-flags: -Zmiri-tag-raw-pointers // Gather all references from a mutable iterator and make sure Miri notices if // using them is dangerous. fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { diff --git a/tests/run-pass/vecdeque.rs b/tests/run-pass/vecdeque.rs index 54aeb89ec83f..f45c21d20781 100644 --- a/tests/run-pass/vecdeque.rs +++ b/tests/run-pass/vecdeque.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-track-raw-pointers +// compile-flags: -Zmiri-tag-raw-pointers use std::collections::VecDeque; fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { From a15539e9111e4e30c0229c63c99cdba1627a6e5f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Nov 2021 12:16:03 -0500 Subject: [PATCH 2832/5092] run rustdoc with the miri cfg flag --- cargo-miri/bin.rs | 2 ++ test-cargo-miri/src/lib.rs | 6 ++++++ test-cargo-miri/test.default.stdout.ref | 6 +++--- test-cargo-miri/test.filter.stdout.ref | 2 +- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 21f53a45e41f..9ac1a7086b82 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -1008,6 +1008,8 @@ fn phase_rustdoc(fst_arg: &str, mut args: env::Args) { // rustdoc needs to know the right sysroot. forward_miri_sysroot(&mut cmd); + // make sure the 'miri' flag is set for rustdoc + cmd.arg("--cfg").arg("miri"); // Make rustdoc call us back. let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); diff --git a/test-cargo-miri/src/lib.rs b/test-cargo-miri/src/lib.rs index 6d9158c54ef4..66c8aa2eac57 100644 --- a/test-cargo-miri/src/lib.rs +++ b/test-cargo-miri/src/lib.rs @@ -16,6 +16,12 @@ pub fn make_true() -> bool { issue_1691::use_me() } +/// ```rust +/// cargo_miri_test::miri_only_fn(); +/// ``` +#[cfg(miri)] +pub fn miri_only_fn() {} + pub fn main() { println!("imported main"); } diff --git a/test-cargo-miri/test.default.stdout.ref b/test-cargo-miri/test.default.stdout.ref index d2f94bb5950d..ee8625357509 100644 --- a/test-cargo-miri/test.default.stdout.ref +++ b/test-cargo-miri/test.default.stdout.ref @@ -10,7 +10,7 @@ running 7 tests test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out -running 3 tests -... -test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +running 4 tests +.... +test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/test-cargo-miri/test.filter.stdout.ref b/test-cargo-miri/test.filter.stdout.ref index 6b26e17ff8bb..d14bb8796e85 100644 --- a/test-cargo-miri/test.filter.stdout.ref +++ b/test-cargo-miri/test.filter.stdout.ref @@ -13,5 +13,5 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 3 filtered out; finished in $TIME +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 4 filtered out; finished in $TIME From 77095f8557f241aa0d8dade370f714c4af224cb3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Nov 2021 10:34:32 -0500 Subject: [PATCH 2833/5092] tweak cron job time --- .github/workflows/ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ce13647fa586..94b9dd6fe55f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,8 +10,7 @@ on: branches: - 'master' schedule: - # Use to conveniently edit cron schedule. - - cron: '0 7 * * *' # At 07:00 UTC every day. + - cron: '5 15 * * *' # At 15:05 UTC every day. jobs: build: From 1593f38401cbf3230bd736d874bb6f6fdc15a368 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Nov 2021 21:12:45 -0500 Subject: [PATCH 2834/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index d43b9e8197bb..45cd53ac6c14 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -68ca579406f2fa9ec62710e4a4d5d3e07a168d3c +c9c4b5d7276297679387189d96a952f2b760e7ad From 0766da6fbeba2e4cd3183f181e10bbc7ba69ade8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Nov 2021 09:36:01 -0500 Subject: [PATCH 2835/5092] implement simd_add --- src/shims/intrinsics.rs | 18 ++++++++++++++++++ tests/run-pass/portable-simd.rs | 8 ++++++++ 2 files changed, 26 insertions(+) create mode 100644 tests/run-pass/portable-simd.rs diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index f2f046a3ada1..9f44f5bac6ce 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -305,6 +305,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } + // SIMD operations + "simd_add" => { + let &[ref left, ref right] = check_arg_count(args)?; + let (left, left_len) = this.operand_to_simd(left)?; + let (right, right_len) = this.operand_to_simd(right)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + assert_eq!(dest_len, left_len); + assert_eq!(dest_len, right_len); + + for i in 0..dest_len { + let left = this.read_immediate(&this.mplace_index(&left, i)?.into())?; + let right = this.read_immediate(&this.mplace_index(&right, i)?.into())?; + let dest = this.mplace_index(&dest, i)?.into(); + this.binop_ignore_overflow(mir::BinOp::Add, &left, &right, &dest)?; + } + } + // Atomic operations "atomic_load" => this.atomic_load(args, dest, AtomicReadOp::SeqCst)?, "atomic_load_relaxed" => this.atomic_load(args, dest, AtomicReadOp::Relaxed)?, diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs new file mode 100644 index 000000000000..1ea7931aed32 --- /dev/null +++ b/tests/run-pass/portable-simd.rs @@ -0,0 +1,8 @@ +#![feature(portable_simd)] +use std::simd::*; + +fn main() { + let a = f32x4::splat(10.0); + let b = f32x4::from_array([1.0, 2.0, 3.0, 4.0]); + assert_eq!(a + b, f32x4::from_array([11.0, 12.0, 13.0, 14.0])); +} From b816cb94e79f7f23e12b567e7f412125fe1ef8b7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Nov 2021 09:42:30 -0500 Subject: [PATCH 2836/5092] implement SIMD sub, mul, div; also test i32 binops --- src/shims/intrinsics.rs | 12 ++++++++++-- tests/run-pass/portable-simd.rs | 21 ++++++++++++++++++++- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 9f44f5bac6ce..d684b41ed81d 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -306,7 +306,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // SIMD operations - "simd_add" => { + "simd_add" | "simd_sub" | "simd_mul" | "simd_div" => { let &[ref left, ref right] = check_arg_count(args)?; let (left, left_len) = this.operand_to_simd(left)?; let (right, right_len) = this.operand_to_simd(right)?; @@ -315,11 +315,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert_eq!(dest_len, left_len); assert_eq!(dest_len, right_len); + let op = match intrinsic_name { + "simd_add" => mir::BinOp::Add, + "simd_sub" => mir::BinOp::Sub, + "simd_mul" => mir::BinOp::Mul, + "simd_div" => mir::BinOp::Div, + _ => unreachable!(), + }; + for i in 0..dest_len { let left = this.read_immediate(&this.mplace_index(&left, i)?.into())?; let right = this.read_immediate(&this.mplace_index(&right, i)?.into())?; let dest = this.mplace_index(&dest, i)?.into(); - this.binop_ignore_overflow(mir::BinOp::Add, &left, &right, &dest)?; + this.binop_ignore_overflow(op, &left, &right, &dest)?; } } diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 1ea7931aed32..42a6befd868b 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -1,8 +1,27 @@ #![feature(portable_simd)] use std::simd::*; -fn main() { +fn simd_ops_f32() { let a = f32x4::splat(10.0); let b = f32x4::from_array([1.0, 2.0, 3.0, 4.0]); assert_eq!(a + b, f32x4::from_array([11.0, 12.0, 13.0, 14.0])); + assert_eq!(a - b, f32x4::from_array([9.0, 8.0, 7.0, 6.0])); + assert_eq!(a * b, f32x4::from_array([10.0, 20.0, 30.0, 40.0])); + assert_eq!(b / a, f32x4::from_array([0.1, 0.2, 0.3, 0.4])); + assert_eq!(a / 2.0, f32x4::splat(5.0)); +} + +fn simd_ops_i32() { + let a = i32x4::splat(10); + let b = i32x4::from_array([1, 2, 3, 4]); + assert_eq!(a + b, i32x4::from_array([11, 12, 13, 14])); + assert_eq!(a - b, i32x4::from_array([9, 8, 7, 6])); + assert_eq!(a * b, i32x4::from_array([10, 20, 30, 40])); + assert_eq!(a / b, i32x4::from_array([10, 5, 3, 2])); + assert_eq!(a / 2, i32x4::splat(5)); +} + +fn main() { + simd_ops_f32(); + simd_ops_i32(); } From 84027dcd228848e29ce3fa552caa615a9b7d5de5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 20 Nov 2021 22:39:22 -0500 Subject: [PATCH 2837/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 45cd53ac6c14..e7e504a38a7c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c9c4b5d7276297679387189d96a952f2b760e7ad +5bc98076f37dd8c1476de4bbe0515c55a65332b7 From 7dd1f0571cde175af95b62ad805ba7381680a048 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Nov 2021 13:53:02 -0500 Subject: [PATCH 2838/5092] test for overflow-checks=off --- tests/run-pass/overflow_checks_off.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tests/run-pass/overflow_checks_off.rs diff --git a/tests/run-pass/overflow_checks_off.rs b/tests/run-pass/overflow_checks_off.rs new file mode 100644 index 000000000000..d6c6971e4952 --- /dev/null +++ b/tests/run-pass/overflow_checks_off.rs @@ -0,0 +1,18 @@ +// compile-flags: -C overflow-checks=off + +// Check that we correctly implement the intended behavior of these operators +// when they are not being overflow-checked. + +// FIXME: if we call the functions in `std::ops`, we still get the panics. +// Miri does not implement the codegen-time hack that backs `#[rustc_inherit_overflow_checks]`. +// use std::ops::*; + +fn main() { + assert_eq!(-{-0x80i8}, -0x80); + + assert_eq!(0xffu8 + 1, 0_u8); + assert_eq!(0u8 - 1, 0xff_u8); + assert_eq!(0xffu8 * 2, 0xfe_u8); + assert_eq!(1u8 << 9, 2_u8); + assert_eq!(2u8 >> 9, 1_u8); +} From c4502cbbe80b691a28de18373fba0d508370177f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Nov 2021 14:32:03 -0500 Subject: [PATCH 2839/5092] async-fn test: make run_fut more general and entirely safe --- tests/run-pass/async-fn.rs | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index d03c2cf282b8..414d5aaf5cc7 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -1,8 +1,6 @@ #![feature(never_type)] -use std::{future::Future, pin::Pin, task::Poll}; -use std::task::{Wake, Waker, Context}; -use std::sync::Arc; +use std::future::Future; // See if we can run a basic `async fn` pub async fn foo(x: &u32, y: u32) -> u32 { @@ -47,7 +45,10 @@ async fn partial_init(x: u32) -> u32 { let _x: (String, !) = (String::new(), return async { x + x }.await); } -fn run_fut(mut fut: impl Future, output: u32) { +fn run_fut(fut: impl Future) -> T { + use std::sync::Arc; + use std::task::{Context, Poll, Wake, Waker}; + struct MyWaker; impl Wake for MyWaker { fn wake(self: Arc) { @@ -57,16 +58,20 @@ fn run_fut(mut fut: impl Future, output: u32) { let waker = Waker::from(Arc::new(MyWaker)); let mut context = Context::from_waker(&waker); - assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(output)); + + let mut pinned = Box::pin(fut); + loop { + match pinned.as_mut().poll(&mut context) { + Poll::Pending => continue, + Poll::Ready(v) => return v, + } + } } fn main() { let x = 5; - run_fut(foo(&x, 7), 31); - - run_fut(build_aggregate(1, 2, 3, 4), 10); - - run_fut(includes_never(false, 4), 16); - - run_fut(partial_init(4), 8); + assert_eq!(run_fut(foo(&x, 7)), 31); + assert_eq!(run_fut(build_aggregate(1, 2, 3, 4)), 10); + assert_eq!(run_fut(includes_never(false, 4)), 16); + assert_eq!(run_fut(partial_init(4)), 8); } From a534bbbf8aeb14d2ee1c2d167e6e6073a114bf69 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 25 Nov 2021 17:13:16 -0500 Subject: [PATCH 2840/5092] portable SIMD: add rem intrinsic; test div and rem intrinsic UB --- src/shims/intrinsics.rs | 3 ++- .../{div-by-zero-1.rs => div-by-zero.rs} | 0 .../{div-by-zero-2.rs => rem-by-zero.rs} | 0 tests/compile-fail/intrinsics/simd-div-by-zero.rs | 15 +++++++++++++++ tests/compile-fail/intrinsics/simd-rem-by-zero.rs | 15 +++++++++++++++ tests/run-pass/portable-simd.rs | 2 ++ 6 files changed, 34 insertions(+), 1 deletion(-) rename tests/compile-fail/intrinsics/{div-by-zero-1.rs => div-by-zero.rs} (100%) rename tests/compile-fail/intrinsics/{div-by-zero-2.rs => rem-by-zero.rs} (100%) create mode 100644 tests/compile-fail/intrinsics/simd-div-by-zero.rs create mode 100644 tests/compile-fail/intrinsics/simd-rem-by-zero.rs diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index d684b41ed81d..547f23f620d2 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -306,7 +306,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // SIMD operations - "simd_add" | "simd_sub" | "simd_mul" | "simd_div" => { + "simd_add" | "simd_sub" | "simd_mul" | "simd_div" | "simd_rem" => { let &[ref left, ref right] = check_arg_count(args)?; let (left, left_len) = this.operand_to_simd(left)?; let (right, right_len) = this.operand_to_simd(right)?; @@ -320,6 +320,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "simd_sub" => mir::BinOp::Sub, "simd_mul" => mir::BinOp::Mul, "simd_div" => mir::BinOp::Div, + "simd_rem" => mir::BinOp::Rem, _ => unreachable!(), }; diff --git a/tests/compile-fail/intrinsics/div-by-zero-1.rs b/tests/compile-fail/intrinsics/div-by-zero.rs similarity index 100% rename from tests/compile-fail/intrinsics/div-by-zero-1.rs rename to tests/compile-fail/intrinsics/div-by-zero.rs diff --git a/tests/compile-fail/intrinsics/div-by-zero-2.rs b/tests/compile-fail/intrinsics/rem-by-zero.rs similarity index 100% rename from tests/compile-fail/intrinsics/div-by-zero-2.rs rename to tests/compile-fail/intrinsics/rem-by-zero.rs diff --git a/tests/compile-fail/intrinsics/simd-div-by-zero.rs b/tests/compile-fail/intrinsics/simd-div-by-zero.rs new file mode 100644 index 000000000000..4244e63d23e5 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-div-by-zero.rs @@ -0,0 +1,15 @@ +#![feature(platform_intrinsics, repr_simd)] + +extern "platform-intrinsic" { + pub(crate) fn simd_div(x: T, y: T) -> T; +} + +#[repr(simd)] +#[allow(non_camel_case_types)] +struct i32x2(i32, i32); + +fn main() { unsafe { + let x = i32x2(1, 1); + let y = i32x2(1, 0); + simd_div(x, y); //~ERROR Undefined Behavior: dividing by zero +} } diff --git a/tests/compile-fail/intrinsics/simd-rem-by-zero.rs b/tests/compile-fail/intrinsics/simd-rem-by-zero.rs new file mode 100644 index 000000000000..bc3128b5fb5f --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-rem-by-zero.rs @@ -0,0 +1,15 @@ +#![feature(platform_intrinsics, repr_simd)] + +extern "platform-intrinsic" { + pub(crate) fn simd_rem(x: T, y: T) -> T; +} + +#[repr(simd)] +#[allow(non_camel_case_types)] +struct i32x2(i32, i32); + +fn main() { unsafe { + let x = i32x2(1, 1); + let y = i32x2(1, 0); + simd_rem(x, y); //~ERROR Undefined Behavior: calculating the remainder with a divisor of zero +} } diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 42a6befd868b..2d94c87ff042 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -9,6 +9,7 @@ fn simd_ops_f32() { assert_eq!(a * b, f32x4::from_array([10.0, 20.0, 30.0, 40.0])); assert_eq!(b / a, f32x4::from_array([0.1, 0.2, 0.3, 0.4])); assert_eq!(a / 2.0, f32x4::splat(5.0)); + assert_eq!(a % b, f32x4::from_array([0.0, 0.0, 1.0, 2.0])); } fn simd_ops_i32() { @@ -19,6 +20,7 @@ fn simd_ops_i32() { assert_eq!(a * b, i32x4::from_array([10, 20, 30, 40])); assert_eq!(a / b, i32x4::from_array([10, 5, 3, 2])); assert_eq!(a / 2, i32x4::splat(5)); + assert_eq!(a % b, i32x4::from_array([0, 0, 1, 2])); } fn main() { From 4414d963233ab37f2c3941e7b5dde043a77d37f8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 25 Nov 2021 17:24:47 -0500 Subject: [PATCH 2841/5092] implement shl and shr SIMD intrinsics --- src/shims/intrinsics.rs | 25 ++++++++++++++++--- .../intrinsics/simd-shl-too-far.rs | 15 +++++++++++ .../intrinsics/simd-shr-too-far.rs | 15 +++++++++++ tests/run-pass/portable-simd.rs | 2 ++ 4 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 tests/compile-fail/intrinsics/simd-shl-too-far.rs create mode 100644 tests/compile-fail/intrinsics/simd-shr-too-far.rs diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 547f23f620d2..f80062668f3e 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -306,7 +306,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // SIMD operations - "simd_add" | "simd_sub" | "simd_mul" | "simd_div" | "simd_rem" => { + #[rustfmt::skip] + | "simd_add" + | "simd_sub" + | "simd_mul" + | "simd_div" + | "simd_rem" + | "simd_shl" + | "simd_shr" => { let &[ref left, ref right] = check_arg_count(args)?; let (left, left_len) = this.operand_to_simd(left)?; let (right, right_len) = this.operand_to_simd(right)?; @@ -321,14 +328,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "simd_mul" => mir::BinOp::Mul, "simd_div" => mir::BinOp::Div, "simd_rem" => mir::BinOp::Rem, + "simd_shl" => mir::BinOp::Shl, + "simd_shr" => mir::BinOp::Shr, _ => unreachable!(), }; for i in 0..dest_len { let left = this.read_immediate(&this.mplace_index(&left, i)?.into())?; let right = this.read_immediate(&this.mplace_index(&right, i)?.into())?; - let dest = this.mplace_index(&dest, i)?.into(); - this.binop_ignore_overflow(op, &left, &right, &dest)?; + let dest = this.mplace_index(&dest, i)?; + let (val, overflowed, ty) = this.overflowing_binary_op(op, &left, &right)?; + assert_eq!(ty, dest.layout.ty); + if matches!(op, mir::BinOp::Shl | mir::BinOp::Shr) { + // Shifts have extra UB as SIMD operations that the MIR binop does not have. + // See . + if overflowed { + let r_val = right.to_scalar()?.to_bits(right.layout.size)?; + throw_ub_format!("overflowing shift by {} in `{}` in SIMD lane {}", r_val, intrinsic_name, i); + } + } + this.write_scalar(val, &dest.into())?; } } diff --git a/tests/compile-fail/intrinsics/simd-shl-too-far.rs b/tests/compile-fail/intrinsics/simd-shl-too-far.rs new file mode 100644 index 000000000000..b973386f1b5c --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-shl-too-far.rs @@ -0,0 +1,15 @@ +#![feature(platform_intrinsics, repr_simd)] + +extern "platform-intrinsic" { + pub(crate) fn simd_shl(x: T, y: T) -> T; +} + +#[repr(simd)] +#[allow(non_camel_case_types)] +struct i32x2(i32, i32); + +fn main() { unsafe { + let x = i32x2(1, 1); + let y = i32x2(100, 0); + simd_shl(x, y); //~ERROR overflowing shift by 100 in `simd_shl` in SIMD lane 0 +} } diff --git a/tests/compile-fail/intrinsics/simd-shr-too-far.rs b/tests/compile-fail/intrinsics/simd-shr-too-far.rs new file mode 100644 index 000000000000..0b4eb8c11679 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-shr-too-far.rs @@ -0,0 +1,15 @@ +#![feature(platform_intrinsics, repr_simd)] + +extern "platform-intrinsic" { + pub(crate) fn simd_shr(x: T, y: T) -> T; +} + +#[repr(simd)] +#[allow(non_camel_case_types)] +struct i32x2(i32, i32); + +fn main() { unsafe { + let x = i32x2(1, 1); + let y = i32x2(20, 40); + simd_shr(x, y); //~ERROR overflowing shift by 40 in `simd_shr` in SIMD lane 1 +} } diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 2d94c87ff042..5d3337661878 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -21,6 +21,8 @@ fn simd_ops_i32() { assert_eq!(a / b, i32x4::from_array([10, 5, 3, 2])); assert_eq!(a / 2, i32x4::splat(5)); assert_eq!(a % b, i32x4::from_array([0, 0, 1, 2])); + assert_eq!(b << 2, i32x4::from_array([4, 8, 12, 16])); + assert_eq!(b >> 1, i32x4::from_array([0, 1, 1, 2])); } fn main() { From 5d71528e4dc614be312e5f9565bbe67d3292efc7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 25 Nov 2021 17:35:14 -0500 Subject: [PATCH 2842/5092] hack to work around RA quirk --- cargo-miri/miri | 3 +++ miri | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100755 cargo-miri/miri diff --git a/cargo-miri/miri b/cargo-miri/miri new file mode 100755 index 000000000000..ed8c80b33fd0 --- /dev/null +++ b/cargo-miri/miri @@ -0,0 +1,3 @@ +#!/bin/sh +# Hack to work around https://github.com/rust-analyzer/rust-analyzer/issues/10793. +exec "$(dirname "$0")"/../miri "$@" diff --git a/miri b/miri index 337b2a496de8..4be1d5bc78f8 100755 --- a/miri +++ b/miri @@ -39,10 +39,11 @@ EOF TARGET=$(rustc --version --verbose | grep "^host:" | cut -d ' ' -f 2) SYSROOT=$(rustc --print sysroot) LIBDIR=$SYSROOT/lib/rustlib/$TARGET/lib -MIRIDIR=$(dirname "$0") if readlink -e . &>/dev/null; then # This platform supports `readlink -e`. - MIRIDIR=$(readlink -e "$MIRIDIR") + MIRIDIR=$(dirname "$(readlink -e "$0")") +else + MIRIDIR=$(dirname "$0") fi if ! test -d "$LIBDIR"; then echo "Something went wrong determining the library dir." From d800d1e2cbe86540a500d1d1cbea5e4a7a207e53 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Nov 2021 17:15:14 -0500 Subject: [PATCH 2843/5092] rustup; stub support for some extern statics used for weak symbols --- rust-version | 2 +- src/machine.rs | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/rust-version b/rust-version index e7e504a38a7c..0844897398bf 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -5bc98076f37dd8c1476de4bbe0515c55a65332b7 +686e313a9aa14107c8631ffe48fa09110a7692db diff --git a/src/machine.rs b/src/machine.rs index 201854e76fa4..b1998ccccaa4 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -228,18 +228,22 @@ impl MemoryExtra { ) -> InterpResult<'tcx> { match this.tcx.sess.target.os.as_str() { "linux" => { - // "__cxa_thread_atexit_impl" - // This should be all-zero, pointer-sized. - let layout = this.machine.layouts.usize; - let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; - this.write_scalar(Scalar::from_machine_usize(0, this), &place.into())?; - Self::add_extern_static(this, "__cxa_thread_atexit_impl", place.ptr); // "environ" Self::add_extern_static( this, "environ", this.machine.env_vars.environ.unwrap().ptr, ); + // A couple zero-initialized pointer-sized extern statics. + // Most of them are for weak symbols, which we all set to null (indicating that the + // symbol is not supported, and triggering fallback code which ends up calling a + // syscall that we do support). + for name in &["__cxa_thread_atexit_impl", "getrandom", "statx"] { + let layout = this.machine.layouts.usize; + let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; + this.write_scalar(Scalar::from_machine_usize(0, this), &place.into())?; + Self::add_extern_static(this, name, place.ptr); + } } "windows" => { // "_tls_used" From ee666d8987f29a86a8bd37a85aecc9608ba2d2eb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 28 Nov 2021 10:07:31 -0500 Subject: [PATCH 2844/5092] add tests for alignment on array initialization --- rust-version | 2 +- tests/run-pass/async-fn.rs | 13 ++++++++++++ tests/run-pass/issue-miri-1925.rs | 33 +++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 tests/run-pass/issue-miri-1925.rs diff --git a/rust-version b/rust-version index 0844897398bf..cc01c7ccb4a8 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -686e313a9aa14107c8631ffe48fa09110a7692db +58f9efd36de5669ab731ec7ebf565999ff17b159 diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 414d5aaf5cc7..1602b5638e90 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -45,6 +45,18 @@ async fn partial_init(x: u32) -> u32 { let _x: (String, !) = (String::new(), return async { x + x }.await); } +async fn read_exact(_from: &mut &[u8], _to: &mut [u8]) -> Option<()> { + Some(()) +} + +async fn hello_world() { + let data = [0u8; 1]; + let mut reader = &data[..]; + + let mut marker = [0u8; 1]; + read_exact(&mut reader, &mut marker).await.unwrap(); +} + fn run_fut(fut: impl Future) -> T { use std::sync::Arc; use std::task::{Context, Poll, Wake, Waker}; @@ -74,4 +86,5 @@ fn main() { assert_eq!(run_fut(build_aggregate(1, 2, 3, 4)), 10); assert_eq!(run_fut(includes_never(false, 4)), 16); assert_eq!(run_fut(partial_init(4)), 8); + run_fut(hello_world()); } diff --git a/tests/run-pass/issue-miri-1925.rs b/tests/run-pass/issue-miri-1925.rs new file mode 100644 index 000000000000..262889f56eae --- /dev/null +++ b/tests/run-pass/issue-miri-1925.rs @@ -0,0 +1,33 @@ +// compile-flags: -Zmiri-symbolic-alignment-check + +use std::mem::size_of; + +fn main() { + let mut a = Params::new(); + a.key_block = [0; BLOCKBYTES]; +} + +#[repr(C)] +#[derive(Clone)] +#[allow(unused)] +pub struct Params { + hash_length: u8, + key_length: u8, + key_block: [u8; BLOCKBYTES], + max_leaf_length: u32, +} + +pub const OUTBYTES: usize = 8 * size_of::(); +pub const KEYBYTES: usize = 8 * size_of::(); +pub const BLOCKBYTES: usize = 16 * size_of::(); + +impl Params { + pub fn new() -> Self { + Self { + hash_length: OUTBYTES as u8, + key_length: 0, + key_block: [0; BLOCKBYTES], + max_leaf_length: 0, + } + } +} From 70dd979a44c5a2c79400285821f7ac0a06eaee55 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Nov 2021 11:44:19 -0500 Subject: [PATCH 2845/5092] rustup --- rust-version | 2 +- src/shims/intrinsics.rs | 31 ------------------------------- 2 files changed, 1 insertion(+), 32 deletions(-) diff --git a/rust-version b/rust-version index cc01c7ccb4a8..6de6fe762036 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -58f9efd36de5669ab731ec7ebf565999ff17b159 +1c0287830e0fb3c4007afea2819ba03766da6e9c diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index f80062668f3e..39ed5ada0aa9 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -550,37 +550,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_umax_relaxed" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Relaxed)?, - // Query type information - "assert_zero_valid" | "assert_uninit_valid" => { - let &[] = check_arg_count(args)?; - let ty = instance.substs.type_at(0); - let layout = this.layout_of(ty)?; - // Abort here because the caller might not be panic safe. - if layout.abi.is_uninhabited() { - // Use this message even for the other intrinsics, as that's what codegen does - throw_machine_stop!(TerminationInfo::Abort(format!( - "aborted execution: attempted to instantiate uninhabited type `{}`", - ty - ))) - } - if intrinsic_name == "assert_zero_valid" - && !layout.might_permit_raw_init(this, /*zero:*/ true) - { - throw_machine_stop!(TerminationInfo::Abort(format!( - "aborted execution: attempted to zero-initialize type `{}`, which is invalid", - ty - ))) - } - if intrinsic_name == "assert_uninit_valid" - && !layout.might_permit_raw_init(this, /*zero:*/ false) - { - throw_machine_stop!(TerminationInfo::Abort(format!( - "aborted execution: attempted to leave type `{}` uninitialized, which is invalid", - ty - ))) - } - } - // Other "exact_div" => { let &[ref num, ref denom] = check_arg_count(args)?; From b0a463334c866ed479609adce1ee30911bf30cea Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Fri, 3 Dec 2021 15:57:37 -0500 Subject: [PATCH 2846/5092] intptrcast: Never allocate two objects directly adjecent When two objects directly follow each other in memory, what is the provenance of an integer cast to a pointer that points directly between them? For a zero-size region, it could point into the end of the first object, or the start of the second. We can avoid answering this difficult question by simply never allocating two objects directly beside each other. This fixes some of the false positives from #1866. --- src/intptrcast.rs | 9 +++++---- tests/run-pass/adjacent-allocs.rs | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 tests/run-pass/adjacent-allocs.rs diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 665a13418401..91fd26ed75b3 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -1,5 +1,4 @@ use std::cell::RefCell; -use std::cmp::max; use std::collections::hash_map::Entry; use log::trace; @@ -107,9 +106,11 @@ impl<'mir, 'tcx> GlobalState { slack, ); - // Remember next base address. If this allocation is zero-sized, leave a gap - // of at least 1 to avoid two allocations having the same base address. - global_state.next_base_addr = base_addr.checked_add(max(size.bytes(), 1)).unwrap(); + // Remember next base address. Leave a gap of at least 1 to avoid two zero-sized allocations + // having the same base address, and to avoid ambiguous provenance for the address between two + // allocations. + let bytes = size.bytes().checked_add(1).unwrap(); + global_state.next_base_addr = base_addr.checked_add(bytes).unwrap(); // Given that `next_base_addr` increases in each allocation, pushing the // corresponding tuple keeps `int_to_ptr_map` sorted global_state.int_to_ptr_map.push((base_addr, alloc_id)); diff --git a/tests/run-pass/adjacent-allocs.rs b/tests/run-pass/adjacent-allocs.rs new file mode 100644 index 000000000000..812dfcc66c29 --- /dev/null +++ b/tests/run-pass/adjacent-allocs.rs @@ -0,0 +1,21 @@ +fn main() { + // The slack between allocations is random. + // Loop a few times to hit the zero-slack case. + for _ in 0..1024 { + let n = 0u64; + let ptr: *const u64 = &n; + + // Allocate a new stack variable whose lifetime quickly ends. + // If there's a chance that &m == ptr.add(1), then an int-to-ptr cast of + // that value will have ambiguous provenance between n and m. + // See https://github.com/rust-lang/miri/issues/1866#issuecomment-985770125 + { + let m = 0u64; + let _ = &m as *const u64; + } + + let iptr = ptr as usize; + let zst = (iptr + 8) as *const (); + unsafe { *zst } + } +} From d537ed401d323182e178aa496871604c50f4600a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Dec 2021 11:02:20 -0500 Subject: [PATCH 2847/5092] rustup --- rust-version | 2 +- tests/run-pass/concurrency/tls_lib_drop.rs | 1 - tests/run-pass/concurrency/tls_lib_drop_single_thread.rs | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 6de6fe762036..1de7877db7fb 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1c0287830e0fb3c4007afea2819ba03766da6e9c +1597728ef5820d3ffcb9d3f0c890ef7802398751 diff --git a/tests/run-pass/concurrency/tls_lib_drop.rs b/tests/run-pass/concurrency/tls_lib_drop.rs index 00a12599ce99..3220aa43148d 100644 --- a/tests/run-pass/concurrency/tls_lib_drop.rs +++ b/tests/run-pass/concurrency/tls_lib_drop.rs @@ -1,5 +1,4 @@ // ignore-windows: Concurrency on Windows is not supported yet. -#![feature(thread_local_const_init)] use std::cell::RefCell; use std::thread; diff --git a/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs b/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs index 16ca8a0d2eff..c8be1273bd14 100644 --- a/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs +++ b/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs @@ -1,6 +1,5 @@ // compile-flags: -Zmiri-tag-raw-pointers //! Check that destructors of the thread locals are executed on all OSes. -#![feature(thread_local_const_init)] use std::cell::RefCell; From eadeedde425e5a8027cf745da233bf3de58419a9 Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Sun, 5 Dec 2021 13:54:25 +0000 Subject: [PATCH 2848/5092] Handle uninit data in pthread_condattr_destroy --- src/shims/posix/sync.rs | 12 ++++++++++- .../libc_pthread_condattr_double_destroy.rs | 19 ++++++++++++++++++ .../concurrency/pthread_condattr_init.rs | 20 +++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/sync/libc_pthread_condattr_double_destroy.rs create mode 100644 tests/run-pass/concurrency/pthread_condattr_init.rs diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 606f58a207e5..abf52a94e7e7 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -189,6 +189,14 @@ fn condattr_set_clock_id<'mir, 'tcx: 'mir>( ecx.write_scalar_at_offset(attr_op, 0, clock_id, ecx.machine.layouts.i32) } +fn condattr_deinit_clock_id<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + attr_op: &OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ()> { + let layout = layout_of_maybe_uninit(ecx.tcx, ecx.machine.layouts.i32.ty); + ecx.write_scalar_at_offset(attr_op, 0, ScalarMaybeUninit::Uninit, layout) +} + // pthread_cond_t // Our chosen memory layout for the emulated conditional variable (does not have @@ -652,7 +660,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_condattr_destroy(&mut self, attr_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - condattr_set_clock_id(this, attr_op, ScalarMaybeUninit::Uninit)?; + condattr_get_clock_id(this, attr_op)?.check_init()?; + + condattr_deinit_clock_id(this, attr_op)?; Ok(0) } diff --git a/tests/compile-fail/sync/libc_pthread_condattr_double_destroy.rs b/tests/compile-fail/sync/libc_pthread_condattr_double_destroy.rs new file mode 100644 index 000000000000..44af51a3e871 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_condattr_double_destroy.rs @@ -0,0 +1,19 @@ +// ignore-windows: No libc on Windows +#![feature(rustc_private)] + +/// Test that destroying a pthread_condattr twice fails, even without a check for number validity +extern crate libc; + +fn main() { + unsafe { + use core::mem::MaybeUninit; + let mut attr = MaybeUninit::::uninit(); + + libc::pthread_condattr_init(attr.as_mut_ptr()); + + libc::pthread_condattr_destroy(attr.as_mut_ptr()); + + libc::pthread_condattr_destroy(attr.as_mut_ptr()); + //~^ Undefined Behavior: using uninitialized data, but this operation requires initialized memory + } +} diff --git a/tests/run-pass/concurrency/pthread_condattr_init.rs b/tests/run-pass/concurrency/pthread_condattr_init.rs new file mode 100644 index 000000000000..285c6014e2d9 --- /dev/null +++ b/tests/run-pass/concurrency/pthread_condattr_init.rs @@ -0,0 +1,20 @@ +// ignore-windows: No libc on Windows +// compile-flags: -Zmiri-check-number-validity + +#![feature(rustc_private)] + +/// Test that pthread_condattr_destroy doesn't trigger a number validity error. +extern crate libc; + +fn main() { + unsafe { + use core::mem::MaybeUninit; + let mut attr = MaybeUninit::::uninit(); + + let r = libc::pthread_condattr_init(attr.as_mut_ptr()); + assert_eq!(r, 0); + + let r = libc::pthread_condattr_destroy(attr.as_mut_ptr()); + assert_eq!(r, 0); + } +} From 6a98c64c8b684ad12ae1a11fc7ad55a176b45bfe Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Dec 2021 20:33:20 -0500 Subject: [PATCH 2849/5092] final tweaks --- src/intptrcast.rs | 6 +++--- tests/run-pass/adjacent-allocs.rs | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 91fd26ed75b3..6f4169e950a9 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -108,9 +108,9 @@ impl<'mir, 'tcx> GlobalState { // Remember next base address. Leave a gap of at least 1 to avoid two zero-sized allocations // having the same base address, and to avoid ambiguous provenance for the address between two - // allocations. - let bytes = size.bytes().checked_add(1).unwrap(); - global_state.next_base_addr = base_addr.checked_add(bytes).unwrap(); + // allocations (also see https://github.com/rust-lang/unsafe-code-guidelines/issues/313). + let size_plus_1 = size.bytes().checked_add(1).unwrap(); + global_state.next_base_addr = base_addr.checked_add(size_plus_1).unwrap(); // Given that `next_base_addr` increases in each allocation, pushing the // corresponding tuple keeps `int_to_ptr_map` sorted global_state.int_to_ptr_map.push((base_addr, alloc_id)); diff --git a/tests/run-pass/adjacent-allocs.rs b/tests/run-pass/adjacent-allocs.rs index 812dfcc66c29..509965fe4fa9 100644 --- a/tests/run-pass/adjacent-allocs.rs +++ b/tests/run-pass/adjacent-allocs.rs @@ -16,6 +16,7 @@ fn main() { let iptr = ptr as usize; let zst = (iptr + 8) as *const (); + // This is a ZST ptr just at the end of `n`, so it should be valid to deref. unsafe { *zst } } } From ae120563cc4ee0ac2f0b687c6ccc1d2d68c6f892 Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Mon, 6 Dec 2021 19:26:13 +0000 Subject: [PATCH 2850/5092] Destroying any uninit posix_ object is UB --- src/shims/posix/sync.rs | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index abf52a94e7e7..29bca11f831e 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -186,15 +186,12 @@ fn condattr_set_clock_id<'mir, 'tcx: 'mir>( attr_op: &OpTy<'tcx, Tag>, clock_id: impl Into>, ) -> InterpResult<'tcx, ()> { - ecx.write_scalar_at_offset(attr_op, 0, clock_id, ecx.machine.layouts.i32) -} - -fn condattr_deinit_clock_id<'mir, 'tcx: 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, - attr_op: &OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ()> { - let layout = layout_of_maybe_uninit(ecx.tcx, ecx.machine.layouts.i32.ty); - ecx.write_scalar_at_offset(attr_op, 0, ScalarMaybeUninit::Uninit, layout) + ecx.write_scalar_at_offset( + attr_op, + 0, + clock_id, + layout_of_maybe_uninit(ecx.tcx, ecx.machine.layouts.i32.ty), + ) } // pthread_cond_t @@ -367,6 +364,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutexattr_destroy(&mut self, attr_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Destroying an uninit pthread_mutexattr is UB, so check to make sure it's not uninit. + mutexattr_get_kind(this, attr_op)?.check_init()?; + mutexattr_set_kind(this, attr_op, ScalarMaybeUninit::Uninit)?; Ok(0) @@ -505,6 +505,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_ub_format!("destroyed a locked mutex"); } + // Destroying an uninit pthread_mutex is UB, so check to make sure it's not uninit. + mutex_get_kind(this, mutex_op)?.check_init()?; + mutex_get_id(this, mutex_op)?.check_init()?; + mutex_set_kind(this, mutex_op, ScalarMaybeUninit::Uninit)?; mutex_set_id(this, mutex_op, ScalarMaybeUninit::Uninit)?; // FIXME: delete interpreter state associated with this mutex. @@ -606,6 +610,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_ub_format!("destroyed a locked rwlock"); } + // Destroying an uninit pthread_rwlock is UB, so check to make sure it's not uninit. + rwlock_get_id(this, rwlock_op)?.check_init()?; + rwlock_set_id(this, rwlock_op, ScalarMaybeUninit::Uninit)?; // FIXME: delete interpreter state associated with this rwlock. @@ -660,9 +667,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_condattr_destroy(&mut self, attr_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Destroying an uninit pthread_condattr is UB, so check to make sure it's not uninit. condattr_get_clock_id(this, attr_op)?.check_init()?; - condattr_deinit_clock_id(this, attr_op)?; + condattr_set_clock_id(this, attr_op, ScalarMaybeUninit::Uninit)?; Ok(0) } @@ -799,6 +807,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.condvar_is_awaited(id) { throw_ub_format!("destroying an awaited conditional variable"); } + + // Destroying an uninit pthread_cond is UB, so check to make sure it's not uninit. + cond_get_id(this, cond_op)?.check_init()?; + cond_get_clock_id(this, cond_op)?.check_init()?; + cond_set_id(this, cond_op, ScalarMaybeUninit::Uninit)?; cond_set_clock_id(this, cond_op, ScalarMaybeUninit::Uninit)?; // FIXME: delete interpreter state associated with this condvar. From f0d915703ca8130367d6089cb79369f67888c9ad Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Mon, 6 Dec 2021 21:15:02 +0000 Subject: [PATCH 2851/5092] Add tests for double destroying various pthread items --- .../sync/libc_pthread_cond_double_destroy.rs | 22 ++++++++++++++++++ .../sync/libc_pthread_mutex_double_destroy.rs | 23 +++++++++++++++++++ .../libc_pthread_mutexattr_double_destroy.rs | 19 +++++++++++++++ .../libc_pthread_rwlock_double_destroy.rs | 16 +++++++++++++ 4 files changed, 80 insertions(+) create mode 100644 tests/compile-fail/sync/libc_pthread_cond_double_destroy.rs create mode 100644 tests/compile-fail/sync/libc_pthread_mutex_double_destroy.rs create mode 100644 tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.rs create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.rs diff --git a/tests/compile-fail/sync/libc_pthread_cond_double_destroy.rs b/tests/compile-fail/sync/libc_pthread_cond_double_destroy.rs new file mode 100644 index 000000000000..c376618357d2 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_cond_double_destroy.rs @@ -0,0 +1,22 @@ +// ignore-windows: No libc on Windows +#![feature(rustc_private)] + +/// Test that destroying a pthread_cond twice fails, even without a check for number validity +extern crate libc; + +fn main() { + unsafe { + use core::mem::MaybeUninit; + let mut attr = MaybeUninit::::uninit(); + libc::pthread_condattr_init(attr.as_mut_ptr()); + + let mut cond = MaybeUninit::::uninit(); + + libc::pthread_cond_init(cond.as_mut_ptr(), attr.as_ptr()); + + libc::pthread_cond_destroy(cond.as_mut_ptr()); + + libc::pthread_cond_destroy(cond.as_mut_ptr()); + //~^ Undefined Behavior: using uninitialized data, but this operation requires initialized memory + } +} diff --git a/tests/compile-fail/sync/libc_pthread_mutex_double_destroy.rs b/tests/compile-fail/sync/libc_pthread_mutex_double_destroy.rs new file mode 100644 index 000000000000..08abc0ca12c5 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_mutex_double_destroy.rs @@ -0,0 +1,23 @@ +// ignore-windows: No libc on Windows +#![feature(rustc_private)] + +/// Test that destroying a pthread_mutex twice fails, even without a check for number validity +extern crate libc; + +fn main() { + unsafe { + use core::mem::MaybeUninit; + + let mut attr = MaybeUninit::::uninit(); + libc::pthread_mutexattr_init(attr.as_mut_ptr()); + + let mut mutex = MaybeUninit::::uninit(); + + libc::pthread_mutex_init(mutex.as_mut_ptr(), attr.as_ptr()); + + libc::pthread_mutex_destroy(mutex.as_mut_ptr()); + + libc::pthread_mutex_destroy(mutex.as_mut_ptr()); + //~^ Undefined Behavior: using uninitialized data, but this operation requires initialized memory + } +} diff --git a/tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.rs b/tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.rs new file mode 100644 index 000000000000..69ca3ad512fa --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.rs @@ -0,0 +1,19 @@ +// ignore-windows: No libc on Windows +#![feature(rustc_private)] + +/// Test that destroying a pthread_mutexattr twice fails, even without a check for number validity +extern crate libc; + +fn main() { + unsafe { + use core::mem::MaybeUninit; + let mut attr = MaybeUninit::::uninit(); + + libc::pthread_mutexattr_init(attr.as_mut_ptr()); + + libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); + + libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); + //~^ Undefined Behavior: using uninitialized data, but this operation requires initialized memory + } +} diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.rs b/tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.rs new file mode 100644 index 000000000000..d20c78155fd2 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.rs @@ -0,0 +1,16 @@ +// ignore-windows: No libc on Windows +#![feature(rustc_private)] + +/// Test that destroying a pthread_rwlock twice fails, even without a check for number validity +extern crate libc; + +fn main() { + unsafe { + let mut lock = libc::PTHREAD_RWLOCK_INITIALIZER; + + libc::pthread_rwlock_destroy(&mut lock); + + libc::pthread_rwlock_destroy(&mut lock); + //~^ Undefined Behavior: using uninitialized data, but this operation requires initialized memory + } +} From a4b2fc0c5a3acd6ab737aa1f4c29df8dbd621a80 Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Mon, 6 Dec 2021 21:50:14 +0000 Subject: [PATCH 2852/5092] Adjust pthread tests --- .../run-pass/concurrency/libc_pthread_cond.rs | 35 ++++++++++--------- .../concurrency/pthread_condattr_init.rs | 20 ----------- tests/run-pass/concurrency/sync.rs | 7 +++- 3 files changed, 24 insertions(+), 38 deletions(-) delete mode 100644 tests/run-pass/concurrency/pthread_condattr_init.rs diff --git a/tests/run-pass/concurrency/libc_pthread_cond.rs b/tests/run-pass/concurrency/libc_pthread_cond.rs index a545c922db1a..0e09ec9126a5 100644 --- a/tests/run-pass/concurrency/libc_pthread_cond.rs +++ b/tests/run-pass/concurrency/libc_pthread_cond.rs @@ -1,6 +1,6 @@ // ignore-windows: No libc on Windows // ignore-macos: pthread_condattr_setclock is not supported on MacOS. -// compile-flags: -Zmiri-disable-isolation +// compile-flags: -Zmiri-disable-isolation -Zmiri-check-number-validity #![feature(rustc_private)] @@ -8,23 +8,24 @@ /// monotonic and system clocks. extern crate libc; -use std::mem; +use std::mem::MaybeUninit; use std::time::Instant; fn test_timed_wait_timeout(clock_id: i32) { unsafe { - let mut attr: libc::pthread_condattr_t = mem::zeroed(); - assert_eq!(libc::pthread_condattr_init(&mut attr as *mut _), 0); - assert_eq!(libc::pthread_condattr_setclock(&mut attr as *mut _, clock_id), 0); + let mut attr: MaybeUninit = MaybeUninit::uninit(); + assert_eq!(libc::pthread_condattr_init(attr.as_mut_ptr()), 0); + assert_eq!(libc::pthread_condattr_setclock(attr.as_mut_ptr(), clock_id), 0); - let mut cond: libc::pthread_cond_t = mem::zeroed(); - assert_eq!(libc::pthread_cond_init(&mut cond as *mut _, &attr as *const _), 0); - assert_eq!(libc::pthread_condattr_destroy(&mut attr as *mut _), 0); + let mut cond: MaybeUninit = MaybeUninit::uninit(); + assert_eq!(libc::pthread_cond_init(cond.as_mut_ptr(), attr.as_ptr()), 0); + assert_eq!(libc::pthread_condattr_destroy(attr.as_mut_ptr()), 0); - let mut mutex: libc::pthread_mutex_t = mem::zeroed(); + let mut mutex: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER; - let mut now: libc::timespec = mem::zeroed(); - assert_eq!(libc::clock_gettime(clock_id, &mut now), 0); + let mut now_mu: MaybeUninit = MaybeUninit::uninit(); + assert_eq!(libc::clock_gettime(clock_id, now_mu.as_mut_ptr()), 0); + let now = now_mu.assume_init(); // Waiting for a second... mostly because waiting less requires mich more tricky arithmetic. // FIXME: wait less. let timeout = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: now.tv_nsec }; @@ -32,7 +33,7 @@ fn test_timed_wait_timeout(clock_id: i32) { assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); let current_time = Instant::now(); assert_eq!( - libc::pthread_cond_timedwait(&mut cond as *mut _, &mut mutex as *mut _, &timeout), + libc::pthread_cond_timedwait(cond.as_mut_ptr(), &mut mutex as *mut _, &timeout), libc::ETIMEDOUT ); let elapsed_time = current_time.elapsed().as_millis(); @@ -40,7 +41,7 @@ fn test_timed_wait_timeout(clock_id: i32) { // Test calling `pthread_cond_timedwait` again with an already elapsed timeout. assert_eq!( - libc::pthread_cond_timedwait(&mut cond as *mut _, &mut mutex as *mut _, &timeout), + libc::pthread_cond_timedwait(cond.as_mut_ptr(), &mut mutex as *mut _, &timeout), libc::ETIMEDOUT ); @@ -49,7 +50,7 @@ fn test_timed_wait_timeout(clock_id: i32) { let invalid_timeout_1 = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: 1_000_000_000 }; assert_eq!( libc::pthread_cond_timedwait( - &mut cond as *mut _, + cond.as_mut_ptr(), &mut mutex as *mut _, &invalid_timeout_1 ), @@ -58,7 +59,7 @@ fn test_timed_wait_timeout(clock_id: i32) { let invalid_timeout_2 = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: -1 }; assert_eq!( libc::pthread_cond_timedwait( - &mut cond as *mut _, + cond.as_mut_ptr(), &mut mutex as *mut _, &invalid_timeout_2 ), @@ -68,7 +69,7 @@ fn test_timed_wait_timeout(clock_id: i32) { let invalid_timeout_3 = libc::timespec { tv_sec: -1, tv_nsec: 0 }; assert_eq!( libc::pthread_cond_timedwait( - &mut cond as *mut _, + cond.as_mut_ptr(), &mut mutex as *mut _, &invalid_timeout_3 ), @@ -77,7 +78,7 @@ fn test_timed_wait_timeout(clock_id: i32) { assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_cond_destroy(&mut cond as *mut _), 0); + assert_eq!(libc::pthread_cond_destroy(cond.as_mut_ptr()), 0); } } diff --git a/tests/run-pass/concurrency/pthread_condattr_init.rs b/tests/run-pass/concurrency/pthread_condattr_init.rs deleted file mode 100644 index 285c6014e2d9..000000000000 --- a/tests/run-pass/concurrency/pthread_condattr_init.rs +++ /dev/null @@ -1,20 +0,0 @@ -// ignore-windows: No libc on Windows -// compile-flags: -Zmiri-check-number-validity - -#![feature(rustc_private)] - -/// Test that pthread_condattr_destroy doesn't trigger a number validity error. -extern crate libc; - -fn main() { - unsafe { - use core::mem::MaybeUninit; - let mut attr = MaybeUninit::::uninit(); - - let r = libc::pthread_condattr_init(attr.as_mut_ptr()); - assert_eq!(r, 0); - - let r = libc::pthread_condattr_destroy(attr.as_mut_ptr()); - assert_eq!(r, 0); - } -} diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index 88187d64e604..da6f6f25ec1c 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation +// compile-flags: -Zmiri-disable-isolation -Zmiri-check-number-validity use std::sync::mpsc::{channel, sync_channel}; use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock}; @@ -340,6 +340,10 @@ fn park_unpark() { assert!((200..1000).contains(&start.elapsed().as_millis())); } +fn check_condvar() { + let _ = std::sync::Condvar::new(); +} + fn main() { check_barriers(); check_conditional_variables_notify_one(); @@ -357,4 +361,5 @@ fn main() { check_rwlock_unlock_bug2(); park_timeout(); park_unpark(); + check_condvar(); } From 250d450593633dcb40b5ba515b492afbe6d01c99 Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Tue, 7 Dec 2021 08:26:46 +0000 Subject: [PATCH 2853/5092] Add comment explaining false positives in _destroy --- src/shims/posix/sync.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 29bca11f831e..1d0483e49d51 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -367,6 +367,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Destroying an uninit pthread_mutexattr is UB, so check to make sure it's not uninit. mutexattr_get_kind(this, attr_op)?.check_init()?; + // This is technically not right and might lead to false positives. For example, the below + // code is *likely* sound, even assuming uninit numbers are UB, but miri with + // -Zmiri-check-number-validity complains + // + // let mut x: MaybeUninit = MaybeUninit::zeroed(); + // libc::pthread_mutexattr_init(x.as_mut_ptr()); + // libc::pthread_mutexattr_destroy(x.as_mut_ptr()); + // x.assume_init(); + // + // This can always be revisited to have some external state to catch double-destroys + // but not complain about the above code. See https://github.com/rust-lang/miri/pull/1933 + mutexattr_set_kind(this, attr_op, ScalarMaybeUninit::Uninit)?; Ok(0) @@ -509,6 +521,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex_get_kind(this, mutex_op)?.check_init()?; mutex_get_id(this, mutex_op)?.check_init()?; + // This might lead to false positives, see comment in pthread_mutexattr_destroy mutex_set_kind(this, mutex_op, ScalarMaybeUninit::Uninit)?; mutex_set_id(this, mutex_op, ScalarMaybeUninit::Uninit)?; // FIXME: delete interpreter state associated with this mutex. @@ -613,6 +626,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Destroying an uninit pthread_rwlock is UB, so check to make sure it's not uninit. rwlock_get_id(this, rwlock_op)?.check_init()?; + // This might lead to false positives, see comment in pthread_mutexattr_destroy rwlock_set_id(this, rwlock_op, ScalarMaybeUninit::Uninit)?; // FIXME: delete interpreter state associated with this rwlock. @@ -670,6 +684,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Destroying an uninit pthread_condattr is UB, so check to make sure it's not uninit. condattr_get_clock_id(this, attr_op)?.check_init()?; + // This might lead to false positives, see comment in pthread_mutexattr_destroy condattr_set_clock_id(this, attr_op, ScalarMaybeUninit::Uninit)?; Ok(0) @@ -812,6 +827,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx cond_get_id(this, cond_op)?.check_init()?; cond_get_clock_id(this, cond_op)?.check_init()?; + // This might lead to false positives, see comment in pthread_mutexattr_destroy cond_set_id(this, cond_op, ScalarMaybeUninit::Uninit)?; cond_set_clock_id(this, cond_op, ScalarMaybeUninit::Uninit)?; // FIXME: delete interpreter state associated with this condvar. From fd830e7b278063c93c57028b9469875fb36718a6 Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Tue, 7 Dec 2021 17:25:28 +0000 Subject: [PATCH 2854/5092] Code comment changes from code review Co-authored-by: Ralf Jung --- src/shims/posix/sync.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 1d0483e49d51..ea940df1c6e8 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -367,6 +367,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Destroying an uninit pthread_mutexattr is UB, so check to make sure it's not uninit. mutexattr_get_kind(this, attr_op)?.check_init()?; + // To catch double-destroys, we de-initialize the mutexattr. // This is technically not right and might lead to false positives. For example, the below // code is *likely* sound, even assuming uninit numbers are UB, but miri with // -Zmiri-check-number-validity complains @@ -376,6 +377,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // libc::pthread_mutexattr_destroy(x.as_mut_ptr()); // x.assume_init(); // + // However, the way libstd uses the pthread APIs works in our favor here, so we can get away with this. // This can always be revisited to have some external state to catch double-destroys // but not complain about the above code. See https://github.com/rust-lang/miri/pull/1933 From 50b9b701ab7b6775a1f00be24d9298489198e14e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 8 Dec 2021 10:01:51 -0500 Subject: [PATCH 2855/5092] rustup --- rust-version | 2 +- tests/run-pass/portable-simd.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 1de7877db7fb..1f57a0197e0e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1597728ef5820d3ffcb9d3f0c890ef7802398751 +4459e720bee5a741b962cfcd6f0593b32dc19009 diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 5d3337661878..beb0504e0e4f 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -8,7 +8,7 @@ fn simd_ops_f32() { assert_eq!(a - b, f32x4::from_array([9.0, 8.0, 7.0, 6.0])); assert_eq!(a * b, f32x4::from_array([10.0, 20.0, 30.0, 40.0])); assert_eq!(b / a, f32x4::from_array([0.1, 0.2, 0.3, 0.4])); - assert_eq!(a / 2.0, f32x4::splat(5.0)); + assert_eq!(a / f32x4::splat(2.0), f32x4::splat(5.0)); assert_eq!(a % b, f32x4::from_array([0.0, 0.0, 1.0, 2.0])); } @@ -19,10 +19,10 @@ fn simd_ops_i32() { assert_eq!(a - b, i32x4::from_array([9, 8, 7, 6])); assert_eq!(a * b, i32x4::from_array([10, 20, 30, 40])); assert_eq!(a / b, i32x4::from_array([10, 5, 3, 2])); - assert_eq!(a / 2, i32x4::splat(5)); + assert_eq!(a / i32x4::splat(2), i32x4::splat(5)); assert_eq!(a % b, i32x4::from_array([0, 0, 1, 2])); - assert_eq!(b << 2, i32x4::from_array([4, 8, 12, 16])); - assert_eq!(b >> 1, i32x4::from_array([0, 1, 1, 2])); + assert_eq!(b << i32x4::splat(2), i32x4::from_array([4, 8, 12, 16])); + assert_eq!(b >> i32x4::splat(1), i32x4::from_array([0, 1, 1, 2])); } fn main() { From 7670a5657a5deacf35687d690e352605388ef2b9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Dec 2021 18:14:17 +0100 Subject: [PATCH 2856/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 1f57a0197e0e..3f00e3abe914 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4459e720bee5a741b962cfcd6f0593b32dc19009 +404c8471aba60c2d837fa728e7c729a0f52d5830 From 6dcb5389cda597d9ab09d4390c574e3cdb866240 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Dec 2021 18:20:03 +0100 Subject: [PATCH 2857/5092] update lockfile --- Cargo.lock | 132 +++++++++++------------ cargo-miri/Cargo.lock | 239 +++++++++++++++--------------------------- 2 files changed, 150 insertions(+), 221 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 24593d333284..674ce8a2b1ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,18 +4,18 @@ version = 3 [[package]] name = "aho-corasick" -version = "0.7.15" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" dependencies = [ "memchr", ] [[package]] name = "anyhow" -version = "1.0.40" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" +checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203" [[package]] name = "atty" @@ -30,9 +30,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "cfg-if" @@ -53,9 +53,9 @@ dependencies = [ [[package]] name = "compiletest_rs" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64698e5e2435db061a85e6320af12c30c5fd88eb84b35d2c1e03ce4f143255ca" +checksum = "29843cb8d351febf86557681d049d1e1652b81a086a190fa1173c07fd17fbf83" dependencies = [ "diff", "filetime", @@ -116,9 +116,9 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8" +checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" dependencies = [ "cfg-if", "libc", @@ -137,9 +137,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ "cfg-if", "libc", @@ -148,9 +148,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] @@ -169,18 +169,18 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "instant" -version = "0.1.9" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ "cfg-if", ] [[package]] name = "itoa" -version = "0.4.7" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" [[package]] name = "lazy_static" @@ -190,15 +190,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.92" +version = "0.2.112" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714" +checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" [[package]] name = "lock_api" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3c91c24eae6777794bb1997ad98bbb87daf92890acab859f7eaa4320333176" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" dependencies = [ "scopeguard", ] @@ -228,15 +228,15 @@ dependencies = [ [[package]] name = "memchr" -version = "2.3.4" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "memmap2" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397d1a6d6d0563c0f5462bbdae662cf6c784edf5e828e40c7257f85d82bf56dd" +checksum = "723e3ebdcdc5c023db1df315364573789f8857c11b631a2fdfad7c00f5c046b4" dependencies = [ "libc", ] @@ -281,9 +281,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", @@ -292,9 +292,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" dependencies = [ "cfg-if", "instant", @@ -315,33 +315,33 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.10" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" [[package]] name = "proc-macro2" -version = "1.0.26" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" +checksum = "fb37d2df5df740e582f28f8560cf425f52bb267d872fe58358eadb554909f07a" dependencies = [ "unicode-xid", ] [[package]] name = "quote" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" dependencies = [ "proc-macro2", ] [[package]] name = "rand" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ "libc", "rand_chacha", @@ -351,9 +351,9 @@ dependencies = [ [[package]] name = "rand_chacha" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", "rand_core", @@ -361,27 +361,27 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ "getrandom", ] [[package]] name = "rand_hc" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" dependencies = [ "rand_core", ] [[package]] name = "redox_syscall" -version = "0.2.5" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ "bitflags", ] @@ -398,9 +398,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.4.5" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" dependencies = [ "aho-corasick", "memchr", @@ -409,9 +409,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.23" +version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "remove_dir_all" @@ -457,15 +457,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb5d2a036dc6d2d8fd16fde3498b04306e29bd193bf306a57427019b823d5acd" +checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" [[package]] name = "ryu" -version = "1.0.5" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" [[package]] name = "scopeguard" @@ -481,18 +481,18 @@ checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" [[package]] name = "serde" -version = "1.0.125" +version = "1.0.131" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" +checksum = "b4ad69dfbd3e45369132cc64e6748c2d65cdfb001a2b1c232d128b4ad60561c1" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.125" +version = "1.0.131" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" +checksum = "b710a83c4e0dff6a3d511946b95274ad9ca9e5d3ae497b63fda866ac955358d2" dependencies = [ "proc-macro2", "quote", @@ -501,9 +501,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.64" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" +checksum = "bcbd0344bc6533bc7ec56df11d42fb70f1b912351c0825ccb7211b59d8af7cf5" dependencies = [ "itoa", "ryu", @@ -524,9 +524,9 @@ checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" [[package]] name = "syn" -version = "1.0.68" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87" +checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" dependencies = [ "proc-macro2", "quote", @@ -582,15 +582,15 @@ dependencies = [ [[package]] name = "unicode-width" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "unicode-xid" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "wasi" diff --git a/cargo-miri/Cargo.lock b/cargo-miri/Cargo.lock index cf536ecbb20f..c6a7f8b9c13f 100644 --- a/cargo-miri/Cargo.lock +++ b/cargo-miri/Cargo.lock @@ -4,21 +4,9 @@ version = 3 [[package]] name = "anyhow" -version = "1.0.40" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" - -[[package]] -name = "arrayref" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" - -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203" [[package]] name = "autocfg" @@ -26,28 +14,11 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" -[[package]] -name = "base64" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" - [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" - -[[package]] -name = "blake2b_simd" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" -dependencies = [ - "arrayref", - "arrayvec", - "constant_time_eq", -] +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "cargo-miri" @@ -63,9 +34,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.67" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" +checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" dependencies = [ "jobserver", ] @@ -89,37 +60,20 @@ dependencies = [ "winapi", ] -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "crossbeam-utils" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" -dependencies = [ - "autocfg", - "cfg-if", - "lazy_static", -] - [[package]] name = "directories" -version = "3.0.1" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8fed639d60b58d0f53498ab13d26f621fd77569cc6edb031f4cc36a2ad9da0f" +checksum = "e69600ff1703123957937708eb27f7a564e48885c537782722ed0ba3189ce1d7" dependencies = [ "dirs-sys", ] [[package]] name = "dirs-sys" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a" +checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" dependencies = [ "libc", "redox_users", @@ -128,18 +82,18 @@ dependencies = [ [[package]] name = "enum-iterator" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c79a6321a1197d7730510c7e3f6cb80432dfefecb32426de8cea0aa19b4bb8d7" +checksum = "4eeac5c5edb79e4e39fe8439ef35207780a11f69c52cbe424ce3dfad4cb78de6" dependencies = [ "enum-iterator-derive", ] [[package]] name = "enum-iterator-derive" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e94aa31f7c0dc764f57896dc615ddd76fc13b0d5dca7eb6cc5e018a5a09ec06" +checksum = "c134c37760b27a871ba422106eedbb8247da973a09e82558bf26d619c882b159" dependencies = [ "proc-macro2", "quote", @@ -158,20 +112,20 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.16" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ "cfg-if", "libc", - "wasi 0.9.0+wasi-snapshot-preview1", + "wasi", ] [[package]] name = "getset" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b328c01a4d71d2d8173daa93562a73ab0fe85616876f02500f53d82948c504" +checksum = "e45727250e75cc04ff2846a66397da8ef2b3db8e40e0cef4df67950a07621eb9" dependencies = [ "proc-macro-error", "proc-macro2", @@ -181,9 +135,9 @@ dependencies = [ [[package]] name = "git2" -version = "0.13.17" +version = "0.13.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d250f5f82326884bd39c2853577e70a121775db76818ffa452ed1e80de12986" +checksum = "f29229cc1b24c0e6062f6e742aa3e256492a5323365e5ed3413599f8a5eff7d6" dependencies = [ "bitflags", "libc", @@ -194,9 +148,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89829a5d69c23d348314a7ac337fe39173b61149a9864deabd260983aed48c21" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" dependencies = [ "matches", "unicode-bidi", @@ -205,36 +159,30 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.7" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" [[package]] name = "jobserver" -version = "0.1.21" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c71313ebb9439f74b00d9d2dcec36440beaf57a6aa0623068441dd7cd81a7f2" +checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" dependencies = [ "libc", ] -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - [[package]] name = "libc" -version = "0.2.92" +version = "0.2.112" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714" +checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" [[package]] name = "libgit2-sys" -version = "0.12.18+1.1.0" +version = "0.12.26+1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da6a42da88fc37ee1ecda212ffa254c25713532980005d5f7c0b0fbe7e6e885" +checksum = "19e1c899248e606fbfe68dcb31d8b0176ebab833b103824af31bddf4b7457494" dependencies = [ "cc", "libc", @@ -244,9 +192,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "602113192b08db8f38796c4e85c39e960c145965140e918018bcde1952429655" +checksum = "de5435b8549c16d423ed0c03dbaafe57cf6c3344744f1242520d59c9d8ecec66" dependencies = [ "cc", "libc", @@ -265,9 +213,9 @@ dependencies = [ [[package]] name = "matches" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "num-integer" @@ -305,9 +253,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.19" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" +checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" [[package]] name = "proc-macro-error" @@ -335,49 +283,39 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.26" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" +checksum = "fb37d2df5df740e582f28f8560cf425f52bb267d872fe58358eadb554909f07a" dependencies = [ "unicode-xid", ] [[package]] name = "quote" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" -version = "0.1.57" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" - -[[package]] -name = "redox_users" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ - "getrandom", - "redox_syscall", - "rust-argon2", + "bitflags", ] [[package]] -name = "rust-argon2" -version = "0.8.3" +name = "redox_users" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ - "base64", - "blake2b_simd", - "constant_time_eq", - "crossbeam-utils", + "getrandom", + "redox_syscall", ] [[package]] @@ -397,15 +335,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb5d2a036dc6d2d8fd16fde3498b04306e29bd193bf306a57427019b823d5acd" +checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" [[package]] name = "ryu" -version = "1.0.5" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" [[package]] name = "semver" @@ -427,18 +365,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.125" +version = "1.0.131" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" +checksum = "b4ad69dfbd3e45369132cc64e6748c2d65cdfb001a2b1c232d128b4ad60561c1" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.125" +version = "1.0.131" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" +checksum = "b710a83c4e0dff6a3d511946b95274ad9ca9e5d3ae497b63fda866ac955358d2" dependencies = [ "proc-macro2", "quote", @@ -447,9 +385,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.64" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" +checksum = "bcbd0344bc6533bc7ec56df11d42fb70f1b912351c0825ccb7211b59d8af7cf5" dependencies = [ "itoa", "ryu", @@ -458,9 +396,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.68" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87" +checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" dependencies = [ "proc-macro2", "quote", @@ -469,18 +407,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.24" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.24" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" dependencies = [ "proc-macro2", "quote", @@ -489,20 +427,19 @@ dependencies = [ [[package]] name = "time" -version = "0.1.44" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" dependencies = [ "libc", - "wasi 0.10.0+wasi-snapshot-preview1", "winapi", ] [[package]] name = "tinyvec" -version = "1.1.1" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317cca572a0e89c3ce0ca1f1bdc9369547fe318a683418e42ac8f59d14701023" +checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" dependencies = [ "tinyvec_macros", ] @@ -521,33 +458,30 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" [[package]] name = "unicode-bidi" -version = "0.3.4" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -dependencies = [ - "matches", -] +checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" [[package]] name = "unicode-normalization" -version = "0.1.17" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" dependencies = [ "tinyvec", ] [[package]] name = "unicode-xid" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "url" -version = "2.2.1" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" dependencies = [ "form_urlencoded", "idna", @@ -557,17 +491,18 @@ dependencies = [ [[package]] name = "vcpkg" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "vergen" -version = "5.1.0" +version = "5.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbc87f9a7a9d61b15d51d1d3547284f67b6b4f1494ce3fc5814c101f35a5183" +checksum = "6cf88d94e969e7956d924ba70741316796177fa0c79a2c9f4ab04998d96e966e" dependencies = [ "anyhow", + "cfg-if", "chrono", "enum-iterator", "getset", @@ -584,15 +519,9 @@ checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" [[package]] name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" +version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "winapi" From 44cad75069fd3b8f2945d57c478b4e567da73440 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 Dec 2021 16:51:40 +0100 Subject: [PATCH 2858/5092] fix iteration-order-dependent output --- src/shims/foreign_items.rs | 29 ++++++++++++++----- .../exported_symbol_clashing.rs | 4 +-- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 18f1673235c6..4ec422cf1f86 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -173,14 +173,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx continue; }; if symbol_name == link_name { - if let Some((instance, original_cnum)) = instance_and_crate { - throw_machine_stop!(TerminationInfo::MultipleSymbolDefinitions { - link_name, - first: tcx.def_span(instance.def_id()).data(), - first_crate: tcx.crate_name(original_cnum), - second: tcx.def_span(def_id).data(), - second_crate: tcx.crate_name(cnum), - }); + if let Some((original_instance, original_cnum)) = instance_and_crate { + // Make sure we are consistent wrt what is 'first' and 'second'. + let original_span = tcx.def_span(original_instance.def_id()).data(); + let span = tcx.def_span(def_id).data(); + if original_span < span { + throw_machine_stop!(TerminationInfo::MultipleSymbolDefinitions { + link_name, + first: original_span, + first_crate: tcx.crate_name(original_cnum), + second: span, + second_crate: tcx.crate_name(cnum), + }); + } else { + throw_machine_stop!(TerminationInfo::MultipleSymbolDefinitions { + link_name, + first: span, + first_crate: tcx.crate_name(cnum), + second: original_span, + second_crate: tcx.crate_name(original_cnum), + }); + } } if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) { throw_ub_format!( diff --git a/tests/compile-fail/function_calls/exported_symbol_clashing.rs b/tests/compile-fail/function_calls/exported_symbol_clashing.rs index 105d98fc10a9..0e64778d8909 100644 --- a/tests/compile-fail/function_calls/exported_symbol_clashing.rs +++ b/tests/compile-fail/function_calls/exported_symbol_clashing.rs @@ -1,10 +1,10 @@ #[no_mangle] fn foo() {} -//~^ HELP then it's defined here again, in crate `exported_symbol_clashing` +//~^ HELP it's first defined here, in crate `exported_symbol_clashing` #[export_name = "foo"] fn bar() {} -//~^ HELP it's first defined here, in crate `exported_symbol_clashing` +//~^ HELP then it's defined here again, in crate `exported_symbol_clashing` fn main() { extern "Rust" { From d8f7b831e72a421ffb60c60cb318342d4c409b62 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 Dec 2021 18:41:41 +0100 Subject: [PATCH 2859/5092] add regression test --- rust-version | 2 +- src/shims/foreign_items.rs | 2 +- tests/run-pass/issue-91636.rs | 20 ++++++++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 tests/run-pass/issue-91636.rs diff --git a/rust-version b/rust-version index 3f00e3abe914..b517ff5b95ca 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -404c8471aba60c2d837fa728e7c729a0f52d5830 +c5ecc157043ba413568b09292001a4a74b541a4e diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 4ec422cf1f86..42d7958b260f 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -176,7 +176,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some((original_instance, original_cnum)) = instance_and_crate { // Make sure we are consistent wrt what is 'first' and 'second'. let original_span = tcx.def_span(original_instance.def_id()).data(); - let span = tcx.def_span(def_id).data(); + let span = tcx.def_span(def_id).data(); if original_span < span { throw_machine_stop!(TerminationInfo::MultipleSymbolDefinitions { link_name, diff --git a/tests/run-pass/issue-91636.rs b/tests/run-pass/issue-91636.rs new file mode 100644 index 000000000000..21000bb68d2b --- /dev/null +++ b/tests/run-pass/issue-91636.rs @@ -0,0 +1,20 @@ +type BuiltIn = for<'a> fn(&str); + +struct Function { + inner: BuiltIn, +} + +impl Function { + fn new(subr: BuiltIn) -> Self { + Self { inner: subr } + } +} + +fn dummy(_: &str) {} + +fn main() { + let func1 = Function::new(dummy); + let func2 = Function::new(dummy); + let inner: fn(&'static _) -> _ = func1.inner; + assert!(inner == func2.inner); +} From 4da38299fa9e6483642bce23204ca0445a0fc086 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 Dec 2021 18:58:28 +0100 Subject: [PATCH 2860/5092] looks like the asm macro is stable :D --- test-cargo-miri/build.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test-cargo-miri/build.rs b/test-cargo-miri/build.rs index 31d251bc6789..72a4ee0de30b 100644 --- a/test-cargo-miri/build.rs +++ b/test-cargo-miri/build.rs @@ -1,5 +1,3 @@ -#![feature(asm)] - use std::env; #[cfg(miri)] @@ -9,7 +7,7 @@ fn not_in_miri() -> i32 { // Inline assembly definitely does not work in Miri. let mut dummy = 42; unsafe { - asm!("/* {} */", in(reg) &mut dummy); + std::arch::asm!("/* {} */", in(reg) &mut dummy); } return dummy; } From b44f7ea079270e675e487dd723201027ac37de55 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 16 Dec 2021 15:20:58 +0100 Subject: [PATCH 2861/5092] require xargo 0.3.23 --- cargo-miri/bin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 9ac1a7086b82..183ce25b3555 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -12,7 +12,7 @@ use serde::{Deserialize, Serialize}; use rustc_version::VersionMeta; -const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 22); +const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 23); const CARGO_MIRI_HELP: &str = r#"Runs binary crates and tests in Miri From db74c1c030ba913e15b0c8bb86c50dc794f647b2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 19 Dec 2021 17:46:17 +0100 Subject: [PATCH 2862/5092] readme: be more explicit about the toolchain --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 487f8aeb2baf..76764f8b0773 100644 --- a/README.md +++ b/README.md @@ -81,8 +81,11 @@ rustup +nightly component add miri If `rustup` says the `miri` component is unavailable, that's because not all nightly releases come with all tools. Check out [this website](https://rust-lang.github.io/rustup-components-history) to -determine a nightly version that comes with Miri and install that using -`rustup toolchain install nightly-YYYY-MM-DD`. +determine a nightly version that comes with Miri and install that using `rustup +toolchain install nightly-YYYY-MM-DD`. Either way, all of the following commands +assume the right toolchain is pinned via `rustup override set nightly` or +`rustup override set nightly-YYYY-MM-DD`. (Alternatively, use `cargo ++nightly`/`cargo +nightly-YYYY-MM-DD` for each of the following commands.) Now you can run your project in Miri: From c0f1670e47ac00c08afcf953cdf3060554b231ed Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 19 Dec 2021 19:49:05 +0100 Subject: [PATCH 2863/5092] rustup --- rust-version | 2 +- src/shims/intrinsics.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index b517ff5b95ca..dc73dadf90b7 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c5ecc157043ba413568b09292001a4a74b541a4e +41c3017c82bbc16842cc3bc1afa904e6910e293c diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 39ed5ada0aa9..c2978ae34b35 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -32,7 +32,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // All supported intrinsics have a return place. - let intrinsic_name = &*this.tcx.item_name(instance.def_id()).as_str(); + let intrinsic_name = this.tcx.item_name(instance.def_id()); + let intrinsic_name = intrinsic_name.as_str(); let (dest, ret) = match ret { None => throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name), Some(p) => p, From a9dd9b9571c5ef88632f84d239872da9509f8aba Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 20 Dec 2021 23:14:17 +0100 Subject: [PATCH 2864/5092] macOS-compatible realpath --- miri | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/miri b/miri index 4be1d5bc78f8..0ba7e536abe5 100755 --- a/miri +++ b/miri @@ -39,12 +39,8 @@ EOF TARGET=$(rustc --version --verbose | grep "^host:" | cut -d ' ' -f 2) SYSROOT=$(rustc --print sysroot) LIBDIR=$SYSROOT/lib/rustlib/$TARGET/lib -if readlink -e . &>/dev/null; then - # This platform supports `readlink -e`. - MIRIDIR=$(dirname "$(readlink -e "$0")") -else - MIRIDIR=$(dirname "$0") -fi +# macOS does not have a useful readlink/realpath so we have to use Python instead... +MIRIDIR=$(dirname "$(python -c 'import os, sys; print(os.path.realpath(sys.argv[1]))' "$0")") if ! test -d "$LIBDIR"; then echo "Something went wrong determining the library dir." echo "I got $LIBDIR but that does not exist." From cd6921923c107781abd815f3e5ed6f9540a3ab73 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 19 Dec 2021 18:45:56 -0500 Subject: [PATCH 2865/5092] Provide better notes when tracking a pointer tag --- src/diagnostics.rs | 20 ++++++++++++++++++-- src/stacked_borrows.rs | 19 +++++++++++++------ 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 0d91f5246151..a28418e74905 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -7,6 +7,7 @@ use log::trace; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{source_map::DUMMY_SP, Span, SpanData, Symbol}; +use crate::stacked_borrows::{AccessKind, SbTag}; use crate::*; /// Details of premature program termination. @@ -58,7 +59,9 @@ impl MachineStopType for TerminationInfo {} /// Miri specific diagnostics pub enum NonHaltingDiagnostic { CreatedPointerTag(NonZeroU64), - PoppedPointerTag(Item), + /// This `Item` was popped from the borrow stack, either due to a grant of + /// `AccessKind` to `SbTag` or a deallocation when the second argument is `None`. + PoppedPointerTag(Item, Option<(SbTag, AccessKind)>), CreatedCallId(CallId), CreatedAlloc(AllocId), FreedAlloc(AllocId), @@ -321,7 +324,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx use NonHaltingDiagnostic::*; let msg = match e { CreatedPointerTag(tag) => format!("created tag {:?}", tag), - PoppedPointerTag(item) => format!("popped tracked tag for item {:?}", item), + PoppedPointerTag(item, tag) => + match tag { + None => + format!( + "popped tracked tag for item {:?} due to deallocation", + item + ), + Some((tag, access)) => { + format!( + "popped tracked tag for item {:?} due to {:?} access for {:?}", + item, access, tag + ) + } + }, CreatedCallId(id) => format!("function call with id {}", id), CreatedAlloc(AllocId(id)) => format!("created allocation with id {}", id), FreedAlloc(AllocId(id)) => format!("freed allocation with id {}", id), diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 57c09ea40b68..2919ce919aa4 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -111,7 +111,7 @@ pub struct GlobalState { pub type MemoryExtra = RefCell; /// Indicates which kind of access is being performed. -#[derive(Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] pub enum AccessKind { Read, Write, @@ -296,19 +296,26 @@ impl<'tcx> Stack { } /// Check if the given item is protected. + /// + /// The `provoking_access` argument is only used to produce diagnostics. + /// It is `Some` when we are granting the contained access for said tag, and it is + /// `None` during a deallocation. fn check_protector( item: &Item, - tag: Option, + provoking_access: Option<(SbTag, AccessKind)>, global: &GlobalState, ) -> InterpResult<'tcx> { if let SbTag::Tagged(id) = item.tag { if Some(id) == global.tracked_pointer_tag { - register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag(item.clone())); + register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag( + item.clone(), + provoking_access, + )); } } if let Some(call) = item.protector { if global.is_active(call) { - if let Some(tag) = tag { + if let Some((tag, _)) = provoking_access { Err(err_sb_ub(format!( "not granting access to tag {:?} because incompatible item is protected: {:?}", tag, item @@ -348,7 +355,7 @@ impl<'tcx> Stack { let first_incompatible_idx = self.find_first_write_incompatible(granting_idx); for item in self.borrows.drain(first_incompatible_idx..).rev() { trace!("access: popping item {:?}", item); - Stack::check_protector(&item, Some(tag), global)?; + Stack::check_protector(&item, Some((tag, access)), global)?; } } else { // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses. @@ -363,7 +370,7 @@ impl<'tcx> Stack { let item = &mut self.borrows[idx]; if item.perm == Permission::Unique { trace!("access: disabling item {:?}", item); - Stack::check_protector(item, Some(tag), global)?; + Stack::check_protector(item, Some((tag, access)), global)?; item.perm = Permission::Disabled; } } From e51810df2c11e2a58de77d4b304f78d93851fca9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 Dec 2021 15:57:39 +0100 Subject: [PATCH 2866/5092] add and document MIRI_LIB_SRC env var to set the source from which Miri builds the standard library --- CONTRIBUTING.md | 10 ++++++++++ README.md | 6 ++++++ cargo-miri/bin.rs | 16 +++++++++++++--- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index caed6e3226d8..359378504343 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -107,6 +107,16 @@ There's a test for the cargo wrapper in the `test-cargo-miri` directory; run `./run-test.py` in there to execute it. Like `./miri test`, this respects the `MIRI_TEST_TARGET` environment variable to execute the test for another target. +### Using a modified standard library + +Miri re-builds the standard library into a custom sysroot, so it is fairly easy +to test Miri against a modified standard library -- you do not even have to +build Miri yourself, the Miri shipped by `rustup` will work. All you have to do +is set the `MIRI_LIB_SRC` environment variable to the `library` folder of a +`rust-lang/rust` repository checkout. Note that changing files in that directory +does not automatically trigger a re-build of the standard library; you have to +clear the Miri build cache manually (on Linux, `rm -rf ~/.cache/miri`). + ## Configuring `rust-analyzer` To configure `rust-analyzer` and VS Code for working on Miri, save the following diff --git a/README.md b/README.md index 76764f8b0773..fb9a55669903 100644 --- a/README.md +++ b/README.md @@ -306,6 +306,12 @@ Moreover, Miri recognizes some environment variables: Miri executions, also [see "Testing the Miri driver" in `CONTRIBUTING.md`][testing-miri]. * `MIRIFLAGS` (recognized by `cargo miri` and the test suite) defines extra flags to be passed to Miri. +* `MIRI_LIB_SRC` defines the directory where Miri expects the sources of the + standard library that it will build and use for interpretation. This directory + must point to the `library` subdirectory of a `rust-lang/rust` repository + checkout. Note that changing files in that directory does not automatically + trigger a re-build of the standard library; you have to clear the Miri build + cache manually (on Linux, `rm -rf ~/.cache/miri`). * `MIRI_SYSROOT` (recognized by `cargo miri` and the test suite) indicates the sysroot to use. To do the same thing with `miri` directly, use the `--sysroot` flag. diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 183ce25b3555..a946f7988833 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -1,5 +1,5 @@ use std::env; -use std::ffi::OsString; +use std::ffi::{OsStr, OsString}; use std::fmt::Write as _; use std::fs::{self, File}; use std::io::{self, BufRead, BufReader, BufWriter, Read, Write}; @@ -341,8 +341,11 @@ fn setup(subcommand: MiriCommand) { ask_to_run(cmd, ask_user, "install a recent enough xargo"); } - // Determine where the rust sources are located. `XARGO_RUST_SRC` env var trumps everything. - let rust_src = match std::env::var_os("XARGO_RUST_SRC") { + // Determine where the rust sources are located. The env vars manually setting the source + // (`MIRI_LIB_SRC`, `XARGO_RUST_SRC`) trump auto-detection. + let rust_src_env_var = + std::env::var_os("MIRI_LIB_SRC").or_else(|| std::env::var_os("XARGO_RUST_SRC")); + let rust_src = match rust_src_env_var { Some(path) => { let path = PathBuf::from(path); // Make path absolute if possible. @@ -376,6 +379,13 @@ fn setup(subcommand: MiriCommand) { if !rust_src.exists() { show_error(format!("given Rust source directory `{}` does not exist.", rust_src.display())); } + if rust_src.file_name().and_then(OsStr::to_str) != Some("library") { + show_error(format!( + "given Rust source directory `{}` does not seem to be the `library` subdirectory of \ + a Rust source checkout.", + rust_src.display() + )); + } // Next, we need our own libstd. Prepare a xargo project for that purpose. // We will do this work in whatever is a good cache dir for this platform. From a31229797388920eafe18796bf9e2c27cf86c895 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 29 Nov 2021 12:48:04 -0500 Subject: [PATCH 2867/5092] adjust for FnAbi changes --- rust-version | 2 +- src/helpers.rs | 2 +- src/machine.rs | 2 +- src/shims/foreign_items.rs | 156 ++++++++++++++++++++----------------- src/shims/mod.rs | 4 +- 5 files changed, 90 insertions(+), 76 deletions(-) diff --git a/rust-version b/rust-version index dc73dadf90b7..1ff2a14b5baa 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -41c3017c82bbc16842cc3bc1afa904e6910e293c +59337cddd41880f8075b07860a99be4dc402ddb1 diff --git a/src/helpers.rs b/src/helpers.rs index 081712dddc83..0cc6138ca702 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -687,7 +687,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx link_name: Symbol, ) -> InterpResult<'tcx, ()> { self.check_abi(abi, exp_abi)?; - if let Some(body) = self.eval_context_mut().lookup_exported_symbol(link_name)? { + if let Some((body, _)) = self.eval_context_mut().lookup_exported_symbol(link_name)? { throw_machine_stop!(TerminationInfo::SymbolShimClashing { link_name, span: body.span.data(), diff --git a/src/machine.rs b/src/machine.rs index b1998ccccaa4..7cde8a8df681 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -452,7 +452,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { args: &[OpTy<'tcx, Tag>], ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: StackPopUnwind, - ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { + ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { ecx.find_mir_or_eval_fn(instance, abi, args, ret, unwind) } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 42d7958b260f..b07db9535129 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -1,4 +1,5 @@ use std::{ + collections::hash_map::Entry, convert::{TryFrom, TryInto}, iter, }; @@ -34,7 +35,7 @@ pub enum EmulateByNameResult<'mir, 'tcx> { /// Jumping has already been taken care of. AlreadyJumped, /// A MIR body has been found for the function - MirBody(&'mir mir::Body<'tcx>), + MirBody(&'mir mir::Body<'tcx>, ty::Instance<'tcx>), /// The item is not supported. NotSupported, } @@ -135,81 +136,91 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn lookup_exported_symbol( &mut self, link_name: Symbol, - ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { + ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { let this = self.eval_context_mut(); let tcx = this.tcx.tcx; // If the result was cached, just return it. - if let Some(instance) = this.machine.exported_symbols_cache.get(&link_name) { - return instance.map(|instance| this.load_mir(instance.def, None)).transpose(); - } - - // Find it if it was not cached. - let mut instance_and_crate: Option<(ty::Instance<'_>, CrateNum)> = None; - // `dependency_formats` includes all the transitive informations needed to link a crate, - // which is what we need here since we need to dig out `exported_symbols` from all transitive - // dependencies. - let dependency_formats = tcx.dependency_formats(()); - let dependency_format = dependency_formats - .iter() - .find(|(crate_type, _)| *crate_type == CrateType::Executable) - .expect("interpreting a non-executable crate"); - for cnum in - iter::once(LOCAL_CRATE).chain(dependency_format.1.iter().enumerate().filter_map( - |(num, &linkage)| (linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1)), - )) - { - // We can ignore `_export_level` here: we are a Rust crate, and everything is exported - // from a Rust crate. - for &(symbol, _export_level) in tcx.exported_symbols(cnum) { - if let ExportedSymbol::NonGeneric(def_id) = symbol { - let attrs = tcx.codegen_fn_attrs(def_id); - let symbol_name = if let Some(export_name) = attrs.export_name { - export_name - } else if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) { - tcx.item_name(def_id) - } else { - // Skip over items without an explicitly defined symbol name. - continue; - }; - if symbol_name == link_name { - if let Some((original_instance, original_cnum)) = instance_and_crate { - // Make sure we are consistent wrt what is 'first' and 'second'. - let original_span = tcx.def_span(original_instance.def_id()).data(); - let span = tcx.def_span(def_id).data(); - if original_span < span { - throw_machine_stop!(TerminationInfo::MultipleSymbolDefinitions { - link_name, - first: original_span, - first_crate: tcx.crate_name(original_cnum), - second: span, - second_crate: tcx.crate_name(cnum), - }); + // (Cannot use `or_insert` since the code below might have to throw an error.) + let entry = this.machine.exported_symbols_cache.entry(link_name); + let instance = *match entry { + Entry::Occupied(e) => e.into_mut(), + Entry::Vacant(e) => { + // Find it if it was not cached. + let mut instance_and_crate: Option<(ty::Instance<'_>, CrateNum)> = None; + // `dependency_formats` includes all the transitive informations needed to link a crate, + // which is what we need here since we need to dig out `exported_symbols` from all transitive + // dependencies. + let dependency_formats = tcx.dependency_formats(()); + let dependency_format = dependency_formats + .iter() + .find(|(crate_type, _)| *crate_type == CrateType::Executable) + .expect("interpreting a non-executable crate"); + for cnum in iter::once(LOCAL_CRATE).chain( + dependency_format.1.iter().enumerate().filter_map(|(num, &linkage)| { + (linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1)) + }), + ) { + // We can ignore `_export_level` here: we are a Rust crate, and everything is exported + // from a Rust crate. + for &(symbol, _export_level) in tcx.exported_symbols(cnum) { + if let ExportedSymbol::NonGeneric(def_id) = symbol { + let attrs = tcx.codegen_fn_attrs(def_id); + let symbol_name = if let Some(export_name) = attrs.export_name { + export_name + } else if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) { + tcx.item_name(def_id) } else { - throw_machine_stop!(TerminationInfo::MultipleSymbolDefinitions { - link_name, - first: span, - first_crate: tcx.crate_name(cnum), - second: original_span, - second_crate: tcx.crate_name(original_cnum), - }); + // Skip over items without an explicitly defined symbol name. + continue; + }; + if symbol_name == link_name { + if let Some((original_instance, original_cnum)) = instance_and_crate + { + // Make sure we are consistent wrt what is 'first' and 'second'. + let original_span = + tcx.def_span(original_instance.def_id()).data(); + let span = tcx.def_span(def_id).data(); + if original_span < span { + throw_machine_stop!( + TerminationInfo::MultipleSymbolDefinitions { + link_name, + first: original_span, + first_crate: tcx.crate_name(original_cnum), + second: span, + second_crate: tcx.crate_name(cnum), + } + ); + } else { + throw_machine_stop!( + TerminationInfo::MultipleSymbolDefinitions { + link_name, + first: span, + first_crate: tcx.crate_name(cnum), + second: original_span, + second_crate: tcx.crate_name(original_cnum), + } + ); + } + } + if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) { + throw_ub_format!( + "attempt to call an exported symbol that is not defined as a function" + ); + } + instance_and_crate = Some((ty::Instance::mono(tcx, def_id), cnum)); } } - if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) { - throw_ub_format!( - "attempt to call an exported symbol that is not defined as a function" - ); - } - instance_and_crate = Some((ty::Instance::mono(tcx, def_id), cnum)); } } - } - } - let instance = instance_and_crate.map(|ic| ic.0); - // Cache it and load its MIR, if found. - this.machine.exported_symbols_cache.try_insert(link_name, instance).unwrap(); - instance.map(|instance| this.load_mir(instance.def, None)).transpose() + e.insert(instance_and_crate.map(|ic| ic.0)) + } + }; + match instance { + None => Ok(None), // no symbol with this name + Some(instance) => Ok(Some((this.load_mir(instance.def, None)?, instance))), + } } /// Emulates calling a foreign item, failing if the item is not supported. @@ -225,7 +236,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: StackPopUnwind, - ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { + ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); let link_name = this @@ -253,7 +264,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_abi_and_shim_symbol_clash(abi, Abi::Rust, link_name)?; let panic_impl_id = tcx.lang_items().panic_impl().unwrap(); let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id); - return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); + return Ok(Some(( + &*this.load_mir(panic_impl_instance.def, None)?, + panic_impl_instance, + ))); } #[rustfmt::skip] | "exit" @@ -297,7 +311,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.go_to_block(ret); } EmulateByNameResult::AlreadyJumped => (), - EmulateByNameResult::MirBody(mir) => return Ok(Some(mir)), + EmulateByNameResult::MirBody(mir, instance) => return Ok(Some((mir, instance))), EmulateByNameResult::NotSupported => { if let Some(body) = this.lookup_exported_symbol(link_name)? { return Ok(Some(body)); @@ -328,11 +342,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match allocator_kind { AllocatorKind::Global => { - let body = this + let (body, instance) = this .lookup_exported_symbol(symbol)? .expect("symbol should be present if there is a global allocator"); - Ok(EmulateByNameResult::MirBody(body)) + Ok(EmulateByNameResult::MirBody(body, instance)) } AllocatorKind::Default => { default(this)?; diff --git a/src/shims/mod.rs b/src/shims/mod.rs index b05fa76a934f..66f673d241d3 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -30,7 +30,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: StackPopUnwind, - ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { + ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { let this = self.eval_context_mut(); trace!("eval_fn_call: {:#?}, {:?}", instance, ret.map(|p| p.0)); @@ -54,7 +54,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Otherwise, load the MIR. - Ok(Some(&*this.load_mir(instance.def, None)?)) + Ok(Some((&*this.load_mir(instance.def, None)?, instance))) } /// Returns `true` if the computation was performed, and `false` if we should just evaluate From 5ab0ea67f20e723d4d297fe332255a1c1c641a6c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 Dec 2021 21:37:06 -0500 Subject: [PATCH 2868/5092] adjust output for calling convention check --- .../function_calls/exported_symbol_abi_mismatch.rs | 6 +++--- tests/compile-fail/panic/bad_unwind.rs | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.rs b/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.rs index f92fae5d2935..7dbda584e8d4 100644 --- a/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.rs +++ b/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.rs @@ -11,7 +11,7 @@ fn main() { #[cfg(fn_ptr)] unsafe { std::mem::transmute::(foo)() } - //[fn_ptr]~^ ERROR calling a function with ABI Rust using caller ABI C + //[fn_ptr]~^ ERROR calling a function with calling convention Rust using calling convention C // `Instance` caching should not suppress ABI check. #[cfg(cache)] @@ -23,7 +23,7 @@ fn main() { fn foo(); } unsafe { foo() } - //[no_cache]~^ ERROR calling a function with ABI Rust using caller ABI C - //[cache]~^^ ERROR calling a function with ABI Rust using caller ABI C + //[no_cache]~^ ERROR calling a function with calling convention Rust using calling convention C + //[cache]~^^ ERROR calling a function with calling convention Rust using calling convention C } } diff --git a/tests/compile-fail/panic/bad_unwind.rs b/tests/compile-fail/panic/bad_unwind.rs index fde2c19af07d..1feee9a12ae0 100644 --- a/tests/compile-fail/panic/bad_unwind.rs +++ b/tests/compile-fail/panic/bad_unwind.rs @@ -1,9 +1,7 @@ -// error-pattern: calling a function with ABI C-unwind using caller ABI C +// error-pattern: unwinding past a stack frame that does not allow unwinding #![feature(c_unwind)] //! Unwinding when the caller ABI is "C" (without "-unwind") is UB. -//! Currently we detect the ABI mismatch; we could probably allow such calls in principle one day -//! but then we have to detect the unexpected unwinding. extern "C-unwind" fn unwind() { panic!(); From a58d43cf31f445ff2b36e1c762640d7a725ec5bc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 1 Jan 2022 18:52:45 +0100 Subject: [PATCH 2869/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 1ff2a14b5baa..cada8fabde57 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -59337cddd41880f8075b07860a99be4dc402ddb1 +4f49627c6fe2a32d1fed6310466bb0e1c535c0c0 From 77cec811b44ff5931251b5fcaf5594b63dae0afa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 1 Jan 2022 19:01:46 +0100 Subject: [PATCH 2870/5092] exclude mutable references to !Unpin types from uniqueness guarantees --- src/stacked_borrows.rs | 18 ++++++++-- .../generators-self-referential.rs | 34 +++++++++++++++++++ 2 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 tests/run-pass/stacked-borrows/generators-self-referential.rs diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 2919ce919aa4..37ecb749a487 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -9,7 +9,11 @@ use std::num::NonZeroU64; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::Mutability; use rustc_middle::mir::RetagKind; -use rustc_middle::ty::{self, layout::LayoutOf}; +use rustc_middle::ty::{ + self, + layout::{HasParamEnv, LayoutOf}, +}; +use rustc_span::DUMMY_SP; use rustc_target::abi::Size; use crate::*; @@ -657,8 +661,16 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Make sure that raw pointers and mutable shared references are reborrowed "weak": // There could be existing unique pointers reborrowed from them that should remain valid! let perm = match kind { - RefKind::Unique { two_phase: false } => Permission::Unique, - RefKind::Unique { two_phase: true } => Permission::SharedReadWrite, + RefKind::Unique { two_phase: false } + if place.layout.ty.is_unpin(this.tcx.at(DUMMY_SP), this.param_env()) => + { + // Only if the type is unpin do we actually enforce uniqueness + Permission::Unique + } + RefKind::Unique { .. } => { + // Two-phase references and !Unpin references are treated as SharedReadWrite + Permission::SharedReadWrite + } RefKind::Raw { mutable: true } => Permission::SharedReadWrite, RefKind::Shared | RefKind::Raw { mutable: false } => { // Shared references and *const are a whole different kind of game, the diff --git a/tests/run-pass/stacked-borrows/generators-self-referential.rs b/tests/run-pass/stacked-borrows/generators-self-referential.rs new file mode 100644 index 000000000000..01ce8a61418c --- /dev/null +++ b/tests/run-pass/stacked-borrows/generators-self-referential.rs @@ -0,0 +1,34 @@ +// See https://github.com/rust-lang/unsafe-code-guidelines/issues/148: +// this fails when Stacked Borrows is strictly applied even to `!Unpin` types. +#![feature(generators, generator_trait)] + +use std::{ + ops::{Generator, GeneratorState}, + pin::Pin, +}; + +fn firstn() -> impl Generator { + static move || { + let mut num = 0; + let num = &mut num; + + yield *num; + *num += 1; //~ ERROR: borrow stack + + yield *num; + *num += 1; + + yield *num; + *num += 1; + } +} + +fn main() { + let mut generator_iterator = firstn(); + let mut pin = unsafe { Pin::new_unchecked(&mut generator_iterator) }; + let mut sum = 0; + while let GeneratorState::Yielded(x) = pin.as_mut().resume(()) { + sum += x; + } + assert_eq!(sum, 3); +} From 45442c80b8075a67f7e9f3d1e71f62cb160b310c Mon Sep 17 00:00:00 2001 From: klensy Date: Mon, 3 Jan 2022 02:47:42 +0300 Subject: [PATCH 2871/5092] update crate rustc_version 0.3 -> 0.4 to remove some deps --- cargo-miri/Cargo.lock | 35 ++++------------------------------- cargo-miri/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 32 deletions(-) diff --git a/cargo-miri/Cargo.lock b/cargo-miri/Cargo.lock index c6a7f8b9c13f..abb60080b786 100644 --- a/cargo-miri/Cargo.lock +++ b/cargo-miri/Cargo.lock @@ -242,15 +242,6 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" -[[package]] -name = "pest" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" -dependencies = [ - "ucd-trie", -] - [[package]] name = "pkg-config" version = "0.3.24" @@ -326,9 +317,9 @@ checksum = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" [[package]] name = "rustc_version" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ "semver", ] @@ -347,21 +338,9 @@ checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" [[package]] name = "semver" -version = "0.11.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" -dependencies = [ - "pest", -] +checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" [[package]] name = "serde" @@ -450,12 +429,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" -[[package]] -name = "ucd-trie" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" - [[package]] name = "unicode-bidi" version = "0.3.7" diff --git a/cargo-miri/Cargo.toml b/cargo-miri/Cargo.toml index f0ef30eabcf7..15c46569232a 100644 --- a/cargo-miri/Cargo.toml +++ b/cargo-miri/Cargo.toml @@ -15,7 +15,7 @@ doctest = false # and no doc tests [dependencies] directories = "3" -rustc_version = "0.3" +rustc_version = "0.4" serde_json = "1.0.40" # A noop dependency that changes in the Rust repository, it's a bit of a hack. From 808f7941151c7cbb5dc8c84479d3e0fa7fbbba74 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 3 Jan 2022 22:54:58 +0100 Subject: [PATCH 2872/5092] rustup --- rust-version | 2 +- src/machine.rs | 30 ------------------------------ 2 files changed, 1 insertion(+), 31 deletions(-) diff --git a/rust-version b/rust-version index cada8fabde57..cb81868b2aec 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4f49627c6fe2a32d1fed6310466bb0e1c535c0c0 +ddabe0775c5f5b551d5eb54e3c4366fb8bec0c92 diff --git a/src/machine.rs b/src/machine.rs index 7cde8a8df681..3ca07db921a9 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -7,7 +7,6 @@ use std::fmt; use std::num::NonZeroU64; use std::time::Instant; -use log::trace; use rand::rngs::StdRng; use rand::SeedableRng; @@ -503,35 +502,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx.binary_ptr_op(bin_op, left, right) } - fn box_alloc( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - dest: &PlaceTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { - trace!("box_alloc for {:?}", dest.layout.ty); - let layout = ecx.layout_of(dest.layout.ty.builtin_deref(false).unwrap().ty)?; - // First argument: `size`. - // (`0` is allowed here -- this is expected to be handled by the lang item). - let size = Scalar::from_machine_usize(layout.size.bytes(), ecx); - - // Second argument: `align`. - let align = Scalar::from_machine_usize(layout.align.abi.bytes(), ecx); - - // Call the `exchange_malloc` lang item. - let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap(); - let malloc = ty::Instance::mono(ecx.tcx.tcx, malloc); - ecx.call_function( - malloc, - Abi::Rust, - &[size.into(), align.into()], - Some(dest), - // Don't do anything when we are done. The `statement()` function will increment - // the old stack frame's stmt counter to the next statement, which means that when - // `exchange_malloc` returns, we go on evaluating exactly where we want to be. - StackPopCleanup::None { cleanup: true }, - )?; - Ok(()) - } - fn thread_local_static_base_pointer( ecx: &mut InterpCx<'mir, 'tcx, Self>, def_id: DefId, From 81751a2a00f40fb21ab220cc2ab422121be4e79d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 4 Jan 2022 11:14:50 +0100 Subject: [PATCH 2873/5092] adjust for StackPopCleanup::None rename --- src/eval.rs | 4 ++-- src/shims/posix/thread.rs | 2 +- src/shims/tls.rs | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index e3f252b50a92..9cd3a9a56466 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -247,7 +247,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( Abi::Rust, &[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv], Some(&ret_place.into()), - StackPopCleanup::None { cleanup: true }, + StackPopCleanup::Root { cleanup: true }, )?; } EntryFnType::Start => { @@ -256,7 +256,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( Abi::Rust, &[argc.into(), argv], Some(&ret_place.into()), - StackPopCleanup::None { cleanup: true }, + StackPopCleanup::Root { cleanup: true }, )?; } } diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index e64ef3b23c6f..b49817e88511 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -54,7 +54,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Abi::C { unwind: false }, &[*func_arg], Some(&ret_place.into()), - StackPopCleanup::None { cleanup: true }, + StackPopCleanup::Root { cleanup: true }, )?; // Restore the old active thread frame. diff --git a/src/shims/tls.rs b/src/shims/tls.rs index cf8b8e3e1b88..32bea8dde475 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -259,7 +259,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Abi::System { unwind: false }, &[Scalar::null_ptr(this).into(), reason.into(), Scalar::null_ptr(this).into()], Some(&ret_place), - StackPopCleanup::None { cleanup: true }, + StackPopCleanup::Root { cleanup: true }, )?; this.enable_thread(active_thread); @@ -282,7 +282,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Abi::C { unwind: false }, &[data.into()], Some(&ret_place), - StackPopCleanup::None { cleanup: true }, + StackPopCleanup::Root { cleanup: true }, )?; // Enable the thread so that it steps through the destructor which @@ -325,7 +325,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Abi::C { unwind: false }, &[ptr.into()], Some(&ret_place), - StackPopCleanup::None { cleanup: true }, + StackPopCleanup::Root { cleanup: true }, )?; this.enable_thread(active_thread); From 522f40b0867ecc63c39d644e09968c65fb859f55 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 5 Jan 2022 09:55:29 +0100 Subject: [PATCH 2874/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index cb81868b2aec..4c43ab08421a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -ddabe0775c5f5b551d5eb54e3c4366fb8bec0c92 +26c9b0046f96403cdf959e4e1f874ec25f9dbf6f From 9376bf5d4df99d76c7457a159b7ce7d7dfb8f251 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 8 Jan 2022 17:27:48 +0100 Subject: [PATCH 2875/5092] rustup --- rust-version | 2 +- tests/run-pass/available-concurrency.rs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 4c43ab08421a..391c95bfc14c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -26c9b0046f96403cdf959e4e1f874ec25f9dbf6f +66f64a441a05cee8d5d701477b43ed851f778f3a diff --git a/tests/run-pass/available-concurrency.rs b/tests/run-pass/available-concurrency.rs index 422046c62d62..eb4d09b1f549 100644 --- a/tests/run-pass/available-concurrency.rs +++ b/tests/run-pass/available-concurrency.rs @@ -1,5 +1,3 @@ -#![feature(available_parallelism)] - fn main() { assert_eq!(std::thread::available_parallelism().unwrap().get(), 1); } From ee6198fb98f1a2137ef3c0a8040b2e216a0c48fd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Jan 2022 14:50:03 +0100 Subject: [PATCH 2876/5092] rustup --- rust-version | 2 +- src/helpers.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 391c95bfc14c..87b2fe72105a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -66f64a441a05cee8d5d701477b43ed851f778f3a +e19ca1d946269f7b7eb13171531caf2e16f42076 diff --git a/src/helpers.rs b/src/helpers.rs index 0cc6138ca702..0c4e0c4e969e 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -27,7 +27,7 @@ fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option Date: Tue, 11 Jan 2022 16:17:39 +0100 Subject: [PATCH 2877/5092] Remove spurious `maybe_uninit_extra` Signed-off-by: Miguel Ojeda --- tests/run-pass/stacked-borrows/interior_mutability.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/run-pass/stacked-borrows/interior_mutability.rs b/tests/run-pass/stacked-borrows/interior_mutability.rs index 87624e520db1..23d82b8e435b 100644 --- a/tests/run-pass/stacked-borrows/interior_mutability.rs +++ b/tests/run-pass/stacked-borrows/interior_mutability.rs @@ -1,4 +1,3 @@ -#![feature(maybe_uninit_extra)] use std::mem::MaybeUninit; use std::cell::{Cell, RefCell, UnsafeCell}; From 42b144ee8c1ce99ed03972f9658d101059b6dfbc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 26 Jan 2022 10:54:55 -0500 Subject: [PATCH 2878/5092] rustup --- rust-version | 2 +- src/shims/posix/macos/dlsym.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 87b2fe72105a..09474d264038 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e19ca1d946269f7b7eb13171531caf2e16f42076 +a7f375789bab1a4e4a291c963081a8ca7d2b6bd7 diff --git a/src/shims/posix/macos/dlsym.rs b/src/shims/posix/macos/dlsym.rs index d5996cc6a9ed..9994bfd53dc5 100644 --- a/src/shims/posix/macos/dlsym.rs +++ b/src/shims/posix/macos/dlsym.rs @@ -17,6 +17,7 @@ impl Dlsym { pub fn from_str(name: &str) -> InterpResult<'static, Option> { Ok(match name { "getentropy" => Some(Dlsym::getentropy), + "openat" => None, // std has a fallback for this _ => throw_unsup_format!("unsupported macOS dlsym: {}", name), }) } From 3d5eb52cbd7d3f9c036da7e6548865d38d1db1ed Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 4 Feb 2022 17:17:28 +0100 Subject: [PATCH 2879/5092] rustup: disable read_dir test for now --- rust-version | 2 +- tests/run-pass/fs.rs | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 09474d264038..8b9c2e479e35 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a7f375789bab1a4e4a291c963081a8ca7d2b6bd7 +009c1d02484dcc18e1596a33b3d8989a90361c89 diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 1261dbf1768d..568b7ab4e3b7 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -6,7 +6,7 @@ extern crate libc; use std::fs::{ - File, create_dir, OpenOptions, read_dir, remove_dir, remove_dir_all, remove_file, rename, + File, create_dir, OpenOptions, remove_dir, remove_dir_all, remove_file, rename, }; use std::ffi::CString; use std::io::{Read, Write, Error, ErrorKind, Result, Seek, SeekFrom}; @@ -331,17 +331,19 @@ fn test_directory() { let path_2 = dir_path.join("test_file_2"); drop(File::create(&path_2).unwrap()); // Test that the files are present inside the directory + /* FIXME(1966) disabled due to missing readdir support let dir_iter = read_dir(&dir_path).unwrap(); let mut file_names = dir_iter.map(|e| e.unwrap().file_name()).collect::>(); file_names.sort_unstable(); - assert_eq!(file_names, vec!["test_file_1", "test_file_2"]); + assert_eq!(file_names, vec!["test_file_1", "test_file_2"]); */ // Clean up the files in the directory remove_file(&path_1).unwrap(); remove_file(&path_2).unwrap(); // Now there should be nothing left in the directory. - let dir_iter = read_dir(&dir_path).unwrap(); + /* FIXME(1966) disabled due to missing readdir support + dir_iter = read_dir(&dir_path).unwrap(); let file_names = dir_iter.map(|e| e.unwrap().file_name()).collect::>(); - assert!(file_names.is_empty()); + assert!(file_names.is_empty());*/ // Deleting the directory should succeed. remove_dir(&dir_path).unwrap(); From 6b8baee33978eaa526fec909f2de24754089acae Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 4 Feb 2022 17:55:53 +0100 Subject: [PATCH 2880/5092] rustup; implement simd_and/or --- rust-version | 2 +- src/shims/intrinsics.rs | 6 +++++- tests/run-pass/portable-simd.rs | 8 +++++--- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 8b9c2e479e35..5343cde310d4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -009c1d02484dcc18e1596a33b3d8989a90361c89 +4e8fb743ccbec27344b2dd42de7057f41d4ebfdd diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index c2978ae34b35..0dabaaa70069 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -314,7 +314,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "simd_div" | "simd_rem" | "simd_shl" - | "simd_shr" => { + | "simd_shr" + | "simd_and" + | "simd_or" => { let &[ref left, ref right] = check_arg_count(args)?; let (left, left_len) = this.operand_to_simd(left)?; let (right, right_len) = this.operand_to_simd(right)?; @@ -331,6 +333,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "simd_rem" => mir::BinOp::Rem, "simd_shl" => mir::BinOp::Shl, "simd_shr" => mir::BinOp::Shr, + "simd_and" => mir::BinOp::BitAnd, + "simd_or" => mir::BinOp::BitOr, _ => unreachable!(), }; diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index beb0504e0e4f..28999577308b 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -18,11 +18,13 @@ fn simd_ops_i32() { assert_eq!(a + b, i32x4::from_array([11, 12, 13, 14])); assert_eq!(a - b, i32x4::from_array([9, 8, 7, 6])); assert_eq!(a * b, i32x4::from_array([10, 20, 30, 40])); - assert_eq!(a / b, i32x4::from_array([10, 5, 3, 2])); - assert_eq!(a / i32x4::splat(2), i32x4::splat(5)); - assert_eq!(a % b, i32x4::from_array([0, 0, 1, 2])); + //assert_eq!(a / b, i32x4::from_array([10, 5, 3, 2])); + //assert_eq!(a / i32x4::splat(2), i32x4::splat(5)); + //assert_eq!(a % b, i32x4::from_array([0, 0, 1, 2])); assert_eq!(b << i32x4::splat(2), i32x4::from_array([4, 8, 12, 16])); assert_eq!(b >> i32x4::splat(1), i32x4::from_array([0, 1, 1, 2])); + assert_eq!(b & i32x4::splat(2), i32x4::from_array([0, 2, 2, 0])); + assert_eq!(b | i32x4::splat(2), i32x4::from_array([3, 2, 3, 6])); } fn main() { From dfa0a3b3c7fc430f3ab7595d39bd45b712e5dd94 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Feb 2022 11:53:51 +0100 Subject: [PATCH 2881/5092] implement const_allocate intrinsic --- rust-version | 2 +- src/shims/intrinsics.rs | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 5343cde310d4..0c82628c569a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4e8fb743ccbec27344b2dd42de7057f41d4ebfdd +78450d2d602b06d9b94349aaf8cece1a4acaf3a8 diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 0dabaaa70069..d0d35dc45817 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -54,6 +54,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let right = this.read_immediate(right)?; this.binop_ignore_overflow(mir::BinOp::Ne, &left, &right, dest)?; } + "const_allocate" => { + // For now, for compatibility with the run-time implementation of this, we just return null. + // See . + this.write_null(dest)?; + } // Raw memory accesses "volatile_load" => { From ec66d2934be8496ca75c72d6baf0cfaf923632bd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Feb 2022 12:17:37 +0100 Subject: [PATCH 2882/5092] implement const_deallocate as a NOP --- src/shims/intrinsics.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index d0d35dc45817..df41a88aeeb6 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -59,6 +59,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // See . this.write_null(dest)?; } + "const_deallocate" => { + // complete NOP + } // Raw memory accesses "volatile_load" => { From a21c98a896e7a748b361e2d615b0d098a3751939 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 20 Feb 2022 21:41:37 -0500 Subject: [PATCH 2883/5092] another for the trophy case --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index fb9a55669903..3f300db83643 100644 --- a/README.md +++ b/README.md @@ -453,6 +453,7 @@ Definite bugs found: * [`encoding_rs` doing out-of-bounds pointer arithmetic](https://github.com/hsivonen/encoding_rs/pull/53) * [TiKV using `Vec::from_raw_parts` incorrectly](https://github.com/tikv/agatedb/pull/24) * Incorrect doctests for [`AtomicPtr`](https://github.com/rust-lang/rust/pull/84052) and [`Box::from_raw_in`](https://github.com/rust-lang/rust/pull/84053) +* [Insufficient alignment in `ThinVec`](https://github.com/Gankra/thin-vec/pull/27) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From c8fff51825a495a3803b0abf3ab09e31b00345f3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Feb 2022 21:34:05 -0500 Subject: [PATCH 2884/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 0c82628c569a..d64c1095494d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -78450d2d602b06d9b94349aaf8cece1a4acaf3a8 +b8967b0d52a2ba5f0c9da0da03e78ccba5534e4a From 1ac1e55f3b0903f8088d9da77e8da889c97477f6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Feb 2022 21:41:52 -0500 Subject: [PATCH 2885/5092] implement simd_eq and simd_reduce_any --- src/shims/intrinsics.rs | 39 +++++++++++++++++-- .../intrinsics/simd-reduce-invalid-bool.rs | 14 +++++++ tests/run-pass/portable-simd.rs | 27 +++++++++++-- 3 files changed, 73 insertions(+), 7 deletions(-) create mode 100644 tests/compile-fail/intrinsics/simd-reduce-invalid-bool.rs diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index df41a88aeeb6..a75367b82c12 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -324,7 +324,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "simd_shl" | "simd_shr" | "simd_and" - | "simd_or" => { + | "simd_or" + | "simd_eq" => { let &[ref left, ref right] = check_arg_count(args)?; let (left, left_len) = this.operand_to_simd(left)?; let (right, right_len) = this.operand_to_simd(right)?; @@ -343,6 +344,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "simd_shr" => mir::BinOp::Shr, "simd_and" => mir::BinOp::BitAnd, "simd_or" => mir::BinOp::BitOr, + "simd_eq" => mir::BinOp::Eq, _ => unreachable!(), }; @@ -351,7 +353,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let right = this.read_immediate(&this.mplace_index(&right, i)?.into())?; let dest = this.mplace_index(&dest, i)?; let (val, overflowed, ty) = this.overflowing_binary_op(op, &left, &right)?; - assert_eq!(ty, dest.layout.ty); if matches!(op, mir::BinOp::Shl | mir::BinOp::Shr) { // Shifts have extra UB as SIMD operations that the MIR binop does not have. // See . @@ -360,9 +361,41 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_ub_format!("overflowing shift by {} in `{}` in SIMD lane {}", r_val, intrinsic_name, i); } } - this.write_scalar(val, &dest.into())?; + if matches!(op, mir::BinOp::Eq) { + // Special handling for boolean-returning operations + assert_eq!(ty, this.tcx.types.bool); + let val = val.to_bool().unwrap(); + let val = if val { -1 } else { 0 }; // SIMD uses all-1 as pattern for "true" + let val = Scalar::from_int(val, dest.layout.size); + this.write_scalar(val, &dest.into())?; + } else { + assert_eq!(ty, dest.layout.ty); + this.write_scalar(val, &dest.into())?; + } } } + "simd_reduce_any" => { + let &[ref arg] = check_arg_count(args)?; + let (arg, arg_len) = this.operand_to_simd(arg)?; + + let mut res = false; // the neutral element + for i in 0..arg_len { + let op = this.read_immediate(&this.mplace_index(&arg, i)?.into())?; + // We convert it to a *signed* integer and expect either 0 or -1 (the latter means all bits were set). + let val = op.to_scalar()?.to_int(op.layout.size)?; + let val = match val { + 0 => false, + -1 => true, + _ => + throw_ub_format!( + "each element of a simd_reduce_any operand must be all-0-bits or all-1-bits" + ), + }; + res = res | val; + } + + this.write_scalar(Scalar::from_bool(res), dest)?; + } // Atomic operations "atomic_load" => this.atomic_load(args, dest, AtomicReadOp::SeqCst)?, diff --git a/tests/compile-fail/intrinsics/simd-reduce-invalid-bool.rs b/tests/compile-fail/intrinsics/simd-reduce-invalid-bool.rs new file mode 100644 index 000000000000..41dd7d74f4ec --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-reduce-invalid-bool.rs @@ -0,0 +1,14 @@ +#![feature(platform_intrinsics, repr_simd)] + +extern "platform-intrinsic" { + pub(crate) fn simd_reduce_any(x: T) -> bool; +} + +#[repr(simd)] +#[allow(non_camel_case_types)] +struct i32x2(i32, i32); + +fn main() { unsafe { + let x = i32x2(0, 1); + simd_reduce_any(x); //~ERROR must be all-0-bits or all-1-bits +} } diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 28999577308b..17fea5916675 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -1,4 +1,4 @@ -#![feature(portable_simd)] +#![feature(portable_simd, platform_intrinsics)] use std::simd::*; fn simd_ops_f32() { @@ -18,16 +18,35 @@ fn simd_ops_i32() { assert_eq!(a + b, i32x4::from_array([11, 12, 13, 14])); assert_eq!(a - b, i32x4::from_array([9, 8, 7, 6])); assert_eq!(a * b, i32x4::from_array([10, 20, 30, 40])); - //assert_eq!(a / b, i32x4::from_array([10, 5, 3, 2])); - //assert_eq!(a / i32x4::splat(2), i32x4::splat(5)); - //assert_eq!(a % b, i32x4::from_array([0, 0, 1, 2])); + assert_eq!(a / b, i32x4::from_array([10, 5, 3, 2])); + assert_eq!(a / i32x4::splat(2), i32x4::splat(5)); + assert_eq!(a % b, i32x4::from_array([0, 0, 1, 2])); assert_eq!(b << i32x4::splat(2), i32x4::from_array([4, 8, 12, 16])); assert_eq!(b >> i32x4::splat(1), i32x4::from_array([0, 1, 1, 2])); assert_eq!(b & i32x4::splat(2), i32x4::from_array([0, 2, 2, 0])); assert_eq!(b | i32x4::splat(2), i32x4::from_array([3, 2, 3, 6])); } +fn simd_intrinsics() { + extern "platform-intrinsic" { + pub(crate) fn simd_eq(x: T, y: T) -> U; + pub(crate) fn simd_reduce_any(x: T) -> bool; + } + + // Make sure simd_eq returns all-1 for `true` + let a = i32x4::splat(10); + let b = i32x4::from_array([1, 2, 10, 4]); + let c: i32x4 = unsafe { simd_eq(a, b) }; + assert_eq!(c, i32x4::from_array([0, 0, -1, 0])); + + unsafe { + assert!(!simd_reduce_any(i32x4::splat(0))); + assert!(simd_reduce_any(i32x4::splat(-1))); + } +} + fn main() { simd_ops_f32(); simd_ops_i32(); + simd_intrinsics(); } From 19ecd130b5854ea29c50de9bd985f56e00c6718e Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 20 Feb 2022 11:55:39 -0500 Subject: [PATCH 2886/5092] Prune backtraces similar to RUST_BACKTRACE=1 logic Previously, Miri would always print a backtrace including all frames when encountering an error. This adds -Zmiri-backtrace which defaults to 1, internally called BacktraceStyle::Short. By default, backtraces are pruned to start at __rust_begin_short_backtrace, similar to std. Then we also remove non-local frames from the bottom of the trace. This cleans up the last one or two shims outside main or a test. Users can opt out of pruning by setting -Zmiri-backtrace=full, and will be automatically opted out if there are no local frames because that means the reported error is likely in the Rust runtime, which this pruning is crafted to remove. --- src/bin/miri.rs | 10 ++++++++++ src/diagnostics.rs | 50 +++++++++++++++++++++++++++++++++++++++++++++- src/eval.rs | 12 +++++++++++ src/lib.rs | 2 +- src/machine.rs | 4 ++++ 5 files changed, 76 insertions(+), 2 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 672c7e8c9675..333ff6af889f 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -29,6 +29,8 @@ use rustc_middle::{ }; use rustc_session::{config::ErrorOutputType, search_paths::PathKind, CtfeBacktrace}; +use miri::BacktraceStyle; + struct MiriCompilerCalls { miri_config: miri::MiriConfig, } @@ -462,6 +464,14 @@ fn main() { let measureme_out = arg.strip_prefix("-Zmiri-measureme=").unwrap(); miri_config.measureme_out = Some(measureme_out.to_string()); } + arg if arg.starts_with("-Zmiri-backtrace=") => { + miri_config.backtrace_style = match arg.strip_prefix("-Zmiri-backtrace=") { + Some("0") => BacktraceStyle::Off, + Some("1") => BacktraceStyle::Short, + Some("full") => BacktraceStyle::Full, + _ => panic!("-Zmiri-backtrace may only be 0, 1, or full"), + }; + } _ => { // Forward to rustc. rustc_args.push(arg); diff --git a/src/diagnostics.rs b/src/diagnostics.rs index a28418e74905..718148060749 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -157,6 +157,46 @@ pub fn report_error<'tcx, 'mir>( } }; + let mut stacktrace = ecx.generate_stacktrace(); + let has_local_frame = stacktrace.iter().any(|frame| frame.instance.def_id().is_local()); + match ecx.machine.backtrace_style { + BacktraceStyle::Off => { + // Retain one frame so that we can print a span for the error itself + stacktrace.truncate(1); + } + BacktraceStyle::Short => { + // Only prune frames if there is at least one local frame. This check ensures that if + // we get a backtrace that never makes it to the user code because it has detected a + // bug in the Rust runtime, we don't prune away every frame. + if has_local_frame { + // This is part of the logic that `std` uses to select the relevant part of a + // backtrace. But here, we only look for __rust_begin_short_backtrace, not + // __rust_end_short_backtrace because the end symbol comes from a call to the default + // panic handler. + stacktrace = stacktrace + .into_iter() + .take_while(|frame| { + let def_id = frame.instance.def_id(); + let path = ecx.tcx.tcx.def_path_str(def_id); + !path.contains("__rust_begin_short_backtrace") + }) + .collect::>(); + + // After we prune frames from the bottom, there are a few left that are part of the + // Rust runtime. So we remove frames until we get to a local symbol, which should be + // main or a test. + // This len check ensures that we don't somehow remove every frame, as doing so breaks + // the primary error message. + while stacktrace.len() > 1 + && stacktrace.last().map_or(false, |e| !e.instance.def_id().is_local()) + { + stacktrace.pop(); + } + } + } + BacktraceStyle::Full => {} + } + e.print_backtrace(); let msg = e.to_string(); report_msg( @@ -165,9 +205,17 @@ pub fn report_error<'tcx, 'mir>( &if let Some(title) = title { format!("{}: {}", title, msg) } else { msg.clone() }, msg, helps, - &ecx.generate_stacktrace(), + &stacktrace, ); + // Include a note like `std` does for short backtraces, but since we are opt-out not opt-in, we + // do not include a note when backtraces are off. + if ecx.machine.backtrace_style == BacktraceStyle::Short && has_local_frame { + ecx.tcx.sess.diagnostic().note_without_error( + "some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace", + ); + } + // Debug-dump all locals. for (i, frame) in ecx.active_thread_stack().iter().enumerate() { trace!("-------------------"); diff --git a/src/eval.rs b/src/eval.rs index 9cd3a9a56466..e2e85e3e7572 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -57,6 +57,16 @@ pub enum IsolatedOp { Allow, } +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum BacktraceStyle { + /// Prints a terser backtrace which ideally only contains relevant information. + Short, + /// Prints a backtrace with all possible information. + Full, + /// Prints only the frame that the error occurs in. + Off, +} + /// Configuration needed to spawn a Miri instance. #[derive(Clone)] pub struct MiriConfig { @@ -98,6 +108,7 @@ pub struct MiriConfig { pub measureme_out: Option, /// Panic when unsupported functionality is encountered pub panic_on_unsupported: bool, + pub backtrace_style: BacktraceStyle, } impl Default for MiriConfig { @@ -121,6 +132,7 @@ impl Default for MiriConfig { cmpxchg_weak_failure_rate: 0.8, measureme_out: None, panic_on_unsupported: false, + backtrace_style: BacktraceStyle::Short, } } } diff --git a/src/lib.rs b/src/lib.rs index c786487d4a14..006eedde4b6f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -60,7 +60,7 @@ pub use crate::diagnostics::{ NonHaltingDiagnostic, TerminationInfo, }; pub use crate::eval::{ - create_ecx, eval_entry, AlignmentCheck, IsolatedOp, MiriConfig, RejectOpWith, + create_ecx, eval_entry, AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, RejectOpWith, }; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; pub use crate::machine::{ diff --git a/src/machine.rs b/src/machine.rs index 3ca07db921a9..a75ac844902f 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -343,6 +343,9 @@ pub struct Evaluator<'mir, 'tcx> { /// functionality is encountered. If `false`, an error is propagated in the Miri application context /// instead (default behavior) pub(crate) panic_on_unsupported: bool, + + /// Equivalent setting as RUST_BACKTRACE on encountering an error. + pub(crate) backtrace_style: BacktraceStyle, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { @@ -374,6 +377,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { string_cache: Default::default(), exported_symbols_cache: FxHashMap::default(), panic_on_unsupported: config.panic_on_unsupported, + backtrace_style: config.backtrace_style, } } From a20d1f1889dbefcfec00d7050eaed751bd6983b8 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 22 Feb 2022 21:09:30 -0500 Subject: [PATCH 2887/5092] Add crossbeam-epoch and integer-encoding to the trophy case --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 3f300db83643..cc2965a716b7 100644 --- a/README.md +++ b/README.md @@ -454,6 +454,8 @@ Definite bugs found: * [TiKV using `Vec::from_raw_parts` incorrectly](https://github.com/tikv/agatedb/pull/24) * Incorrect doctests for [`AtomicPtr`](https://github.com/rust-lang/rust/pull/84052) and [`Box::from_raw_in`](https://github.com/rust-lang/rust/pull/84053) * [Insufficient alignment in `ThinVec`](https://github.com/Gankra/thin-vec/pull/27) +* [`crossbeam-epoch` calling `assume_init` on a partly-initialized `MaybeUninit`](https://github.com/crossbeam-rs/crossbeam/pull/779) +* [`integer-encoding` dereferencing a misaligned pointer](https://github.com/dermesser/integer-encoding-rs/pull/23) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From 444396d62056eada5dd6bf6e360aaa7377278754 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 24 Feb 2022 10:55:40 -0500 Subject: [PATCH 2888/5092] rustup --- rust-version | 2 +- tests/compile-fail/validity/execute_memory.rs | 8 -------- tests/compile-fail/validity/fn_ptr_offset.rs | 2 +- tests/compile-fail/validity/invalid_fnptr_null.rs | 5 +++++ tests/compile-fail/validity/invalid_fnptr_uninit.rs | 2 +- tests/run-pass/function_pointers.rs | 11 +++++++++++ 6 files changed, 19 insertions(+), 11 deletions(-) delete mode 100644 tests/compile-fail/validity/execute_memory.rs create mode 100644 tests/compile-fail/validity/invalid_fnptr_null.rs diff --git a/rust-version b/rust-version index d64c1095494d..903f326d3fbd 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -b8967b0d52a2ba5f0c9da0da03e78ccba5534e4a +3d127e2040b57157936f5f24e114a8b4c9a505ef diff --git a/tests/compile-fail/validity/execute_memory.rs b/tests/compile-fail/validity/execute_memory.rs deleted file mode 100644 index 5230e7fdf529..000000000000 --- a/tests/compile-fail/validity/execute_memory.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(box_syntax)] - -fn main() { - let x = box 42; - unsafe { - let _f = std::mem::transmute::, fn()>(x); //~ ERROR expected a function pointer - } -} diff --git a/tests/compile-fail/validity/fn_ptr_offset.rs b/tests/compile-fail/validity/fn_ptr_offset.rs index c651fbe070fb..27d8c830ce90 100644 --- a/tests/compile-fail/validity/fn_ptr_offset.rs +++ b/tests/compile-fail/validity/fn_ptr_offset.rs @@ -6,5 +6,5 @@ fn main() { let x : fn() = f; let y : *mut u8 = unsafe { mem::transmute(x) }; let y = y.wrapping_offset(1); - let _x : fn() = unsafe { mem::transmute(y) }; //~ ERROR expected a function pointer + let _x : fn() = unsafe { mem::transmute(y) }; //~ ERROR encountered a potentially null function pointer } diff --git a/tests/compile-fail/validity/invalid_fnptr_null.rs b/tests/compile-fail/validity/invalid_fnptr_null.rs new file mode 100644 index 000000000000..2270740fe149 --- /dev/null +++ b/tests/compile-fail/validity/invalid_fnptr_null.rs @@ -0,0 +1,5 @@ +#![allow(invalid_value)] + +fn main() { + let _b: fn() = unsafe { std::mem::transmute(0usize) }; //~ ERROR encountered a potentially null function pointer +} diff --git a/tests/compile-fail/validity/invalid_fnptr_uninit.rs b/tests/compile-fail/validity/invalid_fnptr_uninit.rs index dbd6711dc65a..2d479dd319f3 100644 --- a/tests/compile-fail/validity/invalid_fnptr_uninit.rs +++ b/tests/compile-fail/validity/invalid_fnptr_uninit.rs @@ -6,5 +6,5 @@ union MyUninit { } fn main() { - let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR encountered uninitialized bytes, but expected a function pointer + let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR encountered uninitialized bytes } diff --git a/tests/run-pass/function_pointers.rs b/tests/run-pass/function_pointers.rs index 26a2d5a6c2a9..dcef1fa221dc 100644 --- a/tests/run-pass/function_pointers.rs +++ b/tests/run-pass/function_pointers.rs @@ -1,3 +1,5 @@ +use std::mem; + trait Answer { fn answer() -> Self; } @@ -56,4 +58,13 @@ fn main() { assert!(return_fn_ptr(g) == g); assert!(return_fn_ptr(g) as unsafe fn() -> i32 == g as fn() -> i32 as unsafe fn() -> i32); assert!(return_fn_ptr(f) != f); + + // Any non-null value is okay for function pointers. + unsafe { + let _x: fn() = mem::transmute(1usize); + let mut b = Box::new(42); + let ptr = &mut *b as *mut _; + drop(b); + let _x: fn() = mem::transmute(ptr); + } } From ddd3e3c4e016677613fe04d5ef3995f362f4a93d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 25 Feb 2022 12:05:59 -0500 Subject: [PATCH 2889/5092] rustup --- rust-version | 2 +- src/diagnostics.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 903f326d3fbd..ab902204cd3b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -3d127e2040b57157936f5f24e114a8b4c9a505ef +d4de1f230ca30b7ce08fbf453daebf8b2e7ffcc9 diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 718148060749..d651aabb86cf 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -254,7 +254,7 @@ fn report_msg<'tcx>( ) { let span = stacktrace.first().map_or(DUMMY_SP, |fi| fi.span); let mut err = match diag_level { - DiagLevel::Error => tcx.sess.struct_span_err(span, title), + DiagLevel::Error => tcx.sess.struct_span_err(span, title).forget_guarantee(), DiagLevel::Warning => tcx.sess.struct_span_warn(span, title), DiagLevel::Note => tcx.sess.diagnostic().span_note_diag(span, title), }; From e9b140b4a5aa71b16a3c89be483b6fecd600379e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 24 Feb 2022 19:41:11 -0500 Subject: [PATCH 2890/5092] update fn ptr tests --- tests/compile-fail/validity/fn_ptr_offset.rs | 10 ---------- tests/compile-fail/validity/invalid_fnptr_null.rs | 2 +- tests/run-pass/function_pointers.rs | 5 +++-- 3 files changed, 4 insertions(+), 13 deletions(-) delete mode 100644 tests/compile-fail/validity/fn_ptr_offset.rs diff --git a/tests/compile-fail/validity/fn_ptr_offset.rs b/tests/compile-fail/validity/fn_ptr_offset.rs deleted file mode 100644 index 27d8c830ce90..000000000000 --- a/tests/compile-fail/validity/fn_ptr_offset.rs +++ /dev/null @@ -1,10 +0,0 @@ -use std::mem; - -fn f() {} - -fn main() { - let x : fn() = f; - let y : *mut u8 = unsafe { mem::transmute(x) }; - let y = y.wrapping_offset(1); - let _x : fn() = unsafe { mem::transmute(y) }; //~ ERROR encountered a potentially null function pointer -} diff --git a/tests/compile-fail/validity/invalid_fnptr_null.rs b/tests/compile-fail/validity/invalid_fnptr_null.rs index 2270740fe149..0634fba36a33 100644 --- a/tests/compile-fail/validity/invalid_fnptr_null.rs +++ b/tests/compile-fail/validity/invalid_fnptr_null.rs @@ -1,5 +1,5 @@ #![allow(invalid_value)] fn main() { - let _b: fn() = unsafe { std::mem::transmute(0usize) }; //~ ERROR encountered a potentially null function pointer + let _b: fn() = unsafe { std::mem::transmute(0usize) }; //~ ERROR encountered a null function pointer } diff --git a/tests/run-pass/function_pointers.rs b/tests/run-pass/function_pointers.rs index dcef1fa221dc..e7d9b2ddd98c 100644 --- a/tests/run-pass/function_pointers.rs +++ b/tests/run-pass/function_pointers.rs @@ -62,9 +62,10 @@ fn main() { // Any non-null value is okay for function pointers. unsafe { let _x: fn() = mem::transmute(1usize); - let mut b = Box::new(42); - let ptr = &mut *b as *mut _; + let mut b = Box::new(42u8); + let ptr = &mut *b as *mut u8; drop(b); let _x: fn() = mem::transmute(ptr); + let _x: fn() = mem::transmute(ptr.wrapping_offset(1)); } } From d2bb231954190da64d0b10c275beeb87833d87b2 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Fri, 25 Feb 2022 19:18:05 -0500 Subject: [PATCH 2891/5092] Prune stacktraces for tag-tracking diagnostics too --- src/diagnostics.rs | 94 ++++++++++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 41 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 718148060749..8494f8a8ef0f 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -75,6 +75,54 @@ enum DiagLevel { Note, } +fn has_local_frame(stacktrace: &[FrameInfo<'_>]) -> bool { + stacktrace.iter().any(|frame| frame.instance.def_id().is_local()) +} + +fn prune_stacktrace<'mir, 'tcx>( + ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, + mut stacktrace: Vec>, +) -> Vec> { + match ecx.machine.backtrace_style { + BacktraceStyle::Off => { + // Retain one frame so that we can print a span for the error itself + stacktrace.truncate(1); + } + BacktraceStyle::Short => { + // Only prune frames if there is at least one local frame. This check ensures that if + // we get a backtrace that never makes it to the user code because it has detected a + // bug in the Rust runtime, we don't prune away every frame. + if has_local_frame(&stacktrace) { + // This is part of the logic that `std` uses to select the relevant part of a + // backtrace. But here, we only look for __rust_begin_short_backtrace, not + // __rust_end_short_backtrace because the end symbol comes from a call to the default + // panic handler. + stacktrace = stacktrace + .into_iter() + .take_while(|frame| { + let def_id = frame.instance.def_id(); + let path = ecx.tcx.tcx.def_path_str(def_id); + !path.contains("__rust_begin_short_backtrace") + }) + .collect::>(); + + // After we prune frames from the bottom, there are a few left that are part of the + // Rust runtime. So we remove frames until we get to a local symbol, which should be + // main or a test. + // This len check ensures that we don't somehow remove every frame, as doing so breaks + // the primary error message. + while stacktrace.len() > 1 + && stacktrace.last().map_or(false, |e| !e.instance.def_id().is_local()) + { + stacktrace.pop(); + } + } + } + BacktraceStyle::Full => {} + } + stacktrace +} + /// Emit a custom diagnostic without going through the miri-engine machinery pub fn report_error<'tcx, 'mir>( ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, @@ -157,46 +205,8 @@ pub fn report_error<'tcx, 'mir>( } }; - let mut stacktrace = ecx.generate_stacktrace(); - let has_local_frame = stacktrace.iter().any(|frame| frame.instance.def_id().is_local()); - match ecx.machine.backtrace_style { - BacktraceStyle::Off => { - // Retain one frame so that we can print a span for the error itself - stacktrace.truncate(1); - } - BacktraceStyle::Short => { - // Only prune frames if there is at least one local frame. This check ensures that if - // we get a backtrace that never makes it to the user code because it has detected a - // bug in the Rust runtime, we don't prune away every frame. - if has_local_frame { - // This is part of the logic that `std` uses to select the relevant part of a - // backtrace. But here, we only look for __rust_begin_short_backtrace, not - // __rust_end_short_backtrace because the end symbol comes from a call to the default - // panic handler. - stacktrace = stacktrace - .into_iter() - .take_while(|frame| { - let def_id = frame.instance.def_id(); - let path = ecx.tcx.tcx.def_path_str(def_id); - !path.contains("__rust_begin_short_backtrace") - }) - .collect::>(); - - // After we prune frames from the bottom, there are a few left that are part of the - // Rust runtime. So we remove frames until we get to a local symbol, which should be - // main or a test. - // This len check ensures that we don't somehow remove every frame, as doing so breaks - // the primary error message. - while stacktrace.len() > 1 - && stacktrace.last().map_or(false, |e| !e.instance.def_id().is_local()) - { - stacktrace.pop(); - } - } - } - BacktraceStyle::Full => {} - } - + let stacktrace = ecx.generate_stacktrace(); + let stacktrace = prune_stacktrace(ecx, stacktrace); e.print_backtrace(); let msg = e.to_string(); report_msg( @@ -210,7 +220,7 @@ pub fn report_error<'tcx, 'mir>( // Include a note like `std` does for short backtraces, but since we are opt-out not opt-in, we // do not include a note when backtraces are off. - if ecx.machine.backtrace_style == BacktraceStyle::Short && has_local_frame { + if ecx.machine.backtrace_style == BacktraceStyle::Short && has_local_frame(&stacktrace) { ecx.tcx.sess.diagnostic().note_without_error( "some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace", ); @@ -367,6 +377,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); } + let stacktrace = prune_stacktrace(this, stacktrace); + // Show diagnostics. for e in diagnostics.drain(..) { use NonHaltingDiagnostic::*; From f1c649890b517997b0bab3b303415e2f6ceea476 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 26 Feb 2022 17:02:17 -0500 Subject: [PATCH 2892/5092] Only print the pruning note if the trace was definitely pruned --- src/diagnostics.rs | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 8494f8a8ef0f..2b210a6de691 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -75,24 +75,26 @@ enum DiagLevel { Note, } -fn has_local_frame(stacktrace: &[FrameInfo<'_>]) -> bool { - stacktrace.iter().any(|frame| frame.instance.def_id().is_local()) -} - +/// Attempts to prune a stacktrace to omit the Rust runtime, and returns a bool indicating if any +/// frames were pruned. If the stacktrace does not have any local frames, we conclude that it must +/// be pointing to a problem in the Rust runtime itself, and do not prune it at all. fn prune_stacktrace<'mir, 'tcx>( ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, mut stacktrace: Vec>, -) -> Vec> { +) -> (Vec>, bool) { match ecx.machine.backtrace_style { BacktraceStyle::Off => { // Retain one frame so that we can print a span for the error itself stacktrace.truncate(1); + (stacktrace, false) } BacktraceStyle::Short => { + let original_len = stacktrace.len(); // Only prune frames if there is at least one local frame. This check ensures that if // we get a backtrace that never makes it to the user code because it has detected a // bug in the Rust runtime, we don't prune away every frame. - if has_local_frame(&stacktrace) { + let has_local_frame = stacktrace.iter().any(|frame| frame.instance.def_id().is_local()); + if has_local_frame { // This is part of the logic that `std` uses to select the relevant part of a // backtrace. But here, we only look for __rust_begin_short_backtrace, not // __rust_end_short_backtrace because the end symbol comes from a call to the default @@ -117,10 +119,11 @@ fn prune_stacktrace<'mir, 'tcx>( stacktrace.pop(); } } + let was_pruned = stacktrace.len() != original_len; + (stacktrace, was_pruned) } - BacktraceStyle::Full => {} + BacktraceStyle::Full => (stacktrace, false), } - stacktrace } /// Emit a custom diagnostic without going through the miri-engine machinery @@ -206,7 +209,7 @@ pub fn report_error<'tcx, 'mir>( }; let stacktrace = ecx.generate_stacktrace(); - let stacktrace = prune_stacktrace(ecx, stacktrace); + let (stacktrace, was_pruned) = prune_stacktrace(ecx, stacktrace); e.print_backtrace(); let msg = e.to_string(); report_msg( @@ -218,9 +221,8 @@ pub fn report_error<'tcx, 'mir>( &stacktrace, ); - // Include a note like `std` does for short backtraces, but since we are opt-out not opt-in, we - // do not include a note when backtraces are off. - if ecx.machine.backtrace_style == BacktraceStyle::Short && has_local_frame(&stacktrace) { + // Include a note like `std` does when we omit frames from a backtrace + if was_pruned { ecx.tcx.sess.diagnostic().note_without_error( "some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace", ); @@ -377,7 +379,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); } - let stacktrace = prune_stacktrace(this, stacktrace); + let (stacktrace, _was_pruned) = prune_stacktrace(this, stacktrace); // Show diagnostics. for e in diagnostics.drain(..) { From 71075672f5af74aa3e119892ffe57fee2a336e1e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 27 Feb 2022 15:22:49 -0500 Subject: [PATCH 2893/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index ab902204cd3b..ba41809f0749 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d4de1f230ca30b7ce08fbf453daebf8b2e7ffcc9 +6a705566166debf5eff88c57140df607fa409aaa From c347b04e8280f09fd3f5d5f28020b6c50505895c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 27 Feb 2022 15:27:34 -0500 Subject: [PATCH 2894/5092] add test for rust issue 94371 --- tests/run-pass/issue-94371.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tests/run-pass/issue-94371.rs diff --git a/tests/run-pass/issue-94371.rs b/tests/run-pass/issue-94371.rs new file mode 100644 index 000000000000..1336348efb17 --- /dev/null +++ b/tests/run-pass/issue-94371.rs @@ -0,0 +1,13 @@ +#[repr(C)] +struct Demo(u64, bool, u64, u32, u64, u64, u64); + +fn test() -> (Demo, Demo) { + let mut x = Demo(1, true, 3, 4, 5, 6, 7); + let mut y = Demo(10, false, 12, 13, 14, 15, 16); + std::mem::swap(&mut x, &mut y); + (x, y) +} + +fn main() { + drop(test()); +} From 4dded23925994103e3e793d5edbe0d30222cdaa4 Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Mon, 28 Feb 2022 19:59:21 -0500 Subject: [PATCH 2895/5092] add `special_module_name` lint --- compiler/rustc_lint/src/builtin.rs | 74 +++++++++++++++++++ compiler/rustc_lint/src/lib.rs | 1 + src/test/ui/modules/dummy.rs | 0 src/test/ui/modules/special_module_name.rs | 8 ++ .../ui/modules/special_module_name.stderr | 37 ++++++++++ .../ui/modules/special_module_name_ignore.rs | 9 +++ 6 files changed, 129 insertions(+) create mode 100644 src/test/ui/modules/dummy.rs create mode 100644 src/test/ui/modules/special_module_name.rs create mode 100644 src/test/ui/modules/special_module_name.stderr create mode 100644 src/test/ui/modules/special_module_name_ignore.rs diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 30b5f9b34d09..961e1e9507b9 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -3248,3 +3248,77 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels { } } } + +declare_lint! { + /// The `special_module_name` lint detects module + /// declarations for files that have a special meaning. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// mod lib; + /// + /// fn main() { + /// lib::run(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Cargo recognizes `lib.rs` and `main.rs` as the root of a + /// library or binary crate, so declaring them as modules + /// will lead to miscompilation of the crate unless configured + /// explicitly. + /// + /// To access a library from a binary target within the same crate, + /// use `your_crate_name::` as the path path instead of `lib::`: + /// + /// ```rust,compile_fail + /// // bar/src/lib.rs + /// fn run() { + /// // ... + /// } + /// + /// // bar/src/main.rs + /// fn main() { + /// bar::run(); + /// } + /// ``` + /// + /// Binary targets cannot be used as libraries and so declaring + /// one as a module is not allowed. + pub SPECIAL_MODULE_NAME, + Warn, + "module declarations for files with a special meaning", +} + +declare_lint_pass!(SpecialModuleName => [SPECIAL_MODULE_NAME]); + +impl EarlyLintPass for SpecialModuleName { + fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &ast::Crate) { + for item in &krate.items { + if let ast::ItemKind::Mod(..) = item.kind { + if item.attrs.iter().any(|a| a.has_name(sym::path)) { + continue; + } + + match item.ident.name.as_str() { + "lib" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, |lint| { + lint.build("found module declaration for lib.rs") + .note("lib.rs is the root of this crate's library target") + .help("to refer to it from other targets, use the library's name as the path") + .emit() + }), + "main" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, |lint| { + lint.build("found module declaration for main.rs") + .note("a binary crate cannot be used as library") + .emit() + }), + _ => continue + } + } + } + } +} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 69863b5ff827..107df79c3809 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -129,6 +129,7 @@ macro_rules! early_lint_passes { UnusedBraces: UnusedBraces, UnusedImportBraces: UnusedImportBraces, UnsafeCode: UnsafeCode, + SpecialModuleName: SpecialModuleName, AnonymousParameters: AnonymousParameters, EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::default(), NonCamelCaseTypes: NonCamelCaseTypes, diff --git a/src/test/ui/modules/dummy.rs b/src/test/ui/modules/dummy.rs new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/test/ui/modules/special_module_name.rs b/src/test/ui/modules/special_module_name.rs new file mode 100644 index 000000000000..15c59b2da828 --- /dev/null +++ b/src/test/ui/modules/special_module_name.rs @@ -0,0 +1,8 @@ +mod lib; +//~^ WARN found module declaration for lib.rs +//~| ERROR file not found for module `lib` +mod main; +//~^ WARN found module declaration for main.rs +//~| ERROR file not found for module `main` + +fn main() {} diff --git a/src/test/ui/modules/special_module_name.stderr b/src/test/ui/modules/special_module_name.stderr new file mode 100644 index 000000000000..8b3da29386df --- /dev/null +++ b/src/test/ui/modules/special_module_name.stderr @@ -0,0 +1,37 @@ +error[E0583]: file not found for module `lib` + --> $DIR/special_module_name.rs:1:1 + | +LL | mod lib; + | ^^^^^^^^ + | + = help: to create the module `lib`, create file "$DIR/lib.rs" or "$DIR/lib/mod.rs" + +error[E0583]: file not found for module `main` + --> $DIR/special_module_name.rs:4:1 + | +LL | mod main; + | ^^^^^^^^^ + | + = help: to create the module `main`, create file "$DIR/main.rs" or "$DIR/main/mod.rs" + +warning: found module declaration for lib.rs + --> $DIR/special_module_name.rs:1:1 + | +LL | mod lib; + | ^^^^^^^^ + | + = note: `#[warn(special_module_name)]` on by default + = note: lib.rs is the root of this crate's library target + = help: to refer to it from other targets, use the library's name as the path + +warning: found module declaration for main.rs + --> $DIR/special_module_name.rs:4:1 + | +LL | mod main; + | ^^^^^^^^^ + | + = note: a binary crate cannot be used as library + +error: aborting due to 2 previous errors; 2 warnings emitted + +For more information about this error, try `rustc --explain E0583`. diff --git a/src/test/ui/modules/special_module_name_ignore.rs b/src/test/ui/modules/special_module_name_ignore.rs new file mode 100644 index 000000000000..cae06b49ee0b --- /dev/null +++ b/src/test/ui/modules/special_module_name_ignore.rs @@ -0,0 +1,9 @@ +// run-pass + +#[path = "dummy.rs"] +mod lib; + +#[path = "dummy.rs"] +mod main; + +fn main() {} From f672282bf25db5670f5809f78b1cd701037cc2dc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 1 Mar 2022 18:15:39 -0500 Subject: [PATCH 2896/5092] factor SIMD bool handling into helper functions --- src/helpers.rs | 15 +++++++++++++++ src/shims/intrinsics.rs | 16 +++------------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 0c4e0c4e969e..2f1c74a0587e 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -758,3 +758,18 @@ pub fn immty_from_uint_checked<'tcx>( err_unsup_format!("unsigned value {:#x} does not fit in {} bits", int, layout.size.bits()) })?) } + +pub fn bool_to_simd_element(b: bool, size: Size) -> Scalar { + // SIMD uses all-1 as pattern for "true" + let val = if b { -1 } else { 0 }; + Scalar::from_int(val, size) +} + +pub fn simd_element_to_bool<'tcx>(elem: ImmTy<'tcx, Tag>) -> InterpResult<'tcx, bool> { + let val = elem.to_scalar()?.to_int(elem.layout.size)?; + Ok(match val { + 0 => false, + -1 => true, + _ => throw_ub_format!("each element of a SIMD mask must be all-0-bits or all-1-bits"), + }) +} diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index a75367b82c12..74914963f74c 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -8,7 +8,7 @@ use rustc_middle::{mir, mir::BinOp, ty, ty::FloatTy}; use rustc_target::abi::{Align, Integer}; use crate::*; -use helpers::check_arg_count; +use helpers::{bool_to_simd_element, check_arg_count, simd_element_to_bool}; pub enum AtomicOp { MirOp(mir::BinOp, bool), @@ -365,8 +365,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Special handling for boolean-returning operations assert_eq!(ty, this.tcx.types.bool); let val = val.to_bool().unwrap(); - let val = if val { -1 } else { 0 }; // SIMD uses all-1 as pattern for "true" - let val = Scalar::from_int(val, dest.layout.size); + let val = bool_to_simd_element(val, dest.layout.size); this.write_scalar(val, &dest.into())?; } else { assert_eq!(ty, dest.layout.ty); @@ -381,16 +380,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut res = false; // the neutral element for i in 0..arg_len { let op = this.read_immediate(&this.mplace_index(&arg, i)?.into())?; - // We convert it to a *signed* integer and expect either 0 or -1 (the latter means all bits were set). - let val = op.to_scalar()?.to_int(op.layout.size)?; - let val = match val { - 0 => false, - -1 => true, - _ => - throw_ub_format!( - "each element of a simd_reduce_any operand must be all-0-bits or all-1-bits" - ), - }; + let val = simd_element_to_bool(op)?; res = res | val; } From aa4f82ea4887bb9e0847bb2de287ef968b6b27f4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 1 Mar 2022 18:40:40 -0500 Subject: [PATCH 2897/5092] implement simd_select --- rust-version | 2 +- src/shims/intrinsics.rs | 22 ++++++++++++++++++++++ tests/run-pass/portable-simd.rs | 21 ++++++++++++--------- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/rust-version b/rust-version index ba41809f0749..cab2da408db4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6a705566166debf5eff88c57140df607fa409aaa +f0c4da49983aa699f715caf681e3154b445fb60b diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 74914963f74c..e84923314186 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -386,6 +386,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_bool(res), dest)?; } + "simd_select" => { + let &[ref mask, ref yes, ref no] = check_arg_count(args)?; + let (mask, mask_len) = this.operand_to_simd(mask)?; + let (yes, yes_len) = this.operand_to_simd(yes)?; + let (no, no_len) = this.operand_to_simd(no)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + assert_eq!(dest_len, mask_len); + assert_eq!(dest_len, yes_len); + assert_eq!(dest_len, no_len); + + for i in 0..dest_len { + let mask = this.read_immediate(&this.mplace_index(&mask, i)?.into())?; + let yes = this.read_immediate(&this.mplace_index(&yes, i)?.into())?; + let no = this.read_immediate(&this.mplace_index(&no, i)?.into())?; + let dest = this.mplace_index(&dest, i)?; + + let mask = simd_element_to_bool(mask)?; + let val = if mask { yes } else { no }; + this.write_immediate(*val, &dest.into())?; + } + } // Atomic operations "atomic_load" => this.atomic_load(args, dest, AtomicReadOp::SeqCst)?, diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 17fea5916675..3c1437f0e0fc 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -29,19 +29,22 @@ fn simd_ops_i32() { fn simd_intrinsics() { extern "platform-intrinsic" { - pub(crate) fn simd_eq(x: T, y: T) -> U; - pub(crate) fn simd_reduce_any(x: T) -> bool; + fn simd_eq(x: T, y: T) -> U; + fn simd_reduce_any(x: T) -> bool; + fn simd_select(m: M, yes: T, no: T) -> T; } - - // Make sure simd_eq returns all-1 for `true` - let a = i32x4::splat(10); - let b = i32x4::from_array([1, 2, 10, 4]); - let c: i32x4 = unsafe { simd_eq(a, b) }; - assert_eq!(c, i32x4::from_array([0, 0, -1, 0])); - unsafe { + // Make sure simd_eq returns all-1 for `true` + let a = i32x4::splat(10); + let b = i32x4::from_array([1, 2, 10, 4]); + let c: i32x4 = simd_eq(a, b); + assert_eq!(c, i32x4::from_array([0, 0, -1, 0])); + assert!(!simd_reduce_any(i32x4::splat(0))); assert!(simd_reduce_any(i32x4::splat(-1))); + + assert_eq!(simd_select(i8x4::from_array([0, -1, -1, 0]), a, b), i32x4::from_array([1, 10, 10, 4])); + assert_eq!(simd_select(i8x4::from_array([0, -1, -1, 0]), b, a), i32x4::from_array([10, 2, 10, 10])); } } From 363236e2d493b8a29d6ed7e849279ecf22c732ce Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 1 Mar 2022 18:44:37 -0500 Subject: [PATCH 2898/5092] test overflowing Div/Rem --- tests/run-pass/portable-simd.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 3c1437f0e0fc..98d5b65e3e68 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -20,7 +20,9 @@ fn simd_ops_i32() { assert_eq!(a * b, i32x4::from_array([10, 20, 30, 40])); assert_eq!(a / b, i32x4::from_array([10, 5, 3, 2])); assert_eq!(a / i32x4::splat(2), i32x4::splat(5)); + assert_eq!(i32x2::splat(i32::MIN) / i32x2::splat(-1), i32x2::splat(i32::MIN)); assert_eq!(a % b, i32x4::from_array([0, 0, 1, 2])); + assert_eq!(i32x2::splat(i32::MIN) % i32x2::splat(-1), i32x2::splat(0)); assert_eq!(b << i32x4::splat(2), i32x4::from_array([4, 8, 12, 16])); assert_eq!(b >> i32x4::splat(1), i32x4::from_array([0, 1, 1, 2])); assert_eq!(b & i32x4::splat(2), i32x4::from_array([0, 2, 2, 0])); From 798dc5a78ac9b0016c9b5c193bf8c7dea73ef908 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 2 Mar 2022 13:06:28 -0500 Subject: [PATCH 2899/5092] Make sure we notice when a u16 is loaded at offset 1 into a u8 allocation --- .../unaligned_pointers/unaligned_ptr4.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/compile-fail/unaligned_pointers/unaligned_ptr4.rs diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr4.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr4.rs new file mode 100644 index 000000000000..10766746bd42 --- /dev/null +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr4.rs @@ -0,0 +1,12 @@ +// This should fail even without validation or Stacked Borrows. +// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows + +fn main() { + // Make sure we notice when a u16 is loaded at offset 1 into a u8 allocation. + // (This would be missed if u8 allocations are *always* at odd addresses.) + for _ in 0..10 { // Try many times as this might work by chance. + let x = [0u8; 4]; + let ptr = x.as_ptr().wrapping_offset(1).cast::(); + let _val = unsafe { *ptr }; //~ERROR but alignment + } +} From 97ddcf1f6b1183f3187a74f29f0feb0a4ff4887c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 1 Mar 2022 20:37:46 -0500 Subject: [PATCH 2900/5092] adjust for div/rem overflow being UB --- tests/compile-fail/intrinsics/exact_div4.rs | 2 +- tests/compile-fail/intrinsics/unchecked_div1.rs | 2 +- tests/run-pass/integer-ops.rs | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/compile-fail/intrinsics/exact_div4.rs b/tests/compile-fail/intrinsics/exact_div4.rs index c241b2df660e..2831795de82e 100644 --- a/tests/compile-fail/intrinsics/exact_div4.rs +++ b/tests/compile-fail/intrinsics/exact_div4.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // divison of MIN by -1 - unsafe { std::intrinsics::exact_div(i64::MIN, -1); } //~ ERROR result of dividing MIN by -1 cannot be represented + unsafe { std::intrinsics::exact_div(i64::MIN, -1); } //~ ERROR overflow in signed remainder (dividing MIN by -1) } diff --git a/tests/compile-fail/intrinsics/unchecked_div1.rs b/tests/compile-fail/intrinsics/unchecked_div1.rs index 53d80007646d..08b654da3ed7 100644 --- a/tests/compile-fail/intrinsics/unchecked_div1.rs +++ b/tests/compile-fail/intrinsics/unchecked_div1.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MIN/-1 cannot be represented - unsafe { std::intrinsics::unchecked_div(i16::MIN, -1); } //~ ERROR overflow executing `unchecked_div` + unsafe { std::intrinsics::unchecked_div(i16::MIN, -1); } //~ ERROR overflow in signed division (dividing MIN by -1) } diff --git a/tests/run-pass/integer-ops.rs b/tests/run-pass/integer-ops.rs index 36bd5797177a..fde220d8f35e 100644 --- a/tests/run-pass/integer-ops.rs +++ b/tests/run-pass/integer-ops.rs @@ -116,6 +116,9 @@ pub fn main() { assert_eq!(100i8.wrapping_rem(10), 0); assert_eq!((-128i8).wrapping_rem(-1), 0); + assert_eq!(i32::MIN.wrapping_div(-1), i32::MIN); + assert_eq!(i32::MIN.wrapping_rem(-1), 0); + assert_eq!(100i8.wrapping_neg(), -100); assert_eq!((-128i8).wrapping_neg(), -128); From d7c7fc0fa2c00ece9680daae137fedbb17923cee Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 3 Mar 2022 12:26:42 -0500 Subject: [PATCH 2901/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index cab2da408db4..56281423c527 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -f0c4da49983aa699f715caf681e3154b445fb60b +45660949132222ba7ec0905649b2affd68e0e13c From c0f72510550529ca8ddaaffd94709bec457debff Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 3 Mar 2022 12:32:42 -0500 Subject: [PATCH 2902/5092] add test for simd division overflow UB --- .../compile-fail/intrinsics/simd-div-overflow.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/compile-fail/intrinsics/simd-div-overflow.rs diff --git a/tests/compile-fail/intrinsics/simd-div-overflow.rs b/tests/compile-fail/intrinsics/simd-div-overflow.rs new file mode 100644 index 000000000000..277b9e807baa --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-div-overflow.rs @@ -0,0 +1,15 @@ +#![feature(platform_intrinsics, repr_simd)] + +extern "platform-intrinsic" { + pub(crate) fn simd_div(x: T, y: T) -> T; +} + +#[repr(simd)] +#[allow(non_camel_case_types)] +struct i32x2(i32, i32); + +fn main() { unsafe { + let x = i32x2(1, i32::MIN); + let y = i32x2(1, -1); + simd_div(x, y); //~ERROR Undefined Behavior: overflow in signed division +} } From 0bd83245edb4a420bdf89edea5f6e50f70c78475 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Thu, 3 Mar 2022 13:10:05 -0500 Subject: [PATCH 2903/5092] rkyv deallocation alignment issue --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index cc2965a716b7..f073cde7764e 100644 --- a/README.md +++ b/README.md @@ -456,6 +456,7 @@ Definite bugs found: * [Insufficient alignment in `ThinVec`](https://github.com/Gankra/thin-vec/pull/27) * [`crossbeam-epoch` calling `assume_init` on a partly-initialized `MaybeUninit`](https://github.com/crossbeam-rs/crossbeam/pull/779) * [`integer-encoding` dereferencing a misaligned pointer](https://github.com/dermesser/integer-encoding-rs/pull/23) +* [`rkyv` constructing a `Box<[u8]>` from an overaligned allocation](https://github.com/rkyv/rkyv/commit/a9417193a34757e12e24263178be8b2eebb72456) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From 0147b88ce59cb44cd854c7033a5663e43479e612 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 3 Mar 2022 14:44:50 -0500 Subject: [PATCH 2904/5092] use binary_op over overflowing_binary_op --- src/data_race.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index 9e5dfd9dbaf0..a6ef56a0c204 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -553,7 +553,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let this = self.eval_context_mut(); let old = this.allow_data_races_mut(|this| this.read_immediate(&place.into()))?; - let lt = this.overflowing_binary_op(mir::BinOp::Lt, &old, &rhs)?.0.to_bool()?; + let lt = this.binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar()?.to_bool()?; let new_val = if min { if lt { &old } else { &rhs } @@ -593,11 +593,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // Read as immediate for the sake of `binary_op()` let old = this.allow_data_races_mut(|this| this.read_immediate(&(place.into())))?; // `binary_op` will bail if either of them is not a scalar. - let eq = this.overflowing_binary_op(mir::BinOp::Eq, &old, expect_old)?.0; + let eq = this.binary_op(mir::BinOp::Eq, &old, expect_old)?; // If the operation would succeed, but is "weak", fail some portion // of the time, based on `rate`. let rate = this.memory.extra.cmpxchg_weak_failure_rate; - let cmpxchg_success = eq.to_bool()? + let cmpxchg_success = eq.to_scalar()?.to_bool()? && (!can_fail_spuriously || this.memory.extra.rng.get_mut().gen::() < rate); let res = Immediate::ScalarPair( old.to_scalar_or_uninit(), From 0d4902f12f2630ababe056b167ad20eb0633bb01 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 3 Mar 2022 14:54:54 -0500 Subject: [PATCH 2905/5092] implement simd_neg and simd_fabs --- src/lib.rs | 1 + src/shims/intrinsics.rs | 39 +++++++++++++++++++++++++++++---- tests/run-pass/portable-simd.rs | 27 ++++++++++++++++++----- 3 files changed, 58 insertions(+), 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 006eedde4b6f..9542fb9b9635 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ #![feature(map_try_insert)] #![feature(never_type)] #![feature(try_blocks)] +#![feature(let_else)] #![feature(bool_to_option)] #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index e84923314186..f713721f5840 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -316,6 +316,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // SIMD operations #[rustfmt::skip] + | "simd_neg" + | "simd_fabs" => { + let &[ref op] = check_arg_count(args)?; + let (op, op_len) = this.operand_to_simd(op)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + assert_eq!(dest_len, op_len); + + for i in 0..dest_len { + let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; + let dest = this.mplace_index(&dest, i)?; + let val = match intrinsic_name { + "simd_neg" => this.unary_op(mir::UnOp::Neg, &op)?.to_scalar()?, + "simd_fabs" => { + // Works for f32 and f64. + let ty::Float(float_ty) = op.layout.ty.kind() else { + bug!("simd_fabs operand is not a float") + }; + let op = op.to_scalar()?; + // FIXME: Using host floats. + match float_ty { + FloatTy::F32 => Scalar::from_f32(op.to_f32()?.abs()), + FloatTy::F64 => Scalar::from_f64(op.to_f64()?.abs()), + } + } + _ => bug!(), + }; + this.write_scalar(val, &dest.into())?; + } + } + #[rustfmt::skip] | "simd_add" | "simd_sub" | "simd_mul" @@ -374,12 +405,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "simd_reduce_any" => { - let &[ref arg] = check_arg_count(args)?; - let (arg, arg_len) = this.operand_to_simd(arg)?; + let &[ref op] = check_arg_count(args)?; + let (op, op_len) = this.operand_to_simd(op)?; let mut res = false; // the neutral element - for i in 0..arg_len { - let op = this.read_immediate(&this.mplace_index(&arg, i)?.into())?; + for i in 0..op_len { + let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; let val = simd_element_to_bool(op)?; res = res | val; } diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 98d5b65e3e68..c0c1ecd0235a 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -3,18 +3,34 @@ use std::simd::*; fn simd_ops_f32() { let a = f32x4::splat(10.0); - let b = f32x4::from_array([1.0, 2.0, 3.0, 4.0]); - assert_eq!(a + b, f32x4::from_array([11.0, 12.0, 13.0, 14.0])); - assert_eq!(a - b, f32x4::from_array([9.0, 8.0, 7.0, 6.0])); - assert_eq!(a * b, f32x4::from_array([10.0, 20.0, 30.0, 40.0])); - assert_eq!(b / a, f32x4::from_array([0.1, 0.2, 0.3, 0.4])); + let b = f32x4::from_array([1.0, 2.0, 3.0, -4.0]); + assert_eq!(-b, f32x4::from_array([-1.0, -2.0, -3.0, 4.0])); + assert_eq!(a + b, f32x4::from_array([11.0, 12.0, 13.0, 6.0])); + assert_eq!(a - b, f32x4::from_array([9.0, 8.0, 7.0, 14.0])); + assert_eq!(a * b, f32x4::from_array([10.0, 20.0, 30.0, -40.0])); + assert_eq!(b / a, f32x4::from_array([0.1, 0.2, 0.3, -0.4])); assert_eq!(a / f32x4::splat(2.0), f32x4::splat(5.0)); assert_eq!(a % b, f32x4::from_array([0.0, 0.0, 1.0, 2.0])); + assert_eq!(b.abs(), f32x4::from_array([1.0, 2.0, 3.0, 4.0])); +} + +fn simd_ops_f64() { + let a = f64x4::splat(10.0); + let b = f64x4::from_array([1.0, 2.0, 3.0, -4.0]); + assert_eq!(-b, f64x4::from_array([-1.0, -2.0, -3.0, 4.0])); + assert_eq!(a + b, f64x4::from_array([11.0, 12.0, 13.0, 6.0])); + assert_eq!(a - b, f64x4::from_array([9.0, 8.0, 7.0, 14.0])); + assert_eq!(a * b, f64x4::from_array([10.0, 20.0, 30.0, -40.0])); + assert_eq!(b / a, f64x4::from_array([0.1, 0.2, 0.3, -0.4])); + assert_eq!(a / f64x4::splat(2.0), f64x4::splat(5.0)); + assert_eq!(a % b, f64x4::from_array([0.0, 0.0, 1.0, 2.0])); + assert_eq!(b.abs(), f64x4::from_array([1.0, 2.0, 3.0, 4.0])); } fn simd_ops_i32() { let a = i32x4::splat(10); let b = i32x4::from_array([1, 2, 3, 4]); + assert_eq!(-b, i32x4::from_array([-1, -2, -3, -4])); assert_eq!(a + b, i32x4::from_array([11, 12, 13, 14])); assert_eq!(a - b, i32x4::from_array([9, 8, 7, 6])); assert_eq!(a * b, i32x4::from_array([10, 20, 30, 40])); @@ -52,6 +68,7 @@ fn simd_intrinsics() { fn main() { simd_ops_f32(); + simd_ops_f64(); simd_ops_i32(); simd_intrinsics(); } From 3adc203c1cb9185ac546285c32e302a7f834bf11 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Mar 2022 11:09:50 -0500 Subject: [PATCH 2906/5092] add flag to forward specific env vars (while isolation remains enabled) --- README.md | 11 +++++++---- src/bin/miri.rs | 5 +++++ src/eval.rs | 5 ++++- src/shims/env.rs | 10 ++++++++-- tests/run-pass/env-forward.rs | 5 +++++ 5 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 tests/run-pass/env-forward.rs diff --git a/README.md b/README.md index f073cde7764e..3c5af59d3f07 100644 --- a/README.md +++ b/README.md @@ -236,10 +236,13 @@ environment variable: execution with a "permission denied" error being returned to the program. `warn` prints a full backtrace when that happen; `warn-nobacktrace` is less verbose. `hide` hides the warning entirely. -* `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from - the host so that it cannot be accessed by the program. Can be used multiple - times to exclude several variables. On Windows, the `TERM` environment - variable is excluded by default. +* `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from the host so that it + cannot be accessed by the program. Can be used multiple times to exclude several variables. On + Windows, the `TERM` environment variable is excluded by default. This has no effect unless + `-Zmiri-disable-validation` is also set. +* `-Zmiri-env-forward=` forwards the `var` environment variable to the interpreted program. Can + be used multiple times to forward several variables. This has no effect if + `-Zmiri-disable-validation` is set. * `-Zmiri-ignore-leaks` disables the memory leak checker, and also allows some remaining threads to exist when the main thread exits. * `-Zmiri-measureme=` enables `measureme` profiling for the interpreted program. diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 333ff6af889f..dd7b0b54f488 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -399,6 +399,11 @@ fn main() { .excluded_env_vars .push(arg.strip_prefix("-Zmiri-env-exclude=").unwrap().to_owned()); } + arg if arg.starts_with("-Zmiri-env-forward=") => { + miri_config + .forwarded_env_vars + .push(arg.strip_prefix("-Zmiri-env-forward=").unwrap().to_owned()); + } arg if arg.starts_with("-Zmiri-track-pointer-tag=") => { let id: u64 = match arg.strip_prefix("-Zmiri-track-pointer-tag=").unwrap().parse() { diff --git a/src/eval.rs b/src/eval.rs index e2e85e3e7572..97856d92020b 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -86,6 +86,8 @@ pub struct MiriConfig { pub ignore_leaks: bool, /// Environment variables that should always be isolated from the host. pub excluded_env_vars: Vec, + /// Environment variables that should always be forwarded from the host. + pub forwarded_env_vars: Vec, /// Command-line arguments passed to the interpreted program. pub args: Vec, /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`). @@ -122,6 +124,7 @@ impl Default for MiriConfig { isolated_op: IsolatedOp::Reject(RejectOpWith::Abort), ignore_leaks: false, excluded_env_vars: vec![], + forwarded_env_vars: vec![], args: vec![], seed: None, tracked_pointer_tag: None, @@ -157,7 +160,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( MemoryExtra::new(&config), ); // Complete initialization. - EnvVars::init(&mut ecx, config.excluded_env_vars)?; + EnvVars::init(&mut ecx, config.excluded_env_vars, config.forwarded_env_vars)?; MemoryExtra::init_extern_statics(&mut ecx)?; // Make sure we have MIR. We check MIR for some stable monomorphic function in libcore. diff --git a/src/shims/env.rs b/src/shims/env.rs index 4d297fd935d5..59fd16912a22 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -39,6 +39,7 @@ impl<'tcx> EnvVars<'tcx> { pub(crate) fn init<'mir>( ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, mut excluded_env_vars: Vec, + forwarded_env_vars: Vec, ) -> InterpResult<'tcx> { let target_os = ecx.tcx.sess.target.os.as_str(); if target_os == "windows" { @@ -47,9 +48,14 @@ impl<'tcx> EnvVars<'tcx> { excluded_env_vars.push("TERM".to_owned()); } - if ecx.machine.communicate() { + // Skip the loop entirely if we don't want to forward anything. + if ecx.machine.communicate() || !forwarded_env_vars.is_empty() { for (name, value) in env::vars() { - if !excluded_env_vars.contains(&name) { + let forward = match ecx.machine.communicate() { + true => !excluded_env_vars.contains(&name), + false => forwarded_env_vars.contains(&name), + }; + if forward { let var_ptr = match target_os { "linux" | "macos" => alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx)?, diff --git a/tests/run-pass/env-forward.rs b/tests/run-pass/env-forward.rs new file mode 100644 index 000000000000..8eebc45f55a7 --- /dev/null +++ b/tests/run-pass/env-forward.rs @@ -0,0 +1,5 @@ +// compile-flags: -Zmiri-env-forward=MIRI_ENV_VAR_TEST + +fn main() { + assert_eq!(std::env::var("MIRI_ENV_VAR_TEST"), Ok("0".to_owned())); +} From ceec2b3cebab9072beccd65c678b5bc51f830b5d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Mar 2022 11:13:32 -0500 Subject: [PATCH 2907/5092] avoid env var forwarding logic panicking for non-UTF-8 env vars --- src/shims/env.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 59fd16912a22..dfd1ef207d96 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -50,10 +50,10 @@ impl<'tcx> EnvVars<'tcx> { // Skip the loop entirely if we don't want to forward anything. if ecx.machine.communicate() || !forwarded_env_vars.is_empty() { - for (name, value) in env::vars() { + for (name, value) in env::vars_os() { let forward = match ecx.machine.communicate() { - true => !excluded_env_vars.contains(&name), - false => forwarded_env_vars.contains(&name), + true => !excluded_env_vars.iter().any(|v| v.as_str() == &name), + false => forwarded_env_vars.iter().any(|v| v.as_str() == &name), }; if forward { let var_ptr = match target_os { From 90207a548481b1abac9fc28c8f8f03897789e6fa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Mar 2022 13:30:16 -0500 Subject: [PATCH 2908/5092] implement missing SIMD comparison operators, simd_xor, and simd_reduce_all --- src/shims/intrinsics.rs | 57 ++++++++++++++++++++++++--------- tests/run-pass/portable-simd.rs | 48 +++++++++++++++++++++------ 2 files changed, 80 insertions(+), 25 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index f713721f5840..5bebc52b7828 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -356,7 +356,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "simd_shr" | "simd_and" | "simd_or" - | "simd_eq" => { + | "simd_xor" + | "simd_eq" + | "simd_ne" + | "simd_lt" + | "simd_le" + | "simd_gt" + | "simd_ge" => { + use mir::BinOp; + let &[ref left, ref right] = check_arg_count(args)?; let (left, left_len) = this.operand_to_simd(left)?; let (right, right_len) = this.operand_to_simd(right)?; @@ -366,16 +374,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert_eq!(dest_len, right_len); let op = match intrinsic_name { - "simd_add" => mir::BinOp::Add, - "simd_sub" => mir::BinOp::Sub, - "simd_mul" => mir::BinOp::Mul, - "simd_div" => mir::BinOp::Div, - "simd_rem" => mir::BinOp::Rem, - "simd_shl" => mir::BinOp::Shl, - "simd_shr" => mir::BinOp::Shr, - "simd_and" => mir::BinOp::BitAnd, - "simd_or" => mir::BinOp::BitOr, - "simd_eq" => mir::BinOp::Eq, + "simd_add" => BinOp::Add, + "simd_sub" => BinOp::Sub, + "simd_mul" => BinOp::Mul, + "simd_div" => BinOp::Div, + "simd_rem" => BinOp::Rem, + "simd_shl" => BinOp::Shl, + "simd_shr" => BinOp::Shr, + "simd_and" => BinOp::BitAnd, + "simd_or" => BinOp::BitOr, + "simd_xor" => BinOp::BitXor, + "simd_eq" => BinOp::Eq, + "simd_ne" => BinOp::Ne, + "simd_lt" => BinOp::Lt, + "simd_le" => BinOp::Le, + "simd_gt" => BinOp::Gt, + "simd_ge" => BinOp::Ge, _ => unreachable!(), }; @@ -384,7 +398,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let right = this.read_immediate(&this.mplace_index(&right, i)?.into())?; let dest = this.mplace_index(&dest, i)?; let (val, overflowed, ty) = this.overflowing_binary_op(op, &left, &right)?; - if matches!(op, mir::BinOp::Shl | mir::BinOp::Shr) { + if matches!(op, BinOp::Shl | BinOp::Shr) { // Shifts have extra UB as SIMD operations that the MIR binop does not have. // See . if overflowed { @@ -392,27 +406,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_ub_format!("overflowing shift by {} in `{}` in SIMD lane {}", r_val, intrinsic_name, i); } } - if matches!(op, mir::BinOp::Eq) { + if matches!(op, BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge) { // Special handling for boolean-returning operations assert_eq!(ty, this.tcx.types.bool); let val = val.to_bool().unwrap(); let val = bool_to_simd_element(val, dest.layout.size); this.write_scalar(val, &dest.into())?; } else { + assert_ne!(ty, this.tcx.types.bool); assert_eq!(ty, dest.layout.ty); this.write_scalar(val, &dest.into())?; } } } - "simd_reduce_any" => { + "simd_reduce_any" | "simd_reduce_all" => { let &[ref op] = check_arg_count(args)?; let (op, op_len) = this.operand_to_simd(op)?; - let mut res = false; // the neutral element + // the neutral element + let mut res = match intrinsic_name { + "simd_reduce_any" => false, + "simd_reduce_all" => true, + _ => bug!(), + }; + for i in 0..op_len { let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; let val = simd_element_to_bool(op)?; - res = res | val; + res = match intrinsic_name { + "simd_reduce_any" => res | val, + "simd_reduce_all" => res & val, + _ => bug!(), + }; } this.write_scalar(Scalar::from_bool(res), dest)?; diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index c0c1ecd0235a..d43e7be8b192 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -12,6 +12,14 @@ fn simd_ops_f32() { assert_eq!(a / f32x4::splat(2.0), f32x4::splat(5.0)); assert_eq!(a % b, f32x4::from_array([0.0, 0.0, 1.0, 2.0])); assert_eq!(b.abs(), f32x4::from_array([1.0, 2.0, 3.0, 4.0])); + + // FIXME use Mask::from_array once simd_cast is implemented. + assert_eq!(a.lanes_eq(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([0, -1, 0, 0]))); + assert_eq!(a.lanes_ne(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([-1, 0, -1, -1]))); + assert_eq!(a.lanes_le(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([0, -1, -1, 0]))); + assert_eq!(a.lanes_lt(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([0, 0, -1, 0]))); + assert_eq!(a.lanes_ge(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([-1, -1, 0, -1]))); + assert_eq!(a.lanes_gt(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([-1, 0, 0, -1]))); } fn simd_ops_f64() { @@ -25,30 +33,48 @@ fn simd_ops_f64() { assert_eq!(a / f64x4::splat(2.0), f64x4::splat(5.0)); assert_eq!(a % b, f64x4::from_array([0.0, 0.0, 1.0, 2.0])); assert_eq!(b.abs(), f64x4::from_array([1.0, 2.0, 3.0, 4.0])); + + // FIXME use Mask::from_array once simd_cast is implemented. + assert_eq!(a.lanes_eq(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([0, -1, 0, 0]))); + assert_eq!(a.lanes_ne(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([-1, 0, -1, -1]))); + assert_eq!(a.lanes_le(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([0, -1, -1, 0]))); + assert_eq!(a.lanes_lt(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([0, 0, -1, 0]))); + assert_eq!(a.lanes_ge(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([-1, -1, 0, -1]))); + assert_eq!(a.lanes_gt(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([-1, 0, 0, -1]))); } fn simd_ops_i32() { let a = i32x4::splat(10); - let b = i32x4::from_array([1, 2, 3, 4]); - assert_eq!(-b, i32x4::from_array([-1, -2, -3, -4])); - assert_eq!(a + b, i32x4::from_array([11, 12, 13, 14])); - assert_eq!(a - b, i32x4::from_array([9, 8, 7, 6])); - assert_eq!(a * b, i32x4::from_array([10, 20, 30, 40])); - assert_eq!(a / b, i32x4::from_array([10, 5, 3, 2])); + let b = i32x4::from_array([1, 2, 3, -4]); + assert_eq!(-b, i32x4::from_array([-1, -2, -3, 4])); + assert_eq!(a + b, i32x4::from_array([11, 12, 13, 6])); + assert_eq!(a - b, i32x4::from_array([9, 8, 7, 14])); + assert_eq!(a * b, i32x4::from_array([10, 20, 30, -40])); + assert_eq!(a / b, i32x4::from_array([10, 5, 3, -2])); assert_eq!(a / i32x4::splat(2), i32x4::splat(5)); assert_eq!(i32x2::splat(i32::MIN) / i32x2::splat(-1), i32x2::splat(i32::MIN)); assert_eq!(a % b, i32x4::from_array([0, 0, 1, 2])); assert_eq!(i32x2::splat(i32::MIN) % i32x2::splat(-1), i32x2::splat(0)); - assert_eq!(b << i32x4::splat(2), i32x4::from_array([4, 8, 12, 16])); - assert_eq!(b >> i32x4::splat(1), i32x4::from_array([0, 1, 1, 2])); + assert_eq!(b << i32x4::splat(2), i32x4::from_array([4, 8, 12, -16])); + assert_eq!(b >> i32x4::splat(1), i32x4::from_array([0, 1, 1, -2])); assert_eq!(b & i32x4::splat(2), i32x4::from_array([0, 2, 2, 0])); - assert_eq!(b | i32x4::splat(2), i32x4::from_array([3, 2, 3, 6])); + assert_eq!(b | i32x4::splat(2), i32x4::from_array([3, 2, 3, -2])); + assert_eq!(b ^ i32x4::splat(2), i32x4::from_array([3, 0, 1, -2])); + + // FIXME use Mask::from_array once simd_cast is implemented. + assert_eq!(a.lanes_eq(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([0, -1, 0, 0]))); + assert_eq!(a.lanes_ne(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([-1, 0, -1, -1]))); + assert_eq!(a.lanes_le(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([0, -1, -1, 0]))); + assert_eq!(a.lanes_lt(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([0, 0, -1, 0]))); + assert_eq!(a.lanes_ge(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([-1, -1, 0, -1]))); + assert_eq!(a.lanes_gt(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([-1, 0, 0, -1]))); } fn simd_intrinsics() { extern "platform-intrinsic" { fn simd_eq(x: T, y: T) -> U; fn simd_reduce_any(x: T) -> bool; + fn simd_reduce_all(x: T) -> bool; fn simd_select(m: M, yes: T, no: T) -> T; } unsafe { @@ -60,6 +86,10 @@ fn simd_intrinsics() { assert!(!simd_reduce_any(i32x4::splat(0))); assert!(simd_reduce_any(i32x4::splat(-1))); + assert!(simd_reduce_any(i32x2::from_array([0, -1]))); + assert!(!simd_reduce_all(i32x4::splat(0))); + assert!(simd_reduce_all(i32x4::splat(-1))); + assert!(!simd_reduce_all(i32x2::from_array([0, -1]))); assert_eq!(simd_select(i8x4::from_array([0, -1, -1, 0]), a, b), i32x4::from_array([1, 10, 10, 4])); assert_eq!(simd_select(i8x4::from_array([0, -1, -1, 0]), b, a), i32x4::from_array([10, 2, 10, 10])); From ec0e513c6433db787cff2b1b2f09886e9cfa7e76 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Mar 2022 17:26:32 -0500 Subject: [PATCH 2909/5092] rustup --- rust-version | 2 +- .../{available-concurrency.rs => available-parallelism.rs} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/run-pass/{available-concurrency.rs => available-parallelism.rs} (100%) diff --git a/rust-version b/rust-version index 56281423c527..0742c6178958 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -45660949132222ba7ec0905649b2affd68e0e13c +c274e4969f058b1c644243181ece9f829efa7594 diff --git a/tests/run-pass/available-concurrency.rs b/tests/run-pass/available-parallelism.rs similarity index 100% rename from tests/run-pass/available-concurrency.rs rename to tests/run-pass/available-parallelism.rs From 8e97599af47ba3a1e4ed2185b8d0dddd9c69f0dd Mon Sep 17 00:00:00 2001 From: asquared31415 <34665709+asquared31415@users.noreply.github.com> Date: Sat, 5 Feb 2022 20:41:29 -0500 Subject: [PATCH 2910/5092] allow varargs for libc::open when it is allowed by the second argument --- src/shims/posix/foreign_items.rs | 5 +- src/shims/posix/fs.rs | 41 +++++++---- .../fs/unix_open_missing_required_mode.rs | 16 +++++ .../fs/unix_open_too_many_args.rs | 16 +++++ tests/run-pass/fs.rs | 69 +++++++++++++++---- 5 files changed, 117 insertions(+), 30 deletions(-) create mode 100644 tests/compile-fail/fs/unix_open_missing_required_mode.rs create mode 100644 tests/compile-fail/fs/unix_open_too_many_args.rs diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 83b4032cd98a..02fb7089c34d 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -55,8 +55,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "open" | "open64" => { - let &[ref path, ref flag, ref mode] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let result = this.open(path, flag, mode)?; + // `open` is variadic, the third argument is only present when the second argument has O_CREAT (or on linux O_TMPFILE, but miri doesn't support that) set + this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?; + let result = this.open(args)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fcntl" => { diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 36c076037708..7956cfe4dcef 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -474,23 +474,18 @@ fn maybe_sync_file( impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn open( - &mut self, - path_op: &OpTy<'tcx, Tag>, - flag_op: &OpTy<'tcx, Tag>, - mode_op: &OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, i32> { + fn open(&mut self, args: &[OpTy<'tcx, Tag>]) -> InterpResult<'tcx, i32> { + if args.len() < 2 || args.len() > 3 { + throw_ub_format!( + "incorrect number of arguments for `open`: got {}, expected 2 or 3", + args.len() + ); + } + let this = self.eval_context_mut(); - let flag = this.read_scalar(flag_op)?.to_i32()?; - - // Get the mode. On macOS, the argument type `mode_t` is actually `u16`, but - // C integer promotion rules mean that on the ABI level, it gets passed as `u32` - // (see https://github.com/rust-lang/rust/issues/71915). - let mode = this.read_scalar(mode_op)?.to_u32()?; - if mode != 0o666 { - throw_unsup_format!("non-default mode 0o{:o} is not supported", mode); - } + let path_op = &args[0]; + let flag = this.read_scalar(&args[1])?.to_i32()?; let mut options = OpenOptions::new(); @@ -535,6 +530,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let o_creat = this.eval_libc_i32("O_CREAT")?; if flag & o_creat != 0 { + // Get the mode. On macOS, the argument type `mode_t` is actually `u16`, but + // C integer promotion rules mean that on the ABI level, it gets passed as `u32` + // (see https://github.com/rust-lang/rust/issues/71915). + let mode = if let Some(arg) = args.get(2) { + this.read_scalar(arg)?.to_u32()? + } else { + throw_ub_format!( + "incorrect number of arguments for `open` with `O_CREAT`: got {}, expected 3", + args.len() + ); + }; + + if mode != 0o666 { + throw_unsup_format!("non-default mode 0o{:o} is not supported", mode); + } + mirror |= o_creat; let o_excl = this.eval_libc_i32("O_EXCL")?; diff --git a/tests/compile-fail/fs/unix_open_missing_required_mode.rs b/tests/compile-fail/fs/unix_open_missing_required_mode.rs new file mode 100644 index 000000000000..2bac72912544 --- /dev/null +++ b/tests/compile-fail/fs/unix_open_missing_required_mode.rs @@ -0,0 +1,16 @@ +// ignore-windows: No libc on Windows +// compile-flags: -Zmiri-disable-isolation + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + test_file_open_missing_needed_mode(); +} + +fn test_file_open_missing_needed_mode() { + let name = b"missing_arg.txt\0"; + let name_ptr = name.as_ptr().cast::(); + let _fd = unsafe { libc::open(name_ptr, libc::O_CREAT) }; //~ ERROR Undefined Behavior: incorrect number of arguments for `open` with `O_CREAT`: got 2, expected 3 +} diff --git a/tests/compile-fail/fs/unix_open_too_many_args.rs b/tests/compile-fail/fs/unix_open_too_many_args.rs new file mode 100644 index 000000000000..9df7415d3133 --- /dev/null +++ b/tests/compile-fail/fs/unix_open_too_many_args.rs @@ -0,0 +1,16 @@ +// ignore-windows: No libc on Windows +// compile-flags: -Zmiri-disable-isolation + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + test_open_too_many_args(); +} + +fn test_open_too_many_args() { + let name = b"too_many_args.txt\0"; + let name_ptr = name.as_ptr().cast::(); + let _fd = unsafe { libc::open(name_ptr, libc::O_RDONLY, 0, 0) }; //~ ERROR Undefined Behavior: incorrect number of arguments for `open`: got 4, expected 2 or 3 +} diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 568b7ab4e3b7..9ab1d4c03383 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -5,13 +5,10 @@ extern crate libc; -use std::fs::{ - File, create_dir, OpenOptions, remove_dir, remove_dir_all, remove_file, rename, -}; use std::ffi::CString; -use std::io::{Read, Write, Error, ErrorKind, Result, Seek, SeekFrom}; -use std::path::{PathBuf, Path}; - +use std::fs::{create_dir, remove_dir, remove_dir_all, remove_file, rename, File, OpenOptions}; +use std::io::{Error, ErrorKind, Read, Result, Seek, SeekFrom, Write}; +use std::path::{Path, PathBuf}; fn main() { test_file(); @@ -26,6 +23,11 @@ fn main() { test_rename(); test_directory(); test_dup_stdout_stderr(); + + // These all require unix, if the test is changed to no longer `ignore-windows`, move these to a unix test + test_file_open_unix_allow_two_args(); + test_file_open_unix_needs_three_args(); + test_file_open_unix_extra_third_arg(); } fn tmp() -> PathBuf { @@ -41,7 +43,8 @@ fn tmp() -> PathBuf { #[cfg(not(windows))] return PathBuf::from(tmp.replace("\\", "/")); - }).unwrap_or_else(|_| std::env::temp_dir()) + }) + .unwrap_or_else(|_| std::env::temp_dir()) } /// Prepare: compute filename and make sure the file does not exist. @@ -93,6 +96,39 @@ fn test_file() { remove_file(&path).unwrap(); } +fn test_file_open_unix_allow_two_args() { + use std::os::unix::ffi::OsStrExt; + + let path = prepare_with_content("test_file_open_unix_allow_two_args.txt", &[]); + + let mut name = path.into_os_string(); + name.push("\0"); + let name_ptr = name.as_bytes().as_ptr().cast::(); + let _fd = unsafe { libc::open(name_ptr, libc::O_RDONLY) }; +} + +fn test_file_open_unix_needs_three_args() { + use std::os::unix::ffi::OsStrExt; + + let path = prepare_with_content("test_file_open_unix_needs_three_args.txt", &[]); + + let mut name = path.into_os_string(); + name.push("\0"); + let name_ptr = name.as_bytes().as_ptr().cast::(); + let _fd = unsafe { libc::open(name_ptr, libc::O_CREAT, 0o666) }; +} + +fn test_file_open_unix_extra_third_arg() { + use std::os::unix::ffi::OsStrExt; + + let path = prepare_with_content("test_file_open_unix_extra_third_arg.txt", &[]); + + let mut name = path.into_os_string(); + name.push("\0"); + let name_ptr = name.as_bytes().as_ptr().cast::(); + let _fd = unsafe { libc::open(name_ptr, libc::O_RDONLY, 42) }; +} + fn test_file_clone() { let bytes = b"Hello, World!\n"; let path = prepare_with_content("miri_test_fs_file_clone.txt", bytes); @@ -115,7 +151,10 @@ fn test_file_create_new() { // Creating a new file that doesn't yet exist should succeed. OpenOptions::new().write(true).create_new(true).open(&path).unwrap(); // Creating a new file that already exists should fail. - assert_eq!(ErrorKind::AlreadyExists, OpenOptions::new().write(true).create_new(true).open(&path).unwrap_err().kind()); + assert_eq!( + ErrorKind::AlreadyExists, + OpenOptions::new().write(true).create_new(true).open(&path).unwrap_err().kind() + ); // Optionally creating a new file that already exists should succeed. OpenOptions::new().write(true).create(true).open(&path).unwrap(); @@ -235,7 +274,6 @@ fn test_symlink() { symlink_file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); - #[cfg(unix)] { use std::os::unix::ffi::OsStrExt; @@ -250,7 +288,9 @@ fn test_symlink() { // Make the buf one byte larger than it needs to be, // and check that the last byte is not overwritten. let mut large_buf = vec![0xFF; expected_path.len() + 1]; - let res = unsafe { libc::readlink(symlink_c_ptr, large_buf.as_mut_ptr().cast(), large_buf.len()) }; + let res = unsafe { + libc::readlink(symlink_c_ptr, large_buf.as_mut_ptr().cast(), large_buf.len()) + }; // Check that the resovled path was properly written into the buf. assert_eq!(&large_buf[..(large_buf.len() - 1)], expected_path); assert_eq!(large_buf.last(), Some(&0xFF)); @@ -259,18 +299,21 @@ fn test_symlink() { // Test that the resolved path is truncated if the provided buffer // is too small. let mut small_buf = [0u8; 2]; - let res = unsafe { libc::readlink(symlink_c_ptr, small_buf.as_mut_ptr().cast(), small_buf.len()) }; + let res = unsafe { + libc::readlink(symlink_c_ptr, small_buf.as_mut_ptr().cast(), small_buf.len()) + }; assert_eq!(small_buf, &expected_path[..small_buf.len()]); assert_eq!(res, small_buf.len() as isize); // Test that we report a proper error for a missing path. let bad_path = CString::new("MIRI_MISSING_FILE_NAME").unwrap(); - let res = unsafe { libc::readlink(bad_path.as_ptr(), small_buf.as_mut_ptr().cast(), small_buf.len()) }; + let res = unsafe { + libc::readlink(bad_path.as_ptr(), small_buf.as_mut_ptr().cast(), small_buf.len()) + }; assert_eq!(res, -1); assert_eq!(Error::last_os_error().kind(), ErrorKind::NotFound); } - // Test that metadata of a symbolic link is correct. check_metadata(bytes, &symlink_path).unwrap(); // Test that the metadata of a symbolic link is correct when not following it. From 3ed8ad4423684a006e8db194c91f585798b500ab Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Mar 2022 18:46:14 -0500 Subject: [PATCH 2911/5092] avoid repeated string matching, and add more simd_reduce intrinsics --- src/machine.rs | 2 ++ src/shims/intrinsics.rs | 62 ++++++++++++++++++++++++--------- tests/run-pass/portable-simd.rs | 7 ++++ 3 files changed, 55 insertions(+), 16 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index a75ac844902f..481808dc7819 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -267,6 +267,7 @@ pub struct PrimitiveLayouts<'tcx> { pub u8: TyAndLayout<'tcx>, pub u32: TyAndLayout<'tcx>, pub usize: TyAndLayout<'tcx>, + pub bool: TyAndLayout<'tcx>, } impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> { @@ -279,6 +280,7 @@ impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> { u8: layout_cx.layout_of(layout_cx.tcx.types.u8)?, u32: layout_cx.layout_of(layout_cx.tcx.types.u32)?, usize: layout_cx.layout_of(layout_cx.tcx.types.usize)?, + bool: layout_cx.layout_of(layout_cx.tcx.types.bool)?, }) } } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 5bebc52b7828..532eb08b191b 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -324,12 +324,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert_eq!(dest_len, op_len); + enum Op { + MirOp(mir::UnOp), + Abs, + } + let which = match intrinsic_name { + "simd_neg" => Op::MirOp(mir::UnOp::Neg), + "simd_fabs" => Op::Abs, + _ => unreachable!(), + }; + for i in 0..dest_len { let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; let dest = this.mplace_index(&dest, i)?; - let val = match intrinsic_name { - "simd_neg" => this.unary_op(mir::UnOp::Neg, &op)?.to_scalar()?, - "simd_fabs" => { + let val = match which { + Op::MirOp(mir_op) => this.unary_op(mir_op, &op)?.to_scalar()?, + Op::Abs => { // Works for f32 and f64. let ty::Float(float_ty) = op.layout.ty.kind() else { bug!("simd_fabs operand is not a float") @@ -341,7 +351,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx FloatTy::F64 => Scalar::from_f64(op.to_f64()?.abs()), } } - _ => bug!(), }; this.write_scalar(val, &dest.into())?; } @@ -419,28 +428,49 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } - "simd_reduce_any" | "simd_reduce_all" => { + #[rustfmt::skip] + | "simd_reduce_and" + | "simd_reduce_or" + | "simd_reduce_xor" + | "simd_reduce_any" + | "simd_reduce_all" => { + use mir::BinOp; + let &[ref op] = check_arg_count(args)?; let (op, op_len) = this.operand_to_simd(op)?; - // the neutral element - let mut res = match intrinsic_name { - "simd_reduce_any" => false, - "simd_reduce_all" => true, - _ => bug!(), + let imm_from_bool = + |b| ImmTy::from_scalar(Scalar::from_bool(b), this.machine.layouts.bool); + + enum Op { + MirOp(BinOp), + MirOpBool(BinOp), + } + // The initial value is the neutral element. + let (which, init) = match intrinsic_name { + "simd_reduce_and" => (Op::MirOp(BinOp::BitAnd), ImmTy::from_int(-1, dest.layout)), + "simd_reduce_or" => (Op::MirOp(BinOp::BitOr), ImmTy::from_int(0, dest.layout)), + "simd_reduce_xor" => (Op::MirOp(BinOp::BitXor), ImmTy::from_int(0, dest.layout)), + "simd_reduce_any" => (Op::MirOpBool(BinOp::BitOr), imm_from_bool(false)), + "simd_reduce_all" => (Op::MirOpBool(BinOp::BitAnd), imm_from_bool(true)), + _ => unreachable!(), }; + let mut res = init; for i in 0..op_len { let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; - let val = simd_element_to_bool(op)?; - res = match intrinsic_name { - "simd_reduce_any" => res | val, - "simd_reduce_all" => res & val, - _ => bug!(), + res = match which { + Op::MirOp(mir_op) => { + this.binary_op(mir_op, &res, &op)? + } + Op::MirOpBool(mir_op) => { + let op = imm_from_bool(simd_element_to_bool(op)?); + this.binary_op(mir_op, &res, &op)? + } }; } - this.write_scalar(Scalar::from_bool(res), dest)?; + this.write_immediate(*res, dest)?; } "simd_select" => { let &[ref mask, ref yes, ref no] = check_arg_count(args)?; diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index d43e7be8b192..ef8a5752b7cc 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -68,6 +68,13 @@ fn simd_ops_i32() { assert_eq!(a.lanes_lt(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([0, 0, -1, 0]))); assert_eq!(a.lanes_ge(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([-1, -1, 0, -1]))); assert_eq!(a.lanes_gt(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([-1, 0, 0, -1]))); + + assert_eq!(a.horizontal_and(), 10); + assert_eq!(b.horizontal_and(), 0); + assert_eq!(a.horizontal_or(), 10); + assert_eq!(b.horizontal_or(), -1); + assert_eq!(a.horizontal_xor(), 0); + assert_eq!(b.horizontal_xor(), -4); } fn simd_intrinsics() { From b491b72673e0b6ae43ce7e14195082537749cc24 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Mar 2022 19:02:00 -0500 Subject: [PATCH 2912/5092] implement simd_reduce_{add,mul} --- src/shims/intrinsics.rs | 29 +++++++++++++++++++++++++---- tests/run-pass/portable-simd.rs | 4 ++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 532eb08b191b..670e3cb1b8ac 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -382,7 +382,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert_eq!(dest_len, left_len); assert_eq!(dest_len, right_len); - let op = match intrinsic_name { + let mir_op = match intrinsic_name { "simd_add" => BinOp::Add, "simd_sub" => BinOp::Sub, "simd_mul" => BinOp::Mul, @@ -406,8 +406,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let left = this.read_immediate(&this.mplace_index(&left, i)?.into())?; let right = this.read_immediate(&this.mplace_index(&right, i)?.into())?; let dest = this.mplace_index(&dest, i)?; - let (val, overflowed, ty) = this.overflowing_binary_op(op, &left, &right)?; - if matches!(op, BinOp::Shl | BinOp::Shr) { + let (val, overflowed, ty) = this.overflowing_binary_op(mir_op, &left, &right)?; + if matches!(mir_op, BinOp::Shl | BinOp::Shr) { // Shifts have extra UB as SIMD operations that the MIR binop does not have. // See . if overflowed { @@ -415,7 +415,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_ub_format!("overflowing shift by {} in `{}` in SIMD lane {}", r_val, intrinsic_name, i); } } - if matches!(op, BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge) { + if matches!(mir_op, BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge) { // Special handling for boolean-returning operations assert_eq!(ty, this.tcx.types.bool); let val = val.to_bool().unwrap(); @@ -469,7 +469,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } }; } + this.write_immediate(*res, dest)?; + } + #[rustfmt::skip] + | "simd_reduce_add_ordered" + | "simd_reduce_mul_ordered" => { + use mir::BinOp; + let &[ref op, ref init] = check_arg_count(args)?; + let (op, op_len) = this.operand_to_simd(op)?; + let init = this.read_immediate(init)?; + + let mir_op = match intrinsic_name { + "simd_reduce_add_ordered" => BinOp::Add, + "simd_reduce_mul_ordered" => BinOp::Mul, + _ => unreachable!(), + }; + + let mut res = init; + for i in 0..op_len { + let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; + res = this.binary_op(mir_op, &res, &op)?; + } this.write_immediate(*res, dest)?; } "simd_select" => { diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index ef8a5752b7cc..9d1ca12a9f10 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -75,6 +75,10 @@ fn simd_ops_i32() { assert_eq!(b.horizontal_or(), -1); assert_eq!(a.horizontal_xor(), 0); assert_eq!(b.horizontal_xor(), -4); + assert_eq!(a.horizontal_sum(), 40); + assert_eq!(b.horizontal_sum(), 2); + assert_eq!(a.horizontal_product(), 100*100); + assert_eq!(b.horizontal_product(), 6*-4); } fn simd_intrinsics() { From 9810a147a777e1cea91dd01a946fa6a0baf97e62 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Mar 2022 22:59:23 -0500 Subject: [PATCH 2913/5092] add extra tests for shifts with negative offsets --- tests/run-pass/integer-ops.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/integer-ops.rs b/tests/run-pass/integer-ops.rs index fde220d8f35e..f5c1a7a5ff21 100644 --- a/tests/run-pass/integer-ops.rs +++ b/tests/run-pass/integer-ops.rs @@ -1,13 +1,24 @@ +// compile-flags: -Coverflow-checks=off #![allow(arithmetic_overflow)] pub fn main() { - // This tests that do (not) do sign extension properly when loading integers + // This tests that we do (not) do sign extension properly when loading integers assert_eq!(u32::MAX as i64, 4294967295); assert_eq!(i32::MIN as i64, -2147483648); assert_eq!(i8::MAX, 127); assert_eq!(i8::MIN, -128); + // Shifts with negative offsets are subtle. + assert_eq!(13 << -2i8, 13 << 254); + assert_eq!(13 << i8::MIN, 13); + assert_eq!(13 << -1i16, 13 << u16::MAX); + assert_eq!(13 << i16::MIN, 13); + assert_eq!(13i128 << -2i8, 13i128 << 254); + assert_eq!(13i128 << i8::MIN, 13); + assert_eq!(13i128 << -1i16, 13i128 << u16::MAX); + assert_eq!(13i128 << i16::MIN, 13); + assert_eq!(i32::from_str_radix("A", 16), Ok(10)); let n = -0b1000_0000i8; From 21d36ffd04b0472aebebd7cf447cac74c90d8b47 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Mar 2022 23:03:14 -0500 Subject: [PATCH 2914/5092] also test f32/f64 simd_reduce --- tests/run-pass/portable-simd.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 9d1ca12a9f10..5d7420604bb7 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -20,6 +20,11 @@ fn simd_ops_f32() { assert_eq!(a.lanes_lt(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([0, 0, -1, 0]))); assert_eq!(a.lanes_ge(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([-1, -1, 0, -1]))); assert_eq!(a.lanes_gt(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([-1, 0, 0, -1]))); + + assert_eq!(a.horizontal_sum(), 40.0); + assert_eq!(b.horizontal_sum(), 2.0); + assert_eq!(a.horizontal_product(), 100.0*100.0); + assert_eq!(b.horizontal_product(), -24.0); } fn simd_ops_f64() { @@ -41,6 +46,11 @@ fn simd_ops_f64() { assert_eq!(a.lanes_lt(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([0, 0, -1, 0]))); assert_eq!(a.lanes_ge(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([-1, -1, 0, -1]))); assert_eq!(a.lanes_gt(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([-1, 0, 0, -1]))); + + assert_eq!(a.horizontal_sum(), 40.0); + assert_eq!(b.horizontal_sum(), 2.0); + assert_eq!(a.horizontal_product(), 100.0*100.0); + assert_eq!(b.horizontal_product(), -24.0); } fn simd_ops_i32() { @@ -78,7 +88,7 @@ fn simd_ops_i32() { assert_eq!(a.horizontal_sum(), 40); assert_eq!(b.horizontal_sum(), 2); assert_eq!(a.horizontal_product(), 100*100); - assert_eq!(b.horizontal_product(), 6*-4); + assert_eq!(b.horizontal_product(), -24); } fn simd_intrinsics() { From 594a70a28901efa14c8119242c5692027dbd8eb9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Mar 2022 09:39:32 -0500 Subject: [PATCH 2915/5092] rustup --- rust-version | 2 +- src/thread.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 0742c6178958..109a8080b07f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c274e4969f058b1c644243181ece9f829efa7594 +8876ca3dd46b99fe7e6ad937f11493d37996231e diff --git a/src/thread.rs b/src/thread.rs index a5deceb6e71d..b2f2a8098de2 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -574,7 +574,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let allocation = tcx.eval_static_initializer(def_id)?; // Create a fresh allocation with this content. let new_alloc = - this.memory.allocate_with(allocation.clone(), MiriMemoryKind::Tls.into()); + this.memory.allocate_with(allocation.inner().clone(), MiriMemoryKind::Tls.into()); this.machine.threads.set_thread_local_alloc(def_id, new_alloc); Ok(new_alloc) } From db06d4998fa8e64c290a7ae439fb2f8aefb2223e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 6 Mar 2022 13:58:41 -0500 Subject: [PATCH 2916/5092] implement simd_cast, simd_as --- src/shims/intrinsics.rs | 39 +++++ .../intrinsics/simd-float-to-int.rs | 7 + tests/run-pass/portable-simd.rs | 141 ++++++++++++++---- 3 files changed, 161 insertions(+), 26 deletions(-) create mode 100644 tests/compile-fail/intrinsics/simd-float-to-int.rs diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 670e3cb1b8ac..2f29ec4553d4 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -515,6 +515,45 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_immediate(*val, &dest.into())?; } } + #[rustfmt::skip] + "simd_cast" | "simd_as" => { + let &[ref op] = check_arg_count(args)?; + let (op, op_len) = this.operand_to_simd(op)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + assert_eq!(dest_len, op_len); + + let safe_cast = intrinsic_name == "simd_as"; + + for i in 0..dest_len { + let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; + let dest = this.mplace_index(&dest, i)?; + + let val = match (op.layout.ty.kind(), dest.layout.ty.kind()) { + // Int-to-(int|float): always safe + (ty::Int(_) | ty::Uint(_), ty::Int(_) | ty::Uint(_) | ty::Float(_)) => + this.misc_cast(&op, dest.layout.ty)?, + // Float-to-float: always safe + (ty::Float(_), ty::Float(_)) => + this.misc_cast(&op, dest.layout.ty)?, + // Float-to-int in safe mode + (ty::Float(_), ty::Int(_) | ty::Uint(_)) if safe_cast => + this.misc_cast(&op, dest.layout.ty)?, + // Float-to-int in unchecked mode + (ty::Float(FloatTy::F32), ty::Int(_) | ty::Uint(_)) if !safe_cast => + this.float_to_int_unchecked(op.to_scalar()?.to_f32()?, dest.layout.ty)?.into(), + (ty::Float(FloatTy::F64), ty::Int(_) | ty::Uint(_)) if !safe_cast => + this.float_to_int_unchecked(op.to_scalar()?.to_f64()?, dest.layout.ty)?.into(), + _ => + throw_unsup_format!( + "Unsupported SIMD cast from element type {} to {}", + op.layout.ty, + dest.layout.ty + ), + }; + this.write_immediate(val, &dest.into())?; + } + } // Atomic operations "atomic_load" => this.atomic_load(args, dest, AtomicReadOp::SeqCst)?, diff --git a/tests/compile-fail/intrinsics/simd-float-to-int.rs b/tests/compile-fail/intrinsics/simd-float-to-int.rs new file mode 100644 index 000000000000..88d5a7a466f0 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-float-to-int.rs @@ -0,0 +1,7 @@ +// error-pattern: cannot be represented in target type `i32` +#![feature(portable_simd)] +use std::simd::*; + +fn main() { unsafe { + let _x : i32x2 = f32x2::from_array([f32::MAX, f32::MIN]).to_int_unchecked(); +} } diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 5d7420604bb7..022e8c91f970 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -13,17 +13,16 @@ fn simd_ops_f32() { assert_eq!(a % b, f32x4::from_array([0.0, 0.0, 1.0, 2.0])); assert_eq!(b.abs(), f32x4::from_array([1.0, 2.0, 3.0, 4.0])); - // FIXME use Mask::from_array once simd_cast is implemented. - assert_eq!(a.lanes_eq(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([0, -1, 0, 0]))); - assert_eq!(a.lanes_ne(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([-1, 0, -1, -1]))); - assert_eq!(a.lanes_le(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([0, -1, -1, 0]))); - assert_eq!(a.lanes_lt(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([0, 0, -1, 0]))); - assert_eq!(a.lanes_ge(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([-1, -1, 0, -1]))); - assert_eq!(a.lanes_gt(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([-1, 0, 0, -1]))); + assert_eq!(a.lanes_eq(f32x4::splat(5.0) * b), Mask::from_array([false, true, false, false])); + assert_eq!(a.lanes_ne(f32x4::splat(5.0) * b), Mask::from_array([true, false, true, true])); + assert_eq!(a.lanes_le(f32x4::splat(5.0) * b), Mask::from_array([false, true, true, false])); + assert_eq!(a.lanes_lt(f32x4::splat(5.0) * b), Mask::from_array([false, false, true, false])); + assert_eq!(a.lanes_ge(f32x4::splat(5.0) * b), Mask::from_array([true, true, false, true])); + assert_eq!(a.lanes_gt(f32x4::splat(5.0) * b), Mask::from_array([true, false, false, true])); assert_eq!(a.horizontal_sum(), 40.0); assert_eq!(b.horizontal_sum(), 2.0); - assert_eq!(a.horizontal_product(), 100.0*100.0); + assert_eq!(a.horizontal_product(), 100.0 * 100.0); assert_eq!(b.horizontal_product(), -24.0); } @@ -39,17 +38,16 @@ fn simd_ops_f64() { assert_eq!(a % b, f64x4::from_array([0.0, 0.0, 1.0, 2.0])); assert_eq!(b.abs(), f64x4::from_array([1.0, 2.0, 3.0, 4.0])); - // FIXME use Mask::from_array once simd_cast is implemented. - assert_eq!(a.lanes_eq(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([0, -1, 0, 0]))); - assert_eq!(a.lanes_ne(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([-1, 0, -1, -1]))); - assert_eq!(a.lanes_le(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([0, -1, -1, 0]))); - assert_eq!(a.lanes_lt(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([0, 0, -1, 0]))); - assert_eq!(a.lanes_ge(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([-1, -1, 0, -1]))); - assert_eq!(a.lanes_gt(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([-1, 0, 0, -1]))); + assert_eq!(a.lanes_eq(f64x4::splat(5.0) * b), Mask::from_array([false, true, false, false])); + assert_eq!(a.lanes_ne(f64x4::splat(5.0) * b), Mask::from_array([true, false, true, true])); + assert_eq!(a.lanes_le(f64x4::splat(5.0) * b), Mask::from_array([false, true, true, false])); + assert_eq!(a.lanes_lt(f64x4::splat(5.0) * b), Mask::from_array([false, false, true, false])); + assert_eq!(a.lanes_ge(f64x4::splat(5.0) * b), Mask::from_array([true, true, false, true])); + assert_eq!(a.lanes_gt(f64x4::splat(5.0) * b), Mask::from_array([true, false, false, true])); assert_eq!(a.horizontal_sum(), 40.0); assert_eq!(b.horizontal_sum(), 2.0); - assert_eq!(a.horizontal_product(), 100.0*100.0); + assert_eq!(a.horizontal_product(), 100.0 * 100.0); assert_eq!(b.horizontal_product(), -24.0); } @@ -71,13 +69,12 @@ fn simd_ops_i32() { assert_eq!(b | i32x4::splat(2), i32x4::from_array([3, 2, 3, -2])); assert_eq!(b ^ i32x4::splat(2), i32x4::from_array([3, 0, 1, -2])); - // FIXME use Mask::from_array once simd_cast is implemented. - assert_eq!(a.lanes_eq(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([0, -1, 0, 0]))); - assert_eq!(a.lanes_ne(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([-1, 0, -1, -1]))); - assert_eq!(a.lanes_le(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([0, -1, -1, 0]))); - assert_eq!(a.lanes_lt(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([0, 0, -1, 0]))); - assert_eq!(a.lanes_ge(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([-1, -1, 0, -1]))); - assert_eq!(a.lanes_gt(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([-1, 0, 0, -1]))); + assert_eq!(a.lanes_eq(i32x4::splat(5) * b), Mask::from_array([false, true, false, false])); + assert_eq!(a.lanes_ne(i32x4::splat(5) * b), Mask::from_array([true, false, true, true])); + assert_eq!(a.lanes_le(i32x4::splat(5) * b), Mask::from_array([false, true, true, false])); + assert_eq!(a.lanes_lt(i32x4::splat(5) * b), Mask::from_array([false, false, true, false])); + assert_eq!(a.lanes_ge(i32x4::splat(5) * b), Mask::from_array([true, true, false, true])); + assert_eq!(a.lanes_gt(i32x4::splat(5) * b), Mask::from_array([true, false, false, true])); assert_eq!(a.horizontal_and(), 10); assert_eq!(b.horizontal_and(), 0); @@ -87,10 +84,94 @@ fn simd_ops_i32() { assert_eq!(b.horizontal_xor(), -4); assert_eq!(a.horizontal_sum(), 40); assert_eq!(b.horizontal_sum(), 2); - assert_eq!(a.horizontal_product(), 100*100); + assert_eq!(a.horizontal_product(), 100 * 100); assert_eq!(b.horizontal_product(), -24); } +fn simd_mask() { + let intmask = Mask::from_int(i32x4::from_array([0, -1, 0, 0])); + assert_eq!(intmask, Mask::from_array([false, true, false, false])); + assert_eq!(intmask.to_array(), [false, true, false, false]); +} + +fn simd_cast() { + // between integer types + assert_eq!(i32x4::from_array([1, 2, 3, -4]), i16x4::from_array([1, 2, 3, -4]).cast()); + assert_eq!(i16x4::from_array([1, 2, 3, -4]), i32x4::from_array([1, 2, 3, -4]).cast()); + assert_eq!(i32x4::from_array([1, -1, 3, 4]), u64x4::from_array([1, u64::MAX, 3, 4]).cast()); + + // float -> int + assert_eq!( + i8x4::from_array([127, -128, 127, -128]), + f32x4::from_array([127.99, -128.99, 999.0, -999.0]).cast() + ); + assert_eq!( + i32x4::from_array([0, 1, -1, 2147483520]), + f32x4::from_array([ + -0.0, + /*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd), + /*-0x1.19999ap+0*/ f32::from_bits(0xbf8ccccd), + 2147483520.0 + ]) + .cast() + ); + assert_eq!( + i32x8::from_array([i32::MAX, i32::MIN, i32::MAX, i32::MIN, i32::MAX, i32::MIN, 0, 0]), + f32x8::from_array([ + 2147483648.0f32, + -2147483904.0f32, + f32::MAX, + f32::MIN, + f32::INFINITY, + f32::NEG_INFINITY, + f32::NAN, + -f32::NAN, + ]) + .cast() + ); + + // int -> float + assert_eq!( + f32x4::from_array([ + -2147483648.0, + /*0x1.26580cp+30*/ f32::from_bits(0x4e932c06), + 16777220.0, + -16777220.0, + ]), + i32x4::from_array([-2147483647i32, 1234567890i32, 16777219i32, -16777219i32]).cast() + ); + + // float -> float + assert_eq!( + f32x4::from_array([f32::INFINITY, f32::INFINITY, f32::NEG_INFINITY, f32::NEG_INFINITY]), + f64x4::from_array([f64::MAX, f64::INFINITY, f64::MIN, f64::NEG_INFINITY]).cast() + ); + + // unchecked casts + unsafe { + assert_eq!( + i32x4::from_array([0, 1, -1, 2147483520]), + f32x4::from_array([ + -0.0, + /*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd), + /*-0x1.19999ap+0*/ f32::from_bits(0xbf8ccccd), + 2147483520.0 + ]) + .to_int_unchecked() + ); + assert_eq!( + u64x4::from_array([0, 10000000000000000, u64::MAX - 2047, 9223372036854775808]), + f64x4::from_array([ + -0.99999999999, + 1e16, + (u64::MAX - 1024) as f64, + 9223372036854775808.0 + ]) + .to_int_unchecked() + ); + } +} + fn simd_intrinsics() { extern "platform-intrinsic" { fn simd_eq(x: T, y: T) -> U; @@ -112,14 +193,22 @@ fn simd_intrinsics() { assert!(simd_reduce_all(i32x4::splat(-1))); assert!(!simd_reduce_all(i32x2::from_array([0, -1]))); - assert_eq!(simd_select(i8x4::from_array([0, -1, -1, 0]), a, b), i32x4::from_array([1, 10, 10, 4])); - assert_eq!(simd_select(i8x4::from_array([0, -1, -1, 0]), b, a), i32x4::from_array([10, 2, 10, 10])); + assert_eq!( + simd_select(i8x4::from_array([0, -1, -1, 0]), a, b), + i32x4::from_array([1, 10, 10, 4]) + ); + assert_eq!( + simd_select(i8x4::from_array([0, -1, -1, 0]), b, a), + i32x4::from_array([10, 2, 10, 10]) + ); } } fn main() { + simd_mask(); simd_ops_f32(); simd_ops_f64(); simd_ops_i32(); + simd_cast(); simd_intrinsics(); } From 9851b743c1a4a1fdb62579c2c8bb6d6f543a7028 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 6 Mar 2022 14:31:45 -0500 Subject: [PATCH 2917/5092] implement simd_reduce_min/max --- src/shims/intrinsics.rs | 50 ++++++++++++++++++++++++++------- tests/run-pass/portable-simd.rs | 12 ++++++++ 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 2f29ec4553d4..6f1685369803 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -433,7 +433,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "simd_reduce_or" | "simd_reduce_xor" | "simd_reduce_any" - | "simd_reduce_all" => { + | "simd_reduce_all" + | "simd_reduce_max" + | "simd_reduce_min" => { use mir::BinOp; let &[ref op] = check_arg_count(args)?; @@ -445,19 +447,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx enum Op { MirOp(BinOp), MirOpBool(BinOp), + Max, + Min, } - // The initial value is the neutral element. - let (which, init) = match intrinsic_name { - "simd_reduce_and" => (Op::MirOp(BinOp::BitAnd), ImmTy::from_int(-1, dest.layout)), - "simd_reduce_or" => (Op::MirOp(BinOp::BitOr), ImmTy::from_int(0, dest.layout)), - "simd_reduce_xor" => (Op::MirOp(BinOp::BitXor), ImmTy::from_int(0, dest.layout)), - "simd_reduce_any" => (Op::MirOpBool(BinOp::BitOr), imm_from_bool(false)), - "simd_reduce_all" => (Op::MirOpBool(BinOp::BitAnd), imm_from_bool(true)), + let which = match intrinsic_name { + "simd_reduce_and" => Op::MirOp(BinOp::BitAnd), + "simd_reduce_or" => Op::MirOp(BinOp::BitOr), + "simd_reduce_xor" => Op::MirOp(BinOp::BitXor), + "simd_reduce_any" => Op::MirOpBool(BinOp::BitOr), + "simd_reduce_all" => Op::MirOpBool(BinOp::BitAnd), + "simd_reduce_max" => Op::Max, + "simd_reduce_min" => Op::Min, _ => unreachable!(), }; - let mut res = init; - for i in 0..op_len { + // Initialize with first lane, then proceed with the rest. + let mut res = this.read_immediate(&this.mplace_index(&op, 0)?.into())?; + if matches!(which, Op::MirOpBool(_)) { + // Convert to `bool` scalar. + res = imm_from_bool(simd_element_to_bool(res)?); + } + for i in 1..op_len { let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; res = match which { Op::MirOp(mir_op) => { @@ -467,6 +477,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let op = imm_from_bool(simd_element_to_bool(op)?); this.binary_op(mir_op, &res, &op)? } + Op::Max => { + // if `op > res`... + if this.binary_op(BinOp::Gt, &op, &res)?.to_scalar()?.to_bool()? { + // update accumulator + op + } else { + // no change + res + } + } + Op::Min => { + // if `op < res`... + if this.binary_op(BinOp::Lt, &op, &res)?.to_scalar()?.to_bool()? { + // update accumulator + op + } else { + // no change + res + } + } }; } this.write_immediate(*res, dest)?; diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 022e8c91f970..ccedf61a3810 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -24,6 +24,10 @@ fn simd_ops_f32() { assert_eq!(b.horizontal_sum(), 2.0); assert_eq!(a.horizontal_product(), 100.0 * 100.0); assert_eq!(b.horizontal_product(), -24.0); + assert_eq!(a.horizontal_max(), 10.0); + assert_eq!(b.horizontal_max(), 3.0); + assert_eq!(a.horizontal_min(), 10.0); + assert_eq!(b.horizontal_min(), -4.0); } fn simd_ops_f64() { @@ -49,6 +53,10 @@ fn simd_ops_f64() { assert_eq!(b.horizontal_sum(), 2.0); assert_eq!(a.horizontal_product(), 100.0 * 100.0); assert_eq!(b.horizontal_product(), -24.0); + assert_eq!(a.horizontal_max(), 10.0); + assert_eq!(b.horizontal_max(), 3.0); + assert_eq!(a.horizontal_min(), 10.0); + assert_eq!(b.horizontal_min(), -4.0); } fn simd_ops_i32() { @@ -86,6 +94,10 @@ fn simd_ops_i32() { assert_eq!(b.horizontal_sum(), 2); assert_eq!(a.horizontal_product(), 100 * 100); assert_eq!(b.horizontal_product(), -24); + assert_eq!(a.horizontal_max(), 10); + assert_eq!(b.horizontal_max(), 3); + assert_eq!(a.horizontal_min(), 10); + assert_eq!(b.horizontal_min(), -4); } fn simd_mask() { From 2f97eb68a0f77d3829151bc57855d42535465a6d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 6 Mar 2022 15:26:15 -0500 Subject: [PATCH 2918/5092] implement simd_fmax/fmin --- src/shims/intrinsics.rs | 139 ++++++++++++++++++++------------ tests/run-pass/portable-simd.rs | 23 ++++-- 2 files changed, 103 insertions(+), 59 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 6f1685369803..7dc4a000d1e8 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -371,7 +371,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "simd_lt" | "simd_le" | "simd_gt" - | "simd_ge" => { + | "simd_ge" + | "simd_fmax" + | "simd_fmin" => { use mir::BinOp; let &[ref left, ref right] = check_arg_count(args)?; @@ -382,23 +384,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert_eq!(dest_len, left_len); assert_eq!(dest_len, right_len); - let mir_op = match intrinsic_name { - "simd_add" => BinOp::Add, - "simd_sub" => BinOp::Sub, - "simd_mul" => BinOp::Mul, - "simd_div" => BinOp::Div, - "simd_rem" => BinOp::Rem, - "simd_shl" => BinOp::Shl, - "simd_shr" => BinOp::Shr, - "simd_and" => BinOp::BitAnd, - "simd_or" => BinOp::BitOr, - "simd_xor" => BinOp::BitXor, - "simd_eq" => BinOp::Eq, - "simd_ne" => BinOp::Ne, - "simd_lt" => BinOp::Lt, - "simd_le" => BinOp::Le, - "simd_gt" => BinOp::Gt, - "simd_ge" => BinOp::Ge, + enum Op { + MirOp(BinOp), + FMax, + FMin, + } + let which = match intrinsic_name { + "simd_add" => Op::MirOp(BinOp::Add), + "simd_sub" => Op::MirOp(BinOp::Sub), + "simd_mul" => Op::MirOp(BinOp::Mul), + "simd_div" => Op::MirOp(BinOp::Div), + "simd_rem" => Op::MirOp(BinOp::Rem), + "simd_shl" => Op::MirOp(BinOp::Shl), + "simd_shr" => Op::MirOp(BinOp::Shr), + "simd_and" => Op::MirOp(BinOp::BitAnd), + "simd_or" => Op::MirOp(BinOp::BitOr), + "simd_xor" => Op::MirOp(BinOp::BitXor), + "simd_eq" => Op::MirOp(BinOp::Eq), + "simd_ne" => Op::MirOp(BinOp::Ne), + "simd_lt" => Op::MirOp(BinOp::Lt), + "simd_le" => Op::MirOp(BinOp::Le), + "simd_gt" => Op::MirOp(BinOp::Gt), + "simd_ge" => Op::MirOp(BinOp::Ge), + "simd_fmax" => Op::FMax, + "simd_fmin" => Op::FMin, _ => unreachable!(), }; @@ -406,26 +415,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let left = this.read_immediate(&this.mplace_index(&left, i)?.into())?; let right = this.read_immediate(&this.mplace_index(&right, i)?.into())?; let dest = this.mplace_index(&dest, i)?; - let (val, overflowed, ty) = this.overflowing_binary_op(mir_op, &left, &right)?; - if matches!(mir_op, BinOp::Shl | BinOp::Shr) { - // Shifts have extra UB as SIMD operations that the MIR binop does not have. - // See . - if overflowed { - let r_val = right.to_scalar()?.to_bits(right.layout.size)?; - throw_ub_format!("overflowing shift by {} in `{}` in SIMD lane {}", r_val, intrinsic_name, i); + let val = match which { + Op::MirOp(mir_op) => { + let (val, overflowed, ty) = this.overflowing_binary_op(mir_op, &left, &right)?; + if matches!(mir_op, BinOp::Shl | BinOp::Shr) { + // Shifts have extra UB as SIMD operations that the MIR binop does not have. + // See . + if overflowed { + let r_val = right.to_scalar()?.to_bits(right.layout.size)?; + throw_ub_format!("overflowing shift by {} in `{}` in SIMD lane {}", r_val, intrinsic_name, i); + } + } + if matches!(mir_op, BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge) { + // Special handling for boolean-returning operations + assert_eq!(ty, this.tcx.types.bool); + let val = val.to_bool().unwrap(); + bool_to_simd_element(val, dest.layout.size) + } else { + assert_ne!(ty, this.tcx.types.bool); + assert_eq!(ty, dest.layout.ty); + val + } } - } - if matches!(mir_op, BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge) { - // Special handling for boolean-returning operations - assert_eq!(ty, this.tcx.types.bool); - let val = val.to_bool().unwrap(); - let val = bool_to_simd_element(val, dest.layout.size); - this.write_scalar(val, &dest.into())?; - } else { - assert_ne!(ty, this.tcx.types.bool); - assert_eq!(ty, dest.layout.ty); - this.write_scalar(val, &dest.into())?; - } + Op::FMax => { + assert!(matches!(dest.layout.ty.kind(), ty::Float(_))); + this.max_op(&left, &right)?.to_scalar()? + } + Op::FMin => { + assert!(matches!(dest.layout.ty.kind(), ty::Float(_))); + this.min_op(&left, &right)?.to_scalar()? + } + }; + this.write_scalar(val, &dest.into())?; } } #[rustfmt::skip] @@ -478,24 +499,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.binary_op(mir_op, &res, &op)? } Op::Max => { - // if `op > res`... - if this.binary_op(BinOp::Gt, &op, &res)?.to_scalar()?.to_bool()? { - // update accumulator - op - } else { - // no change - res - } + this.max_op(&res, &op)? } Op::Min => { - // if `op < res`... - if this.binary_op(BinOp::Lt, &op, &res)?.to_scalar()?.to_bool()? { - // update accumulator - op - } else { - // no change - res - } + this.min_op(&res, &op)? } }; } @@ -1071,4 +1078,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => bug!("`float_to_int_unchecked` called with non-int output type {:?}", dest_ty), }) } + + fn max_op( + &self, + left: &ImmTy<'tcx, Tag>, + right: &ImmTy<'tcx, Tag>, + ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { + let this = self.eval_context_ref(); + Ok(if this.binary_op(BinOp::Gt, left, right)?.to_scalar()?.to_bool()? { + *left + } else { + *right + }) + } + + fn min_op( + &self, + left: &ImmTy<'tcx, Tag>, + right: &ImmTy<'tcx, Tag>, + ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { + let this = self.eval_context_ref(); + Ok(if this.binary_op(BinOp::Lt, left, right)?.to_scalar()?.to_bool()? { + *left + } else { + *right + }) + } } diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index ccedf61a3810..817d18a45d4b 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -12,6 +12,8 @@ fn simd_ops_f32() { assert_eq!(a / f32x4::splat(2.0), f32x4::splat(5.0)); assert_eq!(a % b, f32x4::from_array([0.0, 0.0, 1.0, 2.0])); assert_eq!(b.abs(), f32x4::from_array([1.0, 2.0, 3.0, 4.0])); + assert_eq!(a.max(b * f32x4::splat(4.0)), f32x4::from_array([10.0, 10.0, 12.0, 10.0])); + assert_eq!(a.min(b * f32x4::splat(4.0)), f32x4::from_array([4.0, 8.0, 10.0, -16.0])); assert_eq!(a.lanes_eq(f32x4::splat(5.0) * b), Mask::from_array([false, true, false, false])); assert_eq!(a.lanes_ne(f32x4::splat(5.0) * b), Mask::from_array([true, false, true, true])); @@ -41,6 +43,8 @@ fn simd_ops_f64() { assert_eq!(a / f64x4::splat(2.0), f64x4::splat(5.0)); assert_eq!(a % b, f64x4::from_array([0.0, 0.0, 1.0, 2.0])); assert_eq!(b.abs(), f64x4::from_array([1.0, 2.0, 3.0, 4.0])); + assert_eq!(a.max(b * f64x4::splat(4.0)), f64x4::from_array([10.0, 10.0, 12.0, 10.0])); + assert_eq!(a.min(b * f64x4::splat(4.0)), f64x4::from_array([4.0, 8.0, 10.0, -16.0])); assert_eq!(a.lanes_eq(f64x4::splat(5.0) * b), Mask::from_array([false, true, false, false])); assert_eq!(a.lanes_ne(f64x4::splat(5.0) * b), Mask::from_array([true, false, true, true])); @@ -71,6 +75,12 @@ fn simd_ops_i32() { assert_eq!(i32x2::splat(i32::MIN) / i32x2::splat(-1), i32x2::splat(i32::MIN)); assert_eq!(a % b, i32x4::from_array([0, 0, 1, 2])); assert_eq!(i32x2::splat(i32::MIN) % i32x2::splat(-1), i32x2::splat(0)); + assert_eq!(b.abs(), i32x4::from_array([1, 2, 3, 4])); + // FIXME not a per-lane method (https://github.com/rust-lang/rust/issues/94682) + // assert_eq!(a.max(b * i32x4::splat(4)), i32x4::from_array([10, 10, 12, 10])); + // assert_eq!(a.min(b * i32x4::splat(4)), i32x4::from_array([4, 8, 10, -16])); + + assert_eq!(!b, i32x4::from_array([!1, !2, !3, !-4])); assert_eq!(b << i32x4::splat(2), i32x4::from_array([4, 8, 12, -16])); assert_eq!(b >> i32x4::splat(1), i32x4::from_array([0, 1, 1, -2])); assert_eq!(b & i32x4::splat(2), i32x4::from_array([0, 2, 2, 0])); @@ -84,12 +94,6 @@ fn simd_ops_i32() { assert_eq!(a.lanes_ge(i32x4::splat(5) * b), Mask::from_array([true, true, false, true])); assert_eq!(a.lanes_gt(i32x4::splat(5) * b), Mask::from_array([true, false, false, true])); - assert_eq!(a.horizontal_and(), 10); - assert_eq!(b.horizontal_and(), 0); - assert_eq!(a.horizontal_or(), 10); - assert_eq!(b.horizontal_or(), -1); - assert_eq!(a.horizontal_xor(), 0); - assert_eq!(b.horizontal_xor(), -4); assert_eq!(a.horizontal_sum(), 40); assert_eq!(b.horizontal_sum(), 2); assert_eq!(a.horizontal_product(), 100 * 100); @@ -98,6 +102,13 @@ fn simd_ops_i32() { assert_eq!(b.horizontal_max(), 3); assert_eq!(a.horizontal_min(), 10); assert_eq!(b.horizontal_min(), -4); + + assert_eq!(a.horizontal_and(), 10); + assert_eq!(b.horizontal_and(), 0); + assert_eq!(a.horizontal_or(), 10); + assert_eq!(b.horizontal_or(), -1); + assert_eq!(a.horizontal_xor(), 0); + assert_eq!(b.horizontal_xor(), -4); } fn simd_mask() { From b87a9c90e1ca983eb81778d79b23db8c52eace54 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 6 Mar 2022 16:54:51 -0500 Subject: [PATCH 2919/5092] fix handling of NaNs in simd max/min --- rust-version | 2 +- src/shims/intrinsics.rs | 87 ++++++++++++++++++++------------- tests/run-pass/portable-simd.rs | 26 ++++++++++ 3 files changed, 81 insertions(+), 34 deletions(-) diff --git a/rust-version b/rust-version index 109a8080b07f..a769188204f5 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8876ca3dd46b99fe7e6ad937f11493d37996231e +297273c45b205820a4c055082c71677197a40b55 diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 7dc4a000d1e8..897ebe4ae79f 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -345,7 +345,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx bug!("simd_fabs operand is not a float") }; let op = op.to_scalar()?; - // FIXME: Using host floats. match float_ty { FloatTy::F32 => Scalar::from_f32(op.to_f32()?.abs()), FloatTy::F64 => Scalar::from_f64(op.to_f64()?.abs()), @@ -438,12 +437,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } Op::FMax => { - assert!(matches!(dest.layout.ty.kind(), ty::Float(_))); - this.max_op(&left, &right)?.to_scalar()? + fmax_op(&left, &right)? } Op::FMin => { - assert!(matches!(dest.layout.ty.kind(), ty::Float(_))); - this.min_op(&left, &right)?.to_scalar()? + fmin_op(&left, &right)? } }; this.write_scalar(val, &dest.into())?; @@ -499,10 +496,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.binary_op(mir_op, &res, &op)? } Op::Max => { - this.max_op(&res, &op)? + if matches!(res.layout.ty.kind(), ty::Float(_)) { + ImmTy::from_scalar(fmax_op(&res, &op)?, res.layout) + } else { + // Just boring integers, so NaNs to worry about + if this.binary_op(BinOp::Ge, &res, &op)?.to_scalar()?.to_bool()? { + res + } else { + op + } + } } Op::Min => { - this.min_op(&res, &op)? + if matches!(res.layout.ty.kind(), ty::Float(_)) { + ImmTy::from_scalar(fmin_op(&res, &op)?, res.layout) + } else { + // Just boring integers, so NaNs to worry about + if this.binary_op(BinOp::Le, &res, &op)?.to_scalar()?.to_bool()? { + res + } else { + op + } + } } }; } @@ -1078,30 +1093,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => bug!("`float_to_int_unchecked` called with non-int output type {:?}", dest_ty), }) } - - fn max_op( - &self, - left: &ImmTy<'tcx, Tag>, - right: &ImmTy<'tcx, Tag>, - ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { - let this = self.eval_context_ref(); - Ok(if this.binary_op(BinOp::Gt, left, right)?.to_scalar()?.to_bool()? { - *left - } else { - *right - }) - } - - fn min_op( - &self, - left: &ImmTy<'tcx, Tag>, - right: &ImmTy<'tcx, Tag>, - ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { - let this = self.eval_context_ref(); - Ok(if this.binary_op(BinOp::Lt, left, right)?.to_scalar()?.to_bool()? { - *left - } else { - *right - }) - } +} + +fn fmax_op<'tcx>( + left: &ImmTy<'tcx, Tag>, + right: &ImmTy<'tcx, Tag>, +) -> InterpResult<'tcx, Scalar> { + assert_eq!(left.layout.ty, right.layout.ty); + let ty::Float(float_ty) = left.layout.ty.kind() else { + bug!("fmax operand is not a float") + }; + let left = left.to_scalar()?; + let right = right.to_scalar()?; + Ok(match float_ty { + FloatTy::F32 => Scalar::from_f32(left.to_f32()?.max(right.to_f32()?)), + FloatTy::F64 => Scalar::from_f64(left.to_f64()?.max(right.to_f64()?)), + }) +} + +fn fmin_op<'tcx>( + left: &ImmTy<'tcx, Tag>, + right: &ImmTy<'tcx, Tag>, +) -> InterpResult<'tcx, Scalar> { + assert_eq!(left.layout.ty, right.layout.ty); + let ty::Float(float_ty) = left.layout.ty.kind() else { + bug!("fmin operand is not a float") + }; + let left = left.to_scalar()?; + let right = right.to_scalar()?; + Ok(match float_ty { + FloatTy::F32 => Scalar::from_f32(left.to_f32()?.min(right.to_f32()?)), + FloatTy::F64 => Scalar::from_f64(left.to_f64()?.min(right.to_f64()?)), + }) } diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 817d18a45d4b..48297ee4e690 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -30,6 +30,19 @@ fn simd_ops_f32() { assert_eq!(b.horizontal_max(), 3.0); assert_eq!(a.horizontal_min(), 10.0); assert_eq!(b.horizontal_min(), -4.0); + + assert_eq!( + f32x2::from_array([0.0, f32::NAN]).max(f32x2::from_array([f32::NAN, 0.0])), + f32x2::from_array([0.0, 0.0]) + ); + assert_eq!(f32x2::from_array([0.0, f32::NAN]).horizontal_max(), 0.0); + assert_eq!(f32x2::from_array([f32::NAN, 0.0]).horizontal_max(), 0.0); + assert_eq!( + f32x2::from_array([0.0, f32::NAN]).min(f32x2::from_array([f32::NAN, 0.0])), + f32x2::from_array([0.0, 0.0]) + ); + assert_eq!(f32x2::from_array([0.0, f32::NAN]).horizontal_min(), 0.0); + assert_eq!(f32x2::from_array([f32::NAN, 0.0]).horizontal_min(), 0.0); } fn simd_ops_f64() { @@ -61,6 +74,19 @@ fn simd_ops_f64() { assert_eq!(b.horizontal_max(), 3.0); assert_eq!(a.horizontal_min(), 10.0); assert_eq!(b.horizontal_min(), -4.0); + + assert_eq!( + f64x2::from_array([0.0, f64::NAN]).max(f64x2::from_array([f64::NAN, 0.0])), + f64x2::from_array([0.0, 0.0]) + ); + assert_eq!(f64x2::from_array([0.0, f64::NAN]).horizontal_max(), 0.0); + assert_eq!(f64x2::from_array([f64::NAN, 0.0]).horizontal_max(), 0.0); + assert_eq!( + f64x2::from_array([0.0, f64::NAN]).min(f64x2::from_array([f64::NAN, 0.0])), + f64x2::from_array([0.0, 0.0]) + ); + assert_eq!(f64x2::from_array([0.0, f64::NAN]).horizontal_min(), 0.0); + assert_eq!(f64x2::from_array([f64::NAN, 0.0]).horizontal_min(), 0.0); } fn simd_ops_i32() { From c03575275a56112edacd1c5cd26a8eb2d4763b74 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Mar 2022 12:00:27 -0500 Subject: [PATCH 2920/5092] update recommended CI snippet, add GHA example --- README.md | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 3c5af59d3f07..55154356c9da 100644 --- a/README.md +++ b/README.md @@ -144,20 +144,37 @@ endian-sensitive code. ### Running Miri on CI To run Miri on CI, make sure that you handle the case where the latest nightly -does not ship the Miri component because it currently does not build. For -example, you can use the following snippet to always test with the latest -nightly that *does* come with Miri: +does not ship the Miri component because it currently does not build. `rustup +toolchain install --component` knows how to handle this situation, so the +following snippet should always work: ```sh -MIRI_NIGHTLY=nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/miri) -echo "Installing latest nightly with Miri: $MIRI_NIGHTLY" -rustup set profile minimal -rustup override set "$MIRI_NIGHTLY" -rustup component add miri +rustup toolchain install nightly --component miri +rustup override set nightly cargo miri test ``` +Here is an example job for GitHub Actions: + +```yaml + miri: + name: "Miri" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install Miri + run: | + rustup toolchain install nightly --component miri + rustup override set nightly + cargo miri setup + - name: Test with Miri + run: cargo miri test +``` + +The explicit `cargo miri setup` helps to keep the output of the actual test step +clean. + ### Common Problems When using the above instructions, you may encounter a number of confusing compiler From 735bee273690940e9944291c70ab808cbc1062c1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Mar 2022 14:12:59 -0500 Subject: [PATCH 2921/5092] implement simd_saturating intrinsics --- rust-version | 2 +- src/shims/intrinsics.rs | 10 +++++++++- tests/run-pass/portable-simd.rs | 19 ++++++++++++++++++- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index a769188204f5..dcc365ef0ad9 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -297273c45b205820a4c055082c71677197a40b55 +d137c3a7bd3b180317044f8ccb9a8b4b3bb07db3 diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 897ebe4ae79f..49c9c0fb0d96 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -372,7 +372,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "simd_gt" | "simd_ge" | "simd_fmax" - | "simd_fmin" => { + | "simd_fmin" + | "simd_saturating_add" + | "simd_saturating_sub" => { use mir::BinOp; let &[ref left, ref right] = check_arg_count(args)?; @@ -385,6 +387,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx enum Op { MirOp(BinOp), + SaturatingOp(BinOp), FMax, FMin, } @@ -407,6 +410,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "simd_ge" => Op::MirOp(BinOp::Ge), "simd_fmax" => Op::FMax, "simd_fmin" => Op::FMin, + "simd_saturating_add" => Op::SaturatingOp(BinOp::Add), + "simd_saturating_sub" => Op::SaturatingOp(BinOp::Sub), _ => unreachable!(), }; @@ -442,6 +447,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Op::FMin => { fmin_op(&left, &right)? } + Op::SaturatingOp(mir_op) => { + this.saturating_arith(mir_op, &left, &right)? + } }; this.write_scalar(val, &dest.into())?; } diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 48297ee4e690..b87bd4fd6ad2 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -102,10 +102,27 @@ fn simd_ops_i32() { assert_eq!(a % b, i32x4::from_array([0, 0, 1, 2])); assert_eq!(i32x2::splat(i32::MIN) % i32x2::splat(-1), i32x2::splat(0)); assert_eq!(b.abs(), i32x4::from_array([1, 2, 3, 4])); - // FIXME not a per-lane method (https://github.com/rust-lang/rust/issues/94682) + // FIXME not a per-lane method (https://github.com/rust-lang/portable-simd/issues/247) // assert_eq!(a.max(b * i32x4::splat(4)), i32x4::from_array([10, 10, 12, 10])); // assert_eq!(a.min(b * i32x4::splat(4)), i32x4::from_array([4, 8, 10, -16])); + assert_eq!( + i8x4::from_array([i8::MAX, -23, 23, i8::MIN]).saturating_add(i8x4::from_array([1, i8::MIN, i8::MAX, 28])), + i8x4::from_array([i8::MAX, i8::MIN, i8::MAX, -100]) + ); + assert_eq!( + i8x4::from_array([i8::MAX, -28, 27, 42]).saturating_sub(i8x4::from_array([1, i8::MAX, i8::MAX, -80])), + i8x4::from_array([126, i8::MIN, -100, 122]) + ); + assert_eq!( + u8x4::from_array([u8::MAX, 0, 23, 42]).saturating_add(u8x4::from_array([1, 1, u8::MAX, 200])), + u8x4::from_array([u8::MAX, 1, u8::MAX, 242]) + ); + assert_eq!( + u8x4::from_array([u8::MAX, 0, 23, 42]).saturating_sub(u8x4::from_array([1, 1, u8::MAX, 200])), + u8x4::from_array([254, 0, 0, 0]) + ); + assert_eq!(!b, i32x4::from_array([!1, !2, !3, !-4])); assert_eq!(b << i32x4::splat(2), i32x4::from_array([4, 8, 12, -16])); assert_eq!(b >> i32x4::splat(1), i32x4::from_array([0, 1, 1, -2])); From 0088715411c2fcb3ea36cdbb969fb9966d722320 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Mon, 7 Mar 2022 12:46:53 -0500 Subject: [PATCH 2922/5092] Rename MiriMemoryKind::Env to Runtime In preparation to use it for other runtime-internal allocations. --- src/data_race.rs | 2 +- src/machine.rs | 9 +++++---- src/shims/env.rs | 25 +++++++++++++------------ src/stacked_borrows.rs | 2 +- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index a6ef56a0c204..1e91c66b859e 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -743,7 +743,7 @@ impl VClockAlloc { MemoryKind::Machine( MiriMemoryKind::Global | MiriMemoryKind::Machine - | MiriMemoryKind::Env + | MiriMemoryKind::Runtime | MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls, ) diff --git a/src/machine.rs b/src/machine.rs index 481808dc7819..bb43cb95507c 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -71,8 +71,9 @@ pub enum MiriMemoryKind { /// Memory for args, errno, and other parts of the machine-managed environment. /// This memory may leak. Machine, - /// Memory for env vars. Separate from `Machine` because we clean it up and leak-check it. - Env, + /// Memory allocated by the runtime (e.g. env vars). Separate from `Machine` + /// because we clean it up and leak-check it. + Runtime, /// Globals copied from `tcx`. /// This memory may leak. Global, @@ -96,7 +97,7 @@ impl MayLeak for MiriMemoryKind { fn may_leak(self) -> bool { use self::MiriMemoryKind::*; match self { - Rust | C | WinHeap | Env => false, + Rust | C | WinHeap | Runtime => false, Machine | Global | ExternStatic | Tls => true, } } @@ -110,7 +111,7 @@ impl fmt::Display for MiriMemoryKind { C => write!(f, "C heap"), WinHeap => write!(f, "Windows heap"), Machine => write!(f, "machine-managed memory"), - Env => write!(f, "environment variable"), + Runtime => write!(f, "language runtime memory"), Global => write!(f, "global (static or const)"), ExternStatic => write!(f, "extern static"), Tls => write!(f, "thread-local static"), diff --git a/src/shims/env.rs b/src/shims/env.rs index dfd1ef207d96..fd7728688580 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -78,12 +78,12 @@ impl<'tcx> EnvVars<'tcx> { ) -> InterpResult<'tcx> { // Deallocate individual env vars. for (_name, ptr) in ecx.machine.env_vars.map.drain() { - ecx.memory.deallocate(ptr, None, MiriMemoryKind::Env.into())?; + ecx.memory.deallocate(ptr, None, MiriMemoryKind::Runtime.into())?; } // Deallocate environ var list. let environ = ecx.machine.env_vars.environ.unwrap(); let old_vars_ptr = ecx.read_pointer(&environ.into())?; - ecx.memory.deallocate(old_vars_ptr, None, MiriMemoryKind::Env.into())?; + ecx.memory.deallocate(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?; Ok(()) } } @@ -96,7 +96,7 @@ fn alloc_env_var_as_c_str<'mir, 'tcx>( let mut name_osstring = name.to_os_string(); name_osstring.push("="); name_osstring.push(value); - ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Env.into()) + ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Runtime.into()) } fn alloc_env_var_as_wide_str<'mir, 'tcx>( @@ -107,7 +107,7 @@ fn alloc_env_var_as_wide_str<'mir, 'tcx>( let mut name_osstring = name.to_os_string(); name_osstring.push("="); name_osstring.push(value); - ecx.alloc_os_str_as_wide_str(name_osstring.as_os_str(), MiriMemoryKind::Env.into()) + ecx.alloc_os_str_as_wide_str(name_osstring.as_os_str(), MiriMemoryKind::Runtime.into()) } impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -186,7 +186,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Allocate environment block & Store environment variables to environment block. // Final null terminator(block terminator) is added by `alloc_os_str_to_wide_str`. - let envblock_ptr = this.alloc_os_str_as_wide_str(&env_vars, MiriMemoryKind::Env.into())?; + let envblock_ptr = + this.alloc_os_str_as_wide_str(&env_vars, MiriMemoryKind::Runtime.into())?; // If the function succeeds, the return value is a pointer to the environment block of the current process. Ok(envblock_ptr) } @@ -200,7 +201,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.assert_target_os("windows", "FreeEnvironmentStringsW"); let env_block_ptr = this.read_pointer(env_block_op)?; - let result = this.memory.deallocate(env_block_ptr, None, MiriMemoryKind::Env.into()); + let result = this.memory.deallocate(env_block_ptr, None, MiriMemoryKind::Runtime.into()); // If the function succeeds, the return value is nonzero. Ok(result.is_ok() as i32) } @@ -231,7 +232,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some((name, value)) = new { let var_ptr = alloc_env_var_as_c_str(&name, &value, &mut this)?; if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { - this.memory.deallocate(var, None, MiriMemoryKind::Env.into())?; + this.memory.deallocate(var, None, MiriMemoryKind::Runtime.into())?; } this.update_environ()?; Ok(0) // return zero on success @@ -268,7 +269,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if this.ptr_is_null(value_ptr)? { // Delete environment variable `{name}` if let Some(var) = this.machine.env_vars.map.remove(&name) { - this.memory.deallocate(var, None, MiriMemoryKind::Env.into())?; + this.memory.deallocate(var, None, MiriMemoryKind::Runtime.into())?; this.update_environ()?; } Ok(1) // return non-zero on success @@ -276,7 +277,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let value = this.read_os_str_from_wide_str(value_ptr)?; let var_ptr = alloc_env_var_as_wide_str(&name, &value, &mut this)?; if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { - this.memory.deallocate(var, None, MiriMemoryKind::Env.into())?; + this.memory.deallocate(var, None, MiriMemoryKind::Runtime.into())?; } this.update_environ()?; Ok(1) // return non-zero on success @@ -301,7 +302,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } if let Some(old) = success { if let Some(var) = old { - this.memory.deallocate(var, None, MiriMemoryKind::Env.into())?; + this.memory.deallocate(var, None, MiriMemoryKind::Runtime.into())?; } this.update_environ()?; Ok(0) @@ -437,7 +438,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Deallocate the old environ list, if any. if let Some(environ) = this.machine.env_vars.environ { let old_vars_ptr = this.read_pointer(&environ.into())?; - this.memory.deallocate(old_vars_ptr, None, MiriMemoryKind::Env.into())?; + this.memory.deallocate(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?; } else { // No `environ` allocated yet, let's do that. // This is memory backing an extern static, hence `ExternStatic`, not `Env`. @@ -455,7 +456,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tcx = this.tcx; let vars_layout = this.layout_of(tcx.mk_array(tcx.types.usize, u64::try_from(vars.len()).unwrap()))?; - let vars_place = this.allocate(vars_layout, MiriMemoryKind::Env.into())?; + let vars_place = this.allocate(vars_layout, MiriMemoryKind::Runtime.into())?; for (idx, var) in vars.into_iter().enumerate() { let place = this.mplace_field(&vars_place, idx)?; this.write_pointer(var, &place.into())?; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 37ecb749a487..0e47a9e1c3b0 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -535,7 +535,7 @@ impl Stacks { MiriMemoryKind::Global | MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls - | MiriMemoryKind::Env + | MiriMemoryKind::Runtime | MiriMemoryKind::Machine, ) => (extra.base_tag(id), Permission::SharedReadWrite), // Heap allocations we only track precisely when raw pointers are tagged, for now. From 0886419524c5baf61d6f3980e81ba4e0429ac402 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Tue, 22 Feb 2022 17:06:05 -0500 Subject: [PATCH 2923/5092] Implement a readdir64() shim for Linux Partial fix for #1966. --- src/shims/posix/fs.rs | 120 ++++++++++++++----------- src/shims/posix/linux/foreign_items.rs | 8 +- tests/run-pass/fs.rs | 12 +-- 3 files changed, 76 insertions(+), 64 deletions(-) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 7956cfe4dcef..300e3c514b37 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -16,6 +16,7 @@ use rustc_target::abi::{Align, Size}; use crate::*; use helpers::{check_arg_count, immty_from_int_checked, immty_from_uint_checked}; +use shims::os_str::os_str_to_bytes; use shims::time::system_time_to_duration; #[derive(Debug)] @@ -421,6 +422,22 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' } } +/// An open directory, tracked by DirHandler. +#[derive(Debug)] +pub struct OpenDir { + /// The directory reader on the host. + read_dir: ReadDir, + /// The most recent entry returned by readdir() + entry: Pointer>, +} + +impl OpenDir { + fn new(read_dir: ReadDir) -> Self { + // We rely on `free` being a NOP on null pointers. + Self { read_dir, entry: Pointer::null() } + } +} + #[derive(Debug)] pub struct DirHandler { /// Directory iterators used to emulate libc "directory streams", as used in opendir, readdir, @@ -432,7 +449,7 @@ pub struct DirHandler { /// the corresponding ReadDir iterator from this map, and information from the next /// directory entry is returned. When closedir is called, the ReadDir iterator is removed from /// the map. - streams: FxHashMap, + streams: FxHashMap, /// ID number to be used by the next call to opendir next_id: u64, } @@ -441,7 +458,7 @@ impl DirHandler { fn insert_new(&mut self, read_dir: ReadDir) -> u64 { let id = self.next_id; self.next_id += 1; - self.streams.try_insert(id, read_dir).unwrap(); + self.streams.try_insert(id, OpenDir::new(read_dir)).unwrap(); id } } @@ -1207,32 +1224,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn linux_readdir64_r( - &mut self, - dirp_op: &OpTy<'tcx, Tag>, - entry_op: &OpTy<'tcx, Tag>, - result_op: &OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, i32> { + fn linux_readdir64(&mut self, dirp_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - this.assert_target_os("linux", "readdir64_r"); + this.assert_target_os("linux", "readdir64"); let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("`readdir64_r`", reject_with)?; - // Set error code as "EBADF" (bad fd) - return this.handle_not_found(); + this.reject_in_isolation("`readdir`", reject_with)?; + let eacc = this.eval_libc("EBADF")?; + this.set_last_error(eacc)?; + return Ok(Scalar::null_ptr(this)); } - let dir_iter = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { - err_unsup_format!("the DIR pointer passed to readdir64_r did not come from opendir") + let open_dir = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { + err_unsup_format!("the DIR pointer passed to readdir64 did not come from opendir") })?; - match dir_iter.next() { + + let entry = match open_dir.read_dir.next() { Some(Ok(dir_entry)) => { - // Write into entry, write pointer to result, return 0 on success. - // The name is written with write_os_str_to_c_str, while the rest of the + // Write the directory entry into a newly allocated buffer. + // The name is written with write_bytes, while the rest of the // dirent64 struct is written using write_packed_immediates. // For reference: @@ -1244,22 +1258,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // pub d_name: [c_char; 256], // } - let entry_place = this.deref_operand(entry_op)?; - let name_place = this.mplace_field(&entry_place, 4)?; + let mut name = dir_entry.file_name(); // not a Path as there are no separators! + name.push("\0"); // Add a NUL terminator + let name_bytes = os_str_to_bytes(&name)?; + let name_len = u64::try_from(name_bytes.len()).unwrap(); - let file_name = dir_entry.file_name(); // not a Path as there are no separators! - let (name_fits, _) = this.write_os_str_to_c_str( - &file_name, - name_place.ptr, - name_place.layout.size.bytes(), - )?; - if !name_fits { - throw_unsup_format!( - "a directory entry had a name too large to fit in libc::dirent64" - ); - } + let dirent64_layout = this.libc_ty_layout("dirent64")?; + let d_name_offset = dirent64_layout.fields.offset(4 /* d_name */).bytes(); + let size = d_name_offset.checked_add(name_len).unwrap(); - let entry_place = this.deref_operand(entry_op)?; + let entry = + this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::Runtime)?; + + // FIXME: make use of dirent64_layout let ino64_t_layout = this.libc_ty_layout("ino64_t")?; let off64_t_layout = this.libc_ty_layout("off64_t")?; let c_ushort_layout = this.libc_ty_layout("c_ushort")?; @@ -1277,33 +1288,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let imms = [ immty_from_uint_checked(ino, ino64_t_layout)?, // d_ino immty_from_uint_checked(0u128, off64_t_layout)?, // d_off - immty_from_uint_checked(0u128, c_ushort_layout)?, // d_reclen + immty_from_uint_checked(size, c_ushort_layout)?, // d_reclen immty_from_int_checked(file_type, c_uchar_layout)?, // d_type ]; + let entry_layout = this.layout_of(this.tcx.mk_array(this.tcx.types.u8, size))?; + let entry_place = MPlaceTy::from_aligned_ptr(entry, entry_layout); this.write_packed_immediates(&entry_place, &imms)?; - let result_place = this.deref_operand(result_op)?; - this.write_scalar(this.read_scalar(entry_op)?, &result_place.into())?; + let name_ptr = entry.offset(Size::from_bytes(d_name_offset), this)?; + this.memory.write_bytes(name_ptr, name_bytes.iter().copied())?; - Ok(0) + entry } None => { - // end of stream: return 0, assign *result=NULL - this.write_null(&this.deref_operand(result_op)?.into())?; - Ok(0) + // end of stream: return NULL + Pointer::null() } - Some(Err(e)) => - match e.raw_os_error() { - // return positive error number on error - Some(error) => Ok(error), - None => { - throw_unsup_format!( - "the error {} couldn't be converted to a return value", - e - ) - } - }, - } + Some(Err(e)) => { + this.set_last_error_from_io_error(e.kind())?; + Pointer::null() + } + }; + + let open_dir = this.machine.dir_handler.streams.get_mut(&dirp).unwrap(); + let old_entry = std::mem::replace(&mut open_dir.entry, entry); + this.free(old_entry, MiriMemoryKind::Runtime)?; + + Ok(Scalar::from_maybe_pointer(entry, this)) } fn macos_readdir_r( @@ -1325,10 +1336,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return this.handle_not_found(); } - let dir_iter = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { + let open_dir = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { err_unsup_format!("the DIR pointer passed to readdir_r did not come from opendir") })?; - match dir_iter.next() { + match open_dir.read_dir.next() { Some(Ok(dir_entry)) => { // Write into entry, write pointer to result, return 0 on success. // The name is written with write_os_str_to_c_str, while the rest of the @@ -1419,8 +1430,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return this.handle_not_found(); } - if let Some(dir_iter) = this.machine.dir_handler.streams.remove(&dirp) { - drop(dir_iter); + if let Some(open_dir) = this.machine.dir_handler.streams.remove(&dirp) { + this.free(open_dir.entry, MiriMemoryKind::Runtime)?; + drop(open_dir); Ok(0) } else { this.handle_not_found() diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 8d0f8487f5e1..280f24e9ea49 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -43,11 +43,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.opendir(name)?; this.write_scalar(result, dest)?; } - "readdir64_r" => { - let &[ref dirp, ref entry, ref result] = + "readdir64" => { + let &[ref dirp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let result = this.linux_readdir64_r(dirp, entry, result)?; - this.write_scalar(Scalar::from_i32(result), dest)?; + let result = this.linux_readdir64(dirp)?; + this.write_scalar(result, dest)?; } "ftruncate64" => { let &[ref fd, ref length] = diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 9ab1d4c03383..be680131f84a 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -6,7 +6,9 @@ extern crate libc; use std::ffi::CString; -use std::fs::{create_dir, remove_dir, remove_dir_all, remove_file, rename, File, OpenOptions}; +use std::fs::{ + create_dir, read_dir, remove_dir, remove_dir_all, remove_file, rename, File, OpenOptions, +}; use std::io::{Error, ErrorKind, Read, Result, Seek, SeekFrom, Write}; use std::path::{Path, PathBuf}; @@ -374,19 +376,17 @@ fn test_directory() { let path_2 = dir_path.join("test_file_2"); drop(File::create(&path_2).unwrap()); // Test that the files are present inside the directory - /* FIXME(1966) disabled due to missing readdir support let dir_iter = read_dir(&dir_path).unwrap(); let mut file_names = dir_iter.map(|e| e.unwrap().file_name()).collect::>(); file_names.sort_unstable(); - assert_eq!(file_names, vec!["test_file_1", "test_file_2"]); */ + assert_eq!(file_names, vec!["test_file_1", "test_file_2"]); // Clean up the files in the directory remove_file(&path_1).unwrap(); remove_file(&path_2).unwrap(); // Now there should be nothing left in the directory. - /* FIXME(1966) disabled due to missing readdir support - dir_iter = read_dir(&dir_path).unwrap(); + let dir_iter = read_dir(&dir_path).unwrap(); let file_names = dir_iter.map(|e| e.unwrap().file_name()).collect::>(); - assert!(file_names.is_empty());*/ + assert!(file_names.is_empty()); // Deleting the directory should succeed. remove_dir(&dir_path).unwrap(); From 6d3506adef3537c2f3b28f4121cf694971fb0b91 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Mar 2022 18:30:12 -0500 Subject: [PATCH 2924/5092] fs: add and test for DirectoryNotEmpty error variant --- src/helpers.rs | 1 + src/lib.rs | 1 + tests/run-pass/fs.rs | 3 +++ 3 files changed, 5 insertions(+) diff --git a/src/helpers.rs b/src/helpers.rs index 2f1c74a0587e..cae8f5ddb448 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -490,6 +490,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx TimedOut => "ETIMEDOUT", AlreadyExists => "EEXIST", WouldBlock => "EWOULDBLOCK", + DirectoryNotEmpty => "ENOTEMPTY", _ => { throw_unsup_format!( "io error {:?} cannot be translated into a raw os error", diff --git a/src/lib.rs b/src/lib.rs index 9542fb9b9635..6c9b8ee0b8f9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ #![feature(try_blocks)] #![feature(let_else)] #![feature(bool_to_option)] +#![feature(io_error_more)] #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index be680131f84a..7f5553e2f2cb 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -2,6 +2,7 @@ // compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] +#![feature(io_error_more)] extern crate libc; @@ -380,6 +381,8 @@ fn test_directory() { let mut file_names = dir_iter.map(|e| e.unwrap().file_name()).collect::>(); file_names.sort_unstable(); assert_eq!(file_names, vec!["test_file_1", "test_file_2"]); + // Deleting the directory should fail, since it is not empty. + assert_eq!(ErrorKind::DirectoryNotEmpty, remove_dir(&dir_path).unwrap_err().kind()); // Clean up the files in the directory remove_file(&path_1).unwrap(); remove_file(&path_2).unwrap(); From d54c5fb66824246a836f36e6bcf43ce41e356805 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Mar 2022 19:57:44 -0500 Subject: [PATCH 2925/5092] rustup --- rust-version | 2 +- src/shims/backtrace.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index dcc365ef0ad9..de3e19e6b04d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d137c3a7bd3b180317044f8ccb9a8b4b3bb07db3 +89adcc636f94d34a6fc90fa117e28ddf6be7b983 diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index eb25cfd9935f..a73c78b62728 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -105,7 +105,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // which we pass to user code. let fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(fn_instance)); - let num_fields = dest.layout.layout.fields.count(); + let num_fields = dest.layout.fields.count(); if !(4..=5).contains(&num_fields) { // Always mention 5 fields, since the 4-field struct From 3eba7fcf7336c7cebdea4b2c2140c947b6bac67c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Mar 2022 18:48:31 -0500 Subject: [PATCH 2926/5092] implement simd_shuffle --- src/shims/intrinsics.rs | 41 ++++++++++++++++++++++++++++++++- tests/run-pass/portable-simd.rs | 12 ++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 49c9c0fb0d96..43c61091b9e4 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -3,7 +3,7 @@ use std::iter; use log::trace; use rustc_apfloat::{Float, Round}; -use rustc_middle::ty::layout::{IntegerExt, LayoutOf}; +use rustc_middle::ty::layout::{HasParamEnv, IntegerExt, LayoutOf}; use rustc_middle::{mir, mir::BinOp, ty, ty::FloatTy}; use rustc_target::abi::{Align, Integer}; @@ -614,6 +614,45 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_immediate(val, &dest.into())?; } } + "simd_shuffle" => { + let &[ref left, ref right, ref index] = check_arg_count(args)?; + let (left, left_len) = this.operand_to_simd(left)?; + let (right, right_len) = this.operand_to_simd(right)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + // `index` is an array, not a SIMD type + let ty::Array(_, index_len) = index.layout.ty.kind() else { + bug!("simd_shuffle index argument has non-array type {}", index.layout.ty) + }; + let index_len = index_len.eval_usize(*this.tcx, this.param_env()); + + assert_eq!(left_len, right_len); + assert_eq!(index_len, dest_len); + + for i in 0..dest_len { + let src_index: u64 = this + .read_immediate(&this.operand_index(&index, i)?.into())? + .to_scalar()? + .to_u32()? + .into(); + let dest = this.mplace_index(&dest, i)?; + + let val = if src_index < left_len { + this.read_immediate(&this.mplace_index(&left, src_index)?.into())? + } else if src_index < left_len.checked_add(right_len).unwrap() { + this.read_immediate( + &this.mplace_index(&right, src_index - left_len)?.into(), + )? + } else { + bug!( + "simd_shuffle index {} is out of bounds for 2 vectors of size {}", + src_index, + left_len + ); + }; + this.write_immediate(*val, &dest.into())?; + } + } // Atomic operations "atomic_load" => this.atomic_load(args, dest, AtomicReadOp::SeqCst)?, diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index b87bd4fd6ad2..67e4e52a7849 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -238,6 +238,17 @@ fn simd_cast() { } } +fn simd_swizzle() { + use Which::*; + + let a = f32x4::splat(10.0); + let b = f32x4::from_array([1.0, 2.0, 3.0, -4.0]); + + assert_eq!(simd_swizzle!(b, [3, 0, 0, 2]), f32x4::from_array([-4.0, 1.0, 1.0, 3.0])); + assert_eq!(simd_swizzle!(b, [1, 2]), f32x2::from_array([2.0, 3.0])); + assert_eq!(simd_swizzle!(b, a, [First(3), Second(0)]), f32x2::from_array([-4.0, 10.0])); +} + fn simd_intrinsics() { extern "platform-intrinsic" { fn simd_eq(x: T, y: T) -> U; @@ -276,5 +287,6 @@ fn main() { simd_ops_f64(); simd_ops_i32(); simd_cast(); + simd_swizzle(); simd_intrinsics(); } From 576e2bbed5cfa26fdab2af62e1372d1f8fa581d1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Mar 2022 19:18:07 -0500 Subject: [PATCH 2927/5092] implement gather --- src/shims/intrinsics.rs | 27 ++++++++++++++++++++ tests/compile-fail/intrinsics/simd-gather.rs | 9 +++++++ tests/run-pass/portable-simd.rs | 8 ++++++ 3 files changed, 44 insertions(+) create mode 100644 tests/compile-fail/intrinsics/simd-gather.rs diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 43c61091b9e4..54e7118b2593 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -653,6 +653,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_immediate(*val, &dest.into())?; } } + "simd_gather" => { + let &[ref passthru, ref ptrs, ref mask] = check_arg_count(args)?; + let (passthru, passthru_len) = this.operand_to_simd(passthru)?; + let (ptrs, ptrs_len) = this.operand_to_simd(ptrs)?; + let (mask, mask_len) = this.operand_to_simd(mask)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + assert_eq!(dest_len, passthru_len); + assert_eq!(dest_len, ptrs_len); + assert_eq!(dest_len, mask_len); + + for i in 0..dest_len { + let passthru = this.read_immediate(&this.mplace_index(&passthru, i)?.into())?; + let ptr = this.read_immediate(&this.mplace_index(&ptrs, i)?.into())?; + let mask = this.read_immediate(&this.mplace_index(&mask, i)?.into())?; + let dest = this.mplace_index(&dest, i)?; + + let mask = simd_element_to_bool(mask)?; + let val = if mask { + let place = this.deref_operand(&ptr.into())?; + this.read_immediate(&place.into())? + } else { + passthru + }; + this.write_immediate(*val, &dest.into())?; + } + } // Atomic operations "atomic_load" => this.atomic_load(args, dest, AtomicReadOp::SeqCst)?, diff --git a/tests/compile-fail/intrinsics/simd-gather.rs b/tests/compile-fail/intrinsics/simd-gather.rs new file mode 100644 index 000000000000..2fb5da01f106 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-gather.rs @@ -0,0 +1,9 @@ +// error-pattern: out-of-bounds +#![feature(portable_simd)] +use std::simd::*; + +fn main() { unsafe { + let vec: &[i16] = &[10, 11, 12, 13, 14, 15, 16, 17, 18]; + let idxs = Simd::from_array([9, 3, 0, 17]); + let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true), idxs, Simd::splat(0)); +} } diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 67e4e52a7849..ad9dafea4bad 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -249,6 +249,13 @@ fn simd_swizzle() { assert_eq!(simd_swizzle!(b, a, [First(3), Second(0)]), f32x2::from_array([-4.0, 10.0])); } +fn simd_gather_scatter() { + let vec: &[i16] = &[10, 11, 12, 13, 14, 15, 16, 17, 18]; + let idxs = Simd::from_array([9, 3, 0, 17]); + let result = Simd::gather_or_default(&vec, idxs); // Note the lane that is out-of-bounds. + assert_eq!(result, Simd::from_array([0, 13, 10, 0])); +} + fn simd_intrinsics() { extern "platform-intrinsic" { fn simd_eq(x: T, y: T) -> U; @@ -288,5 +295,6 @@ fn main() { simd_ops_i32(); simd_cast(); simd_swizzle(); + simd_gather_scatter(); simd_intrinsics(); } From 41ffce1145efd87e23878ce0802a52557b24d852 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Mar 2022 19:26:40 -0500 Subject: [PATCH 2928/5092] implement simd_scatter --- src/shims/intrinsics.rs | 26 ++++++++++++++++--- tests/compile-fail/intrinsics/simd-gather.rs | 4 +-- tests/compile-fail/intrinsics/simd-scatter.rs | 9 +++++++ tests/run-pass/portable-simd.rs | 6 ++++- 4 files changed, 38 insertions(+), 7 deletions(-) create mode 100644 tests/compile-fail/intrinsics/simd-scatter.rs diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 54e7118b2593..b4416bfa9859 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -570,8 +570,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let no = this.read_immediate(&this.mplace_index(&no, i)?.into())?; let dest = this.mplace_index(&dest, i)?; - let mask = simd_element_to_bool(mask)?; - let val = if mask { yes } else { no }; + let val = if simd_element_to_bool(mask)? { yes } else { no }; this.write_immediate(*val, &dest.into())?; } } @@ -670,8 +669,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mask = this.read_immediate(&this.mplace_index(&mask, i)?.into())?; let dest = this.mplace_index(&dest, i)?; - let mask = simd_element_to_bool(mask)?; - let val = if mask { + let val = if simd_element_to_bool(mask)? { let place = this.deref_operand(&ptr.into())?; this.read_immediate(&place.into())? } else { @@ -680,6 +678,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_immediate(*val, &dest.into())?; } } + "simd_scatter" => { + let &[ref value, ref ptrs, ref mask] = check_arg_count(args)?; + let (value, value_len) = this.operand_to_simd(value)?; + let (ptrs, ptrs_len) = this.operand_to_simd(ptrs)?; + let (mask, mask_len) = this.operand_to_simd(mask)?; + + assert_eq!(ptrs_len, value_len); + assert_eq!(ptrs_len, mask_len); + + for i in 0..ptrs_len { + let value = this.read_immediate(&this.mplace_index(&value, i)?.into())?; + let ptr = this.read_immediate(&this.mplace_index(&ptrs, i)?.into())?; + let mask = this.read_immediate(&this.mplace_index(&mask, i)?.into())?; + + if simd_element_to_bool(mask)? { + let place = this.deref_operand(&ptr.into())?; + this.write_immediate(*value, &place.into())?; + } + } + } // Atomic operations "atomic_load" => this.atomic_load(args, dest, AtomicReadOp::SeqCst)?, diff --git a/tests/compile-fail/intrinsics/simd-gather.rs b/tests/compile-fail/intrinsics/simd-gather.rs index 2fb5da01f106..ae6f048226dd 100644 --- a/tests/compile-fail/intrinsics/simd-gather.rs +++ b/tests/compile-fail/intrinsics/simd-gather.rs @@ -1,9 +1,9 @@ -// error-pattern: out-of-bounds +// error-pattern: pointer to 1 byte starting at offset 9 is out-of-bounds #![feature(portable_simd)] use std::simd::*; fn main() { unsafe { - let vec: &[i16] = &[10, 11, 12, 13, 14, 15, 16, 17, 18]; + let vec: &[i8] = &[10, 11, 12, 13, 14, 15, 16, 17, 18]; let idxs = Simd::from_array([9, 3, 0, 17]); let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true), idxs, Simd::splat(0)); } } diff --git a/tests/compile-fail/intrinsics/simd-scatter.rs b/tests/compile-fail/intrinsics/simd-scatter.rs new file mode 100644 index 000000000000..f46e4f0d4f6a --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-scatter.rs @@ -0,0 +1,9 @@ +// error-pattern: pointer to 1 byte starting at offset 9 is out-of-bounds +#![feature(portable_simd)] +use std::simd::*; + +fn main() { unsafe { + let mut vec: Vec = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; + let idxs = Simd::from_array([9, 3, 0, 17]); + Simd::from_array([-27, 82, -41, 124]).scatter_select_unchecked(&mut vec, Mask::splat(true), idxs); +} } diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index ad9dafea4bad..c046af0bcf52 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -250,10 +250,14 @@ fn simd_swizzle() { } fn simd_gather_scatter() { - let vec: &[i16] = &[10, 11, 12, 13, 14, 15, 16, 17, 18]; + let mut vec: Vec = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; let idxs = Simd::from_array([9, 3, 0, 17]); let result = Simd::gather_or_default(&vec, idxs); // Note the lane that is out-of-bounds. assert_eq!(result, Simd::from_array([0, 13, 10, 0])); + + let idxs = Simd::from_array([9, 3, 0, 0]); + Simd::from_array([-27, 82, -41, 124]).scatter(&mut vec, idxs); + assert_eq!(vec, vec![124, 11, 12, 82, 14, 15, 16, 17, 18]); } fn simd_intrinsics() { From bae720c75b10faf78ebe387bb51c2547daebd34b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 10 Mar 2022 18:56:19 -0500 Subject: [PATCH 2929/5092] add ptr_offset_from OOB test, and update test errors --- tests/compile-fail/intrinsics/copy_null.rs | 2 +- tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs | 2 +- tests/compile-fail/intrinsics/ptr_offset_from_oob.rs | 11 +++++++++++ tests/compile-fail/intrinsics/write_bytes_null.rs | 2 +- tests/compile-fail/null_pointer_deref_zst.rs | 2 +- tests/compile-fail/null_pointer_write_zst.rs | 2 +- 6 files changed, 16 insertions(+), 5 deletions(-) create mode 100644 tests/compile-fail/intrinsics/ptr_offset_from_oob.rs diff --git a/tests/compile-fail/intrinsics/copy_null.rs b/tests/compile-fail/intrinsics/copy_null.rs index 60cb7e4eff51..8f32ad1a760f 100644 --- a/tests/compile-fail/intrinsics/copy_null.rs +++ b/tests/compile-fail/intrinsics/copy_null.rs @@ -9,5 +9,5 @@ fn main() { let mut data = [0u16; 4]; let ptr = &mut data[0] as *mut u16; // Even copying 0 elements from NULL should error. - unsafe { copy_nonoverlapping(std::ptr::null(), ptr, 0); } //~ ERROR: memory access failed: 0x0 is not a valid pointer + unsafe { copy_nonoverlapping(std::ptr::null(), ptr, 0); } //~ ERROR: memory access failed: null pointer is not a valid pointer } diff --git a/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs b/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs index d8a8f66e7aee..248d85d65e24 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs +++ b/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs @@ -1,4 +1,4 @@ -// error-pattern: pointer arithmetic failed: 0x0 is not a valid pointer +// error-pattern: pointer arithmetic failed: null pointer is not a valid pointer fn main() { let x = 0 as *mut i32; diff --git a/tests/compile-fail/intrinsics/ptr_offset_from_oob.rs b/tests/compile-fail/intrinsics/ptr_offset_from_oob.rs new file mode 100644 index 000000000000..ef1ca1e2729d --- /dev/null +++ b/tests/compile-fail/intrinsics/ptr_offset_from_oob.rs @@ -0,0 +1,11 @@ +#![feature(core_intrinsics)] + +use std::intrinsics::ptr_offset_from; + +fn main() { + let start_ptr = &4 as *const _ as *const u8; + let length = 10; + let end_ptr = start_ptr.wrapping_add(length); + // Even if the offset is 0, a dangling OOB pointer is not allowed. + unsafe { ptr_offset_from(end_ptr, end_ptr) }; //~ERROR pointer at offset 10 is out-of-bounds +} diff --git a/tests/compile-fail/intrinsics/write_bytes_null.rs b/tests/compile-fail/intrinsics/write_bytes_null.rs index c3f77b27b4ff..60966f0a94c0 100644 --- a/tests/compile-fail/intrinsics/write_bytes_null.rs +++ b/tests/compile-fail/intrinsics/write_bytes_null.rs @@ -6,5 +6,5 @@ extern "rust-intrinsic" { } fn main() { - unsafe { write_bytes::(std::ptr::null_mut(), 0, 0) }; //~ ERROR memory access failed: 0x0 is not a valid pointer + unsafe { write_bytes::(std::ptr::null_mut(), 0, 0) }; //~ ERROR memory access failed: null pointer is not a valid pointer } diff --git a/tests/compile-fail/null_pointer_deref_zst.rs b/tests/compile-fail/null_pointer_deref_zst.rs index 04617c58f3ce..f3830c078e5e 100644 --- a/tests/compile-fail/null_pointer_deref_zst.rs +++ b/tests/compile-fail/null_pointer_deref_zst.rs @@ -3,6 +3,6 @@ #[allow(deref_nullptr)] fn main() { - let x: () = unsafe { *std::ptr::null() }; //~ ERROR dereferencing pointer failed: 0x0 is not a valid pointer + let x: () = unsafe { *std::ptr::null() }; //~ ERROR dereferencing pointer failed: null pointer is not a valid pointer panic!("this should never print: {:?}", x); } diff --git a/tests/compile-fail/null_pointer_write_zst.rs b/tests/compile-fail/null_pointer_write_zst.rs index 46a8345b1b45..63474d965175 100644 --- a/tests/compile-fail/null_pointer_write_zst.rs +++ b/tests/compile-fail/null_pointer_write_zst.rs @@ -1,6 +1,6 @@ // Some optimizations remove ZST accesses, thus masking this UB. // compile-flags: -Zmir-opt-level=0 -// error-pattern: memory access failed: 0x0 is not a valid pointer +// error-pattern: memory access failed: null pointer is not a valid pointer #[allow(deref_nullptr)] fn main() { From 21ff2f9fcab1baf240fd46a56806c8598246799a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 11 Mar 2022 22:07:43 -0500 Subject: [PATCH 2930/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index de3e19e6b04d..a4c6cd44182c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -89adcc636f94d34a6fc90fa117e28ddf6be7b983 +2c6a29af35a81e20f8af4c32bf1b55c59b89eccd From 27d5b846eed9f92990f4fc47f0e35f514cfc66f0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Mar 2022 09:46:10 -0500 Subject: [PATCH 2931/5092] rustup --- rust-version | 2 +- src/helpers.rs | 2 +- src/shims/backtrace.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index a4c6cd44182c..9885aba10293 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -2c6a29af35a81e20f8af4c32bf1b55c59b89eccd +258256697b8550860be0f6194dec532ac616c2c1 diff --git a/src/helpers.rs b/src/helpers.rs index cae8f5ddb448..e733ea8062dc 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -298,7 +298,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty); let is_unsafe_cell = match v.layout.ty.kind() { ty::Adt(adt, _) => - Some(adt.did) == self.ecx.tcx.lang_items().unsafe_cell_type(), + Some(adt.did()) == self.ecx.tcx.lang_items().unsafe_cell_type(), _ => false, }; if is_unsafe_cell { diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index a73c78b62728..7d069611e268 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -134,7 +134,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dest = this.force_allocation(dest)?; if let ty::Adt(adt, _) = dest.layout.ty.kind() { - if !adt.repr.c() { + if !adt.repr().c() { throw_ub_format!( "miri_resolve_frame must be declared with a `#[repr(C)]` return type" ); From 9a6450af95dd63c6e4f5ca43feff49313692885c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Mar 2022 10:09:15 -0500 Subject: [PATCH 2932/5092] also accept odd number of hex digits; add README section on randomized alignment testing --- Cargo.lock | 7 ------- Cargo.toml | 1 - README.md | 18 +++++++++++++++++- src/bin/miri.rs | 22 +++++----------------- 4 files changed, 22 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 674ce8a2b1ea..35e45800c0ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -155,12 +155,6 @@ dependencies = [ "libc", ] -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - [[package]] name = "humantime" version = "2.1.0" @@ -258,7 +252,6 @@ dependencies = [ "compiletest_rs", "env_logger", "getrandom", - "hex", "libc", "log", "measureme", diff --git a/Cargo.toml b/Cargo.toml index a4d85e39e65d..356f6822fa18 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,6 @@ getrandom = { version = "0.2", features = ["std"] } env_logger = "0.9" log = "0.4" shell-escape = "0.1.4" -hex = "0.4.0" rand = "0.8" smallvec = "1.7" diff --git a/README.md b/README.md index 55154356c9da..8e8670f37751 100644 --- a/README.md +++ b/README.md @@ -175,12 +175,28 @@ Here is an example job for GitHub Actions: The explicit `cargo miri setup` helps to keep the output of the actual test step clean. +### Testing for alignment issues + +Miri can sometimes miss misaligned accesses since allocations can "happen to be" +aligned just right. You can use `-Zmiri-symbolic-alignment-check` to definitely +catch all such issues, but that flag will also cause false positives when code +does manual pointer arithmetic to account for alignment. Another alternative is +to call Miri with various values for `-Zmiri-seed`; that will alter the +randomness that is used to determine allocation base addresses. The following +snippet calls Miri in a loop with different values for the seed: + +``` +for seed in $({ echo obase=16; seq 255; } | bc); do + MIRIFLAGS=-Zmiri-seed=$seed cargo miri test || { echo "Last seed: $seed"; break; }; +done +``` + ### Common Problems When using the above instructions, you may encounter a number of confusing compiler errors. -### "note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace" +#### "note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace" You may see this when trying to get Miri to display a backtrace. By default, Miri doesn't expose any environment to the program, so running diff --git a/src/bin/miri.rs b/src/bin/miri.rs index dd7b0b54f488..a1f7c617f0af 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -15,7 +15,6 @@ use std::num::NonZeroU64; use std::path::PathBuf; use std::str::FromStr; -use hex::FromHexError; use log::debug; use rustc_data_structures::sync::Lrc; @@ -377,22 +376,11 @@ fn main() { if miri_config.seed.is_some() { panic!("Cannot specify -Zmiri-seed multiple times!"); } - let seed_raw = hex::decode(arg.strip_prefix("-Zmiri-seed=").unwrap()) - .unwrap_or_else(|err| match err { - FromHexError::InvalidHexCharacter { .. } => panic!( - "-Zmiri-seed should only contain valid hex digits [0-9a-fA-F]" - ), - FromHexError::OddLength => - panic!("-Zmiri-seed should have an even number of digits"), - err => panic!("unknown error decoding -Zmiri-seed as hex: {:?}", err), - }); - if seed_raw.len() > 8 { - panic!("-Zmiri-seed must be at most 8 bytes, was {}", seed_raw.len()); - } - - let mut bytes = [0; 8]; - bytes[..seed_raw.len()].copy_from_slice(&seed_raw); - miri_config.seed = Some(u64::from_be_bytes(bytes)); + let seed = u64::from_str_radix(arg.strip_prefix("-Zmiri-seed=").unwrap(), 16) + .unwrap_or_else(|_| panic!( + "-Zmiri-seed should only contain valid hex digits [0-9a-fA-F] and fit into a u64 (max 16 characters)" + )); + miri_config.seed = Some(seed); } arg if arg.starts_with("-Zmiri-env-exclude=") => { miri_config From 3c5cb89f638af28b8f645fb73a3210fb66bc725f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Mar 2022 10:14:07 -0500 Subject: [PATCH 2933/5092] exclude TERM by default --- README.md | 5 +++-- src/shims/env.rs | 8 +++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 55154356c9da..9c8efbec2767 100644 --- a/README.md +++ b/README.md @@ -254,8 +254,9 @@ environment variable: `warn` prints a full backtrace when that happen; `warn-nobacktrace` is less verbose. `hide` hides the warning entirely. * `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from the host so that it - cannot be accessed by the program. Can be used multiple times to exclude several variables. On - Windows, the `TERM` environment variable is excluded by default. This has no effect unless + cannot be accessed by the program. Can be used multiple times to exclude several variables. The + `TERM` environment variable is excluded by default to [speed up the test + harness](https://github.com/rust-lang/miri/issues/1702). This has no effect unless `-Zmiri-disable-validation` is also set. * `-Zmiri-env-forward=` forwards the `var` environment variable to the interpreted program. Can be used multiple times to forward several variables. This has no effect if diff --git a/src/shims/env.rs b/src/shims/env.rs index fd7728688580..1916d7d70a41 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -42,11 +42,9 @@ impl<'tcx> EnvVars<'tcx> { forwarded_env_vars: Vec, ) -> InterpResult<'tcx> { let target_os = ecx.tcx.sess.target.os.as_str(); - if target_os == "windows" { - // Temporary hack: Exclude `TERM` var to avoid terminfo trying to open the termcap file. - // Can be removed once https://github.com/rust-lang/miri/issues/1013 is resolved. - excluded_env_vars.push("TERM".to_owned()); - } + // HACK: Exclude `TERM` var to avoid terminfo trying to open the termcap file. + // This is (a) very slow and (b) does not work on Windows. + excluded_env_vars.push("TERM".to_owned()); // Skip the loop entirely if we don't want to forward anything. if ecx.machine.communicate() || !forwarded_env_vars.is_empty() { From 4bd6bc90986987c65f5f3e183032ce0a78fc716b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Mar 2022 10:34:54 -0500 Subject: [PATCH 2934/5092] use dirent64_layout and field projections for writing dirent info --- src/helpers.rs | 12 +++++++++++- src/shims/posix/fs.rs | 20 +++++--------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index e733ea8062dc..84792c2394e3 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -104,9 +104,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.layout_of(ty) } + /// Write a uint of the appropriate size to `dest`. + fn write_uint(&mut self, i: impl Into, dest: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + self.eval_context_mut().write_scalar(Scalar::from_uint(i, dest.layout.size), dest) + } + + /// Write an int of the appropriate size to `dest`. + fn write_int(&mut self, i: impl Into, dest: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + self.eval_context_mut().write_scalar(Scalar::from_int(i, dest.layout.size), dest) + } + /// Write a 0 of the appropriate size to `dest`. fn write_null(&mut self, dest: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { - self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest) + self.write_int(0, dest) } /// Test if this pointer equals 0. diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 300e3c514b37..efb11b3bee9f 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -1270,12 +1270,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let entry = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::Runtime)?; - // FIXME: make use of dirent64_layout - let ino64_t_layout = this.libc_ty_layout("ino64_t")?; - let off64_t_layout = this.libc_ty_layout("off64_t")?; - let c_ushort_layout = this.libc_ty_layout("c_ushort")?; - let c_uchar_layout = this.libc_ty_layout("c_uchar")?; - // If the host is a Unix system, fill in the inode number with its real value. // If not, use 0 as a fallback value. #[cfg(unix)] @@ -1285,15 +1279,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let file_type = this.file_type_to_d_type(dir_entry.file_type())?; - let imms = [ - immty_from_uint_checked(ino, ino64_t_layout)?, // d_ino - immty_from_uint_checked(0u128, off64_t_layout)?, // d_off - immty_from_uint_checked(size, c_ushort_layout)?, // d_reclen - immty_from_int_checked(file_type, c_uchar_layout)?, // d_type - ]; - let entry_layout = this.layout_of(this.tcx.mk_array(this.tcx.types.u8, size))?; - let entry_place = MPlaceTy::from_aligned_ptr(entry, entry_layout); - this.write_packed_immediates(&entry_place, &imms)?; + let entry_place = MPlaceTy::from_aligned_ptr(entry, dirent64_layout); + this.write_uint(ino, &this.mplace_field(&entry_place, 0)?.into())?; // d_ino + this.write_uint(0u128, &this.mplace_field(&entry_place, 1)?.into())?; // d_off + this.write_uint(size, &this.mplace_field(&entry_place, 2)?.into())?; // d_reclen + this.write_int(file_type, &this.mplace_field(&entry_place, 3)?.into())?; // d_type let name_ptr = entry.offset(Size::from_bytes(d_name_offset), this)?; this.memory.write_bytes(name_ptr, name_bytes.iter().copied())?; From 47f8218d0dfcd9f31185f2628d07a993ba6780f5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Mar 2022 11:21:45 -0500 Subject: [PATCH 2935/5092] add write_int_fields to replace write_packed_immediates for stat, lookup fields by name --- src/helpers.rs | 122 +++++++++++++------------- src/shims/posix/fs.rs | 194 +++++++++++++++++++++--------------------- src/shims/time.rs | 35 ++------ 3 files changed, 169 insertions(+), 182 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 84792c2394e3..ba12e0a7e394 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -57,8 +57,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Evaluates the scalar at the specified path. Returns Some(val) /// if the path could be resolved, and None otherwise - fn eval_path_scalar(&mut self, path: &[&str]) -> InterpResult<'tcx, Scalar> { - let this = self.eval_context_mut(); + fn eval_path_scalar(&self, path: &[&str]) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_ref(); let instance = this.resolve_path(path); let cid = GlobalId { instance, promoted: None }; let const_val = this.eval_to_allocation(cid)?; @@ -67,51 +67,98 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Helper function to get a `libc` constant as a `Scalar`. - fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar> { - self.eval_context_mut().eval_path_scalar(&["libc", name]) + fn eval_libc(&self, name: &str) -> InterpResult<'tcx, Scalar> { + self.eval_path_scalar(&["libc", name]) } /// Helper function to get a `libc` constant as an `i32`. - fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { + fn eval_libc_i32(&self, name: &str) -> InterpResult<'tcx, i32> { // TODO: Cache the result. self.eval_libc(name)?.to_i32() } /// Helper function to get a `windows` constant as a `Scalar`. - fn eval_windows(&mut self, module: &str, name: &str) -> InterpResult<'tcx, Scalar> { - self.eval_context_mut().eval_path_scalar(&["std", "sys", "windows", module, name]) + fn eval_windows(&self, module: &str, name: &str) -> InterpResult<'tcx, Scalar> { + self.eval_context_ref().eval_path_scalar(&["std", "sys", "windows", module, name]) } /// Helper function to get a `windows` constant as a `u64`. - fn eval_windows_u64(&mut self, module: &str, name: &str) -> InterpResult<'tcx, u64> { + fn eval_windows_u64(&self, module: &str, name: &str) -> InterpResult<'tcx, u64> { // TODO: Cache the result. self.eval_windows(module, name)?.to_u64() } /// Helper function to get the `TyAndLayout` of a `libc` type - fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> { - let this = self.eval_context_mut(); + 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()); this.layout_of(ty) } /// Helper function to get the `TyAndLayout` of a `windows` type - fn windows_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> { - let this = self.eval_context_mut(); + 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]) .ty(*this.tcx, ty::ParamEnv::reveal_all()); this.layout_of(ty) } - /// Write a uint of the appropriate size to `dest`. - fn write_uint(&mut self, i: impl Into, dest: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { - self.eval_context_mut().write_scalar(Scalar::from_uint(i, dest.layout.size), dest) + /// Project to the given *named* field of the mplace (which must be a struct or union type). + fn mplace_field_named( + &self, + mplace: &MPlaceTy<'tcx, Tag>, + name: &str, + ) -> InterpResult<'tcx, MPlaceTy<'tcx, Tag>> { + let this = self.eval_context_ref(); + let adt = mplace.layout.ty.ty_adt_def().unwrap(); + for (idx, field) in adt.non_enum_variant().fields.iter().enumerate() { + if field.name.as_str() == name { + return this.mplace_field(mplace, idx); + } + } + bug!("No field named {} in type {}", name, mplace.layout.ty); } - /// Write an int of the appropriate size to `dest`. + /// Write an int of the appropriate size to `dest`. The target type may be signed or unsigned, + /// we try to do the right thing anyway. `i128` can fit all integer types except for `u128` so + /// this method is fine for almost all integer types. fn write_int(&mut self, i: impl Into, dest: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { - self.eval_context_mut().write_scalar(Scalar::from_int(i, dest.layout.size), dest) + assert!(dest.layout.abi.is_scalar(), "write_int on non-scalar type {}", dest.layout.ty); + let val = if dest.layout.abi.is_signed() { + Scalar::from_int(i, dest.layout.size) + } else { + Scalar::from_uint(u64::try_from(i.into()).unwrap(), dest.layout.size) + }; + self.eval_context_mut().write_scalar(val, dest) + } + + /// Write the first N fields of the given place. + fn write_int_fields( + &mut self, + values: &[i128], + dest: &MPlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + for (idx, &val) in values.iter().enumerate() { + let field = this.mplace_field(dest, idx)?; + this.write_int(val, &field.into())?; + } + Ok(()) + } + + /// Write the given fields of the given place. + fn write_int_fields_named( + &mut self, + values: &[(&str, i128)], + dest: &MPlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + for &(name, val) in values.iter() { + let field = this.mplace_field_named(dest, name)?; + this.write_int(val, &field.into())?; + } + Ok(()) } /// Write a 0 of the appropriate size to `dest`. @@ -383,27 +430,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - // Writes several `ImmTy`s contiguously into memory. This is useful when you have to pack - // different values into a struct. - fn write_packed_immediates( - &mut self, - place: &MPlaceTy<'tcx, Tag>, - imms: &[ImmTy<'tcx, Tag>], - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - - let mut offset = Size::from_bytes(0); - - for &imm in imms { - this.write_immediate( - *imm, - &place.offset(offset, MemPlaceMeta::None, imm.layout, &*this.tcx)?.into(), - )?; - offset += imm.layout.size; - } - Ok(()) - } - /// Helper function used inside the shims of foreign functions to check that isolation is /// disabled. It returns an error using the `name` of the foreign function if this is not the /// case. @@ -750,26 +776,6 @@ pub fn isolation_abort_error(name: &str) -> InterpResult<'static> { ))) } -pub fn immty_from_int_checked<'tcx>( - int: impl Into, - layout: TyAndLayout<'tcx>, -) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { - let int = int.into(); - Ok(ImmTy::try_from_int(int, layout).ok_or_else(|| { - err_unsup_format!("signed value {:#x} does not fit in {} bits", int, layout.size.bits()) - })?) -} - -pub fn immty_from_uint_checked<'tcx>( - int: impl Into, - layout: TyAndLayout<'tcx>, -) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { - let int = int.into(); - Ok(ImmTy::try_from_uint(int, layout).ok_or_else(|| { - err_unsup_format!("unsigned value {:#x} does not fit in {} bits", int, layout.size.bits()) - })?) -} - pub fn bool_to_simd_element(b: bool, size: Size) -> Scalar { // SIMD uses all-1 as pattern for "true" let val = if b { -1 } else { 0 }; diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index efb11b3bee9f..b71f53cce566 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::{self, layout::LayoutOf}; use rustc_target::abi::{Align, Size}; use crate::*; -use helpers::{check_arg_count, immty_from_int_checked, immty_from_uint_checked}; +use helpers::check_arg_count; use shims::os_str::os_str_to_bytes; use shims::time::system_time_to_duration; @@ -318,45 +318,32 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' let (created_sec, created_nsec) = metadata.created.unwrap_or((0, 0)); let (modified_sec, modified_nsec) = metadata.modified.unwrap_or((0, 0)); - let dev_t_layout = this.libc_ty_layout("dev_t")?; - let mode_t_layout = this.libc_ty_layout("mode_t")?; - let nlink_t_layout = this.libc_ty_layout("nlink_t")?; - let ino_t_layout = this.libc_ty_layout("ino_t")?; - let uid_t_layout = this.libc_ty_layout("uid_t")?; - let gid_t_layout = this.libc_ty_layout("gid_t")?; - let time_t_layout = this.libc_ty_layout("time_t")?; - let long_layout = this.libc_ty_layout("c_long")?; - let off_t_layout = this.libc_ty_layout("off_t")?; - let blkcnt_t_layout = this.libc_ty_layout("blkcnt_t")?; - let blksize_t_layout = this.libc_ty_layout("blksize_t")?; - let uint32_t_layout = this.libc_ty_layout("uint32_t")?; - - let imms = [ - immty_from_uint_checked(0u128, dev_t_layout)?, // st_dev - immty_from_uint_checked(mode, mode_t_layout)?, // st_mode - immty_from_uint_checked(0u128, nlink_t_layout)?, // st_nlink - immty_from_uint_checked(0u128, ino_t_layout)?, // st_ino - immty_from_uint_checked(0u128, uid_t_layout)?, // st_uid - immty_from_uint_checked(0u128, gid_t_layout)?, // st_gid - immty_from_uint_checked(0u128, dev_t_layout)?, // st_rdev - immty_from_uint_checked(0u128, uint32_t_layout)?, // padding - immty_from_uint_checked(access_sec, time_t_layout)?, // st_atime - immty_from_uint_checked(access_nsec, long_layout)?, // st_atime_nsec - immty_from_uint_checked(modified_sec, time_t_layout)?, // st_mtime - immty_from_uint_checked(modified_nsec, long_layout)?, // st_mtime_nsec - immty_from_uint_checked(0u128, time_t_layout)?, // st_ctime - immty_from_uint_checked(0u128, long_layout)?, // st_ctime_nsec - immty_from_uint_checked(created_sec, time_t_layout)?, // st_birthtime - immty_from_uint_checked(created_nsec, long_layout)?, // st_birthtime_nsec - immty_from_uint_checked(metadata.size, off_t_layout)?, // st_size - immty_from_uint_checked(0u128, blkcnt_t_layout)?, // st_blocks - immty_from_uint_checked(0u128, blksize_t_layout)?, // st_blksize - immty_from_uint_checked(0u128, uint32_t_layout)?, // st_flags - immty_from_uint_checked(0u128, uint32_t_layout)?, // st_gen - ]; - let buf = this.deref_operand(buf_op)?; - this.write_packed_immediates(&buf, &imms)?; + this.write_int_fields_named( + &[ + ("st_dev", 0), + ("st_mode", mode.into()), + ("st_nlink", 0), + ("st_ino", 0), + ("st_uid", 0), + ("st_gid", 0), + ("st_rdev", 0), + ("st_atime", access_sec.into()), + ("st_atime_nsec", access_nsec.into()), + ("st_mtime", modified_sec.into()), + ("st_mtime_nsec", modified_nsec.into()), + ("st_ctime", 0), + ("st_ctime_nsec", 0), + ("st_birthtime", created_sec.into()), + ("st_birthtime_nsec", created_nsec.into()), + ("st_size", metadata.size.into()), + ("st_blocks", 0), + ("st_blksize", 0), + ("st_flags", 0), + ("st_gen", 0), + ], + &buf, + )?; Ok(0) } @@ -954,7 +941,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `syscall` function is untyped. This means that all the `statx` parameters are provided // 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_place = { + 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 @@ -1064,44 +1051,55 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) .unwrap_or(Ok((0, 0)))?; - let __u32_layout = this.libc_ty_layout("__u32")?; - let __u64_layout = this.libc_ty_layout("__u64")?; - let __u16_layout = this.libc_ty_layout("__u16")?; - - // Now we transform all this fields into `ImmTy`s and write them to `statxbuf`. We write a - // zero for the unavailable fields. - let imms = [ - immty_from_uint_checked(mask, __u32_layout)?, // stx_mask - immty_from_uint_checked(0u128, __u32_layout)?, // stx_blksize - immty_from_uint_checked(0u128, __u64_layout)?, // stx_attributes - immty_from_uint_checked(0u128, __u32_layout)?, // stx_nlink - immty_from_uint_checked(0u128, __u32_layout)?, // stx_uid - immty_from_uint_checked(0u128, __u32_layout)?, // stx_gid - immty_from_uint_checked(mode, __u16_layout)?, // stx_mode - immty_from_uint_checked(0u128, __u16_layout)?, // statx padding - immty_from_uint_checked(0u128, __u64_layout)?, // stx_ino - immty_from_uint_checked(metadata.size, __u64_layout)?, // stx_size - immty_from_uint_checked(0u128, __u64_layout)?, // stx_blocks - immty_from_uint_checked(0u128, __u64_layout)?, // stx_attributes - immty_from_uint_checked(access_sec, __u64_layout)?, // stx_atime.tv_sec - immty_from_uint_checked(access_nsec, __u32_layout)?, // stx_atime.tv_nsec - immty_from_uint_checked(0u128, __u32_layout)?, // statx_timestamp padding - immty_from_uint_checked(created_sec, __u64_layout)?, // stx_btime.tv_sec - immty_from_uint_checked(created_nsec, __u32_layout)?, // stx_btime.tv_nsec - immty_from_uint_checked(0u128, __u32_layout)?, // statx_timestamp padding - immty_from_uint_checked(0u128, __u64_layout)?, // stx_ctime.tv_sec - immty_from_uint_checked(0u128, __u32_layout)?, // stx_ctime.tv_nsec - immty_from_uint_checked(0u128, __u32_layout)?, // statx_timestamp padding - immty_from_uint_checked(modified_sec, __u64_layout)?, // stx_mtime.tv_sec - immty_from_uint_checked(modified_nsec, __u32_layout)?, // stx_mtime.tv_nsec - immty_from_uint_checked(0u128, __u32_layout)?, // statx_timestamp padding - immty_from_uint_checked(0u128, __u64_layout)?, // stx_rdev_major - immty_from_uint_checked(0u128, __u64_layout)?, // stx_rdev_minor - immty_from_uint_checked(0u128, __u64_layout)?, // stx_dev_major - immty_from_uint_checked(0u128, __u64_layout)?, // stx_dev_minor - ]; - - this.write_packed_immediates(&statxbuf_place, &imms)?; + // Now we write everything to `statxbuf`. We write a zero for the unavailable fields. + this.write_int_fields_named( + &[ + ("stx_mask", mask.into()), + ("stx_blksize", 0), + ("stx_attributes", 0), + ("stx_nlink", 0), + ("stx_uid", 0), + ("stx_gid", 0), + ("stx_mode", mode.into()), + ("stx_ino", 0), + ("stx_size", metadata.size.into()), + ("stx_blocks", 0), + ("stx_attributes_mask", 0), + ("stx_rdev_major", 0), + ("stx_rdev_minor", 0), + ("stx_dev_major", 0), + ("stx_dev_minor", 0), + ], + &statxbuf, + )?; + this.write_int_fields( + &[ + access_sec.into(), // stx_atime.tv_sec + access_nsec.into(), // stx_atime.tv_nsec + ], + &this.mplace_field_named(&statxbuf, "stx_atime")?, + )?; + this.write_int_fields( + &[ + created_sec.into(), // stx_btime.tv_sec + created_nsec.into(), // stx_btime.tv_nsec + ], + &this.mplace_field_named(&statxbuf, "stx_btime")?, + )?; + this.write_int_fields( + &[ + 0.into(), // stx_ctime.tv_sec + 0.into(), // stx_ctime.tv_nsec + ], + &this.mplace_field_named(&statxbuf, "stx_ctime")?, + )?; + this.write_int_fields( + &[ + modified_sec.into(), // stx_mtime.tv_sec + modified_nsec.into(), // stx_mtime.tv_nsec + ], + &this.mplace_field_named(&statxbuf, "stx_mtime")?, + )?; Ok(0) } @@ -1247,7 +1245,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(Ok(dir_entry)) => { // Write the directory entry into a newly allocated buffer. // The name is written with write_bytes, while the rest of the - // dirent64 struct is written using write_packed_immediates. + // dirent64 struct is written using write_int_fields. // For reference: // pub struct dirent64 { @@ -1279,11 +1277,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let file_type = this.file_type_to_d_type(dir_entry.file_type())?; - let entry_place = MPlaceTy::from_aligned_ptr(entry, dirent64_layout); - this.write_uint(ino, &this.mplace_field(&entry_place, 0)?.into())?; // d_ino - this.write_uint(0u128, &this.mplace_field(&entry_place, 1)?.into())?; // d_off - this.write_uint(size, &this.mplace_field(&entry_place, 2)?.into())?; // d_reclen - this.write_int(file_type, &this.mplace_field(&entry_place, 3)?.into())?; // d_type + this.write_int_fields( + &[ + ino.into(), // d_ino + 0, // d_off + size.into(), // d_reclen + file_type.into(), // d_type + ], + &MPlaceTy::from_aligned_ptr(entry, dirent64_layout), + )?; let name_ptr = entry.offset(Size::from_bytes(d_name_offset), this)?; this.memory.write_bytes(name_ptr, name_bytes.iter().copied())?; @@ -1333,7 +1335,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(Ok(dir_entry)) => { // Write into entry, write pointer to result, return 0 on success. // The name is written with write_os_str_to_c_str, while the rest of the - // dirent struct is written using write_packed_Immediates. + // dirent struct is written using write_int_fields. // For reference: // pub struct dirent { @@ -1361,10 +1363,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let entry_place = this.deref_operand(entry_op)?; - let ino_t_layout = this.libc_ty_layout("ino_t")?; - let off_t_layout = this.libc_ty_layout("off_t")?; - let c_ushort_layout = this.libc_ty_layout("c_ushort")?; - let c_uchar_layout = this.libc_ty_layout("c_uchar")?; // If the host is a Unix system, fill in the inode number with its real value. // If not, use 0 as a fallback value. @@ -1375,14 +1373,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let file_type = this.file_type_to_d_type(dir_entry.file_type())?; - let imms = [ - immty_from_uint_checked(ino, ino_t_layout)?, // d_ino - immty_from_uint_checked(0u128, off_t_layout)?, // d_seekoff - immty_from_uint_checked(0u128, c_ushort_layout)?, // d_reclen - immty_from_uint_checked(file_name_len, c_ushort_layout)?, // d_namlen - immty_from_int_checked(file_type, c_uchar_layout)?, // d_type - ]; - this.write_packed_immediates(&entry_place, &imms)?; + this.write_int_fields( + &[ + ino.into(), // d_ino + 0, // d_seekoff + 0, // d_reclen + file_name_len.into(), // d_namlen + file_type.into(), // d_type + ], + &entry_place, + )?; let result_place = this.deref_operand(result_op)?; this.write_scalar(this.read_scalar(entry_op)?, &result_place.into())?; diff --git a/src/shims/time.rs b/src/shims/time.rs index 1db9d85debdc..0acd697fa405 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -2,7 +2,6 @@ use std::convert::TryFrom; use std::time::{Duration, Instant, SystemTime}; use crate::*; -use helpers::{immty_from_int_checked, immty_from_uint_checked}; use thread::Time; /// Returns the time elapsed between the provided time and the unix epoch as a `Duration`. @@ -24,7 +23,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("`clock_gettime`")?; let clk_id = this.read_scalar(clk_id_op)?.to_i32()?; - let tp = this.deref_operand(tp_op)?; let duration = if clk_id == this.eval_libc_i32("CLOCK_REALTIME")? { system_time_to_duration(&SystemTime::now())? @@ -41,12 +39,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tv_sec = duration.as_secs(); let tv_nsec = duration.subsec_nanos(); - let imms = [ - immty_from_int_checked(tv_sec, this.libc_ty_layout("time_t")?)?, - immty_from_int_checked(tv_nsec, this.libc_ty_layout("c_long")?)?, - ]; - - this.write_packed_immediates(&tp, &imms)?; + this.write_int_fields(&[tv_sec.into(), tv_nsec.into()], &this.deref_operand(tp_op)?)?; Ok(0) } @@ -69,18 +62,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } - let tv = this.deref_operand(tv_op)?; - let duration = system_time_to_duration(&SystemTime::now())?; let tv_sec = duration.as_secs(); let tv_usec = duration.subsec_micros(); - let imms = [ - immty_from_int_checked(tv_sec, this.libc_ty_layout("time_t")?)?, - immty_from_int_checked(tv_usec, this.libc_ty_layout("suseconds_t")?)?, - ]; - - this.write_packed_immediates(&tv, &imms)?; + this.write_int_fields(&[tv_sec.into(), tv_usec.into()], &this.deref_operand(tv_op)?)?; Ok(0) } @@ -105,12 +91,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dwLowDateTime = u32::try_from(duration_ticks & 0x00000000FFFFFFFF).unwrap(); let dwHighDateTime = u32::try_from((duration_ticks & 0xFFFFFFFF00000000) >> 32).unwrap(); - let DWORD_tylayout = this.machine.layouts.u32; - let imms = [ - immty_from_uint_checked(dwLowDateTime, DWORD_tylayout)?, - immty_from_uint_checked(dwHighDateTime, DWORD_tylayout)?, - ]; - this.write_packed_immediates(&this.deref_operand(LPFILETIME_op)?, &imms)?; + this.write_int_fields( + &[dwLowDateTime.into(), dwHighDateTime.into()], + &this.deref_operand(LPFILETIME_op)?, + )?; + Ok(()) } @@ -185,12 +170,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Since our emulated ticks in `mach_absolute_time` *are* nanoseconds, // no scaling needs to happen. let (numer, denom) = (1, 1); - let imms = [ - immty_from_int_checked(numer, this.machine.layouts.u32)?, - immty_from_int_checked(denom, this.machine.layouts.u32)?, - ]; + this.write_int_fields(&[numer.into(), denom.into()], &info)?; - this.write_packed_immediates(&info, &imms)?; Ok(0) // KERN_SUCCESS } From 61bfa8afe828a94aaaa7ebb0dac110fd91644bb4 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sun, 13 Mar 2022 18:02:22 -0700 Subject: [PATCH 2936/5092] Fixup renamed fn for Simd --- rust-version | 2 +- tests/run-pass/portable-simd.rs | 76 ++++++++++++++++----------------- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/rust-version b/rust-version index 9885aba10293..5306a4d18628 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -258256697b8550860be0f6194dec532ac616c2c1 +e95b10ba4ac4564ed25f7eef143e3182c33b3902 diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index c046af0bcf52..eca8e8f377d6 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -22,27 +22,27 @@ fn simd_ops_f32() { assert_eq!(a.lanes_ge(f32x4::splat(5.0) * b), Mask::from_array([true, true, false, true])); assert_eq!(a.lanes_gt(f32x4::splat(5.0) * b), Mask::from_array([true, false, false, true])); - assert_eq!(a.horizontal_sum(), 40.0); - assert_eq!(b.horizontal_sum(), 2.0); - assert_eq!(a.horizontal_product(), 100.0 * 100.0); - assert_eq!(b.horizontal_product(), -24.0); - assert_eq!(a.horizontal_max(), 10.0); - assert_eq!(b.horizontal_max(), 3.0); - assert_eq!(a.horizontal_min(), 10.0); - assert_eq!(b.horizontal_min(), -4.0); + assert_eq!(a.reduce_sum(), 40.0); + assert_eq!(b.reduce_sum(), 2.0); + assert_eq!(a.reduce_product(), 100.0 * 100.0); + assert_eq!(b.reduce_product(), -24.0); + assert_eq!(a.reduce_max(), 10.0); + assert_eq!(b.reduce_max(), 3.0); + assert_eq!(a.reduce_min(), 10.0); + assert_eq!(b.reduce_min(), -4.0); assert_eq!( f32x2::from_array([0.0, f32::NAN]).max(f32x2::from_array([f32::NAN, 0.0])), f32x2::from_array([0.0, 0.0]) ); - assert_eq!(f32x2::from_array([0.0, f32::NAN]).horizontal_max(), 0.0); - assert_eq!(f32x2::from_array([f32::NAN, 0.0]).horizontal_max(), 0.0); + assert_eq!(f32x2::from_array([0.0, f32::NAN]).reduce_max(), 0.0); + assert_eq!(f32x2::from_array([f32::NAN, 0.0]).reduce_max(), 0.0); assert_eq!( f32x2::from_array([0.0, f32::NAN]).min(f32x2::from_array([f32::NAN, 0.0])), f32x2::from_array([0.0, 0.0]) ); - assert_eq!(f32x2::from_array([0.0, f32::NAN]).horizontal_min(), 0.0); - assert_eq!(f32x2::from_array([f32::NAN, 0.0]).horizontal_min(), 0.0); + assert_eq!(f32x2::from_array([0.0, f32::NAN]).reduce_min(), 0.0); + assert_eq!(f32x2::from_array([f32::NAN, 0.0]).reduce_min(), 0.0); } fn simd_ops_f64() { @@ -66,27 +66,27 @@ fn simd_ops_f64() { assert_eq!(a.lanes_ge(f64x4::splat(5.0) * b), Mask::from_array([true, true, false, true])); assert_eq!(a.lanes_gt(f64x4::splat(5.0) * b), Mask::from_array([true, false, false, true])); - assert_eq!(a.horizontal_sum(), 40.0); - assert_eq!(b.horizontal_sum(), 2.0); - assert_eq!(a.horizontal_product(), 100.0 * 100.0); - assert_eq!(b.horizontal_product(), -24.0); - assert_eq!(a.horizontal_max(), 10.0); - assert_eq!(b.horizontal_max(), 3.0); - assert_eq!(a.horizontal_min(), 10.0); - assert_eq!(b.horizontal_min(), -4.0); + assert_eq!(a.reduce_sum(), 40.0); + assert_eq!(b.reduce_sum(), 2.0); + assert_eq!(a.reduce_product(), 100.0 * 100.0); + assert_eq!(b.reduce_product(), -24.0); + assert_eq!(a.reduce_max(), 10.0); + assert_eq!(b.reduce_max(), 3.0); + assert_eq!(a.reduce_min(), 10.0); + assert_eq!(b.reduce_min(), -4.0); assert_eq!( f64x2::from_array([0.0, f64::NAN]).max(f64x2::from_array([f64::NAN, 0.0])), f64x2::from_array([0.0, 0.0]) ); - assert_eq!(f64x2::from_array([0.0, f64::NAN]).horizontal_max(), 0.0); - assert_eq!(f64x2::from_array([f64::NAN, 0.0]).horizontal_max(), 0.0); + assert_eq!(f64x2::from_array([0.0, f64::NAN]).reduce_max(), 0.0); + assert_eq!(f64x2::from_array([f64::NAN, 0.0]).reduce_max(), 0.0); assert_eq!( f64x2::from_array([0.0, f64::NAN]).min(f64x2::from_array([f64::NAN, 0.0])), f64x2::from_array([0.0, 0.0]) ); - assert_eq!(f64x2::from_array([0.0, f64::NAN]).horizontal_min(), 0.0); - assert_eq!(f64x2::from_array([f64::NAN, 0.0]).horizontal_min(), 0.0); + assert_eq!(f64x2::from_array([0.0, f64::NAN]).reduce_min(), 0.0); + assert_eq!(f64x2::from_array([f64::NAN, 0.0]).reduce_min(), 0.0); } fn simd_ops_i32() { @@ -137,21 +137,21 @@ fn simd_ops_i32() { assert_eq!(a.lanes_ge(i32x4::splat(5) * b), Mask::from_array([true, true, false, true])); assert_eq!(a.lanes_gt(i32x4::splat(5) * b), Mask::from_array([true, false, false, true])); - assert_eq!(a.horizontal_sum(), 40); - assert_eq!(b.horizontal_sum(), 2); - assert_eq!(a.horizontal_product(), 100 * 100); - assert_eq!(b.horizontal_product(), -24); - assert_eq!(a.horizontal_max(), 10); - assert_eq!(b.horizontal_max(), 3); - assert_eq!(a.horizontal_min(), 10); - assert_eq!(b.horizontal_min(), -4); + assert_eq!(a.reduce_sum(), 40); + assert_eq!(b.reduce_sum(), 2); + assert_eq!(a.reduce_product(), 100 * 100); + assert_eq!(b.reduce_product(), -24); + assert_eq!(a.reduce_max(), 10); + assert_eq!(b.reduce_max(), 3); + assert_eq!(a.reduce_min(), 10); + assert_eq!(b.reduce_min(), -4); - assert_eq!(a.horizontal_and(), 10); - assert_eq!(b.horizontal_and(), 0); - assert_eq!(a.horizontal_or(), 10); - assert_eq!(b.horizontal_or(), -1); - assert_eq!(a.horizontal_xor(), 0); - assert_eq!(b.horizontal_xor(), -4); + assert_eq!(a.reduce_and(), 10); + assert_eq!(b.reduce_and(), 0); + assert_eq!(a.reduce_or(), 10); + assert_eq!(b.reduce_or(), -1); + assert_eq!(a.reduce_xor(), 0); + assert_eq!(b.reduce_xor(), -4); } fn simd_mask() { From f338b0229b16cabe6e8b02664d15aee2ed83603d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Mar 2022 14:42:06 -0500 Subject: [PATCH 2937/5092] test integer SIMD min/max --- tests/run-pass/portable-simd.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index eca8e8f377d6..28b9a1b03d94 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -102,9 +102,8 @@ fn simd_ops_i32() { assert_eq!(a % b, i32x4::from_array([0, 0, 1, 2])); assert_eq!(i32x2::splat(i32::MIN) % i32x2::splat(-1), i32x2::splat(0)); assert_eq!(b.abs(), i32x4::from_array([1, 2, 3, 4])); - // FIXME not a per-lane method (https://github.com/rust-lang/portable-simd/issues/247) - // assert_eq!(a.max(b * i32x4::splat(4)), i32x4::from_array([10, 10, 12, 10])); - // assert_eq!(a.min(b * i32x4::splat(4)), i32x4::from_array([4, 8, 10, -16])); + assert_eq!(a.max(b * i32x4::splat(4)), i32x4::from_array([10, 10, 12, 10])); + assert_eq!(a.min(b * i32x4::splat(4)), i32x4::from_array([4, 8, 10, -16])); assert_eq!( i8x4::from_array([i8::MAX, -23, 23, i8::MIN]).saturating_add(i8x4::from_array([1, i8::MIN, i8::MAX, 28])), From 559e4951953f9139cfd6fb4c614882ab99232676 Mon Sep 17 00:00:00 2001 From: Jake Vossen Date: Wed, 16 Mar 2022 10:18:51 -0600 Subject: [PATCH 2938/5092] missing backtick on miri-isolation warning help --- src/diagnostics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 3bf8c7bc17bb..1ccf3c5dba73 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -150,7 +150,7 @@ pub fn report_error<'tcx, 'mir>( UnsupportedInIsolation(_) => vec![ (None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation;")), - (None, format!("or pass `-Zmiri-isolation-error=warn to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning")), + (None, format!("or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning")), ], ExperimentalUb { url, .. } => vec![ From 202964127b0874ac9aa0e10e7baa7ae4ef576908 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 16 Mar 2022 18:33:59 -0400 Subject: [PATCH 2939/5092] implement fabs using soft floats --- src/shims/intrinsics.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index b4416bfa9859..24aeb448912b 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -90,9 +90,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Floating-point operations + "fabsf32" => { + let &[ref f] = check_arg_count(args)?; + let f = this.read_scalar(f)?.to_f32()?; + // Can be implemented in soft-floats. + this.write_scalar(Scalar::from_f32(f.abs()), dest)?; + } + "fabsf64" => { + let &[ref f] = check_arg_count(args)?; + let f = this.read_scalar(f)?.to_f64()?; + // Can be implemented in soft-floats. + this.write_scalar(Scalar::from_f64(f.abs()), dest)?; + } #[rustfmt::skip] | "sinf32" - | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" @@ -110,7 +121,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let f = match intrinsic_name { "sinf32" => f.sin(), - "fabsf32" => f.abs(), "cosf32" => f.cos(), "sqrtf32" => f.sqrt(), "expf32" => f.exp(), @@ -129,7 +139,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[rustfmt::skip] | "sinf64" - | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" @@ -147,7 +156,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let f = match intrinsic_name { "sinf64" => f.sin(), - "fabsf64" => f.abs(), "cosf64" => f.cos(), "sqrtf64" => f.sqrt(), "expf64" => f.exp(), From 1f237b3b7dc905b7095d540ee91a3a23617a5792 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 16 Mar 2022 18:51:34 -0400 Subject: [PATCH 2940/5092] implement SIMD float rounding functions --- src/shims/intrinsics.rs | 50 ++++++++++++++++++++++++- tests/run-pass/portable-simd.rs | 65 +++++++++++++++++++++++++++++++-- 2 files changed, 109 insertions(+), 6 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 24aeb448912b..9b6df483b92a 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -325,20 +325,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // SIMD operations #[rustfmt::skip] | "simd_neg" - | "simd_fabs" => { + | "simd_fabs" + | "simd_ceil" + | "simd_floor" + | "simd_round" + | "simd_trunc" => { let &[ref op] = check_arg_count(args)?; let (op, op_len) = this.operand_to_simd(op)?; let (dest, dest_len) = this.place_to_simd(dest)?; assert_eq!(dest_len, op_len); + #[derive(Copy, Clone)] + enum HostFloatOp { + Ceil, + Floor, + Round, + Trunc, + } + #[derive(Copy, Clone)] enum Op { MirOp(mir::UnOp), Abs, + HostOp(HostFloatOp), } let which = match intrinsic_name { "simd_neg" => Op::MirOp(mir::UnOp::Neg), "simd_fabs" => Op::Abs, + "simd_ceil" => Op::HostOp(HostFloatOp::Ceil), + "simd_floor" => Op::HostOp(HostFloatOp::Floor), + "simd_round" => Op::HostOp(HostFloatOp::Round), + "simd_trunc" => Op::HostOp(HostFloatOp::Trunc), _ => unreachable!(), }; @@ -350,7 +367,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Op::Abs => { // Works for f32 and f64. let ty::Float(float_ty) = op.layout.ty.kind() else { - bug!("simd_fabs operand is not a float") + bug!("{} operand is not a float", intrinsic_name) }; let op = op.to_scalar()?; match float_ty { @@ -358,6 +375,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx FloatTy::F64 => Scalar::from_f64(op.to_f64()?.abs()), } } + Op::HostOp(host_op) => { + let ty::Float(float_ty) = op.layout.ty.kind() else { + bug!("{} operand is not a float", intrinsic_name) + }; + // FIXME using host floats + match float_ty { + FloatTy::F32 => { + let f = f32::from_bits(op.to_scalar()?.to_u32()?); + let res = match host_op { + HostFloatOp::Ceil => f.ceil(), + HostFloatOp::Floor => f.floor(), + HostFloatOp::Round => f.round(), + HostFloatOp::Trunc => f.trunc(), + }; + Scalar::from_u32(res.to_bits()) + } + FloatTy::F64 => { + let f = f64::from_bits(op.to_scalar()?.to_u64()?); + let res = match host_op { + HostFloatOp::Ceil => f.ceil(), + HostFloatOp::Floor => f.floor(), + HostFloatOp::Round => f.round(), + HostFloatOp::Trunc => f.trunc(), + }; + Scalar::from_u64(res.to_bits()) + } + } + + } }; this.write_scalar(val, &dest.into())?; } diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 28b9a1b03d94..a15a0a3b1e00 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -106,19 +106,39 @@ fn simd_ops_i32() { assert_eq!(a.min(b * i32x4::splat(4)), i32x4::from_array([4, 8, 10, -16])); assert_eq!( - i8x4::from_array([i8::MAX, -23, 23, i8::MIN]).saturating_add(i8x4::from_array([1, i8::MIN, i8::MAX, 28])), + i8x4::from_array([i8::MAX, -23, 23, i8::MIN]).saturating_add(i8x4::from_array([ + 1, + i8::MIN, + i8::MAX, + 28 + ])), i8x4::from_array([i8::MAX, i8::MIN, i8::MAX, -100]) ); assert_eq!( - i8x4::from_array([i8::MAX, -28, 27, 42]).saturating_sub(i8x4::from_array([1, i8::MAX, i8::MAX, -80])), + i8x4::from_array([i8::MAX, -28, 27, 42]).saturating_sub(i8x4::from_array([ + 1, + i8::MAX, + i8::MAX, + -80 + ])), i8x4::from_array([126, i8::MIN, -100, 122]) ); assert_eq!( - u8x4::from_array([u8::MAX, 0, 23, 42]).saturating_add(u8x4::from_array([1, 1, u8::MAX, 200])), + u8x4::from_array([u8::MAX, 0, 23, 42]).saturating_add(u8x4::from_array([ + 1, + 1, + u8::MAX, + 200 + ])), u8x4::from_array([u8::MAX, 1, u8::MAX, 242]) ); assert_eq!( - u8x4::from_array([u8::MAX, 0, 23, 42]).saturating_sub(u8x4::from_array([1, 1, u8::MAX, 200])), + u8x4::from_array([u8::MAX, 0, 23, 42]).saturating_sub(u8x4::from_array([ + 1, + 1, + u8::MAX, + 200 + ])), u8x4::from_array([254, 0, 0, 0]) ); @@ -259,6 +279,42 @@ fn simd_gather_scatter() { assert_eq!(vec, vec![124, 11, 12, 82, 14, 15, 16, 17, 18]); } +fn simd_round() { + assert_eq!( + f32x4::from_array([0.9, 1.001, 2.0, -4.5]).ceil(), + f32x4::from_array([1.0, 2.0, 2.0, -4.0]) + ); + assert_eq!( + f32x4::from_array([0.9, 1.001, 2.0, -4.5]).floor(), + f32x4::from_array([0.0, 1.0, 2.0, -5.0]) + ); + assert_eq!( + f32x4::from_array([0.9, 1.001, 2.0, -4.5]).round(), + f32x4::from_array([1.0, 1.0, 2.0, -5.0]) + ); + assert_eq!( + f32x4::from_array([0.9, 1.001, 2.0, -4.5]).trunc(), + f32x4::from_array([0.0, 1.0, 2.0, -4.0]) + ); + + assert_eq!( + f64x4::from_array([0.9, 1.001, 2.0, -4.5]).ceil(), + f64x4::from_array([1.0, 2.0, 2.0, -4.0]) + ); + assert_eq!( + f64x4::from_array([0.9, 1.001, 2.0, -4.5]).floor(), + f64x4::from_array([0.0, 1.0, 2.0, -5.0]) + ); + assert_eq!( + f64x4::from_array([0.9, 1.001, 2.0, -4.5]).round(), + f64x4::from_array([1.0, 1.0, 2.0, -5.0]) + ); + assert_eq!( + f64x4::from_array([0.9, 1.001, 2.0, -4.5]).trunc(), + f64x4::from_array([0.0, 1.0, 2.0, -4.0]) + ); +} + fn simd_intrinsics() { extern "platform-intrinsic" { fn simd_eq(x: T, y: T) -> U; @@ -299,5 +355,6 @@ fn main() { simd_cast(); simd_swizzle(); simd_gather_scatter(); + simd_round(); simd_intrinsics(); } From 730cd272481427149d8d4a1e471d983a73f77105 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 5 Feb 2022 19:44:56 -0500 Subject: [PATCH 2941/5092] Print more in SB error diagnostics This tries to clarify exactly why an access is not valid by printing what memory range the access was over, which in combination with tag-tracking may help a user figure out the source of the problem. --- src/diagnostics.rs | 31 +++-- src/stacked_borrows.rs | 125 ++++++++++++++---- tests/compile-fail/box-cell-alias.rs | 2 +- .../stacked_borrows/illegal_write3.rs | 2 +- .../stacked_borrows/raw_tracking.rs | 2 +- .../stacked_borrows/shr_frozen_violation1.rs | 2 +- .../compile-fail/stacked_borrows/zst_slice.rs | 2 +- 7 files changed, 126 insertions(+), 40 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 1ccf3c5dba73..fbcb2e0d0ff7 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -17,6 +17,7 @@ pub enum TerminationInfo { UnsupportedInIsolation(String), ExperimentalUb { msg: String, + help: Option, url: String, }, Deadlock, @@ -133,6 +134,8 @@ pub fn report_error<'tcx, 'mir>( ) -> Option { use InterpError::*; + let mut msg = vec![]; + let (title, helps) = match &e.kind() { MachineStop(info) => { let info = info.downcast_ref::().expect("invalid MachineStop payload"); @@ -152,11 +155,13 @@ pub fn report_error<'tcx, 'mir>( (None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation;")), (None, format!("or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning")), ], - ExperimentalUb { url, .. } => + ExperimentalUb { url, help, .. } => { + msg.extend(help.clone()); vec![ (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental")), - (None, format!("see {} for further information", url)), - ], + (None, format!("see {} for further information", url)) + ] + } MultipleSymbolDefinitions { first, first_crate, second, second_crate, .. } => vec![ (Some(*first), format!("it's first defined here, in crate `{}`", first_crate)), @@ -211,11 +216,11 @@ pub fn report_error<'tcx, 'mir>( let stacktrace = ecx.generate_stacktrace(); let (stacktrace, was_pruned) = prune_stacktrace(ecx, stacktrace); e.print_backtrace(); - let msg = e.to_string(); + msg.insert(0, e.to_string()); report_msg( *ecx.tcx, DiagLevel::Error, - &if let Some(title) = title { format!("{}: {}", title, msg) } else { msg.clone() }, + &if let Some(title) = title { format!("{}: {}", title, msg[0]) } else { msg[0].clone() }, msg, helps, &stacktrace, @@ -256,11 +261,14 @@ pub fn report_error<'tcx, 'mir>( /// Report an error or note (depending on the `error` argument) with the given stacktrace. /// Also emits a full stacktrace of the interpreter stack. +/// We want to present a multi-line span message for some errors. Diagnostics do not support this +/// directly, so we pass the lines as a `Vec` and display each line after the first with an +/// additional `span_label` or `note` call. fn report_msg<'tcx>( tcx: TyCtxt<'tcx>, diag_level: DiagLevel, title: &str, - span_msg: String, + span_msg: Vec, mut helps: Vec<(Option, String)>, stacktrace: &[FrameInfo<'tcx>], ) { @@ -273,12 +281,17 @@ fn report_msg<'tcx>( // Show main message. if span != DUMMY_SP { - err.span_label(span, span_msg); + for line in span_msg { + err.span_label(span, line); + } } else { // Make sure we show the message even when it is a dummy span. - err.note(&span_msg); + for line in span_msg { + err.note(&line); + } err.note("(no span available)"); } + // Show help messages. if !helps.is_empty() { // Add visual separator before backtrace. @@ -413,7 +426,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => ("tracking was triggered", DiagLevel::Note), }; - report_msg(*this.tcx, diag_level, title, msg, vec![], &stacktrace); + report_msg(*this.tcx, diag_level, title, vec![msg], vec![], &stacktrace); } }); } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 0e47a9e1c3b0..777b8e9331ee 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -220,9 +220,10 @@ impl GlobalState { } /// Error reporting -fn err_sb_ub(msg: String) -> InterpError<'static> { +fn err_sb_ub(msg: String, help: Option) -> InterpError<'static> { err_machine_stop!(TerminationInfo::ExperimentalUb { msg, + help, url: format!( "https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md" ), @@ -320,12 +321,18 @@ impl<'tcx> Stack { if let Some(call) = item.protector { if global.is_active(call) { if let Some((tag, _)) = provoking_access { - Err(err_sb_ub(format!( - "not granting access to tag {:?} because incompatible item is protected: {:?}", - tag, item - )))? + Err(err_sb_ub( + format!( + "not granting access to tag {:?} because incompatible item is protected: {:?}", + tag, item + ), + None, + ))? } else { - Err(err_sb_ub(format!("deallocating while item is protected: {:?}", item)))? + Err(err_sb_ub( + format!("deallocating while item is protected: {:?}", item), + None, + ))? } } } @@ -334,22 +341,21 @@ impl<'tcx> Stack { /// Test if a memory `access` using pointer tagged `tag` is granted. /// If yes, return the index of the item that granted it. + /// `range` refers the entire operation, and `offset` refers to the specific offset into the + /// allocation that we are currently checking. fn access( &mut self, access: AccessKind, tag: SbTag, - dbg_ptr: Pointer, // just for debug printing amd error messages + (alloc_id, range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &GlobalState, ) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. - let granting_idx = self.find_granting(access, tag).ok_or_else(|| { - err_sb_ub(format!( - "no item granting {} to tag {:?} at {:?} found in borrow stack.", - access, tag, dbg_ptr, - )) - })?; + let granting_idx = self + .find_granting(access, tag) + .ok_or_else(|| self.access_error(access, tag, alloc_id, range, offset))?; // Step 2: Remove incompatible items above them. Make sure we do not remove protected // items. Behavior differs for reads and writes. @@ -389,7 +395,7 @@ impl<'tcx> Stack { fn dealloc( &mut self, tag: SbTag, - dbg_ptr: Pointer, // just for debug printing amd error messages + dbg_ptr: Pointer, // just for debug printing and error messages global: &GlobalState, ) -> InterpResult<'tcx> { // Step 1: Find granting item. @@ -397,7 +403,7 @@ impl<'tcx> Stack { err_sb_ub(format!( "no item granting write access for deallocation to tag {:?} at {:?} found in borrow stack", tag, dbg_ptr, - )) + ), None) })?; // Step 2: Remove all items. Also checks for protectors. @@ -412,11 +418,13 @@ impl<'tcx> Stack { /// `weak` controls whether this operation is weak or strong: weak granting does not act as /// an access, and they add the new item directly on top of the one it is derived /// from instead of all the way at the top of the stack. + /// `range` refers the entire operation, and `offset` refers to the specific location in + /// `range` that we are currently checking. fn grant( &mut self, derived_from: SbTag, new: Item, - dbg_ptr: Pointer, + (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &GlobalState, ) -> InterpResult<'tcx> { // Figure out which access `perm` corresponds to. @@ -424,11 +432,9 @@ impl<'tcx> Stack { if new.perm.grants(AccessKind::Write) { AccessKind::Write } else { AccessKind::Read }; // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. - let granting_idx = self.find_granting(access, derived_from) - .ok_or_else(|| err_sb_ub(format!( - "trying to reborrow for {:?} at {:?}, but parent tag {:?} does not have an appropriate item in the borrow stack", - new.perm, dbg_ptr, derived_from, - )))?; + let granting_idx = self + .find_granting(access, derived_from) + .ok_or_else(|| self.grant_error(derived_from, new, alloc_id, alloc_range, offset))?; // Compute where to put the new item. // Either way, we ensure that we insert the new item in a way such that between @@ -447,7 +453,7 @@ impl<'tcx> Stack { // A "safe" reborrow for a pointer that actually expects some aliasing guarantees. // Here, creating a reference actually counts as an access. // This ensures F2b for `Unique`, by removing offending `SharedReadOnly`. - self.access(access, derived_from, dbg_ptr, global)?; + self.access(access, derived_from, (alloc_id, alloc_range, offset), global)?; // We insert "as far up as possible": We know only compatible items are remaining // on top of `derived_from`, and we want the new item at the top so that we @@ -467,6 +473,72 @@ impl<'tcx> Stack { Ok(()) } + + /// Report a descriptive error when `new` could not be granted from `derived_from`. + fn grant_error( + &self, + derived_from: SbTag, + new: Item, + alloc_id: AllocId, + alloc_range: AllocRange, + error_offset: Size, + ) -> InterpError<'static> { + let action = format!( + "trying to reborrow {:?} for {:?} permission at {}[{:#x}]", + derived_from, + new.perm, + alloc_id, + error_offset.bytes(), + ); + err_sb_ub( + format!("{}{}", action, self.error_cause(derived_from)), + Some(Self::operation_summary("a reborrow", alloc_id, alloc_range)), + ) + } + + /// Report a descriptive error when `access` is not permitted based on `tag`. + fn access_error( + &self, + access: AccessKind, + tag: SbTag, + alloc_id: AllocId, + alloc_range: AllocRange, + error_offset: Size, + ) -> InterpError<'static> { + let action = format!( + "attempting a {} using {:?} at {}[{:#x}]", + access, + tag, + alloc_id, + error_offset.bytes(), + ); + err_sb_ub( + format!("{}{}", action, self.error_cause(tag)), + Some(Self::operation_summary("an access", alloc_id, alloc_range)), + ) + } + + fn operation_summary( + operation: &'static str, + alloc_id: AllocId, + alloc_range: AllocRange, + ) -> String { + format!( + "this error occurs as part of {} at {:?}[{:#x}..{:#x}]", + operation, + alloc_id, + alloc_range.start.bytes(), + alloc_range.end().bytes() + ) + } + + fn error_cause(&self, tag: SbTag) -> &'static str { + if self.borrows.iter().any(|item| item.tag == tag && item.perm != Permission::Disabled) { + ", but that tag only grants SharedReadOnly permission for this location" + } else { + ", but that tag does not exist in the borrow stack for this location" + } + } } // # Stacked Borrows Core End @@ -566,7 +638,7 @@ impl Stacks { ); let global = &*extra.borrow(); self.for_each(range, move |offset, stack| { - stack.access(AccessKind::Read, tag, Pointer::new(alloc_id, offset), global) + stack.access(AccessKind::Read, tag, (alloc_id, range, offset), global) }) } @@ -586,7 +658,7 @@ impl Stacks { ); let global = extra.get_mut(); self.for_each_mut(range, move |offset, stack| { - stack.access(AccessKind::Write, tag, Pointer::new(alloc_id, offset), global) + stack.access(AccessKind::Write, tag, (alloc_id, range, offset), global) }) } @@ -693,7 +765,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; let item = Item { perm, tag: new_tag, protector }; stacked_borrows.for_each(range, |offset, stack| { - stack.grant(orig_tag, item, Pointer::new(alloc_id, offset), &*global) + stack.grant(orig_tag, item, (alloc_id, range, offset), &*global) }) })?; return Ok(()); @@ -707,8 +779,9 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx alloc_extra.stacked_borrows.as_mut().expect("we should have Stacked Borrows data"); let global = memory_extra.stacked_borrows.as_mut().unwrap().get_mut(); let item = Item { perm, tag: new_tag, protector }; + let range = alloc_range(base_offset, size); stacked_borrows.for_each_mut(alloc_range(base_offset, size), |offset, stack| { - stack.grant(orig_tag, item, Pointer::new(alloc_id, offset), global) + stack.grant(orig_tag, item, (alloc_id, range, offset), global) })?; Ok(()) } diff --git a/tests/compile-fail/box-cell-alias.rs b/tests/compile-fail/box-cell-alias.rs index 58fc3530d7bf..5b9614f79fde 100644 --- a/tests/compile-fail/box-cell-alias.rs +++ b/tests/compile-fail/box-cell-alias.rs @@ -6,7 +6,7 @@ use std::cell::Cell; fn helper(val: Box>, ptr: *const Cell) -> u8 { val.set(10); - unsafe { (*ptr).set(20); } //~ ERROR does not have an appropriate item in the borrow stack + unsafe { (*ptr).set(20); } //~ ERROR does not exist in the borrow stack val.get() } diff --git a/tests/compile-fail/stacked_borrows/illegal_write3.rs b/tests/compile-fail/stacked_borrows/illegal_write3.rs index d2d8528d9078..7851eeb02690 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write3.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write3.rs @@ -3,6 +3,6 @@ fn main() { // Make sure raw ptr with raw tag cannot mutate frozen location without breaking the shared ref. let r#ref = ⌖ // freeze let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag - unsafe { *ptr = 42; } //~ ERROR borrow stack + unsafe { *ptr = 42; } //~ ERROR only grants SharedReadOnly permission let _val = *r#ref; } diff --git a/tests/compile-fail/stacked_borrows/raw_tracking.rs b/tests/compile-fail/stacked_borrows/raw_tracking.rs index 0d6d0198fbe9..a8e1d806cbbb 100644 --- a/tests/compile-fail/stacked_borrows/raw_tracking.rs +++ b/tests/compile-fail/stacked_borrows/raw_tracking.rs @@ -7,6 +7,6 @@ fn main() { let raw2 = &mut l as *mut _; // invalidates raw1 // Without raw pointer tracking, Stacked Borrows cannot distinguish raw1 and raw2, and thus // fails to realize that raw1 should not be used any more. - unsafe { *raw1 = 13; } //~ ERROR no item granting write access to tag + unsafe { *raw1 = 13; } //~ ERROR does not exist in the borrow stack unsafe { *raw2 = 13; } } diff --git a/tests/compile-fail/stacked_borrows/shr_frozen_violation1.rs b/tests/compile-fail/stacked_borrows/shr_frozen_violation1.rs index 5031210c547b..1ea96086d3e4 100644 --- a/tests/compile-fail/stacked_borrows/shr_frozen_violation1.rs +++ b/tests/compile-fail/stacked_borrows/shr_frozen_violation1.rs @@ -9,5 +9,5 @@ fn main() { } fn unknown_code(x: &i32) { - unsafe { *(x as *const i32 as *mut i32) = 7; } //~ ERROR borrow stack + unsafe { *(x as *const i32 as *mut i32) = 7; } //~ ERROR only grants SharedReadOnly permission } diff --git a/tests/compile-fail/stacked_borrows/zst_slice.rs b/tests/compile-fail/stacked_borrows/zst_slice.rs index 14d5d77a2bb6..065bf77d04ae 100644 --- a/tests/compile-fail/stacked_borrows/zst_slice.rs +++ b/tests/compile-fail/stacked_borrows/zst_slice.rs @@ -1,5 +1,5 @@ // compile-flags: -Zmiri-tag-raw-pointers -// error-pattern: does not have an appropriate item in the borrow stack +// error-pattern: does not exist in the borrow stack fn main() { unsafe { From 4fd5dca27c1ec311ee11844f3b9e2f53ddb454df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 16 Mar 2022 22:12:39 -0400 Subject: [PATCH 2942/5092] implement SIMD sqrt and fma --- src/shims/intrinsics.rs | 37 ++++++++++++++++++++++++++++++++- tests/run-pass/portable-simd.rs | 10 +++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 9b6df483b92a..726e6b6b9619 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -329,7 +329,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "simd_ceil" | "simd_floor" | "simd_round" - | "simd_trunc" => { + | "simd_trunc" + | "simd_fsqrt" => { let &[ref op] = check_arg_count(args)?; let (op, op_len) = this.operand_to_simd(op)?; let (dest, dest_len) = this.place_to_simd(dest)?; @@ -342,6 +343,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Floor, Round, Trunc, + Sqrt, } #[derive(Copy, Clone)] enum Op { @@ -356,6 +358,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "simd_floor" => Op::HostOp(HostFloatOp::Floor), "simd_round" => Op::HostOp(HostFloatOp::Round), "simd_trunc" => Op::HostOp(HostFloatOp::Trunc), + "simd_fsqrt" => Op::HostOp(HostFloatOp::Sqrt), _ => unreachable!(), }; @@ -388,6 +391,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx HostFloatOp::Floor => f.floor(), HostFloatOp::Round => f.round(), HostFloatOp::Trunc => f.trunc(), + HostFloatOp::Sqrt => f.sqrt(), }; Scalar::from_u32(res.to_bits()) } @@ -398,6 +402,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx HostFloatOp::Floor => f.floor(), HostFloatOp::Round => f.round(), HostFloatOp::Trunc => f.trunc(), + HostFloatOp::Sqrt => f.sqrt(), }; Scalar::from_u64(res.to_bits()) } @@ -508,6 +513,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(val, &dest.into())?; } } + "simd_fma" => { + let &[ref a, ref b, ref c] = check_arg_count(args)?; + let (a, a_len) = this.operand_to_simd(a)?; + let (b, b_len) = this.operand_to_simd(b)?; + let (c, c_len) = this.operand_to_simd(c)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + assert_eq!(dest_len, a_len); + assert_eq!(dest_len, b_len); + assert_eq!(dest_len, c_len); + + for i in 0..dest_len { + let a = this.read_immediate(&this.mplace_index(&a, i)?.into())?.to_scalar()?; + let b = this.read_immediate(&this.mplace_index(&b, i)?.into())?.to_scalar()?; + let c = this.read_immediate(&this.mplace_index(&c, i)?.into())?.to_scalar()?; + let dest = this.mplace_index(&dest, i)?; + + // Works for f32 and f64. + let ty::Float(float_ty) = dest.layout.ty.kind() else { + bug!("{} operand is not a float", intrinsic_name) + }; + let val = match float_ty { + FloatTy::F32 => + Scalar::from_f32(a.to_f32()?.mul_add(b.to_f32()?, c.to_f32()?).value), + FloatTy::F64 => + Scalar::from_f64(a.to_f64()?.mul_add(b.to_f64()?, c.to_f64()?).value), + }; + this.write_scalar(val, &dest.into())?; + } + } #[rustfmt::skip] | "simd_reduce_and" | "simd_reduce_or" diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index a15a0a3b1e00..80b0b4556c6e 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -15,6 +15,11 @@ fn simd_ops_f32() { assert_eq!(a.max(b * f32x4::splat(4.0)), f32x4::from_array([10.0, 10.0, 12.0, 10.0])); assert_eq!(a.min(b * f32x4::splat(4.0)), f32x4::from_array([4.0, 8.0, 10.0, -16.0])); + assert_eq!(a.mul_add(b, a), (a*b)+a); + assert_eq!(b.mul_add(b, a), (b*b)+a); + assert_eq!((a*a).sqrt(), a); + assert_eq!((b*b).sqrt(), b.abs()); + assert_eq!(a.lanes_eq(f32x4::splat(5.0) * b), Mask::from_array([false, true, false, false])); assert_eq!(a.lanes_ne(f32x4::splat(5.0) * b), Mask::from_array([true, false, true, true])); assert_eq!(a.lanes_le(f32x4::splat(5.0) * b), Mask::from_array([false, true, true, false])); @@ -59,6 +64,11 @@ fn simd_ops_f64() { assert_eq!(a.max(b * f64x4::splat(4.0)), f64x4::from_array([10.0, 10.0, 12.0, 10.0])); assert_eq!(a.min(b * f64x4::splat(4.0)), f64x4::from_array([4.0, 8.0, 10.0, -16.0])); + assert_eq!(a.mul_add(b, a), (a*b)+a); + assert_eq!(b.mul_add(b, a), (b*b)+a); + assert_eq!((a*a).sqrt(), a); + assert_eq!((b*b).sqrt(), b.abs()); + assert_eq!(a.lanes_eq(f64x4::splat(5.0) * b), Mask::from_array([false, true, false, false])); assert_eq!(a.lanes_ne(f64x4::splat(5.0) * b), Mask::from_array([true, false, true, true])); assert_eq!(a.lanes_le(f64x4::splat(5.0) * b), Mask::from_array([false, true, true, false])); From bfed3c4f0d285df97c0e9cbe342665b8b37b7a96 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 16 Mar 2022 20:33:54 -0400 Subject: [PATCH 2943/5092] implement simd bitmask intrinsics --- src/helpers.rs | 15 ------- src/shims/intrinsics.rs | 74 ++++++++++++++++++++++++++++++++- tests/run-pass/portable-simd.rs | 15 +++++++ 3 files changed, 87 insertions(+), 17 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index ba12e0a7e394..fe2f33ffd33e 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -775,18 +775,3 @@ pub fn isolation_abort_error(name: &str) -> InterpResult<'static> { name, ))) } - -pub fn bool_to_simd_element(b: bool, size: Size) -> Scalar { - // SIMD uses all-1 as pattern for "true" - let val = if b { -1 } else { 0 }; - Scalar::from_int(val, size) -} - -pub fn simd_element_to_bool<'tcx>(elem: ImmTy<'tcx, Tag>) -> InterpResult<'tcx, bool> { - let val = elem.to_scalar()?.to_int(elem.layout.size)?; - Ok(match val { - 0 => false, - -1 => true, - _ => throw_ub_format!("each element of a SIMD mask must be all-0-bits or all-1-bits"), - }) -} diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 726e6b6b9619..b704004e16c0 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -1,3 +1,4 @@ +use std::convert::TryInto; use std::iter; use log::trace; @@ -5,10 +6,10 @@ use log::trace; use rustc_apfloat::{Float, Round}; use rustc_middle::ty::layout::{HasParamEnv, IntegerExt, LayoutOf}; use rustc_middle::{mir, mir::BinOp, ty, ty::FloatTy}; -use rustc_target::abi::{Align, Integer}; +use rustc_target::abi::{Align, Endian, HasDataLayout, Integer, Size}; use crate::*; -use helpers::{bool_to_simd_element, check_arg_count, simd_element_to_bool}; +use helpers::check_arg_count; pub enum AtomicOp { MirOp(mir::BinOp, bool), @@ -663,6 +664,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_immediate(*val, &dest.into())?; } } + "simd_select_bitmask" => { + let &[ref mask, ref yes, ref no] = check_arg_count(args)?; + let (yes, yes_len) = this.operand_to_simd(yes)?; + let (no, no_len) = this.operand_to_simd(no)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + assert!(mask.layout.ty.is_integral()); + assert_eq!(dest_len.max(8), mask.layout.size.bits()); + assert!(dest_len <= 64); + assert_eq!(dest_len, yes_len); + assert_eq!(dest_len, no_len); + + let mask: u64 = this + .read_scalar(mask)? + .check_init()? + .to_bits(mask.layout.size)? + .try_into() + .unwrap(); + for i in 0..dest_len { + let mask = + mask & (1 << simd_bitmask_index(i, dest_len, this.data_layout().endian)); + let yes = this.read_immediate(&this.mplace_index(&yes, i)?.into())?; + let no = this.read_immediate(&this.mplace_index(&no, i)?.into())?; + let dest = this.mplace_index(&dest, i)?; + + let val = if mask != 0 { yes } else { no }; + this.write_immediate(*val, &dest.into())?; + } + } #[rustfmt::skip] "simd_cast" | "simd_as" => { let &[ref op] = check_arg_count(args)?; @@ -787,6 +817,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } + "simd_bitmask" => { + let &[ref op] = check_arg_count(args)?; + let (op, op_len) = this.operand_to_simd(op)?; + + assert!(dest.layout.ty.is_integral()); + assert_eq!(op_len.max(8), dest.layout.size.bits()); + assert!(op_len <= 64); + + let mut res = 0u64; + for i in 0..op_len { + let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; + if simd_element_to_bool(op)? { + res |= 1 << simd_bitmask_index(i, op_len, this.data_layout().endian); + } + } + this.write_int(res, dest)?; + } // Atomic operations "atomic_load" => this.atomic_load(args, dest, AtomicReadOp::SeqCst)?, @@ -1307,3 +1354,26 @@ fn fmin_op<'tcx>( FloatTy::F64 => Scalar::from_f64(left.to_f64()?.min(right.to_f64()?)), }) } + +fn bool_to_simd_element(b: bool, size: Size) -> Scalar { + // SIMD uses all-1 as pattern for "true" + let val = if b { -1 } else { 0 }; + Scalar::from_int(val, size) +} + +fn simd_element_to_bool<'tcx>(elem: ImmTy<'tcx, Tag>) -> InterpResult<'tcx, bool> { + let val = elem.to_scalar()?.to_int(elem.layout.size)?; + Ok(match val { + 0 => false, + -1 => true, + _ => throw_ub_format!("each element of a SIMD mask must be all-0-bits or all-1-bits"), + }) +} + +fn simd_bitmask_index(idx: u64, len: u64, endianess: Endian) -> u64 { + assert!(idx < len); + match endianess { + Endian::Little => idx, + Endian::Big => len.max(8) - 1 - idx, // reverse order of bits + } +} diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 80b0b4556c6e..a74559b72be4 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -187,6 +187,21 @@ fn simd_mask() { let intmask = Mask::from_int(i32x4::from_array([0, -1, 0, 0])); assert_eq!(intmask, Mask::from_array([false, true, false, false])); assert_eq!(intmask.to_array(), [false, true, false, false]); + + let values = [ + true, false, false, true, false, false, true, false, true, true, false, false, false, true, + false, true, + ]; + let mask = Mask::::from_array(values); + let bitmask = mask.to_bitmask(); + assert_eq!(bitmask, 0b1010001101001001); + assert_eq!(Mask::::from_bitmask(bitmask), mask); + + let values = [false, false, false, true]; + let mask = Mask::::from_array(values); + let bitmask = mask.to_bitmask(); + assert_eq!(bitmask, 0b1000); + assert_eq!(Mask::::from_bitmask(bitmask), mask); } fn simd_cast() { From b5d3a25b49f97301bfeaa632d1cf432b3c0e8a71 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 16 Mar 2022 20:52:01 -0400 Subject: [PATCH 2944/5092] detect when unused bits of a SIMD bitmask are non-0 --- src/shims/intrinsics.rs | 30 +++++++++++++------ .../intrinsics/simd-select-bitmask-invalid.rs | 15 ++++++++++ .../intrinsics/simd-select-invalid-bool.rs | 15 ++++++++++ 3 files changed, 51 insertions(+), 9 deletions(-) create mode 100644 tests/compile-fail/intrinsics/simd-select-bitmask-invalid.rs create mode 100644 tests/compile-fail/intrinsics/simd-select-invalid-bool.rs diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index b704004e16c0..495ad93951fe 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -669,10 +669,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (yes, yes_len) = this.operand_to_simd(yes)?; let (no, no_len) = this.operand_to_simd(no)?; let (dest, dest_len) = this.place_to_simd(dest)?; + let bitmask_len = dest_len.max(8); assert!(mask.layout.ty.is_integral()); - assert_eq!(dest_len.max(8), mask.layout.size.bits()); - assert!(dest_len <= 64); + assert!(bitmask_len <= 64); + assert_eq!(bitmask_len, mask.layout.size.bits()); assert_eq!(dest_len, yes_len); assert_eq!(dest_len, no_len); @@ -684,7 +685,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .unwrap(); for i in 0..dest_len { let mask = - mask & (1 << simd_bitmask_index(i, dest_len, this.data_layout().endian)); + mask & (1 << simd_bitmask_index(i, bitmask_len, this.data_layout().endian)); let yes = this.read_immediate(&this.mplace_index(&yes, i)?.into())?; let no = this.read_immediate(&this.mplace_index(&no, i)?.into())?; let dest = this.mplace_index(&dest, i)?; @@ -692,6 +693,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val = if mask != 0 { yes } else { no }; this.write_immediate(*val, &dest.into())?; } + for i in dest_len..bitmask_len { + // If the mask is "padded", ensure that padding is all-zero. + let mask = + mask & (1 << simd_bitmask_index(i, bitmask_len, this.data_layout().endian)); + if mask != 0 { + throw_ub_format!( + "a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits" + ); + } + } } #[rustfmt::skip] "simd_cast" | "simd_as" => { @@ -820,16 +831,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "simd_bitmask" => { let &[ref op] = check_arg_count(args)?; let (op, op_len) = this.operand_to_simd(op)?; + let bitmask_len = op_len.max(8); assert!(dest.layout.ty.is_integral()); - assert_eq!(op_len.max(8), dest.layout.size.bits()); - assert!(op_len <= 64); + assert!(bitmask_len <= 64); + assert_eq!(bitmask_len, dest.layout.size.bits()); let mut res = 0u64; for i in 0..op_len { let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; if simd_element_to_bool(op)? { - res |= 1 << simd_bitmask_index(i, op_len, this.data_layout().endian); + res |= 1 << simd_bitmask_index(i, bitmask_len, this.data_layout().endian); } } this.write_int(res, dest)?; @@ -1370,10 +1382,10 @@ fn simd_element_to_bool<'tcx>(elem: ImmTy<'tcx, Tag>) -> InterpResult<'tcx, bool }) } -fn simd_bitmask_index(idx: u64, len: u64, endianess: Endian) -> u64 { - assert!(idx < len); +fn simd_bitmask_index(idx: u64, bitmask_len: u64, endianess: Endian) -> u64 { + assert!(idx < bitmask_len); match endianess { Endian::Little => idx, - Endian::Big => len.max(8) - 1 - idx, // reverse order of bits + Endian::Big => bitmask_len - 1 - idx, // reverse order of bits } } diff --git a/tests/compile-fail/intrinsics/simd-select-bitmask-invalid.rs b/tests/compile-fail/intrinsics/simd-select-bitmask-invalid.rs new file mode 100644 index 000000000000..ab69072c3097 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-select-bitmask-invalid.rs @@ -0,0 +1,15 @@ +#![feature(platform_intrinsics, repr_simd)] + +extern "platform-intrinsic" { + fn simd_select_bitmask(m: M, yes: T, no: T) -> T; +} + +#[repr(simd)] +#[allow(non_camel_case_types)] +#[derive(Copy, Clone)] +struct i32x2(i32, i32); + +fn main() { unsafe { + let x = i32x2(0, 1); + simd_select_bitmask(0b11111111u8, x, x); //~ERROR bitmask less than 8 bits long must be filled with 0s for the remaining bits +} } diff --git a/tests/compile-fail/intrinsics/simd-select-invalid-bool.rs b/tests/compile-fail/intrinsics/simd-select-invalid-bool.rs new file mode 100644 index 000000000000..98f67cfcd7e1 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-select-invalid-bool.rs @@ -0,0 +1,15 @@ +#![feature(platform_intrinsics, repr_simd)] + +extern "platform-intrinsic" { + fn simd_select(m: M, yes: T, no: T) -> T; +} + +#[repr(simd)] +#[allow(non_camel_case_types)] +#[derive(Copy, Clone)] +struct i32x2(i32, i32); + +fn main() { unsafe { + let x = i32x2(0, 1); + simd_select(x, x, x); //~ERROR must be all-0-bits or all-1-bits +} } From 1b1321a685f4d5e362786c1876dbcc9e2de866ba Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 17 Mar 2022 13:14:16 -0400 Subject: [PATCH 2945/5092] fix simd_bitmask shorter than a byte on big-endian --- src/shims/intrinsics.rs | 13 ++++++------- tests/run-pass/portable-simd.rs | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 495ad93951fe..c344d0ff9c34 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -685,7 +685,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .unwrap(); for i in 0..dest_len { let mask = - mask & (1 << simd_bitmask_index(i, bitmask_len, this.data_layout().endian)); + mask & (1 << simd_bitmask_index(i, dest_len, this.data_layout().endian)); let yes = this.read_immediate(&this.mplace_index(&yes, i)?.into())?; let no = this.read_immediate(&this.mplace_index(&no, i)?.into())?; let dest = this.mplace_index(&dest, i)?; @@ -695,8 +695,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } for i in dest_len..bitmask_len { // If the mask is "padded", ensure that padding is all-zero. - let mask = - mask & (1 << simd_bitmask_index(i, bitmask_len, this.data_layout().endian)); + let mask = mask & (1 << i); if mask != 0 { throw_ub_format!( "a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits" @@ -841,7 +840,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx for i in 0..op_len { let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; if simd_element_to_bool(op)? { - res |= 1 << simd_bitmask_index(i, bitmask_len, this.data_layout().endian); + res |= 1 << simd_bitmask_index(i, op_len, this.data_layout().endian); } } this.write_int(res, dest)?; @@ -1382,10 +1381,10 @@ fn simd_element_to_bool<'tcx>(elem: ImmTy<'tcx, Tag>) -> InterpResult<'tcx, bool }) } -fn simd_bitmask_index(idx: u64, bitmask_len: u64, endianess: Endian) -> u64 { - assert!(idx < bitmask_len); +fn simd_bitmask_index(idx: u64, vec_len: u64, endianess: Endian) -> u64 { + assert!(idx < vec_len); match endianess { Endian::Little => idx, - Endian::Big => bitmask_len - 1 - idx, // reverse order of bits + Endian::Big => vec_len - 1 - idx, // reverse order of bits } } diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index a74559b72be4..99a64ea370f6 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -200,7 +200,7 @@ fn simd_mask() { let values = [false, false, false, true]; let mask = Mask::::from_array(values); let bitmask = mask.to_bitmask(); - assert_eq!(bitmask, 0b1000); + // FIXME fails until https://github.com/rust-lang/portable-simd/pull/267 lands: assert_eq!(bitmask, 0b1000); assert_eq!(Mask::::from_bitmask(bitmask), mask); } From 65125df1cd31b467dba2a71c03d6c4343e2a05b8 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 12 Mar 2022 17:23:22 -0500 Subject: [PATCH 2946/5092] Consider the cargo workspace when checking if a frame is local --- README.md | 5 ++++- cargo-miri/bin.rs | 41 +++++++++++++++++++++++++++++++---------- src/diagnostics.rs | 23 ++++++++++++----------- src/helpers.rs | 21 ++++++++++++++++++++- src/machine.rs | 13 ++++++++++++- 5 files changed, 79 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 0af25ccbff2c..fb999d85a192 100644 --- a/README.md +++ b/README.md @@ -375,9 +375,12 @@ binaries, and as such worth documenting: directory after loading all the source files, but before commencing interpretation. This is useful if the interpreted program wants a different working directory at run-time than at build-time. +* `MIRI_LOCAL_CRATES` is set by `cargo-miri` to tell the Miri driver which + crates should be given special treatment in diagnostics, in addition to the + crate currently being compiled. * `MIRI_VERBOSE` when set to any value tells the various `cargo-miri` phases to perform verbose logging. - + [testing-miri]: CONTRIBUTING.md#testing-the-miri-driver ## Miri `extern` functions diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index a946f7988833..373c63647c35 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -482,12 +482,13 @@ path = "lib.rs" } } -/// Detect the target directory by calling `cargo metadata`. -fn detect_target_dir() -> PathBuf { - #[derive(Deserialize)] - struct Metadata { - target_directory: PathBuf, - } +#[derive(Deserialize)] +struct Metadata { + target_directory: PathBuf, + workspace_members: Vec, +} + +fn get_cargo_metadata() -> Metadata { let mut cmd = cargo(); // `-Zunstable-options` is required by `--config`. cmd.args(["metadata", "--no-deps", "--format-version=1", "-Zunstable-options"]); @@ -514,9 +515,25 @@ fn detect_target_dir() -> PathBuf { if !status.success() { std::process::exit(status.code().unwrap_or(-1)); } - metadata - .unwrap_or_else(|e| show_error(format!("invalid `cargo metadata` output: {}", e))) - .target_directory + metadata.unwrap_or_else(|e| show_error(format!("invalid `cargo metadata` output: {}", e))) +} + +/// Pulls all the crates in this workspace from the cargo metadata. +/// Workspace members are emitted like "miri 0.1.0 (path+file:///path/to/miri)" +/// Additionally, somewhere between cargo metadata and TyCtxt, '-' gets replaced with '_' so we +/// make that same transformation here. +fn local_crates(metadata: &Metadata) -> String { + assert!(metadata.workspace_members.len() > 0); + let mut local_crates = String::new(); + for member in &metadata.workspace_members { + let name = member.split(" ").nth(0).unwrap(); + let name = name.replace("-", "_"); + local_crates.push_str(&name); + local_crates.push(','); + } + local_crates.pop(); // Remove the trailing ',' + + local_crates } fn phase_cargo_miri(mut args: env::Args) { @@ -595,8 +612,10 @@ fn phase_cargo_miri(mut args: env::Args) { } } + let metadata = get_cargo_metadata(); + // Detect the target directory if it's not specified via `--target-dir`. - let target_dir = target_dir.get_or_insert_with(detect_target_dir); + let target_dir = target_dir.get_or_insert_with(|| metadata.target_directory.clone()); // Set `--target-dir` to `miri` inside the original target directory. target_dir.push("miri"); @@ -628,6 +647,8 @@ fn phase_cargo_miri(mut args: env::Args) { // Set rustdoc to us as well, so we can run doctests. cmd.env("RUSTDOC", &cargo_miri_path); + cmd.env("MIRI_LOCAL_CRATES", local_crates(&metadata)); + // Run cargo. if verbose { eprintln!("[cargo-miri miri] RUSTC_WRAPPER={:?}", cargo_miri_path); diff --git a/src/diagnostics.rs b/src/diagnostics.rs index fbcb2e0d0ff7..0815d73d9bcb 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -4,7 +4,7 @@ use std::num::NonZeroU64; use log::trace; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty; use rustc_span::{source_map::DUMMY_SP, Span, SpanData, Symbol}; use crate::stacked_borrows::{AccessKind, SbTag}; @@ -94,7 +94,7 @@ fn prune_stacktrace<'mir, 'tcx>( // Only prune frames if there is at least one local frame. This check ensures that if // we get a backtrace that never makes it to the user code because it has detected a // bug in the Rust runtime, we don't prune away every frame. - let has_local_frame = stacktrace.iter().any(|frame| frame.instance.def_id().is_local()); + let has_local_frame = stacktrace.iter().any(|frame| ecx.machine.is_local(frame)); if has_local_frame { // This is part of the logic that `std` uses to select the relevant part of a // backtrace. But here, we only look for __rust_begin_short_backtrace, not @@ -115,7 +115,7 @@ fn prune_stacktrace<'mir, 'tcx>( // This len check ensures that we don't somehow remove every frame, as doing so breaks // the primary error message. while stacktrace.len() > 1 - && stacktrace.last().map_or(false, |e| !e.instance.def_id().is_local()) + && stacktrace.last().map_or(false, |frame| !ecx.machine.is_local(frame)) { stacktrace.pop(); } @@ -218,7 +218,7 @@ pub fn report_error<'tcx, 'mir>( e.print_backtrace(); msg.insert(0, e.to_string()); report_msg( - *ecx.tcx, + ecx, DiagLevel::Error, &if let Some(title) = title { format!("{}: {}", title, msg[0]) } else { msg[0].clone() }, msg, @@ -264,8 +264,8 @@ pub fn report_error<'tcx, 'mir>( /// We want to present a multi-line span message for some errors. Diagnostics do not support this /// directly, so we pass the lines as a `Vec` and display each line after the first with an /// additional `span_label` or `note` call. -fn report_msg<'tcx>( - tcx: TyCtxt<'tcx>, +fn report_msg<'mir, 'tcx>( + ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, diag_level: DiagLevel, title: &str, span_msg: Vec, @@ -273,10 +273,11 @@ fn report_msg<'tcx>( stacktrace: &[FrameInfo<'tcx>], ) { let span = stacktrace.first().map_or(DUMMY_SP, |fi| fi.span); + let sess = ecx.tcx.sess; let mut err = match diag_level { - DiagLevel::Error => tcx.sess.struct_span_err(span, title).forget_guarantee(), - DiagLevel::Warning => tcx.sess.struct_span_warn(span, title), - DiagLevel::Note => tcx.sess.diagnostic().span_note_diag(span, title), + DiagLevel::Error => sess.struct_span_err(span, title).forget_guarantee(), + DiagLevel::Warning => sess.struct_span_warn(span, title), + DiagLevel::Note => sess.diagnostic().span_note_diag(span, title), }; // Show main message. @@ -306,7 +307,7 @@ fn report_msg<'tcx>( } // Add backtrace for (idx, frame_info) in stacktrace.iter().enumerate() { - let is_local = frame_info.instance.def_id().is_local(); + let is_local = ecx.machine.is_local(frame_info); // No span for non-local frames and the first frame (which is the error site). if is_local && idx > 0 { err.span_note(frame_info.span, &frame_info.to_string()); @@ -426,7 +427,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => ("tracking was triggered", DiagLevel::Note), }; - report_msg(*this.tcx, diag_level, title, vec![msg], vec![], &stacktrace); + report_msg(this, diag_level, title, vec![msg], vec![], &stacktrace); } }); } diff --git a/src/helpers.rs b/src/helpers.rs index fe2f33ffd33e..3ffb983aa69e 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -12,7 +12,7 @@ use rustc_middle::ty::{ layout::{LayoutOf, TyAndLayout}, List, TyCtxt, }; -use rustc_span::Symbol; +use rustc_span::{def_id::CrateNum, Symbol}; use rustc_target::abi::{Align, FieldsShape, Size, Variants}; use rustc_target::spec::abi::Abi; @@ -775,3 +775,22 @@ pub fn isolation_abort_error(name: &str) -> InterpResult<'static> { name, ))) } + +/// Retrieve the list of local crates that should have been passed by cargo-miri in +/// MIRI_LOCAL_CRATES and turn them into `CrateNum`s. +pub fn get_local_crates(tcx: &TyCtxt<'_>) -> Vec { + // Convert the local crate names from the passed-in config into CrateNums so that they can + // be looked up quickly during execution + let local_crate_names = std::env::var("MIRI_LOCAL_CRATES") + .map(|crates| crates.split(",").map(|krate| krate.to_string()).collect::>()) + .unwrap_or_default(); + let mut local_crates = Vec::new(); + for &crate_num in tcx.crates(()) { + let name = tcx.crate_name(crate_num); + let name = name.as_str(); + if local_crate_names.iter().any(|local_name| local_name == name) { + local_crates.push(crate_num); + } + } + local_crates +} diff --git a/src/machine.rs b/src/machine.rs index bb43cb95507c..2cf7cd0fae0e 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -19,7 +19,7 @@ use rustc_middle::{ Instance, TyCtxt, }, }; -use rustc_span::def_id::DefId; +use rustc_span::def_id::{CrateNum, DefId}; use rustc_span::symbol::{sym, Symbol}; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; @@ -349,10 +349,14 @@ pub struct Evaluator<'mir, 'tcx> { /// Equivalent setting as RUST_BACKTRACE on encountering an error. pub(crate) backtrace_style: BacktraceStyle, + + /// Crates which are considered local for the purposes of error reporting. + pub(crate) local_crates: Vec, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Self { + let local_crates = helpers::get_local_crates(&layout_cx.tcx); let layouts = PrimitiveLayouts::new(layout_cx).expect("Couldn't get layouts of primitive types"); let profiler = config.measureme_out.as_ref().map(|out| { @@ -381,12 +385,19 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { exported_symbols_cache: FxHashMap::default(), panic_on_unsupported: config.panic_on_unsupported, backtrace_style: config.backtrace_style, + local_crates, } } pub(crate) fn communicate(&self) -> bool { self.isolated_op == IsolatedOp::Allow } + + /// Check whether the stack frame that this `FrameInfo` refers to is part of a local crate. + pub(crate) fn is_local(&self, frame: &FrameInfo<'_>) -> bool { + let def_id = frame.instance.def_id(); + def_id.is_local() || self.local_crates.contains(&def_id.krate) + } } /// A rustc InterpCx for Miri. From 2c670b10dfcfd23ff95ce32ba9bbc9d3ead14f05 Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Thu, 24 Feb 2022 22:11:20 -0800 Subject: [PATCH 2947/5092] add new version of backtrace api using flags=1 --- README.md | 28 ++- src/shims/backtrace.rs | 204 +++++++++++++----- src/shims/foreign_items.rs | 9 + .../backtrace/bad-backtrace-flags.rs | 9 + .../backtrace/bad-backtrace-resolve-flags.rs | 25 +++ .../bad-backtrace-resolve-names-flags.rs | 16 ++ .../backtrace/bad-backtrace-size-flags.rs | 9 + .../backtrace/bad-backtrace-version.rs | 9 - .../{backtrace-api.rs => backtrace-api-v0.rs} | 0 ...ace-api.stderr => backtrace-api-v0.stderr} | 10 +- tests/run-pass/backtrace-api-v0.stdout | 5 + tests/run-pass/backtrace-api-v1.rs | 65 ++++++ tests/run-pass/backtrace-api-v1.stderr | 18 ++ tests/run-pass/backtrace-api-v1.stdout | 5 + tests/run-pass/backtrace-api.stdout | 5 - 15 files changed, 335 insertions(+), 82 deletions(-) create mode 100644 tests/compile-fail/backtrace/bad-backtrace-flags.rs create mode 100644 tests/compile-fail/backtrace/bad-backtrace-resolve-flags.rs create mode 100644 tests/compile-fail/backtrace/bad-backtrace-resolve-names-flags.rs create mode 100644 tests/compile-fail/backtrace/bad-backtrace-size-flags.rs delete mode 100644 tests/compile-fail/backtrace/bad-backtrace-version.rs rename tests/run-pass/{backtrace-api.rs => backtrace-api-v0.rs} (100%) rename tests/run-pass/{backtrace-api.stderr => backtrace-api-v0.stderr} (82%) create mode 100644 tests/run-pass/backtrace-api-v0.stdout create mode 100644 tests/run-pass/backtrace-api-v1.rs create mode 100644 tests/run-pass/backtrace-api-v1.stderr create mode 100644 tests/run-pass/backtrace-api-v1.stdout delete mode 100644 tests/run-pass/backtrace-api.stdout diff --git a/README.md b/README.md index fb9a55669903..086ed1b0efa8 100644 --- a/README.md +++ b/README.md @@ -358,23 +358,28 @@ extern "Rust" { /// `ptr` has to point to the beginning of an allocated block. fn miri_static_root(ptr: *const u8); + // Miri-provided extern function to get the amount of frames in the current backtrace. + // The `flags` argument must be `0`. + fn miri_backtrace_size(flags: u64) -> usize; + /// Miri-provided extern function to obtain a backtrace of the current call stack. - /// This returns a boxed slice of pointers - each pointer is an opaque value - /// that is only useful when passed to `miri_resolve_frame` - /// The `flags` argument must be `0`. - fn miri_get_backtrace(flags: u64) -> Box<[*mut ()]>; + /// This writes a slice of pointers into `buf` - each pointer is an opaque value + /// that is only useful when passed to `miri_resolve_frame`. + /// `buf` must have `miri_backtrace_size(0) * pointer_size` bytes of space. + /// The `flags` argument must be `1`. + fn miri_get_backtrace(flags: u64, buf: *mut *mut ()); /// Miri-provided extern function to resolve a frame pointer obtained - /// from `miri_get_backtrace`. The `flags` argument must be `0`, + /// from `miri_get_backtrace`. The `flags` argument must be `1`, /// and `MiriFrame` should be declared as follows: /// /// ```rust /// #[repr(C)] /// struct MiriFrame { - /// // The name of the function being executed, encoded in UTF-8 - /// name: Box<[u8]>, - /// // The filename of the function being executed, encoded in UTF-8 - /// filename: Box<[u8]>, + /// // The size of the name of the function being executed, encoded in UTF-8 + /// name_len: usize, + /// // The size of filename of the function being executed, encoded in UTF-8 + /// filename_len: usize, /// // The line number currently being executed in `filename`, starting from '1'. /// lineno: u32, /// // The column number currently being executed in `filename`, starting from '1'. @@ -390,6 +395,11 @@ extern "Rust" { /// This function can be called on any thread (not just the one which obtained `frame`). fn miri_resolve_frame(frame: *mut (), flags: u64) -> MiriFrame; + /// Miri-provided extern function to get the name and filename of the frame provided by `miri_resolve_frame`. + /// `name_buf` and `filename_buf` should be allocated with the `name_len` and `filename_len` fields of `MiriFrame`. + /// The flags argument must be `0`. + fn miri_resolve_frame_names(ptr: *mut (), flags: u64, name_buf: *mut u8, filename_buf: *mut u8); + /// Miri-provided extern function to begin unwinding with the given payload. /// /// This is internal and unstable and should not be used; we give it here diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index eb25cfd9935f..52a8ac98f2de 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -1,13 +1,33 @@ use crate::*; use rustc_ast::ast::Mutability; use rustc_middle::ty::layout::LayoutOf as _; -use rustc_middle::ty::{self, TypeAndMut}; -use rustc_span::{BytePos, Symbol}; +use rustc_middle::ty::{self, Instance, TypeAndMut}; +use rustc_span::{BytePos, Loc, Symbol}; use rustc_target::{abi::Size, spec::abi::Abi}; use std::convert::TryInto as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn handle_miri_backtrace_size( + &mut self, + abi: Abi, + link_name: Symbol, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let &[ref flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; + + let flags = this.read_scalar(flags)?.to_u64()?; + if flags != 0 { + throw_unsup_format!("unknown `miri_backtrace_size` flags {}", flags); + } + + let frame_count = this.active_thread_stack().len(); + + this.write_scalar(Scalar::from_machine_usize(frame_count.try_into().unwrap(), this), dest) + } + fn handle_miri_get_backtrace( &mut self, abi: Abi, @@ -17,12 +37,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let tcx = this.tcx; - let &[ref flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; - let flags = this.read_scalar(flags)?.to_u64()?; - if flags != 0 { - throw_unsup_format!("unknown `miri_get_backtrace` flags {}", flags); - } + let flags = if let Some(flags_op) = args.get(0) { + this.read_scalar(flags_op)?.to_u64()? + } else { + throw_ub_format!("expected at least 1 argument") + }; let mut data = Vec::new(); for frame in this.active_thread_stack().iter().rev() { @@ -49,46 +69,60 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) .collect(); - let len = ptrs.len(); + let len: u64 = ptrs.len().try_into().unwrap(); let ptr_ty = tcx.mk_ptr(TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Mut }); - let array_ty = tcx.mk_array(ptr_ty, ptrs.len().try_into().unwrap()); + let array_layout = this.layout_of(tcx.mk_array(ptr_ty, len)).unwrap(); - // Write pointers into array - let alloc = - this.allocate(this.layout_of(array_ty).unwrap(), MiriMemoryKind::Rust.into())?; - for (i, ptr) in ptrs.into_iter().enumerate() { - let place = this.mplace_index(&alloc, i as u64)?; - this.write_pointer(ptr, &place.into())?; - } + match flags { + // storage for pointers is allocated by miri + // deallocating the slice is undefined behavior with a custom global allocator + 0 => { + let &[_flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; + + let alloc = this.allocate(array_layout, MiriMemoryKind::Rust.into())?; + + // Write pointers into array + for (i, ptr) in ptrs.into_iter().enumerate() { + let place = this.mplace_index(&alloc, i as u64)?; + + this.write_pointer(ptr, &place.into())?; + } + + this.write_immediate( + Immediate::new_slice(Scalar::from_maybe_pointer(alloc.ptr, this), len, this), + dest, + )?; + } + // storage for pointers is allocated by the caller + 1 => { + let &[_flags, ref buf] = this.check_shim(abi, Abi::Rust, link_name, args)?; + + let buf_place = this.deref_operand(buf)?; + + let ptr_layout = this.layout_of(ptr_ty)?; + + for (i, ptr) in ptrs.into_iter().enumerate() { + let offset = ptr_layout.size * i.try_into().unwrap(); + + let op_place = + buf_place.offset(offset, MemPlaceMeta::None, ptr_layout, this)?; + + this.write_pointer(ptr, &op_place.into())?; + } + } + _ => throw_unsup_format!("unknown `miri_get_backtrace` flags {}", flags), + }; - this.write_immediate( - Immediate::new_slice( - Scalar::from_maybe_pointer(alloc.ptr, this), - len.try_into().unwrap(), - this, - ), - dest, - )?; Ok(()) } - fn handle_miri_resolve_frame( + fn resolve_frame_pointer( &mut self, - abi: Abi, - link_name: Symbol, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { + ptr: &OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, (Instance<'tcx>, Loc, String, String)> { let this = self.eval_context_mut(); - let tcx = this.tcx; - let &[ref ptr, ref flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; - - let flags = this.read_scalar(flags)?.to_u64()?; - if flags != 0 { - throw_unsup_format!("unknown `miri_resolve_frame` flags {}", flags); - } let ptr = this.read_pointer(ptr)?; // Take apart the pointer, we need its pieces. @@ -101,6 +135,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_ub_format!("expected function pointer, found {:?}", ptr); }; + let lo = + this.tcx.sess.source_map().lookup_char_pos(BytePos(offset.bytes().try_into().unwrap())); + + let name = fn_instance.to_string(); + let filename = lo.file.name.prefer_remapped().to_string(); + + Ok((fn_instance, lo, name, filename)) + } + + fn handle_miri_resolve_frame( + &mut self, + abi: Abi, + link_name: Symbol, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let &[ref ptr, ref flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; + + let flags = this.read_scalar(flags)?.to_u64()?; + + let (fn_instance, lo, name, filename) = this.resolve_frame_pointer(ptr)?; + // Reconstruct the original function pointer, // which we pass to user code. let fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(fn_instance)); @@ -115,23 +172,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); } - let pos = BytePos(offset.bytes().try_into().unwrap()); - let name = fn_instance.to_string(); - - let lo = tcx.sess.source_map().lookup_char_pos(pos); - - let filename = lo.file.name.prefer_remapped().to_string(); let lineno: u32 = lo.line as u32; // `lo.col` is 0-based - add 1 to make it 1-based for the caller. let colno: u32 = lo.col.0 as u32 + 1; - // These are "mutable" allocations as we consider them to be owned by the callee. - let name_alloc = this.allocate_str(&name, MiriMemoryKind::Rust.into(), Mutability::Mut); - let filename_alloc = - this.allocate_str(&filename, MiriMemoryKind::Rust.into(), Mutability::Mut); - let lineno_alloc = Scalar::from_u32(lineno); - let colno_alloc = Scalar::from_u32(colno); - let dest = this.force_allocation(dest)?; if let ty::Adt(adt, _) = dest.layout.ty.kind() { if !adt.repr.c() { @@ -141,10 +185,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - this.write_immediate(name_alloc.to_ref(this), &this.mplace_field(&dest, 0)?.into())?; - this.write_immediate(filename_alloc.to_ref(this), &this.mplace_field(&dest, 1)?.into())?; - this.write_scalar(lineno_alloc, &this.mplace_field(&dest, 2)?.into())?; - this.write_scalar(colno_alloc, &this.mplace_field(&dest, 3)?.into())?; + match flags { + 0 => { + // These are "mutable" allocations as we consider them to be owned by the callee. + let name_alloc = + this.allocate_str(&name, MiriMemoryKind::Rust.into(), Mutability::Mut); + let filename_alloc = + this.allocate_str(&filename, MiriMemoryKind::Rust.into(), Mutability::Mut); + + this.write_immediate( + name_alloc.to_ref(this), + &this.mplace_field(&dest, 0)?.into(), + )?; + this.write_immediate( + filename_alloc.to_ref(this), + &this.mplace_field(&dest, 1)?.into(), + )?; + } + 1 => { + this.write_scalar( + Scalar::from_machine_usize(name.len().try_into().unwrap(), this), + &this.mplace_field(&dest, 0)?.into(), + )?; + this.write_scalar( + Scalar::from_machine_usize(filename.len().try_into().unwrap(), this), + &this.mplace_field(&dest, 1)?.into(), + )?; + } + _ => throw_unsup_format!("unknown `miri_resolve_frame` flags {}", flags), + } + + this.write_scalar(Scalar::from_u32(lineno), &this.mplace_field(&dest, 2)?.into())?; + this.write_scalar(Scalar::from_u32(colno), &this.mplace_field(&dest, 3)?.into())?; // Support a 4-field struct for now - this is deprecated // and slated for removal. @@ -154,4 +226,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } + + fn handle_miri_resolve_frame_names( + &mut self, + abi: Abi, + link_name: Symbol, + args: &[OpTy<'tcx, Tag>], + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let &[ref ptr, ref flags, ref name_ptr, ref filename_ptr] = + this.check_shim(abi, Abi::Rust, link_name, args)?; + + let flags = this.read_scalar(flags)?.to_u64()?; + if flags != 0 { + throw_unsup_format!("unknown `miri_resolve_frame_names` flags {}", flags); + } + + let (_, _, name, filename) = this.resolve_frame_pointer(ptr)?; + + this.memory.write_bytes(this.read_pointer(name_ptr)?, name.bytes())?; + this.memory.write_bytes(this.read_pointer(filename_ptr)?, filename.bytes())?; + + Ok(()) + } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index b07db9535129..ecffd310de56 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -380,6 +380,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.static_roots.push(alloc_id); } + // Obtains the size of a Miri backtrace. See the README for details. + "miri_backtrace_size" => { + this.handle_miri_backtrace_size(abi, link_name, args, dest)?; + } + // Obtains a Miri backtrace. See the README for details. "miri_get_backtrace" => { // `check_shim` happens inside `handle_miri_get_backtrace`. @@ -392,6 +397,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.handle_miri_resolve_frame(abi, link_name, args, dest)?; } + // Writes the function and file names of a Miri backtrace frame into a user provided buffer. See the README for details. + "miri_resolve_frame_names" => { + this.handle_miri_resolve_frame_names(abi, link_name, args)?; + } // Standard C allocation "malloc" => { diff --git a/tests/compile-fail/backtrace/bad-backtrace-flags.rs b/tests/compile-fail/backtrace/bad-backtrace-flags.rs new file mode 100644 index 000000000000..5f30513e931e --- /dev/null +++ b/tests/compile-fail/backtrace/bad-backtrace-flags.rs @@ -0,0 +1,9 @@ +extern "Rust" { + fn miri_get_backtrace(flags: u64, buf: *mut *mut ()); +} + +fn main() { + unsafe { + miri_get_backtrace(2, 0 as *mut _); //~ ERROR unsupported operation: unknown `miri_get_backtrace` flags 2 + } +} diff --git a/tests/compile-fail/backtrace/bad-backtrace-resolve-flags.rs b/tests/compile-fail/backtrace/bad-backtrace-resolve-flags.rs new file mode 100644 index 000000000000..5a30253a893b --- /dev/null +++ b/tests/compile-fail/backtrace/bad-backtrace-resolve-flags.rs @@ -0,0 +1,25 @@ +#[repr(C)] +struct MiriFrame { + name_len: usize, + filename_len: usize, + lineno: u32, + colno: u32, + fn_ptr: *mut (), +} + +extern "Rust" { + fn miri_backtrace_size(flags: u64) -> usize; + fn miri_get_backtrace(flags: u64, buf: *mut *mut ()); + fn miri_resolve_frame(ptr: *mut (), flags: u64) -> MiriFrame; +} + +fn main() { + unsafe { + let mut buf = vec![0 as *mut _; miri_backtrace_size(0)]; + + miri_get_backtrace(1, buf.as_mut_ptr()); + + // miri_resolve_frame will error from an invalid backtrace before it will from invalid flags + miri_resolve_frame(buf[0], 2); //~ ERROR unsupported operation: unknown `miri_resolve_frame` flags 2 + } +} diff --git a/tests/compile-fail/backtrace/bad-backtrace-resolve-names-flags.rs b/tests/compile-fail/backtrace/bad-backtrace-resolve-names-flags.rs new file mode 100644 index 000000000000..8e69a275753f --- /dev/null +++ b/tests/compile-fail/backtrace/bad-backtrace-resolve-names-flags.rs @@ -0,0 +1,16 @@ +extern "Rust" { + fn miri_backtrace_size(flags: u64) -> usize; + fn miri_get_backtrace(flags: u64, buf: *mut *mut ()); + fn miri_resolve_frame_names(ptr: *mut (), flags: u64, name_buf: *mut u8, filename_buf: *mut u8); +} + +fn main() { + unsafe { + let mut buf = vec![0 as *mut _; miri_backtrace_size(0)]; + + miri_get_backtrace(1, buf.as_mut_ptr()); + + // miri_resolve_frame_names will error from an invalid backtrace before it will from invalid flags + miri_resolve_frame_names(buf[0], 2, 0 as *mut _, 0 as *mut _); //~ ERROR unsupported operation: unknown `miri_resolve_frame_names` flags 2 + } +} diff --git a/tests/compile-fail/backtrace/bad-backtrace-size-flags.rs b/tests/compile-fail/backtrace/bad-backtrace-size-flags.rs new file mode 100644 index 000000000000..25eded9e48df --- /dev/null +++ b/tests/compile-fail/backtrace/bad-backtrace-size-flags.rs @@ -0,0 +1,9 @@ +extern "Rust" { + fn miri_backtrace_size(flags: u64) -> usize; +} + +fn main() { + unsafe { + miri_backtrace_size(2); //~ ERROR unsupported operation: unknown `miri_backtrace_size` flags 2 + } +} diff --git a/tests/compile-fail/backtrace/bad-backtrace-version.rs b/tests/compile-fail/backtrace/bad-backtrace-version.rs deleted file mode 100644 index 4579b5d0ade8..000000000000 --- a/tests/compile-fail/backtrace/bad-backtrace-version.rs +++ /dev/null @@ -1,9 +0,0 @@ -extern "Rust" { - fn miri_resolve_frame(ptr: *mut (), flags: u64); -} - -fn main() { - unsafe { - miri_resolve_frame(0 as *mut _, 1); //~ ERROR unsupported operation: unknown `miri_resolve_frame` flags 1 - } -} diff --git a/tests/run-pass/backtrace-api.rs b/tests/run-pass/backtrace-api-v0.rs similarity index 100% rename from tests/run-pass/backtrace-api.rs rename to tests/run-pass/backtrace-api-v0.rs diff --git a/tests/run-pass/backtrace-api.stderr b/tests/run-pass/backtrace-api-v0.stderr similarity index 82% rename from tests/run-pass/backtrace-api.stderr rename to tests/run-pass/backtrace-api-v0.stderr index bd5908ba2979..8a697a44ea9d 100644 --- a/tests/run-pass/backtrace-api.stderr +++ b/tests/run-pass/backtrace-api-v0.stderr @@ -1,8 +1,8 @@ -$DIR/backtrace-api.rs:13:59 (func_d) -$DIR/backtrace-api.rs:12:50 (func_c) -$DIR/backtrace-api.rs:6:53 (func_b) -$DIR/backtrace-api.rs:5:50 (func_a) -$DIR/backtrace-api.rs:17:18 (main) +$DIR/backtrace-api-v0.rs:13:59 (func_d) +$DIR/backtrace-api-v0.rs:12:50 (func_c) +$DIR/backtrace-api-v0.rs:6:53 (func_b) +$DIR/backtrace-api-v0.rs:5:50 (func_a) +$DIR/backtrace-api-v0.rs:17:18 (main) RUSTLIB/core/src/ops/function.rs:LL:COL (>::call_once - shim(fn())) RUSTLIB/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace) RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start::{closure#0}) diff --git a/tests/run-pass/backtrace-api-v0.stdout b/tests/run-pass/backtrace-api-v0.stdout new file mode 100644 index 000000000000..c80a3f3bbcab --- /dev/null +++ b/tests/run-pass/backtrace-api-v0.stdout @@ -0,0 +1,5 @@ +$DIR/backtrace-api-v0.rs:13:59 (func_d) +$DIR/backtrace-api-v0.rs:12:50 (func_c) +$DIR/backtrace-api-v0.rs:6:53 (func_b::) +$DIR/backtrace-api-v0.rs:5:50 (func_a) +$DIR/backtrace-api-v0.rs:17:18 (main) diff --git a/tests/run-pass/backtrace-api-v1.rs b/tests/run-pass/backtrace-api-v1.rs new file mode 100644 index 000000000000..7b72c85812eb --- /dev/null +++ b/tests/run-pass/backtrace-api-v1.rs @@ -0,0 +1,65 @@ +// normalize-stderr-test ".*/(rust[^/]*|checkout)/library/" -> "RUSTLIB/" +// normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL " +// normalize-stderr-test "::<.*>" -> "" + +#[inline(never)] fn func_a() -> Box<[*mut ()]> { func_b::() } +#[inline(never)] fn func_b() -> Box<[*mut ()]> { func_c() } + +macro_rules! invoke_func_d { + () => { func_d() } +} + +#[inline(never)] fn func_c() -> Box<[*mut ()]> { invoke_func_d!() } +#[inline(never)] fn func_d() -> Box<[*mut ()]> { unsafe { let count = miri_backtrace_size(0); let mut buf = vec![std::ptr::null_mut(); count]; miri_get_backtrace(1, buf.as_mut_ptr()); buf.into() } } + +fn main() { + let mut seen_main = false; + let frames = func_a(); + for frame in frames.into_iter() { + let miri_frame = unsafe { miri_resolve_frame(*frame, 1) }; + + let mut name = vec![0; miri_frame.name_len]; + let mut filename = vec![0; miri_frame.filename_len]; + + unsafe { + miri_resolve_frame_names(*frame, 0, name.as_mut_ptr(), filename.as_mut_ptr()); + } + + let name = String::from_utf8(name).unwrap(); + let filename = String::from_utf8(filename).unwrap(); + + if name == "func_a" { + assert_eq!(func_a as *mut (), miri_frame.fn_ptr); + } + + // Print every frame to stderr. + let out = format!("{}:{}:{} ({})", filename, miri_frame.lineno, miri_frame.colno, name); + eprintln!("{}", out); + // Print the 'main' frame (and everything before it) to stdout, skipping + // the printing of internal (and possibly fragile) libstd frames. + if !seen_main { + println!("{}", out); + seen_main = name == "main"; + } + } +} + +// This goes at the bottom of the file so that we can change it +// without disturbing line numbers of the functions in the backtrace. + +extern "Rust" { + fn miri_backtrace_size(flags: u64) -> usize; + fn miri_get_backtrace(flags: u64, buf: *mut *mut ()); + fn miri_resolve_frame(ptr: *mut (), flags: u64) -> MiriFrame; + fn miri_resolve_frame_names(ptr: *mut (), flags: u64, name_buf: *mut u8, filename_buf: *mut u8); +} + +#[derive(Debug)] +#[repr(C)] +struct MiriFrame { + name_len: usize, + filename_len: usize, + lineno: u32, + colno: u32, + fn_ptr: *mut (), +} \ No newline at end of file diff --git a/tests/run-pass/backtrace-api-v1.stderr b/tests/run-pass/backtrace-api-v1.stderr new file mode 100644 index 000000000000..806a1c60f5a0 --- /dev/null +++ b/tests/run-pass/backtrace-api-v1.stderr @@ -0,0 +1,18 @@ +$DIR/backtrace-api-v1.rs:13:144 (func_d) +$DIR/backtrace-api-v1.rs:12:50 (func_c) +$DIR/backtrace-api-v1.rs:6:53 (func_b) +$DIR/backtrace-api-v1.rs:5:50 (func_a) +$DIR/backtrace-api-v1.rs:17:18 (main) +RUSTLIB/core/src/ops/function.rs:LL:COL (>::call_once - shim(fn())) +RUSTLIB/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace) +RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start::{closure#0}) +RUSTLIB/core/src/ops/function.rs:LL:COL (std::ops::function::impls::call_once) +RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try::do_call) +RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try) +RUSTLIB/std/src/panic.rs:LL:COL (std::panic::catch_unwind) +RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start_internal::{closure#2}) +RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try::do_call) +RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try) +RUSTLIB/std/src/panic.rs:LL:COL (std::panic::catch_unwind) +RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start_internal) +RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start) diff --git a/tests/run-pass/backtrace-api-v1.stdout b/tests/run-pass/backtrace-api-v1.stdout new file mode 100644 index 000000000000..2670d560eb19 --- /dev/null +++ b/tests/run-pass/backtrace-api-v1.stdout @@ -0,0 +1,5 @@ +$DIR/backtrace-api-v1.rs:13:144 (func_d) +$DIR/backtrace-api-v1.rs:12:50 (func_c) +$DIR/backtrace-api-v1.rs:6:53 (func_b::) +$DIR/backtrace-api-v1.rs:5:50 (func_a) +$DIR/backtrace-api-v1.rs:17:18 (main) diff --git a/tests/run-pass/backtrace-api.stdout b/tests/run-pass/backtrace-api.stdout deleted file mode 100644 index 175ff3b82946..000000000000 --- a/tests/run-pass/backtrace-api.stdout +++ /dev/null @@ -1,5 +0,0 @@ -$DIR/backtrace-api.rs:13:59 (func_d) -$DIR/backtrace-api.rs:12:50 (func_c) -$DIR/backtrace-api.rs:6:53 (func_b::) -$DIR/backtrace-api.rs:5:50 (func_a) -$DIR/backtrace-api.rs:17:18 (main) From 65469fe85bd1ca30ee5f890e49799d6a67688006 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Mar 2022 13:37:46 -0500 Subject: [PATCH 2948/5092] test remove_dir_all --- src/shims/posix/macos/dlsym.rs | 1 - tests/run-pass/fs.rs | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/shims/posix/macos/dlsym.rs b/src/shims/posix/macos/dlsym.rs index 9994bfd53dc5..d5996cc6a9ed 100644 --- a/src/shims/posix/macos/dlsym.rs +++ b/src/shims/posix/macos/dlsym.rs @@ -17,7 +17,6 @@ impl Dlsym { pub fn from_str(name: &str) -> InterpResult<'static, Option> { Ok(match name { "getentropy" => Some(Dlsym::getentropy), - "openat" => None, // std has a fallback for this _ => throw_unsup_format!("unsupported macOS dlsym: {}", name), }) } diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 7f5553e2f2cb..67817e3e2c85 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -395,6 +395,12 @@ fn test_directory() { remove_dir(&dir_path).unwrap(); // Reading the metadata of a non-existent directory should fail with a "not found" error. assert_eq!(ErrorKind::NotFound, check_metadata(&[], &dir_path).unwrap_err().kind()); + + // To test remove_dir_all, re-create the directory with a file and a directory in it. + create_dir(&dir_path).unwrap(); + drop(File::create(&path_1).unwrap()); + create_dir(&path_2).unwrap(); + remove_dir_all(&dir_path).unwrap(); } fn test_dup_stdout_stderr() { From 1cda05e174b9860f6c683a55167ab577988c999e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 20 Mar 2022 10:36:44 -0400 Subject: [PATCH 2949/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 5306a4d18628..249d5ad47eb8 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e95b10ba4ac4564ed25f7eef143e3182c33b3902 +c7ce69faf2a7ea16c15d922985ca27ba70da30ee From aafc0694fc002c744b4aa7aa77186bcd0a58622f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 18 Mar 2022 08:50:49 -0400 Subject: [PATCH 2950/5092] test arbitrary-self dyn receivers --- tests/run-pass/dyn-arbitrary-self.rs | 134 +++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 tests/run-pass/dyn-arbitrary-self.rs diff --git a/tests/run-pass/dyn-arbitrary-self.rs b/tests/run-pass/dyn-arbitrary-self.rs new file mode 100644 index 000000000000..9003c478990b --- /dev/null +++ b/tests/run-pass/dyn-arbitrary-self.rs @@ -0,0 +1,134 @@ +#![feature(arbitrary_self_types, unsize, coerce_unsized, dispatch_from_dyn)] +#![feature(rustc_attrs)] + +fn pin_box_dyn() { + use std::pin::Pin; + + trait Foo { + fn bar(self: Pin<&mut Self>) -> bool; + } + + impl Foo for &'static str { + fn bar(self: Pin<&mut Self>) -> bool { + true + } + } + + let mut test: Pin> = Box::pin("foo"); + test.as_mut().bar(); +} + +fn stdlib_pointers() { + use std::{ + rc::Rc, + sync::Arc, + pin::Pin, + }; + + trait Trait { + fn by_rc(self: Rc) -> i64; + fn by_arc(self: Arc) -> i64; + fn by_pin_mut(self: Pin<&mut Self>) -> i64; + fn by_pin_box(self: Pin>) -> i64; + } + + impl Trait for i64 { + fn by_rc(self: Rc) -> i64 { + *self + } + fn by_arc(self: Arc) -> i64 { + *self + } + fn by_pin_mut(self: Pin<&mut Self>) -> i64 { + *self + } + fn by_pin_box(self: Pin>) -> i64 { + *self + } + } + + let rc = Rc::new(1i64) as Rc; + assert_eq!(1, rc.by_rc()); + + let arc = Arc::new(2i64) as Arc; + assert_eq!(2, arc.by_arc()); + + let mut value = 3i64; + let pin_mut = Pin::new(&mut value) as Pin<&mut dyn Trait>; + assert_eq!(3, pin_mut.by_pin_mut()); + + let pin_box = Into::>>::into(Box::new(4i64)) as Pin>; + assert_eq!(4, pin_box.by_pin_box()); +} + +fn pointers_and_wrappers() { + use std::{ + ops::{Deref, CoerceUnsized, DispatchFromDyn}, + marker::Unsize, + }; + + struct Ptr(Box); + + impl Deref for Ptr { + type Target = T; + + fn deref(&self) -> &T { + &*self.0 + } + } + + impl + ?Sized, U: ?Sized> CoerceUnsized> for Ptr {} + impl + ?Sized, U: ?Sized> DispatchFromDyn> for Ptr {} + + struct Wrapper(T); + + impl Deref for Wrapper { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } + } + + impl, U> CoerceUnsized> for Wrapper {} + impl, U> DispatchFromDyn> for Wrapper {} + + + trait Trait { + // This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable + // without unsized_locals), but wrappers arond `Self` currently are not. + // FIXME (mikeyhew) uncomment this when unsized rvalues object-safety is implemented + // fn wrapper(self: Wrapper) -> i32; + fn ptr_wrapper(self: Ptr>) -> i32; + fn wrapper_ptr(self: Wrapper>) -> i32; + fn wrapper_ptr_wrapper(self: Wrapper>>) -> i32; + } + + impl Trait for i32 { + fn ptr_wrapper(self: Ptr>) -> i32 { + **self + } + fn wrapper_ptr(self: Wrapper>) -> i32 { + **self + } + fn wrapper_ptr_wrapper(self: Wrapper>>) -> i32 { + ***self + } + } + + let pw = Ptr(Box::new(Wrapper(5))) as Ptr>; + assert_eq!(pw.ptr_wrapper(), 5); + + let wp = Wrapper(Ptr(Box::new(6))) as Wrapper>; + assert_eq!(wp.wrapper_ptr(), 6); + + let wpw = Wrapper(Ptr(Box::new(Wrapper(7)))) as Wrapper>>; + assert_eq!(wpw.wrapper_ptr_wrapper(), 7); +} + + +fn main() { + pin_box_dyn(); + stdlib_pointers(); + pointers_and_wrappers(); +} From b066856f34240fdb8789c1ddd0c732a50a27b0f8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 20 Mar 2022 14:04:05 -0400 Subject: [PATCH 2951/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 249d5ad47eb8..561d020f1200 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c7ce69faf2a7ea16c15d922985ca27ba70da30ee +9bd53718e2537d95d8c092609618c2dcd6f05127 From 694846f8b462739ecefc476e7b2a9662ead3759d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 22 Mar 2022 14:26:40 -0400 Subject: [PATCH 2952/5092] vec test: check number validity --- tests/run-pass/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/vec.rs b/tests/run-pass/vec.rs index c0cf42134527..44e25387fff4 100644 --- a/tests/run-pass/vec.rs +++ b/tests/run-pass/vec.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-tag-raw-pointers +// compile-flags: -Zmiri-tag-raw-pointers -Zmiri-check-number-validity // Gather all references from a mutable iterator and make sure Miri notices if // using them is dangerous. fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { From 951ac65f265022a30e9538c4123862728f0816b1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 22 Mar 2022 14:28:36 -0400 Subject: [PATCH 2953/5092] regression test for reverse() unsoundness --- tests/run-pass/vec.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/run-pass/vec.rs b/tests/run-pass/vec.rs index 44e25387fff4..102396f4b91f 100644 --- a/tests/run-pass/vec.rs +++ b/tests/run-pass/vec.rs @@ -148,6 +148,16 @@ fn swap_remove() { vec.swap_remove(1); } +fn reverse() { + #[repr(align(2))] + #[derive(Debug)] + struct Foo(u8); + + let mut v: Vec<_> = (0..50).map(Foo).collect(); + v.reverse(); + assert!(v[0].0 == 49); +} + fn main() { assert_eq!(vec_reallocate().len(), 5); @@ -176,4 +186,5 @@ fn main() { sort(); swap(); swap_remove(); + reverse(); } From 3275df31ea91d638fd75cc5f627c211de8bd8f71 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 24 Mar 2022 10:06:33 -0400 Subject: [PATCH 2954/5092] rustup --- rust-version | 2 +- tests/compile-fail/null_pointer_deref.rs | 2 +- tests/compile-fail/null_pointer_write.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 561d020f1200..7c9e50da5ceb 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9bd53718e2537d95d8c092609618c2dcd6f05127 +d2df372bca13bb60979c909660e69f2451630e81 diff --git a/tests/compile-fail/null_pointer_deref.rs b/tests/compile-fail/null_pointer_deref.rs index 076b2df609ab..92c45b183c0c 100644 --- a/tests/compile-fail/null_pointer_deref.rs +++ b/tests/compile-fail/null_pointer_deref.rs @@ -1,5 +1,5 @@ #[allow(deref_nullptr)] fn main() { - let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR null pointer is not a valid pointer for this operation + let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR null pointer is not a valid pointer panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/null_pointer_write.rs b/tests/compile-fail/null_pointer_write.rs index 5294e60c025f..f8dca6882c2d 100644 --- a/tests/compile-fail/null_pointer_write.rs +++ b/tests/compile-fail/null_pointer_write.rs @@ -1,4 +1,4 @@ #[allow(deref_nullptr)] fn main() { - unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR null pointer is not a valid pointer for this operation + unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR null pointer is not a valid pointer } From 9772c85ebc9620050eec48a322d96d7474ab97f5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 26 Mar 2022 10:44:30 -0400 Subject: [PATCH 2955/5092] another test for too big type --- .../{slice-too-big.rs => too-big-slice.rs} | 0 tests/compile-fail/too-big-unsized.rs | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+) rename tests/compile-fail/{slice-too-big.rs => too-big-slice.rs} (100%) create mode 100644 tests/compile-fail/too-big-unsized.rs diff --git a/tests/compile-fail/slice-too-big.rs b/tests/compile-fail/too-big-slice.rs similarity index 100% rename from tests/compile-fail/slice-too-big.rs rename to tests/compile-fail/too-big-slice.rs diff --git a/tests/compile-fail/too-big-unsized.rs b/tests/compile-fail/too-big-unsized.rs new file mode 100644 index 000000000000..ad7bc6e938ac --- /dev/null +++ b/tests/compile-fail/too-big-unsized.rs @@ -0,0 +1,18 @@ +use std::mem; + +#[allow(unused)] +struct MySlice { + prefix: u64, + tail: [u8], +} + +#[cfg(target_pointer_width = "64")] +const TOO_BIG: usize = 1usize << 47; +#[cfg(target_pointer_width = "32")] +const TOO_BIG: usize = 1usize << 31; + +fn main() { unsafe { + let ptr = Box::into_raw(Box::new(0u8)); + // The slice part is actually not "too big", but together with the `prefix` field it is. + let _x: &MySlice = mem::transmute((ptr, TOO_BIG-1)); //~ ERROR: invalid reference metadata: total size is bigger than largest supported object +} } From ede470e1fcb8b6e488f39c48a84cde0f639adcc9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 26 Mar 2022 13:10:20 -0400 Subject: [PATCH 2956/5092] ensure that -Zmiri-check-number-validity detects integers with provenance --- tests/compile-fail/ptr_integer_array_transmute.rs | 6 ++++++ tests/compile-fail/ptr_integer_transmute.rs | 6 ++++++ 2 files changed, 12 insertions(+) create mode 100644 tests/compile-fail/ptr_integer_array_transmute.rs create mode 100644 tests/compile-fail/ptr_integer_transmute.rs diff --git a/tests/compile-fail/ptr_integer_array_transmute.rs b/tests/compile-fail/ptr_integer_array_transmute.rs new file mode 100644 index 000000000000..7a1ae2f3c9a1 --- /dev/null +++ b/tests/compile-fail/ptr_integer_array_transmute.rs @@ -0,0 +1,6 @@ +// compile-flags: -Zmiri-check-number-validity + +fn main() { + let r = &mut 42; + let _i: [usize; 1] = unsafe { std::mem::transmute(r) }; //~ ERROR encountered a pointer, but expected plain (non-pointer) bytes +} diff --git a/tests/compile-fail/ptr_integer_transmute.rs b/tests/compile-fail/ptr_integer_transmute.rs new file mode 100644 index 000000000000..e15a15763757 --- /dev/null +++ b/tests/compile-fail/ptr_integer_transmute.rs @@ -0,0 +1,6 @@ +// compile-flags: -Zmiri-check-number-validity + +fn main() { + let r = &mut 42; + let _i: usize = unsafe { std::mem::transmute(r) }; //~ ERROR expected initialized plain (non-pointer) bytes +} From 552b77e3b9841f697d954f2ab341711dbff8d029 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 26 Mar 2022 14:29:58 -0400 Subject: [PATCH 2957/5092] fix types in env shim to avoid ptr-int transmutes --- src/machine.rs | 23 ++++++++++++++--------- src/shims/backtrace.rs | 5 ++--- src/shims/env.rs | 7 ++++--- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 2cf7cd0fae0e..9c763149ffa2 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -10,13 +10,14 @@ use std::time::Instant; use rand::rngs::StdRng; use rand::SeedableRng; +use rustc_ast::ast::Mutability; use rustc_data_structures::fx::FxHashMap; use rustc_middle::{ mir, ty::{ self, layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout}, - Instance, TyCtxt, + Instance, TyCtxt, TypeAndMut, }, }; use rustc_span::def_id::{CrateNum, DefId}; @@ -269,19 +270,23 @@ pub struct PrimitiveLayouts<'tcx> { pub u32: TyAndLayout<'tcx>, pub usize: TyAndLayout<'tcx>, pub bool: TyAndLayout<'tcx>, + pub mut_raw_ptr: TyAndLayout<'tcx>, } impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> { fn new(layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result> { + let tcx = layout_cx.tcx; + let mut_raw_ptr = tcx.mk_ptr(TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Mut }); Ok(Self { - unit: layout_cx.layout_of(layout_cx.tcx.mk_unit())?, - i8: layout_cx.layout_of(layout_cx.tcx.types.i8)?, - i32: layout_cx.layout_of(layout_cx.tcx.types.i32)?, - isize: layout_cx.layout_of(layout_cx.tcx.types.isize)?, - u8: layout_cx.layout_of(layout_cx.tcx.types.u8)?, - u32: layout_cx.layout_of(layout_cx.tcx.types.u32)?, - usize: layout_cx.layout_of(layout_cx.tcx.types.usize)?, - bool: layout_cx.layout_of(layout_cx.tcx.types.bool)?, + unit: layout_cx.layout_of(tcx.mk_unit())?, + i8: layout_cx.layout_of(tcx.types.i8)?, + i32: layout_cx.layout_of(tcx.types.i32)?, + isize: layout_cx.layout_of(tcx.types.isize)?, + u8: layout_cx.layout_of(tcx.types.u8)?, + u32: layout_cx.layout_of(tcx.types.u32)?, + usize: layout_cx.layout_of(tcx.types.usize)?, + bool: layout_cx.layout_of(tcx.types.bool)?, + mut_raw_ptr: layout_cx.layout_of(mut_raw_ptr)?, }) } } diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 541cec8e8474..6a8a9553e936 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -1,7 +1,7 @@ use crate::*; use rustc_ast::ast::Mutability; use rustc_middle::ty::layout::LayoutOf as _; -use rustc_middle::ty::{self, Instance, TypeAndMut}; +use rustc_middle::ty::{self, Instance}; use rustc_span::{BytePos, Loc, Symbol}; use rustc_target::{abi::Size, spec::abi::Abi}; use std::convert::TryInto as _; @@ -71,8 +71,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let len: u64 = ptrs.len().try_into().unwrap(); - let ptr_ty = tcx.mk_ptr(TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Mut }); - + let ptr_ty = this.machine.layouts.mut_raw_ptr.ty; let array_layout = this.layout_of(tcx.mk_array(ptr_ty, len)).unwrap(); match flags { diff --git a/src/shims/env.rs b/src/shims/env.rs index 1916d7d70a41..c2050647abca 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -440,7 +440,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { // No `environ` allocated yet, let's do that. // This is memory backing an extern static, hence `ExternStatic`, not `Env`. - let layout = this.machine.layouts.usize; + let layout = this.machine.layouts.mut_raw_ptr; let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; this.machine.env_vars.environ = Some(place); } @@ -452,8 +452,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx vars.push(Pointer::null()); // Make an array with all these pointers inside Miri. let tcx = this.tcx; - let vars_layout = - this.layout_of(tcx.mk_array(tcx.types.usize, u64::try_from(vars.len()).unwrap()))?; + let vars_layout = this.layout_of( + tcx.mk_array(this.machine.layouts.mut_raw_ptr.ty, u64::try_from(vars.len()).unwrap()), + )?; let vars_place = this.allocate(vars_layout, MiriMemoryKind::Runtime.into())?; for (idx, var) in vars.into_iter().enumerate() { let place = this.mplace_field(&vars_place, idx)?; From 5d7c495de5d4ed870fe9c4fc2337c5ce0c96dec9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 26 Mar 2022 14:33:17 -0400 Subject: [PATCH 2958/5092] channels do ptr-int transmutes so move them to non-check-number-validity test --- tests/run-pass/concurrency/channels.rs | 57 +++++++++++++++++++++ tests/run-pass/concurrency/channels.stderr | 2 + tests/run-pass/concurrency/simple.rs | 1 + tests/run-pass/concurrency/simple.stderr | 4 +- tests/run-pass/concurrency/sync.rs | 50 ------------------ tests/run-pass/concurrency/thread_locals.rs | 1 + 6 files changed, 63 insertions(+), 52 deletions(-) create mode 100644 tests/run-pass/concurrency/channels.rs create mode 100644 tests/run-pass/concurrency/channels.stderr diff --git a/tests/run-pass/concurrency/channels.rs b/tests/run-pass/concurrency/channels.rs new file mode 100644 index 000000000000..58d073c85acc --- /dev/null +++ b/tests/run-pass/concurrency/channels.rs @@ -0,0 +1,57 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-isolation + +use std::sync::mpsc::{channel, sync_channel}; +use std::thread; + +// Check if channels are working. + +/// The test taken from the Rust documentation. +fn simple_send() { + let (tx, rx) = channel(); + thread::spawn(move || { + tx.send(10).unwrap(); + }); + assert_eq!(rx.recv().unwrap(), 10); +} + +/// The test taken from the Rust documentation. +fn multiple_send() { + let (tx, rx) = channel(); + for i in 0..10 { + let tx = tx.clone(); + thread::spawn(move || { + tx.send(i).unwrap(); + }); + } + + let mut sum = 0; + for _ in 0..10 { + let j = rx.recv().unwrap(); + assert!(0 <= j && j < 10); + sum += j; + } + assert_eq!(sum, 45); +} + +/// The test taken from the Rust documentation. +fn send_on_sync() { + let (sender, receiver) = sync_channel(1); + + // this returns immediately + sender.send(1).unwrap(); + + thread::spawn(move || { + // this will block until the previous message has been received + sender.send(2).unwrap(); + }); + + assert_eq!(receiver.recv().unwrap(), 1); + assert_eq!(receiver.recv().unwrap(), 2); +} + +fn main() { + simple_send(); + multiple_send(); + send_on_sync(); +} diff --git a/tests/run-pass/concurrency/channels.stderr b/tests/run-pass/concurrency/channels.stderr new file mode 100644 index 000000000000..03676519d4f1 --- /dev/null +++ b/tests/run-pass/concurrency/channels.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + diff --git a/tests/run-pass/concurrency/simple.rs b/tests/run-pass/concurrency/simple.rs index c22506821f54..c659cfbc3fdc 100644 --- a/tests/run-pass/concurrency/simple.rs +++ b/tests/run-pass/concurrency/simple.rs @@ -1,4 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-check-number-validity use std::thread; diff --git a/tests/run-pass/concurrency/simple.stderr b/tests/run-pass/concurrency/simple.stderr index f46b1442d749..35f5f10274c9 100644 --- a/tests/run-pass/concurrency/simple.stderr +++ b/tests/run-pass/concurrency/simple.stderr @@ -1,5 +1,5 @@ warning: thread support is experimental and incomplete: weak memory effects are not emulated. -thread '' panicked at 'Hello!', $DIR/simple.rs:54:9 +thread '' panicked at 'Hello!', $DIR/simple.rs:55:9 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -thread 'childthread' panicked at 'Hello, world!', $DIR/simple.rs:64:9 +thread 'childthread' panicked at 'Hello, world!', $DIR/simple.rs:65:9 diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index da6f6f25ec1c..d47aa2a8d234 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -1,7 +1,6 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-disable-isolation -Zmiri-check-number-validity -use std::sync::mpsc::{channel, sync_channel}; use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock}; use std::thread; use std::time::{Duration, Instant}; @@ -181,52 +180,6 @@ fn check_rwlock_read_no_deadlock() { handle.join().unwrap(); } -// Check if channels are working. - -/// The test taken from the Rust documentation. -fn simple_send() { - let (tx, rx) = channel(); - thread::spawn(move || { - tx.send(10).unwrap(); - }); - assert_eq!(rx.recv().unwrap(), 10); -} - -/// The test taken from the Rust documentation. -fn multiple_send() { - let (tx, rx) = channel(); - for i in 0..10 { - let tx = tx.clone(); - thread::spawn(move || { - tx.send(i).unwrap(); - }); - } - - let mut sum = 0; - for _ in 0..10 { - let j = rx.recv().unwrap(); - assert!(0 <= j && j < 10); - sum += j; - } - assert_eq!(sum, 45); -} - -/// The test taken from the Rust documentation. -fn send_on_sync() { - let (sender, receiver) = sync_channel(1); - - // this returns immediately - sender.send(1).unwrap(); - - thread::spawn(move || { - // this will block until the previous message has been received - sender.send(2).unwrap(); - }); - - assert_eq!(receiver.recv().unwrap(), 1); - assert_eq!(receiver.recv().unwrap(), 2); -} - // Check if Rust once statics are working. static mut VAL: usize = 0; @@ -353,9 +306,6 @@ fn main() { check_mutex(); check_rwlock_write(); check_rwlock_read_no_deadlock(); - simple_send(); - multiple_send(); - send_on_sync(); check_once(); check_rwlock_unlock_bug1(); check_rwlock_unlock_bug2(); diff --git a/tests/run-pass/concurrency/thread_locals.rs b/tests/run-pass/concurrency/thread_locals.rs index 384c2ac9155b..0fd4a9f1372d 100644 --- a/tests/run-pass/concurrency/thread_locals.rs +++ b/tests/run-pass/concurrency/thread_locals.rs @@ -1,4 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-check-number-validity //! The main purpose of this test is to check that if we take a pointer to //! thread's `t1` thread-local `A` and send it to another thread `t2`, From 0beb318b04d6733d4811390b2c96be06231b7bb8 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sun, 27 Mar 2022 18:41:40 +0900 Subject: [PATCH 2959/5092] add .vscode to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 389565791c00..b84a1cfe9f53 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ target tex/*/out *.dot *.rs.bk +.vscode From f3c35d51050a1d89da252734ff5fc8b9ba0b9937 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 27 Mar 2022 09:40:46 -0400 Subject: [PATCH 2960/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 7c9e50da5ceb..2497974aa7ea 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d2df372bca13bb60979c909660e69f2451630e81 +100f12d17026fccfc5d80527b5976dd66b228b13 From 811e6dd71dbbf5c4aee5b4ea1cc7c51f266e717a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 31 Mar 2022 11:18:56 -0400 Subject: [PATCH 2961/5092] test int_log functions --- rust-version | 2 +- tests/run-pass/integer-ops.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 2497974aa7ea..bed83f84eedf 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -100f12d17026fccfc5d80527b5976dd66b228b13 +df20355fa9fa5e9fb89be4e4bfee8a643bb7a23e diff --git a/tests/run-pass/integer-ops.rs b/tests/run-pass/integer-ops.rs index f5c1a7a5ff21..764b2dca82ca 100644 --- a/tests/run-pass/integer-ops.rs +++ b/tests/run-pass/integer-ops.rs @@ -1,4 +1,5 @@ // compile-flags: -Coverflow-checks=off +#![feature(int_log)] #![allow(arithmetic_overflow)] pub fn main() { @@ -171,4 +172,32 @@ pub fn main() { assert_eq!(10i8.overflowing_abs(), (10,false)); assert_eq!((-10i8).overflowing_abs(), (10,false)); assert_eq!((-128i8).overflowing_abs(), (-128,true)); + + // Logarithms + macro_rules! test_log { + ($type:ident, $max_log2:expr, $max_log10:expr) => { + assert_eq!($type::MIN.checked_log2(), None); + assert_eq!($type::MIN.checked_log10(), None); + assert_eq!($type::MAX.checked_log2(), Some($max_log2)); + assert_eq!($type::MAX.checked_log10(), Some($max_log10)); + } + } + + test_log!(i8, 6, 2); + test_log!(u8, 7, 2); + test_log!(i16, 14, 4); + test_log!(u16, 15, 4); + test_log!(i32, 30, 9); + test_log!(u32, 31, 9); + test_log!(i64, 62, 18); + test_log!(u64, 63, 19); + test_log!(i128, 126, 38); + test_log!(u128, 127, 38); + + for i in (1..=i16::MAX).step_by(i8::MAX as usize) { + assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as u32)); + } + for i in (1..=u16::MAX).step_by(i8::MAX as usize) { + assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as u32)); + } } From 9af03bf342708f591f5596916b08d5d5d784245e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Apr 2022 14:10:24 -0400 Subject: [PATCH 2962/5092] add -Zmiri-strict-provenance --- README.md | 4 ++++ src/bin/miri.rs | 4 ++++ src/eval.rs | 7 ++++++- src/intptrcast.rs | 20 +++++++++++++------ src/machine.rs | 2 +- tests/compile-fail/box-cell-alias.rs | 2 +- .../compile-fail/stacked_borrows/zst_slice.rs | 2 +- .../compile-fail/strict-provenance-offset.rs | 9 +++++++++ tests/run-pass/btreemap.rs | 2 +- tests/run-pass/concurrency/channels.rs | 1 - tests/run-pass/concurrency/sync.rs | 2 +- tests/run-pass/concurrency/thread_locals.rs | 2 +- .../concurrency/tls_lib_drop_single_thread.rs | 1 - tests/run-pass/rc.rs | 2 +- tests/run-pass/slices.rs | 2 +- tests/run-pass/strings.rs | 2 +- tests/run-pass/vec.rs | 2 +- tests/run-pass/vecdeque.rs | 2 +- 18 files changed, 48 insertions(+), 20 deletions(-) create mode 100644 tests/compile-fail/strict-provenance-offset.rs diff --git a/README.md b/README.md index 5d8b9034f3ad..2203a0643a90 100644 --- a/README.md +++ b/README.md @@ -294,6 +294,10 @@ environment variable: entropy. The default seed is 0. **NOTE**: This entropy is not good enough for cryptographic use! Do not generate secret keys in Miri or perform other kinds of cryptographic operations that rely on proper random numbers. +* `-Zmiri-strict-provenance` enables [strict + provenance](https://github.com/rust-lang/rust/issues/95228) checking in Miri. This means that + casting an integer to a pointer yields a result with 'invalid' provenance, i.e., with provenance + that cannot be used for any memory access. Also implies `-Zmiri-tag-raw-pointers`. * `-Zmiri-symbolic-alignment-check` makes the alignment check more strict. By default, alignment is checked by casting the pointer to an integer, and making sure that is a multiple of the alignment. This can lead to cases where a diff --git a/src/bin/miri.rs b/src/bin/miri.rs index a1f7c617f0af..5a9c96ef99b4 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -363,6 +363,10 @@ fn main() { "-Zmiri-tag-raw-pointers" => { miri_config.tag_raw = true; } + "-Zmiri-strict-provenance" => { + miri_config.strict_provenance = true; + miri_config.tag_raw = true; + } "-Zmiri-track-raw-pointers" => { eprintln!( "WARNING: -Zmiri-track-raw-pointers has been renamed to -Zmiri-tag-raw-pointers, the old name is deprecated." diff --git a/src/eval.rs b/src/eval.rs index 97856d92020b..788e30c9e78e 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -108,9 +108,13 @@ pub struct MiriConfig { /// If `Some`, enable the `measureme` profiler, writing results to a file /// with the specified prefix. pub measureme_out: Option, - /// Panic when unsupported functionality is encountered + /// Panic when unsupported functionality is encountered. pub panic_on_unsupported: bool, + /// Which style to use for printing backtraces. pub backtrace_style: BacktraceStyle, + /// Whether to enforce "strict provenance" rules. Enabling this means int2ptr casts return + /// pointers with an invalid provenance, i.e., not valid for any memory access. + pub strict_provenance: bool, } impl Default for MiriConfig { @@ -136,6 +140,7 @@ impl Default for MiriConfig { measureme_out: None, panic_on_unsupported: false, backtrace_style: BacktraceStyle::Short, + strict_provenance: false, } } } diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 6f4169e950a9..9333536c9c5f 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -15,23 +15,27 @@ pub type MemoryExtra = RefCell; pub struct GlobalState { /// This is used as a map between the address of each allocation and its `AllocId`. /// It is always sorted - pub int_to_ptr_map: Vec<(u64, AllocId)>, + int_to_ptr_map: Vec<(u64, AllocId)>, /// The base address for each allocation. We cannot put that into /// `AllocExtra` because function pointers also have a base address, and /// they do not have an `AllocExtra`. /// This is the inverse of `int_to_ptr_map`. - pub base_addr: FxHashMap, + base_addr: FxHashMap, /// This is used as a memory address when a new pointer is casted to an integer. It /// is always larger than any address that was previously made part of a block. - pub next_base_addr: u64, + next_base_addr: u64, + /// Whether to enforce "strict provenance" rules. Enabling this means int2ptr casts return + /// pointers with an invalid provenance, i.e., not valid for any memory access. + strict_provenance: bool, } -impl Default for GlobalState { - fn default() -> Self { +impl GlobalState { + pub fn new(config: &MiriConfig) -> Self { GlobalState { int_to_ptr_map: Vec::default(), base_addr: FxHashMap::default(), next_base_addr: STACK_ADDR, + strict_provenance: config.strict_provenance, } } } @@ -43,8 +47,12 @@ impl<'mir, 'tcx> GlobalState { ) -> Pointer> { trace!("Casting 0x{:x} to a pointer", addr); let global_state = memory.extra.intptrcast.borrow(); - let pos = global_state.int_to_ptr_map.binary_search_by_key(&addr, |(addr, _)| *addr); + if global_state.strict_provenance { + return Pointer::new(None, Size::from_bytes(addr)); + } + + let pos = global_state.int_to_ptr_map.binary_search_by_key(&addr, |(addr, _)| *addr); let alloc_id = match pos { Ok(pos) => Some(global_state.int_to_ptr_map[pos].1), Err(0) => None, diff --git a/src/machine.rs b/src/machine.rs index 9c763149ffa2..e9ed50724426 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -205,7 +205,7 @@ impl MemoryExtra { MemoryExtra { stacked_borrows, data_race, - intptrcast: Default::default(), + intptrcast: RefCell::new(intptrcast::GlobalState::new(config)), extern_statics: FxHashMap::default(), rng: RefCell::new(rng), tracked_alloc_id: config.tracked_alloc_id, diff --git a/tests/compile-fail/box-cell-alias.rs b/tests/compile-fail/box-cell-alias.rs index 5b9614f79fde..49cce2750784 100644 --- a/tests/compile-fail/box-cell-alias.rs +++ b/tests/compile-fail/box-cell-alias.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-tag-raw-pointers +// compile-flags: -Zmiri-strict-provenance // Taken from . diff --git a/tests/compile-fail/stacked_borrows/zst_slice.rs b/tests/compile-fail/stacked_borrows/zst_slice.rs index 065bf77d04ae..d45b3dcac087 100644 --- a/tests/compile-fail/stacked_borrows/zst_slice.rs +++ b/tests/compile-fail/stacked_borrows/zst_slice.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-tag-raw-pointers +// compile-flags: -Zmiri-strict-provenance // error-pattern: does not exist in the borrow stack fn main() { diff --git a/tests/compile-fail/strict-provenance-offset.rs b/tests/compile-fail/strict-provenance-offset.rs new file mode 100644 index 000000000000..6955d0243a9a --- /dev/null +++ b/tests/compile-fail/strict-provenance-offset.rs @@ -0,0 +1,9 @@ +// compile-flags: -Zmiri-strict-provenance +// error-pattern: not a valid pointer + +fn main() { + let x = 22; + let ptr = &x as *const _ as *const u8; + let roundtrip = ptr as usize as *const u8; + let _ = unsafe { roundtrip.offset(1) }; +} diff --git a/tests/run-pass/btreemap.rs b/tests/run-pass/btreemap.rs index 842ba0f4a874..4e11aa5917e3 100644 --- a/tests/run-pass/btreemap.rs +++ b/tests/run-pass/btreemap.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-tag-raw-pointers +// compile-flags: -Zmiri-strict-provenance -Zmiri-check-number-validity #![feature(btree_drain_filter)] use std::collections::{BTreeMap, BTreeSet}; use std::mem; diff --git a/tests/run-pass/concurrency/channels.rs b/tests/run-pass/concurrency/channels.rs index 58d073c85acc..7d28cd726d0e 100644 --- a/tests/run-pass/concurrency/channels.rs +++ b/tests/run-pass/concurrency/channels.rs @@ -1,5 +1,4 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation use std::sync::mpsc::{channel, sync_channel}; use std::thread; diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index d47aa2a8d234..95ede8e6c02d 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmiri-check-number-validity +// compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance -Zmiri-check-number-validity use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock}; use std::thread; diff --git a/tests/run-pass/concurrency/thread_locals.rs b/tests/run-pass/concurrency/thread_locals.rs index 0fd4a9f1372d..8b4f2a6f79d3 100644 --- a/tests/run-pass/concurrency/thread_locals.rs +++ b/tests/run-pass/concurrency/thread_locals.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-check-number-validity +// compile-flags: -Zmiri-strict-provenance -Zmiri-check-number-validity //! The main purpose of this test is to check that if we take a pointer to //! thread's `t1` thread-local `A` and send it to another thread `t2`, diff --git a/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs b/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs index c8be1273bd14..ef8b2c02ed92 100644 --- a/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs +++ b/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs @@ -1,4 +1,3 @@ -// compile-flags: -Zmiri-tag-raw-pointers //! Check that destructors of the thread locals are executed on all OSes. use std::cell::RefCell; diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index e00d9df32eec..fcc5156de89a 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-tag-raw-pointers +// compile-flags: -Zmiri-strict-provenance -Zmiri-check-number-validity #![feature(new_uninit)] #![feature(get_mut_unchecked)] diff --git a/tests/run-pass/slices.rs b/tests/run-pass/slices.rs index 9d98c44741b4..1b3bef5e07b5 100644 --- a/tests/run-pass/slices.rs +++ b/tests/run-pass/slices.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-tag-raw-pointers +// compile-flags: -Zmiri-strict-provenance -Zmiri-check-number-validity #![feature(new_uninit)] #![feature(slice_as_chunks)] #![feature(slice_partition_dedup)] diff --git a/tests/run-pass/strings.rs b/tests/run-pass/strings.rs index 6998ec6e59b9..5c36168a6ea3 100644 --- a/tests/run-pass/strings.rs +++ b/tests/run-pass/strings.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-tag-raw-pointers +// compile-flags: -Zmiri-strict-provenance -Zmiri-check-number-validity fn empty() -> &'static str { "" diff --git a/tests/run-pass/vec.rs b/tests/run-pass/vec.rs index 102396f4b91f..0d4c8016cdb6 100644 --- a/tests/run-pass/vec.rs +++ b/tests/run-pass/vec.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-tag-raw-pointers -Zmiri-check-number-validity +// compile-flags: -Zmiri-strict-provenance -Zmiri-check-number-validity // Gather all references from a mutable iterator and make sure Miri notices if // using them is dangerous. fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { diff --git a/tests/run-pass/vecdeque.rs b/tests/run-pass/vecdeque.rs index f45c21d20781..8e8b395cbd9a 100644 --- a/tests/run-pass/vecdeque.rs +++ b/tests/run-pass/vecdeque.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-tag-raw-pointers +// compile-flags: -Zmiri-strict-provenance -Zmiri-check-number-validity use std::collections::VecDeque; fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { From aa04dc1eeb53e90ee8473648610945a08232e56f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 27 Mar 2022 20:01:04 -0400 Subject: [PATCH 2963/5092] Rust values can be up to isize::MAX in size --- src/shims/intrinsics.rs | 2 ++ tests/compile-fail/too-big-unsized.rs | 7 +------ tests/run-pass/slices.rs | 9 +++++++++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index c344d0ff9c34..7e2068e4657b 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -83,6 +83,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val_byte = this.read_scalar(val_byte)?.to_u8()?; let ptr = this.read_pointer(ptr)?; let count = this.read_scalar(count)?.to_machine_usize(this)?; + // `checked_mul` enforces a too small bound (the correct one would probably be machine_isize_max), + // but no actual allocation can be big enough for the difference to be noticeable. let byte_count = ty_layout.size.checked_mul(count, this).ok_or_else(|| { err_ub_format!("overflow computing total size of `{}`", intrinsic_name) })?; diff --git a/tests/compile-fail/too-big-unsized.rs b/tests/compile-fail/too-big-unsized.rs index ad7bc6e938ac..824190a66eeb 100644 --- a/tests/compile-fail/too-big-unsized.rs +++ b/tests/compile-fail/too-big-unsized.rs @@ -6,13 +6,8 @@ struct MySlice { tail: [u8], } -#[cfg(target_pointer_width = "64")] -const TOO_BIG: usize = 1usize << 47; -#[cfg(target_pointer_width = "32")] -const TOO_BIG: usize = 1usize << 31; - fn main() { unsafe { let ptr = Box::into_raw(Box::new(0u8)); // The slice part is actually not "too big", but together with the `prefix` field it is. - let _x: &MySlice = mem::transmute((ptr, TOO_BIG-1)); //~ ERROR: invalid reference metadata: total size is bigger than largest supported object + let _x: &MySlice = mem::transmute((ptr, isize::MAX as usize)); //~ ERROR: invalid reference metadata: total size is bigger than largest supported object } } diff --git a/tests/run-pass/slices.rs b/tests/run-pass/slices.rs index 9d98c44741b4..bf3585f74e95 100644 --- a/tests/run-pass/slices.rs +++ b/tests/run-pass/slices.rs @@ -2,6 +2,7 @@ #![feature(new_uninit)] #![feature(slice_as_chunks)] #![feature(slice_partition_dedup)] +#![feature(layout_for_ptr)] use std::slice; @@ -250,9 +251,17 @@ fn test_for_invalidated_pointers() { buffer.copy_within(1.., 0); } +fn large_raw_slice() { + let size = isize::MAX as usize; + // Creating a raw slice of size isize::MAX and asking for its size is okay. + let s = std::ptr::slice_from_raw_parts(1usize as *const u8, size); + assert_eq!(size, unsafe { std::mem::size_of_val_raw(s) }); +} + fn main() { slice_of_zst(); test_iter_ref_consistency(); uninit_slice(); test_for_invalidated_pointers(); + large_raw_slice(); } From e13668092ce69bcedf00f02668a43ecf88e76b22 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Apr 2022 17:22:11 -0400 Subject: [PATCH 2964/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index bed83f84eedf..38c99cc0b539 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -df20355fa9fa5e9fb89be4e4bfee8a643bb7a23e +297a8018b525c28ef10ee6a91d61954839b508b9 From 1d79b60a1eed7fd1b176de1cbe2fa44ee158cc0d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Apr 2022 23:59:16 -0400 Subject: [PATCH 2965/5092] make strict-provenance imply check-number-validity --- README.md | 3 ++- src/bin/miri.rs | 1 + tests/run-pass/btreemap.rs | 2 +- tests/run-pass/concurrency/sync.rs | 2 +- tests/run-pass/concurrency/thread_locals.rs | 2 +- tests/run-pass/rc.rs | 2 +- tests/run-pass/slices.rs | 2 +- tests/run-pass/strings.rs | 2 +- tests/run-pass/vec.rs | 2 +- tests/run-pass/vecdeque.rs | 2 +- 10 files changed, 11 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 2203a0643a90..d394eb3cfbe9 100644 --- a/README.md +++ b/README.md @@ -297,7 +297,8 @@ environment variable: * `-Zmiri-strict-provenance` enables [strict provenance](https://github.com/rust-lang/rust/issues/95228) checking in Miri. This means that casting an integer to a pointer yields a result with 'invalid' provenance, i.e., with provenance - that cannot be used for any memory access. Also implies `-Zmiri-tag-raw-pointers`. + that cannot be used for any memory access. Also implies `-Zmiri-tag-raw-pointers` and + `-Zmiri-check-number-validity`. * `-Zmiri-symbolic-alignment-check` makes the alignment check more strict. By default, alignment is checked by casting the pointer to an integer, and making sure that is a multiple of the alignment. This can lead to cases where a diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 5a9c96ef99b4..be4776f459cd 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -366,6 +366,7 @@ fn main() { "-Zmiri-strict-provenance" => { miri_config.strict_provenance = true; miri_config.tag_raw = true; + miri_config.check_number_validity = true; } "-Zmiri-track-raw-pointers" => { eprintln!( diff --git a/tests/run-pass/btreemap.rs b/tests/run-pass/btreemap.rs index 4e11aa5917e3..413d7ef53d1c 100644 --- a/tests/run-pass/btreemap.rs +++ b/tests/run-pass/btreemap.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance -Zmiri-check-number-validity +// compile-flags: -Zmiri-strict-provenance #![feature(btree_drain_filter)] use std::collections::{BTreeMap, BTreeSet}; use std::mem; diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index 95ede8e6c02d..5e43fea96864 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance -Zmiri-check-number-validity +// compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock}; use std::thread; diff --git a/tests/run-pass/concurrency/thread_locals.rs b/tests/run-pass/concurrency/thread_locals.rs index 8b4f2a6f79d3..7938284bd634 100644 --- a/tests/run-pass/concurrency/thread_locals.rs +++ b/tests/run-pass/concurrency/thread_locals.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-strict-provenance -Zmiri-check-number-validity +// compile-flags: -Zmiri-strict-provenance //! The main purpose of this test is to check that if we take a pointer to //! thread's `t1` thread-local `A` and send it to another thread `t2`, diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index fcc5156de89a..6d51825fc0df 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance -Zmiri-check-number-validity +// compile-flags: -Zmiri-strict-provenance #![feature(new_uninit)] #![feature(get_mut_unchecked)] diff --git a/tests/run-pass/slices.rs b/tests/run-pass/slices.rs index f9d0b4eb8eae..b6537b4f1b4d 100644 --- a/tests/run-pass/slices.rs +++ b/tests/run-pass/slices.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance -Zmiri-check-number-validity +// compile-flags: -Zmiri-strict-provenance #![feature(new_uninit)] #![feature(slice_as_chunks)] #![feature(slice_partition_dedup)] diff --git a/tests/run-pass/strings.rs b/tests/run-pass/strings.rs index 5c36168a6ea3..77ecaed4fe9b 100644 --- a/tests/run-pass/strings.rs +++ b/tests/run-pass/strings.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance -Zmiri-check-number-validity +// compile-flags: -Zmiri-strict-provenance fn empty() -> &'static str { "" diff --git a/tests/run-pass/vec.rs b/tests/run-pass/vec.rs index 0d4c8016cdb6..788f05ce9774 100644 --- a/tests/run-pass/vec.rs +++ b/tests/run-pass/vec.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance -Zmiri-check-number-validity +// compile-flags: -Zmiri-strict-provenance // Gather all references from a mutable iterator and make sure Miri notices if // using them is dangerous. fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { diff --git a/tests/run-pass/vecdeque.rs b/tests/run-pass/vecdeque.rs index 8e8b395cbd9a..0cba0165cae1 100644 --- a/tests/run-pass/vecdeque.rs +++ b/tests/run-pass/vecdeque.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance -Zmiri-check-number-validity +// compile-flags: -Zmiri-strict-provenance use std::collections::VecDeque; fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { From 3dcba56349ebc41b20948e982dc61a9ed9305f59 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Apr 2022 00:05:27 -0400 Subject: [PATCH 2966/5092] add test for nasty example --- .../strict_provenance_transmute.rs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 tests/compile-fail/strict_provenance_transmute.rs diff --git a/tests/compile-fail/strict_provenance_transmute.rs b/tests/compile-fail/strict_provenance_transmute.rs new file mode 100644 index 000000000000..0fc64295f94c --- /dev/null +++ b/tests/compile-fail/strict_provenance_transmute.rs @@ -0,0 +1,27 @@ +// compile-flags: -Zmiri-strict-provenance +#![feature(strict_provenance)] + +use std::mem; + +// This is the example from +// . + +unsafe fn deref(left: *const u8, right: *const u8) { + let left_int: usize = mem::transmute(left); //~ERROR expected initialized plain (non-pointer) bytes + let right_int: usize = mem::transmute(right); + if left_int == right_int { + // The compiler is allowed to replace `left_int` by `right_int` here... + let left_ptr: *const u8 = mem::transmute(left_int); + // ...which however means here it could be dereferencing the wrong pointer. + let _val = *left_ptr; + } +} + +fn main() { + let ptr1 = &0u8 as *const u8; + let ptr2 = &1u8 as *const u8; + unsafe { + // Two pointers with the same address but different provenance. + deref(ptr1, ptr2.with_addr(ptr1.addr())); + } +} From 830cc58f8a10598f4caa337ca97be51741945499 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Apr 2022 20:00:03 -0400 Subject: [PATCH 2967/5092] rustup --- rust-version | 2 +- src/helpers.rs | 4 ++-- src/machine.rs | 2 +- src/shims/env.rs | 2 +- src/shims/foreign_items.rs | 4 ++-- src/shims/posix/foreign_items.rs | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/rust-version b/rust-version index 38c99cc0b539..8e4cdeddfccb 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -297a8018b525c28ef10ee6a91d61954839b508b9 +6af09d2505f38e4f1df291df56d497fb2ad935ed diff --git a/src/helpers.rs b/src/helpers.rs index 3ffb983aa69e..7a63bb03dfe7 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -510,7 +510,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let target = &this.tcx.sess.target; let target_os = &target.os; - let last_error = if target.families.contains(&"unix".to_owned()) { + let last_error = if target.families.iter().any(|f| f == "unix") { this.eval_libc(match err_kind { ConnectionRefused => "ECONNREFUSED", ConnectionReset => "ECONNRESET", @@ -534,7 +534,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) } })? - } else if target.families.contains(&"windows".to_owned()) { + } else if target.families.iter().any(|f| f == "windows") { // FIXME: we have to finish implementing the Windows equivalent of this. this.eval_windows( "c", diff --git a/src/machine.rs b/src/machine.rs index e9ed50724426..b4b07a61a8b4 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -227,7 +227,7 @@ impl MemoryExtra { pub fn init_extern_statics<'tcx, 'mir>( this: &mut MiriEvalContext<'mir, 'tcx>, ) -> InterpResult<'tcx> { - match this.tcx.sess.target.os.as_str() { + match this.tcx.sess.target.os.as_ref() { "linux" => { // "environ" Self::add_extern_static( diff --git a/src/shims/env.rs b/src/shims/env.rs index c2050647abca..822bef56ce68 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -41,7 +41,7 @@ impl<'tcx> EnvVars<'tcx> { mut excluded_env_vars: Vec, forwarded_env_vars: Vec, ) -> InterpResult<'tcx> { - let target_os = ecx.tcx.sess.target.os.as_str(); + let target_os = ecx.tcx.sess.target.os.as_ref(); // HACK: Exclude `TERM` var to avoid terminfo trying to open the termcap file. // This is (a) very slow and (b) does not work on Windows. excluded_env_vars.push("TERM".to_owned()); diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index ecffd310de56..d9e4d9382246 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -46,7 +46,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn min_align(&self, size: u64, kind: MiriMemoryKind) -> Align { let this = self.eval_context_ref(); // List taken from `libstd/sys_common/alloc.rs`. - let min_align = match this.tcx.sess.target.arch.as_str() { + let min_align = match this.tcx.sess.target.arch.as_ref() { "x86" | "arm" | "mips" | "powerpc" | "powerpc64" | "asmjs" | "wasm32" => 8, "x86_64" | "aarch64" | "mips64" | "s390x" | "sparc64" => 16, arch => bug!("Unsupported target architecture: {}", arch), @@ -695,7 +695,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Platform-specific shims - _ => match this.tcx.sess.target.os.as_str() { + _ => match this.tcx.sess.target.os.as_ref() { "linux" | "macos" => return shims::posix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), target => throw_unsup_format!("the target `{}` is not supported", target), diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 02fb7089c34d..36bf53059929 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -462,7 +462,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Platform-specific shims _ => { - match this.tcx.sess.target.os.as_str() { + match this.tcx.sess.target.os.as_ref() { "linux" => return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), "macos" => return shims::posix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), _ => unreachable!(), From 79a1001b3946a0816a4199ad033657da6411a4f4 Mon Sep 17 00:00:00 2001 From: Alex Touchet Date: Mon, 4 Apr 2022 15:52:09 -0700 Subject: [PATCH 2968/5092] Use SPDX license format --- Cargo.toml | 2 +- cargo-miri/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 356f6822fa18..540eeabebb7a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Miri Team"] description = "An experimental interpreter for Rust MIR (core driver)." -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" name = "miri" repository = "https://github.com/rust-lang/miri" version = "0.1.0" diff --git a/cargo-miri/Cargo.toml b/cargo-miri/Cargo.toml index 15c46569232a..7789a8a89594 100644 --- a/cargo-miri/Cargo.toml +++ b/cargo-miri/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Miri Team"] description = "An experimental interpreter for Rust MIR (cargo wrapper)." -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" name = "cargo-miri" repository = "https://github.com/rust-lang/miri" version = "0.1.0" From 6e1f3cd8ff080b85f6ba71b3f90300aca194a434 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Apr 2022 16:12:52 -0400 Subject: [PATCH 2969/5092] adjust for MemoryExtra being merged into Machine --- src/data_race.rs | 26 ++- src/diagnostics.rs | 4 +- src/eval.rs | 16 +- src/helpers.rs | 14 +- src/intptrcast.rs | 56 +++-- src/lib.rs | 4 +- src/machine.rs | 284 ++++++++++++------------- src/shims/backtrace.rs | 10 +- src/shims/env.rs | 28 +-- src/shims/foreign_items.rs | 34 ++- src/shims/intrinsics.rs | 16 +- src/shims/mod.rs | 4 +- src/shims/os_str.rs | 6 +- src/shims/panic.rs | 6 +- src/shims/posix/foreign_items.rs | 6 +- src/shims/posix/fs.rs | 30 +-- src/shims/posix/linux/sync.rs | 2 +- src/shims/posix/macos/foreign_items.rs | 2 +- src/shims/posix/thread.rs | 4 +- src/shims/tls.rs | 2 +- src/shims/windows/foreign_items.rs | 6 +- src/stacked_borrows.rs | 46 ++-- src/sync.rs | 16 +- src/thread.rs | 16 +- 24 files changed, 310 insertions(+), 328 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index 1e91c66b859e..4a79d9e99047 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -79,7 +79,6 @@ use crate::{ }; pub type AllocExtra = VClockAlloc; -pub type MemoryExtra = GlobalState; /// Valid atomic read-write operations, alias of atomic::Ordering (not non-exhaustive). #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -596,9 +595,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let eq = this.binary_op(mir::BinOp::Eq, &old, expect_old)?; // If the operation would succeed, but is "weak", fail some portion // of the time, based on `rate`. - let rate = this.memory.extra.cmpxchg_weak_failure_rate; + let rate = this.machine.cmpxchg_weak_failure_rate; let cmpxchg_success = eq.to_scalar()?.to_bool()? - && (!can_fail_spuriously || this.memory.extra.rng.get_mut().gen::() < rate); + && (!can_fail_spuriously || this.machine.rng.get_mut().gen::() < rate); let res = Immediate::ScalarPair( old.to_scalar_or_uninit(), Scalar::from_bool(cmpxchg_success).into(), @@ -690,7 +689,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// Update the data-race detector for an atomic fence on the current thread. fn validate_atomic_fence(&mut self, atomic: AtomicFenceOp) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - if let Some(data_race) = &mut this.memory.extra.data_race { + if let Some(data_race) = &mut this.machine.data_race { data_race.maybe_perform_sync_operation(move |index, mut clocks| { log::trace!("Atomic fence on {:?} with ordering {:?}", index, atomic); @@ -725,7 +724,7 @@ pub struct VClockAlloc { impl VClockAlloc { /// Create a new data-race detector for newly allocated memory. pub fn new_allocation( - global: &MemoryExtra, + global: &GlobalState, len: Size, kind: MemoryKind, ) -> VClockAlloc { @@ -796,7 +795,7 @@ impl VClockAlloc { #[cold] #[inline(never)] fn report_data_race<'tcx>( - global: &MemoryExtra, + global: &GlobalState, range: &MemoryCellClocks, action: &str, is_atomic: bool, @@ -950,13 +949,13 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { #[inline] fn allow_data_races_ref(&self, op: impl FnOnce(&MiriEvalContext<'mir, 'tcx>) -> R) -> R { let this = self.eval_context_ref(); - let old = if let Some(data_race) = &this.memory.extra.data_race { + let old = if let Some(data_race) = &this.machine.data_race { data_race.multi_threaded.replace(false) } else { false }; let result = op(this); - if let Some(data_race) = &this.memory.extra.data_race { + if let Some(data_race) = &this.machine.data_race { data_race.multi_threaded.set(old); } result @@ -971,13 +970,13 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { op: impl FnOnce(&mut MiriEvalContext<'mir, 'tcx>) -> R, ) -> R { let this = self.eval_context_mut(); - let old = if let Some(data_race) = &this.memory.extra.data_race { + let old = if let Some(data_race) = &this.machine.data_race { data_race.multi_threaded.replace(false) } else { false }; let result = op(this); - if let Some(data_race) = &this.memory.extra.data_race { + if let Some(data_race) = &this.machine.data_race { data_race.multi_threaded.set(old); } result @@ -997,14 +996,13 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> Result<(), DataRace>, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); - if let Some(data_race) = &this.memory.extra.data_race { + if let Some(data_race) = &this.machine.data_race { if data_race.multi_threaded.get() { let size = place.layout.size; - let (alloc_id, base_offset, ptr) = this.memory.ptr_get_alloc(place.ptr)?; + let (alloc_id, base_offset, ptr) = this.ptr_get_alloc_id(place.ptr)?; // Load and log the atomic operation. // Note that atomic loads are possible even from read-only allocations, so `get_alloc_extra_mut` is not an option. - let alloc_meta = - &this.memory.get_alloc_extra(alloc_id)?.data_race.as_ref().unwrap(); + let alloc_meta = &this.get_alloc_extra(alloc_id)?.data_race.as_ref().unwrap(); log::trace!( "Atomic op({}) with ordering {:?} on {:?} (size={})", description, diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 0815d73d9bcb..e1a2e3184ebf 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -196,7 +196,7 @@ pub fn report_error<'tcx, 'mir>( Unsupported(_) => vec![(None, format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"))], UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. }) - if ecx.memory.extra.check_alignment == AlignmentCheck::Symbolic + if ecx.machine.check_alignment == AlignmentCheck::Symbolic => vec![ (None, format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior")), @@ -251,7 +251,7 @@ pub fn report_error<'tcx, 'mir>( access.uninit_offset.bytes(), access.uninit_offset.bytes() + access.uninit_size.bytes(), ); - eprintln!("{:?}", ecx.memory.dump_alloc(*alloc_id)); + eprintln!("{:?}", ecx.dump_alloc(*alloc_id)); } _ => {} } diff --git a/src/eval.rs b/src/eval.rs index 788e30c9e78e..4c006867e177 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -153,7 +153,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( tcx: TyCtxt<'tcx>, entry_id: DefId, entry_type: EntryFnType, - config: MiriConfig, + config: &MiriConfig, ) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, MPlaceTy<'tcx, Tag>)> { let param_env = ty::ParamEnv::reveal_all(); let layout_cx = LayoutCx { tcx, param_env }; @@ -161,12 +161,10 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( tcx, rustc_span::source_map::DUMMY_SP, param_env, - Evaluator::new(&config, layout_cx), - MemoryExtra::new(&config), + Evaluator::new(config, layout_cx), ); - // Complete initialization. - EnvVars::init(&mut ecx, config.excluded_env_vars, config.forwarded_env_vars)?; - MemoryExtra::init_extern_statics(&mut ecx)?; + // Some parts of initialization require a full `InterpCx`. + Evaluator::late_init(&mut ecx, config)?; // Make sure we have MIR. We check MIR for some stable monomorphic function in libcore. let sentinel = ecx.resolve_path(&["core", "ascii", "escape_default"]); @@ -260,7 +258,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( .unwrap() .unwrap(); - let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(entry_instance)); + let main_ptr = ecx.create_fn_alloc_ptr(FnVal::Instance(entry_instance)); ecx.call_function( start_instance, @@ -296,7 +294,7 @@ pub fn eval_entry<'tcx>( // Copy setting before we move `config`. let ignore_leaks = config.ignore_leaks; - let (mut ecx, ret_place) = match create_ecx(tcx, entry_id, entry_type, config) { + let (mut ecx, ret_place) = match create_ecx(tcx, entry_id, entry_type, &config) { Ok(v) => v, Err(err) => { err.print_backtrace(); @@ -354,7 +352,7 @@ pub fn eval_entry<'tcx>( } // Check for memory leaks. info!("Additonal static roots: {:?}", ecx.machine.static_roots); - let leaks = ecx.memory.leak_report(&ecx.machine.static_roots); + let leaks = ecx.leak_report(&ecx.machine.static_roots); if leaks != 0 { tcx.sess.err("the evaluated program leaked memory"); tcx.sess.note_without_error("pass `-Zmiri-ignore-leaks` to disable this check"); diff --git a/src/helpers.rs b/src/helpers.rs index 7a63bb03dfe7..9e4527d592b3 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -199,11 +199,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx getrandom::getrandom(&mut data) .map_err(|err| err_unsup_format!("host getrandom failed: {}", err))?; } else { - let rng = this.memory.extra.rng.get_mut(); + let rng = this.machine.rng.get_mut(); rng.fill_bytes(&mut data); } - this.memory.write_bytes(ptr, data.iter().copied()) + this.write_bytes_ptr(ptr, data.iter().copied()) } /// Call a function: Push the stack frame and pass the arguments. @@ -645,7 +645,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx loop { // FIXME: We are re-getting the allocation each time around the loop. // Would be nice if we could somehow "extend" an existing AllocRange. - let alloc = this.memory.get(ptr.offset(len, this)?.into(), size1, Align::ONE)?.unwrap(); // not a ZST, so we will get a result + let alloc = + this.get_ptr_alloc(ptr.offset(len, this)?.into(), size1, Align::ONE)?.unwrap(); // not a ZST, so we will get a result let byte = alloc.read_scalar(alloc_range(Size::ZERO, size1))?.to_u8()?; if byte == 0 { break; @@ -655,7 +656,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Step 2: get the bytes. - this.memory.read_bytes(ptr.into(), len) + this.read_bytes_ptr(ptr.into(), len) } fn read_wide_str(&self, mut ptr: Pointer>) -> InterpResult<'tcx, Vec> { @@ -667,7 +668,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx loop { // FIXME: We are re-getting the allocation each time around the loop. // Would be nice if we could somehow "extend" an existing AllocRange. - let alloc = this.memory.get(ptr.into(), size2, align2)?.unwrap(); // not a ZST, so we will get a result + let alloc = this.get_ptr_alloc(ptr.into(), size2, align2)?.unwrap(); // not a ZST, so we will get a result let wchar = alloc.read_scalar(alloc_range(Size::ZERO, size2))?.to_u16()?; if wchar == 0 { break; @@ -750,8 +751,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Mark a machine allocation that was just created as immutable. fn mark_immutable(&mut self, mplace: &MemPlace) { let this = self.eval_context_mut(); - this.memory - .mark_immutable(mplace.ptr.into_pointer_or_addr().unwrap().provenance.alloc_id) + this.alloc_mark_immutable(mplace.ptr.into_pointer_or_addr().unwrap().provenance.alloc_id) .unwrap(); } } diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 9333536c9c5f..b1c96c7f1e7c 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -9,10 +9,10 @@ use rustc_target::abi::{HasDataLayout, Size}; use crate::*; -pub type MemoryExtra = RefCell; +pub type GlobalState = RefCell; #[derive(Clone, Debug)] -pub struct GlobalState { +pub struct GlobalStateInner { /// This is used as a map between the address of each allocation and its `AllocId`. /// It is always sorted int_to_ptr_map: Vec<(u64, AllocId)>, @@ -29,9 +29,9 @@ pub struct GlobalState { strict_provenance: bool, } -impl GlobalState { +impl GlobalStateInner { pub fn new(config: &MiriConfig) -> Self { - GlobalState { + GlobalStateInner { int_to_ptr_map: Vec::default(), base_addr: FxHashMap::default(), next_base_addr: STACK_ADDR, @@ -40,13 +40,10 @@ impl GlobalState { } } -impl<'mir, 'tcx> GlobalState { - pub fn ptr_from_addr( - addr: u64, - memory: &Memory<'mir, 'tcx, Evaluator<'mir, 'tcx>>, - ) -> Pointer> { +impl<'mir, 'tcx> GlobalStateInner { + pub fn ptr_from_addr(addr: u64, ecx: &MiriEvalContext<'mir, 'tcx>) -> Pointer> { trace!("Casting 0x{:x} to a pointer", addr); - let global_state = memory.extra.intptrcast.borrow(); + let global_state = ecx.machine.intptrcast.borrow(); if global_state.strict_provenance { return Pointer::new(None, Size::from_bytes(addr)); @@ -64,7 +61,11 @@ impl<'mir, 'tcx> GlobalState { let offset = addr - glb; // If the offset exceeds the size of the allocation, don't use this `alloc_id`. if offset - <= memory.get_size_and_align(alloc_id, AllocCheck::MaybeDead).unwrap().0.bytes() + <= ecx + .get_alloc_size_and_align(alloc_id, AllocCheck::MaybeDead) + .unwrap() + .0 + .bytes() { Some(alloc_id) } else { @@ -79,11 +80,8 @@ impl<'mir, 'tcx> GlobalState { ) } - fn alloc_base_addr( - memory: &Memory<'mir, 'tcx, Evaluator<'mir, 'tcx>>, - alloc_id: AllocId, - ) -> u64 { - let mut global_state = memory.extra.intptrcast.borrow_mut(); + fn alloc_base_addr(ecx: &MiriEvalContext<'mir, 'tcx>, alloc_id: AllocId) -> u64 { + let mut global_state = ecx.machine.intptrcast.borrow_mut(); let global_state = &mut *global_state; match global_state.base_addr.entry(alloc_id) { @@ -92,12 +90,12 @@ impl<'mir, 'tcx> GlobalState { // There is nothing wrong with a raw pointer being cast to an integer only after // it became dangling. Hence `MaybeDead`. let (size, align) = - memory.get_size_and_align(alloc_id, AllocCheck::MaybeDead).unwrap(); + ecx.get_alloc_size_and_align(alloc_id, AllocCheck::MaybeDead).unwrap(); // This allocation does not have a base address yet, pick one. // Leave some space to the previous allocation, to give it some chance to be less aligned. let slack = { - let mut rng = memory.extra.rng.borrow_mut(); + let mut rng = ecx.machine.rng.borrow_mut(); // This means that `(global_state.next_base_addr + slack) % 16` is uniformly distributed. rng.gen_range(0..16) }; @@ -129,27 +127,21 @@ impl<'mir, 'tcx> GlobalState { } /// Convert a relative (tcx) pointer to an absolute address. - pub fn rel_ptr_to_addr( - memory: &Memory<'mir, 'tcx, Evaluator<'mir, 'tcx>>, - ptr: Pointer, - ) -> u64 { + pub fn rel_ptr_to_addr(ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer) -> u64 { let (alloc_id, offset) = ptr.into_parts(); // offset is relative - let base_addr = GlobalState::alloc_base_addr(memory, alloc_id); + let base_addr = GlobalStateInner::alloc_base_addr(ecx, alloc_id); // Add offset with the right kind of pointer-overflowing arithmetic. - let dl = memory.data_layout(); + let dl = ecx.data_layout(); dl.overflowing_offset(base_addr, offset.bytes()).0 } - pub fn abs_ptr_to_rel( - memory: &Memory<'mir, 'tcx, Evaluator<'mir, 'tcx>>, - ptr: Pointer, - ) -> Size { + pub fn abs_ptr_to_rel(ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer) -> Size { let (tag, addr) = ptr.into_parts(); // addr is absolute - let base_addr = GlobalState::alloc_base_addr(memory, tag.alloc_id); + let base_addr = GlobalStateInner::alloc_base_addr(ecx, tag.alloc_id); // Wrapping "addr - base_addr" - let dl = memory.data_layout(); + let dl = ecx.data_layout(); let neg_base_addr = (base_addr as i64).wrapping_neg(); Size::from_bytes(dl.overflowing_signed_offset(addr.bytes(), neg_base_addr).0) } @@ -170,7 +162,7 @@ mod tests { #[test] fn test_align_addr() { - assert_eq!(GlobalState::align_addr(37, 4), 40); - assert_eq!(GlobalState::align_addr(44, 4), 44); + assert_eq!(GlobalStateInner::align_addr(37, 4), 40); + assert_eq!(GlobalStateInner::align_addr(44, 4), 44); } } diff --git a/src/lib.rs b/src/lib.rs index 6c9b8ee0b8f9..f14120ae4ccc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -66,8 +66,8 @@ pub use crate::eval::{ }; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; pub use crate::machine::{ - AllocExtra, Evaluator, FrameData, MemoryExtra, MiriEvalContext, MiriEvalContextExt, - MiriMemoryKind, Tag, NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, + AllocExtra, Evaluator, FrameData, MiriEvalContext, MiriEvalContextExt, MiriMemoryKind, Tag, + NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, }; pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; diff --git a/src/machine.rs b/src/machine.rs index b4b07a61a8b4..9108f4f16663 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -163,103 +163,6 @@ pub struct AllocExtra { pub data_race: Option, } -/// Extra global memory data -#[derive(Debug)] -pub struct MemoryExtra { - pub stacked_borrows: Option, - pub data_race: Option, - pub intptrcast: intptrcast::MemoryExtra, - - /// Mapping extern static names to their base pointer. - extern_statics: FxHashMap>, - - /// The random number generator used for resolving non-determinism. - /// Needs to be queried by ptr_to_int, hence needs interior mutability. - pub(crate) rng: RefCell, - - /// An allocation ID to report when it is being allocated - /// (helps for debugging memory leaks and use after free bugs). - tracked_alloc_id: Option, - - /// Controls whether alignment of memory accesses is being checked. - pub(crate) check_alignment: AlignmentCheck, - - /// Failure rate of compare_exchange_weak, between 0.0 and 1.0 - pub(crate) cmpxchg_weak_failure_rate: f64, -} - -impl MemoryExtra { - pub fn new(config: &MiriConfig) -> Self { - let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0)); - let stacked_borrows = if config.stacked_borrows { - Some(RefCell::new(stacked_borrows::GlobalState::new( - config.tracked_pointer_tag, - config.tracked_call_id, - config.tag_raw, - ))) - } else { - None - }; - let data_race = - if config.data_race_detector { Some(data_race::GlobalState::new()) } else { None }; - MemoryExtra { - stacked_borrows, - data_race, - intptrcast: RefCell::new(intptrcast::GlobalState::new(config)), - extern_statics: FxHashMap::default(), - rng: RefCell::new(rng), - tracked_alloc_id: config.tracked_alloc_id, - check_alignment: config.check_alignment, - cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate, - } - } - - fn add_extern_static<'tcx, 'mir>( - this: &mut MiriEvalContext<'mir, 'tcx>, - name: &str, - ptr: Pointer>, - ) { - let ptr = ptr.into_pointer_or_addr().unwrap(); - this.memory.extra.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap(); - } - - /// Sets up the "extern statics" for this machine. - pub fn init_extern_statics<'tcx, 'mir>( - this: &mut MiriEvalContext<'mir, 'tcx>, - ) -> InterpResult<'tcx> { - match this.tcx.sess.target.os.as_ref() { - "linux" => { - // "environ" - Self::add_extern_static( - this, - "environ", - this.machine.env_vars.environ.unwrap().ptr, - ); - // A couple zero-initialized pointer-sized extern statics. - // Most of them are for weak symbols, which we all set to null (indicating that the - // symbol is not supported, and triggering fallback code which ends up calling a - // syscall that we do support). - for name in &["__cxa_thread_atexit_impl", "getrandom", "statx"] { - let layout = this.machine.layouts.usize; - let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; - this.write_scalar(Scalar::from_machine_usize(0, this), &place.into())?; - Self::add_extern_static(this, name, place.ptr); - } - } - "windows" => { - // "_tls_used" - // This is some obscure hack that is part of the Windows TLS story. It's a `u8`. - let layout = this.machine.layouts.u8; - let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; - this.write_scalar(Scalar::from_u8(0), &place.into())?; - Self::add_extern_static(this, "_tls_used", place.ptr); - } - _ => {} // No "extern statics" supported on this target - } - Ok(()) - } -} - /// Precomputed layouts of primitive types pub struct PrimitiveLayouts<'tcx> { pub unit: TyAndLayout<'tcx>, @@ -293,6 +196,10 @@ impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> { /// The machine itself. pub struct Evaluator<'mir, 'tcx> { + pub stacked_borrows: Option, + pub data_race: Option, + pub intptrcast: intptrcast::GlobalState, + /// Environment variables set by `setenv`. /// Miri does not expose env vars from the host to the emulated program. pub(crate) env_vars: EnvVars<'tcx>, @@ -357,6 +264,23 @@ pub struct Evaluator<'mir, 'tcx> { /// Crates which are considered local for the purposes of error reporting. pub(crate) local_crates: Vec, + + /// Mapping extern static names to their base pointer. + extern_statics: FxHashMap>, + + /// The random number generator used for resolving non-determinism. + /// Needs to be queried by ptr_to_int, hence needs interior mutability. + pub(crate) rng: RefCell, + + /// An allocation ID to report when it is being allocated + /// (helps for debugging memory leaks and use after free bugs). + tracked_alloc_id: Option, + + /// Controls whether alignment of memory accesses is being checked. + pub(crate) check_alignment: AlignmentCheck, + + /// Failure rate of compare_exchange_weak, between 0.0 and 1.0 + pub(crate) cmpxchg_weak_failure_rate: f64, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { @@ -367,9 +291,23 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { let profiler = config.measureme_out.as_ref().map(|out| { measureme::Profiler::new(out).expect("Couldn't create `measureme` profiler") }); + let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0)); + let stacked_borrows = if config.stacked_borrows { + Some(RefCell::new(stacked_borrows::GlobalStateInner::new( + config.tracked_pointer_tag, + config.tracked_call_id, + config.tag_raw, + ))) + } else { + None + }; + let data_race = + if config.data_race_detector { Some(data_race::GlobalState::new()) } else { None }; Evaluator { - // `env_vars` could be initialized properly here if `Memory` were available before - // calling this method. + stacked_borrows, + data_race, + intptrcast: RefCell::new(intptrcast::GlobalStateInner::new(config)), + // `env_vars` depends on a full interpreter so we cannot properly initialize it yet. env_vars: EnvVars::default(), argc: None, argv: None, @@ -391,9 +329,66 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { panic_on_unsupported: config.panic_on_unsupported, backtrace_style: config.backtrace_style, local_crates, + extern_statics: FxHashMap::default(), + rng: RefCell::new(rng), + tracked_alloc_id: config.tracked_alloc_id, + check_alignment: config.check_alignment, + cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate, } } + pub(crate) fn late_init( + this: &mut MiriEvalContext<'mir, 'tcx>, + config: &MiriConfig, + ) -> InterpResult<'tcx> { + EnvVars::init(this, config)?; + Evaluator::init_extern_statics(this)?; + Ok(()) + } + + fn add_extern_static( + this: &mut MiriEvalContext<'mir, 'tcx>, + name: &str, + ptr: Pointer>, + ) { + let ptr = ptr.into_pointer_or_addr().unwrap(); + this.machine.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap(); + } + + /// Sets up the "extern statics" for this machine. + fn init_extern_statics(this: &mut MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx> { + match this.tcx.sess.target.os.as_ref() { + "linux" => { + // "environ" + Self::add_extern_static( + this, + "environ", + this.machine.env_vars.environ.unwrap().ptr, + ); + // A couple zero-initialized pointer-sized extern statics. + // Most of them are for weak symbols, which we all set to null (indicating that the + // symbol is not supported, and triggering fallback code which ends up calling a + // syscall that we do support). + for name in &["__cxa_thread_atexit_impl", "getrandom", "statx"] { + let layout = this.machine.layouts.usize; + let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; + this.write_scalar(Scalar::from_machine_usize(0, this), &place.into())?; + Self::add_extern_static(this, name, place.ptr); + } + } + "windows" => { + // "_tls_used" + // This is some obscure hack that is part of the Windows TLS story. It's a `u8`. + let layout = this.machine.layouts.u8; + let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; + this.write_scalar(Scalar::from_u8(0), &place.into())?; + Self::add_extern_static(this, "_tls_used", place.ptr); + } + _ => {} // No "extern statics" supported on this target + } + Ok(()) + } + pub(crate) fn communicate(&self) -> bool { self.isolated_op == IsolatedOp::Allow } @@ -429,7 +424,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { type MemoryKind = MiriMemoryKind; type FrameExtra = FrameData<'tcx>; - type MemoryExtra = MemoryExtra; type AllocExtra = AllocExtra; type PointerTag = Tag; type ExtraFnVal = Dlsym; @@ -442,33 +436,33 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { const PANIC_ON_ALLOC_FAIL: bool = false; #[inline(always)] - fn enforce_alignment(memory_extra: &MemoryExtra) -> bool { - memory_extra.check_alignment != AlignmentCheck::None + fn enforce_alignment(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { + ecx.machine.check_alignment != AlignmentCheck::None } #[inline(always)] - fn force_int_for_alignment_check(memory_extra: &Self::MemoryExtra) -> bool { - memory_extra.check_alignment == AlignmentCheck::Int + fn force_int_for_alignment_check(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { + ecx.machine.check_alignment == AlignmentCheck::Int } #[inline(always)] - fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + fn enforce_validity(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { ecx.machine.validate } #[inline(always)] - fn enforce_number_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + fn enforce_number_validity(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { ecx.machine.enforce_number_validity } #[inline(always)] - fn enforce_abi(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + fn enforce_abi(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { ecx.machine.enforce_abi } #[inline(always)] fn find_mir_or_eval_fn( - ecx: &mut InterpCx<'mir, 'tcx, Self>, + ecx: &mut MiriEvalContext<'mir, 'tcx>, instance: ty::Instance<'tcx>, abi: Abi, args: &[OpTy<'tcx, Tag>], @@ -480,7 +474,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn call_extra_fn( - ecx: &mut InterpCx<'mir, 'tcx, Self>, + ecx: &mut MiriEvalContext<'mir, 'tcx>, fn_val: Dlsym, abi: Abi, args: &[OpTy<'tcx, Tag>], @@ -492,7 +486,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn call_intrinsic( - ecx: &mut rustc_const_eval::interpret::InterpCx<'mir, 'tcx, Self>, + ecx: &mut MiriEvalContext<'mir, 'tcx>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, @@ -503,7 +497,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn assert_panic( - ecx: &mut InterpCx<'mir, 'tcx, Self>, + ecx: &mut MiriEvalContext<'mir, 'tcx>, msg: &mir::AssertMessage<'tcx>, unwind: Option, ) -> InterpResult<'tcx> { @@ -511,13 +505,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } #[inline(always)] - fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: String) -> InterpResult<'tcx, !> { + fn abort(_ecx: &mut MiriEvalContext<'mir, 'tcx>, msg: String) -> InterpResult<'tcx, !> { throw_machine_stop!(TerminationInfo::Abort(msg)) } #[inline(always)] fn binary_ptr_op( - ecx: &rustc_const_eval::interpret::InterpCx<'mir, 'tcx, Self>, + ecx: &MiriEvalContext<'mir, 'tcx>, bin_op: mir::BinOp, left: &ImmTy<'tcx, Tag>, right: &ImmTy<'tcx, Tag>, @@ -526,22 +520,22 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } fn thread_local_static_base_pointer( - ecx: &mut InterpCx<'mir, 'tcx, Self>, + ecx: &mut MiriEvalContext<'mir, 'tcx>, def_id: DefId, ) -> InterpResult<'tcx, Pointer> { ecx.get_or_create_thread_local_alloc(def_id) } fn extern_static_base_pointer( - memory: &Memory<'mir, 'tcx, Self>, + ecx: &MiriEvalContext<'mir, 'tcx>, def_id: DefId, ) -> InterpResult<'tcx, Pointer> { - let attrs = memory.tcx.get_attrs(def_id); - let link_name = match memory.tcx.sess.first_attr_value_str_by_name(&attrs, sym::link_name) { + let attrs = ecx.tcx.get_attrs(def_id); + let link_name = match ecx.tcx.sess.first_attr_value_str_by_name(&attrs, sym::link_name) { Some(name) => name, - None => memory.tcx.item_name(def_id), + None => ecx.tcx.item_name(def_id), }; - if let Some(&ptr) = memory.extra.extern_statics.get(&link_name) { + if let Some(&ptr) = ecx.machine.extern_statics.get(&link_name) { Ok(ptr) } else { throw_unsup_format!("`extern` static {:?} is not supported by Miri", def_id) @@ -549,41 +543,41 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } fn init_allocation_extra<'b>( - mem: &Memory<'mir, 'tcx, Self>, + ecx: &MiriEvalContext<'mir, 'tcx>, id: AllocId, alloc: Cow<'b, Allocation>, kind: Option>, ) -> Cow<'b, Allocation> { - if Some(id) == mem.extra.tracked_alloc_id { + if Some(id) == ecx.machine.tracked_alloc_id { register_diagnostic(NonHaltingDiagnostic::CreatedAlloc(id)); } let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); - let stacks = if let Some(stacked_borrows) = &mem.extra.stacked_borrows { + let stacks = if let Some(stacked_borrows) = &ecx.machine.stacked_borrows { Some(Stacks::new_allocation(id, alloc.size(), stacked_borrows, kind)) } else { None }; - let race_alloc = if let Some(data_race) = &mem.extra.data_race { + let race_alloc = if let Some(data_race) = &ecx.machine.data_race { Some(data_race::AllocExtra::new_allocation(&data_race, alloc.size(), kind)) } else { None }; let alloc: Allocation = alloc.convert_tag_add_extra( - &mem.tcx, + &ecx.tcx, AllocExtra { stacked_borrows: stacks, data_race: race_alloc }, - |ptr| Evaluator::tag_alloc_base_pointer(mem, ptr), + |ptr| Evaluator::tag_alloc_base_pointer(ecx, ptr), ); Cow::Owned(alloc) } fn tag_alloc_base_pointer( - mem: &Memory<'mir, 'tcx, Self>, + ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer, ) -> Pointer { - let absolute_addr = intptrcast::GlobalState::rel_ptr_to_addr(&mem, ptr); - let sb_tag = if let Some(stacked_borrows) = &mem.extra.stacked_borrows { + let absolute_addr = intptrcast::GlobalStateInner::rel_ptr_to_addr(ecx, ptr); + let sb_tag = if let Some(stacked_borrows) = &ecx.machine.stacked_borrows { stacked_borrows.borrow_mut().base_tag(ptr.provenance) } else { SbTag::Untagged @@ -593,38 +587,38 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn ptr_from_addr( - mem: &Memory<'mir, 'tcx, Self>, + ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, ) -> Pointer> { - intptrcast::GlobalState::ptr_from_addr(addr, mem) + intptrcast::GlobalStateInner::ptr_from_addr(addr, ecx) } /// Convert a pointer with provenance into an allocation-offset pair, /// or a `None` with an absolute address if that conversion is not possible. fn ptr_get_alloc( - mem: &Memory<'mir, 'tcx, Self>, + ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer, ) -> (AllocId, Size) { - let rel = intptrcast::GlobalState::abs_ptr_to_rel(mem, ptr); + let rel = intptrcast::GlobalStateInner::abs_ptr_to_rel(ecx, ptr); (ptr.provenance.alloc_id, rel) } #[inline(always)] fn memory_read( - memory_extra: &Self::MemoryExtra, + machine: &Self, alloc_extra: &AllocExtra, tag: Tag, range: AllocRange, ) -> InterpResult<'tcx> { if let Some(data_race) = &alloc_extra.data_race { - data_race.read(tag.alloc_id, range, memory_extra.data_race.as_ref().unwrap())?; + data_race.read(tag.alloc_id, range, machine.data_race.as_ref().unwrap())?; } if let Some(stacked_borrows) = &alloc_extra.stacked_borrows { stacked_borrows.memory_read( tag.alloc_id, tag.sb, range, - memory_extra.stacked_borrows.as_ref().unwrap(), + machine.stacked_borrows.as_ref().unwrap(), ) } else { Ok(()) @@ -633,20 +627,20 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn memory_written( - memory_extra: &mut Self::MemoryExtra, + machine: &mut Self, alloc_extra: &mut AllocExtra, tag: Tag, range: AllocRange, ) -> InterpResult<'tcx> { if let Some(data_race) = &mut alloc_extra.data_race { - data_race.write(tag.alloc_id, range, memory_extra.data_race.as_mut().unwrap())?; + data_race.write(tag.alloc_id, range, machine.data_race.as_mut().unwrap())?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { stacked_borrows.memory_written( tag.alloc_id, tag.sb, range, - memory_extra.stacked_borrows.as_mut().unwrap(), + machine.stacked_borrows.as_mut().unwrap(), ) } else { Ok(()) @@ -655,23 +649,23 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn memory_deallocated( - memory_extra: &mut Self::MemoryExtra, + machine: &mut Self, alloc_extra: &mut AllocExtra, tag: Tag, range: AllocRange, ) -> InterpResult<'tcx> { - if Some(tag.alloc_id) == memory_extra.tracked_alloc_id { + if Some(tag.alloc_id) == machine.tracked_alloc_id { register_diagnostic(NonHaltingDiagnostic::FreedAlloc(tag.alloc_id)); } if let Some(data_race) = &mut alloc_extra.data_race { - data_race.deallocate(tag.alloc_id, range, memory_extra.data_race.as_mut().unwrap())?; + data_race.deallocate(tag.alloc_id, range, machine.data_race.as_mut().unwrap())?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { stacked_borrows.memory_deallocated( tag.alloc_id, tag.sb, range, - memory_extra.stacked_borrows.as_mut().unwrap(), + machine.stacked_borrows.as_mut().unwrap(), ) } else { Ok(()) @@ -684,7 +678,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { kind: mir::RetagKind, place: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { - if ecx.memory.extra.stacked_borrows.is_some() { ecx.retag(kind, place) } else { Ok(()) } + if ecx.machine.stacked_borrows.is_some() { ecx.retag(kind, place) } else { Ok(()) } } #[inline(always)] @@ -707,7 +701,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { None }; - let stacked_borrows = ecx.memory.extra.stacked_borrows.as_ref(); + let stacked_borrows = ecx.machine.stacked_borrows.as_ref(); let call_id = stacked_borrows.map_or(NonZeroU64::new(1).unwrap(), |stacked_borrows| { stacked_borrows.borrow_mut().new_call() }); @@ -730,7 +724,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn after_stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { - if ecx.memory.extra.stacked_borrows.is_some() { ecx.retag_return_place() } else { Ok(()) } + if ecx.machine.stacked_borrows.is_some() { ecx.retag_return_place() } else { Ok(()) } } #[inline(always)] diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 6a8a9553e936..32fbbffc63f8 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -64,7 +64,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // to reconstruct the needed frame information in `handle_miri_resolve_frame`. // Note that we never actually read or write anything from/to this pointer - // all of the data is represented by the pointer value itself. - let fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(instance)); + let fn_ptr = this.create_fn_alloc_ptr(FnVal::Instance(instance)); fn_ptr.wrapping_offset(Size::from_bytes(pos.0), this) }) .collect(); @@ -125,7 +125,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.read_pointer(ptr)?; // Take apart the pointer, we need its pieces. - let (alloc_id, offset, ptr) = this.memory.ptr_get_alloc(ptr)?; + let (alloc_id, offset, ptr) = this.ptr_get_alloc_id(ptr)?; let fn_instance = if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(alloc_id) { @@ -159,7 +159,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Reconstruct the original function pointer, // which we pass to user code. - let fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(fn_instance)); + let fn_ptr = this.create_fn_alloc_ptr(FnVal::Instance(fn_instance)); let num_fields = dest.layout.fields.count(); @@ -244,8 +244,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (_, _, name, filename) = this.resolve_frame_pointer(ptr)?; - this.memory.write_bytes(this.read_pointer(name_ptr)?, name.bytes())?; - this.memory.write_bytes(this.read_pointer(filename_ptr)?, filename.bytes())?; + this.write_bytes_ptr(this.read_pointer(name_ptr)?, name.bytes())?; + this.write_bytes_ptr(this.read_pointer(filename_ptr)?, filename.bytes())?; Ok(()) } diff --git a/src/shims/env.rs b/src/shims/env.rs index 822bef56ce68..7be26de45916 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -2,6 +2,7 @@ use std::convert::TryFrom; use std::env; use std::ffi::{OsStr, OsString}; use std::io::ErrorKind; +use std::mem; use rustc_const_eval::interpret::Pointer; use rustc_data_structures::fx::FxHashMap; @@ -38,20 +39,20 @@ pub struct EnvVars<'tcx> { impl<'tcx> EnvVars<'tcx> { pub(crate) fn init<'mir>( ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, - mut excluded_env_vars: Vec, - forwarded_env_vars: Vec, + config: &MiriConfig, ) -> InterpResult<'tcx> { let target_os = ecx.tcx.sess.target.os.as_ref(); // HACK: Exclude `TERM` var to avoid terminfo trying to open the termcap file. // This is (a) very slow and (b) does not work on Windows. + let mut excluded_env_vars = config.excluded_env_vars.clone(); excluded_env_vars.push("TERM".to_owned()); // Skip the loop entirely if we don't want to forward anything. - if ecx.machine.communicate() || !forwarded_env_vars.is_empty() { + if ecx.machine.communicate() || !config.forwarded_env_vars.is_empty() { for (name, value) in env::vars_os() { let forward = match ecx.machine.communicate() { true => !excluded_env_vars.iter().any(|v| v.as_str() == &name), - false => forwarded_env_vars.iter().any(|v| v.as_str() == &name), + false => config.forwarded_env_vars.iter().any(|v| v.as_str() == &name), }; if forward { let var_ptr = match target_os { @@ -75,13 +76,14 @@ impl<'tcx> EnvVars<'tcx> { ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, ) -> InterpResult<'tcx> { // Deallocate individual env vars. - for (_name, ptr) in ecx.machine.env_vars.map.drain() { - ecx.memory.deallocate(ptr, None, MiriMemoryKind::Runtime.into())?; + let env_vars = mem::take(&mut ecx.machine.env_vars.map); + for (_name, ptr) in env_vars { + ecx.deallocate_ptr(ptr, None, MiriMemoryKind::Runtime.into())?; } // Deallocate environ var list. let environ = ecx.machine.env_vars.environ.unwrap(); let old_vars_ptr = ecx.read_pointer(&environ.into())?; - ecx.memory.deallocate(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?; + ecx.deallocate_ptr(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?; Ok(()) } } @@ -199,7 +201,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.assert_target_os("windows", "FreeEnvironmentStringsW"); let env_block_ptr = this.read_pointer(env_block_op)?; - let result = this.memory.deallocate(env_block_ptr, None, MiriMemoryKind::Runtime.into()); + let result = this.deallocate_ptr(env_block_ptr, None, MiriMemoryKind::Runtime.into()); // If the function succeeds, the return value is nonzero. Ok(result.is_ok() as i32) } @@ -230,7 +232,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some((name, value)) = new { let var_ptr = alloc_env_var_as_c_str(&name, &value, &mut this)?; if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { - this.memory.deallocate(var, None, MiriMemoryKind::Runtime.into())?; + this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?; } this.update_environ()?; Ok(0) // return zero on success @@ -267,7 +269,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if this.ptr_is_null(value_ptr)? { // Delete environment variable `{name}` if let Some(var) = this.machine.env_vars.map.remove(&name) { - this.memory.deallocate(var, None, MiriMemoryKind::Runtime.into())?; + this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?; this.update_environ()?; } Ok(1) // return non-zero on success @@ -275,7 +277,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let value = this.read_os_str_from_wide_str(value_ptr)?; let var_ptr = alloc_env_var_as_wide_str(&name, &value, &mut this)?; if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { - this.memory.deallocate(var, None, MiriMemoryKind::Runtime.into())?; + this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?; } this.update_environ()?; Ok(1) // return non-zero on success @@ -300,7 +302,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } if let Some(old) = success { if let Some(var) = old { - this.memory.deallocate(var, None, MiriMemoryKind::Runtime.into())?; + this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?; } this.update_environ()?; Ok(0) @@ -436,7 +438,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Deallocate the old environ list, if any. if let Some(environ) = this.machine.env_vars.environ { let old_vars_ptr = this.read_pointer(&environ.into())?; - this.memory.deallocate(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?; + this.deallocate_ptr(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?; } else { // No `environ` allocated yet, let's do that. // This is memory backing an extern static, hence `ExternStatic`, not `Env`. diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index d9e4d9382246..77567e9bcae5 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -82,10 +82,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(Pointer::null()) } else { let align = this.min_align(size, kind); - let ptr = this.memory.allocate(Size::from_bytes(size), align, kind.into())?; + let ptr = this.allocate_ptr(Size::from_bytes(size), align, kind.into())?; if zero_init { // We just allocated this, the access is definitely in-bounds. - this.memory.write_bytes(ptr.into(), iter::repeat(0u8).take(size as usize)).unwrap(); + this.write_bytes_ptr(ptr.into(), iter::repeat(0u8).take(size as usize)).unwrap(); } Ok(ptr.into()) } @@ -94,7 +94,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn free(&mut self, ptr: Pointer>, kind: MiriMemoryKind) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if !this.ptr_is_null(ptr)? { - this.memory.deallocate(ptr, None, kind.into())?; + this.deallocate_ptr(ptr, None, kind.into())?; } Ok(()) } @@ -112,15 +112,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(Pointer::null()) } else { let new_ptr = - this.memory.allocate(Size::from_bytes(new_size), new_align, kind.into())?; + this.allocate_ptr(Size::from_bytes(new_size), new_align, kind.into())?; Ok(new_ptr.into()) } } else { if new_size == 0 { - this.memory.deallocate(old_ptr, None, kind.into())?; + this.deallocate_ptr(old_ptr, None, kind.into())?; Ok(Pointer::null()) } else { - let new_ptr = this.memory.reallocate( + let new_ptr = this.reallocate_ptr( old_ptr, None, Size::from_bytes(new_size), @@ -373,7 +373,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "miri_static_root" => { let &[ref ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; - let (alloc_id, offset, _) = this.memory.ptr_get_alloc(ptr)?; + let (alloc_id, offset, _) = this.ptr_get_alloc_id(ptr)?; if offset != Size::ZERO { throw_unsup_format!("pointer passed to miri_static_root must point to beginning of an allocated block"); } @@ -440,7 +440,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return this.emulate_allocator(Symbol::intern("__rg_alloc"), |this| { Self::check_alloc_request(size, align)?; - let ptr = this.memory.allocate( + let ptr = this.allocate_ptr( Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into(), @@ -457,14 +457,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return this.emulate_allocator(Symbol::intern("__rg_alloc_zeroed"), |this| { Self::check_alloc_request(size, align)?; - let ptr = this.memory.allocate( + let ptr = this.allocate_ptr( Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into(), )?; // We just allocated this, the access is definitely in-bounds. - this.memory.write_bytes(ptr.into(), iter::repeat(0u8).take(usize::try_from(size).unwrap())).unwrap(); + this.write_bytes_ptr(ptr.into(), iter::repeat(0u8).take(usize::try_from(size).unwrap())).unwrap(); this.write_pointer(ptr, dest) }); } @@ -476,7 +476,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return this.emulate_allocator(Symbol::intern("__rg_dealloc"), |this| { // No need to check old_size/align; we anyway check that they match the allocation. - this.memory.deallocate( + this.deallocate_ptr( ptr, Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())), MiriMemoryKind::Rust.into(), @@ -495,7 +495,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Self::check_alloc_request(new_size, align)?; let align = Align::from_bytes(align).unwrap(); - let new_ptr = this.memory.reallocate( + let new_ptr = this.reallocate_ptr( ptr, Some((Size::from_bytes(old_size), align)), Size::from_bytes(new_size), @@ -514,8 +514,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let n = Size::from_bytes(this.read_scalar(n)?.to_machine_usize(this)?); let result = { - let left_bytes = this.memory.read_bytes(left, n)?; - let right_bytes = this.memory.read_bytes(right, n)?; + let left_bytes = this.read_bytes_ptr(left, n)?; + let right_bytes = this.read_bytes_ptr(right, n)?; use std::cmp::Ordering::*; match left_bytes.cmp(right_bytes) { @@ -533,8 +533,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; if let Some(idx) = this - .memory - .read_bytes(ptr, Size::from_bytes(num))? + .read_bytes_ptr(ptr, Size::from_bytes(num))? .iter() .rev() .position(|&c| c == val) @@ -551,8 +550,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; let idx = this - .memory - .read_bytes(ptr, Size::from_bytes(num))? + .read_bytes_ptr(ptr, Size::from_bytes(num))? .iter() .position(|&c| c == val); if let Some(idx) = idx { diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 7e2068e4657b..9101cbcf05ff 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -88,8 +88,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let byte_count = ty_layout.size.checked_mul(count, this).ok_or_else(|| { err_ub_format!("overflow computing total size of `{}`", intrinsic_name) })?; - this.memory - .write_bytes(ptr, iter::repeat(val_byte).take(byte_count.bytes() as usize))?; + this.write_bytes_ptr( + ptr, + iter::repeat(val_byte).take(byte_count.bytes() as usize), + )?; } // Floating-point operations @@ -1087,7 +1089,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access_align( + this.check_ptr_access_align( place.ptr, place.layout.size, align, @@ -1113,7 +1115,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access_align( + this.check_ptr_access_align( place.ptr, place.layout.size, align, @@ -1168,7 +1170,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access_align( + this.check_ptr_access_align( place.ptr, place.layout.size, align, @@ -1210,7 +1212,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access_align( + this.check_ptr_access_align( place.ptr, place.layout.size, align, @@ -1241,7 +1243,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access_align( + this.check_ptr_access_align( place.ptr, place.layout.size, align, diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 66f673d241d3..83bc6b6ae1ba 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -69,7 +69,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let (dest, ret) = ret.unwrap(); - if this.memory.extra.check_alignment != AlignmentCheck::Symbolic { + if this.machine.check_alignment != AlignmentCheck::Symbolic { // Just use actual implementation. return Ok(false); } @@ -86,7 +86,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Ok(ptr) = ptr.into_pointer_or_addr() { // Only do anything if we can identify the allocation this goes to. let (_, cur_align) = - this.memory.get_size_and_align(ptr.provenance.alloc_id, AllocCheck::MaybeDead)?; + this.get_alloc_size_and_align(ptr.provenance.alloc_id, AllocCheck::MaybeDead)?; if cur_align.bytes() >= req_align { // If the allocation alignment is at least the required alignment we use the // real implementation. diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index ede29d04d6bc..c03f7ad79be7 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -108,8 +108,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok((false, string_length)); } self.eval_context_mut() - .memory - .write_bytes(ptr, bytes.iter().copied().chain(iter::once(0u8)))?; + .write_bytes_ptr(ptr, bytes.iter().copied().chain(iter::once(0u8)))?; Ok((true, string_length)) } @@ -152,8 +151,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let size2 = Size::from_bytes(2); let this = self.eval_context_mut(); let mut alloc = this - .memory - .get_mut(ptr, size2 * string_length, Align::from_bytes(2).unwrap())? + .get_ptr_alloc_mut(ptr, size2 * string_length, Align::from_bytes(2).unwrap())? .unwrap(); // not a ZST, so we will get a result for (offset, wchar) in u16_vec.into_iter().chain(iter::once(0x0000)).enumerate() { let offset = u64::try_from(offset).unwrap(); diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 04a8e9063f9a..4190cccae6d0 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -89,7 +89,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let catch_fn = this.read_scalar(catch_fn)?.check_init()?; // Now we make a function call, and pass `data` as first and only argument. - let f_instance = this.memory.get_fn(try_fn)?.as_instance()?; + let f_instance = this.get_ptr_fn(try_fn)?.as_instance()?; trace!("try_fn: {:?}", f_instance); let ret_place = MPlaceTy::dangling(this.machine.layouts.unit).into(); this.call_function( @@ -123,7 +123,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); trace!("handle_stack_pop(extra = {:?}, unwinding = {})", extra, unwinding); - if let Some(stacked_borrows) = &this.memory.extra.stacked_borrows { + if let Some(stacked_borrows) = &this.machine.stacked_borrows { stacked_borrows.borrow_mut().end_call(extra.call_id); } @@ -146,7 +146,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Push the `catch_fn` stackframe. let f_instance = - this.memory.get_fn(this.scalar_to_ptr(catch_unwind.catch_fn))?.as_instance()?; + this.get_ptr_fn(this.scalar_to_ptr(catch_unwind.catch_fn))?.as_instance()?; trace!("catch_fn: {:?}", f_instance); let ret_place = MPlaceTy::dangling(this.machine.layouts.unit).into(); this.call_function( diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 36bf53059929..4bf0bbc26212 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -157,7 +157,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if size == 0 { this.write_null(&ret.into())?; } else { - let ptr = this.memory.allocate( + let ptr = this.allocate_ptr( Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::C.into(), @@ -174,7 +174,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let symbol = this.read_pointer(symbol)?; let symbol_name = this.read_c_str(symbol)?; if let Some(dlsym) = Dlsym::from_str(symbol_name, &this.tcx.sess.target.os)? { - let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); + let ptr = this.create_fn_alloc_ptr(FnVal::Other(dlsym)); this.write_pointer(ptr, dest)?; } else { this.write_null(dest)?; @@ -214,7 +214,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Extract the function type out of the signature (that seems easier than constructing it ourselves). let dtor = if !this.ptr_is_null(dtor)? { - Some(this.memory.get_fn(dtor)?.as_instance()?) + Some(this.get_ptr_fn(dtor)?.as_instance()?) } else { None }; diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index b71f53cce566..288935576e0d 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -34,7 +34,7 @@ trait FileDescriptor: std::fmt::Debug { bytes: &mut [u8], ) -> InterpResult<'tcx, io::Result>; fn write<'tcx>( - &mut self, + &self, communicate_allowed: bool, bytes: &[u8], ) -> InterpResult<'tcx, io::Result>; @@ -66,12 +66,12 @@ impl FileDescriptor for FileHandle { } fn write<'tcx>( - &mut self, + &self, communicate_allowed: bool, bytes: &[u8], ) -> InterpResult<'tcx, io::Result> { assert!(communicate_allowed, "isolation should have prevented even opening a file"); - Ok(self.file.write(bytes)) + Ok((&mut &self.file).write(bytes)) } fn seek<'tcx>( @@ -133,7 +133,7 @@ impl FileDescriptor for io::Stdin { } fn write<'tcx>( - &mut self, + &self, _communicate_allowed: bool, _bytes: &[u8], ) -> InterpResult<'tcx, io::Result> { @@ -174,12 +174,12 @@ impl FileDescriptor for io::Stdout { } fn write<'tcx>( - &mut self, + &self, _communicate_allowed: bool, bytes: &[u8], ) -> InterpResult<'tcx, io::Result> { // We allow writing to stderr even with isolation enabled. - let result = Write::write(self, bytes); + let result = Write::write(&mut { self }, bytes); // Stdout is buffered, flush to make sure it appears on the // screen. This is the write() syscall of the interpreted // program, we want it to correspond to a write() syscall on @@ -224,13 +224,13 @@ impl FileDescriptor for io::Stderr { } fn write<'tcx>( - &mut self, + &self, _communicate_allowed: bool, bytes: &[u8], ) -> InterpResult<'tcx, io::Result> { // We allow writing to stderr even with isolation enabled. // No need to flush, stderr is not buffered. - Ok(Write::write(self, bytes)) + Ok(Write::write(&mut { self }, bytes)) } fn seek<'tcx>( @@ -681,7 +681,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("Reading from FD {}, size {}", fd, count); // Check that the *entire* buffer is actually valid memory. - this.memory.check_ptr_access_align( + this.check_ptr_access_align( buf, Size::from_bytes(count), Align::ONE, @@ -707,7 +707,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match result { Ok(read_bytes) => { // If reading to `bytes` did not fail, we write those bytes to the buffer. - this.memory.write_bytes(buf, bytes)?; + this.write_bytes_ptr(buf, bytes)?; Ok(read_bytes) } Err(e) => { @@ -727,7 +727,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Isolation check is done via `FileDescriptor` trait. // Check that the *entire* buffer is actually valid memory. - this.memory.check_ptr_access_align( + this.check_ptr_access_align( buf, Size::from_bytes(count), Align::ONE, @@ -739,8 +739,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64); let communicate = this.machine.communicate(); - if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { - let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; + if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { + let bytes = this.read_bytes_ptr(buf, Size::from_bytes(count))?; let result = file_descriptor.write(communicate, &bytes)?.map(|c| i64::try_from(c).unwrap()); this.try_unwrap_io_result(result) @@ -1288,7 +1288,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; let name_ptr = entry.offset(Size::from_bytes(d_name_offset), this)?; - this.memory.write_bytes(name_ptr, name_bytes.iter().copied())?; + this.write_bytes_ptr(name_ptr, name_bytes.iter().copied())?; entry } @@ -1597,7 +1597,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // 'readlink' truncates the resolved path if // the provided buffer is not large enough. - this.memory.write_bytes(buf, path_bytes.iter().copied())?; + this.write_bytes_ptr(buf, path_bytes.iter().copied())?; Ok(path_bytes.len().try_into().unwrap()) } Err(e) => { diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 17ddca879e68..60c0c2d7c101 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -79,7 +79,7 @@ pub fn futex<'tcx>( // Check the pointer for alignment and validity. // The API requires `addr` to be a 4-byte aligned pointer, and will // use the 4 bytes at the given address as an (atomic) i32. - this.memory.check_ptr_access_align( + this.check_ptr_access_align( this.scalar_to_ptr(addr_scalar), Size::from_bytes(4), Align::from_bytes(4).unwrap(), diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index 8147b1442907..18646b70130e 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -121,7 +121,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[ref dtor, ref data] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let dtor = this.read_pointer(dtor)?; - let dtor = this.memory.get_fn(dtor)?.as_instance()?; + let dtor = this.get_ptr_fn(dtor)?.as_instance()?; let data = this.read_scalar(data)?.check_init()?; let active_thread = this.get_active_thread(); this.machine.tls.set_macos_thread_dtor(active_thread, dtor, data)?; diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index b49817e88511..58d48028f62c 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -41,7 +41,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let old_thread_id = this.set_active_thread(new_thread_id); // Perform the function pointer load in the new thread frame. - let instance = this.memory.get_fn(fn_ptr)?.as_instance()?; + let instance = this.get_ptr_fn(fn_ptr)?.as_instance()?; // Note: the returned value is currently ignored (see the FIXME in // pthread_join below) because the Rust standard library does not use @@ -122,7 +122,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut name = this.get_active_thread_name().to_vec(); name.push(0u8); assert!(name.len() <= 16); - this.memory.write_bytes(address, name)?; + this.write_bytes_ptr(address, name)?; } else { throw_unsup_format!("unsupported prctl option {}", option); } diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 32bea8dde475..297d0c1228a4 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -249,7 +249,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "p_thread_callback", ])?; let thread_callback = - this.memory.get_fn(this.scalar_to_ptr(thread_callback))?.as_instance()?; + this.get_ptr_fn(this.scalar_to_ptr(thread_callback))?.as_instance()?; // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. let reason = this.eval_path_scalar(&["std", "sys", "windows", "c", "DLL_THREAD_DETACH"])?; diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 61a1759ffee5..82ac5c5d75c4 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -87,7 +87,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // stdout/stderr use std::io::{self, Write}; - let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(u64::from(n)))?; + let buf_cont = this.read_bytes_ptr(buf, Size::from_bytes(u64::from(n)))?; let res = if handle == -11 { io::stdout().write(buf_cont) } else { @@ -157,7 +157,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let system_info = this.deref_operand(system_info)?; // Initialize with `0`. - this.memory.write_bytes( + this.write_bytes_ptr( system_info.ptr, iter::repeat(0u8).take(system_info.layout.size.bytes() as usize), )?; @@ -269,7 +269,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.read_scalar(hModule)?.to_machine_isize(this)?; let name = this.read_c_str(this.read_pointer(lpProcName)?)?; if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.os)? { - let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); + let ptr = this.create_fn_alloc_ptr(FnVal::Other(dlsym)); this.write_pointer(ptr, dest)?; } else { this.write_null(dest)?; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 777b8e9331ee..a365d909981b 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -93,7 +93,7 @@ pub struct Stacks { /// Extra global state, available to the memory access hooks. #[derive(Debug)] -pub struct GlobalState { +pub struct GlobalStateInner { /// Next unused pointer ID (tag). next_ptr_id: PtrId, /// Table storing the "base" tag for each allocation. @@ -111,8 +111,8 @@ pub struct GlobalState { /// Whether to track raw pointers. tag_raw: bool, } -/// Memory extra state gives us interior mutable access to the global state. -pub type MemoryExtra = RefCell; +/// We need interior mutable access to the global state. +pub type GlobalState = RefCell; /// Indicates which kind of access is being performed. #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] @@ -156,13 +156,13 @@ impl fmt::Display for RefKind { } /// Utilities for initialization and ID generation -impl GlobalState { +impl GlobalStateInner { pub fn new( tracked_pointer_tag: Option, tracked_call_id: Option, tag_raw: bool, ) -> Self { - GlobalState { + GlobalStateInner { next_ptr_id: NonZeroU64::new(1).unwrap(), base_ptr_ids: FxHashMap::default(), next_call_id: NonZeroU64::new(1).unwrap(), @@ -308,7 +308,7 @@ impl<'tcx> Stack { fn check_protector( item: &Item, provoking_access: Option<(SbTag, AccessKind)>, - global: &GlobalState, + global: &GlobalStateInner, ) -> InterpResult<'tcx> { if let SbTag::Tagged(id) = item.tag { if Some(id) == global.tracked_pointer_tag { @@ -348,7 +348,7 @@ impl<'tcx> Stack { access: AccessKind, tag: SbTag, (alloc_id, range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages - global: &GlobalState, + global: &GlobalStateInner, ) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. @@ -396,7 +396,7 @@ impl<'tcx> Stack { &mut self, tag: SbTag, dbg_ptr: Pointer, // just for debug printing and error messages - global: &GlobalState, + global: &GlobalStateInner, ) -> InterpResult<'tcx> { // Step 1: Find granting item. self.find_granting(AccessKind::Write, tag).ok_or_else(|| { @@ -425,7 +425,7 @@ impl<'tcx> Stack { derived_from: SbTag, new: Item, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages - global: &GlobalState, + global: &GlobalStateInner, ) -> InterpResult<'tcx> { // Figure out which access `perm` corresponds to. let access = @@ -584,10 +584,10 @@ impl Stacks { pub fn new_allocation( id: AllocId, size: Size, - extra: &MemoryExtra, + state: &GlobalState, kind: MemoryKind, ) -> Self { - let mut extra = extra.borrow_mut(); + let mut extra = state.borrow_mut(); let (base_tag, perm) = match kind { // New unique borrow. This tag is not accessible by the program, // so it will only ever be used when using the local directly (i.e., @@ -628,7 +628,7 @@ impl Stacks { alloc_id: AllocId, tag: SbTag, range: AllocRange, - extra: &MemoryExtra, + state: &GlobalState, ) -> InterpResult<'tcx> { trace!( "read access with tag {:?}: {:?}, size {}", @@ -636,7 +636,7 @@ impl Stacks { Pointer::new(alloc_id, range.start), range.size.bytes() ); - let global = &*extra.borrow(); + let global = &*state.borrow(); self.for_each(range, move |offset, stack| { stack.access(AccessKind::Read, tag, (alloc_id, range, offset), global) }) @@ -648,7 +648,7 @@ impl Stacks { alloc_id: AllocId, tag: SbTag, range: AllocRange, - extra: &mut MemoryExtra, + state: &mut GlobalState, ) -> InterpResult<'tcx> { trace!( "write access with tag {:?}: {:?}, size {}", @@ -656,7 +656,7 @@ impl Stacks { Pointer::new(alloc_id, range.start), range.size.bytes() ); - let global = extra.get_mut(); + let global = state.get_mut(); self.for_each_mut(range, move |offset, stack| { stack.access(AccessKind::Write, tag, (alloc_id, range, offset), global) }) @@ -668,10 +668,10 @@ impl Stacks { alloc_id: AllocId, tag: SbTag, range: AllocRange, - extra: &mut MemoryExtra, + state: &mut GlobalState, ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", tag, alloc_id, range.size.bytes()); - let global = extra.get_mut(); + let global = state.get_mut(); self.for_each_mut(range, move |offset, stack| { stack.dealloc(tag, Pointer::new(alloc_id, offset), global) }) @@ -702,12 +702,12 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); return Ok(()); } - let (alloc_id, base_offset, ptr) = this.memory.ptr_get_alloc(place.ptr)?; + let (alloc_id, base_offset, ptr) = this.ptr_get_alloc_id(place.ptr)?; let orig_tag = ptr.provenance.sb; // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). let (alloc_size, _) = - this.memory.get_size_and_align(alloc_id, AllocCheck::Dereferenceable)?; + this.get_alloc_size_and_align(alloc_id, AllocCheck::Dereferenceable)?; if base_offset + size > alloc_size { throw_ub!(PointerOutOfBounds { alloc_id, @@ -750,10 +750,10 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We need a frozen-sensitive reborrow. // We have to use shared references to alloc/memory_extra here since // `visit_freeze_sensitive` needs to access the global state. - let extra = this.memory.get_alloc_extra(alloc_id)?; + let extra = this.get_alloc_extra(alloc_id)?; let stacked_borrows = extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); - let global = this.memory.extra.stacked_borrows.as_ref().unwrap().borrow(); + let global = this.machine.stacked_borrows.as_ref().unwrap().borrow(); this.visit_freeze_sensitive(place, size, |mut range, frozen| { // Adjust range. range.start += base_offset; @@ -774,7 +774,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Here we can avoid `borrow()` calls because we have mutable references. // Note that this asserts that the allocation is mutable -- but since we are creating a // mutable pointer, that seems reasonable. - let (alloc_extra, memory_extra) = this.memory.get_alloc_extra_mut(alloc_id)?; + let (alloc_extra, memory_extra) = this.get_alloc_extra_mut(alloc_id)?; let stacked_borrows = alloc_extra.stacked_borrows.as_mut().expect("we should have Stacked Borrows data"); let global = memory_extra.stacked_borrows.as_mut().unwrap().get_mut(); @@ -808,7 +808,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Compute new borrow. let new_tag = { - let mem_extra = this.memory.extra.stacked_borrows.as_mut().unwrap().get_mut(); + let mem_extra = this.machine.stacked_borrows.as_mut().unwrap().get_mut(); match kind { // Give up tracking for raw pointers. RefKind::Raw { .. } if !mem_extra.tag_raw => SbTag::Untagged, diff --git a/src/sync.rs b/src/sync.rs index 0e4e9695d81d..44ea18f4055d 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -242,7 +242,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex.owner = Some(thread); } mutex.lock_count = mutex.lock_count.checked_add(1).unwrap(); - if let Some(data_race) = &this.memory.extra.data_race { + if let Some(data_race) = &this.machine.data_race { data_race.validate_lock_acquire(&mutex.data_race, thread); } } @@ -268,7 +268,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex.owner = None; // The mutex is completely unlocked. Try transfering ownership // to another thread. - if let Some(data_race) = &this.memory.extra.data_race { + if let Some(data_race) = &this.machine.data_race { data_race.validate_lock_release(&mut mutex.data_race, current_owner); } this.mutex_dequeue_and_lock(id); @@ -328,7 +328,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let rwlock = &mut this.machine.threads.sync.rwlocks[id]; let count = rwlock.readers.entry(reader).or_insert(0); *count = count.checked_add(1).expect("the reader counter overflowed"); - if let Some(data_race) = &this.memory.extra.data_race { + if let Some(data_race) = &this.machine.data_race { data_race.validate_lock_acquire(&rwlock.data_race, reader); } } @@ -352,7 +352,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Entry::Vacant(_) => return false, // we did not even own this lock } - if let Some(data_race) = &this.memory.extra.data_race { + if let Some(data_race) = &this.machine.data_race { data_race.validate_lock_release_shared(&mut rwlock.data_race_reader, reader); } @@ -385,7 +385,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("rwlock_writer_lock: {:?} now held by {:?}", id, writer); let rwlock = &mut this.machine.threads.sync.rwlocks[id]; rwlock.writer = Some(writer); - if let Some(data_race) = &this.memory.extra.data_race { + if let Some(data_race) = &this.machine.data_race { data_race.validate_lock_acquire(&rwlock.data_race, writer); } } @@ -405,7 +405,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Release memory to both reader and writer vector clocks // since this writer happens-before both the union of readers once they are finished // and the next writer - if let Some(data_race) = &this.memory.extra.data_race { + if let Some(data_race) = &this.machine.data_race { data_race.validate_lock_release(&mut rwlock.data_race, current_writer); data_race.validate_lock_release(&mut rwlock.data_race_reader, current_writer); } @@ -465,7 +465,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let current_thread = this.get_active_thread(); let condvar = &mut this.machine.threads.sync.condvars[id]; - let data_race = &this.memory.extra.data_race; + let data_race = &this.machine.data_race; // Each condvar signal happens-before the end of the condvar wake if let Some(data_race) = data_race { @@ -498,7 +498,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let current_thread = this.get_active_thread(); let futex = &mut this.machine.threads.sync.futexes.get_mut(&addr)?; - let data_race = &this.memory.extra.data_race; + let data_race = &this.machine.data_race; // Each futex-wake happens-before the end of the futex wait if let Some(data_race) = data_race { diff --git a/src/thread.rs b/src/thread.rs index b2f2a8098de2..2c5f6c2391f0 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -574,7 +574,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let allocation = tcx.eval_static_initializer(def_id)?; // Create a fresh allocation with this content. let new_alloc = - this.memory.allocate_with(allocation.inner().clone(), MiriMemoryKind::Tls.into()); + this.allocate_raw_ptr(allocation.inner().clone(), MiriMemoryKind::Tls.into()); this.machine.threads.set_thread_local_alloc(def_id, new_alloc); Ok(new_alloc) } @@ -584,7 +584,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn create_thread(&mut self) -> ThreadId { let this = self.eval_context_mut(); let id = this.machine.threads.create_thread(); - if let Some(data_race) = &mut this.memory.extra.data_race { + if let Some(data_race) = &mut this.machine.data_race { data_race.thread_created(id); } id @@ -599,14 +599,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.machine.threads.join_thread(joined_thread_id, this.memory.extra.data_race.as_mut())?; + this.machine.threads.join_thread(joined_thread_id, this.machine.data_race.as_mut())?; Ok(()) } #[inline] fn set_active_thread(&mut self, thread_id: ThreadId) -> ThreadId { let this = self.eval_context_mut(); - if let Some(data_race) = &this.memory.extra.data_race { + if let Some(data_race) = &this.machine.data_race { data_race.thread_set_active(thread_id); } this.machine.threads.set_active_thread_id(thread_id) @@ -669,7 +669,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn set_active_thread_name(&mut self, new_thread_name: Vec) { let this = self.eval_context_mut(); - if let Some(data_race) = &mut this.memory.extra.data_race { + if let Some(data_race) = &mut this.machine.data_race { if let Ok(string) = String::from_utf8(new_thread_name.clone()) { data_race.thread_set_name(this.machine.threads.active_thread, string); } @@ -753,7 +753,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { let this = self.eval_context_mut(); - let data_race = &this.memory.extra.data_race; + let data_race = &this.machine.data_race; this.machine.threads.schedule(data_race) } @@ -764,8 +764,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn thread_terminated(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - for ptr in this.machine.threads.thread_terminated(this.memory.extra.data_race.as_mut()) { - this.memory.deallocate(ptr.into(), None, MiriMemoryKind::Tls.into())?; + for ptr in this.machine.threads.thread_terminated(this.machine.data_race.as_mut()) { + this.deallocate_ptr(ptr.into(), None, MiriMemoryKind::Tls.into())?; } Ok(()) } From 0512b2a376c7d984e94367bf578c1f98c88654f2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 Apr 2022 11:10:21 -0400 Subject: [PATCH 2970/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 8e4cdeddfccb..3007bc068a24 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6af09d2505f38e4f1df291df56d497fb2ad935ed +634770c0a7f8598164ab825cfe419cc8b03c36e5 From 46ff257b4e3e417b145b13fbbbb0fb45fde08b15 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 Apr 2022 18:29:17 -0400 Subject: [PATCH 2971/5092] test that partially uninit MaybeUninit works correctly --- rust-version | 2 +- tests/run-pass/partially-uninit.rs | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tests/run-pass/partially-uninit.rs diff --git a/rust-version b/rust-version index 3007bc068a24..c84d46fa5142 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -634770c0a7f8598164ab825cfe419cc8b03c36e5 +f262ca12aac76152c4b46cefcf8300f0249a5eb2 diff --git a/tests/run-pass/partially-uninit.rs b/tests/run-pass/partially-uninit.rs new file mode 100644 index 000000000000..1de530842827 --- /dev/null +++ b/tests/run-pass/partially-uninit.rs @@ -0,0 +1,15 @@ +// compile-flags: -Zmiri-check-number-validity + +use std::mem::{self, MaybeUninit}; + +#[repr(C)] +#[derive(Copy, Clone, Debug, PartialEq)] +struct Demo(bool, u16); + +fn main() { unsafe { + // Transmute-round-trip through a type with Scalar layout is lossless. + // This is tricky because that 'scalar' is *partially* uninitialized. + let x = Demo(true, 3); + let y: MaybeUninit = mem::transmute(x); + assert_eq!(x, mem::transmute(y)); +} } From 37cefa32d2badcb6eebd6851104108f1e02d3c3c Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 6 Apr 2022 23:03:52 +0200 Subject: [PATCH 2972/5092] Add support for FUTEX_WAIT_BITSET(bitset=MAX). --- src/shims/posix/linux/sync.rs | 49 ++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 60c0c2d7c101..a4097bcd75fa 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -36,6 +36,7 @@ pub fn futex<'tcx>( let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?; let futex_wait = this.eval_libc_i32("FUTEX_WAIT")?; + let futex_wait_bitset = this.eval_libc_i32("FUTEX_WAIT_BITSET")?; let futex_wake = this.eval_libc_i32("FUTEX_WAKE")?; let futex_realtime = this.eval_libc_i32("FUTEX_CLOCK_REALTIME")?; @@ -45,12 +46,32 @@ pub fn futex<'tcx>( // FUTEX_WAIT: (int *addr, int op = FUTEX_WAIT, int val, const timespec *timeout) // Blocks the thread if *addr still equals val. Wakes up when FUTEX_WAKE is called on the same address, // or *timeout expires. `timeout == null` for an infinite timeout. - op if op & !futex_realtime == futex_wait => { - if args.len() < 5 { - throw_ub_format!( - "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT`: got {}, expected at least 5", - args.len() - ); + // + // FUTEX_WAIT_BITSET: (int *addr, int op = FUTEX_WAIT_BITSET, int val, const timespec *timeout, int *_ignored, unsigned int bitset) + // When bitset is u32::MAX, this is identical to FUTEX_WAIT, except the timeout is absolute rather than relative. + op if op & !futex_realtime == futex_wait || op & !futex_realtime == futex_wait_bitset => { + let wait_bitset = op & !futex_realtime == futex_wait_bitset; + + if wait_bitset { + if args.len() != 7 { + throw_ub_format!( + "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT_BITSET`: got {}, expected 7", + args.len() + ); + } + + let bitset = this.read_scalar(&args[6])?.to_u32()?; + + if bitset != u32::MAX { + throw_unsup_format!("Miri does not support `futex` syscall with `op=FUTEX_WAIT_BITSET` with a bitset other than UINT_MAX"); + } + } else { + if args.len() < 5 { + throw_ub_format!( + "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT`: got {}, expected at least 5", + args.len() + ); + } } // `deref_operand` but not actually dereferencing the ptr yet (it might be NULL!). @@ -70,10 +91,20 @@ pub fn futex<'tcx>( return Ok(()); } }; - Some(if op & futex_realtime != 0 { - Time::RealTime(SystemTime::now().checked_add(duration).unwrap()) + Some(if wait_bitset { + // FUTEX_WAIT_BITSET uses an absolute timestamp. + if op & futex_realtime != 0 { + Time::RealTime(SystemTime::UNIX_EPOCH.checked_add(duration).unwrap()) + } else { + Time::Monotonic(this.machine.time_anchor.checked_add(duration).unwrap()) + } } else { - Time::Monotonic(Instant::now().checked_add(duration).unwrap()) + // FUTEX_WAIT uses a relative timestamp. + if op & futex_realtime != 0 { + Time::RealTime(SystemTime::now().checked_add(duration).unwrap()) + } else { + Time::Monotonic(Instant::now().checked_add(duration).unwrap()) + } }) }; // Check the pointer for alignment and validity. From a72a929b19875eaa459b79c398b7fff234e8b6ad Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 6 Apr 2022 23:04:15 +0200 Subject: [PATCH 2973/5092] Add test for FUTEX_WAIT_BITSET. --- tests/run-pass/concurrency/linux-futex.rs | 38 +++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/run-pass/concurrency/linux-futex.rs b/tests/run-pass/concurrency/linux-futex.rs index 0f2a0236326b..7ffe59e7a1bb 100644 --- a/tests/run-pass/concurrency/linux-futex.rs +++ b/tests/run-pass/concurrency/linux-futex.rs @@ -7,6 +7,7 @@ #![feature(rustc_private)] extern crate libc; +use std::mem::MaybeUninit; use std::ptr; use std::thread; use std::time::{Duration, Instant}; @@ -93,6 +94,42 @@ fn wait_timeout() { assert!((200..1000).contains(&start.elapsed().as_millis())); } +fn wait_absolute_timeout() { + let start = Instant::now(); + + // Get the current monotonic timestamp as timespec. + let mut timeout = unsafe { + let mut now: MaybeUninit = MaybeUninit::uninit(); + assert_eq!(libc::clock_gettime(libc::CLOCK_MONOTONIC, now.as_mut_ptr()), 0); + now.assume_init() + }; + + // Add 200ms. + timeout.tv_nsec += 200_000_000; + if timeout.tv_nsec > 1_000_000_000 { + timeout.tv_nsec -= 1_000_000_000; + timeout.tv_sec += 1; + } + + let futex: i32 = 123; + + // Wait for 200ms from now, with nobody waking us up early. + unsafe { + assert_eq!(libc::syscall( + libc::SYS_futex, + &futex as *const i32, + libc::FUTEX_WAIT_BITSET, + 123, + &timeout, + 0, + u32::MAX, + ), -1); + assert_eq!(*libc::__errno_location(), libc::ETIMEDOUT); + } + + assert!((200..1000).contains(&start.elapsed().as_millis())); +} + fn wait_wake() { let start = Instant::now(); @@ -128,5 +165,6 @@ fn main() { wake_dangling(); wait_wrong_val(); wait_timeout(); + wait_absolute_timeout(); wait_wake(); } From 12c88886b0a2a112de8ab802447bdd2b48fdb795 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 6 Apr 2022 23:13:47 +0200 Subject: [PATCH 2974/5092] Formatting. --- src/shims/posix/linux/sync.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index a4097bcd75fa..cb1a9d74fa46 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -63,7 +63,9 @@ pub fn futex<'tcx>( let bitset = this.read_scalar(&args[6])?.to_u32()?; if bitset != u32::MAX { - throw_unsup_format!("Miri does not support `futex` syscall with `op=FUTEX_WAIT_BITSET` with a bitset other than UINT_MAX"); + throw_unsup_format!( + "Miri does not support `futex` syscall with `op=FUTEX_WAIT_BITSET` with a bitset other than UINT_MAX" + ); } } else { if args.len() < 5 { From 53ed500c92d95b0f7c5ab974573b0e7ca283d45e Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 6 Apr 2022 23:48:14 +0200 Subject: [PATCH 2975/5092] Fully support FUTEX_*_BITSET. --- src/shims/posix/linux/sync.rs | 50 ++++++++++++++++++++++++++--------- src/sync.rs | 16 ++++++----- 2 files changed, 48 insertions(+), 18 deletions(-) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index cb1a9d74fa46..b0db9dd51f4f 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -38,6 +38,7 @@ pub fn futex<'tcx>( let futex_wait = this.eval_libc_i32("FUTEX_WAIT")?; let futex_wait_bitset = this.eval_libc_i32("FUTEX_WAIT_BITSET")?; let futex_wake = this.eval_libc_i32("FUTEX_WAKE")?; + let futex_wake_bitset = this.eval_libc_i32("FUTEX_WAKE_BITSET")?; let futex_realtime = this.eval_libc_i32("FUTEX_CLOCK_REALTIME")?; // FUTEX_PRIVATE enables an optimization that stops it from working across processes. @@ -48,10 +49,14 @@ pub fn futex<'tcx>( // or *timeout expires. `timeout == null` for an infinite timeout. // // FUTEX_WAIT_BITSET: (int *addr, int op = FUTEX_WAIT_BITSET, int val, const timespec *timeout, int *_ignored, unsigned int bitset) - // When bitset is u32::MAX, this is identical to FUTEX_WAIT, except the timeout is absolute rather than relative. + // This is identical to FUTEX_WAIT, except: + // - The timeout is absolute rather than relative. + // - You can specify the bitset to selecting what WAKE operations to respond to. op if op & !futex_realtime == futex_wait || op & !futex_realtime == futex_wait_bitset => { let wait_bitset = op & !futex_realtime == futex_wait_bitset; + let bitset; + if wait_bitset { if args.len() != 7 { throw_ub_format!( @@ -59,14 +64,7 @@ pub fn futex<'tcx>( args.len() ); } - - let bitset = this.read_scalar(&args[6])?.to_u32()?; - - if bitset != u32::MAX { - throw_unsup_format!( - "Miri does not support `futex` syscall with `op=FUTEX_WAIT_BITSET` with a bitset other than UINT_MAX" - ); - } + bitset = this.read_scalar(&args[6])?.to_u32()?; } else { if args.len() < 5 { throw_ub_format!( @@ -74,6 +72,14 @@ pub fn futex<'tcx>( args.len() ); } + bitset = u32::MAX; + } + + if bitset == 0 { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?; + return Ok(()); } // `deref_operand` but not actually dereferencing the ptr yet (it might be NULL!). @@ -141,7 +147,7 @@ pub fn futex<'tcx>( if val == futex_val { // The value still matches, so we block the trait make it wait for FUTEX_WAKE. this.block_thread(thread); - this.futex_wait(addr_scalar.to_machine_usize(this)?, thread); + this.futex_wait(addr_scalar.to_machine_usize(this)?, thread, bitset); // Succesfully waking up from FUTEX_WAIT always returns zero. this.write_scalar(Scalar::from_machine_isize(0, this), dest)?; // Register a timeout callback if a timeout was specified. @@ -173,10 +179,30 @@ pub fn futex<'tcx>( // Wakes at most `val` threads waiting on the futex at `addr`. // Returns the amount of threads woken up. // Does not access the futex value at *addr. - op if op == futex_wake => { + // FUTEX_WAKE_BITSET: (int *addr, int op = FUTEX_WAKE, int val, const timespect *_unused, int *_unused, unsigned int bitset) + // Same as FUTEX_WAKE, but allows you to specify a bitset to select which threads to wake up. + op if op == futex_wake || op == futex_wake_bitset => { + let bitset; + if op == futex_wake_bitset { + if args.len() != 7 { + throw_ub_format!( + "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAKE_BITSET`: got {}, expected 7", + args.len() + ); + } + bitset = this.read_scalar(&args[6])?.to_u32()?; + } else { + bitset = u32::MAX; + } + if bitset == 0 { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?; + return Ok(()); + } let mut n = 0; for _ in 0..val { - if let Some(thread) = this.futex_wake(addr_scalar.to_machine_usize(this)?) { + if let Some(thread) = this.futex_wake(addr_scalar.to_machine_usize(this)?, bitset) { this.unblock_thread(thread); this.unregister_timeout_callback_if_exists(thread); n += 1; diff --git a/src/sync.rs b/src/sync.rs index 44ea18f4055d..9007f25ce5c7 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -144,6 +144,8 @@ struct Futex { struct FutexWaiter { /// The thread that is waiting on this futex. thread: ThreadId, + /// The bitset used by FUTEX_*_BITSET, or u32::MAX for other operations. + bitset: u32, } /// The state of all synchronization variables. @@ -486,15 +488,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.threads.sync.condvars[id].waiters.retain(|waiter| waiter.thread != thread); } - fn futex_wait(&mut self, addr: u64, thread: ThreadId) { + fn futex_wait(&mut self, addr: u64, thread: ThreadId, bitset: u32) { let this = self.eval_context_mut(); let futex = &mut this.machine.threads.sync.futexes.entry(addr).or_default(); let waiters = &mut futex.waiters; assert!(waiters.iter().all(|waiter| waiter.thread != thread), "thread is already waiting"); - waiters.push_back(FutexWaiter { thread }); + waiters.push_back(FutexWaiter { thread, bitset }); } - fn futex_wake(&mut self, addr: u64) -> Option { + fn futex_wake(&mut self, addr: u64, bitset: u32) -> Option { let this = self.eval_context_mut(); let current_thread = this.get_active_thread(); let futex = &mut this.machine.threads.sync.futexes.get_mut(&addr)?; @@ -504,13 +506,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(data_race) = data_race { data_race.validate_lock_release(&mut futex.data_race, current_thread); } - let res = futex.waiters.pop_front().map(|waiter| { + + // Wake up the first thread in the queue that matches any of the bits in the bitset. + futex.waiters.iter().position(|w| w.bitset & bitset != 0).map(|i| { + let waiter = futex.waiters.remove(i).unwrap(); if let Some(data_race) = data_race { data_race.validate_lock_acquire(&futex.data_race, waiter.thread); } waiter.thread - }); - res + }) } fn futex_remove_waiter(&mut self, addr: u64, thread: ThreadId) { From 5581e338067c5af7937f41d0b6ee55cfc8319cc0 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 6 Apr 2022 23:48:26 +0200 Subject: [PATCH 2976/5092] Add test for FUTEX_*_BITSET. --- tests/run-pass/concurrency/linux-futex.rs | 48 +++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tests/run-pass/concurrency/linux-futex.rs b/tests/run-pass/concurrency/linux-futex.rs index 7ffe59e7a1bb..fb7c022929bd 100644 --- a/tests/run-pass/concurrency/linux-futex.rs +++ b/tests/run-pass/concurrency/linux-futex.rs @@ -160,6 +160,53 @@ fn wait_wake() { assert!((200..1000).contains(&start.elapsed().as_millis())); } +fn wait_wake_bitset() { + let start = Instant::now(); + + static FUTEX: i32 = 0; + + thread::spawn(move || { + thread::sleep(Duration::from_millis(200)); + unsafe { + assert_eq!(libc::syscall( + libc::SYS_futex, + &FUTEX as *const i32, + libc::FUTEX_WAKE_BITSET, + 10, // Wake up at most 10 threads. + 0, + 0, + 0b1001, // bitset + ), 0); // Didn't match any thread. + } + thread::sleep(Duration::from_millis(200)); + unsafe { + assert_eq!(libc::syscall( + libc::SYS_futex, + &FUTEX as *const i32, + libc::FUTEX_WAKE_BITSET, + 10, // Wake up at most 10 threads. + 0, + 0, + 0b0110, // bitset + ), 1); // Woken up one thread. + } + }); + + unsafe { + assert_eq!(libc::syscall( + libc::SYS_futex, + &FUTEX as *const i32, + libc::FUTEX_WAIT_BITSET, + 0, + ptr::null::(), + 0, + 0b0100, // bitset + ), 0); + } + + assert!((400..1000).contains(&start.elapsed().as_millis())); +} + fn main() { wake_nobody(); wake_dangling(); @@ -167,4 +214,5 @@ fn main() { wait_timeout(); wait_absolute_timeout(); wait_wake(); + wait_wake_bitset(); } From 03417de176f5f3811c5ba7782b9b547fe5be89a5 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 6 Apr 2022 23:55:02 +0200 Subject: [PATCH 2977/5092] Use `let = if;` instead of `let; if`. --- src/shims/posix/linux/sync.rs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index b0db9dd51f4f..9350ad6ba94d 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -55,16 +55,14 @@ pub fn futex<'tcx>( op if op & !futex_realtime == futex_wait || op & !futex_realtime == futex_wait_bitset => { let wait_bitset = op & !futex_realtime == futex_wait_bitset; - let bitset; - - if wait_bitset { + let bitset = if wait_bitset { if args.len() != 7 { throw_ub_format!( "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT_BITSET`: got {}, expected 7", args.len() ); } - bitset = this.read_scalar(&args[6])?.to_u32()?; + this.read_scalar(&args[6])?.to_u32()? } else { if args.len() < 5 { throw_ub_format!( @@ -72,8 +70,8 @@ pub fn futex<'tcx>( args.len() ); } - bitset = u32::MAX; - } + u32::MAX + }; if bitset == 0 { let einval = this.eval_libc("EINVAL")?; @@ -182,18 +180,17 @@ pub fn futex<'tcx>( // FUTEX_WAKE_BITSET: (int *addr, int op = FUTEX_WAKE, int val, const timespect *_unused, int *_unused, unsigned int bitset) // Same as FUTEX_WAKE, but allows you to specify a bitset to select which threads to wake up. op if op == futex_wake || op == futex_wake_bitset => { - let bitset; - if op == futex_wake_bitset { + let bitset = if op == futex_wake_bitset { if args.len() != 7 { throw_ub_format!( "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAKE_BITSET`: got {}, expected 7", args.len() ); } - bitset = this.read_scalar(&args[6])?.to_u32()?; + this.read_scalar(&args[6])?.to_u32()? } else { - bitset = u32::MAX; - } + u32::MAX + }; if bitset == 0 { let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; From 4fdda315cc1d2175a1c49617eb342cdffe8c351f Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 7 Apr 2022 00:02:20 +0200 Subject: [PATCH 2978/5092] Put 306ba8357fb36212b7d30efb9eb9e41659ac1445 in rust-version. --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index c84d46fa5142..60b8609f73b4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -f262ca12aac76152c4b46cefcf8300f0249a5eb2 +306ba8357fb36212b7d30efb9eb9e41659ac1445 From f2cfc928a52429e4be51565876ed5c2b6625ecc4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Apr 2022 08:35:29 -0400 Subject: [PATCH 2979/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 60b8609f73b4..f08a8228d45f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -306ba8357fb36212b7d30efb9eb9e41659ac1445 +bbe9d27b8ff36da56638aa43d6d0cdfdf89a4e57 From e1556c857692b9595357a35bcd567f6761c2abc4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Apr 2022 18:30:25 -0400 Subject: [PATCH 2980/5092] add machine hook tcx parameters --- src/machine.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/machine.rs b/src/machine.rs index 9108f4f16663..9e0cb69f28d8 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -605,6 +605,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn memory_read( + _tcx: TyCtxt<'tcx>, machine: &Self, alloc_extra: &AllocExtra, tag: Tag, @@ -627,6 +628,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn memory_written( + _tcx: TyCtxt<'tcx>, machine: &mut Self, alloc_extra: &mut AllocExtra, tag: Tag, @@ -649,6 +651,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn memory_deallocated( + _tcx: TyCtxt<'tcx>, machine: &mut Self, alloc_extra: &mut AllocExtra, tag: Tag, From 59ee672fef55dda91c912286e614cd3dd2c82899 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Apr 2022 15:27:57 -0400 Subject: [PATCH 2981/5092] for variadic functions, accept arbitrary trailing arguments but make sure we check all leading arguments --- src/shims/posix/fs.rs | 31 ++++++++++-------- src/shims/posix/linux/foreign_items.rs | 15 +++------ src/shims/posix/linux/sync.rs | 40 +++++++++++++---------- tests/run-pass/concurrency/linux-futex.rs | 16 ++++----- 4 files changed, 52 insertions(+), 50 deletions(-) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 288935576e0d..11b9082da64d 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -15,7 +15,6 @@ use rustc_middle::ty::{self, layout::LayoutOf}; use rustc_target::abi::{Align, Size}; use crate::*; -use helpers::check_arg_count; use shims::os_str::os_str_to_bytes; use shims::time::system_time_to_duration; @@ -479,16 +478,16 @@ fn maybe_sync_file( impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn open(&mut self, args: &[OpTy<'tcx, Tag>]) -> InterpResult<'tcx, i32> { - if args.len() < 2 || args.len() > 3 { + if args.len() < 2 { throw_ub_format!( - "incorrect number of arguments for `open`: got {}, expected 2 or 3", + "incorrect number of arguments for `open`: got {}, expected at least 2", args.len() ); } let this = self.eval_context_mut(); - let path_op = &args[0]; + let path = this.read_pointer(&args[0])?; let flag = this.read_scalar(&args[1])?.to_i32()?; let mut options = OpenOptions::new(); @@ -541,7 +540,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.read_scalar(arg)?.to_u32()? } else { throw_ub_format!( - "incorrect number of arguments for `open` with `O_CREAT`: got {}, expected 3", + "incorrect number of arguments for `open` with `O_CREAT`: got {}, expected at least 3", args.len() ); }; @@ -572,7 +571,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("unsupported flags {:#x}", flag & !mirror); } - let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; + let path = this.read_path_from_c_str(path)?; // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { @@ -614,7 +613,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `FD_CLOEXEC` value without checking if the flag is set for the file because `std` // always sets this flag when opening a file. However we still need to check that the // file itself is open. - let &[_, _] = check_arg_count(args)?; if this.machine.file_handler.handles.contains_key(&fd) { Ok(this.eval_libc_i32("FD_CLOEXEC")?) } else { @@ -627,8 +625,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // because exec() isn't supported. The F_DUPFD and F_DUPFD_CLOEXEC commands only // differ in whether the FD_CLOEXEC flag is pre-set on the new file descriptor, // thus they can share the same implementation here. - let &[_, _, ref start] = check_arg_count(args)?; - let start = this.read_scalar(start)?.to_i32()?; + if args.len() < 3 { + throw_ub_format!( + "incorrect number of arguments for fcntl with cmd=`F_DUPFD`/`F_DUPFD_CLOEXEC`: got {}, expected at least 3", + args.len() + ); + } + let start = this.read_scalar(&args[2])?.to_i32()?; let fh = &mut this.machine.file_handler; @@ -646,7 +649,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx None => return this.handle_not_found(), } } else if this.tcx.sess.target.os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC")? { - let &[_, _] = check_arg_count(args)?; if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support fullfsync for all FDs let FileHandle { file, writable } = file_descriptor.as_file_handle()?; @@ -919,15 +921,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dirfd_op: &OpTy<'tcx, Tag>, // Should be an `int` pathname_op: &OpTy<'tcx, Tag>, // Should be a `const char *` flags_op: &OpTy<'tcx, Tag>, // Should be an `int` - _mask_op: &OpTy<'tcx, Tag>, // Should be an `unsigned int` + mask_op: &OpTy<'tcx, Tag>, // Should be an `unsigned int` statxbuf_op: &OpTy<'tcx, Tag>, // Should be a `struct statx *` ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("linux", "statx"); - let statxbuf_ptr = this.read_pointer(statxbuf_op)?; + let dirfd = this.read_scalar(dirfd_op)?.to_i32()?; let pathname_ptr = this.read_pointer(pathname_op)?; + let flags = this.read_scalar(flags_op)?.to_i32()?; + let _mask = this.read_scalar(mask_op)?.to_u32()?; + let statxbuf_ptr = this.read_pointer(statxbuf_op)?; // If the statxbuf or pathname pointers are null, the function fails with `EFAULT`. if this.ptr_is_null(statxbuf_ptr)? || this.ptr_is_null(pathname_ptr)? { @@ -953,9 +958,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let path = this.read_path_from_c_str(pathname_ptr)?.into_owned(); // See for a discussion of argument sizes. - let flags = this.read_scalar(flags_op)?.to_i32()?; let empty_path_flag = flags & this.eval_libc("AT_EMPTY_PATH")?.to_i32()? != 0; - let dirfd = this.read_scalar(dirfd_op)?.to_i32()?; // We only support: // * interpreting `path` as an absolute directory, // * interpreting `path` as a path relative to `dirfd` when the latter is `AT_FDCWD`, or diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 280f24e9ea49..453c77f1b534 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -130,16 +130,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // count is checked bellow. this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?; // The syscall variadic function is legal to call with more arguments than needed, - // extra arguments are simply ignored. However, all arguments need to be scalars; - // other types might be treated differently by the calling convention. - for arg in args { - if !matches!(arg.layout.abi, rustc_target::abi::Abi::Scalar(_)) { - throw_ub_format!( - "`syscall` arguments must all have scalar layout, but {} does not", - arg.layout.ty - ); - } - } + // extra arguments are simply ignored. The important check is that when we use an + // argument, we have to also check all arguments *before* it to ensure that they + // have the right type. let sys_getrandom = this.eval_libc("SYS_getrandom")?.to_machine_usize(this)?; @@ -181,7 +174,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // `futex` is used by some synchonization primitives. id if id == sys_futex => { - futex(this, args, dest)?; + futex(this, &args[1..], dest)?; } id => { this.handle_unsupported(format!("can't execute syscall with ID {}", id))?; diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 9350ad6ba94d..362373bb7d3b 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -4,6 +4,7 @@ use rustc_target::abi::{Align, Size}; use std::time::{Instant, SystemTime}; /// Implementation of the SYS_futex syscall. +/// `args` is the arguments *after* the syscall number. pub fn futex<'tcx>( this: &mut MiriEvalContext<'_, 'tcx>, args: &[OpTy<'tcx, Tag>], @@ -17,9 +18,9 @@ pub fn futex<'tcx>( // may or may not be left out from the `syscall()` call. // Therefore we don't use `check_arg_count` here, but only check for the // number of arguments to fall within a range. - if args.len() < 4 { + if args.len() < 3 { throw_ub_format!( - "incorrect number of arguments for `futex` syscall: got {}, expected at least 4", + "incorrect number of arguments for `futex` syscall: got {}, expected at least 3", args.len() ); } @@ -27,12 +28,13 @@ pub fn futex<'tcx>( // The first three arguments (after the syscall number itself) are the same to all futex operations: // (int *addr, int op, int val). // We checked above that these definitely exist. - let addr = this.read_immediate(&args[1])?; - let op = this.read_scalar(&args[2])?.to_i32()?; - let val = this.read_scalar(&args[3])?.to_i32()?; + let addr = this.read_immediate(&args[0])?; + let op = this.read_scalar(&args[1])?.to_i32()?; + let val = this.read_scalar(&args[2])?.to_i32()?; let thread = this.get_active_thread(); let addr_scalar = addr.to_scalar()?; + let addr_usize = addr_scalar.to_machine_usize(this)?; let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?; let futex_wait = this.eval_libc_i32("FUTEX_WAIT")?; @@ -56,17 +58,19 @@ pub fn futex<'tcx>( let wait_bitset = op & !futex_realtime == futex_wait_bitset; let bitset = if wait_bitset { - if args.len() != 7 { + if args.len() < 6 { throw_ub_format!( - "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT_BITSET`: got {}, expected 7", + "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT_BITSET`: got {}, expected at least 6", args.len() ); } - this.read_scalar(&args[6])?.to_u32()? + let _timeout = this.read_pointer(&args[3])?; + let _uaddr2 = this.read_pointer(&args[4])?; + this.read_scalar(&args[5])?.to_u32()? } else { - if args.len() < 5 { + if args.len() < 4 { throw_ub_format!( - "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT`: got {}, expected at least 5", + "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT`: got {}, expected at least 4", args.len() ); } @@ -81,7 +85,7 @@ pub fn futex<'tcx>( } // `deref_operand` but not actually dereferencing the ptr yet (it might be NULL!). - let timeout = this.ref_to_mplace(&this.read_immediate(&args[4])?)?; + let timeout = this.ref_to_mplace(&this.read_immediate(&args[3])?)?; let timeout_time = if this.ptr_is_null(timeout.ptr)? { None } else { @@ -145,7 +149,7 @@ pub fn futex<'tcx>( if val == futex_val { // The value still matches, so we block the trait make it wait for FUTEX_WAKE. this.block_thread(thread); - this.futex_wait(addr_scalar.to_machine_usize(this)?, thread, bitset); + this.futex_wait(addr_usize, thread, bitset); // Succesfully waking up from FUTEX_WAIT always returns zero. this.write_scalar(Scalar::from_machine_isize(0, this), dest)?; // Register a timeout callback if a timeout was specified. @@ -157,7 +161,7 @@ pub fn futex<'tcx>( timeout_time, Box::new(move |this| { this.unblock_thread(thread); - this.futex_remove_waiter(addr_scalar.to_machine_usize(this)?, thread); + this.futex_remove_waiter(addr_usize, thread); let etimedout = this.eval_libc("ETIMEDOUT")?; this.set_last_error(etimedout)?; this.write_scalar(Scalar::from_machine_isize(-1, this), &dest)?; @@ -181,13 +185,15 @@ pub fn futex<'tcx>( // Same as FUTEX_WAKE, but allows you to specify a bitset to select which threads to wake up. op if op == futex_wake || op == futex_wake_bitset => { let bitset = if op == futex_wake_bitset { - if args.len() != 7 { + if args.len() < 6 { throw_ub_format!( - "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAKE_BITSET`: got {}, expected 7", + "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAKE_BITSET`: got {}, expected at least 6", args.len() ); } - this.read_scalar(&args[6])?.to_u32()? + let _timeout = this.read_pointer(&args[3])?; + let _uaddr2 = this.read_pointer(&args[4])?; + this.read_scalar(&args[5])?.to_u32()? } else { u32::MAX }; @@ -199,7 +205,7 @@ pub fn futex<'tcx>( } let mut n = 0; for _ in 0..val { - if let Some(thread) = this.futex_wake(addr_scalar.to_machine_usize(this)?, bitset) { + if let Some(thread) = this.futex_wake(addr_usize, bitset) { this.unblock_thread(thread); this.unregister_timeout_callback_if_exists(thread); n += 1; diff --git a/tests/run-pass/concurrency/linux-futex.rs b/tests/run-pass/concurrency/linux-futex.rs index fb7c022929bd..4ac928398e23 100644 --- a/tests/run-pass/concurrency/linux-futex.rs +++ b/tests/run-pass/concurrency/linux-futex.rs @@ -32,8 +32,8 @@ fn wake_nobody() { &futex as *const i32, libc::FUTEX_WAKE, 1, - 0, - 0, + ptr::null::(), + 0usize, 0, ), 0); } @@ -121,7 +121,7 @@ fn wait_absolute_timeout() { libc::FUTEX_WAIT_BITSET, 123, &timeout, - 0, + 0usize, u32::MAX, ), -1); assert_eq!(*libc::__errno_location(), libc::ETIMEDOUT); @@ -173,8 +173,8 @@ fn wait_wake_bitset() { &FUTEX as *const i32, libc::FUTEX_WAKE_BITSET, 10, // Wake up at most 10 threads. - 0, - 0, + ptr::null::(), + 0usize, 0b1001, // bitset ), 0); // Didn't match any thread. } @@ -185,8 +185,8 @@ fn wait_wake_bitset() { &FUTEX as *const i32, libc::FUTEX_WAKE_BITSET, 10, // Wake up at most 10 threads. - 0, - 0, + ptr::null::(), + 0usize, 0b0110, // bitset ), 1); // Woken up one thread. } @@ -199,7 +199,7 @@ fn wait_wake_bitset() { libc::FUTEX_WAIT_BITSET, 0, ptr::null::(), - 0, + 0usize, 0b0100, // bitset ), 0); } From cac48dd734434ff3f9a53f78b54eebd9020f2a18 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Apr 2022 16:14:50 -0400 Subject: [PATCH 2982/5092] treat prctl like a variadic function --- src/shims/posix/fs.rs | 2 +- src/shims/posix/linux/foreign_items.rs | 6 ++-- src/shims/posix/thread.rs | 36 +++++++++++++------ .../fs/unix_open_missing_required_mode.rs | 2 +- .../fs/unix_open_too_many_args.rs | 16 --------- 5 files changed, 30 insertions(+), 32 deletions(-) delete mode 100644 tests/compile-fail/fs/unix_open_too_many_args.rs diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 11b9082da64d..5395d0f0bf11 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -921,7 +921,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dirfd_op: &OpTy<'tcx, Tag>, // Should be an `int` pathname_op: &OpTy<'tcx, Tag>, // Should be a `const char *` flags_op: &OpTy<'tcx, Tag>, // Should be an `int` - mask_op: &OpTy<'tcx, Tag>, // Should be an `unsigned int` + mask_op: &OpTy<'tcx, Tag>, // Should be an `unsigned int` statxbuf_op: &OpTy<'tcx, Tag>, // Should be a `struct statx *` ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 453c77f1b534..339fb04dae33 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -106,9 +106,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "prctl" => { - let &[ref option, ref arg2, ref arg3, ref arg4, ref arg5] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let result = this.prctl(option, arg2, arg3, arg4, arg5)?; + // prctl is variadic. (It is not documented like that in the manpage, but defined like that in the libc crate.) + this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?; + let result = this.prctl(args)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_setclock" => { diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index 58d48028f62c..69875a9ffc44 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -97,20 +97,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_uint(thread_id.to_u32(), dest.layout.size), dest) } - fn prctl( - &mut self, - option: &OpTy<'tcx, Tag>, - arg2: &OpTy<'tcx, Tag>, - _arg3: &OpTy<'tcx, Tag>, - _arg4: &OpTy<'tcx, Tag>, - _arg5: &OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, i32> { + fn prctl(&mut self, args: &[OpTy<'tcx, Tag>]) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("linux", "prctl"); - let option = this.read_scalar(option)?.to_i32()?; + if args.len() < 1 { + throw_ub_format!( + "incorrect number of arguments for `prctl`: got {}, expected at least 1", + args.len() + ); + } + + let option = this.read_scalar(&args[0])?.to_i32()?; if option == this.eval_libc_i32("PR_SET_NAME")? { - let address = this.read_pointer(arg2)?; + if args.len() < 2 { + throw_ub_format!( + "incorrect number of arguments for `prctl` with `PR_SET_NAME`: got {}, expected at least 2", + args.len() + ); + } + + let address = this.read_pointer(&args[1])?; let mut name = this.read_c_str(address)?.to_owned(); // The name should be no more than 16 bytes, including the null // byte. Since `read_c_str` returns the string without the null @@ -118,7 +125,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name.truncate(15); this.set_active_thread_name(name); } else if option == this.eval_libc_i32("PR_GET_NAME")? { - let address = this.read_pointer(arg2)?; + if args.len() < 2 { + throw_ub_format!( + "incorrect number of arguments for `prctl` with `PR_SET_NAME`: got {}, expected at least 2", + args.len() + ); + } + + let address = this.read_pointer(&args[1])?; let mut name = this.get_active_thread_name().to_vec(); name.push(0u8); assert!(name.len() <= 16); diff --git a/tests/compile-fail/fs/unix_open_missing_required_mode.rs b/tests/compile-fail/fs/unix_open_missing_required_mode.rs index 2bac72912544..bd2ae6094be1 100644 --- a/tests/compile-fail/fs/unix_open_missing_required_mode.rs +++ b/tests/compile-fail/fs/unix_open_missing_required_mode.rs @@ -12,5 +12,5 @@ fn main() { fn test_file_open_missing_needed_mode() { let name = b"missing_arg.txt\0"; let name_ptr = name.as_ptr().cast::(); - let _fd = unsafe { libc::open(name_ptr, libc::O_CREAT) }; //~ ERROR Undefined Behavior: incorrect number of arguments for `open` with `O_CREAT`: got 2, expected 3 + let _fd = unsafe { libc::open(name_ptr, libc::O_CREAT) }; //~ ERROR Undefined Behavior: incorrect number of arguments for `open` with `O_CREAT`: got 2, expected at least 3 } diff --git a/tests/compile-fail/fs/unix_open_too_many_args.rs b/tests/compile-fail/fs/unix_open_too_many_args.rs deleted file mode 100644 index 9df7415d3133..000000000000 --- a/tests/compile-fail/fs/unix_open_too_many_args.rs +++ /dev/null @@ -1,16 +0,0 @@ -// ignore-windows: No libc on Windows -// compile-flags: -Zmiri-disable-isolation - -#![feature(rustc_private)] - -extern crate libc; - -fn main() { - test_open_too_many_args(); -} - -fn test_open_too_many_args() { - let name = b"too_many_args.txt\0"; - let name_ptr = name.as_ptr().cast::(); - let _fd = unsafe { libc::open(name_ptr, libc::O_RDONLY, 0, 0) }; //~ ERROR Undefined Behavior: incorrect number of arguments for `open`: got 4, expected 2 or 3 -} From c8553d8162709879bd215e8444335f0a58f8b085 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Apr 2022 15:03:57 -0400 Subject: [PATCH 2983/5092] fix Windows stdout/stderr --- src/shims/windows/dlsym.rs | 82 ++++++++++++++++++++++++++++-- src/shims/windows/foreign_items.rs | 60 +++++++--------------- tests/run-pass/vecdeque.rs | 2 +- 3 files changed, 96 insertions(+), 48 deletions(-) diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 325100bdb3a7..ac9e085b5d7c 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -1,10 +1,16 @@ use rustc_middle::mir; +use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; +use log::trace; + +use crate::helpers::check_arg_count; use crate::*; #[derive(Debug, Copy, Clone)] -pub enum Dlsym {} +pub enum Dlsym { + NtWriteFile, +} impl Dlsym { // Returns an error for unsupported symbols, and None if this symbol @@ -12,6 +18,7 @@ impl Dlsym { pub fn from_str(name: &str) -> InterpResult<'static, Option> { Ok(match name { "GetSystemTimePreciseAsFileTime" => None, + "NtWriteFile" => Some(Dlsym::NtWriteFile), _ => throw_unsup_format!("unsupported Windows dlsym: {}", name), }) } @@ -23,15 +30,82 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, dlsym: Dlsym, abi: Abi, - _args: &[OpTy<'tcx, Tag>], + args: &[OpTy<'tcx, Tag>], ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let (_dest, _ret) = ret.expect("we don't support any diverging dlsym"); + let (dest, ret) = ret.expect("we don't support any diverging dlsym"); assert!(this.tcx.sess.target.os == "windows"); this.check_abi(abi, Abi::System { unwind: false })?; - match dlsym {} + match dlsym { + Dlsym::NtWriteFile => { + if !this.frame_in_std() { + throw_unsup_format!( + "NtWriteFile support is crude and just enough for stdout to work" + ); + } + + let &[ + ref handle, + ref _event, + ref _apc_routine, + ref _apc_context, + ref io_status_block, + ref buf, + ref n, + ref byte_offset, + ref _key, + ] = check_arg_count(args)?; + let handle = this.read_scalar(handle)?.to_machine_isize(this)?; + let buf = this.read_pointer(buf)?; + let n = this.read_scalar(n)?.to_u32()?; + let byte_offset = this.read_scalar(byte_offset)?.to_machine_usize(this)?; // is actually a pointer + let io_status_block = this.deref_operand(io_status_block)?; + + if byte_offset != 0 { + throw_unsup_format!( + "NtWriteFile ByteOffset paremeter is non-null, which is unsupported" + ); + } + + let written = if handle == -11 || handle == -12 { + // stdout/stderr + use std::io::{self, Write}; + + let buf_cont = this.read_bytes_ptr(buf, Size::from_bytes(u64::from(n)))?; + let res = if handle == -11 { + io::stdout().write(buf_cont) + } else { + io::stderr().write(buf_cont) + }; + res.ok().map(|n| n as u32) + } else { + throw_unsup_format!( + "on Windows, writing to anything except stdout/stderr is not supported" + ) + }; + // We have to put the result into io_status_block. + if let Some(n) = written { + let io_status_information = + this.mplace_field_named(&io_status_block, "Information")?; + this.write_scalar( + Scalar::from_machine_usize(n.into(), this), + &io_status_information.into(), + )?; + } + // Return whether this was a success. >= 0 is success. + // For the error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR. + this.write_scalar( + Scalar::from_i32(if written.is_some() { 0 } else { 0xC0000185u32 as i32 }), + dest, + )?; + } + } + + trace!("{:?}", this.dump_place(**dest)); + this.go_to_block(ret); + Ok(()) } } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 82ac5c5d75c4..d72302794318 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -23,6 +23,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Windows API stubs. // HANDLE = isize + // NTSTATUS = LONH = i32 // DWORD = ULONG = u32 // BOOL = i32 // BOOLEAN = u8 @@ -64,49 +65,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } - // File related shims - "GetStdHandle" => { - let &[ref which] = - this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - let which = this.read_scalar(which)?.to_i32()?; - // We just make this the identity function, so we know later in `WriteFile` - // which one it is. - this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?; - } - "WriteFile" => { - let &[ref handle, ref buf, ref n, ref written_ptr, ref overlapped] = - this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore - let handle = this.read_scalar(handle)?.to_machine_isize(this)?; - let buf = this.read_pointer(buf)?; - let n = this.read_scalar(n)?.to_u32()?; - let written_place = this.deref_operand(written_ptr)?; - // Spec says to always write `0` first. - this.write_null(&written_place.into())?; - let written = if handle == -11 || handle == -12 { - // stdout/stderr - use std::io::{self, Write}; - - let buf_cont = this.read_bytes_ptr(buf, Size::from_bytes(u64::from(n)))?; - let res = if handle == -11 { - io::stdout().write(buf_cont) - } else { - io::stderr().write(buf_cont) - }; - res.ok().map(|n| n as u32) - } else { - throw_unsup_format!( - "on Windows, writing to anything except stdout/stderr is not supported" - ) - }; - // If there was no error, write back how much was written. - if let Some(n) = written { - this.write_scalar(Scalar::from_u32(n), &written_place.into())?; - } - // Return whether this was a success. - this.write_scalar(Scalar::from_i32(if written.is_some() { 1 } else { 0 }), dest)?; - } - // Allocation "HeapAlloc" => { let &[ref handle, ref flags, ref size] = @@ -333,6 +291,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // value if this call does result in switching to another thread. this.write_null(dest)?; } + "GetStdHandle" => { + let &[ref which] = + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let which = this.read_scalar(which)?.to_i32()?; + // We just make this the identity function, so we know later in `NtWriteFile` which + // one it is. This is very fake, but libtest needs it so we cannot make it a + // std-only shim. + this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?; + } // Better error for attempts to create a thread "CreateThread" => { @@ -350,6 +317,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Just fake a HANDLE this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } + "GetModuleHandleA" if this.frame_in_std() => { + #[allow(non_snake_case)] + let &[_lpModuleName] = + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + // We need to return something non-null here to make `compat_fn!` work. + this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; + } "SetConsoleTextAttribute" if this.frame_in_std() => { #[allow(non_snake_case)] let &[ref _hConsoleOutput, ref _wAttribute] = diff --git a/tests/run-pass/vecdeque.rs b/tests/run-pass/vecdeque.rs index 0cba0165cae1..fa6707632dc7 100644 --- a/tests/run-pass/vecdeque.rs +++ b/tests/run-pass/vecdeque.rs @@ -26,7 +26,7 @@ fn main() { assert_eq!(**a, 2); } - // Regression test for Debug and Diaplay impl's + // Regression test for Debug impl's println!("{:?} {:?}", dst, dst.iter()); println!("{:?}", VecDeque::::new().iter()); From 363f8ab745e4dc1db105a6e7513fb77dd8ad3550 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Apr 2022 16:39:18 -0400 Subject: [PATCH 2984/5092] thread name setting works with strict provenance now :) --- tests/run-pass/concurrency/simple.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/concurrency/simple.rs b/tests/run-pass/concurrency/simple.rs index c659cfbc3fdc..40d8802472ac 100644 --- a/tests/run-pass/concurrency/simple.rs +++ b/tests/run-pass/concurrency/simple.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-check-number-validity +// compile-flags: -Zmiri-strict-provenance use std::thread; From 3a59a15af718339675273b397b822ef1e3f4290b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Apr 2022 08:01:19 -0400 Subject: [PATCH 2985/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index f08a8228d45f..1f717dbd6ed5 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -bbe9d27b8ff36da56638aa43d6d0cdfdf89a4e57 +1a4b9a85634c17a60e8802307510c300a35a4b9b From d2cb11cc152056b6fa682c9925972600c4606d54 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Apr 2022 09:41:29 -0400 Subject: [PATCH 2986/5092] rustup --- rust-version | 2 +- src/operator.rs | 2 +- src/shims/panic.rs | 2 +- src/shims/posix/linux/sync.rs | 2 +- src/shims/tls.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 1f717dbd6ed5..0866489745ac 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1a4b9a85634c17a60e8802307510c300a35a4b9b +fbdb10f9fabe47eb763cb4b52b5721740cc63783 diff --git a/src/operator.rs b/src/operator.rs index 59099469a332..61c72270e9f7 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -61,7 +61,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { let pointee_ty = left.layout.ty.builtin_deref(true).expect("Offset called on non-ptr type").ty; let ptr = self.ptr_offset_inbounds( - self.scalar_to_ptr(left.to_scalar()?), + self.scalar_to_ptr(left.to_scalar()?)?, pointee_ty, right.to_scalar()?.to_machine_isize(self)?, )?; diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 4190cccae6d0..8f4e3f578ee9 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -146,7 +146,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Push the `catch_fn` stackframe. let f_instance = - this.get_ptr_fn(this.scalar_to_ptr(catch_unwind.catch_fn))?.as_instance()?; + this.get_ptr_fn(this.scalar_to_ptr(catch_unwind.catch_fn)?)?.as_instance()?; trace!("catch_fn: {:?}", f_instance); let ret_place = MPlaceTy::dangling(this.machine.layouts.unit).into(); this.call_function( diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 362373bb7d3b..72898baa4b0a 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -121,7 +121,7 @@ pub fn futex<'tcx>( // The API requires `addr` to be a 4-byte aligned pointer, and will // use the 4 bytes at the given address as an (atomic) i32. this.check_ptr_access_align( - this.scalar_to_ptr(addr_scalar), + this.scalar_to_ptr(addr_scalar)?, Size::from_bytes(4), Align::from_bytes(4).unwrap(), CheckInAllocMsg::MemoryAccessTest, diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 297d0c1228a4..ceed123c7ac4 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -249,7 +249,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "p_thread_callback", ])?; let thread_callback = - this.get_ptr_fn(this.scalar_to_ptr(thread_callback))?.as_instance()?; + this.get_ptr_fn(this.scalar_to_ptr(thread_callback)?)?.as_instance()?; // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. let reason = this.eval_path_scalar(&["std", "sys", "windows", "c", "DLL_THREAD_DETACH"])?; From af3f683ba64c4ef3caf9b43a79a8125f2d72b24d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Apr 2022 11:16:50 -0400 Subject: [PATCH 2987/5092] port Miri to edition 2021 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 540eeabebb7a..4956a8dffd49 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ name = "miri" repository = "https://github.com/rust-lang/miri" version = "0.1.0" default-run = "miri" -edition = "2018" +edition = "2021" [lib] test = true # we have unit tests From a57c30118a001678295396852fe044ce7b0031eb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Apr 2022 11:17:16 -0400 Subject: [PATCH 2988/5092] port cargo-miri to edition 2021 --- cargo-miri/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-miri/Cargo.toml b/cargo-miri/Cargo.toml index 7789a8a89594..eb926525305c 100644 --- a/cargo-miri/Cargo.toml +++ b/cargo-miri/Cargo.toml @@ -5,7 +5,7 @@ license = "MIT OR Apache-2.0" name = "cargo-miri" repository = "https://github.com/rust-lang/miri" version = "0.1.0" -edition = "2018" +edition = "2021" [[bin]] name = "cargo-miri" From 855af088b8567bc20805e544b8e38f67b409702a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Apr 2022 11:20:32 -0400 Subject: [PATCH 2989/5092] remove no longer needed imports --- src/bin/miri.rs | 1 - src/eval.rs | 1 - src/helpers.rs | 1 - src/shims/backtrace.rs | 1 - src/shims/env.rs | 1 - src/shims/foreign_items.rs | 6 +----- src/shims/intrinsics.rs | 1 - src/shims/os_str.rs | 1 - src/shims/posix/fs.rs | 1 - src/shims/posix/thread.rs | 2 -- src/shims/time.rs | 1 - src/sync.rs | 1 - src/thread.rs | 1 - src/vector_clock.rs | 2 +- 14 files changed, 2 insertions(+), 19 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index be4776f459cd..727e0b717b11 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -9,7 +9,6 @@ extern crate rustc_metadata; extern crate rustc_middle; extern crate rustc_session; -use std::convert::TryFrom; use std::env; use std::num::NonZeroU64; use std::path::PathBuf; diff --git a/src/eval.rs b/src/eval.rs index 4c006867e177..5f829525cc57 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -1,6 +1,5 @@ //! Main evaluator loop and setting up the initial stack frame. -use std::convert::TryFrom; use std::ffi::OsStr; use std::iter; diff --git a/src/helpers.rs b/src/helpers.rs index 9e4527d592b3..5b6e616400b4 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,4 +1,3 @@ -use std::convert::{TryFrom, TryInto}; use std::mem; use std::num::NonZeroUsize; use std::time::Duration; diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 32fbbffc63f8..2ec4bbb32e02 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -4,7 +4,6 @@ use rustc_middle::ty::layout::LayoutOf as _; use rustc_middle::ty::{self, Instance}; use rustc_span::{BytePos, Loc, Symbol}; use rustc_target::{abi::Size, spec::abi::Abi}; -use std::convert::TryInto as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { diff --git a/src/shims/env.rs b/src/shims/env.rs index 7be26de45916..3b1b1f011e3e 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,4 +1,3 @@ -use std::convert::TryFrom; use std::env; use std::ffi::{OsStr, OsString}; use std::io::ErrorKind; diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 77567e9bcae5..7b457e9ed79a 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -1,8 +1,4 @@ -use std::{ - collections::hash_map::Entry, - convert::{TryFrom, TryInto}, - iter, -}; +use std::{collections::hash_map::Entry, iter}; use log::trace; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 9101cbcf05ff..58e546d6b0b0 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -1,4 +1,3 @@ -use std::convert::TryInto; use std::iter; use log::trace; diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index c03f7ad79be7..8db75fed4a5f 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -1,5 +1,4 @@ use std::borrow::Cow; -use std::convert::TryFrom; use std::ffi::{OsStr, OsString}; use std::iter; use std::path::{Path, PathBuf}; diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 5395d0f0bf11..73e21dd57dc4 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -1,6 +1,5 @@ use std::borrow::Cow; use std::collections::BTreeMap; -use std::convert::{TryFrom, TryInto}; use std::fs::{ read_dir, remove_dir, remove_file, rename, DirBuilder, File, FileType, OpenOptions, ReadDir, }; diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index 69875a9ffc44..7840a1e1e970 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -1,5 +1,3 @@ -use std::convert::TryInto; - use crate::*; use rustc_middle::ty::layout::LayoutOf; use rustc_target::spec::abi::Abi; diff --git a/src/shims/time.rs b/src/shims/time.rs index 0acd697fa405..78bf6f59b349 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -1,4 +1,3 @@ -use std::convert::TryFrom; use std::time::{Duration, Instant, SystemTime}; use crate::*; diff --git a/src/sync.rs b/src/sync.rs index 9007f25ce5c7..bbcd39333c78 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -1,5 +1,4 @@ use std::collections::{hash_map::Entry, HashMap, VecDeque}; -use std::convert::TryFrom; use std::num::NonZeroU32; use std::ops::Not; diff --git a/src/thread.rs b/src/thread.rs index 2c5f6c2391f0..96131dba3ca6 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -2,7 +2,6 @@ use std::cell::RefCell; use std::collections::hash_map::Entry; -use std::convert::TryFrom; use std::num::TryFromIntError; use std::time::{Duration, Instant, SystemTime}; diff --git a/src/vector_clock.rs b/src/vector_clock.rs index 74180f25b3bb..e13e9c39fc69 100644 --- a/src/vector_clock.rs +++ b/src/vector_clock.rs @@ -1,6 +1,6 @@ use rustc_index::vec::Idx; use smallvec::SmallVec; -use std::{cmp::Ordering, convert::TryFrom, fmt::Debug, ops::Index}; +use std::{cmp::Ordering, fmt::Debug, ops::Index}; /// A vector clock index, this is associated with a thread id /// but in some cases one vector index may be shared with From 507c09f45f0e32b7868b2bf38a3a046d93311e38 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Apr 2022 11:22:18 -0400 Subject: [PATCH 2990/5092] use new format string syntax in some places --- src/diagnostics.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index e1a2e3184ebf..ce66dea5e746 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -414,11 +414,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) } }, - CreatedCallId(id) => format!("function call with id {}", id), - CreatedAlloc(AllocId(id)) => format!("created allocation with id {}", id), - FreedAlloc(AllocId(id)) => format!("freed allocation with id {}", id), + CreatedCallId(id) => format!("function call with id {id}"), + CreatedAlloc(AllocId(id)) => format!("created allocation with id {id}"), + FreedAlloc(AllocId(id)) => format!("freed allocation with id {id}"), RejectedIsolatedOp(ref op) => - format!("{} was made to return an error due to isolation", op), + format!("{op} was made to return an error due to isolation"), }; let (title, diag_level) = match e { From ebb70da4c66dba4a0e036377b3cc19cc41f92e9a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 Apr 2022 09:36:30 -0400 Subject: [PATCH 2991/5092] rustup --- rust-version | 2 +- tests/run-pass/concurrency/channels.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 0866489745ac..34bc4a803878 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -fbdb10f9fabe47eb763cb4b52b5721740cc63783 +7af93292c27cd8b4a14f0f35bcb4c7e7ca9c287a diff --git a/tests/run-pass/concurrency/channels.rs b/tests/run-pass/concurrency/channels.rs index 7d28cd726d0e..b0c095b2d359 100644 --- a/tests/run-pass/concurrency/channels.rs +++ b/tests/run-pass/concurrency/channels.rs @@ -1,4 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-strict-provenance use std::sync::mpsc::{channel, sync_channel}; use std::thread; From 3f1d3aedcdddd26a07d436e8db870f868075b55a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 Apr 2022 11:23:56 -0400 Subject: [PATCH 2992/5092] increase slack for timeout test --- tests/run-pass/concurrency/sync.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index 5e43fea96864..303d49e3c33f 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -91,7 +91,7 @@ fn check_conditional_variables_timed_wait_timeout() { let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap(); assert!(timeout.timed_out()); let elapsed_time = now.elapsed().as_millis(); - assert!(100 <= elapsed_time && elapsed_time <= 500); + assert!(100 <= elapsed_time && elapsed_time <= 800); } /// Test that signaling a conditional variable when waiting with a timeout works From c08f460beb86b60aab150f258d96bf99c6eae1b8 Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Fri, 15 Apr 2022 16:21:21 -0400 Subject: [PATCH 2993/5092] tidy --- src/test/ui/modules/dummy.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/ui/modules/dummy.rs b/src/test/ui/modules/dummy.rs index e69de29bb2d1..831e38292a9b 100644 --- a/src/test/ui/modules/dummy.rs +++ b/src/test/ui/modules/dummy.rs @@ -0,0 +1 @@ +pub struct Dummy; From 0669b227596969c1c2f6b6315d1d05e1f4c6a60d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 16 Apr 2022 08:41:34 -0400 Subject: [PATCH 2994/5092] rustup --- rust-version | 2 +- src/shims/intrinsics.rs | 21 +++++++++++++++++---- tests/run-pass/portable-simd.rs | 1 + 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 34bc4a803878..d476da0baaf8 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7af93292c27cd8b4a14f0f35bcb4c7e7ca9c287a +c8422403f775126c40d558838d321c063554c822 diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 58e546d6b0b0..1b69be5153b0 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -437,7 +437,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "simd_fmax" | "simd_fmin" | "simd_saturating_add" - | "simd_saturating_sub" => { + | "simd_saturating_sub" + | "simd_arith_offset" => { use mir::BinOp; let &[ref left, ref right] = check_arg_count(args)?; @@ -453,6 +454,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx SaturatingOp(BinOp), FMax, FMin, + WrappingOffset, } let which = match intrinsic_name { "simd_add" => Op::MirOp(BinOp::Add), @@ -475,6 +477,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "simd_fmin" => Op::FMin, "simd_saturating_add" => Op::SaturatingOp(BinOp::Add), "simd_saturating_sub" => Op::SaturatingOp(BinOp::Sub), + "simd_arith_offset" => Op::WrappingOffset, _ => unreachable!(), }; @@ -504,15 +507,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx val } } + Op::SaturatingOp(mir_op) => { + this.saturating_arith(mir_op, &left, &right)? + } + Op::WrappingOffset => { + let ptr = this.scalar_to_ptr(left.to_scalar()?)?; + let offset_count = right.to_scalar()?.to_machine_isize(this)?; + let pointee_ty = left.layout.ty.builtin_deref(true).unwrap().ty; + + let pointee_size = i64::try_from(this.layout_of(pointee_ty)?.size.bytes()).unwrap(); + let offset_bytes = offset_count.wrapping_mul(pointee_size); + let offset_ptr = ptr.wrapping_signed_offset(offset_bytes, this); + Scalar::from_maybe_pointer(offset_ptr, this) + } Op::FMax => { fmax_op(&left, &right)? } Op::FMin => { fmin_op(&left, &right)? } - Op::SaturatingOp(mir_op) => { - this.saturating_arith(mir_op, &left, &right)? - } }; this.write_scalar(val, &dest.into())?; } diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 99a64ea370f6..3e43595c94ae 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-strict-provenance #![feature(portable_simd, platform_intrinsics)] use std::simd::*; From efe871f20850b89f5ff18a7fa6a4fabdc6ae2887 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 16 Apr 2022 09:13:40 -0400 Subject: [PATCH 2995/5092] readme --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d394eb3cfbe9..0a507016e571 100644 --- a/README.md +++ b/README.md @@ -57,8 +57,11 @@ in your program, and cannot run all programs: executions. * Miri runs the program as a platform-independent interpreter, so the program has no access to most platform-specific APIs or FFI. A few APIs have been - implemented (such as printing to stdout) but most have not: for example, Miri - currently does not support SIMD or networking. + implemented (such as printing to stdout, accessing environment variables, and + basic file system access) but most have not: for example, Miri currently does + not support networking. System API support varies between targets; if you run + on Windows it is a good idea to use `--target x86_64-unknown-linux-gnu` to get + better support. * Threading support is not finished yet. E.g., weak memory effects are not emulated and spin loops (without syscalls) just loop forever. There is no threading support on Windows. From db2c4b6dfa765582d8f184ec09ee17643e183725 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 16 Apr 2022 22:50:46 -0400 Subject: [PATCH 2996/5092] implement strerror_r --- src/helpers.rs | 95 ++++++++++++++++++++------------ src/shims/posix/foreign_items.rs | 14 +++++ tests/run-pass/fs.rs | 2 + 3 files changed, 77 insertions(+), 34 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 5b6e616400b4..b052463bb022 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -21,6 +21,27 @@ use crate::*; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +const UNIX_IO_ERROR_TABLE: &[(std::io::ErrorKind, &str)] = { + use std::io::ErrorKind::*; + &[ + (ConnectionRefused, "ECONNREFUSED"), + (ConnectionReset, "ECONNRESET"), + (PermissionDenied, "EPERM"), + (BrokenPipe, "EPIPE"), + (NotConnected, "ENOTCONN"), + (ConnectionAborted, "ECONNABORTED"), + (AddrNotAvailable, "EADDRNOTAVAIL"), + (AddrInUse, "EADDRINUSE"), + (NotFound, "ENOENT"), + (Interrupted, "EINTR"), + (InvalidInput, "EINVAL"), + (TimedOut, "ETIMEDOUT"), + (AlreadyExists, "EEXIST"), + (WouldBlock, "EWOULDBLOCK"), + (DirectoryNotEmpty, "ENOTEMPTY"), + ] +}; + /// Gets an instance for a path. fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option { tcx.crates(()).iter().find(|&&krate| tcx.crate_name(krate).as_str() == path[0]).and_then( @@ -502,39 +523,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.read_scalar(&errno_place.into())?.check_init() } - /// Sets the last OS error using a `std::io::ErrorKind`. This function tries to produce the most - /// similar OS error from the `std::io::ErrorKind` and sets it as the last OS error. - fn set_last_error_from_io_error(&mut self, err_kind: std::io::ErrorKind) -> InterpResult<'tcx> { - use std::io::ErrorKind::*; - let this = self.eval_context_mut(); + /// This function tries to produce the most similar OS error from the `std::io::ErrorKind` + /// as a platform-specific errnum. + fn io_error_to_errnum(&self, err_kind: std::io::ErrorKind) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_ref(); let target = &this.tcx.sess.target; - let target_os = &target.os; - let last_error = if target.families.iter().any(|f| f == "unix") { - this.eval_libc(match err_kind { - ConnectionRefused => "ECONNREFUSED", - ConnectionReset => "ECONNRESET", - PermissionDenied => "EPERM", - BrokenPipe => "EPIPE", - NotConnected => "ENOTCONN", - ConnectionAborted => "ECONNABORTED", - AddrNotAvailable => "EADDRNOTAVAIL", - AddrInUse => "EADDRINUSE", - NotFound => "ENOENT", - Interrupted => "EINTR", - InvalidInput => "EINVAL", - TimedOut => "ETIMEDOUT", - AlreadyExists => "EEXIST", - WouldBlock => "EWOULDBLOCK", - DirectoryNotEmpty => "ENOTEMPTY", - _ => { - throw_unsup_format!( - "io error {:?} cannot be translated into a raw os error", - err_kind - ) + if target.families.iter().any(|f| f == "unix") { + for &(kind, name) in UNIX_IO_ERROR_TABLE { + if err_kind == kind { + return this.eval_libc(name); } - })? + } + throw_unsup_format!("io error {:?} cannot be translated into a raw os error", err_kind) } else if target.families.iter().any(|f| f == "windows") { // FIXME: we have to finish implementing the Windows equivalent of this. + use std::io::ErrorKind::*; this.eval_windows( "c", match err_kind { @@ -546,14 +549,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx err_kind ), }, - )? + ) } else { throw_unsup_format!( - "setting the last OS error from an io::Error is unsupported for {}.", - target_os + "converting io::Error into errnum is unsupported for OS {}", + target.os ) - }; - this.set_last_error(last_error) + } + } + + /// The inverse of `io_error_to_errnum`. + fn errnum_to_io_error(&self, errnum: Scalar) -> InterpResult<'tcx, std::io::ErrorKind> { + let this = self.eval_context_ref(); + let target = &this.tcx.sess.target; + if target.families.iter().any(|f| f == "unix") { + let errnum = errnum.to_i32()?; + for &(kind, name) in UNIX_IO_ERROR_TABLE { + if errnum == this.eval_libc_i32(name)? { + return Ok(kind); + } + } + throw_unsup_format!("raw errnum {:?} cannot be translated into io::Error", errnum) + } else { + throw_unsup_format!( + "converting errnum into io::Error is unsupported for OS {}", + target.os + ) + } + } + + /// Sets the last OS error using a `std::io::ErrorKind`. + fn set_last_error_from_io_error(&mut self, err_kind: std::io::ErrorKind) -> InterpResult<'tcx> { + self.set_last_error(self.io_error_to_errnum(err_kind)?) } /// Helper function that consumes an `std::io::Result` and returns an diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 4bf0bbc26212..16619d4aeb77 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -1,3 +1,5 @@ +use std::ffi::OsStr; + use log::trace; use rustc_middle::mir; @@ -421,6 +423,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We do not support forking, so there is nothing to do here. this.write_null(dest)?; } + "strerror_r" | "__xpg_strerror_r" => { + let &[ref errnum, ref buf, ref buflen] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let errnum = this.read_scalar(errnum)?.check_init()?; + let buf = this.read_pointer(buf)?; + let buflen = this.read_scalar(buflen)?.to_machine_usize(this)?; + + let error = this.errnum_to_io_error(errnum)?; + let formatted = error.to_string(); + let (complete, _) = this.write_os_str_to_c_str(OsStr::new(&formatted), buf, buflen)?; + let ret = if complete { 0 } else { this.eval_libc_i32("ERANGE")? }; + this.write_int(ret, dest)?; + } // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 67817e3e2c85..bc78cb560f00 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -335,6 +335,8 @@ fn test_errors() { // The following tests also check that the `__errno_location()` shim is working properly. // Opening a non-existing file should fail with a "not found" error. assert_eq!(ErrorKind::NotFound, File::open(&path).unwrap_err().kind()); + // Make sure we can also format this. + format!("{0:?}: {0}", File::open(&path).unwrap_err()); // Removing a non-existing file should fail with a "not found" error. assert_eq!(ErrorKind::NotFound, remove_file(&path).unwrap_err().kind()); // Reading the metadata of a non-existing file should fail with a "not found" error. From 5a3ec3780ea1345dc2745ce9935c92fdd43402db Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Apr 2022 21:46:42 -0400 Subject: [PATCH 2997/5092] add size assertions for some core types --- src/machine.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/machine.rs b/src/machine.rs index 9e0cb69f28d8..532aeeece07e 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -12,6 +12,8 @@ use rand::SeedableRng; use rustc_ast::ast::Mutability; use rustc_data_structures::fx::FxHashMap; +#[allow(unused)] +use rustc_data_structures::static_assert_size; use rustc_middle::{ mir, ty::{ @@ -128,6 +130,13 @@ pub struct Tag { pub sb: SbTag, } +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +static_assert_size!(Pointer, 24); +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +static_assert_size!(Pointer>, 24); +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +static_assert_size!(ScalarMaybeUninit, 32); + impl Provenance for Tag { /// We use absolute addresses in the `offset` of a `Pointer`. const OFFSET_IS_ADDR: bool = true; From 763ff1c49fd6671d64709fe269c2d3a130dce4a6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Apr 2022 14:56:07 -0400 Subject: [PATCH 2998/5092] do not consider thread-local allocations read-only --- src/thread.rs | 7 +++++-- tests/run-pass/concurrency/thread_locals.rs | 6 ++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/thread.rs b/src/thread.rs index 96131dba3ca6..27bc9566d8fd 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -10,6 +10,7 @@ use log::trace; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; use rustc_index::vec::{Idx, IndexVec}; +use rustc_middle::mir::Mutability; use crate::sync::SynchronizationState; use crate::*; @@ -571,9 +572,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("foreign thread-local statics are not supported"); } let allocation = tcx.eval_static_initializer(def_id)?; + let mut allocation = allocation.inner().clone(); + // This allocation will be deallocated when the thread dies, so it is not in read-only memory. + allocation.mutability = Mutability::Mut; // Create a fresh allocation with this content. - let new_alloc = - this.allocate_raw_ptr(allocation.inner().clone(), MiriMemoryKind::Tls.into()); + let new_alloc = this.allocate_raw_ptr(allocation, MiriMemoryKind::Tls.into()); this.machine.threads.set_thread_local_alloc(def_id, new_alloc); Ok(new_alloc) } diff --git a/tests/run-pass/concurrency/thread_locals.rs b/tests/run-pass/concurrency/thread_locals.rs index 7938284bd634..5b11539f7f11 100644 --- a/tests/run-pass/concurrency/thread_locals.rs +++ b/tests/run-pass/concurrency/thread_locals.rs @@ -16,6 +16,10 @@ static mut A: u8 = 0; static mut B: u8 = 0; static mut C: u8 = 0; +// Regression test for https://github.com/rust-lang/rust/issues/96191. +#[thread_local] +static READ_ONLY: u8 = 42; + unsafe fn get_a_ref() -> *mut u8 { &mut A } @@ -25,6 +29,8 @@ struct Sender(*mut u8); unsafe impl Send for Sender {} fn main() { + let _val = READ_ONLY; + let ptr = unsafe { let x = get_a_ref(); *x = 5; From ec1dc749a344522b080ec8162b9fd24fce0c507e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Apr 2022 10:20:11 -0400 Subject: [PATCH 2999/5092] adjust for provenance cleanup --- src/data_race.rs | 6 +++--- src/machine.rs | 36 +++++++++++++++++++----------------- src/shims/backtrace.rs | 2 +- src/stacked_borrows.rs | 3 +-- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index 4a79d9e99047..7625763a3bb4 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -999,7 +999,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { if let Some(data_race) = &this.machine.data_race { if data_race.multi_threaded.get() { let size = place.layout.size; - let (alloc_id, base_offset, ptr) = this.ptr_get_alloc_id(place.ptr)?; + let (alloc_id, base_offset, _tag) = this.ptr_get_alloc_id(place.ptr)?; // Load and log the atomic operation. // Note that atomic loads are possible even from read-only allocations, so `get_alloc_extra_mut` is not an option. let alloc_meta = &this.get_alloc_extra(alloc_id)?.data_race.as_ref().unwrap(); @@ -1007,7 +1007,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { "Atomic op({}) with ordering {:?} on {:?} (size={})", description, &atomic, - ptr, + place.ptr, size.bytes() ); @@ -1039,7 +1039,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { { log::trace!( "Updated atomic memory({:?}, size={}) to {:#?}", - ptr, + place.ptr, size.bytes(), range.atomic_ops ); diff --git a/src/machine.rs b/src/machine.rs index 532aeeece07e..df53d90b05c5 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -431,11 +431,13 @@ impl<'mir, 'tcx> MiriEvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> /// Machine hook implementations. impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { type MemoryKind = MiriMemoryKind; + type ExtraFnVal = Dlsym; type FrameExtra = FrameData<'tcx>; type AllocExtra = AllocExtra; + type PointerTag = Tag; - type ExtraFnVal = Dlsym; + type TagExtra = SbTag; type MemoryMap = MonoHashMap, Allocation)>; @@ -607,9 +609,9 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn ptr_get_alloc( ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer, - ) -> (AllocId, Size) { + ) -> (AllocId, Size, Self::TagExtra) { let rel = intptrcast::GlobalStateInner::abs_ptr_to_rel(ecx, ptr); - (ptr.provenance.alloc_id, rel) + (ptr.provenance.alloc_id, rel, ptr.provenance.sb) } #[inline(always)] @@ -617,16 +619,16 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { _tcx: TyCtxt<'tcx>, machine: &Self, alloc_extra: &AllocExtra, - tag: Tag, + (alloc_id, tag): (AllocId, Self::TagExtra), range: AllocRange, ) -> InterpResult<'tcx> { if let Some(data_race) = &alloc_extra.data_race { - data_race.read(tag.alloc_id, range, machine.data_race.as_ref().unwrap())?; + data_race.read(alloc_id, range, machine.data_race.as_ref().unwrap())?; } if let Some(stacked_borrows) = &alloc_extra.stacked_borrows { stacked_borrows.memory_read( - tag.alloc_id, - tag.sb, + alloc_id, + tag, range, machine.stacked_borrows.as_ref().unwrap(), ) @@ -640,16 +642,16 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { _tcx: TyCtxt<'tcx>, machine: &mut Self, alloc_extra: &mut AllocExtra, - tag: Tag, + (alloc_id, tag): (AllocId, Self::TagExtra), range: AllocRange, ) -> InterpResult<'tcx> { if let Some(data_race) = &mut alloc_extra.data_race { - data_race.write(tag.alloc_id, range, machine.data_race.as_mut().unwrap())?; + data_race.write(alloc_id, range, machine.data_race.as_mut().unwrap())?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { stacked_borrows.memory_written( - tag.alloc_id, - tag.sb, + alloc_id, + tag, range, machine.stacked_borrows.as_mut().unwrap(), ) @@ -663,19 +665,19 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { _tcx: TyCtxt<'tcx>, machine: &mut Self, alloc_extra: &mut AllocExtra, - tag: Tag, + (alloc_id, tag): (AllocId, Self::TagExtra), range: AllocRange, ) -> InterpResult<'tcx> { - if Some(tag.alloc_id) == machine.tracked_alloc_id { - register_diagnostic(NonHaltingDiagnostic::FreedAlloc(tag.alloc_id)); + if Some(alloc_id) == machine.tracked_alloc_id { + register_diagnostic(NonHaltingDiagnostic::FreedAlloc(alloc_id)); } if let Some(data_race) = &mut alloc_extra.data_race { - data_race.deallocate(tag.alloc_id, range, machine.data_race.as_mut().unwrap())?; + data_race.deallocate(alloc_id, range, machine.data_race.as_mut().unwrap())?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { stacked_borrows.memory_deallocated( - tag.alloc_id, - tag.sb, + alloc_id, + tag, range, machine.stacked_borrows.as_mut().unwrap(), ) diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 2ec4bbb32e02..3ada61abbd29 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -124,7 +124,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.read_pointer(ptr)?; // Take apart the pointer, we need its pieces. - let (alloc_id, offset, ptr) = this.ptr_get_alloc_id(ptr)?; + let (alloc_id, offset, _tag) = this.ptr_get_alloc_id(ptr)?; let fn_instance = if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(alloc_id) { diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index a365d909981b..0029de3b5a9c 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -702,8 +702,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); return Ok(()); } - let (alloc_id, base_offset, ptr) = this.ptr_get_alloc_id(place.ptr)?; - let orig_tag = ptr.provenance.sb; + let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?; // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). let (alloc_size, _) = From f1023fbdc9aafc8c78c7a6967d0dc4daa741c2a1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Apr 2022 12:38:26 -0400 Subject: [PATCH 3000/5092] avoid into_pointer_or_addr and into_parts in visit_freeze_sensitive --- src/helpers.rs | 34 ++++++++++++++-------------------- src/intptrcast.rs | 4 ++-- src/machine.rs | 1 + src/shims/mod.rs | 5 ++--- 4 files changed, 19 insertions(+), 25 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index b052463bb022..9d387b065938 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -271,8 +271,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Visits the memory covered by `place`, sensitive to freezing: the 2nd parameter /// of `action` will be true if this is frozen, false if this is in an `UnsafeCell`. /// The range is relative to `place`. - /// - /// Assumes that the `place` has a proper pointer in it. fn visit_freeze_sensitive( &self, place: &MPlaceTy<'tcx, Tag>, @@ -290,33 +288,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Store how far we proceeded into the place so far. Everything to the left of // this offset has already been handled, in the sense that the frozen parts // have had `action` called on them. - let ptr = place.ptr.into_pointer_or_addr().unwrap(); - let start_offset = ptr.into_parts().1 as Size; // we just compare offsets, the abs. value never matters - let mut cur_offset = start_offset; + let start_addr = place.ptr.addr(); + let mut cur_addr = start_addr; // Called when we detected an `UnsafeCell` at the given offset and size. // Calls `action` and advances `cur_ptr`. - let mut unsafe_cell_action = |unsafe_cell_ptr: Pointer>, + let mut unsafe_cell_action = |unsafe_cell_ptr: &Pointer>, unsafe_cell_size: Size| { - let unsafe_cell_ptr = unsafe_cell_ptr.into_pointer_or_addr().unwrap(); - debug_assert_eq!(unsafe_cell_ptr.provenance, ptr.provenance); // We assume that we are given the fields in increasing offset order, // and nothing else changes. - let unsafe_cell_offset = unsafe_cell_ptr.into_parts().1 as Size; // we just compare offsets, the abs. value never matters - assert!(unsafe_cell_offset >= cur_offset); - let frozen_size = unsafe_cell_offset - cur_offset; + let unsafe_cell_addr = unsafe_cell_ptr.addr(); + assert!(unsafe_cell_addr >= cur_addr); + let frozen_size = unsafe_cell_addr - cur_addr; // Everything between the cur_ptr and this `UnsafeCell` is frozen. if frozen_size != Size::ZERO { - action(alloc_range(cur_offset - start_offset, frozen_size), /*frozen*/ true)?; + action(alloc_range(cur_addr - start_addr, frozen_size), /*frozen*/ true)?; } - cur_offset += frozen_size; + cur_addr += frozen_size; // This `UnsafeCell` is NOT frozen. if unsafe_cell_size != Size::ZERO { action( - alloc_range(cur_offset - start_offset, unsafe_cell_size), + alloc_range(cur_addr - start_addr, unsafe_cell_size), /*frozen*/ false, )?; } - cur_offset += unsafe_cell_size; + cur_addr += unsafe_cell_size; // Done Ok(()) }; @@ -334,7 +329,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .unwrap_or_else(|| place.layout.size); // Now handle this `UnsafeCell`, unless it is empty. if unsafe_cell_size != Size::ZERO { - unsafe_cell_action(place.ptr, unsafe_cell_size) + unsafe_cell_action(&place.ptr, unsafe_cell_size) } else { Ok(()) } @@ -344,7 +339,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // The part between the end_ptr and the end of the place is also frozen. // So pretend there is a 0-sized `UnsafeCell` at the end. - unsafe_cell_action(place.ptr.wrapping_offset(size, this), Size::ZERO)?; + unsafe_cell_action(&place.ptr.offset(size, this)?, Size::ZERO)?; // Done! return Ok(()); @@ -428,9 +423,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut places = fields.collect::>>>()?; // we just compare offsets, the abs. value never matters - places.sort_by_key(|place| { - place.ptr.into_pointer_or_addr().unwrap().into_parts().1 as Size - }); + places.sort_by_key(|place| place.ptr.addr()); self.walk_aggregate(place, places.into_iter().map(Ok)) } FieldsShape::Union { .. } | FieldsShape::Primitive => { @@ -777,6 +770,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Mark a machine allocation that was just created as immutable. fn mark_immutable(&mut self, mplace: &MemPlace) { let this = self.eval_context_mut(); + // This got just allocated, so there definitely is a pointer here. this.alloc_mark_immutable(mplace.ptr.into_pointer_or_addr().unwrap().provenance.alloc_id) .unwrap(); } diff --git a/src/intptrcast.rs b/src/intptrcast.rs index b1c96c7f1e7c..895241bcc326 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -128,7 +128,7 @@ impl<'mir, 'tcx> GlobalStateInner { /// Convert a relative (tcx) pointer to an absolute address. pub fn rel_ptr_to_addr(ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer) -> u64 { - let (alloc_id, offset) = ptr.into_parts(); // offset is relative + let (alloc_id, offset) = ptr.into_parts(); // offset is relative (AllocId provenance) let base_addr = GlobalStateInner::alloc_base_addr(ecx, alloc_id); // Add offset with the right kind of pointer-overflowing arithmetic. @@ -137,7 +137,7 @@ impl<'mir, 'tcx> GlobalStateInner { } pub fn abs_ptr_to_rel(ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer) -> Size { - let (tag, addr) = ptr.into_parts(); // addr is absolute + let (tag, addr) = ptr.into_parts(); // addr is absolute (Tag provenance) let base_addr = GlobalStateInner::alloc_base_addr(ecx, tag.alloc_id); // Wrapping "addr - base_addr" diff --git a/src/machine.rs b/src/machine.rs index df53d90b05c5..66854921a33e 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -360,6 +360,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { name: &str, ptr: Pointer>, ) { + // This got just allocated, so there definitely is a pointer here. let ptr = ptr.into_pointer_or_addr().unwrap(); this.machine.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap(); } diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 83bc6b6ae1ba..af6064925f04 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -83,10 +83,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let ptr = this.read_pointer(ptr_op)?; - if let Ok(ptr) = ptr.into_pointer_or_addr() { + if let Ok((alloc_id, _offset, _)) = this.ptr_try_get_alloc_id(ptr) { // Only do anything if we can identify the allocation this goes to. - let (_, cur_align) = - this.get_alloc_size_and_align(ptr.provenance.alloc_id, AllocCheck::MaybeDead)?; + let (_, cur_align) = this.get_alloc_size_and_align(alloc_id, AllocCheck::MaybeDead)?; if cur_align.bytes() >= req_align { // If the allocation alignment is at least the required alignment we use the // real implementation. From dd968a89bf13a739655cc8a379976bd93dc9bc58 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Apr 2022 08:44:06 -0400 Subject: [PATCH 3001/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index d476da0baaf8..fa9ce8aca882 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c8422403f775126c40d558838d321c063554c822 +27af5175497936ea3413bef5816e7c0172514b9c From b5a76c7ff075b96415d5941c95854b217e294d9d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Apr 2022 08:44:10 -0400 Subject: [PATCH 3002/5092] add test for https://github.com/rust-lang/miri/issues/2068 --- tests/run-pass/issue-miri-2068.rs | 48 +++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 tests/run-pass/issue-miri-2068.rs diff --git a/tests/run-pass/issue-miri-2068.rs b/tests/run-pass/issue-miri-2068.rs new file mode 100644 index 000000000000..7576ba78f607 --- /dev/null +++ b/tests/run-pass/issue-miri-2068.rs @@ -0,0 +1,48 @@ +#![feature(pin_macro)] + +use core::future::Future; +use core::pin::Pin; +use core::task::{Context, Poll}; + +use std::sync::Arc; + +struct NopWaker; + +impl std::task::Wake for NopWaker { + fn wake(self: Arc) {} +} + +pub fn fuzzing_block_on>(fut: F) -> O { + let mut fut = std::pin::pin!(fut); + let waker = std::task::Waker::from(Arc::new(NopWaker)); + let mut context = std::task::Context::from_waker(&waker); + loop { + match fut.as_mut().poll(&mut context) { + Poll::Ready(v) => return v, + Poll::Pending => {} + } + } +} + +pub struct LastFuture { + last: S, +} + +impl Future for LastFuture +where + Self: Unpin, + S: Unpin + Copy, +{ + type Output = S; + + fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { + return Poll::Ready(self.last); + } +} + +fn main() { + fuzzing_block_on(async { + LastFuture { last: &0u32 }.await; + LastFuture { last: Option::::None }.await; + }); +} From d4a85f6305a41df2118f15cd77953cea366dea1b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Apr 2022 10:39:17 -0400 Subject: [PATCH 3003/5092] add another test for #2068 --- tests/run-pass/issue-miri-2068-2.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 tests/run-pass/issue-miri-2068-2.rs diff --git a/tests/run-pass/issue-miri-2068-2.rs b/tests/run-pass/issue-miri-2068-2.rs new file mode 100644 index 000000000000..45b2004e3353 --- /dev/null +++ b/tests/run-pass/issue-miri-2068-2.rs @@ -0,0 +1,14 @@ +// compile-flags: -Zmiri-disable-validation + +use std::mem::MaybeUninit; + +fn main() { unsafe { + let mut x = MaybeUninit::::uninit(); + // Put in a ptr. + x.as_mut_ptr().cast::<&i32>().write_unaligned(&0); + // Overwrite parts of that pointer with 'uninit' through a Scalar. + let ptr = x.as_mut_ptr().cast::(); + *ptr = MaybeUninit::uninit().assume_init(); + // Reading this back should hence work fine. + let _c = *ptr; +} } From e214e6db98badf837e95db89d7a9905294569cd6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Apr 2022 10:47:22 -0400 Subject: [PATCH 3004/5092] add mut_below_shr test --- tests/run-pass/stacked-borrows/stacked-borrows.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index 8aea945f9093..b63f9addb0f6 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -16,6 +16,7 @@ fn main() { disjoint_mutable_subborrows(); raw_ref_to_part(); array_casts(); + mut_below_shr(); } // Make sure that reading from an `&mut` does, like reborrowing to `&`, @@ -186,3 +187,12 @@ fn array_casts() { let p = &x as *const usize; assert_eq!(unsafe { *p.add(1) }, 1); } + +/// Transmuting &&i32 to &&mut i32 is fine. +fn mut_below_shr() { + let x = 0; + let y = &x; + let p = unsafe { core::mem::transmute::<&&i32,&&mut i32>(&y) }; + let r = &**p; + let _val = *r; +} From 432015d1f64d3a8065464c29e5af7396fc666c94 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Apr 2022 17:41:09 -0400 Subject: [PATCH 3005/5092] rustup --- rust-version | 2 +- tests/compile-fail/never_transmute_void.rs | 15 +++++++++------ tests/run-pass/async-fn.rs | 2 +- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/rust-version b/rust-version index fa9ce8aca882..7cc913cf8679 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -27af5175497936ea3413bef5816e7c0172514b9c +51ea9bb29b07d76c5a7167d054b54f4eb7f5b44e diff --git a/tests/compile-fail/never_transmute_void.rs b/tests/compile-fail/never_transmute_void.rs index 5e9e2ac204ea..e5aa04dfec1a 100644 --- a/tests/compile-fail/never_transmute_void.rs +++ b/tests/compile-fail/never_transmute_void.rs @@ -4,15 +4,18 @@ #![feature(never_type)] #![allow(unused, invalid_value)] -enum Void {} +mod m { + enum VoidI {} + pub struct Void(VoidI); -fn f(v: Void) -> ! { - match v {} //~ ERROR entering unreachable code + pub fn f(v: Void) -> ! { + match v.0 {} //~ ERROR entering unreachable code + } } fn main() { - let v: Void = unsafe { - std::mem::transmute::<(), Void>(()) + let v = unsafe { + std::mem::transmute::<(), m::Void>(()) }; - f(v); //~ inside `main` + m::f(v); //~ inside `main` } diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 1602b5638e90..1d5d9a27cc8a 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -29,7 +29,7 @@ fn never() -> Never { } async fn includes_never(crash: bool, x: u32) -> u32 { - let mut result = async { x * x }.await; + let result = async { x * x }.await; if !crash { return result; } From bf17dbebc9ee9bbc2b5e38f92ccc1a8b51bfa167 Mon Sep 17 00:00:00 2001 From: y86-dev <94611769+y86-dev@users.noreply.github.com> Date: Wed, 20 Apr 2022 11:10:59 +0200 Subject: [PATCH 3006/5092] Added support for multiple tracked pointers, allocs and calls - Changed arg parsing to handle comma seperated list of `u64`'s. - Changed type and field names of config, executor and global state to hold a set of tracked ids. - Adjusted Readme: - explained list format - arguments do not overwrite, instead append - no effect on duplication - Created a parsing function for comma separated lists - Added error printing to alloc_id parsing --- README.md | 14 +++++--- src/bin/miri.rs | 78 +++++++++++++++++++++++++----------------- src/eval.rs | 20 ++++++----- src/machine.rs | 15 ++++---- src/stacked_borrows.rs | 23 +++++++------ 5 files changed, 87 insertions(+), 63 deletions(-) diff --git a/README.md b/README.md index 0a507016e571..ca14f02d86ae 100644 --- a/README.md +++ b/README.md @@ -314,16 +314,20 @@ environment variable: ensure alignment. (The standard library `align_to` method works fine in both modes; under symbolic alignment it only fills the middle slice when the allocation guarantees sufficient alignment.) -* `-Zmiri-track-alloc-id=` shows a backtrace when the given allocation is +* `-Zmiri-track-alloc-id=,,...` shows a backtrace when the given allocations are being allocated or freed. This helps in debugging memory leaks and - use after free bugs. -* `-Zmiri-track-call-id=` shows a backtrace when the given call id is + use after free bugs. Specifying this argument multiple times does not overwrite the previous + values, instead it appends its values to the list. Listing an id multiple times has no effect. +* `-Zmiri-track-call-id=,,...` shows a backtrace when the given call ids are assigned to a stack frame. This helps in debugging UB related to Stacked - Borrows "protectors". -* `-Zmiri-track-pointer-tag=` shows a backtrace when the given pointer tag + Borrows "protectors". Specifying this argument multiple times does not overwrite the previous + values, instead it appends its values to the list. Listing an id multiple times has no effect. +* `-Zmiri-track-pointer-tag=,,...` shows a backtrace when a given pointer tag is popped from a borrow stack (which is where the tag becomes invalid and any future use of it will error). This helps you in finding out why UB is happening and where in your code would be a good place to look for it. + Specifying this argument multiple times does not overwrite the previous + values, instead it appends its values to the list. Listing a tag multiple times has no effect. * `-Zmiri-tag-raw-pointers` makes Stacked Borrows assign proper tags even for raw pointers. This can make valid code using int-to-ptr casts fail to pass the checks, but also can help identify latent aliasing issues in code that Miri accepts by default. You can recognize false positives by diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 727e0b717b11..e4d0af431312 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -251,6 +251,13 @@ fn run_compiler( std::process::exit(exit_code) } +/// Parses a comma separated list of `T` from the given string: +/// +/// `,,,...` +fn parse_comma_list(input: &str) -> Result, T::Err> { + input.split(',').map(str::parse::).collect() +} + fn main() { rustc_driver::install_ice_hook(); @@ -397,46 +404,55 @@ fn main() { .push(arg.strip_prefix("-Zmiri-env-forward=").unwrap().to_owned()); } arg if arg.starts_with("-Zmiri-track-pointer-tag=") => { - let id: u64 = - match arg.strip_prefix("-Zmiri-track-pointer-tag=").unwrap().parse() { - Ok(id) => id, - Err(err) => - panic!( - "-Zmiri-track-pointer-tag requires a valid `u64` argument: {}", - err - ), - }; - if let Some(id) = miri::PtrId::new(id) { - miri_config.tracked_pointer_tag = Some(id); - } else { - panic!("-Zmiri-track-pointer-tag requires a nonzero argument"); + let ids: Vec = match parse_comma_list( + arg.strip_prefix("-Zmiri-track-pointer-tag=").unwrap(), + ) { + Ok(ids) => ids, + Err(err) => + panic!( + "-Zmiri-track-pointer-tag requires a comma separated list of valid `u64` arguments: {}", + err + ), + }; + for id in ids.into_iter().map(miri::PtrId::new) { + if let Some(id) = id { + miri_config.tracked_pointer_tags.insert(id); + } else { + panic!("-Zmiri-track-pointer-tag requires nonzero arguments"); + } } } arg if arg.starts_with("-Zmiri-track-call-id=") => { - let id: u64 = match arg.strip_prefix("-Zmiri-track-call-id=").unwrap().parse() { - Ok(id) => id, + let ids: Vec = match parse_comma_list( + arg.strip_prefix("-Zmiri-track-call-id=").unwrap(), + ) { + Ok(ids) => ids, Err(err) => - panic!("-Zmiri-track-call-id requires a valid `u64` argument: {}", err), + panic!( + "-Zmiri-track-call-id requires a comma separated list of valid `u64` arguments: {}", + err + ), }; - if let Some(id) = miri::CallId::new(id) { - miri_config.tracked_call_id = Some(id); - } else { - panic!("-Zmiri-track-call-id requires a nonzero argument"); + for id in ids.into_iter().map(miri::CallId::new) { + if let Some(id) = id { + miri_config.tracked_call_ids.insert(id); + } else { + panic!("-Zmiri-track-call-id requires a nonzero argument"); + } } } arg if arg.starts_with("-Zmiri-track-alloc-id=") => { - let id = match arg - .strip_prefix("-Zmiri-track-alloc-id=") - .unwrap() - .parse() - .ok() - .and_then(NonZeroU64::new) - { - Some(id) => id, - None => - panic!("-Zmiri-track-alloc-id requires a valid non-zero `u64` argument"), + let ids: Vec = match parse_comma_list::( + arg.strip_prefix("-Zmiri-track-alloc-id=").unwrap(), + ) { + Ok(ids) => ids.into_iter().map(miri::AllocId).collect(), + Err(err) => + panic!( + "-Zmiri-track-alloc-id requires a comma separated list of valid non-zero `u64` arguments: {}", + err + ), }; - miri_config.tracked_alloc_id = Some(miri::AllocId(id)); + miri_config.tracked_alloc_ids.extend(ids); } arg if arg.starts_with("-Zmiri-compare-exchange-weak-failure-rate=") => { let rate = match arg diff --git a/src/eval.rs b/src/eval.rs index 5f829525cc57..24a0fc8ef161 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -15,6 +15,8 @@ use rustc_target::spec::abi::Abi; use rustc_session::config::EntryFnType; +use std::collections::HashSet; + use crate::*; #[derive(Copy, Clone, Debug, PartialEq)] @@ -91,12 +93,12 @@ pub struct MiriConfig { pub args: Vec, /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`). pub seed: Option, - /// The stacked borrows pointer id to report about - pub tracked_pointer_tag: Option, - /// The stacked borrows call ID to report about - pub tracked_call_id: Option, - /// The allocation id to report about. - pub tracked_alloc_id: Option, + /// The stacked borrows pointer ids to report about + pub tracked_pointer_tags: HashSet, + /// The stacked borrows call IDs to report about + pub tracked_call_ids: HashSet, + /// The allocation ids to report about. + pub tracked_alloc_ids: HashSet, /// Whether to track raw pointers in stacked borrows. pub tag_raw: bool, /// Determine if data race detection should be enabled @@ -130,9 +132,9 @@ impl Default for MiriConfig { forwarded_env_vars: vec![], args: vec![], seed: None, - tracked_pointer_tag: None, - tracked_call_id: None, - tracked_alloc_id: None, + tracked_pointer_tags: Default::default(), + tracked_call_ids: Default::default(), + tracked_alloc_ids: Default::default(), tag_raw: false, data_race_detector: true, cmpxchg_weak_failure_rate: 0.8, diff --git a/src/machine.rs b/src/machine.rs index 66854921a33e..c0f833f17610 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -3,6 +3,7 @@ use std::borrow::Cow; use std::cell::RefCell; +use std::collections::HashSet; use std::fmt; use std::num::NonZeroU64; use std::time::Instant; @@ -281,9 +282,9 @@ pub struct Evaluator<'mir, 'tcx> { /// Needs to be queried by ptr_to_int, hence needs interior mutability. pub(crate) rng: RefCell, - /// An allocation ID to report when it is being allocated + /// The allocation IDs to report when they are being allocated /// (helps for debugging memory leaks and use after free bugs). - tracked_alloc_id: Option, + tracked_alloc_ids: HashSet, /// Controls whether alignment of memory accesses is being checked. pub(crate) check_alignment: AlignmentCheck, @@ -303,8 +304,8 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0)); let stacked_borrows = if config.stacked_borrows { Some(RefCell::new(stacked_borrows::GlobalStateInner::new( - config.tracked_pointer_tag, - config.tracked_call_id, + config.tracked_pointer_tags.clone(), + config.tracked_call_ids.clone(), config.tag_raw, ))) } else { @@ -340,7 +341,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { local_crates, extern_statics: FxHashMap::default(), rng: RefCell::new(rng), - tracked_alloc_id: config.tracked_alloc_id, + tracked_alloc_ids: config.tracked_alloc_ids.clone(), check_alignment: config.check_alignment, cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate, } @@ -560,7 +561,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { alloc: Cow<'b, Allocation>, kind: Option>, ) -> Cow<'b, Allocation> { - if Some(id) == ecx.machine.tracked_alloc_id { + if ecx.machine.tracked_alloc_ids.contains(&id) { register_diagnostic(NonHaltingDiagnostic::CreatedAlloc(id)); } @@ -669,7 +670,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { (alloc_id, tag): (AllocId, Self::TagExtra), range: AllocRange, ) -> InterpResult<'tcx> { - if Some(alloc_id) == machine.tracked_alloc_id { + if machine.tracked_alloc_ids.contains(&alloc_id) { register_diagnostic(NonHaltingDiagnostic::FreedAlloc(alloc_id)); } if let Some(data_race) = &mut alloc_extra.data_race { diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 0029de3b5a9c..9d175e9c4d16 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -15,6 +15,7 @@ use rustc_middle::ty::{ }; use rustc_span::DUMMY_SP; use rustc_target::abi::Size; +use std::collections::HashSet; use crate::*; @@ -104,10 +105,10 @@ pub struct GlobalStateInner { next_call_id: CallId, /// Those call IDs corresponding to functions that are still running. active_calls: FxHashSet, - /// The pointer id to trace - tracked_pointer_tag: Option, - /// The call id to trace - tracked_call_id: Option, + /// The pointer ids to trace + tracked_pointer_tags: HashSet, + /// The call ids to trace + tracked_call_ids: HashSet, /// Whether to track raw pointers. tag_raw: bool, } @@ -158,8 +159,8 @@ impl fmt::Display for RefKind { /// Utilities for initialization and ID generation impl GlobalStateInner { pub fn new( - tracked_pointer_tag: Option, - tracked_call_id: Option, + tracked_pointer_tags: HashSet, + tracked_call_ids: HashSet, tag_raw: bool, ) -> Self { GlobalStateInner { @@ -167,15 +168,15 @@ impl GlobalStateInner { base_ptr_ids: FxHashMap::default(), next_call_id: NonZeroU64::new(1).unwrap(), active_calls: FxHashSet::default(), - tracked_pointer_tag, - tracked_call_id, + tracked_pointer_tags, + tracked_call_ids, tag_raw, } } fn new_ptr(&mut self) -> PtrId { let id = self.next_ptr_id; - if Some(id) == self.tracked_pointer_tag { + if self.tracked_pointer_tags.contains(&id) { register_diagnostic(NonHaltingDiagnostic::CreatedPointerTag(id)); } self.next_ptr_id = NonZeroU64::new(id.get() + 1).unwrap(); @@ -185,7 +186,7 @@ impl GlobalStateInner { pub fn new_call(&mut self) -> CallId { let id = self.next_call_id; trace!("new_call: Assigning ID {}", id); - if Some(id) == self.tracked_call_id { + if self.tracked_call_ids.contains(&id) { register_diagnostic(NonHaltingDiagnostic::CreatedCallId(id)); } assert!(self.active_calls.insert(id)); @@ -311,7 +312,7 @@ impl<'tcx> Stack { global: &GlobalStateInner, ) -> InterpResult<'tcx> { if let SbTag::Tagged(id) = item.tag { - if Some(id) == global.tracked_pointer_tag { + if global.tracked_pointer_tags.contains(&id) { register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag( item.clone(), provoking_access, From 3ca59d2fbf7b60b83ab79bf98e951ef54ff1ffad Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Apr 2022 16:09:35 +0200 Subject: [PATCH 3007/5092] make sure 2-phase borows work even with raw ptr tagging --- tests/run-pass/stacked-borrows/2phase.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-pass/stacked-borrows/2phase.rs b/tests/run-pass/stacked-borrows/2phase.rs index 97f435472e30..948da140477e 100644 --- a/tests/run-pass/stacked-borrows/2phase.rs +++ b/tests/run-pass/stacked-borrows/2phase.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-tag-raw-pointers #![allow(mutable_borrow_reservation_conflict)] trait S: Sized { From b472ef5bd808a38e808a3ed66f4cf67391829448 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Apr 2022 16:19:28 +0200 Subject: [PATCH 3008/5092] be explicit about types --- src/eval.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 24a0fc8ef161..f8d23cb8279c 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -132,9 +132,9 @@ impl Default for MiriConfig { forwarded_env_vars: vec![], args: vec![], seed: None, - tracked_pointer_tags: Default::default(), - tracked_call_ids: Default::default(), - tracked_alloc_ids: Default::default(), + tracked_pointer_tags: HashSet::default(), + tracked_call_ids: HashSet::default(), + tracked_alloc_ids: HashSet::default(), tag_raw: false, data_race_detector: true, cmpxchg_weak_failure_rate: 0.8, From 4d4855c7620696fa4e0e1d8171385b69912e02a8 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 25 Apr 2022 13:12:55 +0000 Subject: [PATCH 3009/5092] Add a command line flag to avoid printing to stdout and stderr --- src/bin/miri.rs | 3 ++ src/eval.rs | 4 +++ src/machine.rs | 4 +-- src/shims/posix/fs.rs | 60 +++++++++++++++++++++++++++++++---- tests/run-pass/hide_stdout.rs | 5 +++ 5 files changed, 68 insertions(+), 8 deletions(-) create mode 100644 tests/run-pass/hide_stdout.rs diff --git a/src/bin/miri.rs b/src/bin/miri.rs index e4d0af431312..b55b6f8d5589 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -374,6 +374,9 @@ fn main() { miri_config.tag_raw = true; miri_config.check_number_validity = true; } + "-Zmiri-drop-stdout-stderr" => { + miri_config.drop_stdout_stderr = true; + } "-Zmiri-track-raw-pointers" => { eprintln!( "WARNING: -Zmiri-track-raw-pointers has been renamed to -Zmiri-tag-raw-pointers, the old name is deprecated." diff --git a/src/eval.rs b/src/eval.rs index f8d23cb8279c..f1cbb00942bb 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -116,6 +116,9 @@ pub struct MiriConfig { /// Whether to enforce "strict provenance" rules. Enabling this means int2ptr casts return /// pointers with an invalid provenance, i.e., not valid for any memory access. pub strict_provenance: bool, + /// Whether to ignore any output by the program. This is helpful when debugging miri + /// as its messages don't get intermingled with the program messages. + pub drop_stdout_stderr: bool, } impl Default for MiriConfig { @@ -142,6 +145,7 @@ impl Default for MiriConfig { panic_on_unsupported: false, backtrace_style: BacktraceStyle::Short, strict_provenance: false, + drop_stdout_stderr: false, } } } diff --git a/src/machine.rs b/src/machine.rs index c0f833f17610..1fdc398dd9f0 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -28,7 +28,7 @@ use rustc_span::symbol::{sym, Symbol}; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; -use crate::*; +use crate::{*, shims::posix::FileHandler}; // Some global facts about the emulated machine. pub const PAGE_SIZE: u64 = 4 * 1024; // FIXME: adjust to target architecture @@ -327,7 +327,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { validate: config.validate, enforce_number_validity: config.check_number_validity, enforce_abi: config.check_abi, - file_handler: Default::default(), + file_handler: FileHandler::new(config.drop_stdout_stderr), dir_handler: Default::default(), time_anchor: Instant::now(), layouts, diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 73e21dd57dc4..78d0e958e2a0 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -251,22 +251,70 @@ impl FileDescriptor for io::Stderr { } } +#[derive(Debug)] +struct DevNull; + +impl FileDescriptor for DevNull { + fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { + throw_unsup_format!("/dev/null cannot be used as FileHandle"); + } + + fn read<'tcx>( + &mut self, + _communicate_allowed: bool, + _bytes: &mut [u8], + ) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("cannot read from /dev/null"); + } + + fn write<'tcx>( + &self, + _communicate_allowed: bool, + bytes: &[u8], + ) -> InterpResult<'tcx, io::Result> { + // We just don't write anything + Ok(Ok(bytes.len())) + } + + fn seek<'tcx>( + &mut self, + _communicate_allowed: bool, + _offset: SeekFrom, + ) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("cannot seek on /dev/null"); + } + + fn close<'tcx>( + self: Box, + _communicate_allowed: bool, + ) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("/dev/null cannot be closed"); + } + + fn dup<'tcx>(&mut self) -> io::Result> { + Ok(Box::new(DevNull)) + } +} + #[derive(Debug)] pub struct FileHandler { handles: BTreeMap>, } -impl<'tcx> Default for FileHandler { - fn default() -> Self { +impl<'tcx> FileHandler { + pub(crate) fn new(drop_stdout_stderr: bool) -> FileHandler { let mut handles: BTreeMap<_, Box> = BTreeMap::new(); - handles.insert(0i32, Box::new(io::stdin())); - handles.insert(1i32, Box::new(io::stdout())); + if drop_stdout_stderr { + handles.insert(0i32, Box::new(DevNull)); + handles.insert(1i32, Box::new(DevNull)); + } else { + handles.insert(0i32, Box::new(io::stdin())); + handles.insert(1i32, Box::new(io::stdout())); + } handles.insert(2i32, Box::new(io::stderr())); FileHandler { handles } } -} -impl<'tcx> FileHandler { fn insert_fd(&mut self, file_handle: Box) -> i32 { self.insert_fd_with_min_fd(file_handle, 0) } diff --git a/tests/run-pass/hide_stdout.rs b/tests/run-pass/hide_stdout.rs new file mode 100644 index 000000000000..04a4ef9df174 --- /dev/null +++ b/tests/run-pass/hide_stdout.rs @@ -0,0 +1,5 @@ +// compile-flags: -Zmiri-drop-stdout-stderr + +fn main() { + println!("cake"); +} From 1d0fe1b6bbf373190465f115777a2d98bb2741bd Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 25 Apr 2022 14:22:55 +0000 Subject: [PATCH 3010/5092] Implement the output dropping for windows, too --- src/machine.rs | 4 ++++ src/shims/windows/dlsym.rs | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/machine.rs b/src/machine.rs index 1fdc398dd9f0..6cce1a5db252 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -291,6 +291,9 @@ pub struct Evaluator<'mir, 'tcx> { /// Failure rate of compare_exchange_weak, between 0.0 and 1.0 pub(crate) cmpxchg_weak_failure_rate: f64, + + /// Corresponds to -Zmiri-drop-stdout-stderr and doesn't write the output but acts as if it succeeded. + pub(crate) drop_stdout_stderr: bool, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { @@ -344,6 +347,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { tracked_alloc_ids: config.tracked_alloc_ids.clone(), check_alignment: config.check_alignment, cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate, + drop_stdout_stderr: config.drop_stdout_stderr, } } diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index ac9e085b5d7c..05230531d917 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -75,7 +75,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx use std::io::{self, Write}; let buf_cont = this.read_bytes_ptr(buf, Size::from_bytes(u64::from(n)))?; - let res = if handle == -11 { + let res = if this.machine.drop_stdout_stderr { + Ok(buf_cont.len()) + } else if handle == -11 { io::stdout().write(buf_cont) } else { io::stderr().write(buf_cont) From f8f776fee9ad540c117f71aed62c5648a4927bf1 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Mon, 25 Apr 2022 21:34:40 +0100 Subject: [PATCH 3011/5092] Update export_symbols --- rust-version | 2 +- src/bin/miri.rs | 13 +++++++++++-- src/shims/foreign_items.rs | 4 ++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 7cc913cf8679..685628ac99d5 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -51ea9bb29b07d76c5a7167d054b54f4eb7f5b44e +18b53cefdf7456bf68937b08e377b7e622a115c2 diff --git a/src/bin/miri.rs b/src/bin/miri.rs index e4d0af431312..8a89d7f6410a 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -22,7 +22,9 @@ use rustc_errors::emitter::{ColorConfig, HumanReadableErrorType}; use rustc_hir::{self as hir, def_id::LOCAL_CRATE, Node}; use rustc_interface::interface::Config; use rustc_middle::{ - middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}, + middle::exported_symbols::{ + ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel, + }, ty::{query::ExternProviders, TyCtxt}, }; use rustc_session::{config::ErrorOutputType, search_paths::PathKind, CtfeBacktrace}; @@ -130,7 +132,14 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { && tcx.codegen_fn_attrs(local_def_id).contains_extern_indicator()) .then_some(( ExportedSymbol::NonGeneric(local_def_id.to_def_id()), - SymbolExportLevel::C, + // Some dummy `SymbolExportInfo` here. We only use + // `exported_symbols` in shims/foreign_items.rs and the export info + // is ignored. + SymbolExportInfo { + level: SymbolExportLevel::C, + kind: SymbolExportKind::Text, + used: false, + }, )) }), ) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 7b457e9ed79a..ef88c550ecb2 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -157,9 +157,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx (linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1)) }), ) { - // We can ignore `_export_level` here: we are a Rust crate, and everything is exported + // We can ignore `_export_info` here: we are a Rust crate, and everything is exported // from a Rust crate. - for &(symbol, _export_level) in tcx.exported_symbols(cnum) { + for &(symbol, _export_info) in tcx.exported_symbols(cnum) { if let ExportedSymbol::NonGeneric(def_id) = symbol { let attrs = tcx.codegen_fn_attrs(def_id); let symbol_name = if let Some(export_name) = attrs.export_name { From a192a199a8761a8c2b71ba2ca8202091b248716e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 26 Apr 2022 09:33:20 +0000 Subject: [PATCH 3012/5092] Rename flag, datastructure and messaging around muting stdout and stderr --- src/bin/miri.rs | 4 ++-- src/eval.rs | 4 ++-- src/machine.rs | 8 ++++---- src/shims/posix/fs.rs | 24 ++++++++++++------------ src/shims/windows/dlsym.rs | 2 +- tests/run-pass/hide_stdout.rs | 2 +- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index b55b6f8d5589..2fa045b57462 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -374,8 +374,8 @@ fn main() { miri_config.tag_raw = true; miri_config.check_number_validity = true; } - "-Zmiri-drop-stdout-stderr" => { - miri_config.drop_stdout_stderr = true; + "-Zmiri-mute-stdout-stderr" => { + miri_config.mute_stdout_stderr = true; } "-Zmiri-track-raw-pointers" => { eprintln!( diff --git a/src/eval.rs b/src/eval.rs index f1cbb00942bb..028c9b97abb3 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -118,7 +118,7 @@ pub struct MiriConfig { pub strict_provenance: bool, /// Whether to ignore any output by the program. This is helpful when debugging miri /// as its messages don't get intermingled with the program messages. - pub drop_stdout_stderr: bool, + pub mute_stdout_stderr: bool, } impl Default for MiriConfig { @@ -145,7 +145,7 @@ impl Default for MiriConfig { panic_on_unsupported: false, backtrace_style: BacktraceStyle::Short, strict_provenance: false, - drop_stdout_stderr: false, + mute_stdout_stderr: false, } } } diff --git a/src/machine.rs b/src/machine.rs index 6cce1a5db252..1c916220c8c5 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -292,8 +292,8 @@ pub struct Evaluator<'mir, 'tcx> { /// Failure rate of compare_exchange_weak, between 0.0 and 1.0 pub(crate) cmpxchg_weak_failure_rate: f64, - /// Corresponds to -Zmiri-drop-stdout-stderr and doesn't write the output but acts as if it succeeded. - pub(crate) drop_stdout_stderr: bool, + /// Corresponds to -Zmiri-mute-stdout-stderr and doesn't write the output but acts as if it succeeded. + pub(crate) mute_stdout_stderr: bool, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { @@ -330,7 +330,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { validate: config.validate, enforce_number_validity: config.check_number_validity, enforce_abi: config.check_abi, - file_handler: FileHandler::new(config.drop_stdout_stderr), + file_handler: FileHandler::new(config.mute_stdout_stderr), dir_handler: Default::default(), time_anchor: Instant::now(), layouts, @@ -347,7 +347,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { tracked_alloc_ids: config.tracked_alloc_ids.clone(), check_alignment: config.check_alignment, cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate, - drop_stdout_stderr: config.drop_stdout_stderr, + mute_stdout_stderr: config.mute_stdout_stderr, } } diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 78d0e958e2a0..1b0a94e0ffc9 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -252,11 +252,11 @@ impl FileDescriptor for io::Stderr { } #[derive(Debug)] -struct DevNull; +struct DummyOutput; -impl FileDescriptor for DevNull { +impl FileDescriptor for DummyOutput { fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { - throw_unsup_format!("/dev/null cannot be used as FileHandle"); + throw_unsup_format!("stderr and stdout cannot be used as FileHandle"); } fn read<'tcx>( @@ -264,7 +264,7 @@ impl FileDescriptor for DevNull { _communicate_allowed: bool, _bytes: &mut [u8], ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("cannot read from /dev/null"); + throw_unsup_format!("cannot read from stderr or stdout"); } fn write<'tcx>( @@ -272,7 +272,7 @@ impl FileDescriptor for DevNull { _communicate_allowed: bool, bytes: &[u8], ) -> InterpResult<'tcx, io::Result> { - // We just don't write anything + // We just don't write anything, but report to the user that we did. Ok(Ok(bytes.len())) } @@ -281,18 +281,18 @@ impl FileDescriptor for DevNull { _communicate_allowed: bool, _offset: SeekFrom, ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("cannot seek on /dev/null"); + throw_unsup_format!("cannot seek on stderr or stdout"); } fn close<'tcx>( self: Box, _communicate_allowed: bool, ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("/dev/null cannot be closed"); + throw_unsup_format!("stderr and stdout cannot be closed"); } fn dup<'tcx>(&mut self) -> io::Result> { - Ok(Box::new(DevNull)) + Ok(Box::new(DummyOutput)) } } @@ -302,11 +302,11 @@ pub struct FileHandler { } impl<'tcx> FileHandler { - pub(crate) fn new(drop_stdout_stderr: bool) -> FileHandler { + pub(crate) fn new(mute_stdout_stderr: bool) -> FileHandler { let mut handles: BTreeMap<_, Box> = BTreeMap::new(); - if drop_stdout_stderr { - handles.insert(0i32, Box::new(DevNull)); - handles.insert(1i32, Box::new(DevNull)); + if mute_stdout_stderr { + handles.insert(0i32, Box::new(DummyOutput)); + handles.insert(1i32, Box::new(DummyOutput)); } else { handles.insert(0i32, Box::new(io::stdin())); handles.insert(1i32, Box::new(io::stdout())); diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 05230531d917..ddbad8c5affa 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -75,7 +75,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx use std::io::{self, Write}; let buf_cont = this.read_bytes_ptr(buf, Size::from_bytes(u64::from(n)))?; - let res = if this.machine.drop_stdout_stderr { + let res = if this.machine.mute_stdout_stderr { Ok(buf_cont.len()) } else if handle == -11 { io::stdout().write(buf_cont) diff --git a/tests/run-pass/hide_stdout.rs b/tests/run-pass/hide_stdout.rs index 04a4ef9df174..849fce913862 100644 --- a/tests/run-pass/hide_stdout.rs +++ b/tests/run-pass/hide_stdout.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-drop-stdout-stderr +// compile-flags: -Zmiri-mute-stdout-stderr fn main() { println!("cake"); From 5e26cdaf3a574efa8e88b31b9df4d120e0805d7d Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 26 Apr 2022 09:36:02 +0000 Subject: [PATCH 3013/5092] Add readme entry --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index ca14f02d86ae..4cb03ed7b0b2 100644 --- a/README.md +++ b/README.md @@ -265,6 +265,10 @@ environment variable: * `-Zmiri-disable-isolation` disables host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness. +* `-Zmiri-mute-stdout-stderr` silently ignores all writes to stdout and stderr, + but reports to the program that it did actually write. This is useful when you + are not interested in the actual program's messages, but only want to see miri's + errors and warnings. * `-Zmiri-isolation-error=` configures Miri's response to operations requiring host access while isolation is enabled. `abort`, `hide`, `warn`, and `warn-nobacktrace` are the supported actions. The default is to `abort`, From b0a51720c69198ccfe0467b43cd2658d9341bd76 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:25:10 -0700 Subject: [PATCH 3014/5092] Suppress all currently triggered clippy lints --- src/bin/miri.rs | 1 + src/lib.rs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 8a89d7f6410a..0030c24b19e6 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -1,4 +1,5 @@ #![feature(rustc_private, bool_to_option, stmt_expr_attributes)] +#![allow(clippy::manual_range_contains)] extern crate rustc_data_structures; extern crate rustc_driver; diff --git a/src/lib.rs b/src/lib.rs index f14120ae4ccc..285e8d10e562 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,6 +8,36 @@ #![feature(io_error_more)] #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] +// TODO: Uncategorized. Some of these we'll want to fix, some keep ignored. +#![allow( + clippy::assign_op_pattern, + clippy::clone_on_copy, + clippy::collapsible_else_if, + clippy::collapsible_if, + clippy::comparison_chain, + clippy::enum_variant_names, + clippy::extra_unused_lifetimes, + clippy::field_reassign_with_default, + clippy::from_over_into, + clippy::if_same_then_else, + clippy::len_zero, + clippy::manual_map, + clippy::mem_replace_with_default, + clippy::needless_borrow, + clippy::needless_lifetimes, + clippy::needless_question_mark, + clippy::needless_return, + clippy::new_without_default, + clippy::op_ref, + clippy::redundant_closure, + clippy::redundant_field_names, + clippy::single_char_add_str, + clippy::single_char_pattern, + clippy::single_match, + clippy::unnecessary_mut_passed, + clippy::useless_conversion, + clippy::useless_format +)] extern crate rustc_apfloat; extern crate rustc_ast; From 03897452039a749c717b8bf3b7f9bb030035e88d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:25:38 -0700 Subject: [PATCH 3015/5092] Resolve clippy::assign_op_pattern error: manual implementation of an assign operation --> src/helpers.rs:673:17 | 673 | len = len + size1; | ^^^^^^^^^^^^^^^^^ help: replace it with: `len += size1` | = note: `-D clippy::assign-op-pattern` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#assign_op_pattern --- src/helpers.rs | 2 +- src/lib.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 9d387b065938..c995a926d63f 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -670,7 +670,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if byte == 0 { break; } else { - len = len + size1; + len += size1; } } diff --git a/src/lib.rs b/src/lib.rs index 285e8d10e562..8dca869aa84b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,6 @@ #![allow(clippy::cast_lossless)] // TODO: Uncategorized. Some of these we'll want to fix, some keep ignored. #![allow( - clippy::assign_op_pattern, clippy::clone_on_copy, clippy::collapsible_else_if, clippy::collapsible_if, From 9125cc1c280ca9c13ae341a4cf12eee30c52f76d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:26:28 -0700 Subject: [PATCH 3016/5092] Resolve clippy::clone_on_copy error: using `clone` on type `std::option::Option` which implements the `Copy` trait --> src/shims/tls.rs:307:24 | 307 | let last_key = this.machine.tls.dtors_running[&active_thread].last_dtor_key.clone(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try removing the `clone` call: `this.machine.tls.dtors_running[&active_thread].last_dtor_key` | = note: `-D clippy::clone-on-copy` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_copy error: using `clone` on type `stacked_borrows::Item` which implements the `Copy` trait --> src/stacked_borrows.rs:317:21 | 317 | item.clone(), | ^^^^^^^^^^^^ help: try dereferencing it: `*item` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_copy --- src/lib.rs | 1 - src/shims/tls.rs | 2 +- src/stacked_borrows.rs | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 8dca869aa84b..083dff0e61e8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,6 @@ #![allow(clippy::cast_lossless)] // TODO: Uncategorized. Some of these we'll want to fix, some keep ignored. #![allow( - clippy::clone_on_copy, clippy::collapsible_else_if, clippy::collapsible_if, clippy::comparison_chain, diff --git a/src/shims/tls.rs b/src/shims/tls.rs index ceed123c7ac4..31a3e12b41bd 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -304,7 +304,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert!(this.has_terminated(active_thread), "running TLS dtors for non-terminated thread"); // Fetch next dtor after `key`. - let last_key = this.machine.tls.dtors_running[&active_thread].last_dtor_key.clone(); + let last_key = this.machine.tls.dtors_running[&active_thread].last_dtor_key; let dtor = match this.machine.tls.fetch_tls_dtor(last_key, active_thread) { dtor @ Some(_) => dtor, // We ran each dtor once, start over from the beginning. diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 9d175e9c4d16..d6caba81713c 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -314,7 +314,7 @@ impl<'tcx> Stack { if let SbTag::Tagged(id) = item.tag { if global.tracked_pointer_tags.contains(&id) { register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag( - item.clone(), + *item, provoking_access, )); } From 1fa63f1e9b490fb33ff38781a7af57c36987a392 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:29:01 -0700 Subject: [PATCH 3017/5092] Resolve clippy::extra_unused_lifetimes error: this lifetime isn't used in the function definition --> src/helpers.rs:46:20 | 46 | fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option { | ^^^^ | = note: `-D clippy::extra-unused-lifetimes` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_lifetimes error: this lifetime isn't used in the function definition --> src/shims/posix/fs.rs:49:12 | 49 | fn dup<'tcx>(&mut self) -> io::Result>; | ^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_lifetimes error: this lifetime isn't used in the function definition --> src/shims/os_str.rs:81:41 | 81 | pub fn u16vec_to_osstring<'tcx, 'a>(u16_vec: Vec) -> InterpResult<'tcx, OsString> { | ^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_lifetimes error: this lifetime isn't used in the function definition --> src/thread.rs:72:26 | 72 | pub fn to_u32_scalar<'tcx>(&self) -> Scalar { | ^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_lifetimes --- src/helpers.rs | 2 +- src/lib.rs | 1 - src/shims/os_str.rs | 2 +- src/shims/posix/fs.rs | 10 +++++----- src/thread.rs | 2 +- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index c995a926d63f..a2073066fac0 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -43,7 +43,7 @@ const UNIX_IO_ERROR_TABLE: &[(std::io::ErrorKind, &str)] = { }; /// Gets an instance for a path. -fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option { +fn try_resolve_did<'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option { 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 }; diff --git a/src/lib.rs b/src/lib.rs index 083dff0e61e8..0063753418b8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,7 +14,6 @@ clippy::collapsible_if, clippy::comparison_chain, clippy::enum_variant_names, - clippy::extra_unused_lifetimes, clippy::field_reassign_with_default, clippy::from_over_into, clippy::if_same_then_else, diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 8db75fed4a5f..d6669b21a731 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -78,7 +78,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(OsString::from_wide(&u16_vec[..])) } #[cfg(not(windows))] - pub fn u16vec_to_osstring<'tcx, 'a>(u16_vec: Vec) -> InterpResult<'tcx, OsString> { + pub fn u16vec_to_osstring<'tcx>(u16_vec: Vec) -> InterpResult<'tcx, OsString> { let s = String::from_utf16(&u16_vec[..]) .map_err(|_| err_unsup_format!("{:?} is not a valid utf-16 string", u16_vec))?; Ok(s.into()) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 73e21dd57dc4..93ca3c80198b 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -46,7 +46,7 @@ trait FileDescriptor: std::fmt::Debug { _communicate_allowed: bool, ) -> InterpResult<'tcx, io::Result>; - fn dup<'tcx>(&mut self) -> io::Result>; + fn dup(&mut self) -> io::Result>; } impl FileDescriptor for FileHandle { @@ -107,7 +107,7 @@ impl FileDescriptor for FileHandle { } } - fn dup<'tcx>(&mut self) -> io::Result> { + fn dup(&mut self) -> io::Result> { let duplicated = self.file.try_clone()?; Ok(Box::new(FileHandle { file: duplicated, writable: self.writable })) } @@ -153,7 +153,7 @@ impl FileDescriptor for io::Stdin { throw_unsup_format!("stdin cannot be closed"); } - fn dup<'tcx>(&mut self) -> io::Result> { + fn dup(&mut self) -> io::Result> { Ok(Box::new(io::stdin())) } } @@ -203,7 +203,7 @@ impl FileDescriptor for io::Stdout { throw_unsup_format!("stdout cannot be closed"); } - fn dup<'tcx>(&mut self) -> io::Result> { + fn dup(&mut self) -> io::Result> { Ok(Box::new(io::stdout())) } } @@ -246,7 +246,7 @@ impl FileDescriptor for io::Stderr { throw_unsup_format!("stderr cannot be closed"); } - fn dup<'tcx>(&mut self) -> io::Result> { + fn dup(&mut self) -> io::Result> { Ok(Box::new(io::stderr())) } } diff --git a/src/thread.rs b/src/thread.rs index 27bc9566d8fd..fc2c9ed779b6 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -69,7 +69,7 @@ impl From for ThreadId { } impl ThreadId { - pub fn to_u32_scalar<'tcx>(&self) -> Scalar { + pub fn to_u32_scalar(&self) -> Scalar { Scalar::from_u32(u32::try_from(self.0).unwrap()) } } From 168e87682f1a99cb267bae1eea9d2ee6bcfc3276 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:33:45 -0700 Subject: [PATCH 3018/5092] Resolve clippy::len_zero error: length comparison to one --> src/shims/posix/thread.rs:102:12 | 102 | if args.len() < 1 { | ^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `args.is_empty()` | = note: `-D clippy::len-zero` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#len_zero --- src/lib.rs | 1 - src/shims/posix/thread.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0063753418b8..9fbc3f8a33b6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,7 +17,6 @@ clippy::field_reassign_with_default, clippy::from_over_into, clippy::if_same_then_else, - clippy::len_zero, clippy::manual_map, clippy::mem_replace_with_default, clippy::needless_borrow, diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index 7840a1e1e970..0b8684d39eb2 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -99,7 +99,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("linux", "prctl"); - if args.len() < 1 { + if args.is_empty() { throw_ub_format!( "incorrect number of arguments for `prctl`: got {}, expected at least 1", args.len() From 16c2400737d5f919235b9c00efaf9137bc3fd75c Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:39:51 -0700 Subject: [PATCH 3019/5092] Resolve clippy::mem_replace_with_default error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` --> src/helpers.rs:54:29 | 54 | for item in mem::replace(&mut items, Default::default()).iter() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut items)` | = note: `-D clippy::mem-replace-with-default` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default --- src/helpers.rs | 2 +- src/lib.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index a2073066fac0..10dbd373786a 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -51,7 +51,7 @@ fn try_resolve_did<'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option { let mut path_it = path.iter().skip(1).peekable(); while let Some(segment) = path_it.next() { - for item in mem::replace(&mut items, Default::default()).iter() { + 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()); diff --git a/src/lib.rs b/src/lib.rs index 9fbc3f8a33b6..5d2faac57d83 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,6 @@ clippy::from_over_into, clippy::if_same_then_else, clippy::manual_map, - clippy::mem_replace_with_default, clippy::needless_borrow, clippy::needless_lifetimes, clippy::needless_question_mark, From 2ca7f3b45df176295d276ce50f7f32845c7f614d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:40:28 -0700 Subject: [PATCH 3020/5092] Resolve clippy::needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/data_race.rs:565:34 | 565 | this.validate_atomic_rmw(&place, atomic)?; | ^^^^^^ help: change this to: `place` | = note: `-D clippy::needless-borrow` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/data_race.rs:1413:27 | 1413 | clocks.clock.join(&lock); | ^^^^^ help: change this to: `lock` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/helpers.rs:326:51 | 326 | .size_and_align_of_mplace(&place)? | ^^^^^^ help: change this to: `place` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/helpers.rs:365:17 | 365 | &self.ecx | ^^^^^^^^^ help: change this to: `self.ecx` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/helpers.rs:634:47 | 634 | let seconds_place = this.mplace_field(&tp, 0)?; | ^^^ help: change this to: `tp` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/helpers.rs:637:51 | 637 | let nanoseconds_place = this.mplace_field(&tp, 1)?; | ^^^ help: change this to: `tp` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/machine.rs:547:73 | 547 | let link_name = match ecx.tcx.sess.first_attr_value_str_by_name(&attrs, sym::link_name) { | ^^^^^^ help: change this to: `attrs` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/machine.rs:576:56 | 576 | Some(data_race::AllocExtra::new_allocation(&data_race, alloc.size(), kind)) | ^^^^^^^^^^ help: change this to: `data_race` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/shims/foreign_items.rs:241:43 | 241 | .first_attr_value_str_by_name(&attrs, sym::link_name) | ^^^^^^ help: change this to: `attrs` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/shims/intrinsics.rs:778:61 | 778 | .read_immediate(&this.operand_index(&index, i)?.into())? | ^^^^^^ help: change this to: `index` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/shims/intrinsics.rs:1195:44 | 1195 | this.write_immediate(*old, &dest)?; // old value is returned | ^^^^^ help: change this to: `dest` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/shims/intrinsics.rs:1200:44 | 1200 | this.write_immediate(*old, &dest)?; // old value is returned | ^^^^^ help: change this to: `dest` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/shims/posix/fs.rs:54:12 | 54 | Ok(&self) | ^^^^^ help: change this to: `self` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/shims/posix/fs.rs:654:49 | 654 | let io_result = maybe_sync_file(&file, *writable, File::sync_all); | ^^^^^ help: change this to: `file` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/shims/posix/fs.rs:746:52 | 746 | file_descriptor.write(communicate, &bytes)?.map(|c| i64::try_from(c).unwrap()); | ^^^^^^ help: change this to: `bytes` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/shims/posix/fs.rs:1494:45 | 1494 | let io_result = maybe_sync_file(&file, *writable, File::sync_all); | ^^^^^ help: change this to: `file` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/shims/posix/fs.rs:1516:45 | 1516 | let io_result = maybe_sync_file(&file, *writable, File::sync_data); | ^^^^^ help: change this to: `file` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/shims/posix/fs.rs:1561:45 | 1561 | let io_result = maybe_sync_file(&file, *writable, File::sync_data); | ^^^^^ help: change this to: `file` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/shims/env.rs:232:65 | 232 | let var_ptr = alloc_env_var_as_c_str(&name, &value, &mut this)?; | ^^^^^^^^^ help: change this to: `this` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/shims/env.rs:277:68 | 277 | let var_ptr = alloc_env_var_as_wide_str(&name, &value, &mut this)?; | ^^^^^^^^^ help: change this to: `this` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/shims/env.rs:328:37 | 328 | let buf = this.read_pointer(&buf_op)?; | ^^^^^^^ help: change this to: `buf_op` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/shims/env.rs:329:37 | 329 | let size = this.read_scalar(&size_op)?.to_machine_usize(&*this.tcx)?; | ^^^^^^^^ help: change this to: `size_op` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow --- src/data_race.rs | 4 ++-- src/helpers.rs | 8 ++++---- src/lib.rs | 1 - src/machine.rs | 4 ++-- src/shims/env.rs | 12 ++++++------ src/shims/foreign_items.rs | 2 +- src/shims/intrinsics.rs | 6 +++--- src/shims/posix/fs.rs | 12 ++++++------ 8 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index 7625763a3bb4..b2bd29c5cb19 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -562,7 +562,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { this.allow_data_races_mut(|this| this.write_immediate(**new_val, &(*place).into()))?; - this.validate_atomic_rmw(&place, atomic)?; + this.validate_atomic_rmw(place, atomic)?; // Return the old value. Ok(old) @@ -1410,7 +1410,7 @@ impl GlobalState { /// incremented. pub fn validate_lock_acquire(&self, lock: &VClock, thread: ThreadId) { let (_, mut clocks) = self.load_thread_state_mut(thread); - clocks.clock.join(&lock); + clocks.clock.join(lock); } /// Release a lock handle, express that this happens-before diff --git a/src/helpers.rs b/src/helpers.rs index 10dbd373786a..1d84b3fdf16e 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -323,7 +323,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("unsafe_cell_action on {:?}", place.ptr); // We need a size to go on. let unsafe_cell_size = this - .size_and_align_of_mplace(&place)? + .size_and_align_of_mplace(place)? .map(|(size, _)| size) // for extern types, just cover what we can .unwrap_or_else(|| place.layout.size); @@ -362,7 +362,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline(always)] fn ecx(&self) -> &MiriEvalContext<'mir, 'tcx> { - &self.ecx + self.ecx } // Hook to detect `UnsafeCell`. @@ -631,10 +631,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// `EINVAL` in this case. fn read_timespec(&mut self, tp: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); - let seconds_place = this.mplace_field(&tp, 0)?; + let seconds_place = this.mplace_field(tp, 0)?; let seconds_scalar = this.read_scalar(&seconds_place.into())?; let seconds = seconds_scalar.to_machine_isize(this)?; - let nanoseconds_place = this.mplace_field(&tp, 1)?; + let nanoseconds_place = this.mplace_field(tp, 1)?; let nanoseconds_scalar = this.read_scalar(&nanoseconds_place.into())?; let nanoseconds = nanoseconds_scalar.to_machine_isize(this)?; diff --git a/src/lib.rs b/src/lib.rs index 5d2faac57d83..598d9cc96ae6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,6 @@ clippy::from_over_into, clippy::if_same_then_else, clippy::manual_map, - clippy::needless_borrow, clippy::needless_lifetimes, clippy::needless_question_mark, clippy::needless_return, diff --git a/src/machine.rs b/src/machine.rs index c0f833f17610..0a8a229c8aa2 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -544,7 +544,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { def_id: DefId, ) -> InterpResult<'tcx, Pointer> { let attrs = ecx.tcx.get_attrs(def_id); - let link_name = match ecx.tcx.sess.first_attr_value_str_by_name(&attrs, sym::link_name) { + let link_name = match ecx.tcx.sess.first_attr_value_str_by_name(attrs, sym::link_name) { Some(name) => name, None => ecx.tcx.item_name(def_id), }; @@ -573,7 +573,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { None }; let race_alloc = if let Some(data_race) = &ecx.machine.data_race { - Some(data_race::AllocExtra::new_allocation(&data_race, alloc.size(), kind)) + Some(data_race::AllocExtra::new_allocation(data_race, alloc.size(), kind)) } else { None }; diff --git a/src/shims/env.rs b/src/shims/env.rs index 3b1b1f011e3e..915decc28725 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -210,7 +210,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name_op: &OpTy<'tcx, Tag>, value_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { - let mut this = self.eval_context_mut(); + let this = self.eval_context_mut(); let target_os = &this.tcx.sess.target.os; assert!( target_os == "linux" || target_os == "macos", @@ -229,7 +229,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } if let Some((name, value)) = new { - let var_ptr = alloc_env_var_as_c_str(&name, &value, &mut this)?; + let var_ptr = alloc_env_var_as_c_str(&name, &value, this)?; if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?; } @@ -249,7 +249,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name_op: &OpTy<'tcx, Tag>, // LPCWSTR value_op: &OpTy<'tcx, Tag>, // LPCWSTR ) -> InterpResult<'tcx, i32> { - let mut this = self.eval_context_mut(); + let this = self.eval_context_mut(); this.assert_target_os("windows", "SetEnvironmentVariableW"); let name_ptr = this.read_pointer(name_op)?; @@ -274,7 +274,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(1) // return non-zero on success } else { let value = this.read_os_str_from_wide_str(value_ptr)?; - let var_ptr = alloc_env_var_as_wide_str(&name, &value, &mut this)?; + let var_ptr = alloc_env_var_as_wide_str(&name, &value, this)?; if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?; } @@ -325,8 +325,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "`getcwd` is only available for the UNIX target family" ); - let buf = this.read_pointer(&buf_op)?; - let size = this.read_scalar(&size_op)?.to_machine_usize(&*this.tcx)?; + let buf = this.read_pointer(buf_op)?; + let size = this.read_scalar(size_op)?.to_machine_usize(&*this.tcx)?; if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`getcwd`", reject_with)?; diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index ef88c550ecb2..9256013fb157 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -238,7 +238,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let link_name = this .tcx .sess - .first_attr_value_str_by_name(&attrs, sym::link_name) + .first_attr_value_str_by_name(attrs, sym::link_name) .unwrap_or_else(|| this.tcx.item_name(def_id)); let tcx = this.tcx.tcx; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 1b69be5153b0..06537b5d333b 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -775,7 +775,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx for i in 0..dest_len { let src_index: u64 = this - .read_immediate(&this.operand_index(&index, i)?.into())? + .read_immediate(&this.operand_index(index, i)?.into())? .to_scalar()? .to_u32()? .into(); @@ -1192,12 +1192,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match atomic_op { AtomicOp::Min => { let old = this.atomic_min_max_scalar(&place, rhs, true, atomic)?; - this.write_immediate(*old, &dest)?; // old value is returned + this.write_immediate(*old, dest)?; // old value is returned Ok(()) } AtomicOp::Max => { let old = this.atomic_min_max_scalar(&place, rhs, false, atomic)?; - this.write_immediate(*old, &dest)?; // old value is returned + this.write_immediate(*old, dest)?; // old value is returned Ok(()) } AtomicOp::MirOp(op, neg) => { diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 93ca3c80198b..7957edf5c65e 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -51,7 +51,7 @@ trait FileDescriptor: std::fmt::Debug { impl FileDescriptor for FileHandle { fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { - Ok(&self) + Ok(self) } fn read<'tcx>( @@ -651,7 +651,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support fullfsync for all FDs let FileHandle { file, writable } = file_descriptor.as_file_handle()?; - let io_result = maybe_sync_file(&file, *writable, File::sync_all); + let io_result = maybe_sync_file(file, *writable, File::sync_all); this.try_unwrap_io_result(io_result) } else { this.handle_not_found() @@ -743,7 +743,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { let bytes = this.read_bytes_ptr(buf, Size::from_bytes(count))?; let result = - file_descriptor.write(communicate, &bytes)?.map(|c| i64::try_from(c).unwrap()); + file_descriptor.write(communicate, bytes)?.map(|c| i64::try_from(c).unwrap()); this.try_unwrap_io_result(result) } else { this.handle_not_found() @@ -1491,7 +1491,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support fsync for all FDs let FileHandle { file, writable } = file_descriptor.as_file_handle()?; - let io_result = maybe_sync_file(&file, *writable, File::sync_all); + let io_result = maybe_sync_file(file, *writable, File::sync_all); this.try_unwrap_io_result(io_result) } else { this.handle_not_found() @@ -1513,7 +1513,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support fdatasync for all FDs let FileHandle { file, writable } = file_descriptor.as_file_handle()?; - let io_result = maybe_sync_file(&file, *writable, File::sync_data); + let io_result = maybe_sync_file(file, *writable, File::sync_data); this.try_unwrap_io_result(io_result) } else { this.handle_not_found() @@ -1558,7 +1558,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support sync_data_range for all FDs let FileHandle { file, writable } = file_descriptor.as_file_handle()?; - let io_result = maybe_sync_file(&file, *writable, File::sync_data); + let io_result = maybe_sync_file(file, *writable, File::sync_data); this.try_unwrap_io_result(io_result) } else { this.handle_not_found() From c6bd81bbf30bc5d36aae8bf6e5613737f139a7ac Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:43:36 -0700 Subject: [PATCH 3021/5092] Resolve clippy::needless_lifetimes error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) --> src/range_map.rs:66:5 | 66 | pub fn iter<'a>(&'a self, offset: Size, len: Size) -> impl Iterator + 'a { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::needless-lifetimes` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) --> src/range_map.rs:86:5 | 86 | pub fn iter_mut_all<'a>(&'a mut self) -> impl Iterator + 'a { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) --> src/range_map.rs:122:5 | 122 | / pub fn iter_mut<'a>( 123 | | &'a mut self, 124 | | offset: Size, 125 | | len: Size, 126 | | ) -> impl Iterator + 'a | |_____________________________________________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) --> src/shims/intrinsics.rs:1391:1 | 1391 | fn simd_element_to_bool<'tcx>(elem: ImmTy<'tcx, Tag>) -> InterpResult<'tcx, bool> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes --- src/range_map.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/range_map.rs b/src/range_map.rs index 8b5a3af5bac5..f0507ffabad0 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -63,7 +63,7 @@ impl RangeMap { /// through interior mutability. /// /// The iterator also provides the offset of the given element. - pub fn iter<'a>(&'a self, offset: Size, len: Size) -> impl Iterator + 'a { + pub fn iter(&self, offset: Size, len: Size) -> impl Iterator { let offset = offset.bytes(); let len = len.bytes(); // Compute a slice starting with the elements we care about. @@ -83,7 +83,7 @@ impl RangeMap { .map(|elem| (Size::from_bytes(elem.range.start), &elem.data)) } - pub fn iter_mut_all<'a>(&'a mut self) -> impl Iterator + 'a { + pub fn iter_mut_all(&mut self) -> impl Iterator { self.v.iter_mut().map(|elem| &mut elem.data) } @@ -119,11 +119,7 @@ impl RangeMap { /// Moreover, this will opportunistically merge neighbouring equal blocks. /// /// The iterator also provides the offset of the given element. - pub fn iter_mut<'a>( - &'a mut self, - offset: Size, - len: Size, - ) -> impl Iterator + 'a + pub fn iter_mut(&mut self, offset: Size, len: Size) -> impl Iterator where T: Clone + PartialEq, { From 6e2297fde014ea5a89765bde4ade220b8f50fd7d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:47:57 -0700 Subject: [PATCH 3022/5092] Resolve clippy::needless_question_mark error: question mark operator is useless here --> src/helpers.rs:86:16 | 86 | return Ok(const_val.check_init()?); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `const_val.check_init()` | = note: `-D clippy::needless-question-mark` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_question_mark --- src/helpers.rs | 2 +- src/lib.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 1d84b3fdf16e..b9ac4afff36d 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -83,7 +83,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let cid = GlobalId { instance, promoted: None }; let const_val = this.eval_to_allocation(cid)?; let const_val = this.read_scalar(&const_val.into())?; - return Ok(const_val.check_init()?); + const_val.check_init() } /// Helper function to get a `libc` constant as a `Scalar`. diff --git a/src/lib.rs b/src/lib.rs index 598d9cc96ae6..cd40fa419763 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,7 +19,6 @@ clippy::if_same_then_else, clippy::manual_map, clippy::needless_lifetimes, - clippy::needless_question_mark, clippy::needless_return, clippy::new_without_default, clippy::op_ref, From a893618854b3c22fbe54a9b771ade85edada4143 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 14:37:54 -0700 Subject: [PATCH 3023/5092] Implement llvm.x86.addcarry.64 --- src/shims/foreign_items.rs | 15 +++++++++++++++ tests/run-pass/intrinsics-x86.rs | 22 ++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 tests/run-pass/intrinsics-x86.rs diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index ef88c550ecb2..807fca817016 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -671,6 +671,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Architecture-specific shims + "llvm.x86.addcarry.64" if this.tcx.sess.target.arch == "x86_64" => { + // Computes u8+u64+u64, returning tuple (u8,u64) comprising the output carry and truncated sum. + let &[ref c_in, ref a, ref b] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; + let c_in = this.read_scalar(c_in)?.to_u8()?; + let a = this.read_scalar(a)?.to_u64()?; + let b = this.read_scalar(b)?.to_u64()?; + + let wide_sum = c_in as u128 + a as u128 + b as u128; + let (c_out, sum) = ((wide_sum >> 64) as u8, wide_sum as u64); + + let c_out_field = this.place_field(dest, 0)?; + this.write_scalar(Scalar::from_u8(c_out), &c_out_field)?; + let sum_field = this.place_field(dest, 1)?; + this.write_scalar(Scalar::from_u64(sum), &sum_field)?; + } "llvm.x86.sse2.pause" if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" => { let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.yield_active_thread(); diff --git a/tests/run-pass/intrinsics-x86.rs b/tests/run-pass/intrinsics-x86.rs new file mode 100644 index 000000000000..88cd782e70a4 --- /dev/null +++ b/tests/run-pass/intrinsics-x86.rs @@ -0,0 +1,22 @@ +#[cfg(target_arch = "x86_64")] +mod x86_64 { + use core::arch::x86_64 as arch; + + fn adc(c_in: u8, a: u64, b: u64) -> (u8, u64) { + let mut sum = 0; + // SAFETY: There are no safety requirements for calling `_addcarry_u64`. + // It's just unsafe for API consistency with other intrinsics. + let c_out = unsafe { arch::_addcarry_u64(c_in, a, b, &mut sum) }; + (c_out, sum) + } + + pub fn main() { + assert_eq!(adc(1, 1, 1), (0, 3)); + assert_eq!(adc(3, u64::MAX, u64::MAX), (2, 1)); + } +} + +fn main() { + #[cfg(target_arch = "x86_64")] + x86_64::main(); +} From 519755a82356895545a8e383c6aa27aba20eabd6 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:48:24 -0700 Subject: [PATCH 3024/5092] Resolve clippy::needless_return error: unneeded `return` statement --> src/helpers.rs:734:13 | 734 | return Ok(()); | ^^^^^^^^^^^^^^ help: remove `return`: `Ok(())` | = note: `-D clippy::needless-return` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_return error: unneeded `return` statement --> src/range_map.rs:113:9 | 113 | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_return error: unneeded `return` statement --> src/shims/posix/fs.rs:648:25 | 648 | None => return this.handle_not_found(), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `this.handle_not_found()` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_return error: unneeded `return` statement --> src/shims/panic.rs:62:9 | 62 | return Ok(()); | ^^^^^^^^^^^^^^ help: remove `return`: `Ok(())` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_return error: unneeded `return` statement --> src/shims/panic.rs:115:9 | 115 | return Ok(()); | ^^^^^^^^^^^^^^ help: remove `return`: `Ok(())` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_return error: unneeded `return` statement --> src/thread.rs:477:9 | 477 | return free_tls_statics; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `free_tls_statics` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_return error: unneeded `return` statement --> src/thread.rs:459:17 | 459 | return false; | ^^^^^^^^^^^^^ help: remove `return`: `false` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_return --- src/helpers.rs | 2 +- src/lib.rs | 1 - src/range_map.rs | 2 +- src/shims/panic.rs | 4 ++-- src/shims/posix/fs.rs | 2 +- src/thread.rs | 4 ++-- 6 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index b9ac4afff36d..76a65bcbb76e 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -731,7 +731,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // message is slightly different here to make automated analysis easier let error_msg = format!("unsupported Miri functionality: {}", error_msg.as_ref()); this.start_panic(error_msg.as_ref(), StackPopUnwind::Skip)?; - return Ok(()); + Ok(()) } else { throw_unsup_format!("{}", error_msg.as_ref()); } diff --git a/src/lib.rs b/src/lib.rs index cd40fa419763..50d6a09eb891 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,7 +19,6 @@ clippy::if_same_then_else, clippy::manual_map, clippy::needless_lifetimes, - clippy::needless_return, clippy::new_without_default, clippy::op_ref, clippy::redundant_closure, diff --git a/src/range_map.rs b/src/range_map.rs index f0507ffabad0..474ad9dcccd9 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -110,7 +110,7 @@ impl RangeMap { // Copy the data, and insert second element. let second = Elem { range: second_range, data: elem.data.clone() }; self.v.insert(index + 1, second); - return true; + true } /// Provides mutable iteration over everything in the given range. As a side-effect, diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 8f4e3f578ee9..96d3b7c9f891 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -59,7 +59,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Jump to the unwind block to begin unwinding. this.unwind_to_block(unwind)?; - return Ok(()); + Ok(()) } /// Handles the `try` intrinsic, the underlying implementation of `std::panicking::try`. @@ -112,7 +112,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(CatchUnwindData { catch_fn, data, dest: *dest, ret }); } - return Ok(()); + Ok(()) } fn handle_stack_pop( diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 7957edf5c65e..f224a1461f93 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -645,7 +645,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } - None => return this.handle_not_found(), + None => this.handle_not_found(), } } else if this.tcx.sess.target.os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC")? { if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { diff --git a/src/thread.rs b/src/thread.rs index fc2c9ed779b6..2ed8b3a7ce1c 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -456,7 +456,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { // Delete this static from the map and from memory. // We cannot free directly here as we cannot use `?` in this context. free_tls_statics.push(alloc_id); - return false; + false }); } // Set the thread into a terminated state in the data-race detector @@ -474,7 +474,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { thread.state = ThreadState::Enabled; } } - return free_tls_statics; + free_tls_statics } /// Decide which action to take next and on which thread. From 95510587ff5d827cf2fd9aea130f2f0113d09e20 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:54:09 -0700 Subject: [PATCH 3025/5092] Resolve clippy::op_ref error: taken reference of right operand --> src/shims/env.rs:53:63 | 53 | true => !excluded_env_vars.iter().any(|v| v.as_str() == &name), | ^^^^^^^^^^^^^^----- | | | help: use the right value directly: `name` | = note: `-D clippy::op-ref` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#op_ref error: taken reference of right operand --> src/shims/env.rs:54:71 | 54 | false => config.forwarded_env_vars.iter().any(|v| v.as_str() == &name), | ^^^^^^^^^^^^^^----- | | | help: use the right value directly: `name` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#op_ref --- src/lib.rs | 1 - src/shims/env.rs | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 50d6a09eb891..cd62c0c1f3fe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,6 @@ clippy::manual_map, clippy::needless_lifetimes, clippy::new_without_default, - clippy::op_ref, clippy::redundant_closure, clippy::redundant_field_names, clippy::single_char_add_str, diff --git a/src/shims/env.rs b/src/shims/env.rs index 915decc28725..34a716f08ab2 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -50,8 +50,8 @@ impl<'tcx> EnvVars<'tcx> { if ecx.machine.communicate() || !config.forwarded_env_vars.is_empty() { for (name, value) in env::vars_os() { let forward = match ecx.machine.communicate() { - true => !excluded_env_vars.iter().any(|v| v.as_str() == &name), - false => config.forwarded_env_vars.iter().any(|v| v.as_str() == &name), + true => !excluded_env_vars.iter().any(|v| **v == name), + false => config.forwarded_env_vars.iter().any(|v| **v == name), }; if forward { let var_ptr = match target_os { From 48f4f2734d221f06990613ad364e1065608463f4 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:55:55 -0700 Subject: [PATCH 3026/5092] Resolve clippy::redundant_closure error: redundant closure --> src/data_race.rs:787:18 | 787 | .map(|idx| VectorIdx::new(idx)) | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `VectorIdx::new` | = note: `-D clippy::redundant-closure` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure error: redundant closure --> src/thread.rs:61:31 | 61 | u32::try_from(id).map(|id_u32| Self(id_u32)) | ^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `Self` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure --- src/data_race.rs | 2 +- src/lib.rs | 1 - src/thread.rs | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index b2bd29c5cb19..d249d28d03f5 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -784,7 +784,7 @@ impl VClockAlloc { None } }) - .map(|idx| VectorIdx::new(idx)) + .map(VectorIdx::new) } /// Report a data-race found in the program. diff --git a/src/lib.rs b/src/lib.rs index cd62c0c1f3fe..262c4e2e2898 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,6 @@ clippy::manual_map, clippy::needless_lifetimes, clippy::new_without_default, - clippy::redundant_closure, clippy::redundant_field_names, clippy::single_char_add_str, clippy::single_char_pattern, diff --git a/src/thread.rs b/src/thread.rs index 2ed8b3a7ce1c..0d15f60c23bf 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -58,7 +58,7 @@ impl Idx for ThreadId { impl TryFrom for ThreadId { type Error = TryFromIntError; fn try_from(id: u64) -> Result { - u32::try_from(id).map(|id_u32| Self(id_u32)) + u32::try_from(id).map(Self) } } From 2f32221fe4d3508e1823514b8638a2ee872c2fa5 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:56:46 -0700 Subject: [PATCH 3027/5092] Resolve clippy::redundant_field_names error: redundant field names in struct initialization --> src/helpers.rs:199:34 | 199 | let place = mir::Place { local: local, projection: List::empty() }; | ^^^^^^^^^^^^ help: replace it with: `local` | = note: `-D clippy::redundant-field-names` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names error: redundant field names in struct initialization --> src/thread.rs:238:13 | 238 | threads: threads, | ^^^^^^^^^^^^^^^^ help: replace it with: `threads` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names --- src/helpers.rs | 2 +- src/lib.rs | 1 - src/thread.rs | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 76a65bcbb76e..57c85575942b 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -196,7 +196,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Get the `Place` for a local fn local_place(&mut self, local: mir::Local) -> InterpResult<'tcx, PlaceTy<'tcx, Tag>> { let this = self.eval_context_mut(); - let place = mir::Place { local: local, projection: List::empty() }; + let place = mir::Place { local, projection: List::empty() }; this.eval_place(place) } diff --git a/src/lib.rs b/src/lib.rs index 262c4e2e2898..5095fc691430 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,6 @@ clippy::manual_map, clippy::needless_lifetimes, clippy::new_without_default, - clippy::redundant_field_names, clippy::single_char_add_str, clippy::single_char_pattern, clippy::single_match, diff --git a/src/thread.rs b/src/thread.rs index 0d15f60c23bf..031463f8ea74 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -235,7 +235,7 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { threads.push(main_thread); Self { active_thread: ThreadId::new(0), - threads: threads, + threads, sync: SynchronizationState::default(), thread_local_alloc_ids: Default::default(), yield_active_thread: false, From 277d0b53a7a0b8f3112baaeb2d5f31ee76bba646 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:57:35 -0700 Subject: [PATCH 3028/5092] Resolve clippy::single_char_add_str error: calling `push_str()` using a single-character string literal --> src/diagnostics.rs:299:9 | 299 | helps.last_mut().unwrap().1.push_str("\n"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `helps.last_mut().unwrap().1.push('\n')` | = note: `-D clippy::single-char-add-str` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#single_char_add_str --- src/diagnostics.rs | 2 +- src/lib.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index ce66dea5e746..1a39a1ff332e 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -296,7 +296,7 @@ fn report_msg<'mir, 'tcx>( // Show help messages. if !helps.is_empty() { // Add visual separator before backtrace. - helps.last_mut().unwrap().1.push_str("\n"); + helps.last_mut().unwrap().1.push('\n'); for (span_data, help) in helps { if let Some(span_data) = span_data { err.span_help(span_data.span(), &help); diff --git a/src/lib.rs b/src/lib.rs index 5095fc691430..536fc957a3f1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,6 @@ clippy::manual_map, clippy::needless_lifetimes, clippy::new_without_default, - clippy::single_char_add_str, clippy::single_char_pattern, clippy::single_match, clippy::unnecessary_mut_passed, From 1986f90c6ae95f2c1f49f4c11390abb9a5eb4876 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:58:13 -0700 Subject: [PATCH 3029/5092] Resolve clippy::single_char_pattern error: single-character string constant used as pattern --> src/helpers.rs:805:36 | 805 | .map(|crates| crates.split(",").map(|krate| krate.to_string()).collect::>()) | ^^^ help: try using a `char` instead: `','` | = note: `-D clippy::single-char-pattern` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#single_char_pattern --- src/helpers.rs | 2 +- src/lib.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 57c85575942b..34156c54b43d 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -802,7 +802,7 @@ pub fn get_local_crates(tcx: &TyCtxt<'_>) -> Vec { // Convert the local crate names from the passed-in config into CrateNums so that they can // be looked up quickly during execution let local_crate_names = std::env::var("MIRI_LOCAL_CRATES") - .map(|crates| crates.split(",").map(|krate| krate.to_string()).collect::>()) + .map(|crates| crates.split(',').map(|krate| krate.to_string()).collect::>()) .unwrap_or_default(); let mut local_crates = Vec::new(); for &crate_num in tcx.crates(()) { diff --git a/src/lib.rs b/src/lib.rs index 536fc957a3f1..e67f161e863b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,6 @@ clippy::manual_map, clippy::needless_lifetimes, clippy::new_without_default, - clippy::single_char_pattern, clippy::single_match, clippy::unnecessary_mut_passed, clippy::useless_conversion, From 4b523fce18e91dff63722f5de70d48a6d5dd1b83 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:59:03 -0700 Subject: [PATCH 3030/5092] Resolve clippy::unnecessary_mut_passed error: the method `validate_lock_acquire` doesn't need a mutable reference --> src/sync.rs:477:49 | 477 | data_race.validate_lock_acquire(&mut condvar.data_race, waiter.thread); | ^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::unnecessary-mut-passed` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed --- src/lib.rs | 1 - src/sync.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e67f161e863b..8e21294fd8dc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,6 @@ clippy::needless_lifetimes, clippy::new_without_default, clippy::single_match, - clippy::unnecessary_mut_passed, clippy::useless_conversion, clippy::useless_format )] diff --git a/src/sync.rs b/src/sync.rs index bbcd39333c78..ac1687a22e30 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -474,7 +474,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } condvar.waiters.pop_front().map(|waiter| { if let Some(data_race) = data_race { - data_race.validate_lock_acquire(&mut condvar.data_race, waiter.thread); + data_race.validate_lock_acquire(&condvar.data_race, waiter.thread); } (waiter.thread, waiter.mutex) }) From d35c82f79f343fa0d0c0c352e9f43a74c2b6513e Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:59:42 -0700 Subject: [PATCH 3031/5092] Resolve clippy::useless_conversion error: useless conversion to the same type: `rustc_const_eval::interpret::Pointer>` --> src/helpers.rs:668:36 | 668 | this.get_ptr_alloc(ptr.offset(len, this)?.into(), size1, Align::ONE)?.unwrap(); // not a ZST, so we will get a result | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `ptr.offset(len, this)?` | = note: `-D clippy::useless-conversion` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion error: useless conversion to the same type: `rustc_const_eval::interpret::Pointer>` --> src/helpers.rs:678:29 | 678 | this.read_bytes_ptr(ptr.into(), len) | ^^^^^^^^^^ help: consider removing `.into()`: `ptr` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion error: useless conversion to the same type: `rustc_const_eval::interpret::Pointer>` --> src/helpers.rs:690:44 | 690 | let alloc = this.get_ptr_alloc(ptr.into(), size2, align2)?.unwrap(); // not a ZST, so we will get a result | ^^^^^^^^^^ help: consider removing `.into()`: `ptr` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion error: useless conversion to the same type: `rustc_const_eval::interpret::OpTy` --> src/shims/intrinsics.rs:778:42 | 778 | .read_immediate(&this.operand_index(index, i)?.into())? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `this.operand_index(index, i)?` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion error: useless conversion to the same type: `u32` --> src/shims/posix/fs.rs:1171:26 | 1171 | builder.mode(mode.into()); | ^^^^^^^^^^^ help: consider removing `.into()`: `mode` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion error: useless conversion to the same type: `std::ffi::OsString` --> src/shims/env.rs:67:53 | 67 | ecx.machine.env_vars.map.insert(OsString::from(name), var_ptr); | ^^^^^^^^^^^^^^^^^^^^ help: consider removing `OsString::from()`: `name` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion error: useless conversion to the same type: `rustc_const_eval::interpret::Scalar` --> src/shims/tls.rs:102:44 | 102 | Ok(value.unwrap_or_else(|| Scalar::null_ptr(cx).into())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `Scalar::null_ptr(cx)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion error: useless conversion to the same type: `u32` --> src/thread.rs:73:26 | 73 | Scalar::from_u32(u32::try_from(self.0).unwrap()) | ^^^^^^^^^^^^^^^^^^^^^ | = help: consider removing `u32::try_from()` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion --- src/helpers.rs | 7 +++---- src/lib.rs | 1 - src/shims/env.rs | 2 +- src/shims/intrinsics.rs | 2 +- src/shims/posix/fs.rs | 2 +- src/shims/tls.rs | 2 +- src/thread.rs | 2 +- 7 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 34156c54b43d..107a2551995a 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -664,8 +664,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx loop { // FIXME: We are re-getting the allocation each time around the loop. // Would be nice if we could somehow "extend" an existing AllocRange. - let alloc = - this.get_ptr_alloc(ptr.offset(len, this)?.into(), size1, Align::ONE)?.unwrap(); // not a ZST, so we will get a result + let alloc = this.get_ptr_alloc(ptr.offset(len, this)?, size1, Align::ONE)?.unwrap(); // not a ZST, so we will get a result let byte = alloc.read_scalar(alloc_range(Size::ZERO, size1))?.to_u8()?; if byte == 0 { break; @@ -675,7 +674,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Step 2: get the bytes. - this.read_bytes_ptr(ptr.into(), len) + this.read_bytes_ptr(ptr, len) } fn read_wide_str(&self, mut ptr: Pointer>) -> InterpResult<'tcx, Vec> { @@ -687,7 +686,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx loop { // FIXME: We are re-getting the allocation each time around the loop. // Would be nice if we could somehow "extend" an existing AllocRange. - let alloc = this.get_ptr_alloc(ptr.into(), size2, align2)?.unwrap(); // not a ZST, so we will get a result + let alloc = this.get_ptr_alloc(ptr, size2, align2)?.unwrap(); // not a ZST, so we will get a result let wchar = alloc.read_scalar(alloc_range(Size::ZERO, size2))?.to_u16()?; if wchar == 0 { break; diff --git a/src/lib.rs b/src/lib.rs index 8e21294fd8dc..0699dfba4b7b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,6 @@ clippy::needless_lifetimes, clippy::new_without_default, clippy::single_match, - clippy::useless_conversion, clippy::useless_format )] diff --git a/src/shims/env.rs b/src/shims/env.rs index 34a716f08ab2..ae9b8c75145f 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -64,7 +64,7 @@ impl<'tcx> EnvVars<'tcx> { unsupported ), }; - ecx.machine.env_vars.map.insert(OsString::from(name), var_ptr); + ecx.machine.env_vars.map.insert(name, var_ptr); } } } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 06537b5d333b..b2c31f1c140b 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -775,7 +775,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx for i in 0..dest_len { let src_index: u64 = this - .read_immediate(&this.operand_index(index, i)?.into())? + .read_immediate(&this.operand_index(index, i)?)? .to_scalar()? .to_u32()? .into(); diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index f224a1461f93..a63b2ad80c27 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -1168,7 +1168,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[cfg(unix)] { use std::os::unix::fs::DirBuilderExt; - builder.mode(mode.into()); + builder.mode(mode); } let result = builder.create(path).map(|_| 0i32); diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 31a3e12b41bd..3de739a8d048 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -99,7 +99,7 @@ impl<'tcx> TlsData<'tcx> { Some(TlsEntry { data, .. }) => { let value = data.get(&thread_id).copied(); trace!("TLS key {} for thread {:?} loaded: {:?}", key, thread_id, value); - Ok(value.unwrap_or_else(|| Scalar::null_ptr(cx).into())) + Ok(value.unwrap_or_else(|| Scalar::null_ptr(cx))) } None => throw_ub_format!("loading from a non-existing TLS key: {}", key), } diff --git a/src/thread.rs b/src/thread.rs index 031463f8ea74..8edd6672a747 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -70,7 +70,7 @@ impl From for ThreadId { impl ThreadId { pub fn to_u32_scalar(&self) -> Scalar { - Scalar::from_u32(u32::try_from(self.0).unwrap()) + Scalar::from_u32(self.0) } } From 96036c65bfa1251c4ba2bcf1ebd2f00bfe9b4e2e Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 16:03:38 -0700 Subject: [PATCH 3032/5092] Keep remaining clippy ignores --- src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0699dfba4b7b..3f1ba574ce06 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,9 +7,8 @@ #![feature(bool_to_option)] #![feature(io_error_more)] #![warn(rust_2018_idioms)] -#![allow(clippy::cast_lossless)] -// TODO: Uncategorized. Some of these we'll want to fix, some keep ignored. #![allow( + clippy::cast_lossless, clippy::collapsible_else_if, clippy::collapsible_if, clippy::comparison_chain, From 0bdf91ddc73d80fcd5359bc9ba4882941529d928 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 20:25:04 -0700 Subject: [PATCH 3033/5092] Update GitHub Actions actions/checkout@v2 to v3 The v2 implementation uses Node 12, which is end-of-life on April 30, 2022. See https://nodejs.org/en/about/releases/. Update to v3, which is based on Node 16 whose support lasts until April 30, 2024. --- .github/workflows/ci.yml | 4 ++-- README.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 94b9dd6fe55f..0904afc82020 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: os: windows-latest host_target: i686-pc-windows-msvc steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 # We install gnu-tar because BSD tar is buggy on macOS builders of GHA. # See . @@ -97,7 +97,7 @@ jobs: name: check formatting (ignored by bors) runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install latest nightly uses: actions-rs/toolchain@v1 with: diff --git a/README.md b/README.md index ca14f02d86ae..6d5ee30e498d 100644 --- a/README.md +++ b/README.md @@ -165,7 +165,7 @@ Here is an example job for GitHub Actions: name: "Miri" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install Miri run: | rustup toolchain install nightly --component miri From f3f7e083dc92aba7a4c1818e56464fcb79f22f19 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 12 Mar 2022 17:23:22 -0500 Subject: [PATCH 3034/5092] Print spans where tags are created and invalidated --- src/diagnostics.rs | 46 +++++- src/eval.rs | 21 +++ src/helpers.rs | 9 ++ src/machine.rs | 6 +- src/stacked_borrows.rs | 311 +++++++++++++++++++++++++++++++++++------ 5 files changed, 341 insertions(+), 52 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 1a39a1ff332e..c6b6c3388cab 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -7,7 +7,8 @@ use log::trace; use rustc_middle::ty; use rustc_span::{source_map::DUMMY_SP, Span, SpanData, Symbol}; -use crate::stacked_borrows::{AccessKind, SbTag}; +use crate::helpers::HexRange; +use crate::stacked_borrows::{AccessKind, SbTag, TagHistory}; use crate::*; /// Details of premature program termination. @@ -19,6 +20,7 @@ pub enum TerminationInfo { msg: String, help: Option, url: String, + history: Option, }, Deadlock, MultipleSymbolDefinitions { @@ -155,12 +157,46 @@ pub fn report_error<'tcx, 'mir>( (None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation;")), (None, format!("or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning")), ], - ExperimentalUb { url, help, .. } => { + ExperimentalUb { url, help, history, .. } => { msg.extend(help.clone()); - vec![ + let mut helps = vec![ (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental")), - (None, format!("see {} for further information", url)) - ] + (None, format!("see {} for further information", url)), + ]; + match history { + Some(TagHistory::Tagged {tag, created: (created_range, created_span), invalidated, protected }) => { + let msg = format!("{:?} was created due to a retag at offsets {}", tag, HexRange(*created_range)); + helps.push((Some(created_span.clone()), msg)); + if let Some((invalidated_range, invalidated_span)) = invalidated { + let msg = format!("{:?} was later invalidated due to a retag at offsets {}", tag, HexRange(*invalidated_range)); + helps.push((Some(invalidated_span.clone()), msg)); + } + if let Some((protecting_tag, protecting_tag_span, protection_span)) = protected { + helps.push((Some(protecting_tag_span.clone()), format!("{:?} was protected due to {:?} which was created here", tag, protecting_tag))); + helps.push((Some(protection_span.clone()), "this protector is live for this call".to_string())); + } + } + Some(TagHistory::Untagged{ recently_created, recently_invalidated, matching_created, protected }) => { + if let Some((range, span)) = recently_created { + let msg = format!("tag was most recently created at offsets {}", HexRange(*range)); + helps.push((Some(span.clone()), msg)); + } + if let Some((range, span)) = recently_invalidated { + let msg = format!("tag was later invalidated at offsets {}", HexRange(*range)); + helps.push((Some(span.clone()), msg)); + } + if let Some((range, span)) = matching_created { + let msg = format!("this tag was also created here at offsets {}", HexRange(*range)); + helps.push((Some(span.clone()), msg)); + } + if let Some((protecting_tag, protecting_tag_span, protection_span)) = protected { + helps.push((Some(protecting_tag_span.clone()), format!("{:?} was protected due to a tag which was created here", protecting_tag))); + helps.push((Some(protection_span.clone()), "this protector is live for this call".to_string())); + } + } + None => {} + } + helps } MultipleSymbolDefinitions { first, first_crate, second, second_crate, .. } => vec![ diff --git a/src/eval.rs b/src/eval.rs index f8d23cb8279c..8b964ba90f04 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -283,6 +283,24 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( Ok((ecx, ret_place)) } +// This is potentially a performance hazard. +// Factoring it into its own function lets us keep an eye on how much it shows up in a profile. +fn set_current_span<'mir, 'tcx: 'mir>(ecx: &mut MiriEvalContext<'mir, 'tcx>) { + let current_span = Machine::stack(&ecx) + .into_iter() + .rev() + .find(|frame| { + let info = + FrameInfo { instance: frame.instance, span: frame.current_span(), lint_root: None }; + ecx.machine.is_local(&info) + }) + .map(|frame| frame.current_span()) + .unwrap_or(rustc_span::DUMMY_SP); + if let Some(sb) = ecx.machine.stacked_borrows.as_mut() { + sb.get_mut().current_span = current_span; + } +} + /// Evaluates the entry function specified by `entry_id`. /// Returns `Some(return_code)` if program executed completed. /// Returns `None` if an evaluation error occured. @@ -310,6 +328,9 @@ pub fn eval_entry<'tcx>( let info = ecx.preprocess_diagnostics(); match ecx.schedule()? { SchedulingAction::ExecuteStep => { + if ecx.machine.stacked_borrows.is_some() { + set_current_span(&mut ecx); + } assert!(ecx.step()?, "a terminated thread was scheduled for execution"); } SchedulingAction::ExecuteTimeoutCallback => { diff --git a/src/helpers.rs b/src/helpers.rs index 107a2551995a..8d7147fff7a4 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -813,3 +813,12 @@ pub fn get_local_crates(tcx: &TyCtxt<'_>) -> Vec { } local_crates } + +/// Formats an AllocRange like [0x1..0x3], for use in diagnostics. +pub struct HexRange(pub AllocRange); + +impl std::fmt::Display for HexRange { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "[{:#x}..{:#x}]", self.0.start.bytes(), self.0.end().bytes()) + } +} diff --git a/src/machine.rs b/src/machine.rs index 0a8a229c8aa2..5f25fd298865 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -632,7 +632,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { alloc_id, tag, range, - machine.stacked_borrows.as_ref().unwrap(), + machine.stacked_borrows.as_ref().unwrap(), ) } else { Ok(()) @@ -655,7 +655,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { alloc_id, tag, range, - machine.stacked_borrows.as_mut().unwrap(), + machine.stacked_borrows.as_ref().unwrap(), ) } else { Ok(()) @@ -681,7 +681,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { alloc_id, tag, range, - machine.stacked_borrows.as_mut().unwrap(), + machine.stacked_borrows.as_ref().unwrap(), ) } else { Ok(()) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index d6caba81713c..225407a7bbfa 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -3,6 +3,7 @@ use log::trace; use std::cell::RefCell; +use std::collections::HashMap; use std::fmt; use std::num::NonZeroU64; @@ -14,9 +15,11 @@ use rustc_middle::ty::{ layout::{HasParamEnv, LayoutOf}, }; use rustc_span::DUMMY_SP; +use rustc_span::{Span, SpanData}; use rustc_target::abi::Size; use std::collections::HashSet; +use crate::helpers::HexRange; use crate::*; pub type PtrId = NonZeroU64; @@ -111,7 +114,53 @@ pub struct GlobalStateInner { tracked_call_ids: HashSet, /// Whether to track raw pointers. tag_raw: bool, + /// Extra per-allocation information + extras: HashMap, + /// Current span + pub(crate) current_span: Span, } + +#[derive(Debug, Default)] +struct AllocHistory { + // The time tags can be compressed down to one bit per event, by just storing a Vec + // where each bit is set to indicate if the event was a creation or a retag + current_time: usize, + creations: Vec, + invalidations: Vec, + protectors: Vec, +} + +#[derive(Debug)] +struct Protection { + orig_tag: SbTag, + tag: SbTag, + span: Span, +} + +#[derive(Debug)] +struct Event { + time: usize, + parent: Option, + tag: SbTag, + range: AllocRange, + span: Span, +} + +pub enum TagHistory { + Tagged { + tag: SbTag, + created: (AllocRange, SpanData), + invalidated: Option<(AllocRange, SpanData)>, + protected: Option<(SbTag, SpanData, SpanData)>, + }, + Untagged { + recently_created: Option<(AllocRange, SpanData)>, + recently_invalidated: Option<(AllocRange, SpanData)>, + matching_created: Option<(AllocRange, SpanData)>, + protected: Option<(SbTag, SpanData, SpanData)>, + }, +} + /// We need interior mutable access to the global state. pub type GlobalState = RefCell; @@ -171,6 +220,8 @@ impl GlobalStateInner { tracked_pointer_tags, tracked_call_ids, tag_raw, + extras: HashMap::new(), + current_span: DUMMY_SP, } } @@ -218,16 +269,155 @@ impl GlobalStateInner { self.base_ptr_ids.try_insert(id, tag).unwrap(); tag } + + fn add_creation( + &mut self, + parent: Option, + tag: SbTag, + alloc: AllocId, + range: AllocRange, + ) { + let extras = self.extras.entry(alloc).or_default(); + extras.creations.push(Event { + parent, + tag, + range, + span: self.current_span, + time: extras.current_time, + }); + extras.current_time += 1; + } + + fn add_invalidation(&mut self, tag: SbTag, alloc: AllocId, range: AllocRange) { + let extras = self.extras.entry(alloc).or_default(); + extras.invalidations.push(Event { + parent: None, + tag, + range, + span: self.current_span, + time: extras.current_time, + }); + extras.current_time += 1; + } + + fn add_protector(&mut self, orig_tag: SbTag, tag: SbTag, alloc: AllocId) { + let extras = self.extras.entry(alloc).or_default(); + extras.protectors.push(Protection { orig_tag, tag, span: self.current_span }); + extras.current_time += 1; + } + + fn get_stack_history( + &self, + tag: SbTag, + alloc: AllocId, + alloc_range: AllocRange, + offset: Size, + protector_tag: Option, + ) -> Option { + let extras = self.extras.get(&alloc)?; + let protected = protector_tag + .and_then(|protector| { + extras.protectors.iter().find_map(|protection| { + if protection.tag == protector { + Some((protection.orig_tag, protection.span.data())) + } else { + None + } + }) + }) + .and_then(|(tag, call_span)| { + extras.creations.iter().rev().find_map(|event| { + if event.tag == tag { + Some((event.parent?, event.span.data(), call_span)) + } else { + None + } + }) + }); + if let SbTag::Tagged(_) = tag { + let get_matching = |events: &[Event]| { + events.iter().rev().find_map(|event| { + if event.tag == tag { Some((event.range, event.span.data())) } else { None } + }) + }; + Some(TagHistory::Tagged { + tag, + created: get_matching(&extras.creations)?, + invalidated: get_matching(&extras.invalidations), + protected, + }) + } else { + let mut created_time = 0; + // Find the most recently created tag that satsfies this offset + let recently_created = extras.creations.iter().rev().find_map(|event| { + if event.tag == tag && offset >= event.range.start && offset < event.range.end() { + created_time = event.time; + Some((event.range, event.span.data())) + } else { + None + } + }); + + // Find a different recently created tag that satisfies this whole operation, predates + // the recently created tag, and has a different span. + // We're trying to make a guess at which span the user wanted to provide the tag that + // they're using. + let matching_created = if let Some((_created_range, created_span)) = recently_created { + extras.creations.iter().rev().find_map(|event| { + if event.tag == tag + && alloc_range.start >= event.range.start + && alloc_range.end() <= event.range.end() + && event.span.data() != created_span + && event.time != created_time + { + Some((event.range, event.span.data())) + } else { + None + } + }) + } else { + None + }; + + let recently_invalidated = if recently_created.is_some() { + // Find the most recent invalidation of this tag which post-dates the creation + let mut found = None; + for event in extras.invalidations.iter().rev() { + if event.time < created_time { + break; + } + if event.tag == tag && offset >= event.range.start && offset < event.range.end() + { + found = Some((event.range, event.span.data())) + } + } + found + } else { + None + }; + Some(TagHistory::Untagged { + recently_created, + matching_created, + recently_invalidated, + protected, + }) + } + } } /// Error reporting -fn err_sb_ub(msg: String, help: Option) -> InterpError<'static> { +fn err_sb_ub( + msg: String, + help: Option, + history: Option, +) -> InterpError<'static> { err_machine_stop!(TerminationInfo::ExperimentalUb { msg, help, url: format!( "https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md" ), + history }) } @@ -308,31 +498,39 @@ impl<'tcx> Stack { /// `None` during a deallocation. fn check_protector( item: &Item, - provoking_access: Option<(SbTag, AccessKind)>, + provoking_access: Option<(SbTag, AllocId, AllocRange, Size)>, // just for debug printing amd error messages global: &GlobalStateInner, ) -> InterpResult<'tcx> { if let SbTag::Tagged(id) = item.tag { if global.tracked_pointer_tags.contains(&id) { register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag( *item, - provoking_access, + None, )); } } if let Some(call) = item.protector { if global.is_active(call) { - if let Some((tag, _)) = provoking_access { + if let Some((tag, alloc_id, alloc_range, offset)) = provoking_access { Err(err_sb_ub( format!( "not granting access to tag {:?} because incompatible item is protected: {:?}", tag, item ), None, + global.get_stack_history( + tag, + alloc_id, + alloc_range, + offset, + Some(item.tag), + ), ))? } else { Err(err_sb_ub( format!("deallocating while item is protected: {:?}", item), None, + None, ))? } } @@ -348,15 +546,15 @@ impl<'tcx> Stack { &mut self, access: AccessKind, tag: SbTag, - (alloc_id, range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages - global: &GlobalStateInner, + (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages + global: &mut GlobalStateInner, ) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. - let granting_idx = self - .find_granting(access, tag) - .ok_or_else(|| self.access_error(access, tag, alloc_id, range, offset))?; + let granting_idx = self.find_granting(access, tag).ok_or_else(|| { + self.access_error(access, tag, alloc_id, alloc_range, offset, global) + })?; // Step 2: Remove incompatible items above them. Make sure we do not remove protected // items. Behavior differs for reads and writes. @@ -366,7 +564,8 @@ impl<'tcx> Stack { let first_incompatible_idx = self.find_first_write_incompatible(granting_idx); for item in self.borrows.drain(first_incompatible_idx..).rev() { trace!("access: popping item {:?}", item); - Stack::check_protector(&item, Some((tag, access)), global)?; + Stack::check_protector(&item, Some((tag, alloc_id, alloc_range, offset)), global)?; + global.add_invalidation(item.tag, alloc_id, alloc_range); } } else { // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses. @@ -381,8 +580,13 @@ impl<'tcx> Stack { let item = &mut self.borrows[idx]; if item.perm == Permission::Unique { trace!("access: disabling item {:?}", item); - Stack::check_protector(item, Some((tag, access)), global)?; + Stack::check_protector( + item, + Some((tag, alloc_id, alloc_range, offset)), + global, + )?; item.perm = Permission::Disabled; + global.add_invalidation(item.tag, alloc_id, alloc_range); } } } @@ -396,15 +600,18 @@ impl<'tcx> Stack { fn dealloc( &mut self, tag: SbTag, - dbg_ptr: Pointer, // just for debug printing and error messages + (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing amd error messages global: &GlobalStateInner, ) -> InterpResult<'tcx> { // Step 1: Find granting item. self.find_granting(AccessKind::Write, tag).ok_or_else(|| { err_sb_ub(format!( "no item granting write access for deallocation to tag {:?} at {:?} found in borrow stack", - tag, dbg_ptr, - ), None) + tag, alloc_id, + ), + None, + global.get_stack_history(tag, alloc_id, alloc_range, offset, None), + ) })?; // Step 2: Remove all items. Also checks for protectors. @@ -426,16 +633,16 @@ impl<'tcx> Stack { derived_from: SbTag, new: Item, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages - global: &GlobalStateInner, + global: &mut GlobalStateInner, ) -> InterpResult<'tcx> { // Figure out which access `perm` corresponds to. let access = if new.perm.grants(AccessKind::Write) { AccessKind::Write } else { AccessKind::Read }; // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. - let granting_idx = self - .find_granting(access, derived_from) - .ok_or_else(|| self.grant_error(derived_from, new, alloc_id, alloc_range, offset))?; + let granting_idx = self.find_granting(access, derived_from).ok_or_else(|| { + self.grant_error(derived_from, new, alloc_id, alloc_range, offset, global) + })?; // Compute where to put the new item. // Either way, we ensure that we insert the new item in a way such that between @@ -483,6 +690,7 @@ impl<'tcx> Stack { alloc_id: AllocId, alloc_range: AllocRange, error_offset: Size, + global: &GlobalStateInner, ) -> InterpError<'static> { let action = format!( "trying to reborrow {:?} for {:?} permission at {}[{:#x}]", @@ -494,6 +702,7 @@ impl<'tcx> Stack { err_sb_ub( format!("{}{}", action, self.error_cause(derived_from)), Some(Self::operation_summary("a reborrow", alloc_id, alloc_range)), + global.get_stack_history(derived_from, alloc_id, alloc_range, error_offset, None), ) } @@ -505,6 +714,7 @@ impl<'tcx> Stack { alloc_id: AllocId, alloc_range: AllocRange, error_offset: Size, + global: &GlobalStateInner, ) -> InterpError<'static> { let action = format!( "attempting a {} using {:?} at {}[{:#x}]", @@ -516,6 +726,7 @@ impl<'tcx> Stack { err_sb_ub( format!("{}{}", action, self.error_cause(tag)), Some(Self::operation_summary("an access", alloc_id, alloc_range)), + global.get_stack_history(tag, alloc_id, alloc_range, error_offset, None), ) } @@ -525,11 +736,10 @@ impl<'tcx> Stack { alloc_range: AllocRange, ) -> String { format!( - "this error occurs as part of {} at {:?}[{:#x}..{:#x}]", + "this error occurs as part of {} at {:?}{}", operation, alloc_id, - alloc_range.start.bytes(), - alloc_range.end().bytes() + HexRange(alloc_range) ) } @@ -620,6 +830,7 @@ impl Stacks { (tag, Permission::SharedReadWrite) } }; + extra.add_creation(None, base_tag, id, alloc_range(Size::ZERO, size)); Stacks::new(size, perm, base_tag) } @@ -637,11 +848,11 @@ impl Stacks { Pointer::new(alloc_id, range.start), range.size.bytes() ); - let global = &*state.borrow(); self.for_each(range, move |offset, stack| { - stack.access(AccessKind::Read, tag, (alloc_id, range, offset), global) + let mut state = state.borrow_mut(); + stack.access(AccessKind::Read, tag, (alloc_id, range, offset), &mut state) }) - } + } #[inline(always)] pub fn memory_written<'tcx>( @@ -649,7 +860,7 @@ impl Stacks { alloc_id: AllocId, tag: SbTag, range: AllocRange, - state: &mut GlobalState, + state: &GlobalState, ) -> InterpResult<'tcx> { trace!( "write access with tag {:?}: {:?}, size {}", @@ -657,9 +868,9 @@ impl Stacks { Pointer::new(alloc_id, range.start), range.size.bytes() ); - let global = state.get_mut(); self.for_each_mut(range, move |offset, stack| { - stack.access(AccessKind::Write, tag, (alloc_id, range, offset), global) + let mut state = state.borrow_mut(); + stack.access(AccessKind::Write, tag, (alloc_id, range, offset), &mut state) }) } @@ -669,13 +880,15 @@ impl Stacks { alloc_id: AllocId, tag: SbTag, range: AllocRange, - state: &mut GlobalState, + state: &GlobalState, ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", tag, alloc_id, range.size.bytes()); - let global = state.get_mut(); self.for_each_mut(range, move |offset, stack| { - stack.dealloc(tag, Pointer::new(alloc_id, offset), global) - }) + let mut state = state.borrow_mut(); + stack.dealloc(tag, (alloc_id, range, offset), &mut state) + })?; + state.borrow_mut().extras.remove(&alloc_id); + Ok(()) } } @@ -705,6 +918,17 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?; + let mem_extra = this.machine.stacked_borrows.as_mut().unwrap().get_mut(); + mem_extra.add_creation( + Some(orig_tag), + new_tag, + alloc_id, + alloc_range(base_offset, base_offset + size), + ); + if protect { + mem_extra.add_protector(orig_tag, new_tag, alloc_id); + } + // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). let (alloc_size, _) = this.get_alloc_size_and_align(alloc_id, AllocCheck::Dereferenceable)?; @@ -753,7 +977,6 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let extra = this.get_alloc_extra(alloc_id)?; let stacked_borrows = extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); - let global = this.machine.stacked_borrows.as_ref().unwrap().borrow(); this.visit_freeze_sensitive(place, size, |mut range, frozen| { // Adjust range. range.start += base_offset; @@ -765,7 +988,9 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; let item = Item { perm, tag: new_tag, protector }; stacked_borrows.for_each(range, |offset, stack| { - stack.grant(orig_tag, item, (alloc_id, range, offset), &*global) + let mut global = + this.machine.stacked_borrows.as_ref().unwrap().borrow_mut(); + stack.grant(orig_tag, item, (alloc_id, range, offset), &mut *global) }) })?; return Ok(()); @@ -777,11 +1002,11 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (alloc_extra, memory_extra) = this.get_alloc_extra_mut(alloc_id)?; let stacked_borrows = alloc_extra.stacked_borrows.as_mut().expect("we should have Stacked Borrows data"); - let global = memory_extra.stacked_borrows.as_mut().unwrap().get_mut(); let item = Item { perm, tag: new_tag, protector }; let range = alloc_range(base_offset, size); - stacked_borrows.for_each_mut(alloc_range(base_offset, size), |offset, stack| { - stack.grant(orig_tag, item, (alloc_id, range, offset), global) + stacked_borrows.for_each_mut(range, |offset, stack| { + let mut global = memory_extra.stacked_borrows.as_ref().unwrap().borrow_mut(); + stack.grant(orig_tag, item, (alloc_id, range, offset), &mut *global) })?; Ok(()) } @@ -807,14 +1032,12 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Compute new borrow. - let new_tag = { - let mem_extra = this.machine.stacked_borrows.as_mut().unwrap().get_mut(); - match kind { - // Give up tracking for raw pointers. - RefKind::Raw { .. } if !mem_extra.tag_raw => SbTag::Untagged, - // All other pointers are properly tracked. - _ => SbTag::Tagged(mem_extra.new_ptr()), - } + let mem_extra = this.machine.stacked_borrows.as_mut().unwrap().get_mut(); + let new_tag = match kind { + // Give up tracking for raw pointers. + RefKind::Raw { .. } if !mem_extra.tag_raw => SbTag::Untagged, + // All other pointers are properly tracked. + _ => SbTag::Tagged(mem_extra.new_ptr()), }; // Reborrow. From 5861d137b25997a7f4947fe6046003d2d0facde2 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Fri, 15 Apr 2022 23:04:07 -0400 Subject: [PATCH 3035/5092] Set the current span (somewhat) lazily --- src/diagnostics.rs | 4 ++-- src/eval.rs | 23 +++----------------- src/machine.rs | 48 +++++++++++++++++++++++++++++++++++++++--- src/stacked_borrows.rs | 14 ++++++------ src/thread.rs | 2 +- 5 files changed, 58 insertions(+), 33 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index c6b6c3388cab..bba1989e2d58 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -165,10 +165,10 @@ pub fn report_error<'tcx, 'mir>( ]; match history { Some(TagHistory::Tagged {tag, created: (created_range, created_span), invalidated, protected }) => { - let msg = format!("{:?} was created due to a retag at offsets {}", tag, HexRange(*created_range)); + let msg = format!("{:?} was created by a retag at offsets {}", tag, HexRange(*created_range)); helps.push((Some(created_span.clone()), msg)); if let Some((invalidated_range, invalidated_span)) = invalidated { - let msg = format!("{:?} was later invalidated due to a retag at offsets {}", tag, HexRange(*invalidated_range)); + let msg = format!("{:?} was later invalidated at offsets {}", tag, HexRange(*invalidated_range)); helps.push((Some(invalidated_span.clone()), msg)); } if let Some((protecting_tag, protecting_tag_span, protection_span)) = protected { diff --git a/src/eval.rs b/src/eval.rs index 8b964ba90f04..80738d33e0b9 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -16,6 +16,7 @@ use rustc_target::spec::abi::Abi; use rustc_session::config::EntryFnType; use std::collections::HashSet; +use rustc_span::DUMMY_SP; use crate::*; @@ -283,24 +284,6 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( Ok((ecx, ret_place)) } -// This is potentially a performance hazard. -// Factoring it into its own function lets us keep an eye on how much it shows up in a profile. -fn set_current_span<'mir, 'tcx: 'mir>(ecx: &mut MiriEvalContext<'mir, 'tcx>) { - let current_span = Machine::stack(&ecx) - .into_iter() - .rev() - .find(|frame| { - let info = - FrameInfo { instance: frame.instance, span: frame.current_span(), lint_root: None }; - ecx.machine.is_local(&info) - }) - .map(|frame| frame.current_span()) - .unwrap_or(rustc_span::DUMMY_SP); - if let Some(sb) = ecx.machine.stacked_borrows.as_mut() { - sb.get_mut().current_span = current_span; - } -} - /// Evaluates the entry function specified by `entry_id`. /// Returns `Some(return_code)` if program executed completed. /// Returns `None` if an evaluation error occured. @@ -328,8 +311,8 @@ pub fn eval_entry<'tcx>( let info = ecx.preprocess_diagnostics(); match ecx.schedule()? { SchedulingAction::ExecuteStep => { - if ecx.machine.stacked_borrows.is_some() { - set_current_span(&mut ecx); + if let Some(sb) = ecx.machine.stacked_borrows.as_mut() { + sb.get_mut().current_span = DUMMY_SP; } assert!(ecx.step()?, "a terminated thread was scheduled for execution"); } diff --git a/src/machine.rs b/src/machine.rs index 5f25fd298865..de9aaa2859d8 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -25,6 +25,7 @@ use rustc_middle::{ }; use rustc_span::def_id::{CrateNum, DefId}; use rustc_span::symbol::{sym, Symbol}; +use rustc_span::DUMMY_SP; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; @@ -561,6 +562,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { alloc: Cow<'b, Allocation>, kind: Option>, ) -> Cow<'b, Allocation> { + set_current_span(&ecx.machine); if ecx.machine.tracked_alloc_ids.contains(&id) { register_diagnostic(NonHaltingDiagnostic::CreatedAlloc(id)); } @@ -589,6 +591,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer, ) -> Pointer { + set_current_span(&ecx.machine); let absolute_addr = intptrcast::GlobalStateInner::rel_ptr_to_addr(ecx, ptr); let sb_tag = if let Some(stacked_borrows) = &ecx.machine.stacked_borrows { stacked_borrows.borrow_mut().base_tag(ptr.provenance) @@ -624,6 +627,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { (alloc_id, tag): (AllocId, Self::TagExtra), range: AllocRange, ) -> InterpResult<'tcx> { + set_current_span(&machine); if let Some(data_race) = &alloc_extra.data_race { data_race.read(alloc_id, range, machine.data_race.as_ref().unwrap())?; } @@ -632,7 +636,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { alloc_id, tag, range, - machine.stacked_borrows.as_ref().unwrap(), + machine.stacked_borrows.as_ref().unwrap(), ) } else { Ok(()) @@ -647,6 +651,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { (alloc_id, tag): (AllocId, Self::TagExtra), range: AllocRange, ) -> InterpResult<'tcx> { + set_current_span(&machine); if let Some(data_race) = &mut alloc_extra.data_race { data_race.write(alloc_id, range, machine.data_race.as_mut().unwrap())?; } @@ -670,6 +675,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { (alloc_id, tag): (AllocId, Self::TagExtra), range: AllocRange, ) -> InterpResult<'tcx> { + set_current_span(&machine); if machine.tracked_alloc_ids.contains(&alloc_id) { register_diagnostic(NonHaltingDiagnostic::FreedAlloc(alloc_id)); } @@ -694,7 +700,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { kind: mir::RetagKind, place: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { - if ecx.machine.stacked_borrows.is_some() { ecx.retag(kind, place) } else { Ok(()) } + if ecx.machine.stacked_borrows.is_some() { + set_current_span(&ecx.machine); + ecx.retag(kind, place) + } else { + Ok(()) + } } #[inline(always)] @@ -740,7 +751,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn after_stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { - if ecx.machine.stacked_borrows.is_some() { ecx.retag_return_place() } else { Ok(()) } + if ecx.machine.stacked_borrows.is_some() { + set_current_span(&ecx.machine); + ecx.retag_return_place() + } else { + Ok(()) + } } #[inline(always)] @@ -757,3 +773,29 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { res } } + +// This is potentially a performance hazard. +// Factoring it into its own function lets us keep an eye on how much it shows up in a profile. +fn set_current_span<'mir, 'tcx: 'mir>(machine: &Evaluator<'mir, 'tcx>) { + if let Some(sb) = machine.stacked_borrows.as_ref() { + if sb.borrow().current_span != DUMMY_SP { + return; + } + let current_span = machine + .threads + .active_thread_stack() + .into_iter() + .rev() + .find(|frame| { + let info = FrameInfo { + instance: frame.instance, + span: frame.current_span(), + lint_root: None, + }; + machine.is_local(&info) + }) + .map(|frame| frame.current_span()) + .unwrap_or(rustc_span::DUMMY_SP); + sb.borrow_mut().current_span = current_span; + } +} diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 225407a7bbfa..fcb702ea6ba8 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -125,9 +125,9 @@ struct AllocHistory { // The time tags can be compressed down to one bit per event, by just storing a Vec // where each bit is set to indicate if the event was a creation or a retag current_time: usize, - creations: Vec, - invalidations: Vec, - protectors: Vec, + creations: smallvec::SmallVec<[Event; 2]>, + invalidations: smallvec::SmallVec<[Event; 1]>, + protectors: smallvec::SmallVec<[Protection; 1]>, } #[derive(Debug)] @@ -552,9 +552,9 @@ impl<'tcx> Stack { // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. - let granting_idx = self.find_granting(access, tag).ok_or_else(|| { - self.access_error(access, tag, alloc_id, alloc_range, offset, global) - })?; + let granting_idx = self + .find_granting(access, tag) + .ok_or_else(|| self.access_error(access, tag, alloc_id, alloc_range, offset, global))?; // Step 2: Remove incompatible items above them. Make sure we do not remove protected // items. Behavior differs for reads and writes. @@ -852,7 +852,7 @@ impl Stacks { let mut state = state.borrow_mut(); stack.access(AccessKind::Read, tag, (alloc_id, range, offset), &mut state) }) - } + } #[inline(always)] pub fn memory_written<'tcx>( diff --git a/src/thread.rs b/src/thread.rs index 8edd6672a747..5673af048fc5 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -263,7 +263,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Borrow the stack of the active thread. - fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] { + pub fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] { &self.threads[self.active_thread].stack } From cddd85e2f30fb185de55209f5843a235cdc79a88 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Mon, 25 Apr 2022 14:18:52 -0400 Subject: [PATCH 3036/5092] Move SB diagnostics to a module --- src/diagnostics.rs | 2 +- src/eval.rs | 2 +- src/machine.rs | 1 + src/stacked_borrows.rs | 258 +------------------------ src/stacked_borrows/diagnostics.rs | 299 +++++++++++++++++++++++++++++ 5 files changed, 311 insertions(+), 251 deletions(-) create mode 100644 src/stacked_borrows/diagnostics.rs diff --git a/src/diagnostics.rs b/src/diagnostics.rs index bba1989e2d58..56cd3bb83def 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -8,7 +8,7 @@ use rustc_middle::ty; use rustc_span::{source_map::DUMMY_SP, Span, SpanData, Symbol}; use crate::helpers::HexRange; -use crate::stacked_borrows::{AccessKind, SbTag, TagHistory}; +use crate::stacked_borrows::{diagnostics::TagHistory, AccessKind, SbTag}; use crate::*; /// Details of premature program termination. diff --git a/src/eval.rs b/src/eval.rs index 80738d33e0b9..a3228f763a8e 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -15,8 +15,8 @@ use rustc_target::spec::abi::Abi; use rustc_session::config::EntryFnType; -use std::collections::HashSet; use rustc_span::DUMMY_SP; +use std::collections::HashSet; use crate::*; diff --git a/src/machine.rs b/src/machine.rs index de9aaa2859d8..2fb5dca6dd68 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -776,6 +776,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { // This is potentially a performance hazard. // Factoring it into its own function lets us keep an eye on how much it shows up in a profile. +/// fn set_current_span<'mir, 'tcx: 'mir>(machine: &Evaluator<'mir, 'tcx>) { if let Some(sb) = machine.stacked_borrows.as_ref() { if sb.borrow().current_span != DUMMY_SP { diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index fcb702ea6ba8..6ffa89087e86 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -14,14 +14,18 @@ use rustc_middle::ty::{ self, layout::{HasParamEnv, LayoutOf}, }; +use rustc_span::Span; use rustc_span::DUMMY_SP; -use rustc_span::{Span, SpanData}; use rustc_target::abi::Size; use std::collections::HashSet; -use crate::helpers::HexRange; use crate::*; +pub mod diagnostics; +use diagnostics::{AllocHistory, GlobalStateExt, StackExt}; + +use diagnostics::TagHistory; + pub type PtrId = NonZeroU64; pub type CallId = NonZeroU64; pub type AllocExtra = Stacks; @@ -120,47 +124,6 @@ pub struct GlobalStateInner { pub(crate) current_span: Span, } -#[derive(Debug, Default)] -struct AllocHistory { - // The time tags can be compressed down to one bit per event, by just storing a Vec - // where each bit is set to indicate if the event was a creation or a retag - current_time: usize, - creations: smallvec::SmallVec<[Event; 2]>, - invalidations: smallvec::SmallVec<[Event; 1]>, - protectors: smallvec::SmallVec<[Protection; 1]>, -} - -#[derive(Debug)] -struct Protection { - orig_tag: SbTag, - tag: SbTag, - span: Span, -} - -#[derive(Debug)] -struct Event { - time: usize, - parent: Option, - tag: SbTag, - range: AllocRange, - span: Span, -} - -pub enum TagHistory { - Tagged { - tag: SbTag, - created: (AllocRange, SpanData), - invalidated: Option<(AllocRange, SpanData)>, - protected: Option<(SbTag, SpanData, SpanData)>, - }, - Untagged { - recently_created: Option<(AllocRange, SpanData)>, - recently_invalidated: Option<(AllocRange, SpanData)>, - matching_created: Option<(AllocRange, SpanData)>, - protected: Option<(SbTag, SpanData, SpanData)>, - }, -} - /// We need interior mutable access to the global state. pub type GlobalState = RefCell; @@ -269,144 +232,10 @@ impl GlobalStateInner { self.base_ptr_ids.try_insert(id, tag).unwrap(); tag } - - fn add_creation( - &mut self, - parent: Option, - tag: SbTag, - alloc: AllocId, - range: AllocRange, - ) { - let extras = self.extras.entry(alloc).or_default(); - extras.creations.push(Event { - parent, - tag, - range, - span: self.current_span, - time: extras.current_time, - }); - extras.current_time += 1; - } - - fn add_invalidation(&mut self, tag: SbTag, alloc: AllocId, range: AllocRange) { - let extras = self.extras.entry(alloc).or_default(); - extras.invalidations.push(Event { - parent: None, - tag, - range, - span: self.current_span, - time: extras.current_time, - }); - extras.current_time += 1; - } - - fn add_protector(&mut self, orig_tag: SbTag, tag: SbTag, alloc: AllocId) { - let extras = self.extras.entry(alloc).or_default(); - extras.protectors.push(Protection { orig_tag, tag, span: self.current_span }); - extras.current_time += 1; - } - - fn get_stack_history( - &self, - tag: SbTag, - alloc: AllocId, - alloc_range: AllocRange, - offset: Size, - protector_tag: Option, - ) -> Option { - let extras = self.extras.get(&alloc)?; - let protected = protector_tag - .and_then(|protector| { - extras.protectors.iter().find_map(|protection| { - if protection.tag == protector { - Some((protection.orig_tag, protection.span.data())) - } else { - None - } - }) - }) - .and_then(|(tag, call_span)| { - extras.creations.iter().rev().find_map(|event| { - if event.tag == tag { - Some((event.parent?, event.span.data(), call_span)) - } else { - None - } - }) - }); - if let SbTag::Tagged(_) = tag { - let get_matching = |events: &[Event]| { - events.iter().rev().find_map(|event| { - if event.tag == tag { Some((event.range, event.span.data())) } else { None } - }) - }; - Some(TagHistory::Tagged { - tag, - created: get_matching(&extras.creations)?, - invalidated: get_matching(&extras.invalidations), - protected, - }) - } else { - let mut created_time = 0; - // Find the most recently created tag that satsfies this offset - let recently_created = extras.creations.iter().rev().find_map(|event| { - if event.tag == tag && offset >= event.range.start && offset < event.range.end() { - created_time = event.time; - Some((event.range, event.span.data())) - } else { - None - } - }); - - // Find a different recently created tag that satisfies this whole operation, predates - // the recently created tag, and has a different span. - // We're trying to make a guess at which span the user wanted to provide the tag that - // they're using. - let matching_created = if let Some((_created_range, created_span)) = recently_created { - extras.creations.iter().rev().find_map(|event| { - if event.tag == tag - && alloc_range.start >= event.range.start - && alloc_range.end() <= event.range.end() - && event.span.data() != created_span - && event.time != created_time - { - Some((event.range, event.span.data())) - } else { - None - } - }) - } else { - None - }; - - let recently_invalidated = if recently_created.is_some() { - // Find the most recent invalidation of this tag which post-dates the creation - let mut found = None; - for event in extras.invalidations.iter().rev() { - if event.time < created_time { - break; - } - if event.tag == tag && offset >= event.range.start && offset < event.range.end() - { - found = Some((event.range, event.span.data())) - } - } - found - } else { - None - }; - Some(TagHistory::Untagged { - recently_created, - matching_created, - recently_invalidated, - protected, - }) - } - } } /// Error reporting -fn err_sb_ub( +pub fn err_sb_ub( msg: String, help: Option, history: Option, @@ -498,7 +327,7 @@ impl<'tcx> Stack { /// `None` during a deallocation. fn check_protector( item: &Item, - provoking_access: Option<(SbTag, AllocId, AllocRange, Size)>, // just for debug printing amd error messages + provoking_access: Option<(SbTag, AllocId, AllocRange, Size)>, // just for debug printing and error messages global: &GlobalStateInner, ) -> InterpResult<'tcx> { if let SbTag::Tagged(id) = item.tag { @@ -600,7 +429,7 @@ impl<'tcx> Stack { fn dealloc( &mut self, tag: SbTag, - (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing amd error messages + (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &GlobalStateInner, ) -> InterpResult<'tcx> { // Step 1: Find granting item. @@ -681,75 +510,6 @@ impl<'tcx> Stack { Ok(()) } - - /// Report a descriptive error when `new` could not be granted from `derived_from`. - fn grant_error( - &self, - derived_from: SbTag, - new: Item, - alloc_id: AllocId, - alloc_range: AllocRange, - error_offset: Size, - global: &GlobalStateInner, - ) -> InterpError<'static> { - let action = format!( - "trying to reborrow {:?} for {:?} permission at {}[{:#x}]", - derived_from, - new.perm, - alloc_id, - error_offset.bytes(), - ); - err_sb_ub( - format!("{}{}", action, self.error_cause(derived_from)), - Some(Self::operation_summary("a reborrow", alloc_id, alloc_range)), - global.get_stack_history(derived_from, alloc_id, alloc_range, error_offset, None), - ) - } - - /// Report a descriptive error when `access` is not permitted based on `tag`. - fn access_error( - &self, - access: AccessKind, - tag: SbTag, - alloc_id: AllocId, - alloc_range: AllocRange, - error_offset: Size, - global: &GlobalStateInner, - ) -> InterpError<'static> { - let action = format!( - "attempting a {} using {:?} at {}[{:#x}]", - access, - tag, - alloc_id, - error_offset.bytes(), - ); - err_sb_ub( - format!("{}{}", action, self.error_cause(tag)), - Some(Self::operation_summary("an access", alloc_id, alloc_range)), - global.get_stack_history(tag, alloc_id, alloc_range, error_offset, None), - ) - } - - fn operation_summary( - operation: &'static str, - alloc_id: AllocId, - alloc_range: AllocRange, - ) -> String { - format!( - "this error occurs as part of {} at {:?}{}", - operation, - alloc_id, - HexRange(alloc_range) - ) - } - - fn error_cause(&self, tag: SbTag) -> &'static str { - if self.borrows.iter().any(|item| item.tag == tag && item.perm != Permission::Disabled) { - ", but that tag only grants SharedReadOnly permission for this location" - } else { - ", but that tag does not exist in the borrow stack for this location" - } - } } // # Stacked Borrows Core End diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs new file mode 100644 index 000000000000..d5a65825bc2c --- /dev/null +++ b/src/stacked_borrows/diagnostics.rs @@ -0,0 +1,299 @@ +use rustc_middle::mir::interpret::{AllocId, AllocRange}; +use rustc_span::{Span, SpanData}; +use rustc_target::abi::Size; + +use crate::helpers::HexRange; +use crate::stacked_borrows::{err_sb_ub, AccessKind, GlobalStateInner, Permission}; +use crate::Item; +use crate::SbTag; +use crate::Stack; + +use rustc_middle::mir::interpret::InterpError; + +#[derive(Debug, Default)] +pub struct AllocHistory { + // The time tags can be compressed down to one bit per event, by just storing a Vec + // where each bit is set to indicate if the event was a creation or a retag + current_time: usize, + creations: smallvec::SmallVec<[Event; 2]>, + invalidations: smallvec::SmallVec<[Event; 1]>, + protectors: smallvec::SmallVec<[Protection; 1]>, +} + +#[derive(Debug)] +struct Protection { + orig_tag: SbTag, + tag: SbTag, + span: Span, +} + +#[derive(Debug)] +struct Event { + time: usize, + parent: Option, + tag: SbTag, + range: AllocRange, + span: Span, +} + +pub enum TagHistory { + Tagged { + tag: SbTag, + created: (AllocRange, SpanData), + invalidated: Option<(AllocRange, SpanData)>, + protected: Option<(SbTag, SpanData, SpanData)>, + }, + Untagged { + recently_created: Option<(AllocRange, SpanData)>, + recently_invalidated: Option<(AllocRange, SpanData)>, + matching_created: Option<(AllocRange, SpanData)>, + protected: Option<(SbTag, SpanData, SpanData)>, + }, +} + +pub trait GlobalStateExt { + fn add_creation( + &mut self, + parent: Option, + tag: SbTag, + alloc: AllocId, + range: AllocRange, + ); + + fn add_invalidation(&mut self, tag: SbTag, alloc: AllocId, range: AllocRange); + + fn add_protector(&mut self, orig_tag: SbTag, tag: SbTag, alloc: AllocId); + + fn get_stack_history( + &self, + tag: SbTag, + alloc: AllocId, + alloc_range: AllocRange, + offset: Size, + protector_tag: Option, + ) -> Option; +} + +impl GlobalStateExt for GlobalStateInner { + fn add_creation( + &mut self, + parent: Option, + tag: SbTag, + alloc: AllocId, + range: AllocRange, + ) { + let extras = self.extras.entry(alloc).or_default(); + extras.creations.push(Event { + parent, + tag, + range, + span: self.current_span, + time: extras.current_time, + }); + extras.current_time += 1; + } + + fn add_invalidation(&mut self, tag: SbTag, alloc: AllocId, range: AllocRange) { + let extras = self.extras.entry(alloc).or_default(); + extras.invalidations.push(Event { + parent: None, + tag, + range, + span: self.current_span, + time: extras.current_time, + }); + extras.current_time += 1; + } + + fn add_protector(&mut self, orig_tag: SbTag, tag: SbTag, alloc: AllocId) { + let extras = self.extras.entry(alloc).or_default(); + extras.protectors.push(Protection { orig_tag, tag, span: self.current_span }); + extras.current_time += 1; + } + + fn get_stack_history( + &self, + tag: SbTag, + alloc: AllocId, + alloc_range: AllocRange, + offset: Size, + protector_tag: Option, + ) -> Option { + let extras = self.extras.get(&alloc)?; + let protected = protector_tag + .and_then(|protector| { + extras.protectors.iter().find_map(|protection| { + if protection.tag == protector { + Some((protection.orig_tag, protection.span.data())) + } else { + None + } + }) + }) + .and_then(|(tag, call_span)| { + extras.creations.iter().rev().find_map(|event| { + if event.tag == tag { + Some((event.parent?, event.span.data(), call_span)) + } else { + None + } + }) + }); + if let SbTag::Tagged(_) = tag { + let get_matching = |events: &[Event]| { + events.iter().rev().find_map(|event| { + if event.tag == tag { Some((event.range, event.span.data())) } else { None } + }) + }; + Some(TagHistory::Tagged { + tag, + created: get_matching(&extras.creations)?, + invalidated: get_matching(&extras.invalidations), + protected, + }) + } else { + let mut created_time = 0; + // Find the most recently created tag that satsfies this offset + let recently_created = extras.creations.iter().rev().find_map(|event| { + if event.tag == tag && offset >= event.range.start && offset < event.range.end() { + created_time = event.time; + Some((event.range, event.span.data())) + } else { + None + } + }); + + // Find a different recently created tag that satisfies this whole operation, predates + // the recently created tag, and has a different span. + // We're trying to make a guess at which span the user wanted to provide the tag that + // they're using. + let matching_created = if let Some((_created_range, created_span)) = recently_created { + extras.creations.iter().rev().find_map(|event| { + if event.tag == tag + && alloc_range.start >= event.range.start + && alloc_range.end() <= event.range.end() + && event.span.data() != created_span + && event.time != created_time + { + Some((event.range, event.span.data())) + } else { + None + } + }) + } else { + None + }; + + let recently_invalidated = if recently_created.is_some() { + // Find the most recent invalidation of this tag which post-dates the creation + let mut found = None; + for event in extras.invalidations.iter().rev() { + if event.time < created_time { + break; + } + if event.tag == tag && offset >= event.range.start && offset < event.range.end() + { + found = Some((event.range, event.span.data())) + } + } + found + } else { + None + }; + Some(TagHistory::Untagged { + recently_created, + matching_created, + recently_invalidated, + protected, + }) + } + } +} + +pub trait StackExt { + fn grant_error( + &self, + derived_from: SbTag, + new: Item, + alloc_id: AllocId, + alloc_range: AllocRange, + error_offset: Size, + global: &GlobalStateInner, + ) -> InterpError<'static>; + + fn access_error( + &self, + access: AccessKind, + tag: SbTag, + alloc_id: AllocId, + alloc_range: AllocRange, + error_offset: Size, + global: &GlobalStateInner, + ) -> InterpError<'static>; +} + +impl StackExt for Stack { + /// Report a descriptive error when `new` could not be granted from `derived_from`. + fn grant_error( + &self, + derived_from: SbTag, + new: Item, + alloc_id: AllocId, + alloc_range: AllocRange, + error_offset: Size, + global: &GlobalStateInner, + ) -> InterpError<'static> { + let action = format!( + "trying to reborrow {:?} for {:?} permission at {}[{:#x}]", + derived_from, + new.perm, + alloc_id, + error_offset.bytes(), + ); + err_sb_ub( + format!("{}{}", action, error_cause(self, derived_from)), + Some(operation_summary("a reborrow", alloc_id, alloc_range)), + global.get_stack_history(derived_from, alloc_id, alloc_range, error_offset, None), + ) + } + + /// Report a descriptive error when `access` is not permitted based on `tag`. + fn access_error( + &self, + access: AccessKind, + tag: SbTag, + alloc_id: AllocId, + alloc_range: AllocRange, + error_offset: Size, + global: &GlobalStateInner, + ) -> InterpError<'static> { + let action = format!( + "attempting a {} using {:?} at {}[{:#x}]", + access, + tag, + alloc_id, + error_offset.bytes(), + ); + err_sb_ub( + format!("{}{}", action, error_cause(self, tag)), + Some(operation_summary("an access", alloc_id, alloc_range)), + global.get_stack_history(tag, alloc_id, alloc_range, error_offset, None), + ) + } +} + +fn operation_summary( + operation: &'static str, + alloc_id: AllocId, + alloc_range: AllocRange, +) -> String { + format!("this error occurs as part of {} at {:?}{}", operation, alloc_id, HexRange(alloc_range)) +} + +fn error_cause(stack: &Stack, tag: SbTag) -> &'static str { + if stack.borrows.iter().any(|item| item.tag == tag && item.perm != Permission::Disabled) { + ", but that tag only grants SharedReadOnly permission for this location" + } else { + ", but that tag does not exist in the borrow stack for this location" + } +} From a0ac13d8a16af1fa24f43d7f6cb39a9f78ba91fe Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 Apr 2022 17:06:50 +0200 Subject: [PATCH 3037/5092] gracefully handle type-too-large layout errors --- src/diagnostics.rs | 4 +--- tests/compile-fail/erroneous_const.rs | 2 +- tests/compile-fail/type-too-large.rs | 6 ++++++ 3 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 tests/compile-fail/type-too-large.rs diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 1a39a1ff332e..5d20cc6ff6ba 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -182,10 +182,8 @@ pub fn report_error<'tcx, 'mir>( "Undefined Behavior", ResourceExhaustion(_) => "resource exhaustion", - InvalidProgram(InvalidProgramInfo::ReferencedConstant) => + InvalidProgram(InvalidProgramInfo::AlreadyReported(_) | InvalidProgramInfo::Layout(..)) => "post-monomorphization error", - InvalidProgram(InvalidProgramInfo::AlreadyReported(_)) => - "error occurred", kind => bug!("This error should be impossible in Miri: {:?}", kind), }; diff --git a/tests/compile-fail/erroneous_const.rs b/tests/compile-fail/erroneous_const.rs index 2592483fe65a..8975694f51cc 100644 --- a/tests/compile-fail/erroneous_const.rs +++ b/tests/compile-fail/erroneous_const.rs @@ -12,7 +12,7 @@ impl PrintName { fn no_codegen() { if false { - let _ = PrintName::::VOID; //~ERROR error occurred: encountered constant + let _ = PrintName::::VOID; //~ERROR post-monomorphization error } } fn main() { diff --git a/tests/compile-fail/type-too-large.rs b/tests/compile-fail/type-too-large.rs new file mode 100644 index 000000000000..2c4ff7013a46 --- /dev/null +++ b/tests/compile-fail/type-too-large.rs @@ -0,0 +1,6 @@ +// ignore-32bit + +fn main() { + let _fat: [u8; (1<<61)+(1<<31)] = + [0; (1u64<<61) as usize +(1u64<<31) as usize]; //~ ERROR post-monomorphization error +} From 1d9e91ed507155c86299125239b993761b110fb1 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 30 Apr 2022 10:14:24 -0700 Subject: [PATCH 3038/5092] Replace unneeded use of `ref` in favor of "match ergonomics" --- src/shims/backtrace.rs | 10 +-- src/shims/foreign_items.rs | 47 +++++----- src/shims/intrinsics.rs | 80 ++++++++--------- src/shims/mod.rs | 2 +- src/shims/panic.rs | 4 +- src/shims/posix/foreign_items.rs | 120 ++++++++++++------------- src/shims/posix/linux/foreign_items.rs | 30 +++---- src/shims/posix/macos/dlsym.rs | 2 +- src/shims/posix/macos/foreign_items.rs | 46 ++++------ src/shims/windows/dlsym.rs | 20 ++--- src/shims/windows/foreign_items.rs | 87 +++++++++--------- tests/run-pass/vec-matching-fold.rs | 8 +- 12 files changed, 219 insertions(+), 237 deletions(-) diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 3ada61abbd29..339aa4d57e22 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -15,7 +15,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[ref flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; + let [flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; let flags = this.read_scalar(flags)?.to_u64()?; if flags != 0 { @@ -77,7 +77,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // storage for pointers is allocated by miri // deallocating the slice is undefined behavior with a custom global allocator 0 => { - let &[_flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; + let [_flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; let alloc = this.allocate(array_layout, MiriMemoryKind::Rust.into())?; @@ -95,7 +95,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // storage for pointers is allocated by the caller 1 => { - let &[_flags, ref buf] = this.check_shim(abi, Abi::Rust, link_name, args)?; + let [_flags, buf] = this.check_shim(abi, Abi::Rust, link_name, args)?; let buf_place = this.deref_operand(buf)?; @@ -150,7 +150,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[ref ptr, ref flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; + let [ptr, flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; let flags = this.read_scalar(flags)?.to_u64()?; @@ -233,7 +233,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[ref ptr, ref flags, ref name_ptr, ref filename_ptr] = + let [ptr, flags, name_ptr, filename_ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?; let flags = this.read_scalar(flags)?.to_u64()?; diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 8a79ed03162e..ba4e384846be 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -274,14 +274,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { Abi::System { unwind: false } }; - let &[ref code] = this.check_shim(abi, exp_abi, link_name, args)?; + let [code] = this.check_shim(abi, exp_abi, link_name, args)?; // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway let code = this.read_scalar(code)?.to_i32()?; throw_machine_stop!(TerminationInfo::Exit(code.into())); } "abort" => { - let &[] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; throw_machine_stop!(TerminationInfo::Abort( "the program aborted execution".to_owned() )) @@ -367,7 +366,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match &*link_name.as_str() { // Miri-specific extern functions "miri_static_root" => { - let &[ref ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?; + let [ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; let (alloc_id, offset, _) = this.ptr_get_alloc_id(ptr)?; if offset != Size::ZERO { @@ -400,13 +399,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Standard C allocation "malloc" => { - let &[ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C)?; this.write_pointer(res, dest)?; } "calloc" => { - let &[ref items, ref len] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [items, len] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let items = this.read_scalar(items)?.to_machine_usize(this)?; let len = this.read_scalar(len)?.to_machine_usize(this)?; let size = @@ -415,12 +414,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_pointer(res, dest)?; } "free" => { - let &[ref ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let ptr = this.read_pointer(ptr)?; this.free(ptr, MiriMemoryKind::C)?; } "realloc" => { - let &[ref old_ptr, ref new_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [old_ptr, new_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let old_ptr = this.read_pointer(old_ptr)?; let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; let res = this.realloc(old_ptr, new_size, MiriMemoryKind::C)?; @@ -429,7 +428,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Rust allocation "__rust_alloc" => { - let &[ref size, ref align] = this.check_shim(abi, Abi::Rust, link_name, args)?; + let [size, align] = this.check_shim(abi, Abi::Rust, link_name, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -446,7 +445,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }); } "__rust_alloc_zeroed" => { - let &[ref size, ref align] = this.check_shim(abi, Abi::Rust, link_name, args)?; + let [size, align] = this.check_shim(abi, Abi::Rust, link_name, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -465,7 +464,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }); } "__rust_dealloc" => { - let &[ref ptr, ref old_size, ref align] = this.check_shim(abi, Abi::Rust, link_name, args)?; + let [ptr, old_size, align] = this.check_shim(abi, Abi::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -480,7 +479,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }); } "__rust_realloc" => { - let &[ref ptr, ref old_size, ref align, ref new_size] = this.check_shim(abi, Abi::Rust, link_name, args)?; + let [ptr, old_size, align, new_size] = this.check_shim(abi, Abi::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -504,7 +503,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // C memory handling functions "memcmp" => { - let &[ref left, ref right, ref n] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [left, right, n] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let left = this.read_pointer(left)?; let right = this.read_pointer(right)?; let n = Size::from_bytes(this.read_scalar(n)?.to_machine_usize(this)?); @@ -524,7 +523,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "memrchr" => { - let &[ref ptr, ref val, ref num] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [ptr, val, num] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let ptr = this.read_pointer(ptr)?; let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; @@ -541,7 +540,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "memchr" => { - let &[ref ptr, ref val, ref num] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [ptr, val, num] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let ptr = this.read_pointer(ptr)?; let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; @@ -557,7 +556,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "strlen" => { - let &[ref ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let ptr = this.read_pointer(ptr)?; let n = this.read_c_str(ptr)?.len(); this.write_scalar(Scalar::from_machine_usize(u64::try_from(n).unwrap(), this), dest)?; @@ -573,7 +572,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asinf" | "atanf" => { - let &[ref f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let f = match &*link_name.as_str() { @@ -593,7 +592,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypotf" | "atan2f" => { - let &[ref f1, ref f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [f1, f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // underscore case for windows, here and below // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) // FIXME: Using host floats. @@ -615,7 +614,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asin" | "atan" => { - let &[ref f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let f = match &*link_name.as_str() { @@ -635,7 +634,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypot" | "atan2" => { - let &[ref f1, ref f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [f1, f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?); let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?); @@ -651,7 +650,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "ldexp" | "scalbn" => { - let &[ref x, ref exp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [x, exp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. let x = this.read_scalar(x)?.to_f64()?; let exp = this.read_scalar(exp)?.to_i32()?; @@ -673,7 +672,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Architecture-specific shims "llvm.x86.addcarry.64" if this.tcx.sess.target.arch == "x86_64" => { // Computes u8+u64+u64, returning tuple (u8,u64) comprising the output carry and truncated sum. - let &[ref c_in, ref a, ref b] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; + let [c_in, a, b] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; let c_in = this.read_scalar(c_in)?.to_u8()?; let a = this.read_scalar(a)?.to_u64()?; let b = this.read_scalar(b)?.to_u64()?; @@ -687,11 +686,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_u64(sum), &sum_field)?; } "llvm.x86.sse2.pause" if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.yield_active_thread(); } "llvm.aarch64.isb" if this.tcx.sess.target.arch == "aarch64" => { - let &[ref arg] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; + let [arg] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; let arg = this.read_scalar(arg)?.to_i32()?; match arg { 15 => { // SY ("full system scope") diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index b2c31f1c140b..a6f818c493e6 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -43,13 +43,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match intrinsic_name { // Miri overwriting CTFE intrinsics. "ptr_guaranteed_eq" => { - let &[ref left, ref right] = check_arg_count(args)?; + let [left, right] = check_arg_count(args)?; let left = this.read_immediate(left)?; let right = this.read_immediate(right)?; this.binop_ignore_overflow(mir::BinOp::Eq, &left, &right, dest)?; } "ptr_guaranteed_ne" => { - let &[ref left, ref right] = check_arg_count(args)?; + let [left, right] = check_arg_count(args)?; let left = this.read_immediate(left)?; let right = this.read_immediate(right)?; this.binop_ignore_overflow(mir::BinOp::Ne, &left, &right, dest)?; @@ -65,18 +65,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Raw memory accesses "volatile_load" => { - let &[ref place] = check_arg_count(args)?; + let [place] = check_arg_count(args)?; let place = this.deref_operand(place)?; this.copy_op(&place.into(), dest)?; } "volatile_store" => { - let &[ref place, ref dest] = check_arg_count(args)?; + let [place, dest] = check_arg_count(args)?; let place = this.deref_operand(place)?; this.copy_op(dest, &place.into())?; } "write_bytes" | "volatile_set_memory" => { - let &[ref ptr, ref val_byte, ref count] = check_arg_count(args)?; + let [ptr, val_byte, count] = check_arg_count(args)?; let ty = instance.substs.type_at(0); let ty_layout = this.layout_of(ty)?; let val_byte = this.read_scalar(val_byte)?.to_u8()?; @@ -95,13 +95,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Floating-point operations "fabsf32" => { - let &[ref f] = check_arg_count(args)?; + let [f] = check_arg_count(args)?; let f = this.read_scalar(f)?.to_f32()?; // Can be implemented in soft-floats. this.write_scalar(Scalar::from_f32(f.abs()), dest)?; } "fabsf64" => { - let &[ref f] = check_arg_count(args)?; + let [f] = check_arg_count(args)?; let f = this.read_scalar(f)?.to_f64()?; // Can be implemented in soft-floats. this.write_scalar(Scalar::from_f64(f.abs()), dest)?; @@ -120,7 +120,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "truncf32" | "roundf32" => { - let &[ref f] = check_arg_count(args)?; + let [f] = check_arg_count(args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let f = match intrinsic_name { @@ -155,7 +155,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "truncf64" | "roundf64" => { - let &[ref f] = check_arg_count(args)?; + let [f] = check_arg_count(args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let f = match intrinsic_name { @@ -183,7 +183,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "fdiv_fast" | "frem_fast" => { - let &[ref a, ref b] = check_arg_count(args)?; + let [a, b] = check_arg_count(args)?; let a = this.read_immediate(a)?; let b = this.read_immediate(b)?; let op = match intrinsic_name { @@ -228,7 +228,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "maxnumf32" | "copysignf32" => { - let &[ref a, ref b] = check_arg_count(args)?; + let [a, b] = check_arg_count(args)?; let a = this.read_scalar(a)?.to_f32()?; let b = this.read_scalar(b)?.to_f32()?; let res = match intrinsic_name { @@ -245,7 +245,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "maxnumf64" | "copysignf64" => { - let &[ref a, ref b] = check_arg_count(args)?; + let [a, b] = check_arg_count(args)?; let a = this.read_scalar(a)?.to_f64()?; let b = this.read_scalar(b)?.to_f64()?; let res = match intrinsic_name { @@ -258,7 +258,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "powf32" => { - let &[ref f, ref f2] = check_arg_count(args)?; + let [f, f2] = check_arg_count(args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let f2 = f32::from_bits(this.read_scalar(f2)?.to_u32()?); @@ -266,7 +266,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "powf64" => { - let &[ref f, ref f2] = check_arg_count(args)?; + let [f, f2] = check_arg_count(args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?); @@ -274,7 +274,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "fmaf32" => { - let &[ref a, ref b, ref c] = check_arg_count(args)?; + let [a, b, c] = check_arg_count(args)?; let a = this.read_scalar(a)?.to_f32()?; let b = this.read_scalar(b)?.to_f32()?; let c = this.read_scalar(c)?.to_f32()?; @@ -283,7 +283,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "fmaf64" => { - let &[ref a, ref b, ref c] = check_arg_count(args)?; + let [a, b, c] = check_arg_count(args)?; let a = this.read_scalar(a)?.to_f64()?; let b = this.read_scalar(b)?.to_f64()?; let c = this.read_scalar(c)?.to_f64()?; @@ -292,7 +292,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "powif32" => { - let &[ref f, ref i] = check_arg_count(args)?; + let [f, i] = check_arg_count(args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let i = this.read_scalar(i)?.to_i32()?; @@ -300,7 +300,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "powif64" => { - let &[ref f, ref i] = check_arg_count(args)?; + let [f, i] = check_arg_count(args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let i = this.read_scalar(i)?.to_i32()?; @@ -308,7 +308,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "float_to_int_unchecked" => { - let &[ref val] = check_arg_count(args)?; + let [val] = check_arg_count(args)?; let val = this.read_immediate(val)?; let res = match val.layout.ty.kind() { @@ -335,7 +335,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "simd_round" | "simd_trunc" | "simd_fsqrt" => { - let &[ref op] = check_arg_count(args)?; + let [op] = check_arg_count(args)?; let (op, op_len) = this.operand_to_simd(op)?; let (dest, dest_len) = this.place_to_simd(dest)?; @@ -441,7 +441,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "simd_arith_offset" => { use mir::BinOp; - let &[ref left, ref right] = check_arg_count(args)?; + let [left, right] = check_arg_count(args)?; let (left, left_len) = this.operand_to_simd(left)?; let (right, right_len) = this.operand_to_simd(right)?; let (dest, dest_len) = this.place_to_simd(dest)?; @@ -531,7 +531,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "simd_fma" => { - let &[ref a, ref b, ref c] = check_arg_count(args)?; + let [a, b, c] = check_arg_count(args)?; let (a, a_len) = this.operand_to_simd(a)?; let (b, b_len) = this.operand_to_simd(b)?; let (c, c_len) = this.operand_to_simd(c)?; @@ -570,7 +570,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "simd_reduce_min" => { use mir::BinOp; - let &[ref op] = check_arg_count(args)?; + let [op] = check_arg_count(args)?; let (op, op_len) = this.operand_to_simd(op)?; let imm_from_bool = @@ -642,7 +642,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "simd_reduce_mul_ordered" => { use mir::BinOp; - let &[ref op, ref init] = check_arg_count(args)?; + let [op, init] = check_arg_count(args)?; let (op, op_len) = this.operand_to_simd(op)?; let init = this.read_immediate(init)?; @@ -660,7 +660,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_immediate(*res, dest)?; } "simd_select" => { - let &[ref mask, ref yes, ref no] = check_arg_count(args)?; + let [mask, yes, no] = check_arg_count(args)?; let (mask, mask_len) = this.operand_to_simd(mask)?; let (yes, yes_len) = this.operand_to_simd(yes)?; let (no, no_len) = this.operand_to_simd(no)?; @@ -681,7 +681,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "simd_select_bitmask" => { - let &[ref mask, ref yes, ref no] = check_arg_count(args)?; + let [mask, yes, no] = check_arg_count(args)?; let (yes, yes_len) = this.operand_to_simd(yes)?; let (no, no_len) = this.operand_to_simd(no)?; let (dest, dest_len) = this.place_to_simd(dest)?; @@ -721,7 +721,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[rustfmt::skip] "simd_cast" | "simd_as" => { - let &[ref op] = check_arg_count(args)?; + let [op] = check_arg_count(args)?; let (op, op_len) = this.operand_to_simd(op)?; let (dest, dest_len) = this.place_to_simd(dest)?; @@ -759,7 +759,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "simd_shuffle" => { - let &[ref left, ref right, ref index] = check_arg_count(args)?; + let [left, right, index] = check_arg_count(args)?; let (left, left_len) = this.operand_to_simd(left)?; let (right, right_len) = this.operand_to_simd(right)?; let (dest, dest_len) = this.place_to_simd(dest)?; @@ -798,7 +798,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "simd_gather" => { - let &[ref passthru, ref ptrs, ref mask] = check_arg_count(args)?; + let [passthru, ptrs, mask] = check_arg_count(args)?; let (passthru, passthru_len) = this.operand_to_simd(passthru)?; let (ptrs, ptrs_len) = this.operand_to_simd(ptrs)?; let (mask, mask_len) = this.operand_to_simd(mask)?; @@ -824,7 +824,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "simd_scatter" => { - let &[ref value, ref ptrs, ref mask] = check_arg_count(args)?; + let [value, ptrs, mask] = check_arg_count(args)?; let (value, value_len) = this.operand_to_simd(value)?; let (ptrs, ptrs_len) = this.operand_to_simd(ptrs)?; let (mask, mask_len) = this.operand_to_simd(mask)?; @@ -844,7 +844,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "simd_bitmask" => { - let &[ref op] = check_arg_count(args)?; + let [op] = check_arg_count(args)?; let (op, op_len) = this.operand_to_simd(op)?; let bitmask_len = op_len.max(8); @@ -1063,14 +1063,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Other "exact_div" => { - let &[ref num, ref denom] = check_arg_count(args)?; + let [num, denom] = check_arg_count(args)?; this.exact_div(&this.read_immediate(num)?, &this.read_immediate(denom)?, dest)?; } "try" => return this.handle_try(args, dest, ret), "breakpoint" => { - let &[] = check_arg_count(args)?; + let [] = check_arg_count(args)?; // normally this would raise a SIGTRAP, which aborts if no debugger is connected throw_machine_stop!(TerminationInfo::Abort("Trace/breakpoint trap".to_string())) } @@ -1091,7 +1091,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[ref place] = check_arg_count(args)?; + let [place] = check_arg_count(args)?; let place = this.deref_operand(place)?; // make sure it fits into a scalar; otherwise it cannot be atomic @@ -1119,7 +1119,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[ref place, ref val] = check_arg_count(args)?; + let [place, val] = check_arg_count(args)?; let place = this.deref_operand(place)?; let val = this.read_scalar(val)?; // make sure it fits into a scalar; otherwise it cannot be atomic @@ -1144,7 +1144,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], atomic: AtomicFenceOp, ) -> InterpResult<'tcx> { - let &[] = check_arg_count(args)?; + let [] = check_arg_count(args)?; let _ = atomic; //FIXME: compiler fences are currently ignored Ok(()) @@ -1156,7 +1156,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx atomic: AtomicFenceOp, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[] = check_arg_count(args)?; + let [] = check_arg_count(args)?; this.validate_atomic_fence(atomic)?; Ok(()) } @@ -1170,7 +1170,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[ref place, ref rhs] = check_arg_count(args)?; + let [place, rhs] = check_arg_count(args)?; let place = this.deref_operand(place)?; if !place.layout.ty.is_integral() { @@ -1216,7 +1216,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[ref place, ref new] = check_arg_count(args)?; + let [place, new] = check_arg_count(args)?; let place = this.deref_operand(place)?; let new = this.read_scalar(new)?; @@ -1246,7 +1246,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[ref place, ref expect_old, ref new] = check_arg_count(args)?; + let [place, expect_old, new] = check_arg_count(args)?; let place = this.deref_operand(place)?; let expect_old = this.read_immediate(expect_old)?; // read as immediate for the sake of `binary_op()` let new = this.read_scalar(new)?; diff --git a/src/shims/mod.rs b/src/shims/mod.rs index af6064925f04..f003552434fe 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -36,7 +36,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // There are some more lang items we want to hook that CTFE does not hook (yet). if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { - let &[ref ptr, ref align] = check_arg_count(args)?; + let [ptr, align] = check_arg_count(args)?; if this.align_offset(ptr, align, ret, unwind)? { return Ok(None); } diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 96d3b7c9f891..f92e39048bc8 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -51,7 +51,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("miri_start_panic: {:?}", this.frame().instance); // Get the raw pointer stored in arg[0] (the panic payload). - let &[ref payload] = this.check_shim(abi, Abi::Rust, link_name, args)?; + let [payload] = this.check_shim(abi, Abi::Rust, link_name, args)?; let payload = this.read_scalar(payload)?.check_init()?; let thread = this.active_thread_mut(); assert!(thread.panic_payload.is_none(), "the panic runtime should avoid double-panics"); @@ -83,7 +83,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // a pointer to `Box`. // Get all the arguments. - let &[ref try_fn, ref data, ref catch_fn] = check_arg_count(args)?; + let [try_fn, data, catch_fn] = check_arg_count(args)?; let try_fn = this.read_pointer(try_fn)?; let data = this.read_scalar(data)?.check_init()?; let catch_fn = this.read_scalar(catch_fn)?.check_init()?; diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 16619d4aeb77..566befb0efd0 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -29,28 +29,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match &*link_name.as_str() { // Environment related shims "getenv" => { - let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.getenv(name)?; this.write_pointer(result, dest)?; } "unsetenv" => { - let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.unsetenv(name)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "setenv" => { - let &[ref name, ref value, ref overwrite] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [name, value, overwrite] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(overwrite)?.to_i32()?; let result = this.setenv(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "getcwd" => { - let &[ref buf, ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [buf, size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.getcwd(buf, size)?; this.write_pointer(result, dest)?; } "chdir" => { - let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.chdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -70,7 +70,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "read" => { - let &[ref fd, ref buf, ref count] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [fd, buf, count] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_pointer(buf)?; let count = this.read_scalar(count)?.to_machine_usize(this)?; @@ -78,7 +78,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "write" => { - let &[ref fd, ref buf, ref n] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [fd, buf, n] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_pointer(buf)?; let count = this.read_scalar(n)?.to_machine_usize(this)?; @@ -88,60 +88,60 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "unlink" => { - let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.unlink(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "symlink" => { - let &[ref target, ref linkpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [target, linkpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.symlink(target, linkpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rename" => { - let &[ref oldpath, ref newpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [oldpath, newpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.rename(oldpath, newpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mkdir" => { - let &[ref path, ref mode] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [path, mode] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.mkdir(path, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rmdir" => { - let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.rmdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "closedir" => { - let &[ref dirp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [dirp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.closedir(dirp)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lseek" | "lseek64" => { - let &[ref fd, ref offset, ref whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [fd, offset, whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.lseek64(fd, offset, whence)?; // "lseek" is only used on macOS which is 64bit-only, so `i64` always works. this.write_scalar(Scalar::from_i64(result), dest)?; } "fsync" => { - let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.fsync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fdatasync" => { - let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.fdatasync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "readlink" => { - let &[ref pathname, ref buf, ref bufsize] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [pathname, buf, bufsize] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.readlink(pathname, buf, bufsize)?; this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } // Allocation "posix_memalign" => { - let &[ref ret, ref align, ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [ret, align, size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let ret = this.deref_operand(ret)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; @@ -171,7 +171,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamic symbol loading "dlsym" => { - let &[ref handle, ref symbol] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [handle, symbol] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(handle)?.to_machine_usize(this)?; let symbol = this.read_pointer(symbol)?; let symbol_name = this.read_c_str(symbol)?; @@ -185,7 +185,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "sysconf" => { - let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let name = this.read_scalar(name)?.to_i32()?; let sysconfs = &[ @@ -210,7 +210,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "pthread_key_create" => { - let &[ref key, ref dtor] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [key, dtor] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let key_place = this.deref_operand(key)?; let dtor = this.read_pointer(dtor)?; @@ -239,21 +239,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_key_delete" => { - let &[ref key] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [key] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let key = this.read_scalar(key)?.check_init()?.to_bits(key.layout.size)?; this.machine.tls.delete_tls_key(key)?; // Return success (0) this.write_null(dest)?; } "pthread_getspecific" => { - let &[ref key] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [key] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let key = this.read_scalar(key)?.check_init()?.to_bits(key.layout.size)?; let active_thread = this.get_active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { - let &[ref key, ref new_ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [key, new_ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let key = this.read_scalar(key)?.check_init()?.to_bits(key.layout.size)?; let active_thread = this.get_active_thread(); let new_data = this.read_scalar(new_ptr)?; @@ -265,149 +265,149 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Synchronization primitives "pthread_mutexattr_init" => { - let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutexattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_settype" => { - let &[ref attr, ref kind] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [attr, kind] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutexattr_settype(attr, kind)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_destroy" => { - let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutexattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_init" => { - let &[ref mutex, ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [mutex, attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutex_init(mutex, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_lock" => { - let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutex_lock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_trylock" => { - let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutex_trylock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_unlock" => { - let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutex_unlock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_destroy" => { - let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutex_destroy(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_rdlock" => { - let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_rwlock_rdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_tryrdlock" => { - let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_rwlock_tryrdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_wrlock" => { - let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_rwlock_wrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_trywrlock" => { - let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_rwlock_trywrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_unlock" => { - let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_rwlock_unlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_destroy" => { - let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_rwlock_destroy(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_init" => { - let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_condattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_destroy" => { - let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_condattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_init" => { - let &[ref cond, ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [cond, attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_cond_init(cond, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_signal" => { - let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_cond_signal(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_broadcast" => { - let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_cond_broadcast(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_wait" => { - let &[ref cond, ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [cond, mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_cond_wait(cond, mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_timedwait" => { - let &[ref cond, ref mutex, ref abstime] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [cond, mutex, abstime] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.pthread_cond_timedwait(cond, mutex, abstime, dest)?; } "pthread_cond_destroy" => { - let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_cond_destroy(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Threading "pthread_create" => { - let &[ref thread, ref attr, ref start, ref arg] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [thread, attr, start, arg] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_create(thread, attr, start, arg)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_join" => { - let &[ref thread, ref retval] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [thread, retval] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_join(thread, retval)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_detach" => { - let &[ref thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_detach(thread)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_self" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.pthread_self(dest)?; } "sched_yield" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.sched_yield()?; this.write_scalar(Scalar::from_i32(result), dest)?; } "nanosleep" => { - let &[ref req, ref rem] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [req, rem] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.nanosleep(req, rem)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Miscellaneous "isatty" => { - let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(fd)?.to_i32()?; // "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error" // FIXME: we just say nothing is a terminal. @@ -416,7 +416,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_atfork" => { - let &[ref prepare, ref parent, ref child] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [prepare, parent, child] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_pointer(prepare)?; this.read_pointer(parent)?; this.read_pointer(child)?; @@ -424,7 +424,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "strerror_r" | "__xpg_strerror_r" => { - let &[ref errnum, ref buf, ref buflen] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [errnum, buf, buflen] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let errnum = this.read_scalar(errnum)?.check_init()?; let buf = this.read_pointer(buf)?; let buflen = this.read_scalar(buflen)?.to_machine_usize(this)?; @@ -440,7 +440,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These shims are enabled only when the caller is in the standard library. "pthread_attr_getguardsize" if this.frame_in_std() => { - let &[ref _attr, ref guard_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [_attr, guard_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let guard_size = this.deref_operand(guard_size)?; let guard_size_layout = this.libc_ty_layout("size_t")?; this.write_scalar(Scalar::from_uint(crate::PAGE_SIZE, guard_size_layout.size), &guard_size.into())?; @@ -452,25 +452,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "pthread_attr_init" | "pthread_attr_destroy" if this.frame_in_std() => { - let &[_] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [_] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_null(dest)?; } | "pthread_attr_setstacksize" if this.frame_in_std() => { - let &[_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_null(dest)?; } | "signal" | "sigaltstack" if this.frame_in_std() => { - let &[_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_null(dest)?; } | "sigaction" | "mprotect" if this.frame_in_std() => { - let &[_, _, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [_, _, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_null(dest)?; } diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 339fb04dae33..f966c63b7239 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -24,7 +24,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match &*link_name.as_str() { // errno "__errno_location" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref(this).to_scalar()?, dest)?; } @@ -33,31 +33,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These symbols have different names on Linux and macOS, which is the only reason they are not // in the `posix` module. "close" => { - let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.close(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" => { - let &[ref name] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir64" => { - let &[ref dirp] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [dirp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.linux_readdir64(dirp)?; this.write_scalar(result, dest)?; } "ftruncate64" => { - let &[ref fd, ref length] = + let [fd, length] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Linux-only "posix_fadvise" => { - let &[ref fd, ref offset, ref len, ref advice] = + let [fd, offset, len, advice] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(fd)?.to_i32()?; this.read_scalar(offset)?.to_machine_isize(this)?; @@ -67,7 +65,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "sync_file_range" => { - let &[ref fd, ref offset, ref nbytes, ref flags] = + let [fd, offset, nbytes, flags] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.sync_file_range(fd, offset, nbytes, flags)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -76,7 +74,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "clock_gettime" => { // This is a POSIX function but it has only been tested on linux. - let &[ref clk_id, ref tp] = + let [clk_id, tp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.clock_gettime(clk_id, tp)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -85,7 +83,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_attr_getstack" => { // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. - let &[ref attr_place, ref addr_place, ref size_place] = + let [attr_place, addr_place, size_place] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.deref_operand(attr_place)?; let addr_place = this.deref_operand(addr_place)?; @@ -112,13 +110,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_setclock" => { - let &[ref attr, ref clock_id] = + let [attr, clock_id] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_condattr_setclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_getclock" => { - let &[ref attr, ref clock_id] = + let [attr, clock_id] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_condattr_getclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -185,12 +183,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscelanneous "getrandom" => { - let &[ref ptr, ref len, ref flags] = + let [ptr, len, flags] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; getrandom(this, ptr, len, flags, dest)?; } "sched_getaffinity" => { - let &[ref pid, ref cpusetsize, ref mask] = + let [pid, cpusetsize, mask] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(pid)?.to_i32()?; this.read_scalar(cpusetsize)?.to_machine_usize(this)?; @@ -204,7 +202,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "pthread_getattr_np" if this.frame_in_std() => { - let &[ref _thread, ref _attr] = + let [_thread, _attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_null(dest)?; } diff --git a/src/shims/posix/macos/dlsym.rs b/src/shims/posix/macos/dlsym.rs index d5996cc6a9ed..8ce56d35da65 100644 --- a/src/shims/posix/macos/dlsym.rs +++ b/src/shims/posix/macos/dlsym.rs @@ -36,7 +36,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match dlsym { Dlsym::getentropy => { - let &[ref ptr, ref len] = check_arg_count(args)?; + let [ptr, len] = check_arg_count(args)?; let ptr = this.read_pointer(ptr)?; let len = this.read_scalar(len)?.to_machine_usize(this)?; this.gen_random(ptr, len)?; diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index 18646b70130e..7f6393fd30f1 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -22,50 +22,47 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match &*link_name.as_str() { // errno "__error" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref(this).to_scalar()?, dest)?; } // File related shims "close" | "close$NOCANCEL" => { - let &[ref result] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [result] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.close(result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "stat" | "stat$INODE64" => { - let &[ref path, ref buf] = + let [path, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_stat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lstat" | "lstat$INODE64" => { - let &[ref path, ref buf] = + let [path, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_lstat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fstat" | "fstat$INODE64" => { - let &[ref fd, ref buf] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [fd, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_fstat(fd, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" | "opendir$INODE64" => { - let &[ref name] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir_r" | "readdir_r$INODE64" => { - let &[ref dirp, ref entry, ref result] = + let [dirp, entry, result] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_readdir_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate" => { - let &[ref fd, ref length] = + let [fd, length] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -73,7 +70,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Environment related shims "_NSGetEnviron" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_pointer( this.machine.env_vars.environ.expect("machine must be initialized").ptr, dest, @@ -82,34 +79,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "gettimeofday" => { - let &[ref tv, ref tz] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [tv, tz] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.gettimeofday(tv, tz)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mach_absolute_time" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.mach_absolute_time()?; this.write_scalar(Scalar::from_u64(result), dest)?; } "mach_timebase_info" => { - let &[ref info] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [info] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.mach_timebase_info(info)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Access to command-line arguments "_NSGetArgc" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_pointer( this.machine.argc.expect("machine must be initialized").ptr, dest, )?; } "_NSGetArgv" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_pointer( this.machine.argv.expect("machine must be initialized").ptr, dest, @@ -118,7 +113,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "_tlv_atexit" => { - let &[ref dtor, ref data] = + let [dtor, data] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let dtor = this.read_pointer(dtor)?; let dtor = this.get_ptr_fn(dtor)?.as_instance()?; @@ -129,15 +124,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_get_stackaddr_np" => { - let &[ref thread] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size()); this.write_scalar(stack_addr, dest)?; } "pthread_get_stacksize_np" => { - let &[ref thread] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size()); this.write_scalar(stack_size, dest)?; @@ -145,8 +138,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_setname_np" => { - let &[ref name] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let name = this.read_pointer(name)?; this.pthread_setname_np(name)?; } @@ -155,7 +147,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These shims are enabled only when the caller is in the standard library. "mmap" if this.frame_in_std() => { // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. - let &[ref addr, _, _, _, _, _] = + let [addr, _, _, _, _, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let addr = this.read_scalar(addr)?.check_init()?; this.write_scalar(addr, dest)?; diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index ac9e085b5d7c..5583e3a25895 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -47,16 +47,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); } - let &[ - ref handle, - ref _event, - ref _apc_routine, - ref _apc_context, - ref io_status_block, - ref buf, - ref n, - ref byte_offset, - ref _key, + let [ + handle, + _event, + _apc_routine, + _apc_context, + io_status_block, + buf, + n, + byte_offset, + _key, ] = check_arg_count(args)?; let handle = this.read_scalar(handle)?.to_machine_isize(this)?; let buf = this.read_pointer(buf)?; diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index d72302794318..c49362d52b31 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -30,36 +30,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match &*link_name.as_str() { // Environment related shims "GetEnvironmentVariableW" => { - let &[ref name, ref buf, ref size] = + let [name, buf, size] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.GetEnvironmentVariableW(name, buf, size)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetEnvironmentVariableW" => { - let &[ref name, ref value] = + let [name, value] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.SetEnvironmentVariableW(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetEnvironmentStringsW" => { - let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.GetEnvironmentStringsW()?; this.write_pointer(result, dest)?; } "FreeEnvironmentStringsW" => { - let &[ref env_block] = + let [env_block] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.FreeEnvironmentStringsW(env_block)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetCurrentDirectoryW" => { - let &[ref size, ref buf] = + let [size, buf] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.GetCurrentDirectoryW(size, buf)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetCurrentDirectoryW" => { - let &[ref path] = + let [path] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.SetCurrentDirectoryW(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -67,7 +67,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Allocation "HeapAlloc" => { - let &[ref handle, ref flags, ref size] = + let [handle, flags, size] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(handle)?.to_machine_isize(this)?; let flags = this.read_scalar(flags)?.to_u32()?; @@ -77,7 +77,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_pointer(res, dest)?; } "HeapFree" => { - let &[ref handle, ref flags, ref ptr] = + let [handle, flags, ptr] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; @@ -86,7 +86,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(1), dest)?; } "HeapReAlloc" => { - let &[ref handle, ref flags, ref ptr, ref size] = + let [handle, flags, ptr, size] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; @@ -98,20 +98,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // errno "SetLastError" => { - let &[ref error] = + let [error] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let error = this.read_scalar(error)?.check_init()?; this.set_last_error(error)?; } "GetLastError" => { - let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let last_error = this.get_last_error()?; this.write_scalar(last_error, dest)?; } // Querying system information "GetSystemInfo" => { - let &[ref system_info] = + let [system_info] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let system_info = this.deref_operand(system_info)?; // Initialize with `0`. @@ -130,20 +130,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This just creates a key; Windows does not natively support TLS destructors. // Create key and return it. - let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let key = this.machine.tls.create_tls_key(None, dest.layout.size)?; this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { - let &[ref key] = - this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let [key] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "TlsSetValue" => { - let &[ref key, ref new_ptr] = + let [key, new_ptr] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); @@ -156,7 +155,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Access to command-line arguments "GetCommandLineW" => { - let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.write_pointer( this.machine.cmd_line.expect("machine must be initialized").ptr, dest, @@ -166,20 +165,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "GetSystemTimeAsFileTime" => { #[allow(non_snake_case)] - let &[ref LPFILETIME] = + let [LPFILETIME] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.GetSystemTimeAsFileTime(LPFILETIME)?; } "QueryPerformanceCounter" => { #[allow(non_snake_case)] - let &[ref lpPerformanceCount] = + let [lpPerformanceCount] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.QueryPerformanceCounter(lpPerformanceCount)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "QueryPerformanceFrequency" => { #[allow(non_snake_case)] - let &[ref lpFrequency] = + let [lpFrequency] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.QueryPerformanceFrequency(lpFrequency)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -187,34 +186,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Synchronization primitives "AcquireSRWLockExclusive" => { - let &[ref ptr] = - this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let [ptr] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.AcquireSRWLockExclusive(ptr)?; } "ReleaseSRWLockExclusive" => { - let &[ref ptr] = - this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let [ptr] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.ReleaseSRWLockExclusive(ptr)?; } "TryAcquireSRWLockExclusive" => { - let &[ref ptr] = - this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let [ptr] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let ret = this.TryAcquireSRWLockExclusive(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; } "AcquireSRWLockShared" => { - let &[ref ptr] = - this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let [ptr] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.AcquireSRWLockShared(ptr)?; } "ReleaseSRWLockShared" => { - let &[ref ptr] = - this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let [ptr] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.ReleaseSRWLockShared(ptr)?; } "TryAcquireSRWLockShared" => { - let &[ref ptr] = - this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let [ptr] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let ret = this.TryAcquireSRWLockShared(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; } @@ -222,7 +215,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamic symbol loading "GetProcAddress" => { #[allow(non_snake_case)] - let &[ref hModule, ref lpProcName] = + let [hModule, lpProcName] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(hModule)?.to_machine_isize(this)?; let name = this.read_c_str(this.read_pointer(lpProcName)?)?; @@ -237,7 +230,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscellaneous "SystemFunction036" => { // This is really 'RtlGenRandom'. - let &[ref ptr, ref len] = + let [ptr, len] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let ptr = this.read_pointer(ptr)?; let len = this.read_scalar(len)?.to_u32()?; @@ -245,7 +238,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_bool(true), dest)?; } "BCryptGenRandom" => { - let &[ref algorithm, ref ptr, ref len, ref flags] = + let [algorithm, ptr, len, flags] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let algorithm = this.read_scalar(algorithm)?; let ptr = this.read_pointer(ptr)?; @@ -267,7 +260,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "GetConsoleScreenBufferInfo" => { // `term` needs this, so we fake it. - let &[ref console, ref buffer_info] = + let [console, buffer_info] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(console)?.to_machine_isize(this)?; this.deref_operand(buffer_info)?; @@ -277,7 +270,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "GetConsoleMode" => { // Windows "isatty" (in libtest) needs this, so we fake it. - let &[ref console, ref mode] = + let [console, mode] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(console)?.to_machine_isize(this)?; this.deref_operand(mode)?; @@ -286,13 +279,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "SwitchToThread" => { - let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; // Note that once Miri supports concurrency, this will need to return a nonzero // value if this call does result in switching to another thread. this.write_null(dest)?; } "GetStdHandle" => { - let &[ref which] = + let [which] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let which = this.read_scalar(which)?.to_i32()?; // We just make this the identity function, so we know later in `NtWriteFile` which @@ -303,7 +296,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Better error for attempts to create a thread "CreateThread" => { - let &[_, _, _, _, _, _] = + let [_, _, _, _, _, _] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.handle_unsupported("can't create threads on Windows")?; @@ -313,34 +306,34 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "GetProcessHeap" if this.frame_in_std() => { - let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; // Just fake a HANDLE this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } "GetModuleHandleA" if this.frame_in_std() => { #[allow(non_snake_case)] - let &[_lpModuleName] = + let [_lpModuleName] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; // We need to return something non-null here to make `compat_fn!` work. this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } "SetConsoleTextAttribute" if this.frame_in_std() => { #[allow(non_snake_case)] - let &[ref _hConsoleOutput, ref _wAttribute] = + let [_hConsoleOutput, _wAttribute] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; // Pretend these does not exist / nothing happened, by returning zero. this.write_null(dest)?; } "AddVectoredExceptionHandler" if this.frame_in_std() => { #[allow(non_snake_case)] - let &[ref _First, ref _Handler] = + let [_First, _Handler] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_machine_usize(1, this), dest)?; } "SetThreadStackGuarantee" if this.frame_in_std() => { #[allow(non_snake_case)] - let &[_StackSizeInBytes] = + let [_StackSizeInBytes] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_u32(1), dest)?; @@ -352,7 +345,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.frame_in_std() => { #[allow(non_snake_case)] - let &[ref _lpCriticalSection] = + let [_lpCriticalSection] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; assert_eq!( this.get_total_thread_count(), @@ -365,7 +358,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "TryEnterCriticalSection" if this.frame_in_std() => { #[allow(non_snake_case)] - let &[ref _lpCriticalSection] = + let [_lpCriticalSection] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; assert_eq!( this.get_total_thread_count(), diff --git a/tests/run-pass/vec-matching-fold.rs b/tests/run-pass/vec-matching-fold.rs index 8fd36253b57f..749f93fc0fd2 100644 --- a/tests/run-pass/vec-matching-fold.rs +++ b/tests/run-pass/vec-matching-fold.rs @@ -7,9 +7,9 @@ fn foldl(values: &[T], U: Clone+Debug, T:Debug, F: FnMut(U, &T) -> U, { match values { - &[ref head, ref tail @ ..] => + [head, tail @ ..] => foldl(tail, function(initial, head), function), - &[] => { + [] => { let res = initial.clone(); res } } @@ -23,9 +23,9 @@ fn foldr(values: &[T], F: FnMut(&T, U) -> U, { match values { - &[ref head @ .., ref tail] => + [head @ .., tail] => foldr(head, function(tail, initial), function), - &[] => { + [] => { let res = initial.clone(); res } } From 8d42a7cfdf1eda2584c223354aaa76dd8dde7021 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 30 Apr 2022 10:06:19 -0700 Subject: [PATCH 3039/5092] Replace `as` casts in llvm.x86.addcarry.64 implementation --- src/helpers.rs | 2 ++ src/helpers/convert.rs | 49 ++++++++++++++++++++++++++++++++++++++ src/shims/foreign_items.rs | 5 ++-- 3 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 src/helpers/convert.rs diff --git a/src/helpers.rs b/src/helpers.rs index 107a2551995a..5b820218a9dd 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,3 +1,5 @@ +pub mod convert; + use std::mem; use std::num::NonZeroUsize; use std::time::Duration; diff --git a/src/helpers/convert.rs b/src/helpers/convert.rs new file mode 100644 index 000000000000..4506fe47495d --- /dev/null +++ b/src/helpers/convert.rs @@ -0,0 +1,49 @@ +use implementations::NarrowerThan; + +/// Replacement for `as` casts going from wide integer to narrower integer. +/// +/// # Example +/// +/// ```ignore +/// let x = 99_u64; +/// let lo = x.truncate::(); +/// // lo is of type u16, equivalent to `x as u16`. +/// ``` +pub(crate) trait Truncate: Sized { + fn truncate(self) -> To + where + To: NarrowerThan, + { + NarrowerThan::truncate_from(self) + } +} + +impl Truncate for u16 {} +impl Truncate for u32 {} +impl Truncate for u64 {} +impl Truncate for u128 {} + +mod implementations { + pub(crate) trait NarrowerThan { + fn truncate_from(wide: T) -> Self; + } + + macro_rules! impl_narrower_than { + ($(NarrowerThan<{$($ty:ty),*}> for $self:ty)*) => { + $($( + impl NarrowerThan<$ty> for $self { + fn truncate_from(wide: $ty) -> Self { + wide as Self + } + } + )*)* + }; + } + + impl_narrower_than! { + NarrowerThan<{u128, u64, u32, u16}> for u8 + NarrowerThan<{u128, u64, u32}> for u16 + NarrowerThan<{u128, u64}> for u32 + NarrowerThan<{u128}> for u64 + } +} diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 8a79ed03162e..5ff70e41518a 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -22,6 +22,7 @@ use rustc_target::{ }; use super::backtrace::EvalContextExt as _; +use crate::helpers::convert::Truncate; use crate::*; /// Returned by `emulate_foreign_item_by_name`. @@ -678,8 +679,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let a = this.read_scalar(a)?.to_u64()?; let b = this.read_scalar(b)?.to_u64()?; - let wide_sum = c_in as u128 + a as u128 + b as u128; - let (c_out, sum) = ((wide_sum >> 64) as u8, wide_sum as u64); + let wide_sum = u128::from(c_in) + u128::from(a) + u128::from(b); + let (c_out, sum) = ((wide_sum >> 64).truncate::(), wide_sum.truncate::()); let c_out_field = this.place_field(dest, 0)?; this.write_scalar(Scalar::from_u8(c_out), &c_out_field)?; From b99414871488682bd2010d7314c9a7496717ffbb Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 30 Apr 2022 10:40:35 -0700 Subject: [PATCH 3040/5092] Clean up all trailing whitespace --- Cargo.toml | 2 +- bench-cargo-miri/mse/src/main.rs | 2 +- rustup-toolchain | 4 +-- .../data_race/dangling_thread_async_race.rs | 2 +- .../data_race/dealloc_read_race2.rs | 2 +- .../data_race/read_write_race_stack.rs | 2 +- .../data_race/write_write_race_stack.rs | 4 +-- tests/compile-fail/panic/double_panic.rs | 2 +- tests/compile-fail/rc_as_ptr.rs | 2 +- tests/run-pass/backtrace-api-v1.rs | 4 +-- tests/run-pass/concurrency/data_race.rs | 6 ++-- tests/run-pass/dyn-arbitrary-self.rs | 30 +++++++++---------- tests/run-pass/ptr_offset.rs | 2 +- .../stacked-borrows/stacked-borrows.rs | 2 +- tests/run-pass/threadleak_ignored.rs | 2 +- 15 files changed, 34 insertions(+), 34 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4956a8dffd49..6d65ab6e1e46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ rustc_version = "0.4" colored = "2" [package.metadata.rust-analyzer] -# This crate uses #[feature(rustc_private)]. +# This crate uses #[feature(rustc_private)]. # See https://github.com/rust-analyzer/rust-analyzer/pull/7891 rustc_private = true diff --git a/bench-cargo-miri/mse/src/main.rs b/bench-cargo-miri/mse/src/main.rs index 57e286071055..b182f6cec65a 100644 --- a/bench-cargo-miri/mse/src/main.rs +++ b/bench-cargo-miri/mse/src/main.rs @@ -4,7 +4,7 @@ static PCM: &[i16] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, fn main() { #[cfg(increase_thread_usage)] let thread = std::thread::spawn(|| 4); - + for _ in 0..2 { mse(PCM.len(), PCM, EXPECTED); } diff --git a/rustup-toolchain b/rustup-toolchain index 5b7e8f7fcd63..421db2b3d79f 100755 --- a/rustup-toolchain +++ b/rustup-toolchain @@ -8,9 +8,9 @@ set -e # USAGE: # # ./rustup-toolchain: Update "miri" toolchain to match `rust-version` (the known-good version for this commit). -# +# # ./rustup-toolchain HEAD: Update "miri" toolchain and `rust-version` file to latest rustc HEAD. -# +# # ./rustup-toolchain $COMMIT: Update "miri" toolchain and `rust-version` file to match that commit. # Make sure rustup-toolchain-install-master is installed. diff --git a/tests/compile-fail/data_race/dangling_thread_async_race.rs b/tests/compile-fail/data_race/dangling_thread_async_race.rs index ad539ec5b083..6aa5a469be3b 100644 --- a/tests/compile-fail/data_race/dangling_thread_async_race.rs +++ b/tests/compile-fail/data_race/dangling_thread_async_race.rs @@ -36,7 +36,7 @@ fn main() { let join2 = unsafe { spawn(move || { - *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 3) and Write on Thread(id = 1) + *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 3) and Write on Thread(id = 1) }) }; diff --git a/tests/compile-fail/data_race/dealloc_read_race2.rs b/tests/compile-fail/data_race/dealloc_read_race2.rs index a4bf210ef439..9f9dbfc77ed5 100644 --- a/tests/compile-fail/data_race/dealloc_read_race2.rs +++ b/tests/compile-fail/data_race/dealloc_read_race2.rs @@ -23,7 +23,7 @@ pub fn main() { }); let j2 = spawn(move || { - // Also an error of the form: Data race detected between Read on Thread(id = 2) and Deallocate on Thread(id = 1) + // Also an error of the form: Data race detected between Read on Thread(id = 2) and Deallocate on Thread(id = 1) // but the invalid allocation is detected first. *ptr.0 //~ ERROR dereferenced after this allocation got freed }); diff --git a/tests/compile-fail/data_race/read_write_race_stack.rs b/tests/compile-fail/data_race/read_write_race_stack.rs index 0cf915cdef2b..5a1c0a4b6d6d 100644 --- a/tests/compile-fail/data_race/read_write_race_stack.rs +++ b/tests/compile-fail/data_race/read_write_race_stack.rs @@ -40,7 +40,7 @@ pub fn main() { let mut stack_var = 0usize; pointer.store(&mut stack_var as *mut _, Ordering::Release); - + sleep(Duration::from_millis(200)); stack_var //~ ERROR Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) diff --git a/tests/compile-fail/data_race/write_write_race_stack.rs b/tests/compile-fail/data_race/write_write_race_stack.rs index aa1428f8a74b..bfe1464cb572 100644 --- a/tests/compile-fail/data_race/write_write_race_stack.rs +++ b/tests/compile-fail/data_race/write_write_race_stack.rs @@ -37,11 +37,11 @@ pub fn main() { let mut stack_var = 0usize; pointer.store(&mut stack_var as *mut _, Ordering::Release); - + sleep(Duration::from_millis(200)); stack_var = 1usize; //~ ERROR Data race detected between Write on Thread(id = 1) and Write on Thread(id = 2) - + // read to silence errors stack_var }); diff --git a/tests/compile-fail/panic/double_panic.rs b/tests/compile-fail/panic/double_panic.rs index b42c1aff1032..670c037988c2 100644 --- a/tests/compile-fail/panic/double_panic.rs +++ b/tests/compile-fail/panic/double_panic.rs @@ -8,5 +8,5 @@ impl Drop for Foo { } fn main() { let _foo = Foo; - panic!("first"); + panic!("first"); } diff --git a/tests/compile-fail/rc_as_ptr.rs b/tests/compile-fail/rc_as_ptr.rs index 1a9c322ac8d0..dc4e099982f8 100644 --- a/tests/compile-fail/rc_as_ptr.rs +++ b/tests/compile-fail/rc_as_ptr.rs @@ -12,7 +12,7 @@ fn main() { assert!(ptr::eq(&*strong, Weak::as_ptr(&weak))); // The strong here keeps it alive, so we can still access the object. assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); - + drop(strong); // But not any more. We can do Weak::as_raw(&weak), but accessing the pointer would lead to // undefined behaviour. diff --git a/tests/run-pass/backtrace-api-v1.rs b/tests/run-pass/backtrace-api-v1.rs index 7b72c85812eb..58ed63eaf395 100644 --- a/tests/run-pass/backtrace-api-v1.rs +++ b/tests/run-pass/backtrace-api-v1.rs @@ -24,7 +24,7 @@ fn main() { unsafe { miri_resolve_frame_names(*frame, 0, name.as_mut_ptr(), filename.as_mut_ptr()); } - + let name = String::from_utf8(name).unwrap(); let filename = String::from_utf8(filename).unwrap(); @@ -62,4 +62,4 @@ struct MiriFrame { lineno: u32, colno: u32, fn_ptr: *mut (), -} \ No newline at end of file +} diff --git a/tests/run-pass/concurrency/data_race.rs b/tests/run-pass/concurrency/data_race.rs index b53acc2691ff..2dc0ee3f8f1a 100644 --- a/tests/run-pass/concurrency/data_race.rs +++ b/tests/run-pass/concurrency/data_race.rs @@ -16,12 +16,12 @@ fn test_fence_sync() { let mut var = 0u32; let ptr = &mut var as *mut u32; let evil_ptr = EvilSend(ptr); - - + + let j1 = spawn(move || { unsafe { *evil_ptr.0 = 1; } fence(Ordering::Release); - SYNC.store(1, Ordering::Relaxed) + SYNC.store(1, Ordering::Relaxed) }); let j2 = spawn(move || { diff --git a/tests/run-pass/dyn-arbitrary-self.rs b/tests/run-pass/dyn-arbitrary-self.rs index 9003c478990b..5c19c260dd95 100644 --- a/tests/run-pass/dyn-arbitrary-self.rs +++ b/tests/run-pass/dyn-arbitrary-self.rs @@ -24,14 +24,14 @@ fn stdlib_pointers() { sync::Arc, pin::Pin, }; - + trait Trait { fn by_rc(self: Rc) -> i64; fn by_arc(self: Arc) -> i64; fn by_pin_mut(self: Pin<&mut Self>) -> i64; fn by_pin_box(self: Pin>) -> i64; } - + impl Trait for i64 { fn by_rc(self: Rc) -> i64 { *self @@ -46,7 +46,7 @@ fn stdlib_pointers() { *self } } - + let rc = Rc::new(1i64) as Rc; assert_eq!(1, rc.by_rc()); @@ -66,34 +66,34 @@ fn pointers_and_wrappers() { ops::{Deref, CoerceUnsized, DispatchFromDyn}, marker::Unsize, }; - + struct Ptr(Box); - + impl Deref for Ptr { type Target = T; - + fn deref(&self) -> &T { &*self.0 } } - + impl + ?Sized, U: ?Sized> CoerceUnsized> for Ptr {} impl + ?Sized, U: ?Sized> DispatchFromDyn> for Ptr {} - + struct Wrapper(T); - + impl Deref for Wrapper { type Target = T; - + fn deref(&self) -> &T { &self.0 } } - + impl, U> CoerceUnsized> for Wrapper {} impl, U> DispatchFromDyn> for Wrapper {} - - + + trait Trait { // This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable // without unsized_locals), but wrappers arond `Self` currently are not. @@ -103,7 +103,7 @@ fn pointers_and_wrappers() { fn wrapper_ptr(self: Wrapper>) -> i32; fn wrapper_ptr_wrapper(self: Wrapper>>) -> i32; } - + impl Trait for i32 { fn ptr_wrapper(self: Ptr>) -> i32 { **self @@ -115,7 +115,7 @@ fn pointers_and_wrappers() { ***self } } - + let pw = Ptr(Box::new(Wrapper(5))) as Ptr>; assert_eq!(pw.ptr_wrapper(), 5); diff --git a/tests/run-pass/ptr_offset.rs b/tests/run-pass/ptr_offset.rs index 71d057b8c9ce..6af3e28854ab 100644 --- a/tests/run-pass/ptr_offset.rs +++ b/tests/run-pass/ptr_offset.rs @@ -18,7 +18,7 @@ fn test_offset_from() { unsafe { assert_eq!(x.offset_from(y), -12); assert_eq!((y as *const u32).offset_from(x as *const u32), 12/4); assert_eq!((x as *const u32).offset_from(y as *const u32), -12/4); - + let x = (((x as usize) * 2) / 2) as *const u8; assert_eq!(y.offset_from(x), 12); assert_eq!(x.offset_from(y), -12); diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index b63f9addb0f6..80bab726a8f1 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -1,6 +1,6 @@ // compile-flags: -Zmiri-tag-raw-pointers use std::ptr; - + // Test various stacked-borrows-related things. fn main() { read_does_not_invalidate1(); diff --git a/tests/run-pass/threadleak_ignored.rs b/tests/run-pass/threadleak_ignored.rs index 7bb51d2dea61..cbdc7c6e9106 100644 --- a/tests/run-pass/threadleak_ignored.rs +++ b/tests/run-pass/threadleak_ignored.rs @@ -22,7 +22,7 @@ fn main() { // Set up a channel so that we can learn when the other thread initialized `X` // (so that we are sure there is something to drop). let (send, recv) = std::sync::mpsc::channel::<()>(); - + let _detached = std::thread::spawn(move || { X.with(|x| *x.borrow_mut() = Some(LoudDrop(1))); send.send(()).unwrap(); From 68ab457aa04090d52b7b1a91058957afd56ecc52 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 30 Apr 2022 13:50:35 -0400 Subject: [PATCH 3041/5092] Pass AccessKind to check_protector --- src/stacked_borrows.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 6ffa89087e86..fa7d72222ed0 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -327,20 +327,21 @@ impl<'tcx> Stack { /// `None` during a deallocation. fn check_protector( item: &Item, - provoking_access: Option<(SbTag, AllocId, AllocRange, Size)>, // just for debug printing and error messages + provoking_access: Option<(SbTag, AllocId, AllocRange, Size, AccessKind)>, // just for debug printing and error messages global: &GlobalStateInner, ) -> InterpResult<'tcx> { if let SbTag::Tagged(id) = item.tag { if global.tracked_pointer_tags.contains(&id) { register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag( *item, - None, + provoking_access + .map(|(tag, _alloc_id, _alloc_range, _size, access)| (tag, access)), )); } } if let Some(call) = item.protector { if global.is_active(call) { - if let Some((tag, alloc_id, alloc_range, offset)) = provoking_access { + if let Some((tag, alloc_id, alloc_range, offset, _access)) = provoking_access { Err(err_sb_ub( format!( "not granting access to tag {:?} because incompatible item is protected: {:?}", @@ -393,7 +394,11 @@ impl<'tcx> Stack { let first_incompatible_idx = self.find_first_write_incompatible(granting_idx); for item in self.borrows.drain(first_incompatible_idx..).rev() { trace!("access: popping item {:?}", item); - Stack::check_protector(&item, Some((tag, alloc_id, alloc_range, offset)), global)?; + Stack::check_protector( + &item, + Some((tag, alloc_id, alloc_range, offset, access)), + global, + )?; global.add_invalidation(item.tag, alloc_id, alloc_range); } } else { @@ -411,7 +416,7 @@ impl<'tcx> Stack { trace!("access: disabling item {:?}", item); Stack::check_protector( item, - Some((tag, alloc_id, alloc_range, offset)), + Some((tag, alloc_id, alloc_range, offset, access)), global, )?; item.perm = Permission::Disabled; From 1e49078a54a31af65900d0a72ee6d695676eba84 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 May 2022 13:44:12 +0200 Subject: [PATCH 3042/5092] mention some papers that use Miri --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 6d5ee30e498d..cc7164db1853 100644 --- a/README.md +++ b/README.md @@ -540,6 +540,12 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [Various standard library aliasing issues involving raw pointers](https://github.com/rust-lang/rust/pull/78602) * [`<[T]>::copy_within` using a loan after invalidating it](https://github.com/rust-lang/rust/pull/85610) +## Scientific papers employing Miri + +* [Stacked Borrows: An Aliasing Model for Rust](https://plv.mpi-sws.org/rustbelt/stacked-borrows/) +* [Using Lightweight Formal Methods to Validate a Key-Value Storage Node in Amazon S3](https://www.amazon.science/publications/using-lightweight-formal-methods-to-validate-a-key-value-storage-node-in-amazon-s3) +* [SyRust: Automatic Testing of Rust Libraries with Semantic-Aware Program Synthesis](https://dl.acm.org/doi/10.1145/3453483.3454084) + ## License Licensed under either of From 9bb4410d3a3594e969dd6dfb9e601a9651699093 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 5 May 2022 10:28:40 +0200 Subject: [PATCH 3043/5092] tweak MIRI_SYSROOT docs --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index cc7164db1853..9b05d3420e61 100644 --- a/README.md +++ b/README.md @@ -361,9 +361,10 @@ Moreover, Miri recognizes some environment variables: checkout. Note that changing files in that directory does not automatically trigger a re-build of the standard library; you have to clear the Miri build cache manually (on Linux, `rm -rf ~/.cache/miri`). -* `MIRI_SYSROOT` (recognized by `cargo miri` and the test suite) - indicates the sysroot to use. To do the same thing with `miri` - directly, use the `--sysroot` flag. +* `MIRI_SYSROOT` (recognized by `cargo miri` and the test suite) indicates the + sysroot to use. Only set this if you do not want to use the automatically + created sysroot. (The `miri` driver sysroot is controlled via the `--sysroot` + flag instead.) * `MIRI_TEST_TARGET` (recognized by the test suite) indicates which target architecture to test against. `miri` and `cargo miri` accept the `--target` flag for the same purpose. From 9605ae807d4db775a63d2a1c8da2719d478c2906 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 6 May 2022 17:28:01 +0200 Subject: [PATCH 3044/5092] rustup --- rust-version | 2 +- src/bin/miri.rs | 2 +- src/lib.rs | 1 - tests/run-pass/stacked-borrows/2phase.rs | 1 - 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index 685628ac99d5..5a3074f09a4b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -18b53cefdf7456bf68937b08e377b7e622a115c2 +9a251644fa2adde5f46eea8d342b7e60e4716039 diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 0030c24b19e6..3fac07a41a6b 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -1,4 +1,4 @@ -#![feature(rustc_private, bool_to_option, stmt_expr_attributes)] +#![feature(rustc_private, stmt_expr_attributes)] #![allow(clippy::manual_range_contains)] extern crate rustc_data_structures; diff --git a/src/lib.rs b/src/lib.rs index 3f1ba574ce06..ee7a3bcdc5cb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,6 @@ #![feature(never_type)] #![feature(try_blocks)] #![feature(let_else)] -#![feature(bool_to_option)] #![feature(io_error_more)] #![warn(rust_2018_idioms)] #![allow( diff --git a/tests/run-pass/stacked-borrows/2phase.rs b/tests/run-pass/stacked-borrows/2phase.rs index 948da140477e..065c76913a71 100644 --- a/tests/run-pass/stacked-borrows/2phase.rs +++ b/tests/run-pass/stacked-borrows/2phase.rs @@ -1,5 +1,4 @@ // compile-flags: -Zmiri-tag-raw-pointers -#![allow(mutable_borrow_reservation_conflict)] trait S: Sized { fn tpb(&mut self, _s: Self) {} From d585b92fe3f48eae65c85cea4f1203cde644f8d3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 8 May 2022 17:56:09 +0200 Subject: [PATCH 3045/5092] test for "erroneous constant used" post-monomorphization error --- src/diagnostics.rs | 6 +++++- tests/compile-fail/erroneous_const2.rs | 12 ++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/erroneous_const2.rs diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 5d20cc6ff6ba..2be61c502598 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -182,7 +182,11 @@ pub fn report_error<'tcx, 'mir>( "Undefined Behavior", ResourceExhaustion(_) => "resource exhaustion", - InvalidProgram(InvalidProgramInfo::AlreadyReported(_) | InvalidProgramInfo::Layout(..)) => + InvalidProgram( + InvalidProgramInfo::AlreadyReported(_) | + InvalidProgramInfo::Layout(..) | + InvalidProgramInfo::ReferencedConstant + ) => "post-monomorphization error", kind => bug!("This error should be impossible in Miri: {:?}", kind), diff --git a/tests/compile-fail/erroneous_const2.rs b/tests/compile-fail/erroneous_const2.rs new file mode 100644 index 000000000000..cdec2ec4f095 --- /dev/null +++ b/tests/compile-fail/erroneous_const2.rs @@ -0,0 +1,12 @@ +const X: u32 = 5; +const Y: u32 = 6; +const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; +//~^ERROR any use of this value +//~|WARN previously accepted + +fn main() { + println!("{}", FOO); //~ERROR post-monomorphization error + //~|ERROR evaluation of constant value failed + //~|ERROR erroneous constant used + //~|WARN previously accepted +} From 5a6c4a60fedf354f10309047455420edb1dc9968 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 9 May 2022 10:21:15 +0200 Subject: [PATCH 3046/5092] rustup --- rust-version | 2 +- src/machine.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 5a3074f09a4b..8a247d5ab69b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9a251644fa2adde5f46eea8d342b7e60e4716039 +8fbd92d0b95d847c68948d8dbbfaccb470db4f92 diff --git a/src/machine.rs b/src/machine.rs index 0a8a229c8aa2..8b077fa815b1 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -380,7 +380,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { // Most of them are for weak symbols, which we all set to null (indicating that the // symbol is not supported, and triggering fallback code which ends up calling a // syscall that we do support). - for name in &["__cxa_thread_atexit_impl", "getrandom", "statx"] { + for name in &["__cxa_thread_atexit_impl", "getrandom", "statx", "__clock_gettime64"] { let layout = this.machine.layouts.usize; let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; this.write_scalar(Scalar::from_machine_usize(0, this), &place.into())?; From 8dbe1d02cdaaf533f91eeaf22e7627ffd8007022 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 9 May 2022 11:17:48 +0200 Subject: [PATCH 3047/5092] rustfmt --- src/machine.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/machine.rs b/src/machine.rs index 8b077fa815b1..2d8f5855330f 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -380,7 +380,8 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { // Most of them are for weak symbols, which we all set to null (indicating that the // symbol is not supported, and triggering fallback code which ends up calling a // syscall that we do support). - for name in &["__cxa_thread_atexit_impl", "getrandom", "statx", "__clock_gettime64"] { + for name in &["__cxa_thread_atexit_impl", "getrandom", "statx", "__clock_gettime64"] + { let layout = this.machine.layouts.usize; let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; this.write_scalar(Scalar::from_machine_usize(0, this), &place.into())?; From c8b947a5edb209c55c2ec2d6c4c1075db5d4d4ce Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 10 May 2022 07:23:03 +0000 Subject: [PATCH 3048/5092] Use alphabetical order for miri flags --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4cb03ed7b0b2..291c01dd4cfd 100644 --- a/README.md +++ b/README.md @@ -265,10 +265,6 @@ environment variable: * `-Zmiri-disable-isolation` disables host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness. -* `-Zmiri-mute-stdout-stderr` silently ignores all writes to stdout and stderr, - but reports to the program that it did actually write. This is useful when you - are not interested in the actual program's messages, but only want to see miri's - errors and warnings. * `-Zmiri-isolation-error=` configures Miri's response to operations requiring host access while isolation is enabled. `abort`, `hide`, `warn`, and `warn-nobacktrace` are the supported actions. The default is to `abort`, @@ -290,6 +286,10 @@ environment variable: This can be used to find which parts of your program are executing slowly under Miri. The profile is written out to a file with the prefix ``, and can be processed using the tools in the repository https://github.com/rust-lang/measureme. +* `-Zmiri-mute-stdout-stderr` silently ignores all writes to stdout and stderr, + but reports to the program that it did actually write. This is useful when you + are not interested in the actual program's messages, but only want to see miri's + errors and warnings. * `-Zmiri-panic-on-unsupported` will makes some forms of unsupported functionality, such as FFI and unsupported syscalls, panic within the context of the emulated application instead of raising an error within the context of Miri (and halting From 6dc6256413a242a3917b01ac28059024dc6bef45 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 10 May 2022 07:23:50 +0000 Subject: [PATCH 3049/5092] Wording nit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 291c01dd4cfd..127206e11544 100644 --- a/README.md +++ b/README.md @@ -288,7 +288,7 @@ environment variable: using the tools in the repository https://github.com/rust-lang/measureme. * `-Zmiri-mute-stdout-stderr` silently ignores all writes to stdout and stderr, but reports to the program that it did actually write. This is useful when you - are not interested in the actual program's messages, but only want to see miri's + are not interested in the actual program's output, but only want to see miri's errors and warnings. * `-Zmiri-panic-on-unsupported` will makes some forms of unsupported functionality, such as FFI and unsupported syscalls, panic within the context of the emulated From 82411c5840dc4e06f20c14a81767b48ef4fb19be Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 10 May 2022 12:14:47 +0200 Subject: [PATCH 3050/5092] stop relying on python being in the PATH --- miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri b/miri index 0ba7e536abe5..56ae119cd1bc 100755 --- a/miri +++ b/miri @@ -40,7 +40,7 @@ TARGET=$(rustc --version --verbose | grep "^host:" | cut -d ' ' -f 2) SYSROOT=$(rustc --print sysroot) LIBDIR=$SYSROOT/lib/rustlib/$TARGET/lib # macOS does not have a useful readlink/realpath so we have to use Python instead... -MIRIDIR=$(dirname "$(python -c 'import os, sys; print(os.path.realpath(sys.argv[1]))' "$0")") +MIRIDIR=$(dirname "$(python3 -c 'import os, sys; print(os.path.realpath(sys.argv[1]))' "$0")") if ! test -d "$LIBDIR"; then echo "Something went wrong determining the library dir." echo "I got $LIBDIR but that does not exist." From a2f683757449657911d130c650cb0eba5b81563b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 10 May 2022 12:21:01 +0200 Subject: [PATCH 3051/5092] rustfmt --- src/machine.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine.rs b/src/machine.rs index 1f1caa866118..2ecb583abb2c 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -28,7 +28,7 @@ use rustc_span::symbol::{sym, Symbol}; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; -use crate::{*, shims::posix::FileHandler}; +use crate::{shims::posix::FileHandler, *}; // Some global facts about the emulated machine. pub const PAGE_SIZE: u64 = 4 * 1024; // FIXME: adjust to target architecture From b25d7b0e34fd488558e1665da1b2aa2397bfaaeb Mon Sep 17 00:00:00 2001 From: y86-dev <94611769+y86-dev@users.noreply.github.com> Date: Tue, 10 May 2022 20:46:12 +0200 Subject: [PATCH 3052/5092] Clarified issues when building miri with a custom rustc Co-authored-by: Ralf Jung --- CONTRIBUTING.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 359378504343..054ff433d3ed 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -206,6 +206,13 @@ rustup toolchain link stage2 build/x86_64-unknown-linux-gnu/stage2 rustup override set stage2 ``` +Important: You need to delete the miri cache (located at `~/.cache/miri` on Linux; the exact location is printed after the library build: "A libstd for Miri is now available in ...") when +you change the stdlib, otherwise the old, chached version will be used. + +Note: `./x.py --stage 2 compiler/rustc` currently errors with `thread 'main' +panicked at 'fs::read(stamp) failed with No such file or directory (os error 2)`, +you can simply ignore that error; Miri will build anyway. + For more information about building and configuring a local compiler, see . From 4632b2c6897ed8bfd4da39d45999a8b0a5b875f5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 10 May 2022 21:38:32 +0200 Subject: [PATCH 3053/5092] tweak wording --- CONTRIBUTING.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 054ff433d3ed..996164b93e8b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -206,8 +206,9 @@ rustup toolchain link stage2 build/x86_64-unknown-linux-gnu/stage2 rustup override set stage2 ``` -Important: You need to delete the miri cache (located at `~/.cache/miri` on Linux; the exact location is printed after the library build: "A libstd for Miri is now available in ...") when -you change the stdlib, otherwise the old, chached version will be used. +Important: You need to delete the Miri cache when you change the stdlib; otherwise the +old, chached version will be used. On Linux, the cache is located at `~/.cache/miri`; the exact +location is printed after the library build: "A libstd for Miri is now available in ...". Note: `./x.py --stage 2 compiler/rustc` currently errors with `thread 'main' panicked at 'fs::read(stamp) failed with No such file or directory (os error 2)`, From c15845bf2951991ce47ec047666a2cbe75759e9d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 May 2022 10:03:56 +0200 Subject: [PATCH 3054/5092] when MIRI_LOG is set, set RUSTC_LOG_ENTRY_EXIT --- src/bin/miri.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index b1c2872513e4..0aa8755573a6 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -155,6 +155,10 @@ fn init_early_loggers() { // initialize them both, and we always initialize `miri`'s first. let env = env_logger::Env::new().filter("MIRI_LOG").write_style("MIRI_LOG_STYLE"); env_logger::init_from_env(env); + // Enable verbose entry/exit logging by default if MIRI_LOG is set. + if env::var_os("MIRI_LOG").is_some() && env::var_os("RUSTC_LOG_ENTRY_EXIT").is_none() { + env::set_var("RUSTC_LOG_ENTRY_EXIT", "1"); + } // We only initialize `rustc` if the env var is set (so the user asked for it). // If it is not set, we avoid initializing now so that we can initialize // later with our custom settings, and *not* log anything for what happens before From 1a7f6d504a12f826b59c2cee3067fe02701aef04 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sat, 7 May 2022 21:30:15 +0100 Subject: [PATCH 3055/5092] Use proper atomic rmw for {mutex, rwlock, cond, srwlock}_get_or_create_id --- src/data_race.rs | 31 ++++++++++++-------- src/shims/posix/sync.rs | 61 +++++++++++++++++++++++++++------------ src/shims/windows/sync.rs | 21 ++++++++++---- src/sync.rs | 21 ++++++++++++++ 4 files changed, 98 insertions(+), 36 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index d249d28d03f5..b7ccaa35305e 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -441,6 +441,23 @@ impl MemoryCellClocks { /// Evaluation context extensions. impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { + /// Calculates the MPlaceTy given the offset and layout of an access on an operand + fn offset_and_layout_to_place( + &self, + op: &OpTy<'tcx, Tag>, + offset: u64, + layout: TyAndLayout<'tcx>, + ) -> InterpResult<'tcx, MPlaceTy<'tcx, Tag>> { + let this = self.eval_context_ref(); + let op_place = this.deref_operand(op)?; + let offset = Size::from_bytes(offset); + + // Ensure that the access is within bounds. + assert!(op_place.layout.size >= offset + layout.size); + let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; + Ok(value_place) + } + /// Atomic variant of read_scalar_at_offset. fn read_scalar_at_offset_atomic( &self, @@ -450,12 +467,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicReadOp, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_ref(); - let op_place = this.deref_operand(op)?; - let offset = Size::from_bytes(offset); - - // Ensure that the following read at an offset is within bounds. - assert!(op_place.layout.size >= offset + layout.size); - let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; + let value_place = this.offset_and_layout_to_place(op, offset, layout)?; this.read_scalar_atomic(&value_place, atomic) } @@ -469,12 +481,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicWriteOp, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let op_place = this.deref_operand(op)?; - let offset = Size::from_bytes(offset); - - // Ensure that the following read at an offset is within bounds. - assert!(op_place.layout.size >= offset + layout.size); - let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; + let value_place = this.offset_and_layout_to_place(op, offset, layout)?; this.write_scalar_atomic(value.into(), &value_place, atomic) } diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index ea940df1c6e8..f8c680c0e828 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -112,15 +112,23 @@ fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, MutexId> { - let id = mutex_get_id(ecx, mutex_op)?.to_u32()?; - if id == 0 { - // 0 is a default value and also not a valid mutex id. Need to allocate - // a new mutex. + let value_place = ecx.offset_and_layout_to_place(mutex_op, 4, ecx.machine.layouts.u32)?; + let (old, success) = ecx + .atomic_compare_exchange_scalar( + &value_place, + &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), + ecx.mutex_next_id().to_u32_scalar().into(), + AtomicRwOp::Relaxed, + AtomicReadOp::Relaxed, + false, + )? + .to_scalar_pair()?; + + if success.to_bool().expect("compare_exchange's second return value is a bool") { let id = ecx.mutex_create(); - mutex_set_id(ecx, mutex_op, id.to_u32_scalar())?; Ok(id) } else { - Ok(MutexId::from_u32(id)) + Ok(MutexId::from_u32(old.to_u32().expect("layout is u32"))) } } @@ -156,15 +164,23 @@ fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, rwlock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, RwLockId> { - let id = rwlock_get_id(ecx, rwlock_op)?.to_u32()?; - if id == 0 { - // 0 is a default value and also not a valid rwlock id. Need to allocate - // a new read-write lock. + let value_place = ecx.offset_and_layout_to_place(rwlock_op, 4, ecx.machine.layouts.u32)?; + let (old, success) = ecx + .atomic_compare_exchange_scalar( + &value_place, + &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), + ecx.rwlock_next_id().to_u32_scalar().into(), + AtomicRwOp::Relaxed, + AtomicReadOp::Relaxed, + false, + )? + .to_scalar_pair()?; + + if success.to_bool().expect("compare_exchange's second return value is a bool") { let id = ecx.rwlock_create(); - rwlock_set_id(ecx, rwlock_op, id.to_u32_scalar())?; Ok(id) } else { - Ok(RwLockId::from_u32(id)) + Ok(RwLockId::from_u32(old.to_u32().expect("layout is u32"))) } } @@ -228,15 +244,24 @@ fn cond_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, cond_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, CondvarId> { - let id = cond_get_id(ecx, cond_op)?.to_u32()?; - if id == 0 { - // 0 is a default value and also not a valid conditional variable id. - // Need to allocate a new id. + let value_place = ecx.offset_and_layout_to_place(cond_op, 4, ecx.machine.layouts.u32)?; + + let (old, success) = ecx + .atomic_compare_exchange_scalar( + &value_place, + &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), + ecx.condvar_next_id().to_u32_scalar().into(), + AtomicRwOp::Relaxed, + AtomicReadOp::Relaxed, + false, + )? + .to_scalar_pair()?; + + if success.to_bool().expect("compare_exchange's second return value is a bool") { let id = ecx.condvar_create(); - cond_set_id(ecx, cond_op, id.to_u32_scalar())?; Ok(id) } else { - Ok(CondvarId::from_u32(id)) + Ok(CondvarId::from_u32(old.to_u32().expect("layout is u32"))) } } diff --git a/src/shims/windows/sync.rs b/src/shims/windows/sync.rs index 78458dc6c997..ccd65aac900f 100644 --- a/src/shims/windows/sync.rs +++ b/src/shims/windows/sync.rs @@ -7,15 +7,24 @@ fn srwlock_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, lock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, RwLockId> { - let id = ecx.read_scalar_at_offset(lock_op, 0, ecx.machine.layouts.u32)?.to_u32()?; - if id == 0 { - // 0 is a default value and also not a valid rwlock id. Need to allocate - // a new rwlock. + let value_place = ecx.offset_and_layout_to_place(lock_op, 0, ecx.machine.layouts.u32)?; + + let (old, success) = ecx + .atomic_compare_exchange_scalar( + &value_place, + &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), + ecx.rwlock_next_id().to_u32_scalar().into(), + AtomicRwOp::AcqRel, + AtomicReadOp::Acquire, + false, + )? + .to_scalar_pair()?; + + if success.to_bool().expect("compare_exchange's second return value is a bool") { let id = ecx.rwlock_create(); - ecx.write_scalar_at_offset(lock_op, 0, id.to_u32_scalar(), ecx.machine.layouts.u32)?; Ok(id) } else { - Ok(RwLockId::from_u32(id)) + Ok(RwLockId::from_u32(old.to_u32().expect("layout is u32"))) } } diff --git a/src/sync.rs b/src/sync.rs index ac1687a22e30..8c5b8ebfec75 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -208,6 +208,13 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // situations. impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + #[inline] + /// Peek the id of the next mutex + fn mutex_next_id(&self) -> MutexId { + let this = self.eval_context_ref(); + this.machine.threads.sync.mutexes.next_index() + } + #[inline] /// Create state for a new mutex. fn mutex_create(&mut self) -> MutexId { @@ -290,6 +297,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.block_thread(thread); } + #[inline] + /// Peek the id of the next read write lock + fn rwlock_next_id(&self) -> RwLockId { + let this = self.eval_context_ref(); + this.machine.threads.sync.rwlocks.next_index() + } + #[inline] /// Create state for a new read write lock. fn rwlock_create(&mut self) -> RwLockId { @@ -438,6 +452,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.block_thread(writer); } + #[inline] + /// Peek the id of the next Condvar + fn condvar_next_id(&self) -> CondvarId { + let this = self.eval_context_ref(); + this.machine.threads.sync.condvars.next_index() + } + #[inline] /// Create state for a new conditional variable. fn condvar_create(&mut self) -> CondvarId { From 972b3b340ad99553618e551937d93bf28e2d2f5c Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Wed, 11 May 2022 19:13:00 -0400 Subject: [PATCH 3056/5092] Cleanup/Refactoring from review * Pass a ThreadInfo down to grant/access to get the current span lazily * Rename add_* to log_* for clarity * Hoist borrow_mut calls out of loops by tweaking the for_each signature * Explain the parameters of check_protector a bit more --- src/eval.rs | 4 -- src/machine.rs | 58 +++++---------------- src/stacked_borrows.rs | 84 ++++++++++++++++++------------ src/stacked_borrows/diagnostics.rs | 69 ++++++++++++++++++------ 4 files changed, 117 insertions(+), 98 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index a3228f763a8e..f8d23cb8279c 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -15,7 +15,6 @@ use rustc_target::spec::abi::Abi; use rustc_session::config::EntryFnType; -use rustc_span::DUMMY_SP; use std::collections::HashSet; use crate::*; @@ -311,9 +310,6 @@ pub fn eval_entry<'tcx>( let info = ecx.preprocess_diagnostics(); match ecx.schedule()? { SchedulingAction::ExecuteStep => { - if let Some(sb) = ecx.machine.stacked_borrows.as_mut() { - sb.get_mut().current_span = DUMMY_SP; - } assert!(ecx.step()?, "a terminated thread was scheduled for execution"); } SchedulingAction::ExecuteTimeoutCallback => { diff --git a/src/machine.rs b/src/machine.rs index 2fb5dca6dd68..7cb08066a6c3 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -25,7 +25,6 @@ use rustc_middle::{ }; use rustc_span::def_id::{CrateNum, DefId}; use rustc_span::symbol::{sym, Symbol}; -use rustc_span::DUMMY_SP; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; @@ -308,6 +307,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { config.tracked_pointer_tags.clone(), config.tracked_call_ids.clone(), config.tag_raw, + local_crates.clone(), ))) } else { None @@ -562,7 +562,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { alloc: Cow<'b, Allocation>, kind: Option>, ) -> Cow<'b, Allocation> { - set_current_span(&ecx.machine); if ecx.machine.tracked_alloc_ids.contains(&id) { register_diagnostic(NonHaltingDiagnostic::CreatedAlloc(id)); } @@ -570,7 +569,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); let stacks = if let Some(stacked_borrows) = &ecx.machine.stacked_borrows { - Some(Stacks::new_allocation(id, alloc.size(), stacked_borrows, kind)) + Some(Stacks::new_allocation( + id, + alloc.size(), + stacked_borrows, + kind, + &ecx.machine.threads, + )) } else { None }; @@ -591,7 +596,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer, ) -> Pointer { - set_current_span(&ecx.machine); let absolute_addr = intptrcast::GlobalStateInner::rel_ptr_to_addr(ecx, ptr); let sb_tag = if let Some(stacked_borrows) = &ecx.machine.stacked_borrows { stacked_borrows.borrow_mut().base_tag(ptr.provenance) @@ -627,7 +631,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { (alloc_id, tag): (AllocId, Self::TagExtra), range: AllocRange, ) -> InterpResult<'tcx> { - set_current_span(&machine); if let Some(data_race) = &alloc_extra.data_race { data_race.read(alloc_id, range, machine.data_race.as_ref().unwrap())?; } @@ -637,6 +640,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { tag, range, machine.stacked_borrows.as_ref().unwrap(), + &machine.threads, ) } else { Ok(()) @@ -651,7 +655,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { (alloc_id, tag): (AllocId, Self::TagExtra), range: AllocRange, ) -> InterpResult<'tcx> { - set_current_span(&machine); if let Some(data_race) = &mut alloc_extra.data_race { data_race.write(alloc_id, range, machine.data_race.as_mut().unwrap())?; } @@ -661,6 +664,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { tag, range, machine.stacked_borrows.as_ref().unwrap(), + &machine.threads, ) } else { Ok(()) @@ -675,7 +679,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { (alloc_id, tag): (AllocId, Self::TagExtra), range: AllocRange, ) -> InterpResult<'tcx> { - set_current_span(&machine); if machine.tracked_alloc_ids.contains(&alloc_id) { register_diagnostic(NonHaltingDiagnostic::FreedAlloc(alloc_id)); } @@ -700,12 +703,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { kind: mir::RetagKind, place: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { - if ecx.machine.stacked_borrows.is_some() { - set_current_span(&ecx.machine); - ecx.retag(kind, place) - } else { - Ok(()) - } + if ecx.machine.stacked_borrows.is_some() { ecx.retag(kind, place) } else { Ok(()) } } #[inline(always)] @@ -751,12 +749,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn after_stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { - if ecx.machine.stacked_borrows.is_some() { - set_current_span(&ecx.machine); - ecx.retag_return_place() - } else { - Ok(()) - } + if ecx.machine.stacked_borrows.is_some() { ecx.retag_return_place() } else { Ok(()) } } #[inline(always)] @@ -773,30 +766,3 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { res } } - -// This is potentially a performance hazard. -// Factoring it into its own function lets us keep an eye on how much it shows up in a profile. -/// -fn set_current_span<'mir, 'tcx: 'mir>(machine: &Evaluator<'mir, 'tcx>) { - if let Some(sb) = machine.stacked_borrows.as_ref() { - if sb.borrow().current_span != DUMMY_SP { - return; - } - let current_span = machine - .threads - .active_thread_stack() - .into_iter() - .rev() - .find(|frame| { - let info = FrameInfo { - instance: frame.instance, - span: frame.current_span(), - lint_root: None, - }; - machine.is_local(&info) - }) - .map(|frame| frame.current_span()) - .unwrap_or(rustc_span::DUMMY_SP); - sb.borrow_mut().current_span = current_span; - } -} diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index fa7d72222ed0..1aec3c0e5eab 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -14,7 +14,7 @@ use rustc_middle::ty::{ self, layout::{HasParamEnv, LayoutOf}, }; -use rustc_span::Span; +use rustc_span::def_id::CrateNum; use rustc_span::DUMMY_SP; use rustc_target::abi::Size; use std::collections::HashSet; @@ -118,10 +118,10 @@ pub struct GlobalStateInner { tracked_call_ids: HashSet, /// Whether to track raw pointers. tag_raw: bool, + /// Crates which are considered local for the purposes of error reporting. + local_crates: Vec, /// Extra per-allocation information extras: HashMap, - /// Current span - pub(crate) current_span: Span, } /// We need interior mutable access to the global state. @@ -174,6 +174,7 @@ impl GlobalStateInner { tracked_pointer_tags: HashSet, tracked_call_ids: HashSet, tag_raw: bool, + local_crates: Vec, ) -> Self { GlobalStateInner { next_ptr_id: NonZeroU64::new(1).unwrap(), @@ -183,8 +184,8 @@ impl GlobalStateInner { tracked_pointer_tags, tracked_call_ids, tag_raw, + local_crates, extras: HashMap::new(), - current_span: DUMMY_SP, } } @@ -325,6 +326,9 @@ impl<'tcx> Stack { /// The `provoking_access` argument is only used to produce diagnostics. /// It is `Some` when we are granting the contained access for said tag, and it is /// `None` during a deallocation. + /// Within `provoking_access, the `AllocRange` refers the entire operation, and + /// the `Size` refers to the specific location in the `AllocRange` that we are + /// currently checking. fn check_protector( item: &Item, provoking_access: Option<(SbTag, AllocId, AllocRange, Size, AccessKind)>, // just for debug printing and error messages @@ -378,6 +382,7 @@ impl<'tcx> Stack { tag: SbTag, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &mut GlobalStateInner, + threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. @@ -399,7 +404,7 @@ impl<'tcx> Stack { Some((tag, alloc_id, alloc_range, offset, access)), global, )?; - global.add_invalidation(item.tag, alloc_id, alloc_range); + global.log_invalidation(item.tag, alloc_id, alloc_range, threads); } } else { // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses. @@ -420,7 +425,7 @@ impl<'tcx> Stack { global, )?; item.perm = Permission::Disabled; - global.add_invalidation(item.tag, alloc_id, alloc_range); + global.log_invalidation(item.tag, alloc_id, alloc_range, threads); } } } @@ -468,6 +473,7 @@ impl<'tcx> Stack { new: Item, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &mut GlobalStateInner, + threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { // Figure out which access `perm` corresponds to. let access = @@ -495,7 +501,7 @@ impl<'tcx> Stack { // A "safe" reborrow for a pointer that actually expects some aliasing guarantees. // Here, creating a reference actually counts as an access. // This ensures F2b for `Unique`, by removing offending `SharedReadOnly`. - self.access(access, derived_from, (alloc_id, alloc_range, offset), global)?; + self.access(access, derived_from, (alloc_id, alloc_range, offset), global, threads)?; // We insert "as far up as possible": We know only compatible items are remaining // on top of `derived_from`, and we want the new item at the top so that we @@ -532,7 +538,7 @@ impl<'tcx> Stacks { fn for_each( &self, range: AllocRange, - f: impl Fn(Size, &mut Stack) -> InterpResult<'tcx>, + mut f: impl FnMut(Size, &mut Stack) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { let mut stacks = self.stacks.borrow_mut(); for (offset, stack) in stacks.iter_mut(range.start, range.size) { @@ -545,7 +551,7 @@ impl<'tcx> Stacks { fn for_each_mut( &mut self, range: AllocRange, - f: impl Fn(Size, &mut Stack) -> InterpResult<'tcx>, + mut f: impl FnMut(Size, &mut Stack) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { let stacks = self.stacks.get_mut(); for (offset, stack) in stacks.iter_mut(range.start, range.size) { @@ -562,6 +568,7 @@ impl Stacks { size: Size, state: &GlobalState, kind: MemoryKind, + threads: &ThreadManager<'_, '_>, ) -> Self { let mut extra = state.borrow_mut(); let (base_tag, perm) = match kind { @@ -595,7 +602,7 @@ impl Stacks { (tag, Permission::SharedReadWrite) } }; - extra.add_creation(None, base_tag, id, alloc_range(Size::ZERO, size)); + extra.log_creation(None, base_tag, id, alloc_range(Size::ZERO, size), threads); Stacks::new(size, perm, base_tag) } @@ -606,6 +613,7 @@ impl Stacks { tag: SbTag, range: AllocRange, state: &GlobalState, + threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { trace!( "read access with tag {:?}: {:?}, size {}", @@ -613,9 +621,9 @@ impl Stacks { Pointer::new(alloc_id, range.start), range.size.bytes() ); - self.for_each(range, move |offset, stack| { - let mut state = state.borrow_mut(); - stack.access(AccessKind::Read, tag, (alloc_id, range, offset), &mut state) + let mut state = state.borrow_mut(); + self.for_each(range, |offset, stack| { + stack.access(AccessKind::Read, tag, (alloc_id, range, offset), &mut state, threads) }) } @@ -626,6 +634,7 @@ impl Stacks { tag: SbTag, range: AllocRange, state: &GlobalState, + threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { trace!( "write access with tag {:?}: {:?}, size {}", @@ -633,9 +642,9 @@ impl Stacks { Pointer::new(alloc_id, range.start), range.size.bytes() ); - self.for_each_mut(range, move |offset, stack| { - let mut state = state.borrow_mut(); - stack.access(AccessKind::Write, tag, (alloc_id, range, offset), &mut state) + let mut state = state.borrow_mut(); + self.for_each_mut(range, |offset, stack| { + stack.access(AccessKind::Write, tag, (alloc_id, range, offset), &mut state, threads) }) } @@ -648,11 +657,11 @@ impl Stacks { state: &GlobalState, ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", tag, alloc_id, range.size.bytes()); - self.for_each_mut(range, move |offset, stack| { - let mut state = state.borrow_mut(); + let mut state = state.borrow_mut(); + self.for_each_mut(range, |offset, stack| { stack.dealloc(tag, (alloc_id, range, offset), &mut state) })?; - state.borrow_mut().extras.remove(&alloc_id); + state.extras.remove(&alloc_id); Ok(()) } } @@ -684,14 +693,15 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?; let mem_extra = this.machine.stacked_borrows.as_mut().unwrap().get_mut(); - mem_extra.add_creation( + mem_extra.log_creation( Some(orig_tag), new_tag, alloc_id, alloc_range(base_offset, base_offset + size), + &this.machine.threads, ); if protect { - mem_extra.add_protector(orig_tag, new_tag, alloc_id); + mem_extra.log_protector(orig_tag, new_tag, alloc_id, &this.machine.threads); } // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). @@ -752,10 +762,15 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Permission::SharedReadWrite }; let item = Item { perm, tag: new_tag, protector }; + let mut global = this.machine.stacked_borrows.as_ref().unwrap().borrow_mut(); stacked_borrows.for_each(range, |offset, stack| { - let mut global = - this.machine.stacked_borrows.as_ref().unwrap().borrow_mut(); - stack.grant(orig_tag, item, (alloc_id, range, offset), &mut *global) + stack.grant( + orig_tag, + item, + (alloc_id, range, offset), + &mut *global, + &this.machine.threads, + ) }) })?; return Ok(()); @@ -764,15 +779,16 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Here we can avoid `borrow()` calls because we have mutable references. // Note that this asserts that the allocation is mutable -- but since we are creating a // mutable pointer, that seems reasonable. - let (alloc_extra, memory_extra) = this.get_alloc_extra_mut(alloc_id)?; + let (alloc_extra, machine) = this.get_alloc_extra_mut(alloc_id)?; let stacked_borrows = alloc_extra.stacked_borrows.as_mut().expect("we should have Stacked Borrows data"); let item = Item { perm, tag: new_tag, protector }; let range = alloc_range(base_offset, size); + let mut global = machine.stacked_borrows.as_ref().unwrap().borrow_mut(); stacked_borrows.for_each_mut(range, |offset, stack| { - let mut global = memory_extra.stacked_borrows.as_ref().unwrap().borrow_mut(); - stack.grant(orig_tag, item, (alloc_id, range, offset), &mut *global) + stack.grant(orig_tag, item, (alloc_id, range, offset), &mut global, &machine.threads) })?; + Ok(()) } @@ -797,12 +813,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Compute new borrow. - let mem_extra = this.machine.stacked_borrows.as_mut().unwrap().get_mut(); - let new_tag = match kind { - // Give up tracking for raw pointers. - RefKind::Raw { .. } if !mem_extra.tag_raw => SbTag::Untagged, - // All other pointers are properly tracked. - _ => SbTag::Tagged(mem_extra.new_ptr()), + let new_tag = { + let mem_extra = this.machine.stacked_borrows.as_mut().unwrap().get_mut(); + match kind { + // Give up tracking for raw pointers. + RefKind::Raw { .. } if !mem_extra.tag_raw => SbTag::Untagged, + // All other pointers are properly tracked. + _ => SbTag::Tagged(mem_extra.new_ptr()), + } }; // Reborrow. diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index d5a65825bc2c..f657a926c0a5 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -7,6 +7,7 @@ use crate::stacked_borrows::{err_sb_ub, AccessKind, GlobalStateInner, Permission use crate::Item; use crate::SbTag; use crate::Stack; +use crate::ThreadManager; use rustc_middle::mir::interpret::InterpError; @@ -52,17 +53,32 @@ pub enum TagHistory { } pub trait GlobalStateExt { - fn add_creation( + fn current_span(&self, threads: &ThreadManager<'_, '_>) -> Span; + + fn log_creation( &mut self, parent: Option, tag: SbTag, alloc: AllocId, range: AllocRange, + threads: &ThreadManager<'_, '_>, ); - fn add_invalidation(&mut self, tag: SbTag, alloc: AllocId, range: AllocRange); + fn log_invalidation( + &mut self, + tag: SbTag, + alloc: AllocId, + range: AllocRange, + threads: &ThreadManager<'_, '_>, + ); - fn add_protector(&mut self, orig_tag: SbTag, tag: SbTag, alloc: AllocId); + fn log_protector( + &mut self, + orig_tag: SbTag, + tag: SbTag, + alloc: AllocId, + threads: &ThreadManager<'_, '_>, + ); fn get_stack_history( &self, @@ -75,39 +91,62 @@ pub trait GlobalStateExt { } impl GlobalStateExt for GlobalStateInner { - fn add_creation( + fn current_span(&self, threads: &ThreadManager<'_, '_>) -> Span { + threads + .active_thread_stack() + .into_iter() + .rev() + .find(|frame| { + let def_id = frame.instance.def_id(); + def_id.is_local() || self.local_crates.contains(&def_id.krate) + }) + .map(|frame| frame.current_span()) + .unwrap_or(rustc_span::DUMMY_SP) + } + + fn log_creation( &mut self, parent: Option, tag: SbTag, alloc: AllocId, range: AllocRange, + threads: &ThreadManager<'_, '_>, ) { + let span = self.current_span(threads); let extras = self.extras.entry(alloc).or_default(); - extras.creations.push(Event { - parent, - tag, - range, - span: self.current_span, - time: extras.current_time, - }); + extras.creations.push(Event { parent, tag, range, span, time: extras.current_time }); extras.current_time += 1; } - fn add_invalidation(&mut self, tag: SbTag, alloc: AllocId, range: AllocRange) { + fn log_invalidation( + &mut self, + tag: SbTag, + alloc: AllocId, + range: AllocRange, + threads: &ThreadManager<'_, '_>, + ) { + let span = self.current_span(threads); let extras = self.extras.entry(alloc).or_default(); extras.invalidations.push(Event { parent: None, tag, range, - span: self.current_span, + span, time: extras.current_time, }); extras.current_time += 1; } - fn add_protector(&mut self, orig_tag: SbTag, tag: SbTag, alloc: AllocId) { + fn log_protector( + &mut self, + orig_tag: SbTag, + tag: SbTag, + alloc: AllocId, + threads: &ThreadManager<'_, '_>, + ) { + let span = self.current_span(threads); let extras = self.extras.entry(alloc).or_default(); - extras.protectors.push(Protection { orig_tag, tag, span: self.current_span }); + extras.protectors.push(Protection { orig_tag, tag, span }); extras.current_time += 1; } From 0ee9d3d047ab3c23c1f87e5c58a0a3e64a3dfe66 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 12 May 2022 10:42:53 +0000 Subject: [PATCH 3057/5092] Update a path to libstd source in our comments --- src/shims/foreign_items.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index e9845c537663..66ba793b98cc 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -42,7 +42,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Returns the minimum alignment for the target architecture for allocations of the given size. fn min_align(&self, size: u64, kind: MiriMemoryKind) -> Align { let this = self.eval_context_ref(); - // List taken from `libstd/sys_common/alloc.rs`. + // List taken from `library/std/src/sys/common/alloc.rs`. + // This list should be kept in sync with the one from libstd. let min_align = match this.tcx.sess.target.arch.as_ref() { "x86" | "arm" | "mips" | "powerpc" | "powerpc64" | "asmjs" | "wasm32" => 8, "x86_64" | "aarch64" | "mips64" | "s390x" | "sparc64" => 16, From 19e1c72a778d3f9762d08e90fb41b0afe04a7214 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 May 2022 19:01:04 +0200 Subject: [PATCH 3058/5092] rustup --- rust-version | 2 +- src/helpers.rs | 10 +++++++++- src/machine.rs | 8 ++------ src/shims/foreign_items.rs | 9 ++------- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/rust-version b/rust-version index 8a247d5ab69b..630aee6793f3 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8fbd92d0b95d847c68948d8dbbfaccb470db4f92 +481db40311cdd241ae4d33f34f2f75732e44d8e8 diff --git a/src/helpers.rs b/src/helpers.rs index 5b820218a9dd..30fb28436298 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -13,7 +13,7 @@ use rustc_middle::ty::{ layout::{LayoutOf, TyAndLayout}, List, TyCtxt, }; -use rustc_span::{def_id::CrateNum, Symbol}; +use rustc_span::{def_id::CrateNum, sym, Symbol}; use rustc_target::abi::{Align, FieldsShape, Size, Variants}; use rustc_target::spec::abi::Abi; @@ -775,6 +775,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.alloc_mark_immutable(mplace.ptr.into_pointer_or_addr().unwrap().provenance.alloc_id) .unwrap(); } + + fn item_link_name(&self, def_id: DefId) -> Symbol { + let tcx = self.eval_context_ref().tcx; + match tcx.get_attrs(def_id, sym::link_name).filter_map(|a| a.value_str()).next() { + Some(name) => name, + None => tcx.item_name(def_id), + } + } } /// Check that the number of args is what we expect. diff --git a/src/machine.rs b/src/machine.rs index 2ecb583abb2c..5facc5327d3f 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -24,7 +24,7 @@ use rustc_middle::{ }, }; use rustc_span::def_id::{CrateNum, DefId}; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::Symbol; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; @@ -548,11 +548,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx: &MiriEvalContext<'mir, 'tcx>, def_id: DefId, ) -> InterpResult<'tcx, Pointer> { - let attrs = ecx.tcx.get_attrs(def_id); - let link_name = match ecx.tcx.sess.first_attr_value_str_by_name(attrs, sym::link_name) { - Some(name) => name, - None => ecx.tcx.item_name(def_id), - }; + let link_name = ecx.item_link_name(def_id); if let Some(&ptr) = ecx.machine.extern_statics.get(&link_name) { Ok(ptr) } else { diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index e9845c537663..bebe77a02194 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -15,7 +15,7 @@ use rustc_middle::middle::{ use rustc_middle::mir; use rustc_middle::ty; use rustc_session::config::CrateType; -use rustc_span::{symbol::sym, Symbol}; +use rustc_span::Symbol; use rustc_target::{ abi::{Align, Size}, spec::abi::Abi, @@ -235,12 +235,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx unwind: StackPopUnwind, ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { let this = self.eval_context_mut(); - let attrs = this.tcx.get_attrs(def_id); - let link_name = this - .tcx - .sess - .first_attr_value_str_by_name(attrs, sym::link_name) - .unwrap_or_else(|| this.tcx.item_name(def_id)); + let link_name = this.item_link_name(def_id); let tcx = this.tcx.tcx; // First: functions that diverge. From a5db2c32e5f0b29c730451a80efc0b4751ca208e Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Thu, 12 May 2022 20:31:40 +0100 Subject: [PATCH 3059/5092] Refactor to hide *_next_id functions --- src/shims/posix/sync.rs | 107 +++++++++++++++++++++----------------- src/shims/windows/sync.rs | 35 +++++++------ src/sync.rs | 72 +++++++++++++++++-------- 3 files changed, 129 insertions(+), 85 deletions(-) diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index f8c680c0e828..2e5da5b53798 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -113,23 +113,27 @@ fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( mutex_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, MutexId> { let value_place = ecx.offset_and_layout_to_place(mutex_op, 4, ecx.machine.layouts.u32)?; - let (old, success) = ecx - .atomic_compare_exchange_scalar( - &value_place, - &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), - ecx.mutex_next_id().to_u32_scalar().into(), - AtomicRwOp::Relaxed, - AtomicReadOp::Relaxed, - false, - )? - .to_scalar_pair()?; - if success.to_bool().expect("compare_exchange's second return value is a bool") { - let id = ecx.mutex_create(); - Ok(id) - } else { - Ok(MutexId::from_u32(old.to_u32().expect("layout is u32"))) - } + ecx.mutex_get_or_create(|ecx, next_id| { + let (old, success) = ecx + .atomic_compare_exchange_scalar( + &value_place, + &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), + next_id.to_u32_scalar().into(), + AtomicRwOp::Relaxed, + AtomicReadOp::Relaxed, + false, + )? + .to_scalar_pair() + .expect("compare_exchange returns a scalar pair"); + + Ok(if success.to_bool().expect("compare_exchange's second return value is a bool") { + // Caller of the closure needs to allocate next_id + None + } else { + Some(MutexId::from_u32(old.to_u32().expect("layout is u32"))) + }) + }) } // pthread_rwlock_t is between 32 and 56 bytes, depending on the platform. @@ -165,23 +169,27 @@ fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( rwlock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, RwLockId> { let value_place = ecx.offset_and_layout_to_place(rwlock_op, 4, ecx.machine.layouts.u32)?; - let (old, success) = ecx - .atomic_compare_exchange_scalar( - &value_place, - &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), - ecx.rwlock_next_id().to_u32_scalar().into(), - AtomicRwOp::Relaxed, - AtomicReadOp::Relaxed, - false, - )? - .to_scalar_pair()?; - if success.to_bool().expect("compare_exchange's second return value is a bool") { - let id = ecx.rwlock_create(); - Ok(id) - } else { - Ok(RwLockId::from_u32(old.to_u32().expect("layout is u32"))) - } + ecx.rwlock_get_or_create(|ecx, next_id| { + let (old, success) = ecx + .atomic_compare_exchange_scalar( + &value_place, + &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), + next_id.to_u32_scalar().into(), + AtomicRwOp::Relaxed, + AtomicReadOp::Relaxed, + false, + )? + .to_scalar_pair() + .expect("compare_exchange returns a scalar pair"); + + Ok(if success.to_bool().expect("compare_exchange's second return value is a bool") { + // Caller of the closure needs to allocate next_id + None + } else { + Some(RwLockId::from_u32(old.to_u32().expect("layout is u32"))) + }) + }) } // pthread_condattr_t @@ -246,23 +254,26 @@ fn cond_get_or_create_id<'mir, 'tcx: 'mir>( ) -> InterpResult<'tcx, CondvarId> { let value_place = ecx.offset_and_layout_to_place(cond_op, 4, ecx.machine.layouts.u32)?; - let (old, success) = ecx - .atomic_compare_exchange_scalar( - &value_place, - &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), - ecx.condvar_next_id().to_u32_scalar().into(), - AtomicRwOp::Relaxed, - AtomicReadOp::Relaxed, - false, - )? - .to_scalar_pair()?; + ecx.condvar_get_or_create(|ecx, next_id| { + let (old, success) = ecx + .atomic_compare_exchange_scalar( + &value_place, + &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), + next_id.to_u32_scalar().into(), + AtomicRwOp::Relaxed, + AtomicReadOp::Relaxed, + false, + )? + .to_scalar_pair() + .expect("compare_exchange returns a scalar pair"); - if success.to_bool().expect("compare_exchange's second return value is a bool") { - let id = ecx.condvar_create(); - Ok(id) - } else { - Ok(CondvarId::from_u32(old.to_u32().expect("layout is u32"))) - } + Ok(if success.to_bool().expect("compare_exchange's second return value is a bool") { + // Caller of the closure needs to allocate next_id + None + } else { + Some(CondvarId::from_u32(old.to_u32().expect("layout is u32"))) + }) + }) } fn cond_get_clock_id<'mir, 'tcx: 'mir>( diff --git a/src/shims/windows/sync.rs b/src/shims/windows/sync.rs index ccd65aac900f..ff10b3b6aafe 100644 --- a/src/shims/windows/sync.rs +++ b/src/shims/windows/sync.rs @@ -9,23 +9,26 @@ fn srwlock_get_or_create_id<'mir, 'tcx: 'mir>( ) -> InterpResult<'tcx, RwLockId> { let value_place = ecx.offset_and_layout_to_place(lock_op, 0, ecx.machine.layouts.u32)?; - let (old, success) = ecx - .atomic_compare_exchange_scalar( - &value_place, - &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), - ecx.rwlock_next_id().to_u32_scalar().into(), - AtomicRwOp::AcqRel, - AtomicReadOp::Acquire, - false, - )? - .to_scalar_pair()?; + ecx.rwlock_get_or_create(|ecx, next_id| { + let (old, success) = ecx + .atomic_compare_exchange_scalar( + &value_place, + &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), + next_id.to_u32_scalar().into(), + AtomicRwOp::Relaxed, + AtomicReadOp::Relaxed, + false, + )? + .to_scalar_pair() + .expect("compare_exchange returns a scalar pair"); - if success.to_bool().expect("compare_exchange's second return value is a bool") { - let id = ecx.rwlock_create(); - Ok(id) - } else { - Ok(RwLockId::from_u32(old.to_u32().expect("layout is u32"))) - } + Ok(if success.to_bool().expect("compare_exchange's second return value is a bool") { + // Caller of the closure needs to allocate next_id + None + } else { + Some(RwLockId::from_u32(old.to_u32().expect("layout is u32"))) + }) + }) } impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} diff --git a/src/sync.rs b/src/sync.rs index 8c5b8ebfec75..fb69c67eccd9 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -208,13 +208,6 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // situations. impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - #[inline] - /// Peek the id of the next mutex - fn mutex_next_id(&self) -> MutexId { - let this = self.eval_context_ref(); - this.machine.threads.sync.mutexes.next_index() - } - #[inline] /// Create state for a new mutex. fn mutex_create(&mut self) -> MutexId { @@ -222,6 +215,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.threads.sync.mutexes.push(Default::default()) } + #[inline] + /// Provides the closure with the next MutexId. Creates that mutex if the closure returns None, + /// otherwise returns the value from the closure + fn mutex_get_or_create(&mut self, existing: F) -> InterpResult<'tcx, MutexId> + where + F: FnOnce(&mut MiriEvalContext<'mir, 'tcx>, MutexId) -> InterpResult<'tcx, Option>, + { + let this = self.eval_context_mut(); + if let Some(old) = existing(this, this.machine.threads.sync.mutexes.next_index())? { + Ok(old) + } else { + Ok(self.mutex_create()) + } + } + #[inline] /// Get the id of the thread that currently owns this lock. fn mutex_get_owner(&mut self, id: MutexId) -> ThreadId { @@ -297,13 +305,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.block_thread(thread); } - #[inline] - /// Peek the id of the next read write lock - fn rwlock_next_id(&self) -> RwLockId { - let this = self.eval_context_ref(); - this.machine.threads.sync.rwlocks.next_index() - } - #[inline] /// Create state for a new read write lock. fn rwlock_create(&mut self) -> RwLockId { @@ -311,6 +312,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.threads.sync.rwlocks.push(Default::default()) } + #[inline] + /// Provides the closure with the next RwLockId. Creates that RwLock if the closure returns None, + /// otherwise returns the value from the closure + fn rwlock_get_or_create(&mut self, existing: F) -> InterpResult<'tcx, RwLockId> + where + F: FnOnce( + &mut MiriEvalContext<'mir, 'tcx>, + RwLockId, + ) -> InterpResult<'tcx, Option>, + { + let this = self.eval_context_mut(); + if let Some(old) = existing(this, this.machine.threads.sync.rwlocks.next_index())? { + Ok(old) + } else { + Ok(self.rwlock_create()) + } + } + #[inline] /// Check if locked. fn rwlock_is_locked(&self, id: RwLockId) -> bool { @@ -452,13 +471,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.block_thread(writer); } - #[inline] - /// Peek the id of the next Condvar - fn condvar_next_id(&self) -> CondvarId { - let this = self.eval_context_ref(); - this.machine.threads.sync.condvars.next_index() - } - #[inline] /// Create state for a new conditional variable. fn condvar_create(&mut self) -> CondvarId { @@ -466,6 +478,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.threads.sync.condvars.push(Default::default()) } + #[inline] + /// Provides the closure with the next CondvarId. Creates that Condvar if the closure returns None, + /// otherwise returns the value from the closure + fn condvar_get_or_create(&mut self, existing: F) -> InterpResult<'tcx, CondvarId> + where + F: FnOnce( + &mut MiriEvalContext<'mir, 'tcx>, + CondvarId, + ) -> InterpResult<'tcx, Option>, + { + let this = self.eval_context_mut(); + if let Some(old) = existing(this, this.machine.threads.sync.condvars.next_index())? { + Ok(old) + } else { + Ok(self.condvar_create()) + } + } + #[inline] /// Is the conditional variable awaited? fn condvar_is_awaited(&mut self, id: CondvarId) -> bool { From 10d978c180217f09c576822a312bc7353adfc17c Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Thu, 12 May 2022 21:06:17 +0100 Subject: [PATCH 3060/5092] Inline _create() calls and add assertions --- src/sync.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/sync.rs b/src/sync.rs index fb69c67eccd9..0eebe4f654e4 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -223,10 +223,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx F: FnOnce(&mut MiriEvalContext<'mir, 'tcx>, MutexId) -> InterpResult<'tcx, Option>, { let this = self.eval_context_mut(); - if let Some(old) = existing(this, this.machine.threads.sync.mutexes.next_index())? { + let next_index = this.machine.threads.sync.mutexes.next_index(); + if let Some(old) = existing(this, next_index)? { Ok(old) } else { - Ok(self.mutex_create()) + let new_index = this.machine.threads.sync.mutexes.push(Default::default()); + assert_eq!(next_index, new_index); + Ok(new_index) } } @@ -323,10 +326,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, Option>, { let this = self.eval_context_mut(); - if let Some(old) = existing(this, this.machine.threads.sync.rwlocks.next_index())? { + let next_index = this.machine.threads.sync.rwlocks.next_index(); + if let Some(old) = existing(this, next_index)? { Ok(old) } else { - Ok(self.rwlock_create()) + let new_index = this.machine.threads.sync.rwlocks.push(Default::default()); + assert_eq!(next_index, new_index); + Ok(new_index) } } @@ -489,10 +495,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, Option>, { let this = self.eval_context_mut(); - if let Some(old) = existing(this, this.machine.threads.sync.condvars.next_index())? { + let next_index = this.machine.threads.sync.condvars.next_index(); + if let Some(old) = existing(this, next_index)? { Ok(old) } else { - Ok(self.condvar_create()) + let new_index = this.machine.threads.sync.condvars.push(Default::default()); + assert_eq!(next_index, new_index); + Ok(new_index) } } From 9e38dc4d499a6c405e0685d71235495699a34209 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Fri, 13 May 2022 18:42:53 +0100 Subject: [PATCH 3061/5092] Move and rename offset_and_layout_to_place to deref_operand_and_offset --- src/data_race.rs | 27 +++++---------------------- src/helpers.rs | 29 +++++++++++++++++++---------- src/shims/posix/sync.rs | 6 +++--- src/shims/windows/sync.rs | 2 +- 4 files changed, 28 insertions(+), 36 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index b7ccaa35305e..b8656627e6f9 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -73,9 +73,9 @@ use rustc_middle::{mir, ty::layout::TyAndLayout}; use rustc_target::abi::Size; use crate::{ - AllocId, AllocRange, ImmTy, Immediate, InterpResult, MPlaceTy, MemPlaceMeta, MemoryKind, - MiriEvalContext, MiriEvalContextExt, MiriMemoryKind, OpTy, Pointer, RangeMap, Scalar, - ScalarMaybeUninit, Tag, ThreadId, VClock, VTimestamp, VectorIdx, + AllocId, AllocRange, HelpersEvalContextExt, ImmTy, Immediate, InterpResult, MPlaceTy, + MemoryKind, MiriEvalContext, MiriEvalContextExt, MiriMemoryKind, OpTy, Pointer, RangeMap, + Scalar, ScalarMaybeUninit, Tag, ThreadId, VClock, VTimestamp, VectorIdx, }; pub type AllocExtra = VClockAlloc; @@ -441,23 +441,6 @@ impl MemoryCellClocks { /// Evaluation context extensions. impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { - /// Calculates the MPlaceTy given the offset and layout of an access on an operand - fn offset_and_layout_to_place( - &self, - op: &OpTy<'tcx, Tag>, - offset: u64, - layout: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, Tag>> { - let this = self.eval_context_ref(); - let op_place = this.deref_operand(op)?; - let offset = Size::from_bytes(offset); - - // Ensure that the access is within bounds. - assert!(op_place.layout.size >= offset + layout.size); - let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; - Ok(value_place) - } - /// Atomic variant of read_scalar_at_offset. fn read_scalar_at_offset_atomic( &self, @@ -467,7 +450,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicReadOp, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_ref(); - let value_place = this.offset_and_layout_to_place(op, offset, layout)?; + let value_place = this.deref_operand_and_offset(op, offset, layout)?; this.read_scalar_atomic(&value_place, atomic) } @@ -481,7 +464,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicWriteOp, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let value_place = this.offset_and_layout_to_place(op, offset, layout)?; + let value_place = this.deref_operand_and_offset(op, offset, layout)?; this.write_scalar_atomic(value.into(), &value_place, atomic) } diff --git a/src/helpers.rs b/src/helpers.rs index 5b820218a9dd..ba5ebd3026c4 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -597,6 +597,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + /// Calculates the MPlaceTy given the offset and layout of an access on an operand + fn deref_operand_and_offset( + &self, + op: &OpTy<'tcx, Tag>, + offset: u64, + layout: TyAndLayout<'tcx>, + ) -> InterpResult<'tcx, MPlaceTy<'tcx, Tag>> { + let this = self.eval_context_ref(); + let op_place = this.deref_operand(op)?; + let offset = Size::from_bytes(offset); + + // Ensure that the access is within bounds. + assert!(op_place.layout.size >= offset + layout.size); + let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; + Ok(value_place) + } + fn read_scalar_at_offset( &self, op: &OpTy<'tcx, Tag>, @@ -604,11 +621,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx layout: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_ref(); - let op_place = this.deref_operand(op)?; - let offset = Size::from_bytes(offset); - // Ensure that the following read at an offset is within bounds - assert!(op_place.layout.size >= offset + layout.size); - let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; + let value_place = this.deref_operand_and_offset(op, offset, layout)?; this.read_scalar(&value_place.into()) } @@ -620,11 +633,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx layout: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, ()> { let this = self.eval_context_mut(); - let op_place = this.deref_operand(op)?; - let offset = Size::from_bytes(offset); - // Ensure that the following read at an offset is within bounds - assert!(op_place.layout.size >= offset + layout.size); - let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; + let value_place = this.deref_operand_and_offset(op, offset, layout)?; this.write_scalar(value, &value_place.into()) } diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 2e5da5b53798..56d496984757 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -112,7 +112,7 @@ fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, MutexId> { - let value_place = ecx.offset_and_layout_to_place(mutex_op, 4, ecx.machine.layouts.u32)?; + let value_place = ecx.deref_operand_and_offset(mutex_op, 4, ecx.machine.layouts.u32)?; ecx.mutex_get_or_create(|ecx, next_id| { let (old, success) = ecx @@ -168,7 +168,7 @@ fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, rwlock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, RwLockId> { - let value_place = ecx.offset_and_layout_to_place(rwlock_op, 4, ecx.machine.layouts.u32)?; + let value_place = ecx.deref_operand_and_offset(rwlock_op, 4, ecx.machine.layouts.u32)?; ecx.rwlock_get_or_create(|ecx, next_id| { let (old, success) = ecx @@ -252,7 +252,7 @@ fn cond_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, cond_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, CondvarId> { - let value_place = ecx.offset_and_layout_to_place(cond_op, 4, ecx.machine.layouts.u32)?; + let value_place = ecx.deref_operand_and_offset(cond_op, 4, ecx.machine.layouts.u32)?; ecx.condvar_get_or_create(|ecx, next_id| { let (old, success) = ecx diff --git a/src/shims/windows/sync.rs b/src/shims/windows/sync.rs index ff10b3b6aafe..6a6b2269e62a 100644 --- a/src/shims/windows/sync.rs +++ b/src/shims/windows/sync.rs @@ -7,7 +7,7 @@ fn srwlock_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, lock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, RwLockId> { - let value_place = ecx.offset_and_layout_to_place(lock_op, 0, ecx.machine.layouts.u32)?; + let value_place = ecx.deref_operand_and_offset(lock_op, 0, ecx.machine.layouts.u32)?; ecx.rwlock_get_or_create(|ecx, next_id| { let (old, success) = ecx From fde022007b82d67c0fe655fe32c80a93b6715bb2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 13 May 2022 23:19:17 +0200 Subject: [PATCH 3062/5092] data_race: use glob import like most files --- src/data_race.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index b8656627e6f9..ba7300374562 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -72,11 +72,7 @@ use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::{mir, ty::layout::TyAndLayout}; use rustc_target::abi::Size; -use crate::{ - AllocId, AllocRange, HelpersEvalContextExt, ImmTy, Immediate, InterpResult, MPlaceTy, - MemoryKind, MiriEvalContext, MiriEvalContextExt, MiriMemoryKind, OpTy, Pointer, RangeMap, - Scalar, ScalarMaybeUninit, Tag, ThreadId, VClock, VTimestamp, VectorIdx, -}; +use crate::*; pub type AllocExtra = VClockAlloc; From 8ff0aac06c73d75d5eebea173889fb2ca94c0c75 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Fri, 13 May 2022 19:04:51 -0400 Subject: [PATCH 3063/5092] More review feedback * Store the local crates in an Rc<[CrateNum]> * Move all the allocation history into Stacks * Clean up the implementation of get_logs_relevant_to a bit --- src/helpers.rs | 5 +- src/machine.rs | 5 +- src/stacked_borrows.rs | 151 ++++++++++++++-------- src/stacked_borrows/diagnostics.rs | 194 ++++++++++------------------- 4 files changed, 168 insertions(+), 187 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 8d7147fff7a4..2198bba4fe23 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,5 +1,6 @@ use std::mem; use std::num::NonZeroUsize; +use std::rc::Rc; use std::time::Duration; use log::trace; @@ -797,7 +798,7 @@ pub fn isolation_abort_error(name: &str) -> InterpResult<'static> { /// Retrieve the list of local crates that should have been passed by cargo-miri in /// MIRI_LOCAL_CRATES and turn them into `CrateNum`s. -pub fn get_local_crates(tcx: &TyCtxt<'_>) -> Vec { +pub fn get_local_crates(tcx: &TyCtxt<'_>) -> Rc<[CrateNum]> { // Convert the local crate names from the passed-in config into CrateNums so that they can // be looked up quickly during execution let local_crate_names = std::env::var("MIRI_LOCAL_CRATES") @@ -811,7 +812,7 @@ pub fn get_local_crates(tcx: &TyCtxt<'_>) -> Vec { local_crates.push(crate_num); } } - local_crates + Rc::from(local_crates.as_slice()) } /// Formats an AllocRange like [0x1..0x3], for use in diagnostics. diff --git a/src/machine.rs b/src/machine.rs index 7cb08066a6c3..f215f465c00d 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -6,6 +6,7 @@ use std::cell::RefCell; use std::collections::HashSet; use std::fmt; use std::num::NonZeroU64; +use std::rc::Rc; use std::time::Instant; use rand::rngs::StdRng; @@ -273,7 +274,7 @@ pub struct Evaluator<'mir, 'tcx> { pub(crate) backtrace_style: BacktraceStyle, /// Crates which are considered local for the purposes of error reporting. - pub(crate) local_crates: Vec, + pub(crate) local_crates: Rc<[CrateNum]>, /// Mapping extern static names to their base pointer. extern_statics: FxHashMap>, @@ -307,7 +308,6 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { config.tracked_pointer_tags.clone(), config.tracked_call_ids.clone(), config.tag_raw, - local_crates.clone(), ))) } else { None @@ -575,6 +575,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { stacked_borrows, kind, &ecx.machine.threads, + ecx.machine.local_crates.clone(), )) } else { None diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 1aec3c0e5eab..8dda4a9e22a0 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -3,9 +3,9 @@ use log::trace; use std::cell::RefCell; -use std::collections::HashMap; use std::fmt; use std::num::NonZeroU64; +use std::rc::Rc; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::Mutability; @@ -22,7 +22,7 @@ use std::collections::HashSet; use crate::*; pub mod diagnostics; -use diagnostics::{AllocHistory, GlobalStateExt, StackExt}; +use diagnostics::AllocHistory; use diagnostics::TagHistory; @@ -97,6 +97,8 @@ pub struct Stack { pub struct Stacks { // Even reading memory can have effects on the stack, so we need a `RefCell` here. stacks: RefCell>, + /// Stores past operations on this allocation + history: RefCell, } /// Extra global state, available to the memory access hooks. @@ -118,10 +120,6 @@ pub struct GlobalStateInner { tracked_call_ids: HashSet, /// Whether to track raw pointers. tag_raw: bool, - /// Crates which are considered local for the purposes of error reporting. - local_crates: Vec, - /// Extra per-allocation information - extras: HashMap, } /// We need interior mutable access to the global state. @@ -174,7 +172,6 @@ impl GlobalStateInner { tracked_pointer_tags: HashSet, tracked_call_ids: HashSet, tag_raw: bool, - local_crates: Vec, ) -> Self { GlobalStateInner { next_ptr_id: NonZeroU64::new(1).unwrap(), @@ -184,8 +181,6 @@ impl GlobalStateInner { tracked_pointer_tags, tracked_call_ids, tag_raw, - local_crates, - extras: HashMap::new(), } } @@ -331,30 +326,29 @@ impl<'tcx> Stack { /// currently checking. fn check_protector( item: &Item, - provoking_access: Option<(SbTag, AllocId, AllocRange, Size, AccessKind)>, // just for debug printing and error messages + provoking_access: Option<(SbTag, AllocRange, Size, AccessKind)>, // just for debug printing and error messages global: &GlobalStateInner, + alloc_history: &mut AllocHistory, ) -> InterpResult<'tcx> { if let SbTag::Tagged(id) = item.tag { if global.tracked_pointer_tags.contains(&id) { register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag( *item, - provoking_access - .map(|(tag, _alloc_id, _alloc_range, _size, access)| (tag, access)), + provoking_access.map(|(tag, _alloc_range, _size, access)| (tag, access)), )); } } if let Some(call) = item.protector { if global.is_active(call) { - if let Some((tag, alloc_id, alloc_range, offset, _access)) = provoking_access { + if let Some((tag, alloc_range, offset, _access)) = provoking_access { Err(err_sb_ub( format!( "not granting access to tag {:?} because incompatible item is protected: {:?}", tag, item ), None, - global.get_stack_history( + alloc_history.get_logs_relevant_to( tag, - alloc_id, alloc_range, offset, Some(item.tag), @@ -383,13 +377,14 @@ impl<'tcx> Stack { (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &mut GlobalStateInner, threads: &ThreadManager<'_, 'tcx>, + alloc_history: &mut AllocHistory, ) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. - let granting_idx = self - .find_granting(access, tag) - .ok_or_else(|| self.access_error(access, tag, alloc_id, alloc_range, offset, global))?; + let granting_idx = self.find_granting(access, tag).ok_or_else(|| { + alloc_history.access_error(access, tag, alloc_id, alloc_range, offset, self) + })?; // Step 2: Remove incompatible items above them. Make sure we do not remove protected // items. Behavior differs for reads and writes. @@ -401,10 +396,11 @@ impl<'tcx> Stack { trace!("access: popping item {:?}", item); Stack::check_protector( &item, - Some((tag, alloc_id, alloc_range, offset, access)), + Some((tag, alloc_range, offset, access)), global, + alloc_history, )?; - global.log_invalidation(item.tag, alloc_id, alloc_range, threads); + alloc_history.log_invalidation(item.tag, alloc_range, threads); } } else { // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses. @@ -421,11 +417,12 @@ impl<'tcx> Stack { trace!("access: disabling item {:?}", item); Stack::check_protector( item, - Some((tag, alloc_id, alloc_range, offset, access)), + Some((tag, alloc_range, offset, access)), global, + alloc_history, )?; item.perm = Permission::Disabled; - global.log_invalidation(item.tag, alloc_id, alloc_range, threads); + alloc_history.log_invalidation(item.tag, alloc_range, threads); } } } @@ -441,6 +438,7 @@ impl<'tcx> Stack { tag: SbTag, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &GlobalStateInner, + alloc_history: &mut AllocHistory, ) -> InterpResult<'tcx> { // Step 1: Find granting item. self.find_granting(AccessKind::Write, tag).ok_or_else(|| { @@ -449,13 +447,13 @@ impl<'tcx> Stack { tag, alloc_id, ), None, - global.get_stack_history(tag, alloc_id, alloc_range, offset, None), + alloc_history.get_logs_relevant_to(tag, alloc_range, offset, None), ) })?; // Step 2: Remove all items. Also checks for protectors. for item in self.borrows.drain(..).rev() { - Stack::check_protector(&item, None, global)?; + Stack::check_protector(&item, None, global, alloc_history)?; } Ok(()) @@ -474,6 +472,7 @@ impl<'tcx> Stack { (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &mut GlobalStateInner, threads: &ThreadManager<'_, 'tcx>, + alloc_history: &mut AllocHistory, ) -> InterpResult<'tcx> { // Figure out which access `perm` corresponds to. let access = @@ -481,7 +480,7 @@ impl<'tcx> Stack { // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. let granting_idx = self.find_granting(access, derived_from).ok_or_else(|| { - self.grant_error(derived_from, new, alloc_id, alloc_range, offset, global) + alloc_history.grant_error(derived_from, new, alloc_id, alloc_range, offset, self) })?; // Compute where to put the new item. @@ -501,7 +500,14 @@ impl<'tcx> Stack { // A "safe" reborrow for a pointer that actually expects some aliasing guarantees. // Here, creating a reference actually counts as an access. // This ensures F2b for `Unique`, by removing offending `SharedReadOnly`. - self.access(access, derived_from, (alloc_id, alloc_range, offset), global, threads)?; + self.access( + access, + derived_from, + (alloc_id, alloc_range, offset), + global, + threads, + alloc_history, + )?; // We insert "as far up as possible": We know only compatible items are remaining // on top of `derived_from`, and we want the new item at the top so that we @@ -527,22 +533,26 @@ impl<'tcx> Stack { /// Map per-stack operations to higher-level per-location-range operations. impl<'tcx> Stacks { /// Creates new stack with initial tag. - fn new(size: Size, perm: Permission, tag: SbTag) -> Self { + fn new(size: Size, perm: Permission, tag: SbTag, local_crates: Rc<[CrateNum]>) -> Self { let item = Item { perm, tag, protector: None }; let stack = Stack { borrows: vec![item] }; - Stacks { stacks: RefCell::new(RangeMap::new(size, stack)) } + Stacks { + stacks: RefCell::new(RangeMap::new(size, stack)), + history: RefCell::new(AllocHistory::new(local_crates)), + } } /// Call `f` on every stack in the range. fn for_each( &self, range: AllocRange, - mut f: impl FnMut(Size, &mut Stack) -> InterpResult<'tcx>, + mut f: impl FnMut(Size, &mut Stack, &mut AllocHistory) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { let mut stacks = self.stacks.borrow_mut(); + let history = &mut *self.history.borrow_mut(); for (offset, stack) in stacks.iter_mut(range.start, range.size) { - f(offset, stack)?; + f(offset, stack, history)?; } Ok(()) } @@ -551,11 +561,12 @@ impl<'tcx> Stacks { fn for_each_mut( &mut self, range: AllocRange, - mut f: impl FnMut(Size, &mut Stack) -> InterpResult<'tcx>, + mut f: impl FnMut(Size, &mut Stack, &mut AllocHistory) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { let stacks = self.stacks.get_mut(); + let history = &mut *self.history.borrow_mut(); for (offset, stack) in stacks.iter_mut(range.start, range.size) { - f(offset, stack)?; + f(offset, stack, history)?; } Ok(()) } @@ -569,6 +580,7 @@ impl Stacks { state: &GlobalState, kind: MemoryKind, threads: &ThreadManager<'_, '_>, + local_crates: Rc<[CrateNum]>, ) -> Self { let mut extra = state.borrow_mut(); let (base_tag, perm) = match kind { @@ -602,8 +614,14 @@ impl Stacks { (tag, Permission::SharedReadWrite) } }; - extra.log_creation(None, base_tag, id, alloc_range(Size::ZERO, size), threads); - Stacks::new(size, perm, base_tag) + let stacks = Stacks::new(size, perm, base_tag, local_crates); + stacks.history.borrow_mut().log_creation( + None, + base_tag, + alloc_range(Size::ZERO, size), + threads, + ); + stacks } #[inline(always)] @@ -622,8 +640,15 @@ impl Stacks { range.size.bytes() ); let mut state = state.borrow_mut(); - self.for_each(range, |offset, stack| { - stack.access(AccessKind::Read, tag, (alloc_id, range, offset), &mut state, threads) + self.for_each(range, |offset, stack, history| { + stack.access( + AccessKind::Read, + tag, + (alloc_id, range, offset), + &mut state, + threads, + history, + ) }) } @@ -643,8 +668,15 @@ impl Stacks { range.size.bytes() ); let mut state = state.borrow_mut(); - self.for_each_mut(range, |offset, stack| { - stack.access(AccessKind::Write, tag, (alloc_id, range, offset), &mut state, threads) + self.for_each_mut(range, |offset, stack, history| { + stack.access( + AccessKind::Write, + tag, + (alloc_id, range, offset), + &mut state, + threads, + history, + ) }) } @@ -658,10 +690,9 @@ impl Stacks { ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", tag, alloc_id, range.size.bytes()); let mut state = state.borrow_mut(); - self.for_each_mut(range, |offset, stack| { - stack.dealloc(tag, (alloc_id, range, offset), &mut state) + self.for_each_mut(range, |offset, stack, history| { + stack.dealloc(tag, (alloc_id, range, offset), &mut state, history) })?; - state.extras.remove(&alloc_id); Ok(()) } } @@ -692,16 +723,20 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?; - let mem_extra = this.machine.stacked_borrows.as_mut().unwrap().get_mut(); - mem_extra.log_creation( - Some(orig_tag), - new_tag, - alloc_id, - alloc_range(base_offset, base_offset + size), - &this.machine.threads, - ); - if protect { - mem_extra.log_protector(orig_tag, new_tag, alloc_id, &this.machine.threads); + { + let extra = this.get_alloc_extra(alloc_id)?; + let stacked_borrows = + extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); + let mut alloc_history = stacked_borrows.history.borrow_mut(); + alloc_history.log_creation( + Some(orig_tag), + new_tag, + alloc_range(base_offset, base_offset + size), + &this.machine.threads, + ); + if protect { + alloc_history.log_protector(orig_tag, new_tag, &this.machine.threads); + } } // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). @@ -763,13 +798,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; let item = Item { perm, tag: new_tag, protector }; let mut global = this.machine.stacked_borrows.as_ref().unwrap().borrow_mut(); - stacked_borrows.for_each(range, |offset, stack| { + stacked_borrows.for_each(range, |offset, stack, history| { stack.grant( orig_tag, item, (alloc_id, range, offset), &mut *global, &this.machine.threads, + history, ) }) })?; @@ -785,8 +821,15 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let item = Item { perm, tag: new_tag, protector }; let range = alloc_range(base_offset, size); let mut global = machine.stacked_borrows.as_ref().unwrap().borrow_mut(); - stacked_borrows.for_each_mut(range, |offset, stack| { - stack.grant(orig_tag, item, (alloc_id, range, offset), &mut global, &machine.threads) + stacked_borrows.for_each_mut(range, |offset, stack, history| { + stack.grant( + orig_tag, + item, + (alloc_id, range, offset), + &mut global, + &machine.threads, + history, + ) })?; Ok(()) diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index f657a926c0a5..734c3a14e3b3 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -1,9 +1,13 @@ +use smallvec::SmallVec; +use std::rc::Rc; + use rustc_middle::mir::interpret::{AllocId, AllocRange}; +use rustc_span::def_id::CrateNum; use rustc_span::{Span, SpanData}; use rustc_target::abi::Size; use crate::helpers::HexRange; -use crate::stacked_borrows::{err_sb_ub, AccessKind, GlobalStateInner, Permission}; +use crate::stacked_borrows::{err_sb_ub, AccessKind, Permission}; use crate::Item; use crate::SbTag; use crate::Stack; @@ -11,7 +15,7 @@ use crate::ThreadManager; use rustc_middle::mir::interpret::InterpError; -#[derive(Debug, Default)] +#[derive(Clone, Debug)] pub struct AllocHistory { // The time tags can be compressed down to one bit per event, by just storing a Vec // where each bit is set to indicate if the event was a creation or a retag @@ -19,16 +23,18 @@ pub struct AllocHistory { creations: smallvec::SmallVec<[Event; 2]>, invalidations: smallvec::SmallVec<[Event; 1]>, protectors: smallvec::SmallVec<[Protection; 1]>, + /// This field is a clone of the `local_crates` field on `Evaluator`. + local_crates: Rc<[CrateNum]>, } -#[derive(Debug)] +#[derive(Clone, Debug)] struct Protection { orig_tag: SbTag, tag: SbTag, span: Span, } -#[derive(Debug)] +#[derive(Clone, Debug)] struct Event { time: usize, parent: Option, @@ -52,45 +58,17 @@ pub enum TagHistory { }, } -pub trait GlobalStateExt { - fn current_span(&self, threads: &ThreadManager<'_, '_>) -> Span; +impl AllocHistory { + pub fn new(local_crates: Rc<[CrateNum]>) -> Self { + Self { + current_time: 0, + creations: SmallVec::new(), + invalidations: SmallVec::new(), + protectors: SmallVec::new(), + local_crates, + } + } - fn log_creation( - &mut self, - parent: Option, - tag: SbTag, - alloc: AllocId, - range: AllocRange, - threads: &ThreadManager<'_, '_>, - ); - - fn log_invalidation( - &mut self, - tag: SbTag, - alloc: AllocId, - range: AllocRange, - threads: &ThreadManager<'_, '_>, - ); - - fn log_protector( - &mut self, - orig_tag: SbTag, - tag: SbTag, - alloc: AllocId, - threads: &ThreadManager<'_, '_>, - ); - - fn get_stack_history( - &self, - tag: SbTag, - alloc: AllocId, - alloc_range: AllocRange, - offset: Size, - protector_tag: Option, - ) -> Option; -} - -impl GlobalStateExt for GlobalStateInner { fn current_span(&self, threads: &ThreadManager<'_, '_>) -> Span { threads .active_thread_stack() @@ -104,64 +82,45 @@ impl GlobalStateExt for GlobalStateInner { .unwrap_or(rustc_span::DUMMY_SP) } - fn log_creation( + pub fn log_creation( &mut self, parent: Option, tag: SbTag, - alloc: AllocId, range: AllocRange, threads: &ThreadManager<'_, '_>, ) { let span = self.current_span(threads); - let extras = self.extras.entry(alloc).or_default(); - extras.creations.push(Event { parent, tag, range, span, time: extras.current_time }); - extras.current_time += 1; + self.creations.push(Event { parent, tag, range, span, time: self.current_time }); + self.current_time += 1; } - fn log_invalidation( + pub fn log_invalidation( &mut self, tag: SbTag, - alloc: AllocId, range: AllocRange, threads: &ThreadManager<'_, '_>, ) { let span = self.current_span(threads); - let extras = self.extras.entry(alloc).or_default(); - extras.invalidations.push(Event { - parent: None, - tag, - range, - span, - time: extras.current_time, - }); - extras.current_time += 1; + self.invalidations.push(Event { parent: None, tag, range, span, time: self.current_time }); + self.current_time += 1; } - fn log_protector( - &mut self, - orig_tag: SbTag, - tag: SbTag, - alloc: AllocId, - threads: &ThreadManager<'_, '_>, - ) { + pub fn log_protector(&mut self, orig_tag: SbTag, tag: SbTag, threads: &ThreadManager<'_, '_>) { let span = self.current_span(threads); - let extras = self.extras.entry(alloc).or_default(); - extras.protectors.push(Protection { orig_tag, tag, span }); - extras.current_time += 1; + self.protectors.push(Protection { orig_tag, tag, span }); + self.current_time += 1; } - fn get_stack_history( + pub fn get_logs_relevant_to( &self, tag: SbTag, - alloc: AllocId, alloc_range: AllocRange, offset: Size, protector_tag: Option, ) -> Option { - let extras = self.extras.get(&alloc)?; let protected = protector_tag .and_then(|protector| { - extras.protectors.iter().find_map(|protection| { + self.protectors.iter().find_map(|protection| { if protection.tag == protector { Some((protection.orig_tag, protection.span.data())) } else { @@ -170,7 +129,7 @@ impl GlobalStateExt for GlobalStateInner { }) }) .and_then(|(tag, call_span)| { - extras.creations.iter().rev().find_map(|event| { + self.creations.iter().rev().find_map(|event| { if event.tag == tag { Some((event.parent?, event.span.data(), call_span)) } else { @@ -178,6 +137,7 @@ impl GlobalStateExt for GlobalStateInner { } }) }); + if let SbTag::Tagged(_) = tag { let get_matching = |events: &[Event]| { events.iter().rev().find_map(|event| { @@ -186,14 +146,14 @@ impl GlobalStateExt for GlobalStateInner { }; Some(TagHistory::Tagged { tag, - created: get_matching(&extras.creations)?, - invalidated: get_matching(&extras.invalidations), + created: get_matching(&self.creations)?, + invalidated: get_matching(&self.invalidations), protected, }) } else { let mut created_time = 0; // Find the most recently created tag that satsfies this offset - let recently_created = extras.creations.iter().rev().find_map(|event| { + let recently_created = self.creations.iter().rev().find_map(|event| { if event.tag == tag && offset >= event.range.start && offset < event.range.end() { created_time = event.time; Some((event.range, event.span.data())) @@ -206,8 +166,8 @@ impl GlobalStateExt for GlobalStateInner { // the recently created tag, and has a different span. // We're trying to make a guess at which span the user wanted to provide the tag that // they're using. - let matching_created = if let Some((_created_range, created_span)) = recently_created { - extras.creations.iter().rev().find_map(|event| { + let matching_created = recently_created.and_then(|(_created_range, created_span)| { + self.creations.iter().rev().find_map(|event| { if event.tag == tag && alloc_range.start >= event.range.start && alloc_range.end() <= event.range.end() @@ -219,26 +179,26 @@ impl GlobalStateExt for GlobalStateInner { None } }) - } else { - None - }; + }); + + // Find the most recent invalidation of this tag which post-dates the creation + let recently_invalidated = recently_created.and_then(|_| { + self.invalidations + .iter() + .rev() + .take_while(|event| event.time > created_time) + .find_map(|event| { + if event.tag == tag + && offset >= event.range.start + && offset < event.range.end() + { + Some((event.range, event.span.data())) + } else { + None + } + }) + }); - let recently_invalidated = if recently_created.is_some() { - // Find the most recent invalidation of this tag which post-dates the creation - let mut found = None; - for event in extras.invalidations.iter().rev() { - if event.time < created_time { - break; - } - if event.tag == tag && offset >= event.range.start && offset < event.range.end() - { - found = Some((event.range, event.span.data())) - } - } - found - } else { - None - }; Some(TagHistory::Untagged { recently_created, matching_created, @@ -247,40 +207,16 @@ impl GlobalStateExt for GlobalStateInner { }) } } -} -pub trait StackExt { - fn grant_error( - &self, - derived_from: SbTag, - new: Item, - alloc_id: AllocId, - alloc_range: AllocRange, - error_offset: Size, - global: &GlobalStateInner, - ) -> InterpError<'static>; - - fn access_error( - &self, - access: AccessKind, - tag: SbTag, - alloc_id: AllocId, - alloc_range: AllocRange, - error_offset: Size, - global: &GlobalStateInner, - ) -> InterpError<'static>; -} - -impl StackExt for Stack { /// Report a descriptive error when `new` could not be granted from `derived_from`. - fn grant_error( + pub fn grant_error( &self, derived_from: SbTag, new: Item, alloc_id: AllocId, alloc_range: AllocRange, error_offset: Size, - global: &GlobalStateInner, + stack: &Stack, ) -> InterpError<'static> { let action = format!( "trying to reborrow {:?} for {:?} permission at {}[{:#x}]", @@ -290,21 +226,21 @@ impl StackExt for Stack { error_offset.bytes(), ); err_sb_ub( - format!("{}{}", action, error_cause(self, derived_from)), + format!("{}{}", action, error_cause(stack, derived_from)), Some(operation_summary("a reborrow", alloc_id, alloc_range)), - global.get_stack_history(derived_from, alloc_id, alloc_range, error_offset, None), + self.get_logs_relevant_to(derived_from, alloc_range, error_offset, None), ) } /// Report a descriptive error when `access` is not permitted based on `tag`. - fn access_error( + pub fn access_error( &self, access: AccessKind, tag: SbTag, alloc_id: AllocId, alloc_range: AllocRange, error_offset: Size, - global: &GlobalStateInner, + stack: &Stack, ) -> InterpError<'static> { let action = format!( "attempting a {} using {:?} at {}[{:#x}]", @@ -314,9 +250,9 @@ impl StackExt for Stack { error_offset.bytes(), ); err_sb_ub( - format!("{}{}", action, error_cause(self, tag)), + format!("{}{}", action, error_cause(stack, tag)), Some(operation_summary("an access", alloc_id, alloc_range)), - global.get_stack_history(tag, alloc_id, alloc_range, error_offset, None), + self.get_logs_relevant_to(tag, alloc_range, error_offset, None), ) } } From f8478df6dcdf92192f0df550145283673c494a73 Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Sat, 14 May 2022 13:03:47 -0500 Subject: [PATCH 3064/5092] Bump rustc for permissive provenance --- rust-version | 2 +- src/machine.rs | 26 +++++++++++++++++++++----- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index 630aee6793f3..1c54dc72ba4b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -481db40311cdd241ae4d33f34f2f75732e44d8e8 +2d691170885b32502b391b8b1a0d54d2419a5653 diff --git a/src/machine.rs b/src/machine.rs index 5facc5327d3f..035f5df70723 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -158,8 +158,8 @@ impl Provenance for Tag { write!(f, "{:?}", tag.sb) } - fn get_alloc_id(self) -> AllocId { - self.alloc_id + fn get_alloc_id(self) -> Option { + Some(self.alloc_id) } } @@ -600,21 +600,37 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } #[inline(always)] - fn ptr_from_addr( + fn ptr_from_addr_cast( ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, ) -> Pointer> { intptrcast::GlobalStateInner::ptr_from_addr(addr, ecx) } + #[inline(always)] + fn ptr_from_addr_transmute( + ecx: &MiriEvalContext<'mir, 'tcx>, + addr: u64, + ) -> Pointer> { + Self::ptr_from_addr_cast(ecx, addr) + } + + #[inline(always)] + fn expose_ptr( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _ptr: Pointer, + ) -> InterpResult<'tcx> { + Ok(()) + } + /// Convert a pointer with provenance into an allocation-offset pair, /// or a `None` with an absolute address if that conversion is not possible. fn ptr_get_alloc( ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer, - ) -> (AllocId, Size, Self::TagExtra) { + ) -> Option<(AllocId, Size, Self::TagExtra)> { let rel = intptrcast::GlobalStateInner::abs_ptr_to_rel(ecx, ptr); - (ptr.provenance.alloc_id, rel, ptr.provenance.sb) + Some((ptr.provenance.alloc_id, rel, ptr.provenance.sb)) } #[inline(always)] From 90a190e03b56b9efd5f431caee9b9f7ebc17371d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 15 May 2022 10:26:47 +0200 Subject: [PATCH 3065/5092] don't ICE when libcore is missing --- src/eval.rs | 13 ++++++++----- src/helpers.rs | 11 ++++++++--- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 028c9b97abb3..5f6348fe0bde 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -172,15 +172,18 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( Evaluator::late_init(&mut ecx, config)?; // Make sure we have MIR. We check MIR for some stable monomorphic function in libcore. - let sentinel = ecx.resolve_path(&["core", "ascii", "escape_default"]); - if !tcx.is_mir_available(sentinel.def.def_id()) { - tcx.sess.fatal("the current sysroot was built without `-Zalways-encode-mir`. Use `cargo miri setup` to prepare a sysroot that is suitable for Miri."); + let sentinel = ecx.try_resolve_path(&["core", "ascii", "escape_default"]); + 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. \ + Use `cargo miri setup` to prepare a sysroot that is suitable for Miri." + ); } - // Setup first stack-frame + // Setup first stack frame. let entry_instance = ty::Instance::mono(tcx, entry_id); - // First argument is constructed later, because its skipped if the entry function uses #[start] + // First argument is constructed later, because it's skipped if the entry function uses #[start]. // Second argument (argc): length of `config.args`. let argc = Scalar::from_machine_usize(u64::try_from(config.args.len()).unwrap(), &ecx); diff --git a/src/helpers.rs b/src/helpers.rs index 0341c7880235..6beb3f8c3bb0 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -71,11 +71,16 @@ fn try_resolve_did<'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option { } pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + /// Gets an instance for a path; fails gracefully if the path does not exist. + fn try_resolve_path(&self, path: &[&str]) -> Option> { + let did = try_resolve_did(self.eval_context_ref().tcx.tcx, path)?; + Some(ty::Instance::mono(self.eval_context_ref().tcx.tcx, did)) + } + /// Gets an instance for a path. fn resolve_path(&self, path: &[&str]) -> ty::Instance<'tcx> { - let did = try_resolve_did(self.eval_context_ref().tcx.tcx, path) - .unwrap_or_else(|| panic!("failed to find required Rust item: {:?}", path)); - ty::Instance::mono(self.eval_context_ref().tcx.tcx, did) + self.try_resolve_path(path) + .unwrap_or_else(|| panic!("failed to find required Rust item: {:?}", path)) } /// Evaluates the scalar at the specified path. Returns Some(val) From ea63a695c8ba0f4322f21074f7646e0ea9f43001 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 15 May 2022 12:56:39 +0200 Subject: [PATCH 3066/5092] rustup --- rust-version | 2 +- src/shims/posix/sync.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 1c54dc72ba4b..dd746e9e2ae4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -2d691170885b32502b391b8b1a0d54d2419a5653 +e1ec3260d79497080ca86540562d410ba67d2a95 diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 56d496984757..1b6112a3311f 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -876,8 +876,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn layout_of_maybe_uninit<'tcx>(tcx: TyCtxtAt<'tcx>, param: Ty<'tcx>) -> TyAndLayout<'tcx> { let def_id = tcx.require_lang_item(LangItem::MaybeUninit, None); - let def_ty = tcx.type_of(def_id); - let ty = def_ty.subst(*tcx, &[param.into()]); + let ty = tcx.bound_type_of(def_id).subst(*tcx, &[param.into()]); let param_env = tcx.param_env(def_id); tcx.layout_of(param_env.and(ty)).unwrap() From 3406829bb3dec61b913d449d02f22e79614d14d7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 17 May 2022 15:36:59 +0200 Subject: [PATCH 3067/5092] rustup-toolchain: also prepare toolchain for vscode --- rustup-toolchain | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rustup-toolchain b/rustup-toolchain index 421db2b3d79f..7fdcdabcee14 100755 --- a/rustup-toolchain +++ b/rustup-toolchain @@ -44,3 +44,7 @@ rustup override set miri # Cleanup. cargo clean + +# Call 'cargo metadata' on the sources in case that changes the lockfile +# (which fails under soem setups when it is done from inside vscode). +cargo metadata --format-version 1 --manifest-path "$(rustc --print sysroot)/lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml" >/dev/null From 6b6f92d4bc50dfcfa62010122182b91f1ca40530 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 17 May 2022 18:59:27 +0200 Subject: [PATCH 3068/5092] I cannot type --- rustup-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rustup-toolchain b/rustup-toolchain index 7fdcdabcee14..59ce6f85a085 100755 --- a/rustup-toolchain +++ b/rustup-toolchain @@ -46,5 +46,5 @@ rustup override set miri cargo clean # Call 'cargo metadata' on the sources in case that changes the lockfile -# (which fails under soem setups when it is done from inside vscode). +# (which fails under some setups when it is done from inside vscode). cargo metadata --format-version 1 --manifest-path "$(rustc --print sysroot)/lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml" >/dev/null From 30548bb57e3a848568280a72878c3de8b8101d36 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 17 May 2022 17:36:34 +0200 Subject: [PATCH 3069/5092] test for validity of references pointing to uninhabited types --- tests/compile-fail/validity/ref_to_uninhabited1.rs | 6 ++++++ tests/compile-fail/validity/ref_to_uninhabited2.rs | 7 +++++++ 2 files changed, 13 insertions(+) create mode 100644 tests/compile-fail/validity/ref_to_uninhabited1.rs create mode 100644 tests/compile-fail/validity/ref_to_uninhabited2.rs diff --git a/tests/compile-fail/validity/ref_to_uninhabited1.rs b/tests/compile-fail/validity/ref_to_uninhabited1.rs new file mode 100644 index 000000000000..e5522ccaeab5 --- /dev/null +++ b/tests/compile-fail/validity/ref_to_uninhabited1.rs @@ -0,0 +1,6 @@ +#![feature(never_type)] +use std::mem::transmute; + +fn main() { unsafe { + let _x: &! = transmute(&42); //~ERROR encountered a reference pointing to uninhabited type ! +} } diff --git a/tests/compile-fail/validity/ref_to_uninhabited2.rs b/tests/compile-fail/validity/ref_to_uninhabited2.rs new file mode 100644 index 000000000000..3778719dc58c --- /dev/null +++ b/tests/compile-fail/validity/ref_to_uninhabited2.rs @@ -0,0 +1,7 @@ +use std::mem::transmute; + +enum Void {} + +fn main() { unsafe { + let _x: &(i32, Void) = transmute(&42); //~ERROR encountered a reference pointing to uninhabited type (i32, Void) +} } From 092c2b9d9239fce273d1268289da0a1f454a01c2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 18 May 2022 08:32:08 +0200 Subject: [PATCH 3070/5092] change one of the ref-to-uninhbaited tests to Box --- tests/compile-fail/validity/ref_to_uninhabited1.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/compile-fail/validity/ref_to_uninhabited1.rs b/tests/compile-fail/validity/ref_to_uninhabited1.rs index e5522ccaeab5..51a3279ffae9 100644 --- a/tests/compile-fail/validity/ref_to_uninhabited1.rs +++ b/tests/compile-fail/validity/ref_to_uninhabited1.rs @@ -1,6 +1,7 @@ #![feature(never_type)] -use std::mem::transmute; +use std::mem::{transmute, forget}; fn main() { unsafe { - let _x: &! = transmute(&42); //~ERROR encountered a reference pointing to uninhabited type ! + let x: Box = transmute(&mut 42); //~ERROR encountered a box pointing to uninhabited type ! + forget(x); } } From 439f861101f72b6e6298b87151f23fa3cfcda7f7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 18 May 2022 08:33:10 +0200 Subject: [PATCH 3071/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index dd746e9e2ae4..8788a013aca7 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e1ec3260d79497080ca86540562d410ba67d2a95 +77972d2d0134fb597249b3b64dcf9510a790c34e From ada864f387d5425076159a3cdf1c33fcc371838b Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Thu, 19 May 2022 09:29:08 -0400 Subject: [PATCH 3072/5092] Pass the correct size to the AllocRange for log_creation --- src/stacked_borrows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 8dda4a9e22a0..d7c213932324 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -731,7 +731,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx alloc_history.log_creation( Some(orig_tag), new_tag, - alloc_range(base_offset, base_offset + size), + alloc_range(base_offset, size), &this.machine.threads, ); if protect { From a941af81614825db21a4b0b59d9c4ff6c5edd547 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 20 May 2022 08:08:11 +0200 Subject: [PATCH 3073/5092] rustup --- rust-version | 2 +- tests/run-pass/concurrency/tls_lib_drop.rs | 2 +- tests/run-pass/concurrency/tls_lib_drop_single_thread.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 8788a013aca7..e6bd4b95a8bd 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -77972d2d0134fb597249b3b64dcf9510a790c34e +f24ef2e296ec6fc6fd2e24d7e4bfec3f4cb0577a diff --git a/tests/run-pass/concurrency/tls_lib_drop.rs b/tests/run-pass/concurrency/tls_lib_drop.rs index 3220aa43148d..86f03bac34f6 100644 --- a/tests/run-pass/concurrency/tls_lib_drop.rs +++ b/tests/run-pass/concurrency/tls_lib_drop.rs @@ -10,7 +10,7 @@ struct TestCell { impl Drop for TestCell { fn drop(&mut self) { for _ in 0..10 { thread::yield_now(); } - println!("Dropping: {} (should be before 'Continue main 1').", self.value.borrow()) + println!("Dropping: {} (should be before 'Continue main 1').", *self.value.borrow()) } } diff --git a/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs b/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs index ef8b2c02ed92..2766ba36d12b 100644 --- a/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs +++ b/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs @@ -8,7 +8,7 @@ struct TestCell { impl Drop for TestCell { fn drop(&mut self) { - eprintln!("Dropping: {}", self.value.borrow()) + eprintln!("Dropping: {}", *self.value.borrow()) } } From 8b4d613cc81c8cc2b52485149e4aa1c8bae3394d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 20 May 2022 18:11:31 +0200 Subject: [PATCH 3074/5092] rustup --- rust-version | 2 +- src/machine.rs | 7 ++++++- tests/compile-fail/ptr_integer_transmute.rs | 2 +- tests/compile-fail/strict_provenance_transmute.rs | 2 +- tests/compile-fail/uninit_float.rs | 2 +- tests/compile-fail/uninit_integer.rs | 2 +- tests/compile-fail/uninit_integer_signed.rs | 2 +- 7 files changed, 12 insertions(+), 7 deletions(-) diff --git a/rust-version b/rust-version index e6bd4b95a8bd..5526a13d5fc7 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -f24ef2e296ec6fc6fd2e24d7e4bfec3f4cb0577a +22ee39504a702f75485582d02060495a01254de1 diff --git a/src/machine.rs b/src/machine.rs index 3d97bed7ae25..7ab15b9f9ceb 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -470,7 +470,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } #[inline(always)] - fn enforce_number_validity(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { + fn enforce_number_init(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { + ecx.machine.enforce_number_validity + } + + #[inline(always)] + fn enforce_number_no_provenance(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { ecx.machine.enforce_number_validity } diff --git a/tests/compile-fail/ptr_integer_transmute.rs b/tests/compile-fail/ptr_integer_transmute.rs index e15a15763757..bb9e8e1e220f 100644 --- a/tests/compile-fail/ptr_integer_transmute.rs +++ b/tests/compile-fail/ptr_integer_transmute.rs @@ -2,5 +2,5 @@ fn main() { let r = &mut 42; - let _i: usize = unsafe { std::mem::transmute(r) }; //~ ERROR expected initialized plain (non-pointer) bytes + let _i: usize = unsafe { std::mem::transmute(r) }; //~ ERROR expected plain (non-pointer) bytes } diff --git a/tests/compile-fail/strict_provenance_transmute.rs b/tests/compile-fail/strict_provenance_transmute.rs index 0fc64295f94c..a684d65b2ce1 100644 --- a/tests/compile-fail/strict_provenance_transmute.rs +++ b/tests/compile-fail/strict_provenance_transmute.rs @@ -7,7 +7,7 @@ use std::mem; // . unsafe fn deref(left: *const u8, right: *const u8) { - let left_int: usize = mem::transmute(left); //~ERROR expected initialized plain (non-pointer) bytes + let left_int: usize = mem::transmute(left); //~ERROR expected plain (non-pointer) bytes let right_int: usize = mem::transmute(right); if left_int == right_int { // The compiler is allowed to replace `left_int` by `right_int` here... diff --git a/tests/compile-fail/uninit_float.rs b/tests/compile-fail/uninit_float.rs index 06953e1ced96..1cb687f9b008 100644 --- a/tests/compile-fail/uninit_float.rs +++ b/tests/compile-fail/uninit_float.rs @@ -4,5 +4,5 @@ fn main() { let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - //~^ ERROR type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes + //~^ ERROR type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes } diff --git a/tests/compile-fail/uninit_integer.rs b/tests/compile-fail/uninit_integer.rs index 757f69c050fe..c700f1f46d99 100644 --- a/tests/compile-fail/uninit_integer.rs +++ b/tests/compile-fail/uninit_integer.rs @@ -4,5 +4,5 @@ fn main() { let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - //~^ ERROR type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes + //~^ ERROR type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes } diff --git a/tests/compile-fail/uninit_integer_signed.rs b/tests/compile-fail/uninit_integer_signed.rs index bb5d7314a7c1..28bca0b19a78 100644 --- a/tests/compile-fail/uninit_integer_signed.rs +++ b/tests/compile-fail/uninit_integer_signed.rs @@ -4,5 +4,5 @@ fn main() { let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - //~^ ERROR type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes + //~^ ERROR type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes } From 3b73eb4456e97a13f139cd8045f19319503f6a0b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 20 May 2022 23:35:31 +0200 Subject: [PATCH 3075/5092] explain what we mean by 'unsound' --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5b97ca95d93f..1897a4fd4639 100644 --- a/README.md +++ b/README.md @@ -236,7 +236,8 @@ up the sysroot. If you are using `miri` (the Miri driver) directly, see the [miri-flags]: #miri--z-flags-and-environment-variables Miri adds its own set of `-Z` flags, which are usually set via the `MIRIFLAGS` -environment variable: +environment variable. Some of these are **unsound**, which means they can lead +to Miri failing to detect cases of undefined behavior in a program. * `-Zmiri-check-number-validity` enables checking of integer and float validity (e.g., they must be initialized and not carry pointer provenance) as part of From 58fdd55a8026f9526e75c41aca082aba62c50362 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 20 May 2022 23:35:42 +0200 Subject: [PATCH 3076/5092] the Windows CI runner takes a lot longer than the others; let it do less work x86_64-apple-darwin is also used as the host OS for the macOS runner, so no need to test it twice. --- ci.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/ci.sh b/ci.sh index a86c5ca490a4..c19aceb641e3 100755 --- a/ci.sh +++ b/ci.sh @@ -55,7 +55,6 @@ case $HOST_TARGET in ;; i686-pc-windows-msvc) MIRI_TEST_TARGET=x86_64-unknown-linux-gnu run_tests - MIRI_TEST_TARGET=x86_64-apple-darwin run_tests ;; *) echo "FATAL: unknown OS" From aadbe8fd4583a61c83b785571a1c05dd978b0d56 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 20 May 2022 23:36:35 +0200 Subject: [PATCH 3077/5092] explain which targets we support to what extent --- README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/README.md b/README.md index 1897a4fd4639..abcfd3e6d050 100644 --- a/README.md +++ b/README.md @@ -194,6 +194,28 @@ for seed in $({ echo obase=16; seq 255; } | bc); do done ``` +### Supported targets + +Miri does not support all targets supported by Rust. The good news, however, is +that no matter your host OS/platform, it is easy to run code for *any* target +using `--target`! + +The following targets are tested on CI and thus should always work (to the +degree documented below): + +- The best-supported target is `x86_64-unknown-linux-gnu`. Miri releases are + blocked on things working with this target. Most other Linux targets should + also work well; we do run the test suite on `i686-unknown-linux-gnu` as a + 32bit target and `mips64-unknown-linux-gnuabi64` as a big-endian target. +- `x86_64-apple-darwin` should work basically as well as Linux. We also test + `aarch64-apple-darwin`. However, we might ship Miri with a nightly even when + some features on these targets regress. +- `x86_64-pc-windows-msvc` works, but supports fewer features than the Linux and + Apple targets. For example, file system access and concurrency are not + supported on Windows. We also test `i686-pc-windows-msvc`, with the same + reduced feature set. We might ship Miri with a nightly even when some features + on these targets regress. + ### Common Problems When using the above instructions, you may encounter a number of confusing compiler From b4089a77abbfa19b674ebf1343a8ef974c10e67c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 May 2022 09:33:47 +0200 Subject: [PATCH 3078/5092] refresh our GHA caches --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0904afc82020..edf74603b6e1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -56,7 +56,8 @@ jobs: ~/.cargo/git/db # contains package information of crates installed via `cargo install`. ~/.cargo/.crates.toml - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + ~/.cargo/.crates2.json + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-xargo0.3.25 restore-keys: ${{ runner.os }}-cargo - name: Install rustup-toolchain-install-master and xargo From e932ea50ba21b355b08a5572a20cb53d2c74aacb Mon Sep 17 00:00:00 2001 From: Mateusz Gienieczko Date: Sat, 21 May 2022 16:10:08 +0200 Subject: [PATCH 3079/5092] Add failing page_size test. --- test-cargo-miri/Cargo.lock | 33 +++++++++++++++++++ test-cargo-miri/Cargo.toml | 1 + test-cargo-miri/test.cross-target.stdout.ref | 6 ++-- test-cargo-miri/test.default.stdout.ref | 6 ++-- .../test.filter.cross-target.stdout.ref | 2 +- test-cargo-miri/test.filter.stdout.ref | 2 +- test-cargo-miri/test.test-target.stdout.ref | 5 +-- test-cargo-miri/tests/test.rs | 20 ++++++++--- 8 files changed, 61 insertions(+), 14 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 7f06fdf28dec..4bece389dc87 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -22,6 +22,7 @@ dependencies = [ "issue_1705", "issue_1760", "issue_rust_86261", + "page_size", "rand", "serde_derive", ] @@ -123,6 +124,16 @@ dependencies = [ "libc", ] +[[package]] +name = "page_size" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eebde548fbbf1ea81a99b128872779c437752fb99f217c45245e1a61dcd9edcd" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "ppv-lite86" version = "0.2.10" @@ -233,3 +244,25 @@ name = "wasi" version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 39ce1757f0e4..2193d354d5d2 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -22,6 +22,7 @@ rand = { version = "0.8", features = ["small_rng"] } getrandom_1 = { package = "getrandom", version = "0.1" } getrandom_2 = { package = "getrandom", version = "0.2" } serde_derive = "1.0" # not actually used, but exercises some unique code path (`--extern` .so file) +page_size = "0.4.1" [lib] test = false # test that this is respected (will show in the output) diff --git a/test-cargo-miri/test.cross-target.stdout.ref b/test-cargo-miri/test.cross-target.stdout.ref index aa4a5839b145..3673e5549d8c 100644 --- a/test-cargo-miri/test.cross-target.stdout.ref +++ b/test-cargo-miri/test.cross-target.stdout.ref @@ -5,7 +5,7 @@ test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out imported main -running 7 tests -..i.... -test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out +running 8 tests +..i..... +test result: ok. 7 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/test.default.stdout.ref b/test-cargo-miri/test.default.stdout.ref index ee8625357509..a59108efb332 100644 --- a/test-cargo-miri/test.default.stdout.ref +++ b/test-cargo-miri/test.default.stdout.ref @@ -5,9 +5,9 @@ test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out imported main -running 7 tests -..i.... -test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out +running 8 tests +..i..... +test result: ok. 7 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out running 4 tests diff --git a/test-cargo-miri/test.filter.cross-target.stdout.ref b/test-cargo-miri/test.filter.cross-target.stdout.ref index b38aac9aa868..9fb7670d0649 100644 --- a/test-cargo-miri/test.filter.cross-target.stdout.ref +++ b/test-cargo-miri/test.filter.cross-target.stdout.ref @@ -8,5 +8,5 @@ imported main running 1 test test simple1 ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 7 filtered out diff --git a/test-cargo-miri/test.filter.stdout.ref b/test-cargo-miri/test.filter.stdout.ref index d14bb8796e85..4b598960a096 100644 --- a/test-cargo-miri/test.filter.stdout.ref +++ b/test-cargo-miri/test.filter.stdout.ref @@ -8,7 +8,7 @@ imported main running 1 test test simple1 ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 7 filtered out running 0 tests diff --git a/test-cargo-miri/test.test-target.stdout.ref b/test-cargo-miri/test.test-target.stdout.ref index 6655eb840929..ca069b702eba 100644 --- a/test-cargo-miri/test.test-target.stdout.ref +++ b/test-cargo-miri/test.test-target.stdout.ref @@ -1,12 +1,13 @@ -running 7 tests +running 8 tests test cargo_env ... ok test do_panic - should panic ... ok test does_not_work_on_miri ... ignored test entropy_rng ... ok test fail_index_check - should panic ... ok +test page_size ... ok test simple1 ... ok test simple2 ... ok -test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out +test result: ok. 7 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index f0ff10ff6c0d..6758e99703cc 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -1,4 +1,4 @@ -use rand::{SeedableRng, Rng, rngs::SmallRng}; +use rand::{rngs::SmallRng, Rng, SeedableRng}; // Having more than 1 test does seem to make a difference // (i.e., this calls ptr::swap which having just one test does not). @@ -49,14 +49,26 @@ fn cargo_env() { } #[test] -#[should_panic(expected="Explicit panic")] -fn do_panic() { // In large, friendly letters :) +#[should_panic(expected = "Explicit panic")] +fn do_panic() { + // In large, friendly letters :) panic!("Explicit panic from test!"); } #[test] #[allow(unconditional_panic)] -#[should_panic(expected="the len is 0 but the index is 42")] +#[should_panic(expected = "the len is 0 but the index is 42")] fn fail_index_check() { [][42] } + +#[test] +fn page_size() { + let page_size = page_size::get(); + + assert!( + page_size.next_power_of_two() == page_size, + "page size not a power of two: {}", + page_size + ); +} From c4ee368acb065b783f3bc094077b4a5cdd1d7a27 Mon Sep 17 00:00:00 2001 From: Mateusz Gienieczko Date: Sat, 21 May 2022 18:17:25 +0200 Subject: [PATCH 3080/5092] Set page size in GetSystemInfo. --- src/shims/windows/foreign_items.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index c49362d52b31..8fc599dd2d0b 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -119,9 +119,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx system_info.ptr, iter::repeat(0u8).take(system_info.layout.size.bytes() as usize), )?; - // Set number of processors. let dword_size = Size::from_bytes(4); - let num_cpus = this.mplace_field(&system_info, 6)?; + + // In WinApi SYSTEM_INFO's first field is a 4-byte union, but num_cpus + // inlines it as two 2-byte fields. In num_cpus case all fields are offset by 1 + // compared to WinApi. See https://github.com/rust-lang/miri/issues/2136#issuecomment-1133661262. + let first_field = this.mplace_field(&system_info, 0)?; + let offset = if first_field.layout.size.bytes() == 2 { 1 } else { 0 }; + + let page_size = this.mplace_field(&system_info, 1 + offset)?; + let num_cpus = this.mplace_field(&system_info, 5 + offset)?; + + // Set page size. + this.write_scalar(Scalar::from_int(PAGE_SIZE, dword_size), &page_size.into())?; + // Set number of processors. this.write_scalar(Scalar::from_int(NUM_CPUS, dword_size), &num_cpus.into())?; } From 63e98aee0cc005c27431a0eca317fecf6706b072 Mon Sep 17 00:00:00 2001 From: Mateusz Gienieczko Date: Sat, 21 May 2022 19:44:12 +0200 Subject: [PATCH 3081/5092] Change GetSystemInfo to explicit offset. --- src/shims/windows/foreign_items.rs | 35 +++++++++++++++++++----------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 8fc599dd2d0b..f9cf755c5b4f 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -111,6 +111,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "GetSystemInfo" => { + use crate::rustc_middle::ty::{layout::LayoutOf, TyKind, UintTy}; + let [system_info] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let system_info = this.deref_operand(system_info)?; @@ -119,21 +121,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx system_info.ptr, iter::repeat(0u8).take(system_info.layout.size.bytes() as usize), )?; - let dword_size = Size::from_bytes(4); - - // In WinApi SYSTEM_INFO's first field is a 4-byte union, but num_cpus - // inlines it as two 2-byte fields. In num_cpus case all fields are offset by 1 - // compared to WinApi. See https://github.com/rust-lang/miri/issues/2136#issuecomment-1133661262. - let first_field = this.mplace_field(&system_info, 0)?; - let offset = if first_field.layout.size.bytes() == 2 { 1 } else { 0 }; - - let page_size = this.mplace_field(&system_info, 1 + offset)?; - let num_cpus = this.mplace_field(&system_info, 5 + offset)?; - + // Set selected fields. + let dword_ty = this.tcx.mk_ty(TyKind::Uint(UintTy::U32)); + let dword_layout = this.layout_of(dword_ty)?; // Set page size. - this.write_scalar(Scalar::from_int(PAGE_SIZE, dword_size), &page_size.into())?; + let page_size = system_info.offset( + Size::from_bytes(4), + MemPlaceMeta::None, + dword_layout, + &this.tcx, + )?; + this.write_scalar( + Scalar::from_int(PAGE_SIZE, dword_layout.size), + &page_size.into(), + )?; // Set number of processors. - this.write_scalar(Scalar::from_int(NUM_CPUS, dword_size), &num_cpus.into())?; + let num_cpus = system_info.offset( + Size::from_bytes(32), + MemPlaceMeta::None, + dword_layout, + &this.tcx, + )?; + this.write_scalar(Scalar::from_int(NUM_CPUS, dword_layout.size), &num_cpus.into())?; } // Thread-local storage From 3cfce6ffb23d8ea83593b4956212954a0459d372 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 21 May 2022 13:37:41 -0400 Subject: [PATCH 3082/5092] Make allow_data_races_* public to silence data races during cleanup --- src/data_race.rs | 84 +++++++++++++++++++++++++----------------------- src/eval.rs | 7 +++- 2 files changed, 49 insertions(+), 42 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index ba7300374562..5a6dd1d81d06 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -437,6 +437,49 @@ impl MemoryCellClocks { /// Evaluation context extensions. impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { + /// Temporarily allow data-races to occur. This should only be used in + /// one of these cases: + /// - One of the appropriate `validate_atomic` functions will be called to + /// to treat a memory access as atomic. + /// - The memory being accessed should be treated as internal state, that + /// cannot be accessed by the interpreted program. + /// - Execution of the interpreted program execution has halted. + #[inline] + fn allow_data_races_ref(&self, op: impl FnOnce(&MiriEvalContext<'mir, 'tcx>) -> R) -> R { + let this = self.eval_context_ref(); + let old = if let Some(data_race) = &this.machine.data_race { + data_race.multi_threaded.replace(false) + } else { + false + }; + let result = op(this); + if let Some(data_race) = &this.machine.data_race { + data_race.multi_threaded.set(old); + } + result + } + + /// Same as `allow_data_races_ref`, this temporarily disables any data-race detection and + /// so should only be used for atomic operations or internal state that the program cannot + /// access. + #[inline] + fn allow_data_races_mut( + &mut self, + op: impl FnOnce(&mut MiriEvalContext<'mir, 'tcx>) -> R, + ) -> R { + let this = self.eval_context_mut(); + let old = if let Some(data_race) = &this.machine.data_race { + data_race.multi_threaded.replace(false) + } else { + false + }; + let result = op(this); + if let Some(data_race) = &this.machine.data_race { + data_race.multi_threaded.set(old); + } + result + } + /// Atomic variant of read_scalar_at_offset. fn read_scalar_at_offset_atomic( &self, @@ -927,47 +970,6 @@ impl VClockAlloc { impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { - // Temporarily allow data-races to occur, this should only be - // used if either one of the appropriate `validate_atomic` functions - // will be called to treat a memory access as atomic or if the memory - // being accessed should be treated as internal state, that cannot be - // accessed by the interpreted program. - #[inline] - fn allow_data_races_ref(&self, op: impl FnOnce(&MiriEvalContext<'mir, 'tcx>) -> R) -> R { - let this = self.eval_context_ref(); - let old = if let Some(data_race) = &this.machine.data_race { - data_race.multi_threaded.replace(false) - } else { - false - }; - let result = op(this); - if let Some(data_race) = &this.machine.data_race { - data_race.multi_threaded.set(old); - } - result - } - - /// Same as `allow_data_races_ref`, this temporarily disables any data-race detection and - /// so should only be used for atomic operations or internal state that the program cannot - /// access. - #[inline] - fn allow_data_races_mut( - &mut self, - op: impl FnOnce(&mut MiriEvalContext<'mir, 'tcx>) -> R, - ) -> R { - let this = self.eval_context_mut(); - let old = if let Some(data_race) = &this.machine.data_race { - data_race.multi_threaded.replace(false) - } else { - false - }; - let result = op(this); - if let Some(data_race) = &this.machine.data_race { - data_race.multi_threaded.set(old); - } - result - } - /// Generic atomic operation implementation fn validate_atomic_op( &self, diff --git a/src/eval.rs b/src/eval.rs index 5f6348fe0bde..c4d58eb77143 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -344,7 +344,12 @@ pub fn eval_entry<'tcx>( })(); // Machine cleanup. - EnvVars::cleanup(&mut ecx).unwrap(); + // Execution of the program has halted so any memory access we do here + // cannot produce a real data race. If we do not do something to disable + // data race detection here, some uncommon combination of errors will + // cause a data race to be detected: + // https://github.com/rust-lang/miri/issues/2020 + ecx.allow_data_races_mut(|ecx| EnvVars::cleanup(ecx).unwrap()); // Process the result. match res { From 2fa53c03857095945b1e6ebfeec94cb39077297b Mon Sep 17 00:00:00 2001 From: Mateusz Gienieczko Date: Sat, 21 May 2022 21:42:25 +0200 Subject: [PATCH 3083/5092] Dynamic offset calculation in GetSystemInfo. --- src/shims/windows/foreign_items.rs | 36 ++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index f9cf755c5b4f..f2852d6bcca0 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -8,6 +8,7 @@ use rustc_target::spec::abi::Abi; use crate::*; use shims::foreign_items::EmulateByNameResult; use shims::windows::sync::EvalContextExt as _; +use smallvec::SmallVec; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -122,11 +123,42 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx iter::repeat(0u8).take(system_info.layout.size.bytes() as usize), )?; // Set selected fields. + let word_ty = this.tcx.mk_ty(TyKind::Uint(UintTy::U16)); let dword_ty = this.tcx.mk_ty(TyKind::Uint(UintTy::U32)); + let usize_ty = this.tcx.mk_ty(TyKind::Uint(UintTy::Usize)); + let word_layout = this.layout_of(word_ty)?; let dword_layout = this.layout_of(dword_ty)?; + let usize_layout = this.layout_of(usize_ty)?; + + // Using `mplace_field` is error-prone, see: https://github.com/rust-lang/miri/issues/2136. + // Pointer fields have different sizes on different targets. + // To avoid all these issue we calculate the offsets dynamically. + let field_sizes = [ + word_layout.size, // 0, wProcessorArchitecture : WORD + word_layout.size, // 1, wReserved : WORD + dword_layout.size, // 2, dwPageSize : DWORD + usize_layout.size, // 3, lpMinimumApplicationAddress : LPVOID + usize_layout.size, // 4, lpMaximumApplicationAddress : LPVOID + usize_layout.size, // 5, dwActiveProcessorMask : DWORD_PTR + dword_layout.size, // 6, dwNumberOfProcessors : DWORD + dword_layout.size, // 7, dwProcessorType : DWORD + dword_layout.size, // 8, dwAllocationGranularity : DWORD + word_layout.size, // 9, wProcessorLevel : WORD + word_layout.size, // 10, wProcessorRevision : WORD + ]; + let field_offsets: SmallVec<[Size; 11]> = field_sizes + .iter() + .copied() + .scan(Size::ZERO, |a, x| { + let res = Some(*a); + *a += x; + res + }) + .collect(); + // Set page size. let page_size = system_info.offset( - Size::from_bytes(4), + field_offsets[2], MemPlaceMeta::None, dword_layout, &this.tcx, @@ -137,7 +169,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; // Set number of processors. let num_cpus = system_info.offset( - Size::from_bytes(32), + field_offsets[6], MemPlaceMeta::None, dword_layout, &this.tcx, From b7d032c2199ec09a89b7aeafd7ad3b7e82cac7e7 Mon Sep 17 00:00:00 2001 From: Mateusz Gienieczko Date: Sun, 22 May 2022 00:59:49 +0200 Subject: [PATCH 3084/5092] Fix comment formatting. --- test-cargo-miri/tests/test.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 6758e99703cc..ba027381fa5b 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -50,8 +50,8 @@ fn cargo_env() { #[test] #[should_panic(expected = "Explicit panic")] -fn do_panic() { - // In large, friendly letters :) +fn do_panic() // In large, friendly letters :) +{ panic!("Explicit panic from test!"); } From a40ff562a0c20f8588c9a47816515d2ed3dc2284 Mon Sep 17 00:00:00 2001 From: Mateusz Gienieczko Date: Sun, 22 May 2022 01:00:59 +0200 Subject: [PATCH 3085/5092] Add `i16` and `u16` primitive layout. --- src/machine.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/machine.rs b/src/machine.rs index 7ab15b9f9ceb..9e95c632c7f4 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -178,9 +178,11 @@ pub struct AllocExtra { pub struct PrimitiveLayouts<'tcx> { pub unit: TyAndLayout<'tcx>, pub i8: TyAndLayout<'tcx>, + pub i16: TyAndLayout<'tcx>, pub i32: TyAndLayout<'tcx>, pub isize: TyAndLayout<'tcx>, pub u8: TyAndLayout<'tcx>, + pub u16: TyAndLayout<'tcx>, pub u32: TyAndLayout<'tcx>, pub usize: TyAndLayout<'tcx>, pub bool: TyAndLayout<'tcx>, @@ -194,9 +196,11 @@ impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> { Ok(Self { unit: layout_cx.layout_of(tcx.mk_unit())?, i8: layout_cx.layout_of(tcx.types.i8)?, + i16: layout_cx.layout_of(tcx.types.i16)?, i32: layout_cx.layout_of(tcx.types.i32)?, isize: layout_cx.layout_of(tcx.types.isize)?, u8: layout_cx.layout_of(tcx.types.u8)?, + u16: layout_cx.layout_of(tcx.types.u16)?, u32: layout_cx.layout_of(tcx.types.u32)?, usize: layout_cx.layout_of(tcx.types.usize)?, bool: layout_cx.layout_of(tcx.types.bool)?, From bd731508d46e232cb674cef93c41dbcaf391ae45 Mon Sep 17 00:00:00 2001 From: Mateusz Gienieczko Date: Sun, 22 May 2022 01:01:12 +0200 Subject: [PATCH 3086/5092] Use precomputed layouts. --- src/shims/windows/foreign_items.rs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index f2852d6bcca0..1a9b2300f723 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -112,8 +112,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "GetSystemInfo" => { - use crate::rustc_middle::ty::{layout::LayoutOf, TyKind, UintTy}; - let [system_info] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let system_info = this.deref_operand(system_info)?; @@ -123,16 +121,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx iter::repeat(0u8).take(system_info.layout.size.bytes() as usize), )?; // Set selected fields. - let word_ty = this.tcx.mk_ty(TyKind::Uint(UintTy::U16)); - let dword_ty = this.tcx.mk_ty(TyKind::Uint(UintTy::U32)); - let usize_ty = this.tcx.mk_ty(TyKind::Uint(UintTy::Usize)); - let word_layout = this.layout_of(word_ty)?; - let dword_layout = this.layout_of(dword_ty)?; - let usize_layout = this.layout_of(usize_ty)?; + let word_layout = this.machine.layouts.u16; + let dword_layout = this.machine.layouts.u32; + let usize_layout = this.machine.layouts.usize; // Using `mplace_field` is error-prone, see: https://github.com/rust-lang/miri/issues/2136. // Pointer fields have different sizes on different targets. - // To avoid all these issue we calculate the offsets dynamically. + // To avoid all these issue we calculate the offsets ourselves. let field_sizes = [ word_layout.size, // 0, wProcessorArchitecture : WORD word_layout.size, // 1, wReserved : WORD From 9a5c9a54817804e2cd9ca49a83be8dad85111412 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 May 2022 07:59:18 +0200 Subject: [PATCH 3087/5092] comment on test --- test-cargo-miri/tests/test.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index ba027381fa5b..1a8b3c72565d 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -66,6 +66,7 @@ fn fail_index_check() { fn page_size() { let page_size = page_size::get(); + // In particular, this checks that it is not 0. assert!( page_size.next_power_of_two() == page_size, "page size not a power of two: {}", From 486a7699357e6a6d7b58a6a8f49a9852a0a37e84 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 21 May 2022 12:14:17 -0400 Subject: [PATCH 3088/5092] Handle diagnotics emitted in runtime initialization --- src/eval.rs | 10 ++++++++++ tests/run-pass/track-alloc-1.rs | 5 +++++ tests/run-pass/track-alloc-1.stderr | 5 +++++ 3 files changed, 20 insertions(+) create mode 100644 tests/run-pass/track-alloc-1.rs create mode 100644 tests/run-pass/track-alloc-1.stderr diff --git a/src/eval.rs b/src/eval.rs index 5f6348fe0bde..0255368b20f2 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -168,6 +168,12 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( param_env, Evaluator::new(config, layout_cx), ); + + // Capture the current interpreter stack state (which should be empty) so that we can emit + // allocation-tracking and tag-tracking diagnostics for allocations which are part of the + // runtime. + let info = ecx.preprocess_diagnostics(); + // Some parts of initialization require a full `InterpCx`. Evaluator::late_init(&mut ecx, config)?; @@ -287,6 +293,10 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } } + // Emit any diagnostics related to the setup process for the runtime, so that when the + // interpreter loop starts there are no unprocessed diagnostics. + ecx.process_diagnostics(info); + Ok((ecx, ret_place)) } diff --git a/tests/run-pass/track-alloc-1.rs b/tests/run-pass/track-alloc-1.rs new file mode 100644 index 000000000000..7bb217309f94 --- /dev/null +++ b/tests/run-pass/track-alloc-1.rs @@ -0,0 +1,5 @@ +// Ensure that tracking early allocations doesn't ICE Miri. +// Early allocations are probably part of the runtime and therefore uninteresting, but they +// shouldn't cause a crash. +// compile-flags: -Zmiri-track-alloc-id=1 +fn main() {} diff --git a/tests/run-pass/track-alloc-1.stderr b/tests/run-pass/track-alloc-1.stderr new file mode 100644 index 000000000000..3c5a55d986e3 --- /dev/null +++ b/tests/run-pass/track-alloc-1.stderr @@ -0,0 +1,5 @@ +note: tracking was triggered + | + = note: created allocation with id 1 + = note: (no span available) + From 73534a678dedc9f68d4dfdd8532eec664bdb1e3c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 May 2022 18:16:59 +0200 Subject: [PATCH 3089/5092] tweak comment --- src/eval.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/eval.rs b/src/eval.rs index 0255368b20f2..a8279e8d60e2 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -171,7 +171,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Capture the current interpreter stack state (which should be empty) so that we can emit // allocation-tracking and tag-tracking diagnostics for allocations which are part of the - // runtime. + // early runtime setup. let info = ecx.preprocess_diagnostics(); // Some parts of initialization require a full `InterpCx`. From d7d7a9a1627fd75d49ae9516a531154726d6190d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sun, 22 May 2022 21:47:44 +0200 Subject: [PATCH 3090/5092] [NFC] shims: fs: fmt --- src/shims/posix/fs.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index dec1e9781680..3fcbbb803eaf 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -31,16 +31,19 @@ trait FileDescriptor: std::fmt::Debug { communicate_allowed: bool, bytes: &mut [u8], ) -> InterpResult<'tcx, io::Result>; + fn write<'tcx>( &self, communicate_allowed: bool, bytes: &[u8], ) -> InterpResult<'tcx, io::Result>; + fn seek<'tcx>( &mut self, communicate_allowed: bool, offset: SeekFrom, ) -> InterpResult<'tcx, io::Result>; + fn close<'tcx>( self: Box, _communicate_allowed: bool, From 89da571b5d7d35220dd65c670caf66e25c10a892 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sun, 22 May 2022 21:54:00 +0200 Subject: [PATCH 3091/5092] shims: fs: silence stderr instead of stdout. Fixes #2143 --- src/shims/posix/fs.rs | 6 +++--- tests/run-pass/hide_stdout.rs | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 3fcbbb803eaf..79539fd9c49e 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -307,14 +307,14 @@ pub struct FileHandler { impl<'tcx> FileHandler { pub(crate) fn new(mute_stdout_stderr: bool) -> FileHandler { let mut handles: BTreeMap<_, Box> = BTreeMap::new(); + handles.insert(0i32, Box::new(io::stdin())); if mute_stdout_stderr { - handles.insert(0i32, Box::new(DummyOutput)); handles.insert(1i32, Box::new(DummyOutput)); + handles.insert(2i32, Box::new(DummyOutput)); } else { - handles.insert(0i32, Box::new(io::stdin())); handles.insert(1i32, Box::new(io::stdout())); + handles.insert(2i32, Box::new(io::stderr())); } - handles.insert(2i32, Box::new(io::stderr())); FileHandler { handles } } diff --git a/tests/run-pass/hide_stdout.rs b/tests/run-pass/hide_stdout.rs index 849fce913862..3ee68d01f43d 100644 --- a/tests/run-pass/hide_stdout.rs +++ b/tests/run-pass/hide_stdout.rs @@ -1,5 +1,6 @@ // compile-flags: -Zmiri-mute-stdout-stderr fn main() { - println!("cake"); + println!("print to stdout"); + eprintln!("print to stderr"); } From b20c6cfd81b8df20e0714e3bc8a6054be682d5f1 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 7 Dec 2021 22:05:13 -0500 Subject: [PATCH 3092/5092] Factor current-span logic into a lazy caching handle --- src/helpers.rs | 44 ++++++++++++++++++++++++++--- src/lib.rs | 2 +- src/machine.rs | 10 +++---- src/stacked_borrows.rs | 45 ++++++++++++++---------------- src/stacked_borrows/diagnostics.rs | 40 +++++++++----------------- 5 files changed, 79 insertions(+), 62 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 6beb3f8c3bb0..2d1fffc6a125 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -2,7 +2,6 @@ pub mod convert; use std::mem; use std::num::NonZeroUsize; -use std::rc::Rc; use std::time::Duration; use log::trace; @@ -14,7 +13,7 @@ use rustc_middle::ty::{ layout::{LayoutOf, TyAndLayout}, List, TyCtxt, }; -use rustc_span::{def_id::CrateNum, sym, Symbol}; +use rustc_span::{def_id::CrateNum, sym, Span, Symbol}; use rustc_target::abi::{Align, FieldsShape, Size, Variants}; use rustc_target::spec::abi::Abi; @@ -800,6 +799,43 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } +impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { + pub fn current_span(&self) -> CurrentSpan<'_, 'mir, 'tcx> { + CurrentSpan { span: None, machine: self } + } +} + +/// A `CurrentSpan` should be created infrequently (ideally once) per interpreter step. It does +/// nothing on creation, but when `CurrentSpan::get` is called, searches the current stack for the +/// topmost frame which corresponds to a local crate, and returns the current span in that frame. +/// The result of that search is cached so that later calls are approximately free. +#[derive(Clone)] +pub struct CurrentSpan<'a, 'tcx, 'mir> { + span: Option, + machine: &'a Evaluator<'tcx, 'mir>, +} + +impl<'a, 'tcx, 'mir> CurrentSpan<'a, 'tcx, 'mir> { + pub fn get(&mut self) -> Span { + *self.span.get_or_insert_with(|| Self::current_span(&self.machine)) + } + + #[inline(never)] + fn current_span(machine: &Evaluator<'_, '_>) -> Span { + machine + .threads + .active_thread_stack() + .into_iter() + .rev() + .find(|frame| { + let def_id = frame.instance.def_id(); + def_id.is_local() || machine.local_crates.contains(&def_id.krate) + }) + .map(|frame| frame.current_span()) + .unwrap_or(rustc_span::DUMMY_SP) + } +} + /// Check that the number of args is what we expect. pub fn check_arg_count<'a, 'tcx, const N: usize>( args: &'a [OpTy<'tcx, Tag>], @@ -822,7 +858,7 @@ pub fn isolation_abort_error(name: &str) -> InterpResult<'static> { /// Retrieve the list of local crates that should have been passed by cargo-miri in /// MIRI_LOCAL_CRATES and turn them into `CrateNum`s. -pub fn get_local_crates(tcx: &TyCtxt<'_>) -> Rc<[CrateNum]> { +pub fn get_local_crates(tcx: &TyCtxt<'_>) -> Vec { // Convert the local crate names from the passed-in config into CrateNums so that they can // be looked up quickly during execution let local_crate_names = std::env::var("MIRI_LOCAL_CRATES") @@ -836,7 +872,7 @@ pub fn get_local_crates(tcx: &TyCtxt<'_>) -> Rc<[CrateNum]> { local_crates.push(crate_num); } } - Rc::from(local_crates.as_slice()) + local_crates } /// Formats an AllocRange like [0x1..0x3], for use in diagnostics. diff --git a/src/lib.rs b/src/lib.rs index ee7a3bcdc5cb..9fa2c61fd831 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -77,7 +77,7 @@ pub use crate::diagnostics::{ pub use crate::eval::{ create_ecx, eval_entry, AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, RejectOpWith, }; -pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; +pub use crate::helpers::{CurrentSpan, EvalContextExt as HelpersEvalContextExt}; pub use crate::machine::{ AllocExtra, Evaluator, FrameData, MiriEvalContext, MiriEvalContextExt, MiriMemoryKind, Tag, NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, diff --git a/src/machine.rs b/src/machine.rs index 9e95c632c7f4..d78b0135e94f 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -6,7 +6,6 @@ use std::cell::RefCell; use std::collections::HashSet; use std::fmt; use std::num::NonZeroU64; -use std::rc::Rc; use std::time::Instant; use rand::rngs::StdRng; @@ -278,7 +277,7 @@ pub struct Evaluator<'mir, 'tcx> { pub(crate) backtrace_style: BacktraceStyle, /// Crates which are considered local for the purposes of error reporting. - pub(crate) local_crates: Rc<[CrateNum]>, + pub(crate) local_crates: Vec, /// Mapping extern static names to their base pointer. extern_statics: FxHashMap>, @@ -584,8 +583,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { alloc.size(), stacked_borrows, kind, - &ecx.machine.threads, - ecx.machine.local_crates.clone(), + ecx.machine.current_span(), )) } else { None @@ -667,7 +665,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { tag, range, machine.stacked_borrows.as_ref().unwrap(), - &machine.threads, + machine.current_span(), ) } else { Ok(()) @@ -691,7 +689,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { tag, range, machine.stacked_borrows.as_ref().unwrap(), - &machine.threads, + machine.current_span(), ) } else { Ok(()) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index d7c213932324..625ffb2c5d20 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -5,7 +5,6 @@ use log::trace; use std::cell::RefCell; use std::fmt; use std::num::NonZeroU64; -use std::rc::Rc; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::Mutability; @@ -14,7 +13,6 @@ use rustc_middle::ty::{ self, layout::{HasParamEnv, LayoutOf}, }; -use rustc_span::def_id::CrateNum; use rustc_span::DUMMY_SP; use rustc_target::abi::Size; use std::collections::HashSet; @@ -22,9 +20,7 @@ use std::collections::HashSet; use crate::*; pub mod diagnostics; -use diagnostics::AllocHistory; - -use diagnostics::TagHistory; +use diagnostics::{AllocHistory, TagHistory}; pub type PtrId = NonZeroU64; pub type CallId = NonZeroU64; @@ -376,7 +372,7 @@ impl<'tcx> Stack { tag: SbTag, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &mut GlobalStateInner, - threads: &ThreadManager<'_, 'tcx>, + current_span: &mut CurrentSpan<'_, '_, 'tcx>, alloc_history: &mut AllocHistory, ) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. @@ -400,7 +396,7 @@ impl<'tcx> Stack { global, alloc_history, )?; - alloc_history.log_invalidation(item.tag, alloc_range, threads); + alloc_history.log_invalidation(item.tag, alloc_range, current_span); } } else { // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses. @@ -422,7 +418,7 @@ impl<'tcx> Stack { alloc_history, )?; item.perm = Permission::Disabled; - alloc_history.log_invalidation(item.tag, alloc_range, threads); + alloc_history.log_invalidation(item.tag, alloc_range, current_span); } } } @@ -471,7 +467,7 @@ impl<'tcx> Stack { new: Item, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &mut GlobalStateInner, - threads: &ThreadManager<'_, 'tcx>, + current_span: &mut CurrentSpan<'_, '_, 'tcx>, alloc_history: &mut AllocHistory, ) -> InterpResult<'tcx> { // Figure out which access `perm` corresponds to. @@ -505,7 +501,7 @@ impl<'tcx> Stack { derived_from, (alloc_id, alloc_range, offset), global, - threads, + current_span, alloc_history, )?; @@ -533,13 +529,13 @@ impl<'tcx> Stack { /// Map per-stack operations to higher-level per-location-range operations. impl<'tcx> Stacks { /// Creates new stack with initial tag. - fn new(size: Size, perm: Permission, tag: SbTag, local_crates: Rc<[CrateNum]>) -> Self { + fn new(size: Size, perm: Permission, tag: SbTag) -> Self { let item = Item { perm, tag, protector: None }; let stack = Stack { borrows: vec![item] }; Stacks { stacks: RefCell::new(RangeMap::new(size, stack)), - history: RefCell::new(AllocHistory::new(local_crates)), + history: RefCell::new(AllocHistory::new()), } } @@ -579,8 +575,7 @@ impl Stacks { size: Size, state: &GlobalState, kind: MemoryKind, - threads: &ThreadManager<'_, '_>, - local_crates: Rc<[CrateNum]>, + mut current_span: CurrentSpan<'_, '_, '_>, ) -> Self { let mut extra = state.borrow_mut(); let (base_tag, perm) = match kind { @@ -614,12 +609,12 @@ impl Stacks { (tag, Permission::SharedReadWrite) } }; - let stacks = Stacks::new(size, perm, base_tag, local_crates); + let stacks = Stacks::new(size, perm, base_tag); stacks.history.borrow_mut().log_creation( None, base_tag, alloc_range(Size::ZERO, size), - threads, + &mut current_span, ); stacks } @@ -631,7 +626,7 @@ impl Stacks { tag: SbTag, range: AllocRange, state: &GlobalState, - threads: &ThreadManager<'_, 'tcx>, + mut current_span: CurrentSpan<'_, '_, 'tcx>, ) -> InterpResult<'tcx> { trace!( "read access with tag {:?}: {:?}, size {}", @@ -646,7 +641,7 @@ impl Stacks { tag, (alloc_id, range, offset), &mut state, - threads, + &mut current_span, history, ) }) @@ -659,7 +654,7 @@ impl Stacks { tag: SbTag, range: AllocRange, state: &GlobalState, - threads: &ThreadManager<'_, 'tcx>, + mut current_span: CurrentSpan<'_, '_, 'tcx>, ) -> InterpResult<'tcx> { trace!( "write access with tag {:?}: {:?}, size {}", @@ -674,7 +669,7 @@ impl Stacks { tag, (alloc_id, range, offset), &mut state, - threads, + &mut current_span, history, ) }) @@ -723,6 +718,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?; + let mut current_span = this.machine.current_span(); { let extra = this.get_alloc_extra(alloc_id)?; let stacked_borrows = @@ -732,10 +728,10 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(orig_tag), new_tag, alloc_range(base_offset, size), - &this.machine.threads, + &mut current_span, ); if protect { - alloc_history.log_protector(orig_tag, new_tag, &this.machine.threads); + alloc_history.log_protector(orig_tag, new_tag, &mut current_span); } } @@ -804,7 +800,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx item, (alloc_id, range, offset), &mut *global, - &this.machine.threads, + &mut current_span, history, ) }) @@ -821,13 +817,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let item = Item { perm, tag: new_tag, protector }; let range = alloc_range(base_offset, size); let mut global = machine.stacked_borrows.as_ref().unwrap().borrow_mut(); + let mut current_span = machine.current_span(); stacked_borrows.for_each_mut(range, |offset, stack, history| { stack.grant( orig_tag, item, (alloc_id, range, offset), &mut global, - &machine.threads, + &mut current_span, history, ) })?; diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index 734c3a14e3b3..f3692cdeeb04 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -1,17 +1,14 @@ use smallvec::SmallVec; -use std::rc::Rc; use rustc_middle::mir::interpret::{AllocId, AllocRange}; -use rustc_span::def_id::CrateNum; use rustc_span::{Span, SpanData}; use rustc_target::abi::Size; -use crate::helpers::HexRange; +use crate::helpers::{CurrentSpan, HexRange}; use crate::stacked_borrows::{err_sb_ub, AccessKind, Permission}; use crate::Item; use crate::SbTag; use crate::Stack; -use crate::ThreadManager; use rustc_middle::mir::interpret::InterpError; @@ -23,8 +20,6 @@ pub struct AllocHistory { creations: smallvec::SmallVec<[Event; 2]>, invalidations: smallvec::SmallVec<[Event; 1]>, protectors: smallvec::SmallVec<[Protection; 1]>, - /// This field is a clone of the `local_crates` field on `Evaluator`. - local_crates: Rc<[CrateNum]>, } #[derive(Clone, Debug)] @@ -59,37 +54,23 @@ pub enum TagHistory { } impl AllocHistory { - pub fn new(local_crates: Rc<[CrateNum]>) -> Self { + pub fn new() -> Self { Self { current_time: 0, creations: SmallVec::new(), invalidations: SmallVec::new(), protectors: SmallVec::new(), - local_crates, } } - fn current_span(&self, threads: &ThreadManager<'_, '_>) -> Span { - threads - .active_thread_stack() - .into_iter() - .rev() - .find(|frame| { - let def_id = frame.instance.def_id(); - def_id.is_local() || self.local_crates.contains(&def_id.krate) - }) - .map(|frame| frame.current_span()) - .unwrap_or(rustc_span::DUMMY_SP) - } - pub fn log_creation( &mut self, parent: Option, tag: SbTag, range: AllocRange, - threads: &ThreadManager<'_, '_>, + current_span: &mut CurrentSpan<'_, '_, '_>, ) { - let span = self.current_span(threads); + let span = current_span.get(); self.creations.push(Event { parent, tag, range, span, time: self.current_time }); self.current_time += 1; } @@ -98,15 +79,20 @@ impl AllocHistory { &mut self, tag: SbTag, range: AllocRange, - threads: &ThreadManager<'_, '_>, + current_span: &mut CurrentSpan<'_, '_, '_>, ) { - let span = self.current_span(threads); + let span = current_span.get(); self.invalidations.push(Event { parent: None, tag, range, span, time: self.current_time }); self.current_time += 1; } - pub fn log_protector(&mut self, orig_tag: SbTag, tag: SbTag, threads: &ThreadManager<'_, '_>) { - let span = self.current_span(threads); + pub fn log_protector( + &mut self, + orig_tag: SbTag, + tag: SbTag, + current_span: &mut CurrentSpan<'_, '_, '_>, + ) { + let span = current_span.get(); self.protectors.push(Protection { orig_tag, tag, span }); self.current_time += 1; } From fdfbd7a658b58f1f579ad677a73a516668b35ed6 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Sat, 7 May 2022 10:37:20 -0700 Subject: [PATCH 3093/5092] Fix backwards `cmpxchg_weak_failure_rate` check --- src/data_race.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index 5a6dd1d81d06..c52b84018466 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -623,10 +623,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // `binary_op` will bail if either of them is not a scalar. let eq = this.binary_op(mir::BinOp::Eq, &old, expect_old)?; // If the operation would succeed, but is "weak", fail some portion - // of the time, based on `rate`. - let rate = this.machine.cmpxchg_weak_failure_rate; + // of the time, based on `success_rate`. + let success_rate = 1.0 - this.machine.cmpxchg_weak_failure_rate; let cmpxchg_success = eq.to_scalar()?.to_bool()? - && (!can_fail_spuriously || this.machine.rng.get_mut().gen::() < rate); + && if can_fail_spuriously { + this.machine.rng.get_mut().gen_bool(success_rate) + } else { + true + }; let res = Immediate::ScalarPair( old.to_scalar_or_uninit(), Scalar::from_bool(cmpxchg_success).into(), From f7bc441fd342783ad42b8a9fbb2a1595e80044ad Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Sun, 22 May 2022 15:22:05 -0500 Subject: [PATCH 3094/5092] Initial work on permissive provenance --- src/bin/miri.rs | 8 +- src/eval.rs | 7 +- src/helpers.rs | 4 +- src/intptrcast.rs | 123 +++++++++++++++--- src/lib.rs | 5 +- src/machine.rs | 70 +++++++--- src/stacked_borrows.rs | 11 +- tests/compile-fail/ptr_int_unexposed.rs | 12 ++ tests/compile-fail/ptr_legacy_provenance.rs | 21 +++ .../run-pass/ptr_int_permissive_provenance.rs | 62 +++++++++ 10 files changed, 275 insertions(+), 48 deletions(-) create mode 100644 tests/compile-fail/ptr_int_unexposed.rs create mode 100644 tests/compile-fail/ptr_legacy_provenance.rs create mode 100644 tests/run-pass/ptr_int_permissive_provenance.rs diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 0aa8755573a6..784f0da8a30d 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -30,7 +30,7 @@ use rustc_middle::{ }; use rustc_session::{config::ErrorOutputType, search_paths::PathKind, CtfeBacktrace}; -use miri::BacktraceStyle; +use miri::{BacktraceStyle, ProvenanceMode}; struct MiriCompilerCalls { miri_config: miri::MiriConfig, @@ -384,10 +384,14 @@ fn main() { miri_config.tag_raw = true; } "-Zmiri-strict-provenance" => { - miri_config.strict_provenance = true; + miri_config.provenance_mode = ProvenanceMode::Strict; miri_config.tag_raw = true; miri_config.check_number_validity = true; } + "-Zmiri-permissive-provenance" => { + miri_config.provenance_mode = ProvenanceMode::Permissive; + miri_config.tag_raw = true; + } "-Zmiri-mute-stdout-stderr" => { miri_config.mute_stdout_stderr = true; } diff --git a/src/eval.rs b/src/eval.rs index 13dff22ea3cc..430ff06cf15a 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -113,9 +113,8 @@ pub struct MiriConfig { pub panic_on_unsupported: bool, /// Which style to use for printing backtraces. pub backtrace_style: BacktraceStyle, - /// Whether to enforce "strict provenance" rules. Enabling this means int2ptr casts return - /// pointers with an invalid provenance, i.e., not valid for any memory access. - pub strict_provenance: bool, + /// Which provenance to use for int2ptr casts + pub provenance_mode: ProvenanceMode, /// Whether to ignore any output by the program. This is helpful when debugging miri /// as its messages don't get intermingled with the program messages. pub mute_stdout_stderr: bool, @@ -144,7 +143,7 @@ impl Default for MiriConfig { measureme_out: None, panic_on_unsupported: false, backtrace_style: BacktraceStyle::Short, - strict_provenance: false, + provenance_mode: ProvenanceMode::Legacy, mute_stdout_stderr: false, } } diff --git a/src/helpers.rs b/src/helpers.rs index 2d1fffc6a125..08b2fa98a230 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -786,8 +786,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn mark_immutable(&mut self, mplace: &MemPlace) { let this = self.eval_context_mut(); // This got just allocated, so there definitely is a pointer here. - this.alloc_mark_immutable(mplace.ptr.into_pointer_or_addr().unwrap().provenance.alloc_id) - .unwrap(); + let provenance = mplace.ptr.into_pointer_or_addr().unwrap().provenance; + this.alloc_mark_immutable(provenance.get_alloc_id().unwrap()).unwrap(); } fn item_link_name(&self, def_id: DefId) -> Symbol { diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 895241bcc326..8395cdc2733d 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -4,11 +4,25 @@ use std::collections::hash_map::Entry; use log::trace; use rand::Rng; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_target::abi::{HasDataLayout, Size}; use crate::*; +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum ProvenanceMode { + /// Int2ptr casts return pointers with "wildcard" provenance + /// that basically matches that of all exposed pointers + /// (and SB tags, if enabled). + Permissive, + /// Int2ptr casts return pointers with an invalid provenance, + /// i.e., not valid for any memory access. + Strict, + /// Int2ptr casts determine the allocation they point to at cast time. + /// All allocations are considered exposed. + Legacy, +} + pub type GlobalState = RefCell; #[derive(Clone, Debug)] @@ -21,12 +35,14 @@ pub struct GlobalStateInner { /// they do not have an `AllocExtra`. /// This is the inverse of `int_to_ptr_map`. base_addr: FxHashMap, + /// Whether an allocation has been exposed or not. This cannot be put + /// into `AllocExtra` for the same reason as `base_addr`. + exposed: FxHashSet, /// This is used as a memory address when a new pointer is casted to an integer. It /// is always larger than any address that was previously made part of a block. next_base_addr: u64, - /// Whether to enforce "strict provenance" rules. Enabling this means int2ptr casts return - /// pointers with an invalid provenance, i.e., not valid for any memory access. - strict_provenance: bool, + /// The provenance to use for int2ptr casts + provenance_mode: ProvenanceMode, } impl GlobalStateInner { @@ -34,22 +50,22 @@ impl GlobalStateInner { GlobalStateInner { int_to_ptr_map: Vec::default(), base_addr: FxHashMap::default(), + exposed: FxHashSet::default(), next_base_addr: STACK_ADDR, - strict_provenance: config.strict_provenance, + provenance_mode: config.provenance_mode, } } } impl<'mir, 'tcx> GlobalStateInner { - pub fn ptr_from_addr(addr: u64, ecx: &MiriEvalContext<'mir, 'tcx>) -> Pointer> { - trace!("Casting 0x{:x} to a pointer", addr); + // Returns the exposed `AllocId` that corresponds to the specified addr, + // or `None` if the addr is out of bounds + fn alloc_id_from_addr(ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64) -> Option { let global_state = ecx.machine.intptrcast.borrow(); - - if global_state.strict_provenance { - return Pointer::new(None, Size::from_bytes(addr)); - } + assert!(global_state.provenance_mode != ProvenanceMode::Strict); let pos = global_state.int_to_ptr_map.binary_search_by_key(&addr, |(addr, _)| *addr); + let alloc_id = match pos { Ok(pos) => Some(global_state.int_to_ptr_map[pos].1), Err(0) => None, @@ -60,6 +76,7 @@ impl<'mir, 'tcx> GlobalStateInner { // This never overflows because `addr >= glb` let offset = addr - glb; // If the offset exceeds the size of the allocation, don't use this `alloc_id`. + if offset <= ecx .get_alloc_size_and_align(alloc_id, AllocCheck::MaybeDead) @@ -72,12 +89,65 @@ impl<'mir, 'tcx> GlobalStateInner { None } } - }; - // Pointers created from integers are untagged. - Pointer::new( - alloc_id.map(|alloc_id| Tag { alloc_id, sb: SbTag::Untagged }), - Size::from_bytes(addr), - ) + }?; + + // In legacy mode, we consider all allocations exposed. + if global_state.provenance_mode == ProvenanceMode::Legacy + || global_state.exposed.contains(&alloc_id) + { + Some(alloc_id) + } else { + None + } + } + + pub fn expose_addr(ecx: &MiriEvalContext<'mir, 'tcx>, alloc_id: AllocId) { + trace!("Exposing allocation id {:?}", alloc_id); + + let mut global_state = ecx.machine.intptrcast.borrow_mut(); + if global_state.provenance_mode == ProvenanceMode::Permissive { + global_state.exposed.insert(alloc_id); + } + } + + pub fn ptr_from_addr_transmute( + ecx: &MiriEvalContext<'mir, 'tcx>, + addr: u64, + ) -> Pointer> { + trace!("Transmuting 0x{:x} to a pointer", addr); + + let global_state = ecx.machine.intptrcast.borrow(); + + // In legacy mode, we have to support int2ptr transmutes, + // so just pretend they do the same thing as a cast. + if global_state.provenance_mode == ProvenanceMode::Legacy { + Self::ptr_from_addr_cast(ecx, addr) + } else { + Pointer::new(None, Size::from_bytes(addr)) + } + } + + pub fn ptr_from_addr_cast( + ecx: &MiriEvalContext<'mir, 'tcx>, + addr: u64, + ) -> Pointer> { + trace!("Casting 0x{:x} to a pointer", addr); + + let global_state = ecx.machine.intptrcast.borrow(); + + if global_state.provenance_mode == ProvenanceMode::Strict { + Pointer::new(None, Size::from_bytes(addr)) + } else if global_state.provenance_mode == ProvenanceMode::Legacy { + let alloc_id = Self::alloc_id_from_addr(ecx, addr); + + Pointer::new( + alloc_id + .map(|alloc_id| Tag::Concrete(ConcreteTag { alloc_id, sb: SbTag::Untagged })), + Size::from_bytes(addr), + ) + } else { + Pointer::new(Some(Tag::Wildcard), Size::from_bytes(addr)) + } } fn alloc_base_addr(ecx: &MiriEvalContext<'mir, 'tcx>, alloc_id: AllocId) -> u64 { @@ -136,14 +206,27 @@ impl<'mir, 'tcx> GlobalStateInner { dl.overflowing_offset(base_addr, offset.bytes()).0 } - pub fn abs_ptr_to_rel(ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer) -> Size { + pub fn abs_ptr_to_rel( + ecx: &MiriEvalContext<'mir, 'tcx>, + ptr: Pointer, + ) -> Option<(AllocId, Size)> { let (tag, addr) = ptr.into_parts(); // addr is absolute (Tag provenance) - let base_addr = GlobalStateInner::alloc_base_addr(ecx, tag.alloc_id); + + let alloc_id = if let Tag::Concrete(concrete) = tag { + concrete.alloc_id + } else { + GlobalStateInner::alloc_id_from_addr(ecx, addr.bytes())? + }; + + let base_addr = GlobalStateInner::alloc_base_addr(ecx, alloc_id); // Wrapping "addr - base_addr" let dl = ecx.data_layout(); let neg_base_addr = (base_addr as i64).wrapping_neg(); - Size::from_bytes(dl.overflowing_signed_offset(addr.bytes(), neg_base_addr).0) + Some(( + alloc_id, + Size::from_bytes(dl.overflowing_signed_offset(addr.bytes(), neg_base_addr).0), + )) } /// Shifts `addr` to make it aligned with `align` by rounding `addr` to the smallest multiple diff --git a/src/lib.rs b/src/lib.rs index 9fa2c61fd831..e571c8a00102 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -78,9 +78,10 @@ pub use crate::eval::{ create_ecx, eval_entry, AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, RejectOpWith, }; pub use crate::helpers::{CurrentSpan, EvalContextExt as HelpersEvalContextExt}; +pub use crate::intptrcast::ProvenanceMode; pub use crate::machine::{ - AllocExtra, Evaluator, FrameData, MiriEvalContext, MiriEvalContextExt, MiriMemoryKind, Tag, - NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, + AllocExtra, ConcreteTag, Evaluator, FrameData, MiriEvalContext, MiriEvalContextExt, + MiriMemoryKind, Tag, NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, }; pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; diff --git a/src/machine.rs b/src/machine.rs index d78b0135e94f..12a32d81b5c9 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -125,7 +125,13 @@ impl fmt::Display for MiriMemoryKind { /// Pointer provenance (tag). #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Tag { +pub enum Tag { + Concrete(ConcreteTag), + Wildcard, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct ConcreteTag { pub alloc_id: AllocId, /// Stacked Borrows tag. pub sb: SbTag, @@ -133,8 +139,8 @@ pub struct Tag { #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(Pointer, 24); -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(Pointer>, 24); +// #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +// static_assert_size!(Pointer>, 24); #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(ScalarMaybeUninit, 32); @@ -148,18 +154,31 @@ impl Provenance for Tag { fn fmt(ptr: &Pointer, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (tag, addr) = ptr.into_parts(); // address is absolute write!(f, "0x{:x}", addr.bytes())?; - // Forward `alternate` flag to `alloc_id` printing. - if f.alternate() { - write!(f, "[{:#?}]", tag.alloc_id)?; - } else { - write!(f, "[{:?}]", tag.alloc_id)?; + + match tag { + Tag::Concrete(tag) => { + // Forward `alternate` flag to `alloc_id` printing. + if f.alternate() { + write!(f, "[{:#?}]", tag.alloc_id)?; + } else { + write!(f, "[{:?}]", tag.alloc_id)?; + } + // Print Stacked Borrows tag. + write!(f, "{:?}", tag.sb)?; + } + Tag::Wildcard => { + write!(f, "[Wildcard]")?; + } } - // Print Stacked Borrows tag. - write!(f, "{:?}", tag.sb) + + Ok(()) } fn get_alloc_id(self) -> Option { - Some(self.alloc_id) + match self { + Tag::Concrete(concrete) => Some(concrete.alloc_id), + Tag::Wildcard => None, + } } } @@ -611,7 +630,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } else { SbTag::Untagged }; - Pointer::new(Tag { alloc_id: ptr.provenance, sb: sb_tag }, Size::from_bytes(absolute_addr)) + Pointer::new( + Tag::Concrete(ConcreteTag { alloc_id: ptr.provenance, sb: sb_tag }), + Size::from_bytes(absolute_addr), + ) } #[inline(always)] @@ -619,7 +641,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, ) -> Pointer> { - intptrcast::GlobalStateInner::ptr_from_addr(addr, ecx) + intptrcast::GlobalStateInner::ptr_from_addr_cast(ecx, addr) } #[inline(always)] @@ -627,14 +649,22 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, ) -> Pointer> { - Self::ptr_from_addr_cast(ecx, addr) + intptrcast::GlobalStateInner::ptr_from_addr_transmute(ecx, addr) } #[inline(always)] fn expose_ptr( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _ptr: Pointer, + ecx: &mut InterpCx<'mir, 'tcx, Self>, + ptr: Pointer, ) -> InterpResult<'tcx> { + let tag = ptr.provenance; + + if let Tag::Concrete(concrete) = tag { + intptrcast::GlobalStateInner::expose_addr(ecx, concrete.alloc_id); + } + + // No need to do anything for wildcard pointers as + // their provenances have already been previously exposed. Ok(()) } @@ -645,7 +675,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ptr: Pointer, ) -> Option<(AllocId, Size, Self::TagExtra)> { let rel = intptrcast::GlobalStateInner::abs_ptr_to_rel(ecx, ptr); - Some((ptr.provenance.alloc_id, rel, ptr.provenance.sb)) + + let sb = match ptr.provenance { + Tag::Concrete(ConcreteTag { sb, .. }) => sb, + Tag::Wildcard => SbTag::Untagged, + }; + + rel.map(|(alloc_id, size)| (alloc_id, size, sb)) } #[inline(always)] diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 625ffb2c5d20..f137b861342a 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -867,7 +867,16 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.reborrow(&place, size, kind, new_tag, protect)?; // Adjust pointer. - let new_place = place.map_provenance(|p| p.map(|t| Tag { sb: new_tag, ..t })); + let new_place = place.map_provenance(|p| { + p.map(|t| { + // TODO: Fix this eventually + if let Tag::Concrete(t) = t { + Tag::Concrete(ConcreteTag { sb: new_tag, ..t }) + } else { + t + } + }) + }); // Return new pointer. Ok(ImmTy::from_immediate(new_place.to_ref(this), val.layout)) diff --git a/tests/compile-fail/ptr_int_unexposed.rs b/tests/compile-fail/ptr_int_unexposed.rs new file mode 100644 index 000000000000..2aecb68b8b64 --- /dev/null +++ b/tests/compile-fail/ptr_int_unexposed.rs @@ -0,0 +1,12 @@ +// compile-flags: -Zmiri-permissive-provenance -Zmiri-disable-stacked-borrows + +fn main() { + let x: i32 = 3; + let x_ptr = &x as *const i32; + + // TODO: switch this to addr() once we intrinsify it + let x_usize: usize = unsafe { std::mem::transmute(x_ptr) }; + // Cast back a pointer that did *not* get exposed. + let ptr = x_usize as *const i32; + assert_eq!(unsafe { *ptr }, 3); //~ ERROR Undefined Behavior: dereferencing pointer failed +} diff --git a/tests/compile-fail/ptr_legacy_provenance.rs b/tests/compile-fail/ptr_legacy_provenance.rs new file mode 100644 index 000000000000..aecc1460e085 --- /dev/null +++ b/tests/compile-fail/ptr_legacy_provenance.rs @@ -0,0 +1,21 @@ +// compile-flags: -Zmiri-disable-stacked-borrows +#![feature(strict_provenance)] + +use std::ptr; + +// Make sure that with legacy provenance, the allocation id of +// a casted pointer is determined at cast-time +fn main() { + let x: i32 = 0; + let y: i32 = 1; + + let x_ptr = &x as *const i32; + let y_ptr = &y as *const i32; + + let x_usize = x_ptr.expose_addr(); + let y_usize = y_ptr.expose_addr(); + + let ptr = ptr::from_exposed_addr::(y_usize); + let ptr = ptr.with_addr(x_usize); + assert_eq!(unsafe { *ptr }, 0); //~ ERROR is out-of-bounds +} diff --git a/tests/run-pass/ptr_int_permissive_provenance.rs b/tests/run-pass/ptr_int_permissive_provenance.rs new file mode 100644 index 000000000000..e025cf921313 --- /dev/null +++ b/tests/run-pass/ptr_int_permissive_provenance.rs @@ -0,0 +1,62 @@ +// compile-flags: -Zmiri-permissive-provenance -Zmiri-disable-stacked-borrows +#![feature(strict_provenance)] + +use std::ptr; + +/// Ensure we can expose the address of a pointer that is out-of-bounds +fn ptr_roundtrip_out_of_bounds() { + let x: i32 = 3; + let x_ptr = &x as *const i32; + + let x_usize = x_ptr.wrapping_offset(128).expose_addr(); + + let ptr = ptr::from_exposed_addr::(x_usize).wrapping_offset(-128); + assert_eq!(unsafe { *ptr }, 3); +} + +/// Ensure that we can move between allocations after casting back to a ptr +fn ptr_roundtrip_confusion() { + let x: i32 = 0; + let y: i32 = 1; + + let x_ptr = &x as *const i32; + let y_ptr = &y as *const i32; + + let x_usize = x_ptr.expose_addr(); + let y_usize = y_ptr.expose_addr(); + + let ptr = ptr::from_exposed_addr::(y_usize); + let ptr = ptr.with_addr(x_usize); + assert_eq!(unsafe { *ptr }, 0); +} + +/// Ensure we can cast back a different integer than the one we got when exposing. +fn ptr_roundtrip_imperfect() { + let x: u8 = 3; + let x_ptr = &x as *const u8; + + let x_usize = x_ptr.expose_addr() + 128; + + let ptr = ptr::from_exposed_addr::(x_usize).wrapping_offset(-128); + assert_eq!(unsafe { *ptr }, 3); +} + +/// Ensure that we can roundtrip through a pointer with an address of 0 +fn ptr_roundtrip_null() { + let x = &42; + let x_ptr = x as *const i32; + let x_null_ptr = x_ptr.with_addr(0); // addr 0, but still the provenance of x + let null = x_null_ptr.expose_addr(); + assert_eq!(null, 0); + + let x_null_ptr_copy = ptr::from_exposed_addr::(null); // just a roundtrip, so has provenance of x (angelically) + let x_ptr_copy = x_null_ptr_copy.with_addr(x_ptr.addr()); // addr of x and provenance of x + assert_eq!(unsafe { *x_ptr_copy }, 42); +} + +fn main() { + ptr_roundtrip_out_of_bounds(); + ptr_roundtrip_confusion(); + ptr_roundtrip_imperfect(); + ptr_roundtrip_null(); +} From f8f2255a91f316da6c25906c7f1f9edb353b66ba Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 May 2022 09:03:06 +0200 Subject: [PATCH 3095/5092] readme: document permissive-provenance flag --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index abcfd3e6d050..235b81173b5f 100644 --- a/README.md +++ b/README.md @@ -318,6 +318,17 @@ to Miri failing to detect cases of undefined behavior in a program. application instead of raising an error within the context of Miri (and halting execution). Note that code might not expect these operations to ever panic, so this flag can lead to strange (mis)behavior. +* `-Zmiri-permissive-provenance` is **experimental**. This will make Miri do a + best-effort attempt to implement the semantics of + [`expose_addr`](https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.expose_addr) + and + [`ptr::from_exposed_addr`](https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html) + for pointer-to-int and int-to-pointer casts, respectively. This will + necessarily miss some bugs as those semantics are not efficiently + implementable in a sanitizer, but it will only miss bugs that concerns + memory/pointers which is subject to these operations. Also note that this flag + is currently incompatible with Stacked Borrows, so you will have to also pass + `-Zmiri-disable-stacked-borrows` to use this. * `-Zmiri-seed=` configures the seed of the RNG that Miri uses to resolve non-determinism. This RNG is used to pick base addresses for allocations. When isolation is enabled (the default), this is also used to emulate system From 697dca2e0e62ff7717f991dbcf3a6c6fd952f3a1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 May 2022 09:17:04 +0200 Subject: [PATCH 3096/5092] clean up int2ptr code a bit --- src/intptrcast.rs | 53 +++++++++++++++++++++++++++++++---------------- src/machine.rs | 28 ++++++++++++------------- 2 files changed, 49 insertions(+), 32 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 8395cdc2733d..4850945b4eeb 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -105,6 +105,8 @@ impl<'mir, 'tcx> GlobalStateInner { trace!("Exposing allocation id {:?}", alloc_id); let mut global_state = ecx.machine.intptrcast.borrow_mut(); + // In legacy and strict mode, we don't need this, so we can save some cycles + // by not tracking it. if global_state.provenance_mode == ProvenanceMode::Permissive { global_state.exposed.insert(alloc_id); } @@ -118,12 +120,17 @@ impl<'mir, 'tcx> GlobalStateInner { let global_state = ecx.machine.intptrcast.borrow(); - // In legacy mode, we have to support int2ptr transmutes, - // so just pretend they do the same thing as a cast. - if global_state.provenance_mode == ProvenanceMode::Legacy { - Self::ptr_from_addr_cast(ecx, addr) - } else { - Pointer::new(None, Size::from_bytes(addr)) + match global_state.provenance_mode { + ProvenanceMode::Legacy => { + // In legacy mode, we have to support int2ptr transmutes, + // so just pretend they do the same thing as a cast. + Self::ptr_from_addr_cast(ecx, addr) + } + ProvenanceMode::Permissive | ProvenanceMode::Strict => { + // Both of these modes consider transmuted pointers to be "invalid" (`None` + // provenance). + Pointer::new(None, Size::from_bytes(addr)) + } } } @@ -135,18 +142,26 @@ impl<'mir, 'tcx> GlobalStateInner { let global_state = ecx.machine.intptrcast.borrow(); - if global_state.provenance_mode == ProvenanceMode::Strict { - Pointer::new(None, Size::from_bytes(addr)) - } else if global_state.provenance_mode == ProvenanceMode::Legacy { - let alloc_id = Self::alloc_id_from_addr(ecx, addr); - - Pointer::new( - alloc_id - .map(|alloc_id| Tag::Concrete(ConcreteTag { alloc_id, sb: SbTag::Untagged })), - Size::from_bytes(addr), - ) - } else { - Pointer::new(Some(Tag::Wildcard), Size::from_bytes(addr)) + match global_state.provenance_mode { + ProvenanceMode::Legacy => { + // Determine the allocation this points to at cast time. + let alloc_id = Self::alloc_id_from_addr(ecx, addr); + Pointer::new( + alloc_id.map(|alloc_id| { + Tag::Concrete(ConcreteTag { alloc_id, sb: SbTag::Untagged }) + }), + Size::from_bytes(addr), + ) + } + ProvenanceMode::Strict => { + // We don't support int2ptr casts in this mode (i.e., we treat them like + // transmutes). + Pointer::new(None, Size::from_bytes(addr)) + } + ProvenanceMode::Permissive => { + // This is how wildcard pointers are born. + Pointer::new(Some(Tag::Wildcard), Size::from_bytes(addr)) + } } } @@ -215,6 +230,8 @@ impl<'mir, 'tcx> GlobalStateInner { let alloc_id = if let Tag::Concrete(concrete) = tag { concrete.alloc_id } else { + // A wildcard pointer. + assert_eq!(ecx.machine.intptrcast.borrow().provenance_mode, ProvenanceMode::Permissive); GlobalStateInner::alloc_id_from_addr(ecx, addr.bytes())? }; diff --git a/src/machine.rs b/src/machine.rs index 12a32d81b5c9..0972699e7288 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -652,19 +652,18 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { intptrcast::GlobalStateInner::ptr_from_addr_transmute(ecx, addr) } - #[inline(always)] fn expose_ptr( ecx: &mut InterpCx<'mir, 'tcx, Self>, ptr: Pointer, ) -> InterpResult<'tcx> { - let tag = ptr.provenance; - - if let Tag::Concrete(concrete) = tag { - intptrcast::GlobalStateInner::expose_addr(ecx, concrete.alloc_id); + match ptr.provenance { + Tag::Concrete(concrete) => + intptrcast::GlobalStateInner::expose_addr(ecx, concrete.alloc_id), + Tag::Wildcard => { + // No need to do anything for wildcard pointers as + // their provenances have already been previously exposed. + } } - - // No need to do anything for wildcard pointers as - // their provenances have already been previously exposed. Ok(()) } @@ -676,12 +675,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ) -> Option<(AllocId, Size, Self::TagExtra)> { let rel = intptrcast::GlobalStateInner::abs_ptr_to_rel(ecx, ptr); - let sb = match ptr.provenance { - Tag::Concrete(ConcreteTag { sb, .. }) => sb, - Tag::Wildcard => SbTag::Untagged, - }; - - rel.map(|(alloc_id, size)| (alloc_id, size, sb)) + rel.map(|(alloc_id, size)| { + let sb = match ptr.provenance { + Tag::Concrete(ConcreteTag { sb, .. }) => sb, + Tag::Wildcard => SbTag::Untagged, + }; + (alloc_id, size, sb) + }) } #[inline(always)] From a3a2a474cb85cebb487b148860bcbd88b4c7a735 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 May 2022 10:15:34 +0200 Subject: [PATCH 3097/5092] split flag section into common and advanced flags --- README.md | 72 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 235b81173b5f..876b2fcf972a 100644 --- a/README.md +++ b/README.md @@ -258,33 +258,12 @@ up the sysroot. If you are using `miri` (the Miri driver) directly, see the [miri-flags]: #miri--z-flags-and-environment-variables Miri adds its own set of `-Z` flags, which are usually set via the `MIRIFLAGS` -environment variable. Some of these are **unsound**, which means they can lead -to Miri failing to detect cases of undefined behavior in a program. +environment variable. We first document the most relevant and most commonly used flags: -* `-Zmiri-check-number-validity` enables checking of integer and float validity - (e.g., they must be initialized and not carry pointer provenance) as part of - enforcing validity invariants. This has no effect when - `-Zmiri-disable-validation` is present. * `-Zmiri-compare-exchange-weak-failure-rate=` changes the failure rate of `compare_exchange_weak` operations. The default is `0.8` (so 4 out of 5 weak ops will fail). You can change it to any value between `0.0` and `1.0`, where `1.0` means it will always fail and `0.0` means it will never fail. -* `-Zmiri-disable-abi-check` disables checking [function ABI]. Using this flag - is **unsound**. -* `-Zmiri-disable-alignment-check` disables checking pointer alignment, so you - can focus on other failures, but it means Miri can miss bugs in your program. - Using this flag is **unsound**. -* `-Zmiri-disable-data-race-detector` disables checking for data races. Using - this flag is **unsound**. -* `-Zmiri-disable-stacked-borrows` disables checking the experimental - [Stacked Borrows] aliasing rules. This can make Miri run faster, but it also - means no aliasing violations will be detected. Using this flag is **unsound** - (but the affected soundness rules are experimental). -* `-Zmiri-disable-validation` disables enforcing validity invariants, which are - enforced by default. This is mostly useful to focus on other failures (such - as out-of-bounds accesses) first. Setting this flag means Miri can miss bugs - in your program. However, this can also help to make Miri run faster. Using - this flag is **unsound**. * `-Zmiri-disable-isolation` disables host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness. @@ -305,6 +284,44 @@ to Miri failing to detect cases of undefined behavior in a program. `-Zmiri-disable-validation` is set. * `-Zmiri-ignore-leaks` disables the memory leak checker, and also allows some remaining threads to exist when the main thread exits. +* `-Zmiri-seed=` configures the seed of the RNG that Miri uses to resolve + non-determinism. This RNG is used to pick base addresses for allocations. When + isolation is enabled (the default), this is also used to emulate system + entropy. The default seed is 0. You can increase test coverage by running Miri + multiple times with different seeds. + **NOTE**: This entropy is not good enough for cryptographic use! Do not + generate secret keys in Miri or perform other kinds of cryptographic + operations that rely on proper random numbers. +* `-Zmiri-strict-provenance` enables [strict + provenance](https://github.com/rust-lang/rust/issues/95228) checking in Miri. This means that + casting an integer to a pointer yields a result with 'invalid' provenance, i.e., with provenance + that cannot be used for any memory access. Also implies `-Zmiri-tag-raw-pointers` and + `-Zmiri-check-number-validity`. + +The remaining flags are for advanced use only, and more likely to change or be removed. +Some of these are **unsound**, which means they can lead +to Miri failing to detect cases of undefined behavior in a program. + +* `-Zmiri-check-number-validity` enables checking of integer and float validity + (e.g., they must be initialized and not carry pointer provenance) as part of + enforcing validity invariants. This has no effect when + `-Zmiri-disable-validation` is present. +* `-Zmiri-disable-abi-check` disables checking [function ABI]. Using this flag + is **unsound**. +* `-Zmiri-disable-alignment-check` disables checking pointer alignment, so you + can focus on other failures, but it means Miri can miss bugs in your program. + Using this flag is **unsound**. +* `-Zmiri-disable-data-race-detector` disables checking for data races. Using + this flag is **unsound**. +* `-Zmiri-disable-stacked-borrows` disables checking the experimental + [Stacked Borrows] aliasing rules. This can make Miri run faster, but it also + means no aliasing violations will be detected. Using this flag is **unsound** + (but the affected soundness rules are experimental). +* `-Zmiri-disable-validation` disables enforcing validity invariants, which are + enforced by default. This is mostly useful to focus on other failures (such + as out-of-bounds accesses) first. Setting this flag means Miri can miss bugs + in your program. However, this can also help to make Miri run faster. Using + this flag is **unsound**. * `-Zmiri-measureme=` enables `measureme` profiling for the interpreted program. This can be used to find which parts of your program are executing slowly under Miri. The profile is written out to a file with the prefix ``, and can be processed @@ -329,17 +346,6 @@ to Miri failing to detect cases of undefined behavior in a program. memory/pointers which is subject to these operations. Also note that this flag is currently incompatible with Stacked Borrows, so you will have to also pass `-Zmiri-disable-stacked-borrows` to use this. -* `-Zmiri-seed=` configures the seed of the RNG that Miri uses to resolve - non-determinism. This RNG is used to pick base addresses for allocations. - When isolation is enabled (the default), this is also used to emulate system - entropy. The default seed is 0. **NOTE**: This entropy is not good enough - for cryptographic use! Do not generate secret keys in Miri or perform other - kinds of cryptographic operations that rely on proper random numbers. -* `-Zmiri-strict-provenance` enables [strict - provenance](https://github.com/rust-lang/rust/issues/95228) checking in Miri. This means that - casting an integer to a pointer yields a result with 'invalid' provenance, i.e., with provenance - that cannot be used for any memory access. Also implies `-Zmiri-tag-raw-pointers` and - `-Zmiri-check-number-validity`. * `-Zmiri-symbolic-alignment-check` makes the alignment check more strict. By default, alignment is checked by casting the pointer to an integer, and making sure that is a multiple of the alignment. This can lead to cases where a From 5ed22b32a21101b3e4b33684e5e895e3bd441a5e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 May 2022 10:28:46 +0200 Subject: [PATCH 3098/5092] test that compare-exchange-weak-failure-rate=0.0 means what it says --- .../atomic-compare-exchange-weak-never-fail.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tests/run-pass/atomic-compare-exchange-weak-never-fail.rs diff --git a/tests/run-pass/atomic-compare-exchange-weak-never-fail.rs b/tests/run-pass/atomic-compare-exchange-weak-never-fail.rs new file mode 100644 index 000000000000..2c2d4e61d9f5 --- /dev/null +++ b/tests/run-pass/atomic-compare-exchange-weak-never-fail.rs @@ -0,0 +1,17 @@ +// compile-flags: -Zmiri-compare-exchange-weak-failure-rate=0.0 +use std::sync::atomic::{AtomicBool, Ordering::*}; + +// Ensure that compare_exchange_weak never fails. +fn main() { + let atomic = AtomicBool::new(false); + let tries = 100; + for _ in 0..tries { + let cur = atomic.load(Relaxed); + // Try (weakly) to flip the flag. + if atomic.compare_exchange_weak(cur, !cur, Relaxed, Relaxed).is_err() { + // We failed. Avoid panic machinery as that uses atomics/locks. + eprintln!("compare_exchange_weak failed"); + std::process::abort(); + } + } +} From 4d9eafe19a1e63b76fc7f04c4194e05133e27668 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 May 2022 11:24:08 +0200 Subject: [PATCH 3099/5092] fix some old typos --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 876b2fcf972a..0f6c5007ba6c 100644 --- a/README.md +++ b/README.md @@ -278,10 +278,10 @@ environment variable. We first document the most relevant and most commonly used cannot be accessed by the program. Can be used multiple times to exclude several variables. The `TERM` environment variable is excluded by default to [speed up the test harness](https://github.com/rust-lang/miri/issues/1702). This has no effect unless - `-Zmiri-disable-validation` is also set. + `-Zmiri-disable-isolation` is also set. * `-Zmiri-env-forward=` forwards the `var` environment variable to the interpreted program. Can be used multiple times to forward several variables. This has no effect if - `-Zmiri-disable-validation` is set. + `-Zmiri-disable-isolation` is set. * `-Zmiri-ignore-leaks` disables the memory leak checker, and also allows some remaining threads to exist when the main thread exits. * `-Zmiri-seed=` configures the seed of the RNG that Miri uses to resolve From 6e7a8c017abaea2d3dacf21b50d27c33f7e8bfde Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 May 2022 11:27:20 +0200 Subject: [PATCH 3100/5092] move some compile-fail tests to a more appropriate location --- tests/compile-fail/{ => validity}/ptr_integer_transmute.rs | 0 tests/compile-fail/{ => validity}/uninit_float.rs | 0 tests/compile-fail/{ => validity}/uninit_integer.rs | 0 tests/compile-fail/{ => validity}/uninit_integer_signed.rs | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename tests/compile-fail/{ => validity}/ptr_integer_transmute.rs (100%) rename tests/compile-fail/{ => validity}/uninit_float.rs (100%) rename tests/compile-fail/{ => validity}/uninit_integer.rs (100%) rename tests/compile-fail/{ => validity}/uninit_integer_signed.rs (100%) diff --git a/tests/compile-fail/ptr_integer_transmute.rs b/tests/compile-fail/validity/ptr_integer_transmute.rs similarity index 100% rename from tests/compile-fail/ptr_integer_transmute.rs rename to tests/compile-fail/validity/ptr_integer_transmute.rs diff --git a/tests/compile-fail/uninit_float.rs b/tests/compile-fail/validity/uninit_float.rs similarity index 100% rename from tests/compile-fail/uninit_float.rs rename to tests/compile-fail/validity/uninit_float.rs diff --git a/tests/compile-fail/uninit_integer.rs b/tests/compile-fail/validity/uninit_integer.rs similarity index 100% rename from tests/compile-fail/uninit_integer.rs rename to tests/compile-fail/validity/uninit_integer.rs diff --git a/tests/compile-fail/uninit_integer_signed.rs b/tests/compile-fail/validity/uninit_integer_signed.rs similarity index 100% rename from tests/compile-fail/uninit_integer_signed.rs rename to tests/compile-fail/validity/uninit_integer_signed.rs From 42d5e5bf96327970810c018af59eff65554fc53a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 May 2022 12:19:42 +0200 Subject: [PATCH 3101/5092] move some tests to more suitable locations --- tests/compile-fail/{ => dangling_pointers}/null_pointer_deref.rs | 0 .../{ => dangling_pointers}/null_pointer_deref_zst.rs | 0 tests/compile-fail/{ => dangling_pointers}/null_pointer_write.rs | 0 .../{ => dangling_pointers}/null_pointer_write_zst.rs | 0 tests/compile-fail/{ => provenance}/ptr_int_unexposed.rs | 0 tests/compile-fail/{ => provenance}/ptr_legacy_provenance.rs | 0 tests/compile-fail/{ => provenance}/strict-provenance-offset.rs | 0 .../compile-fail/{ => provenance}/strict_provenance_transmute.rs | 0 tests/compile-fail/{ => validity}/ptr_integer_array_transmute.rs | 0 tests/compile-fail/{ => validity}/too-big-slice.rs | 0 tests/compile-fail/{ => validity}/too-big-unsized.rs | 0 11 files changed, 0 insertions(+), 0 deletions(-) rename tests/compile-fail/{ => dangling_pointers}/null_pointer_deref.rs (100%) rename tests/compile-fail/{ => dangling_pointers}/null_pointer_deref_zst.rs (100%) rename tests/compile-fail/{ => dangling_pointers}/null_pointer_write.rs (100%) rename tests/compile-fail/{ => dangling_pointers}/null_pointer_write_zst.rs (100%) rename tests/compile-fail/{ => provenance}/ptr_int_unexposed.rs (100%) rename tests/compile-fail/{ => provenance}/ptr_legacy_provenance.rs (100%) rename tests/compile-fail/{ => provenance}/strict-provenance-offset.rs (100%) rename tests/compile-fail/{ => provenance}/strict_provenance_transmute.rs (100%) rename tests/compile-fail/{ => validity}/ptr_integer_array_transmute.rs (100%) rename tests/compile-fail/{ => validity}/too-big-slice.rs (100%) rename tests/compile-fail/{ => validity}/too-big-unsized.rs (100%) diff --git a/tests/compile-fail/null_pointer_deref.rs b/tests/compile-fail/dangling_pointers/null_pointer_deref.rs similarity index 100% rename from tests/compile-fail/null_pointer_deref.rs rename to tests/compile-fail/dangling_pointers/null_pointer_deref.rs diff --git a/tests/compile-fail/null_pointer_deref_zst.rs b/tests/compile-fail/dangling_pointers/null_pointer_deref_zst.rs similarity index 100% rename from tests/compile-fail/null_pointer_deref_zst.rs rename to tests/compile-fail/dangling_pointers/null_pointer_deref_zst.rs diff --git a/tests/compile-fail/null_pointer_write.rs b/tests/compile-fail/dangling_pointers/null_pointer_write.rs similarity index 100% rename from tests/compile-fail/null_pointer_write.rs rename to tests/compile-fail/dangling_pointers/null_pointer_write.rs diff --git a/tests/compile-fail/null_pointer_write_zst.rs b/tests/compile-fail/dangling_pointers/null_pointer_write_zst.rs similarity index 100% rename from tests/compile-fail/null_pointer_write_zst.rs rename to tests/compile-fail/dangling_pointers/null_pointer_write_zst.rs diff --git a/tests/compile-fail/ptr_int_unexposed.rs b/tests/compile-fail/provenance/ptr_int_unexposed.rs similarity index 100% rename from tests/compile-fail/ptr_int_unexposed.rs rename to tests/compile-fail/provenance/ptr_int_unexposed.rs diff --git a/tests/compile-fail/ptr_legacy_provenance.rs b/tests/compile-fail/provenance/ptr_legacy_provenance.rs similarity index 100% rename from tests/compile-fail/ptr_legacy_provenance.rs rename to tests/compile-fail/provenance/ptr_legacy_provenance.rs diff --git a/tests/compile-fail/strict-provenance-offset.rs b/tests/compile-fail/provenance/strict-provenance-offset.rs similarity index 100% rename from tests/compile-fail/strict-provenance-offset.rs rename to tests/compile-fail/provenance/strict-provenance-offset.rs diff --git a/tests/compile-fail/strict_provenance_transmute.rs b/tests/compile-fail/provenance/strict_provenance_transmute.rs similarity index 100% rename from tests/compile-fail/strict_provenance_transmute.rs rename to tests/compile-fail/provenance/strict_provenance_transmute.rs diff --git a/tests/compile-fail/ptr_integer_array_transmute.rs b/tests/compile-fail/validity/ptr_integer_array_transmute.rs similarity index 100% rename from tests/compile-fail/ptr_integer_array_transmute.rs rename to tests/compile-fail/validity/ptr_integer_array_transmute.rs diff --git a/tests/compile-fail/too-big-slice.rs b/tests/compile-fail/validity/too-big-slice.rs similarity index 100% rename from tests/compile-fail/too-big-slice.rs rename to tests/compile-fail/validity/too-big-slice.rs diff --git a/tests/compile-fail/too-big-unsized.rs b/tests/compile-fail/validity/too-big-unsized.rs similarity index 100% rename from tests/compile-fail/too-big-unsized.rs rename to tests/compile-fail/validity/too-big-unsized.rs From 460a0137ccb41e242b221332232e6a21cdcd7606 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 May 2022 12:37:48 +0200 Subject: [PATCH 3102/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 5526a13d5fc7..b3496efafdd2 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -22ee39504a702f75485582d02060495a01254de1 +9e2f65586366b731f13a10021c5191a664f4adc2 From f0921bd5dc0de7dddebdd9a08d3636473ae980cf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 May 2022 17:35:36 +0200 Subject: [PATCH 3103/5092] rustup --- rust-version | 2 +- tests/run-pass/concurrency/sync.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index b3496efafdd2..983b23fe2288 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9e2f65586366b731f13a10021c5191a664f4adc2 +32c8c5df06c025441ad04791d7982d65c79a60e4 diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index 303d49e3c33f..6889aad91cf2 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -91,7 +91,7 @@ fn check_conditional_variables_timed_wait_timeout() { let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap(); assert!(timeout.timed_out()); let elapsed_time = now.elapsed().as_millis(); - assert!(100 <= elapsed_time && elapsed_time <= 800); + assert!(100 <= elapsed_time && elapsed_time <= 1000); } /// Test that signaling a conditional variable when waiting with a timeout works From 168c83a0b78588ecbe30d0adf7d7d794f62e4312 Mon Sep 17 00:00:00 2001 From: Jakob Degen Date: Fri, 20 May 2022 23:08:32 -0400 Subject: [PATCH 3104/5092] Adjust Miri to also require return places everywhere --- src/diagnostics.rs | 2 +- src/eval.rs | 4 ++-- src/helpers.rs | 2 +- src/machine.rs | 15 +++++++++------ src/shims/dlsym.rs | 8 +++++--- src/shims/foreign_items.rs | 5 +++-- src/shims/intrinsics.rs | 7 ++++--- src/shims/mod.rs | 14 ++++++++------ src/shims/panic.rs | 8 ++++---- src/shims/posix/dlsym.rs | 7 ++++--- src/shims/posix/linux/dlsym.rs | 5 +++-- src/shims/posix/macos/dlsym.rs | 5 +++-- src/shims/posix/thread.rs | 2 +- src/shims/tls.rs | 6 +++--- src/shims/windows/dlsym.rs | 5 +++-- src/stacked_borrows.rs | 9 ++------- 16 files changed, 56 insertions(+), 48 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 8afcf851ba4e..527ff032d670 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -275,7 +275,7 @@ pub fn report_error<'tcx, 'mir>( for (i, frame) in ecx.active_thread_stack().iter().enumerate() { trace!("-------------------"); trace!("Frame {}", i); - trace!(" return: {:?}", frame.return_place.map(|p| *p)); + trace!(" return: {:?}", *frame.return_place); for (i, local) in frame.locals.iter().enumerate() { trace!(" local {}: {:?}", i, local.value); } diff --git a/src/eval.rs b/src/eval.rs index 430ff06cf15a..badda8f3bc39 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -277,7 +277,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( start_instance, Abi::Rust, &[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv], - Some(&ret_place.into()), + &ret_place.into(), StackPopCleanup::Root { cleanup: true }, )?; } @@ -286,7 +286,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( entry_instance, Abi::Rust, &[argc.into(), argv], - Some(&ret_place.into()), + &ret_place.into(), StackPopCleanup::Root { cleanup: true }, )?; } diff --git a/src/helpers.rs b/src/helpers.rs index 08b2fa98a230..24c471a8b0ba 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -240,7 +240,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx f: ty::Instance<'tcx>, caller_abi: Abi, args: &[Immediate], - dest: Option<&PlaceTy<'tcx, Tag>>, + dest: &PlaceTy<'tcx, Tag>, stack_pop: StackPopCleanup, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/machine.rs b/src/machine.rs index 0972699e7288..c5c884e8d7a0 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -512,10 +512,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { instance: ty::Instance<'tcx>, abi: Abi, args: &[OpTy<'tcx, Tag>], - ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + dest: &PlaceTy<'tcx, Tag>, + ret: Option, unwind: StackPopUnwind, ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { - ecx.find_mir_or_eval_fn(instance, abi, args, ret, unwind) + ecx.find_mir_or_eval_fn(instance, abi, args, dest, ret, unwind) } #[inline(always)] @@ -524,10 +525,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn_val: Dlsym, abi: Abi, args: &[OpTy<'tcx, Tag>], - ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + dest: &PlaceTy<'tcx, Tag>, + ret: Option, _unwind: StackPopUnwind, ) -> InterpResult<'tcx> { - ecx.call_dlsym(fn_val, abi, args, ret) + ecx.call_dlsym(fn_val, abi, args, dest, ret) } #[inline(always)] @@ -535,10 +537,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx: &mut MiriEvalContext<'mir, 'tcx>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], - ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + dest: &PlaceTy<'tcx, Tag>, + ret: Option, unwind: StackPopUnwind, ) -> InterpResult<'tcx> { - ecx.call_intrinsic(instance, args, ret, unwind) + ecx.call_intrinsic(instance, args, dest, ret, unwind) } #[inline(always)] diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 1855d65d6c50..d83a309c3e1f 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -32,13 +32,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dlsym: Dlsym, abi: Abi, args: &[OpTy<'tcx, Tag>], - ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + dest: &PlaceTy<'tcx, Tag>, + ret: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); match dlsym { - Dlsym::Posix(dlsym) => posix::EvalContextExt::call_dlsym(this, dlsym, abi, args, ret), + Dlsym::Posix(dlsym) => + posix::EvalContextExt::call_dlsym(this, dlsym, abi, args, dest, ret), Dlsym::Windows(dlsym) => - windows::EvalContextExt::call_dlsym(this, dlsym, abi, args, ret), + windows::EvalContextExt::call_dlsym(this, dlsym, abi, args, dest, ret), } } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 44bf4ba7e369..e978391801f1 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -232,7 +232,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx def_id: DefId, abi: Abi, args: &[OpTy<'tcx, Tag>], - ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + dest: &PlaceTy<'tcx, Tag>, + ret: Option, unwind: StackPopUnwind, ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { let this = self.eval_context_mut(); @@ -240,7 +241,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tcx = this.tcx.tcx; // First: functions that diverge. - let (dest, ret) = match ret { + let ret = match ret { None => match &*link_name.as_str() { "miri_start_panic" => { diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index a6f818c493e6..1f06971a3e70 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -22,19 +22,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], - ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + dest: &PlaceTy<'tcx, Tag>, + ret: Option, _unwind: StackPopUnwind, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - if this.emulate_intrinsic(instance, args, ret)? { + if this.emulate_intrinsic(instance, args, dest, ret)? { return Ok(()); } // All supported intrinsics have a return place. let intrinsic_name = this.tcx.item_name(instance.def_id()); let intrinsic_name = intrinsic_name.as_str(); - let (dest, ret) = match ret { + let ret = match ret { None => throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name), Some(p) => p, }; diff --git a/src/shims/mod.rs b/src/shims/mod.rs index f003552434fe..926fcd5d040b 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -28,16 +28,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx instance: ty::Instance<'tcx>, abi: Abi, args: &[OpTy<'tcx, Tag>], - ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + dest: &PlaceTy<'tcx, Tag>, + ret: Option, unwind: StackPopUnwind, ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { let this = self.eval_context_mut(); - trace!("eval_fn_call: {:#?}, {:?}", instance, ret.map(|p| p.0)); + trace!("eval_fn_call: {:#?}, {:?}", instance, dest); // There are some more lang items we want to hook that CTFE does not hook (yet). if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { let [ptr, align] = check_arg_count(args)?; - if this.align_offset(ptr, align, ret, unwind)? { + if this.align_offset(ptr, align, dest, ret, unwind)? { return Ok(None); } } @@ -50,7 +51,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // to run extra MIR), and Ok(Some(body)) if we found MIR to run for the // foreign function // Any needed call to `goto_block` will be performed by `emulate_foreign_item`. - return this.emulate_foreign_item(instance.def_id(), abi, args, ret, unwind); + return this.emulate_foreign_item(instance.def_id(), abi, args, dest, ret, unwind); } // Otherwise, load the MIR. @@ -63,11 +64,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, ptr_op: &OpTy<'tcx, Tag>, align_op: &OpTy<'tcx, Tag>, - ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + dest: &PlaceTy<'tcx, Tag>, + ret: Option, unwind: StackPopUnwind, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - let (dest, ret) = ret.unwrap(); + let ret = ret.unwrap(); if this.machine.check_alignment != AlignmentCheck::Symbolic { // Just use actual implementation. diff --git a/src/shims/panic.rs b/src/shims/panic.rs index f92e39048bc8..ed6e72591dd0 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -96,7 +96,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx f_instance, Abi::Rust, &[data.into()], - Some(&ret_place), + &ret_place, // Directly return to caller. StackPopCleanup::Goto { ret: Some(ret), unwind: StackPopUnwind::Skip }, )?; @@ -153,7 +153,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx f_instance, Abi::Rust, &[catch_unwind.data.into(), payload.into()], - Some(&ret_place), + &ret_place, // Directly return to caller of `try`. StackPopCleanup::Goto { ret: Some(catch_unwind.ret), unwind: StackPopUnwind::Skip }, )?; @@ -179,7 +179,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx panic, Abi::Rust, &[msg.to_ref(this)], - None, + &MPlaceTy::dangling(this.machine.layouts.unit).into(), StackPopCleanup::Goto { ret: None, unwind }, ) } @@ -208,7 +208,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx panic_bounds_check, Abi::Rust, &[index.into(), len.into()], - None, + &MPlaceTy::dangling(this.machine.layouts.unit).into(), StackPopCleanup::Goto { ret: None, unwind: match unwind { diff --git a/src/shims/posix/dlsym.rs b/src/shims/posix/dlsym.rs index b07bf91a69a5..0ea441e00e9a 100644 --- a/src/shims/posix/dlsym.rs +++ b/src/shims/posix/dlsym.rs @@ -30,15 +30,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dlsym: Dlsym, abi: Abi, args: &[OpTy<'tcx, Tag>], - ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + dest: &PlaceTy<'tcx, Tag>, + ret: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.check_abi(abi, Abi::C { unwind: false })?; match dlsym { - Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, ret), - Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, args, ret), + Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), + Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), } } } diff --git a/src/shims/posix/linux/dlsym.rs b/src/shims/posix/linux/dlsym.rs index 1b7ac2754af7..a2d6570fe8d6 100644 --- a/src/shims/posix/linux/dlsym.rs +++ b/src/shims/posix/linux/dlsym.rs @@ -24,10 +24,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, dlsym: Dlsym, _args: &[OpTy<'tcx, Tag>], - ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + _dest: &PlaceTy<'tcx, Tag>, + ret: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let (_dest, _ret) = ret.expect("we don't support any diverging dlsym"); + let _ret = ret.expect("we don't support any diverging dlsym"); assert!(this.tcx.sess.target.os == "linux"); match dlsym {} diff --git a/src/shims/posix/macos/dlsym.rs b/src/shims/posix/macos/dlsym.rs index 8ce56d35da65..9369548992e5 100644 --- a/src/shims/posix/macos/dlsym.rs +++ b/src/shims/posix/macos/dlsym.rs @@ -28,10 +28,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, dlsym: Dlsym, args: &[OpTy<'tcx, Tag>], - ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + dest: &PlaceTy<'tcx, Tag>, + ret: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let (dest, ret) = ret.expect("we don't support any diverging dlsym"); + let ret = ret.expect("we don't support any diverging dlsym"); assert!(this.tcx.sess.target.os == "macos"); match dlsym { diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index 0b8684d39eb2..88c3fb0bc8ea 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -51,7 +51,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx instance, Abi::C { unwind: false }, &[*func_arg], - Some(&ret_place.into()), + &ret_place.into(), StackPopCleanup::Root { cleanup: true }, )?; diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 3de739a8d048..87c8d7eadc3b 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -258,7 +258,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx thread_callback, Abi::System { unwind: false }, &[Scalar::null_ptr(this).into(), reason.into(), Scalar::null_ptr(this).into()], - Some(&ret_place), + &ret_place, StackPopCleanup::Root { cleanup: true }, )?; @@ -281,7 +281,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx instance, Abi::C { unwind: false }, &[data.into()], - Some(&ret_place), + &ret_place, StackPopCleanup::Root { cleanup: true }, )?; @@ -324,7 +324,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx instance, Abi::C { unwind: false }, &[ptr.into()], - Some(&ret_place), + &ret_place, StackPopCleanup::Root { cleanup: true }, )?; diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 865c01386045..b5408e492ce9 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -31,10 +31,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dlsym: Dlsym, abi: Abi, args: &[OpTy<'tcx, Tag>], - ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + dest: &PlaceTy<'tcx, Tag>, + ret: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let (dest, ret) = ret.expect("we don't support any diverging dlsym"); + let ret = ret.expect("we don't support any diverging dlsym"); assert!(this.tcx.sess.target.os == "windows"); this.check_abi(abi, Abi::System { unwind: false })?; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index f137b861342a..30a9cc265dce 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -930,12 +930,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// explicit. Also see https://github.com/rust-lang/rust/issues/71117. fn retag_return_place(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let return_place = if let Some(return_place) = this.frame_mut().return_place { - return_place - } else { - // No return place, nothing to do. - return Ok(()); - }; + let return_place = this.frame_mut().return_place; if return_place.layout.is_zst() { // There may not be any memory here, nothing to do. return Ok(()); @@ -955,7 +950,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; // And use reborrowed pointer for return place. let return_place = this.ref_to_mplace(&val)?; - this.frame_mut().return_place = Some(return_place.into()); + this.frame_mut().return_place = return_place.into(); Ok(()) } From e428d29d93423fd68991bbc7bce68a991ea743e9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 24 May 2022 17:16:03 +0200 Subject: [PATCH 3105/5092] rustp --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 983b23fe2288..f4df767fc22f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -32c8c5df06c025441ad04791d7982d65c79a60e4 +b2eba058e6e1c698723e47074561a30b50b5fa7a From fcf3bc2335331e7c79e7e7ae78265e2db4637748 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 24 May 2022 17:49:11 +0200 Subject: [PATCH 3106/5092] with permissive-provenance set, we already treat ptr::invalid correctly --- tests/compile-fail/provenance/ptr_invalid.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 tests/compile-fail/provenance/ptr_invalid.rs diff --git a/tests/compile-fail/provenance/ptr_invalid.rs b/tests/compile-fail/provenance/ptr_invalid.rs new file mode 100644 index 000000000000..b371103e6b66 --- /dev/null +++ b/tests/compile-fail/provenance/ptr_invalid.rs @@ -0,0 +1,10 @@ +// compile-flags: -Zmiri-permissive-provenance +#![feature(strict_provenance)] + +// Ensure that a `ptr::invalid` ptr is truly invalid. +fn main() { + let x = 42; + let xptr = &x as *const i32; + let xptr_invalid = std::ptr::invalid::(xptr.expose_addr()); + let _val = unsafe { *xptr_invalid }; //~ ERROR is not a valid pointer +} From f1756c3ddd06f8d82fa20fb9d738708f84382a33 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 17 Mar 2022 13:49:10 +0000 Subject: [PATCH 3107/5092] Add a custom ui test runner and move all tests to it --- CONTRIBUTING.md | 20 +- Cargo.lock | 341 ++++++--------- Cargo.toml | 5 +- README.md | 17 +- cargo-miri/bin.rs | 7 +- ci.sh | 3 +- miri | 7 +- src/machine.rs | 6 +- tests/compile-fail/abort-terminator.stderr | 19 + .../alloc/deallocate-bad-alignment.stderr | 16 + .../alloc/deallocate-bad-size.stderr | 16 + .../alloc/deallocate-twice.stderr | 16 + .../compile-fail/alloc/global_system_mixup.rs | 2 + .../alloc/global_system_mixup.stderr | 17 + .../alloc/no_global_allocator.stderr | 12 + .../alloc/reallocate-bad-size.stderr | 16 + .../alloc/reallocate-change-alloc.stderr | 15 + .../alloc/reallocate-dangling.stderr | 16 + tests/compile-fail/alloc/stack_free.stderr | 20 + .../backtrace/bad-backtrace-decl.stderr | 15 + .../backtrace/bad-backtrace-flags.stderr | 14 + .../backtrace/bad-backtrace-ptr.stderr | 15 + .../bad-backtrace-resolve-flags.stderr | 14 + .../bad-backtrace-resolve-names-flags.stderr | 14 + .../backtrace/bad-backtrace-size-flags.stderr | 14 + .../backtrace/bad-backtrace-version.stderr | 14 + tests/compile-fail/box-cell-alias.stderr | 32 ++ .../branchless-select-i128-pointer.stderr | 15 + tests/compile-fail/breakpoint.stderr | 12 + .../libc_pthread_create_main_terminate.stderr | 8 + .../libc_pthread_join_detached.stderr | 17 + .../libc_pthread_join_joined.stderr | 17 + .../concurrency/libc_pthread_join_main.stderr | 17 + .../libc_pthread_join_multiple.stderr | 17 + .../concurrency/libc_pthread_join_self.stderr | 17 + .../compile-fail/concurrency/thread-spawn.rs | 3 +- .../thread_local_static_dealloc.stderr | 17 + .../concurrency/too_few_args.stderr | 16 + .../concurrency/too_many_args.stderr | 16 + .../concurrency/unwind_top_of_stack.stderr | 19 + .../dangling_pointer_addr_of.stderr | 16 + .../dangling_pointer_deref.stderr | 15 + .../dangling_zst_deref.stderr | 15 + .../dangling_pointers/deref-invalid-ptr.rs | 2 +- .../deref-invalid-ptr.stderr | 15 + .../deref-partially-dangling.stderr | 15 + .../dangling_pointers/dyn_size.stderr | 15 + .../maybe_null_pointer_deref_zst.stderr | 15 + .../maybe_null_pointer_write_zst.stderr | 15 + .../null_pointer_deref.stderr | 15 + .../null_pointer_deref_zst.stderr | 15 + .../null_pointer_write.stderr | 15 + .../null_pointer_write_zst.stderr | 17 + .../out_of_bounds_read1.stderr | 15 + .../out_of_bounds_read2.stderr | 15 + .../dangling_pointers/stack_temporary.stderr | 15 + .../storage_dead_dangling.stderr | 20 + .../dangling_pointers/wild_pointer_deref.rs | 2 +- .../wild_pointer_deref.stderr | 15 + .../data_race/alloc_read_race.stderr | 17 + .../data_race/alloc_write_race.stderr | 17 + .../atomic_read_na_write_race1.stderr | 17 + .../atomic_read_na_write_race2.stderr | 17 + .../atomic_write_na_read_race1.stderr | 17 + .../atomic_write_na_read_race2.stderr | 17 + .../atomic_write_na_write_race1.stderr | 17 + .../atomic_write_na_write_race2.stderr | 17 + .../dangling_thread_async_race.stderr | 17 + .../data_race/dangling_thread_race.stderr | 17 + .../data_race/dealloc_read_race1.stderr | 17 + .../data_race/dealloc_read_race2.stderr | 17 + .../data_race/dealloc_read_race_stack.stderr | 17 + .../data_race/dealloc_write_race1.stderr | 17 + .../data_race/dealloc_write_race2.stderr | 17 + .../data_race/dealloc_write_race_stack.stderr | 17 + .../enable_after_join_to_main.stderr | 17 + .../data_race/read_write_race.stderr | 17 + .../data_race/read_write_race_stack.stderr | 17 + .../data_race/relax_acquire_race.stderr | 17 + .../data_race/release_seq_race.stderr | 17 + .../release_seq_race_same_thread.stderr | 17 + tests/compile-fail/data_race/rmw_race.stderr | 17 + .../data_race/write_write_race.stderr | 17 + .../data_race/write_write_race_stack.stderr | 17 + .../environ-gets-deallocated.stderr | 15 + tests/compile-fail/erroneous_const.stderr | 26 ++ tests/compile-fail/erroneous_const2.stderr | 41 ++ tests/compile-fail/extern_static.stderr | 14 + tests/compile-fail/fast_math_both.stderr | 15 + tests/compile-fail/fast_math_first.stderr | 15 + tests/compile-fail/fast_math_second.stderr | 15 + tests/compile-fail/fs/close_stdout.stderr | 14 + tests/compile-fail/fs/isolated_file.stderr | 22 + tests/compile-fail/fs/isolated_stdin.stderr | 15 + tests/compile-fail/fs/read_from_stdout.stderr | 14 + .../fs/unix_open_missing_required_mode.stderr | 20 + .../fs/unix_open_too_many_args.stderr | 20 + tests/compile-fail/fs/write_to_stdin.stderr | 14 + .../function_calls/check_arg_abi.stderr | 15 + .../check_arg_count_abort.stderr | 15 + .../check_arg_count_too_few_args.stderr | 15 + .../check_arg_count_too_many_args.stderr | 15 + .../function_calls/check_callback_abi.stderr | 19 + .../exported_symbol_abi_mismatch.cache.stderr | 15 + ...exported_symbol_abi_mismatch.fn_ptr.stderr | 15 + ...ported_symbol_abi_mismatch.no_cache.stderr | 15 + .../exported_symbol_bad_unwind1.stderr | 17 + .../exported_symbol_bad_unwind2.both.stderr | 23 + ...orted_symbol_bad_unwind2.definition.stderr | 23 + ...ted_symbol_bad_unwind2.extern_block.stderr | 17 + .../exported_symbol_clashing.stderr | 22 + .../exported_symbol_shim_clashing.stderr | 20 + .../exported_symbol_wrong_arguments.stderr | 15 + .../exported_symbol_wrong_type.stderr | 15 + .../cast_box_int_to_fn_ptr.stderr | 15 + .../function_pointers/cast_fn_ptr1.stderr | 15 + .../function_pointers/cast_fn_ptr2.stderr | 15 + .../function_pointers/cast_fn_ptr3.stderr | 15 + .../function_pointers/cast_fn_ptr4.stderr | 15 + .../function_pointers/cast_fn_ptr5.stderr | 15 + .../function_pointers/cast_int_to_fn_ptr.rs | 2 +- .../cast_int_to_fn_ptr.stderr | 15 + .../function_pointers/deref_fn_ptr.stderr | 15 + .../function_pointers/execute_memory.stderr | 15 + .../function_pointers/fn_ptr_offset.stderr | 15 + .../generator-pinned-moved.stderr | 26 ++ tests/compile-fail/intrinsics/assume.stderr | 15 + .../compile-fail/intrinsics/copy_null.stderr | 15 + .../intrinsics/copy_overflow.stderr | 17 + .../intrinsics/copy_overlapping.stderr | 15 + .../compile-fail/intrinsics/copy_unaligned.rs | 2 +- .../intrinsics/copy_unaligned.stderr | 15 + .../intrinsics/ctlz_nonzero.stderr | 15 + .../intrinsics/cttz_nonzero.stderr | 15 + .../intrinsics/div-by-zero.stderr | 15 + .../compile-fail/intrinsics/exact_div1.stderr | 15 + .../compile-fail/intrinsics/exact_div2.stderr | 15 + .../compile-fail/intrinsics/exact_div3.stderr | 15 + .../compile-fail/intrinsics/exact_div4.stderr | 15 + .../intrinsics/float_to_int_32_inf1.stderr | 15 + .../intrinsics/float_to_int_32_infneg1.stderr | 15 + .../intrinsics/float_to_int_32_nan.stderr | 15 + .../intrinsics/float_to_int_32_nanneg.stderr | 15 + .../intrinsics/float_to_int_32_neg.stderr | 15 + .../float_to_int_32_too_big1.stderr | 15 + .../float_to_int_32_too_big2.stderr | 15 + .../float_to_int_32_too_small1.stderr | 15 + .../intrinsics/float_to_int_64_inf1.stderr | 15 + .../intrinsics/float_to_int_64_infneg1.stderr | 15 + .../intrinsics/float_to_int_64_infneg2.stderr | 15 + .../intrinsics/float_to_int_64_nan.stderr | 15 + .../intrinsics/float_to_int_64_neg.stderr | 15 + .../float_to_int_64_too_big1.stderr | 15 + .../float_to_int_64_too_big2.stderr | 15 + .../float_to_int_64_too_big3.stderr | 15 + .../float_to_int_64_too_big4.stderr | 15 + .../float_to_int_64_too_big5.stderr | 15 + .../float_to_int_64_too_big6.stderr | 15 + .../float_to_int_64_too_big7.stderr | 15 + .../float_to_int_64_too_small1.stderr | 15 + .../float_to_int_64_too_small2.stderr | 15 + .../float_to_int_64_too_small3.stderr | 15 + .../intrinsics/out_of_bounds_ptr_1.stderr | 16 + .../intrinsics/out_of_bounds_ptr_2.stderr | 16 + .../intrinsics/out_of_bounds_ptr_3.stderr | 16 + .../intrinsics/overflowing-unchecked-rsh.rs | 2 +- .../overflowing-unchecked-rsh.stderr | 15 + .../intrinsics/ptr_offset_0_plus_0.stderr | 16 + .../intrinsics/ptr_offset_from_oob.stderr | 15 + .../intrinsics/ptr_offset_int_plus_int.rs | 2 +- .../intrinsics/ptr_offset_int_plus_int.stderr | 16 + .../intrinsics/ptr_offset_int_plus_ptr.rs | 2 +- .../intrinsics/ptr_offset_int_plus_ptr.stderr | 16 + .../intrinsics/ptr_offset_overflow.rs | 2 +- .../intrinsics/ptr_offset_overflow.stderr | 16 + .../intrinsics/ptr_offset_ptr_plus_0.stderr | 16 + .../intrinsics/rem-by-zero.stderr | 15 + .../intrinsics/simd-div-by-zero.stderr | 15 + .../intrinsics/simd-div-overflow.stderr | 15 + .../intrinsics/simd-float-to-int.stderr | 17 + .../intrinsics/simd-gather.stderr | 16 + .../simd-reduce-invalid-bool.stderr | 15 + .../intrinsics/simd-rem-by-zero.stderr | 15 + .../intrinsics/simd-scatter.stderr | 16 + .../simd-select-bitmask-invalid.stderr | 15 + .../simd-select-invalid-bool.stderr | 15 + .../intrinsics/simd-shl-too-far.stderr | 15 + .../intrinsics/simd-shr-too-far.stderr | 15 + .../intrinsics/unchecked_add1.stderr | 15 + .../intrinsics/unchecked_add2.stderr | 15 + .../intrinsics/unchecked_div1.stderr | 15 + .../intrinsics/unchecked_mul1.stderr | 15 + .../intrinsics/unchecked_mul2.stderr | 15 + .../intrinsics/unchecked_sub1.stderr | 15 + .../intrinsics/unchecked_sub2.stderr | 15 + .../intrinsics/uninit_uninhabited_type.stderr | 12 + .../intrinsics/write_bytes_null.stderr | 15 + .../intrinsics/write_bytes_overflow.stderr | 17 + .../intrinsics/zero_fn_ptr.stderr | 12 + tests/compile-fail/invalid_bool.rs | 2 +- tests/compile-fail/invalid_bool.stderr | 15 + tests/compile-fail/invalid_char.rs | 2 +- tests/compile-fail/invalid_char.stderr | 15 + tests/compile-fail/invalid_enum_tag.rs | 2 +- tests/compile-fail/invalid_enum_tag.stderr | 16 + tests/compile-fail/invalid_int.stderr | 15 + tests/compile-fail/issue-miri-1112.stderr | 20 + tests/compile-fail/memleak.rs | 3 +- tests/compile-fail/memleak.stderr | 10 + tests/compile-fail/memleak_rc.32bit.stderr | 10 + tests/compile-fail/memleak_rc.64bit.stderr | 11 + tests/compile-fail/memleak_rc.rs | 4 +- tests/compile-fail/modifying_constants.stderr | 15 + tests/compile-fail/never_say_never.stderr | 15 + .../never_transmute_humans.stderr | 15 + .../compile-fail/never_transmute_void.stderr | 20 + tests/compile-fail/no_main.stderr | 2 + tests/compile-fail/null_pointer_deref.stderr | 15 + .../null_pointer_deref_zst.stderr | 15 + tests/compile-fail/null_pointer_write.stderr | 15 + .../null_pointer_write_zst.stderr | 17 + .../panic/bad_miri_start_panic.stderr | 15 + tests/compile-fail/panic/bad_unwind.stderr | 25 ++ tests/compile-fail/panic/double_panic.stderr | 91 ++++ tests/compile-fail/panic/panic_abort1.stderr | 22 + tests/compile-fail/panic/panic_abort2.stderr | 23 + tests/compile-fail/panic/panic_abort3.stderr | 24 + tests/compile-fail/panic/panic_abort4.stderr | 23 + .../panic/unwind_panic_abort.stderr | 15 + .../pointer_partial_overwrite.stderr | 15 + .../compile-fail/pointer_partial_read.stderr | 14 + .../provenance/ptr_int_unexposed.stderr | 15 + .../provenance/ptr_invalid.stderr | 15 + .../provenance/ptr_legacy_provenance.rs | 1 + .../provenance/ptr_legacy_provenance.stderr | 15 + .../strict-provenance-offset.stderr | 16 + .../strict_provenance_transmute.stderr | 20 + .../ptr_integer_array_transmute.stderr | 15 + .../compile-fail/ptr_integer_transmute.stderr | 15 + tests/compile-fail/rc_as_ptr.stderr | 16 + .../reading_half_a_pointer.stderr | 14 + tests/compile-fail/rustc-error.stderr | 14 + tests/compile-fail/shim_arg_size.32bit.stderr | 15 + tests/compile-fail/shim_arg_size.64bit.stderr | 15 + tests/compile-fail/shim_arg_size.rs | 2 + tests/compile-fail/slice-too-big.stderr | 15 + .../alias_through_mutation.stderr | 27 ++ .../stacked_borrows/aliasing_mut1.stderr | 34 ++ .../stacked_borrows/aliasing_mut2.stderr | 34 ++ .../stacked_borrows/aliasing_mut3.stderr | 32 ++ .../stacked_borrows/aliasing_mut4.stderr | 34 ++ .../box_exclusive_violation1.stderr | 38 ++ .../stacked_borrows/buggy_as_mut_slice.stderr | 27 ++ .../stacked_borrows/buggy_split_at_mut.stderr | 27 ++ .../deallocate_against_barrier1.stderr | 34 ++ .../deallocate_against_barrier2.stderr | 34 ++ .../stacked_borrows/illegal_read1.stderr | 27 ++ .../stacked_borrows/illegal_read2.stderr | 27 ++ .../stacked_borrows/illegal_read3.stderr | 27 ++ .../stacked_borrows/illegal_read4.stderr | 27 ++ .../stacked_borrows/illegal_read5.rs | 1 + .../stacked_borrows/illegal_read5.stderr | 27 ++ .../stacked_borrows/illegal_read6.stderr | 27 ++ .../stacked_borrows/illegal_read7.stderr | 27 ++ .../stacked_borrows/illegal_read8.stderr | 27 ++ .../stacked_borrows/illegal_write1.stderr | 27 ++ .../stacked_borrows/illegal_write2.stderr | 27 ++ .../stacked_borrows/illegal_write3.stderr | 22 + .../stacked_borrows/illegal_write4.stderr | 27 ++ .../stacked_borrows/illegal_write5.stderr | 27 ++ .../stacked_borrows/illegal_write6.stderr | 39 ++ .../stacked_borrows/interior_mut1.stderr | 27 ++ .../stacked_borrows/interior_mut2.stderr | 27 ++ .../invalidate_against_barrier1.stderr | 39 ++ .../invalidate_against_barrier2.stderr | 39 ++ .../stacked_borrows/issue-miri-1050-1.stderr | 17 + .../stacked_borrows/issue-miri-1050-2.rs | 2 +- .../stacked_borrows/issue-miri-1050-2.stderr | 17 + .../stacked_borrows/load_invalid_mut.stderr | 27 ++ .../stacked_borrows/load_invalid_shr.stderr | 27 ++ .../mut_exclusive_violation1.stderr | 37 ++ .../mut_exclusive_violation2.stderr | 27 ++ .../stacked_borrows/outdated_local.stderr | 27 ++ .../stacked_borrows/pass_invalid_mut.stderr | 27 ++ .../stacked_borrows/pass_invalid_shr.stderr | 27 ++ .../stacked_borrows/pointer_smuggling.stderr | 32 ++ .../stacked_borrows/raw_tracking.stderr | 27 ++ .../stacked_borrows/return_invalid_mut.stderr | 32 ++ .../return_invalid_mut_option.stderr | 27 ++ .../return_invalid_mut_tuple.stderr | 27 ++ .../stacked_borrows/return_invalid_shr.stderr | 32 ++ .../return_invalid_shr_option.stderr | 27 ++ .../return_invalid_shr_tuple.stderr | 27 ++ .../shared_rw_borrows_are_weak1.stderr | 27 ++ .../shared_rw_borrows_are_weak2.rs | 1 + .../shared_rw_borrows_are_weak2.stderr | 27 ++ .../shr_frozen_violation1.stderr | 32 ++ .../static_memory_modification.rs | 2 +- .../static_memory_modification.stderr | 15 + .../transmute-is-no-escape.stderr | 18 + .../stacked_borrows/unescaped_local.stderr | 27 ++ .../stacked_borrows/unescaped_static.stderr | 18 + .../stacked_borrows/zst_slice.stderr | 16 + .../static_memory_modification1.stderr | 15 + .../static_memory_modification2.stderr | 15 + .../static_memory_modification3.stderr | 15 + .../strict-provenance-offset.stderr | 16 + .../strict_provenance_transmute.stderr | 20 + .../libc_pthread_cond_double_destroy.stderr | 15 + ...ibc_pthread_condattr_double_destroy.stderr | 15 + .../libc_pthread_mutex_NULL_deadlock.stderr | 15 + .../sync/libc_pthread_mutex_deadlock.stderr | 14 + ...libc_pthread_mutex_default_deadlock.stderr | 15 + .../libc_pthread_mutex_destroy_locked.stderr | 15 + .../libc_pthread_mutex_double_destroy.stderr | 15 + .../libc_pthread_mutex_normal_deadlock.stderr | 12 + ...thread_mutex_normal_unlock_unlocked.stderr | 15 + .../libc_pthread_mutex_wrong_owner.stderr | 17 + ...bc_pthread_mutexattr_double_destroy.stderr | 15 + ..._pthread_rwlock_destroy_read_locked.stderr | 15 + ...pthread_rwlock_destroy_write_locked.stderr | 15 + .../libc_pthread_rwlock_double_destroy.stderr | 15 + ...k_read_write_deadlock_single_thread.stderr | 12 + ...ibc_pthread_rwlock_read_wrong_owner.stderr | 17 + ...libc_pthread_rwlock_unlock_unlocked.stderr | 15 + ..._pthread_rwlock_write_read_deadlock.stderr | 14 + ...k_write_read_deadlock_single_thread.stderr | 12 + ...pthread_rwlock_write_write_deadlock.stderr | 14 + ..._write_write_deadlock_single_thread.stderr | 12 + ...bc_pthread_rwlock_write_wrong_owner.stderr | 17 + tests/compile-fail/too-big-slice.stderr | 15 + tests/compile-fail/too-big-unsized.stderr | 15 + .../compile-fail/transmute-pair-uninit.stderr | 15 + tests/compile-fail/transmute_fat1.stderr | 14 + tests/compile-fail/type-too-large.stderr | 12 + .../unaligned_pointers/alignment.rs | 3 +- .../unaligned_pointers/alignment.stderr | 15 + .../atomic_unaligned.stderr | 15 + .../unaligned_pointers/dyn_alignment.rs | 2 +- .../unaligned_pointers/dyn_alignment.stderr | 15 + .../intptrcast_alignment_check.rs | 2 +- .../intptrcast_alignment_check.stderr | 15 + .../unaligned_pointers/reference_to_packed.rs | 2 +- .../reference_to_packed.stderr | 15 + .../unaligned_pointers/unaligned_ptr1.rs | 2 +- .../unaligned_pointers/unaligned_ptr1.stderr | 15 + .../unaligned_pointers/unaligned_ptr2.rs | 2 +- .../unaligned_pointers/unaligned_ptr2.stderr | 15 + .../unaligned_pointers/unaligned_ptr3.stderr | 15 + .../unaligned_pointers/unaligned_ptr4.stderr | 15 + .../unaligned_ptr_addr_of.rs | 2 +- .../unaligned_ptr_addr_of.stderr | 16 + .../unaligned_pointers/unaligned_ptr_zst.rs | 2 +- .../unaligned_ptr_zst.stderr | 15 + tests/compile-fail/uninit_buffer.stderr | 23 + tests/compile-fail/uninit_byte_read.stderr | 15 + tests/compile-fail/uninit_float.stderr | 15 + tests/compile-fail/uninit_integer.stderr | 15 + .../compile-fail/uninit_integer_signed.stderr | 15 + tests/compile-fail/uninit_raw_ptr.stderr | 15 + tests/compile-fail/unreachable.stderr | 16 + .../unsupported_foreign_function.stderr | 14 + tests/compile-fail/unsupported_signal.stderr | 14 + .../compile-fail/validity/cast_fn_ptr1.stderr | 15 + .../compile-fail/validity/cast_fn_ptr2.stderr | 15 + tests/compile-fail/validity/dangling_ref1.rs | 2 +- .../validity/dangling_ref1.stderr | 15 + .../validity/dangling_ref2.stderr | 15 + .../validity/dangling_ref3.stderr | 15 + tests/compile-fail/validity/invalid_bool.rs | 2 +- .../compile-fail/validity/invalid_bool.stderr | 15 + .../validity/invalid_bool_uninit.stderr | 15 + tests/compile-fail/validity/invalid_char.rs | 2 +- .../compile-fail/validity/invalid_char.stderr | 15 + .../validity/invalid_char_uninit.rs | 2 +- .../validity/invalid_char_uninit.stderr | 15 + .../validity/invalid_enum_tag.stderr | 15 + ...invalid_enum_tag_256variants_uninit.stderr | 15 + .../validity/invalid_fnptr_null.stderr | 15 + .../validity/invalid_fnptr_uninit.stderr | 15 + .../validity/invalid_wide_raw.stderr | 15 + tests/compile-fail/validity/nonzero.stderr | 15 + .../ptr_integer_array_transmute.stderr | 15 + .../validity/ptr_integer_transmute.stderr | 15 + .../validity/ref_to_uninhabited1.stderr | 15 + .../validity/ref_to_uninhabited2.stderr | 15 + .../validity/too-big-slice.stderr | 15 + .../validity/too-big-unsized.stderr | 15 + .../validity/transmute_through_ptr.stderr | 15 + .../compile-fail/validity/uninit_float.stderr | 15 + .../validity/uninit_integer.stderr | 15 + .../validity/uninit_integer_signed.stderr | 15 + tests/compile-fail/zst1.stderr | 15 + tests/compile-fail/zst2.stderr | 15 + tests/compile-fail/zst3.stderr | 15 + tests/compiletest.rs | 161 ++++--- .../exported_symbol_good_unwind.rs | 0 .../exported_symbol_good_unwind.stderr | 6 +- .../panic/div-by-zero-2.rs | 0 .../panic/div-by-zero-2.stderr | 2 +- .../panic/overflowing-lsh-neg.rs | 0 .../panic/overflowing-lsh-neg.stderr | 2 +- .../panic/overflowing-rsh-1.rs | 0 .../panic/overflowing-rsh-1.stderr | 2 +- .../panic/overflowing-rsh-2.rs | 0 .../panic/overflowing-rsh-2.stderr | 2 +- tests/run-fail/panic/panic1.rs | 7 + .../panic/panic1.stderr | 30 +- tests/{run-pass => run-fail}/panic/panic2.rs | 0 .../panic/panic2.stderr | 2 +- tests/{run-pass => run-fail}/panic/panic3.rs | 0 .../panic/panic3.stderr | 2 +- tests/{run-pass => run-fail}/panic/panic4.rs | 0 .../panic/panic4.stderr | 2 +- .../panic/unsupported_foreign_function.rs | 0 .../panic/unsupported_foreign_function.stderr | 2 +- .../panic/unsupported_syscall.rs | 2 +- .../panic/unsupported_syscall.stderr | 2 +- .../{run-pass => run-fail}/transmute_fat2.rs | 0 .../transmute_fat2.stderr | 2 +- tests/run-pass/backtrace-api-v0.rs | 4 +- tests/run-pass/backtrace-api-v0.stderr | 36 +- tests/run-pass/backtrace-api-v0.stdout | 10 +- tests/run-pass/backtrace-api-v1.rs | 4 +- tests/run-pass/backtrace-api-v1.stderr | 36 +- tests/run-pass/backtrace-api-v1.stdout | 10 +- tests/run-pass/backtrace-std.rs | 3 - tests/run-pass/backtrace-std.stderr | 36 +- .../concurrency/disable_data_race_detector.rs | 2 +- .../run-pass/concurrency/libc_pthread_cond.rs | 2 +- tests/run-pass/concurrency/linux-futex.rs | 5 +- tests/run-pass/concurrency/simple.stderr | 4 +- tests/run-pass/current_dir_with_isolation.rs | 4 +- tests/run-pass/fs_with_isolation.rs | 2 +- .../linux-getrandom-without-isolation.rs | 5 +- tests/run-pass/linux-getrandom.rs | 5 +- tests/run-pass/panic/catch_panic.rs | 2 - tests/run-pass/panic/catch_panic.stderr | 24 +- tests/run-pass/panic/concurrent-panic.stderr | 4 +- tests/run-pass/panic/panic1.rs | 9 - .../generators-self-referential.rs | 2 +- tests/run-pass/track-alloc-1.stderr | 6 +- tests/run-pass/wtf8.rs | 3 +- ui_test/Cargo.toml | 14 + ui_test/README.md | 30 ++ ui_test/src/comments.rs | 111 +++++ ui_test/src/lib.rs | 410 ++++++++++++++++++ 447 files changed, 7323 insertions(+), 464 deletions(-) create mode 100644 tests/compile-fail/abort-terminator.stderr create mode 100644 tests/compile-fail/alloc/deallocate-bad-alignment.stderr create mode 100644 tests/compile-fail/alloc/deallocate-bad-size.stderr create mode 100644 tests/compile-fail/alloc/deallocate-twice.stderr create mode 100644 tests/compile-fail/alloc/global_system_mixup.stderr create mode 100644 tests/compile-fail/alloc/no_global_allocator.stderr create mode 100644 tests/compile-fail/alloc/reallocate-bad-size.stderr create mode 100644 tests/compile-fail/alloc/reallocate-change-alloc.stderr create mode 100644 tests/compile-fail/alloc/reallocate-dangling.stderr create mode 100644 tests/compile-fail/alloc/stack_free.stderr create mode 100644 tests/compile-fail/backtrace/bad-backtrace-decl.stderr create mode 100644 tests/compile-fail/backtrace/bad-backtrace-flags.stderr create mode 100644 tests/compile-fail/backtrace/bad-backtrace-ptr.stderr create mode 100644 tests/compile-fail/backtrace/bad-backtrace-resolve-flags.stderr create mode 100644 tests/compile-fail/backtrace/bad-backtrace-resolve-names-flags.stderr create mode 100644 tests/compile-fail/backtrace/bad-backtrace-size-flags.stderr create mode 100644 tests/compile-fail/backtrace/bad-backtrace-version.stderr create mode 100644 tests/compile-fail/box-cell-alias.stderr create mode 100644 tests/compile-fail/branchless-select-i128-pointer.stderr create mode 100644 tests/compile-fail/breakpoint.stderr create mode 100644 tests/compile-fail/concurrency/libc_pthread_create_main_terminate.stderr create mode 100644 tests/compile-fail/concurrency/libc_pthread_join_detached.stderr create mode 100644 tests/compile-fail/concurrency/libc_pthread_join_joined.stderr create mode 100644 tests/compile-fail/concurrency/libc_pthread_join_main.stderr create mode 100644 tests/compile-fail/concurrency/libc_pthread_join_multiple.stderr create mode 100644 tests/compile-fail/concurrency/libc_pthread_join_self.stderr create mode 100644 tests/compile-fail/concurrency/thread_local_static_dealloc.stderr create mode 100644 tests/compile-fail/concurrency/too_few_args.stderr create mode 100644 tests/compile-fail/concurrency/too_many_args.stderr create mode 100644 tests/compile-fail/concurrency/unwind_top_of_stack.stderr create mode 100644 tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.stderr create mode 100644 tests/compile-fail/dangling_pointers/dangling_pointer_deref.stderr create mode 100644 tests/compile-fail/dangling_pointers/dangling_zst_deref.stderr create mode 100644 tests/compile-fail/dangling_pointers/deref-invalid-ptr.stderr create mode 100644 tests/compile-fail/dangling_pointers/deref-partially-dangling.stderr create mode 100644 tests/compile-fail/dangling_pointers/dyn_size.stderr create mode 100644 tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr create mode 100644 tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.stderr create mode 100644 tests/compile-fail/dangling_pointers/null_pointer_deref.stderr create mode 100644 tests/compile-fail/dangling_pointers/null_pointer_deref_zst.stderr create mode 100644 tests/compile-fail/dangling_pointers/null_pointer_write.stderr create mode 100644 tests/compile-fail/dangling_pointers/null_pointer_write_zst.stderr create mode 100644 tests/compile-fail/dangling_pointers/out_of_bounds_read1.stderr create mode 100644 tests/compile-fail/dangling_pointers/out_of_bounds_read2.stderr create mode 100644 tests/compile-fail/dangling_pointers/stack_temporary.stderr create mode 100644 tests/compile-fail/dangling_pointers/storage_dead_dangling.stderr create mode 100644 tests/compile-fail/dangling_pointers/wild_pointer_deref.stderr create mode 100644 tests/compile-fail/data_race/alloc_read_race.stderr create mode 100644 tests/compile-fail/data_race/alloc_write_race.stderr create mode 100644 tests/compile-fail/data_race/atomic_read_na_write_race1.stderr create mode 100644 tests/compile-fail/data_race/atomic_read_na_write_race2.stderr create mode 100644 tests/compile-fail/data_race/atomic_write_na_read_race1.stderr create mode 100644 tests/compile-fail/data_race/atomic_write_na_read_race2.stderr create mode 100644 tests/compile-fail/data_race/atomic_write_na_write_race1.stderr create mode 100644 tests/compile-fail/data_race/atomic_write_na_write_race2.stderr create mode 100644 tests/compile-fail/data_race/dangling_thread_async_race.stderr create mode 100644 tests/compile-fail/data_race/dangling_thread_race.stderr create mode 100644 tests/compile-fail/data_race/dealloc_read_race1.stderr create mode 100644 tests/compile-fail/data_race/dealloc_read_race2.stderr create mode 100644 tests/compile-fail/data_race/dealloc_read_race_stack.stderr create mode 100644 tests/compile-fail/data_race/dealloc_write_race1.stderr create mode 100644 tests/compile-fail/data_race/dealloc_write_race2.stderr create mode 100644 tests/compile-fail/data_race/dealloc_write_race_stack.stderr create mode 100644 tests/compile-fail/data_race/enable_after_join_to_main.stderr create mode 100644 tests/compile-fail/data_race/read_write_race.stderr create mode 100644 tests/compile-fail/data_race/read_write_race_stack.stderr create mode 100644 tests/compile-fail/data_race/relax_acquire_race.stderr create mode 100644 tests/compile-fail/data_race/release_seq_race.stderr create mode 100644 tests/compile-fail/data_race/release_seq_race_same_thread.stderr create mode 100644 tests/compile-fail/data_race/rmw_race.stderr create mode 100644 tests/compile-fail/data_race/write_write_race.stderr create mode 100644 tests/compile-fail/data_race/write_write_race_stack.stderr create mode 100644 tests/compile-fail/environ-gets-deallocated.stderr create mode 100644 tests/compile-fail/erroneous_const.stderr create mode 100644 tests/compile-fail/erroneous_const2.stderr create mode 100644 tests/compile-fail/extern_static.stderr create mode 100644 tests/compile-fail/fast_math_both.stderr create mode 100644 tests/compile-fail/fast_math_first.stderr create mode 100644 tests/compile-fail/fast_math_second.stderr create mode 100644 tests/compile-fail/fs/close_stdout.stderr create mode 100644 tests/compile-fail/fs/isolated_file.stderr create mode 100644 tests/compile-fail/fs/isolated_stdin.stderr create mode 100644 tests/compile-fail/fs/read_from_stdout.stderr create mode 100644 tests/compile-fail/fs/unix_open_missing_required_mode.stderr create mode 100644 tests/compile-fail/fs/unix_open_too_many_args.stderr create mode 100644 tests/compile-fail/fs/write_to_stdin.stderr create mode 100644 tests/compile-fail/function_calls/check_arg_abi.stderr create mode 100644 tests/compile-fail/function_calls/check_arg_count_abort.stderr create mode 100644 tests/compile-fail/function_calls/check_arg_count_too_few_args.stderr create mode 100644 tests/compile-fail/function_calls/check_arg_count_too_many_args.stderr create mode 100644 tests/compile-fail/function_calls/check_callback_abi.stderr create mode 100644 tests/compile-fail/function_calls/exported_symbol_abi_mismatch.cache.stderr create mode 100644 tests/compile-fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr create mode 100644 tests/compile-fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr create mode 100644 tests/compile-fail/function_calls/exported_symbol_bad_unwind1.stderr create mode 100644 tests/compile-fail/function_calls/exported_symbol_bad_unwind2.both.stderr create mode 100644 tests/compile-fail/function_calls/exported_symbol_bad_unwind2.definition.stderr create mode 100644 tests/compile-fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr create mode 100644 tests/compile-fail/function_calls/exported_symbol_clashing.stderr create mode 100644 tests/compile-fail/function_calls/exported_symbol_shim_clashing.stderr create mode 100644 tests/compile-fail/function_calls/exported_symbol_wrong_arguments.stderr create mode 100644 tests/compile-fail/function_calls/exported_symbol_wrong_type.stderr create mode 100644 tests/compile-fail/function_pointers/cast_box_int_to_fn_ptr.stderr create mode 100644 tests/compile-fail/function_pointers/cast_fn_ptr1.stderr create mode 100644 tests/compile-fail/function_pointers/cast_fn_ptr2.stderr create mode 100644 tests/compile-fail/function_pointers/cast_fn_ptr3.stderr create mode 100644 tests/compile-fail/function_pointers/cast_fn_ptr4.stderr create mode 100644 tests/compile-fail/function_pointers/cast_fn_ptr5.stderr create mode 100644 tests/compile-fail/function_pointers/cast_int_to_fn_ptr.stderr create mode 100644 tests/compile-fail/function_pointers/deref_fn_ptr.stderr create mode 100644 tests/compile-fail/function_pointers/execute_memory.stderr create mode 100644 tests/compile-fail/function_pointers/fn_ptr_offset.stderr create mode 100644 tests/compile-fail/generator-pinned-moved.stderr create mode 100644 tests/compile-fail/intrinsics/assume.stderr create mode 100644 tests/compile-fail/intrinsics/copy_null.stderr create mode 100644 tests/compile-fail/intrinsics/copy_overflow.stderr create mode 100644 tests/compile-fail/intrinsics/copy_overlapping.stderr create mode 100644 tests/compile-fail/intrinsics/copy_unaligned.stderr create mode 100644 tests/compile-fail/intrinsics/ctlz_nonzero.stderr create mode 100644 tests/compile-fail/intrinsics/cttz_nonzero.stderr create mode 100644 tests/compile-fail/intrinsics/div-by-zero.stderr create mode 100644 tests/compile-fail/intrinsics/exact_div1.stderr create mode 100644 tests/compile-fail/intrinsics/exact_div2.stderr create mode 100644 tests/compile-fail/intrinsics/exact_div3.stderr create mode 100644 tests/compile-fail/intrinsics/exact_div4.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_inf1.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_infneg1.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_nan.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_nanneg.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_neg.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_too_big1.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_too_big2.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_too_small1.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_inf1.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_infneg1.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_infneg2.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_nan.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_neg.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_big1.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_big2.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_big3.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_big4.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_big5.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_big6.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_big7.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_small1.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_small2.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_small3.stderr create mode 100644 tests/compile-fail/intrinsics/out_of_bounds_ptr_1.stderr create mode 100644 tests/compile-fail/intrinsics/out_of_bounds_ptr_2.stderr create mode 100644 tests/compile-fail/intrinsics/out_of_bounds_ptr_3.stderr create mode 100644 tests/compile-fail/intrinsics/overflowing-unchecked-rsh.stderr create mode 100644 tests/compile-fail/intrinsics/ptr_offset_0_plus_0.stderr create mode 100644 tests/compile-fail/intrinsics/ptr_offset_from_oob.stderr create mode 100644 tests/compile-fail/intrinsics/ptr_offset_int_plus_int.stderr create mode 100644 tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.stderr create mode 100644 tests/compile-fail/intrinsics/ptr_offset_overflow.stderr create mode 100644 tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.stderr create mode 100644 tests/compile-fail/intrinsics/rem-by-zero.stderr create mode 100644 tests/compile-fail/intrinsics/simd-div-by-zero.stderr create mode 100644 tests/compile-fail/intrinsics/simd-div-overflow.stderr create mode 100644 tests/compile-fail/intrinsics/simd-float-to-int.stderr create mode 100644 tests/compile-fail/intrinsics/simd-gather.stderr create mode 100644 tests/compile-fail/intrinsics/simd-reduce-invalid-bool.stderr create mode 100644 tests/compile-fail/intrinsics/simd-rem-by-zero.stderr create mode 100644 tests/compile-fail/intrinsics/simd-scatter.stderr create mode 100644 tests/compile-fail/intrinsics/simd-select-bitmask-invalid.stderr create mode 100644 tests/compile-fail/intrinsics/simd-select-invalid-bool.stderr create mode 100644 tests/compile-fail/intrinsics/simd-shl-too-far.stderr create mode 100644 tests/compile-fail/intrinsics/simd-shr-too-far.stderr create mode 100644 tests/compile-fail/intrinsics/unchecked_add1.stderr create mode 100644 tests/compile-fail/intrinsics/unchecked_add2.stderr create mode 100644 tests/compile-fail/intrinsics/unchecked_div1.stderr create mode 100644 tests/compile-fail/intrinsics/unchecked_mul1.stderr create mode 100644 tests/compile-fail/intrinsics/unchecked_mul2.stderr create mode 100644 tests/compile-fail/intrinsics/unchecked_sub1.stderr create mode 100644 tests/compile-fail/intrinsics/unchecked_sub2.stderr create mode 100644 tests/compile-fail/intrinsics/uninit_uninhabited_type.stderr create mode 100644 tests/compile-fail/intrinsics/write_bytes_null.stderr create mode 100644 tests/compile-fail/intrinsics/write_bytes_overflow.stderr create mode 100644 tests/compile-fail/intrinsics/zero_fn_ptr.stderr create mode 100644 tests/compile-fail/invalid_bool.stderr create mode 100644 tests/compile-fail/invalid_char.stderr create mode 100644 tests/compile-fail/invalid_enum_tag.stderr create mode 100644 tests/compile-fail/invalid_int.stderr create mode 100644 tests/compile-fail/issue-miri-1112.stderr create mode 100644 tests/compile-fail/memleak.stderr create mode 100644 tests/compile-fail/memleak_rc.32bit.stderr create mode 100644 tests/compile-fail/memleak_rc.64bit.stderr create mode 100644 tests/compile-fail/modifying_constants.stderr create mode 100644 tests/compile-fail/never_say_never.stderr create mode 100644 tests/compile-fail/never_transmute_humans.stderr create mode 100644 tests/compile-fail/never_transmute_void.stderr create mode 100644 tests/compile-fail/no_main.stderr create mode 100644 tests/compile-fail/null_pointer_deref.stderr create mode 100644 tests/compile-fail/null_pointer_deref_zst.stderr create mode 100644 tests/compile-fail/null_pointer_write.stderr create mode 100644 tests/compile-fail/null_pointer_write_zst.stderr create mode 100644 tests/compile-fail/panic/bad_miri_start_panic.stderr create mode 100644 tests/compile-fail/panic/bad_unwind.stderr create mode 100644 tests/compile-fail/panic/double_panic.stderr create mode 100644 tests/compile-fail/panic/panic_abort1.stderr create mode 100644 tests/compile-fail/panic/panic_abort2.stderr create mode 100644 tests/compile-fail/panic/panic_abort3.stderr create mode 100644 tests/compile-fail/panic/panic_abort4.stderr create mode 100644 tests/compile-fail/panic/unwind_panic_abort.stderr create mode 100644 tests/compile-fail/pointer_partial_overwrite.stderr create mode 100644 tests/compile-fail/pointer_partial_read.stderr create mode 100644 tests/compile-fail/provenance/ptr_int_unexposed.stderr create mode 100644 tests/compile-fail/provenance/ptr_invalid.stderr create mode 100644 tests/compile-fail/provenance/ptr_legacy_provenance.stderr create mode 100644 tests/compile-fail/provenance/strict-provenance-offset.stderr create mode 100644 tests/compile-fail/provenance/strict_provenance_transmute.stderr create mode 100644 tests/compile-fail/ptr_integer_array_transmute.stderr create mode 100644 tests/compile-fail/ptr_integer_transmute.stderr create mode 100644 tests/compile-fail/rc_as_ptr.stderr create mode 100644 tests/compile-fail/reading_half_a_pointer.stderr create mode 100644 tests/compile-fail/rustc-error.stderr create mode 100644 tests/compile-fail/shim_arg_size.32bit.stderr create mode 100644 tests/compile-fail/shim_arg_size.64bit.stderr create mode 100644 tests/compile-fail/slice-too-big.stderr create mode 100644 tests/compile-fail/stacked_borrows/alias_through_mutation.stderr create mode 100644 tests/compile-fail/stacked_borrows/aliasing_mut1.stderr create mode 100644 tests/compile-fail/stacked_borrows/aliasing_mut2.stderr create mode 100644 tests/compile-fail/stacked_borrows/aliasing_mut3.stderr create mode 100644 tests/compile-fail/stacked_borrows/aliasing_mut4.stderr create mode 100644 tests/compile-fail/stacked_borrows/box_exclusive_violation1.stderr create mode 100644 tests/compile-fail/stacked_borrows/buggy_as_mut_slice.stderr create mode 100644 tests/compile-fail/stacked_borrows/buggy_split_at_mut.stderr create mode 100644 tests/compile-fail/stacked_borrows/deallocate_against_barrier1.stderr create mode 100644 tests/compile-fail/stacked_borrows/deallocate_against_barrier2.stderr create mode 100644 tests/compile-fail/stacked_borrows/illegal_read1.stderr create mode 100644 tests/compile-fail/stacked_borrows/illegal_read2.stderr create mode 100644 tests/compile-fail/stacked_borrows/illegal_read3.stderr create mode 100644 tests/compile-fail/stacked_borrows/illegal_read4.stderr create mode 100644 tests/compile-fail/stacked_borrows/illegal_read5.stderr create mode 100644 tests/compile-fail/stacked_borrows/illegal_read6.stderr create mode 100644 tests/compile-fail/stacked_borrows/illegal_read7.stderr create mode 100644 tests/compile-fail/stacked_borrows/illegal_read8.stderr create mode 100644 tests/compile-fail/stacked_borrows/illegal_write1.stderr create mode 100644 tests/compile-fail/stacked_borrows/illegal_write2.stderr create mode 100644 tests/compile-fail/stacked_borrows/illegal_write3.stderr create mode 100644 tests/compile-fail/stacked_borrows/illegal_write4.stderr create mode 100644 tests/compile-fail/stacked_borrows/illegal_write5.stderr create mode 100644 tests/compile-fail/stacked_borrows/illegal_write6.stderr create mode 100644 tests/compile-fail/stacked_borrows/interior_mut1.stderr create mode 100644 tests/compile-fail/stacked_borrows/interior_mut2.stderr create mode 100644 tests/compile-fail/stacked_borrows/invalidate_against_barrier1.stderr create mode 100644 tests/compile-fail/stacked_borrows/invalidate_against_barrier2.stderr create mode 100644 tests/compile-fail/stacked_borrows/issue-miri-1050-1.stderr create mode 100644 tests/compile-fail/stacked_borrows/issue-miri-1050-2.stderr create mode 100644 tests/compile-fail/stacked_borrows/load_invalid_mut.stderr create mode 100644 tests/compile-fail/stacked_borrows/load_invalid_shr.stderr create mode 100644 tests/compile-fail/stacked_borrows/mut_exclusive_violation1.stderr create mode 100644 tests/compile-fail/stacked_borrows/mut_exclusive_violation2.stderr create mode 100644 tests/compile-fail/stacked_borrows/outdated_local.stderr create mode 100644 tests/compile-fail/stacked_borrows/pass_invalid_mut.stderr create mode 100644 tests/compile-fail/stacked_borrows/pass_invalid_shr.stderr create mode 100644 tests/compile-fail/stacked_borrows/pointer_smuggling.stderr create mode 100644 tests/compile-fail/stacked_borrows/raw_tracking.stderr create mode 100644 tests/compile-fail/stacked_borrows/return_invalid_mut.stderr create mode 100644 tests/compile-fail/stacked_borrows/return_invalid_mut_option.stderr create mode 100644 tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.stderr create mode 100644 tests/compile-fail/stacked_borrows/return_invalid_shr.stderr create mode 100644 tests/compile-fail/stacked_borrows/return_invalid_shr_option.stderr create mode 100644 tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.stderr create mode 100644 tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr create mode 100644 tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr create mode 100644 tests/compile-fail/stacked_borrows/shr_frozen_violation1.stderr create mode 100644 tests/compile-fail/stacked_borrows/static_memory_modification.stderr create mode 100644 tests/compile-fail/stacked_borrows/transmute-is-no-escape.stderr create mode 100644 tests/compile-fail/stacked_borrows/unescaped_local.stderr create mode 100644 tests/compile-fail/stacked_borrows/unescaped_static.stderr create mode 100644 tests/compile-fail/stacked_borrows/zst_slice.stderr create mode 100644 tests/compile-fail/static_memory_modification1.stderr create mode 100644 tests/compile-fail/static_memory_modification2.stderr create mode 100644 tests/compile-fail/static_memory_modification3.stderr create mode 100644 tests/compile-fail/strict-provenance-offset.stderr create mode 100644 tests/compile-fail/strict_provenance_transmute.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_cond_double_destroy.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_condattr_double_destroy.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_mutex_NULL_deadlock.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_mutex_deadlock.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_mutex_default_deadlock.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_mutex_destroy_locked.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_mutex_double_destroy.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_destroy_read_locked.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_destroy_write_locked.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_unlock_unlocked.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr create mode 100644 tests/compile-fail/too-big-slice.stderr create mode 100644 tests/compile-fail/too-big-unsized.stderr create mode 100644 tests/compile-fail/transmute-pair-uninit.stderr create mode 100644 tests/compile-fail/transmute_fat1.stderr create mode 100644 tests/compile-fail/type-too-large.stderr create mode 100644 tests/compile-fail/unaligned_pointers/alignment.stderr create mode 100644 tests/compile-fail/unaligned_pointers/atomic_unaligned.stderr create mode 100644 tests/compile-fail/unaligned_pointers/dyn_alignment.stderr create mode 100644 tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.stderr create mode 100644 tests/compile-fail/unaligned_pointers/reference_to_packed.stderr create mode 100644 tests/compile-fail/unaligned_pointers/unaligned_ptr1.stderr create mode 100644 tests/compile-fail/unaligned_pointers/unaligned_ptr2.stderr create mode 100644 tests/compile-fail/unaligned_pointers/unaligned_ptr3.stderr create mode 100644 tests/compile-fail/unaligned_pointers/unaligned_ptr4.stderr create mode 100644 tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.stderr create mode 100644 tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.stderr create mode 100644 tests/compile-fail/uninit_buffer.stderr create mode 100644 tests/compile-fail/uninit_byte_read.stderr create mode 100644 tests/compile-fail/uninit_float.stderr create mode 100644 tests/compile-fail/uninit_integer.stderr create mode 100644 tests/compile-fail/uninit_integer_signed.stderr create mode 100644 tests/compile-fail/uninit_raw_ptr.stderr create mode 100644 tests/compile-fail/unreachable.stderr create mode 100644 tests/compile-fail/unsupported_foreign_function.stderr create mode 100644 tests/compile-fail/unsupported_signal.stderr create mode 100644 tests/compile-fail/validity/cast_fn_ptr1.stderr create mode 100644 tests/compile-fail/validity/cast_fn_ptr2.stderr create mode 100644 tests/compile-fail/validity/dangling_ref1.stderr create mode 100644 tests/compile-fail/validity/dangling_ref2.stderr create mode 100644 tests/compile-fail/validity/dangling_ref3.stderr create mode 100644 tests/compile-fail/validity/invalid_bool.stderr create mode 100644 tests/compile-fail/validity/invalid_bool_uninit.stderr create mode 100644 tests/compile-fail/validity/invalid_char.stderr create mode 100644 tests/compile-fail/validity/invalid_char_uninit.stderr create mode 100644 tests/compile-fail/validity/invalid_enum_tag.stderr create mode 100644 tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.stderr create mode 100644 tests/compile-fail/validity/invalid_fnptr_null.stderr create mode 100644 tests/compile-fail/validity/invalid_fnptr_uninit.stderr create mode 100644 tests/compile-fail/validity/invalid_wide_raw.stderr create mode 100644 tests/compile-fail/validity/nonzero.stderr create mode 100644 tests/compile-fail/validity/ptr_integer_array_transmute.stderr create mode 100644 tests/compile-fail/validity/ptr_integer_transmute.stderr create mode 100644 tests/compile-fail/validity/ref_to_uninhabited1.stderr create mode 100644 tests/compile-fail/validity/ref_to_uninhabited2.stderr create mode 100644 tests/compile-fail/validity/too-big-slice.stderr create mode 100644 tests/compile-fail/validity/too-big-unsized.stderr create mode 100644 tests/compile-fail/validity/transmute_through_ptr.stderr create mode 100644 tests/compile-fail/validity/uninit_float.stderr create mode 100644 tests/compile-fail/validity/uninit_integer.stderr create mode 100644 tests/compile-fail/validity/uninit_integer_signed.stderr create mode 100644 tests/compile-fail/zst1.stderr create mode 100644 tests/compile-fail/zst2.stderr create mode 100644 tests/compile-fail/zst3.stderr rename tests/{run-pass => run-fail}/function_calls/exported_symbol_good_unwind.rs (100%) rename tests/{run-pass => run-fail}/function_calls/exported_symbol_good_unwind.stderr (80%) rename tests/{run-pass => run-fail}/panic/div-by-zero-2.rs (100%) rename tests/{run-pass => run-fail}/panic/div-by-zero-2.stderr (88%) rename tests/{run-pass => run-fail}/panic/overflowing-lsh-neg.rs (100%) rename tests/{run-pass => run-fail}/panic/overflowing-lsh-neg.stderr (80%) rename tests/{run-pass => run-fail}/panic/overflowing-rsh-1.rs (100%) rename tests/{run-pass => run-fail}/panic/overflowing-rsh-1.stderr (80%) rename tests/{run-pass => run-fail}/panic/overflowing-rsh-2.rs (100%) rename tests/{run-pass => run-fail}/panic/overflowing-rsh-2.stderr (80%) create mode 100644 tests/run-fail/panic/panic1.rs rename tests/{run-pass => run-fail}/panic/panic1.stderr (55%) rename tests/{run-pass => run-fail}/panic/panic2.rs (100%) rename tests/{run-pass => run-fail}/panic/panic2.stderr (92%) rename tests/{run-pass => run-fail}/panic/panic3.rs (100%) rename tests/{run-pass => run-fail}/panic/panic3.stderr (94%) rename tests/{run-pass => run-fail}/panic/panic4.rs (100%) rename tests/{run-pass => run-fail}/panic/panic4.stderr (92%) rename tests/{run-pass => run-fail}/panic/unsupported_foreign_function.rs (100%) rename tests/{run-pass => run-fail}/panic/unsupported_foreign_function.stderr (95%) rename tests/{run-pass => run-fail}/panic/unsupported_syscall.rs (78%) rename tests/{run-pass => run-fail}/panic/unsupported_syscall.stderr (69%) rename tests/{run-pass => run-fail}/transmute_fat2.rs (100%) rename tests/{run-pass => run-fail}/transmute_fat2.stderr (75%) delete mode 100644 tests/run-pass/panic/panic1.rs create mode 100644 ui_test/Cargo.toml create mode 100644 ui_test/README.md create mode 100644 ui_test/src/comments.rs create mode 100644 ui_test/src/lib.rs diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 996164b93e8b..b74444fbc6e4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ # Contribution Guide -If you want to hack on miri yourself, great! Here are some resources you might +If you want to hack on Miri yourself, great! Here are some resources you might find useful. ## Getting started @@ -89,6 +89,20 @@ MIRI_LOG=rustc_mir::interpret=info,miri::stacked_borrows ./miri run tests/run-pa In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an evaluation error was originally raised. +#### UI testing + +We use ui-testing in Miri, meaning we generate `.stderr` and `.stdout` files for the output +produced by Miri. You can use `./miri bless` to automatically (re)generate these files when +you add new tests or change how Miri presents certain output. + +Note that when you also use `MIRIFLAGS` to change optimizations and similar, the ui output +will change in unexpected ways. In order to still be able +to run the other checks while ignoring the ui output, use `MIRI_SKIP_UI_CHECKS=1 ./miri test`. + +For more info on how to configure ui tests see [the documentation on the ui test crate][ui_test] + +[ui_test]: ui_test/README.md + ### Testing `cargo miri` Working with the driver directly gives you full control, but you also lose all @@ -183,7 +197,7 @@ A big part of the Miri driver lives in rustc, so working on Miri will sometimes require using a locally built rustc. The bug you want to fix may actually be on the rustc side, or you just need to get more detailed trace of the execution than what is possible with release builds -- in both cases, you should develop -miri against a rustc you compiled yourself, with debug assertions (and hence +Miri against a rustc you compiled yourself, with debug assertions (and hence tracing) enabled. The setup for a local rustc works as follows: @@ -191,7 +205,7 @@ The setup for a local rustc works as follows: # Clone the rust-lang/rust repo. git clone https://github.com/rust-lang/rust rustc cd rustc -# Create a config.toml with defaults for working on miri. +# Create a config.toml with defaults for working on Miri. ./x.py setup compiler # Now edit `config.toml` and under `[rust]` set `debug-assertions = true`. diff --git a/Cargo.lock b/Cargo.lock index 35e45800c0ed..5377f9420b7c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,10 +12,13 @@ dependencies = [ ] [[package]] -name = "anyhow" -version = "1.0.51" +name = "ansi_term" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] [[package]] name = "atty" @@ -28,6 +31,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + [[package]] name = "bitflags" version = "1.3.2" @@ -52,26 +61,82 @@ dependencies = [ ] [[package]] -name = "compiletest_rs" -version = "0.7.1" +name = "crossbeam" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29843cb8d351febf86557681d049d1e1652b81a086a190fa1173c07fd17fbf83" +checksum = "4ae5588f6b3c3cb05239e90bd110f257254aecd01e4635400391aeae07497845" dependencies = [ - "diff", - "filetime", - "getopts", + "cfg-if", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", "lazy_static", - "libc", - "log", - "miow", - "regex", - "rustfix", - "serde", - "serde_derive", - "serde_json", - "tempfile", - "tester", - "winapi", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +dependencies = [ + "cfg-if", + "lazy_static", +] + +[[package]] +name = "ctor" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c" +dependencies = [ + "quote", + "syn", ] [[package]] @@ -80,27 +145,6 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - [[package]] name = "env_logger" version = "0.9.0" @@ -114,27 +158,6 @@ dependencies = [ "termcolor", ] -[[package]] -name = "filetime" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "winapi", -] - -[[package]] -name = "getopts" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" -dependencies = [ - "unicode-width", -] - [[package]] name = "getrandom" version = "0.2.3" @@ -170,12 +193,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "itoa" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" - [[package]] name = "lazy_static" version = "1.4.0" @@ -236,12 +253,12 @@ dependencies = [ ] [[package]] -name = "miow" -version = "0.3.7" +name = "memoffset" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" dependencies = [ - "winapi", + "autocfg", ] [[package]] @@ -249,27 +266,27 @@ name = "miri" version = "0.1.0" dependencies = [ "colored", - "compiletest_rs", "env_logger", "getrandom", + "lazy_static", "libc", "log", "measureme", "rand", + "regex", "rustc-workspace-hack", - "rustc_version", "shell-escape", "smallvec", + "ui_test", ] [[package]] -name = "num_cpus" -version = "1.13.0" +name = "output_vt100" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" dependencies = [ - "hermit-abi", - "libc", + "winapi", ] [[package]] @@ -313,19 +330,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" [[package]] -name = "proc-macro2" -version = "1.0.33" +name = "pretty_assertions" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb37d2df5df740e582f28f8560cf425f52bb267d872fe58358eadb554909f07a" +checksum = "c89f989ac94207d048d92db058e4f6ec7342b0971fc58d1271ca148b799b3563" dependencies = [ - "unicode-xid", + "ansi_term", + "ctor", + "diff", + "output_vt100", +] + +[[package]] +name = "proc-macro2" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +dependencies = [ + "unicode-ident", ] [[package]] name = "quote" -version = "1.0.10" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" dependencies = [ "proc-macro2", ] @@ -379,21 +408,11 @@ dependencies = [ "bitflags", ] -[[package]] -name = "redox_users" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" -dependencies = [ - "getrandom", - "redox_syscall", -] - [[package]] name = "regex" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" dependencies = [ "aho-corasick", "memchr", @@ -406,15 +425,6 @@ version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - [[package]] name = "rustc-hash" version = "1.1.0" @@ -436,30 +446,6 @@ dependencies = [ "semver", ] -[[package]] -name = "rustfix" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2c50b74badcddeb8f7652fa8323ce440b95286f8e4b64ebfd871c609672704e" -dependencies = [ - "anyhow", - "log", - "serde", - "serde_json", -] - -[[package]] -name = "rustversion" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" - -[[package]] -name = "ryu" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" - [[package]] name = "scopeguard" version = "1.1.0" @@ -468,40 +454,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "semver" -version = "1.0.4" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" - -[[package]] -name = "serde" -version = "1.0.131" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ad69dfbd3e45369132cc64e6748c2d65cdfb001a2b1c232d128b4ad60561c1" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.131" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b710a83c4e0dff6a3d511946b95274ad9ca9e5d3ae497b63fda866ac955358d2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcbd0344bc6533bc7ec56df11d42fb70f1b912351c0825ccb7211b59d8af7cf5" -dependencies = [ - "itoa", - "ryu", - "serde", -] +checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" [[package]] name = "shell-escape" @@ -517,38 +472,13 @@ checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" [[package]] name = "syn" -version = "1.0.82" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" +checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" dependencies = [ "proc-macro2", "quote", - "unicode-xid", -] - -[[package]] -name = "tempfile" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" -dependencies = [ - "cfg-if", - "libc", - "rand", - "redox_syscall", - "remove_dir_all", - "winapi", -] - -[[package]] -name = "term" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" -dependencies = [ - "dirs-next", - "rustversion", - "winapi", + "unicode-ident", ] [[package]] @@ -561,29 +491,22 @@ dependencies = [ ] [[package]] -name = "tester" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0639d10d8f4615f223a57275cf40f9bdb7cfbb806bcb7f7cc56e3beb55a576eb" +name = "ui_test" +version = "0.1.0" dependencies = [ - "cfg-if", - "getopts", - "libc", - "num_cpus", - "term", + "colored", + "crossbeam", + "lazy_static", + "pretty_assertions", + "regex", + "rustc_version", ] [[package]] -name = "unicode-width" -version = "0.1.9" +name = "unicode-ident" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" - -[[package]] -name = "unicode-xid" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" [[package]] name = "wasi" diff --git a/Cargo.toml b/Cargo.toml index 6d65ab6e1e46..cf6f4c8b2ee9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,9 +37,10 @@ measureme = "9.1.2" libc = "0.2" [dev-dependencies] -compiletest_rs = { version = "0.7", features = ["tmp"] } -rustc_version = "0.4" colored = "2" +ui_test = { path = "ui_test" } +regex = "1.5.5" +lazy_static = "1.4.0" [package.metadata.rust-analyzer] # This crate uses #[feature(rustc_private)]. diff --git a/README.md b/README.md index 0f6c5007ba6c..afee8a8bfa05 100644 --- a/README.md +++ b/README.md @@ -328,7 +328,7 @@ to Miri failing to detect cases of undefined behavior in a program. using the tools in the repository https://github.com/rust-lang/measureme. * `-Zmiri-mute-stdout-stderr` silently ignores all writes to stdout and stderr, but reports to the program that it did actually write. This is useful when you - are not interested in the actual program's output, but only want to see miri's + are not interested in the actual program's output, but only want to see Miri's errors and warnings. * `-Zmiri-panic-on-unsupported` will makes some forms of unsupported functionality, such as FFI and unsupported syscalls, panic within the context of the emulated @@ -412,6 +412,11 @@ Moreover, Miri recognizes some environment variables: * `MIRI_TEST_TARGET` (recognized by the test suite) indicates which target architecture to test against. `miri` and `cargo miri` accept the `--target` flag for the same purpose. +* `MIRI_BLESS` (recognized by the test suite) overwrite all `stderr` and `stdout` files + instead of checking whether the output matches. +* `MIRI_SKIP_UI_CHECKS` (recognized by the test suite) don't check whether the + `stderr` or `stdout` files match the actual output. Useful for the rustc test suite + which has subtle differences that we don't care about. The following environment variables are *internal* and must not be used by anyone but Miri itself. They are used to communicate between different Miri @@ -519,15 +524,15 @@ GitHub or use the [Miri stream on the Rust Zulip][zulip]. This project began as part of an undergraduate research course in 2015 by @solson at the [University of Saskatchewan][usask]. There are [slides] and a -[report] available from that project. In 2016, @oli-obk joined to prepare miri +[report] available from that project. In 2016, @oli-obk joined to prepare Miri for eventually being used as const evaluator in the Rust compiler itself (basically, for `const` and `static` stuff), replacing the old evaluator that worked directly on the AST. In 2017, @RalfJung did an internship with Mozilla -and began developing miri towards a tool for detecting undefined behavior, and -also using miri as a way to explore the consequences of various possible -definitions for undefined behavior in Rust. @oli-obk's move of the miri engine +and began developing Miri towards a tool for detecting undefined behavior, and +also using Miri as a way to explore the consequences of various possible +definitions for undefined behavior in Rust. @oli-obk's move of the Miri engine into the compiler finally came to completion in early 2018. Meanwhile, later -that year, @RalfJung did a second internship, developing miri further with +that year, @RalfJung did a second internship, developing Miri further with support for checking basic type invariants and verifying that references are used according to their aliasing restrictions. diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 373c63647c35..e08cb8c88c00 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -461,7 +461,12 @@ path = "lib.rs" command.env_remove("RUSTFLAGS"); // Disable debug assertions in the standard library -- Miri is already slow enough. // But keep the overflow checks, they are cheap. - command.env("RUSTFLAGS", "-Cdebug-assertions=off -Coverflow-checks=on"); + // Also remap the current directory to something that is stable across different + // machines. Otherwise ui output would contain the current directory. + command.env( + "RUSTFLAGS", + "-Cdebug-assertions=off -Coverflow-checks=on -Zremap-cwd-prefix=rustc_src", + ); // Finally run it! if command.status().expect("failed to run xargo").success().not() { show_error(format!("failed to run xargo")); diff --git a/ci.sh b/ci.sh index c19aceb641e3..d435e0e2a210 100755 --- a/ci.sh +++ b/ci.sh @@ -24,7 +24,8 @@ function run_tests { if [ -z "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with optimizations (`-O` is what cargo passes, but crank MIR # optimizations up all the way). - MIRIFLAGS="-O -Zmir-opt-level=4" ./miri test --locked + # Optimizations change diagnostics (mostly backtraces), so we don't check them + MIRIFLAGS="-O -Zmir-opt-level=4" MIRI_SKIP_UI_CHECKS=1 ./miri test --locked fi # On Windows, there is always "python", not "python3" or "python2". diff --git a/miri b/miri index 56ae119cd1bc..6a809b74356a 100755 --- a/miri +++ b/miri @@ -123,10 +123,15 @@ build|build-debug) cargo build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" cargo build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" ;; -test|test-debug) +test|test-debug|bless|bless-debug) # First build and get a sysroot. cargo build $CARGO_BUILD_FLAGS find_sysroot + case "$COMMAND" in + bless|bless-debug) + export MIRI_BLESS="Gesundheit" + ;; + esac # Then test, and let caller control flags. # Only in root project as `cargo-miri` has no tests. exec cargo test $CARGO_BUILD_FLAGS "$@" diff --git a/src/machine.rs b/src/machine.rs index c5c884e8d7a0..249b578b1214 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -583,7 +583,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { if let Some(&ptr) = ecx.machine.extern_statics.get(&link_name) { Ok(ptr) } else { - throw_unsup_format!("`extern` static {:?} is not supported by Miri", def_id) + throw_unsup_format!( + "`extern` static `{}` from crate `{}` is not supported by Miri", + ecx.tcx.def_path_str(def_id), + ecx.tcx.crate_name(def_id.krate), + ) } } diff --git a/tests/compile-fail/abort-terminator.stderr b/tests/compile-fail/abort-terminator.stderr new file mode 100644 index 000000000000..76501ca074fd --- /dev/null +++ b/tests/compile-fail/abort-terminator.stderr @@ -0,0 +1,19 @@ +thread 'main' panicked at 'explicit panic', $DIR/abort-terminator.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +error: abnormal termination: the program aborted execution + --> $DIR/abort-terminator.rs:LL:CC + | +LL | extern "C" fn panic_abort() { panic!() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the program aborted execution + | + = note: inside `panic_abort` at $DIR/abort-terminator.rs:LL:CC +note: inside `main` at $DIR/abort-terminator.rs:LL:CC + --> $DIR/abort-terminator.rs:LL:CC + | +LL | panic_abort(); + | ^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/alloc/deallocate-bad-alignment.stderr b/tests/compile-fail/alloc/deallocate-bad-alignment.stderr new file mode 100644 index 000000000000..e03704b118a6 --- /dev/null +++ b/tests/compile-fail/alloc/deallocate-bad-alignment.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: incorrect layout on deallocation: ALLOC has size 1 and alignment ALIGN, but gave size 1 and alignment ALIGN + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::alloc::dealloc` at rustc_src/src/alloc.rs:LL:CC +note: inside `main` at $DIR/deallocate-bad-alignment.rs:LL:CC + --> $DIR/deallocate-bad-alignment.rs:LL:CC + | +LL | dealloc(x, Layout::from_size_align_unchecked(1, 2)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/alloc/deallocate-bad-size.stderr b/tests/compile-fail/alloc/deallocate-bad-size.stderr new file mode 100644 index 000000000000..3ab15094daeb --- /dev/null +++ b/tests/compile-fail/alloc/deallocate-bad-size.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: incorrect layout on deallocation: ALLOC has size 1 and alignment ALIGN, but gave size 2 and alignment ALIGN + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::alloc::dealloc` at rustc_src/src/alloc.rs:LL:CC +note: inside `main` at $DIR/deallocate-bad-size.rs:LL:CC + --> $DIR/deallocate-bad-size.rs:LL:CC + | +LL | dealloc(x, Layout::from_size_align_unchecked(2, 1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/alloc/deallocate-twice.stderr b/tests/compile-fail/alloc/deallocate-twice.stderr new file mode 100644 index 000000000000..dfd14c397865 --- /dev/null +++ b/tests/compile-fail/alloc/deallocate-twice.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::alloc::dealloc` at rustc_src/src/alloc.rs:LL:CC +note: inside `main` at $DIR/deallocate-twice.rs:LL:CC + --> $DIR/deallocate-twice.rs:LL:CC + | +LL | dealloc(x, Layout::from_size_align_unchecked(1, 1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/alloc/global_system_mixup.rs b/tests/compile-fail/alloc/global_system_mixup.rs index afe9d5cc8254..3f58de4d6fb0 100644 --- a/tests/compile-fail/alloc/global_system_mixup.rs +++ b/tests/compile-fail/alloc/global_system_mixup.rs @@ -2,6 +2,8 @@ // (even when the default `Global` uses `System`). // error-pattern: which is Rust heap memory, using +// normalize-stderr-test: "using [A-Za-z]+ heap deallocation operation" -> "using PLATFORM heap deallocation operation" + #![feature(allocator_api, slice_ptr_get)] use std::alloc::{Allocator, Global, System, Layout}; diff --git a/tests/compile-fail/alloc/global_system_mixup.stderr b/tests/compile-fail/alloc/global_system_mixup.stderr new file mode 100644 index 000000000000..93598be134f7 --- /dev/null +++ b/tests/compile-fail/alloc/global_system_mixup.stderr @@ -0,0 +1,17 @@ +error: Undefined Behavior: deallocating ALLOC, which is Rust heap memory, using PLATFORM heap deallocation operation + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::sys::PLATFORM::alloc::::dealloc` at rustc_src/src/sys/PLATFORM/alloc.rs:LL:CC + = note: inside `::deallocate` at rustc_src/src/alloc.rs:LL:CC +note: inside `main` at $DIR/global_system_mixup.rs:LL:CC + --> $DIR/global_system_mixup.rs:LL:CC + | +LL | unsafe { System.deallocate(ptr, l); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/alloc/no_global_allocator.stderr b/tests/compile-fail/alloc/no_global_allocator.stderr new file mode 100644 index 000000000000..2a9840ee83c4 --- /dev/null +++ b/tests/compile-fail/alloc/no_global_allocator.stderr @@ -0,0 +1,12 @@ +error: unsupported operation: can't call foreign function: __rust_alloc + --> $DIR/no_global_allocator.rs:LL:CC + | +LL | __rust_alloc(1, 1); + | ^^^^^^^^^^^^^^^^^^ can't call foreign function: __rust_alloc + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `start` at $DIR/no_global_allocator.rs:LL:CC + +error: aborting due to previous error + diff --git a/tests/compile-fail/alloc/reallocate-bad-size.stderr b/tests/compile-fail/alloc/reallocate-bad-size.stderr new file mode 100644 index 000000000000..f2692b1c343f --- /dev/null +++ b/tests/compile-fail/alloc/reallocate-bad-size.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: incorrect layout on deallocation: ALLOC has size 1 and alignment ALIGN, but gave size 2 and alignment ALIGN + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::alloc::realloc` at rustc_src/src/alloc.rs:LL:CC +note: inside `main` at $DIR/reallocate-bad-size.rs:LL:CC + --> $DIR/reallocate-bad-size.rs:LL:CC + | +LL | let _y = realloc(x, Layout::from_size_align_unchecked(2, 1), 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/alloc/reallocate-change-alloc.stderr b/tests/compile-fail/alloc/reallocate-change-alloc.stderr new file mode 100644 index 000000000000..d400931379b0 --- /dev/null +++ b/tests/compile-fail/alloc/reallocate-change-alloc.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> $DIR/reallocate-change-alloc.rs:LL:CC + | +LL | let _z = *x; + | ^^ pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/reallocate-change-alloc.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/alloc/reallocate-dangling.stderr b/tests/compile-fail/alloc/reallocate-dangling.stderr new file mode 100644 index 000000000000..d813fb0db902 --- /dev/null +++ b/tests/compile-fail/alloc/reallocate-dangling.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::alloc::realloc` at rustc_src/src/alloc.rs:LL:CC +note: inside `main` at $DIR/reallocate-dangling.rs:LL:CC + --> $DIR/reallocate-dangling.rs:LL:CC + | +LL | let _z = realloc(x, Layout::from_size_align_unchecked(1, 1), 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/alloc/stack_free.stderr b/tests/compile-fail/alloc/stack_free.stderr new file mode 100644 index 000000000000..9df85d6eab7f --- /dev/null +++ b/tests/compile-fail/alloc/stack_free.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: deallocating ALLOC, which is stack variable memory, using Rust heap deallocation operation + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::alloc::dealloc` at rustc_src/src/alloc.rs:LL:CC + = note: inside `::deallocate` at rustc_src/src/alloc.rs:LL:CC + = note: inside `alloc::alloc::box_free::` at rustc_src/src/alloc.rs:LL:CC + = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at rustc_src/src/ptr/mod.rs:LL:CC + = note: inside `std::mem::drop::>` at rustc_src/src/mem/mod.rs:LL:CC +note: inside `main` at $DIR/stack_free.rs:LL:CC + --> $DIR/stack_free.rs:LL:CC + | +LL | drop(bad_box); + | ^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/backtrace/bad-backtrace-decl.stderr b/tests/compile-fail/backtrace/bad-backtrace-decl.stderr new file mode 100644 index 000000000000..007ef96f72a9 --- /dev/null +++ b/tests/compile-fail/backtrace/bad-backtrace-decl.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: bad declaration of miri_resolve_frame - should return a struct with 5 fields + --> $DIR/bad-backtrace-decl.rs:LL:CC + | +LL | ... miri_resolve_frame(*frame, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad declaration of miri_resolve_frame - should return a struct with 5 fields + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/bad-backtrace-decl.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/backtrace/bad-backtrace-flags.stderr b/tests/compile-fail/backtrace/bad-backtrace-flags.stderr new file mode 100644 index 000000000000..f6ffe3c93c89 --- /dev/null +++ b/tests/compile-fail/backtrace/bad-backtrace-flags.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: unknown `miri_get_backtrace` flags 2 + --> $DIR/bad-backtrace-flags.rs:LL:CC + | +LL | miri_get_backtrace(2, 0 as *mut _); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_get_backtrace` flags 2 + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/bad-backtrace-flags.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/backtrace/bad-backtrace-ptr.stderr b/tests/compile-fail/backtrace/bad-backtrace-ptr.stderr new file mode 100644 index 000000000000..ed726a5dcdc2 --- /dev/null +++ b/tests/compile-fail/backtrace/bad-backtrace-ptr.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: null pointer is not a valid pointer for this operation + --> $DIR/bad-backtrace-ptr.rs:LL:CC + | +LL | miri_resolve_frame(0 as *mut _, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ null pointer is not a valid pointer for this operation + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/bad-backtrace-ptr.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/backtrace/bad-backtrace-resolve-flags.stderr b/tests/compile-fail/backtrace/bad-backtrace-resolve-flags.stderr new file mode 100644 index 000000000000..49495651dfec --- /dev/null +++ b/tests/compile-fail/backtrace/bad-backtrace-resolve-flags.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: unknown `miri_resolve_frame` flags 2 + --> $DIR/bad-backtrace-resolve-flags.rs:LL:CC + | +LL | miri_resolve_frame(buf[0], 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_resolve_frame` flags 2 + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/bad-backtrace-resolve-flags.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/backtrace/bad-backtrace-resolve-names-flags.stderr b/tests/compile-fail/backtrace/bad-backtrace-resolve-names-flags.stderr new file mode 100644 index 000000000000..d575caa4ff4e --- /dev/null +++ b/tests/compile-fail/backtrace/bad-backtrace-resolve-names-flags.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: unknown `miri_resolve_frame_names` flags 2 + --> $DIR/bad-backtrace-resolve-names-flags.rs:LL:CC + | +LL | ... miri_resolve_frame_names(buf[0], 2, 0 as *mut _, 0 as *mut _); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_resolve_frame_names` flags 2 + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/bad-backtrace-resolve-names-flags.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/backtrace/bad-backtrace-size-flags.stderr b/tests/compile-fail/backtrace/bad-backtrace-size-flags.stderr new file mode 100644 index 000000000000..09f22b74b9c3 --- /dev/null +++ b/tests/compile-fail/backtrace/bad-backtrace-size-flags.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: unknown `miri_backtrace_size` flags 2 + --> $DIR/bad-backtrace-size-flags.rs:LL:CC + | +LL | miri_backtrace_size(2); + | ^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_backtrace_size` flags 2 + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/bad-backtrace-size-flags.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/backtrace/bad-backtrace-version.stderr b/tests/compile-fail/backtrace/bad-backtrace-version.stderr new file mode 100644 index 000000000000..4e7292732754 --- /dev/null +++ b/tests/compile-fail/backtrace/bad-backtrace-version.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: unknown `miri_resolve_frame` flags 1 + --> $DIR/bad-backtrace-version.rs:7:9 + | +LL | miri_resolve_frame(0 as *mut _, 1); //~ ERROR unsupported operation: unknown `miri_resolve_frame` flags 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_resolve_frame` flags 1 + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/bad-backtrace-version.rs:7:9 + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/box-cell-alias.stderr b/tests/compile-fail/box-cell-alias.stderr new file mode 100644 index 000000000000..a4eaec93a8fb --- /dev/null +++ b/tests/compile-fail/box-cell-alias.stderr @@ -0,0 +1,32 @@ +error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/box-cell-alias.rs:LL:CC + | +LL | unsafe { (*ptr).set(20); } + | ^^^^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x1] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x1] + --> $DIR/box-cell-alias.rs:LL:CC + | +LL | let ptr: *const Cell = &*val; + | ^^^^^ +help: was later invalidated at offsets [0x0..0x1] + --> $DIR/box-cell-alias.rs:LL:CC + | +LL | let res = helper(val, ptr); + | ^^^ + = note: inside `helper` at $DIR/box-cell-alias.rs:LL:CC +note: inside `main` at $DIR/box-cell-alias.rs:LL:CC + --> $DIR/box-cell-alias.rs:LL:CC + | +LL | let res = helper(val, ptr); + | ^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/branchless-select-i128-pointer.stderr b/tests/compile-fail/branchless-select-i128-pointer.stderr new file mode 100644 index 000000000000..2e0f81398303 --- /dev/null +++ b/tests/compile-fail/branchless-select-i128-pointer.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes + --> $DIR/branchless-select-i128-pointer.rs:LL:CC + | +LL | !mask & transmute::<_, TwoPtrs>("false !") | mask & transmute::<_, TwoPtrs>("true !"), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/branchless-select-i128-pointer.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/breakpoint.stderr b/tests/compile-fail/breakpoint.stderr new file mode 100644 index 000000000000..7b9bbdb38289 --- /dev/null +++ b/tests/compile-fail/breakpoint.stderr @@ -0,0 +1,12 @@ +error: abnormal termination: Trace/breakpoint trap + --> $DIR/breakpoint.rs:LL:CC + | +LL | core::intrinsics::breakpoint() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Trace/breakpoint trap + | + = note: inside `main` at $DIR/breakpoint.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.stderr b/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.stderr new file mode 100644 index 000000000000..0f7fbefe0af0 --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.stderr @@ -0,0 +1,8 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: the main thread terminated without waiting for all remaining threads + +note: pass `-Zmiri-ignore-leaks` to disable this check + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/concurrency/libc_pthread_join_detached.stderr b/tests/compile-fail/concurrency/libc_pthread_join_detached.stderr new file mode 100644 index 000000000000..688f61a98b90 --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_join_detached.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: trying to join a detached or already joined thread + --> $DIR/libc_pthread_join_detached.rs:LL:CC + | +LL | ... assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached or already joined thread + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/libc_pthread_join_detached.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/concurrency/libc_pthread_join_joined.stderr b/tests/compile-fail/concurrency/libc_pthread_join_joined.stderr new file mode 100644 index 000000000000..518f72de5bef --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_join_joined.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: trying to join a detached or already joined thread + --> $DIR/libc_pthread_join_joined.rs:LL:CC + | +LL | ... assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached or already joined thread + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/libc_pthread_join_joined.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/concurrency/libc_pthread_join_main.stderr b/tests/compile-fail/concurrency/libc_pthread_join_main.stderr new file mode 100644 index 000000000000..5d9ec148e079 --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_join_main.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: trying to join a detached or already joined thread + --> $DIR/libc_pthread_join_main.rs:LL:CC + | +LL | ... assert_eq!(libc::pthread_join(thread_id, ptr::null_mut()), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached or already joined thread + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/libc_pthread_join_main.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/concurrency/libc_pthread_join_multiple.stderr b/tests/compile-fail/concurrency/libc_pthread_join_multiple.stderr new file mode 100644 index 000000000000..57126a14ae2f --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_join_multiple.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: trying to join a detached or already joined thread + --> $DIR/libc_pthread_join_multiple.rs:LL:CC + | +LL | ... assert_eq!(libc::pthread_join(native_copy, ptr::null_mut()), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached or already joined thread + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/libc_pthread_join_multiple.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/concurrency/libc_pthread_join_self.stderr b/tests/compile-fail/concurrency/libc_pthread_join_self.stderr new file mode 100644 index 000000000000..d638d089398a --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_join_self.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: trying to join itself + --> $DIR/libc_pthread_join_self.rs:LL:CC + | +LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join itself + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/libc_pthread_join_self.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/concurrency/thread-spawn.rs b/tests/compile-fail/concurrency/thread-spawn.rs index 6f07d083a0e5..948ce946d894 100644 --- a/tests/compile-fail/concurrency/thread-spawn.rs +++ b/tests/compile-fail/concurrency/thread-spawn.rs @@ -1,5 +1,4 @@ -// ignore-linux: Only Windows is not supported. -// ignore-macos: Only Windows is not supported. +// only-windows: Only Windows is not supported. use std::thread; diff --git a/tests/compile-fail/concurrency/thread_local_static_dealloc.stderr b/tests/compile-fail/concurrency/thread_local_static_dealloc.stderr new file mode 100644 index 000000000000..cdeb22fb3175 --- /dev/null +++ b/tests/compile-fail/concurrency/thread_local_static_dealloc.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> $DIR/thread_local_static_dealloc.rs:LL:CC + | +LL | let _val = *(dangling_ptr as *const u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/thread_local_static_dealloc.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/concurrency/too_few_args.stderr b/tests/compile-fail/concurrency/too_few_args.stderr new file mode 100644 index 000000000000..753b5e9ea7eb --- /dev/null +++ b/tests/compile-fail/concurrency/too_few_args.stderr @@ -0,0 +1,16 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: callee has fewer arguments than expected + --> $DIR/too_few_args.rs:LL:CC + | +LL | panic!() + | ^^^^^^^^ callee has fewer arguments than expected + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `thread_start` at rustc_src/src/panic.rs:LL:CC + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/concurrency/too_many_args.stderr b/tests/compile-fail/concurrency/too_many_args.stderr new file mode 100644 index 000000000000..483b032a9b17 --- /dev/null +++ b/tests/compile-fail/concurrency/too_many_args.stderr @@ -0,0 +1,16 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: callee has more arguments than expected + --> $DIR/too_many_args.rs:LL:CC + | +LL | panic!() + | ^^^^^^^^ callee has more arguments than expected + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `thread_start` at rustc_src/src/panic.rs:LL:CC + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/concurrency/unwind_top_of_stack.stderr b/tests/compile-fail/concurrency/unwind_top_of_stack.stderr new file mode 100644 index 000000000000..600b8443d2c7 --- /dev/null +++ b/tests/compile-fail/concurrency/unwind_top_of_stack.stderr @@ -0,0 +1,19 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +thread '' panicked at 'explicit panic', $DIR/unwind_top_of_stack.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +error: Undefined Behavior: unwinding past the topmost frame of the stack + --> $DIR/unwind_top_of_stack.rs:LL:CC + | +LL | / extern "C-unwind" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { +LL | | panic!() +LL | | } + | |_^ unwinding past the topmost frame of the stack + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `thread_start` at $DIR/unwind_top_of_stack.rs:LL:CC + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.stderr b/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.stderr new file mode 100644 index 000000000000..6638be3758cf --- /dev/null +++ b/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> $DIR/dangling_pointer_addr_of.rs:LL:CC + | +LL | let x = unsafe { ptr::addr_of!(*p) }; + | ^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at rustc_src/src/ptr/mod.rs:LL:CC + = note: this error originates in the macro `ptr::addr_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/dangling_pointer_deref.stderr b/tests/compile-fail/dangling_pointers/dangling_pointer_deref.stderr new file mode 100644 index 000000000000..69e7af74857a --- /dev/null +++ b/tests/compile-fail/dangling_pointers/dangling_pointer_deref.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> $DIR/dangling_pointer_deref.rs:LL:CC + | +LL | let x = unsafe { *p }; + | ^^ pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/dangling_pointer_deref.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/dangling_zst_deref.stderr b/tests/compile-fail/dangling_pointers/dangling_zst_deref.stderr new file mode 100644 index 000000000000..658635433c7a --- /dev/null +++ b/tests/compile-fail/dangling_pointers/dangling_zst_deref.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> $DIR/dangling_zst_deref.rs:LL:CC + | +LL | let _x = unsafe { *p }; + | ^^ pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/dangling_zst_deref.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs b/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs index 87071d8b4591..56830e97caa3 100644 --- a/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs +++ b/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs @@ -3,5 +3,5 @@ fn main() { let x = 16usize as *const u32; - let _y = unsafe { &*x as *const u32 }; //~ ERROR 0x10 is not a valid pointer + let _y = unsafe { &*x as *const u32 }; //~ ERROR is not a valid pointer } diff --git a/tests/compile-fail/dangling_pointers/deref-invalid-ptr.stderr b/tests/compile-fail/dangling_pointers/deref-invalid-ptr.stderr new file mode 100644 index 000000000000..f4361d9fefa9 --- /dev/null +++ b/tests/compile-fail/dangling_pointers/deref-invalid-ptr.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: 0x10 is not a valid pointer + --> $DIR/deref-invalid-ptr.rs:LL:CC + | +LL | let _y = unsafe { &*x as *const u32 }; + | ^^^ dereferencing pointer failed: 0x10 is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/deref-invalid-ptr.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/deref-partially-dangling.stderr b/tests/compile-fail/dangling_pointers/deref-partially-dangling.stderr new file mode 100644 index 000000000000..dc51eae71a3a --- /dev/null +++ b/tests/compile-fail/dangling_pointers/deref-partially-dangling.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 8, so pointer to 12 bytes starting at offset 0 is out-of-bounds + --> $DIR/deref-partially-dangling.rs:LL:CC + | +LL | let val = unsafe { (*xptr).1 }; + | ^^^^^^^^^ dereferencing pointer failed: ALLOC has size 8, so pointer to 12 bytes starting at offset 0 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/deref-partially-dangling.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/dyn_size.stderr b/tests/compile-fail/dangling_pointers/dyn_size.stderr new file mode 100644 index 000000000000..6048a3b4434d --- /dev/null +++ b/tests/compile-fail/dangling_pointers/dyn_size.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds + --> $DIR/dyn_size.rs:LL:CC + | +LL | let _ptr = unsafe { &*ptr }; + | ^^^^^ dereferencing pointer failed: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/dyn_size.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr b/tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr new file mode 100644 index 000000000000..b4da315a5542 --- /dev/null +++ b/tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds + --> $DIR/maybe_null_pointer_deref_zst.rs:LL:CC + | +LL | let _x: () = unsafe { *ptr }; + | ^^^^ dereferencing pointer failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/maybe_null_pointer_deref_zst.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.stderr b/tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.stderr new file mode 100644 index 000000000000..dc810424abc6 --- /dev/null +++ b/tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds + --> $DIR/maybe_null_pointer_write_zst.rs:LL:CC + | +LL | unsafe { *ptr = zst_val; } + | ^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/maybe_null_pointer_write_zst.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/null_pointer_deref.stderr b/tests/compile-fail/dangling_pointers/null_pointer_deref.stderr new file mode 100644 index 000000000000..0930160023f1 --- /dev/null +++ b/tests/compile-fail/dangling_pointers/null_pointer_deref.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: null pointer is not a valid pointer + --> $DIR/null_pointer_deref.rs:LL:CC + | +LL | let x: i32 = unsafe { *std::ptr::null() }; + | ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/null_pointer_deref.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/null_pointer_deref_zst.stderr b/tests/compile-fail/dangling_pointers/null_pointer_deref_zst.stderr new file mode 100644 index 000000000000..25fea50b15af --- /dev/null +++ b/tests/compile-fail/dangling_pointers/null_pointer_deref_zst.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: null pointer is not a valid pointer + --> $DIR/null_pointer_deref_zst.rs:LL:CC + | +LL | let x: () = unsafe { *std::ptr::null() }; + | ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/null_pointer_deref_zst.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/null_pointer_write.stderr b/tests/compile-fail/dangling_pointers/null_pointer_write.stderr new file mode 100644 index 000000000000..5ac8cc7c20fd --- /dev/null +++ b/tests/compile-fail/dangling_pointers/null_pointer_write.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: null pointer is not a valid pointer + --> $DIR/null_pointer_write.rs:LL:CC + | +LL | unsafe { *std::ptr::null_mut() = 0i32 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/null_pointer_write.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/null_pointer_write_zst.stderr b/tests/compile-fail/dangling_pointers/null_pointer_write_zst.stderr new file mode 100644 index 000000000000..b40a9154f182 --- /dev/null +++ b/tests/compile-fail/dangling_pointers/null_pointer_write_zst.stderr @@ -0,0 +1,17 @@ +error: Undefined Behavior: memory access failed: null pointer is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::ptr::write::<[u8; 0]>` at rustc_src/src/ptr/mod.rs:LL:CC + = note: inside `std::ptr::mut_ptr::::write` at rustc_src/src/ptr/mut_ptr.rs:LL:CC +note: inside `main` at $DIR/null_pointer_write_zst.rs:LL:CC + --> $DIR/null_pointer_write_zst.rs:LL:CC + | +LL | unsafe { std::ptr::null_mut::<[u8; 0]>().write(zst_val) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/out_of_bounds_read1.stderr b/tests/compile-fail/dangling_pointers/out_of_bounds_read1.stderr new file mode 100644 index 000000000000..1982b07066b1 --- /dev/null +++ b/tests/compile-fail/dangling_pointers/out_of_bounds_read1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 2, so pointer to 1 byte starting at offset 5 is out-of-bounds + --> $DIR/out_of_bounds_read1.rs:LL:CC + | +LL | let x = unsafe { *v.as_ptr().wrapping_offset(5) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 2, so pointer to 1 byte starting at offset 5 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/out_of_bounds_read1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/out_of_bounds_read2.stderr b/tests/compile-fail/dangling_pointers/out_of_bounds_read2.stderr new file mode 100644 index 000000000000..b70ce44c48a0 --- /dev/null +++ b/tests/compile-fail/dangling_pointers/out_of_bounds_read2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 2, so pointer to 1 byte starting at offset 5 is out-of-bounds + --> $DIR/out_of_bounds_read2.rs:LL:CC + | +LL | let x = unsafe { *v.as_ptr().wrapping_offset(5) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 2, so pointer to 1 byte starting at offset 5 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/out_of_bounds_read2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/stack_temporary.stderr b/tests/compile-fail/dangling_pointers/stack_temporary.stderr new file mode 100644 index 000000000000..f4f84765be54 --- /dev/null +++ b/tests/compile-fail/dangling_pointers/stack_temporary.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> $DIR/stack_temporary.rs:LL:CC + | +LL | let val = *x; + | ^^ pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/stack_temporary.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/storage_dead_dangling.stderr b/tests/compile-fail/dangling_pointers/storage_dead_dangling.stderr new file mode 100644 index 000000000000..aed14105ad07 --- /dev/null +++ b/tests/compile-fail/dangling_pointers/storage_dead_dangling.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> $DIR/storage_dead_dangling.rs:LL:CC + | +LL | unsafe { &mut *(LEAK as *mut i32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `evil` at $DIR/storage_dead_dangling.rs:LL:CC +note: inside `main` at $DIR/storage_dead_dangling.rs:LL:CC + --> $DIR/storage_dead_dangling.rs:LL:CC + | +LL | evil(); + | ^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/wild_pointer_deref.rs b/tests/compile-fail/dangling_pointers/wild_pointer_deref.rs index 2749ccfc0a02..eebaea48ba67 100644 --- a/tests/compile-fail/dangling_pointers/wild_pointer_deref.rs +++ b/tests/compile-fail/dangling_pointers/wild_pointer_deref.rs @@ -1,5 +1,5 @@ fn main() { let p = 44 as *const i32; - let x = unsafe { *p }; //~ ERROR 0x2c is not a valid pointer + let x = unsafe { *p }; //~ ERROR is not a valid pointer panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/dangling_pointers/wild_pointer_deref.stderr b/tests/compile-fail/dangling_pointers/wild_pointer_deref.stderr new file mode 100644 index 000000000000..b20f310da083 --- /dev/null +++ b/tests/compile-fail/dangling_pointers/wild_pointer_deref.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: 0x2c is not a valid pointer + --> $DIR/wild_pointer_deref.rs:LL:CC + | +LL | let x = unsafe { *p }; + | ^^ dereferencing pointer failed: 0x2c is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/wild_pointer_deref.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/data_race/alloc_read_race.stderr b/tests/compile-fail/data_race/alloc_read_race.stderr new file mode 100644 index 000000000000..9d9006966b33 --- /dev/null +++ b/tests/compile-fail/data_race/alloc_read_race.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Read on Thread(id = 2) and Allocate on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/alloc_read_race.rs:LL:CC + | +LL | *pointer.load(Ordering::Relaxed) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Read on Thread(id = 2) and Allocate on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/alloc_read_race.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/alloc_write_race.stderr b/tests/compile-fail/data_race/alloc_write_race.stderr new file mode 100644 index 000000000000..318895cae6b0 --- /dev/null +++ b/tests/compile-fail/data_race/alloc_write_race.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Allocate on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/alloc_write_race.rs:LL:CC + | +LL | *pointer.load(Ordering::Relaxed) = 2; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Write on Thread(id = 2) and Allocate on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/alloc_write_race.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/atomic_read_na_write_race1.stderr b/tests/compile-fail/data_race/atomic_read_na_write_race1.stderr new file mode 100644 index 000000000000..09d7accb0543 --- /dev/null +++ b/tests/compile-fail/data_race/atomic_read_na_write_race1.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Atomic Load on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/atomic_read_na_write_race1.rs:LL:CC + | +LL | atomic_load(c.0 as *mut usize) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Load on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/atomic_read_na_write_race1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/atomic_read_na_write_race2.stderr b/tests/compile-fail/data_race/atomic_read_na_write_race2.stderr new file mode 100644 index 000000000000..739ce83d0b07 --- /dev/null +++ b/tests/compile-fail/data_race/atomic_read_na_write_race2.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Atomic Load on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/atomic_read_na_write_race2.rs:LL:CC + | +LL | *atomic_ref.get_mut() = 32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Write on Thread(id = 2) and Atomic Load on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/atomic_read_na_write_race2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/atomic_write_na_read_race1.stderr b/tests/compile-fail/data_race/atomic_write_na_read_race1.stderr new file mode 100644 index 000000000000..6d67f58aaee4 --- /dev/null +++ b/tests/compile-fail/data_race/atomic_write_na_read_race1.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Read on Thread(id = 2) and Atomic Store on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/atomic_write_na_read_race1.rs:LL:CC + | +LL | *atomic_ref.get_mut() + | ^^^^^^^^^^^^^^^^^^^^^ Data race detected between Read on Thread(id = 2) and Atomic Store on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/atomic_write_na_read_race1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/atomic_write_na_read_race2.stderr b/tests/compile-fail/data_race/atomic_write_na_read_race2.stderr new file mode 100644 index 000000000000..d9950ebcb75b --- /dev/null +++ b/tests/compile-fail/data_race/atomic_write_na_read_race2.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Atomic Store on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/atomic_write_na_read_race2.rs:LL:CC + | +LL | atomic_store(c.0 as *mut usize, 32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Store on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/atomic_write_na_read_race2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/atomic_write_na_write_race1.stderr b/tests/compile-fail/data_race/atomic_write_na_write_race1.stderr new file mode 100644 index 000000000000..29ccf7021253 --- /dev/null +++ b/tests/compile-fail/data_race/atomic_write_na_write_race1.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Atomic Store on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/atomic_write_na_write_race1.rs:LL:CC + | +LL | atomic_store(c.0 as *mut usize, 64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Store on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/atomic_write_na_write_race1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/atomic_write_na_write_race2.stderr b/tests/compile-fail/data_race/atomic_write_na_write_race2.stderr new file mode 100644 index 000000000000..5488f05de031 --- /dev/null +++ b/tests/compile-fail/data_race/atomic_write_na_write_race2.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Atomic Store on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/atomic_write_na_write_race2.rs:LL:CC + | +LL | *atomic_ref.get_mut() = 32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Write on Thread(id = 2) and Atomic Store on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/atomic_write_na_write_race2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/dangling_thread_async_race.stderr b/tests/compile-fail/data_race/dangling_thread_async_race.stderr new file mode 100644 index 000000000000..eccc243d696e --- /dev/null +++ b/tests/compile-fail/data_race/dangling_thread_async_race.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Write on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/dangling_thread_async_race.rs:LL:CC + | +LL | *c.0 = 64; + | ^^^^^^^^^ Data race detected between Write on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/dangling_thread_async_race.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/dangling_thread_race.stderr b/tests/compile-fail/data_race/dangling_thread_race.stderr new file mode 100644 index 000000000000..4dffeb14233a --- /dev/null +++ b/tests/compile-fail/data_race/dangling_thread_race.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/dangling_thread_race.rs:LL:CC + | +LL | *c.0 = 64; + | ^^^^^^^^^ Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/dangling_thread_race.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/dealloc_read_race1.stderr b/tests/compile-fail/data_race/dealloc_read_race1.stderr new file mode 100644 index 000000000000..37196021ead9 --- /dev/null +++ b/tests/compile-fail/data_race/dealloc_read_race1.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/dealloc_read_race1.rs:LL:CC + | +LL | __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/dealloc_read_race1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/dealloc_read_race2.stderr b/tests/compile-fail/data_race/dealloc_read_race2.stderr new file mode 100644 index 000000000000..03fb5dbea90d --- /dev/null +++ b/tests/compile-fail/data_race/dealloc_read_race2.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> $DIR/dealloc_read_race2.rs:LL:CC + | +LL | *ptr.0 + | ^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/dealloc_read_race2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack.stderr b/tests/compile-fail/data_race/dealloc_read_race_stack.stderr new file mode 100644 index 000000000000..055724fe2979 --- /dev/null +++ b/tests/compile-fail/data_race/dealloc_read_race_stack.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/dealloc_read_race_stack.rs:LL:CC + | +LL | } + | ^ Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/dealloc_read_race_stack.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/dealloc_write_race1.stderr b/tests/compile-fail/data_race/dealloc_write_race1.stderr new file mode 100644 index 000000000000..7160f49af697 --- /dev/null +++ b/tests/compile-fail/data_race/dealloc_write_race1.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/dealloc_write_race1.rs:LL:CC + | +LL | __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/dealloc_write_race1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/dealloc_write_race2.stderr b/tests/compile-fail/data_race/dealloc_write_race2.stderr new file mode 100644 index 000000000000..cb0d0af8672b --- /dev/null +++ b/tests/compile-fail/data_race/dealloc_write_race2.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> $DIR/dealloc_write_race2.rs:LL:CC + | +LL | *ptr.0 = 2; + | ^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/dealloc_write_race2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack.stderr b/tests/compile-fail/data_race/dealloc_write_race_stack.stderr new file mode 100644 index 000000000000..05a8e1a8b7e2 --- /dev/null +++ b/tests/compile-fail/data_race/dealloc_write_race_stack.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/dealloc_write_race_stack.rs:LL:CC + | +LL | } + | ^ Data race detected between Deallocate on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/dealloc_write_race_stack.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/enable_after_join_to_main.stderr b/tests/compile-fail/data_race/enable_after_join_to_main.stderr new file mode 100644 index 000000000000..e612e08ade4f --- /dev/null +++ b/tests/compile-fail/data_race/enable_after_join_to_main.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Write on Thread(id = 6) and Write on Thread(id = 5) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/enable_after_join_to_main.rs:LL:CC + | +LL | *c.0 = 64; + | ^^^^^^^^^ Data race detected between Write on Thread(id = 6) and Write on Thread(id = 5) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/enable_after_join_to_main.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/read_write_race.stderr b/tests/compile-fail/data_race/read_write_race.stderr new file mode 100644 index 000000000000..fc04141830bf --- /dev/null +++ b/tests/compile-fail/data_race/read_write_race.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/read_write_race.rs:LL:CC + | +LL | *c.0 = 64; + | ^^^^^^^^^ Data race detected between Write on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/read_write_race.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/read_write_race_stack.stderr b/tests/compile-fail/data_race/read_write_race_stack.stderr new file mode 100644 index 000000000000..aad63731ca05 --- /dev/null +++ b/tests/compile-fail/data_race/read_write_race_stack.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/read_write_race_stack.rs:LL:CC + | +LL | stack_var + | ^^^^^^^^^ Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/read_write_race_stack.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/relax_acquire_race.stderr b/tests/compile-fail/data_race/relax_acquire_race.stderr new file mode 100644 index 000000000000..a437120c891d --- /dev/null +++ b/tests/compile-fail/data_race/relax_acquire_race.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/relax_acquire_race.rs:LL:CC + | +LL | *c.0 + | ^^^^ Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/relax_acquire_race.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/release_seq_race.stderr b/tests/compile-fail/data_race/release_seq_race.stderr new file mode 100644 index 000000000000..1a1c7ac64f78 --- /dev/null +++ b/tests/compile-fail/data_race/release_seq_race.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/release_seq_race.rs:LL:CC + | +LL | *c.0 + | ^^^^ Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/release_seq_race.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/release_seq_race_same_thread.stderr b/tests/compile-fail/data_race/release_seq_race_same_thread.stderr new file mode 100644 index 000000000000..f357c0647d4d --- /dev/null +++ b/tests/compile-fail/data_race/release_seq_race_same_thread.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Read on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/release_seq_race_same_thread.rs:LL:CC + | +LL | *c.0 + | ^^^^ Data race detected between Read on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/release_seq_race_same_thread.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/rmw_race.stderr b/tests/compile-fail/data_race/rmw_race.stderr new file mode 100644 index 000000000000..dd3692c6dcc8 --- /dev/null +++ b/tests/compile-fail/data_race/rmw_race.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/rmw_race.rs:LL:CC + | +LL | *c.0 + | ^^^^ Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/rmw_race.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/write_write_race.stderr b/tests/compile-fail/data_race/write_write_race.stderr new file mode 100644 index 000000000000..dafee7dbf8cf --- /dev/null +++ b/tests/compile-fail/data_race/write_write_race.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/write_write_race.rs:LL:CC + | +LL | *c.0 = 64; + | ^^^^^^^^^ Data race detected between Write on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/write_write_race.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/write_write_race_stack.stderr b/tests/compile-fail/data_race/write_write_race_stack.stderr new file mode 100644 index 000000000000..8d113673ac15 --- /dev/null +++ b/tests/compile-fail/data_race/write_write_race_stack.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Write on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/write_write_race_stack.rs:LL:CC + | +LL | stack_var = 1usize; + | ^^^^^^^^^^^^^^^^^^ Data race detected between Write on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/write_write_race_stack.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/environ-gets-deallocated.stderr b/tests/compile-fail/environ-gets-deallocated.stderr new file mode 100644 index 000000000000..640d953a811d --- /dev/null +++ b/tests/compile-fail/environ-gets-deallocated.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> $DIR/environ-gets-deallocated.rs:LL:CC + | +LL | let _y = unsafe { *pointer }; + | ^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/environ-gets-deallocated.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/erroneous_const.stderr b/tests/compile-fail/erroneous_const.stderr new file mode 100644 index 000000000000..e1758ad657de --- /dev/null +++ b/tests/compile-fail/erroneous_const.stderr @@ -0,0 +1,26 @@ +error[E0080]: evaluation of `PrintName::::VOID` failed + --> $DIR/erroneous_const.rs:LL:CC + | +LL | const VOID: ! = panic!(); + | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/erroneous_const.rs:LL:CC + | + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: post-monomorphization error: encountered constants with type errors, stopping evaluation + --> $DIR/erroneous_const.rs:LL:CC + | +LL | let _ = PrintName::::VOID; + | ^^^^^^^^^^^^^^^^^^^^ encountered constants with type errors, stopping evaluation + | + = note: inside `no_codegen::` at $DIR/erroneous_const.rs:LL:CC +note: inside `main` at $DIR/erroneous_const.rs:LL:CC + --> $DIR/erroneous_const.rs:LL:CC + | +LL | no_codegen::(); + | ^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/compile-fail/erroneous_const2.stderr b/tests/compile-fail/erroneous_const2.stderr new file mode 100644 index 000000000000..d5c89a8e82bf --- /dev/null +++ b/tests/compile-fail/erroneous_const2.stderr @@ -0,0 +1,41 @@ +error: any use of this value will cause an error + --> $DIR/erroneous_const2.rs:LL:CC + | +LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; + | ------------------^^^^^--------------------------- + | | + | attempt to compute `5_u32 - 6_u32`, which would overflow + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + +error[E0080]: evaluation of constant value failed + --> $DIR/erroneous_const2.rs:LL:CC + | +LL | println!("{}", FOO); + | ^^^ referenced constant has errors + +error: erroneous constant used + --> $DIR/erroneous_const2.rs:LL:CC + | +LL | println!("{}", FOO); + | ^^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: post-monomorphization error: referenced constant has errors + --> $DIR/erroneous_const2.rs:LL:CC + | +LL | println!("{}", FOO); + | ^^^ referenced constant has errors + | + = note: inside `main` at $DIR/erroneous_const2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/compile-fail/extern_static.stderr b/tests/compile-fail/extern_static.stderr new file mode 100644 index 000000000000..e673d074bc84 --- /dev/null +++ b/tests/compile-fail/extern_static.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: `extern` static `FOO` from crate `extern_static` is not supported by Miri + --> $DIR/extern_static.rs:LL:CC + | +LL | let _val = unsafe { std::ptr::addr_of!(FOO) }; + | ^^^ `extern` static `FOO` from crate `extern_static` is not supported by Miri + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/extern_static.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/fast_math_both.stderr b/tests/compile-fail/fast_math_both.stderr new file mode 100644 index 000000000000..542044df4d9c --- /dev/null +++ b/tests/compile-fail/fast_math_both.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `fsub_fast` intrinsic called with non-finite value as both parameters + --> $DIR/fast_math_both.rs:LL:CC + | +LL | ...: f32 = core::intrinsics::fsub_fast(f32::NAN, f32::NAN); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `fsub_fast` intrinsic called with non-finite value as both parameters + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/fast_math_both.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/fast_math_first.stderr b/tests/compile-fail/fast_math_first.stderr new file mode 100644 index 000000000000..74ba08dc8787 --- /dev/null +++ b/tests/compile-fail/fast_math_first.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `frem_fast` intrinsic called with non-finite value as first parameter + --> $DIR/fast_math_first.rs:LL:CC + | +LL | ... let _x: f32 = core::intrinsics::frem_fast(f32::NAN, 3.2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `frem_fast` intrinsic called with non-finite value as first parameter + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/fast_math_first.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/fast_math_second.stderr b/tests/compile-fail/fast_math_second.stderr new file mode 100644 index 000000000000..cbb059a07f68 --- /dev/null +++ b/tests/compile-fail/fast_math_second.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `fmul_fast` intrinsic called with non-finite value as second parameter + --> $DIR/fast_math_second.rs:LL:CC + | +LL | ...f32 = core::intrinsics::fmul_fast(3.4f32, f32::INFINITY); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `fmul_fast` intrinsic called with non-finite value as second parameter + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/fast_math_second.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/fs/close_stdout.stderr b/tests/compile-fail/fs/close_stdout.stderr new file mode 100644 index 000000000000..79fa0458b4bd --- /dev/null +++ b/tests/compile-fail/fs/close_stdout.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: stdout cannot be closed + --> $DIR/close_stdout.rs:LL:CC + | +LL | libc::close(1); + | ^^^^^^^^^^^^^^ stdout cannot be closed + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/close_stdout.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/fs/isolated_file.stderr b/tests/compile-fail/fs/isolated_file.stderr new file mode 100644 index 000000000000..056a67259c1a --- /dev/null +++ b/tests/compile-fail/fs/isolated_file.stderr @@ -0,0 +1,22 @@ +error: unsupported operation: `open` not available when isolation is enabled + | + = help: pass the flag `-Zmiri-disable-isolation` to disable isolation; + = help: or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning + + = note: inside closure at rustc_src/src/sys/PLATFORM/fs.rs:LL:CC + = note: inside `std::sys::PLATFORM::cvt_r::` at rustc_src/src/sys/PLATFORM/mod.rs:LL:CC + = note: inside `std::sys::PLATFORM::fs::File::open_c` at rustc_src/src/sys/PLATFORM/fs.rs:LL:CC + = note: inside `std::sys::PLATFORM::fs::File::open` at rustc_src/src/sys/PLATFORM/fs.rs:LL:CC + = note: inside `std::fs::OpenOptions::_open` at rustc_src/src/fs.rs:LL:CC + = note: inside `std::fs::OpenOptions::open::<&std::path::Path>` at rustc_src/src/fs.rs:LL:CC + = note: inside `std::fs::File::open::<&str>` at rustc_src/src/fs.rs:LL:CC +note: inside `main` at $DIR/isolated_file.rs:LL:CC + --> $DIR/isolated_file.rs:LL:CC + | +LL | let _file = std::fs::File::open("file.txt").unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/fs/isolated_stdin.stderr b/tests/compile-fail/fs/isolated_stdin.stderr new file mode 100644 index 000000000000..4fbd11e7cd9b --- /dev/null +++ b/tests/compile-fail/fs/isolated_stdin.stderr @@ -0,0 +1,15 @@ +error: unsupported operation: `read` from stdin not available when isolation is enabled + --> $DIR/isolated_stdin.rs:LL:CC + | +LL | libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `read` from stdin not available when isolation is enabled + | + = help: pass the flag `-Zmiri-disable-isolation` to disable isolation; + = help: or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning + + = note: inside `main` at $DIR/isolated_stdin.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/fs/read_from_stdout.stderr b/tests/compile-fail/fs/read_from_stdout.stderr new file mode 100644 index 000000000000..45573c471e2a --- /dev/null +++ b/tests/compile-fail/fs/read_from_stdout.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: cannot read from stdout + --> $DIR/read_from_stdout.rs:LL:CC + | +LL | libc::read(1, bytes.as_mut_ptr() as *mut libc::c_void, 512); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot read from stdout + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/read_from_stdout.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/fs/unix_open_missing_required_mode.stderr b/tests/compile-fail/fs/unix_open_missing_required_mode.stderr new file mode 100644 index 000000000000..700323433124 --- /dev/null +++ b/tests/compile-fail/fs/unix_open_missing_required_mode.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: incorrect number of arguments for `open` with `O_CREAT`: got 2, expected at least 3 + --> $DIR/unix_open_missing_required_mode.rs:LL:CC + | +LL | ...safe { libc::open(name_ptr, libc::O_CREAT) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of arguments for `open` with `O_CREAT`: got 2, expected at least 3 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `test_file_open_missing_needed_mode` at $DIR/unix_open_missing_required_mode.rs:LL:CC +note: inside `main` at $DIR/unix_open_missing_required_mode.rs:LL:CC + --> $DIR/unix_open_missing_required_mode.rs:LL:CC + | +LL | test_file_open_missing_needed_mode(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/fs/unix_open_too_many_args.stderr b/tests/compile-fail/fs/unix_open_too_many_args.stderr new file mode 100644 index 000000000000..f71a44d34dab --- /dev/null +++ b/tests/compile-fail/fs/unix_open_too_many_args.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: incorrect number of arguments for `open`: got 4, expected 2 or 3 + --> $DIR/unix_open_too_many_args.rs:15:24 + | +LL | let _fd = unsafe { libc::open(name_ptr, libc::O_RDONLY, 0, 0) }; //~ ERROR Undefined Behavior: incorrect number of arguments for `ope... + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of arguments for `open`: got 4, expected 2 or 3 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `test_open_too_many_args` at $DIR/unix_open_too_many_args.rs:15:24 +note: inside `main` at $DIR/unix_open_too_many_args.rs:9:5 + --> $DIR/unix_open_too_many_args.rs:9:5 + | +LL | test_open_too_many_args(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/fs/write_to_stdin.stderr b/tests/compile-fail/fs/write_to_stdin.stderr new file mode 100644 index 000000000000..1cbc3eef66ae --- /dev/null +++ b/tests/compile-fail/fs/write_to_stdin.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: cannot write to stdin + --> $DIR/write_to_stdin.rs:LL:CC + | +LL | libc::write(0, bytes.as_ptr() as *const libc::c_void, 5); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot write to stdin + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/write_to_stdin.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/check_arg_abi.stderr b/tests/compile-fail/function_calls/check_arg_abi.stderr new file mode 100644 index 000000000000..9ee7d301b19f --- /dev/null +++ b/tests/compile-fail/function_calls/check_arg_abi.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calling a function with ABI C using caller ABI Rust + --> $DIR/check_arg_abi.rs:LL:CC + | +LL | let _ = malloc(0); + | ^^^^^^^^^ calling a function with ABI C using caller ABI Rust + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/check_arg_abi.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/check_arg_count_abort.stderr b/tests/compile-fail/function_calls/check_arg_count_abort.stderr new file mode 100644 index 000000000000..c7682578f99b --- /dev/null +++ b/tests/compile-fail/function_calls/check_arg_count_abort.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: incorrect number of arguments: got 1, expected 0 + --> $DIR/check_arg_count_abort.rs:LL:CC + | +LL | abort(1); + | ^^^^^^^^ incorrect number of arguments: got 1, expected 0 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/check_arg_count_abort.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/check_arg_count_too_few_args.stderr b/tests/compile-fail/function_calls/check_arg_count_too_few_args.stderr new file mode 100644 index 000000000000..b7d6bbfd5719 --- /dev/null +++ b/tests/compile-fail/function_calls/check_arg_count_too_few_args.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: incorrect number of arguments: got 0, expected 1 + --> $DIR/check_arg_count_too_few_args.rs:LL:CC + | +LL | let _ = malloc(); + | ^^^^^^^^ incorrect number of arguments: got 0, expected 1 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/check_arg_count_too_few_args.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/check_arg_count_too_many_args.stderr b/tests/compile-fail/function_calls/check_arg_count_too_many_args.stderr new file mode 100644 index 000000000000..33cc5750b890 --- /dev/null +++ b/tests/compile-fail/function_calls/check_arg_count_too_many_args.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: incorrect number of arguments: got 2, expected 1 + --> $DIR/check_arg_count_too_many_args.rs:LL:CC + | +LL | let _ = malloc(1, 2); + | ^^^^^^^^^^^^ incorrect number of arguments: got 2, expected 1 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/check_arg_count_too_many_args.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/check_callback_abi.stderr b/tests/compile-fail/function_calls/check_callback_abi.stderr new file mode 100644 index 000000000000..ea7c2bb6b4ae --- /dev/null +++ b/tests/compile-fail/function_calls/check_callback_abi.stderr @@ -0,0 +1,19 @@ +error: Undefined Behavior: calling a function with ABI C using caller ABI Rust + --> $DIR/check_callback_abi.rs:LL:CC + | +LL | / std::intrinsics::r#try( +LL | | std::mem::transmute::(try_fn), +LL | | std::ptr::null_mut(), +LL | | |_, _| unreachable!(), +LL | | ); + | |_________^ calling a function with ABI C using caller ABI Rust + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/check_callback_abi.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.cache.stderr b/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.cache.stderr new file mode 100644 index 000000000000..bf0d27d91576 --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.cache.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calling a function with calling convention Rust using calling convention C + --> $DIR/exported_symbol_abi_mismatch.rs:LL:CC + | +LL | unsafe { foo() } + | ^^^^^ calling a function with calling convention Rust using calling convention C + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/exported_symbol_abi_mismatch.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr b/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr new file mode 100644 index 000000000000..ee810af315fc --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calling a function with calling convention Rust using calling convention C + --> $DIR/exported_symbol_abi_mismatch.rs:LL:CC + | +LL | unsafe { std::mem::transmute::(foo)() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with calling convention Rust using calling convention C + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/exported_symbol_abi_mismatch.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr b/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr new file mode 100644 index 000000000000..bf0d27d91576 --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calling a function with calling convention Rust using calling convention C + --> $DIR/exported_symbol_abi_mismatch.rs:LL:CC + | +LL | unsafe { foo() } + | ^^^^^ calling a function with calling convention Rust using calling convention C + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/exported_symbol_abi_mismatch.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind1.stderr b/tests/compile-fail/function_calls/exported_symbol_bad_unwind1.stderr new file mode 100644 index 000000000000..8cd74f1fd86d --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_bad_unwind1.stderr @@ -0,0 +1,17 @@ +thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_bad_unwind1.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +error: Undefined Behavior: unwinding past a stack frame that does not allow unwinding + --> $DIR/exported_symbol_bad_unwind1.rs:LL:CC + | +LL | unsafe { unwind() } + | ^^^^^^^^ unwinding past a stack frame that does not allow unwinding + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/exported_symbol_bad_unwind1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.both.stderr b/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.both.stderr new file mode 100644 index 000000000000..48df075ba622 --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.both.stderr @@ -0,0 +1,23 @@ +thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_bad_unwind2.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +error: abnormal termination: the program aborted execution + --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC + | +LL | / extern "C-unwind" fn nounwind() { +LL | | //[definition]~^ ERROR abnormal termination: the program aborted execution +LL | | //[both]~^^ ERROR abnormal termination: the program aborted execution +LL | | panic!(); +LL | | } + | |_^ the program aborted execution + | + = note: inside `nounwind` at $DIR/exported_symbol_bad_unwind2.rs:LL:CC +note: inside `main` at $DIR/exported_symbol_bad_unwind2.rs:LL:CC + --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC + | +LL | unsafe { nounwind() } + | ^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.definition.stderr b/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.definition.stderr new file mode 100644 index 000000000000..48df075ba622 --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.definition.stderr @@ -0,0 +1,23 @@ +thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_bad_unwind2.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +error: abnormal termination: the program aborted execution + --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC + | +LL | / extern "C-unwind" fn nounwind() { +LL | | //[definition]~^ ERROR abnormal termination: the program aborted execution +LL | | //[both]~^^ ERROR abnormal termination: the program aborted execution +LL | | panic!(); +LL | | } + | |_^ the program aborted execution + | + = note: inside `nounwind` at $DIR/exported_symbol_bad_unwind2.rs:LL:CC +note: inside `main` at $DIR/exported_symbol_bad_unwind2.rs:LL:CC + --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC + | +LL | unsafe { nounwind() } + | ^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr b/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr new file mode 100644 index 000000000000..fac42bf66ae4 --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr @@ -0,0 +1,17 @@ +thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_bad_unwind2.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +error: Undefined Behavior: unwinding past a stack frame that does not allow unwinding + --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC + | +LL | unsafe { nounwind() } + | ^^^^^^^^^^ unwinding past a stack frame that does not allow unwinding + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/exported_symbol_bad_unwind2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/exported_symbol_clashing.stderr b/tests/compile-fail/function_calls/exported_symbol_clashing.stderr new file mode 100644 index 000000000000..1ddd882c4cb3 --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_clashing.stderr @@ -0,0 +1,22 @@ +error: multiple definitions of symbol `foo` + --> $DIR/exported_symbol_clashing.rs:LL:CC + | +LL | unsafe { foo() } + | ^^^^^ multiple definitions of symbol `foo` + | +help: it's first defined here, in crate `exported_symbol_clashing` + --> $DIR/exported_symbol_clashing.rs:LL:CC + | +LL | fn foo() {} + | ^^^^^^^^ +help: then it's defined here again, in crate `exported_symbol_clashing` + --> $DIR/exported_symbol_clashing.rs:LL:CC + | +LL | fn bar() {} + | ^^^^^^^^ + = note: inside `main` at $DIR/exported_symbol_clashing.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/exported_symbol_shim_clashing.stderr b/tests/compile-fail/function_calls/exported_symbol_shim_clashing.stderr new file mode 100644 index 000000000000..fa25b4e3f347 --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_shim_clashing.stderr @@ -0,0 +1,20 @@ +error: found `malloc` symbol definition that clashes with a built-in shim + --> $DIR/exported_symbol_shim_clashing.rs:LL:CC + | +LL | malloc(0); + | ^^^^^^^^^ found `malloc` symbol definition that clashes with a built-in shim + | +help: the `malloc` symbol is defined here + --> $DIR/exported_symbol_shim_clashing.rs:LL:CC + | +LL | / extern "C" fn malloc(_: usize) -> *mut std::ffi::c_void { +LL | | +LL | | unreachable!() +LL | | } + | |_^ + = note: inside `main` at $DIR/exported_symbol_shim_clashing.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/exported_symbol_wrong_arguments.stderr b/tests/compile-fail/function_calls/exported_symbol_wrong_arguments.stderr new file mode 100644 index 000000000000..fe5498c85d7f --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_wrong_arguments.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calling a function with more arguments than it expected + --> $DIR/exported_symbol_wrong_arguments.rs:LL:CC + | +LL | unsafe { foo(1) } + | ^^^^^^ calling a function with more arguments than it expected + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/exported_symbol_wrong_arguments.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/exported_symbol_wrong_type.stderr b/tests/compile-fail/function_calls/exported_symbol_wrong_type.stderr new file mode 100644 index 000000000000..f40270490871 --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_wrong_type.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: attempt to call an exported symbol that is not defined as a function + --> $DIR/exported_symbol_wrong_type.rs:LL:CC + | +LL | unsafe { FOO() } + | ^^^^^ attempt to call an exported symbol that is not defined as a function + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/exported_symbol_wrong_type.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_pointers/cast_box_int_to_fn_ptr.stderr b/tests/compile-fail/function_pointers/cast_box_int_to_fn_ptr.stderr new file mode 100644 index 000000000000..13f8ef378243 --- /dev/null +++ b/tests/compile-fail/function_pointers/cast_box_int_to_fn_ptr.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: using ALLOC as function pointer but it does not point to a function + --> $DIR/cast_box_int_to_fn_ptr.rs:LL:CC + | +LL | (*g)(42) + | ^^^^^^^^ using ALLOC as function pointer but it does not point to a function + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/cast_box_int_to_fn_ptr.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr1.stderr b/tests/compile-fail/function_pointers/cast_fn_ptr1.stderr new file mode 100644 index 000000000000..765dbb6578ab --- /dev/null +++ b/tests/compile-fail/function_pointers/cast_fn_ptr1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calling a function with more arguments than it expected + --> $DIR/cast_fn_ptr1.rs:LL:CC + | +LL | g(42) + | ^^^^^ calling a function with more arguments than it expected + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/cast_fn_ptr1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr2.stderr b/tests/compile-fail/function_pointers/cast_fn_ptr2.stderr new file mode 100644 index 000000000000..123d0e1b0bb6 --- /dev/null +++ b/tests/compile-fail/function_pointers/cast_fn_ptr2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calling a function with argument of type (i32, i32) passing data of type i32 + --> $DIR/cast_fn_ptr2.rs:LL:CC + | +LL | g(42) + | ^^^^^ calling a function with argument of type (i32, i32) passing data of type i32 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/cast_fn_ptr2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr3.stderr b/tests/compile-fail/function_pointers/cast_fn_ptr3.stderr new file mode 100644 index 000000000000..51f6ca0713d7 --- /dev/null +++ b/tests/compile-fail/function_pointers/cast_fn_ptr3.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calling a function with fewer arguments than it requires + --> $DIR/cast_fn_ptr3.rs:LL:CC + | +LL | g() + | ^^^ calling a function with fewer arguments than it requires + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/cast_fn_ptr3.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr4.stderr b/tests/compile-fail/function_pointers/cast_fn_ptr4.stderr new file mode 100644 index 000000000000..515f00ec3929 --- /dev/null +++ b/tests/compile-fail/function_pointers/cast_fn_ptr4.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calling a function with argument of type *const [i32] passing data of type *const i32 + --> $DIR/cast_fn_ptr4.rs:LL:CC + | +LL | g(&42 as *const i32) + | ^^^^^^^^^^^^^^^^^^^^ calling a function with argument of type *const [i32] passing data of type *const i32 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/cast_fn_ptr4.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr5.stderr b/tests/compile-fail/function_pointers/cast_fn_ptr5.stderr new file mode 100644 index 000000000000..2978866c9290 --- /dev/null +++ b/tests/compile-fail/function_pointers/cast_fn_ptr5.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calling a function with return type u32 passing return place of type () + --> $DIR/cast_fn_ptr5.rs:LL:CC + | +LL | g() + | ^^^ calling a function with return type u32 passing return place of type () + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/cast_fn_ptr5.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs b/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs index 299fd5ae49e0..b206cb9ab360 100644 --- a/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs +++ b/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs @@ -6,5 +6,5 @@ fn main() { std::mem::transmute::(42) }; - g(42) //~ ERROR 0x2a is not a valid pointer + g(42) //~ ERROR not a valid pointer } diff --git a/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.stderr b/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.stderr new file mode 100644 index 000000000000..25501e74913d --- /dev/null +++ b/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: 0x2a is not a valid pointer + --> $DIR/cast_int_to_fn_ptr.rs:LL:CC + | +LL | g(42) + | ^^^^^ 0x2a is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/cast_int_to_fn_ptr.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_pointers/deref_fn_ptr.stderr b/tests/compile-fail/function_pointers/deref_fn_ptr.stderr new file mode 100644 index 000000000000..1e3da2726d4b --- /dev/null +++ b/tests/compile-fail/function_pointers/deref_fn_ptr.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: accessing ALLOC which contains a function + --> $DIR/deref_fn_ptr.rs:LL:CC + | +LL | *std::mem::transmute::(f) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing ALLOC which contains a function + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/deref_fn_ptr.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_pointers/execute_memory.stderr b/tests/compile-fail/function_pointers/execute_memory.stderr new file mode 100644 index 000000000000..daa6277b85e4 --- /dev/null +++ b/tests/compile-fail/function_pointers/execute_memory.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: using ALLOC as function pointer but it does not point to a function + --> $DIR/execute_memory.rs:LL:CC + | +LL | f() + | ^^^ using ALLOC as function pointer but it does not point to a function + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/execute_memory.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_pointers/fn_ptr_offset.stderr b/tests/compile-fail/function_pointers/fn_ptr_offset.stderr new file mode 100644 index 000000000000..0f3baab1b512 --- /dev/null +++ b/tests/compile-fail/function_pointers/fn_ptr_offset.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: using ALLOC+0x1 as function pointer but it does not point to a function + --> $DIR/fn_ptr_offset.rs:LL:CC + | +LL | x(); + | ^^^ using ALLOC+0x1 as function pointer but it does not point to a function + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/fn_ptr_offset.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/generator-pinned-moved.stderr b/tests/compile-fail/generator-pinned-moved.stderr new file mode 100644 index 000000000000..98ccf3097c29 --- /dev/null +++ b/tests/compile-fail/generator-pinned-moved.stderr @@ -0,0 +1,26 @@ +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> $DIR/generator-pinned-moved.rs:LL:CC + | +LL | *num += 1; + | ^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/generator-pinned-moved.rs:LL:CC +note: inside ` as std::iter::Iterator>::next` at $DIR/generator-pinned-moved.rs:LL:CC + --> $DIR/generator-pinned-moved.rs:LL:CC + | +LL | match me.resume(()) { + | ^^^^^^^^^^^^^ + = note: inside `> as std::iter::Iterator>::next` at rustc_src/src/boxed.rs:LL:CC +note: inside `main` at $DIR/generator-pinned-moved.rs:LL:CC + --> $DIR/generator-pinned-moved.rs:LL:CC + | +LL | generator_iterator_2.next(); // and use moved value + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/assume.stderr b/tests/compile-fail/intrinsics/assume.stderr new file mode 100644 index 000000000000..e5059a699b10 --- /dev/null +++ b/tests/compile-fail/intrinsics/assume.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `assume` intrinsic called with `false` + --> $DIR/assume.rs:LL:CC + | +LL | std::intrinsics::assume(x > 42); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `assume` intrinsic called with `false` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/assume.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/copy_null.stderr b/tests/compile-fail/intrinsics/copy_null.stderr new file mode 100644 index 000000000000..461f529fa85d --- /dev/null +++ b/tests/compile-fail/intrinsics/copy_null.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: memory access failed: null pointer is not a valid pointer + --> $DIR/copy_null.rs:LL:CC + | +LL | unsafe { copy_nonoverlapping(std::ptr::null(), ptr, 0); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/copy_null.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/copy_overflow.stderr b/tests/compile-fail/intrinsics/copy_overflow.stderr new file mode 100644 index 000000000000..512184a36c18 --- /dev/null +++ b/tests/compile-fail/intrinsics/copy_overflow.stderr @@ -0,0 +1,17 @@ +error: Undefined Behavior: overflow computing total size of `copy` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::intrinsics::copy::` at rustc_src/src/intrinsics.rs:LL:CC + = note: inside `std::ptr::mut_ptr::::copy_from` at rustc_src/src/ptr/mut_ptr.rs:LL:CC +note: inside `main` at $DIR/copy_overflow.rs:LL:CC + --> $DIR/copy_overflow.rs:LL:CC + | +LL | (&mut y as *mut i32).copy_from(&x, 1usize << (mem::size_of::() * 8 - 1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/copy_overlapping.stderr b/tests/compile-fail/intrinsics/copy_overlapping.stderr new file mode 100644 index 000000000000..cba08d9b5c82 --- /dev/null +++ b/tests/compile-fail/intrinsics/copy_overlapping.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: copy_nonoverlapping called on overlapping ranges + --> $DIR/copy_overlapping.rs:LL:CC + | +LL | copy_nonoverlapping(a, b, 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ copy_nonoverlapping called on overlapping ranges + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/copy_overlapping.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/copy_unaligned.rs b/tests/compile-fail/intrinsics/copy_unaligned.rs index 84f4de93461e..7aff0adc407a 100644 --- a/tests/compile-fail/intrinsics/copy_unaligned.rs +++ b/tests/compile-fail/intrinsics/copy_unaligned.rs @@ -9,5 +9,5 @@ fn main() { let mut data = [0u16; 8]; let ptr = (&mut data[0] as *mut u16 as *mut u8).wrapping_add(1) as *mut u16; // Even copying 0 elements to something unaligned should error - unsafe { copy_nonoverlapping(&data[5], ptr, 0); } //~ ERROR accessing memory with alignment 1, but alignment 2 is required + unsafe { copy_nonoverlapping(&data[5], ptr, 0); } //~ ERROR accessing memory with alignment ALIGN, but alignment ALIGN is required } diff --git a/tests/compile-fail/intrinsics/copy_unaligned.stderr b/tests/compile-fail/intrinsics/copy_unaligned.stderr new file mode 100644 index 000000000000..b99588698d22 --- /dev/null +++ b/tests/compile-fail/intrinsics/copy_unaligned.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required + --> $DIR/copy_unaligned.rs:LL:CC + | +LL | unsafe { copy_nonoverlapping(&data[5], ptr, 0); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/copy_unaligned.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/ctlz_nonzero.stderr b/tests/compile-fail/intrinsics/ctlz_nonzero.stderr new file mode 100644 index 000000000000..0c895cf138e9 --- /dev/null +++ b/tests/compile-fail/intrinsics/ctlz_nonzero.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `ctlz_nonzero` called on 0 + --> $DIR/ctlz_nonzero.rs:LL:CC + | +LL | ctlz_nonzero(0u8); + | ^^^^^^^^^^^^^^^^^ `ctlz_nonzero` called on 0 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/ctlz_nonzero.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/cttz_nonzero.stderr b/tests/compile-fail/intrinsics/cttz_nonzero.stderr new file mode 100644 index 000000000000..5257668d53e9 --- /dev/null +++ b/tests/compile-fail/intrinsics/cttz_nonzero.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `cttz_nonzero` called on 0 + --> $DIR/cttz_nonzero.rs:LL:CC + | +LL | cttz_nonzero(0u8); + | ^^^^^^^^^^^^^^^^^ `cttz_nonzero` called on 0 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/cttz_nonzero.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/div-by-zero.stderr b/tests/compile-fail/intrinsics/div-by-zero.stderr new file mode 100644 index 000000000000..388f4aef7fa9 --- /dev/null +++ b/tests/compile-fail/intrinsics/div-by-zero.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dividing by zero + --> $DIR/div-by-zero.rs:LL:CC + | +LL | let _n = unchecked_div(1i64, 0); + | ^^^^^^^^^^^^^^^^^^^^^^ dividing by zero + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/div-by-zero.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/exact_div1.stderr b/tests/compile-fail/intrinsics/exact_div1.stderr new file mode 100644 index 000000000000..a0f03b201a8d --- /dev/null +++ b/tests/compile-fail/intrinsics/exact_div1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calculating the remainder with a divisor of zero + --> $DIR/exact_div1.rs:LL:CC + | +LL | unsafe { std::intrinsics::exact_div(2, 0); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calculating the remainder with a divisor of zero + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/exact_div1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/exact_div2.stderr b/tests/compile-fail/intrinsics/exact_div2.stderr new file mode 100644 index 000000000000..78a85c9caac6 --- /dev/null +++ b/tests/compile-fail/intrinsics/exact_div2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: exact_div: 2_u16 cannot be divided by 3_u16 without remainder + --> $DIR/exact_div2.rs:LL:CC + | +LL | unsafe { std::intrinsics::exact_div(2u16, 3); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: 2_u16 cannot be divided by 3_u16 without remainder + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/exact_div2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/exact_div3.stderr b/tests/compile-fail/intrinsics/exact_div3.stderr new file mode 100644 index 000000000000..3062b60d468e --- /dev/null +++ b/tests/compile-fail/intrinsics/exact_div3.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: exact_div: -19_i8 cannot be divided by 2_i8 without remainder + --> $DIR/exact_div3.rs:LL:CC + | +LL | unsafe { std::intrinsics::exact_div(-19i8, 2); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: -19_i8 cannot be divided by 2_i8 without remainder + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/exact_div3.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/exact_div4.stderr b/tests/compile-fail/intrinsics/exact_div4.stderr new file mode 100644 index 000000000000..1ae67ad87a5d --- /dev/null +++ b/tests/compile-fail/intrinsics/exact_div4.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: overflow in signed remainder (dividing MIN by -1) + --> $DIR/exact_div4.rs:LL:CC + | +LL | unsafe { std::intrinsics::exact_div(i64::MIN, -1); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/exact_div4.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_32_inf1.stderr b/tests/compile-fail/intrinsics/float_to_int_32_inf1.stderr new file mode 100644 index 000000000000..cdf232d93eb2 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_inf1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on +Inf which cannot be represented in target type `i32` + --> $DIR/float_to_int_32_inf1.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(f32::INFINITY); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on +Inf which cannot be represented in target type `i32` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_32_inf1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_32_infneg1.stderr b/tests/compile-fail/intrinsics/float_to_int_32_infneg1.stderr new file mode 100644 index 000000000000..ae7301193682 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_infneg1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `i32` + --> $DIR/float_to_int_32_infneg1.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(f32::NEG_INFINITY); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `i32` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_32_infneg1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_32_nan.stderr b/tests/compile-fail/intrinsics/float_to_int_32_nan.stderr new file mode 100644 index 000000000000..9c20abef78df --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_nan.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` + --> $DIR/float_to_int_32_nan.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(f32::NAN); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_32_nan.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_32_nanneg.stderr b/tests/compile-fail/intrinsics/float_to_int_32_nanneg.stderr new file mode 100644 index 000000000000..f5675fd654dd --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_nanneg.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` + --> $DIR/float_to_int_32_nanneg.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(-f32::NAN); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_32_nanneg.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_32_neg.stderr b/tests/compile-fail/intrinsics/float_to_int_32_neg.stderr new file mode 100644 index 000000000000..3b7c755af654 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_neg.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -1 which cannot be represented in target type `u32` + --> $DIR/float_to_int_32_neg.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(-1.000000001f32); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1 which cannot be represented in target type `u32` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_32_neg.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_32_too_big1.stderr b/tests/compile-fail/intrinsics/float_to_int_32_too_big1.stderr new file mode 100644 index 000000000000..abfda9eef0af --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_too_big1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 2.14748365E+9 which cannot be represented in target type `i32` + --> $DIR/float_to_int_32_too_big1.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(2147483648.0f32); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2.14748365E+9 which cannot be represented in target type `i32` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_32_too_big1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_32_too_big2.stderr b/tests/compile-fail/intrinsics/float_to_int_32_too_big2.stderr new file mode 100644 index 000000000000..2680d0c9908c --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_too_big2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 4.2949673E+9 which cannot be represented in target type `u32` + --> $DIR/float_to_int_32_too_big2.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::((u32::MAX-127) as f32); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 4.2949673E+9 which cannot be represented in target type `u32` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_32_too_big2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_32_too_small1.stderr b/tests/compile-fail/intrinsics/float_to_int_32_too_small1.stderr new file mode 100644 index 000000000000..b03bd380df47 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_too_small1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -2.1474839E+9 which cannot be represented in target type `i32` + --> $DIR/float_to_int_32_too_small1.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(-2147483904.0f32); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2.1474839E+9 which cannot be represented in target type `i32` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_32_too_small1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_inf1.stderr b/tests/compile-fail/intrinsics/float_to_int_64_inf1.stderr new file mode 100644 index 000000000000..7509844cfd41 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_inf1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on +Inf which cannot be represented in target type `u128` + --> $DIR/float_to_int_64_inf1.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(f64::INFINITY); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on +Inf which cannot be represented in target type `u128` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_inf1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_infneg1.stderr b/tests/compile-fail/intrinsics/float_to_int_64_infneg1.stderr new file mode 100644 index 000000000000..539cd52d83d0 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_infneg1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `u128` + --> $DIR/float_to_int_64_infneg1.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(f64::NEG_INFINITY); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `u128` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_infneg1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_infneg2.stderr b/tests/compile-fail/intrinsics/float_to_int_64_infneg2.stderr new file mode 100644 index 000000000000..ceb18c3f4121 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_infneg2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `i128` + --> $DIR/float_to_int_64_infneg2.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(f64::NEG_INFINITY); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `i128` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_infneg2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_nan.stderr b/tests/compile-fail/intrinsics/float_to_int_64_nan.stderr new file mode 100644 index 000000000000..eee8d2fac0b3 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_nan.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` + --> $DIR/float_to_int_64_nan.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(f64::NAN); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_nan.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_neg.stderr b/tests/compile-fail/intrinsics/float_to_int_64_neg.stderr new file mode 100644 index 000000000000..384c0232465a --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_neg.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -1 which cannot be represented in target type `u128` + --> $DIR/float_to_int_64_neg.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(-1.0000000000001f64); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1 which cannot be represented in target type `u128` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_neg.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big1.stderr b/tests/compile-fail/intrinsics/float_to_int_64_too_big1.stderr new file mode 100644 index 000000000000..bb5b10a2710f --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 2147483648 which cannot be represented in target type `i32` + --> $DIR/float_to_int_64_too_big1.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(2147483648.0f64); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2147483648 which cannot be represented in target type `i32` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_too_big1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big2.stderr b/tests/compile-fail/intrinsics/float_to_int_64_too_big2.stderr new file mode 100644 index 000000000000..a4d57c2f5cee --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 9.2233720368547758E+18 which cannot be represented in target type `i64` + --> $DIR/float_to_int_64_too_big2.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(9223372036854775808.0f64); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 9.2233720368547758E+18 which cannot be represented in target type `i64` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_too_big2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big3.stderr b/tests/compile-fail/intrinsics/float_to_int_64_too_big3.stderr new file mode 100644 index 000000000000..2b7379fcbd38 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big3.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 1.8446744073709552E+19 which cannot be represented in target type `u64` + --> $DIR/float_to_int_64_too_big3.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(18446744073709551616.0f64); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 1.8446744073709552E+19 which cannot be represented in target type `u64` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_too_big3.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big4.stderr b/tests/compile-fail/intrinsics/float_to_int_64_too_big4.stderr new file mode 100644 index 000000000000..d30817607b9f --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big4.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 3.4028236692093846E+38 which cannot be represented in target type `u128` + --> $DIR/float_to_int_64_too_big4.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(u128::MAX as f64); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 3.4028236692093846E+38 which cannot be represented in target type `u128` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_too_big4.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big5.stderr b/tests/compile-fail/intrinsics/float_to_int_64_too_big5.stderr new file mode 100644 index 000000000000..f6b0c0a3527f --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big5.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 2.4028236692093845E+38 which cannot be represented in target type `i128` + --> $DIR/float_to_int_64_too_big5.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(240282366920938463463374607431768211455.0f64); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2.4028236692093845E+38 which cannot be represented in target type `i128` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_too_big5.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big6.stderr b/tests/compile-fail/intrinsics/float_to_int_64_too_big6.stderr new file mode 100644 index 000000000000..e0eab8148b07 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big6.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 1.7976931348623157E+308 which cannot be represented in target type `u128` + --> $DIR/float_to_int_64_too_big6.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(f64::MAX); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 1.7976931348623157E+308 which cannot be represented in target type `u128` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_too_big6.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big7.stderr b/tests/compile-fail/intrinsics/float_to_int_64_too_big7.stderr new file mode 100644 index 000000000000..a291b21c7aad --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big7.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -1.7976931348623157E+308 which cannot be represented in target type `i128` + --> $DIR/float_to_int_64_too_big7.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(f64::MIN); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1.7976931348623157E+308 which cannot be represented in target type `i128` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_too_big7.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_small1.stderr b/tests/compile-fail/intrinsics/float_to_int_64_too_small1.stderr new file mode 100644 index 000000000000..81ca218505dd --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_small1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -2147483649 which cannot be represented in target type `i32` + --> $DIR/float_to_int_64_too_small1.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(-2147483649.0f64); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2147483649 which cannot be represented in target type `i32` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_too_small1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_small2.stderr b/tests/compile-fail/intrinsics/float_to_int_64_too_small2.stderr new file mode 100644 index 000000000000..245f5cf0238c --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_small2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -9.2233720368547778E+18 which cannot be represented in target type `i64` + --> $DIR/float_to_int_64_too_small2.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(-9223372036854777856.0f64); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -9.2233720368547778E+18 which cannot be represented in target type `i64` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_too_small2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_small3.stderr b/tests/compile-fail/intrinsics/float_to_int_64_too_small3.stderr new file mode 100644 index 000000000000..f684ed2cde98 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_small3.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -2.4028236692093845E+38 which cannot be represented in target type `i128` + --> $DIR/float_to_int_64_too_small3.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(-240282366920938463463374607431768211455.0f64); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2.4028236692093845E+38 which cannot be represented in target type `i128` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_too_small3.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_1.stderr b/tests/compile-fail/intrinsics/out_of_bounds_ptr_1.stderr new file mode 100644 index 000000000000..2b00876297fa --- /dev/null +++ b/tests/compile-fail/intrinsics/out_of_bounds_ptr_1.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: pointer arithmetic failed: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::ptr::const_ptr::::offset` at rustc_src/src/ptr/const_ptr.rs:LL:CC +note: inside `main` at $DIR/out_of_bounds_ptr_1.rs:LL:CC + --> $DIR/out_of_bounds_ptr_1.rs:LL:CC + | +LL | let x = unsafe { x.offset(5) }; + | ^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_2.stderr b/tests/compile-fail/intrinsics/out_of_bounds_ptr_2.stderr new file mode 100644 index 000000000000..32ac570f7231 --- /dev/null +++ b/tests/compile-fail/intrinsics/out_of_bounds_ptr_2.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: overflowing in-bounds pointer arithmetic + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::ptr::const_ptr::::offset` at rustc_src/src/ptr/const_ptr.rs:LL:CC +note: inside `main` at $DIR/out_of_bounds_ptr_2.rs:LL:CC + --> $DIR/out_of_bounds_ptr_2.rs:LL:CC + | +LL | let x = unsafe { x.offset(isize::MIN) }; + | ^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_3.stderr b/tests/compile-fail/intrinsics/out_of_bounds_ptr_3.stderr new file mode 100644 index 000000000000..cd48112cb430 --- /dev/null +++ b/tests/compile-fail/intrinsics/out_of_bounds_ptr_3.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: pointer arithmetic failed: ALLOC has size 4, so pointer to 1 byte starting at offset -1 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::ptr::const_ptr::::offset` at rustc_src/src/ptr/const_ptr.rs:LL:CC +note: inside `main` at $DIR/out_of_bounds_ptr_3.rs:LL:CC + --> $DIR/out_of_bounds_ptr_3.rs:LL:CC + | +LL | let x = unsafe { x.offset(-1) }; + | ^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/overflowing-unchecked-rsh.rs b/tests/compile-fail/intrinsics/overflowing-unchecked-rsh.rs index 730d01597f4d..6402f4bb74c6 100644 --- a/tests/compile-fail/intrinsics/overflowing-unchecked-rsh.rs +++ b/tests/compile-fail/intrinsics/overflowing-unchecked-rsh.rs @@ -2,7 +2,7 @@ use std::intrinsics::*; -//error-pattern: overflowing shift by 64 in `unchecked_shr` +// error-pattern: overflowing shift by 64 in `unchecked_shr` fn main() { unsafe { diff --git a/tests/compile-fail/intrinsics/overflowing-unchecked-rsh.stderr b/tests/compile-fail/intrinsics/overflowing-unchecked-rsh.stderr new file mode 100644 index 000000000000..0d22b166b267 --- /dev/null +++ b/tests/compile-fail/intrinsics/overflowing-unchecked-rsh.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: overflowing shift by 64 in `unchecked_shr` + --> $DIR/overflowing-unchecked-rsh.rs:LL:CC + | +LL | let _n = unchecked_shr(1i64, 64); + | ^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 64 in `unchecked_shr` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/overflowing-unchecked-rsh.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.stderr b/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.stderr new file mode 100644 index 000000000000..d3e2fe4013f4 --- /dev/null +++ b/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: pointer arithmetic failed: null pointer is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::ptr::mut_ptr::::offset` at rustc_src/src/ptr/mut_ptr.rs:LL:CC +note: inside `main` at $DIR/ptr_offset_0_plus_0.rs:LL:CC + --> $DIR/ptr_offset_0_plus_0.rs:LL:CC + | +LL | let _x = unsafe { x.offset(0) }; // UB despite offset 0, NULL is never inbounds + | ^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/ptr_offset_from_oob.stderr b/tests/compile-fail/intrinsics/ptr_offset_from_oob.stderr new file mode 100644 index 000000000000..0e723a5ee395 --- /dev/null +++ b/tests/compile-fail/intrinsics/ptr_offset_from_oob.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: out-of-bounds offset_from: ALLOC has size 4, so pointer at offset 10 is out-of-bounds + --> $DIR/ptr_offset_from_oob.rs:LL:CC + | +LL | unsafe { ptr_offset_from(end_ptr, end_ptr) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: ALLOC has size 4, so pointer at offset 10 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/ptr_offset_from_oob.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs b/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs index ea6bef151e1c..e332a9dc624a 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs +++ b/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs @@ -1,4 +1,4 @@ -// error-pattern: 0x1 is not a valid pointer +// error-pattern: is not a valid pointer fn main() { // Can't offset an integer pointer by non-zero offset. diff --git a/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.stderr b/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.stderr new file mode 100644 index 000000000000..a47ed4719d90 --- /dev/null +++ b/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: pointer arithmetic failed: 0x1 is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::ptr::mut_ptr::::offset` at rustc_src/src/ptr/mut_ptr.rs:LL:CC +note: inside `main` at $DIR/ptr_offset_int_plus_int.rs:LL:CC + --> $DIR/ptr_offset_int_plus_int.rs:LL:CC + | +LL | let _val = (1 as *mut u8).offset(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs b/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs index 8ff5c3596ef6..2d27e25a7af1 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs +++ b/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs @@ -1,4 +1,4 @@ -// error-pattern: 0x1 is not a valid pointer +// error-pattern: is not a valid pointer fn main() { let ptr = Box::into_raw(Box::new(0u32)); diff --git a/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.stderr b/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.stderr new file mode 100644 index 000000000000..58b33e706d3e --- /dev/null +++ b/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: pointer arithmetic failed: 0x1 is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::ptr::mut_ptr::::offset` at rustc_src/src/ptr/mut_ptr.rs:LL:CC +note: inside `main` at $DIR/ptr_offset_int_plus_ptr.rs:LL:CC + --> $DIR/ptr_offset_int_plus_ptr.rs:LL:CC + | +LL | let _val = (1 as *mut u8).offset(ptr as isize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/ptr_offset_overflow.rs b/tests/compile-fail/intrinsics/ptr_offset_overflow.rs index 452bf341c9e2..734547b6013b 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_overflow.rs +++ b/tests/compile-fail/intrinsics/ptr_offset_overflow.rs @@ -1,4 +1,4 @@ -//error-pattern: overflowing in-bounds pointer arithmetic +// error-pattern: overflowing in-bounds pointer arithmetic fn main() { let v = [1i8, 2]; let x = &v[1] as *const i8; diff --git a/tests/compile-fail/intrinsics/ptr_offset_overflow.stderr b/tests/compile-fail/intrinsics/ptr_offset_overflow.stderr new file mode 100644 index 000000000000..81ff87168c12 --- /dev/null +++ b/tests/compile-fail/intrinsics/ptr_offset_overflow.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: overflowing in-bounds pointer arithmetic + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::ptr::const_ptr::::offset` at rustc_src/src/ptr/const_ptr.rs:LL:CC +note: inside `main` at $DIR/ptr_offset_overflow.rs:LL:CC + --> $DIR/ptr_offset_overflow.rs:LL:CC + | +LL | let _val = unsafe { x.offset(isize::MIN) }; + | ^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.stderr b/tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.stderr new file mode 100644 index 000000000000..686ab1796647 --- /dev/null +++ b/tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: pointer arithmetic failed: ALLOC has size 4, so pointer at offset 32 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::ptr::mut_ptr::::offset` at rustc_src/src/ptr/mut_ptr.rs:LL:CC +note: inside `main` at $DIR/ptr_offset_ptr_plus_0.rs:LL:CC + --> $DIR/ptr_offset_ptr_plus_0.rs:LL:CC + | +LL | let _x = unsafe { x.offset(0) }; // UB despite offset 0, the pointer is not inbounds of the only object it can point to + | ^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/rem-by-zero.stderr b/tests/compile-fail/intrinsics/rem-by-zero.stderr new file mode 100644 index 000000000000..7501aca7b247 --- /dev/null +++ b/tests/compile-fail/intrinsics/rem-by-zero.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calculating the remainder with a divisor of zero + --> $DIR/rem-by-zero.rs:LL:CC + | +LL | let _n = unchecked_rem(3u32, 0); + | ^^^^^^^^^^^^^^^^^^^^^^ calculating the remainder with a divisor of zero + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/rem-by-zero.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/simd-div-by-zero.stderr b/tests/compile-fail/intrinsics/simd-div-by-zero.stderr new file mode 100644 index 000000000000..77c12de8d81a --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-div-by-zero.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dividing by zero + --> $DIR/simd-div-by-zero.rs:LL:CC + | +LL | simd_div(x, y); + | ^^^^^^^^^^^^^^ dividing by zero + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/simd-div-by-zero.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/simd-div-overflow.stderr b/tests/compile-fail/intrinsics/simd-div-overflow.stderr new file mode 100644 index 000000000000..53479a738b7b --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-div-overflow.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: overflow in signed division (dividing MIN by -1) + --> $DIR/simd-div-overflow.rs:LL:CC + | +LL | simd_div(x, y); + | ^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/simd-div-overflow.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/simd-float-to-int.stderr b/tests/compile-fail/intrinsics/simd-float-to-int.stderr new file mode 100644 index 000000000000..378c2b48bb93 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-float-to-int.stderr @@ -0,0 +1,17 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 3.40282347E+38 which cannot be represented in target type `i32` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `core::core_simd::round::>::to_int_unchecked::` at rustc_src/src/../../portable-simd/crates/core_simd/src/round.rs:LL:CC +note: inside `main` at $DIR/simd-float-to-int.rs:LL:CC + --> $DIR/simd-float-to-int.rs:LL:CC + | +LL | let _x : i32x2 = f32x2::from_array([f32::MAX, f32::MIN]).to_int_unchecked(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `implement` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/simd-gather.stderr b/tests/compile-fail/intrinsics/simd-gather.stderr new file mode 100644 index 000000000000..3da14e1fe375 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-gather.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 9, so pointer to 1 byte starting at offset 9 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::simd::Simd::::gather_select_unchecked` at rustc_src/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC +note: inside `main` at $DIR/simd-gather.rs:LL:CC + --> $DIR/simd-gather.rs:LL:CC + | +LL | let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true), idxs, Simd::splat(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/simd-reduce-invalid-bool.stderr b/tests/compile-fail/intrinsics/simd-reduce-invalid-bool.stderr new file mode 100644 index 000000000000..a2404b174e88 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-reduce-invalid-bool.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: each element of a SIMD mask must be all-0-bits or all-1-bits + --> $DIR/simd-reduce-invalid-bool.rs:LL:CC + | +LL | simd_reduce_any(x); + | ^^^^^^^^^^^^^^^^^^ each element of a SIMD mask must be all-0-bits or all-1-bits + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/simd-reduce-invalid-bool.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/simd-rem-by-zero.stderr b/tests/compile-fail/intrinsics/simd-rem-by-zero.stderr new file mode 100644 index 000000000000..98e5ca207972 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-rem-by-zero.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calculating the remainder with a divisor of zero + --> $DIR/simd-rem-by-zero.rs:LL:CC + | +LL | simd_rem(x, y); + | ^^^^^^^^^^^^^^ calculating the remainder with a divisor of zero + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/simd-rem-by-zero.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/simd-scatter.stderr b/tests/compile-fail/intrinsics/simd-scatter.stderr new file mode 100644 index 000000000000..2d2cc2972ab3 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-scatter.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 9, so pointer to 1 byte starting at offset 9 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::simd::Simd::::scatter_select_unchecked` at rustc_src/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC +note: inside `main` at $DIR/simd-scatter.rs:LL:CC + --> $DIR/simd-scatter.rs:LL:CC + | +LL | Simd::from_array([-27, 82, -41, 124]).scatter_select_unchecked(&mut vec, Mask::splat(true), idxs); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/simd-select-bitmask-invalid.stderr b/tests/compile-fail/intrinsics/simd-select-bitmask-invalid.stderr new file mode 100644 index 000000000000..e5fe3c886cb8 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-select-bitmask-invalid.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits + --> $DIR/simd-select-bitmask-invalid.rs:LL:CC + | +LL | simd_select_bitmask(0b11111111u8, x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/simd-select-bitmask-invalid.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/simd-select-invalid-bool.stderr b/tests/compile-fail/intrinsics/simd-select-invalid-bool.stderr new file mode 100644 index 000000000000..f0a1282edac4 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-select-invalid-bool.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: each element of a SIMD mask must be all-0-bits or all-1-bits + --> $DIR/simd-select-invalid-bool.rs:LL:CC + | +LL | simd_select(x, x, x); + | ^^^^^^^^^^^^^^^^^^^^ each element of a SIMD mask must be all-0-bits or all-1-bits + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/simd-select-invalid-bool.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/simd-shl-too-far.stderr b/tests/compile-fail/intrinsics/simd-shl-too-far.stderr new file mode 100644 index 000000000000..dcd38d6f0114 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-shl-too-far.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: overflowing shift by 100 in `simd_shl` in SIMD lane 0 + --> $DIR/simd-shl-too-far.rs:LL:CC + | +LL | simd_shl(x, y); + | ^^^^^^^^^^^^^^ overflowing shift by 100 in `simd_shl` in SIMD lane 0 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/simd-shl-too-far.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/simd-shr-too-far.stderr b/tests/compile-fail/intrinsics/simd-shr-too-far.stderr new file mode 100644 index 000000000000..c2c2850522f5 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-shr-too-far.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: overflowing shift by 40 in `simd_shr` in SIMD lane 1 + --> $DIR/simd-shr-too-far.rs:LL:CC + | +LL | simd_shr(x, y); + | ^^^^^^^^^^^^^^ overflowing shift by 40 in `simd_shr` in SIMD lane 1 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/simd-shr-too-far.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/unchecked_add1.stderr b/tests/compile-fail/intrinsics/unchecked_add1.stderr new file mode 100644 index 000000000000..b967b46ac9ba --- /dev/null +++ b/tests/compile-fail/intrinsics/unchecked_add1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: overflow executing `unchecked_add` + --> $DIR/unchecked_add1.rs:LL:CC + | +LL | unsafe { std::intrinsics::unchecked_add(40000u16, 30000); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_add` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/unchecked_add1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/unchecked_add2.stderr b/tests/compile-fail/intrinsics/unchecked_add2.stderr new file mode 100644 index 000000000000..18a116b7da96 --- /dev/null +++ b/tests/compile-fail/intrinsics/unchecked_add2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: overflow executing `unchecked_add` + --> $DIR/unchecked_add2.rs:LL:CC + | +LL | unsafe { std::intrinsics::unchecked_add(-30000i16, -8000); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_add` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/unchecked_add2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/unchecked_div1.stderr b/tests/compile-fail/intrinsics/unchecked_div1.stderr new file mode 100644 index 000000000000..f153e4efd984 --- /dev/null +++ b/tests/compile-fail/intrinsics/unchecked_div1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: overflow in signed division (dividing MIN by -1) + --> $DIR/unchecked_div1.rs:LL:CC + | +LL | unsafe { std::intrinsics::unchecked_div(i16::MIN, -1); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/unchecked_div1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/unchecked_mul1.stderr b/tests/compile-fail/intrinsics/unchecked_mul1.stderr new file mode 100644 index 000000000000..5372ba9933a2 --- /dev/null +++ b/tests/compile-fail/intrinsics/unchecked_mul1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: overflow executing `unchecked_mul` + --> $DIR/unchecked_mul1.rs:LL:CC + | +LL | unsafe { std::intrinsics::unchecked_mul(300u16, 250u16); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_mul` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/unchecked_mul1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/unchecked_mul2.stderr b/tests/compile-fail/intrinsics/unchecked_mul2.stderr new file mode 100644 index 000000000000..20a44d2422ae --- /dev/null +++ b/tests/compile-fail/intrinsics/unchecked_mul2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: overflow executing `unchecked_mul` + --> $DIR/unchecked_mul2.rs:LL:CC + | +LL | unsafe { std::intrinsics::unchecked_mul(1_000_000_000i32, -4); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_mul` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/unchecked_mul2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/unchecked_sub1.stderr b/tests/compile-fail/intrinsics/unchecked_sub1.stderr new file mode 100644 index 000000000000..12abfed8ff73 --- /dev/null +++ b/tests/compile-fail/intrinsics/unchecked_sub1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: overflow executing `unchecked_sub` + --> $DIR/unchecked_sub1.rs:LL:CC + | +LL | unsafe { std::intrinsics::unchecked_sub(14u32, 22); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_sub` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/unchecked_sub1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/unchecked_sub2.stderr b/tests/compile-fail/intrinsics/unchecked_sub2.stderr new file mode 100644 index 000000000000..d62d2de2f930 --- /dev/null +++ b/tests/compile-fail/intrinsics/unchecked_sub2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: overflow executing `unchecked_sub` + --> $DIR/unchecked_sub2.rs:LL:CC + | +LL | unsafe { std::intrinsics::unchecked_sub(30000i16, -7000); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_sub` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/unchecked_sub2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/uninit_uninhabited_type.stderr b/tests/compile-fail/intrinsics/uninit_uninhabited_type.stderr new file mode 100644 index 000000000000..150128ba2a41 --- /dev/null +++ b/tests/compile-fail/intrinsics/uninit_uninhabited_type.stderr @@ -0,0 +1,12 @@ +error: abnormal termination: aborted execution: attempted to instantiate uninhabited type `!` + --> $DIR/uninit_uninhabited_type.rs:LL:CC + | +LL | unsafe { std::mem::uninitialized::() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!` + | + = note: inside `main` at $DIR/uninit_uninhabited_type.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/write_bytes_null.stderr b/tests/compile-fail/intrinsics/write_bytes_null.stderr new file mode 100644 index 000000000000..77f675e8fb62 --- /dev/null +++ b/tests/compile-fail/intrinsics/write_bytes_null.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: memory access failed: null pointer is not a valid pointer + --> $DIR/write_bytes_null.rs:LL:CC + | +LL | unsafe { write_bytes::(std::ptr::null_mut(), 0, 0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/write_bytes_null.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/write_bytes_overflow.stderr b/tests/compile-fail/intrinsics/write_bytes_overflow.stderr new file mode 100644 index 000000000000..018ba83f53fb --- /dev/null +++ b/tests/compile-fail/intrinsics/write_bytes_overflow.stderr @@ -0,0 +1,17 @@ +error: Undefined Behavior: overflow computing total size of `write_bytes` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::intrinsics::write_bytes::` at rustc_src/src/intrinsics.rs:LL:CC + = note: inside `std::ptr::mut_ptr::::write_bytes` at rustc_src/src/ptr/mut_ptr.rs:LL:CC +note: inside `main` at $DIR/write_bytes_overflow.rs:LL:CC + --> $DIR/write_bytes_overflow.rs:LL:CC + | +LL | (&mut y as *mut i32).write_bytes(0u8, 1usize << (mem::size_of::() * 8 - 1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/zero_fn_ptr.stderr b/tests/compile-fail/intrinsics/zero_fn_ptr.stderr new file mode 100644 index 000000000000..9d44ba9f746a --- /dev/null +++ b/tests/compile-fail/intrinsics/zero_fn_ptr.stderr @@ -0,0 +1,12 @@ +error: abnormal termination: aborted execution: attempted to zero-initialize type `fn()`, which is invalid + --> $DIR/zero_fn_ptr.rs:LL:CC + | +LL | unsafe { std::mem::zeroed::() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to zero-initialize type `fn()`, which is invalid + | + = note: inside `main` at $DIR/zero_fn_ptr.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index 22b9de5776fe..c0c982b8ca21 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -5,5 +5,5 @@ fn main() { let b = unsafe { std::mem::transmute::(2) }; - let _x = b == std::hint::black_box(true); //~ ERROR interpreting an invalid 8-bit value as a bool: 0x02 + let _x = b == std::hint::black_box(true); //~ ERROR interpreting an invalid 8-bit value as a bool } diff --git a/tests/compile-fail/invalid_bool.stderr b/tests/compile-fail/invalid_bool.stderr new file mode 100644 index 000000000000..23c5365618b8 --- /dev/null +++ b/tests/compile-fail/invalid_bool.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: interpreting an invalid 8-bit value as a bool: 0x02 + --> $DIR/invalid_bool.rs:LL:CC + | +LL | let _x = b == std::hint::black_box(true); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ interpreting an invalid 8-bit value as a bool: 0x02 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/invalid_bool.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/invalid_char.rs b/tests/compile-fail/invalid_char.rs index b240cb22ebe9..9d485b73f246 100644 --- a/tests/compile-fail/invalid_char.rs +++ b/tests/compile-fail/invalid_char.rs @@ -6,5 +6,5 @@ fn main() { let c = 0xFFFFFFu32; assert!(std::char::from_u32(c).is_none()); let c = unsafe { std::mem::transmute::(c) }; - let _x = c == 'x'; //~ ERROR interpreting an invalid 32-bit value as a char: 0x00ffffff + let _x = c == 'x'; //~ ERROR interpreting an invalid 32-bit value as a char } diff --git a/tests/compile-fail/invalid_char.stderr b/tests/compile-fail/invalid_char.stderr new file mode 100644 index 000000000000..69f3ef1f4a6d --- /dev/null +++ b/tests/compile-fail/invalid_char.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: interpreting an invalid 32-bit value as a char: $HEX + --> $DIR/invalid_char.rs:LL:CC + | +LL | let _x = c == 'x'; + | ^^^^^^^^ interpreting an invalid 32-bit value as a char: $HEX + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/invalid_char.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/invalid_enum_tag.rs b/tests/compile-fail/invalid_enum_tag.rs index 762a70d803a4..63b6003f3d89 100644 --- a/tests/compile-fail/invalid_enum_tag.rs +++ b/tests/compile-fail/invalid_enum_tag.rs @@ -2,7 +2,7 @@ // Make sure we find these even with many checks disabled. // compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation -// error-pattern: enum value has invalid tag: 0x0000002a +// error-pattern: enum value has invalid tag use std::mem; diff --git a/tests/compile-fail/invalid_enum_tag.stderr b/tests/compile-fail/invalid_enum_tag.stderr new file mode 100644 index 000000000000..a602204cf46b --- /dev/null +++ b/tests/compile-fail/invalid_enum_tag.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: enum value has invalid tag: $HEX + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::mem::discriminant::` at rustc_src/src/mem/mod.rs:LL:CC +note: inside `main` at $DIR/invalid_enum_tag.rs:LL:CC + --> $DIR/invalid_enum_tag.rs:LL:CC + | +LL | let _val = mem::discriminant(&f); + | ^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/invalid_int.stderr b/tests/compile-fail/invalid_int.stderr new file mode 100644 index 000000000000..cd7919444f0a --- /dev/null +++ b/tests/compile-fail/invalid_int.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> $DIR/invalid_int.rs:LL:CC + | +LL | let _x = i + 0; + | ^^^^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/invalid_int.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/issue-miri-1112.stderr b/tests/compile-fail/issue-miri-1112.stderr new file mode 100644 index 000000000000..1dfcad0c147b --- /dev/null +++ b/tests/compile-fail/issue-miri-1112.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: type validation failed: encountered invalid drop function pointer in vtable (function has incompatible signature) + --> $DIR/issue-miri-1112.rs:LL:CC + | +LL | let obj = std::mem::transmute::(obj); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (function has incompatible signature) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `FunnyPointer::from_data_ptr` at $DIR/issue-miri-1112.rs:LL:CC +note: inside `main` at $DIR/issue-miri-1112.rs:LL:CC + --> $DIR/issue-miri-1112.rs:LL:CC + | +LL | let _raw: &FunnyPointer = FunnyPointer::from_data_ptr(&hello, &meta as *const _); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/memleak.rs b/tests/compile-fail/memleak.rs index 71b4e2f442f3..7dee9ddf1c98 100644 --- a/tests/compile-fail/memleak.rs +++ b/tests/compile-fail/memleak.rs @@ -1,4 +1,5 @@ -//error-pattern: the evaluated program leaked memory +// error-pattern: the evaluated program leaked memory +// normalize-stderr-test: ".*│.*" -> "$$stripped$$" fn main() { std::mem::forget(Box::new(42)); diff --git a/tests/compile-fail/memleak.stderr b/tests/compile-fail/memleak.stderr new file mode 100644 index 000000000000..f8b62af3eb85 --- /dev/null +++ b/tests/compile-fail/memleak.stderr @@ -0,0 +1,10 @@ +The following memory was leaked: ALLOC (Rust heap, size: 4, align: 4) { +$stripped$ +} + +error: the evaluated program leaked memory + +note: pass `-Zmiri-ignore-leaks` to disable this check + +error: aborting due to previous error + diff --git a/tests/compile-fail/memleak_rc.32bit.stderr b/tests/compile-fail/memleak_rc.32bit.stderr new file mode 100644 index 000000000000..da222609091a --- /dev/null +++ b/tests/compile-fail/memleak_rc.32bit.stderr @@ -0,0 +1,10 @@ +The following memory was leaked: ALLOC (Rust heap, size: 16, align: 4) { +$stripped$ +} + +error: the evaluated program leaked memory + +note: pass `-Zmiri-ignore-leaks` to disable this check + +error: aborting due to previous error + diff --git a/tests/compile-fail/memleak_rc.64bit.stderr b/tests/compile-fail/memleak_rc.64bit.stderr new file mode 100644 index 000000000000..8c24bbc779bd --- /dev/null +++ b/tests/compile-fail/memleak_rc.64bit.stderr @@ -0,0 +1,11 @@ +The following memory was leaked: ALLOC (Rust heap, size: 32, align: 8) { +$stripped$ +$stripped$ +} + +error: the evaluated program leaked memory + +note: pass `-Zmiri-ignore-leaks` to disable this check + +error: aborting due to previous error + diff --git a/tests/compile-fail/memleak_rc.rs b/tests/compile-fail/memleak_rc.rs index b2bc6722afb0..17bcb36f3610 100644 --- a/tests/compile-fail/memleak_rc.rs +++ b/tests/compile-fail/memleak_rc.rs @@ -1,4 +1,6 @@ -//error-pattern: the evaluated program leaked memory +// error-pattern: the evaluated program leaked memory +// stderr-per-bitwidth +// normalize-stderr-test: ".*│.*" -> "$$stripped$$" use std::rc::Rc; use std::cell::RefCell; diff --git a/tests/compile-fail/modifying_constants.stderr b/tests/compile-fail/modifying_constants.stderr new file mode 100644 index 000000000000..995011482323 --- /dev/null +++ b/tests/compile-fail/modifying_constants.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: writing to ALLOC which is read-only + --> $DIR/modifying_constants.rs:LL:CC + | +LL | *y = 42; + | ^^^^^^^ writing to ALLOC which is read-only + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/modifying_constants.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/never_say_never.stderr b/tests/compile-fail/never_say_never.stderr new file mode 100644 index 000000000000..22ad10f13103 --- /dev/null +++ b/tests/compile-fail/never_say_never.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: entering unreachable code + --> $DIR/never_say_never.rs:LL:CC + | +LL | *(y as *const _ as *const !) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/never_say_never.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/never_transmute_humans.stderr b/tests/compile-fail/never_transmute_humans.stderr new file mode 100644 index 000000000000..6d8fa37e98ef --- /dev/null +++ b/tests/compile-fail/never_transmute_humans.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: transmuting to uninhabited type + --> $DIR/never_transmute_humans.rs:LL:CC + | +LL | std::mem::transmute::(Human) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/never_transmute_humans.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/never_transmute_void.stderr b/tests/compile-fail/never_transmute_void.stderr new file mode 100644 index 000000000000..8d8a4d0e832f --- /dev/null +++ b/tests/compile-fail/never_transmute_void.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: entering unreachable code + --> $DIR/never_transmute_void.rs:LL:CC + | +LL | match v.0 {} + | ^^^ entering unreachable code + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `m::f` at $DIR/never_transmute_void.rs:LL:CC +note: inside `main` at $DIR/never_transmute_void.rs:LL:CC + --> $DIR/never_transmute_void.rs:LL:CC + | +LL | m::f(v); + | ^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/no_main.stderr b/tests/compile-fail/no_main.stderr new file mode 100644 index 000000000000..52591a8d6da3 --- /dev/null +++ b/tests/compile-fail/no_main.stderr @@ -0,0 +1,2 @@ +error: miri can only run programs that have a main function + diff --git a/tests/compile-fail/null_pointer_deref.stderr b/tests/compile-fail/null_pointer_deref.stderr new file mode 100644 index 000000000000..0930160023f1 --- /dev/null +++ b/tests/compile-fail/null_pointer_deref.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: null pointer is not a valid pointer + --> $DIR/null_pointer_deref.rs:LL:CC + | +LL | let x: i32 = unsafe { *std::ptr::null() }; + | ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/null_pointer_deref.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/null_pointer_deref_zst.stderr b/tests/compile-fail/null_pointer_deref_zst.stderr new file mode 100644 index 000000000000..25fea50b15af --- /dev/null +++ b/tests/compile-fail/null_pointer_deref_zst.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: null pointer is not a valid pointer + --> $DIR/null_pointer_deref_zst.rs:LL:CC + | +LL | let x: () = unsafe { *std::ptr::null() }; + | ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/null_pointer_deref_zst.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/null_pointer_write.stderr b/tests/compile-fail/null_pointer_write.stderr new file mode 100644 index 000000000000..5ac8cc7c20fd --- /dev/null +++ b/tests/compile-fail/null_pointer_write.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: null pointer is not a valid pointer + --> $DIR/null_pointer_write.rs:LL:CC + | +LL | unsafe { *std::ptr::null_mut() = 0i32 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/null_pointer_write.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/null_pointer_write_zst.stderr b/tests/compile-fail/null_pointer_write_zst.stderr new file mode 100644 index 000000000000..b40a9154f182 --- /dev/null +++ b/tests/compile-fail/null_pointer_write_zst.stderr @@ -0,0 +1,17 @@ +error: Undefined Behavior: memory access failed: null pointer is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::ptr::write::<[u8; 0]>` at rustc_src/src/ptr/mod.rs:LL:CC + = note: inside `std::ptr::mut_ptr::::write` at rustc_src/src/ptr/mut_ptr.rs:LL:CC +note: inside `main` at $DIR/null_pointer_write_zst.rs:LL:CC + --> $DIR/null_pointer_write_zst.rs:LL:CC + | +LL | unsafe { std::ptr::null_mut::<[u8; 0]>().write(zst_val) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/panic/bad_miri_start_panic.stderr b/tests/compile-fail/panic/bad_miri_start_panic.stderr new file mode 100644 index 000000000000..dca5d39b7665 --- /dev/null +++ b/tests/compile-fail/panic/bad_miri_start_panic.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: unwinding past a stack frame that does not allow unwinding + --> $DIR/bad_miri_start_panic.rs:LL:CC + | +LL | unsafe { miri_start_panic(&mut 0) } + | ^^^^^^^^^^^^^^^^^^^^^^^^ unwinding past a stack frame that does not allow unwinding + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/bad_miri_start_panic.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/panic/bad_unwind.stderr b/tests/compile-fail/panic/bad_unwind.stderr new file mode 100644 index 000000000000..529f4179a8f7 --- /dev/null +++ b/tests/compile-fail/panic/bad_unwind.stderr @@ -0,0 +1,25 @@ +thread 'main' panicked at 'explicit panic', $DIR/bad_unwind.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +error: Undefined Behavior: unwinding past a stack frame that does not allow unwinding + --> $DIR/bad_unwind.rs:LL:CC + | +LL | std::panic::catch_unwind(|| unwind()).unwrap_err(); + | ^^^^^^^^ unwinding past a stack frame that does not allow unwinding + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/bad_unwind.rs:LL:CC + = note: inside `std::panicking::r#try::do_call::<[closure@$DIR/bad_unwind.rs:LL:CC: 13:41], ()>` at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::panicking::r#try::<(), [closure@$DIR/bad_unwind.rs:LL:CC: 13:41]>` at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::panic::catch_unwind::<[closure@$DIR/bad_unwind.rs:LL:CC: 13:41], ()>` at rustc_src/src/panic.rs:LL:CC +note: inside `main` at $DIR/bad_unwind.rs:LL:CC + --> $DIR/bad_unwind.rs:LL:CC + | +LL | std::panic::catch_unwind(|| unwind()).unwrap_err(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/panic/double_panic.stderr b/tests/compile-fail/panic/double_panic.stderr new file mode 100644 index 000000000000..b854a6b72158 --- /dev/null +++ b/tests/compile-fail/panic/double_panic.stderr @@ -0,0 +1,91 @@ +thread 'main' panicked at 'first', $DIR/double_panic.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +thread 'main' panicked at 'second', $DIR/double_panic.rs:LL:CC +stack backtrace: + 0: std::backtrace_rs::backtrace::miri::trace_unsynchronized + at rustc_src/src/../../backtrace/src/backtrace/miri.rs:LL:CC + 1: std::backtrace_rs::backtrace::miri::trace + at rustc_src/src/../../backtrace/src/backtrace/miri.rs:LL:CC + 2: std::backtrace_rs::backtrace::trace_unsynchronized + at rustc_src/src/../../backtrace/src/backtrace/mod.rs:LL:CC + 3: std::sys_common::backtrace::_print_fmt + at rustc_src/src/sys_common/backtrace.rs:LL:CC + 4: ::fmt + at rustc_src/src/sys_common/backtrace.rs:LL:CC + 5: std::fmt::write + at rustc_src/src/fmt/mod.rs:LL:CC + 6: ::write_fmt + at rustc_src/src/io/mod.rs:LL:CC + 7: std::sys_common::backtrace::_print + at rustc_src/src/sys_common/backtrace.rs:LL:CC + 8: std::sys_common::backtrace::print + at rustc_src/src/sys_common/backtrace.rs:LL:CC + 9: std::panicking::default_hook::{closure#1} + at rustc_src/src/panicking.rs:LL:CC + 10: std::panicking::default_hook + at rustc_src/src/panicking.rs:LL:CC + 11: std::panicking::rust_panic_with_hook + at rustc_src/src/panicking.rs:LL:CC + 12: std::rt::begin_panic::{closure#0} + at rustc_src/src/panicking.rs:LL:CC + 13: std::sys_common::backtrace::__rust_end_short_backtrace + at rustc_src/src/sys_common/backtrace.rs:LL:CC + 14: std::rt::begin_panic + at rustc_src/src/panicking.rs:LL:CC + 15: ::drop + at $DIR/double_panic.rs:LL:CC + 16: std::ptr::drop_in_place - shim(Some(Foo)) + at rustc_src/src/ptr/mod.rs:LL:CC + 17: main + at $DIR/double_panic.rs:LL:CC + 18: >::call_once - shim(fn()) + at rustc_src/src/ops/function.rs:LL:CC + 19: std::sys_common::backtrace::__rust_begin_short_backtrace + at rustc_src/src/sys_common/backtrace.rs:LL:CC + 20: std::rt::lang_start::{closure#0} + at rustc_src/src/rt.rs:LL:CC + 21: std::ops::function::impls::call_once + at rustc_src/src/ops/function.rs:LL:CC + 22: std::panicking::r#try::do_call + at rustc_src/src/panicking.rs:LL:CC + 23: std::panicking::r#try + at rustc_src/src/panicking.rs:LL:CC + 24: std::panic::catch_unwind + at rustc_src/src/panic.rs:LL:CC + 25: std::rt::lang_start_internal::{closure#2} + at rustc_src/src/rt.rs:LL:CC + 26: std::panicking::r#try::do_call + at rustc_src/src/panicking.rs:LL:CC + 27: std::panicking::r#try + at rustc_src/src/panicking.rs:LL:CC + 28: std::panic::catch_unwind + at rustc_src/src/panic.rs:LL:CC + 29: std::rt::lang_start_internal + at rustc_src/src/rt.rs:LL:CC + 30: std::rt::lang_start + at rustc_src/src/rt.rs:LL:CC +thread panicked while panicking. aborting. +error: abnormal termination: the program aborted execution + | + = note: inside `std::sys::PLATFORM::abort_internal` at rustc_src/src/sys/PLATFORM/mod.rs:LL:CC + = note: inside `std::panicking::rust_panic_with_hook` at rustc_src/src/panicking.rs:LL:CC + = note: inside closure at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::rt::begin_panic<&str>::{closure#0}], !>` at rustc_src/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::rt::begin_panic::<&str>` at rustc_src/src/panicking.rs:LL:CC +note: inside `::drop` at rustc_src/src/panic.rs:LL:CC + --> $DIR/double_panic.rs:LL:CC + | +LL | panic!("second"); + | ^^^^^^^^^^^^^^^^ + = note: inside `std::ptr::drop_in_place:: - shim(Some(Foo))` at rustc_src/src/ptr/mod.rs:LL:CC +note: inside `main` at $DIR/double_panic.rs:LL:CC + --> $DIR/double_panic.rs:LL:CC + | +LL | } + | ^ + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/panic/panic_abort1.stderr b/tests/compile-fail/panic/panic_abort1.stderr new file mode 100644 index 000000000000..93f48bb89e3b --- /dev/null +++ b/tests/compile-fail/panic/panic_abort1.stderr @@ -0,0 +1,22 @@ +thread 'main' panicked at 'panicking from libstd', $DIR/panic_abort1.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +error: abnormal termination: the program aborted execution + | + = note: inside `panic_abort::__rust_start_panic::abort` at rustc_src/src/lib.rs:LL:CC + = note: inside `panic_abort::__rust_start_panic` at rustc_src/src/lib.rs:LL:CC + = note: inside `std::panicking::rust_panic` at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::panicking::rust_panic_with_hook` at rustc_src/src/panicking.rs:LL:CC + = note: inside closure at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::rt::begin_panic<&str>::{closure#0}], !>` at rustc_src/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::rt::begin_panic::<&str>` at rustc_src/src/panicking.rs:LL:CC +note: inside `main` at rustc_src/src/panic.rs:LL:CC + --> $DIR/panic_abort1.rs:LL:CC + | +LL | std::panic!("panicking from libstd"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/panic/panic_abort2.stderr b/tests/compile-fail/panic/panic_abort2.stderr new file mode 100644 index 000000000000..bb4b96fd0aeb --- /dev/null +++ b/tests/compile-fail/panic/panic_abort2.stderr @@ -0,0 +1,23 @@ +thread 'main' panicked at '42-panicking from libstd', $DIR/panic_abort2.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +error: abnormal termination: the program aborted execution + | + = note: inside `panic_abort::__rust_start_panic::abort` at rustc_src/src/lib.rs:LL:CC + = note: inside `panic_abort::__rust_start_panic` at rustc_src/src/lib.rs:LL:CC + = note: inside `std::panicking::rust_panic` at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::panicking::rust_panic_with_hook` at rustc_src/src/panicking.rs:LL:CC + = note: inside closure at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at rustc_src/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::panicking::begin_panic_handler` at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::rt::panic_fmt` at rustc_src/src/panicking.rs:LL:CC +note: inside `main` at rustc_src/src/panic.rs:LL:CC + --> $DIR/panic_abort2.rs:LL:CC + | +LL | std::panic!("{}-panicking from libstd", 42); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/panic/panic_abort3.stderr b/tests/compile-fail/panic/panic_abort3.stderr new file mode 100644 index 000000000000..a799ce4b4de9 --- /dev/null +++ b/tests/compile-fail/panic/panic_abort3.stderr @@ -0,0 +1,24 @@ +thread 'main' panicked at 'panicking from libcore', $DIR/panic_abort3.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +error: abnormal termination: the program aborted execution + | + = note: inside `panic_abort::__rust_start_panic::abort` at rustc_src/src/lib.rs:LL:CC + = note: inside `panic_abort::__rust_start_panic` at rustc_src/src/lib.rs:LL:CC + = note: inside `std::panicking::rust_panic` at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::panicking::rust_panic_with_hook` at rustc_src/src/panicking.rs:LL:CC + = note: inside closure at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at rustc_src/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::panicking::begin_panic_handler` at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::rt::panic_fmt` at rustc_src/src/panicking.rs:LL:CC + = note: inside `core::panicking::panic` at rustc_src/src/panicking.rs:LL:CC +note: inside `main` at rustc_src/src/panic.rs:LL:CC + --> $DIR/panic_abort3.rs:LL:CC + | +LL | core::panic!("panicking from libcore"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/panic/panic_abort4.stderr b/tests/compile-fail/panic/panic_abort4.stderr new file mode 100644 index 000000000000..a24d0948d1cf --- /dev/null +++ b/tests/compile-fail/panic/panic_abort4.stderr @@ -0,0 +1,23 @@ +thread 'main' panicked at '42-panicking from libcore', $DIR/panic_abort4.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +error: abnormal termination: the program aborted execution + | + = note: inside `panic_abort::__rust_start_panic::abort` at rustc_src/src/lib.rs:LL:CC + = note: inside `panic_abort::__rust_start_panic` at rustc_src/src/lib.rs:LL:CC + = note: inside `std::panicking::rust_panic` at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::panicking::rust_panic_with_hook` at rustc_src/src/panicking.rs:LL:CC + = note: inside closure at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at rustc_src/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::panicking::begin_panic_handler` at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::rt::panic_fmt` at rustc_src/src/panicking.rs:LL:CC +note: inside `main` at rustc_src/src/panic.rs:LL:CC + --> $DIR/panic_abort4.rs:LL:CC + | +LL | core::panic!("{}-panicking from libcore", 42); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/panic/unwind_panic_abort.stderr b/tests/compile-fail/panic/unwind_panic_abort.stderr new file mode 100644 index 000000000000..7ae965156f00 --- /dev/null +++ b/tests/compile-fail/panic/unwind_panic_abort.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: unwinding past a stack frame that does not allow unwinding + --> $DIR/unwind_panic_abort.rs:LL:CC + | +LL | unsafe { miri_start_panic(&mut 0); } + | ^^^^^^^^^^^^^^^^^^^^^^^^ unwinding past a stack frame that does not allow unwinding + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/unwind_panic_abort.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/pointer_partial_overwrite.stderr b/tests/compile-fail/pointer_partial_overwrite.stderr new file mode 100644 index 000000000000..6779df99c3fb --- /dev/null +++ b/tests/compile-fail/pointer_partial_overwrite.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> $DIR/pointer_partial_overwrite.rs:LL:CC + | +LL | let x = *p; + | ^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/pointer_partial_overwrite.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/pointer_partial_read.stderr b/tests/compile-fail/pointer_partial_read.stderr new file mode 100644 index 000000000000..dc35f7e109a5 --- /dev/null +++ b/tests/compile-fail/pointer_partial_read.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: unable to turn pointer into raw bytes + --> $DIR/pointer_partial_read.rs:LL:CC + | +LL | let _val = unsafe { *z }; + | ^^ unable to turn pointer into raw bytes + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/pointer_partial_read.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/provenance/ptr_int_unexposed.stderr b/tests/compile-fail/provenance/ptr_int_unexposed.stderr new file mode 100644 index 000000000000..cdd25d0e638e --- /dev/null +++ b/tests/compile-fail/provenance/ptr_int_unexposed.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: $HEX is not a valid pointer + --> $DIR/ptr_int_unexposed.rs:LL:CC + | +LL | assert_eq!(unsafe { *ptr }, 3); + | ^^^^ dereferencing pointer failed: $HEX is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/ptr_int_unexposed.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/provenance/ptr_invalid.stderr b/tests/compile-fail/provenance/ptr_invalid.stderr new file mode 100644 index 000000000000..76a40765eb2f --- /dev/null +++ b/tests/compile-fail/provenance/ptr_invalid.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: $HEX is not a valid pointer + --> $DIR/ptr_invalid.rs:LL:CC + | +LL | let _val = unsafe { *xptr_invalid }; + | ^^^^^^^^^^^^^ dereferencing pointer failed: $HEX is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/ptr_invalid.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/provenance/ptr_legacy_provenance.rs b/tests/compile-fail/provenance/ptr_legacy_provenance.rs index aecc1460e085..538ec4484edb 100644 --- a/tests/compile-fail/provenance/ptr_legacy_provenance.rs +++ b/tests/compile-fail/provenance/ptr_legacy_provenance.rs @@ -1,4 +1,5 @@ // compile-flags: -Zmiri-disable-stacked-borrows +// normalize-stderr-test: "offset -[0-9]+" -> "offset -XX" #![feature(strict_provenance)] use std::ptr; diff --git a/tests/compile-fail/provenance/ptr_legacy_provenance.stderr b/tests/compile-fail/provenance/ptr_legacy_provenance.stderr new file mode 100644 index 000000000000..4552be08145d --- /dev/null +++ b/tests/compile-fail/provenance/ptr_legacy_provenance.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 4, so pointer to 4 bytes starting at offset -XX is out-of-bounds + --> $DIR/ptr_legacy_provenance.rs:LL:CC + | +LL | assert_eq!(unsafe { *ptr }, 0); + | ^^^^ dereferencing pointer failed: ALLOC has size 4, so pointer to 4 bytes starting at offset -XX is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/ptr_legacy_provenance.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/provenance/strict-provenance-offset.stderr b/tests/compile-fail/provenance/strict-provenance-offset.stderr new file mode 100644 index 000000000000..482b7a404c51 --- /dev/null +++ b/tests/compile-fail/provenance/strict-provenance-offset.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: pointer arithmetic failed: $HEX is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::ptr::const_ptr::::offset` at rustc_src/src/ptr/const_ptr.rs:LL:CC +note: inside `main` at $DIR/strict-provenance-offset.rs:LL:CC + --> $DIR/strict-provenance-offset.rs:LL:CC + | +LL | let _ = unsafe { roundtrip.offset(1) }; + | ^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/provenance/strict_provenance_transmute.stderr b/tests/compile-fail/provenance/strict_provenance_transmute.stderr new file mode 100644 index 000000000000..544431815c1b --- /dev/null +++ b/tests/compile-fail/provenance/strict_provenance_transmute.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: type validation failed: encountered pointer to $HEX[ALLOC], but expected plain (non-pointer) bytes + --> $DIR/strict_provenance_transmute.rs:LL:CC + | +LL | let left_int: usize = mem::transmute(left); + | ^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to $HEX[ALLOC], but expected plain (non-pointer) bytes + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `deref` at $DIR/strict_provenance_transmute.rs:LL:CC +note: inside `main` at $DIR/strict_provenance_transmute.rs:LL:CC + --> $DIR/strict_provenance_transmute.rs:LL:CC + | +LL | deref(ptr1, ptr2.with_addr(ptr1.addr())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/ptr_integer_array_transmute.stderr b/tests/compile-fail/ptr_integer_array_transmute.stderr new file mode 100644 index 000000000000..bc2ca54438ff --- /dev/null +++ b/tests/compile-fail/ptr_integer_array_transmute.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered a pointer, but expected plain (non-pointer) bytes + --> $DIR/ptr_integer_array_transmute.rs:LL:CC + | +LL | let _i: [usize; 1] = unsafe { std::mem::transmute(r) }; + | ^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected plain (non-pointer) bytes + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/ptr_integer_array_transmute.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/ptr_integer_transmute.stderr b/tests/compile-fail/ptr_integer_transmute.stderr new file mode 100644 index 000000000000..de9ebf4eb06b --- /dev/null +++ b/tests/compile-fail/ptr_integer_transmute.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered pointer to $HEX[ALLOC], but expected initialized plain (non-pointer) bytes + --> $DIR/ptr_integer_transmute.rs:LL:CC + | +LL | let _i: usize = unsafe { std::mem::transmute(r) }; + | ^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to $HEX[ALLOC], but expected initialized plain (non-pointer) bytes + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/ptr_integer_transmute.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/rc_as_ptr.stderr b/tests/compile-fail/rc_as_ptr.stderr new file mode 100644 index 000000000000..3d745b7dc5c9 --- /dev/null +++ b/tests/compile-fail/rc_as_ptr.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> $DIR/rc_as_ptr.rs:LL:CC + | +LL | assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at rustc_src/src/macros/mod.rs:LL:CC + = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/reading_half_a_pointer.stderr b/tests/compile-fail/reading_half_a_pointer.stderr new file mode 100644 index 000000000000..505c8deafb6d --- /dev/null +++ b/tests/compile-fail/reading_half_a_pointer.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: unable to turn pointer into raw bytes + --> $DIR/reading_half_a_pointer.rs:LL:CC + | +LL | let _x = *d_alias; + | ^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/reading_half_a_pointer.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/rustc-error.stderr b/tests/compile-fail/rustc-error.stderr new file mode 100644 index 000000000000..09d0f7a6df95 --- /dev/null +++ b/tests/compile-fail/rustc-error.stderr @@ -0,0 +1,14 @@ +error[E0423]: expected function, found macro `println` + --> $DIR/rustc-error.rs:LL:CC + | +LL | println("Hello, world!"); + | ^^^^^^^ not a function + | +help: use `!` to invoke the macro + | +LL | println!("Hello, world!"); + | + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0423`. diff --git a/tests/compile-fail/shim_arg_size.32bit.stderr b/tests/compile-fail/shim_arg_size.32bit.stderr new file mode 100644 index 000000000000..3b54a5b51248 --- /dev/null +++ b/tests/compile-fail/shim_arg_size.32bit.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: scalar size mismatch: expected 4 bytes but got 2 bytes instead + --> $DIR/shim_arg_size.rs:LL:CC + | +LL | let _p1 = malloc(42); + | ^^^^^^^^^^ scalar size mismatch: expected 4 bytes but got 2 bytes instead + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/shim_arg_size.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/shim_arg_size.64bit.stderr b/tests/compile-fail/shim_arg_size.64bit.stderr new file mode 100644 index 000000000000..5e33604c121d --- /dev/null +++ b/tests/compile-fail/shim_arg_size.64bit.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: scalar size mismatch: expected 8 bytes but got 4 bytes instead + --> $DIR/shim_arg_size.rs:LL:CC + | +LL | let _p1 = malloc(42); + | ^^^^^^^^^^ scalar size mismatch: expected 8 bytes but got 4 bytes instead + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/shim_arg_size.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/shim_arg_size.rs b/tests/compile-fail/shim_arg_size.rs index 556195d6e905..1297e5ed070f 100644 --- a/tests/compile-fail/shim_arg_size.rs +++ b/tests/compile-fail/shim_arg_size.rs @@ -1,3 +1,5 @@ +// stderr-per-bitwidth + fn main() { extern "C" { // Use the wrong type(ie. not the pointer width) for the `size` diff --git a/tests/compile-fail/slice-too-big.stderr b/tests/compile-fail/slice-too-big.stderr new file mode 100644 index 000000000000..13239506c633 --- /dev/null +++ b/tests/compile-fail/slice-too-big.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object + --> $DIR/slice-too-big.rs:5:21 + | +LL | let _x: &[u8] = mem::transmute((ptr, usize::MAX)); //~ ERROR: invalid reference metadata: slice is bigger than largest supported object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/slice-too-big.rs:5:21 + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/alias_through_mutation.stderr b/tests/compile-fail/stacked_borrows/alias_through_mutation.stderr new file mode 100644 index 000000000000..6862a67faec2 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/alias_through_mutation.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/alias_through_mutation.rs:LL:CC + | +LL | let _val = *target_alias; + | ^^^^^^^^^^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/alias_through_mutation.rs:LL:CC + | +LL | unsafe { *x = &mut *(target as *mut _); } + | ^^^^^^^^^^^^^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/alias_through_mutation.rs:LL:CC + | +LL | *target = 13; + | ^^^^^^^^^^^^ + = note: inside `main` at $DIR/alias_through_mutation.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut1.stderr b/tests/compile-fail/stacked_borrows/aliasing_mut1.stderr new file mode 100644 index 000000000000..5f2e5cbbad36 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/aliasing_mut1.stderr @@ -0,0 +1,34 @@ +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] + --> $DIR/aliasing_mut1.rs:LL:CC + | +LL | pub fn safe(_x: &mut i32, _y: &mut i32) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/aliasing_mut1.rs:LL:CC + | +LL | let xraw: *mut i32 = unsafe { mem::transmute(&mut x) }; + | ^^^^^^ +help: was protected due to which was created here + --> $DIR/aliasing_mut1.rs:LL:CC + | +LL | let xraw: *mut i32 = unsafe { mem::transmute(&mut x) }; + | ^^^^^^ +help: this protector is live for this call + --> $DIR/aliasing_mut1.rs:LL:CC + | +LL | pub fn safe(_x: &mut i32, _y: &mut i32) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `safe` at $DIR/aliasing_mut1.rs:LL:CC +note: inside `main` at $DIR/aliasing_mut1.rs:LL:CC + --> $DIR/aliasing_mut1.rs:LL:CC + | +LL | safe_raw(xraw, xraw); + | ^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut2.stderr b/tests/compile-fail/stacked_borrows/aliasing_mut2.stderr new file mode 100644 index 000000000000..bb82252e78d4 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/aliasing_mut2.stderr @@ -0,0 +1,34 @@ +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] + --> $DIR/aliasing_mut2.rs:LL:CC + | +LL | pub fn safe(_x: &i32, _y: &mut i32) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/aliasing_mut2.rs:LL:CC + | +LL | let xref = &mut x; + | ^^^^^^ +help: was protected due to which was created here + --> $DIR/aliasing_mut2.rs:LL:CC + | +LL | safe_raw(xshr, xraw); + | ^^^^ +help: this protector is live for this call + --> $DIR/aliasing_mut2.rs:LL:CC + | +LL | pub fn safe(_x: &i32, _y: &mut i32) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `safe` at $DIR/aliasing_mut2.rs:LL:CC +note: inside `main` at $DIR/aliasing_mut2.rs:LL:CC + --> $DIR/aliasing_mut2.rs:LL:CC + | +LL | safe_raw(xshr, xraw); + | ^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut3.stderr b/tests/compile-fail/stacked_borrows/aliasing_mut3.stderr new file mode 100644 index 000000000000..0cfddcac8486 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/aliasing_mut3.stderr @@ -0,0 +1,32 @@ +error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/aliasing_mut3.rs:LL:CC + | +LL | pub fn safe(_x: &mut i32, _y: &i32) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: tag was most recently created at offsets [0x0..0x4] + --> $DIR/aliasing_mut3.rs:LL:CC + | +LL | safe_raw(xraw, xshr); + | ^^^^ +help: tag was later invalidated at offsets [0x0..0x4] + --> $DIR/aliasing_mut3.rs:LL:CC + | +LL | pub fn safe(_x: &mut i32, _y: &i32) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `safe` at $DIR/aliasing_mut3.rs:LL:CC +note: inside `main` at $DIR/aliasing_mut3.rs:LL:CC + --> $DIR/aliasing_mut3.rs:LL:CC + | +LL | safe_raw(xraw, xshr); + | ^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut4.stderr b/tests/compile-fail/stacked_borrows/aliasing_mut4.stderr new file mode 100644 index 000000000000..13b589b94754 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/aliasing_mut4.stderr @@ -0,0 +1,34 @@ +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] + --> $DIR/aliasing_mut4.rs:LL:CC + | +LL | pub fn safe(_x: &i32, _y: &mut Cell) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/aliasing_mut4.rs:LL:CC + | +LL | let xref = &mut x; + | ^^^^^^ +help: was protected due to which was created here + --> $DIR/aliasing_mut4.rs:LL:CC + | +LL | safe_raw(xshr, xraw as *mut _); + | ^^^^ +help: this protector is live for this call + --> $DIR/aliasing_mut4.rs:LL:CC + | +LL | pub fn safe(_x: &i32, _y: &mut Cell) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `safe` at $DIR/aliasing_mut4.rs:LL:CC +note: inside `main` at $DIR/aliasing_mut4.rs:LL:CC + --> $DIR/aliasing_mut4.rs:LL:CC + | +LL | safe_raw(xshr, xraw as *mut _); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/box_exclusive_violation1.stderr b/tests/compile-fail/stacked_borrows/box_exclusive_violation1.stderr new file mode 100644 index 000000000000..94d450955348 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/box_exclusive_violation1.stderr @@ -0,0 +1,38 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/box_exclusive_violation1.rs:LL:CC + | +LL | *our + | ^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/box_exclusive_violation1.rs:LL:CC + | +LL | / fn demo_mut_advanced_unique(mut our: Box) -> i32 { +LL | | unknown_code_1(&*our); +LL | | +LL | | // This "re-asserts" uniqueness of the reference: After writing, we know +... | +LL | | *our +LL | | } + | |_^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/box_exclusive_violation1.rs:LL:CC + | +LL | *LEAK = 7; + | ^^^^^^^^^ + = note: inside `demo_mut_advanced_unique` at $DIR/box_exclusive_violation1.rs:LL:CC +note: inside `main` at $DIR/box_exclusive_violation1.rs:LL:CC + --> $DIR/box_exclusive_violation1.rs:LL:CC + | +LL | demo_mut_advanced_unique(Box::new(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.stderr b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.stderr new file mode 100644 index 000000000000..8eed3732a0cb --- /dev/null +++ b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a write access using at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + --> $DIR/buggy_as_mut_slice.rs:LL:CC + | +LL | v1[1] = 5; + | ^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x4..0x8] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0xc] + --> $DIR/buggy_as_mut_slice.rs:LL:CC + | +LL | let v1 = safe::as_mut_slice(&v); + | ^^^^^^^^^^^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0xc] + --> $DIR/buggy_as_mut_slice.rs:LL:CC + | +LL | from_raw_parts_mut(self_.as_ptr() as *mut T, self_.len()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/buggy_as_mut_slice.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.stderr b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.stderr new file mode 100644 index 000000000000..d1d8d1f6aa3c --- /dev/null +++ b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: trying to reborrow for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/buggy_split_at_mut.rs:LL:CC + | +LL | let (a, b) = safe::split_at_mut(&mut array, 0); + | ^ + | | + | trying to reborrow for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x10] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x10] + --> $DIR/buggy_split_at_mut.rs:LL:CC + | +LL | (from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x10] + --> $DIR/buggy_split_at_mut.rs:LL:CC + | +LL | from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/buggy_split_at_mut.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier1.stderr b/tests/compile-fail/stacked_borrows/deallocate_against_barrier1.stderr new file mode 100644 index 000000000000..593419fe9b37 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/deallocate_against_barrier1.stderr @@ -0,0 +1,34 @@ +error: Undefined Behavior: deallocating while item is protected: [Unique for (call ID)] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information + + = note: inside `std::alloc::dealloc` at rustc_src/src/alloc.rs:LL:CC + = note: inside `::deallocate` at rustc_src/src/alloc.rs:LL:CC + = note: inside `alloc::alloc::box_free::` at rustc_src/src/alloc.rs:LL:CC + = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at rustc_src/src/ptr/mod.rs:LL:CC + = note: inside `std::mem::drop::>` at rustc_src/src/mem/mod.rs:LL:CC +note: inside closure at $DIR/deallocate_against_barrier1.rs:LL:CC + --> $DIR/deallocate_against_barrier1.rs:LL:CC + | +LL | drop(unsafe { Box::from_raw(raw) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `<[closure@$DIR/deallocate_against_barrier1.rs:LL:CC: 12:6] as std::ops::FnOnce<(&mut i32,)>>::call_once - shim` at rustc_src/src/ops/function.rs:LL:CC +note: inside `inner` at $DIR/deallocate_against_barrier1.rs:LL:CC + --> $DIR/deallocate_against_barrier1.rs:LL:CC + | +LL | f(x) + | ^^^^ +note: inside `main` at $DIR/deallocate_against_barrier1.rs:LL:CC + --> $DIR/deallocate_against_barrier1.rs:LL:CC + | +LL | / inner(Box::leak(Box::new(0)), |x| { +LL | | let raw = x as *mut _; +LL | | drop(unsafe { Box::from_raw(raw) }); +LL | | }); + | |______^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.stderr b/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.stderr new file mode 100644 index 000000000000..f6734db71588 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.stderr @@ -0,0 +1,34 @@ +error: Undefined Behavior: deallocating while item is protected: [SharedReadWrite for (call ID)] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information + + = note: inside `std::alloc::dealloc` at rustc_src/src/alloc.rs:LL:CC + = note: inside `::deallocate` at rustc_src/src/alloc.rs:LL:CC + = note: inside `alloc::alloc::box_free::, std::alloc::Global>` at rustc_src/src/alloc.rs:LL:CC + = note: inside `std::ptr::drop_in_place::>> - shim(Some(std::boxed::Box>))` at rustc_src/src/ptr/mod.rs:LL:CC + = note: inside `std::mem::drop::>>` at rustc_src/src/mem/mod.rs:LL:CC +note: inside closure at $DIR/deallocate_against_barrier2.rs:LL:CC + --> $DIR/deallocate_against_barrier2.rs:LL:CC + | +LL | drop(unsafe { Box::from_raw(raw) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `<[closure@$DIR/deallocate_against_barrier2.rs:LL:CC: 16:6] as std::ops::FnOnce<(&std::cell::Cell,)>>::call_once - shim` at rustc_src/src/ops/function.rs:LL:CC +note: inside `inner` at $DIR/deallocate_against_barrier2.rs:LL:CC + --> $DIR/deallocate_against_barrier2.rs:LL:CC + | +LL | f(x) + | ^^^^ +note: inside `main` at $DIR/deallocate_against_barrier2.rs:LL:CC + --> $DIR/deallocate_against_barrier2.rs:LL:CC + | +LL | / inner(Box::leak(Box::new(Cell::new(0))), |x| { +LL | | let raw = x as *const _ as *mut Cell; +LL | | drop(unsafe { Box::from_raw(raw) }); +LL | | }); + | |______^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/illegal_read1.stderr b/tests/compile-fail/stacked_borrows/illegal_read1.stderr new file mode 100644 index 000000000000..ca3147e6221e --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read1.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_read1.rs:LL:CC + | +LL | let _val = *xref; // ...but any use of raw will invalidate our ref. + | ^^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/illegal_read1.rs:LL:CC + | +LL | let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok... + | ^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/illegal_read1.rs:LL:CC + | +LL | let _val = unsafe { *xraw }; + | ^^^^^ + = note: inside `main` at $DIR/illegal_read1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/illegal_read2.stderr b/tests/compile-fail/stacked_borrows/illegal_read2.stderr new file mode 100644 index 000000000000..b6343ddd30b6 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read2.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_read2.rs:LL:CC + | +LL | let _val = *xref; // ...but any use of raw will invalidate our ref. + | ^^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/illegal_read2.rs:LL:CC + | +LL | let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok... + | ^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/illegal_read2.rs:LL:CC + | +LL | let shr = unsafe { &*xraw }; + | ^^^^^^ + = note: inside `main` at $DIR/illegal_read2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/illegal_read3.stderr b/tests/compile-fail/stacked_borrows/illegal_read3.stderr new file mode 100644 index 000000000000..ab26696a765c --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read3.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_read3.rs:LL:CC + | +LL | let _val = *xref2; + | ^^^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/illegal_read3.rs:LL:CC + | +LL | let xref2 = &mut *xref1; + | ^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/illegal_read3.rs:LL:CC + | +LL | let _val = unsafe { *xref1.to }; + | ^^^^^^^^^ + = note: inside `main` at $DIR/illegal_read3.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/illegal_read4.stderr b/tests/compile-fail/stacked_borrows/illegal_read4.stderr new file mode 100644 index 000000000000..968c31ba23af --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read4.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_read4.rs:LL:CC + | +LL | let _illegal = *xref2; + | ^^^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/illegal_read4.rs:LL:CC + | +LL | let xref2 = unsafe { &mut *xraw }; + | ^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/illegal_read4.rs:LL:CC + | +LL | let _val = unsafe { *xraw }; // use the raw again, this invalidates xref2 *even* with the special read except for uniq refs + | ^^^^^ + = note: inside `main` at $DIR/illegal_read4.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/illegal_read5.rs b/tests/compile-fail/stacked_borrows/illegal_read5.rs index d6120cd64ad0..58f506251de2 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read5.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read5.rs @@ -1,5 +1,6 @@ // We *can* have aliasing &RefCell and &mut T, but we cannot read through the former. // Else we couldn't optimize based on the assumption that `xref` below is truly unique. +// normalize-stderr-test: "0x[0-9a-fA-F]+" -> "$$HEX" use std::cell::RefCell; use std::{mem, ptr}; diff --git a/tests/compile-fail/stacked_borrows/illegal_read5.stderr b/tests/compile-fail/stacked_borrows/illegal_read5.stderr new file mode 100644 index 000000000000..df6f0a1c6886 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read5.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[$HEX], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_read5.rs:LL:CC + | +LL | let _val = *xref; // the mutable one is dead and gone + | ^^^^^ + | | + | attempting a read access using at ALLOC[$HEX], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[$HEX..$HEX] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [$HEX..$HEX] + --> $DIR/illegal_read5.rs:LL:CC + | +LL | let xref: &mut i32 = &mut *refmut; + | ^^^^^^^^^^^^ +help: was later invalidated at offsets [$HEX..$HEX] + --> $DIR/illegal_read5.rs:LL:CC + | +LL | mem::forget(unsafe { ptr::read(xshr) }); // but after reading through the shared ref + | ^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/illegal_read5.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/illegal_read6.stderr b/tests/compile-fail/stacked_borrows/illegal_read6.stderr new file mode 100644 index 000000000000..c2be5bb370c5 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read6.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_read6.rs:LL:CC + | +LL | let _val = *raw; + | ^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: tag was most recently created at offsets [0x0..0x4] + --> $DIR/illegal_read6.rs:LL:CC + | +LL | let raw = x as *mut _; + | ^ +help: tag was later invalidated at offsets [0x0..0x4] + --> $DIR/illegal_read6.rs:LL:CC + | +LL | let x = &mut *x; // kill `raw` + | ^^^^^^^ + = note: inside `main` at $DIR/illegal_read6.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/illegal_read7.stderr b/tests/compile-fail/stacked_borrows/illegal_read7.stderr new file mode 100644 index 000000000000..921d8872b70b --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read7.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_read7.rs:LL:CC + | +LL | let _val = *x.get_mut(); + | ^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/illegal_read7.rs:LL:CC + | +LL | let x = &mut *raw; + | ^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/illegal_read7.rs:LL:CC + | +LL | let _val = ptr::read(raw); + | ^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/illegal_read7.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/illegal_read8.stderr b/tests/compile-fail/stacked_borrows/illegal_read8.stderr new file mode 100644 index 000000000000..6c6168032b24 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read8.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_read8.rs:LL:CC + | +LL | let _fail = *y1; + | ^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/illegal_read8.rs:LL:CC + | +LL | let y1: &i32 = mem::transmute(&*x); // launder lifetimes + | ^^^^^^^^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/illegal_read8.rs:LL:CC + | +LL | *y2 += 1; + | ^^^^^^^^ + = note: inside `main` at $DIR/illegal_read8.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/illegal_write1.stderr b/tests/compile-fail/stacked_borrows/illegal_write1.stderr new file mode 100644 index 000000000000..08fa05ff9f1f --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_write1.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_write1.rs:LL:CC + | +LL | let _x = *xref; + | ^^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/illegal_write1.rs:LL:CC + | +LL | let xref = &*target; + | ^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/illegal_write1.rs:LL:CC + | +LL | unsafe { *x = 42; } // invalidates shared ref, activates raw + | ^^^^^^^ + = note: inside `main` at $DIR/illegal_write1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/illegal_write2.stderr b/tests/compile-fail/stacked_borrows/illegal_write2.stderr new file mode 100644 index 000000000000..13f41eea9153 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_write2.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_write2.rs:LL:CC + | +LL | unsafe { *target2 = 13; } + | ^^^^^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: tag was most recently created at offsets [0x0..0x4] + --> $DIR/illegal_write2.rs:LL:CC + | +LL | let target2 = target as *mut _; + | ^^^^^^ +help: tag was later invalidated at offsets [0x0..0x4] + --> $DIR/illegal_write2.rs:LL:CC + | +LL | drop(&mut *target); // reborrow + | ^^^^^^^^^^^^ + = note: inside `main` at $DIR/illegal_write2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/illegal_write3.stderr b/tests/compile-fail/stacked_borrows/illegal_write3.stderr new file mode 100644 index 000000000000..b37caee5ef20 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_write3.stderr @@ -0,0 +1,22 @@ +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location + --> $DIR/illegal_write3.rs:LL:CC + | +LL | unsafe { *ptr = 42; } + | ^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: tag was most recently created at offsets [0x0..0x4] + --> $DIR/illegal_write3.rs:LL:CC + | +LL | let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag + | ^^^^^ + = note: inside `main` at $DIR/illegal_write3.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/illegal_write4.stderr b/tests/compile-fail/stacked_borrows/illegal_write4.stderr new file mode 100644 index 000000000000..5c0b4ec868e2 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_write4.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_write4.rs:LL:CC + | +LL | let _val = *reference; + | ^^^^^^^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/illegal_write4.rs:LL:CC + | +LL | let reference = unsafe { &*raw }; // freeze + | ^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/illegal_write4.rs:LL:CC + | +LL | let _mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag + | ^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/illegal_write4.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/illegal_write5.stderr b/tests/compile-fail/stacked_borrows/illegal_write5.stderr new file mode 100644 index 000000000000..f9a4dcfd8d21 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_write5.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_write5.rs:LL:CC + | +LL | let _val = *xref; + | ^^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/illegal_write5.rs:LL:CC + | +LL | let xref = unsafe { &mut *xraw }; + | ^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/illegal_write5.rs:LL:CC + | +LL | unsafe { *xraw = 15 }; + | ^^^^^^^^^^ + = note: inside `main` at $DIR/illegal_write5.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/illegal_write6.stderr b/tests/compile-fail/stacked_borrows/illegal_write6.stderr new file mode 100644 index 000000000000..5861aeefaf46 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_write6.stderr @@ -0,0 +1,39 @@ +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] + --> $DIR/illegal_write6.rs:LL:CC + | +LL | unsafe { *y = 2; } + | ^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: tag was most recently created at offsets [0x0..0x4] + --> $DIR/illegal_write6.rs:LL:CC + | +LL | let p = x as *mut u32; + | ^ +help: was protected due to a tag which was created here + --> $DIR/illegal_write6.rs:LL:CC + | +LL | foo(x, p); + | ^ +help: this protector is live for this call + --> $DIR/illegal_write6.rs:LL:CC + | +LL | / fn foo(a: &mut u32, y: *mut u32) -> u32 { +LL | | *a = 1; +LL | | let _b = &*a; +LL | | unsafe { *y = 2; } +LL | | return *a; +LL | | } + | |_^ + = note: inside `foo` at $DIR/illegal_write6.rs:LL:CC +note: inside `main` at $DIR/illegal_write6.rs:LL:CC + --> $DIR/illegal_write6.rs:LL:CC + | +LL | foo(x, p); + | ^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/interior_mut1.stderr b/tests/compile-fail/stacked_borrows/interior_mut1.stderr new file mode 100644 index 000000000000..af4163c93605 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/interior_mut1.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/interior_mut1.rs:LL:CC + | +LL | let _val = *inner_shr.get(); + | ^^^^^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/interior_mut1.rs:LL:CC + | +LL | let inner_shr = &*inner_uniq; // adds a SharedReadWrite + | ^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/interior_mut1.rs:LL:CC + | +LL | *c.get() = UnsafeCell::new(1); // invalidates inner_shr + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/interior_mut1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/interior_mut2.stderr b/tests/compile-fail/stacked_borrows/interior_mut2.stderr new file mode 100644 index 000000000000..5a4ddf381e71 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/interior_mut2.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/interior_mut2.rs:LL:CC + | +LL | let _val = *inner_shr.get(); + | ^^^^^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/interior_mut2.rs:LL:CC + | +LL | let inner_shr = &*inner_uniq; + | ^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/interior_mut2.rs:LL:CC + | +LL | *c.get() = UnsafeCell::new(0); // now inner_shr gets invalidated + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/interior_mut2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/invalidate_against_barrier1.stderr b/tests/compile-fail/stacked_borrows/invalidate_against_barrier1.stderr new file mode 100644 index 000000000000..47f7a06a8585 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/invalidate_against_barrier1.stderr @@ -0,0 +1,39 @@ +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] + --> $DIR/invalidate_against_barrier1.rs:LL:CC + | +LL | let _val = unsafe { *x }; + | ^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: tag was most recently created at offsets [0x0..0x4] + --> $DIR/invalidate_against_barrier1.rs:LL:CC + | +LL | let xraw = &mut x as *mut _; + | ^^^^^^ +help: was protected due to a tag which was created here + --> $DIR/invalidate_against_barrier1.rs:LL:CC + | +LL | inner(xraw, xref); + | ^^^^ +help: this protector is live for this call + --> $DIR/invalidate_against_barrier1.rs:LL:CC + | +LL | / fn inner(x: *mut i32, _y: &mut i32) { +LL | | // If `x` and `y` alias, retagging is fine with this... but we really +LL | | // shouldn't be allowed to use `x` at all because `y` was assumed to be +LL | | // unique for the duration of this call. +LL | | let _val = unsafe { *x }; +LL | | } + | |_^ + = note: inside `inner` at $DIR/invalidate_against_barrier1.rs:LL:CC +note: inside `main` at $DIR/invalidate_against_barrier1.rs:LL:CC + --> $DIR/invalidate_against_barrier1.rs:LL:CC + | +LL | inner(xraw, xref); + | ^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/invalidate_against_barrier2.stderr b/tests/compile-fail/stacked_borrows/invalidate_against_barrier2.stderr new file mode 100644 index 000000000000..fa2e6aa05a2b --- /dev/null +++ b/tests/compile-fail/stacked_borrows/invalidate_against_barrier2.stderr @@ -0,0 +1,39 @@ +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] + --> $DIR/invalidate_against_barrier2.rs:LL:CC + | +LL | unsafe { *x = 0 }; + | ^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: tag was most recently created at offsets [0x0..0x4] + --> $DIR/invalidate_against_barrier2.rs:LL:CC + | +LL | let xraw = &mut x as *mut _; + | ^^^^^^ +help: was protected due to a tag which was created here + --> $DIR/invalidate_against_barrier2.rs:LL:CC + | +LL | inner(xraw, xref); + | ^^^^ +help: this protector is live for this call + --> $DIR/invalidate_against_barrier2.rs:LL:CC + | +LL | / fn inner(x: *mut i32, _y: &i32) { +LL | | // If `x` and `y` alias, retagging is fine with this... but we really +LL | | // shouldn't be allowed to write to `x` at all because `y` was assumed to be +LL | | // immutable for the duration of this call. +LL | | unsafe { *x = 0 }; +LL | | } + | |_^ + = note: inside `inner` at $DIR/invalidate_against_barrier2.rs:LL:CC +note: inside `main` at $DIR/invalidate_against_barrier2.rs:LL:CC + --> $DIR/invalidate_against_barrier2.rs:LL:CC + | +LL | inner(xraw, xref); + | ^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-1.stderr b/tests/compile-fail/stacked_borrows/issue-miri-1050-1.stderr new file mode 100644 index 000000000000..70c774818bce --- /dev/null +++ b/tests/compile-fail/stacked_borrows/issue-miri-1050-1.stderr @@ -0,0 +1,17 @@ +error: Undefined Behavior: ALLOC has size 2, so pointer to 4 bytes starting at offset 0 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::boxed::Box::::from_raw_in` at rustc_src/src/boxed.rs:LL:CC + = note: inside `std::boxed::Box::::from_raw` at rustc_src/src/boxed.rs:LL:CC +note: inside `main` at $DIR/issue-miri-1050-1.rs:LL:CC + --> $DIR/issue-miri-1050-1.rs:LL:CC + | +LL | Box::from_raw(ptr as *mut u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs b/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs index 30cbf0b339a1..8f0b47501604 100644 --- a/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs +++ b/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs @@ -1,4 +1,4 @@ -// error-pattern: 0x4 is not a valid pointer +// error-pattern: is not a valid pointer use std::ptr::NonNull; fn main() { unsafe { diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-2.stderr b/tests/compile-fail/stacked_borrows/issue-miri-1050-2.stderr new file mode 100644 index 000000000000..579f728b2b07 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/issue-miri-1050-2.stderr @@ -0,0 +1,17 @@ +error: Undefined Behavior: 0x4 is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::boxed::Box::::from_raw_in` at rustc_src/src/boxed.rs:LL:CC + = note: inside `std::boxed::Box::::from_raw` at rustc_src/src/boxed.rs:LL:CC +note: inside `main` at $DIR/issue-miri-1050-2.rs:LL:CC + --> $DIR/issue-miri-1050-2.rs:LL:CC + | +LL | Box::from_raw(ptr.as_ptr()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/load_invalid_mut.stderr b/tests/compile-fail/stacked_borrows/load_invalid_mut.stderr new file mode 100644 index 000000000000..00eda4fe5a31 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/load_invalid_mut.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: trying to reborrow for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/load_invalid_mut.rs:LL:CC + | +LL | let _val = *xref_in_mem; + | ^^^^^^^^^^^^ + | | + | trying to reborrow for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/load_invalid_mut.rs:LL:CC + | +LL | let xref_in_mem = Box::new(xref); + | ^^^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/load_invalid_mut.rs:LL:CC + | +LL | let _val = unsafe { *xraw }; // invalidate xref + | ^^^^^ + = note: inside `main` at $DIR/load_invalid_mut.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/load_invalid_shr.stderr b/tests/compile-fail/stacked_borrows/load_invalid_shr.stderr new file mode 100644 index 000000000000..eb61b4762f84 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/load_invalid_shr.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/load_invalid_shr.rs:LL:CC + | +LL | let _val = *xref_in_mem; + | ^^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/load_invalid_shr.rs:LL:CC + | +LL | let xref_in_mem = Box::new(xref); + | ^^^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/load_invalid_shr.rs:LL:CC + | +LL | unsafe { *xraw = 42 }; // unfreeze + | ^^^^^^^^^^ + = note: inside `main` at $DIR/load_invalid_shr.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/mut_exclusive_violation1.stderr b/tests/compile-fail/stacked_borrows/mut_exclusive_violation1.stderr new file mode 100644 index 000000000000..2d8ef7c1a4eb --- /dev/null +++ b/tests/compile-fail/stacked_borrows/mut_exclusive_violation1.stderr @@ -0,0 +1,37 @@ +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/mut_exclusive_violation1.rs:LL:CC + | +LL | *LEAK = 7; + | ^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: tag was most recently created at offsets [0x0..0x4] + --> $DIR/mut_exclusive_violation1.rs:LL:CC + | +LL | LEAK = x as *const _ as *mut _; + | ^ +help: tag was later invalidated at offsets [0x0..0x4] + --> $DIR/mut_exclusive_violation1.rs:LL:CC + | +LL | *our = 5; + | ^^^^^^^^ + = note: inside `unknown_code_2` at $DIR/mut_exclusive_violation1.rs:LL:CC +note: inside `demo_mut_advanced_unique` at $DIR/mut_exclusive_violation1.rs:LL:CC + --> $DIR/mut_exclusive_violation1.rs:LL:CC + | +LL | unknown_code_2(); + | ^^^^^^^^^^^^^^^^ +note: inside `main` at $DIR/mut_exclusive_violation1.rs:LL:CC + --> $DIR/mut_exclusive_violation1.rs:LL:CC + | +LL | demo_mut_advanced_unique(&mut 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/mut_exclusive_violation2.stderr b/tests/compile-fail/stacked_borrows/mut_exclusive_violation2.stderr new file mode 100644 index 000000000000..ae0eab467bf6 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/mut_exclusive_violation2.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/mut_exclusive_violation2.rs:LL:CC + | +LL | let _val = *raw1; + | ^^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/mut_exclusive_violation2.rs:LL:CC + | +LL | let raw1 = ptr1.as_mut(); + | ^^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/mut_exclusive_violation2.rs:LL:CC + | +LL | let _raw2 = ptr2.as_mut(); + | ^^^^^^^^^^^^^ + = note: inside `main` at $DIR/mut_exclusive_violation2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/outdated_local.stderr b/tests/compile-fail/stacked_borrows/outdated_local.stderr new file mode 100644 index 000000000000..1c1deac2317f --- /dev/null +++ b/tests/compile-fail/stacked_borrows/outdated_local.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/outdated_local.rs:LL:CC + | +LL | assert_eq!(unsafe { *y }, 1); + | ^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: tag was most recently created at offsets [0x0..0x4] + --> $DIR/outdated_local.rs:LL:CC + | +LL | let y: *const i32 = &x; + | ^^ +help: tag was later invalidated at offsets [0x0..0x4] + --> $DIR/outdated_local.rs:LL:CC + | +LL | x = 1; // this invalidates y by reactivating the lowermost uniq borrow for this local + | ^^^^^ + = note: inside `main` at $DIR/outdated_local.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_mut.stderr b/tests/compile-fail/stacked_borrows/pass_invalid_mut.stderr new file mode 100644 index 000000000000..280e51693a5c --- /dev/null +++ b/tests/compile-fail/stacked_borrows/pass_invalid_mut.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/pass_invalid_mut.rs:LL:CC + | +LL | foo(xref); + | ^^^^ + | | + | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/pass_invalid_mut.rs:LL:CC + | +LL | let xref = unsafe { &mut *xraw }; + | ^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/pass_invalid_mut.rs:LL:CC + | +LL | let _val = unsafe { *xraw }; // invalidate xref + | ^^^^^ + = note: inside `main` at $DIR/pass_invalid_mut.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_shr.stderr b/tests/compile-fail/stacked_borrows/pass_invalid_shr.stderr new file mode 100644 index 000000000000..b111832193b9 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/pass_invalid_shr.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/pass_invalid_shr.rs:LL:CC + | +LL | foo(xref); + | ^^^^ + | | + | trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/pass_invalid_shr.rs:LL:CC + | +LL | let xref = unsafe { &*xraw }; + | ^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/pass_invalid_shr.rs:LL:CC + | +LL | unsafe { *xraw = 42 }; // unfreeze + | ^^^^^^^^^^ + = note: inside `main` at $DIR/pass_invalid_shr.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/pointer_smuggling.stderr b/tests/compile-fail/stacked_borrows/pointer_smuggling.stderr new file mode 100644 index 000000000000..097de439f79d --- /dev/null +++ b/tests/compile-fail/stacked_borrows/pointer_smuggling.stderr @@ -0,0 +1,32 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/pointer_smuggling.rs:LL:CC + | +LL | let _x = unsafe { *PTR }; + | ^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x1] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: tag was most recently created at offsets [0x0..0x1] + --> $DIR/pointer_smuggling.rs:LL:CC + | +LL | PTR = x; + | ^ +help: tag was later invalidated at offsets [0x0..0x1] + --> $DIR/pointer_smuggling.rs:LL:CC + | +LL | *val = 2; // this invalidates any raw ptrs `fun1` might have created. + | ^^^^^^^^ + = note: inside `fun2` at $DIR/pointer_smuggling.rs:LL:CC +note: inside `main` at $DIR/pointer_smuggling.rs:LL:CC + --> $DIR/pointer_smuggling.rs:LL:CC + | +LL | fun2(); // if they now use a raw ptr they break our reference + | ^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/raw_tracking.stderr b/tests/compile-fail/stacked_borrows/raw_tracking.stderr new file mode 100644 index 000000000000..a03d55a90486 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/raw_tracking.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/raw_tracking.rs:LL:CC + | +LL | unsafe { *raw1 = 13; } + | ^^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/raw_tracking.rs:LL:CC + | +LL | let raw1 = &mut l as *mut _; + | ^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/raw_tracking.rs:LL:CC + | +LL | let raw2 = &mut l as *mut _; // invalidates raw1 + | ^^^^^^ + = note: inside `main` at $DIR/raw_tracking.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut.stderr b/tests/compile-fail/stacked_borrows/return_invalid_mut.stderr new file mode 100644 index 000000000000..6de657b82980 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut.stderr @@ -0,0 +1,32 @@ +error: Undefined Behavior: trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + --> $DIR/return_invalid_mut.rs:LL:CC + | +LL | ret + | ^^^ + | | + | trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x4..0x8] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x4..0x8] + --> $DIR/return_invalid_mut.rs:LL:CC + | +LL | let ret = unsafe { &mut (*xraw).1 }; + | ^^^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x8] + --> $DIR/return_invalid_mut.rs:LL:CC + | +LL | let _val = unsafe { *xraw }; // invalidate xref + | ^^^^^ + = note: inside `foo` at $DIR/return_invalid_mut.rs:LL:CC +note: inside `main` at $DIR/return_invalid_mut.rs:LL:CC + --> $DIR/return_invalid_mut.rs:LL:CC + | +LL | foo(&mut (1, 2)); + | ^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut_option.stderr b/tests/compile-fail/stacked_borrows/return_invalid_mut_option.stderr new file mode 100644 index 000000000000..8b95765dcc46 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut_option.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + --> $DIR/return_invalid_mut_option.rs:LL:CC + | +LL | Some(_x) => {}, + | ^^ + | | + | trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x4..0x8] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x4..0x8] + --> $DIR/return_invalid_mut_option.rs:LL:CC + | +LL | let ret = Some(ret); + | ^^^ +help: was later invalidated at offsets [0x0..0x8] + --> $DIR/return_invalid_mut_option.rs:LL:CC + | +LL | let _val = unsafe { *xraw }; // invalidate xref + | ^^^^^ + = note: inside `main` at $DIR/return_invalid_mut_option.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.stderr b/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.stderr new file mode 100644 index 000000000000..f9e6d65c78e6 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + --> $DIR/return_invalid_mut_tuple.rs:LL:CC + | +LL | foo(&mut (1, 2)).0; + | ^^^^^^^^^^^^^^^^^^ + | | + | trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x4..0x8] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x4..0x8] + --> $DIR/return_invalid_mut_tuple.rs:LL:CC + | +LL | let ret = (unsafe { &mut (*xraw).1 },); + | ^^^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x8] + --> $DIR/return_invalid_mut_tuple.rs:LL:CC + | +LL | let _val = unsafe { *xraw }; // invalidate xref + | ^^^^^ + = note: inside `main` at $DIR/return_invalid_mut_tuple.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr.stderr b/tests/compile-fail/stacked_borrows/return_invalid_shr.stderr new file mode 100644 index 000000000000..20dcb8e93c2c --- /dev/null +++ b/tests/compile-fail/stacked_borrows/return_invalid_shr.stderr @@ -0,0 +1,32 @@ +error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + --> $DIR/return_invalid_shr.rs:LL:CC + | +LL | ret + | ^^^ + | | + | trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x4..0x8] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x4..0x8] + --> $DIR/return_invalid_shr.rs:LL:CC + | +LL | let ret = unsafe { &(*xraw).1 }; + | ^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x8] + --> $DIR/return_invalid_shr.rs:LL:CC + | +LL | unsafe { *xraw = (42, 23) }; // unfreeze + | ^^^^^^^^^^^^^^^^ + = note: inside `foo` at $DIR/return_invalid_shr.rs:LL:CC +note: inside `main` at $DIR/return_invalid_shr.rs:LL:CC + --> $DIR/return_invalid_shr.rs:LL:CC + | +LL | foo(&mut (1, 2)); + | ^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr_option.stderr b/tests/compile-fail/stacked_borrows/return_invalid_shr_option.stderr new file mode 100644 index 000000000000..0c41a10a3f97 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/return_invalid_shr_option.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + --> $DIR/return_invalid_shr_option.rs:LL:CC + | +LL | Some(_x) => {}, + | ^^ + | | + | trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x4..0x8] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x4..0x8] + --> $DIR/return_invalid_shr_option.rs:LL:CC + | +LL | let ret = Some(unsafe { &(*xraw).1 }); + | ^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x8] + --> $DIR/return_invalid_shr_option.rs:LL:CC + | +LL | unsafe { *xraw = (42, 23) }; // unfreeze + | ^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/return_invalid_shr_option.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.stderr b/tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.stderr new file mode 100644 index 000000000000..9e7be7ad0138 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + --> $DIR/return_invalid_shr_tuple.rs:LL:CC + | +LL | foo(&mut (1, 2)).0; + | ^^^^^^^^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x4..0x8] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x4..0x8] + --> $DIR/return_invalid_shr_tuple.rs:LL:CC + | +LL | let ret = (unsafe { &(*xraw).1 },); + | ^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x8] + --> $DIR/return_invalid_shr_tuple.rs:LL:CC + | +LL | unsafe { *xraw = (42, 23) }; // unfreeze + | ^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/return_invalid_shr_tuple.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr b/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr new file mode 100644 index 000000000000..576a21bbf6d4 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/shared_rw_borrows_are_weak1.rs:LL:CC + | +LL | y.get_mut(); + | ^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/shared_rw_borrows_are_weak1.rs:LL:CC + | +LL | let y: &mut Cell = mem::transmute(&mut *x); // launder lifetime + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/shared_rw_borrows_are_weak1.rs:LL:CC + | +LL | shr_rw.set(1); + | ^^^^^^^^^^^^^ + = note: inside `main` at $DIR/shared_rw_borrows_are_weak1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.rs b/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.rs index 942bb503db02..d4aef74dff6b 100644 --- a/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.rs +++ b/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.rs @@ -1,6 +1,7 @@ // We want to test that granting a SharedReadWrite will be added // *below* an already granted SharedReadWrite -- so writing to // the SharedReadWrite will invalidate the SharedReadWrite. +// normalize-stderr-test: "0x[0-9a-fA-F]+" -> "$$HEX" use std::mem; use std::cell::RefCell; diff --git a/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr b/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr new file mode 100644 index 000000000000..e2159ed5892f --- /dev/null +++ b/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[$HEX], but that tag does not exist in the borrow stack for this location + --> $DIR/shared_rw_borrows_are_weak2.rs:LL:CC + | +LL | let _val = *y; + | ^^ + | | + | attempting a read access using at ALLOC[$HEX], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[$HEX..$HEX] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [$HEX..$HEX] + --> $DIR/shared_rw_borrows_are_weak2.rs:LL:CC + | +LL | let y: &i32 = mem::transmute(&*x.borrow()); // launder lifetime + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: was later invalidated at offsets [$HEX..$HEX] + --> $DIR/shared_rw_borrows_are_weak2.rs:LL:CC + | +LL | shr_rw.replace(1); + | ^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/shared_rw_borrows_are_weak2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/shr_frozen_violation1.stderr b/tests/compile-fail/stacked_borrows/shr_frozen_violation1.stderr new file mode 100644 index 000000000000..689ad1c6b668 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/shr_frozen_violation1.stderr @@ -0,0 +1,32 @@ +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location + --> $DIR/shr_frozen_violation1.rs:LL:CC + | +LL | unsafe { *(x as *const i32 as *mut i32) = 7; } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: tag was most recently created at offsets [0x0..0x4] + --> $DIR/shr_frozen_violation1.rs:LL:CC + | +LL | unsafe { *(x as *const i32 as *mut i32) = 7; } + | ^ + = note: inside `unknown_code` at $DIR/shr_frozen_violation1.rs:LL:CC +note: inside `foo` at $DIR/shr_frozen_violation1.rs:LL:CC + --> $DIR/shr_frozen_violation1.rs:LL:CC + | +LL | unknown_code(&*x); + | ^^^^^^^^^^^^^^^^^ +note: inside `main` at $DIR/shr_frozen_violation1.rs:LL:CC + --> $DIR/shr_frozen_violation1.rs:LL:CC + | +LL | println!("{}", foo(&mut 0)); + | ^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/static_memory_modification.rs b/tests/compile-fail/stacked_borrows/static_memory_modification.rs index 417a03bb0335..72e2ed938124 100644 --- a/tests/compile-fail/stacked_borrows/static_memory_modification.rs +++ b/tests/compile-fail/stacked_borrows/static_memory_modification.rs @@ -3,6 +3,6 @@ static X: usize = 5; #[allow(mutable_transmutes)] fn main() { let _x = unsafe { - std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR writing to alloc1 which is read-only + std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR writing to ALLOC which is read-only }; } diff --git a/tests/compile-fail/stacked_borrows/static_memory_modification.stderr b/tests/compile-fail/stacked_borrows/static_memory_modification.stderr new file mode 100644 index 000000000000..091eb29f64d7 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/static_memory_modification.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: writing to ALLOC which is read-only + --> $DIR/static_memory_modification.rs:LL:CC + | +LL | std::mem::transmute::<&usize, &mut usize>(&X) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ writing to ALLOC which is read-only + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/static_memory_modification.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/transmute-is-no-escape.stderr b/tests/compile-fail/stacked_borrows/transmute-is-no-escape.stderr new file mode 100644 index 000000000000..f2ea4f919c67 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/transmute-is-no-escape.stderr @@ -0,0 +1,18 @@ +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/transmute-is-no-escape.rs:LL:CC + | +LL | unsafe { *raw = 13; } + | ^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information + + = note: inside `main` at $DIR/transmute-is-no-escape.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/unescaped_local.stderr b/tests/compile-fail/stacked_borrows/unescaped_local.stderr new file mode 100644 index 000000000000..a8d869549a9a --- /dev/null +++ b/tests/compile-fail/stacked_borrows/unescaped_local.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/unescaped_local.rs:LL:CC + | +LL | unsafe { *raw = 13; } + | ^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: tag was most recently created at offsets [0x0..0x4] + --> $DIR/unescaped_local.rs:LL:CC + | +LL | let raw = &mut x as *mut i32 as usize as *mut i32; + | ^^^^^^ +help: tag was later invalidated at offsets [0x0..0x4] + --> $DIR/unescaped_local.rs:LL:CC + | +LL | let _ptr = &mut x; + | ^^^^^^ + = note: inside `main` at $DIR/unescaped_local.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/unescaped_static.stderr b/tests/compile-fail/stacked_borrows/unescaped_static.stderr new file mode 100644 index 000000000000..b191855644c2 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/unescaped_static.stderr @@ -0,0 +1,18 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x1], but that tag does not exist in the borrow stack for this location + --> $DIR/unescaped_static.rs:LL:CC + | +LL | let _val = unsafe { *ptr_to_first.add(1) }; + | ^^^^^^^^^^^^^^^^^^^^ + | | + | attempting a read access using at ALLOC[0x1], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x1..0x2] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information + + = note: inside `main` at $DIR/unescaped_static.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/zst_slice.stderr b/tests/compile-fail/stacked_borrows/zst_slice.stderr new file mode 100644 index 000000000000..f9d8b024e986 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/zst_slice.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information + + = note: inside `core::slice::::get_unchecked::` at rustc_src/src/slice/mod.rs:LL:CC +note: inside `main` at $DIR/zst_slice.rs:LL:CC + --> $DIR/zst_slice.rs:LL:CC + | +LL | assert_eq!(*s.get_unchecked(1), 2); + | ^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/static_memory_modification1.stderr b/tests/compile-fail/static_memory_modification1.stderr new file mode 100644 index 000000000000..a37a79fa56f9 --- /dev/null +++ b/tests/compile-fail/static_memory_modification1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: writing to ALLOC which is read-only + --> $DIR/static_memory_modification1.rs:LL:CC + | +LL | *std::mem::transmute::<&usize, &mut usize>(&X) = 6; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ writing to ALLOC which is read-only + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/static_memory_modification1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/static_memory_modification2.stderr b/tests/compile-fail/static_memory_modification2.stderr new file mode 100644 index 000000000000..d38f3f6342c3 --- /dev/null +++ b/tests/compile-fail/static_memory_modification2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: writing to ALLOC which is read-only + --> $DIR/static_memory_modification2.rs:LL:CC + | +LL | transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ writing to ALLOC which is read-only + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/static_memory_modification2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/static_memory_modification3.stderr b/tests/compile-fail/static_memory_modification3.stderr new file mode 100644 index 000000000000..96e3877c54fb --- /dev/null +++ b/tests/compile-fail/static_memory_modification3.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: writing to ALLOC which is read-only + --> $DIR/static_memory_modification3.rs:LL:CC + | +LL | transmute::<&[u8], &mut [u8]>(bs)[4] = 42; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ writing to ALLOC which is read-only + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/static_memory_modification3.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/strict-provenance-offset.stderr b/tests/compile-fail/strict-provenance-offset.stderr new file mode 100644 index 000000000000..482b7a404c51 --- /dev/null +++ b/tests/compile-fail/strict-provenance-offset.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: pointer arithmetic failed: $HEX is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::ptr::const_ptr::::offset` at rustc_src/src/ptr/const_ptr.rs:LL:CC +note: inside `main` at $DIR/strict-provenance-offset.rs:LL:CC + --> $DIR/strict-provenance-offset.rs:LL:CC + | +LL | let _ = unsafe { roundtrip.offset(1) }; + | ^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/strict_provenance_transmute.stderr b/tests/compile-fail/strict_provenance_transmute.stderr new file mode 100644 index 000000000000..c2140b9786ca --- /dev/null +++ b/tests/compile-fail/strict_provenance_transmute.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: type validation failed: encountered pointer to $HEX[ALLOC], but expected initialized plain (non-pointer) bytes + --> $DIR/strict_provenance_transmute.rs:LL:CC + | +LL | let left_int: usize = mem::transmute(left); + | ^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to $HEX[ALLOC], but expected initialized plain (non-pointer) bytes + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `deref` at $DIR/strict_provenance_transmute.rs:LL:CC +note: inside `main` at $DIR/strict_provenance_transmute.rs:LL:CC + --> $DIR/strict_provenance_transmute.rs:LL:CC + | +LL | deref(ptr1, ptr2.with_addr(ptr1.addr())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_cond_double_destroy.stderr b/tests/compile-fail/sync/libc_pthread_cond_double_destroy.stderr new file mode 100644 index 000000000000..362952678139 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_cond_double_destroy.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> $DIR/libc_pthread_cond_double_destroy.rs:LL:CC + | +LL | libc::pthread_cond_destroy(cond.as_mut_ptr()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/libc_pthread_cond_double_destroy.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_condattr_double_destroy.stderr b/tests/compile-fail/sync/libc_pthread_condattr_double_destroy.stderr new file mode 100644 index 000000000000..14439445e727 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_condattr_double_destroy.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> $DIR/libc_pthread_condattr_double_destroy.rs:LL:CC + | +LL | libc::pthread_condattr_destroy(attr.as_mut_ptr()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/libc_pthread_condattr_double_destroy.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_mutex_NULL_deadlock.stderr b/tests/compile-fail/sync/libc_pthread_mutex_NULL_deadlock.stderr new file mode 100644 index 000000000000..d42174b9fb74 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_mutex_NULL_deadlock.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: trying to acquire already locked default mutex + --> $DIR/libc_pthread_mutex_NULL_deadlock.rs:LL:CC + | +LL | libc::pthread_mutex_lock(&mut mutex as *mut _); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to acquire already locked default mutex + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/libc_pthread_mutex_NULL_deadlock.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_mutex_deadlock.stderr b/tests/compile-fail/sync/libc_pthread_mutex_deadlock.stderr new file mode 100644 index 000000000000..ac37096ad80d --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_mutex_deadlock.stderr @@ -0,0 +1,14 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: deadlock: the evaluated program deadlocked + --> $DIR/libc_pthread_mutex_deadlock.rs:LL:CC + | +LL | assert_eq!(libc::pthread_mutex_lock(lock_copy.0.get() as *mut _), 0); + | ^ the evaluated program deadlocked + | + = note: inside closure at $DIR/libc_pthread_mutex_deadlock.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/sync/libc_pthread_mutex_default_deadlock.stderr b/tests/compile-fail/sync/libc_pthread_mutex_default_deadlock.stderr new file mode 100644 index 000000000000..cb5daef68cbe --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_mutex_default_deadlock.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: trying to acquire already locked default mutex + --> $DIR/libc_pthread_mutex_default_deadlock.rs:LL:CC + | +LL | libc::pthread_mutex_lock(&mut mutex as *mut _); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to acquire already locked default mutex + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/libc_pthread_mutex_default_deadlock.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_mutex_destroy_locked.stderr b/tests/compile-fail/sync/libc_pthread_mutex_destroy_locked.stderr new file mode 100644 index 000000000000..96a3c645ab63 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_mutex_destroy_locked.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: destroyed a locked mutex + --> $DIR/libc_pthread_mutex_destroy_locked.rs:LL:CC + | +LL | libc::pthread_mutex_destroy(&mut mutex as *mut _); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ destroyed a locked mutex + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/libc_pthread_mutex_destroy_locked.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_mutex_double_destroy.stderr b/tests/compile-fail/sync/libc_pthread_mutex_double_destroy.stderr new file mode 100644 index 000000000000..9df2dd32b804 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_mutex_double_destroy.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> $DIR/libc_pthread_mutex_double_destroy.rs:LL:CC + | +LL | libc::pthread_mutex_destroy(mutex.as_mut_ptr()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/libc_pthread_mutex_double_destroy.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.stderr b/tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.stderr new file mode 100644 index 000000000000..b7877d3aa397 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.stderr @@ -0,0 +1,12 @@ +error: deadlock: the evaluated program deadlocked + --> $DIR/libc_pthread_mutex_normal_deadlock.rs:LL:CC + | +LL | libc::pthread_mutex_lock(&mut mutex as *mut _); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program deadlocked + | + = note: inside `main` at $DIR/libc_pthread_mutex_normal_deadlock.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr b/tests/compile-fail/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr new file mode 100644 index 000000000000..b0858374cd9f --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked by the current thread + --> $DIR/libc_pthread_mutex_normal_unlock_unlocked.rs:LL:CC + | +LL | libc::pthread_mutex_unlock(&mut mutex as *mut _); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked by the current thread + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/libc_pthread_mutex_normal_unlock_unlocked.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.stderr b/tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.stderr new file mode 100644 index 000000000000..6603b264d9b4 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: unlocked a default mutex that was not locked by the current thread + --> $DIR/libc_pthread_mutex_wrong_owner.rs:LL:CC + | +LL | ...t_eq!(libc::pthread_mutex_unlock(lock_copy.0.get() as *mut _), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unlocked a default mutex that was not locked by the current thread + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/libc_pthread_mutex_wrong_owner.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.stderr b/tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.stderr new file mode 100644 index 000000000000..21adfa61d115 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> $DIR/libc_pthread_mutexattr_double_destroy.rs:LL:CC + | +LL | libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/libc_pthread_mutexattr_double_destroy.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_destroy_read_locked.stderr b/tests/compile-fail/sync/libc_pthread_rwlock_destroy_read_locked.stderr new file mode 100644 index 000000000000..80a88a773e5c --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_destroy_read_locked.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: destroyed a locked rwlock + --> $DIR/libc_pthread_rwlock_destroy_read_locked.rs:LL:CC + | +LL | libc::pthread_rwlock_destroy(rw.get()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ destroyed a locked rwlock + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/libc_pthread_rwlock_destroy_read_locked.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_destroy_write_locked.stderr b/tests/compile-fail/sync/libc_pthread_rwlock_destroy_write_locked.stderr new file mode 100644 index 000000000000..0fd49a63306c --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_destroy_write_locked.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: destroyed a locked rwlock + --> $DIR/libc_pthread_rwlock_destroy_write_locked.rs:LL:CC + | +LL | libc::pthread_rwlock_destroy(rw.get()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ destroyed a locked rwlock + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/libc_pthread_rwlock_destroy_write_locked.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.stderr b/tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.stderr new file mode 100644 index 000000000000..d60afc67c85b --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> $DIR/libc_pthread_rwlock_double_destroy.rs:LL:CC + | +LL | libc::pthread_rwlock_destroy(&mut lock); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/libc_pthread_rwlock_double_destroy.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr b/tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr new file mode 100644 index 000000000000..075c8f0ef529 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr @@ -0,0 +1,12 @@ +error: deadlock: the evaluated program deadlocked + --> $DIR/libc_pthread_rwlock_read_write_deadlock_single_thread.rs:LL:CC + | +LL | libc::pthread_rwlock_wrlock(rw.get()); + | ^ the evaluated program deadlocked + | + = note: inside `main` at $DIR/libc_pthread_rwlock_read_write_deadlock_single_thread.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr b/tests/compile-fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr new file mode 100644 index 000000000000..d3820f0dcb74 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: unlocked an rwlock that was not locked by the active thread + --> $DIR/libc_pthread_rwlock_read_wrong_owner.rs:LL:CC + | +LL | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unlocked an rwlock that was not locked by the active thread + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/libc_pthread_rwlock_read_wrong_owner.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_unlock_unlocked.stderr b/tests/compile-fail/sync/libc_pthread_rwlock_unlock_unlocked.stderr new file mode 100644 index 000000000000..f8454d05587f --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_unlock_unlocked.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: unlocked an rwlock that was not locked by the active thread + --> $DIR/libc_pthread_rwlock_unlock_unlocked.rs:LL:CC + | +LL | libc::pthread_rwlock_unlock(rw.get()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unlocked an rwlock that was not locked by the active thread + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/libc_pthread_rwlock_unlock_unlocked.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr b/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr new file mode 100644 index 000000000000..748a363a27a4 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr @@ -0,0 +1,14 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: deadlock: the evaluated program deadlocked + --> $DIR/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC + | +LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); + | ^ the evaluated program deadlocked + | + = note: inside closure at $DIR/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr b/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr new file mode 100644 index 000000000000..caab19a782f9 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr @@ -0,0 +1,12 @@ +error: deadlock: the evaluated program deadlocked + --> $DIR/libc_pthread_rwlock_write_read_deadlock_single_thread.rs:LL:CC + | +LL | libc::pthread_rwlock_rdlock(rw.get()); + | ^ the evaluated program deadlocked + | + = note: inside `main` at $DIR/libc_pthread_rwlock_write_read_deadlock_single_thread.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr b/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr new file mode 100644 index 000000000000..c6a03ff9afb8 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr @@ -0,0 +1,14 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: deadlock: the evaluated program deadlocked + --> $DIR/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC + | +LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); + | ^ the evaluated program deadlocked + | + = note: inside closure at $DIR/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr b/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr new file mode 100644 index 000000000000..30f5f447c717 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr @@ -0,0 +1,12 @@ +error: deadlock: the evaluated program deadlocked + --> $DIR/libc_pthread_rwlock_write_write_deadlock_single_thread.rs:LL:CC + | +LL | libc::pthread_rwlock_wrlock(rw.get()); + | ^ the evaluated program deadlocked + | + = note: inside `main` at $DIR/libc_pthread_rwlock_write_write_deadlock_single_thread.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr b/tests/compile-fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr new file mode 100644 index 000000000000..02a6cf11c0a2 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: unlocked an rwlock that was not locked by the active thread + --> $DIR/libc_pthread_rwlock_write_wrong_owner.rs:LL:CC + | +LL | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unlocked an rwlock that was not locked by the active thread + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/libc_pthread_rwlock_write_wrong_owner.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/too-big-slice.stderr b/tests/compile-fail/too-big-slice.stderr new file mode 100644 index 000000000000..11d20d3e623b --- /dev/null +++ b/tests/compile-fail/too-big-slice.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object + --> $DIR/too-big-slice.rs:LL:CC + | +LL | let _x: &[u8] = mem::transmute((ptr, usize::MAX)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/too-big-slice.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/too-big-unsized.stderr b/tests/compile-fail/too-big-unsized.stderr new file mode 100644 index 000000000000..0c7b7b23246e --- /dev/null +++ b/tests/compile-fail/too-big-unsized.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered invalid reference metadata: total size is bigger than largest supported object + --> $DIR/too-big-unsized.rs:LL:CC + | +LL | let _x: &MySlice = mem::transmute((ptr, isize::MAX as usize)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: total size is bigger than largest supported object + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/too-big-unsized.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/transmute-pair-uninit.stderr b/tests/compile-fail/transmute-pair-uninit.stderr new file mode 100644 index 000000000000..f574e9740282 --- /dev/null +++ b/tests/compile-fail/transmute-pair-uninit.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> $DIR/transmute-pair-uninit.rs:LL:CC + | +LL | if v == 0 { println!("it is zero"); } + | ^^^^^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/transmute-pair-uninit.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/transmute_fat1.stderr b/tests/compile-fail/transmute_fat1.stderr new file mode 100644 index 000000000000..2966f042001c --- /dev/null +++ b/tests/compile-fail/transmute_fat1.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: unable to turn pointer into raw bytes + --> $DIR/transmute_fat1.rs:LL:CC + | +LL | let _val = bad[0] + bad[bad.len()-1]; + | ^^^^^^ unable to turn pointer into raw bytes + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/transmute_fat1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/type-too-large.stderr b/tests/compile-fail/type-too-large.stderr new file mode 100644 index 000000000000..3d555da40cc3 --- /dev/null +++ b/tests/compile-fail/type-too-large.stderr @@ -0,0 +1,12 @@ +error: post-monomorphization error: values of the type `[u8; 2305843011361177600]` are too big for the current architecture + --> $DIR/type-too-large.rs:LL:CC + | +LL | [0; (1u64<<61) as usize +(1u64<<31) as usize]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ values of the type `[u8; 2305843011361177600]` are too big for the current architecture + | + = note: inside `main` at $DIR/type-too-large.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/unaligned_pointers/alignment.rs b/tests/compile-fail/unaligned_pointers/alignment.rs index ff31fc6c293e..b77f0eef82dd 100644 --- a/tests/compile-fail/unaligned_pointers/alignment.rs +++ b/tests/compile-fail/unaligned_pointers/alignment.rs @@ -1,4 +1,5 @@ // error-pattern: but alignment 4 is required +// normalize-stderr-test: "\.add\(1\)" -> " " fn main() { // No retry needed, this fails reliably. @@ -7,7 +8,7 @@ fn main() { let x_ptr: *mut u8 = x.as_mut_ptr(); // At least one of these is definitely unaligned. unsafe { - *(x_ptr as *mut u32) = 42; + *(x_ptr as *mut u32) = 42; *(x_ptr.add(1) as *mut u32) = 42; } } diff --git a/tests/compile-fail/unaligned_pointers/alignment.stderr b/tests/compile-fail/unaligned_pointers/alignment.stderr new file mode 100644 index 000000000000..c21e2ed2ec67 --- /dev/null +++ b/tests/compile-fail/unaligned_pointers/alignment.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required + --> $DIR/alignment.rs:LL:CC + | +LL | *(x_ptr as *mut u32) = 42; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/alignment.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/unaligned_pointers/atomic_unaligned.stderr b/tests/compile-fail/unaligned_pointers/atomic_unaligned.stderr new file mode 100644 index 000000000000..f56e6612fb32 --- /dev/null +++ b/tests/compile-fail/unaligned_pointers/atomic_unaligned.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required + --> $DIR/atomic_unaligned.rs:LL:CC + | +LL | ::std::intrinsics::atomic_load(zptr); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | + = help: this usually indicates that your program performed an invalid operation and caused Undefined Behavior + = help: but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives + + = note: inside `main` at $DIR/atomic_unaligned.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs index 91d9ec475b1f..9d8829fe1ee0 100644 --- a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs +++ b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs @@ -16,6 +16,6 @@ fn main() { // Overwrite the data part of `ptr` so it points to `buf`. unsafe { (&mut ptr as *mut _ as *mut *const u8).write(&buf as *const _ as *const u8); } // Re-borrow that. This should be UB. - let _ptr = &*ptr; //~ERROR alignment 256 is required + let _ptr = &*ptr; //~ERROR alignment ALIGN is required } } diff --git a/tests/compile-fail/unaligned_pointers/dyn_alignment.stderr b/tests/compile-fail/unaligned_pointers/dyn_alignment.stderr new file mode 100644 index 000000000000..6c64f0e365e7 --- /dev/null +++ b/tests/compile-fail/unaligned_pointers/dyn_alignment.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required + --> $DIR/dyn_alignment.rs:LL:CC + | +LL | let _ptr = &*ptr; + | ^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/dyn_alignment.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs b/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs index 9872a493c02a..a8d0b5afbb89 100644 --- a/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs +++ b/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs @@ -12,6 +12,6 @@ fn main() { // Manually make sure the pointer is properly aligned. let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr+1 }; let u16_ptr = base_addr_aligned as *mut u16; - unsafe { *u16_ptr = 2; } //~ERROR memory with alignment 1, but alignment 2 is required + unsafe { *u16_ptr = 2; } //~ERROR memory with alignment ALIGN, but alignment ALIGN is required println!("{:?}", x); } diff --git a/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.stderr b/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.stderr new file mode 100644 index 000000000000..8e0986c45335 --- /dev/null +++ b/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required + --> $DIR/intptrcast_alignment_check.rs:LL:CC + | +LL | unsafe { *u16_ptr = 2; } + | ^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | + = help: this usually indicates that your program performed an invalid operation and caused Undefined Behavior + = help: but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives + + = note: inside `main` at $DIR/intptrcast_alignment_check.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/unaligned_pointers/reference_to_packed.rs b/tests/compile-fail/unaligned_pointers/reference_to_packed.rs index b376859d22c1..60d2524040a2 100644 --- a/tests/compile-fail/unaligned_pointers/reference_to_packed.rs +++ b/tests/compile-fail/unaligned_pointers/reference_to_packed.rs @@ -16,6 +16,6 @@ fn main() { y: 99, }; let p = &foo.x; - let i = *p; //~ERROR alignment 4 is required + let i = *p; //~ERROR alignment ALIGN is required } } diff --git a/tests/compile-fail/unaligned_pointers/reference_to_packed.stderr b/tests/compile-fail/unaligned_pointers/reference_to_packed.stderr new file mode 100644 index 000000000000..3dbc47f71d7b --- /dev/null +++ b/tests/compile-fail/unaligned_pointers/reference_to_packed.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required + --> $DIR/reference_to_packed.rs:LL:CC + | +LL | let i = *p; + | ^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/reference_to_packed.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs index 1d72e5170b7c..fe46e7b8addb 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs @@ -6,6 +6,6 @@ fn main() { let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. - let _x = unsafe { *x }; //~ERROR memory with alignment 2, but alignment 4 is required + let _x = unsafe { *x }; //~ERROR memory with alignment ALIGN, but alignment ALIGN is required } } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr1.stderr b/tests/compile-fail/unaligned_pointers/unaligned_ptr1.stderr new file mode 100644 index 000000000000..afc458e9ccb1 --- /dev/null +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required + --> $DIR/unaligned_ptr1.rs:LL:CC + | +LL | let _x = unsafe { *x }; + | ^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/unaligned_ptr1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs index 49612e2b8a09..1d1e7fad05c9 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs @@ -8,5 +8,5 @@ fn main() { let x = (x.as_ptr() as *const u8).wrapping_offset(3) as *const u32; // This must fail because alignment is violated: the offset is not sufficiently aligned. // Also make the offset not a power of 2, that used to ICE. - let _x = unsafe { *x }; //~ERROR memory with alignment 1, but alignment 4 is required + let _x = unsafe { *x }; //~ERROR memory with alignment ALIGN, but alignment ALIGN is required } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr2.stderr b/tests/compile-fail/unaligned_pointers/unaligned_ptr2.stderr new file mode 100644 index 000000000000..ac1ef5c38121 --- /dev/null +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required + --> $DIR/unaligned_ptr2.rs:LL:CC + | +LL | let _x = unsafe { *x }; + | ^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/unaligned_ptr2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr3.stderr b/tests/compile-fail/unaligned_pointers/unaligned_ptr3.stderr new file mode 100644 index 000000000000..7075bb4c7b4b --- /dev/null +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr3.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required + --> $DIR/unaligned_ptr3.rs:LL:CC + | +LL | let _x = unsafe { *x }; + | ^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/unaligned_ptr3.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr4.stderr b/tests/compile-fail/unaligned_pointers/unaligned_ptr4.stderr new file mode 100644 index 000000000000..e72f28682fd7 --- /dev/null +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr4.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required + --> $DIR/unaligned_ptr4.rs:LL:CC + | +LL | let _val = unsafe { *ptr }; + | ^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/unaligned_ptr4.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs index e33f3c8598f3..d97306b3cb81 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs @@ -8,6 +8,6 @@ fn main() { let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. // The deref is UB even if we just put the result into a raw pointer. - let _x = unsafe { ptr::addr_of!(*x) }; //~ ERROR memory with alignment 2, but alignment 4 is required + let _x = unsafe { ptr::addr_of!(*x) }; //~ ERROR memory with alignment ALIGN, but alignment ALIGN is required } } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.stderr b/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.stderr new file mode 100644 index 000000000000..b858a291dea8 --- /dev/null +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required + --> $DIR/unaligned_ptr_addr_of.rs:LL:CC + | +LL | let _x = unsafe { ptr::addr_of!(*x) }; + | ^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at rustc_src/src/ptr/mod.rs:LL:CC + = note: this error originates in the macro `ptr::addr_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs index 27403c11abc7..c549688c262e 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs @@ -7,6 +7,6 @@ fn main() { let x = i as u8; let x = &x as *const _ as *const [u32; 0]; // This must fail because alignment is violated. Test specifically for loading ZST. - let _x = unsafe { *x }; //~ERROR alignment 4 is required + let _x = unsafe { *x }; //~ERROR alignment ALIGN is required } } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.stderr b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.stderr new file mode 100644 index 000000000000..7ee9a949cc71 --- /dev/null +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required + --> $DIR/unaligned_ptr_zst.rs:LL:CC + | +LL | let _x = unsafe { *x }; + | ^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/unaligned_ptr_zst.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/uninit_buffer.stderr b/tests/compile-fail/uninit_buffer.stderr new file mode 100644 index 000000000000..903a1deee3fe --- /dev/null +++ b/tests/compile-fail/uninit_buffer.stderr @@ -0,0 +1,23 @@ +error: Undefined Behavior: reading 16 bytes of memory starting at ALLOC, but 12 bytes are uninitialized starting at ALLOC+0x4, and this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `::compare` at rustc_src/src/slice/cmp.rs:LL:CC + = note: inside `core::slice::cmp::::cmp` at rustc_src/src/slice/cmp.rs:LL:CC +note: inside `main` at $DIR/uninit_buffer.rs:LL:CC + --> $DIR/uninit_buffer.rs:LL:CC + | +LL | drop(slice1.cmp(slice2)); + | ^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +Uninitialized read occurred at offsets 0x4..0x10 into this allocation: +ALLOC (Rust heap, size: 32, align: 8) { + 0x00 │ 41 42 43 44 __ __ __ __ __ __ __ __ __ __ __ __ │ ABCD░░░░░░░░░░░░ + 0x10 │ 00 __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ .░░░░░░░░░░░░░░░ +} + +error: aborting due to previous error + diff --git a/tests/compile-fail/uninit_byte_read.stderr b/tests/compile-fail/uninit_byte_read.stderr new file mode 100644 index 000000000000..b07473f95b9e --- /dev/null +++ b/tests/compile-fail/uninit_byte_read.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> $DIR/uninit_byte_read.rs:LL:CC + | +LL | let x = undef + 1; + | ^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/uninit_byte_read.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/uninit_float.stderr b/tests/compile-fail/uninit_float.stderr new file mode 100644 index 000000000000..90cdc3ba0fae --- /dev/null +++ b/tests/compile-fail/uninit_float.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes + --> $DIR/uninit_float.rs:LL:CC + | +LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/uninit_float.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/uninit_integer.stderr b/tests/compile-fail/uninit_integer.stderr new file mode 100644 index 000000000000..88b57c1d279a --- /dev/null +++ b/tests/compile-fail/uninit_integer.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes + --> $DIR/uninit_integer.rs:LL:CC + | +LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/uninit_integer.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/uninit_integer_signed.stderr b/tests/compile-fail/uninit_integer_signed.stderr new file mode 100644 index 000000000000..fc15462280a6 --- /dev/null +++ b/tests/compile-fail/uninit_integer_signed.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes + --> $DIR/uninit_integer_signed.rs:LL:CC + | +LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/uninit_integer_signed.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/uninit_raw_ptr.stderr b/tests/compile-fail/uninit_raw_ptr.stderr new file mode 100644 index 000000000000..96074fc1e789 --- /dev/null +++ b/tests/compile-fail/uninit_raw_ptr.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed at .value: encountered uninitialized raw pointer + --> $DIR/uninit_raw_ptr.rs:LL:CC + | +LL | let _val = unsafe { std::mem::MaybeUninit::<*const u8>::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized raw pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/uninit_raw_ptr.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/unreachable.stderr b/tests/compile-fail/unreachable.stderr new file mode 100644 index 000000000000..59ab84331955 --- /dev/null +++ b/tests/compile-fail/unreachable.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: entering unreachable code + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::hint::unreachable_unchecked` at rustc_src/src/hint.rs:LL:CC +note: inside `main` at $DIR/unreachable.rs:LL:CC + --> $DIR/unreachable.rs:LL:CC + | +LL | unsafe { std::hint::unreachable_unchecked() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/unsupported_foreign_function.stderr b/tests/compile-fail/unsupported_foreign_function.stderr new file mode 100644 index 000000000000..b8b1925d2ccc --- /dev/null +++ b/tests/compile-fail/unsupported_foreign_function.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: can't call foreign function: foo + --> $DIR/unsupported_foreign_function.rs:LL:CC + | +LL | foo(); + | ^^^^^ can't call foreign function: foo + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/unsupported_foreign_function.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/unsupported_signal.stderr b/tests/compile-fail/unsupported_signal.stderr new file mode 100644 index 000000000000..8fcbc7fb4739 --- /dev/null +++ b/tests/compile-fail/unsupported_signal.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: can't call foreign function: signal + --> $DIR/unsupported_signal.rs:LL:CC + | +LL | libc::signal(libc::SIGPIPE, libc::SIG_IGN); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't call foreign function: signal + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/unsupported_signal.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/cast_fn_ptr1.stderr b/tests/compile-fail/validity/cast_fn_ptr1.stderr new file mode 100644 index 000000000000..d048377a7793 --- /dev/null +++ b/tests/compile-fail/validity/cast_fn_ptr1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered a null reference + --> $DIR/cast_fn_ptr1.rs:LL:CC + | +LL | g(0usize as *const i32) + | ^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a null reference + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/cast_fn_ptr1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/cast_fn_ptr2.stderr b/tests/compile-fail/validity/cast_fn_ptr2.stderr new file mode 100644 index 000000000000..10b9b9b8602b --- /dev/null +++ b/tests/compile-fail/validity/cast_fn_ptr2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered a null reference + --> $DIR/cast_fn_ptr2.rs:LL:CC + | +LL | let _x = g(); + | ^^^ type validation failed: encountered a null reference + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/cast_fn_ptr2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/dangling_ref1.rs b/tests/compile-fail/validity/dangling_ref1.rs index 78425cde4a8a..3243eee06eb6 100644 --- a/tests/compile-fail/validity/dangling_ref1.rs +++ b/tests/compile-fail/validity/dangling_ref1.rs @@ -3,5 +3,5 @@ use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address $HEX is unallocated) } diff --git a/tests/compile-fail/validity/dangling_ref1.stderr b/tests/compile-fail/validity/dangling_ref1.stderr new file mode 100644 index 000000000000..0d358fd7f7f9 --- /dev/null +++ b/tests/compile-fail/validity/dangling_ref1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated) + --> $DIR/dangling_ref1.rs:LL:CC + | +LL | let _x: &i32 = unsafe { mem::transmute(16usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (address 0x10 is unallocated) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/dangling_ref1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/dangling_ref2.stderr b/tests/compile-fail/validity/dangling_ref2.stderr new file mode 100644 index 000000000000..e3bbb72fdcf1 --- /dev/null +++ b/tests/compile-fail/validity/dangling_ref2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered a dangling reference (going beyond the bounds of its allocation) + --> $DIR/dangling_ref2.rs:LL:CC + | +LL | let _x: &i32 = unsafe { mem::transmute(ptr) }; + | ^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (going beyond the bounds of its allocation) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/dangling_ref2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/dangling_ref3.stderr b/tests/compile-fail/validity/dangling_ref3.stderr new file mode 100644 index 000000000000..5842eca9fc8e --- /dev/null +++ b/tests/compile-fail/validity/dangling_ref3.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered a dangling reference (use-after-free) + --> $DIR/dangling_ref3.rs:LL:CC + | +LL | let _x: &i32 = unsafe { mem::transmute(dangling()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (use-after-free) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/dangling_ref3.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/invalid_bool.rs b/tests/compile-fail/validity/invalid_bool.rs index 0b2d648d02ad..df6c19df7f23 100644 --- a/tests/compile-fail/validity/invalid_bool.rs +++ b/tests/compile-fail/validity/invalid_bool.rs @@ -1,3 +1,3 @@ fn main() { - let _b = unsafe { std::mem::transmute::(2) }; //~ ERROR encountered 0x02, but expected a boolean + let _b = unsafe { std::mem::transmute::(2) }; //~ ERROR expected a boolean } diff --git a/tests/compile-fail/validity/invalid_bool.stderr b/tests/compile-fail/validity/invalid_bool.stderr new file mode 100644 index 000000000000..d17319d2dce8 --- /dev/null +++ b/tests/compile-fail/validity/invalid_bool.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered 0x02, but expected a boolean + --> $DIR/invalid_bool.rs:LL:CC + | +LL | let _b = unsafe { std::mem::transmute::(2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x02, but expected a boolean + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/invalid_bool.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/invalid_bool_uninit.stderr b/tests/compile-fail/validity/invalid_bool_uninit.stderr new file mode 100644 index 000000000000..e262e69dc696 --- /dev/null +++ b/tests/compile-fail/validity/invalid_bool_uninit.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered uninitialized bytes, but expected a boolean + --> $DIR/invalid_bool_uninit.rs:LL:CC + | +LL | let _b = unsafe { MyUninit { init: () }.uninit }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a boolean + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/invalid_bool_uninit.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/invalid_char.rs b/tests/compile-fail/validity/invalid_char.rs index 079823f894a8..d9a55f241c00 100644 --- a/tests/compile-fail/validity/invalid_char.rs +++ b/tests/compile-fail/validity/invalid_char.rs @@ -1,6 +1,6 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); - let _val = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered 0xffffffff, but expected a valid unicode scalar value + let _val = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered $HEX, but expected a valid unicode scalar value 'a' => {true}, 'b' => {false}, _ => {true}, diff --git a/tests/compile-fail/validity/invalid_char.stderr b/tests/compile-fail/validity/invalid_char.stderr new file mode 100644 index 000000000000..99f5ce0bb211 --- /dev/null +++ b/tests/compile-fail/validity/invalid_char.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered $HEX, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) + --> $DIR/invalid_char.rs:LL:CC + | +LL | let _val = match unsafe { std::mem::transmute::(-1) } { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered $HEX, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/invalid_char.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/invalid_char_uninit.rs b/tests/compile-fail/validity/invalid_char_uninit.rs index 34798dfbc659..cb885d001cff 100644 --- a/tests/compile-fail/validity/invalid_char_uninit.rs +++ b/tests/compile-fail/validity/invalid_char_uninit.rs @@ -6,5 +6,5 @@ union MyUninit { } fn main() { - let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) + let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR encountered uninitialized bytes, but expected a valid unicode scalar value } diff --git a/tests/compile-fail/validity/invalid_char_uninit.stderr b/tests/compile-fail/validity/invalid_char_uninit.stderr new file mode 100644 index 000000000000..b27c9b2bb69c --- /dev/null +++ b/tests/compile-fail/validity/invalid_char_uninit.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) + --> $DIR/invalid_char_uninit.rs:LL:CC + | +LL | let _b = unsafe { MyUninit { init: () }.uninit }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/invalid_char_uninit.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/invalid_enum_tag.stderr b/tests/compile-fail/validity/invalid_enum_tag.stderr new file mode 100644 index 000000000000..c6d862ae1b02 --- /dev/null +++ b/tests/compile-fail/validity/invalid_enum_tag.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed at .: encountered $HEX, but expected a valid enum tag + --> $DIR/invalid_enum_tag.rs:LL:CC + | +LL | ... { std::mem::transmute::(42) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .: encountered $HEX, but expected a valid enum tag + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/invalid_enum_tag.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.stderr b/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.stderr new file mode 100644 index 000000000000..1a6039c477d6 --- /dev/null +++ b/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed at .: encountered uninitialized bytes, but expected a valid enum tag + --> $DIR/invalid_enum_tag_256variants_uninit.rs:LL:CC + | +LL | let _a = unsafe { MyUninit { init: () }.uninit }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .: encountered uninitialized bytes, but expected a valid enum tag + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/invalid_enum_tag_256variants_uninit.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/invalid_fnptr_null.stderr b/tests/compile-fail/validity/invalid_fnptr_null.stderr new file mode 100644 index 000000000000..e3cea40e0c33 --- /dev/null +++ b/tests/compile-fail/validity/invalid_fnptr_null.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered a null function pointer + --> $DIR/invalid_fnptr_null.rs:LL:CC + | +LL | let _b: fn() = unsafe { std::mem::transmute(0usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a null function pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/invalid_fnptr_null.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/invalid_fnptr_uninit.stderr b/tests/compile-fail/validity/invalid_fnptr_uninit.stderr new file mode 100644 index 000000000000..84a5657e7870 --- /dev/null +++ b/tests/compile-fail/validity/invalid_fnptr_uninit.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered uninitialized bytes, but expected a proper pointer or integer value + --> $DIR/invalid_fnptr_uninit.rs:LL:CC + | +LL | let _b = unsafe { MyUninit { init: () }.uninit }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a proper pointer or integer value + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/invalid_fnptr_uninit.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/invalid_wide_raw.stderr b/tests/compile-fail/validity/invalid_wide_raw.stderr new file mode 100644 index 000000000000..f64b824d6ba6 --- /dev/null +++ b/tests/compile-fail/validity/invalid_wide_raw.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered dangling vtable pointer in wide pointer + --> $DIR/invalid_wide_raw.rs:LL:CC + | +LL | dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling vtable pointer in wide pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/invalid_wide_raw.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/nonzero.stderr b/tests/compile-fail/validity/nonzero.stderr new file mode 100644 index 000000000000..ba01acb6a169 --- /dev/null +++ b/tests/compile-fail/validity/nonzero.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered 0, but expected something greater or equal to 1 + --> $DIR/nonzero.rs:LL:CC + | +LL | let _x = Some(unsafe { NonZero(0) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/nonzero.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/ptr_integer_array_transmute.stderr b/tests/compile-fail/validity/ptr_integer_array_transmute.stderr new file mode 100644 index 000000000000..bc2ca54438ff --- /dev/null +++ b/tests/compile-fail/validity/ptr_integer_array_transmute.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered a pointer, but expected plain (non-pointer) bytes + --> $DIR/ptr_integer_array_transmute.rs:LL:CC + | +LL | let _i: [usize; 1] = unsafe { std::mem::transmute(r) }; + | ^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected plain (non-pointer) bytes + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/ptr_integer_array_transmute.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/ptr_integer_transmute.stderr b/tests/compile-fail/validity/ptr_integer_transmute.stderr new file mode 100644 index 000000000000..cad53d71f4d9 --- /dev/null +++ b/tests/compile-fail/validity/ptr_integer_transmute.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered pointer to $HEX[ALLOC], but expected plain (non-pointer) bytes + --> $DIR/ptr_integer_transmute.rs:LL:CC + | +LL | let _i: usize = unsafe { std::mem::transmute(r) }; + | ^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to $HEX[ALLOC], but expected plain (non-pointer) bytes + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/ptr_integer_transmute.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/ref_to_uninhabited1.stderr b/tests/compile-fail/validity/ref_to_uninhabited1.stderr new file mode 100644 index 000000000000..de41944944e3 --- /dev/null +++ b/tests/compile-fail/validity/ref_to_uninhabited1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered a box pointing to uninhabited type ! + --> $DIR/ref_to_uninhabited1.rs:LL:CC + | +LL | let x: Box = transmute(&mut 42); + | ^^^^^^^^^^^^^^^^^^ type validation failed: encountered a box pointing to uninhabited type ! + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/ref_to_uninhabited1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/ref_to_uninhabited2.stderr b/tests/compile-fail/validity/ref_to_uninhabited2.stderr new file mode 100644 index 000000000000..754c39e78901 --- /dev/null +++ b/tests/compile-fail/validity/ref_to_uninhabited2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered a reference pointing to uninhabited type (i32, Void) + --> $DIR/ref_to_uninhabited2.rs:LL:CC + | +LL | let _x: &(i32, Void) = transmute(&42); + | ^^^^^^^^^^^^^^ type validation failed: encountered a reference pointing to uninhabited type (i32, Void) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/ref_to_uninhabited2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/too-big-slice.stderr b/tests/compile-fail/validity/too-big-slice.stderr new file mode 100644 index 000000000000..11d20d3e623b --- /dev/null +++ b/tests/compile-fail/validity/too-big-slice.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object + --> $DIR/too-big-slice.rs:LL:CC + | +LL | let _x: &[u8] = mem::transmute((ptr, usize::MAX)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/too-big-slice.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/too-big-unsized.stderr b/tests/compile-fail/validity/too-big-unsized.stderr new file mode 100644 index 000000000000..0c7b7b23246e --- /dev/null +++ b/tests/compile-fail/validity/too-big-unsized.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered invalid reference metadata: total size is bigger than largest supported object + --> $DIR/too-big-unsized.rs:LL:CC + | +LL | let _x: &MySlice = mem::transmute((ptr, isize::MAX as usize)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: total size is bigger than largest supported object + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/too-big-unsized.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/transmute_through_ptr.stderr b/tests/compile-fail/validity/transmute_through_ptr.stderr new file mode 100644 index 000000000000..d06dbe3194f5 --- /dev/null +++ b/tests/compile-fail/validity/transmute_through_ptr.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed at .: encountered $HEX, but expected a valid enum tag + --> $DIR/transmute_through_ptr.rs:LL:CC + | +LL | let y = x; // reading this ought to be enough to trigger validation + | ^ type validation failed at .: encountered $HEX, but expected a valid enum tag + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/transmute_through_ptr.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/uninit_float.stderr b/tests/compile-fail/validity/uninit_float.stderr new file mode 100644 index 000000000000..3f244adbabed --- /dev/null +++ b/tests/compile-fail/validity/uninit_float.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes + --> $DIR/uninit_float.rs:LL:CC + | +LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/uninit_float.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/uninit_integer.stderr b/tests/compile-fail/validity/uninit_integer.stderr new file mode 100644 index 000000000000..e3e2f0a17852 --- /dev/null +++ b/tests/compile-fail/validity/uninit_integer.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes + --> $DIR/uninit_integer.rs:LL:CC + | +LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/uninit_integer.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/uninit_integer_signed.stderr b/tests/compile-fail/validity/uninit_integer_signed.stderr new file mode 100644 index 000000000000..e6d9b51e40e4 --- /dev/null +++ b/tests/compile-fail/validity/uninit_integer_signed.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes + --> $DIR/uninit_integer_signed.rs:LL:CC + | +LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/uninit_integer_signed.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/zst1.stderr b/tests/compile-fail/zst1.stderr new file mode 100644 index 000000000000..ba13c9d7e52a --- /dev/null +++ b/tests/compile-fail/zst1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds + --> $DIR/zst1.rs:LL:CC + | +LL | let _val = unsafe { *x }; + | ^^ dereferencing pointer failed: ALLOC has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/zst1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/zst2.stderr b/tests/compile-fail/zst2.stderr new file mode 100644 index 000000000000..088bb2a1ccf0 --- /dev/null +++ b/tests/compile-fail/zst2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> $DIR/zst2.rs:LL:CC + | +LL | unsafe { *x = zst_val; } + | ^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/zst2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/zst3.stderr b/tests/compile-fail/zst3.stderr new file mode 100644 index 000000000000..a7d84dcaad59 --- /dev/null +++ b/tests/compile-fail/zst3.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 1, so pointer at offset 2 is out-of-bounds + --> $DIR/zst3.rs:LL:CC + | +LL | unsafe { *(x as *mut [u8; 0]) = zst_val; } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 1, so pointer at offset 2 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/zst3.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compiletest.rs b/tests/compiletest.rs index a0d49c9ddcf4..92a8bd6291e2 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -1,82 +1,127 @@ +use colored::*; +use regex::Regex; use std::env; use std::path::PathBuf; - -use colored::*; -use compiletest_rs as compiletest; +use ui_test::{Config, Mode, OutputConflictHandling}; fn miri_path() -> PathBuf { PathBuf::from(option_env!("MIRI").unwrap_or(env!("CARGO_BIN_EXE_miri"))) } -fn run_tests(mode: &str, path: &str, target: &str) { +fn run_tests(mode: Mode, path: &str, target: Option) { let in_rustc_test_suite = option_env!("RUSTC_STAGE").is_some(); + // Add some flags we always want. let mut flags = Vec::new(); - flags.push("--edition 2018".to_owned()); + flags.push("--edition".to_owned()); + flags.push("2018".to_owned()); if in_rustc_test_suite { // Less aggressive warnings to make the rustc toolstate management less painful. // (We often get warnings when e.g. a feature gets stabilized or some lint gets added/improved.) flags.push("-Astable-features".to_owned()); } else { - flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs + flags.push("-Dwarnings".to_owned()); + flags.push("-Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs } if let Ok(sysroot) = env::var("MIRI_SYSROOT") { - flags.push(format!("--sysroot {}", sysroot)); + flags.push("--sysroot".to_string()); + flags.push(sysroot); } if let Ok(extra_flags) = env::var("MIRIFLAGS") { - flags.push(extra_flags); + for flag in extra_flags.split_whitespace() { + flags.push(flag.to_string()); + } + } + flags.push("-Zui-testing".to_string()); + if let Some(target) = &target { + flags.push("--target".to_string()); + flags.push(target.clone()); } - let flags = flags.join(" "); - eprintln!(" Compiler flags: {}", flags); + let skip_ui_checks = in_rustc_test_suite || env::var_os("MIRI_SKIP_UI_CHECKS").is_some(); - // The rest of the configuration. - let mut config = compiletest::Config::default().tempdir(); - config.mode = mode.parse().expect("Invalid mode"); - config.rustc_path = miri_path(); - if let Some(lib_path) = option_env!("RUSTC_LIB_PATH") { - config.run_lib_path = PathBuf::from(lib_path); - config.compile_lib_path = PathBuf::from(lib_path); + let output_conflict_handling = match (env::var_os("MIRI_BLESS").is_some(), skip_ui_checks) { + (false, false) => OutputConflictHandling::Error, + (true, false) => OutputConflictHandling::Bless, + (false, true) => OutputConflictHandling::Ignore, + (true, true) => panic!("cannot use MIRI_BLESS and MIRI_SKIP_UI_CHECKS at the same time"), + }; + + let config = Config { + args: flags, + target, + stderr_filters: STDERR.clone(), + stdout_filters: STDOUT.clone(), + root_dir: PathBuf::from(path), + mode, + program: miri_path(), + output_conflict_handling, + }; + ui_test::run_tests(config) +} + +macro_rules! regexes { + ($name:ident: $($regex:expr => $replacement:expr,)*) => {lazy_static::lazy_static! { + static ref $name: Vec<(Regex, &'static str)> = vec![ + $((Regex::new($regex).unwrap(), $replacement),)* + ]; + }}; +} + +regexes! { + STDOUT: + // Windows file paths + r"\\" => "/", +} + +regexes! { + STDERR: + // erase line and column info + r"\.rs:[0-9]+:[0-9]+" => ".rs:LL:CC", + // erase alloc ids + "alloc[0-9]+" => "ALLOC", + // erase Stacked Borrows tags + "<[0-9]+>" => "", + // erase whitespace that differs between platforms + r" +at (.*\.rs)" => " at $1", + // erase generics in backtraces + "([0-9]+: .*)::<.*>" => "$1", + // erase addresses in backtraces + "([0-9]+: ) +0x[0-9a-f]+ - (.*)" => "$1$2", + // erase long hexadecimals + r"0x[0-9a-fA-F]+[0-9a-fA-F]{2,2}" => "$$HEX", + // erase clocks + r"VClock\(\[[^\]]+\]\)" => "VClock", + // erase specific alignments + "alignment [0-9]+" => "alignment ALIGN", + // erase thread caller ids + r"\(call [0-9]+\)" => "(call ID)", + // erase platform module paths + "sys::[a-z]+::" => "sys::PLATFORM::", + // Windows file paths + r"\\" => "/", + // erase platform file paths + "sys/[a-z]+/" => "sys/PLATFORM/", + // erase error annotations in tests + r"\s*//~.*" => "", +} + +fn ui(mode: Mode, path: &str) { + let target = get_target(); + + eprint!("{}", format!("## Running ui tests in {path} against miri for ").green().bold()); + + if let Some(target) = &target { + eprintln!("{target}"); + } else { + eprintln!("host"); } - config.filters = env::args().nth(1).into_iter().collect(); - config.host = get_host(); - config.src_base = PathBuf::from(path); - config.target = target.to_owned(); - config.target_rustcflags = Some(flags); - compiletest::run_tests(&config); + + run_tests(mode, path, target); } -fn compile_fail(path: &str, target: &str) { - eprintln!( - "{}", - format!("## Running compile-fail tests in {} against miri for target {}", path, target) - .green() - .bold() - ); - - run_tests("compile-fail", path, target); -} - -fn miri_pass(path: &str, target: &str) { - eprintln!( - "{}", - format!("## Running run-pass tests in {} against miri for target {}", path, target) - .green() - .bold() - ); - - run_tests("ui", path, target); -} - -fn get_host() -> String { - let version_meta = - rustc_version::VersionMeta::for_command(std::process::Command::new(miri_path())) - .expect("failed to parse rustc version info"); - version_meta.host -} - -fn get_target() -> String { - env::var("MIRI_TEST_TARGET").unwrap_or_else(|_| get_host()) +fn get_target() -> Option { + env::var("MIRI_TEST_TARGET").ok() } fn main() { @@ -84,10 +129,8 @@ fn main() { env::set_var("MIRI_ENV_VAR_TEST", "0"); // Let the tests know where to store temp files (they might run for a different target, which can make this hard to find). env::set_var("MIRI_TEMP", env::temp_dir()); - // Panic tests expect backtraces to be printed. - env::set_var("RUST_BACKTRACE", "1"); - let target = get_target(); - miri_pass("tests/run-pass", &target); - compile_fail("tests/compile-fail", &target); + ui(Mode::Pass, "tests/run-pass"); + ui(Mode::Panic, "tests/run-fail"); + ui(Mode::Fail, "tests/compile-fail"); } diff --git a/tests/run-pass/function_calls/exported_symbol_good_unwind.rs b/tests/run-fail/function_calls/exported_symbol_good_unwind.rs similarity index 100% rename from tests/run-pass/function_calls/exported_symbol_good_unwind.rs rename to tests/run-fail/function_calls/exported_symbol_good_unwind.rs diff --git a/tests/run-pass/function_calls/exported_symbol_good_unwind.stderr b/tests/run-fail/function_calls/exported_symbol_good_unwind.stderr similarity index 80% rename from tests/run-pass/function_calls/exported_symbol_good_unwind.stderr rename to tests/run-fail/function_calls/exported_symbol_good_unwind.stderr index 40a8f39509fa..bff897775e8f 100644 --- a/tests/run-pass/function_calls/exported_symbol_good_unwind.stderr +++ b/tests/run-fail/function_calls/exported_symbol_good_unwind.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:11:5 +thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:16:5 -thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:22:5 +thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:LL:CC +thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:LL:CC diff --git a/tests/run-pass/panic/div-by-zero-2.rs b/tests/run-fail/panic/div-by-zero-2.rs similarity index 100% rename from tests/run-pass/panic/div-by-zero-2.rs rename to tests/run-fail/panic/div-by-zero-2.rs diff --git a/tests/run-pass/panic/div-by-zero-2.stderr b/tests/run-fail/panic/div-by-zero-2.stderr similarity index 88% rename from tests/run-pass/panic/div-by-zero-2.stderr rename to tests/run-fail/panic/div-by-zero-2.stderr index 60ff33c8bfcd..538d87113654 100644 --- a/tests/run-pass/panic/div-by-zero-2.stderr +++ b/tests/run-fail/panic/div-by-zero-2.stderr @@ -1,2 +1,2 @@ -thread 'main' panicked at 'attempt to divide by zero', $DIR/div-by-zero-2.rs:4:14 +thread 'main' panicked at 'attempt to divide by zero', $DIR/div-by-zero-2.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/panic/overflowing-lsh-neg.rs b/tests/run-fail/panic/overflowing-lsh-neg.rs similarity index 100% rename from tests/run-pass/panic/overflowing-lsh-neg.rs rename to tests/run-fail/panic/overflowing-lsh-neg.rs diff --git a/tests/run-pass/panic/overflowing-lsh-neg.stderr b/tests/run-fail/panic/overflowing-lsh-neg.stderr similarity index 80% rename from tests/run-pass/panic/overflowing-lsh-neg.stderr rename to tests/run-fail/panic/overflowing-lsh-neg.stderr index 64959da0faea..21e434d873f7 100644 --- a/tests/run-pass/panic/overflowing-lsh-neg.stderr +++ b/tests/run-fail/panic/overflowing-lsh-neg.stderr @@ -1,2 +1,2 @@ -thread 'main' panicked at 'attempt to shift left with overflow', $DIR/overflowing-lsh-neg.rs:4:14 +thread 'main' panicked at 'attempt to shift left with overflow', $DIR/overflowing-lsh-neg.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/panic/overflowing-rsh-1.rs b/tests/run-fail/panic/overflowing-rsh-1.rs similarity index 100% rename from tests/run-pass/panic/overflowing-rsh-1.rs rename to tests/run-fail/panic/overflowing-rsh-1.rs diff --git a/tests/run-pass/panic/overflowing-rsh-1.stderr b/tests/run-fail/panic/overflowing-rsh-1.stderr similarity index 80% rename from tests/run-pass/panic/overflowing-rsh-1.stderr rename to tests/run-fail/panic/overflowing-rsh-1.stderr index bd8843f8d603..fd04bf1bd4ec 100644 --- a/tests/run-pass/panic/overflowing-rsh-1.stderr +++ b/tests/run-fail/panic/overflowing-rsh-1.stderr @@ -1,2 +1,2 @@ -thread 'main' panicked at 'attempt to shift right with overflow', $DIR/overflowing-rsh-1.rs:4:14 +thread 'main' panicked at 'attempt to shift right with overflow', $DIR/overflowing-rsh-1.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/panic/overflowing-rsh-2.rs b/tests/run-fail/panic/overflowing-rsh-2.rs similarity index 100% rename from tests/run-pass/panic/overflowing-rsh-2.rs rename to tests/run-fail/panic/overflowing-rsh-2.rs diff --git a/tests/run-pass/panic/overflowing-rsh-2.stderr b/tests/run-fail/panic/overflowing-rsh-2.stderr similarity index 80% rename from tests/run-pass/panic/overflowing-rsh-2.stderr rename to tests/run-fail/panic/overflowing-rsh-2.stderr index c43090ea7037..eb568e4d742b 100644 --- a/tests/run-pass/panic/overflowing-rsh-2.stderr +++ b/tests/run-fail/panic/overflowing-rsh-2.stderr @@ -1,2 +1,2 @@ -thread 'main' panicked at 'attempt to shift right with overflow', $DIR/overflowing-rsh-2.rs:5:14 +thread 'main' panicked at 'attempt to shift right with overflow', $DIR/overflowing-rsh-2.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-fail/panic/panic1.rs b/tests/run-fail/panic/panic1.rs new file mode 100644 index 000000000000..cfaa642beb8e --- /dev/null +++ b/tests/run-fail/panic/panic1.rs @@ -0,0 +1,7 @@ +// rustc-env: RUST_BACKTRACE=1 +// compile-flags: -Zmiri-disable-isolation + + +fn main() { + std::panic!("panicking from libstd"); +} diff --git a/tests/run-pass/panic/panic1.stderr b/tests/run-fail/panic/panic1.stderr similarity index 55% rename from tests/run-pass/panic/panic1.stderr rename to tests/run-fail/panic/panic1.stderr index 0b59b2a523b3..d4dcfc47a839 100644 --- a/tests/run-pass/panic/panic1.stderr +++ b/tests/run-fail/panic/panic1.stderr @@ -1,31 +1,31 @@ -thread 'main' panicked at 'panicking from libstd', $DIR/panic1.rs:8:5 +thread 'main' panicked at 'panicking from libstd', $DIR/panic1.rs:LL:CC stack backtrace: 0: std::rt::begin_panic - at RUSTLIB/$FILE:LL:COL + at rustc_src/src/panicking.rs:LL:CC 1: main - at $DIR/panic1.rs:8:5 + at $DIR/panic1.rs:LL:CC 2: >::call_once - shim(fn()) - at RUSTLIB/$FILE:LL:COL + at rustc_src/src/ops/function.rs:LL:CC 3: std::rt::lang_start::{closure#0} - at RUSTLIB/$FILE:LL:COL + at rustc_src/src/rt.rs:LL:CC 4: std::ops::function::impls::call_once - at RUSTLIB/$FILE:LL:COL + at rustc_src/src/ops/function.rs:LL:CC 5: std::panicking::r#try::do_call - at RUSTLIB/$FILE:LL:COL + at rustc_src/src/panicking.rs:LL:CC 6: std::panicking::r#try - at RUSTLIB/$FILE:LL:COL + at rustc_src/src/panicking.rs:LL:CC 7: std::panic::catch_unwind - at RUSTLIB/$FILE:LL:COL + at rustc_src/src/panic.rs:LL:CC 8: std::rt::lang_start_internal::{closure#2} - at RUSTLIB/$FILE:LL:COL + at rustc_src/src/rt.rs:LL:CC 9: std::panicking::r#try::do_call - at RUSTLIB/$FILE:LL:COL + at rustc_src/src/panicking.rs:LL:CC 10: std::panicking::r#try - at RUSTLIB/$FILE:LL:COL + at rustc_src/src/panicking.rs:LL:CC 11: std::panic::catch_unwind - at RUSTLIB/$FILE:LL:COL + at rustc_src/src/panic.rs:LL:CC 12: std::rt::lang_start_internal - at RUSTLIB/$FILE:LL:COL + at rustc_src/src/rt.rs:LL:CC 13: std::rt::lang_start - at RUSTLIB/$FILE:LL:COL + at rustc_src/src/rt.rs:LL:CC note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. diff --git a/tests/run-pass/panic/panic2.rs b/tests/run-fail/panic/panic2.rs similarity index 100% rename from tests/run-pass/panic/panic2.rs rename to tests/run-fail/panic/panic2.rs diff --git a/tests/run-pass/panic/panic2.stderr b/tests/run-fail/panic/panic2.stderr similarity index 92% rename from tests/run-pass/panic/panic2.stderr rename to tests/run-fail/panic/panic2.stderr index c0415b4e70f0..c192ca3f64c3 100644 --- a/tests/run-pass/panic/panic2.stderr +++ b/tests/run-fail/panic/panic2.stderr @@ -1,2 +1,2 @@ -thread 'main' panicked at '42-panicking from libstd', $DIR/panic2.rs:2:5 +thread 'main' panicked at '42-panicking from libstd', $DIR/panic2.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/panic/panic3.rs b/tests/run-fail/panic/panic3.rs similarity index 100% rename from tests/run-pass/panic/panic3.rs rename to tests/run-fail/panic/panic3.rs diff --git a/tests/run-pass/panic/panic3.stderr b/tests/run-fail/panic/panic3.stderr similarity index 94% rename from tests/run-pass/panic/panic3.stderr rename to tests/run-fail/panic/panic3.stderr index 8aa8761aebf7..0ce4a37fd519 100644 --- a/tests/run-pass/panic/panic3.stderr +++ b/tests/run-fail/panic/panic3.stderr @@ -1,2 +1,2 @@ -thread 'main' panicked at 'panicking from libcore', $DIR/panic3.rs:2:5 +thread 'main' panicked at 'panicking from libcore', $DIR/panic3.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/panic/panic4.rs b/tests/run-fail/panic/panic4.rs similarity index 100% rename from tests/run-pass/panic/panic4.rs rename to tests/run-fail/panic/panic4.rs diff --git a/tests/run-pass/panic/panic4.stderr b/tests/run-fail/panic/panic4.stderr similarity index 92% rename from tests/run-pass/panic/panic4.stderr rename to tests/run-fail/panic/panic4.stderr index a71d25b74c43..82df953b61c0 100644 --- a/tests/run-pass/panic/panic4.stderr +++ b/tests/run-fail/panic/panic4.stderr @@ -1,2 +1,2 @@ -thread 'main' panicked at '42-panicking from libcore', $DIR/panic4.rs:2:5 +thread 'main' panicked at '42-panicking from libcore', $DIR/panic4.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/panic/unsupported_foreign_function.rs b/tests/run-fail/panic/unsupported_foreign_function.rs similarity index 100% rename from tests/run-pass/panic/unsupported_foreign_function.rs rename to tests/run-fail/panic/unsupported_foreign_function.rs diff --git a/tests/run-pass/panic/unsupported_foreign_function.stderr b/tests/run-fail/panic/unsupported_foreign_function.stderr similarity index 95% rename from tests/run-pass/panic/unsupported_foreign_function.stderr rename to tests/run-fail/panic/unsupported_foreign_function.stderr index bd7f3490d809..9af3e48655f3 100644 --- a/tests/run-pass/panic/unsupported_foreign_function.stderr +++ b/tests/run-fail/panic/unsupported_foreign_function.stderr @@ -1,2 +1,2 @@ -thread 'main' panicked at 'unsupported Miri functionality: can't call foreign function: foo', $DIR/unsupported_foreign_function.rs:9:9 +thread 'main' panicked at 'unsupported Miri functionality: can't call foreign function: foo', $DIR/unsupported_foreign_function.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/panic/unsupported_syscall.rs b/tests/run-fail/panic/unsupported_syscall.rs similarity index 78% rename from tests/run-pass/panic/unsupported_syscall.rs rename to tests/run-fail/panic/unsupported_syscall.rs index 854f179392c4..2e62a5d8ae8d 100644 --- a/tests/run-pass/panic/unsupported_syscall.rs +++ b/tests/run-fail/panic/unsupported_syscall.rs @@ -1,5 +1,5 @@ // ignore-windows: No libc on Windows -// ignore-macos: `syscall` is not supported on macOS +// ignore-apple: `syscall` is not supported on macOS // compile-flags: -Zmiri-panic-on-unsupported #![feature(rustc_private)] diff --git a/tests/run-pass/panic/unsupported_syscall.stderr b/tests/run-fail/panic/unsupported_syscall.stderr similarity index 69% rename from tests/run-pass/panic/unsupported_syscall.stderr rename to tests/run-fail/panic/unsupported_syscall.stderr index 49796ee2021f..90aa5a907363 100644 --- a/tests/run-pass/panic/unsupported_syscall.stderr +++ b/tests/run-fail/panic/unsupported_syscall.stderr @@ -1,2 +1,2 @@ -thread 'main' panicked at 'unsupported Miri functionality: can't execute syscall with ID 0', $DIR/unsupported_syscall.rs:10:9 +thread 'main' panicked at 'unsupported Miri functionality: can't execute syscall with ID 0', $DIR/unsupported_syscall.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/transmute_fat2.rs b/tests/run-fail/transmute_fat2.rs similarity index 100% rename from tests/run-pass/transmute_fat2.rs rename to tests/run-fail/transmute_fat2.rs diff --git a/tests/run-pass/transmute_fat2.stderr b/tests/run-fail/transmute_fat2.stderr similarity index 75% rename from tests/run-pass/transmute_fat2.stderr rename to tests/run-fail/transmute_fat2.stderr index 54ccdfb5e465..f497ab672550 100644 --- a/tests/run-pass/transmute_fat2.stderr +++ b/tests/run-fail/transmute_fat2.stderr @@ -1,2 +1,2 @@ -thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', $DIR/transmute_fat2.rs:15:5 +thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', $DIR/transmute_fat2.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/backtrace-api-v0.rs b/tests/run-pass/backtrace-api-v0.rs index cb3706e9f513..62702c088dd6 100644 --- a/tests/run-pass/backtrace-api-v0.rs +++ b/tests/run-pass/backtrace-api-v0.rs @@ -1,6 +1,4 @@ -// normalize-stderr-test ".*/(rust[^/]*|checkout)/library/" -> "RUSTLIB/" -// normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL " -// normalize-stderr-test "::<.*>" -> "" +// normalize-stderr-test: "::<.*>" -> "" #[inline(never)] fn func_a() -> Box<[*mut ()]> { func_b::() } #[inline(never)] fn func_b() -> Box<[*mut ()]> { func_c() } diff --git a/tests/run-pass/backtrace-api-v0.stderr b/tests/run-pass/backtrace-api-v0.stderr index 8a697a44ea9d..d81f5ad1d626 100644 --- a/tests/run-pass/backtrace-api-v0.stderr +++ b/tests/run-pass/backtrace-api-v0.stderr @@ -1,18 +1,18 @@ -$DIR/backtrace-api-v0.rs:13:59 (func_d) -$DIR/backtrace-api-v0.rs:12:50 (func_c) -$DIR/backtrace-api-v0.rs:6:53 (func_b) -$DIR/backtrace-api-v0.rs:5:50 (func_a) -$DIR/backtrace-api-v0.rs:17:18 (main) -RUSTLIB/core/src/ops/function.rs:LL:COL (>::call_once - shim(fn())) -RUSTLIB/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace) -RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start::{closure#0}) -RUSTLIB/core/src/ops/function.rs:LL:COL (std::ops::function::impls::call_once) -RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try::do_call) -RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try) -RUSTLIB/std/src/panic.rs:LL:COL (std::panic::catch_unwind) -RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start_internal::{closure#2}) -RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try::do_call) -RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try) -RUSTLIB/std/src/panic.rs:LL:COL (std::panic::catch_unwind) -RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start_internal) -RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start) +$DIR/backtrace-api-v0.rs:LL:CC (func_d) +$DIR/backtrace-api-v0.rs:LL:CC (func_c) +$DIR/backtrace-api-v0.rs:LL:CC (func_b) +$DIR/backtrace-api-v0.rs:LL:CC (func_a) +$DIR/backtrace-api-v0.rs:LL:CC (main) +rustc_src/src/ops/function.rs:LL:CC (>::call_once - shim(fn())) +rustc_src/src/sys_common/backtrace.rs:LL:CC (std::sys_common::backtrace::__rust_begin_short_backtrace) +rustc_src/src/rt.rs:LL:CC (std::rt::lang_start::{closure#0}) +rustc_src/src/ops/function.rs:LL:CC (std::ops::function::impls::call_once) +rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try::do_call) +rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try) +rustc_src/src/panic.rs:LL:CC (std::panic::catch_unwind) +rustc_src/src/rt.rs:LL:CC (std::rt::lang_start_internal::{closure#2}) +rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try::do_call) +rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try) +rustc_src/src/panic.rs:LL:CC (std::panic::catch_unwind) +rustc_src/src/rt.rs:LL:CC (std::rt::lang_start_internal) +rustc_src/src/rt.rs:LL:CC (std::rt::lang_start) diff --git a/tests/run-pass/backtrace-api-v0.stdout b/tests/run-pass/backtrace-api-v0.stdout index c80a3f3bbcab..9de1d034bb73 100644 --- a/tests/run-pass/backtrace-api-v0.stdout +++ b/tests/run-pass/backtrace-api-v0.stdout @@ -1,5 +1,5 @@ -$DIR/backtrace-api-v0.rs:13:59 (func_d) -$DIR/backtrace-api-v0.rs:12:50 (func_c) -$DIR/backtrace-api-v0.rs:6:53 (func_b::) -$DIR/backtrace-api-v0.rs:5:50 (func_a) -$DIR/backtrace-api-v0.rs:17:18 (main) +$DIR/backtrace-api-v0.rs:11:59 (func_d) +$DIR/backtrace-api-v0.rs:10:50 (func_c) +$DIR/backtrace-api-v0.rs:4:53 (func_b) +$DIR/backtrace-api-v0.rs:3:50 (func_a) +$DIR/backtrace-api-v0.rs:15:18 (main) diff --git a/tests/run-pass/backtrace-api-v1.rs b/tests/run-pass/backtrace-api-v1.rs index 58ed63eaf395..6d4a29c954e9 100644 --- a/tests/run-pass/backtrace-api-v1.rs +++ b/tests/run-pass/backtrace-api-v1.rs @@ -1,6 +1,4 @@ -// normalize-stderr-test ".*/(rust[^/]*|checkout)/library/" -> "RUSTLIB/" -// normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL " -// normalize-stderr-test "::<.*>" -> "" +// normalize-stderr-test: "::<.*>" -> "" #[inline(never)] fn func_a() -> Box<[*mut ()]> { func_b::() } #[inline(never)] fn func_b() -> Box<[*mut ()]> { func_c() } diff --git a/tests/run-pass/backtrace-api-v1.stderr b/tests/run-pass/backtrace-api-v1.stderr index 806a1c60f5a0..87c59f426968 100644 --- a/tests/run-pass/backtrace-api-v1.stderr +++ b/tests/run-pass/backtrace-api-v1.stderr @@ -1,18 +1,18 @@ -$DIR/backtrace-api-v1.rs:13:144 (func_d) -$DIR/backtrace-api-v1.rs:12:50 (func_c) -$DIR/backtrace-api-v1.rs:6:53 (func_b) -$DIR/backtrace-api-v1.rs:5:50 (func_a) -$DIR/backtrace-api-v1.rs:17:18 (main) -RUSTLIB/core/src/ops/function.rs:LL:COL (>::call_once - shim(fn())) -RUSTLIB/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace) -RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start::{closure#0}) -RUSTLIB/core/src/ops/function.rs:LL:COL (std::ops::function::impls::call_once) -RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try::do_call) -RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try) -RUSTLIB/std/src/panic.rs:LL:COL (std::panic::catch_unwind) -RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start_internal::{closure#2}) -RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try::do_call) -RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try) -RUSTLIB/std/src/panic.rs:LL:COL (std::panic::catch_unwind) -RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start_internal) -RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start) +$DIR/backtrace-api-v1.rs:LL:CC (func_d) +$DIR/backtrace-api-v1.rs:LL:CC (func_c) +$DIR/backtrace-api-v1.rs:LL:CC (func_b) +$DIR/backtrace-api-v1.rs:LL:CC (func_a) +$DIR/backtrace-api-v1.rs:LL:CC (main) +rustc_src/src/ops/function.rs:LL:CC (>::call_once - shim(fn())) +rustc_src/src/sys_common/backtrace.rs:LL:CC (std::sys_common::backtrace::__rust_begin_short_backtrace) +rustc_src/src/rt.rs:LL:CC (std::rt::lang_start::{closure#0}) +rustc_src/src/ops/function.rs:LL:CC (std::ops::function::impls::call_once) +rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try::do_call) +rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try) +rustc_src/src/panic.rs:LL:CC (std::panic::catch_unwind) +rustc_src/src/rt.rs:LL:CC (std::rt::lang_start_internal::{closure#2}) +rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try::do_call) +rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try) +rustc_src/src/panic.rs:LL:CC (std::panic::catch_unwind) +rustc_src/src/rt.rs:LL:CC (std::rt::lang_start_internal) +rustc_src/src/rt.rs:LL:CC (std::rt::lang_start) diff --git a/tests/run-pass/backtrace-api-v1.stdout b/tests/run-pass/backtrace-api-v1.stdout index 2670d560eb19..b820a1be0a19 100644 --- a/tests/run-pass/backtrace-api-v1.stdout +++ b/tests/run-pass/backtrace-api-v1.stdout @@ -1,5 +1,5 @@ -$DIR/backtrace-api-v1.rs:13:144 (func_d) -$DIR/backtrace-api-v1.rs:12:50 (func_c) -$DIR/backtrace-api-v1.rs:6:53 (func_b::) -$DIR/backtrace-api-v1.rs:5:50 (func_a) -$DIR/backtrace-api-v1.rs:17:18 (main) +$DIR/backtrace-api-v1.rs:11:144 (func_d) +$DIR/backtrace-api-v1.rs:10:50 (func_c) +$DIR/backtrace-api-v1.rs:4:53 (func_b) +$DIR/backtrace-api-v1.rs:3:50 (func_a) +$DIR/backtrace-api-v1.rs:15:18 (main) diff --git a/tests/run-pass/backtrace-std.rs b/tests/run-pass/backtrace-std.rs index 9b61aabab3b2..64b7e7293b19 100644 --- a/tests/run-pass/backtrace-std.rs +++ b/tests/run-pass/backtrace-std.rs @@ -1,6 +1,3 @@ -// normalize-stderr-test "at .*/(rust[^/]*|checkout)/library/" -> "at RUSTLIB/" -// normalize-stderr-test "RUSTLIB/([^:]*):\d+:\d+"-> "RUSTLIB/$1:LL:CC" -// normalize-stderr-test "::<.*>" -> "" // compile-flags: -Zmiri-disable-isolation #![feature(backtrace)] diff --git a/tests/run-pass/backtrace-std.stderr b/tests/run-pass/backtrace-std.stderr index 64386085c775..848ccaea1b62 100644 --- a/tests/run-pass/backtrace-std.stderr +++ b/tests/run-pass/backtrace-std.stderr @@ -1,36 +1,36 @@ 0: func_d - at $DIR/backtrace-std.rs:18:45 + at $DIR/backtrace-std.rs:LL:CC 1: func_c - at $DIR/backtrace-std.rs:17:45 + at $DIR/backtrace-std.rs:LL:CC 2: func_b - at $DIR/backtrace-std.rs:11:48 + at $DIR/backtrace-std.rs:LL:CC 3: func_a - at $DIR/backtrace-std.rs:10:45 + at $DIR/backtrace-std.rs:LL:CC 4: main - at $DIR/backtrace-std.rs:21:19 + at $DIR/backtrace-std.rs:LL:CC 5: >::call_once - shim(fn()) - at RUSTLIB/core/src/ops/function.rs:LL:CC + at rustc_src/src/ops/function.rs:LL:CC 6: std::sys_common::backtrace::__rust_begin_short_backtrace - at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + at rustc_src/src/sys_common/backtrace.rs:LL:CC 7: std::rt::lang_start::{closure#0} - at RUSTLIB/std/src/rt.rs:LL:CC + at rustc_src/src/rt.rs:LL:CC 8: std::ops::function::impls::call_once - at RUSTLIB/core/src/ops/function.rs:LL:CC + at rustc_src/src/ops/function.rs:LL:CC 9: std::panicking::r#try::do_call - at RUSTLIB/std/src/panicking.rs:LL:CC + at rustc_src/src/panicking.rs:LL:CC 10: std::panicking::r#try - at RUSTLIB/std/src/panicking.rs:LL:CC + at rustc_src/src/panicking.rs:LL:CC 11: std::panic::catch_unwind - at RUSTLIB/std/src/panic.rs:LL:CC + at rustc_src/src/panic.rs:LL:CC 12: std::rt::lang_start_internal::{closure#2} - at RUSTLIB/std/src/rt.rs:LL:CC + at rustc_src/src/rt.rs:LL:CC 13: std::panicking::r#try::do_call - at RUSTLIB/std/src/panicking.rs:LL:CC + at rustc_src/src/panicking.rs:LL:CC 14: std::panicking::r#try - at RUSTLIB/std/src/panicking.rs:LL:CC + at rustc_src/src/panicking.rs:LL:CC 15: std::panic::catch_unwind - at RUSTLIB/std/src/panic.rs:LL:CC + at rustc_src/src/panic.rs:LL:CC 16: std::rt::lang_start_internal - at RUSTLIB/std/src/rt.rs:LL:CC + at rustc_src/src/rt.rs:LL:CC 17: std::rt::lang_start - at RUSTLIB/std/src/rt.rs:LL:CC + at rustc_src/src/rt.rs:LL:CC diff --git a/tests/run-pass/concurrency/disable_data_race_detector.rs b/tests/run-pass/concurrency/disable_data_race_detector.rs index 8b2d180f11d4..14e2d5651de0 100644 --- a/tests/run-pass/concurrency/disable_data_race_detector.rs +++ b/tests/run-pass/concurrency/disable_data_race_detector.rs @@ -19,7 +19,7 @@ pub fn main() { }); let j2 = spawn(move || { - *c.0 = 64; //~ ERROR Data race (but not detected as the detector is disabled) + *c.0 = 64; // Data race (but not detected as the detector is disabled) }); j1.join().unwrap(); diff --git a/tests/run-pass/concurrency/libc_pthread_cond.rs b/tests/run-pass/concurrency/libc_pthread_cond.rs index 0e09ec9126a5..631675aaaf54 100644 --- a/tests/run-pass/concurrency/libc_pthread_cond.rs +++ b/tests/run-pass/concurrency/libc_pthread_cond.rs @@ -1,5 +1,5 @@ // ignore-windows: No libc on Windows -// ignore-macos: pthread_condattr_setclock is not supported on MacOS. +// ignore-apple: pthread_condattr_setclock is not supported on MacOS. // compile-flags: -Zmiri-disable-isolation -Zmiri-check-number-validity #![feature(rustc_private)] diff --git a/tests/run-pass/concurrency/linux-futex.rs b/tests/run-pass/concurrency/linux-futex.rs index 4ac928398e23..8a67e0b525a9 100644 --- a/tests/run-pass/concurrency/linux-futex.rs +++ b/tests/run-pass/concurrency/linux-futex.rs @@ -1,7 +1,4 @@ -// Unfortunately, the test framework does not support 'only-linux', -// so we need to ignore Windows and macOS instead. -// ignore-macos: Uses Linux-only APIs -// ignore-windows: Uses Linux-only APIs +// only-linux // compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] diff --git a/tests/run-pass/concurrency/simple.stderr b/tests/run-pass/concurrency/simple.stderr index 35f5f10274c9..bb60638bd683 100644 --- a/tests/run-pass/concurrency/simple.stderr +++ b/tests/run-pass/concurrency/simple.stderr @@ -1,5 +1,5 @@ warning: thread support is experimental and incomplete: weak memory effects are not emulated. -thread '' panicked at 'Hello!', $DIR/simple.rs:55:9 +thread '' panicked at 'Hello!', $DIR/simple.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -thread 'childthread' panicked at 'Hello, world!', $DIR/simple.rs:65:9 +thread 'childthread' panicked at 'Hello, world!', $DIR/simple.rs:LL:CC diff --git a/tests/run-pass/current_dir_with_isolation.rs b/tests/run-pass/current_dir_with_isolation.rs index b5fe6114b2f3..98c44d57b65a 100644 --- a/tests/run-pass/current_dir_with_isolation.rs +++ b/tests/run-pass/current_dir_with_isolation.rs @@ -1,6 +1,6 @@ // compile-flags: -Zmiri-isolation-error=warn-nobacktrace -// normalize-stderr-test "(getcwd|GetCurrentDirectoryW)" -> "$$GETCWD" -// normalize-stderr-test "(chdir|SetCurrentDirectoryW)" -> "$$SETCWD" +// normalize-stderr-test: "(getcwd|GetCurrentDirectoryW)" -> "$$GETCWD" +// normalize-stderr-test: "(chdir|SetCurrentDirectoryW)" -> "$$SETCWD" use std::env; use std::io::ErrorKind; diff --git a/tests/run-pass/fs_with_isolation.rs b/tests/run-pass/fs_with_isolation.rs index a9e1e5094fa5..cd91cd9be30e 100644 --- a/tests/run-pass/fs_with_isolation.rs +++ b/tests/run-pass/fs_with_isolation.rs @@ -1,6 +1,6 @@ // ignore-windows: File handling is not implemented yet // compile-flags: -Zmiri-isolation-error=warn-nobacktrace -// normalize-stderr-test "(stat(x)?)" -> "$$STAT" +// normalize-stderr-test: "(stat(x)?)" -> "$$STAT" #![feature(rustc_private)] diff --git a/tests/run-pass/linux-getrandom-without-isolation.rs b/tests/run-pass/linux-getrandom-without-isolation.rs index ce9ff8b6c3f9..e08d4466a7bf 100644 --- a/tests/run-pass/linux-getrandom-without-isolation.rs +++ b/tests/run-pass/linux-getrandom-without-isolation.rs @@ -1,7 +1,4 @@ -// Unfortunately, compiletest_rs does not support 'only-linux', -// so we need to ignore Windows and macOS instead. -// ignore-macos: Uses Linux-only APIs -// ignore-windows: Uses Linux-only APIs +// only-linux // compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] extern crate libc; diff --git a/tests/run-pass/linux-getrandom.rs b/tests/run-pass/linux-getrandom.rs index f582a282c59b..762e754f8127 100644 --- a/tests/run-pass/linux-getrandom.rs +++ b/tests/run-pass/linux-getrandom.rs @@ -1,7 +1,4 @@ -// Unfortunately, compiletest_rs does not support 'only-linux', -// so we need to ignore Windows and macOS instead. -// ignore-macos: Uses Linux-only APIs -// ignore-windows: Uses Linux-only APIs +// only-linux #![feature(rustc_private)] extern crate libc; diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index 63a3c9a47648..80881948c03c 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -1,5 +1,3 @@ -// normalize-stderr-test "[^ ]*core/[a-z_/]+.rs[0-9:]*" -> "$$LOC" -// normalize-stderr-test "catch_panic\.rs:[0-9]{2}" -> "catch_panic.rs:LL" // We test the `align_offset` panic below, make sure we test the interpreter impl and not the "real" one. // compile-flags: -Zmiri-symbolic-alignment-check #![feature(never_type)] diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr index 0f43ab2520a5..36a7818d2766 100644 --- a/tests/run-pass/panic/catch_panic.stderr +++ b/tests/run-pass/panic/catch_panic.stderr @@ -1,26 +1,26 @@ -thread 'main' panicked at 'Hello from panic: std', $DIR/catch_panic.rs:LL:27 +thread 'main' panicked at 'Hello from panic: std', $DIR/catch_panic.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace Caught panic message (&str): Hello from panic: std -thread 'main' panicked at 'Hello from panic: 1', $DIR/catch_panic.rs:LL:26 +thread 'main' panicked at 'Hello from panic: 1', $DIR/catch_panic.rs:LL:CC Caught panic message (String): Hello from panic: 1 -thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:LL:26 +thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:LL:CC Caught panic message (String): Hello from panic: 2 -thread 'main' panicked at 'Box', $DIR/catch_panic.rs:LL:27 +thread 'main' panicked at 'Box', $DIR/catch_panic.rs:LL:CC Failed to get caught panic message. -thread 'main' panicked at 'Hello from panic: core', $DIR/catch_panic.rs:LL:27 +thread 'main' panicked at 'Hello from panic: core', $DIR/catch_panic.rs:LL:CC Caught panic message (&str): Hello from panic: core -thread 'main' panicked at 'Hello from panic: 5', $DIR/catch_panic.rs:LL:26 +thread 'main' panicked at 'Hello from panic: 5', $DIR/catch_panic.rs:LL:CC Caught panic message (String): Hello from panic: 5 -thread 'main' panicked at 'Hello from panic: 6', $DIR/catch_panic.rs:LL:26 +thread 'main' panicked at 'Hello from panic: 6', $DIR/catch_panic.rs:LL:CC Caught panic message (String): Hello from panic: 6 -thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4', $DIR/catch_panic.rs:LL:33 +thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4', $DIR/catch_panic.rs:LL:CC Caught panic message (String): index out of bounds: the len is 3 but the index is 4 -thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:LL:33 +thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:LL:CC Caught panic message (&str): attempt to divide by zero -thread 'main' panicked at 'align_offset: align is not a power-of-two', $LOC +thread 'main' panicked at 'align_offset: align is not a power-of-two', rustc_src/src/ptr/const_ptr.rs:LL:CC Caught panic message (&str): align_offset: align is not a power-of-two -thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:LL:29 +thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:LL:CC Caught panic message (&str): assertion failed: false -thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:LL:29 +thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:LL:CC Caught panic message (&str): assertion failed: false Success! diff --git a/tests/run-pass/panic/concurrent-panic.stderr b/tests/run-pass/panic/concurrent-panic.stderr index 1ee688c1d32c..ae132c9ee348 100644 --- a/tests/run-pass/panic/concurrent-panic.stderr +++ b/tests/run-pass/panic/concurrent-panic.stderr @@ -2,11 +2,11 @@ warning: thread support is experimental and incomplete: weak memory effects are Thread 1 starting, will block on mutex Thread 1 reported it has started -thread '' panicked at 'panic in thread 2', $DIR/concurrent-panic.rs:65:13 +thread '' panicked at 'panic in thread 2', $DIR/concurrent-panic.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace Thread 2 blocking on thread 1 Thread 2 reported it has started Unlocking mutex -thread '' panicked at 'panic in thread 1', $DIR/concurrent-panic.rs:42:13 +thread '' panicked at 'panic in thread 1', $DIR/concurrent-panic.rs:LL:CC Thread 1 has exited Thread 2 has exited diff --git a/tests/run-pass/panic/panic1.rs b/tests/run-pass/panic/panic1.rs deleted file mode 100644 index da300ecb59f6..000000000000 --- a/tests/run-pass/panic/panic1.rs +++ /dev/null @@ -1,9 +0,0 @@ -// rustc-env: RUST_BACKTRACE=1 -// compile-flags: -Zmiri-disable-isolation -// normalize-stderr-test "at .*/(rust[^/]*|checkout)/library/.*" -> "at RUSTLIB/$$FILE:LL:COL" -// normalize-stderr-test "::<.*>" -> "" - - -fn main() { - std::panic!("panicking from libstd"); -} diff --git a/tests/run-pass/stacked-borrows/generators-self-referential.rs b/tests/run-pass/stacked-borrows/generators-self-referential.rs index 01ce8a61418c..b71912882dd2 100644 --- a/tests/run-pass/stacked-borrows/generators-self-referential.rs +++ b/tests/run-pass/stacked-borrows/generators-self-referential.rs @@ -13,7 +13,7 @@ fn firstn() -> impl Generator { let num = &mut num; yield *num; - *num += 1; //~ ERROR: borrow stack + *num += 1; // would fail here yield *num; *num += 1; diff --git a/tests/run-pass/track-alloc-1.stderr b/tests/run-pass/track-alloc-1.stderr index 3c5a55d986e3..be96b729838d 100644 --- a/tests/run-pass/track-alloc-1.stderr +++ b/tests/run-pass/track-alloc-1.stderr @@ -1,5 +1,5 @@ note: tracking was triggered - | - = note: created allocation with id 1 - = note: (no span available) + | + = note: created allocation with id 1 + = note: (no span available) diff --git a/tests/run-pass/wtf8.rs b/tests/run-pass/wtf8.rs index 2b4da785f2ee..5a5815068081 100644 --- a/tests/run-pass/wtf8.rs +++ b/tests/run-pass/wtf8.rs @@ -1,5 +1,4 @@ -// ignore-linux: tests Windows-only APIs -// ignore-macos: tests Windows-only APIs +// only-windows use std::os::windows::ffi::{OsStrExt, OsStringExt}; use std::ffi::{OsStr, OsString}; diff --git a/ui_test/Cargo.toml b/ui_test/Cargo.toml new file mode 100644 index 000000000000..66d35fdd2228 --- /dev/null +++ b/ui_test/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "ui_test" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rustc_version = "0.4" +colored = "2" +regex = "1.5.5" +pretty_assertions = "1.2.1" +crossbeam = "0.8.1" +lazy_static = "1.4.0" diff --git a/ui_test/README.md b/ui_test/README.md new file mode 100644 index 000000000000..fdd94a74823e --- /dev/null +++ b/ui_test/README.md @@ -0,0 +1,30 @@ +A smaller version of compiletest-rs + +## Supported magic comment annotations + +Note that the space after `//`, when it is present, is *not* optional -- it must be exactly one. + +* `// ignore-XXX` avoids running the test on targets whose triple contains `XXX` + * `XXX` can also be one of `64bit`, `32bit` or `16bit` +* `// only-XXX` avoids running the test on targets whose triple **does not** contain `XXX` + * `XXX` can also be one of `64bit`, `32bit` or `16bit` +* `// stderr-per-bitwidth` produces one stderr file per bitwidth, as they may differ significantly sometimes +* `// error-pattern: XXX` make sure the stderr output contains `XXX` +* `//~ ERROR: XXX` make sure the stderr output contains `XXX` for an error in the line where this comment is written + * NOTE: it is not checked at present that it is actually in the line where the error occurred, or that it is truly an ERROR/WARNING/HELP/NOTE, but you should treat it as such until that becomes true. + * Also supports `HELP` or `WARN` for different kind of message + * if the all caps note is left out, any message is matched + * This checks the output *before* normalization, so you can check things that get normalized away, but need to + be careful not to accidentally have a pattern that differs between platforms. +* `// revisions: XXX YYY` runs the test once for each space separated name in the list + * emits one stderr file per revision + * `//~` comments can be restricted to specific revisions by adding the revision name before the `~` in square brackets: `//[XXX]~` +* `// compile-flags: XXX` appends `XXX` to the command line arguments passed to the rustc driver +* `// rustc-env: XXX=YYY` sets the env var `XXX` to `YYY` for the rustc driver execution. + * for Miri these env vars are used during compilation via rustc and during the emulation of the program +* `// normalize-stderr-test: "REGEX" -> "REPLACEMENT"` replaces all matches of `REGEX` in the stderr with `REPLACEMENT`. The replacement may specify `$1` and similar backreferences to paste captures. + +## Significant differences to compiletest-rs + +* `ignore-*` and `only-*` opereate solely on the triple, instead of supporting things like `macos` +* only `//~` comments can be individualized per revision diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs new file mode 100644 index 000000000000..14566d2feccf --- /dev/null +++ b/ui_test/src/comments.rs @@ -0,0 +1,111 @@ +use std::path::Path; + +use regex::Regex; + +/// This crate supports various magic comments that get parsed as file-specific +/// configuration values. This struct parses them all in one go and then they +/// get processed by their respective use sites. +#[derive(Default)] +pub struct Comments { + /// List of revision names to execute. Can only be speicified once + pub revisions: Option>, + /// Don't run this test if any of these filters apply + pub ignore: Vec, + /// Only run this test if all of these filters apply + pub only: Vec, + /// Generate one .stderr file per bit width, by prepending with `.64bit` and similar + pub stderr_per_bitwidth: bool, + /// Additional flags to pass to the executable + pub compile_flags: Vec, + /// Additional env vars to set for the executable + pub env_vars: Vec<(String, String)>, + /// Normalizations to apply to the stderr output before emitting it to disk + pub normalize_stderr: Vec<(Regex, String)>, + /// An arbitrary pattern to look for in the stderr. + pub error_pattern: Option<(String, usize)>, + pub error_matches: Vec, +} + +pub struct ErrorMatch { + pub matched: String, + pub revision: Option, + pub definition_line: usize, +} + +impl Comments { + pub fn parse(path: &Path) -> Self { + let mut this = Self::default(); + let content = std::fs::read_to_string(path).unwrap(); + let error_pattern_regex = + Regex::new(r"//(\[(?P[^\]]+)\])?~[|^]*\s*(ERROR|HELP|WARN)?:?(?P.*)") + .unwrap(); + for (l, line) in content.lines().enumerate() { + if let Some(revisions) = line.strip_prefix("// revisions:") { + assert_eq!( + this.revisions, + None, + "{}:{l}, cannot specifiy revisions twice", + path.display() + ); + this.revisions = + Some(revisions.trim().split_whitespace().map(|s| s.to_string()).collect()); + } + if let Some(s) = line.strip_prefix("// ignore-") { + let s = s + .split_once(|c: char| c == ':' || c.is_whitespace()) + .map(|(s, _)| s) + .unwrap_or(s); + this.ignore.push(s.to_owned()); + } + if let Some(s) = line.strip_prefix("// only-") { + let s = s + .split_once(|c: char| c == ':' || c.is_whitespace()) + .map(|(s, _)| s) + .unwrap_or(s); + this.only.push(s.to_owned()); + } + if line.starts_with("// stderr-per-bitwidth") { + assert!( + !this.stderr_per_bitwidth, + "{}:{l}, cannot specifiy stderr-per-bitwidth twice", + path.display() + ); + this.stderr_per_bitwidth = true; + } + if let Some(s) = line.strip_prefix("// compile-flags:") { + this.compile_flags.extend(s.split_whitespace().map(|s| s.to_string())); + } + if let Some(s) = line.strip_prefix("// rustc-env:") { + for env in s.split_whitespace() { + if let Some((k, v)) = env.split_once('=') { + this.env_vars.push((k.to_string(), v.to_string())); + } + } + } + if let Some(s) = line.strip_prefix("// normalize-stderr-test:") { + let (from, to) = s.split_once("->").expect("normalize-stderr-test needs a `->`"); + let from = from.trim().trim_matches('"'); + let to = to.trim().trim_matches('"'); + let from = Regex::new(from).unwrap(); + this.normalize_stderr.push((from, to.to_string())); + } + if let Some(s) = line.strip_prefix("// error-pattern:") { + assert_eq!( + this.error_pattern, + None, + "{}:{l}, cannot specifiy error_pattern twice", + path.display() + ); + this.error_pattern = Some((s.trim().to_string(), l)); + } + if let Some(captures) = error_pattern_regex.captures(line) { + // FIXME: check that the error happens on the marked line + let matched = captures["text"].trim().to_string(); + + let revision = captures.name("revision").map(|rev| rev.as_str().to_string()); + this.error_matches.push(ErrorMatch { matched, revision, definition_line: l }); + } + } + this + } +} diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs new file mode 100644 index 000000000000..95ae3a51b235 --- /dev/null +++ b/ui_test/src/lib.rs @@ -0,0 +1,410 @@ +use std::fmt::Write; +use std::path::{Path, PathBuf}; +use std::process::{Command, ExitStatus}; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Mutex; + +use colored::*; +use comments::ErrorMatch; +use crossbeam::queue::SegQueue; +use regex::Regex; + +use crate::comments::Comments; + +mod comments; + +#[derive(Debug)] +pub struct Config { + /// Arguments passed to the binary that is executed. + pub args: Vec, + /// `None` to run on the host, otherwise a target triple + pub target: Option, + /// Filters applied to stderr output before processing it + pub stderr_filters: Filter, + /// Filters applied to stdout output before processing it + pub stdout_filters: Filter, + /// The folder in which to start searching for .rs files + pub root_dir: PathBuf, + pub mode: Mode, + pub program: PathBuf, + pub output_conflict_handling: OutputConflictHandling, +} + +#[derive(Debug)] +pub enum OutputConflictHandling { + /// The default: emit a diff of the expected/actual output. + Error, + /// Ignore mismatches in the stderr/stdout files. + Ignore, + /// Instead of erroring if the stderr/stdout differs from the expected + /// automatically replace it with the found output (after applying filters). + Bless, +} + +pub type Filter = Vec<(Regex, &'static str)>; + +pub fn run_tests(config: Config) { + eprintln!(" Compiler flags: {:?}", config.args); + + // Get the triple with which to run the tests + let target = config.target.clone().unwrap_or_else(|| config.get_host()); + + // A queue for files or folders to process + let todo = SegQueue::new(); + todo.push(config.root_dir.clone()); + + // Some statistics and failure reports. + let failures = Mutex::new(vec![]); + let succeeded = AtomicUsize::default(); + let skipped = AtomicUsize::default(); + + crossbeam::scope(|s| { + for _ in 0..std::thread::available_parallelism().unwrap().get() { + s.spawn(|_| { + while let Some(path) = todo.pop() { + // Collect everything inside directories + if path.is_dir() { + for entry in std::fs::read_dir(path).unwrap() { + todo.push(entry.unwrap().path()); + } + continue; + } + // Only look at .rs files + if !path.extension().map(|ext| ext == "rs").unwrap_or(false) { + continue; + } + let comments = Comments::parse(&path); + // Skip file if only/skip rules do (not) apply + if ignore_file(&comments, &target) { + skipped.fetch_add(1, Ordering::Relaxed); + eprintln!("{} .. {}", path.display(), "skipped".yellow()); + continue; + } + // Run the test for all revisions + for revision in + comments.revisions.clone().unwrap_or_else(|| vec![String::new()]) + { + let (m, errors) = run_test(&path, &config, &target, &revision, &comments); + + // Using `format` to prevent messages from threads from getting intermingled. + let mut msg = format!("{} ", path.display()); + if !revision.is_empty() { + write!(msg, "(revision `{revision}`) ").unwrap(); + } + write!(msg, " .. ").unwrap(); + if errors.is_empty() { + eprintln!("{msg}{}", "ok".green()); + succeeded.fetch_add(1, Ordering::Relaxed); + } else { + eprintln!("{msg}{}", "FAILED".red().bold()); + failures.lock().unwrap().push((path.clone(), m, revision, errors)); + } + } + } + }); + } + }) + .unwrap(); + + // Print all errors in a single thread to show reliable output + let failures = failures.into_inner().unwrap(); + let succeeded = succeeded.load(Ordering::Relaxed); + let skipped = skipped.load(Ordering::Relaxed); + if !failures.is_empty() { + for (path, miri, revision, errors) in &failures { + eprintln!(); + eprint!("{}", path.display().to_string().underline()); + if !revision.is_empty() { + eprint!(" (revision `{}`)", revision); + } + eprint!("{}", " FAILED".red()); + eprintln!(); + eprintln!("command: {:?}", miri); + eprintln!(); + let mut dump_stderr = None; + for error in errors { + match error { + Error::ExitStatus(mode, exit_status) => eprintln!("{mode:?} got {exit_status}"), + Error::PatternNotFound { stderr, pattern, definition_line } => { + eprintln!("`{pattern}` {} in stderr output", "not found".red()); + eprintln!( + "expected because of pattern here: {}:{definition_line}", + path.display() + ); + dump_stderr = Some(stderr.clone()) + } + Error::NoPatternsFound => + eprintln!("{}", "no error patterns found in failure test".red()), + Error::PatternFoundInPassTest => + eprintln!("{}", "error pattern found in success test".red()), + Error::OutputDiffers { path, actual, expected } => { + dump_stderr = None; + eprintln!("actual output differed from expected {}", path.display()); + eprintln!("{}", pretty_assertions::StrComparison::new(expected, actual)); + eprintln!() + } + } + eprintln!(); + } + if let Some(stderr) = dump_stderr { + eprintln!("actual stderr:"); + eprintln!("{}", stderr); + eprintln!(); + } + } + eprintln!( + "{} tests failed, {} tests passed, {} skipped", + failures.len().to_string().red().bold(), + succeeded.to_string().green(), + skipped.to_string().yellow() + ); + std::process::exit(1); + } + eprintln!(); + eprintln!( + "{} tests passed, {} skipped", + succeeded.to_string().green(), + skipped.to_string().yellow() + ); +} + +#[derive(Debug)] +enum Error { + /// Got an invalid exit status for the given mode. + ExitStatus(Mode, ExitStatus), + PatternNotFound { + stderr: String, + pattern: String, + definition_line: usize, + }, + /// A ui test checking for failure does not have any failure patterns + NoPatternsFound, + /// A ui test checking for success has failure patterns + PatternFoundInPassTest, + /// Stderr/Stdout differed from the `.stderr`/`.stdout` file present. + OutputDiffers { + path: PathBuf, + actual: String, + expected: String, + }, +} + +type Errors = Vec; + +fn run_test( + path: &Path, + config: &Config, + target: &str, + revision: &str, + comments: &Comments, +) -> (Command, Errors) { + // Run miri + let mut miri = Command::new(&config.program); + miri.args(config.args.iter()); + miri.arg(path); + if !revision.is_empty() { + miri.arg(format!("--cfg={revision}")); + } + for arg in &comments.compile_flags { + miri.arg(arg); + } + for (k, v) in &comments.env_vars { + miri.env(k, v); + } + let output = miri.output().expect("could not execute miri"); + let mut errors = config.mode.ok(output.status); + // Check output files (if any) + let revised = |extension: &str| { + if revision.is_empty() { + extension.to_string() + } else { + format!("{}.{}", revision, extension) + } + }; + // Check output files against actual output + check_output( + &output.stderr, + path, + &mut errors, + revised("stderr"), + target, + &config.stderr_filters, + &config, + comments, + ); + check_output( + &output.stdout, + path, + &mut errors, + revised("stdout"), + target, + &config.stdout_filters, + &config, + comments, + ); + // Check error annotations in the source against output + check_annotations(&output.stderr, &mut errors, config, revision, comments); + (miri, errors) +} + +fn check_annotations( + unnormalized_stderr: &[u8], + errors: &mut Errors, + config: &Config, + revision: &str, + comments: &Comments, +) { + let unnormalized_stderr = std::str::from_utf8(unnormalized_stderr).unwrap(); + let mut found_annotation = false; + if let Some((ref error_pattern, definition_line)) = comments.error_pattern { + if !unnormalized_stderr.contains(error_pattern) { + errors.push(Error::PatternNotFound { + stderr: unnormalized_stderr.to_string(), + pattern: error_pattern.to_string(), + definition_line, + }); + } + found_annotation = true; + } + for &ErrorMatch { ref matched, revision: ref rev, definition_line } in &comments.error_matches { + // FIXME: check that the error happens on the marked line + + if let Some(rev) = rev { + if rev != revision { + continue; + } + } + + if !unnormalized_stderr.contains(matched) { + errors.push(Error::PatternNotFound { + stderr: unnormalized_stderr.to_string(), + pattern: matched.to_string(), + definition_line, + }); + } + found_annotation = true; + } + match (config.mode, found_annotation) { + (Mode::Pass, true) | (Mode::Panic, true) => errors.push(Error::PatternFoundInPassTest), + (Mode::Fail, false) => errors.push(Error::NoPatternsFound), + _ => {} + }; +} + +fn check_output( + output: &[u8], + path: &Path, + errors: &mut Errors, + kind: String, + target: &str, + filters: &Filter, + config: &Config, + comments: &Comments, +) { + let output = std::str::from_utf8(&output).unwrap(); + let output = normalize(path, output, filters, comments); + let path = output_path(path, comments, kind, target); + match config.output_conflict_handling { + OutputConflictHandling::Bless => + if output.is_empty() { + let _ = std::fs::remove_file(path); + } else { + std::fs::write(path, &output).unwrap(); + }, + OutputConflictHandling::Error => { + let expected_output = std::fs::read_to_string(&path).unwrap_or_default(); + if output != expected_output { + errors.push(Error::OutputDiffers { + path, + actual: output, + expected: expected_output, + }); + } + } + OutputConflictHandling::Ignore => {} + } +} + +fn output_path(path: &Path, comments: &Comments, kind: String, target: &str) -> PathBuf { + if comments.stderr_per_bitwidth { + return path.with_extension(format!("{}.{kind}", get_pointer_width(target))); + } + path.with_extension(kind) +} + +fn ignore_file(comments: &Comments, target: &str) -> bool { + for s in &comments.ignore { + if target.contains(s) { + return true; + } + if get_pointer_width(target) == s { + return true; + } + } + for s in &comments.only { + if !target.contains(s) { + return true; + } + if get_pointer_width(target) != s { + return true; + } + } + false +} + +// Taken 1:1 from compiletest-rs +fn get_pointer_width(triple: &str) -> &'static str { + if (triple.contains("64") && !triple.ends_with("gnux32") && !triple.ends_with("gnu_ilp32")) + || triple.starts_with("s390x") + { + "64bit" + } else if triple.starts_with("avr") { + "16bit" + } else { + "32bit" + } +} + +fn normalize(path: &Path, text: &str, filters: &Filter, comments: &Comments) -> String { + // Useless paths + let mut text = text.replace(&path.parent().unwrap().display().to_string(), "$DIR"); + if let Some(lib_path) = option_env!("RUSTC_LIB_PATH") { + text = text.replace(lib_path, "RUSTLIB"); + } + + for (regex, replacement) in filters.iter() { + text = regex.replace_all(&text, *replacement).to_string(); + } + + for (from, to) in &comments.normalize_stderr { + text = from.replace_all(&text, to).to_string(); + } + text +} + +impl Config { + fn get_host(&self) -> String { + rustc_version::VersionMeta::for_command(std::process::Command::new(&self.program)) + .expect("failed to parse rustc version info") + .host + } +} + +#[derive(Copy, Clone, Debug)] +pub enum Mode { + // The test passes a full execution of the rustc driver + Pass, + // The rustc driver panicked + Panic, + // The rustc driver emitted an error + Fail, +} + +impl Mode { + fn ok(self, status: ExitStatus) -> Errors { + match (status.code().unwrap(), self) { + (1, Mode::Fail) | (101, Mode::Panic) | (0, Mode::Pass) => vec![], + _ => vec![Error::ExitStatus(self, status)], + } + } +} From 8c42ef1dee4143c3ba8a2c31558b75edb179b517 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 May 2022 15:44:27 +0200 Subject: [PATCH 3108/5092] enable number validity checking and ptr::invalid checking by default --- README.md | 14 +++++--- src/bin/miri.rs | 12 +++++-- src/eval.rs | 9 +++-- src/intptrcast.rs | 19 ++++------ src/machine.rs | 17 ++++++--- src/shims/posix/sync.rs | 3 +- .../provenance/ptr_int_unexposed.rs | 2 +- tests/compile-fail/provenance/ptr_invalid.rs | 1 - .../stacked_borrows/illegal_read3.rs | 1 + tests/compile-fail/transmute-pair-uninit.rs | 1 + tests/compile-fail/uninit_byte_read.rs | 1 + .../invalid_enum_tag_256variants_uninit.rs | 1 + .../validity/ptr_integer_array_transmute.rs | 2 -- .../validity/ptr_integer_transmute.rs | 2 -- tests/compile-fail/validity/uninit_float.rs | 2 -- tests/compile-fail/validity/uninit_integer.rs | 2 -- .../validity/uninit_integer_signed.rs | 2 -- tests/run-pass/bitop-beyond-alignment.rs | 36 ------------------- .../run-pass/concurrency/libc_pthread_cond.rs | 2 +- tests/run-pass/intptrcast.rs | 2 ++ tests/run-pass/libc.rs | 10 +++--- tests/run-pass/move-uninit-primval.rs | 1 + tests/run-pass/partially-uninit.rs | 2 -- tests/run-pass/ptr_offset.rs | 4 ++- tests/run-pass/tag-align-dyn-u64.rs | 3 +- tests/run-pass/transmute_fat.rs | 5 +-- tests/run-pass/uninit_number_ignored.rs | 2 +- 27 files changed, 67 insertions(+), 91 deletions(-) delete mode 100644 tests/run-pass/bitop-beyond-alignment.rs diff --git a/README.md b/README.md index afee8a8bfa05..9248576b3c2a 100644 --- a/README.md +++ b/README.md @@ -44,8 +44,7 @@ in your program, and cannot run all programs: positives here, so if your program runs fine in Miri right now that is by no means a guarantee that it is UB-free when these questions get answered. - In particular, Miri does currently not check that integers/floats are - initialized or that references point to valid data. + In particular, Miri does currently not check that references point to valid data. * If the program relies on unspecified details of how data is laid out, it will still run fine in Miri -- but might break (including causing UB) on different compiler versions or different platforms. @@ -302,10 +301,15 @@ The remaining flags are for advanced use only, and more likely to change or be r Some of these are **unsound**, which means they can lead to Miri failing to detect cases of undefined behavior in a program. -* `-Zmiri-check-number-validity` enables checking of integer and float validity - (e.g., they must be initialized and not carry pointer provenance) as part of - enforcing validity invariants. This has no effect when +* `-Zmiri-allow-uninit-numbers` disables the check to ensure that number types (integer and float + types) always hold initialized data. (They must still be initialized when any actual operation, + such as arithmetic, is performed.) Using this flag is **unsound**. This has no effect when `-Zmiri-disable-validation` is present. +* `-Zmiri-allow-ptr-int-transmute` makes Miri more accepting of transmutation between pointers and + integers via `mem::transmute` or union/pointer type punning. This has two effects: it disables the + check against integers storing a pointer (i.e., data with provenance), thus allowing + pointer-to-integer transmutation, and it treats integer-to-pointer transmutation as equivalent to + a cast. Using this flag is **unsound**. * `-Zmiri-disable-abi-check` disables checking [function ABI]. Using this flag is **unsound**. * `-Zmiri-disable-alignment-check` disables checking pointer alignment, so you diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 784f0da8a30d..9c4cd0684c61 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -335,7 +335,16 @@ fn main() { miri_config.check_alignment = miri::AlignmentCheck::Symbolic; } "-Zmiri-check-number-validity" => { - miri_config.check_number_validity = true; + eprintln!( + "WARNING: the flag `-Zmiri-check-number-validity` no longer has any effect \ + since it is now enabled by default" + ); + } + "-Zmiri-allow-uninit-numbers" => { + miri_config.allow_uninit_numbers = true; + } + "-Zmiri-allow-ptr-int-transmute" => { + miri_config.allow_ptr_int_transmute = true; } "-Zmiri-disable-abi-check" => { miri_config.check_abi = false; @@ -386,7 +395,6 @@ fn main() { "-Zmiri-strict-provenance" => { miri_config.provenance_mode = ProvenanceMode::Strict; miri_config.tag_raw = true; - miri_config.check_number_validity = true; } "-Zmiri-permissive-provenance" => { miri_config.provenance_mode = ProvenanceMode::Permissive; diff --git a/src/eval.rs b/src/eval.rs index badda8f3bc39..39fccb092433 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -77,8 +77,10 @@ pub struct MiriConfig { pub stacked_borrows: bool, /// Controls alignment checking. pub check_alignment: AlignmentCheck, - /// Controls integer and float validity (e.g., initialization) checking. - pub check_number_validity: bool, + /// Controls integer and float validity initialization checking. + pub allow_uninit_numbers: bool, + /// Controls how we treat ptr2int and int2ptr transmutes. + pub allow_ptr_int_transmute: bool, /// Controls function [ABI](Abi) checking. pub check_abi: bool, /// Action for an op requiring communication with the host. @@ -126,7 +128,8 @@ impl Default for MiriConfig { validate: true, stacked_borrows: true, check_alignment: AlignmentCheck::Int, - check_number_validity: false, + allow_uninit_numbers: false, + allow_ptr_int_transmute: false, check_abi: true, isolated_op: IsolatedOp::Reject(RejectOpWith::Abort), ignore_leaks: false, diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 4850945b4eeb..4a86490ed09a 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -118,19 +118,12 @@ impl<'mir, 'tcx> GlobalStateInner { ) -> Pointer> { trace!("Transmuting 0x{:x} to a pointer", addr); - let global_state = ecx.machine.intptrcast.borrow(); - - match global_state.provenance_mode { - ProvenanceMode::Legacy => { - // In legacy mode, we have to support int2ptr transmutes, - // so just pretend they do the same thing as a cast. - Self::ptr_from_addr_cast(ecx, addr) - } - ProvenanceMode::Permissive | ProvenanceMode::Strict => { - // Both of these modes consider transmuted pointers to be "invalid" (`None` - // provenance). - Pointer::new(None, Size::from_bytes(addr)) - } + if ecx.machine.allow_ptr_int_transmute { + // When we allow transmutes, treat them like casts. + Self::ptr_from_addr_cast(ecx, addr) + } else { + // We consider transmuted pointers to be "invalid" (`None` provenance). + Pointer::new(None, Size::from_bytes(addr)) } } diff --git a/src/machine.rs b/src/machine.rs index 249b578b1214..1cb815706195 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -255,13 +255,19 @@ pub struct Evaluator<'mir, 'tcx> { /// Whether to enforce the validity invariant. pub(crate) validate: bool, - /// Whether to enforce validity (e.g., initialization) of integers and floats. - pub(crate) enforce_number_validity: bool, + /// Whether to allow uninitialized numbers (integers and floats). + pub(crate) allow_uninit_numbers: bool, + + /// Whether to allow ptr2int transmutes, and whether to allow *dereferencing* the result of an + /// int2ptr transmute. + pub(crate) allow_ptr_int_transmute: bool, /// Whether to enforce [ABI](Abi) of function calls. pub(crate) enforce_abi: bool, + /// The table of file descriptors. pub(crate) file_handler: shims::posix::FileHandler, + /// The table of directory descriptors. pub(crate) dir_handler: shims::posix::DirHandler, /// The "time anchor" for this machine's monotone clock (for `Instant` simulation). @@ -351,7 +357,8 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { tls: TlsData::default(), isolated_op: config.isolated_op, validate: config.validate, - enforce_number_validity: config.check_number_validity, + allow_uninit_numbers: config.allow_uninit_numbers, + allow_ptr_int_transmute: config.allow_ptr_int_transmute, enforce_abi: config.check_abi, file_handler: FileHandler::new(config.mute_stdout_stderr), dir_handler: Default::default(), @@ -493,12 +500,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn enforce_number_init(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { - ecx.machine.enforce_number_validity + !ecx.machine.allow_uninit_numbers } #[inline(always)] fn enforce_number_no_provenance(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { - ecx.machine.enforce_number_validity + !ecx.machine.allow_ptr_int_transmute } #[inline(always)] diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 1b6112a3311f..f56a309bf078 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -405,8 +405,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // To catch double-destroys, we de-initialize the mutexattr. // This is technically not right and might lead to false positives. For example, the below - // code is *likely* sound, even assuming uninit numbers are UB, but miri with - // -Zmiri-check-number-validity complains + // code is *likely* sound, even assuming uninit numbers are UB, but Miri complains. // // let mut x: MaybeUninit = MaybeUninit::zeroed(); // libc::pthread_mutexattr_init(x.as_mut_ptr()); diff --git a/tests/compile-fail/provenance/ptr_int_unexposed.rs b/tests/compile-fail/provenance/ptr_int_unexposed.rs index 2aecb68b8b64..8a336e43ba18 100644 --- a/tests/compile-fail/provenance/ptr_int_unexposed.rs +++ b/tests/compile-fail/provenance/ptr_int_unexposed.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance -Zmiri-disable-stacked-borrows +// compile-flags: -Zmiri-permissive-provenance -Zmiri-disable-stacked-borrows -Zmiri-allow-ptr-int-transmute fn main() { let x: i32 = 3; diff --git a/tests/compile-fail/provenance/ptr_invalid.rs b/tests/compile-fail/provenance/ptr_invalid.rs index b371103e6b66..f4f3ed5afa5c 100644 --- a/tests/compile-fail/provenance/ptr_invalid.rs +++ b/tests/compile-fail/provenance/ptr_invalid.rs @@ -1,4 +1,3 @@ -// compile-flags: -Zmiri-permissive-provenance #![feature(strict_provenance)] // Ensure that a `ptr::invalid` ptr is truly invalid. diff --git a/tests/compile-fail/stacked_borrows/illegal_read3.rs b/tests/compile-fail/stacked_borrows/illegal_read3.rs index 09fd5d534cf7..672c200861c6 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read3.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read3.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-allow-ptr-int-transmute // A callee may not read the destination of our `&mut` without us noticing. // Thise code got carefully checked to not introduce any reborrows // that are not explicit in the source. Let's hope the compiler does not break this later! diff --git a/tests/compile-fail/transmute-pair-uninit.rs b/tests/compile-fail/transmute-pair-uninit.rs index 42aa7a969278..18c80ac42ac8 100644 --- a/tests/compile-fail/transmute-pair-uninit.rs +++ b/tests/compile-fail/transmute-pair-uninit.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-allow-uninit-numbers #![feature(core_intrinsics)] use std::mem; diff --git a/tests/compile-fail/uninit_byte_read.rs b/tests/compile-fail/uninit_byte_read.rs index 36c14137bdc1..9a1f8df94d60 100644 --- a/tests/compile-fail/uninit_byte_read.rs +++ b/tests/compile-fail/uninit_byte_read.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-allow-uninit-numbers fn main() { let v: Vec = Vec::with_capacity(10); let undef = unsafe { *v.get_unchecked(5) }; diff --git a/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs b/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs index ccf97b416c69..c36685ab2f46 100644 --- a/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs +++ b/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-allow-uninit-numbers #![allow(unused, deprecated, invalid_value)] #[derive(Copy, Clone)] diff --git a/tests/compile-fail/validity/ptr_integer_array_transmute.rs b/tests/compile-fail/validity/ptr_integer_array_transmute.rs index 7a1ae2f3c9a1..92c635ff2218 100644 --- a/tests/compile-fail/validity/ptr_integer_array_transmute.rs +++ b/tests/compile-fail/validity/ptr_integer_array_transmute.rs @@ -1,5 +1,3 @@ -// compile-flags: -Zmiri-check-number-validity - fn main() { let r = &mut 42; let _i: [usize; 1] = unsafe { std::mem::transmute(r) }; //~ ERROR encountered a pointer, but expected plain (non-pointer) bytes diff --git a/tests/compile-fail/validity/ptr_integer_transmute.rs b/tests/compile-fail/validity/ptr_integer_transmute.rs index bb9e8e1e220f..b23ccbbb1b03 100644 --- a/tests/compile-fail/validity/ptr_integer_transmute.rs +++ b/tests/compile-fail/validity/ptr_integer_transmute.rs @@ -1,5 +1,3 @@ -// compile-flags: -Zmiri-check-number-validity - fn main() { let r = &mut 42; let _i: usize = unsafe { std::mem::transmute(r) }; //~ ERROR expected plain (non-pointer) bytes diff --git a/tests/compile-fail/validity/uninit_float.rs b/tests/compile-fail/validity/uninit_float.rs index 1cb687f9b008..e79cbb45f984 100644 --- a/tests/compile-fail/validity/uninit_float.rs +++ b/tests/compile-fail/validity/uninit_float.rs @@ -1,5 +1,3 @@ -// compile-flags: -Zmiri-check-number-validity - // This test is adapted from https://github.com/rust-lang/miri/issues/1340#issue-600900312. fn main() { diff --git a/tests/compile-fail/validity/uninit_integer.rs b/tests/compile-fail/validity/uninit_integer.rs index c700f1f46d99..bfa25d6ef356 100644 --- a/tests/compile-fail/validity/uninit_integer.rs +++ b/tests/compile-fail/validity/uninit_integer.rs @@ -1,5 +1,3 @@ -// compile-flags: -Zmiri-check-number-validity - // This test is from https://github.com/rust-lang/miri/issues/1340#issue-600900312. fn main() { diff --git a/tests/compile-fail/validity/uninit_integer_signed.rs b/tests/compile-fail/validity/uninit_integer_signed.rs index 28bca0b19a78..1764120805c4 100644 --- a/tests/compile-fail/validity/uninit_integer_signed.rs +++ b/tests/compile-fail/validity/uninit_integer_signed.rs @@ -1,5 +1,3 @@ -// compile-flags: -Zmiri-check-number-validity - // This test is adapted from https://github.com/rust-lang/miri/issues/1340#issue-600900312. fn main() { diff --git a/tests/run-pass/bitop-beyond-alignment.rs b/tests/run-pass/bitop-beyond-alignment.rs deleted file mode 100644 index e540a2a4b723..000000000000 --- a/tests/run-pass/bitop-beyond-alignment.rs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::mem; - -enum Tag { - Tag2(A) -} - -#[allow(dead_code)] -struct Rec { - c8: u8, - t: Tag -} - -fn mk_rec() -> Rec { - return Rec { c8:0, t:Tag::Tag2(0) }; -} - -fn is_u64_aligned(u: &Tag) -> bool { - let p: usize = unsafe { mem::transmute(u) }; - let u64_align = std::mem::align_of::(); - return (p & (u64_align + 1)) == 0; -} - -pub fn main() { - let x = mk_rec(); - is_u64_aligned(&x.t); // the result of this is non-deterministic (even with a fixed seed, results vary between targets) -} diff --git a/tests/run-pass/concurrency/libc_pthread_cond.rs b/tests/run-pass/concurrency/libc_pthread_cond.rs index 631675aaaf54..1f6f46cbeb51 100644 --- a/tests/run-pass/concurrency/libc_pthread_cond.rs +++ b/tests/run-pass/concurrency/libc_pthread_cond.rs @@ -1,6 +1,6 @@ // ignore-windows: No libc on Windows // ignore-apple: pthread_condattr_setclock is not supported on MacOS. -// compile-flags: -Zmiri-disable-isolation -Zmiri-check-number-validity +// compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] diff --git a/tests/run-pass/intptrcast.rs b/tests/run-pass/intptrcast.rs index 6e72d30d4123..573bdbae704a 100644 --- a/tests/run-pass/intptrcast.rs +++ b/tests/run-pass/intptrcast.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-allow-ptr-int-transmute + // This returns a miri pointer at type usize, if the argument is a proper pointer fn transmute_ptr_to_int(x: *const T) -> usize { unsafe { std::mem::transmute(x) } diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index ab9a690fe1d7..fd3625639bfd 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -197,17 +197,17 @@ fn test_prctl_thread_name() { use libc::c_long; unsafe { let mut buf = [255; 10]; - assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr() as c_long, 0 as c_long, 0 as c_long, 0 as c_long), 0); + assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), 0); assert_eq!(b"\0", &buf); let thread_name = CString::new("hello").expect("CString::new failed"); - assert_eq!(libc::prctl(libc::PR_SET_NAME, thread_name.as_ptr() as c_long, 0 as c_long, 0 as c_long, 0 as c_long), 0); + assert_eq!(libc::prctl(libc::PR_SET_NAME, thread_name.as_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), 0); let mut buf = [255; 6]; - assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr() as c_long, 0 as c_long, 0 as c_long, 0 as c_long), 0); + assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), 0); assert_eq!(b"hello\0", &buf); let long_thread_name = CString::new("01234567890123456789").expect("CString::new failed"); - assert_eq!(libc::prctl(libc::PR_SET_NAME, long_thread_name.as_ptr() as c_long, 0 as c_long, 0 as c_long, 0 as c_long), 0); + assert_eq!(libc::prctl(libc::PR_SET_NAME, long_thread_name.as_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), 0); let mut buf = [255; 16]; - assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr() as c_long, 0 as c_long, 0 as c_long, 0 as c_long), 0); + assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), 0); assert_eq!(b"012345678901234\0", &buf); } } diff --git a/tests/run-pass/move-uninit-primval.rs b/tests/run-pass/move-uninit-primval.rs index b8bd869b48c9..0edc3c9e6cd8 100644 --- a/tests/run-pass/move-uninit-primval.rs +++ b/tests/run-pass/move-uninit-primval.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-allow-uninit-numbers #![allow(deprecated)] struct Foo { diff --git a/tests/run-pass/partially-uninit.rs b/tests/run-pass/partially-uninit.rs index 1de530842827..5ee9abbcb95b 100644 --- a/tests/run-pass/partially-uninit.rs +++ b/tests/run-pass/partially-uninit.rs @@ -1,5 +1,3 @@ -// compile-flags: -Zmiri-check-number-validity - use std::mem::{self, MaybeUninit}; #[repr(C)] diff --git a/tests/run-pass/ptr_offset.rs b/tests/run-pass/ptr_offset.rs index 6af3e28854ab..4c6341813f5b 100644 --- a/tests/run-pass/ptr_offset.rs +++ b/tests/run-pass/ptr_offset.rs @@ -61,7 +61,9 @@ fn ptr_offset() { unsafe { let p = f as fn() -> i32 as usize; let x = (p as *mut u32).offset(0) as usize; - let f: fn() -> i32 = mem::transmute(x); + // *cast* to ptr, then transmute to fn ptr. + // (transmuting int to [fn]ptr causes trouble.) + let f: fn() -> i32 = mem::transmute(x as *const ()); assert_eq!(f(), 42); } } diff --git a/tests/run-pass/tag-align-dyn-u64.rs b/tests/run-pass/tag-align-dyn-u64.rs index 8a97758fbb59..460c2b25594a 100644 --- a/tests/run-pass/tag-align-dyn-u64.rs +++ b/tests/run-pass/tag-align-dyn-u64.rs @@ -25,7 +25,8 @@ fn mk_rec() -> Rec { } fn is_u64_aligned(u: &Tag) -> bool { - let p: usize = unsafe { mem::transmute(u) }; + let p: *const () = unsafe { mem::transmute(u) }; + let p = p as usize; let u64_align = std::mem::align_of::(); return (p & (u64_align - 1)) == 0; } diff --git a/tests/run-pass/transmute_fat.rs b/tests/run-pass/transmute_fat.rs index 238122de8d4c..8a6e15031cb4 100644 --- a/tests/run-pass/transmute_fat.rs +++ b/tests/run-pass/transmute_fat.rs @@ -1,5 +1,5 @@ // Stacked Borrows disallows this becuase the reference is never cast to a raw pointer. -// compile-flags: -Zmiri-disable-stacked-borrows +// compile-flags: -Zmiri-disable-stacked-borrows -Zmiri-allow-ptr-int-transmute fn main() { // If we are careful, we can exploit data layout... @@ -7,7 +7,8 @@ fn main() { std::mem::transmute::<&[u8], [usize; 2]>(&[42]) }; let ptr = raw[0] + raw[1]; - let ptr = ptr as *const u8; + // We transmute both ways, to really test allow-ptr-int-transmute. + let ptr: *const u8 = unsafe { std::mem::transmute(ptr) }; // The pointer is one-past-the end, but we decrement it into bounds before using it assert_eq!(unsafe { *ptr.offset(-1) }, 42); } diff --git a/tests/run-pass/uninit_number_ignored.rs b/tests/run-pass/uninit_number_ignored.rs index 77d6af6e99cf..13aac61ba84c 100644 --- a/tests/run-pass/uninit_number_ignored.rs +++ b/tests/run-pass/uninit_number_ignored.rs @@ -1,5 +1,5 @@ +// compile-flags: -Zmiri-allow-uninit-numbers // This test is adapted from https://github.com/rust-lang/miri/issues/1340#issue-600900312. -// This test passes because -Zmiri-check-number-validity is not passed. fn main() { let _val1 = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; From a6b5b0e4ff911c5e36e544fc2aed80e8d4ed912b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 25 May 2022 18:12:54 +0200 Subject: [PATCH 3109/5092] tweak new test suite output --- tests/compiletest.rs | 12 +++++------- ui_test/src/lib.rs | 24 +++++++++++++----------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 92a8bd6291e2..9ffc4744eb85 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -109,13 +109,11 @@ regexes! { fn ui(mode: Mode, path: &str) { let target = get_target(); - eprint!("{}", format!("## Running ui tests in {path} against miri for ").green().bold()); - - if let Some(target) = &target { - eprintln!("{target}"); - } else { - eprintln!("host"); - } + let msg = format!( + "## Running ui tests in {path} against miri for {}", + target.as_deref().unwrap_or("host") + ); + eprintln!("{}", msg.green().bold()); run_tests(mode, path, target); } diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 95ae3a51b235..b779d6844a97 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -56,7 +56,7 @@ pub fn run_tests(config: Config) { // Some statistics and failure reports. let failures = Mutex::new(vec![]); let succeeded = AtomicUsize::default(); - let skipped = AtomicUsize::default(); + let ignored = AtomicUsize::default(); crossbeam::scope(|s| { for _ in 0..std::thread::available_parallelism().unwrap().get() { @@ -74,10 +74,10 @@ pub fn run_tests(config: Config) { continue; } let comments = Comments::parse(&path); - // Skip file if only/skip rules do (not) apply + // Ignore file if only/ignore rules do (not) apply if ignore_file(&comments, &target) { - skipped.fetch_add(1, Ordering::Relaxed); - eprintln!("{} .. {}", path.display(), "skipped".yellow()); + ignored.fetch_add(1, Ordering::Relaxed); + eprintln!("{} .. {}", path.display(), "ignored".yellow()); continue; } // Run the test for all revisions @@ -91,7 +91,7 @@ pub fn run_tests(config: Config) { if !revision.is_empty() { write!(msg, "(revision `{revision}`) ").unwrap(); } - write!(msg, " .. ").unwrap(); + write!(msg, "... ").unwrap(); if errors.is_empty() { eprintln!("{msg}{}", "ok".green()); succeeded.fetch_add(1, Ordering::Relaxed); @@ -109,7 +109,7 @@ pub fn run_tests(config: Config) { // Print all errors in a single thread to show reliable output let failures = failures.into_inner().unwrap(); let succeeded = succeeded.load(Ordering::Relaxed); - let skipped = skipped.load(Ordering::Relaxed); + let ignored = ignored.load(Ordering::Relaxed); if !failures.is_empty() { for (path, miri, revision, errors) in &failures { eprintln!(); @@ -117,7 +117,7 @@ pub fn run_tests(config: Config) { if !revision.is_empty() { eprint!(" (revision `{}`)", revision); } - eprint!("{}", " FAILED".red()); + eprint!(" {}", "FAILED".red()); eprintln!(); eprintln!("command: {:?}", miri); eprintln!(); @@ -153,19 +153,21 @@ pub fn run_tests(config: Config) { } } eprintln!( - "{} tests failed, {} tests passed, {} skipped", + "{} tests failed, {} tests passed, {} ignored", failures.len().to_string().red().bold(), succeeded.to_string().green(), - skipped.to_string().yellow() + ignored.to_string().yellow() ); std::process::exit(1); } eprintln!(); eprintln!( - "{} tests passed, {} skipped", + "test result: {}. {} tests passed, {} ignored", + "ok".green(), succeeded.to_string().green(), - skipped.to_string().yellow() + ignored.to_string().yellow() ); + eprintln!(); } #[derive(Debug)] From 23bbe2bce72c4674ef46507a2db1e4e5e55ff3ff Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 25 May 2022 16:08:41 +0000 Subject: [PATCH 3110/5092] Reproduce #2156 --- ui_test/.gitignore | 1 + ui_test/src/comments.rs | 11 +++++-- ui_test/src/lib.rs | 10 +++--- ui_test/tests/check_annotations.rs | 49 ++++++++++++++++++++++++++++++ ui_test/tests/comment_parser.rs | 22 ++++++++++++++ 5 files changed, 85 insertions(+), 8 deletions(-) create mode 100644 ui_test/.gitignore create mode 100644 ui_test/tests/check_annotations.rs create mode 100644 ui_test/tests/comment_parser.rs diff --git a/ui_test/.gitignore b/ui_test/.gitignore new file mode 100644 index 000000000000..03314f77b5aa --- /dev/null +++ b/ui_test/.gitignore @@ -0,0 +1 @@ +Cargo.lock diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 14566d2feccf..193cda68b9aa 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -5,7 +5,7 @@ use regex::Regex; /// This crate supports various magic comments that get parsed as file-specific /// configuration values. This struct parses them all in one go and then they /// get processed by their respective use sites. -#[derive(Default)] +#[derive(Default, Debug)] pub struct Comments { /// List of revision names to execute. Can only be speicified once pub revisions: Option>, @@ -26,6 +26,7 @@ pub struct Comments { pub error_matches: Vec, } +#[derive(Debug)] pub struct ErrorMatch { pub matched: String, pub revision: Option, @@ -33,9 +34,13 @@ pub struct ErrorMatch { } impl Comments { - pub fn parse(path: &Path) -> Self { - let mut this = Self::default(); + pub fn parse_file(path: &Path) -> Self { let content = std::fs::read_to_string(path).unwrap(); + Self::parse(path, &content) + } + + pub fn parse(path: &Path, content: &str) -> Self { + let mut this = Self::default(); let error_pattern_regex = Regex::new(r"//(\[(?P[^\]]+)\])?~[|^]*\s*(ERROR|HELP|WARN)?:?(?P.*)") .unwrap(); diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index b779d6844a97..4f7e55fdce8d 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -9,7 +9,7 @@ use comments::ErrorMatch; use crossbeam::queue::SegQueue; use regex::Regex; -use crate::comments::Comments; +pub use crate::comments::Comments; mod comments; @@ -73,7 +73,7 @@ pub fn run_tests(config: Config) { if !path.extension().map(|ext| ext == "rs").unwrap_or(false) { continue; } - let comments = Comments::parse(&path); + let comments = Comments::parse_file(&path); // Ignore file if only/ignore rules do (not) apply if ignore_file(&comments, &target) { ignored.fetch_add(1, Ordering::Relaxed); @@ -171,7 +171,7 @@ pub fn run_tests(config: Config) { } #[derive(Debug)] -enum Error { +pub enum Error { /// Got an invalid exit status for the given mode. ExitStatus(Mode, ExitStatus), PatternNotFound { @@ -191,7 +191,7 @@ enum Error { }, } -type Errors = Vec; +pub type Errors = Vec; fn run_test( path: &Path, @@ -249,7 +249,7 @@ fn run_test( (miri, errors) } -fn check_annotations( +pub fn check_annotations( unnormalized_stderr: &[u8], errors: &mut Errors, config: &Config, diff --git a/ui_test/tests/check_annotations.rs b/ui_test/tests/check_annotations.rs new file mode 100644 index 000000000000..4735fe1fa049 --- /dev/null +++ b/ui_test/tests/check_annotations.rs @@ -0,0 +1,49 @@ +use std::path::{Path, PathBuf}; + +use ui_test::{check_annotations, Comments, Config, Error, Mode, OutputConflictHandling}; + +fn config() -> Config { + Config { + args: vec![], + target: None, + stderr_filters: vec![], + stdout_filters: vec![], + root_dir: PathBuf::from("."), + mode: Mode::Fail, + program: PathBuf::from("cake"), + output_conflict_handling: OutputConflictHandling::Error, + } +} + +#[test] +fn issue_2156() { + let s = r" +use std::mem; + +fn main() { + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address $HEX is unallocated) +} + "; + let comments = Comments::parse(Path::new(""), s); + let mut errors = vec![]; + let config = config(); + let unnormalized_stderr = r" +error: Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated) + --> tests/compile-fail/validity/dangling_ref1.rs:6:29 + | +LL | let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address $HEX is unallocated) + | ^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (address 0x10 is unallocated) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at tests/compile-fail/validity/dangling_ref1.rs:6:29 +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace +error: aborting due to previous error + "; + check_annotations(unnormalized_stderr.as_bytes(), &mut errors, &config, "", &comments); + match &errors[..] { + [Error::PatternNotFound { .. }] => {} + _ => panic!("{:#?}", errors), + } +} diff --git a/ui_test/tests/comment_parser.rs b/ui_test/tests/comment_parser.rs new file mode 100644 index 000000000000..ee1382a6c788 --- /dev/null +++ b/ui_test/tests/comment_parser.rs @@ -0,0 +1,22 @@ +use std::path::Path; + +use ui_test::Comments; + +#[test] +fn issue_2156() { + let s = r" +use std::mem; + +fn main() { + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address $HEX is unallocated) +} + "; + let comments = Comments::parse(Path::new(""), s); + println!("{:#?}", comments); + assert_eq!(comments.error_matches[0].definition_line, 4); + assert_eq!(comments.error_matches[0].revision, None); + assert_eq!( + comments.error_matches[0].matched, + "encountered a dangling reference (address $HEX is unallocated)" + ); +} From 21795f3ce4eabfce2fd5d36e0d9852bde9d52158 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 25 May 2022 16:11:37 +0000 Subject: [PATCH 3111/5092] Fix annotations matching themselves --- ui_test/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 4f7e55fdce8d..f657be4ea65c 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -257,6 +257,9 @@ pub fn check_annotations( comments: &Comments, ) { let unnormalized_stderr = std::str::from_utf8(unnormalized_stderr).unwrap(); + // erase annotations from the stderr so they don't match themselves + let annotations = Regex::new(r"\s*//~.*").unwrap(); + let unnormalized_stderr = annotations.replace(unnormalized_stderr, ""); let mut found_annotation = false; if let Some((ref error_pattern, definition_line)) = comments.error_pattern { if !unnormalized_stderr.contains(error_pattern) { From b64a1c46c67c58e2da05c67ef1b2d73dd756549c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 25 May 2022 16:15:31 +0000 Subject: [PATCH 3112/5092] Make the file path of the failure more visible to be able to click it faster --- ui_test/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index f657be4ea65c..ba1f874413d8 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -129,7 +129,7 @@ pub fn run_tests(config: Config) { eprintln!("`{pattern}` {} in stderr output", "not found".red()); eprintln!( "expected because of pattern here: {}:{definition_line}", - path.display() + path.display().to_string().bold() ); dump_stderr = Some(stderr.clone()) } From 8acfbc3b3332ed7f5364bc38c947c6c083ef99df Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 25 May 2022 16:15:37 +0000 Subject: [PATCH 3113/5092] Update all tests --- tests/compile-fail/intrinsics/copy_unaligned.rs | 2 +- .../compile-fail/stacked_borrows/static_memory_modification.rs | 2 +- tests/compile-fail/unaligned_pointers/dyn_alignment.rs | 2 +- .../unaligned_pointers/intptrcast_alignment_check.rs | 2 +- tests/compile-fail/unaligned_pointers/reference_to_packed.rs | 2 +- tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs | 2 +- tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs | 2 +- tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs | 2 +- tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs | 2 +- tests/compile-fail/validity/dangling_ref1.rs | 2 +- tests/compile-fail/validity/invalid_char.rs | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/compile-fail/intrinsics/copy_unaligned.rs b/tests/compile-fail/intrinsics/copy_unaligned.rs index 7aff0adc407a..84f4de93461e 100644 --- a/tests/compile-fail/intrinsics/copy_unaligned.rs +++ b/tests/compile-fail/intrinsics/copy_unaligned.rs @@ -9,5 +9,5 @@ fn main() { let mut data = [0u16; 8]; let ptr = (&mut data[0] as *mut u16 as *mut u8).wrapping_add(1) as *mut u16; // Even copying 0 elements to something unaligned should error - unsafe { copy_nonoverlapping(&data[5], ptr, 0); } //~ ERROR accessing memory with alignment ALIGN, but alignment ALIGN is required + unsafe { copy_nonoverlapping(&data[5], ptr, 0); } //~ ERROR accessing memory with alignment 1, but alignment 2 is required } diff --git a/tests/compile-fail/stacked_borrows/static_memory_modification.rs b/tests/compile-fail/stacked_borrows/static_memory_modification.rs index 72e2ed938124..417a03bb0335 100644 --- a/tests/compile-fail/stacked_borrows/static_memory_modification.rs +++ b/tests/compile-fail/stacked_borrows/static_memory_modification.rs @@ -3,6 +3,6 @@ static X: usize = 5; #[allow(mutable_transmutes)] fn main() { let _x = unsafe { - std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR writing to ALLOC which is read-only + std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR writing to alloc1 which is read-only }; } diff --git a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs index 9d8829fe1ee0..91d9ec475b1f 100644 --- a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs +++ b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs @@ -16,6 +16,6 @@ fn main() { // Overwrite the data part of `ptr` so it points to `buf`. unsafe { (&mut ptr as *mut _ as *mut *const u8).write(&buf as *const _ as *const u8); } // Re-borrow that. This should be UB. - let _ptr = &*ptr; //~ERROR alignment ALIGN is required + let _ptr = &*ptr; //~ERROR alignment 256 is required } } diff --git a/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs b/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs index a8d0b5afbb89..9872a493c02a 100644 --- a/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs +++ b/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs @@ -12,6 +12,6 @@ fn main() { // Manually make sure the pointer is properly aligned. let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr+1 }; let u16_ptr = base_addr_aligned as *mut u16; - unsafe { *u16_ptr = 2; } //~ERROR memory with alignment ALIGN, but alignment ALIGN is required + unsafe { *u16_ptr = 2; } //~ERROR memory with alignment 1, but alignment 2 is required println!("{:?}", x); } diff --git a/tests/compile-fail/unaligned_pointers/reference_to_packed.rs b/tests/compile-fail/unaligned_pointers/reference_to_packed.rs index 60d2524040a2..b376859d22c1 100644 --- a/tests/compile-fail/unaligned_pointers/reference_to_packed.rs +++ b/tests/compile-fail/unaligned_pointers/reference_to_packed.rs @@ -16,6 +16,6 @@ fn main() { y: 99, }; let p = &foo.x; - let i = *p; //~ERROR alignment ALIGN is required + let i = *p; //~ERROR alignment 4 is required } } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs index fe46e7b8addb..1d72e5170b7c 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs @@ -6,6 +6,6 @@ fn main() { let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. - let _x = unsafe { *x }; //~ERROR memory with alignment ALIGN, but alignment ALIGN is required + let _x = unsafe { *x }; //~ERROR memory with alignment 2, but alignment 4 is required } } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs index 1d1e7fad05c9..49612e2b8a09 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs @@ -8,5 +8,5 @@ fn main() { let x = (x.as_ptr() as *const u8).wrapping_offset(3) as *const u32; // This must fail because alignment is violated: the offset is not sufficiently aligned. // Also make the offset not a power of 2, that used to ICE. - let _x = unsafe { *x }; //~ERROR memory with alignment ALIGN, but alignment ALIGN is required + let _x = unsafe { *x }; //~ERROR memory with alignment 1, but alignment 4 is required } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs index d97306b3cb81..e33f3c8598f3 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs @@ -8,6 +8,6 @@ fn main() { let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. // The deref is UB even if we just put the result into a raw pointer. - let _x = unsafe { ptr::addr_of!(*x) }; //~ ERROR memory with alignment ALIGN, but alignment ALIGN is required + let _x = unsafe { ptr::addr_of!(*x) }; //~ ERROR memory with alignment 2, but alignment 4 is required } } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs index c549688c262e..27403c11abc7 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs @@ -7,6 +7,6 @@ fn main() { let x = i as u8; let x = &x as *const _ as *const [u32; 0]; // This must fail because alignment is violated. Test specifically for loading ZST. - let _x = unsafe { *x }; //~ERROR alignment ALIGN is required + let _x = unsafe { *x }; //~ERROR alignment 4 is required } } diff --git a/tests/compile-fail/validity/dangling_ref1.rs b/tests/compile-fail/validity/dangling_ref1.rs index 3243eee06eb6..78425cde4a8a 100644 --- a/tests/compile-fail/validity/dangling_ref1.rs +++ b/tests/compile-fail/validity/dangling_ref1.rs @@ -3,5 +3,5 @@ use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address $HEX is unallocated) + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) } diff --git a/tests/compile-fail/validity/invalid_char.rs b/tests/compile-fail/validity/invalid_char.rs index d9a55f241c00..079823f894a8 100644 --- a/tests/compile-fail/validity/invalid_char.rs +++ b/tests/compile-fail/validity/invalid_char.rs @@ -1,6 +1,6 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); - let _val = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered $HEX, but expected a valid unicode scalar value + let _val = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered 0xffffffff, but expected a valid unicode scalar value 'a' => {true}, 'b' => {false}, _ => {true}, From e4d6c00aa2cc1ad794f57cdae4eeee9878f14f0a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 25 May 2022 17:48:03 +0000 Subject: [PATCH 3114/5092] Run tests for ui_test together with miri test --- miri | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/miri b/miri index 6a809b74356a..3846eb795a4f 100755 --- a/miri +++ b/miri @@ -134,7 +134,8 @@ test|test-debug|bless|bless-debug) esac # Then test, and let caller control flags. # Only in root project as `cargo-miri` has no tests. - exec cargo test $CARGO_BUILD_FLAGS "$@" + cargo test $CARGO_BUILD_FLAGS "$@" + cargo test --manifest-path ui_test/Cargo.toml ;; run|run-debug) # Scan for "--target" to set the "MIRI_TEST_TARGET" env var so From d466eb8f664a4436e5913a387fc26446f161c22a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 25 May 2022 17:53:39 +0000 Subject: [PATCH 3115/5092] Explain `Comments::parse` arguments --- ui_test/src/comments.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 193cda68b9aa..64f999f54101 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -39,6 +39,8 @@ impl Comments { Self::parse(path, &content) } + /// Parse comments in `content`. + /// `path` is only used to emit diagnostics if parsing fails. pub fn parse(path: &Path, content: &str) -> Self { let mut this = Self::default(); let error_pattern_regex = From 25b7a12625f65229b924adb9f4a9b431da873ed1 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 25 May 2022 17:58:45 +0000 Subject: [PATCH 3116/5092] Properly name a test --- ui_test/tests/comment_parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui_test/tests/comment_parser.rs b/ui_test/tests/comment_parser.rs index ee1382a6c788..a9e19cbb9c5a 100644 --- a/ui_test/tests/comment_parser.rs +++ b/ui_test/tests/comment_parser.rs @@ -3,7 +3,7 @@ use std::path::Path; use ui_test::Comments; #[test] -fn issue_2156() { +fn parse_simple_comment() { let s = r" use std::mem; From a51ae9fb2c9bbfa6abb5eafb66d393afd00933e7 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 25 May 2022 18:24:55 +0000 Subject: [PATCH 3117/5092] Use unit tests to keep private things private --- ui_test/src/comments.rs | 3 +++ .../{tests/comment_parser.rs => src/comments/tests.rs} | 2 +- ui_test/src/lib.rs | 8 +++++--- ui_test/{tests/check_annotations.rs => src/tests.rs} | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) rename ui_test/{tests/comment_parser.rs => src/comments/tests.rs} (96%) rename ui_test/{tests/check_annotations.rs => src/tests.rs} (95%) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 64f999f54101..e83e84b22a14 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -2,6 +2,9 @@ use std::path::Path; use regex::Regex; +#[cfg(test)] +mod tests; + /// This crate supports various magic comments that get parsed as file-specific /// configuration values. This struct parses them all in one go and then they /// get processed by their respective use sites. diff --git a/ui_test/tests/comment_parser.rs b/ui_test/src/comments/tests.rs similarity index 96% rename from ui_test/tests/comment_parser.rs rename to ui_test/src/comments/tests.rs index a9e19cbb9c5a..2bcaaa70a429 100644 --- a/ui_test/tests/comment_parser.rs +++ b/ui_test/src/comments/tests.rs @@ -1,6 +1,6 @@ use std::path::Path; -use ui_test::Comments; +use super::Comments; #[test] fn parse_simple_comment() { diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index ba1f874413d8..4a3014713b2a 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -12,6 +12,8 @@ use regex::Regex; pub use crate::comments::Comments; mod comments; +#[cfg(test)] +mod tests; #[derive(Debug)] pub struct Config { @@ -171,7 +173,7 @@ pub fn run_tests(config: Config) { } #[derive(Debug)] -pub enum Error { +enum Error { /// Got an invalid exit status for the given mode. ExitStatus(Mode, ExitStatus), PatternNotFound { @@ -191,7 +193,7 @@ pub enum Error { }, } -pub type Errors = Vec; +type Errors = Vec; fn run_test( path: &Path, @@ -249,7 +251,7 @@ fn run_test( (miri, errors) } -pub fn check_annotations( +fn check_annotations( unnormalized_stderr: &[u8], errors: &mut Errors, config: &Config, diff --git a/ui_test/tests/check_annotations.rs b/ui_test/src/tests.rs similarity index 95% rename from ui_test/tests/check_annotations.rs rename to ui_test/src/tests.rs index 4735fe1fa049..841f790b95b5 100644 --- a/ui_test/tests/check_annotations.rs +++ b/ui_test/src/tests.rs @@ -1,6 +1,6 @@ use std::path::{Path, PathBuf}; -use ui_test::{check_annotations, Comments, Config, Error, Mode, OutputConflictHandling}; +use super::{check_annotations, Comments, Config, Error, Mode, OutputConflictHandling}; fn config() -> Config { Config { From 6b18cf0e20607cda3716be299965f202898d1437 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 25 May 2022 18:25:45 +0000 Subject: [PATCH 3118/5092] Self-descriptive verbosity --- ui_test/src/comments/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui_test/src/comments/tests.rs b/ui_test/src/comments/tests.rs index 2bcaaa70a429..0140fdf4a9c6 100644 --- a/ui_test/src/comments/tests.rs +++ b/ui_test/src/comments/tests.rs @@ -12,7 +12,7 @@ fn main() { } "; let comments = Comments::parse(Path::new(""), s); - println!("{:#?}", comments); + println!("parsed comments: {:#?}", comments); assert_eq!(comments.error_matches[0].definition_line, 4); assert_eq!(comments.error_matches[0].revision, None); assert_eq!( From 10e06be15a3524e30eb1b8c896b748c0e94b74ff Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 27 May 2022 11:35:26 +0000 Subject: [PATCH 3119/5092] Don't export private things --- ui_test/src/comments.rs | 8 ++++---- ui_test/src/lib.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index e83e84b22a14..e6e45de4160e 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -9,7 +9,7 @@ mod tests; /// configuration values. This struct parses them all in one go and then they /// get processed by their respective use sites. #[derive(Default, Debug)] -pub struct Comments { +pub(crate) struct Comments { /// List of revision names to execute. Can only be speicified once pub revisions: Option>, /// Don't run this test if any of these filters apply @@ -30,21 +30,21 @@ pub struct Comments { } #[derive(Debug)] -pub struct ErrorMatch { +pub(crate) struct ErrorMatch { pub matched: String, pub revision: Option, pub definition_line: usize, } impl Comments { - pub fn parse_file(path: &Path) -> Self { + pub(crate) fn parse_file(path: &Path) -> Self { let content = std::fs::read_to_string(path).unwrap(); Self::parse(path, &content) } /// Parse comments in `content`. /// `path` is only used to emit diagnostics if parsing fails. - pub fn parse(path: &Path, content: &str) -> Self { + pub(crate) fn parse(path: &Path, content: &str) -> Self { let mut this = Self::default(); let error_pattern_regex = Regex::new(r"//(\[(?P[^\]]+)\])?~[|^]*\s*(ERROR|HELP|WARN)?:?(?P.*)") diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 4a3014713b2a..dd5a1d062434 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -9,7 +9,7 @@ use comments::ErrorMatch; use crossbeam::queue::SegQueue; use regex::Regex; -pub use crate::comments::Comments; +use crate::comments::Comments; mod comments; #[cfg(test)] From 1b7e278922267792a8a99067e7e9d387f45c0e3f Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 27 May 2022 11:43:14 +0000 Subject: [PATCH 3120/5092] Reintroduce path filters --- miri | 4 ++-- tests/compiletest.rs | 3 +++ ui_test/src/lib.rs | 13 +++++++++++++ ui_test/src/tests.rs | 1 + 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/miri b/miri index 3846eb795a4f..9c4eeb527580 100755 --- a/miri +++ b/miri @@ -133,9 +133,9 @@ test|test-debug|bless|bless-debug) ;; esac # Then test, and let caller control flags. - # Only in root project as `cargo-miri` has no tests. + # Only in root project and ui_test as `cargo-miri` has no tests. cargo test $CARGO_BUILD_FLAGS "$@" - cargo test --manifest-path ui_test/Cargo.toml + cargo test --manifest-path ui_test/Cargo.toml "$@" ;; run|run-debug) # Scan for "--target" to set the "MIRI_TEST_TARGET" env var so diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 9ffc4744eb85..4be658e86cba 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -47,6 +47,8 @@ fn run_tests(mode: Mode, path: &str, target: Option) { (true, true) => panic!("cannot use MIRI_BLESS and MIRI_SKIP_UI_CHECKS at the same time"), }; + let path_filter = std::env::args().skip(1).next(); + let config = Config { args: flags, target, @@ -54,6 +56,7 @@ fn run_tests(mode: Mode, path: &str, target: Option) { stdout_filters: STDOUT.clone(), root_dir: PathBuf::from(path), mode, + path_filter, program: miri_path(), output_conflict_handling, }; diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index dd5a1d062434..81560db6dff7 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -30,6 +30,8 @@ pub struct Config { pub mode: Mode, pub program: PathBuf, pub output_conflict_handling: OutputConflictHandling, + /// Only run tests with this string in their path/name + pub path_filter: Option, } #[derive(Debug)] @@ -75,6 +77,17 @@ pub fn run_tests(config: Config) { if !path.extension().map(|ext| ext == "rs").unwrap_or(false) { continue; } + if let Some(path_filter) = &config.path_filter { + if !path.display().to_string().contains(path_filter) { + ignored.fetch_add(1, Ordering::Relaxed); + eprintln!( + "{} .. {}", + path.display(), + "ignored (command line filter)".yellow() + ); + continue; + } + } let comments = Comments::parse_file(&path); // Ignore file if only/ignore rules do (not) apply if ignore_file(&comments, &target) { diff --git a/ui_test/src/tests.rs b/ui_test/src/tests.rs index 841f790b95b5..5485e6b4f26b 100644 --- a/ui_test/src/tests.rs +++ b/ui_test/src/tests.rs @@ -10,6 +10,7 @@ fn config() -> Config { stdout_filters: vec![], root_dir: PathBuf::from("."), mode: Mode::Fail, + path_filter: None, program: PathBuf::from("cake"), output_conflict_handling: OutputConflictHandling::Error, } From 740574206b1a9d494ec8cff4fc37621944e472f5 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 27 May 2022 14:24:38 +0000 Subject: [PATCH 3121/5092] Commit our ui test crate's cargo lockfile --- ui_test/.gitignore | 1 - ui_test/Cargo.lock | 304 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 304 insertions(+), 1 deletion(-) delete mode 100644 ui_test/.gitignore create mode 100644 ui_test/Cargo.lock diff --git a/ui_test/.gitignore b/ui_test/.gitignore deleted file mode 100644 index 03314f77b5aa..000000000000 --- a/ui_test/.gitignore +++ /dev/null @@ -1 +0,0 @@ -Cargo.lock diff --git a/ui_test/Cargo.lock b/ui_test/Cargo.lock new file mode 100644 index 000000000000..185af43ac0b4 --- /dev/null +++ b/ui_test/Cargo.lock @@ -0,0 +1,304 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "colored" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +dependencies = [ + "atty", + "lazy_static", + "winapi", +] + +[[package]] +name = "crossbeam" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae5588f6b3c3cb05239e90bd110f257254aecd01e4635400391aeae07497845" +dependencies = [ + "cfg-if", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +dependencies = [ + "cfg-if", + "lazy_static", +] + +[[package]] +name = "ctor" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "diff" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "output_vt100" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" +dependencies = [ + "winapi", +] + +[[package]] +name = "pretty_assertions" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89f989ac94207d048d92db058e4f6ec7342b0971fc58d1271ca148b799b3563" +dependencies = [ + "ansi_term", + "ctor", + "diff", + "output_vt100", +] + +[[package]] +name = "proc-macro2" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "semver" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" + +[[package]] +name = "syn" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "ui_test" +version = "0.1.0" +dependencies = [ + "colored", + "crossbeam", + "lazy_static", + "pretty_assertions", + "regex", + "rustc_version", +] + +[[package]] +name = "unicode-ident" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" From 12261474140d20f6b07613de7c3a3b4210fd5a2e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 May 2022 18:08:13 +0200 Subject: [PATCH 3122/5092] rustup --- README.md | 4 +++- rust-version | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9248576b3c2a..824a8d3e328a 100644 --- a/README.md +++ b/README.md @@ -262,7 +262,9 @@ environment variable. We first document the most relevant and most commonly used * `-Zmiri-compare-exchange-weak-failure-rate=` changes the failure rate of `compare_exchange_weak` operations. The default is `0.8` (so 4 out of 5 weak ops will fail). You can change it to any value between `0.0` and `1.0`, where `1.0` means it - will always fail and `0.0` means it will never fail. + will always fail and `0.0` means it will never fail. Note than setting it to + `1.0` will likely cause hangs, since it means programs using + `compare_exchange_weak` cannot make progress. * `-Zmiri-disable-isolation` disables host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness. diff --git a/rust-version b/rust-version index f4df767fc22f..0024b676d775 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -b2eba058e6e1c698723e47074561a30b50b5fa7a +68314177e70017c08f6cdf295631bb508f9f85bc From 424841817a47030191cd64f1177e242d8c450983 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 May 2022 08:25:36 +0200 Subject: [PATCH 3123/5092] disable optimized tests for now --- ci.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index d435e0e2a210..bdca26fd0491 100755 --- a/ci.sh +++ b/ci.sh @@ -25,7 +25,9 @@ function run_tests { # Only for host architecture: tests with optimizations (`-O` is what cargo passes, but crank MIR # optimizations up all the way). # Optimizations change diagnostics (mostly backtraces), so we don't check them - MIRIFLAGS="-O -Zmir-opt-level=4" MIRI_SKIP_UI_CHECKS=1 ./miri test --locked + #FIXME(#2155): we want to only run the pass and panic tests here, not the fail tests. + #MIRIFLAGS="-O -Zmir-opt-level=4" MIRI_SKIP_UI_CHECKS=1 ./miri test --locked + true fi # On Windows, there is always "python", not "python3" or "python2". From 7cd5fc3de327b9db96918cc895676f2d94c0a44d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 May 2022 14:06:35 +0200 Subject: [PATCH 3124/5092] rustup --- rust-version | 2 +- src/helpers.rs | 2 +- src/shims/dlsym.rs | 2 +- src/shims/posix/dlsym.rs | 2 +- src/shims/posix/linux/dlsym.rs | 2 +- src/shims/posix/macos/dlsym.rs | 2 +- src/shims/windows/dlsym.rs | 2 +- src/stacked_borrows.rs | 4 ++-- src/stacked_borrows/diagnostics.rs | 8 ++++---- 9 files changed, 13 insertions(+), 13 deletions(-) diff --git a/rust-version b/rust-version index 0024b676d775..8da4cbec7ff2 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -68314177e70017c08f6cdf295631bb508f9f85bc +0f06824013761ed6829887019033f1001e68f623 diff --git a/src/helpers.rs b/src/helpers.rs index 24c471a8b0ba..5a76e15465c4 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -849,7 +849,7 @@ where throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N) } -pub fn isolation_abort_error(name: &str) -> InterpResult<'static> { +pub fn isolation_abort_error<'tcx>(name: &str) -> InterpResult<'tcx> { throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!( "{} not available when isolation is enabled", name, diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index d83a309c3e1f..05296d3a4eb7 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -15,7 +15,7 @@ pub enum Dlsym { impl Dlsym { // Returns an error for unsupported symbols, and None if this symbol // should become a NULL pointer (pretend it does not exist). - pub fn from_str(name: &[u8], target_os: &str) -> InterpResult<'static, Option> { + pub fn from_str<'tcx>(name: &[u8], target_os: &str) -> InterpResult<'tcx, Option> { let name = &*String::from_utf8_lossy(name); Ok(match target_os { "linux" | "macos" => posix::Dlsym::from_str(name, target_os)?.map(Dlsym::Posix), diff --git a/src/shims/posix/dlsym.rs b/src/shims/posix/dlsym.rs index 0ea441e00e9a..339110467c73 100644 --- a/src/shims/posix/dlsym.rs +++ b/src/shims/posix/dlsym.rs @@ -14,7 +14,7 @@ pub enum Dlsym { impl Dlsym { // Returns an error for unsupported symbols, and None if this symbol // should become a NULL pointer (pretend it does not exist). - pub fn from_str(name: &str, target_os: &str) -> InterpResult<'static, Option> { + pub fn from_str<'tcx>(name: &str, target_os: &str) -> InterpResult<'tcx, Option> { Ok(match target_os { "linux" => linux::Dlsym::from_str(name)?.map(Dlsym::Linux), "macos" => macos::Dlsym::from_str(name)?.map(Dlsym::MacOs), diff --git a/src/shims/posix/linux/dlsym.rs b/src/shims/posix/linux/dlsym.rs index a2d6570fe8d6..72e8c7f16f85 100644 --- a/src/shims/posix/linux/dlsym.rs +++ b/src/shims/posix/linux/dlsym.rs @@ -8,7 +8,7 @@ pub enum Dlsym {} impl Dlsym { // Returns an error for unsupported symbols, and None if this symbol // should become a NULL pointer (pretend it does not exist). - pub fn from_str(name: &str) -> InterpResult<'static, Option> { + pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { Ok(match &*name { "__pthread_get_minstack" => None, "getrandom" => None, // std falls back to syscall(SYS_getrandom, ...) when this is NULL. diff --git a/src/shims/posix/macos/dlsym.rs b/src/shims/posix/macos/dlsym.rs index 9369548992e5..2e97b7918e96 100644 --- a/src/shims/posix/macos/dlsym.rs +++ b/src/shims/posix/macos/dlsym.rs @@ -14,7 +14,7 @@ pub enum Dlsym { impl Dlsym { // Returns an error for unsupported symbols, and None if this symbol // should become a NULL pointer (pretend it does not exist). - pub fn from_str(name: &str) -> InterpResult<'static, Option> { + pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { Ok(match name { "getentropy" => Some(Dlsym::getentropy), _ => throw_unsup_format!("unsupported macOS dlsym: {}", name), diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index b5408e492ce9..fb0c334b3d93 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -15,7 +15,7 @@ pub enum Dlsym { impl Dlsym { // Returns an error for unsupported symbols, and None if this symbol // should become a NULL pointer (pretend it does not exist). - pub fn from_str(name: &str) -> InterpResult<'static, Option> { + pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { Ok(match name { "GetSystemTimePreciseAsFileTime" => None, "NtWriteFile" => Some(Dlsym::NtWriteFile), diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 30a9cc265dce..d492a565a728 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -227,11 +227,11 @@ impl GlobalStateInner { } /// Error reporting -pub fn err_sb_ub( +pub fn err_sb_ub<'tcx>( msg: String, help: Option, history: Option, -) -> InterpError<'static> { +) -> InterpError<'tcx> { err_machine_stop!(TerminationInfo::ExperimentalUb { msg, help, diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index f3692cdeeb04..5400e9abe503 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -195,7 +195,7 @@ impl AllocHistory { } /// Report a descriptive error when `new` could not be granted from `derived_from`. - pub fn grant_error( + pub fn grant_error<'tcx>( &self, derived_from: SbTag, new: Item, @@ -203,7 +203,7 @@ impl AllocHistory { alloc_range: AllocRange, error_offset: Size, stack: &Stack, - ) -> InterpError<'static> { + ) -> InterpError<'tcx> { let action = format!( "trying to reborrow {:?} for {:?} permission at {}[{:#x}]", derived_from, @@ -219,7 +219,7 @@ impl AllocHistory { } /// Report a descriptive error when `access` is not permitted based on `tag`. - pub fn access_error( + pub fn access_error<'tcx>( &self, access: AccessKind, tag: SbTag, @@ -227,7 +227,7 @@ impl AllocHistory { alloc_range: AllocRange, error_offset: Size, stack: &Stack, - ) -> InterpError<'static> { + ) -> InterpError<'tcx> { let action = format!( "attempting a {} using {:?} at {}[{:#x}]", access, From 821b32bd406e9c29b2e9ca2a647d30021cff653d Mon Sep 17 00:00:00 2001 From: Aaron Kofsky Date: Sun, 29 May 2022 14:35:00 -0400 Subject: [PATCH 3125/5092] Add `let_underscore_drop` lint. This lint checks for statements similar to `let _ = foo`, where `foo` is a type that implements `Drop`. These types of let statements cause the expression in them to be dropped immediately, instead of at the end of the scope. Such behavior can be surprizing, especially if you are relying on the value to be dropped at the end of the scope. Instead, the binding should be an underscore prefixed name (like `_unused`) or the value should explicitly be passed to `std::mem::drop()` if the value really should be dropped immediately. --- compiler/rustc_lint/src/let_underscore.rs | 66 +++++++++++++++++++++++ compiler/rustc_lint/src/lib.rs | 5 ++ src/test/ui/let_underscore_drop.rs | 13 +++++ src/test/ui/let_underscore_drop.stderr | 12 +++++ 4 files changed, 96 insertions(+) create mode 100644 compiler/rustc_lint/src/let_underscore.rs create mode 100644 src/test/ui/let_underscore_drop.rs create mode 100644 src/test/ui/let_underscore_drop.stderr diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs new file mode 100644 index 000000000000..44242173c008 --- /dev/null +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -0,0 +1,66 @@ +use crate::{LateContext, LateLintPass, LintContext}; +use rustc_hir as hir; + +declare_lint! { + /// The `let_underscore_drop` lint checks for statements which don't bind + /// an expression which has a non-trivial Drop implementation to anything, + /// causing the expression to be dropped immediately instead of at end of + /// scope. + /// + /// ### Example + /// ```rust + /// struct SomeStruct; + /// impl Drop for SomeStruct { + /// fn drop(&mut self) { + /// println!("Dropping SomeStruct"); + /// } + /// } + /// + /// fn main() { + /// // SomeStuct is dropped immediately instead of at end of scope, + /// // so "Dropping SomeStruct" is printed before "end of main". + /// // The order of prints would be reversed if SomeStruct was bound to + /// // a name (such as "_foo"). + /// let _ = SomeStruct; + /// println!("end of main"); + /// } + /// ``` + /// ### Explanation + /// + /// Statements which assign an expression to an underscore causes the + /// expression to immediately drop instead of extending the expression's + /// lifetime to the end of the scope. This is usually unintended, + /// especially for types like `MutexGuard`, which are typically used to + /// lock a mutex for the duration of an entire scope. + /// + /// If you want to extend the expression's lifetime to the end of the scope, + /// assign an underscore-prefixed name (such as `_foo`) to the expression. + /// If you do actually want to drop the expression immediately, then + /// calling `std::mem::drop` on the expression is clearer and helps convey + /// intent. + pub LET_UNDERSCORE_DROP, + Warn, + "non-binding let on a type that implements `Drop`" +} + +declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_DROP]); + +impl<'tcx> LateLintPass<'tcx> for LetUnderscore { + fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::Local<'_>) { + if !matches!(local.pat.kind, hir::PatKind::Wild) { + return; + } + if let Some(init) = local.init { + let init_ty = cx.typeck_results().expr_ty(init); + let needs_drop = init_ty.needs_drop(cx.tcx, cx.param_env); + if needs_drop { + cx.struct_span_lint(LET_UNDERSCORE_DROP, local.span, |lint| { + lint.build("non-binding let on a type that implements `Drop`") + .help("consider binding to an unused variable") + .help("consider explicitly droping with `std::mem::drop`") + .emit(); + }) + } + } + } +} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 0a0f292fe7a4..55396b36dbc2 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -54,6 +54,7 @@ mod expect; pub mod hidden_unicode_codepoints; mod internal; mod late; +mod let_underscore; mod levels; mod methods; mod non_ascii_idents; @@ -85,6 +86,7 @@ use builtin::*; use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums; use hidden_unicode_codepoints::*; use internal::*; +use let_underscore::*; use methods::*; use non_ascii_idents::*; use non_fmt_panic::NonPanicFmt; @@ -199,6 +201,7 @@ macro_rules! late_lint_mod_passes { VariantSizeDifferences: VariantSizeDifferences, BoxPointers: BoxPointers, PathStatements: PathStatements, + LetUnderscore: LetUnderscore, // Depends on referenced function signatures in expressions UnusedResults: UnusedResults, NonUpperCaseGlobals: NonUpperCaseGlobals, @@ -314,6 +317,8 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { REDUNDANT_SEMICOLONS ); + add_lint_group!("let_underscore", LET_UNDERSCORE_DROP); + add_lint_group!( "rust_2018_idioms", BARE_TRAIT_OBJECTS, diff --git a/src/test/ui/let_underscore_drop.rs b/src/test/ui/let_underscore_drop.rs new file mode 100644 index 000000000000..c1c5207d0fe8 --- /dev/null +++ b/src/test/ui/let_underscore_drop.rs @@ -0,0 +1,13 @@ +// run-pass + +struct NontrivialDrop; + +impl Drop for NontrivialDrop { + fn drop(&mut self) { + println!("Dropping!"); + } +} + +fn main() { + let _ = NontrivialDrop; //~WARNING non-binding let on a type that implements `Drop` +} diff --git a/src/test/ui/let_underscore_drop.stderr b/src/test/ui/let_underscore_drop.stderr new file mode 100644 index 000000000000..40ed1abd8dc6 --- /dev/null +++ b/src/test/ui/let_underscore_drop.stderr @@ -0,0 +1,12 @@ +warning: non-binding let on a type that implements `Drop` + --> $DIR/let_underscore_drop.rs:12:5 + | +LL | let _ = NontrivialDrop; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(let_underscore_drop)]` on by default + = help: consider binding to an unused variable + = help: consider explicitly droping with `std::mem::drop` + +warning: 1 warning emitted + From 9a1475dbe2f19eb01eaa9a02b4fd93063713b648 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 22 May 2022 19:39:09 -0400 Subject: [PATCH 3126/5092] Save a created event for zero-size reborrows --- src/stacked_borrows.rs | 21 ++++++++++++++++++- .../stacked_borrows/zst_slice.stderr | 6 +++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index d492a565a728..2eba35118388 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -706,7 +706,26 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if size == Size::ZERO { - // Nothing to do for zero-sized accesses. + // Don't update any stacks for a zero-sized access; borrow stacks are per-byte and this + // touches no bytes so there is no stack to put this tag in. + // However, if the pointer for this operation points at a real allocation we still + // record where it was created so that we can issue a helpful diagnostic if there is an + // attempt to use it for a non-zero-sized access. + // Dangling slices are a common case here; it's valid to get their length but with raw + // pointer tagging for example all calls to get_unchecked on them are invalid. + if let Ok((alloc_id, base_offset, orig_tag)) = this.ptr_try_get_alloc_id(place.ptr) { + let extra = this.get_alloc_extra(alloc_id)?; + let stacked_borrows = + extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); + let mut alloc_history = stacked_borrows.history.borrow_mut(); + alloc_history.log_creation( + Some(orig_tag), + new_tag, + alloc_range(base_offset, Size::ZERO), + &mut this.machine.current_span(), + ); + } + trace!( "reborrow of size 0: {} reference {:?} derived from {:?} (pointee {})", kind, diff --git a/tests/compile-fail/stacked_borrows/zst_slice.stderr b/tests/compile-fail/stacked_borrows/zst_slice.stderr index f9d8b024e986..c6b4dc16b797 100644 --- a/tests/compile-fail/stacked_borrows/zst_slice.stderr +++ b/tests/compile-fail/stacked_borrows/zst_slice.stderr @@ -2,7 +2,11 @@ error: Undefined Behavior: trying to reborrow for SharedReadOnly permissio | = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - +help: was created by a retag at offsets [0x0..0x0] + --> $DIR/zst_slice.rs:LL:CC + | +LL | assert_eq!(*s.get_unchecked(1), 2); + | ^^^^^^^^^^^^^^^^^^ = note: inside `core::slice::::get_unchecked::` at rustc_src/src/slice/mod.rs:LL:CC note: inside `main` at $DIR/zst_slice.rs:LL:CC --> $DIR/zst_slice.rs:LL:CC From 3832227734d2ac87254a7cd057f4280f443563e5 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 30 May 2022 07:26:47 +0000 Subject: [PATCH 3127/5092] Forward CARGO_BUILD_FLAGS to ui_test test suite --- miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri b/miri index 9c4eeb527580..352aed530b19 100755 --- a/miri +++ b/miri @@ -135,7 +135,7 @@ test|test-debug|bless|bless-debug) # Then test, and let caller control flags. # Only in root project and ui_test as `cargo-miri` has no tests. cargo test $CARGO_BUILD_FLAGS "$@" - cargo test --manifest-path ui_test/Cargo.toml "$@" + cargo test $CARGO_BUILD_FLAGS --manifest-path ui_test/Cargo.toml "$@" ;; run|run-debug) # Scan for "--target" to set the "MIRI_TEST_TARGET" env var so From e37dfa6d91f65f4b97232bea1d587591cb2982e5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 May 2022 10:27:41 +0200 Subject: [PATCH 3128/5092] ui_test: support multiple filters --- tests/compiletest.rs | 5 +++-- ui_test/src/lib.rs | 11 ++++++----- ui_test/src/tests.rs | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 4be658e86cba..307272264275 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -47,7 +47,8 @@ fn run_tests(mode: Mode, path: &str, target: Option) { (true, true) => panic!("cannot use MIRI_BLESS and MIRI_SKIP_UI_CHECKS at the same time"), }; - let path_filter = std::env::args().skip(1).next(); + // Pass on all arguments as filters. + let path_filter = std::env::args().skip(1); let config = Config { args: flags, @@ -56,7 +57,7 @@ fn run_tests(mode: Mode, path: &str, target: Option) { stdout_filters: STDOUT.clone(), root_dir: PathBuf::from(path), mode, - path_filter, + path_filter: path_filter.collect(), program: miri_path(), output_conflict_handling, }; diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 81560db6dff7..866a9fe46ace 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -30,8 +30,8 @@ pub struct Config { pub mode: Mode, pub program: PathBuf, pub output_conflict_handling: OutputConflictHandling, - /// Only run tests with this string in their path/name - pub path_filter: Option, + /// Only run tests with one of these strings in their path/name + pub path_filter: Vec, } #[derive(Debug)] @@ -77,12 +77,13 @@ pub fn run_tests(config: Config) { if !path.extension().map(|ext| ext == "rs").unwrap_or(false) { continue; } - if let Some(path_filter) = &config.path_filter { - if !path.display().to_string().contains(path_filter) { + if !config.path_filter.is_empty() { + let path_display = path.display().to_string(); + if !config.path_filter.iter().any(|filter| path_display.contains(filter)) { ignored.fetch_add(1, Ordering::Relaxed); eprintln!( "{} .. {}", - path.display(), + path_display, "ignored (command line filter)".yellow() ); continue; diff --git a/ui_test/src/tests.rs b/ui_test/src/tests.rs index 5485e6b4f26b..b2544e68ada1 100644 --- a/ui_test/src/tests.rs +++ b/ui_test/src/tests.rs @@ -10,7 +10,7 @@ fn config() -> Config { stdout_filters: vec![], root_dir: PathBuf::from("."), mode: Mode::Fail, - path_filter: None, + path_filter: vec![], program: PathBuf::from("cake"), output_conflict_handling: OutputConflictHandling::Error, } From 8694e656bee538fb3d1db0bf4fb6625943cd4087 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 May 2022 10:28:07 +0200 Subject: [PATCH 3129/5092] test mir-opt-level=4 again on run tests --- ci.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ci.sh b/ci.sh index bdca26fd0491..080bd9204db5 100755 --- a/ci.sh +++ b/ci.sh @@ -26,8 +26,7 @@ function run_tests { # optimizations up all the way). # Optimizations change diagnostics (mostly backtraces), so we don't check them #FIXME(#2155): we want to only run the pass and panic tests here, not the fail tests. - #MIRIFLAGS="-O -Zmir-opt-level=4" MIRI_SKIP_UI_CHECKS=1 ./miri test --locked - true + MIRIFLAGS="-O -Zmir-opt-level=4" MIRI_SKIP_UI_CHECKS=1 ./miri test --locked -- tests/{run-pass,run-fail} fi # On Windows, there is always "python", not "python3" or "python2". From 4e91c2e368c7e96b85c12cef61363eb9eccac621 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 May 2022 10:29:02 +0200 Subject: [PATCH 3130/5092] ui_test: printing more consistent with compiletest distinguish "ignored" from "filtered out" --- ui_test/src/lib.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 866a9fe46ace..b7488d817a6c 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -61,6 +61,7 @@ pub fn run_tests(config: Config) { let failures = Mutex::new(vec![]); let succeeded = AtomicUsize::default(); let ignored = AtomicUsize::default(); + let filtered = AtomicUsize::default(); crossbeam::scope(|s| { for _ in 0..std::thread::available_parallelism().unwrap().get() { @@ -80,12 +81,7 @@ pub fn run_tests(config: Config) { if !config.path_filter.is_empty() { let path_display = path.display().to_string(); if !config.path_filter.iter().any(|filter| path_display.contains(filter)) { - ignored.fetch_add(1, Ordering::Relaxed); - eprintln!( - "{} .. {}", - path_display, - "ignored (command line filter)".yellow() - ); + filtered.fetch_add(1, Ordering::Relaxed); continue; } } @@ -93,7 +89,7 @@ pub fn run_tests(config: Config) { // Ignore file if only/ignore rules do (not) apply if ignore_file(&comments, &target) { ignored.fetch_add(1, Ordering::Relaxed); - eprintln!("{} .. {}", path.display(), "ignored".yellow()); + eprintln!("{} ... {}", path.display(), "ignored".yellow()); continue; } // Run the test for all revisions @@ -126,6 +122,7 @@ pub fn run_tests(config: Config) { let failures = failures.into_inner().unwrap(); let succeeded = succeeded.load(Ordering::Relaxed); let ignored = ignored.load(Ordering::Relaxed); + let filtered = filtered.load(Ordering::Relaxed); if !failures.is_empty() { for (path, miri, revision, errors) in &failures { eprintln!(); @@ -169,19 +166,22 @@ pub fn run_tests(config: Config) { } } eprintln!( - "{} tests failed, {} tests passed, {} ignored", + "test result: {}. {} tests failed, {} tests passed, {} ignored, {} filtered out", + "FAIL".red(), failures.len().to_string().red().bold(), succeeded.to_string().green(), - ignored.to_string().yellow() + ignored.to_string().yellow(), + filtered.to_string().yellow(), ); std::process::exit(1); } eprintln!(); eprintln!( - "test result: {}. {} tests passed, {} ignored", + "test result: {}. {} tests passed, {} ignored, {} filtered out", "ok".green(), succeeded.to_string().green(), - ignored.to_string().yellow() + ignored.to_string().yellow(), + filtered.to_string().yellow(), ); eprintln!(); } From 86e53f41b099f48e25fe53aa2d13101f17fae049 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 May 2022 10:31:12 +0200 Subject: [PATCH 3131/5092] print reason for ignoring --- ui_test/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index b7488d817a6c..305b4721e964 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -89,7 +89,7 @@ pub fn run_tests(config: Config) { // Ignore file if only/ignore rules do (not) apply if ignore_file(&comments, &target) { ignored.fetch_add(1, Ordering::Relaxed); - eprintln!("{} ... {}", path.display(), "ignored".yellow()); + eprintln!("{} ... {}", path.display(), "ignored (in-test comment)".yellow()); continue; } // Run the test for all revisions From b9d79a25baa9e2fefa5ee56a93517a7f96904c9c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 May 2022 12:20:12 +0200 Subject: [PATCH 3132/5092] also 'check' the test suite --- miri | 2 +- ui_test/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/miri b/miri index 352aed530b19..5c9cb81885c9 100755 --- a/miri +++ b/miri @@ -115,7 +115,7 @@ install|install-debug) ;; check|check-debug) # Check, and let caller control flags. - cargo check $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" + cargo check $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@" cargo check $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" ;; build|build-debug) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 305b4721e964..90c475d4bed5 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -98,7 +98,7 @@ pub fn run_tests(config: Config) { { let (m, errors) = run_test(&path, &config, &target, &revision, &comments); - // Using `format` to prevent messages from threads from getting intermingled. + // Using a single `eprintln!` to prevent messages from threads from getting intermingled. let mut msg = format!("{} ", path.display()); if !revision.is_empty() { write!(msg, "(revision `{revision}`) ").unwrap(); From 80bf204848eb2c97effa717e8e4f876f6545d55f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 May 2022 12:28:13 +0200 Subject: [PATCH 3133/5092] don't configure the same regex twice --- tests/compiletest.rs | 2 -- ui_test/src/lib.rs | 20 ++++++++++---------- ui_test/src/tests.rs | 4 ++-- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 307272264275..937ae0d9d7de 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -106,8 +106,6 @@ regexes! { r"\\" => "/", // erase platform file paths "sys/[a-z]+/" => "sys/PLATFORM/", - // erase error annotations in tests - r"\s*//~.*" => "", } fn ui(mode: Mode, path: &str) { diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 90c475d4bed5..648efb1f4714 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -231,6 +231,11 @@ fn run_test( } let output = miri.output().expect("could not execute miri"); let mut errors = config.mode.ok(output.status); + // Always remove annotation comments from stderr. + let annotations = Regex::new(r"\s*//~.*").unwrap(); + let stderr = std::str::from_utf8(&output.stderr).unwrap(); + let stderr = annotations.replace_all(stderr, ""); + let stdout = std::str::from_utf8(&output.stdout).unwrap(); // Check output files (if any) let revised = |extension: &str| { if revision.is_empty() { @@ -241,7 +246,7 @@ fn run_test( }; // Check output files against actual output check_output( - &output.stderr, + &stderr, path, &mut errors, revised("stderr"), @@ -251,7 +256,7 @@ fn run_test( comments, ); check_output( - &output.stdout, + &stdout, path, &mut errors, revised("stdout"), @@ -261,21 +266,17 @@ fn run_test( comments, ); // Check error annotations in the source against output - check_annotations(&output.stderr, &mut errors, config, revision, comments); + check_annotations(&stderr, &mut errors, config, revision, comments); (miri, errors) } fn check_annotations( - unnormalized_stderr: &[u8], + unnormalized_stderr: &str, errors: &mut Errors, config: &Config, revision: &str, comments: &Comments, ) { - let unnormalized_stderr = std::str::from_utf8(unnormalized_stderr).unwrap(); - // erase annotations from the stderr so they don't match themselves - let annotations = Regex::new(r"\s*//~.*").unwrap(); - let unnormalized_stderr = annotations.replace(unnormalized_stderr, ""); let mut found_annotation = false; if let Some((ref error_pattern, definition_line)) = comments.error_pattern { if !unnormalized_stderr.contains(error_pattern) { @@ -313,7 +314,7 @@ fn check_annotations( } fn check_output( - output: &[u8], + output: &str, path: &Path, errors: &mut Errors, kind: String, @@ -322,7 +323,6 @@ fn check_output( config: &Config, comments: &Comments, ) { - let output = std::str::from_utf8(&output).unwrap(); let output = normalize(path, output, filters, comments); let path = output_path(path, comments, kind, target); match config.output_conflict_handling { diff --git a/ui_test/src/tests.rs b/ui_test/src/tests.rs index b2544e68ada1..7b25eaeeafe9 100644 --- a/ui_test/src/tests.rs +++ b/ui_test/src/tests.rs @@ -42,9 +42,9 @@ LL | let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountere note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to previous error "; - check_annotations(unnormalized_stderr.as_bytes(), &mut errors, &config, "", &comments); + check_annotations(unnormalized_stderr, &mut errors, &config, "", &comments); match &errors[..] { [Error::PatternNotFound { .. }] => {} - _ => panic!("{:#?}", errors), + _ => panic!("not the expected error: {:#?}", errors), } } From 4d80880854b2ae832d9e490f0d761bbc5170c3bb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 May 2022 12:32:49 +0200 Subject: [PATCH 3134/5092] fmt --- ui_test/src/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 648efb1f4714..37af27dcfb1d 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -89,7 +89,11 @@ pub fn run_tests(config: Config) { // Ignore file if only/ignore rules do (not) apply if ignore_file(&comments, &target) { ignored.fetch_add(1, Ordering::Relaxed); - eprintln!("{} ... {}", path.display(), "ignored (in-test comment)".yellow()); + eprintln!( + "{} ... {}", + path.display(), + "ignored (in-test comment)".yellow() + ); continue; } // Run the test for all revisions From 962957f11f456949395535037b45b98d18bbcf19 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 May 2022 12:56:34 +0200 Subject: [PATCH 3135/5092] make it possible to test more of ui_test --- ui_test/src/lib.rs | 34 ++++++++++++++++++++++++++++------ ui_test/src/tests.rs | 15 +++++++++------ 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 37af27dcfb1d..6052efe02e06 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -235,11 +235,34 @@ fn run_test( } let output = miri.output().expect("could not execute miri"); let mut errors = config.mode.ok(output.status); + check_test_result( + path, + config, + target, + revision, + comments, + &mut errors, + &output.stdout, + &output.stderr, + ); + (miri, errors) +} + +fn check_test_result( + path: &Path, + config: &Config, + target: &str, + revision: &str, + comments: &Comments, + errors: &mut Errors, + stdout: &[u8], + stderr: &[u8], +) { // Always remove annotation comments from stderr. let annotations = Regex::new(r"\s*//~.*").unwrap(); - let stderr = std::str::from_utf8(&output.stderr).unwrap(); + let stderr = std::str::from_utf8(stderr).unwrap(); let stderr = annotations.replace_all(stderr, ""); - let stdout = std::str::from_utf8(&output.stdout).unwrap(); + let stdout = std::str::from_utf8(stdout).unwrap(); // Check output files (if any) let revised = |extension: &str| { if revision.is_empty() { @@ -252,7 +275,7 @@ fn run_test( check_output( &stderr, path, - &mut errors, + errors, revised("stderr"), target, &config.stderr_filters, @@ -262,7 +285,7 @@ fn run_test( check_output( &stdout, path, - &mut errors, + errors, revised("stdout"), target, &config.stdout_filters, @@ -270,8 +293,7 @@ fn run_test( comments, ); // Check error annotations in the source against output - check_annotations(&stderr, &mut errors, config, revision, comments); - (miri, errors) + check_annotations(&stderr, errors, config, revision, comments); } fn check_annotations( diff --git a/ui_test/src/tests.rs b/ui_test/src/tests.rs index 7b25eaeeafe9..d0ef1195d888 100644 --- a/ui_test/src/tests.rs +++ b/ui_test/src/tests.rs @@ -1,6 +1,6 @@ use std::path::{Path, PathBuf}; -use super::{check_annotations, Comments, Config, Error, Mode, OutputConflictHandling}; +use super::*; fn config() -> Config { Config { @@ -8,7 +8,7 @@ fn config() -> Config { target: None, stderr_filters: vec![], stdout_filters: vec![], - root_dir: PathBuf::from("."), + root_dir: PathBuf::from("$RUSTROOT"), mode: Mode::Fail, path_filter: vec![], program: PathBuf::from("cake"), @@ -25,10 +25,12 @@ fn main() { let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address $HEX is unallocated) } "; - let comments = Comments::parse(Path::new(""), s); + let path = Path::new("$DIR/"); + let comments = Comments::parse(&path, s); let mut errors = vec![]; let config = config(); - let unnormalized_stderr = r" + // Crucially, the intended error string *does* appear in this output, as a quote of the comment itself. + let stderr = br" error: Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated) --> tests/compile-fail/validity/dangling_ref1.rs:6:29 | @@ -42,9 +44,10 @@ LL | let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountere note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to previous error "; - check_annotations(unnormalized_stderr, &mut errors, &config, "", &comments); + check_test_result(&path, &config, "", "", &comments, &mut errors, /*stdout*/ br"", stderr); + // The "OutputDiffers" is because we cannot open the .rs file match &errors[..] { - [Error::PatternNotFound { .. }] => {} + [Error::OutputDiffers { .. }, Error::PatternNotFound { .. }] => {} _ => panic!("not the expected error: {:#?}", errors), } } From ba9391334e8d23261eb09ce7162015993f7c2aa3 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 29 May 2022 18:00:06 -0400 Subject: [PATCH 3136/5092] Add support for _COARSE clocks, spruce up comments --- src/shims/time.rs | 22 ++++++++++++++++++---- tests/run-pass/libc.rs | 25 +++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index 78bf6f59b349..be453a429ec5 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -16,6 +16,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx clk_id_op: &OpTy<'tcx, Tag>, tp_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { + // This clock support is deliberately minimal because a lot of clock types have fiddly + // properties (is it possible for Miri to be suspended independently of the host?). If you + // have a use for another clock type, please open an issue. + let this = self.eval_context_mut(); this.assert_target_os("linux", "clock_gettime"); @@ -23,11 +27,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let clk_id = this.read_scalar(clk_id_op)?.to_i32()?; - let duration = if clk_id == this.eval_libc_i32("CLOCK_REALTIME")? { + // Linux has two main kinds of clocks. REALTIME clocks return the actual time since the + // Unix epoch, including effects which may cause time to move backwards such as NTP. + // Linux further distinguishes regular and "coarse" clocks, but the "coarse" version + // is just specified to be "faster and less precise", so we implement both the same way. + let absolute_clocks = + [this.eval_libc_i32("CLOCK_REALTIME")?, this.eval_libc_i32("CLOCK_REALTIME_COARSE")?]; + // The second kind is MONOTONIC clocks for which 0 is an arbitrary time point, but they are + // never allowed to go backwards. We don't need to do any additonal monotonicity + // enforcement because std::time::Instant already guarantees that it is monotonic. + let relative_clocks = + [this.eval_libc_i32("CLOCK_MONOTONIC")?, this.eval_libc_i32("CLOCK_MONOTONIC_COARSE")?]; + + let duration = if absolute_clocks.contains(&clk_id) { system_time_to_duration(&SystemTime::now())? - } else if clk_id == this.eval_libc_i32("CLOCK_MONOTONIC")? { - // Absolute time does not matter, only relative time does, so we can just - // use our own time anchor here. + } else if relative_clocks.contains(&clk_id) { Instant::now().duration_since(this.machine.time_anchor) } else { let einval = this.eval_libc("EINVAL")?; diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index fd3625639bfd..bf5ae9829011 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -230,6 +230,28 @@ fn test_thread_local_errno() { } } +/// Tests whether clock support exists at all +#[cfg(target_os = "linux")] +fn test_clocks() { + let mut tp = std::mem::MaybeUninit::::uninit(); + let is_error = unsafe { + libc::clock_gettime(libc::CLOCK_REALTIME, tp.as_mut_ptr()) + }; + assert_eq!(is_error, 0); + let is_error = unsafe { + libc::clock_gettime(libc::CLOCK_REALTIME_COARSE, tp.as_mut_ptr()) + }; + assert_eq!(is_error, 0); + let is_error = unsafe { + libc::clock_gettime(libc::CLOCK_MONOTONIC, tp.as_mut_ptr()) + }; + assert_eq!(is_error, 0); + let is_error = unsafe { + libc::clock_gettime(libc::CLOCK_MONOTONIC_COARSE, tp.as_mut_ptr()) + }; + assert_eq!(is_error, 0); +} + fn main() { #[cfg(target_os = "linux")] test_posix_fadvise(); @@ -249,4 +271,7 @@ fn main() { test_prctl_thread_name(); test_thread_local_errno(); + + #[cfg(target_os = "linux")] + test_clocks(); } From a8e457fad1fd295068bb58e43a36cfb0e996ec4e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 May 2022 17:47:16 -0400 Subject: [PATCH 3137/5092] use is_power_of_two where appropriate --- test-cargo-miri/tests/test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 1a8b3c72565d..545c79db2760 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -68,7 +68,7 @@ fn page_size() { // In particular, this checks that it is not 0. assert!( - page_size.next_power_of_two() == page_size, + page_size.is_power_of_two(), "page size not a power of two: {}", page_size ); From 12660997425e3d2c9ace188531eff02e52ad7262 Mon Sep 17 00:00:00 2001 From: Stovent Date: Thu, 10 Feb 2022 00:24:12 -0500 Subject: [PATCH 3138/5092] Implement carrying_add and borrowing_sub on signed numbers --- library/core/src/num/int_macros.rs | 80 +++++++++++++++++++++++++++ library/core/tests/lib.rs | 1 + library/core/tests/num/int_macros.rs | 26 +++++++++ library/core/tests/num/uint_macros.rs | 22 ++++++++ 4 files changed, 129 insertions(+) diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 1f435784be14..4e51b90b835c 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -1512,6 +1512,53 @@ macro_rules! int_impl { (a as Self, b) } + /// Calculates `self + rhs + carry` without the ability to overflow. + /// + /// Performs "ternary addition" which takes in an extra bit to add, and may return an + /// additional bit of overflow. This allows for chaining together multiple additions + /// to create "big integers" which represent larger values. + /// + #[doc = concat!("This can be thought of as a ", stringify!($BITS), "-bit \"full adder\", in the electronics sense.")] + /// + /// # Examples + /// + /// Basic usage + /// + /// ``` + /// #![feature(bigint_helper_methods)] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, false), (7, false));")] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, true), (8, false));")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), (", stringify!($SelfT), "::MIN, true));")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(0, true), (", stringify!($SelfT), "::MIN, true));")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, true), (", stringify!($SelfT), "::MIN + 1, true));")] + #[doc = concat!("assert_eq!(", + stringify!($SelfT), "::MAX.carrying_add(", stringify!($SelfT), "::MAX, true), ", + "(-1, true));" + )] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.carrying_add(-1, true), (", stringify!($SelfT), "::MIN, false));")] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".carrying_add(", stringify!($SelfT), "::MAX, true), (", stringify!($SelfT), "::MIN, true));")] + /// ``` + /// + /// If `carry` is false, this method is equivalent to [`overflowing_add`](Self::overflowing_add): + /// + /// ``` + /// #![feature(bigint_helper_methods)] + #[doc = concat!("assert_eq!(5_", stringify!($SelfT), ".carrying_add(2, false), 5_", stringify!($SelfT), ".overflowing_add(2));")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), ", stringify!($SelfT), "::MAX.overflowing_add(1));")] + /// ``` + #[unstable(feature = "bigint_helper_methods", issue = "85532")] + #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn carrying_add(self, rhs: Self, carry: bool) -> (Self, bool) { + // note: longer-term this should be done via an intrinsic. + // note: no intermediate overflow is required (https://github.com/rust-lang/rust/issues/85532#issuecomment-1032214946). + let (a, b) = self.overflowing_add(rhs); + let (c, d) = a.overflowing_add(carry as $SelfT); + (c, b != d) + } + /// Calculates `self` + `rhs` with an unsigned `rhs` /// /// Returns a tuple of the addition along with a boolean indicating @@ -1563,6 +1610,39 @@ macro_rules! int_impl { (a as Self, b) } + /// Calculates `self - rhs - borrow` without the ability to overflow. + /// + /// Performs "ternary subtraction" which takes in an extra bit to subtract, and may return + /// an additional bit of overflow. This allows for chaining together multiple subtractions + /// to create "big integers" which represent larger values. + /// + /// # Examples + /// + /// Basic usage + /// + /// ``` + /// #![feature(bigint_helper_methods)] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, false), (3, false));")] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, true), (2, false));")] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".borrowing_sub(1, false), (-1, false));")] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".borrowing_sub(1, true), (-2, false));")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.borrowing_sub(1, true), (", stringify!($SelfT), "::MAX - 1, true));")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.borrowing_sub(-1, false), (", stringify!($SelfT), "::MIN, true));")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.borrowing_sub(-1, true), (", stringify!($SelfT), "::MAX, false));")] + /// ``` + #[unstable(feature = "bigint_helper_methods", issue = "85532")] + #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn borrowing_sub(self, rhs: Self, borrow: bool) -> (Self, bool) { + // note: longer-term this should be done via an intrinsic. + // note: no intermediate overflow is required (https://github.com/rust-lang/rust/issues/85532#issuecomment-1032214946). + let (a, b) = self.overflowing_sub(rhs); + let (c, d) = a.overflowing_sub(borrow as $SelfT); + (c, b != d) + } + /// Calculates `self` - `rhs` with an unsigned `rhs` /// /// Returns a tuple of the subtraction along with a boolean indicating diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 7e9d7d271018..3132d8adb362 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -3,6 +3,7 @@ #![feature(array_methods)] #![feature(array_windows)] #![feature(bench_black_box)] +#![feature(bigint_helper_methods)] #![feature(cell_update)] #![feature(const_assume)] #![feature(const_black_box)] diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs index 8b84a78e6be0..18c55e43aac8 100644 --- a/library/core/tests/num/int_macros.rs +++ b/library/core/tests/num/int_macros.rs @@ -338,6 +338,32 @@ macro_rules! int_module { assert_eq!(MIN.checked_next_multiple_of(-3), None); assert_eq!(MIN.checked_next_multiple_of(-1), Some(MIN)); } + + #[test] + fn test_carrying_add() { + assert_eq!($T::MAX.carrying_add(1, false), ($T::MIN, true)); + assert_eq!($T::MAX.carrying_add(0, true), ($T::MIN, true)); + assert_eq!($T::MAX.carrying_add(1, true), ($T::MIN + 1, true)); + assert_eq!($T::MAX.carrying_add(-1, false), ($T::MAX - 1, false)); + assert_eq!($T::MAX.carrying_add(-1, true), ($T::MAX, false)); // no intermediate overflow + assert_eq!($T::MIN.carrying_add(-1, false), ($T::MAX, true)); + assert_eq!($T::MIN.carrying_add(-1, true), ($T::MIN, false)); // no intermediate overflow + assert_eq!((0 as $T).carrying_add($T::MAX, true), ($T::MIN, true)); + assert_eq!((0 as $T).carrying_add($T::MIN, true), ($T::MIN + 1, false)); + } + + #[test] + fn test_borrowing_sub() { + assert_eq!($T::MIN.borrowing_sub(1, false), ($T::MAX, true)); + assert_eq!($T::MIN.borrowing_sub(0, true), ($T::MAX, true)); + assert_eq!($T::MIN.borrowing_sub(1, true), ($T::MAX - 1, true)); + assert_eq!($T::MIN.borrowing_sub(-1, false), ($T::MIN + 1, false)); + assert_eq!($T::MIN.borrowing_sub(-1, true), ($T::MIN, false)); // no intermediate overflow + assert_eq!($T::MAX.borrowing_sub(-1, false), ($T::MIN, true)); + assert_eq!($T::MAX.borrowing_sub(-1, true), ($T::MAX, false)); // no intermediate overflow + assert_eq!((0 as $T).borrowing_sub($T::MIN, false), ($T::MIN, true)); + assert_eq!((0 as $T).borrowing_sub($T::MIN, true), ($T::MAX, false)); + } } }; } diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs index 93ae620c2330..15ae9f2324f6 100644 --- a/library/core/tests/num/uint_macros.rs +++ b/library/core/tests/num/uint_macros.rs @@ -230,6 +230,28 @@ macro_rules! uint_module { assert_eq!((1 as $T).checked_next_multiple_of(0), None); assert_eq!(MAX.checked_next_multiple_of(2), None); } + + #[test] + fn test_carrying_add() { + assert_eq!($T::MAX.carrying_add(1, false), (0, true)); + assert_eq!($T::MAX.carrying_add(0, true), (0, true)); + assert_eq!($T::MAX.carrying_add(1, true), (1, true)); + + assert_eq!($T::MIN.carrying_add($T::MAX, false), ($T::MAX, false)); + assert_eq!($T::MIN.carrying_add(0, true), (1, false)); + assert_eq!($T::MIN.carrying_add($T::MAX, true), (0, true)); + } + + #[test] + fn test_borrowing_sub() { + assert_eq!($T::MIN.borrowing_sub(1, false), ($T::MAX, true)); + assert_eq!($T::MIN.borrowing_sub(0, true), ($T::MAX, true)); + assert_eq!($T::MIN.borrowing_sub(1, true), ($T::MAX - 1, true)); + + assert_eq!($T::MAX.borrowing_sub($T::MAX, false), (0, false)); + assert_eq!($T::MAX.borrowing_sub(0, true), ($T::MAX - 1, false)); + assert_eq!($T::MAX.borrowing_sub($T::MAX, true), ($T::MAX, true)); + } } }; } From 5c690555f226909786a43b4bf0dc58f8bffa7a6b Mon Sep 17 00:00:00 2001 From: Stovent Date: Fri, 11 Feb 2022 15:25:51 -0500 Subject: [PATCH 3139/5092] Correct signed bit int documentation --- library/core/src/num/int_macros.rs | 74 ++++++++++++++++++++++++++---- 1 file changed, 64 insertions(+), 10 deletions(-) diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 4e51b90b835c..0cd64753f9b2 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -1514,15 +1514,41 @@ macro_rules! int_impl { /// Calculates `self + rhs + carry` without the ability to overflow. /// - /// Performs "ternary addition" which takes in an extra bit to add, and may return an - /// additional bit of overflow. This allows for chaining together multiple additions - /// to create "big integers" which represent larger values. - /// - #[doc = concat!("This can be thought of as a ", stringify!($BITS), "-bit \"full adder\", in the electronics sense.")] + /// Performs "signed ternary addition" which takes in an extra bit to add, and may return an + /// additional bit of overflow. This signed function is used only on the highest-ordered data, + /// for which the signed overflow result indicates whether the big integer overflowed or not. /// /// # Examples /// - /// Basic usage + /// Standard signed bit integer implementation + /// + /// ```rs + /// #![feature(bigint_helper_methods)] + /// struct I16 { + /// pub low: u8, // Low-order bytes has to be unsigned. + /// /// Most Significant Data has to be of the same signedness as the desired type. + /// /// So u8 to implement U16, i8 to implement I16. + /// pub high: i8, + /// } + /// + /// impl I16 { + /// /// Adds `rhs` to `self` and returns true if signed overflow occurs, false otherwise. + /// pub fn overflowing_add(&mut self, rhs: Self) -> bool { + /// let (low_res, low_carry) = self.low.carrying_add(rhs.low, false); + /// + /// // The signed `carrying_add` method is used to detect signed overflow. + /// let (high_res, high_carry) = self.high.carrying_add(rhs.high, low_carry); + /// + /// self.low = low_res; + /// self.high = high_res; + /// high_carry + /// } + /// } + /// + /// fn main() {} + /// ``` + /// + /// General behavior /// /// ``` /// #![feature(bigint_helper_methods)] @@ -1612,13 +1638,41 @@ macro_rules! int_impl { /// Calculates `self - rhs - borrow` without the ability to overflow. /// - /// Performs "ternary subtraction" which takes in an extra bit to subtract, and may return - /// an additional bit of overflow. This allows for chaining together multiple subtractions - /// to create "big integers" which represent larger values. + /// Performs "signed ternary subtraction" which takes in an extra bit to subtract, and may return an + /// additional bit of overflow. This signed function is used only on the highest-ordered data, + /// for which the signed overflow result indicates whether the big integer overflowed or not. /// /// # Examples /// - /// Basic usage + /// Standard signed bit integer implementation + /// + /// ```rs + /// #![feature(bigint_helper_methods)] + /// struct I16 { + /// pub low: u8, // Low-order bytes has to be unsigned. + /// /// Most Significant Data has to be of the same signedness as the desired type. + /// /// So u8 to implement U16, i8 to implement I16. + /// pub high: i8, + /// } + /// + /// impl I16 { + /// /// Subtracts `rhs` from `self` and returns true if signed overflow occurs, false otherwise. + /// pub fn overflowing_sub(&mut self, rhs: Self) -> bool { + /// let (low_res, low_carry) = self.low.borrowing_sub(rhs.low, false); + /// + /// // The signed `borrowing_sub` method is used to detect signed overflow. + /// let (high_res, high_carry) = self.high.borrowing_sub(rhs.high, low_carry); + /// + /// self.low = low_res; + /// self.high = high_res; + /// high_carry + /// } + /// } + /// + /// fn main() {} + /// ``` + /// + /// General behavior /// /// ``` /// #![feature(bigint_helper_methods)] From b998d82d8d098ee0e5127123543f5720965c6648 Mon Sep 17 00:00:00 2001 From: Stovent Date: Fri, 11 Feb 2022 15:47:37 -0500 Subject: [PATCH 3140/5092] Remove too long example --- library/core/src/num/int_macros.rs | 60 +----------------------------- 1 file changed, 2 insertions(+), 58 deletions(-) diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 0cd64753f9b2..2d97fa62accd 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -1520,35 +1520,7 @@ macro_rules! int_impl { /// /// # Examples /// - /// Standard signed bit integer implementation - /// - /// ```rs - /// #![feature(bigint_helper_methods)] - /// struct I16 { - /// pub low: u8, // Low-order bytes has to be unsigned. - /// /// Most Significant Data has to be of the same signedness as the desired type. - /// /// So u8 to implement U16, i8 to implement I16. - /// pub high: i8, - /// } - /// - /// impl I16 { - /// /// Adds `rhs` to `self` and returns true if signed overflow occurs, false otherwise. - /// pub fn overflowing_add(&mut self, rhs: Self) -> bool { - /// let (low_res, low_carry) = self.low.carrying_add(rhs.low, false); - /// - /// // The signed `carrying_add` method is used to detect signed overflow. - /// let (high_res, high_carry) = self.high.carrying_add(rhs.high, low_carry); - /// - /// self.low = low_res; - /// self.high = high_res; - /// high_carry - /// } - /// } - /// - /// fn main() {} - /// ``` - /// - /// General behavior + /// Basic usage: /// /// ``` /// #![feature(bigint_helper_methods)] @@ -1644,35 +1616,7 @@ macro_rules! int_impl { /// /// # Examples /// - /// Standard signed bit integer implementation - /// - /// ```rs - /// #![feature(bigint_helper_methods)] - /// struct I16 { - /// pub low: u8, // Low-order bytes has to be unsigned. - /// /// Most Significant Data has to be of the same signedness as the desired type. - /// /// So u8 to implement U16, i8 to implement I16. - /// pub high: i8, - /// } - /// - /// impl I16 { - /// /// Subtracts `rhs` from `self` and returns true if signed overflow occurs, false otherwise. - /// pub fn overflowing_sub(&mut self, rhs: Self) -> bool { - /// let (low_res, low_carry) = self.low.borrowing_sub(rhs.low, false); - /// - /// // The signed `borrowing_sub` method is used to detect signed overflow. - /// let (high_res, high_carry) = self.high.borrowing_sub(rhs.high, low_carry); - /// - /// self.low = low_res; - /// self.high = high_res; - /// high_carry - /// } - /// } - /// - /// fn main() {} - /// ``` - /// - /// General behavior + /// Basic usage: /// /// ``` /// #![feature(bigint_helper_methods)] From d455421edcb0c0084207d44b206ee1032913e580 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 May 2022 19:19:39 -0400 Subject: [PATCH 3141/5092] rustup --- rust-version | 2 +- tests/compile-fail/generator-pinned-moved.rs | 1 + tests/compile-fail/generator-pinned-moved.stderr | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 8da4cbec7ff2..09a847a94fbe 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0f06824013761ed6829887019033f1001e68f623 +c35035cefc709abddabfb28ecc6a326458d46ce2 diff --git a/tests/compile-fail/generator-pinned-moved.rs b/tests/compile-fail/generator-pinned-moved.rs index e0ce5cb7333a..8c8e82847004 100644 --- a/tests/compile-fail/generator-pinned-moved.rs +++ b/tests/compile-fail/generator-pinned-moved.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-disable-validation #![feature(generators, generator_trait)] use std::{ diff --git a/tests/compile-fail/generator-pinned-moved.stderr b/tests/compile-fail/generator-pinned-moved.stderr index 98ccf3097c29..0ac4f8caa078 100644 --- a/tests/compile-fail/generator-pinned-moved.stderr +++ b/tests/compile-fail/generator-pinned-moved.stderr @@ -8,12 +8,12 @@ LL | *num += 1; = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: inside closure at $DIR/generator-pinned-moved.rs:LL:CC -note: inside ` as std::iter::Iterator>::next` at $DIR/generator-pinned-moved.rs:LL:CC +note: inside ` as std::iter::Iterator>::next` at $DIR/generator-pinned-moved.rs:LL:CC --> $DIR/generator-pinned-moved.rs:LL:CC | LL | match me.resume(()) { | ^^^^^^^^^^^^^ - = note: inside `> as std::iter::Iterator>::next` at rustc_src/src/boxed.rs:LL:CC + = note: inside `> as std::iter::Iterator>::next` at rustc_src/src/boxed.rs:LL:CC note: inside `main` at $DIR/generator-pinned-moved.rs:LL:CC --> $DIR/generator-pinned-moved.rs:LL:CC | From 7fb5110160b0d931814fcc1176ac440cd19af4a8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 May 2022 19:21:22 -0400 Subject: [PATCH 3142/5092] normalize away some more line numbers --- tests/compile-fail/generator-pinned-moved.stderr | 4 ++-- tests/compile-fail/panic/bad_unwind.stderr | 6 +++--- .../stacked_borrows/deallocate_against_barrier1.stderr | 2 +- .../stacked_borrows/deallocate_against_barrier2.stderr | 2 +- tests/compiletest.rs | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/compile-fail/generator-pinned-moved.stderr b/tests/compile-fail/generator-pinned-moved.stderr index 0ac4f8caa078..56bfc6092b7e 100644 --- a/tests/compile-fail/generator-pinned-moved.stderr +++ b/tests/compile-fail/generator-pinned-moved.stderr @@ -8,12 +8,12 @@ LL | *num += 1; = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: inside closure at $DIR/generator-pinned-moved.rs:LL:CC -note: inside ` as std::iter::Iterator>::next` at $DIR/generator-pinned-moved.rs:LL:CC +note: inside ` as std::iter::Iterator>::next` at $DIR/generator-pinned-moved.rs:LL:CC --> $DIR/generator-pinned-moved.rs:LL:CC | LL | match me.resume(()) { | ^^^^^^^^^^^^^ - = note: inside `> as std::iter::Iterator>::next` at rustc_src/src/boxed.rs:LL:CC + = note: inside `> as std::iter::Iterator>::next` at rustc_src/src/boxed.rs:LL:CC note: inside `main` at $DIR/generator-pinned-moved.rs:LL:CC --> $DIR/generator-pinned-moved.rs:LL:CC | diff --git a/tests/compile-fail/panic/bad_unwind.stderr b/tests/compile-fail/panic/bad_unwind.stderr index 529f4179a8f7..5030391bc6ea 100644 --- a/tests/compile-fail/panic/bad_unwind.stderr +++ b/tests/compile-fail/panic/bad_unwind.stderr @@ -10,9 +10,9 @@ LL | std::panic::catch_unwind(|| unwind()).unwrap_err(); = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: inside closure at $DIR/bad_unwind.rs:LL:CC - = note: inside `std::panicking::r#try::do_call::<[closure@$DIR/bad_unwind.rs:LL:CC: 13:41], ()>` at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::panicking::r#try::<(), [closure@$DIR/bad_unwind.rs:LL:CC: 13:41]>` at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::panic::catch_unwind::<[closure@$DIR/bad_unwind.rs:LL:CC: 13:41], ()>` at rustc_src/src/panic.rs:LL:CC + = note: inside `std::panicking::r#try::do_call::<[closure@$DIR/bad_unwind.rs:LL:CC], ()>` at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::panicking::r#try::<(), [closure@$DIR/bad_unwind.rs:LL:CC]>` at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::panic::catch_unwind::<[closure@$DIR/bad_unwind.rs:LL:CC], ()>` at rustc_src/src/panic.rs:LL:CC note: inside `main` at $DIR/bad_unwind.rs:LL:CC --> $DIR/bad_unwind.rs:LL:CC | diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier1.stderr b/tests/compile-fail/stacked_borrows/deallocate_against_barrier1.stderr index 593419fe9b37..804bb0f92af8 100644 --- a/tests/compile-fail/stacked_borrows/deallocate_against_barrier1.stderr +++ b/tests/compile-fail/stacked_borrows/deallocate_against_barrier1.stderr @@ -13,7 +13,7 @@ note: inside closure at $DIR/deallocate_against_barrier1.rs:LL:CC | LL | drop(unsafe { Box::from_raw(raw) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: inside `<[closure@$DIR/deallocate_against_barrier1.rs:LL:CC: 12:6] as std::ops::FnOnce<(&mut i32,)>>::call_once - shim` at rustc_src/src/ops/function.rs:LL:CC + = note: inside `<[closure@$DIR/deallocate_against_barrier1.rs:LL:CC] as std::ops::FnOnce<(&mut i32,)>>::call_once - shim` at rustc_src/src/ops/function.rs:LL:CC note: inside `inner` at $DIR/deallocate_against_barrier1.rs:LL:CC --> $DIR/deallocate_against_barrier1.rs:LL:CC | diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.stderr b/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.stderr index f6734db71588..41a32a6280a7 100644 --- a/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.stderr +++ b/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.stderr @@ -13,7 +13,7 @@ note: inside closure at $DIR/deallocate_against_barrier2.rs:LL:CC | LL | drop(unsafe { Box::from_raw(raw) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: inside `<[closure@$DIR/deallocate_against_barrier2.rs:LL:CC: 16:6] as std::ops::FnOnce<(&std::cell::Cell,)>>::call_once - shim` at rustc_src/src/ops/function.rs:LL:CC + = note: inside `<[closure@$DIR/deallocate_against_barrier2.rs:LL:CC] as std::ops::FnOnce<(&std::cell::Cell,)>>::call_once - shim` at rustc_src/src/ops/function.rs:LL:CC note: inside `inner` at $DIR/deallocate_against_barrier2.rs:LL:CC --> $DIR/deallocate_against_barrier2.rs:LL:CC | diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 4be658e86cba..cf053fccb478 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -80,7 +80,7 @@ regexes! { regexes! { STDERR: // erase line and column info - r"\.rs:[0-9]+:[0-9]+" => ".rs:LL:CC", + r"\.rs:[0-9]+:[0-9]+(: [0-9]+:[0-9]+)?" => ".rs:LL:CC", // erase alloc ids "alloc[0-9]+" => "ALLOC", // erase Stacked Borrows tags From eb6d4cdac0dd2151a910109161588ffa52556dbb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 31 May 2022 08:42:22 -0400 Subject: [PATCH 3143/5092] reduce some code duplication --- src/stacked_borrows.rs | 59 +++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 2eba35118388..e2e63f8a52a2 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -705,6 +705,30 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx protect: bool, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + let current_span = &mut this.machine.current_span(); + + let log_creation = |this: &MiriEvalContext<'mir, 'tcx>, + current_span: &mut CurrentSpan<'_, '_, '_>, + alloc_id, + base_offset, + orig_tag| + -> InterpResult<'tcx> { + let extra = this.get_alloc_extra(alloc_id)?; + let stacked_borrows = + extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); + let mut alloc_history = stacked_borrows.history.borrow_mut(); + alloc_history.log_creation( + Some(orig_tag), + new_tag, + alloc_range(base_offset, size), + current_span, + ); + if protect { + alloc_history.log_protector(orig_tag, new_tag, current_span); + } + Ok(()) + }; + if size == Size::ZERO { // Don't update any stacks for a zero-sized access; borrow stacks are per-byte and this // touches no bytes so there is no stack to put this tag in. @@ -714,16 +738,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dangling slices are a common case here; it's valid to get their length but with raw // pointer tagging for example all calls to get_unchecked on them are invalid. if let Ok((alloc_id, base_offset, orig_tag)) = this.ptr_try_get_alloc_id(place.ptr) { - let extra = this.get_alloc_extra(alloc_id)?; - let stacked_borrows = - extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); - let mut alloc_history = stacked_borrows.history.borrow_mut(); - alloc_history.log_creation( - Some(orig_tag), - new_tag, - alloc_range(base_offset, Size::ZERO), - &mut this.machine.current_span(), - ); + log_creation(this, current_span, alloc_id, base_offset, orig_tag)?; } trace!( @@ -736,23 +751,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(()); } let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?; - - let mut current_span = this.machine.current_span(); - { - let extra = this.get_alloc_extra(alloc_id)?; - let stacked_borrows = - extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); - let mut alloc_history = stacked_borrows.history.borrow_mut(); - alloc_history.log_creation( - Some(orig_tag), - new_tag, - alloc_range(base_offset, size), - &mut current_span, - ); - if protect { - alloc_history.log_protector(orig_tag, new_tag, &mut current_span); - } - } + log_creation(this, current_span, alloc_id, base_offset, orig_tag)?; // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). let (alloc_size, _) = @@ -819,7 +818,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx item, (alloc_id, range, offset), &mut *global, - &mut current_span, + current_span, history, ) }) @@ -836,14 +835,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let item = Item { perm, tag: new_tag, protector }; let range = alloc_range(base_offset, size); let mut global = machine.stacked_borrows.as_ref().unwrap().borrow_mut(); - let mut current_span = machine.current_span(); + let current_span = &mut machine.current_span(); // `get_alloc_extra_mut` invalidated our old `current_span` stacked_borrows.for_each_mut(range, |offset, stack, history| { stack.grant( orig_tag, item, (alloc_id, range, offset), &mut global, - &mut current_span, + current_span, history, ) })?; From 62c48b29987cd0e01d0140fcd01185fd02a57795 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 31 May 2022 08:44:48 -0400 Subject: [PATCH 3144/5092] fix some lifetime names --- src/helpers.rs | 6 +++--- src/stacked_borrows.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 5a76e15465c4..d9a7edcc1135 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -810,12 +810,12 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { /// topmost frame which corresponds to a local crate, and returns the current span in that frame. /// The result of that search is cached so that later calls are approximately free. #[derive(Clone)] -pub struct CurrentSpan<'a, 'tcx, 'mir> { +pub struct CurrentSpan<'a, 'mir, 'tcx> { span: Option, - machine: &'a Evaluator<'tcx, 'mir>, + machine: &'a Evaluator<'mir, 'tcx>, } -impl<'a, 'tcx, 'mir> CurrentSpan<'a, 'tcx, 'mir> { +impl<'a, 'mir, 'tcx> CurrentSpan<'a, 'mir, 'tcx> { pub fn get(&mut self) -> Span { *self.span.get_or_insert_with(|| Self::current_span(&self.machine)) } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index e2e63f8a52a2..6cb71f43118c 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -708,7 +708,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let current_span = &mut this.machine.current_span(); let log_creation = |this: &MiriEvalContext<'mir, 'tcx>, - current_span: &mut CurrentSpan<'_, '_, '_>, + current_span: &mut CurrentSpan<'_, 'mir, 'tcx>, alloc_id, base_offset, orig_tag| From 9a448744a2b4f90c135f9425df0437970aa9d5fa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 31 May 2022 18:23:47 -0400 Subject: [PATCH 3145/5092] different strategy for normalizing Rust stdlib path --- cargo-miri/bin.rs | 7 +- .../alloc/deallocate-bad-alignment.stderr | 6 +- .../alloc/deallocate-bad-size.stderr | 6 +- .../alloc/deallocate-twice.stderr | 6 +- .../alloc/global_system_mixup.stderr | 8 +- .../alloc/reallocate-bad-size.stderr | 6 +- .../alloc/reallocate-dangling.stderr | 6 +- tests/compile-fail/alloc/stack_free.stderr | 14 ++-- .../concurrency/too_few_args.stderr | 2 +- .../concurrency/too_many_args.stderr | 2 +- .../dangling_pointer_addr_of.stderr | 2 +- .../null_pointer_write_zst.stderr | 8 +- tests/compile-fail/fs/isolated_file.stderr | 18 +++-- .../generator-pinned-moved.stderr | 2 +- .../intrinsics/copy_overflow.stderr | 8 +- .../intrinsics/out_of_bounds_ptr_1.stderr | 6 +- .../intrinsics/out_of_bounds_ptr_2.stderr | 6 +- .../intrinsics/out_of_bounds_ptr_3.stderr | 6 +- .../intrinsics/ptr_offset_0_plus_0.stderr | 6 +- .../intrinsics/ptr_offset_int_plus_int.stderr | 6 +- .../intrinsics/ptr_offset_int_plus_ptr.stderr | 6 +- .../intrinsics/ptr_offset_overflow.stderr | 6 +- .../intrinsics/ptr_offset_ptr_plus_0.stderr | 6 +- .../intrinsics/simd-float-to-int.stderr | 6 +- .../intrinsics/simd-gather.stderr | 6 +- .../intrinsics/simd-scatter.stderr | 6 +- .../intrinsics/write_bytes_overflow.stderr | 8 +- tests/compile-fail/invalid_enum_tag.stderr | 6 +- tests/compile-fail/panic/bad_unwind.stderr | 6 +- tests/compile-fail/panic/double_panic.stderr | 76 ++++++++++--------- tests/compile-fail/panic/panic_abort1.stderr | 20 +++-- tests/compile-fail/panic/panic_abort2.stderr | 22 +++--- tests/compile-fail/panic/panic_abort3.stderr | 24 +++--- tests/compile-fail/panic/panic_abort4.stderr | 22 +++--- .../strict-provenance-offset.stderr | 6 +- tests/compile-fail/rc_as_ptr.stderr | 2 +- .../deallocate_against_barrier1.stderr | 16 ++-- .../deallocate_against_barrier2.stderr | 16 ++-- .../stacked_borrows/issue-miri-1050-1.stderr | 8 +- .../stacked_borrows/issue-miri-1050-2.stderr | 8 +- .../stacked_borrows/zst_slice.stderr | 9 ++- .../unaligned_ptr_addr_of.stderr | 2 +- tests/compile-fail/uninit_buffer.stderr | 8 +- tests/compile-fail/unreachable.stderr | 6 +- tests/compiletest.rs | 2 + tests/run-fail/panic/panic1.stderr | 26 +++---- tests/run-pass/backtrace-api-v0.stderr | 15 +--- tests/run-pass/backtrace-api-v1.stderr | 15 +--- tests/run-pass/backtrace-std.stderr | 26 +++---- tests/run-pass/panic/catch_panic.stderr | 2 +- 50 files changed, 318 insertions(+), 200 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index e08cb8c88c00..373c63647c35 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -461,12 +461,7 @@ path = "lib.rs" command.env_remove("RUSTFLAGS"); // Disable debug assertions in the standard library -- Miri is already slow enough. // But keep the overflow checks, they are cheap. - // Also remap the current directory to something that is stable across different - // machines. Otherwise ui output would contain the current directory. - command.env( - "RUSTFLAGS", - "-Cdebug-assertions=off -Coverflow-checks=on -Zremap-cwd-prefix=rustc_src", - ); + command.env("RUSTFLAGS", "-Cdebug-assertions=off -Coverflow-checks=on"); // Finally run it! if command.status().expect("failed to run xargo").success().not() { show_error(format!("failed to run xargo")); diff --git a/tests/compile-fail/alloc/deallocate-bad-alignment.stderr b/tests/compile-fail/alloc/deallocate-bad-alignment.stderr index e03704b118a6..52c0310cabaa 100644 --- a/tests/compile-fail/alloc/deallocate-bad-alignment.stderr +++ b/tests/compile-fail/alloc/deallocate-bad-alignment.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: incorrect layout on deallocation: ALLOC has size 1 and alignment ALIGN, but gave size 1 and alignment ALIGN + --> RUSTLIB/alloc/src/alloc.rs:LL:CC + | +LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: ALLOC has size 1 and alignment ALIGN, but gave size 1 and alignment ALIGN | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::alloc::dealloc` at rustc_src/src/alloc.rs:LL:CC + = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/deallocate-bad-alignment.rs:LL:CC --> $DIR/deallocate-bad-alignment.rs:LL:CC | diff --git a/tests/compile-fail/alloc/deallocate-bad-size.stderr b/tests/compile-fail/alloc/deallocate-bad-size.stderr index 3ab15094daeb..fe0a5130eb54 100644 --- a/tests/compile-fail/alloc/deallocate-bad-size.stderr +++ b/tests/compile-fail/alloc/deallocate-bad-size.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: incorrect layout on deallocation: ALLOC has size 1 and alignment ALIGN, but gave size 2 and alignment ALIGN + --> RUSTLIB/alloc/src/alloc.rs:LL:CC + | +LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: ALLOC has size 1 and alignment ALIGN, but gave size 2 and alignment ALIGN | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::alloc::dealloc` at rustc_src/src/alloc.rs:LL:CC + = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/deallocate-bad-size.rs:LL:CC --> $DIR/deallocate-bad-size.rs:LL:CC | diff --git a/tests/compile-fail/alloc/deallocate-twice.stderr b/tests/compile-fail/alloc/deallocate-twice.stderr index dfd14c397865..cca20be6e661 100644 --- a/tests/compile-fail/alloc/deallocate-twice.stderr +++ b/tests/compile-fail/alloc/deallocate-twice.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> RUSTLIB/alloc/src/alloc.rs:LL:CC + | +LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::alloc::dealloc` at rustc_src/src/alloc.rs:LL:CC + = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/deallocate-twice.rs:LL:CC --> $DIR/deallocate-twice.rs:LL:CC | diff --git a/tests/compile-fail/alloc/global_system_mixup.stderr b/tests/compile-fail/alloc/global_system_mixup.stderr index 93598be134f7..84d68be78cd1 100644 --- a/tests/compile-fail/alloc/global_system_mixup.stderr +++ b/tests/compile-fail/alloc/global_system_mixup.stderr @@ -1,10 +1,14 @@ error: Undefined Behavior: deallocating ALLOC, which is Rust heap memory, using PLATFORM heap deallocation operation + --> RUSTLIB/std/src/sys/PLATFORM/alloc.rs:LL:CC + | +LL | libc::free(ptr as *mut libc::c_void) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating ALLOC, which is Rust heap memory, using PLATFORM heap deallocation operation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::sys::PLATFORM::alloc::::dealloc` at rustc_src/src/sys/PLATFORM/alloc.rs:LL:CC - = note: inside `::deallocate` at rustc_src/src/alloc.rs:LL:CC + = note: inside `std::sys::PLATFORM::alloc::::dealloc` at RUSTLIB/std/src/sys/PLATFORM/alloc.rs:LL:CC + = note: inside `::deallocate` at RUSTLIB/std/src/alloc.rs:LL:CC note: inside `main` at $DIR/global_system_mixup.rs:LL:CC --> $DIR/global_system_mixup.rs:LL:CC | diff --git a/tests/compile-fail/alloc/reallocate-bad-size.stderr b/tests/compile-fail/alloc/reallocate-bad-size.stderr index f2692b1c343f..04dce05e78f5 100644 --- a/tests/compile-fail/alloc/reallocate-bad-size.stderr +++ b/tests/compile-fail/alloc/reallocate-bad-size.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: incorrect layout on deallocation: ALLOC has size 1 and alignment ALIGN, but gave size 2 and alignment ALIGN + --> RUSTLIB/alloc/src/alloc.rs:LL:CC + | +LL | unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: ALLOC has size 1 and alignment ALIGN, but gave size 2 and alignment ALIGN | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::alloc::realloc` at rustc_src/src/alloc.rs:LL:CC + = note: inside `std::alloc::realloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/reallocate-bad-size.rs:LL:CC --> $DIR/reallocate-bad-size.rs:LL:CC | diff --git a/tests/compile-fail/alloc/reallocate-dangling.stderr b/tests/compile-fail/alloc/reallocate-dangling.stderr index d813fb0db902..84e7b934202a 100644 --- a/tests/compile-fail/alloc/reallocate-dangling.stderr +++ b/tests/compile-fail/alloc/reallocate-dangling.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> RUSTLIB/alloc/src/alloc.rs:LL:CC + | +LL | unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::alloc::realloc` at rustc_src/src/alloc.rs:LL:CC + = note: inside `std::alloc::realloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/reallocate-dangling.rs:LL:CC --> $DIR/reallocate-dangling.rs:LL:CC | diff --git a/tests/compile-fail/alloc/stack_free.stderr b/tests/compile-fail/alloc/stack_free.stderr index 9df85d6eab7f..073510a6080d 100644 --- a/tests/compile-fail/alloc/stack_free.stderr +++ b/tests/compile-fail/alloc/stack_free.stderr @@ -1,13 +1,17 @@ error: Undefined Behavior: deallocating ALLOC, which is stack variable memory, using Rust heap deallocation operation + --> RUSTLIB/alloc/src/alloc.rs:LL:CC + | +LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating ALLOC, which is stack variable memory, using Rust heap deallocation operation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::alloc::dealloc` at rustc_src/src/alloc.rs:LL:CC - = note: inside `::deallocate` at rustc_src/src/alloc.rs:LL:CC - = note: inside `alloc::alloc::box_free::` at rustc_src/src/alloc.rs:LL:CC - = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at rustc_src/src/ptr/mod.rs:LL:CC - = note: inside `std::mem::drop::>` at rustc_src/src/mem/mod.rs:LL:CC + = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC + = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC + = note: inside `alloc::alloc::box_free::` at RUSTLIB/alloc/src/alloc.rs:LL:CC + = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC + = note: inside `std::mem::drop::>` at RUSTLIB/core/src/mem/mod.rs:LL:CC note: inside `main` at $DIR/stack_free.rs:LL:CC --> $DIR/stack_free.rs:LL:CC | diff --git a/tests/compile-fail/concurrency/too_few_args.stderr b/tests/compile-fail/concurrency/too_few_args.stderr index 753b5e9ea7eb..7401b2902ead 100644 --- a/tests/compile-fail/concurrency/too_few_args.stderr +++ b/tests/compile-fail/concurrency/too_few_args.stderr @@ -9,7 +9,7 @@ LL | panic!() = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `thread_start` at rustc_src/src/panic.rs:LL:CC + = note: inside `thread_start` at RUSTLIB/std/src/panic.rs:LL:CC = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error; 1 warning emitted diff --git a/tests/compile-fail/concurrency/too_many_args.stderr b/tests/compile-fail/concurrency/too_many_args.stderr index 483b032a9b17..951b76317f25 100644 --- a/tests/compile-fail/concurrency/too_many_args.stderr +++ b/tests/compile-fail/concurrency/too_many_args.stderr @@ -9,7 +9,7 @@ LL | panic!() = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `thread_start` at rustc_src/src/panic.rs:LL:CC + = note: inside `thread_start` at RUSTLIB/std/src/panic.rs:LL:CC = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error; 1 warning emitted diff --git a/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.stderr b/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.stderr index 6638be3758cf..1e793f549acd 100644 --- a/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.stderr +++ b/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.stderr @@ -7,7 +7,7 @@ LL | let x = unsafe { ptr::addr_of!(*p) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `main` at rustc_src/src/ptr/mod.rs:LL:CC + = note: inside `main` at RUSTLIB/core/src/ptr/mod.rs:LL:CC = note: this error originates in the macro `ptr::addr_of` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/compile-fail/dangling_pointers/null_pointer_write_zst.stderr b/tests/compile-fail/dangling_pointers/null_pointer_write_zst.stderr index b40a9154f182..ee8afcfb7d90 100644 --- a/tests/compile-fail/dangling_pointers/null_pointer_write_zst.stderr +++ b/tests/compile-fail/dangling_pointers/null_pointer_write_zst.stderr @@ -1,10 +1,14 @@ error: Undefined Behavior: memory access failed: null pointer is not a valid pointer + --> RUSTLIB/core/src/ptr/mod.rs:LL:CC + | +LL | copy_nonoverlapping(&src as *const T, dst, 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::ptr::write::<[u8; 0]>` at rustc_src/src/ptr/mod.rs:LL:CC - = note: inside `std::ptr::mut_ptr::::write` at rustc_src/src/ptr/mut_ptr.rs:LL:CC + = note: inside `std::ptr::write::<[u8; 0]>` at RUSTLIB/core/src/ptr/mod.rs:LL:CC + = note: inside `std::ptr::mut_ptr::::write` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC note: inside `main` at $DIR/null_pointer_write_zst.rs:LL:CC --> $DIR/null_pointer_write_zst.rs:LL:CC | diff --git a/tests/compile-fail/fs/isolated_file.stderr b/tests/compile-fail/fs/isolated_file.stderr index 056a67259c1a..d06698c940dd 100644 --- a/tests/compile-fail/fs/isolated_file.stderr +++ b/tests/compile-fail/fs/isolated_file.stderr @@ -1,15 +1,19 @@ error: unsupported operation: `open` not available when isolation is enabled + --> RUSTLIB/std/src/sys/PLATFORM/fs.rs:LL:CC + | +LL | let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode as c_int) })?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `open` not available when isolation is enabled | = help: pass the flag `-Zmiri-disable-isolation` to disable isolation; = help: or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning - = note: inside closure at rustc_src/src/sys/PLATFORM/fs.rs:LL:CC - = note: inside `std::sys::PLATFORM::cvt_r::` at rustc_src/src/sys/PLATFORM/mod.rs:LL:CC - = note: inside `std::sys::PLATFORM::fs::File::open_c` at rustc_src/src/sys/PLATFORM/fs.rs:LL:CC - = note: inside `std::sys::PLATFORM::fs::File::open` at rustc_src/src/sys/PLATFORM/fs.rs:LL:CC - = note: inside `std::fs::OpenOptions::_open` at rustc_src/src/fs.rs:LL:CC - = note: inside `std::fs::OpenOptions::open::<&std::path::Path>` at rustc_src/src/fs.rs:LL:CC - = note: inside `std::fs::File::open::<&str>` at rustc_src/src/fs.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/sys/PLATFORM/fs.rs:LL:CC + = note: inside `std::sys::PLATFORM::cvt_r::` at RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC + = note: inside `std::sys::PLATFORM::fs::File::open_c` at RUSTLIB/std/src/sys/PLATFORM/fs.rs:LL:CC + = note: inside `std::sys::PLATFORM::fs::File::open` at RUSTLIB/std/src/sys/PLATFORM/fs.rs:LL:CC + = note: inside `std::fs::OpenOptions::_open` at RUSTLIB/std/src/fs.rs:LL:CC + = note: inside `std::fs::OpenOptions::open::<&std::path::Path>` at RUSTLIB/std/src/fs.rs:LL:CC + = note: inside `std::fs::File::open::<&str>` at RUSTLIB/std/src/fs.rs:LL:CC note: inside `main` at $DIR/isolated_file.rs:LL:CC --> $DIR/isolated_file.rs:LL:CC | diff --git a/tests/compile-fail/generator-pinned-moved.stderr b/tests/compile-fail/generator-pinned-moved.stderr index 56bfc6092b7e..0ccf3091cde7 100644 --- a/tests/compile-fail/generator-pinned-moved.stderr +++ b/tests/compile-fail/generator-pinned-moved.stderr @@ -13,7 +13,7 @@ note: inside `> as std::iter::Iterator>::next` at rustc_src/src/boxed.rs:LL:CC + = note: inside `> as std::iter::Iterator>::next` at RUSTLIB/alloc/src/boxed.rs:LL:CC note: inside `main` at $DIR/generator-pinned-moved.rs:LL:CC --> $DIR/generator-pinned-moved.rs:LL:CC | diff --git a/tests/compile-fail/intrinsics/copy_overflow.stderr b/tests/compile-fail/intrinsics/copy_overflow.stderr index 512184a36c18..897ea5ffec5e 100644 --- a/tests/compile-fail/intrinsics/copy_overflow.stderr +++ b/tests/compile-fail/intrinsics/copy_overflow.stderr @@ -1,10 +1,14 @@ error: Undefined Behavior: overflow computing total size of `copy` + --> RUSTLIB/core/src/intrinsics.rs:LL:CC + | +LL | copy(src, dst, count) + | ^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::intrinsics::copy::` at rustc_src/src/intrinsics.rs:LL:CC - = note: inside `std::ptr::mut_ptr::::copy_from` at rustc_src/src/ptr/mut_ptr.rs:LL:CC + = note: inside `std::intrinsics::copy::` at RUSTLIB/core/src/intrinsics.rs:LL:CC + = note: inside `std::ptr::mut_ptr::::copy_from` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC note: inside `main` at $DIR/copy_overflow.rs:LL:CC --> $DIR/copy_overflow.rs:LL:CC | diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_1.stderr b/tests/compile-fail/intrinsics/out_of_bounds_ptr_1.stderr index 2b00876297fa..8a7da324ef89 100644 --- a/tests/compile-fail/intrinsics/out_of_bounds_ptr_1.stderr +++ b/tests/compile-fail/intrinsics/out_of_bounds_ptr_1.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: pointer arithmetic failed: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds + --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC + | +LL | unsafe { intrinsics::offset(self, count) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer arithmetic failed: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::ptr::const_ptr::::offset` at rustc_src/src/ptr/const_ptr.rs:LL:CC + = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC note: inside `main` at $DIR/out_of_bounds_ptr_1.rs:LL:CC --> $DIR/out_of_bounds_ptr_1.rs:LL:CC | diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_2.stderr b/tests/compile-fail/intrinsics/out_of_bounds_ptr_2.stderr index 32ac570f7231..78a17a2ab7b5 100644 --- a/tests/compile-fail/intrinsics/out_of_bounds_ptr_2.stderr +++ b/tests/compile-fail/intrinsics/out_of_bounds_ptr_2.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: overflowing in-bounds pointer arithmetic + --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC + | +LL | unsafe { intrinsics::offset(self, count) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing in-bounds pointer arithmetic | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::ptr::const_ptr::::offset` at rustc_src/src/ptr/const_ptr.rs:LL:CC + = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC note: inside `main` at $DIR/out_of_bounds_ptr_2.rs:LL:CC --> $DIR/out_of_bounds_ptr_2.rs:LL:CC | diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_3.stderr b/tests/compile-fail/intrinsics/out_of_bounds_ptr_3.stderr index cd48112cb430..9866529eeeb5 100644 --- a/tests/compile-fail/intrinsics/out_of_bounds_ptr_3.stderr +++ b/tests/compile-fail/intrinsics/out_of_bounds_ptr_3.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: pointer arithmetic failed: ALLOC has size 4, so pointer to 1 byte starting at offset -1 is out-of-bounds + --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC + | +LL | unsafe { intrinsics::offset(self, count) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer arithmetic failed: ALLOC has size 4, so pointer to 1 byte starting at offset -1 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::ptr::const_ptr::::offset` at rustc_src/src/ptr/const_ptr.rs:LL:CC + = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC note: inside `main` at $DIR/out_of_bounds_ptr_3.rs:LL:CC --> $DIR/out_of_bounds_ptr_3.rs:LL:CC | diff --git a/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.stderr b/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.stderr index d3e2fe4013f4..741314ea8a68 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.stderr +++ b/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: pointer arithmetic failed: null pointer is not a valid pointer + --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC + | +LL | unsafe { intrinsics::offset(self, count) as *mut T } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer arithmetic failed: null pointer is not a valid pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::ptr::mut_ptr::::offset` at rustc_src/src/ptr/mut_ptr.rs:LL:CC + = note: inside `std::ptr::mut_ptr::::offset` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC note: inside `main` at $DIR/ptr_offset_0_plus_0.rs:LL:CC --> $DIR/ptr_offset_0_plus_0.rs:LL:CC | diff --git a/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.stderr b/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.stderr index a47ed4719d90..e6b8f102f394 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.stderr +++ b/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: pointer arithmetic failed: 0x1 is not a valid pointer + --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC + | +LL | unsafe { intrinsics::offset(self, count) as *mut T } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer arithmetic failed: 0x1 is not a valid pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::ptr::mut_ptr::::offset` at rustc_src/src/ptr/mut_ptr.rs:LL:CC + = note: inside `std::ptr::mut_ptr::::offset` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC note: inside `main` at $DIR/ptr_offset_int_plus_int.rs:LL:CC --> $DIR/ptr_offset_int_plus_int.rs:LL:CC | diff --git a/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.stderr b/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.stderr index 58b33e706d3e..f88ad758d438 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.stderr +++ b/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: pointer arithmetic failed: 0x1 is not a valid pointer + --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC + | +LL | unsafe { intrinsics::offset(self, count) as *mut T } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer arithmetic failed: 0x1 is not a valid pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::ptr::mut_ptr::::offset` at rustc_src/src/ptr/mut_ptr.rs:LL:CC + = note: inside `std::ptr::mut_ptr::::offset` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC note: inside `main` at $DIR/ptr_offset_int_plus_ptr.rs:LL:CC --> $DIR/ptr_offset_int_plus_ptr.rs:LL:CC | diff --git a/tests/compile-fail/intrinsics/ptr_offset_overflow.stderr b/tests/compile-fail/intrinsics/ptr_offset_overflow.stderr index 81ff87168c12..a144141c3c38 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_overflow.stderr +++ b/tests/compile-fail/intrinsics/ptr_offset_overflow.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: overflowing in-bounds pointer arithmetic + --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC + | +LL | unsafe { intrinsics::offset(self, count) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing in-bounds pointer arithmetic | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::ptr::const_ptr::::offset` at rustc_src/src/ptr/const_ptr.rs:LL:CC + = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC note: inside `main` at $DIR/ptr_offset_overflow.rs:LL:CC --> $DIR/ptr_offset_overflow.rs:LL:CC | diff --git a/tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.stderr b/tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.stderr index 686ab1796647..15e21ee676f7 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.stderr +++ b/tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: pointer arithmetic failed: ALLOC has size 4, so pointer at offset 32 is out-of-bounds + --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC + | +LL | unsafe { intrinsics::offset(self, count) as *mut T } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer arithmetic failed: ALLOC has size 4, so pointer at offset 32 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::ptr::mut_ptr::::offset` at rustc_src/src/ptr/mut_ptr.rs:LL:CC + = note: inside `std::ptr::mut_ptr::::offset` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC note: inside `main` at $DIR/ptr_offset_ptr_plus_0.rs:LL:CC --> $DIR/ptr_offset_ptr_plus_0.rs:LL:CC | diff --git a/tests/compile-fail/intrinsics/simd-float-to-int.stderr b/tests/compile-fail/intrinsics/simd-float-to-int.stderr index 378c2b48bb93..6e6a136c39af 100644 --- a/tests/compile-fail/intrinsics/simd-float-to-int.stderr +++ b/tests/compile-fail/intrinsics/simd-float-to-int.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 3.40282347E+38 which cannot be represented in target type `i32` + --> RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/round.rs:LL:CC + | +LL | implement! { f32 } + | ^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 3.40282347E+38 which cannot be represented in target type `i32` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `core::core_simd::round::>::to_int_unchecked::` at rustc_src/src/../../portable-simd/crates/core_simd/src/round.rs:LL:CC + = note: inside `core::core_simd::round::>::to_int_unchecked::` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/round.rs:LL:CC note: inside `main` at $DIR/simd-float-to-int.rs:LL:CC --> $DIR/simd-float-to-int.rs:LL:CC | diff --git a/tests/compile-fail/intrinsics/simd-gather.stderr b/tests/compile-fail/intrinsics/simd-gather.stderr index 3da14e1fe375..8021077a92d3 100644 --- a/tests/compile-fail/intrinsics/simd-gather.stderr +++ b/tests/compile-fail/intrinsics/simd-gather.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 9, so pointer to 1 byte starting at offset 9 is out-of-bounds + --> RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC + | +LL | unsafe { intrinsics::simd_gather(or, ptrs, enable.to_int()) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 9, so pointer to 1 byte starting at offset 9 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::simd::Simd::::gather_select_unchecked` at rustc_src/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC + = note: inside `std::simd::Simd::::gather_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC note: inside `main` at $DIR/simd-gather.rs:LL:CC --> $DIR/simd-gather.rs:LL:CC | diff --git a/tests/compile-fail/intrinsics/simd-scatter.stderr b/tests/compile-fail/intrinsics/simd-scatter.stderr index 2d2cc2972ab3..08536c611255 100644 --- a/tests/compile-fail/intrinsics/simd-scatter.stderr +++ b/tests/compile-fail/intrinsics/simd-scatter.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 9, so pointer to 1 byte starting at offset 9 is out-of-bounds + --> RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC + | +LL | intrinsics::simd_scatter(self, ptrs, enable.to_int()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 9, so pointer to 1 byte starting at offset 9 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::simd::Simd::::scatter_select_unchecked` at rustc_src/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC + = note: inside `std::simd::Simd::::scatter_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC note: inside `main` at $DIR/simd-scatter.rs:LL:CC --> $DIR/simd-scatter.rs:LL:CC | diff --git a/tests/compile-fail/intrinsics/write_bytes_overflow.stderr b/tests/compile-fail/intrinsics/write_bytes_overflow.stderr index 018ba83f53fb..0d5259dce2f4 100644 --- a/tests/compile-fail/intrinsics/write_bytes_overflow.stderr +++ b/tests/compile-fail/intrinsics/write_bytes_overflow.stderr @@ -1,10 +1,14 @@ error: Undefined Behavior: overflow computing total size of `write_bytes` + --> RUSTLIB/core/src/intrinsics.rs:LL:CC + | +LL | write_bytes(dst, val, count) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `write_bytes` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::intrinsics::write_bytes::` at rustc_src/src/intrinsics.rs:LL:CC - = note: inside `std::ptr::mut_ptr::::write_bytes` at rustc_src/src/ptr/mut_ptr.rs:LL:CC + = note: inside `std::intrinsics::write_bytes::` at RUSTLIB/core/src/intrinsics.rs:LL:CC + = note: inside `std::ptr::mut_ptr::::write_bytes` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC note: inside `main` at $DIR/write_bytes_overflow.rs:LL:CC --> $DIR/write_bytes_overflow.rs:LL:CC | diff --git a/tests/compile-fail/invalid_enum_tag.stderr b/tests/compile-fail/invalid_enum_tag.stderr index a602204cf46b..b5e93d320a86 100644 --- a/tests/compile-fail/invalid_enum_tag.stderr +++ b/tests/compile-fail/invalid_enum_tag.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: enum value has invalid tag: $HEX + --> RUSTLIB/core/src/mem/mod.rs:LL:CC + | +LL | Discriminant(intrinsics::discriminant_value(v)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ enum value has invalid tag: $HEX | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::mem::discriminant::` at rustc_src/src/mem/mod.rs:LL:CC + = note: inside `std::mem::discriminant::` at RUSTLIB/core/src/mem/mod.rs:LL:CC note: inside `main` at $DIR/invalid_enum_tag.rs:LL:CC --> $DIR/invalid_enum_tag.rs:LL:CC | diff --git a/tests/compile-fail/panic/bad_unwind.stderr b/tests/compile-fail/panic/bad_unwind.stderr index 5030391bc6ea..745cef8be702 100644 --- a/tests/compile-fail/panic/bad_unwind.stderr +++ b/tests/compile-fail/panic/bad_unwind.stderr @@ -10,9 +10,9 @@ LL | std::panic::catch_unwind(|| unwind()).unwrap_err(); = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: inside closure at $DIR/bad_unwind.rs:LL:CC - = note: inside `std::panicking::r#try::do_call::<[closure@$DIR/bad_unwind.rs:LL:CC], ()>` at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::panicking::r#try::<(), [closure@$DIR/bad_unwind.rs:LL:CC]>` at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::panic::catch_unwind::<[closure@$DIR/bad_unwind.rs:LL:CC], ()>` at rustc_src/src/panic.rs:LL:CC + = note: inside `std::panicking::r#try::do_call::<[closure@$DIR/bad_unwind.rs:LL:CC], ()>` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::panicking::r#try::<(), [closure@$DIR/bad_unwind.rs:LL:CC]>` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::panic::catch_unwind::<[closure@$DIR/bad_unwind.rs:LL:CC], ()>` at RUSTLIB/std/src/panic.rs:LL:CC note: inside `main` at $DIR/bad_unwind.rs:LL:CC --> $DIR/bad_unwind.rs:LL:CC | diff --git a/tests/compile-fail/panic/double_panic.stderr b/tests/compile-fail/panic/double_panic.stderr index b854a6b72158..9cdba65c0a82 100644 --- a/tests/compile-fail/panic/double_panic.stderr +++ b/tests/compile-fail/panic/double_panic.stderr @@ -3,81 +3,85 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace thread 'main' panicked at 'second', $DIR/double_panic.rs:LL:CC stack backtrace: 0: std::backtrace_rs::backtrace::miri::trace_unsynchronized - at rustc_src/src/../../backtrace/src/backtrace/miri.rs:LL:CC + at RUSTLIB/std/src/../../backtrace/src/backtrace/miri.rs:LL:CC 1: std::backtrace_rs::backtrace::miri::trace - at rustc_src/src/../../backtrace/src/backtrace/miri.rs:LL:CC + at RUSTLIB/std/src/../../backtrace/src/backtrace/miri.rs:LL:CC 2: std::backtrace_rs::backtrace::trace_unsynchronized - at rustc_src/src/../../backtrace/src/backtrace/mod.rs:LL:CC + at RUSTLIB/std/src/../../backtrace/src/backtrace/mod.rs:LL:CC 3: std::sys_common::backtrace::_print_fmt - at rustc_src/src/sys_common/backtrace.rs:LL:CC + at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC 4: ::fmt - at rustc_src/src/sys_common/backtrace.rs:LL:CC + at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC 5: std::fmt::write - at rustc_src/src/fmt/mod.rs:LL:CC + at RUSTLIB/core/src/fmt/mod.rs:LL:CC 6: ::write_fmt - at rustc_src/src/io/mod.rs:LL:CC + at RUSTLIB/std/src/io/mod.rs:LL:CC 7: std::sys_common::backtrace::_print - at rustc_src/src/sys_common/backtrace.rs:LL:CC + at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC 8: std::sys_common::backtrace::print - at rustc_src/src/sys_common/backtrace.rs:LL:CC + at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC 9: std::panicking::default_hook::{closure#1} - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 10: std::panicking::default_hook - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 11: std::panicking::rust_panic_with_hook - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 12: std::rt::begin_panic::{closure#0} - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 13: std::sys_common::backtrace::__rust_end_short_backtrace - at rustc_src/src/sys_common/backtrace.rs:LL:CC + at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC 14: std::rt::begin_panic - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 15: ::drop at $DIR/double_panic.rs:LL:CC 16: std::ptr::drop_in_place - shim(Some(Foo)) - at rustc_src/src/ptr/mod.rs:LL:CC + at RUSTLIB/core/src/ptr/mod.rs:LL:CC 17: main at $DIR/double_panic.rs:LL:CC 18: >::call_once - shim(fn()) - at rustc_src/src/ops/function.rs:LL:CC + at RUSTLIB/core/src/ops/function.rs:LL:CC 19: std::sys_common::backtrace::__rust_begin_short_backtrace - at rustc_src/src/sys_common/backtrace.rs:LL:CC + at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC 20: std::rt::lang_start::{closure#0} - at rustc_src/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC 21: std::ops::function::impls::call_once - at rustc_src/src/ops/function.rs:LL:CC + at RUSTLIB/core/src/ops/function.rs:LL:CC 22: std::panicking::r#try::do_call - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 23: std::panicking::r#try - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 24: std::panic::catch_unwind - at rustc_src/src/panic.rs:LL:CC + at RUSTLIB/std/src/panic.rs:LL:CC 25: std::rt::lang_start_internal::{closure#2} - at rustc_src/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC 26: std::panicking::r#try::do_call - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 27: std::panicking::r#try - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 28: std::panic::catch_unwind - at rustc_src/src/panic.rs:LL:CC + at RUSTLIB/std/src/panic.rs:LL:CC 29: std::rt::lang_start_internal - at rustc_src/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC 30: std::rt::lang_start - at rustc_src/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC thread panicked while panicking. aborting. error: abnormal termination: the program aborted execution + --> RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC | - = note: inside `std::sys::PLATFORM::abort_internal` at rustc_src/src/sys/PLATFORM/mod.rs:LL:CC - = note: inside `std::panicking::rust_panic_with_hook` at rustc_src/src/panicking.rs:LL:CC - = note: inside closure at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::rt::begin_panic<&str>::{closure#0}], !>` at rustc_src/src/sys_common/backtrace.rs:LL:CC - = note: inside `std::rt::begin_panic::<&str>` at rustc_src/src/panicking.rs:LL:CC -note: inside `::drop` at rustc_src/src/panic.rs:LL:CC +LL | unsafe { libc::abort() } + | ^^^^^^^^^^^^^ the program aborted execution + | + = note: inside `std::sys::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC + = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::rt::begin_panic<&str>::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::rt::begin_panic::<&str>` at RUSTLIB/std/src/panicking.rs:LL:CC +note: inside `::drop` at RUSTLIB/std/src/panic.rs:LL:CC --> $DIR/double_panic.rs:LL:CC | LL | panic!("second"); | ^^^^^^^^^^^^^^^^ - = note: inside `std::ptr::drop_in_place:: - shim(Some(Foo))` at rustc_src/src/ptr/mod.rs:LL:CC + = note: inside `std::ptr::drop_in_place:: - shim(Some(Foo))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC note: inside `main` at $DIR/double_panic.rs:LL:CC --> $DIR/double_panic.rs:LL:CC | diff --git a/tests/compile-fail/panic/panic_abort1.stderr b/tests/compile-fail/panic/panic_abort1.stderr index 93f48bb89e3b..79e1f29ef8aa 100644 --- a/tests/compile-fail/panic/panic_abort1.stderr +++ b/tests/compile-fail/panic/panic_abort1.stderr @@ -1,15 +1,19 @@ thread 'main' panicked at 'panicking from libstd', $DIR/panic_abort1.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: abnormal termination: the program aborted execution + --> RUSTLIB/panic_abort/src/lib.rs:LL:CC | - = note: inside `panic_abort::__rust_start_panic::abort` at rustc_src/src/lib.rs:LL:CC - = note: inside `panic_abort::__rust_start_panic` at rustc_src/src/lib.rs:LL:CC - = note: inside `std::panicking::rust_panic` at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::panicking::rust_panic_with_hook` at rustc_src/src/panicking.rs:LL:CC - = note: inside closure at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::rt::begin_panic<&str>::{closure#0}], !>` at rustc_src/src/sys_common/backtrace.rs:LL:CC - = note: inside `std::rt::begin_panic::<&str>` at rustc_src/src/panicking.rs:LL:CC -note: inside `main` at rustc_src/src/panic.rs:LL:CC +LL | libc::abort(); + | ^^^^^^^^^^^^^ the program aborted execution + | + = note: inside `panic_abort::__rust_start_panic::abort` at RUSTLIB/panic_abort/src/lib.rs:LL:CC + = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC + = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::rt::begin_panic<&str>::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::rt::begin_panic::<&str>` at RUSTLIB/std/src/panicking.rs:LL:CC +note: inside `main` at RUSTLIB/std/src/panic.rs:LL:CC --> $DIR/panic_abort1.rs:LL:CC | LL | std::panic!("panicking from libstd"); diff --git a/tests/compile-fail/panic/panic_abort2.stderr b/tests/compile-fail/panic/panic_abort2.stderr index bb4b96fd0aeb..3cd08ab645e8 100644 --- a/tests/compile-fail/panic/panic_abort2.stderr +++ b/tests/compile-fail/panic/panic_abort2.stderr @@ -1,16 +1,20 @@ thread 'main' panicked at '42-panicking from libstd', $DIR/panic_abort2.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: abnormal termination: the program aborted execution + --> RUSTLIB/panic_abort/src/lib.rs:LL:CC | - = note: inside `panic_abort::__rust_start_panic::abort` at rustc_src/src/lib.rs:LL:CC - = note: inside `panic_abort::__rust_start_panic` at rustc_src/src/lib.rs:LL:CC - = note: inside `std::panicking::rust_panic` at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::panicking::rust_panic_with_hook` at rustc_src/src/panicking.rs:LL:CC - = note: inside closure at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at rustc_src/src/sys_common/backtrace.rs:LL:CC - = note: inside `std::panicking::begin_panic_handler` at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::rt::panic_fmt` at rustc_src/src/panicking.rs:LL:CC -note: inside `main` at rustc_src/src/panic.rs:LL:CC +LL | libc::abort(); + | ^^^^^^^^^^^^^ the program aborted execution + | + = note: inside `panic_abort::__rust_start_panic::abort` at RUSTLIB/panic_abort/src/lib.rs:LL:CC + = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC + = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::rt::panic_fmt` at RUSTLIB/core/src/panicking.rs:LL:CC +note: inside `main` at RUSTLIB/std/src/panic.rs:LL:CC --> $DIR/panic_abort2.rs:LL:CC | LL | std::panic!("{}-panicking from libstd", 42); diff --git a/tests/compile-fail/panic/panic_abort3.stderr b/tests/compile-fail/panic/panic_abort3.stderr index a799ce4b4de9..f6e8b16df961 100644 --- a/tests/compile-fail/panic/panic_abort3.stderr +++ b/tests/compile-fail/panic/panic_abort3.stderr @@ -1,17 +1,21 @@ thread 'main' panicked at 'panicking from libcore', $DIR/panic_abort3.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: abnormal termination: the program aborted execution + --> RUSTLIB/panic_abort/src/lib.rs:LL:CC | - = note: inside `panic_abort::__rust_start_panic::abort` at rustc_src/src/lib.rs:LL:CC - = note: inside `panic_abort::__rust_start_panic` at rustc_src/src/lib.rs:LL:CC - = note: inside `std::panicking::rust_panic` at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::panicking::rust_panic_with_hook` at rustc_src/src/panicking.rs:LL:CC - = note: inside closure at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at rustc_src/src/sys_common/backtrace.rs:LL:CC - = note: inside `std::panicking::begin_panic_handler` at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::rt::panic_fmt` at rustc_src/src/panicking.rs:LL:CC - = note: inside `core::panicking::panic` at rustc_src/src/panicking.rs:LL:CC -note: inside `main` at rustc_src/src/panic.rs:LL:CC +LL | libc::abort(); + | ^^^^^^^^^^^^^ the program aborted execution + | + = note: inside `panic_abort::__rust_start_panic::abort` at RUSTLIB/panic_abort/src/lib.rs:LL:CC + = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC + = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::rt::panic_fmt` at RUSTLIB/core/src/panicking.rs:LL:CC + = note: inside `core::panicking::panic` at RUSTLIB/core/src/panicking.rs:LL:CC +note: inside `main` at RUSTLIB/core/src/panic.rs:LL:CC --> $DIR/panic_abort3.rs:LL:CC | LL | core::panic!("panicking from libcore"); diff --git a/tests/compile-fail/panic/panic_abort4.stderr b/tests/compile-fail/panic/panic_abort4.stderr index a24d0948d1cf..39fe03a2e027 100644 --- a/tests/compile-fail/panic/panic_abort4.stderr +++ b/tests/compile-fail/panic/panic_abort4.stderr @@ -1,16 +1,20 @@ thread 'main' panicked at '42-panicking from libcore', $DIR/panic_abort4.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: abnormal termination: the program aborted execution + --> RUSTLIB/panic_abort/src/lib.rs:LL:CC | - = note: inside `panic_abort::__rust_start_panic::abort` at rustc_src/src/lib.rs:LL:CC - = note: inside `panic_abort::__rust_start_panic` at rustc_src/src/lib.rs:LL:CC - = note: inside `std::panicking::rust_panic` at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::panicking::rust_panic_with_hook` at rustc_src/src/panicking.rs:LL:CC - = note: inside closure at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at rustc_src/src/sys_common/backtrace.rs:LL:CC - = note: inside `std::panicking::begin_panic_handler` at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::rt::panic_fmt` at rustc_src/src/panicking.rs:LL:CC -note: inside `main` at rustc_src/src/panic.rs:LL:CC +LL | libc::abort(); + | ^^^^^^^^^^^^^ the program aborted execution + | + = note: inside `panic_abort::__rust_start_panic::abort` at RUSTLIB/panic_abort/src/lib.rs:LL:CC + = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC + = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::rt::panic_fmt` at RUSTLIB/core/src/panicking.rs:LL:CC +note: inside `main` at RUSTLIB/core/src/panic.rs:LL:CC --> $DIR/panic_abort4.rs:LL:CC | LL | core::panic!("{}-panicking from libcore", 42); diff --git a/tests/compile-fail/provenance/strict-provenance-offset.stderr b/tests/compile-fail/provenance/strict-provenance-offset.stderr index 482b7a404c51..8e3daca939db 100644 --- a/tests/compile-fail/provenance/strict-provenance-offset.stderr +++ b/tests/compile-fail/provenance/strict-provenance-offset.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: pointer arithmetic failed: $HEX is not a valid pointer + --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC + | +LL | unsafe { intrinsics::offset(self, count) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer arithmetic failed: $HEX is not a valid pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::ptr::const_ptr::::offset` at rustc_src/src/ptr/const_ptr.rs:LL:CC + = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC note: inside `main` at $DIR/strict-provenance-offset.rs:LL:CC --> $DIR/strict-provenance-offset.rs:LL:CC | diff --git a/tests/compile-fail/rc_as_ptr.stderr b/tests/compile-fail/rc_as_ptr.stderr index 3d745b7dc5c9..d4864da04e41 100644 --- a/tests/compile-fail/rc_as_ptr.stderr +++ b/tests/compile-fail/rc_as_ptr.stderr @@ -7,7 +7,7 @@ LL | assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `main` at rustc_src/src/macros/mod.rs:LL:CC + = note: inside `main` at RUSTLIB/core/src/macros/mod.rs:LL:CC = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier1.stderr b/tests/compile-fail/stacked_borrows/deallocate_against_barrier1.stderr index 804bb0f92af8..38b84e638be4 100644 --- a/tests/compile-fail/stacked_borrows/deallocate_against_barrier1.stderr +++ b/tests/compile-fail/stacked_borrows/deallocate_against_barrier1.stderr @@ -1,19 +1,23 @@ error: Undefined Behavior: deallocating while item is protected: [Unique for (call ID)] + --> RUSTLIB/alloc/src/alloc.rs:LL:CC + | +LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item is protected: [Unique for (call ID)] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - = note: inside `std::alloc::dealloc` at rustc_src/src/alloc.rs:LL:CC - = note: inside `::deallocate` at rustc_src/src/alloc.rs:LL:CC - = note: inside `alloc::alloc::box_free::` at rustc_src/src/alloc.rs:LL:CC - = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at rustc_src/src/ptr/mod.rs:LL:CC - = note: inside `std::mem::drop::>` at rustc_src/src/mem/mod.rs:LL:CC + = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC + = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC + = note: inside `alloc::alloc::box_free::` at RUSTLIB/alloc/src/alloc.rs:LL:CC + = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC + = note: inside `std::mem::drop::>` at RUSTLIB/core/src/mem/mod.rs:LL:CC note: inside closure at $DIR/deallocate_against_barrier1.rs:LL:CC --> $DIR/deallocate_against_barrier1.rs:LL:CC | LL | drop(unsafe { Box::from_raw(raw) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: inside `<[closure@$DIR/deallocate_against_barrier1.rs:LL:CC] as std::ops::FnOnce<(&mut i32,)>>::call_once - shim` at rustc_src/src/ops/function.rs:LL:CC + = note: inside `<[closure@$DIR/deallocate_against_barrier1.rs:LL:CC] as std::ops::FnOnce<(&mut i32,)>>::call_once - shim` at RUSTLIB/core/src/ops/function.rs:LL:CC note: inside `inner` at $DIR/deallocate_against_barrier1.rs:LL:CC --> $DIR/deallocate_against_barrier1.rs:LL:CC | diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.stderr b/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.stderr index 41a32a6280a7..72e6814b8e14 100644 --- a/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.stderr +++ b/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.stderr @@ -1,19 +1,23 @@ error: Undefined Behavior: deallocating while item is protected: [SharedReadWrite for (call ID)] + --> RUSTLIB/alloc/src/alloc.rs:LL:CC + | +LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item is protected: [SharedReadWrite for (call ID)] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - = note: inside `std::alloc::dealloc` at rustc_src/src/alloc.rs:LL:CC - = note: inside `::deallocate` at rustc_src/src/alloc.rs:LL:CC - = note: inside `alloc::alloc::box_free::, std::alloc::Global>` at rustc_src/src/alloc.rs:LL:CC - = note: inside `std::ptr::drop_in_place::>> - shim(Some(std::boxed::Box>))` at rustc_src/src/ptr/mod.rs:LL:CC - = note: inside `std::mem::drop::>>` at rustc_src/src/mem/mod.rs:LL:CC + = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC + = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC + = note: inside `alloc::alloc::box_free::, std::alloc::Global>` at RUSTLIB/alloc/src/alloc.rs:LL:CC + = note: inside `std::ptr::drop_in_place::>> - shim(Some(std::boxed::Box>))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC + = note: inside `std::mem::drop::>>` at RUSTLIB/core/src/mem/mod.rs:LL:CC note: inside closure at $DIR/deallocate_against_barrier2.rs:LL:CC --> $DIR/deallocate_against_barrier2.rs:LL:CC | LL | drop(unsafe { Box::from_raw(raw) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: inside `<[closure@$DIR/deallocate_against_barrier2.rs:LL:CC] as std::ops::FnOnce<(&std::cell::Cell,)>>::call_once - shim` at rustc_src/src/ops/function.rs:LL:CC + = note: inside `<[closure@$DIR/deallocate_against_barrier2.rs:LL:CC] as std::ops::FnOnce<(&std::cell::Cell,)>>::call_once - shim` at RUSTLIB/core/src/ops/function.rs:LL:CC note: inside `inner` at $DIR/deallocate_against_barrier2.rs:LL:CC --> $DIR/deallocate_against_barrier2.rs:LL:CC | diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-1.stderr b/tests/compile-fail/stacked_borrows/issue-miri-1050-1.stderr index 70c774818bce..b4953f95181a 100644 --- a/tests/compile-fail/stacked_borrows/issue-miri-1050-1.stderr +++ b/tests/compile-fail/stacked_borrows/issue-miri-1050-1.stderr @@ -1,10 +1,14 @@ error: Undefined Behavior: ALLOC has size 2, so pointer to 4 bytes starting at offset 0 is out-of-bounds + --> RUSTLIB/alloc/src/boxed.rs:LL:CC + | +LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ALLOC has size 2, so pointer to 4 bytes starting at offset 0 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::boxed::Box::::from_raw_in` at rustc_src/src/boxed.rs:LL:CC - = note: inside `std::boxed::Box::::from_raw` at rustc_src/src/boxed.rs:LL:CC + = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC + = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC note: inside `main` at $DIR/issue-miri-1050-1.rs:LL:CC --> $DIR/issue-miri-1050-1.rs:LL:CC | diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-2.stderr b/tests/compile-fail/stacked_borrows/issue-miri-1050-2.stderr index 579f728b2b07..cd6cfc0ecc3a 100644 --- a/tests/compile-fail/stacked_borrows/issue-miri-1050-2.stderr +++ b/tests/compile-fail/stacked_borrows/issue-miri-1050-2.stderr @@ -1,10 +1,14 @@ error: Undefined Behavior: 0x4 is not a valid pointer + --> RUSTLIB/alloc/src/boxed.rs:LL:CC + | +LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 0x4 is not a valid pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::boxed::Box::::from_raw_in` at rustc_src/src/boxed.rs:LL:CC - = note: inside `std::boxed::Box::::from_raw` at rustc_src/src/boxed.rs:LL:CC + = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC + = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC note: inside `main` at $DIR/issue-miri-1050-2.rs:LL:CC --> $DIR/issue-miri-1050-2.rs:LL:CC | diff --git a/tests/compile-fail/stacked_borrows/zst_slice.stderr b/tests/compile-fail/stacked_borrows/zst_slice.stderr index c6b4dc16b797..6809aa3d25fb 100644 --- a/tests/compile-fail/stacked_borrows/zst_slice.stderr +++ b/tests/compile-fail/stacked_borrows/zst_slice.stderr @@ -1,4 +1,11 @@ error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + --> RUSTLIB/core/src/slice/mod.rs:LL:CC + | +LL | unsafe { &*index.get_unchecked(self) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -7,7 +14,7 @@ help: was created by a retag at offsets [0x0..0x0] | LL | assert_eq!(*s.get_unchecked(1), 2); | ^^^^^^^^^^^^^^^^^^ - = note: inside `core::slice::::get_unchecked::` at rustc_src/src/slice/mod.rs:LL:CC + = note: inside `core::slice::::get_unchecked::` at RUSTLIB/core/src/slice/mod.rs:LL:CC note: inside `main` at $DIR/zst_slice.rs:LL:CC --> $DIR/zst_slice.rs:LL:CC | diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.stderr b/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.stderr index b858a291dea8..31f9163b3cf0 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.stderr +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.stderr @@ -7,7 +7,7 @@ LL | let _x = unsafe { ptr::addr_of!(*x) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `main` at rustc_src/src/ptr/mod.rs:LL:CC + = note: inside `main` at RUSTLIB/core/src/ptr/mod.rs:LL:CC = note: this error originates in the macro `ptr::addr_of` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/compile-fail/uninit_buffer.stderr b/tests/compile-fail/uninit_buffer.stderr index 903a1deee3fe..02e4bcb90be6 100644 --- a/tests/compile-fail/uninit_buffer.stderr +++ b/tests/compile-fail/uninit_buffer.stderr @@ -1,10 +1,14 @@ error: Undefined Behavior: reading 16 bytes of memory starting at ALLOC, but 12 bytes are uninitialized starting at ALLOC+0x4, and this operation requires initialized memory + --> RUSTLIB/core/src/slice/cmp.rs:LL:CC + | +LL | let mut order = unsafe { memcmp(left.as_ptr(), right.as_ptr(), len) as isize }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading 16 bytes of memory starting at ALLOC, but 12 bytes are uninitialized starting at ALLOC+0x4, and this operation requires initialized memory | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `::compare` at rustc_src/src/slice/cmp.rs:LL:CC - = note: inside `core::slice::cmp::::cmp` at rustc_src/src/slice/cmp.rs:LL:CC + = note: inside `::compare` at RUSTLIB/core/src/slice/cmp.rs:LL:CC + = note: inside `core::slice::cmp::::cmp` at RUSTLIB/core/src/slice/cmp.rs:LL:CC note: inside `main` at $DIR/uninit_buffer.rs:LL:CC --> $DIR/uninit_buffer.rs:LL:CC | diff --git a/tests/compile-fail/unreachable.stderr b/tests/compile-fail/unreachable.stderr index 59ab84331955..1cad7dd901b7 100644 --- a/tests/compile-fail/unreachable.stderr +++ b/tests/compile-fail/unreachable.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: entering unreachable code + --> RUSTLIB/core/src/hint.rs:LL:CC + | +LL | unsafe { intrinsics::unreachable() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::hint::unreachable_unchecked` at rustc_src/src/hint.rs:LL:CC + = note: inside `std::hint::unreachable_unchecked` at RUSTLIB/core/src/hint.rs:LL:CC note: inside `main` at $DIR/unreachable.rs:LL:CC --> $DIR/unreachable.rs:LL:CC | diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 3830b1c1bd54..3b6cf6a6d1fd 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -104,6 +104,8 @@ regexes! { "sys::[a-z]+::" => "sys::PLATFORM::", // Windows file paths r"\\" => "/", + // erase Rust stdlib path + "[^ `]*/(rust[^/]*|checkout)/library/" => "RUSTLIB/", // erase platform file paths "sys/[a-z]+/" => "sys/PLATFORM/", } diff --git a/tests/run-fail/panic/panic1.stderr b/tests/run-fail/panic/panic1.stderr index d4dcfc47a839..f86ce187b2c9 100644 --- a/tests/run-fail/panic/panic1.stderr +++ b/tests/run-fail/panic/panic1.stderr @@ -1,31 +1,31 @@ thread 'main' panicked at 'panicking from libstd', $DIR/panic1.rs:LL:CC stack backtrace: 0: std::rt::begin_panic - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 1: main at $DIR/panic1.rs:LL:CC 2: >::call_once - shim(fn()) - at rustc_src/src/ops/function.rs:LL:CC + at RUSTLIB/core/src/ops/function.rs:LL:CC 3: std::rt::lang_start::{closure#0} - at rustc_src/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC 4: std::ops::function::impls::call_once - at rustc_src/src/ops/function.rs:LL:CC + at RUSTLIB/core/src/ops/function.rs:LL:CC 5: std::panicking::r#try::do_call - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 6: std::panicking::r#try - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 7: std::panic::catch_unwind - at rustc_src/src/panic.rs:LL:CC + at RUSTLIB/std/src/panic.rs:LL:CC 8: std::rt::lang_start_internal::{closure#2} - at rustc_src/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC 9: std::panicking::r#try::do_call - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 10: std::panicking::r#try - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 11: std::panic::catch_unwind - at rustc_src/src/panic.rs:LL:CC + at RUSTLIB/std/src/panic.rs:LL:CC 12: std::rt::lang_start_internal - at rustc_src/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC 13: std::rt::lang_start - at rustc_src/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. diff --git a/tests/run-pass/backtrace-api-v0.stderr b/tests/run-pass/backtrace-api-v0.stderr index d81f5ad1d626..ee556b3e4a05 100644 --- a/tests/run-pass/backtrace-api-v0.stderr +++ b/tests/run-pass/backtrace-api-v0.stderr @@ -2,17 +2,4 @@ $DIR/backtrace-api-v0.rs:LL:CC (func_d) $DIR/backtrace-api-v0.rs:LL:CC (func_c) $DIR/backtrace-api-v0.rs:LL:CC (func_b) $DIR/backtrace-api-v0.rs:LL:CC (func_a) -$DIR/backtrace-api-v0.rs:LL:CC (main) -rustc_src/src/ops/function.rs:LL:CC (>::call_once - shim(fn())) -rustc_src/src/sys_common/backtrace.rs:LL:CC (std::sys_common::backtrace::__rust_begin_short_backtrace) -rustc_src/src/rt.rs:LL:CC (std::rt::lang_start::{closure#0}) -rustc_src/src/ops/function.rs:LL:CC (std::ops::function::impls::call_once) -rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try::do_call) -rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try) -rustc_src/src/panic.rs:LL:CC (std::panic::catch_unwind) -rustc_src/src/rt.rs:LL:CC (std::rt::lang_start_internal::{closure#2}) -rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try::do_call) -rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try) -rustc_src/src/panic.rs:LL:CC (std::panic::catch_unwind) -rustc_src/src/rt.rs:LL:CC (std::rt::lang_start_internal) -rustc_src/src/rt.rs:LL:CC (std::rt::lang_start) +$DIR/backtrace-api-v0.rs:LL:CC RUSTLIB/core/src/ops/function.rs:LL:CC (>::call_once - RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC (std::sys_common::backtrace::__rust_begin_short_backtrace) diff --git a/tests/run-pass/backtrace-api-v1.stderr b/tests/run-pass/backtrace-api-v1.stderr index 87c59f426968..7dc281af31dd 100644 --- a/tests/run-pass/backtrace-api-v1.stderr +++ b/tests/run-pass/backtrace-api-v1.stderr @@ -2,17 +2,4 @@ $DIR/backtrace-api-v1.rs:LL:CC (func_d) $DIR/backtrace-api-v1.rs:LL:CC (func_c) $DIR/backtrace-api-v1.rs:LL:CC (func_b) $DIR/backtrace-api-v1.rs:LL:CC (func_a) -$DIR/backtrace-api-v1.rs:LL:CC (main) -rustc_src/src/ops/function.rs:LL:CC (>::call_once - shim(fn())) -rustc_src/src/sys_common/backtrace.rs:LL:CC (std::sys_common::backtrace::__rust_begin_short_backtrace) -rustc_src/src/rt.rs:LL:CC (std::rt::lang_start::{closure#0}) -rustc_src/src/ops/function.rs:LL:CC (std::ops::function::impls::call_once) -rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try::do_call) -rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try) -rustc_src/src/panic.rs:LL:CC (std::panic::catch_unwind) -rustc_src/src/rt.rs:LL:CC (std::rt::lang_start_internal::{closure#2}) -rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try::do_call) -rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try) -rustc_src/src/panic.rs:LL:CC (std::panic::catch_unwind) -rustc_src/src/rt.rs:LL:CC (std::rt::lang_start_internal) -rustc_src/src/rt.rs:LL:CC (std::rt::lang_start) +$DIR/backtrace-api-v1.rs:LL:CC RUSTLIB/core/src/ops/function.rs:LL:CC (>::call_once - RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC (std::sys_common::backtrace::__rust_begin_short_backtrace) diff --git a/tests/run-pass/backtrace-std.stderr b/tests/run-pass/backtrace-std.stderr index 848ccaea1b62..4596cadb958d 100644 --- a/tests/run-pass/backtrace-std.stderr +++ b/tests/run-pass/backtrace-std.stderr @@ -9,28 +9,28 @@ 4: main at $DIR/backtrace-std.rs:LL:CC 5: >::call_once - shim(fn()) - at rustc_src/src/ops/function.rs:LL:CC + at RUSTLIB/core/src/ops/function.rs:LL:CC 6: std::sys_common::backtrace::__rust_begin_short_backtrace - at rustc_src/src/sys_common/backtrace.rs:LL:CC + at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC 7: std::rt::lang_start::{closure#0} - at rustc_src/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC 8: std::ops::function::impls::call_once - at rustc_src/src/ops/function.rs:LL:CC + at RUSTLIB/core/src/ops/function.rs:LL:CC 9: std::panicking::r#try::do_call - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 10: std::panicking::r#try - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 11: std::panic::catch_unwind - at rustc_src/src/panic.rs:LL:CC + at RUSTLIB/std/src/panic.rs:LL:CC 12: std::rt::lang_start_internal::{closure#2} - at rustc_src/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC 13: std::panicking::r#try::do_call - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 14: std::panicking::r#try - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 15: std::panic::catch_unwind - at rustc_src/src/panic.rs:LL:CC + at RUSTLIB/std/src/panic.rs:LL:CC 16: std::rt::lang_start_internal - at rustc_src/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC 17: std::rt::lang_start - at rustc_src/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr index 36a7818d2766..0ced5588cc12 100644 --- a/tests/run-pass/panic/catch_panic.stderr +++ b/tests/run-pass/panic/catch_panic.stderr @@ -17,7 +17,7 @@ thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4' Caught panic message (String): index out of bounds: the len is 3 but the index is 4 thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:LL:CC Caught panic message (&str): attempt to divide by zero -thread 'main' panicked at 'align_offset: align is not a power-of-two', rustc_src/src/ptr/const_ptr.rs:LL:CC +thread 'main' panicked at 'align_offset: align is not a power-of-two', RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC Caught panic message (&str): align_offset: align is not a power-of-two thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:LL:CC Caught panic message (&str): assertion failed: false From 8997db2ec99d980e827f8bb4ed212dce1d5e7e02 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 31 May 2022 19:00:14 -0400 Subject: [PATCH 3146/5092] paper over platform differences --- tests/compile-fail/alloc/global_system_mixup.rs | 2 ++ tests/compile-fail/alloc/global_system_mixup.stderr | 6 +++--- tests/compile-fail/panic/double_panic.rs | 2 ++ tests/compile-fail/panic/double_panic.stderr | 6 +++--- tests/compile-fail/panic/panic_abort1.rs | 2 ++ tests/compile-fail/panic/panic_abort1.stderr | 6 +++--- tests/compile-fail/panic/panic_abort2.rs | 2 ++ tests/compile-fail/panic/panic_abort2.stderr | 6 +++--- tests/compile-fail/panic/panic_abort3.rs | 2 ++ tests/compile-fail/panic/panic_abort3.stderr | 6 +++--- tests/compile-fail/panic/panic_abort4.rs | 2 ++ tests/compile-fail/panic/panic_abort4.stderr | 6 +++--- 12 files changed, 30 insertions(+), 18 deletions(-) diff --git a/tests/compile-fail/alloc/global_system_mixup.rs b/tests/compile-fail/alloc/global_system_mixup.rs index 3f58de4d6fb0..bb87b132f322 100644 --- a/tests/compile-fail/alloc/global_system_mixup.rs +++ b/tests/compile-fail/alloc/global_system_mixup.rs @@ -3,6 +3,8 @@ // error-pattern: which is Rust heap memory, using // normalize-stderr-test: "using [A-Za-z]+ heap deallocation operation" -> "using PLATFORM heap deallocation operation" +// normalize-stderr-test: "\| +\^+" -> "| ^" +// normalize-stderr-test: "libc::free\([^()]*\)|unsafe \{ HeapFree\([^()]*\) \};" -> "FREE();" #![feature(allocator_api, slice_ptr_get)] diff --git a/tests/compile-fail/alloc/global_system_mixup.stderr b/tests/compile-fail/alloc/global_system_mixup.stderr index 84d68be78cd1..a3b9009e3035 100644 --- a/tests/compile-fail/alloc/global_system_mixup.stderr +++ b/tests/compile-fail/alloc/global_system_mixup.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: deallocating ALLOC, which is Rust heap memory, using PLATFORM heap deallocation operation --> RUSTLIB/std/src/sys/PLATFORM/alloc.rs:LL:CC | -LL | libc::free(ptr as *mut libc::c_void) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating ALLOC, which is Rust heap memory, using PLATFORM heap deallocation operation +LL | FREE(); + | ^ deallocating ALLOC, which is Rust heap memory, using PLATFORM heap deallocation operation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information @@ -13,7 +13,7 @@ note: inside `main` at $DIR/global_system_mixup.rs:LL:CC --> $DIR/global_system_mixup.rs:LL:CC | LL | unsafe { System.deallocate(ptr, l); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/compile-fail/panic/double_panic.rs b/tests/compile-fail/panic/double_panic.rs index 670c037988c2..f3af66a79abc 100644 --- a/tests/compile-fail/panic/double_panic.rs +++ b/tests/compile-fail/panic/double_panic.rs @@ -1,4 +1,6 @@ // error-pattern: the program aborted +// normalize-stderr-test: "\| +\^+" -> "| ^" +// normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" struct Foo; impl Drop for Foo { diff --git a/tests/compile-fail/panic/double_panic.stderr b/tests/compile-fail/panic/double_panic.stderr index 9cdba65c0a82..0dbd68c0984f 100644 --- a/tests/compile-fail/panic/double_panic.stderr +++ b/tests/compile-fail/panic/double_panic.stderr @@ -68,8 +68,8 @@ thread panicked while panicking. aborting. error: abnormal termination: the program aborted execution --> RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC | -LL | unsafe { libc::abort() } - | ^^^^^^^^^^^^^ the program aborted execution +LL | ABORT(); + | ^ the program aborted execution | = note: inside `std::sys::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC @@ -80,7 +80,7 @@ note: inside `::drop` at RUSTLIB/std/src/panic.rs:LL:CC --> $DIR/double_panic.rs:LL:CC | LL | panic!("second"); - | ^^^^^^^^^^^^^^^^ + | ^ = note: inside `std::ptr::drop_in_place:: - shim(Some(Foo))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC note: inside `main` at $DIR/double_panic.rs:LL:CC --> $DIR/double_panic.rs:LL:CC diff --git a/tests/compile-fail/panic/panic_abort1.rs b/tests/compile-fail/panic/panic_abort1.rs index 095d9e3d75b0..9c094c659837 100644 --- a/tests/compile-fail/panic/panic_abort1.rs +++ b/tests/compile-fail/panic/panic_abort1.rs @@ -1,4 +1,6 @@ // error-pattern: the program aborted execution +// normalize-stderr-test: "\| +\^+" -> "| ^" +// normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();" // compile-flags: -C panic=abort fn main() { diff --git a/tests/compile-fail/panic/panic_abort1.stderr b/tests/compile-fail/panic/panic_abort1.stderr index 79e1f29ef8aa..9610a161280a 100644 --- a/tests/compile-fail/panic/panic_abort1.stderr +++ b/tests/compile-fail/panic/panic_abort1.stderr @@ -3,8 +3,8 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: abnormal termination: the program aborted execution --> RUSTLIB/panic_abort/src/lib.rs:LL:CC | -LL | libc::abort(); - | ^^^^^^^^^^^^^ the program aborted execution +LL | ABORT(); + | ^ the program aborted execution | = note: inside `panic_abort::__rust_start_panic::abort` at RUSTLIB/panic_abort/src/lib.rs:LL:CC = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC @@ -17,7 +17,7 @@ note: inside `main` at RUSTLIB/std/src/panic.rs:LL:CC --> $DIR/panic_abort1.rs:LL:CC | LL | std::panic!("panicking from libstd"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/compile-fail/panic/panic_abort2.rs b/tests/compile-fail/panic/panic_abort2.rs index de177bc4e716..7eb9a3c24aa2 100644 --- a/tests/compile-fail/panic/panic_abort2.rs +++ b/tests/compile-fail/panic/panic_abort2.rs @@ -1,4 +1,6 @@ // error-pattern: the program aborted execution +// normalize-stderr-test: "\| +\^+" -> "| ^" +// normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();" // compile-flags: -C panic=abort fn main() { diff --git a/tests/compile-fail/panic/panic_abort2.stderr b/tests/compile-fail/panic/panic_abort2.stderr index 3cd08ab645e8..0c446323a779 100644 --- a/tests/compile-fail/panic/panic_abort2.stderr +++ b/tests/compile-fail/panic/panic_abort2.stderr @@ -3,8 +3,8 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: abnormal termination: the program aborted execution --> RUSTLIB/panic_abort/src/lib.rs:LL:CC | -LL | libc::abort(); - | ^^^^^^^^^^^^^ the program aborted execution +LL | ABORT(); + | ^ the program aborted execution | = note: inside `panic_abort::__rust_start_panic::abort` at RUSTLIB/panic_abort/src/lib.rs:LL:CC = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC @@ -18,7 +18,7 @@ note: inside `main` at RUSTLIB/std/src/panic.rs:LL:CC --> $DIR/panic_abort2.rs:LL:CC | LL | std::panic!("{}-panicking from libstd", 42); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/compile-fail/panic/panic_abort3.rs b/tests/compile-fail/panic/panic_abort3.rs index 2d65da4fe341..1940b48bad78 100644 --- a/tests/compile-fail/panic/panic_abort3.rs +++ b/tests/compile-fail/panic/panic_abort3.rs @@ -1,4 +1,6 @@ // error-pattern: the program aborted execution +// normalize-stderr-test: "\| +\^+" -> "| ^" +// normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();" // compile-flags: -C panic=abort fn main() { diff --git a/tests/compile-fail/panic/panic_abort3.stderr b/tests/compile-fail/panic/panic_abort3.stderr index f6e8b16df961..2d7b576372e0 100644 --- a/tests/compile-fail/panic/panic_abort3.stderr +++ b/tests/compile-fail/panic/panic_abort3.stderr @@ -3,8 +3,8 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: abnormal termination: the program aborted execution --> RUSTLIB/panic_abort/src/lib.rs:LL:CC | -LL | libc::abort(); - | ^^^^^^^^^^^^^ the program aborted execution +LL | ABORT(); + | ^ the program aborted execution | = note: inside `panic_abort::__rust_start_panic::abort` at RUSTLIB/panic_abort/src/lib.rs:LL:CC = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC @@ -19,7 +19,7 @@ note: inside `main` at RUSTLIB/core/src/panic.rs:LL:CC --> $DIR/panic_abort3.rs:LL:CC | LL | core::panic!("panicking from libcore"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/compile-fail/panic/panic_abort4.rs b/tests/compile-fail/panic/panic_abort4.rs index 41d32a604fed..e5190ea0765d 100644 --- a/tests/compile-fail/panic/panic_abort4.rs +++ b/tests/compile-fail/panic/panic_abort4.rs @@ -1,4 +1,6 @@ // error-pattern: the program aborted execution +// normalize-stderr-test: "\| +\^+" -> "| ^" +// normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();" // compile-flags: -C panic=abort fn main() { diff --git a/tests/compile-fail/panic/panic_abort4.stderr b/tests/compile-fail/panic/panic_abort4.stderr index 39fe03a2e027..b0b11248104d 100644 --- a/tests/compile-fail/panic/panic_abort4.stderr +++ b/tests/compile-fail/panic/panic_abort4.stderr @@ -3,8 +3,8 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: abnormal termination: the program aborted execution --> RUSTLIB/panic_abort/src/lib.rs:LL:CC | -LL | libc::abort(); - | ^^^^^^^^^^^^^ the program aborted execution +LL | ABORT(); + | ^ the program aborted execution | = note: inside `panic_abort::__rust_start_panic::abort` at RUSTLIB/panic_abort/src/lib.rs:LL:CC = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC @@ -18,7 +18,7 @@ note: inside `main` at RUSTLIB/core/src/panic.rs:LL:CC --> $DIR/panic_abort4.rs:LL:CC | LL | core::panic!("{}-panicking from libcore", 42); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace From 81d661f1341905b7c012c0d2ec97697ec0bfc821 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 Jun 2022 06:28:27 -0400 Subject: [PATCH 3147/5092] bump xargo version, and tweak xargo caching --- .github/workflows/ci.yml | 5 +++-- cargo-miri/bin.rs | 5 +++-- cargo-miri/version.rs | 2 ++ 3 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 cargo-miri/version.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index edf74603b6e1..84bf54246e1d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,14 +57,15 @@ jobs: # contains package information of crates installed via `cargo install`. ~/.cargo/.crates.toml ~/.cargo/.crates2.json - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-xargo0.3.25 + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock', 'cargo-miri/version.rs') }} restore-keys: ${{ runner.os }}-cargo - name: Install rustup-toolchain-install-master and xargo shell: bash run: | cargo install rustup-toolchain-install-master - cargo install xargo + # Only install xargo if we don't have it cached + if ! which xargo; then cargo install xargo; fi - name: Install "master" toolchain shell: bash diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 373c63647c35..fd4af14e7ded 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -1,3 +1,5 @@ +mod version; + use std::env; use std::ffi::{OsStr, OsString}; use std::fmt::Write as _; @@ -9,10 +11,9 @@ use std::path::{Path, PathBuf}; use std::process::{self, Command}; use serde::{Deserialize, Serialize}; - use rustc_version::VersionMeta; -const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 23); +use version::*; const CARGO_MIRI_HELP: &str = r#"Runs binary crates and tests in Miri diff --git a/cargo-miri/version.rs b/cargo-miri/version.rs new file mode 100644 index 000000000000..366e90df1798 --- /dev/null +++ b/cargo-miri/version.rs @@ -0,0 +1,2 @@ +// We put this in a separate file so that it can be hashed for GHA caching. +pub const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 26); From 1571571e38a10c69d3fb43b88bfc84b5a3eeb62e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 Jun 2022 06:31:08 -0400 Subject: [PATCH 3148/5092] also avoid rebuilding cached RTIM --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 84bf54246e1d..8eeb3491d95e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -63,8 +63,8 @@ jobs: - name: Install rustup-toolchain-install-master and xargo shell: bash run: | - cargo install rustup-toolchain-install-master - # Only install xargo if we don't have it cached + # Only install tools if we don't have them cached + if ! which rustup-toolchain-install-master; then cargo install rustup-toolchain-install-master; fi if ! which xargo; then cargo install xargo; fi - name: Install "master" toolchain From 61265f5f19d1537ba184bd13bd5d83c533bf30cd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 Jun 2022 06:42:11 -0400 Subject: [PATCH 3149/5092] fmt --- cargo-miri/bin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index fd4af14e7ded..34904279e94f 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -10,8 +10,8 @@ use std::ops::Not; use std::path::{Path, PathBuf}; use std::process::{self, Command}; -use serde::{Deserialize, Serialize}; use rustc_version::VersionMeta; +use serde::{Deserialize, Serialize}; use version::*; From 4f700938053eb582f1812a804dabe30c65d7f546 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 Jun 2022 06:45:09 -0400 Subject: [PATCH 3150/5092] advanced GHA --- .github/workflows/ci.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8eeb3491d95e..f34e92571ff0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,7 +46,8 @@ jobs: # we cannot reuse anyway when the nightly changes (and it grows quite large # over time). - name: Add cache for cargo - uses: actions/cache@v2 + id: cache + uses: actions/cache@v3 with: path: | # Taken from . @@ -61,11 +62,11 @@ jobs: restore-keys: ${{ runner.os }}-cargo - name: Install rustup-toolchain-install-master and xargo + if: ${{ steps.cache.outputs.cache-hit == 'false' }} shell: bash run: | - # Only install tools if we don't have them cached - if ! which rustup-toolchain-install-master; then cargo install rustup-toolchain-install-master; fi - if ! which xargo; then cargo install xargo; fi + cargo install rustup-toolchain-install-master + cargo install xargo - name: Install "master" toolchain shell: bash From 4b100a1b58767a4fd5884355072e27a42892babc Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 30 May 2022 12:17:36 +0000 Subject: [PATCH 3151/5092] Check that diagnostics happen in the line that they are annotated for --- Cargo.lock | 45 +++ src/bin/miri.rs | 11 +- tests/compile-fail/intrinsics/assume.rs | 2 +- tests/compile-fail/no_main.stderr | 2 + .../sync/libc_pthread_cond_double_destroy.rs | 2 +- .../libc_pthread_condattr_double_destroy.rs | 2 +- .../sync/libc_pthread_mutex_double_destroy.rs | 2 +- .../libc_pthread_mutexattr_double_destroy.rs | 2 +- .../libc_pthread_rwlock_double_destroy.rs | 2 +- ui_test/Cargo.lock | 45 +++ ui_test/Cargo.toml | 2 + ui_test/README.md | 6 +- ui_test/src/comments.rs | 36 +- ui_test/src/comments/tests.rs | 2 +- ui_test/src/lib.rs | 193 ++++++++--- ui_test/src/rustc_stderr.rs | 152 +++++++++ ui_test/src/tests.rs | 308 ++++++++++++++++-- 17 files changed, 737 insertions(+), 77 deletions(-) create mode 100644 ui_test/src/rustc_stderr.rs diff --git a/Cargo.lock b/Cargo.lock index 5377f9420b7c..29b7e0bec26a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -193,6 +193,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + [[package]] name = "lazy_static" version = "1.4.0" @@ -446,6 +452,12 @@ dependencies = [ "semver", ] +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + [[package]] name = "scopeguard" version = "1.1.0" @@ -458,6 +470,37 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" +[[package]] +name = "serde" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "shell-escape" version = "0.1.5" @@ -500,6 +543,8 @@ dependencies = [ "pretty_assertions", "regex", "rustc_version", + "serde", + "serde_json", ] [[package]] diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 9c4cd0684c61..2cf5bc644dbf 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -19,7 +19,6 @@ use log::debug; use rustc_data_structures::sync::Lrc; use rustc_driver::Compilation; -use rustc_errors::emitter::{ColorConfig, HumanReadableErrorType}; use rustc_hir::{self as hir, def_id::LOCAL_CRATE, Node}; use rustc_interface::interface::Config; use rustc_middle::{ @@ -28,7 +27,7 @@ use rustc_middle::{ }, ty::{query::ExternProviders, TyCtxt}, }; -use rustc_session::{config::ErrorOutputType, search_paths::PathKind, CtfeBacktrace}; +use rustc_session::{search_paths::PathKind, CtfeBacktrace}; use miri::{BacktraceStyle, ProvenanceMode}; @@ -64,13 +63,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { let (entry_def_id, entry_type) = if let Some(entry_def) = tcx.entry_fn(()) { entry_def } else { - let output_ty = ErrorOutputType::HumanReadable(HumanReadableErrorType::Default( - ColorConfig::Auto, - )); - rustc_session::early_error( - output_ty, - "miri can only run programs that have a main function", - ); + tcx.sess.fatal("miri can only run programs that have a main function"); }; let mut config = self.miri_config.clone(); diff --git a/tests/compile-fail/intrinsics/assume.rs b/tests/compile-fail/intrinsics/assume.rs index 7b18cab79805..ad193d849918 100644 --- a/tests/compile-fail/intrinsics/assume.rs +++ b/tests/compile-fail/intrinsics/assume.rs @@ -5,6 +5,6 @@ fn main() { unsafe { std::intrinsics::assume(x < 10); std::intrinsics::assume(x > 1); - std::intrinsics::assume(x > 42); //~ `assume` intrinsic called with `false` + std::intrinsics::assume(x > 42); //~ ERROR `assume` intrinsic called with `false` } } diff --git a/tests/compile-fail/no_main.stderr b/tests/compile-fail/no_main.stderr index 52591a8d6da3..88bdfb4e387c 100644 --- a/tests/compile-fail/no_main.stderr +++ b/tests/compile-fail/no_main.stderr @@ -1,2 +1,4 @@ error: miri can only run programs that have a main function +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_cond_double_destroy.rs b/tests/compile-fail/sync/libc_pthread_cond_double_destroy.rs index c376618357d2..18be75b308cf 100644 --- a/tests/compile-fail/sync/libc_pthread_cond_double_destroy.rs +++ b/tests/compile-fail/sync/libc_pthread_cond_double_destroy.rs @@ -17,6 +17,6 @@ fn main() { libc::pthread_cond_destroy(cond.as_mut_ptr()); libc::pthread_cond_destroy(cond.as_mut_ptr()); - //~^ Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR Undefined Behavior: using uninitialized data, but this operation requires initialized memory } } diff --git a/tests/compile-fail/sync/libc_pthread_condattr_double_destroy.rs b/tests/compile-fail/sync/libc_pthread_condattr_double_destroy.rs index 44af51a3e871..1543a5841ad2 100644 --- a/tests/compile-fail/sync/libc_pthread_condattr_double_destroy.rs +++ b/tests/compile-fail/sync/libc_pthread_condattr_double_destroy.rs @@ -14,6 +14,6 @@ fn main() { libc::pthread_condattr_destroy(attr.as_mut_ptr()); libc::pthread_condattr_destroy(attr.as_mut_ptr()); - //~^ Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR Undefined Behavior: using uninitialized data, but this operation requires initialized memory } } diff --git a/tests/compile-fail/sync/libc_pthread_mutex_double_destroy.rs b/tests/compile-fail/sync/libc_pthread_mutex_double_destroy.rs index 08abc0ca12c5..3710810cd2c3 100644 --- a/tests/compile-fail/sync/libc_pthread_mutex_double_destroy.rs +++ b/tests/compile-fail/sync/libc_pthread_mutex_double_destroy.rs @@ -18,6 +18,6 @@ fn main() { libc::pthread_mutex_destroy(mutex.as_mut_ptr()); libc::pthread_mutex_destroy(mutex.as_mut_ptr()); - //~^ Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR Undefined Behavior: using uninitialized data, but this operation requires initialized memory } } diff --git a/tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.rs b/tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.rs index 69ca3ad512fa..c232780ee2ea 100644 --- a/tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.rs +++ b/tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.rs @@ -14,6 +14,6 @@ fn main() { libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); - //~^ Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR Undefined Behavior: using uninitialized data, but this operation requires initialized memory } } diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.rs b/tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.rs index d20c78155fd2..055bb1af489f 100644 --- a/tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.rs +++ b/tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.rs @@ -11,6 +11,6 @@ fn main() { libc::pthread_rwlock_destroy(&mut lock); libc::pthread_rwlock_destroy(&mut lock); - //~^ Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR Undefined Behavior: using uninitialized data, but this operation requires initialized memory } } diff --git a/ui_test/Cargo.lock b/ui_test/Cargo.lock index 185af43ac0b4..5a4cdb892713 100644 --- a/ui_test/Cargo.lock +++ b/ui_test/Cargo.lock @@ -148,6 +148,12 @@ dependencies = [ "libc", ] +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + [[package]] name = "lazy_static" version = "1.4.0" @@ -240,6 +246,12 @@ dependencies = [ "semver", ] +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + [[package]] name = "scopeguard" version = "1.1.0" @@ -252,6 +264,37 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" +[[package]] +name = "serde" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "syn" version = "1.0.95" @@ -273,6 +316,8 @@ dependencies = [ "pretty_assertions", "regex", "rustc_version", + "serde", + "serde_json", ] [[package]] diff --git a/ui_test/Cargo.toml b/ui_test/Cargo.toml index 66d35fdd2228..92c00915cbfe 100644 --- a/ui_test/Cargo.toml +++ b/ui_test/Cargo.toml @@ -12,3 +12,5 @@ regex = "1.5.5" pretty_assertions = "1.2.1" crossbeam = "0.8.1" lazy_static = "1.4.0" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" diff --git a/ui_test/README.md b/ui_test/README.md index fdd94a74823e..b3c9a3378cf3 100644 --- a/ui_test/README.md +++ b/ui_test/README.md @@ -11,9 +11,9 @@ Note that the space after `//`, when it is present, is *not* optional -- it must * `// stderr-per-bitwidth` produces one stderr file per bitwidth, as they may differ significantly sometimes * `// error-pattern: XXX` make sure the stderr output contains `XXX` * `//~ ERROR: XXX` make sure the stderr output contains `XXX` for an error in the line where this comment is written - * NOTE: it is not checked at present that it is actually in the line where the error occurred, or that it is truly an ERROR/WARNING/HELP/NOTE, but you should treat it as such until that becomes true. - * Also supports `HELP` or `WARN` for different kind of message - * if the all caps note is left out, any message is matched + * Also supports `HELP`, `WARN` or `NOTE` for different kind of message + * if one of those levels is specified explicitly, *all* diagnostics of this level or higher need an annotation. If you want to avoid this, just leave out the all caps level note entirely. + * If the all caps note is left out, a message of any level is matched. Leaving it out is not allowed for `ERROR` levels. * This checks the output *before* normalization, so you can check things that get normalized away, but need to be careful not to accidentally have a pattern that differs between platforms. * `// revisions: XXX YYY` runs the test once for each space separated name in the list diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index e6e45de4160e..cc9870a63be4 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -2,6 +2,8 @@ use std::path::Path; use regex::Regex; +use crate::rustc_stderr::Level; + #[cfg(test)] mod tests; @@ -33,7 +35,11 @@ pub(crate) struct Comments { pub(crate) struct ErrorMatch { pub matched: String, pub revision: Option, + pub level: Option, + /// The line where the message was defined, for reporting issues with it (e.g. in case it wasn't found). pub definition_line: usize, + /// The line this pattern is expecting to find a message in. + pub line: usize, } impl Comments { @@ -47,9 +53,13 @@ impl Comments { pub(crate) fn parse(path: &Path, content: &str) -> Self { let mut this = Self::default(); let error_pattern_regex = - Regex::new(r"//(\[(?P[^\]]+)\])?~[|^]*\s*(ERROR|HELP|WARN)?:?(?P.*)") + Regex::new(r"//(\[(?P[^\]]+)\])?~(?P\||[\^]+)?\s*(?PERROR|HELP|WARN|NOTE)?:?(?P.*)") .unwrap(); + + // The line that a `|` will refer to + let mut fallthrough_to = None; for (l, line) in content.lines().enumerate() { + let l = l + 1; // enumerate starts at 0, but line numbers start at 1 if let Some(revisions) = line.strip_prefix("// revisions:") { assert_eq!( this.revisions, @@ -113,7 +123,29 @@ impl Comments { let matched = captures["text"].trim().to_string(); let revision = captures.name("revision").map(|rev| rev.as_str().to_string()); - this.error_matches.push(ErrorMatch { matched, revision, definition_line: l }); + + let level = captures.name("level").map(|rev| rev.as_str().parse().unwrap()); + + let match_line = match captures.name("offset").map(|rev| rev.as_str()) { + Some("|") => fallthrough_to.expect("`//~|` pattern without preceding line"), + Some(pat) => { + debug_assert!(pat.chars().all(|c| c == '^')); + l - pat.len() + } + None => l, + }; + + fallthrough_to = Some(match_line); + + this.error_matches.push(ErrorMatch { + matched, + revision, + level, + definition_line: l, + line: match_line, + }); + } else { + fallthrough_to = None; } } this diff --git a/ui_test/src/comments/tests.rs b/ui_test/src/comments/tests.rs index 0140fdf4a9c6..ef9662241424 100644 --- a/ui_test/src/comments/tests.rs +++ b/ui_test/src/comments/tests.rs @@ -13,7 +13,7 @@ fn main() { "; let comments = Comments::parse(Path::new(""), s); println!("parsed comments: {:#?}", comments); - assert_eq!(comments.error_matches[0].definition_line, 4); + assert_eq!(comments.error_matches[0].definition_line, 5); assert_eq!(comments.error_matches[0].revision, None); assert_eq!( comments.error_matches[0].matched, diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 6052efe02e06..4a9cdd386ac2 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -8,10 +8,12 @@ use colored::*; use comments::ErrorMatch; use crossbeam::queue::SegQueue; use regex::Regex; +use rustc_stderr::{Level, Message}; use crate::comments::Comments; mod comments; +mod rustc_stderr; #[cfg(test)] mod tests; @@ -100,7 +102,8 @@ pub fn run_tests(config: Config) { for revision in comments.revisions.clone().unwrap_or_else(|| vec![String::new()]) { - let (m, errors) = run_test(&path, &config, &target, &revision, &comments); + let (m, errors, stderr) = + run_test(&path, &config, &target, &revision, &comments); // Using a single `eprintln!` to prevent messages from threads from getting intermingled. let mut msg = format!("{} ", path.display()); @@ -113,7 +116,13 @@ pub fn run_tests(config: Config) { succeeded.fetch_add(1, Ordering::Relaxed); } else { eprintln!("{msg}{}", "FAILED".red().bold()); - failures.lock().unwrap().push((path.clone(), m, revision, errors)); + failures.lock().unwrap().push(( + path.clone(), + m, + revision, + errors, + stderr, + )); } } } @@ -128,7 +137,7 @@ pub fn run_tests(config: Config) { let ignored = ignored.load(Ordering::Relaxed); let filtered = filtered.load(Ordering::Relaxed); if !failures.is_empty() { - for (path, miri, revision, errors) in &failures { + for (path, miri, revision, errors, stderr) in &failures { eprintln!(); eprint!("{}", path.display().to_string().underline()); if !revision.is_empty() { @@ -138,32 +147,63 @@ pub fn run_tests(config: Config) { eprintln!(); eprintln!("command: {:?}", miri); eprintln!(); - let mut dump_stderr = None; + // `None` means never dump, as we already dumped it for an `OutputDiffers` + // `Some(false)` means there's no reason to dump, as all errors are independent of the stderr + // `Some(true)` means that there was a pattern in the .rs file that was not found in the output. + let mut dump_stderr = Some(false); for error in errors { match error { Error::ExitStatus(mode, exit_status) => eprintln!("{mode:?} got {exit_status}"), - Error::PatternNotFound { stderr, pattern, definition_line } => { + Error::PatternNotFound { pattern, definition_line } => { eprintln!("`{pattern}` {} in stderr output", "not found".red()); eprintln!( "expected because of pattern here: {}:{definition_line}", path.display().to_string().bold() ); - dump_stderr = Some(stderr.clone()) + dump_stderr = dump_stderr.map(|_| true); + } + Error::NoPatternsFound => { + eprintln!("{}", "no error patterns found in failure test".red()); } - Error::NoPatternsFound => - eprintln!("{}", "no error patterns found in failure test".red()), Error::PatternFoundInPassTest => eprintln!("{}", "error pattern found in success test".red()), Error::OutputDiffers { path, actual, expected } => { - dump_stderr = None; + if path.extension().unwrap() == "stderr" { + dump_stderr = None; + } eprintln!("actual output differed from expected {}", path.display()); eprintln!("{}", pretty_assertions::StrComparison::new(expected, actual)); eprintln!() } + Error::ErrorsWithoutPattern { path: None, msgs } => { + eprintln!( + "There were {} unmatched diagnostics that occurred outside the testfile and had not pattern", + msgs.len(), + ); + for Message { level, message } in msgs { + eprintln!(" {level:?}: {message}") + } + } + Error::ErrorsWithoutPattern { path: Some((path, line)), msgs } => { + eprintln!( + "There were {} unmatched diagnostics at {}:{line}", + msgs.len(), + path.display() + ); + for Message { level, message } in msgs { + eprintln!(" {level:?}: {message}") + } + } + Error::ErrorPatternWithoutErrorAnnotation(path, line) => { + eprintln!( + "Annotation at {}:{line} matched an error diagnostic but did not have `ERROR` before its message", + path.display() + ); + } } eprintln!(); } - if let Some(stderr) = dump_stderr { + if let Some(true) = dump_stderr { eprintln!("actual stderr:"); eprintln!("{}", stderr); eprintln!(); @@ -195,7 +235,6 @@ enum Error { /// Got an invalid exit status for the given mode. ExitStatus(Mode, ExitStatus), PatternNotFound { - stderr: String, pattern: String, definition_line: usize, }, @@ -209,6 +248,11 @@ enum Error { actual: String, expected: String, }, + ErrorsWithoutPattern { + msgs: Vec, + path: Option<(PathBuf, usize)>, + }, + ErrorPatternWithoutErrorAnnotation(PathBuf, usize), } type Errors = Vec; @@ -219,7 +263,7 @@ fn run_test( target: &str, revision: &str, comments: &Comments, -) -> (Command, Errors) { +) -> (Command, Errors, String) { // Run miri let mut miri = Command::new(&config.program); miri.args(config.args.iter()); @@ -227,6 +271,7 @@ fn run_test( if !revision.is_empty() { miri.arg(format!("--cfg={revision}")); } + miri.arg("--error-format=json"); for arg in &comments.compile_flags { miri.arg(arg); } @@ -235,7 +280,7 @@ fn run_test( } let output = miri.output().expect("could not execute miri"); let mut errors = config.mode.ok(output.status); - check_test_result( + let stderr = check_test_result( path, config, target, @@ -245,7 +290,7 @@ fn run_test( &output.stdout, &output.stderr, ); - (miri, errors) + (miri, errors, stderr) } fn check_test_result( @@ -257,11 +302,9 @@ fn check_test_result( errors: &mut Errors, stdout: &[u8], stderr: &[u8], -) { +) -> String { // Always remove annotation comments from stderr. - let annotations = Regex::new(r"\s*//~.*").unwrap(); - let stderr = std::str::from_utf8(stderr).unwrap(); - let stderr = annotations.replace_all(stderr, ""); + let diagnostics = rustc_stderr::process(path, stderr); let stdout = std::str::from_utf8(stdout).unwrap(); // Check output files (if any) let revised = |extension: &str| { @@ -273,7 +316,7 @@ fn check_test_result( }; // Check output files against actual output check_output( - &stderr, + &diagnostics.rendered, path, errors, revised("stderr"), @@ -293,50 +336,126 @@ fn check_test_result( comments, ); // Check error annotations in the source against output - check_annotations(&stderr, errors, config, revision, comments); + check_annotations( + diagnostics.messages, + diagnostics.messages_from_unknown_file_or_line, + path, + errors, + config, + revision, + comments, + ); + diagnostics.rendered } fn check_annotations( - unnormalized_stderr: &str, + mut messages: Vec>, + mut messages_from_unknown_file_or_line: Vec, + path: &Path, errors: &mut Errors, config: &Config, revision: &str, comments: &Comments, ) { - let mut found_annotation = false; if let Some((ref error_pattern, definition_line)) = comments.error_pattern { - if !unnormalized_stderr.contains(error_pattern) { + let mut found = false; + + // first check the diagnostics messages outside of our file. We check this first, so that + // you can mix in-file annotations with // error-pattern annotations, even if there is overlap + // in the messages. + if let Some(i) = messages_from_unknown_file_or_line + .iter() + .position(|msg| msg.message.contains(error_pattern)) + { + messages_from_unknown_file_or_line.remove(i); + found = true; + } + + // if nothing was found, check the ones inside our file. We permit this because some tests may have + // flaky line numbers for their messages. + if !found { + for line in &mut messages { + if let Some(i) = line.iter().position(|msg| msg.message.contains(error_pattern)) { + line.remove(i); + found = true; + break; + } + } + } + + if !found { errors.push(Error::PatternNotFound { - stderr: unnormalized_stderr.to_string(), pattern: error_pattern.to_string(), definition_line, }); } - found_annotation = true; } - for &ErrorMatch { ref matched, revision: ref rev, definition_line } in &comments.error_matches { - // FIXME: check that the error happens on the marked line + // The order on `Level` is such that `Error` is the highest level. + // We will ensure that *all* diagnostics of level at least `lowest_annotation_level` + // are matched. + let mut lowest_annotation_level = Level::Error; + for &ErrorMatch { ref matched, revision: ref rev, definition_line, line, level } in + &comments.error_matches + { if let Some(rev) = rev { if rev != revision { continue; } } - - if !unnormalized_stderr.contains(matched) { - errors.push(Error::PatternNotFound { - stderr: unnormalized_stderr.to_string(), - pattern: matched.to_string(), - definition_line, - }); + if let Some(level) = level { + // If we found a diagnostic with a level annotation, make sure that all + // diagnostics of that level have annotations, even if we don't end up finding a matching diagnostic + // for this pattern. + lowest_annotation_level = std::cmp::min(lowest_annotation_level, level); } - found_annotation = true; + + if let Some(msgs) = messages.get_mut(line) { + let found = msgs.iter().position(|msg| { + msg.message.contains(matched) + // in case there is no level on the annotation, match any level. + && level.map_or(true, |level| { + msg.level == level + }) + }); + if let Some(found) = found { + let msg = msgs.remove(found); + if msg.level == Level::Error && level.is_none() { + errors + .push(Error::ErrorPatternWithoutErrorAnnotation(path.to_path_buf(), line)); + } + continue; + } + } + + errors.push(Error::PatternNotFound { pattern: matched.to_string(), definition_line }); } - match (config.mode, found_annotation) { + + let filter = |msgs: Vec| -> Vec<_> { + msgs.into_iter().filter(|msg| msg.level >= lowest_annotation_level).collect() + }; + + let messages_from_unknown_file_or_line = filter(messages_from_unknown_file_or_line); + if !messages_from_unknown_file_or_line.is_empty() { + errors.push(Error::ErrorsWithoutPattern { + path: None, + msgs: messages_from_unknown_file_or_line, + }); + } + + for (line, msgs) in messages.into_iter().enumerate() { + let msgs = filter(msgs); + if !msgs.is_empty() { + errors + .push(Error::ErrorsWithoutPattern { path: Some((path.to_path_buf(), line)), msgs }); + } + } + + match (config.mode, comments.error_pattern.is_some() || !comments.error_matches.is_empty()) { (Mode::Pass, true) | (Mode::Panic, true) => errors.push(Error::PatternFoundInPassTest), (Mode::Fail, false) => errors.push(Error::NoPatternsFound), _ => {} - }; + } } fn check_output( diff --git a/ui_test/src/rustc_stderr.rs b/ui_test/src/rustc_stderr.rs new file mode 100644 index 000000000000..ac76a78a3cbc --- /dev/null +++ b/ui_test/src/rustc_stderr.rs @@ -0,0 +1,152 @@ +use std::{ + fmt::Write, + path::{Path, PathBuf}, +}; + +use regex::Regex; + +#[derive(serde::Deserialize, Debug)] +struct RustcMessage { + rendered: Option, + spans: Vec, + level: String, + message: String, + children: Vec, +} + +#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] +pub(crate) enum Level { + Error = 4, + Warn = 3, + Help = 2, + Note = 1, + /// Only used for "For more information about this error, try `rustc --explain EXXXX`". + FailureNote = 0, +} + +#[derive(Debug)] +pub(crate) struct Message { + pub(crate) level: Level, + pub(crate) message: String, +} + +/// Information about macro expansion. +#[derive(serde::Deserialize, Debug)] +struct Expansion { + span: Span, +} + +#[derive(serde::Deserialize, Debug)] +struct Span { + line_start: usize, + file_name: PathBuf, + expansion: Option>, +} + +impl std::str::FromStr for Level { + type Err = String; + fn from_str(s: &str) -> Result { + match s { + "ERROR" | "error" => Ok(Self::Error), + "WARN" | "warning" => Ok(Self::Warn), + "HELP" | "help" => Ok(Self::Help), + "NOTE" | "note" => Ok(Self::Note), + "failure-note" => Ok(Self::FailureNote), + _ => Err(format!("unknown level `{s}`")), + } + } +} + +#[derive(Debug)] +pub(crate) struct Diagnostics { + /// Rendered and concatenated version of all diagnostics. + /// This is equivalent to non-json diagnostics. + pub rendered: String, + /// Per line, a list of messages for that line. + pub messages: Vec>, + /// Messages not on any line (usually because they are from libstd) + pub messages_from_unknown_file_or_line: Vec, +} + +impl RustcMessage { + fn line(&self, file: &Path) -> Option { + self.spans.iter().find_map(|span| span.line(file)) + } + + /// Put the message and its children into the line-indexed list. + fn insert_recursive( + self, + file: &Path, + messages: &mut Vec>, + messages_from_unknown_file_or_line: &mut Vec, + line: Option, + ) { + let line = self.line(file).or(line); + let msg = Message { level: self.level.parse().unwrap(), message: self.message }; + if let Some(line) = line { + if messages.len() <= line { + messages.resize_with(line + 1, Vec::new); + } + messages[line].push(msg); + // All other messages go into the general bin, unless they are specifically of the + // "aborting due to X previous errors" variety, as we never want to match those. They + // only count the number of errors and provide no useful information about the tests. + } else if !(msg.message.starts_with("aborting due to") + && msg.message.contains("previous error")) + { + messages_from_unknown_file_or_line.push(msg); + } + for child in self.children { + child.insert_recursive(file, messages, messages_from_unknown_file_or_line, line) + } + } +} + +impl Span { + /// Returns a line number *in the given file*, if possible. + fn line(&self, file: &Path) -> Option { + if self.file_name == file { + Some(self.line_start) + } else { + self.expansion.as_ref()?.span.line(file) + } + } +} + +pub(crate) fn filter_annotations_from_rendered(rendered: &str) -> std::borrow::Cow<'_, str> { + let annotations = Regex::new(r"\s*//~.*").unwrap(); + annotations.replace_all(&rendered, "") +} + +pub(crate) fn process(file: &Path, stderr: &[u8]) -> Diagnostics { + let stderr = std::str::from_utf8(&stderr).unwrap(); + let mut rendered = String::new(); + let mut messages = vec![]; + let mut messages_from_unknown_file_or_line = vec![]; + for line in stderr.lines() { + if line.starts_with("{") { + match serde_json::from_str::(line) { + Ok(msg) => { + write!( + rendered, + "{}", + filter_annotations_from_rendered(msg.rendered.as_ref().unwrap()) + ) + .unwrap(); + msg.insert_recursive( + file, + &mut messages, + &mut messages_from_unknown_file_or_line, + None, + ); + } + Err(err) => + panic!("failed to parse rustc JSON output at line: {}\nerr:{}", line, err), + } + } else { + // FIXME: do we want to throw interpreter stderr into a separate file? + writeln!(rendered, "{}", line).unwrap(); + } + } + Diagnostics { rendered, messages, messages_from_unknown_file_or_line } +} diff --git a/ui_test/src/tests.rs b/ui_test/src/tests.rs index d0ef1195d888..7e08a68be7b9 100644 --- a/ui_test/src/tests.rs +++ b/ui_test/src/tests.rs @@ -1,5 +1,8 @@ use std::path::{Path, PathBuf}; +use crate::rustc_stderr::Level; +use crate::rustc_stderr::Message; + use super::*; fn config() -> Config { @@ -29,25 +32,292 @@ fn main() { let comments = Comments::parse(&path, s); let mut errors = vec![]; let config = config(); - // Crucially, the intended error string *does* appear in this output, as a quote of the comment itself. - let stderr = br" -error: Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated) - --> tests/compile-fail/validity/dangling_ref1.rs:6:29 - | -LL | let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address $HEX is unallocated) - | ^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (address 0x10 is unallocated) - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `main` at tests/compile-fail/validity/dangling_ref1.rs:6:29 -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error - "; - check_test_result(&path, &config, "", "", &comments, &mut errors, /*stdout*/ br"", stderr); - // The "OutputDiffers" is because we cannot open the .rs file + let messages = vec![ + vec![], vec![], vec![], vec![], vec![], + vec![ + Message { + message:"Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), + level: Level::Error, + } + ] + ]; + check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); match &errors[..] { - [Error::OutputDiffers { .. }, Error::PatternNotFound { .. }] => {} - _ => panic!("not the expected error: {:#?}", errors), + [ + Error::PatternNotFound { definition_line: 5, .. }, + Error::ErrorsWithoutPattern { path: Some((_, 5)), .. }, + ] => {} + _ => panic!("{:#?}", errors), + } +} + +#[test] +fn find_pattern() { + let s = r" +use std::mem; + +fn main() { + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) +} + "; + let comments = Comments::parse(Path::new(""), s); + let config = config(); + { + let messages = vec![vec![], vec![], vec![], vec![], vec![], vec![ + Message { + message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), + level: Level::Error, + } + ] + ]; + let mut errors = vec![]; + check_annotations( + messages, + vec![], + Path::new("moobar"), + &mut errors, + &config, + "", + &comments, + ); + match &errors[..] { + [] => {} + _ => panic!("{:#?}", errors), + } + } + + // only difference to above is a wrong line number + { + let messages = vec![vec![], vec![], vec![], vec![], vec![ + Message { + message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), + level: Level::Error, + } + ] + ]; + let mut errors = vec![]; + check_annotations( + messages, + vec![], + Path::new("moobar"), + &mut errors, + &config, + "", + &comments, + ); + match &errors[..] { + [ + Error::PatternNotFound { definition_line: 5, .. }, + Error::ErrorsWithoutPattern { path: Some((_, 4)), .. }, + ] => {} + _ => panic!("not the expected error: {:#?}", errors), + } + } + + // only difference to first is a wrong level + { + let messages = vec![ + vec![], vec![], vec![], vec![], vec![], + vec![ + Message { + message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), + level: Level::Note, + } + ] + ]; + let mut errors = vec![]; + check_annotations( + messages, + vec![], + Path::new("moobar"), + &mut errors, + &config, + "", + &comments, + ); + match &errors[..] { + // Note no `ErrorsWithoutPattern`, because there are no `//~NOTE` in the test file, so we ignore them + [Error::PatternNotFound { definition_line: 5, .. }] => {} + _ => panic!("not the expected error: {:#?}", errors), + } + } +} + +#[test] +fn duplicate_pattern() { + let s = r" +use std::mem; + +fn main() { + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) + //~^ ERROR encountered a dangling reference (address 0x10 is unallocated) +} + "; + let comments = Comments::parse(Path::new(""), s); + let config = config(); + let messages = vec![ + vec![], vec![], vec![], vec![], vec![], + vec![ + Message { + message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), + level: Level::Error, + } + ] + ]; + let mut errors = vec![]; + check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); + match &errors[..] { + [Error::PatternNotFound { definition_line: 6, .. }] => {} + _ => panic!("{:#?}", errors), + } +} + +#[test] +fn missing_pattern() { + let s = r" +use std::mem; + +fn main() { + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) +} + "; + let comments = Comments::parse(Path::new(""), s); + let config = config(); + let messages = vec![ + vec![], vec![], vec![], vec![], vec![], + vec![ + Message { + message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), + level: Level::Error, + }, + Message { + message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), + level: Level::Error, + } + ] + ]; + let mut errors = vec![]; + check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); + match &errors[..] { + [Error::ErrorsWithoutPattern { path: Some((_, 5)), .. }] => {} + _ => panic!("{:#?}", errors), + } +} + +#[test] +fn missing_warn_pattern() { + let s = r" +use std::mem; + +fn main() { + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) + //~^ WARN cake +} + "; + let comments = Comments::parse(Path::new(""), s); + let config = config(); + let messages= vec![ + vec![], + vec![], + vec![], + vec![], + vec![], + vec![ + Message { + message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), + level: Level::Error, + }, + Message { + message: "kaboom".to_string(), + level: Level::Warn, + }, + Message { + message: "cake".to_string(), + level: Level::Warn, + }, + ], + ]; + let mut errors = vec![]; + check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); + match &errors[..] { + [Error::ErrorsWithoutPattern { path: Some((_, 5)), msgs, .. }] => + match &msgs[..] { + [Message { message, level: Level::Warn }] if message == "kaboom" => {} + _ => panic!("{:#?}", msgs), + }, + _ => panic!("{:#?}", errors), + } +} + +#[test] +fn missing_implicit_warn_pattern() { + let s = r" +use std::mem; + +fn main() { + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) + //~^ cake +} + "; + let comments = Comments::parse(Path::new(""), s); + let config = config(); + let messages = vec![ + vec![], + vec![], + vec![], + vec![], + vec![], + vec![ + Message { + message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), + level: Level::Error, + }, + Message { + message: "kaboom".to_string(), + level: Level::Warn, + }, + Message { + message: "cake".to_string(), + level: Level::Warn, + }, + ], + ]; + let mut errors = vec![]; + check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); + match &errors[..] { + [] => {} + _ => panic!("{:#?}", errors), + } +} + +#[test] +fn implicit_err_pattern() { + let s = r" +use std::mem; + +fn main() { + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ encountered a dangling reference (address 0x10 is unallocated) +} + "; + let comments = Comments::parse(Path::new(""), s); + let config = config(); + let messages = vec![ + vec![], + vec![], + vec![], + vec![], + vec![], + vec![ + Message { + message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), + level: Level::Error, + }, + ], + ]; + let mut errors = vec![]; + check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); + match &errors[..] { + [Error::ErrorPatternWithoutErrorAnnotation(_, 5)] => {} + _ => panic!("{:#?}", errors), } } From 9b9edc7440ee0c417403cc7c40f2aa3f72734fc7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 Jun 2022 06:14:59 -0400 Subject: [PATCH 3152/5092] print list of failed tests in summary --- ui_test/src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 4a9cdd386ac2..0b076a5f51ec 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -209,6 +209,11 @@ pub fn run_tests(config: Config) { eprintln!(); } } + eprintln!("{}", "failures:".red().underline()); + for (path, _miri, _revision, _errors, _stderr) in &failures { + eprintln!(" {}", path.display()); + } + eprintln!(); eprintln!( "test result: {}. {} tests failed, {} tests passed, {} ignored, {} filtered out", "FAIL".red(), From 3d634c975c7d7faf92a46d7d9a1a0267bd48e86a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 Jun 2022 10:53:38 -0400 Subject: [PATCH 3153/5092] rename test suite directories --- ci.sh | 2 +- tests/compiletest.rs | 6 +++--- tests/{compile-fail => fail}/abort-terminator.rs | 0 tests/{compile-fail => fail}/abort-terminator.stderr | 0 .../alloc/deallocate-bad-alignment.rs | 0 .../alloc/deallocate-bad-alignment.stderr | 0 tests/{compile-fail => fail}/alloc/deallocate-bad-size.rs | 0 .../{compile-fail => fail}/alloc/deallocate-bad-size.stderr | 0 tests/{compile-fail => fail}/alloc/deallocate-twice.rs | 0 tests/{compile-fail => fail}/alloc/deallocate-twice.stderr | 0 tests/{compile-fail => fail}/alloc/global_system_mixup.rs | 0 .../{compile-fail => fail}/alloc/global_system_mixup.stderr | 0 tests/{compile-fail => fail}/alloc/no_global_allocator.rs | 0 .../{compile-fail => fail}/alloc/no_global_allocator.stderr | 0 tests/{compile-fail => fail}/alloc/reallocate-bad-size.rs | 0 .../{compile-fail => fail}/alloc/reallocate-bad-size.stderr | 0 .../{compile-fail => fail}/alloc/reallocate-change-alloc.rs | 0 .../alloc/reallocate-change-alloc.stderr | 0 tests/{compile-fail => fail}/alloc/reallocate-dangling.rs | 0 .../{compile-fail => fail}/alloc/reallocate-dangling.stderr | 0 tests/{compile-fail => fail}/alloc/stack_free.rs | 0 tests/{compile-fail => fail}/alloc/stack_free.stderr | 0 .../{compile-fail => fail}/backtrace/bad-backtrace-decl.rs | 0 .../backtrace/bad-backtrace-decl.stderr | 0 .../{compile-fail => fail}/backtrace/bad-backtrace-flags.rs | 0 .../backtrace/bad-backtrace-flags.stderr | 0 tests/{compile-fail => fail}/backtrace/bad-backtrace-ptr.rs | 0 .../backtrace/bad-backtrace-ptr.stderr | 0 .../backtrace/bad-backtrace-resolve-flags.rs | 0 .../backtrace/bad-backtrace-resolve-flags.stderr | 0 .../backtrace/bad-backtrace-resolve-names-flags.rs | 0 .../backtrace/bad-backtrace-resolve-names-flags.stderr | 0 .../backtrace/bad-backtrace-size-flags.rs | 0 .../backtrace/bad-backtrace-size-flags.stderr | 0 .../backtrace/bad-backtrace-version.stderr | 0 tests/{compile-fail => fail}/box-cell-alias.rs | 0 tests/{compile-fail => fail}/box-cell-alias.stderr | 0 .../branchless-select-i128-pointer.rs | 0 .../branchless-select-i128-pointer.stderr | 0 tests/{compile-fail => fail}/breakpoint.rs | 0 tests/{compile-fail => fail}/breakpoint.stderr | 0 .../concurrency/libc_pthread_create_main_terminate.rs | 0 .../concurrency/libc_pthread_create_main_terminate.stderr | 0 .../concurrency/libc_pthread_join_detached.rs | 0 .../concurrency/libc_pthread_join_detached.stderr | 0 .../concurrency/libc_pthread_join_joined.rs | 0 .../concurrency/libc_pthread_join_joined.stderr | 0 .../concurrency/libc_pthread_join_main.rs | 0 .../concurrency/libc_pthread_join_main.stderr | 0 .../concurrency/libc_pthread_join_multiple.rs | 0 .../concurrency/libc_pthread_join_multiple.stderr | 0 .../concurrency/libc_pthread_join_self.rs | 0 .../concurrency/libc_pthread_join_self.stderr | 0 tests/{compile-fail => fail}/concurrency/thread-spawn.rs | 0 .../concurrency/thread_local_static_dealloc.rs | 0 .../concurrency/thread_local_static_dealloc.stderr | 0 tests/{compile-fail => fail}/concurrency/too_few_args.rs | 0 .../{compile-fail => fail}/concurrency/too_few_args.stderr | 0 tests/{compile-fail => fail}/concurrency/too_many_args.rs | 0 .../{compile-fail => fail}/concurrency/too_many_args.stderr | 0 .../concurrency/unwind_top_of_stack.rs | 0 .../concurrency/unwind_top_of_stack.stderr | 0 .../dangling_pointers/dangling_pointer_addr_of.rs | 0 .../dangling_pointers/dangling_pointer_addr_of.stderr | 0 .../dangling_pointers/dangling_pointer_deref.rs | 0 .../dangling_pointers/dangling_pointer_deref.stderr | 0 .../dangling_pointers/dangling_zst_deref.rs | 0 .../dangling_pointers/dangling_zst_deref.stderr | 0 .../dangling_pointers/deref-invalid-ptr.rs | 0 .../dangling_pointers/deref-invalid-ptr.stderr | 0 .../dangling_pointers/deref-partially-dangling.rs | 0 .../dangling_pointers/deref-partially-dangling.stderr | 0 tests/{compile-fail => fail}/dangling_pointers/dyn_size.rs | 0 .../dangling_pointers/dyn_size.stderr | 0 .../dangling_pointers/maybe_null_pointer_deref_zst.rs | 0 .../dangling_pointers/maybe_null_pointer_deref_zst.stderr | 0 .../dangling_pointers/maybe_null_pointer_write_zst.rs | 0 .../dangling_pointers/maybe_null_pointer_write_zst.stderr | 0 .../dangling_pointers/null_pointer_deref.rs | 0 .../dangling_pointers/null_pointer_deref.stderr | 0 .../dangling_pointers/null_pointer_deref_zst.rs | 0 .../dangling_pointers/null_pointer_deref_zst.stderr | 0 .../dangling_pointers/null_pointer_write.rs | 0 .../dangling_pointers/null_pointer_write.stderr | 0 .../dangling_pointers/null_pointer_write_zst.rs | 0 .../dangling_pointers/null_pointer_write_zst.stderr | 0 .../dangling_pointers/out_of_bounds_read1.rs | 0 .../dangling_pointers/out_of_bounds_read1.stderr | 0 .../dangling_pointers/out_of_bounds_read2.rs | 0 .../dangling_pointers/out_of_bounds_read2.stderr | 0 .../dangling_pointers/stack_temporary.rs | 0 .../dangling_pointers/stack_temporary.stderr | 0 .../dangling_pointers/storage_dead_dangling.rs | 0 .../dangling_pointers/storage_dead_dangling.stderr | 0 .../dangling_pointers/wild_pointer_deref.rs | 0 .../dangling_pointers/wild_pointer_deref.stderr | 0 tests/{compile-fail => fail}/data_race/alloc_read_race.rs | 0 .../{compile-fail => fail}/data_race/alloc_read_race.stderr | 0 tests/{compile-fail => fail}/data_race/alloc_write_race.rs | 0 .../data_race/alloc_write_race.stderr | 0 .../data_race/atomic_read_na_write_race1.rs | 0 .../data_race/atomic_read_na_write_race1.stderr | 0 .../data_race/atomic_read_na_write_race2.rs | 0 .../data_race/atomic_read_na_write_race2.stderr | 0 .../data_race/atomic_write_na_read_race1.rs | 0 .../data_race/atomic_write_na_read_race1.stderr | 0 .../data_race/atomic_write_na_read_race2.rs | 0 .../data_race/atomic_write_na_read_race2.stderr | 0 .../data_race/atomic_write_na_write_race1.rs | 0 .../data_race/atomic_write_na_write_race1.stderr | 0 .../data_race/atomic_write_na_write_race2.rs | 0 .../data_race/atomic_write_na_write_race2.stderr | 0 .../data_race/dangling_thread_async_race.rs | 0 .../data_race/dangling_thread_async_race.stderr | 0 .../data_race/dangling_thread_race.rs | 0 .../data_race/dangling_thread_race.stderr | 0 .../{compile-fail => fail}/data_race/dealloc_read_race1.rs | 0 .../data_race/dealloc_read_race1.stderr | 0 .../{compile-fail => fail}/data_race/dealloc_read_race2.rs | 0 .../data_race/dealloc_read_race2.stderr | 0 .../data_race/dealloc_read_race_stack.rs | 0 .../data_race/dealloc_read_race_stack.stderr | 0 .../{compile-fail => fail}/data_race/dealloc_write_race1.rs | 0 .../data_race/dealloc_write_race1.stderr | 0 .../{compile-fail => fail}/data_race/dealloc_write_race2.rs | 0 .../data_race/dealloc_write_race2.stderr | 0 .../data_race/dealloc_write_race_stack.rs | 0 .../data_race/dealloc_write_race_stack.stderr | 0 .../data_race/enable_after_join_to_main.rs | 0 .../data_race/enable_after_join_to_main.stderr | 0 tests/{compile-fail => fail}/data_race/read_write_race.rs | 0 .../{compile-fail => fail}/data_race/read_write_race.stderr | 0 .../data_race/read_write_race_stack.rs | 0 .../data_race/read_write_race_stack.stderr | 0 .../{compile-fail => fail}/data_race/relax_acquire_race.rs | 0 .../data_race/relax_acquire_race.stderr | 0 tests/{compile-fail => fail}/data_race/release_seq_race.rs | 0 .../data_race/release_seq_race.stderr | 0 .../data_race/release_seq_race_same_thread.rs | 0 .../data_race/release_seq_race_same_thread.stderr | 0 tests/{compile-fail => fail}/data_race/rmw_race.rs | 0 tests/{compile-fail => fail}/data_race/rmw_race.stderr | 0 tests/{compile-fail => fail}/data_race/write_write_race.rs | 0 .../data_race/write_write_race.stderr | 0 .../data_race/write_write_race_stack.rs | 0 .../data_race/write_write_race_stack.stderr | 0 tests/{compile-fail => fail}/environ-gets-deallocated.rs | 0 .../{compile-fail => fail}/environ-gets-deallocated.stderr | 0 tests/{compile-fail => fail}/erroneous_const.rs | 0 tests/{compile-fail => fail}/erroneous_const.stderr | 0 tests/{compile-fail => fail}/erroneous_const2.rs | 0 tests/{compile-fail => fail}/erroneous_const2.stderr | 0 tests/{compile-fail => fail}/extern_static.rs | 0 tests/{compile-fail => fail}/extern_static.stderr | 0 tests/{compile-fail => fail}/fast_math_both.rs | 0 tests/{compile-fail => fail}/fast_math_both.stderr | 0 tests/{compile-fail => fail}/fast_math_first.rs | 0 tests/{compile-fail => fail}/fast_math_first.stderr | 0 tests/{compile-fail => fail}/fast_math_second.rs | 0 tests/{compile-fail => fail}/fast_math_second.stderr | 0 tests/{compile-fail => fail}/fs/close_stdout.rs | 0 tests/{compile-fail => fail}/fs/close_stdout.stderr | 0 tests/{compile-fail => fail}/fs/isolated_file.rs | 0 tests/{compile-fail => fail}/fs/isolated_file.stderr | 0 tests/{compile-fail => fail}/fs/isolated_stdin.rs | 0 tests/{compile-fail => fail}/fs/isolated_stdin.stderr | 0 tests/{compile-fail => fail}/fs/read_from_stdout.rs | 0 tests/{compile-fail => fail}/fs/read_from_stdout.stderr | 0 .../fs/unix_open_missing_required_mode.rs | 0 .../fs/unix_open_missing_required_mode.stderr | 0 .../fs/unix_open_too_many_args.stderr | 0 tests/{compile-fail => fail}/fs/write_to_stdin.rs | 0 tests/{compile-fail => fail}/fs/write_to_stdin.stderr | 0 .../{compile-fail => fail}/function_calls/check_arg_abi.rs | 0 .../function_calls/check_arg_abi.stderr | 0 .../function_calls/check_arg_count_abort.rs | 0 .../function_calls/check_arg_count_abort.stderr | 0 .../function_calls/check_arg_count_too_few_args.rs | 0 .../function_calls/check_arg_count_too_few_args.stderr | 0 .../function_calls/check_arg_count_too_many_args.rs | 0 .../function_calls/check_arg_count_too_many_args.stderr | 0 .../function_calls/check_callback_abi.rs | 0 .../function_calls/check_callback_abi.stderr | 0 .../exported_symbol_abi_mismatch.cache.stderr | 0 .../exported_symbol_abi_mismatch.fn_ptr.stderr | 0 .../exported_symbol_abi_mismatch.no_cache.stderr | 0 .../function_calls/exported_symbol_abi_mismatch.rs | 0 .../function_calls/exported_symbol_bad_unwind1.rs | 0 .../function_calls/exported_symbol_bad_unwind1.stderr | 0 .../function_calls/exported_symbol_bad_unwind2.both.stderr | 0 .../exported_symbol_bad_unwind2.definition.stderr | 0 .../exported_symbol_bad_unwind2.extern_block.stderr | 0 .../function_calls/exported_symbol_bad_unwind2.rs | 0 .../function_calls/exported_symbol_clashing.rs | 0 .../function_calls/exported_symbol_clashing.stderr | 0 .../function_calls/exported_symbol_shim_clashing.rs | 0 .../function_calls/exported_symbol_shim_clashing.stderr | 0 .../function_calls/exported_symbol_wrong_arguments.rs | 0 .../function_calls/exported_symbol_wrong_arguments.stderr | 0 .../function_calls/exported_symbol_wrong_type.rs | 0 .../function_calls/exported_symbol_wrong_type.stderr | 0 .../function_pointers/cast_box_int_to_fn_ptr.rs | 0 .../function_pointers/cast_box_int_to_fn_ptr.stderr | 0 .../function_pointers/cast_fn_ptr1.rs | 0 .../function_pointers/cast_fn_ptr1.stderr | 0 .../function_pointers/cast_fn_ptr2.rs | 0 .../function_pointers/cast_fn_ptr2.stderr | 0 .../function_pointers/cast_fn_ptr3.rs | 0 .../function_pointers/cast_fn_ptr3.stderr | 0 .../function_pointers/cast_fn_ptr4.rs | 0 .../function_pointers/cast_fn_ptr4.stderr | 0 .../function_pointers/cast_fn_ptr5.rs | 0 .../function_pointers/cast_fn_ptr5.stderr | 0 .../function_pointers/cast_int_to_fn_ptr.rs | 0 .../function_pointers/cast_int_to_fn_ptr.stderr | 0 .../function_pointers/deref_fn_ptr.rs | 0 .../function_pointers/deref_fn_ptr.stderr | 0 .../function_pointers/execute_memory.rs | 0 .../function_pointers/execute_memory.stderr | 0 .../function_pointers/fn_ptr_offset.rs | 0 .../function_pointers/fn_ptr_offset.stderr | 0 tests/{compile-fail => fail}/generator-pinned-moved.rs | 0 tests/{compile-fail => fail}/generator-pinned-moved.stderr | 0 tests/{compile-fail => fail}/intrinsics/assume.rs | 0 tests/{compile-fail => fail}/intrinsics/assume.stderr | 0 tests/{compile-fail => fail}/intrinsics/copy_null.rs | 0 tests/{compile-fail => fail}/intrinsics/copy_null.stderr | 0 tests/{compile-fail => fail}/intrinsics/copy_overflow.rs | 0 .../{compile-fail => fail}/intrinsics/copy_overflow.stderr | 0 tests/{compile-fail => fail}/intrinsics/copy_overlapping.rs | 0 .../intrinsics/copy_overlapping.stderr | 0 tests/{compile-fail => fail}/intrinsics/copy_unaligned.rs | 0 .../{compile-fail => fail}/intrinsics/copy_unaligned.stderr | 0 tests/{compile-fail => fail}/intrinsics/ctlz_nonzero.rs | 0 tests/{compile-fail => fail}/intrinsics/ctlz_nonzero.stderr | 0 tests/{compile-fail => fail}/intrinsics/cttz_nonzero.rs | 0 tests/{compile-fail => fail}/intrinsics/cttz_nonzero.stderr | 0 tests/{compile-fail => fail}/intrinsics/div-by-zero.rs | 0 tests/{compile-fail => fail}/intrinsics/div-by-zero.stderr | 0 tests/{compile-fail => fail}/intrinsics/exact_div1.rs | 0 tests/{compile-fail => fail}/intrinsics/exact_div1.stderr | 0 tests/{compile-fail => fail}/intrinsics/exact_div2.rs | 0 tests/{compile-fail => fail}/intrinsics/exact_div2.stderr | 0 tests/{compile-fail => fail}/intrinsics/exact_div3.rs | 0 tests/{compile-fail => fail}/intrinsics/exact_div3.stderr | 0 tests/{compile-fail => fail}/intrinsics/exact_div4.rs | 0 tests/{compile-fail => fail}/intrinsics/exact_div4.stderr | 0 .../intrinsics/float_to_int_32_inf1.rs | 0 .../intrinsics/float_to_int_32_inf1.stderr | 0 .../intrinsics/float_to_int_32_infneg1.rs | 0 .../intrinsics/float_to_int_32_infneg1.stderr | 0 .../intrinsics/float_to_int_32_nan.rs | 0 .../intrinsics/float_to_int_32_nan.stderr | 0 .../intrinsics/float_to_int_32_nanneg.rs | 0 .../intrinsics/float_to_int_32_nanneg.stderr | 0 .../intrinsics/float_to_int_32_neg.rs | 0 .../intrinsics/float_to_int_32_neg.stderr | 0 .../intrinsics/float_to_int_32_too_big1.rs | 0 .../intrinsics/float_to_int_32_too_big1.stderr | 0 .../intrinsics/float_to_int_32_too_big2.rs | 0 .../intrinsics/float_to_int_32_too_big2.stderr | 0 .../intrinsics/float_to_int_32_too_small1.rs | 0 .../intrinsics/float_to_int_32_too_small1.stderr | 0 .../intrinsics/float_to_int_64_inf1.rs | 0 .../intrinsics/float_to_int_64_inf1.stderr | 0 .../intrinsics/float_to_int_64_infneg1.rs | 0 .../intrinsics/float_to_int_64_infneg1.stderr | 0 .../intrinsics/float_to_int_64_infneg2.rs | 0 .../intrinsics/float_to_int_64_infneg2.stderr | 0 .../intrinsics/float_to_int_64_nan.rs | 0 .../intrinsics/float_to_int_64_nan.stderr | 0 .../intrinsics/float_to_int_64_neg.rs | 0 .../intrinsics/float_to_int_64_neg.stderr | 0 .../intrinsics/float_to_int_64_too_big1.rs | 0 .../intrinsics/float_to_int_64_too_big1.stderr | 0 .../intrinsics/float_to_int_64_too_big2.rs | 0 .../intrinsics/float_to_int_64_too_big2.stderr | 0 .../intrinsics/float_to_int_64_too_big3.rs | 0 .../intrinsics/float_to_int_64_too_big3.stderr | 0 .../intrinsics/float_to_int_64_too_big4.rs | 0 .../intrinsics/float_to_int_64_too_big4.stderr | 0 .../intrinsics/float_to_int_64_too_big5.rs | 0 .../intrinsics/float_to_int_64_too_big5.stderr | 0 .../intrinsics/float_to_int_64_too_big6.rs | 0 .../intrinsics/float_to_int_64_too_big6.stderr | 0 .../intrinsics/float_to_int_64_too_big7.rs | 0 .../intrinsics/float_to_int_64_too_big7.stderr | 0 .../intrinsics/float_to_int_64_too_small1.rs | 0 .../intrinsics/float_to_int_64_too_small1.stderr | 0 .../intrinsics/float_to_int_64_too_small2.rs | 0 .../intrinsics/float_to_int_64_too_small2.stderr | 0 .../intrinsics/float_to_int_64_too_small3.rs | 0 .../intrinsics/float_to_int_64_too_small3.stderr | 0 .../intrinsics/out_of_bounds_ptr_1.rs | 0 .../intrinsics/out_of_bounds_ptr_1.stderr | 0 .../intrinsics/out_of_bounds_ptr_2.rs | 0 .../intrinsics/out_of_bounds_ptr_2.stderr | 0 .../intrinsics/out_of_bounds_ptr_3.rs | 0 .../intrinsics/out_of_bounds_ptr_3.stderr | 0 .../intrinsics/overflowing-unchecked-rsh.rs | 0 .../intrinsics/overflowing-unchecked-rsh.stderr | 0 .../intrinsics/ptr_offset_0_plus_0.rs | 0 .../intrinsics/ptr_offset_0_plus_0.stderr | 0 .../intrinsics/ptr_offset_from_oob.rs | 0 .../intrinsics/ptr_offset_from_oob.stderr | 0 .../intrinsics/ptr_offset_int_plus_int.rs | 0 .../intrinsics/ptr_offset_int_plus_int.stderr | 0 .../intrinsics/ptr_offset_int_plus_ptr.rs | 0 .../intrinsics/ptr_offset_int_plus_ptr.stderr | 0 .../intrinsics/ptr_offset_overflow.rs | 0 .../intrinsics/ptr_offset_overflow.stderr | 0 .../intrinsics/ptr_offset_ptr_plus_0.rs | 0 .../intrinsics/ptr_offset_ptr_plus_0.stderr | 0 tests/{compile-fail => fail}/intrinsics/rem-by-zero.rs | 0 tests/{compile-fail => fail}/intrinsics/rem-by-zero.stderr | 0 tests/{compile-fail => fail}/intrinsics/simd-div-by-zero.rs | 0 .../intrinsics/simd-div-by-zero.stderr | 0 .../{compile-fail => fail}/intrinsics/simd-div-overflow.rs | 0 .../intrinsics/simd-div-overflow.stderr | 0 .../{compile-fail => fail}/intrinsics/simd-float-to-int.rs | 0 .../intrinsics/simd-float-to-int.stderr | 0 tests/{compile-fail => fail}/intrinsics/simd-gather.rs | 0 tests/{compile-fail => fail}/intrinsics/simd-gather.stderr | 0 .../intrinsics/simd-reduce-invalid-bool.rs | 0 .../intrinsics/simd-reduce-invalid-bool.stderr | 0 tests/{compile-fail => fail}/intrinsics/simd-rem-by-zero.rs | 0 .../intrinsics/simd-rem-by-zero.stderr | 0 tests/{compile-fail => fail}/intrinsics/simd-scatter.rs | 0 tests/{compile-fail => fail}/intrinsics/simd-scatter.stderr | 0 .../intrinsics/simd-select-bitmask-invalid.rs | 0 .../intrinsics/simd-select-bitmask-invalid.stderr | 0 .../intrinsics/simd-select-invalid-bool.rs | 0 .../intrinsics/simd-select-invalid-bool.stderr | 0 tests/{compile-fail => fail}/intrinsics/simd-shl-too-far.rs | 0 .../intrinsics/simd-shl-too-far.stderr | 0 tests/{compile-fail => fail}/intrinsics/simd-shr-too-far.rs | 0 .../intrinsics/simd-shr-too-far.stderr | 0 tests/{compile-fail => fail}/intrinsics/unchecked_add1.rs | 0 .../{compile-fail => fail}/intrinsics/unchecked_add1.stderr | 0 tests/{compile-fail => fail}/intrinsics/unchecked_add2.rs | 0 .../{compile-fail => fail}/intrinsics/unchecked_add2.stderr | 0 tests/{compile-fail => fail}/intrinsics/unchecked_div1.rs | 0 .../{compile-fail => fail}/intrinsics/unchecked_div1.stderr | 0 tests/{compile-fail => fail}/intrinsics/unchecked_mul1.rs | 0 .../{compile-fail => fail}/intrinsics/unchecked_mul1.stderr | 0 tests/{compile-fail => fail}/intrinsics/unchecked_mul2.rs | 0 .../{compile-fail => fail}/intrinsics/unchecked_mul2.stderr | 0 tests/{compile-fail => fail}/intrinsics/unchecked_sub1.rs | 0 .../{compile-fail => fail}/intrinsics/unchecked_sub1.stderr | 0 tests/{compile-fail => fail}/intrinsics/unchecked_sub2.rs | 0 .../{compile-fail => fail}/intrinsics/unchecked_sub2.stderr | 0 .../intrinsics/uninit_uninhabited_type.rs | 0 .../intrinsics/uninit_uninhabited_type.stderr | 0 tests/{compile-fail => fail}/intrinsics/write_bytes_null.rs | 0 .../intrinsics/write_bytes_null.stderr | 0 .../intrinsics/write_bytes_overflow.rs | 0 .../intrinsics/write_bytes_overflow.stderr | 0 tests/{compile-fail => fail}/intrinsics/zero_fn_ptr.rs | 0 tests/{compile-fail => fail}/intrinsics/zero_fn_ptr.stderr | 0 tests/{compile-fail => fail}/invalid_bool.rs | 0 tests/{compile-fail => fail}/invalid_bool.stderr | 0 tests/{compile-fail => fail}/invalid_char.rs | 0 tests/{compile-fail => fail}/invalid_char.stderr | 0 tests/{compile-fail => fail}/invalid_enum_tag.rs | 0 tests/{compile-fail => fail}/invalid_enum_tag.stderr | 0 tests/{compile-fail => fail}/invalid_int.rs | 0 tests/{compile-fail => fail}/invalid_int.stderr | 0 tests/{compile-fail => fail}/issue-miri-1112.rs | 0 tests/{compile-fail => fail}/issue-miri-1112.stderr | 0 tests/{compile-fail => fail}/memleak.rs | 0 tests/{compile-fail => fail}/memleak.stderr | 0 tests/{compile-fail => fail}/memleak_rc.32bit.stderr | 0 tests/{compile-fail => fail}/memleak_rc.64bit.stderr | 0 tests/{compile-fail => fail}/memleak_rc.rs | 0 tests/{compile-fail => fail}/modifying_constants.rs | 0 tests/{compile-fail => fail}/modifying_constants.stderr | 0 tests/{compile-fail => fail}/never_say_never.rs | 0 tests/{compile-fail => fail}/never_say_never.stderr | 0 tests/{compile-fail => fail}/never_transmute_humans.rs | 0 tests/{compile-fail => fail}/never_transmute_humans.stderr | 0 tests/{compile-fail => fail}/never_transmute_void.rs | 0 tests/{compile-fail => fail}/never_transmute_void.stderr | 0 tests/{compile-fail => fail}/no_main.rs | 0 tests/{compile-fail => fail}/no_main.stderr | 0 tests/{compile-fail => fail}/null_pointer_deref.stderr | 0 tests/{compile-fail => fail}/null_pointer_deref_zst.stderr | 0 tests/{compile-fail => fail}/null_pointer_write.stderr | 0 tests/{compile-fail => fail}/null_pointer_write_zst.stderr | 0 tests/{compile-fail => fail}/panic/bad_miri_start_panic.rs | 0 .../panic/bad_miri_start_panic.stderr | 0 tests/{compile-fail => fail}/panic/bad_unwind.rs | 0 tests/{compile-fail => fail}/panic/bad_unwind.stderr | 0 tests/{compile-fail => fail}/panic/double_panic.rs | 0 tests/{compile-fail => fail}/panic/double_panic.stderr | 0 tests/{compile-fail => fail}/panic/panic_abort1.rs | 0 tests/{compile-fail => fail}/panic/panic_abort1.stderr | 0 tests/{compile-fail => fail}/panic/panic_abort2.rs | 0 tests/{compile-fail => fail}/panic/panic_abort2.stderr | 0 tests/{compile-fail => fail}/panic/panic_abort3.rs | 0 tests/{compile-fail => fail}/panic/panic_abort3.stderr | 0 tests/{compile-fail => fail}/panic/panic_abort4.rs | 0 tests/{compile-fail => fail}/panic/panic_abort4.stderr | 0 tests/{compile-fail => fail}/panic/unwind_panic_abort.rs | 0 .../{compile-fail => fail}/panic/unwind_panic_abort.stderr | 0 tests/{compile-fail => fail}/pointer_partial_overwrite.rs | 0 .../{compile-fail => fail}/pointer_partial_overwrite.stderr | 0 tests/{compile-fail => fail}/pointer_partial_read.rs | 0 tests/{compile-fail => fail}/pointer_partial_read.stderr | 0 .../{compile-fail => fail}/provenance/ptr_int_unexposed.rs | 0 .../provenance/ptr_int_unexposed.stderr | 0 tests/{compile-fail => fail}/provenance/ptr_invalid.rs | 0 tests/{compile-fail => fail}/provenance/ptr_invalid.stderr | 0 .../provenance/ptr_legacy_provenance.rs | 0 .../provenance/ptr_legacy_provenance.stderr | 0 .../provenance/strict-provenance-offset.rs | 0 .../provenance/strict-provenance-offset.stderr | 0 .../provenance/strict_provenance_transmute.rs | 0 .../provenance/strict_provenance_transmute.stderr | 0 .../ptr_integer_array_transmute.stderr | 0 tests/{compile-fail => fail}/ptr_integer_transmute.stderr | 0 tests/{compile-fail => fail}/rc_as_ptr.rs | 0 tests/{compile-fail => fail}/rc_as_ptr.stderr | 0 tests/{compile-fail => fail}/reading_half_a_pointer.rs | 0 tests/{compile-fail => fail}/reading_half_a_pointer.stderr | 0 tests/{compile-fail => fail}/rustc-error.rs | 0 tests/{compile-fail => fail}/rustc-error.stderr | 0 tests/{compile-fail => fail}/shim_arg_size.32bit.stderr | 0 tests/{compile-fail => fail}/shim_arg_size.64bit.stderr | 0 tests/{compile-fail => fail}/shim_arg_size.rs | 0 tests/{compile-fail => fail}/slice-too-big.stderr | 0 .../stacked_borrows/alias_through_mutation.rs | 0 .../stacked_borrows/alias_through_mutation.stderr | 0 .../{compile-fail => fail}/stacked_borrows/aliasing_mut1.rs | 0 .../stacked_borrows/aliasing_mut1.stderr | 0 .../{compile-fail => fail}/stacked_borrows/aliasing_mut2.rs | 0 .../stacked_borrows/aliasing_mut2.stderr | 0 .../{compile-fail => fail}/stacked_borrows/aliasing_mut3.rs | 0 .../stacked_borrows/aliasing_mut3.stderr | 0 .../{compile-fail => fail}/stacked_borrows/aliasing_mut4.rs | 0 .../stacked_borrows/aliasing_mut4.stderr | 0 .../stacked_borrows/box_exclusive_violation1.rs | 0 .../stacked_borrows/box_exclusive_violation1.stderr | 0 .../stacked_borrows/buggy_as_mut_slice.rs | 0 .../stacked_borrows/buggy_as_mut_slice.stderr | 0 .../stacked_borrows/buggy_split_at_mut.rs | 0 .../stacked_borrows/buggy_split_at_mut.stderr | 0 .../stacked_borrows/deallocate_against_barrier1.rs | 0 .../stacked_borrows/deallocate_against_barrier1.stderr | 0 .../stacked_borrows/deallocate_against_barrier2.rs | 0 .../stacked_borrows/deallocate_against_barrier2.stderr | 0 .../{compile-fail => fail}/stacked_borrows/illegal_read1.rs | 0 .../stacked_borrows/illegal_read1.stderr | 0 .../{compile-fail => fail}/stacked_borrows/illegal_read2.rs | 0 .../stacked_borrows/illegal_read2.stderr | 0 .../{compile-fail => fail}/stacked_borrows/illegal_read3.rs | 0 .../stacked_borrows/illegal_read3.stderr | 0 .../{compile-fail => fail}/stacked_borrows/illegal_read4.rs | 0 .../stacked_borrows/illegal_read4.stderr | 0 .../{compile-fail => fail}/stacked_borrows/illegal_read5.rs | 0 .../stacked_borrows/illegal_read5.stderr | 0 .../{compile-fail => fail}/stacked_borrows/illegal_read6.rs | 0 .../stacked_borrows/illegal_read6.stderr | 0 .../{compile-fail => fail}/stacked_borrows/illegal_read7.rs | 0 .../stacked_borrows/illegal_read7.stderr | 0 .../{compile-fail => fail}/stacked_borrows/illegal_read8.rs | 0 .../stacked_borrows/illegal_read8.stderr | 0 .../stacked_borrows/illegal_write1.rs | 0 .../stacked_borrows/illegal_write1.stderr | 0 .../stacked_borrows/illegal_write2.rs | 0 .../stacked_borrows/illegal_write2.stderr | 0 .../stacked_borrows/illegal_write3.rs | 0 .../stacked_borrows/illegal_write3.stderr | 0 .../stacked_borrows/illegal_write4.rs | 0 .../stacked_borrows/illegal_write4.stderr | 0 .../stacked_borrows/illegal_write5.rs | 0 .../stacked_borrows/illegal_write5.stderr | 0 .../stacked_borrows/illegal_write6.rs | 0 .../stacked_borrows/illegal_write6.stderr | 0 .../{compile-fail => fail}/stacked_borrows/interior_mut1.rs | 0 .../stacked_borrows/interior_mut1.stderr | 0 .../{compile-fail => fail}/stacked_borrows/interior_mut2.rs | 0 .../stacked_borrows/interior_mut2.stderr | 0 .../stacked_borrows/invalidate_against_barrier1.rs | 0 .../stacked_borrows/invalidate_against_barrier1.stderr | 0 .../stacked_borrows/invalidate_against_barrier2.rs | 0 .../stacked_borrows/invalidate_against_barrier2.stderr | 0 .../stacked_borrows/issue-miri-1050-1.rs | 0 .../stacked_borrows/issue-miri-1050-1.stderr | 0 .../stacked_borrows/issue-miri-1050-2.rs | 0 .../stacked_borrows/issue-miri-1050-2.stderr | 0 .../stacked_borrows/load_invalid_mut.rs | 0 .../stacked_borrows/load_invalid_mut.stderr | 0 .../stacked_borrows/load_invalid_shr.rs | 0 .../stacked_borrows/load_invalid_shr.stderr | 0 .../stacked_borrows/mut_exclusive_violation1.rs | 0 .../stacked_borrows/mut_exclusive_violation1.stderr | 0 .../stacked_borrows/mut_exclusive_violation2.rs | 0 .../stacked_borrows/mut_exclusive_violation2.stderr | 0 .../stacked_borrows/outdated_local.rs | 0 .../stacked_borrows/outdated_local.stderr | 0 .../stacked_borrows/pass_invalid_mut.rs | 0 .../stacked_borrows/pass_invalid_mut.stderr | 0 .../stacked_borrows/pass_invalid_shr.rs | 0 .../stacked_borrows/pass_invalid_shr.stderr | 0 .../stacked_borrows/pointer_smuggling.rs | 0 .../stacked_borrows/pointer_smuggling.stderr | 0 .../{compile-fail => fail}/stacked_borrows/raw_tracking.rs | 0 .../stacked_borrows/raw_tracking.stderr | 0 .../stacked_borrows/return_invalid_mut.rs | 0 .../stacked_borrows/return_invalid_mut.stderr | 0 .../stacked_borrows/return_invalid_mut_option.rs | 0 .../stacked_borrows/return_invalid_mut_option.stderr | 0 .../stacked_borrows/return_invalid_mut_tuple.rs | 0 .../stacked_borrows/return_invalid_mut_tuple.stderr | 0 .../stacked_borrows/return_invalid_shr.rs | 0 .../stacked_borrows/return_invalid_shr.stderr | 0 .../stacked_borrows/return_invalid_shr_option.rs | 0 .../stacked_borrows/return_invalid_shr_option.stderr | 0 .../stacked_borrows/return_invalid_shr_tuple.rs | 0 .../stacked_borrows/return_invalid_shr_tuple.stderr | 0 .../stacked_borrows/shared_rw_borrows_are_weak1.rs | 0 .../stacked_borrows/shared_rw_borrows_are_weak1.stderr | 0 .../stacked_borrows/shared_rw_borrows_are_weak2.rs | 0 .../stacked_borrows/shared_rw_borrows_are_weak2.stderr | 0 .../stacked_borrows/shr_frozen_violation1.rs | 0 .../stacked_borrows/shr_frozen_violation1.stderr | 0 .../stacked_borrows/static_memory_modification.rs | 0 .../stacked_borrows/static_memory_modification.stderr | 0 .../stacked_borrows/transmute-is-no-escape.rs | 0 .../stacked_borrows/transmute-is-no-escape.stderr | 0 .../stacked_borrows/unescaped_local.rs | 0 .../stacked_borrows/unescaped_local.stderr | 0 .../stacked_borrows/unescaped_static.rs | 0 .../stacked_borrows/unescaped_static.stderr | 0 tests/{compile-fail => fail}/stacked_borrows/zst_slice.rs | 0 .../{compile-fail => fail}/stacked_borrows/zst_slice.stderr | 0 tests/{compile-fail => fail}/static_memory_modification1.rs | 0 .../static_memory_modification1.stderr | 0 tests/{compile-fail => fail}/static_memory_modification2.rs | 0 .../static_memory_modification2.stderr | 0 tests/{compile-fail => fail}/static_memory_modification3.rs | 0 .../static_memory_modification3.stderr | 0 .../{compile-fail => fail}/strict-provenance-offset.stderr | 0 .../strict_provenance_transmute.stderr | 0 .../sync/libc_pthread_cond_double_destroy.rs | 0 .../sync/libc_pthread_cond_double_destroy.stderr | 0 .../sync/libc_pthread_condattr_double_destroy.rs | 0 .../sync/libc_pthread_condattr_double_destroy.stderr | 0 .../sync/libc_pthread_mutex_NULL_deadlock.rs | 0 .../sync/libc_pthread_mutex_NULL_deadlock.stderr | 0 .../sync/libc_pthread_mutex_deadlock.rs | 0 .../sync/libc_pthread_mutex_deadlock.stderr | 0 .../sync/libc_pthread_mutex_default_deadlock.rs | 0 .../sync/libc_pthread_mutex_default_deadlock.stderr | 0 .../sync/libc_pthread_mutex_destroy_locked.rs | 0 .../sync/libc_pthread_mutex_destroy_locked.stderr | 0 .../sync/libc_pthread_mutex_double_destroy.rs | 0 .../sync/libc_pthread_mutex_double_destroy.stderr | 0 .../sync/libc_pthread_mutex_normal_deadlock.rs | 0 .../sync/libc_pthread_mutex_normal_deadlock.stderr | 0 .../sync/libc_pthread_mutex_normal_unlock_unlocked.rs | 0 .../sync/libc_pthread_mutex_normal_unlock_unlocked.stderr | 0 .../sync/libc_pthread_mutex_wrong_owner.rs | 0 .../sync/libc_pthread_mutex_wrong_owner.stderr | 0 .../sync/libc_pthread_mutexattr_double_destroy.rs | 0 .../sync/libc_pthread_mutexattr_double_destroy.stderr | 0 .../sync/libc_pthread_rwlock_destroy_read_locked.rs | 0 .../sync/libc_pthread_rwlock_destroy_read_locked.stderr | 0 .../sync/libc_pthread_rwlock_destroy_write_locked.rs | 0 .../sync/libc_pthread_rwlock_destroy_write_locked.stderr | 0 .../sync/libc_pthread_rwlock_double_destroy.rs | 0 .../sync/libc_pthread_rwlock_double_destroy.stderr | 0 ...libc_pthread_rwlock_read_write_deadlock_single_thread.rs | 0 ..._pthread_rwlock_read_write_deadlock_single_thread.stderr | 0 .../sync/libc_pthread_rwlock_read_wrong_owner.rs | 0 .../sync/libc_pthread_rwlock_read_wrong_owner.stderr | 0 .../sync/libc_pthread_rwlock_unlock_unlocked.rs | 0 .../sync/libc_pthread_rwlock_unlock_unlocked.stderr | 0 .../sync/libc_pthread_rwlock_write_read_deadlock.rs | 0 .../sync/libc_pthread_rwlock_write_read_deadlock.stderr | 0 ...libc_pthread_rwlock_write_read_deadlock_single_thread.rs | 0 ..._pthread_rwlock_write_read_deadlock_single_thread.stderr | 0 .../sync/libc_pthread_rwlock_write_write_deadlock.rs | 0 .../sync/libc_pthread_rwlock_write_write_deadlock.stderr | 0 ...ibc_pthread_rwlock_write_write_deadlock_single_thread.rs | 0 ...pthread_rwlock_write_write_deadlock_single_thread.stderr | 0 .../sync/libc_pthread_rwlock_write_wrong_owner.rs | 0 .../sync/libc_pthread_rwlock_write_wrong_owner.stderr | 0 tests/{compile-fail => fail}/too-big-slice.stderr | 0 tests/{compile-fail => fail}/too-big-unsized.stderr | 0 tests/{compile-fail => fail}/transmute-pair-uninit.rs | 0 tests/{compile-fail => fail}/transmute-pair-uninit.stderr | 0 tests/{compile-fail => fail}/transmute_fat1.rs | 0 tests/{compile-fail => fail}/transmute_fat1.stderr | 0 tests/{compile-fail => fail}/type-too-large.rs | 0 tests/{compile-fail => fail}/type-too-large.stderr | 0 .../{compile-fail => fail}/unaligned_pointers/alignment.rs | 0 .../unaligned_pointers/alignment.stderr | 0 .../unaligned_pointers/atomic_unaligned.rs | 0 .../unaligned_pointers/atomic_unaligned.stderr | 0 .../unaligned_pointers/dyn_alignment.rs | 0 .../unaligned_pointers/dyn_alignment.stderr | 0 .../unaligned_pointers/intptrcast_alignment_check.rs | 0 .../unaligned_pointers/intptrcast_alignment_check.stderr | 0 .../unaligned_pointers/reference_to_packed.rs | 0 .../unaligned_pointers/reference_to_packed.stderr | 0 .../unaligned_pointers/unaligned_ptr1.rs | 0 .../unaligned_pointers/unaligned_ptr1.stderr | 0 .../unaligned_pointers/unaligned_ptr2.rs | 0 .../unaligned_pointers/unaligned_ptr2.stderr | 0 .../unaligned_pointers/unaligned_ptr3.rs | 0 .../unaligned_pointers/unaligned_ptr3.stderr | 0 .../unaligned_pointers/unaligned_ptr4.rs | 0 .../unaligned_pointers/unaligned_ptr4.stderr | 0 .../unaligned_pointers/unaligned_ptr_addr_of.rs | 0 .../unaligned_pointers/unaligned_ptr_addr_of.stderr | 0 .../unaligned_pointers/unaligned_ptr_zst.rs | 0 .../unaligned_pointers/unaligned_ptr_zst.stderr | 0 tests/{compile-fail => fail}/uninit_buffer.rs | 0 tests/{compile-fail => fail}/uninit_buffer.stderr | 0 tests/{compile-fail => fail}/uninit_byte_read.rs | 0 tests/{compile-fail => fail}/uninit_byte_read.stderr | 0 tests/{compile-fail => fail}/uninit_float.stderr | 0 tests/{compile-fail => fail}/uninit_integer.stderr | 0 tests/{compile-fail => fail}/uninit_integer_signed.stderr | 0 tests/{compile-fail => fail}/uninit_raw_ptr.rs | 0 tests/{compile-fail => fail}/uninit_raw_ptr.stderr | 0 tests/{compile-fail => fail}/unreachable.rs | 0 tests/{compile-fail => fail}/unreachable.stderr | 0 .../{compile-fail => fail}/unsupported_foreign_function.rs | 0 .../unsupported_foreign_function.stderr | 0 tests/{compile-fail => fail}/unsupported_signal.rs | 0 tests/{compile-fail => fail}/unsupported_signal.stderr | 0 tests/{compile-fail => fail}/validity/cast_fn_ptr1.rs | 0 tests/{compile-fail => fail}/validity/cast_fn_ptr1.stderr | 0 tests/{compile-fail => fail}/validity/cast_fn_ptr2.rs | 0 tests/{compile-fail => fail}/validity/cast_fn_ptr2.stderr | 0 tests/{compile-fail => fail}/validity/dangling_ref1.rs | 0 tests/{compile-fail => fail}/validity/dangling_ref1.stderr | 0 tests/{compile-fail => fail}/validity/dangling_ref2.rs | 0 tests/{compile-fail => fail}/validity/dangling_ref2.stderr | 0 tests/{compile-fail => fail}/validity/dangling_ref3.rs | 0 tests/{compile-fail => fail}/validity/dangling_ref3.stderr | 0 tests/{compile-fail => fail}/validity/invalid_bool.rs | 0 tests/{compile-fail => fail}/validity/invalid_bool.stderr | 0 .../{compile-fail => fail}/validity/invalid_bool_uninit.rs | 0 .../validity/invalid_bool_uninit.stderr | 0 tests/{compile-fail => fail}/validity/invalid_char.rs | 0 tests/{compile-fail => fail}/validity/invalid_char.stderr | 0 .../{compile-fail => fail}/validity/invalid_char_uninit.rs | 0 .../validity/invalid_char_uninit.stderr | 0 tests/{compile-fail => fail}/validity/invalid_enum_tag.rs | 0 .../{compile-fail => fail}/validity/invalid_enum_tag.stderr | 0 .../validity/invalid_enum_tag_256variants_uninit.rs | 0 .../validity/invalid_enum_tag_256variants_uninit.stderr | 0 tests/{compile-fail => fail}/validity/invalid_fnptr_null.rs | 0 .../validity/invalid_fnptr_null.stderr | 0 .../{compile-fail => fail}/validity/invalid_fnptr_uninit.rs | 0 .../validity/invalid_fnptr_uninit.stderr | 0 tests/{compile-fail => fail}/validity/invalid_wide_raw.rs | 0 .../{compile-fail => fail}/validity/invalid_wide_raw.stderr | 0 tests/{compile-fail => fail}/validity/nonzero.rs | 0 tests/{compile-fail => fail}/validity/nonzero.stderr | 0 .../validity/ptr_integer_array_transmute.rs | 0 .../validity/ptr_integer_array_transmute.stderr | 0 .../validity/ptr_integer_transmute.rs | 0 .../validity/ptr_integer_transmute.stderr | 0 .../{compile-fail => fail}/validity/ref_to_uninhabited1.rs | 0 .../validity/ref_to_uninhabited1.stderr | 0 .../{compile-fail => fail}/validity/ref_to_uninhabited2.rs | 0 .../validity/ref_to_uninhabited2.stderr | 0 tests/{compile-fail => fail}/validity/too-big-slice.rs | 0 tests/{compile-fail => fail}/validity/too-big-slice.stderr | 0 tests/{compile-fail => fail}/validity/too-big-unsized.rs | 0 .../{compile-fail => fail}/validity/too-big-unsized.stderr | 0 .../validity/transmute_through_ptr.rs | 0 .../validity/transmute_through_ptr.stderr | 0 tests/{compile-fail => fail}/validity/uninit_float.rs | 0 tests/{compile-fail => fail}/validity/uninit_float.stderr | 0 tests/{compile-fail => fail}/validity/uninit_integer.rs | 0 tests/{compile-fail => fail}/validity/uninit_integer.stderr | 0 .../validity/uninit_integer_signed.rs | 0 .../validity/uninit_integer_signed.stderr | 0 tests/{compile-fail => fail}/zst1.rs | 0 tests/{compile-fail => fail}/zst1.stderr | 0 tests/{compile-fail => fail}/zst2.rs | 0 tests/{compile-fail => fail}/zst2.stderr | 0 tests/{compile-fail => fail}/zst3.rs | 0 tests/{compile-fail => fail}/zst3.stderr | 0 .../function_calls/exported_symbol_good_unwind.rs | 0 .../function_calls/exported_symbol_good_unwind.stderr | 0 tests/{run-fail => panic}/panic/div-by-zero-2.rs | 0 tests/{run-fail => panic}/panic/div-by-zero-2.stderr | 0 tests/{run-fail => panic}/panic/overflowing-lsh-neg.rs | 0 tests/{run-fail => panic}/panic/overflowing-lsh-neg.stderr | 0 tests/{run-fail => panic}/panic/overflowing-rsh-1.rs | 0 tests/{run-fail => panic}/panic/overflowing-rsh-1.stderr | 0 tests/{run-fail => panic}/panic/overflowing-rsh-2.rs | 0 tests/{run-fail => panic}/panic/overflowing-rsh-2.stderr | 0 tests/{run-fail => panic}/panic/panic1.rs | 0 tests/{run-fail => panic}/panic/panic1.stderr | 0 tests/{run-fail => panic}/panic/panic2.rs | 0 tests/{run-fail => panic}/panic/panic2.stderr | 0 tests/{run-fail => panic}/panic/panic3.rs | 0 tests/{run-fail => panic}/panic/panic3.stderr | 0 tests/{run-fail => panic}/panic/panic4.rs | 0 tests/{run-fail => panic}/panic/panic4.stderr | 0 .../panic/unsupported_foreign_function.rs | 0 .../panic/unsupported_foreign_function.stderr | 0 tests/{run-fail => panic}/panic/unsupported_syscall.rs | 0 tests/{run-fail => panic}/panic/unsupported_syscall.stderr | 0 tests/{run-fail => panic}/transmute_fat2.rs | 0 tests/{run-fail => panic}/transmute_fat2.stderr | 0 tests/{run-pass => pass}/adjacent-allocs.rs | 0 tests/{run-pass => pass}/align.rs | 0 tests/{run-pass => pass}/align_offset_symbolic.rs | 0 tests/{run-pass => pass}/align_offset_symbolic.stdout | 0 tests/{run-pass => pass}/args.rs | 0 tests/{run-pass => pass}/args.stdout | 0 tests/{run-pass => pass}/arrays.rs | 0 tests/{run-pass => pass}/arrays.stdout | 0 tests/{run-pass => pass}/associated-const.rs | 0 tests/{run-pass => pass}/assume_bug.rs | 0 tests/{run-pass => pass}/async-fn.rs | 0 .../atomic-compare-exchange-weak-never-fail.rs | 0 tests/{run-pass => pass}/atomic.rs | 0 tests/{run-pass => pass}/available-parallelism.rs | 0 tests/{run-pass => pass}/backtrace-api-v0.rs | 0 tests/{run-pass => pass}/backtrace-api-v0.stderr | 0 tests/{run-pass => pass}/backtrace-api-v0.stdout | 0 tests/{run-pass => pass}/backtrace-api-v1.rs | 0 tests/{run-pass => pass}/backtrace-api-v1.stderr | 0 tests/{run-pass => pass}/backtrace-api-v1.stdout | 0 tests/{run-pass => pass}/backtrace-std.rs | 0 tests/{run-pass => pass}/backtrace-std.stderr | 0 tests/{run-pass => pass}/bad_substs.rs | 0 tests/{run-pass => pass}/binary-heap.rs | 0 tests/{run-pass => pass}/binops.rs | 0 tests/{run-pass => pass}/bools.rs | 0 tests/{run-pass => pass}/box.rs | 0 tests/{run-pass => pass}/box.stdout | 0 tests/{run-pass => pass}/btreemap.rs | 0 tests/{run-pass => pass}/c_enums.rs | 0 tests/{run-pass => pass}/calloc.rs | 0 tests/{run-pass => pass}/calls.rs | 0 tests/{run-pass => pass}/cast-rfc0401-vtable-kinds.rs | 0 tests/{run-pass => pass}/cast_fn_ptr.rs | 0 tests/{run-pass => pass}/cast_fn_ptr_unsafe.rs | 0 tests/{run-pass => pass}/catch.rs | 0 tests/{run-pass => pass}/catch.stdout | 0 tests/{run-pass => pass}/cfg_miri.rs | 0 tests/{run-pass => pass}/char.rs | 0 tests/{run-pass => pass}/closure-drop.rs | 0 tests/{run-pass => pass}/closure-field-ty.rs | 0 tests/{run-pass => pass}/closures.rs | 0 .../coerce_non_capture_closure_to_fn_ptr.rs | 0 tests/{run-pass => pass}/coercions.rs | 0 tests/{run-pass => pass}/concurrency/channels.rs | 0 tests/{run-pass => pass}/concurrency/channels.stderr | 0 .../concurrency/concurrent_caller_location.rs | 0 .../concurrency/concurrent_caller_location.stderr | 0 tests/{run-pass => pass}/concurrency/data_race.rs | 0 tests/{run-pass => pass}/concurrency/data_race.stderr | 0 .../concurrency/disable_data_race_detector.rs | 0 .../concurrency/disable_data_race_detector.stderr | 0 tests/{run-pass => pass}/concurrency/issue1643.rs | 0 tests/{run-pass => pass}/concurrency/issue1643.stderr | 0 tests/{run-pass => pass}/concurrency/libc_pthread_cond.rs | 0 tests/{run-pass => pass}/concurrency/linux-futex.rs | 0 tests/{run-pass => pass}/concurrency/linux-futex.stderr | 0 tests/{run-pass => pass}/concurrency/simple.rs | 0 tests/{run-pass => pass}/concurrency/simple.stderr | 0 tests/{run-pass => pass}/concurrency/sync.rs | 0 tests/{run-pass => pass}/concurrency/sync.stderr | 0 tests/{run-pass => pass}/concurrency/sync.stdout | 0 tests/{run-pass => pass}/concurrency/sync_singlethread.rs | 0 tests/{run-pass => pass}/concurrency/thread_locals.rs | 0 tests/{run-pass => pass}/concurrency/thread_locals.stderr | 0 tests/{run-pass => pass}/concurrency/tls_lib_drop.rs | 0 tests/{run-pass => pass}/concurrency/tls_lib_drop.stderr | 0 tests/{run-pass => pass}/concurrency/tls_lib_drop.stdout | 0 .../concurrency/tls_lib_drop_single_thread.rs | 0 .../concurrency/tls_lib_drop_single_thread.stderr | 0 .../concurrency/tls_pthread_drop_order.rs | 0 tests/{run-pass => pass}/const-vec-of-fns.rs | 0 tests/{run-pass => pass}/constants.rs | 0 tests/{run-pass => pass}/current_dir.rs | 0 tests/{run-pass => pass}/current_dir_with_isolation.rs | 0 tests/{run-pass => pass}/current_dir_with_isolation.stderr | 0 tests/{run-pass => pass}/deriving-associated-types.rs | 0 tests/{run-pass => pass}/disable-alignment-check.rs | 0 tests/{run-pass => pass}/drop_empty_slice.rs | 0 tests/{run-pass => pass}/drop_on_array_elements.rs | 0 tests/{run-pass => pass}/drop_on_fat_ptr_array_elements.rs | 0 tests/{run-pass => pass}/drop_on_zst_array_elements.rs | 0 tests/{run-pass => pass}/drop_through_owned_slice.rs | 0 tests/{run-pass => pass}/drop_through_trait_object.rs | 0 tests/{run-pass => pass}/drop_through_trait_object_rc.rs | 0 tests/{run-pass => pass}/dst-field-align.rs | 0 tests/{run-pass => pass}/dst-irrefutable-bind.rs | 0 tests/{run-pass => pass}/dst-raw.rs | 0 tests/{run-pass => pass}/dst-struct-sole.rs | 0 tests/{run-pass => pass}/dst-struct.rs | 0 tests/{run-pass => pass}/dyn-arbitrary-self.rs | 0 tests/{run-pass => pass}/dyn-traits.rs | 0 .../enum-nullable-const-null-with-fields.rs | 0 tests/{run-pass => pass}/enum_discriminant_ptr_value.rs | 0 tests/{run-pass => pass}/enums.rs | 0 tests/{run-pass => pass}/env-exclude.rs | 0 tests/{run-pass => pass}/env-forward.rs | 0 tests/{run-pass => pass}/env-without-isolation.rs | 0 tests/{run-pass => pass}/env.rs | 0 tests/{run-pass => pass}/env.stdout | 0 tests/{run-pass => pass}/exit.rs | 0 tests/{run-pass => pass}/extern_crate_std_in_main.rs | 0 tests/{run-pass => pass}/extern_types.rs | 0 tests/{run-pass => pass}/fat_ptr.rs | 0 tests/{run-pass => pass}/float.rs | 0 tests/{run-pass => pass}/float_fast_math.rs | 0 tests/{run-pass => pass}/foreign-fn-linkname.rs | 0 tests/{run-pass => pass}/format.rs | 0 tests/{run-pass => pass}/format.stdout | 0 tests/{run-pass => pass}/from_utf8.rs | 0 tests/{run-pass => pass}/fs.rs | 0 tests/{run-pass => pass}/fs.stderr | 0 tests/{run-pass => pass}/fs.stdout | 0 tests/{run-pass => pass}/fs_with_isolation.rs | 0 tests/{run-pass => pass}/fs_with_isolation.stderr | 0 .../{run-pass => pass}/function_calls/disable_abi_check.rs | 0 tests/{run-pass => pass}/function_calls/exported_symbol.rs | 0 tests/{run-pass => pass}/function_pointers.rs | 0 tests/{run-pass => pass}/generator.rs | 0 tests/{run-pass => pass}/global_allocator.rs | 0 tests/{run-pass => pass}/global_allocator.stdout | 0 tests/{run-pass => pass}/hashmap.rs | 0 tests/{run-pass => pass}/heap.rs | 0 tests/{run-pass => pass}/heap_allocator.rs | 0 tests/{run-pass => pass}/hello.rs | 0 tests/{run-pass => pass}/hello.stdout | 0 tests/{run-pass => pass}/hide_stdout.rs | 0 tests/{run-pass => pass}/integer-ops.rs | 0 tests/{run-pass => pass}/intptrcast.rs | 0 tests/{run-pass => pass}/intrinsics-integer.rs | 0 tests/{run-pass => pass}/intrinsics-math.rs | 0 tests/{run-pass => pass}/intrinsics-x86.rs | 0 tests/{run-pass => pass}/intrinsics.rs | 0 tests/{run-pass => pass}/ints.rs | 0 tests/{run-pass => pass}/issue-15063.rs | 0 tests/{run-pass => pass}/issue-15080.rs | 0 tests/{run-pass => pass}/issue-15523-big.rs | 0 tests/{run-pass => pass}/issue-17877.rs | 0 tests/{run-pass => pass}/issue-20575.rs | 0 tests/{run-pass => pass}/issue-23261.rs | 0 tests/{run-pass => pass}/issue-26709.rs | 0 tests/{run-pass => pass}/issue-27901.rs | 0 tests/{run-pass => pass}/issue-29746.rs | 0 tests/{run-pass => pass}/issue-30530.rs | 0 tests/{run-pass => pass}/issue-31267-additional.rs | 0 tests/{run-pass => pass}/issue-33387.rs | 0 tests/{run-pass => pass}/issue-34571.rs | 0 tests/{run-pass => pass}/issue-35815.rs | 0 tests/{run-pass => pass}/issue-36278-prefix-nesting.rs | 0 tests/{run-pass => pass}/issue-3794.rs | 0 tests/{run-pass => pass}/issue-3794.stdout | 0 tests/{run-pass => pass}/issue-53728.rs | 0 tests/{run-pass => pass}/issue-5917.rs | 0 tests/{run-pass => pass}/issue-73223.rs | 0 tests/{run-pass => pass}/issue-91636.rs | 0 tests/{run-pass => pass}/issue-94371.rs | 0 tests/{run-pass => pass}/issue-miri-1075.rs | 0 tests/{run-pass => pass}/issue-miri-133.rs | 0 tests/{run-pass => pass}/issue-miri-184.rs | 0 tests/{run-pass => pass}/issue-miri-1925.rs | 0 tests/{run-pass => pass}/issue-miri-2068-2.rs | 0 tests/{run-pass => pass}/issue-miri-2068.rs | 0 tests/{run-pass => pass}/iter.rs | 0 tests/{run-pass => pass}/last-use-in-cap-clause.rs | 0 tests/{run-pass => pass}/leak-in-static.rs | 0 tests/{run-pass => pass}/libc.rs | 0 tests/{run-pass => pass}/libc.stderr | 0 tests/{run-pass => pass}/linked-list.rs | 0 .../{run-pass => pass}/linux-getrandom-without-isolation.rs | 0 tests/{run-pass => pass}/linux-getrandom.rs | 0 tests/{run-pass => pass}/loop-break-value.rs | 0 tests/{run-pass => pass}/loops.rs | 0 tests/{run-pass => pass}/main_fn.rs | 0 tests/{run-pass => pass}/main_result.rs | 0 tests/{run-pass => pass}/malloc.rs | 0 tests/{run-pass => pass}/many_shr_bor.rs | 0 tests/{run-pass => pass}/match_slice.rs | 0 tests/{run-pass => pass}/memchr.rs | 0 tests/{run-pass => pass}/memleak_ignored.rs | 0 tests/{run-pass => pass}/move-arg-2-unique.rs | 0 tests/{run-pass => pass}/move-arg-3-unique.rs | 0 tests/{run-pass => pass}/move-uninit-primval.rs | 0 tests/{run-pass => pass}/mpsc.rs | 0 tests/{run-pass => pass}/multi_arg_closure.rs | 0 tests/{run-pass => pass}/negative_discriminant.rs | 0 tests/{run-pass => pass}/observed_local_mut.rs | 0 tests/{run-pass => pass}/option_box_transmute_ptr.rs | 0 tests/{run-pass => pass}/option_eq.rs | 0 tests/{run-pass => pass}/overflow_checks_off.rs | 0 tests/{run-pass => pass}/overloaded-calls-simple.rs | 0 tests/{run-pass => pass}/packed_struct.rs | 0 tests/{run-pass => pass}/panic/catch_panic.rs | 0 tests/{run-pass => pass}/panic/catch_panic.stderr | 0 tests/{run-pass => pass}/panic/concurrent-panic.rs | 0 tests/{run-pass => pass}/panic/concurrent-panic.stderr | 0 tests/{run-pass => pass}/panic/std-panic-locations.rs | 0 tests/{run-pass => pass}/partially-uninit.rs | 0 tests/{run-pass => pass}/pointers.rs | 0 tests/{run-pass => pass}/portable-simd.rs | 0 tests/{run-pass => pass}/products.rs | 0 tests/{run-pass => pass}/ptr_int_casts.rs | 0 tests/{run-pass => pass}/ptr_int_permissive_provenance.rs | 0 tests/{run-pass => pass}/ptr_offset.rs | 0 tests/{run-pass => pass}/ptr_raw.rs | 0 tests/{run-pass => pass}/rc.rs | 0 tests/{run-pass => pass}/recursive_static.rs | 0 tests/{run-pass => pass}/reentrant-println.rs | 0 tests/{run-pass => pass}/reentrant-println.stdout | 0 .../regions-lifetime-nonfree-late-bound.rs | 0 tests/{run-pass => pass}/regions-mock-trans.rs | 0 tests/{run-pass => pass}/rename_std.rs | 0 tests/{run-pass => pass}/rfc1623.rs | 0 tests/{run-pass => pass}/rust-lang-org.rs | 0 tests/{run-pass => pass}/send-is-not-static-par-for.rs | 0 tests/{run-pass => pass}/sendable-class.rs | 0 tests/{run-pass => pass}/simd-intrinsic-generic-elements.rs | 0 tests/{run-pass => pass}/slices.rs | 0 tests/{run-pass => pass}/small_enum_size_bug.rs | 0 tests/{run-pass => pass}/specialization.rs | 0 tests/{run-pass => pass}/stacked-borrows/2phase.rs | 0 .../stacked-borrows/generators-self-referential.rs | 0 tests/{run-pass => pass}/stacked-borrows/int-to-ptr.rs | 0 .../stacked-borrows/interior_mutability.rs | 0 tests/{run-pass => pass}/stacked-borrows/refcell.rs | 0 tests/{run-pass => pass}/stacked-borrows/stacked-borrows.rs | 0 .../stacked-borrows/stacked-borrows.stderr | 0 tests/{run-pass => pass}/start.rs | 0 tests/{run-pass => pass}/start.stdout | 0 tests/{run-pass => pass}/static_memory_modification.rs | 0 tests/{run-pass => pass}/static_mut.rs | 0 tests/{run-pass => pass}/strings.rs | 0 tests/{run-pass => pass}/subslice_array.rs | 0 tests/{run-pass => pass}/sums.rs | 0 tests/{run-pass => pass}/tag-align-dyn-u64.rs | 0 tests/{run-pass => pass}/threadleak_ignored.rs | 0 tests/{run-pass => pass}/threadleak_ignored.stderr | 0 tests/{run-pass => pass}/time.rs | 0 tests/{run-pass => pass}/too-large-primval-write-problem.rs | 0 tests/{run-pass => pass}/track-alloc-1.rs | 0 tests/{run-pass => pass}/track-alloc-1.stderr | 0 tests/{run-pass => pass}/track-caller-attribute.rs | 0 tests/{run-pass => pass}/transmute_fat.rs | 0 tests/{run-pass => pass}/trivial.rs | 0 tests/{run-pass => pass}/try-operator-custom.rs | 0 .../tuple_like_enum_variant_constructor.rs | 0 .../tuple_like_enum_variant_constructor_pointer_opt.rs | 0 ...uple_like_enum_variant_constructor_struct_pointer_opt.rs | 0 tests/{run-pass => pass}/tuple_like_struct_constructor.rs | 0 tests/{run-pass => pass}/u128.rs | 0 tests/{run-pass => pass}/uninit_number_ignored.rs | 0 tests/{run-pass => pass}/union-overwrite.rs | 0 tests/{run-pass => pass}/union.rs | 0 tests/{run-pass => pass}/unops.rs | 0 tests/{run-pass => pass}/unsized-tuple-impls.rs | 0 tests/{run-pass => pass}/validation_lifetime_resolution.rs | 0 tests/{run-pass => pass}/vec-matching-fold.rs | 0 tests/{run-pass => pass}/vec.rs | 0 tests/{run-pass => pass}/vecdeque.rs | 0 tests/{run-pass => pass}/vecdeque.stdout | 0 tests/{run-pass => pass}/volatile.rs | 0 tests/{run-pass => pass}/without-validation.rs | 0 tests/{run-pass => pass}/write-bytes.rs | 0 tests/{run-pass => pass}/wtf8.rs | 0 tests/{run-pass => pass}/zst.rs | 0 tests/{run-pass => pass}/zst_box.rs | 0 tests/{run-pass => pass}/zst_variant_drop.rs | 0 979 files changed, 4 insertions(+), 4 deletions(-) rename tests/{compile-fail => fail}/abort-terminator.rs (100%) rename tests/{compile-fail => fail}/abort-terminator.stderr (100%) rename tests/{compile-fail => fail}/alloc/deallocate-bad-alignment.rs (100%) rename tests/{compile-fail => fail}/alloc/deallocate-bad-alignment.stderr (100%) rename tests/{compile-fail => fail}/alloc/deallocate-bad-size.rs (100%) rename tests/{compile-fail => fail}/alloc/deallocate-bad-size.stderr (100%) rename tests/{compile-fail => fail}/alloc/deallocate-twice.rs (100%) rename tests/{compile-fail => fail}/alloc/deallocate-twice.stderr (100%) rename tests/{compile-fail => fail}/alloc/global_system_mixup.rs (100%) rename tests/{compile-fail => fail}/alloc/global_system_mixup.stderr (100%) rename tests/{compile-fail => fail}/alloc/no_global_allocator.rs (100%) rename tests/{compile-fail => fail}/alloc/no_global_allocator.stderr (100%) rename tests/{compile-fail => fail}/alloc/reallocate-bad-size.rs (100%) rename tests/{compile-fail => fail}/alloc/reallocate-bad-size.stderr (100%) rename tests/{compile-fail => fail}/alloc/reallocate-change-alloc.rs (100%) rename tests/{compile-fail => fail}/alloc/reallocate-change-alloc.stderr (100%) rename tests/{compile-fail => fail}/alloc/reallocate-dangling.rs (100%) rename tests/{compile-fail => fail}/alloc/reallocate-dangling.stderr (100%) rename tests/{compile-fail => fail}/alloc/stack_free.rs (100%) rename tests/{compile-fail => fail}/alloc/stack_free.stderr (100%) rename tests/{compile-fail => fail}/backtrace/bad-backtrace-decl.rs (100%) rename tests/{compile-fail => fail}/backtrace/bad-backtrace-decl.stderr (100%) rename tests/{compile-fail => fail}/backtrace/bad-backtrace-flags.rs (100%) rename tests/{compile-fail => fail}/backtrace/bad-backtrace-flags.stderr (100%) rename tests/{compile-fail => fail}/backtrace/bad-backtrace-ptr.rs (100%) rename tests/{compile-fail => fail}/backtrace/bad-backtrace-ptr.stderr (100%) rename tests/{compile-fail => fail}/backtrace/bad-backtrace-resolve-flags.rs (100%) rename tests/{compile-fail => fail}/backtrace/bad-backtrace-resolve-flags.stderr (100%) rename tests/{compile-fail => fail}/backtrace/bad-backtrace-resolve-names-flags.rs (100%) rename tests/{compile-fail => fail}/backtrace/bad-backtrace-resolve-names-flags.stderr (100%) rename tests/{compile-fail => fail}/backtrace/bad-backtrace-size-flags.rs (100%) rename tests/{compile-fail => fail}/backtrace/bad-backtrace-size-flags.stderr (100%) rename tests/{compile-fail => fail}/backtrace/bad-backtrace-version.stderr (100%) rename tests/{compile-fail => fail}/box-cell-alias.rs (100%) rename tests/{compile-fail => fail}/box-cell-alias.stderr (100%) rename tests/{compile-fail => fail}/branchless-select-i128-pointer.rs (100%) rename tests/{compile-fail => fail}/branchless-select-i128-pointer.stderr (100%) rename tests/{compile-fail => fail}/breakpoint.rs (100%) rename tests/{compile-fail => fail}/breakpoint.stderr (100%) rename tests/{compile-fail => fail}/concurrency/libc_pthread_create_main_terminate.rs (100%) rename tests/{compile-fail => fail}/concurrency/libc_pthread_create_main_terminate.stderr (100%) rename tests/{compile-fail => fail}/concurrency/libc_pthread_join_detached.rs (100%) rename tests/{compile-fail => fail}/concurrency/libc_pthread_join_detached.stderr (100%) rename tests/{compile-fail => fail}/concurrency/libc_pthread_join_joined.rs (100%) rename tests/{compile-fail => fail}/concurrency/libc_pthread_join_joined.stderr (100%) rename tests/{compile-fail => fail}/concurrency/libc_pthread_join_main.rs (100%) rename tests/{compile-fail => fail}/concurrency/libc_pthread_join_main.stderr (100%) rename tests/{compile-fail => fail}/concurrency/libc_pthread_join_multiple.rs (100%) rename tests/{compile-fail => fail}/concurrency/libc_pthread_join_multiple.stderr (100%) rename tests/{compile-fail => fail}/concurrency/libc_pthread_join_self.rs (100%) rename tests/{compile-fail => fail}/concurrency/libc_pthread_join_self.stderr (100%) rename tests/{compile-fail => fail}/concurrency/thread-spawn.rs (100%) rename tests/{compile-fail => fail}/concurrency/thread_local_static_dealloc.rs (100%) rename tests/{compile-fail => fail}/concurrency/thread_local_static_dealloc.stderr (100%) rename tests/{compile-fail => fail}/concurrency/too_few_args.rs (100%) rename tests/{compile-fail => fail}/concurrency/too_few_args.stderr (100%) rename tests/{compile-fail => fail}/concurrency/too_many_args.rs (100%) rename tests/{compile-fail => fail}/concurrency/too_many_args.stderr (100%) rename tests/{compile-fail => fail}/concurrency/unwind_top_of_stack.rs (100%) rename tests/{compile-fail => fail}/concurrency/unwind_top_of_stack.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/dangling_pointer_addr_of.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/dangling_pointer_addr_of.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/dangling_pointer_deref.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/dangling_pointer_deref.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/dangling_zst_deref.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/dangling_zst_deref.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/deref-invalid-ptr.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/deref-invalid-ptr.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/deref-partially-dangling.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/deref-partially-dangling.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/dyn_size.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/dyn_size.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/maybe_null_pointer_deref_zst.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/maybe_null_pointer_deref_zst.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/maybe_null_pointer_write_zst.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/maybe_null_pointer_write_zst.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/null_pointer_deref.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/null_pointer_deref.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/null_pointer_deref_zst.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/null_pointer_deref_zst.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/null_pointer_write.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/null_pointer_write.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/null_pointer_write_zst.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/null_pointer_write_zst.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/out_of_bounds_read1.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/out_of_bounds_read1.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/out_of_bounds_read2.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/out_of_bounds_read2.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/stack_temporary.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/stack_temporary.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/storage_dead_dangling.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/storage_dead_dangling.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/wild_pointer_deref.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/wild_pointer_deref.stderr (100%) rename tests/{compile-fail => fail}/data_race/alloc_read_race.rs (100%) rename tests/{compile-fail => fail}/data_race/alloc_read_race.stderr (100%) rename tests/{compile-fail => fail}/data_race/alloc_write_race.rs (100%) rename tests/{compile-fail => fail}/data_race/alloc_write_race.stderr (100%) rename tests/{compile-fail => fail}/data_race/atomic_read_na_write_race1.rs (100%) rename tests/{compile-fail => fail}/data_race/atomic_read_na_write_race1.stderr (100%) rename tests/{compile-fail => fail}/data_race/atomic_read_na_write_race2.rs (100%) rename tests/{compile-fail => fail}/data_race/atomic_read_na_write_race2.stderr (100%) rename tests/{compile-fail => fail}/data_race/atomic_write_na_read_race1.rs (100%) rename tests/{compile-fail => fail}/data_race/atomic_write_na_read_race1.stderr (100%) rename tests/{compile-fail => fail}/data_race/atomic_write_na_read_race2.rs (100%) rename tests/{compile-fail => fail}/data_race/atomic_write_na_read_race2.stderr (100%) rename tests/{compile-fail => fail}/data_race/atomic_write_na_write_race1.rs (100%) rename tests/{compile-fail => fail}/data_race/atomic_write_na_write_race1.stderr (100%) rename tests/{compile-fail => fail}/data_race/atomic_write_na_write_race2.rs (100%) rename tests/{compile-fail => fail}/data_race/atomic_write_na_write_race2.stderr (100%) rename tests/{compile-fail => fail}/data_race/dangling_thread_async_race.rs (100%) rename tests/{compile-fail => fail}/data_race/dangling_thread_async_race.stderr (100%) rename tests/{compile-fail => fail}/data_race/dangling_thread_race.rs (100%) rename tests/{compile-fail => fail}/data_race/dangling_thread_race.stderr (100%) rename tests/{compile-fail => fail}/data_race/dealloc_read_race1.rs (100%) rename tests/{compile-fail => fail}/data_race/dealloc_read_race1.stderr (100%) rename tests/{compile-fail => fail}/data_race/dealloc_read_race2.rs (100%) rename tests/{compile-fail => fail}/data_race/dealloc_read_race2.stderr (100%) rename tests/{compile-fail => fail}/data_race/dealloc_read_race_stack.rs (100%) rename tests/{compile-fail => fail}/data_race/dealloc_read_race_stack.stderr (100%) rename tests/{compile-fail => fail}/data_race/dealloc_write_race1.rs (100%) rename tests/{compile-fail => fail}/data_race/dealloc_write_race1.stderr (100%) rename tests/{compile-fail => fail}/data_race/dealloc_write_race2.rs (100%) rename tests/{compile-fail => fail}/data_race/dealloc_write_race2.stderr (100%) rename tests/{compile-fail => fail}/data_race/dealloc_write_race_stack.rs (100%) rename tests/{compile-fail => fail}/data_race/dealloc_write_race_stack.stderr (100%) rename tests/{compile-fail => fail}/data_race/enable_after_join_to_main.rs (100%) rename tests/{compile-fail => fail}/data_race/enable_after_join_to_main.stderr (100%) rename tests/{compile-fail => fail}/data_race/read_write_race.rs (100%) rename tests/{compile-fail => fail}/data_race/read_write_race.stderr (100%) rename tests/{compile-fail => fail}/data_race/read_write_race_stack.rs (100%) rename tests/{compile-fail => fail}/data_race/read_write_race_stack.stderr (100%) rename tests/{compile-fail => fail}/data_race/relax_acquire_race.rs (100%) rename tests/{compile-fail => fail}/data_race/relax_acquire_race.stderr (100%) rename tests/{compile-fail => fail}/data_race/release_seq_race.rs (100%) rename tests/{compile-fail => fail}/data_race/release_seq_race.stderr (100%) rename tests/{compile-fail => fail}/data_race/release_seq_race_same_thread.rs (100%) rename tests/{compile-fail => fail}/data_race/release_seq_race_same_thread.stderr (100%) rename tests/{compile-fail => fail}/data_race/rmw_race.rs (100%) rename tests/{compile-fail => fail}/data_race/rmw_race.stderr (100%) rename tests/{compile-fail => fail}/data_race/write_write_race.rs (100%) rename tests/{compile-fail => fail}/data_race/write_write_race.stderr (100%) rename tests/{compile-fail => fail}/data_race/write_write_race_stack.rs (100%) rename tests/{compile-fail => fail}/data_race/write_write_race_stack.stderr (100%) rename tests/{compile-fail => fail}/environ-gets-deallocated.rs (100%) rename tests/{compile-fail => fail}/environ-gets-deallocated.stderr (100%) rename tests/{compile-fail => fail}/erroneous_const.rs (100%) rename tests/{compile-fail => fail}/erroneous_const.stderr (100%) rename tests/{compile-fail => fail}/erroneous_const2.rs (100%) rename tests/{compile-fail => fail}/erroneous_const2.stderr (100%) rename tests/{compile-fail => fail}/extern_static.rs (100%) rename tests/{compile-fail => fail}/extern_static.stderr (100%) rename tests/{compile-fail => fail}/fast_math_both.rs (100%) rename tests/{compile-fail => fail}/fast_math_both.stderr (100%) rename tests/{compile-fail => fail}/fast_math_first.rs (100%) rename tests/{compile-fail => fail}/fast_math_first.stderr (100%) rename tests/{compile-fail => fail}/fast_math_second.rs (100%) rename tests/{compile-fail => fail}/fast_math_second.stderr (100%) rename tests/{compile-fail => fail}/fs/close_stdout.rs (100%) rename tests/{compile-fail => fail}/fs/close_stdout.stderr (100%) rename tests/{compile-fail => fail}/fs/isolated_file.rs (100%) rename tests/{compile-fail => fail}/fs/isolated_file.stderr (100%) rename tests/{compile-fail => fail}/fs/isolated_stdin.rs (100%) rename tests/{compile-fail => fail}/fs/isolated_stdin.stderr (100%) rename tests/{compile-fail => fail}/fs/read_from_stdout.rs (100%) rename tests/{compile-fail => fail}/fs/read_from_stdout.stderr (100%) rename tests/{compile-fail => fail}/fs/unix_open_missing_required_mode.rs (100%) rename tests/{compile-fail => fail}/fs/unix_open_missing_required_mode.stderr (100%) rename tests/{compile-fail => fail}/fs/unix_open_too_many_args.stderr (100%) rename tests/{compile-fail => fail}/fs/write_to_stdin.rs (100%) rename tests/{compile-fail => fail}/fs/write_to_stdin.stderr (100%) rename tests/{compile-fail => fail}/function_calls/check_arg_abi.rs (100%) rename tests/{compile-fail => fail}/function_calls/check_arg_abi.stderr (100%) rename tests/{compile-fail => fail}/function_calls/check_arg_count_abort.rs (100%) rename tests/{compile-fail => fail}/function_calls/check_arg_count_abort.stderr (100%) rename tests/{compile-fail => fail}/function_calls/check_arg_count_too_few_args.rs (100%) rename tests/{compile-fail => fail}/function_calls/check_arg_count_too_few_args.stderr (100%) rename tests/{compile-fail => fail}/function_calls/check_arg_count_too_many_args.rs (100%) rename tests/{compile-fail => fail}/function_calls/check_arg_count_too_many_args.stderr (100%) rename tests/{compile-fail => fail}/function_calls/check_callback_abi.rs (100%) rename tests/{compile-fail => fail}/function_calls/check_callback_abi.stderr (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_abi_mismatch.cache.stderr (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_abi_mismatch.no_cache.stderr (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_abi_mismatch.rs (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_bad_unwind1.rs (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_bad_unwind1.stderr (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_bad_unwind2.both.stderr (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_bad_unwind2.definition.stderr (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_bad_unwind2.extern_block.stderr (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_bad_unwind2.rs (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_clashing.rs (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_clashing.stderr (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_shim_clashing.rs (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_shim_clashing.stderr (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_wrong_arguments.rs (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_wrong_arguments.stderr (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_wrong_type.rs (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_wrong_type.stderr (100%) rename tests/{compile-fail => fail}/function_pointers/cast_box_int_to_fn_ptr.rs (100%) rename tests/{compile-fail => fail}/function_pointers/cast_box_int_to_fn_ptr.stderr (100%) rename tests/{compile-fail => fail}/function_pointers/cast_fn_ptr1.rs (100%) rename tests/{compile-fail => fail}/function_pointers/cast_fn_ptr1.stderr (100%) rename tests/{compile-fail => fail}/function_pointers/cast_fn_ptr2.rs (100%) rename tests/{compile-fail => fail}/function_pointers/cast_fn_ptr2.stderr (100%) rename tests/{compile-fail => fail}/function_pointers/cast_fn_ptr3.rs (100%) rename tests/{compile-fail => fail}/function_pointers/cast_fn_ptr3.stderr (100%) rename tests/{compile-fail => fail}/function_pointers/cast_fn_ptr4.rs (100%) rename tests/{compile-fail => fail}/function_pointers/cast_fn_ptr4.stderr (100%) rename tests/{compile-fail => fail}/function_pointers/cast_fn_ptr5.rs (100%) rename tests/{compile-fail => fail}/function_pointers/cast_fn_ptr5.stderr (100%) rename tests/{compile-fail => fail}/function_pointers/cast_int_to_fn_ptr.rs (100%) rename tests/{compile-fail => fail}/function_pointers/cast_int_to_fn_ptr.stderr (100%) rename tests/{compile-fail => fail}/function_pointers/deref_fn_ptr.rs (100%) rename tests/{compile-fail => fail}/function_pointers/deref_fn_ptr.stderr (100%) rename tests/{compile-fail => fail}/function_pointers/execute_memory.rs (100%) rename tests/{compile-fail => fail}/function_pointers/execute_memory.stderr (100%) rename tests/{compile-fail => fail}/function_pointers/fn_ptr_offset.rs (100%) rename tests/{compile-fail => fail}/function_pointers/fn_ptr_offset.stderr (100%) rename tests/{compile-fail => fail}/generator-pinned-moved.rs (100%) rename tests/{compile-fail => fail}/generator-pinned-moved.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/assume.rs (100%) rename tests/{compile-fail => fail}/intrinsics/assume.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/copy_null.rs (100%) rename tests/{compile-fail => fail}/intrinsics/copy_null.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/copy_overflow.rs (100%) rename tests/{compile-fail => fail}/intrinsics/copy_overflow.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/copy_overlapping.rs (100%) rename tests/{compile-fail => fail}/intrinsics/copy_overlapping.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/copy_unaligned.rs (100%) rename tests/{compile-fail => fail}/intrinsics/copy_unaligned.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/ctlz_nonzero.rs (100%) rename tests/{compile-fail => fail}/intrinsics/ctlz_nonzero.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/cttz_nonzero.rs (100%) rename tests/{compile-fail => fail}/intrinsics/cttz_nonzero.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/div-by-zero.rs (100%) rename tests/{compile-fail => fail}/intrinsics/div-by-zero.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/exact_div1.rs (100%) rename tests/{compile-fail => fail}/intrinsics/exact_div1.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/exact_div2.rs (100%) rename tests/{compile-fail => fail}/intrinsics/exact_div2.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/exact_div3.rs (100%) rename tests/{compile-fail => fail}/intrinsics/exact_div3.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/exact_div4.rs (100%) rename tests/{compile-fail => fail}/intrinsics/exact_div4.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_inf1.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_inf1.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_infneg1.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_infneg1.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_nan.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_nan.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_nanneg.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_nanneg.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_neg.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_neg.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_too_big1.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_too_big1.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_too_big2.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_too_big2.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_too_small1.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_too_small1.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_inf1.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_inf1.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_infneg1.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_infneg1.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_infneg2.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_infneg2.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_nan.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_nan.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_neg.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_neg.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_big1.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_big1.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_big2.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_big2.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_big3.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_big3.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_big4.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_big4.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_big5.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_big5.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_big6.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_big6.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_big7.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_big7.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_small1.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_small1.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_small2.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_small2.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_small3.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_small3.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/out_of_bounds_ptr_1.rs (100%) rename tests/{compile-fail => fail}/intrinsics/out_of_bounds_ptr_1.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/out_of_bounds_ptr_2.rs (100%) rename tests/{compile-fail => fail}/intrinsics/out_of_bounds_ptr_2.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/out_of_bounds_ptr_3.rs (100%) rename tests/{compile-fail => fail}/intrinsics/out_of_bounds_ptr_3.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/overflowing-unchecked-rsh.rs (100%) rename tests/{compile-fail => fail}/intrinsics/overflowing-unchecked-rsh.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/ptr_offset_0_plus_0.rs (100%) rename tests/{compile-fail => fail}/intrinsics/ptr_offset_0_plus_0.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/ptr_offset_from_oob.rs (100%) rename tests/{compile-fail => fail}/intrinsics/ptr_offset_from_oob.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/ptr_offset_int_plus_int.rs (100%) rename tests/{compile-fail => fail}/intrinsics/ptr_offset_int_plus_int.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/ptr_offset_int_plus_ptr.rs (100%) rename tests/{compile-fail => fail}/intrinsics/ptr_offset_int_plus_ptr.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/ptr_offset_overflow.rs (100%) rename tests/{compile-fail => fail}/intrinsics/ptr_offset_overflow.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/ptr_offset_ptr_plus_0.rs (100%) rename tests/{compile-fail => fail}/intrinsics/ptr_offset_ptr_plus_0.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/rem-by-zero.rs (100%) rename tests/{compile-fail => fail}/intrinsics/rem-by-zero.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/simd-div-by-zero.rs (100%) rename tests/{compile-fail => fail}/intrinsics/simd-div-by-zero.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/simd-div-overflow.rs (100%) rename tests/{compile-fail => fail}/intrinsics/simd-div-overflow.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/simd-float-to-int.rs (100%) rename tests/{compile-fail => fail}/intrinsics/simd-float-to-int.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/simd-gather.rs (100%) rename tests/{compile-fail => fail}/intrinsics/simd-gather.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/simd-reduce-invalid-bool.rs (100%) rename tests/{compile-fail => fail}/intrinsics/simd-reduce-invalid-bool.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/simd-rem-by-zero.rs (100%) rename tests/{compile-fail => fail}/intrinsics/simd-rem-by-zero.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/simd-scatter.rs (100%) rename tests/{compile-fail => fail}/intrinsics/simd-scatter.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/simd-select-bitmask-invalid.rs (100%) rename tests/{compile-fail => fail}/intrinsics/simd-select-bitmask-invalid.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/simd-select-invalid-bool.rs (100%) rename tests/{compile-fail => fail}/intrinsics/simd-select-invalid-bool.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/simd-shl-too-far.rs (100%) rename tests/{compile-fail => fail}/intrinsics/simd-shl-too-far.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/simd-shr-too-far.rs (100%) rename tests/{compile-fail => fail}/intrinsics/simd-shr-too-far.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/unchecked_add1.rs (100%) rename tests/{compile-fail => fail}/intrinsics/unchecked_add1.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/unchecked_add2.rs (100%) rename tests/{compile-fail => fail}/intrinsics/unchecked_add2.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/unchecked_div1.rs (100%) rename tests/{compile-fail => fail}/intrinsics/unchecked_div1.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/unchecked_mul1.rs (100%) rename tests/{compile-fail => fail}/intrinsics/unchecked_mul1.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/unchecked_mul2.rs (100%) rename tests/{compile-fail => fail}/intrinsics/unchecked_mul2.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/unchecked_sub1.rs (100%) rename tests/{compile-fail => fail}/intrinsics/unchecked_sub1.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/unchecked_sub2.rs (100%) rename tests/{compile-fail => fail}/intrinsics/unchecked_sub2.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/uninit_uninhabited_type.rs (100%) rename tests/{compile-fail => fail}/intrinsics/uninit_uninhabited_type.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/write_bytes_null.rs (100%) rename tests/{compile-fail => fail}/intrinsics/write_bytes_null.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/write_bytes_overflow.rs (100%) rename tests/{compile-fail => fail}/intrinsics/write_bytes_overflow.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/zero_fn_ptr.rs (100%) rename tests/{compile-fail => fail}/intrinsics/zero_fn_ptr.stderr (100%) rename tests/{compile-fail => fail}/invalid_bool.rs (100%) rename tests/{compile-fail => fail}/invalid_bool.stderr (100%) rename tests/{compile-fail => fail}/invalid_char.rs (100%) rename tests/{compile-fail => fail}/invalid_char.stderr (100%) rename tests/{compile-fail => fail}/invalid_enum_tag.rs (100%) rename tests/{compile-fail => fail}/invalid_enum_tag.stderr (100%) rename tests/{compile-fail => fail}/invalid_int.rs (100%) rename tests/{compile-fail => fail}/invalid_int.stderr (100%) rename tests/{compile-fail => fail}/issue-miri-1112.rs (100%) rename tests/{compile-fail => fail}/issue-miri-1112.stderr (100%) rename tests/{compile-fail => fail}/memleak.rs (100%) rename tests/{compile-fail => fail}/memleak.stderr (100%) rename tests/{compile-fail => fail}/memleak_rc.32bit.stderr (100%) rename tests/{compile-fail => fail}/memleak_rc.64bit.stderr (100%) rename tests/{compile-fail => fail}/memleak_rc.rs (100%) rename tests/{compile-fail => fail}/modifying_constants.rs (100%) rename tests/{compile-fail => fail}/modifying_constants.stderr (100%) rename tests/{compile-fail => fail}/never_say_never.rs (100%) rename tests/{compile-fail => fail}/never_say_never.stderr (100%) rename tests/{compile-fail => fail}/never_transmute_humans.rs (100%) rename tests/{compile-fail => fail}/never_transmute_humans.stderr (100%) rename tests/{compile-fail => fail}/never_transmute_void.rs (100%) rename tests/{compile-fail => fail}/never_transmute_void.stderr (100%) rename tests/{compile-fail => fail}/no_main.rs (100%) rename tests/{compile-fail => fail}/no_main.stderr (100%) rename tests/{compile-fail => fail}/null_pointer_deref.stderr (100%) rename tests/{compile-fail => fail}/null_pointer_deref_zst.stderr (100%) rename tests/{compile-fail => fail}/null_pointer_write.stderr (100%) rename tests/{compile-fail => fail}/null_pointer_write_zst.stderr (100%) rename tests/{compile-fail => fail}/panic/bad_miri_start_panic.rs (100%) rename tests/{compile-fail => fail}/panic/bad_miri_start_panic.stderr (100%) rename tests/{compile-fail => fail}/panic/bad_unwind.rs (100%) rename tests/{compile-fail => fail}/panic/bad_unwind.stderr (100%) rename tests/{compile-fail => fail}/panic/double_panic.rs (100%) rename tests/{compile-fail => fail}/panic/double_panic.stderr (100%) rename tests/{compile-fail => fail}/panic/panic_abort1.rs (100%) rename tests/{compile-fail => fail}/panic/panic_abort1.stderr (100%) rename tests/{compile-fail => fail}/panic/panic_abort2.rs (100%) rename tests/{compile-fail => fail}/panic/panic_abort2.stderr (100%) rename tests/{compile-fail => fail}/panic/panic_abort3.rs (100%) rename tests/{compile-fail => fail}/panic/panic_abort3.stderr (100%) rename tests/{compile-fail => fail}/panic/panic_abort4.rs (100%) rename tests/{compile-fail => fail}/panic/panic_abort4.stderr (100%) rename tests/{compile-fail => fail}/panic/unwind_panic_abort.rs (100%) rename tests/{compile-fail => fail}/panic/unwind_panic_abort.stderr (100%) rename tests/{compile-fail => fail}/pointer_partial_overwrite.rs (100%) rename tests/{compile-fail => fail}/pointer_partial_overwrite.stderr (100%) rename tests/{compile-fail => fail}/pointer_partial_read.rs (100%) rename tests/{compile-fail => fail}/pointer_partial_read.stderr (100%) rename tests/{compile-fail => fail}/provenance/ptr_int_unexposed.rs (100%) rename tests/{compile-fail => fail}/provenance/ptr_int_unexposed.stderr (100%) rename tests/{compile-fail => fail}/provenance/ptr_invalid.rs (100%) rename tests/{compile-fail => fail}/provenance/ptr_invalid.stderr (100%) rename tests/{compile-fail => fail}/provenance/ptr_legacy_provenance.rs (100%) rename tests/{compile-fail => fail}/provenance/ptr_legacy_provenance.stderr (100%) rename tests/{compile-fail => fail}/provenance/strict-provenance-offset.rs (100%) rename tests/{compile-fail => fail}/provenance/strict-provenance-offset.stderr (100%) rename tests/{compile-fail => fail}/provenance/strict_provenance_transmute.rs (100%) rename tests/{compile-fail => fail}/provenance/strict_provenance_transmute.stderr (100%) rename tests/{compile-fail => fail}/ptr_integer_array_transmute.stderr (100%) rename tests/{compile-fail => fail}/ptr_integer_transmute.stderr (100%) rename tests/{compile-fail => fail}/rc_as_ptr.rs (100%) rename tests/{compile-fail => fail}/rc_as_ptr.stderr (100%) rename tests/{compile-fail => fail}/reading_half_a_pointer.rs (100%) rename tests/{compile-fail => fail}/reading_half_a_pointer.stderr (100%) rename tests/{compile-fail => fail}/rustc-error.rs (100%) rename tests/{compile-fail => fail}/rustc-error.stderr (100%) rename tests/{compile-fail => fail}/shim_arg_size.32bit.stderr (100%) rename tests/{compile-fail => fail}/shim_arg_size.64bit.stderr (100%) rename tests/{compile-fail => fail}/shim_arg_size.rs (100%) rename tests/{compile-fail => fail}/slice-too-big.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/alias_through_mutation.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/alias_through_mutation.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/aliasing_mut1.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/aliasing_mut1.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/aliasing_mut2.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/aliasing_mut2.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/aliasing_mut3.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/aliasing_mut3.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/aliasing_mut4.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/aliasing_mut4.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/box_exclusive_violation1.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/box_exclusive_violation1.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/buggy_as_mut_slice.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/buggy_as_mut_slice.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/buggy_split_at_mut.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/buggy_split_at_mut.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/deallocate_against_barrier1.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/deallocate_against_barrier1.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/deallocate_against_barrier2.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/deallocate_against_barrier2.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read1.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read1.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read2.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read2.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read3.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read3.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read4.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read4.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read5.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read5.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read6.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read6.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read7.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read7.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read8.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read8.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_write1.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_write1.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_write2.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_write2.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_write3.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_write3.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_write4.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_write4.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_write5.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_write5.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_write6.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_write6.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/interior_mut1.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/interior_mut1.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/interior_mut2.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/interior_mut2.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/invalidate_against_barrier1.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/invalidate_against_barrier1.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/invalidate_against_barrier2.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/invalidate_against_barrier2.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/issue-miri-1050-1.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/issue-miri-1050-1.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/issue-miri-1050-2.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/issue-miri-1050-2.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/load_invalid_mut.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/load_invalid_mut.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/load_invalid_shr.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/load_invalid_shr.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/mut_exclusive_violation1.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/mut_exclusive_violation1.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/mut_exclusive_violation2.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/mut_exclusive_violation2.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/outdated_local.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/outdated_local.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/pass_invalid_mut.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/pass_invalid_mut.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/pass_invalid_shr.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/pass_invalid_shr.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/pointer_smuggling.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/pointer_smuggling.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/raw_tracking.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/raw_tracking.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/return_invalid_mut.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/return_invalid_mut.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/return_invalid_mut_option.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/return_invalid_mut_option.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/return_invalid_mut_tuple.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/return_invalid_mut_tuple.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/return_invalid_shr.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/return_invalid_shr.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/return_invalid_shr_option.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/return_invalid_shr_option.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/return_invalid_shr_tuple.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/return_invalid_shr_tuple.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/shared_rw_borrows_are_weak1.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/shared_rw_borrows_are_weak1.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/shared_rw_borrows_are_weak2.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/shared_rw_borrows_are_weak2.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/shr_frozen_violation1.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/shr_frozen_violation1.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/static_memory_modification.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/static_memory_modification.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/transmute-is-no-escape.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/transmute-is-no-escape.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/unescaped_local.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/unescaped_local.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/unescaped_static.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/unescaped_static.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/zst_slice.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/zst_slice.stderr (100%) rename tests/{compile-fail => fail}/static_memory_modification1.rs (100%) rename tests/{compile-fail => fail}/static_memory_modification1.stderr (100%) rename tests/{compile-fail => fail}/static_memory_modification2.rs (100%) rename tests/{compile-fail => fail}/static_memory_modification2.stderr (100%) rename tests/{compile-fail => fail}/static_memory_modification3.rs (100%) rename tests/{compile-fail => fail}/static_memory_modification3.stderr (100%) rename tests/{compile-fail => fail}/strict-provenance-offset.stderr (100%) rename tests/{compile-fail => fail}/strict_provenance_transmute.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_cond_double_destroy.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_cond_double_destroy.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_condattr_double_destroy.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_condattr_double_destroy.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_NULL_deadlock.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_NULL_deadlock.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_deadlock.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_deadlock.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_default_deadlock.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_default_deadlock.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_destroy_locked.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_destroy_locked.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_double_destroy.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_double_destroy.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_normal_deadlock.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_normal_deadlock.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_normal_unlock_unlocked.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_wrong_owner.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_wrong_owner.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutexattr_double_destroy.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutexattr_double_destroy.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_destroy_read_locked.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_destroy_read_locked.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_destroy_write_locked.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_destroy_write_locked.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_double_destroy.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_double_destroy.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_read_wrong_owner.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_read_wrong_owner.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_unlock_unlocked.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_unlock_unlocked.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_write_read_deadlock.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_write_read_deadlock.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_write_write_deadlock.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_write_write_deadlock.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_write_wrong_owner.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_write_wrong_owner.stderr (100%) rename tests/{compile-fail => fail}/too-big-slice.stderr (100%) rename tests/{compile-fail => fail}/too-big-unsized.stderr (100%) rename tests/{compile-fail => fail}/transmute-pair-uninit.rs (100%) rename tests/{compile-fail => fail}/transmute-pair-uninit.stderr (100%) rename tests/{compile-fail => fail}/transmute_fat1.rs (100%) rename tests/{compile-fail => fail}/transmute_fat1.stderr (100%) rename tests/{compile-fail => fail}/type-too-large.rs (100%) rename tests/{compile-fail => fail}/type-too-large.stderr (100%) rename tests/{compile-fail => fail}/unaligned_pointers/alignment.rs (100%) rename tests/{compile-fail => fail}/unaligned_pointers/alignment.stderr (100%) rename tests/{compile-fail => fail}/unaligned_pointers/atomic_unaligned.rs (100%) rename tests/{compile-fail => fail}/unaligned_pointers/atomic_unaligned.stderr (100%) rename tests/{compile-fail => fail}/unaligned_pointers/dyn_alignment.rs (100%) rename tests/{compile-fail => fail}/unaligned_pointers/dyn_alignment.stderr (100%) rename tests/{compile-fail => fail}/unaligned_pointers/intptrcast_alignment_check.rs (100%) rename tests/{compile-fail => fail}/unaligned_pointers/intptrcast_alignment_check.stderr (100%) rename tests/{compile-fail => fail}/unaligned_pointers/reference_to_packed.rs (100%) rename tests/{compile-fail => fail}/unaligned_pointers/reference_to_packed.stderr (100%) rename tests/{compile-fail => fail}/unaligned_pointers/unaligned_ptr1.rs (100%) rename tests/{compile-fail => fail}/unaligned_pointers/unaligned_ptr1.stderr (100%) rename tests/{compile-fail => fail}/unaligned_pointers/unaligned_ptr2.rs (100%) rename tests/{compile-fail => fail}/unaligned_pointers/unaligned_ptr2.stderr (100%) rename tests/{compile-fail => fail}/unaligned_pointers/unaligned_ptr3.rs (100%) rename tests/{compile-fail => fail}/unaligned_pointers/unaligned_ptr3.stderr (100%) rename tests/{compile-fail => fail}/unaligned_pointers/unaligned_ptr4.rs (100%) rename tests/{compile-fail => fail}/unaligned_pointers/unaligned_ptr4.stderr (100%) rename tests/{compile-fail => fail}/unaligned_pointers/unaligned_ptr_addr_of.rs (100%) rename tests/{compile-fail => fail}/unaligned_pointers/unaligned_ptr_addr_of.stderr (100%) rename tests/{compile-fail => fail}/unaligned_pointers/unaligned_ptr_zst.rs (100%) rename tests/{compile-fail => fail}/unaligned_pointers/unaligned_ptr_zst.stderr (100%) rename tests/{compile-fail => fail}/uninit_buffer.rs (100%) rename tests/{compile-fail => fail}/uninit_buffer.stderr (100%) rename tests/{compile-fail => fail}/uninit_byte_read.rs (100%) rename tests/{compile-fail => fail}/uninit_byte_read.stderr (100%) rename tests/{compile-fail => fail}/uninit_float.stderr (100%) rename tests/{compile-fail => fail}/uninit_integer.stderr (100%) rename tests/{compile-fail => fail}/uninit_integer_signed.stderr (100%) rename tests/{compile-fail => fail}/uninit_raw_ptr.rs (100%) rename tests/{compile-fail => fail}/uninit_raw_ptr.stderr (100%) rename tests/{compile-fail => fail}/unreachable.rs (100%) rename tests/{compile-fail => fail}/unreachable.stderr (100%) rename tests/{compile-fail => fail}/unsupported_foreign_function.rs (100%) rename tests/{compile-fail => fail}/unsupported_foreign_function.stderr (100%) rename tests/{compile-fail => fail}/unsupported_signal.rs (100%) rename tests/{compile-fail => fail}/unsupported_signal.stderr (100%) rename tests/{compile-fail => fail}/validity/cast_fn_ptr1.rs (100%) rename tests/{compile-fail => fail}/validity/cast_fn_ptr1.stderr (100%) rename tests/{compile-fail => fail}/validity/cast_fn_ptr2.rs (100%) rename tests/{compile-fail => fail}/validity/cast_fn_ptr2.stderr (100%) rename tests/{compile-fail => fail}/validity/dangling_ref1.rs (100%) rename tests/{compile-fail => fail}/validity/dangling_ref1.stderr (100%) rename tests/{compile-fail => fail}/validity/dangling_ref2.rs (100%) rename tests/{compile-fail => fail}/validity/dangling_ref2.stderr (100%) rename tests/{compile-fail => fail}/validity/dangling_ref3.rs (100%) rename tests/{compile-fail => fail}/validity/dangling_ref3.stderr (100%) rename tests/{compile-fail => fail}/validity/invalid_bool.rs (100%) rename tests/{compile-fail => fail}/validity/invalid_bool.stderr (100%) rename tests/{compile-fail => fail}/validity/invalid_bool_uninit.rs (100%) rename tests/{compile-fail => fail}/validity/invalid_bool_uninit.stderr (100%) rename tests/{compile-fail => fail}/validity/invalid_char.rs (100%) rename tests/{compile-fail => fail}/validity/invalid_char.stderr (100%) rename tests/{compile-fail => fail}/validity/invalid_char_uninit.rs (100%) rename tests/{compile-fail => fail}/validity/invalid_char_uninit.stderr (100%) rename tests/{compile-fail => fail}/validity/invalid_enum_tag.rs (100%) rename tests/{compile-fail => fail}/validity/invalid_enum_tag.stderr (100%) rename tests/{compile-fail => fail}/validity/invalid_enum_tag_256variants_uninit.rs (100%) rename tests/{compile-fail => fail}/validity/invalid_enum_tag_256variants_uninit.stderr (100%) rename tests/{compile-fail => fail}/validity/invalid_fnptr_null.rs (100%) rename tests/{compile-fail => fail}/validity/invalid_fnptr_null.stderr (100%) rename tests/{compile-fail => fail}/validity/invalid_fnptr_uninit.rs (100%) rename tests/{compile-fail => fail}/validity/invalid_fnptr_uninit.stderr (100%) rename tests/{compile-fail => fail}/validity/invalid_wide_raw.rs (100%) rename tests/{compile-fail => fail}/validity/invalid_wide_raw.stderr (100%) rename tests/{compile-fail => fail}/validity/nonzero.rs (100%) rename tests/{compile-fail => fail}/validity/nonzero.stderr (100%) rename tests/{compile-fail => fail}/validity/ptr_integer_array_transmute.rs (100%) rename tests/{compile-fail => fail}/validity/ptr_integer_array_transmute.stderr (100%) rename tests/{compile-fail => fail}/validity/ptr_integer_transmute.rs (100%) rename tests/{compile-fail => fail}/validity/ptr_integer_transmute.stderr (100%) rename tests/{compile-fail => fail}/validity/ref_to_uninhabited1.rs (100%) rename tests/{compile-fail => fail}/validity/ref_to_uninhabited1.stderr (100%) rename tests/{compile-fail => fail}/validity/ref_to_uninhabited2.rs (100%) rename tests/{compile-fail => fail}/validity/ref_to_uninhabited2.stderr (100%) rename tests/{compile-fail => fail}/validity/too-big-slice.rs (100%) rename tests/{compile-fail => fail}/validity/too-big-slice.stderr (100%) rename tests/{compile-fail => fail}/validity/too-big-unsized.rs (100%) rename tests/{compile-fail => fail}/validity/too-big-unsized.stderr (100%) rename tests/{compile-fail => fail}/validity/transmute_through_ptr.rs (100%) rename tests/{compile-fail => fail}/validity/transmute_through_ptr.stderr (100%) rename tests/{compile-fail => fail}/validity/uninit_float.rs (100%) rename tests/{compile-fail => fail}/validity/uninit_float.stderr (100%) rename tests/{compile-fail => fail}/validity/uninit_integer.rs (100%) rename tests/{compile-fail => fail}/validity/uninit_integer.stderr (100%) rename tests/{compile-fail => fail}/validity/uninit_integer_signed.rs (100%) rename tests/{compile-fail => fail}/validity/uninit_integer_signed.stderr (100%) rename tests/{compile-fail => fail}/zst1.rs (100%) rename tests/{compile-fail => fail}/zst1.stderr (100%) rename tests/{compile-fail => fail}/zst2.rs (100%) rename tests/{compile-fail => fail}/zst2.stderr (100%) rename tests/{compile-fail => fail}/zst3.rs (100%) rename tests/{compile-fail => fail}/zst3.stderr (100%) rename tests/{run-fail => panic}/function_calls/exported_symbol_good_unwind.rs (100%) rename tests/{run-fail => panic}/function_calls/exported_symbol_good_unwind.stderr (100%) rename tests/{run-fail => panic}/panic/div-by-zero-2.rs (100%) rename tests/{run-fail => panic}/panic/div-by-zero-2.stderr (100%) rename tests/{run-fail => panic}/panic/overflowing-lsh-neg.rs (100%) rename tests/{run-fail => panic}/panic/overflowing-lsh-neg.stderr (100%) rename tests/{run-fail => panic}/panic/overflowing-rsh-1.rs (100%) rename tests/{run-fail => panic}/panic/overflowing-rsh-1.stderr (100%) rename tests/{run-fail => panic}/panic/overflowing-rsh-2.rs (100%) rename tests/{run-fail => panic}/panic/overflowing-rsh-2.stderr (100%) rename tests/{run-fail => panic}/panic/panic1.rs (100%) rename tests/{run-fail => panic}/panic/panic1.stderr (100%) rename tests/{run-fail => panic}/panic/panic2.rs (100%) rename tests/{run-fail => panic}/panic/panic2.stderr (100%) rename tests/{run-fail => panic}/panic/panic3.rs (100%) rename tests/{run-fail => panic}/panic/panic3.stderr (100%) rename tests/{run-fail => panic}/panic/panic4.rs (100%) rename tests/{run-fail => panic}/panic/panic4.stderr (100%) rename tests/{run-fail => panic}/panic/unsupported_foreign_function.rs (100%) rename tests/{run-fail => panic}/panic/unsupported_foreign_function.stderr (100%) rename tests/{run-fail => panic}/panic/unsupported_syscall.rs (100%) rename tests/{run-fail => panic}/panic/unsupported_syscall.stderr (100%) rename tests/{run-fail => panic}/transmute_fat2.rs (100%) rename tests/{run-fail => panic}/transmute_fat2.stderr (100%) rename tests/{run-pass => pass}/adjacent-allocs.rs (100%) rename tests/{run-pass => pass}/align.rs (100%) rename tests/{run-pass => pass}/align_offset_symbolic.rs (100%) rename tests/{run-pass => pass}/align_offset_symbolic.stdout (100%) rename tests/{run-pass => pass}/args.rs (100%) rename tests/{run-pass => pass}/args.stdout (100%) rename tests/{run-pass => pass}/arrays.rs (100%) rename tests/{run-pass => pass}/arrays.stdout (100%) rename tests/{run-pass => pass}/associated-const.rs (100%) rename tests/{run-pass => pass}/assume_bug.rs (100%) rename tests/{run-pass => pass}/async-fn.rs (100%) rename tests/{run-pass => pass}/atomic-compare-exchange-weak-never-fail.rs (100%) rename tests/{run-pass => pass}/atomic.rs (100%) rename tests/{run-pass => pass}/available-parallelism.rs (100%) rename tests/{run-pass => pass}/backtrace-api-v0.rs (100%) rename tests/{run-pass => pass}/backtrace-api-v0.stderr (100%) rename tests/{run-pass => pass}/backtrace-api-v0.stdout (100%) rename tests/{run-pass => pass}/backtrace-api-v1.rs (100%) rename tests/{run-pass => pass}/backtrace-api-v1.stderr (100%) rename tests/{run-pass => pass}/backtrace-api-v1.stdout (100%) rename tests/{run-pass => pass}/backtrace-std.rs (100%) rename tests/{run-pass => pass}/backtrace-std.stderr (100%) rename tests/{run-pass => pass}/bad_substs.rs (100%) rename tests/{run-pass => pass}/binary-heap.rs (100%) rename tests/{run-pass => pass}/binops.rs (100%) rename tests/{run-pass => pass}/bools.rs (100%) rename tests/{run-pass => pass}/box.rs (100%) rename tests/{run-pass => pass}/box.stdout (100%) rename tests/{run-pass => pass}/btreemap.rs (100%) rename tests/{run-pass => pass}/c_enums.rs (100%) rename tests/{run-pass => pass}/calloc.rs (100%) rename tests/{run-pass => pass}/calls.rs (100%) rename tests/{run-pass => pass}/cast-rfc0401-vtable-kinds.rs (100%) rename tests/{run-pass => pass}/cast_fn_ptr.rs (100%) rename tests/{run-pass => pass}/cast_fn_ptr_unsafe.rs (100%) rename tests/{run-pass => pass}/catch.rs (100%) rename tests/{run-pass => pass}/catch.stdout (100%) rename tests/{run-pass => pass}/cfg_miri.rs (100%) rename tests/{run-pass => pass}/char.rs (100%) rename tests/{run-pass => pass}/closure-drop.rs (100%) rename tests/{run-pass => pass}/closure-field-ty.rs (100%) rename tests/{run-pass => pass}/closures.rs (100%) rename tests/{run-pass => pass}/coerce_non_capture_closure_to_fn_ptr.rs (100%) rename tests/{run-pass => pass}/coercions.rs (100%) rename tests/{run-pass => pass}/concurrency/channels.rs (100%) rename tests/{run-pass => pass}/concurrency/channels.stderr (100%) rename tests/{run-pass => pass}/concurrency/concurrent_caller_location.rs (100%) rename tests/{run-pass => pass}/concurrency/concurrent_caller_location.stderr (100%) rename tests/{run-pass => pass}/concurrency/data_race.rs (100%) rename tests/{run-pass => pass}/concurrency/data_race.stderr (100%) rename tests/{run-pass => pass}/concurrency/disable_data_race_detector.rs (100%) rename tests/{run-pass => pass}/concurrency/disable_data_race_detector.stderr (100%) rename tests/{run-pass => pass}/concurrency/issue1643.rs (100%) rename tests/{run-pass => pass}/concurrency/issue1643.stderr (100%) rename tests/{run-pass => pass}/concurrency/libc_pthread_cond.rs (100%) rename tests/{run-pass => pass}/concurrency/linux-futex.rs (100%) rename tests/{run-pass => pass}/concurrency/linux-futex.stderr (100%) rename tests/{run-pass => pass}/concurrency/simple.rs (100%) rename tests/{run-pass => pass}/concurrency/simple.stderr (100%) rename tests/{run-pass => pass}/concurrency/sync.rs (100%) rename tests/{run-pass => pass}/concurrency/sync.stderr (100%) rename tests/{run-pass => pass}/concurrency/sync.stdout (100%) rename tests/{run-pass => pass}/concurrency/sync_singlethread.rs (100%) rename tests/{run-pass => pass}/concurrency/thread_locals.rs (100%) rename tests/{run-pass => pass}/concurrency/thread_locals.stderr (100%) rename tests/{run-pass => pass}/concurrency/tls_lib_drop.rs (100%) rename tests/{run-pass => pass}/concurrency/tls_lib_drop.stderr (100%) rename tests/{run-pass => pass}/concurrency/tls_lib_drop.stdout (100%) rename tests/{run-pass => pass}/concurrency/tls_lib_drop_single_thread.rs (100%) rename tests/{run-pass => pass}/concurrency/tls_lib_drop_single_thread.stderr (100%) rename tests/{run-pass => pass}/concurrency/tls_pthread_drop_order.rs (100%) rename tests/{run-pass => pass}/const-vec-of-fns.rs (100%) rename tests/{run-pass => pass}/constants.rs (100%) rename tests/{run-pass => pass}/current_dir.rs (100%) rename tests/{run-pass => pass}/current_dir_with_isolation.rs (100%) rename tests/{run-pass => pass}/current_dir_with_isolation.stderr (100%) rename tests/{run-pass => pass}/deriving-associated-types.rs (100%) rename tests/{run-pass => pass}/disable-alignment-check.rs (100%) rename tests/{run-pass => pass}/drop_empty_slice.rs (100%) rename tests/{run-pass => pass}/drop_on_array_elements.rs (100%) rename tests/{run-pass => pass}/drop_on_fat_ptr_array_elements.rs (100%) rename tests/{run-pass => pass}/drop_on_zst_array_elements.rs (100%) rename tests/{run-pass => pass}/drop_through_owned_slice.rs (100%) rename tests/{run-pass => pass}/drop_through_trait_object.rs (100%) rename tests/{run-pass => pass}/drop_through_trait_object_rc.rs (100%) rename tests/{run-pass => pass}/dst-field-align.rs (100%) rename tests/{run-pass => pass}/dst-irrefutable-bind.rs (100%) rename tests/{run-pass => pass}/dst-raw.rs (100%) rename tests/{run-pass => pass}/dst-struct-sole.rs (100%) rename tests/{run-pass => pass}/dst-struct.rs (100%) rename tests/{run-pass => pass}/dyn-arbitrary-self.rs (100%) rename tests/{run-pass => pass}/dyn-traits.rs (100%) rename tests/{run-pass => pass}/enum-nullable-const-null-with-fields.rs (100%) rename tests/{run-pass => pass}/enum_discriminant_ptr_value.rs (100%) rename tests/{run-pass => pass}/enums.rs (100%) rename tests/{run-pass => pass}/env-exclude.rs (100%) rename tests/{run-pass => pass}/env-forward.rs (100%) rename tests/{run-pass => pass}/env-without-isolation.rs (100%) rename tests/{run-pass => pass}/env.rs (100%) rename tests/{run-pass => pass}/env.stdout (100%) rename tests/{run-pass => pass}/exit.rs (100%) rename tests/{run-pass => pass}/extern_crate_std_in_main.rs (100%) rename tests/{run-pass => pass}/extern_types.rs (100%) rename tests/{run-pass => pass}/fat_ptr.rs (100%) rename tests/{run-pass => pass}/float.rs (100%) rename tests/{run-pass => pass}/float_fast_math.rs (100%) rename tests/{run-pass => pass}/foreign-fn-linkname.rs (100%) rename tests/{run-pass => pass}/format.rs (100%) rename tests/{run-pass => pass}/format.stdout (100%) rename tests/{run-pass => pass}/from_utf8.rs (100%) rename tests/{run-pass => pass}/fs.rs (100%) rename tests/{run-pass => pass}/fs.stderr (100%) rename tests/{run-pass => pass}/fs.stdout (100%) rename tests/{run-pass => pass}/fs_with_isolation.rs (100%) rename tests/{run-pass => pass}/fs_with_isolation.stderr (100%) rename tests/{run-pass => pass}/function_calls/disable_abi_check.rs (100%) rename tests/{run-pass => pass}/function_calls/exported_symbol.rs (100%) rename tests/{run-pass => pass}/function_pointers.rs (100%) rename tests/{run-pass => pass}/generator.rs (100%) rename tests/{run-pass => pass}/global_allocator.rs (100%) rename tests/{run-pass => pass}/global_allocator.stdout (100%) rename tests/{run-pass => pass}/hashmap.rs (100%) rename tests/{run-pass => pass}/heap.rs (100%) rename tests/{run-pass => pass}/heap_allocator.rs (100%) rename tests/{run-pass => pass}/hello.rs (100%) rename tests/{run-pass => pass}/hello.stdout (100%) rename tests/{run-pass => pass}/hide_stdout.rs (100%) rename tests/{run-pass => pass}/integer-ops.rs (100%) rename tests/{run-pass => pass}/intptrcast.rs (100%) rename tests/{run-pass => pass}/intrinsics-integer.rs (100%) rename tests/{run-pass => pass}/intrinsics-math.rs (100%) rename tests/{run-pass => pass}/intrinsics-x86.rs (100%) rename tests/{run-pass => pass}/intrinsics.rs (100%) rename tests/{run-pass => pass}/ints.rs (100%) rename tests/{run-pass => pass}/issue-15063.rs (100%) rename tests/{run-pass => pass}/issue-15080.rs (100%) rename tests/{run-pass => pass}/issue-15523-big.rs (100%) rename tests/{run-pass => pass}/issue-17877.rs (100%) rename tests/{run-pass => pass}/issue-20575.rs (100%) rename tests/{run-pass => pass}/issue-23261.rs (100%) rename tests/{run-pass => pass}/issue-26709.rs (100%) rename tests/{run-pass => pass}/issue-27901.rs (100%) rename tests/{run-pass => pass}/issue-29746.rs (100%) rename tests/{run-pass => pass}/issue-30530.rs (100%) rename tests/{run-pass => pass}/issue-31267-additional.rs (100%) rename tests/{run-pass => pass}/issue-33387.rs (100%) rename tests/{run-pass => pass}/issue-34571.rs (100%) rename tests/{run-pass => pass}/issue-35815.rs (100%) rename tests/{run-pass => pass}/issue-36278-prefix-nesting.rs (100%) rename tests/{run-pass => pass}/issue-3794.rs (100%) rename tests/{run-pass => pass}/issue-3794.stdout (100%) rename tests/{run-pass => pass}/issue-53728.rs (100%) rename tests/{run-pass => pass}/issue-5917.rs (100%) rename tests/{run-pass => pass}/issue-73223.rs (100%) rename tests/{run-pass => pass}/issue-91636.rs (100%) rename tests/{run-pass => pass}/issue-94371.rs (100%) rename tests/{run-pass => pass}/issue-miri-1075.rs (100%) rename tests/{run-pass => pass}/issue-miri-133.rs (100%) rename tests/{run-pass => pass}/issue-miri-184.rs (100%) rename tests/{run-pass => pass}/issue-miri-1925.rs (100%) rename tests/{run-pass => pass}/issue-miri-2068-2.rs (100%) rename tests/{run-pass => pass}/issue-miri-2068.rs (100%) rename tests/{run-pass => pass}/iter.rs (100%) rename tests/{run-pass => pass}/last-use-in-cap-clause.rs (100%) rename tests/{run-pass => pass}/leak-in-static.rs (100%) rename tests/{run-pass => pass}/libc.rs (100%) rename tests/{run-pass => pass}/libc.stderr (100%) rename tests/{run-pass => pass}/linked-list.rs (100%) rename tests/{run-pass => pass}/linux-getrandom-without-isolation.rs (100%) rename tests/{run-pass => pass}/linux-getrandom.rs (100%) rename tests/{run-pass => pass}/loop-break-value.rs (100%) rename tests/{run-pass => pass}/loops.rs (100%) rename tests/{run-pass => pass}/main_fn.rs (100%) rename tests/{run-pass => pass}/main_result.rs (100%) rename tests/{run-pass => pass}/malloc.rs (100%) rename tests/{run-pass => pass}/many_shr_bor.rs (100%) rename tests/{run-pass => pass}/match_slice.rs (100%) rename tests/{run-pass => pass}/memchr.rs (100%) rename tests/{run-pass => pass}/memleak_ignored.rs (100%) rename tests/{run-pass => pass}/move-arg-2-unique.rs (100%) rename tests/{run-pass => pass}/move-arg-3-unique.rs (100%) rename tests/{run-pass => pass}/move-uninit-primval.rs (100%) rename tests/{run-pass => pass}/mpsc.rs (100%) rename tests/{run-pass => pass}/multi_arg_closure.rs (100%) rename tests/{run-pass => pass}/negative_discriminant.rs (100%) rename tests/{run-pass => pass}/observed_local_mut.rs (100%) rename tests/{run-pass => pass}/option_box_transmute_ptr.rs (100%) rename tests/{run-pass => pass}/option_eq.rs (100%) rename tests/{run-pass => pass}/overflow_checks_off.rs (100%) rename tests/{run-pass => pass}/overloaded-calls-simple.rs (100%) rename tests/{run-pass => pass}/packed_struct.rs (100%) rename tests/{run-pass => pass}/panic/catch_panic.rs (100%) rename tests/{run-pass => pass}/panic/catch_panic.stderr (100%) rename tests/{run-pass => pass}/panic/concurrent-panic.rs (100%) rename tests/{run-pass => pass}/panic/concurrent-panic.stderr (100%) rename tests/{run-pass => pass}/panic/std-panic-locations.rs (100%) rename tests/{run-pass => pass}/partially-uninit.rs (100%) rename tests/{run-pass => pass}/pointers.rs (100%) rename tests/{run-pass => pass}/portable-simd.rs (100%) rename tests/{run-pass => pass}/products.rs (100%) rename tests/{run-pass => pass}/ptr_int_casts.rs (100%) rename tests/{run-pass => pass}/ptr_int_permissive_provenance.rs (100%) rename tests/{run-pass => pass}/ptr_offset.rs (100%) rename tests/{run-pass => pass}/ptr_raw.rs (100%) rename tests/{run-pass => pass}/rc.rs (100%) rename tests/{run-pass => pass}/recursive_static.rs (100%) rename tests/{run-pass => pass}/reentrant-println.rs (100%) rename tests/{run-pass => pass}/reentrant-println.stdout (100%) rename tests/{run-pass => pass}/regions-lifetime-nonfree-late-bound.rs (100%) rename tests/{run-pass => pass}/regions-mock-trans.rs (100%) rename tests/{run-pass => pass}/rename_std.rs (100%) rename tests/{run-pass => pass}/rfc1623.rs (100%) rename tests/{run-pass => pass}/rust-lang-org.rs (100%) rename tests/{run-pass => pass}/send-is-not-static-par-for.rs (100%) rename tests/{run-pass => pass}/sendable-class.rs (100%) rename tests/{run-pass => pass}/simd-intrinsic-generic-elements.rs (100%) rename tests/{run-pass => pass}/slices.rs (100%) rename tests/{run-pass => pass}/small_enum_size_bug.rs (100%) rename tests/{run-pass => pass}/specialization.rs (100%) rename tests/{run-pass => pass}/stacked-borrows/2phase.rs (100%) rename tests/{run-pass => pass}/stacked-borrows/generators-self-referential.rs (100%) rename tests/{run-pass => pass}/stacked-borrows/int-to-ptr.rs (100%) rename tests/{run-pass => pass}/stacked-borrows/interior_mutability.rs (100%) rename tests/{run-pass => pass}/stacked-borrows/refcell.rs (100%) rename tests/{run-pass => pass}/stacked-borrows/stacked-borrows.rs (100%) rename tests/{run-pass => pass}/stacked-borrows/stacked-borrows.stderr (100%) rename tests/{run-pass => pass}/start.rs (100%) rename tests/{run-pass => pass}/start.stdout (100%) rename tests/{run-pass => pass}/static_memory_modification.rs (100%) rename tests/{run-pass => pass}/static_mut.rs (100%) rename tests/{run-pass => pass}/strings.rs (100%) rename tests/{run-pass => pass}/subslice_array.rs (100%) rename tests/{run-pass => pass}/sums.rs (100%) rename tests/{run-pass => pass}/tag-align-dyn-u64.rs (100%) rename tests/{run-pass => pass}/threadleak_ignored.rs (100%) rename tests/{run-pass => pass}/threadleak_ignored.stderr (100%) rename tests/{run-pass => pass}/time.rs (100%) rename tests/{run-pass => pass}/too-large-primval-write-problem.rs (100%) rename tests/{run-pass => pass}/track-alloc-1.rs (100%) rename tests/{run-pass => pass}/track-alloc-1.stderr (100%) rename tests/{run-pass => pass}/track-caller-attribute.rs (100%) rename tests/{run-pass => pass}/transmute_fat.rs (100%) rename tests/{run-pass => pass}/trivial.rs (100%) rename tests/{run-pass => pass}/try-operator-custom.rs (100%) rename tests/{run-pass => pass}/tuple_like_enum_variant_constructor.rs (100%) rename tests/{run-pass => pass}/tuple_like_enum_variant_constructor_pointer_opt.rs (100%) rename tests/{run-pass => pass}/tuple_like_enum_variant_constructor_struct_pointer_opt.rs (100%) rename tests/{run-pass => pass}/tuple_like_struct_constructor.rs (100%) rename tests/{run-pass => pass}/u128.rs (100%) rename tests/{run-pass => pass}/uninit_number_ignored.rs (100%) rename tests/{run-pass => pass}/union-overwrite.rs (100%) rename tests/{run-pass => pass}/union.rs (100%) rename tests/{run-pass => pass}/unops.rs (100%) rename tests/{run-pass => pass}/unsized-tuple-impls.rs (100%) rename tests/{run-pass => pass}/validation_lifetime_resolution.rs (100%) rename tests/{run-pass => pass}/vec-matching-fold.rs (100%) rename tests/{run-pass => pass}/vec.rs (100%) rename tests/{run-pass => pass}/vecdeque.rs (100%) rename tests/{run-pass => pass}/vecdeque.stdout (100%) rename tests/{run-pass => pass}/volatile.rs (100%) rename tests/{run-pass => pass}/without-validation.rs (100%) rename tests/{run-pass => pass}/write-bytes.rs (100%) rename tests/{run-pass => pass}/wtf8.rs (100%) rename tests/{run-pass => pass}/zst.rs (100%) rename tests/{run-pass => pass}/zst_box.rs (100%) rename tests/{run-pass => pass}/zst_variant_drop.rs (100%) diff --git a/ci.sh b/ci.sh index 080bd9204db5..01b86ff2f96b 100755 --- a/ci.sh +++ b/ci.sh @@ -26,7 +26,7 @@ function run_tests { # optimizations up all the way). # Optimizations change diagnostics (mostly backtraces), so we don't check them #FIXME(#2155): we want to only run the pass and panic tests here, not the fail tests. - MIRIFLAGS="-O -Zmir-opt-level=4" MIRI_SKIP_UI_CHECKS=1 ./miri test --locked -- tests/{run-pass,run-fail} + MIRIFLAGS="-O -Zmir-opt-level=4" MIRI_SKIP_UI_CHECKS=1 ./miri test --locked -- tests/{pass,panic} fi # On Windows, there is always "python", not "python3" or "python2". diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 3b6cf6a6d1fd..4481c02d7650 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -132,7 +132,7 @@ fn main() { // Let the tests know where to store temp files (they might run for a different target, which can make this hard to find). env::set_var("MIRI_TEMP", env::temp_dir()); - ui(Mode::Pass, "tests/run-pass"); - ui(Mode::Panic, "tests/run-fail"); - ui(Mode::Fail, "tests/compile-fail"); + ui(Mode::Pass, "tests/pass"); + ui(Mode::Panic, "tests/panic"); + ui(Mode::Fail, "tests/fail"); } diff --git a/tests/compile-fail/abort-terminator.rs b/tests/fail/abort-terminator.rs similarity index 100% rename from tests/compile-fail/abort-terminator.rs rename to tests/fail/abort-terminator.rs diff --git a/tests/compile-fail/abort-terminator.stderr b/tests/fail/abort-terminator.stderr similarity index 100% rename from tests/compile-fail/abort-terminator.stderr rename to tests/fail/abort-terminator.stderr diff --git a/tests/compile-fail/alloc/deallocate-bad-alignment.rs b/tests/fail/alloc/deallocate-bad-alignment.rs similarity index 100% rename from tests/compile-fail/alloc/deallocate-bad-alignment.rs rename to tests/fail/alloc/deallocate-bad-alignment.rs diff --git a/tests/compile-fail/alloc/deallocate-bad-alignment.stderr b/tests/fail/alloc/deallocate-bad-alignment.stderr similarity index 100% rename from tests/compile-fail/alloc/deallocate-bad-alignment.stderr rename to tests/fail/alloc/deallocate-bad-alignment.stderr diff --git a/tests/compile-fail/alloc/deallocate-bad-size.rs b/tests/fail/alloc/deallocate-bad-size.rs similarity index 100% rename from tests/compile-fail/alloc/deallocate-bad-size.rs rename to tests/fail/alloc/deallocate-bad-size.rs diff --git a/tests/compile-fail/alloc/deallocate-bad-size.stderr b/tests/fail/alloc/deallocate-bad-size.stderr similarity index 100% rename from tests/compile-fail/alloc/deallocate-bad-size.stderr rename to tests/fail/alloc/deallocate-bad-size.stderr diff --git a/tests/compile-fail/alloc/deallocate-twice.rs b/tests/fail/alloc/deallocate-twice.rs similarity index 100% rename from tests/compile-fail/alloc/deallocate-twice.rs rename to tests/fail/alloc/deallocate-twice.rs diff --git a/tests/compile-fail/alloc/deallocate-twice.stderr b/tests/fail/alloc/deallocate-twice.stderr similarity index 100% rename from tests/compile-fail/alloc/deallocate-twice.stderr rename to tests/fail/alloc/deallocate-twice.stderr diff --git a/tests/compile-fail/alloc/global_system_mixup.rs b/tests/fail/alloc/global_system_mixup.rs similarity index 100% rename from tests/compile-fail/alloc/global_system_mixup.rs rename to tests/fail/alloc/global_system_mixup.rs diff --git a/tests/compile-fail/alloc/global_system_mixup.stderr b/tests/fail/alloc/global_system_mixup.stderr similarity index 100% rename from tests/compile-fail/alloc/global_system_mixup.stderr rename to tests/fail/alloc/global_system_mixup.stderr diff --git a/tests/compile-fail/alloc/no_global_allocator.rs b/tests/fail/alloc/no_global_allocator.rs similarity index 100% rename from tests/compile-fail/alloc/no_global_allocator.rs rename to tests/fail/alloc/no_global_allocator.rs diff --git a/tests/compile-fail/alloc/no_global_allocator.stderr b/tests/fail/alloc/no_global_allocator.stderr similarity index 100% rename from tests/compile-fail/alloc/no_global_allocator.stderr rename to tests/fail/alloc/no_global_allocator.stderr diff --git a/tests/compile-fail/alloc/reallocate-bad-size.rs b/tests/fail/alloc/reallocate-bad-size.rs similarity index 100% rename from tests/compile-fail/alloc/reallocate-bad-size.rs rename to tests/fail/alloc/reallocate-bad-size.rs diff --git a/tests/compile-fail/alloc/reallocate-bad-size.stderr b/tests/fail/alloc/reallocate-bad-size.stderr similarity index 100% rename from tests/compile-fail/alloc/reallocate-bad-size.stderr rename to tests/fail/alloc/reallocate-bad-size.stderr diff --git a/tests/compile-fail/alloc/reallocate-change-alloc.rs b/tests/fail/alloc/reallocate-change-alloc.rs similarity index 100% rename from tests/compile-fail/alloc/reallocate-change-alloc.rs rename to tests/fail/alloc/reallocate-change-alloc.rs diff --git a/tests/compile-fail/alloc/reallocate-change-alloc.stderr b/tests/fail/alloc/reallocate-change-alloc.stderr similarity index 100% rename from tests/compile-fail/alloc/reallocate-change-alloc.stderr rename to tests/fail/alloc/reallocate-change-alloc.stderr diff --git a/tests/compile-fail/alloc/reallocate-dangling.rs b/tests/fail/alloc/reallocate-dangling.rs similarity index 100% rename from tests/compile-fail/alloc/reallocate-dangling.rs rename to tests/fail/alloc/reallocate-dangling.rs diff --git a/tests/compile-fail/alloc/reallocate-dangling.stderr b/tests/fail/alloc/reallocate-dangling.stderr similarity index 100% rename from tests/compile-fail/alloc/reallocate-dangling.stderr rename to tests/fail/alloc/reallocate-dangling.stderr diff --git a/tests/compile-fail/alloc/stack_free.rs b/tests/fail/alloc/stack_free.rs similarity index 100% rename from tests/compile-fail/alloc/stack_free.rs rename to tests/fail/alloc/stack_free.rs diff --git a/tests/compile-fail/alloc/stack_free.stderr b/tests/fail/alloc/stack_free.stderr similarity index 100% rename from tests/compile-fail/alloc/stack_free.stderr rename to tests/fail/alloc/stack_free.stderr diff --git a/tests/compile-fail/backtrace/bad-backtrace-decl.rs b/tests/fail/backtrace/bad-backtrace-decl.rs similarity index 100% rename from tests/compile-fail/backtrace/bad-backtrace-decl.rs rename to tests/fail/backtrace/bad-backtrace-decl.rs diff --git a/tests/compile-fail/backtrace/bad-backtrace-decl.stderr b/tests/fail/backtrace/bad-backtrace-decl.stderr similarity index 100% rename from tests/compile-fail/backtrace/bad-backtrace-decl.stderr rename to tests/fail/backtrace/bad-backtrace-decl.stderr diff --git a/tests/compile-fail/backtrace/bad-backtrace-flags.rs b/tests/fail/backtrace/bad-backtrace-flags.rs similarity index 100% rename from tests/compile-fail/backtrace/bad-backtrace-flags.rs rename to tests/fail/backtrace/bad-backtrace-flags.rs diff --git a/tests/compile-fail/backtrace/bad-backtrace-flags.stderr b/tests/fail/backtrace/bad-backtrace-flags.stderr similarity index 100% rename from tests/compile-fail/backtrace/bad-backtrace-flags.stderr rename to tests/fail/backtrace/bad-backtrace-flags.stderr diff --git a/tests/compile-fail/backtrace/bad-backtrace-ptr.rs b/tests/fail/backtrace/bad-backtrace-ptr.rs similarity index 100% rename from tests/compile-fail/backtrace/bad-backtrace-ptr.rs rename to tests/fail/backtrace/bad-backtrace-ptr.rs diff --git a/tests/compile-fail/backtrace/bad-backtrace-ptr.stderr b/tests/fail/backtrace/bad-backtrace-ptr.stderr similarity index 100% rename from tests/compile-fail/backtrace/bad-backtrace-ptr.stderr rename to tests/fail/backtrace/bad-backtrace-ptr.stderr diff --git a/tests/compile-fail/backtrace/bad-backtrace-resolve-flags.rs b/tests/fail/backtrace/bad-backtrace-resolve-flags.rs similarity index 100% rename from tests/compile-fail/backtrace/bad-backtrace-resolve-flags.rs rename to tests/fail/backtrace/bad-backtrace-resolve-flags.rs diff --git a/tests/compile-fail/backtrace/bad-backtrace-resolve-flags.stderr b/tests/fail/backtrace/bad-backtrace-resolve-flags.stderr similarity index 100% rename from tests/compile-fail/backtrace/bad-backtrace-resolve-flags.stderr rename to tests/fail/backtrace/bad-backtrace-resolve-flags.stderr diff --git a/tests/compile-fail/backtrace/bad-backtrace-resolve-names-flags.rs b/tests/fail/backtrace/bad-backtrace-resolve-names-flags.rs similarity index 100% rename from tests/compile-fail/backtrace/bad-backtrace-resolve-names-flags.rs rename to tests/fail/backtrace/bad-backtrace-resolve-names-flags.rs diff --git a/tests/compile-fail/backtrace/bad-backtrace-resolve-names-flags.stderr b/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr similarity index 100% rename from tests/compile-fail/backtrace/bad-backtrace-resolve-names-flags.stderr rename to tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr diff --git a/tests/compile-fail/backtrace/bad-backtrace-size-flags.rs b/tests/fail/backtrace/bad-backtrace-size-flags.rs similarity index 100% rename from tests/compile-fail/backtrace/bad-backtrace-size-flags.rs rename to tests/fail/backtrace/bad-backtrace-size-flags.rs diff --git a/tests/compile-fail/backtrace/bad-backtrace-size-flags.stderr b/tests/fail/backtrace/bad-backtrace-size-flags.stderr similarity index 100% rename from tests/compile-fail/backtrace/bad-backtrace-size-flags.stderr rename to tests/fail/backtrace/bad-backtrace-size-flags.stderr diff --git a/tests/compile-fail/backtrace/bad-backtrace-version.stderr b/tests/fail/backtrace/bad-backtrace-version.stderr similarity index 100% rename from tests/compile-fail/backtrace/bad-backtrace-version.stderr rename to tests/fail/backtrace/bad-backtrace-version.stderr diff --git a/tests/compile-fail/box-cell-alias.rs b/tests/fail/box-cell-alias.rs similarity index 100% rename from tests/compile-fail/box-cell-alias.rs rename to tests/fail/box-cell-alias.rs diff --git a/tests/compile-fail/box-cell-alias.stderr b/tests/fail/box-cell-alias.stderr similarity index 100% rename from tests/compile-fail/box-cell-alias.stderr rename to tests/fail/box-cell-alias.stderr diff --git a/tests/compile-fail/branchless-select-i128-pointer.rs b/tests/fail/branchless-select-i128-pointer.rs similarity index 100% rename from tests/compile-fail/branchless-select-i128-pointer.rs rename to tests/fail/branchless-select-i128-pointer.rs diff --git a/tests/compile-fail/branchless-select-i128-pointer.stderr b/tests/fail/branchless-select-i128-pointer.stderr similarity index 100% rename from tests/compile-fail/branchless-select-i128-pointer.stderr rename to tests/fail/branchless-select-i128-pointer.stderr diff --git a/tests/compile-fail/breakpoint.rs b/tests/fail/breakpoint.rs similarity index 100% rename from tests/compile-fail/breakpoint.rs rename to tests/fail/breakpoint.rs diff --git a/tests/compile-fail/breakpoint.stderr b/tests/fail/breakpoint.stderr similarity index 100% rename from tests/compile-fail/breakpoint.stderr rename to tests/fail/breakpoint.stderr diff --git a/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs b/tests/fail/concurrency/libc_pthread_create_main_terminate.rs similarity index 100% rename from tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs rename to tests/fail/concurrency/libc_pthread_create_main_terminate.rs diff --git a/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.stderr b/tests/fail/concurrency/libc_pthread_create_main_terminate.stderr similarity index 100% rename from tests/compile-fail/concurrency/libc_pthread_create_main_terminate.stderr rename to tests/fail/concurrency/libc_pthread_create_main_terminate.stderr diff --git a/tests/compile-fail/concurrency/libc_pthread_join_detached.rs b/tests/fail/concurrency/libc_pthread_join_detached.rs similarity index 100% rename from tests/compile-fail/concurrency/libc_pthread_join_detached.rs rename to tests/fail/concurrency/libc_pthread_join_detached.rs diff --git a/tests/compile-fail/concurrency/libc_pthread_join_detached.stderr b/tests/fail/concurrency/libc_pthread_join_detached.stderr similarity index 100% rename from tests/compile-fail/concurrency/libc_pthread_join_detached.stderr rename to tests/fail/concurrency/libc_pthread_join_detached.stderr diff --git a/tests/compile-fail/concurrency/libc_pthread_join_joined.rs b/tests/fail/concurrency/libc_pthread_join_joined.rs similarity index 100% rename from tests/compile-fail/concurrency/libc_pthread_join_joined.rs rename to tests/fail/concurrency/libc_pthread_join_joined.rs diff --git a/tests/compile-fail/concurrency/libc_pthread_join_joined.stderr b/tests/fail/concurrency/libc_pthread_join_joined.stderr similarity index 100% rename from tests/compile-fail/concurrency/libc_pthread_join_joined.stderr rename to tests/fail/concurrency/libc_pthread_join_joined.stderr diff --git a/tests/compile-fail/concurrency/libc_pthread_join_main.rs b/tests/fail/concurrency/libc_pthread_join_main.rs similarity index 100% rename from tests/compile-fail/concurrency/libc_pthread_join_main.rs rename to tests/fail/concurrency/libc_pthread_join_main.rs diff --git a/tests/compile-fail/concurrency/libc_pthread_join_main.stderr b/tests/fail/concurrency/libc_pthread_join_main.stderr similarity index 100% rename from tests/compile-fail/concurrency/libc_pthread_join_main.stderr rename to tests/fail/concurrency/libc_pthread_join_main.stderr diff --git a/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs b/tests/fail/concurrency/libc_pthread_join_multiple.rs similarity index 100% rename from tests/compile-fail/concurrency/libc_pthread_join_multiple.rs rename to tests/fail/concurrency/libc_pthread_join_multiple.rs diff --git a/tests/compile-fail/concurrency/libc_pthread_join_multiple.stderr b/tests/fail/concurrency/libc_pthread_join_multiple.stderr similarity index 100% rename from tests/compile-fail/concurrency/libc_pthread_join_multiple.stderr rename to tests/fail/concurrency/libc_pthread_join_multiple.stderr diff --git a/tests/compile-fail/concurrency/libc_pthread_join_self.rs b/tests/fail/concurrency/libc_pthread_join_self.rs similarity index 100% rename from tests/compile-fail/concurrency/libc_pthread_join_self.rs rename to tests/fail/concurrency/libc_pthread_join_self.rs diff --git a/tests/compile-fail/concurrency/libc_pthread_join_self.stderr b/tests/fail/concurrency/libc_pthread_join_self.stderr similarity index 100% rename from tests/compile-fail/concurrency/libc_pthread_join_self.stderr rename to tests/fail/concurrency/libc_pthread_join_self.stderr diff --git a/tests/compile-fail/concurrency/thread-spawn.rs b/tests/fail/concurrency/thread-spawn.rs similarity index 100% rename from tests/compile-fail/concurrency/thread-spawn.rs rename to tests/fail/concurrency/thread-spawn.rs diff --git a/tests/compile-fail/concurrency/thread_local_static_dealloc.rs b/tests/fail/concurrency/thread_local_static_dealloc.rs similarity index 100% rename from tests/compile-fail/concurrency/thread_local_static_dealloc.rs rename to tests/fail/concurrency/thread_local_static_dealloc.rs diff --git a/tests/compile-fail/concurrency/thread_local_static_dealloc.stderr b/tests/fail/concurrency/thread_local_static_dealloc.stderr similarity index 100% rename from tests/compile-fail/concurrency/thread_local_static_dealloc.stderr rename to tests/fail/concurrency/thread_local_static_dealloc.stderr diff --git a/tests/compile-fail/concurrency/too_few_args.rs b/tests/fail/concurrency/too_few_args.rs similarity index 100% rename from tests/compile-fail/concurrency/too_few_args.rs rename to tests/fail/concurrency/too_few_args.rs diff --git a/tests/compile-fail/concurrency/too_few_args.stderr b/tests/fail/concurrency/too_few_args.stderr similarity index 100% rename from tests/compile-fail/concurrency/too_few_args.stderr rename to tests/fail/concurrency/too_few_args.stderr diff --git a/tests/compile-fail/concurrency/too_many_args.rs b/tests/fail/concurrency/too_many_args.rs similarity index 100% rename from tests/compile-fail/concurrency/too_many_args.rs rename to tests/fail/concurrency/too_many_args.rs diff --git a/tests/compile-fail/concurrency/too_many_args.stderr b/tests/fail/concurrency/too_many_args.stderr similarity index 100% rename from tests/compile-fail/concurrency/too_many_args.stderr rename to tests/fail/concurrency/too_many_args.stderr diff --git a/tests/compile-fail/concurrency/unwind_top_of_stack.rs b/tests/fail/concurrency/unwind_top_of_stack.rs similarity index 100% rename from tests/compile-fail/concurrency/unwind_top_of_stack.rs rename to tests/fail/concurrency/unwind_top_of_stack.rs diff --git a/tests/compile-fail/concurrency/unwind_top_of_stack.stderr b/tests/fail/concurrency/unwind_top_of_stack.stderr similarity index 100% rename from tests/compile-fail/concurrency/unwind_top_of_stack.stderr rename to tests/fail/concurrency/unwind_top_of_stack.stderr diff --git a/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.rs b/tests/fail/dangling_pointers/dangling_pointer_addr_of.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.rs rename to tests/fail/dangling_pointers/dangling_pointer_addr_of.rs diff --git a/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.stderr b/tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.stderr rename to tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr diff --git a/tests/compile-fail/dangling_pointers/dangling_pointer_deref.rs b/tests/fail/dangling_pointers/dangling_pointer_deref.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/dangling_pointer_deref.rs rename to tests/fail/dangling_pointers/dangling_pointer_deref.rs diff --git a/tests/compile-fail/dangling_pointers/dangling_pointer_deref.stderr b/tests/fail/dangling_pointers/dangling_pointer_deref.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/dangling_pointer_deref.stderr rename to tests/fail/dangling_pointers/dangling_pointer_deref.stderr diff --git a/tests/compile-fail/dangling_pointers/dangling_zst_deref.rs b/tests/fail/dangling_pointers/dangling_zst_deref.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/dangling_zst_deref.rs rename to tests/fail/dangling_pointers/dangling_zst_deref.rs diff --git a/tests/compile-fail/dangling_pointers/dangling_zst_deref.stderr b/tests/fail/dangling_pointers/dangling_zst_deref.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/dangling_zst_deref.stderr rename to tests/fail/dangling_pointers/dangling_zst_deref.stderr diff --git a/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs b/tests/fail/dangling_pointers/deref-invalid-ptr.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs rename to tests/fail/dangling_pointers/deref-invalid-ptr.rs diff --git a/tests/compile-fail/dangling_pointers/deref-invalid-ptr.stderr b/tests/fail/dangling_pointers/deref-invalid-ptr.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/deref-invalid-ptr.stderr rename to tests/fail/dangling_pointers/deref-invalid-ptr.stderr diff --git a/tests/compile-fail/dangling_pointers/deref-partially-dangling.rs b/tests/fail/dangling_pointers/deref-partially-dangling.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/deref-partially-dangling.rs rename to tests/fail/dangling_pointers/deref-partially-dangling.rs diff --git a/tests/compile-fail/dangling_pointers/deref-partially-dangling.stderr b/tests/fail/dangling_pointers/deref-partially-dangling.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/deref-partially-dangling.stderr rename to tests/fail/dangling_pointers/deref-partially-dangling.stderr diff --git a/tests/compile-fail/dangling_pointers/dyn_size.rs b/tests/fail/dangling_pointers/dyn_size.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/dyn_size.rs rename to tests/fail/dangling_pointers/dyn_size.rs diff --git a/tests/compile-fail/dangling_pointers/dyn_size.stderr b/tests/fail/dangling_pointers/dyn_size.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/dyn_size.stderr rename to tests/fail/dangling_pointers/dyn_size.stderr diff --git a/tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.rs b/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.rs rename to tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.rs diff --git a/tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr b/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr rename to tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr diff --git a/tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.rs b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.rs rename to tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs diff --git a/tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.stderr b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.stderr rename to tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr diff --git a/tests/compile-fail/dangling_pointers/null_pointer_deref.rs b/tests/fail/dangling_pointers/null_pointer_deref.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/null_pointer_deref.rs rename to tests/fail/dangling_pointers/null_pointer_deref.rs diff --git a/tests/compile-fail/dangling_pointers/null_pointer_deref.stderr b/tests/fail/dangling_pointers/null_pointer_deref.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/null_pointer_deref.stderr rename to tests/fail/dangling_pointers/null_pointer_deref.stderr diff --git a/tests/compile-fail/dangling_pointers/null_pointer_deref_zst.rs b/tests/fail/dangling_pointers/null_pointer_deref_zst.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/null_pointer_deref_zst.rs rename to tests/fail/dangling_pointers/null_pointer_deref_zst.rs diff --git a/tests/compile-fail/dangling_pointers/null_pointer_deref_zst.stderr b/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/null_pointer_deref_zst.stderr rename to tests/fail/dangling_pointers/null_pointer_deref_zst.stderr diff --git a/tests/compile-fail/dangling_pointers/null_pointer_write.rs b/tests/fail/dangling_pointers/null_pointer_write.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/null_pointer_write.rs rename to tests/fail/dangling_pointers/null_pointer_write.rs diff --git a/tests/compile-fail/dangling_pointers/null_pointer_write.stderr b/tests/fail/dangling_pointers/null_pointer_write.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/null_pointer_write.stderr rename to tests/fail/dangling_pointers/null_pointer_write.stderr diff --git a/tests/compile-fail/dangling_pointers/null_pointer_write_zst.rs b/tests/fail/dangling_pointers/null_pointer_write_zst.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/null_pointer_write_zst.rs rename to tests/fail/dangling_pointers/null_pointer_write_zst.rs diff --git a/tests/compile-fail/dangling_pointers/null_pointer_write_zst.stderr b/tests/fail/dangling_pointers/null_pointer_write_zst.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/null_pointer_write_zst.stderr rename to tests/fail/dangling_pointers/null_pointer_write_zst.stderr diff --git a/tests/compile-fail/dangling_pointers/out_of_bounds_read1.rs b/tests/fail/dangling_pointers/out_of_bounds_read1.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/out_of_bounds_read1.rs rename to tests/fail/dangling_pointers/out_of_bounds_read1.rs diff --git a/tests/compile-fail/dangling_pointers/out_of_bounds_read1.stderr b/tests/fail/dangling_pointers/out_of_bounds_read1.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/out_of_bounds_read1.stderr rename to tests/fail/dangling_pointers/out_of_bounds_read1.stderr diff --git a/tests/compile-fail/dangling_pointers/out_of_bounds_read2.rs b/tests/fail/dangling_pointers/out_of_bounds_read2.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/out_of_bounds_read2.rs rename to tests/fail/dangling_pointers/out_of_bounds_read2.rs diff --git a/tests/compile-fail/dangling_pointers/out_of_bounds_read2.stderr b/tests/fail/dangling_pointers/out_of_bounds_read2.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/out_of_bounds_read2.stderr rename to tests/fail/dangling_pointers/out_of_bounds_read2.stderr diff --git a/tests/compile-fail/dangling_pointers/stack_temporary.rs b/tests/fail/dangling_pointers/stack_temporary.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/stack_temporary.rs rename to tests/fail/dangling_pointers/stack_temporary.rs diff --git a/tests/compile-fail/dangling_pointers/stack_temporary.stderr b/tests/fail/dangling_pointers/stack_temporary.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/stack_temporary.stderr rename to tests/fail/dangling_pointers/stack_temporary.stderr diff --git a/tests/compile-fail/dangling_pointers/storage_dead_dangling.rs b/tests/fail/dangling_pointers/storage_dead_dangling.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/storage_dead_dangling.rs rename to tests/fail/dangling_pointers/storage_dead_dangling.rs diff --git a/tests/compile-fail/dangling_pointers/storage_dead_dangling.stderr b/tests/fail/dangling_pointers/storage_dead_dangling.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/storage_dead_dangling.stderr rename to tests/fail/dangling_pointers/storage_dead_dangling.stderr diff --git a/tests/compile-fail/dangling_pointers/wild_pointer_deref.rs b/tests/fail/dangling_pointers/wild_pointer_deref.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/wild_pointer_deref.rs rename to tests/fail/dangling_pointers/wild_pointer_deref.rs diff --git a/tests/compile-fail/dangling_pointers/wild_pointer_deref.stderr b/tests/fail/dangling_pointers/wild_pointer_deref.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/wild_pointer_deref.stderr rename to tests/fail/dangling_pointers/wild_pointer_deref.stderr diff --git a/tests/compile-fail/data_race/alloc_read_race.rs b/tests/fail/data_race/alloc_read_race.rs similarity index 100% rename from tests/compile-fail/data_race/alloc_read_race.rs rename to tests/fail/data_race/alloc_read_race.rs diff --git a/tests/compile-fail/data_race/alloc_read_race.stderr b/tests/fail/data_race/alloc_read_race.stderr similarity index 100% rename from tests/compile-fail/data_race/alloc_read_race.stderr rename to tests/fail/data_race/alloc_read_race.stderr diff --git a/tests/compile-fail/data_race/alloc_write_race.rs b/tests/fail/data_race/alloc_write_race.rs similarity index 100% rename from tests/compile-fail/data_race/alloc_write_race.rs rename to tests/fail/data_race/alloc_write_race.rs diff --git a/tests/compile-fail/data_race/alloc_write_race.stderr b/tests/fail/data_race/alloc_write_race.stderr similarity index 100% rename from tests/compile-fail/data_race/alloc_write_race.stderr rename to tests/fail/data_race/alloc_write_race.stderr diff --git a/tests/compile-fail/data_race/atomic_read_na_write_race1.rs b/tests/fail/data_race/atomic_read_na_write_race1.rs similarity index 100% rename from tests/compile-fail/data_race/atomic_read_na_write_race1.rs rename to tests/fail/data_race/atomic_read_na_write_race1.rs diff --git a/tests/compile-fail/data_race/atomic_read_na_write_race1.stderr b/tests/fail/data_race/atomic_read_na_write_race1.stderr similarity index 100% rename from tests/compile-fail/data_race/atomic_read_na_write_race1.stderr rename to tests/fail/data_race/atomic_read_na_write_race1.stderr diff --git a/tests/compile-fail/data_race/atomic_read_na_write_race2.rs b/tests/fail/data_race/atomic_read_na_write_race2.rs similarity index 100% rename from tests/compile-fail/data_race/atomic_read_na_write_race2.rs rename to tests/fail/data_race/atomic_read_na_write_race2.rs diff --git a/tests/compile-fail/data_race/atomic_read_na_write_race2.stderr b/tests/fail/data_race/atomic_read_na_write_race2.stderr similarity index 100% rename from tests/compile-fail/data_race/atomic_read_na_write_race2.stderr rename to tests/fail/data_race/atomic_read_na_write_race2.stderr diff --git a/tests/compile-fail/data_race/atomic_write_na_read_race1.rs b/tests/fail/data_race/atomic_write_na_read_race1.rs similarity index 100% rename from tests/compile-fail/data_race/atomic_write_na_read_race1.rs rename to tests/fail/data_race/atomic_write_na_read_race1.rs diff --git a/tests/compile-fail/data_race/atomic_write_na_read_race1.stderr b/tests/fail/data_race/atomic_write_na_read_race1.stderr similarity index 100% rename from tests/compile-fail/data_race/atomic_write_na_read_race1.stderr rename to tests/fail/data_race/atomic_write_na_read_race1.stderr diff --git a/tests/compile-fail/data_race/atomic_write_na_read_race2.rs b/tests/fail/data_race/atomic_write_na_read_race2.rs similarity index 100% rename from tests/compile-fail/data_race/atomic_write_na_read_race2.rs rename to tests/fail/data_race/atomic_write_na_read_race2.rs diff --git a/tests/compile-fail/data_race/atomic_write_na_read_race2.stderr b/tests/fail/data_race/atomic_write_na_read_race2.stderr similarity index 100% rename from tests/compile-fail/data_race/atomic_write_na_read_race2.stderr rename to tests/fail/data_race/atomic_write_na_read_race2.stderr diff --git a/tests/compile-fail/data_race/atomic_write_na_write_race1.rs b/tests/fail/data_race/atomic_write_na_write_race1.rs similarity index 100% rename from tests/compile-fail/data_race/atomic_write_na_write_race1.rs rename to tests/fail/data_race/atomic_write_na_write_race1.rs diff --git a/tests/compile-fail/data_race/atomic_write_na_write_race1.stderr b/tests/fail/data_race/atomic_write_na_write_race1.stderr similarity index 100% rename from tests/compile-fail/data_race/atomic_write_na_write_race1.stderr rename to tests/fail/data_race/atomic_write_na_write_race1.stderr diff --git a/tests/compile-fail/data_race/atomic_write_na_write_race2.rs b/tests/fail/data_race/atomic_write_na_write_race2.rs similarity index 100% rename from tests/compile-fail/data_race/atomic_write_na_write_race2.rs rename to tests/fail/data_race/atomic_write_na_write_race2.rs diff --git a/tests/compile-fail/data_race/atomic_write_na_write_race2.stderr b/tests/fail/data_race/atomic_write_na_write_race2.stderr similarity index 100% rename from tests/compile-fail/data_race/atomic_write_na_write_race2.stderr rename to tests/fail/data_race/atomic_write_na_write_race2.stderr diff --git a/tests/compile-fail/data_race/dangling_thread_async_race.rs b/tests/fail/data_race/dangling_thread_async_race.rs similarity index 100% rename from tests/compile-fail/data_race/dangling_thread_async_race.rs rename to tests/fail/data_race/dangling_thread_async_race.rs diff --git a/tests/compile-fail/data_race/dangling_thread_async_race.stderr b/tests/fail/data_race/dangling_thread_async_race.stderr similarity index 100% rename from tests/compile-fail/data_race/dangling_thread_async_race.stderr rename to tests/fail/data_race/dangling_thread_async_race.stderr diff --git a/tests/compile-fail/data_race/dangling_thread_race.rs b/tests/fail/data_race/dangling_thread_race.rs similarity index 100% rename from tests/compile-fail/data_race/dangling_thread_race.rs rename to tests/fail/data_race/dangling_thread_race.rs diff --git a/tests/compile-fail/data_race/dangling_thread_race.stderr b/tests/fail/data_race/dangling_thread_race.stderr similarity index 100% rename from tests/compile-fail/data_race/dangling_thread_race.stderr rename to tests/fail/data_race/dangling_thread_race.stderr diff --git a/tests/compile-fail/data_race/dealloc_read_race1.rs b/tests/fail/data_race/dealloc_read_race1.rs similarity index 100% rename from tests/compile-fail/data_race/dealloc_read_race1.rs rename to tests/fail/data_race/dealloc_read_race1.rs diff --git a/tests/compile-fail/data_race/dealloc_read_race1.stderr b/tests/fail/data_race/dealloc_read_race1.stderr similarity index 100% rename from tests/compile-fail/data_race/dealloc_read_race1.stderr rename to tests/fail/data_race/dealloc_read_race1.stderr diff --git a/tests/compile-fail/data_race/dealloc_read_race2.rs b/tests/fail/data_race/dealloc_read_race2.rs similarity index 100% rename from tests/compile-fail/data_race/dealloc_read_race2.rs rename to tests/fail/data_race/dealloc_read_race2.rs diff --git a/tests/compile-fail/data_race/dealloc_read_race2.stderr b/tests/fail/data_race/dealloc_read_race2.stderr similarity index 100% rename from tests/compile-fail/data_race/dealloc_read_race2.stderr rename to tests/fail/data_race/dealloc_read_race2.stderr diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack.rs b/tests/fail/data_race/dealloc_read_race_stack.rs similarity index 100% rename from tests/compile-fail/data_race/dealloc_read_race_stack.rs rename to tests/fail/data_race/dealloc_read_race_stack.rs diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack.stderr b/tests/fail/data_race/dealloc_read_race_stack.stderr similarity index 100% rename from tests/compile-fail/data_race/dealloc_read_race_stack.stderr rename to tests/fail/data_race/dealloc_read_race_stack.stderr diff --git a/tests/compile-fail/data_race/dealloc_write_race1.rs b/tests/fail/data_race/dealloc_write_race1.rs similarity index 100% rename from tests/compile-fail/data_race/dealloc_write_race1.rs rename to tests/fail/data_race/dealloc_write_race1.rs diff --git a/tests/compile-fail/data_race/dealloc_write_race1.stderr b/tests/fail/data_race/dealloc_write_race1.stderr similarity index 100% rename from tests/compile-fail/data_race/dealloc_write_race1.stderr rename to tests/fail/data_race/dealloc_write_race1.stderr diff --git a/tests/compile-fail/data_race/dealloc_write_race2.rs b/tests/fail/data_race/dealloc_write_race2.rs similarity index 100% rename from tests/compile-fail/data_race/dealloc_write_race2.rs rename to tests/fail/data_race/dealloc_write_race2.rs diff --git a/tests/compile-fail/data_race/dealloc_write_race2.stderr b/tests/fail/data_race/dealloc_write_race2.stderr similarity index 100% rename from tests/compile-fail/data_race/dealloc_write_race2.stderr rename to tests/fail/data_race/dealloc_write_race2.stderr diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack.rs b/tests/fail/data_race/dealloc_write_race_stack.rs similarity index 100% rename from tests/compile-fail/data_race/dealloc_write_race_stack.rs rename to tests/fail/data_race/dealloc_write_race_stack.rs diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack.stderr b/tests/fail/data_race/dealloc_write_race_stack.stderr similarity index 100% rename from tests/compile-fail/data_race/dealloc_write_race_stack.stderr rename to tests/fail/data_race/dealloc_write_race_stack.stderr diff --git a/tests/compile-fail/data_race/enable_after_join_to_main.rs b/tests/fail/data_race/enable_after_join_to_main.rs similarity index 100% rename from tests/compile-fail/data_race/enable_after_join_to_main.rs rename to tests/fail/data_race/enable_after_join_to_main.rs diff --git a/tests/compile-fail/data_race/enable_after_join_to_main.stderr b/tests/fail/data_race/enable_after_join_to_main.stderr similarity index 100% rename from tests/compile-fail/data_race/enable_after_join_to_main.stderr rename to tests/fail/data_race/enable_after_join_to_main.stderr diff --git a/tests/compile-fail/data_race/read_write_race.rs b/tests/fail/data_race/read_write_race.rs similarity index 100% rename from tests/compile-fail/data_race/read_write_race.rs rename to tests/fail/data_race/read_write_race.rs diff --git a/tests/compile-fail/data_race/read_write_race.stderr b/tests/fail/data_race/read_write_race.stderr similarity index 100% rename from tests/compile-fail/data_race/read_write_race.stderr rename to tests/fail/data_race/read_write_race.stderr diff --git a/tests/compile-fail/data_race/read_write_race_stack.rs b/tests/fail/data_race/read_write_race_stack.rs similarity index 100% rename from tests/compile-fail/data_race/read_write_race_stack.rs rename to tests/fail/data_race/read_write_race_stack.rs diff --git a/tests/compile-fail/data_race/read_write_race_stack.stderr b/tests/fail/data_race/read_write_race_stack.stderr similarity index 100% rename from tests/compile-fail/data_race/read_write_race_stack.stderr rename to tests/fail/data_race/read_write_race_stack.stderr diff --git a/tests/compile-fail/data_race/relax_acquire_race.rs b/tests/fail/data_race/relax_acquire_race.rs similarity index 100% rename from tests/compile-fail/data_race/relax_acquire_race.rs rename to tests/fail/data_race/relax_acquire_race.rs diff --git a/tests/compile-fail/data_race/relax_acquire_race.stderr b/tests/fail/data_race/relax_acquire_race.stderr similarity index 100% rename from tests/compile-fail/data_race/relax_acquire_race.stderr rename to tests/fail/data_race/relax_acquire_race.stderr diff --git a/tests/compile-fail/data_race/release_seq_race.rs b/tests/fail/data_race/release_seq_race.rs similarity index 100% rename from tests/compile-fail/data_race/release_seq_race.rs rename to tests/fail/data_race/release_seq_race.rs diff --git a/tests/compile-fail/data_race/release_seq_race.stderr b/tests/fail/data_race/release_seq_race.stderr similarity index 100% rename from tests/compile-fail/data_race/release_seq_race.stderr rename to tests/fail/data_race/release_seq_race.stderr diff --git a/tests/compile-fail/data_race/release_seq_race_same_thread.rs b/tests/fail/data_race/release_seq_race_same_thread.rs similarity index 100% rename from tests/compile-fail/data_race/release_seq_race_same_thread.rs rename to tests/fail/data_race/release_seq_race_same_thread.rs diff --git a/tests/compile-fail/data_race/release_seq_race_same_thread.stderr b/tests/fail/data_race/release_seq_race_same_thread.stderr similarity index 100% rename from tests/compile-fail/data_race/release_seq_race_same_thread.stderr rename to tests/fail/data_race/release_seq_race_same_thread.stderr diff --git a/tests/compile-fail/data_race/rmw_race.rs b/tests/fail/data_race/rmw_race.rs similarity index 100% rename from tests/compile-fail/data_race/rmw_race.rs rename to tests/fail/data_race/rmw_race.rs diff --git a/tests/compile-fail/data_race/rmw_race.stderr b/tests/fail/data_race/rmw_race.stderr similarity index 100% rename from tests/compile-fail/data_race/rmw_race.stderr rename to tests/fail/data_race/rmw_race.stderr diff --git a/tests/compile-fail/data_race/write_write_race.rs b/tests/fail/data_race/write_write_race.rs similarity index 100% rename from tests/compile-fail/data_race/write_write_race.rs rename to tests/fail/data_race/write_write_race.rs diff --git a/tests/compile-fail/data_race/write_write_race.stderr b/tests/fail/data_race/write_write_race.stderr similarity index 100% rename from tests/compile-fail/data_race/write_write_race.stderr rename to tests/fail/data_race/write_write_race.stderr diff --git a/tests/compile-fail/data_race/write_write_race_stack.rs b/tests/fail/data_race/write_write_race_stack.rs similarity index 100% rename from tests/compile-fail/data_race/write_write_race_stack.rs rename to tests/fail/data_race/write_write_race_stack.rs diff --git a/tests/compile-fail/data_race/write_write_race_stack.stderr b/tests/fail/data_race/write_write_race_stack.stderr similarity index 100% rename from tests/compile-fail/data_race/write_write_race_stack.stderr rename to tests/fail/data_race/write_write_race_stack.stderr diff --git a/tests/compile-fail/environ-gets-deallocated.rs b/tests/fail/environ-gets-deallocated.rs similarity index 100% rename from tests/compile-fail/environ-gets-deallocated.rs rename to tests/fail/environ-gets-deallocated.rs diff --git a/tests/compile-fail/environ-gets-deallocated.stderr b/tests/fail/environ-gets-deallocated.stderr similarity index 100% rename from tests/compile-fail/environ-gets-deallocated.stderr rename to tests/fail/environ-gets-deallocated.stderr diff --git a/tests/compile-fail/erroneous_const.rs b/tests/fail/erroneous_const.rs similarity index 100% rename from tests/compile-fail/erroneous_const.rs rename to tests/fail/erroneous_const.rs diff --git a/tests/compile-fail/erroneous_const.stderr b/tests/fail/erroneous_const.stderr similarity index 100% rename from tests/compile-fail/erroneous_const.stderr rename to tests/fail/erroneous_const.stderr diff --git a/tests/compile-fail/erroneous_const2.rs b/tests/fail/erroneous_const2.rs similarity index 100% rename from tests/compile-fail/erroneous_const2.rs rename to tests/fail/erroneous_const2.rs diff --git a/tests/compile-fail/erroneous_const2.stderr b/tests/fail/erroneous_const2.stderr similarity index 100% rename from tests/compile-fail/erroneous_const2.stderr rename to tests/fail/erroneous_const2.stderr diff --git a/tests/compile-fail/extern_static.rs b/tests/fail/extern_static.rs similarity index 100% rename from tests/compile-fail/extern_static.rs rename to tests/fail/extern_static.rs diff --git a/tests/compile-fail/extern_static.stderr b/tests/fail/extern_static.stderr similarity index 100% rename from tests/compile-fail/extern_static.stderr rename to tests/fail/extern_static.stderr diff --git a/tests/compile-fail/fast_math_both.rs b/tests/fail/fast_math_both.rs similarity index 100% rename from tests/compile-fail/fast_math_both.rs rename to tests/fail/fast_math_both.rs diff --git a/tests/compile-fail/fast_math_both.stderr b/tests/fail/fast_math_both.stderr similarity index 100% rename from tests/compile-fail/fast_math_both.stderr rename to tests/fail/fast_math_both.stderr diff --git a/tests/compile-fail/fast_math_first.rs b/tests/fail/fast_math_first.rs similarity index 100% rename from tests/compile-fail/fast_math_first.rs rename to tests/fail/fast_math_first.rs diff --git a/tests/compile-fail/fast_math_first.stderr b/tests/fail/fast_math_first.stderr similarity index 100% rename from tests/compile-fail/fast_math_first.stderr rename to tests/fail/fast_math_first.stderr diff --git a/tests/compile-fail/fast_math_second.rs b/tests/fail/fast_math_second.rs similarity index 100% rename from tests/compile-fail/fast_math_second.rs rename to tests/fail/fast_math_second.rs diff --git a/tests/compile-fail/fast_math_second.stderr b/tests/fail/fast_math_second.stderr similarity index 100% rename from tests/compile-fail/fast_math_second.stderr rename to tests/fail/fast_math_second.stderr diff --git a/tests/compile-fail/fs/close_stdout.rs b/tests/fail/fs/close_stdout.rs similarity index 100% rename from tests/compile-fail/fs/close_stdout.rs rename to tests/fail/fs/close_stdout.rs diff --git a/tests/compile-fail/fs/close_stdout.stderr b/tests/fail/fs/close_stdout.stderr similarity index 100% rename from tests/compile-fail/fs/close_stdout.stderr rename to tests/fail/fs/close_stdout.stderr diff --git a/tests/compile-fail/fs/isolated_file.rs b/tests/fail/fs/isolated_file.rs similarity index 100% rename from tests/compile-fail/fs/isolated_file.rs rename to tests/fail/fs/isolated_file.rs diff --git a/tests/compile-fail/fs/isolated_file.stderr b/tests/fail/fs/isolated_file.stderr similarity index 100% rename from tests/compile-fail/fs/isolated_file.stderr rename to tests/fail/fs/isolated_file.stderr diff --git a/tests/compile-fail/fs/isolated_stdin.rs b/tests/fail/fs/isolated_stdin.rs similarity index 100% rename from tests/compile-fail/fs/isolated_stdin.rs rename to tests/fail/fs/isolated_stdin.rs diff --git a/tests/compile-fail/fs/isolated_stdin.stderr b/tests/fail/fs/isolated_stdin.stderr similarity index 100% rename from tests/compile-fail/fs/isolated_stdin.stderr rename to tests/fail/fs/isolated_stdin.stderr diff --git a/tests/compile-fail/fs/read_from_stdout.rs b/tests/fail/fs/read_from_stdout.rs similarity index 100% rename from tests/compile-fail/fs/read_from_stdout.rs rename to tests/fail/fs/read_from_stdout.rs diff --git a/tests/compile-fail/fs/read_from_stdout.stderr b/tests/fail/fs/read_from_stdout.stderr similarity index 100% rename from tests/compile-fail/fs/read_from_stdout.stderr rename to tests/fail/fs/read_from_stdout.stderr diff --git a/tests/compile-fail/fs/unix_open_missing_required_mode.rs b/tests/fail/fs/unix_open_missing_required_mode.rs similarity index 100% rename from tests/compile-fail/fs/unix_open_missing_required_mode.rs rename to tests/fail/fs/unix_open_missing_required_mode.rs diff --git a/tests/compile-fail/fs/unix_open_missing_required_mode.stderr b/tests/fail/fs/unix_open_missing_required_mode.stderr similarity index 100% rename from tests/compile-fail/fs/unix_open_missing_required_mode.stderr rename to tests/fail/fs/unix_open_missing_required_mode.stderr diff --git a/tests/compile-fail/fs/unix_open_too_many_args.stderr b/tests/fail/fs/unix_open_too_many_args.stderr similarity index 100% rename from tests/compile-fail/fs/unix_open_too_many_args.stderr rename to tests/fail/fs/unix_open_too_many_args.stderr diff --git a/tests/compile-fail/fs/write_to_stdin.rs b/tests/fail/fs/write_to_stdin.rs similarity index 100% rename from tests/compile-fail/fs/write_to_stdin.rs rename to tests/fail/fs/write_to_stdin.rs diff --git a/tests/compile-fail/fs/write_to_stdin.stderr b/tests/fail/fs/write_to_stdin.stderr similarity index 100% rename from tests/compile-fail/fs/write_to_stdin.stderr rename to tests/fail/fs/write_to_stdin.stderr diff --git a/tests/compile-fail/function_calls/check_arg_abi.rs b/tests/fail/function_calls/check_arg_abi.rs similarity index 100% rename from tests/compile-fail/function_calls/check_arg_abi.rs rename to tests/fail/function_calls/check_arg_abi.rs diff --git a/tests/compile-fail/function_calls/check_arg_abi.stderr b/tests/fail/function_calls/check_arg_abi.stderr similarity index 100% rename from tests/compile-fail/function_calls/check_arg_abi.stderr rename to tests/fail/function_calls/check_arg_abi.stderr diff --git a/tests/compile-fail/function_calls/check_arg_count_abort.rs b/tests/fail/function_calls/check_arg_count_abort.rs similarity index 100% rename from tests/compile-fail/function_calls/check_arg_count_abort.rs rename to tests/fail/function_calls/check_arg_count_abort.rs diff --git a/tests/compile-fail/function_calls/check_arg_count_abort.stderr b/tests/fail/function_calls/check_arg_count_abort.stderr similarity index 100% rename from tests/compile-fail/function_calls/check_arg_count_abort.stderr rename to tests/fail/function_calls/check_arg_count_abort.stderr diff --git a/tests/compile-fail/function_calls/check_arg_count_too_few_args.rs b/tests/fail/function_calls/check_arg_count_too_few_args.rs similarity index 100% rename from tests/compile-fail/function_calls/check_arg_count_too_few_args.rs rename to tests/fail/function_calls/check_arg_count_too_few_args.rs diff --git a/tests/compile-fail/function_calls/check_arg_count_too_few_args.stderr b/tests/fail/function_calls/check_arg_count_too_few_args.stderr similarity index 100% rename from tests/compile-fail/function_calls/check_arg_count_too_few_args.stderr rename to tests/fail/function_calls/check_arg_count_too_few_args.stderr diff --git a/tests/compile-fail/function_calls/check_arg_count_too_many_args.rs b/tests/fail/function_calls/check_arg_count_too_many_args.rs similarity index 100% rename from tests/compile-fail/function_calls/check_arg_count_too_many_args.rs rename to tests/fail/function_calls/check_arg_count_too_many_args.rs diff --git a/tests/compile-fail/function_calls/check_arg_count_too_many_args.stderr b/tests/fail/function_calls/check_arg_count_too_many_args.stderr similarity index 100% rename from tests/compile-fail/function_calls/check_arg_count_too_many_args.stderr rename to tests/fail/function_calls/check_arg_count_too_many_args.stderr diff --git a/tests/compile-fail/function_calls/check_callback_abi.rs b/tests/fail/function_calls/check_callback_abi.rs similarity index 100% rename from tests/compile-fail/function_calls/check_callback_abi.rs rename to tests/fail/function_calls/check_callback_abi.rs diff --git a/tests/compile-fail/function_calls/check_callback_abi.stderr b/tests/fail/function_calls/check_callback_abi.stderr similarity index 100% rename from tests/compile-fail/function_calls/check_callback_abi.stderr rename to tests/fail/function_calls/check_callback_abi.stderr diff --git a/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.cache.stderr b/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_abi_mismatch.cache.stderr rename to tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr diff --git a/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr b/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr rename to tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr diff --git a/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr b/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr rename to tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr diff --git a/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.rs b/tests/fail/function_calls/exported_symbol_abi_mismatch.rs similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_abi_mismatch.rs rename to tests/fail/function_calls/exported_symbol_abi_mismatch.rs diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind1.rs b/tests/fail/function_calls/exported_symbol_bad_unwind1.rs similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_bad_unwind1.rs rename to tests/fail/function_calls/exported_symbol_bad_unwind1.rs diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind1.stderr b/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_bad_unwind1.stderr rename to tests/fail/function_calls/exported_symbol_bad_unwind1.stderr diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.both.stderr b/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_bad_unwind2.both.stderr rename to tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.definition.stderr b/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_bad_unwind2.definition.stderr rename to tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr b/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr rename to tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.rs b/tests/fail/function_calls/exported_symbol_bad_unwind2.rs similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_bad_unwind2.rs rename to tests/fail/function_calls/exported_symbol_bad_unwind2.rs diff --git a/tests/compile-fail/function_calls/exported_symbol_clashing.rs b/tests/fail/function_calls/exported_symbol_clashing.rs similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_clashing.rs rename to tests/fail/function_calls/exported_symbol_clashing.rs diff --git a/tests/compile-fail/function_calls/exported_symbol_clashing.stderr b/tests/fail/function_calls/exported_symbol_clashing.stderr similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_clashing.stderr rename to tests/fail/function_calls/exported_symbol_clashing.stderr diff --git a/tests/compile-fail/function_calls/exported_symbol_shim_clashing.rs b/tests/fail/function_calls/exported_symbol_shim_clashing.rs similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_shim_clashing.rs rename to tests/fail/function_calls/exported_symbol_shim_clashing.rs diff --git a/tests/compile-fail/function_calls/exported_symbol_shim_clashing.stderr b/tests/fail/function_calls/exported_symbol_shim_clashing.stderr similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_shim_clashing.stderr rename to tests/fail/function_calls/exported_symbol_shim_clashing.stderr diff --git a/tests/compile-fail/function_calls/exported_symbol_wrong_arguments.rs b/tests/fail/function_calls/exported_symbol_wrong_arguments.rs similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_wrong_arguments.rs rename to tests/fail/function_calls/exported_symbol_wrong_arguments.rs diff --git a/tests/compile-fail/function_calls/exported_symbol_wrong_arguments.stderr b/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_wrong_arguments.stderr rename to tests/fail/function_calls/exported_symbol_wrong_arguments.stderr diff --git a/tests/compile-fail/function_calls/exported_symbol_wrong_type.rs b/tests/fail/function_calls/exported_symbol_wrong_type.rs similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_wrong_type.rs rename to tests/fail/function_calls/exported_symbol_wrong_type.rs diff --git a/tests/compile-fail/function_calls/exported_symbol_wrong_type.stderr b/tests/fail/function_calls/exported_symbol_wrong_type.stderr similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_wrong_type.stderr rename to tests/fail/function_calls/exported_symbol_wrong_type.stderr diff --git a/tests/compile-fail/function_pointers/cast_box_int_to_fn_ptr.rs b/tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs similarity index 100% rename from tests/compile-fail/function_pointers/cast_box_int_to_fn_ptr.rs rename to tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs diff --git a/tests/compile-fail/function_pointers/cast_box_int_to_fn_ptr.stderr b/tests/fail/function_pointers/cast_box_int_to_fn_ptr.stderr similarity index 100% rename from tests/compile-fail/function_pointers/cast_box_int_to_fn_ptr.stderr rename to tests/fail/function_pointers/cast_box_int_to_fn_ptr.stderr diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr1.rs b/tests/fail/function_pointers/cast_fn_ptr1.rs similarity index 100% rename from tests/compile-fail/function_pointers/cast_fn_ptr1.rs rename to tests/fail/function_pointers/cast_fn_ptr1.rs diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr1.stderr b/tests/fail/function_pointers/cast_fn_ptr1.stderr similarity index 100% rename from tests/compile-fail/function_pointers/cast_fn_ptr1.stderr rename to tests/fail/function_pointers/cast_fn_ptr1.stderr diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr2.rs b/tests/fail/function_pointers/cast_fn_ptr2.rs similarity index 100% rename from tests/compile-fail/function_pointers/cast_fn_ptr2.rs rename to tests/fail/function_pointers/cast_fn_ptr2.rs diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr2.stderr b/tests/fail/function_pointers/cast_fn_ptr2.stderr similarity index 100% rename from tests/compile-fail/function_pointers/cast_fn_ptr2.stderr rename to tests/fail/function_pointers/cast_fn_ptr2.stderr diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr3.rs b/tests/fail/function_pointers/cast_fn_ptr3.rs similarity index 100% rename from tests/compile-fail/function_pointers/cast_fn_ptr3.rs rename to tests/fail/function_pointers/cast_fn_ptr3.rs diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr3.stderr b/tests/fail/function_pointers/cast_fn_ptr3.stderr similarity index 100% rename from tests/compile-fail/function_pointers/cast_fn_ptr3.stderr rename to tests/fail/function_pointers/cast_fn_ptr3.stderr diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr4.rs b/tests/fail/function_pointers/cast_fn_ptr4.rs similarity index 100% rename from tests/compile-fail/function_pointers/cast_fn_ptr4.rs rename to tests/fail/function_pointers/cast_fn_ptr4.rs diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr4.stderr b/tests/fail/function_pointers/cast_fn_ptr4.stderr similarity index 100% rename from tests/compile-fail/function_pointers/cast_fn_ptr4.stderr rename to tests/fail/function_pointers/cast_fn_ptr4.stderr diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr5.rs b/tests/fail/function_pointers/cast_fn_ptr5.rs similarity index 100% rename from tests/compile-fail/function_pointers/cast_fn_ptr5.rs rename to tests/fail/function_pointers/cast_fn_ptr5.rs diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr5.stderr b/tests/fail/function_pointers/cast_fn_ptr5.stderr similarity index 100% rename from tests/compile-fail/function_pointers/cast_fn_ptr5.stderr rename to tests/fail/function_pointers/cast_fn_ptr5.stderr diff --git a/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs b/tests/fail/function_pointers/cast_int_to_fn_ptr.rs similarity index 100% rename from tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs rename to tests/fail/function_pointers/cast_int_to_fn_ptr.rs diff --git a/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.stderr b/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr similarity index 100% rename from tests/compile-fail/function_pointers/cast_int_to_fn_ptr.stderr rename to tests/fail/function_pointers/cast_int_to_fn_ptr.stderr diff --git a/tests/compile-fail/function_pointers/deref_fn_ptr.rs b/tests/fail/function_pointers/deref_fn_ptr.rs similarity index 100% rename from tests/compile-fail/function_pointers/deref_fn_ptr.rs rename to tests/fail/function_pointers/deref_fn_ptr.rs diff --git a/tests/compile-fail/function_pointers/deref_fn_ptr.stderr b/tests/fail/function_pointers/deref_fn_ptr.stderr similarity index 100% rename from tests/compile-fail/function_pointers/deref_fn_ptr.stderr rename to tests/fail/function_pointers/deref_fn_ptr.stderr diff --git a/tests/compile-fail/function_pointers/execute_memory.rs b/tests/fail/function_pointers/execute_memory.rs similarity index 100% rename from tests/compile-fail/function_pointers/execute_memory.rs rename to tests/fail/function_pointers/execute_memory.rs diff --git a/tests/compile-fail/function_pointers/execute_memory.stderr b/tests/fail/function_pointers/execute_memory.stderr similarity index 100% rename from tests/compile-fail/function_pointers/execute_memory.stderr rename to tests/fail/function_pointers/execute_memory.stderr diff --git a/tests/compile-fail/function_pointers/fn_ptr_offset.rs b/tests/fail/function_pointers/fn_ptr_offset.rs similarity index 100% rename from tests/compile-fail/function_pointers/fn_ptr_offset.rs rename to tests/fail/function_pointers/fn_ptr_offset.rs diff --git a/tests/compile-fail/function_pointers/fn_ptr_offset.stderr b/tests/fail/function_pointers/fn_ptr_offset.stderr similarity index 100% rename from tests/compile-fail/function_pointers/fn_ptr_offset.stderr rename to tests/fail/function_pointers/fn_ptr_offset.stderr diff --git a/tests/compile-fail/generator-pinned-moved.rs b/tests/fail/generator-pinned-moved.rs similarity index 100% rename from tests/compile-fail/generator-pinned-moved.rs rename to tests/fail/generator-pinned-moved.rs diff --git a/tests/compile-fail/generator-pinned-moved.stderr b/tests/fail/generator-pinned-moved.stderr similarity index 100% rename from tests/compile-fail/generator-pinned-moved.stderr rename to tests/fail/generator-pinned-moved.stderr diff --git a/tests/compile-fail/intrinsics/assume.rs b/tests/fail/intrinsics/assume.rs similarity index 100% rename from tests/compile-fail/intrinsics/assume.rs rename to tests/fail/intrinsics/assume.rs diff --git a/tests/compile-fail/intrinsics/assume.stderr b/tests/fail/intrinsics/assume.stderr similarity index 100% rename from tests/compile-fail/intrinsics/assume.stderr rename to tests/fail/intrinsics/assume.stderr diff --git a/tests/compile-fail/intrinsics/copy_null.rs b/tests/fail/intrinsics/copy_null.rs similarity index 100% rename from tests/compile-fail/intrinsics/copy_null.rs rename to tests/fail/intrinsics/copy_null.rs diff --git a/tests/compile-fail/intrinsics/copy_null.stderr b/tests/fail/intrinsics/copy_null.stderr similarity index 100% rename from tests/compile-fail/intrinsics/copy_null.stderr rename to tests/fail/intrinsics/copy_null.stderr diff --git a/tests/compile-fail/intrinsics/copy_overflow.rs b/tests/fail/intrinsics/copy_overflow.rs similarity index 100% rename from tests/compile-fail/intrinsics/copy_overflow.rs rename to tests/fail/intrinsics/copy_overflow.rs diff --git a/tests/compile-fail/intrinsics/copy_overflow.stderr b/tests/fail/intrinsics/copy_overflow.stderr similarity index 100% rename from tests/compile-fail/intrinsics/copy_overflow.stderr rename to tests/fail/intrinsics/copy_overflow.stderr diff --git a/tests/compile-fail/intrinsics/copy_overlapping.rs b/tests/fail/intrinsics/copy_overlapping.rs similarity index 100% rename from tests/compile-fail/intrinsics/copy_overlapping.rs rename to tests/fail/intrinsics/copy_overlapping.rs diff --git a/tests/compile-fail/intrinsics/copy_overlapping.stderr b/tests/fail/intrinsics/copy_overlapping.stderr similarity index 100% rename from tests/compile-fail/intrinsics/copy_overlapping.stderr rename to tests/fail/intrinsics/copy_overlapping.stderr diff --git a/tests/compile-fail/intrinsics/copy_unaligned.rs b/tests/fail/intrinsics/copy_unaligned.rs similarity index 100% rename from tests/compile-fail/intrinsics/copy_unaligned.rs rename to tests/fail/intrinsics/copy_unaligned.rs diff --git a/tests/compile-fail/intrinsics/copy_unaligned.stderr b/tests/fail/intrinsics/copy_unaligned.stderr similarity index 100% rename from tests/compile-fail/intrinsics/copy_unaligned.stderr rename to tests/fail/intrinsics/copy_unaligned.stderr diff --git a/tests/compile-fail/intrinsics/ctlz_nonzero.rs b/tests/fail/intrinsics/ctlz_nonzero.rs similarity index 100% rename from tests/compile-fail/intrinsics/ctlz_nonzero.rs rename to tests/fail/intrinsics/ctlz_nonzero.rs diff --git a/tests/compile-fail/intrinsics/ctlz_nonzero.stderr b/tests/fail/intrinsics/ctlz_nonzero.stderr similarity index 100% rename from tests/compile-fail/intrinsics/ctlz_nonzero.stderr rename to tests/fail/intrinsics/ctlz_nonzero.stderr diff --git a/tests/compile-fail/intrinsics/cttz_nonzero.rs b/tests/fail/intrinsics/cttz_nonzero.rs similarity index 100% rename from tests/compile-fail/intrinsics/cttz_nonzero.rs rename to tests/fail/intrinsics/cttz_nonzero.rs diff --git a/tests/compile-fail/intrinsics/cttz_nonzero.stderr b/tests/fail/intrinsics/cttz_nonzero.stderr similarity index 100% rename from tests/compile-fail/intrinsics/cttz_nonzero.stderr rename to tests/fail/intrinsics/cttz_nonzero.stderr diff --git a/tests/compile-fail/intrinsics/div-by-zero.rs b/tests/fail/intrinsics/div-by-zero.rs similarity index 100% rename from tests/compile-fail/intrinsics/div-by-zero.rs rename to tests/fail/intrinsics/div-by-zero.rs diff --git a/tests/compile-fail/intrinsics/div-by-zero.stderr b/tests/fail/intrinsics/div-by-zero.stderr similarity index 100% rename from tests/compile-fail/intrinsics/div-by-zero.stderr rename to tests/fail/intrinsics/div-by-zero.stderr diff --git a/tests/compile-fail/intrinsics/exact_div1.rs b/tests/fail/intrinsics/exact_div1.rs similarity index 100% rename from tests/compile-fail/intrinsics/exact_div1.rs rename to tests/fail/intrinsics/exact_div1.rs diff --git a/tests/compile-fail/intrinsics/exact_div1.stderr b/tests/fail/intrinsics/exact_div1.stderr similarity index 100% rename from tests/compile-fail/intrinsics/exact_div1.stderr rename to tests/fail/intrinsics/exact_div1.stderr diff --git a/tests/compile-fail/intrinsics/exact_div2.rs b/tests/fail/intrinsics/exact_div2.rs similarity index 100% rename from tests/compile-fail/intrinsics/exact_div2.rs rename to tests/fail/intrinsics/exact_div2.rs diff --git a/tests/compile-fail/intrinsics/exact_div2.stderr b/tests/fail/intrinsics/exact_div2.stderr similarity index 100% rename from tests/compile-fail/intrinsics/exact_div2.stderr rename to tests/fail/intrinsics/exact_div2.stderr diff --git a/tests/compile-fail/intrinsics/exact_div3.rs b/tests/fail/intrinsics/exact_div3.rs similarity index 100% rename from tests/compile-fail/intrinsics/exact_div3.rs rename to tests/fail/intrinsics/exact_div3.rs diff --git a/tests/compile-fail/intrinsics/exact_div3.stderr b/tests/fail/intrinsics/exact_div3.stderr similarity index 100% rename from tests/compile-fail/intrinsics/exact_div3.stderr rename to tests/fail/intrinsics/exact_div3.stderr diff --git a/tests/compile-fail/intrinsics/exact_div4.rs b/tests/fail/intrinsics/exact_div4.rs similarity index 100% rename from tests/compile-fail/intrinsics/exact_div4.rs rename to tests/fail/intrinsics/exact_div4.rs diff --git a/tests/compile-fail/intrinsics/exact_div4.stderr b/tests/fail/intrinsics/exact_div4.stderr similarity index 100% rename from tests/compile-fail/intrinsics/exact_div4.stderr rename to tests/fail/intrinsics/exact_div4.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_32_inf1.rs b/tests/fail/intrinsics/float_to_int_32_inf1.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_inf1.rs rename to tests/fail/intrinsics/float_to_int_32_inf1.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_32_inf1.stderr b/tests/fail/intrinsics/float_to_int_32_inf1.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_inf1.stderr rename to tests/fail/intrinsics/float_to_int_32_inf1.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_32_infneg1.rs b/tests/fail/intrinsics/float_to_int_32_infneg1.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_infneg1.rs rename to tests/fail/intrinsics/float_to_int_32_infneg1.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_32_infneg1.stderr b/tests/fail/intrinsics/float_to_int_32_infneg1.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_infneg1.stderr rename to tests/fail/intrinsics/float_to_int_32_infneg1.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_32_nan.rs b/tests/fail/intrinsics/float_to_int_32_nan.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_nan.rs rename to tests/fail/intrinsics/float_to_int_32_nan.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_32_nan.stderr b/tests/fail/intrinsics/float_to_int_32_nan.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_nan.stderr rename to tests/fail/intrinsics/float_to_int_32_nan.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_32_nanneg.rs b/tests/fail/intrinsics/float_to_int_32_nanneg.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_nanneg.rs rename to tests/fail/intrinsics/float_to_int_32_nanneg.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_32_nanneg.stderr b/tests/fail/intrinsics/float_to_int_32_nanneg.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_nanneg.stderr rename to tests/fail/intrinsics/float_to_int_32_nanneg.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_32_neg.rs b/tests/fail/intrinsics/float_to_int_32_neg.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_neg.rs rename to tests/fail/intrinsics/float_to_int_32_neg.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_32_neg.stderr b/tests/fail/intrinsics/float_to_int_32_neg.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_neg.stderr rename to tests/fail/intrinsics/float_to_int_32_neg.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_32_too_big1.rs b/tests/fail/intrinsics/float_to_int_32_too_big1.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_too_big1.rs rename to tests/fail/intrinsics/float_to_int_32_too_big1.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_32_too_big1.stderr b/tests/fail/intrinsics/float_to_int_32_too_big1.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_too_big1.stderr rename to tests/fail/intrinsics/float_to_int_32_too_big1.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_32_too_big2.rs b/tests/fail/intrinsics/float_to_int_32_too_big2.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_too_big2.rs rename to tests/fail/intrinsics/float_to_int_32_too_big2.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_32_too_big2.stderr b/tests/fail/intrinsics/float_to_int_32_too_big2.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_too_big2.stderr rename to tests/fail/intrinsics/float_to_int_32_too_big2.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_32_too_small1.rs b/tests/fail/intrinsics/float_to_int_32_too_small1.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_too_small1.rs rename to tests/fail/intrinsics/float_to_int_32_too_small1.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_32_too_small1.stderr b/tests/fail/intrinsics/float_to_int_32_too_small1.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_too_small1.stderr rename to tests/fail/intrinsics/float_to_int_32_too_small1.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_inf1.rs b/tests/fail/intrinsics/float_to_int_64_inf1.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_inf1.rs rename to tests/fail/intrinsics/float_to_int_64_inf1.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_inf1.stderr b/tests/fail/intrinsics/float_to_int_64_inf1.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_inf1.stderr rename to tests/fail/intrinsics/float_to_int_64_inf1.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_infneg1.rs b/tests/fail/intrinsics/float_to_int_64_infneg1.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_infneg1.rs rename to tests/fail/intrinsics/float_to_int_64_infneg1.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_infneg1.stderr b/tests/fail/intrinsics/float_to_int_64_infneg1.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_infneg1.stderr rename to tests/fail/intrinsics/float_to_int_64_infneg1.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_infneg2.rs b/tests/fail/intrinsics/float_to_int_64_infneg2.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_infneg2.rs rename to tests/fail/intrinsics/float_to_int_64_infneg2.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_infneg2.stderr b/tests/fail/intrinsics/float_to_int_64_infneg2.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_infneg2.stderr rename to tests/fail/intrinsics/float_to_int_64_infneg2.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_nan.rs b/tests/fail/intrinsics/float_to_int_64_nan.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_nan.rs rename to tests/fail/intrinsics/float_to_int_64_nan.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_nan.stderr b/tests/fail/intrinsics/float_to_int_64_nan.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_nan.stderr rename to tests/fail/intrinsics/float_to_int_64_nan.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_neg.rs b/tests/fail/intrinsics/float_to_int_64_neg.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_neg.rs rename to tests/fail/intrinsics/float_to_int_64_neg.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_neg.stderr b/tests/fail/intrinsics/float_to_int_64_neg.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_neg.stderr rename to tests/fail/intrinsics/float_to_int_64_neg.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big1.rs b/tests/fail/intrinsics/float_to_int_64_too_big1.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_big1.rs rename to tests/fail/intrinsics/float_to_int_64_too_big1.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big1.stderr b/tests/fail/intrinsics/float_to_int_64_too_big1.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_big1.stderr rename to tests/fail/intrinsics/float_to_int_64_too_big1.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big2.rs b/tests/fail/intrinsics/float_to_int_64_too_big2.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_big2.rs rename to tests/fail/intrinsics/float_to_int_64_too_big2.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big2.stderr b/tests/fail/intrinsics/float_to_int_64_too_big2.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_big2.stderr rename to tests/fail/intrinsics/float_to_int_64_too_big2.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big3.rs b/tests/fail/intrinsics/float_to_int_64_too_big3.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_big3.rs rename to tests/fail/intrinsics/float_to_int_64_too_big3.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big3.stderr b/tests/fail/intrinsics/float_to_int_64_too_big3.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_big3.stderr rename to tests/fail/intrinsics/float_to_int_64_too_big3.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big4.rs b/tests/fail/intrinsics/float_to_int_64_too_big4.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_big4.rs rename to tests/fail/intrinsics/float_to_int_64_too_big4.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big4.stderr b/tests/fail/intrinsics/float_to_int_64_too_big4.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_big4.stderr rename to tests/fail/intrinsics/float_to_int_64_too_big4.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big5.rs b/tests/fail/intrinsics/float_to_int_64_too_big5.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_big5.rs rename to tests/fail/intrinsics/float_to_int_64_too_big5.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big5.stderr b/tests/fail/intrinsics/float_to_int_64_too_big5.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_big5.stderr rename to tests/fail/intrinsics/float_to_int_64_too_big5.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big6.rs b/tests/fail/intrinsics/float_to_int_64_too_big6.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_big6.rs rename to tests/fail/intrinsics/float_to_int_64_too_big6.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big6.stderr b/tests/fail/intrinsics/float_to_int_64_too_big6.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_big6.stderr rename to tests/fail/intrinsics/float_to_int_64_too_big6.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big7.rs b/tests/fail/intrinsics/float_to_int_64_too_big7.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_big7.rs rename to tests/fail/intrinsics/float_to_int_64_too_big7.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big7.stderr b/tests/fail/intrinsics/float_to_int_64_too_big7.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_big7.stderr rename to tests/fail/intrinsics/float_to_int_64_too_big7.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_small1.rs b/tests/fail/intrinsics/float_to_int_64_too_small1.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_small1.rs rename to tests/fail/intrinsics/float_to_int_64_too_small1.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_small1.stderr b/tests/fail/intrinsics/float_to_int_64_too_small1.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_small1.stderr rename to tests/fail/intrinsics/float_to_int_64_too_small1.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_small2.rs b/tests/fail/intrinsics/float_to_int_64_too_small2.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_small2.rs rename to tests/fail/intrinsics/float_to_int_64_too_small2.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_small2.stderr b/tests/fail/intrinsics/float_to_int_64_too_small2.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_small2.stderr rename to tests/fail/intrinsics/float_to_int_64_too_small2.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_small3.rs b/tests/fail/intrinsics/float_to_int_64_too_small3.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_small3.rs rename to tests/fail/intrinsics/float_to_int_64_too_small3.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_small3.stderr b/tests/fail/intrinsics/float_to_int_64_too_small3.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_small3.stderr rename to tests/fail/intrinsics/float_to_int_64_too_small3.stderr diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_1.rs b/tests/fail/intrinsics/out_of_bounds_ptr_1.rs similarity index 100% rename from tests/compile-fail/intrinsics/out_of_bounds_ptr_1.rs rename to tests/fail/intrinsics/out_of_bounds_ptr_1.rs diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_1.stderr b/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr similarity index 100% rename from tests/compile-fail/intrinsics/out_of_bounds_ptr_1.stderr rename to tests/fail/intrinsics/out_of_bounds_ptr_1.stderr diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_2.rs b/tests/fail/intrinsics/out_of_bounds_ptr_2.rs similarity index 100% rename from tests/compile-fail/intrinsics/out_of_bounds_ptr_2.rs rename to tests/fail/intrinsics/out_of_bounds_ptr_2.rs diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_2.stderr b/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr similarity index 100% rename from tests/compile-fail/intrinsics/out_of_bounds_ptr_2.stderr rename to tests/fail/intrinsics/out_of_bounds_ptr_2.stderr diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_3.rs b/tests/fail/intrinsics/out_of_bounds_ptr_3.rs similarity index 100% rename from tests/compile-fail/intrinsics/out_of_bounds_ptr_3.rs rename to tests/fail/intrinsics/out_of_bounds_ptr_3.rs diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_3.stderr b/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr similarity index 100% rename from tests/compile-fail/intrinsics/out_of_bounds_ptr_3.stderr rename to tests/fail/intrinsics/out_of_bounds_ptr_3.stderr diff --git a/tests/compile-fail/intrinsics/overflowing-unchecked-rsh.rs b/tests/fail/intrinsics/overflowing-unchecked-rsh.rs similarity index 100% rename from tests/compile-fail/intrinsics/overflowing-unchecked-rsh.rs rename to tests/fail/intrinsics/overflowing-unchecked-rsh.rs diff --git a/tests/compile-fail/intrinsics/overflowing-unchecked-rsh.stderr b/tests/fail/intrinsics/overflowing-unchecked-rsh.stderr similarity index 100% rename from tests/compile-fail/intrinsics/overflowing-unchecked-rsh.stderr rename to tests/fail/intrinsics/overflowing-unchecked-rsh.stderr diff --git a/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs b/tests/fail/intrinsics/ptr_offset_0_plus_0.rs similarity index 100% rename from tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs rename to tests/fail/intrinsics/ptr_offset_0_plus_0.rs diff --git a/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.stderr b/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr similarity index 100% rename from tests/compile-fail/intrinsics/ptr_offset_0_plus_0.stderr rename to tests/fail/intrinsics/ptr_offset_0_plus_0.stderr diff --git a/tests/compile-fail/intrinsics/ptr_offset_from_oob.rs b/tests/fail/intrinsics/ptr_offset_from_oob.rs similarity index 100% rename from tests/compile-fail/intrinsics/ptr_offset_from_oob.rs rename to tests/fail/intrinsics/ptr_offset_from_oob.rs diff --git a/tests/compile-fail/intrinsics/ptr_offset_from_oob.stderr b/tests/fail/intrinsics/ptr_offset_from_oob.stderr similarity index 100% rename from tests/compile-fail/intrinsics/ptr_offset_from_oob.stderr rename to tests/fail/intrinsics/ptr_offset_from_oob.stderr diff --git a/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs b/tests/fail/intrinsics/ptr_offset_int_plus_int.rs similarity index 100% rename from tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs rename to tests/fail/intrinsics/ptr_offset_int_plus_int.rs diff --git a/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.stderr b/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr similarity index 100% rename from tests/compile-fail/intrinsics/ptr_offset_int_plus_int.stderr rename to tests/fail/intrinsics/ptr_offset_int_plus_int.stderr diff --git a/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs similarity index 100% rename from tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs rename to tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs diff --git a/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.stderr b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr similarity index 100% rename from tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.stderr rename to tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr diff --git a/tests/compile-fail/intrinsics/ptr_offset_overflow.rs b/tests/fail/intrinsics/ptr_offset_overflow.rs similarity index 100% rename from tests/compile-fail/intrinsics/ptr_offset_overflow.rs rename to tests/fail/intrinsics/ptr_offset_overflow.rs diff --git a/tests/compile-fail/intrinsics/ptr_offset_overflow.stderr b/tests/fail/intrinsics/ptr_offset_overflow.stderr similarity index 100% rename from tests/compile-fail/intrinsics/ptr_offset_overflow.stderr rename to tests/fail/intrinsics/ptr_offset_overflow.stderr diff --git a/tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.rs b/tests/fail/intrinsics/ptr_offset_ptr_plus_0.rs similarity index 100% rename from tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.rs rename to tests/fail/intrinsics/ptr_offset_ptr_plus_0.rs diff --git a/tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.stderr b/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr similarity index 100% rename from tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.stderr rename to tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr diff --git a/tests/compile-fail/intrinsics/rem-by-zero.rs b/tests/fail/intrinsics/rem-by-zero.rs similarity index 100% rename from tests/compile-fail/intrinsics/rem-by-zero.rs rename to tests/fail/intrinsics/rem-by-zero.rs diff --git a/tests/compile-fail/intrinsics/rem-by-zero.stderr b/tests/fail/intrinsics/rem-by-zero.stderr similarity index 100% rename from tests/compile-fail/intrinsics/rem-by-zero.stderr rename to tests/fail/intrinsics/rem-by-zero.stderr diff --git a/tests/compile-fail/intrinsics/simd-div-by-zero.rs b/tests/fail/intrinsics/simd-div-by-zero.rs similarity index 100% rename from tests/compile-fail/intrinsics/simd-div-by-zero.rs rename to tests/fail/intrinsics/simd-div-by-zero.rs diff --git a/tests/compile-fail/intrinsics/simd-div-by-zero.stderr b/tests/fail/intrinsics/simd-div-by-zero.stderr similarity index 100% rename from tests/compile-fail/intrinsics/simd-div-by-zero.stderr rename to tests/fail/intrinsics/simd-div-by-zero.stderr diff --git a/tests/compile-fail/intrinsics/simd-div-overflow.rs b/tests/fail/intrinsics/simd-div-overflow.rs similarity index 100% rename from tests/compile-fail/intrinsics/simd-div-overflow.rs rename to tests/fail/intrinsics/simd-div-overflow.rs diff --git a/tests/compile-fail/intrinsics/simd-div-overflow.stderr b/tests/fail/intrinsics/simd-div-overflow.stderr similarity index 100% rename from tests/compile-fail/intrinsics/simd-div-overflow.stderr rename to tests/fail/intrinsics/simd-div-overflow.stderr diff --git a/tests/compile-fail/intrinsics/simd-float-to-int.rs b/tests/fail/intrinsics/simd-float-to-int.rs similarity index 100% rename from tests/compile-fail/intrinsics/simd-float-to-int.rs rename to tests/fail/intrinsics/simd-float-to-int.rs diff --git a/tests/compile-fail/intrinsics/simd-float-to-int.stderr b/tests/fail/intrinsics/simd-float-to-int.stderr similarity index 100% rename from tests/compile-fail/intrinsics/simd-float-to-int.stderr rename to tests/fail/intrinsics/simd-float-to-int.stderr diff --git a/tests/compile-fail/intrinsics/simd-gather.rs b/tests/fail/intrinsics/simd-gather.rs similarity index 100% rename from tests/compile-fail/intrinsics/simd-gather.rs rename to tests/fail/intrinsics/simd-gather.rs diff --git a/tests/compile-fail/intrinsics/simd-gather.stderr b/tests/fail/intrinsics/simd-gather.stderr similarity index 100% rename from tests/compile-fail/intrinsics/simd-gather.stderr rename to tests/fail/intrinsics/simd-gather.stderr diff --git a/tests/compile-fail/intrinsics/simd-reduce-invalid-bool.rs b/tests/fail/intrinsics/simd-reduce-invalid-bool.rs similarity index 100% rename from tests/compile-fail/intrinsics/simd-reduce-invalid-bool.rs rename to tests/fail/intrinsics/simd-reduce-invalid-bool.rs diff --git a/tests/compile-fail/intrinsics/simd-reduce-invalid-bool.stderr b/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr similarity index 100% rename from tests/compile-fail/intrinsics/simd-reduce-invalid-bool.stderr rename to tests/fail/intrinsics/simd-reduce-invalid-bool.stderr diff --git a/tests/compile-fail/intrinsics/simd-rem-by-zero.rs b/tests/fail/intrinsics/simd-rem-by-zero.rs similarity index 100% rename from tests/compile-fail/intrinsics/simd-rem-by-zero.rs rename to tests/fail/intrinsics/simd-rem-by-zero.rs diff --git a/tests/compile-fail/intrinsics/simd-rem-by-zero.stderr b/tests/fail/intrinsics/simd-rem-by-zero.stderr similarity index 100% rename from tests/compile-fail/intrinsics/simd-rem-by-zero.stderr rename to tests/fail/intrinsics/simd-rem-by-zero.stderr diff --git a/tests/compile-fail/intrinsics/simd-scatter.rs b/tests/fail/intrinsics/simd-scatter.rs similarity index 100% rename from tests/compile-fail/intrinsics/simd-scatter.rs rename to tests/fail/intrinsics/simd-scatter.rs diff --git a/tests/compile-fail/intrinsics/simd-scatter.stderr b/tests/fail/intrinsics/simd-scatter.stderr similarity index 100% rename from tests/compile-fail/intrinsics/simd-scatter.stderr rename to tests/fail/intrinsics/simd-scatter.stderr diff --git a/tests/compile-fail/intrinsics/simd-select-bitmask-invalid.rs b/tests/fail/intrinsics/simd-select-bitmask-invalid.rs similarity index 100% rename from tests/compile-fail/intrinsics/simd-select-bitmask-invalid.rs rename to tests/fail/intrinsics/simd-select-bitmask-invalid.rs diff --git a/tests/compile-fail/intrinsics/simd-select-bitmask-invalid.stderr b/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr similarity index 100% rename from tests/compile-fail/intrinsics/simd-select-bitmask-invalid.stderr rename to tests/fail/intrinsics/simd-select-bitmask-invalid.stderr diff --git a/tests/compile-fail/intrinsics/simd-select-invalid-bool.rs b/tests/fail/intrinsics/simd-select-invalid-bool.rs similarity index 100% rename from tests/compile-fail/intrinsics/simd-select-invalid-bool.rs rename to tests/fail/intrinsics/simd-select-invalid-bool.rs diff --git a/tests/compile-fail/intrinsics/simd-select-invalid-bool.stderr b/tests/fail/intrinsics/simd-select-invalid-bool.stderr similarity index 100% rename from tests/compile-fail/intrinsics/simd-select-invalid-bool.stderr rename to tests/fail/intrinsics/simd-select-invalid-bool.stderr diff --git a/tests/compile-fail/intrinsics/simd-shl-too-far.rs b/tests/fail/intrinsics/simd-shl-too-far.rs similarity index 100% rename from tests/compile-fail/intrinsics/simd-shl-too-far.rs rename to tests/fail/intrinsics/simd-shl-too-far.rs diff --git a/tests/compile-fail/intrinsics/simd-shl-too-far.stderr b/tests/fail/intrinsics/simd-shl-too-far.stderr similarity index 100% rename from tests/compile-fail/intrinsics/simd-shl-too-far.stderr rename to tests/fail/intrinsics/simd-shl-too-far.stderr diff --git a/tests/compile-fail/intrinsics/simd-shr-too-far.rs b/tests/fail/intrinsics/simd-shr-too-far.rs similarity index 100% rename from tests/compile-fail/intrinsics/simd-shr-too-far.rs rename to tests/fail/intrinsics/simd-shr-too-far.rs diff --git a/tests/compile-fail/intrinsics/simd-shr-too-far.stderr b/tests/fail/intrinsics/simd-shr-too-far.stderr similarity index 100% rename from tests/compile-fail/intrinsics/simd-shr-too-far.stderr rename to tests/fail/intrinsics/simd-shr-too-far.stderr diff --git a/tests/compile-fail/intrinsics/unchecked_add1.rs b/tests/fail/intrinsics/unchecked_add1.rs similarity index 100% rename from tests/compile-fail/intrinsics/unchecked_add1.rs rename to tests/fail/intrinsics/unchecked_add1.rs diff --git a/tests/compile-fail/intrinsics/unchecked_add1.stderr b/tests/fail/intrinsics/unchecked_add1.stderr similarity index 100% rename from tests/compile-fail/intrinsics/unchecked_add1.stderr rename to tests/fail/intrinsics/unchecked_add1.stderr diff --git a/tests/compile-fail/intrinsics/unchecked_add2.rs b/tests/fail/intrinsics/unchecked_add2.rs similarity index 100% rename from tests/compile-fail/intrinsics/unchecked_add2.rs rename to tests/fail/intrinsics/unchecked_add2.rs diff --git a/tests/compile-fail/intrinsics/unchecked_add2.stderr b/tests/fail/intrinsics/unchecked_add2.stderr similarity index 100% rename from tests/compile-fail/intrinsics/unchecked_add2.stderr rename to tests/fail/intrinsics/unchecked_add2.stderr diff --git a/tests/compile-fail/intrinsics/unchecked_div1.rs b/tests/fail/intrinsics/unchecked_div1.rs similarity index 100% rename from tests/compile-fail/intrinsics/unchecked_div1.rs rename to tests/fail/intrinsics/unchecked_div1.rs diff --git a/tests/compile-fail/intrinsics/unchecked_div1.stderr b/tests/fail/intrinsics/unchecked_div1.stderr similarity index 100% rename from tests/compile-fail/intrinsics/unchecked_div1.stderr rename to tests/fail/intrinsics/unchecked_div1.stderr diff --git a/tests/compile-fail/intrinsics/unchecked_mul1.rs b/tests/fail/intrinsics/unchecked_mul1.rs similarity index 100% rename from tests/compile-fail/intrinsics/unchecked_mul1.rs rename to tests/fail/intrinsics/unchecked_mul1.rs diff --git a/tests/compile-fail/intrinsics/unchecked_mul1.stderr b/tests/fail/intrinsics/unchecked_mul1.stderr similarity index 100% rename from tests/compile-fail/intrinsics/unchecked_mul1.stderr rename to tests/fail/intrinsics/unchecked_mul1.stderr diff --git a/tests/compile-fail/intrinsics/unchecked_mul2.rs b/tests/fail/intrinsics/unchecked_mul2.rs similarity index 100% rename from tests/compile-fail/intrinsics/unchecked_mul2.rs rename to tests/fail/intrinsics/unchecked_mul2.rs diff --git a/tests/compile-fail/intrinsics/unchecked_mul2.stderr b/tests/fail/intrinsics/unchecked_mul2.stderr similarity index 100% rename from tests/compile-fail/intrinsics/unchecked_mul2.stderr rename to tests/fail/intrinsics/unchecked_mul2.stderr diff --git a/tests/compile-fail/intrinsics/unchecked_sub1.rs b/tests/fail/intrinsics/unchecked_sub1.rs similarity index 100% rename from tests/compile-fail/intrinsics/unchecked_sub1.rs rename to tests/fail/intrinsics/unchecked_sub1.rs diff --git a/tests/compile-fail/intrinsics/unchecked_sub1.stderr b/tests/fail/intrinsics/unchecked_sub1.stderr similarity index 100% rename from tests/compile-fail/intrinsics/unchecked_sub1.stderr rename to tests/fail/intrinsics/unchecked_sub1.stderr diff --git a/tests/compile-fail/intrinsics/unchecked_sub2.rs b/tests/fail/intrinsics/unchecked_sub2.rs similarity index 100% rename from tests/compile-fail/intrinsics/unchecked_sub2.rs rename to tests/fail/intrinsics/unchecked_sub2.rs diff --git a/tests/compile-fail/intrinsics/unchecked_sub2.stderr b/tests/fail/intrinsics/unchecked_sub2.stderr similarity index 100% rename from tests/compile-fail/intrinsics/unchecked_sub2.stderr rename to tests/fail/intrinsics/unchecked_sub2.stderr diff --git a/tests/compile-fail/intrinsics/uninit_uninhabited_type.rs b/tests/fail/intrinsics/uninit_uninhabited_type.rs similarity index 100% rename from tests/compile-fail/intrinsics/uninit_uninhabited_type.rs rename to tests/fail/intrinsics/uninit_uninhabited_type.rs diff --git a/tests/compile-fail/intrinsics/uninit_uninhabited_type.stderr b/tests/fail/intrinsics/uninit_uninhabited_type.stderr similarity index 100% rename from tests/compile-fail/intrinsics/uninit_uninhabited_type.stderr rename to tests/fail/intrinsics/uninit_uninhabited_type.stderr diff --git a/tests/compile-fail/intrinsics/write_bytes_null.rs b/tests/fail/intrinsics/write_bytes_null.rs similarity index 100% rename from tests/compile-fail/intrinsics/write_bytes_null.rs rename to tests/fail/intrinsics/write_bytes_null.rs diff --git a/tests/compile-fail/intrinsics/write_bytes_null.stderr b/tests/fail/intrinsics/write_bytes_null.stderr similarity index 100% rename from tests/compile-fail/intrinsics/write_bytes_null.stderr rename to tests/fail/intrinsics/write_bytes_null.stderr diff --git a/tests/compile-fail/intrinsics/write_bytes_overflow.rs b/tests/fail/intrinsics/write_bytes_overflow.rs similarity index 100% rename from tests/compile-fail/intrinsics/write_bytes_overflow.rs rename to tests/fail/intrinsics/write_bytes_overflow.rs diff --git a/tests/compile-fail/intrinsics/write_bytes_overflow.stderr b/tests/fail/intrinsics/write_bytes_overflow.stderr similarity index 100% rename from tests/compile-fail/intrinsics/write_bytes_overflow.stderr rename to tests/fail/intrinsics/write_bytes_overflow.stderr diff --git a/tests/compile-fail/intrinsics/zero_fn_ptr.rs b/tests/fail/intrinsics/zero_fn_ptr.rs similarity index 100% rename from tests/compile-fail/intrinsics/zero_fn_ptr.rs rename to tests/fail/intrinsics/zero_fn_ptr.rs diff --git a/tests/compile-fail/intrinsics/zero_fn_ptr.stderr b/tests/fail/intrinsics/zero_fn_ptr.stderr similarity index 100% rename from tests/compile-fail/intrinsics/zero_fn_ptr.stderr rename to tests/fail/intrinsics/zero_fn_ptr.stderr diff --git a/tests/compile-fail/invalid_bool.rs b/tests/fail/invalid_bool.rs similarity index 100% rename from tests/compile-fail/invalid_bool.rs rename to tests/fail/invalid_bool.rs diff --git a/tests/compile-fail/invalid_bool.stderr b/tests/fail/invalid_bool.stderr similarity index 100% rename from tests/compile-fail/invalid_bool.stderr rename to tests/fail/invalid_bool.stderr diff --git a/tests/compile-fail/invalid_char.rs b/tests/fail/invalid_char.rs similarity index 100% rename from tests/compile-fail/invalid_char.rs rename to tests/fail/invalid_char.rs diff --git a/tests/compile-fail/invalid_char.stderr b/tests/fail/invalid_char.stderr similarity index 100% rename from tests/compile-fail/invalid_char.stderr rename to tests/fail/invalid_char.stderr diff --git a/tests/compile-fail/invalid_enum_tag.rs b/tests/fail/invalid_enum_tag.rs similarity index 100% rename from tests/compile-fail/invalid_enum_tag.rs rename to tests/fail/invalid_enum_tag.rs diff --git a/tests/compile-fail/invalid_enum_tag.stderr b/tests/fail/invalid_enum_tag.stderr similarity index 100% rename from tests/compile-fail/invalid_enum_tag.stderr rename to tests/fail/invalid_enum_tag.stderr diff --git a/tests/compile-fail/invalid_int.rs b/tests/fail/invalid_int.rs similarity index 100% rename from tests/compile-fail/invalid_int.rs rename to tests/fail/invalid_int.rs diff --git a/tests/compile-fail/invalid_int.stderr b/tests/fail/invalid_int.stderr similarity index 100% rename from tests/compile-fail/invalid_int.stderr rename to tests/fail/invalid_int.stderr diff --git a/tests/compile-fail/issue-miri-1112.rs b/tests/fail/issue-miri-1112.rs similarity index 100% rename from tests/compile-fail/issue-miri-1112.rs rename to tests/fail/issue-miri-1112.rs diff --git a/tests/compile-fail/issue-miri-1112.stderr b/tests/fail/issue-miri-1112.stderr similarity index 100% rename from tests/compile-fail/issue-miri-1112.stderr rename to tests/fail/issue-miri-1112.stderr diff --git a/tests/compile-fail/memleak.rs b/tests/fail/memleak.rs similarity index 100% rename from tests/compile-fail/memleak.rs rename to tests/fail/memleak.rs diff --git a/tests/compile-fail/memleak.stderr b/tests/fail/memleak.stderr similarity index 100% rename from tests/compile-fail/memleak.stderr rename to tests/fail/memleak.stderr diff --git a/tests/compile-fail/memleak_rc.32bit.stderr b/tests/fail/memleak_rc.32bit.stderr similarity index 100% rename from tests/compile-fail/memleak_rc.32bit.stderr rename to tests/fail/memleak_rc.32bit.stderr diff --git a/tests/compile-fail/memleak_rc.64bit.stderr b/tests/fail/memleak_rc.64bit.stderr similarity index 100% rename from tests/compile-fail/memleak_rc.64bit.stderr rename to tests/fail/memleak_rc.64bit.stderr diff --git a/tests/compile-fail/memleak_rc.rs b/tests/fail/memleak_rc.rs similarity index 100% rename from tests/compile-fail/memleak_rc.rs rename to tests/fail/memleak_rc.rs diff --git a/tests/compile-fail/modifying_constants.rs b/tests/fail/modifying_constants.rs similarity index 100% rename from tests/compile-fail/modifying_constants.rs rename to tests/fail/modifying_constants.rs diff --git a/tests/compile-fail/modifying_constants.stderr b/tests/fail/modifying_constants.stderr similarity index 100% rename from tests/compile-fail/modifying_constants.stderr rename to tests/fail/modifying_constants.stderr diff --git a/tests/compile-fail/never_say_never.rs b/tests/fail/never_say_never.rs similarity index 100% rename from tests/compile-fail/never_say_never.rs rename to tests/fail/never_say_never.rs diff --git a/tests/compile-fail/never_say_never.stderr b/tests/fail/never_say_never.stderr similarity index 100% rename from tests/compile-fail/never_say_never.stderr rename to tests/fail/never_say_never.stderr diff --git a/tests/compile-fail/never_transmute_humans.rs b/tests/fail/never_transmute_humans.rs similarity index 100% rename from tests/compile-fail/never_transmute_humans.rs rename to tests/fail/never_transmute_humans.rs diff --git a/tests/compile-fail/never_transmute_humans.stderr b/tests/fail/never_transmute_humans.stderr similarity index 100% rename from tests/compile-fail/never_transmute_humans.stderr rename to tests/fail/never_transmute_humans.stderr diff --git a/tests/compile-fail/never_transmute_void.rs b/tests/fail/never_transmute_void.rs similarity index 100% rename from tests/compile-fail/never_transmute_void.rs rename to tests/fail/never_transmute_void.rs diff --git a/tests/compile-fail/never_transmute_void.stderr b/tests/fail/never_transmute_void.stderr similarity index 100% rename from tests/compile-fail/never_transmute_void.stderr rename to tests/fail/never_transmute_void.stderr diff --git a/tests/compile-fail/no_main.rs b/tests/fail/no_main.rs similarity index 100% rename from tests/compile-fail/no_main.rs rename to tests/fail/no_main.rs diff --git a/tests/compile-fail/no_main.stderr b/tests/fail/no_main.stderr similarity index 100% rename from tests/compile-fail/no_main.stderr rename to tests/fail/no_main.stderr diff --git a/tests/compile-fail/null_pointer_deref.stderr b/tests/fail/null_pointer_deref.stderr similarity index 100% rename from tests/compile-fail/null_pointer_deref.stderr rename to tests/fail/null_pointer_deref.stderr diff --git a/tests/compile-fail/null_pointer_deref_zst.stderr b/tests/fail/null_pointer_deref_zst.stderr similarity index 100% rename from tests/compile-fail/null_pointer_deref_zst.stderr rename to tests/fail/null_pointer_deref_zst.stderr diff --git a/tests/compile-fail/null_pointer_write.stderr b/tests/fail/null_pointer_write.stderr similarity index 100% rename from tests/compile-fail/null_pointer_write.stderr rename to tests/fail/null_pointer_write.stderr diff --git a/tests/compile-fail/null_pointer_write_zst.stderr b/tests/fail/null_pointer_write_zst.stderr similarity index 100% rename from tests/compile-fail/null_pointer_write_zst.stderr rename to tests/fail/null_pointer_write_zst.stderr diff --git a/tests/compile-fail/panic/bad_miri_start_panic.rs b/tests/fail/panic/bad_miri_start_panic.rs similarity index 100% rename from tests/compile-fail/panic/bad_miri_start_panic.rs rename to tests/fail/panic/bad_miri_start_panic.rs diff --git a/tests/compile-fail/panic/bad_miri_start_panic.stderr b/tests/fail/panic/bad_miri_start_panic.stderr similarity index 100% rename from tests/compile-fail/panic/bad_miri_start_panic.stderr rename to tests/fail/panic/bad_miri_start_panic.stderr diff --git a/tests/compile-fail/panic/bad_unwind.rs b/tests/fail/panic/bad_unwind.rs similarity index 100% rename from tests/compile-fail/panic/bad_unwind.rs rename to tests/fail/panic/bad_unwind.rs diff --git a/tests/compile-fail/panic/bad_unwind.stderr b/tests/fail/panic/bad_unwind.stderr similarity index 100% rename from tests/compile-fail/panic/bad_unwind.stderr rename to tests/fail/panic/bad_unwind.stderr diff --git a/tests/compile-fail/panic/double_panic.rs b/tests/fail/panic/double_panic.rs similarity index 100% rename from tests/compile-fail/panic/double_panic.rs rename to tests/fail/panic/double_panic.rs diff --git a/tests/compile-fail/panic/double_panic.stderr b/tests/fail/panic/double_panic.stderr similarity index 100% rename from tests/compile-fail/panic/double_panic.stderr rename to tests/fail/panic/double_panic.stderr diff --git a/tests/compile-fail/panic/panic_abort1.rs b/tests/fail/panic/panic_abort1.rs similarity index 100% rename from tests/compile-fail/panic/panic_abort1.rs rename to tests/fail/panic/panic_abort1.rs diff --git a/tests/compile-fail/panic/panic_abort1.stderr b/tests/fail/panic/panic_abort1.stderr similarity index 100% rename from tests/compile-fail/panic/panic_abort1.stderr rename to tests/fail/panic/panic_abort1.stderr diff --git a/tests/compile-fail/panic/panic_abort2.rs b/tests/fail/panic/panic_abort2.rs similarity index 100% rename from tests/compile-fail/panic/panic_abort2.rs rename to tests/fail/panic/panic_abort2.rs diff --git a/tests/compile-fail/panic/panic_abort2.stderr b/tests/fail/panic/panic_abort2.stderr similarity index 100% rename from tests/compile-fail/panic/panic_abort2.stderr rename to tests/fail/panic/panic_abort2.stderr diff --git a/tests/compile-fail/panic/panic_abort3.rs b/tests/fail/panic/panic_abort3.rs similarity index 100% rename from tests/compile-fail/panic/panic_abort3.rs rename to tests/fail/panic/panic_abort3.rs diff --git a/tests/compile-fail/panic/panic_abort3.stderr b/tests/fail/panic/panic_abort3.stderr similarity index 100% rename from tests/compile-fail/panic/panic_abort3.stderr rename to tests/fail/panic/panic_abort3.stderr diff --git a/tests/compile-fail/panic/panic_abort4.rs b/tests/fail/panic/panic_abort4.rs similarity index 100% rename from tests/compile-fail/panic/panic_abort4.rs rename to tests/fail/panic/panic_abort4.rs diff --git a/tests/compile-fail/panic/panic_abort4.stderr b/tests/fail/panic/panic_abort4.stderr similarity index 100% rename from tests/compile-fail/panic/panic_abort4.stderr rename to tests/fail/panic/panic_abort4.stderr diff --git a/tests/compile-fail/panic/unwind_panic_abort.rs b/tests/fail/panic/unwind_panic_abort.rs similarity index 100% rename from tests/compile-fail/panic/unwind_panic_abort.rs rename to tests/fail/panic/unwind_panic_abort.rs diff --git a/tests/compile-fail/panic/unwind_panic_abort.stderr b/tests/fail/panic/unwind_panic_abort.stderr similarity index 100% rename from tests/compile-fail/panic/unwind_panic_abort.stderr rename to tests/fail/panic/unwind_panic_abort.stderr diff --git a/tests/compile-fail/pointer_partial_overwrite.rs b/tests/fail/pointer_partial_overwrite.rs similarity index 100% rename from tests/compile-fail/pointer_partial_overwrite.rs rename to tests/fail/pointer_partial_overwrite.rs diff --git a/tests/compile-fail/pointer_partial_overwrite.stderr b/tests/fail/pointer_partial_overwrite.stderr similarity index 100% rename from tests/compile-fail/pointer_partial_overwrite.stderr rename to tests/fail/pointer_partial_overwrite.stderr diff --git a/tests/compile-fail/pointer_partial_read.rs b/tests/fail/pointer_partial_read.rs similarity index 100% rename from tests/compile-fail/pointer_partial_read.rs rename to tests/fail/pointer_partial_read.rs diff --git a/tests/compile-fail/pointer_partial_read.stderr b/tests/fail/pointer_partial_read.stderr similarity index 100% rename from tests/compile-fail/pointer_partial_read.stderr rename to tests/fail/pointer_partial_read.stderr diff --git a/tests/compile-fail/provenance/ptr_int_unexposed.rs b/tests/fail/provenance/ptr_int_unexposed.rs similarity index 100% rename from tests/compile-fail/provenance/ptr_int_unexposed.rs rename to tests/fail/provenance/ptr_int_unexposed.rs diff --git a/tests/compile-fail/provenance/ptr_int_unexposed.stderr b/tests/fail/provenance/ptr_int_unexposed.stderr similarity index 100% rename from tests/compile-fail/provenance/ptr_int_unexposed.stderr rename to tests/fail/provenance/ptr_int_unexposed.stderr diff --git a/tests/compile-fail/provenance/ptr_invalid.rs b/tests/fail/provenance/ptr_invalid.rs similarity index 100% rename from tests/compile-fail/provenance/ptr_invalid.rs rename to tests/fail/provenance/ptr_invalid.rs diff --git a/tests/compile-fail/provenance/ptr_invalid.stderr b/tests/fail/provenance/ptr_invalid.stderr similarity index 100% rename from tests/compile-fail/provenance/ptr_invalid.stderr rename to tests/fail/provenance/ptr_invalid.stderr diff --git a/tests/compile-fail/provenance/ptr_legacy_provenance.rs b/tests/fail/provenance/ptr_legacy_provenance.rs similarity index 100% rename from tests/compile-fail/provenance/ptr_legacy_provenance.rs rename to tests/fail/provenance/ptr_legacy_provenance.rs diff --git a/tests/compile-fail/provenance/ptr_legacy_provenance.stderr b/tests/fail/provenance/ptr_legacy_provenance.stderr similarity index 100% rename from tests/compile-fail/provenance/ptr_legacy_provenance.stderr rename to tests/fail/provenance/ptr_legacy_provenance.stderr diff --git a/tests/compile-fail/provenance/strict-provenance-offset.rs b/tests/fail/provenance/strict-provenance-offset.rs similarity index 100% rename from tests/compile-fail/provenance/strict-provenance-offset.rs rename to tests/fail/provenance/strict-provenance-offset.rs diff --git a/tests/compile-fail/provenance/strict-provenance-offset.stderr b/tests/fail/provenance/strict-provenance-offset.stderr similarity index 100% rename from tests/compile-fail/provenance/strict-provenance-offset.stderr rename to tests/fail/provenance/strict-provenance-offset.stderr diff --git a/tests/compile-fail/provenance/strict_provenance_transmute.rs b/tests/fail/provenance/strict_provenance_transmute.rs similarity index 100% rename from tests/compile-fail/provenance/strict_provenance_transmute.rs rename to tests/fail/provenance/strict_provenance_transmute.rs diff --git a/tests/compile-fail/provenance/strict_provenance_transmute.stderr b/tests/fail/provenance/strict_provenance_transmute.stderr similarity index 100% rename from tests/compile-fail/provenance/strict_provenance_transmute.stderr rename to tests/fail/provenance/strict_provenance_transmute.stderr diff --git a/tests/compile-fail/ptr_integer_array_transmute.stderr b/tests/fail/ptr_integer_array_transmute.stderr similarity index 100% rename from tests/compile-fail/ptr_integer_array_transmute.stderr rename to tests/fail/ptr_integer_array_transmute.stderr diff --git a/tests/compile-fail/ptr_integer_transmute.stderr b/tests/fail/ptr_integer_transmute.stderr similarity index 100% rename from tests/compile-fail/ptr_integer_transmute.stderr rename to tests/fail/ptr_integer_transmute.stderr diff --git a/tests/compile-fail/rc_as_ptr.rs b/tests/fail/rc_as_ptr.rs similarity index 100% rename from tests/compile-fail/rc_as_ptr.rs rename to tests/fail/rc_as_ptr.rs diff --git a/tests/compile-fail/rc_as_ptr.stderr b/tests/fail/rc_as_ptr.stderr similarity index 100% rename from tests/compile-fail/rc_as_ptr.stderr rename to tests/fail/rc_as_ptr.stderr diff --git a/tests/compile-fail/reading_half_a_pointer.rs b/tests/fail/reading_half_a_pointer.rs similarity index 100% rename from tests/compile-fail/reading_half_a_pointer.rs rename to tests/fail/reading_half_a_pointer.rs diff --git a/tests/compile-fail/reading_half_a_pointer.stderr b/tests/fail/reading_half_a_pointer.stderr similarity index 100% rename from tests/compile-fail/reading_half_a_pointer.stderr rename to tests/fail/reading_half_a_pointer.stderr diff --git a/tests/compile-fail/rustc-error.rs b/tests/fail/rustc-error.rs similarity index 100% rename from tests/compile-fail/rustc-error.rs rename to tests/fail/rustc-error.rs diff --git a/tests/compile-fail/rustc-error.stderr b/tests/fail/rustc-error.stderr similarity index 100% rename from tests/compile-fail/rustc-error.stderr rename to tests/fail/rustc-error.stderr diff --git a/tests/compile-fail/shim_arg_size.32bit.stderr b/tests/fail/shim_arg_size.32bit.stderr similarity index 100% rename from tests/compile-fail/shim_arg_size.32bit.stderr rename to tests/fail/shim_arg_size.32bit.stderr diff --git a/tests/compile-fail/shim_arg_size.64bit.stderr b/tests/fail/shim_arg_size.64bit.stderr similarity index 100% rename from tests/compile-fail/shim_arg_size.64bit.stderr rename to tests/fail/shim_arg_size.64bit.stderr diff --git a/tests/compile-fail/shim_arg_size.rs b/tests/fail/shim_arg_size.rs similarity index 100% rename from tests/compile-fail/shim_arg_size.rs rename to tests/fail/shim_arg_size.rs diff --git a/tests/compile-fail/slice-too-big.stderr b/tests/fail/slice-too-big.stderr similarity index 100% rename from tests/compile-fail/slice-too-big.stderr rename to tests/fail/slice-too-big.stderr diff --git a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs b/tests/fail/stacked_borrows/alias_through_mutation.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/alias_through_mutation.rs rename to tests/fail/stacked_borrows/alias_through_mutation.rs diff --git a/tests/compile-fail/stacked_borrows/alias_through_mutation.stderr b/tests/fail/stacked_borrows/alias_through_mutation.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/alias_through_mutation.stderr rename to tests/fail/stacked_borrows/alias_through_mutation.stderr diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut1.rs b/tests/fail/stacked_borrows/aliasing_mut1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/aliasing_mut1.rs rename to tests/fail/stacked_borrows/aliasing_mut1.rs diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut1.stderr b/tests/fail/stacked_borrows/aliasing_mut1.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/aliasing_mut1.stderr rename to tests/fail/stacked_borrows/aliasing_mut1.stderr diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut2.rs b/tests/fail/stacked_borrows/aliasing_mut2.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/aliasing_mut2.rs rename to tests/fail/stacked_borrows/aliasing_mut2.rs diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut2.stderr b/tests/fail/stacked_borrows/aliasing_mut2.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/aliasing_mut2.stderr rename to tests/fail/stacked_borrows/aliasing_mut2.stderr diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut3.rs b/tests/fail/stacked_borrows/aliasing_mut3.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/aliasing_mut3.rs rename to tests/fail/stacked_borrows/aliasing_mut3.rs diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut3.stderr b/tests/fail/stacked_borrows/aliasing_mut3.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/aliasing_mut3.stderr rename to tests/fail/stacked_borrows/aliasing_mut3.stderr diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut4.rs b/tests/fail/stacked_borrows/aliasing_mut4.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/aliasing_mut4.rs rename to tests/fail/stacked_borrows/aliasing_mut4.rs diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut4.stderr b/tests/fail/stacked_borrows/aliasing_mut4.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/aliasing_mut4.stderr rename to tests/fail/stacked_borrows/aliasing_mut4.stderr diff --git a/tests/compile-fail/stacked_borrows/box_exclusive_violation1.rs b/tests/fail/stacked_borrows/box_exclusive_violation1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/box_exclusive_violation1.rs rename to tests/fail/stacked_borrows/box_exclusive_violation1.rs diff --git a/tests/compile-fail/stacked_borrows/box_exclusive_violation1.stderr b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/box_exclusive_violation1.stderr rename to tests/fail/stacked_borrows/box_exclusive_violation1.stderr diff --git a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/fail/stacked_borrows/buggy_as_mut_slice.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs rename to tests/fail/stacked_borrows/buggy_as_mut_slice.rs diff --git a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.stderr b/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/buggy_as_mut_slice.stderr rename to tests/fail/stacked_borrows/buggy_as_mut_slice.stderr diff --git a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs b/tests/fail/stacked_borrows/buggy_split_at_mut.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs rename to tests/fail/stacked_borrows/buggy_split_at_mut.rs diff --git a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.stderr b/tests/fail/stacked_borrows/buggy_split_at_mut.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/buggy_split_at_mut.stderr rename to tests/fail/stacked_borrows/buggy_split_at_mut.stderr diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier1.rs b/tests/fail/stacked_borrows/deallocate_against_barrier1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/deallocate_against_barrier1.rs rename to tests/fail/stacked_borrows/deallocate_against_barrier1.rs diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier1.stderr b/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/deallocate_against_barrier1.stderr rename to tests/fail/stacked_borrows/deallocate_against_barrier1.stderr diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.rs b/tests/fail/stacked_borrows/deallocate_against_barrier2.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/deallocate_against_barrier2.rs rename to tests/fail/stacked_borrows/deallocate_against_barrier2.rs diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.stderr b/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/deallocate_against_barrier2.stderr rename to tests/fail/stacked_borrows/deallocate_against_barrier2.stderr diff --git a/tests/compile-fail/stacked_borrows/illegal_read1.rs b/tests/fail/stacked_borrows/illegal_read1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read1.rs rename to tests/fail/stacked_borrows/illegal_read1.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read1.stderr b/tests/fail/stacked_borrows/illegal_read1.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read1.stderr rename to tests/fail/stacked_borrows/illegal_read1.stderr diff --git a/tests/compile-fail/stacked_borrows/illegal_read2.rs b/tests/fail/stacked_borrows/illegal_read2.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read2.rs rename to tests/fail/stacked_borrows/illegal_read2.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read2.stderr b/tests/fail/stacked_borrows/illegal_read2.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read2.stderr rename to tests/fail/stacked_borrows/illegal_read2.stderr diff --git a/tests/compile-fail/stacked_borrows/illegal_read3.rs b/tests/fail/stacked_borrows/illegal_read3.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read3.rs rename to tests/fail/stacked_borrows/illegal_read3.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read3.stderr b/tests/fail/stacked_borrows/illegal_read3.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read3.stderr rename to tests/fail/stacked_borrows/illegal_read3.stderr diff --git a/tests/compile-fail/stacked_borrows/illegal_read4.rs b/tests/fail/stacked_borrows/illegal_read4.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read4.rs rename to tests/fail/stacked_borrows/illegal_read4.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read4.stderr b/tests/fail/stacked_borrows/illegal_read4.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read4.stderr rename to tests/fail/stacked_borrows/illegal_read4.stderr diff --git a/tests/compile-fail/stacked_borrows/illegal_read5.rs b/tests/fail/stacked_borrows/illegal_read5.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read5.rs rename to tests/fail/stacked_borrows/illegal_read5.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read5.stderr b/tests/fail/stacked_borrows/illegal_read5.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read5.stderr rename to tests/fail/stacked_borrows/illegal_read5.stderr diff --git a/tests/compile-fail/stacked_borrows/illegal_read6.rs b/tests/fail/stacked_borrows/illegal_read6.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read6.rs rename to tests/fail/stacked_borrows/illegal_read6.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read6.stderr b/tests/fail/stacked_borrows/illegal_read6.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read6.stderr rename to tests/fail/stacked_borrows/illegal_read6.stderr diff --git a/tests/compile-fail/stacked_borrows/illegal_read7.rs b/tests/fail/stacked_borrows/illegal_read7.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read7.rs rename to tests/fail/stacked_borrows/illegal_read7.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read7.stderr b/tests/fail/stacked_borrows/illegal_read7.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read7.stderr rename to tests/fail/stacked_borrows/illegal_read7.stderr diff --git a/tests/compile-fail/stacked_borrows/illegal_read8.rs b/tests/fail/stacked_borrows/illegal_read8.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read8.rs rename to tests/fail/stacked_borrows/illegal_read8.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read8.stderr b/tests/fail/stacked_borrows/illegal_read8.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read8.stderr rename to tests/fail/stacked_borrows/illegal_read8.stderr diff --git a/tests/compile-fail/stacked_borrows/illegal_write1.rs b/tests/fail/stacked_borrows/illegal_write1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write1.rs rename to tests/fail/stacked_borrows/illegal_write1.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_write1.stderr b/tests/fail/stacked_borrows/illegal_write1.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write1.stderr rename to tests/fail/stacked_borrows/illegal_write1.stderr diff --git a/tests/compile-fail/stacked_borrows/illegal_write2.rs b/tests/fail/stacked_borrows/illegal_write2.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write2.rs rename to tests/fail/stacked_borrows/illegal_write2.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_write2.stderr b/tests/fail/stacked_borrows/illegal_write2.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write2.stderr rename to tests/fail/stacked_borrows/illegal_write2.stderr diff --git a/tests/compile-fail/stacked_borrows/illegal_write3.rs b/tests/fail/stacked_borrows/illegal_write3.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write3.rs rename to tests/fail/stacked_borrows/illegal_write3.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_write3.stderr b/tests/fail/stacked_borrows/illegal_write3.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write3.stderr rename to tests/fail/stacked_borrows/illegal_write3.stderr diff --git a/tests/compile-fail/stacked_borrows/illegal_write4.rs b/tests/fail/stacked_borrows/illegal_write4.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write4.rs rename to tests/fail/stacked_borrows/illegal_write4.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_write4.stderr b/tests/fail/stacked_borrows/illegal_write4.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write4.stderr rename to tests/fail/stacked_borrows/illegal_write4.stderr diff --git a/tests/compile-fail/stacked_borrows/illegal_write5.rs b/tests/fail/stacked_borrows/illegal_write5.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write5.rs rename to tests/fail/stacked_borrows/illegal_write5.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_write5.stderr b/tests/fail/stacked_borrows/illegal_write5.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write5.stderr rename to tests/fail/stacked_borrows/illegal_write5.stderr diff --git a/tests/compile-fail/stacked_borrows/illegal_write6.rs b/tests/fail/stacked_borrows/illegal_write6.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write6.rs rename to tests/fail/stacked_borrows/illegal_write6.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_write6.stderr b/tests/fail/stacked_borrows/illegal_write6.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write6.stderr rename to tests/fail/stacked_borrows/illegal_write6.stderr diff --git a/tests/compile-fail/stacked_borrows/interior_mut1.rs b/tests/fail/stacked_borrows/interior_mut1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/interior_mut1.rs rename to tests/fail/stacked_borrows/interior_mut1.rs diff --git a/tests/compile-fail/stacked_borrows/interior_mut1.stderr b/tests/fail/stacked_borrows/interior_mut1.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/interior_mut1.stderr rename to tests/fail/stacked_borrows/interior_mut1.stderr diff --git a/tests/compile-fail/stacked_borrows/interior_mut2.rs b/tests/fail/stacked_borrows/interior_mut2.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/interior_mut2.rs rename to tests/fail/stacked_borrows/interior_mut2.rs diff --git a/tests/compile-fail/stacked_borrows/interior_mut2.stderr b/tests/fail/stacked_borrows/interior_mut2.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/interior_mut2.stderr rename to tests/fail/stacked_borrows/interior_mut2.stderr diff --git a/tests/compile-fail/stacked_borrows/invalidate_against_barrier1.rs b/tests/fail/stacked_borrows/invalidate_against_barrier1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/invalidate_against_barrier1.rs rename to tests/fail/stacked_borrows/invalidate_against_barrier1.rs diff --git a/tests/compile-fail/stacked_borrows/invalidate_against_barrier1.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/invalidate_against_barrier1.stderr rename to tests/fail/stacked_borrows/invalidate_against_barrier1.stderr diff --git a/tests/compile-fail/stacked_borrows/invalidate_against_barrier2.rs b/tests/fail/stacked_borrows/invalidate_against_barrier2.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/invalidate_against_barrier2.rs rename to tests/fail/stacked_borrows/invalidate_against_barrier2.rs diff --git a/tests/compile-fail/stacked_borrows/invalidate_against_barrier2.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/invalidate_against_barrier2.stderr rename to tests/fail/stacked_borrows/invalidate_against_barrier2.stderr diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-1.rs b/tests/fail/stacked_borrows/issue-miri-1050-1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/issue-miri-1050-1.rs rename to tests/fail/stacked_borrows/issue-miri-1050-1.rs diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-1.stderr b/tests/fail/stacked_borrows/issue-miri-1050-1.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/issue-miri-1050-1.stderr rename to tests/fail/stacked_borrows/issue-miri-1050-1.stderr diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs b/tests/fail/stacked_borrows/issue-miri-1050-2.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs rename to tests/fail/stacked_borrows/issue-miri-1050-2.rs diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-2.stderr b/tests/fail/stacked_borrows/issue-miri-1050-2.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/issue-miri-1050-2.stderr rename to tests/fail/stacked_borrows/issue-miri-1050-2.stderr diff --git a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs b/tests/fail/stacked_borrows/load_invalid_mut.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/load_invalid_mut.rs rename to tests/fail/stacked_borrows/load_invalid_mut.rs diff --git a/tests/compile-fail/stacked_borrows/load_invalid_mut.stderr b/tests/fail/stacked_borrows/load_invalid_mut.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/load_invalid_mut.stderr rename to tests/fail/stacked_borrows/load_invalid_mut.stderr diff --git a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs b/tests/fail/stacked_borrows/load_invalid_shr.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/load_invalid_shr.rs rename to tests/fail/stacked_borrows/load_invalid_shr.rs diff --git a/tests/compile-fail/stacked_borrows/load_invalid_shr.stderr b/tests/fail/stacked_borrows/load_invalid_shr.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/load_invalid_shr.stderr rename to tests/fail/stacked_borrows/load_invalid_shr.stderr diff --git a/tests/compile-fail/stacked_borrows/mut_exclusive_violation1.rs b/tests/fail/stacked_borrows/mut_exclusive_violation1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/mut_exclusive_violation1.rs rename to tests/fail/stacked_borrows/mut_exclusive_violation1.rs diff --git a/tests/compile-fail/stacked_borrows/mut_exclusive_violation1.stderr b/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/mut_exclusive_violation1.stderr rename to tests/fail/stacked_borrows/mut_exclusive_violation1.stderr diff --git a/tests/compile-fail/stacked_borrows/mut_exclusive_violation2.rs b/tests/fail/stacked_borrows/mut_exclusive_violation2.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/mut_exclusive_violation2.rs rename to tests/fail/stacked_borrows/mut_exclusive_violation2.rs diff --git a/tests/compile-fail/stacked_borrows/mut_exclusive_violation2.stderr b/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/mut_exclusive_violation2.stderr rename to tests/fail/stacked_borrows/mut_exclusive_violation2.stderr diff --git a/tests/compile-fail/stacked_borrows/outdated_local.rs b/tests/fail/stacked_borrows/outdated_local.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/outdated_local.rs rename to tests/fail/stacked_borrows/outdated_local.rs diff --git a/tests/compile-fail/stacked_borrows/outdated_local.stderr b/tests/fail/stacked_borrows/outdated_local.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/outdated_local.stderr rename to tests/fail/stacked_borrows/outdated_local.stderr diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs b/tests/fail/stacked_borrows/pass_invalid_mut.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/pass_invalid_mut.rs rename to tests/fail/stacked_borrows/pass_invalid_mut.rs diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_mut.stderr b/tests/fail/stacked_borrows/pass_invalid_mut.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/pass_invalid_mut.stderr rename to tests/fail/stacked_borrows/pass_invalid_mut.stderr diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs b/tests/fail/stacked_borrows/pass_invalid_shr.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/pass_invalid_shr.rs rename to tests/fail/stacked_borrows/pass_invalid_shr.rs diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_shr.stderr b/tests/fail/stacked_borrows/pass_invalid_shr.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/pass_invalid_shr.stderr rename to tests/fail/stacked_borrows/pass_invalid_shr.stderr diff --git a/tests/compile-fail/stacked_borrows/pointer_smuggling.rs b/tests/fail/stacked_borrows/pointer_smuggling.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/pointer_smuggling.rs rename to tests/fail/stacked_borrows/pointer_smuggling.rs diff --git a/tests/compile-fail/stacked_borrows/pointer_smuggling.stderr b/tests/fail/stacked_borrows/pointer_smuggling.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/pointer_smuggling.stderr rename to tests/fail/stacked_borrows/pointer_smuggling.stderr diff --git a/tests/compile-fail/stacked_borrows/raw_tracking.rs b/tests/fail/stacked_borrows/raw_tracking.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/raw_tracking.rs rename to tests/fail/stacked_borrows/raw_tracking.rs diff --git a/tests/compile-fail/stacked_borrows/raw_tracking.stderr b/tests/fail/stacked_borrows/raw_tracking.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/raw_tracking.stderr rename to tests/fail/stacked_borrows/raw_tracking.stderr diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs b/tests/fail/stacked_borrows/return_invalid_mut.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/return_invalid_mut.rs rename to tests/fail/stacked_borrows/return_invalid_mut.rs diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut.stderr b/tests/fail/stacked_borrows/return_invalid_mut.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/return_invalid_mut.stderr rename to tests/fail/stacked_borrows/return_invalid_mut.stderr diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs b/tests/fail/stacked_borrows/return_invalid_mut_option.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs rename to tests/fail/stacked_borrows/return_invalid_mut_option.rs diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut_option.stderr b/tests/fail/stacked_borrows/return_invalid_mut_option.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/return_invalid_mut_option.stderr rename to tests/fail/stacked_borrows/return_invalid_mut_option.stderr diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs b/tests/fail/stacked_borrows/return_invalid_mut_tuple.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs rename to tests/fail/stacked_borrows/return_invalid_mut_tuple.rs diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.stderr b/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.stderr rename to tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr.rs b/tests/fail/stacked_borrows/return_invalid_shr.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/return_invalid_shr.rs rename to tests/fail/stacked_borrows/return_invalid_shr.rs diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr.stderr b/tests/fail/stacked_borrows/return_invalid_shr.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/return_invalid_shr.stderr rename to tests/fail/stacked_borrows/return_invalid_shr.stderr diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr_option.rs b/tests/fail/stacked_borrows/return_invalid_shr_option.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/return_invalid_shr_option.rs rename to tests/fail/stacked_borrows/return_invalid_shr_option.rs diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr_option.stderr b/tests/fail/stacked_borrows/return_invalid_shr_option.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/return_invalid_shr_option.stderr rename to tests/fail/stacked_borrows/return_invalid_shr_option.stderr diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.rs b/tests/fail/stacked_borrows/return_invalid_shr_tuple.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.rs rename to tests/fail/stacked_borrows/return_invalid_shr_tuple.rs diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.stderr b/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.stderr rename to tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr diff --git a/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak1.rs b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak1.rs rename to tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs diff --git a/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr rename to tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr diff --git a/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.rs b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.rs rename to tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs diff --git a/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr rename to tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr diff --git a/tests/compile-fail/stacked_borrows/shr_frozen_violation1.rs b/tests/fail/stacked_borrows/shr_frozen_violation1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/shr_frozen_violation1.rs rename to tests/fail/stacked_borrows/shr_frozen_violation1.rs diff --git a/tests/compile-fail/stacked_borrows/shr_frozen_violation1.stderr b/tests/fail/stacked_borrows/shr_frozen_violation1.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/shr_frozen_violation1.stderr rename to tests/fail/stacked_borrows/shr_frozen_violation1.stderr diff --git a/tests/compile-fail/stacked_borrows/static_memory_modification.rs b/tests/fail/stacked_borrows/static_memory_modification.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/static_memory_modification.rs rename to tests/fail/stacked_borrows/static_memory_modification.rs diff --git a/tests/compile-fail/stacked_borrows/static_memory_modification.stderr b/tests/fail/stacked_borrows/static_memory_modification.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/static_memory_modification.stderr rename to tests/fail/stacked_borrows/static_memory_modification.stderr diff --git a/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs b/tests/fail/stacked_borrows/transmute-is-no-escape.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs rename to tests/fail/stacked_borrows/transmute-is-no-escape.rs diff --git a/tests/compile-fail/stacked_borrows/transmute-is-no-escape.stderr b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/transmute-is-no-escape.stderr rename to tests/fail/stacked_borrows/transmute-is-no-escape.stderr diff --git a/tests/compile-fail/stacked_borrows/unescaped_local.rs b/tests/fail/stacked_borrows/unescaped_local.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/unescaped_local.rs rename to tests/fail/stacked_borrows/unescaped_local.rs diff --git a/tests/compile-fail/stacked_borrows/unescaped_local.stderr b/tests/fail/stacked_borrows/unescaped_local.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/unescaped_local.stderr rename to tests/fail/stacked_borrows/unescaped_local.stderr diff --git a/tests/compile-fail/stacked_borrows/unescaped_static.rs b/tests/fail/stacked_borrows/unescaped_static.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/unescaped_static.rs rename to tests/fail/stacked_borrows/unescaped_static.rs diff --git a/tests/compile-fail/stacked_borrows/unescaped_static.stderr b/tests/fail/stacked_borrows/unescaped_static.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/unescaped_static.stderr rename to tests/fail/stacked_borrows/unescaped_static.stderr diff --git a/tests/compile-fail/stacked_borrows/zst_slice.rs b/tests/fail/stacked_borrows/zst_slice.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/zst_slice.rs rename to tests/fail/stacked_borrows/zst_slice.rs diff --git a/tests/compile-fail/stacked_borrows/zst_slice.stderr b/tests/fail/stacked_borrows/zst_slice.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/zst_slice.stderr rename to tests/fail/stacked_borrows/zst_slice.stderr diff --git a/tests/compile-fail/static_memory_modification1.rs b/tests/fail/static_memory_modification1.rs similarity index 100% rename from tests/compile-fail/static_memory_modification1.rs rename to tests/fail/static_memory_modification1.rs diff --git a/tests/compile-fail/static_memory_modification1.stderr b/tests/fail/static_memory_modification1.stderr similarity index 100% rename from tests/compile-fail/static_memory_modification1.stderr rename to tests/fail/static_memory_modification1.stderr diff --git a/tests/compile-fail/static_memory_modification2.rs b/tests/fail/static_memory_modification2.rs similarity index 100% rename from tests/compile-fail/static_memory_modification2.rs rename to tests/fail/static_memory_modification2.rs diff --git a/tests/compile-fail/static_memory_modification2.stderr b/tests/fail/static_memory_modification2.stderr similarity index 100% rename from tests/compile-fail/static_memory_modification2.stderr rename to tests/fail/static_memory_modification2.stderr diff --git a/tests/compile-fail/static_memory_modification3.rs b/tests/fail/static_memory_modification3.rs similarity index 100% rename from tests/compile-fail/static_memory_modification3.rs rename to tests/fail/static_memory_modification3.rs diff --git a/tests/compile-fail/static_memory_modification3.stderr b/tests/fail/static_memory_modification3.stderr similarity index 100% rename from tests/compile-fail/static_memory_modification3.stderr rename to tests/fail/static_memory_modification3.stderr diff --git a/tests/compile-fail/strict-provenance-offset.stderr b/tests/fail/strict-provenance-offset.stderr similarity index 100% rename from tests/compile-fail/strict-provenance-offset.stderr rename to tests/fail/strict-provenance-offset.stderr diff --git a/tests/compile-fail/strict_provenance_transmute.stderr b/tests/fail/strict_provenance_transmute.stderr similarity index 100% rename from tests/compile-fail/strict_provenance_transmute.stderr rename to tests/fail/strict_provenance_transmute.stderr diff --git a/tests/compile-fail/sync/libc_pthread_cond_double_destroy.rs b/tests/fail/sync/libc_pthread_cond_double_destroy.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_cond_double_destroy.rs rename to tests/fail/sync/libc_pthread_cond_double_destroy.rs diff --git a/tests/compile-fail/sync/libc_pthread_cond_double_destroy.stderr b/tests/fail/sync/libc_pthread_cond_double_destroy.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_cond_double_destroy.stderr rename to tests/fail/sync/libc_pthread_cond_double_destroy.stderr diff --git a/tests/compile-fail/sync/libc_pthread_condattr_double_destroy.rs b/tests/fail/sync/libc_pthread_condattr_double_destroy.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_condattr_double_destroy.rs rename to tests/fail/sync/libc_pthread_condattr_double_destroy.rs diff --git a/tests/compile-fail/sync/libc_pthread_condattr_double_destroy.stderr b/tests/fail/sync/libc_pthread_condattr_double_destroy.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_condattr_double_destroy.stderr rename to tests/fail/sync/libc_pthread_condattr_double_destroy.stderr diff --git a/tests/compile-fail/sync/libc_pthread_mutex_NULL_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_NULL_deadlock.rs rename to tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs diff --git a/tests/compile-fail/sync/libc_pthread_mutex_NULL_deadlock.stderr b/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_NULL_deadlock.stderr rename to tests/fail/sync/libc_pthread_mutex_NULL_deadlock.stderr diff --git a/tests/compile-fail/sync/libc_pthread_mutex_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_deadlock.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_deadlock.rs rename to tests/fail/sync/libc_pthread_mutex_deadlock.rs diff --git a/tests/compile-fail/sync/libc_pthread_mutex_deadlock.stderr b/tests/fail/sync/libc_pthread_mutex_deadlock.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_deadlock.stderr rename to tests/fail/sync/libc_pthread_mutex_deadlock.stderr diff --git a/tests/compile-fail/sync/libc_pthread_mutex_default_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_default_deadlock.rs rename to tests/fail/sync/libc_pthread_mutex_default_deadlock.rs diff --git a/tests/compile-fail/sync/libc_pthread_mutex_default_deadlock.stderr b/tests/fail/sync/libc_pthread_mutex_default_deadlock.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_default_deadlock.stderr rename to tests/fail/sync/libc_pthread_mutex_default_deadlock.stderr diff --git a/tests/compile-fail/sync/libc_pthread_mutex_destroy_locked.rs b/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_destroy_locked.rs rename to tests/fail/sync/libc_pthread_mutex_destroy_locked.rs diff --git a/tests/compile-fail/sync/libc_pthread_mutex_destroy_locked.stderr b/tests/fail/sync/libc_pthread_mutex_destroy_locked.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_destroy_locked.stderr rename to tests/fail/sync/libc_pthread_mutex_destroy_locked.stderr diff --git a/tests/compile-fail/sync/libc_pthread_mutex_double_destroy.rs b/tests/fail/sync/libc_pthread_mutex_double_destroy.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_double_destroy.rs rename to tests/fail/sync/libc_pthread_mutex_double_destroy.rs diff --git a/tests/compile-fail/sync/libc_pthread_mutex_double_destroy.stderr b/tests/fail/sync/libc_pthread_mutex_double_destroy.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_double_destroy.stderr rename to tests/fail/sync/libc_pthread_mutex_double_destroy.stderr diff --git a/tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.rs rename to tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs diff --git a/tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.stderr b/tests/fail/sync/libc_pthread_mutex_normal_deadlock.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.stderr rename to tests/fail/sync/libc_pthread_mutex_normal_deadlock.stderr diff --git a/tests/compile-fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs rename to tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs diff --git a/tests/compile-fail/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr rename to tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr diff --git a/tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.rs b/tests/fail/sync/libc_pthread_mutex_wrong_owner.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.rs rename to tests/fail/sync/libc_pthread_mutex_wrong_owner.rs diff --git a/tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.stderr b/tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.stderr rename to tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr diff --git a/tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.rs b/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.rs rename to tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs diff --git a/tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.stderr b/tests/fail/sync/libc_pthread_mutexattr_double_destroy.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.stderr rename to tests/fail/sync/libc_pthread_mutexattr_double_destroy.stderr diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_destroy_read_locked.rs b/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_destroy_read_locked.rs rename to tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_destroy_read_locked.stderr b/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_destroy_read_locked.stderr rename to tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.stderr diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_destroy_write_locked.rs b/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_destroy_write_locked.rs rename to tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_destroy_write_locked.stderr b/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_destroy_write_locked.stderr rename to tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.stderr diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.rs b/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.rs rename to tests/fail/sync/libc_pthread_rwlock_double_destroy.rs diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.stderr b/tests/fail/sync/libc_pthread_rwlock_double_destroy.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.stderr rename to tests/fail/sync/libc_pthread_rwlock_double_destroy.stderr diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs rename to tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr b/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr rename to tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_read_wrong_owner.rs b/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_read_wrong_owner.rs rename to tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr b/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr rename to tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_unlock_unlocked.rs b/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_unlock_unlocked.rs rename to tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_unlock_unlocked.stderr b/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_unlock_unlocked.stderr rename to tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.stderr diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock.rs b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock.rs rename to tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr rename to tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs rename to tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr rename to tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock.rs b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock.rs rename to tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr rename to tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs rename to tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr rename to tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_wrong_owner.rs b/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_write_wrong_owner.rs rename to tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr b/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr rename to tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr diff --git a/tests/compile-fail/too-big-slice.stderr b/tests/fail/too-big-slice.stderr similarity index 100% rename from tests/compile-fail/too-big-slice.stderr rename to tests/fail/too-big-slice.stderr diff --git a/tests/compile-fail/too-big-unsized.stderr b/tests/fail/too-big-unsized.stderr similarity index 100% rename from tests/compile-fail/too-big-unsized.stderr rename to tests/fail/too-big-unsized.stderr diff --git a/tests/compile-fail/transmute-pair-uninit.rs b/tests/fail/transmute-pair-uninit.rs similarity index 100% rename from tests/compile-fail/transmute-pair-uninit.rs rename to tests/fail/transmute-pair-uninit.rs diff --git a/tests/compile-fail/transmute-pair-uninit.stderr b/tests/fail/transmute-pair-uninit.stderr similarity index 100% rename from tests/compile-fail/transmute-pair-uninit.stderr rename to tests/fail/transmute-pair-uninit.stderr diff --git a/tests/compile-fail/transmute_fat1.rs b/tests/fail/transmute_fat1.rs similarity index 100% rename from tests/compile-fail/transmute_fat1.rs rename to tests/fail/transmute_fat1.rs diff --git a/tests/compile-fail/transmute_fat1.stderr b/tests/fail/transmute_fat1.stderr similarity index 100% rename from tests/compile-fail/transmute_fat1.stderr rename to tests/fail/transmute_fat1.stderr diff --git a/tests/compile-fail/type-too-large.rs b/tests/fail/type-too-large.rs similarity index 100% rename from tests/compile-fail/type-too-large.rs rename to tests/fail/type-too-large.rs diff --git a/tests/compile-fail/type-too-large.stderr b/tests/fail/type-too-large.stderr similarity index 100% rename from tests/compile-fail/type-too-large.stderr rename to tests/fail/type-too-large.stderr diff --git a/tests/compile-fail/unaligned_pointers/alignment.rs b/tests/fail/unaligned_pointers/alignment.rs similarity index 100% rename from tests/compile-fail/unaligned_pointers/alignment.rs rename to tests/fail/unaligned_pointers/alignment.rs diff --git a/tests/compile-fail/unaligned_pointers/alignment.stderr b/tests/fail/unaligned_pointers/alignment.stderr similarity index 100% rename from tests/compile-fail/unaligned_pointers/alignment.stderr rename to tests/fail/unaligned_pointers/alignment.stderr diff --git a/tests/compile-fail/unaligned_pointers/atomic_unaligned.rs b/tests/fail/unaligned_pointers/atomic_unaligned.rs similarity index 100% rename from tests/compile-fail/unaligned_pointers/atomic_unaligned.rs rename to tests/fail/unaligned_pointers/atomic_unaligned.rs diff --git a/tests/compile-fail/unaligned_pointers/atomic_unaligned.stderr b/tests/fail/unaligned_pointers/atomic_unaligned.stderr similarity index 100% rename from tests/compile-fail/unaligned_pointers/atomic_unaligned.stderr rename to tests/fail/unaligned_pointers/atomic_unaligned.stderr diff --git a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs b/tests/fail/unaligned_pointers/dyn_alignment.rs similarity index 100% rename from tests/compile-fail/unaligned_pointers/dyn_alignment.rs rename to tests/fail/unaligned_pointers/dyn_alignment.rs diff --git a/tests/compile-fail/unaligned_pointers/dyn_alignment.stderr b/tests/fail/unaligned_pointers/dyn_alignment.stderr similarity index 100% rename from tests/compile-fail/unaligned_pointers/dyn_alignment.stderr rename to tests/fail/unaligned_pointers/dyn_alignment.stderr diff --git a/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs b/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs similarity index 100% rename from tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs rename to tests/fail/unaligned_pointers/intptrcast_alignment_check.rs diff --git a/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.stderr b/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr similarity index 100% rename from tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.stderr rename to tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr diff --git a/tests/compile-fail/unaligned_pointers/reference_to_packed.rs b/tests/fail/unaligned_pointers/reference_to_packed.rs similarity index 100% rename from tests/compile-fail/unaligned_pointers/reference_to_packed.rs rename to tests/fail/unaligned_pointers/reference_to_packed.rs diff --git a/tests/compile-fail/unaligned_pointers/reference_to_packed.stderr b/tests/fail/unaligned_pointers/reference_to_packed.stderr similarity index 100% rename from tests/compile-fail/unaligned_pointers/reference_to_packed.stderr rename to tests/fail/unaligned_pointers/reference_to_packed.stderr diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs b/tests/fail/unaligned_pointers/unaligned_ptr1.rs similarity index 100% rename from tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs rename to tests/fail/unaligned_pointers/unaligned_ptr1.rs diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr1.stderr b/tests/fail/unaligned_pointers/unaligned_ptr1.stderr similarity index 100% rename from tests/compile-fail/unaligned_pointers/unaligned_ptr1.stderr rename to tests/fail/unaligned_pointers/unaligned_ptr1.stderr diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs b/tests/fail/unaligned_pointers/unaligned_ptr2.rs similarity index 100% rename from tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs rename to tests/fail/unaligned_pointers/unaligned_ptr2.rs diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr2.stderr b/tests/fail/unaligned_pointers/unaligned_ptr2.stderr similarity index 100% rename from tests/compile-fail/unaligned_pointers/unaligned_ptr2.stderr rename to tests/fail/unaligned_pointers/unaligned_ptr2.stderr diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs b/tests/fail/unaligned_pointers/unaligned_ptr3.rs similarity index 100% rename from tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs rename to tests/fail/unaligned_pointers/unaligned_ptr3.rs diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr3.stderr b/tests/fail/unaligned_pointers/unaligned_ptr3.stderr similarity index 100% rename from tests/compile-fail/unaligned_pointers/unaligned_ptr3.stderr rename to tests/fail/unaligned_pointers/unaligned_ptr3.stderr diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr4.rs b/tests/fail/unaligned_pointers/unaligned_ptr4.rs similarity index 100% rename from tests/compile-fail/unaligned_pointers/unaligned_ptr4.rs rename to tests/fail/unaligned_pointers/unaligned_ptr4.rs diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr4.stderr b/tests/fail/unaligned_pointers/unaligned_ptr4.stderr similarity index 100% rename from tests/compile-fail/unaligned_pointers/unaligned_ptr4.stderr rename to tests/fail/unaligned_pointers/unaligned_ptr4.stderr diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs b/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs similarity index 100% rename from tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs rename to tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.stderr b/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.stderr similarity index 100% rename from tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.stderr rename to tests/fail/unaligned_pointers/unaligned_ptr_addr_of.stderr diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs b/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs similarity index 100% rename from tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs rename to tests/fail/unaligned_pointers/unaligned_ptr_zst.rs diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.stderr b/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr similarity index 100% rename from tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.stderr rename to tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr diff --git a/tests/compile-fail/uninit_buffer.rs b/tests/fail/uninit_buffer.rs similarity index 100% rename from tests/compile-fail/uninit_buffer.rs rename to tests/fail/uninit_buffer.rs diff --git a/tests/compile-fail/uninit_buffer.stderr b/tests/fail/uninit_buffer.stderr similarity index 100% rename from tests/compile-fail/uninit_buffer.stderr rename to tests/fail/uninit_buffer.stderr diff --git a/tests/compile-fail/uninit_byte_read.rs b/tests/fail/uninit_byte_read.rs similarity index 100% rename from tests/compile-fail/uninit_byte_read.rs rename to tests/fail/uninit_byte_read.rs diff --git a/tests/compile-fail/uninit_byte_read.stderr b/tests/fail/uninit_byte_read.stderr similarity index 100% rename from tests/compile-fail/uninit_byte_read.stderr rename to tests/fail/uninit_byte_read.stderr diff --git a/tests/compile-fail/uninit_float.stderr b/tests/fail/uninit_float.stderr similarity index 100% rename from tests/compile-fail/uninit_float.stderr rename to tests/fail/uninit_float.stderr diff --git a/tests/compile-fail/uninit_integer.stderr b/tests/fail/uninit_integer.stderr similarity index 100% rename from tests/compile-fail/uninit_integer.stderr rename to tests/fail/uninit_integer.stderr diff --git a/tests/compile-fail/uninit_integer_signed.stderr b/tests/fail/uninit_integer_signed.stderr similarity index 100% rename from tests/compile-fail/uninit_integer_signed.stderr rename to tests/fail/uninit_integer_signed.stderr diff --git a/tests/compile-fail/uninit_raw_ptr.rs b/tests/fail/uninit_raw_ptr.rs similarity index 100% rename from tests/compile-fail/uninit_raw_ptr.rs rename to tests/fail/uninit_raw_ptr.rs diff --git a/tests/compile-fail/uninit_raw_ptr.stderr b/tests/fail/uninit_raw_ptr.stderr similarity index 100% rename from tests/compile-fail/uninit_raw_ptr.stderr rename to tests/fail/uninit_raw_ptr.stderr diff --git a/tests/compile-fail/unreachable.rs b/tests/fail/unreachable.rs similarity index 100% rename from tests/compile-fail/unreachable.rs rename to tests/fail/unreachable.rs diff --git a/tests/compile-fail/unreachable.stderr b/tests/fail/unreachable.stderr similarity index 100% rename from tests/compile-fail/unreachable.stderr rename to tests/fail/unreachable.stderr diff --git a/tests/compile-fail/unsupported_foreign_function.rs b/tests/fail/unsupported_foreign_function.rs similarity index 100% rename from tests/compile-fail/unsupported_foreign_function.rs rename to tests/fail/unsupported_foreign_function.rs diff --git a/tests/compile-fail/unsupported_foreign_function.stderr b/tests/fail/unsupported_foreign_function.stderr similarity index 100% rename from tests/compile-fail/unsupported_foreign_function.stderr rename to tests/fail/unsupported_foreign_function.stderr diff --git a/tests/compile-fail/unsupported_signal.rs b/tests/fail/unsupported_signal.rs similarity index 100% rename from tests/compile-fail/unsupported_signal.rs rename to tests/fail/unsupported_signal.rs diff --git a/tests/compile-fail/unsupported_signal.stderr b/tests/fail/unsupported_signal.stderr similarity index 100% rename from tests/compile-fail/unsupported_signal.stderr rename to tests/fail/unsupported_signal.stderr diff --git a/tests/compile-fail/validity/cast_fn_ptr1.rs b/tests/fail/validity/cast_fn_ptr1.rs similarity index 100% rename from tests/compile-fail/validity/cast_fn_ptr1.rs rename to tests/fail/validity/cast_fn_ptr1.rs diff --git a/tests/compile-fail/validity/cast_fn_ptr1.stderr b/tests/fail/validity/cast_fn_ptr1.stderr similarity index 100% rename from tests/compile-fail/validity/cast_fn_ptr1.stderr rename to tests/fail/validity/cast_fn_ptr1.stderr diff --git a/tests/compile-fail/validity/cast_fn_ptr2.rs b/tests/fail/validity/cast_fn_ptr2.rs similarity index 100% rename from tests/compile-fail/validity/cast_fn_ptr2.rs rename to tests/fail/validity/cast_fn_ptr2.rs diff --git a/tests/compile-fail/validity/cast_fn_ptr2.stderr b/tests/fail/validity/cast_fn_ptr2.stderr similarity index 100% rename from tests/compile-fail/validity/cast_fn_ptr2.stderr rename to tests/fail/validity/cast_fn_ptr2.stderr diff --git a/tests/compile-fail/validity/dangling_ref1.rs b/tests/fail/validity/dangling_ref1.rs similarity index 100% rename from tests/compile-fail/validity/dangling_ref1.rs rename to tests/fail/validity/dangling_ref1.rs diff --git a/tests/compile-fail/validity/dangling_ref1.stderr b/tests/fail/validity/dangling_ref1.stderr similarity index 100% rename from tests/compile-fail/validity/dangling_ref1.stderr rename to tests/fail/validity/dangling_ref1.stderr diff --git a/tests/compile-fail/validity/dangling_ref2.rs b/tests/fail/validity/dangling_ref2.rs similarity index 100% rename from tests/compile-fail/validity/dangling_ref2.rs rename to tests/fail/validity/dangling_ref2.rs diff --git a/tests/compile-fail/validity/dangling_ref2.stderr b/tests/fail/validity/dangling_ref2.stderr similarity index 100% rename from tests/compile-fail/validity/dangling_ref2.stderr rename to tests/fail/validity/dangling_ref2.stderr diff --git a/tests/compile-fail/validity/dangling_ref3.rs b/tests/fail/validity/dangling_ref3.rs similarity index 100% rename from tests/compile-fail/validity/dangling_ref3.rs rename to tests/fail/validity/dangling_ref3.rs diff --git a/tests/compile-fail/validity/dangling_ref3.stderr b/tests/fail/validity/dangling_ref3.stderr similarity index 100% rename from tests/compile-fail/validity/dangling_ref3.stderr rename to tests/fail/validity/dangling_ref3.stderr diff --git a/tests/compile-fail/validity/invalid_bool.rs b/tests/fail/validity/invalid_bool.rs similarity index 100% rename from tests/compile-fail/validity/invalid_bool.rs rename to tests/fail/validity/invalid_bool.rs diff --git a/tests/compile-fail/validity/invalid_bool.stderr b/tests/fail/validity/invalid_bool.stderr similarity index 100% rename from tests/compile-fail/validity/invalid_bool.stderr rename to tests/fail/validity/invalid_bool.stderr diff --git a/tests/compile-fail/validity/invalid_bool_uninit.rs b/tests/fail/validity/invalid_bool_uninit.rs similarity index 100% rename from tests/compile-fail/validity/invalid_bool_uninit.rs rename to tests/fail/validity/invalid_bool_uninit.rs diff --git a/tests/compile-fail/validity/invalid_bool_uninit.stderr b/tests/fail/validity/invalid_bool_uninit.stderr similarity index 100% rename from tests/compile-fail/validity/invalid_bool_uninit.stderr rename to tests/fail/validity/invalid_bool_uninit.stderr diff --git a/tests/compile-fail/validity/invalid_char.rs b/tests/fail/validity/invalid_char.rs similarity index 100% rename from tests/compile-fail/validity/invalid_char.rs rename to tests/fail/validity/invalid_char.rs diff --git a/tests/compile-fail/validity/invalid_char.stderr b/tests/fail/validity/invalid_char.stderr similarity index 100% rename from tests/compile-fail/validity/invalid_char.stderr rename to tests/fail/validity/invalid_char.stderr diff --git a/tests/compile-fail/validity/invalid_char_uninit.rs b/tests/fail/validity/invalid_char_uninit.rs similarity index 100% rename from tests/compile-fail/validity/invalid_char_uninit.rs rename to tests/fail/validity/invalid_char_uninit.rs diff --git a/tests/compile-fail/validity/invalid_char_uninit.stderr b/tests/fail/validity/invalid_char_uninit.stderr similarity index 100% rename from tests/compile-fail/validity/invalid_char_uninit.stderr rename to tests/fail/validity/invalid_char_uninit.stderr diff --git a/tests/compile-fail/validity/invalid_enum_tag.rs b/tests/fail/validity/invalid_enum_tag.rs similarity index 100% rename from tests/compile-fail/validity/invalid_enum_tag.rs rename to tests/fail/validity/invalid_enum_tag.rs diff --git a/tests/compile-fail/validity/invalid_enum_tag.stderr b/tests/fail/validity/invalid_enum_tag.stderr similarity index 100% rename from tests/compile-fail/validity/invalid_enum_tag.stderr rename to tests/fail/validity/invalid_enum_tag.stderr diff --git a/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs b/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs similarity index 100% rename from tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs rename to tests/fail/validity/invalid_enum_tag_256variants_uninit.rs diff --git a/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.stderr b/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr similarity index 100% rename from tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.stderr rename to tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr diff --git a/tests/compile-fail/validity/invalid_fnptr_null.rs b/tests/fail/validity/invalid_fnptr_null.rs similarity index 100% rename from tests/compile-fail/validity/invalid_fnptr_null.rs rename to tests/fail/validity/invalid_fnptr_null.rs diff --git a/tests/compile-fail/validity/invalid_fnptr_null.stderr b/tests/fail/validity/invalid_fnptr_null.stderr similarity index 100% rename from tests/compile-fail/validity/invalid_fnptr_null.stderr rename to tests/fail/validity/invalid_fnptr_null.stderr diff --git a/tests/compile-fail/validity/invalid_fnptr_uninit.rs b/tests/fail/validity/invalid_fnptr_uninit.rs similarity index 100% rename from tests/compile-fail/validity/invalid_fnptr_uninit.rs rename to tests/fail/validity/invalid_fnptr_uninit.rs diff --git a/tests/compile-fail/validity/invalid_fnptr_uninit.stderr b/tests/fail/validity/invalid_fnptr_uninit.stderr similarity index 100% rename from tests/compile-fail/validity/invalid_fnptr_uninit.stderr rename to tests/fail/validity/invalid_fnptr_uninit.stderr diff --git a/tests/compile-fail/validity/invalid_wide_raw.rs b/tests/fail/validity/invalid_wide_raw.rs similarity index 100% rename from tests/compile-fail/validity/invalid_wide_raw.rs rename to tests/fail/validity/invalid_wide_raw.rs diff --git a/tests/compile-fail/validity/invalid_wide_raw.stderr b/tests/fail/validity/invalid_wide_raw.stderr similarity index 100% rename from tests/compile-fail/validity/invalid_wide_raw.stderr rename to tests/fail/validity/invalid_wide_raw.stderr diff --git a/tests/compile-fail/validity/nonzero.rs b/tests/fail/validity/nonzero.rs similarity index 100% rename from tests/compile-fail/validity/nonzero.rs rename to tests/fail/validity/nonzero.rs diff --git a/tests/compile-fail/validity/nonzero.stderr b/tests/fail/validity/nonzero.stderr similarity index 100% rename from tests/compile-fail/validity/nonzero.stderr rename to tests/fail/validity/nonzero.stderr diff --git a/tests/compile-fail/validity/ptr_integer_array_transmute.rs b/tests/fail/validity/ptr_integer_array_transmute.rs similarity index 100% rename from tests/compile-fail/validity/ptr_integer_array_transmute.rs rename to tests/fail/validity/ptr_integer_array_transmute.rs diff --git a/tests/compile-fail/validity/ptr_integer_array_transmute.stderr b/tests/fail/validity/ptr_integer_array_transmute.stderr similarity index 100% rename from tests/compile-fail/validity/ptr_integer_array_transmute.stderr rename to tests/fail/validity/ptr_integer_array_transmute.stderr diff --git a/tests/compile-fail/validity/ptr_integer_transmute.rs b/tests/fail/validity/ptr_integer_transmute.rs similarity index 100% rename from tests/compile-fail/validity/ptr_integer_transmute.rs rename to tests/fail/validity/ptr_integer_transmute.rs diff --git a/tests/compile-fail/validity/ptr_integer_transmute.stderr b/tests/fail/validity/ptr_integer_transmute.stderr similarity index 100% rename from tests/compile-fail/validity/ptr_integer_transmute.stderr rename to tests/fail/validity/ptr_integer_transmute.stderr diff --git a/tests/compile-fail/validity/ref_to_uninhabited1.rs b/tests/fail/validity/ref_to_uninhabited1.rs similarity index 100% rename from tests/compile-fail/validity/ref_to_uninhabited1.rs rename to tests/fail/validity/ref_to_uninhabited1.rs diff --git a/tests/compile-fail/validity/ref_to_uninhabited1.stderr b/tests/fail/validity/ref_to_uninhabited1.stderr similarity index 100% rename from tests/compile-fail/validity/ref_to_uninhabited1.stderr rename to tests/fail/validity/ref_to_uninhabited1.stderr diff --git a/tests/compile-fail/validity/ref_to_uninhabited2.rs b/tests/fail/validity/ref_to_uninhabited2.rs similarity index 100% rename from tests/compile-fail/validity/ref_to_uninhabited2.rs rename to tests/fail/validity/ref_to_uninhabited2.rs diff --git a/tests/compile-fail/validity/ref_to_uninhabited2.stderr b/tests/fail/validity/ref_to_uninhabited2.stderr similarity index 100% rename from tests/compile-fail/validity/ref_to_uninhabited2.stderr rename to tests/fail/validity/ref_to_uninhabited2.stderr diff --git a/tests/compile-fail/validity/too-big-slice.rs b/tests/fail/validity/too-big-slice.rs similarity index 100% rename from tests/compile-fail/validity/too-big-slice.rs rename to tests/fail/validity/too-big-slice.rs diff --git a/tests/compile-fail/validity/too-big-slice.stderr b/tests/fail/validity/too-big-slice.stderr similarity index 100% rename from tests/compile-fail/validity/too-big-slice.stderr rename to tests/fail/validity/too-big-slice.stderr diff --git a/tests/compile-fail/validity/too-big-unsized.rs b/tests/fail/validity/too-big-unsized.rs similarity index 100% rename from tests/compile-fail/validity/too-big-unsized.rs rename to tests/fail/validity/too-big-unsized.rs diff --git a/tests/compile-fail/validity/too-big-unsized.stderr b/tests/fail/validity/too-big-unsized.stderr similarity index 100% rename from tests/compile-fail/validity/too-big-unsized.stderr rename to tests/fail/validity/too-big-unsized.stderr diff --git a/tests/compile-fail/validity/transmute_through_ptr.rs b/tests/fail/validity/transmute_through_ptr.rs similarity index 100% rename from tests/compile-fail/validity/transmute_through_ptr.rs rename to tests/fail/validity/transmute_through_ptr.rs diff --git a/tests/compile-fail/validity/transmute_through_ptr.stderr b/tests/fail/validity/transmute_through_ptr.stderr similarity index 100% rename from tests/compile-fail/validity/transmute_through_ptr.stderr rename to tests/fail/validity/transmute_through_ptr.stderr diff --git a/tests/compile-fail/validity/uninit_float.rs b/tests/fail/validity/uninit_float.rs similarity index 100% rename from tests/compile-fail/validity/uninit_float.rs rename to tests/fail/validity/uninit_float.rs diff --git a/tests/compile-fail/validity/uninit_float.stderr b/tests/fail/validity/uninit_float.stderr similarity index 100% rename from tests/compile-fail/validity/uninit_float.stderr rename to tests/fail/validity/uninit_float.stderr diff --git a/tests/compile-fail/validity/uninit_integer.rs b/tests/fail/validity/uninit_integer.rs similarity index 100% rename from tests/compile-fail/validity/uninit_integer.rs rename to tests/fail/validity/uninit_integer.rs diff --git a/tests/compile-fail/validity/uninit_integer.stderr b/tests/fail/validity/uninit_integer.stderr similarity index 100% rename from tests/compile-fail/validity/uninit_integer.stderr rename to tests/fail/validity/uninit_integer.stderr diff --git a/tests/compile-fail/validity/uninit_integer_signed.rs b/tests/fail/validity/uninit_integer_signed.rs similarity index 100% rename from tests/compile-fail/validity/uninit_integer_signed.rs rename to tests/fail/validity/uninit_integer_signed.rs diff --git a/tests/compile-fail/validity/uninit_integer_signed.stderr b/tests/fail/validity/uninit_integer_signed.stderr similarity index 100% rename from tests/compile-fail/validity/uninit_integer_signed.stderr rename to tests/fail/validity/uninit_integer_signed.stderr diff --git a/tests/compile-fail/zst1.rs b/tests/fail/zst1.rs similarity index 100% rename from tests/compile-fail/zst1.rs rename to tests/fail/zst1.rs diff --git a/tests/compile-fail/zst1.stderr b/tests/fail/zst1.stderr similarity index 100% rename from tests/compile-fail/zst1.stderr rename to tests/fail/zst1.stderr diff --git a/tests/compile-fail/zst2.rs b/tests/fail/zst2.rs similarity index 100% rename from tests/compile-fail/zst2.rs rename to tests/fail/zst2.rs diff --git a/tests/compile-fail/zst2.stderr b/tests/fail/zst2.stderr similarity index 100% rename from tests/compile-fail/zst2.stderr rename to tests/fail/zst2.stderr diff --git a/tests/compile-fail/zst3.rs b/tests/fail/zst3.rs similarity index 100% rename from tests/compile-fail/zst3.rs rename to tests/fail/zst3.rs diff --git a/tests/compile-fail/zst3.stderr b/tests/fail/zst3.stderr similarity index 100% rename from tests/compile-fail/zst3.stderr rename to tests/fail/zst3.stderr diff --git a/tests/run-fail/function_calls/exported_symbol_good_unwind.rs b/tests/panic/function_calls/exported_symbol_good_unwind.rs similarity index 100% rename from tests/run-fail/function_calls/exported_symbol_good_unwind.rs rename to tests/panic/function_calls/exported_symbol_good_unwind.rs diff --git a/tests/run-fail/function_calls/exported_symbol_good_unwind.stderr b/tests/panic/function_calls/exported_symbol_good_unwind.stderr similarity index 100% rename from tests/run-fail/function_calls/exported_symbol_good_unwind.stderr rename to tests/panic/function_calls/exported_symbol_good_unwind.stderr diff --git a/tests/run-fail/panic/div-by-zero-2.rs b/tests/panic/panic/div-by-zero-2.rs similarity index 100% rename from tests/run-fail/panic/div-by-zero-2.rs rename to tests/panic/panic/div-by-zero-2.rs diff --git a/tests/run-fail/panic/div-by-zero-2.stderr b/tests/panic/panic/div-by-zero-2.stderr similarity index 100% rename from tests/run-fail/panic/div-by-zero-2.stderr rename to tests/panic/panic/div-by-zero-2.stderr diff --git a/tests/run-fail/panic/overflowing-lsh-neg.rs b/tests/panic/panic/overflowing-lsh-neg.rs similarity index 100% rename from tests/run-fail/panic/overflowing-lsh-neg.rs rename to tests/panic/panic/overflowing-lsh-neg.rs diff --git a/tests/run-fail/panic/overflowing-lsh-neg.stderr b/tests/panic/panic/overflowing-lsh-neg.stderr similarity index 100% rename from tests/run-fail/panic/overflowing-lsh-neg.stderr rename to tests/panic/panic/overflowing-lsh-neg.stderr diff --git a/tests/run-fail/panic/overflowing-rsh-1.rs b/tests/panic/panic/overflowing-rsh-1.rs similarity index 100% rename from tests/run-fail/panic/overflowing-rsh-1.rs rename to tests/panic/panic/overflowing-rsh-1.rs diff --git a/tests/run-fail/panic/overflowing-rsh-1.stderr b/tests/panic/panic/overflowing-rsh-1.stderr similarity index 100% rename from tests/run-fail/panic/overflowing-rsh-1.stderr rename to tests/panic/panic/overflowing-rsh-1.stderr diff --git a/tests/run-fail/panic/overflowing-rsh-2.rs b/tests/panic/panic/overflowing-rsh-2.rs similarity index 100% rename from tests/run-fail/panic/overflowing-rsh-2.rs rename to tests/panic/panic/overflowing-rsh-2.rs diff --git a/tests/run-fail/panic/overflowing-rsh-2.stderr b/tests/panic/panic/overflowing-rsh-2.stderr similarity index 100% rename from tests/run-fail/panic/overflowing-rsh-2.stderr rename to tests/panic/panic/overflowing-rsh-2.stderr diff --git a/tests/run-fail/panic/panic1.rs b/tests/panic/panic/panic1.rs similarity index 100% rename from tests/run-fail/panic/panic1.rs rename to tests/panic/panic/panic1.rs diff --git a/tests/run-fail/panic/panic1.stderr b/tests/panic/panic/panic1.stderr similarity index 100% rename from tests/run-fail/panic/panic1.stderr rename to tests/panic/panic/panic1.stderr diff --git a/tests/run-fail/panic/panic2.rs b/tests/panic/panic/panic2.rs similarity index 100% rename from tests/run-fail/panic/panic2.rs rename to tests/panic/panic/panic2.rs diff --git a/tests/run-fail/panic/panic2.stderr b/tests/panic/panic/panic2.stderr similarity index 100% rename from tests/run-fail/panic/panic2.stderr rename to tests/panic/panic/panic2.stderr diff --git a/tests/run-fail/panic/panic3.rs b/tests/panic/panic/panic3.rs similarity index 100% rename from tests/run-fail/panic/panic3.rs rename to tests/panic/panic/panic3.rs diff --git a/tests/run-fail/panic/panic3.stderr b/tests/panic/panic/panic3.stderr similarity index 100% rename from tests/run-fail/panic/panic3.stderr rename to tests/panic/panic/panic3.stderr diff --git a/tests/run-fail/panic/panic4.rs b/tests/panic/panic/panic4.rs similarity index 100% rename from tests/run-fail/panic/panic4.rs rename to tests/panic/panic/panic4.rs diff --git a/tests/run-fail/panic/panic4.stderr b/tests/panic/panic/panic4.stderr similarity index 100% rename from tests/run-fail/panic/panic4.stderr rename to tests/panic/panic/panic4.stderr diff --git a/tests/run-fail/panic/unsupported_foreign_function.rs b/tests/panic/panic/unsupported_foreign_function.rs similarity index 100% rename from tests/run-fail/panic/unsupported_foreign_function.rs rename to tests/panic/panic/unsupported_foreign_function.rs diff --git a/tests/run-fail/panic/unsupported_foreign_function.stderr b/tests/panic/panic/unsupported_foreign_function.stderr similarity index 100% rename from tests/run-fail/panic/unsupported_foreign_function.stderr rename to tests/panic/panic/unsupported_foreign_function.stderr diff --git a/tests/run-fail/panic/unsupported_syscall.rs b/tests/panic/panic/unsupported_syscall.rs similarity index 100% rename from tests/run-fail/panic/unsupported_syscall.rs rename to tests/panic/panic/unsupported_syscall.rs diff --git a/tests/run-fail/panic/unsupported_syscall.stderr b/tests/panic/panic/unsupported_syscall.stderr similarity index 100% rename from tests/run-fail/panic/unsupported_syscall.stderr rename to tests/panic/panic/unsupported_syscall.stderr diff --git a/tests/run-fail/transmute_fat2.rs b/tests/panic/transmute_fat2.rs similarity index 100% rename from tests/run-fail/transmute_fat2.rs rename to tests/panic/transmute_fat2.rs diff --git a/tests/run-fail/transmute_fat2.stderr b/tests/panic/transmute_fat2.stderr similarity index 100% rename from tests/run-fail/transmute_fat2.stderr rename to tests/panic/transmute_fat2.stderr diff --git a/tests/run-pass/adjacent-allocs.rs b/tests/pass/adjacent-allocs.rs similarity index 100% rename from tests/run-pass/adjacent-allocs.rs rename to tests/pass/adjacent-allocs.rs diff --git a/tests/run-pass/align.rs b/tests/pass/align.rs similarity index 100% rename from tests/run-pass/align.rs rename to tests/pass/align.rs diff --git a/tests/run-pass/align_offset_symbolic.rs b/tests/pass/align_offset_symbolic.rs similarity index 100% rename from tests/run-pass/align_offset_symbolic.rs rename to tests/pass/align_offset_symbolic.rs diff --git a/tests/run-pass/align_offset_symbolic.stdout b/tests/pass/align_offset_symbolic.stdout similarity index 100% rename from tests/run-pass/align_offset_symbolic.stdout rename to tests/pass/align_offset_symbolic.stdout diff --git a/tests/run-pass/args.rs b/tests/pass/args.rs similarity index 100% rename from tests/run-pass/args.rs rename to tests/pass/args.rs diff --git a/tests/run-pass/args.stdout b/tests/pass/args.stdout similarity index 100% rename from tests/run-pass/args.stdout rename to tests/pass/args.stdout diff --git a/tests/run-pass/arrays.rs b/tests/pass/arrays.rs similarity index 100% rename from tests/run-pass/arrays.rs rename to tests/pass/arrays.rs diff --git a/tests/run-pass/arrays.stdout b/tests/pass/arrays.stdout similarity index 100% rename from tests/run-pass/arrays.stdout rename to tests/pass/arrays.stdout diff --git a/tests/run-pass/associated-const.rs b/tests/pass/associated-const.rs similarity index 100% rename from tests/run-pass/associated-const.rs rename to tests/pass/associated-const.rs diff --git a/tests/run-pass/assume_bug.rs b/tests/pass/assume_bug.rs similarity index 100% rename from tests/run-pass/assume_bug.rs rename to tests/pass/assume_bug.rs diff --git a/tests/run-pass/async-fn.rs b/tests/pass/async-fn.rs similarity index 100% rename from tests/run-pass/async-fn.rs rename to tests/pass/async-fn.rs diff --git a/tests/run-pass/atomic-compare-exchange-weak-never-fail.rs b/tests/pass/atomic-compare-exchange-weak-never-fail.rs similarity index 100% rename from tests/run-pass/atomic-compare-exchange-weak-never-fail.rs rename to tests/pass/atomic-compare-exchange-weak-never-fail.rs diff --git a/tests/run-pass/atomic.rs b/tests/pass/atomic.rs similarity index 100% rename from tests/run-pass/atomic.rs rename to tests/pass/atomic.rs diff --git a/tests/run-pass/available-parallelism.rs b/tests/pass/available-parallelism.rs similarity index 100% rename from tests/run-pass/available-parallelism.rs rename to tests/pass/available-parallelism.rs diff --git a/tests/run-pass/backtrace-api-v0.rs b/tests/pass/backtrace-api-v0.rs similarity index 100% rename from tests/run-pass/backtrace-api-v0.rs rename to tests/pass/backtrace-api-v0.rs diff --git a/tests/run-pass/backtrace-api-v0.stderr b/tests/pass/backtrace-api-v0.stderr similarity index 100% rename from tests/run-pass/backtrace-api-v0.stderr rename to tests/pass/backtrace-api-v0.stderr diff --git a/tests/run-pass/backtrace-api-v0.stdout b/tests/pass/backtrace-api-v0.stdout similarity index 100% rename from tests/run-pass/backtrace-api-v0.stdout rename to tests/pass/backtrace-api-v0.stdout diff --git a/tests/run-pass/backtrace-api-v1.rs b/tests/pass/backtrace-api-v1.rs similarity index 100% rename from tests/run-pass/backtrace-api-v1.rs rename to tests/pass/backtrace-api-v1.rs diff --git a/tests/run-pass/backtrace-api-v1.stderr b/tests/pass/backtrace-api-v1.stderr similarity index 100% rename from tests/run-pass/backtrace-api-v1.stderr rename to tests/pass/backtrace-api-v1.stderr diff --git a/tests/run-pass/backtrace-api-v1.stdout b/tests/pass/backtrace-api-v1.stdout similarity index 100% rename from tests/run-pass/backtrace-api-v1.stdout rename to tests/pass/backtrace-api-v1.stdout diff --git a/tests/run-pass/backtrace-std.rs b/tests/pass/backtrace-std.rs similarity index 100% rename from tests/run-pass/backtrace-std.rs rename to tests/pass/backtrace-std.rs diff --git a/tests/run-pass/backtrace-std.stderr b/tests/pass/backtrace-std.stderr similarity index 100% rename from tests/run-pass/backtrace-std.stderr rename to tests/pass/backtrace-std.stderr diff --git a/tests/run-pass/bad_substs.rs b/tests/pass/bad_substs.rs similarity index 100% rename from tests/run-pass/bad_substs.rs rename to tests/pass/bad_substs.rs diff --git a/tests/run-pass/binary-heap.rs b/tests/pass/binary-heap.rs similarity index 100% rename from tests/run-pass/binary-heap.rs rename to tests/pass/binary-heap.rs diff --git a/tests/run-pass/binops.rs b/tests/pass/binops.rs similarity index 100% rename from tests/run-pass/binops.rs rename to tests/pass/binops.rs diff --git a/tests/run-pass/bools.rs b/tests/pass/bools.rs similarity index 100% rename from tests/run-pass/bools.rs rename to tests/pass/bools.rs diff --git a/tests/run-pass/box.rs b/tests/pass/box.rs similarity index 100% rename from tests/run-pass/box.rs rename to tests/pass/box.rs diff --git a/tests/run-pass/box.stdout b/tests/pass/box.stdout similarity index 100% rename from tests/run-pass/box.stdout rename to tests/pass/box.stdout diff --git a/tests/run-pass/btreemap.rs b/tests/pass/btreemap.rs similarity index 100% rename from tests/run-pass/btreemap.rs rename to tests/pass/btreemap.rs diff --git a/tests/run-pass/c_enums.rs b/tests/pass/c_enums.rs similarity index 100% rename from tests/run-pass/c_enums.rs rename to tests/pass/c_enums.rs diff --git a/tests/run-pass/calloc.rs b/tests/pass/calloc.rs similarity index 100% rename from tests/run-pass/calloc.rs rename to tests/pass/calloc.rs diff --git a/tests/run-pass/calls.rs b/tests/pass/calls.rs similarity index 100% rename from tests/run-pass/calls.rs rename to tests/pass/calls.rs diff --git a/tests/run-pass/cast-rfc0401-vtable-kinds.rs b/tests/pass/cast-rfc0401-vtable-kinds.rs similarity index 100% rename from tests/run-pass/cast-rfc0401-vtable-kinds.rs rename to tests/pass/cast-rfc0401-vtable-kinds.rs diff --git a/tests/run-pass/cast_fn_ptr.rs b/tests/pass/cast_fn_ptr.rs similarity index 100% rename from tests/run-pass/cast_fn_ptr.rs rename to tests/pass/cast_fn_ptr.rs diff --git a/tests/run-pass/cast_fn_ptr_unsafe.rs b/tests/pass/cast_fn_ptr_unsafe.rs similarity index 100% rename from tests/run-pass/cast_fn_ptr_unsafe.rs rename to tests/pass/cast_fn_ptr_unsafe.rs diff --git a/tests/run-pass/catch.rs b/tests/pass/catch.rs similarity index 100% rename from tests/run-pass/catch.rs rename to tests/pass/catch.rs diff --git a/tests/run-pass/catch.stdout b/tests/pass/catch.stdout similarity index 100% rename from tests/run-pass/catch.stdout rename to tests/pass/catch.stdout diff --git a/tests/run-pass/cfg_miri.rs b/tests/pass/cfg_miri.rs similarity index 100% rename from tests/run-pass/cfg_miri.rs rename to tests/pass/cfg_miri.rs diff --git a/tests/run-pass/char.rs b/tests/pass/char.rs similarity index 100% rename from tests/run-pass/char.rs rename to tests/pass/char.rs diff --git a/tests/run-pass/closure-drop.rs b/tests/pass/closure-drop.rs similarity index 100% rename from tests/run-pass/closure-drop.rs rename to tests/pass/closure-drop.rs diff --git a/tests/run-pass/closure-field-ty.rs b/tests/pass/closure-field-ty.rs similarity index 100% rename from tests/run-pass/closure-field-ty.rs rename to tests/pass/closure-field-ty.rs diff --git a/tests/run-pass/closures.rs b/tests/pass/closures.rs similarity index 100% rename from tests/run-pass/closures.rs rename to tests/pass/closures.rs diff --git a/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs b/tests/pass/coerce_non_capture_closure_to_fn_ptr.rs similarity index 100% rename from tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs rename to tests/pass/coerce_non_capture_closure_to_fn_ptr.rs diff --git a/tests/run-pass/coercions.rs b/tests/pass/coercions.rs similarity index 100% rename from tests/run-pass/coercions.rs rename to tests/pass/coercions.rs diff --git a/tests/run-pass/concurrency/channels.rs b/tests/pass/concurrency/channels.rs similarity index 100% rename from tests/run-pass/concurrency/channels.rs rename to tests/pass/concurrency/channels.rs diff --git a/tests/run-pass/concurrency/channels.stderr b/tests/pass/concurrency/channels.stderr similarity index 100% rename from tests/run-pass/concurrency/channels.stderr rename to tests/pass/concurrency/channels.stderr diff --git a/tests/run-pass/concurrency/concurrent_caller_location.rs b/tests/pass/concurrency/concurrent_caller_location.rs similarity index 100% rename from tests/run-pass/concurrency/concurrent_caller_location.rs rename to tests/pass/concurrency/concurrent_caller_location.rs diff --git a/tests/run-pass/concurrency/concurrent_caller_location.stderr b/tests/pass/concurrency/concurrent_caller_location.stderr similarity index 100% rename from tests/run-pass/concurrency/concurrent_caller_location.stderr rename to tests/pass/concurrency/concurrent_caller_location.stderr diff --git a/tests/run-pass/concurrency/data_race.rs b/tests/pass/concurrency/data_race.rs similarity index 100% rename from tests/run-pass/concurrency/data_race.rs rename to tests/pass/concurrency/data_race.rs diff --git a/tests/run-pass/concurrency/data_race.stderr b/tests/pass/concurrency/data_race.stderr similarity index 100% rename from tests/run-pass/concurrency/data_race.stderr rename to tests/pass/concurrency/data_race.stderr diff --git a/tests/run-pass/concurrency/disable_data_race_detector.rs b/tests/pass/concurrency/disable_data_race_detector.rs similarity index 100% rename from tests/run-pass/concurrency/disable_data_race_detector.rs rename to tests/pass/concurrency/disable_data_race_detector.rs diff --git a/tests/run-pass/concurrency/disable_data_race_detector.stderr b/tests/pass/concurrency/disable_data_race_detector.stderr similarity index 100% rename from tests/run-pass/concurrency/disable_data_race_detector.stderr rename to tests/pass/concurrency/disable_data_race_detector.stderr diff --git a/tests/run-pass/concurrency/issue1643.rs b/tests/pass/concurrency/issue1643.rs similarity index 100% rename from tests/run-pass/concurrency/issue1643.rs rename to tests/pass/concurrency/issue1643.rs diff --git a/tests/run-pass/concurrency/issue1643.stderr b/tests/pass/concurrency/issue1643.stderr similarity index 100% rename from tests/run-pass/concurrency/issue1643.stderr rename to tests/pass/concurrency/issue1643.stderr diff --git a/tests/run-pass/concurrency/libc_pthread_cond.rs b/tests/pass/concurrency/libc_pthread_cond.rs similarity index 100% rename from tests/run-pass/concurrency/libc_pthread_cond.rs rename to tests/pass/concurrency/libc_pthread_cond.rs diff --git a/tests/run-pass/concurrency/linux-futex.rs b/tests/pass/concurrency/linux-futex.rs similarity index 100% rename from tests/run-pass/concurrency/linux-futex.rs rename to tests/pass/concurrency/linux-futex.rs diff --git a/tests/run-pass/concurrency/linux-futex.stderr b/tests/pass/concurrency/linux-futex.stderr similarity index 100% rename from tests/run-pass/concurrency/linux-futex.stderr rename to tests/pass/concurrency/linux-futex.stderr diff --git a/tests/run-pass/concurrency/simple.rs b/tests/pass/concurrency/simple.rs similarity index 100% rename from tests/run-pass/concurrency/simple.rs rename to tests/pass/concurrency/simple.rs diff --git a/tests/run-pass/concurrency/simple.stderr b/tests/pass/concurrency/simple.stderr similarity index 100% rename from tests/run-pass/concurrency/simple.stderr rename to tests/pass/concurrency/simple.stderr diff --git a/tests/run-pass/concurrency/sync.rs b/tests/pass/concurrency/sync.rs similarity index 100% rename from tests/run-pass/concurrency/sync.rs rename to tests/pass/concurrency/sync.rs diff --git a/tests/run-pass/concurrency/sync.stderr b/tests/pass/concurrency/sync.stderr similarity index 100% rename from tests/run-pass/concurrency/sync.stderr rename to tests/pass/concurrency/sync.stderr diff --git a/tests/run-pass/concurrency/sync.stdout b/tests/pass/concurrency/sync.stdout similarity index 100% rename from tests/run-pass/concurrency/sync.stdout rename to tests/pass/concurrency/sync.stdout diff --git a/tests/run-pass/concurrency/sync_singlethread.rs b/tests/pass/concurrency/sync_singlethread.rs similarity index 100% rename from tests/run-pass/concurrency/sync_singlethread.rs rename to tests/pass/concurrency/sync_singlethread.rs diff --git a/tests/run-pass/concurrency/thread_locals.rs b/tests/pass/concurrency/thread_locals.rs similarity index 100% rename from tests/run-pass/concurrency/thread_locals.rs rename to tests/pass/concurrency/thread_locals.rs diff --git a/tests/run-pass/concurrency/thread_locals.stderr b/tests/pass/concurrency/thread_locals.stderr similarity index 100% rename from tests/run-pass/concurrency/thread_locals.stderr rename to tests/pass/concurrency/thread_locals.stderr diff --git a/tests/run-pass/concurrency/tls_lib_drop.rs b/tests/pass/concurrency/tls_lib_drop.rs similarity index 100% rename from tests/run-pass/concurrency/tls_lib_drop.rs rename to tests/pass/concurrency/tls_lib_drop.rs diff --git a/tests/run-pass/concurrency/tls_lib_drop.stderr b/tests/pass/concurrency/tls_lib_drop.stderr similarity index 100% rename from tests/run-pass/concurrency/tls_lib_drop.stderr rename to tests/pass/concurrency/tls_lib_drop.stderr diff --git a/tests/run-pass/concurrency/tls_lib_drop.stdout b/tests/pass/concurrency/tls_lib_drop.stdout similarity index 100% rename from tests/run-pass/concurrency/tls_lib_drop.stdout rename to tests/pass/concurrency/tls_lib_drop.stdout diff --git a/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs b/tests/pass/concurrency/tls_lib_drop_single_thread.rs similarity index 100% rename from tests/run-pass/concurrency/tls_lib_drop_single_thread.rs rename to tests/pass/concurrency/tls_lib_drop_single_thread.rs diff --git a/tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr b/tests/pass/concurrency/tls_lib_drop_single_thread.stderr similarity index 100% rename from tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr rename to tests/pass/concurrency/tls_lib_drop_single_thread.stderr diff --git a/tests/run-pass/concurrency/tls_pthread_drop_order.rs b/tests/pass/concurrency/tls_pthread_drop_order.rs similarity index 100% rename from tests/run-pass/concurrency/tls_pthread_drop_order.rs rename to tests/pass/concurrency/tls_pthread_drop_order.rs diff --git a/tests/run-pass/const-vec-of-fns.rs b/tests/pass/const-vec-of-fns.rs similarity index 100% rename from tests/run-pass/const-vec-of-fns.rs rename to tests/pass/const-vec-of-fns.rs diff --git a/tests/run-pass/constants.rs b/tests/pass/constants.rs similarity index 100% rename from tests/run-pass/constants.rs rename to tests/pass/constants.rs diff --git a/tests/run-pass/current_dir.rs b/tests/pass/current_dir.rs similarity index 100% rename from tests/run-pass/current_dir.rs rename to tests/pass/current_dir.rs diff --git a/tests/run-pass/current_dir_with_isolation.rs b/tests/pass/current_dir_with_isolation.rs similarity index 100% rename from tests/run-pass/current_dir_with_isolation.rs rename to tests/pass/current_dir_with_isolation.rs diff --git a/tests/run-pass/current_dir_with_isolation.stderr b/tests/pass/current_dir_with_isolation.stderr similarity index 100% rename from tests/run-pass/current_dir_with_isolation.stderr rename to tests/pass/current_dir_with_isolation.stderr diff --git a/tests/run-pass/deriving-associated-types.rs b/tests/pass/deriving-associated-types.rs similarity index 100% rename from tests/run-pass/deriving-associated-types.rs rename to tests/pass/deriving-associated-types.rs diff --git a/tests/run-pass/disable-alignment-check.rs b/tests/pass/disable-alignment-check.rs similarity index 100% rename from tests/run-pass/disable-alignment-check.rs rename to tests/pass/disable-alignment-check.rs diff --git a/tests/run-pass/drop_empty_slice.rs b/tests/pass/drop_empty_slice.rs similarity index 100% rename from tests/run-pass/drop_empty_slice.rs rename to tests/pass/drop_empty_slice.rs diff --git a/tests/run-pass/drop_on_array_elements.rs b/tests/pass/drop_on_array_elements.rs similarity index 100% rename from tests/run-pass/drop_on_array_elements.rs rename to tests/pass/drop_on_array_elements.rs diff --git a/tests/run-pass/drop_on_fat_ptr_array_elements.rs b/tests/pass/drop_on_fat_ptr_array_elements.rs similarity index 100% rename from tests/run-pass/drop_on_fat_ptr_array_elements.rs rename to tests/pass/drop_on_fat_ptr_array_elements.rs diff --git a/tests/run-pass/drop_on_zst_array_elements.rs b/tests/pass/drop_on_zst_array_elements.rs similarity index 100% rename from tests/run-pass/drop_on_zst_array_elements.rs rename to tests/pass/drop_on_zst_array_elements.rs diff --git a/tests/run-pass/drop_through_owned_slice.rs b/tests/pass/drop_through_owned_slice.rs similarity index 100% rename from tests/run-pass/drop_through_owned_slice.rs rename to tests/pass/drop_through_owned_slice.rs diff --git a/tests/run-pass/drop_through_trait_object.rs b/tests/pass/drop_through_trait_object.rs similarity index 100% rename from tests/run-pass/drop_through_trait_object.rs rename to tests/pass/drop_through_trait_object.rs diff --git a/tests/run-pass/drop_through_trait_object_rc.rs b/tests/pass/drop_through_trait_object_rc.rs similarity index 100% rename from tests/run-pass/drop_through_trait_object_rc.rs rename to tests/pass/drop_through_trait_object_rc.rs diff --git a/tests/run-pass/dst-field-align.rs b/tests/pass/dst-field-align.rs similarity index 100% rename from tests/run-pass/dst-field-align.rs rename to tests/pass/dst-field-align.rs diff --git a/tests/run-pass/dst-irrefutable-bind.rs b/tests/pass/dst-irrefutable-bind.rs similarity index 100% rename from tests/run-pass/dst-irrefutable-bind.rs rename to tests/pass/dst-irrefutable-bind.rs diff --git a/tests/run-pass/dst-raw.rs b/tests/pass/dst-raw.rs similarity index 100% rename from tests/run-pass/dst-raw.rs rename to tests/pass/dst-raw.rs diff --git a/tests/run-pass/dst-struct-sole.rs b/tests/pass/dst-struct-sole.rs similarity index 100% rename from tests/run-pass/dst-struct-sole.rs rename to tests/pass/dst-struct-sole.rs diff --git a/tests/run-pass/dst-struct.rs b/tests/pass/dst-struct.rs similarity index 100% rename from tests/run-pass/dst-struct.rs rename to tests/pass/dst-struct.rs diff --git a/tests/run-pass/dyn-arbitrary-self.rs b/tests/pass/dyn-arbitrary-self.rs similarity index 100% rename from tests/run-pass/dyn-arbitrary-self.rs rename to tests/pass/dyn-arbitrary-self.rs diff --git a/tests/run-pass/dyn-traits.rs b/tests/pass/dyn-traits.rs similarity index 100% rename from tests/run-pass/dyn-traits.rs rename to tests/pass/dyn-traits.rs diff --git a/tests/run-pass/enum-nullable-const-null-with-fields.rs b/tests/pass/enum-nullable-const-null-with-fields.rs similarity index 100% rename from tests/run-pass/enum-nullable-const-null-with-fields.rs rename to tests/pass/enum-nullable-const-null-with-fields.rs diff --git a/tests/run-pass/enum_discriminant_ptr_value.rs b/tests/pass/enum_discriminant_ptr_value.rs similarity index 100% rename from tests/run-pass/enum_discriminant_ptr_value.rs rename to tests/pass/enum_discriminant_ptr_value.rs diff --git a/tests/run-pass/enums.rs b/tests/pass/enums.rs similarity index 100% rename from tests/run-pass/enums.rs rename to tests/pass/enums.rs diff --git a/tests/run-pass/env-exclude.rs b/tests/pass/env-exclude.rs similarity index 100% rename from tests/run-pass/env-exclude.rs rename to tests/pass/env-exclude.rs diff --git a/tests/run-pass/env-forward.rs b/tests/pass/env-forward.rs similarity index 100% rename from tests/run-pass/env-forward.rs rename to tests/pass/env-forward.rs diff --git a/tests/run-pass/env-without-isolation.rs b/tests/pass/env-without-isolation.rs similarity index 100% rename from tests/run-pass/env-without-isolation.rs rename to tests/pass/env-without-isolation.rs diff --git a/tests/run-pass/env.rs b/tests/pass/env.rs similarity index 100% rename from tests/run-pass/env.rs rename to tests/pass/env.rs diff --git a/tests/run-pass/env.stdout b/tests/pass/env.stdout similarity index 100% rename from tests/run-pass/env.stdout rename to tests/pass/env.stdout diff --git a/tests/run-pass/exit.rs b/tests/pass/exit.rs similarity index 100% rename from tests/run-pass/exit.rs rename to tests/pass/exit.rs diff --git a/tests/run-pass/extern_crate_std_in_main.rs b/tests/pass/extern_crate_std_in_main.rs similarity index 100% rename from tests/run-pass/extern_crate_std_in_main.rs rename to tests/pass/extern_crate_std_in_main.rs diff --git a/tests/run-pass/extern_types.rs b/tests/pass/extern_types.rs similarity index 100% rename from tests/run-pass/extern_types.rs rename to tests/pass/extern_types.rs diff --git a/tests/run-pass/fat_ptr.rs b/tests/pass/fat_ptr.rs similarity index 100% rename from tests/run-pass/fat_ptr.rs rename to tests/pass/fat_ptr.rs diff --git a/tests/run-pass/float.rs b/tests/pass/float.rs similarity index 100% rename from tests/run-pass/float.rs rename to tests/pass/float.rs diff --git a/tests/run-pass/float_fast_math.rs b/tests/pass/float_fast_math.rs similarity index 100% rename from tests/run-pass/float_fast_math.rs rename to tests/pass/float_fast_math.rs diff --git a/tests/run-pass/foreign-fn-linkname.rs b/tests/pass/foreign-fn-linkname.rs similarity index 100% rename from tests/run-pass/foreign-fn-linkname.rs rename to tests/pass/foreign-fn-linkname.rs diff --git a/tests/run-pass/format.rs b/tests/pass/format.rs similarity index 100% rename from tests/run-pass/format.rs rename to tests/pass/format.rs diff --git a/tests/run-pass/format.stdout b/tests/pass/format.stdout similarity index 100% rename from tests/run-pass/format.stdout rename to tests/pass/format.stdout diff --git a/tests/run-pass/from_utf8.rs b/tests/pass/from_utf8.rs similarity index 100% rename from tests/run-pass/from_utf8.rs rename to tests/pass/from_utf8.rs diff --git a/tests/run-pass/fs.rs b/tests/pass/fs.rs similarity index 100% rename from tests/run-pass/fs.rs rename to tests/pass/fs.rs diff --git a/tests/run-pass/fs.stderr b/tests/pass/fs.stderr similarity index 100% rename from tests/run-pass/fs.stderr rename to tests/pass/fs.stderr diff --git a/tests/run-pass/fs.stdout b/tests/pass/fs.stdout similarity index 100% rename from tests/run-pass/fs.stdout rename to tests/pass/fs.stdout diff --git a/tests/run-pass/fs_with_isolation.rs b/tests/pass/fs_with_isolation.rs similarity index 100% rename from tests/run-pass/fs_with_isolation.rs rename to tests/pass/fs_with_isolation.rs diff --git a/tests/run-pass/fs_with_isolation.stderr b/tests/pass/fs_with_isolation.stderr similarity index 100% rename from tests/run-pass/fs_with_isolation.stderr rename to tests/pass/fs_with_isolation.stderr diff --git a/tests/run-pass/function_calls/disable_abi_check.rs b/tests/pass/function_calls/disable_abi_check.rs similarity index 100% rename from tests/run-pass/function_calls/disable_abi_check.rs rename to tests/pass/function_calls/disable_abi_check.rs diff --git a/tests/run-pass/function_calls/exported_symbol.rs b/tests/pass/function_calls/exported_symbol.rs similarity index 100% rename from tests/run-pass/function_calls/exported_symbol.rs rename to tests/pass/function_calls/exported_symbol.rs diff --git a/tests/run-pass/function_pointers.rs b/tests/pass/function_pointers.rs similarity index 100% rename from tests/run-pass/function_pointers.rs rename to tests/pass/function_pointers.rs diff --git a/tests/run-pass/generator.rs b/tests/pass/generator.rs similarity index 100% rename from tests/run-pass/generator.rs rename to tests/pass/generator.rs diff --git a/tests/run-pass/global_allocator.rs b/tests/pass/global_allocator.rs similarity index 100% rename from tests/run-pass/global_allocator.rs rename to tests/pass/global_allocator.rs diff --git a/tests/run-pass/global_allocator.stdout b/tests/pass/global_allocator.stdout similarity index 100% rename from tests/run-pass/global_allocator.stdout rename to tests/pass/global_allocator.stdout diff --git a/tests/run-pass/hashmap.rs b/tests/pass/hashmap.rs similarity index 100% rename from tests/run-pass/hashmap.rs rename to tests/pass/hashmap.rs diff --git a/tests/run-pass/heap.rs b/tests/pass/heap.rs similarity index 100% rename from tests/run-pass/heap.rs rename to tests/pass/heap.rs diff --git a/tests/run-pass/heap_allocator.rs b/tests/pass/heap_allocator.rs similarity index 100% rename from tests/run-pass/heap_allocator.rs rename to tests/pass/heap_allocator.rs diff --git a/tests/run-pass/hello.rs b/tests/pass/hello.rs similarity index 100% rename from tests/run-pass/hello.rs rename to tests/pass/hello.rs diff --git a/tests/run-pass/hello.stdout b/tests/pass/hello.stdout similarity index 100% rename from tests/run-pass/hello.stdout rename to tests/pass/hello.stdout diff --git a/tests/run-pass/hide_stdout.rs b/tests/pass/hide_stdout.rs similarity index 100% rename from tests/run-pass/hide_stdout.rs rename to tests/pass/hide_stdout.rs diff --git a/tests/run-pass/integer-ops.rs b/tests/pass/integer-ops.rs similarity index 100% rename from tests/run-pass/integer-ops.rs rename to tests/pass/integer-ops.rs diff --git a/tests/run-pass/intptrcast.rs b/tests/pass/intptrcast.rs similarity index 100% rename from tests/run-pass/intptrcast.rs rename to tests/pass/intptrcast.rs diff --git a/tests/run-pass/intrinsics-integer.rs b/tests/pass/intrinsics-integer.rs similarity index 100% rename from tests/run-pass/intrinsics-integer.rs rename to tests/pass/intrinsics-integer.rs diff --git a/tests/run-pass/intrinsics-math.rs b/tests/pass/intrinsics-math.rs similarity index 100% rename from tests/run-pass/intrinsics-math.rs rename to tests/pass/intrinsics-math.rs diff --git a/tests/run-pass/intrinsics-x86.rs b/tests/pass/intrinsics-x86.rs similarity index 100% rename from tests/run-pass/intrinsics-x86.rs rename to tests/pass/intrinsics-x86.rs diff --git a/tests/run-pass/intrinsics.rs b/tests/pass/intrinsics.rs similarity index 100% rename from tests/run-pass/intrinsics.rs rename to tests/pass/intrinsics.rs diff --git a/tests/run-pass/ints.rs b/tests/pass/ints.rs similarity index 100% rename from tests/run-pass/ints.rs rename to tests/pass/ints.rs diff --git a/tests/run-pass/issue-15063.rs b/tests/pass/issue-15063.rs similarity index 100% rename from tests/run-pass/issue-15063.rs rename to tests/pass/issue-15063.rs diff --git a/tests/run-pass/issue-15080.rs b/tests/pass/issue-15080.rs similarity index 100% rename from tests/run-pass/issue-15080.rs rename to tests/pass/issue-15080.rs diff --git a/tests/run-pass/issue-15523-big.rs b/tests/pass/issue-15523-big.rs similarity index 100% rename from tests/run-pass/issue-15523-big.rs rename to tests/pass/issue-15523-big.rs diff --git a/tests/run-pass/issue-17877.rs b/tests/pass/issue-17877.rs similarity index 100% rename from tests/run-pass/issue-17877.rs rename to tests/pass/issue-17877.rs diff --git a/tests/run-pass/issue-20575.rs b/tests/pass/issue-20575.rs similarity index 100% rename from tests/run-pass/issue-20575.rs rename to tests/pass/issue-20575.rs diff --git a/tests/run-pass/issue-23261.rs b/tests/pass/issue-23261.rs similarity index 100% rename from tests/run-pass/issue-23261.rs rename to tests/pass/issue-23261.rs diff --git a/tests/run-pass/issue-26709.rs b/tests/pass/issue-26709.rs similarity index 100% rename from tests/run-pass/issue-26709.rs rename to tests/pass/issue-26709.rs diff --git a/tests/run-pass/issue-27901.rs b/tests/pass/issue-27901.rs similarity index 100% rename from tests/run-pass/issue-27901.rs rename to tests/pass/issue-27901.rs diff --git a/tests/run-pass/issue-29746.rs b/tests/pass/issue-29746.rs similarity index 100% rename from tests/run-pass/issue-29746.rs rename to tests/pass/issue-29746.rs diff --git a/tests/run-pass/issue-30530.rs b/tests/pass/issue-30530.rs similarity index 100% rename from tests/run-pass/issue-30530.rs rename to tests/pass/issue-30530.rs diff --git a/tests/run-pass/issue-31267-additional.rs b/tests/pass/issue-31267-additional.rs similarity index 100% rename from tests/run-pass/issue-31267-additional.rs rename to tests/pass/issue-31267-additional.rs diff --git a/tests/run-pass/issue-33387.rs b/tests/pass/issue-33387.rs similarity index 100% rename from tests/run-pass/issue-33387.rs rename to tests/pass/issue-33387.rs diff --git a/tests/run-pass/issue-34571.rs b/tests/pass/issue-34571.rs similarity index 100% rename from tests/run-pass/issue-34571.rs rename to tests/pass/issue-34571.rs diff --git a/tests/run-pass/issue-35815.rs b/tests/pass/issue-35815.rs similarity index 100% rename from tests/run-pass/issue-35815.rs rename to tests/pass/issue-35815.rs diff --git a/tests/run-pass/issue-36278-prefix-nesting.rs b/tests/pass/issue-36278-prefix-nesting.rs similarity index 100% rename from tests/run-pass/issue-36278-prefix-nesting.rs rename to tests/pass/issue-36278-prefix-nesting.rs diff --git a/tests/run-pass/issue-3794.rs b/tests/pass/issue-3794.rs similarity index 100% rename from tests/run-pass/issue-3794.rs rename to tests/pass/issue-3794.rs diff --git a/tests/run-pass/issue-3794.stdout b/tests/pass/issue-3794.stdout similarity index 100% rename from tests/run-pass/issue-3794.stdout rename to tests/pass/issue-3794.stdout diff --git a/tests/run-pass/issue-53728.rs b/tests/pass/issue-53728.rs similarity index 100% rename from tests/run-pass/issue-53728.rs rename to tests/pass/issue-53728.rs diff --git a/tests/run-pass/issue-5917.rs b/tests/pass/issue-5917.rs similarity index 100% rename from tests/run-pass/issue-5917.rs rename to tests/pass/issue-5917.rs diff --git a/tests/run-pass/issue-73223.rs b/tests/pass/issue-73223.rs similarity index 100% rename from tests/run-pass/issue-73223.rs rename to tests/pass/issue-73223.rs diff --git a/tests/run-pass/issue-91636.rs b/tests/pass/issue-91636.rs similarity index 100% rename from tests/run-pass/issue-91636.rs rename to tests/pass/issue-91636.rs diff --git a/tests/run-pass/issue-94371.rs b/tests/pass/issue-94371.rs similarity index 100% rename from tests/run-pass/issue-94371.rs rename to tests/pass/issue-94371.rs diff --git a/tests/run-pass/issue-miri-1075.rs b/tests/pass/issue-miri-1075.rs similarity index 100% rename from tests/run-pass/issue-miri-1075.rs rename to tests/pass/issue-miri-1075.rs diff --git a/tests/run-pass/issue-miri-133.rs b/tests/pass/issue-miri-133.rs similarity index 100% rename from tests/run-pass/issue-miri-133.rs rename to tests/pass/issue-miri-133.rs diff --git a/tests/run-pass/issue-miri-184.rs b/tests/pass/issue-miri-184.rs similarity index 100% rename from tests/run-pass/issue-miri-184.rs rename to tests/pass/issue-miri-184.rs diff --git a/tests/run-pass/issue-miri-1925.rs b/tests/pass/issue-miri-1925.rs similarity index 100% rename from tests/run-pass/issue-miri-1925.rs rename to tests/pass/issue-miri-1925.rs diff --git a/tests/run-pass/issue-miri-2068-2.rs b/tests/pass/issue-miri-2068-2.rs similarity index 100% rename from tests/run-pass/issue-miri-2068-2.rs rename to tests/pass/issue-miri-2068-2.rs diff --git a/tests/run-pass/issue-miri-2068.rs b/tests/pass/issue-miri-2068.rs similarity index 100% rename from tests/run-pass/issue-miri-2068.rs rename to tests/pass/issue-miri-2068.rs diff --git a/tests/run-pass/iter.rs b/tests/pass/iter.rs similarity index 100% rename from tests/run-pass/iter.rs rename to tests/pass/iter.rs diff --git a/tests/run-pass/last-use-in-cap-clause.rs b/tests/pass/last-use-in-cap-clause.rs similarity index 100% rename from tests/run-pass/last-use-in-cap-clause.rs rename to tests/pass/last-use-in-cap-clause.rs diff --git a/tests/run-pass/leak-in-static.rs b/tests/pass/leak-in-static.rs similarity index 100% rename from tests/run-pass/leak-in-static.rs rename to tests/pass/leak-in-static.rs diff --git a/tests/run-pass/libc.rs b/tests/pass/libc.rs similarity index 100% rename from tests/run-pass/libc.rs rename to tests/pass/libc.rs diff --git a/tests/run-pass/libc.stderr b/tests/pass/libc.stderr similarity index 100% rename from tests/run-pass/libc.stderr rename to tests/pass/libc.stderr diff --git a/tests/run-pass/linked-list.rs b/tests/pass/linked-list.rs similarity index 100% rename from tests/run-pass/linked-list.rs rename to tests/pass/linked-list.rs diff --git a/tests/run-pass/linux-getrandom-without-isolation.rs b/tests/pass/linux-getrandom-without-isolation.rs similarity index 100% rename from tests/run-pass/linux-getrandom-without-isolation.rs rename to tests/pass/linux-getrandom-without-isolation.rs diff --git a/tests/run-pass/linux-getrandom.rs b/tests/pass/linux-getrandom.rs similarity index 100% rename from tests/run-pass/linux-getrandom.rs rename to tests/pass/linux-getrandom.rs diff --git a/tests/run-pass/loop-break-value.rs b/tests/pass/loop-break-value.rs similarity index 100% rename from tests/run-pass/loop-break-value.rs rename to tests/pass/loop-break-value.rs diff --git a/tests/run-pass/loops.rs b/tests/pass/loops.rs similarity index 100% rename from tests/run-pass/loops.rs rename to tests/pass/loops.rs diff --git a/tests/run-pass/main_fn.rs b/tests/pass/main_fn.rs similarity index 100% rename from tests/run-pass/main_fn.rs rename to tests/pass/main_fn.rs diff --git a/tests/run-pass/main_result.rs b/tests/pass/main_result.rs similarity index 100% rename from tests/run-pass/main_result.rs rename to tests/pass/main_result.rs diff --git a/tests/run-pass/malloc.rs b/tests/pass/malloc.rs similarity index 100% rename from tests/run-pass/malloc.rs rename to tests/pass/malloc.rs diff --git a/tests/run-pass/many_shr_bor.rs b/tests/pass/many_shr_bor.rs similarity index 100% rename from tests/run-pass/many_shr_bor.rs rename to tests/pass/many_shr_bor.rs diff --git a/tests/run-pass/match_slice.rs b/tests/pass/match_slice.rs similarity index 100% rename from tests/run-pass/match_slice.rs rename to tests/pass/match_slice.rs diff --git a/tests/run-pass/memchr.rs b/tests/pass/memchr.rs similarity index 100% rename from tests/run-pass/memchr.rs rename to tests/pass/memchr.rs diff --git a/tests/run-pass/memleak_ignored.rs b/tests/pass/memleak_ignored.rs similarity index 100% rename from tests/run-pass/memleak_ignored.rs rename to tests/pass/memleak_ignored.rs diff --git a/tests/run-pass/move-arg-2-unique.rs b/tests/pass/move-arg-2-unique.rs similarity index 100% rename from tests/run-pass/move-arg-2-unique.rs rename to tests/pass/move-arg-2-unique.rs diff --git a/tests/run-pass/move-arg-3-unique.rs b/tests/pass/move-arg-3-unique.rs similarity index 100% rename from tests/run-pass/move-arg-3-unique.rs rename to tests/pass/move-arg-3-unique.rs diff --git a/tests/run-pass/move-uninit-primval.rs b/tests/pass/move-uninit-primval.rs similarity index 100% rename from tests/run-pass/move-uninit-primval.rs rename to tests/pass/move-uninit-primval.rs diff --git a/tests/run-pass/mpsc.rs b/tests/pass/mpsc.rs similarity index 100% rename from tests/run-pass/mpsc.rs rename to tests/pass/mpsc.rs diff --git a/tests/run-pass/multi_arg_closure.rs b/tests/pass/multi_arg_closure.rs similarity index 100% rename from tests/run-pass/multi_arg_closure.rs rename to tests/pass/multi_arg_closure.rs diff --git a/tests/run-pass/negative_discriminant.rs b/tests/pass/negative_discriminant.rs similarity index 100% rename from tests/run-pass/negative_discriminant.rs rename to tests/pass/negative_discriminant.rs diff --git a/tests/run-pass/observed_local_mut.rs b/tests/pass/observed_local_mut.rs similarity index 100% rename from tests/run-pass/observed_local_mut.rs rename to tests/pass/observed_local_mut.rs diff --git a/tests/run-pass/option_box_transmute_ptr.rs b/tests/pass/option_box_transmute_ptr.rs similarity index 100% rename from tests/run-pass/option_box_transmute_ptr.rs rename to tests/pass/option_box_transmute_ptr.rs diff --git a/tests/run-pass/option_eq.rs b/tests/pass/option_eq.rs similarity index 100% rename from tests/run-pass/option_eq.rs rename to tests/pass/option_eq.rs diff --git a/tests/run-pass/overflow_checks_off.rs b/tests/pass/overflow_checks_off.rs similarity index 100% rename from tests/run-pass/overflow_checks_off.rs rename to tests/pass/overflow_checks_off.rs diff --git a/tests/run-pass/overloaded-calls-simple.rs b/tests/pass/overloaded-calls-simple.rs similarity index 100% rename from tests/run-pass/overloaded-calls-simple.rs rename to tests/pass/overloaded-calls-simple.rs diff --git a/tests/run-pass/packed_struct.rs b/tests/pass/packed_struct.rs similarity index 100% rename from tests/run-pass/packed_struct.rs rename to tests/pass/packed_struct.rs diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/pass/panic/catch_panic.rs similarity index 100% rename from tests/run-pass/panic/catch_panic.rs rename to tests/pass/panic/catch_panic.rs diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/pass/panic/catch_panic.stderr similarity index 100% rename from tests/run-pass/panic/catch_panic.stderr rename to tests/pass/panic/catch_panic.stderr diff --git a/tests/run-pass/panic/concurrent-panic.rs b/tests/pass/panic/concurrent-panic.rs similarity index 100% rename from tests/run-pass/panic/concurrent-panic.rs rename to tests/pass/panic/concurrent-panic.rs diff --git a/tests/run-pass/panic/concurrent-panic.stderr b/tests/pass/panic/concurrent-panic.stderr similarity index 100% rename from tests/run-pass/panic/concurrent-panic.stderr rename to tests/pass/panic/concurrent-panic.stderr diff --git a/tests/run-pass/panic/std-panic-locations.rs b/tests/pass/panic/std-panic-locations.rs similarity index 100% rename from tests/run-pass/panic/std-panic-locations.rs rename to tests/pass/panic/std-panic-locations.rs diff --git a/tests/run-pass/partially-uninit.rs b/tests/pass/partially-uninit.rs similarity index 100% rename from tests/run-pass/partially-uninit.rs rename to tests/pass/partially-uninit.rs diff --git a/tests/run-pass/pointers.rs b/tests/pass/pointers.rs similarity index 100% rename from tests/run-pass/pointers.rs rename to tests/pass/pointers.rs diff --git a/tests/run-pass/portable-simd.rs b/tests/pass/portable-simd.rs similarity index 100% rename from tests/run-pass/portable-simd.rs rename to tests/pass/portable-simd.rs diff --git a/tests/run-pass/products.rs b/tests/pass/products.rs similarity index 100% rename from tests/run-pass/products.rs rename to tests/pass/products.rs diff --git a/tests/run-pass/ptr_int_casts.rs b/tests/pass/ptr_int_casts.rs similarity index 100% rename from tests/run-pass/ptr_int_casts.rs rename to tests/pass/ptr_int_casts.rs diff --git a/tests/run-pass/ptr_int_permissive_provenance.rs b/tests/pass/ptr_int_permissive_provenance.rs similarity index 100% rename from tests/run-pass/ptr_int_permissive_provenance.rs rename to tests/pass/ptr_int_permissive_provenance.rs diff --git a/tests/run-pass/ptr_offset.rs b/tests/pass/ptr_offset.rs similarity index 100% rename from tests/run-pass/ptr_offset.rs rename to tests/pass/ptr_offset.rs diff --git a/tests/run-pass/ptr_raw.rs b/tests/pass/ptr_raw.rs similarity index 100% rename from tests/run-pass/ptr_raw.rs rename to tests/pass/ptr_raw.rs diff --git a/tests/run-pass/rc.rs b/tests/pass/rc.rs similarity index 100% rename from tests/run-pass/rc.rs rename to tests/pass/rc.rs diff --git a/tests/run-pass/recursive_static.rs b/tests/pass/recursive_static.rs similarity index 100% rename from tests/run-pass/recursive_static.rs rename to tests/pass/recursive_static.rs diff --git a/tests/run-pass/reentrant-println.rs b/tests/pass/reentrant-println.rs similarity index 100% rename from tests/run-pass/reentrant-println.rs rename to tests/pass/reentrant-println.rs diff --git a/tests/run-pass/reentrant-println.stdout b/tests/pass/reentrant-println.stdout similarity index 100% rename from tests/run-pass/reentrant-println.stdout rename to tests/pass/reentrant-println.stdout diff --git a/tests/run-pass/regions-lifetime-nonfree-late-bound.rs b/tests/pass/regions-lifetime-nonfree-late-bound.rs similarity index 100% rename from tests/run-pass/regions-lifetime-nonfree-late-bound.rs rename to tests/pass/regions-lifetime-nonfree-late-bound.rs diff --git a/tests/run-pass/regions-mock-trans.rs b/tests/pass/regions-mock-trans.rs similarity index 100% rename from tests/run-pass/regions-mock-trans.rs rename to tests/pass/regions-mock-trans.rs diff --git a/tests/run-pass/rename_std.rs b/tests/pass/rename_std.rs similarity index 100% rename from tests/run-pass/rename_std.rs rename to tests/pass/rename_std.rs diff --git a/tests/run-pass/rfc1623.rs b/tests/pass/rfc1623.rs similarity index 100% rename from tests/run-pass/rfc1623.rs rename to tests/pass/rfc1623.rs diff --git a/tests/run-pass/rust-lang-org.rs b/tests/pass/rust-lang-org.rs similarity index 100% rename from tests/run-pass/rust-lang-org.rs rename to tests/pass/rust-lang-org.rs diff --git a/tests/run-pass/send-is-not-static-par-for.rs b/tests/pass/send-is-not-static-par-for.rs similarity index 100% rename from tests/run-pass/send-is-not-static-par-for.rs rename to tests/pass/send-is-not-static-par-for.rs diff --git a/tests/run-pass/sendable-class.rs b/tests/pass/sendable-class.rs similarity index 100% rename from tests/run-pass/sendable-class.rs rename to tests/pass/sendable-class.rs diff --git a/tests/run-pass/simd-intrinsic-generic-elements.rs b/tests/pass/simd-intrinsic-generic-elements.rs similarity index 100% rename from tests/run-pass/simd-intrinsic-generic-elements.rs rename to tests/pass/simd-intrinsic-generic-elements.rs diff --git a/tests/run-pass/slices.rs b/tests/pass/slices.rs similarity index 100% rename from tests/run-pass/slices.rs rename to tests/pass/slices.rs diff --git a/tests/run-pass/small_enum_size_bug.rs b/tests/pass/small_enum_size_bug.rs similarity index 100% rename from tests/run-pass/small_enum_size_bug.rs rename to tests/pass/small_enum_size_bug.rs diff --git a/tests/run-pass/specialization.rs b/tests/pass/specialization.rs similarity index 100% rename from tests/run-pass/specialization.rs rename to tests/pass/specialization.rs diff --git a/tests/run-pass/stacked-borrows/2phase.rs b/tests/pass/stacked-borrows/2phase.rs similarity index 100% rename from tests/run-pass/stacked-borrows/2phase.rs rename to tests/pass/stacked-borrows/2phase.rs diff --git a/tests/run-pass/stacked-borrows/generators-self-referential.rs b/tests/pass/stacked-borrows/generators-self-referential.rs similarity index 100% rename from tests/run-pass/stacked-borrows/generators-self-referential.rs rename to tests/pass/stacked-borrows/generators-self-referential.rs diff --git a/tests/run-pass/stacked-borrows/int-to-ptr.rs b/tests/pass/stacked-borrows/int-to-ptr.rs similarity index 100% rename from tests/run-pass/stacked-borrows/int-to-ptr.rs rename to tests/pass/stacked-borrows/int-to-ptr.rs diff --git a/tests/run-pass/stacked-borrows/interior_mutability.rs b/tests/pass/stacked-borrows/interior_mutability.rs similarity index 100% rename from tests/run-pass/stacked-borrows/interior_mutability.rs rename to tests/pass/stacked-borrows/interior_mutability.rs diff --git a/tests/run-pass/stacked-borrows/refcell.rs b/tests/pass/stacked-borrows/refcell.rs similarity index 100% rename from tests/run-pass/stacked-borrows/refcell.rs rename to tests/pass/stacked-borrows/refcell.rs diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/pass/stacked-borrows/stacked-borrows.rs similarity index 100% rename from tests/run-pass/stacked-borrows/stacked-borrows.rs rename to tests/pass/stacked-borrows/stacked-borrows.rs diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.stderr b/tests/pass/stacked-borrows/stacked-borrows.stderr similarity index 100% rename from tests/run-pass/stacked-borrows/stacked-borrows.stderr rename to tests/pass/stacked-borrows/stacked-borrows.stderr diff --git a/tests/run-pass/start.rs b/tests/pass/start.rs similarity index 100% rename from tests/run-pass/start.rs rename to tests/pass/start.rs diff --git a/tests/run-pass/start.stdout b/tests/pass/start.stdout similarity index 100% rename from tests/run-pass/start.stdout rename to tests/pass/start.stdout diff --git a/tests/run-pass/static_memory_modification.rs b/tests/pass/static_memory_modification.rs similarity index 100% rename from tests/run-pass/static_memory_modification.rs rename to tests/pass/static_memory_modification.rs diff --git a/tests/run-pass/static_mut.rs b/tests/pass/static_mut.rs similarity index 100% rename from tests/run-pass/static_mut.rs rename to tests/pass/static_mut.rs diff --git a/tests/run-pass/strings.rs b/tests/pass/strings.rs similarity index 100% rename from tests/run-pass/strings.rs rename to tests/pass/strings.rs diff --git a/tests/run-pass/subslice_array.rs b/tests/pass/subslice_array.rs similarity index 100% rename from tests/run-pass/subslice_array.rs rename to tests/pass/subslice_array.rs diff --git a/tests/run-pass/sums.rs b/tests/pass/sums.rs similarity index 100% rename from tests/run-pass/sums.rs rename to tests/pass/sums.rs diff --git a/tests/run-pass/tag-align-dyn-u64.rs b/tests/pass/tag-align-dyn-u64.rs similarity index 100% rename from tests/run-pass/tag-align-dyn-u64.rs rename to tests/pass/tag-align-dyn-u64.rs diff --git a/tests/run-pass/threadleak_ignored.rs b/tests/pass/threadleak_ignored.rs similarity index 100% rename from tests/run-pass/threadleak_ignored.rs rename to tests/pass/threadleak_ignored.rs diff --git a/tests/run-pass/threadleak_ignored.stderr b/tests/pass/threadleak_ignored.stderr similarity index 100% rename from tests/run-pass/threadleak_ignored.stderr rename to tests/pass/threadleak_ignored.stderr diff --git a/tests/run-pass/time.rs b/tests/pass/time.rs similarity index 100% rename from tests/run-pass/time.rs rename to tests/pass/time.rs diff --git a/tests/run-pass/too-large-primval-write-problem.rs b/tests/pass/too-large-primval-write-problem.rs similarity index 100% rename from tests/run-pass/too-large-primval-write-problem.rs rename to tests/pass/too-large-primval-write-problem.rs diff --git a/tests/run-pass/track-alloc-1.rs b/tests/pass/track-alloc-1.rs similarity index 100% rename from tests/run-pass/track-alloc-1.rs rename to tests/pass/track-alloc-1.rs diff --git a/tests/run-pass/track-alloc-1.stderr b/tests/pass/track-alloc-1.stderr similarity index 100% rename from tests/run-pass/track-alloc-1.stderr rename to tests/pass/track-alloc-1.stderr diff --git a/tests/run-pass/track-caller-attribute.rs b/tests/pass/track-caller-attribute.rs similarity index 100% rename from tests/run-pass/track-caller-attribute.rs rename to tests/pass/track-caller-attribute.rs diff --git a/tests/run-pass/transmute_fat.rs b/tests/pass/transmute_fat.rs similarity index 100% rename from tests/run-pass/transmute_fat.rs rename to tests/pass/transmute_fat.rs diff --git a/tests/run-pass/trivial.rs b/tests/pass/trivial.rs similarity index 100% rename from tests/run-pass/trivial.rs rename to tests/pass/trivial.rs diff --git a/tests/run-pass/try-operator-custom.rs b/tests/pass/try-operator-custom.rs similarity index 100% rename from tests/run-pass/try-operator-custom.rs rename to tests/pass/try-operator-custom.rs diff --git a/tests/run-pass/tuple_like_enum_variant_constructor.rs b/tests/pass/tuple_like_enum_variant_constructor.rs similarity index 100% rename from tests/run-pass/tuple_like_enum_variant_constructor.rs rename to tests/pass/tuple_like_enum_variant_constructor.rs diff --git a/tests/run-pass/tuple_like_enum_variant_constructor_pointer_opt.rs b/tests/pass/tuple_like_enum_variant_constructor_pointer_opt.rs similarity index 100% rename from tests/run-pass/tuple_like_enum_variant_constructor_pointer_opt.rs rename to tests/pass/tuple_like_enum_variant_constructor_pointer_opt.rs diff --git a/tests/run-pass/tuple_like_enum_variant_constructor_struct_pointer_opt.rs b/tests/pass/tuple_like_enum_variant_constructor_struct_pointer_opt.rs similarity index 100% rename from tests/run-pass/tuple_like_enum_variant_constructor_struct_pointer_opt.rs rename to tests/pass/tuple_like_enum_variant_constructor_struct_pointer_opt.rs diff --git a/tests/run-pass/tuple_like_struct_constructor.rs b/tests/pass/tuple_like_struct_constructor.rs similarity index 100% rename from tests/run-pass/tuple_like_struct_constructor.rs rename to tests/pass/tuple_like_struct_constructor.rs diff --git a/tests/run-pass/u128.rs b/tests/pass/u128.rs similarity index 100% rename from tests/run-pass/u128.rs rename to tests/pass/u128.rs diff --git a/tests/run-pass/uninit_number_ignored.rs b/tests/pass/uninit_number_ignored.rs similarity index 100% rename from tests/run-pass/uninit_number_ignored.rs rename to tests/pass/uninit_number_ignored.rs diff --git a/tests/run-pass/union-overwrite.rs b/tests/pass/union-overwrite.rs similarity index 100% rename from tests/run-pass/union-overwrite.rs rename to tests/pass/union-overwrite.rs diff --git a/tests/run-pass/union.rs b/tests/pass/union.rs similarity index 100% rename from tests/run-pass/union.rs rename to tests/pass/union.rs diff --git a/tests/run-pass/unops.rs b/tests/pass/unops.rs similarity index 100% rename from tests/run-pass/unops.rs rename to tests/pass/unops.rs diff --git a/tests/run-pass/unsized-tuple-impls.rs b/tests/pass/unsized-tuple-impls.rs similarity index 100% rename from tests/run-pass/unsized-tuple-impls.rs rename to tests/pass/unsized-tuple-impls.rs diff --git a/tests/run-pass/validation_lifetime_resolution.rs b/tests/pass/validation_lifetime_resolution.rs similarity index 100% rename from tests/run-pass/validation_lifetime_resolution.rs rename to tests/pass/validation_lifetime_resolution.rs diff --git a/tests/run-pass/vec-matching-fold.rs b/tests/pass/vec-matching-fold.rs similarity index 100% rename from tests/run-pass/vec-matching-fold.rs rename to tests/pass/vec-matching-fold.rs diff --git a/tests/run-pass/vec.rs b/tests/pass/vec.rs similarity index 100% rename from tests/run-pass/vec.rs rename to tests/pass/vec.rs diff --git a/tests/run-pass/vecdeque.rs b/tests/pass/vecdeque.rs similarity index 100% rename from tests/run-pass/vecdeque.rs rename to tests/pass/vecdeque.rs diff --git a/tests/run-pass/vecdeque.stdout b/tests/pass/vecdeque.stdout similarity index 100% rename from tests/run-pass/vecdeque.stdout rename to tests/pass/vecdeque.stdout diff --git a/tests/run-pass/volatile.rs b/tests/pass/volatile.rs similarity index 100% rename from tests/run-pass/volatile.rs rename to tests/pass/volatile.rs diff --git a/tests/run-pass/without-validation.rs b/tests/pass/without-validation.rs similarity index 100% rename from tests/run-pass/without-validation.rs rename to tests/pass/without-validation.rs diff --git a/tests/run-pass/write-bytes.rs b/tests/pass/write-bytes.rs similarity index 100% rename from tests/run-pass/write-bytes.rs rename to tests/pass/write-bytes.rs diff --git a/tests/run-pass/wtf8.rs b/tests/pass/wtf8.rs similarity index 100% rename from tests/run-pass/wtf8.rs rename to tests/pass/wtf8.rs diff --git a/tests/run-pass/zst.rs b/tests/pass/zst.rs similarity index 100% rename from tests/run-pass/zst.rs rename to tests/pass/zst.rs diff --git a/tests/run-pass/zst_box.rs b/tests/pass/zst_box.rs similarity index 100% rename from tests/run-pass/zst_box.rs rename to tests/pass/zst_box.rs diff --git a/tests/run-pass/zst_variant_drop.rs b/tests/pass/zst_variant_drop.rs similarity index 100% rename from tests/run-pass/zst_variant_drop.rs rename to tests/pass/zst_variant_drop.rs From 0b7a148ad9e5b990c9d6278f5010959afdac90ed Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Wed, 1 Jun 2022 17:32:01 -0700 Subject: [PATCH 3154/5092] add test for backtrace with global allocator --- tests/pass/backtrace-global-alloc.rs | 13 +++++++++++ tests/pass/backtrace-global-alloc.stderr | 28 ++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 tests/pass/backtrace-global-alloc.rs create mode 100644 tests/pass/backtrace-global-alloc.stderr diff --git a/tests/pass/backtrace-global-alloc.rs b/tests/pass/backtrace-global-alloc.rs new file mode 100644 index 000000000000..8c51bf62706e --- /dev/null +++ b/tests/pass/backtrace-global-alloc.rs @@ -0,0 +1,13 @@ +// compile-flags: -Zmiri-disable-isolation + +#![feature(backtrace)] + +use std::alloc::System; +use std::backtrace::Backtrace; + +#[global_allocator] +static GLOBAL_ALLOCATOR: System = System; + +fn main() { + eprint!("{}", Backtrace::capture()); +} diff --git a/tests/pass/backtrace-global-alloc.stderr b/tests/pass/backtrace-global-alloc.stderr new file mode 100644 index 000000000000..c48061d64d08 --- /dev/null +++ b/tests/pass/backtrace-global-alloc.stderr @@ -0,0 +1,28 @@ + 0: main + at $DIR/backtrace-global-alloc.rs:LL:CC + 1: >::call_once - shim(fn()) + at RUSTLIB/core/src/ops/function.rs:LL:CC + 2: std::sys_common::backtrace::__rust_begin_short_backtrace + at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + 3: std::rt::lang_start::{closure#0} + at RUSTLIB/std/src/rt.rs:LL:CC + 4: std::ops::function::impls::call_once + at RUSTLIB/core/src/ops/function.rs:LL:CC + 5: std::panicking::r#try::do_call + at RUSTLIB/std/src/panicking.rs:LL:CC + 6: std::panicking::r#try + at RUSTLIB/std/src/panicking.rs:LL:CC + 7: std::panic::catch_unwind + at RUSTLIB/std/src/panic.rs:LL:CC + 8: std::rt::lang_start_internal::{closure#2} + at RUSTLIB/std/src/rt.rs:LL:CC + 9: std::panicking::r#try::do_call + at RUSTLIB/std/src/panicking.rs:LL:CC + 10: std::panicking::r#try + at RUSTLIB/std/src/panicking.rs:LL:CC + 11: std::panic::catch_unwind + at RUSTLIB/std/src/panic.rs:LL:CC + 12: std::rt::lang_start_internal + at RUSTLIB/std/src/rt.rs:LL:CC + 13: std::rt::lang_start + at RUSTLIB/std/src/rt.rs:LL:CC From e79a331fea9ee9d772de8ffabd7c8aa4cb33dcea Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Jun 2022 15:11:22 -0400 Subject: [PATCH 3155/5092] do not pass TyCtxt by reference --- src/helpers.rs | 2 +- src/machine.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index d9a7edcc1135..8339ecde121e 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -858,7 +858,7 @@ pub fn isolation_abort_error<'tcx>(name: &str) -> InterpResult<'tcx> { /// Retrieve the list of local crates that should have been passed by cargo-miri in /// MIRI_LOCAL_CRATES and turn them into `CrateNum`s. -pub fn get_local_crates(tcx: &TyCtxt<'_>) -> Vec { +pub fn get_local_crates(tcx: TyCtxt<'_>) -> Vec { // Convert the local crate names from the passed-in config into CrateNums so that they can // be looked up quickly during execution let local_crate_names = std::env::var("MIRI_LOCAL_CRATES") diff --git a/src/machine.rs b/src/machine.rs index 1cb815706195..9a358bb6d53a 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -327,7 +327,7 @@ pub struct Evaluator<'mir, 'tcx> { impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Self { - let local_crates = helpers::get_local_crates(&layout_cx.tcx); + let local_crates = helpers::get_local_crates(layout_cx.tcx); let layouts = PrimitiveLayouts::new(layout_cx).expect("Couldn't get layouts of primitive types"); let profiler = config.measureme_out.as_ref().map(|out| { From bc5da2b5a74e959445f4d12802fac90203c3b924 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Jun 2022 21:09:10 -0400 Subject: [PATCH 3156/5092] test ui output also in rustc test suite --- tests/compiletest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 3b6cf6a6d1fd..fef2d1f7a588 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -38,7 +38,7 @@ fn run_tests(mode: Mode, path: &str, target: Option) { flags.push(target.clone()); } - let skip_ui_checks = in_rustc_test_suite || env::var_os("MIRI_SKIP_UI_CHECKS").is_some(); + let skip_ui_checks = env::var_os("MIRI_SKIP_UI_CHECKS").is_some(); let output_conflict_handling = match (env::var_os("MIRI_BLESS").is_some(), skip_ui_checks) { (false, false) => OutputConflictHandling::Error, From 2b9c45f96f57069396e2029583aa762ecca569d4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 3 Jun 2022 07:36:05 -0400 Subject: [PATCH 3157/5092] delete stale stderr files --- .../backtrace/bad-backtrace-version.stderr | 14 ------------- tests/fail/fs/unix_open_too_many_args.stderr | 20 ------------------- tests/fail/null_pointer_deref.stderr | 15 -------------- tests/fail/null_pointer_deref_zst.stderr | 15 -------------- tests/fail/null_pointer_write.stderr | 15 -------------- tests/fail/null_pointer_write_zst.stderr | 17 ---------------- tests/fail/ptr_integer_array_transmute.stderr | 15 -------------- tests/fail/ptr_integer_transmute.stderr | 15 -------------- tests/fail/slice-too-big.stderr | 15 -------------- tests/fail/strict-provenance-offset.stderr | 16 --------------- tests/fail/strict_provenance_transmute.stderr | 20 ------------------- tests/fail/too-big-slice.stderr | 15 -------------- tests/fail/too-big-unsized.stderr | 15 -------------- tests/fail/uninit_float.stderr | 15 -------------- tests/fail/uninit_integer.stderr | 15 -------------- tests/fail/uninit_integer_signed.stderr | 15 -------------- 16 files changed, 252 deletions(-) delete mode 100644 tests/fail/backtrace/bad-backtrace-version.stderr delete mode 100644 tests/fail/fs/unix_open_too_many_args.stderr delete mode 100644 tests/fail/null_pointer_deref.stderr delete mode 100644 tests/fail/null_pointer_deref_zst.stderr delete mode 100644 tests/fail/null_pointer_write.stderr delete mode 100644 tests/fail/null_pointer_write_zst.stderr delete mode 100644 tests/fail/ptr_integer_array_transmute.stderr delete mode 100644 tests/fail/ptr_integer_transmute.stderr delete mode 100644 tests/fail/slice-too-big.stderr delete mode 100644 tests/fail/strict-provenance-offset.stderr delete mode 100644 tests/fail/strict_provenance_transmute.stderr delete mode 100644 tests/fail/too-big-slice.stderr delete mode 100644 tests/fail/too-big-unsized.stderr delete mode 100644 tests/fail/uninit_float.stderr delete mode 100644 tests/fail/uninit_integer.stderr delete mode 100644 tests/fail/uninit_integer_signed.stderr diff --git a/tests/fail/backtrace/bad-backtrace-version.stderr b/tests/fail/backtrace/bad-backtrace-version.stderr deleted file mode 100644 index 4e7292732754..000000000000 --- a/tests/fail/backtrace/bad-backtrace-version.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: unsupported operation: unknown `miri_resolve_frame` flags 1 - --> $DIR/bad-backtrace-version.rs:7:9 - | -LL | miri_resolve_frame(0 as *mut _, 1); //~ ERROR unsupported operation: unknown `miri_resolve_frame` flags 1 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_resolve_frame` flags 1 - | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - - = note: inside `main` at $DIR/bad-backtrace-version.rs:7:9 - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/fs/unix_open_too_many_args.stderr b/tests/fail/fs/unix_open_too_many_args.stderr deleted file mode 100644 index f71a44d34dab..000000000000 --- a/tests/fail/fs/unix_open_too_many_args.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: Undefined Behavior: incorrect number of arguments for `open`: got 4, expected 2 or 3 - --> $DIR/unix_open_too_many_args.rs:15:24 - | -LL | let _fd = unsafe { libc::open(name_ptr, libc::O_RDONLY, 0, 0) }; //~ ERROR Undefined Behavior: incorrect number of arguments for `ope... - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of arguments for `open`: got 4, expected 2 or 3 - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `test_open_too_many_args` at $DIR/unix_open_too_many_args.rs:15:24 -note: inside `main` at $DIR/unix_open_too_many_args.rs:9:5 - --> $DIR/unix_open_too_many_args.rs:9:5 - | -LL | test_open_too_many_args(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/null_pointer_deref.stderr b/tests/fail/null_pointer_deref.stderr deleted file mode 100644 index 0930160023f1..000000000000 --- a/tests/fail/null_pointer_deref.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: dereferencing pointer failed: null pointer is not a valid pointer - --> $DIR/null_pointer_deref.rs:LL:CC - | -LL | let x: i32 = unsafe { *std::ptr::null() }; - | ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is not a valid pointer - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `main` at $DIR/null_pointer_deref.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/null_pointer_deref_zst.stderr b/tests/fail/null_pointer_deref_zst.stderr deleted file mode 100644 index 25fea50b15af..000000000000 --- a/tests/fail/null_pointer_deref_zst.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: dereferencing pointer failed: null pointer is not a valid pointer - --> $DIR/null_pointer_deref_zst.rs:LL:CC - | -LL | let x: () = unsafe { *std::ptr::null() }; - | ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is not a valid pointer - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `main` at $DIR/null_pointer_deref_zst.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/null_pointer_write.stderr b/tests/fail/null_pointer_write.stderr deleted file mode 100644 index 5ac8cc7c20fd..000000000000 --- a/tests/fail/null_pointer_write.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: dereferencing pointer failed: null pointer is not a valid pointer - --> $DIR/null_pointer_write.rs:LL:CC - | -LL | unsafe { *std::ptr::null_mut() = 0i32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is not a valid pointer - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `main` at $DIR/null_pointer_write.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/null_pointer_write_zst.stderr b/tests/fail/null_pointer_write_zst.stderr deleted file mode 100644 index b40a9154f182..000000000000 --- a/tests/fail/null_pointer_write_zst.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error: Undefined Behavior: memory access failed: null pointer is not a valid pointer - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `std::ptr::write::<[u8; 0]>` at rustc_src/src/ptr/mod.rs:LL:CC - = note: inside `std::ptr::mut_ptr::::write` at rustc_src/src/ptr/mut_ptr.rs:LL:CC -note: inside `main` at $DIR/null_pointer_write_zst.rs:LL:CC - --> $DIR/null_pointer_write_zst.rs:LL:CC - | -LL | unsafe { std::ptr::null_mut::<[u8; 0]>().write(zst_val) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/ptr_integer_array_transmute.stderr b/tests/fail/ptr_integer_array_transmute.stderr deleted file mode 100644 index bc2ca54438ff..000000000000 --- a/tests/fail/ptr_integer_array_transmute.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: type validation failed: encountered a pointer, but expected plain (non-pointer) bytes - --> $DIR/ptr_integer_array_transmute.rs:LL:CC - | -LL | let _i: [usize; 1] = unsafe { std::mem::transmute(r) }; - | ^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected plain (non-pointer) bytes - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `main` at $DIR/ptr_integer_array_transmute.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/ptr_integer_transmute.stderr b/tests/fail/ptr_integer_transmute.stderr deleted file mode 100644 index de9ebf4eb06b..000000000000 --- a/tests/fail/ptr_integer_transmute.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: type validation failed: encountered pointer to $HEX[ALLOC], but expected initialized plain (non-pointer) bytes - --> $DIR/ptr_integer_transmute.rs:LL:CC - | -LL | let _i: usize = unsafe { std::mem::transmute(r) }; - | ^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to $HEX[ALLOC], but expected initialized plain (non-pointer) bytes - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `main` at $DIR/ptr_integer_transmute.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/slice-too-big.stderr b/tests/fail/slice-too-big.stderr deleted file mode 100644 index 13239506c633..000000000000 --- a/tests/fail/slice-too-big.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object - --> $DIR/slice-too-big.rs:5:21 - | -LL | let _x: &[u8] = mem::transmute((ptr, usize::MAX)); //~ ERROR: invalid reference metadata: slice is bigger than largest supported object - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `main` at $DIR/slice-too-big.rs:5:21 - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/strict-provenance-offset.stderr b/tests/fail/strict-provenance-offset.stderr deleted file mode 100644 index 482b7a404c51..000000000000 --- a/tests/fail/strict-provenance-offset.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error: Undefined Behavior: pointer arithmetic failed: $HEX is not a valid pointer - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `std::ptr::const_ptr::::offset` at rustc_src/src/ptr/const_ptr.rs:LL:CC -note: inside `main` at $DIR/strict-provenance-offset.rs:LL:CC - --> $DIR/strict-provenance-offset.rs:LL:CC - | -LL | let _ = unsafe { roundtrip.offset(1) }; - | ^^^^^^^^^^^^^^^^^^^ - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/strict_provenance_transmute.stderr b/tests/fail/strict_provenance_transmute.stderr deleted file mode 100644 index c2140b9786ca..000000000000 --- a/tests/fail/strict_provenance_transmute.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: Undefined Behavior: type validation failed: encountered pointer to $HEX[ALLOC], but expected initialized plain (non-pointer) bytes - --> $DIR/strict_provenance_transmute.rs:LL:CC - | -LL | let left_int: usize = mem::transmute(left); - | ^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to $HEX[ALLOC], but expected initialized plain (non-pointer) bytes - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `deref` at $DIR/strict_provenance_transmute.rs:LL:CC -note: inside `main` at $DIR/strict_provenance_transmute.rs:LL:CC - --> $DIR/strict_provenance_transmute.rs:LL:CC - | -LL | deref(ptr1, ptr2.with_addr(ptr1.addr())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/too-big-slice.stderr b/tests/fail/too-big-slice.stderr deleted file mode 100644 index 11d20d3e623b..000000000000 --- a/tests/fail/too-big-slice.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object - --> $DIR/too-big-slice.rs:LL:CC - | -LL | let _x: &[u8] = mem::transmute((ptr, usize::MAX)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `main` at $DIR/too-big-slice.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/too-big-unsized.stderr b/tests/fail/too-big-unsized.stderr deleted file mode 100644 index 0c7b7b23246e..000000000000 --- a/tests/fail/too-big-unsized.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: type validation failed: encountered invalid reference metadata: total size is bigger than largest supported object - --> $DIR/too-big-unsized.rs:LL:CC - | -LL | let _x: &MySlice = mem::transmute((ptr, isize::MAX as usize)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: total size is bigger than largest supported object - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `main` at $DIR/too-big-unsized.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/uninit_float.stderr b/tests/fail/uninit_float.stderr deleted file mode 100644 index 90cdc3ba0fae..000000000000 --- a/tests/fail/uninit_float.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes - --> $DIR/uninit_float.rs:LL:CC - | -LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `main` at $DIR/uninit_float.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/uninit_integer.stderr b/tests/fail/uninit_integer.stderr deleted file mode 100644 index 88b57c1d279a..000000000000 --- a/tests/fail/uninit_integer.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes - --> $DIR/uninit_integer.rs:LL:CC - | -LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `main` at $DIR/uninit_integer.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/uninit_integer_signed.stderr b/tests/fail/uninit_integer_signed.stderr deleted file mode 100644 index fc15462280a6..000000000000 --- a/tests/fail/uninit_integer_signed.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes - --> $DIR/uninit_integer_signed.rs:LL:CC - | -LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `main` at $DIR/uninit_integer_signed.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - From 625b4ed3412b259c3e2aa0c171b65d745de6af8c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 3 Jun 2022 14:48:45 -0400 Subject: [PATCH 3158/5092] fix dangling reference in the README --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 824a8d3e328a..a55ebcb125b3 100644 --- a/README.md +++ b/README.md @@ -296,8 +296,7 @@ environment variable. We first document the most relevant and most commonly used * `-Zmiri-strict-provenance` enables [strict provenance](https://github.com/rust-lang/rust/issues/95228) checking in Miri. This means that casting an integer to a pointer yields a result with 'invalid' provenance, i.e., with provenance - that cannot be used for any memory access. Also implies `-Zmiri-tag-raw-pointers` and - `-Zmiri-check-number-validity`. + that cannot be used for any memory access. Also implies `-Zmiri-tag-raw-pointers`. The remaining flags are for advanced use only, and more likely to change or be removed. Some of these are **unsound**, which means they can lead From bcc491a6babbbc8e555980ad157cf8a01777bfde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 4 Jun 2022 13:40:54 +0200 Subject: [PATCH 3159/5092] clippy fixes clippy::redundant_closure clippy::unnecessary_mut_passed clippy::single_char_pattern clippy::clone_on_copy clippy::into_iter_on_ref clippy::extra_unused_lifetimes --- benches/fibonacci.rs | 4 ++-- benches/smoke.rs | 2 +- src/diagnostics.rs | 18 +++++++++--------- src/eval.rs | 2 +- src/helpers.rs | 4 ++-- src/shims/posix/fs.rs | 2 +- src/stacked_borrows.rs | 4 ++-- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/benches/fibonacci.rs b/benches/fibonacci.rs index ebb1b5fd0b18..9a68a69e800f 100644 --- a/benches/fibonacci.rs +++ b/benches/fibonacci.rs @@ -7,7 +7,7 @@ use crate::helpers::*; #[bench] fn fib(bencher: &mut Bencher) { - bencher.iter(|| fibonacci_helper::main()) + bencher.iter(fibonacci_helper::main) } #[bench] @@ -17,7 +17,7 @@ fn fib_miri(bencher: &mut Bencher) { #[bench] fn fib_iter(bencher: &mut Bencher) { - bencher.iter(|| fibonacci_helper_iterative::main()) + bencher.iter(fibonacci_helper_iterative::main) } #[bench] diff --git a/benches/smoke.rs b/benches/smoke.rs index 9229e972d7f3..372cd0b22b7a 100644 --- a/benches/smoke.rs +++ b/benches/smoke.rs @@ -7,7 +7,7 @@ use crate::helpers::*; #[bench] fn noop(bencher: &mut Bencher) { - bencher.iter(|| smoke_helper::main()) + bencher.iter(smoke_helper::main) } /* diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 527ff032d670..ace521f1bed0 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -166,32 +166,32 @@ pub fn report_error<'tcx, 'mir>( match history { Some(TagHistory::Tagged {tag, created: (created_range, created_span), invalidated, protected }) => { let msg = format!("{:?} was created by a retag at offsets {}", tag, HexRange(*created_range)); - helps.push((Some(created_span.clone()), msg)); + helps.push((Some(*created_span), msg)); if let Some((invalidated_range, invalidated_span)) = invalidated { let msg = format!("{:?} was later invalidated at offsets {}", tag, HexRange(*invalidated_range)); - helps.push((Some(invalidated_span.clone()), msg)); + helps.push((Some(*invalidated_span), msg)); } if let Some((protecting_tag, protecting_tag_span, protection_span)) = protected { - helps.push((Some(protecting_tag_span.clone()), format!("{:?} was protected due to {:?} which was created here", tag, protecting_tag))); - helps.push((Some(protection_span.clone()), "this protector is live for this call".to_string())); + helps.push((Some(*protecting_tag_span), format!("{:?} was protected due to {:?} which was created here", tag, protecting_tag))); + helps.push((Some(*protection_span), "this protector is live for this call".to_string())); } } Some(TagHistory::Untagged{ recently_created, recently_invalidated, matching_created, protected }) => { if let Some((range, span)) = recently_created { let msg = format!("tag was most recently created at offsets {}", HexRange(*range)); - helps.push((Some(span.clone()), msg)); + helps.push((Some(*span), msg)); } if let Some((range, span)) = recently_invalidated { let msg = format!("tag was later invalidated at offsets {}", HexRange(*range)); - helps.push((Some(span.clone()), msg)); + helps.push((Some(*span), msg)); } if let Some((range, span)) = matching_created { let msg = format!("this tag was also created here at offsets {}", HexRange(*range)); - helps.push((Some(span.clone()), msg)); + helps.push((Some(*span), msg)); } if let Some((protecting_tag, protecting_tag_span, protection_span)) = protected { - helps.push((Some(protecting_tag_span.clone()), format!("{:?} was protected due to a tag which was created here", protecting_tag))); - helps.push((Some(protection_span.clone()), "this protector is live for this call".to_string())); + helps.push((Some(*protecting_tag_span), format!("{:?} was protected due to a tag which was created here", protecting_tag))); + helps.push((Some(*protection_span), "this protector is live for this call".to_string())); } } None => {} diff --git a/src/eval.rs b/src/eval.rs index 39fccb092433..a782dfa3fce1 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -491,6 +491,6 @@ mod tests { let cmd = String::from_utf16_lossy(&args_to_utf16_command_string( [r"C:\Program Files\", "arg1", "arg 2", "arg \" 3"].iter(), )); - assert_eq!(cmd.trim_end_matches("\0"), r#""C:\Program Files\" arg1 "arg 2" "arg \" 3""#); + assert_eq!(cmd.trim_end_matches('\0'), r#""C:\Program Files\" arg1 "arg 2" "arg \" 3""#); } } diff --git a/src/helpers.rs b/src/helpers.rs index 8339ecde121e..cb4c3c293e93 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -817,7 +817,7 @@ pub struct CurrentSpan<'a, 'mir, 'tcx> { impl<'a, 'mir, 'tcx> CurrentSpan<'a, 'mir, 'tcx> { pub fn get(&mut self) -> Span { - *self.span.get_or_insert_with(|| Self::current_span(&self.machine)) + *self.span.get_or_insert_with(|| Self::current_span(self.machine)) } #[inline(never)] @@ -825,7 +825,7 @@ impl<'a, 'mir, 'tcx> CurrentSpan<'a, 'mir, 'tcx> { machine .threads .active_thread_stack() - .into_iter() + .iter() .rev() .find(|frame| { let def_id = frame.instance.def_id(); diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 79539fd9c49e..d02410664bd4 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -304,7 +304,7 @@ pub struct FileHandler { handles: BTreeMap>, } -impl<'tcx> FileHandler { +impl FileHandler { pub(crate) fn new(mute_stdout_stderr: bool) -> FileHandler { let mut handles: BTreeMap<_, Box> = BTreeMap::new(); handles.insert(0i32, Box::new(io::stdin())); diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 6cb71f43118c..a19e30b113e3 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -684,9 +684,9 @@ impl Stacks { state: &GlobalState, ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", tag, alloc_id, range.size.bytes()); - let mut state = state.borrow_mut(); + let state = state.borrow(); self.for_each_mut(range, |offset, stack, history| { - stack.dealloc(tag, (alloc_id, range, offset), &mut state, history) + stack.dealloc(tag, (alloc_id, range, offset), &state, history) })?; Ok(()) } From bd7f83dc3773ee1a0ce6ebb5bf7c3a8cd04bb968 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 Jun 2022 11:48:46 -0400 Subject: [PATCH 3160/5092] run clippy on CI --- .github/workflows/ci.yml | 55 ++++++++++++++++++++-------------------- rustup-toolchain | 5 +++- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f34e92571ff0..41cf159e0c80 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -72,20 +72,10 @@ jobs: shell: bash run: | if [[ ${{ github.event_name }} == 'schedule' ]]; then - RUSTC_HASH=$(git ls-remote https://github.com/rust-lang/rust.git master | awk '{print $1}') + ./rustup-toolchain HEAD --host ${{ matrix.host_target }} else - RUSTC_HASH=$(< rust-version) + ./rustup-toolchain "" --host ${{ matrix.host_target }} fi - # We need a nightly cargo for parts of the cargo miri test suite. - rustup-toolchain-install-master \ - -f \ - -n master "$RUSTC_HASH" \ - -c cargo \ - -c rust-src \ - -c rustc-dev \ - -c llvm-tools \ - --host ${{ matrix.host_target }} - rustup default master - name: Show Rust version run: | @@ -97,26 +87,35 @@ jobs: run: bash ./ci.sh fmt: - name: check formatting (ignored by bors) + name: formatting (ignored by bors) runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Install latest nightly - uses: actions-rs/toolchain@v1 - with: - toolchain: nightly - components: rustfmt - default: true - - name: Check formatting (miri) - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --all -- --check - - name: Check formatting (cargo-miri) - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --manifest-path cargo-miri/Cargo.toml --all -- --check + run: | + rustup toolchain install nightly --component rustfmt + rustup override set nightly + - name: Formatting (miri, ui_test) + run: cargo fmt --all --check + - name: Formatting (cargo-miri) + run: cargo fmt --manifest-path cargo-miri/Cargo.toml --all --check + + clippy: + name: clippy (ignored by bors) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install required toolchain + # We need a toolchain that can actually build Miri, just a nightly won't do. + run: | + cargo install rustup-toolchain-install-master # TODO: cache this? + ./rustup-toolchain "" -c clippy + - name: Clippy (miri) + run: cargo clippy --all-targets -- -D warnings + #- name: Clippy (ui_test) + # run: cargo clippy --manifest-path ui_test/Cargo.toml --all-targets -- -D warnings + - name: Clippy (cargo-miri) + run: cargo clippy --manifest-path cargo-miri/Cargo.toml --all-targets -- -D warnings # These jobs doesn't actually test anything, but they're only used to tell # bors the build completed, as there is no practical way to detect when a diff --git a/rustup-toolchain b/rustup-toolchain index 59ce6f85a085..7e5d57349b9d 100755 --- a/rustup-toolchain +++ b/rustup-toolchain @@ -12,6 +12,8 @@ set -e # ./rustup-toolchain HEAD: Update "miri" toolchain and `rust-version` file to latest rustc HEAD. # # ./rustup-toolchain $COMMIT: Update "miri" toolchain and `rust-version` file to match that commit. +# +# Any extra parameters are passed to `rustup-toolchain-install-master`. # Make sure rustup-toolchain-install-master is installed. if ! which rustup-toolchain-install-master >/dev/null; then @@ -28,6 +30,7 @@ else NEW_COMMIT="$1" fi echo "$NEW_COMMIT" > rust-version +shift # Check if we already are at that commit. CUR_COMMIT=$(rustc +miri --version -v 2>/dev/null | egrep "^commit-hash: " | cut -d " " -f 2) @@ -39,7 +42,7 @@ fi # Install and setup new toolchain. rustup toolchain uninstall miri -rustup-toolchain-install-master -n miri -c cargo -c rust-src -c rustc-dev -c llvm-tools -- "$NEW_COMMIT" +rustup-toolchain-install-master -n miri -c cargo -c rust-src -c rustc-dev -c llvm-tools "$@" -- "$NEW_COMMIT" rustup override set miri # Cleanup. From 151b6b13e0766c23833038db0a5b99a09562af53 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 Jun 2022 11:55:36 -0400 Subject: [PATCH 3161/5092] clippy: main crate --- benches/helpers/fibonacci_helper_iterative.rs | 2 +- src/lib.rs | 7 ++----- src/machine.rs | 6 +++--- src/shims/intrinsics.rs | 2 +- src/shims/posix/sync.rs | 7 ++++--- 5 files changed, 11 insertions(+), 13 deletions(-) diff --git a/benches/helpers/fibonacci_helper_iterative.rs b/benches/helpers/fibonacci_helper_iterative.rs index 59283be4820f..0c2732828966 100644 --- a/benches/helpers/fibonacci_helper_iterative.rs +++ b/benches/helpers/fibonacci_helper_iterative.rs @@ -9,7 +9,7 @@ fn fib(n: usize) -> usize { for _ in 0..n { let c = a; a = b; - b = c + b; + b += c; } a } diff --git a/src/lib.rs b/src/lib.rs index e571c8a00102..f7c256656a76 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,19 +7,16 @@ #![feature(io_error_more)] #![warn(rust_2018_idioms)] #![allow( - clippy::cast_lossless, clippy::collapsible_else_if, clippy::collapsible_if, clippy::comparison_chain, clippy::enum_variant_names, clippy::field_reassign_with_default, - clippy::from_over_into, - clippy::if_same_then_else, clippy::manual_map, - clippy::needless_lifetimes, clippy::new_without_default, clippy::single_match, - clippy::useless_format + clippy::useless_format, + clippy::derive_partial_eq_without_eq )] extern crate rustc_apfloat; diff --git a/src/machine.rs b/src/machine.rs index 9a358bb6d53a..6a7cbe58711a 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -89,10 +89,10 @@ pub enum MiriMemoryKind { Tls, } -impl Into> for MiriMemoryKind { +impl From for MemoryKind { #[inline(always)] - fn into(self) -> MemoryKind { - MemoryKind::Machine(self) + fn from(kind: MiriMemoryKind) -> MemoryKind { + MemoryKind::Machine(kind) } } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 1f06971a3e70..8d4da31fd0d7 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -1389,7 +1389,7 @@ fn bool_to_simd_element(b: bool, size: Size) -> Scalar { Scalar::from_int(val, size) } -fn simd_element_to_bool<'tcx>(elem: ImmTy<'tcx, Tag>) -> InterpResult<'tcx, bool> { +fn simd_element_to_bool(elem: ImmTy<'_, Tag>) -> InterpResult<'_, bool> { let val = elem.to_scalar()?.to_int(elem.layout.size)?; Ok(match val { 0 => false, diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index f56a309bf078..373996312eaf 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -535,9 +535,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_ub_format!( "unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked by the current thread" ); - } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { - this.eval_libc_i32("EPERM") - } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { + } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? + || kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? + { this.eval_libc_i32("EPERM") } else { throw_unsup_format!("called pthread_mutex_unlock on an unsupported type of mutex"); @@ -642,6 +642,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let id = rwlock_get_or_create_id(this, rwlock_op)?; let active_thread = this.get_active_thread(); + #[allow(clippy::if_same_then_else)] if this.rwlock_reader_unlock(id, active_thread) { Ok(0) } else if this.rwlock_writer_unlock(id, active_thread) { From 3d30aece836c5f524b49eb308ee516a09dd9e0a9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 Jun 2022 12:11:23 -0400 Subject: [PATCH 3162/5092] clippy: cargo-miri --- cargo-miri/bin.rs | 49 ++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 34904279e94f..ba885d307a85 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -1,3 +1,5 @@ +#![allow(clippy::useless_format, clippy::derive_partial_eq_without_eq)] + mod version; use std::env; @@ -96,6 +98,9 @@ fn show_version() { // Only use `option_env` on vergen variables to ensure the build succeeds // when vergen failed to find the git info. if let Some(sha) = option_env!("VERGEN_GIT_SHA_SHORT") { + // This `unwrap` can never fail because if VERGEN_GIT_SHA_SHORT exists, then so does + // VERGEN_GIT_COMMIT_DATE. + #[allow(clippy::option_env_unwrap)] write!(&mut version, " ({} {})", sha, option_env!("VERGEN_GIT_COMMIT_DATE").unwrap()) .unwrap(); } @@ -135,16 +140,14 @@ impl> Iterator for ArgSplitFlagValue<'_, I> { fn next(&mut self) -> Option { let arg = self.args.next()?; - if arg.starts_with(self.name) { + if let Some(suffix) = arg.strip_prefix(self.name) { // Strip leading `name`. - let suffix = &arg[self.name.len()..]; if suffix.is_empty() { // This argument is exactly `name`; the next one is the value. return self.args.next().map(Ok); - } else if suffix.starts_with('=') { + } else if let Some(suffix) = suffix.strip_prefix('=') { // This argument is `name=value`; get the value. - // Strip leading `=`. - return Some(Ok(suffix[1..].to_owned())); + return Some(Ok(suffix.to_owned())); } } Some(Err(arg)) @@ -255,7 +258,7 @@ fn xargo_version() -> Option<(u32, u32, u32)> { let line = out .stderr .lines() - .nth(0) + .next() .expect("malformed `xargo --version` output: not at least one line") .expect("malformed `xargo --version` output: error reading first line"); let (name, version) = { @@ -285,7 +288,7 @@ fn xargo_version() -> Option<(u32, u32, u32)> { .expect("malformed `xargo --version` output: not a patch version piece") .parse() .expect("malformed `xargo --version` output: patch version is not an integer"); - if !version_pieces.next().is_none() { + if version_pieces.next().is_some() { panic!("malformed `xargo --version` output: more than three pieces in version"); } Some((major, minor, patch)) @@ -311,7 +314,7 @@ fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { println!("Running `{:?}` to {}.", cmd, text); } - if cmd.status().expect(&format!("failed to execute {:?}", cmd)).success().not() { + if cmd.status().unwrap_or_else(|_| panic!("failed to execute {:?}", cmd)).success().not() { show_error(format!("failed to {}", text)); } } @@ -499,10 +502,11 @@ fn get_cargo_metadata() -> Metadata { for arg in ArgSplitFlagValue::new( env::args().skip(3), // skip the program name, "miri" and "run" / "test" config_flag, - ) { - if let Ok(config) = arg { - cmd.arg(config_flag).arg(config); - } + ) + // Only look at `Ok` + .flatten() + { + cmd.arg(config_flag).arg(arg); } let mut child = cmd .stdin(process::Stdio::null()) @@ -524,11 +528,11 @@ fn get_cargo_metadata() -> Metadata { /// Additionally, somewhere between cargo metadata and TyCtxt, '-' gets replaced with '_' so we /// make that same transformation here. fn local_crates(metadata: &Metadata) -> String { - assert!(metadata.workspace_members.len() > 0); + assert!(!metadata.workspace_members.is_empty()); let mut local_crates = String::new(); for member in &metadata.workspace_members { - let name = member.split(" ").nth(0).unwrap(); - let name = name.replace("-", "_"); + let name = member.split(' ').next().unwrap(); + let name = name.replace('-', "_"); local_crates.push_str(&name); local_crates.push(','); } @@ -708,7 +712,7 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { get_arg_flag_value("--crate-name").unwrap(), // This is technically a `-C` flag but the prefix seems unique enough... // (and cargo passes this before the filename so it should be unique) - get_arg_flag_value("extra-filename").unwrap_or(String::new()), + get_arg_flag_value("extra-filename").unwrap_or_default(), suffix, )); path @@ -808,11 +812,10 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { // Forward arguments, but remove "link" from "--emit" to make this a check-only build. let emit_flag = "--emit"; while let Some(arg) = args.next() { - if arg.starts_with(emit_flag) { + if let Some(val) = arg.strip_prefix(emit_flag) { // Patch this argument. First, extract its value. - let val = &arg[emit_flag.len()..]; - assert!(val.starts_with("="), "`cargo` should pass `--emit=X` as one argument"); - let val = &val[1..]; + let val = + val.strip_prefix('=').expect("`cargo` should pass `--emit=X` as one argument"); let mut val: Vec<_> = val.split(',').collect(); // Now make sure "link" is not in there, but "metadata" is. if let Some(i) = val.iter().position(|&s| s == "link") { @@ -937,12 +940,10 @@ fn phase_runner(binary: &Path, binary_args: env::Args, phase: RunnerPhase) { while let Some(arg) = args.next() { if arg == "--extern" { forward_patched_extern_arg(&mut args, &mut cmd); - } else if arg.starts_with(error_format_flag) { - let suffix = &arg[error_format_flag.len()..]; + } else if let Some(suffix) = arg.strip_prefix(error_format_flag) { assert!(suffix.starts_with('=')); // Drop this argument. - } else if arg.starts_with(json_flag) { - let suffix = &arg[json_flag.len()..]; + } else if let Some(suffix) = arg.strip_prefix(json_flag) { assert!(suffix.starts_with('=')); // Drop this argument. } else { From ad7587fedcf29a6629e0218f0e180ddf8960461d Mon Sep 17 00:00:00 2001 From: Aaron Kofsky Date: Tue, 31 May 2022 14:05:04 -0400 Subject: [PATCH 3163/5092] Add `let_underscore_lock` lint. Similar to `let_underscore_drop`, this lint checks for statements similar to `let _ = foo`, where `foo` is a lock guard. These types of let statements are especially problematic because the lock gets released immediately, instead of at the end of the scope. This behavior is almost always the wrong thing. --- compiler/rustc_lint/src/let_underscore.rs | 72 ++++++++++++++++++++++- compiler/rustc_lint/src/lib.rs | 2 +- src/test/ui/let_underscore_lock.rs | 8 +++ src/test/ui/let_underscore_lock.stderr | 12 ++++ 4 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/let_underscore_lock.rs create mode 100644 src/test/ui/let_underscore_lock.stderr diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index 44242173c008..81906a24d902 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -1,5 +1,7 @@ use crate::{LateContext, LateLintPass, LintContext}; use rustc_hir as hir; +use rustc_middle::ty::{self, subst::GenericArgKind}; +use rustc_span::Symbol; declare_lint! { /// The `let_underscore_drop` lint checks for statements which don't bind @@ -43,7 +45,53 @@ declare_lint! { "non-binding let on a type that implements `Drop`" } -declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_DROP]); +declare_lint! { + /// The `let_underscore_lock` lint checks for statements which don't bind + /// a mutex to anything, causing the lock to be released immediately instead + /// of at end of scope, which is typically incorrect. + /// + /// ### Example + /// ```rust + /// use std::sync::{Arc, Mutex}; + /// use std::thread; + /// let data = Arc::new(Mutex::new(0)); + /// + /// thread::spawn(move || { + /// // The lock is immediately released instead of at the end of the + /// // scope, which is probably not intended. + /// let _ = data.lock().unwrap(); + /// println!("doing some work"); + /// let mut lock = data.lock().unwrap(); + /// *lock += 1; + /// }); + /// ``` + /// ### Explanation + /// + /// Statements which assign an expression to an underscore causes the + /// expression to immediately drop instead of extending the expression's + /// lifetime to the end of the scope. This is usually unintended, + /// especially for types like `MutexGuard`, which are typically used to + /// lock a mutex for the duration of an entire scope. + /// + /// If you want to extend the expression's lifetime to the end of the scope, + /// assign an underscore-prefixed name (such as `_foo`) to the expression. + /// If you do actually want to drop the expression immediately, then + /// calling `std::mem::drop` on the expression is clearer and helps convey + /// intent. + pub LET_UNDERSCORE_LOCK, + Warn, + "non-binding let on a synchronization lock" +} + +declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_DROP, LET_UNDERSCORE_LOCK]); + +const SYNC_GUARD_PATHS: [&[&str]; 5] = [ + &["std", "sync", "mutex", "MutexGuard"], + &["std", "sync", "rwlock", "RwLockReadGuard"], + &["std", "sync", "rwlock", "RwLockWriteGuard"], + &["parking_lot", "raw_mutex", "RawMutex"], + &["parking_lot", "raw_rwlock", "RawRwLock"], +]; impl<'tcx> LateLintPass<'tcx> for LetUnderscore { fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::Local<'_>) { @@ -53,7 +101,27 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { if let Some(init) = local.init { let init_ty = cx.typeck_results().expr_ty(init); let needs_drop = init_ty.needs_drop(cx.tcx, cx.param_env); - if needs_drop { + let is_sync_lock = init_ty.walk().any(|inner| match inner.unpack() { + GenericArgKind::Type(inner_ty) => { + SYNC_GUARD_PATHS.iter().any(|guard_path| match inner_ty.kind() { + ty::Adt(adt, _) => { + let ty_path = cx.get_def_path(adt.did()); + guard_path.iter().map(|x| Symbol::intern(x)).eq(ty_path.iter().copied()) + } + _ => false, + }) + } + + GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, + }); + if is_sync_lock { + cx.struct_span_lint(LET_UNDERSCORE_LOCK, local.span, |lint| { + lint.build("non-binding let on a synchronization lock") + .help("consider binding to an unused variable") + .help("consider explicitly droping with `std::mem::drop`") + .emit(); + }) + } else if needs_drop { cx.struct_span_lint(LET_UNDERSCORE_DROP, local.span, |lint| { lint.build("non-binding let on a type that implements `Drop`") .help("consider binding to an unused variable") diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 55396b36dbc2..79661c0fefe8 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -317,7 +317,7 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { REDUNDANT_SEMICOLONS ); - add_lint_group!("let_underscore", LET_UNDERSCORE_DROP); + add_lint_group!("let_underscore", LET_UNDERSCORE_DROP, LET_UNDERSCORE_LOCK); add_lint_group!( "rust_2018_idioms", diff --git a/src/test/ui/let_underscore_lock.rs b/src/test/ui/let_underscore_lock.rs new file mode 100644 index 000000000000..774b610db2fb --- /dev/null +++ b/src/test/ui/let_underscore_lock.rs @@ -0,0 +1,8 @@ +// run-pass + +use std::sync::{Arc, Mutex}; + +fn main() { + let data = Arc::new(Mutex::new(0)); + let _ = data.lock().unwrap(); //~WARNING non-binding let on a synchronization lock +} diff --git a/src/test/ui/let_underscore_lock.stderr b/src/test/ui/let_underscore_lock.stderr new file mode 100644 index 000000000000..77379d8c3db2 --- /dev/null +++ b/src/test/ui/let_underscore_lock.stderr @@ -0,0 +1,12 @@ +warning: non-binding let on a synchronization lock + --> $DIR/let_underscore_lock.rs:7:5 + | +LL | let _ = data.lock().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(let_underscore_lock)]` on by default + = help: consider binding to an unused variable + = help: consider explicitly droping with `std::mem::drop` + +warning: 1 warning emitted + From 758a9fd0f9ac191f0ea99215e07816631f402b7e Mon Sep 17 00:00:00 2001 From: Aaron Kofsky Date: Thu, 2 Jun 2022 14:58:44 -0400 Subject: [PATCH 3164/5092] Add `let_underscore_must_use` lint. Similar to `let_underscore_drop`, this lint checks for statements similar to `let _ = foo`, where `foo` is an expression marked `must_use`. --- compiler/rustc_lint/src/let_underscore.rs | 106 ++++++++++++++++++++- compiler/rustc_lint/src/lib.rs | 7 +- src/test/ui/let_underscore_must_use.rs | 12 +++ src/test/ui/let_underscore_must_use.stderr | 21 ++++ 4 files changed, 143 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/let_underscore_must_use.rs create mode 100644 src/test/ui/let_underscore_must_use.stderr diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index 81906a24d902..40e6d12abf91 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -1,6 +1,6 @@ use crate::{LateContext, LateLintPass, LintContext}; use rustc_hir as hir; -use rustc_middle::ty::{self, subst::GenericArgKind}; +use rustc_middle::ty::{self, subst::GenericArgKind, Ty}; use rustc_span::Symbol; declare_lint! { @@ -83,7 +83,32 @@ declare_lint! { "non-binding let on a synchronization lock" } -declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_DROP, LET_UNDERSCORE_LOCK]); +declare_lint! { + /// The `let_underscore_must_use` lint checks for statements which don't bind + /// a `must_use` expression to anything, causing the lock to be released + /// immediately instead of at end of scope, which is typically incorrect. + /// + /// ### Example + /// ```rust + /// #[must_use] + /// struct SomeStruct; + /// + /// fn main() { + /// // SomeStuct is dropped immediately instead of at end of scope. + /// let _ = SomeStruct; + /// } + /// ``` + /// ### Explanation + /// + /// Statements which assign an expression to an underscore causes the + /// expression to immediately drop. Usually, it's better to explicitly handle + /// the `must_use` expression. + pub LET_UNDERSCORE_MUST_USE, + Warn, + "non-binding let on a expression marked `must_use`" +} + +declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_DROP, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_MUST_USE]); const SYNC_GUARD_PATHS: [&[&str]; 5] = [ &["std", "sync", "mutex", "MutexGuard"], @@ -114,6 +139,8 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, }); + let is_must_use_ty = is_must_use_ty(cx, cx.typeck_results().expr_ty(init)); + let is_must_use_func_call = is_must_use_func_call(cx, init); if is_sync_lock { cx.struct_span_lint(LET_UNDERSCORE_LOCK, local.span, |lint| { lint.build("non-binding let on a synchronization lock") @@ -121,6 +148,13 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { .help("consider explicitly droping with `std::mem::drop`") .emit(); }) + } else if is_must_use_ty || is_must_use_func_call { + cx.struct_span_lint(LET_UNDERSCORE_MUST_USE, local.span, |lint| { + lint.build("non-binding let on a expression marked `must_use`") + .help("consider binding to an unused variable") + .help("consider explicitly droping with `std::mem::drop`") + .emit(); + }) } else if needs_drop { cx.struct_span_lint(LET_UNDERSCORE_DROP, local.span, |lint| { lint.build("non-binding let on a type that implements `Drop`") @@ -130,5 +164,73 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { }) } } + + fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + match ty.kind() { + ty::Adt(adt, _) => has_must_use_attr(cx, adt.did()), + ty::Foreign(ref did) => has_must_use_attr(cx, *did), + ty::Slice(ty) + | ty::Array(ty, _) + | ty::RawPtr(ty::TypeAndMut { ty, .. }) + | ty::Ref(_, ty, _) => { + // for the Array case we don't need to care for the len == 0 case + // because we don't want to lint functions returning empty arrays + is_must_use_ty(cx, *ty) + } + ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)), + ty::Opaque(ref def_id, _) => { + for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) { + if let ty::PredicateKind::Trait(trait_predicate) = + predicate.kind().skip_binder() + { + if has_must_use_attr(cx, trait_predicate.trait_ref.def_id) { + return true; + } + } + } + false + } + ty::Dynamic(binder, _) => { + for predicate in binder.iter() { + if let ty::ExistentialPredicate::Trait(ref trait_ref) = + predicate.skip_binder() + { + if has_must_use_attr(cx, trait_ref.def_id) { + return true; + } + } + } + false + } + _ => false, + } + } + + // check if expr is calling method or function with #[must_use] attribute + fn is_must_use_func_call(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + let did = match expr.kind { + hir::ExprKind::Call(path, _) if let hir::ExprKind::Path(ref qpath) = path.kind => { + if let hir::def::Res::Def(_, did) = cx.qpath_res(qpath, path.hir_id) { + Some(did) + } else { + None + } + }, + hir::ExprKind::MethodCall(..) => { + cx.typeck_results().type_dependent_def_id(expr.hir_id) + } + _ => None, + }; + + did.map_or(false, |did| has_must_use_attr(cx, did)) + } + + // returns true if DefId contains a `#[must_use]` attribute + fn has_must_use_attr(cx: &LateContext<'_>, did: hir::def_id::DefId) -> bool { + cx.tcx + .get_attrs(did, rustc_span::sym::must_use) + .find(|a| a.has_name(rustc_span::sym::must_use)) + .is_some() + } } } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 79661c0fefe8..4359a54b698d 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -317,7 +317,12 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { REDUNDANT_SEMICOLONS ); - add_lint_group!("let_underscore", LET_UNDERSCORE_DROP, LET_UNDERSCORE_LOCK); + add_lint_group!( + "let_underscore", + LET_UNDERSCORE_DROP, + LET_UNDERSCORE_LOCK, + LET_UNDERSCORE_MUST_USE + ); add_lint_group!( "rust_2018_idioms", diff --git a/src/test/ui/let_underscore_must_use.rs b/src/test/ui/let_underscore_must_use.rs new file mode 100644 index 000000000000..6a78e3fc4b40 --- /dev/null +++ b/src/test/ui/let_underscore_must_use.rs @@ -0,0 +1,12 @@ +// run-pass + +#[must_use] +struct MustUseType; + +#[must_use] +fn must_use_function() -> () {} + +fn main() { + let _ = MustUseType; //~WARNING non-binding let on a expression marked `must_use` + let _ = must_use_function(); //~WARNING non-binding let on a expression marked `must_use` +} diff --git a/src/test/ui/let_underscore_must_use.stderr b/src/test/ui/let_underscore_must_use.stderr new file mode 100644 index 000000000000..0b840385e5df --- /dev/null +++ b/src/test/ui/let_underscore_must_use.stderr @@ -0,0 +1,21 @@ +warning: non-binding let on a expression marked `must_use` + --> $DIR/let_underscore_must_use.rs:10:5 + | +LL | let _ = MustUseType; + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(let_underscore_must_use)]` on by default + = help: consider binding to an unused variable + = help: consider explicitly droping with `std::mem::drop` + +warning: non-binding let on a expression marked `must_use` + --> $DIR/let_underscore_must_use.rs:11:5 + | +LL | let _ = must_use_function(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider binding to an unused variable + = help: consider explicitly droping with `std::mem::drop` + +warning: 2 warnings emitted + From 36b6309c6556e5486138057e8c654b40e005327d Mon Sep 17 00:00:00 2001 From: Aaron Kofsky Date: Fri, 3 Jun 2022 14:37:14 -0400 Subject: [PATCH 3165/5092] Move let_underscore tests to their own subfolder. This was done to pass `tidy`. --- src/test/ui/{ => let_underscore}/let_underscore_drop.rs | 0 src/test/ui/{ => let_underscore}/let_underscore_drop.stderr | 0 src/test/ui/{ => let_underscore}/let_underscore_lock.rs | 0 src/test/ui/{ => let_underscore}/let_underscore_lock.stderr | 0 src/test/ui/{ => let_underscore}/let_underscore_must_use.rs | 0 src/test/ui/{ => let_underscore}/let_underscore_must_use.stderr | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/{ => let_underscore}/let_underscore_drop.rs (100%) rename src/test/ui/{ => let_underscore}/let_underscore_drop.stderr (100%) rename src/test/ui/{ => let_underscore}/let_underscore_lock.rs (100%) rename src/test/ui/{ => let_underscore}/let_underscore_lock.stderr (100%) rename src/test/ui/{ => let_underscore}/let_underscore_must_use.rs (100%) rename src/test/ui/{ => let_underscore}/let_underscore_must_use.stderr (100%) diff --git a/src/test/ui/let_underscore_drop.rs b/src/test/ui/let_underscore/let_underscore_drop.rs similarity index 100% rename from src/test/ui/let_underscore_drop.rs rename to src/test/ui/let_underscore/let_underscore_drop.rs diff --git a/src/test/ui/let_underscore_drop.stderr b/src/test/ui/let_underscore/let_underscore_drop.stderr similarity index 100% rename from src/test/ui/let_underscore_drop.stderr rename to src/test/ui/let_underscore/let_underscore_drop.stderr diff --git a/src/test/ui/let_underscore_lock.rs b/src/test/ui/let_underscore/let_underscore_lock.rs similarity index 100% rename from src/test/ui/let_underscore_lock.rs rename to src/test/ui/let_underscore/let_underscore_lock.rs diff --git a/src/test/ui/let_underscore_lock.stderr b/src/test/ui/let_underscore/let_underscore_lock.stderr similarity index 100% rename from src/test/ui/let_underscore_lock.stderr rename to src/test/ui/let_underscore/let_underscore_lock.stderr diff --git a/src/test/ui/let_underscore_must_use.rs b/src/test/ui/let_underscore/let_underscore_must_use.rs similarity index 100% rename from src/test/ui/let_underscore_must_use.rs rename to src/test/ui/let_underscore/let_underscore_must_use.rs diff --git a/src/test/ui/let_underscore_must_use.stderr b/src/test/ui/let_underscore/let_underscore_must_use.stderr similarity index 100% rename from src/test/ui/let_underscore_must_use.stderr rename to src/test/ui/let_underscore/let_underscore_must_use.stderr From ae2ac3b4c568d2d20cb395a57a163e1e298d6d6c Mon Sep 17 00:00:00 2001 From: Aaron Kofsky Date: Fri, 3 Jun 2022 16:19:55 -0400 Subject: [PATCH 3166/5092] Allow `let_underscore_drop` and `let_underscore_must_use` by default. These lints are very noisy and are allow-by-default in clippy anyways. Hence, setting them to allow-by-default here makes more sense than warning constantly on these cases. --- compiler/rustc_lint/src/let_underscore.rs | 4 ++-- src/test/ui/let_underscore/let_underscore_drop.rs | 1 + src/test/ui/let_underscore/let_underscore_drop.stderr | 4 ++-- src/test/ui/let_underscore/let_underscore_must_use.rs | 1 + src/test/ui/let_underscore/let_underscore_must_use.stderr | 6 +++--- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index 40e6d12abf91..985c7300efa9 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -41,7 +41,7 @@ declare_lint! { /// calling `std::mem::drop` on the expression is clearer and helps convey /// intent. pub LET_UNDERSCORE_DROP, - Warn, + Allow, "non-binding let on a type that implements `Drop`" } @@ -104,7 +104,7 @@ declare_lint! { /// expression to immediately drop. Usually, it's better to explicitly handle /// the `must_use` expression. pub LET_UNDERSCORE_MUST_USE, - Warn, + Allow, "non-binding let on a expression marked `must_use`" } diff --git a/src/test/ui/let_underscore/let_underscore_drop.rs b/src/test/ui/let_underscore/let_underscore_drop.rs index c1c5207d0fe8..75c6ecec3ee5 100644 --- a/src/test/ui/let_underscore/let_underscore_drop.rs +++ b/src/test/ui/let_underscore/let_underscore_drop.rs @@ -1,4 +1,5 @@ // run-pass +// compile-flags: -W let_underscore_drop struct NontrivialDrop; diff --git a/src/test/ui/let_underscore/let_underscore_drop.stderr b/src/test/ui/let_underscore/let_underscore_drop.stderr index 40ed1abd8dc6..f4fd663c7f9e 100644 --- a/src/test/ui/let_underscore/let_underscore_drop.stderr +++ b/src/test/ui/let_underscore/let_underscore_drop.stderr @@ -1,10 +1,10 @@ warning: non-binding let on a type that implements `Drop` - --> $DIR/let_underscore_drop.rs:12:5 + --> $DIR/let_underscore_drop.rs:13:5 | LL | let _ = NontrivialDrop; | ^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `#[warn(let_underscore_drop)]` on by default + = note: requested on the command line with `-W let-underscore-drop` = help: consider binding to an unused variable = help: consider explicitly droping with `std::mem::drop` diff --git a/src/test/ui/let_underscore/let_underscore_must_use.rs b/src/test/ui/let_underscore/let_underscore_must_use.rs index 6a78e3fc4b40..8efaad51ea87 100644 --- a/src/test/ui/let_underscore/let_underscore_must_use.rs +++ b/src/test/ui/let_underscore/let_underscore_must_use.rs @@ -1,4 +1,5 @@ // run-pass +// compile-flags: -W let_underscore_must_use #[must_use] struct MustUseType; diff --git a/src/test/ui/let_underscore/let_underscore_must_use.stderr b/src/test/ui/let_underscore/let_underscore_must_use.stderr index 0b840385e5df..ea1de45e17b5 100644 --- a/src/test/ui/let_underscore/let_underscore_must_use.stderr +++ b/src/test/ui/let_underscore/let_underscore_must_use.stderr @@ -1,15 +1,15 @@ warning: non-binding let on a expression marked `must_use` - --> $DIR/let_underscore_must_use.rs:10:5 + --> $DIR/let_underscore_must_use.rs:11:5 | LL | let _ = MustUseType; | ^^^^^^^^^^^^^^^^^^^^ | - = note: `#[warn(let_underscore_must_use)]` on by default + = note: requested on the command line with `-W let-underscore-must-use` = help: consider binding to an unused variable = help: consider explicitly droping with `std::mem::drop` warning: non-binding let on a expression marked `must_use` - --> $DIR/let_underscore_must_use.rs:11:5 + --> $DIR/let_underscore_must_use.rs:12:5 | LL | let _ = must_use_function(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From eba6c789dcfca7065d1c292c06eb447ac9895db3 Mon Sep 17 00:00:00 2001 From: Aaron Kofsky Date: Fri, 3 Jun 2022 21:33:13 -0400 Subject: [PATCH 3167/5092] Show code suggestions in `let_undescore` lint messages. This commit uses `span_suggestion_verbose` to add what specific code changes can be done as suggested by the lint--in this case, either binding the expression to an unused variable or using `std::mem::drop` to drop the value explicitly. --- compiler/rustc_lint/src/let_underscore.rs | 60 +++++++++++++++---- .../let_underscore/let_underscore_drop.stderr | 10 +++- .../let_underscore/let_underscore_lock.stderr | 10 +++- .../let_underscore_must_use.stderr | 20 +++++-- 4 files changed, 79 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index 985c7300efa9..4e4cedaeb782 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -1,6 +1,10 @@ use crate::{LateContext, LateLintPass, LintContext}; +use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_middle::ty::{self, subst::GenericArgKind, Ty}; +use rustc_middle::{ + lint::LintDiagnosticBuilder, + ty::{self, subst::GenericArgKind, Ty}, +}; use rustc_span::Symbol; declare_lint! { @@ -141,30 +145,60 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { }); let is_must_use_ty = is_must_use_ty(cx, cx.typeck_results().expr_ty(init)); let is_must_use_func_call = is_must_use_func_call(cx, init); + if is_sync_lock { cx.struct_span_lint(LET_UNDERSCORE_LOCK, local.span, |lint| { - lint.build("non-binding let on a synchronization lock") - .help("consider binding to an unused variable") - .help("consider explicitly droping with `std::mem::drop`") - .emit(); + build_and_emit_lint( + lint, + local, + init.span, + "non-binding let on a synchronization lock", + ) }) } else if is_must_use_ty || is_must_use_func_call { cx.struct_span_lint(LET_UNDERSCORE_MUST_USE, local.span, |lint| { - lint.build("non-binding let on a expression marked `must_use`") - .help("consider binding to an unused variable") - .help("consider explicitly droping with `std::mem::drop`") - .emit(); + build_and_emit_lint( + lint, + local, + init.span, + "non-binding let on a expression marked `must_use`", + ); }) } else if needs_drop { cx.struct_span_lint(LET_UNDERSCORE_DROP, local.span, |lint| { - lint.build("non-binding let on a type that implements `Drop`") - .help("consider binding to an unused variable") - .help("consider explicitly droping with `std::mem::drop`") - .emit(); + build_and_emit_lint( + lint, + local, + init.span, + "non-binding let on a type that implements `Drop`", + ); }) } } + fn build_and_emit_lint( + lint: LintDiagnosticBuilder<'_, ()>, + local: &hir::Local<'_>, + init_span: rustc_span::Span, + msg: &str, + ) { + lint.build(msg) + .span_suggestion_verbose( + local.pat.span, + "consider binding to an unused variable", + "_unused", + Applicability::MachineApplicable, + ) + .span_suggestion_verbose( + init_span, + "consider explicitly droping with `std::mem::drop`", + "drop(...)", + Applicability::HasPlaceholders, + ) + .emit(); + } + + // return true if `ty` is a type that is marked as `must_use` fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { match ty.kind() { ty::Adt(adt, _) => has_must_use_attr(cx, adt.did()), diff --git a/src/test/ui/let_underscore/let_underscore_drop.stderr b/src/test/ui/let_underscore/let_underscore_drop.stderr index f4fd663c7f9e..5034f682bb76 100644 --- a/src/test/ui/let_underscore/let_underscore_drop.stderr +++ b/src/test/ui/let_underscore/let_underscore_drop.stderr @@ -5,8 +5,14 @@ LL | let _ = NontrivialDrop; | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: requested on the command line with `-W let-underscore-drop` - = help: consider binding to an unused variable - = help: consider explicitly droping with `std::mem::drop` +help: consider binding to an unused variable + | +LL | let _unused = NontrivialDrop; + | ~~~~~~~ +help: consider explicitly droping with `std::mem::drop` + | +LL | let _ = drop(...); + | ~~~~~~~~~ warning: 1 warning emitted diff --git a/src/test/ui/let_underscore/let_underscore_lock.stderr b/src/test/ui/let_underscore/let_underscore_lock.stderr index 77379d8c3db2..08f81962f3c6 100644 --- a/src/test/ui/let_underscore/let_underscore_lock.stderr +++ b/src/test/ui/let_underscore/let_underscore_lock.stderr @@ -5,8 +5,14 @@ LL | let _ = data.lock().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(let_underscore_lock)]` on by default - = help: consider binding to an unused variable - = help: consider explicitly droping with `std::mem::drop` +help: consider binding to an unused variable + | +LL | let _unused = data.lock().unwrap(); + | ~~~~~~~ +help: consider explicitly droping with `std::mem::drop` + | +LL | let _ = drop(...); + | ~~~~~~~~~ warning: 1 warning emitted diff --git a/src/test/ui/let_underscore/let_underscore_must_use.stderr b/src/test/ui/let_underscore/let_underscore_must_use.stderr index ea1de45e17b5..959572edd7c0 100644 --- a/src/test/ui/let_underscore/let_underscore_must_use.stderr +++ b/src/test/ui/let_underscore/let_underscore_must_use.stderr @@ -5,8 +5,14 @@ LL | let _ = MustUseType; | ^^^^^^^^^^^^^^^^^^^^ | = note: requested on the command line with `-W let-underscore-must-use` - = help: consider binding to an unused variable - = help: consider explicitly droping with `std::mem::drop` +help: consider binding to an unused variable + | +LL | let _unused = MustUseType; + | ~~~~~~~ +help: consider explicitly droping with `std::mem::drop` + | +LL | let _ = drop(...); + | ~~~~~~~~~ warning: non-binding let on a expression marked `must_use` --> $DIR/let_underscore_must_use.rs:12:5 @@ -14,8 +20,14 @@ warning: non-binding let on a expression marked `must_use` LL | let _ = must_use_function(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider binding to an unused variable - = help: consider explicitly droping with `std::mem::drop` +help: consider binding to an unused variable + | +LL | let _unused = must_use_function(); + | ~~~~~~~ +help: consider explicitly droping with `std::mem::drop` + | +LL | let _ = drop(...); + | ~~~~~~~~~ warning: 2 warnings emitted From f479289e78bc60fbb2aaa3abb33f7726bb12ea89 Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Sat, 4 Jun 2022 16:12:45 -0400 Subject: [PATCH 3168/5092] move dummy test module to auxiliary directory --- src/test/ui/modules/auxiliary/dummy_lib.rs | 2 ++ src/test/ui/modules/dummy.rs | 1 - src/test/ui/modules/special_module_name_ignore.rs | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/modules/auxiliary/dummy_lib.rs delete mode 100644 src/test/ui/modules/dummy.rs diff --git a/src/test/ui/modules/auxiliary/dummy_lib.rs b/src/test/ui/modules/auxiliary/dummy_lib.rs new file mode 100644 index 000000000000..ef805c1f0203 --- /dev/null +++ b/src/test/ui/modules/auxiliary/dummy_lib.rs @@ -0,0 +1,2 @@ +#[allow(dead_code)] +pub struct Dummy; diff --git a/src/test/ui/modules/dummy.rs b/src/test/ui/modules/dummy.rs deleted file mode 100644 index 831e38292a9b..000000000000 --- a/src/test/ui/modules/dummy.rs +++ /dev/null @@ -1 +0,0 @@ -pub struct Dummy; diff --git a/src/test/ui/modules/special_module_name_ignore.rs b/src/test/ui/modules/special_module_name_ignore.rs index cae06b49ee0b..07cea9b2b05a 100644 --- a/src/test/ui/modules/special_module_name_ignore.rs +++ b/src/test/ui/modules/special_module_name_ignore.rs @@ -1,9 +1,9 @@ // run-pass -#[path = "dummy.rs"] +#[path = "auxiliary/dummy_lib.rs"] mod lib; -#[path = "dummy.rs"] +#[path = "auxiliary/dummy_lib.rs"] mod main; fn main() {} From 6b179e3a67a2242b63892a1831ba217d968c2f62 Mon Sep 17 00:00:00 2001 From: Aaron Kofsky Date: Sat, 4 Jun 2022 13:50:12 -0400 Subject: [PATCH 3169/5092] Set `let_underscore_lock` to Deny by default. Clippy sets this lint to Deny by default, and it having the lint be Deny is useful for when we test the lint against a Crater run. --- compiler/rustc_lint/src/let_underscore.rs | 4 ++-- src/test/ui/let_underscore/let_underscore_lock.rs | 4 +--- src/test/ui/let_underscore/let_underscore_lock.stderr | 8 ++++---- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index 4e4cedaeb782..306c6197c24e 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -55,7 +55,7 @@ declare_lint! { /// of at end of scope, which is typically incorrect. /// /// ### Example - /// ```rust + /// ```compile_fail /// use std::sync::{Arc, Mutex}; /// use std::thread; /// let data = Arc::new(Mutex::new(0)); @@ -83,7 +83,7 @@ declare_lint! { /// calling `std::mem::drop` on the expression is clearer and helps convey /// intent. pub LET_UNDERSCORE_LOCK, - Warn, + Deny, "non-binding let on a synchronization lock" } diff --git a/src/test/ui/let_underscore/let_underscore_lock.rs b/src/test/ui/let_underscore/let_underscore_lock.rs index 774b610db2fb..c37264136ef7 100644 --- a/src/test/ui/let_underscore/let_underscore_lock.rs +++ b/src/test/ui/let_underscore/let_underscore_lock.rs @@ -1,8 +1,6 @@ -// run-pass - use std::sync::{Arc, Mutex}; fn main() { let data = Arc::new(Mutex::new(0)); - let _ = data.lock().unwrap(); //~WARNING non-binding let on a synchronization lock + let _ = data.lock().unwrap(); //~ERROR non-binding let on a synchronization lock } diff --git a/src/test/ui/let_underscore/let_underscore_lock.stderr b/src/test/ui/let_underscore/let_underscore_lock.stderr index 08f81962f3c6..b7e14e8c7b5c 100644 --- a/src/test/ui/let_underscore/let_underscore_lock.stderr +++ b/src/test/ui/let_underscore/let_underscore_lock.stderr @@ -1,10 +1,10 @@ -warning: non-binding let on a synchronization lock - --> $DIR/let_underscore_lock.rs:7:5 +error: non-binding let on a synchronization lock + --> $DIR/let_underscore_lock.rs:5:5 | LL | let _ = data.lock().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: `#[warn(let_underscore_lock)]` on by default + = note: `#[deny(let_underscore_lock)]` on by default help: consider binding to an unused variable | LL | let _unused = data.lock().unwrap(); @@ -14,5 +14,5 @@ help: consider explicitly droping with `std::mem::drop` LL | let _ = drop(...); | ~~~~~~~~~ -warning: 1 warning emitted +error: aborting due to previous error From 32c03080f184704d4ccb19cd359a1d5784d78770 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 Jun 2022 19:43:46 -0400 Subject: [PATCH 3170/5092] rustup --- rust-version | 2 +- src/shims/windows/dlsym.rs | 1 + src/shims/windows/foreign_items.rs | 4 ++++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 09a847a94fbe..e7a7ad9dd818 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c35035cefc709abddabfb28ecc6a326458d46ce2 +4e725bad73747a4c93a3ac53106e4b4006edc665 diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index fb0c334b3d93..60ef11b79608 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -18,6 +18,7 @@ impl Dlsym { pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { Ok(match name { "GetSystemTimePreciseAsFileTime" => None, + "SetThreadDescription" => None, "NtWriteFile" => Some(Dlsym::NtWriteFile), _ => throw_unsup_format!("unsupported Windows dlsym: {}", name), }) diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 1a9b2300f723..05f9aed17476 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -415,6 +415,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // There is only one thread, so this always succeeds and returns TRUE. this.write_scalar(Scalar::from_i32(1), dest)?; } + "GetCurrentThread" if this.frame_in_std() => { + let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; + } _ => return Ok(EmulateByNameResult::NotSupported), } From a7e2b3e879790284b64529e3fb7d659274420a90 Mon Sep 17 00:00:00 2001 From: Aaron Kofsky Date: Sat, 4 Jun 2022 19:52:12 -0400 Subject: [PATCH 3171/5092] Move local functions to outer scope. --- compiler/rustc_lint/src/let_underscore.rs | 140 +++++++++++----------- 1 file changed, 68 insertions(+), 72 deletions(-) diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index 306c6197c24e..c2d1cff313b8 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -175,74 +175,72 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { }) } } + } +} - fn build_and_emit_lint( - lint: LintDiagnosticBuilder<'_, ()>, - local: &hir::Local<'_>, - init_span: rustc_span::Span, - msg: &str, - ) { - lint.build(msg) - .span_suggestion_verbose( - local.pat.span, - "consider binding to an unused variable", - "_unused", - Applicability::MachineApplicable, - ) - .span_suggestion_verbose( - init_span, - "consider explicitly droping with `std::mem::drop`", - "drop(...)", - Applicability::HasPlaceholders, - ) - .emit(); +fn build_and_emit_lint( + lint: LintDiagnosticBuilder<'_, ()>, + local: &hir::Local<'_>, + init_span: rustc_span::Span, + msg: &str, +) { + lint.build(msg) + .span_suggestion_verbose( + local.pat.span, + "consider binding to an unused variable", + "_unused", + Applicability::MachineApplicable, + ) + .span_suggestion_verbose( + init_span, + "consider explicitly droping with `std::mem::drop`", + "drop(...)", + Applicability::HasPlaceholders, + ) + .emit(); +} + +// return true if `ty` is a type that is marked as `must_use` +fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + match ty.kind() { + ty::Adt(adt, _) => has_must_use_attr(cx, adt.did()), + ty::Foreign(ref did) => has_must_use_attr(cx, *did), + ty::Slice(ty) + | ty::Array(ty, _) + | ty::RawPtr(ty::TypeAndMut { ty, .. }) + | ty::Ref(_, ty, _) => { + // for the Array case we don't need to care for the len == 0 case + // because we don't want to lint functions returning empty arrays + is_must_use_ty(cx, *ty) } - - // return true if `ty` is a type that is marked as `must_use` - fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - match ty.kind() { - ty::Adt(adt, _) => has_must_use_attr(cx, adt.did()), - ty::Foreign(ref did) => has_must_use_attr(cx, *did), - ty::Slice(ty) - | ty::Array(ty, _) - | ty::RawPtr(ty::TypeAndMut { ty, .. }) - | ty::Ref(_, ty, _) => { - // for the Array case we don't need to care for the len == 0 case - // because we don't want to lint functions returning empty arrays - is_must_use_ty(cx, *ty) - } - ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)), - ty::Opaque(ref def_id, _) => { - for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) { - if let ty::PredicateKind::Trait(trait_predicate) = - predicate.kind().skip_binder() - { - if has_must_use_attr(cx, trait_predicate.trait_ref.def_id) { - return true; - } - } + ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)), + ty::Opaque(ref def_id, _) => { + for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) { + if let ty::PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder() { + if has_must_use_attr(cx, trait_predicate.trait_ref.def_id) { + return true; } - false } - ty::Dynamic(binder, _) => { - for predicate in binder.iter() { - if let ty::ExistentialPredicate::Trait(ref trait_ref) = - predicate.skip_binder() - { - if has_must_use_attr(cx, trait_ref.def_id) { - return true; - } - } - } - false - } - _ => false, } + false } + ty::Dynamic(binder, _) => { + for predicate in binder.iter() { + if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { + if has_must_use_attr(cx, trait_ref.def_id) { + return true; + } + } + } + false + } + _ => false, + } +} - // check if expr is calling method or function with #[must_use] attribute - fn is_must_use_func_call(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { - let did = match expr.kind { +// check if expr is calling method or function with #[must_use] attribute +fn is_must_use_func_call(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + let did = match expr.kind { hir::ExprKind::Call(path, _) if let hir::ExprKind::Path(ref qpath) = path.kind => { if let hir::def::Res::Def(_, did) = cx.qpath_res(qpath, path.hir_id) { Some(did) @@ -256,15 +254,13 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { _ => None, }; - did.map_or(false, |did| has_must_use_attr(cx, did)) - } - - // returns true if DefId contains a `#[must_use]` attribute - fn has_must_use_attr(cx: &LateContext<'_>, did: hir::def_id::DefId) -> bool { - cx.tcx - .get_attrs(did, rustc_span::sym::must_use) - .find(|a| a.has_name(rustc_span::sym::must_use)) - .is_some() - } - } + did.map_or(false, |did| has_must_use_attr(cx, did)) +} + +// returns true if DefId contains a `#[must_use]` attribute +fn has_must_use_attr(cx: &LateContext<'_>, did: hir::def_id::DefId) -> bool { + cx.tcx + .get_attrs(did, rustc_span::sym::must_use) + .find(|a| a.has_name(rustc_span::sym::must_use)) + .is_some() } From 7e485bf4ddd3f56c76a572757d60c24dcfaa7dbe Mon Sep 17 00:00:00 2001 From: Aaron Kofsky Date: Sat, 4 Jun 2022 20:04:01 -0400 Subject: [PATCH 3172/5092] Move `let_underscore` tests into the `lint` subfolder. --- src/test/ui/{ => lint}/let_underscore/let_underscore_drop.rs | 0 src/test/ui/{ => lint}/let_underscore/let_underscore_drop.stderr | 0 src/test/ui/{ => lint}/let_underscore/let_underscore_lock.rs | 0 src/test/ui/{ => lint}/let_underscore/let_underscore_lock.stderr | 0 src/test/ui/{ => lint}/let_underscore/let_underscore_must_use.rs | 0 .../ui/{ => lint}/let_underscore/let_underscore_must_use.stderr | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/{ => lint}/let_underscore/let_underscore_drop.rs (100%) rename src/test/ui/{ => lint}/let_underscore/let_underscore_drop.stderr (100%) rename src/test/ui/{ => lint}/let_underscore/let_underscore_lock.rs (100%) rename src/test/ui/{ => lint}/let_underscore/let_underscore_lock.stderr (100%) rename src/test/ui/{ => lint}/let_underscore/let_underscore_must_use.rs (100%) rename src/test/ui/{ => lint}/let_underscore/let_underscore_must_use.stderr (100%) diff --git a/src/test/ui/let_underscore/let_underscore_drop.rs b/src/test/ui/lint/let_underscore/let_underscore_drop.rs similarity index 100% rename from src/test/ui/let_underscore/let_underscore_drop.rs rename to src/test/ui/lint/let_underscore/let_underscore_drop.rs diff --git a/src/test/ui/let_underscore/let_underscore_drop.stderr b/src/test/ui/lint/let_underscore/let_underscore_drop.stderr similarity index 100% rename from src/test/ui/let_underscore/let_underscore_drop.stderr rename to src/test/ui/lint/let_underscore/let_underscore_drop.stderr diff --git a/src/test/ui/let_underscore/let_underscore_lock.rs b/src/test/ui/lint/let_underscore/let_underscore_lock.rs similarity index 100% rename from src/test/ui/let_underscore/let_underscore_lock.rs rename to src/test/ui/lint/let_underscore/let_underscore_lock.rs diff --git a/src/test/ui/let_underscore/let_underscore_lock.stderr b/src/test/ui/lint/let_underscore/let_underscore_lock.stderr similarity index 100% rename from src/test/ui/let_underscore/let_underscore_lock.stderr rename to src/test/ui/lint/let_underscore/let_underscore_lock.stderr diff --git a/src/test/ui/let_underscore/let_underscore_must_use.rs b/src/test/ui/lint/let_underscore/let_underscore_must_use.rs similarity index 100% rename from src/test/ui/let_underscore/let_underscore_must_use.rs rename to src/test/ui/lint/let_underscore/let_underscore_must_use.rs diff --git a/src/test/ui/let_underscore/let_underscore_must_use.stderr b/src/test/ui/lint/let_underscore/let_underscore_must_use.stderr similarity index 100% rename from src/test/ui/let_underscore/let_underscore_must_use.stderr rename to src/test/ui/lint/let_underscore/let_underscore_must_use.stderr From 1421cffca17f8904664d036996768d5880604f71 Mon Sep 17 00:00:00 2001 From: Aaron Kofsky Date: Sat, 4 Jun 2022 20:12:26 -0400 Subject: [PATCH 3173/5092] Add `let_underscore` lint group to `GROUP_DESCRIPTIONS`. --- src/tools/lint-docs/src/groups.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs index 9696e35b7963..2a923a61b0a7 100644 --- a/src/tools/lint-docs/src/groups.rs +++ b/src/tools/lint-docs/src/groups.rs @@ -8,6 +8,7 @@ use std::process::Command; /// Descriptions of rustc lint groups. static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[ ("unused", "Lints that detect things being declared but not used, or excess syntax"), + ("let-underscore", "Lints that detect wildcard let bindings that are likely to be invalid"), ("rustdoc", "Rustdoc-specific lints"), ("rust-2018-idioms", "Lints to nudge you toward idiomatic features of Rust 2018"), ("nonstandard-style", "Violation of standard naming conventions"), From 30e8adb1a766e8444586fef3953bf7715fe588e1 Mon Sep 17 00:00:00 2001 From: Aaron Kofsky Date: Sat, 4 Jun 2022 20:16:56 -0400 Subject: [PATCH 3174/5092] Use `has_attr` instead of `get_attrs` in `has_must_use_attr` --- compiler/rustc_lint/src/let_underscore.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index c2d1cff313b8..d33ea450b3e8 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -259,8 +259,5 @@ fn is_must_use_func_call(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { // returns true if DefId contains a `#[must_use]` attribute fn has_must_use_attr(cx: &LateContext<'_>, did: hir::def_id::DefId) -> bool { - cx.tcx - .get_attrs(did, rustc_span::sym::must_use) - .find(|a| a.has_name(rustc_span::sym::must_use)) - .is_some() + cx.tcx.has_attr(did, rustc_span::sym::must_use) } From e6b66784aca8564557485d902968ff7523cf30ca Mon Sep 17 00:00:00 2001 From: Aaron Kofsky Date: Sat, 4 Jun 2022 20:19:19 -0400 Subject: [PATCH 3175/5092] Bail out early if the type does not has a trivial Drop implementation. If the type has a trivial Drop implementation, then it is probably irrelevant that the type was dropped immediately, since nothing important happens on drop. Hence, we can bail out early instead of doing some expensive checks. --- compiler/rustc_lint/src/let_underscore.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index d33ea450b3e8..1e4565a226c7 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -129,7 +129,11 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { } if let Some(init) = local.init { let init_ty = cx.typeck_results().expr_ty(init); - let needs_drop = init_ty.needs_drop(cx.tcx, cx.param_env); + // If the type has a trivial Drop implementation, then it doesn't + // matter that we drop the value immediately. + if !init_ty.needs_drop(cx.tcx, cx.param_env) { + return; + } let is_sync_lock = init_ty.walk().any(|inner| match inner.unpack() { GenericArgKind::Type(inner_ty) => { SYNC_GUARD_PATHS.iter().any(|guard_path| match inner_ty.kind() { @@ -164,7 +168,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { "non-binding let on a expression marked `must_use`", ); }) - } else if needs_drop { + } else { cx.struct_span_lint(LET_UNDERSCORE_DROP, local.span, |lint| { build_and_emit_lint( lint, From 6342b58ef0f71ca0284dced4b1d22f9726c1c74a Mon Sep 17 00:00:00 2001 From: Aaron Kofsky Date: Sat, 4 Jun 2022 22:27:32 -0400 Subject: [PATCH 3176/5092] Use diagnostic items instead of hard coded paths for `let_underscore_lock` Using diagnostic items avoids having to update the paths if the guard types ever get moved around for some reason. Additionally, it also greatly simplifies the `is_sync_lock` check. --- compiler/rustc_lint/src/let_underscore.rs | 31 ++++++++--------------- compiler/rustc_span/src/symbol.rs | 3 +++ 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index 1e4565a226c7..2ad09312d9d5 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -3,7 +3,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_middle::{ lint::LintDiagnosticBuilder, - ty::{self, subst::GenericArgKind, Ty}, + ty::{self, Ty}, }; use rustc_span::Symbol; @@ -114,12 +114,10 @@ declare_lint! { declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_DROP, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_MUST_USE]); -const SYNC_GUARD_PATHS: [&[&str]; 5] = [ - &["std", "sync", "mutex", "MutexGuard"], - &["std", "sync", "rwlock", "RwLockReadGuard"], - &["std", "sync", "rwlock", "RwLockWriteGuard"], - &["parking_lot", "raw_mutex", "RawMutex"], - &["parking_lot", "raw_rwlock", "RawRwLock"], +const SYNC_GUARD_SYMBOLS: [Symbol; 3] = [ + rustc_span::sym::MutexGuard, + rustc_span::sym::RwLockReadGuard, + rustc_span::sym::RwLockWriteGuard, ]; impl<'tcx> LateLintPass<'tcx> for LetUnderscore { @@ -134,19 +132,12 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { if !init_ty.needs_drop(cx.tcx, cx.param_env) { return; } - let is_sync_lock = init_ty.walk().any(|inner| match inner.unpack() { - GenericArgKind::Type(inner_ty) => { - SYNC_GUARD_PATHS.iter().any(|guard_path| match inner_ty.kind() { - ty::Adt(adt, _) => { - let ty_path = cx.get_def_path(adt.did()); - guard_path.iter().map(|x| Symbol::intern(x)).eq(ty_path.iter().copied()) - } - _ => false, - }) - } - - GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, - }); + let is_sync_lock = match init_ty.kind() { + ty::Adt(adt, _) => SYNC_GUARD_SYMBOLS + .iter() + .any(|guard_symbol| cx.tcx.is_diagnostic_item(*guard_symbol, adt.did())), + _ => false, + }; let is_must_use_ty = is_must_use_ty(cx, cx.typeck_results().expr_ty(init)); let is_must_use_func_call = is_must_use_func_call(cx, init); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 5c9c16350e46..bc9f5c910df5 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -213,6 +213,7 @@ symbols! { LinkedList, LintPass, Mutex, + MutexGuard, N, None, Ok, @@ -250,6 +251,8 @@ symbols! { Right, RustcDecodable, RustcEncodable, + RwLockReadGuard, + RwLockWriteGuard, Send, SeqCst, SliceIndex, From 11663b1d78cd4e9bc68cf13e55ee73189f1d1cf5 Mon Sep 17 00:00:00 2001 From: Aaron Kofsky Date: Sat, 4 Jun 2022 23:31:47 -0400 Subject: [PATCH 3177/5092] Use `check-pass` instead of `run-pass` We don't actually care about running these programs, only checking the warnings they generate. --- src/test/ui/lint/let_underscore/let_underscore_drop.rs | 2 +- src/test/ui/lint/let_underscore/let_underscore_lock.rs | 1 + src/test/ui/lint/let_underscore/let_underscore_must_use.rs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test/ui/lint/let_underscore/let_underscore_drop.rs b/src/test/ui/lint/let_underscore/let_underscore_drop.rs index 75c6ecec3ee5..85ca5dd2880a 100644 --- a/src/test/ui/lint/let_underscore/let_underscore_drop.rs +++ b/src/test/ui/lint/let_underscore/let_underscore_drop.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // compile-flags: -W let_underscore_drop struct NontrivialDrop; diff --git a/src/test/ui/lint/let_underscore/let_underscore_lock.rs b/src/test/ui/lint/let_underscore/let_underscore_lock.rs index c37264136ef7..7423862cdf05 100644 --- a/src/test/ui/lint/let_underscore/let_underscore_lock.rs +++ b/src/test/ui/lint/let_underscore/let_underscore_lock.rs @@ -1,3 +1,4 @@ +// check-fail use std::sync::{Arc, Mutex}; fn main() { diff --git a/src/test/ui/lint/let_underscore/let_underscore_must_use.rs b/src/test/ui/lint/let_underscore/let_underscore_must_use.rs index 8efaad51ea87..3f79dc7a096b 100644 --- a/src/test/ui/lint/let_underscore/let_underscore_must_use.rs +++ b/src/test/ui/lint/let_underscore/let_underscore_must_use.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // compile-flags: -W let_underscore_must_use #[must_use] From b5b5b5471ba324f6b4d5a53957a800ad44126964 Mon Sep 17 00:00:00 2001 From: Aaron Kofsky Date: Sun, 5 Jun 2022 00:05:50 -0400 Subject: [PATCH 3178/5092] Remove `let_underscore_must_use` The `let_underscore_must_use` lint was really only added because clippy included it, but it doesn't actually seem very useful. --- compiler/rustc_lint/src/let_underscore.rs | 105 +----------------- compiler/rustc_lint/src/lib.rs | 7 +- .../let_underscore/let_underscore_must_use.rs | 13 --- .../let_underscore_must_use.stderr | 33 ------ 4 files changed, 3 insertions(+), 155 deletions(-) delete mode 100644 src/test/ui/lint/let_underscore/let_underscore_must_use.rs delete mode 100644 src/test/ui/lint/let_underscore/let_underscore_must_use.stderr diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index 2ad09312d9d5..dea878c4460b 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -1,10 +1,7 @@ use crate::{LateContext, LateLintPass, LintContext}; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_middle::{ - lint::LintDiagnosticBuilder, - ty::{self, Ty}, -}; +use rustc_middle::{lint::LintDiagnosticBuilder, ty}; use rustc_span::Symbol; declare_lint! { @@ -87,32 +84,7 @@ declare_lint! { "non-binding let on a synchronization lock" } -declare_lint! { - /// The `let_underscore_must_use` lint checks for statements which don't bind - /// a `must_use` expression to anything, causing the lock to be released - /// immediately instead of at end of scope, which is typically incorrect. - /// - /// ### Example - /// ```rust - /// #[must_use] - /// struct SomeStruct; - /// - /// fn main() { - /// // SomeStuct is dropped immediately instead of at end of scope. - /// let _ = SomeStruct; - /// } - /// ``` - /// ### Explanation - /// - /// Statements which assign an expression to an underscore causes the - /// expression to immediately drop. Usually, it's better to explicitly handle - /// the `must_use` expression. - pub LET_UNDERSCORE_MUST_USE, - Allow, - "non-binding let on a expression marked `must_use`" -} - -declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_DROP, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_MUST_USE]); +declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_DROP, LET_UNDERSCORE_LOCK]); const SYNC_GUARD_SYMBOLS: [Symbol; 3] = [ rustc_span::sym::MutexGuard, @@ -138,8 +110,6 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { .any(|guard_symbol| cx.tcx.is_diagnostic_item(*guard_symbol, adt.did())), _ => false, }; - let is_must_use_ty = is_must_use_ty(cx, cx.typeck_results().expr_ty(init)); - let is_must_use_func_call = is_must_use_func_call(cx, init); if is_sync_lock { cx.struct_span_lint(LET_UNDERSCORE_LOCK, local.span, |lint| { @@ -150,15 +120,6 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { "non-binding let on a synchronization lock", ) }) - } else if is_must_use_ty || is_must_use_func_call { - cx.struct_span_lint(LET_UNDERSCORE_MUST_USE, local.span, |lint| { - build_and_emit_lint( - lint, - local, - init.span, - "non-binding let on a expression marked `must_use`", - ); - }) } else { cx.struct_span_lint(LET_UNDERSCORE_DROP, local.span, |lint| { build_and_emit_lint( @@ -194,65 +155,3 @@ fn build_and_emit_lint( ) .emit(); } - -// return true if `ty` is a type that is marked as `must_use` -fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { - match ty.kind() { - ty::Adt(adt, _) => has_must_use_attr(cx, adt.did()), - ty::Foreign(ref did) => has_must_use_attr(cx, *did), - ty::Slice(ty) - | ty::Array(ty, _) - | ty::RawPtr(ty::TypeAndMut { ty, .. }) - | ty::Ref(_, ty, _) => { - // for the Array case we don't need to care for the len == 0 case - // because we don't want to lint functions returning empty arrays - is_must_use_ty(cx, *ty) - } - ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)), - ty::Opaque(ref def_id, _) => { - for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) { - if let ty::PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder() { - if has_must_use_attr(cx, trait_predicate.trait_ref.def_id) { - return true; - } - } - } - false - } - ty::Dynamic(binder, _) => { - for predicate in binder.iter() { - if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { - if has_must_use_attr(cx, trait_ref.def_id) { - return true; - } - } - } - false - } - _ => false, - } -} - -// check if expr is calling method or function with #[must_use] attribute -fn is_must_use_func_call(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { - let did = match expr.kind { - hir::ExprKind::Call(path, _) if let hir::ExprKind::Path(ref qpath) = path.kind => { - if let hir::def::Res::Def(_, did) = cx.qpath_res(qpath, path.hir_id) { - Some(did) - } else { - None - } - }, - hir::ExprKind::MethodCall(..) => { - cx.typeck_results().type_dependent_def_id(expr.hir_id) - } - _ => None, - }; - - did.map_or(false, |did| has_must_use_attr(cx, did)) -} - -// returns true if DefId contains a `#[must_use]` attribute -fn has_must_use_attr(cx: &LateContext<'_>, did: hir::def_id::DefId) -> bool { - cx.tcx.has_attr(did, rustc_span::sym::must_use) -} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 4359a54b698d..79661c0fefe8 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -317,12 +317,7 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { REDUNDANT_SEMICOLONS ); - add_lint_group!( - "let_underscore", - LET_UNDERSCORE_DROP, - LET_UNDERSCORE_LOCK, - LET_UNDERSCORE_MUST_USE - ); + add_lint_group!("let_underscore", LET_UNDERSCORE_DROP, LET_UNDERSCORE_LOCK); add_lint_group!( "rust_2018_idioms", diff --git a/src/test/ui/lint/let_underscore/let_underscore_must_use.rs b/src/test/ui/lint/let_underscore/let_underscore_must_use.rs deleted file mode 100644 index 3f79dc7a096b..000000000000 --- a/src/test/ui/lint/let_underscore/let_underscore_must_use.rs +++ /dev/null @@ -1,13 +0,0 @@ -// check-pass -// compile-flags: -W let_underscore_must_use - -#[must_use] -struct MustUseType; - -#[must_use] -fn must_use_function() -> () {} - -fn main() { - let _ = MustUseType; //~WARNING non-binding let on a expression marked `must_use` - let _ = must_use_function(); //~WARNING non-binding let on a expression marked `must_use` -} diff --git a/src/test/ui/lint/let_underscore/let_underscore_must_use.stderr b/src/test/ui/lint/let_underscore/let_underscore_must_use.stderr deleted file mode 100644 index 959572edd7c0..000000000000 --- a/src/test/ui/lint/let_underscore/let_underscore_must_use.stderr +++ /dev/null @@ -1,33 +0,0 @@ -warning: non-binding let on a expression marked `must_use` - --> $DIR/let_underscore_must_use.rs:11:5 - | -LL | let _ = MustUseType; - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: requested on the command line with `-W let-underscore-must-use` -help: consider binding to an unused variable - | -LL | let _unused = MustUseType; - | ~~~~~~~ -help: consider explicitly droping with `std::mem::drop` - | -LL | let _ = drop(...); - | ~~~~~~~~~ - -warning: non-binding let on a expression marked `must_use` - --> $DIR/let_underscore_must_use.rs:12:5 - | -LL | let _ = must_use_function(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: consider binding to an unused variable - | -LL | let _unused = must_use_function(); - | ~~~~~~~ -help: consider explicitly droping with `std::mem::drop` - | -LL | let _ = drop(...); - | ~~~~~~~~~ - -warning: 2 warnings emitted - From 321a598b7519733aff7dea8b4ebd3631626d656b Mon Sep 17 00:00:00 2001 From: Aaron Kofsky Date: Sun, 5 Jun 2022 01:01:54 -0400 Subject: [PATCH 3179/5092] Add diagnostic items to MutexGuard and RwLock Guards I forgot to add the diagnostic to the actual types in `std` earlier. --- library/std/src/sync/mutex.rs | 1 + library/std/src/sync/rwlock.rs | 2 ++ src/test/ui/lint/let_underscore/let_underscore_lock.stderr | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs index 3d8281fe5938..d976725c2761 100644 --- a/library/std/src/sync/mutex.rs +++ b/library/std/src/sync/mutex.rs @@ -193,6 +193,7 @@ unsafe impl Sync for Mutex {} and cause Futures to not implement `Send`"] #[stable(feature = "rust1", since = "1.0.0")] #[clippy::has_significant_drop] +#[cfg_attr(not(test), rustc_diagnostic_item = "MutexGuard")] pub struct MutexGuard<'a, T: ?Sized + 'a> { lock: &'a Mutex, poison: poison::Guard, diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index 4f1b4bedaab2..e956f00a12fd 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -100,6 +100,7 @@ unsafe impl Sync for RwLock {} and cause Futures to not implement `Send`"] #[stable(feature = "rust1", since = "1.0.0")] #[clippy::has_significant_drop] +#[cfg_attr(not(test), rustc_diagnostic_item = "RwLockReadGuard")] pub struct RwLockReadGuard<'a, T: ?Sized + 'a> { lock: &'a RwLock, } @@ -124,6 +125,7 @@ unsafe impl Sync for RwLockReadGuard<'_, T> {} and cause Future's to not implement `Send`"] #[stable(feature = "rust1", since = "1.0.0")] #[clippy::has_significant_drop] +#[cfg_attr(not(test), rustc_diagnostic_item = "RwLockWriteGuard")] pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> { lock: &'a RwLock, poison: poison::Guard, diff --git a/src/test/ui/lint/let_underscore/let_underscore_lock.stderr b/src/test/ui/lint/let_underscore/let_underscore_lock.stderr index b7e14e8c7b5c..7ff42cb15244 100644 --- a/src/test/ui/lint/let_underscore/let_underscore_lock.stderr +++ b/src/test/ui/lint/let_underscore/let_underscore_lock.stderr @@ -1,5 +1,5 @@ error: non-binding let on a synchronization lock - --> $DIR/let_underscore_lock.rs:5:5 + --> $DIR/let_underscore_lock.rs:6:5 | LL | let _ = data.lock().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 4a852126b979d6a04f5ce2a0b132dcc88002cea1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Jun 2022 11:47:39 -0400 Subject: [PATCH 3180/5092] do not use int2ptr casts in strict provenance tests --- ...{strict-provenance-offset.rs => ptr_invalid_offset.rs} | 4 +++- ...provenance-offset.stderr => ptr_invalid_offset.stderr} | 4 ++-- tests/pass/slices.rs | 8 +++++--- 3 files changed, 10 insertions(+), 6 deletions(-) rename tests/fail/provenance/{strict-provenance-offset.rs => ptr_invalid_offset.rs} (59%) rename tests/fail/provenance/{strict-provenance-offset.stderr => ptr_invalid_offset.stderr} (89%) diff --git a/tests/fail/provenance/strict-provenance-offset.rs b/tests/fail/provenance/ptr_invalid_offset.rs similarity index 59% rename from tests/fail/provenance/strict-provenance-offset.rs rename to tests/fail/provenance/ptr_invalid_offset.rs index 6955d0243a9a..4447575405bb 100644 --- a/tests/fail/provenance/strict-provenance-offset.rs +++ b/tests/fail/provenance/ptr_invalid_offset.rs @@ -1,9 +1,11 @@ // compile-flags: -Zmiri-strict-provenance // error-pattern: not a valid pointer +#![feature(strict_provenance)] fn main() { let x = 22; let ptr = &x as *const _ as *const u8; - let roundtrip = ptr as usize as *const u8; + let roundtrip = std::ptr::invalid::(ptr as usize); + // Not even offsetting this is allowed. let _ = unsafe { roundtrip.offset(1) }; } diff --git a/tests/fail/provenance/strict-provenance-offset.stderr b/tests/fail/provenance/ptr_invalid_offset.stderr similarity index 89% rename from tests/fail/provenance/strict-provenance-offset.stderr rename to tests/fail/provenance/ptr_invalid_offset.stderr index 8e3daca939db..661fabf29afb 100644 --- a/tests/fail/provenance/strict-provenance-offset.stderr +++ b/tests/fail/provenance/ptr_invalid_offset.stderr @@ -8,8 +8,8 @@ LL | unsafe { intrinsics::offset(self, count) } = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC -note: inside `main` at $DIR/strict-provenance-offset.rs:LL:CC - --> $DIR/strict-provenance-offset.rs:LL:CC +note: inside `main` at $DIR/ptr_invalid_offset.rs:LL:CC + --> $DIR/ptr_invalid_offset.rs:LL:CC | LL | let _ = unsafe { roundtrip.offset(1) }; | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/pass/slices.rs b/tests/pass/slices.rs index b6537b4f1b4d..6cdfbb7841ae 100644 --- a/tests/pass/slices.rs +++ b/tests/pass/slices.rs @@ -3,8 +3,10 @@ #![feature(slice_as_chunks)] #![feature(slice_partition_dedup)] #![feature(layout_for_ptr)] +#![feature(strict_provenance)] use std::slice; +use std::ptr; fn slice_of_zst() { fn foo(v: &[T]) -> Option<&[T]> { @@ -25,7 +27,7 @@ fn slice_of_zst() { // In a slice of zero-size elements the pointer is meaningless. // Ensure iteration still works even if the pointer is at the end of the address space. - let slice: &[()] = unsafe { slice::from_raw_parts(-5isize as *const (), 10) }; + let slice: &[()] = unsafe { slice::from_raw_parts(ptr::invalid(-5isize as usize), 10) }; assert_eq!(slice.len(), 10); assert_eq!(slice.iter().count(), 10); @@ -38,7 +40,7 @@ fn slice_of_zst() { assert!(foo(slice).is_some()); // Test mutable iterators as well - let slice: &mut [()] = unsafe { slice::from_raw_parts_mut(-5isize as *mut (), 10) }; + let slice: &mut [()] = unsafe { slice::from_raw_parts_mut(ptr::invalid_mut(-5isize as usize), 10) }; assert_eq!(slice.len(), 10); assert_eq!(slice.iter_mut().count(), 10); @@ -254,7 +256,7 @@ fn test_for_invalidated_pointers() { fn large_raw_slice() { let size = isize::MAX as usize; // Creating a raw slice of size isize::MAX and asking for its size is okay. - let s = std::ptr::slice_from_raw_parts(1usize as *const u8, size); + let s = std::ptr::slice_from_raw_parts(ptr::invalid::(1), size); assert_eq!(size, unsafe { std::mem::size_of_val_raw(s) }); } From b2832008e236d20fdb1ba7d724d389295d1d2493 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Jun 2022 12:14:57 -0400 Subject: [PATCH 3181/5092] add interesting data race test --- tests/fail/data_race/fence_after_load.rs | 24 ++++++++++++++++++++ tests/fail/data_race/fence_after_load.stderr | 17 ++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 tests/fail/data_race/fence_after_load.rs create mode 100644 tests/fail/data_race/fence_after_load.stderr diff --git a/tests/fail/data_race/fence_after_load.rs b/tests/fail/data_race/fence_after_load.rs new file mode 100644 index 000000000000..b38171593386 --- /dev/null +++ b/tests/fail/data_race/fence_after_load.rs @@ -0,0 +1,24 @@ +// compile-flags: -Zmiri-disable-isolation +// ignore-windows: Concurrency on Windows is not supported yet. +use std::sync::Arc; +use std::sync::atomic::{AtomicUsize, Ordering, fence}; +use std::time::Duration; +use std::thread; + +fn main() { + static mut V: u32 = 0; + let a = Arc::new(AtomicUsize::default()); + let b = a.clone(); + thread::spawn(move || { + unsafe { V = 1 } + b.store(1, Ordering::SeqCst); + }); + thread::sleep(Duration::from_millis(100)); + fence(Ordering::SeqCst); + // Imagine the other thread's actions happening here. + assert_eq!(a.load(Ordering::Relaxed), 1); + // The fence is useless, since it did not happen-after the `store` in the other thread. + // Hence this is a data race. + // Also see https://github.com/rust-lang/miri/issues/2192. + unsafe { V = 2 } //~ERROR Data race detected +} diff --git a/tests/fail/data_race/fence_after_load.stderr b/tests/fail/data_race/fence_after_load.stderr new file mode 100644 index 000000000000..14452391327a --- /dev/null +++ b/tests/fail/data_race/fence_after_load.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/fence_after_load.rs:LL:CC + | +LL | unsafe { V = 2 } + | ^^^^^ Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/fence_after_load.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + From 211feb106a188fef698bb36d19402808f9930154 Mon Sep 17 00:00:00 2001 From: Aaron Kofsky Date: Sun, 5 Jun 2022 12:47:19 -0400 Subject: [PATCH 3182/5092] Add `{{produces}}` tag to lint doc comments. --- compiler/rustc_lint/src/let_underscore.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index dea878c4460b..520c865cc192 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -11,7 +11,7 @@ declare_lint! { /// scope. /// /// ### Example - /// ```rust + /// ``` /// struct SomeStruct; /// impl Drop for SomeStruct { /// fn drop(&mut self) { @@ -20,6 +20,7 @@ declare_lint! { /// } /// /// fn main() { + /// #[warn(let_underscore_drop)] /// // SomeStuct is dropped immediately instead of at end of scope, /// // so "Dropping SomeStruct" is printed before "end of main". /// // The order of prints would be reversed if SomeStruct was bound to @@ -28,6 +29,9 @@ declare_lint! { /// println!("end of main"); /// } /// ``` + /// + /// {{produces}} + /// /// ### Explanation /// /// Statements which assign an expression to an underscore causes the @@ -66,6 +70,9 @@ declare_lint! { /// *lock += 1; /// }); /// ``` + /// + /// {{produces}} + /// /// ### Explanation /// /// Statements which assign an expression to an underscore causes the From 47745380cd3928779361d34327b622e3813cda93 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Jun 2022 14:20:22 -0400 Subject: [PATCH 3183/5092] make Miri's scheduler proper round-robin --- src/thread.rs | 26 +++++++++++++++------- tests/pass/concurrency/spin_loops.rs | 33 ++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 tests/pass/concurrency/spin_loops.rs diff --git a/src/thread.rs b/src/thread.rs index 5673af048fc5..b6fb866f714a 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -518,16 +518,26 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { return Ok(SchedulingAction::ExecuteTimeoutCallback); } // No callbacks scheduled, pick a regular thread to execute. - // We need to pick a new thread for execution. - for (id, thread) in self.threads.iter_enumerated() { + // The active thread blocked or yielded. So we go search for another enabled thread. + // Curcially, we start searching at the current active thread ID, rather than at 0, since we + // want to avoid always scheduling threads 0 and 1 without ever making progress in thread 2. + // + // `skip(N)` means we start iterating at thread N, so we skip 1 more to start just *after* + // the active thread. Then after that we look at `take(N)`, i.e., the threads *before* the + // active thread. + let threads = self + .threads + .iter_enumerated() + .skip(self.active_thread.index() + 1) + .chain(self.threads.iter_enumerated().take(self.active_thread.index())); + for (id, thread) in threads { + debug_assert_ne!(self.active_thread, id); if thread.state == ThreadState::Enabled { - if !self.yield_active_thread || id != self.active_thread { - self.active_thread = id; - if let Some(data_race) = data_race { - data_race.thread_set_active(self.active_thread); - } - break; + self.active_thread = id; + if let Some(data_race) = data_race { + data_race.thread_set_active(self.active_thread); } + break; } } self.yield_active_thread = false; diff --git a/tests/pass/concurrency/spin_loops.rs b/tests/pass/concurrency/spin_loops.rs new file mode 100644 index 000000000000..4229e5440681 --- /dev/null +++ b/tests/pass/concurrency/spin_loops.rs @@ -0,0 +1,33 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +use std::thread; +use std::sync::atomic::{AtomicUsize, Ordering}; + +static FLAG: AtomicUsize = AtomicUsize::new(0); + +// When a thread yields, Miri's scheduler used to pick the thread with the lowest ID +// that can run. IDs are assigned in thread creation order. +// This means we could make 2 threads infinitely ping-pong with each other while +// really there is a 3rd thread that we should schedule to make progress. + +fn main() { + let waiter1 = thread::spawn(|| { + while FLAG.load(Ordering::Acquire) == 0 { + // spin and wait + thread::yield_now(); + } + }); + let waiter2 = thread::spawn(|| { + while FLAG.load(Ordering::Acquire) == 0 { + // spin and wait + thread::yield_now(); + } + }); + let progress = thread::spawn(|| { + FLAG.store(1, Ordering::Release); + }); + // The first `join` blocks the main thread and thus takes it out of the equation. + waiter1.join().unwrap(); + waiter2.join().unwrap(); + progress.join().unwrap(); +} From 34b359be1ec89383baff1dba5f74f5bfe8beedd7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Jun 2022 14:31:44 -0400 Subject: [PATCH 3184/5092] more spin-loop-tests --- tests/pass/concurrency/spin_loops.rs | 65 +++++++++++++++++++++--- tests/pass/concurrency/spin_loops.stderr | 2 + 2 files changed, 59 insertions(+), 8 deletions(-) create mode 100644 tests/pass/concurrency/spin_loops.stderr diff --git a/tests/pass/concurrency/spin_loops.rs b/tests/pass/concurrency/spin_loops.rs index 4229e5440681..a6fceb03638d 100644 --- a/tests/pass/concurrency/spin_loops.rs +++ b/tests/pass/concurrency/spin_loops.rs @@ -1,16 +1,17 @@ // ignore-windows: Concurrency on Windows is not supported yet. use std::thread; -use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; +use std::sync::mpsc; +use std::cell::Cell; -static FLAG: AtomicUsize = AtomicUsize::new(0); +/// When a thread yields, Miri's scheduler used to pick the thread with the lowest ID +/// that can run. IDs are assigned in thread creation order. +/// This means we could make 2 threads infinitely ping-pong with each other while +/// really there is a 3rd thread that we should schedule to make progress. +fn two_player_ping_pong() { + static FLAG: AtomicUsize = AtomicUsize::new(0); -// When a thread yields, Miri's scheduler used to pick the thread with the lowest ID -// that can run. IDs are assigned in thread creation order. -// This means we could make 2 threads infinitely ping-pong with each other while -// really there is a 3rd thread that we should schedule to make progress. - -fn main() { let waiter1 = thread::spawn(|| { while FLAG.load(Ordering::Acquire) == 0 { // spin and wait @@ -31,3 +32,51 @@ fn main() { waiter2.join().unwrap(); progress.join().unwrap(); } + +/// Based on a test by @jethrogb. +fn launcher() { + static THREAD2_LAUNCHED: AtomicBool = AtomicBool::new(false); + + for _ in 0..10 { + let (tx, rx) = mpsc::sync_channel(0); + THREAD2_LAUNCHED.store(false, Ordering::SeqCst); + + let jh = thread::spawn(move || { + struct RecvOnDrop(Cell>>); + + impl Drop for RecvOnDrop { + fn drop(&mut self) { + let rx = self.0.take().unwrap(); + while !THREAD2_LAUNCHED.load(Ordering::SeqCst) { + thread::yield_now(); + } + rx.recv().unwrap(); + } + } + + let tl_rx: RecvOnDrop = RecvOnDrop(Cell::new(None)); + tl_rx.0.set(Some(rx)); + }); + + let tx_clone = tx.clone(); + let jh2 = thread::spawn(move || { + THREAD2_LAUNCHED.store(true, Ordering::SeqCst); + jh.join().unwrap(); + tx_clone.send(()).expect_err( + "Expecting channel to be closed because thread 1 TLS destructors must've run", + ); + }); + + while !THREAD2_LAUNCHED.load(Ordering::SeqCst) { + thread::yield_now(); + } + thread::yield_now(); + tx.send(()).expect("Expecting channel to be live because thread 2 must block on join"); + jh2.join().unwrap(); + } +} + +fn main() { + two_player_ping_pong(); + launcher(); +} diff --git a/tests/pass/concurrency/spin_loops.stderr b/tests/pass/concurrency/spin_loops.stderr new file mode 100644 index 000000000000..03676519d4f1 --- /dev/null +++ b/tests/pass/concurrency/spin_loops.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + From d0a0369a24003da3800957f9bab01f631f76a792 Mon Sep 17 00:00:00 2001 From: infrandomness Date: Sun, 5 Jun 2022 22:29:30 +0200 Subject: [PATCH 3185/5092] Refactor POSIX to UNIX This renames the directory containing posix to unix; where applicable, it also rename functions with the word "posix" to "unix" --- src/machine.rs | 6 +++--- src/shims/dlsym.rs | 8 ++++---- src/shims/foreign_items.rs | 2 +- src/shims/mod.rs | 2 +- src/shims/{posix => unix}/dlsym.rs | 4 ++-- src/shims/{posix => unix}/foreign_items.rs | 10 +++++----- src/shims/{posix => unix}/fs.rs | 0 src/shims/{posix => unix}/linux/dlsym.rs | 0 src/shims/{posix => unix}/linux/foreign_items.rs | 8 ++++---- src/shims/{posix => unix}/linux/mod.rs | 0 src/shims/{posix => unix}/linux/sync.rs | 0 src/shims/{posix => unix}/macos/dlsym.rs | 0 src/shims/{posix => unix}/macos/foreign_items.rs | 4 ++-- src/shims/{posix => unix}/macos/mod.rs | 0 src/shims/{posix => unix}/mod.rs | 0 src/shims/{posix => unix}/sync.rs | 0 src/shims/{posix => unix}/thread.rs | 0 17 files changed, 22 insertions(+), 22 deletions(-) rename src/shims/{posix => unix}/dlsym.rs (94%) rename src/shims/{posix => unix}/foreign_items.rs (98%) rename src/shims/{posix => unix}/fs.rs (100%) rename src/shims/{posix => unix}/linux/dlsym.rs (100%) rename src/shims/{posix => unix}/linux/foreign_items.rs (98%) rename src/shims/{posix => unix}/linux/mod.rs (100%) rename src/shims/{posix => unix}/linux/sync.rs (100%) rename src/shims/{posix => unix}/macos/dlsym.rs (100%) rename src/shims/{posix => unix}/macos/foreign_items.rs (98%) rename src/shims/{posix => unix}/macos/mod.rs (100%) rename src/shims/{posix => unix}/mod.rs (100%) rename src/shims/{posix => unix}/sync.rs (100%) rename src/shims/{posix => unix}/thread.rs (100%) diff --git a/src/machine.rs b/src/machine.rs index 6a7cbe58711a..369bb92c6f39 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -28,7 +28,7 @@ use rustc_span::Symbol; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; -use crate::{shims::posix::FileHandler, *}; +use crate::{shims::unix::FileHandler, *}; // Some global facts about the emulated machine. pub const PAGE_SIZE: u64 = 4 * 1024; // FIXME: adjust to target architecture @@ -266,9 +266,9 @@ pub struct Evaluator<'mir, 'tcx> { pub(crate) enforce_abi: bool, /// The table of file descriptors. - pub(crate) file_handler: shims::posix::FileHandler, + pub(crate) file_handler: shims::unix::FileHandler, /// The table of directory descriptors. - pub(crate) dir_handler: shims::posix::DirHandler, + pub(crate) dir_handler: shims::unix::DirHandler, /// The "time anchor" for this machine's monotone clock (for `Instant` simulation). pub(crate) time_anchor: Instant, diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 05296d3a4eb7..c5081582281b 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -2,13 +2,13 @@ use rustc_middle::mir; use rustc_target::spec::abi::Abi; use crate::*; -use shims::posix::dlsym as posix; +use shims::unix::dlsym as unix; use shims::windows::dlsym as windows; #[derive(Debug, Copy, Clone)] #[allow(non_camel_case_types)] pub enum Dlsym { - Posix(posix::Dlsym), + Posix(unix::Dlsym), Windows(windows::Dlsym), } @@ -18,7 +18,7 @@ impl Dlsym { pub fn from_str<'tcx>(name: &[u8], target_os: &str) -> InterpResult<'tcx, Option> { let name = &*String::from_utf8_lossy(name); Ok(match target_os { - "linux" | "macos" => posix::Dlsym::from_str(name, target_os)?.map(Dlsym::Posix), + "linux" | "macos" => unix::Dlsym::from_str(name, target_os)?.map(Dlsym::Posix), "windows" => windows::Dlsym::from_str(name)?.map(Dlsym::Windows), os => bug!("dlsym not implemented for target_os {}", os), }) @@ -38,7 +38,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); match dlsym { Dlsym::Posix(dlsym) => - posix::EvalContextExt::call_dlsym(this, dlsym, abi, args, dest, ret), + unix::EvalContextExt::call_dlsym(this, dlsym, abi, args, dest, ret), Dlsym::Windows(dlsym) => windows::EvalContextExt::call_dlsym(this, dlsym, abi, args, dest, ret), } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index e978391801f1..12b5b40e69e8 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -702,7 +702,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Platform-specific shims _ => match this.tcx.sess.target.os.as_ref() { - "linux" | "macos" => return shims::posix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), + "linux" | "macos" => return shims::unix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), target => throw_unsup_format!("the target `{}` is not supported", target), } diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 926fcd5d040b..cdffe2f65b4f 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -1,7 +1,7 @@ mod backtrace; pub mod foreign_items; pub mod intrinsics; -pub mod posix; +pub mod unix; pub mod windows; pub mod dlsym; diff --git a/src/shims/posix/dlsym.rs b/src/shims/unix/dlsym.rs similarity index 94% rename from src/shims/posix/dlsym.rs rename to src/shims/unix/dlsym.rs index 339110467c73..578ae488a98e 100644 --- a/src/shims/posix/dlsym.rs +++ b/src/shims/unix/dlsym.rs @@ -2,8 +2,8 @@ use rustc_middle::mir; use rustc_target::spec::abi::Abi; use crate::*; -use shims::posix::linux::dlsym as linux; -use shims::posix::macos::dlsym as macos; +use shims::unix::linux::dlsym as linux; +use shims::unix::macos::dlsym as macos; #[derive(Debug, Copy, Clone)] pub enum Dlsym { diff --git a/src/shims/posix/foreign_items.rs b/src/shims/unix/foreign_items.rs similarity index 98% rename from src/shims/posix/foreign_items.rs rename to src/shims/unix/foreign_items.rs index 566befb0efd0..32cf7e6f891f 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -10,9 +10,9 @@ use rustc_target::spec::abi::Abi; use crate::*; use shims::foreign_items::EmulateByNameResult; -use shims::posix::fs::EvalContextExt as _; -use shims::posix::sync::EvalContextExt as _; -use shims::posix::thread::EvalContextExt as _; +use shims::unix::fs::EvalContextExt as _; +use shims::unix::sync::EvalContextExt as _; +use shims::unix::thread::EvalContextExt as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -477,8 +477,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Platform-specific shims _ => { match this.tcx.sess.target.os.as_ref() { - "linux" => return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), - "macos" => return shims::posix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), + "linux" => return shims::unix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), + "macos" => return shims::unix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), _ => unreachable!(), } } diff --git a/src/shims/posix/fs.rs b/src/shims/unix/fs.rs similarity index 100% rename from src/shims/posix/fs.rs rename to src/shims/unix/fs.rs diff --git a/src/shims/posix/linux/dlsym.rs b/src/shims/unix/linux/dlsym.rs similarity index 100% rename from src/shims/posix/linux/dlsym.rs rename to src/shims/unix/linux/dlsym.rs diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs similarity index 98% rename from src/shims/posix/linux/foreign_items.rs rename to src/shims/unix/linux/foreign_items.rs index f966c63b7239..7a9c687fcd76 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -4,10 +4,10 @@ use rustc_target::spec::abi::Abi; use crate::*; use shims::foreign_items::EmulateByNameResult; -use shims::posix::fs::EvalContextExt as _; -use shims::posix::linux::sync::futex; -use shims::posix::sync::EvalContextExt as _; -use shims::posix::thread::EvalContextExt as _; +use shims::unix::fs::EvalContextExt as _; +use shims::unix::linux::sync::futex; +use shims::unix::sync::EvalContextExt as _; +use shims::unix::thread::EvalContextExt as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { diff --git a/src/shims/posix/linux/mod.rs b/src/shims/unix/linux/mod.rs similarity index 100% rename from src/shims/posix/linux/mod.rs rename to src/shims/unix/linux/mod.rs diff --git a/src/shims/posix/linux/sync.rs b/src/shims/unix/linux/sync.rs similarity index 100% rename from src/shims/posix/linux/sync.rs rename to src/shims/unix/linux/sync.rs diff --git a/src/shims/posix/macos/dlsym.rs b/src/shims/unix/macos/dlsym.rs similarity index 100% rename from src/shims/posix/macos/dlsym.rs rename to src/shims/unix/macos/dlsym.rs diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/unix/macos/foreign_items.rs similarity index 98% rename from src/shims/posix/macos/foreign_items.rs rename to src/shims/unix/macos/foreign_items.rs index 7f6393fd30f1..a1adfa0d2fda 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/unix/macos/foreign_items.rs @@ -4,8 +4,8 @@ use rustc_target::spec::abi::Abi; use crate::*; use shims::foreign_items::EmulateByNameResult; -use shims::posix::fs::EvalContextExt as _; -use shims::posix::thread::EvalContextExt as _; +use shims::unix::fs::EvalContextExt as _; +use shims::unix::thread::EvalContextExt as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { diff --git a/src/shims/posix/macos/mod.rs b/src/shims/unix/macos/mod.rs similarity index 100% rename from src/shims/posix/macos/mod.rs rename to src/shims/unix/macos/mod.rs diff --git a/src/shims/posix/mod.rs b/src/shims/unix/mod.rs similarity index 100% rename from src/shims/posix/mod.rs rename to src/shims/unix/mod.rs diff --git a/src/shims/posix/sync.rs b/src/shims/unix/sync.rs similarity index 100% rename from src/shims/posix/sync.rs rename to src/shims/unix/sync.rs diff --git a/src/shims/posix/thread.rs b/src/shims/unix/thread.rs similarity index 100% rename from src/shims/posix/thread.rs rename to src/shims/unix/thread.rs From f31a8e09510380dc3b0f6a36d59b3d4c5b5a3de7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 11:07:25 -0400 Subject: [PATCH 3186/5092] argument parsing: make better use of strip_prefix --- src/bin/miri.rs | 336 ++++++++++++++++++++---------------------------- 1 file changed, 141 insertions(+), 195 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 2cf5bc644dbf..e3f38956dae2 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -310,208 +310,154 @@ fn main() { } else if after_dashdash { // Everything that comes after `--` is forwarded to the interpreted crate. miri_config.args.push(arg); - } else { - match arg.as_str() { - "-Zmiri-disable-validation" => { - miri_config.validate = false; - } - "-Zmiri-disable-stacked-borrows" => { - miri_config.stacked_borrows = false; - } - "-Zmiri-disable-data-race-detector" => { - miri_config.data_race_detector = false; - } - "-Zmiri-disable-alignment-check" => { - miri_config.check_alignment = miri::AlignmentCheck::None; - } - "-Zmiri-symbolic-alignment-check" => { - miri_config.check_alignment = miri::AlignmentCheck::Symbolic; - } - "-Zmiri-check-number-validity" => { - eprintln!( - "WARNING: the flag `-Zmiri-check-number-validity` no longer has any effect \ + } else if arg == "--" { + after_dashdash = true; + } else if arg == "-Zmiri-disable-validation" { + miri_config.validate = false; + } else if arg == "-Zmiri-disable-stacked-borrows" { + miri_config.stacked_borrows = false; + } else if arg == "-Zmiri-disable-data-race-detector" { + miri_config.data_race_detector = false; + } else if arg == "-Zmiri-disable-alignment-check" { + miri_config.check_alignment = miri::AlignmentCheck::None; + } else if arg == "-Zmiri-symbolic-alignment-check" { + miri_config.check_alignment = miri::AlignmentCheck::Symbolic; + } else if arg == "-Zmiri-check-number-validity" { + eprintln!( + "WARNING: the flag `-Zmiri-check-number-validity` no longer has any effect \ since it is now enabled by default" - ); - } - "-Zmiri-allow-uninit-numbers" => { - miri_config.allow_uninit_numbers = true; - } - "-Zmiri-allow-ptr-int-transmute" => { - miri_config.allow_ptr_int_transmute = true; - } - "-Zmiri-disable-abi-check" => { - miri_config.check_abi = false; - } - "-Zmiri-disable-isolation" => { - if matches!(isolation_enabled, Some(true)) { - panic!( - "-Zmiri-disable-isolation cannot be used along with -Zmiri-isolation-error" - ); - } else { - isolation_enabled = Some(false); - } - miri_config.isolated_op = miri::IsolatedOp::Allow; - } - arg if arg.starts_with("-Zmiri-isolation-error=") => { - if matches!(isolation_enabled, Some(false)) { - panic!( - "-Zmiri-isolation-error cannot be used along with -Zmiri-disable-isolation" - ); - } else { - isolation_enabled = Some(true); - } + ); + } else if arg == "-Zmiri-allow-uninit-numbers" { + miri_config.allow_uninit_numbers = true; + } else if arg == "-Zmiri-allow-ptr-int-transmute" { + miri_config.allow_ptr_int_transmute = true; + } else if arg == "-Zmiri-disable-abi-check" { + miri_config.check_abi = false; + } else if arg == "-Zmiri-disable-isolation" { + if matches!(isolation_enabled, Some(true)) { + panic!("-Zmiri-disable-isolation cannot be used along with -Zmiri-isolation-error"); + } else { + isolation_enabled = Some(false); + } + miri_config.isolated_op = miri::IsolatedOp::Allow; + } else if let Some(param) = arg.strip_prefix("-Zmiri-isolation-error=") { + if matches!(isolation_enabled, Some(false)) { + panic!("-Zmiri-isolation-error cannot be used along with -Zmiri-disable-isolation"); + } else { + isolation_enabled = Some(true); + } - miri_config.isolated_op = match arg - .strip_prefix("-Zmiri-isolation-error=") - .unwrap() - { - "abort" => miri::IsolatedOp::Reject(miri::RejectOpWith::Abort), - "hide" => miri::IsolatedOp::Reject(miri::RejectOpWith::NoWarning), - "warn" => miri::IsolatedOp::Reject(miri::RejectOpWith::Warning), - "warn-nobacktrace" => - miri::IsolatedOp::Reject(miri::RejectOpWith::WarningWithoutBacktrace), - _ => - panic!( - "-Zmiri-isolation-error must be `abort`, `hide`, `warn`, or `warn-nobacktrace`" - ), - }; - } - "-Zmiri-ignore-leaks" => { - miri_config.ignore_leaks = true; - } - "-Zmiri-panic-on-unsupported" => { - miri_config.panic_on_unsupported = true; - } - "-Zmiri-tag-raw-pointers" => { - miri_config.tag_raw = true; - } - "-Zmiri-strict-provenance" => { - miri_config.provenance_mode = ProvenanceMode::Strict; - miri_config.tag_raw = true; - } - "-Zmiri-permissive-provenance" => { - miri_config.provenance_mode = ProvenanceMode::Permissive; - miri_config.tag_raw = true; - } - "-Zmiri-mute-stdout-stderr" => { - miri_config.mute_stdout_stderr = true; - } - "-Zmiri-track-raw-pointers" => { - eprintln!( - "WARNING: -Zmiri-track-raw-pointers has been renamed to -Zmiri-tag-raw-pointers, the old name is deprecated." - ); - miri_config.tag_raw = true; - } - "--" => { - after_dashdash = true; - } - arg if arg.starts_with("-Zmiri-seed=") => { - if miri_config.seed.is_some() { - panic!("Cannot specify -Zmiri-seed multiple times!"); - } - let seed = u64::from_str_radix(arg.strip_prefix("-Zmiri-seed=").unwrap(), 16) + miri_config.isolated_op = match param { + "abort" => miri::IsolatedOp::Reject(miri::RejectOpWith::Abort), + "hide" => miri::IsolatedOp::Reject(miri::RejectOpWith::NoWarning), + "warn" => miri::IsolatedOp::Reject(miri::RejectOpWith::Warning), + "warn-nobacktrace" => + miri::IsolatedOp::Reject(miri::RejectOpWith::WarningWithoutBacktrace), + _ => + panic!( + "-Zmiri-isolation-error must be `abort`, `hide`, `warn`, or `warn-nobacktrace`" + ), + }; + } else if arg == "-Zmiri-ignore-leaks" { + miri_config.ignore_leaks = true; + } else if arg == "-Zmiri-panic-on-unsupported" { + miri_config.panic_on_unsupported = true; + } else if arg == "-Zmiri-tag-raw-pointers" { + miri_config.tag_raw = true; + } else if arg == "-Zmiri-strict-provenance" { + miri_config.provenance_mode = ProvenanceMode::Strict; + miri_config.tag_raw = true; + } else if arg == "-Zmiri-permissive-provenance" { + miri_config.provenance_mode = ProvenanceMode::Permissive; + miri_config.tag_raw = true; + } else if arg == "-Zmiri-mute-stdout-stderr" { + miri_config.mute_stdout_stderr = true; + } else if arg == "-Zmiri-track-raw-pointers" { + eprintln!( + "WARNING: -Zmiri-track-raw-pointers has been renamed to -Zmiri-tag-raw-pointers, the old name is deprecated." + ); + miri_config.tag_raw = true; + } else if let Some(param) = arg.strip_prefix("-Zmiri-seed=") { + if miri_config.seed.is_some() { + panic!("Cannot specify -Zmiri-seed multiple times!"); + } + let seed = u64::from_str_radix(param, 16) .unwrap_or_else(|_| panic!( "-Zmiri-seed should only contain valid hex digits [0-9a-fA-F] and fit into a u64 (max 16 characters)" )); - miri_config.seed = Some(seed); - } - arg if arg.starts_with("-Zmiri-env-exclude=") => { - miri_config - .excluded_env_vars - .push(arg.strip_prefix("-Zmiri-env-exclude=").unwrap().to_owned()); - } - arg if arg.starts_with("-Zmiri-env-forward=") => { - miri_config - .forwarded_env_vars - .push(arg.strip_prefix("-Zmiri-env-forward=").unwrap().to_owned()); - } - arg if arg.starts_with("-Zmiri-track-pointer-tag=") => { - let ids: Vec = match parse_comma_list( - arg.strip_prefix("-Zmiri-track-pointer-tag=").unwrap(), - ) { - Ok(ids) => ids, - Err(err) => - panic!( - "-Zmiri-track-pointer-tag requires a comma separated list of valid `u64` arguments: {}", - err - ), - }; - for id in ids.into_iter().map(miri::PtrId::new) { - if let Some(id) = id { - miri_config.tracked_pointer_tags.insert(id); - } else { - panic!("-Zmiri-track-pointer-tag requires nonzero arguments"); - } - } - } - arg if arg.starts_with("-Zmiri-track-call-id=") => { - let ids: Vec = match parse_comma_list( - arg.strip_prefix("-Zmiri-track-call-id=").unwrap(), - ) { - Ok(ids) => ids, - Err(err) => - panic!( - "-Zmiri-track-call-id requires a comma separated list of valid `u64` arguments: {}", - err - ), - }; - for id in ids.into_iter().map(miri::CallId::new) { - if let Some(id) = id { - miri_config.tracked_call_ids.insert(id); - } else { - panic!("-Zmiri-track-call-id requires a nonzero argument"); - } - } - } - arg if arg.starts_with("-Zmiri-track-alloc-id=") => { - let ids: Vec = match parse_comma_list::( - arg.strip_prefix("-Zmiri-track-alloc-id=").unwrap(), - ) { - Ok(ids) => ids.into_iter().map(miri::AllocId).collect(), - Err(err) => - panic!( - "-Zmiri-track-alloc-id requires a comma separated list of valid non-zero `u64` arguments: {}", - err - ), - }; - miri_config.tracked_alloc_ids.extend(ids); - } - arg if arg.starts_with("-Zmiri-compare-exchange-weak-failure-rate=") => { - let rate = match arg - .strip_prefix("-Zmiri-compare-exchange-weak-failure-rate=") - .unwrap() - .parse::() - { - Ok(rate) if rate >= 0.0 && rate <= 1.0 => rate, - Ok(_) => - panic!( - "-Zmiri-compare-exchange-weak-failure-rate must be between `0.0` and `1.0`" - ), - Err(err) => - panic!( - "-Zmiri-compare-exchange-weak-failure-rate requires a `f64` between `0.0` and `1.0`: {}", - err - ), - }; - miri_config.cmpxchg_weak_failure_rate = rate; - } - arg if arg.starts_with("-Zmiri-measureme=") => { - let measureme_out = arg.strip_prefix("-Zmiri-measureme=").unwrap(); - miri_config.measureme_out = Some(measureme_out.to_string()); - } - arg if arg.starts_with("-Zmiri-backtrace=") => { - miri_config.backtrace_style = match arg.strip_prefix("-Zmiri-backtrace=") { - Some("0") => BacktraceStyle::Off, - Some("1") => BacktraceStyle::Short, - Some("full") => BacktraceStyle::Full, - _ => panic!("-Zmiri-backtrace may only be 0, 1, or full"), - }; - } - _ => { - // Forward to rustc. - rustc_args.push(arg); + miri_config.seed = Some(seed); + } else if let Some(param) = arg.strip_prefix("-Zmiri-env-exclude=") { + miri_config.excluded_env_vars.push(param.to_owned()); + } else if let Some(param) = arg.strip_prefix("-Zmiri-env-forward=") { + miri_config.forwarded_env_vars.push(param.to_owned()); + } else if let Some(param) = arg.strip_prefix("-Zmiri-track-pointer-tag=") { + let ids: Vec = match parse_comma_list(param) { + Ok(ids) => ids, + Err(err) => + panic!( + "-Zmiri-track-pointer-tag requires a comma separated list of valid `u64` arguments: {}", + err + ), + }; + for id in ids.into_iter().map(miri::PtrId::new) { + if let Some(id) = id { + miri_config.tracked_pointer_tags.insert(id); + } else { + panic!("-Zmiri-track-pointer-tag requires nonzero arguments"); } } + } else if let Some(param) = arg.strip_prefix("-Zmiri-track-call-id=") { + let ids: Vec = match parse_comma_list(param) { + Ok(ids) => ids, + Err(err) => + panic!( + "-Zmiri-track-call-id requires a comma separated list of valid `u64` arguments: {}", + err + ), + }; + for id in ids.into_iter().map(miri::CallId::new) { + if let Some(id) = id { + miri_config.tracked_call_ids.insert(id); + } else { + panic!("-Zmiri-track-call-id requires a nonzero argument"); + } + } + } else if let Some(param) = arg.strip_prefix("-Zmiri-track-alloc-id=") { + let ids: Vec = match parse_comma_list::(param) { + Ok(ids) => ids.into_iter().map(miri::AllocId).collect(), + Err(err) => + panic!( + "-Zmiri-track-alloc-id requires a comma separated list of valid non-zero `u64` arguments: {}", + err + ), + }; + miri_config.tracked_alloc_ids.extend(ids); + } else if let Some(param) = arg.strip_prefix("-Zmiri-compare-exchange-weak-failure-rate=") { + let rate = match param.parse::() { + Ok(rate) if rate >= 0.0 && rate <= 1.0 => rate, + Ok(_) => + panic!( + "-Zmiri-compare-exchange-weak-failure-rate must be between `0.0` and `1.0`" + ), + Err(err) => + panic!( + "-Zmiri-compare-exchange-weak-failure-rate requires a `f64` between `0.0` and `1.0`: {}", + err + ), + }; + miri_config.cmpxchg_weak_failure_rate = rate; + } else if let Some(param) = arg.strip_prefix("-Zmiri-measureme=") { + miri_config.measureme_out = Some(param.to_string()); + } else if let Some(param) = arg.strip_prefix("-Zmiri-backtrace=") { + miri_config.backtrace_style = match param { + "0" => BacktraceStyle::Off, + "1" => BacktraceStyle::Short, + "full" => BacktraceStyle::Full, + _ => panic!("-Zmiri-backtrace may only be 0, 1, or full"), + }; + } else { + // Forward to rustc. + rustc_args.push(arg); } } From 63625b03974bdb41f7629045ebfa239328fdcf02 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 3 Jun 2022 08:46:22 -0400 Subject: [PATCH 3187/5092] adjust for better provenance control --- src/diagnostics.rs | 14 +++++++--- src/helpers.rs | 4 +-- tests/fail/branchless-select-i128-pointer.rs | 6 ++--- .../branchless-select-i128-pointer.stderr | 8 +++--- tests/fail/pointer_partial_overwrite.rs | 2 +- tests/fail/pointer_partial_read.rs | 9 ------- tests/fail/pointer_partial_read.stderr | 14 ---------- .../permissive_provenance_transmute.rs | 27 +++++++++++++++++++ .../permissive_provenance_transmute.stderr | 20 ++++++++++++++ .../provenance/strict_provenance_transmute.rs | 4 +-- .../strict_provenance_transmute.stderr | 6 ++--- tests/fail/transmute_fat1.rs | 5 ++-- tests/fail/transmute_fat1.stderr | 9 ++++--- tests/fail/validity/ptr_integer_transmute.rs | 4 --- .../validity/ptr_integer_transmute.stderr | 15 ----------- ..._provenance.rs => ptr_int_from_exposed.rs} | 0 tests/pass/ptr_int_transmute.rs | 22 +++++++++++++++ 17 files changed, 103 insertions(+), 66 deletions(-) delete mode 100644 tests/fail/pointer_partial_read.rs delete mode 100644 tests/fail/pointer_partial_read.stderr create mode 100644 tests/fail/provenance/permissive_provenance_transmute.rs create mode 100644 tests/fail/provenance/permissive_provenance_transmute.stderr delete mode 100644 tests/fail/validity/ptr_integer_transmute.rs delete mode 100644 tests/fail/validity/ptr_integer_transmute.stderr rename tests/pass/{ptr_int_permissive_provenance.rs => ptr_int_from_exposed.rs} (100%) create mode 100644 tests/pass/ptr_int_transmute.rs diff --git a/src/diagnostics.rs b/src/diagnostics.rs index ace521f1bed0..52f93a6cea9d 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -229,9 +229,16 @@ pub fn report_error<'tcx, 'mir>( }; #[rustfmt::skip] let helps = match e.kind() { - Unsupported(UnsupportedOpInfo::ThreadLocalStatic(_) | UnsupportedOpInfo::ReadExternStatic(_)) => + Unsupported( + UnsupportedOpInfo::ThreadLocalStatic(_) | + UnsupportedOpInfo::ReadExternStatic(_) + ) => panic!("Error should never be raised by Miri: {:?}", e.kind()), - Unsupported(_) => + Unsupported( + UnsupportedOpInfo::Unsupported(_) | + UnsupportedOpInfo::PartialPointerOverwrite(_) | + UnsupportedOpInfo::ReadPointerAsBytes + ) => vec![(None, format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"))], UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. }) if ecx.machine.check_alignment == AlignmentCheck::Symbolic @@ -245,7 +252,8 @@ pub fn report_error<'tcx, 'mir>( (None, format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior")), (None, format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information")), ], - _ => vec![], + InvalidProgram(_) | ResourceExhaustion(_) | MachineStop(_) => + vec![], }; (Some(title), helps) } diff --git a/src/helpers.rs b/src/helpers.rs index cb4c3c293e93..4c79633c72de 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -681,7 +681,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: We are re-getting the allocation each time around the loop. // Would be nice if we could somehow "extend" an existing AllocRange. let alloc = this.get_ptr_alloc(ptr.offset(len, this)?, size1, Align::ONE)?.unwrap(); // not a ZST, so we will get a result - let byte = alloc.read_scalar(alloc_range(Size::ZERO, size1))?.to_u8()?; + let byte = alloc.read_integer(Size::ZERO, size1)?.to_u8()?; if byte == 0 { break; } else { @@ -703,7 +703,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: We are re-getting the allocation each time around the loop. // Would be nice if we could somehow "extend" an existing AllocRange. let alloc = this.get_ptr_alloc(ptr, size2, align2)?.unwrap(); // not a ZST, so we will get a result - let wchar = alloc.read_scalar(alloc_range(Size::ZERO, size2))?.to_u16()?; + let wchar = alloc.read_integer(Size::ZERO, size2)?.to_u16()?; if wchar == 0 { break; } else { diff --git a/tests/fail/branchless-select-i128-pointer.rs b/tests/fail/branchless-select-i128-pointer.rs index 61fd57f8f050..20fbcd1de78a 100644 --- a/tests/fail/branchless-select-i128-pointer.rs +++ b/tests/fail/branchless-select-i128-pointer.rs @@ -9,10 +9,10 @@ fn main() { for &my_bool in &[true, false] { let mask = -(my_bool as TwoPtrs); // false -> 0, true -> -1 aka !0 // This is branchless code to select one or the other pointer. - // For now, Miri brafs on it, but if this code ever passes we better make sure it behaves correctly. + // However, it drops provenance when transmuting to TwoPtrs, so this is UB. let val = unsafe { - transmute::<_, &str>( - !mask & transmute::<_, TwoPtrs>("false !") | mask & transmute::<_, TwoPtrs>("true !"), //~ERROR encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes + transmute::<_, &str>( //~ERROR type validation failed: encountered a dangling reference + !mask & transmute::<_, TwoPtrs>("false !") | mask & transmute::<_, TwoPtrs>("true !"), ) }; println!("{}", val); diff --git a/tests/fail/branchless-select-i128-pointer.stderr b/tests/fail/branchless-select-i128-pointer.stderr index 2e0f81398303..f37dcf955e33 100644 --- a/tests/fail/branchless-select-i128-pointer.stderr +++ b/tests/fail/branchless-select-i128-pointer.stderr @@ -1,8 +1,10 @@ -error: Undefined Behavior: type validation failed: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes +error: Undefined Behavior: type validation failed: encountered a dangling reference (address $HEX is unallocated) --> $DIR/branchless-select-i128-pointer.rs:LL:CC | -LL | !mask & transmute::<_, TwoPtrs>("false !") | mask & transmute::<_, TwoPtrs>("true !"), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes +LL | / transmute::<_, &str>( +LL | | !mask & transmute::<_, TwoPtrs>("false !") | mask & transmute::<_, TwoPtrs>("true !"), +LL | | ) + | |_____________^ type validation failed: encountered a dangling reference (address $HEX is unallocated) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/pointer_partial_overwrite.rs b/tests/fail/pointer_partial_overwrite.rs index 8bee58d20a59..1bbb33aa2bbd 100644 --- a/tests/fail/pointer_partial_overwrite.rs +++ b/tests/fail/pointer_partial_overwrite.rs @@ -2,7 +2,7 @@ // compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation // Test what happens when we overwrite parts of a pointer. -// Also see . +// Also see . fn main() { let mut p = &42; diff --git a/tests/fail/pointer_partial_read.rs b/tests/fail/pointer_partial_read.rs deleted file mode 100644 index a4a5071f5da0..000000000000 --- a/tests/fail/pointer_partial_read.rs +++ /dev/null @@ -1,9 +0,0 @@ -// Test what happens when we read parts of a pointer. -// Related to . -fn main() { - let x = 13; - let y = &x; - let z = &y as *const &i32 as *const u8; - // the deref fails, because we are reading only a part of the pointer - let _val = unsafe { *z }; //~ ERROR unable to turn pointer into raw bytes -} diff --git a/tests/fail/pointer_partial_read.stderr b/tests/fail/pointer_partial_read.stderr deleted file mode 100644 index dc35f7e109a5..000000000000 --- a/tests/fail/pointer_partial_read.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: unsupported operation: unable to turn pointer into raw bytes - --> $DIR/pointer_partial_read.rs:LL:CC - | -LL | let _val = unsafe { *z }; - | ^^ unable to turn pointer into raw bytes - | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - - = note: inside `main` at $DIR/pointer_partial_read.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/provenance/permissive_provenance_transmute.rs b/tests/fail/provenance/permissive_provenance_transmute.rs new file mode 100644 index 000000000000..dbfc5732ed3b --- /dev/null +++ b/tests/fail/provenance/permissive_provenance_transmute.rs @@ -0,0 +1,27 @@ +// compile-flags: -Zmiri-permissive-provenance -Zmiri-disable-stacked-borrows +#![feature(strict_provenance)] + +use std::mem; + +// This is the example from +// . + +unsafe fn deref(left: *const u8, right: *const u8) { + let left_int: usize = mem::transmute(left); + let right_int: usize = mem::transmute(right); + if left_int == right_int { + // The compiler is allowed to replace `left_int` by `right_int` here... + let left_ptr: *const u8 = mem::transmute(left_int); + // ...which however means here it could be dereferencing the wrong pointer. + let _val = *left_ptr; //~ERROR dereferencing pointer failed + } +} + +fn main() { + let ptr1 = &0u8 as *const u8; + let ptr2 = &1u8 as *const u8; + unsafe { + // Two pointers with the same address but different provenance. + deref(ptr1, ptr2.with_addr(ptr1.addr())); + } +} diff --git a/tests/fail/provenance/permissive_provenance_transmute.stderr b/tests/fail/provenance/permissive_provenance_transmute.stderr new file mode 100644 index 000000000000..12f3562011a8 --- /dev/null +++ b/tests/fail/provenance/permissive_provenance_transmute.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: dereferencing pointer failed: $HEX is not a valid pointer + --> $DIR/permissive_provenance_transmute.rs:LL:CC + | +LL | let _val = *left_ptr; + | ^^^^^^^^^ dereferencing pointer failed: $HEX is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `deref` at $DIR/permissive_provenance_transmute.rs:LL:CC +note: inside `main` at $DIR/permissive_provenance_transmute.rs:LL:CC + --> $DIR/permissive_provenance_transmute.rs:LL:CC + | +LL | deref(ptr1, ptr2.with_addr(ptr1.addr())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/provenance/strict_provenance_transmute.rs b/tests/fail/provenance/strict_provenance_transmute.rs index a684d65b2ce1..12a141e9ddfe 100644 --- a/tests/fail/provenance/strict_provenance_transmute.rs +++ b/tests/fail/provenance/strict_provenance_transmute.rs @@ -7,13 +7,13 @@ use std::mem; // . unsafe fn deref(left: *const u8, right: *const u8) { - let left_int: usize = mem::transmute(left); //~ERROR expected plain (non-pointer) bytes + let left_int: usize = mem::transmute(left); let right_int: usize = mem::transmute(right); if left_int == right_int { // The compiler is allowed to replace `left_int` by `right_int` here... let left_ptr: *const u8 = mem::transmute(left_int); // ...which however means here it could be dereferencing the wrong pointer. - let _val = *left_ptr; + let _val = *left_ptr; //~ERROR dereferencing pointer failed } } diff --git a/tests/fail/provenance/strict_provenance_transmute.stderr b/tests/fail/provenance/strict_provenance_transmute.stderr index 544431815c1b..8df94d50bbac 100644 --- a/tests/fail/provenance/strict_provenance_transmute.stderr +++ b/tests/fail/provenance/strict_provenance_transmute.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered pointer to $HEX[ALLOC], but expected plain (non-pointer) bytes +error: Undefined Behavior: dereferencing pointer failed: $HEX is not a valid pointer --> $DIR/strict_provenance_transmute.rs:LL:CC | -LL | let left_int: usize = mem::transmute(left); - | ^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to $HEX[ALLOC], but expected plain (non-pointer) bytes +LL | let _val = *left_ptr; + | ^^^^^^^^^ dereferencing pointer failed: $HEX is not a valid pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/transmute_fat1.rs b/tests/fail/transmute_fat1.rs index da45dad7b7d4..22fb4c6fdcc9 100644 --- a/tests/fail/transmute_fat1.rs +++ b/tests/fail/transmute_fat1.rs @@ -1,5 +1,4 @@ -// This should fail even without validation -// compile-flags: -Zmiri-disable-validation +// error-pattern: type validation failed: encountered a pointer fn main() { #[cfg(target_pointer_width="64")] @@ -10,5 +9,5 @@ fn main() { let bad = unsafe { std::mem::transmute::<&[u8], [u8; 8]>(&[1u8]) }; - let _val = bad[0] + bad[bad.len()-1]; //~ ERROR unable to turn pointer into raw bytes + let _val = bad[0] + bad[bad.len()-1]; } diff --git a/tests/fail/transmute_fat1.stderr b/tests/fail/transmute_fat1.stderr index 2966f042001c..ea83dd442d2b 100644 --- a/tests/fail/transmute_fat1.stderr +++ b/tests/fail/transmute_fat1.stderr @@ -1,10 +1,11 @@ -error: unsupported operation: unable to turn pointer into raw bytes +error: Undefined Behavior: type validation failed: encountered a pointer, but expected plain (non-pointer) bytes --> $DIR/transmute_fat1.rs:LL:CC | -LL | let _val = bad[0] + bad[bad.len()-1]; - | ^^^^^^ unable to turn pointer into raw bytes +LL | std::mem::transmute::<&[u8], [u8; 16]>(&[1u8]) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected plain (non-pointer) bytes | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: inside `main` at $DIR/transmute_fat1.rs:LL:CC diff --git a/tests/fail/validity/ptr_integer_transmute.rs b/tests/fail/validity/ptr_integer_transmute.rs deleted file mode 100644 index b23ccbbb1b03..000000000000 --- a/tests/fail/validity/ptr_integer_transmute.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn main() { - let r = &mut 42; - let _i: usize = unsafe { std::mem::transmute(r) }; //~ ERROR expected plain (non-pointer) bytes -} diff --git a/tests/fail/validity/ptr_integer_transmute.stderr b/tests/fail/validity/ptr_integer_transmute.stderr deleted file mode 100644 index cad53d71f4d9..000000000000 --- a/tests/fail/validity/ptr_integer_transmute.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: type validation failed: encountered pointer to $HEX[ALLOC], but expected plain (non-pointer) bytes - --> $DIR/ptr_integer_transmute.rs:LL:CC - | -LL | let _i: usize = unsafe { std::mem::transmute(r) }; - | ^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to $HEX[ALLOC], but expected plain (non-pointer) bytes - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `main` at $DIR/ptr_integer_transmute.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/pass/ptr_int_permissive_provenance.rs b/tests/pass/ptr_int_from_exposed.rs similarity index 100% rename from tests/pass/ptr_int_permissive_provenance.rs rename to tests/pass/ptr_int_from_exposed.rs diff --git a/tests/pass/ptr_int_transmute.rs b/tests/pass/ptr_int_transmute.rs new file mode 100644 index 000000000000..ba50480c5399 --- /dev/null +++ b/tests/pass/ptr_int_transmute.rs @@ -0,0 +1,22 @@ +// Test what happens when we read parts of a pointer. +// Related to . +fn ptr_partial_read() { + let x = 13; + let y = &x; + let z = &y as *const &i32 as *const u8; + + // This just strips provenance, but should work fine otherwise. + let _val = unsafe { *z }; +} + +fn transmute_strip_provenance() { + let r = &mut 42; + let addr = r as *mut _ as usize; + let i: usize = unsafe { std::mem::transmute(r) }; + assert_eq!(i, addr); +} + +fn main() { + ptr_partial_read(); + transmute_strip_provenance(); +} From 34d4928dce663ae9c2292ea84b046419fa995537 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 3 Jun 2022 08:47:00 -0400 Subject: [PATCH 3188/5092] addr no longer exposes :) --- tests/fail/provenance/ptr_int_unexposed.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/fail/provenance/ptr_int_unexposed.rs b/tests/fail/provenance/ptr_int_unexposed.rs index 8a336e43ba18..310024c1efc7 100644 --- a/tests/fail/provenance/ptr_int_unexposed.rs +++ b/tests/fail/provenance/ptr_int_unexposed.rs @@ -1,12 +1,12 @@ -// compile-flags: -Zmiri-permissive-provenance -Zmiri-disable-stacked-borrows -Zmiri-allow-ptr-int-transmute +// compile-flags: -Zmiri-permissive-provenance -Zmiri-disable-stacked-borrows +#![feature(strict_provenance)] fn main() { let x: i32 = 3; let x_ptr = &x as *const i32; - // TODO: switch this to addr() once we intrinsify it - let x_usize: usize = unsafe { std::mem::transmute(x_ptr) }; - // Cast back a pointer that did *not* get exposed. - let ptr = x_usize as *const i32; + let x_usize: usize = x_ptr.addr(); + // Cast back an address that did *not* get exposed. + let ptr = std::ptr::from_exposed_addr::(x_usize); assert_eq!(unsafe { *ptr }, 3); //~ ERROR Undefined Behavior: dereferencing pointer failed } From b1b38361724489c9227599b6f772b4f6944ce6b6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 11:44:27 -0400 Subject: [PATCH 3189/5092] fix rustup-toolchain without arguments --- rustup-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rustup-toolchain b/rustup-toolchain index 7e5d57349b9d..ca5508e225a1 100755 --- a/rustup-toolchain +++ b/rustup-toolchain @@ -30,7 +30,7 @@ else NEW_COMMIT="$1" fi echo "$NEW_COMMIT" > rust-version -shift +shift || true # don't fail if shifting fails # Check if we already are at that commit. CUR_COMMIT=$(rustc +miri --version -v 2>/dev/null | egrep "^commit-hash: " | cut -d " " -f 2) From 7f5cfa54d9816b0b985a737bb2fd3bf48ad98714 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 11:44:36 -0400 Subject: [PATCH 3190/5092] port some tests away from flags we want to remove --- tests/fail/stacked_borrows/illegal_read3.rs | 20 ++++++++----------- .../fail/stacked_borrows/illegal_read3.stderr | 4 ++-- tests/fail/transmute-pair-uninit.rs | 3 +-- tests/fail/transmute-pair-uninit.stderr | 6 +++--- tests/fail/uninit_byte_read.rs | 5 ++--- tests/fail/uninit_byte_read.stderr | 6 +++--- .../invalid_enum_tag_256variants_uninit.rs | 1 + tests/pass/intptrcast.rs | 6 ++---- tests/pass/transmute_fat.rs | 11 ++++------ 9 files changed, 26 insertions(+), 36 deletions(-) diff --git a/tests/fail/stacked_borrows/illegal_read3.rs b/tests/fail/stacked_borrows/illegal_read3.rs index 672c200861c6..3de8f57d6223 100644 --- a/tests/fail/stacked_borrows/illegal_read3.rs +++ b/tests/fail/stacked_borrows/illegal_read3.rs @@ -1,16 +1,18 @@ -// compile-flags: -Zmiri-allow-ptr-int-transmute // A callee may not read the destination of our `&mut` without us noticing. // Thise code got carefully checked to not introduce any reborrows // that are not explicit in the source. Let's hope the compiler does not break this later! -#![feature(untagged_unions)] - use std::mem; +union HiddenRef { + // We avoid retagging at this type, so shared vs mutable does not matter. + r: &'static i32, +} + fn main() { let mut x: i32 = 15; let xref1 = &mut x; - let xref1_sneaky: usize = unsafe { mem::transmute_copy(&xref1) }; + let xref1_sneaky: HiddenRef = unsafe { mem::transmute_copy(&xref1) }; // Derived from `xref1`, so using raw value is still ok, ... let xref2 = &mut *xref1; callee(xref1_sneaky); @@ -19,14 +21,8 @@ fn main() { //~^ ERROR: borrow stack } -fn callee(xref1: usize) { - // Transmuting through a union to avoid retagging. - union UsizeToRef { - from: usize, - to: &'static mut i32, - } - let xref1 = UsizeToRef { from: xref1 }; +fn callee(xref1: HiddenRef) { // Doing the deref and the transmute (through the union) in the same place expression // should avoid retagging. - let _val = unsafe { *xref1.to }; + let _val = unsafe { *xref1.r }; } diff --git a/tests/fail/stacked_borrows/illegal_read3.stderr b/tests/fail/stacked_borrows/illegal_read3.stderr index ab26696a765c..75c4305ee81f 100644 --- a/tests/fail/stacked_borrows/illegal_read3.stderr +++ b/tests/fail/stacked_borrows/illegal_read3.stderr @@ -17,8 +17,8 @@ LL | let xref2 = &mut *xref1; help: was later invalidated at offsets [0x0..0x4] --> $DIR/illegal_read3.rs:LL:CC | -LL | let _val = unsafe { *xref1.to }; - | ^^^^^^^^^ +LL | let _val = unsafe { *xref1.r }; + | ^^^^^^^^ = note: inside `main` at $DIR/illegal_read3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/transmute-pair-uninit.rs b/tests/fail/transmute-pair-uninit.rs index 18c80ac42ac8..1bd60f9cff73 100644 --- a/tests/fail/transmute-pair-uninit.rs +++ b/tests/fail/transmute-pair-uninit.rs @@ -1,4 +1,3 @@ -// compile-flags: -Zmiri-allow-uninit-numbers #![feature(core_intrinsics)] use std::mem; @@ -18,6 +17,6 @@ fn main() { assert_eq!(byte, 0); } let v = unsafe { *z.offset(first_undef) }; + //~^ ERROR uninitialized if v == 0 { println!("it is zero"); } - //~^ ERROR this operation requires initialized memory } diff --git a/tests/fail/transmute-pair-uninit.stderr b/tests/fail/transmute-pair-uninit.stderr index f574e9740282..833c3abbb2fb 100644 --- a/tests/fail/transmute-pair-uninit.stderr +++ b/tests/fail/transmute-pair-uninit.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: type validation failed: encountered uninitialized bytes, but expected initialized bytes --> $DIR/transmute-pair-uninit.rs:LL:CC | -LL | if v == 0 { println!("it is zero"); } - | ^^^^^^ using uninitialized data, but this operation requires initialized memory +LL | let v = unsafe { *z.offset(first_undef) }; + | ^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/uninit_byte_read.rs b/tests/fail/uninit_byte_read.rs index 9a1f8df94d60..6868e5895507 100644 --- a/tests/fail/uninit_byte_read.rs +++ b/tests/fail/uninit_byte_read.rs @@ -1,7 +1,6 @@ -// compile-flags: -Zmiri-allow-uninit-numbers fn main() { let v: Vec = Vec::with_capacity(10); - let undef = unsafe { *v.get_unchecked(5) }; - let x = undef + 1; //~ ERROR this operation requires initialized memory + let undef = unsafe { *v.get_unchecked(5) }; //~ ERROR uninitialized + let x = undef + 1; panic!("this should never print: {}", x); } diff --git a/tests/fail/uninit_byte_read.stderr b/tests/fail/uninit_byte_read.stderr index b07473f95b9e..d150be3e7e78 100644 --- a/tests/fail/uninit_byte_read.stderr +++ b/tests/fail/uninit_byte_read.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: type validation failed: encountered uninitialized bytes, but expected initialized bytes --> $DIR/uninit_byte_read.rs:LL:CC | -LL | let x = undef + 1; - | ^^^^^^^^^ using uninitialized data, but this operation requires initialized memory +LL | let undef = unsafe { *v.get_unchecked(5) }; + | ^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs b/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs index c36685ab2f46..b6f86698b3fb 100644 --- a/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs +++ b/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs @@ -1,3 +1,4 @@ +// Even when uninit numbers are allowed, this enum is not. // compile-flags: -Zmiri-allow-uninit-numbers #![allow(unused, deprecated, invalid_value)] diff --git a/tests/pass/intptrcast.rs b/tests/pass/intptrcast.rs index 573bdbae704a..aafa90204fc2 100644 --- a/tests/pass/intptrcast.rs +++ b/tests/pass/intptrcast.rs @@ -1,6 +1,4 @@ -// compile-flags: -Zmiri-allow-ptr-int-transmute - -// This returns a miri pointer at type usize, if the argument is a proper pointer +// This strips provenance fn transmute_ptr_to_int(x: *const T) -> usize { unsafe { std::mem::transmute(x) } } @@ -39,7 +37,7 @@ fn transmute() { // transmuting. let a: *const i32 = &42; let b = transmute_ptr_to_int(a) as u8; - let c = a as usize as u8; + let c = a as u8; assert_eq!(b, c); } diff --git a/tests/pass/transmute_fat.rs b/tests/pass/transmute_fat.rs index 8a6e15031cb4..c62298a9aced 100644 --- a/tests/pass/transmute_fat.rs +++ b/tests/pass/transmute_fat.rs @@ -1,14 +1,11 @@ // Stacked Borrows disallows this becuase the reference is never cast to a raw pointer. -// compile-flags: -Zmiri-disable-stacked-borrows -Zmiri-allow-ptr-int-transmute +// compile-flags: -Zmiri-disable-stacked-borrows fn main() { // If we are careful, we can exploit data layout... let raw = unsafe { - std::mem::transmute::<&[u8], [usize; 2]>(&[42]) + std::mem::transmute::<&[u8], [*const u8; 2]>(&[42]) }; - let ptr = raw[0] + raw[1]; - // We transmute both ways, to really test allow-ptr-int-transmute. - let ptr: *const u8 = unsafe { std::mem::transmute(ptr) }; - // The pointer is one-past-the end, but we decrement it into bounds before using it - assert_eq!(unsafe { *ptr.offset(-1) }, 42); + let ptr: *const u8 = unsafe { std::mem::transmute_copy(&raw) }; + assert_eq!(unsafe { *ptr }, 42); } From b39e4c729acfb2467fd4aed8cea626de00b73ddf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 12:10:40 -0400 Subject: [PATCH 3191/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index e7a7ad9dd818..2898937edfb4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4e725bad73747a4c93a3ac53106e4b4006edc665 +9d20fd109809f20c049d6895a5be27a1fbd39daa From 3ba6456181bd2ea335c8e5b91e85b8094e0f8804 Mon Sep 17 00:00:00 2001 From: infrandomness Date: Mon, 6 Jun 2022 18:17:38 +0200 Subject: [PATCH 3192/5092] Fix rustdoc warnings --- src/data_race.rs | 8 ++++---- src/shims/tls.rs | 4 ++-- src/stacked_borrows.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index c52b84018466..eb67a487b5a5 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -1,11 +1,11 @@ //! Implementation of a data-race detector using Lamport Timestamps / Vector-clocks //! based on the Dynamic Race Detection for C++: -//! https://www.doc.ic.ac.uk/~afd/homepages/papers/pdfs/2017/POPL.pdf +//! //! which does not report false-positives when fences are used, and gives better //! accuracy in presence of read-modify-write operations. //! //! The implementation contains modifications to correctly model the changes to the memory model in C++20 -//! regarding the weakening of release sequences: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0982r1.html. +//! regarding the weakening of release sequences: . //! Relaxed stores now unconditionally block all currently active release sequences and so per-thread tracking of release //! sequences is not needed. //! @@ -15,7 +15,7 @@ //! This does not explore weak memory orders and so can still miss data-races //! but should not report false-positives //! -//! Data-race definition from(https://en.cppreference.com/w/cpp/language/memory_model#Threads_and_data_races): +//! Data-race definition from(): //! a data race occurs between two memory accesses if they are on different threads, at least one operation //! is non-atomic, at least one operation is a write and neither access happens-before the other. Read the link //! for full definition. @@ -24,7 +24,7 @@ //! because it only re-uses vector indexes once all currently-active (not-terminated) threads have an internal //! vector clock that happens-after the join operation of the candidate thread. Threads that have not been joined //! on are not considered. Since the thread's vector clock will only increase and a data-race implies that -//! there is some index x where clock[x] > thread_clock, when this is true clock[candidate-idx] > thread_clock +//! there is some index x where clock\[x\] > thread_clock, when this is true clock\[candidate-idx\] > thread_clock //! can never hold and hence a data-race can never be reported in that vector index again. //! This means that the thread-index can be safely re-used, starting on the next timestamp for the newly created //! thread. diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 87c8d7eadc3b..6b4e9d4f7533 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -135,7 +135,7 @@ impl<'tcx> TlsData<'tcx> { /// [`_tlv_atexit` /// implementation](https://github.com/opensource-apple/dyld/blob/195030646877261f0c8c7ad8b001f52d6a26f514/src/threadLocalVariables.c#L389): /// - /// // NOTE: this does not need locks because it only operates on current thread data + /// NOTE: this does not need locks because it only operates on current thread data pub fn set_macos_thread_dtor( &mut self, thread: ThreadId, @@ -347,7 +347,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Note: we consistently run TLS destructors for all threads, including the /// main thread. However, it is not clear that we should run the TLS /// destructors for the main thread. See issue: - /// https://github.com/rust-lang/rust/issues/28129. + /// . fn schedule_next_tls_dtor_for_active_thread(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let active_thread = this.get_active_thread(); diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index a19e30b113e3..0d671ec653b5 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -945,7 +945,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// it does not alias with anything. /// /// This is a HACK because there is nothing in MIR that would make the retag - /// explicit. Also see https://github.com/rust-lang/rust/issues/71117. + /// explicit. Also see . fn retag_return_place(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let return_place = this.frame_mut().return_place; From 84edb76e2698c62d65605d18f1c2294007d3b3aa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 12:33:48 -0400 Subject: [PATCH 3193/5092] make output bitwidth-independent --- tests/fail/transmute_fat1.rs | 3 ++- tests/fail/transmute_fat1.stderr | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/fail/transmute_fat1.rs b/tests/fail/transmute_fat1.rs index 22fb4c6fdcc9..8b351d3a09e9 100644 --- a/tests/fail/transmute_fat1.rs +++ b/tests/fail/transmute_fat1.rs @@ -1,4 +1,5 @@ // error-pattern: type validation failed: encountered a pointer +// normalize-stderr-test: "\[u8; (08|16)\]" -> "$$ARRAY" fn main() { #[cfg(target_pointer_width="64")] @@ -7,7 +8,7 @@ fn main() { }; #[cfg(target_pointer_width="32")] let bad = unsafe { - std::mem::transmute::<&[u8], [u8; 8]>(&[1u8]) + std::mem::transmute::<&[u8], [u8; 08]>(&[1u8]) }; let _val = bad[0] + bad[bad.len()-1]; } diff --git a/tests/fail/transmute_fat1.stderr b/tests/fail/transmute_fat1.stderr index ea83dd442d2b..cbfa8dff2a50 100644 --- a/tests/fail/transmute_fat1.stderr +++ b/tests/fail/transmute_fat1.stderr @@ -1,7 +1,7 @@ error: Undefined Behavior: type validation failed: encountered a pointer, but expected plain (non-pointer) bytes --> $DIR/transmute_fat1.rs:LL:CC | -LL | std::mem::transmute::<&[u8], [u8; 16]>(&[1u8]) +LL | std::mem::transmute::<&[u8], $ARRAY>(&[1u8]) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected plain (non-pointer) bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior From 8d36e8b32c800e6227ab2ffa7fb64729313e10a1 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sat, 25 Dec 2021 23:45:33 +0000 Subject: [PATCH 3194/5092] Add weak memory config option --- src/bin/miri.rs | 3 +++ src/eval.rs | 3 +++ src/machine.rs | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index e3f38956dae2..907e620404b9 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -318,6 +318,7 @@ fn main() { miri_config.stacked_borrows = false; } else if arg == "-Zmiri-disable-data-race-detector" { miri_config.data_race_detector = false; + miri_config.weak_memory_emulation = false; } else if arg == "-Zmiri-disable-alignment-check" { miri_config.check_alignment = miri::AlignmentCheck::None; } else if arg == "-Zmiri-symbolic-alignment-check" { @@ -340,6 +341,8 @@ fn main() { isolation_enabled = Some(false); } miri_config.isolated_op = miri::IsolatedOp::Allow; + } else if arg == "-Zmiri-disable-weak-memory-emulation" { + miri_config.weak_memory_emulation = false; } else if let Some(param) = arg.strip_prefix("-Zmiri-isolation-error=") { if matches!(isolation_enabled, Some(false)) { panic!("-Zmiri-isolation-error cannot be used along with -Zmiri-disable-isolation"); diff --git a/src/eval.rs b/src/eval.rs index a782dfa3fce1..bdf527a0d13e 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -105,6 +105,8 @@ pub struct MiriConfig { pub tag_raw: bool, /// Determine if data race detection should be enabled pub data_race_detector: bool, + /// Determine if weak memory emulation should be enabled. Requires data race detection to be enabled + pub weak_memory_emulation: bool, /// Rate of spurious failures for compare_exchange_weak atomic operations, /// between 0.0 and 1.0, defaulting to 0.8 (80% chance of failure). pub cmpxchg_weak_failure_rate: f64, @@ -142,6 +144,7 @@ impl Default for MiriConfig { tracked_alloc_ids: HashSet::default(), tag_raw: false, data_race_detector: true, + weak_memory_emulation: true, cmpxchg_weak_failure_rate: 0.8, measureme_out: None, panic_on_unsupported: false, diff --git a/src/machine.rs b/src/machine.rs index 369bb92c6f39..2060bba0b853 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -323,6 +323,9 @@ pub struct Evaluator<'mir, 'tcx> { /// Corresponds to -Zmiri-mute-stdout-stderr and doesn't write the output but acts as if it succeeded. pub(crate) mute_stdout_stderr: bool, + + /// Whether weak memory emulation is enabled + pub(crate) weak_memory: bool, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { @@ -378,6 +381,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { check_alignment: config.check_alignment, cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate, mute_stdout_stderr: config.mute_stdout_stderr, + weak_memory: config.weak_memory_emulation, } } From 16315b1540959e4834ba461471e868868c68c4bc Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Mon, 17 Jan 2022 17:40:17 +0000 Subject: [PATCH 3195/5092] Add test cases --- tests/run-pass/concurrency/weak_memory.rs | 257 ++++++++++++++++++ tests/run-pass/concurrency/weak_memory.stderr | 2 + 2 files changed, 259 insertions(+) create mode 100644 tests/run-pass/concurrency/weak_memory.rs create mode 100644 tests/run-pass/concurrency/weak_memory.stderr diff --git a/tests/run-pass/concurrency/weak_memory.rs b/tests/run-pass/concurrency/weak_memory.rs new file mode 100644 index 000000000000..bd3d1de7c23e --- /dev/null +++ b/tests/run-pass/concurrency/weak_memory.rs @@ -0,0 +1,257 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows + +// Weak memory emulation tests. All of the following test if +// our weak memory emulation produces any inconsistent execution outcomes +// +// Due to the random nature of choosing valid stores, it is always +// possible that our tests spuriously succeeds: even though our weak +// memory emulation code has incorrectly identified a store in +// modification order as being valid, it may be never chosen by +// the RNG and never observed in our tests. +// +// To mitigate this, each test is ran enough times such that the chance +// of spurious success is very low. These tests never supriously fail. +// +// Note that we can't effectively test whether our weak memory emulation +// can produce *all* consistent execution outcomes. This may be possible +// if Miri's scheduler is sufficiently random and explores all possible +// interleavings of our small test cases after a reasonable number of runs. +// However, since Miri's scheduler is not even pre-emptive, there will +// always be possible interleavings (and possible execution outcomes), +// that can never be observed regardless of how weak memory emulation is +// implemented. + +// Test cases and their consistent outcomes are from +// http://svr-pes20-cppmem.cl.cam.ac.uk/cppmem/ +// Based on +// M. Batty, S. Owens, S. Sarkar, P. Sewell and T. Weber, +// "Mathematizing C++ concurrency", ACM SIGPLAN Notices, vol. 46, no. 1, pp. 55-66, 2011. +// Available: https://ss265.host.cs.st-andrews.ac.uk/papers/n3132.pdf. + +use std::sync::atomic::Ordering::*; +use std::sync::atomic::{fence, AtomicUsize}; +use std::thread::{spawn, yield_now}; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +// We can't create static items because we need to run each test +// multiple tests +fn static_atomic(val: usize) -> &'static AtomicUsize { + let ret = Box::leak(Box::new(AtomicUsize::new(val))); + // A workaround to put the initialisation value in the store buffer + ret.store(val, Relaxed); + ret +} + +// Spins and yields until until acquires a pre-determined value +fn acquires_value(loc: &AtomicUsize, val: usize) -> usize { + while loc.load(Acquire) != val { + yield_now(); + } + val +} + +fn reads_value(loc: &AtomicUsize, val: usize) -> usize { + while loc.load(Relaxed) != val { + yield_now(); + } + val +} + +// https://plv.mpi-sws.org/scfix/paper.pdf +// 2.2 Second Problem: SC Fences are Too Weak +fn test_rwc_syncs() { + /* + int main() { + atomic_int x = 0; + atomic_int y = 0; + + {{{ x.store(1,mo_relaxed); + ||| { r1=x.load(mo_relaxed).readsvalue(1); + fence(mo_seq_cst); + r2=y.load(mo_relaxed); } + ||| { y.store(1,mo_relaxed); + fence(mo_seq_cst); + r3=x.load(mo_relaxed); } + }}} + return 0; + } + */ + let x = static_atomic(0); + let y = static_atomic(0); + + let j1 = spawn(move || { + x.store(1, Relaxed); + }); + + let j2 = spawn(move || { + reads_value(&x, 1); + fence(SeqCst); + y.load(Relaxed) + }); + + let j3 = spawn(move || { + y.store(1, Relaxed); + fence(SeqCst); + x.load(Relaxed) + }); + + j1.join().unwrap(); + let b = j2.join().unwrap(); + let c = j3.join().unwrap(); + + assert_ne!((b, c), (0, 0)); +} + +fn test_corr() { + let x = static_atomic(0); + let y = static_atomic(0); + + let j1 = spawn(move || { + x.store(1, Relaxed); + x.store(2, Relaxed); + }); + + let j2 = spawn(move || { + let r2 = x.load(Relaxed); // -------------------------------------+ + y.store(1, Release); // ---------------------+ | + r2 // | | + }); // | | + // |synchronizes-with |happens-before + let j3 = spawn(move || { // | | + acquires_value(&y, 1); // <------------------+ | + x.load(Relaxed) // <----------------------------------------------+ + // The two reads on x are ordered by hb, so they cannot observe values + // differently from the modification order. If the first read observed + // 2, then the second read must observe 2 as well. + }); + + j1.join().unwrap(); + let r2 = j2.join().unwrap(); + let r3 = j3.join().unwrap(); + if r2 == 2 { + assert_eq!(r3, 2); + } +} + +fn test_wrc() { + let x = static_atomic(0); + let y = static_atomic(0); + + let j1 = spawn(move || { + x.store(1, Release); // ---------------------+---------------------+ + }); // | | + // |synchronizes-with | + let j2 = spawn(move || { // | | + acquires_value(&x, 1); // <------------------+ | + y.store(1, Release); // ---------------------+ |happens-before + }); // | | + // |synchronizes-with | + let j3 = spawn(move || { // | | + acquires_value(&y, 1); // <------------------+ | + x.load(Relaxed) // <-----------------------------------------------+ + }); + + j1.join().unwrap(); + j2.join().unwrap(); + let r3 = j3.join().unwrap(); + + assert_eq!(r3, 1); +} + +fn test_message_passing() { + let mut var = 0u32; + let ptr = &mut var as *mut u32; + let x = EvilSend(ptr); + let y = static_atomic(0); + + let j1 = spawn(move || { + unsafe { *x.0 = 1 }; // -----------------------------------------+ + y.store(1, Release); // ---------------------+ | + }); // | | + // |synchronizes-with | happens-before + let j2 = spawn(move || { // | | + acquires_value(&y, 1); // <------------------+ | + unsafe { *x.0 } // <---------------------------------------------+ + }); + + j1.join().unwrap(); + let r2 = j2.join().unwrap(); + + assert_eq!(r2, 1); +} + +// LB+acq_rel+acq_rel +fn test_load_buffering_acq_rel() { + let x = static_atomic(0); + let y = static_atomic(0); + let j1 = spawn(move || { + let r1 = x.load(Acquire); + y.store(1, Release); + r1 + }); + + let j2 = spawn(move || { + let r2 = y.load(Acquire); + x.store(1, Release); + r2 + }); + + let r1 = j1.join().unwrap(); + let r2 = j2.join().unwrap(); + + // 3 consistent outcomes: (0,0), (0,1), (1,0) + assert_ne!((r1, r2), (1, 1)); +} + +fn test_mixed_access() { + /* + int main() { + atomic_int x = 0; + {{{ + x.store(1, mo_relaxed); + }}} + + x.store(2, mo_relaxed); + + {{{ + r1 = x.load(mo_relaxed); + }}} + + return 0; + } + */ + let x = static_atomic(0); + + spawn(move || { + x.store(1, Relaxed); + }) + .join() + .unwrap(); + + x.store(2, Relaxed); + + let r2 = spawn(move || x.load(Relaxed)).join().unwrap(); + + assert_eq!(r2, 2); +} + +pub fn main() { + // TODO: does this make chances of spurious success + // "sufficiently low"? This also takes a long time to run, + // prehaps each function should be its own test case so they + // can be run in parallel + for _ in 0..500 { + test_mixed_access(); + test_load_buffering_acq_rel(); + test_message_passing(); + test_wrc(); + test_corr(); + test_rwc_syncs(); + } +} diff --git a/tests/run-pass/concurrency/weak_memory.stderr b/tests/run-pass/concurrency/weak_memory.stderr new file mode 100644 index 000000000000..03676519d4f1 --- /dev/null +++ b/tests/run-pass/concurrency/weak_memory.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + From e7698f4f07dcec9cf42b3de133f9ca171d0677f0 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Mon, 27 Dec 2021 19:07:23 +0000 Subject: [PATCH 3196/5092] Implement weak memory emulation --- src/data_race.rs | 170 +++++++++++-- src/lib.rs | 1 + src/machine.rs | 12 +- src/weak_memory.rs | 297 ++++++++++++++++++++++ tests/run-pass/concurrency/weak_memory.rs | 23 ++ 5 files changed, 476 insertions(+), 27 deletions(-) create mode 100644 src/weak_memory.rs diff --git a/src/data_race.rs b/src/data_race.rs index eb67a487b5a5..82ee32ddee71 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -12,7 +12,7 @@ //! The implementation also models races with memory allocation and deallocation via treating allocation and //! deallocation as a type of write internally for detecting data-races. //! -//! This does not explore weak memory orders and so can still miss data-races +//! Weak memory orders are explored but not all weak behaviours are exhibited, so it can still miss data-races //! but should not report false-positives //! //! Data-race definition from(): @@ -29,22 +29,6 @@ //! This means that the thread-index can be safely re-used, starting on the next timestamp for the newly created //! thread. //! -//! The sequentially consistent ordering corresponds to the ordering that the threads -//! are currently scheduled, this means that the data-race detector has no additional -//! logic for sequentially consistent accesses at the moment since they are indistinguishable -//! from acquire/release operations. If weak memory orderings are explored then this -//! may need to change or be updated accordingly. -//! -//! Per the C++ spec for the memory model a sequentially consistent operation: -//! "A load operation with this memory order performs an acquire operation, -//! a store performs a release operation, and read-modify-write performs -//! both an acquire operation and a release operation, plus a single total -//! order exists in which all threads observe all modifications in the same -//! order (see Sequentially-consistent ordering below) " -//! So in the absence of weak memory effects a seq-cst load & a seq-cst store is identical -//! to an acquire load and a release store given the global sequentially consistent order -//! of the schedule. -//! //! The timestamps used in the data-race detector assign each sequence of non-atomic operations //! followed by a single atomic or concurrent operation a single timestamp. //! Write, Read, Write, ThreadJoin will be represented by a single timestamp value on a thread. @@ -67,6 +51,7 @@ use std::{ mem, }; +use rustc_const_eval::interpret::alloc_range; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::{mir, ty::layout::TyAndLayout}; @@ -115,10 +100,10 @@ pub enum AtomicFenceOp { /// of a thread, contains the happens-before clock and /// additional metadata to model atomic fence operations. #[derive(Clone, Default, Debug)] -struct ThreadClockSet { +pub struct ThreadClockSet { /// The increasing clock representing timestamps /// that happen-before this thread. - clock: VClock, + pub clock: VClock, /// The set of timestamps that will happen-before this /// thread once it performs an acquire fence. @@ -127,6 +112,12 @@ struct ThreadClockSet { /// The last timestamp of happens-before relations that /// have been released by this thread by a fence. fence_release: VClock, + + pub fence_seqcst: VClock, + + pub write_seqcst: VClock, + + pub read_seqcst: VClock, } impl ThreadClockSet { @@ -169,7 +160,7 @@ pub struct DataRace; /// common case where no atomic operations /// exists on the memory cell. #[derive(Clone, PartialEq, Eq, Default, Debug)] -struct AtomicMemoryCellClocks { +pub struct AtomicMemoryCellClocks { /// The clock-vector of the timestamp of the last atomic /// read operation performed by each thread. /// This detects potential data-races between atomic read @@ -514,7 +505,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicReadOp, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_ref(); + // This will read from the last store in the modification order of this location. In case + // weak memory emulation is enabled, this may not be the store we will pick to actually read from and return. + // This is fine with StackedBorrow and race checks because they don't concern metadata on + // the *value* (including the associated provenance if this is an AtomicPtr) at this location. + // Only metadata on the location itself is used. let scalar = this.allow_data_races_ref(move |this| this.read_scalar(&place.into()))?; + + if let Some(global) = &this.machine.data_race { + let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; + if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { + if atomic == AtomicReadOp::SeqCst { + global.sc_read(); + } + let mut rng = this.machine.rng.borrow_mut(); + let loaded = alloc_buffers.buffered_read( + alloc_range(base_offset, place.layout.size), + global, + atomic == AtomicReadOp::SeqCst, + &mut *rng, + || this.validate_atomic_load(place, atomic), + )?; + + return Ok(loaded.unwrap_or(scalar)); + } + } + this.validate_atomic_load(place, atomic)?; Ok(scalar) } @@ -528,7 +544,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.allow_data_races_mut(move |this| this.write_scalar(val, &(*dest).into()))?; - this.validate_atomic_store(dest, atomic) + + this.validate_atomic_store(dest, atomic)?; + let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(dest.ptr)?; + if let ( + crate::AllocExtra { weak_memory: Some(alloc_buffers), .. }, + crate::Evaluator { data_race: Some(global), .. }, + ) = this.get_alloc_extra_mut(alloc_id)? + { + if atomic == AtomicWriteOp::SeqCst { + global.sc_write(); + } + let size = dest.layout.size; + alloc_buffers.buffered_write( + val, + alloc_range(base_offset, size), + global, + atomic == AtomicWriteOp::SeqCst, + )?; + } + + Ok(()) } /// Perform an atomic operation on a memory location. @@ -550,6 +586,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { this.allow_data_races_mut(|this| this.write_immediate(*val, &(*place).into()))?; this.validate_atomic_rmw(place, atomic)?; + + this.buffered_atomic_rmw(val.to_scalar_or_uninit(), place, atomic)?; Ok(old) } @@ -565,7 +603,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let old = this.allow_data_races_mut(|this| this.read_scalar(&place.into()))?; this.allow_data_races_mut(|this| this.write_scalar(new, &(*place).into()))?; + this.validate_atomic_rmw(place, atomic)?; + + this.buffered_atomic_rmw(new, place, atomic)?; Ok(old) } @@ -584,15 +625,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let lt = this.binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar()?.to_bool()?; let new_val = if min { - if lt { &old } else { &rhs } + if lt { + &old + } else { + &rhs + } } else { - if lt { &rhs } else { &old } + if lt { + &rhs + } else { + &old + } }; this.allow_data_races_mut(|this| this.write_immediate(**new_val, &(*place).into()))?; this.validate_atomic_rmw(place, atomic)?; + this.buffered_atomic_rmw(new_val.to_scalar_or_uninit(), place, atomic)?; + // Return the old value. Ok(old) } @@ -642,14 +693,56 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { if cmpxchg_success { this.allow_data_races_mut(|this| this.write_scalar(new, &(*place).into()))?; this.validate_atomic_rmw(place, success)?; + this.buffered_atomic_rmw(new, place, success)?; } else { this.validate_atomic_load(place, fail)?; + // A failed compare exchange is equivalent to a load, reading from the latest store + // in the modification order. + // Since `old` is only a value and not the store element, we need to separately + // find it in our store buffer and perform load_impl on it. + if let Some(global) = &this.machine.data_race { + if fail == AtomicReadOp::SeqCst { + global.sc_read(); + } + let size = place.layout.size; + let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; + if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { + if global.multi_threaded.get() { + alloc_buffers.read_from_last_store(alloc_range(base_offset, size), global); + } + } + } } // Return the old value. Ok(res) } + fn buffered_atomic_rmw( + &mut self, + new_val: ScalarMaybeUninit, + place: &MPlaceTy<'tcx, Tag>, + atomic: AtomicRwOp, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; + if let ( + crate::AllocExtra { weak_memory: Some(alloc_buffers), .. }, + crate::Evaluator { data_race: Some(global), .. }, + ) = this.get_alloc_extra_mut(alloc_id)? + { + if atomic == AtomicRwOp::SeqCst { + global.sc_read(); + global.sc_write(); + } + let size = place.layout.size; + let range = alloc_range(base_offset, size); + alloc_buffers.read_from_last_store(range, global); + alloc_buffers.buffered_write(new_val, range, global, atomic == AtomicRwOp::SeqCst)?; + } + Ok(()) + } + /// Update the data-race detector for an atomic read occurring at the /// associated memory-place and on the current thread. fn validate_atomic_load( @@ -723,7 +816,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { fn validate_atomic_fence(&mut self, atomic: AtomicFenceOp) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if let Some(data_race) = &mut this.machine.data_race { - data_race.maybe_perform_sync_operation(move |index, mut clocks| { + data_race.maybe_perform_sync_operation(|index, mut clocks| { log::trace!("Atomic fence on {:?} with ordering {:?}", index, atomic); // Apply data-race detection for the current fences @@ -737,6 +830,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // Either Release | AcqRel | SeqCst clocks.apply_release_fence(); } + if atomic == AtomicFenceOp::SeqCst { + data_race.last_sc_fence.borrow_mut().set_at_index(&clocks.clock, index); + clocks.fence_seqcst.join(&data_race.last_sc_fence.borrow()); + clocks.write_seqcst.join(&data_race.last_sc_write.borrow()); + } // Increment timestamp in case of release semantics. Ok(atomic != AtomicFenceOp::Acquire) @@ -1116,6 +1214,12 @@ pub struct GlobalState { /// The associated vector index will be moved into re-use candidates /// after the join operation occurs. terminated_threads: RefCell>, + + /// The timestamp of last SC fence performed by each thread + last_sc_fence: RefCell, + + /// The timestamp of last SC write performed by each thread + last_sc_write: RefCell, } impl GlobalState { @@ -1131,6 +1235,8 @@ impl GlobalState { active_thread_count: Cell::new(1), reuse_candidates: RefCell::new(FxHashSet::default()), terminated_threads: RefCell::new(FxHashMap::default()), + last_sc_fence: RefCell::new(VClock::default()), + last_sc_write: RefCell::new(VClock::default()), }; // Setup the main-thread since it is not explicitly created: @@ -1445,7 +1551,7 @@ impl GlobalState { /// Load the current vector clock in use and the current set of thread clocks /// in use for the vector. #[inline] - fn current_thread_state(&self) -> (VectorIdx, Ref<'_, ThreadClockSet>) { + pub fn current_thread_state(&self) -> (VectorIdx, Ref<'_, ThreadClockSet>) { let index = self.current_index(); let ref_vector = self.vector_clocks.borrow(); let clocks = Ref::map(ref_vector, |vec| &vec[index]); @@ -1455,7 +1561,7 @@ impl GlobalState { /// Load the current vector clock in use and the current set of thread clocks /// in use for the vector mutably for modification. #[inline] - fn current_thread_state_mut(&self) -> (VectorIdx, RefMut<'_, ThreadClockSet>) { + pub fn current_thread_state_mut(&self) -> (VectorIdx, RefMut<'_, ThreadClockSet>) { let index = self.current_index(); let ref_vector = self.vector_clocks.borrow_mut(); let clocks = RefMut::map(ref_vector, |vec| &mut vec[index]); @@ -1468,4 +1574,16 @@ impl GlobalState { fn current_index(&self) -> VectorIdx { self.current_index.get() } + + // SC ATOMIC STORE rule in the paper. + fn sc_write(&self) { + let (index, clocks) = self.current_thread_state(); + self.last_sc_write.borrow_mut().set_at_index(&clocks.clock, index); + } + + // SC ATOMIC READ rule in the paper. + fn sc_read(&self) { + let (.., mut clocks) = self.current_thread_state_mut(); + clocks.read_seqcst.join(&self.last_sc_fence.borrow()); + } } diff --git a/src/lib.rs b/src/lib.rs index f7c256656a76..06ab2fabab04 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,6 +45,7 @@ mod stacked_borrows; mod sync; mod thread; mod vector_clock; +mod weak_memory; // Establish a "crate-wide prelude": we often import `crate::*`. diff --git a/src/machine.rs b/src/machine.rs index 2060bba0b853..aa2a930ccd25 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -190,6 +190,9 @@ pub struct AllocExtra { /// Data race detection via the use of a vector-clock, /// this is only added if it is enabled. pub data_race: Option, + /// Weak memory emulation via the use of store buffers, + /// this is only added if it is enabled. + pub weak_memory: Option, } /// Precomputed layouts of primitive types @@ -630,9 +633,16 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } else { None }; + let buffer_alloc = if ecx.machine.weak_memory { + // FIXME: if this is an atomic obejct, we want to supply its initial value + // while allocating the store buffer here. + Some(weak_memory::AllocExtra::new_allocation(alloc.size())) + } else { + None + }; let alloc: Allocation = alloc.convert_tag_add_extra( &ecx.tcx, - AllocExtra { stacked_borrows: stacks, data_race: race_alloc }, + AllocExtra { stacked_borrows: stacks, data_race: race_alloc, weak_memory: buffer_alloc }, |ptr| Evaluator::tag_alloc_base_pointer(ecx, ptr), ); Cow::Owned(alloc) diff --git a/src/weak_memory.rs b/src/weak_memory.rs new file mode 100644 index 000000000000..c82a31d0a89c --- /dev/null +++ b/src/weak_memory.rs @@ -0,0 +1,297 @@ +//! Implementation of C++11-consistent weak memory emulation using store buffers +//! based on Dynamic Race Detection for C++ ("the paper"): +//! https://www.doc.ic.ac.uk/~afd/homepages/papers/pdfs/2017/POPL.pdf + +// Our and the author's own implementation (tsan11) of the paper have some deviations from the provided operational semantics in §5.3: +// 1. In the operational semantics, store elements keep a copy of the atomic object's vector clock (AtomicCellClocks::sync_vector in miri), +// but this is not used anywhere so it's omitted here. +// +// 2. In the operational semantics, each store element keeps the timestamp of a thread when it loads from the store. +// If the same thread loads from the same store element multiple times, then the timestamps at all loads are saved in a list of load elements. +// This is not necessary as later loads by the same thread will always have greater timetstamp values, so we only need to record the timestamp of the first +// load by each thread. This optimisation is done in tsan11 +// (https://github.com/ChrisLidbury/tsan11/blob/ecbd6b81e9b9454e01cba78eb9d88684168132c7/lib/tsan/rtl/tsan_relaxed.h#L35-L37) +// and here. +// +// 3. §4.5 of the paper wants an SC store to mark all existing stores in the buffer that happens before it +// as SC. This is not done in the operational semantics but implemented correctly in tsan11 +// (https://github.com/ChrisLidbury/tsan11/blob/ecbd6b81e9b9454e01cba78eb9d88684168132c7/lib/tsan/rtl/tsan_relaxed.cc#L160-L167) +// and here. +// +// 4. W_SC ; R_SC case requires the SC load to ignore all but last store maked SC (stores not marked SC are not +// affected). But this rule is applied to all loads in ReadsFromSet from the paper (last two lines of code), not just SC load. +// This is implemented correctly in tsan11 +// (https://github.com/ChrisLidbury/tsan11/blob/ecbd6b81e9b9454e01cba78eb9d88684168132c7/lib/tsan/rtl/tsan_relaxed.cc#L295) +// and here. + +use std::{ + cell::{Ref, RefCell, RefMut}, + collections::VecDeque, +}; + +use rustc_const_eval::interpret::{AllocRange, InterpResult, ScalarMaybeUninit}; +use rustc_data_structures::fx::FxHashMap; +use rustc_target::abi::Size; + +use crate::{ + data_race::{GlobalState, ThreadClockSet}, + RangeMap, Tag, VClock, VTimestamp, VectorIdx, +}; + +pub type AllocExtra = StoreBufferAlloc; +#[derive(Debug, Clone)] +pub struct StoreBufferAlloc { + /// Store buffer of each atomic object in this allocation + // Load may modify a StoreBuffer to record the loading thread's + // timestamp so we need interior mutability here. + store_buffer: RefCell>, +} + +impl StoreBufferAlloc { + pub fn new_allocation(len: Size) -> Self { + Self { store_buffer: RefCell::new(RangeMap::new(len, StoreBuffer::default())) } + } + + /// Gets a store buffer associated with an atomic object in this allocation + fn get_store_buffer(&self, range: AllocRange) -> Ref<'_, StoreBuffer> { + Ref::map(self.store_buffer.borrow(), |range_map| { + let (.., store_buffer) = range_map.iter(range.start, range.size).next().unwrap(); + store_buffer + }) + } + + fn get_store_buffer_mut(&self, range: AllocRange) -> RefMut<'_, StoreBuffer> { + RefMut::map(self.store_buffer.borrow_mut(), |range_map| { + let (.., store_buffer) = range_map.iter_mut(range.start, range.size).next().unwrap(); + store_buffer + }) + } + + /// Reads from the last store in modification order + pub fn read_from_last_store<'tcx>(&self, range: AllocRange, global: &GlobalState) { + let store_buffer = self.get_store_buffer(range); + let store_elem = store_buffer.buffer.back(); + if let Some(store_elem) = store_elem { + let (index, clocks) = global.current_thread_state(); + store_elem.load_impl(index, &clocks); + } + } + + pub fn buffered_read<'tcx>( + &self, + range: AllocRange, + global: &GlobalState, + is_seqcst: bool, + rng: &mut (impl rand::Rng + ?Sized), + validate: impl FnOnce() -> InterpResult<'tcx>, + ) -> InterpResult<'tcx, Option>> { + // Having a live borrow to store_buffer while calling validate_atomic_load is fine + // because the race detector doesn't touch store_buffer + let store_buffer = self.get_store_buffer(range); + + let store_elem = { + // The `clocks` we got here must be dropped before calling validate_atomic_load + // as the race detector will update it + let (.., clocks) = global.current_thread_state(); + // Load from a valid entry in the store buffer + store_buffer.fetch_store(is_seqcst, &clocks, &mut *rng) + }; + + // Unlike in write_scalar_atomic, thread clock updates have to be done + // after we've picked a store element from the store buffer, as presented + // in ATOMIC LOAD rule of the paper. This is because fetch_store + // requires access to ThreadClockSet.clock, which is updated by the race detector + validate()?; + + let loaded = store_elem.map(|store_elem| { + let (index, clocks) = global.current_thread_state(); + store_elem.load_impl(index, &clocks) + }); + Ok(loaded) + } + + pub fn buffered_write<'tcx>( + &mut self, + val: ScalarMaybeUninit, + range: AllocRange, + global: &GlobalState, + is_seqcst: bool, + ) -> InterpResult<'tcx> { + let (index, clocks) = global.current_thread_state(); + + let mut store_buffer = self.get_store_buffer_mut(range); + store_buffer.store_impl(val, index, &clocks.clock, is_seqcst); + Ok(()) + } +} + +const STORE_BUFFER_LIMIT: usize = 128; +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct StoreBuffer { + // Stores to this location in modification order + buffer: VecDeque, +} + +impl Default for StoreBuffer { + fn default() -> Self { + let mut buffer = VecDeque::new(); + buffer.reserve(STORE_BUFFER_LIMIT); + Self { buffer } + } +} + +impl<'mir, 'tcx: 'mir> StoreBuffer { + /// Selects a valid store element in the buffer. + /// The buffer does not contain the value used to initialise the atomic object + /// so a fresh atomic object has an empty store buffer until an explicit store. + fn fetch_store( + &self, + is_seqcst: bool, + clocks: &ThreadClockSet, + rng: &mut R, + ) -> Option<&StoreElement> { + use rand::seq::IteratorRandom; + let mut found_sc = false; + // FIXME: this should be an inclusive take_while (stops after a false predicate, but + // includes the element that gave the false), but such function doesn't yet + // exist in the standard libary https://github.com/rust-lang/rust/issues/62208 + let mut keep_searching = true; + let candidates = self + .buffer + .iter() + .rev() + .take_while(move |&store_elem| { + if !keep_searching { + return false; + } + // CoWR: if a store happens-before the current load, + // then we can't read-from anything earlier in modification order. + if store_elem.timestamp <= clocks.clock[store_elem.store_index] { + log::info!("Stopped due to coherent write-read"); + keep_searching = false; + return true; + } + + // CoRR: if there was a load from this store which happened-before the current load, + // then we cannot read-from anything earlier in modification order. + if store_elem.loads.borrow().iter().any(|(&load_index, &load_timestamp)| { + load_timestamp <= clocks.clock[load_index] + }) { + log::info!("Stopped due to coherent read-read"); + keep_searching = false; + return true; + } + + // The current load, which may be sequenced-after an SC fence, can only read-from + // the last store sequenced-before an SC fence in another thread (or any stores + // later than that SC fence) + if store_elem.timestamp <= clocks.fence_seqcst[store_elem.store_index] { + log::info!("Stopped due to coherent load sequenced after sc fence"); + keep_searching = false; + return true; + } + + // The current non-SC load can only read-from the latest SC store (or any stores later than that + // SC store) + if store_elem.timestamp <= clocks.write_seqcst[store_elem.store_index] + && store_elem.is_seqcst + { + log::info!("Stopped due to needing to load from the last SC store"); + keep_searching = false; + return true; + } + + // The current SC load can only read-from the last store sequenced-before + // the last SC fence (or any stores later than the SC fence) + if is_seqcst && store_elem.timestamp <= clocks.read_seqcst[store_elem.store_index] { + log::info!("Stopped due to sc load needing to load from the last SC store before an SC fence"); + keep_searching = false; + return true; + } + + true + }) + .filter(|&store_elem| { + if is_seqcst { + // An SC load needs to ignore all but last store maked SC (stores not marked SC are not + // affected) + let include = !(store_elem.is_seqcst && found_sc); + found_sc |= store_elem.is_seqcst; + include + } else { + true + } + }); + + candidates.choose(rng) + } + + /// ATOMIC STORE IMPL in the paper (except we don't need the location's vector clock) + fn store_impl( + &mut self, + val: ScalarMaybeUninit, + index: VectorIdx, + thread_clock: &VClock, + is_seqcst: bool, + ) { + let store_elem = StoreElement { + store_index: index, + timestamp: thread_clock[index], + // In the language provided in the paper, an atomic store takes the value from a + // non-atomic memory location. + // But we already have the immediate value here so we don't need to do the memory + // access + val, + is_seqcst, + loads: RefCell::new(FxHashMap::default()), + }; + self.buffer.push_back(store_elem); + if self.buffer.len() > STORE_BUFFER_LIMIT { + self.buffer.pop_front(); + } + if is_seqcst { + // Every store that happens before this needs to be marked as SC + // so that in a later SC load, only the last SC store (i.e. this one) or stores that + // aren't ordered by hb with the last SC is picked. + self.buffer.iter_mut().rev().for_each(|elem| { + if elem.timestamp <= thread_clock[elem.store_index] { + elem.is_seqcst = true; + } + }) + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct StoreElement { + /// The identifier of the vector index, corresponding to a thread + /// that performed the store. + store_index: VectorIdx, + + /// Whether this store is SC. + is_seqcst: bool, + + /// The timestamp of the storing thread when it performed the store + timestamp: VTimestamp, + /// The value of this store + val: ScalarMaybeUninit, + + /// Timestamp of first loads from this store element by each thread + /// Behind a RefCell to keep load op take &self + loads: RefCell>, +} + +impl StoreElement { + /// ATOMIC LOAD IMPL in the paper + /// Unlike the operational semantics in the paper, we don't need to keep track + /// of the thread timestamp for every single load. Keeping track of the first (smallest) + /// timestamp of each thread that has loaded from a store is sufficient: if the earliest + /// load of another thread happens before the current one, then we must stop searching the store + /// buffer regardless of subsequent loads by the same thread; if the earliest load of another + /// thread doesn't happen before the current one, then no subsequent load by the other thread + /// can happen before the current one. + fn load_impl(&self, index: VectorIdx, clocks: &ThreadClockSet) -> ScalarMaybeUninit { + let _ = self.loads.borrow_mut().try_insert(index, clocks.clock[index]); + self.val + } +} diff --git a/tests/run-pass/concurrency/weak_memory.rs b/tests/run-pass/concurrency/weak_memory.rs index bd3d1de7c23e..b8e780ade1a0 100644 --- a/tests/run-pass/concurrency/weak_memory.rs +++ b/tests/run-pass/concurrency/weak_memory.rs @@ -63,6 +63,28 @@ fn reads_value(loc: &AtomicUsize, val: usize) -> usize { val } +// https://plv.mpi-sws.org/scfix/paper.pdf +// Test case SB +fn test_sc_store_buffering() { + let x = static_atomic(0); + let y = static_atomic(0); + + let j1 = spawn(move || { + x.store(1, SeqCst); + y.load(SeqCst) + }); + + let j2 = spawn(move || { + y.store(1, SeqCst); + x.load(SeqCst) + }); + + let a = j1.join().unwrap(); + let b = j2.join().unwrap(); + + assert_ne!((a, b), (0, 0)); +} + // https://plv.mpi-sws.org/scfix/paper.pdf // 2.2 Second Problem: SC Fences are Too Weak fn test_rwc_syncs() { @@ -247,6 +269,7 @@ pub fn main() { // prehaps each function should be its own test case so they // can be run in parallel for _ in 0..500 { + test_sc_store_buffering(); test_mixed_access(); test_load_buffering_acq_rel(); test_message_passing(); From aca3b3a645e6d0295e9f1829c37af811a6de5251 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Fri, 15 Apr 2022 21:44:22 +0100 Subject: [PATCH 3197/5092] set_at_index sets the default value (0) if index doesn't exist in the other vector --- src/vector_clock.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/vector_clock.rs b/src/vector_clock.rs index e13e9c39fc69..716fdba0f67c 100644 --- a/src/vector_clock.rs +++ b/src/vector_clock.rs @@ -108,10 +108,8 @@ impl VClock { /// Set the element at the current index of the vector pub fn set_at_index(&mut self, other: &Self, idx: VectorIdx) { - let idx = idx.index(); - let mut_slice = self.get_mut_with_min_len(idx + 1); - let slice = other.as_slice(); - mut_slice[idx] = slice[idx]; + let mut_slice = self.get_mut_with_min_len(idx.index() + 1); + mut_slice[idx.index()] = other[idx]; } /// Set the vector to the all-zero vector From cf266584b7d9e42f6b1ba622b828e7d95c243225 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sat, 16 Apr 2022 01:01:49 +0100 Subject: [PATCH 3198/5092] Comment out and provide context to C++20 test --- tests/run-pass/concurrency/weak_memory.rs | 144 +++++++++++----------- 1 file changed, 75 insertions(+), 69 deletions(-) diff --git a/tests/run-pass/concurrency/weak_memory.rs b/tests/run-pass/concurrency/weak_memory.rs index b8e780ade1a0..efbbc45909cf 100644 --- a/tests/run-pass/concurrency/weak_memory.rs +++ b/tests/run-pass/concurrency/weak_memory.rs @@ -63,73 +63,6 @@ fn reads_value(loc: &AtomicUsize, val: usize) -> usize { val } -// https://plv.mpi-sws.org/scfix/paper.pdf -// Test case SB -fn test_sc_store_buffering() { - let x = static_atomic(0); - let y = static_atomic(0); - - let j1 = spawn(move || { - x.store(1, SeqCst); - y.load(SeqCst) - }); - - let j2 = spawn(move || { - y.store(1, SeqCst); - x.load(SeqCst) - }); - - let a = j1.join().unwrap(); - let b = j2.join().unwrap(); - - assert_ne!((a, b), (0, 0)); -} - -// https://plv.mpi-sws.org/scfix/paper.pdf -// 2.2 Second Problem: SC Fences are Too Weak -fn test_rwc_syncs() { - /* - int main() { - atomic_int x = 0; - atomic_int y = 0; - - {{{ x.store(1,mo_relaxed); - ||| { r1=x.load(mo_relaxed).readsvalue(1); - fence(mo_seq_cst); - r2=y.load(mo_relaxed); } - ||| { y.store(1,mo_relaxed); - fence(mo_seq_cst); - r3=x.load(mo_relaxed); } - }}} - return 0; - } - */ - let x = static_atomic(0); - let y = static_atomic(0); - - let j1 = spawn(move || { - x.store(1, Relaxed); - }); - - let j2 = spawn(move || { - reads_value(&x, 1); - fence(SeqCst); - y.load(Relaxed) - }); - - let j3 = spawn(move || { - y.store(1, Relaxed); - fence(SeqCst); - x.load(Relaxed) - }); - - j1.join().unwrap(); - let b = j2.join().unwrap(); - let c = j3.join().unwrap(); - - assert_ne!((b, c), (0, 0)); -} - fn test_corr() { let x = static_atomic(0); let y = static_atomic(0); @@ -263,18 +196,91 @@ fn test_mixed_access() { assert_eq!(r2, 2); } +// The following two tests are taken from Repairing Sequential Consistency in C/C++11 +// by Lahav et al. +// https://plv.mpi-sws.org/scfix/paper.pdf + +// Test case SB +fn test_sc_store_buffering() { + let x = static_atomic(0); + let y = static_atomic(0); + + let j1 = spawn(move || { + x.store(1, SeqCst); + y.load(SeqCst) + }); + + let j2 = spawn(move || { + y.store(1, SeqCst); + x.load(SeqCst) + }); + + let a = j1.join().unwrap(); + let b = j2.join().unwrap(); + + assert_ne!((a, b), (0, 0)); +} + +// 2.2 Second Problem: SC Fences are Too Weak +// This test should pass under the C++20 model Rust is using. +// Unfortunately, Miri's weak memory emulation only follows C++11 model +// as we don't know how to correctly emulate C++20's revised SC semantics +#[allow(dead_code)] +fn test_cpp20_rwc_syncs() { + /* + int main() { + atomic_int x = 0; + atomic_int y = 0; + + {{{ x.store(1,mo_relaxed); + ||| { r1=x.load(mo_relaxed).readsvalue(1); + fence(mo_seq_cst); + r2=y.load(mo_relaxed); } + ||| { y.store(1,mo_relaxed); + fence(mo_seq_cst); + r3=x.load(mo_relaxed); } + }}} + return 0; + } + */ + let x = static_atomic(0); + let y = static_atomic(0); + + let j1 = spawn(move || { + x.store(1, Relaxed); + }); + + let j2 = spawn(move || { + reads_value(&x, 1); + fence(SeqCst); + y.load(Relaxed) + }); + + let j3 = spawn(move || { + y.store(1, Relaxed); + fence(SeqCst); + x.load(Relaxed) + }); + + j1.join().unwrap(); + let b = j2.join().unwrap(); + let c = j3.join().unwrap(); + + assert_ne!((b, c), (0, 0)); +} + pub fn main() { // TODO: does this make chances of spurious success // "sufficiently low"? This also takes a long time to run, // prehaps each function should be its own test case so they // can be run in parallel for _ in 0..500 { - test_sc_store_buffering(); test_mixed_access(); test_load_buffering_acq_rel(); test_message_passing(); test_wrc(); test_corr(); - test_rwc_syncs(); + test_sc_store_buffering(); + // test_cpp20_rwc_syncs(); } } From ecdab5ff35297e9d70647f076b3aba656c8ad850 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 1 May 2022 12:36:00 +0100 Subject: [PATCH 3199/5092] Clearer boundries between alloc metadata with multiple buffers and an individual store buffer --- src/data_race.rs | 20 ++++---- src/weak_memory.rs | 112 ++++++++++++++++++++++----------------------- 2 files changed, 64 insertions(+), 68 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index 82ee32ddee71..303cf7007e75 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -519,8 +519,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { global.sc_read(); } let mut rng = this.machine.rng.borrow_mut(); - let loaded = alloc_buffers.buffered_read( - alloc_range(base_offset, place.layout.size), + let buffer = alloc_buffers.get_store_buffer(alloc_range(base_offset, place.layout.size)); + let loaded = buffer.buffered_read( global, atomic == AtomicReadOp::SeqCst, &mut *rng, @@ -555,10 +555,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { if atomic == AtomicWriteOp::SeqCst { global.sc_write(); } - let size = dest.layout.size; - alloc_buffers.buffered_write( + let mut buffer = alloc_buffers.get_store_buffer_mut(alloc_range(base_offset, dest.layout.size)); + buffer.buffered_write( val, - alloc_range(base_offset, size), global, atomic == AtomicWriteOp::SeqCst, )?; @@ -708,7 +707,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { if global.multi_threaded.get() { - alloc_buffers.read_from_last_store(alloc_range(base_offset, size), global); + let buffer = alloc_buffers.get_store_buffer(alloc_range(base_offset, size)); + buffer.read_from_last_store(global); } } } @@ -735,10 +735,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { global.sc_read(); global.sc_write(); } - let size = place.layout.size; - let range = alloc_range(base_offset, size); - alloc_buffers.read_from_last_store(range, global); - alloc_buffers.buffered_write(new_val, range, global, atomic == AtomicRwOp::SeqCst)?; + let range = alloc_range(base_offset, place.layout.size); + let mut buffer = alloc_buffers.get_store_buffer_mut(range); + buffer.read_from_last_store(global); + buffer.buffered_write(new_val, global, atomic == AtomicRwOp::SeqCst)?; } Ok(()) } diff --git a/src/weak_memory.rs b/src/weak_memory.rs index c82a31d0a89c..2cf9a98b1335 100644 --- a/src/weak_memory.rs +++ b/src/weak_memory.rs @@ -53,76 +53,20 @@ impl StoreBufferAlloc { } /// Gets a store buffer associated with an atomic object in this allocation - fn get_store_buffer(&self, range: AllocRange) -> Ref<'_, StoreBuffer> { + pub fn get_store_buffer(&self, range: AllocRange) -> Ref<'_, StoreBuffer> { Ref::map(self.store_buffer.borrow(), |range_map| { let (.., store_buffer) = range_map.iter(range.start, range.size).next().unwrap(); store_buffer }) } - fn get_store_buffer_mut(&self, range: AllocRange) -> RefMut<'_, StoreBuffer> { + pub fn get_store_buffer_mut(&self, range: AllocRange) -> RefMut<'_, StoreBuffer> { RefMut::map(self.store_buffer.borrow_mut(), |range_map| { let (.., store_buffer) = range_map.iter_mut(range.start, range.size).next().unwrap(); store_buffer }) } - /// Reads from the last store in modification order - pub fn read_from_last_store<'tcx>(&self, range: AllocRange, global: &GlobalState) { - let store_buffer = self.get_store_buffer(range); - let store_elem = store_buffer.buffer.back(); - if let Some(store_elem) = store_elem { - let (index, clocks) = global.current_thread_state(); - store_elem.load_impl(index, &clocks); - } - } - - pub fn buffered_read<'tcx>( - &self, - range: AllocRange, - global: &GlobalState, - is_seqcst: bool, - rng: &mut (impl rand::Rng + ?Sized), - validate: impl FnOnce() -> InterpResult<'tcx>, - ) -> InterpResult<'tcx, Option>> { - // Having a live borrow to store_buffer while calling validate_atomic_load is fine - // because the race detector doesn't touch store_buffer - let store_buffer = self.get_store_buffer(range); - - let store_elem = { - // The `clocks` we got here must be dropped before calling validate_atomic_load - // as the race detector will update it - let (.., clocks) = global.current_thread_state(); - // Load from a valid entry in the store buffer - store_buffer.fetch_store(is_seqcst, &clocks, &mut *rng) - }; - - // Unlike in write_scalar_atomic, thread clock updates have to be done - // after we've picked a store element from the store buffer, as presented - // in ATOMIC LOAD rule of the paper. This is because fetch_store - // requires access to ThreadClockSet.clock, which is updated by the race detector - validate()?; - - let loaded = store_elem.map(|store_elem| { - let (index, clocks) = global.current_thread_state(); - store_elem.load_impl(index, &clocks) - }); - Ok(loaded) - } - - pub fn buffered_write<'tcx>( - &mut self, - val: ScalarMaybeUninit, - range: AllocRange, - global: &GlobalState, - is_seqcst: bool, - ) -> InterpResult<'tcx> { - let (index, clocks) = global.current_thread_state(); - - let mut store_buffer = self.get_store_buffer_mut(range); - store_buffer.store_impl(val, index, &clocks.clock, is_seqcst); - Ok(()) - } } const STORE_BUFFER_LIMIT: usize = 128; @@ -141,6 +85,58 @@ impl Default for StoreBuffer { } impl<'mir, 'tcx: 'mir> StoreBuffer { + /// Reads from the last store in modification order + pub fn read_from_last_store(&self, global: &GlobalState) { + let store_elem = self.buffer.back(); + if let Some(store_elem) = store_elem { + let (index, clocks) = global.current_thread_state(); + store_elem.load_impl(index, &clocks); + } + } + + pub fn buffered_read( + &self, + global: &GlobalState, + is_seqcst: bool, + rng: &mut (impl rand::Rng + ?Sized), + validate: impl FnOnce() -> InterpResult<'tcx>, + ) -> InterpResult<'tcx, Option>> { + // Having a live borrow to store_buffer while calling validate_atomic_load is fine + // because the race detector doesn't touch store_buffer + + let store_elem = { + // The `clocks` we got here must be dropped before calling validate_atomic_load + // as the race detector will update it + let (.., clocks) = global.current_thread_state(); + // Load from a valid entry in the store buffer + self.fetch_store(is_seqcst, &clocks, &mut *rng) + }; + + // Unlike in write_scalar_atomic, thread clock updates have to be done + // after we've picked a store element from the store buffer, as presented + // in ATOMIC LOAD rule of the paper. This is because fetch_store + // requires access to ThreadClockSet.clock, which is updated by the race detector + validate()?; + + let loaded = store_elem.map(|store_elem| { + let (index, clocks) = global.current_thread_state(); + store_elem.load_impl(index, &clocks) + }); + Ok(loaded) + } + + pub fn buffered_write( + &mut self, + val: ScalarMaybeUninit, + global: &GlobalState, + is_seqcst: bool, + ) -> InterpResult<'tcx> { + let (index, clocks) = global.current_thread_state(); + + self.store_impl(val, index, &clocks.clock, is_seqcst); + Ok(()) + } + /// Selects a valid store element in the buffer. /// The buffer does not contain the value used to initialise the atomic object /// so a fresh atomic object has an empty store buffer until an explicit store. From 53f4887659fd587ca551db664c317fb15998dfd0 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Fri, 6 May 2022 23:46:29 +0100 Subject: [PATCH 3200/5092] Use a new AllocationMap to store store buffers in the same allocation --- src/allocation_map.rs | 272 ++++++++++++++++++++++++++++++++++++++++++ src/data_race.rs | 26 ++-- src/lib.rs | 1 + src/machine.rs | 8 +- src/weak_memory.rs | 74 +++++++++--- 5 files changed, 342 insertions(+), 39 deletions(-) create mode 100644 src/allocation_map.rs diff --git a/src/allocation_map.rs b/src/allocation_map.rs new file mode 100644 index 000000000000..6c14ce165407 --- /dev/null +++ b/src/allocation_map.rs @@ -0,0 +1,272 @@ +//! Implements a map from allocation ranges to data. +//! This is somewhat similar to RangeMap, but the ranges +//! and data are discrete and non-splittable. An allocation in the +//! map will always have the same range until explicitly removed + +use rustc_target::abi::Size; +use std::ops::{Index, IndexMut, Range}; + +use rustc_const_eval::interpret::AllocRange; + +#[derive(Clone, Debug)] +struct Elem { + /// The range covered by this element; never empty. + range: AllocRange, + /// The data stored for this element. + data: T, +} + +/// Index of an allocation within the map +type Position = usize; + +#[derive(Clone, Debug)] +pub struct AllocationMap { + v: Vec>, +} + +#[derive(Clone, Debug, PartialEq)] +pub enum AccessType { + /// The access perfectly overlaps (same offset and range) with the exsiting allocation + PerfectlyOverlapping(Position), + /// The access does not touch any exising allocation + Empty(Position), + /// The access overlaps with one or more existing allocations + ImperfectlyOverlapping(Range), +} + +impl AllocationMap { + pub fn new() -> Self { + Self { v: Vec::new() } + } + + /// Finds the position of the allocation containing the given offset. If the offset is not + /// in an existing allocation, then returns Err containing the position + /// where such allocation should be inserted + fn find_offset(&self, offset: Size) -> Result { + // We do a binary search. + let mut left = 0usize; // inclusive + let mut right = self.v.len(); // exclusive + loop { + if left == right { + // No element contains the given offset. But the + // index is where such element should be placed at. + return Err(left); + } + let candidate = left.checked_add(right).unwrap() / 2; + let elem = &self.v[candidate]; + if offset < elem.range.start { + // We are too far right (offset is further left). + debug_assert!(candidate < right); // we are making progress + right = candidate; + } else if offset >= elem.range.end() { + // We are too far left (offset is further right). + debug_assert!(candidate >= left); // we are making progress + left = candidate + 1; + } else { + // This is it! + return Ok(candidate); + } + } + } + + /// Determines whether a given access on `range` overlaps with + /// an existing allocation + pub fn access_type(&self, range: AllocRange) -> AccessType { + match self.find_offset(range.start) { + Ok(index) => { + // Start of the range belongs to an existing object, now let's check the overlapping situation + let elem = &self.v[index]; + // FIXME: derive Eq for AllocRange in rustc + if elem.range.start == range.start && elem.range.size == range.size { + // Happy case: perfectly overlapping access + AccessType::PerfectlyOverlapping(index) + } else { + // FIXME: add a last() method to AllocRange that returns the last inclusive offset (end() is exclusive) + let end_index = match self.find_offset(range.end() - Size::from_bytes(1)) { + // If the end lands in an existing object, add one to get the exclusive index + Ok(inclusive) => inclusive + 1, + Err(exclusive) => exclusive, + }; + + AccessType::ImperfectlyOverlapping(index..end_index) + } + } + Err(index) => { + // Start of the range doesn't belong to an existing object + match self.find_offset(range.end() - Size::from_bytes(1)) { + // Neither does the end + Err(end_index) => + if index == end_index { + // There's nothing between the start and the end, so the range thing is empty + AccessType::Empty(index) + } else { + // Otherwise we have entirely covered an existing object + AccessType::ImperfectlyOverlapping(index..end_index) + }, + // Otherwise at least part of it overlaps with something else + Ok(end_index) => AccessType::ImperfectlyOverlapping(index..end_index + 1), + } + } + } + } + + /// Inserts an object and its occupied range at given position + pub fn insert(&mut self, index: Position, range: AllocRange, data: T) { + self.v.insert(index, Elem { range, data }); + // If we aren't the first element, then our start must be greater than the preivous element's end + if index > 0 { + debug_assert!(self.v[index - 1].range.end() <= range.start); + } + // If we aren't the last element, then our end must be smaller than next element's start + if index < self.v.len() - 1 { + debug_assert!(range.end() <= self.v[index + 1].range.start); + } + } + + /// Removes an object at given position + pub fn remove(&mut self, index: Position) -> T { + self.v.remove(index).data + } +} + +impl Index for AllocationMap { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self.v[index].data + } +} + +impl IndexMut for AllocationMap { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + &mut self.v[index].data + } +} + +#[cfg(test)] +mod tests { + use rustc_const_eval::interpret::alloc_range; + + use super::*; + + #[test] + fn empty_map() { + // FIXME: make Size::from_bytes const + let four = Size::from_bytes(4); + let map = AllocationMap::<()>::new(); + + // Correctly tells where we should insert the first element (at index 0) + assert_eq!(map.find_offset(Size::from_bytes(3)), Err(0)); + + // Correctly tells the access type along with the supposed index + assert_eq!(map.access_type(alloc_range(Size::ZERO, four)), AccessType::Empty(0)); + } + + #[test] + #[should_panic] + fn no_overlapping_inserts() { + let four = Size::from_bytes(4); + + let mut map = AllocationMap::<&str>::new(); + + // |_|_|_|_|#|#|#|#|_|_|_|_|... + // 0 1 2 3 4 5 6 7 8 9 a b c d + map.insert(0, alloc_range(four, four), "#"); + // |_|_|_|_|#|#|#|#|_|_|_|_|... + // 0 ^ ^ ^ ^ 5 6 7 8 9 a b c d + map.insert(0, alloc_range(Size::from_bytes(1), four), "@"); + } + + #[test] + fn boundaries() { + let four = Size::from_bytes(4); + + let mut map = AllocationMap::<&str>::new(); + + // |#|#|#|#|_|_|... + // 0 1 2 3 4 5 + map.insert(0, alloc_range(Size::ZERO, four), "#"); + // |#|#|#|#|_|_|... + // 0 1 2 3 ^ 5 + assert_eq!(map.find_offset(four), Err(1)); + // |#|#|#|#|_|_|_|_|_|... + // 0 1 2 3 ^ ^ ^ ^ 8 + assert_eq!(map.access_type(alloc_range(four, four)), AccessType::Empty(1)); + + let eight = Size::from_bytes(8); + // |#|#|#|#|_|_|_|_|@|@|@|@|_|_|... + // 0 1 2 3 4 5 6 7 8 9 a b c d + map.insert(1, alloc_range(eight, four), "@"); + // |#|#|#|#|_|_|_|_|@|@|@|@|_|_|... + // 0 1 2 3 4 5 6 ^ 8 9 a b c d + assert_eq!(map.find_offset(Size::from_bytes(7)), Err(1)); + // |#|#|#|#|_|_|_|_|@|@|@|@|_|_|... + // 0 1 2 3 ^ ^ ^ ^ 8 9 a b c d + assert_eq!(map.access_type(alloc_range(four, four)), AccessType::Empty(1)); + } + + #[test] + fn perfectly_overlapping() { + let four = Size::from_bytes(4); + + let mut map = AllocationMap::<&str>::new(); + + // |#|#|#|#|_|_|... + // 0 1 2 3 4 5 + map.insert(0, alloc_range(Size::ZERO, four), "#"); + // |#|#|#|#|_|_|... + // ^ ^ ^ ^ 4 5 + assert_eq!(map.find_offset(Size::ZERO), Ok(0)); + assert_eq!( + map.access_type(alloc_range(Size::ZERO, four)), + AccessType::PerfectlyOverlapping(0) + ); + + // |#|#|#|#|@|@|@|@|_|... + // 0 1 2 3 4 5 6 7 8 + map.insert(1, alloc_range(four, four), "@"); + // |#|#|#|#|@|@|@|@|_|... + // 0 1 2 3 ^ ^ ^ ^ 8 + assert_eq!(map.find_offset(four), Ok(1)); + assert_eq!(map.access_type(alloc_range(four, four)), AccessType::PerfectlyOverlapping(1)); + } + + #[test] + fn straddling() { + let four = Size::from_bytes(4); + + let mut map = AllocationMap::<&str>::new(); + + // |_|_|_|_|#|#|#|#|_|_|_|_|... + // 0 1 2 3 4 5 6 7 8 9 a b c d + map.insert(0, alloc_range(four, four), "#"); + // |_|_|_|_|#|#|#|#|_|_|_|_|... + // 0 1 ^ ^ ^ ^ 6 7 8 9 a b c d + assert_eq!( + map.access_type(alloc_range(Size::from_bytes(2), four)), + AccessType::ImperfectlyOverlapping(0..1) + ); + // |_|_|_|_|#|#|#|#|_|_|_|_|... + // 0 1 2 3 4 5 ^ ^ ^ ^ a b c d + assert_eq!( + map.access_type(alloc_range(Size::from_bytes(6), four)), + AccessType::ImperfectlyOverlapping(0..1) + ); + // |_|_|_|_|#|#|#|#|_|_|_|_|... + // 0 1 ^ ^ ^ ^ ^ ^ ^ ^ a b c d + assert_eq!( + map.access_type(alloc_range(Size::from_bytes(2), Size::from_bytes(8))), + AccessType::ImperfectlyOverlapping(0..1) + ); + + // |_|_|_|_|#|#|#|#|_|_|@|@|_|_|... + // 0 1 2 3 4 5 6 7 8 9 a b c d + map.insert(1, alloc_range(Size::from_bytes(10), Size::from_bytes(2)), "@"); + // |_|_|_|_|#|#|#|#|_|_|@|@|_|_|... + // 0 1 2 3 4 5 ^ ^ ^ ^ ^ ^ ^ ^ + assert_eq!( + map.access_type(alloc_range(Size::from_bytes(6), Size::from_bytes(8))), + AccessType::ImperfectlyOverlapping(0..2) + ); + } +} diff --git a/src/data_race.rs b/src/data_race.rs index 303cf7007e75..d9bfbc1bdb5a 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -519,7 +519,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { global.sc_read(); } let mut rng = this.machine.rng.borrow_mut(); - let buffer = alloc_buffers.get_store_buffer(alloc_range(base_offset, place.layout.size)); + let buffer = + alloc_buffers.get_store_buffer(alloc_range(base_offset, place.layout.size)); let loaded = buffer.buffered_read( global, atomic == AtomicReadOp::SeqCst, @@ -555,12 +556,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { if atomic == AtomicWriteOp::SeqCst { global.sc_write(); } - let mut buffer = alloc_buffers.get_store_buffer_mut(alloc_range(base_offset, dest.layout.size)); - buffer.buffered_write( - val, - global, - atomic == AtomicWriteOp::SeqCst, - )?; + let buffer = + alloc_buffers.get_store_buffer_mut(alloc_range(base_offset, dest.layout.size)); + buffer.buffered_write(val, global, atomic == AtomicWriteOp::SeqCst)?; } Ok(()) @@ -624,17 +622,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let lt = this.binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar()?.to_bool()?; let new_val = if min { - if lt { - &old - } else { - &rhs - } + if lt { &old } else { &rhs } } else { - if lt { - &rhs - } else { - &old - } + if lt { &rhs } else { &old } }; this.allow_data_races_mut(|this| this.write_immediate(**new_val, &(*place).into()))?; @@ -736,7 +726,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { global.sc_write(); } let range = alloc_range(base_offset, place.layout.size); - let mut buffer = alloc_buffers.get_store_buffer_mut(range); + let buffer = alloc_buffers.get_store_buffer_mut(range); buffer.read_from_last_store(global); buffer.buffered_write(new_val, global, atomic == AtomicRwOp::SeqCst)?; } diff --git a/src/lib.rs b/src/lib.rs index 06ab2fabab04..3270a57c4964 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,6 +31,7 @@ extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; +mod allocation_map; mod data_race; mod diagnostics; mod eval; diff --git a/src/machine.rs b/src/machine.rs index aa2a930ccd25..ca7fff7b08b9 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -636,13 +636,17 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { let buffer_alloc = if ecx.machine.weak_memory { // FIXME: if this is an atomic obejct, we want to supply its initial value // while allocating the store buffer here. - Some(weak_memory::AllocExtra::new_allocation(alloc.size())) + Some(weak_memory::AllocExtra::new_allocation()) } else { None }; let alloc: Allocation = alloc.convert_tag_add_extra( &ecx.tcx, - AllocExtra { stacked_borrows: stacks, data_race: race_alloc, weak_memory: buffer_alloc }, + AllocExtra { + stacked_borrows: stacks, + data_race: race_alloc, + weak_memory: buffer_alloc, + }, |ptr| Evaluator::tag_alloc_base_pointer(ecx, ptr), ); Cow::Owned(alloc) diff --git a/src/weak_memory.rs b/src/weak_memory.rs index 2cf9a98b1335..34c669239d5b 100644 --- a/src/weak_memory.rs +++ b/src/weak_memory.rs @@ -12,7 +12,7 @@ // load by each thread. This optimisation is done in tsan11 // (https://github.com/ChrisLidbury/tsan11/blob/ecbd6b81e9b9454e01cba78eb9d88684168132c7/lib/tsan/rtl/tsan_relaxed.h#L35-L37) // and here. -// +// // 3. §4.5 of the paper wants an SC store to mark all existing stores in the buffer that happens before it // as SC. This is not done in the operational semantics but implemented correctly in tsan11 // (https://github.com/ChrisLidbury/tsan11/blob/ecbd6b81e9b9454e01cba78eb9d88684168132c7/lib/tsan/rtl/tsan_relaxed.cc#L160-L167) @@ -25,48 +25,84 @@ // and here. use std::{ - cell::{Ref, RefCell, RefMut}, + cell::{Ref, RefCell}, collections::VecDeque, }; use rustc_const_eval::interpret::{AllocRange, InterpResult, ScalarMaybeUninit}; use rustc_data_structures::fx::FxHashMap; -use rustc_target::abi::Size; use crate::{ + allocation_map::{AccessType, AllocationMap}, data_race::{GlobalState, ThreadClockSet}, - RangeMap, Tag, VClock, VTimestamp, VectorIdx, + Tag, VClock, VTimestamp, VectorIdx, }; pub type AllocExtra = StoreBufferAlloc; + #[derive(Debug, Clone)] pub struct StoreBufferAlloc { /// Store buffer of each atomic object in this allocation - // Load may modify a StoreBuffer to record the loading thread's - // timestamp so we need interior mutability here. - store_buffer: RefCell>, + // Behind a RefCell because we need to allocate/remove on read access + store_buffer: RefCell>, } impl StoreBufferAlloc { - pub fn new_allocation(len: Size) -> Self { - Self { store_buffer: RefCell::new(RangeMap::new(len, StoreBuffer::default())) } + pub fn new_allocation() -> Self { + Self { store_buffer: RefCell::new(AllocationMap::new()) } } /// Gets a store buffer associated with an atomic object in this allocation pub fn get_store_buffer(&self, range: AllocRange) -> Ref<'_, StoreBuffer> { - Ref::map(self.store_buffer.borrow(), |range_map| { - let (.., store_buffer) = range_map.iter(range.start, range.size).next().unwrap(); - store_buffer - }) + let access_type = self.store_buffer.borrow().access_type(range); + let index = match access_type { + AccessType::PerfectlyOverlapping(index) => index, + AccessType::Empty(index) => { + // First atomic access on this range, allocate a new StoreBuffer + let mut buffer = self.store_buffer.borrow_mut(); + buffer.insert(index, range, StoreBuffer::default()); + index + } + AccessType::ImperfectlyOverlapping(index_range) => { + // Accesses that imperfectly overlaps with existing atomic objects + // do not have well-defined behaviours. But we don't throw a UB here + // because we have (or will) checked that all bytes in the current + // access are non-racy. + // The behaviour here is that we delete all the existing objects this + // access touches, and allocate a new and empty one for the exact range. + // A read on an empty buffer returns None, which means the program will + // observe the latest value in modification order at every byte. + let mut buffer = self.store_buffer.borrow_mut(); + for index in index_range.clone() { + buffer.remove(index); + } + buffer.insert(index_range.start, range, StoreBuffer::default()); + index_range.start + } + }; + Ref::map(self.store_buffer.borrow(), |buffer| &buffer[index]) } - pub fn get_store_buffer_mut(&self, range: AllocRange) -> RefMut<'_, StoreBuffer> { - RefMut::map(self.store_buffer.borrow_mut(), |range_map| { - let (.., store_buffer) = range_map.iter_mut(range.start, range.size).next().unwrap(); - store_buffer - }) + /// Gets a mutable store buffer associated with an atomic object in this allocation + pub fn get_store_buffer_mut(&mut self, range: AllocRange) -> &mut StoreBuffer { + let buffer = self.store_buffer.get_mut(); + let access_type = buffer.access_type(range); + let index = match access_type { + AccessType::PerfectlyOverlapping(index) => index, + AccessType::Empty(index) => { + buffer.insert(index, range, StoreBuffer::default()); + index + } + AccessType::ImperfectlyOverlapping(index_range) => { + for index in index_range.clone() { + buffer.remove(index); + } + buffer.insert(index_range.start, range, StoreBuffer::default()); + index_range.start + } + }; + &mut buffer[index] } - } const STORE_BUFFER_LIMIT: usize = 128; From a71b10381e1e956e87bcd75ffc5ec7273680aba6 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sat, 7 May 2022 00:31:17 +0100 Subject: [PATCH 3201/5092] Add imperfectly overlapping test --- tests/run-pass/concurrency/weak_memory.rs | 24 ++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/concurrency/weak_memory.rs b/tests/run-pass/concurrency/weak_memory.rs index efbbc45909cf..90820d4348df 100644 --- a/tests/run-pass/concurrency/weak_memory.rs +++ b/tests/run-pass/concurrency/weak_memory.rs @@ -28,9 +28,10 @@ // M. Batty, S. Owens, S. Sarkar, P. Sewell and T. Weber, // "Mathematizing C++ concurrency", ACM SIGPLAN Notices, vol. 46, no. 1, pp. 55-66, 2011. // Available: https://ss265.host.cs.st-andrews.ac.uk/papers/n3132.pdf. +#![feature(atomic_from_mut)] use std::sync::atomic::Ordering::*; -use std::sync::atomic::{fence, AtomicUsize}; +use std::sync::atomic::{fence, AtomicU16, AtomicU32, AtomicUsize}; use std::thread::{spawn, yield_now}; #[derive(Copy, Clone)] @@ -196,6 +197,26 @@ fn test_mixed_access() { assert_eq!(r2, 2); } +// Strictly speaking, atomic accesses that imperfectly overlap with existing +// atomic objects are UB. Nonetheless we'd like to provide a sane value when +// the access is not racy. +fn test_imperfectly_overlapping_access() { + let mut qword = AtomicU32::new(42); + assert_eq!(qword.load(Relaxed), 42); + qword.store(u32::to_be(0xabbafafa), Relaxed); + + let qword_mut = qword.get_mut(); + + let dwords_mut = unsafe { std::mem::transmute::<&mut u32, &mut [u16; 2]>(qword_mut) }; + + let (hi_mut, lo_mut) = dwords_mut.split_at_mut(1); + + let (hi, lo) = (AtomicU16::from_mut(&mut hi_mut[0]), AtomicU16::from_mut(&mut lo_mut[0])); + + assert_eq!(u16::from_be(hi.load(Relaxed)), 0xabba); + assert_eq!(u16::from_be(lo.load(Relaxed)), 0xfafa); +} + // The following two tests are taken from Repairing Sequential Consistency in C/C++11 // by Lahav et al. // https://plv.mpi-sws.org/scfix/paper.pdf @@ -270,6 +291,7 @@ fn test_cpp20_rwc_syncs() { } pub fn main() { + test_imperfectly_overlapping_access(); // TODO: does this make chances of spurious success // "sufficiently low"? This also takes a long time to run, // prehaps each function should be its own test case so they From bf7fe68fba3a3bbfaef7fdbace268d0001e038cf Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sat, 7 May 2022 00:54:54 +0100 Subject: [PATCH 3202/5092] Add -Zmiri-disable-weak-memory-emulation to README --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a55ebcb125b3..e5c2465944e6 100644 --- a/README.md +++ b/README.md @@ -317,11 +317,13 @@ to Miri failing to detect cases of undefined behavior in a program. can focus on other failures, but it means Miri can miss bugs in your program. Using this flag is **unsound**. * `-Zmiri-disable-data-race-detector` disables checking for data races. Using - this flag is **unsound**. + this flag is **unsound**. This implies `-Zmiri-disable-weak-memory-emulation`. * `-Zmiri-disable-stacked-borrows` disables checking the experimental [Stacked Borrows] aliasing rules. This can make Miri run faster, but it also means no aliasing violations will be detected. Using this flag is **unsound** (but the affected soundness rules are experimental). +* `-Zmiri-disable-weak-memory-emulation` disables the emulation of some C++11 weak + memory effects. * `-Zmiri-disable-validation` disables enforcing validity invariants, which are enforced by default. This is mostly useful to focus on other failures (such as out-of-bounds accesses) first. Setting this flag means Miri can miss bugs From 11ca975cd83351aae3b113ceb754dde4a304a6b5 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sat, 7 May 2022 01:07:16 +0100 Subject: [PATCH 3203/5092] Move type definitions together and clarify fetch_store on empty buffer --- src/weak_memory.rs | 59 +++++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/src/weak_memory.rs b/src/weak_memory.rs index 34c669239d5b..0d892a5b38db 100644 --- a/src/weak_memory.rs +++ b/src/weak_memory.rs @@ -40,6 +40,8 @@ use crate::{ pub type AllocExtra = StoreBufferAlloc; +const STORE_BUFFER_LIMIT: usize = 128; + #[derive(Debug, Clone)] pub struct StoreBufferAlloc { /// Store buffer of each atomic object in this allocation @@ -47,6 +49,31 @@ pub struct StoreBufferAlloc { store_buffer: RefCell>, } +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct StoreBuffer { + // Stores to this location in modification order + buffer: VecDeque, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct StoreElement { + /// The identifier of the vector index, corresponding to a thread + /// that performed the store. + store_index: VectorIdx, + + /// Whether this store is SC. + is_seqcst: bool, + + /// The timestamp of the storing thread when it performed the store + timestamp: VTimestamp, + /// The value of this store + val: ScalarMaybeUninit, + + /// Timestamp of first loads from this store element by each thread + /// Behind a RefCell to keep load op take &self + loads: RefCell>, +} + impl StoreBufferAlloc { pub fn new_allocation() -> Self { Self { store_buffer: RefCell::new(AllocationMap::new()) } @@ -105,13 +132,6 @@ impl StoreBufferAlloc { } } -const STORE_BUFFER_LIMIT: usize = 128; -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct StoreBuffer { - // Stores to this location in modification order - buffer: VecDeque, -} - impl Default for StoreBuffer { fn default() -> Self { let mut buffer = VecDeque::new(); @@ -175,7 +195,11 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { /// Selects a valid store element in the buffer. /// The buffer does not contain the value used to initialise the atomic object - /// so a fresh atomic object has an empty store buffer until an explicit store. + /// so a fresh atomic object has an empty store buffer and this function + /// will return `None`. In this case, the caller should ensure that the non-buffered + /// value from `MiriEvalContext::read_scalar()` is observed by the program, which is + /// the initial value of the atomic object. `MiriEvalContext::read_scalar()` is always + /// the latest value in modification order so it is always correct to be observed by any thread. fn fetch_store( &self, is_seqcst: bool, @@ -294,25 +318,6 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { } } -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct StoreElement { - /// The identifier of the vector index, corresponding to a thread - /// that performed the store. - store_index: VectorIdx, - - /// Whether this store is SC. - is_seqcst: bool, - - /// The timestamp of the storing thread when it performed the store - timestamp: VTimestamp, - /// The value of this store - val: ScalarMaybeUninit, - - /// Timestamp of first loads from this store element by each thread - /// Behind a RefCell to keep load op take &self - loads: RefCell>, -} - impl StoreElement { /// ATOMIC LOAD IMPL in the paper /// Unlike the operational semantics in the paper, we don't need to keep track From 32627d5abb8791d2de10199964128ea8238d5c2b Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sat, 7 May 2022 01:46:19 +0100 Subject: [PATCH 3204/5092] Disable weak memory emulation on scheduler-dependent data race tests --- tests/fail/data_race/alloc_read_race.rs | 1 + tests/fail/data_race/alloc_write_race.rs | 1 + tests/fail/data_race/dealloc_read_race_stack.rs | 2 +- tests/fail/data_race/dealloc_write_race_stack.rs | 2 +- tests/fail/data_race/read_write_race_stack.rs | 2 +- tests/fail/data_race/relax_acquire_race.rs | 1 + tests/fail/data_race/release_seq_race.rs | 2 +- tests/fail/data_race/release_seq_race_same_thread.rs | 2 +- tests/fail/data_race/rmw_race.rs | 1 + tests/fail/data_race/write_write_race_stack.rs | 2 +- tests/pass/concurrency/data_race.rs | 1 + 11 files changed, 11 insertions(+), 6 deletions(-) diff --git a/tests/fail/data_race/alloc_read_race.rs b/tests/fail/data_race/alloc_read_race.rs index 093c9024f202..2ddbb657245a 100644 --- a/tests/fail/data_race/alloc_read_race.rs +++ b/tests/fail/data_race/alloc_read_race.rs @@ -1,4 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-weak-memory-emulation #![feature(new_uninit)] use std::thread::spawn; diff --git a/tests/fail/data_race/alloc_write_race.rs b/tests/fail/data_race/alloc_write_race.rs index becebe6a122a..d32eb5567606 100644 --- a/tests/fail/data_race/alloc_write_race.rs +++ b/tests/fail/data_race/alloc_write_race.rs @@ -1,4 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-weak-memory-emulation #![feature(new_uninit)] use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_read_race_stack.rs b/tests/fail/data_race/dealloc_read_race_stack.rs index 6b573121e599..b70db5f4ac4b 100644 --- a/tests/fail/data_race/dealloc_read_race_stack.rs +++ b/tests/fail/data_race/dealloc_read_race_stack.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation +// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation use std::thread::{spawn, sleep}; use std::ptr::null_mut; diff --git a/tests/fail/data_race/dealloc_write_race_stack.rs b/tests/fail/data_race/dealloc_write_race_stack.rs index 34a16b00b83d..f2b49fc5f344 100644 --- a/tests/fail/data_race/dealloc_write_race_stack.rs +++ b/tests/fail/data_race/dealloc_write_race_stack.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation +// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation use std::thread::{spawn, sleep}; use std::ptr::null_mut; diff --git a/tests/fail/data_race/read_write_race_stack.rs b/tests/fail/data_race/read_write_race_stack.rs index 5a1c0a4b6d6d..9edeed0af652 100644 --- a/tests/fail/data_race/read_write_race_stack.rs +++ b/tests/fail/data_race/read_write_race_stack.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 +// compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 -Zmiri-disable-weak-memory-emulation // Note: mir-opt-level set to 0 to prevent the read of stack_var in thread 1 // from being optimized away and preventing the detection of the data-race. diff --git a/tests/fail/data_race/relax_acquire_race.rs b/tests/fail/data_race/relax_acquire_race.rs index 8b8616431f37..20e63dc4b171 100644 --- a/tests/fail/data_race/relax_acquire_race.rs +++ b/tests/fail/data_race/relax_acquire_race.rs @@ -1,4 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-weak-memory-emulation use std::thread::spawn; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/release_seq_race.rs b/tests/fail/data_race/release_seq_race.rs index 29c428b388d4..6ff84aa04b26 100644 --- a/tests/fail/data_race/release_seq_race.rs +++ b/tests/fail/data_race/release_seq_race.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation +// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation use std::thread::{spawn, sleep}; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/release_seq_race_same_thread.rs b/tests/fail/data_race/release_seq_race_same_thread.rs index 54b9f49937c8..1245fb96f497 100644 --- a/tests/fail/data_race/release_seq_race_same_thread.rs +++ b/tests/fail/data_race/release_seq_race_same_thread.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation +// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation use std::thread::spawn; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/rmw_race.rs b/tests/fail/data_race/rmw_race.rs index fcf683a65d8e..c968c83422c0 100644 --- a/tests/fail/data_race/rmw_race.rs +++ b/tests/fail/data_race/rmw_race.rs @@ -1,4 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-weak-memory-emulation use std::thread::spawn; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/write_write_race_stack.rs b/tests/fail/data_race/write_write_race_stack.rs index bfe1464cb572..daa3e5f5c478 100644 --- a/tests/fail/data_race/write_write_race_stack.rs +++ b/tests/fail/data_race/write_write_race_stack.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation +// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation use std::thread::{spawn, sleep}; use std::ptr::null_mut; diff --git a/tests/pass/concurrency/data_race.rs b/tests/pass/concurrency/data_race.rs index 2dc0ee3f8f1a..c51080f474fb 100644 --- a/tests/pass/concurrency/data_race.rs +++ b/tests/pass/concurrency/data_race.rs @@ -1,4 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-weak-memory-emulation use std::sync::atomic::{AtomicUsize, fence, Ordering}; From f729f289255bcc8d1bfad614ac74bc51d411826a Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sat, 7 May 2022 17:34:18 +0100 Subject: [PATCH 3205/5092] Move cpp20_rwc_syncs into compile-fail --- .../weak_memory/cpp20_rwc_syncs.rs | 85 +++++++++++++++++++ tests/run-pass/concurrency/weak_memory.rs | 58 +------------ 2 files changed, 86 insertions(+), 57 deletions(-) create mode 100644 tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs diff --git a/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs b/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs new file mode 100644 index 000000000000..b9e395fd7741 --- /dev/null +++ b/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs @@ -0,0 +1,85 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-ignore-leaks + +// https://plv.mpi-sws.org/scfix/paper.pdf +// 2.2 Second Problem: SC Fences are Too Weak +// This test should pass under the C++20 model Rust is using. +// Unfortunately, Miri's weak memory emulation only follows C++11 model +// as we don't know how to correctly emulate C++20's revised SC semantics, +// so we have to stick to C++11 emulation from exiting research. + +use std::sync::atomic::Ordering::*; +use std::thread::{spawn, yield_now}; +use std::sync::atomic::{fence, AtomicUsize}; + +// Spins and yields until until it reads value +fn reads_value(loc: &AtomicUsize, val: usize) -> usize { + while loc.load(Relaxed) != val { + yield_now(); + } + val +} + +// We can't create static items because we need to run each test +// multiple tests +fn static_atomic(val: usize) -> &'static AtomicUsize { + let ret = Box::leak(Box::new(AtomicUsize::new(val))); + // A workaround to put the initialisation value in the store buffer + ret.store(val, Relaxed); + ret +} + +fn test_cpp20_rwc_syncs() { + /* + int main() { + atomic_int x = 0; + atomic_int y = 0; + + {{{ x.store(1,mo_relaxed); + ||| { r1=x.load(mo_relaxed).readsvalue(1); + fence(mo_seq_cst); + r2=y.load(mo_relaxed); } + ||| { y.store(1,mo_relaxed); + fence(mo_seq_cst); + r3=x.load(mo_relaxed); } + }}} + return 0; + } + */ + let x = static_atomic(0); + let y = static_atomic(0); + + let j1 = spawn(move || { + x.store(1, Relaxed); + }); + + let j2 = spawn(move || { + reads_value(&x, 1); + fence(SeqCst); + y.load(Relaxed) + }); + + let j3 = spawn(move || { + y.store(1, Relaxed); + fence(SeqCst); + x.load(Relaxed) + }); + + j1.join().unwrap(); + let b = j2.join().unwrap(); + let c = j3.join().unwrap(); + + if (b, c) == (0, 0) { + // FIXME: the standalone compiletest-rs needs to support + // failure-status header to allow us to write assert_ne!((b, c), (0, 0)) + // https://rustc-dev-guide.rust-lang.org/tests/headers.html#miscellaneous-headers + // because panic exits with 101 but compile-rs expects 1 + let _ = unsafe { std::mem::MaybeUninit::<*const u32>::uninit().assume_init() }; //~ ERROR uninitialized + } +} + +pub fn main() { + for _ in 0..500 { + test_cpp20_rwc_syncs(); + } +} \ No newline at end of file diff --git a/tests/run-pass/concurrency/weak_memory.rs b/tests/run-pass/concurrency/weak_memory.rs index 90820d4348df..e85c2d1960c4 100644 --- a/tests/run-pass/concurrency/weak_memory.rs +++ b/tests/run-pass/concurrency/weak_memory.rs @@ -31,7 +31,7 @@ #![feature(atomic_from_mut)] use std::sync::atomic::Ordering::*; -use std::sync::atomic::{fence, AtomicU16, AtomicU32, AtomicUsize}; +use std::sync::atomic::{AtomicU16, AtomicU32, AtomicUsize}; use std::thread::{spawn, yield_now}; #[derive(Copy, Clone)] @@ -57,13 +57,6 @@ fn acquires_value(loc: &AtomicUsize, val: usize) -> usize { val } -fn reads_value(loc: &AtomicUsize, val: usize) -> usize { - while loc.load(Relaxed) != val { - yield_now(); - } - val -} - fn test_corr() { let x = static_atomic(0); let y = static_atomic(0); @@ -242,54 +235,6 @@ fn test_sc_store_buffering() { assert_ne!((a, b), (0, 0)); } -// 2.2 Second Problem: SC Fences are Too Weak -// This test should pass under the C++20 model Rust is using. -// Unfortunately, Miri's weak memory emulation only follows C++11 model -// as we don't know how to correctly emulate C++20's revised SC semantics -#[allow(dead_code)] -fn test_cpp20_rwc_syncs() { - /* - int main() { - atomic_int x = 0; - atomic_int y = 0; - - {{{ x.store(1,mo_relaxed); - ||| { r1=x.load(mo_relaxed).readsvalue(1); - fence(mo_seq_cst); - r2=y.load(mo_relaxed); } - ||| { y.store(1,mo_relaxed); - fence(mo_seq_cst); - r3=x.load(mo_relaxed); } - }}} - return 0; - } - */ - let x = static_atomic(0); - let y = static_atomic(0); - - let j1 = spawn(move || { - x.store(1, Relaxed); - }); - - let j2 = spawn(move || { - reads_value(&x, 1); - fence(SeqCst); - y.load(Relaxed) - }); - - let j3 = spawn(move || { - y.store(1, Relaxed); - fence(SeqCst); - x.load(Relaxed) - }); - - j1.join().unwrap(); - let b = j2.join().unwrap(); - let c = j3.join().unwrap(); - - assert_ne!((b, c), (0, 0)); -} - pub fn main() { test_imperfectly_overlapping_access(); // TODO: does this make chances of spurious success @@ -303,6 +248,5 @@ pub fn main() { test_wrc(); test_corr(); test_sc_store_buffering(); - // test_cpp20_rwc_syncs(); } } From 89138a67dc2b9f7ac5363bad114984cb35033158 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Tue, 10 May 2022 23:25:18 +0100 Subject: [PATCH 3206/5092] Add more top-level comments --- src/weak_memory.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/weak_memory.rs b/src/weak_memory.rs index 0d892a5b38db..fc2e220e5e51 100644 --- a/src/weak_memory.rs +++ b/src/weak_memory.rs @@ -1,6 +1,34 @@ //! Implementation of C++11-consistent weak memory emulation using store buffers //! based on Dynamic Race Detection for C++ ("the paper"): //! https://www.doc.ic.ac.uk/~afd/homepages/papers/pdfs/2017/POPL.pdf +//! +//! This implementation will never generate weak memory behaviours forbidden by the C++11 model, +//! but it is incapable of producing all possible weak behaviours allowed by the model. There are +//! certain weak behaviours observable on real hardware but not while using this. +//! +//! Note that this implementation does not take into account of C++20's memory model revision to SC accesses +//! and fences introduced by P0668 (https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0668r5.html). +//! This implementation is not fully correct under the revised C++20 model and may generate behaviours C++20 +//! disallows. +//! +//! Rust follows the full C++20 memory model (except for the Consume ordering). It is therefore +//! possible for this implementation to generate behaviours never observable when the same program is compiled and +//! run natively. Unfortunately, no literature exists at the time of writing which proposes an implementable and C++20-compatible +//! relaxed memory model that supports all atomic operation existing in Rust. The closest one is +//! A Promising Semantics for Relaxed-Memory Concurrency by Jeehoon Kang et al. (https://www.cs.tau.ac.il/~orilahav/papers/popl17.pdf) +//! However, this model lacks SC accesses and is therefore unusable by Miri (SC accesses are everywhere in library code). +//! +//! If you find anything that proposes a relaxed memory model that is C++20-consistent, supports all orderings Rust's atomic accesses +//! and fences accept, and is implementable (with operational semanitcs), please open a GitHub issue! +//! +//! One characteristic of this implementation, in contrast to some other notable operational models such as ones proposed in +//! Taming Release-Acquire Consistency by Ori Lahav et al. (https://plv.mpi-sws.org/sra/paper.pdf) or Promising Semantics noted above, +//! is that this implementation does not require each thread to hold an isolated view of the entire memory. Here, store buffers are per-location +//! and shared across all threads. This is more memory efficient but does require store elements (representing writes to a location) to record +//! information about reads, whereas in the other two models it is the other way round: reads points to the write it got its value from. +//! Additionally, writes in our implementation do not have globally unique timestamps attached. In the other two models this timestamp is +//! used to make sure a value in a thread's view is not overwritten by a write that occured earlier than the one in the existing view. +//! In our implementation, this is detected using read information attached to store elements, as there is no data strucutre representing reads. // Our and the author's own implementation (tsan11) of the paper have some deviations from the provided operational semantics in §5.3: // 1. In the operational semantics, store elements keep a copy of the atomic object's vector clock (AtomicCellClocks::sync_vector in miri), @@ -40,6 +68,10 @@ use crate::{ pub type AllocExtra = StoreBufferAlloc; +// Each store buffer must be bounded otherwise it will grow indefinitely. +// However, bounding the store buffer means restricting the amount of weak +// behaviours observable. The author picked 128 as a good tradeoff +// so we follow them here. const STORE_BUFFER_LIMIT: usize = 128; #[derive(Debug, Clone)] From 62b514e23571beb0f051b4927e08a31460d324ac Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Tue, 10 May 2022 23:34:38 +0100 Subject: [PATCH 3207/5092] Update README --- README.md | 15 +++++++++------ src/weak_memory.rs | 10 +++++----- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index e5c2465944e6..ece45fca128c 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,8 @@ for example: or an invalid enum discriminant) * **Experimental**: Violations of the [Stacked Borrows] rules governing aliasing for reference types -* **Experimental**: Data races (but no weak memory effects) +* **Experimental**: Data races +* **Experimental**: Weak memory emulation On top of that, Miri will also tell you about memory leaks: when there is memory still allocated at the end of the execution, and that memory is not reachable @@ -61,9 +62,11 @@ in your program, and cannot run all programs: not support networking. System API support varies between targets; if you run on Windows it is a good idea to use `--target x86_64-unknown-linux-gnu` to get better support. -* Threading support is not finished yet. E.g., weak memory effects are not - emulated and spin loops (without syscalls) just loop forever. There is no - threading support on Windows. +* Threading support is not finished yet. E.g. spin loops (without syscalls) just + loop forever. There is no threading support on Windows. +* Weak memory emulation may produce weak behaivours unobservable by compiled + programs running on real hardware when `SeqCst` fences are used, and it cannot + produce all behaviors possibly observable on real hardware. [rust]: https://www.rust-lang.org/ [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md @@ -322,13 +325,13 @@ to Miri failing to detect cases of undefined behavior in a program. [Stacked Borrows] aliasing rules. This can make Miri run faster, but it also means no aliasing violations will be detected. Using this flag is **unsound** (but the affected soundness rules are experimental). -* `-Zmiri-disable-weak-memory-emulation` disables the emulation of some C++11 weak - memory effects. * `-Zmiri-disable-validation` disables enforcing validity invariants, which are enforced by default. This is mostly useful to focus on other failures (such as out-of-bounds accesses) first. Setting this flag means Miri can miss bugs in your program. However, this can also help to make Miri run faster. Using this flag is **unsound**. +* `-Zmiri-disable-weak-memory-emulation` disables the emulation of some C++11 weak + memory effects. * `-Zmiri-measureme=` enables `measureme` profiling for the interpreted program. This can be used to find which parts of your program are executing slowly under Miri. The profile is written out to a file with the prefix ``, and can be processed diff --git a/src/weak_memory.rs b/src/weak_memory.rs index fc2e220e5e51..b9ab12923117 100644 --- a/src/weak_memory.rs +++ b/src/weak_memory.rs @@ -1,26 +1,26 @@ //! Implementation of C++11-consistent weak memory emulation using store buffers //! based on Dynamic Race Detection for C++ ("the paper"): //! https://www.doc.ic.ac.uk/~afd/homepages/papers/pdfs/2017/POPL.pdf -//! +//! //! This implementation will never generate weak memory behaviours forbidden by the C++11 model, //! but it is incapable of producing all possible weak behaviours allowed by the model. There are //! certain weak behaviours observable on real hardware but not while using this. -//! +//! //! Note that this implementation does not take into account of C++20's memory model revision to SC accesses //! and fences introduced by P0668 (https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0668r5.html). //! This implementation is not fully correct under the revised C++20 model and may generate behaviours C++20 //! disallows. -//! +//! //! Rust follows the full C++20 memory model (except for the Consume ordering). It is therefore //! possible for this implementation to generate behaviours never observable when the same program is compiled and //! run natively. Unfortunately, no literature exists at the time of writing which proposes an implementable and C++20-compatible //! relaxed memory model that supports all atomic operation existing in Rust. The closest one is //! A Promising Semantics for Relaxed-Memory Concurrency by Jeehoon Kang et al. (https://www.cs.tau.ac.il/~orilahav/papers/popl17.pdf) //! However, this model lacks SC accesses and is therefore unusable by Miri (SC accesses are everywhere in library code). -//! +//! //! If you find anything that proposes a relaxed memory model that is C++20-consistent, supports all orderings Rust's atomic accesses //! and fences accept, and is implementable (with operational semanitcs), please open a GitHub issue! -//! +//! //! One characteristic of this implementation, in contrast to some other notable operational models such as ones proposed in //! Taming Release-Acquire Consistency by Ori Lahav et al. (https://plv.mpi-sws.org/sra/paper.pdf) or Promising Semantics noted above, //! is that this implementation does not require each thread to hold an isolated view of the entire memory. Here, store buffers are per-location From 773131bb261a2a96426f9024271f5557bbbf5c1a Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Wed, 11 May 2022 23:52:38 +0100 Subject: [PATCH 3208/5092] Improve privacy and comments --- src/data_race.rs | 14 ++++++++++---- src/weak_memory.rs | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index d9bfbc1bdb5a..78b9b09f1615 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -103,7 +103,7 @@ pub enum AtomicFenceOp { pub struct ThreadClockSet { /// The increasing clock representing timestamps /// that happen-before this thread. - pub clock: VClock, + pub(crate) clock: VClock, /// The set of timestamps that will happen-before this /// thread once it performs an acquire fence. @@ -113,11 +113,17 @@ pub struct ThreadClockSet { /// have been released by this thread by a fence. fence_release: VClock, - pub fence_seqcst: VClock, + /// Timestamps of the last SC fence performed by each + /// thread, updated when this thread performs an SC fence + pub(crate) fence_seqcst: VClock, - pub write_seqcst: VClock, + /// Timestamps of the last SC write performed by each + /// thread, updated when this thread performs an SC fence + pub(crate) write_seqcst: VClock, - pub read_seqcst: VClock, + /// Timestamps of the last SC fence performed by each + /// thread, updated when this thread performs an SC read + pub(crate) read_seqcst: VClock, } impl ThreadClockSet { diff --git a/src/weak_memory.rs b/src/weak_memory.rs index b9ab12923117..46838c5c8a1f 100644 --- a/src/weak_memory.rs +++ b/src/weak_memory.rs @@ -88,7 +88,7 @@ pub struct StoreBuffer { } #[derive(Debug, Clone, PartialEq, Eq)] -pub struct StoreElement { +struct StoreElement { /// The identifier of the vector index, corresponding to a thread /// that performed the store. store_index: VectorIdx, From 7d874db213cdb17f20c4960e314bcce328d2b61c Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Thu, 12 May 2022 22:04:37 +0100 Subject: [PATCH 3209/5092] Add tests showing weak memory behaviours --- .../consistency.rs} | 39 +--------- .../consistency.stderr} | 0 .../weak_memory/imperfectly_overlapping.rs | 29 +++++++ tests/run-pass/weak_memory/weak.rs | 77 +++++++++++++++++++ tests/run-pass/weak_memory/weak.stderr | 2 + 5 files changed, 112 insertions(+), 35 deletions(-) rename tests/run-pass/{concurrency/weak_memory.rs => weak_memory/consistency.rs} (80%) rename tests/run-pass/{concurrency/weak_memory.stderr => weak_memory/consistency.stderr} (100%) create mode 100644 tests/run-pass/weak_memory/imperfectly_overlapping.rs create mode 100644 tests/run-pass/weak_memory/weak.rs create mode 100644 tests/run-pass/weak_memory/weak.stderr diff --git a/tests/run-pass/concurrency/weak_memory.rs b/tests/run-pass/weak_memory/consistency.rs similarity index 80% rename from tests/run-pass/concurrency/weak_memory.rs rename to tests/run-pass/weak_memory/consistency.rs index e85c2d1960c4..d7c44f6ac281 100644 --- a/tests/run-pass/concurrency/weak_memory.rs +++ b/tests/run-pass/weak_memory/consistency.rs @@ -1,8 +1,8 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows -// Weak memory emulation tests. All of the following test if -// our weak memory emulation produces any inconsistent execution outcomes +// The following tests check whether our weak memory emulation produces +// any inconsistent execution outcomes // // Due to the random nature of choosing valid stores, it is always // possible that our tests spuriously succeeds: even though our weak @@ -12,15 +12,6 @@ // // To mitigate this, each test is ran enough times such that the chance // of spurious success is very low. These tests never supriously fail. -// -// Note that we can't effectively test whether our weak memory emulation -// can produce *all* consistent execution outcomes. This may be possible -// if Miri's scheduler is sufficiently random and explores all possible -// interleavings of our small test cases after a reasonable number of runs. -// However, since Miri's scheduler is not even pre-emptive, there will -// always be possible interleavings (and possible execution outcomes), -// that can never be observed regardless of how weak memory emulation is -// implemented. // Test cases and their consistent outcomes are from // http://svr-pes20-cppmem.cl.cam.ac.uk/cppmem/ @@ -28,10 +19,9 @@ // M. Batty, S. Owens, S. Sarkar, P. Sewell and T. Weber, // "Mathematizing C++ concurrency", ACM SIGPLAN Notices, vol. 46, no. 1, pp. 55-66, 2011. // Available: https://ss265.host.cs.st-andrews.ac.uk/papers/n3132.pdf. -#![feature(atomic_from_mut)] +use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::*; -use std::sync::atomic::{AtomicU16, AtomicU32, AtomicUsize}; use std::thread::{spawn, yield_now}; #[derive(Copy, Clone)] @@ -41,7 +31,7 @@ unsafe impl Send for EvilSend {} unsafe impl Sync for EvilSend {} // We can't create static items because we need to run each test -// multiple tests +// multiple times fn static_atomic(val: usize) -> &'static AtomicUsize { let ret = Box::leak(Box::new(AtomicUsize::new(val))); // A workaround to put the initialisation value in the store buffer @@ -190,26 +180,6 @@ fn test_mixed_access() { assert_eq!(r2, 2); } -// Strictly speaking, atomic accesses that imperfectly overlap with existing -// atomic objects are UB. Nonetheless we'd like to provide a sane value when -// the access is not racy. -fn test_imperfectly_overlapping_access() { - let mut qword = AtomicU32::new(42); - assert_eq!(qword.load(Relaxed), 42); - qword.store(u32::to_be(0xabbafafa), Relaxed); - - let qword_mut = qword.get_mut(); - - let dwords_mut = unsafe { std::mem::transmute::<&mut u32, &mut [u16; 2]>(qword_mut) }; - - let (hi_mut, lo_mut) = dwords_mut.split_at_mut(1); - - let (hi, lo) = (AtomicU16::from_mut(&mut hi_mut[0]), AtomicU16::from_mut(&mut lo_mut[0])); - - assert_eq!(u16::from_be(hi.load(Relaxed)), 0xabba); - assert_eq!(u16::from_be(lo.load(Relaxed)), 0xfafa); -} - // The following two tests are taken from Repairing Sequential Consistency in C/C++11 // by Lahav et al. // https://plv.mpi-sws.org/scfix/paper.pdf @@ -236,7 +206,6 @@ fn test_sc_store_buffering() { } pub fn main() { - test_imperfectly_overlapping_access(); // TODO: does this make chances of spurious success // "sufficiently low"? This also takes a long time to run, // prehaps each function should be its own test case so they diff --git a/tests/run-pass/concurrency/weak_memory.stderr b/tests/run-pass/weak_memory/consistency.stderr similarity index 100% rename from tests/run-pass/concurrency/weak_memory.stderr rename to tests/run-pass/weak_memory/consistency.stderr diff --git a/tests/run-pass/weak_memory/imperfectly_overlapping.rs b/tests/run-pass/weak_memory/imperfectly_overlapping.rs new file mode 100644 index 000000000000..2a8e8e5f323d --- /dev/null +++ b/tests/run-pass/weak_memory/imperfectly_overlapping.rs @@ -0,0 +1,29 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +#![feature(atomic_from_mut)] + +use std::sync::atomic::Ordering::*; +use std::sync::atomic::{AtomicU16, AtomicU32}; + +// Strictly speaking, atomic accesses that imperfectly overlap with existing +// atomic objects are UB. Nonetheless we'd like to provide a sane value when +// the access is not racy. +fn test_same_thread() { + let mut qword = AtomicU32::new(42); + assert_eq!(qword.load(Relaxed), 42); + qword.store(u32::to_be(0xabbafafa), Relaxed); + + let qword_mut = qword.get_mut(); + + let dwords_mut = unsafe { std::mem::transmute::<&mut u32, &mut [u16; 2]>(qword_mut) }; + + let (hi_mut, lo_mut) = dwords_mut.split_at_mut(1); + + let (hi, lo) = (AtomicU16::from_mut(&mut hi_mut[0]), AtomicU16::from_mut(&mut lo_mut[0])); + + assert_eq!(u16::from_be(hi.load(Relaxed)), 0xabba); + assert_eq!(u16::from_be(lo.load(Relaxed)), 0xfafa); +} + +pub fn main() { + test_same_thread(); +} diff --git a/tests/run-pass/weak_memory/weak.rs b/tests/run-pass/weak_memory/weak.rs new file mode 100644 index 000000000000..ab0c20cc9772 --- /dev/null +++ b/tests/run-pass/weak_memory/weak.rs @@ -0,0 +1,77 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-ignore-leaks + +// Tests showing weak memory behaviours are exhibited. All tests +// return true when the desired behaviour is seen. +// This is scheduler and pseudo-RNG dependent, so each test is +// run multiple times until one try returns true. +// Spurious failure is possible, if you are really unlucky with +// the RNG. + +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering::*; +use std::thread::spawn; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +// We can't create static items because we need to run each test +// multiple times +fn static_atomic(val: usize) -> &'static AtomicUsize { + let ret = Box::leak(Box::new(AtomicUsize::new(val))); + // A workaround to put the initialisation value in the store buffer + ret.store(val, Relaxed); + ret +} + +fn relaxed() -> bool { + let x = static_atomic(0); + let j1 = spawn(move || { + x.store(1, Relaxed); + x.store(2, Relaxed); + }); + + let j2 = spawn(move || x.load(Relaxed)); + + j1.join().unwrap(); + let r2 = j2.join().unwrap(); + + r2 == 1 +} + +// https://www.doc.ic.ac.uk/~afd/homepages/papers/pdfs/2017/POPL.pdf Figure 8 +fn seq_cst() -> bool { + let x = static_atomic(0); + + let j1 = spawn(move || { + x.store(1, Relaxed); + }); + + let j2 = spawn(move || { + x.store(2, SeqCst); + x.store(3, SeqCst); + }); + + let j3 = spawn(move || x.load(SeqCst)); + + j1.join().unwrap(); + j2.join().unwrap(); + let r3 = j3.join().unwrap(); + + r3 == 1 +} + +// Asserts that the function returns true at least once in 100 runs +macro_rules! assert_once { + ($f:ident) => { + assert!(std::iter::repeat_with(|| $f()).take(100).any(|x| x)); + }; +} + +pub fn main() { + assert_once!(relaxed); + assert_once!(seq_cst); +} diff --git a/tests/run-pass/weak_memory/weak.stderr b/tests/run-pass/weak_memory/weak.stderr new file mode 100644 index 000000000000..03676519d4f1 --- /dev/null +++ b/tests/run-pass/weak_memory/weak.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + From 6040c9f50aa9a66f1cd6d30a92f9483dd51feebe Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Thu, 12 May 2022 18:57:03 +0100 Subject: [PATCH 3210/5092] Refactor store buffer search conditions --- src/weak_memory.rs | 72 +++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 42 deletions(-) diff --git a/src/weak_memory.rs b/src/weak_memory.rs index 46838c5c8a1f..223567d3cae1 100644 --- a/src/weak_memory.rs +++ b/src/weak_memory.rs @@ -252,59 +252,47 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { if !keep_searching { return false; } - // CoWR: if a store happens-before the current load, - // then we can't read-from anything earlier in modification order. - if store_elem.timestamp <= clocks.clock[store_elem.store_index] { - log::info!("Stopped due to coherent write-read"); - keep_searching = false; - return true; - } - // CoRR: if there was a load from this store which happened-before the current load, - // then we cannot read-from anything earlier in modification order. - if store_elem.loads.borrow().iter().any(|(&load_index, &load_timestamp)| { + keep_searching = if store_elem.timestamp <= clocks.clock[store_elem.store_index] { + // CoWR: if a store happens-before the current load, + // then we can't read-from anything earlier in modification order. + log::info!("Stopping due to coherent write-read"); + false + } else if store_elem.loads.borrow().iter().any(|(&load_index, &load_timestamp)| { load_timestamp <= clocks.clock[load_index] }) { - log::info!("Stopped due to coherent read-read"); - keep_searching = false; - return true; - } - - // The current load, which may be sequenced-after an SC fence, can only read-from - // the last store sequenced-before an SC fence in another thread (or any stores - // later than that SC fence) - if store_elem.timestamp <= clocks.fence_seqcst[store_elem.store_index] { - log::info!("Stopped due to coherent load sequenced after sc fence"); - keep_searching = false; - return true; - } - - // The current non-SC load can only read-from the latest SC store (or any stores later than that - // SC store) - if store_elem.timestamp <= clocks.write_seqcst[store_elem.store_index] + // CoRR: if there was a load from this store which happened-before the current load, + // then we cannot read-from anything earlier in modification order. + log::info!("Stopping due to coherent read-read"); + false + } else if store_elem.timestamp <= clocks.fence_seqcst[store_elem.store_index] { + // The current load, which may be sequenced-after an SC fence, can only read-from + // the last store sequenced-before an SC fence in another thread (or any stores + // later than that SC fence) + log::info!("Stopping due to coherent load sequenced after sc fence"); + false + } else if store_elem.timestamp <= clocks.write_seqcst[store_elem.store_index] && store_elem.is_seqcst { - log::info!("Stopped due to needing to load from the last SC store"); - keep_searching = false; - return true; - } - - // The current SC load can only read-from the last store sequenced-before - // the last SC fence (or any stores later than the SC fence) - if is_seqcst && store_elem.timestamp <= clocks.read_seqcst[store_elem.store_index] { - log::info!("Stopped due to sc load needing to load from the last SC store before an SC fence"); - keep_searching = false; - return true; - } + // The current non-SC load can only read-from the latest SC store (or any stores later than that + // SC store) + log::info!("Stopping due to needing to load from the last SC store"); + false + } else if is_seqcst && store_elem.timestamp <= clocks.read_seqcst[store_elem.store_index] { + // The current SC load can only read-from the last store sequenced-before + // the last SC fence (or any stores later than the SC fence) + log::info!("Stopping due to sc load needing to load from the last SC store before an SC fence"); + false + } else {true}; true }) .filter(|&store_elem| { - if is_seqcst { + if is_seqcst && store_elem.is_seqcst { // An SC load needs to ignore all but last store maked SC (stores not marked SC are not // affected) - let include = !(store_elem.is_seqcst && found_sc); - found_sc |= store_elem.is_seqcst; + let include = !found_sc; + found_sc = true; include } else { true From 13e34653461a274c5759f5c33b19285e3daa9df5 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Fri, 13 May 2022 00:15:57 +0100 Subject: [PATCH 3211/5092] Reduce the number of runs in consistency tests --- tests/run-pass/weak_memory/consistency.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/run-pass/weak_memory/consistency.rs b/tests/run-pass/weak_memory/consistency.rs index d7c44f6ac281..8705d0bc6781 100644 --- a/tests/run-pass/weak_memory/consistency.rs +++ b/tests/run-pass/weak_memory/consistency.rs @@ -206,11 +206,7 @@ fn test_sc_store_buffering() { } pub fn main() { - // TODO: does this make chances of spurious success - // "sufficiently low"? This also takes a long time to run, - // prehaps each function should be its own test case so they - // can be run in parallel - for _ in 0..500 { + for _ in 0..100 { test_mixed_access(); test_load_buffering_acq_rel(); test_message_passing(); From 8739e45bef31493053816f350a268245b4c0b787 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Fri, 13 May 2022 23:23:58 +0100 Subject: [PATCH 3212/5092] Move data_race and weak_memory into a submodule --- src/{ => concurrency}/allocation_map.rs | 0 src/{ => concurrency}/data_race.rs | 16 ++++++++-------- src/concurrency/mod.rs | 3 +++ src/{ => concurrency}/weak_memory.rs | 17 +++++++++-------- src/lib.rs | 6 ++---- src/machine.rs | 6 +++++- src/thread.rs | 1 + 7 files changed, 28 insertions(+), 21 deletions(-) rename src/{ => concurrency}/allocation_map.rs (100%) rename src/{ => concurrency}/data_race.rs (99%) create mode 100644 src/concurrency/mod.rs rename src/{ => concurrency}/weak_memory.rs (97%) diff --git a/src/allocation_map.rs b/src/concurrency/allocation_map.rs similarity index 100% rename from src/allocation_map.rs rename to src/concurrency/allocation_map.rs diff --git a/src/data_race.rs b/src/concurrency/data_race.rs similarity index 99% rename from src/data_race.rs rename to src/concurrency/data_race.rs index 78b9b09f1615..c0137bf86d8b 100644 --- a/src/data_race.rs +++ b/src/concurrency/data_race.rs @@ -100,10 +100,10 @@ pub enum AtomicFenceOp { /// of a thread, contains the happens-before clock and /// additional metadata to model atomic fence operations. #[derive(Clone, Default, Debug)] -pub struct ThreadClockSet { +pub(super) struct ThreadClockSet { /// The increasing clock representing timestamps /// that happen-before this thread. - pub(crate) clock: VClock, + pub(super) clock: VClock, /// The set of timestamps that will happen-before this /// thread once it performs an acquire fence. @@ -115,15 +115,15 @@ pub struct ThreadClockSet { /// Timestamps of the last SC fence performed by each /// thread, updated when this thread performs an SC fence - pub(crate) fence_seqcst: VClock, + pub(super) fence_seqcst: VClock, /// Timestamps of the last SC write performed by each /// thread, updated when this thread performs an SC fence - pub(crate) write_seqcst: VClock, + pub(super) write_seqcst: VClock, /// Timestamps of the last SC fence performed by each /// thread, updated when this thread performs an SC read - pub(crate) read_seqcst: VClock, + pub(super) read_seqcst: VClock, } impl ThreadClockSet { @@ -166,7 +166,7 @@ pub struct DataRace; /// common case where no atomic operations /// exists on the memory cell. #[derive(Clone, PartialEq, Eq, Default, Debug)] -pub struct AtomicMemoryCellClocks { +struct AtomicMemoryCellClocks { /// The clock-vector of the timestamp of the last atomic /// read operation performed by each thread. /// This detects potential data-races between atomic read @@ -1547,7 +1547,7 @@ impl GlobalState { /// Load the current vector clock in use and the current set of thread clocks /// in use for the vector. #[inline] - pub fn current_thread_state(&self) -> (VectorIdx, Ref<'_, ThreadClockSet>) { + pub(super) fn current_thread_state(&self) -> (VectorIdx, Ref<'_, ThreadClockSet>) { let index = self.current_index(); let ref_vector = self.vector_clocks.borrow(); let clocks = Ref::map(ref_vector, |vec| &vec[index]); @@ -1557,7 +1557,7 @@ impl GlobalState { /// Load the current vector clock in use and the current set of thread clocks /// in use for the vector mutably for modification. #[inline] - pub fn current_thread_state_mut(&self) -> (VectorIdx, RefMut<'_, ThreadClockSet>) { + pub(super) fn current_thread_state_mut(&self) -> (VectorIdx, RefMut<'_, ThreadClockSet>) { let index = self.current_index(); let ref_vector = self.vector_clocks.borrow_mut(); let clocks = RefMut::map(ref_vector, |vec| &mut vec[index]); diff --git a/src/concurrency/mod.rs b/src/concurrency/mod.rs new file mode 100644 index 000000000000..ad1586bbf0f9 --- /dev/null +++ b/src/concurrency/mod.rs @@ -0,0 +1,3 @@ +mod allocation_map; +pub mod data_race; +pub mod weak_memory; diff --git a/src/weak_memory.rs b/src/concurrency/weak_memory.rs similarity index 97% rename from src/weak_memory.rs rename to src/concurrency/weak_memory.rs index 223567d3cae1..5bdadc804f86 100644 --- a/src/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -60,10 +60,11 @@ use std::{ use rustc_const_eval::interpret::{AllocRange, InterpResult, ScalarMaybeUninit}; use rustc_data_structures::fx::FxHashMap; -use crate::{ +use crate::{Tag, VClock, VTimestamp, VectorIdx}; + +use super::{ allocation_map::{AccessType, AllocationMap}, data_race::{GlobalState, ThreadClockSet}, - Tag, VClock, VTimestamp, VectorIdx, }; pub type AllocExtra = StoreBufferAlloc; @@ -82,7 +83,7 @@ pub struct StoreBufferAlloc { } #[derive(Debug, Clone, PartialEq, Eq)] -pub struct StoreBuffer { +pub(super) struct StoreBuffer { // Stores to this location in modification order buffer: VecDeque, } @@ -112,7 +113,7 @@ impl StoreBufferAlloc { } /// Gets a store buffer associated with an atomic object in this allocation - pub fn get_store_buffer(&self, range: AllocRange) -> Ref<'_, StoreBuffer> { + pub(super) fn get_store_buffer(&self, range: AllocRange) -> Ref<'_, StoreBuffer> { let access_type = self.store_buffer.borrow().access_type(range); let index = match access_type { AccessType::PerfectlyOverlapping(index) => index, @@ -143,7 +144,7 @@ impl StoreBufferAlloc { } /// Gets a mutable store buffer associated with an atomic object in this allocation - pub fn get_store_buffer_mut(&mut self, range: AllocRange) -> &mut StoreBuffer { + pub(super) fn get_store_buffer_mut(&mut self, range: AllocRange) -> &mut StoreBuffer { let buffer = self.store_buffer.get_mut(); let access_type = buffer.access_type(range); let index = match access_type { @@ -174,7 +175,7 @@ impl Default for StoreBuffer { impl<'mir, 'tcx: 'mir> StoreBuffer { /// Reads from the last store in modification order - pub fn read_from_last_store(&self, global: &GlobalState) { + pub(super) fn read_from_last_store(&self, global: &GlobalState) { let store_elem = self.buffer.back(); if let Some(store_elem) = store_elem { let (index, clocks) = global.current_thread_state(); @@ -182,7 +183,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { } } - pub fn buffered_read( + pub(super) fn buffered_read( &self, global: &GlobalState, is_seqcst: bool, @@ -213,7 +214,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { Ok(loaded) } - pub fn buffered_write( + pub(super) fn buffered_write( &mut self, val: ScalarMaybeUninit, global: &GlobalState, diff --git a/src/lib.rs b/src/lib.rs index 3270a57c4964..982d3873d573 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,8 +31,7 @@ extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; -mod allocation_map; -mod data_race; +mod concurrency; mod diagnostics; mod eval; mod helpers; @@ -46,7 +45,6 @@ mod stacked_borrows; mod sync; mod thread; mod vector_clock; -mod weak_memory; // Establish a "crate-wide prelude": we often import `crate::*`. @@ -65,7 +63,7 @@ pub use crate::shims::time::EvalContextExt as _; pub use crate::shims::tls::{EvalContextExt as _, TlsData}; pub use crate::shims::EvalContextExt as _; -pub use crate::data_race::{ +pub use crate::concurrency::data_race::{ AtomicFenceOp, AtomicReadOp, AtomicRwOp, AtomicWriteOp, EvalContextExt as DataRaceEvalContextExt, }; diff --git a/src/machine.rs b/src/machine.rs index ca7fff7b08b9..41c852747ad7 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -28,7 +28,11 @@ use rustc_span::Symbol; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; -use crate::{shims::unix::FileHandler, *}; +use crate::{ + concurrency::{data_race, weak_memory}, + shims::unix::FileHandler, + *, +}; // Some global facts about the emulated machine. pub const PAGE_SIZE: u64 = 4 * 1024; // FIXME: adjust to target architecture diff --git a/src/thread.rs b/src/thread.rs index b6fb866f714a..0d702fd9c8e1 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -12,6 +12,7 @@ use rustc_hir::def_id::DefId; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::mir::Mutability; +use crate::concurrency::data_race; use crate::sync::SynchronizationState; use crate::*; From 335667c7749930f9f30e7045bc29690dd81a85f8 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sat, 14 May 2022 01:45:21 +0100 Subject: [PATCH 3213/5092] Move buffered functions into their own ext trait --- src/concurrency/data_race.rs | 89 +++-------------------- src/concurrency/weak_memory.rs | 124 +++++++++++++++++++++++++++++++-- 2 files changed, 128 insertions(+), 85 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index c0137bf86d8b..22b72dadade7 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -51,7 +51,6 @@ use std::{ mem, }; -use rustc_const_eval::interpret::alloc_range; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::{mir, ty::layout::TyAndLayout}; @@ -59,6 +58,8 @@ use rustc_target::abi::Size; use crate::*; +use super::weak_memory::EvalContextExt as _; + pub type AllocExtra = VClockAlloc; /// Valid atomic read-write operations, alias of atomic::Ordering (not non-exhaustive). @@ -517,29 +518,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // the *value* (including the associated provenance if this is an AtomicPtr) at this location. // Only metadata on the location itself is used. let scalar = this.allow_data_races_ref(move |this| this.read_scalar(&place.into()))?; - - if let Some(global) = &this.machine.data_race { - let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; - if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { - if atomic == AtomicReadOp::SeqCst { - global.sc_read(); - } - let mut rng = this.machine.rng.borrow_mut(); - let buffer = - alloc_buffers.get_store_buffer(alloc_range(base_offset, place.layout.size)); - let loaded = buffer.buffered_read( - global, - atomic == AtomicReadOp::SeqCst, - &mut *rng, - || this.validate_atomic_load(place, atomic), - )?; - - return Ok(loaded.unwrap_or(scalar)); - } - } - - this.validate_atomic_load(place, atomic)?; - Ok(scalar) + this.buffered_atomic_read(place, atomic, scalar, || { + this.validate_atomic_load(place, atomic) + }) } /// Perform an atomic write operation at the memory location. @@ -551,23 +532,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.allow_data_races_mut(move |this| this.write_scalar(val, &(*dest).into()))?; - this.validate_atomic_store(dest, atomic)?; - let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(dest.ptr)?; - if let ( - crate::AllocExtra { weak_memory: Some(alloc_buffers), .. }, - crate::Evaluator { data_race: Some(global), .. }, - ) = this.get_alloc_extra_mut(alloc_id)? - { - if atomic == AtomicWriteOp::SeqCst { - global.sc_write(); - } - let buffer = - alloc_buffers.get_store_buffer_mut(alloc_range(base_offset, dest.layout.size)); - buffer.buffered_write(val, global, atomic == AtomicWriteOp::SeqCst)?; - } - - Ok(()) + this.buffered_atomic_write(val, dest, atomic) } /// Perform an atomic operation on a memory location. @@ -695,50 +661,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // in the modification order. // Since `old` is only a value and not the store element, we need to separately // find it in our store buffer and perform load_impl on it. - if let Some(global) = &this.machine.data_race { - if fail == AtomicReadOp::SeqCst { - global.sc_read(); - } - let size = place.layout.size; - let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; - if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { - if global.multi_threaded.get() { - let buffer = alloc_buffers.get_store_buffer(alloc_range(base_offset, size)); - buffer.read_from_last_store(global); - } - } - } + this.perform_read_on_buffered_latest(place, fail)?; } // Return the old value. Ok(res) } - fn buffered_atomic_rmw( - &mut self, - new_val: ScalarMaybeUninit, - place: &MPlaceTy<'tcx, Tag>, - atomic: AtomicRwOp, - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; - if let ( - crate::AllocExtra { weak_memory: Some(alloc_buffers), .. }, - crate::Evaluator { data_race: Some(global), .. }, - ) = this.get_alloc_extra_mut(alloc_id)? - { - if atomic == AtomicRwOp::SeqCst { - global.sc_read(); - global.sc_write(); - } - let range = alloc_range(base_offset, place.layout.size); - let buffer = alloc_buffers.get_store_buffer_mut(range); - buffer.read_from_last_store(global); - buffer.buffered_write(new_val, global, atomic == AtomicRwOp::SeqCst)?; - } - Ok(()) - } - /// Update the data-race detector for an atomic read occurring at the /// associated memory-place and on the current thread. fn validate_atomic_load( @@ -1572,13 +1501,13 @@ impl GlobalState { } // SC ATOMIC STORE rule in the paper. - fn sc_write(&self) { + pub(super) fn sc_write(&self) { let (index, clocks) = self.current_thread_state(); self.last_sc_write.borrow_mut().set_at_index(&clocks.clock, index); } // SC ATOMIC READ rule in the paper. - fn sc_read(&self) { + pub(super) fn sc_read(&self) { let (.., mut clocks) = self.current_thread_state_mut(); clocks.read_seqcst.join(&self.last_sc_fence.borrow()); } diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index 5bdadc804f86..fba7d18cdf07 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -57,10 +57,12 @@ use std::{ collections::VecDeque, }; -use rustc_const_eval::interpret::{AllocRange, InterpResult, ScalarMaybeUninit}; +use rustc_const_eval::interpret::{ + alloc_range, AllocRange, InterpResult, MPlaceTy, ScalarMaybeUninit, +}; use rustc_data_structures::fx::FxHashMap; -use crate::{Tag, VClock, VTimestamp, VectorIdx}; +use crate::{AtomicReadOp, AtomicRwOp, AtomicWriteOp, Tag, VClock, VTimestamp, VectorIdx}; use super::{ allocation_map::{AccessType, AllocationMap}, @@ -113,7 +115,7 @@ impl StoreBufferAlloc { } /// Gets a store buffer associated with an atomic object in this allocation - pub(super) fn get_store_buffer(&self, range: AllocRange) -> Ref<'_, StoreBuffer> { + fn get_store_buffer(&self, range: AllocRange) -> Ref<'_, StoreBuffer> { let access_type = self.store_buffer.borrow().access_type(range); let index = match access_type { AccessType::PerfectlyOverlapping(index) => index, @@ -144,7 +146,7 @@ impl StoreBufferAlloc { } /// Gets a mutable store buffer associated with an atomic object in this allocation - pub(super) fn get_store_buffer_mut(&mut self, range: AllocRange) -> &mut StoreBuffer { + fn get_store_buffer_mut(&mut self, range: AllocRange) -> &mut StoreBuffer { let buffer = self.store_buffer.get_mut(); let access_type = buffer.access_type(range); let index = match access_type { @@ -201,7 +203,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { self.fetch_store(is_seqcst, &clocks, &mut *rng) }; - // Unlike in write_scalar_atomic, thread clock updates have to be done + // Unlike in buffered_atomic_write, thread clock updates have to be done // after we've picked a store element from the store buffer, as presented // in ATOMIC LOAD rule of the paper. This is because fetch_store // requires access to ThreadClockSet.clock, which is updated by the race detector @@ -353,3 +355,115 @@ impl StoreElement { self.val } } + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: + crate::MiriEvalContextExt<'mir, 'tcx> +{ + fn buffered_atomic_rmw( + &mut self, + new_val: ScalarMaybeUninit, + place: &MPlaceTy<'tcx, Tag>, + atomic: AtomicRwOp, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; + if let ( + crate::AllocExtra { weak_memory: Some(alloc_buffers), .. }, + crate::Evaluator { data_race: Some(global), .. }, + ) = this.get_alloc_extra_mut(alloc_id)? + { + if atomic == AtomicRwOp::SeqCst { + global.sc_read(); + global.sc_write(); + } + let range = alloc_range(base_offset, place.layout.size); + let buffer = alloc_buffers.get_store_buffer_mut(range); + buffer.read_from_last_store(global); + buffer.buffered_write(new_val, global, atomic == AtomicRwOp::SeqCst)?; + } + Ok(()) + } + + fn buffered_atomic_read( + &self, + place: &MPlaceTy<'tcx, Tag>, + atomic: AtomicReadOp, + latest_in_mo: ScalarMaybeUninit, + validate: impl FnOnce() -> InterpResult<'tcx>, + ) -> InterpResult<'tcx, ScalarMaybeUninit> { + let this = self.eval_context_ref(); + if let Some(global) = &this.machine.data_race { + let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; + if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { + if atomic == AtomicReadOp::SeqCst { + global.sc_read(); + } + let mut rng = this.machine.rng.borrow_mut(); + let buffer = + alloc_buffers.get_store_buffer(alloc_range(base_offset, place.layout.size)); + let loaded = buffer.buffered_read( + global, + atomic == AtomicReadOp::SeqCst, + &mut *rng, + validate, + )?; + + return Ok(loaded.unwrap_or(latest_in_mo)); + } + } + + // Race detector or weak memory disabled, simply read the latest value + validate()?; + Ok(latest_in_mo) + } + + fn buffered_atomic_write( + &mut self, + val: ScalarMaybeUninit, + dest: &MPlaceTy<'tcx, Tag>, + atomic: AtomicWriteOp, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(dest.ptr)?; + if let ( + crate::AllocExtra { weak_memory: Some(alloc_buffers), .. }, + crate::Evaluator { data_race: Some(global), .. }, + ) = this.get_alloc_extra_mut(alloc_id)? + { + if atomic == AtomicWriteOp::SeqCst { + global.sc_write(); + } + let buffer = + alloc_buffers.get_store_buffer_mut(alloc_range(base_offset, dest.layout.size)); + buffer.buffered_write(val, global, atomic == AtomicWriteOp::SeqCst)?; + } + + // Caller should've written to dest with the vanilla scalar write, we do nothing here + Ok(()) + } + + /// Caller should never need to consult the store buffer for the latest value. + /// This function is used exclusively for failed atomic_compare_exchange_scalar + /// to perform load_impl on the latest store element + fn perform_read_on_buffered_latest( + &self, + place: &MPlaceTy<'tcx, Tag>, + atomic: AtomicReadOp, + ) -> InterpResult<'tcx> { + let this = self.eval_context_ref(); + + if let Some(global) = &this.machine.data_race { + if atomic == AtomicReadOp::SeqCst { + global.sc_read(); + } + let size = place.layout.size; + let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; + if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { + let buffer = alloc_buffers.get_store_buffer(alloc_range(base_offset, size)); + buffer.read_from_last_store(global); + } + } + Ok(()) + } +} From 5a4a1bfccc50e0e6c6df98e4b95837de79e01023 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 15 May 2022 22:29:40 +0100 Subject: [PATCH 3214/5092] Remove incorrect comment --- src/concurrency/weak_memory.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index fba7d18cdf07..f6466724b5e9 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -127,9 +127,7 @@ impl StoreBufferAlloc { } AccessType::ImperfectlyOverlapping(index_range) => { // Accesses that imperfectly overlaps with existing atomic objects - // do not have well-defined behaviours. But we don't throw a UB here - // because we have (or will) checked that all bytes in the current - // access are non-racy. + // do not have well-defined behaviours. // The behaviour here is that we delete all the existing objects this // access touches, and allocate a new and empty one for the exact range. // A read on an empty buffer returns None, which means the program will From 6b54c9237789c275a82eeb483052b302f490b57c Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Mon, 16 May 2022 20:00:11 +0100 Subject: [PATCH 3215/5092] Throw UB on imperfectly overlapping access --- src/concurrency/allocation_map.rs | 5 -- src/concurrency/weak_memory.rs | 53 ++++++++++--------- .../weak_memory/imperfectly_overlapping.rs | 15 +++--- 3 files changed, 36 insertions(+), 37 deletions(-) rename tests/{run-pass => compile-fail}/weak_memory/imperfectly_overlapping.rs (54%) diff --git a/src/concurrency/allocation_map.rs b/src/concurrency/allocation_map.rs index 6c14ce165407..5b6c06d59ec2 100644 --- a/src/concurrency/allocation_map.rs +++ b/src/concurrency/allocation_map.rs @@ -122,11 +122,6 @@ impl AllocationMap { debug_assert!(range.end() <= self.v[index + 1].range.start); } } - - /// Removes an object at given position - pub fn remove(&mut self, index: Position) -> T { - self.v.remove(index).data - } } impl Index for AllocationMap { diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index f6466724b5e9..a796b56e2c0a 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -85,7 +85,7 @@ pub struct StoreBufferAlloc { } #[derive(Debug, Clone, PartialEq, Eq)] -pub(super) struct StoreBuffer { +struct StoreBuffer { // Stores to this location in modification order buffer: VecDeque, } @@ -115,7 +115,10 @@ impl StoreBufferAlloc { } /// Gets a store buffer associated with an atomic object in this allocation - fn get_store_buffer(&self, range: AllocRange) -> Ref<'_, StoreBuffer> { + fn get_store_buffer<'tcx>( + &self, + range: AllocRange, + ) -> InterpResult<'tcx, Ref<'_, StoreBuffer>> { let access_type = self.store_buffer.borrow().access_type(range); let index = match access_type { AccessType::PerfectlyOverlapping(index) => index, @@ -128,23 +131,23 @@ impl StoreBufferAlloc { AccessType::ImperfectlyOverlapping(index_range) => { // Accesses that imperfectly overlaps with existing atomic objects // do not have well-defined behaviours. - // The behaviour here is that we delete all the existing objects this - // access touches, and allocate a new and empty one for the exact range. - // A read on an empty buffer returns None, which means the program will - // observe the latest value in modification order at every byte. - let mut buffer = self.store_buffer.borrow_mut(); - for index in index_range.clone() { - buffer.remove(index); + // FIXME: if this access happens before all previous accesses on every object it overlaps + // with, then we would like to tolerate it. However this is not easy to check. + if index_range.start + 1 == index_range.end { + throw_ub_format!("mixed-size access on an existing atomic object"); + } else { + throw_ub_format!("access overlaps with multiple existing atomic objects"); } - buffer.insert(index_range.start, range, StoreBuffer::default()); - index_range.start } }; - Ref::map(self.store_buffer.borrow(), |buffer| &buffer[index]) + Ok(Ref::map(self.store_buffer.borrow(), |buffer| &buffer[index])) } /// Gets a mutable store buffer associated with an atomic object in this allocation - fn get_store_buffer_mut(&mut self, range: AllocRange) -> &mut StoreBuffer { + fn get_store_buffer_mut<'tcx>( + &mut self, + range: AllocRange, + ) -> InterpResult<'tcx, &mut StoreBuffer> { let buffer = self.store_buffer.get_mut(); let access_type = buffer.access_type(range); let index = match access_type { @@ -154,14 +157,14 @@ impl StoreBufferAlloc { index } AccessType::ImperfectlyOverlapping(index_range) => { - for index in index_range.clone() { - buffer.remove(index); + if index_range.start + 1 == index_range.end { + throw_ub_format!("mixed-size access on an existing atomic object"); + } else { + throw_ub_format!("access overlaps with multiple existing atomic objects"); } - buffer.insert(index_range.start, range, StoreBuffer::default()); - index_range.start } }; - &mut buffer[index] + Ok(&mut buffer[index]) } } @@ -175,7 +178,7 @@ impl Default for StoreBuffer { impl<'mir, 'tcx: 'mir> StoreBuffer { /// Reads from the last store in modification order - pub(super) fn read_from_last_store(&self, global: &GlobalState) { + fn read_from_last_store(&self, global: &GlobalState) { let store_elem = self.buffer.back(); if let Some(store_elem) = store_elem { let (index, clocks) = global.current_thread_state(); @@ -183,7 +186,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { } } - pub(super) fn buffered_read( + fn buffered_read( &self, global: &GlobalState, is_seqcst: bool, @@ -214,7 +217,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { Ok(loaded) } - pub(super) fn buffered_write( + fn buffered_write( &mut self, val: ScalarMaybeUninit, global: &GlobalState, @@ -376,7 +379,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: global.sc_write(); } let range = alloc_range(base_offset, place.layout.size); - let buffer = alloc_buffers.get_store_buffer_mut(range); + let buffer = alloc_buffers.get_store_buffer_mut(range)?; buffer.read_from_last_store(global); buffer.buffered_write(new_val, global, atomic == AtomicRwOp::SeqCst)?; } @@ -399,7 +402,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: } let mut rng = this.machine.rng.borrow_mut(); let buffer = - alloc_buffers.get_store_buffer(alloc_range(base_offset, place.layout.size)); + alloc_buffers.get_store_buffer(alloc_range(base_offset, place.layout.size))?; let loaded = buffer.buffered_read( global, atomic == AtomicReadOp::SeqCst, @@ -433,7 +436,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: global.sc_write(); } let buffer = - alloc_buffers.get_store_buffer_mut(alloc_range(base_offset, dest.layout.size)); + alloc_buffers.get_store_buffer_mut(alloc_range(base_offset, dest.layout.size))?; buffer.buffered_write(val, global, atomic == AtomicWriteOp::SeqCst)?; } @@ -458,7 +461,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let size = place.layout.size; let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { - let buffer = alloc_buffers.get_store_buffer(alloc_range(base_offset, size)); + let buffer = alloc_buffers.get_store_buffer(alloc_range(base_offset, size))?; buffer.read_from_last_store(global); } } diff --git a/tests/run-pass/weak_memory/imperfectly_overlapping.rs b/tests/compile-fail/weak_memory/imperfectly_overlapping.rs similarity index 54% rename from tests/run-pass/weak_memory/imperfectly_overlapping.rs rename to tests/compile-fail/weak_memory/imperfectly_overlapping.rs index 2a8e8e5f323d..e3f89b5b684f 100644 --- a/tests/run-pass/weak_memory/imperfectly_overlapping.rs +++ b/tests/compile-fail/weak_memory/imperfectly_overlapping.rs @@ -1,16 +1,15 @@ // ignore-windows: Concurrency on Windows is not supported yet. #![feature(atomic_from_mut)] +#![feature(core_intrinsics)] +use std::intrinsics::atomic_load; use std::sync::atomic::Ordering::*; use std::sync::atomic::{AtomicU16, AtomicU32}; -// Strictly speaking, atomic accesses that imperfectly overlap with existing -// atomic objects are UB. Nonetheless we'd like to provide a sane value when -// the access is not racy. fn test_same_thread() { let mut qword = AtomicU32::new(42); assert_eq!(qword.load(Relaxed), 42); - qword.store(u32::to_be(0xabbafafa), Relaxed); + qword.store(0xabbafafa, Relaxed); let qword_mut = qword.get_mut(); @@ -18,10 +17,12 @@ fn test_same_thread() { let (hi_mut, lo_mut) = dwords_mut.split_at_mut(1); - let (hi, lo) = (AtomicU16::from_mut(&mut hi_mut[0]), AtomicU16::from_mut(&mut lo_mut[0])); + let (hi, _) = (AtomicU16::from_mut(&mut hi_mut[0]), AtomicU16::from_mut(&mut lo_mut[0])); - assert_eq!(u16::from_be(hi.load(Relaxed)), 0xabba); - assert_eq!(u16::from_be(lo.load(Relaxed)), 0xfafa); + unsafe { + //Equivalent to: hi.load(Ordering::SeqCst) + atomic_load(hi.get_mut() as *mut u16); //~ ERROR: mixed-size access on an existing atomic object + } } pub fn main() { From 577054c6ded13a70ee07d6fc3397518ae1e81710 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Mon, 16 May 2022 22:26:38 +0100 Subject: [PATCH 3216/5092] Rename variables in AllocationMap --- src/concurrency/allocation_map.rs | 73 ++++++++++++++++--------------- src/concurrency/weak_memory.rs | 32 +++++++------- 2 files changed, 54 insertions(+), 51 deletions(-) diff --git a/src/concurrency/allocation_map.rs b/src/concurrency/allocation_map.rs index 5b6c06d59ec2..2524389c0be8 100644 --- a/src/concurrency/allocation_map.rs +++ b/src/concurrency/allocation_map.rs @@ -49,7 +49,7 @@ impl AllocationMap { loop { if left == right { // No element contains the given offset. But the - // index is where such element should be placed at. + // position is where such element should be placed at. return Err(left); } let candidate = left.checked_add(right).unwrap() / 2; @@ -73,53 +73,56 @@ impl AllocationMap { /// an existing allocation pub fn access_type(&self, range: AllocRange) -> AccessType { match self.find_offset(range.start) { - Ok(index) => { + Ok(pos) => { // Start of the range belongs to an existing object, now let's check the overlapping situation - let elem = &self.v[index]; + let elem = &self.v[pos]; // FIXME: derive Eq for AllocRange in rustc if elem.range.start == range.start && elem.range.size == range.size { // Happy case: perfectly overlapping access - AccessType::PerfectlyOverlapping(index) + AccessType::PerfectlyOverlapping(pos) } else { // FIXME: add a last() method to AllocRange that returns the last inclusive offset (end() is exclusive) - let end_index = match self.find_offset(range.end() - Size::from_bytes(1)) { - // If the end lands in an existing object, add one to get the exclusive index - Ok(inclusive) => inclusive + 1, - Err(exclusive) => exclusive, + let end_pos = match self.find_offset(range.end() - Size::from_bytes(1)) { + // If the end lands in an existing object, add one to get the exclusive position + Ok(inclusive_pos) => inclusive_pos + 1, + Err(exclusive_pos) => exclusive_pos, }; - AccessType::ImperfectlyOverlapping(index..end_index) + AccessType::ImperfectlyOverlapping(pos..end_pos) } } - Err(index) => { + Err(pos) => { // Start of the range doesn't belong to an existing object match self.find_offset(range.end() - Size::from_bytes(1)) { // Neither does the end - Err(end_index) => - if index == end_index { + Err(end_pos) => + if pos == end_pos { // There's nothing between the start and the end, so the range thing is empty - AccessType::Empty(index) + AccessType::Empty(pos) } else { // Otherwise we have entirely covered an existing object - AccessType::ImperfectlyOverlapping(index..end_index) + AccessType::ImperfectlyOverlapping(pos..end_pos) }, // Otherwise at least part of it overlaps with something else - Ok(end_index) => AccessType::ImperfectlyOverlapping(index..end_index + 1), + Ok(end_pos) => AccessType::ImperfectlyOverlapping(pos..end_pos + 1), } } } } /// Inserts an object and its occupied range at given position - pub fn insert(&mut self, index: Position, range: AllocRange, data: T) { - self.v.insert(index, Elem { range, data }); + // The Position can be calculated from AllocRange, but the only user of AllocationMap + // always calls access_type before calling insert/index/index_mut, and we don't + // want to repeat the binary search on each time, so we ask the caller to supply Position + pub fn insert_at_pos(&mut self, pos: Position, range: AllocRange, data: T) { + self.v.insert(pos, Elem { range, data }); // If we aren't the first element, then our start must be greater than the preivous element's end - if index > 0 { - debug_assert!(self.v[index - 1].range.end() <= range.start); + if pos > 0 { + debug_assert!(self.v[pos - 1].range.end() <= range.start); } // If we aren't the last element, then our end must be smaller than next element's start - if index < self.v.len() - 1 { - debug_assert!(range.end() <= self.v[index + 1].range.start); + if pos < self.v.len() - 1 { + debug_assert!(range.end() <= self.v[pos + 1].range.start); } } } @@ -127,14 +130,14 @@ impl AllocationMap { impl Index for AllocationMap { type Output = T; - fn index(&self, index: usize) -> &Self::Output { - &self.v[index].data + fn index(&self, pos: Position) -> &Self::Output { + &self.v[pos].data } } impl IndexMut for AllocationMap { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.v[index].data + fn index_mut(&mut self, pos: Position) -> &mut Self::Output { + &mut self.v[pos].data } } @@ -150,10 +153,10 @@ mod tests { let four = Size::from_bytes(4); let map = AllocationMap::<()>::new(); - // Correctly tells where we should insert the first element (at index 0) + // Correctly tells where we should insert the first element (at position 0) assert_eq!(map.find_offset(Size::from_bytes(3)), Err(0)); - // Correctly tells the access type along with the supposed index + // Correctly tells the access type along with the supposed position assert_eq!(map.access_type(alloc_range(Size::ZERO, four)), AccessType::Empty(0)); } @@ -166,10 +169,10 @@ mod tests { // |_|_|_|_|#|#|#|#|_|_|_|_|... // 0 1 2 3 4 5 6 7 8 9 a b c d - map.insert(0, alloc_range(four, four), "#"); + map.insert_at_pos(0, alloc_range(four, four), "#"); // |_|_|_|_|#|#|#|#|_|_|_|_|... // 0 ^ ^ ^ ^ 5 6 7 8 9 a b c d - map.insert(0, alloc_range(Size::from_bytes(1), four), "@"); + map.insert_at_pos(0, alloc_range(Size::from_bytes(1), four), "@"); } #[test] @@ -180,7 +183,7 @@ mod tests { // |#|#|#|#|_|_|... // 0 1 2 3 4 5 - map.insert(0, alloc_range(Size::ZERO, four), "#"); + map.insert_at_pos(0, alloc_range(Size::ZERO, four), "#"); // |#|#|#|#|_|_|... // 0 1 2 3 ^ 5 assert_eq!(map.find_offset(four), Err(1)); @@ -191,7 +194,7 @@ mod tests { let eight = Size::from_bytes(8); // |#|#|#|#|_|_|_|_|@|@|@|@|_|_|... // 0 1 2 3 4 5 6 7 8 9 a b c d - map.insert(1, alloc_range(eight, four), "@"); + map.insert_at_pos(1, alloc_range(eight, four), "@"); // |#|#|#|#|_|_|_|_|@|@|@|@|_|_|... // 0 1 2 3 4 5 6 ^ 8 9 a b c d assert_eq!(map.find_offset(Size::from_bytes(7)), Err(1)); @@ -208,7 +211,7 @@ mod tests { // |#|#|#|#|_|_|... // 0 1 2 3 4 5 - map.insert(0, alloc_range(Size::ZERO, four), "#"); + map.insert_at_pos(0, alloc_range(Size::ZERO, four), "#"); // |#|#|#|#|_|_|... // ^ ^ ^ ^ 4 5 assert_eq!(map.find_offset(Size::ZERO), Ok(0)); @@ -219,7 +222,7 @@ mod tests { // |#|#|#|#|@|@|@|@|_|... // 0 1 2 3 4 5 6 7 8 - map.insert(1, alloc_range(four, four), "@"); + map.insert_at_pos(1, alloc_range(four, four), "@"); // |#|#|#|#|@|@|@|@|_|... // 0 1 2 3 ^ ^ ^ ^ 8 assert_eq!(map.find_offset(four), Ok(1)); @@ -234,7 +237,7 @@ mod tests { // |_|_|_|_|#|#|#|#|_|_|_|_|... // 0 1 2 3 4 5 6 7 8 9 a b c d - map.insert(0, alloc_range(four, four), "#"); + map.insert_at_pos(0, alloc_range(four, four), "#"); // |_|_|_|_|#|#|#|#|_|_|_|_|... // 0 1 ^ ^ ^ ^ 6 7 8 9 a b c d assert_eq!( @@ -256,7 +259,7 @@ mod tests { // |_|_|_|_|#|#|#|#|_|_|@|@|_|_|... // 0 1 2 3 4 5 6 7 8 9 a b c d - map.insert(1, alloc_range(Size::from_bytes(10), Size::from_bytes(2)), "@"); + map.insert_at_pos(1, alloc_range(Size::from_bytes(10), Size::from_bytes(2)), "@"); // |_|_|_|_|#|#|#|#|_|_|@|@|_|_|... // 0 1 2 3 4 5 ^ ^ ^ ^ ^ ^ ^ ^ assert_eq!( diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index a796b56e2c0a..bd4ae06892bd 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -120,27 +120,27 @@ impl StoreBufferAlloc { range: AllocRange, ) -> InterpResult<'tcx, Ref<'_, StoreBuffer>> { let access_type = self.store_buffer.borrow().access_type(range); - let index = match access_type { - AccessType::PerfectlyOverlapping(index) => index, - AccessType::Empty(index) => { + let pos = match access_type { + AccessType::PerfectlyOverlapping(pos) => pos, + AccessType::Empty(pos) => { // First atomic access on this range, allocate a new StoreBuffer let mut buffer = self.store_buffer.borrow_mut(); - buffer.insert(index, range, StoreBuffer::default()); - index + buffer.insert_at_pos(pos, range, StoreBuffer::default()); + pos } - AccessType::ImperfectlyOverlapping(index_range) => { + AccessType::ImperfectlyOverlapping(pos_range) => { // Accesses that imperfectly overlaps with existing atomic objects // do not have well-defined behaviours. // FIXME: if this access happens before all previous accesses on every object it overlaps // with, then we would like to tolerate it. However this is not easy to check. - if index_range.start + 1 == index_range.end { + if pos_range.start + 1 == pos_range.end { throw_ub_format!("mixed-size access on an existing atomic object"); } else { throw_ub_format!("access overlaps with multiple existing atomic objects"); } } }; - Ok(Ref::map(self.store_buffer.borrow(), |buffer| &buffer[index])) + Ok(Ref::map(self.store_buffer.borrow(), |buffer| &buffer[pos])) } /// Gets a mutable store buffer associated with an atomic object in this allocation @@ -150,21 +150,21 @@ impl StoreBufferAlloc { ) -> InterpResult<'tcx, &mut StoreBuffer> { let buffer = self.store_buffer.get_mut(); let access_type = buffer.access_type(range); - let index = match access_type { - AccessType::PerfectlyOverlapping(index) => index, - AccessType::Empty(index) => { - buffer.insert(index, range, StoreBuffer::default()); - index + let pos = match access_type { + AccessType::PerfectlyOverlapping(pos) => pos, + AccessType::Empty(pos) => { + buffer.insert_at_pos(pos, range, StoreBuffer::default()); + pos } - AccessType::ImperfectlyOverlapping(index_range) => { - if index_range.start + 1 == index_range.end { + AccessType::ImperfectlyOverlapping(pos_range) => { + if pos_range.start + 1 == pos_range.end { throw_ub_format!("mixed-size access on an existing atomic object"); } else { throw_ub_format!("access overlaps with multiple existing atomic objects"); } } }; - Ok(&mut buffer[index]) + Ok(&mut buffer[pos]) } } From 92145373c350d1e41b852aa0332218f614a85bc3 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Mon, 16 May 2022 23:05:36 +0100 Subject: [PATCH 3217/5092] Put the initialisation value into the store buffer --- src/concurrency/data_race.rs | 26 +++-- src/concurrency/weak_memory.rs | 115 ++++++++++++++-------- tests/run-pass/weak_memory/consistency.rs | 13 ++- tests/run-pass/weak_memory/weak.rs | 36 ++++++- 4 files changed, 137 insertions(+), 53 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 22b72dadade7..2d69d02a100f 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -533,7 +533,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let this = self.eval_context_mut(); this.allow_data_races_mut(move |this| this.write_scalar(val, &(*dest).into()))?; this.validate_atomic_store(dest, atomic)?; - this.buffered_atomic_write(val, dest, atomic) + // FIXME: it's not possible to get the value before write_scalar. A read_scalar will cause + // side effects from a read the program did not perform. So we have to initialise + // the store buffer with the value currently being written + // ONCE this is fixed please remove the hack in buffered_atomic_write() in weak_memory.rs + this.buffered_atomic_write(val, dest, atomic, val) } /// Perform an atomic operation on a memory location. @@ -556,7 +560,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { this.validate_atomic_rmw(place, atomic)?; - this.buffered_atomic_rmw(val.to_scalar_or_uninit(), place, atomic)?; + this.buffered_atomic_rmw( + val.to_scalar_or_uninit(), + place, + atomic, + old.to_scalar_or_uninit(), + )?; Ok(old) } @@ -575,7 +584,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { this.validate_atomic_rmw(place, atomic)?; - this.buffered_atomic_rmw(new, place, atomic)?; + this.buffered_atomic_rmw(new, place, atomic, old)?; Ok(old) } @@ -603,7 +612,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { this.validate_atomic_rmw(place, atomic)?; - this.buffered_atomic_rmw(new_val.to_scalar_or_uninit(), place, atomic)?; + this.buffered_atomic_rmw( + new_val.to_scalar_or_uninit(), + place, + atomic, + old.to_scalar_or_uninit(), + )?; // Return the old value. Ok(old) @@ -654,14 +668,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { if cmpxchg_success { this.allow_data_races_mut(|this| this.write_scalar(new, &(*place).into()))?; this.validate_atomic_rmw(place, success)?; - this.buffered_atomic_rmw(new, place, success)?; + this.buffered_atomic_rmw(new, place, success, old.to_scalar_or_uninit())?; } else { this.validate_atomic_load(place, fail)?; // A failed compare exchange is equivalent to a load, reading from the latest store // in the modification order. // Since `old` is only a value and not the store element, we need to separately // find it in our store buffer and perform load_impl on it. - this.perform_read_on_buffered_latest(place, fail)?; + this.perform_read_on_buffered_latest(place, fail, old.to_scalar_or_uninit())?; } // Return the old value. diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index bd4ae06892bd..1cb9fba71526 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -81,11 +81,11 @@ const STORE_BUFFER_LIMIT: usize = 128; pub struct StoreBufferAlloc { /// Store buffer of each atomic object in this allocation // Behind a RefCell because we need to allocate/remove on read access - store_buffer: RefCell>, + store_buffers: RefCell>, } #[derive(Debug, Clone, PartialEq, Eq)] -struct StoreBuffer { +pub(super) struct StoreBuffer { // Stores to this location in modification order buffer: VecDeque, } @@ -111,21 +111,23 @@ struct StoreElement { impl StoreBufferAlloc { pub fn new_allocation() -> Self { - Self { store_buffer: RefCell::new(AllocationMap::new()) } + Self { store_buffers: RefCell::new(AllocationMap::new()) } } /// Gets a store buffer associated with an atomic object in this allocation - fn get_store_buffer<'tcx>( + /// Or creates one with the specified initial value + fn get_or_create_store_buffer<'tcx>( &self, range: AllocRange, + init: ScalarMaybeUninit, ) -> InterpResult<'tcx, Ref<'_, StoreBuffer>> { - let access_type = self.store_buffer.borrow().access_type(range); + let access_type = self.store_buffers.borrow().access_type(range); let pos = match access_type { AccessType::PerfectlyOverlapping(pos) => pos, AccessType::Empty(pos) => { - // First atomic access on this range, allocate a new StoreBuffer - let mut buffer = self.store_buffer.borrow_mut(); - buffer.insert_at_pos(pos, range, StoreBuffer::default()); + let new_buffer = StoreBuffer::new(init); + let mut buffers = self.store_buffers.borrow_mut(); + buffers.insert_at_pos(pos, range, new_buffer); pos } AccessType::ImperfectlyOverlapping(pos_range) => { @@ -140,20 +142,22 @@ impl StoreBufferAlloc { } } }; - Ok(Ref::map(self.store_buffer.borrow(), |buffer| &buffer[pos])) + Ok(Ref::map(self.store_buffers.borrow(), |buffer| &buffer[pos])) } /// Gets a mutable store buffer associated with an atomic object in this allocation - fn get_store_buffer_mut<'tcx>( + fn get_or_create_store_buffer_mut<'tcx>( &mut self, range: AllocRange, + init: ScalarMaybeUninit, ) -> InterpResult<'tcx, &mut StoreBuffer> { - let buffer = self.store_buffer.get_mut(); - let access_type = buffer.access_type(range); + let buffers = self.store_buffers.get_mut(); + let access_type = buffers.access_type(range); let pos = match access_type { AccessType::PerfectlyOverlapping(pos) => pos, AccessType::Empty(pos) => { - buffer.insert_at_pos(pos, range, StoreBuffer::default()); + let new_buffer = StoreBuffer::new(init); + buffers.insert_at_pos(pos, range, new_buffer); pos } AccessType::ImperfectlyOverlapping(pos_range) => { @@ -164,19 +168,28 @@ impl StoreBufferAlloc { } } }; - Ok(&mut buffer[pos]) - } -} - -impl Default for StoreBuffer { - fn default() -> Self { - let mut buffer = VecDeque::new(); - buffer.reserve(STORE_BUFFER_LIMIT); - Self { buffer } + Ok(&mut buffers[pos]) } } impl<'mir, 'tcx: 'mir> StoreBuffer { + fn new(init: ScalarMaybeUninit) -> Self { + let mut buffer = VecDeque::new(); + buffer.reserve(STORE_BUFFER_LIMIT); + let mut ret = Self { buffer }; + let store_elem = StoreElement { + // The thread index and timestamp of the initialisation write + // are never meaningfully used, so it's fine to leave them as 0 + store_index: VectorIdx::from(0), + timestamp: 0, + val: init, + is_seqcst: false, + loads: RefCell::new(FxHashMap::default()), + }; + ret.buffer.push_back(store_elem); + ret + } + /// Reads from the last store in modification order fn read_from_last_store(&self, global: &GlobalState) { let store_elem = self.buffer.back(); @@ -192,7 +205,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { is_seqcst: bool, rng: &mut (impl rand::Rng + ?Sized), validate: impl FnOnce() -> InterpResult<'tcx>, - ) -> InterpResult<'tcx, Option>> { + ) -> InterpResult<'tcx, ScalarMaybeUninit> { // Having a live borrow to store_buffer while calling validate_atomic_load is fine // because the race detector doesn't touch store_buffer @@ -210,10 +223,8 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { // requires access to ThreadClockSet.clock, which is updated by the race detector validate()?; - let loaded = store_elem.map(|store_elem| { - let (index, clocks) = global.current_thread_state(); - store_elem.load_impl(index, &clocks) - }); + let (index, clocks) = global.current_thread_state(); + let loaded = store_elem.load_impl(index, &clocks); Ok(loaded) } @@ -230,23 +241,18 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { } /// Selects a valid store element in the buffer. - /// The buffer does not contain the value used to initialise the atomic object - /// so a fresh atomic object has an empty store buffer and this function - /// will return `None`. In this case, the caller should ensure that the non-buffered - /// value from `MiriEvalContext::read_scalar()` is observed by the program, which is - /// the initial value of the atomic object. `MiriEvalContext::read_scalar()` is always - /// the latest value in modification order so it is always correct to be observed by any thread. fn fetch_store( &self, is_seqcst: bool, clocks: &ThreadClockSet, rng: &mut R, - ) -> Option<&StoreElement> { + ) -> &StoreElement { use rand::seq::IteratorRandom; let mut found_sc = false; - // FIXME: this should be an inclusive take_while (stops after a false predicate, but + // FIXME: we want an inclusive take_while (stops after a false predicate, but // includes the element that gave the false), but such function doesn't yet // exist in the standard libary https://github.com/rust-lang/rust/issues/62208 + // so we have to hack around it with keep_searching let mut keep_searching = true; let candidates = self .buffer @@ -303,7 +309,9 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { } }); - candidates.choose(rng) + candidates + .choose(rng) + .expect("store buffer cannot be empty, an element is populated on construction") } /// ATOMIC STORE IMPL in the paper (except we don't need the location's vector clock) @@ -366,6 +374,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: new_val: ScalarMaybeUninit, place: &MPlaceTy<'tcx, Tag>, atomic: AtomicRwOp, + init: ScalarMaybeUninit, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; @@ -379,7 +388,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: global.sc_write(); } let range = alloc_range(base_offset, place.layout.size); - let buffer = alloc_buffers.get_store_buffer_mut(range)?; + let buffer = alloc_buffers.get_or_create_store_buffer_mut(range, init)?; buffer.read_from_last_store(global); buffer.buffered_write(new_val, global, atomic == AtomicRwOp::SeqCst)?; } @@ -401,8 +410,10 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: global.sc_read(); } let mut rng = this.machine.rng.borrow_mut(); - let buffer = - alloc_buffers.get_store_buffer(alloc_range(base_offset, place.layout.size))?; + let buffer = alloc_buffers.get_or_create_store_buffer( + alloc_range(base_offset, place.layout.size), + latest_in_mo, + )?; let loaded = buffer.buffered_read( global, atomic == AtomicReadOp::SeqCst, @@ -410,7 +421,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: validate, )?; - return Ok(loaded.unwrap_or(latest_in_mo)); + return Ok(loaded); } } @@ -424,6 +435,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: val: ScalarMaybeUninit, dest: &MPlaceTy<'tcx, Tag>, atomic: AtomicWriteOp, + init: ScalarMaybeUninit, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(dest.ptr)?; @@ -435,8 +447,23 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: if atomic == AtomicWriteOp::SeqCst { global.sc_write(); } - let buffer = - alloc_buffers.get_store_buffer_mut(alloc_range(base_offset, dest.layout.size))?; + + // UGLY HACK: in write_scalar_atomic() we don't know the value before our write, + // so init == val always. If the buffer is fresh then we would've duplicated an entry, + // so we need to remove it. + let was_empty = matches!( + alloc_buffers + .store_buffers + .borrow() + .access_type(alloc_range(base_offset, dest.layout.size)), + AccessType::Empty(_) + ); + let buffer = alloc_buffers + .get_or_create_store_buffer_mut(alloc_range(base_offset, dest.layout.size), init)?; + if was_empty { + buffer.buffer.pop_front(); + } + buffer.buffered_write(val, global, atomic == AtomicWriteOp::SeqCst)?; } @@ -451,6 +478,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: &self, place: &MPlaceTy<'tcx, Tag>, atomic: AtomicReadOp, + init: ScalarMaybeUninit, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); @@ -461,7 +489,8 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let size = place.layout.size; let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { - let buffer = alloc_buffers.get_store_buffer(alloc_range(base_offset, size))?; + let buffer = alloc_buffers + .get_or_create_store_buffer(alloc_range(base_offset, size), init)?; buffer.read_from_last_store(global); } } diff --git a/tests/run-pass/weak_memory/consistency.rs b/tests/run-pass/weak_memory/consistency.rs index 8705d0bc6781..67f0e8d35dd3 100644 --- a/tests/run-pass/weak_memory/consistency.rs +++ b/tests/run-pass/weak_memory/consistency.rs @@ -34,8 +34,6 @@ unsafe impl Sync for EvilSend {} // multiple times fn static_atomic(val: usize) -> &'static AtomicUsize { let ret = Box::leak(Box::new(AtomicUsize::new(val))); - // A workaround to put the initialisation value in the store buffer - ret.store(val, Relaxed); ret } @@ -205,8 +203,19 @@ fn test_sc_store_buffering() { assert_ne!((a, b), (0, 0)); } +fn test_single_thread() { + let x = AtomicUsize::new(42); + + assert_eq!(x.load(Relaxed), 42); + + x.store(43, Relaxed); + + assert_eq!(x.load(Relaxed), 43); +} + pub fn main() { for _ in 0..100 { + test_single_thread(); test_mixed_access(); test_load_buffering_acq_rel(); test_message_passing(); diff --git a/tests/run-pass/weak_memory/weak.rs b/tests/run-pass/weak_memory/weak.rs index ab0c20cc9772..75380381922d 100644 --- a/tests/run-pass/weak_memory/weak.rs +++ b/tests/run-pass/weak_memory/weak.rs @@ -22,11 +22,17 @@ unsafe impl Sync for EvilSend {} // multiple times fn static_atomic(val: usize) -> &'static AtomicUsize { let ret = Box::leak(Box::new(AtomicUsize::new(val))); - // A workaround to put the initialisation value in the store buffer - ret.store(val, Relaxed); ret } +// Spins until it reads the given value +fn reads_value(loc: &AtomicUsize, val: usize) -> usize { + while loc.load(Relaxed) != val { + std::hint::spin_loop(); + } + val +} + fn relaxed() -> bool { let x = static_atomic(0); let j1 = spawn(move || { @@ -64,6 +70,31 @@ fn seq_cst() -> bool { r3 == 1 } +fn initialization_write() -> bool { + let x = static_atomic(11); + assert_eq!(x.load(Relaxed), 11); + + let wait = static_atomic(0); + + let j1 = spawn(move || { + x.store(22, Relaxed); + // Relaxed is intentional. We want to test if the thread 2 reads the initialisation write + // after a relaxed write + wait.store(1, Relaxed); + }); + + let j2 = spawn(move || { + reads_value(wait, 1); + x.load(Relaxed) + }); + + j1.join().unwrap(); + let r2 = j2.join().unwrap(); + + r2 == 11 +} + + // Asserts that the function returns true at least once in 100 runs macro_rules! assert_once { ($f:ident) => { @@ -74,4 +105,5 @@ macro_rules! assert_once { pub fn main() { assert_once!(relaxed); assert_once!(seq_cst); + assert_once!(initialization_write); } From e2002b4c657b218d3866342078b5fd0ce3118021 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Tue, 17 May 2022 00:14:30 +0100 Subject: [PATCH 3218/5092] Amend experimental thread support warnings --- src/shims/unix/thread.rs | 2 +- tests/pass/concurrency/channels.stderr | 2 +- tests/pass/concurrency/concurrent_caller_location.stderr | 2 +- tests/pass/concurrency/data_race.stderr | 2 +- tests/pass/concurrency/disable_data_race_detector.stderr | 2 +- tests/pass/concurrency/issue1643.stderr | 2 +- tests/pass/concurrency/linux-futex.stderr | 2 +- tests/pass/concurrency/simple.stderr | 2 +- tests/pass/concurrency/sync.stderr | 2 +- tests/pass/concurrency/thread_locals.stderr | 2 +- tests/pass/concurrency/tls_lib_drop.stderr | 2 +- tests/pass/libc.stderr | 2 +- tests/pass/panic/concurrent-panic.stderr | 2 +- tests/pass/threadleak_ignored.stderr | 2 +- tests/run-pass/weak_memory/consistency.stderr | 2 +- tests/run-pass/weak_memory/weak.stderr | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/shims/unix/thread.rs b/src/shims/unix/thread.rs index 88c3fb0bc8ea..812cb7376b71 100644 --- a/src/shims/unix/thread.rs +++ b/src/shims/unix/thread.rs @@ -14,7 +14,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.tcx.sess.warn( - "thread support is experimental and incomplete: weak memory effects are not emulated.", + "thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model.", ); // Create the new thread diff --git a/tests/pass/concurrency/channels.stderr b/tests/pass/concurrency/channels.stderr index 03676519d4f1..1d0ce4b3853d 100644 --- a/tests/pass/concurrency/channels.stderr +++ b/tests/pass/concurrency/channels.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. diff --git a/tests/pass/concurrency/concurrent_caller_location.stderr b/tests/pass/concurrency/concurrent_caller_location.stderr index 03676519d4f1..1d0ce4b3853d 100644 --- a/tests/pass/concurrency/concurrent_caller_location.stderr +++ b/tests/pass/concurrency/concurrent_caller_location.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. diff --git a/tests/pass/concurrency/data_race.stderr b/tests/pass/concurrency/data_race.stderr index 03676519d4f1..1d0ce4b3853d 100644 --- a/tests/pass/concurrency/data_race.stderr +++ b/tests/pass/concurrency/data_race.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. diff --git a/tests/pass/concurrency/disable_data_race_detector.stderr b/tests/pass/concurrency/disable_data_race_detector.stderr index 03676519d4f1..1d0ce4b3853d 100644 --- a/tests/pass/concurrency/disable_data_race_detector.stderr +++ b/tests/pass/concurrency/disable_data_race_detector.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. diff --git a/tests/pass/concurrency/issue1643.stderr b/tests/pass/concurrency/issue1643.stderr index 03676519d4f1..1d0ce4b3853d 100644 --- a/tests/pass/concurrency/issue1643.stderr +++ b/tests/pass/concurrency/issue1643.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. diff --git a/tests/pass/concurrency/linux-futex.stderr b/tests/pass/concurrency/linux-futex.stderr index 03676519d4f1..1d0ce4b3853d 100644 --- a/tests/pass/concurrency/linux-futex.stderr +++ b/tests/pass/concurrency/linux-futex.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. diff --git a/tests/pass/concurrency/simple.stderr b/tests/pass/concurrency/simple.stderr index bb60638bd683..386dc922691a 100644 --- a/tests/pass/concurrency/simple.stderr +++ b/tests/pass/concurrency/simple.stderr @@ -1,4 +1,4 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. thread '' panicked at 'Hello!', $DIR/simple.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/pass/concurrency/sync.stderr b/tests/pass/concurrency/sync.stderr index 03676519d4f1..1d0ce4b3853d 100644 --- a/tests/pass/concurrency/sync.stderr +++ b/tests/pass/concurrency/sync.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. diff --git a/tests/pass/concurrency/thread_locals.stderr b/tests/pass/concurrency/thread_locals.stderr index 03676519d4f1..1d0ce4b3853d 100644 --- a/tests/pass/concurrency/thread_locals.stderr +++ b/tests/pass/concurrency/thread_locals.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. diff --git a/tests/pass/concurrency/tls_lib_drop.stderr b/tests/pass/concurrency/tls_lib_drop.stderr index 03676519d4f1..1d0ce4b3853d 100644 --- a/tests/pass/concurrency/tls_lib_drop.stderr +++ b/tests/pass/concurrency/tls_lib_drop.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. diff --git a/tests/pass/libc.stderr b/tests/pass/libc.stderr index 03676519d4f1..1d0ce4b3853d 100644 --- a/tests/pass/libc.stderr +++ b/tests/pass/libc.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. diff --git a/tests/pass/panic/concurrent-panic.stderr b/tests/pass/panic/concurrent-panic.stderr index ae132c9ee348..0d4a409dfecf 100644 --- a/tests/pass/panic/concurrent-panic.stderr +++ b/tests/pass/panic/concurrent-panic.stderr @@ -1,4 +1,4 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. Thread 1 starting, will block on mutex Thread 1 reported it has started diff --git a/tests/pass/threadleak_ignored.stderr b/tests/pass/threadleak_ignored.stderr index aa037511853b..9205eb70b207 100644 --- a/tests/pass/threadleak_ignored.stderr +++ b/tests/pass/threadleak_ignored.stderr @@ -1,3 +1,3 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. Dropping 0 diff --git a/tests/run-pass/weak_memory/consistency.stderr b/tests/run-pass/weak_memory/consistency.stderr index 03676519d4f1..1d0ce4b3853d 100644 --- a/tests/run-pass/weak_memory/consistency.stderr +++ b/tests/run-pass/weak_memory/consistency.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. diff --git a/tests/run-pass/weak_memory/weak.stderr b/tests/run-pass/weak_memory/weak.stderr index 03676519d4f1..1d0ce4b3853d 100644 --- a/tests/run-pass/weak_memory/weak.stderr +++ b/tests/run-pass/weak_memory/weak.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. From 31c01415cbb1793ae9492f40bbdd917cfe8d1fa5 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Tue, 17 May 2022 20:04:18 +0100 Subject: [PATCH 3219/5092] Replace yield_now() with spin loop hint --- tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs | 6 +++--- tests/run-pass/weak_memory/consistency.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs b/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs index b9e395fd7741..423d0e0e8ffb 100644 --- a/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs +++ b/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs @@ -9,13 +9,13 @@ // so we have to stick to C++11 emulation from exiting research. use std::sync::atomic::Ordering::*; -use std::thread::{spawn, yield_now}; +use std::thread::spawn; use std::sync::atomic::{fence, AtomicUsize}; -// Spins and yields until until it reads value +// Spins until it reads value fn reads_value(loc: &AtomicUsize, val: usize) -> usize { while loc.load(Relaxed) != val { - yield_now(); + std::hint::spin_loop(); } val } diff --git a/tests/run-pass/weak_memory/consistency.rs b/tests/run-pass/weak_memory/consistency.rs index 67f0e8d35dd3..fa13803830f5 100644 --- a/tests/run-pass/weak_memory/consistency.rs +++ b/tests/run-pass/weak_memory/consistency.rs @@ -22,7 +22,7 @@ use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::*; -use std::thread::{spawn, yield_now}; +use std::thread::spawn; #[derive(Copy, Clone)] struct EvilSend(pub T); @@ -37,10 +37,10 @@ fn static_atomic(val: usize) -> &'static AtomicUsize { ret } -// Spins and yields until until acquires a pre-determined value +// Spins until acquires a pre-determined value fn acquires_value(loc: &AtomicUsize, val: usize) -> usize { while loc.load(Acquire) != val { - yield_now(); + std::hint::spin_loop(); } val } From 5ddd4eff0382ba454e8123c663f9e11c14597f79 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Thu, 19 May 2022 20:14:16 +0100 Subject: [PATCH 3220/5092] Spelling, punctuation and grammar Co-authored-by: Ralf Jung --- README.md | 2 +- tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs | 8 ++++---- tests/run-pass/weak_memory/consistency.rs | 2 +- tests/run-pass/weak_memory/weak.rs | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index ece45fca128c..938a64cd045b 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ for example: * **Experimental**: Violations of the [Stacked Borrows] rules governing aliasing for reference types * **Experimental**: Data races -* **Experimental**: Weak memory emulation +* **Experimental**: Emulation of weak memory effects (i.e., reads can return outdated values) On top of that, Miri will also tell you about memory leaks: when there is memory still allocated at the end of the execution, and that memory is not reachable diff --git a/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs b/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs index 423d0e0e8ffb..34097f4a8937 100644 --- a/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs +++ b/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs @@ -4,15 +4,15 @@ // https://plv.mpi-sws.org/scfix/paper.pdf // 2.2 Second Problem: SC Fences are Too Weak // This test should pass under the C++20 model Rust is using. -// Unfortunately, Miri's weak memory emulation only follows C++11 model +// Unfortunately, Miri's weak memory emulation only follows the C++11 model // as we don't know how to correctly emulate C++20's revised SC semantics, -// so we have to stick to C++11 emulation from exiting research. +// so we have to stick to C++11 emulation from existing research. use std::sync::atomic::Ordering::*; use std::thread::spawn; use std::sync::atomic::{fence, AtomicUsize}; -// Spins until it reads value +// Spins until it reads the given value fn reads_value(loc: &AtomicUsize, val: usize) -> usize { while loc.load(Relaxed) != val { std::hint::spin_loop(); @@ -24,7 +24,7 @@ fn reads_value(loc: &AtomicUsize, val: usize) -> usize { // multiple tests fn static_atomic(val: usize) -> &'static AtomicUsize { let ret = Box::leak(Box::new(AtomicUsize::new(val))); - // A workaround to put the initialisation value in the store buffer + // A workaround to put the initialization value in the store buffer. ret.store(val, Relaxed); ret } diff --git a/tests/run-pass/weak_memory/consistency.rs b/tests/run-pass/weak_memory/consistency.rs index fa13803830f5..8a7c1340cc59 100644 --- a/tests/run-pass/weak_memory/consistency.rs +++ b/tests/run-pass/weak_memory/consistency.rs @@ -37,7 +37,7 @@ fn static_atomic(val: usize) -> &'static AtomicUsize { ret } -// Spins until acquires a pre-determined value +// Spins until it acquires a pre-determined value. fn acquires_value(loc: &AtomicUsize, val: usize) -> usize { while loc.load(Acquire) != val { std::hint::spin_loop(); diff --git a/tests/run-pass/weak_memory/weak.rs b/tests/run-pass/weak_memory/weak.rs index 75380381922d..70e1bf00f442 100644 --- a/tests/run-pass/weak_memory/weak.rs +++ b/tests/run-pass/weak_memory/weak.rs @@ -6,7 +6,7 @@ // This is scheduler and pseudo-RNG dependent, so each test is // run multiple times until one try returns true. // Spurious failure is possible, if you are really unlucky with -// the RNG. +// the RNG and always read the latest value from the store buffer. use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::*; From 6d27f188c21f98ff9d8f2f252becb18df27d6c4a Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 22 May 2022 22:07:50 +0100 Subject: [PATCH 3221/5092] Update src/concurrency/weak_memory.rs Co-authored-by: Ralf Jung --- src/concurrency/weak_memory.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index 1cb9fba71526..51092478c3fd 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -102,6 +102,9 @@ struct StoreElement { /// The timestamp of the storing thread when it performed the store timestamp: VTimestamp, /// The value of this store + // FIXME: this means the store is either fully initialized or fully uninitialized; + // we will have to change this if we want to support atomics on + // partially initialized data. val: ScalarMaybeUninit, /// Timestamp of first loads from this store element by each thread From dafd813c16231834d3bce7875a8c616d1e49a8c1 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 22 May 2022 22:18:22 +0100 Subject: [PATCH 3222/5092] Move transmute into a separate function --- .../weak_memory/imperfectly_overlapping.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/tests/compile-fail/weak_memory/imperfectly_overlapping.rs b/tests/compile-fail/weak_memory/imperfectly_overlapping.rs index e3f89b5b684f..6f91e147fa83 100644 --- a/tests/compile-fail/weak_memory/imperfectly_overlapping.rs +++ b/tests/compile-fail/weak_memory/imperfectly_overlapping.rs @@ -6,21 +6,26 @@ use std::intrinsics::atomic_load; use std::sync::atomic::Ordering::*; use std::sync::atomic::{AtomicU16, AtomicU32}; +fn split_u32(dword: &mut u32) -> &mut [u16; 2] { + unsafe { std::mem::transmute::<&mut u32, &mut [u16; 2]>(dword) } +} + fn test_same_thread() { - let mut qword = AtomicU32::new(42); - assert_eq!(qword.load(Relaxed), 42); - qword.store(0xabbafafa, Relaxed); + let mut dword = AtomicU32::new(42); + assert_eq!(dword.load(Relaxed), 42); + dword.store(0xabbafafa, Relaxed); - let qword_mut = qword.get_mut(); + let dword_mut = dword.get_mut(); - let dwords_mut = unsafe { std::mem::transmute::<&mut u32, &mut [u16; 2]>(qword_mut) }; + let words_mut = split_u32(dword_mut); - let (hi_mut, lo_mut) = dwords_mut.split_at_mut(1); + let (hi_mut, lo_mut) = words_mut.split_at_mut(1); let (hi, _) = (AtomicU16::from_mut(&mut hi_mut[0]), AtomicU16::from_mut(&mut lo_mut[0])); unsafe { - //Equivalent to: hi.load(Ordering::SeqCst) + // Equivalent to: hi.load(Ordering::SeqCst) + // We need to use intrisics to for precise error location atomic_load(hi.get_mut() as *mut u16); //~ ERROR: mixed-size access on an existing atomic object } } From 7dcb19ead429e526afac7800a0b90f2b39cfa4f1 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Mon, 23 May 2022 22:05:16 +0100 Subject: [PATCH 3223/5092] Add rust-only operation tests --- .../weak_memory/imperfectly_overlapping.rs | 35 -------- tests/run-pass/weak_memory/extra_cpp.rs | 79 +++++++++++++++++++ tests/run-pass/weak_memory/extra_cpp.stderr | 2 + 3 files changed, 81 insertions(+), 35 deletions(-) delete mode 100644 tests/compile-fail/weak_memory/imperfectly_overlapping.rs create mode 100644 tests/run-pass/weak_memory/extra_cpp.rs create mode 100644 tests/run-pass/weak_memory/extra_cpp.stderr diff --git a/tests/compile-fail/weak_memory/imperfectly_overlapping.rs b/tests/compile-fail/weak_memory/imperfectly_overlapping.rs deleted file mode 100644 index 6f91e147fa83..000000000000 --- a/tests/compile-fail/weak_memory/imperfectly_overlapping.rs +++ /dev/null @@ -1,35 +0,0 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -#![feature(atomic_from_mut)] -#![feature(core_intrinsics)] - -use std::intrinsics::atomic_load; -use std::sync::atomic::Ordering::*; -use std::sync::atomic::{AtomicU16, AtomicU32}; - -fn split_u32(dword: &mut u32) -> &mut [u16; 2] { - unsafe { std::mem::transmute::<&mut u32, &mut [u16; 2]>(dword) } -} - -fn test_same_thread() { - let mut dword = AtomicU32::new(42); - assert_eq!(dword.load(Relaxed), 42); - dword.store(0xabbafafa, Relaxed); - - let dword_mut = dword.get_mut(); - - let words_mut = split_u32(dword_mut); - - let (hi_mut, lo_mut) = words_mut.split_at_mut(1); - - let (hi, _) = (AtomicU16::from_mut(&mut hi_mut[0]), AtomicU16::from_mut(&mut lo_mut[0])); - - unsafe { - // Equivalent to: hi.load(Ordering::SeqCst) - // We need to use intrisics to for precise error location - atomic_load(hi.get_mut() as *mut u16); //~ ERROR: mixed-size access on an existing atomic object - } -} - -pub fn main() { - test_same_thread(); -} diff --git a/tests/run-pass/weak_memory/extra_cpp.rs b/tests/run-pass/weak_memory/extra_cpp.rs new file mode 100644 index 000000000000..b20ec5834990 --- /dev/null +++ b/tests/run-pass/weak_memory/extra_cpp.rs @@ -0,0 +1,79 @@ +// compile-flags: -Zmiri-ignore-leaks + +// Tests operations not perfomable through C++'s atomic API +// but doable in safe (at least sound) Rust. + +#![feature(atomic_from_mut)] + +use std::sync::atomic::Ordering::*; +use std::sync::atomic::{AtomicU16, AtomicU32, AtomicUsize}; +use std::thread::spawn; + +fn static_atomic_mut(val: usize) -> &'static mut AtomicUsize { + let ret = Box::leak(Box::new(AtomicUsize::new(val))); + ret +} + +fn split_u32(dword: &mut u32) -> &mut [u16; 2] { + unsafe { std::mem::transmute::<&mut u32, &mut [u16; 2]>(dword) } +} + +fn mem_replace() { + let mut x = AtomicU32::new(0); + + let old_x = std::mem::replace(&mut x, AtomicU32::new(42)); + + assert_eq!(x.load(Relaxed), 42); + assert_eq!(old_x.load(Relaxed), 0); +} + +fn assign_to_mut() { + let x = static_atomic_mut(0); + x.store(1, Relaxed); + + *x = AtomicUsize::new(2); + + assert_eq!(x.load(Relaxed), 2); +} + +fn get_mut_write() { + let x = static_atomic_mut(0); + x.store(1, Relaxed); + { + let x_mut = x.get_mut(); + *x_mut = 2; + } + + let j1 = spawn(move || x.load(Relaxed)); + + let r1 = j1.join().unwrap(); + assert_eq!(r1, 2); +} + +// This is technically doable in C++ with atomic_ref +// but little literature exists atm on its involvement +// in mixed size/atomicity accesses +fn from_mut_split() { + let mut x: u32 = 0; + + { + let x_atomic = AtomicU32::from_mut(&mut x); + x_atomic.store(u32::from_be(0xabbafafa), Relaxed); + } + + let (x_hi, x_lo) = split_u32(&mut x).split_at_mut(1); + + let x_hi_atomic = AtomicU16::from_mut(&mut x_hi[0]); + let x_lo_atomic = AtomicU16::from_mut(&mut x_lo[0]); + + assert_eq!(x_hi_atomic.load(Relaxed), u16::from_be(0xabba)); + assert_eq!(x_lo_atomic.load(Relaxed), u16::from_be(0xfafa)); +} + + +pub fn main() { + get_mut_write(); + from_mut_split(); + assign_to_mut(); + mem_replace(); +} diff --git a/tests/run-pass/weak_memory/extra_cpp.stderr b/tests/run-pass/weak_memory/extra_cpp.stderr new file mode 100644 index 000000000000..1d0ce4b3853d --- /dev/null +++ b/tests/run-pass/weak_memory/extra_cpp.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. + From 2321b15342b05445ab7d7ac07a28382b454e0206 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Tue, 24 May 2022 21:07:22 +0100 Subject: [PATCH 3224/5092] Differentiate between not multithreading and temp disabling race detection --- src/concurrency/data_race.rs | 44 +++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 2d69d02a100f..7ac2ed615a11 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -445,14 +445,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { #[inline] fn allow_data_races_ref(&self, op: impl FnOnce(&MiriEvalContext<'mir, 'tcx>) -> R) -> R { let this = self.eval_context_ref(); - let old = if let Some(data_race) = &this.machine.data_race { - data_race.multi_threaded.replace(false) - } else { - false - }; + if let Some(data_race) = &this.machine.data_race { + data_race.ongoing_atomic_access.set(true); + } let result = op(this); if let Some(data_race) = &this.machine.data_race { - data_race.multi_threaded.set(old); + data_race.ongoing_atomic_access.set(false); } result } @@ -466,14 +464,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { op: impl FnOnce(&mut MiriEvalContext<'mir, 'tcx>) -> R, ) -> R { let this = self.eval_context_mut(); - let old = if let Some(data_race) = &this.machine.data_race { - data_race.multi_threaded.replace(false) - } else { - false - }; + if let Some(data_race) = &this.machine.data_race { + data_race.ongoing_atomic_access.set(true); + } let result = op(this); if let Some(data_race) = &this.machine.data_race { - data_race.multi_threaded.set(old); + data_race.ongoing_atomic_access.set(false); } result } @@ -923,7 +919,7 @@ impl VClockAlloc { } /// Detect data-races for an unsynchronized read operation, will not perform - /// data-race detection if `multi-threaded` is false, either due to no threads + /// data-race detection if `race_detecting()` is false, either due to no threads /// being created or if it is temporarily disabled during a racy read or write /// operation for which data-race detection is handled separately, for example /// atomic read operations. @@ -933,7 +929,7 @@ impl VClockAlloc { range: AllocRange, global: &GlobalState, ) -> InterpResult<'tcx> { - if global.multi_threaded.get() { + if global.race_detecting() { let (index, clocks) = global.current_thread_state(); let mut alloc_ranges = self.alloc_ranges.borrow_mut(); for (offset, range) in alloc_ranges.iter_mut(range.start, range.size) { @@ -962,7 +958,7 @@ impl VClockAlloc { write_type: WriteType, global: &mut GlobalState, ) -> InterpResult<'tcx> { - if global.multi_threaded.get() { + if global.race_detecting() { let (index, clocks) = global.current_thread_state(); for (offset, range) in self.alloc_ranges.get_mut().iter_mut(range.start, range.size) { if let Err(DataRace) = range.write_race_detect(&*clocks, index, write_type) { @@ -983,7 +979,7 @@ impl VClockAlloc { } /// Detect data-races for an unsynchronized write operation, will not perform - /// data-race threads if `multi-threaded` is false, either due to no threads + /// data-race threads if `race_detecting()` is false, either due to no threads /// being created or if it is temporarily disabled during a racy read or write /// operation pub fn write<'tcx>( @@ -996,7 +992,7 @@ impl VClockAlloc { } /// Detect data-races for an unsynchronized deallocate operation, will not perform - /// data-race threads if `multi-threaded` is false, either due to no threads + /// data-race threads if `race_detecting()` is false, either due to no threads /// being created or if it is temporarily disabled during a racy read or write /// operation pub fn deallocate<'tcx>( @@ -1026,7 +1022,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); if let Some(data_race) = &this.machine.data_race { - if data_race.multi_threaded.get() { + if data_race.race_detecting() { let size = place.layout.size; let (alloc_id, base_offset, _tag) = this.ptr_get_alloc_id(place.ptr)?; // Load and log the atomic operation. @@ -1116,6 +1112,10 @@ pub struct GlobalState { /// any data-races. multi_threaded: Cell, + /// A flag to mark we are currently performing + /// an atomic access to supress data race detection + ongoing_atomic_access: Cell, + /// Mapping of a vector index to a known set of thread /// clocks, this is not directly mapping from a thread id /// since it may refer to multiple threads. @@ -1167,6 +1167,7 @@ impl GlobalState { pub fn new() -> Self { let mut global_state = GlobalState { multi_threaded: Cell::new(false), + ongoing_atomic_access: Cell::new(false), vector_clocks: RefCell::new(IndexVec::new()), vector_info: RefCell::new(IndexVec::new()), thread_info: RefCell::new(IndexVec::new()), @@ -1192,6 +1193,13 @@ impl GlobalState { global_state } + // We perform data race detection when there are more than 1 active thread + // and we are not currently in the middle of an atomic acces where data race + // is impossible + fn race_detecting(&self) -> bool { + self.multi_threaded.get() && !self.ongoing_atomic_access.get() + } + // Try to find vector index values that can potentially be re-used // by a new thread instead of a new vector index being created. fn find_vector_index_reuse_candidate(&self) -> Option { From 226ed41cca4cf83cd6afc18f0d3ce4ef2cdc8691 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Tue, 24 May 2022 22:03:04 +0100 Subject: [PATCH 3225/5092] Destroy store buffers on non-racy non-atomic accesses --- src/concurrency/allocation_map.rs | 8 ++++++++ src/concurrency/data_race.rs | 4 ++++ src/concurrency/weak_memory.rs | 28 ++++++++++++++++++++++++---- src/machine.rs | 23 +++++++++++++++++------ 4 files changed, 53 insertions(+), 10 deletions(-) diff --git a/src/concurrency/allocation_map.rs b/src/concurrency/allocation_map.rs index 2524389c0be8..62469dcaf43a 100644 --- a/src/concurrency/allocation_map.rs +++ b/src/concurrency/allocation_map.rs @@ -125,6 +125,14 @@ impl AllocationMap { debug_assert!(range.end() <= self.v[pos + 1].range.start); } } + + pub fn remove_pos_range(&mut self, pos_range: Range) { + self.v.drain(pos_range); + } + + pub fn remove_from_pos(&mut self, pos: Position) { + self.v.remove(pos); + } } impl Index for AllocationMap { diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 7ac2ed615a11..2483bcdf49a2 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -1200,6 +1200,10 @@ impl GlobalState { self.multi_threaded.get() && !self.ongoing_atomic_access.get() } + pub fn ongoing_atomic_access(&self) -> bool { + self.ongoing_atomic_access.get() + } + // Try to find vector index values that can potentially be re-used // by a new thread instead of a new vector index being created. fn find_vector_index_reuse_candidate(&self) -> Option { diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index 51092478c3fd..7d8d7da6dc4e 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -11,10 +11,10 @@ //! This implementation is not fully correct under the revised C++20 model and may generate behaviours C++20 //! disallows. //! -//! Rust follows the full C++20 memory model (except for the Consume ordering). It is therefore -//! possible for this implementation to generate behaviours never observable when the same program is compiled and -//! run natively. Unfortunately, no literature exists at the time of writing which proposes an implementable and C++20-compatible -//! relaxed memory model that supports all atomic operation existing in Rust. The closest one is +//! Rust follows the C++20 memory model (except for the Consume ordering and some operations not performable through C++'s +//! std::atomic API). It is therefore possible for this implementation to generate behaviours never observable when the +//! same program is compiled and run natively. Unfortunately, no literature exists at the time of writing which proposes +//! an implementable and C++20-compatible relaxed memory model that supports all atomic operation existing in Rust. The closest one is //! A Promising Semantics for Relaxed-Memory Concurrency by Jeehoon Kang et al. (https://www.cs.tau.ac.il/~orilahav/papers/popl17.pdf) //! However, this model lacks SC accesses and is therefore unusable by Miri (SC accesses are everywhere in library code). //! @@ -117,6 +117,26 @@ impl StoreBufferAlloc { Self { store_buffers: RefCell::new(AllocationMap::new()) } } + /// When a non-atomic access happens on a location that has been atomically accessed + /// before without data race, we can determine that the non-atomic access fully happens + /// before all the prior atomic accesses so the location no longer needs to exhibit + /// any weak memory behaviours until further atomic accesses. + pub fn destroy_atomicity<'tcx>(&self, range: AllocRange) { + let mut buffers = self.store_buffers.borrow_mut(); + let access_type = buffers.access_type(range); + match access_type { + AccessType::PerfectlyOverlapping(pos) => { + buffers.remove_from_pos(pos); + } + AccessType::ImperfectlyOverlapping(pos_range) => { + buffers.remove_pos_range(pos_range); + } + AccessType::Empty(_) => { + // Do nothing + } + } + } + /// Gets a store buffer associated with an atomic object in this allocation /// Or creates one with the specified initial value fn get_or_create_store_buffer<'tcx>( diff --git a/src/machine.rs b/src/machine.rs index 41c852747ad7..6dc2a75b69fd 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -738,10 +738,17 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { range, machine.stacked_borrows.as_ref().unwrap(), machine.current_span(), - ) - } else { - Ok(()) + )?; } + if let Some(weak_memory) = &alloc_extra.weak_memory { + if !machine.data_race.as_ref().unwrap().ongoing_atomic_access() { + // This is a non-atomic access. And if we are accessing a previously atomically + // accessed location without racing with them, then the location no longer needs + // to exhibit weak-memory behaviours until a fresh atomic access happens + weak_memory.destroy_atomicity(range); + } + } + Ok(()) } #[inline(always)] @@ -762,10 +769,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { range, machine.stacked_borrows.as_ref().unwrap(), machine.current_span(), - ) - } else { - Ok(()) + )?; } + if let Some(weak_memory) = &alloc_extra.weak_memory { + if !machine.data_race.as_ref().unwrap().ongoing_atomic_access() { + weak_memory.destroy_atomicity(range); + } + } + Ok(()) } #[inline(always)] From 613d60db0bc0bfac9c3ad57245fc09e08795a550 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Wed, 25 May 2022 20:46:08 +0100 Subject: [PATCH 3226/5092] Allow non-racy mixed size accesses --- src/concurrency/data_race.rs | 63 ++++++++++++- src/concurrency/weak_memory.rs | 92 +++++++++++++++---- .../weak_memory/cpp20_rwc_syncs.rs | 6 +- .../weak_memory/racing_mixed_size.rs | 38 ++++++++ tests/run-pass/weak_memory/extra_cpp.rs | 89 +++++++++++++++++- 5 files changed, 262 insertions(+), 26 deletions(-) create mode 100644 tests/compile-fail/weak_memory/racing_mixed_size.rs diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 2483bcdf49a2..8b8694ac1835 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -287,6 +287,20 @@ impl MemoryCellClocks { Ok(()) } + /// Checks if the memory cell write races with any prior atomic read or write + fn write_race_free_with_atomic(&mut self, clocks: &ThreadClockSet) -> bool { + if let Some(atomic) = self.atomic() { + atomic.read_vector <= clocks.clock && atomic.write_vector <= clocks.clock + } else { + true + } + } + + /// Checks if the memory cell read races with any prior atomic write + fn read_race_free_with_atomic(&self, clocks: &ThreadClockSet) -> bool { + if let Some(atomic) = self.atomic() { atomic.write_vector <= clocks.clock } else { true } + } + /// Update memory cell data-race tracking for atomic /// load relaxed semantics, is a no-op if this memory was /// not used previously as atomic memory. @@ -514,6 +528,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // the *value* (including the associated provenance if this is an AtomicPtr) at this location. // Only metadata on the location itself is used. let scalar = this.allow_data_races_ref(move |this| this.read_scalar(&place.into()))?; + this.validate_overlapping_atomic_read(place)?; this.buffered_atomic_read(place, atomic, scalar, || { this.validate_atomic_load(place, atomic) }) @@ -527,6 +542,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicWriteOp, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + this.validate_overlapping_atomic_write(dest)?; this.allow_data_races_mut(move |this| this.write_scalar(val, &(*dest).into()))?; this.validate_atomic_store(dest, atomic)?; // FIXME: it's not possible to get the value before write_scalar. A read_scalar will cause @@ -547,6 +563,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let this = self.eval_context_mut(); + this.validate_overlapping_atomic_write(place)?; let old = this.allow_data_races_mut(|this| this.read_immediate(&place.into()))?; // Atomics wrap around on overflow. @@ -575,6 +592,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_mut(); + this.validate_overlapping_atomic_write(place)?; let old = this.allow_data_races_mut(|this| this.read_scalar(&place.into()))?; this.allow_data_races_mut(|this| this.write_scalar(new, &(*place).into()))?; @@ -595,6 +613,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let this = self.eval_context_mut(); + this.validate_overlapping_atomic_write(place)?; let old = this.allow_data_races_mut(|this| this.read_immediate(&place.into()))?; let lt = this.binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar()?.to_bool()?; @@ -637,6 +656,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { use rand::Rng as _; let this = self.eval_context_mut(); + this.validate_overlapping_atomic_write(place)?; // Failure ordering cannot be stronger than success ordering, therefore first attempt // to read with the failure ordering and if successful then try again with the success // read ordering and write in the success case. @@ -686,6 +706,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicReadOp, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); + this.validate_overlapping_atomic_read(place)?; this.validate_atomic_op( place, atomic, @@ -708,6 +729,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicWriteOp, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + this.validate_overlapping_atomic_write(place)?; this.validate_atomic_op( place, atomic, @@ -733,6 +755,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); let release = matches!(atomic, Release | AcqRel | SeqCst); let this = self.eval_context_mut(); + this.validate_overlapping_atomic_write(place)?; this.validate_atomic_op(place, atomic, "Atomic RMW", move |memory, clocks, index, _| { if acquire { memory.load_acquire(clocks, index)?; @@ -918,6 +941,44 @@ impl VClockAlloc { ) } + /// Detect racing atomic writes (not data races) + /// on every byte of the current access range + pub(super) fn read_race_free_with_atomic<'tcx>( + &self, + range: AllocRange, + global: &GlobalState, + ) -> bool { + if global.race_detecting() { + let (_, clocks) = global.current_thread_state(); + let alloc_ranges = self.alloc_ranges.borrow(); + for (_, range) in alloc_ranges.iter(range.start, range.size) { + if !range.read_race_free_with_atomic(&clocks) { + return false; + } + } + } + true + } + + /// Detect racing atomic read and writes (not data races) + /// on every byte of the current access range + pub(super) fn write_race_free_with_atomic<'tcx>( + &mut self, + range: AllocRange, + global: &GlobalState, + ) -> bool { + if global.race_detecting() { + let (_, clocks) = global.current_thread_state(); + let alloc_ranges = self.alloc_ranges.get_mut(); + for (_, range) in alloc_ranges.iter_mut(range.start, range.size) { + if !range.write_race_free_with_atomic(&clocks) { + return false; + } + } + } + true + } + /// Detect data-races for an unsynchronized read operation, will not perform /// data-race detection if `race_detecting()` is false, either due to no threads /// being created or if it is temporarily disabled during a racy read or write @@ -1027,7 +1088,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let (alloc_id, base_offset, _tag) = this.ptr_get_alloc_id(place.ptr)?; // Load and log the atomic operation. // Note that atomic loads are possible even from read-only allocations, so `get_alloc_extra_mut` is not an option. - let alloc_meta = &this.get_alloc_extra(alloc_id)?.data_race.as_ref().unwrap(); + let alloc_meta = this.get_alloc_extra(alloc_id)?.data_race.as_ref().unwrap(); log::trace!( "Atomic op({}) with ordering {:?} on {:?} (size={})", description, diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index 7d8d7da6dc4e..a4fbd14f4374 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -29,6 +29,13 @@ //! Additionally, writes in our implementation do not have globally unique timestamps attached. In the other two models this timestamp is //! used to make sure a value in a thread's view is not overwritten by a write that occured earlier than the one in the existing view. //! In our implementation, this is detected using read information attached to store elements, as there is no data strucutre representing reads. +//! +//! Safe/sound Rust allows for more operations on atomic locations than the C++20 atomic API was intended to allow, such as non-atomically accessing +//! a previously atomically accessed location, or accessing previously atomically accessed locations with a differently sized operation +//! (such as accessing the top 16 bits of an AtomicU32). These senarios are generally undiscussed in formalisations of C++ memory model. +//! In Rust, these operations can only be done through a `&mut AtomicFoo` reference or one derived from it, therefore these operations +//! can only happen after all previous accesses on the same locations. This implementation is adapted to allow these operations. +//! A mixed size/atomicity read that races with writes, or a write that races with reads or writes will still cause UBs to be thrown. // Our and the author's own implementation (tsan11) of the paper have some deviations from the provided operational semantics in §5.3: // 1. In the operational semantics, store elements keep a copy of the atomic object's vector clock (AtomicCellClocks::sync_vector in miri), @@ -117,6 +124,14 @@ impl StoreBufferAlloc { Self { store_buffers: RefCell::new(AllocationMap::new()) } } + /// Checks if the range imperfectly overlaps with existing buffers + /// Used to determine if mixed-size atomic accesses + fn is_overlapping(&self, range: AllocRange) -> bool { + let buffers = self.store_buffers.borrow(); + let access_type = buffers.access_type(range); + matches!(access_type, AccessType::ImperfectlyOverlapping(_)) + } + /// When a non-atomic access happens on a location that has been atomically accessed /// before without data race, we can determine that the non-atomic access fully happens /// before all the prior atomic accesses so the location no longer needs to exhibit @@ -148,21 +163,16 @@ impl StoreBufferAlloc { let pos = match access_type { AccessType::PerfectlyOverlapping(pos) => pos, AccessType::Empty(pos) => { - let new_buffer = StoreBuffer::new(init); let mut buffers = self.store_buffers.borrow_mut(); - buffers.insert_at_pos(pos, range, new_buffer); + buffers.insert_at_pos(pos, range, StoreBuffer::new(init)); pos } AccessType::ImperfectlyOverlapping(pos_range) => { - // Accesses that imperfectly overlaps with existing atomic objects - // do not have well-defined behaviours. - // FIXME: if this access happens before all previous accesses on every object it overlaps - // with, then we would like to tolerate it. However this is not easy to check. - if pos_range.start + 1 == pos_range.end { - throw_ub_format!("mixed-size access on an existing atomic object"); - } else { - throw_ub_format!("access overlaps with multiple existing atomic objects"); - } + // Once we reach here we would've already checked that this access is not racy + let mut buffers = self.store_buffers.borrow_mut(); + buffers.remove_pos_range(pos_range.clone()); + buffers.insert_at_pos(pos_range.start, range, StoreBuffer::new(init)); + pos_range.start } }; Ok(Ref::map(self.store_buffers.borrow(), |buffer| &buffer[pos])) @@ -179,16 +189,13 @@ impl StoreBufferAlloc { let pos = match access_type { AccessType::PerfectlyOverlapping(pos) => pos, AccessType::Empty(pos) => { - let new_buffer = StoreBuffer::new(init); - buffers.insert_at_pos(pos, range, new_buffer); + buffers.insert_at_pos(pos, range, StoreBuffer::new(init)); pos } AccessType::ImperfectlyOverlapping(pos_range) => { - if pos_range.start + 1 == pos_range.end { - throw_ub_format!("mixed-size access on an existing atomic object"); - } else { - throw_ub_format!("access overlaps with multiple existing atomic objects"); - } + buffers.remove_pos_range(pos_range.clone()); + buffers.insert_at_pos(pos_range.start, range, StoreBuffer::new(init)); + pos_range.start } }; Ok(&mut buffers[pos]) @@ -392,6 +399,55 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + // If weak memory emulation is enabled, check if this atomic op imperfectly overlaps with a previous + // atomic write. If it does, then we require it to be ordered (non-racy) with all previous atomic + // writes on all the bytes in range + fn validate_overlapping_atomic_read(&self, place: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + let this = self.eval_context_ref(); + let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; + if let crate::AllocExtra { + weak_memory: Some(alloc_buffers), + data_race: Some(alloc_clocks), + .. + } = this.get_alloc_extra(alloc_id)? + { + let range = alloc_range(base_offset, place.layout.size); + if alloc_buffers.is_overlapping(range) + && !alloc_clocks + .read_race_free_with_atomic(range, this.machine.data_race.as_ref().unwrap()) + { + throw_ub_format!("racy imperfectly overlapping atomic access"); + } + } + Ok(()) + } + + // Same as above but needs to be ordered with all previous atomic read or writes + fn validate_overlapping_atomic_write( + &mut self, + place: &MPlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; + if let ( + crate::AllocExtra { + weak_memory: Some(alloc_buffers), + data_race: Some(alloc_clocks), + .. + }, + crate::Evaluator { data_race: Some(global), .. }, + ) = this.get_alloc_extra_mut(alloc_id)? + { + let range = alloc_range(base_offset, place.layout.size); + if alloc_buffers.is_overlapping(range) + && !alloc_clocks.write_race_free_with_atomic(range, global) + { + throw_ub_format!("racy imperfectly overlapping atomic access"); + } + } + Ok(()) + } + fn buffered_atomic_rmw( &mut self, new_val: ScalarMaybeUninit, diff --git a/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs b/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs index 34097f4a8937..7dad0a12e5dd 100644 --- a/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs +++ b/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs @@ -9,8 +9,8 @@ // so we have to stick to C++11 emulation from existing research. use std::sync::atomic::Ordering::*; -use std::thread::spawn; use std::sync::atomic::{fence, AtomicUsize}; +use std::thread::spawn; // Spins until it reads the given value fn reads_value(loc: &AtomicUsize, val: usize) -> usize { @@ -25,7 +25,7 @@ fn reads_value(loc: &AtomicUsize, val: usize) -> usize { fn static_atomic(val: usize) -> &'static AtomicUsize { let ret = Box::leak(Box::new(AtomicUsize::new(val))); // A workaround to put the initialization value in the store buffer. - ret.store(val, Relaxed); + ret.load(Relaxed); ret } @@ -82,4 +82,4 @@ pub fn main() { for _ in 0..500 { test_cpp20_rwc_syncs(); } -} \ No newline at end of file +} diff --git a/tests/compile-fail/weak_memory/racing_mixed_size.rs b/tests/compile-fail/weak_memory/racing_mixed_size.rs new file mode 100644 index 000000000000..d4ba48afe39d --- /dev/null +++ b/tests/compile-fail/weak_memory/racing_mixed_size.rs @@ -0,0 +1,38 @@ +// compile-flags: -Zmiri-ignore-leaks + +#![feature(core_intrinsics)] + +use std::sync::atomic::AtomicU32; +use std::sync::atomic::Ordering::*; +use std::thread::spawn; + +fn static_atomic_u32(val: u32) -> &'static AtomicU32 { + let ret = Box::leak(Box::new(AtomicU32::new(val))); + ret +} + +fn split_u32_ptr(dword: *const u32) -> *const [u16; 2] { + unsafe { std::mem::transmute::<*const u32, *const [u16; 2]>(dword) } +} + +// Wine's SRWLock implementation does this, which is definitely undefined in C++ memory model +// https://github.com/wine-mirror/wine/blob/303f8042f9db508adaca02ef21f8de4992cb9c03/dlls/ntdll/sync.c#L543-L566 +// Though it probably works just fine on x86 +pub fn main() { + let x = static_atomic_u32(0); + let j1 = spawn(move || { + x.store(1, Relaxed); + }); + + let j2 = spawn(move || { + let x_ptr = x as *const AtomicU32 as *const u32; + let x_split = split_u32_ptr(x_ptr); + unsafe { + let hi = &(*x_split)[0] as *const u16; + std::intrinsics::atomic_load_relaxed(hi); //~ ERROR: imperfectly overlapping + } + }); + + j1.join().unwrap(); + j2.join().unwrap(); +} diff --git a/tests/run-pass/weak_memory/extra_cpp.rs b/tests/run-pass/weak_memory/extra_cpp.rs index b20ec5834990..b1a683798bb3 100644 --- a/tests/run-pass/weak_memory/extra_cpp.rs +++ b/tests/run-pass/weak_memory/extra_cpp.rs @@ -4,13 +4,19 @@ // but doable in safe (at least sound) Rust. #![feature(atomic_from_mut)] +#![feature(core_intrinsics)] use std::sync::atomic::Ordering::*; -use std::sync::atomic::{AtomicU16, AtomicU32, AtomicUsize}; +use std::sync::atomic::{AtomicU16, AtomicU32}; use std::thread::spawn; -fn static_atomic_mut(val: usize) -> &'static mut AtomicUsize { - let ret = Box::leak(Box::new(AtomicUsize::new(val))); +fn static_atomic_mut(val: u32) -> &'static mut AtomicU32 { + let ret = Box::leak(Box::new(AtomicU32::new(val))); + ret +} + +fn static_atomic(val: u32) -> &'static AtomicU32 { + let ret = Box::leak(Box::new(AtomicU32::new(val))); ret } @@ -18,6 +24,10 @@ fn split_u32(dword: &mut u32) -> &mut [u16; 2] { unsafe { std::mem::transmute::<&mut u32, &mut [u16; 2]>(dword) } } +fn split_u32_ptr(dword: *const u32) -> *const [u16; 2] { + unsafe { std::mem::transmute::<*const u32, *const [u16; 2]>(dword) } +} + fn mem_replace() { let mut x = AtomicU32::new(0); @@ -31,7 +41,7 @@ fn assign_to_mut() { let x = static_atomic_mut(0); x.store(1, Relaxed); - *x = AtomicUsize::new(2); + *x = AtomicU32::new(2); assert_eq!(x.load(Relaxed), 2); } @@ -70,10 +80,81 @@ fn from_mut_split() { assert_eq!(x_lo_atomic.load(Relaxed), u16::from_be(0xfafa)); } +// Although not possible to do in safe Rust, +// we allow non-atomic and atomic reads to race +// as this should be sound +fn racing_mixed_atomicity_read() { + let x = static_atomic(0); + x.store(42, Relaxed); + + let j1 = spawn(move || x.load(Relaxed)); + + let j2 = spawn(move || { + let x_ptr = x as *const AtomicU32 as *const u32; + unsafe { std::intrinsics::atomic_load_relaxed(x_ptr) } + }); + + let r1 = j1.join().unwrap(); + let r2 = j2.join().unwrap(); + + assert_eq!(r1, 42); + assert_eq!(r2, 42); +} + +fn racing_mixed_size_read() { + let x = static_atomic(0); + + let j1 = spawn(move || { + x.load(Relaxed); + }); + + let j2 = spawn(move || { + let x_ptr = x as *const AtomicU32 as *const u32; + let x_split = split_u32_ptr(x_ptr); + unsafe { + let hi = &(*x_split)[0] as *const u16; + std::intrinsics::atomic_load_relaxed(hi); //~ ERROR: imperfectly overlapping + } + }); + + j1.join().unwrap(); + j2.join().unwrap(); +} + +fn racing_mixed_atomicity_and_size_read() { + let x = static_atomic(u32::from_be(0xabbafafa)); + + let j1 = spawn(move || { + x.load(Relaxed); + }); + + let j2 = spawn(move || { + let x_ptr = x as *const AtomicU32 as *const u32; + unsafe { *x_ptr }; + }); + + let j3 = spawn(move || { + let x_ptr = x as *const AtomicU32 as *const u32; + let x_split = split_u32_ptr(x_ptr); + unsafe { + let hi = &(*x_split)[0] as *const u16; + std::intrinsics::atomic_load_relaxed(hi) + } + }); + + j1.join().unwrap(); + j2.join().unwrap(); + let r3 = j3.join().unwrap(); + + assert_eq!(r3, u16::from_be(0xabba)); +} pub fn main() { get_mut_write(); from_mut_split(); assign_to_mut(); mem_replace(); + racing_mixed_atomicity_read(); + racing_mixed_size_read(); + racing_mixed_atomicity_and_size_read(); } From bfa56454e9544278be9f5de7abad54bcee9af51c Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Wed, 25 May 2022 21:10:00 +0100 Subject: [PATCH 3227/5092] Split extra_cpp tests into sound and unsafe --- src/concurrency/weak_memory.rs | 1 + tests/run-pass/weak_memory/extra_cpp.rs | 83 +--------------- .../run-pass/weak_memory/extra_cpp_unsafe.rs | 97 +++++++++++++++++++ .../weak_memory/extra_cpp_unsafe.stderr | 2 + 4 files changed, 102 insertions(+), 81 deletions(-) create mode 100644 tests/run-pass/weak_memory/extra_cpp_unsafe.rs create mode 100644 tests/run-pass/weak_memory/extra_cpp_unsafe.stderr diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index a4fbd14f4374..942d71a52ff2 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -36,6 +36,7 @@ //! In Rust, these operations can only be done through a `&mut AtomicFoo` reference or one derived from it, therefore these operations //! can only happen after all previous accesses on the same locations. This implementation is adapted to allow these operations. //! A mixed size/atomicity read that races with writes, or a write that races with reads or writes will still cause UBs to be thrown. +//! You can refer to test cases in weak_memory/extra_cpp.rs and weak_memory/extra_cpp_unsafe.rs for examples of these operations. // Our and the author's own implementation (tsan11) of the paper have some deviations from the provided operational semantics in §5.3: // 1. In the operational semantics, store elements keep a copy of the atomic object's vector clock (AtomicCellClocks::sync_vector in miri), diff --git a/tests/run-pass/weak_memory/extra_cpp.rs b/tests/run-pass/weak_memory/extra_cpp.rs index b1a683798bb3..3edac581c353 100644 --- a/tests/run-pass/weak_memory/extra_cpp.rs +++ b/tests/run-pass/weak_memory/extra_cpp.rs @@ -15,19 +15,10 @@ fn static_atomic_mut(val: u32) -> &'static mut AtomicU32 { ret } -fn static_atomic(val: u32) -> &'static AtomicU32 { - let ret = Box::leak(Box::new(AtomicU32::new(val))); - ret -} - fn split_u32(dword: &mut u32) -> &mut [u16; 2] { unsafe { std::mem::transmute::<&mut u32, &mut [u16; 2]>(dword) } } -fn split_u32_ptr(dword: *const u32) -> *const [u16; 2] { - unsafe { std::mem::transmute::<*const u32, *const [u16; 2]>(dword) } -} - fn mem_replace() { let mut x = AtomicU32::new(0); @@ -71,6 +62,8 @@ fn from_mut_split() { x_atomic.store(u32::from_be(0xabbafafa), Relaxed); } + // Split the `AtomicU32` into two `AtomicU16`. + // Crucially, there is no non-atomic access to `x`! All accesses are atomic, but of different size. let (x_hi, x_lo) = split_u32(&mut x).split_at_mut(1); let x_hi_atomic = AtomicU16::from_mut(&mut x_hi[0]); @@ -80,81 +73,9 @@ fn from_mut_split() { assert_eq!(x_lo_atomic.load(Relaxed), u16::from_be(0xfafa)); } -// Although not possible to do in safe Rust, -// we allow non-atomic and atomic reads to race -// as this should be sound -fn racing_mixed_atomicity_read() { - let x = static_atomic(0); - x.store(42, Relaxed); - - let j1 = spawn(move || x.load(Relaxed)); - - let j2 = spawn(move || { - let x_ptr = x as *const AtomicU32 as *const u32; - unsafe { std::intrinsics::atomic_load_relaxed(x_ptr) } - }); - - let r1 = j1.join().unwrap(); - let r2 = j2.join().unwrap(); - - assert_eq!(r1, 42); - assert_eq!(r2, 42); -} - -fn racing_mixed_size_read() { - let x = static_atomic(0); - - let j1 = spawn(move || { - x.load(Relaxed); - }); - - let j2 = spawn(move || { - let x_ptr = x as *const AtomicU32 as *const u32; - let x_split = split_u32_ptr(x_ptr); - unsafe { - let hi = &(*x_split)[0] as *const u16; - std::intrinsics::atomic_load_relaxed(hi); //~ ERROR: imperfectly overlapping - } - }); - - j1.join().unwrap(); - j2.join().unwrap(); -} - -fn racing_mixed_atomicity_and_size_read() { - let x = static_atomic(u32::from_be(0xabbafafa)); - - let j1 = spawn(move || { - x.load(Relaxed); - }); - - let j2 = spawn(move || { - let x_ptr = x as *const AtomicU32 as *const u32; - unsafe { *x_ptr }; - }); - - let j3 = spawn(move || { - let x_ptr = x as *const AtomicU32 as *const u32; - let x_split = split_u32_ptr(x_ptr); - unsafe { - let hi = &(*x_split)[0] as *const u16; - std::intrinsics::atomic_load_relaxed(hi) - } - }); - - j1.join().unwrap(); - j2.join().unwrap(); - let r3 = j3.join().unwrap(); - - assert_eq!(r3, u16::from_be(0xabba)); -} - pub fn main() { get_mut_write(); from_mut_split(); assign_to_mut(); mem_replace(); - racing_mixed_atomicity_read(); - racing_mixed_size_read(); - racing_mixed_atomicity_and_size_read(); } diff --git a/tests/run-pass/weak_memory/extra_cpp_unsafe.rs b/tests/run-pass/weak_memory/extra_cpp_unsafe.rs new file mode 100644 index 000000000000..95cc97d4dbb2 --- /dev/null +++ b/tests/run-pass/weak_memory/extra_cpp_unsafe.rs @@ -0,0 +1,97 @@ +// compile-flags: -Zmiri-ignore-leaks + +// Tests operations not perfomable through C++'s atomic API +// but doable in unsafe Rust which we think *should* be fine. +// Nonetheless they may be determined as inconsistent with the +// memory model in the future. + +#![feature(atomic_from_mut)] +#![feature(core_intrinsics)] + +use std::sync::atomic::AtomicU32; +use std::sync::atomic::Ordering::*; +use std::thread::spawn; + +fn static_atomic(val: u32) -> &'static AtomicU32 { + let ret = Box::leak(Box::new(AtomicU32::new(val))); + ret +} + +fn split_u32_ptr(dword: *const u32) -> *const [u16; 2] { + unsafe { std::mem::transmute::<*const u32, *const [u16; 2]>(dword) } +} + +// We allow non-atomic and atomic reads to race +fn racing_mixed_atomicity_read() { + let x = static_atomic(0); + x.store(42, Relaxed); + + let j1 = spawn(move || x.load(Relaxed)); + + let j2 = spawn(move || { + let x_ptr = x as *const AtomicU32 as *const u32; + unsafe { std::intrinsics::atomic_load_relaxed(x_ptr) } + }); + + let r1 = j1.join().unwrap(); + let r2 = j2.join().unwrap(); + + assert_eq!(r1, 42); + assert_eq!(r2, 42); +} + +// We allow mixed-size atomic reads to race +fn racing_mixed_size_read() { + let x = static_atomic(0); + + let j1 = spawn(move || { + x.load(Relaxed); + }); + + let j2 = spawn(move || { + let x_ptr = x as *const AtomicU32 as *const u32; + let x_split = split_u32_ptr(x_ptr); + unsafe { + let hi = &(*x_split)[0] as *const u16; + std::intrinsics::atomic_load_relaxed(hi); + } + }); + + j1.join().unwrap(); + j2.join().unwrap(); +} + +// And the combination of both of above +fn racing_mixed_atomicity_and_size_read() { + let x = static_atomic(u32::from_be(0xabbafafa)); + + let j1 = spawn(move || { + x.load(Relaxed); + }); + + let j2 = spawn(move || { + let x_ptr = x as *const AtomicU32 as *const u32; + unsafe { *x_ptr }; + }); + + let j3 = spawn(move || { + let x_ptr = x as *const AtomicU32 as *const u32; + let x_split = split_u32_ptr(x_ptr); + unsafe { + let hi = &(*x_split)[0] as *const u16; + std::intrinsics::atomic_load_relaxed(hi) + } + }); + + j1.join().unwrap(); + j2.join().unwrap(); + let r3 = j3.join().unwrap(); + + assert_eq!(r3, u16::from_be(0xabba)); +} + +pub fn main() { + racing_mixed_atomicity_read(); + racing_mixed_size_read(); + racing_mixed_atomicity_and_size_read(); +} diff --git a/tests/run-pass/weak_memory/extra_cpp_unsafe.stderr b/tests/run-pass/weak_memory/extra_cpp_unsafe.stderr new file mode 100644 index 000000000000..1d0ce4b3853d --- /dev/null +++ b/tests/run-pass/weak_memory/extra_cpp_unsafe.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. + From 6a73dedb36516c89914bbdf7f97c425d8615e1ae Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Wed, 25 May 2022 21:54:30 +0100 Subject: [PATCH 3228/5092] Update experimental threading warning --- src/shims/unix/thread.rs | 2 +- .../weak_memory/cpp20_rwc_syncs.stderr | 23 +++++++++++++++++++ .../weak_memory/racing_mixed_size.rs | 1 + .../weak_memory/racing_mixed_size.stderr | 18 +++++++++++++++ .../libc_pthread_create_main_terminate.stderr | 3 ++- .../libc_pthread_join_detached.stderr | 3 ++- .../libc_pthread_join_joined.stderr | 3 ++- .../concurrency/libc_pthread_join_main.stderr | 3 ++- .../libc_pthread_join_multiple.stderr | 3 ++- .../concurrency/libc_pthread_join_self.stderr | 3 ++- .../thread_local_static_dealloc.stderr | 3 ++- tests/fail/concurrency/too_few_args.stderr | 3 ++- tests/fail/concurrency/too_many_args.stderr | 3 ++- .../concurrency/unwind_top_of_stack.stderr | 3 ++- tests/fail/data_race/alloc_read_race.stderr | 3 ++- tests/fail/data_race/alloc_write_race.stderr | 3 ++- .../atomic_read_na_write_race1.stderr | 3 ++- .../atomic_read_na_write_race2.stderr | 3 ++- .../atomic_write_na_read_race1.stderr | 3 ++- .../atomic_write_na_read_race2.stderr | 3 ++- .../atomic_write_na_write_race1.stderr | 3 ++- .../atomic_write_na_write_race2.stderr | 3 ++- .../dangling_thread_async_race.stderr | 3 ++- .../data_race/dangling_thread_race.stderr | 3 ++- .../fail/data_race/dealloc_read_race1.stderr | 3 ++- .../fail/data_race/dealloc_read_race2.stderr | 3 ++- .../data_race/dealloc_read_race_stack.stderr | 3 ++- .../fail/data_race/dealloc_write_race1.stderr | 3 ++- .../fail/data_race/dealloc_write_race2.stderr | 3 ++- .../data_race/dealloc_write_race_stack.stderr | 3 ++- .../enable_after_join_to_main.stderr | 3 ++- tests/fail/data_race/fence_after_load.stderr | 3 ++- tests/fail/data_race/read_write_race.stderr | 3 ++- .../data_race/read_write_race_stack.stderr | 3 ++- .../fail/data_race/relax_acquire_race.stderr | 3 ++- tests/fail/data_race/release_seq_race.stderr | 3 ++- .../release_seq_race_same_thread.stderr | 3 ++- tests/fail/data_race/rmw_race.stderr | 3 ++- tests/fail/data_race/write_write_race.stderr | 3 ++- .../data_race/write_write_race_stack.stderr | 3 ++- .../sync/libc_pthread_mutex_deadlock.stderr | 3 ++- .../libc_pthread_mutex_wrong_owner.stderr | 3 ++- ...ibc_pthread_rwlock_read_wrong_owner.stderr | 3 ++- ..._pthread_rwlock_write_read_deadlock.stderr | 3 ++- ...pthread_rwlock_write_write_deadlock.stderr | 3 ++- ...bc_pthread_rwlock_write_wrong_owner.stderr | 3 ++- tests/pass/concurrency/channels.stderr | 3 ++- .../concurrent_caller_location.stderr | 3 ++- tests/pass/concurrency/data_race.stderr | 3 ++- .../disable_data_race_detector.stderr | 3 ++- tests/pass/concurrency/issue1643.stderr | 3 ++- tests/pass/concurrency/linux-futex.stderr | 3 ++- tests/pass/concurrency/simple.stderr | 3 ++- tests/pass/concurrency/spin_loops.stderr | 3 ++- tests/pass/concurrency/sync.stderr | 3 ++- tests/pass/concurrency/thread_locals.stderr | 3 ++- tests/pass/concurrency/tls_lib_drop.stderr | 3 ++- tests/pass/libc.stderr | 3 ++- tests/pass/panic/concurrent-panic.stderr | 3 ++- tests/pass/threadleak_ignored.stderr | 3 ++- tests/run-pass/weak_memory/consistency.stderr | 3 ++- tests/run-pass/weak_memory/extra_cpp.rs | 1 + tests/run-pass/weak_memory/extra_cpp.stderr | 3 ++- .../run-pass/weak_memory/extra_cpp_unsafe.rs | 1 + .../weak_memory/extra_cpp_unsafe.stderr | 3 ++- tests/run-pass/weak_memory/weak.stderr | 3 ++- 66 files changed, 165 insertions(+), 61 deletions(-) create mode 100644 tests/compile-fail/weak_memory/cpp20_rwc_syncs.stderr create mode 100644 tests/compile-fail/weak_memory/racing_mixed_size.stderr diff --git a/src/shims/unix/thread.rs b/src/shims/unix/thread.rs index 812cb7376b71..4dc40cf2fe3d 100644 --- a/src/shims/unix/thread.rs +++ b/src/shims/unix/thread.rs @@ -14,7 +14,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.tcx.sess.warn( - "thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model.", + "thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops.\n(see https://github.com/rust-lang/miri/issues/1388)", ); // Create the new thread diff --git a/tests/compile-fail/weak_memory/cpp20_rwc_syncs.stderr b/tests/compile-fail/weak_memory/cpp20_rwc_syncs.stderr new file mode 100644 index 000000000000..f4f467120e8a --- /dev/null +++ b/tests/compile-fail/weak_memory/cpp20_rwc_syncs.stderr @@ -0,0 +1,23 @@ +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) + +error: Undefined Behavior: type validation failed at .value: encountered uninitialized raw pointer + --> $DIR/cpp20_rwc_syncs.rs:LL:CC + | +LL | let _ = unsafe { std::mem::MaybeUninit::<*const u32>::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized raw pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `test_cpp20_rwc_syncs` at $DIR/cpp20_rwc_syncs.rs:LL:CC +note: inside `main` at $DIR/cpp20_rwc_syncs.rs:LL:CC + --> $DIR/cpp20_rwc_syncs.rs:LL:CC + | +LL | test_cpp20_rwc_syncs(); + | ^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/weak_memory/racing_mixed_size.rs b/tests/compile-fail/weak_memory/racing_mixed_size.rs index d4ba48afe39d..513d97edb51c 100644 --- a/tests/compile-fail/weak_memory/racing_mixed_size.rs +++ b/tests/compile-fail/weak_memory/racing_mixed_size.rs @@ -1,3 +1,4 @@ +// ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-ignore-leaks #![feature(core_intrinsics)] diff --git a/tests/compile-fail/weak_memory/racing_mixed_size.stderr b/tests/compile-fail/weak_memory/racing_mixed_size.stderr new file mode 100644 index 000000000000..b3074d93c9cb --- /dev/null +++ b/tests/compile-fail/weak_memory/racing_mixed_size.stderr @@ -0,0 +1,18 @@ +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) + +error: Undefined Behavior: racy imperfectly overlapping atomic access + --> $DIR/racing_mixed_size.rs:LL:CC + | +LL | std::intrinsics::atomic_load_relaxed(hi); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/racing_mixed_size.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/fail/concurrency/libc_pthread_create_main_terminate.stderr b/tests/fail/concurrency/libc_pthread_create_main_terminate.stderr index 0f7fbefe0af0..2ce73fdaaec1 100644 --- a/tests/fail/concurrency/libc_pthread_create_main_terminate.stderr +++ b/tests/fail/concurrency/libc_pthread_create_main_terminate.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: the main thread terminated without waiting for all remaining threads diff --git a/tests/fail/concurrency/libc_pthread_join_detached.stderr b/tests/fail/concurrency/libc_pthread_join_detached.stderr index 688f61a98b90..b106cc4c9541 100644 --- a/tests/fail/concurrency/libc_pthread_join_detached.stderr +++ b/tests/fail/concurrency/libc_pthread_join_detached.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: trying to join a detached or already joined thread --> $DIR/libc_pthread_join_detached.rs:LL:CC diff --git a/tests/fail/concurrency/libc_pthread_join_joined.stderr b/tests/fail/concurrency/libc_pthread_join_joined.stderr index 518f72de5bef..438998208d11 100644 --- a/tests/fail/concurrency/libc_pthread_join_joined.stderr +++ b/tests/fail/concurrency/libc_pthread_join_joined.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: trying to join a detached or already joined thread --> $DIR/libc_pthread_join_joined.rs:LL:CC diff --git a/tests/fail/concurrency/libc_pthread_join_main.stderr b/tests/fail/concurrency/libc_pthread_join_main.stderr index 5d9ec148e079..04f2ab07406c 100644 --- a/tests/fail/concurrency/libc_pthread_join_main.stderr +++ b/tests/fail/concurrency/libc_pthread_join_main.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: trying to join a detached or already joined thread --> $DIR/libc_pthread_join_main.rs:LL:CC diff --git a/tests/fail/concurrency/libc_pthread_join_multiple.stderr b/tests/fail/concurrency/libc_pthread_join_multiple.stderr index 57126a14ae2f..daf18c50e034 100644 --- a/tests/fail/concurrency/libc_pthread_join_multiple.stderr +++ b/tests/fail/concurrency/libc_pthread_join_multiple.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: trying to join a detached or already joined thread --> $DIR/libc_pthread_join_multiple.rs:LL:CC diff --git a/tests/fail/concurrency/libc_pthread_join_self.stderr b/tests/fail/concurrency/libc_pthread_join_self.stderr index d638d089398a..b2e0779f5fbb 100644 --- a/tests/fail/concurrency/libc_pthread_join_self.stderr +++ b/tests/fail/concurrency/libc_pthread_join_self.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: trying to join itself --> $DIR/libc_pthread_join_self.rs:LL:CC diff --git a/tests/fail/concurrency/thread_local_static_dealloc.stderr b/tests/fail/concurrency/thread_local_static_dealloc.stderr index cdeb22fb3175..ad5528dc555a 100644 --- a/tests/fail/concurrency/thread_local_static_dealloc.stderr +++ b/tests/fail/concurrency/thread_local_static_dealloc.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed --> $DIR/thread_local_static_dealloc.rs:LL:CC diff --git a/tests/fail/concurrency/too_few_args.stderr b/tests/fail/concurrency/too_few_args.stderr index 7401b2902ead..1ed8c5a510f4 100644 --- a/tests/fail/concurrency/too_few_args.stderr +++ b/tests/fail/concurrency/too_few_args.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: callee has fewer arguments than expected --> $DIR/too_few_args.rs:LL:CC diff --git a/tests/fail/concurrency/too_many_args.stderr b/tests/fail/concurrency/too_many_args.stderr index 951b76317f25..5602dab993b0 100644 --- a/tests/fail/concurrency/too_many_args.stderr +++ b/tests/fail/concurrency/too_many_args.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: callee has more arguments than expected --> $DIR/too_many_args.rs:LL:CC diff --git a/tests/fail/concurrency/unwind_top_of_stack.stderr b/tests/fail/concurrency/unwind_top_of_stack.stderr index 600b8443d2c7..26a196a5590f 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.stderr +++ b/tests/fail/concurrency/unwind_top_of_stack.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) thread '' panicked at 'explicit panic', $DIR/unwind_top_of_stack.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/fail/data_race/alloc_read_race.stderr b/tests/fail/data_race/alloc_read_race.stderr index 9d9006966b33..0b247fb19bc9 100644 --- a/tests/fail/data_race/alloc_read_race.stderr +++ b/tests/fail/data_race/alloc_read_race.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Read on Thread(id = 2) and Allocate on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/alloc_read_race.rs:LL:CC diff --git a/tests/fail/data_race/alloc_write_race.stderr b/tests/fail/data_race/alloc_write_race.stderr index 318895cae6b0..3594980ef9b0 100644 --- a/tests/fail/data_race/alloc_write_race.stderr +++ b/tests/fail/data_race/alloc_write_race.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Allocate on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/alloc_write_race.rs:LL:CC diff --git a/tests/fail/data_race/atomic_read_na_write_race1.stderr b/tests/fail/data_race/atomic_read_na_write_race1.stderr index 09d7accb0543..0c9aaf5a0019 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.stderr +++ b/tests/fail/data_race/atomic_read_na_write_race1.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Atomic Load on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/atomic_read_na_write_race1.rs:LL:CC diff --git a/tests/fail/data_race/atomic_read_na_write_race2.stderr b/tests/fail/data_race/atomic_read_na_write_race2.stderr index 739ce83d0b07..6e3a1330f9dd 100644 --- a/tests/fail/data_race/atomic_read_na_write_race2.stderr +++ b/tests/fail/data_race/atomic_read_na_write_race2.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Atomic Load on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/atomic_read_na_write_race2.rs:LL:CC diff --git a/tests/fail/data_race/atomic_write_na_read_race1.stderr b/tests/fail/data_race/atomic_write_na_read_race1.stderr index 6d67f58aaee4..4dc4ac1e6768 100644 --- a/tests/fail/data_race/atomic_write_na_read_race1.stderr +++ b/tests/fail/data_race/atomic_write_na_read_race1.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Read on Thread(id = 2) and Atomic Store on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/atomic_write_na_read_race1.rs:LL:CC diff --git a/tests/fail/data_race/atomic_write_na_read_race2.stderr b/tests/fail/data_race/atomic_write_na_read_race2.stderr index d9950ebcb75b..e665073c539e 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.stderr +++ b/tests/fail/data_race/atomic_write_na_read_race2.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Atomic Store on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/atomic_write_na_read_race2.rs:LL:CC diff --git a/tests/fail/data_race/atomic_write_na_write_race1.stderr b/tests/fail/data_race/atomic_write_na_write_race1.stderr index 29ccf7021253..a70c3b52de50 100644 --- a/tests/fail/data_race/atomic_write_na_write_race1.stderr +++ b/tests/fail/data_race/atomic_write_na_write_race1.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Atomic Store on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/atomic_write_na_write_race1.rs:LL:CC diff --git a/tests/fail/data_race/atomic_write_na_write_race2.stderr b/tests/fail/data_race/atomic_write_na_write_race2.stderr index 5488f05de031..79730d507934 100644 --- a/tests/fail/data_race/atomic_write_na_write_race2.stderr +++ b/tests/fail/data_race/atomic_write_na_write_race2.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Atomic Store on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/atomic_write_na_write_race2.rs:LL:CC diff --git a/tests/fail/data_race/dangling_thread_async_race.stderr b/tests/fail/data_race/dangling_thread_async_race.stderr index eccc243d696e..21b3eefc5e41 100644 --- a/tests/fail/data_race/dangling_thread_async_race.stderr +++ b/tests/fail/data_race/dangling_thread_async_race.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Write on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/dangling_thread_async_race.rs:LL:CC diff --git a/tests/fail/data_race/dangling_thread_race.stderr b/tests/fail/data_race/dangling_thread_race.stderr index 4dffeb14233a..3ca8862a5819 100644 --- a/tests/fail/data_race/dangling_thread_race.stderr +++ b/tests/fail/data_race/dangling_thread_race.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/dangling_thread_race.rs:LL:CC diff --git a/tests/fail/data_race/dealloc_read_race1.stderr b/tests/fail/data_race/dealloc_read_race1.stderr index 37196021ead9..10b32003ff40 100644 --- a/tests/fail/data_race/dealloc_read_race1.stderr +++ b/tests/fail/data_race/dealloc_read_race1.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/dealloc_read_race1.rs:LL:CC diff --git a/tests/fail/data_race/dealloc_read_race2.stderr b/tests/fail/data_race/dealloc_read_race2.stderr index 03fb5dbea90d..a21de1d9f7a9 100644 --- a/tests/fail/data_race/dealloc_read_race2.stderr +++ b/tests/fail/data_race/dealloc_read_race2.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed --> $DIR/dealloc_read_race2.rs:LL:CC diff --git a/tests/fail/data_race/dealloc_read_race_stack.stderr b/tests/fail/data_race/dealloc_read_race_stack.stderr index 055724fe2979..0f7213eb8d52 100644 --- a/tests/fail/data_race/dealloc_read_race_stack.stderr +++ b/tests/fail/data_race/dealloc_read_race_stack.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/dealloc_read_race_stack.rs:LL:CC diff --git a/tests/fail/data_race/dealloc_write_race1.stderr b/tests/fail/data_race/dealloc_write_race1.stderr index 7160f49af697..76258e9d8fc0 100644 --- a/tests/fail/data_race/dealloc_write_race1.stderr +++ b/tests/fail/data_race/dealloc_write_race1.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/dealloc_write_race1.rs:LL:CC diff --git a/tests/fail/data_race/dealloc_write_race2.stderr b/tests/fail/data_race/dealloc_write_race2.stderr index cb0d0af8672b..d9aef72118d8 100644 --- a/tests/fail/data_race/dealloc_write_race2.stderr +++ b/tests/fail/data_race/dealloc_write_race2.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed --> $DIR/dealloc_write_race2.rs:LL:CC diff --git a/tests/fail/data_race/dealloc_write_race_stack.stderr b/tests/fail/data_race/dealloc_write_race_stack.stderr index 05a8e1a8b7e2..70533f654b77 100644 --- a/tests/fail/data_race/dealloc_write_race_stack.stderr +++ b/tests/fail/data_race/dealloc_write_race_stack.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/dealloc_write_race_stack.rs:LL:CC diff --git a/tests/fail/data_race/enable_after_join_to_main.stderr b/tests/fail/data_race/enable_after_join_to_main.stderr index e612e08ade4f..58d33ffa8cf3 100644 --- a/tests/fail/data_race/enable_after_join_to_main.stderr +++ b/tests/fail/data_race/enable_after_join_to_main.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Write on Thread(id = 6) and Write on Thread(id = 5) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/enable_after_join_to_main.rs:LL:CC diff --git a/tests/fail/data_race/fence_after_load.stderr b/tests/fail/data_race/fence_after_load.stderr index 14452391327a..1e3186b08fa1 100644 --- a/tests/fail/data_race/fence_after_load.stderr +++ b/tests/fail/data_race/fence_after_load.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/fence_after_load.rs:LL:CC diff --git a/tests/fail/data_race/read_write_race.stderr b/tests/fail/data_race/read_write_race.stderr index fc04141830bf..5078e662546a 100644 --- a/tests/fail/data_race/read_write_race.stderr +++ b/tests/fail/data_race/read_write_race.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/read_write_race.rs:LL:CC diff --git a/tests/fail/data_race/read_write_race_stack.stderr b/tests/fail/data_race/read_write_race_stack.stderr index aad63731ca05..843bea753b65 100644 --- a/tests/fail/data_race/read_write_race_stack.stderr +++ b/tests/fail/data_race/read_write_race_stack.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/read_write_race_stack.rs:LL:CC diff --git a/tests/fail/data_race/relax_acquire_race.stderr b/tests/fail/data_race/relax_acquire_race.stderr index a437120c891d..d2423ff91631 100644 --- a/tests/fail/data_race/relax_acquire_race.stderr +++ b/tests/fail/data_race/relax_acquire_race.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/relax_acquire_race.rs:LL:CC diff --git a/tests/fail/data_race/release_seq_race.stderr b/tests/fail/data_race/release_seq_race.stderr index 1a1c7ac64f78..ffbf50c09172 100644 --- a/tests/fail/data_race/release_seq_race.stderr +++ b/tests/fail/data_race/release_seq_race.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/release_seq_race.rs:LL:CC diff --git a/tests/fail/data_race/release_seq_race_same_thread.stderr b/tests/fail/data_race/release_seq_race_same_thread.stderr index f357c0647d4d..b76021514611 100644 --- a/tests/fail/data_race/release_seq_race_same_thread.stderr +++ b/tests/fail/data_race/release_seq_race_same_thread.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Read on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/release_seq_race_same_thread.rs:LL:CC diff --git a/tests/fail/data_race/rmw_race.stderr b/tests/fail/data_race/rmw_race.stderr index dd3692c6dcc8..c6b09ba5f00b 100644 --- a/tests/fail/data_race/rmw_race.stderr +++ b/tests/fail/data_race/rmw_race.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/rmw_race.rs:LL:CC diff --git a/tests/fail/data_race/write_write_race.stderr b/tests/fail/data_race/write_write_race.stderr index dafee7dbf8cf..5acba97486ea 100644 --- a/tests/fail/data_race/write_write_race.stderr +++ b/tests/fail/data_race/write_write_race.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/write_write_race.rs:LL:CC diff --git a/tests/fail/data_race/write_write_race_stack.stderr b/tests/fail/data_race/write_write_race_stack.stderr index 8d113673ac15..d052206f4cc7 100644 --- a/tests/fail/data_race/write_write_race_stack.stderr +++ b/tests/fail/data_race/write_write_race_stack.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Write on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/write_write_race_stack.rs:LL:CC diff --git a/tests/fail/sync/libc_pthread_mutex_deadlock.stderr b/tests/fail/sync/libc_pthread_mutex_deadlock.stderr index ac37096ad80d..d1f9ee6cdd5f 100644 --- a/tests/fail/sync/libc_pthread_mutex_deadlock.stderr +++ b/tests/fail/sync/libc_pthread_mutex_deadlock.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: deadlock: the evaluated program deadlocked --> $DIR/libc_pthread_mutex_deadlock.rs:LL:CC diff --git a/tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr b/tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr index 6603b264d9b4..e9f0e2d4c157 100644 --- a/tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr +++ b/tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: unlocked a default mutex that was not locked by the current thread --> $DIR/libc_pthread_mutex_wrong_owner.rs:LL:CC diff --git a/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr b/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr index d3820f0dcb74..c25ab25a3da5 100644 --- a/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr +++ b/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: unlocked an rwlock that was not locked by the active thread --> $DIR/libc_pthread_rwlock_read_wrong_owner.rs:LL:CC diff --git a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr index 748a363a27a4..8fc2ae4c82e5 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr +++ b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: deadlock: the evaluated program deadlocked --> $DIR/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC diff --git a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr index c6a03ff9afb8..86c67925fb93 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr +++ b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: deadlock: the evaluated program deadlocked --> $DIR/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC diff --git a/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr b/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr index 02a6cf11c0a2..8965d55a489d 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr +++ b/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: unlocked an rwlock that was not locked by the active thread --> $DIR/libc_pthread_rwlock_write_wrong_owner.rs:LL:CC diff --git a/tests/pass/concurrency/channels.stderr b/tests/pass/concurrency/channels.stderr index 1d0ce4b3853d..9fe6daa778c1 100644 --- a/tests/pass/concurrency/channels.stderr +++ b/tests/pass/concurrency/channels.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) diff --git a/tests/pass/concurrency/concurrent_caller_location.stderr b/tests/pass/concurrency/concurrent_caller_location.stderr index 1d0ce4b3853d..9fe6daa778c1 100644 --- a/tests/pass/concurrency/concurrent_caller_location.stderr +++ b/tests/pass/concurrency/concurrent_caller_location.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) diff --git a/tests/pass/concurrency/data_race.stderr b/tests/pass/concurrency/data_race.stderr index 1d0ce4b3853d..9fe6daa778c1 100644 --- a/tests/pass/concurrency/data_race.stderr +++ b/tests/pass/concurrency/data_race.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) diff --git a/tests/pass/concurrency/disable_data_race_detector.stderr b/tests/pass/concurrency/disable_data_race_detector.stderr index 1d0ce4b3853d..9fe6daa778c1 100644 --- a/tests/pass/concurrency/disable_data_race_detector.stderr +++ b/tests/pass/concurrency/disable_data_race_detector.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) diff --git a/tests/pass/concurrency/issue1643.stderr b/tests/pass/concurrency/issue1643.stderr index 1d0ce4b3853d..9fe6daa778c1 100644 --- a/tests/pass/concurrency/issue1643.stderr +++ b/tests/pass/concurrency/issue1643.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) diff --git a/tests/pass/concurrency/linux-futex.stderr b/tests/pass/concurrency/linux-futex.stderr index 1d0ce4b3853d..9fe6daa778c1 100644 --- a/tests/pass/concurrency/linux-futex.stderr +++ b/tests/pass/concurrency/linux-futex.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) diff --git a/tests/pass/concurrency/simple.stderr b/tests/pass/concurrency/simple.stderr index 386dc922691a..0ba9e8645b28 100644 --- a/tests/pass/concurrency/simple.stderr +++ b/tests/pass/concurrency/simple.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) thread '' panicked at 'Hello!', $DIR/simple.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/pass/concurrency/spin_loops.stderr b/tests/pass/concurrency/spin_loops.stderr index 03676519d4f1..9fe6daa778c1 100644 --- a/tests/pass/concurrency/spin_loops.stderr +++ b/tests/pass/concurrency/spin_loops.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) diff --git a/tests/pass/concurrency/sync.stderr b/tests/pass/concurrency/sync.stderr index 1d0ce4b3853d..9fe6daa778c1 100644 --- a/tests/pass/concurrency/sync.stderr +++ b/tests/pass/concurrency/sync.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) diff --git a/tests/pass/concurrency/thread_locals.stderr b/tests/pass/concurrency/thread_locals.stderr index 1d0ce4b3853d..9fe6daa778c1 100644 --- a/tests/pass/concurrency/thread_locals.stderr +++ b/tests/pass/concurrency/thread_locals.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) diff --git a/tests/pass/concurrency/tls_lib_drop.stderr b/tests/pass/concurrency/tls_lib_drop.stderr index 1d0ce4b3853d..9fe6daa778c1 100644 --- a/tests/pass/concurrency/tls_lib_drop.stderr +++ b/tests/pass/concurrency/tls_lib_drop.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) diff --git a/tests/pass/libc.stderr b/tests/pass/libc.stderr index 1d0ce4b3853d..9fe6daa778c1 100644 --- a/tests/pass/libc.stderr +++ b/tests/pass/libc.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) diff --git a/tests/pass/panic/concurrent-panic.stderr b/tests/pass/panic/concurrent-panic.stderr index 0d4a409dfecf..b90cc01bb857 100644 --- a/tests/pass/panic/concurrent-panic.stderr +++ b/tests/pass/panic/concurrent-panic.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) Thread 1 starting, will block on mutex Thread 1 reported it has started diff --git a/tests/pass/threadleak_ignored.stderr b/tests/pass/threadleak_ignored.stderr index 9205eb70b207..af327a3012c3 100644 --- a/tests/pass/threadleak_ignored.stderr +++ b/tests/pass/threadleak_ignored.stderr @@ -1,3 +1,4 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) Dropping 0 diff --git a/tests/run-pass/weak_memory/consistency.stderr b/tests/run-pass/weak_memory/consistency.stderr index 1d0ce4b3853d..9fe6daa778c1 100644 --- a/tests/run-pass/weak_memory/consistency.stderr +++ b/tests/run-pass/weak_memory/consistency.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) diff --git a/tests/run-pass/weak_memory/extra_cpp.rs b/tests/run-pass/weak_memory/extra_cpp.rs index 3edac581c353..750c628458b8 100644 --- a/tests/run-pass/weak_memory/extra_cpp.rs +++ b/tests/run-pass/weak_memory/extra_cpp.rs @@ -1,3 +1,4 @@ +// ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-ignore-leaks // Tests operations not perfomable through C++'s atomic API diff --git a/tests/run-pass/weak_memory/extra_cpp.stderr b/tests/run-pass/weak_memory/extra_cpp.stderr index 1d0ce4b3853d..9fe6daa778c1 100644 --- a/tests/run-pass/weak_memory/extra_cpp.stderr +++ b/tests/run-pass/weak_memory/extra_cpp.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) diff --git a/tests/run-pass/weak_memory/extra_cpp_unsafe.rs b/tests/run-pass/weak_memory/extra_cpp_unsafe.rs index 95cc97d4dbb2..7c375d7345f3 100644 --- a/tests/run-pass/weak_memory/extra_cpp_unsafe.rs +++ b/tests/run-pass/weak_memory/extra_cpp_unsafe.rs @@ -1,3 +1,4 @@ +// ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-ignore-leaks // Tests operations not perfomable through C++'s atomic API diff --git a/tests/run-pass/weak_memory/extra_cpp_unsafe.stderr b/tests/run-pass/weak_memory/extra_cpp_unsafe.stderr index 1d0ce4b3853d..9fe6daa778c1 100644 --- a/tests/run-pass/weak_memory/extra_cpp_unsafe.stderr +++ b/tests/run-pass/weak_memory/extra_cpp_unsafe.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) diff --git a/tests/run-pass/weak_memory/weak.stderr b/tests/run-pass/weak_memory/weak.stderr index 1d0ce4b3853d..9fe6daa778c1 100644 --- a/tests/run-pass/weak_memory/weak.stderr +++ b/tests/run-pass/weak_memory/weak.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) From a7c832b04a2e11c39c58606182d2666b853c3602 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 29 May 2022 09:57:24 +0100 Subject: [PATCH 3229/5092] Wording improvements Co-authored-by: Ralf Jung --- src/concurrency/weak_memory.rs | 4 +++- src/machine.rs | 4 ++-- tests/compile-fail/weak_memory/racing_mixed_size.stderr | 4 ++-- tests/run-pass/weak_memory/extra_cpp_unsafe.rs | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index 942d71a52ff2..888f9edceb32 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -417,7 +417,9 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: && !alloc_clocks .read_race_free_with_atomic(range, this.machine.data_race.as_ref().unwrap()) { - throw_ub_format!("racy imperfectly overlapping atomic access"); + throw_ub_format!( + "racy imperfectly overlapping atomic access is not possible in the C++20 memory model" + ); } } Ok(()) diff --git a/src/machine.rs b/src/machine.rs index 6dc2a75b69fd..b8cb89087004 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -743,8 +743,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { if let Some(weak_memory) = &alloc_extra.weak_memory { if !machine.data_race.as_ref().unwrap().ongoing_atomic_access() { // This is a non-atomic access. And if we are accessing a previously atomically - // accessed location without racing with them, then the location no longer needs - // to exhibit weak-memory behaviours until a fresh atomic access happens + // accessed location without racing with them, then the location no longer + // exhibits weak-memory behaviors until a fresh atomic access happens. weak_memory.destroy_atomicity(range); } } diff --git a/tests/compile-fail/weak_memory/racing_mixed_size.stderr b/tests/compile-fail/weak_memory/racing_mixed_size.stderr index b3074d93c9cb..b03424a861c9 100644 --- a/tests/compile-fail/weak_memory/racing_mixed_size.stderr +++ b/tests/compile-fail/weak_memory/racing_mixed_size.stderr @@ -1,11 +1,11 @@ warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. (see https://github.com/rust-lang/miri/issues/1388) -error: Undefined Behavior: racy imperfectly overlapping atomic access +error: Undefined Behavior: racy imperfectly overlapping atomic access is not possible in the C++20 memory model --> $DIR/racing_mixed_size.rs:LL:CC | LL | std::intrinsics::atomic_load_relaxed(hi); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access is not possible in the C++20 memory model | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/run-pass/weak_memory/extra_cpp_unsafe.rs b/tests/run-pass/weak_memory/extra_cpp_unsafe.rs index 7c375d7345f3..de9a3af3fd3e 100644 --- a/tests/run-pass/weak_memory/extra_cpp_unsafe.rs +++ b/tests/run-pass/weak_memory/extra_cpp_unsafe.rs @@ -62,7 +62,7 @@ fn racing_mixed_size_read() { j2.join().unwrap(); } -// And the combination of both of above +// And we allow the combination of both of the above. fn racing_mixed_atomicity_and_size_read() { let x = static_atomic(u32::from_be(0xabbafafa)); From ceb173d64773736e0c60ba6104912c725f07c2c9 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 29 May 2022 12:03:45 +0100 Subject: [PATCH 3230/5092] Move logic out of machine.rs --- src/concurrency/weak_memory.rs | 28 +++++++++++++++------------- src/machine.rs | 11 ++--------- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index 888f9edceb32..3c692783d145 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -135,20 +135,22 @@ impl StoreBufferAlloc { /// When a non-atomic access happens on a location that has been atomically accessed /// before without data race, we can determine that the non-atomic access fully happens - /// before all the prior atomic accesses so the location no longer needs to exhibit + /// after all the prior atomic accesses so the location no longer needs to exhibit /// any weak memory behaviours until further atomic accesses. - pub fn destroy_atomicity<'tcx>(&self, range: AllocRange) { - let mut buffers = self.store_buffers.borrow_mut(); - let access_type = buffers.access_type(range); - match access_type { - AccessType::PerfectlyOverlapping(pos) => { - buffers.remove_from_pos(pos); - } - AccessType::ImperfectlyOverlapping(pos_range) => { - buffers.remove_pos_range(pos_range); - } - AccessType::Empty(_) => { - // Do nothing + pub fn memory_accessed<'tcx>(&self, range: AllocRange, global: &GlobalState) { + if !global.ongoing_atomic_access() { + let mut buffers = self.store_buffers.borrow_mut(); + let access_type = buffers.access_type(range); + match access_type { + AccessType::PerfectlyOverlapping(pos) => { + buffers.remove_from_pos(pos); + } + AccessType::ImperfectlyOverlapping(pos_range) => { + buffers.remove_pos_range(pos_range); + } + AccessType::Empty(_) => { + // The range had no weak behaivours attached, do nothing + } } } } diff --git a/src/machine.rs b/src/machine.rs index b8cb89087004..5ee2d9a9abd4 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -741,12 +741,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { )?; } if let Some(weak_memory) = &alloc_extra.weak_memory { - if !machine.data_race.as_ref().unwrap().ongoing_atomic_access() { - // This is a non-atomic access. And if we are accessing a previously atomically - // accessed location without racing with them, then the location no longer - // exhibits weak-memory behaviors until a fresh atomic access happens. - weak_memory.destroy_atomicity(range); - } + weak_memory.memory_accessed(range, machine.data_race.as_ref().unwrap()); } Ok(()) } @@ -772,9 +767,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { )?; } if let Some(weak_memory) = &alloc_extra.weak_memory { - if !machine.data_race.as_ref().unwrap().ongoing_atomic_access() { - weak_memory.destroy_atomicity(range); - } + weak_memory.memory_accessed(range, machine.data_race.as_ref().unwrap()); } Ok(()) } From 4a07f78dadd3e5608157486b204fd4be2cde15a7 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 29 May 2022 15:05:07 +0100 Subject: [PATCH 3231/5092] Forbade all racing mixed size atomic accesses --- src/concurrency/data_race.rs | 52 +++++------------ src/concurrency/weak_memory.rs | 41 +++----------- .../weak_memory/racing_mixed_size.rs | 1 - .../weak_memory/racing_mixed_size_read.rs | 39 +++++++++++++ .../weak_memory/racing_mixed_size_read.stderr | 18 ++++++ .../run-pass/weak_memory/extra_cpp_unsafe.rs | 56 ------------------- 6 files changed, 78 insertions(+), 129 deletions(-) create mode 100644 tests/compile-fail/weak_memory/racing_mixed_size_read.rs create mode 100644 tests/compile-fail/weak_memory/racing_mixed_size_read.stderr diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 8b8694ac1835..61cd6a3c0c0d 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -287,8 +287,8 @@ impl MemoryCellClocks { Ok(()) } - /// Checks if the memory cell write races with any prior atomic read or write - fn write_race_free_with_atomic(&mut self, clocks: &ThreadClockSet) -> bool { + /// Checks if the memory cell access is ordered with all prior atomic reads and writes + fn race_free_with_atomic(&self, clocks: &ThreadClockSet) -> bool { if let Some(atomic) = self.atomic() { atomic.read_vector <= clocks.clock && atomic.write_vector <= clocks.clock } else { @@ -296,11 +296,6 @@ impl MemoryCellClocks { } } - /// Checks if the memory cell read races with any prior atomic write - fn read_race_free_with_atomic(&self, clocks: &ThreadClockSet) -> bool { - if let Some(atomic) = self.atomic() { atomic.write_vector <= clocks.clock } else { true } - } - /// Update memory cell data-race tracking for atomic /// load relaxed semantics, is a no-op if this memory was /// not used previously as atomic memory. @@ -528,7 +523,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // the *value* (including the associated provenance if this is an AtomicPtr) at this location. // Only metadata on the location itself is used. let scalar = this.allow_data_races_ref(move |this| this.read_scalar(&place.into()))?; - this.validate_overlapping_atomic_read(place)?; + this.validate_overlapping_atomic(place)?; this.buffered_atomic_read(place, atomic, scalar, || { this.validate_atomic_load(place, atomic) }) @@ -542,7 +537,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicWriteOp, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.validate_overlapping_atomic_write(dest)?; + this.validate_overlapping_atomic(dest)?; this.allow_data_races_mut(move |this| this.write_scalar(val, &(*dest).into()))?; this.validate_atomic_store(dest, atomic)?; // FIXME: it's not possible to get the value before write_scalar. A read_scalar will cause @@ -563,7 +558,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let this = self.eval_context_mut(); - this.validate_overlapping_atomic_write(place)?; + this.validate_overlapping_atomic(place)?; let old = this.allow_data_races_mut(|this| this.read_immediate(&place.into()))?; // Atomics wrap around on overflow. @@ -592,7 +587,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_mut(); - this.validate_overlapping_atomic_write(place)?; + this.validate_overlapping_atomic(place)?; let old = this.allow_data_races_mut(|this| this.read_scalar(&place.into()))?; this.allow_data_races_mut(|this| this.write_scalar(new, &(*place).into()))?; @@ -613,7 +608,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let this = self.eval_context_mut(); - this.validate_overlapping_atomic_write(place)?; + this.validate_overlapping_atomic(place)?; let old = this.allow_data_races_mut(|this| this.read_immediate(&place.into()))?; let lt = this.binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar()?.to_bool()?; @@ -656,7 +651,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { use rand::Rng as _; let this = self.eval_context_mut(); - this.validate_overlapping_atomic_write(place)?; + this.validate_overlapping_atomic(place)?; // Failure ordering cannot be stronger than success ordering, therefore first attempt // to read with the failure ordering and if successful then try again with the success // read ordering and write in the success case. @@ -706,7 +701,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicReadOp, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); - this.validate_overlapping_atomic_read(place)?; + this.validate_overlapping_atomic(place)?; this.validate_atomic_op( place, atomic, @@ -729,7 +724,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicWriteOp, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.validate_overlapping_atomic_write(place)?; + this.validate_overlapping_atomic(place)?; this.validate_atomic_op( place, atomic, @@ -755,7 +750,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); let release = matches!(atomic, Release | AcqRel | SeqCst); let this = self.eval_context_mut(); - this.validate_overlapping_atomic_write(place)?; + this.validate_overlapping_atomic(place)?; this.validate_atomic_op(place, atomic, "Atomic RMW", move |memory, clocks, index, _| { if acquire { memory.load_acquire(clocks, index)?; @@ -941,9 +936,9 @@ impl VClockAlloc { ) } - /// Detect racing atomic writes (not data races) + /// Detect racing atomic read and writes (not data races) /// on every byte of the current access range - pub(super) fn read_race_free_with_atomic<'tcx>( + pub(super) fn race_free_with_atomic<'tcx>( &self, range: AllocRange, global: &GlobalState, @@ -952,26 +947,7 @@ impl VClockAlloc { let (_, clocks) = global.current_thread_state(); let alloc_ranges = self.alloc_ranges.borrow(); for (_, range) in alloc_ranges.iter(range.start, range.size) { - if !range.read_race_free_with_atomic(&clocks) { - return false; - } - } - } - true - } - - /// Detect racing atomic read and writes (not data races) - /// on every byte of the current access range - pub(super) fn write_race_free_with_atomic<'tcx>( - &mut self, - range: AllocRange, - global: &GlobalState, - ) -> bool { - if global.race_detecting() { - let (_, clocks) = global.current_thread_state(); - let alloc_ranges = self.alloc_ranges.get_mut(); - for (_, range) in alloc_ranges.iter_mut(range.start, range.size) { - if !range.write_race_free_with_atomic(&clocks) { + if !range.race_free_with_atomic(&clocks) { return false; } } diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index 3c692783d145..9bf46bb23b0b 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -35,7 +35,8 @@ //! (such as accessing the top 16 bits of an AtomicU32). These senarios are generally undiscussed in formalisations of C++ memory model. //! In Rust, these operations can only be done through a `&mut AtomicFoo` reference or one derived from it, therefore these operations //! can only happen after all previous accesses on the same locations. This implementation is adapted to allow these operations. -//! A mixed size/atomicity read that races with writes, or a write that races with reads or writes will still cause UBs to be thrown. +//! A mixed atomicity read that races with writes, or a write that races with reads or writes will still cause UBs to be thrown. +//! Mixed size atomic accesses must not race with any other atomic access, whether read or write, or a UB will be thrown. //! You can refer to test cases in weak_memory/extra_cpp.rs and weak_memory/extra_cpp_unsafe.rs for examples of these operations. // Our and the author's own implementation (tsan11) of the paper have some deviations from the provided operational semantics in §5.3: @@ -403,9 +404,9 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { // If weak memory emulation is enabled, check if this atomic op imperfectly overlaps with a previous - // atomic write. If it does, then we require it to be ordered (non-racy) with all previous atomic - // writes on all the bytes in range - fn validate_overlapping_atomic_read(&self, place: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + // atomic read or write. If it does, then we require it to be ordered (non-racy) with all previous atomic + // accesses on all the bytes in range + fn validate_overlapping_atomic(&self, place: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { let this = self.eval_context_ref(); let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; if let crate::AllocExtra { @@ -417,37 +418,9 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let range = alloc_range(base_offset, place.layout.size); if alloc_buffers.is_overlapping(range) && !alloc_clocks - .read_race_free_with_atomic(range, this.machine.data_race.as_ref().unwrap()) + .race_free_with_atomic(range, this.machine.data_race.as_ref().unwrap()) { - throw_ub_format!( - "racy imperfectly overlapping atomic access is not possible in the C++20 memory model" - ); - } - } - Ok(()) - } - - // Same as above but needs to be ordered with all previous atomic read or writes - fn validate_overlapping_atomic_write( - &mut self, - place: &MPlaceTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; - if let ( - crate::AllocExtra { - weak_memory: Some(alloc_buffers), - data_race: Some(alloc_clocks), - .. - }, - crate::Evaluator { data_race: Some(global), .. }, - ) = this.get_alloc_extra_mut(alloc_id)? - { - let range = alloc_range(base_offset, place.layout.size); - if alloc_buffers.is_overlapping(range) - && !alloc_clocks.write_race_free_with_atomic(range, global) - { - throw_ub_format!("racy imperfectly overlapping atomic access"); + throw_ub_format!("racy imperfectly overlapping atomic access is not possible in the C++20 memory model"); } } Ok(()) diff --git a/tests/compile-fail/weak_memory/racing_mixed_size.rs b/tests/compile-fail/weak_memory/racing_mixed_size.rs index 513d97edb51c..6d53670a4e92 100644 --- a/tests/compile-fail/weak_memory/racing_mixed_size.rs +++ b/tests/compile-fail/weak_memory/racing_mixed_size.rs @@ -1,5 +1,4 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-ignore-leaks #![feature(core_intrinsics)] diff --git a/tests/compile-fail/weak_memory/racing_mixed_size_read.rs b/tests/compile-fail/weak_memory/racing_mixed_size_read.rs new file mode 100644 index 000000000000..0129b55aff61 --- /dev/null +++ b/tests/compile-fail/weak_memory/racing_mixed_size_read.rs @@ -0,0 +1,39 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +#![feature(core_intrinsics)] + +use std::sync::atomic::AtomicU32; +use std::sync::atomic::Ordering::*; +use std::thread::spawn; + +fn static_atomic(val: u32) -> &'static AtomicU32 { + let ret = Box::leak(Box::new(AtomicU32::new(val))); + ret +} + +fn split_u32_ptr(dword: *const u32) -> *const [u16; 2] { + unsafe { std::mem::transmute::<*const u32, *const [u16; 2]>(dword) } +} + +// Racing mixed size reads may cause two loads to read-from +// the same store but observe different values, which doesn't make +// sense under the formal model so we forbade this. +pub fn main() { + let x = static_atomic(0); + + let j1 = spawn(move || { + x.load(Relaxed); + }); + + let j2 = spawn(move || { + let x_ptr = x as *const AtomicU32 as *const u32; + let x_split = split_u32_ptr(x_ptr); + unsafe { + let hi = &(*x_split)[0] as *const u16; + std::intrinsics::atomic_load_relaxed(hi); //~ ERROR: imperfectly overlapping + } + }); + + j1.join().unwrap(); + j2.join().unwrap(); +} diff --git a/tests/compile-fail/weak_memory/racing_mixed_size_read.stderr b/tests/compile-fail/weak_memory/racing_mixed_size_read.stderr new file mode 100644 index 000000000000..80cc2fe756bf --- /dev/null +++ b/tests/compile-fail/weak_memory/racing_mixed_size_read.stderr @@ -0,0 +1,18 @@ +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) + +error: Undefined Behavior: racy imperfectly overlapping atomic access is not possible in the C++20 memory model + --> $DIR/racing_mixed_size_read.rs:LL:CC + | +LL | std::intrinsics::atomic_load_relaxed(hi); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access is not possible in the C++20 memory model + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/racing_mixed_size_read.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/run-pass/weak_memory/extra_cpp_unsafe.rs b/tests/run-pass/weak_memory/extra_cpp_unsafe.rs index de9a3af3fd3e..478e436e59d1 100644 --- a/tests/run-pass/weak_memory/extra_cpp_unsafe.rs +++ b/tests/run-pass/weak_memory/extra_cpp_unsafe.rs @@ -18,10 +18,6 @@ fn static_atomic(val: u32) -> &'static AtomicU32 { ret } -fn split_u32_ptr(dword: *const u32) -> *const [u16; 2] { - unsafe { std::mem::transmute::<*const u32, *const [u16; 2]>(dword) } -} - // We allow non-atomic and atomic reads to race fn racing_mixed_atomicity_read() { let x = static_atomic(0); @@ -41,58 +37,6 @@ fn racing_mixed_atomicity_read() { assert_eq!(r2, 42); } -// We allow mixed-size atomic reads to race -fn racing_mixed_size_read() { - let x = static_atomic(0); - - let j1 = spawn(move || { - x.load(Relaxed); - }); - - let j2 = spawn(move || { - let x_ptr = x as *const AtomicU32 as *const u32; - let x_split = split_u32_ptr(x_ptr); - unsafe { - let hi = &(*x_split)[0] as *const u16; - std::intrinsics::atomic_load_relaxed(hi); - } - }); - - j1.join().unwrap(); - j2.join().unwrap(); -} - -// And we allow the combination of both of the above. -fn racing_mixed_atomicity_and_size_read() { - let x = static_atomic(u32::from_be(0xabbafafa)); - - let j1 = spawn(move || { - x.load(Relaxed); - }); - - let j2 = spawn(move || { - let x_ptr = x as *const AtomicU32 as *const u32; - unsafe { *x_ptr }; - }); - - let j3 = spawn(move || { - let x_ptr = x as *const AtomicU32 as *const u32; - let x_split = split_u32_ptr(x_ptr); - unsafe { - let hi = &(*x_split)[0] as *const u16; - std::intrinsics::atomic_load_relaxed(hi) - } - }); - - j1.join().unwrap(); - j2.join().unwrap(); - let r3 = j3.join().unwrap(); - - assert_eq!(r3, u16::from_be(0xabba)); -} - pub fn main() { racing_mixed_atomicity_read(); - racing_mixed_size_read(); - racing_mixed_atomicity_and_size_read(); } From 8215702d5a27c77197cf8d12e03caca6c3884783 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 29 May 2022 19:48:36 +0100 Subject: [PATCH 3232/5092] Refer to GitHub issue on overwritten init value --- src/concurrency/data_race.rs | 1 + src/concurrency/weak_memory.rs | 1 + src/machine.rs | 2 -- tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs | 1 + 4 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 61cd6a3c0c0d..35baf97b7276 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -544,6 +544,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // side effects from a read the program did not perform. So we have to initialise // the store buffer with the value currently being written // ONCE this is fixed please remove the hack in buffered_atomic_write() in weak_memory.rs + // https://github.com/rust-lang/miri/issues/2164 this.buffered_atomic_write(val, dest, atomic, val) } diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index 9bf46bb23b0b..237a13ea8646 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -508,6 +508,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: // UGLY HACK: in write_scalar_atomic() we don't know the value before our write, // so init == val always. If the buffer is fresh then we would've duplicated an entry, // so we need to remove it. + // See https://github.com/rust-lang/miri/issues/2164 let was_empty = matches!( alloc_buffers .store_buffers diff --git a/src/machine.rs b/src/machine.rs index 5ee2d9a9abd4..1ae49edd6001 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -638,8 +638,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { None }; let buffer_alloc = if ecx.machine.weak_memory { - // FIXME: if this is an atomic obejct, we want to supply its initial value - // while allocating the store buffer here. Some(weak_memory::AllocExtra::new_allocation()) } else { None diff --git a/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs b/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs index 7dad0a12e5dd..7fe24d638346 100644 --- a/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs +++ b/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs @@ -25,6 +25,7 @@ fn reads_value(loc: &AtomicUsize, val: usize) -> usize { fn static_atomic(val: usize) -> &'static AtomicUsize { let ret = Box::leak(Box::new(AtomicUsize::new(val))); // A workaround to put the initialization value in the store buffer. + // See https://github.com/rust-lang/miri/issues/2164 ret.load(Relaxed); ret } From c73107164089249477d56fbc580104231459a2a6 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 29 May 2022 21:10:36 +0100 Subject: [PATCH 3233/5092] Give flag temp disabling race detector a better name --- src/concurrency/data_race.rs | 25 +++++++++++++------------ src/concurrency/weak_memory.rs | 6 ++++-- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 35baf97b7276..f6f0ce528edb 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -455,11 +455,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { fn allow_data_races_ref(&self, op: impl FnOnce(&MiriEvalContext<'mir, 'tcx>) -> R) -> R { let this = self.eval_context_ref(); if let Some(data_race) = &this.machine.data_race { - data_race.ongoing_atomic_access.set(true); + data_race.ongoing_action_data_race_free.set(true); } let result = op(this); if let Some(data_race) = &this.machine.data_race { - data_race.ongoing_atomic_access.set(false); + data_race.ongoing_action_data_race_free.set(false); } result } @@ -474,11 +474,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> R { let this = self.eval_context_mut(); if let Some(data_race) = &this.machine.data_race { - data_race.ongoing_atomic_access.set(true); + data_race.ongoing_action_data_race_free.set(true); } let result = op(this); if let Some(data_race) = &this.machine.data_race { - data_race.ongoing_atomic_access.set(false); + data_race.ongoing_action_data_race_free.set(false); } result } @@ -1151,8 +1151,9 @@ pub struct GlobalState { multi_threaded: Cell, /// A flag to mark we are currently performing - /// an atomic access to supress data race detection - ongoing_atomic_access: Cell, + /// a data race free action (such as atomic access) + /// to supress the race detector + ongoing_action_data_race_free: Cell, /// Mapping of a vector index to a known set of thread /// clocks, this is not directly mapping from a thread id @@ -1205,7 +1206,7 @@ impl GlobalState { pub fn new() -> Self { let mut global_state = GlobalState { multi_threaded: Cell::new(false), - ongoing_atomic_access: Cell::new(false), + ongoing_action_data_race_free: Cell::new(false), vector_clocks: RefCell::new(IndexVec::new()), vector_info: RefCell::new(IndexVec::new()), thread_info: RefCell::new(IndexVec::new()), @@ -1232,14 +1233,14 @@ impl GlobalState { } // We perform data race detection when there are more than 1 active thread - // and we are not currently in the middle of an atomic acces where data race - // is impossible + // and we have not temporarily disabled race detection to perform something + // data race free fn race_detecting(&self) -> bool { - self.multi_threaded.get() && !self.ongoing_atomic_access.get() + self.multi_threaded.get() && !self.ongoing_action_data_race_free.get() } - pub fn ongoing_atomic_access(&self) -> bool { - self.ongoing_atomic_access.get() + pub fn ongoing_action_data_race_free(&self) -> bool { + self.ongoing_action_data_race_free.get() } // Try to find vector index values that can potentially be re-used diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index 237a13ea8646..dc32a3ddca41 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -139,7 +139,7 @@ impl StoreBufferAlloc { /// after all the prior atomic accesses so the location no longer needs to exhibit /// any weak memory behaviours until further atomic accesses. pub fn memory_accessed<'tcx>(&self, range: AllocRange, global: &GlobalState) { - if !global.ongoing_atomic_access() { + if !global.ongoing_action_data_race_free() { let mut buffers = self.store_buffers.borrow_mut(); let access_type = buffers.access_type(range); match access_type { @@ -420,7 +420,9 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: && !alloc_clocks .race_free_with_atomic(range, this.machine.data_race.as_ref().unwrap()) { - throw_ub_format!("racy imperfectly overlapping atomic access is not possible in the C++20 memory model"); + throw_ub_format!( + "racy imperfectly overlapping atomic access is not possible in the C++20 memory model" + ); } } Ok(()) From 6d0c76ea1b5021ec526421825a4c62b467c5b1e2 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 29 May 2022 22:53:57 +0100 Subject: [PATCH 3234/5092] Specify only perfectly overlapping accesses can race --- tests/run-pass/weak_memory/extra_cpp_unsafe.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/weak_memory/extra_cpp_unsafe.rs b/tests/run-pass/weak_memory/extra_cpp_unsafe.rs index 478e436e59d1..d77a090e6e43 100644 --- a/tests/run-pass/weak_memory/extra_cpp_unsafe.rs +++ b/tests/run-pass/weak_memory/extra_cpp_unsafe.rs @@ -18,7 +18,7 @@ fn static_atomic(val: u32) -> &'static AtomicU32 { ret } -// We allow non-atomic and atomic reads to race +// We allow perfectly overlapping non-atomic and atomic reads to race fn racing_mixed_atomicity_read() { let x = static_atomic(0); x.store(42, Relaxed); From 65f39bd5cf708c5d934ccb6d20efa7b9e54bab2a Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sat, 4 Jun 2022 18:18:46 +0100 Subject: [PATCH 3235/5092] Move tests to new directories --- tests/{compile-fail => fail}/weak_memory/cpp20_rwc_syncs.rs | 0 tests/{compile-fail => fail}/weak_memory/cpp20_rwc_syncs.stderr | 0 tests/{compile-fail => fail}/weak_memory/racing_mixed_size.rs | 0 tests/{compile-fail => fail}/weak_memory/racing_mixed_size.stderr | 0 .../{compile-fail => fail}/weak_memory/racing_mixed_size_read.rs | 0 .../weak_memory/racing_mixed_size_read.stderr | 0 tests/{run-pass => pass}/weak_memory/consistency.rs | 0 tests/{run-pass => pass}/weak_memory/consistency.stderr | 0 tests/{run-pass => pass}/weak_memory/extra_cpp.rs | 0 tests/{run-pass => pass}/weak_memory/extra_cpp.stderr | 0 tests/{run-pass => pass}/weak_memory/extra_cpp_unsafe.rs | 0 tests/{run-pass => pass}/weak_memory/extra_cpp_unsafe.stderr | 0 tests/{run-pass => pass}/weak_memory/weak.rs | 0 tests/{run-pass => pass}/weak_memory/weak.stderr | 0 14 files changed, 0 insertions(+), 0 deletions(-) rename tests/{compile-fail => fail}/weak_memory/cpp20_rwc_syncs.rs (100%) rename tests/{compile-fail => fail}/weak_memory/cpp20_rwc_syncs.stderr (100%) rename tests/{compile-fail => fail}/weak_memory/racing_mixed_size.rs (100%) rename tests/{compile-fail => fail}/weak_memory/racing_mixed_size.stderr (100%) rename tests/{compile-fail => fail}/weak_memory/racing_mixed_size_read.rs (100%) rename tests/{compile-fail => fail}/weak_memory/racing_mixed_size_read.stderr (100%) rename tests/{run-pass => pass}/weak_memory/consistency.rs (100%) rename tests/{run-pass => pass}/weak_memory/consistency.stderr (100%) rename tests/{run-pass => pass}/weak_memory/extra_cpp.rs (100%) rename tests/{run-pass => pass}/weak_memory/extra_cpp.stderr (100%) rename tests/{run-pass => pass}/weak_memory/extra_cpp_unsafe.rs (100%) rename tests/{run-pass => pass}/weak_memory/extra_cpp_unsafe.stderr (100%) rename tests/{run-pass => pass}/weak_memory/weak.rs (100%) rename tests/{run-pass => pass}/weak_memory/weak.stderr (100%) diff --git a/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs b/tests/fail/weak_memory/cpp20_rwc_syncs.rs similarity index 100% rename from tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs rename to tests/fail/weak_memory/cpp20_rwc_syncs.rs diff --git a/tests/compile-fail/weak_memory/cpp20_rwc_syncs.stderr b/tests/fail/weak_memory/cpp20_rwc_syncs.stderr similarity index 100% rename from tests/compile-fail/weak_memory/cpp20_rwc_syncs.stderr rename to tests/fail/weak_memory/cpp20_rwc_syncs.stderr diff --git a/tests/compile-fail/weak_memory/racing_mixed_size.rs b/tests/fail/weak_memory/racing_mixed_size.rs similarity index 100% rename from tests/compile-fail/weak_memory/racing_mixed_size.rs rename to tests/fail/weak_memory/racing_mixed_size.rs diff --git a/tests/compile-fail/weak_memory/racing_mixed_size.stderr b/tests/fail/weak_memory/racing_mixed_size.stderr similarity index 100% rename from tests/compile-fail/weak_memory/racing_mixed_size.stderr rename to tests/fail/weak_memory/racing_mixed_size.stderr diff --git a/tests/compile-fail/weak_memory/racing_mixed_size_read.rs b/tests/fail/weak_memory/racing_mixed_size_read.rs similarity index 100% rename from tests/compile-fail/weak_memory/racing_mixed_size_read.rs rename to tests/fail/weak_memory/racing_mixed_size_read.rs diff --git a/tests/compile-fail/weak_memory/racing_mixed_size_read.stderr b/tests/fail/weak_memory/racing_mixed_size_read.stderr similarity index 100% rename from tests/compile-fail/weak_memory/racing_mixed_size_read.stderr rename to tests/fail/weak_memory/racing_mixed_size_read.stderr diff --git a/tests/run-pass/weak_memory/consistency.rs b/tests/pass/weak_memory/consistency.rs similarity index 100% rename from tests/run-pass/weak_memory/consistency.rs rename to tests/pass/weak_memory/consistency.rs diff --git a/tests/run-pass/weak_memory/consistency.stderr b/tests/pass/weak_memory/consistency.stderr similarity index 100% rename from tests/run-pass/weak_memory/consistency.stderr rename to tests/pass/weak_memory/consistency.stderr diff --git a/tests/run-pass/weak_memory/extra_cpp.rs b/tests/pass/weak_memory/extra_cpp.rs similarity index 100% rename from tests/run-pass/weak_memory/extra_cpp.rs rename to tests/pass/weak_memory/extra_cpp.rs diff --git a/tests/run-pass/weak_memory/extra_cpp.stderr b/tests/pass/weak_memory/extra_cpp.stderr similarity index 100% rename from tests/run-pass/weak_memory/extra_cpp.stderr rename to tests/pass/weak_memory/extra_cpp.stderr diff --git a/tests/run-pass/weak_memory/extra_cpp_unsafe.rs b/tests/pass/weak_memory/extra_cpp_unsafe.rs similarity index 100% rename from tests/run-pass/weak_memory/extra_cpp_unsafe.rs rename to tests/pass/weak_memory/extra_cpp_unsafe.rs diff --git a/tests/run-pass/weak_memory/extra_cpp_unsafe.stderr b/tests/pass/weak_memory/extra_cpp_unsafe.stderr similarity index 100% rename from tests/run-pass/weak_memory/extra_cpp_unsafe.stderr rename to tests/pass/weak_memory/extra_cpp_unsafe.stderr diff --git a/tests/run-pass/weak_memory/weak.rs b/tests/pass/weak_memory/weak.rs similarity index 100% rename from tests/run-pass/weak_memory/weak.rs rename to tests/pass/weak_memory/weak.rs diff --git a/tests/run-pass/weak_memory/weak.stderr b/tests/pass/weak_memory/weak.stderr similarity index 100% rename from tests/run-pass/weak_memory/weak.stderr rename to tests/pass/weak_memory/weak.stderr From 137903671305d30ede80586388cd4db535aa92be Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 5 Jun 2022 10:37:40 +0100 Subject: [PATCH 3236/5092] Simplify known C++20 inconsistency test --- .../cpp20_rwc_syncs.rs | 11 +++++---- tests/fail/should-pass/cpp20_rwc_syncs.stderr | 3 +++ tests/fail/weak_memory/cpp20_rwc_syncs.stderr | 23 ------------------- 3 files changed, 9 insertions(+), 28 deletions(-) rename tests/fail/{weak_memory => should-pass}/cpp20_rwc_syncs.rs (83%) create mode 100644 tests/fail/should-pass/cpp20_rwc_syncs.stderr delete mode 100644 tests/fail/weak_memory/cpp20_rwc_syncs.stderr diff --git a/tests/fail/weak_memory/cpp20_rwc_syncs.rs b/tests/fail/should-pass/cpp20_rwc_syncs.rs similarity index 83% rename from tests/fail/weak_memory/cpp20_rwc_syncs.rs rename to tests/fail/should-pass/cpp20_rwc_syncs.rs index 7fe24d638346..e5192cd0d670 100644 --- a/tests/fail/weak_memory/cpp20_rwc_syncs.rs +++ b/tests/fail/should-pass/cpp20_rwc_syncs.rs @@ -1,5 +1,6 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-ignore-leaks +// error-pattern: // https://plv.mpi-sws.org/scfix/paper.pdf // 2.2 Second Problem: SC Fences are Too Weak @@ -70,12 +71,12 @@ fn test_cpp20_rwc_syncs() { let b = j2.join().unwrap(); let c = j3.join().unwrap(); + // We cannot write assert_ne!() since ui_test's fail + // tests expect exit status 1, whereas panics produce 101. + // Our ui_test does not yet support overriding failure status codes. if (b, c) == (0, 0) { - // FIXME: the standalone compiletest-rs needs to support - // failure-status header to allow us to write assert_ne!((b, c), (0, 0)) - // https://rustc-dev-guide.rust-lang.org/tests/headers.html#miscellaneous-headers - // because panic exits with 101 but compile-rs expects 1 - let _ = unsafe { std::mem::MaybeUninit::<*const u32>::uninit().assume_init() }; //~ ERROR uninitialized + // This *should* be unreachable, but Miri will reach it. + std::process::exit(1); } } diff --git a/tests/fail/should-pass/cpp20_rwc_syncs.stderr b/tests/fail/should-pass/cpp20_rwc_syncs.stderr new file mode 100644 index 000000000000..9fe6daa778c1 --- /dev/null +++ b/tests/fail/should-pass/cpp20_rwc_syncs.stderr @@ -0,0 +1,3 @@ +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) + diff --git a/tests/fail/weak_memory/cpp20_rwc_syncs.stderr b/tests/fail/weak_memory/cpp20_rwc_syncs.stderr deleted file mode 100644 index f4f467120e8a..000000000000 --- a/tests/fail/weak_memory/cpp20_rwc_syncs.stderr +++ /dev/null @@ -1,23 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - -error: Undefined Behavior: type validation failed at .value: encountered uninitialized raw pointer - --> $DIR/cpp20_rwc_syncs.rs:LL:CC - | -LL | let _ = unsafe { std::mem::MaybeUninit::<*const u32>::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized raw pointer - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `test_cpp20_rwc_syncs` at $DIR/cpp20_rwc_syncs.rs:LL:CC -note: inside `main` at $DIR/cpp20_rwc_syncs.rs:LL:CC - --> $DIR/cpp20_rwc_syncs.rs:LL:CC - | -LL | test_cpp20_rwc_syncs(); - | ^^^^^^^^^^^^^^^^^^^^^^ - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error; 1 warning emitted - From 6fb7c131ed48d33b8290ce2bf970c37fd9781828 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 5 Jun 2022 20:47:01 +0100 Subject: [PATCH 3237/5092] Remove unused lifetimes --- src/concurrency/data_race.rs | 6 +----- src/concurrency/weak_memory.rs | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index f6f0ce528edb..28b09d2f909a 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -939,11 +939,7 @@ impl VClockAlloc { /// Detect racing atomic read and writes (not data races) /// on every byte of the current access range - pub(super) fn race_free_with_atomic<'tcx>( - &self, - range: AllocRange, - global: &GlobalState, - ) -> bool { + pub(super) fn race_free_with_atomic(&self, range: AllocRange, global: &GlobalState) -> bool { if global.race_detecting() { let (_, clocks) = global.current_thread_state(); let alloc_ranges = self.alloc_ranges.borrow(); diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index dc32a3ddca41..a771a09ed1ec 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -138,7 +138,7 @@ impl StoreBufferAlloc { /// before without data race, we can determine that the non-atomic access fully happens /// after all the prior atomic accesses so the location no longer needs to exhibit /// any weak memory behaviours until further atomic accesses. - pub fn memory_accessed<'tcx>(&self, range: AllocRange, global: &GlobalState) { + pub fn memory_accessed(&self, range: AllocRange, global: &GlobalState) { if !global.ongoing_action_data_race_free() { let mut buffers = self.store_buffers.borrow_mut(); let access_type = buffers.access_type(range); From bf7a5c41540a4005eb0f8d66afda205691fbb14b Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 5 Jun 2022 21:48:07 +0100 Subject: [PATCH 3238/5092] Add more backgrounds on lazy store buffers Co-authored-by: Ralf Jung --- src/concurrency/weak_memory.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index a771a09ed1ec..02af0efe9fa7 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -30,7 +30,18 @@ //! used to make sure a value in a thread's view is not overwritten by a write that occured earlier than the one in the existing view. //! In our implementation, this is detected using read information attached to store elements, as there is no data strucutre representing reads. //! -//! Safe/sound Rust allows for more operations on atomic locations than the C++20 atomic API was intended to allow, such as non-atomically accessing +//! The C++ memory model is built around the notion of an 'atomic object', so it would be natural +//! to attach store buffers to atomic objects. However, Rust follows LLVM in that it only has +//! 'atomic accesses'. Therefore Miri cannot know when and where atomic 'objects' are being +//! created or destroyed, to manage its store buffers. Instead, we hence lazily create an +//! atomic object on the first atomic access to a given region, and we destroy that object +//! on the next non-atomic or imperfectly overlapping atomic access to that region. +//! These lazy (de)allocations happen in memory_accessed() on non-atomic accesses, and +//! get_or_create_store_buffer() on atomic accesses. This mostly works well, but it does +//! lead to some issues (https://github.com/rust-lang/miri/issues/2164). +//! +//! One consequence of this difference is that safe/sound Rust allows for more operations on atomic locations +//! than the C++20 atomic API was intended to allow, such as non-atomically accessing //! a previously atomically accessed location, or accessing previously atomically accessed locations with a differently sized operation //! (such as accessing the top 16 bits of an AtomicU32). These senarios are generally undiscussed in formalisations of C++ memory model. //! In Rust, these operations can only be done through a `&mut AtomicFoo` reference or one derived from it, therefore these operations @@ -156,8 +167,8 @@ impl StoreBufferAlloc { } } - /// Gets a store buffer associated with an atomic object in this allocation - /// Or creates one with the specified initial value + /// Gets a store buffer associated with an atomic object in this allocation, + /// or creates one with the specified initial value if no atomic object exists yet. fn get_or_create_store_buffer<'tcx>( &self, range: AllocRange, From 1b32d14255aed79e1ff308e8c47b8cb884ed9703 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 5 Jun 2022 22:11:55 +0100 Subject: [PATCH 3239/5092] Make racy imperfectly overlapping atomic access unsupported instead of UB Co-authored-by: Ralf Jung --- src/concurrency/weak_memory.rs | 4 ++-- tests/fail/weak_memory/racing_mixed_size.stderr | 7 +++---- tests/fail/weak_memory/racing_mixed_size_read.stderr | 7 +++---- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index 02af0efe9fa7..da36fcd2fb3a 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -431,8 +431,8 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: && !alloc_clocks .race_free_with_atomic(range, this.machine.data_race.as_ref().unwrap()) { - throw_ub_format!( - "racy imperfectly overlapping atomic access is not possible in the C++20 memory model" + throw_unsup_format!( + "racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation" ); } } diff --git a/tests/fail/weak_memory/racing_mixed_size.stderr b/tests/fail/weak_memory/racing_mixed_size.stderr index b03424a861c9..fc6be84315d7 100644 --- a/tests/fail/weak_memory/racing_mixed_size.stderr +++ b/tests/fail/weak_memory/racing_mixed_size.stderr @@ -1,14 +1,13 @@ warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. (see https://github.com/rust-lang/miri/issues/1388) -error: Undefined Behavior: racy imperfectly overlapping atomic access is not possible in the C++20 memory model +error: unsupported operation: racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation --> $DIR/racing_mixed_size.rs:LL:CC | LL | std::intrinsics::atomic_load_relaxed(hi); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access is not possible in the C++20 memory model + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support = note: inside closure at $DIR/racing_mixed_size.rs:LL:CC diff --git a/tests/fail/weak_memory/racing_mixed_size_read.stderr b/tests/fail/weak_memory/racing_mixed_size_read.stderr index 80cc2fe756bf..846d03f5448f 100644 --- a/tests/fail/weak_memory/racing_mixed_size_read.stderr +++ b/tests/fail/weak_memory/racing_mixed_size_read.stderr @@ -1,14 +1,13 @@ warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. (see https://github.com/rust-lang/miri/issues/1388) -error: Undefined Behavior: racy imperfectly overlapping atomic access is not possible in the C++20 memory model +error: unsupported operation: racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation --> $DIR/racing_mixed_size_read.rs:LL:CC | LL | std::intrinsics::atomic_load_relaxed(hi); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access is not possible in the C++20 memory model + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support = note: inside closure at $DIR/racing_mixed_size_read.rs:LL:CC From 14913e993b9415c3f12159aaa387ed3931a30e73 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 11:45:41 -0400 Subject: [PATCH 3240/5092] deprecate -Zmiri-allow-uninit-numbers and -Zmiri-allow-ptr-int-transmute --- README.md | 6 ++++-- src/bin/miri.rs | 8 ++++++++ .../validity/invalid_enum_tag_256variants_uninit.stderr | 1 + tests/pass/move-uninit-primval.stderr | 1 + tests/pass/uninit_number_ignored.stderr | 1 + 5 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 tests/pass/move-uninit-primval.stderr create mode 100644 tests/pass/uninit_number_ignored.stderr diff --git a/README.md b/README.md index a55ebcb125b3..63990985ba40 100644 --- a/README.md +++ b/README.md @@ -304,13 +304,15 @@ to Miri failing to detect cases of undefined behavior in a program. * `-Zmiri-allow-uninit-numbers` disables the check to ensure that number types (integer and float types) always hold initialized data. (They must still be initialized when any actual operation, - such as arithmetic, is performed.) Using this flag is **unsound**. This has no effect when + such as arithmetic, is performed.) Using this flag is **unsound** and + [deprecated](https://github.com/rust-lang/miri/issues/2187). This has no effect when `-Zmiri-disable-validation` is present. * `-Zmiri-allow-ptr-int-transmute` makes Miri more accepting of transmutation between pointers and integers via `mem::transmute` or union/pointer type punning. This has two effects: it disables the check against integers storing a pointer (i.e., data with provenance), thus allowing pointer-to-integer transmutation, and it treats integer-to-pointer transmutation as equivalent to - a cast. Using this flag is **unsound**. + a cast. Using this flag is **unsound** and + [deprecated](https://github.com/rust-lang/miri/issues/2188). * `-Zmiri-disable-abi-check` disables checking [function ABI]. Using this flag is **unsound**. * `-Zmiri-disable-alignment-check` disables checking pointer alignment, so you diff --git a/src/bin/miri.rs b/src/bin/miri.rs index e3f38956dae2..efb300a8baf2 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -328,8 +328,16 @@ fn main() { since it is now enabled by default" ); } else if arg == "-Zmiri-allow-uninit-numbers" { + eprintln!( + "WARNING: `-Zmiri-allow-uninit-numbers` is deprecated and planned to be removed. \ + Please let us know at if you rely on this flag." + ); miri_config.allow_uninit_numbers = true; } else if arg == "-Zmiri-allow-ptr-int-transmute" { + eprintln!( + "WARNING: `-Zmiri-allow-ptr-int-transmute` is deprecated and planned to be removed. \ + Please let us know at if you rely on this flag." + ); miri_config.allow_ptr_int_transmute = true; } else if arg == "-Zmiri-disable-abi-check" { miri_config.check_abi = false; diff --git a/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr b/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr index 1a6039c477d6..0e924bb741a9 100644 --- a/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr +++ b/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr @@ -1,3 +1,4 @@ +WARNING: `-Zmiri-allow-uninit-numbers` is deprecated and planned to be removed. Please let us know at if you rely on this flag. error: Undefined Behavior: type validation failed at .: encountered uninitialized bytes, but expected a valid enum tag --> $DIR/invalid_enum_tag_256variants_uninit.rs:LL:CC | diff --git a/tests/pass/move-uninit-primval.stderr b/tests/pass/move-uninit-primval.stderr new file mode 100644 index 000000000000..d9f2331fe7fa --- /dev/null +++ b/tests/pass/move-uninit-primval.stderr @@ -0,0 +1 @@ +WARNING: `-Zmiri-allow-uninit-numbers` is deprecated and planned to be removed. Please let us know at if you rely on this flag. diff --git a/tests/pass/uninit_number_ignored.stderr b/tests/pass/uninit_number_ignored.stderr new file mode 100644 index 000000000000..d9f2331fe7fa --- /dev/null +++ b/tests/pass/uninit_number_ignored.stderr @@ -0,0 +1 @@ +WARNING: `-Zmiri-allow-uninit-numbers` is deprecated and planned to be removed. Please let us know at if you rely on this flag. From 66d3ee157ba5192409753e3f4a488f9ab2063e4a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 19:11:59 -0400 Subject: [PATCH 3241/5092] hotfix for incorrect only- logic --- ui_test/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 0b076a5f51ec..caefee1992ed 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -516,9 +516,10 @@ fn ignore_file(comments: &Comments, target: &str) -> bool { if !target.contains(s) { return true; } + /* FIXME(https://github.com/rust-lang/miri/issues/2206) if get_pointer_width(target) != s { return true; - } + } */ } false } From 89edc355e8229ef8c8083e7974971999386c5ce4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 19:48:21 -0400 Subject: [PATCH 3242/5092] bless Windows --- tests/fail/concurrency/thread-spawn.stderr | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 tests/fail/concurrency/thread-spawn.stderr diff --git a/tests/fail/concurrency/thread-spawn.stderr b/tests/fail/concurrency/thread-spawn.stderr new file mode 100644 index 000000000000..eb6c6c9b0bb8 --- /dev/null +++ b/tests/fail/concurrency/thread-spawn.stderr @@ -0,0 +1,30 @@ +error: unsupported operation: can't create threads on Windows + --> RUSTLIB/std/src/sys/PLATFORM/thread.rs:LL:CC + | +LL | let ret = c::CreateThread( + | ___________________^ +LL | | ptr::null_mut(), +LL | | stack, +LL | | thread_start, +... | +LL | | ptr::null_mut(), +LL | | ); + | |_________^ can't create threads on Windows + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `std::sys::PLATFORM::thread::Thread::new` at RUSTLIB/std/src/sys/PLATFORM/thread.rs:LL:CC + = note: inside `std::thread::Builder::spawn_unchecked_::<[closure@$DIR/thread-spawn.rs:LL:CC], ()>` at RUSTLIB/std/src/thread/mod.rs:LL:CC + = note: inside `std::thread::Builder::spawn_unchecked::<[closure@$DIR/thread-spawn.rs:LL:CC], ()>` at RUSTLIB/std/src/thread/mod.rs:LL:CC + = note: inside `std::thread::Builder::spawn::<[closure@$DIR/thread-spawn.rs:LL:CC], ()>` at RUSTLIB/std/src/thread/mod.rs:LL:CC + = note: inside `std::thread::spawn::<[closure@$DIR/thread-spawn.rs:LL:CC], ()>` at RUSTLIB/std/src/thread/mod.rs:LL:CC +note: inside `main` at $DIR/thread-spawn.rs:LL:CC + --> $DIR/thread-spawn.rs:LL:CC + | +LL | thread::spawn(|| {}); + | ^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + From dac95a3ad8507fcad5fa64656ededd4cffc5b996 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 17:27:46 -0400 Subject: [PATCH 3243/5092] =?UTF-8?q?rename=20AllocationMap=20=E2=86=92=20?= =?UTF-8?q?RangeObjectMap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/concurrency/mod.rs | 2 +- ...{allocation_map.rs => range_object_map.rs} | 25 +++++++++---------- src/concurrency/weak_memory.rs | 6 ++--- 3 files changed, 16 insertions(+), 17 deletions(-) rename src/concurrency/{allocation_map.rs => range_object_map.rs} (93%) diff --git a/src/concurrency/mod.rs b/src/concurrency/mod.rs index ad1586bbf0f9..5f8bba802728 100644 --- a/src/concurrency/mod.rs +++ b/src/concurrency/mod.rs @@ -1,3 +1,3 @@ -mod allocation_map; pub mod data_race; +mod range_object_map; pub mod weak_memory; diff --git a/src/concurrency/allocation_map.rs b/src/concurrency/range_object_map.rs similarity index 93% rename from src/concurrency/allocation_map.rs rename to src/concurrency/range_object_map.rs index 62469dcaf43a..2bb328030239 100644 --- a/src/concurrency/allocation_map.rs +++ b/src/concurrency/range_object_map.rs @@ -1,7 +1,6 @@ -//! Implements a map from allocation ranges to data. -//! This is somewhat similar to RangeMap, but the ranges -//! and data are discrete and non-splittable. An allocation in the -//! map will always have the same range until explicitly removed +//! Implements a map from allocation ranges to data. This is somewhat similar to RangeMap, but the +//! ranges and data are discrete and non-splittable -- they represent distinct "objects". An +//! allocation in the map will always have the same range until explicitly removed use rustc_target::abi::Size; use std::ops::{Index, IndexMut, Range}; @@ -20,7 +19,7 @@ struct Elem { type Position = usize; #[derive(Clone, Debug)] -pub struct AllocationMap { +pub struct RangeObjectMap { v: Vec>, } @@ -34,7 +33,7 @@ pub enum AccessType { ImperfectlyOverlapping(Range), } -impl AllocationMap { +impl RangeObjectMap { pub fn new() -> Self { Self { v: Vec::new() } } @@ -135,7 +134,7 @@ impl AllocationMap { } } -impl Index for AllocationMap { +impl Index for RangeObjectMap { type Output = T; fn index(&self, pos: Position) -> &Self::Output { @@ -143,7 +142,7 @@ impl Index for AllocationMap { } } -impl IndexMut for AllocationMap { +impl IndexMut for RangeObjectMap { fn index_mut(&mut self, pos: Position) -> &mut Self::Output { &mut self.v[pos].data } @@ -159,7 +158,7 @@ mod tests { fn empty_map() { // FIXME: make Size::from_bytes const let four = Size::from_bytes(4); - let map = AllocationMap::<()>::new(); + let map = RangeObjectMap::<()>::new(); // Correctly tells where we should insert the first element (at position 0) assert_eq!(map.find_offset(Size::from_bytes(3)), Err(0)); @@ -173,7 +172,7 @@ mod tests { fn no_overlapping_inserts() { let four = Size::from_bytes(4); - let mut map = AllocationMap::<&str>::new(); + let mut map = RangeObjectMap::<&str>::new(); // |_|_|_|_|#|#|#|#|_|_|_|_|... // 0 1 2 3 4 5 6 7 8 9 a b c d @@ -187,7 +186,7 @@ mod tests { fn boundaries() { let four = Size::from_bytes(4); - let mut map = AllocationMap::<&str>::new(); + let mut map = RangeObjectMap::<&str>::new(); // |#|#|#|#|_|_|... // 0 1 2 3 4 5 @@ -215,7 +214,7 @@ mod tests { fn perfectly_overlapping() { let four = Size::from_bytes(4); - let mut map = AllocationMap::<&str>::new(); + let mut map = RangeObjectMap::<&str>::new(); // |#|#|#|#|_|_|... // 0 1 2 3 4 5 @@ -241,7 +240,7 @@ mod tests { fn straddling() { let four = Size::from_bytes(4); - let mut map = AllocationMap::<&str>::new(); + let mut map = RangeObjectMap::<&str>::new(); // |_|_|_|_|#|#|#|#|_|_|_|_|... // 0 1 2 3 4 5 6 7 8 9 a b c d diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index da36fcd2fb3a..be3963a93f07 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -85,8 +85,8 @@ use rustc_data_structures::fx::FxHashMap; use crate::{AtomicReadOp, AtomicRwOp, AtomicWriteOp, Tag, VClock, VTimestamp, VectorIdx}; use super::{ - allocation_map::{AccessType, AllocationMap}, data_race::{GlobalState, ThreadClockSet}, + range_object_map::{AccessType, RangeObjectMap}, }; pub type AllocExtra = StoreBufferAlloc; @@ -101,7 +101,7 @@ const STORE_BUFFER_LIMIT: usize = 128; pub struct StoreBufferAlloc { /// Store buffer of each atomic object in this allocation // Behind a RefCell because we need to allocate/remove on read access - store_buffers: RefCell>, + store_buffers: RefCell>, } #[derive(Debug, Clone, PartialEq, Eq)] @@ -134,7 +134,7 @@ struct StoreElement { impl StoreBufferAlloc { pub fn new_allocation() -> Self { - Self { store_buffers: RefCell::new(AllocationMap::new()) } + Self { store_buffers: RefCell::new(RangeObjectMap::new()) } } /// Checks if the range imperfectly overlaps with existing buffers From b64c9a0a830c664bf31958a082cf7ad1f0742df9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 17:44:16 -0400 Subject: [PATCH 3244/5092] make scheduler preemptive, with configurable preemption rate --- README.md | 18 ++++---- src/bin/miri.rs | 11 +++++ src/eval.rs | 5 ++- src/machine.rs | 9 ++++ src/thread.rs | 10 +++++ .../concurrency/libc_pthread_join_self.rs | 2 + tests/fail/data_race/alloc_read_race.rs | 2 +- tests/fail/data_race/alloc_write_race.rs | 2 +- .../fail/data_race/dealloc_read_race_stack.rs | 2 +- .../data_race/dealloc_write_race_stack.rs | 2 +- tests/fail/data_race/read_write_race_stack.rs | 2 +- tests/fail/data_race/relax_acquire_race.rs | 2 +- tests/fail/data_race/release_seq_race.rs | 2 +- .../data_race/release_seq_race_same_thread.rs | 2 +- tests/fail/data_race/rmw_race.rs | 2 +- .../fail/data_race/write_write_race_stack.rs | 2 +- tests/pass/concurrency/spin_loop.rs | 42 +++++++++++++++++++ tests/pass/concurrency/spin_loop.stderr | 3 ++ ...{spin_loops.rs => spin_loops_nopreempt.rs} | 2 + .../concurrency/spin_loops_nopreempt.stderr | 3 ++ tests/pass/concurrency/sync.rs | 3 +- tests/pass/panic/concurrent-panic.rs | 2 + tests/pass/weak_memory/weak.rs | 2 +- 23 files changed, 111 insertions(+), 21 deletions(-) create mode 100644 tests/pass/concurrency/spin_loop.rs create mode 100644 tests/pass/concurrency/spin_loop.stderr rename tests/pass/concurrency/{spin_loops.rs => spin_loops_nopreempt.rs} (96%) create mode 100644 tests/pass/concurrency/spin_loops_nopreempt.stderr diff --git a/README.md b/README.md index 938a64cd045b..6ccc9e25f697 100644 --- a/README.md +++ b/README.md @@ -288,14 +288,16 @@ environment variable. We first document the most relevant and most commonly used `-Zmiri-disable-isolation` is set. * `-Zmiri-ignore-leaks` disables the memory leak checker, and also allows some remaining threads to exist when the main thread exits. -* `-Zmiri-seed=` configures the seed of the RNG that Miri uses to resolve - non-determinism. This RNG is used to pick base addresses for allocations. When - isolation is enabled (the default), this is also used to emulate system - entropy. The default seed is 0. You can increase test coverage by running Miri - multiple times with different seeds. - **NOTE**: This entropy is not good enough for cryptographic use! Do not - generate secret keys in Miri or perform other kinds of cryptographic - operations that rely on proper random numbers. +* `-Zmiri-preemption-rate` configures the probability that at the end of a basic block, the active + thread will be preempted. The default is `0.01` (i.e., 1%). Setting this to `0` disables + preemption. +* `-Zmiri-seed=` configures the seed of the RNG that Miri uses to resolve non-determinism. This + RNG is used to pick base addresses for allocations, to determine preemption and failure of + `compare_exchange_weak`, and to control store buffering for weak memory emulation. When isolation + is enabled (the default), this is also used to emulate system entropy. The default seed is 0. You + can increase test coverage by running Miri multiple times with different seeds. **NOTE**: This + entropy is not good enough for cryptographic use! Do not generate secret keys in Miri or perform + other kinds of cryptographic operations that rely on proper random numbers. * `-Zmiri-strict-provenance` enables [strict provenance](https://github.com/rust-lang/rust/issues/95228) checking in Miri. This means that casting an integer to a pointer yields a result with 'invalid' provenance, i.e., with provenance diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 907e620404b9..64047d146c3b 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -449,6 +449,17 @@ fn main() { ), }; miri_config.cmpxchg_weak_failure_rate = rate; + } else if let Some(param) = arg.strip_prefix("-Zmiri-preemption-rate=") { + let rate = match param.parse::() { + Ok(rate) if rate >= 0.0 && rate <= 1.0 => rate, + Ok(_) => panic!("-Zmiri-preemption-rate must be between `0.0` and `1.0`"), + Err(err) => + panic!( + "-Zmiri-preemption-rate requires a `f64` between `0.0` and `1.0`: {}", + err + ), + }; + miri_config.preemption_rate = rate; } else if let Some(param) = arg.strip_prefix("-Zmiri-measureme=") { miri_config.measureme_out = Some(param.to_string()); } else if let Some(param) = arg.strip_prefix("-Zmiri-backtrace=") { diff --git a/src/eval.rs b/src/eval.rs index bdf527a0d13e..7c971d2a1490 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -122,6 +122,8 @@ pub struct MiriConfig { /// Whether to ignore any output by the program. This is helpful when debugging miri /// as its messages don't get intermingled with the program messages. pub mute_stdout_stderr: bool, + /// The probability of the active thread being preempted at the end of each basic block. + pub preemption_rate: f64, } impl Default for MiriConfig { @@ -145,12 +147,13 @@ impl Default for MiriConfig { tag_raw: false, data_race_detector: true, weak_memory_emulation: true, - cmpxchg_weak_failure_rate: 0.8, + cmpxchg_weak_failure_rate: 0.8, // 80% measureme_out: None, panic_on_unsupported: false, backtrace_style: BacktraceStyle::Short, provenance_mode: ProvenanceMode::Legacy, mute_stdout_stderr: false, + preemption_rate: 0.01, // 1% } } } diff --git a/src/machine.rs b/src/machine.rs index 1ae49edd6001..5e93045aec1a 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -333,6 +333,9 @@ pub struct Evaluator<'mir, 'tcx> { /// Whether weak memory emulation is enabled pub(crate) weak_memory: bool, + + /// The probability of the active thread being preempted at the end of each basic block. + pub(crate) preemption_rate: f64, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { @@ -389,6 +392,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate, mute_stdout_stderr: config.mute_stdout_stderr, weak_memory: config.weak_memory_emulation, + preemption_rate: config.preemption_rate, } } @@ -846,6 +850,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx.active_thread_stack_mut() } + fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { + ecx.maybe_preempt_active_thread(); + Ok(()) + } + #[inline(always)] fn after_stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { if ecx.machine.stacked_borrows.is_some() { ecx.retag_return_place() } else { Ok(()) } diff --git a/src/thread.rs b/src/thread.rs index 0d702fd9c8e1..9eabbd77419f 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -717,6 +717,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.threads.yield_active_thread(); } + #[inline] + fn maybe_preempt_active_thread(&mut self) { + use rand::Rng as _; + + let this = self.eval_context_mut(); + if this.machine.rng.get_mut().gen_bool(this.machine.preemption_rate) { + this.yield_active_thread(); + } + } + #[inline] fn register_timeout_callback( &mut self, diff --git a/tests/fail/concurrency/libc_pthread_join_self.rs b/tests/fail/concurrency/libc_pthread_join_self.rs index 2a8fe12eafd6..db45b33c1468 100644 --- a/tests/fail/concurrency/libc_pthread_join_self.rs +++ b/tests/fail/concurrency/libc_pthread_join_self.rs @@ -1,4 +1,6 @@ // ignore-windows: No libc on Windows +// We are making scheduler assumptions here. +// compile-flags: -Zmiri-preemption-rate=0 // Joining itself is undefined behavior. diff --git a/tests/fail/data_race/alloc_read_race.rs b/tests/fail/data_race/alloc_read_race.rs index 2ddbb657245a..4adb7071f294 100644 --- a/tests/fail/data_race/alloc_read_race.rs +++ b/tests/fail/data_race/alloc_read_race.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-weak-memory-emulation +// compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 #![feature(new_uninit)] use std::thread::spawn; diff --git a/tests/fail/data_race/alloc_write_race.rs b/tests/fail/data_race/alloc_write_race.rs index d32eb5567606..e4a1192f95b3 100644 --- a/tests/fail/data_race/alloc_write_race.rs +++ b/tests/fail/data_race/alloc_write_race.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-weak-memory-emulation +// compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 #![feature(new_uninit)] use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_read_race_stack.rs b/tests/fail/data_race/dealloc_read_race_stack.rs index b70db5f4ac4b..f458d1126efe 100644 --- a/tests/fail/data_race/dealloc_read_race_stack.rs +++ b/tests/fail/data_race/dealloc_read_race_stack.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation +// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::thread::{spawn, sleep}; use std::ptr::null_mut; diff --git a/tests/fail/data_race/dealloc_write_race_stack.rs b/tests/fail/data_race/dealloc_write_race_stack.rs index f2b49fc5f344..d1fe8c3e9a16 100644 --- a/tests/fail/data_race/dealloc_write_race_stack.rs +++ b/tests/fail/data_race/dealloc_write_race_stack.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation +// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::thread::{spawn, sleep}; use std::ptr::null_mut; diff --git a/tests/fail/data_race/read_write_race_stack.rs b/tests/fail/data_race/read_write_race_stack.rs index 9edeed0af652..f5c4768296b0 100644 --- a/tests/fail/data_race/read_write_race_stack.rs +++ b/tests/fail/data_race/read_write_race_stack.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 -Zmiri-disable-weak-memory-emulation +// compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 // Note: mir-opt-level set to 0 to prevent the read of stack_var in thread 1 // from being optimized away and preventing the detection of the data-race. diff --git a/tests/fail/data_race/relax_acquire_race.rs b/tests/fail/data_race/relax_acquire_race.rs index 20e63dc4b171..64c0f95fa4ba 100644 --- a/tests/fail/data_race/relax_acquire_race.rs +++ b/tests/fail/data_race/relax_acquire_race.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-weak-memory-emulation +// compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::thread::spawn; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/release_seq_race.rs b/tests/fail/data_race/release_seq_race.rs index 6ff84aa04b26..964d1b4937b8 100644 --- a/tests/fail/data_race/release_seq_race.rs +++ b/tests/fail/data_race/release_seq_race.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation +// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::thread::{spawn, sleep}; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/release_seq_race_same_thread.rs b/tests/fail/data_race/release_seq_race_same_thread.rs index 1245fb96f497..01d45a1b7ccf 100644 --- a/tests/fail/data_race/release_seq_race_same_thread.rs +++ b/tests/fail/data_race/release_seq_race_same_thread.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation +// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::thread::spawn; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/rmw_race.rs b/tests/fail/data_race/rmw_race.rs index c968c83422c0..fab6fabe5b6f 100644 --- a/tests/fail/data_race/rmw_race.rs +++ b/tests/fail/data_race/rmw_race.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-weak-memory-emulation +// compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::thread::spawn; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/write_write_race_stack.rs b/tests/fail/data_race/write_write_race_stack.rs index daa3e5f5c478..e6ae207d8610 100644 --- a/tests/fail/data_race/write_write_race_stack.rs +++ b/tests/fail/data_race/write_write_race_stack.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation +// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::thread::{spawn, sleep}; use std::ptr::null_mut; diff --git a/tests/pass/concurrency/spin_loop.rs b/tests/pass/concurrency/spin_loop.rs new file mode 100644 index 000000000000..7d26077bb49f --- /dev/null +++ b/tests/pass/concurrency/spin_loop.rs @@ -0,0 +1,42 @@ +use std::thread; +use std::sync::atomic::{AtomicUsize, Ordering}; + +static FLAG: AtomicUsize = AtomicUsize::new(0); + +fn spin() { + let j = thread::spawn(|| { + while FLAG.load(Ordering::Acquire) == 0 { + // We do *not* yield, and yet this should terminate eventually. + } + }); + thread::yield_now(); // schedule the other thread + FLAG.store(1, Ordering::Release); + j.join().unwrap(); +} + +fn two_player_ping_pong() { + static FLAG: AtomicUsize = AtomicUsize::new(0); + + let waiter1 = thread::spawn(|| { + while FLAG.load(Ordering::Acquire) == 0 { + // We do *not* yield, and yet this should terminate eventually. + } + }); + let waiter2 = thread::spawn(|| { + while FLAG.load(Ordering::Acquire) == 0 { + // We do *not* yield, and yet this should terminate eventually. + } + }); + let progress = thread::spawn(|| { + FLAG.store(1, Ordering::Release); + }); + // The first `join` blocks the main thread and thus takes it out of the equation. + waiter1.join().unwrap(); + waiter2.join().unwrap(); + progress.join().unwrap(); +} + +fn main() { + spin(); + two_player_ping_pong(); +} diff --git a/tests/pass/concurrency/spin_loop.stderr b/tests/pass/concurrency/spin_loop.stderr new file mode 100644 index 000000000000..9fe6daa778c1 --- /dev/null +++ b/tests/pass/concurrency/spin_loop.stderr @@ -0,0 +1,3 @@ +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) + diff --git a/tests/pass/concurrency/spin_loops.rs b/tests/pass/concurrency/spin_loops_nopreempt.rs similarity index 96% rename from tests/pass/concurrency/spin_loops.rs rename to tests/pass/concurrency/spin_loops_nopreempt.rs index a6fceb03638d..d8064f6ed539 100644 --- a/tests/pass/concurrency/spin_loops.rs +++ b/tests/pass/concurrency/spin_loops_nopreempt.rs @@ -1,4 +1,6 @@ // ignore-windows: Concurrency on Windows is not supported yet. +// This specifically tests behavior *without* preemption. +// compile-flags: -Zmiri-preemption-rate=0 use std::thread; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; diff --git a/tests/pass/concurrency/spin_loops_nopreempt.stderr b/tests/pass/concurrency/spin_loops_nopreempt.stderr new file mode 100644 index 000000000000..9fe6daa778c1 --- /dev/null +++ b/tests/pass/concurrency/spin_loops_nopreempt.stderr @@ -0,0 +1,3 @@ +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) + diff --git a/tests/pass/concurrency/sync.rs b/tests/pass/concurrency/sync.rs index 6889aad91cf2..26f44aa43718 100644 --- a/tests/pass/concurrency/sync.rs +++ b/tests/pass/concurrency/sync.rs @@ -1,5 +1,6 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance +// We are making scheduler assumptions here. +// compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance -Zmiri-preemption-rate=0 use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock}; use std::thread; diff --git a/tests/pass/panic/concurrent-panic.rs b/tests/pass/panic/concurrent-panic.rs index 0ff5788e204d..7b17ac4fa79c 100644 --- a/tests/pass/panic/concurrent-panic.rs +++ b/tests/pass/panic/concurrent-panic.rs @@ -1,4 +1,6 @@ // ignore-windows: Concurrency on Windows is not supported yet. +// We are making scheduler assumptions here. +// compile-flags: -Zmiri-preemption-rate=0 //! Cause a panic in one thread while another thread is unwinding. This checks //! that separate threads have their own panicking state. diff --git a/tests/pass/weak_memory/weak.rs b/tests/pass/weak_memory/weak.rs index 70e1bf00f442..e1e9c41e36f5 100644 --- a/tests/pass/weak_memory/weak.rs +++ b/tests/pass/weak_memory/weak.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-ignore-leaks +// compile-flags: -Zmiri-ignore-leaks -Zmiri-preemption-rate=0 // Tests showing weak memory behaviours are exhibited. All tests // return true when the desired behaviour is seen. From bf372a8fbc838e89234adba0339d5f2d1ea5f561 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 18:58:06 -0400 Subject: [PATCH 3245/5092] remove warning about thread support being experimental --- src/shims/unix/thread.rs | 4 ---- tests/pass/concurrency/spin_loop.rs | 1 + 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/shims/unix/thread.rs b/src/shims/unix/thread.rs index 4dc40cf2fe3d..63b9f36d6ffa 100644 --- a/src/shims/unix/thread.rs +++ b/src/shims/unix/thread.rs @@ -13,10 +13,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.tcx.sess.warn( - "thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops.\n(see https://github.com/rust-lang/miri/issues/1388)", - ); - // Create the new thread let new_thread_id = this.create_thread(); diff --git a/tests/pass/concurrency/spin_loop.rs b/tests/pass/concurrency/spin_loop.rs index 7d26077bb49f..1e81f5dc86dc 100644 --- a/tests/pass/concurrency/spin_loop.rs +++ b/tests/pass/concurrency/spin_loop.rs @@ -1,3 +1,4 @@ +// ignore-windows: Concurrency on Windows is not supported yet. use std::thread; use std::sync::atomic::{AtomicUsize, Ordering}; From 11a8b3a00b72505751743230bf265c9eecfd58db Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 19:00:50 -0400 Subject: [PATCH 3246/5092] bless tests --- .../libc_pthread_create_main_terminate.stderr | 5 +--- .../libc_pthread_join_detached.stderr | 5 +--- .../libc_pthread_join_joined.stderr | 5 +--- .../concurrency/libc_pthread_join_main.stderr | 5 +--- .../libc_pthread_join_multiple.stderr | 5 +--- .../concurrency/libc_pthread_join_self.stderr | 5 +--- .../thread_local_static_dealloc.stderr | 5 +--- tests/fail/concurrency/too_few_args.stderr | 5 +--- tests/fail/concurrency/too_many_args.stderr | 5 +--- .../concurrency/unwind_top_of_stack.stderr | 5 +--- tests/fail/data_race/alloc_read_race.stderr | 5 +--- tests/fail/data_race/alloc_write_race.stderr | 5 +--- .../atomic_read_na_write_race1.stderr | 5 +--- .../atomic_read_na_write_race2.stderr | 5 +--- .../atomic_write_na_read_race1.stderr | 5 +--- .../atomic_write_na_read_race2.stderr | 5 +--- .../atomic_write_na_write_race1.stderr | 5 +--- .../atomic_write_na_write_race2.stderr | 5 +--- .../dangling_thread_async_race.stderr | 5 +--- .../data_race/dangling_thread_race.stderr | 5 +--- .../fail/data_race/dealloc_read_race1.stderr | 5 +--- .../fail/data_race/dealloc_read_race2.stderr | 5 +--- .../data_race/dealloc_read_race_stack.stderr | 5 +--- .../fail/data_race/dealloc_write_race1.stderr | 5 +--- .../fail/data_race/dealloc_write_race2.stderr | 5 +--- .../data_race/dealloc_write_race_stack.stderr | 5 +--- .../enable_after_join_to_main.stderr | 5 +--- tests/fail/data_race/fence_after_load.stderr | 5 +--- tests/fail/data_race/read_write_race.stderr | 5 +--- .../data_race/read_write_race_stack.stderr | 5 +--- .../fail/data_race/relax_acquire_race.stderr | 5 +--- tests/fail/data_race/release_seq_race.stderr | 5 +--- .../release_seq_race_same_thread.stderr | 5 +--- tests/fail/data_race/rmw_race.stderr | 5 +--- tests/fail/data_race/write_write_race.stderr | 5 +--- .../data_race/write_write_race_stack.stderr | 5 +--- tests/fail/should-pass/cpp20_rwc_syncs.rs | 4 +-- tests/fail/should-pass/cpp20_rwc_syncs.stderr | 26 +++++++++++++++++-- .../sync/libc_pthread_mutex_deadlock.stderr | 5 +--- .../libc_pthread_mutex_wrong_owner.stderr | 5 +--- ...ibc_pthread_rwlock_read_wrong_owner.stderr | 5 +--- ..._pthread_rwlock_write_read_deadlock.stderr | 5 +--- ...pthread_rwlock_write_write_deadlock.stderr | 5 +--- ...bc_pthread_rwlock_write_wrong_owner.stderr | 5 +--- .../fail/weak_memory/racing_mixed_size.stderr | 5 +--- .../weak_memory/racing_mixed_size_read.stderr | 5 +--- tests/pass/concurrency/channels.stderr | 3 --- .../concurrent_caller_location.stderr | 3 --- tests/pass/concurrency/data_race.stderr | 3 --- .../disable_data_race_detector.stderr | 3 --- tests/pass/concurrency/issue1643.stderr | 3 --- tests/pass/concurrency/linux-futex.stderr | 3 --- tests/pass/concurrency/simple.stderr | 3 --- tests/pass/concurrency/spin_loop.stderr | 3 --- .../concurrency/spin_loops_nopreempt.stderr | 3 --- tests/pass/concurrency/sync.stderr | 3 --- tests/pass/concurrency/thread_locals.stderr | 3 --- tests/pass/concurrency/tls_lib_drop.stderr | 3 --- tests/pass/libc.stderr | 3 --- tests/pass/panic/concurrent-panic.stderr | 3 --- tests/pass/threadleak_ignored.stderr | 3 --- tests/pass/weak_memory/consistency.stderr | 3 --- tests/pass/weak_memory/extra_cpp.stderr | 3 --- .../pass/weak_memory/extra_cpp_unsafe.stderr | 3 --- tests/pass/weak_memory/weak.stderr | 3 --- 65 files changed, 70 insertions(+), 237 deletions(-) delete mode 100644 tests/pass/concurrency/channels.stderr delete mode 100644 tests/pass/concurrency/concurrent_caller_location.stderr delete mode 100644 tests/pass/concurrency/data_race.stderr delete mode 100644 tests/pass/concurrency/disable_data_race_detector.stderr delete mode 100644 tests/pass/concurrency/issue1643.stderr delete mode 100644 tests/pass/concurrency/linux-futex.stderr delete mode 100644 tests/pass/concurrency/spin_loop.stderr delete mode 100644 tests/pass/concurrency/spin_loops_nopreempt.stderr delete mode 100644 tests/pass/concurrency/sync.stderr delete mode 100644 tests/pass/concurrency/thread_locals.stderr delete mode 100644 tests/pass/concurrency/tls_lib_drop.stderr delete mode 100644 tests/pass/libc.stderr delete mode 100644 tests/pass/weak_memory/consistency.stderr delete mode 100644 tests/pass/weak_memory/extra_cpp.stderr delete mode 100644 tests/pass/weak_memory/extra_cpp_unsafe.stderr delete mode 100644 tests/pass/weak_memory/weak.stderr diff --git a/tests/fail/concurrency/libc_pthread_create_main_terminate.stderr b/tests/fail/concurrency/libc_pthread_create_main_terminate.stderr index 2ce73fdaaec1..c5093c0e6011 100644 --- a/tests/fail/concurrency/libc_pthread_create_main_terminate.stderr +++ b/tests/fail/concurrency/libc_pthread_create_main_terminate.stderr @@ -1,9 +1,6 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: the main thread terminated without waiting for all remaining threads note: pass `-Zmiri-ignore-leaks` to disable this check -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/concurrency/libc_pthread_join_detached.stderr b/tests/fail/concurrency/libc_pthread_join_detached.stderr index b106cc4c9541..44d0f727a395 100644 --- a/tests/fail/concurrency/libc_pthread_join_detached.stderr +++ b/tests/fail/concurrency/libc_pthread_join_detached.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: trying to join a detached or already joined thread --> $DIR/libc_pthread_join_detached.rs:LL:CC | @@ -14,5 +11,5 @@ LL | ... assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/concurrency/libc_pthread_join_joined.stderr b/tests/fail/concurrency/libc_pthread_join_joined.stderr index 438998208d11..b67974c58eae 100644 --- a/tests/fail/concurrency/libc_pthread_join_joined.stderr +++ b/tests/fail/concurrency/libc_pthread_join_joined.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: trying to join a detached or already joined thread --> $DIR/libc_pthread_join_joined.rs:LL:CC | @@ -14,5 +11,5 @@ LL | ... assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/concurrency/libc_pthread_join_main.stderr b/tests/fail/concurrency/libc_pthread_join_main.stderr index 04f2ab07406c..3e69df508359 100644 --- a/tests/fail/concurrency/libc_pthread_join_main.stderr +++ b/tests/fail/concurrency/libc_pthread_join_main.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: trying to join a detached or already joined thread --> $DIR/libc_pthread_join_main.rs:LL:CC | @@ -14,5 +11,5 @@ LL | ... assert_eq!(libc::pthread_join(thread_id, ptr::null_mut()), 0); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/concurrency/libc_pthread_join_multiple.stderr b/tests/fail/concurrency/libc_pthread_join_multiple.stderr index daf18c50e034..997bca9fe422 100644 --- a/tests/fail/concurrency/libc_pthread_join_multiple.stderr +++ b/tests/fail/concurrency/libc_pthread_join_multiple.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: trying to join a detached or already joined thread --> $DIR/libc_pthread_join_multiple.rs:LL:CC | @@ -14,5 +11,5 @@ LL | ... assert_eq!(libc::pthread_join(native_copy, ptr::null_mut()), 0); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/concurrency/libc_pthread_join_self.stderr b/tests/fail/concurrency/libc_pthread_join_self.stderr index b2e0779f5fbb..8d2acb817f93 100644 --- a/tests/fail/concurrency/libc_pthread_join_self.stderr +++ b/tests/fail/concurrency/libc_pthread_join_self.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: trying to join itself --> $DIR/libc_pthread_join_self.rs:LL:CC | @@ -14,5 +11,5 @@ LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/concurrency/thread_local_static_dealloc.stderr b/tests/fail/concurrency/thread_local_static_dealloc.stderr index ad5528dc555a..a485edc0da93 100644 --- a/tests/fail/concurrency/thread_local_static_dealloc.stderr +++ b/tests/fail/concurrency/thread_local_static_dealloc.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed --> $DIR/thread_local_static_dealloc.rs:LL:CC | @@ -14,5 +11,5 @@ LL | let _val = *(dangling_ptr as *const u8); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/concurrency/too_few_args.stderr b/tests/fail/concurrency/too_few_args.stderr index 1ed8c5a510f4..9d96b718bc30 100644 --- a/tests/fail/concurrency/too_few_args.stderr +++ b/tests/fail/concurrency/too_few_args.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: callee has fewer arguments than expected --> $DIR/too_few_args.rs:LL:CC | @@ -13,5 +10,5 @@ LL | panic!() = note: inside `thread_start` at RUSTLIB/std/src/panic.rs:LL:CC = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/concurrency/too_many_args.stderr b/tests/fail/concurrency/too_many_args.stderr index 5602dab993b0..7132b8c453af 100644 --- a/tests/fail/concurrency/too_many_args.stderr +++ b/tests/fail/concurrency/too_many_args.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: callee has more arguments than expected --> $DIR/too_many_args.rs:LL:CC | @@ -13,5 +10,5 @@ LL | panic!() = note: inside `thread_start` at RUSTLIB/std/src/panic.rs:LL:CC = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/concurrency/unwind_top_of_stack.stderr b/tests/fail/concurrency/unwind_top_of_stack.stderr index 26a196a5590f..35d6f7c38494 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.stderr +++ b/tests/fail/concurrency/unwind_top_of_stack.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - thread '' panicked at 'explicit panic', $DIR/unwind_top_of_stack.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: Undefined Behavior: unwinding past the topmost frame of the stack @@ -16,5 +13,5 @@ LL | | } = note: inside `thread_start` at $DIR/unwind_top_of_stack.rs:LL:CC -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/alloc_read_race.stderr b/tests/fail/data_race/alloc_read_race.stderr index 0b247fb19bc9..52004f2d2d02 100644 --- a/tests/fail/data_race/alloc_read_race.stderr +++ b/tests/fail/data_race/alloc_read_race.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Read on Thread(id = 2) and Allocate on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/alloc_read_race.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *pointer.load(Ordering::Relaxed) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/alloc_write_race.stderr b/tests/fail/data_race/alloc_write_race.stderr index 3594980ef9b0..b6c05b34073c 100644 --- a/tests/fail/data_race/alloc_write_race.stderr +++ b/tests/fail/data_race/alloc_write_race.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Allocate on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/alloc_write_race.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *pointer.load(Ordering::Relaxed) = 2; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/atomic_read_na_write_race1.stderr b/tests/fail/data_race/atomic_read_na_write_race1.stderr index 0c9aaf5a0019..80e79eb553ee 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.stderr +++ b/tests/fail/data_race/atomic_read_na_write_race1.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Atomic Load on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/atomic_read_na_write_race1.rs:LL:CC | @@ -14,5 +11,5 @@ LL | atomic_load(c.0 as *mut usize) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/atomic_read_na_write_race2.stderr b/tests/fail/data_race/atomic_read_na_write_race2.stderr index 6e3a1330f9dd..9a432c586afe 100644 --- a/tests/fail/data_race/atomic_read_na_write_race2.stderr +++ b/tests/fail/data_race/atomic_read_na_write_race2.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Atomic Load on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/atomic_read_na_write_race2.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *atomic_ref.get_mut() = 32; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/atomic_write_na_read_race1.stderr b/tests/fail/data_race/atomic_write_na_read_race1.stderr index 4dc4ac1e6768..8280f43b518f 100644 --- a/tests/fail/data_race/atomic_write_na_read_race1.stderr +++ b/tests/fail/data_race/atomic_write_na_read_race1.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Read on Thread(id = 2) and Atomic Store on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/atomic_write_na_read_race1.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *atomic_ref.get_mut() note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/atomic_write_na_read_race2.stderr b/tests/fail/data_race/atomic_write_na_read_race2.stderr index e665073c539e..63d0f5814ef4 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.stderr +++ b/tests/fail/data_race/atomic_write_na_read_race2.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Atomic Store on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/atomic_write_na_read_race2.rs:LL:CC | @@ -14,5 +11,5 @@ LL | atomic_store(c.0 as *mut usize, 32); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/atomic_write_na_write_race1.stderr b/tests/fail/data_race/atomic_write_na_write_race1.stderr index a70c3b52de50..332be7406c82 100644 --- a/tests/fail/data_race/atomic_write_na_write_race1.stderr +++ b/tests/fail/data_race/atomic_write_na_write_race1.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Atomic Store on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/atomic_write_na_write_race1.rs:LL:CC | @@ -14,5 +11,5 @@ LL | atomic_store(c.0 as *mut usize, 64); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/atomic_write_na_write_race2.stderr b/tests/fail/data_race/atomic_write_na_write_race2.stderr index 79730d507934..024f525b1213 100644 --- a/tests/fail/data_race/atomic_write_na_write_race2.stderr +++ b/tests/fail/data_race/atomic_write_na_write_race2.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Atomic Store on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/atomic_write_na_write_race2.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *atomic_ref.get_mut() = 32; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/dangling_thread_async_race.stderr b/tests/fail/data_race/dangling_thread_async_race.stderr index 21b3eefc5e41..6d31e3971e53 100644 --- a/tests/fail/data_race/dangling_thread_async_race.stderr +++ b/tests/fail/data_race/dangling_thread_async_race.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Write on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/dangling_thread_async_race.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *c.0 = 64; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/dangling_thread_race.stderr b/tests/fail/data_race/dangling_thread_race.stderr index 3ca8862a5819..ba1ef2760f8f 100644 --- a/tests/fail/data_race/dangling_thread_race.stderr +++ b/tests/fail/data_race/dangling_thread_race.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/dangling_thread_race.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *c.0 = 64; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/dealloc_read_race1.stderr b/tests/fail/data_race/dealloc_read_race1.stderr index 10b32003ff40..6b5cf5fc02f6 100644 --- a/tests/fail/data_race/dealloc_read_race1.stderr +++ b/tests/fail/data_race/dealloc_read_race1.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/dealloc_read_race1.rs:LL:CC | @@ -14,5 +11,5 @@ LL | __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), s note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/dealloc_read_race2.stderr b/tests/fail/data_race/dealloc_read_race2.stderr index a21de1d9f7a9..f703d1896d91 100644 --- a/tests/fail/data_race/dealloc_read_race2.stderr +++ b/tests/fail/data_race/dealloc_read_race2.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed --> $DIR/dealloc_read_race2.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *ptr.0 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/dealloc_read_race_stack.stderr b/tests/fail/data_race/dealloc_read_race_stack.stderr index 0f7213eb8d52..1275d1290b0a 100644 --- a/tests/fail/data_race/dealloc_read_race_stack.stderr +++ b/tests/fail/data_race/dealloc_read_race_stack.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/dealloc_read_race_stack.rs:LL:CC | @@ -14,5 +11,5 @@ LL | } note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/dealloc_write_race1.stderr b/tests/fail/data_race/dealloc_write_race1.stderr index 76258e9d8fc0..ac9701d49f5f 100644 --- a/tests/fail/data_race/dealloc_write_race1.stderr +++ b/tests/fail/data_race/dealloc_write_race1.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/dealloc_write_race1.rs:LL:CC | @@ -14,5 +11,5 @@ LL | __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), s note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/dealloc_write_race2.stderr b/tests/fail/data_race/dealloc_write_race2.stderr index d9aef72118d8..37d1c551d493 100644 --- a/tests/fail/data_race/dealloc_write_race2.stderr +++ b/tests/fail/data_race/dealloc_write_race2.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed --> $DIR/dealloc_write_race2.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *ptr.0 = 2; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/dealloc_write_race_stack.stderr b/tests/fail/data_race/dealloc_write_race_stack.stderr index 70533f654b77..28a131aac07b 100644 --- a/tests/fail/data_race/dealloc_write_race_stack.stderr +++ b/tests/fail/data_race/dealloc_write_race_stack.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/dealloc_write_race_stack.rs:LL:CC | @@ -14,5 +11,5 @@ LL | } note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/enable_after_join_to_main.stderr b/tests/fail/data_race/enable_after_join_to_main.stderr index 58d33ffa8cf3..db7577b0966e 100644 --- a/tests/fail/data_race/enable_after_join_to_main.stderr +++ b/tests/fail/data_race/enable_after_join_to_main.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Write on Thread(id = 6) and Write on Thread(id = 5) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/enable_after_join_to_main.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *c.0 = 64; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/fence_after_load.stderr b/tests/fail/data_race/fence_after_load.stderr index 1e3186b08fa1..17cc6a82a1c2 100644 --- a/tests/fail/data_race/fence_after_load.stderr +++ b/tests/fail/data_race/fence_after_load.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/fence_after_load.rs:LL:CC | @@ -14,5 +11,5 @@ LL | unsafe { V = 2 } note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/read_write_race.stderr b/tests/fail/data_race/read_write_race.stderr index 5078e662546a..b775e2b6fdf1 100644 --- a/tests/fail/data_race/read_write_race.stderr +++ b/tests/fail/data_race/read_write_race.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/read_write_race.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *c.0 = 64; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/read_write_race_stack.stderr b/tests/fail/data_race/read_write_race_stack.stderr index 843bea753b65..0f5f4956ffda 100644 --- a/tests/fail/data_race/read_write_race_stack.stderr +++ b/tests/fail/data_race/read_write_race_stack.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/read_write_race_stack.rs:LL:CC | @@ -14,5 +11,5 @@ LL | stack_var note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/relax_acquire_race.stderr b/tests/fail/data_race/relax_acquire_race.stderr index d2423ff91631..fb376b58f2c1 100644 --- a/tests/fail/data_race/relax_acquire_race.stderr +++ b/tests/fail/data_race/relax_acquire_race.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/relax_acquire_race.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *c.0 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/release_seq_race.stderr b/tests/fail/data_race/release_seq_race.stderr index ffbf50c09172..1de9c0ac1c7f 100644 --- a/tests/fail/data_race/release_seq_race.stderr +++ b/tests/fail/data_race/release_seq_race.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/release_seq_race.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *c.0 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/release_seq_race_same_thread.stderr b/tests/fail/data_race/release_seq_race_same_thread.stderr index b76021514611..9bbdd9a47573 100644 --- a/tests/fail/data_race/release_seq_race_same_thread.stderr +++ b/tests/fail/data_race/release_seq_race_same_thread.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Read on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/release_seq_race_same_thread.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *c.0 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/rmw_race.stderr b/tests/fail/data_race/rmw_race.stderr index c6b09ba5f00b..10d3291fa733 100644 --- a/tests/fail/data_race/rmw_race.stderr +++ b/tests/fail/data_race/rmw_race.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/rmw_race.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *c.0 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/write_write_race.stderr b/tests/fail/data_race/write_write_race.stderr index 5acba97486ea..0054f5bf63a0 100644 --- a/tests/fail/data_race/write_write_race.stderr +++ b/tests/fail/data_race/write_write_race.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/write_write_race.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *c.0 = 64; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/write_write_race_stack.stderr b/tests/fail/data_race/write_write_race_stack.stderr index d052206f4cc7..2012643431f6 100644 --- a/tests/fail/data_race/write_write_race_stack.stderr +++ b/tests/fail/data_race/write_write_race_stack.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Write on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/write_write_race_stack.rs:LL:CC | @@ -14,5 +11,5 @@ LL | stack_var = 1usize; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/should-pass/cpp20_rwc_syncs.rs b/tests/fail/should-pass/cpp20_rwc_syncs.rs index e5192cd0d670..00b03bceb65e 100644 --- a/tests/fail/should-pass/cpp20_rwc_syncs.rs +++ b/tests/fail/should-pass/cpp20_rwc_syncs.rs @@ -1,6 +1,6 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-ignore-leaks -// error-pattern: +// error-pattern: unreachable // https://plv.mpi-sws.org/scfix/paper.pdf // 2.2 Second Problem: SC Fences are Too Weak @@ -76,7 +76,7 @@ fn test_cpp20_rwc_syncs() { // Our ui_test does not yet support overriding failure status codes. if (b, c) == (0, 0) { // This *should* be unreachable, but Miri will reach it. - std::process::exit(1); + unsafe { std::hint::unreachable_unchecked(); } } } diff --git a/tests/fail/should-pass/cpp20_rwc_syncs.stderr b/tests/fail/should-pass/cpp20_rwc_syncs.stderr index 9fe6daa778c1..9aec82d33365 100644 --- a/tests/fail/should-pass/cpp20_rwc_syncs.stderr +++ b/tests/fail/should-pass/cpp20_rwc_syncs.stderr @@ -1,3 +1,25 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) +error: Undefined Behavior: entering unreachable code + --> RUSTLIB/core/src/hint.rs:LL:CC + | +LL | unsafe { intrinsics::unreachable() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::hint::unreachable_unchecked` at RUSTLIB/core/src/hint.rs:LL:CC +note: inside `test_cpp20_rwc_syncs` at $DIR/cpp20_rwc_syncs.rs:LL:CC + --> $DIR/cpp20_rwc_syncs.rs:LL:CC + | +LL | unsafe { std::hint::unreachable_unchecked(); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: inside `main` at $DIR/cpp20_rwc_syncs.rs:LL:CC + --> $DIR/cpp20_rwc_syncs.rs:LL:CC + | +LL | test_cpp20_rwc_syncs(); + | ^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error diff --git a/tests/fail/sync/libc_pthread_mutex_deadlock.stderr b/tests/fail/sync/libc_pthread_mutex_deadlock.stderr index d1f9ee6cdd5f..599655a8692b 100644 --- a/tests/fail/sync/libc_pthread_mutex_deadlock.stderr +++ b/tests/fail/sync/libc_pthread_mutex_deadlock.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: deadlock: the evaluated program deadlocked --> $DIR/libc_pthread_mutex_deadlock.rs:LL:CC | @@ -11,5 +8,5 @@ LL | assert_eq!(libc::pthread_mutex_lock(lock_copy.0.get() as *mut _ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr b/tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr index e9f0e2d4c157..86d02c22819e 100644 --- a/tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr +++ b/tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: unlocked a default mutex that was not locked by the current thread --> $DIR/libc_pthread_mutex_wrong_owner.rs:LL:CC | @@ -14,5 +11,5 @@ LL | ...t_eq!(libc::pthread_mutex_unlock(lock_copy.0.get() as *mut _), 0); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr b/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr index c25ab25a3da5..c7c8823eaa37 100644 --- a/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr +++ b/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: unlocked an rwlock that was not locked by the active thread --> $DIR/libc_pthread_rwlock_read_wrong_owner.rs:LL:CC | @@ -14,5 +11,5 @@ LL | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr index 8fc2ae4c82e5..333fb1afb91b 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr +++ b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: deadlock: the evaluated program deadlocked --> $DIR/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC | @@ -11,5 +8,5 @@ LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mu note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr index 86c67925fb93..93bede54fcf1 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr +++ b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: deadlock: the evaluated program deadlocked --> $DIR/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC | @@ -11,5 +8,5 @@ LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mu note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr b/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr index 8965d55a489d..a7a17ae71b3a 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr +++ b/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: unlocked an rwlock that was not locked by the active thread --> $DIR/libc_pthread_rwlock_write_wrong_owner.rs:LL:CC | @@ -14,5 +11,5 @@ LL | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/weak_memory/racing_mixed_size.stderr b/tests/fail/weak_memory/racing_mixed_size.stderr index fc6be84315d7..0fb23be06bb7 100644 --- a/tests/fail/weak_memory/racing_mixed_size.stderr +++ b/tests/fail/weak_memory/racing_mixed_size.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: unsupported operation: racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation --> $DIR/racing_mixed_size.rs:LL:CC | @@ -13,5 +10,5 @@ LL | std::intrinsics::atomic_load_relaxed(hi); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/weak_memory/racing_mixed_size_read.stderr b/tests/fail/weak_memory/racing_mixed_size_read.stderr index 846d03f5448f..6de185161084 100644 --- a/tests/fail/weak_memory/racing_mixed_size_read.stderr +++ b/tests/fail/weak_memory/racing_mixed_size_read.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: unsupported operation: racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation --> $DIR/racing_mixed_size_read.rs:LL:CC | @@ -13,5 +10,5 @@ LL | std::intrinsics::atomic_load_relaxed(hi); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/pass/concurrency/channels.stderr b/tests/pass/concurrency/channels.stderr deleted file mode 100644 index 9fe6daa778c1..000000000000 --- a/tests/pass/concurrency/channels.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/concurrency/concurrent_caller_location.stderr b/tests/pass/concurrency/concurrent_caller_location.stderr deleted file mode 100644 index 9fe6daa778c1..000000000000 --- a/tests/pass/concurrency/concurrent_caller_location.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/concurrency/data_race.stderr b/tests/pass/concurrency/data_race.stderr deleted file mode 100644 index 9fe6daa778c1..000000000000 --- a/tests/pass/concurrency/data_race.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/concurrency/disable_data_race_detector.stderr b/tests/pass/concurrency/disable_data_race_detector.stderr deleted file mode 100644 index 9fe6daa778c1..000000000000 --- a/tests/pass/concurrency/disable_data_race_detector.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/concurrency/issue1643.stderr b/tests/pass/concurrency/issue1643.stderr deleted file mode 100644 index 9fe6daa778c1..000000000000 --- a/tests/pass/concurrency/issue1643.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/concurrency/linux-futex.stderr b/tests/pass/concurrency/linux-futex.stderr deleted file mode 100644 index 9fe6daa778c1..000000000000 --- a/tests/pass/concurrency/linux-futex.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/concurrency/simple.stderr b/tests/pass/concurrency/simple.stderr index 0ba9e8645b28..028cc0fb736f 100644 --- a/tests/pass/concurrency/simple.stderr +++ b/tests/pass/concurrency/simple.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - thread '' panicked at 'Hello!', $DIR/simple.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace thread 'childthread' panicked at 'Hello, world!', $DIR/simple.rs:LL:CC diff --git a/tests/pass/concurrency/spin_loop.stderr b/tests/pass/concurrency/spin_loop.stderr deleted file mode 100644 index 9fe6daa778c1..000000000000 --- a/tests/pass/concurrency/spin_loop.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/concurrency/spin_loops_nopreempt.stderr b/tests/pass/concurrency/spin_loops_nopreempt.stderr deleted file mode 100644 index 9fe6daa778c1..000000000000 --- a/tests/pass/concurrency/spin_loops_nopreempt.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/concurrency/sync.stderr b/tests/pass/concurrency/sync.stderr deleted file mode 100644 index 9fe6daa778c1..000000000000 --- a/tests/pass/concurrency/sync.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/concurrency/thread_locals.stderr b/tests/pass/concurrency/thread_locals.stderr deleted file mode 100644 index 9fe6daa778c1..000000000000 --- a/tests/pass/concurrency/thread_locals.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/concurrency/tls_lib_drop.stderr b/tests/pass/concurrency/tls_lib_drop.stderr deleted file mode 100644 index 9fe6daa778c1..000000000000 --- a/tests/pass/concurrency/tls_lib_drop.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/libc.stderr b/tests/pass/libc.stderr deleted file mode 100644 index 9fe6daa778c1..000000000000 --- a/tests/pass/libc.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/panic/concurrent-panic.stderr b/tests/pass/panic/concurrent-panic.stderr index b90cc01bb857..fd8fabc89ccc 100644 --- a/tests/pass/panic/concurrent-panic.stderr +++ b/tests/pass/panic/concurrent-panic.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - Thread 1 starting, will block on mutex Thread 1 reported it has started thread '' panicked at 'panic in thread 2', $DIR/concurrent-panic.rs:LL:CC diff --git a/tests/pass/threadleak_ignored.stderr b/tests/pass/threadleak_ignored.stderr index af327a3012c3..7557f49c7584 100644 --- a/tests/pass/threadleak_ignored.stderr +++ b/tests/pass/threadleak_ignored.stderr @@ -1,4 +1 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - Dropping 0 diff --git a/tests/pass/weak_memory/consistency.stderr b/tests/pass/weak_memory/consistency.stderr deleted file mode 100644 index 9fe6daa778c1..000000000000 --- a/tests/pass/weak_memory/consistency.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/weak_memory/extra_cpp.stderr b/tests/pass/weak_memory/extra_cpp.stderr deleted file mode 100644 index 9fe6daa778c1..000000000000 --- a/tests/pass/weak_memory/extra_cpp.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/weak_memory/extra_cpp_unsafe.stderr b/tests/pass/weak_memory/extra_cpp_unsafe.stderr deleted file mode 100644 index 9fe6daa778c1..000000000000 --- a/tests/pass/weak_memory/extra_cpp_unsafe.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/weak_memory/weak.stderr b/tests/pass/weak_memory/weak.stderr deleted file mode 100644 index 9fe6daa778c1..000000000000 --- a/tests/pass/weak_memory/weak.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - From 61f5680da02206b4d3c354100f2e8341fde6c2a0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 7 Jun 2022 07:58:21 -0400 Subject: [PATCH 3247/5092] add stdlib test for TLS dtor order --- tests/pass/concurrency/tls_lib_drop.rs | 109 +++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/tests/pass/concurrency/tls_lib_drop.rs b/tests/pass/concurrency/tls_lib_drop.rs index 86f03bac34f6..552b371cc7f1 100644 --- a/tests/pass/concurrency/tls_lib_drop.rs +++ b/tests/pass/concurrency/tls_lib_drop.rs @@ -71,7 +71,116 @@ fn check_blocking() { thread::yield_now(); } +// This test tests that TLS destructors have run before the thread joins. The +// test has no false positives (meaning: if the test fails, there's actually +// an ordering problem). It may have false negatives, where the test passes but +// join is not guaranteed to be after the TLS destructors. However, false +// negatives should be exceedingly rare due to judicious use of +// thread::yield_now and running the test several times. +fn join_orders_after_tls_destructors() { + use std::sync::atomic::{AtomicU8, Ordering}; + + // We emulate a synchronous MPSC rendezvous channel using only atomics and + // thread::yield_now. We can't use std::mpsc as the implementation itself + // may rely on thread locals. + // + // The basic state machine for an SPSC rendezvous channel is: + // FRESH -> THREAD1_WAITING -> MAIN_THREAD_RENDEZVOUS + // where the first transition is done by the “receiving” thread and the 2nd + // transition is done by the “sending” thread. + // + // We add an additional state `THREAD2_LAUNCHED` between `FRESH` and + // `THREAD1_WAITING` to block until all threads are actually running. + // + // A thread that joins on the “receiving” thread completion should never + // observe the channel in the `THREAD1_WAITING` state. If this does occur, + // we switch to the “poison” state `THREAD2_JOINED` and panic all around. + // (This is equivalent to “sending” from an alternate producer thread.) + const FRESH: u8 = 0; + const THREAD2_LAUNCHED: u8 = 1; + const THREAD1_WAITING: u8 = 2; + const MAIN_THREAD_RENDEZVOUS: u8 = 3; + const THREAD2_JOINED: u8 = 4; + static SYNC_STATE: AtomicU8 = AtomicU8::new(FRESH); + + for _ in 0..10 { + SYNC_STATE.store(FRESH, Ordering::SeqCst); + + let jh = thread::Builder::new() + .name("thread1".into()) + .spawn(move || { + struct TlDrop; + + impl Drop for TlDrop { + fn drop(&mut self) { + let mut sync_state = SYNC_STATE.swap(THREAD1_WAITING, Ordering::SeqCst); + loop { + match sync_state { + THREAD2_LAUNCHED | THREAD1_WAITING => thread::yield_now(), + MAIN_THREAD_RENDEZVOUS => break, + THREAD2_JOINED => panic!( + "Thread 1 still running after thread 2 joined on thread 1" + ), + v => unreachable!("sync state: {}", v), + } + sync_state = SYNC_STATE.load(Ordering::SeqCst); + } + } + } + + thread_local! { + static TL_DROP: TlDrop = TlDrop; + } + + TL_DROP.with(|_| {}); + + loop { + match SYNC_STATE.load(Ordering::SeqCst) { + FRESH => thread::yield_now(), + THREAD2_LAUNCHED => break, + v => unreachable!("sync state: {}", v), + } + } + }) + .unwrap(); + + let jh2 = thread::Builder::new() + .name("thread2".into()) + .spawn(move || { + assert_eq!(SYNC_STATE.swap(THREAD2_LAUNCHED, Ordering::SeqCst), FRESH); + jh.join().unwrap(); + match SYNC_STATE.swap(THREAD2_JOINED, Ordering::SeqCst) { + MAIN_THREAD_RENDEZVOUS => return, + THREAD2_LAUNCHED | THREAD1_WAITING => { + panic!("Thread 2 running after thread 1 join before main thread rendezvous") + } + v => unreachable!("sync state: {:?}", v), + } + }) + .unwrap(); + + loop { + match SYNC_STATE.compare_exchange( + THREAD1_WAITING, + MAIN_THREAD_RENDEZVOUS, + Ordering::SeqCst, + Ordering::SeqCst, + ) { + Ok(_) => break, + Err(FRESH) => thread::yield_now(), + Err(THREAD2_LAUNCHED) => thread::yield_now(), + Err(THREAD2_JOINED) => { + panic!("Main thread rendezvous after thread 2 joined thread 1") + } + v => unreachable!("sync state: {:?}", v), + } + } + jh2.join().unwrap(); + } +} + fn main() { check_destructors(); check_blocking(); + join_orders_after_tls_destructors(); } From 4758ce74efebf59f7f31cb564541dfef00483898 Mon Sep 17 00:00:00 2001 From: InfRandomness <43730933+InfRandomness@users.noreply.github.com> Date: Tue, 7 Jun 2022 17:40:14 +0000 Subject: [PATCH 3248/5092] Fix typo --- src/shims/env.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index ae9b8c75145f..5cffc5c6d1d5 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -381,7 +381,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let target_os = &this.tcx.sess.target.os; assert!( target_os == "linux" || target_os == "macos", - "`getcwd` is only available for the UNIX target family" + "`chdir` is only available for the UNIX target family" ); let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; From cca3dea37974a8f624a41c603e0ec5ca6a450299 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 7 Jun 2022 13:59:47 -0400 Subject: [PATCH 3249/5092] update and move cargo-miri operational description --- cargo-miri/bin.rs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index ba885d307a85..8b11016ca1be 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -1063,6 +1063,19 @@ fn main() { // Skip binary name. args.next().unwrap(); + // Dispatch to `cargo-miri` phase. There are four phases: + // - When we are called via `cargo miri`, we run as the frontend and invoke the underlying + // cargo. We set RUSTDOC, RUSTC_WRAPPER and CARGO_TARGET_RUNNER to ourselves. + // - When we are executed due to RUSTDOC, we run rustdoc and set both `--test-builder` and + // `--runtool` to ourselves. + // - When we are executed due to RUSTC_WRAPPER (or as the rustdoc test builder), we build crates + // or store the flags of binary crates for later interpretation. + // - When we are executed due to CARGO_TARGET_RUNNER (or as the rustdoc runtool), we start + // interpretation based on the flags that were stored earlier. + // + // Additionally, we also set ourselves as RUSTC when calling xargo to build the sysroot, which + // has to be treated slightly differently than when we build regular crates. + // Dispatch running as part of sysroot compilation. if env::var_os("MIRI_CALLED_FROM_XARGO").is_some() { phase_rustc(args, RustcPhase::Setup); @@ -1094,14 +1107,6 @@ fn main() { return; } - // Dispatch to `cargo-miri` phase. There are three phases: - // - When we are called via `cargo miri`, we run as the frontend and invoke the underlying - // cargo. We set RUSTC_WRAPPER and CARGO_TARGET_RUNNER to ourselves. - // - When we are executed due to RUSTC_WRAPPER, we build crates or store the flags of - // binary crates for later interpretation. - // - When we are executed due to CARGO_TARGET_RUNNER, we start interpretation based on the - // flags that were stored earlier. - // On top of that, we are also called as RUSTDOC, but that is just a stub currently. match args.next().as_deref() { Some("miri") => phase_cargo_miri(args), Some("rustc") => phase_rustc(args, RustcPhase::Build), From 7a5de0c98afe9497aa74b3bba124e2fda55ce82c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 7 Jun 2022 16:01:44 -0400 Subject: [PATCH 3250/5092] silence another clippy lint --- src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 982d3873d573..7d8eb92ac58e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,8 @@ clippy::new_without_default, clippy::single_match, clippy::useless_format, - clippy::derive_partial_eq_without_eq + clippy::derive_partial_eq_without_eq, + clippy::too_many_arguments )] extern crate rustc_apfloat; From aa68111c60d6fe1a58638cf8c407509972627a67 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 7 Jun 2022 16:03:32 -0400 Subject: [PATCH 3251/5092] gate bors on clippy --- .github/workflows/ci.yml | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 41cf159e0c80..2bfc58be28d7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -86,22 +86,8 @@ jobs: - name: Test run: bash ./ci.sh - fmt: - name: formatting (ignored by bors) - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Install latest nightly - run: | - rustup toolchain install nightly --component rustfmt - rustup override set nightly - - name: Formatting (miri, ui_test) - run: cargo fmt --all --check - - name: Formatting (cargo-miri) - run: cargo fmt --manifest-path cargo-miri/Cargo.toml --all --check - clippy: - name: clippy (ignored by bors) + name: clippy runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -117,6 +103,20 @@ jobs: - name: Clippy (cargo-miri) run: cargo clippy --manifest-path cargo-miri/Cargo.toml --all-targets -- -D warnings + fmt: + name: formatting (ignored by bors) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install latest nightly + run: | + rustup toolchain install nightly --component rustfmt + rustup override set nightly + - name: Formatting (miri, ui_test) + run: cargo fmt --all --check + - name: Formatting (cargo-miri) + run: cargo fmt --manifest-path cargo-miri/Cargo.toml --all --check + # These jobs doesn't actually test anything, but they're only used to tell # bors the build completed, as there is no practical way to detect when a # workflow is successful listening to webhooks only. @@ -126,7 +126,7 @@ jobs: end-success: name: bors build finished runs-on: ubuntu-latest - needs: [build] + needs: [build, clippy] if: github.event.pusher.name == 'bors' && success() steps: - name: mark the job as a success @@ -134,7 +134,7 @@ jobs: end-failure: name: bors build finished runs-on: ubuntu-latest - needs: [build] + needs: [build, clippy] if: github.event.pusher.name == 'bors' && (failure() || cancelled()) steps: - name: mark the job as a failure @@ -144,7 +144,7 @@ jobs: cron-fail-notify: name: cronjob failure notification runs-on: ubuntu-latest - needs: [build] + needs: [build, clippy] if: github.event_name == 'schedule' && (failure() || cancelled()) steps: - name: Install zulip-send From 2b35dd514e249bcd7d570a3443335236b4a5d9b1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 7 Jun 2022 17:03:11 -0400 Subject: [PATCH 3252/5092] linux-futex test: ensure we join all threads --- tests/pass/concurrency/linux-futex.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/pass/concurrency/linux-futex.rs b/tests/pass/concurrency/linux-futex.rs index 8a67e0b525a9..b2791a428566 100644 --- a/tests/pass/concurrency/linux-futex.rs +++ b/tests/pass/concurrency/linux-futex.rs @@ -132,7 +132,7 @@ fn wait_wake() { static FUTEX: i32 = 0; - thread::spawn(move || { + let t = thread::spawn(move || { thread::sleep(Duration::from_millis(200)); unsafe { assert_eq!(libc::syscall( @@ -155,6 +155,7 @@ fn wait_wake() { } assert!((200..1000).contains(&start.elapsed().as_millis())); + t.join().unwrap(); } fn wait_wake_bitset() { @@ -162,7 +163,7 @@ fn wait_wake_bitset() { static FUTEX: i32 = 0; - thread::spawn(move || { + let t = thread::spawn(move || { thread::sleep(Duration::from_millis(200)); unsafe { assert_eq!(libc::syscall( @@ -202,6 +203,7 @@ fn wait_wake_bitset() { } assert!((400..1000).contains(&start.elapsed().as_millis())); + t.join().unwrap(); } fn main() { From e62e09ac1717191f537bf4d3a52cdfd54413a3e0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 8 Jun 2022 07:57:43 -0400 Subject: [PATCH 3253/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 2898937edfb4..9a72ffb3225d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9d20fd109809f20c049d6895a5be27a1fbd39daa +e45d9973b2665897a768312e971b82cc62633103 From a310ccc9a4ff515b6fa8914970f14296caf768bc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 8 Jun 2022 08:06:32 -0400 Subject: [PATCH 3254/5092] some clippy-induced cleanup --- src/concurrency/data_race.rs | 7 ++----- src/helpers.rs | 2 +- src/mono_hash_map.rs | 2 +- src/shims/foreign_items.rs | 14 +++++++------- src/shims/mod.rs | 2 +- src/shims/unix/foreign_items.rs | 2 +- src/shims/unix/fs.rs | 2 +- src/shims/unix/linux/dlsym.rs | 2 +- src/shims/unix/linux/foreign_items.rs | 2 +- src/shims/unix/macos/foreign_items.rs | 2 +- src/shims/windows/foreign_items.rs | 2 +- 11 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 28b09d2f909a..c81eab1ad23e 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -259,10 +259,7 @@ impl MemoryCellClocks { /// Load the internal atomic memory cells if they exist. #[inline] fn atomic(&self) -> Option<&AtomicMemoryCellClocks> { - match &self.atomic_ops { - Some(op) => Some(&*op), - None => None, - } + self.atomic_ops.as_deref() } /// Load or create the internal atomic memory metadata @@ -1482,7 +1479,7 @@ impl GlobalState { let thread_name = &self.thread_info.borrow()[thread].thread_name; if let Some(name) = thread_name { let name: &str = name; - format!("Thread(id = {:?}, name = {:?})", thread.to_u32(), &*name) + format!("Thread(id = {:?}, name = {:?})", thread.to_u32(), name) } else { format!("Thread(id = {:?})", thread.to_u32()) } diff --git a/src/helpers.rs b/src/helpers.rs index 4c79633c72de..c14aca6c781a 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -255,7 +255,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Push frame. - let mir = &*this.load_mir(f.def, None)?; + let mir = this.load_mir(f.def, None)?; this.push_stack_frame(f, mir, dest, stack_pop)?; // Initialize arguments. diff --git a/src/mono_hash_map.rs b/src/mono_hash_map.rs index 1ae2083d5661..45057632df9b 100644 --- a/src/mono_hash_map.rs +++ b/src/mono_hash_map.rs @@ -61,7 +61,7 @@ impl AllocMap for MonoHashMap { #[inline(always)] fn filter_map_collect(&self, mut f: impl FnMut(&K, &V) -> Option) -> Vec { - self.0.borrow().iter().filter_map(move |(k, v)| f(k, &*v)).collect() + self.0.borrow().iter().filter_map(move |(k, v)| f(k, v)).collect() } /// The most interesting method: Providing a shared reference without diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 12b5b40e69e8..a81dcdc110f1 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -243,7 +243,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // First: functions that diverge. let ret = match ret { None => - match &*link_name.as_str() { + match link_name.as_str() { "miri_start_panic" => { // `check_shim` happens inside `handle_miri_start_panic`. this.handle_miri_start_panic(abi, link_name, args, unwind)?; @@ -259,7 +259,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let panic_impl_id = tcx.lang_items().panic_impl().unwrap(); let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id); return Ok(Some(( - &*this.load_mir(panic_impl_instance.def, None)?, + this.load_mir(panic_impl_instance.def, None)?, panic_impl_instance, ))); } @@ -361,7 +361,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Here we dispatch all the shims for foreign functions. If you have a platform specific // shim, add it to the corresponding submodule. - match &*link_name.as_str() { + match link_name.as_str() { // Miri-specific extern functions "miri_static_root" => { let [ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?; @@ -573,7 +573,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); - let f = match &*link_name.as_str() { + let f = match link_name.as_str() { "cbrtf" => f.cbrt(), "coshf" => f.cosh(), "sinhf" => f.sinh(), @@ -596,7 +596,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: Using host floats. let f1 = f32::from_bits(this.read_scalar(f1)?.to_u32()?); let f2 = f32::from_bits(this.read_scalar(f2)?.to_u32()?); - let n = match &*link_name.as_str() { + let n = match link_name.as_str() { "_hypotf" | "hypotf" => f1.hypot(f2), "atan2f" => f1.atan2(f2), _ => bug!(), @@ -615,7 +615,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); - let f = match &*link_name.as_str() { + let f = match link_name.as_str() { "cbrt" => f.cbrt(), "cosh" => f.cosh(), "sinh" => f.sinh(), @@ -636,7 +636,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: Using host floats. let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?); let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?); - let n = match &*link_name.as_str() { + let n = match link_name.as_str() { "_hypot" | "hypot" => f1.hypot(f2), "atan2" => f1.atan2(f2), _ => bug!(), diff --git a/src/shims/mod.rs b/src/shims/mod.rs index cdffe2f65b4f..f2688bb08caa 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -55,7 +55,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Otherwise, load the MIR. - Ok(Some((&*this.load_mir(instance.def, None)?, instance))) + Ok(Some((this.load_mir(instance.def, None)?, instance))) } /// Returns `true` if the computation was performed, and `false` if we should just evaluate diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 32cf7e6f891f..5f59426bc5bc 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -26,7 +26,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); - match &*link_name.as_str() { + match link_name.as_str() { // Environment related shims "getenv" => { let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index d02410664bd4..c68845571034 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -446,7 +446,7 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' } } Err(e) => - return match e.raw_os_error() { + match e.raw_os_error() { Some(error) => Ok(error), None => throw_unsup_format!( diff --git a/src/shims/unix/linux/dlsym.rs b/src/shims/unix/linux/dlsym.rs index 72e8c7f16f85..01bf17db9f09 100644 --- a/src/shims/unix/linux/dlsym.rs +++ b/src/shims/unix/linux/dlsym.rs @@ -9,7 +9,7 @@ impl Dlsym { // Returns an error for unsupported symbols, and None if this symbol // should become a NULL pointer (pretend it does not exist). pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { - Ok(match &*name { + Ok(match name { "__pthread_get_minstack" => None, "getrandom" => None, // std falls back to syscall(SYS_getrandom, ...) when this is NULL. "statx" => None, // std falls back to syscall(SYS_statx, ...) when this is NULL. diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index 7a9c687fcd76..ab3f39147c60 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -21,7 +21,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); - match &*link_name.as_str() { + match link_name.as_str() { // errno "__errno_location" => { let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/shims/unix/macos/foreign_items.rs b/src/shims/unix/macos/foreign_items.rs index a1adfa0d2fda..f7dd38f639b0 100644 --- a/src/shims/unix/macos/foreign_items.rs +++ b/src/shims/unix/macos/foreign_items.rs @@ -19,7 +19,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); - match &*link_name.as_str() { + match link_name.as_str() { // errno "__error" => { let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 05f9aed17476..08a319159bc5 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -28,7 +28,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // DWORD = ULONG = u32 // BOOL = i32 // BOOLEAN = u8 - match &*link_name.as_str() { + match link_name.as_str() { // Environment related shims "GetEnvironmentVariableW" => { let [name, buf, size] = From 295e18df0dd13440f568d691366d55829f36e748 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 8 Jun 2022 08:12:20 -0400 Subject: [PATCH 3255/5092] document how to get a toolchain with clippy --- CONTRIBUTING.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b74444fbc6e4..c2290a966b23 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,6 +28,11 @@ install that exact version of rustc as a toolchain: This will set up a rustup toolchain called `miri` and set it as an override for the current directory. +If you want to also have `clippy` installed, you need to run this: +``` +./rustup-toolchain "" -c clippy +``` + [`rustup-toolchain-install-master`]: https://github.com/kennytm/rustup-toolchain-install-master ## Building and testing Miri From 657386cc91c7513eaafd327aaf26aa44d6a3da91 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 8 Jun 2022 12:10:54 -0400 Subject: [PATCH 3256/5092] rustup --- rust-version | 2 +- src/machine.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 9a72ffb3225d..85b2e88ac30c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e45d9973b2665897a768312e971b82cc62633103 +09d52bc5d4260bac8b9a2ea8ac7a07c5c72906f1 diff --git a/src/machine.rs b/src/machine.rs index 5e93045aec1a..824f0e3fc874 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -678,8 +678,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn ptr_from_addr_cast( ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, - ) -> Pointer> { - intptrcast::GlobalStateInner::ptr_from_addr_cast(ecx, addr) + ) -> InterpResult<'tcx, Pointer>> { + Ok(intptrcast::GlobalStateInner::ptr_from_addr_cast(ecx, addr)) } #[inline(always)] From 956a84bfe0502e126dcdd173fc84eecc10df5ebc Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Wed, 8 Jun 2022 18:22:48 +0200 Subject: [PATCH 3257/5092] Optimize `SbTag::eq` The code before generated really bad code with a branch. This nudges LLVM towards being smarter and simply comparing the integers. --- src/stacked_borrows.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 0d671ec653b5..fd33eea79026 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -27,12 +27,27 @@ pub type CallId = NonZeroU64; pub type AllocExtra = Stacks; /// Tracking pointer provenance -#[derive(Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Copy, Clone, Hash, Eq)] pub enum SbTag { Tagged(PtrId), Untagged, } +impl SbTag { + fn as_u64(self) -> u64 { + match self { + SbTag::Tagged(id) => id.get(), + SbTag::Untagged => 0, + } + } +} + +impl PartialEq for SbTag { + fn eq(&self, other: &Self) -> bool { + self.as_u64() == other.as_u64() + } +} + impl fmt::Debug for SbTag { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { From c01bf62ee42f7fa28a95449b374812cb47d38a95 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Wed, 8 Jun 2022 18:43:12 +0200 Subject: [PATCH 3258/5092] Allow `clippy::derive_hash_xor_eq` --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 7d8eb92ac58e..22869e9b248c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,7 @@ clippy::single_match, clippy::useless_format, clippy::derive_partial_eq_without_eq, + clippy::derive_hash_xor_eq, clippy::too_many_arguments )] From 93db9a6d71a7f66df81b5c8adbac7bb71d182bc1 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Wed, 8 Jun 2022 19:29:54 +0200 Subject: [PATCH 3259/5092] Add comment to explain manual optimization --- src/stacked_borrows.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index fd33eea79026..88d1b1f10521 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -44,6 +44,9 @@ impl SbTag { impl PartialEq for SbTag { fn eq(&self, other: &Self) -> bool { + // The codegen for the derived Partialeq is bad here and includes a branch. + // Since this code is extremely hot, this is optimized here. + // https://github.com/rust-lang/rust/issues/49892 self.as_u64() == other.as_u64() } } From 8a40e2e9e3f732f6e720969f6a26b74fcaefc34b Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Wed, 8 Jun 2022 19:32:43 -0400 Subject: [PATCH 3260/5092] Add more bench-cargo-miri programs These example programs are derived from long-running (>15 minutes) tests in the test suites of highly-downloaded crates. They should serve as realistic but also somewhat pathological workloads for the interpreter. The unicode program stresses the code which looks for adjacent and equal stacks to merge them. The backtrace program has an uncommonly large working set of borrow tags per borrow stack. This also updates the .gitignore to ignore files commonly emitted in the course of using these benchmark programs. --- .gitignore | 4 ++ bench-cargo-miri/backtraces/Cargo.lock | 94 +++++++++++++++++++++++++ bench-cargo-miri/backtraces/Cargo.toml | 9 +++ bench-cargo-miri/backtraces/src/main.rs | 29 ++++++++ bench-cargo-miri/mse/Cargo.lock | 7 ++ bench-cargo-miri/serde1/Cargo.lock | 89 +++++++++++++++++++++++ bench-cargo-miri/unicode/Cargo.lock | 16 +++++ bench-cargo-miri/unicode/Cargo.toml | 9 +++ bench-cargo-miri/unicode/src/main.rs | 20 ++++++ 9 files changed, 277 insertions(+) create mode 100644 bench-cargo-miri/backtraces/Cargo.lock create mode 100644 bench-cargo-miri/backtraces/Cargo.toml create mode 100644 bench-cargo-miri/backtraces/src/main.rs create mode 100644 bench-cargo-miri/mse/Cargo.lock create mode 100644 bench-cargo-miri/serde1/Cargo.lock create mode 100644 bench-cargo-miri/unicode/Cargo.lock create mode 100644 bench-cargo-miri/unicode/Cargo.toml create mode 100644 bench-cargo-miri/unicode/src/main.rs diff --git a/.gitignore b/.gitignore index b84a1cfe9f53..dcefbc62c70b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,7 @@ tex/*/out *.dot *.rs.bk .vscode +*.mm_profdata +perf.data +perf.data.old +flamegraph.svg diff --git a/bench-cargo-miri/backtraces/Cargo.lock b/bench-cargo-miri/backtraces/Cargo.lock new file mode 100644 index 000000000000..375b129a7e59 --- /dev/null +++ b/bench-cargo-miri/backtraces/Cargo.lock @@ -0,0 +1,94 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "backtrace" +version = "0.3.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "backtraces" +version = "0.1.0" +dependencies = [ + "backtrace", +] + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "gimli" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "miniz_oxide" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" +dependencies = [ + "adler", +] + +[[package]] +name = "object" +version = "0.28.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" +dependencies = [ + "memchr", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" diff --git a/bench-cargo-miri/backtraces/Cargo.toml b/bench-cargo-miri/backtraces/Cargo.toml new file mode 100644 index 000000000000..1ba96b19395d --- /dev/null +++ b/bench-cargo-miri/backtraces/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "backtraces" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +backtrace = "0.3.65" diff --git a/bench-cargo-miri/backtraces/src/main.rs b/bench-cargo-miri/backtraces/src/main.rs new file mode 100644 index 000000000000..eba51c60dbc5 --- /dev/null +++ b/bench-cargo-miri/backtraces/src/main.rs @@ -0,0 +1,29 @@ +//! Extracted from the backtrace crate's test test_frame_conversion + +use backtrace::{Backtrace, BacktraceFrame}; +use std::fmt::Write; + +fn main() { + let mut frames = vec![]; + backtrace::trace(|frame| { + let converted = BacktraceFrame::from(frame.clone()); + frames.push(converted); + true + }); + + let mut manual = Backtrace::from(frames); + manual.resolve(); + let frames = manual.frames(); + + let mut output = String::new(); + for frame in frames { + // Originally these were println! but we'd prefer our benchmarks to not emit a lot of + // output to stdout/stderr. Unfortunately writeln! to a String is faster, but we still + // manage to exercise interesting code paths in Miri. + writeln!(output, "{:?}", frame.ip()).unwrap(); + writeln!(output, "{:?}", frame.symbol_address()).unwrap(); + writeln!(output, "{:?}", frame.module_base_address()).unwrap(); + writeln!(output, "{:?}", frame.symbols()).unwrap(); + } + drop(output); +} diff --git a/bench-cargo-miri/mse/Cargo.lock b/bench-cargo-miri/mse/Cargo.lock new file mode 100644 index 000000000000..d2b1aa341bbb --- /dev/null +++ b/bench-cargo-miri/mse/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "mse" +version = "0.1.0" diff --git a/bench-cargo-miri/serde1/Cargo.lock b/bench-cargo-miri/serde1/Cargo.lock new file mode 100644 index 000000000000..487505761354 --- /dev/null +++ b/bench-cargo-miri/serde1/Cargo.lock @@ -0,0 +1,89 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cargo-miri-test" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "proc-macro2" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + +[[package]] +name = "serde" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "syn" +version = "1.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" diff --git a/bench-cargo-miri/unicode/Cargo.lock b/bench-cargo-miri/unicode/Cargo.lock new file mode 100644 index 000000000000..80d013b7d6d8 --- /dev/null +++ b/bench-cargo-miri/unicode/Cargo.lock @@ -0,0 +1,16 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "unicode" +version = "0.1.0" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" diff --git a/bench-cargo-miri/unicode/Cargo.toml b/bench-cargo-miri/unicode/Cargo.toml new file mode 100644 index 000000000000..7e8708b03f19 --- /dev/null +++ b/bench-cargo-miri/unicode/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "unicode" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +unicode-xid = "0.2.3" diff --git a/bench-cargo-miri/unicode/src/main.rs b/bench-cargo-miri/unicode/src/main.rs new file mode 100644 index 000000000000..3f0ee5ecf6af --- /dev/null +++ b/bench-cargo-miri/unicode/src/main.rs @@ -0,0 +1,20 @@ +//! Extracted from the unicode-xid exhaustive test all_valid_chars_do_not_panic_for_is_xid_continue + +use unicode_xid::UnicodeXID; + +/// A `char` in Rust is a Unicode Scalar Value +/// +/// See: http://www.unicode.org/glossary/#unicode_scalar_value +fn all_valid_chars() -> impl Iterator { + (0u32..=0xD7FF).chain(0xE000u32..=0x10FFFF).map(|u| { + core::convert::TryFrom::try_from(u) + .expect("The selected range should be infallible if the docs match impl") + }) +} + +fn main() { + // Take only the first few chars because we don't want to wait all day + for c in all_valid_chars().take(2_000) { + let _ = UnicodeXID::is_xid_continue(c); + } +} From cdf66060666fa53cbca9647ac7434bdfd2cc37a5 Mon Sep 17 00:00:00 2001 From: Aaron Kofsky Date: Thu, 9 Jun 2022 14:03:35 -0400 Subject: [PATCH 3261/5092] Use `multipart_suggestion` to create an applicable suggestion. The "consider explicitly droping" can now suggest a machine applicable suggestion now. --- compiler/rustc_lint/src/let_underscore.rs | 10 ++++++---- .../ui/lint/let_underscore/let_underscore_drop.stderr | 4 ++-- .../ui/lint/let_underscore/let_underscore_lock.stderr | 4 ++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index 520c865cc192..18661e8c5059 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -154,11 +154,13 @@ fn build_and_emit_lint( "_unused", Applicability::MachineApplicable, ) - .span_suggestion_verbose( - init_span, + .multipart_suggestion( "consider explicitly droping with `std::mem::drop`", - "drop(...)", - Applicability::HasPlaceholders, + vec![ + (init_span.shrink_to_lo(), "drop(".to_string()), + (init_span.shrink_to_hi(), ")".to_string()), + ], + Applicability::MachineApplicable, ) .emit(); } diff --git a/src/test/ui/lint/let_underscore/let_underscore_drop.stderr b/src/test/ui/lint/let_underscore/let_underscore_drop.stderr index 5034f682bb76..dfac6d3f7418 100644 --- a/src/test/ui/lint/let_underscore/let_underscore_drop.stderr +++ b/src/test/ui/lint/let_underscore/let_underscore_drop.stderr @@ -11,8 +11,8 @@ LL | let _unused = NontrivialDrop; | ~~~~~~~ help: consider explicitly droping with `std::mem::drop` | -LL | let _ = drop(...); - | ~~~~~~~~~ +LL | let _ = drop(NontrivialDrop); + | +++++ + warning: 1 warning emitted diff --git a/src/test/ui/lint/let_underscore/let_underscore_lock.stderr b/src/test/ui/lint/let_underscore/let_underscore_lock.stderr index 7ff42cb15244..f37483ddd96d 100644 --- a/src/test/ui/lint/let_underscore/let_underscore_lock.stderr +++ b/src/test/ui/lint/let_underscore/let_underscore_lock.stderr @@ -11,8 +11,8 @@ LL | let _unused = data.lock().unwrap(); | ~~~~~~~ help: consider explicitly droping with `std::mem::drop` | -LL | let _ = drop(...); - | ~~~~~~~~~ +LL | let _ = drop(data.lock().unwrap()); + | +++++ + error: aborting due to previous error From 4da48e06c7b721075d46b51f686e7e326393ab52 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 10 Jun 2022 20:23:30 -0700 Subject: [PATCH 3262/5092] make frame_in_std check work with inlining --- src/helpers.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index c14aca6c781a..e353e17c6805 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -729,10 +729,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn frame_in_std(&self) -> bool { let this = self.eval_context_ref(); - this.tcx.lang_items().start_fn().map_or(false, |start_fn| { - this.tcx.def_path(this.frame().instance.def_id()).krate - == this.tcx.def_path(start_fn).krate - }) + let Some(start_fn) = this.tcx.lang_items().start_fn() else { + // no_std situations + return false; + }; + let frame = this.frame(); + // Make an attempt to get at the instance of the function this is inlined from. + let instance: Option<_> = try { + let scope = frame.current_source_info()?.scope; + let inlined_parent = frame.body.source_scopes[scope].inlined_parent_scope?; + let source = &frame.body.source_scopes[inlined_parent]; + source.inlined.expect("inlined_parent_scope points to scope without inline info").0 + }; + // Fall back to the instance of the function itself. + let instance = instance.unwrap_or(frame.instance); + // Now check if this is in the same crate as start_fn. + this.tcx.def_path(instance.def_id()).krate == this.tcx.def_path(start_fn).krate } /// Handler that should be called when unsupported functionality is encountered. From eaa1e444eb3efa0bb4e1faf00b0ee2b4e3d8f673 Mon Sep 17 00:00:00 2001 From: infrandomness Date: Thu, 9 Jun 2022 16:20:47 +0200 Subject: [PATCH 3263/5092] Add mandatory cargo_doc Co-authored-by: Joshua Nelson --- .github/workflows/ci.yml | 4 +++- src/concurrency/weak_memory.rs | 10 +++++----- src/eval.rs | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2bfc58be28d7..55da948f7b78 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -87,7 +87,7 @@ jobs: run: bash ./ci.sh clippy: - name: clippy + name: clippy + rustdoc runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -102,6 +102,8 @@ jobs: # run: cargo clippy --manifest-path ui_test/Cargo.toml --all-targets -- -D warnings - name: Clippy (cargo-miri) run: cargo clippy --manifest-path cargo-miri/Cargo.toml --all-targets -- -D warnings + - name: Rustdoc + run: RUSTDOCFLAGS="-Dwarnings" cargo doc --document-private-items fmt: name: formatting (ignored by bors) diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index be3963a93f07..e5f58ee5ddd0 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -1,13 +1,13 @@ //! Implementation of C++11-consistent weak memory emulation using store buffers //! based on Dynamic Race Detection for C++ ("the paper"): -//! https://www.doc.ic.ac.uk/~afd/homepages/papers/pdfs/2017/POPL.pdf +//! //! //! This implementation will never generate weak memory behaviours forbidden by the C++11 model, //! but it is incapable of producing all possible weak behaviours allowed by the model. There are //! certain weak behaviours observable on real hardware but not while using this. //! //! Note that this implementation does not take into account of C++20's memory model revision to SC accesses -//! and fences introduced by P0668 (https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0668r5.html). +//! and fences introduced by P0668 (). //! This implementation is not fully correct under the revised C++20 model and may generate behaviours C++20 //! disallows. //! @@ -15,14 +15,14 @@ //! std::atomic API). It is therefore possible for this implementation to generate behaviours never observable when the //! same program is compiled and run natively. Unfortunately, no literature exists at the time of writing which proposes //! an implementable and C++20-compatible relaxed memory model that supports all atomic operation existing in Rust. The closest one is -//! A Promising Semantics for Relaxed-Memory Concurrency by Jeehoon Kang et al. (https://www.cs.tau.ac.il/~orilahav/papers/popl17.pdf) +//! A Promising Semantics for Relaxed-Memory Concurrency by Jeehoon Kang et al. () //! However, this model lacks SC accesses and is therefore unusable by Miri (SC accesses are everywhere in library code). //! //! If you find anything that proposes a relaxed memory model that is C++20-consistent, supports all orderings Rust's atomic accesses //! and fences accept, and is implementable (with operational semanitcs), please open a GitHub issue! //! //! One characteristic of this implementation, in contrast to some other notable operational models such as ones proposed in -//! Taming Release-Acquire Consistency by Ori Lahav et al. (https://plv.mpi-sws.org/sra/paper.pdf) or Promising Semantics noted above, +//! Taming Release-Acquire Consistency by Ori Lahav et al. () or Promising Semantics noted above, //! is that this implementation does not require each thread to hold an isolated view of the entire memory. Here, store buffers are per-location //! and shared across all threads. This is more memory efficient but does require store elements (representing writes to a location) to record //! information about reads, whereas in the other two models it is the other way round: reads points to the write it got its value from. @@ -38,7 +38,7 @@ //! on the next non-atomic or imperfectly overlapping atomic access to that region. //! These lazy (de)allocations happen in memory_accessed() on non-atomic accesses, and //! get_or_create_store_buffer() on atomic accesses. This mostly works well, but it does -//! lead to some issues (https://github.com/rust-lang/miri/issues/2164). +//! lead to some issues (). //! //! One consequence of this difference is that safe/sound Rust allows for more operations on atomic locations //! than the C++20 atomic API was intended to allow, such as non-atomically accessing diff --git a/src/eval.rs b/src/eval.rs index 7c971d2a1490..db843b851e58 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -403,7 +403,7 @@ pub fn eval_entry<'tcx>( /// The string will be UTF-16 encoded and NUL terminated. /// /// Panics if the zeroth argument contains the `"` character because doublequotes -/// in argv[0] cannot be encoded using the standard command line parsing rules. +/// in `argv[0]` cannot be encoded using the standard command line parsing rules. /// /// Further reading: /// * [Parsing C++ command-line arguments](https://docs.microsoft.com/en-us/cpp/cpp/main-function-command-line-args?view=msvc-160#parsing-c-command-line-arguments) From 3e03054ef0056e728a081b03cde8546f91c822aa Mon Sep 17 00:00:00 2001 From: InfRandomness Date: Wed, 8 Jun 2022 10:09:38 +0200 Subject: [PATCH 3264/5092] Add getpid shim --- src/shims/env.rs | 27 +++++++++++++++++++++++++++ src/shims/unix/foreign_items.rs | 6 ++++++ src/shims/windows/foreign_items.rs | 5 +++++ tests/pass/getpid.rs | 9 +++++++++ 4 files changed, 47 insertions(+) create mode 100644 tests/pass/getpid.rs diff --git a/src/shims/env.rs b/src/shims/env.rs index 5cffc5c6d1d5..a65919286117 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -465,4 +465,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } + + fn getpid(&mut self) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + let target_os = &this.tcx.sess.target.os; + assert!( + target_os == "linux" || target_os == "macos", + "`getpid` is only available for the UNIX target family" + ); + + this.check_no_isolation("`getpid`")?; + + // The reason we need to do this wacky of a conversion is because + // `libc::getpid` returns an i32, however, `std::process::id()` return an u32. + // So we un-do the conversion that stdlib does and turn it back into an i32. + + Ok(std::process::id() as i32) + } + + #[allow(non_snake_case)] + fn GetCurrentProcessId(&mut self) -> InterpResult<'tcx, u32> { + let this = self.eval_context_mut(); + this.assert_target_os("windows", "GetCurrentProcessId"); + + this.check_no_isolation("`GetCurrentProcessId`")?; + + Ok(std::process::id()) + } } diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 32cf7e6f891f..2d2a2c0399a8 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -474,6 +474,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } + "getpid" => { + let [] = this.check_shim(abi, Abi::C { unwind: false}, link_name, args)?; + let result = this.getpid()?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + // Platform-specific shims _ => { match this.tcx.sess.target.os.as_ref() { diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 05f9aed17476..8b7742e0a4ae 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -419,6 +419,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } + "GetCurrentProcessId" if this.frame_in_std() => { + let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let result = this.GetCurrentProcessId()?; + this.write_scalar(Scalar::from_u32(result), dest)?; + } _ => return Ok(EmulateByNameResult::NotSupported), } diff --git a/tests/pass/getpid.rs b/tests/pass/getpid.rs new file mode 100644 index 000000000000..258fdeaa8497 --- /dev/null +++ b/tests/pass/getpid.rs @@ -0,0 +1,9 @@ +// compile-flags: -Zmiri-disable-isolation + +fn getpid() -> u32 { + std::process::id() +} + +fn main() { + getpid(); +} From 7237e8635dc0611a051de8d398759fe7eae90d0a Mon Sep 17 00:00:00 2001 From: Aaron Kofsky Date: Sat, 11 Jun 2022 10:19:53 -0400 Subject: [PATCH 3265/5092] Reword suggestion messages. --- compiler/rustc_lint/src/let_underscore.rs | 4 ++-- src/test/ui/lint/let_underscore/let_underscore_drop.stderr | 4 ++-- src/test/ui/lint/let_underscore/let_underscore_lock.stderr | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index 18661e8c5059..fe0e0511f6b4 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -150,12 +150,12 @@ fn build_and_emit_lint( lint.build(msg) .span_suggestion_verbose( local.pat.span, - "consider binding to an unused variable", + "consider binding to an unused variable to avoid immediately dropping the value", "_unused", Applicability::MachineApplicable, ) .multipart_suggestion( - "consider explicitly droping with `std::mem::drop`", + "consider immediately dropping the value", vec![ (init_span.shrink_to_lo(), "drop(".to_string()), (init_span.shrink_to_hi(), ")".to_string()), diff --git a/src/test/ui/lint/let_underscore/let_underscore_drop.stderr b/src/test/ui/lint/let_underscore/let_underscore_drop.stderr index dfac6d3f7418..b6ff9d1a27cd 100644 --- a/src/test/ui/lint/let_underscore/let_underscore_drop.stderr +++ b/src/test/ui/lint/let_underscore/let_underscore_drop.stderr @@ -5,11 +5,11 @@ LL | let _ = NontrivialDrop; | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: requested on the command line with `-W let-underscore-drop` -help: consider binding to an unused variable +help: consider binding to an unused variable to avoid immediately dropping the value | LL | let _unused = NontrivialDrop; | ~~~~~~~ -help: consider explicitly droping with `std::mem::drop` +help: consider immediately dropping the value | LL | let _ = drop(NontrivialDrop); | +++++ + diff --git a/src/test/ui/lint/let_underscore/let_underscore_lock.stderr b/src/test/ui/lint/let_underscore/let_underscore_lock.stderr index f37483ddd96d..1e49b89c5a87 100644 --- a/src/test/ui/lint/let_underscore/let_underscore_lock.stderr +++ b/src/test/ui/lint/let_underscore/let_underscore_lock.stderr @@ -5,11 +5,11 @@ LL | let _ = data.lock().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `#[deny(let_underscore_lock)]` on by default -help: consider binding to an unused variable +help: consider binding to an unused variable to avoid immediately dropping the value | LL | let _unused = data.lock().unwrap(); | ~~~~~~~ -help: consider explicitly droping with `std::mem::drop` +help: consider immediately dropping the value | LL | let _ = drop(data.lock().unwrap()); | +++++ + From b040666e052a94241d2598b06d5e5dc19c77257b Mon Sep 17 00:00:00 2001 From: Aaron Kofsky Date: Sat, 11 Jun 2022 10:36:48 -0400 Subject: [PATCH 3266/5092] Have the drop code suggestion not include `let _ =` --- compiler/rustc_lint/src/let_underscore.rs | 2 +- src/test/ui/lint/let_underscore/let_underscore_drop.stderr | 4 ++-- src/test/ui/lint/let_underscore/let_underscore_lock.stderr | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index fe0e0511f6b4..2ba79aacace8 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -157,7 +157,7 @@ fn build_and_emit_lint( .multipart_suggestion( "consider immediately dropping the value", vec![ - (init_span.shrink_to_lo(), "drop(".to_string()), + (local.span.until(init_span), "drop(".to_string()), (init_span.shrink_to_hi(), ")".to_string()), ], Applicability::MachineApplicable, diff --git a/src/test/ui/lint/let_underscore/let_underscore_drop.stderr b/src/test/ui/lint/let_underscore/let_underscore_drop.stderr index b6ff9d1a27cd..cf7b882e946d 100644 --- a/src/test/ui/lint/let_underscore/let_underscore_drop.stderr +++ b/src/test/ui/lint/let_underscore/let_underscore_drop.stderr @@ -11,8 +11,8 @@ LL | let _unused = NontrivialDrop; | ~~~~~~~ help: consider immediately dropping the value | -LL | let _ = drop(NontrivialDrop); - | +++++ + +LL | drop(NontrivialDrop); + | ~~~~~ + warning: 1 warning emitted diff --git a/src/test/ui/lint/let_underscore/let_underscore_lock.stderr b/src/test/ui/lint/let_underscore/let_underscore_lock.stderr index 1e49b89c5a87..7aa119003b4b 100644 --- a/src/test/ui/lint/let_underscore/let_underscore_lock.stderr +++ b/src/test/ui/lint/let_underscore/let_underscore_lock.stderr @@ -11,8 +11,8 @@ LL | let _unused = data.lock().unwrap(); | ~~~~~~~ help: consider immediately dropping the value | -LL | let _ = drop(data.lock().unwrap()); - | +++++ + +LL | drop(data.lock().unwrap()); + | ~~~~~ + error: aborting due to previous error From 8807c2d8e512668a6f09ddb14c6742bf28e66816 Mon Sep 17 00:00:00 2001 From: Aaron Kofsky Date: Sat, 11 Jun 2022 10:58:04 -0400 Subject: [PATCH 3267/5092] Make `let_underscore_drop` Deny by default. This is done so that we can check the noisiness of this lint in a Crater run. Note that when I built the compiler, I actually encountered lots of places where this lint will trigger and fail compilation, so I had to also set `RUSTFLAGS_NOT_BOOSTRAP` to `-A let_underscore_drop` when compiling to prevent that. --- compiler/rustc_lint/src/let_underscore.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index 2ba79aacace8..d40c83e311f9 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -46,7 +46,7 @@ declare_lint! { /// calling `std::mem::drop` on the expression is clearer and helps convey /// intent. pub LET_UNDERSCORE_DROP, - Allow, + Deny, "non-binding let on a type that implements `Drop`" } From 5f1ba4432bf571cbd27f6c808200294d323e2a28 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 Jun 2022 08:03:51 -0700 Subject: [PATCH 3268/5092] make some rustdoc comments more readable --- src/concurrency/data_race.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index c81eab1ad23e..c1bcd2368133 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -24,7 +24,7 @@ //! because it only re-uses vector indexes once all currently-active (not-terminated) threads have an internal //! vector clock that happens-after the join operation of the candidate thread. Threads that have not been joined //! on are not considered. Since the thread's vector clock will only increase and a data-race implies that -//! there is some index x where clock\[x\] > thread_clock, when this is true clock\[candidate-idx\] > thread_clock +//! there is some index x where `clock[x] > thread_clock`, when this is true `clock[candidate-idx] > thread_clock` //! can never hold and hence a data-race can never be reported in that vector index again. //! This means that the thread-index can be safely re-used, starting on the next timestamp for the newly created //! thread. From 58d00aa6424f64a72b07afed275a49f76e816016 Mon Sep 17 00:00:00 2001 From: infrandomness Date: Sat, 11 Jun 2022 15:37:49 +0200 Subject: [PATCH 3269/5092] Add target_os_is_unix helper --- src/helpers.rs | 6 ++++++ src/shims/dlsym.rs | 4 +++- src/shims/env.rs | 3 ++- src/shims/foreign_items.rs | 4 ++-- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index e353e17c6805..b494e85075c4 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -895,3 +895,9 @@ impl std::fmt::Display for HexRange { write!(f, "[{:#x}..{:#x}]", self.0.start.bytes(), self.0.end().bytes()) } } + +/// Helper function used inside the shims of foreign functions to check that +/// `target_os` is a supported UNIX OS. +pub fn target_os_is_unix(target_os: &str) -> bool { + matches!(target_os, "linux" | "macos") +} diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index c5081582281b..499e9f8a201f 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -1,6 +1,7 @@ use rustc_middle::mir; use rustc_target::spec::abi::Abi; +use crate::helpers::target_os_is_unix; use crate::*; use shims::unix::dlsym as unix; use shims::windows::dlsym as windows; @@ -18,7 +19,8 @@ impl Dlsym { pub fn from_str<'tcx>(name: &[u8], target_os: &str) -> InterpResult<'tcx, Option> { let name = &*String::from_utf8_lossy(name); Ok(match target_os { - "linux" | "macos" => unix::Dlsym::from_str(name, target_os)?.map(Dlsym::Posix), + target if target_os_is_unix(target) => + unix::Dlsym::from_str(name, target)?.map(Dlsym::Posix), "windows" => windows::Dlsym::from_str(name)?.map(Dlsym::Windows), os => bug!("dlsym not implemented for target_os {}", os), }) diff --git a/src/shims/env.rs b/src/shims/env.rs index a65919286117..91acff40fe16 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -8,6 +8,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::layout::LayoutOf; use rustc_target::abi::Size; +use crate::helpers::target_os_is_unix; use crate::*; /// Check whether an operation that writes to a target buffer was successful. @@ -55,7 +56,7 @@ impl<'tcx> EnvVars<'tcx> { }; if forward { let var_ptr = match target_os { - "linux" | "macos" => + target if target_os_is_unix(target) => alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx)?, "windows" => alloc_env_var_as_wide_str(name.as_ref(), value.as_ref(), ecx)?, unsupported => diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index a81dcdc110f1..cd4fedad0fba 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -22,7 +22,7 @@ use rustc_target::{ }; use super::backtrace::EvalContextExt as _; -use crate::helpers::convert::Truncate; +use crate::helpers::{convert::Truncate, target_os_is_unix}; use crate::*; /// Returned by `emulate_foreign_item_by_name`. @@ -702,7 +702,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Platform-specific shims _ => match this.tcx.sess.target.os.as_ref() { - "linux" | "macos" => return shims::unix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), + target if target_os_is_unix(target) => return shims::unix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), target => throw_unsup_format!("the target `{}` is not supported", target), } From bc27fbb2f73b6f8d3f629b6954776a6572c2da19 Mon Sep 17 00:00:00 2001 From: infrandomness Date: Sat, 11 Jun 2022 17:54:23 +0200 Subject: [PATCH 3270/5092] Add `assert_target_os_is_unix` function --- src/helpers.rs | 11 +++++++++++ src/shims/env.rs | 36 ++++++------------------------------ 2 files changed, 17 insertions(+), 30 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index b494e85075c4..134f556bf120 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -493,6 +493,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) } + /// Helper function used inside the shims of foreign functions to assert that the target OS + /// is part of the UNIX family. It panics showing a message with the `name` of the foreign function + /// if this is not the case. + fn assert_target_os_is_unix(&self, name: &str) { + assert!( + target_os_is_unix(self.eval_context_ref().tcx.sess.target.os.as_ref()), + "`{}` is only available for supported UNIX family targets", + name, + ); + } + /// Get last error variable as a place, lazily allocating thread-local storage for it if /// necessary. fn last_error_place(&mut self) -> InterpResult<'tcx, MPlaceTy<'tcx, Tag>> { diff --git a/src/shims/env.rs b/src/shims/env.rs index 91acff40fe16..85ecd2b719f2 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -114,11 +114,7 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn getenv(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, Pointer>> { let this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.os; - assert!( - target_os == "linux" || target_os == "macos", - "`getenv` is only available for the UNIX target family" - ); + this.assert_target_os_is_unix("getenv"); let name_ptr = this.read_pointer(name_op)?; let name = this.read_os_str_from_c_str(name_ptr)?; @@ -212,11 +208,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx value_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.os; - assert!( - target_os == "linux" || target_os == "macos", - "`setenv` is only available for the UNIX target family" - ); + this.assert_target_os_is_unix("setenv"); let name_ptr = this.read_pointer(name_op)?; let value_ptr = this.read_pointer(value_op)?; @@ -286,11 +278,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn unsetenv(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.os; - assert!( - target_os == "linux" || target_os == "macos", - "`unsetenv` is only available for the UNIX target family" - ); + this.assert_target_os_is_unix("unsetenv"); let name_ptr = this.read_pointer(name_op)?; let mut success = None; @@ -320,11 +308,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, Pointer>> { let this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.os; - assert!( - target_os == "linux" || target_os == "macos", - "`getcwd` is only available for the UNIX target family" - ); + this.assert_target_os_is_unix("getcwd"); let buf = this.read_pointer(buf_op)?; let size = this.read_scalar(size_op)?.to_machine_usize(&*this.tcx)?; @@ -379,11 +363,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn chdir(&mut self, path_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.os; - assert!( - target_os == "linux" || target_os == "macos", - "`chdir` is only available for the UNIX target family" - ); + this.assert_target_os_is_unix("chdir"); let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; @@ -469,11 +449,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn getpid(&mut self) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.os; - assert!( - target_os == "linux" || target_os == "macos", - "`getpid` is only available for the UNIX target family" - ); + this.assert_target_os_is_unix("getpid"); this.check_no_isolation("`getpid`")?; From b6bcbf76fdd4da771977c1591eaec3faad05a9f3 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sat, 11 Jun 2022 20:45:45 +0100 Subject: [PATCH 3271/5092] Prevent futex_wait from reading outdated value --- src/shims/unix/linux/sync.rs | 26 ++++++++++------ tests/pass/concurrency/linux-futex.rs | 44 +++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/src/shims/unix/linux/sync.rs b/src/shims/unix/linux/sync.rs index 72898baa4b0a..42494da37b79 100644 --- a/src/shims/unix/linux/sync.rs +++ b/src/shims/unix/linux/sync.rs @@ -126,24 +126,26 @@ pub fn futex<'tcx>( Align::from_bytes(4).unwrap(), CheckInAllocMsg::MemoryAccessTest, )?; + // This SeqCst fence is paired with the SeqCst fence in futex_wake. + // Together, they make sure that our read on addr observes the latest + // value in modification order. + // + // If there is another thread which has changed the value of + // addr (to something other than expected) and called futex_wake + // before we get to run, then we must not block our thread + // because there'll be no one to wake us. We must see + // the value changed by the other thread and return without + // actually waiting. + this.atomic_fence(&[], AtomicFenceOp::SeqCst)?; // Read an `i32` through the pointer, regardless of any wrapper types. // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`. // FIXME: this fails if `addr` is not a pointer type. - // The atomic ordering for futex(https://man7.org/linux/man-pages/man2/futex.2.html): - // "The load of the value of the futex word is an - // atomic memory access (i.e., using atomic machine instructions - // of the respective architecture). This load, the comparison - // with the expected value, and starting to sleep are performed - // atomically and totally ordered with respect to other futex - // operations on the same futex word." - // SeqCst is total order over all operations. - // FIXME: check if this should be changed when weak memory orders are added. let futex_val = this .read_scalar_at_offset_atomic( &addr.into(), 0, this.machine.layouts.i32, - AtomicReadOp::SeqCst, + AtomicReadOp::Relaxed, )? .to_i32()?; if val == futex_val { @@ -203,6 +205,10 @@ pub fn futex<'tcx>( this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?; return Ok(()); } + // Together with the SeqCst fence in futex_wait, this makes sure that futex_wait + // will see the latest value on addr which could be changed by our caller + // before doing the syscall. + this.atomic_fence(&[], AtomicFenceOp::SeqCst)?; let mut n = 0; for _ in 0..val { if let Some(thread) = this.futex_wake(addr_usize, bitset) { diff --git a/tests/pass/concurrency/linux-futex.rs b/tests/pass/concurrency/linux-futex.rs index b2791a428566..56aba60d534a 100644 --- a/tests/pass/concurrency/linux-futex.rs +++ b/tests/pass/concurrency/linux-futex.rs @@ -6,6 +6,8 @@ extern crate libc; use std::mem::MaybeUninit; use std::ptr; +use std::sync::atomic::AtomicI32; +use std::sync::atomic::Ordering; use std::thread; use std::time::{Duration, Instant}; @@ -206,6 +208,47 @@ fn wait_wake_bitset() { t.join().unwrap(); } +const FREE: i32 = 0; +const HELD: i32 = 1; +fn concurrent_wait_wake() { + static FUTEX: AtomicI32 = AtomicI32::new(0); + for _ in 0..100 { + // Suppose the main thread is holding a lock implemented using futex... + FUTEX.store(HELD, Ordering::Relaxed); + + let t = thread::spawn(move || { + // If this syscall runs first, then we'll be woken up by + // the main thread's FUTEX_WAKE, and all is fine. + // + // If this sycall runs after the main thread's store + // and FUTEX_WAKE, the syscall must observe that + // the FUTEX is FREE != HELD and return without waiting + // or we'll deadlock. + unsafe { + libc::syscall( + libc::SYS_futex, + &FUTEX as *const AtomicI32, + libc::FUTEX_WAIT, + HELD, + ptr::null::(), + ); + } + }); + + FUTEX.store(FREE, Ordering::Relaxed); + unsafe { + libc::syscall( + libc::SYS_futex, + &FUTEX as *const AtomicI32, + libc::FUTEX_WAKE, + 1, + ); + } + + t.join().unwrap(); + } +} + fn main() { wake_nobody(); wake_dangling(); @@ -214,4 +257,5 @@ fn main() { wait_absolute_timeout(); wait_wake(); wait_wake_bitset(); + concurrent_wait_wake(); } From 681cb888044601c0c00a02a4302b108758ca7712 Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Sat, 11 Jun 2022 16:41:32 -0700 Subject: [PATCH 3272/5092] Add cache location on windows to documentation --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c2290a966b23..623480890c92 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -134,7 +134,7 @@ build Miri yourself, the Miri shipped by `rustup` will work. All you have to do is set the `MIRI_LIB_SRC` environment variable to the `library` folder of a `rust-lang/rust` repository checkout. Note that changing files in that directory does not automatically trigger a re-build of the standard library; you have to -clear the Miri build cache manually (on Linux, `rm -rf ~/.cache/miri`). +clear the Miri build cache manually (on Linux, `rm -rf ~/.cache/miri` and on Windows, `rmdir /S "%LOCALAPPDATA%\rust-lang\miri"`). ## Configuring `rust-analyzer` @@ -226,7 +226,7 @@ rustup override set stage2 ``` Important: You need to delete the Miri cache when you change the stdlib; otherwise the -old, chached version will be used. On Linux, the cache is located at `~/.cache/miri`; the exact +old, chached version will be used. On Linux, the cache is located at `~/.cache/miri` and on Windows, the cache is located at `%LOCALAPPDATA%\rust-lang\miri`; the exact location is printed after the library build: "A libstd for Miri is now available in ...". Note: `./x.py --stage 2 compiler/rustc` currently errors with `thread 'main' From 069d8fdb71a9a46a76552e8eea7d427b4d6f08a1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Jun 2022 12:25:46 -0400 Subject: [PATCH 3273/5092] test for Stacked Borrows error during vtable validation --- tests/fail/stacked_borrows/vtable.rs | 19 ++++++++++++++++++ tests/fail/stacked_borrows/vtable.stderr | 25 ++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 tests/fail/stacked_borrows/vtable.rs create mode 100644 tests/fail/stacked_borrows/vtable.stderr diff --git a/tests/fail/stacked_borrows/vtable.rs b/tests/fail/stacked_borrows/vtable.rs new file mode 100644 index 000000000000..dd9ba1dfb2bd --- /dev/null +++ b/tests/fail/stacked_borrows/vtable.rs @@ -0,0 +1,19 @@ +// error-pattern: vtable pointer does not have permission +#![feature(ptr_metadata)] + +trait Foo {} + +impl Foo for u32 {} + +fn uwu(thin: *const (), meta: &'static ()) -> *const dyn Foo { + core::ptr::from_raw_parts(thin, unsafe { core::mem::transmute(meta) }) +} + +fn main() { + unsafe { + let orig = 1_u32; + let x = &orig as &dyn Foo; + let (ptr, meta) = (x as *const dyn Foo).to_raw_parts(); + let _ = uwu(ptr, core::mem::transmute(meta)); + } +} diff --git a/tests/fail/stacked_borrows/vtable.stderr b/tests/fail/stacked_borrows/vtable.stderr new file mode 100644 index 000000000000..ac3d71045f0c --- /dev/null +++ b/tests/fail/stacked_borrows/vtable.stderr @@ -0,0 +1,25 @@ +error: Undefined Behavior: type validation failed: encountered vtable pointer does not have permission to read drop function pointer + --> RUSTLIB/core/src/ptr/metadata.rs:LL:CC + | +LL | unsafe { PtrRepr { components: PtrComponents { data_address, metadata } }.const_ptr } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered vtable pointer does not have permission to read drop function pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::ptr::from_raw_parts::` at RUSTLIB/core/src/ptr/metadata.rs:LL:CC +note: inside `uwu` at $DIR/vtable.rs:LL:CC + --> $DIR/vtable.rs:LL:CC + | +LL | core::ptr::from_raw_parts(thin, unsafe { core::mem::transmute(meta) }) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: inside `main` at $DIR/vtable.rs:LL:CC + --> $DIR/vtable.rs:LL:CC + | +LL | let _ = uwu(ptr, core::mem::transmute(meta)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + From c3b8509654451e746d6a33d2009c0c68a60c34ad Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Jun 2022 12:26:16 -0400 Subject: [PATCH 3274/5092] =?UTF-8?q?rename=20ExperimentalUb=20=E2=86=92?= =?UTF-8?q?=20StackedBorrowsUb?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/diagnostics.rs | 14 +++++++------- src/stacked_borrows.rs | 9 +-------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 52f93a6cea9d..0e3e693e33f9 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -16,10 +16,9 @@ pub enum TerminationInfo { Exit(i64), Abort(String), UnsupportedInIsolation(String), - ExperimentalUb { + StackedBorrowsUb { msg: String, help: Option, - url: String, history: Option, }, Deadlock, @@ -43,7 +42,7 @@ impl fmt::Display for TerminationInfo { Exit(code) => write!(f, "the evaluated program completed with exit code {}", code), Abort(msg) => write!(f, "{}", msg), UnsupportedInIsolation(msg) => write!(f, "{}", msg), - ExperimentalUb { msg, .. } => write!(f, "{}", msg), + StackedBorrowsUb { msg, .. } => write!(f, "{}", msg), Deadlock => write!(f, "the evaluated program deadlocked"), MultipleSymbolDefinitions { link_name, .. } => write!(f, "multiple definitions of symbol `{}`", link_name), @@ -146,7 +145,7 @@ pub fn report_error<'tcx, 'mir>( Exit(code) => return Some(*code), Abort(_) => Some("abnormal termination"), UnsupportedInIsolation(_) => Some("unsupported operation"), - ExperimentalUb { .. } => Some("Undefined Behavior"), + StackedBorrowsUb { .. } => Some("Undefined Behavior"), Deadlock => Some("deadlock"), MultipleSymbolDefinitions { .. } | SymbolShimClashing { .. } => None, }; @@ -157,11 +156,12 @@ pub fn report_error<'tcx, 'mir>( (None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation;")), (None, format!("or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning")), ], - ExperimentalUb { url, help, history, .. } => { + StackedBorrowsUb { help, history, .. } => { + let url = "https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md"; msg.extend(help.clone()); let mut helps = vec![ - (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental")), - (None, format!("see {} for further information", url)), + (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental")), + (None, format!("see {url} for further information")), ]; match history { Some(TagHistory::Tagged {tag, created: (created_range, created_span), invalidated, protected }) => { diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 88d1b1f10521..c78741499c2d 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -250,14 +250,7 @@ pub fn err_sb_ub<'tcx>( help: Option, history: Option, ) -> InterpError<'tcx> { - err_machine_stop!(TerminationInfo::ExperimentalUb { - msg, - help, - url: format!( - "https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md" - ), - history - }) + err_machine_stop!(TerminationInfo::StackedBorrowsUb { msg, help, history }) } // # Stacked Borrows Core Begin From d9f8312d9ab86828ae7e1890630197d742b7ee3f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 Jun 2022 17:42:53 -0700 Subject: [PATCH 3275/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 85b2e88ac30c..83da802cfcf5 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -09d52bc5d4260bac8b9a2ea8ac7a07c5c72906f1 +99930ac7f8cbb5d9b319b2e2e92794fd6f24f556 From 4ccd3f860a7828c49da9ada9c819cfa0079c32d6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 Jun 2022 17:45:33 -0700 Subject: [PATCH 3276/5092] tweak punctuation --- CONTRIBUTING.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 623480890c92..29a89e4a5365 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -134,7 +134,8 @@ build Miri yourself, the Miri shipped by `rustup` will work. All you have to do is set the `MIRI_LIB_SRC` environment variable to the `library` folder of a `rust-lang/rust` repository checkout. Note that changing files in that directory does not automatically trigger a re-build of the standard library; you have to -clear the Miri build cache manually (on Linux, `rm -rf ~/.cache/miri` and on Windows, `rmdir /S "%LOCALAPPDATA%\rust-lang\miri"`). +clear the Miri build cache manually (on Linux, `rm -rf ~/.cache/miri`; +and on Windows, `rmdir /S "%LOCALAPPDATA%\rust-lang\miri"`). ## Configuring `rust-analyzer` @@ -226,7 +227,8 @@ rustup override set stage2 ``` Important: You need to delete the Miri cache when you change the stdlib; otherwise the -old, chached version will be used. On Linux, the cache is located at `~/.cache/miri` and on Windows, the cache is located at `%LOCALAPPDATA%\rust-lang\miri`; the exact +old, chached version will be used. On Linux, the cache is located at `~/.cache/miri`, +and on Windows, it is located at `%LOCALAPPDATA%\rust-lang\miri`; the exact location is printed after the library build: "A libstd for Miri is now available in ...". Note: `./x.py --stage 2 compiler/rustc` currently errors with `thread 'main' From 6ed05d976efb98ab01aadddcd22c6628cc37bf08 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 Jun 2022 22:34:01 -0700 Subject: [PATCH 3277/5092] bless --- tests/fail/box-cell-alias.stderr | 2 +- tests/fail/stacked_borrows/alias_through_mutation.stderr | 2 +- tests/fail/stacked_borrows/aliasing_mut1.stderr | 2 +- tests/fail/stacked_borrows/aliasing_mut2.stderr | 2 +- tests/fail/stacked_borrows/aliasing_mut3.stderr | 2 +- tests/fail/stacked_borrows/aliasing_mut4.stderr | 2 +- tests/fail/stacked_borrows/box_exclusive_violation1.stderr | 2 +- tests/fail/stacked_borrows/buggy_as_mut_slice.stderr | 2 +- tests/fail/stacked_borrows/buggy_split_at_mut.stderr | 2 +- tests/fail/stacked_borrows/deallocate_against_barrier1.stderr | 2 +- tests/fail/stacked_borrows/deallocate_against_barrier2.stderr | 2 +- tests/fail/stacked_borrows/illegal_read1.stderr | 2 +- tests/fail/stacked_borrows/illegal_read2.stderr | 2 +- tests/fail/stacked_borrows/illegal_read3.stderr | 2 +- tests/fail/stacked_borrows/illegal_read4.stderr | 2 +- tests/fail/stacked_borrows/illegal_read5.stderr | 2 +- tests/fail/stacked_borrows/illegal_read6.stderr | 2 +- tests/fail/stacked_borrows/illegal_read7.stderr | 2 +- tests/fail/stacked_borrows/illegal_read8.stderr | 2 +- tests/fail/stacked_borrows/illegal_write1.stderr | 2 +- tests/fail/stacked_borrows/illegal_write2.stderr | 2 +- tests/fail/stacked_borrows/illegal_write3.stderr | 2 +- tests/fail/stacked_borrows/illegal_write4.stderr | 2 +- tests/fail/stacked_borrows/illegal_write5.stderr | 2 +- tests/fail/stacked_borrows/illegal_write6.stderr | 2 +- tests/fail/stacked_borrows/interior_mut1.stderr | 2 +- tests/fail/stacked_borrows/interior_mut2.stderr | 2 +- tests/fail/stacked_borrows/invalidate_against_barrier1.stderr | 2 +- tests/fail/stacked_borrows/invalidate_against_barrier2.stderr | 2 +- tests/fail/stacked_borrows/load_invalid_mut.stderr | 2 +- tests/fail/stacked_borrows/load_invalid_shr.stderr | 2 +- tests/fail/stacked_borrows/mut_exclusive_violation1.stderr | 2 +- tests/fail/stacked_borrows/mut_exclusive_violation2.stderr | 2 +- tests/fail/stacked_borrows/outdated_local.stderr | 2 +- tests/fail/stacked_borrows/pass_invalid_mut.stderr | 2 +- tests/fail/stacked_borrows/pass_invalid_shr.stderr | 2 +- tests/fail/stacked_borrows/pointer_smuggling.stderr | 2 +- tests/fail/stacked_borrows/raw_tracking.stderr | 2 +- tests/fail/stacked_borrows/return_invalid_mut.stderr | 2 +- tests/fail/stacked_borrows/return_invalid_mut_option.stderr | 2 +- tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr | 2 +- tests/fail/stacked_borrows/return_invalid_shr.stderr | 2 +- tests/fail/stacked_borrows/return_invalid_shr_option.stderr | 2 +- tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr | 2 +- tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr | 2 +- tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr | 2 +- tests/fail/stacked_borrows/shr_frozen_violation1.stderr | 2 +- tests/fail/stacked_borrows/transmute-is-no-escape.stderr | 2 +- tests/fail/stacked_borrows/unescaped_local.stderr | 2 +- tests/fail/stacked_borrows/unescaped_static.stderr | 2 +- tests/fail/stacked_borrows/zst_slice.stderr | 2 +- 51 files changed, 51 insertions(+), 51 deletions(-) diff --git a/tests/fail/box-cell-alias.stderr b/tests/fail/box-cell-alias.stderr index a4eaec93a8fb..44813be9780c 100644 --- a/tests/fail/box-cell-alias.stderr +++ b/tests/fail/box-cell-alias.stderr @@ -7,7 +7,7 @@ LL | unsafe { (*ptr).set(20); } | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x1] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x1] --> $DIR/box-cell-alias.rs:LL:CC diff --git a/tests/fail/stacked_borrows/alias_through_mutation.stderr b/tests/fail/stacked_borrows/alias_through_mutation.stderr index 6862a67faec2..610a045efcf2 100644 --- a/tests/fail/stacked_borrows/alias_through_mutation.stderr +++ b/tests/fail/stacked_borrows/alias_through_mutation.stderr @@ -7,7 +7,7 @@ LL | let _val = *target_alias; | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/alias_through_mutation.rs:LL:CC diff --git a/tests/fail/stacked_borrows/aliasing_mut1.stderr b/tests/fail/stacked_borrows/aliasing_mut1.stderr index 5f2e5cbbad36..7282612b6fc3 100644 --- a/tests/fail/stacked_borrows/aliasing_mut1.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut1.stderr @@ -4,7 +4,7 @@ error: Undefined Behavior: not granting access to tag because incompatible LL | pub fn safe(_x: &mut i32, _y: &mut i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/aliasing_mut1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/aliasing_mut2.stderr b/tests/fail/stacked_borrows/aliasing_mut2.stderr index bb82252e78d4..d314fff6222e 100644 --- a/tests/fail/stacked_borrows/aliasing_mut2.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut2.stderr @@ -4,7 +4,7 @@ error: Undefined Behavior: not granting access to tag because incompatible LL | pub fn safe(_x: &i32, _y: &mut i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/aliasing_mut2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/aliasing_mut3.stderr b/tests/fail/stacked_borrows/aliasing_mut3.stderr index 0cfddcac8486..a4187be0a25b 100644 --- a/tests/fail/stacked_borrows/aliasing_mut3.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut3.stderr @@ -7,7 +7,7 @@ LL | pub fn safe(_x: &mut i32, _y: &i32) {} | trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x4] --> $DIR/aliasing_mut3.rs:LL:CC diff --git a/tests/fail/stacked_borrows/aliasing_mut4.stderr b/tests/fail/stacked_borrows/aliasing_mut4.stderr index 13b589b94754..0bf5e863bfa3 100644 --- a/tests/fail/stacked_borrows/aliasing_mut4.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut4.stderr @@ -4,7 +4,7 @@ error: Undefined Behavior: not granting access to tag because incompatible LL | pub fn safe(_x: &i32, _y: &mut Cell) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/aliasing_mut4.rs:LL:CC diff --git a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr index 94d450955348..90d945128578 100644 --- a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr +++ b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr @@ -7,7 +7,7 @@ LL | *our | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/box_exclusive_violation1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr b/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr index 8eed3732a0cb..b65e49fd4a7d 100644 --- a/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr +++ b/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr @@ -7,7 +7,7 @@ LL | v1[1] = 5; | attempting a write access using at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x4..0x8] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0xc] --> $DIR/buggy_as_mut_slice.rs:LL:CC diff --git a/tests/fail/stacked_borrows/buggy_split_at_mut.stderr b/tests/fail/stacked_borrows/buggy_split_at_mut.stderr index d1d8d1f6aa3c..1b2536c48e04 100644 --- a/tests/fail/stacked_borrows/buggy_split_at_mut.stderr +++ b/tests/fail/stacked_borrows/buggy_split_at_mut.stderr @@ -7,7 +7,7 @@ LL | let (a, b) = safe::split_at_mut(&mut array, 0); | trying to reborrow for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x10] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x10] --> $DIR/buggy_split_at_mut.rs:LL:CC diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr b/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr index 38b84e638be4..58032fa35a1d 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr +++ b/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr @@ -4,7 +4,7 @@ error: Undefined Behavior: deallocating while item is protected: [Unique for (call ID)] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr b/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr index 72e6814b8e14..088daec040fe 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr +++ b/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr @@ -4,7 +4,7 @@ error: Undefined Behavior: deallocating while item is protected: [SharedReadWrit LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item is protected: [SharedReadWrite for (call ID)] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_read1.stderr b/tests/fail/stacked_borrows/illegal_read1.stderr index ca3147e6221e..bf78c62a0e79 100644 --- a/tests/fail/stacked_borrows/illegal_read1.stderr +++ b/tests/fail/stacked_borrows/illegal_read1.stderr @@ -7,7 +7,7 @@ LL | let _val = *xref; // ...but any use of raw will invalidate our ref. | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_read1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_read2.stderr b/tests/fail/stacked_borrows/illegal_read2.stderr index b6343ddd30b6..b0bc3f9a7f0d 100644 --- a/tests/fail/stacked_borrows/illegal_read2.stderr +++ b/tests/fail/stacked_borrows/illegal_read2.stderr @@ -7,7 +7,7 @@ LL | let _val = *xref; // ...but any use of raw will invalidate our ref. | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_read2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_read3.stderr b/tests/fail/stacked_borrows/illegal_read3.stderr index 75c4305ee81f..34580dec4ee4 100644 --- a/tests/fail/stacked_borrows/illegal_read3.stderr +++ b/tests/fail/stacked_borrows/illegal_read3.stderr @@ -7,7 +7,7 @@ LL | let _val = *xref2; | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_read3.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_read4.stderr b/tests/fail/stacked_borrows/illegal_read4.stderr index 968c31ba23af..19c361a19542 100644 --- a/tests/fail/stacked_borrows/illegal_read4.stderr +++ b/tests/fail/stacked_borrows/illegal_read4.stderr @@ -7,7 +7,7 @@ LL | let _illegal = *xref2; | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_read4.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_read5.stderr b/tests/fail/stacked_borrows/illegal_read5.stderr index df6f0a1c6886..4af149e3831e 100644 --- a/tests/fail/stacked_borrows/illegal_read5.stderr +++ b/tests/fail/stacked_borrows/illegal_read5.stderr @@ -7,7 +7,7 @@ LL | let _val = *xref; // the mutable one is dead and gone | attempting a read access using at ALLOC[$HEX], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[$HEX..$HEX] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [$HEX..$HEX] --> $DIR/illegal_read5.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_read6.stderr b/tests/fail/stacked_borrows/illegal_read6.stderr index c2be5bb370c5..499f060c47c2 100644 --- a/tests/fail/stacked_borrows/illegal_read6.stderr +++ b/tests/fail/stacked_borrows/illegal_read6.stderr @@ -7,7 +7,7 @@ LL | let _val = *raw; | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x4] --> $DIR/illegal_read6.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_read7.stderr b/tests/fail/stacked_borrows/illegal_read7.stderr index 921d8872b70b..e7e1685964bc 100644 --- a/tests/fail/stacked_borrows/illegal_read7.stderr +++ b/tests/fail/stacked_borrows/illegal_read7.stderr @@ -7,7 +7,7 @@ LL | let _val = *x.get_mut(); | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_read7.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_read8.stderr b/tests/fail/stacked_borrows/illegal_read8.stderr index 6c6168032b24..21df77775c8b 100644 --- a/tests/fail/stacked_borrows/illegal_read8.stderr +++ b/tests/fail/stacked_borrows/illegal_read8.stderr @@ -7,7 +7,7 @@ LL | let _fail = *y1; | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_read8.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_write1.stderr b/tests/fail/stacked_borrows/illegal_write1.stderr index 08fa05ff9f1f..76639960a923 100644 --- a/tests/fail/stacked_borrows/illegal_write1.stderr +++ b/tests/fail/stacked_borrows/illegal_write1.stderr @@ -7,7 +7,7 @@ LL | let _x = *xref; | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_write1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_write2.stderr b/tests/fail/stacked_borrows/illegal_write2.stderr index 13f41eea9153..3a225123d1f2 100644 --- a/tests/fail/stacked_borrows/illegal_write2.stderr +++ b/tests/fail/stacked_borrows/illegal_write2.stderr @@ -7,7 +7,7 @@ LL | unsafe { *target2 = 13; } | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x4] --> $DIR/illegal_write2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_write3.stderr b/tests/fail/stacked_borrows/illegal_write3.stderr index b37caee5ef20..0dc948b29152 100644 --- a/tests/fail/stacked_borrows/illegal_write3.stderr +++ b/tests/fail/stacked_borrows/illegal_write3.stderr @@ -7,7 +7,7 @@ LL | unsafe { *ptr = 42; } | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x4] --> $DIR/illegal_write3.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_write4.stderr b/tests/fail/stacked_borrows/illegal_write4.stderr index 5c0b4ec868e2..404e13d1138a 100644 --- a/tests/fail/stacked_borrows/illegal_write4.stderr +++ b/tests/fail/stacked_borrows/illegal_write4.stderr @@ -7,7 +7,7 @@ LL | let _val = *reference; | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_write4.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_write5.stderr b/tests/fail/stacked_borrows/illegal_write5.stderr index f9a4dcfd8d21..b11990814565 100644 --- a/tests/fail/stacked_borrows/illegal_write5.stderr +++ b/tests/fail/stacked_borrows/illegal_write5.stderr @@ -7,7 +7,7 @@ LL | let _val = *xref; | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_write5.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_write6.stderr b/tests/fail/stacked_borrows/illegal_write6.stderr index 5861aeefaf46..a58abc8377a0 100644 --- a/tests/fail/stacked_borrows/illegal_write6.stderr +++ b/tests/fail/stacked_borrows/illegal_write6.stderr @@ -4,7 +4,7 @@ error: Undefined Behavior: not granting access to tag because incompa LL | unsafe { *y = 2; } | ^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x4] --> $DIR/illegal_write6.rs:LL:CC diff --git a/tests/fail/stacked_borrows/interior_mut1.stderr b/tests/fail/stacked_borrows/interior_mut1.stderr index af4163c93605..82cb6e19133d 100644 --- a/tests/fail/stacked_borrows/interior_mut1.stderr +++ b/tests/fail/stacked_borrows/interior_mut1.stderr @@ -7,7 +7,7 @@ LL | let _val = *inner_shr.get(); | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/interior_mut1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/interior_mut2.stderr b/tests/fail/stacked_borrows/interior_mut2.stderr index 5a4ddf381e71..c8a06e32fda0 100644 --- a/tests/fail/stacked_borrows/interior_mut2.stderr +++ b/tests/fail/stacked_borrows/interior_mut2.stderr @@ -7,7 +7,7 @@ LL | let _val = *inner_shr.get(); | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/interior_mut2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr index 47f7a06a8585..08d597ea1895 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr @@ -4,7 +4,7 @@ error: Undefined Behavior: not granting access to tag because incompa LL | let _val = unsafe { *x }; | ^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x4] --> $DIR/invalidate_against_barrier1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr index fa2e6aa05a2b..6aefa216ed56 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr @@ -4,7 +4,7 @@ error: Undefined Behavior: not granting access to tag because incompa LL | unsafe { *x = 0 }; | ^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x4] --> $DIR/invalidate_against_barrier2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/load_invalid_mut.stderr b/tests/fail/stacked_borrows/load_invalid_mut.stderr index 00eda4fe5a31..a15900411ce4 100644 --- a/tests/fail/stacked_borrows/load_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/load_invalid_mut.stderr @@ -7,7 +7,7 @@ LL | let _val = *xref_in_mem; | trying to reborrow for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/load_invalid_mut.rs:LL:CC diff --git a/tests/fail/stacked_borrows/load_invalid_shr.stderr b/tests/fail/stacked_borrows/load_invalid_shr.stderr index eb61b4762f84..85cb8ef93ebd 100644 --- a/tests/fail/stacked_borrows/load_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/load_invalid_shr.stderr @@ -7,7 +7,7 @@ LL | let _val = *xref_in_mem; | trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/load_invalid_shr.rs:LL:CC diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr b/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr index 2d8ef7c1a4eb..4e38bcd2a89c 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr +++ b/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr @@ -7,7 +7,7 @@ LL | *LEAK = 7; | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x4] --> $DIR/mut_exclusive_violation1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr b/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr index ae0eab467bf6..fd52dbe348ac 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr +++ b/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr @@ -7,7 +7,7 @@ LL | let _val = *raw1; | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/mut_exclusive_violation2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/outdated_local.stderr b/tests/fail/stacked_borrows/outdated_local.stderr index 1c1deac2317f..fe3bdd00f462 100644 --- a/tests/fail/stacked_borrows/outdated_local.stderr +++ b/tests/fail/stacked_borrows/outdated_local.stderr @@ -7,7 +7,7 @@ LL | assert_eq!(unsafe { *y }, 1); | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x4] --> $DIR/outdated_local.rs:LL:CC diff --git a/tests/fail/stacked_borrows/pass_invalid_mut.stderr b/tests/fail/stacked_borrows/pass_invalid_mut.stderr index 280e51693a5c..6af914e55f91 100644 --- a/tests/fail/stacked_borrows/pass_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/pass_invalid_mut.stderr @@ -7,7 +7,7 @@ LL | foo(xref); | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/pass_invalid_mut.rs:LL:CC diff --git a/tests/fail/stacked_borrows/pass_invalid_shr.stderr b/tests/fail/stacked_borrows/pass_invalid_shr.stderr index b111832193b9..d38c58273453 100644 --- a/tests/fail/stacked_borrows/pass_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/pass_invalid_shr.stderr @@ -7,7 +7,7 @@ LL | foo(xref); | trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/pass_invalid_shr.rs:LL:CC diff --git a/tests/fail/stacked_borrows/pointer_smuggling.stderr b/tests/fail/stacked_borrows/pointer_smuggling.stderr index 097de439f79d..68ac631ec09e 100644 --- a/tests/fail/stacked_borrows/pointer_smuggling.stderr +++ b/tests/fail/stacked_borrows/pointer_smuggling.stderr @@ -7,7 +7,7 @@ LL | let _x = unsafe { *PTR }; | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x1] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x1] --> $DIR/pointer_smuggling.rs:LL:CC diff --git a/tests/fail/stacked_borrows/raw_tracking.stderr b/tests/fail/stacked_borrows/raw_tracking.stderr index a03d55a90486..93ae613c3c6b 100644 --- a/tests/fail/stacked_borrows/raw_tracking.stderr +++ b/tests/fail/stacked_borrows/raw_tracking.stderr @@ -7,7 +7,7 @@ LL | unsafe { *raw1 = 13; } | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/raw_tracking.rs:LL:CC diff --git a/tests/fail/stacked_borrows/return_invalid_mut.stderr b/tests/fail/stacked_borrows/return_invalid_mut.stderr index 6de657b82980..876850590e51 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut.stderr @@ -7,7 +7,7 @@ LL | ret | trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x4..0x8] --> $DIR/return_invalid_mut.rs:LL:CC diff --git a/tests/fail/stacked_borrows/return_invalid_mut_option.stderr b/tests/fail/stacked_borrows/return_invalid_mut_option.stderr index 8b95765dcc46..98decdc3adc8 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_option.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut_option.stderr @@ -7,7 +7,7 @@ LL | Some(_x) => {}, | trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x4..0x8] --> $DIR/return_invalid_mut_option.rs:LL:CC diff --git a/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr b/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr index f9e6d65c78e6..3062d821765a 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr @@ -7,7 +7,7 @@ LL | foo(&mut (1, 2)).0; | trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x4..0x8] --> $DIR/return_invalid_mut_tuple.rs:LL:CC diff --git a/tests/fail/stacked_borrows/return_invalid_shr.stderr b/tests/fail/stacked_borrows/return_invalid_shr.stderr index 20dcb8e93c2c..aa3f7ddde59e 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr.stderr @@ -7,7 +7,7 @@ LL | ret | trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x4..0x8] --> $DIR/return_invalid_shr.rs:LL:CC diff --git a/tests/fail/stacked_borrows/return_invalid_shr_option.stderr b/tests/fail/stacked_borrows/return_invalid_shr_option.stderr index 0c41a10a3f97..81244a87cb06 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_option.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr_option.stderr @@ -7,7 +7,7 @@ LL | Some(_x) => {}, | trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x4..0x8] --> $DIR/return_invalid_shr_option.rs:LL:CC diff --git a/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr b/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr index 9e7be7ad0138..9519f2f6f07b 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr @@ -7,7 +7,7 @@ LL | foo(&mut (1, 2)).0; | trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x4..0x8] --> $DIR/return_invalid_shr_tuple.rs:LL:CC diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr index 576a21bbf6d4..8bb67f62b531 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr @@ -7,7 +7,7 @@ LL | y.get_mut(); | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/shared_rw_borrows_are_weak1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr index e2159ed5892f..b339785d6484 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr @@ -7,7 +7,7 @@ LL | let _val = *y; | attempting a read access using at ALLOC[$HEX], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[$HEX..$HEX] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [$HEX..$HEX] --> $DIR/shared_rw_borrows_are_weak2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/shr_frozen_violation1.stderr b/tests/fail/stacked_borrows/shr_frozen_violation1.stderr index 689ad1c6b668..a2487cca278c 100644 --- a/tests/fail/stacked_borrows/shr_frozen_violation1.stderr +++ b/tests/fail/stacked_borrows/shr_frozen_violation1.stderr @@ -7,7 +7,7 @@ LL | unsafe { *(x as *const i32 as *mut i32) = 7; } | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x4] --> $DIR/shr_frozen_violation1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr index f2ea4f919c67..75d74ce39346 100644 --- a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr +++ b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr @@ -7,7 +7,7 @@ LL | unsafe { *raw = 13; } | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information = note: inside `main` at $DIR/transmute-is-no-escape.rs:LL:CC diff --git a/tests/fail/stacked_borrows/unescaped_local.stderr b/tests/fail/stacked_borrows/unescaped_local.stderr index a8d869549a9a..42a81245f2a8 100644 --- a/tests/fail/stacked_borrows/unescaped_local.stderr +++ b/tests/fail/stacked_borrows/unescaped_local.stderr @@ -7,7 +7,7 @@ LL | unsafe { *raw = 13; } | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x4] --> $DIR/unescaped_local.rs:LL:CC diff --git a/tests/fail/stacked_borrows/unescaped_static.stderr b/tests/fail/stacked_borrows/unescaped_static.stderr index b191855644c2..a0ac19f04293 100644 --- a/tests/fail/stacked_borrows/unescaped_static.stderr +++ b/tests/fail/stacked_borrows/unescaped_static.stderr @@ -7,7 +7,7 @@ LL | let _val = unsafe { *ptr_to_first.add(1) }; | attempting a read access using at ALLOC[0x1], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x1..0x2] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information = note: inside `main` at $DIR/unescaped_static.rs:LL:CC diff --git a/tests/fail/stacked_borrows/zst_slice.stderr b/tests/fail/stacked_borrows/zst_slice.stderr index 6809aa3d25fb..3474f0c2b423 100644 --- a/tests/fail/stacked_borrows/zst_slice.stderr +++ b/tests/fail/stacked_borrows/zst_slice.stderr @@ -7,7 +7,7 @@ LL | unsafe { &*index.get_unchecked(self) } | trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x0] --> $DIR/zst_slice.rs:LL:CC From 286a30fb1d512b19ea4e614d378682c066a4c97f Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Sun, 12 Jun 2022 12:10:13 -0700 Subject: [PATCH 3278/5092] correct the path --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 29a89e4a5365..4def6dc1b691 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -135,7 +135,7 @@ is set the `MIRI_LIB_SRC` environment variable to the `library` folder of a `rust-lang/rust` repository checkout. Note that changing files in that directory does not automatically trigger a re-build of the standard library; you have to clear the Miri build cache manually (on Linux, `rm -rf ~/.cache/miri`; -and on Windows, `rmdir /S "%LOCALAPPDATA%\rust-lang\miri"`). +and on Windows, `rmdir /S "%LOCALAPPDATA%\rust-lang\miri\cache"`). ## Configuring `rust-analyzer` @@ -228,7 +228,7 @@ rustup override set stage2 Important: You need to delete the Miri cache when you change the stdlib; otherwise the old, chached version will be used. On Linux, the cache is located at `~/.cache/miri`, -and on Windows, it is located at `%LOCALAPPDATA%\rust-lang\miri`; the exact +and on Windows, it is located at `%LOCALAPPDATA%\rust-lang\miri\cache`; the exact location is printed after the library build: "A libstd for Miri is now available in ...". Note: `./x.py --stage 2 compiler/rustc` currently errors with `thread 'main' From 238bbd63abc3f6deb1fff6fffd6afc2886f4b7a7 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 12 Jun 2022 17:55:41 -0700 Subject: [PATCH 3279/5092] Add `#![feature(yeet_expr)]` --- rust-version | 2 +- src/lib.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 83da802cfcf5..3b3645a97bee 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -99930ac7f8cbb5d9b319b2e2e92794fd6f24f556 +546c826f0ccaab36e897860205281f490db274e6 diff --git a/src/lib.rs b/src/lib.rs index 22869e9b248c..dc6c0b8dc603 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ #![feature(try_blocks)] #![feature(let_else)] #![feature(io_error_more)] +#![feature(yeet_expr)] #![warn(rust_2018_idioms)] #![allow( clippy::collapsible_else_if, From 0689f36a5528875d3a0c467a327becbed961e6a6 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 13 Jun 2022 08:55:34 +0000 Subject: [PATCH 3280/5092] Always show stderr on test failure. --- ui_test/src/lib.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index caefee1992ed..7f9eb48e05f9 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -147,10 +147,7 @@ pub fn run_tests(config: Config) { eprintln!(); eprintln!("command: {:?}", miri); eprintln!(); - // `None` means never dump, as we already dumped it for an `OutputDiffers` - // `Some(false)` means there's no reason to dump, as all errors are independent of the stderr - // `Some(true)` means that there was a pattern in the .rs file that was not found in the output. - let mut dump_stderr = Some(false); + let mut dump_stderr = true; for error in errors { match error { Error::ExitStatus(mode, exit_status) => eprintln!("{mode:?} got {exit_status}"), @@ -160,7 +157,6 @@ pub fn run_tests(config: Config) { "expected because of pattern here: {}:{definition_line}", path.display().to_string().bold() ); - dump_stderr = dump_stderr.map(|_| true); } Error::NoPatternsFound => { eprintln!("{}", "no error patterns found in failure test".red()); @@ -169,7 +165,7 @@ pub fn run_tests(config: Config) { eprintln!("{}", "error pattern found in success test".red()), Error::OutputDiffers { path, actual, expected } => { if path.extension().unwrap() == "stderr" { - dump_stderr = None; + dump_stderr = false; } eprintln!("actual output differed from expected {}", path.display()); eprintln!("{}", pretty_assertions::StrComparison::new(expected, actual)); @@ -203,7 +199,8 @@ pub fn run_tests(config: Config) { } eprintln!(); } - if let Some(true) = dump_stderr { + // Unless we already dumped the stderr via an OutputDiffers diff, let's dump it here. + if dump_stderr { eprintln!("actual stderr:"); eprintln!("{}", stderr); eprintln!(); From 0648f03133a899269a86cdd204d45582871bbb61 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 18:34:41 -0400 Subject: [PATCH 3281/5092] ensure all worker threads stay around --- ui_test/src/lib.rs | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 7f9eb48e05f9..8b7b4783fabb 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -1,3 +1,4 @@ +use std::collections::VecDeque; use std::fmt::Write; use std::path::{Path, PathBuf}; use std::process::{Command, ExitStatus}; @@ -6,7 +7,6 @@ use std::sync::Mutex; use colored::*; use comments::ErrorMatch; -use crossbeam::queue::SegQueue; use regex::Regex; use rustc_stderr::{Level, Message}; @@ -55,9 +55,8 @@ pub fn run_tests(config: Config) { // Get the triple with which to run the tests let target = config.target.clone().unwrap_or_else(|| config.get_host()); - // A queue for files or folders to process - let todo = SegQueue::new(); - todo.push(config.root_dir.clone()); + // A channel for files to process + let (submit, receive) = crossbeam::channel::unbounded(); // Some statistics and failure reports. let failures = Mutex::new(vec![]); @@ -66,20 +65,31 @@ pub fn run_tests(config: Config) { let filtered = AtomicUsize::default(); crossbeam::scope(|s| { + // Create a thread that is in charge of walking the directory and submitting jobs. + // It closes the channel when it is done. + s.spawn(|_| { + let mut todo = VecDeque::new(); + todo.push_back(config.root_dir.clone()); + while let Some(path) = todo.pop_front() { + if path.is_dir() { + // Enqueue everything inside this directory. + for entry in std::fs::read_dir(path).unwrap() { + todo.push_back(entry.unwrap().path()); + } + } else if path.extension().map(|ext| ext == "rs").unwrap_or(false) { + // Forward .rs files to the test workers. + submit.send(path).unwrap(); + } + } + // There will be no more jobs. This signals the workers to quit. + // (This also ensures `submit` is moved into this closure.) + drop(submit); + }); + + // Create N worker threads that receive files to test. for _ in 0..std::thread::available_parallelism().unwrap().get() { s.spawn(|_| { - while let Some(path) = todo.pop() { - // Collect everything inside directories - if path.is_dir() { - for entry in std::fs::read_dir(path).unwrap() { - todo.push(entry.unwrap().path()); - } - continue; - } - // Only look at .rs files - if !path.extension().map(|ext| ext == "rs").unwrap_or(false) { - continue; - } + for path in &receive { if !config.path_filter.is_empty() { let path_display = path.display().to_string(); if !config.path_filter.iter().any(|filter| path_display.contains(filter)) { From a2cc014231537d913cc51984a6ec11090d62e787 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 18:53:19 -0400 Subject: [PATCH 3282/5092] test files in a deterministic order --- ui_test/src/lib.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 8b7b4783fabb..d6938b19bfe4 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -73,8 +73,12 @@ pub fn run_tests(config: Config) { while let Some(path) = todo.pop_front() { if path.is_dir() { // Enqueue everything inside this directory. - for entry in std::fs::read_dir(path).unwrap() { - todo.push_back(entry.unwrap().path()); + // We want it sorted, to have some control over scheduling of slow tests. + let mut entries = + std::fs::read_dir(path).unwrap().collect::, _>>().unwrap(); + entries.sort_by_key(|e| e.file_name()); + for entry in entries { + todo.push_back(entry.path()); } } else if path.extension().map(|ext| ext == "rs").unwrap_or(false) { // Forward .rs files to the test workers. From 8ebdad06158f33accee028c2937f95a8a0fca29a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 18:53:33 -0400 Subject: [PATCH 3283/5092] organize more files into folders, and run the weak-mem consistency test as the very first since it is so slow --- .../{weak_memory/consistency.rs => 0weak_memory_consistency.rs} | 2 +- tests/pass/{ => backtrace}/backtrace-api-v0.rs | 0 tests/pass/{ => backtrace}/backtrace-api-v0.stderr | 0 tests/pass/{ => backtrace}/backtrace-api-v0.stdout | 0 tests/pass/{ => backtrace}/backtrace-api-v1.rs | 0 tests/pass/{ => backtrace}/backtrace-api-v1.stderr | 0 tests/pass/{ => backtrace}/backtrace-api-v1.stdout | 0 tests/pass/{ => backtrace}/backtrace-global-alloc.rs | 0 tests/pass/{ => backtrace}/backtrace-global-alloc.stderr | 0 tests/pass/{ => backtrace}/backtrace-std.rs | 0 tests/pass/{ => backtrace}/backtrace-std.stderr | 0 tests/pass/{ => issues}/issue-15063.rs | 0 tests/pass/{ => issues}/issue-15080.rs | 0 tests/pass/{ => issues}/issue-15523-big.rs | 0 tests/pass/{ => issues}/issue-17877.rs | 0 tests/pass/{ => issues}/issue-20575.rs | 0 tests/pass/{ => issues}/issue-23261.rs | 0 tests/pass/{ => issues}/issue-26709.rs | 0 tests/pass/{ => issues}/issue-27901.rs | 0 tests/pass/{ => issues}/issue-29746.rs | 0 tests/pass/{ => issues}/issue-30530.rs | 0 tests/pass/{ => issues}/issue-31267-additional.rs | 0 tests/pass/{ => issues}/issue-33387.rs | 0 tests/pass/{ => issues}/issue-34571.rs | 0 tests/pass/{ => issues}/issue-35815.rs | 0 tests/pass/{ => issues}/issue-36278-prefix-nesting.rs | 0 tests/pass/{ => issues}/issue-3794.rs | 0 tests/pass/{ => issues}/issue-3794.stdout | 0 tests/pass/{ => issues}/issue-53728.rs | 0 tests/pass/{ => issues}/issue-5917.rs | 0 tests/pass/{ => issues}/issue-73223.rs | 0 tests/pass/{ => issues}/issue-91636.rs | 0 tests/pass/{ => issues}/issue-94371.rs | 0 tests/pass/{ => issues}/issue-miri-1075.rs | 0 tests/pass/{ => issues}/issue-miri-133.rs | 0 tests/pass/{ => issues}/issue-miri-184.rs | 0 tests/pass/{ => issues}/issue-miri-1925.rs | 0 tests/pass/{ => issues}/issue-miri-2068-2.rs | 0 tests/pass/{ => issues}/issue-miri-2068.rs | 0 39 files changed, 1 insertion(+), 1 deletion(-) rename tests/pass/{weak_memory/consistency.rs => 0weak_memory_consistency.rs} (99%) rename tests/pass/{ => backtrace}/backtrace-api-v0.rs (100%) rename tests/pass/{ => backtrace}/backtrace-api-v0.stderr (100%) rename tests/pass/{ => backtrace}/backtrace-api-v0.stdout (100%) rename tests/pass/{ => backtrace}/backtrace-api-v1.rs (100%) rename tests/pass/{ => backtrace}/backtrace-api-v1.stderr (100%) rename tests/pass/{ => backtrace}/backtrace-api-v1.stdout (100%) rename tests/pass/{ => backtrace}/backtrace-global-alloc.rs (100%) rename tests/pass/{ => backtrace}/backtrace-global-alloc.stderr (100%) rename tests/pass/{ => backtrace}/backtrace-std.rs (100%) rename tests/pass/{ => backtrace}/backtrace-std.stderr (100%) rename tests/pass/{ => issues}/issue-15063.rs (100%) rename tests/pass/{ => issues}/issue-15080.rs (100%) rename tests/pass/{ => issues}/issue-15523-big.rs (100%) rename tests/pass/{ => issues}/issue-17877.rs (100%) rename tests/pass/{ => issues}/issue-20575.rs (100%) rename tests/pass/{ => issues}/issue-23261.rs (100%) rename tests/pass/{ => issues}/issue-26709.rs (100%) rename tests/pass/{ => issues}/issue-27901.rs (100%) rename tests/pass/{ => issues}/issue-29746.rs (100%) rename tests/pass/{ => issues}/issue-30530.rs (100%) rename tests/pass/{ => issues}/issue-31267-additional.rs (100%) rename tests/pass/{ => issues}/issue-33387.rs (100%) rename tests/pass/{ => issues}/issue-34571.rs (100%) rename tests/pass/{ => issues}/issue-35815.rs (100%) rename tests/pass/{ => issues}/issue-36278-prefix-nesting.rs (100%) rename tests/pass/{ => issues}/issue-3794.rs (100%) rename tests/pass/{ => issues}/issue-3794.stdout (100%) rename tests/pass/{ => issues}/issue-53728.rs (100%) rename tests/pass/{ => issues}/issue-5917.rs (100%) rename tests/pass/{ => issues}/issue-73223.rs (100%) rename tests/pass/{ => issues}/issue-91636.rs (100%) rename tests/pass/{ => issues}/issue-94371.rs (100%) rename tests/pass/{ => issues}/issue-miri-1075.rs (100%) rename tests/pass/{ => issues}/issue-miri-133.rs (100%) rename tests/pass/{ => issues}/issue-miri-184.rs (100%) rename tests/pass/{ => issues}/issue-miri-1925.rs (100%) rename tests/pass/{ => issues}/issue-miri-2068-2.rs (100%) rename tests/pass/{ => issues}/issue-miri-2068.rs (100%) diff --git a/tests/pass/weak_memory/consistency.rs b/tests/pass/0weak_memory_consistency.rs similarity index 99% rename from tests/pass/weak_memory/consistency.rs rename to tests/pass/0weak_memory_consistency.rs index 8a7c1340cc59..fc9dce0c986a 100644 --- a/tests/pass/weak_memory/consistency.rs +++ b/tests/pass/0weak_memory_consistency.rs @@ -214,7 +214,7 @@ fn test_single_thread() { } pub fn main() { - for _ in 0..100 { + for _ in 0..50 { test_single_thread(); test_mixed_access(); test_load_buffering_acq_rel(); diff --git a/tests/pass/backtrace-api-v0.rs b/tests/pass/backtrace/backtrace-api-v0.rs similarity index 100% rename from tests/pass/backtrace-api-v0.rs rename to tests/pass/backtrace/backtrace-api-v0.rs diff --git a/tests/pass/backtrace-api-v0.stderr b/tests/pass/backtrace/backtrace-api-v0.stderr similarity index 100% rename from tests/pass/backtrace-api-v0.stderr rename to tests/pass/backtrace/backtrace-api-v0.stderr diff --git a/tests/pass/backtrace-api-v0.stdout b/tests/pass/backtrace/backtrace-api-v0.stdout similarity index 100% rename from tests/pass/backtrace-api-v0.stdout rename to tests/pass/backtrace/backtrace-api-v0.stdout diff --git a/tests/pass/backtrace-api-v1.rs b/tests/pass/backtrace/backtrace-api-v1.rs similarity index 100% rename from tests/pass/backtrace-api-v1.rs rename to tests/pass/backtrace/backtrace-api-v1.rs diff --git a/tests/pass/backtrace-api-v1.stderr b/tests/pass/backtrace/backtrace-api-v1.stderr similarity index 100% rename from tests/pass/backtrace-api-v1.stderr rename to tests/pass/backtrace/backtrace-api-v1.stderr diff --git a/tests/pass/backtrace-api-v1.stdout b/tests/pass/backtrace/backtrace-api-v1.stdout similarity index 100% rename from tests/pass/backtrace-api-v1.stdout rename to tests/pass/backtrace/backtrace-api-v1.stdout diff --git a/tests/pass/backtrace-global-alloc.rs b/tests/pass/backtrace/backtrace-global-alloc.rs similarity index 100% rename from tests/pass/backtrace-global-alloc.rs rename to tests/pass/backtrace/backtrace-global-alloc.rs diff --git a/tests/pass/backtrace-global-alloc.stderr b/tests/pass/backtrace/backtrace-global-alloc.stderr similarity index 100% rename from tests/pass/backtrace-global-alloc.stderr rename to tests/pass/backtrace/backtrace-global-alloc.stderr diff --git a/tests/pass/backtrace-std.rs b/tests/pass/backtrace/backtrace-std.rs similarity index 100% rename from tests/pass/backtrace-std.rs rename to tests/pass/backtrace/backtrace-std.rs diff --git a/tests/pass/backtrace-std.stderr b/tests/pass/backtrace/backtrace-std.stderr similarity index 100% rename from tests/pass/backtrace-std.stderr rename to tests/pass/backtrace/backtrace-std.stderr diff --git a/tests/pass/issue-15063.rs b/tests/pass/issues/issue-15063.rs similarity index 100% rename from tests/pass/issue-15063.rs rename to tests/pass/issues/issue-15063.rs diff --git a/tests/pass/issue-15080.rs b/tests/pass/issues/issue-15080.rs similarity index 100% rename from tests/pass/issue-15080.rs rename to tests/pass/issues/issue-15080.rs diff --git a/tests/pass/issue-15523-big.rs b/tests/pass/issues/issue-15523-big.rs similarity index 100% rename from tests/pass/issue-15523-big.rs rename to tests/pass/issues/issue-15523-big.rs diff --git a/tests/pass/issue-17877.rs b/tests/pass/issues/issue-17877.rs similarity index 100% rename from tests/pass/issue-17877.rs rename to tests/pass/issues/issue-17877.rs diff --git a/tests/pass/issue-20575.rs b/tests/pass/issues/issue-20575.rs similarity index 100% rename from tests/pass/issue-20575.rs rename to tests/pass/issues/issue-20575.rs diff --git a/tests/pass/issue-23261.rs b/tests/pass/issues/issue-23261.rs similarity index 100% rename from tests/pass/issue-23261.rs rename to tests/pass/issues/issue-23261.rs diff --git a/tests/pass/issue-26709.rs b/tests/pass/issues/issue-26709.rs similarity index 100% rename from tests/pass/issue-26709.rs rename to tests/pass/issues/issue-26709.rs diff --git a/tests/pass/issue-27901.rs b/tests/pass/issues/issue-27901.rs similarity index 100% rename from tests/pass/issue-27901.rs rename to tests/pass/issues/issue-27901.rs diff --git a/tests/pass/issue-29746.rs b/tests/pass/issues/issue-29746.rs similarity index 100% rename from tests/pass/issue-29746.rs rename to tests/pass/issues/issue-29746.rs diff --git a/tests/pass/issue-30530.rs b/tests/pass/issues/issue-30530.rs similarity index 100% rename from tests/pass/issue-30530.rs rename to tests/pass/issues/issue-30530.rs diff --git a/tests/pass/issue-31267-additional.rs b/tests/pass/issues/issue-31267-additional.rs similarity index 100% rename from tests/pass/issue-31267-additional.rs rename to tests/pass/issues/issue-31267-additional.rs diff --git a/tests/pass/issue-33387.rs b/tests/pass/issues/issue-33387.rs similarity index 100% rename from tests/pass/issue-33387.rs rename to tests/pass/issues/issue-33387.rs diff --git a/tests/pass/issue-34571.rs b/tests/pass/issues/issue-34571.rs similarity index 100% rename from tests/pass/issue-34571.rs rename to tests/pass/issues/issue-34571.rs diff --git a/tests/pass/issue-35815.rs b/tests/pass/issues/issue-35815.rs similarity index 100% rename from tests/pass/issue-35815.rs rename to tests/pass/issues/issue-35815.rs diff --git a/tests/pass/issue-36278-prefix-nesting.rs b/tests/pass/issues/issue-36278-prefix-nesting.rs similarity index 100% rename from tests/pass/issue-36278-prefix-nesting.rs rename to tests/pass/issues/issue-36278-prefix-nesting.rs diff --git a/tests/pass/issue-3794.rs b/tests/pass/issues/issue-3794.rs similarity index 100% rename from tests/pass/issue-3794.rs rename to tests/pass/issues/issue-3794.rs diff --git a/tests/pass/issue-3794.stdout b/tests/pass/issues/issue-3794.stdout similarity index 100% rename from tests/pass/issue-3794.stdout rename to tests/pass/issues/issue-3794.stdout diff --git a/tests/pass/issue-53728.rs b/tests/pass/issues/issue-53728.rs similarity index 100% rename from tests/pass/issue-53728.rs rename to tests/pass/issues/issue-53728.rs diff --git a/tests/pass/issue-5917.rs b/tests/pass/issues/issue-5917.rs similarity index 100% rename from tests/pass/issue-5917.rs rename to tests/pass/issues/issue-5917.rs diff --git a/tests/pass/issue-73223.rs b/tests/pass/issues/issue-73223.rs similarity index 100% rename from tests/pass/issue-73223.rs rename to tests/pass/issues/issue-73223.rs diff --git a/tests/pass/issue-91636.rs b/tests/pass/issues/issue-91636.rs similarity index 100% rename from tests/pass/issue-91636.rs rename to tests/pass/issues/issue-91636.rs diff --git a/tests/pass/issue-94371.rs b/tests/pass/issues/issue-94371.rs similarity index 100% rename from tests/pass/issue-94371.rs rename to tests/pass/issues/issue-94371.rs diff --git a/tests/pass/issue-miri-1075.rs b/tests/pass/issues/issue-miri-1075.rs similarity index 100% rename from tests/pass/issue-miri-1075.rs rename to tests/pass/issues/issue-miri-1075.rs diff --git a/tests/pass/issue-miri-133.rs b/tests/pass/issues/issue-miri-133.rs similarity index 100% rename from tests/pass/issue-miri-133.rs rename to tests/pass/issues/issue-miri-133.rs diff --git a/tests/pass/issue-miri-184.rs b/tests/pass/issues/issue-miri-184.rs similarity index 100% rename from tests/pass/issue-miri-184.rs rename to tests/pass/issues/issue-miri-184.rs diff --git a/tests/pass/issue-miri-1925.rs b/tests/pass/issues/issue-miri-1925.rs similarity index 100% rename from tests/pass/issue-miri-1925.rs rename to tests/pass/issues/issue-miri-1925.rs diff --git a/tests/pass/issue-miri-2068-2.rs b/tests/pass/issues/issue-miri-2068-2.rs similarity index 100% rename from tests/pass/issue-miri-2068-2.rs rename to tests/pass/issues/issue-miri-2068-2.rs diff --git a/tests/pass/issue-miri-2068.rs b/tests/pass/issues/issue-miri-2068.rs similarity index 100% rename from tests/pass/issue-miri-2068.rs rename to tests/pass/issues/issue-miri-2068.rs From c16c45362ccb854ab9438a5db5ad6152dc7fd519 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 13 Jun 2022 15:20:01 +0200 Subject: [PATCH 3284/5092] Document file sorting --- ui_test/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ui_test/README.md b/ui_test/README.md index b3c9a3378cf3..07a0a67b9143 100644 --- a/ui_test/README.md +++ b/ui_test/README.md @@ -1,5 +1,10 @@ A smaller version of compiletest-rs +## Magic behavior + +* Tests are run in order of their filenames (files first, then recursing into folders). + So if you have any slow tests, prepend them with a small integral number to make them get run first, taking advantage of parallelism as much as possible (instead of waiting for the slow tests at the end). + ## Supported magic comment annotations Note that the space after `//`, when it is present, is *not* optional -- it must be exactly one. From 56a4c132b6c8661010b5a176d334fd2a0db7cf53 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Mon, 13 Jun 2022 18:24:19 +0100 Subject: [PATCH 3285/5092] Reduce the number of iterations --- tests/pass/concurrency/linux-futex.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/pass/concurrency/linux-futex.rs b/tests/pass/concurrency/linux-futex.rs index 56aba60d534a..0d30ddff4809 100644 --- a/tests/pass/concurrency/linux-futex.rs +++ b/tests/pass/concurrency/linux-futex.rs @@ -212,7 +212,7 @@ const FREE: i32 = 0; const HELD: i32 = 1; fn concurrent_wait_wake() { static FUTEX: AtomicI32 = AtomicI32::new(0); - for _ in 0..100 { + for _ in 0..20 { // Suppose the main thread is holding a lock implemented using futex... FUTEX.store(HELD, Ordering::Relaxed); From 97bd49bf2d1d7604dc0a5040edb2a550adf5497b Mon Sep 17 00:00:00 2001 From: Alan Egerton Date: Tue, 14 Jun 2022 21:57:57 +0100 Subject: [PATCH 3286/5092] Clarify `[T]::select_nth_unstable*` return values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In cases where the nth element is not unique within the slice, it is not correct to say that the values in the returned triplet include ones for "all elements" less/greater than that at the given index: indeed one (or more) such values would then laso contain values equal to that at the given index. The text proposed here clarifies exactly what is returned, but in so doing it is also documenting an implementation detail that previously wasn't detailed: namely that the return slices are slices into the reordered slice. I don't think this can be contentious, because the lifetimes of those returned slices are bound to that of the original (now reordered) slice—so there really isn't any other reasonable implementation that could have this behaviour; but nevertheless it's probably best if @rust-lang/libs-api give it a nod? Fixes #97982 r? m-ou-se @rustbot label +A-docs C-bug +T-libs-api --- library/core/src/slice/mod.rs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 77fd1ec2b8ea..409918952237 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -2628,9 +2628,10 @@ impl [T] { /// less than or equal to any value at a position `j > index`. Additionally, this reordering is /// unstable (i.e. any number of equal elements may end up at position `index`), in-place /// (i.e. does not allocate), and *O*(*n*) worst-case. This function is also/ known as "kth - /// element" in other libraries. It returns a triplet of the following values: all elements less - /// than the one at the given index, the value at the given index, and all elements greater than - /// the one at the given index. + /// element" in other libraries. It returns a triplet of the following from the reordered slice: + /// the subslice prior to `index`, the element at `index`, and the subslice after `index`; + /// accordingly, the values in those two subslices will respectively all be less-than-or-equal-to + /// and greater-than-or-equal-to the value of the element at `index`. /// /// # Current implementation /// @@ -2675,10 +2676,11 @@ impl [T] { /// less than or equal to any value at a position `j > index` using the comparator function. /// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at /// position `index`), in-place (i.e. does not allocate), and *O*(*n*) worst-case. This function - /// is also known as "kth element" in other libraries. It returns a triplet of the following - /// values: all elements less than the one at the given index, the value at the given index, - /// and all elements greater than the one at the given index, using the provided comparator - /// function. + /// is also known as "kth element" in other libraries. It returns a triplet of the following from + /// the slice reordered according to the provided comparator function: the subslice prior to + /// `index`, the element at `index`, and the subslice after `index`; accordingly, the values in + /// those two subslices will respectively all be less-than-or-equal-to and greater-than-or-equal-to + /// the value of the element at `index`. /// /// # Current implementation /// @@ -2727,10 +2729,11 @@ impl [T] { /// less than or equal to any value at a position `j > index` using the key extraction function. /// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at /// position `index`), in-place (i.e. does not allocate), and *O*(*n*) worst-case. This function - /// is also known as "kth element" in other libraries. It returns a triplet of the following - /// values: all elements less than the one at the given index, the value at the given index, and - /// all elements greater than the one at the given index, using the provided key extraction - /// function. + /// is also known as "kth element" in other libraries. It returns a triplet of the following from + /// the slice reordered according to the provided key extraction function: the subslice prior to + /// `index`, the element at `index`, and the subslice after `index`; accordingly, the values in + /// those two subslices will respectively all be less-than-or-equal-to and greater-than-or-equal-to + /// the value of the element at `index`. /// /// # Current implementation /// From 807a19a50a663c75874bb79afeecd4b12de583e2 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Wed, 15 Jun 2022 01:44:32 +0100 Subject: [PATCH 3287/5092] Elaborate correctness comments --- src/shims/unix/linux/sync.rs | 51 +++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/src/shims/unix/linux/sync.rs b/src/shims/unix/linux/sync.rs index 42494da37b79..37d694a32f80 100644 --- a/src/shims/unix/linux/sync.rs +++ b/src/shims/unix/linux/sync.rs @@ -126,16 +126,47 @@ pub fn futex<'tcx>( Align::from_bytes(4).unwrap(), CheckInAllocMsg::MemoryAccessTest, )?; - // This SeqCst fence is paired with the SeqCst fence in futex_wake. - // Together, they make sure that our read on addr observes the latest - // value in modification order. + // There may be a concurrent thread changing the value of addr + // and then invoking the FUTEX_WAKE syscall. It is critical that the + // effects of this and the other thread are correctly observed, + // otherwise we will deadlock. // - // If there is another thread which has changed the value of - // addr (to something other than expected) and called futex_wake - // before we get to run, then we must not block our thread - // because there'll be no one to wake us. We must see - // the value changed by the other thread and return without - // actually waiting. + // There are two scenarios to consider: + // 1. If we (FUTEX_WAIT) executes first, we'll push ourselves into + // the waiters queue and go to sleep. They (addr write & FUTEX_WAKE) + // will see us in the queue and wake us up. + // 2. If they (addr write & FUTEX_WAKE) executes first, we must observe + // addr's new value. If we see an outdated value that happens to equal + // the expected val, then we'll put ourselves to sleep with no one to wake us + // up, so we end up with a deadlock. This is prevented by having a SeqCst + // fence inside FUTEX_WAKE syscall, and another SeqCst fence + // below, the atomic read on addr after the SeqCst fence is guaranteed + // not to see any value older than the addr write immediately before + // calling FUTEX_WAKE. We'll see futex_val != val and return without + // sleeping. + // + // Note that the fences do not create any happens-before relationship. + // The read sees the write immediately before the fence not because + // one happens after the other, but is instead due to a guarantee unique + // to SeqCst fences that restricts what an atomic read placed AFTER the + // fence can see. The read still has to be atomic, otherwise it's a data + // race. This guarantee cannot be achieved with acquire-release fences + // since they only talk about reads placed BEFORE a fence - and places + // no restrictions on what the read itself can see, only that there is + // a happens-before between the fences IF the read happens to see the + // right value. This is useless to us, since we need the read itself + // to see an up-to-date value. + // + // It is also critical that the fence, the atomic load, and the comparison + // altogether happen atomically. If the other thread's fence in FUTEX_WAKE + // gets interleaved after our fence, then we lose the guarantee on the + // atomic load being up-to-date; if the other thread's write on addr and FUTEX_WAKE + // call are interleaved after the load but before the comparison, then we get a TOCTOU + // race condition, and go to sleep thinking the other thread will wake us up, + // even though they have already finished. + // + // Thankfully, preemptions cannot happen inside a Miri shim, so we do not need to + // do anything special to guarantee fence-load-comparison atomicity. this.atomic_fence(&[], AtomicFenceOp::SeqCst)?; // Read an `i32` through the pointer, regardless of any wrapper types. // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`. @@ -149,7 +180,7 @@ pub fn futex<'tcx>( )? .to_i32()?; if val == futex_val { - // The value still matches, so we block the trait make it wait for FUTEX_WAKE. + // The value still matches, so we block the thread make it wait for FUTEX_WAKE. this.block_thread(thread); this.futex_wait(addr_usize, thread, bitset); // Succesfully waking up from FUTEX_WAIT always returns zero. From e70c631a3b15ad5e72c43c09187c6a02e3b92888 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 16 Jun 2022 11:02:54 -0700 Subject: [PATCH 3288/5092] add ICE error level --- ui_test/src/rustc_stderr.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui_test/src/rustc_stderr.rs b/ui_test/src/rustc_stderr.rs index ac76a78a3cbc..203014c50d52 100644 --- a/ui_test/src/rustc_stderr.rs +++ b/ui_test/src/rustc_stderr.rs @@ -16,6 +16,7 @@ struct RustcMessage { #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] pub(crate) enum Level { + Ice = 5, Error = 4, Warn = 3, Help = 2, @@ -52,6 +53,7 @@ impl std::str::FromStr for Level { "HELP" | "help" => Ok(Self::Help), "NOTE" | "note" => Ok(Self::Note), "failure-note" => Ok(Self::FailureNote), + "error: internal compiler error" => Ok(Self::Ice), _ => Err(format!("unknown level `{s}`")), } } From d194e9823c2a51008c2e3b1e2f7b5a6fffead0a1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 16 Jun 2022 10:03:41 -0700 Subject: [PATCH 3289/5092] rustup --- rust-version | 2 +- tests/fail/data_race/fence_after_load.rs | 3 ++- tests/fail/erroneous_const.stderr | 4 ++-- tests/pass/concurrency/channels.rs | 15 ++++++++++++--- tests/pass/threadleak_ignored.rs | 3 ++- 5 files changed, 19 insertions(+), 8 deletions(-) diff --git a/rust-version b/rust-version index 3b3645a97bee..792ac12b8044 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -546c826f0ccaab36e897860205281f490db274e6 +1f34da9ec8a85b6f86c5fa1c121ab6f88f2f4966 diff --git a/tests/fail/data_race/fence_after_load.rs b/tests/fail/data_race/fence_after_load.rs index b38171593386..20cc691f88e1 100644 --- a/tests/fail/data_race/fence_after_load.rs +++ b/tests/fail/data_race/fence_after_load.rs @@ -1,4 +1,5 @@ -// compile-flags: -Zmiri-disable-isolation +// We want to control preemption here. +// compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 // ignore-windows: Concurrency on Windows is not supported yet. use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering, fence}; diff --git a/tests/fail/erroneous_const.stderr b/tests/fail/erroneous_const.stderr index e1758ad657de..d4b8f25e0385 100644 --- a/tests/fail/erroneous_const.stderr +++ b/tests/fail/erroneous_const.stderr @@ -6,11 +6,11 @@ LL | const VOID: ! = panic!(); | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) -error: post-monomorphization error: encountered constants with type errors, stopping evaluation +error: post-monomorphization error: referenced constant has errors --> $DIR/erroneous_const.rs:LL:CC | LL | let _ = PrintName::::VOID; - | ^^^^^^^^^^^^^^^^^^^^ encountered constants with type errors, stopping evaluation + | ^^^^^^^^^^^^^^^^^^^^ referenced constant has errors | = note: inside `no_codegen::` at $DIR/erroneous_const.rs:LL:CC note: inside `main` at $DIR/erroneous_const.rs:LL:CC diff --git a/tests/pass/concurrency/channels.rs b/tests/pass/concurrency/channels.rs index b0c095b2d359..0d6c1749eb51 100644 --- a/tests/pass/concurrency/channels.rs +++ b/tests/pass/concurrency/channels.rs @@ -9,20 +9,23 @@ use std::thread; /// The test taken from the Rust documentation. fn simple_send() { let (tx, rx) = channel(); - thread::spawn(move || { + let t = thread::spawn(move || { tx.send(10).unwrap(); }); assert_eq!(rx.recv().unwrap(), 10); + t.join().unwrap(); } /// The test taken from the Rust documentation. fn multiple_send() { let (tx, rx) = channel(); + let mut threads = vec![]; for i in 0..10 { let tx = tx.clone(); - thread::spawn(move || { + let t = thread::spawn(move || { tx.send(i).unwrap(); }); + threads.push(t); } let mut sum = 0; @@ -32,6 +35,10 @@ fn multiple_send() { sum += j; } assert_eq!(sum, 45); + + for t in threads { + t.join().unwrap(); + } } /// The test taken from the Rust documentation. @@ -41,13 +48,15 @@ fn send_on_sync() { // this returns immediately sender.send(1).unwrap(); - thread::spawn(move || { + let t = thread::spawn(move || { // this will block until the previous message has been received sender.send(2).unwrap(); }); assert_eq!(receiver.recv().unwrap(), 1); assert_eq!(receiver.recv().unwrap(), 2); + + t.join().unwrap(); } fn main() { diff --git a/tests/pass/threadleak_ignored.rs b/tests/pass/threadleak_ignored.rs index cbdc7c6e9106..36d39a72b799 100644 --- a/tests/pass/threadleak_ignored.rs +++ b/tests/pass/threadleak_ignored.rs @@ -1,5 +1,6 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-ignore-leaks +// FIXME: disallow preemption to work around https://github.com/rust-lang/rust/issues/55005 +// compile-flags: -Zmiri-ignore-leaks -Zmiri-preemption-rate=0 //! Test that leaking threads works, and that their destructors are not executed. From a9095ff2139fb305b15006d1f2a1ff16da0b6c29 Mon Sep 17 00:00:00 2001 From: Aaron Kofsky Date: Thu, 16 Jun 2022 21:07:00 -0400 Subject: [PATCH 3290/5092] Re-allow `let_underscore_drop` by default. This lint is way way too noisy to have it be `Deny` by default. --- compiler/rustc_lint/src/let_underscore.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index d40c83e311f9..2ba79aacace8 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -46,7 +46,7 @@ declare_lint! { /// calling `std::mem::drop` on the expression is clearer and helps convey /// intent. pub LET_UNDERSCORE_DROP, - Deny, + Allow, "non-binding let on a type that implements `Drop`" } From 735e95385317fc658360859cc5381cfd3f4779bf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 18 Jun 2022 07:49:40 -0700 Subject: [PATCH 3291/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 792ac12b8044..9782fbe6cd45 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1f34da9ec8a85b6f86c5fa1c121ab6f88f2f4966 +cdcc53b7dc002ea4a7a28105010c5a1126ee31b7 From 737a5b3b9814e919d30f60323a7679697a34b153 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 18 Jun 2022 07:59:46 -0700 Subject: [PATCH 3292/5092] tweak correctness comment --- src/shims/unix/linux/sync.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/shims/unix/linux/sync.rs b/src/shims/unix/linux/sync.rs index 37d694a32f80..0fdbde8d6775 100644 --- a/src/shims/unix/linux/sync.rs +++ b/src/shims/unix/linux/sync.rs @@ -132,10 +132,10 @@ pub fn futex<'tcx>( // otherwise we will deadlock. // // There are two scenarios to consider: - // 1. If we (FUTEX_WAIT) executes first, we'll push ourselves into + // 1. If we (FUTEX_WAIT) execute first, we'll push ourselves into // the waiters queue and go to sleep. They (addr write & FUTEX_WAKE) // will see us in the queue and wake us up. - // 2. If they (addr write & FUTEX_WAKE) executes first, we must observe + // 2. If they (addr write & FUTEX_WAKE) execute first, we must observe // addr's new value. If we see an outdated value that happens to equal // the expected val, then we'll put ourselves to sleep with no one to wake us // up, so we end up with a deadlock. This is prevented by having a SeqCst @@ -157,7 +157,9 @@ pub fn futex<'tcx>( // right value. This is useless to us, since we need the read itself // to see an up-to-date value. // - // It is also critical that the fence, the atomic load, and the comparison + // The above case distinction is valid since both FUTEX_WAIT and FUTEX_WAKE + // contain a SeqCst fence, therefore inducting a total order between the operations. + // It is also critical that the fence, the atomic load, and the comparison in FUTEX_WAIT // altogether happen atomically. If the other thread's fence in FUTEX_WAKE // gets interleaved after our fence, then we lose the guarantee on the // atomic load being up-to-date; if the other thread's write on addr and FUTEX_WAKE From 3f9414565d4e0c54edc20123168d70741454913b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 19 Jun 2022 09:18:16 -0700 Subject: [PATCH 3293/5092] readme --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 50a43436dc21..88ac8a135304 100644 --- a/README.md +++ b/README.md @@ -21,12 +21,15 @@ for example: * **Experimental**: Violations of the [Stacked Borrows] rules governing aliasing for reference types * **Experimental**: Data races -* **Experimental**: Emulation of weak memory effects (i.e., reads can return outdated values) On top of that, Miri will also tell you about memory leaks: when there is memory still allocated at the end of the execution, and that memory is not reachable from a global `static`, Miri will raise an error. +Miri supports almost all Rust language features; in particular, unwinding and +concurrency are properly supported (including some experimental emulation of +weak memory effects, i.e., reads can return outdated values). + You can use Miri to emulate programs on other targets, e.g. to ensure that byte-level data manipulation works correctly both on little-endian and big-endian systems. See @@ -62,8 +65,6 @@ in your program, and cannot run all programs: not support networking. System API support varies between targets; if you run on Windows it is a good idea to use `--target x86_64-unknown-linux-gnu` to get better support. -* Threading support is not finished yet. E.g. spin loops (without syscalls) just - loop forever. There is no threading support on Windows. * Weak memory emulation may produce weak behaivours unobservable by compiled programs running on real hardware when `SeqCst` fences are used, and it cannot produce all behaviors possibly observable on real hardware. From 817adda794b916923534b2733286ee8522430d56 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 30 Apr 2022 11:07:36 -0700 Subject: [PATCH 3294/5092] Add rustfmt::skip to some files Five of the files being skipped here are because rustfmt is buggy (see the error messages below). The others have clearly preferable manual formatting. error[internal]: left behind trailing whitespace --> tests/fail/validity/transmute_through_ptr.rs:18:18:1 | 18 | | ^^^^ | warning: rustfmt has failed to format. See previous 1 errors. error[internal]: left behind trailing whitespace --> tests/fail/stacked_borrows/illegal_read2.rs:10:10:1 | 10 | | ^^^^ | warning: rustfmt has failed to format. See previous 1 errors. error[internal]: left behind trailing whitespace --> tests/fail/stacked_borrows/illegal_read5.rs:15:15:1 | 15 | | ^^^^ | warning: rustfmt has failed to format. See previous 1 errors. error[internal]: left behind trailing whitespace --> tests/fail/stacked_borrows/illegal_read1.rs:10:10:1 | 10 | | ^^^^ | warning: rustfmt has failed to format. See previous 1 errors. error[internal]: left behind trailing whitespace --> tests/fail/erroneous_const2.rs:9:9:1 | 9 | | ^^^^ | warning: rustfmt has failed to format. See previous 1 errors. --- bench-cargo-miri/mse/src/main.rs | 2 ++ tests/fail/erroneous_const2.rs | 1 + tests/fail/stacked_borrows/illegal_read1.rs | 1 + tests/fail/stacked_borrows/illegal_read2.rs | 1 + tests/fail/stacked_borrows/illegal_read5.rs | 1 + tests/fail/validity/transmute_through_ptr.rs | 1 + tests/pass/enums.rs | 1 + 7 files changed, 8 insertions(+) diff --git a/bench-cargo-miri/mse/src/main.rs b/bench-cargo-miri/mse/src/main.rs index b182f6cec65a..bb5fb80e48c1 100644 --- a/bench-cargo-miri/mse/src/main.rs +++ b/bench-cargo-miri/mse/src/main.rs @@ -1,4 +1,6 @@ +#[rustfmt::skip] // no need to wrap these arrays onto hundreds of lines static EXPECTED: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 254, 255, 0, 0, 254, 255, 0, 0, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 255, 255, 1, 0, 255, 255, 1, 0, 0, 0, 1, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 0, 0, 254, 255, 0, 0, 254, 255, 0, 0, 254, 255, 255, 255, 254, 255, 254, 255, 254, 255, 253, 255, 253, 255, 253, 255, 253, 255, 252, 255, 254, 255, 251, 255, 254, 255, 251, 255, 254, 255, 252, 255, 255, 255, 252, 255, 0, 0, 252, 255, 0, 0, 252, 255, 1, 0, 252, 255, 1, 0, 252, 255, 2, 0, 252, 255, 2, 0, 252, 255, 2, 0, 252, 255, 2, 0, 252, 255, 2, 0, 253, 255, 1, 0, 252, 255, 0, 0, 252, 255, 255, 255, 251, 255, 0, 0, 251, 255, 0, 0, 251, 255, 0, 0, 252, 255, 2, 0, 252, 255, 3, 0, 252, 255, 4, 0, 253, 255, 5, 0, 254, 255, 5, 0, 253, 255, 6, 0, 253, 255, 6, 0, 253, 255, 5, 0, 253, 255, 5, 0, 254, 255, 4, 0, 254, 255, 3, 0, 251, 255, 0, 0, 250, 255, 255, 255, 253, 255, 254, 255, 252, 255, 252, 255, 247, 255, 251, 255, 247, 255, 252, 255, 252, 255, 254, 255, 252, 255, 254, 255, 252, 255, 255, 255, 254, 255, 1, 0, 1, 0, 1, 0, 4, 0, 2, 0, 8, 0, 2, 0, 12, 0, 1, 0, 13, 0, 0, 0, 12, 0, 0, 0, 11, 0, 255, 255, 8, 0, 254, 255, 7, 0, 0, 0, 7, 0, 253, 255, 11, 0, 248, 255, 15, 0, 247, 255, 17, 0, 250, 255, 17, 0, 251, 255, 13, 0, 253, 255, 7, 0, 255, 255, 3, 0, 255, 255, 254, 255, 255, 255, 252, 255, 255, 255, 252, 255, 254, 255, 250, 255, 255, 255, 242, 255, 254, 255, 239, 255, 252, 255, 248, 255, 255, 255, 249, 255, 5, 0, 239, 255, 7, 0, 238, 255, 10, 0, 249, 255, 18, 0, 254, 255, 25, 0, 253, 255, 27, 0, 0, 0, 31, 0, 4, 0, 34, 0, 4, 0, 34, 0, 8, 0, 36, 0, 8, 0, 37, 0, 2, 0, 36, 0, 4, 0, 34, 0, 8, 0, 28, 0, 3, 0, 15, 0, 255, 255, 11, 0, 0, 0, 12, 0, 251, 255, 8, 0, 252, 255, 10, 0, 0, 0, 23, 0, 252, 255, 31, 0, 248, 255, 30, 0, 254, 255, 30, 0, 255, 255, 26, 0, 250, 255, 22, 0, 250, 255, 20, 0, 244, 255, 15, 0, 237, 255, 10, 0, 246, 255, 13, 0, 242, 255, 6, 0, 213, 255, 243, 255, 213, 255, 240, 255, 247, 255, 244, 255, 246, 255, 227, 255, 214, 255, 216, 255, 219, 255, 228, 255, 251, 255, 235, 255, 1, 0, 232, 255, 248, 255, 236, 255, 4, 0, 238, 255, 26, 0, 232, 255, 44, 0, 230, 255, 66, 0, 226, 255, 86, 0, 219, 255, 88, 0, 215, 255, 72, 0, 210, 255, 50, 0, 225, 255, 28, 0, 23, 0, 14, 0, 64, 0, 16, 0, 51, 0, 26, 0, 32, 0, 34, 0, 39, 0, 42, 0, 48, 0, 35, 0, 58, 0, 255, 255, 72, 0, 220, 255, 69, 0, 197, 255, 58, 0, 158, 255, 54, 0, 132, 255, 36, 0, 153, 255, 12, 0, 146, 255, 5, 0, 83, 255, 237, 255, 110, 255, 197, 255, 252, 255, 214, 255, 51, 0, 1, 0, 233, 255, 250, 255, 226, 255, 250, 255, 45, 0, 46, 0, 47, 0, 70, 0, 6, 0, 55, 0, 19, 0, 60, 0, 38, 0, 62, 0, 42, 0, 47, 0, 61, 0, 46, 0, 40, 0, 42, 0, 237, 255, 22, 0, 222, 255, 6, 0, 221, 255, 206, 255, 195, 255, 115, 255, 219, 255, 85, 255, 17, 0, 93, 255, 26, 0, 76, 255, 46, 0, 102, 255, 80, 0, 193, 255, 48, 0, 252, 255, 18, 0, 20, 0, 50, 0, 47, 0, 58, 0, 53, 0, 44, 0, 61, 0, 57, 0, 85, 0, 37, 0, 80, 0, 0, 0, 86, 0, 248, 255, 106, 0, 161, 255, 49, 0, 43, 255, 248, 255, 125, 255, 47, 0, 49, 0, 63, 0, 40, 0, 217, 255, 187, 255, 182, 255, 219, 255, 236, 255, 63, 0, 244, 255, 58, 0, 242, 255, 244, 255, 25, 0, 225, 255, 41, 0, 11, 0, 45, 0, 76, 0, 47, 0, 167, 0, 5, 0, 5, 1, 219, 255, 21, 1, 173, 255, 183, 0, 84, 255, 35, 0, 134, 255, 177, 255, 138, 0, 186, 255, 10, 1, 69, 0, 124, 0, 228, 0, 0, 0, 135, 1, 227, 255, 82, 2, 172, 255, 190, 2, 178, 255, 115, 2, 248, 255, 39, 2, 243, 255, 253, 1, 13, 0, 116, 1, 120, 0, 96, 1, 125, 0, 110, 2, 127, 0, 179, 2, 223, 0, 106, 1, 126, 0, 130, 1, 223, 255, 147, 3, 198, 0, 190, 3, 201, 1, 200, 1, 42, 1, 244, 1, 233, 0, 3, 4, 213, 1, 72, 4, 170, 1, 150, 3, 160, 0, 43, 4, 141, 0, 196, 4, 189, 0, 221, 4, 164, 0, 95, 5, 41, 1, 98, 5, 247, 1, 19, 5, 190, 2, 14, 6, 161, 3, 7, 7, 87, 3, 216, 6, 35, 2, 38, 7, 90, 2, 136, 7, 64, 3, 200, 6, 28, 3, 199, 6, 165, 3, 169, 7, 105, 5, 143, 7, 26, 6, 57, 8, 205, 5, 156, 10, 169, 5, 132, 11, 25, 5, 208, 10, 181, 4, 156, 10, 66, 5, 227, 9, 170, 5, 166, 9, 117, 6, 45, 12, 63, 8, 42, 13, 128, 8, 136, 10, 155, 7, 109, 11, 1, 9, 6, 15, 98, 10, 121, 9, 136, 8, 147, 252, 189, 7, 43, 247, 63, 10, 147, 249, 92, 11, 172, 248, 172, 10, 112, 245, 137, 11, 76, 246, 44, 12, 184, 247, 138, 11, 118, 246, 144, 12, 94, 246, 171, 13, 112, 247, 162, 12, 168, 246, 33, 13, 63, 246, 29, 15, 226, 247, 188, 14, 190, 248, 75, 15, 238, 247, 86, 17, 19, 247, 118, 11, 10, 247, 232, 254, 238, 247, 30, 249, 56, 248, 124, 250, 6, 247, 1, 250, 161, 246, 3, 249, 81, 247, 117, 250, 60, 247, 202, 250, 212, 247, 60, 250, 15, 249, 140, 250, 34, 248, 221, 249, 105, 247, 218, 249, 205, 248, 113, 251, 138, 248, 90, 250, 41, 248, 230, 248]; +#[rustfmt::skip] static PCM: &[i16] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1, 0, 1, 0, 0, -2, 0, -2, 0, -2, 0, -2, -2, -2, -3, -3, -3, -3, -4, -2, -5, -2, -5, -2, -4, 0, -4, 0, -4, 0, -4, 1, -4, 1, -4, 2, -4, 2, -4, 2, -4, 2, -4, 2, -3, 1, -4, 0, -4, 0, -5, 0, -5, 0, -5, 0, -4, 2, -4, 3, -4, 4, -3, 5, -2, 5, -3, 6, -3, 6, -3, 5, -3, 5, -2, 4, -2, 3, -5, 0, -6, 0, -3, -2, -4, -4, -9, -5, -9, -4, -4, -2, -4, -2, -4, 0, -2, 1, 1, 1, 4, 2, 8, 2, 12, 1, 13, 0, 12, 0, 11, 0, 8, -2, 7, 0, 7, -3, 11, -8, 15, -9, 17, -6, 17, -5, 13, -3, 7, 0, 3, 0, -2, 0, -4, 0, -4, -2, -6, 0, -14, -2, -17, -4, -8, 0, -7, 5, -17, 7, -18, 10, -7, 18, -2, 25, -3, 27, 0, 31, 4, 34, 4, 34, 8, 36, 8, 37, 2, 36, 4, 34, 8, 28, 3, 15, 0, 11, 0, 12, -5, 8, -4, 10, 0, 23, -4, 31, -8, 30, -2, 30, 0, 26, -6, 22, -6, 20, -12, 15, -19, 10, -10, 13, -14, 6, -43, -13, -43, -16, -9, -12, -10, -29, -42, -40, -37, -28, -5, -21, 1, -24, -8, -20, 4, -18, 26, -24, 44, -26, 66, -30, 86, -37, 88, -41, 72, -46, 50, -31, 28, 23, 14, 64, 16, 51, 26, 32, 34, 39, 42, 48, 35, 58, 0, 72, -36, 69, -59, 58, -98, 54, -124, 36, -103, 12, -110, 5, -173, -19, -146, -59, -4, -42, 51, 1, -23, -6, -30, -6, 45, 46, 47, 70, 6, 55, 19, 60, 38, 62, 42, 47, 61, 46, 40, 42, -19, 22, -34, 6, -35, -50, -61, -141, -37, -171, 17, -163, 26, -180, 46, -154, 80, -63, 48, -4, 18, 20, 50, 47, 58, 53, 44, 61, 57, 85, 37, 80, 0, 86, -8, 106, -95, 49, -213, -8, -131, 47, 49, 63, 40, -39, -69, -74, -37, -20, 63, -12, 58, -14, -12, 25, -31, 41, 11, 45, 76, 47, 167, 5, 261, -37, 277, -83, 183, -172, 35, -122, -79, 138, -70, 266, 69, 124, 228, 0, 391, -29, 594, -84, 702, -78, 627, -8, 551, -13, 509, 13, 372, 120, 352, 125, 622, 127, 691, 223, 362, 126, 386, -33, 915, 198, 958, 457, 456, 298, 500, 233, 1027, 469, 1096, 426, 918, 160, 1067, 141, 1220, 189, 1245, 164, 1375, 297, 1378, 503, 1299, 702, 1550, 929, 1799, 855, 1752, 547, 1830, 602, 1928, 832, 1736, 796, 1735, 933, 1961, 1385, 1935, 1562, 2105, 1485, 2716, 1449, 2948, 1305, 2768, 1205, 2716, 1346, 2531, 1450, 2470, 1653, 3117, 2111, 3370, 2176, 2696, 1947, 2925, 2305, 3846, 2658, 2425, 2184, -877, 1981, -2261, 2623, -1645, 2908, -1876, 2732, -2704, 2953, -2484, 3116, -2120, 2954, -2442, 3216, -2466, 3499, -2192, 3234, -2392, 3361, -2497, 3869, -2078, 3772, -1858, 3915, -2066, 4438, -2285, 2934, -2294, -280, -2066, -1762, -1992, -1412, -2298, -1535, -2399, -1789, -2223, -1419, -2244, -1334, -2092, -1476, -1777, -1396, -2014, -1571, -2199, -1574, -1843, -1167, -1910, -1446, -2007, -1818]; fn main() { diff --git a/tests/fail/erroneous_const2.rs b/tests/fail/erroneous_const2.rs index cdec2ec4f095..dc68cd64d738 100644 --- a/tests/fail/erroneous_const2.rs +++ b/tests/fail/erroneous_const2.rs @@ -4,6 +4,7 @@ const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; //~^ERROR any use of this value //~|WARN previously accepted +#[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/5391 fn main() { println!("{}", FOO); //~ERROR post-monomorphization error //~|ERROR evaluation of constant value failed diff --git a/tests/fail/stacked_borrows/illegal_read1.rs b/tests/fail/stacked_borrows/illegal_read1.rs index d942d2b27b99..b5734964060e 100644 --- a/tests/fail/stacked_borrows/illegal_read1.rs +++ b/tests/fail/stacked_borrows/illegal_read1.rs @@ -1,6 +1,7 @@ // A callee may not read the destination of our `&mut` without // us noticing. +#[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/5391 fn main() { let mut x = 15; let xraw = &mut x as *mut _; diff --git a/tests/fail/stacked_borrows/illegal_read2.rs b/tests/fail/stacked_borrows/illegal_read2.rs index c50c88d48f8c..ed6972c1deb9 100644 --- a/tests/fail/stacked_borrows/illegal_read2.rs +++ b/tests/fail/stacked_borrows/illegal_read2.rs @@ -1,6 +1,7 @@ // A callee may not read the destination of our `&mut` without // us noticing. +#[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/5391 fn main() { let mut x = 15; let xraw = &mut x as *mut _; diff --git a/tests/fail/stacked_borrows/illegal_read5.rs b/tests/fail/stacked_borrows/illegal_read5.rs index 58f506251de2..71af84e5b5f5 100644 --- a/tests/fail/stacked_borrows/illegal_read5.rs +++ b/tests/fail/stacked_borrows/illegal_read5.rs @@ -5,6 +5,7 @@ use std::cell::RefCell; use std::{mem, ptr}; +#[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/5391 fn main() { let rc = RefCell::new(0); let mut refmut = rc.borrow_mut(); diff --git a/tests/fail/validity/transmute_through_ptr.rs b/tests/fail/validity/transmute_through_ptr.rs index cd354eac4aef..b1984429d2de 100644 --- a/tests/fail/validity/transmute_through_ptr.rs +++ b/tests/fail/validity/transmute_through_ptr.rs @@ -7,6 +7,7 @@ fn evil(x: &mut Bool) { unsafe { *x = 44; } // out-of-bounds enum tag } +#[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/5391 fn main() { let mut x = Bool::True; evil(&mut x); diff --git a/tests/pass/enums.rs b/tests/pass/enums.rs index 39bf567076c4..d399beb91b2f 100644 --- a/tests/pass/enums.rs +++ b/tests/pass/enums.rs @@ -64,6 +64,7 @@ fn more_discriminant_overflow() { // from the `bool` field of `V1`), overflowing for variants with large enough // indices (`V3` and `V4`), causing them to be interpreted as other variants. #[allow(dead_code)] + #[rustfmt::skip] // rustfmt prefers every variant on its own line pub enum E2 { V1 { f: bool }, From 66e8751afce516a2ee9fb3324e755f7ad0c42629 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 19 Jun 2022 20:33:59 -0700 Subject: [PATCH 3295/5092] Format tests and benches with rustfmt (1-50 of 300) --- bench-cargo-miri/mse/src/main.rs | 1 - benches/helpers/repeat_manual.rs | 4 +++- test-cargo-miri/cdylib/src/lib.rs | 2 +- test-cargo-miri/issue-1567/src/lib.rs | 2 +- test-cargo-miri/issue-1705/src/lib.rs | 4 ++-- test-cargo-miri/issue-rust-86261/src/lib.rs | 2 +- test-cargo-miri/src/main.rs | 4 ++-- test-cargo-miri/tests/test.rs | 6 +----- tests/fail/abort-terminator.rs | 4 +++- tests/fail/alloc/global_system_mixup.rs | 6 ++++-- tests/fail/concurrency/too_few_args.rs | 3 ++- tests/fail/concurrency/too_many_args.rs | 3 ++- tests/fail/concurrency/unwind_top_of_stack.rs | 6 ++++-- .../fail/dangling_pointers/storage_dead_dangling.rs | 4 +++- tests/fail/data_race/alloc_read_race.rs | 6 +++--- tests/fail/data_race/alloc_write_race.rs | 7 ++++--- tests/fail/data_race/atomic_read_na_write_race1.rs | 4 ++-- tests/fail/data_race/atomic_read_na_write_race2.rs | 2 +- tests/fail/data_race/atomic_write_na_read_race1.rs | 2 +- tests/fail/data_race/atomic_write_na_read_race2.rs | 8 +++----- tests/fail/data_race/atomic_write_na_write_race1.rs | 4 ++-- tests/fail/data_race/atomic_write_na_write_race2.rs | 2 +- tests/fail/data_race/dangling_thread_async_race.rs | 6 ++---- tests/fail/data_race/dangling_thread_race.rs | 7 ++----- tests/fail/data_race/dealloc_read_race2.rs | 6 +++++- tests/fail/data_race/dealloc_read_race_stack.rs | 5 ++--- tests/fail/data_race/dealloc_write_race2.rs | 6 +++++- tests/fail/data_race/dealloc_write_race_stack.rs | 5 ++--- tests/fail/data_race/fence_after_load.rs | 4 ++-- tests/fail/data_race/read_write_race.rs | 4 +--- tests/fail/data_race/read_write_race_stack.rs | 4 ++-- tests/fail/data_race/relax_acquire_race.rs | 2 +- tests/fail/data_race/release_seq_race.rs | 2 +- tests/fail/data_race/release_seq_race_same_thread.rs | 2 +- tests/fail/data_race/rmw_race.rs | 2 +- tests/fail/data_race/write_write_race_stack.rs | 4 ++-- tests/fail/environ-gets-deallocated.rs | 12 ++++++------ .../fail/function_pointers/cast_box_int_to_fn_ptr.rs | 4 +--- tests/fail/function_pointers/cast_fn_ptr1.rs | 4 +--- tests/fail/function_pointers/cast_fn_ptr2.rs | 6 ++---- tests/fail/function_pointers/cast_fn_ptr3.rs | 7 ++----- tests/fail/function_pointers/cast_fn_ptr4.rs | 6 ++---- tests/fail/function_pointers/cast_fn_ptr5.rs | 8 ++++---- tests/fail/function_pointers/cast_int_to_fn_ptr.rs | 4 +--- tests/fail/function_pointers/fn_ptr_offset.rs | 6 +++--- tests/fail/intrinsics/simd-div-by-zero.rs | 12 +++++++----- tests/fail/intrinsics/simd-div-overflow.rs | 12 +++++++----- tests/fail/intrinsics/simd-float-to-int.rs | 8 +++++--- tests/fail/intrinsics/simd-gather.rs | 12 +++++++----- tests/fail/intrinsics/simd-reduce-invalid-bool.rs | 10 ++++++---- 50 files changed, 129 insertions(+), 127 deletions(-) diff --git a/bench-cargo-miri/mse/src/main.rs b/bench-cargo-miri/mse/src/main.rs index bb5fb80e48c1..c09dc2484d38 100644 --- a/bench-cargo-miri/mse/src/main.rs +++ b/bench-cargo-miri/mse/src/main.rs @@ -30,4 +30,3 @@ fn mse(samples: usize, frame_buf: &[i16], buf_ref: &[u8]) -> f64 { } mse / max_samples as f64 } - diff --git a/benches/helpers/repeat_manual.rs b/benches/helpers/repeat_manual.rs index 6ef6f724efce..bd5d6b1e1264 100644 --- a/benches/helpers/repeat_manual.rs +++ b/benches/helpers/repeat_manual.rs @@ -1,7 +1,9 @@ fn main() { let mut data: [u8; 1024] = unsafe { std::mem::uninitialized() }; for i in 0..data.len() { - unsafe { std::ptr::write(&mut data[i], 0); } + unsafe { + std::ptr::write(&mut data[i], 0); + } } assert_eq!(data.len(), 1024); } diff --git a/test-cargo-miri/cdylib/src/lib.rs b/test-cargo-miri/cdylib/src/lib.rs index dd89048284de..e47e588251e4 100644 --- a/test-cargo-miri/cdylib/src/lib.rs +++ b/test-cargo-miri/cdylib/src/lib.rs @@ -2,5 +2,5 @@ use byteorder::{BigEndian, ByteOrder}; #[no_mangle] extern "C" fn use_the_dependency() { - let _n = ::read_u64(&[1,2,3,4,5,6,7,8]); + let _n = ::read_u64(&[1, 2, 3, 4, 5, 6, 7, 8]); } diff --git a/test-cargo-miri/issue-1567/src/lib.rs b/test-cargo-miri/issue-1567/src/lib.rs index 568617c3ba3c..547921683238 100644 --- a/test-cargo-miri/issue-1567/src/lib.rs +++ b/test-cargo-miri/issue-1567/src/lib.rs @@ -1,5 +1,5 @@ use byteorder::{BigEndian, ByteOrder}; pub fn use_the_dependency() { - let _n = ::read_u32(&[1,2,3,4]); + let _n = ::read_u32(&[1, 2, 3, 4]); } diff --git a/test-cargo-miri/issue-1705/src/lib.rs b/test-cargo-miri/issue-1705/src/lib.rs index ef24d3f1a06d..64633490f84b 100644 --- a/test-cargo-miri/issue-1705/src/lib.rs +++ b/test-cargo-miri/issue-1705/src/lib.rs @@ -1,5 +1,5 @@ -use byteorder::{LittleEndian, ByteOrder}; +use byteorder::{ByteOrder, LittleEndian}; pub fn use_the_dependency() { - let _n = ::read_u32(&[1,2,3,4]); + let _n = ::read_u32(&[1, 2, 3, 4]); } diff --git a/test-cargo-miri/issue-rust-86261/src/lib.rs b/test-cargo-miri/issue-rust-86261/src/lib.rs index db725fdb64ed..1947c38b7745 100644 --- a/test-cargo-miri/issue-rust-86261/src/lib.rs +++ b/test-cargo-miri/issue-rust-86261/src/lib.rs @@ -3,7 +3,7 @@ // Regression test for https://github.com/rust-lang/rust/issues/86261: // `#[no_mangle]` on a `use` item. #[no_mangle] -use std::{thread,panic, io, boxed, any, string}; +use std::{any, boxed, io, panic, string, thread}; // `#[no_mangle]` on a struct has a similar problem. #[no_mangle] diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index cb1512d05020..5807d0765fb3 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -8,7 +8,7 @@ fn main() { assert_eq!(env!("MIRITESTVAR"), "testval"); // Exercise external crate, printing to stdout. - let buf = &[1,2,3,4]; + let buf = &[1, 2, 3, 4]; let n = ::read_u32(buf); assert_eq!(n, 0x01020304); println!("{:#010x}", n); @@ -32,7 +32,7 @@ fn main() { #[cfg(unix)] for line in io::stdin().lock().lines() { let num: i32 = line.unwrap().parse().unwrap(); - println!("{}", 2*num); + println!("{}", 2 * num); } // On non-Unix, reading from stdin is not supported. So we hard-code the right answer. #[cfg(not(unix))] diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 545c79db2760..8a938ef3c25f 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -67,9 +67,5 @@ fn page_size() { let page_size = page_size::get(); // In particular, this checks that it is not 0. - assert!( - page_size.is_power_of_two(), - "page size not a power of two: {}", - page_size - ); + assert!(page_size.is_power_of_two(), "page size not a power of two: {}", page_size); } diff --git a/tests/fail/abort-terminator.rs b/tests/fail/abort-terminator.rs index 8e6e2a766007..20859047c620 100644 --- a/tests/fail/abort-terminator.rs +++ b/tests/fail/abort-terminator.rs @@ -1,7 +1,9 @@ // error-pattern: the program aborted #![feature(c_unwind)] -extern "C" fn panic_abort() { panic!() } +extern "C" fn panic_abort() { + panic!() +} fn main() { panic_abort(); diff --git a/tests/fail/alloc/global_system_mixup.rs b/tests/fail/alloc/global_system_mixup.rs index bb87b132f322..735c52500af6 100644 --- a/tests/fail/alloc/global_system_mixup.rs +++ b/tests/fail/alloc/global_system_mixup.rs @@ -8,10 +8,12 @@ #![feature(allocator_api, slice_ptr_get)] -use std::alloc::{Allocator, Global, System, Layout}; +use std::alloc::{Allocator, Global, Layout, System}; fn main() { let l = Layout::from_size_align(1, 1).unwrap(); let ptr = Global.allocate(l).unwrap().as_non_null_ptr(); - unsafe { System.deallocate(ptr, l); } + unsafe { + System.deallocate(ptr, l); + } } diff --git a/tests/fail/concurrency/too_few_args.rs b/tests/fail/concurrency/too_few_args.rs index e2dfa33af898..35412353ace4 100644 --- a/tests/fail/concurrency/too_few_args.rs +++ b/tests/fail/concurrency/too_few_args.rs @@ -19,7 +19,8 @@ fn main() { let attr: libc::pthread_attr_t = mem::zeroed(); // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented. let thread_start: extern "C" fn() -> *mut libc::c_void = thread_start; - let thread_start: extern "C" fn(*mut libc::c_void) -> *mut libc::c_void = mem::transmute(thread_start); + let thread_start: extern "C" fn(*mut libc::c_void) -> *mut libc::c_void = + mem::transmute(thread_start); assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0); assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); } diff --git a/tests/fail/concurrency/too_many_args.rs b/tests/fail/concurrency/too_many_args.rs index 0ef12b07073f..b6156091b0aa 100644 --- a/tests/fail/concurrency/too_many_args.rs +++ b/tests/fail/concurrency/too_many_args.rs @@ -19,7 +19,8 @@ fn main() { let attr: libc::pthread_attr_t = mem::zeroed(); // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented. let thread_start: extern "C" fn(*mut libc::c_void, i32) -> *mut libc::c_void = thread_start; - let thread_start: extern "C" fn(*mut libc::c_void) -> *mut libc::c_void = mem::transmute(thread_start); + let thread_start: extern "C" fn(*mut libc::c_void) -> *mut libc::c_void = + mem::transmute(thread_start); assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0); assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); } diff --git a/tests/fail/concurrency/unwind_top_of_stack.rs b/tests/fail/concurrency/unwind_top_of_stack.rs index 138a43d9d731..e1c17d07b286 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.rs +++ b/tests/fail/concurrency/unwind_top_of_stack.rs @@ -20,8 +20,10 @@ fn main() { let attr: libc::pthread_attr_t = mem::zeroed(); // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented. // Cast to avoid inserting abort-on-unwind. - let thread_start: extern "C-unwind" fn(*mut libc::c_void) -> *mut libc::c_void = thread_start; - let thread_start: extern "C" fn(*mut libc::c_void) -> *mut libc::c_void = mem::transmute(thread_start); + let thread_start: extern "C-unwind" fn(*mut libc::c_void) -> *mut libc::c_void = + thread_start; + let thread_start: extern "C" fn(*mut libc::c_void) -> *mut libc::c_void = + mem::transmute(thread_start); assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0); assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); } diff --git a/tests/fail/dangling_pointers/storage_dead_dangling.rs b/tests/fail/dangling_pointers/storage_dead_dangling.rs index 4d91498eac16..c87db4b0225a 100644 --- a/tests/fail/dangling_pointers/storage_dead_dangling.rs +++ b/tests/fail/dangling_pointers/storage_dead_dangling.rs @@ -4,7 +4,9 @@ static mut LEAK: usize = 0; fn fill(v: &mut i32) { - unsafe { LEAK = v as *mut _ as usize; } + unsafe { + LEAK = v as *mut _ as usize; + } } fn evil() { diff --git a/tests/fail/data_race/alloc_read_race.rs b/tests/fail/data_race/alloc_read_race.rs index 4adb7071f294..12c1b6ec876a 100644 --- a/tests/fail/data_race/alloc_read_race.rs +++ b/tests/fail/data_race/alloc_read_race.rs @@ -2,10 +2,10 @@ // compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 #![feature(new_uninit)] -use std::thread::spawn; -use std::ptr::null_mut; -use std::sync::atomic::{Ordering, AtomicPtr}; use std::mem::MaybeUninit; +use std::ptr::null_mut; +use std::sync::atomic::{AtomicPtr, Ordering}; +use std::thread::spawn; #[derive(Copy, Clone)] struct EvilSend(pub T); diff --git a/tests/fail/data_race/alloc_write_race.rs b/tests/fail/data_race/alloc_write_race.rs index e4a1192f95b3..c050d24bee10 100644 --- a/tests/fail/data_race/alloc_write_race.rs +++ b/tests/fail/data_race/alloc_write_race.rs @@ -2,9 +2,9 @@ // compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 #![feature(new_uninit)] -use std::thread::spawn; use std::ptr::null_mut; -use std::sync::atomic::{Ordering, AtomicPtr}; +use std::sync::atomic::{AtomicPtr, Ordering}; +use std::thread::spawn; #[derive(Copy, Clone)] struct EvilSend(pub T); @@ -30,7 +30,8 @@ pub fn main() { // Uses relaxed semantics to not generate // a release sequence. let pointer = &*ptr.0; - pointer.store(Box::into_raw(Box::::new_uninit()) as *mut usize, Ordering::Relaxed); + pointer + .store(Box::into_raw(Box::::new_uninit()) as *mut usize, Ordering::Relaxed); }); let j2 = spawn(move || { diff --git a/tests/fail/data_race/atomic_read_na_write_race1.rs b/tests/fail/data_race/atomic_read_na_write_race1.rs index 44860ee62800..5131e33fef86 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.rs +++ b/tests/fail/data_race/atomic_read_na_write_race1.rs @@ -1,9 +1,9 @@ // ignore-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] -use std::thread::spawn; -use std::sync::atomic::AtomicUsize; use std::intrinsics::atomic_load; +use std::sync::atomic::AtomicUsize; +use std::thread::spawn; #[derive(Copy, Clone)] struct EvilSend(pub T); diff --git a/tests/fail/data_race/atomic_read_na_write_race2.rs b/tests/fail/data_race/atomic_read_na_write_race2.rs index 6d28e18886cd..1c0146367ad5 100644 --- a/tests/fail/data_race/atomic_read_na_write_race2.rs +++ b/tests/fail/data_race/atomic_read_na_write_race2.rs @@ -1,8 +1,8 @@ // ignore-windows: Concurrency on Windows is not supported yet. -use std::thread::spawn; use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; +use std::thread::spawn; #[derive(Copy, Clone)] struct EvilSend(pub T); diff --git a/tests/fail/data_race/atomic_write_na_read_race1.rs b/tests/fail/data_race/atomic_write_na_read_race1.rs index 0b753f6710a5..a63aafb0453c 100644 --- a/tests/fail/data_race/atomic_write_na_read_race1.rs +++ b/tests/fail/data_race/atomic_write_na_read_race1.rs @@ -1,8 +1,8 @@ // ignore-windows: Concurrency on Windows is not supported yet. -use std::thread::spawn; use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; +use std::thread::spawn; #[derive(Copy, Clone)] struct EvilSend(pub T); diff --git a/tests/fail/data_race/atomic_write_na_read_race2.rs b/tests/fail/data_race/atomic_write_na_read_race2.rs index a9f5fb2fe5bc..359970dfff8f 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.rs +++ b/tests/fail/data_race/atomic_write_na_read_race2.rs @@ -1,9 +1,9 @@ // ignore-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] -use std::thread::spawn; -use std::sync::atomic::AtomicUsize; use std::intrinsics::atomic_store; +use std::sync::atomic::AtomicUsize; +use std::thread::spawn; #[derive(Copy, Clone)] struct EvilSend(pub T); @@ -16,9 +16,7 @@ pub fn main() { let b = &mut a as *mut AtomicUsize; let c = EvilSend(b); unsafe { - let j1 = spawn(move || { - *(c.0 as *mut usize) - }); + let j1 = spawn(move || *(c.0 as *mut usize)); let j2 = spawn(move || { //Equivalent to: (&*c.0).store(32, Ordering::SeqCst) diff --git a/tests/fail/data_race/atomic_write_na_write_race1.rs b/tests/fail/data_race/atomic_write_na_write_race1.rs index d5a828fa6e41..8268924e3c1a 100644 --- a/tests/fail/data_race/atomic_write_na_write_race1.rs +++ b/tests/fail/data_race/atomic_write_na_write_race1.rs @@ -1,9 +1,9 @@ // ignore-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] -use std::thread::spawn; -use std::sync::atomic::AtomicUsize; use std::intrinsics::atomic_store; +use std::sync::atomic::AtomicUsize; +use std::thread::spawn; #[derive(Copy, Clone)] struct EvilSend(pub T); diff --git a/tests/fail/data_race/atomic_write_na_write_race2.rs b/tests/fail/data_race/atomic_write_na_write_race2.rs index 9812dcd79920..440c72a059d8 100644 --- a/tests/fail/data_race/atomic_write_na_write_race2.rs +++ b/tests/fail/data_race/atomic_write_na_write_race2.rs @@ -1,8 +1,8 @@ // ignore-windows: Concurrency on Windows is not supported yet. -use std::thread::spawn; use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; +use std::thread::spawn; #[derive(Copy, Clone)] struct EvilSend(pub T); diff --git a/tests/fail/data_race/dangling_thread_async_race.rs b/tests/fail/data_race/dangling_thread_async_race.rs index 6aa5a469be3b..2656f4b7af14 100644 --- a/tests/fail/data_race/dangling_thread_async_race.rs +++ b/tests/fail/data_race/dangling_thread_async_race.rs @@ -1,10 +1,9 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-disable-isolation -use std::thread::{spawn, sleep}; -use std::time::Duration; use std::mem; - +use std::thread::{sleep, spawn}; +use std::time::Duration; #[derive(Copy, Clone)] struct EvilSend(pub T); @@ -12,7 +11,6 @@ struct EvilSend(pub T); unsafe impl Send for EvilSend {} unsafe impl Sync for EvilSend {} - fn main() { let mut a = 0u32; let b = &mut a as *mut u32; diff --git a/tests/fail/data_race/dangling_thread_race.rs b/tests/fail/data_race/dangling_thread_race.rs index 755ba8efdae9..f1174d8ff6ee 100644 --- a/tests/fail/data_race/dangling_thread_race.rs +++ b/tests/fail/data_race/dangling_thread_race.rs @@ -1,10 +1,9 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-disable-isolation -use std::thread::{spawn, sleep}; -use std::time::Duration; use std::mem; - +use std::thread::{sleep, spawn}; +use std::time::Duration; #[derive(Copy, Clone)] struct EvilSend(pub T); @@ -12,7 +11,6 @@ struct EvilSend(pub T); unsafe impl Send for EvilSend {} unsafe impl Sync for EvilSend {} - fn main() { let mut a = 0u32; let b = &mut a as *mut u32; @@ -34,7 +32,6 @@ fn main() { // remains enabled nevertheless. spawn(|| ()).join().unwrap(); - unsafe { *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) } diff --git a/tests/fail/data_race/dealloc_read_race2.rs b/tests/fail/data_race/dealloc_read_race2.rs index 9f9dbfc77ed5..984268dca149 100644 --- a/tests/fail/data_race/dealloc_read_race2.rs +++ b/tests/fail/data_race/dealloc_read_race2.rs @@ -19,7 +19,11 @@ pub fn main() { unsafe { let j1 = spawn(move || { - __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()) + __rust_dealloc( + ptr.0 as *mut _, + std::mem::size_of::(), + std::mem::align_of::(), + ) }); let j2 = spawn(move || { diff --git a/tests/fail/data_race/dealloc_read_race_stack.rs b/tests/fail/data_race/dealloc_read_race_stack.rs index f458d1126efe..cdb6c182307f 100644 --- a/tests/fail/data_race/dealloc_read_race_stack.rs +++ b/tests/fail/data_race/dealloc_read_race_stack.rs @@ -1,9 +1,9 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -use std::thread::{spawn, sleep}; use std::ptr::null_mut; -use std::sync::atomic::{Ordering, AtomicPtr}; +use std::sync::atomic::{AtomicPtr, Ordering}; +use std::thread::{sleep, spawn}; use std::time::Duration; #[derive(Copy, Clone)] @@ -36,7 +36,6 @@ pub fn main() { sleep(Duration::from_millis(200)); // Now `stack_var` gets deallocated. - } //~ ERROR Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2) }); diff --git a/tests/fail/data_race/dealloc_write_race2.rs b/tests/fail/data_race/dealloc_write_race2.rs index 20c05fa8f17b..2f4b9a194c05 100644 --- a/tests/fail/data_race/dealloc_write_race2.rs +++ b/tests/fail/data_race/dealloc_write_race2.rs @@ -18,7 +18,11 @@ pub fn main() { unsafe { let j1 = spawn(move || { - __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()); + __rust_dealloc( + ptr.0 as *mut _, + std::mem::size_of::(), + std::mem::align_of::(), + ); }); let j2 = spawn(move || { diff --git a/tests/fail/data_race/dealloc_write_race_stack.rs b/tests/fail/data_race/dealloc_write_race_stack.rs index d1fe8c3e9a16..a209a2cd7dbf 100644 --- a/tests/fail/data_race/dealloc_write_race_stack.rs +++ b/tests/fail/data_race/dealloc_write_race_stack.rs @@ -1,9 +1,9 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -use std::thread::{spawn, sleep}; use std::ptr::null_mut; -use std::sync::atomic::{Ordering, AtomicPtr}; +use std::sync::atomic::{AtomicPtr, Ordering}; +use std::thread::{sleep, spawn}; use std::time::Duration; #[derive(Copy, Clone)] @@ -36,7 +36,6 @@ pub fn main() { sleep(Duration::from_millis(200)); // Now `stack_var` gets deallocated. - } //~ ERROR Data race detected between Deallocate on Thread(id = 1) and Write on Thread(id = 2) }); diff --git a/tests/fail/data_race/fence_after_load.rs b/tests/fail/data_race/fence_after_load.rs index 20cc691f88e1..c209ef181253 100644 --- a/tests/fail/data_race/fence_after_load.rs +++ b/tests/fail/data_race/fence_after_load.rs @@ -1,10 +1,10 @@ // We want to control preemption here. // compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 // ignore-windows: Concurrency on Windows is not supported yet. +use std::sync::atomic::{fence, AtomicUsize, Ordering}; use std::sync::Arc; -use std::sync::atomic::{AtomicUsize, Ordering, fence}; -use std::time::Duration; use std::thread; +use std::time::Duration; fn main() { static mut V: u32 = 0; diff --git a/tests/fail/data_race/read_write_race.rs b/tests/fail/data_race/read_write_race.rs index 0df66d66ad07..976ace6e4b6f 100644 --- a/tests/fail/data_race/read_write_race.rs +++ b/tests/fail/data_race/read_write_race.rs @@ -13,9 +13,7 @@ pub fn main() { let b = &mut a as *mut u32; let c = EvilSend(b); unsafe { - let j1 = spawn(move || { - *c.0 - }); + let j1 = spawn(move || *c.0); let j2 = spawn(move || { *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 2) and Read on Thread(id = 1) diff --git a/tests/fail/data_race/read_write_race_stack.rs b/tests/fail/data_race/read_write_race_stack.rs index f5c4768296b0..00c36176a9f1 100644 --- a/tests/fail/data_race/read_write_race_stack.rs +++ b/tests/fail/data_race/read_write_race_stack.rs @@ -4,9 +4,9 @@ // Note: mir-opt-level set to 0 to prevent the read of stack_var in thread 1 // from being optimized away and preventing the detection of the data-race. -use std::thread::{spawn, sleep}; use std::ptr::null_mut; -use std::sync::atomic::{Ordering, AtomicPtr}; +use std::sync::atomic::{AtomicPtr, Ordering}; +use std::thread::{sleep, spawn}; use std::time::Duration; #[derive(Copy, Clone)] diff --git a/tests/fail/data_race/relax_acquire_race.rs b/tests/fail/data_race/relax_acquire_race.rs index 64c0f95fa4ba..3b350f5c89f2 100644 --- a/tests/fail/data_race/relax_acquire_race.rs +++ b/tests/fail/data_race/relax_acquire_race.rs @@ -1,8 +1,8 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -use std::thread::spawn; use std::sync::atomic::{AtomicUsize, Ordering}; +use std::thread::spawn; #[derive(Copy, Clone)] struct EvilSend(pub T); diff --git a/tests/fail/data_race/release_seq_race.rs b/tests/fail/data_race/release_seq_race.rs index 964d1b4937b8..ec03888c76b1 100644 --- a/tests/fail/data_race/release_seq_race.rs +++ b/tests/fail/data_race/release_seq_race.rs @@ -1,8 +1,8 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -use std::thread::{spawn, sleep}; use std::sync::atomic::{AtomicUsize, Ordering}; +use std::thread::{sleep, spawn}; use std::time::Duration; #[derive(Copy, Clone)] diff --git a/tests/fail/data_race/release_seq_race_same_thread.rs b/tests/fail/data_race/release_seq_race_same_thread.rs index 01d45a1b7ccf..187623828947 100644 --- a/tests/fail/data_race/release_seq_race_same_thread.rs +++ b/tests/fail/data_race/release_seq_race_same_thread.rs @@ -1,8 +1,8 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -use std::thread::spawn; use std::sync::atomic::{AtomicUsize, Ordering}; +use std::thread::spawn; #[derive(Copy, Clone)] struct EvilSend(pub T); diff --git a/tests/fail/data_race/rmw_race.rs b/tests/fail/data_race/rmw_race.rs index fab6fabe5b6f..51577b3b7b19 100644 --- a/tests/fail/data_race/rmw_race.rs +++ b/tests/fail/data_race/rmw_race.rs @@ -1,8 +1,8 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -use std::thread::spawn; use std::sync::atomic::{AtomicUsize, Ordering}; +use std::thread::spawn; #[derive(Copy, Clone)] struct EvilSend(pub T); diff --git a/tests/fail/data_race/write_write_race_stack.rs b/tests/fail/data_race/write_write_race_stack.rs index e6ae207d8610..49de5db43b72 100644 --- a/tests/fail/data_race/write_write_race_stack.rs +++ b/tests/fail/data_race/write_write_race_stack.rs @@ -1,9 +1,9 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -use std::thread::{spawn, sleep}; use std::ptr::null_mut; -use std::sync::atomic::{Ordering, AtomicPtr}; +use std::sync::atomic::{AtomicPtr, Ordering}; +use std::thread::{sleep, spawn}; use std::time::Duration; #[derive(Copy, Clone)] diff --git a/tests/fail/environ-gets-deallocated.rs b/tests/fail/environ-gets-deallocated.rs index b5a4441d2f9b..4df9be2bf24d 100644 --- a/tests/fail/environ-gets-deallocated.rs +++ b/tests/fail/environ-gets-deallocated.rs @@ -1,14 +1,14 @@ // ignore-windows: Windows does not have a global environ list that the program can access directly -#[cfg(target_os="linux")] +#[cfg(target_os = "linux")] fn get_environ() -> *const *const u8 { - extern "C" { - static mut environ: *const *const u8; - } - unsafe { environ } + extern "C" { + static mut environ: *const *const u8; + } + unsafe { environ } } -#[cfg(target_os="macos")] +#[cfg(target_os = "macos")] fn get_environ() -> *const *const u8 { extern "C" { fn _NSGetEnviron() -> *mut *const *const u8; diff --git a/tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs b/tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs index 9eea9d92dcd7..f7640cadcbcf 100644 --- a/tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs +++ b/tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs @@ -3,9 +3,7 @@ fn main() { let b = Box::new(42); - let g = unsafe { - std::mem::transmute::<&Box, &fn(i32)>(&b) - }; + let g = unsafe { std::mem::transmute::<&Box, &fn(i32)>(&b) }; (*g)(42) //~ ERROR it does not point to a function } diff --git a/tests/fail/function_pointers/cast_fn_ptr1.rs b/tests/fail/function_pointers/cast_fn_ptr1.rs index 3702ec8c94c4..e4463210dda9 100644 --- a/tests/fail/function_pointers/cast_fn_ptr1.rs +++ b/tests/fail/function_pointers/cast_fn_ptr1.rs @@ -1,9 +1,7 @@ fn main() { fn f() {} - let g = unsafe { - std::mem::transmute::(f) - }; + let g = unsafe { std::mem::transmute::(f) }; g(42) //~ ERROR calling a function with more arguments than it expected } diff --git a/tests/fail/function_pointers/cast_fn_ptr2.rs b/tests/fail/function_pointers/cast_fn_ptr2.rs index 39f0867489ad..5d3222548a7d 100644 --- a/tests/fail/function_pointers/cast_fn_ptr2.rs +++ b/tests/fail/function_pointers/cast_fn_ptr2.rs @@ -1,9 +1,7 @@ fn main() { - fn f(_ : (i32,i32)) {} + fn f(_: (i32, i32)) {} - let g = unsafe { - std::mem::transmute::(f) - }; + let g = unsafe { std::mem::transmute::(f) }; g(42) //~ ERROR calling a function with argument of type (i32, i32) passing data of type i32 } diff --git a/tests/fail/function_pointers/cast_fn_ptr3.rs b/tests/fail/function_pointers/cast_fn_ptr3.rs index 3523db24fa32..943175c34702 100644 --- a/tests/fail/function_pointers/cast_fn_ptr3.rs +++ b/tests/fail/function_pointers/cast_fn_ptr3.rs @@ -1,10 +1,7 @@ fn main() { - fn f(_ : (i32,i32)) {} + fn f(_: (i32, i32)) {} - let g = unsafe { - std::mem::transmute::(f) - }; + let g = unsafe { std::mem::transmute::(f) }; g() //~ ERROR calling a function with fewer arguments than it requires } - diff --git a/tests/fail/function_pointers/cast_fn_ptr4.rs b/tests/fail/function_pointers/cast_fn_ptr4.rs index 22a36a71cef1..238b09b162d2 100644 --- a/tests/fail/function_pointers/cast_fn_ptr4.rs +++ b/tests/fail/function_pointers/cast_fn_ptr4.rs @@ -1,9 +1,7 @@ fn main() { - fn f(_ : *const [i32]) {} + fn f(_: *const [i32]) {} - let g = unsafe { - std::mem::transmute::(f) - }; + let g = unsafe { std::mem::transmute::(f) }; g(&42 as *const i32) //~ ERROR calling a function with argument of type *const [i32] passing data of type *const i32 } diff --git a/tests/fail/function_pointers/cast_fn_ptr5.rs b/tests/fail/function_pointers/cast_fn_ptr5.rs index fb2b4403363e..effbd6db1884 100644 --- a/tests/fail/function_pointers/cast_fn_ptr5.rs +++ b/tests/fail/function_pointers/cast_fn_ptr5.rs @@ -1,9 +1,9 @@ fn main() { - fn f() -> u32 { 42 } + fn f() -> u32 { + 42 + } - let g = unsafe { - std::mem::transmute:: u32, fn()>(f) - }; + let g = unsafe { std::mem::transmute:: u32, fn()>(f) }; g() //~ ERROR calling a function with return type u32 passing return place of type () } diff --git a/tests/fail/function_pointers/cast_int_to_fn_ptr.rs b/tests/fail/function_pointers/cast_int_to_fn_ptr.rs index b206cb9ab360..0adbda50bfe5 100644 --- a/tests/fail/function_pointers/cast_int_to_fn_ptr.rs +++ b/tests/fail/function_pointers/cast_int_to_fn_ptr.rs @@ -2,9 +2,7 @@ // compile-flags: -Zmiri-disable-validation fn main() { - let g = unsafe { - std::mem::transmute::(42) - }; + let g = unsafe { std::mem::transmute::(42) }; g(42) //~ ERROR not a valid pointer } diff --git a/tests/fail/function_pointers/fn_ptr_offset.rs b/tests/fail/function_pointers/fn_ptr_offset.rs index 7e509d53c261..04c54c015922 100644 --- a/tests/fail/function_pointers/fn_ptr_offset.rs +++ b/tests/fail/function_pointers/fn_ptr_offset.rs @@ -6,9 +6,9 @@ use std::mem; fn f() {} fn main() { - let x : fn() = f; - let y : *mut u8 = unsafe { mem::transmute(x) }; + let x: fn() = f; + let y: *mut u8 = unsafe { mem::transmute(x) }; let y = y.wrapping_offset(1); - let x : fn() = unsafe { mem::transmute(y) }; + let x: fn() = unsafe { mem::transmute(y) }; x(); //~ ERROR function pointer but it does not point to a function } diff --git a/tests/fail/intrinsics/simd-div-by-zero.rs b/tests/fail/intrinsics/simd-div-by-zero.rs index 4244e63d23e5..6fdcb875acc1 100644 --- a/tests/fail/intrinsics/simd-div-by-zero.rs +++ b/tests/fail/intrinsics/simd-div-by-zero.rs @@ -8,8 +8,10 @@ extern "platform-intrinsic" { #[allow(non_camel_case_types)] struct i32x2(i32, i32); -fn main() { unsafe { - let x = i32x2(1, 1); - let y = i32x2(1, 0); - simd_div(x, y); //~ERROR Undefined Behavior: dividing by zero -} } +fn main() { + unsafe { + let x = i32x2(1, 1); + let y = i32x2(1, 0); + simd_div(x, y); //~ERROR Undefined Behavior: dividing by zero + } +} diff --git a/tests/fail/intrinsics/simd-div-overflow.rs b/tests/fail/intrinsics/simd-div-overflow.rs index 277b9e807baa..6d52a72e4c6e 100644 --- a/tests/fail/intrinsics/simd-div-overflow.rs +++ b/tests/fail/intrinsics/simd-div-overflow.rs @@ -8,8 +8,10 @@ extern "platform-intrinsic" { #[allow(non_camel_case_types)] struct i32x2(i32, i32); -fn main() { unsafe { - let x = i32x2(1, i32::MIN); - let y = i32x2(1, -1); - simd_div(x, y); //~ERROR Undefined Behavior: overflow in signed division -} } +fn main() { + unsafe { + let x = i32x2(1, i32::MIN); + let y = i32x2(1, -1); + simd_div(x, y); //~ERROR Undefined Behavior: overflow in signed division + } +} diff --git a/tests/fail/intrinsics/simd-float-to-int.rs b/tests/fail/intrinsics/simd-float-to-int.rs index 88d5a7a466f0..bb9adf07c9e9 100644 --- a/tests/fail/intrinsics/simd-float-to-int.rs +++ b/tests/fail/intrinsics/simd-float-to-int.rs @@ -2,6 +2,8 @@ #![feature(portable_simd)] use std::simd::*; -fn main() { unsafe { - let _x : i32x2 = f32x2::from_array([f32::MAX, f32::MIN]).to_int_unchecked(); -} } +fn main() { + unsafe { + let _x: i32x2 = f32x2::from_array([f32::MAX, f32::MIN]).to_int_unchecked(); + } +} diff --git a/tests/fail/intrinsics/simd-gather.rs b/tests/fail/intrinsics/simd-gather.rs index ae6f048226dd..ab9cb56ed0bd 100644 --- a/tests/fail/intrinsics/simd-gather.rs +++ b/tests/fail/intrinsics/simd-gather.rs @@ -2,8 +2,10 @@ #![feature(portable_simd)] use std::simd::*; -fn main() { unsafe { - let vec: &[i8] = &[10, 11, 12, 13, 14, 15, 16, 17, 18]; - let idxs = Simd::from_array([9, 3, 0, 17]); - let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true), idxs, Simd::splat(0)); -} } +fn main() { + unsafe { + let vec: &[i8] = &[10, 11, 12, 13, 14, 15, 16, 17, 18]; + let idxs = Simd::from_array([9, 3, 0, 17]); + let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true), idxs, Simd::splat(0)); + } +} diff --git a/tests/fail/intrinsics/simd-reduce-invalid-bool.rs b/tests/fail/intrinsics/simd-reduce-invalid-bool.rs index 41dd7d74f4ec..c697fd526f86 100644 --- a/tests/fail/intrinsics/simd-reduce-invalid-bool.rs +++ b/tests/fail/intrinsics/simd-reduce-invalid-bool.rs @@ -8,7 +8,9 @@ extern "platform-intrinsic" { #[allow(non_camel_case_types)] struct i32x2(i32, i32); -fn main() { unsafe { - let x = i32x2(0, 1); - simd_reduce_any(x); //~ERROR must be all-0-bits or all-1-bits -} } +fn main() { + unsafe { + let x = i32x2(0, 1); + simd_reduce_any(x); //~ERROR must be all-0-bits or all-1-bits + } +} From ee132c8d07b2de26e2d078c39980a93045759920 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 19 Jun 2022 20:43:35 -0700 Subject: [PATCH 3296/5092] Bless stderr files after rustfmt --- tests/fail/abort-terminator.stderr | 6 ++++-- tests/fail/alloc/global_system_mixup.stderr | 2 +- tests/fail/intrinsics/simd-div-by-zero.stderr | 4 ++-- tests/fail/intrinsics/simd-div-overflow.stderr | 4 ++-- tests/fail/intrinsics/simd-float-to-int.stderr | 4 ++-- tests/fail/intrinsics/simd-gather.stderr | 4 ++-- tests/fail/intrinsics/simd-reduce-invalid-bool.stderr | 4 ++-- 7 files changed, 15 insertions(+), 13 deletions(-) diff --git a/tests/fail/abort-terminator.stderr b/tests/fail/abort-terminator.stderr index 76501ca074fd..b096775e61d3 100644 --- a/tests/fail/abort-terminator.stderr +++ b/tests/fail/abort-terminator.stderr @@ -3,8 +3,10 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: abnormal termination: the program aborted execution --> $DIR/abort-terminator.rs:LL:CC | -LL | extern "C" fn panic_abort() { panic!() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the program aborted execution +LL | / extern "C" fn panic_abort() { +LL | | panic!() +LL | | } + | |_^ the program aborted execution | = note: inside `panic_abort` at $DIR/abort-terminator.rs:LL:CC note: inside `main` at $DIR/abort-terminator.rs:LL:CC diff --git a/tests/fail/alloc/global_system_mixup.stderr b/tests/fail/alloc/global_system_mixup.stderr index a3b9009e3035..f197bc791785 100644 --- a/tests/fail/alloc/global_system_mixup.stderr +++ b/tests/fail/alloc/global_system_mixup.stderr @@ -12,7 +12,7 @@ LL | FREE(); note: inside `main` at $DIR/global_system_mixup.rs:LL:CC --> $DIR/global_system_mixup.rs:LL:CC | -LL | unsafe { System.deallocate(ptr, l); } +LL | System.deallocate(ptr, l); | ^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-div-by-zero.stderr b/tests/fail/intrinsics/simd-div-by-zero.stderr index 77c12de8d81a..37e1aafec2c0 100644 --- a/tests/fail/intrinsics/simd-div-by-zero.stderr +++ b/tests/fail/intrinsics/simd-div-by-zero.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: dividing by zero --> $DIR/simd-div-by-zero.rs:LL:CC | -LL | simd_div(x, y); - | ^^^^^^^^^^^^^^ dividing by zero +LL | simd_div(x, y); + | ^^^^^^^^^^^^^^ dividing by zero | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/simd-div-overflow.stderr b/tests/fail/intrinsics/simd-div-overflow.stderr index 53479a738b7b..b5e8e378a0ab 100644 --- a/tests/fail/intrinsics/simd-div-overflow.stderr +++ b/tests/fail/intrinsics/simd-div-overflow.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow in signed division (dividing MIN by -1) --> $DIR/simd-div-overflow.rs:LL:CC | -LL | simd_div(x, y); - | ^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) +LL | simd_div(x, y); + | ^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/simd-float-to-int.stderr b/tests/fail/intrinsics/simd-float-to-int.stderr index 6e6a136c39af..cfe272d90a1f 100644 --- a/tests/fail/intrinsics/simd-float-to-int.stderr +++ b/tests/fail/intrinsics/simd-float-to-int.stderr @@ -11,8 +11,8 @@ LL | implement! { f32 } note: inside `main` at $DIR/simd-float-to-int.rs:LL:CC --> $DIR/simd-float-to-int.rs:LL:CC | -LL | let _x : i32x2 = f32x2::from_array([f32::MAX, f32::MIN]).to_int_unchecked(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _x: i32x2 = f32x2::from_array([f32::MAX, f32::MIN]).to_int_unchecked(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `implement` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-gather.stderr b/tests/fail/intrinsics/simd-gather.stderr index 8021077a92d3..0464e67f80c6 100644 --- a/tests/fail/intrinsics/simd-gather.stderr +++ b/tests/fail/intrinsics/simd-gather.stderr @@ -11,8 +11,8 @@ LL | unsafe { intrinsics::simd_gather(or, ptrs, enable.to_int()) } note: inside `main` at $DIR/simd-gather.rs:LL:CC --> $DIR/simd-gather.rs:LL:CC | -LL | let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true), idxs, Simd::splat(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true), idxs, Simd::splat(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr b/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr index a2404b174e88..15c39500d4cb 100644 --- a/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr +++ b/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: each element of a SIMD mask must be all-0-bits or all-1-bits --> $DIR/simd-reduce-invalid-bool.rs:LL:CC | -LL | simd_reduce_any(x); - | ^^^^^^^^^^^^^^^^^^ each element of a SIMD mask must be all-0-bits or all-1-bits +LL | simd_reduce_any(x); + | ^^^^^^^^^^^^^^^^^^ each element of a SIMD mask must be all-0-bits or all-1-bits | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information From 6cd74ee9c79f72f2a19cb2a469077fdaf633332d Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 19 Jun 2022 22:57:10 -0400 Subject: [PATCH 3297/5092] Pass --color=always through cargo-miri --- cargo-miri/bin.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 8b11016ca1be..6a5e5dc3913a 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -945,7 +945,14 @@ fn phase_runner(binary: &Path, binary_args: env::Args, phase: RunnerPhase) { // Drop this argument. } else if let Some(suffix) = arg.strip_prefix(json_flag) { assert!(suffix.starts_with('=')); - // Drop this argument. + // This is how we pass through --color=always. We detect that Cargo is detecting rustc + // to emit the diagnostic structure that Cargo would consume from rustc to emit colored + // diagnostics, and ask rustc to emit them. + // See https://github.com/rust-lang/miri/issues/2037 + if arg.split(',').any(|a| a == "diagnostic-rendered-ansi") { + cmd.arg("--color=always"); + } + // But aside from remembering that colored output was requested, drop this argument. } else { cmd.arg(arg); } From fed5ea8b10c4461ada9b4a121556bb7e0c05a3b2 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 20 Jun 2022 02:43:06 -0700 Subject: [PATCH 3298/5092] Manual adjustments --- tests/fail/data_race/atomic_write_na_read_race2.rs | 4 +++- tests/fail/data_race/read_write_race.rs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/fail/data_race/atomic_write_na_read_race2.rs b/tests/fail/data_race/atomic_write_na_read_race2.rs index 359970dfff8f..0b055c9b96ec 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.rs +++ b/tests/fail/data_race/atomic_write_na_read_race2.rs @@ -16,7 +16,9 @@ pub fn main() { let b = &mut a as *mut AtomicUsize; let c = EvilSend(b); unsafe { - let j1 = spawn(move || *(c.0 as *mut usize)); + let j1 = spawn(move || { + let _val = *(c.0 as *mut usize); + }); let j2 = spawn(move || { //Equivalent to: (&*c.0).store(32, Ordering::SeqCst) diff --git a/tests/fail/data_race/read_write_race.rs b/tests/fail/data_race/read_write_race.rs index 976ace6e4b6f..9197912ef2e9 100644 --- a/tests/fail/data_race/read_write_race.rs +++ b/tests/fail/data_race/read_write_race.rs @@ -13,7 +13,9 @@ pub fn main() { let b = &mut a as *mut u32; let c = EvilSend(b); unsafe { - let j1 = spawn(move || *c.0); + let j1 = spawn(move || { + let _val = *c.0; + }); let j2 = spawn(move || { *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 2) and Read on Thread(id = 1) From 53580c1e18a38ddcc0508df5084c8ce2eeb58c42 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 20 Jun 2022 02:43:13 -0700 Subject: [PATCH 3299/5092] Add rustfmt CI for currently formatted directories --- .github/workflows/ci.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 55da948f7b78..ee65d58dccad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -116,8 +116,11 @@ jobs: rustup override set nightly - name: Formatting (miri, ui_test) run: cargo fmt --all --check - - name: Formatting (cargo-miri) - run: cargo fmt --manifest-path cargo-miri/Cargo.toml --all --check + - name: Formatting (everything else) + # TODO: Add `tests` (work in progress). + # Maybe change to `find . -name '*.rs'`, superseding the previous step. + run: find bench-cargo-miri benches cargo-miri test-cargo-miri -name '*.rs' + | xargs rustfmt --edition=2021 --config-path ./rustfmt.toml --check # These jobs doesn't actually test anything, but they're only used to tell # bors the build completed, as there is no practical way to detect when a From 619813500bf96f99b9da1603646f6c58b2680deb Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 20 Jun 2022 15:30:34 -0700 Subject: [PATCH 3300/5092] Format tests with rustfmt (51-100 of 300) --- tests/pass/align.rs | 8 +- tests/pass/align_offset_symbolic.rs | 15 +- tests/pass/backtrace/backtrace-api-v0.rs | 29 ++- tests/pass/backtrace/backtrace-api-v1.rs | 33 ++- tests/pass/backtrace/backtrace-std.rs | 28 ++- tests/pass/binary-heap.rs | 2 +- tests/pass/binops.rs | 19 +- tests/pass/box.rs | 51 +++-- tests/pass/calls.rs | 14 +- tests/pass/cast-rfc0401-vtable-kinds.rs | 36 ++-- tests/pass/cast_fn_ptr.rs | 4 +- tests/pass/catch.rs | 4 +- tests/pass/closure-drop.rs | 5 +- tests/pass/closure-field-ty.rs | 4 +- tests/pass/closures.rs | 24 ++- .../coerce_non_capture_closure_to_fn_ptr.rs | 26 ++- tests/pass/coercions.rs | 59 +++--- .../concurrency/concurrent_caller_location.rs | 2 +- tests/pass/concurrency/data_race.rs | 35 +-- tests/pass/concurrency/simple.rs | 26 +-- tests/pass/concurrency/spin_loop.rs | 2 +- .../pass/concurrency/spin_loops_nopreempt.rs | 4 +- tests/pass/concurrency/sync_singlethread.rs | 4 +- tests/pass/concurrency/tls_lib_drop.rs | 15 +- .../concurrency/tls_pthread_drop_order.rs | 21 +- tests/pass/const-vec-of-fns.rs | 2 +- tests/pass/drop_empty_slice.rs | 2 +- tests/pass/drop_on_array_elements.rs | 6 +- tests/pass/drop_on_fat_ptr_array_elements.rs | 4 +- tests/pass/drop_on_zst_array_elements.rs | 6 +- tests/pass/drop_through_owned_slice.rs | 4 +- tests/pass/drop_through_trait_object.rs | 4 +- tests/pass/drop_through_trait_object_rc.rs | 4 +- tests/pass/dst-field-align.rs | 41 ++-- tests/pass/dst-irrefutable-bind.rs | 8 +- tests/pass/dst-raw.rs | 29 +-- tests/pass/dst-struct-sole.rs | 5 +- tests/pass/dst-struct.rs | 21 +- tests/pass/dyn-arbitrary-self.rs | 10 +- tests/pass/dyn-traits.rs | 17 +- .../enum-nullable-const-null-with-fields.rs | 1 - tests/pass/enums.rs | 18 +- tests/pass/extern_types.rs | 2 +- tests/pass/fat_ptr.rs | 6 +- tests/pass/float.rs | 199 +++++++++++++----- tests/pass/float_fast_math.rs | 2 +- tests/pass/foreign-fn-linkname.rs | 6 +- tests/pass/fs_with_isolation.rs | 7 +- tests/pass/function_calls/exported_symbol.rs | 6 +- tests/pass/function_pointers.rs | 38 +++- 50 files changed, 544 insertions(+), 374 deletions(-) diff --git a/tests/pass/align.rs b/tests/pass/align.rs index 81e7e8c7ccac..5794b7f54276 100644 --- a/tests/pass/align.rs +++ b/tests/pass/align.rs @@ -2,9 +2,11 @@ fn manual_alignment() { let x = &mut [0u8; 3]; let base_addr = x as *mut _ as usize; - let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr+1 }; + let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr + 1 }; let u16_ptr = base_addr_aligned as *mut u16; - unsafe { *u16_ptr = 2; } + unsafe { + *u16_ptr = 2; + } } /// Test standard library `align_to`. @@ -12,7 +14,7 @@ fn align_to() { const LEN: usize = 128; let buf = &[0u8; LEN]; let (l, m, r) = unsafe { buf.align_to::() }; - assert!(m.len()*4 >= LEN-4); + assert!(m.len() * 4 >= LEN - 4); assert!(l.len() + r.len() <= 4); } diff --git a/tests/pass/align_offset_symbolic.rs b/tests/pass/align_offset_symbolic.rs index 70b2e00896dc..ad231bd0d5bb 100644 --- a/tests/pass/align_offset_symbolic.rs +++ b/tests/pass/align_offset_symbolic.rs @@ -36,31 +36,32 @@ fn test_align_to() { { let (l, m, r) = unsafe { s[1..].align_to::() }; assert_eq!(l.len(), 3); - assert_eq!(m.len(), N-1); + assert_eq!(m.len(), N - 1); assert_eq!(r.len(), 0); assert_eq!(raw.wrapping_offset(4), m.as_ptr() as *const u8); } { - let (l, m, r) = unsafe { s[..4*N - 1].align_to::() }; + let (l, m, r) = unsafe { s[..4 * N - 1].align_to::() }; assert_eq!(l.len(), 0); - assert_eq!(m.len(), N-1); + assert_eq!(m.len(), N - 1); assert_eq!(r.len(), 3); assert_eq!(raw, m.as_ptr() as *const u8); } { - let (l, m, r) = unsafe { s[1..4*N - 1].align_to::() }; + let (l, m, r) = unsafe { s[1..4 * N - 1].align_to::() }; assert_eq!(l.len(), 3); - assert_eq!(m.len(), N-2); + assert_eq!(m.len(), N - 2); assert_eq!(r.len(), 3); assert_eq!(raw.wrapping_offset(4), m.as_ptr() as *const u8); } { - #[repr(align(8))] struct Align8(u64); + #[repr(align(8))] + struct Align8(u64); let (l, m, r) = unsafe { s.align_to::() }; // requested alignment higher than allocation alignment - assert_eq!(l.len(), 4*N); + assert_eq!(l.len(), 4 * N); assert_eq!(r.len(), 0); assert_eq!(m.len(), 0); } diff --git a/tests/pass/backtrace/backtrace-api-v0.rs b/tests/pass/backtrace/backtrace-api-v0.rs index 62702c088dd6..32fd47d8c581 100644 --- a/tests/pass/backtrace/backtrace-api-v0.rs +++ b/tests/pass/backtrace/backtrace-api-v0.rs @@ -1,14 +1,28 @@ // normalize-stderr-test: "::<.*>" -> "" -#[inline(never)] fn func_a() -> Box<[*mut ()]> { func_b::() } -#[inline(never)] fn func_b() -> Box<[*mut ()]> { func_c() } - -macro_rules! invoke_func_d { - () => { func_d() } +#[inline(never)] +fn func_a() -> Box<[*mut ()]> { + func_b::() +} +#[inline(never)] +fn func_b() -> Box<[*mut ()]> { + func_c() } -#[inline(never)] fn func_c() -> Box<[*mut ()]> { invoke_func_d!() } -#[inline(never)] fn func_d() -> Box<[*mut ()]> { unsafe { miri_get_backtrace(0) } } +macro_rules! invoke_func_d { + () => { + func_d() + }; +} + +#[inline(never)] +fn func_c() -> Box<[*mut ()]> { + invoke_func_d!() +} +#[inline(never)] +fn func_d() -> Box<[*mut ()]> { + unsafe { miri_get_backtrace(0) } +} fn main() { let mut seen_main = false; @@ -51,4 +65,3 @@ struct MiriFrame { colno: u32, fn_ptr: *mut (), } - diff --git a/tests/pass/backtrace/backtrace-api-v1.rs b/tests/pass/backtrace/backtrace-api-v1.rs index 6d4a29c954e9..c24a5f3e8125 100644 --- a/tests/pass/backtrace/backtrace-api-v1.rs +++ b/tests/pass/backtrace/backtrace-api-v1.rs @@ -1,14 +1,33 @@ // normalize-stderr-test: "::<.*>" -> "" -#[inline(never)] fn func_a() -> Box<[*mut ()]> { func_b::() } -#[inline(never)] fn func_b() -> Box<[*mut ()]> { func_c() } - -macro_rules! invoke_func_d { - () => { func_d() } +#[inline(never)] +fn func_a() -> Box<[*mut ()]> { + func_b::() +} +#[inline(never)] +fn func_b() -> Box<[*mut ()]> { + func_c() } -#[inline(never)] fn func_c() -> Box<[*mut ()]> { invoke_func_d!() } -#[inline(never)] fn func_d() -> Box<[*mut ()]> { unsafe { let count = miri_backtrace_size(0); let mut buf = vec![std::ptr::null_mut(); count]; miri_get_backtrace(1, buf.as_mut_ptr()); buf.into() } } +macro_rules! invoke_func_d { + () => { + func_d() + }; +} + +#[inline(never)] +fn func_c() -> Box<[*mut ()]> { + invoke_func_d!() +} +#[inline(never)] +fn func_d() -> Box<[*mut ()]> { + unsafe { + let count = miri_backtrace_size(0); + let mut buf = vec![std::ptr::null_mut(); count]; + miri_get_backtrace(1, buf.as_mut_ptr()); + buf.into() + } +} fn main() { let mut seen_main = false; diff --git a/tests/pass/backtrace/backtrace-std.rs b/tests/pass/backtrace/backtrace-std.rs index 64b7e7293b19..5de7cdd6a54d 100644 --- a/tests/pass/backtrace/backtrace-std.rs +++ b/tests/pass/backtrace/backtrace-std.rs @@ -4,15 +4,29 @@ use std::backtrace::Backtrace; -#[inline(never)] fn func_a() -> Backtrace { func_b::() } -#[inline(never)] fn func_b() -> Backtrace { func_c() } - -macro_rules! invoke_func_d { - () => { func_d() } +#[inline(never)] +fn func_a() -> Backtrace { + func_b::() +} +#[inline(never)] +fn func_b() -> Backtrace { + func_c() } -#[inline(never)] fn func_c() -> Backtrace { invoke_func_d!() } -#[inline(never)] fn func_d() -> Backtrace { Backtrace::capture() } +macro_rules! invoke_func_d { + () => { + func_d() + }; +} + +#[inline(never)] +fn func_c() -> Backtrace { + invoke_func_d!() +} +#[inline(never)] +fn func_d() -> Backtrace { + Backtrace::capture() +} fn main() { eprint!("{}", func_a()); diff --git a/tests/pass/binary-heap.rs b/tests/pass/binary-heap.rs index 8b8fa6458e65..278038d8ad32 100644 --- a/tests/pass/binary-heap.rs +++ b/tests/pass/binary-heap.rs @@ -26,7 +26,7 @@ fn drain() { for x in heap.drain() { sum += x; } - assert_eq!(sum, 127*128/2); + assert_eq!(sum, 127 * 128 / 2); assert!(heap.is_empty()); } diff --git a/tests/pass/binops.rs b/tests/pass/binops.rs index 1d03c8b3d0aa..0988d7ccc4c6 100644 --- a/tests/pass/binops.rs +++ b/tests/pass/binops.rs @@ -56,21 +56,18 @@ struct P { } fn p(x: isize, y: isize) -> P { - P { - x: x, - y: y - } + P { x: x, y: y } } fn test_class() { - let q = p(1, 2); - let mut r = p(1, 2); + let q = p(1, 2); + let mut r = p(1, 2); - assert_eq!(q, r); - r.y = 17; - assert!((r.y != q.y)); - assert_eq!(r.y, 17); - assert!((q != r)); + assert_eq!(q, r); + r.y = 17; + assert!((r.y != q.y)); + assert_eq!(r.y, 17); + assert!((q != r)); } pub fn main() { diff --git a/tests/pass/box.rs b/tests/pass/box.rs index c29a83507677..c2ecc3707179 100644 --- a/tests/pass/box.rs +++ b/tests/pass/box.rs @@ -6,30 +6,34 @@ fn main() { boxed_pair_to_vec(); } -fn into_raw() { unsafe { - let b = Box::new(4i32); - let r = Box::into_raw(b); +fn into_raw() { + unsafe { + let b = Box::new(4i32); + let r = Box::into_raw(b); - // "lose the tag" - let r2 = ((r as usize)+0) as *mut i32; - *(&mut *r2) = 7; + // "lose the tag" + let r2 = ((r as usize) + 0) as *mut i32; + *(&mut *r2) = 7; - // Use original ptr again - *(&mut *r) = 17; - drop(Box::from_raw(r)); -}} + // Use original ptr again + *(&mut *r) = 17; + drop(Box::from_raw(r)); + } +} -fn into_unique() { unsafe { - let b = Box::new(4i32); - let u = Box::into_unique(b).0; +fn into_unique() { + unsafe { + let b = Box::new(4i32); + let u = Box::into_unique(b).0; - // "lose the tag" - let r = ((u.as_ptr() as usize)+0) as *mut i32; - *(&mut *r) = 7; + // "lose the tag" + let r = ((u.as_ptr() as usize) + 0) as *mut i32; + *(&mut *r) = 7; - // Use original ptr again. - drop(Box::from_raw(u.as_ptr())); -}} + // Use original ptr again. + drop(Box::from_raw(u.as_ptr())); + } +} fn boxed_pair_to_vec() { #[repr(C)] @@ -44,15 +48,10 @@ fn boxed_pair_to_vec() { fn reinterstruct(box_pair: Box) -> Vec { let ref_pair = Box::leak(box_pair) as *mut PairFoo; let ptr_foo = unsafe { &mut (*ref_pair).fst as *mut Foo }; - unsafe { - Vec::from_raw_parts(ptr_foo, 2, 2) - } + unsafe { Vec::from_raw_parts(ptr_foo, 2, 2) } } - let pair_foo = Box::new(PairFoo { - fst: Foo(42), - snd: Foo(1337), - }); + let pair_foo = Box::new(PairFoo { fst: Foo(42), snd: Foo(1337) }); println!("pair_foo = {:?}", pair_foo); for (n, foo) in reinterstruct(pair_foo).into_iter().enumerate() { println!("foo #{} = {:?}", n, foo); diff --git a/tests/pass/calls.rs b/tests/pass/calls.rs index 4cbd7ada69e6..014d1d3acab7 100644 --- a/tests/pass/calls.rs +++ b/tests/pass/calls.rs @@ -7,17 +7,15 @@ fn call() -> i32 { fn factorial_recursive() -> i64 { fn fact(n: i64) -> i64 { - if n == 0 { - 1 - } else { - n * fact(n - 1) - } + if n == 0 { 1 } else { n * fact(n - 1) } } fact(10) } fn call_generic() -> (i16, bool) { - fn id(t: T) -> T { t } + fn id(t: T) -> T { + t + } (id(42), id(true)) } @@ -26,7 +24,9 @@ fn cross_crate_fn_call() -> i64 { if 1i32.is_positive() { 1 } else { 0 } } -const fn foo(i: i64) -> i64 { *&i + 1 } +const fn foo(i: i64) -> i64 { + *&i + 1 +} fn const_fn_call() -> i64 { let x = 5 + foo(5); diff --git a/tests/pass/cast-rfc0401-vtable-kinds.rs b/tests/pass/cast-rfc0401-vtable-kinds.rs index 544510be9bb0..d76c23633da1 100644 --- a/tests/pass/cast-rfc0401-vtable-kinds.rs +++ b/tests/pass/cast-rfc0401-vtable-kinds.rs @@ -2,44 +2,52 @@ // whose vtable have the same kind (both lengths, or both trait pointers). trait Foo { - fn foo(&self, _: T) -> u32 { 42 } + fn foo(&self, _: T) -> u32 { + 42 + } } trait Bar { - fn bar(&self) { println!("Bar!"); } + fn bar(&self) { + println!("Bar!"); + } } impl Foo for () {} -impl Foo for u32 { fn foo(&self, _: u32) -> u32 { self+43 } } +impl Foo for u32 { + fn foo(&self, _: u32) -> u32 { + self + 43 + } +} impl Bar for () {} -unsafe fn round_trip_and_call<'a>(t: *const (dyn Foo+'a)) -> u32 { - let foo_e : *const dyn Foo = t as *const _; +unsafe fn round_trip_and_call<'a>(t: *const (dyn Foo + 'a)) -> u32 { + let foo_e: *const dyn Foo = t as *const _; let r_1 = foo_e as *mut dyn Foo; (&*r_1).foo(0) } #[repr(C)] -struct FooS(T); +struct FooS(T); #[repr(C)] -struct BarS(T); +struct BarS(T); -fn foo_to_bar(u: *const FooS) -> *const BarS { +fn foo_to_bar(u: *const FooS) -> *const BarS { u as *const BarS } fn main() { let x = 4u32; - let y : &dyn Foo = &x; + let y: &dyn Foo = &x; let fl = unsafe { round_trip_and_call(y as *const dyn Foo) }; - assert_eq!(fl, (43+4)); + assert_eq!(fl, (43 + 4)); - let s = FooS([0,1,2]); + let s = FooS([0, 1, 2]); let u: &FooS<[u32]> = &s; let u: *const FooS<[u32]> = u; - let bar_ref : *const BarS<[u32]> = foo_to_bar(u); - let z : &BarS<[u32]> = unsafe{&*bar_ref}; - assert_eq!(&z.0, &[0,1,2]); + let bar_ref: *const BarS<[u32]> = foo_to_bar(u); + let z: &BarS<[u32]> = unsafe { &*bar_ref }; + assert_eq!(&z.0, &[0, 1, 2]); // If validation fails here, that's likely because an immutable suspension is recovered mutably. } diff --git a/tests/pass/cast_fn_ptr.rs b/tests/pass/cast_fn_ptr.rs index 109e8dfc2a02..8954048f4262 100644 --- a/tests/pass/cast_fn_ptr.rs +++ b/tests/pass/cast_fn_ptr.rs @@ -1,9 +1,7 @@ fn main() { fn f(_: *const u8) {} - let g = unsafe { - std::mem::transmute::(f) - }; + let g = unsafe { std::mem::transmute::(f) }; g(&42 as *const _); } diff --git a/tests/pass/catch.rs b/tests/pass/catch.rs index 5fd65f138aaf..745e186a8e17 100644 --- a/tests/pass/catch.rs +++ b/tests/pass/catch.rs @@ -2,6 +2,8 @@ use std::panic::{catch_unwind, AssertUnwindSafe}; fn main() { let mut i = 3; - let _val = catch_unwind(AssertUnwindSafe(|| {i -= 2;} )); + let _val = catch_unwind(AssertUnwindSafe(|| { + i -= 2; + })); println!("{}", i); } diff --git a/tests/pass/closure-drop.rs b/tests/pass/closure-drop.rs index 374efb6032bf..9f9454b4c71c 100644 --- a/tests/pass/closure-drop.rs +++ b/tests/pass/closure-drop.rs @@ -17,9 +17,10 @@ fn main() { // this closure never by val uses its captures // so it's basically a fn(&self) // the shim used to not drop the `x` - let x = move || { let _val = x; }; + let x = move || { + let _val = x; + }; f(x); } assert!(ran_drop); } - diff --git a/tests/pass/closure-field-ty.rs b/tests/pass/closure-field-ty.rs index 0d27728d2232..fdcaf1d51723 100644 --- a/tests/pass/closure-field-ty.rs +++ b/tests/pass/closure-field-ty.rs @@ -3,7 +3,9 @@ fn main() { let mut y = 0; { let mut box_maybe_closure = Box::new(None); - *box_maybe_closure = Some(|| { y += 1; }); + *box_maybe_closure = Some(|| { + y += 1; + }); (box_maybe_closure.unwrap())(); } assert_eq!(y, 1); diff --git a/tests/pass/closures.rs b/tests/pass/closures.rs index 5e2e0f87bdaf..21292765acaa 100644 --- a/tests/pass/closures.rs +++ b/tests/pass/closures.rs @@ -22,7 +22,9 @@ fn crazy_closure() -> (i32, i32, i32) { } fn closure_arg_adjustment_problem() -> i64 { - fn once(f: F) { f(2); } + fn once(f: F) { + f(2); + } let mut y = 1; { let f = |x| y += x; @@ -32,7 +34,9 @@ fn closure_arg_adjustment_problem() -> i64 { } fn fn_once_closure_with_multiple_args() -> i64 { - fn once i64>(f: F) -> i64 { f(2, 3) } + fn once i64>(f: F) -> i64 { + f(2, 3) + } let y = 1; { let f = |x, z| x + y + z; @@ -50,7 +54,8 @@ fn box_dyn() { let mut i = 5; { let mut x: Box = Box::new(|| i *= 2); - x(); x(); + x(); + x(); } assert_eq!(i, 20); } @@ -88,7 +93,9 @@ fn fn_item_with_multiple_args_as_closure_trait_object() { fn fn_ptr_as_closure_trait_object() { fn foo() {} - fn bar(u: u32) { assert_eq!(u, 42); } + fn bar(u: u32) { + assert_eq!(u, 42); + } fn baa(u: u32, f: f32) { assert_eq!(u, 42); assert_eq!(f, 3.141); @@ -101,13 +108,18 @@ fn fn_ptr_as_closure_trait_object() { f(42, 3.141); } - fn main() { assert_eq!(simple(), 12); assert_eq!(crazy_closure(), (84, 10, 10)); assert_eq!(closure_arg_adjustment_problem(), 3); assert_eq!(fn_once_closure_with_multiple_args(), 6); - assert_eq!(boxed_fn_once(Box::new({let x = 13; move || x})), 13); + assert_eq!( + boxed_fn_once(Box::new({ + let x = 13; + move || x + })), + 13 + ); box_dyn(); fn_item_as_closure_trait_object(); diff --git a/tests/pass/coerce_non_capture_closure_to_fn_ptr.rs b/tests/pass/coerce_non_capture_closure_to_fn_ptr.rs index bd8926aaf1ad..fde120db027b 100644 --- a/tests/pass/coerce_non_capture_closure_to_fn_ptr.rs +++ b/tests/pass/coerce_non_capture_closure_to_fn_ptr.rs @@ -1,11 +1,19 @@ -static FOO: fn() = || { assert_ne!(42, 43) }; -static BAR: fn(i32, i32) = |a, b| { assert_ne!(a, b) }; +static FOO: fn() = || assert_ne!(42, 43); +static BAR: fn(i32, i32) = |a, b| assert_ne!(a, b); // use to first make the closure FnOnce() before making it fn() -fn force_once0 R>(f: F) -> F { f } -fn force_once1 R>(f: F) -> F { f } -fn force_mut0 R>(f: F) -> F { f } -fn force_mut1 R>(f: F) -> F { f } +fn force_once0 R>(f: F) -> F { + f +} +fn force_once1 R>(f: F) -> F { + f +} +fn force_mut0 R>(f: F) -> F { + f +} +fn force_mut1 R>(f: F) -> F { + f +} fn main() { FOO(); @@ -15,11 +23,11 @@ fn main() { let boo: &dyn Fn(i32, i32) = &BAR; boo(48, 49); - let f: fn() = ||{}; + let f: fn() = || {}; f(); - let f = force_once0(||{}) as fn(); + let f = force_once0(|| {}) as fn(); f(); - let f = force_mut0(||{}) as fn(); + let f = force_mut0(|| {}) as fn(); f(); let g: fn(i32) = |i| assert_eq!(i, 2); diff --git a/tests/pass/coercions.rs b/tests/pass/coercions.rs index bfc821f799ee..db0d2ffd44bc 100644 --- a/tests/pass/coercions.rs +++ b/tests/pass/coercions.rs @@ -1,30 +1,32 @@ #![feature(coerce_unsized, unsize)] -use std::ops::CoerceUnsized; use std::marker::Unsize; +use std::ops::CoerceUnsized; -fn identity_coercion(x: &(dyn Fn(u32)->u32 + Send)) -> &dyn Fn(u32)->u32 { +fn identity_coercion(x: &(dyn Fn(u32) -> u32 + Send)) -> &dyn Fn(u32) -> u32 { x } -fn fn_coercions(f: &fn(u32) -> u32) -> - (unsafe fn(u32) -> u32, - &(dyn Fn(u32) -> u32 + Send)) -{ +fn fn_coercions(f: &fn(u32) -> u32) -> (unsafe fn(u32) -> u32, &(dyn Fn(u32) -> u32 + Send)) { (*f, f) } -fn simple_array_coercion(x: &[u8; 3]) -> &[u8] { x } +fn simple_array_coercion(x: &[u8; 3]) -> &[u8] { + x +} -fn square(a: u32) -> u32 { a * a } +fn square(a: u32) -> u32 { + a * a +} -#[derive(PartialEq,Eq)] -struct PtrWrapper<'a, T: 'a+?Sized>(u32, u32, (), &'a T); -impl<'a, T: ?Sized+Unsize, U: ?Sized> - CoerceUnsized> for PtrWrapper<'a, T> {} +#[derive(PartialEq, Eq)] +struct PtrWrapper<'a, T: 'a + ?Sized>(u32, u32, (), &'a T); +impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized> for PtrWrapper<'a, T> {} -struct TrivPtrWrapper<'a, T: 'a+?Sized>(&'a T); -impl<'a, T: ?Sized+Unsize, U: ?Sized> - CoerceUnsized> for TrivPtrWrapper<'a, T> {} +struct TrivPtrWrapper<'a, T: 'a + ?Sized>(&'a T); +impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized> + for TrivPtrWrapper<'a, T> +{ +} fn coerce_ptr_wrapper(p: PtrWrapper<[u8; 3]>) -> PtrWrapper<[u8]> { p @@ -34,40 +36,41 @@ fn coerce_triv_ptr_wrapper(p: TrivPtrWrapper<[u8; 3]>) -> TrivPtrWrapper<[u8]> { p } -fn coerce_fat_ptr_wrapper(p: PtrWrapper u32 + Send>) - -> PtrWrapper u32> { +fn coerce_fat_ptr_wrapper( + p: PtrWrapper u32 + Send>, +) -> PtrWrapper u32> { p } -fn coerce_ptr_wrapper_poly<'a, T, Trait: ?Sized>(p: PtrWrapper<'a, T>) - -> PtrWrapper<'a, Trait> - where PtrWrapper<'a, T>: CoerceUnsized> +fn coerce_ptr_wrapper_poly<'a, T, Trait: ?Sized>(p: PtrWrapper<'a, T>) -> PtrWrapper<'a, Trait> +where + PtrWrapper<'a, T>: CoerceUnsized>, { p } fn main() { - let a = [0,1,2]; - let square_local : fn(u32) -> u32 = square; - let (f,g) = fn_coercions(&square_local); + let a = [0, 1, 2]; + let square_local: fn(u32) -> u32 = square; + let (f, g) = fn_coercions(&square_local); // cannot use `square as *const ()` because we can't know whether the compiler duplicates // functions, so two function pointers are only equal if they result from the same function // to function pointer cast - assert_eq!(f as *const (), square_local as *const()); + assert_eq!(f as *const (), square_local as *const ()); assert_eq!(g(4), 16); assert_eq!(identity_coercion(g)(5), 25); assert_eq!(simple_array_coercion(&a), &a); - let w = coerce_ptr_wrapper(PtrWrapper(2,3,(),&a)); - assert!(w == PtrWrapper(2,3,(),&a) as PtrWrapper<[u8]>); + let w = coerce_ptr_wrapper(PtrWrapper(2, 3, (), &a)); + assert!(w == PtrWrapper(2, 3, (), &a) as PtrWrapper<[u8]>); let w = coerce_triv_ptr_wrapper(TrivPtrWrapper(&a)); assert_eq!(&w.0, &a); - let z = coerce_fat_ptr_wrapper(PtrWrapper(2,3,(),&square_local)); + let z = coerce_fat_ptr_wrapper(PtrWrapper(2, 3, (), &square_local)); assert_eq!((z.3)(6), 36); let z: PtrWrapper u32> = - coerce_ptr_wrapper_poly(PtrWrapper(2,3,(),&square_local)); + coerce_ptr_wrapper_poly(PtrWrapper(2, 3, (), &square_local)); assert_eq!((z.3)(6), 36); } diff --git a/tests/pass/concurrency/concurrent_caller_location.rs b/tests/pass/concurrency/concurrent_caller_location.rs index d509d1b3f797..003b9e9ca9f4 100644 --- a/tests/pass/concurrency/concurrent_caller_location.rs +++ b/tests/pass/concurrency/concurrent_caller_location.rs @@ -1,7 +1,7 @@ // ignore-windows: Concurrency on Windows is not supported yet. -use std::thread::spawn; use std::panic::Location; +use std::thread::spawn; fn initialize() { let _ignore = initialize_inner(); diff --git a/tests/pass/concurrency/data_race.rs b/tests/pass/concurrency/data_race.rs index c51080f474fb..071f5bbcdf39 100644 --- a/tests/pass/concurrency/data_race.rs +++ b/tests/pass/concurrency/data_race.rs @@ -1,8 +1,7 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-disable-weak-memory-emulation - -use std::sync::atomic::{AtomicUsize, fence, Ordering}; +use std::sync::atomic::{fence, AtomicUsize, Ordering}; use std::thread::spawn; #[derive(Copy, Clone)] @@ -18,9 +17,10 @@ fn test_fence_sync() { let ptr = &mut var as *mut u32; let evil_ptr = EvilSend(ptr); - let j1 = spawn(move || { - unsafe { *evil_ptr.0 = 1; } + unsafe { + *evil_ptr.0 = 1; + } fence(Ordering::Release); SYNC.store(1, Ordering::Relaxed) }); @@ -38,16 +38,15 @@ fn test_fence_sync() { j2.join().unwrap(); } - fn test_multiple_reads() { let mut var = 42u32; let ptr = &mut var as *mut u32; let evil_ptr = EvilSend(ptr); - let j1 = spawn(move || unsafe {*evil_ptr.0}); - let j2 = spawn(move || unsafe {*evil_ptr.0}); - let j3 = spawn(move || unsafe {*evil_ptr.0}); - let j4 = spawn(move || unsafe {*evil_ptr.0}); + let j1 = spawn(move || unsafe { *evil_ptr.0 }); + let j2 = spawn(move || unsafe { *evil_ptr.0 }); + let j3 = spawn(move || unsafe { *evil_ptr.0 }); + let j4 = spawn(move || unsafe { *evil_ptr.0 }); assert_eq!(j1.join().unwrap(), 42); assert_eq!(j2.join().unwrap(), 42); @@ -75,13 +74,7 @@ pub fn test_rmw_no_block() { } }); - let j3 = spawn(move || { - if SYNC.load(Ordering::Acquire) == 2 { - *c.0 - } else { - 0 - } - }); + let j3 = spawn(move || if SYNC.load(Ordering::Acquire) == 2 { *c.0 } else { 0 }); j1.join().unwrap(); j2.join().unwrap(); @@ -101,16 +94,10 @@ pub fn test_simple_release() { SYNC.store(1, Ordering::Release); }); - let j2 = spawn(move || { - if SYNC.load(Ordering::Acquire) == 1 { - *c.0 - } else { - 0 - } - }); + let j2 = spawn(move || if SYNC.load(Ordering::Acquire) == 1 { *c.0 } else { 0 }); j1.join().unwrap(); - assert_eq!(j2.join().unwrap(),1); + assert_eq!(j2.join().unwrap(), 1); } } diff --git a/tests/pass/concurrency/simple.rs b/tests/pass/concurrency/simple.rs index 40d8802472ac..48c1f3d9fb52 100644 --- a/tests/pass/concurrency/simple.rs +++ b/tests/pass/concurrency/simple.rs @@ -42,31 +42,25 @@ fn create_move_in() { } fn create_move_out() { - let result = thread::spawn(|| { - String::from("Hello!") - }) - .join() - .unwrap(); + let result = thread::spawn(|| String::from("Hello!")).join().unwrap(); assert_eq!(result.len(), 6); } fn panic() { - let result = thread::spawn(|| { - panic!("Hello!") - }) - .join() - .unwrap_err(); + let result = thread::spawn(|| panic!("Hello!")).join().unwrap_err(); let msg = result.downcast_ref::<&'static str>().unwrap(); assert_eq!(*msg, "Hello!"); } fn panic_named() { - thread::Builder::new().name("childthread".to_string()).spawn(move || { - panic!("Hello, world!"); - }) - .unwrap() - .join() - .unwrap_err(); + thread::Builder::new() + .name("childthread".to_string()) + .spawn(move || { + panic!("Hello, world!"); + }) + .unwrap() + .join() + .unwrap_err(); } fn main() { diff --git a/tests/pass/concurrency/spin_loop.rs b/tests/pass/concurrency/spin_loop.rs index 1e81f5dc86dc..e11f0789bb5d 100644 --- a/tests/pass/concurrency/spin_loop.rs +++ b/tests/pass/concurrency/spin_loop.rs @@ -1,6 +1,6 @@ // ignore-windows: Concurrency on Windows is not supported yet. -use std::thread; use std::sync::atomic::{AtomicUsize, Ordering}; +use std::thread; static FLAG: AtomicUsize = AtomicUsize::new(0); diff --git a/tests/pass/concurrency/spin_loops_nopreempt.rs b/tests/pass/concurrency/spin_loops_nopreempt.rs index d8064f6ed539..99a5410c95df 100644 --- a/tests/pass/concurrency/spin_loops_nopreempt.rs +++ b/tests/pass/concurrency/spin_loops_nopreempt.rs @@ -2,10 +2,10 @@ // This specifically tests behavior *without* preemption. // compile-flags: -Zmiri-preemption-rate=0 -use std::thread; +use std::cell::Cell; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::sync::mpsc; -use std::cell::Cell; +use std::thread; /// When a thread yields, Miri's scheduler used to pick the thread with the lowest ID /// that can run. IDs are assigned in thread creation order. diff --git a/tests/pass/concurrency/sync_singlethread.rs b/tests/pass/concurrency/sync_singlethread.rs index 2474fe6633c3..5663e1c1426c 100644 --- a/tests/pass/concurrency/sync_singlethread.rs +++ b/tests/pass/concurrency/sync_singlethread.rs @@ -1,6 +1,6 @@ -use std::sync::{Mutex, TryLockError}; -use std::sync::atomic; use std::hint; +use std::sync::atomic; +use std::sync::{Mutex, TryLockError}; fn main() { test_mutex_stdlib(); diff --git a/tests/pass/concurrency/tls_lib_drop.rs b/tests/pass/concurrency/tls_lib_drop.rs index 552b371cc7f1..fe46406c283c 100644 --- a/tests/pass/concurrency/tls_lib_drop.rs +++ b/tests/pass/concurrency/tls_lib_drop.rs @@ -9,7 +9,9 @@ struct TestCell { impl Drop for TestCell { fn drop(&mut self) { - for _ in 0..10 { thread::yield_now(); } + for _ in 0..10 { + thread::yield_now(); + } println!("Dropping: {} (should be before 'Continue main 1').", *self.value.borrow()) } } @@ -43,7 +45,9 @@ struct JoinCell { impl Drop for JoinCell { fn drop(&mut self) { - for _ in 0..10 { thread::yield_now(); } + for _ in 0..10 { + thread::yield_now(); + } let join_handle = self.value.borrow_mut().take().unwrap(); println!("Joining: {} (should be before 'Continue main 2').", join_handle.join().unwrap()); } @@ -118,9 +122,10 @@ fn join_orders_after_tls_destructors() { match sync_state { THREAD2_LAUNCHED | THREAD1_WAITING => thread::yield_now(), MAIN_THREAD_RENDEZVOUS => break, - THREAD2_JOINED => panic!( - "Thread 1 still running after thread 2 joined on thread 1" - ), + THREAD2_JOINED => + panic!( + "Thread 1 still running after thread 2 joined on thread 1" + ), v => unreachable!("sync state: {}", v), } sync_state = SYNC_STATE.load(Ordering::SeqCst); diff --git a/tests/pass/concurrency/tls_pthread_drop_order.rs b/tests/pass/concurrency/tls_pthread_drop_order.rs index 72ab973b0f08..4d69449821cd 100644 --- a/tests/pass/concurrency/tls_pthread_drop_order.rs +++ b/tests/pass/concurrency/tls_pthread_drop_order.rs @@ -7,13 +7,13 @@ use std::mem; pub type Key = libc::pthread_key_t; -static mut RECORD : usize = 0; -static mut KEYS : [Key; 2] = [0; 2]; -static mut GLOBALS : [u64; 2] = [1, 0]; +static mut RECORD: usize = 0; +static mut KEYS: [Key; 2] = [0; 2]; +static mut GLOBALS: [u64; 2] = [1, 0]; -static mut CANNARY : *mut u64 = 0 as *mut _; // this serves as a cannary: if TLS dtors are not run properly, this will not get deallocated, making the test fail. +static mut CANNARY: *mut u64 = 0 as *mut _; // this serves as a cannary: if TLS dtors are not run properly, this will not get deallocated, making the test fail. -pub unsafe fn create(dtor: Option) -> Key { +pub unsafe fn create(dtor: Option) -> Key { let mut key = 0; assert_eq!(libc::pthread_key_create(&mut key, mem::transmute(dtor)), 0); key @@ -26,18 +26,19 @@ pub unsafe fn set(key: Key, value: *mut u8) { pub fn record(r: usize) { assert!(r < 10); - unsafe { RECORD = RECORD*10 + r }; + unsafe { RECORD = RECORD * 10 + r }; } -unsafe extern fn dtor(ptr: *mut u64) { +unsafe extern "C" fn dtor(ptr: *mut u64) { assert!(CANNARY != 0 as *mut _); // make sure we do not get run too often let val = *ptr; - let which_key = GLOBALS.iter().position(|global| global as *const _ == ptr).expect("Should find my global"); + let which_key = + GLOBALS.iter().position(|global| global as *const _ == ptr).expect("Should find my global"); record(which_key); if val > 0 { - *ptr = val-1; + *ptr = val - 1; set(KEYS[which_key], ptr as *mut _); } @@ -57,7 +58,7 @@ fn main() { // Initialize the keys we use to check destructor ordering for (key, global) in KEYS.iter_mut().zip(GLOBALS.iter_mut()) { - *key = create(Some(mem::transmute(dtor as unsafe extern fn(*mut u64)))); + *key = create(Some(mem::transmute(dtor as unsafe extern "C" fn(*mut u64)))); set(*key, global as *mut _ as *mut u8); } diff --git a/tests/pass/const-vec-of-fns.rs b/tests/pass/const-vec-of-fns.rs index 9b6c6fcc32ef..7f0782fe3224 100644 --- a/tests/pass/const-vec-of-fns.rs +++ b/tests/pass/const-vec-of-fns.rs @@ -5,7 +5,7 @@ * should be read as a null or otherwise wrong pointer and crash. */ -fn f() { } +fn f() {} static mut CLOSURES: &'static mut [fn()] = &mut [f as fn(), f as fn()]; pub fn main() { diff --git a/tests/pass/drop_empty_slice.rs b/tests/pass/drop_empty_slice.rs index 8b481a0a2dd8..9805ce0ace3f 100644 --- a/tests/pass/drop_empty_slice.rs +++ b/tests/pass/drop_empty_slice.rs @@ -2,6 +2,6 @@ fn main() { // With the nested Vec, this is calling Offset(Unique::empty(), 0) on drop. - let args : Vec> = Vec::new(); + let args: Vec> = Vec::new(); let _val = box args; } diff --git a/tests/pass/drop_on_array_elements.rs b/tests/pass/drop_on_array_elements.rs index c9b59f635e14..ae1ef036267e 100644 --- a/tests/pass/drop_on_array_elements.rs +++ b/tests/pass/drop_on_array_elements.rs @@ -5,7 +5,9 @@ static mut DROP_COUNT: usize = 0; impl Drop for Bar { fn drop(&mut self) { assert_eq!(self.0 as usize, unsafe { DROP_COUNT }); // tests whether we are called at a valid address - unsafe { DROP_COUNT += 1; } + unsafe { + DROP_COUNT += 1; + } } } @@ -16,7 +18,7 @@ fn main() { assert_eq!(unsafe { DROP_COUNT }, 4); // check empty case - let b : [Bar; 0] = []; + let b: [Bar; 0] = []; drop(b); assert_eq!(unsafe { DROP_COUNT }, 4); } diff --git a/tests/pass/drop_on_fat_ptr_array_elements.rs b/tests/pass/drop_on_fat_ptr_array_elements.rs index 36162d320212..40025cd07f7e 100644 --- a/tests/pass/drop_on_fat_ptr_array_elements.rs +++ b/tests/pass/drop_on_fat_ptr_array_elements.rs @@ -8,7 +8,9 @@ static mut DROP_COUNT: usize = 0; impl Drop for Bar { fn drop(&mut self) { - unsafe { DROP_COUNT += 1; } + unsafe { + DROP_COUNT += 1; + } } } diff --git a/tests/pass/drop_on_zst_array_elements.rs b/tests/pass/drop_on_zst_array_elements.rs index 1887130fdd8a..babe098e4e6f 100644 --- a/tests/pass/drop_on_zst_array_elements.rs +++ b/tests/pass/drop_on_zst_array_elements.rs @@ -4,7 +4,9 @@ static mut DROP_COUNT: usize = 0; impl Drop for Bar { fn drop(&mut self) { - unsafe { DROP_COUNT += 1; } + unsafe { + DROP_COUNT += 1; + } } } @@ -15,7 +17,7 @@ fn main() { assert_eq!(unsafe { DROP_COUNT }, 4); // check empty case - let b : [Bar; 0] = []; + let b: [Bar; 0] = []; drop(b); assert_eq!(unsafe { DROP_COUNT }, 4); } diff --git a/tests/pass/drop_through_owned_slice.rs b/tests/pass/drop_through_owned_slice.rs index 3ec6be65ed8b..8cdeb57d02f7 100644 --- a/tests/pass/drop_through_owned_slice.rs +++ b/tests/pass/drop_through_owned_slice.rs @@ -4,7 +4,9 @@ static mut DROP_COUNT: usize = 0; impl Drop for Bar { fn drop(&mut self) { - unsafe { DROP_COUNT += 1; } + unsafe { + DROP_COUNT += 1; + } } } diff --git a/tests/pass/drop_through_trait_object.rs b/tests/pass/drop_through_trait_object.rs index 97ba69c9fe28..8d22ca9ceb4a 100644 --- a/tests/pass/drop_through_trait_object.rs +++ b/tests/pass/drop_through_trait_object.rs @@ -6,7 +6,9 @@ static mut DROP_CALLED: bool = false; impl Drop for Bar { fn drop(&mut self) { - unsafe { DROP_CALLED = true; } + unsafe { + DROP_CALLED = true; + } } } diff --git a/tests/pass/drop_through_trait_object_rc.rs b/tests/pass/drop_through_trait_object_rc.rs index 172a4580dc10..7806c0252d27 100644 --- a/tests/pass/drop_through_trait_object_rc.rs +++ b/tests/pass/drop_through_trait_object_rc.rs @@ -6,7 +6,9 @@ static mut DROP_CALLED: bool = false; impl Drop for Bar { fn drop(&mut self) { - unsafe { DROP_CALLED = true; } + unsafe { + DROP_CALLED = true; + } } } diff --git a/tests/pass/dst-field-align.rs b/tests/pass/dst-field-align.rs index 6c827d7b3bea..4d1db03643f7 100644 --- a/tests/pass/dst-field-align.rs +++ b/tests/pass/dst-field-align.rs @@ -1,7 +1,7 @@ #[allow(dead_code)] struct Foo { a: u16, - b: T + b: T, } trait Bar { @@ -9,59 +9,58 @@ trait Bar { } impl Bar for usize { - fn get(&self) -> usize { *self } + fn get(&self) -> usize { + *self + } } struct Baz { - a: T + a: T, } #[allow(dead_code)] struct HasDrop { ptr: Box, - data: T + data: T, } fn main() { // Test that zero-offset works properly - let b : Baz = Baz { a: 7 }; + let b: Baz = Baz { a: 7 }; assert_eq!(b.a.get(), 7); - let b : &Baz = &b; + let b: &Baz = &b; assert_eq!(b.a.get(), 7); // Test that the field is aligned properly - let f : Foo = Foo { a: 0, b: 11 }; + let f: Foo = Foo { a: 0, b: 11 }; assert_eq!(f.b.get(), 11); - let ptr1 : *const u8 = &f.b as *const _ as *const u8; + let ptr1: *const u8 = &f.b as *const _ as *const u8; - let f : &Foo = &f; - let ptr2 : *const u8 = &f.b as *const _ as *const u8; + let f: &Foo = &f; + let ptr2: *const u8 = &f.b as *const _ as *const u8; assert_eq!(f.b.get(), 11); // The pointers should be the same assert_eq!(ptr1, ptr2); // Test that nested DSTs work properly - let f : Foo> = Foo { a: 0, b: Foo { a: 1, b: 17 }}; + let f: Foo> = Foo { a: 0, b: Foo { a: 1, b: 17 } }; assert_eq!(f.b.b.get(), 17); - let f : &Foo> = &f; + let f: &Foo> = &f; assert_eq!(f.b.b.get(), 17); // Test that get the pointer via destructuring works - let f : Foo = Foo { a: 0, b: 11 }; - let f : &Foo = &f; + let f: Foo = Foo { a: 0, b: 11 }; + let f: &Foo = &f; let &Foo { a: _, b: ref bar } = f; assert_eq!(bar.get(), 11); // Make sure that drop flags don't screw things up - let d : HasDrop> = HasDrop { - ptr: Box::new(0), - data: Baz { a: [1,2,3,4] } - }; - assert_eq!([1,2,3,4], d.data.a); + let d: HasDrop> = HasDrop { ptr: Box::new(0), data: Baz { a: [1, 2, 3, 4] } }; + assert_eq!([1, 2, 3, 4], d.data.a); - let d : &HasDrop> = &d; - assert_eq!(&[1,2,3,4], &d.data.a); + let d: &HasDrop> = &d; + assert_eq!(&[1, 2, 3, 4], &d.data.a); } diff --git a/tests/pass/dst-irrefutable-bind.rs b/tests/pass/dst-irrefutable-bind.rs index eeddfce75fd9..fe7335c0c656 100644 --- a/tests/pass/dst-irrefutable-bind.rs +++ b/tests/pass/dst-irrefutable-bind.rs @@ -1,14 +1,14 @@ struct Test(T); fn main() { - let x = Test([1,2,3]); - let x : &Test<[i32]> = &x; + let x = Test([1, 2, 3]); + let x: &Test<[i32]> = &x; - let & ref _y = x; + let &ref _y = x; // Make sure binding to a fat pointer behind a reference // still works - let slice = &[1,2,3]; + let slice = &[1, 2, 3]; let x = Test(&slice); let Test(&_slice) = x; } diff --git a/tests/pass/dst-raw.rs b/tests/pass/dst-raw.rs index 0fe2b72b8c6a..f26191a1d599 100644 --- a/tests/pass/dst-raw.rs +++ b/tests/pass/dst-raw.rs @@ -1,12 +1,11 @@ // Test DST raw pointers - trait Trait { fn foo(&self) -> isize; } struct A { - f: isize + f: isize, } impl Trait for A { fn foo(&self) -> isize { @@ -15,24 +14,20 @@ impl Trait for A { } struct Foo { - f: T + f: T, } pub fn main() { // raw trait object let x = A { f: 42 }; let z: *const dyn Trait = &x; - let r = unsafe { - (&*z).foo() - }; + let r = unsafe { (&*z).foo() }; assert_eq!(r, 42); // raw DST struct - let p = Foo {f: A { f: 42 }}; + let p = Foo { f: A { f: 42 } }; let o: *const Foo = &p; - let r = unsafe { - (&*o).f.foo() - }; + let r = unsafe { (&*o).f.foo() }; assert_eq!(r, 42); // raw slice @@ -54,7 +49,7 @@ pub fn main() { } // raw DST struct with slice - let c: *const Foo<[_]> = &Foo {f: [1, 2, 3]}; + let c: *const Foo<[_]> = &Foo { f: [1, 2, 3] }; unsafe { let b = (&*c).f[0]; assert_eq!(b, 1); @@ -65,16 +60,12 @@ pub fn main() { // all of the above with *mut let mut x = A { f: 42 }; let z: *mut dyn Trait = &mut x; - let r = unsafe { - (&*z).foo() - }; + let r = unsafe { (&*z).foo() }; assert_eq!(r, 42); - let mut p = Foo {f: A { f: 42 }}; + let mut p = Foo { f: A { f: 42 } }; let o: *mut Foo = &mut p; - let r = unsafe { - (&*o).f.foo() - }; + let r = unsafe { (&*o).f.foo() }; assert_eq!(r, 42); let a: *mut [_] = &mut [1, 2, 3]; @@ -93,7 +84,7 @@ pub fn main() { assert_eq!(len, 3); } - let c: *mut Foo<[_]> = &mut Foo {f: [1, 2, 3]}; + let c: *mut Foo<[_]> = &mut Foo { f: [1, 2, 3] }; unsafe { let b = (&*c).f[0]; assert_eq!(b, 1); diff --git a/tests/pass/dst-struct-sole.rs b/tests/pass/dst-struct-sole.rs index 770af864a44c..4b25fbb06300 100644 --- a/tests/pass/dst-struct-sole.rs +++ b/tests/pass/dst-struct-sole.rs @@ -1,8 +1,7 @@ // As dst-struct.rs, but the unsized field is the only field in the struct. - struct Fat { - ptr: T + ptr: T, } // x is a fat pointer @@ -13,7 +12,7 @@ fn foo(x: &Fat<[isize]>) { assert_eq!(x.ptr[1], 2); } -fn foo2(x: &Fat<[T]>) { +fn foo2(x: &Fat<[T]>) { let y = &x.ptr; let bar = Bar; assert_eq!(x.ptr.len(), 3); diff --git a/tests/pass/dst-struct.rs b/tests/pass/dst-struct.rs index bd6517bd1fd7..7191068eb2c4 100644 --- a/tests/pass/dst-struct.rs +++ b/tests/pass/dst-struct.rs @@ -3,7 +3,7 @@ struct Fat { f1: isize, f2: &'static str, - ptr: T + ptr: T, } // x is a fat pointer @@ -16,7 +16,7 @@ fn foo(x: &Fat<[isize]>) { assert_eq!(x.f2, "some str"); } -fn foo2(x: &Fat<[T]>) { +fn foo2(x: &Fat<[T]>) { let y = &x.ptr; let bar = Bar; assert_eq!(x.ptr.len(), 3); @@ -37,7 +37,6 @@ fn foo3(x: &Fat>) { assert_eq!(x.ptr.ptr[1], 2); } - #[derive(Copy, Clone, PartialEq, Eq, Debug)] struct Bar; @@ -53,9 +52,9 @@ impl ToBar for Bar { pub fn main() { // With a vec of ints. - let f1 : Fat<[isize; 3]> = Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + let f1: Fat<[isize; 3]> = Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; foo(&f1); - let f2 : &Fat<[isize; 3]> = &f1; + let f2: &Fat<[isize; 3]> = &f1; foo(f2); let f3: &Fat<[isize]> = f2; foo(f3); @@ -91,7 +90,7 @@ pub fn main() { assert!(f5.ptr.is_empty()); // Deeply nested. - let f1 = Fat { f1: 5, f2: "some str", ptr: Fat { f1: 8, f2: "deep str", ptr: [1, 2, 3]} }; + let f1 = Fat { f1: 5, f2: "some str", ptr: Fat { f1: 8, f2: "deep str", ptr: [1, 2, 3] } }; foo3(&f1); let f2 = &f1; foo3(f2); @@ -100,7 +99,7 @@ pub fn main() { let f4: &Fat> = &f1; foo3(f4); let f5: &Fat> = - &Fat { f1: 5, f2: "some str", ptr: Fat { f1: 8, f2: "deep str", ptr: [1, 2, 3]} }; + &Fat { f1: 5, f2: "some str", ptr: Fat { f1: 8, f2: "deep str", ptr: [1, 2, 3] } }; foo3(f5); // Box. @@ -110,14 +109,14 @@ pub fn main() { assert_eq!((*f2)[1], 2); // Nested Box. - let f1 : Box> = box Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + let f1: Box> = box Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; foo(&*f1); - let f2 : Box> = f1; + let f2: Box> = f1; foo(&*f2); - let f3 : Box> = + let f3: Box> = Box::>::new(Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }); foo(&*f3); - let f4 : Box> = box Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + let f4: Box> = box Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; foo(&*f4); } diff --git a/tests/pass/dyn-arbitrary-self.rs b/tests/pass/dyn-arbitrary-self.rs index 5c19c260dd95..256c72add922 100644 --- a/tests/pass/dyn-arbitrary-self.rs +++ b/tests/pass/dyn-arbitrary-self.rs @@ -19,11 +19,7 @@ fn pin_box_dyn() { } fn stdlib_pointers() { - use std::{ - rc::Rc, - sync::Arc, - pin::Pin, - }; + use std::{pin::Pin, rc::Rc, sync::Arc}; trait Trait { fn by_rc(self: Rc) -> i64; @@ -63,8 +59,8 @@ fn stdlib_pointers() { fn pointers_and_wrappers() { use std::{ - ops::{Deref, CoerceUnsized, DispatchFromDyn}, marker::Unsize, + ops::{CoerceUnsized, Deref, DispatchFromDyn}, }; struct Ptr(Box); @@ -93,7 +89,6 @@ fn pointers_and_wrappers() { impl, U> CoerceUnsized> for Wrapper {} impl, U> DispatchFromDyn> for Wrapper {} - trait Trait { // This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable // without unsized_locals), but wrappers arond `Self` currently are not. @@ -126,7 +121,6 @@ fn pointers_and_wrappers() { assert_eq!(wpw.wrapper_ptr_wrapper(), 7); } - fn main() { pin_box_dyn(); stdlib_pointers(); diff --git a/tests/pass/dyn-traits.rs b/tests/pass/dyn-traits.rs index 51c2130bcd3f..00667757b048 100644 --- a/tests/pass/dyn-traits.rs +++ b/tests/pass/dyn-traits.rs @@ -39,7 +39,6 @@ fn ref_box_dyn() { y.box_method(); } - fn box_box_trait() { struct DroppableStruct; @@ -47,17 +46,23 @@ fn box_box_trait() { impl Drop for DroppableStruct { fn drop(&mut self) { - unsafe { DROPPED = true; } + unsafe { + DROPPED = true; + } } } - trait MyTrait { fn dummy(&self) { } } + trait MyTrait { + fn dummy(&self) {} + } impl MyTrait for Box {} - struct Whatever { w: Box } + struct Whatever { + w: Box, + } - impl Whatever { - fn new(w: Box) -> Whatever { + impl Whatever { + fn new(w: Box) -> Whatever { Whatever { w: w } } } diff --git a/tests/pass/enum-nullable-const-null-with-fields.rs b/tests/pass/enum-nullable-const-null-with-fields.rs index 87389c9c3a81..8385cc5d880c 100644 --- a/tests/pass/enum-nullable-const-null-with-fields.rs +++ b/tests/pass/enum-nullable-const-null-with-fields.rs @@ -1,4 +1,3 @@ - use std::result::Result; use std::result::Result::Ok; diff --git a/tests/pass/enums.rs b/tests/pass/enums.rs index d399beb91b2f..d2dc06525475 100644 --- a/tests/pass/enums.rs +++ b/tests/pass/enums.rs @@ -2,24 +2,21 @@ enum MyEnum { MyEmptyVariant, MyNewtypeVariant(i32), MyTupleVariant(i32, i32), - MyStructVariant { - my_first_field: i32, - my_second_field: i32, - } + MyStructVariant { my_first_field: i32, my_second_field: i32 }, } fn test(me: MyEnum) { match me { - MyEnum::MyEmptyVariant => {}, + MyEnum::MyEmptyVariant => {} MyEnum::MyNewtypeVariant(ref val) => assert_eq!(val, &42), MyEnum::MyTupleVariant(ref a, ref b) => { assert_eq!(a, &43); assert_eq!(b, &44); - }, + } MyEnum::MyStructVariant { ref my_first_field, ref my_second_field } => { assert_eq!(my_first_field, &45); assert_eq!(my_second_field, &46); - }, + } } } @@ -41,7 +38,7 @@ fn discriminant_overflow() { let x = Foo::B; match x { - Foo::B => {}, + Foo::B => {} _ => panic!(), } } @@ -126,10 +123,7 @@ fn main() { test(MyEnum::MyEmptyVariant); test(MyEnum::MyNewtypeVariant(42)); test(MyEnum::MyTupleVariant(43, 44)); - test(MyEnum::MyStructVariant{ - my_first_field: 45, - my_second_field: 46, - }); + test(MyEnum::MyStructVariant { my_first_field: 45, my_second_field: 46 }); discriminant_overflow(); more_discriminant_overflow(); diff --git a/tests/pass/extern_types.rs b/tests/pass/extern_types.rs index b37cd8408ba1..aa4c65ea8928 100644 --- a/tests/pass/extern_types.rs +++ b/tests/pass/extern_types.rs @@ -1,6 +1,6 @@ #![feature(extern_types)] -extern { +extern "C" { type Foo; } diff --git a/tests/pass/fat_ptr.rs b/tests/pass/fat_ptr.rs index 55418c4802a7..8317156a218d 100644 --- a/tests/pass/fat_ptr.rs +++ b/tests/pass/fat_ptr.rs @@ -3,7 +3,7 @@ struct Wrapper(u32, T); struct FatPtrContainer<'a> { - ptr: &'a [u8] + ptr: &'a [u8], } fn fat_ptr_project(a: &Wrapper<[u8]>) -> &[u8] { @@ -36,14 +36,14 @@ fn fat_ptr_constant() -> &'static str { } fn main() { - let a = Wrapper(4, [7,6,5]); + let a = Wrapper(4, [7, 6, 5]); let p = fat_ptr_project(&a); let p = fat_ptr_simple(p); let p = fat_ptr_via_local(p); let p = fat_ptr_from_struct(fat_ptr_to_struct(p)); - let mut target : &[u8] = &[42]; + let mut target: &[u8] = &[42]; fat_ptr_store_to(p, &mut target); assert_eq!(target, &a.1); diff --git a/tests/pass/float.rs b/tests/pass/float.rs index e40ea919dca1..48dd99441ebf 100644 --- a/tests/pass/float.rs +++ b/tests/pass/float.rs @@ -26,60 +26,110 @@ trait FloatToInt: Copy { } impl FloatToInt for f32 { - fn cast(self) -> i8 { self as _ } - unsafe fn cast_unchecked(self) -> i8 { self.to_int_unchecked() } + fn cast(self) -> i8 { + self as _ + } + unsafe fn cast_unchecked(self) -> i8 { + self.to_int_unchecked() + } } impl FloatToInt for f32 { - fn cast(self) -> i32 { self as _ } - unsafe fn cast_unchecked(self) -> i32 { self.to_int_unchecked() } + fn cast(self) -> i32 { + self as _ + } + unsafe fn cast_unchecked(self) -> i32 { + self.to_int_unchecked() + } } impl FloatToInt for f32 { - fn cast(self) -> u32 { self as _ } - unsafe fn cast_unchecked(self) -> u32 { self.to_int_unchecked() } + fn cast(self) -> u32 { + self as _ + } + unsafe fn cast_unchecked(self) -> u32 { + self.to_int_unchecked() + } } impl FloatToInt for f32 { - fn cast(self) -> i64 { self as _ } - unsafe fn cast_unchecked(self) -> i64 { self.to_int_unchecked() } + fn cast(self) -> i64 { + self as _ + } + unsafe fn cast_unchecked(self) -> i64 { + self.to_int_unchecked() + } } impl FloatToInt for f32 { - fn cast(self) -> u64 { self as _ } - unsafe fn cast_unchecked(self) -> u64 { self.to_int_unchecked() } + fn cast(self) -> u64 { + self as _ + } + unsafe fn cast_unchecked(self) -> u64 { + self.to_int_unchecked() + } } impl FloatToInt for f64 { - fn cast(self) -> i8 { self as _ } - unsafe fn cast_unchecked(self) -> i8 { self.to_int_unchecked() } + fn cast(self) -> i8 { + self as _ + } + unsafe fn cast_unchecked(self) -> i8 { + self.to_int_unchecked() + } } impl FloatToInt for f64 { - fn cast(self) -> i32 { self as _ } - unsafe fn cast_unchecked(self) -> i32 { self.to_int_unchecked() } + fn cast(self) -> i32 { + self as _ + } + unsafe fn cast_unchecked(self) -> i32 { + self.to_int_unchecked() + } } impl FloatToInt for f64 { - fn cast(self) -> u32 { self as _ } - unsafe fn cast_unchecked(self) -> u32 { self.to_int_unchecked() } + fn cast(self) -> u32 { + self as _ + } + unsafe fn cast_unchecked(self) -> u32 { + self.to_int_unchecked() + } } impl FloatToInt for f64 { - fn cast(self) -> i64 { self as _ } - unsafe fn cast_unchecked(self) -> i64 { self.to_int_unchecked() } + fn cast(self) -> i64 { + self as _ + } + unsafe fn cast_unchecked(self) -> i64 { + self.to_int_unchecked() + } } impl FloatToInt for f64 { - fn cast(self) -> u64 { self as _ } - unsafe fn cast_unchecked(self) -> u64 { self.to_int_unchecked() } + fn cast(self) -> u64 { + self as _ + } + unsafe fn cast_unchecked(self) -> u64 { + self.to_int_unchecked() + } } impl FloatToInt for f64 { - fn cast(self) -> i128 { self as _ } - unsafe fn cast_unchecked(self) -> i128 { self.to_int_unchecked() } + fn cast(self) -> i128 { + self as _ + } + unsafe fn cast_unchecked(self) -> i128 { + self.to_int_unchecked() + } } impl FloatToInt for f64 { - fn cast(self) -> u128 { self as _ } - unsafe fn cast_unchecked(self) -> u128 { self.to_int_unchecked() } + fn cast(self) -> u128 { + self as _ + } + unsafe fn cast_unchecked(self) -> u128 { + self.to_int_unchecked() + } } /// Test this cast both via `as` and via `approx_unchecked` (i.e., it must not saturate). #[track_caller] #[inline(never)] fn test_both_cast(x: F, y: I) - where F: FloatToInt, I: PartialEq + Debug +where + F: FloatToInt, + I: PartialEq + Debug, { assert_eq!(x.cast(), y); assert_eq!(unsafe { x.cast_unchecked() }, y); @@ -87,15 +137,15 @@ fn test_both_cast(x: F, y: I) fn basic() { // basic arithmetic - assert_eq(6.0_f32*6.0_f32, 36.0_f32); - assert_eq(6.0_f64*6.0_f64, 36.0_f64); - assert_eq(-{5.0_f32}, -5.0_f32); - assert_eq(-{5.0_f64}, -5.0_f64); + assert_eq(6.0_f32 * 6.0_f32, 36.0_f32); + assert_eq(6.0_f64 * 6.0_f64, 36.0_f64); + assert_eq(-{ 5.0_f32 }, -5.0_f32); + assert_eq(-{ 5.0_f64 }, -5.0_f64); // infinities, NaN - assert!((5.0_f32/0.0).is_infinite()); - assert_ne!({5.0_f32/0.0}, {-5.0_f32/0.0}); - assert!((5.0_f64/0.0).is_infinite()); - assert_ne!({5.0_f64/0.0}, {5.0_f64/-0.0}); + assert!((5.0_f32 / 0.0).is_infinite()); + assert_ne!({ 5.0_f32 / 0.0 }, { -5.0_f32 / 0.0 }); + assert!((5.0_f64 / 0.0).is_infinite()); + assert_ne!({ 5.0_f64 / 0.0 }, { 5.0_f64 / -0.0 }); assert!((-5.0_f32).sqrt().is_nan()); assert!((-5.0_f64).sqrt().is_nan()); assert_ne!(f32::NAN, f32::NAN); @@ -161,9 +211,9 @@ fn casts() { test_both_cast::(4294967040.0, 0u32.wrapping_sub(256)); test_both_cast::(/*-0x1.ccccccp-1*/ f32::from_bits(0xbf666666), 0); test_both_cast::(/*-0x1.fffffep-1*/ f32::from_bits(0xbf7fffff), 0); - test_both_cast::((u32::MAX-128) as f32, u32::MAX-255); // rounding loss + test_both_cast::((u32::MAX - 128) as f32, u32::MAX - 255); // rounding loss // unrepresentable casts - assert_eq::((u32::MAX-127) as f32 as u32, u32::MAX); // rounds up and then becomes unrepresentable + assert_eq::((u32::MAX - 127) as f32 as u32, u32::MAX); // rounds up and then becomes unrepresentable assert_eq::(4294967296.0f32 as u32, u32::MAX); assert_eq::(-5.0f32 as u32, 0); assert_eq::(f32::MAX as u32, u32::MAX); @@ -187,7 +237,10 @@ fn casts() { test_both_cast::(0.0, 0); test_both_cast::(-0.0, 0); test_both_cast::(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a), 1); - test_both_cast::(/*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a), -1); + test_both_cast::( + /*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a), + -1, + ); test_both_cast::(1.9, 1); test_both_cast::(-1.9, -1); test_both_cast::(1e8, 100_000_000); @@ -201,9 +254,15 @@ fn casts() { test_both_cast::(0.0, 0); test_both_cast::(-0.0, 0); test_both_cast::(/*0x0.0000000000001p-1022*/ f64::from_bits(0x1), 0); - test_both_cast::(/*-0x0.0000000000001p-1022*/ f64::from_bits(0x8000000000000001), 0); + test_both_cast::( + /*-0x0.0000000000001p-1022*/ f64::from_bits(0x8000000000000001), + 0, + ); test_both_cast::(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a), 1); - test_both_cast::(/*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a), -1); + test_both_cast::( + /*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a), + -1, + ); test_both_cast::(5.0, 5); test_both_cast::(5.9, 5); test_both_cast::(-5.0, -5); @@ -228,11 +287,11 @@ fn casts() { test_both_cast::(-0.99999999999, 0); test_both_cast::(5.0, 5); test_both_cast::(1e16, 10000000000000000); - test_both_cast::((u64::MAX-1024) as f64, u64::MAX-2047); // rounding loss + test_both_cast::((u64::MAX - 1024) as f64, u64::MAX - 2047); // rounding loss test_both_cast::(9223372036854775808.0, 9223372036854775808); // unrepresentable casts assert_eq::(-5.0f64 as u64, 0); - assert_eq::((u64::MAX-1023) as f64 as u64, u64::MAX); // rounds up and then becomes unrepresentable + assert_eq::((u64::MAX - 1023) as f64 as u64, u64::MAX); // rounds up and then becomes unrepresentable assert_eq::(18446744073709551616.0f64 as u64, u64::MAX); assert_eq::(f64::MAX as u64, u64::MAX); assert_eq::(f64::MIN as u64, 0); @@ -258,10 +317,22 @@ fn casts() { assert_eq::((-16777217i32) as f32, -16777216.0); assert_eq::(16777219i32 as f32, 16777220.0); assert_eq::((-16777219i32) as f32, -16777220.0); - assert_eq::(0x7fffff4000000001i64 as f32, /*0x1.fffffep+62*/ f32::from_bits(0x5effffff)); - assert_eq::(0x8000004000000001u64 as i64 as f32, /*-0x1.fffffep+62*/ f32::from_bits(0xdeffffff)); - assert_eq::(0x0020000020000001i64 as f32, /*0x1.000002p+53*/ f32::from_bits(0x5a000001)); - assert_eq::(0xffdfffffdfffffffu64 as i64 as f32, /*-0x1.000002p+53*/ f32::from_bits(0xda000001)); + assert_eq::( + 0x7fffff4000000001i64 as f32, + /*0x1.fffffep+62*/ f32::from_bits(0x5effffff), + ); + assert_eq::( + 0x8000004000000001u64 as i64 as f32, + /*-0x1.fffffep+62*/ f32::from_bits(0xdeffffff), + ); + assert_eq::( + 0x0020000020000001i64 as f32, + /*0x1.000002p+53*/ f32::from_bits(0x5a000001), + ); + assert_eq::( + 0xffdfffffdfffffffu64 as i64 as f32, + /*-0x1.000002p+53*/ f32::from_bits(0xda000001), + ); assert_eq::(i128::MIN as f32, -170141183460469231731687303715884105728.0f32); assert_eq::(u128::MAX as f32, f32::INFINITY); // saturation @@ -284,12 +355,30 @@ fn casts() { assert_eq::((0.0f32 as f64).to_bits(), 0.0f64.to_bits()); assert_eq::(((-0.0f32) as f64).to_bits(), (-0.0f64).to_bits()); assert_eq::(5.0f32 as f64, 5.0f64); - assert_eq::(/*0x1p-149*/ f32::from_bits(0x1) as f64, /*0x1p-149*/ f64::from_bits(0x36a0000000000000)); - assert_eq::(/*-0x1p-149*/ f32::from_bits(0x80000001) as f64, /*-0x1p-149*/ f64::from_bits(0xb6a0000000000000)); - assert_eq::(/*0x1.fffffep+127*/ f32::from_bits(0x7f7fffff) as f64, /*0x1.fffffep+127*/ f64::from_bits(0x47efffffe0000000)); - assert_eq::(/*-0x1.fffffep+127*/ (-f32::from_bits(0x7f7fffff)) as f64, /*-0x1.fffffep+127*/ -f64::from_bits(0x47efffffe0000000)); - assert_eq::(/*0x1p-119*/ f32::from_bits(0x4000000) as f64, /*0x1p-119*/ f64::from_bits(0x3880000000000000)); - assert_eq::(/*0x1.8f867ep+125*/ f32::from_bits(0x7e47c33f) as f64, 6.6382536710104395e+37); + assert_eq::( + /*0x1p-149*/ f32::from_bits(0x1) as f64, + /*0x1p-149*/ f64::from_bits(0x36a0000000000000), + ); + assert_eq::( + /*-0x1p-149*/ f32::from_bits(0x80000001) as f64, + /*-0x1p-149*/ f64::from_bits(0xb6a0000000000000), + ); + assert_eq::( + /*0x1.fffffep+127*/ f32::from_bits(0x7f7fffff) as f64, + /*0x1.fffffep+127*/ f64::from_bits(0x47efffffe0000000), + ); + assert_eq::( + /*-0x1.fffffep+127*/ (-f32::from_bits(0x7f7fffff)) as f64, + /*-0x1.fffffep+127*/ -f64::from_bits(0x47efffffe0000000), + ); + assert_eq::( + /*0x1p-119*/ f32::from_bits(0x4000000) as f64, + /*0x1p-119*/ f64::from_bits(0x3880000000000000), + ); + assert_eq::( + /*0x1.8f867ep+125*/ f32::from_bits(0x7e47c33f) as f64, + 6.6382536710104395e+37, + ); assert_eq::(f32::INFINITY as f64, f64::INFINITY); assert_eq::(f32::NEG_INFINITY as f64, f64::NEG_INFINITY); @@ -299,8 +388,14 @@ fn casts() { assert_eq::(5.0f64 as f32, 5.0f32); assert_eq::(/*0x0.0000000000001p-1022*/ f64::from_bits(0x1) as f32, 0.0); assert_eq::(/*-0x0.0000000000001p-1022*/ (-f64::from_bits(0x1)) as f32, -0.0); - assert_eq::(/*0x1.fffffe0000000p-127*/ f64::from_bits(0x380fffffe0000000) as f32, /*0x1p-149*/ f32::from_bits(0x800000)); - assert_eq::(/*0x1.4eae4f7024c7p+108*/ f64::from_bits(0x46b4eae4f7024c70) as f32, /*0x1.4eae5p+108*/ f32::from_bits(0x75a75728)); + assert_eq::( + /*0x1.fffffe0000000p-127*/ f64::from_bits(0x380fffffe0000000) as f32, + /*0x1p-149*/ f32::from_bits(0x800000), + ); + assert_eq::( + /*0x1.4eae4f7024c7p+108*/ f64::from_bits(0x46b4eae4f7024c70) as f32, + /*0x1.4eae5p+108*/ f32::from_bits(0x75a75728), + ); assert_eq::(f64::MAX as f32, f32::INFINITY); assert_eq::(f64::MIN as f32, f32::NEG_INFINITY); assert_eq::(f64::INFINITY as f32, f32::INFINITY); diff --git a/tests/pass/float_fast_math.rs b/tests/pass/float_fast_math.rs index 8e5a88ff336a..52d985667df2 100644 --- a/tests/pass/float_fast_math.rs +++ b/tests/pass/float_fast_math.rs @@ -1,6 +1,6 @@ #![feature(core_intrinsics)] -use std::intrinsics::{fadd_fast, fsub_fast, fmul_fast, fdiv_fast, frem_fast}; +use std::intrinsics::{fadd_fast, fdiv_fast, fmul_fast, frem_fast, fsub_fast}; #[inline(never)] pub fn test_operations_f64(a: f64, b: f64) { diff --git a/tests/pass/foreign-fn-linkname.rs b/tests/pass/foreign-fn-linkname.rs index 60303c7d7c7c..391b182fda03 100644 --- a/tests/pass/foreign-fn-linkname.rs +++ b/tests/pass/foreign-fn-linkname.rs @@ -7,7 +7,7 @@ use std::ffi::CString; mod mlibc { use libc::{c_char, size_t}; - extern { + extern "C" { #[link_name = "strlen"] pub fn my_strlen(str: *const c_char) -> size_t; } @@ -16,9 +16,7 @@ mod mlibc { fn strlen(str: String) -> usize { // C string is terminated with a zero let s = CString::new(str).unwrap(); - unsafe { - mlibc::my_strlen(s.as_ptr()) as usize - } + unsafe { mlibc::my_strlen(s.as_ptr()) as usize } } pub fn main() { diff --git a/tests/pass/fs_with_isolation.rs b/tests/pass/fs_with_isolation.rs index cd91cd9be30e..6753145e92b2 100644 --- a/tests/pass/fs_with_isolation.rs +++ b/tests/pass/fs_with_isolation.rs @@ -7,9 +7,9 @@ extern crate libc; use std::ffi::CString; -use std::os::unix; use std::fs::{self, File}; use std::io::{Error, ErrorKind}; +use std::os::unix; fn main() { // test `open` @@ -25,7 +25,10 @@ fn main() { assert_eq!(fs::remove_file("foo.txt").unwrap_err().kind(), ErrorKind::PermissionDenied); // test `symlink` - assert_eq!(unix::fs::symlink("foo.txt", "foo_link.txt").unwrap_err().kind(), ErrorKind::PermissionDenied); + assert_eq!( + unix::fs::symlink("foo.txt", "foo_link.txt").unwrap_err().kind(), + ErrorKind::PermissionDenied + ); // test `readlink` let symlink_c_str = CString::new("foo.txt").unwrap(); diff --git a/tests/pass/function_calls/exported_symbol.rs b/tests/pass/function_calls/exported_symbol.rs index ff56bb78a218..27aee9c88358 100644 --- a/tests/pass/function_calls/exported_symbol.rs +++ b/tests/pass/function_calls/exported_symbol.rs @@ -24,7 +24,6 @@ impl AssocFn { } } - fn main() { // Repeat calls to make sure the `Instance` cache is not broken. for _ in 0..3 { @@ -69,9 +68,8 @@ fn main() { } unsafe { - let transmute = |f| { - std::mem::transmute:: i32, unsafe fn() -> i32>(f) - }; + let transmute = + |f| std::mem::transmute:: i32, unsafe fn() -> i32>(f); assert_eq!(transmute(bar)(), -2); assert_eq!(transmute(baz)(), -3); assert_eq!(transmute(qux)(), -4); diff --git a/tests/pass/function_pointers.rs b/tests/pass/function_pointers.rs index e7d9b2ddd98c..b66826e3fcdf 100644 --- a/tests/pass/function_pointers.rs +++ b/tests/pass/function_pointers.rs @@ -16,7 +16,7 @@ fn f() -> T { } fn g(i: i32) -> i32 { - i*42 + i * 42 } fn h(i: i32, j: i32) -> i32 { @@ -31,17 +31,35 @@ fn call_fn_ptr() -> i32 { return_fn_ptr(f)() } -fn indirect i32>(f: F) -> i32 { f() } -fn indirect_mut i32>(mut f: F) -> i32 { f() } -fn indirect_once i32>(f: F) -> i32 { f() } +fn indirect i32>(f: F) -> i32 { + f() +} +fn indirect_mut i32>(mut f: F) -> i32 { + f() +} +fn indirect_once i32>(f: F) -> i32 { + f() +} -fn indirect2 i32>(f: F) -> i32 { f(10) } -fn indirect_mut2 i32>(mut f: F) -> i32 { f(10) } -fn indirect_once2 i32>(f: F) -> i32 { f(10) } +fn indirect2 i32>(f: F) -> i32 { + f(10) +} +fn indirect_mut2 i32>(mut f: F) -> i32 { + f(10) +} +fn indirect_once2 i32>(f: F) -> i32 { + f(10) +} -fn indirect3 i32>(f: F) -> i32 { f(10, 3) } -fn indirect_mut3 i32>(mut f: F) -> i32 { f(10, 3) } -fn indirect_once3 i32>(f: F) -> i32 { f(10, 3) } +fn indirect3 i32>(f: F) -> i32 { + f(10, 3) +} +fn indirect_mut3 i32>(mut f: F) -> i32 { + f(10, 3) +} +fn indirect_once3 i32>(f: F) -> i32 { + f(10, 3) +} fn main() { assert_eq!(call_fn_ptr(), 42); From fafeccaef73bfd1fe9e1f9ab49f0dc050d6fd54c Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 20 Jun 2022 15:39:27 -0700 Subject: [PATCH 3301/5092] Bless stdout files after rustfmt --- tests/pass/backtrace/backtrace-api-v0.stdout | 10 +++++----- tests/pass/backtrace/backtrace-api-v1.stdout | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/pass/backtrace/backtrace-api-v0.stdout b/tests/pass/backtrace/backtrace-api-v0.stdout index 9de1d034bb73..2fe31dd0e6ba 100644 --- a/tests/pass/backtrace/backtrace-api-v0.stdout +++ b/tests/pass/backtrace/backtrace-api-v0.stdout @@ -1,5 +1,5 @@ -$DIR/backtrace-api-v0.rs:11:59 (func_d) -$DIR/backtrace-api-v0.rs:10:50 (func_c) -$DIR/backtrace-api-v0.rs:4:53 (func_b) -$DIR/backtrace-api-v0.rs:3:50 (func_a) -$DIR/backtrace-api-v0.rs:15:18 (main) +$DIR/backtrace-api-v0.rs:24:14 (func_d) +$DIR/backtrace-api-v0.rs:20:5 (func_c) +$DIR/backtrace-api-v0.rs:9:5 (func_b) +$DIR/backtrace-api-v0.rs:5:5 (func_a) +$DIR/backtrace-api-v0.rs:29:18 (main) diff --git a/tests/pass/backtrace/backtrace-api-v1.stdout b/tests/pass/backtrace/backtrace-api-v1.stdout index b820a1be0a19..0d2ae3b516a8 100644 --- a/tests/pass/backtrace/backtrace-api-v1.stdout +++ b/tests/pass/backtrace/backtrace-api-v1.stdout @@ -1,5 +1,5 @@ -$DIR/backtrace-api-v1.rs:11:144 (func_d) -$DIR/backtrace-api-v1.rs:10:50 (func_c) -$DIR/backtrace-api-v1.rs:4:53 (func_b) -$DIR/backtrace-api-v1.rs:3:50 (func_a) -$DIR/backtrace-api-v1.rs:15:18 (main) +$DIR/backtrace-api-v1.rs:27:9 (func_d) +$DIR/backtrace-api-v1.rs:20:5 (func_c) +$DIR/backtrace-api-v1.rs:9:5 (func_b) +$DIR/backtrace-api-v1.rs:5:5 (func_a) +$DIR/backtrace-api-v1.rs:34:18 (main) From df8d8b655b9ff5c1a941697119cc7fac41e77321 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 20 Jun 2022 16:00:37 -0700 Subject: [PATCH 3302/5092] Format tests with rustfmt (101-150 of 300) --- tests/pass/generator.rs | 30 +++++-- tests/pass/hashmap.rs | 8 +- tests/pass/integer-ops.rs | 10 +-- tests/pass/intrinsics-math.rs | 9 +- tests/pass/intrinsics.rs | 10 ++- tests/pass/ints.rs | 4 +- tests/pass/issues/issue-15063.rs | 8 +- tests/pass/issues/issue-15080.rs | 5 +- tests/pass/issues/issue-15523-big.rs | 1 - tests/pass/issues/issue-17877.rs | 22 +++-- tests/pass/issues/issue-23261.rs | 2 +- tests/pass/issues/issue-27901.rs | 8 +- tests/pass/issues/issue-29746.rs | 10 +-- tests/pass/issues/issue-30530.rs | 3 +- tests/pass/issues/issue-34571.rs | 2 +- .../pass/issues/issue-36278-prefix-nesting.rs | 5 +- tests/pass/issues/issue-5917.rs | 7 +- tests/pass/issues/issue-miri-133.rs | 9 +- tests/pass/issues/issue-miri-2068-2.rs | 22 ++--- tests/pass/last-use-in-cap-clause.rs | 8 +- tests/pass/leak-in-static.rs | 5 +- tests/pass/libc.rs | 86 +++++++++++++------ tests/pass/linked-list.rs | 3 +- .../pass/linux-getrandom-without-isolation.rs | 34 +++++++- tests/pass/linux-getrandom.rs | 34 +++++++- tests/pass/loop-break-value.rs | 20 ++--- tests/pass/malloc.rs | 2 +- tests/pass/many_shr_bor.rs | 2 +- tests/pass/match_slice.rs | 6 +- tests/pass/move-arg-2-unique.rs | 4 +- tests/pass/move-uninit-primval.rs | 4 +- tests/pass/negative_discriminant.rs | 5 +- tests/pass/overflow_checks_off.rs | 2 +- tests/pass/overloaded-calls-simple.rs | 10 +-- tests/pass/packed_struct.rs | 34 ++++---- tests/pass/partially-uninit.rs | 16 ++-- tests/pass/pointers.rs | 7 +- tests/pass/portable-simd.rs | 16 ++-- tests/pass/products.rs | 7 +- tests/pass/ptr_offset.rs | 30 ++++--- tests/pass/ptr_raw.rs | 8 +- tests/pass/rc.rs | 10 +-- tests/pass/regions-mock-trans.rs | 19 ++-- tests/pass/send-is-not-static-par-for.rs | 15 ++-- tests/pass/sendable-class.rs | 7 +- tests/pass/simd-intrinsic-generic-elements.rs | 4 +- tests/pass/slices.rs | 35 ++++---- tests/pass/specialization.rs | 8 +- tests/pass/stacked-borrows/2phase.rs | 34 ++++---- .../stacked-borrows/interior_mutability.rs | 18 ++-- 50 files changed, 395 insertions(+), 273 deletions(-) diff --git a/tests/pass/generator.rs b/tests/pass/generator.rs index 9d786edc5ae2..06f48666c557 100644 --- a/tests/pass/generator.rs +++ b/tests/pass/generator.rs @@ -1,15 +1,19 @@ #![feature(generators, generator_trait, never_type)] -use std::ops::{GeneratorState::{self, *}, Generator}; -use std::pin::Pin; -use std::sync::atomic::{AtomicUsize, Ordering}; use std::fmt::Debug; use std::mem::ManuallyDrop; +use std::ops::{ + Generator, + GeneratorState::{self, *}, +}; +use std::pin::Pin; use std::ptr; +use std::sync::atomic::{AtomicUsize, Ordering}; fn basic() { fn finish(mut amt: usize, mut t: T) -> T::Return - where T: Generator + where + T: Generator, { // We are not moving the `t` around until it gets dropped, so this is okay. let mut t = unsafe { Pin::new_unchecked(&mut t) }; @@ -23,7 +27,7 @@ fn basic() { } GeneratorState::Complete(ret) => { assert_eq!(amt, 0); - return ret + return ret; } } } @@ -46,7 +50,7 @@ fn basic() { assert_eq!(x, 2); }); - finish(7*8/2, || { + finish(7 * 8 / 2, || { for i in 0..8 { yield i; } @@ -67,7 +71,10 @@ fn basic() { }); finish(2, || { - if { yield 1; false } { + if { + yield 1; + false + } { yield 1; panic!() } @@ -90,7 +97,9 @@ fn basic() { let b = true; finish(1, || { yield 1; - if b { return; } + if b { + return; + } #[allow(unused)] let x = never(); #[allow(unreachable_code)] @@ -101,7 +110,10 @@ fn basic() { finish(3, || { yield 1; #[allow(unreachable_code)] - let _x: (String, !) = (String::new(), { yield 2; return }); + let _x: (String, !) = (String::new(), { + yield 2; + return; + }); }); } diff --git a/tests/pass/hashmap.rs b/tests/pass/hashmap.rs index 215f762efcc9..29ddd6c59a1a 100644 --- a/tests/pass/hashmap.rs +++ b/tests/pass/hashmap.rs @@ -17,19 +17,19 @@ fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator fn smoketest_map(mut map: HashMap) { map.insert(0, 0); - assert_eq!(map.values().fold(0, |x, y| x+y), 0); + assert_eq!(map.values().fold(0, |x, y| x + y), 0); let num = 25; for i in 1..num { map.insert(i, i); } - assert_eq!(map.values().fold(0, |x, y| x+y), num*(num-1)/2); // check the right things are in the table now + assert_eq!(map.values().fold(0, |x, y| x + y), num * (num - 1) / 2); // check the right things are in the table now // Inserting again replaces the existing entries for i in 0..num { - map.insert(i, num-1-i); + map.insert(i, num - 1 - i); } - assert_eq!(map.values().fold(0, |x, y| x+y), num*(num-1)/2); + assert_eq!(map.values().fold(0, |x, y| x + y), num * (num - 1) / 2); test_all_refs(&mut 13, map.values_mut()); } diff --git a/tests/pass/integer-ops.rs b/tests/pass/integer-ops.rs index 764b2dca82ca..8e2799d68905 100644 --- a/tests/pass/integer-ops.rs +++ b/tests/pass/integer-ops.rs @@ -42,7 +42,7 @@ pub fn main() { let m = -0xFEDCBA987654322i64; assert_eq!(n.rotate_right(4), m); - let n = 0x0123456789ABCDEFi64; + let n = 0x0123456789ABCDEFi64; let m = -0x1032547698BADCFFi64; assert_eq!(n.swap_bytes(), m); @@ -169,9 +169,9 @@ pub fn main() { assert_eq!(0x10i32.overflowing_shr(4), (0x1, false)); assert_eq!(0x10i32.overflowing_shr(36), (0x1, true)); - assert_eq!(10i8.overflowing_abs(), (10,false)); - assert_eq!((-10i8).overflowing_abs(), (10,false)); - assert_eq!((-128i8).overflowing_abs(), (-128,true)); + assert_eq!(10i8.overflowing_abs(), (10, false)); + assert_eq!((-10i8).overflowing_abs(), (10, false)); + assert_eq!((-128i8).overflowing_abs(), (-128, true)); // Logarithms macro_rules! test_log { @@ -180,7 +180,7 @@ pub fn main() { assert_eq!($type::MIN.checked_log10(), None); assert_eq!($type::MAX.checked_log2(), Some($max_log2)); assert_eq!($type::MAX.checked_log10(), Some($max_log10)); - } + }; } test_log!(i8, 6, 2); diff --git a/tests/pass/intrinsics-math.rs b/tests/pass/intrinsics-math.rs index 98cb87ee9342..0cb42580fcb2 100644 --- a/tests/pass/intrinsics-math.rs +++ b/tests/pass/intrinsics-math.rs @@ -9,15 +9,14 @@ // except according to those terms. macro_rules! assert_approx_eq { - ($a:expr, $b:expr) => ({ + ($a:expr, $b:expr) => {{ let (a, b) = (&$a, &$b); - assert!((*a - *b).abs() < 1.0e-6, - "{} is not approximately equal to {}", *a, *b); - }) + assert!((*a - *b).abs() < 1.0e-6, "{} is not approximately equal to {}", *a, *b); + }}; } fn ldexp(a: f64, b: i32) -> f64 { - extern { + extern "C" { fn ldexp(x: f64, n: i32) -> f64; } unsafe { ldexp(a, b) } diff --git a/tests/pass/intrinsics.rs b/tests/pass/intrinsics.rs index 6885641c02ea..9e310082f359 100644 --- a/tests/pass/intrinsics.rs +++ b/tests/pass/intrinsics.rs @@ -20,8 +20,12 @@ fn main() { assert_eq!(size_of_val(&[1, 2, 3] as &[i32]), 12); assert_eq!(size_of_val("foobar"), 6); - unsafe { assert_eq!(size_of_val_raw(&[1] as &[i32] as *const [i32]), 4); } - unsafe { assert_eq!(size_of_val_raw(0x100 as *const i32), 4); } + unsafe { + assert_eq!(size_of_val_raw(&[1] as &[i32] as *const [i32]), 4); + } + unsafe { + assert_eq!(size_of_val_raw(0x100 as *const i32), 4); + } assert_eq!(intrinsics::type_name::>(), "core::option::Option"); @@ -33,7 +37,7 @@ fn main() { let _v = intrinsics::discriminant_value(&Some(())); let _v = intrinsics::discriminant_value(&0); let _v = intrinsics::discriminant_value(&true); - let _v = intrinsics::discriminant_value(&vec![1,2,3]); + let _v = intrinsics::discriminant_value(&vec![1, 2, 3]); let addr = &13 as *const i32; let addr2 = (addr as usize).wrapping_add(usize::MAX).wrapping_add(1); diff --git a/tests/pass/ints.rs b/tests/pass/ints.rs index 5d7c383088de..c04c6921f3c4 100644 --- a/tests/pass/ints.rs +++ b/tests/pass/ints.rs @@ -17,7 +17,7 @@ fn indirect_add() -> i64 { } fn arith() -> i32 { - 3*3 + 4*4 + 3 * 3 + 4 * 4 } fn match_int() -> i16 { @@ -48,7 +48,7 @@ fn main() { assert_eq!(neg(), -1); assert_eq!(add(), 3); assert_eq!(indirect_add(), 3); - assert_eq!(arith(), 5*5); + assert_eq!(arith(), 5 * 5); assert_eq!(match_int(), 20); assert_eq!(match_int_range(), 4); assert_eq!(i64::MIN.overflowing_mul(-1), (i64::MIN, true)); diff --git a/tests/pass/issues/issue-15063.rs b/tests/pass/issues/issue-15063.rs index c85590bb8b4b..cbb1b90f6862 100644 --- a/tests/pass/issues/issue-15063.rs +++ b/tests/pass/issues/issue-15063.rs @@ -1,8 +1,10 @@ #[allow(dead_code)] -enum Two { A, B } +enum Two { + A, + B, +} impl Drop for Two { - fn drop(&mut self) { - } + fn drop(&mut self) {} } fn main() { let _k = Two::A; diff --git a/tests/pass/issues/issue-15080.rs b/tests/pass/issues/issue-15080.rs index 2008e6e157db..4a360993116c 100644 --- a/tests/pass/issues/issue-15080.rs +++ b/tests/pass/issues/issue-15080.rs @@ -1,7 +1,7 @@ fn main() { let mut x: &[_] = &[1, 2, 3, 4]; - let mut result = vec!(); + let mut result = vec![]; loop { x = match *x { [1, n, 3, ref rest @ ..] => { @@ -12,8 +12,7 @@ fn main() { result.push(n); rest } - [] => - break + [] => break, } } assert_eq!(result, [2, 4]); diff --git a/tests/pass/issues/issue-15523-big.rs b/tests/pass/issues/issue-15523-big.rs index 75fd8d8dfce8..7c9fec3ab04b 100644 --- a/tests/pass/issues/issue-15523-big.rs +++ b/tests/pass/issues/issue-15523-big.rs @@ -27,7 +27,6 @@ fn main() { assert!(Eu64::Pos2 < Eu64::PosMax); assert!(Eu64::Pos1 < Eu64::PosMax); - assert!(Ei64::Pos2 > Ei64::Pos1); assert!(Ei64::Pos2 > Ei64::Neg1); assert!(Ei64::Pos1 > Ei64::Neg1); diff --git a/tests/pass/issues/issue-17877.rs b/tests/pass/issues/issue-17877.rs index fa24ab9f4aae..a65c5513de00 100644 --- a/tests/pass/issues/issue-17877.rs +++ b/tests/pass/issues/issue-17877.rs @@ -1,11 +1,17 @@ fn main() { - assert_eq!(match [0u8; 16*1024] { - _ => 42_usize, - }, 42_usize); + assert_eq!( + match [0u8; 16 * 1024] { + _ => 42_usize, + }, + 42_usize + ); - assert_eq!(match [0u8; 16*1024] { - [1, ..] => 0_usize, - [0, ..] => 1_usize, - _ => 2_usize - }, 1_usize); + assert_eq!( + match [0u8; 16 * 1024] { + [1, ..] => 0_usize, + [0, ..] => 1_usize, + _ => 2_usize, + }, + 1_usize + ); } diff --git a/tests/pass/issues/issue-23261.rs b/tests/pass/issues/issue-23261.rs index f3c2f58ddbca..f98252c18bf5 100644 --- a/tests/pass/issues/issue-23261.rs +++ b/tests/pass/issues/issue-23261.rs @@ -2,7 +2,7 @@ struct Foo { a: i32, - inner: T + inner: T, } trait Get { diff --git a/tests/pass/issues/issue-27901.rs b/tests/pass/issues/issue-27901.rs index b0822accb6b6..a9f5dc98720f 100644 --- a/tests/pass/issues/issue-27901.rs +++ b/tests/pass/issues/issue-27901.rs @@ -1,5 +1,9 @@ -trait Stream { type Item; } -impl<'a> Stream for &'a str { type Item = u8; } +trait Stream { + type Item; +} +impl<'a> Stream for &'a str { + type Item = u8; +} fn f<'s>(s: &'s str) -> (&'s str, <&'s str as Stream>::Item) { (s, 42) } diff --git a/tests/pass/issues/issue-29746.rs b/tests/pass/issues/issue-29746.rs index d04703d6877c..43bed4464b9c 100644 --- a/tests/pass/issues/issue-29746.rs +++ b/tests/pass/issues/issue-29746.rs @@ -25,11 +25,11 @@ macro_rules! zip { } fn main() { - let p1 = vec![1i32, 2].into_iter(); - let p2 = vec!["10", "20"].into_iter(); - let p3 = vec![100u16, 200].into_iter(); + let p1 = vec![1i32, 2].into_iter(); + let p2 = vec!["10", "20"].into_iter(); + let p3 = vec![100u16, 200].into_iter(); let p4 = vec![1000i64, 2000].into_iter(); - let e = zip!([p1,p2,p3,p4]).collect::>(); - assert_eq!(e[0], (1i32,"10",100u16,1000i64)); + let e = zip!([p1, p2, p3, p4]).collect::>(); + assert_eq!(e[0], (1i32, "10", 100u16, 1000i64)); } diff --git a/tests/pass/issues/issue-30530.rs b/tests/pass/issues/issue-30530.rs index 86c2d9184e01..472b42adaac8 100644 --- a/tests/pass/issues/issue-30530.rs +++ b/tests/pass/issues/issue-30530.rs @@ -21,7 +21,8 @@ pub enum Handler { } fn main() { - #[allow(unused_must_use)] { + #[allow(unused_must_use)] + { take(Handler::Default, Box::new(main)); } } diff --git a/tests/pass/issues/issue-34571.rs b/tests/pass/issues/issue-34571.rs index 28fe076b644d..e1ed8d19e4ea 100644 --- a/tests/pass/issues/issue-34571.rs +++ b/tests/pass/issues/issue-34571.rs @@ -5,6 +5,6 @@ enum Foo { fn main() { match Foo::Foo(1) { - _ => () + _ => (), } } diff --git a/tests/pass/issues/issue-36278-prefix-nesting.rs b/tests/pass/issues/issue-36278-prefix-nesting.rs index cbffbbc0e0f8..6bc8f02c3baf 100644 --- a/tests/pass/issues/issue-36278-prefix-nesting.rs +++ b/tests/pass/issues/issue-36278-prefix-nesting.rs @@ -9,11 +9,12 @@ struct P([u8; SZ], T); type Ack = P>; fn main() { - let size_of_sized; let size_of_unsized; + let size_of_sized; + let size_of_unsized; let x: Box> = Box::new(P([0; SZ], P([0; SZ], [0; 0]))); size_of_sized = mem::size_of_val::>(&x); let align_of_sized = mem::align_of_val::>(&x); - let y: Box> = x; + let y: Box> = x; size_of_unsized = mem::size_of_val::>(&y); assert_eq!(size_of_sized, size_of_unsized); assert_eq!(align_of_sized, 1); diff --git a/tests/pass/issues/issue-5917.rs b/tests/pass/issues/issue-5917.rs index eb506dd3a17e..f7bbb4350e2b 100644 --- a/tests/pass/issues/issue-5917.rs +++ b/tests/pass/issues/issue-5917.rs @@ -1,7 +1,6 @@ - -struct T (&'static [isize]); -static STATIC : T = T (&[5, 4, 3]); -pub fn main () { +struct T(&'static [isize]); +static STATIC: T = T(&[5, 4, 3]); +pub fn main() { let T(ref v) = STATIC; assert_eq!(v[0], 5); } diff --git a/tests/pass/issues/issue-miri-133.rs b/tests/pass/issues/issue-miri-133.rs index 406b5e102c8b..02c973257133 100644 --- a/tests/pass/issues/issue-miri-133.rs +++ b/tests/pass/issues/issue-miri-133.rs @@ -4,17 +4,12 @@ struct S { _u: U, size_of_u: usize, _v: V, - size_of_v: usize + size_of_v: usize, } impl S { fn new(u: U, v: V) -> Self { - S { - _u: u, - size_of_u: size_of::(), - _v: v, - size_of_v: size_of::() - } + S { _u: u, size_of_u: size_of::(), _v: v, size_of_v: size_of::() } } } diff --git a/tests/pass/issues/issue-miri-2068-2.rs b/tests/pass/issues/issue-miri-2068-2.rs index 45b2004e3353..204a4dd05642 100644 --- a/tests/pass/issues/issue-miri-2068-2.rs +++ b/tests/pass/issues/issue-miri-2068-2.rs @@ -2,13 +2,15 @@ use std::mem::MaybeUninit; -fn main() { unsafe { - let mut x = MaybeUninit::::uninit(); - // Put in a ptr. - x.as_mut_ptr().cast::<&i32>().write_unaligned(&0); - // Overwrite parts of that pointer with 'uninit' through a Scalar. - let ptr = x.as_mut_ptr().cast::(); - *ptr = MaybeUninit::uninit().assume_init(); - // Reading this back should hence work fine. - let _c = *ptr; -} } +fn main() { + unsafe { + let mut x = MaybeUninit::::uninit(); + // Put in a ptr. + x.as_mut_ptr().cast::<&i32>().write_unaligned(&0); + // Overwrite parts of that pointer with 'uninit' through a Scalar. + let ptr = x.as_mut_ptr().cast::(); + *ptr = MaybeUninit::uninit().assume_init(); + // Reading this back should hence work fine. + let _c = *ptr; + } +} diff --git a/tests/pass/last-use-in-cap-clause.rs b/tests/pass/last-use-in-cap-clause.rs index 9d137f706bd3..2160aea16346 100644 --- a/tests/pass/last-use-in-cap-clause.rs +++ b/tests/pass/last-use-in-cap-clause.rs @@ -1,12 +1,14 @@ // Make sure #1399 stays fixed #[allow(dead_code)] -struct A { a: Box } +struct A { + a: Box, +} fn foo() -> Box isize + 'static> { let k: Box<_> = Box::new(22); - let _u = A {a: k.clone()}; - let result = || 22; + let _u = A { a: k.clone() }; + let result = || 22; Box::new(result) } diff --git a/tests/pass/leak-in-static.rs b/tests/pass/leak-in-static.rs index a20577125e73..952339440880 100644 --- a/tests/pass/leak-in-static.rs +++ b/tests/pass/leak-in-static.rs @@ -1,4 +1,7 @@ -use std::{ptr, sync::atomic::{AtomicPtr, Ordering}}; +use std::{ + ptr, + sync::atomic::{AtomicPtr, Ordering}, +}; static mut LEAKER: Option>> = None; diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index bf5ae9829011..5991fae5bb1e 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -7,7 +7,9 @@ extern crate libc; #[cfg(target_os = "linux")] fn tmp() -> std::path::PathBuf { - std::env::var("MIRI_TEMP").map(std::path::PathBuf::from).unwrap_or_else(|_| std::env::temp_dir()) + std::env::var("MIRI_TEMP") + .map(std::path::PathBuf::from) + .unwrap_or_else(|_| std::env::temp_dir()) } #[cfg(target_os = "linux")] @@ -91,7 +93,10 @@ fn test_mutex_libc_init_recursive() { unsafe { let mut attr: libc::pthread_mutexattr_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutexattr_init(&mut attr as *mut _), 0); - assert_eq!(libc::pthread_mutexattr_settype(&mut attr as *mut _, libc::PTHREAD_MUTEX_RECURSIVE), 0); + assert_eq!( + libc::pthread_mutexattr_settype(&mut attr as *mut _, libc::PTHREAD_MUTEX_RECURSIVE), + 0 + ); let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mut attr as *mut _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); @@ -111,8 +116,14 @@ fn test_mutex_libc_init_recursive() { fn test_mutex_libc_init_normal() { unsafe { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, 0x12345678), libc::EINVAL); - assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), 0); + assert_eq!( + libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, 0x12345678), + libc::EINVAL + ); + assert_eq!( + libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), + 0 + ); let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); @@ -127,7 +138,13 @@ fn test_mutex_libc_init_normal() { fn test_mutex_libc_init_errorcheck() { unsafe { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_ERRORCHECK), 0); + assert_eq!( + libc::pthread_mutexattr_settype( + &mut mutexattr as *mut _, + libc::PTHREAD_MUTEX_ERRORCHECK + ), + 0 + ); let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); @@ -193,21 +210,48 @@ fn test_rwlock_libc_static_initializer() { /// Note: `prctl` exists only on Linux. #[cfg(target_os = "linux")] fn test_prctl_thread_name() { - use std::ffi::CString; use libc::c_long; + use std::ffi::CString; unsafe { let mut buf = [255; 10]; - assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), 0); + assert_eq!( + libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), + 0 + ); assert_eq!(b"\0", &buf); let thread_name = CString::new("hello").expect("CString::new failed"); - assert_eq!(libc::prctl(libc::PR_SET_NAME, thread_name.as_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), 0); + assert_eq!( + libc::prctl( + libc::PR_SET_NAME, + thread_name.as_ptr(), + 0 as c_long, + 0 as c_long, + 0 as c_long + ), + 0 + ); let mut buf = [255; 6]; - assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), 0); + assert_eq!( + libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), + 0 + ); assert_eq!(b"hello\0", &buf); let long_thread_name = CString::new("01234567890123456789").expect("CString::new failed"); - assert_eq!(libc::prctl(libc::PR_SET_NAME, long_thread_name.as_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), 0); + assert_eq!( + libc::prctl( + libc::PR_SET_NAME, + long_thread_name.as_ptr(), + 0 as c_long, + 0 as c_long, + 0 as c_long + ), + 0 + ); let mut buf = [255; 16]; - assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), 0); + assert_eq!( + libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), + 0 + ); assert_eq!(b"012345678901234\0", &buf); } } @@ -225,7 +269,9 @@ fn test_thread_local_errno() { assert_eq!(*__errno_location(), 0); *__errno_location() = 0xBAD1DEA; assert_eq!(*__errno_location(), 0xBAD1DEA); - }).join().unwrap(); + }) + .join() + .unwrap(); assert_eq!(*__errno_location(), 0xBEEF); } } @@ -234,21 +280,13 @@ fn test_thread_local_errno() { #[cfg(target_os = "linux")] fn test_clocks() { let mut tp = std::mem::MaybeUninit::::uninit(); - let is_error = unsafe { - libc::clock_gettime(libc::CLOCK_REALTIME, tp.as_mut_ptr()) - }; + let is_error = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, tp.as_mut_ptr()) }; assert_eq!(is_error, 0); - let is_error = unsafe { - libc::clock_gettime(libc::CLOCK_REALTIME_COARSE, tp.as_mut_ptr()) - }; + let is_error = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME_COARSE, tp.as_mut_ptr()) }; assert_eq!(is_error, 0); - let is_error = unsafe { - libc::clock_gettime(libc::CLOCK_MONOTONIC, tp.as_mut_ptr()) - }; + let is_error = unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC, tp.as_mut_ptr()) }; assert_eq!(is_error, 0); - let is_error = unsafe { - libc::clock_gettime(libc::CLOCK_MONOTONIC_COARSE, tp.as_mut_ptr()) - }; + let is_error = unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC_COARSE, tp.as_mut_ptr()) }; assert_eq!(is_error, 0); } diff --git a/tests/pass/linked-list.rs b/tests/pass/linked-list.rs index 0ed9d6032d0e..7377f9f60b01 100644 --- a/tests/pass/linked-list.rs +++ b/tests/pass/linked-list.rs @@ -45,8 +45,7 @@ fn main() { assert_eq!(m.len(), 3 + len * 2); let mut m2 = m.clone(); - assert_eq!(m.into_iter().collect::>(), - [-10, -2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 99]); + assert_eq!(m.into_iter().collect::>(), [-10, -2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 99]); test_all_refs(&mut 13, m2.iter_mut()); } diff --git a/tests/pass/linux-getrandom-without-isolation.rs b/tests/pass/linux-getrandom-without-isolation.rs index e08d4466a7bf..a88db57cc09d 100644 --- a/tests/pass/linux-getrandom-without-isolation.rs +++ b/tests/pass/linux-getrandom-without-isolation.rs @@ -6,10 +6,36 @@ extern crate libc; fn main() { let mut buf = [0u8; 5]; unsafe { - assert_eq!(libc::syscall(libc::SYS_getrandom, 0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), 0); - assert_eq!(libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, 0 as libc::c_uint), 5); + assert_eq!( + libc::syscall( + libc::SYS_getrandom, + 0 as *mut libc::c_void, + 0 as libc::size_t, + 0 as libc::c_uint + ), + 0 + ); + assert_eq!( + libc::syscall( + libc::SYS_getrandom, + buf.as_mut_ptr() as *mut libc::c_void, + 5 as libc::size_t, + 0 as libc::c_uint + ), + 5 + ); - assert_eq!(libc::getrandom(0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), 0); - assert_eq!(libc::getrandom(buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, 0 as libc::c_uint), 5); + assert_eq!( + libc::getrandom(0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), + 0 + ); + assert_eq!( + libc::getrandom( + buf.as_mut_ptr() as *mut libc::c_void, + 5 as libc::size_t, + 0 as libc::c_uint + ), + 5 + ); } } diff --git a/tests/pass/linux-getrandom.rs b/tests/pass/linux-getrandom.rs index 762e754f8127..691117699535 100644 --- a/tests/pass/linux-getrandom.rs +++ b/tests/pass/linux-getrandom.rs @@ -5,10 +5,36 @@ extern crate libc; fn main() { let mut buf = [0u8; 5]; unsafe { - assert_eq!(libc::syscall(libc::SYS_getrandom, 0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), 0); - assert_eq!(libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, 0 as libc::c_uint), 5); + assert_eq!( + libc::syscall( + libc::SYS_getrandom, + 0 as *mut libc::c_void, + 0 as libc::size_t, + 0 as libc::c_uint + ), + 0 + ); + assert_eq!( + libc::syscall( + libc::SYS_getrandom, + buf.as_mut_ptr() as *mut libc::c_void, + 5 as libc::size_t, + 0 as libc::c_uint + ), + 5 + ); - assert_eq!(libc::getrandom(0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), 0); - assert_eq!(libc::getrandom(buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, 0 as libc::c_uint), 5); + assert_eq!( + libc::getrandom(0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), + 0 + ); + assert_eq!( + libc::getrandom( + buf.as_mut_ptr() as *mut libc::c_void, + 5 as libc::size_t, + 0 as libc::c_uint + ), + 5 + ); } } diff --git a/tests/pass/loop-break-value.rs b/tests/pass/loop-break-value.rs index bd7afa7ec1a8..bc4c967d26a5 100644 --- a/tests/pass/loop-break-value.rs +++ b/tests/pass/loop-break-value.rs @@ -16,7 +16,7 @@ pub fn main() { let _never: ! = loop { break loop { break 'outer panic!(); - } + }; }; } }; @@ -36,19 +36,15 @@ pub fn main() { assert_eq!(coerced, &[17u32]); let trait_unified = loop { - break if true { - break Default::default() - } else { - break [13, 14] - }; + break if true { break Default::default() } else { break [13, 14] }; }; assert_eq!(trait_unified, [0, 0]); let trait_unified_2 = loop { if false { - break [String::from("Hello")] + break [String::from("Hello")]; } else { - break Default::default() + break Default::default(); }; }; // compare lengths; ptr comparison is not deterministic @@ -56,11 +52,7 @@ pub fn main() { assert_eq!(trait_unified_2[0].len(), 0); let trait_unified_3 = loop { - break if false { - break [String::from("Hello")] - } else { - ["Yes".into()] - }; + break if false { break [String::from("Hello")] } else { ["Yes".into()] }; }; assert_eq!(trait_unified_3, ["Yes"]); @@ -87,7 +79,7 @@ pub fn main() { Default::default() } else { break; - } + }; }; assert_eq!(regular_break_3, ()); diff --git a/tests/pass/malloc.rs b/tests/pass/malloc.rs index b8eb7b50d340..72abc68bb96b 100644 --- a/tests/pass/malloc.rs +++ b/tests/pass/malloc.rs @@ -4,7 +4,7 @@ extern crate libc; -use core::{slice, ptr}; +use core::{ptr, slice}; fn main() { // Test that small allocations sometimes *are* not very aligned. diff --git a/tests/pass/many_shr_bor.rs b/tests/pass/many_shr_bor.rs index ba2f9b61b1f3..376b41dd6e20 100644 --- a/tests/pass/many_shr_bor.rs +++ b/tests/pass/many_shr_bor.rs @@ -24,7 +24,7 @@ fn test1() { fn test2(r: &mut RefCell) { let x = &*r; // releasing write lock, first suspension recorded let mut x_ref = x.borrow_mut(); - let x_inner : &mut i32 = &mut *x_ref; // new inner write lock, with same lifetime as outer lock + let x_inner: &mut i32 = &mut *x_ref; // new inner write lock, with same lifetime as outer lock let _x_inner_shr = &*x_inner; // releasing inner write lock, recording suspension let _y = &*r; // second suspension for the outer write lock let _x_inner_shr2 = &*x_inner; // 2nd suspension for inner write lock diff --git a/tests/pass/match_slice.rs b/tests/pass/match_slice.rs index 568a1a1c8818..e40a63ef2003 100644 --- a/tests/pass/match_slice.rs +++ b/tests/pass/match_slice.rs @@ -1,8 +1,8 @@ fn main() { let x = "hello"; match x { - "foo" => {}, - "bar" => {}, - _ => {}, + "foo" => {} + "bar" => {} + _ => {} } } diff --git a/tests/pass/move-arg-2-unique.rs b/tests/pass/move-arg-2-unique.rs index b31b868bb96d..669602ac7043 100644 --- a/tests/pass/move-arg-2-unique.rs +++ b/tests/pass/move-arg-2-unique.rs @@ -1,6 +1,8 @@ #![feature(box_syntax)] -fn test(foo: Box> ) { assert_eq!((*foo)[0], 10); } +fn test(foo: Box>) { + assert_eq!((*foo)[0], 10); +} pub fn main() { let x = box vec![10]; diff --git a/tests/pass/move-uninit-primval.rs b/tests/pass/move-uninit-primval.rs index 0edc3c9e6cd8..1ca3873d1d36 100644 --- a/tests/pass/move-uninit-primval.rs +++ b/tests/pass/move-uninit-primval.rs @@ -7,9 +7,7 @@ struct Foo { fn main() { unsafe { - let foo = Foo { - _inner: std::mem::uninitialized(), - }; + let foo = Foo { _inner: std::mem::uninitialized() }; let _bar = foo; } } diff --git a/tests/pass/negative_discriminant.rs b/tests/pass/negative_discriminant.rs index 16f175e7dfc8..5a58deeac0f3 100644 --- a/tests/pass/negative_discriminant.rs +++ b/tests/pass/negative_discriminant.rs @@ -1,4 +1,7 @@ -enum AB { A = -1, B = 1 } +enum AB { + A = -1, + B = 1, +} fn main() { match AB::A { diff --git a/tests/pass/overflow_checks_off.rs b/tests/pass/overflow_checks_off.rs index d6c6971e4952..2896d3161f76 100644 --- a/tests/pass/overflow_checks_off.rs +++ b/tests/pass/overflow_checks_off.rs @@ -8,7 +8,7 @@ // use std::ops::*; fn main() { - assert_eq!(-{-0x80i8}, -0x80); + assert_eq!(-{ -0x80i8 }, -0x80); assert_eq!(0xffu8 + 1, 0_u8); assert_eq!(0u8 - 1, 0xff_u8); diff --git a/tests/pass/overloaded-calls-simple.rs b/tests/pass/overloaded-calls-simple.rs index 12e632c251b4..9fcf7d4a819a 100644 --- a/tests/pass/overloaded-calls-simple.rs +++ b/tests/pass/overloaded-calls-simple.rs @@ -1,4 +1,3 @@ - #![feature(lang_items, unboxed_closures, fn_traits)] struct S3 { @@ -6,18 +5,15 @@ struct S3 { y: i32, } -impl FnOnce<(i32,i32)> for S3 { +impl FnOnce<(i32, i32)> for S3 { type Output = i32; - extern "rust-call" fn call_once(self, (z,zz): (i32,i32)) -> i32 { + extern "rust-call" fn call_once(self, (z, zz): (i32, i32)) -> i32 { self.x * self.y * z * zz } } fn main() { - let s = S3 { - x: 3, - y: 3, - }; + let s = S3 { x: 3, y: 3 }; let ans = s(3, 1); assert_eq!(ans, 27); } diff --git a/tests/pass/packed_struct.rs b/tests/pass/packed_struct.rs index dd95d660d75e..85acab858aab 100644 --- a/tests/pass/packed_struct.rs +++ b/tests/pass/packed_struct.rs @@ -31,34 +31,31 @@ fn test_basic() { assert_eq!(x, 42); } - let mut x = S { - fill: 0, - a: 42, - b: 99, - }; + let mut x = S { fill: 0, a: 42, b: 99 }; let a = x.a; let b = x.b; assert_eq!(a, 42); assert_eq!(b, 99); assert_eq!(&x.fill, &0); // `fill` just requirs 1-byte-align, so this is fine // can't do `assert_eq!(x.a, 42)`, because `assert_eq!` takes a reference - assert_eq!({x.a}, 42); - assert_eq!({x.b}, 99); + assert_eq!({ x.a }, 42); + assert_eq!({ x.b }, 99); // but we *can* take a raw pointer! assert_eq!(unsafe { ptr::addr_of!(x.a).read_unaligned() }, 42); assert_eq!(unsafe { ptr::addr_of!(x.b).read_unaligned() }, 99); x.b = 77; - assert_eq!({x.b}, 77); + assert_eq!({ x.b }, 77); - test(Test2 { x: 0, other: &Test1 { x: 0, other: &42 }}); + test(Test2 { x: 0, other: &Test1 { x: 0, other: &42 } }); } fn test_unsizing() { #[repr(packed)] #[allow(dead_code)] struct UnalignedPtr<'a, T: ?Sized> - where T: 'a, + where + T: 'a, { data: &'a T, } @@ -67,7 +64,8 @@ fn test_unsizing() { where T: std::marker::Unsize + ?Sized, U: ?Sized, - { } + { + } let arr = [1, 2, 3]; let arr_unaligned: UnalignedPtr<[i32; 3]> = UnalignedPtr { data: &arr }; @@ -86,7 +84,7 @@ fn test_drop() { } } - #[repr(packed,C)] + #[repr(packed, C)] struct Packed { f1: u8, // this should move the second field to something not very aligned f2: T, @@ -100,10 +98,10 @@ fn test_inner_packed() { // Even if just the inner struct is packed, accesses to the outer field can get unaligned. // Make sure that works. #[repr(packed)] - #[derive(Clone,Copy)] + #[derive(Clone, Copy)] struct Inner(u32); - #[derive(Clone,Copy)] + #[derive(Clone, Copy)] struct Outer(u8, Inner); let o = Outer(0, Inner(42)); @@ -115,12 +113,12 @@ fn test_inner_packed() { fn test_static() { #[repr(packed)] struct Foo { - i: i32 + i: i32, } static FOO: Foo = Foo { i: 42 }; - assert_eq!({FOO.i}, 42); + assert_eq!({ FOO.i }, 42); } fn test_derive() { @@ -132,8 +130,8 @@ fn test_derive() { c: usize, } - let x = P {a: 1usize, b: 2u8, c: 3usize}; - let y = P {a: 1usize, b: 2u8, c: 4usize}; + let x = P { a: 1usize, b: 2u8, c: 3usize }; + let y = P { a: 1usize, b: 2u8, c: 4usize }; let _clone = x.clone(); assert!(x != y); diff --git a/tests/pass/partially-uninit.rs b/tests/pass/partially-uninit.rs index 5ee9abbcb95b..db26a2084b1c 100644 --- a/tests/pass/partially-uninit.rs +++ b/tests/pass/partially-uninit.rs @@ -4,10 +4,12 @@ use std::mem::{self, MaybeUninit}; #[derive(Copy, Clone, Debug, PartialEq)] struct Demo(bool, u16); -fn main() { unsafe { - // Transmute-round-trip through a type with Scalar layout is lossless. - // This is tricky because that 'scalar' is *partially* uninitialized. - let x = Demo(true, 3); - let y: MaybeUninit = mem::transmute(x); - assert_eq!(x, mem::transmute(y)); -} } +fn main() { + unsafe { + // Transmute-round-trip through a type with Scalar layout is lossless. + // This is tricky because that 'scalar' is *partially* uninitialized. + let x = Demo(true, 3); + let y: MaybeUninit = mem::transmute(x); + assert_eq!(x, mem::transmute(y)); + } +} diff --git a/tests/pass/pointers.rs b/tests/pass/pointers.rs index 5bf60c32541d..898ecc0faf75 100644 --- a/tests/pass/pointers.rs +++ b/tests/pass/pointers.rs @@ -37,7 +37,7 @@ fn match_ref_mut() -> i8 { let opt = Some(&mut t); match opt { Some(&mut (ref mut x, ref mut y)) => *x += *y, - None => {}, + None => {} } } t.0 @@ -59,7 +59,10 @@ fn main() { // Compare even dangling pointers with NULL, and with others in the same allocation, including // out-of-bounds. assert!(dangling_pointer() != std::ptr::null()); - assert!(match dangling_pointer() as usize { 0 => false, _ => true }); + assert!(match dangling_pointer() as usize { + 0 => false, + _ => true, + }); let dangling = dangling_pointer(); assert!(dangling == dangling); assert!(dangling.wrapping_add(1) != dangling); diff --git a/tests/pass/portable-simd.rs b/tests/pass/portable-simd.rs index 3e43595c94ae..ffbaa1832ecb 100644 --- a/tests/pass/portable-simd.rs +++ b/tests/pass/portable-simd.rs @@ -16,10 +16,10 @@ fn simd_ops_f32() { assert_eq!(a.max(b * f32x4::splat(4.0)), f32x4::from_array([10.0, 10.0, 12.0, 10.0])); assert_eq!(a.min(b * f32x4::splat(4.0)), f32x4::from_array([4.0, 8.0, 10.0, -16.0])); - assert_eq!(a.mul_add(b, a), (a*b)+a); - assert_eq!(b.mul_add(b, a), (b*b)+a); - assert_eq!((a*a).sqrt(), a); - assert_eq!((b*b).sqrt(), b.abs()); + assert_eq!(a.mul_add(b, a), (a * b) + a); + assert_eq!(b.mul_add(b, a), (b * b) + a); + assert_eq!((a * a).sqrt(), a); + assert_eq!((b * b).sqrt(), b.abs()); assert_eq!(a.lanes_eq(f32x4::splat(5.0) * b), Mask::from_array([false, true, false, false])); assert_eq!(a.lanes_ne(f32x4::splat(5.0) * b), Mask::from_array([true, false, true, true])); @@ -65,10 +65,10 @@ fn simd_ops_f64() { assert_eq!(a.max(b * f64x4::splat(4.0)), f64x4::from_array([10.0, 10.0, 12.0, 10.0])); assert_eq!(a.min(b * f64x4::splat(4.0)), f64x4::from_array([4.0, 8.0, 10.0, -16.0])); - assert_eq!(a.mul_add(b, a), (a*b)+a); - assert_eq!(b.mul_add(b, a), (b*b)+a); - assert_eq!((a*a).sqrt(), a); - assert_eq!((b*b).sqrt(), b.abs()); + assert_eq!(a.mul_add(b, a), (a * b) + a); + assert_eq!(b.mul_add(b, a), (b * b) + a); + assert_eq!((a * a).sqrt(), a); + assert_eq!((b * b).sqrt(), b.abs()); assert_eq!(a.lanes_eq(f64x4::splat(5.0) * b), Mask::from_array([false, true, false, false])); assert_eq!(a.lanes_ne(f64x4::splat(5.0) * b), Mask::from_array([true, false, true, true])); diff --git a/tests/pass/products.rs b/tests/pass/products.rs index 86bb71a0be56..767d756e5ae1 100644 --- a/tests/pass/products.rs +++ b/tests/pass/products.rs @@ -11,7 +11,10 @@ fn tuple_5() -> (i16, i16, i16, i16, i16) { } #[derive(Debug, PartialEq)] -struct Pair { x: i8, y: i8 } +struct Pair { + x: i8, + y: i8, +} fn pair() -> Pair { Pair { x: 10, y: 20 } @@ -27,6 +30,6 @@ fn main() { assert_eq!(tuple(), (1,)); assert_eq!(tuple_2(), (1, 2)); assert_eq!(tuple_5(), (1, 2, 3, 4, 5)); - assert_eq!(pair(), Pair { x: 10, y: 20} ); + assert_eq!(pair(), Pair { x: 10, y: 20 }); assert_eq!(field_access(), (15, 20)); } diff --git a/tests/pass/ptr_offset.rs b/tests/pass/ptr_offset.rs index 4c6341813f5b..1b25df721452 100644 --- a/tests/pass/ptr_offset.rs +++ b/tests/pass/ptr_offset.rs @@ -8,21 +8,23 @@ fn main() { ptr_offset(); } -fn test_offset_from() { unsafe { - let buf = [0u32; 4]; +fn test_offset_from() { + unsafe { + let buf = [0u32; 4]; - let x = buf.as_ptr() as *const u8; - let y = x.offset(12); + let x = buf.as_ptr() as *const u8; + let y = x.offset(12); - assert_eq!(y.offset_from(x), 12); - assert_eq!(x.offset_from(y), -12); - assert_eq!((y as *const u32).offset_from(x as *const u32), 12/4); - assert_eq!((x as *const u32).offset_from(y as *const u32), -12/4); + assert_eq!(y.offset_from(x), 12); + assert_eq!(x.offset_from(y), -12); + assert_eq!((y as *const u32).offset_from(x as *const u32), 12 / 4); + assert_eq!((x as *const u32).offset_from(y as *const u32), -12 / 4); - let x = (((x as usize) * 2) / 2) as *const u8; - assert_eq!(y.offset_from(x), 12); - assert_eq!(x.offset_from(y), -12); -} } + let x = (((x as usize) * 2) / 2) as *const u8; + assert_eq!(y.offset_from(x), 12); + assert_eq!(x.offset_from(y), -12); + } +} // This also internally uses offset_from. fn test_vec_into_iter() { @@ -50,7 +52,9 @@ fn ptr_arith_offset_overflow() { } fn ptr_offset() { - fn f() -> i32 { 42 } + fn f() -> i32 { + 42 + } let v = [1i16, 2]; let x = &v as *const [i16; 2] as *const i16; diff --git a/tests/pass/ptr_raw.rs b/tests/pass/ptr_raw.rs index 4fbbb270957b..3ba0fba9a941 100644 --- a/tests/pass/ptr_raw.rs +++ b/tests/pass/ptr_raw.rs @@ -5,12 +5,16 @@ fn basic_raw() { assert_eq!(*x, 12); let raw = x as *mut i32; - unsafe { *raw = 42; } + unsafe { + *raw = 42; + } assert_eq!(*x, 42); let raw = x as *mut i32; - unsafe { *raw = 12; } + unsafe { + *raw = 12; + } *x = 23; assert_eq!(*x, 23); diff --git a/tests/pass/rc.rs b/tests/pass/rc.rs index 6d51825fc0df..260e350f27ac 100644 --- a/tests/pass/rc.rs +++ b/tests/pass/rc.rs @@ -3,9 +3,9 @@ #![feature(get_mut_unchecked)] use std::cell::{Cell, RefCell}; +use std::fmt::Debug; use std::rc::{Rc, Weak}; use std::sync::{Arc, Weak as ArcWeak}; -use std::fmt::Debug; fn rc_refcell() { let r = Rc::new(RefCell::new(42)); @@ -30,7 +30,7 @@ fn rc_refcell2() { let x = r2.borrow(); let r3 = r.clone(); let y = r3.borrow(); - assert_eq!((*x + *y)/2, 52); + assert_eq!((*x + *y) / 2, 52); } fn rc_raw() { @@ -62,9 +62,9 @@ fn check_unique_rc(mut r: Rc) { } fn rc_from() { - check_unique_rc::<[_]>(Rc::from(&[1,2,3] as &[_])); - check_unique_rc::<[_]>(Rc::from(vec![1,2,3])); - check_unique_rc::<[_]>(Rc::from(Box::new([1,2,3]) as Box<[_]>)); + check_unique_rc::<[_]>(Rc::from(&[1, 2, 3] as &[_])); + check_unique_rc::<[_]>(Rc::from(vec![1, 2, 3])); + check_unique_rc::<[_]>(Rc::from(Box::new([1, 2, 3]) as Box<[_]>)); check_unique_rc::(Rc::from("Hello, World!")); } diff --git a/tests/pass/regions-mock-trans.rs b/tests/pass/regions-mock-trans.rs index 23ec91461db5..5dafc88756f1 100644 --- a/tests/pass/regions-mock-trans.rs +++ b/tests/pass/regions-mock-trans.rs @@ -9,32 +9,29 @@ use std::mem; struct Arena(()); struct Bcx<'a> { - fcx: &'a Fcx<'a> + fcx: &'a Fcx<'a>, } #[allow(dead_code)] struct Fcx<'a> { arena: &'a Arena, - ccx: &'a Ccx + ccx: &'a Ccx, } #[allow(dead_code)] struct Ccx { - x: isize + x: isize, } -fn alloc<'a>(_bcx : &'a Arena) -> &'a mut Bcx<'a> { - unsafe { - mem::transmute(libc::malloc(mem::size_of::>() - as libc::size_t)) - } +fn alloc<'a>(_bcx: &'a Arena) -> &'a mut Bcx<'a> { + unsafe { mem::transmute(libc::malloc(mem::size_of::>() as libc::size_t)) } } -fn h<'a>(bcx : &'a Bcx<'a>) -> &'a mut Bcx<'a> { +fn h<'a>(bcx: &'a Bcx<'a>) -> &'a mut Bcx<'a> { return alloc(bcx.fcx.arena); } -fn g(fcx : &Fcx) { +fn g(fcx: &Fcx) { let bcx = Bcx { fcx: fcx }; let bcx2 = h(&bcx); unsafe { @@ -42,7 +39,7 @@ fn g(fcx : &Fcx) { } } -fn f(ccx : &Ccx) { +fn f(ccx: &Ccx) { let a = Arena(()); let fcx = Fcx { arena: &a, ccx: ccx }; return g(&fcx); diff --git a/tests/pass/send-is-not-static-par-for.rs b/tests/pass/send-is-not-static-par-for.rs index 396a87fca060..642f75ecc09b 100644 --- a/tests/pass/send-is-not-static-par-for.rs +++ b/tests/pass/send-is-not-static-par-for.rs @@ -1,9 +1,10 @@ use std::sync::Mutex; fn par_for(iter: I, f: F) - where I: Iterator, - I::Item: Send, - F: Fn(I::Item) + Sync +where + I: Iterator, + I::Item: Send, + F: Fn(I::Item) + Sync, { for item in iter { f(item) @@ -12,9 +13,7 @@ fn par_for(iter: I, f: F) fn sum(x: &[i32]) { let sum_lengths = Mutex::new(0); - par_for(x.windows(4), |x| { - *sum_lengths.lock().unwrap() += x.len() - }); + par_for(x.windows(4), |x| *sum_lengths.lock().unwrap() += x.len()); assert_eq!(*sum_lengths.lock().unwrap(), (x.len() - 3) * 4); } @@ -23,9 +22,7 @@ fn main() { let mut elements = [0; 20]; // iterators over references into this stack frame - par_for(elements.iter_mut().enumerate(), |(i, x)| { - *x = i as i32 - }); + par_for(elements.iter_mut().enumerate(), |(i, x)| *x = i as i32); sum(&elements) } diff --git a/tests/pass/sendable-class.rs b/tests/pass/sendable-class.rs index b2feb5316f87..a05278f1855a 100644 --- a/tests/pass/sendable-class.rs +++ b/tests/pass/sendable-class.rs @@ -8,11 +8,8 @@ struct Foo { j: char, } -fn foo(i:isize, j: char) -> Foo { - Foo { - i: i, - j: j - } +fn foo(i: isize, j: char) -> Foo { + Foo { i: i, j: j } } pub fn main() { diff --git a/tests/pass/simd-intrinsic-generic-elements.rs b/tests/pass/simd-intrinsic-generic-elements.rs index 32de27a96233..5958357c8b7b 100644 --- a/tests/pass/simd-intrinsic-generic-elements.rs +++ b/tests/pass/simd-intrinsic-generic-elements.rs @@ -11,8 +11,7 @@ struct i32x4(i32, i32, i32, i32); #[repr(simd)] #[derive(Copy, Clone, Debug, PartialEq)] #[allow(non_camel_case_types)] -struct i32x8(i32, i32, i32, i32, - i32, i32, i32, i32); +struct i32x8(i32, i32, i32, i32, i32, i32, i32, i32); fn main() { let _x2 = i32x2(20, 21); @@ -22,5 +21,4 @@ fn main() { let _y2 = i32x2(120, 121); let _y4 = i32x4(140, 141, 142, 143); let _y8 = i32x8(180, 181, 182, 183, 184, 185, 186, 187); - } diff --git a/tests/pass/slices.rs b/tests/pass/slices.rs index 6cdfbb7841ae..3a13ec59a02e 100644 --- a/tests/pass/slices.rs +++ b/tests/pass/slices.rs @@ -5,8 +5,8 @@ #![feature(layout_for_ptr)] #![feature(strict_provenance)] -use std::slice; use std::ptr; +use std::slice; fn slice_of_zst() { fn foo(v: &[T]) -> Option<&[T]> { @@ -40,7 +40,8 @@ fn slice_of_zst() { assert!(foo(slice).is_some()); // Test mutable iterators as well - let slice: &mut [()] = unsafe { slice::from_raw_parts_mut(ptr::invalid_mut(-5isize as usize), 10) }; + let slice: &mut [()] = + unsafe { slice::from_raw_parts_mut(ptr::invalid_mut(-5isize as usize), 10) }; assert_eq!(slice.len(), 10); assert_eq!(slice.iter_mut().count(), 10); @@ -56,11 +57,11 @@ fn slice_of_zst() { fn test_iter_ref_consistency() { use std::fmt::Debug; - fn test(x : T) { - let v : &[T] = &[x, x, x]; - let v_ptrs : [*const T; 3] = match v { + fn test(x: T) { + let v: &[T] = &[x, x, x]; + let v_ptrs: [*const T; 3] = match v { [ref v1, ref v2, ref v3] => [v1 as *const _, v2 as *const _, v3 as *const _], - _ => unreachable!() + _ => unreachable!(), }; let len = v.len(); @@ -104,19 +105,19 @@ fn test_iter_ref_consistency() { assert_eq!(it.size_hint(), (remaining, Some(remaining))); let prev = it.next_back().unwrap(); - assert_eq!(prev as *const _, v_ptrs[remaining-1]); + assert_eq!(prev as *const _, v_ptrs[remaining - 1]); } assert_eq!(it.size_hint(), (0, Some(0))); assert_eq!(it.next_back(), None, "The final call to next_back() should return None"); } } - fn test_mut(x : T) { - let v : &mut [T] = &mut [x, x, x]; - let v_ptrs : [*mut T; 3] = match v { + fn test_mut(x: T) { + let v: &mut [T] = &mut [x, x, x]; + let v_ptrs: [*mut T; 3] = match v { [ref v1, ref v2, ref v3] => - [v1 as *const _ as *mut _, v2 as *const _ as *mut _, v3 as *const _ as *mut _], - _ => unreachable!() + [v1 as *const _ as *mut _, v2 as *const _ as *mut _, v3 as *const _ as *mut _], + _ => unreachable!(), }; let len = v.len(); @@ -160,7 +161,7 @@ fn test_iter_ref_consistency() { assert_eq!(it.size_hint(), (remaining, Some(remaining))); let prev = it.next_back().unwrap(); - assert_eq!(prev as *mut _, v_ptrs[remaining-1]); + assert_eq!(prev as *mut _, v_ptrs[remaining - 1]); } assert_eq!(it.size_hint(), (0, Some(0))); assert_eq!(it.next_back(), None, "The final call to next_back() should return None"); @@ -215,10 +216,14 @@ fn test_for_invalidated_pointers() { // The invalidated `*const` pointer (the first argument to `core::ptr::copy`) is then used // after the fact when `core::ptr::copy` is called, which triggers undefined behavior. - unsafe { assert_eq!(0, *buffer.as_mut_ptr_range().start ); } + unsafe { + assert_eq!(0, *buffer.as_mut_ptr_range().start); + } // Check that the pointer range is in-bounds, while we're at it let range = buffer.as_mut_ptr_range(); - unsafe { assert_eq!(*range.start, *range.end.sub(len)); } + unsafe { + assert_eq!(*range.start, *range.end.sub(len)); + } buffer.reverse(); diff --git a/tests/pass/specialization.rs b/tests/pass/specialization.rs index 44cef00a22c3..428dea073eb5 100644 --- a/tests/pass/specialization.rs +++ b/tests/pass/specialization.rs @@ -6,11 +6,15 @@ trait IsUnit { } impl IsUnit for T { - default fn is_unit() -> bool { false } + default fn is_unit() -> bool { + false + } } impl IsUnit for () { - fn is_unit() -> bool { true } + fn is_unit() -> bool { + true + } } fn specialization() -> (bool, bool) { diff --git a/tests/pass/stacked-borrows/2phase.rs b/tests/pass/stacked-borrows/2phase.rs index 065c76913a71..2a7588377feb 100644 --- a/tests/pass/stacked-borrows/2phase.rs +++ b/tests/pass/stacked-borrows/2phase.rs @@ -21,7 +21,9 @@ fn two_phase3(b: bool) { let mut y = vec![]; x.push(( { - if b { x = &mut y }; + if b { + x = &mut y + }; 22 }, x.len(), @@ -31,16 +33,16 @@ fn two_phase3(b: bool) { #[allow(unreachable_code)] fn two_phase_raw() { let x: &mut Vec = &mut vec![]; - x.push( - { - // Unfortunately this does not trigger the problem of creating a - // raw ponter from a pointer that had a two-phase borrow derived from - // it because of the implicit &mut reborrow. - let raw = x as *mut _; - unsafe { *raw = vec![1]; } - return + x.push({ + // Unfortunately this does not trigger the problem of creating a + // raw ponter from a pointer that had a two-phase borrow derived from + // it because of the implicit &mut reborrow. + let raw = x as *mut _; + unsafe { + *raw = vec![1]; } - ); + return; + }); } fn two_phase_overlapping1() { @@ -68,13 +70,11 @@ fn with_interior_mutability() { let mut x = Cell::new(1); let l = &x; - x - .do_the_thing({ - x.set(3); - l.set(4); - x.get() + l.get() - }) - ; + x.do_the_thing({ + x.set(3); + l.set(4); + x.get() + l.get() + }); } fn main() { diff --git a/tests/pass/stacked-borrows/interior_mutability.rs b/tests/pass/stacked-borrows/interior_mutability.rs index 23d82b8e435b..1ac9706b525f 100644 --- a/tests/pass/stacked-borrows/interior_mutability.rs +++ b/tests/pass/stacked-borrows/interior_mutability.rs @@ -1,5 +1,5 @@ -use std::mem::MaybeUninit; use std::cell::{Cell, RefCell, UnsafeCell}; +use std::mem::MaybeUninit; fn main() { aliasing_mut_and_shr(); @@ -28,7 +28,7 @@ fn aliasing_mut_and_shr() { let mut bmut = rc.borrow_mut(); inner(&rc, &mut *bmut); drop(bmut); - assert_eq!(*rc.borrow(), 23+12); + assert_eq!(*rc.borrow(), 23 + 12); } fn aliasing_frz_and_shr() { @@ -59,9 +59,11 @@ fn into_interior_mutability() { // Two-phase borrows of the pointer returned by UnsafeCell::get() should not // invalidate aliases. -fn unsafe_cell_2phase() { unsafe { - let x = &UnsafeCell::new(vec![]); - let x2 = &*x; - (*x.get()).push(0); - let _val = (*x2.get()).get(0); -} } +fn unsafe_cell_2phase() { + unsafe { + let x = &UnsafeCell::new(vec![]); + let x2 = &*x; + (*x.get()).push(0); + let _val = (*x2.get()).get(0); + } +} From 6b8c371f068ef83fbb11c0829c5c21965eef4aa2 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 20 Jun 2022 16:08:00 -0700 Subject: [PATCH 3303/5092] Manual adjustments --- tests/pass/issues/issue-17877.rs | 4 ++-- tests/pass/libc.rs | 24 +++++++++---------- .../pass/linux-getrandom-without-isolation.rs | 14 +++++------ tests/pass/linux-getrandom.rs | 14 +++++------ tests/pass/stacked-borrows/2phase.rs | 4 ++-- 5 files changed, 30 insertions(+), 30 deletions(-) diff --git a/tests/pass/issues/issue-17877.rs b/tests/pass/issues/issue-17877.rs index a65c5513de00..64d397f91aee 100644 --- a/tests/pass/issues/issue-17877.rs +++ b/tests/pass/issues/issue-17877.rs @@ -3,7 +3,7 @@ fn main() { match [0u8; 16 * 1024] { _ => 42_usize, }, - 42_usize + 42_usize, ); assert_eq!( @@ -12,6 +12,6 @@ fn main() { [0, ..] => 1_usize, _ => 2_usize, }, - 1_usize + 1_usize, ); } diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index 5991fae5bb1e..f97b9dd2b9ea 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -95,7 +95,7 @@ fn test_mutex_libc_init_recursive() { assert_eq!(libc::pthread_mutexattr_init(&mut attr as *mut _), 0); assert_eq!( libc::pthread_mutexattr_settype(&mut attr as *mut _, libc::PTHREAD_MUTEX_RECURSIVE), - 0 + 0, ); let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mut attr as *mut _), 0); @@ -118,11 +118,11 @@ fn test_mutex_libc_init_normal() { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); assert_eq!( libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, 0x12345678), - libc::EINVAL + libc::EINVAL, ); assert_eq!( libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), - 0 + 0, ); let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); @@ -141,9 +141,9 @@ fn test_mutex_libc_init_errorcheck() { assert_eq!( libc::pthread_mutexattr_settype( &mut mutexattr as *mut _, - libc::PTHREAD_MUTEX_ERRORCHECK + libc::PTHREAD_MUTEX_ERRORCHECK, ), - 0 + 0, ); let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); @@ -216,7 +216,7 @@ fn test_prctl_thread_name() { let mut buf = [255; 10]; assert_eq!( libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), - 0 + 0, ); assert_eq!(b"\0", &buf); let thread_name = CString::new("hello").expect("CString::new failed"); @@ -226,14 +226,14 @@ fn test_prctl_thread_name() { thread_name.as_ptr(), 0 as c_long, 0 as c_long, - 0 as c_long + 0 as c_long, ), - 0 + 0, ); let mut buf = [255; 6]; assert_eq!( libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), - 0 + 0, ); assert_eq!(b"hello\0", &buf); let long_thread_name = CString::new("01234567890123456789").expect("CString::new failed"); @@ -243,14 +243,14 @@ fn test_prctl_thread_name() { long_thread_name.as_ptr(), 0 as c_long, 0 as c_long, - 0 as c_long + 0 as c_long, ), - 0 + 0, ); let mut buf = [255; 16]; assert_eq!( libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), - 0 + 0, ); assert_eq!(b"012345678901234\0", &buf); } diff --git a/tests/pass/linux-getrandom-without-isolation.rs b/tests/pass/linux-getrandom-without-isolation.rs index a88db57cc09d..ad1a1f27c771 100644 --- a/tests/pass/linux-getrandom-without-isolation.rs +++ b/tests/pass/linux-getrandom-without-isolation.rs @@ -11,31 +11,31 @@ fn main() { libc::SYS_getrandom, 0 as *mut libc::c_void, 0 as libc::size_t, - 0 as libc::c_uint + 0 as libc::c_uint, ), - 0 + 0, ); assert_eq!( libc::syscall( libc::SYS_getrandom, buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, - 0 as libc::c_uint + 0 as libc::c_uint, ), - 5 + 5, ); assert_eq!( libc::getrandom(0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), - 0 + 0, ); assert_eq!( libc::getrandom( buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, - 0 as libc::c_uint + 0 as libc::c_uint, ), - 5 + 5, ); } } diff --git a/tests/pass/linux-getrandom.rs b/tests/pass/linux-getrandom.rs index 691117699535..7d3f899f4408 100644 --- a/tests/pass/linux-getrandom.rs +++ b/tests/pass/linux-getrandom.rs @@ -10,31 +10,31 @@ fn main() { libc::SYS_getrandom, 0 as *mut libc::c_void, 0 as libc::size_t, - 0 as libc::c_uint + 0 as libc::c_uint, ), - 0 + 0, ); assert_eq!( libc::syscall( libc::SYS_getrandom, buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, - 0 as libc::c_uint + 0 as libc::c_uint, ), - 5 + 5, ); assert_eq!( libc::getrandom(0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), - 0 + 0, ); assert_eq!( libc::getrandom( buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, - 0 as libc::c_uint + 0 as libc::c_uint, ), - 5 + 5, ); } } diff --git a/tests/pass/stacked-borrows/2phase.rs b/tests/pass/stacked-borrows/2phase.rs index 2a7588377feb..345cb64ccf71 100644 --- a/tests/pass/stacked-borrows/2phase.rs +++ b/tests/pass/stacked-borrows/2phase.rs @@ -22,8 +22,8 @@ fn two_phase3(b: bool) { x.push(( { if b { - x = &mut y - }; + x = &mut y; + } 22 }, x.len(), From 8efc049a9f0ad4b0bd95fa479ef6ec4b8d440b4b Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 20 Jun 2022 15:43:42 -0700 Subject: [PATCH 3304/5092] Manual adjustments --- tests/pass/align_offset_symbolic.rs | 1 + tests/pass/catch.rs | 4 +--- tests/pass/closure-field-ty.rs | 4 +--- tests/pass/closures.rs | 2 +- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/tests/pass/align_offset_symbolic.rs b/tests/pass/align_offset_symbolic.rs index ad231bd0d5bb..b57a23ab8368 100644 --- a/tests/pass/align_offset_symbolic.rs +++ b/tests/pass/align_offset_symbolic.rs @@ -60,6 +60,7 @@ fn test_align_to() { { #[repr(align(8))] struct Align8(u64); + let (l, m, r) = unsafe { s.align_to::() }; // requested alignment higher than allocation alignment assert_eq!(l.len(), 4 * N); assert_eq!(r.len(), 0); diff --git a/tests/pass/catch.rs b/tests/pass/catch.rs index 745e186a8e17..4ede23e68ce2 100644 --- a/tests/pass/catch.rs +++ b/tests/pass/catch.rs @@ -2,8 +2,6 @@ use std::panic::{catch_unwind, AssertUnwindSafe}; fn main() { let mut i = 3; - let _val = catch_unwind(AssertUnwindSafe(|| { - i -= 2; - })); + let _val = catch_unwind(AssertUnwindSafe(|| i -= 2)); println!("{}", i); } diff --git a/tests/pass/closure-field-ty.rs b/tests/pass/closure-field-ty.rs index fdcaf1d51723..1c90a15f8c5c 100644 --- a/tests/pass/closure-field-ty.rs +++ b/tests/pass/closure-field-ty.rs @@ -3,9 +3,7 @@ fn main() { let mut y = 0; { let mut box_maybe_closure = Box::new(None); - *box_maybe_closure = Some(|| { - y += 1; - }); + *box_maybe_closure = Some(|| y += 1); (box_maybe_closure.unwrap())(); } assert_eq!(y, 1); diff --git a/tests/pass/closures.rs b/tests/pass/closures.rs index 21292765acaa..40aedbcaf454 100644 --- a/tests/pass/closures.rs +++ b/tests/pass/closures.rs @@ -118,7 +118,7 @@ fn main() { let x = 13; move || x })), - 13 + 13, ); box_dyn(); From 069f5b6615a42dc8be1133277650c466f6cb8dc5 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 20 Jun 2022 23:40:39 -0700 Subject: [PATCH 3305/5092] Format tests with rustfmt (151-200 of 300) --- tests/fail/intrinsics/simd-rem-by-zero.rs | 12 ++-- tests/fail/intrinsics/simd-scatter.rs | 16 +++-- .../intrinsics/simd-select-bitmask-invalid.rs | 10 +-- .../intrinsics/simd-select-invalid-bool.rs | 10 +-- tests/fail/intrinsics/simd-shl-too-far.rs | 12 ++-- tests/fail/intrinsics/simd-shr-too-far.rs | 12 ++-- tests/fail/invalid_enum_tag.rs | 5 +- tests/fail/issue-miri-1112.rs | 6 +- tests/fail/memleak_rc.rs | 2 +- tests/fail/modifying_constants.rs | 2 +- tests/fail/never_say_never.rs | 6 +- tests/fail/never_transmute_void.rs | 4 +- tests/fail/rc_as_ptr.rs | 2 +- tests/fail/reading_half_a_pointer.rs | 2 +- tests/fail/shim_arg_size.rs | 4 +- tests/fail/should-pass/cpp20_rwc_syncs.rs | 4 +- .../stacked_borrows/alias_through_mutation.rs | 4 +- tests/fail/stacked_borrows/aliasing_mut1.rs | 5 +- tests/fail/stacked_borrows/aliasing_mut2.rs | 5 +- tests/fail/stacked_borrows/aliasing_mut3.rs | 5 +- tests/fail/stacked_borrows/aliasing_mut4.rs | 7 +- .../box_exclusive_violation1.rs | 30 +++++---- .../stacked_borrows/buggy_as_mut_slice.rs | 6 +- .../stacked_borrows/buggy_split_at_mut.rs | 8 ++- tests/fail/stacked_borrows/illegal_read6.rs | 16 +++-- tests/fail/stacked_borrows/illegal_read7.rs | 30 +++++---- tests/fail/stacked_borrows/illegal_read8.rs | 22 ++++--- tests/fail/stacked_borrows/interior_mut1.rs | 22 ++++--- tests/panic/panic/panic1.rs | 1 - tests/panic/transmute_fat2.rs | 18 ++--- tests/pass/stacked-borrows/refcell.rs | 8 +-- tests/pass/stacked-borrows/stacked-borrows.rs | 65 +++++++++++-------- tests/pass/static_memory_modification.rs | 2 +- tests/pass/static_mut.rs | 2 +- tests/pass/strings.rs | 2 +- tests/pass/tag-align-dyn-u64.rs | 6 +- tests/pass/time.rs | 10 ++- tests/pass/track-caller-attribute.rs | 5 +- tests/pass/transmute_fat.rs | 4 +- tests/pass/u128.rs | 24 ++++--- tests/pass/union.rs | 19 ++++-- tests/pass/unops.rs | 2 +- tests/pass/unsized-tuple-impls.rs | 4 +- tests/pass/validation_lifetime_resolution.rs | 12 +++- tests/pass/vec-matching-fold.rs | 30 ++++----- tests/pass/vec.rs | 30 +++------ tests/pass/vecdeque.rs | 2 +- tests/pass/weak_memory/weak.rs | 1 - tests/pass/wtf8.rs | 2 +- tests/pass/zst.rs | 8 ++- 50 files changed, 280 insertions(+), 246 deletions(-) diff --git a/tests/fail/intrinsics/simd-rem-by-zero.rs b/tests/fail/intrinsics/simd-rem-by-zero.rs index bc3128b5fb5f..82cbaed462c6 100644 --- a/tests/fail/intrinsics/simd-rem-by-zero.rs +++ b/tests/fail/intrinsics/simd-rem-by-zero.rs @@ -8,8 +8,10 @@ extern "platform-intrinsic" { #[allow(non_camel_case_types)] struct i32x2(i32, i32); -fn main() { unsafe { - let x = i32x2(1, 1); - let y = i32x2(1, 0); - simd_rem(x, y); //~ERROR Undefined Behavior: calculating the remainder with a divisor of zero -} } +fn main() { + unsafe { + let x = i32x2(1, 1); + let y = i32x2(1, 0); + simd_rem(x, y); //~ERROR Undefined Behavior: calculating the remainder with a divisor of zero + } +} diff --git a/tests/fail/intrinsics/simd-scatter.rs b/tests/fail/intrinsics/simd-scatter.rs index f46e4f0d4f6a..d7a7e344aa30 100644 --- a/tests/fail/intrinsics/simd-scatter.rs +++ b/tests/fail/intrinsics/simd-scatter.rs @@ -2,8 +2,14 @@ #![feature(portable_simd)] use std::simd::*; -fn main() { unsafe { - let mut vec: Vec = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; - let idxs = Simd::from_array([9, 3, 0, 17]); - Simd::from_array([-27, 82, -41, 124]).scatter_select_unchecked(&mut vec, Mask::splat(true), idxs); -} } +fn main() { + unsafe { + let mut vec: Vec = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; + let idxs = Simd::from_array([9, 3, 0, 17]); + Simd::from_array([-27, 82, -41, 124]).scatter_select_unchecked( + &mut vec, + Mask::splat(true), + idxs, + ); + } +} diff --git a/tests/fail/intrinsics/simd-select-bitmask-invalid.rs b/tests/fail/intrinsics/simd-select-bitmask-invalid.rs index ab69072c3097..cc9170c64646 100644 --- a/tests/fail/intrinsics/simd-select-bitmask-invalid.rs +++ b/tests/fail/intrinsics/simd-select-bitmask-invalid.rs @@ -9,7 +9,9 @@ extern "platform-intrinsic" { #[derive(Copy, Clone)] struct i32x2(i32, i32); -fn main() { unsafe { - let x = i32x2(0, 1); - simd_select_bitmask(0b11111111u8, x, x); //~ERROR bitmask less than 8 bits long must be filled with 0s for the remaining bits -} } +fn main() { + unsafe { + let x = i32x2(0, 1); + simd_select_bitmask(0b11111111u8, x, x); //~ERROR bitmask less than 8 bits long must be filled with 0s for the remaining bits + } +} diff --git a/tests/fail/intrinsics/simd-select-invalid-bool.rs b/tests/fail/intrinsics/simd-select-invalid-bool.rs index 98f67cfcd7e1..8ccf4c362c90 100644 --- a/tests/fail/intrinsics/simd-select-invalid-bool.rs +++ b/tests/fail/intrinsics/simd-select-invalid-bool.rs @@ -9,7 +9,9 @@ extern "platform-intrinsic" { #[derive(Copy, Clone)] struct i32x2(i32, i32); -fn main() { unsafe { - let x = i32x2(0, 1); - simd_select(x, x, x); //~ERROR must be all-0-bits or all-1-bits -} } +fn main() { + unsafe { + let x = i32x2(0, 1); + simd_select(x, x, x); //~ERROR must be all-0-bits or all-1-bits + } +} diff --git a/tests/fail/intrinsics/simd-shl-too-far.rs b/tests/fail/intrinsics/simd-shl-too-far.rs index b973386f1b5c..e971b042066c 100644 --- a/tests/fail/intrinsics/simd-shl-too-far.rs +++ b/tests/fail/intrinsics/simd-shl-too-far.rs @@ -8,8 +8,10 @@ extern "platform-intrinsic" { #[allow(non_camel_case_types)] struct i32x2(i32, i32); -fn main() { unsafe { - let x = i32x2(1, 1); - let y = i32x2(100, 0); - simd_shl(x, y); //~ERROR overflowing shift by 100 in `simd_shl` in SIMD lane 0 -} } +fn main() { + unsafe { + let x = i32x2(1, 1); + let y = i32x2(100, 0); + simd_shl(x, y); //~ERROR overflowing shift by 100 in `simd_shl` in SIMD lane 0 + } +} diff --git a/tests/fail/intrinsics/simd-shr-too-far.rs b/tests/fail/intrinsics/simd-shr-too-far.rs index 0b4eb8c11679..ae071f0b7ea1 100644 --- a/tests/fail/intrinsics/simd-shr-too-far.rs +++ b/tests/fail/intrinsics/simd-shr-too-far.rs @@ -8,8 +8,10 @@ extern "platform-intrinsic" { #[allow(non_camel_case_types)] struct i32x2(i32, i32); -fn main() { unsafe { - let x = i32x2(1, 1); - let y = i32x2(20, 40); - simd_shr(x, y); //~ERROR overflowing shift by 40 in `simd_shr` in SIMD lane 1 -} } +fn main() { + unsafe { + let x = i32x2(1, 1); + let y = i32x2(20, 40); + simd_shr(x, y); //~ERROR overflowing shift by 40 in `simd_shr` in SIMD lane 1 + } +} diff --git a/tests/fail/invalid_enum_tag.rs b/tests/fail/invalid_enum_tag.rs index 63b6003f3d89..7ba4da9018a7 100644 --- a/tests/fail/invalid_enum_tag.rs +++ b/tests/fail/invalid_enum_tag.rs @@ -8,7 +8,10 @@ use std::mem; #[repr(C)] pub enum Foo { - A, B, C, D + A, + B, + C, + D, } fn main() { diff --git a/tests/fail/issue-miri-1112.rs b/tests/fail/issue-miri-1112.rs index a00bed190e60..caf2b28c5a86 100644 --- a/tests/fail/issue-miri-1112.rs +++ b/tests/fail/issue-miri-1112.rs @@ -12,11 +12,7 @@ pub struct Meta { impl Meta { pub fn new() -> Self { - Meta { - drop_fn: |_| {}, - size: 0, - align: 1, - } + Meta { drop_fn: |_| {}, size: 0, align: 1 } } } diff --git a/tests/fail/memleak_rc.rs b/tests/fail/memleak_rc.rs index 17bcb36f3610..9ea809f76299 100644 --- a/tests/fail/memleak_rc.rs +++ b/tests/fail/memleak_rc.rs @@ -2,8 +2,8 @@ // stderr-per-bitwidth // normalize-stderr-test: ".*│.*" -> "$$stripped$$" -use std::rc::Rc; use std::cell::RefCell; +use std::rc::Rc; struct Dummy(Rc>>); diff --git a/tests/fail/modifying_constants.rs b/tests/fail/modifying_constants.rs index 2d18dccd319c..0c884142bf1d 100644 --- a/tests/fail/modifying_constants.rs +++ b/tests/fail/modifying_constants.rs @@ -4,6 +4,6 @@ fn main() { let x = &1; // the `&1` is promoted to a constant, but it used to be that only the pointer is marked static, not the pointee let y = unsafe { &mut *(x as *const i32 as *mut i32) }; - *y = 42; //~ ERROR read-only + *y = 42; //~ ERROR read-only assert_eq!(*x, 42); } diff --git a/tests/fail/never_say_never.rs b/tests/fail/never_say_never.rs index 37dfe827d997..7aae8a29211e 100644 --- a/tests/fail/never_say_never.rs +++ b/tests/fail/never_say_never.rs @@ -7,9 +7,11 @@ fn main() { let y = &5; let x: ! = unsafe { - *(y as *const _ as *const !) //~ ERROR entering unreachable code + *(y as *const _ as *const !) //~ ERROR entering unreachable code }; f(x) } -fn f(x: !) -> ! { x } +fn f(x: !) -> ! { + x +} diff --git a/tests/fail/never_transmute_void.rs b/tests/fail/never_transmute_void.rs index e5aa04dfec1a..f5d0f914dac7 100644 --- a/tests/fail/never_transmute_void.rs +++ b/tests/fail/never_transmute_void.rs @@ -14,8 +14,6 @@ mod m { } fn main() { - let v = unsafe { - std::mem::transmute::<(), m::Void>(()) - }; + let v = unsafe { std::mem::transmute::<(), m::Void>(()) }; m::f(v); //~ inside `main` } diff --git a/tests/fail/rc_as_ptr.rs b/tests/fail/rc_as_ptr.rs index dc4e099982f8..049330ef363c 100644 --- a/tests/fail/rc_as_ptr.rs +++ b/tests/fail/rc_as_ptr.rs @@ -1,8 +1,8 @@ // This should fail even without validation // compile-flags: -Zmiri-disable-validation -use std::rc::{Rc, Weak}; use std::ptr; +use std::rc::{Rc, Weak}; /// Taken from the `Weak::as_ptr` doctest. fn main() { diff --git a/tests/fail/reading_half_a_pointer.rs b/tests/fail/reading_half_a_pointer.rs index 6e765a1b0ba1..2a3b096b2f5a 100644 --- a/tests/fail/reading_half_a_pointer.rs +++ b/tests/fail/reading_half_a_pointer.rs @@ -13,7 +13,7 @@ struct Wrapper { data: Data, } -static G : i32 = 0; +static G: i32 = 0; fn main() { let mut w = Wrapper { align: 0, data: Data { pad: 0, ptr: &G } }; diff --git a/tests/fail/shim_arg_size.rs b/tests/fail/shim_arg_size.rs index 1297e5ed070f..37557de0a5e4 100644 --- a/tests/fail/shim_arg_size.rs +++ b/tests/fail/shim_arg_size.rs @@ -4,10 +4,10 @@ fn main() { extern "C" { // Use the wrong type(ie. not the pointer width) for the `size` // argument. - #[cfg(target_pointer_width="64")] + #[cfg(target_pointer_width = "64")] fn malloc(size: u32) -> *mut std::ffi::c_void; - #[cfg(target_pointer_width="32")] + #[cfg(target_pointer_width = "32")] fn malloc(size: u16) -> *mut std::ffi::c_void; } diff --git a/tests/fail/should-pass/cpp20_rwc_syncs.rs b/tests/fail/should-pass/cpp20_rwc_syncs.rs index 00b03bceb65e..85c24246dbeb 100644 --- a/tests/fail/should-pass/cpp20_rwc_syncs.rs +++ b/tests/fail/should-pass/cpp20_rwc_syncs.rs @@ -76,7 +76,9 @@ fn test_cpp20_rwc_syncs() { // Our ui_test does not yet support overriding failure status codes. if (b, c) == (0, 0) { // This *should* be unreachable, but Miri will reach it. - unsafe { std::hint::unreachable_unchecked(); } + unsafe { + std::hint::unreachable_unchecked(); + } } } diff --git a/tests/fail/stacked_borrows/alias_through_mutation.rs b/tests/fail/stacked_borrows/alias_through_mutation.rs index 4a153d74ffb0..15d8e45f8b8b 100644 --- a/tests/fail/stacked_borrows/alias_through_mutation.rs +++ b/tests/fail/stacked_borrows/alias_through_mutation.rs @@ -1,6 +1,8 @@ // This makes a ref that was passed to us via &mut alias with things it should not alias with fn retarget(x: &mut &u32, target: &mut u32) { - unsafe { *x = &mut *(target as *mut _); } + unsafe { + *x = &mut *(target as *mut _); + } } fn main() { diff --git a/tests/fail/stacked_borrows/aliasing_mut1.rs b/tests/fail/stacked_borrows/aliasing_mut1.rs index d047925163bd..ebee134a8acb 100644 --- a/tests/fail/stacked_borrows/aliasing_mut1.rs +++ b/tests/fail/stacked_borrows/aliasing_mut1.rs @@ -8,8 +8,7 @@ fn main() { // We need to apply some tricky to be able to call `safe` with two mutable references // with the same tag: We transmute both the fn ptr (to take raw ptrs) and the argument // (to be raw, but still have the unique tag). - let safe_raw: fn(x: *mut i32, y: *mut i32) = unsafe { - mem::transmute::(safe) - }; + let safe_raw: fn(x: *mut i32, y: *mut i32) = + unsafe { mem::transmute::(safe) }; safe_raw(xraw, xraw); } diff --git a/tests/fail/stacked_borrows/aliasing_mut2.rs b/tests/fail/stacked_borrows/aliasing_mut2.rs index c679e01677eb..971dbb63a9d6 100644 --- a/tests/fail/stacked_borrows/aliasing_mut2.rs +++ b/tests/fail/stacked_borrows/aliasing_mut2.rs @@ -8,8 +8,7 @@ fn main() { let xraw: *mut i32 = unsafe { mem::transmute_copy(&xref) }; let xshr = &*xref; // transmute fn ptr around so that we can avoid retagging - let safe_raw: fn(x: *const i32, y: *mut i32) = unsafe { - mem::transmute::(safe) - }; + let safe_raw: fn(x: *const i32, y: *mut i32) = + unsafe { mem::transmute::(safe) }; safe_raw(xshr, xraw); } diff --git a/tests/fail/stacked_borrows/aliasing_mut3.rs b/tests/fail/stacked_borrows/aliasing_mut3.rs index 3943e9576158..91904b0b1d14 100644 --- a/tests/fail/stacked_borrows/aliasing_mut3.rs +++ b/tests/fail/stacked_borrows/aliasing_mut3.rs @@ -8,8 +8,7 @@ fn main() { let xraw: *mut i32 = unsafe { mem::transmute_copy(&xref) }; let xshr = &*xref; // transmute fn ptr around so that we can avoid retagging - let safe_raw: fn(x: *mut i32, y: *const i32) = unsafe { - mem::transmute::(safe) - }; + let safe_raw: fn(x: *mut i32, y: *const i32) = + unsafe { mem::transmute::(safe) }; safe_raw(xraw, xshr); } diff --git a/tests/fail/stacked_borrows/aliasing_mut4.rs b/tests/fail/stacked_borrows/aliasing_mut4.rs index 778935a6d0b0..79caed5dd6b4 100644 --- a/tests/fail/stacked_borrows/aliasing_mut4.rs +++ b/tests/fail/stacked_borrows/aliasing_mut4.rs @@ -1,5 +1,5 @@ -use std::mem; use std::cell::Cell; +use std::mem; // Make sure &mut UnsafeCell also is exclusive pub fn safe(_x: &i32, _y: &mut Cell) {} //~ ERROR protect @@ -10,8 +10,7 @@ fn main() { let xraw: *mut i32 = unsafe { mem::transmute_copy(&xref) }; let xshr = &*xref; // transmute fn ptr around so that we can avoid retagging - let safe_raw: fn(x: *const i32, y: *mut Cell) = unsafe { - mem::transmute::), _>(safe) - }; + let safe_raw: fn(x: *const i32, y: *mut Cell) = + unsafe { mem::transmute::), _>(safe) }; safe_raw(xshr, xraw as *mut _); } diff --git a/tests/fail/stacked_borrows/box_exclusive_violation1.rs b/tests/fail/stacked_borrows/box_exclusive_violation1.rs index 7d7f5e24e2b0..3ca480ae7ab8 100644 --- a/tests/fail/stacked_borrows/box_exclusive_violation1.rs +++ b/tests/fail/stacked_borrows/box_exclusive_violation1.rs @@ -1,14 +1,14 @@ fn demo_mut_advanced_unique(mut our: Box) -> i32 { - unknown_code_1(&*our); + unknown_code_1(&*our); - // This "re-asserts" uniqueness of the reference: After writing, we know - // our tag is at the top of the stack. - *our = 5; + // This "re-asserts" uniqueness of the reference: After writing, we know + // our tag is at the top of the stack. + *our = 5; - unknown_code_2(); + unknown_code_2(); - // We know this will return 5 - *our //~ ERROR borrow stack + // We know this will return 5 + *our //~ ERROR borrow stack } // Now comes the evil context @@ -16,13 +16,17 @@ use std::ptr; static mut LEAK: *mut i32 = ptr::null_mut(); -fn unknown_code_1(x: &i32) { unsafe { - LEAK = x as *const _ as *mut _; -} } +fn unknown_code_1(x: &i32) { + unsafe { + LEAK = x as *const _ as *mut _; + } +} -fn unknown_code_2() { unsafe { - *LEAK = 7; -} } +fn unknown_code_2() { + unsafe { + *LEAK = 7; + } +} fn main() { demo_mut_advanced_unique(Box::new(0)); diff --git a/tests/fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/fail/stacked_borrows/buggy_as_mut_slice.rs index 9ff67ae35422..6744e4ef4481 100644 --- a/tests/fail/stacked_borrows/buggy_as_mut_slice.rs +++ b/tests/fail/stacked_borrows/buggy_as_mut_slice.rs @@ -2,14 +2,12 @@ mod safe { use std::slice::from_raw_parts_mut; pub fn as_mut_slice(self_: &Vec) -> &mut [T] { - unsafe { - from_raw_parts_mut(self_.as_ptr() as *mut T, self_.len()) - } + unsafe { from_raw_parts_mut(self_.as_ptr() as *mut T, self_.len()) } } } fn main() { - let v = vec![0,1,2]; + let v = vec![0, 1, 2]; let v1 = safe::as_mut_slice(&v); let _v2 = safe::as_mut_slice(&v); v1[1] = 5; diff --git a/tests/fail/stacked_borrows/buggy_split_at_mut.rs b/tests/fail/stacked_borrows/buggy_split_at_mut.rs index 798f68fa13cc..a2ef0fcf178d 100644 --- a/tests/fail/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/fail/stacked_borrows/buggy_split_at_mut.rs @@ -8,14 +8,16 @@ mod safe { unsafe { assert!(mid <= len); - (from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" - from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) + ( + from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" + from_raw_parts_mut(ptr.offset(mid as isize), len - mid), + ) } } } fn main() { - let mut array = [1,2,3,4]; + let mut array = [1, 2, 3, 4]; let (a, b) = safe::split_at_mut(&mut array, 0); //~^ ERROR borrow stack a[1] = 5; diff --git a/tests/fail/stacked_borrows/illegal_read6.rs b/tests/fail/stacked_borrows/illegal_read6.rs index dc3781472900..af89566f6507 100644 --- a/tests/fail/stacked_borrows/illegal_read6.rs +++ b/tests/fail/stacked_borrows/illegal_read6.rs @@ -1,8 +1,10 @@ // Creating a shared reference does not leak the data to raw pointers. -fn main() { unsafe { - let x = &mut 0; - let raw = x as *mut _; - let x = &mut *x; // kill `raw` - let _y = &*x; // this should not activate `raw` again - let _val = *raw; //~ ERROR borrow stack -} } +fn main() { + unsafe { + let x = &mut 0; + let raw = x as *mut _; + let x = &mut *x; // kill `raw` + let _y = &*x; // this should not activate `raw` again + let _val = *raw; //~ ERROR borrow stack + } +} diff --git a/tests/fail/stacked_borrows/illegal_read7.rs b/tests/fail/stacked_borrows/illegal_read7.rs index 25d0878c0455..e960bd5388c0 100644 --- a/tests/fail/stacked_borrows/illegal_read7.rs +++ b/tests/fail/stacked_borrows/illegal_read7.rs @@ -4,17 +4,19 @@ use std::cell::Cell; use std::ptr; -fn main() { unsafe { - let x = &mut Cell::new(0); - let raw = x as *mut Cell; - let x = &mut *raw; - let _shr = &*x; - // The state here is interesting because the top of the stack is [Unique, SharedReadWrite], - // just like if we had done `x as *mut _`. - // If we said that reading from a lower item is fine if the top item is `SharedReadWrite` - // (one way to maybe preserve a stack discipline), then we could now read from `raw` - // without invalidating `x`. That would be bad! It would mean that creating `shr` - // leaked `x` to `raw`. - let _val = ptr::read(raw); - let _val = *x.get_mut(); //~ ERROR borrow stack -} } +fn main() { + unsafe { + let x = &mut Cell::new(0); + let raw = x as *mut Cell; + let x = &mut *raw; + let _shr = &*x; + // The state here is interesting because the top of the stack is [Unique, SharedReadWrite], + // just like if we had done `x as *mut _`. + // If we said that reading from a lower item is fine if the top item is `SharedReadWrite` + // (one way to maybe preserve a stack discipline), then we could now read from `raw` + // without invalidating `x`. That would be bad! It would mean that creating `shr` + // leaked `x` to `raw`. + let _val = ptr::read(raw); + let _val = *x.get_mut(); //~ ERROR borrow stack + } +} diff --git a/tests/fail/stacked_borrows/illegal_read8.rs b/tests/fail/stacked_borrows/illegal_read8.rs index 72fca84ba19b..9fef673fe6c1 100644 --- a/tests/fail/stacked_borrows/illegal_read8.rs +++ b/tests/fail/stacked_borrows/illegal_read8.rs @@ -1,13 +1,15 @@ // Make sure that creating a raw ptr next to a shared ref works // but the shared ref still gets invalidated when the raw ptr is used for writing. -fn main() { unsafe { - use std::mem; - let x = &mut 0; - let y1: &i32 = mem::transmute(&*x); // launder lifetimes - let y2 = x as *mut _; - let _val = *y2; - let _val = *y1; - *y2 += 1; - let _fail = *y1; //~ ERROR borrow stack -} } +fn main() { + unsafe { + use std::mem; + let x = &mut 0; + let y1: &i32 = mem::transmute(&*x); // launder lifetimes + let y2 = x as *mut _; + let _val = *y2; + let _val = *y1; + *y2 += 1; + let _fail = *y1; //~ ERROR borrow stack + } +} diff --git a/tests/fail/stacked_borrows/interior_mut1.rs b/tests/fail/stacked_borrows/interior_mut1.rs index e2f8233bd86b..1ef78edbb7ce 100644 --- a/tests/fail/stacked_borrows/interior_mut1.rs +++ b/tests/fail/stacked_borrows/interior_mut1.rs @@ -1,15 +1,17 @@ use std::cell::UnsafeCell; -fn main() { unsafe { - let c = &UnsafeCell::new(UnsafeCell::new(0)); - let inner_uniq = &mut *c.get(); - // stack: [c: SharedReadWrite, inner_uniq: Unique] +fn main() { + unsafe { + let c = &UnsafeCell::new(UnsafeCell::new(0)); + let inner_uniq = &mut *c.get(); + // stack: [c: SharedReadWrite, inner_uniq: Unique] - let inner_shr = &*inner_uniq; // adds a SharedReadWrite - // stack: [c: SharedReadWrite, inner_uniq: Unique, inner_shr: SharedReadWrite] + let inner_shr = &*inner_uniq; // adds a SharedReadWrite + // stack: [c: SharedReadWrite, inner_uniq: Unique, inner_shr: SharedReadWrite] - *c.get() = UnsafeCell::new(1); // invalidates inner_shr - // stack: [c: SharedReadWrite] + *c.get() = UnsafeCell::new(1); // invalidates inner_shr + // stack: [c: SharedReadWrite] - let _val = *inner_shr.get(); //~ ERROR borrow stack -} } + let _val = *inner_shr.get(); //~ ERROR borrow stack + } +} diff --git a/tests/panic/panic/panic1.rs b/tests/panic/panic/panic1.rs index cfaa642beb8e..e15d7656de83 100644 --- a/tests/panic/panic/panic1.rs +++ b/tests/panic/panic/panic1.rs @@ -1,7 +1,6 @@ // rustc-env: RUST_BACKTRACE=1 // compile-flags: -Zmiri-disable-isolation - fn main() { std::panic!("panicking from libstd"); } diff --git a/tests/panic/transmute_fat2.rs b/tests/panic/transmute_fat2.rs index 2f0271d5813f..0205433ad9fb 100644 --- a/tests/panic/transmute_fat2.rs +++ b/tests/panic/transmute_fat2.rs @@ -1,16 +1,10 @@ fn main() { - #[cfg(all(target_endian="little", target_pointer_width="64"))] - let bad = unsafe { - std::mem::transmute::(42) - }; - #[cfg(all(target_endian="big", target_pointer_width="64"))] - let bad = unsafe { - std::mem::transmute::(42 << 64) - }; - #[cfg(all(target_endian="little", target_pointer_width="32"))] - let bad = unsafe { - std::mem::transmute::(42) - }; + #[cfg(all(target_endian = "little", target_pointer_width = "64"))] + let bad = unsafe { std::mem::transmute::(42) }; + #[cfg(all(target_endian = "big", target_pointer_width = "64"))] + let bad = unsafe { std::mem::transmute::(42 << 64) }; + #[cfg(all(target_endian = "little", target_pointer_width = "32"))] + let bad = unsafe { std::mem::transmute::(42) }; // This created a slice with length 0, so the following will fail the bounds check. bad[0]; } diff --git a/tests/pass/stacked-borrows/refcell.rs b/tests/pass/stacked-borrows/refcell.rs index 83db10577ceb..ecb6f48d30b0 100644 --- a/tests/pass/stacked-borrows/refcell.rs +++ b/tests/pass/stacked-borrows/refcell.rs @@ -1,4 +1,4 @@ -use std::cell::{RefCell, Ref, RefMut}; +use std::cell::{Ref, RefCell, RefMut}; fn main() { basic(); @@ -70,8 +70,8 @@ fn ref_mut_protector() { /// Make sure we do not have bad enum layout optimizations. fn rust_issue_68303() { - let optional=Some(RefCell::new(false)); - let mut handle=optional.as_ref().unwrap().borrow_mut(); + let optional = Some(RefCell::new(false)); + let mut handle = optional.as_ref().unwrap().borrow_mut(); assert!(optional.is_some()); - *handle=true; + *handle = true; } diff --git a/tests/pass/stacked-borrows/stacked-borrows.rs b/tests/pass/stacked-borrows/stacked-borrows.rs index 80bab726a8f1..131783ef4fb5 100644 --- a/tests/pass/stacked-borrows/stacked-borrows.rs +++ b/tests/pass/stacked-borrows/stacked-borrows.rs @@ -50,7 +50,9 @@ fn mut_raw_then_mut_shr() { let xraw = &mut *xref as *mut _; let xshr = &*xref; assert_eq!(*xshr, 2); - unsafe { *xraw = 4; } + unsafe { + *xraw = 4; + } assert_eq!(x, 4); } @@ -60,7 +62,9 @@ fn mut_shr_then_mut_raw() { let xref = &mut 2; let _xshr = &*xref; let xraw = xref as *mut _; - unsafe { *xraw = 3; } + unsafe { + *xraw = 3; + } assert_eq!(*xref, 3); } @@ -75,7 +79,9 @@ fn mut_raw_mut() { let xraw = xref1 as *mut _; let _xref2 = unsafe { &mut *xraw }; let _val = *xref1; - unsafe { *xraw = 4; } + unsafe { + *xraw = 4; + } // we can now use both xraw and xref1, for reading assert_eq!(*xref1, 4); assert_eq!(unsafe { *xraw }, 4); @@ -112,23 +118,27 @@ fn direct_mut_to_const_raw() { } // Make sure that we can create two raw pointers from a mutable reference and use them both. -fn two_raw() { unsafe { - let x = &mut 0; - let y1 = x as *mut _; - let y2 = x as *mut _; - *y1 += 2; - *y2 += 1; -} } +fn two_raw() { + unsafe { + let x = &mut 0; + let y1 = x as *mut _; + let y2 = x as *mut _; + *y1 += 2; + *y2 += 1; + } +} // Make sure that creating a *mut does not invalidate existing shared references. -fn shr_and_raw() { unsafe { - use std::mem; - let x = &mut 0; - let y1: &i32 = mem::transmute(&*x); // launder lifetimes - let y2 = x as *mut _; - let _val = *y1; - *y2 += 1; -} } +fn shr_and_raw() { + unsafe { + use std::mem; + let x = &mut 0; + let y1: &i32 = mem::transmute(&*x); // launder lifetimes + let y2 = x as *mut _; + let _val = *y1; + *y2 += 1; + } +} fn disjoint_mutable_subborrows() { struct Foo { @@ -136,23 +146,20 @@ fn disjoint_mutable_subborrows() { b: Vec, } - unsafe fn borrow_field_a<'a>(this:*mut Foo) -> &'a mut String { + unsafe fn borrow_field_a<'a>(this: *mut Foo) -> &'a mut String { &mut (*this).a } - unsafe fn borrow_field_b<'a>(this:*mut Foo) -> &'a mut Vec { + unsafe fn borrow_field_b<'a>(this: *mut Foo) -> &'a mut Vec { &mut (*this).b } - let mut foo = Foo { - a: "hello".into(), - b: vec![0,1,2], - }; + let mut foo = Foo { a: "hello".into(), b: vec![0, 1, 2] }; let ptr = &mut foo as *mut Foo; - let a = unsafe{ borrow_field_a(ptr) }; - let b = unsafe{ borrow_field_b(ptr) }; + let a = unsafe { borrow_field_a(ptr) }; + let b = unsafe { borrow_field_b(ptr) }; b.push(4); a.push_str(" world"); eprintln!("{:?} {:?}", a, b); @@ -181,7 +188,9 @@ fn raw_ref_to_part() { fn array_casts() { let mut x: [usize; 2] = [0, 0]; let p = &mut x as *mut usize; - unsafe { *p.add(1) = 1; } + unsafe { + *p.add(1) = 1; + } let x: [usize; 2] = [0, 1]; let p = &x as *const usize; @@ -192,7 +201,7 @@ fn array_casts() { fn mut_below_shr() { let x = 0; let y = &x; - let p = unsafe { core::mem::transmute::<&&i32,&&mut i32>(&y) }; + let p = unsafe { core::mem::transmute::<&&i32, &&mut i32>(&y) }; let r = &**p; let _val = *r; } diff --git a/tests/pass/static_memory_modification.rs b/tests/pass/static_memory_modification.rs index 6a4107817798..84a524b1ed16 100644 --- a/tests/pass/static_memory_modification.rs +++ b/tests/pass/static_memory_modification.rs @@ -1,4 +1,4 @@ -use std::sync::atomic::{Ordering, AtomicUsize}; +use std::sync::atomic::{AtomicUsize, Ordering}; static mut X: usize = 5; static Y: AtomicUsize = AtomicUsize::new(5); diff --git a/tests/pass/static_mut.rs b/tests/pass/static_mut.rs index 0aa6a2e92b62..218b02525bd5 100644 --- a/tests/pass/static_mut.rs +++ b/tests/pass/static_mut.rs @@ -1,5 +1,5 @@ static mut FOO: i32 = 42; -static BAR: Foo = Foo(unsafe { &FOO as *const _} ); +static BAR: Foo = Foo(unsafe { &FOO as *const _ }); #[allow(dead_code)] struct Foo(*const i32); diff --git a/tests/pass/strings.rs b/tests/pass/strings.rs index 77ecaed4fe9b..ccefc69bd180 100644 --- a/tests/pass/strings.rs +++ b/tests/pass/strings.rs @@ -22,7 +22,7 @@ fn fat_pointer_on_32_bit() { fn str_indexing() { let mut x = "Hello".to_string(); - let _v = &mut x[..3]; // Test IndexMut on String. + let _v = &mut x[..3]; // Test IndexMut on String. } fn unique_aliasing() { diff --git a/tests/pass/tag-align-dyn-u64.rs b/tests/pass/tag-align-dyn-u64.rs index 460c2b25594a..72211a8d3f3a 100644 --- a/tests/pass/tag-align-dyn-u64.rs +++ b/tests/pass/tag-align-dyn-u64.rs @@ -11,17 +11,17 @@ use std::mem; enum Tag { - Tag2(A) + Tag2(A), } #[allow(dead_code)] struct Rec { c8: u8, - t: Tag + t: Tag, } fn mk_rec() -> Rec { - return Rec { c8:0, t:Tag::Tag2(0) }; + return Rec { c8: 0, t: Tag::Tag2(0) }; } fn is_u64_aligned(u: &Tag) -> bool { diff --git a/tests/pass/time.rs b/tests/pass/time.rs index cce29003e567..38e846309d72 100644 --- a/tests/pass/time.rs +++ b/tests/pass/time.rs @@ -1,6 +1,6 @@ // compile-flags: -Zmiri-disable-isolation -use std::time::{SystemTime, Instant, Duration}; +use std::time::{Duration, Instant, SystemTime}; fn duration_sanity(diff: Duration) { // On my laptop, I observed times around 15-40ms. Add 10x lee-way both ways. @@ -25,7 +25,9 @@ fn main() { let year = 1970 + years_since_epoch; assert!(2020 <= year && year < 2100); // Do some work to make time pass. - for _ in 0..10 { drop(vec![42]); } + for _ in 0..10 { + drop(vec![42]); + } let now2 = SystemTime::now(); assert!(now2 > now1); // Sanity-check the difference we got. @@ -37,7 +39,9 @@ fn main() { // Check `Instant`. let now1 = Instant::now(); // Do some work to make time pass. - for _ in 0..10 { drop(vec![42]); } + for _ in 0..10 { + drop(vec![42]); + } let now2 = Instant::now(); assert!(now2 > now1); // Sanity-check the difference we got. diff --git a/tests/pass/track-caller-attribute.rs b/tests/pass/track-caller-attribute.rs index d1115faa8f75..dd1e2f809adf 100644 --- a/tests/pass/track-caller-attribute.rs +++ b/tests/pass/track-caller-attribute.rs @@ -16,7 +16,9 @@ fn nested_tracked() -> &'static Location<'static> { } macro_rules! caller_location_from_macro { - () => (core::panic::Location::caller()); + () => { + core::panic::Location::caller() + }; } fn test_fn_ptr() { @@ -62,7 +64,6 @@ fn test_trait_obj() { assert_eq!(location.file(), file!()); assert_eq!(location.line(), expected_line); assert_eq!(location.column(), 28); - } fn main() { diff --git a/tests/pass/transmute_fat.rs b/tests/pass/transmute_fat.rs index c62298a9aced..1d2ec92a8038 100644 --- a/tests/pass/transmute_fat.rs +++ b/tests/pass/transmute_fat.rs @@ -3,9 +3,7 @@ fn main() { // If we are careful, we can exploit data layout... - let raw = unsafe { - std::mem::transmute::<&[u8], [*const u8; 2]>(&[42]) - }; + let raw = unsafe { std::mem::transmute::<&[u8], [*const u8; 2]>(&[42]) }; let ptr: *const u8 = unsafe { std::mem::transmute_copy(&raw) }; assert_eq!(unsafe { *ptr }, 42); } diff --git a/tests/pass/u128.rs b/tests/pass/u128.rs index fae73476275b..c327b5cab3d8 100644 --- a/tests/pass/u128.rs +++ b/tests/pass/u128.rs @@ -8,9 +8,10 @@ fn main() { let y: u128 = 0xFFFF_FFFF_FFFF_FFFF__FFFF_FFFF_FFFF_FFFE; assert_eq!(!1, y); assert_eq!(x, y | 1); - assert_eq!(0xFAFF_0000_FF8F_0000__FFFF_0000_FFFF_FFFE, - y & - 0xFAFF_0000_FF8F_0000__FFFF_0000_FFFF_FFFF); + assert_eq!( + 0xFAFF_0000_FF8F_0000__FFFF_0000_FFFF_FFFE, + y & 0xFAFF_0000_FF8F_0000__FFFF_0000_FFFF_FFFF + ); let z: u128 = 0xABCD_EF; assert_eq!(z * z, 0x734C_C2F2_A521); assert_eq!(z * z * z * z, 0x33EE_0E2A_54E2_59DA_A0E7_8E41); @@ -19,8 +20,10 @@ fn main() { assert_eq!(k + k, 0x2468_ACF1_3579_BDFF_DB97_530E_CA86_420); assert_eq!(0, k - k); assert_eq!(0x1234_5678_9ABC_DEFF_EDCB_A987_5A86_421, k - z); - assert_eq!(0x1000_0000_0000_0000_0000_0000_0000_000, - k - 0x234_5678_9ABC_DEFF_EDCB_A987_6543_210); + assert_eq!( + 0x1000_0000_0000_0000_0000_0000_0000_000, + k - 0x234_5678_9ABC_DEFF_EDCB_A987_6543_210 + ); assert_eq!(0x6EF5_DE4C_D3BC_2AAA_3BB4_CC5D_D6EE_8, k / 42); assert_eq!(0, k % 42); assert_eq!(15, z % 42); @@ -38,7 +41,7 @@ fn main() { assert_eq!((z as f32) as u128, z); assert_eq!((z as f64 * 16.0) as u128, z * 16); assert_eq!((z as f32 * 16.0) as u128, z * 16); - let l :u128 = 432 << 100; + let l: u128 = 432 << 100; assert_eq!((l as f32) as u128, l); assert_eq!((l as f64) as u128, l); // formatting @@ -46,10 +49,11 @@ fn main() { assert_eq!("147573952589676412928", format!("{}", j)); assert_eq!("80000000000000000", format!("{:x}", j)); assert_eq!("20000000000000000000000", format!("{:o}", j)); - assert_eq!("10000000000000000000000000000000000000000000000000000000000000000000", - format!("{:b}", j)); - assert_eq!("340282366920938463463374607431768211455", - format!("{}", u128::MAX)); + assert_eq!( + "10000000000000000000000000000000000000000000000000000000000000000000", + format!("{:b}", j) + ); + assert_eq!("340282366920938463463374607431768211455", format!("{}", u128::MAX)); assert_eq!("147573952589676412928", format!("{:?}", j)); // common traits assert_eq!(x, b(x.clone())); diff --git a/tests/pass/union.rs b/tests/pass/union.rs index c80918ee527c..bf7a7b828175 100644 --- a/tests/pass/union.rs +++ b/tests/pass/union.rs @@ -45,7 +45,10 @@ fn b() { fn c() { #[repr(u32)] - enum Tag { I, F } + enum Tag { + I, + F, + } #[repr(C)] union U { @@ -68,10 +71,10 @@ fn c() { } } } - assert!(is_zero(Value { tag: Tag::I, u: U { i: 0 }})); - assert!(is_zero(Value { tag: Tag::F, u: U { f: 0.0 }})); - assert!(!is_zero(Value { tag: Tag::I, u: U { i: 1 }})); - assert!(!is_zero(Value { tag: Tag::F, u: U { f: 42.0 }})); + assert!(is_zero(Value { tag: Tag::I, u: U { i: 0 } })); + assert!(is_zero(Value { tag: Tag::F, u: U { f: 0.0 } })); + assert!(!is_zero(Value { tag: Tag::I, u: U { i: 1 } })); + assert!(!is_zero(Value { tag: Tag::F, u: U { f: 42.0 } })); } fn d() { @@ -82,8 +85,10 @@ fn d() { let u = MyUnion { f1: 10 }; unsafe { match u { - MyUnion { f1: 10 } => { } - MyUnion { f2: _f2 } => { panic!("foo"); } + MyUnion { f1: 10 } => {} + MyUnion { f2: _f2 } => { + panic!("foo"); + } } } } diff --git a/tests/pass/unops.rs b/tests/pass/unops.rs index 650c51ba5d99..f23f68ccbad0 100644 --- a/tests/pass/unops.rs +++ b/tests/pass/unops.rs @@ -1,5 +1,5 @@ fn main() { assert_eq!(!true, false); assert_eq!(!0xFFu16, 0xFF00); - assert_eq!(-{1i16}, -1i16); + assert_eq!(-{ 1i16 }, -1i16); } diff --git a/tests/pass/unsized-tuple-impls.rs b/tests/pass/unsized-tuple-impls.rs index 54bd6f5c34f8..bbab1125a0af 100644 --- a/tests/pass/unsized-tuple-impls.rs +++ b/tests/pass/unsized-tuple-impls.rs @@ -2,8 +2,8 @@ use std::mem; fn main() { - let x : &(i32, i32, [i32]) = &(0, 1, [2, 3]); - let y : &(i32, i32, [i32]) = &(0, 1, [2, 3, 4]); + let x: &(i32, i32, [i32]) = &(0, 1, [2, 3]); + let y: &(i32, i32, [i32]) = &(0, 1, [2, 3, 4]); let mut a = [y, x]; a.sort(); assert_eq!(a, [x, y]); diff --git a/tests/pass/validation_lifetime_resolution.rs b/tests/pass/validation_lifetime_resolution.rs index a0eea517095b..f5eef2ad6e75 100644 --- a/tests/pass/validation_lifetime_resolution.rs +++ b/tests/pass/validation_lifetime_resolution.rs @@ -7,16 +7,22 @@ trait Id { impl<'a> Id for &'a mut i32 { type Out = &'a mut i32; - fn id(self) -> Self { self } + fn id(self) -> Self { + self + } } impl<'a> Id for &'a mut u32 { type Out = &'a mut u32; - fn id(self) -> Self { self } + fn id(self) -> Self { + self + } } -fn foo(mut x: T) where for<'a> &'a mut T: Id +fn foo(mut x: T) +where + for<'a> &'a mut T: Id, { let x = &mut x; let _y = x.id(); diff --git a/tests/pass/vec-matching-fold.rs b/tests/pass/vec-matching-fold.rs index 749f93fc0fd2..3a869703bf96 100644 --- a/tests/pass/vec-matching-fold.rs +++ b/tests/pass/vec-matching-fold.rs @@ -1,32 +1,30 @@ use std::fmt::Debug; -fn foldl(values: &[T], - initial: U, - mut function: F) - -> U where - U: Clone+Debug, T:Debug, +fn foldl(values: &[T], initial: U, mut function: F) -> U +where + U: Clone + Debug, + T: Debug, F: FnMut(U, &T) -> U, -{ match values { - [head, tail @ ..] => - foldl(tail, function(initial, head), function), +{ + match values { + [head, tail @ ..] => foldl(tail, function(initial, head), function), [] => { - let res = initial.clone(); res + let res = initial.clone(); + res } } } -fn foldr(values: &[T], - initial: U, - mut function: F) - -> U where +fn foldr(values: &[T], initial: U, mut function: F) -> U +where U: Clone, F: FnMut(&T, U) -> U, { match values { - [head @ .., tail] => - foldr(head, function(tail, initial), function), + [head @ .., tail] => foldr(head, function(tail, initial), function), [] => { - let res = initial.clone(); res + let res = initial.clone(); + res } } } diff --git a/tests/pass/vec.rs b/tests/pass/vec.rs index 788f05ce9774..89c2561acd97 100644 --- a/tests/pass/vec.rs +++ b/tests/pass/vec.rs @@ -33,51 +33,37 @@ fn make_vec_macro_repeat_zeroed() -> Vec { } fn vec_into_iter() -> u8 { - vec![1, 2, 3, 4] - .into_iter() - .map(|x| x * x) - .fold(0, |x, y| x + y) + vec![1, 2, 3, 4].into_iter().map(|x| x * x).fold(0, |x, y| x + y) } fn vec_into_iter_rev() -> u8 { - vec![1, 2, 3, 4] - .into_iter() - .map(|x| x * x) - .fold(0, |x, y| x + y) + vec![1, 2, 3, 4].into_iter().map(|x| x * x).fold(0, |x, y| x + y) } fn vec_into_iter_zst() -> usize { - vec![[0u64; 0], [0u64; 0]] - .into_iter() - .rev() - .map(|x| x.len()) - .sum() + vec![[0u64; 0], [0u64; 0]].into_iter().rev().map(|x| x.len()).sum() } fn vec_into_iter_rev_zst() -> usize { - vec![[0u64; 0], [0u64; 0]] - .into_iter() - .rev() - .map(|x| x.len()) - .sum() + vec![[0u64; 0], [0u64; 0]].into_iter().rev().map(|x| x.len()).sum() } fn vec_iter_and_mut() { - let mut v = vec![1,2,3,4]; + let mut v = vec![1, 2, 3, 4]; for i in v.iter_mut() { *i += 1; } - assert_eq!(v.iter().sum::(), 2+3+4+5); + assert_eq!(v.iter().sum::(), 2 + 3 + 4 + 5); test_all_refs(&mut 13, v.iter_mut()); } fn vec_iter_and_mut_rev() { - let mut v = vec![1,2,3,4]; + let mut v = vec![1, 2, 3, 4]; for i in v.iter_mut().rev() { *i += 1; } - assert_eq!(v.iter().sum::(), 2+3+4+5); + assert_eq!(v.iter().sum::(), 2 + 3 + 4 + 5); } fn vec_reallocate() -> Vec { diff --git a/tests/pass/vecdeque.rs b/tests/pass/vecdeque.rs index fa6707632dc7..d2295a7afb59 100644 --- a/tests/pass/vecdeque.rs +++ b/tests/pass/vecdeque.rs @@ -23,7 +23,7 @@ fn main() { src.push_front(Box::new(2)); dst.append(&mut src); for a in dst.iter() { - assert_eq!(**a, 2); + assert_eq!(**a, 2); } // Regression test for Debug impl's diff --git a/tests/pass/weak_memory/weak.rs b/tests/pass/weak_memory/weak.rs index e1e9c41e36f5..b9ceb61f0c9f 100644 --- a/tests/pass/weak_memory/weak.rs +++ b/tests/pass/weak_memory/weak.rs @@ -94,7 +94,6 @@ fn initialization_write() -> bool { r2 == 11 } - // Asserts that the function returns true at least once in 100 runs macro_rules! assert_once { ($f:ident) => { diff --git a/tests/pass/wtf8.rs b/tests/pass/wtf8.rs index 5a5815068081..e31b00e95244 100644 --- a/tests/pass/wtf8.rs +++ b/tests/pass/wtf8.rs @@ -1,7 +1,7 @@ // only-windows -use std::os::windows::ffi::{OsStrExt, OsStringExt}; use std::ffi::{OsStr, OsString}; +use std::os::windows::ffi::{OsStrExt, OsStringExt}; fn test1() { let base = "a\té \u{7f}💩\r"; diff --git a/tests/pass/zst.rs b/tests/pass/zst.rs index 988473570913..3a853e7d8a68 100644 --- a/tests/pass/zst.rs +++ b/tests/pass/zst.rs @@ -19,6 +19,10 @@ fn main() { assert_eq!(use_zst(), A); let x = 42 as *mut [u8; 0]; // Reading and writing is ok. - unsafe { *x = zst_val; } - unsafe { let _y = *x; } + unsafe { + *x = zst_val; + } + unsafe { + let _y = *x; + } } From 30376ba709ef627d09a0ff365cd76ec58f329880 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 20 Jun 2022 23:45:49 -0700 Subject: [PATCH 3306/5092] Manual adjustments --- tests/pass/u128.rs | 6 +++--- tests/pass/union.rs | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/pass/u128.rs b/tests/pass/u128.rs index c327b5cab3d8..0ef7a514cb65 100644 --- a/tests/pass/u128.rs +++ b/tests/pass/u128.rs @@ -10,7 +10,7 @@ fn main() { assert_eq!(x, y | 1); assert_eq!( 0xFAFF_0000_FF8F_0000__FFFF_0000_FFFF_FFFE, - y & 0xFAFF_0000_FF8F_0000__FFFF_0000_FFFF_FFFF + y & 0xFAFF_0000_FF8F_0000__FFFF_0000_FFFF_FFFF, ); let z: u128 = 0xABCD_EF; assert_eq!(z * z, 0x734C_C2F2_A521); @@ -22,7 +22,7 @@ fn main() { assert_eq!(0x1234_5678_9ABC_DEFF_EDCB_A987_5A86_421, k - z); assert_eq!( 0x1000_0000_0000_0000_0000_0000_0000_000, - k - 0x234_5678_9ABC_DEFF_EDCB_A987_6543_210 + k - 0x234_5678_9ABC_DEFF_EDCB_A987_6543_210, ); assert_eq!(0x6EF5_DE4C_D3BC_2AAA_3BB4_CC5D_D6EE_8, k / 42); assert_eq!(0, k % 42); @@ -51,7 +51,7 @@ fn main() { assert_eq!("20000000000000000000000", format!("{:o}", j)); assert_eq!( "10000000000000000000000000000000000000000000000000000000000000000000", - format!("{:b}", j) + format!("{:b}", j), ); assert_eq!("340282366920938463463374607431768211455", format!("{}", u128::MAX)); assert_eq!("147573952589676412928", format!("{:?}", j)); diff --git a/tests/pass/union.rs b/tests/pass/union.rs index bf7a7b828175..f98a21310285 100644 --- a/tests/pass/union.rs +++ b/tests/pass/union.rs @@ -86,9 +86,7 @@ fn d() { unsafe { match u { MyUnion { f1: 10 } => {} - MyUnion { f2: _f2 } => { - panic!("foo"); - } + MyUnion { f2: _f2 } => panic!("foo"), } } } From 1c66163871fc0c88bdfa435b8c5d6aedf2a3d4c7 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 20 Jun 2022 23:49:55 -0700 Subject: [PATCH 3307/5092] Bless stderr files after rustfmt --- tests/fail/intrinsics/simd-rem-by-zero.stderr | 4 ++-- tests/fail/intrinsics/simd-scatter.stderr | 8 ++++++-- .../simd-select-bitmask-invalid.stderr | 4 ++-- .../simd-select-invalid-bool.stderr | 4 ++-- tests/fail/intrinsics/simd-shl-too-far.stderr | 4 ++-- tests/fail/intrinsics/simd-shr-too-far.stderr | 4 ++-- tests/fail/should-pass/cpp20_rwc_syncs.stderr | 4 ++-- .../alias_through_mutation.stderr | 4 ++-- .../box_exclusive_violation1.stderr | 20 +++++++++---------- .../stacked_borrows/buggy_as_mut_slice.stderr | 4 ++-- .../stacked_borrows/buggy_split_at_mut.stderr | 8 ++++---- .../fail/stacked_borrows/illegal_read6.stderr | 18 ++++++++--------- .../fail/stacked_borrows/illegal_read7.stderr | 18 ++++++++--------- .../fail/stacked_borrows/illegal_read8.stderr | 18 ++++++++--------- .../fail/stacked_borrows/interior_mut1.stderr | 18 ++++++++--------- 15 files changed, 72 insertions(+), 68 deletions(-) diff --git a/tests/fail/intrinsics/simd-rem-by-zero.stderr b/tests/fail/intrinsics/simd-rem-by-zero.stderr index 98e5ca207972..1adc9f8235ee 100644 --- a/tests/fail/intrinsics/simd-rem-by-zero.stderr +++ b/tests/fail/intrinsics/simd-rem-by-zero.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: calculating the remainder with a divisor of zero --> $DIR/simd-rem-by-zero.rs:LL:CC | -LL | simd_rem(x, y); - | ^^^^^^^^^^^^^^ calculating the remainder with a divisor of zero +LL | simd_rem(x, y); + | ^^^^^^^^^^^^^^ calculating the remainder with a divisor of zero | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/simd-scatter.stderr b/tests/fail/intrinsics/simd-scatter.stderr index 08536c611255..bc6a06fc88e5 100644 --- a/tests/fail/intrinsics/simd-scatter.stderr +++ b/tests/fail/intrinsics/simd-scatter.stderr @@ -11,8 +11,12 @@ LL | intrinsics::simd_scatter(self, ptrs, enable.to_int()) note: inside `main` at $DIR/simd-scatter.rs:LL:CC --> $DIR/simd-scatter.rs:LL:CC | -LL | Simd::from_array([-27, 82, -41, 124]).scatter_select_unchecked(&mut vec, Mask::splat(true), idxs); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | / Simd::from_array([-27, 82, -41, 124]).scatter_select_unchecked( +LL | | &mut vec, +LL | | Mask::splat(true), +LL | | idxs, +LL | | ); + | |_________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr b/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr index e5fe3c886cb8..0a72ed39827b 100644 --- a/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr +++ b/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits --> $DIR/simd-select-bitmask-invalid.rs:LL:CC | -LL | simd_select_bitmask(0b11111111u8, x, x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits +LL | simd_select_bitmask(0b11111111u8, x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/simd-select-invalid-bool.stderr b/tests/fail/intrinsics/simd-select-invalid-bool.stderr index f0a1282edac4..c0ceaac06cdd 100644 --- a/tests/fail/intrinsics/simd-select-invalid-bool.stderr +++ b/tests/fail/intrinsics/simd-select-invalid-bool.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: each element of a SIMD mask must be all-0-bits or all-1-bits --> $DIR/simd-select-invalid-bool.rs:LL:CC | -LL | simd_select(x, x, x); - | ^^^^^^^^^^^^^^^^^^^^ each element of a SIMD mask must be all-0-bits or all-1-bits +LL | simd_select(x, x, x); + | ^^^^^^^^^^^^^^^^^^^^ each element of a SIMD mask must be all-0-bits or all-1-bits | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/simd-shl-too-far.stderr b/tests/fail/intrinsics/simd-shl-too-far.stderr index dcd38d6f0114..1d990e341e68 100644 --- a/tests/fail/intrinsics/simd-shl-too-far.stderr +++ b/tests/fail/intrinsics/simd-shl-too-far.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflowing shift by 100 in `simd_shl` in SIMD lane 0 --> $DIR/simd-shl-too-far.rs:LL:CC | -LL | simd_shl(x, y); - | ^^^^^^^^^^^^^^ overflowing shift by 100 in `simd_shl` in SIMD lane 0 +LL | simd_shl(x, y); + | ^^^^^^^^^^^^^^ overflowing shift by 100 in `simd_shl` in SIMD lane 0 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/simd-shr-too-far.stderr b/tests/fail/intrinsics/simd-shr-too-far.stderr index c2c2850522f5..58ef3737545a 100644 --- a/tests/fail/intrinsics/simd-shr-too-far.stderr +++ b/tests/fail/intrinsics/simd-shr-too-far.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflowing shift by 40 in `simd_shr` in SIMD lane 1 --> $DIR/simd-shr-too-far.rs:LL:CC | -LL | simd_shr(x, y); - | ^^^^^^^^^^^^^^ overflowing shift by 40 in `simd_shr` in SIMD lane 1 +LL | simd_shr(x, y); + | ^^^^^^^^^^^^^^ overflowing shift by 40 in `simd_shr` in SIMD lane 1 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/should-pass/cpp20_rwc_syncs.stderr b/tests/fail/should-pass/cpp20_rwc_syncs.stderr index 9aec82d33365..5f0e86dc653e 100644 --- a/tests/fail/should-pass/cpp20_rwc_syncs.stderr +++ b/tests/fail/should-pass/cpp20_rwc_syncs.stderr @@ -11,8 +11,8 @@ LL | unsafe { intrinsics::unreachable() } note: inside `test_cpp20_rwc_syncs` at $DIR/cpp20_rwc_syncs.rs:LL:CC --> $DIR/cpp20_rwc_syncs.rs:LL:CC | -LL | unsafe { std::hint::unreachable_unchecked(); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | std::hint::unreachable_unchecked(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: inside `main` at $DIR/cpp20_rwc_syncs.rs:LL:CC --> $DIR/cpp20_rwc_syncs.rs:LL:CC | diff --git a/tests/fail/stacked_borrows/alias_through_mutation.stderr b/tests/fail/stacked_borrows/alias_through_mutation.stderr index 610a045efcf2..eb02136478f2 100644 --- a/tests/fail/stacked_borrows/alias_through_mutation.stderr +++ b/tests/fail/stacked_borrows/alias_through_mutation.stderr @@ -12,8 +12,8 @@ LL | let _val = *target_alias; help: was created by a retag at offsets [0x0..0x4] --> $DIR/alias_through_mutation.rs:LL:CC | -LL | unsafe { *x = &mut *(target as *mut _); } - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | *x = &mut *(target as *mut _); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] --> $DIR/alias_through_mutation.rs:LL:CC | diff --git a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr index 90d945128578..3c3e6bbf1bc7 100644 --- a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr +++ b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/box_exclusive_violation1.rs:LL:CC | -LL | *our - | ^^^^ - | | - | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | *our + | ^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -13,18 +13,18 @@ help: was created by a retag at offsets [0x0..0x4] --> $DIR/box_exclusive_violation1.rs:LL:CC | LL | / fn demo_mut_advanced_unique(mut our: Box) -> i32 { -LL | | unknown_code_1(&*our); +LL | | unknown_code_1(&*our); LL | | -LL | | // This "re-asserts" uniqueness of the reference: After writing, we know +LL | | // This "re-asserts" uniqueness of the reference: After writing, we know ... | -LL | | *our +LL | | *our LL | | } | |_^ help: was later invalidated at offsets [0x0..0x4] --> $DIR/box_exclusive_violation1.rs:LL:CC | -LL | *LEAK = 7; - | ^^^^^^^^^ +LL | *LEAK = 7; + | ^^^^^^^^^ = note: inside `demo_mut_advanced_unique` at $DIR/box_exclusive_violation1.rs:LL:CC note: inside `main` at $DIR/box_exclusive_violation1.rs:LL:CC --> $DIR/box_exclusive_violation1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr b/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr index b65e49fd4a7d..14cede13b7a1 100644 --- a/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr +++ b/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr @@ -17,8 +17,8 @@ LL | let v1 = safe::as_mut_slice(&v); help: was later invalidated at offsets [0x0..0xc] --> $DIR/buggy_as_mut_slice.rs:LL:CC | -LL | from_raw_parts_mut(self_.as_ptr() as *mut T, self_.len()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unsafe { from_raw_parts_mut(self_.as_ptr() as *mut T, self_.len()) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: inside `main` at $DIR/buggy_as_mut_slice.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/buggy_split_at_mut.stderr b/tests/fail/stacked_borrows/buggy_split_at_mut.stderr index 1b2536c48e04..47ab7d6a062a 100644 --- a/tests/fail/stacked_borrows/buggy_split_at_mut.stderr +++ b/tests/fail/stacked_borrows/buggy_split_at_mut.stderr @@ -12,13 +12,13 @@ LL | let (a, b) = safe::split_at_mut(&mut array, 0); help: was created by a retag at offsets [0x0..0x10] --> $DIR/buggy_split_at_mut.rs:LL:CC | -LL | (from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x10] --> $DIR/buggy_split_at_mut.rs:LL:CC | -LL | from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | from_raw_parts_mut(ptr.offset(mid as isize), len - mid), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: inside `main` at $DIR/buggy_split_at_mut.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read6.stderr b/tests/fail/stacked_borrows/illegal_read6.stderr index 499f060c47c2..9782f1aa3a58 100644 --- a/tests/fail/stacked_borrows/illegal_read6.stderr +++ b/tests/fail/stacked_borrows/illegal_read6.stderr @@ -1,24 +1,24 @@ error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/illegal_read6.rs:LL:CC | -LL | let _val = *raw; - | ^^^^ - | | - | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | let _val = *raw; + | ^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x4] --> $DIR/illegal_read6.rs:LL:CC | -LL | let raw = x as *mut _; - | ^ +LL | let raw = x as *mut _; + | ^ help: tag was later invalidated at offsets [0x0..0x4] --> $DIR/illegal_read6.rs:LL:CC | -LL | let x = &mut *x; // kill `raw` - | ^^^^^^^ +LL | let x = &mut *x; // kill `raw` + | ^^^^^^^ = note: inside `main` at $DIR/illegal_read6.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read7.stderr b/tests/fail/stacked_borrows/illegal_read7.stderr index e7e1685964bc..3d70945fa6c6 100644 --- a/tests/fail/stacked_borrows/illegal_read7.stderr +++ b/tests/fail/stacked_borrows/illegal_read7.stderr @@ -1,24 +1,24 @@ error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/illegal_read7.rs:LL:CC | -LL | let _val = *x.get_mut(); - | ^^^^^^^^^^^ - | | - | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x4] +LL | let _val = *x.get_mut(); + | ^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_read7.rs:LL:CC | -LL | let x = &mut *raw; - | ^^^^^^^^^ +LL | let x = &mut *raw; + | ^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] --> $DIR/illegal_read7.rs:LL:CC | -LL | let _val = ptr::read(raw); - | ^^^^^^^^^^^^^^ +LL | let _val = ptr::read(raw); + | ^^^^^^^^^^^^^^ = note: inside `main` at $DIR/illegal_read7.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read8.stderr b/tests/fail/stacked_borrows/illegal_read8.stderr index 21df77775c8b..7c0cb0066b27 100644 --- a/tests/fail/stacked_borrows/illegal_read8.stderr +++ b/tests/fail/stacked_borrows/illegal_read8.stderr @@ -1,24 +1,24 @@ error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/illegal_read8.rs:LL:CC | -LL | let _fail = *y1; - | ^^^ - | | - | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | let _fail = *y1; + | ^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_read8.rs:LL:CC | -LL | let y1: &i32 = mem::transmute(&*x); // launder lifetimes - | ^^^^^^^^^^^^^^^^^^^ +LL | let y1: &i32 = mem::transmute(&*x); // launder lifetimes + | ^^^^^^^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] --> $DIR/illegal_read8.rs:LL:CC | -LL | *y2 += 1; - | ^^^^^^^^ +LL | *y2 += 1; + | ^^^^^^^^ = note: inside `main` at $DIR/illegal_read8.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/interior_mut1.stderr b/tests/fail/stacked_borrows/interior_mut1.stderr index 82cb6e19133d..2490fd3e1e9a 100644 --- a/tests/fail/stacked_borrows/interior_mut1.stderr +++ b/tests/fail/stacked_borrows/interior_mut1.stderr @@ -1,24 +1,24 @@ error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/interior_mut1.rs:LL:CC | -LL | let _val = *inner_shr.get(); - | ^^^^^^^^^^^^^^^ - | | - | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x4] +LL | let _val = *inner_shr.get(); + | ^^^^^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/interior_mut1.rs:LL:CC | -LL | let inner_shr = &*inner_uniq; // adds a SharedReadWrite - | ^^^^^^^^^^^^ +LL | let inner_shr = &*inner_uniq; // adds a SharedReadWrite + | ^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] --> $DIR/interior_mut1.rs:LL:CC | -LL | *c.get() = UnsafeCell::new(1); // invalidates inner_shr - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | *c.get() = UnsafeCell::new(1); // invalidates inner_shr + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: inside `main` at $DIR/interior_mut1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace From 3348869f42020680bd588132ae77272e810bd770 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 20 Jun 2022 21:24:06 -0700 Subject: [PATCH 3308/5092] move nopreempt sync tests to their own file --- tests/pass/concurrency/sync.rs | 33 +------------------ tests/pass/concurrency/sync_nopreempt.rs | 40 ++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 32 deletions(-) create mode 100644 tests/pass/concurrency/sync_nopreempt.rs diff --git a/tests/pass/concurrency/sync.rs b/tests/pass/concurrency/sync.rs index 26f44aa43718..5b7805ba2265 100644 --- a/tests/pass/concurrency/sync.rs +++ b/tests/pass/concurrency/sync.rs @@ -1,6 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// We are making scheduler assumptions here. -// compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance -Zmiri-preemption-rate=0 +// compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock}; use std::thread; @@ -53,35 +52,6 @@ fn check_conditional_variables_notify_one() { } } -fn check_conditional_variables_notify_all() { - let pair = Arc::new(((Mutex::new(())), Condvar::new())); - - // Spawn threads and block them on the conditional variable. - let handles: Vec<_> = (0..5) - .map(|_| { - let pair2 = pair.clone(); - thread::spawn(move || { - let (lock, cvar) = &*pair2; - let guard = lock.lock().unwrap(); - // Block waiting on the conditional variable. - let _ = cvar.wait(guard).unwrap(); - }) - }) - .inspect(|_| { - thread::yield_now(); - thread::yield_now(); - }) - .collect(); - - let (_, cvar) = &*pair; - // Unblock all threads. - cvar.notify_all(); - - for handle in handles { - handle.join().unwrap(); - } -} - /// Test that waiting on a conditional variable with a timeout does not /// deadlock. fn check_conditional_variables_timed_wait_timeout() { @@ -301,7 +271,6 @@ fn check_condvar() { fn main() { check_barriers(); check_conditional_variables_notify_one(); - check_conditional_variables_notify_all(); check_conditional_variables_timed_wait_timeout(); check_conditional_variables_timed_wait_notimeout(); check_mutex(); diff --git a/tests/pass/concurrency/sync_nopreempt.rs b/tests/pass/concurrency/sync_nopreempt.rs new file mode 100644 index 000000000000..38dbeb575d64 --- /dev/null +++ b/tests/pass/concurrency/sync_nopreempt.rs @@ -0,0 +1,40 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// We are making scheduler assumptions here. +// compile-flags: -Zmiri-strict-provenance -Zmiri-preemption-rate=0 + +use std::sync::{Condvar, Mutex, Arc}; +use std::thread; + +fn check_conditional_variables_notify_all() { + let pair = Arc::new(((Mutex::new(())), Condvar::new())); + + // Spawn threads and block them on the conditional variable. + let handles: Vec<_> = (0..5) + .map(|_| { + let pair2 = pair.clone(); + thread::spawn(move || { + let (lock, cvar) = &*pair2; + let guard = lock.lock().unwrap(); + // Block waiting on the conditional variable. + let _ = cvar.wait(guard).unwrap(); + }) + }) + .inspect(|_| { + // Ensure the other threads all run and block on the `wait`. + thread::yield_now(); + thread::yield_now(); + }) + .collect(); + + let (_, cvar) = &*pair; + // Unblock all threads. + cvar.notify_all(); + + for handle in handles { + handle.join().unwrap(); + } +} + +fn main() { + check_conditional_variables_notify_all(); +} From b5bc4e1b0c2e96d91e57b450051f29ab454a1c5b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 20 Jun 2022 22:02:02 -0700 Subject: [PATCH 3309/5092] add tests that fail due to SRW protectors also do more iterations of weak mem consistency, since now that is no longer the slowest test ;) --- tests/pass/0concurrency_arc_drop.rs | 19 ++++++++++ tests/pass/0weak_memory_consistency.rs | 2 +- .../stacked-borrows/interior_mutability.rs | 35 ++++++++++++++++++- 3 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 tests/pass/0concurrency_arc_drop.rs diff --git a/tests/pass/0concurrency_arc_drop.rs b/tests/pass/0concurrency_arc_drop.rs new file mode 100644 index 000000000000..b5192cd42140 --- /dev/null +++ b/tests/pass/0concurrency_arc_drop.rs @@ -0,0 +1,19 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +use std::sync::Arc; +use std::thread; + +/// Test for Arc::drop bug (https://github.com/rust-lang/rust/issues/55005) +fn main() { + // The bug seems to take up to 700 iterations to reproduce with most seeds (tested 0-9). + for _ in 0..700 { + let arc_1 = Arc::new(()); + let arc_2 = arc_1.clone(); + let thread = thread::spawn(|| drop(arc_2)); + let mut i = 0; + while i < 256 { + i += 1; + } + drop(arc_1); + thread.join().unwrap(); + } +} diff --git a/tests/pass/0weak_memory_consistency.rs b/tests/pass/0weak_memory_consistency.rs index fc9dce0c986a..601d8547f8c0 100644 --- a/tests/pass/0weak_memory_consistency.rs +++ b/tests/pass/0weak_memory_consistency.rs @@ -214,7 +214,7 @@ fn test_single_thread() { } pub fn main() { - for _ in 0..50 { + for _ in 0..75 { test_single_thread(); test_mixed_access(); test_load_buffering_acq_rel(); diff --git a/tests/pass/stacked-borrows/interior_mutability.rs b/tests/pass/stacked-borrows/interior_mutability.rs index 1ac9706b525f..9ee8af45aefe 100644 --- a/tests/pass/stacked-borrows/interior_mutability.rs +++ b/tests/pass/stacked-borrows/interior_mutability.rs @@ -1,11 +1,14 @@ +// compile-flags: -Zmiri-tag-raw-pointers use std::cell::{Cell, RefCell, UnsafeCell}; -use std::mem::MaybeUninit; +use std::mem::{self, MaybeUninit}; fn main() { aliasing_mut_and_shr(); aliasing_frz_and_shr(); into_interior_mutability(); unsafe_cell_2phase(); + unsafe_cell_deallocate(); + unsafe_cell_invalidate(); } fn aliasing_mut_and_shr() { @@ -67,3 +70,33 @@ fn unsafe_cell_2phase() { let _val = (*x2.get()).get(0); } } + +/// Make sure we can deallocate an UnsafeCell that was passed to an active fn call. +/// (This is the fix for https://github.com/rust-lang/rust/issues/55005.) +fn unsafe_cell_deallocate() { + fn f(x: &UnsafeCell) { + let b: Box = unsafe { Box::from_raw(x as *const _ as *mut i32) }; + drop(b) + } + + let b = Box::new(0i32); + f(unsafe { mem::transmute(Box::into_raw(b)) }); +} + +/// As a side-effect of the above, we also allow this -- at least for now. +fn unsafe_cell_invalidate() { + fn f(_x: &UnsafeCell, y: *mut i32) { + // Writing to y invalidates x, but that is okay. + unsafe { + *y += 1; + } + } + + let mut x = 0i32; + let raw1 = &mut x as *mut _; + let ref1 = unsafe { &mut *raw1 }; + let raw2 = ref1 as *mut _; + // Now the borrow stack is: raw1, ref2, raw2. + // So using raw1 invalidates raw2. + f(unsafe { mem::transmute(raw2) }, raw1); +} From 1b214a0d128779a03accff4e9426edb7c570082c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 20 Jun 2022 22:12:05 -0700 Subject: [PATCH 3310/5092] do not protect SRW items --- src/stacked_borrows.rs | 7 ++++ .../deallocate_against_barrier2.rs | 17 --------- .../deallocate_against_barrier2.stderr | 38 ------------------- 3 files changed, 7 insertions(+), 55 deletions(-) delete mode 100644 tests/fail/stacked_borrows/deallocate_against_barrier2.rs delete mode 100644 tests/fail/stacked_borrows/deallocate_against_barrier2.stderr diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index c78741499c2d..0c537e0d7a5c 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -821,6 +821,13 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { Permission::SharedReadWrite }; + let protector = if frozen { + protector + } else { + // We do not protect inside UnsafeCell. + // This fixes https://github.com/rust-lang/rust/issues/55005. + None + }; let item = Item { perm, tag: new_tag, protector }; let mut global = this.machine.stacked_borrows.as_ref().unwrap().borrow_mut(); stacked_borrows.for_each(range, |offset, stack, history| { diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier2.rs b/tests/fail/stacked_borrows/deallocate_against_barrier2.rs deleted file mode 100644 index 9c0c59d364f2..000000000000 --- a/tests/fail/stacked_borrows/deallocate_against_barrier2.rs +++ /dev/null @@ -1,17 +0,0 @@ -// error-pattern: deallocating while item is protected - -use std::cell::Cell; - -// Check that even `&Cell` are dereferenceable. -// Also see . -fn inner(x: &Cell, f: fn(&Cell)) { - // `f` may mutate, but it may not deallocate! - f(x) -} - -fn main() { - inner(Box::leak(Box::new(Cell::new(0))), |x| { - let raw = x as *const _ as *mut Cell; - drop(unsafe { Box::from_raw(raw) }); - }); -} diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr b/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr deleted file mode 100644 index 088daec040fe..000000000000 --- a/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr +++ /dev/null @@ -1,38 +0,0 @@ -error: Undefined Behavior: deallocating while item is protected: [SharedReadWrite for (call ID)] - --> RUSTLIB/alloc/src/alloc.rs:LL:CC - | -LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item is protected: [SharedReadWrite for (call ID)] - | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental - = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - - = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `alloc::alloc::box_free::, std::alloc::Global>` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `std::ptr::drop_in_place::>> - shim(Some(std::boxed::Box>))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC - = note: inside `std::mem::drop::>>` at RUSTLIB/core/src/mem/mod.rs:LL:CC -note: inside closure at $DIR/deallocate_against_barrier2.rs:LL:CC - --> $DIR/deallocate_against_barrier2.rs:LL:CC - | -LL | drop(unsafe { Box::from_raw(raw) }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: inside `<[closure@$DIR/deallocate_against_barrier2.rs:LL:CC] as std::ops::FnOnce<(&std::cell::Cell,)>>::call_once - shim` at RUSTLIB/core/src/ops/function.rs:LL:CC -note: inside `inner` at $DIR/deallocate_against_barrier2.rs:LL:CC - --> $DIR/deallocate_against_barrier2.rs:LL:CC - | -LL | f(x) - | ^^^^ -note: inside `main` at $DIR/deallocate_against_barrier2.rs:LL:CC - --> $DIR/deallocate_against_barrier2.rs:LL:CC - | -LL | / inner(Box::leak(Box::new(Cell::new(0))), |x| { -LL | | let raw = x as *const _ as *mut Cell; -LL | | drop(unsafe { Box::from_raw(raw) }); -LL | | }); - | |______^ - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - From 5490e775df81e08ff605d8cba7b12624245259b4 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 21 Jun 2022 11:27:44 -0700 Subject: [PATCH 3311/5092] Format tests with rustfmt (201-224 of 300) --- .../thread_local_static_dealloc.rs | 10 +++--- tests/fail/stacked_borrows/interior_mut2.rs | 32 ++++++++++--------- .../fail/stacked_borrows/issue-miri-1050-1.rs | 10 +++--- .../fail/stacked_borrows/issue-miri-1050-2.rs | 10 +++--- .../mut_exclusive_violation1.rs | 30 +++++++++-------- .../mut_exclusive_violation2.rs | 18 ++++++----- .../return_invalid_mut_option.rs | 4 +-- .../return_invalid_shr_option.rs | 4 +-- .../shared_rw_borrows_are_weak1.rs | 18 ++++++----- .../shared_rw_borrows_are_weak2.rs | 18 ++++++----- .../sync/libc_pthread_mutex_destroy_locked.rs | 5 ++- .../libc_pthread_mutex_normal_deadlock.rs | 5 ++- ...bc_pthread_mutex_normal_unlock_unlocked.rs | 5 ++- tests/fail/transmute-pair-uninit.rs | 6 ++-- tests/fail/transmute_fat1.rs | 14 +++----- tests/fail/unaligned_pointers/alignment.rs | 2 +- tests/fail/validity/cast_fn_ptr1.rs | 2 +- tests/fail/validity/cast_fn_ptr2.rs | 4 ++- tests/fail/validity/invalid_enum_tag.rs | 5 ++- tests/fail/validity/invalid_wide_raw.rs | 4 +-- tests/fail/validity/ref_to_uninhabited1.rs | 12 ++++--- tests/fail/validity/ref_to_uninhabited2.rs | 8 +++-- tests/fail/validity/too-big-slice.rs | 10 +++--- tests/fail/validity/too-big-unsized.rs | 12 ++++--- 24 files changed, 143 insertions(+), 105 deletions(-) diff --git a/tests/fail/concurrency/thread_local_static_dealloc.rs b/tests/fail/concurrency/thread_local_static_dealloc.rs index 73e4ab596585..d5a4bf27f897 100644 --- a/tests/fail/concurrency/thread_local_static_dealloc.rs +++ b/tests/fail/concurrency/thread_local_static_dealloc.rs @@ -7,7 +7,9 @@ #[thread_local] static mut TLS: u8 = 0; -fn main() { unsafe { - let dangling_ptr = std::thread::spawn(|| &TLS as *const u8 as usize).join().unwrap(); - let _val = *(dangling_ptr as *const u8); //~ ERROR dereferenced after this allocation got freed -} } +fn main() { + unsafe { + let dangling_ptr = std::thread::spawn(|| &TLS as *const u8 as usize).join().unwrap(); + let _val = *(dangling_ptr as *const u8); //~ ERROR dereferenced after this allocation got freed + } +} diff --git a/tests/fail/stacked_borrows/interior_mut2.rs b/tests/fail/stacked_borrows/interior_mut2.rs index 45770020d33d..4433f28e3459 100644 --- a/tests/fail/stacked_borrows/interior_mut2.rs +++ b/tests/fail/stacked_borrows/interior_mut2.rs @@ -7,22 +7,24 @@ unsafe fn unsafe_cell_get(x: &UnsafeCell) -> &'static mut T { mem::transmute(x) } -fn main() { unsafe { - let c = &UnsafeCell::new(UnsafeCell::new(0)); - let inner_uniq = &mut *c.get(); - let inner_shr = &*inner_uniq; - // stack: [c: SharedReadWrite, inner_uniq: Unique, inner_shr: SharedReadWrite] +fn main() { + unsafe { + let c = &UnsafeCell::new(UnsafeCell::new(0)); + let inner_uniq = &mut *c.get(); + let inner_shr = &*inner_uniq; + // stack: [c: SharedReadWrite, inner_uniq: Unique, inner_shr: SharedReadWrite] - let _val = c.get().read(); // invalidates inner_uniq - // stack: [c: SharedReadWrite, inner_uniq: Disabled, inner_shr: SharedReadWrite] + let _val = c.get().read(); // invalidates inner_uniq + // stack: [c: SharedReadWrite, inner_uniq: Disabled, inner_shr: SharedReadWrite] - // We have to be careful not to add any raw pointers above inner_uniq in - // the stack, hence the use of unsafe_cell_get. - let _val = *unsafe_cell_get(inner_shr); // this still works + // We have to be careful not to add any raw pointers above inner_uniq in + // the stack, hence the use of unsafe_cell_get. + let _val = *unsafe_cell_get(inner_shr); // this still works - *c.get() = UnsafeCell::new(0); // now inner_shr gets invalidated - // stack: [c: SharedReadWrite] + *c.get() = UnsafeCell::new(0); // now inner_shr gets invalidated + // stack: [c: SharedReadWrite] - // now this does not work any more - let _val = *inner_shr.get(); //~ ERROR borrow stack -} } + // now this does not work any more + let _val = *inner_shr.get(); //~ ERROR borrow stack + } +} diff --git a/tests/fail/stacked_borrows/issue-miri-1050-1.rs b/tests/fail/stacked_borrows/issue-miri-1050-1.rs index 852eb69968ed..c1fc695e0d65 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-1.rs +++ b/tests/fail/stacked_borrows/issue-miri-1050-1.rs @@ -1,6 +1,8 @@ // error-pattern: pointer to 4 bytes starting at offset 0 is out-of-bounds -fn main() { unsafe { - let ptr = Box::into_raw(Box::new(0u16)); - Box::from_raw(ptr as *mut u32); -} } +fn main() { + unsafe { + let ptr = Box::into_raw(Box::new(0u16)); + Box::from_raw(ptr as *mut u32); + } +} diff --git a/tests/fail/stacked_borrows/issue-miri-1050-2.rs b/tests/fail/stacked_borrows/issue-miri-1050-2.rs index 8f0b47501604..7d8809cedcd7 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-2.rs +++ b/tests/fail/stacked_borrows/issue-miri-1050-2.rs @@ -1,7 +1,9 @@ // error-pattern: is not a valid pointer use std::ptr::NonNull; -fn main() { unsafe { - let ptr = NonNull::::dangling(); - Box::from_raw(ptr.as_ptr()); -} } +fn main() { + unsafe { + let ptr = NonNull::::dangling(); + Box::from_raw(ptr.as_ptr()); + } +} diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation1.rs b/tests/fail/stacked_borrows/mut_exclusive_violation1.rs index 03343b985a02..a1cb7107eee0 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation1.rs +++ b/tests/fail/stacked_borrows/mut_exclusive_violation1.rs @@ -1,14 +1,14 @@ fn demo_mut_advanced_unique(our: &mut i32) -> i32 { - unknown_code_1(&*our); + unknown_code_1(&*our); - // This "re-asserts" uniqueness of the reference: After writing, we know - // our tag is at the top of the stack. - *our = 5; + // This "re-asserts" uniqueness of the reference: After writing, we know + // our tag is at the top of the stack. + *our = 5; - unknown_code_2(); + unknown_code_2(); - // We know this will return 5 - *our + // We know this will return 5 + *our } // Now comes the evil context @@ -16,13 +16,17 @@ use std::ptr; static mut LEAK: *mut i32 = ptr::null_mut(); -fn unknown_code_1(x: &i32) { unsafe { - LEAK = x as *const _ as *mut _; -} } +fn unknown_code_1(x: &i32) { + unsafe { + LEAK = x as *const _ as *mut _; + } +} -fn unknown_code_2() { unsafe { - *LEAK = 7; //~ ERROR borrow stack -} } +fn unknown_code_2() { + unsafe { + *LEAK = 7; //~ ERROR borrow stack + } +} fn main() { demo_mut_advanced_unique(&mut 0); diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation2.rs b/tests/fail/stacked_borrows/mut_exclusive_violation2.rs index c6802c5ec94e..a5bf8353bae8 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation2.rs +++ b/tests/fail/stacked_borrows/mut_exclusive_violation2.rs @@ -1,10 +1,12 @@ use std::ptr::NonNull; -fn main() { unsafe { - let x = &mut 0; - let mut ptr1 = NonNull::from(x); - let mut ptr2 = ptr1.clone(); - let raw1 = ptr1.as_mut(); - let _raw2 = ptr2.as_mut(); - let _val = *raw1; //~ ERROR borrow stack -} } +fn main() { + unsafe { + let x = &mut 0; + let mut ptr1 = NonNull::from(x); + let mut ptr2 = ptr1.clone(); + let raw1 = ptr1.as_mut(); + let _raw2 = ptr2.as_mut(); + let _val = *raw1; //~ ERROR borrow stack + } +} diff --git a/tests/fail/stacked_borrows/return_invalid_mut_option.rs b/tests/fail/stacked_borrows/return_invalid_mut_option.rs index 1cb3f3f92026..ccdb3dc50579 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_option.rs +++ b/tests/fail/stacked_borrows/return_invalid_mut_option.rs @@ -10,7 +10,7 @@ fn foo(x: &mut (i32, i32)) -> Option<&mut i32> { fn main() { match foo(&mut (1, 2)) { - Some(_x) => {}, //~ ERROR borrow stack - None => {}, + Some(_x) => {} //~ ERROR borrow stack + None => {} } } diff --git a/tests/fail/stacked_borrows/return_invalid_shr_option.rs b/tests/fail/stacked_borrows/return_invalid_shr_option.rs index 2d8527fa3fb4..42b4871c4674 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_option.rs +++ b/tests/fail/stacked_borrows/return_invalid_shr_option.rs @@ -9,7 +9,7 @@ fn foo(x: &mut (i32, i32)) -> Option<&i32> { fn main() { match foo(&mut (1, 2)) { - Some(_x) => {}, //~ ERROR borrow stack - None => {}, + Some(_x) => {} //~ ERROR borrow stack + None => {} } } diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs index d734caf1d97a..a08d2b716ee7 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs @@ -2,13 +2,15 @@ // *below* an already granted Unique -- so writing to // the SharedReadWrite will invalidate the Unique. -use std::mem; use std::cell::Cell; +use std::mem; -fn main() { unsafe { - let x = &mut Cell::new(0); - let y: &mut Cell = mem::transmute(&mut *x); // launder lifetime - let shr_rw = &*x; // thanks to interior mutability this will be a SharedReadWrite - shr_rw.set(1); - y.get_mut(); //~ ERROR borrow stack -} } +fn main() { + unsafe { + let x = &mut Cell::new(0); + let y: &mut Cell = mem::transmute(&mut *x); // launder lifetime + let shr_rw = &*x; // thanks to interior mutability this will be a SharedReadWrite + shr_rw.set(1); + y.get_mut(); //~ ERROR borrow stack + } +} diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs index d4aef74dff6b..07163456cebe 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs @@ -3,13 +3,15 @@ // the SharedReadWrite will invalidate the SharedReadWrite. // normalize-stderr-test: "0x[0-9a-fA-F]+" -> "$$HEX" -use std::mem; use std::cell::RefCell; +use std::mem; -fn main() { unsafe { - let x = &mut RefCell::new(0); - let y: &i32 = mem::transmute(&*x.borrow()); // launder lifetime - let shr_rw = &*x; // thanks to interior mutability this will be a SharedReadWrite - shr_rw.replace(1); - let _val = *y; //~ ERROR borrow stack -} } +fn main() { + unsafe { + let x = &mut RefCell::new(0); + let y: &i32 = mem::transmute(&*x.borrow()); // launder lifetime + let shr_rw = &*x; // thanks to interior mutability this will be a SharedReadWrite + shr_rw.replace(1); + let _val = *y; //~ ERROR borrow stack + } +} diff --git a/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs b/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs index e7ed8ad29621..461a81b8fbac 100644 --- a/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs +++ b/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs @@ -7,7 +7,10 @@ extern crate libc; fn main() { unsafe { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), 0); + assert_eq!( + libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), + 0 + ); let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); diff --git a/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs index 96e0ff3bfff7..7e7af617d5d9 100644 --- a/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs @@ -7,7 +7,10 @@ extern crate libc; fn main() { unsafe { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), 0); + assert_eq!( + libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), + 0 + ); let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); diff --git a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs index 65de62484d5e..c8dd84b838a2 100644 --- a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs +++ b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs @@ -7,7 +7,10 @@ extern crate libc; fn main() { unsafe { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), 0); + assert_eq!( + libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), + 0 + ); let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); diff --git a/tests/fail/transmute-pair-uninit.rs b/tests/fail/transmute-pair-uninit.rs index 1bd60f9cff73..0835287b9e4f 100644 --- a/tests/fail/transmute-pair-uninit.rs +++ b/tests/fail/transmute-pair-uninit.rs @@ -10,7 +10,7 @@ fn main() { let y = &x; // Now read this bytewise. There should be (`ptr_size + 1`) def bytes followed by // (`ptr_size - 1`) undef bytes (the padding after the bool) in there. - let z : *const u8 = y as *const _ as *const _; + let z: *const u8 = y as *const _ as *const _; let first_undef = mem::size_of::() as isize + 1; for i in 0..first_undef { let byte = unsafe { *z.offset(i) }; @@ -18,5 +18,7 @@ fn main() { } let v = unsafe { *z.offset(first_undef) }; //~^ ERROR uninitialized - if v == 0 { println!("it is zero"); } + if v == 0 { + println!("it is zero"); + } } diff --git a/tests/fail/transmute_fat1.rs b/tests/fail/transmute_fat1.rs index 8b351d3a09e9..f9fa2ace7570 100644 --- a/tests/fail/transmute_fat1.rs +++ b/tests/fail/transmute_fat1.rs @@ -2,13 +2,9 @@ // normalize-stderr-test: "\[u8; (08|16)\]" -> "$$ARRAY" fn main() { - #[cfg(target_pointer_width="64")] - let bad = unsafe { - std::mem::transmute::<&[u8], [u8; 16]>(&[1u8]) - }; - #[cfg(target_pointer_width="32")] - let bad = unsafe { - std::mem::transmute::<&[u8], [u8; 08]>(&[1u8]) - }; - let _val = bad[0] + bad[bad.len()-1]; + #[cfg(target_pointer_width = "64")] + let bad = unsafe { std::mem::transmute::<&[u8], [u8; 16]>(&[1u8]) }; + #[cfg(target_pointer_width = "32")] + let bad = unsafe { std::mem::transmute::<&[u8], [u8; 08]>(&[1u8]) }; + let _val = bad[0] + bad[bad.len() - 1]; } diff --git a/tests/fail/unaligned_pointers/alignment.rs b/tests/fail/unaligned_pointers/alignment.rs index b77f0eef82dd..e99d8c967cdd 100644 --- a/tests/fail/unaligned_pointers/alignment.rs +++ b/tests/fail/unaligned_pointers/alignment.rs @@ -8,7 +8,7 @@ fn main() { let x_ptr: *mut u8 = x.as_mut_ptr(); // At least one of these is definitely unaligned. unsafe { - *(x_ptr as *mut u32) = 42; + *(x_ptr as *mut u32) = 42; *(x_ptr.add(1) as *mut u32) = 42; } } diff --git a/tests/fail/validity/cast_fn_ptr1.rs b/tests/fail/validity/cast_fn_ptr1.rs index d755c163bba0..020e7be34f70 100644 --- a/tests/fail/validity/cast_fn_ptr1.rs +++ b/tests/fail/validity/cast_fn_ptr1.rs @@ -2,7 +2,7 @@ fn main() { // Cast a function pointer such that on a call, the argument gets transmuted // from raw ptr to reference. This is ABI-compatible, so it's not the call that // should fail, but validation should. - fn f(_x: &i32) { } + fn f(_x: &i32) {} let g: fn(*const i32) = unsafe { std::mem::transmute(f as fn(&i32)) }; diff --git a/tests/fail/validity/cast_fn_ptr2.rs b/tests/fail/validity/cast_fn_ptr2.rs index d78d56b5b6d6..10fc39f56fae 100644 --- a/tests/fail/validity/cast_fn_ptr2.rs +++ b/tests/fail/validity/cast_fn_ptr2.rs @@ -2,7 +2,9 @@ fn main() { // Cast a function pointer such that when returning, the return value gets transmuted // from raw ptr to reference. This is ABI-compatible, so it's not the call that // should fail, but validation should. - fn f() -> *const i32 { 0usize as *const i32 } + fn f() -> *const i32 { + 0usize as *const i32 + } let g: fn() -> &'static i32 = unsafe { std::mem::transmute(f as fn() -> *const i32) }; diff --git a/tests/fail/validity/invalid_enum_tag.rs b/tests/fail/validity/invalid_enum_tag.rs index d4ee3cc8a34a..9722e6492c82 100644 --- a/tests/fail/validity/invalid_enum_tag.rs +++ b/tests/fail/validity/invalid_enum_tag.rs @@ -1,6 +1,9 @@ #[repr(C)] pub enum Foo { - A, B, C, D + A, + B, + C, + D, } fn main() { diff --git a/tests/fail/validity/invalid_wide_raw.rs b/tests/fail/validity/invalid_wide_raw.rs index ac2d79b5a92a..0a2f6f5b152c 100644 --- a/tests/fail/validity/invalid_wide_raw.rs +++ b/tests/fail/validity/invalid_wide_raw.rs @@ -1,11 +1,11 @@ #![allow(invalid_value)] fn main() { - trait T { } + trait T {} #[derive(Debug)] struct S { #[allow(dead_code)] - x: * mut dyn T + x: *mut dyn T, } dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); //~ ERROR: encountered dangling vtable pointer in wide pointer } diff --git a/tests/fail/validity/ref_to_uninhabited1.rs b/tests/fail/validity/ref_to_uninhabited1.rs index 51a3279ffae9..a46ce017c5a0 100644 --- a/tests/fail/validity/ref_to_uninhabited1.rs +++ b/tests/fail/validity/ref_to_uninhabited1.rs @@ -1,7 +1,9 @@ #![feature(never_type)] -use std::mem::{transmute, forget}; +use std::mem::{forget, transmute}; -fn main() { unsafe { - let x: Box = transmute(&mut 42); //~ERROR encountered a box pointing to uninhabited type ! - forget(x); -} } +fn main() { + unsafe { + let x: Box = transmute(&mut 42); //~ERROR encountered a box pointing to uninhabited type ! + forget(x); + } +} diff --git a/tests/fail/validity/ref_to_uninhabited2.rs b/tests/fail/validity/ref_to_uninhabited2.rs index 3778719dc58c..0a791d1e7fee 100644 --- a/tests/fail/validity/ref_to_uninhabited2.rs +++ b/tests/fail/validity/ref_to_uninhabited2.rs @@ -2,6 +2,8 @@ use std::mem::transmute; enum Void {} -fn main() { unsafe { - let _x: &(i32, Void) = transmute(&42); //~ERROR encountered a reference pointing to uninhabited type (i32, Void) -} } +fn main() { + unsafe { + let _x: &(i32, Void) = transmute(&42); //~ERROR encountered a reference pointing to uninhabited type (i32, Void) + } +} diff --git a/tests/fail/validity/too-big-slice.rs b/tests/fail/validity/too-big-slice.rs index 6a4c18249ee7..61d903220758 100644 --- a/tests/fail/validity/too-big-slice.rs +++ b/tests/fail/validity/too-big-slice.rs @@ -1,6 +1,8 @@ use std::mem; -fn main() { unsafe { - let ptr = Box::into_raw(Box::new(0u8)); - let _x: &[u8] = mem::transmute((ptr, usize::MAX)); //~ ERROR: invalid reference metadata: slice is bigger than largest supported object -} } +fn main() { + unsafe { + let ptr = Box::into_raw(Box::new(0u8)); + let _x: &[u8] = mem::transmute((ptr, usize::MAX)); //~ ERROR: invalid reference metadata: slice is bigger than largest supported object + } +} diff --git a/tests/fail/validity/too-big-unsized.rs b/tests/fail/validity/too-big-unsized.rs index 824190a66eeb..280205dccbf2 100644 --- a/tests/fail/validity/too-big-unsized.rs +++ b/tests/fail/validity/too-big-unsized.rs @@ -6,8 +6,10 @@ struct MySlice { tail: [u8], } -fn main() { unsafe { - let ptr = Box::into_raw(Box::new(0u8)); - // The slice part is actually not "too big", but together with the `prefix` field it is. - let _x: &MySlice = mem::transmute((ptr, isize::MAX as usize)); //~ ERROR: invalid reference metadata: total size is bigger than largest supported object -} } +fn main() { + unsafe { + let ptr = Box::into_raw(Box::new(0u8)); + // The slice part is actually not "too big", but together with the `prefix` field it is. + let _x: &MySlice = mem::transmute((ptr, isize::MAX as usize)); //~ ERROR: invalid reference metadata: total size is bigger than largest supported object + } +} From b3a689e0089a1e41d11f6d4fa83ace7505bbb164 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 21 Jun 2022 11:28:00 -0700 Subject: [PATCH 3312/5092] Manual adjustments --- tests/fail/sync/libc_pthread_mutex_destroy_locked.rs | 2 +- tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs | 2 +- tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs b/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs index 461a81b8fbac..85a37db341fa 100644 --- a/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs +++ b/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs @@ -9,7 +9,7 @@ fn main() { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); assert_eq!( libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), - 0 + 0, ); let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); diff --git a/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs index 7e7af617d5d9..7e29a41920ea 100644 --- a/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs @@ -9,7 +9,7 @@ fn main() { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); assert_eq!( libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), - 0 + 0, ); let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); diff --git a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs index c8dd84b838a2..1f1a2ef34b72 100644 --- a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs +++ b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs @@ -9,7 +9,7 @@ fn main() { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); assert_eq!( libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), - 0 + 0, ); let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); From 7d40530c523bc5c39a0ceb264bada529f4fcb086 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 21 Jun 2022 11:28:24 -0700 Subject: [PATCH 3313/5092] Bless stderr files after rustfmt --- .../thread_local_static_dealloc.stderr | 4 ++-- .../fail/stacked_borrows/interior_mut2.stderr | 18 +++++++-------- .../stacked_borrows/issue-miri-1050-1.stderr | 4 ++-- .../stacked_borrows/issue-miri-1050-2.stderr | 4 ++-- .../mut_exclusive_violation1.stderr | 22 +++++++++---------- .../mut_exclusive_violation2.stderr | 18 +++++++-------- .../return_invalid_mut_option.stderr | 2 +- .../return_invalid_shr_option.stderr | 2 +- .../shared_rw_borrows_are_weak1.stderr | 18 +++++++-------- .../shared_rw_borrows_are_weak2.stderr | 18 +++++++-------- tests/fail/transmute_fat1.stderr | 4 ++-- .../fail/unaligned_pointers/alignment.stderr | 4 ++-- .../fail/validity/ref_to_uninhabited1.stderr | 4 ++-- .../fail/validity/ref_to_uninhabited2.stderr | 4 ++-- tests/fail/validity/too-big-slice.stderr | 4 ++-- tests/fail/validity/too-big-unsized.stderr | 4 ++-- 16 files changed, 67 insertions(+), 67 deletions(-) diff --git a/tests/fail/concurrency/thread_local_static_dealloc.stderr b/tests/fail/concurrency/thread_local_static_dealloc.stderr index a485edc0da93..2a3a8f0f55c3 100644 --- a/tests/fail/concurrency/thread_local_static_dealloc.stderr +++ b/tests/fail/concurrency/thread_local_static_dealloc.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed --> $DIR/thread_local_static_dealloc.rs:LL:CC | -LL | let _val = *(dangling_ptr as *const u8); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed +LL | let _val = *(dangling_ptr as *const u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/stacked_borrows/interior_mut2.stderr b/tests/fail/stacked_borrows/interior_mut2.stderr index c8a06e32fda0..33060a7818ff 100644 --- a/tests/fail/stacked_borrows/interior_mut2.stderr +++ b/tests/fail/stacked_borrows/interior_mut2.stderr @@ -1,24 +1,24 @@ error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/interior_mut2.rs:LL:CC | -LL | let _val = *inner_shr.get(); - | ^^^^^^^^^^^^^^^ - | | - | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x4] +LL | let _val = *inner_shr.get(); + | ^^^^^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/interior_mut2.rs:LL:CC | -LL | let inner_shr = &*inner_uniq; - | ^^^^^^^^^^^^ +LL | let inner_shr = &*inner_uniq; + | ^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] --> $DIR/interior_mut2.rs:LL:CC | -LL | *c.get() = UnsafeCell::new(0); // now inner_shr gets invalidated - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | *c.get() = UnsafeCell::new(0); // now inner_shr gets invalidated + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: inside `main` at $DIR/interior_mut2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/issue-miri-1050-1.stderr b/tests/fail/stacked_borrows/issue-miri-1050-1.stderr index b4953f95181a..c2c471fba881 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-1.stderr +++ b/tests/fail/stacked_borrows/issue-miri-1050-1.stderr @@ -12,8 +12,8 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) note: inside `main` at $DIR/issue-miri-1050-1.rs:LL:CC --> $DIR/issue-miri-1050-1.rs:LL:CC | -LL | Box::from_raw(ptr as *mut u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Box::from_raw(ptr as *mut u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/issue-miri-1050-2.stderr b/tests/fail/stacked_borrows/issue-miri-1050-2.stderr index cd6cfc0ecc3a..c49852cb7f4f 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-2.stderr +++ b/tests/fail/stacked_borrows/issue-miri-1050-2.stderr @@ -12,8 +12,8 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) note: inside `main` at $DIR/issue-miri-1050-2.rs:LL:CC --> $DIR/issue-miri-1050-2.rs:LL:CC | -LL | Box::from_raw(ptr.as_ptr()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Box::from_raw(ptr.as_ptr()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr b/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr index 4e38bcd2a89c..ea14536a3990 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr +++ b/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr @@ -1,30 +1,30 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/mut_exclusive_violation1.rs:LL:CC | -LL | *LEAK = 7; - | ^^^^^^^^^ - | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | *LEAK = 7; + | ^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x4] --> $DIR/mut_exclusive_violation1.rs:LL:CC | -LL | LEAK = x as *const _ as *mut _; - | ^ +LL | LEAK = x as *const _ as *mut _; + | ^ help: tag was later invalidated at offsets [0x0..0x4] --> $DIR/mut_exclusive_violation1.rs:LL:CC | -LL | *our = 5; - | ^^^^^^^^ +LL | *our = 5; + | ^^^^^^^^ = note: inside `unknown_code_2` at $DIR/mut_exclusive_violation1.rs:LL:CC note: inside `demo_mut_advanced_unique` at $DIR/mut_exclusive_violation1.rs:LL:CC --> $DIR/mut_exclusive_violation1.rs:LL:CC | -LL | unknown_code_2(); - | ^^^^^^^^^^^^^^^^ +LL | unknown_code_2(); + | ^^^^^^^^^^^^^^^^ note: inside `main` at $DIR/mut_exclusive_violation1.rs:LL:CC --> $DIR/mut_exclusive_violation1.rs:LL:CC | diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr b/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr index fd52dbe348ac..85baf93613a2 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr +++ b/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr @@ -1,24 +1,24 @@ error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/mut_exclusive_violation2.rs:LL:CC | -LL | let _val = *raw1; - | ^^^^^ - | | - | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | let _val = *raw1; + | ^^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/mut_exclusive_violation2.rs:LL:CC | -LL | let raw1 = ptr1.as_mut(); - | ^^^^^^^^^^^^^ +LL | let raw1 = ptr1.as_mut(); + | ^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] --> $DIR/mut_exclusive_violation2.rs:LL:CC | -LL | let _raw2 = ptr2.as_mut(); - | ^^^^^^^^^^^^^ +LL | let _raw2 = ptr2.as_mut(); + | ^^^^^^^^^^^^^ = note: inside `main` at $DIR/mut_exclusive_violation2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/return_invalid_mut_option.stderr b/tests/fail/stacked_borrows/return_invalid_mut_option.stderr index 98decdc3adc8..4bee128d68a4 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_option.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut_option.stderr @@ -1,7 +1,7 @@ error: Undefined Behavior: trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> $DIR/return_invalid_mut_option.rs:LL:CC | -LL | Some(_x) => {}, +LL | Some(_x) => {} | ^^ | | | trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location diff --git a/tests/fail/stacked_borrows/return_invalid_shr_option.stderr b/tests/fail/stacked_borrows/return_invalid_shr_option.stderr index 81244a87cb06..a23c69d12db1 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_option.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr_option.stderr @@ -1,7 +1,7 @@ error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> $DIR/return_invalid_shr_option.rs:LL:CC | -LL | Some(_x) => {}, +LL | Some(_x) => {} | ^^ | | | trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr index 8bb67f62b531..151654bad5cf 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr @@ -1,24 +1,24 @@ error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/shared_rw_borrows_are_weak1.rs:LL:CC | -LL | y.get_mut(); - | ^^^^^^^^^^^ - | | - | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x4] +LL | y.get_mut(); + | ^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/shared_rw_borrows_are_weak1.rs:LL:CC | -LL | let y: &mut Cell = mem::transmute(&mut *x); // launder lifetime - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | let y: &mut Cell = mem::transmute(&mut *x); // launder lifetime + | ^^^^^^^^^^^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] --> $DIR/shared_rw_borrows_are_weak1.rs:LL:CC | -LL | shr_rw.set(1); - | ^^^^^^^^^^^^^ +LL | shr_rw.set(1); + | ^^^^^^^^^^^^^ = note: inside `main` at $DIR/shared_rw_borrows_are_weak1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr index b339785d6484..c0bf809356bd 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr @@ -1,24 +1,24 @@ error: Undefined Behavior: attempting a read access using at ALLOC[$HEX], but that tag does not exist in the borrow stack for this location --> $DIR/shared_rw_borrows_are_weak2.rs:LL:CC | -LL | let _val = *y; - | ^^ - | | - | attempting a read access using at ALLOC[$HEX], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[$HEX..$HEX] +LL | let _val = *y; + | ^^ + | | + | attempting a read access using at ALLOC[$HEX], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[$HEX..$HEX] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [$HEX..$HEX] --> $DIR/shared_rw_borrows_are_weak2.rs:LL:CC | -LL | let y: &i32 = mem::transmute(&*x.borrow()); // launder lifetime - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let y: &i32 = mem::transmute(&*x.borrow()); // launder lifetime + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: was later invalidated at offsets [$HEX..$HEX] --> $DIR/shared_rw_borrows_are_weak2.rs:LL:CC | -LL | shr_rw.replace(1); - | ^^^^^^^^^^^^^^^^^ +LL | shr_rw.replace(1); + | ^^^^^^^^^^^^^^^^^ = note: inside `main` at $DIR/shared_rw_borrows_are_weak2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/transmute_fat1.stderr b/tests/fail/transmute_fat1.stderr index cbfa8dff2a50..2b095dc3c1c0 100644 --- a/tests/fail/transmute_fat1.stderr +++ b/tests/fail/transmute_fat1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: type validation failed: encountered a pointer, but expected plain (non-pointer) bytes --> $DIR/transmute_fat1.rs:LL:CC | -LL | std::mem::transmute::<&[u8], $ARRAY>(&[1u8]) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected plain (non-pointer) bytes +LL | let bad = unsafe { std::mem::transmute::<&[u8], $ARRAY>(&[1u8]) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected plain (non-pointer) bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/unaligned_pointers/alignment.stderr b/tests/fail/unaligned_pointers/alignment.stderr index c21e2ed2ec67..0e6ca83366ad 100644 --- a/tests/fail/unaligned_pointers/alignment.stderr +++ b/tests/fail/unaligned_pointers/alignment.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required --> $DIR/alignment.rs:LL:CC | -LL | *(x_ptr as *mut u32) = 42; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required +LL | *(x_ptr as *mut u32) = 42; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/ref_to_uninhabited1.stderr b/tests/fail/validity/ref_to_uninhabited1.stderr index de41944944e3..dbaee46a93b8 100644 --- a/tests/fail/validity/ref_to_uninhabited1.stderr +++ b/tests/fail/validity/ref_to_uninhabited1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: type validation failed: encountered a box pointing to uninhabited type ! --> $DIR/ref_to_uninhabited1.rs:LL:CC | -LL | let x: Box = transmute(&mut 42); - | ^^^^^^^^^^^^^^^^^^ type validation failed: encountered a box pointing to uninhabited type ! +LL | let x: Box = transmute(&mut 42); + | ^^^^^^^^^^^^^^^^^^ type validation failed: encountered a box pointing to uninhabited type ! | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/ref_to_uninhabited2.stderr b/tests/fail/validity/ref_to_uninhabited2.stderr index 754c39e78901..115cdfedf777 100644 --- a/tests/fail/validity/ref_to_uninhabited2.stderr +++ b/tests/fail/validity/ref_to_uninhabited2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: type validation failed: encountered a reference pointing to uninhabited type (i32, Void) --> $DIR/ref_to_uninhabited2.rs:LL:CC | -LL | let _x: &(i32, Void) = transmute(&42); - | ^^^^^^^^^^^^^^ type validation failed: encountered a reference pointing to uninhabited type (i32, Void) +LL | let _x: &(i32, Void) = transmute(&42); + | ^^^^^^^^^^^^^^ type validation failed: encountered a reference pointing to uninhabited type (i32, Void) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/too-big-slice.stderr b/tests/fail/validity/too-big-slice.stderr index 11d20d3e623b..9c8d2929bda0 100644 --- a/tests/fail/validity/too-big-slice.stderr +++ b/tests/fail/validity/too-big-slice.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object --> $DIR/too-big-slice.rs:LL:CC | -LL | let _x: &[u8] = mem::transmute((ptr, usize::MAX)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object +LL | let _x: &[u8] = mem::transmute((ptr, usize::MAX)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/too-big-unsized.stderr b/tests/fail/validity/too-big-unsized.stderr index 0c7b7b23246e..18dc5d8b9c18 100644 --- a/tests/fail/validity/too-big-unsized.stderr +++ b/tests/fail/validity/too-big-unsized.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: type validation failed: encountered invalid reference metadata: total size is bigger than largest supported object --> $DIR/too-big-unsized.rs:LL:CC | -LL | let _x: &MySlice = mem::transmute((ptr, isize::MAX as usize)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: total size is bigger than largest supported object +LL | let _x: &MySlice = mem::transmute((ptr, isize::MAX as usize)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: total size is bigger than largest supported object | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information From 6827ac2f37908f328305bae91d2e5387975da64e Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 21 Jun 2022 11:38:02 -0700 Subject: [PATCH 3314/5092] Format tests with rustfmt (225-275 of 300) --- tests/fail/box-cell-alias.rs | 4 +++- .../dangling_pointers/maybe_null_pointer_write_zst.rs | 4 +++- tests/fail/intrinsics/copy_null.rs | 4 +++- tests/fail/intrinsics/copy_unaligned.rs | 4 +++- tests/fail/intrinsics/exact_div1.rs | 4 +++- tests/fail/intrinsics/exact_div2.rs | 4 +++- tests/fail/intrinsics/exact_div3.rs | 4 +++- tests/fail/intrinsics/exact_div4.rs | 4 +++- tests/fail/intrinsics/float_to_int_32_inf1.rs | 4 +++- tests/fail/intrinsics/float_to_int_32_infneg1.rs | 4 +++- tests/fail/intrinsics/float_to_int_32_nan.rs | 4 +++- tests/fail/intrinsics/float_to_int_32_nanneg.rs | 4 +++- tests/fail/intrinsics/float_to_int_32_neg.rs | 4 +++- tests/fail/intrinsics/float_to_int_32_too_big1.rs | 4 +++- tests/fail/intrinsics/float_to_int_32_too_big2.rs | 4 +++- tests/fail/intrinsics/float_to_int_32_too_small1.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_inf1.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_infneg1.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_infneg2.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_nan.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_neg.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_too_big1.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_too_big2.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_too_big3.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_too_big4.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_too_big5.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_too_big6.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_too_big7.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_too_small1.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_too_small2.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_too_small3.rs | 4 +++- tests/fail/intrinsics/unchecked_add1.rs | 4 +++- tests/fail/intrinsics/unchecked_add2.rs | 4 +++- tests/fail/intrinsics/unchecked_div1.rs | 4 +++- tests/fail/intrinsics/unchecked_mul1.rs | 4 +++- tests/fail/intrinsics/unchecked_mul2.rs | 4 +++- tests/fail/intrinsics/unchecked_sub1.rs | 4 +++- tests/fail/intrinsics/unchecked_sub2.rs | 4 +++- tests/fail/panic/unwind_panic_abort.rs | 4 +++- tests/fail/stacked_borrows/illegal_write1.rs | 6 ++++-- tests/fail/stacked_borrows/illegal_write2.rs | 4 +++- tests/fail/stacked_borrows/illegal_write3.rs | 4 +++- tests/fail/stacked_borrows/illegal_write6.rs | 4 +++- tests/fail/stacked_borrows/raw_tracking.rs | 8 ++++++-- tests/fail/stacked_borrows/shr_frozen_violation1.rs | 10 ++++++---- tests/fail/stacked_borrows/transmute-is-no-escape.rs | 4 +++- tests/fail/stacked_borrows/unescaped_local.rs | 4 +++- .../unaligned_pointers/intptrcast_alignment_check.rs | 6 ++++-- tests/fail/validity/transmute_through_ptr.rs | 8 ++++++-- tests/fail/zst2.rs | 4 +++- tests/fail/zst3.rs | 8 ++++++-- 51 files changed, 167 insertions(+), 59 deletions(-) diff --git a/tests/fail/box-cell-alias.rs b/tests/fail/box-cell-alias.rs index 49cce2750784..ffda1033d44b 100644 --- a/tests/fail/box-cell-alias.rs +++ b/tests/fail/box-cell-alias.rs @@ -6,7 +6,9 @@ use std::cell::Cell; fn helper(val: Box>, ptr: *const Cell) -> u8 { val.set(10); - unsafe { (*ptr).set(20); } //~ ERROR does not exist in the borrow stack + unsafe { + (*ptr).set(20); + } //~ ERROR does not exist in the borrow stack val.get() } diff --git a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs index 7f50b9827d94..78384502337c 100644 --- a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs +++ b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs @@ -7,5 +7,7 @@ fn main() { // Also not assigning directly as that's array initialization, not assignment. let zst_val = [1u8; 0]; let ptr = (&0u8 as *const u8).wrapping_sub(0x800) as *mut [u8; 0]; - unsafe { *ptr = zst_val; } //~ ERROR out-of-bounds + unsafe { + *ptr = zst_val; + } //~ ERROR out-of-bounds } diff --git a/tests/fail/intrinsics/copy_null.rs b/tests/fail/intrinsics/copy_null.rs index 8f32ad1a760f..1e572fe4a855 100644 --- a/tests/fail/intrinsics/copy_null.rs +++ b/tests/fail/intrinsics/copy_null.rs @@ -9,5 +9,7 @@ fn main() { let mut data = [0u16; 4]; let ptr = &mut data[0] as *mut u16; // Even copying 0 elements from NULL should error. - unsafe { copy_nonoverlapping(std::ptr::null(), ptr, 0); } //~ ERROR: memory access failed: null pointer is not a valid pointer + unsafe { + copy_nonoverlapping(std::ptr::null(), ptr, 0); + } //~ ERROR: memory access failed: null pointer is not a valid pointer } diff --git a/tests/fail/intrinsics/copy_unaligned.rs b/tests/fail/intrinsics/copy_unaligned.rs index 84f4de93461e..d7097bb91d3a 100644 --- a/tests/fail/intrinsics/copy_unaligned.rs +++ b/tests/fail/intrinsics/copy_unaligned.rs @@ -9,5 +9,7 @@ fn main() { let mut data = [0u16; 8]; let ptr = (&mut data[0] as *mut u16 as *mut u8).wrapping_add(1) as *mut u16; // Even copying 0 elements to something unaligned should error - unsafe { copy_nonoverlapping(&data[5], ptr, 0); } //~ ERROR accessing memory with alignment 1, but alignment 2 is required + unsafe { + copy_nonoverlapping(&data[5], ptr, 0); + } //~ ERROR accessing memory with alignment 1, but alignment 2 is required } diff --git a/tests/fail/intrinsics/exact_div1.rs b/tests/fail/intrinsics/exact_div1.rs index 171bedeadc67..5d2185f1ee1b 100644 --- a/tests/fail/intrinsics/exact_div1.rs +++ b/tests/fail/intrinsics/exact_div1.rs @@ -1,5 +1,7 @@ #![feature(core_intrinsics)] fn main() { // divison by 0 - unsafe { std::intrinsics::exact_div(2, 0); } //~ ERROR divisor of zero + unsafe { + std::intrinsics::exact_div(2, 0); + } //~ ERROR divisor of zero } diff --git a/tests/fail/intrinsics/exact_div2.rs b/tests/fail/intrinsics/exact_div2.rs index 1327046920d2..e0301fbd73e2 100644 --- a/tests/fail/intrinsics/exact_div2.rs +++ b/tests/fail/intrinsics/exact_div2.rs @@ -1,5 +1,7 @@ #![feature(core_intrinsics)] fn main() { // divison with a remainder - unsafe { std::intrinsics::exact_div(2u16, 3); } //~ ERROR 2_u16 cannot be divided by 3_u16 without remainder + unsafe { + std::intrinsics::exact_div(2u16, 3); + } //~ ERROR 2_u16 cannot be divided by 3_u16 without remainder } diff --git a/tests/fail/intrinsics/exact_div3.rs b/tests/fail/intrinsics/exact_div3.rs index 6a309442749b..5f74b2dfa818 100644 --- a/tests/fail/intrinsics/exact_div3.rs +++ b/tests/fail/intrinsics/exact_div3.rs @@ -1,5 +1,7 @@ #![feature(core_intrinsics)] fn main() { // signed divison with a remainder - unsafe { std::intrinsics::exact_div(-19i8, 2); } //~ ERROR -19_i8 cannot be divided by 2_i8 without remainder + unsafe { + std::intrinsics::exact_div(-19i8, 2); + } //~ ERROR -19_i8 cannot be divided by 2_i8 without remainder } diff --git a/tests/fail/intrinsics/exact_div4.rs b/tests/fail/intrinsics/exact_div4.rs index 2831795de82e..f70746d2a116 100644 --- a/tests/fail/intrinsics/exact_div4.rs +++ b/tests/fail/intrinsics/exact_div4.rs @@ -1,5 +1,7 @@ #![feature(core_intrinsics)] fn main() { // divison of MIN by -1 - unsafe { std::intrinsics::exact_div(i64::MIN, -1); } //~ ERROR overflow in signed remainder (dividing MIN by -1) + unsafe { + std::intrinsics::exact_div(i64::MIN, -1); + } //~ ERROR overflow in signed remainder (dividing MIN by -1) } diff --git a/tests/fail/intrinsics/float_to_int_32_inf1.rs b/tests/fail/intrinsics/float_to_int_32_inf1.rs index a56f4aefad3a..32c2e09b53a3 100644 --- a/tests/fail/intrinsics/float_to_int_32_inf1.rs +++ b/tests/fail/intrinsics/float_to_int_32_inf1.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(f32::INFINITY); } //~ ERROR: cannot be represented in target type `i32` + unsafe { + float_to_int_unchecked::(f32::INFINITY); + } //~ ERROR: cannot be represented in target type `i32` } diff --git a/tests/fail/intrinsics/float_to_int_32_infneg1.rs b/tests/fail/intrinsics/float_to_int_32_infneg1.rs index d18f75fcca8a..e1ba2224a088 100644 --- a/tests/fail/intrinsics/float_to_int_32_infneg1.rs +++ b/tests/fail/intrinsics/float_to_int_32_infneg1.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(f32::NEG_INFINITY); } //~ ERROR: cannot be represented in target type `i32` + unsafe { + float_to_int_unchecked::(f32::NEG_INFINITY); + } //~ ERROR: cannot be represented in target type `i32` } diff --git a/tests/fail/intrinsics/float_to_int_32_nan.rs b/tests/fail/intrinsics/float_to_int_32_nan.rs index e1fe8c7cf2f7..6c128d94a87f 100644 --- a/tests/fail/intrinsics/float_to_int_32_nan.rs +++ b/tests/fail/intrinsics/float_to_int_32_nan.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(f32::NAN); } //~ ERROR: cannot be represented in target type `u32` + unsafe { + float_to_int_unchecked::(f32::NAN); + } //~ ERROR: cannot be represented in target type `u32` } diff --git a/tests/fail/intrinsics/float_to_int_32_nanneg.rs b/tests/fail/intrinsics/float_to_int_32_nanneg.rs index 38899045c92c..9bc628e9db92 100644 --- a/tests/fail/intrinsics/float_to_int_32_nanneg.rs +++ b/tests/fail/intrinsics/float_to_int_32_nanneg.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(-f32::NAN); } //~ ERROR: cannot be represented in target type `u32` + unsafe { + float_to_int_unchecked::(-f32::NAN); + } //~ ERROR: cannot be represented in target type `u32` } diff --git a/tests/fail/intrinsics/float_to_int_32_neg.rs b/tests/fail/intrinsics/float_to_int_32_neg.rs index f15cf9a9cd64..188a9256db7e 100644 --- a/tests/fail/intrinsics/float_to_int_32_neg.rs +++ b/tests/fail/intrinsics/float_to_int_32_neg.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(-1.000000001f32); } //~ ERROR: cannot be represented in target type `u32` + unsafe { + float_to_int_unchecked::(-1.000000001f32); + } //~ ERROR: cannot be represented in target type `u32` } diff --git a/tests/fail/intrinsics/float_to_int_32_too_big1.rs b/tests/fail/intrinsics/float_to_int_32_too_big1.rs index ccbf917c8e89..787941e63e2b 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_big1.rs +++ b/tests/fail/intrinsics/float_to_int_32_too_big1.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(2147483648.0f32); } //~ ERROR: cannot be represented in target type `i32` + unsafe { + float_to_int_unchecked::(2147483648.0f32); + } //~ ERROR: cannot be represented in target type `i32` } diff --git a/tests/fail/intrinsics/float_to_int_32_too_big2.rs b/tests/fail/intrinsics/float_to_int_32_too_big2.rs index 6598fd36e038..39b74cb04869 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_big2.rs +++ b/tests/fail/intrinsics/float_to_int_32_too_big2.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::((u32::MAX-127) as f32); } //~ ERROR: cannot be represented in target type `u32` + unsafe { + float_to_int_unchecked::((u32::MAX - 127) as f32); + } //~ ERROR: cannot be represented in target type `u32` } diff --git a/tests/fail/intrinsics/float_to_int_32_too_small1.rs b/tests/fail/intrinsics/float_to_int_32_too_small1.rs index 89f09e1e3f18..a96738214bd0 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_small1.rs +++ b/tests/fail/intrinsics/float_to_int_32_too_small1.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(-2147483904.0f32); } //~ ERROR: cannot be represented in target type `i32` + unsafe { + float_to_int_unchecked::(-2147483904.0f32); + } //~ ERROR: cannot be represented in target type `i32` } diff --git a/tests/fail/intrinsics/float_to_int_64_inf1.rs b/tests/fail/intrinsics/float_to_int_64_inf1.rs index e1a7b818d853..259ec883f6ca 100644 --- a/tests/fail/intrinsics/float_to_int_64_inf1.rs +++ b/tests/fail/intrinsics/float_to_int_64_inf1.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(f64::INFINITY); } //~ ERROR: cannot be represented in target type `u128` + unsafe { + float_to_int_unchecked::(f64::INFINITY); + } //~ ERROR: cannot be represented in target type `u128` } diff --git a/tests/fail/intrinsics/float_to_int_64_infneg1.rs b/tests/fail/intrinsics/float_to_int_64_infneg1.rs index a1d757b1511e..3bc5ac710e97 100644 --- a/tests/fail/intrinsics/float_to_int_64_infneg1.rs +++ b/tests/fail/intrinsics/float_to_int_64_infneg1.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(f64::NEG_INFINITY); } //~ ERROR: cannot be represented in target type `u128` + unsafe { + float_to_int_unchecked::(f64::NEG_INFINITY); + } //~ ERROR: cannot be represented in target type `u128` } diff --git a/tests/fail/intrinsics/float_to_int_64_infneg2.rs b/tests/fail/intrinsics/float_to_int_64_infneg2.rs index e48d19f1a6a8..81a79c4d2116 100644 --- a/tests/fail/intrinsics/float_to_int_64_infneg2.rs +++ b/tests/fail/intrinsics/float_to_int_64_infneg2.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(f64::NEG_INFINITY); } //~ ERROR: cannot be represented in target type `i128` + unsafe { + float_to_int_unchecked::(f64::NEG_INFINITY); + } //~ ERROR: cannot be represented in target type `i128` } diff --git a/tests/fail/intrinsics/float_to_int_64_nan.rs b/tests/fail/intrinsics/float_to_int_64_nan.rs index 03f378f5bcb7..47580ad5b2a0 100644 --- a/tests/fail/intrinsics/float_to_int_64_nan.rs +++ b/tests/fail/intrinsics/float_to_int_64_nan.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(f64::NAN); } //~ ERROR: cannot be represented in target type `u32` + unsafe { + float_to_int_unchecked::(f64::NAN); + } //~ ERROR: cannot be represented in target type `u32` } diff --git a/tests/fail/intrinsics/float_to_int_64_neg.rs b/tests/fail/intrinsics/float_to_int_64_neg.rs index d0b5a3e21cf9..0e97c2f26bb3 100644 --- a/tests/fail/intrinsics/float_to_int_64_neg.rs +++ b/tests/fail/intrinsics/float_to_int_64_neg.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(-1.0000000000001f64); } //~ ERROR: cannot be represented in target type `u128` + unsafe { + float_to_int_unchecked::(-1.0000000000001f64); + } //~ ERROR: cannot be represented in target type `u128` } diff --git a/tests/fail/intrinsics/float_to_int_64_too_big1.rs b/tests/fail/intrinsics/float_to_int_64_too_big1.rs index f928f161872e..fb75a793ded4 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big1.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_big1.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(2147483648.0f64); } //~ ERROR: cannot be represented in target type `i32` + unsafe { + float_to_int_unchecked::(2147483648.0f64); + } //~ ERROR: cannot be represented in target type `i32` } diff --git a/tests/fail/intrinsics/float_to_int_64_too_big2.rs b/tests/fail/intrinsics/float_to_int_64_too_big2.rs index feb24c362dda..0c039ff8493e 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big2.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_big2.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(9223372036854775808.0f64); } //~ ERROR: cannot be represented in target type `i64` + unsafe { + float_to_int_unchecked::(9223372036854775808.0f64); + } //~ ERROR: cannot be represented in target type `i64` } diff --git a/tests/fail/intrinsics/float_to_int_64_too_big3.rs b/tests/fail/intrinsics/float_to_int_64_too_big3.rs index cd491bfed7eb..b9d2775f0325 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big3.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_big3.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(18446744073709551616.0f64); } //~ ERROR: cannot be represented in target type `u64` + unsafe { + float_to_int_unchecked::(18446744073709551616.0f64); + } //~ ERROR: cannot be represented in target type `u64` } diff --git a/tests/fail/intrinsics/float_to_int_64_too_big4.rs b/tests/fail/intrinsics/float_to_int_64_too_big4.rs index e9623dba947f..4a2dc7822f78 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big4.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_big4.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(u128::MAX as f64); } //~ ERROR: cannot be represented in target type `u128` + unsafe { + float_to_int_unchecked::(u128::MAX as f64); + } //~ ERROR: cannot be represented in target type `u128` } diff --git a/tests/fail/intrinsics/float_to_int_64_too_big5.rs b/tests/fail/intrinsics/float_to_int_64_too_big5.rs index 9c31c690b4e8..bf1f797a0003 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big5.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_big5.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(240282366920938463463374607431768211455.0f64); } //~ ERROR: cannot be represented in target type `i128` + unsafe { + float_to_int_unchecked::(240282366920938463463374607431768211455.0f64); + } //~ ERROR: cannot be represented in target type `i128` } diff --git a/tests/fail/intrinsics/float_to_int_64_too_big6.rs b/tests/fail/intrinsics/float_to_int_64_too_big6.rs index f008131a6e52..2b6d6359c9a8 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big6.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_big6.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(f64::MAX); } //~ ERROR: cannot be represented in target type `u128` + unsafe { + float_to_int_unchecked::(f64::MAX); + } //~ ERROR: cannot be represented in target type `u128` } diff --git a/tests/fail/intrinsics/float_to_int_64_too_big7.rs b/tests/fail/intrinsics/float_to_int_64_too_big7.rs index 69922e60a6bc..e9b1333232c0 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big7.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_big7.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(f64::MIN); } //~ ERROR: cannot be represented in target type `i128` + unsafe { + float_to_int_unchecked::(f64::MIN); + } //~ ERROR: cannot be represented in target type `i128` } diff --git a/tests/fail/intrinsics/float_to_int_64_too_small1.rs b/tests/fail/intrinsics/float_to_int_64_too_small1.rs index 08f2f9e3fd26..652edf1931b3 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small1.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_small1.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(-2147483649.0f64); } //~ ERROR: cannot be represented in target type `i32` + unsafe { + float_to_int_unchecked::(-2147483649.0f64); + } //~ ERROR: cannot be represented in target type `i32` } diff --git a/tests/fail/intrinsics/float_to_int_64_too_small2.rs b/tests/fail/intrinsics/float_to_int_64_too_small2.rs index f7b205de5346..d3d5559291b3 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small2.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_small2.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(-9223372036854777856.0f64); } //~ ERROR: cannot be represented in target type `i64` + unsafe { + float_to_int_unchecked::(-9223372036854777856.0f64); + } //~ ERROR: cannot be represented in target type `i64` } diff --git a/tests/fail/intrinsics/float_to_int_64_too_small3.rs b/tests/fail/intrinsics/float_to_int_64_too_small3.rs index 779441f7448c..0e22951a45cd 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small3.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_small3.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(-240282366920938463463374607431768211455.0f64); } //~ ERROR: cannot be represented in target type `i128` + unsafe { + float_to_int_unchecked::(-240282366920938463463374607431768211455.0f64); + } //~ ERROR: cannot be represented in target type `i128` } diff --git a/tests/fail/intrinsics/unchecked_add1.rs b/tests/fail/intrinsics/unchecked_add1.rs index f48b91422c6e..90d0a3d01236 100644 --- a/tests/fail/intrinsics/unchecked_add1.rs +++ b/tests/fail/intrinsics/unchecked_add1.rs @@ -1,5 +1,7 @@ #![feature(core_intrinsics)] fn main() { // MAX overflow - unsafe { std::intrinsics::unchecked_add(40000u16, 30000); } //~ ERROR overflow executing `unchecked_add` + unsafe { + std::intrinsics::unchecked_add(40000u16, 30000); + } //~ ERROR overflow executing `unchecked_add` } diff --git a/tests/fail/intrinsics/unchecked_add2.rs b/tests/fail/intrinsics/unchecked_add2.rs index 150986541c3d..68e9fb4563e7 100644 --- a/tests/fail/intrinsics/unchecked_add2.rs +++ b/tests/fail/intrinsics/unchecked_add2.rs @@ -1,5 +1,7 @@ #![feature(core_intrinsics)] fn main() { // MIN overflow - unsafe { std::intrinsics::unchecked_add(-30000i16, -8000); } //~ ERROR overflow executing `unchecked_add` + unsafe { + std::intrinsics::unchecked_add(-30000i16, -8000); + } //~ ERROR overflow executing `unchecked_add` } diff --git a/tests/fail/intrinsics/unchecked_div1.rs b/tests/fail/intrinsics/unchecked_div1.rs index 08b654da3ed7..23fc1514f1a1 100644 --- a/tests/fail/intrinsics/unchecked_div1.rs +++ b/tests/fail/intrinsics/unchecked_div1.rs @@ -1,5 +1,7 @@ #![feature(core_intrinsics)] fn main() { // MIN/-1 cannot be represented - unsafe { std::intrinsics::unchecked_div(i16::MIN, -1); } //~ ERROR overflow in signed division (dividing MIN by -1) + unsafe { + std::intrinsics::unchecked_div(i16::MIN, -1); + } //~ ERROR overflow in signed division (dividing MIN by -1) } diff --git a/tests/fail/intrinsics/unchecked_mul1.rs b/tests/fail/intrinsics/unchecked_mul1.rs index 050e3ff24377..f26d4d3d213f 100644 --- a/tests/fail/intrinsics/unchecked_mul1.rs +++ b/tests/fail/intrinsics/unchecked_mul1.rs @@ -1,5 +1,7 @@ #![feature(core_intrinsics)] fn main() { // MAX overflow - unsafe { std::intrinsics::unchecked_mul(300u16, 250u16); } //~ ERROR overflow executing `unchecked_mul` + unsafe { + std::intrinsics::unchecked_mul(300u16, 250u16); + } //~ ERROR overflow executing `unchecked_mul` } diff --git a/tests/fail/intrinsics/unchecked_mul2.rs b/tests/fail/intrinsics/unchecked_mul2.rs index 4fb77783b4ce..f3e20e8c295d 100644 --- a/tests/fail/intrinsics/unchecked_mul2.rs +++ b/tests/fail/intrinsics/unchecked_mul2.rs @@ -1,5 +1,7 @@ #![feature(core_intrinsics)] fn main() { // MIN overflow - unsafe { std::intrinsics::unchecked_mul(1_000_000_000i32, -4); } //~ ERROR overflow executing `unchecked_mul` + unsafe { + std::intrinsics::unchecked_mul(1_000_000_000i32, -4); + } //~ ERROR overflow executing `unchecked_mul` } diff --git a/tests/fail/intrinsics/unchecked_sub1.rs b/tests/fail/intrinsics/unchecked_sub1.rs index 69b32dd319b6..3ea5e618074c 100644 --- a/tests/fail/intrinsics/unchecked_sub1.rs +++ b/tests/fail/intrinsics/unchecked_sub1.rs @@ -1,5 +1,7 @@ #![feature(core_intrinsics)] fn main() { // MIN overflow - unsafe { std::intrinsics::unchecked_sub(14u32, 22); } //~ ERROR overflow executing `unchecked_sub` + unsafe { + std::intrinsics::unchecked_sub(14u32, 22); + } //~ ERROR overflow executing `unchecked_sub` } diff --git a/tests/fail/intrinsics/unchecked_sub2.rs b/tests/fail/intrinsics/unchecked_sub2.rs index 5609ea7a3edd..0e9892e58a52 100644 --- a/tests/fail/intrinsics/unchecked_sub2.rs +++ b/tests/fail/intrinsics/unchecked_sub2.rs @@ -1,5 +1,7 @@ #![feature(core_intrinsics)] fn main() { // MAX overflow - unsafe { std::intrinsics::unchecked_sub(30000i16, -7000); } //~ ERROR overflow executing `unchecked_sub` + unsafe { + std::intrinsics::unchecked_sub(30000i16, -7000); + } //~ ERROR overflow executing `unchecked_sub` } diff --git a/tests/fail/panic/unwind_panic_abort.rs b/tests/fail/panic/unwind_panic_abort.rs index a333a4b0ded8..7cb0c7b02799 100644 --- a/tests/fail/panic/unwind_panic_abort.rs +++ b/tests/fail/panic/unwind_panic_abort.rs @@ -7,5 +7,7 @@ extern "Rust" { } fn main() { - unsafe { miri_start_panic(&mut 0); } //~ ERROR unwinding past a stack frame that does not allow unwinding + unsafe { + miri_start_panic(&mut 0); + } //~ ERROR unwinding past a stack frame that does not allow unwinding } diff --git a/tests/fail/stacked_borrows/illegal_write1.rs b/tests/fail/stacked_borrows/illegal_write1.rs index dd262a341ed2..5bdd4ef1f052 100644 --- a/tests/fail/stacked_borrows/illegal_write1.rs +++ b/tests/fail/stacked_borrows/illegal_write1.rs @@ -2,8 +2,10 @@ fn main() { let target = Box::new(42); // has an implicit raw let xref = &*target; { - let x : *mut u32 = xref as *const _ as *mut _; - unsafe { *x = 42; } // invalidates shared ref, activates raw + let x: *mut u32 = xref as *const _ as *mut _; + unsafe { + *x = 42; + } // invalidates shared ref, activates raw } let _x = *xref; //~ ERROR borrow stack } diff --git a/tests/fail/stacked_borrows/illegal_write2.rs b/tests/fail/stacked_borrows/illegal_write2.rs index 62ea05e1811e..25a9cc4012ba 100644 --- a/tests/fail/stacked_borrows/illegal_write2.rs +++ b/tests/fail/stacked_borrows/illegal_write2.rs @@ -3,6 +3,8 @@ fn main() { let target2 = target as *mut _; drop(&mut *target); // reborrow // Now make sure our ref is still the only one. - unsafe { *target2 = 13; } //~ ERROR borrow stack + unsafe { + *target2 = 13; + } //~ ERROR borrow stack let _val = *target; } diff --git a/tests/fail/stacked_borrows/illegal_write3.rs b/tests/fail/stacked_borrows/illegal_write3.rs index 7851eeb02690..4bbd1e56a747 100644 --- a/tests/fail/stacked_borrows/illegal_write3.rs +++ b/tests/fail/stacked_borrows/illegal_write3.rs @@ -3,6 +3,8 @@ fn main() { // Make sure raw ptr with raw tag cannot mutate frozen location without breaking the shared ref. let r#ref = ⌖ // freeze let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag - unsafe { *ptr = 42; } //~ ERROR only grants SharedReadOnly permission + unsafe { + *ptr = 42; + } //~ ERROR only grants SharedReadOnly permission let _val = *r#ref; } diff --git a/tests/fail/stacked_borrows/illegal_write6.rs b/tests/fail/stacked_borrows/illegal_write6.rs index 6985e7f0ead3..49ffb9a8604b 100644 --- a/tests/fail/stacked_borrows/illegal_write6.rs +++ b/tests/fail/stacked_borrows/illegal_write6.rs @@ -7,6 +7,8 @@ fn main() { fn foo(a: &mut u32, y: *mut u32) -> u32 { *a = 1; let _b = &*a; - unsafe { *y = 2; } //~ ERROR: not granting access to tag + unsafe { + *y = 2; + } //~ ERROR: not granting access to tag return *a; } diff --git a/tests/fail/stacked_borrows/raw_tracking.rs b/tests/fail/stacked_borrows/raw_tracking.rs index a8e1d806cbbb..22898483bf19 100644 --- a/tests/fail/stacked_borrows/raw_tracking.rs +++ b/tests/fail/stacked_borrows/raw_tracking.rs @@ -7,6 +7,10 @@ fn main() { let raw2 = &mut l as *mut _; // invalidates raw1 // Without raw pointer tracking, Stacked Borrows cannot distinguish raw1 and raw2, and thus // fails to realize that raw1 should not be used any more. - unsafe { *raw1 = 13; } //~ ERROR does not exist in the borrow stack - unsafe { *raw2 = 13; } + unsafe { + *raw1 = 13; + } //~ ERROR does not exist in the borrow stack + unsafe { + *raw2 = 13; + } } diff --git a/tests/fail/stacked_borrows/shr_frozen_violation1.rs b/tests/fail/stacked_borrows/shr_frozen_violation1.rs index 1ea96086d3e4..803e8c6eb101 100644 --- a/tests/fail/stacked_borrows/shr_frozen_violation1.rs +++ b/tests/fail/stacked_borrows/shr_frozen_violation1.rs @@ -1,7 +1,7 @@ fn foo(x: &mut i32) -> i32 { - *x = 5; - unknown_code(&*x); - *x // must return 5 + *x = 5; + unknown_code(&*x); + *x // must return 5 } fn main() { @@ -9,5 +9,7 @@ fn main() { } fn unknown_code(x: &i32) { - unsafe { *(x as *const i32 as *mut i32) = 7; } //~ ERROR only grants SharedReadOnly permission + unsafe { + *(x as *const i32 as *mut i32) = 7; + } //~ ERROR only grants SharedReadOnly permission } diff --git a/tests/fail/stacked_borrows/transmute-is-no-escape.rs b/tests/fail/stacked_borrows/transmute-is-no-escape.rs index e9282c5ba8f2..2a766d2c1b7c 100644 --- a/tests/fail/stacked_borrows/transmute-is-no-escape.rs +++ b/tests/fail/stacked_borrows/transmute-is-no-escape.rs @@ -10,5 +10,7 @@ fn main() { let _raw: *mut i32 = unsafe { mem::transmute(&mut x[0]) }; // `raw` still carries a tag, so we get another pointer to the same location that does not carry a tag let raw = (&mut x[1] as *mut i32).wrapping_offset(-1); - unsafe { *raw = 13; } //~ ERROR borrow stack + unsafe { + *raw = 13; + } //~ ERROR borrow stack } diff --git a/tests/fail/stacked_borrows/unescaped_local.rs b/tests/fail/stacked_borrows/unescaped_local.rs index b49e6cce63bc..c807f936d121 100644 --- a/tests/fail/stacked_borrows/unescaped_local.rs +++ b/tests/fail/stacked_borrows/unescaped_local.rs @@ -4,5 +4,7 @@ fn main() { let mut x = 42; let raw = &mut x as *mut i32 as usize as *mut i32; let _ptr = &mut x; - unsafe { *raw = 13; } //~ ERROR borrow stack + unsafe { + *raw = 13; + } //~ ERROR borrow stack } diff --git a/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs b/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs index 9872a493c02a..ca892f832092 100644 --- a/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs +++ b/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs @@ -10,8 +10,10 @@ fn main() { let x = &mut [0u8; 3]; let base_addr = x as *mut _ as usize; // Manually make sure the pointer is properly aligned. - let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr+1 }; + let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr + 1 }; let u16_ptr = base_addr_aligned as *mut u16; - unsafe { *u16_ptr = 2; } //~ERROR memory with alignment 1, but alignment 2 is required + unsafe { + *u16_ptr = 2; + } //~ERROR memory with alignment 1, but alignment 2 is required println!("{:?}", x); } diff --git a/tests/fail/validity/transmute_through_ptr.rs b/tests/fail/validity/transmute_through_ptr.rs index b1984429d2de..23da1ba12572 100644 --- a/tests/fail/validity/transmute_through_ptr.rs +++ b/tests/fail/validity/transmute_through_ptr.rs @@ -1,10 +1,14 @@ #[repr(u32)] #[derive(Debug)] -enum Bool { True } +enum Bool { + True, +} fn evil(x: &mut Bool) { let x = x as *mut _ as *mut u32; - unsafe { *x = 44; } // out-of-bounds enum tag + unsafe { + *x = 44; + } // out-of-bounds enum tag } #[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/5391 diff --git a/tests/fail/zst2.rs b/tests/fail/zst2.rs index a602cb731e40..cd9cf3618d25 100644 --- a/tests/fail/zst2.rs +++ b/tests/fail/zst2.rs @@ -11,5 +11,7 @@ fn main() { let mut x_box = Box::new(1u8); let x = &mut *x_box as *mut _ as *mut [u8; 0]; drop(x_box); - unsafe { *x = zst_val; } //~ ERROR dereferenced after this allocation got freed + unsafe { + *x = zst_val; + } //~ ERROR dereferenced after this allocation got freed } diff --git a/tests/fail/zst3.rs b/tests/fail/zst3.rs index 7ecb8c7dca9d..defb5a626ba5 100644 --- a/tests/fail/zst3.rs +++ b/tests/fail/zst3.rs @@ -11,8 +11,12 @@ fn main() { let mut x_box = Box::new(1u8); let x = (&mut *x_box as *mut u8).wrapping_offset(1); // This one is just "at the edge", but still okay - unsafe { *(x as *mut [u8; 0]) = zst_val; } + unsafe { + *(x as *mut [u8; 0]) = zst_val; + } // One byte further is OOB. let x = x.wrapping_offset(1); - unsafe { *(x as *mut [u8; 0]) = zst_val; } //~ ERROR out-of-bounds + unsafe { + *(x as *mut [u8; 0]) = zst_val; + } //~ ERROR out-of-bounds } From 7326da7ce3750087fe13effd595c73caf92f5cdf Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 21 Jun 2022 11:40:02 -0700 Subject: [PATCH 3315/5092] Manual adjustments --- tests/fail/box-cell-alias.rs | 4 ++-- tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs | 4 ++-- tests/fail/intrinsics/copy_null.rs | 4 ++-- tests/fail/intrinsics/copy_unaligned.rs | 4 ++-- tests/fail/intrinsics/exact_div1.rs | 4 ++-- tests/fail/intrinsics/exact_div2.rs | 4 ++-- tests/fail/intrinsics/exact_div3.rs | 4 ++-- tests/fail/intrinsics/exact_div4.rs | 4 ++-- tests/fail/intrinsics/float_to_int_32_inf1.rs | 4 ++-- tests/fail/intrinsics/float_to_int_32_infneg1.rs | 4 ++-- tests/fail/intrinsics/float_to_int_32_nan.rs | 4 ++-- tests/fail/intrinsics/float_to_int_32_nanneg.rs | 4 ++-- tests/fail/intrinsics/float_to_int_32_neg.rs | 4 ++-- tests/fail/intrinsics/float_to_int_32_too_big1.rs | 4 ++-- tests/fail/intrinsics/float_to_int_32_too_big2.rs | 4 ++-- tests/fail/intrinsics/float_to_int_32_too_small1.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_inf1.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_infneg1.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_infneg2.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_nan.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_neg.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_too_big1.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_too_big2.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_too_big3.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_too_big4.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_too_big5.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_too_big6.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_too_big7.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_too_small1.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_too_small2.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_too_small3.rs | 4 ++-- tests/fail/intrinsics/unchecked_add1.rs | 4 ++-- tests/fail/intrinsics/unchecked_add2.rs | 4 ++-- tests/fail/intrinsics/unchecked_div1.rs | 4 ++-- tests/fail/intrinsics/unchecked_mul1.rs | 4 ++-- tests/fail/intrinsics/unchecked_mul2.rs | 4 ++-- tests/fail/intrinsics/unchecked_sub1.rs | 4 ++-- tests/fail/intrinsics/unchecked_sub2.rs | 4 ++-- tests/fail/panic/unwind_panic_abort.rs | 4 ++-- tests/fail/stacked_borrows/illegal_write1.rs | 4 ++-- tests/fail/stacked_borrows/illegal_write2.rs | 4 ++-- tests/fail/stacked_borrows/illegal_write3.rs | 4 ++-- tests/fail/stacked_borrows/illegal_write6.rs | 4 ++-- tests/fail/stacked_borrows/raw_tracking.rs | 4 ++-- tests/fail/stacked_borrows/shr_frozen_violation1.rs | 4 ++-- tests/fail/stacked_borrows/transmute-is-no-escape.rs | 4 ++-- tests/fail/stacked_borrows/unescaped_local.rs | 4 ++-- tests/fail/unaligned_pointers/intptrcast_alignment_check.rs | 4 ++-- tests/fail/validity/transmute_through_ptr.rs | 4 ++-- tests/fail/zst2.rs | 4 ++-- tests/fail/zst3.rs | 4 ++-- 51 files changed, 102 insertions(+), 102 deletions(-) diff --git a/tests/fail/box-cell-alias.rs b/tests/fail/box-cell-alias.rs index ffda1033d44b..c1fec28ae3b7 100644 --- a/tests/fail/box-cell-alias.rs +++ b/tests/fail/box-cell-alias.rs @@ -7,8 +7,8 @@ use std::cell::Cell; fn helper(val: Box>, ptr: *const Cell) -> u8 { val.set(10); unsafe { - (*ptr).set(20); - } //~ ERROR does not exist in the borrow stack + (*ptr).set(20); //~ ERROR does not exist in the borrow stack + } val.get() } diff --git a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs index 78384502337c..3115da436be8 100644 --- a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs +++ b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs @@ -8,6 +8,6 @@ fn main() { let zst_val = [1u8; 0]; let ptr = (&0u8 as *const u8).wrapping_sub(0x800) as *mut [u8; 0]; unsafe { - *ptr = zst_val; - } //~ ERROR out-of-bounds + *ptr = zst_val; //~ ERROR out-of-bounds + } } diff --git a/tests/fail/intrinsics/copy_null.rs b/tests/fail/intrinsics/copy_null.rs index 1e572fe4a855..7ab41232498e 100644 --- a/tests/fail/intrinsics/copy_null.rs +++ b/tests/fail/intrinsics/copy_null.rs @@ -10,6 +10,6 @@ fn main() { let ptr = &mut data[0] as *mut u16; // Even copying 0 elements from NULL should error. unsafe { - copy_nonoverlapping(std::ptr::null(), ptr, 0); - } //~ ERROR: memory access failed: null pointer is not a valid pointer + copy_nonoverlapping(std::ptr::null(), ptr, 0); //~ ERROR: memory access failed: null pointer is not a valid pointer + } } diff --git a/tests/fail/intrinsics/copy_unaligned.rs b/tests/fail/intrinsics/copy_unaligned.rs index d7097bb91d3a..162f06bfacd9 100644 --- a/tests/fail/intrinsics/copy_unaligned.rs +++ b/tests/fail/intrinsics/copy_unaligned.rs @@ -10,6 +10,6 @@ fn main() { let ptr = (&mut data[0] as *mut u16 as *mut u8).wrapping_add(1) as *mut u16; // Even copying 0 elements to something unaligned should error unsafe { - copy_nonoverlapping(&data[5], ptr, 0); - } //~ ERROR accessing memory with alignment 1, but alignment 2 is required + copy_nonoverlapping(&data[5], ptr, 0); //~ ERROR accessing memory with alignment 1, but alignment 2 is required + } } diff --git a/tests/fail/intrinsics/exact_div1.rs b/tests/fail/intrinsics/exact_div1.rs index 5d2185f1ee1b..d8af789e99a2 100644 --- a/tests/fail/intrinsics/exact_div1.rs +++ b/tests/fail/intrinsics/exact_div1.rs @@ -2,6 +2,6 @@ fn main() { // divison by 0 unsafe { - std::intrinsics::exact_div(2, 0); - } //~ ERROR divisor of zero + std::intrinsics::exact_div(2, 0); //~ ERROR divisor of zero + } } diff --git a/tests/fail/intrinsics/exact_div2.rs b/tests/fail/intrinsics/exact_div2.rs index e0301fbd73e2..80f9131bab79 100644 --- a/tests/fail/intrinsics/exact_div2.rs +++ b/tests/fail/intrinsics/exact_div2.rs @@ -2,6 +2,6 @@ fn main() { // divison with a remainder unsafe { - std::intrinsics::exact_div(2u16, 3); - } //~ ERROR 2_u16 cannot be divided by 3_u16 without remainder + std::intrinsics::exact_div(2u16, 3); //~ ERROR 2_u16 cannot be divided by 3_u16 without remainder + } } diff --git a/tests/fail/intrinsics/exact_div3.rs b/tests/fail/intrinsics/exact_div3.rs index 5f74b2dfa818..976fca29f9ba 100644 --- a/tests/fail/intrinsics/exact_div3.rs +++ b/tests/fail/intrinsics/exact_div3.rs @@ -2,6 +2,6 @@ fn main() { // signed divison with a remainder unsafe { - std::intrinsics::exact_div(-19i8, 2); - } //~ ERROR -19_i8 cannot be divided by 2_i8 without remainder + std::intrinsics::exact_div(-19i8, 2); //~ ERROR -19_i8 cannot be divided by 2_i8 without remainder + } } diff --git a/tests/fail/intrinsics/exact_div4.rs b/tests/fail/intrinsics/exact_div4.rs index f70746d2a116..5f4ca587e6d7 100644 --- a/tests/fail/intrinsics/exact_div4.rs +++ b/tests/fail/intrinsics/exact_div4.rs @@ -2,6 +2,6 @@ fn main() { // divison of MIN by -1 unsafe { - std::intrinsics::exact_div(i64::MIN, -1); - } //~ ERROR overflow in signed remainder (dividing MIN by -1) + std::intrinsics::exact_div(i64::MIN, -1); //~ ERROR overflow in signed remainder (dividing MIN by -1) + } } diff --git a/tests/fail/intrinsics/float_to_int_32_inf1.rs b/tests/fail/intrinsics/float_to_int_32_inf1.rs index 32c2e09b53a3..a57845426d58 100644 --- a/tests/fail/intrinsics/float_to_int_32_inf1.rs +++ b/tests/fail/intrinsics/float_to_int_32_inf1.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(f32::INFINITY); - } //~ ERROR: cannot be represented in target type `i32` + float_to_int_unchecked::(f32::INFINITY); //~ ERROR: cannot be represented in target type `i32` + } } diff --git a/tests/fail/intrinsics/float_to_int_32_infneg1.rs b/tests/fail/intrinsics/float_to_int_32_infneg1.rs index e1ba2224a088..d383fc5b50ac 100644 --- a/tests/fail/intrinsics/float_to_int_32_infneg1.rs +++ b/tests/fail/intrinsics/float_to_int_32_infneg1.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(f32::NEG_INFINITY); - } //~ ERROR: cannot be represented in target type `i32` + float_to_int_unchecked::(f32::NEG_INFINITY); //~ ERROR: cannot be represented in target type `i32` + } } diff --git a/tests/fail/intrinsics/float_to_int_32_nan.rs b/tests/fail/intrinsics/float_to_int_32_nan.rs index 6c128d94a87f..a39a5066b6f8 100644 --- a/tests/fail/intrinsics/float_to_int_32_nan.rs +++ b/tests/fail/intrinsics/float_to_int_32_nan.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(f32::NAN); - } //~ ERROR: cannot be represented in target type `u32` + float_to_int_unchecked::(f32::NAN); //~ ERROR: cannot be represented in target type `u32` + } } diff --git a/tests/fail/intrinsics/float_to_int_32_nanneg.rs b/tests/fail/intrinsics/float_to_int_32_nanneg.rs index 9bc628e9db92..71436eb3ba84 100644 --- a/tests/fail/intrinsics/float_to_int_32_nanneg.rs +++ b/tests/fail/intrinsics/float_to_int_32_nanneg.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(-f32::NAN); - } //~ ERROR: cannot be represented in target type `u32` + float_to_int_unchecked::(-f32::NAN); //~ ERROR: cannot be represented in target type `u32` + } } diff --git a/tests/fail/intrinsics/float_to_int_32_neg.rs b/tests/fail/intrinsics/float_to_int_32_neg.rs index 188a9256db7e..98ba964e47c2 100644 --- a/tests/fail/intrinsics/float_to_int_32_neg.rs +++ b/tests/fail/intrinsics/float_to_int_32_neg.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(-1.000000001f32); - } //~ ERROR: cannot be represented in target type `u32` + float_to_int_unchecked::(-1.000000001f32); //~ ERROR: cannot be represented in target type `u32` + } } diff --git a/tests/fail/intrinsics/float_to_int_32_too_big1.rs b/tests/fail/intrinsics/float_to_int_32_too_big1.rs index 787941e63e2b..424b8fd965e9 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_big1.rs +++ b/tests/fail/intrinsics/float_to_int_32_too_big1.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(2147483648.0f32); - } //~ ERROR: cannot be represented in target type `i32` + float_to_int_unchecked::(2147483648.0f32); //~ ERROR: cannot be represented in target type `i32` + } } diff --git a/tests/fail/intrinsics/float_to_int_32_too_big2.rs b/tests/fail/intrinsics/float_to_int_32_too_big2.rs index 39b74cb04869..5c50926c4df3 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_big2.rs +++ b/tests/fail/intrinsics/float_to_int_32_too_big2.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::((u32::MAX - 127) as f32); - } //~ ERROR: cannot be represented in target type `u32` + float_to_int_unchecked::((u32::MAX - 127) as f32); //~ ERROR: cannot be represented in target type `u32` + } } diff --git a/tests/fail/intrinsics/float_to_int_32_too_small1.rs b/tests/fail/intrinsics/float_to_int_32_too_small1.rs index a96738214bd0..e0abd19d03fc 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_small1.rs +++ b/tests/fail/intrinsics/float_to_int_32_too_small1.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(-2147483904.0f32); - } //~ ERROR: cannot be represented in target type `i32` + float_to_int_unchecked::(-2147483904.0f32); //~ ERROR: cannot be represented in target type `i32` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_inf1.rs b/tests/fail/intrinsics/float_to_int_64_inf1.rs index 259ec883f6ca..f5f842e58ece 100644 --- a/tests/fail/intrinsics/float_to_int_64_inf1.rs +++ b/tests/fail/intrinsics/float_to_int_64_inf1.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(f64::INFINITY); - } //~ ERROR: cannot be represented in target type `u128` + float_to_int_unchecked::(f64::INFINITY); //~ ERROR: cannot be represented in target type `u128` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_infneg1.rs b/tests/fail/intrinsics/float_to_int_64_infneg1.rs index 3bc5ac710e97..244c25b31cbf 100644 --- a/tests/fail/intrinsics/float_to_int_64_infneg1.rs +++ b/tests/fail/intrinsics/float_to_int_64_infneg1.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(f64::NEG_INFINITY); - } //~ ERROR: cannot be represented in target type `u128` + float_to_int_unchecked::(f64::NEG_INFINITY); //~ ERROR: cannot be represented in target type `u128` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_infneg2.rs b/tests/fail/intrinsics/float_to_int_64_infneg2.rs index 81a79c4d2116..f7a663d12a56 100644 --- a/tests/fail/intrinsics/float_to_int_64_infneg2.rs +++ b/tests/fail/intrinsics/float_to_int_64_infneg2.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(f64::NEG_INFINITY); - } //~ ERROR: cannot be represented in target type `i128` + float_to_int_unchecked::(f64::NEG_INFINITY); //~ ERROR: cannot be represented in target type `i128` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_nan.rs b/tests/fail/intrinsics/float_to_int_64_nan.rs index 47580ad5b2a0..171cbcc59344 100644 --- a/tests/fail/intrinsics/float_to_int_64_nan.rs +++ b/tests/fail/intrinsics/float_to_int_64_nan.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(f64::NAN); - } //~ ERROR: cannot be represented in target type `u32` + float_to_int_unchecked::(f64::NAN); //~ ERROR: cannot be represented in target type `u32` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_neg.rs b/tests/fail/intrinsics/float_to_int_64_neg.rs index 0e97c2f26bb3..40b67e173b97 100644 --- a/tests/fail/intrinsics/float_to_int_64_neg.rs +++ b/tests/fail/intrinsics/float_to_int_64_neg.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(-1.0000000000001f64); - } //~ ERROR: cannot be represented in target type `u128` + float_to_int_unchecked::(-1.0000000000001f64); //~ ERROR: cannot be represented in target type `u128` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_too_big1.rs b/tests/fail/intrinsics/float_to_int_64_too_big1.rs index fb75a793ded4..e785123c4ca9 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big1.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_big1.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(2147483648.0f64); - } //~ ERROR: cannot be represented in target type `i32` + float_to_int_unchecked::(2147483648.0f64); //~ ERROR: cannot be represented in target type `i32` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_too_big2.rs b/tests/fail/intrinsics/float_to_int_64_too_big2.rs index 0c039ff8493e..4bf31d8ac027 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big2.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_big2.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(9223372036854775808.0f64); - } //~ ERROR: cannot be represented in target type `i64` + float_to_int_unchecked::(9223372036854775808.0f64); //~ ERROR: cannot be represented in target type `i64` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_too_big3.rs b/tests/fail/intrinsics/float_to_int_64_too_big3.rs index b9d2775f0325..9775a56724bc 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big3.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_big3.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(18446744073709551616.0f64); - } //~ ERROR: cannot be represented in target type `u64` + float_to_int_unchecked::(18446744073709551616.0f64); //~ ERROR: cannot be represented in target type `u64` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_too_big4.rs b/tests/fail/intrinsics/float_to_int_64_too_big4.rs index 4a2dc7822f78..53ff06e1e467 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big4.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_big4.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(u128::MAX as f64); - } //~ ERROR: cannot be represented in target type `u128` + float_to_int_unchecked::(u128::MAX as f64); //~ ERROR: cannot be represented in target type `u128` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_too_big5.rs b/tests/fail/intrinsics/float_to_int_64_too_big5.rs index bf1f797a0003..44356ff1771b 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big5.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_big5.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(240282366920938463463374607431768211455.0f64); - } //~ ERROR: cannot be represented in target type `i128` + float_to_int_unchecked::(240282366920938463463374607431768211455.0f64); //~ ERROR: cannot be represented in target type `i128` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_too_big6.rs b/tests/fail/intrinsics/float_to_int_64_too_big6.rs index 2b6d6359c9a8..66f5be96bfd0 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big6.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_big6.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(f64::MAX); - } //~ ERROR: cannot be represented in target type `u128` + float_to_int_unchecked::(f64::MAX); //~ ERROR: cannot be represented in target type `u128` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_too_big7.rs b/tests/fail/intrinsics/float_to_int_64_too_big7.rs index e9b1333232c0..18b380e8575e 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big7.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_big7.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(f64::MIN); - } //~ ERROR: cannot be represented in target type `i128` + float_to_int_unchecked::(f64::MIN); //~ ERROR: cannot be represented in target type `i128` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_too_small1.rs b/tests/fail/intrinsics/float_to_int_64_too_small1.rs index 652edf1931b3..2a23b1dc8a4b 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small1.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_small1.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(-2147483649.0f64); - } //~ ERROR: cannot be represented in target type `i32` + float_to_int_unchecked::(-2147483649.0f64); //~ ERROR: cannot be represented in target type `i32` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_too_small2.rs b/tests/fail/intrinsics/float_to_int_64_too_small2.rs index d3d5559291b3..7fc3effda5df 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small2.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_small2.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(-9223372036854777856.0f64); - } //~ ERROR: cannot be represented in target type `i64` + float_to_int_unchecked::(-9223372036854777856.0f64); //~ ERROR: cannot be represented in target type `i64` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_too_small3.rs b/tests/fail/intrinsics/float_to_int_64_too_small3.rs index 0e22951a45cd..2a8f9c366425 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small3.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_small3.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(-240282366920938463463374607431768211455.0f64); - } //~ ERROR: cannot be represented in target type `i128` + float_to_int_unchecked::(-240282366920938463463374607431768211455.0f64); //~ ERROR: cannot be represented in target type `i128` + } } diff --git a/tests/fail/intrinsics/unchecked_add1.rs b/tests/fail/intrinsics/unchecked_add1.rs index 90d0a3d01236..5409f66e805e 100644 --- a/tests/fail/intrinsics/unchecked_add1.rs +++ b/tests/fail/intrinsics/unchecked_add1.rs @@ -2,6 +2,6 @@ fn main() { // MAX overflow unsafe { - std::intrinsics::unchecked_add(40000u16, 30000); - } //~ ERROR overflow executing `unchecked_add` + std::intrinsics::unchecked_add(40000u16, 30000); //~ ERROR overflow executing `unchecked_add` + } } diff --git a/tests/fail/intrinsics/unchecked_add2.rs b/tests/fail/intrinsics/unchecked_add2.rs index 68e9fb4563e7..5deef7ee5ccd 100644 --- a/tests/fail/intrinsics/unchecked_add2.rs +++ b/tests/fail/intrinsics/unchecked_add2.rs @@ -2,6 +2,6 @@ fn main() { // MIN overflow unsafe { - std::intrinsics::unchecked_add(-30000i16, -8000); - } //~ ERROR overflow executing `unchecked_add` + std::intrinsics::unchecked_add(-30000i16, -8000); //~ ERROR overflow executing `unchecked_add` + } } diff --git a/tests/fail/intrinsics/unchecked_div1.rs b/tests/fail/intrinsics/unchecked_div1.rs index 23fc1514f1a1..c06a5bdce93e 100644 --- a/tests/fail/intrinsics/unchecked_div1.rs +++ b/tests/fail/intrinsics/unchecked_div1.rs @@ -2,6 +2,6 @@ fn main() { // MIN/-1 cannot be represented unsafe { - std::intrinsics::unchecked_div(i16::MIN, -1); - } //~ ERROR overflow in signed division (dividing MIN by -1) + std::intrinsics::unchecked_div(i16::MIN, -1); //~ ERROR overflow in signed division (dividing MIN by -1) + } } diff --git a/tests/fail/intrinsics/unchecked_mul1.rs b/tests/fail/intrinsics/unchecked_mul1.rs index f26d4d3d213f..140bc9e6c75b 100644 --- a/tests/fail/intrinsics/unchecked_mul1.rs +++ b/tests/fail/intrinsics/unchecked_mul1.rs @@ -2,6 +2,6 @@ fn main() { // MAX overflow unsafe { - std::intrinsics::unchecked_mul(300u16, 250u16); - } //~ ERROR overflow executing `unchecked_mul` + std::intrinsics::unchecked_mul(300u16, 250u16); //~ ERROR overflow executing `unchecked_mul` + } } diff --git a/tests/fail/intrinsics/unchecked_mul2.rs b/tests/fail/intrinsics/unchecked_mul2.rs index f3e20e8c295d..c4d16084b3f0 100644 --- a/tests/fail/intrinsics/unchecked_mul2.rs +++ b/tests/fail/intrinsics/unchecked_mul2.rs @@ -2,6 +2,6 @@ fn main() { // MIN overflow unsafe { - std::intrinsics::unchecked_mul(1_000_000_000i32, -4); - } //~ ERROR overflow executing `unchecked_mul` + std::intrinsics::unchecked_mul(1_000_000_000i32, -4); //~ ERROR overflow executing `unchecked_mul` + } } diff --git a/tests/fail/intrinsics/unchecked_sub1.rs b/tests/fail/intrinsics/unchecked_sub1.rs index 3ea5e618074c..cff79f9135f1 100644 --- a/tests/fail/intrinsics/unchecked_sub1.rs +++ b/tests/fail/intrinsics/unchecked_sub1.rs @@ -2,6 +2,6 @@ fn main() { // MIN overflow unsafe { - std::intrinsics::unchecked_sub(14u32, 22); - } //~ ERROR overflow executing `unchecked_sub` + std::intrinsics::unchecked_sub(14u32, 22); //~ ERROR overflow executing `unchecked_sub` + } } diff --git a/tests/fail/intrinsics/unchecked_sub2.rs b/tests/fail/intrinsics/unchecked_sub2.rs index 0e9892e58a52..9b741c2663d8 100644 --- a/tests/fail/intrinsics/unchecked_sub2.rs +++ b/tests/fail/intrinsics/unchecked_sub2.rs @@ -2,6 +2,6 @@ fn main() { // MAX overflow unsafe { - std::intrinsics::unchecked_sub(30000i16, -7000); - } //~ ERROR overflow executing `unchecked_sub` + std::intrinsics::unchecked_sub(30000i16, -7000); //~ ERROR overflow executing `unchecked_sub` + } } diff --git a/tests/fail/panic/unwind_panic_abort.rs b/tests/fail/panic/unwind_panic_abort.rs index 7cb0c7b02799..6afcd7ae7ff1 100644 --- a/tests/fail/panic/unwind_panic_abort.rs +++ b/tests/fail/panic/unwind_panic_abort.rs @@ -8,6 +8,6 @@ extern "Rust" { fn main() { unsafe { - miri_start_panic(&mut 0); - } //~ ERROR unwinding past a stack frame that does not allow unwinding + miri_start_panic(&mut 0); //~ ERROR unwinding past a stack frame that does not allow unwinding + } } diff --git a/tests/fail/stacked_borrows/illegal_write1.rs b/tests/fail/stacked_borrows/illegal_write1.rs index 5bdd4ef1f052..3b67accbbd2e 100644 --- a/tests/fail/stacked_borrows/illegal_write1.rs +++ b/tests/fail/stacked_borrows/illegal_write1.rs @@ -4,8 +4,8 @@ fn main() { { let x: *mut u32 = xref as *const _ as *mut _; unsafe { - *x = 42; - } // invalidates shared ref, activates raw + *x = 42; // invalidates shared ref, activates raw + } } let _x = *xref; //~ ERROR borrow stack } diff --git a/tests/fail/stacked_borrows/illegal_write2.rs b/tests/fail/stacked_borrows/illegal_write2.rs index 25a9cc4012ba..a106b4240c3c 100644 --- a/tests/fail/stacked_borrows/illegal_write2.rs +++ b/tests/fail/stacked_borrows/illegal_write2.rs @@ -4,7 +4,7 @@ fn main() { drop(&mut *target); // reborrow // Now make sure our ref is still the only one. unsafe { - *target2 = 13; - } //~ ERROR borrow stack + *target2 = 13; //~ ERROR borrow stack + } let _val = *target; } diff --git a/tests/fail/stacked_borrows/illegal_write3.rs b/tests/fail/stacked_borrows/illegal_write3.rs index 4bbd1e56a747..5bf651b33aa0 100644 --- a/tests/fail/stacked_borrows/illegal_write3.rs +++ b/tests/fail/stacked_borrows/illegal_write3.rs @@ -4,7 +4,7 @@ fn main() { let r#ref = ⌖ // freeze let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag unsafe { - *ptr = 42; - } //~ ERROR only grants SharedReadOnly permission + *ptr = 42; //~ ERROR only grants SharedReadOnly permission + } let _val = *r#ref; } diff --git a/tests/fail/stacked_borrows/illegal_write6.rs b/tests/fail/stacked_borrows/illegal_write6.rs index 49ffb9a8604b..07d57241205f 100644 --- a/tests/fail/stacked_borrows/illegal_write6.rs +++ b/tests/fail/stacked_borrows/illegal_write6.rs @@ -8,7 +8,7 @@ fn foo(a: &mut u32, y: *mut u32) -> u32 { *a = 1; let _b = &*a; unsafe { - *y = 2; - } //~ ERROR: not granting access to tag + *y = 2; //~ ERROR: not granting access to tag + } return *a; } diff --git a/tests/fail/stacked_borrows/raw_tracking.rs b/tests/fail/stacked_borrows/raw_tracking.rs index 22898483bf19..0a99e4ce47e7 100644 --- a/tests/fail/stacked_borrows/raw_tracking.rs +++ b/tests/fail/stacked_borrows/raw_tracking.rs @@ -8,8 +8,8 @@ fn main() { // Without raw pointer tracking, Stacked Borrows cannot distinguish raw1 and raw2, and thus // fails to realize that raw1 should not be used any more. unsafe { - *raw1 = 13; - } //~ ERROR does not exist in the borrow stack + *raw1 = 13; //~ ERROR does not exist in the borrow stack + } unsafe { *raw2 = 13; } diff --git a/tests/fail/stacked_borrows/shr_frozen_violation1.rs b/tests/fail/stacked_borrows/shr_frozen_violation1.rs index 803e8c6eb101..a6dd9ef4c2ee 100644 --- a/tests/fail/stacked_borrows/shr_frozen_violation1.rs +++ b/tests/fail/stacked_borrows/shr_frozen_violation1.rs @@ -10,6 +10,6 @@ fn main() { fn unknown_code(x: &i32) { unsafe { - *(x as *const i32 as *mut i32) = 7; - } //~ ERROR only grants SharedReadOnly permission + *(x as *const i32 as *mut i32) = 7; //~ ERROR only grants SharedReadOnly permission + } } diff --git a/tests/fail/stacked_borrows/transmute-is-no-escape.rs b/tests/fail/stacked_borrows/transmute-is-no-escape.rs index 2a766d2c1b7c..e23c893d6aaa 100644 --- a/tests/fail/stacked_borrows/transmute-is-no-escape.rs +++ b/tests/fail/stacked_borrows/transmute-is-no-escape.rs @@ -11,6 +11,6 @@ fn main() { // `raw` still carries a tag, so we get another pointer to the same location that does not carry a tag let raw = (&mut x[1] as *mut i32).wrapping_offset(-1); unsafe { - *raw = 13; - } //~ ERROR borrow stack + *raw = 13; //~ ERROR borrow stack + } } diff --git a/tests/fail/stacked_borrows/unescaped_local.rs b/tests/fail/stacked_borrows/unescaped_local.rs index c807f936d121..bfc937bb12b7 100644 --- a/tests/fail/stacked_borrows/unescaped_local.rs +++ b/tests/fail/stacked_borrows/unescaped_local.rs @@ -5,6 +5,6 @@ fn main() { let raw = &mut x as *mut i32 as usize as *mut i32; let _ptr = &mut x; unsafe { - *raw = 13; - } //~ ERROR borrow stack + *raw = 13; //~ ERROR borrow stack + } } diff --git a/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs b/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs index ca892f832092..e96f08fc9a7a 100644 --- a/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs +++ b/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs @@ -13,7 +13,7 @@ fn main() { let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr + 1 }; let u16_ptr = base_addr_aligned as *mut u16; unsafe { - *u16_ptr = 2; - } //~ERROR memory with alignment 1, but alignment 2 is required + *u16_ptr = 2; //~ERROR memory with alignment 1, but alignment 2 is required + } println!("{:?}", x); } diff --git a/tests/fail/validity/transmute_through_ptr.rs b/tests/fail/validity/transmute_through_ptr.rs index 23da1ba12572..4af3b8aef6aa 100644 --- a/tests/fail/validity/transmute_through_ptr.rs +++ b/tests/fail/validity/transmute_through_ptr.rs @@ -7,8 +7,8 @@ enum Bool { fn evil(x: &mut Bool) { let x = x as *mut _ as *mut u32; unsafe { - *x = 44; - } // out-of-bounds enum tag + *x = 44; // out-of-bounds enum tag + } } #[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/5391 diff --git a/tests/fail/zst2.rs b/tests/fail/zst2.rs index cd9cf3618d25..2499f79142db 100644 --- a/tests/fail/zst2.rs +++ b/tests/fail/zst2.rs @@ -12,6 +12,6 @@ fn main() { let x = &mut *x_box as *mut _ as *mut [u8; 0]; drop(x_box); unsafe { - *x = zst_val; - } //~ ERROR dereferenced after this allocation got freed + *x = zst_val; //~ ERROR dereferenced after this allocation got freed + } } diff --git a/tests/fail/zst3.rs b/tests/fail/zst3.rs index defb5a626ba5..741374c7ad98 100644 --- a/tests/fail/zst3.rs +++ b/tests/fail/zst3.rs @@ -17,6 +17,6 @@ fn main() { // One byte further is OOB. let x = x.wrapping_offset(1); unsafe { - *(x as *mut [u8; 0]) = zst_val; - } //~ ERROR out-of-bounds + *(x as *mut [u8; 0]) = zst_val; //~ ERROR out-of-bounds + } } From f1044d2f774b3525ab28372ccd2be30911f2eb29 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 21 Jun 2022 11:42:19 -0700 Subject: [PATCH 3316/5092] Bless stderr files after rustfmt --- tests/fail/box-cell-alias.stderr | 10 +++++----- .../maybe_null_pointer_write_zst.stderr | 4 ++-- tests/fail/intrinsics/copy_null.stderr | 4 ++-- tests/fail/intrinsics/copy_unaligned.stderr | 4 ++-- tests/fail/intrinsics/exact_div1.stderr | 4 ++-- tests/fail/intrinsics/exact_div2.stderr | 4 ++-- tests/fail/intrinsics/exact_div3.stderr | 4 ++-- tests/fail/intrinsics/exact_div4.stderr | 4 ++-- .../intrinsics/float_to_int_32_inf1.stderr | 4 ++-- .../intrinsics/float_to_int_32_infneg1.stderr | 4 ++-- .../fail/intrinsics/float_to_int_32_nan.stderr | 4 ++-- .../intrinsics/float_to_int_32_nanneg.stderr | 4 ++-- .../fail/intrinsics/float_to_int_32_neg.stderr | 4 ++-- .../intrinsics/float_to_int_32_too_big1.stderr | 4 ++-- .../intrinsics/float_to_int_32_too_big2.stderr | 4 ++-- .../float_to_int_32_too_small1.stderr | 4 ++-- .../intrinsics/float_to_int_64_inf1.stderr | 4 ++-- .../intrinsics/float_to_int_64_infneg1.stderr | 4 ++-- .../intrinsics/float_to_int_64_infneg2.stderr | 4 ++-- .../fail/intrinsics/float_to_int_64_nan.stderr | 4 ++-- .../fail/intrinsics/float_to_int_64_neg.stderr | 4 ++-- .../intrinsics/float_to_int_64_too_big1.stderr | 4 ++-- .../intrinsics/float_to_int_64_too_big2.stderr | 4 ++-- .../intrinsics/float_to_int_64_too_big3.stderr | 4 ++-- .../intrinsics/float_to_int_64_too_big4.stderr | 4 ++-- .../intrinsics/float_to_int_64_too_big5.stderr | 4 ++-- .../intrinsics/float_to_int_64_too_big6.stderr | 4 ++-- .../intrinsics/float_to_int_64_too_big7.stderr | 4 ++-- .../float_to_int_64_too_small1.stderr | 4 ++-- .../float_to_int_64_too_small2.stderr | 4 ++-- .../float_to_int_64_too_small3.stderr | 4 ++-- tests/fail/intrinsics/unchecked_add1.stderr | 4 ++-- tests/fail/intrinsics/unchecked_add2.stderr | 4 ++-- tests/fail/intrinsics/unchecked_div1.stderr | 4 ++-- tests/fail/intrinsics/unchecked_mul1.stderr | 4 ++-- tests/fail/intrinsics/unchecked_mul2.stderr | 4 ++-- tests/fail/intrinsics/unchecked_sub1.stderr | 4 ++-- tests/fail/intrinsics/unchecked_sub2.stderr | 4 ++-- tests/fail/panic/unwind_panic_abort.stderr | 4 ++-- .../fail/stacked_borrows/illegal_write1.stderr | 4 ++-- .../fail/stacked_borrows/illegal_write2.stderr | 10 +++++----- .../fail/stacked_borrows/illegal_write3.stderr | 10 +++++----- .../fail/stacked_borrows/illegal_write6.stderr | 7 ++++--- tests/fail/stacked_borrows/raw_tracking.stderr | 10 +++++----- .../shr_frozen_violation1.stderr | 18 +++++++++--------- .../transmute-is-no-escape.stderr | 10 +++++----- .../stacked_borrows/unescaped_local.stderr | 10 +++++----- .../intptrcast_alignment_check.stderr | 4 ++-- tests/fail/zst2.stderr | 4 ++-- tests/fail/zst3.stderr | 4 ++-- 50 files changed, 127 insertions(+), 126 deletions(-) diff --git a/tests/fail/box-cell-alias.stderr b/tests/fail/box-cell-alias.stderr index 44813be9780c..e5a3ad3d33af 100644 --- a/tests/fail/box-cell-alias.stderr +++ b/tests/fail/box-cell-alias.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/box-cell-alias.rs:LL:CC | -LL | unsafe { (*ptr).set(20); } - | ^^^^^^^^^^^^^^ - | | - | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x1] +LL | (*ptr).set(20); + | ^^^^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x1] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr index dc810424abc6..79fd2ba08685 100644 --- a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr +++ b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds --> $DIR/maybe_null_pointer_write_zst.rs:LL:CC | -LL | unsafe { *ptr = zst_val; } - | ^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds +LL | *ptr = zst_val; + | ^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/copy_null.stderr b/tests/fail/intrinsics/copy_null.stderr index 461f529fa85d..bb5a8742e909 100644 --- a/tests/fail/intrinsics/copy_null.stderr +++ b/tests/fail/intrinsics/copy_null.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: memory access failed: null pointer is not a valid pointer --> $DIR/copy_null.rs:LL:CC | -LL | unsafe { copy_nonoverlapping(std::ptr::null(), ptr, 0); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer +LL | copy_nonoverlapping(std::ptr::null(), ptr, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/copy_unaligned.stderr b/tests/fail/intrinsics/copy_unaligned.stderr index b99588698d22..b244eaeb4191 100644 --- a/tests/fail/intrinsics/copy_unaligned.stderr +++ b/tests/fail/intrinsics/copy_unaligned.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required --> $DIR/copy_unaligned.rs:LL:CC | -LL | unsafe { copy_nonoverlapping(&data[5], ptr, 0); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required +LL | copy_nonoverlapping(&data[5], ptr, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/exact_div1.stderr b/tests/fail/intrinsics/exact_div1.stderr index a0f03b201a8d..66f8168fade7 100644 --- a/tests/fail/intrinsics/exact_div1.stderr +++ b/tests/fail/intrinsics/exact_div1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: calculating the remainder with a divisor of zero --> $DIR/exact_div1.rs:LL:CC | -LL | unsafe { std::intrinsics::exact_div(2, 0); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calculating the remainder with a divisor of zero +LL | std::intrinsics::exact_div(2, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calculating the remainder with a divisor of zero | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/exact_div2.stderr b/tests/fail/intrinsics/exact_div2.stderr index 78a85c9caac6..2c102dd0b55c 100644 --- a/tests/fail/intrinsics/exact_div2.stderr +++ b/tests/fail/intrinsics/exact_div2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: exact_div: 2_u16 cannot be divided by 3_u16 without remainder --> $DIR/exact_div2.rs:LL:CC | -LL | unsafe { std::intrinsics::exact_div(2u16, 3); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: 2_u16 cannot be divided by 3_u16 without remainder +LL | std::intrinsics::exact_div(2u16, 3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: 2_u16 cannot be divided by 3_u16 without remainder | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/exact_div3.stderr b/tests/fail/intrinsics/exact_div3.stderr index 3062b60d468e..61eacdc65ff3 100644 --- a/tests/fail/intrinsics/exact_div3.stderr +++ b/tests/fail/intrinsics/exact_div3.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: exact_div: -19_i8 cannot be divided by 2_i8 without remainder --> $DIR/exact_div3.rs:LL:CC | -LL | unsafe { std::intrinsics::exact_div(-19i8, 2); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: -19_i8 cannot be divided by 2_i8 without remainder +LL | std::intrinsics::exact_div(-19i8, 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: -19_i8 cannot be divided by 2_i8 without remainder | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/exact_div4.stderr b/tests/fail/intrinsics/exact_div4.stderr index 1ae67ad87a5d..a3f5aafbe2d6 100644 --- a/tests/fail/intrinsics/exact_div4.stderr +++ b/tests/fail/intrinsics/exact_div4.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow in signed remainder (dividing MIN by -1) --> $DIR/exact_div4.rs:LL:CC | -LL | unsafe { std::intrinsics::exact_div(i64::MIN, -1); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) +LL | std::intrinsics::exact_div(i64::MIN, -1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_32_inf1.stderr b/tests/fail/intrinsics/float_to_int_32_inf1.stderr index cdf232d93eb2..b12fd13b5f4d 100644 --- a/tests/fail/intrinsics/float_to_int_32_inf1.stderr +++ b/tests/fail/intrinsics/float_to_int_32_inf1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on +Inf which cannot be represented in target type `i32` --> $DIR/float_to_int_32_inf1.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(f32::INFINITY); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on +Inf which cannot be represented in target type `i32` +LL | float_to_int_unchecked::(f32::INFINITY); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on +Inf which cannot be represented in target type `i32` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_32_infneg1.stderr b/tests/fail/intrinsics/float_to_int_32_infneg1.stderr index ae7301193682..d9223462bfa5 100644 --- a/tests/fail/intrinsics/float_to_int_32_infneg1.stderr +++ b/tests/fail/intrinsics/float_to_int_32_infneg1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `i32` --> $DIR/float_to_int_32_infneg1.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(f32::NEG_INFINITY); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `i32` +LL | float_to_int_unchecked::(f32::NEG_INFINITY); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `i32` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_32_nan.stderr b/tests/fail/intrinsics/float_to_int_32_nan.stderr index 9c20abef78df..cb8764174abd 100644 --- a/tests/fail/intrinsics/float_to_int_32_nan.stderr +++ b/tests/fail/intrinsics/float_to_int_32_nan.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` --> $DIR/float_to_int_32_nan.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(f32::NAN); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` +LL | float_to_int_unchecked::(f32::NAN); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_32_nanneg.stderr b/tests/fail/intrinsics/float_to_int_32_nanneg.stderr index f5675fd654dd..49e19bf96356 100644 --- a/tests/fail/intrinsics/float_to_int_32_nanneg.stderr +++ b/tests/fail/intrinsics/float_to_int_32_nanneg.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` --> $DIR/float_to_int_32_nanneg.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(-f32::NAN); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` +LL | float_to_int_unchecked::(-f32::NAN); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_32_neg.stderr b/tests/fail/intrinsics/float_to_int_32_neg.stderr index 3b7c755af654..5d847166a071 100644 --- a/tests/fail/intrinsics/float_to_int_32_neg.stderr +++ b/tests/fail/intrinsics/float_to_int_32_neg.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -1 which cannot be represented in target type `u32` --> $DIR/float_to_int_32_neg.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(-1.000000001f32); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1 which cannot be represented in target type `u32` +LL | float_to_int_unchecked::(-1.000000001f32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1 which cannot be represented in target type `u32` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_32_too_big1.stderr b/tests/fail/intrinsics/float_to_int_32_too_big1.stderr index abfda9eef0af..be6ad1f381d4 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_big1.stderr +++ b/tests/fail/intrinsics/float_to_int_32_too_big1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 2.14748365E+9 which cannot be represented in target type `i32` --> $DIR/float_to_int_32_too_big1.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(2147483648.0f32); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2.14748365E+9 which cannot be represented in target type `i32` +LL | float_to_int_unchecked::(2147483648.0f32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2.14748365E+9 which cannot be represented in target type `i32` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_32_too_big2.stderr b/tests/fail/intrinsics/float_to_int_32_too_big2.stderr index 2680d0c9908c..d7fbe5a34b52 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_big2.stderr +++ b/tests/fail/intrinsics/float_to_int_32_too_big2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 4.2949673E+9 which cannot be represented in target type `u32` --> $DIR/float_to_int_32_too_big2.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::((u32::MAX-127) as f32); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 4.2949673E+9 which cannot be represented in target type `u32` +LL | float_to_int_unchecked::((u32::MAX - 127) as f32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 4.2949673E+9 which cannot be represented in target type `u32` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_32_too_small1.stderr b/tests/fail/intrinsics/float_to_int_32_too_small1.stderr index b03bd380df47..2c225b85ec90 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_small1.stderr +++ b/tests/fail/intrinsics/float_to_int_32_too_small1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -2.1474839E+9 which cannot be represented in target type `i32` --> $DIR/float_to_int_32_too_small1.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(-2147483904.0f32); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2.1474839E+9 which cannot be represented in target type `i32` +LL | float_to_int_unchecked::(-2147483904.0f32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2.1474839E+9 which cannot be represented in target type `i32` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_inf1.stderr b/tests/fail/intrinsics/float_to_int_64_inf1.stderr index 7509844cfd41..7bb1f08afa87 100644 --- a/tests/fail/intrinsics/float_to_int_64_inf1.stderr +++ b/tests/fail/intrinsics/float_to_int_64_inf1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on +Inf which cannot be represented in target type `u128` --> $DIR/float_to_int_64_inf1.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(f64::INFINITY); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on +Inf which cannot be represented in target type `u128` +LL | float_to_int_unchecked::(f64::INFINITY); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on +Inf which cannot be represented in target type `u128` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_infneg1.stderr b/tests/fail/intrinsics/float_to_int_64_infneg1.stderr index 539cd52d83d0..eb96f6869a14 100644 --- a/tests/fail/intrinsics/float_to_int_64_infneg1.stderr +++ b/tests/fail/intrinsics/float_to_int_64_infneg1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `u128` --> $DIR/float_to_int_64_infneg1.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(f64::NEG_INFINITY); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `u128` +LL | float_to_int_unchecked::(f64::NEG_INFINITY); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `u128` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_infneg2.stderr b/tests/fail/intrinsics/float_to_int_64_infneg2.stderr index ceb18c3f4121..a2f847be9071 100644 --- a/tests/fail/intrinsics/float_to_int_64_infneg2.stderr +++ b/tests/fail/intrinsics/float_to_int_64_infneg2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `i128` --> $DIR/float_to_int_64_infneg2.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(f64::NEG_INFINITY); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `i128` +LL | float_to_int_unchecked::(f64::NEG_INFINITY); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `i128` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_nan.stderr b/tests/fail/intrinsics/float_to_int_64_nan.stderr index eee8d2fac0b3..8da854975820 100644 --- a/tests/fail/intrinsics/float_to_int_64_nan.stderr +++ b/tests/fail/intrinsics/float_to_int_64_nan.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` --> $DIR/float_to_int_64_nan.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(f64::NAN); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` +LL | float_to_int_unchecked::(f64::NAN); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_neg.stderr b/tests/fail/intrinsics/float_to_int_64_neg.stderr index 384c0232465a..35bb0aaa22cb 100644 --- a/tests/fail/intrinsics/float_to_int_64_neg.stderr +++ b/tests/fail/intrinsics/float_to_int_64_neg.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -1 which cannot be represented in target type `u128` --> $DIR/float_to_int_64_neg.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(-1.0000000000001f64); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1 which cannot be represented in target type `u128` +LL | float_to_int_unchecked::(-1.0000000000001f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1 which cannot be represented in target type `u128` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_too_big1.stderr b/tests/fail/intrinsics/float_to_int_64_too_big1.stderr index bb5b10a2710f..e031e00709e0 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big1.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 2147483648 which cannot be represented in target type `i32` --> $DIR/float_to_int_64_too_big1.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(2147483648.0f64); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2147483648 which cannot be represented in target type `i32` +LL | float_to_int_unchecked::(2147483648.0f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2147483648 which cannot be represented in target type `i32` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_too_big2.stderr b/tests/fail/intrinsics/float_to_int_64_too_big2.stderr index a4d57c2f5cee..8c4478603fbd 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big2.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 9.2233720368547758E+18 which cannot be represented in target type `i64` --> $DIR/float_to_int_64_too_big2.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(9223372036854775808.0f64); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 9.2233720368547758E+18 which cannot be represented in target type `i64` +LL | float_to_int_unchecked::(9223372036854775808.0f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 9.2233720368547758E+18 which cannot be represented in target type `i64` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_too_big3.stderr b/tests/fail/intrinsics/float_to_int_64_too_big3.stderr index 2b7379fcbd38..d7f97f37de59 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big3.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big3.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 1.8446744073709552E+19 which cannot be represented in target type `u64` --> $DIR/float_to_int_64_too_big3.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(18446744073709551616.0f64); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 1.8446744073709552E+19 which cannot be represented in target type `u64` +LL | float_to_int_unchecked::(18446744073709551616.0f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 1.8446744073709552E+19 which cannot be represented in target type `u64` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_too_big4.stderr b/tests/fail/intrinsics/float_to_int_64_too_big4.stderr index d30817607b9f..cfac443f4c9e 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big4.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big4.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 3.4028236692093846E+38 which cannot be represented in target type `u128` --> $DIR/float_to_int_64_too_big4.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(u128::MAX as f64); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 3.4028236692093846E+38 which cannot be represented in target type `u128` +LL | float_to_int_unchecked::(u128::MAX as f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 3.4028236692093846E+38 which cannot be represented in target type `u128` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_too_big5.stderr b/tests/fail/intrinsics/float_to_int_64_too_big5.stderr index f6b0c0a3527f..a0d501dad303 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big5.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big5.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 2.4028236692093845E+38 which cannot be represented in target type `i128` --> $DIR/float_to_int_64_too_big5.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(240282366920938463463374607431768211455.0f64); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2.4028236692093845E+38 which cannot be represented in target type `i128` +LL | float_to_int_unchecked::(240282366920938463463374607431768211455.0f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2.4028236692093845E+38 which cannot be represented in target type `i128` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_too_big6.stderr b/tests/fail/intrinsics/float_to_int_64_too_big6.stderr index e0eab8148b07..afb5d4ffe722 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big6.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big6.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 1.7976931348623157E+308 which cannot be represented in target type `u128` --> $DIR/float_to_int_64_too_big6.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(f64::MAX); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 1.7976931348623157E+308 which cannot be represented in target type `u128` +LL | float_to_int_unchecked::(f64::MAX); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 1.7976931348623157E+308 which cannot be represented in target type `u128` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_too_big7.stderr b/tests/fail/intrinsics/float_to_int_64_too_big7.stderr index a291b21c7aad..291acf529b4f 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big7.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big7.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -1.7976931348623157E+308 which cannot be represented in target type `i128` --> $DIR/float_to_int_64_too_big7.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(f64::MIN); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1.7976931348623157E+308 which cannot be represented in target type `i128` +LL | float_to_int_unchecked::(f64::MIN); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1.7976931348623157E+308 which cannot be represented in target type `i128` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_too_small1.stderr b/tests/fail/intrinsics/float_to_int_64_too_small1.stderr index 81ca218505dd..ceb625972690 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small1.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_small1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -2147483649 which cannot be represented in target type `i32` --> $DIR/float_to_int_64_too_small1.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(-2147483649.0f64); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2147483649 which cannot be represented in target type `i32` +LL | float_to_int_unchecked::(-2147483649.0f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2147483649 which cannot be represented in target type `i32` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_too_small2.stderr b/tests/fail/intrinsics/float_to_int_64_too_small2.stderr index 245f5cf0238c..f8255c2daca0 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small2.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_small2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -9.2233720368547778E+18 which cannot be represented in target type `i64` --> $DIR/float_to_int_64_too_small2.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(-9223372036854777856.0f64); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -9.2233720368547778E+18 which cannot be represented in target type `i64` +LL | float_to_int_unchecked::(-9223372036854777856.0f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -9.2233720368547778E+18 which cannot be represented in target type `i64` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_too_small3.stderr b/tests/fail/intrinsics/float_to_int_64_too_small3.stderr index f684ed2cde98..6bfb6f1f18d8 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small3.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_small3.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -2.4028236692093845E+38 which cannot be represented in target type `i128` --> $DIR/float_to_int_64_too_small3.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(-240282366920938463463374607431768211455.0f64); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2.4028236692093845E+38 which cannot be represented in target type `i128` +LL | float_to_int_unchecked::(-240282366920938463463374607431768211455.0f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2.4028236692093845E+38 which cannot be represented in target type `i128` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/unchecked_add1.stderr b/tests/fail/intrinsics/unchecked_add1.stderr index b967b46ac9ba..403bbbac5149 100644 --- a/tests/fail/intrinsics/unchecked_add1.stderr +++ b/tests/fail/intrinsics/unchecked_add1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow executing `unchecked_add` --> $DIR/unchecked_add1.rs:LL:CC | -LL | unsafe { std::intrinsics::unchecked_add(40000u16, 30000); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_add` +LL | std::intrinsics::unchecked_add(40000u16, 30000); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_add` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/unchecked_add2.stderr b/tests/fail/intrinsics/unchecked_add2.stderr index 18a116b7da96..4881fce719e7 100644 --- a/tests/fail/intrinsics/unchecked_add2.stderr +++ b/tests/fail/intrinsics/unchecked_add2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow executing `unchecked_add` --> $DIR/unchecked_add2.rs:LL:CC | -LL | unsafe { std::intrinsics::unchecked_add(-30000i16, -8000); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_add` +LL | std::intrinsics::unchecked_add(-30000i16, -8000); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_add` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/unchecked_div1.stderr b/tests/fail/intrinsics/unchecked_div1.stderr index f153e4efd984..4792608961d3 100644 --- a/tests/fail/intrinsics/unchecked_div1.stderr +++ b/tests/fail/intrinsics/unchecked_div1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow in signed division (dividing MIN by -1) --> $DIR/unchecked_div1.rs:LL:CC | -LL | unsafe { std::intrinsics::unchecked_div(i16::MIN, -1); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) +LL | std::intrinsics::unchecked_div(i16::MIN, -1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/unchecked_mul1.stderr b/tests/fail/intrinsics/unchecked_mul1.stderr index 5372ba9933a2..e94676fdfed7 100644 --- a/tests/fail/intrinsics/unchecked_mul1.stderr +++ b/tests/fail/intrinsics/unchecked_mul1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow executing `unchecked_mul` --> $DIR/unchecked_mul1.rs:LL:CC | -LL | unsafe { std::intrinsics::unchecked_mul(300u16, 250u16); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_mul` +LL | std::intrinsics::unchecked_mul(300u16, 250u16); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_mul` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/unchecked_mul2.stderr b/tests/fail/intrinsics/unchecked_mul2.stderr index 20a44d2422ae..493e04e46634 100644 --- a/tests/fail/intrinsics/unchecked_mul2.stderr +++ b/tests/fail/intrinsics/unchecked_mul2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow executing `unchecked_mul` --> $DIR/unchecked_mul2.rs:LL:CC | -LL | unsafe { std::intrinsics::unchecked_mul(1_000_000_000i32, -4); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_mul` +LL | std::intrinsics::unchecked_mul(1_000_000_000i32, -4); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_mul` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/unchecked_sub1.stderr b/tests/fail/intrinsics/unchecked_sub1.stderr index 12abfed8ff73..838005dc1e31 100644 --- a/tests/fail/intrinsics/unchecked_sub1.stderr +++ b/tests/fail/intrinsics/unchecked_sub1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow executing `unchecked_sub` --> $DIR/unchecked_sub1.rs:LL:CC | -LL | unsafe { std::intrinsics::unchecked_sub(14u32, 22); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_sub` +LL | std::intrinsics::unchecked_sub(14u32, 22); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_sub` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/unchecked_sub2.stderr b/tests/fail/intrinsics/unchecked_sub2.stderr index d62d2de2f930..dc4b17019879 100644 --- a/tests/fail/intrinsics/unchecked_sub2.stderr +++ b/tests/fail/intrinsics/unchecked_sub2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow executing `unchecked_sub` --> $DIR/unchecked_sub2.rs:LL:CC | -LL | unsafe { std::intrinsics::unchecked_sub(30000i16, -7000); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_sub` +LL | std::intrinsics::unchecked_sub(30000i16, -7000); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_sub` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/panic/unwind_panic_abort.stderr b/tests/fail/panic/unwind_panic_abort.stderr index 7ae965156f00..7094aebd6131 100644 --- a/tests/fail/panic/unwind_panic_abort.stderr +++ b/tests/fail/panic/unwind_panic_abort.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: unwinding past a stack frame that does not allow unwinding --> $DIR/unwind_panic_abort.rs:LL:CC | -LL | unsafe { miri_start_panic(&mut 0); } - | ^^^^^^^^^^^^^^^^^^^^^^^^ unwinding past a stack frame that does not allow unwinding +LL | miri_start_panic(&mut 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^ unwinding past a stack frame that does not allow unwinding | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/stacked_borrows/illegal_write1.stderr b/tests/fail/stacked_borrows/illegal_write1.stderr index 76639960a923..a70a45f2235a 100644 --- a/tests/fail/stacked_borrows/illegal_write1.stderr +++ b/tests/fail/stacked_borrows/illegal_write1.stderr @@ -17,8 +17,8 @@ LL | let xref = &*target; help: was later invalidated at offsets [0x0..0x4] --> $DIR/illegal_write1.rs:LL:CC | -LL | unsafe { *x = 42; } // invalidates shared ref, activates raw - | ^^^^^^^ +LL | *x = 42; // invalidates shared ref, activates raw + | ^^^^^^^ = note: inside `main` at $DIR/illegal_write1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write2.stderr b/tests/fail/stacked_borrows/illegal_write2.stderr index 3a225123d1f2..d2a06cc386a1 100644 --- a/tests/fail/stacked_borrows/illegal_write2.stderr +++ b/tests/fail/stacked_borrows/illegal_write2.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/illegal_write2.rs:LL:CC | -LL | unsafe { *target2 = 13; } - | ^^^^^^^^^^^^^ - | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | *target2 = 13; + | ^^^^^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/illegal_write3.stderr b/tests/fail/stacked_borrows/illegal_write3.stderr index 0dc948b29152..fc87557ea9b4 100644 --- a/tests/fail/stacked_borrows/illegal_write3.stderr +++ b/tests/fail/stacked_borrows/illegal_write3.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location --> $DIR/illegal_write3.rs:LL:CC | -LL | unsafe { *ptr = 42; } - | ^^^^^^^^^ - | | - | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | *ptr = 42; + | ^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/illegal_write6.stderr b/tests/fail/stacked_borrows/illegal_write6.stderr index a58abc8377a0..3a7fc0ef8116 100644 --- a/tests/fail/stacked_borrows/illegal_write6.stderr +++ b/tests/fail/stacked_borrows/illegal_write6.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] --> $DIR/illegal_write6.rs:LL:CC | -LL | unsafe { *y = 2; } - | ^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] +LL | *y = 2; + | ^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -22,7 +22,8 @@ help: this protector is live for this call LL | / fn foo(a: &mut u32, y: *mut u32) -> u32 { LL | | *a = 1; LL | | let _b = &*a; -LL | | unsafe { *y = 2; } +LL | | unsafe { +... | LL | | return *a; LL | | } | |_^ diff --git a/tests/fail/stacked_borrows/raw_tracking.stderr b/tests/fail/stacked_borrows/raw_tracking.stderr index 93ae613c3c6b..60a277ee057e 100644 --- a/tests/fail/stacked_borrows/raw_tracking.stderr +++ b/tests/fail/stacked_borrows/raw_tracking.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/raw_tracking.rs:LL:CC | -LL | unsafe { *raw1 = 13; } - | ^^^^^^^^^^ - | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | *raw1 = 13; + | ^^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/shr_frozen_violation1.stderr b/tests/fail/stacked_borrows/shr_frozen_violation1.stderr index a2487cca278c..0808d8471b45 100644 --- a/tests/fail/stacked_borrows/shr_frozen_violation1.stderr +++ b/tests/fail/stacked_borrows/shr_frozen_violation1.stderr @@ -1,25 +1,25 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location --> $DIR/shr_frozen_violation1.rs:LL:CC | -LL | unsafe { *(x as *const i32 as *mut i32) = 7; } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | *(x as *const i32 as *mut i32) = 7; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x4] --> $DIR/shr_frozen_violation1.rs:LL:CC | -LL | unsafe { *(x as *const i32 as *mut i32) = 7; } - | ^ +LL | *(x as *const i32 as *mut i32) = 7; + | ^ = note: inside `unknown_code` at $DIR/shr_frozen_violation1.rs:LL:CC note: inside `foo` at $DIR/shr_frozen_violation1.rs:LL:CC --> $DIR/shr_frozen_violation1.rs:LL:CC | -LL | unknown_code(&*x); - | ^^^^^^^^^^^^^^^^^ +LL | unknown_code(&*x); + | ^^^^^^^^^^^^^^^^^ note: inside `main` at $DIR/shr_frozen_violation1.rs:LL:CC --> $DIR/shr_frozen_violation1.rs:LL:CC | diff --git a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr index 75d74ce39346..c077e37844d1 100644 --- a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr +++ b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/transmute-is-no-escape.rs:LL:CC | -LL | unsafe { *raw = 13; } - | ^^^^^^^^^ - | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | *raw = 13; + | ^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/unescaped_local.stderr b/tests/fail/stacked_borrows/unescaped_local.stderr index 42a81245f2a8..616c60b8aa1b 100644 --- a/tests/fail/stacked_borrows/unescaped_local.stderr +++ b/tests/fail/stacked_borrows/unescaped_local.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/unescaped_local.rs:LL:CC | -LL | unsafe { *raw = 13; } - | ^^^^^^^^^ - | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | *raw = 13; + | ^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr b/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr index 8e0986c45335..fe63b05a5501 100644 --- a/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr +++ b/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required --> $DIR/intptrcast_alignment_check.rs:LL:CC | -LL | unsafe { *u16_ptr = 2; } - | ^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required +LL | *u16_ptr = 2; + | ^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required | = help: this usually indicates that your program performed an invalid operation and caused Undefined Behavior = help: but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives diff --git a/tests/fail/zst2.stderr b/tests/fail/zst2.stderr index 088bb2a1ccf0..0df2098d2e19 100644 --- a/tests/fail/zst2.stderr +++ b/tests/fail/zst2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed --> $DIR/zst2.rs:LL:CC | -LL | unsafe { *x = zst_val; } - | ^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed +LL | *x = zst_val; + | ^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/zst3.stderr b/tests/fail/zst3.stderr index a7d84dcaad59..dce0d7b3891c 100644 --- a/tests/fail/zst3.stderr +++ b/tests/fail/zst3.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 1, so pointer at offset 2 is out-of-bounds --> $DIR/zst3.rs:LL:CC | -LL | unsafe { *(x as *mut [u8; 0]) = zst_val; } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 1, so pointer at offset 2 is out-of-bounds +LL | *(x as *mut [u8; 0]) = zst_val; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 1, so pointer at offset 2 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information From 8d1b2ca3ec998fc8bdbfe03f5c8faf7cc138a9ed Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Jun 2022 09:45:02 -0700 Subject: [PATCH 3317/5092] check that tag_alloc_base_pointer is not called on the wrong things --- src/machine.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/machine.rs b/src/machine.rs index 824f0e3fc874..955677df6f07 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -662,6 +662,19 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer, ) -> Pointer { + if cfg!(debug_assertions) { + // The machine promises to never call us on thread-local or extern statics. + let alloc_id = ptr.provenance; + match ecx.tcx.get_global_alloc(alloc_id) { + Some(GlobalAlloc::Static(def_id)) if ecx.tcx.is_thread_local_static(def_id) => { + panic!("tag_alloc_base_pointer called on thread-local static") + } + Some(GlobalAlloc::Static(def_id)) if ecx.tcx.is_foreign_item(def_id) => { + panic!("tag_alloc_base_pointer called on extern static") + } + _ => {} + } + } let absolute_addr = intptrcast::GlobalStateInner::rel_ptr_to_addr(ecx, ptr); let sb_tag = if let Some(stacked_borrows) = &ecx.machine.stacked_borrows { stacked_borrows.borrow_mut().base_tag(ptr.provenance) From f992099820993005ec9ac9ddf6d6646b85c55311 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 19 Jun 2022 09:45:05 -0700 Subject: [PATCH 3318/5092] fix ICE when const refers to extern static --- src/machine.rs | 8 ++++---- src/thread.rs | 2 +- tests/fail/extern_static_in_const.rs | 11 +++++++++++ tests/fail/extern_static_in_const.stderr | 14 ++++++++++++++ 4 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 tests/fail/extern_static_in_const.rs create mode 100644 tests/fail/extern_static_in_const.stderr diff --git a/src/machine.rs b/src/machine.rs index 955677df6f07..d14ddaa1a6bb 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -618,7 +618,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { id: AllocId, alloc: Cow<'b, Allocation>, kind: Option>, - ) -> Cow<'b, Allocation> { + ) -> InterpResult<'tcx, Cow<'b, Allocation>> { if ecx.machine.tracked_alloc_ids.contains(&id) { register_diagnostic(NonHaltingDiagnostic::CreatedAlloc(id)); } @@ -653,9 +653,9 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { data_race: race_alloc, weak_memory: buffer_alloc, }, - |ptr| Evaluator::tag_alloc_base_pointer(ecx, ptr), - ); - Cow::Owned(alloc) + |ptr| ecx.global_base_pointer(ptr), + )?; + Ok(Cow::Owned(alloc)) } fn tag_alloc_base_pointer( diff --git a/src/thread.rs b/src/thread.rs index 9eabbd77419f..2135806de3ed 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -587,7 +587,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This allocation will be deallocated when the thread dies, so it is not in read-only memory. allocation.mutability = Mutability::Mut; // Create a fresh allocation with this content. - let new_alloc = this.allocate_raw_ptr(allocation, MiriMemoryKind::Tls.into()); + let new_alloc = this.allocate_raw_ptr(allocation, MiriMemoryKind::Tls.into())?; this.machine.threads.set_thread_local_alloc(def_id, new_alloc); Ok(new_alloc) } diff --git a/tests/fail/extern_static_in_const.rs b/tests/fail/extern_static_in_const.rs new file mode 100644 index 000000000000..4c1de6ace51d --- /dev/null +++ b/tests/fail/extern_static_in_const.rs @@ -0,0 +1,11 @@ +//! Even referencing an unknown `extern static` already triggers an error. + +extern "C" { + static E: [u8; 0]; +} + +static X: &'static [u8; 0] = unsafe { &E }; + +fn main() { + let _val = X; //~ ERROR is not supported by Miri +} diff --git a/tests/fail/extern_static_in_const.stderr b/tests/fail/extern_static_in_const.stderr new file mode 100644 index 000000000000..8524bb02c054 --- /dev/null +++ b/tests/fail/extern_static_in_const.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: `extern` static `E` from crate `extern_static_in_const` is not supported by Miri + --> $DIR/extern_static_in_const.rs:LL:CC + | +LL | let _val = X; + | ^ `extern` static `E` from crate `extern_static_in_const` is not supported by Miri + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/extern_static_in_const.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + From b29a706edd5e9b7d9f8bf0ba1beb2374326f8acf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 21 Jun 2022 21:03:52 -0700 Subject: [PATCH 3319/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 9782fbe6cd45..45773390616b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -cdcc53b7dc002ea4a7a28105010c5a1126ee31b7 +a09c668c965f735f4cd59e7158662b9daa0b71ba From 7308f8f3cfbdaf13613278140d256e85ecc1c84c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 21 Jun 2022 22:24:18 -0700 Subject: [PATCH 3320/5092] ui_test: fix behavior of only-Nbits comments --- ui_test/src/comments.rs | 29 ++++++++++++++++++++++++---- ui_test/src/lib.rs | 42 ++++++++++++++++++----------------------- 2 files changed, 43 insertions(+), 28 deletions(-) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index cc9870a63be4..d50d6a534573 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -15,9 +15,9 @@ pub(crate) struct Comments { /// List of revision names to execute. Can only be speicified once pub revisions: Option>, /// Don't run this test if any of these filters apply - pub ignore: Vec, + pub ignore: Vec, /// Only run this test if all of these filters apply - pub only: Vec, + pub only: Vec, /// Generate one .stderr file per bit width, by prepending with `.64bit` and similar pub stderr_per_bitwidth: bool, /// Additional flags to pass to the executable @@ -31,6 +31,16 @@ pub(crate) struct Comments { pub error_matches: Vec, } + +/// The conditions used for "ignore" and "only" filters. +#[derive(Debug)] +pub(crate) enum Condition { + /// The given string must appear in the target. + Target(String), + /// Tests that the bitwidth is the given one. + Bitwidth(u8), +} + #[derive(Debug)] pub(crate) struct ErrorMatch { pub matched: String, @@ -42,6 +52,17 @@ pub(crate) struct ErrorMatch { pub line: usize, } +impl Condition { + fn parse(c: &str) -> Self { + if let Some(bits) = c.strip_suffix("bit") { + let bits: u8 = bits.parse().expect("ignore/only filter ending in 'bit' must be of the form 'Nbit' for some integer N"); + Condition::Bitwidth(bits) + } else { + Condition::Target(c.to_owned()) + } + } +} + impl Comments { pub(crate) fn parse_file(path: &Path) -> Self { let content = std::fs::read_to_string(path).unwrap(); @@ -75,14 +96,14 @@ impl Comments { .split_once(|c: char| c == ':' || c.is_whitespace()) .map(|(s, _)| s) .unwrap_or(s); - this.ignore.push(s.to_owned()); + this.ignore.push(Condition::parse(s)); } if let Some(s) = line.strip_prefix("// only-") { let s = s .split_once(|c: char| c == ':' || c.is_whitespace()) .map(|(s, _)| s) .unwrap_or(s); - this.only.push(s.to_owned()); + this.only.push(Condition::parse(s)); } if line.starts_with("// stderr-per-bitwidth") { assert!( diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index d6938b19bfe4..970622144680 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -10,7 +10,7 @@ use comments::ErrorMatch; use regex::Regex; use rustc_stderr::{Level, Message}; -use crate::comments::Comments; +use crate::comments::{Comments, Condition}; mod comments; mod rustc_stderr; @@ -103,7 +103,7 @@ pub fn run_tests(config: Config) { } let comments = Comments::parse_file(&path); // Ignore file if only/ignore rules do (not) apply - if ignore_file(&comments, &target) { + if !test_file_conditions(&comments, &target) { ignored.fetch_add(1, Ordering::Relaxed); eprintln!( "{} ... {}", @@ -509,42 +509,36 @@ fn check_output( fn output_path(path: &Path, comments: &Comments, kind: String, target: &str) -> PathBuf { if comments.stderr_per_bitwidth { - return path.with_extension(format!("{}.{kind}", get_pointer_width(target))); + return path.with_extension(format!("{}bit.{kind}", get_pointer_width(target))); } path.with_extension(kind) } -fn ignore_file(comments: &Comments, target: &str) -> bool { - for s in &comments.ignore { - if target.contains(s) { - return true; - } - if get_pointer_width(target) == s { - return true; - } +fn test_condition(condition: &Condition, target: &str) -> bool { + match condition { + Condition::Bitwidth(bits) => get_pointer_width(target) == *bits, + Condition::Target(t) => target.contains(t), } - for s in &comments.only { - if !target.contains(s) { - return true; - } - /* FIXME(https://github.com/rust-lang/miri/issues/2206) - if get_pointer_width(target) != s { - return true; - } */ +} + +/// Returns whether according to the in-file conditions, this file should be run. +fn test_file_conditions(comments: &Comments, target: &str) -> bool { + if comments.ignore.iter().any(|c| test_condition(c, target)) { + return false; } - false + comments.only.iter().all(|c| test_condition(c, target)) } // Taken 1:1 from compiletest-rs -fn get_pointer_width(triple: &str) -> &'static str { +fn get_pointer_width(triple: &str) -> u8 { if (triple.contains("64") && !triple.ends_with("gnux32") && !triple.ends_with("gnu_ilp32")) || triple.starts_with("s390x") { - "64bit" + 64 } else if triple.starts_with("avr") { - "16bit" + 16 } else { - "32bit" + 32 } } From 7d09004aee288b3debfcfa734c77a4805ad76822 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 21 Jun 2022 22:56:50 -0700 Subject: [PATCH 3321/5092] Format tests with rustfmt (276-287 of 299) --- tests/fail/branchless-select-i128-pointer.rs | 6 +- tests/fail/data_race/dealloc_read_race1.rs | 10 +- tests/fail/data_race/dealloc_write_race1.rs | 6 +- .../fail/function_calls/check_callback_abi.rs | 3 +- .../exported_symbol_abi_mismatch.rs | 8 +- tests/fail/type-too-large.rs | 3 +- tests/fail/validity/invalid_char.rs | 9 +- tests/pass/0weak_memory_consistency.rs | 12 +- tests/pass/concurrency/linux-futex.rs | 195 +++++++++--------- tests/pass/deriving-associated-types.rs | 113 ++++------ tests/pass/heap_allocator.rs | 116 +++++++---- tests/pass/iter.rs | 9 +- 12 files changed, 255 insertions(+), 235 deletions(-) diff --git a/tests/fail/branchless-select-i128-pointer.rs b/tests/fail/branchless-select-i128-pointer.rs index 20fbcd1de78a..b0c9c0fd7282 100644 --- a/tests/fail/branchless-select-i128-pointer.rs +++ b/tests/fail/branchless-select-i128-pointer.rs @@ -11,8 +11,10 @@ fn main() { // This is branchless code to select one or the other pointer. // However, it drops provenance when transmuting to TwoPtrs, so this is UB. let val = unsafe { - transmute::<_, &str>( //~ERROR type validation failed: encountered a dangling reference - !mask & transmute::<_, TwoPtrs>("false !") | mask & transmute::<_, TwoPtrs>("true !"), + transmute::<_, &str>( + //~ERROR type validation failed: encountered a dangling reference + !mask & transmute::<_, TwoPtrs>("false !") + | mask & transmute::<_, TwoPtrs>("true !"), ) }; println!("{}", val); diff --git a/tests/fail/data_race/dealloc_read_race1.rs b/tests/fail/data_race/dealloc_read_race1.rs index 14b02e95cc23..38bbd81f1e2f 100644 --- a/tests/fail/data_race/dealloc_read_race1.rs +++ b/tests/fail/data_race/dealloc_read_race1.rs @@ -18,12 +18,14 @@ pub fn main() { let ptr = EvilSend(pointer); unsafe { - let j1 = spawn(move || { - *ptr.0 - }); + let j1 = spawn(move || *ptr.0); let j2 = spawn(move || { - __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()); //~ ERROR Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) + __rust_dealloc( + ptr.0 as *mut _, + std::mem::size_of::(), + std::mem::align_of::(), + ); //~ ERROR Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/fail/data_race/dealloc_write_race1.rs b/tests/fail/data_race/dealloc_write_race1.rs index edcdfffdb5f5..1cfaeb2cb25a 100644 --- a/tests/fail/data_race/dealloc_write_race1.rs +++ b/tests/fail/data_race/dealloc_write_race1.rs @@ -22,7 +22,11 @@ pub fn main() { }); let j2 = spawn(move || { - __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()); //~ ERROR Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) + __rust_dealloc( + ptr.0 as *mut _, + std::mem::size_of::(), + std::mem::align_of::(), + ); //~ ERROR Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/fail/function_calls/check_callback_abi.rs b/tests/fail/function_calls/check_callback_abi.rs index e36bfe1c5783..f76839c34f20 100644 --- a/tests/fail/function_calls/check_callback_abi.rs +++ b/tests/fail/function_calls/check_callback_abi.rs @@ -8,7 +8,8 @@ fn main() { unsafe { // Make sure we check the ABI when Miri itself invokes a function // as part of a shim implementation. - std::intrinsics::r#try( //~ ERROR calling a function with ABI C using caller ABI Rust + std::intrinsics::r#try( + //~ ERROR calling a function with ABI C using caller ABI Rust std::mem::transmute::(try_fn), std::ptr::null_mut(), |_, _| unreachable!(), diff --git a/tests/fail/function_calls/exported_symbol_abi_mismatch.rs b/tests/fail/function_calls/exported_symbol_abi_mismatch.rs index 7dbda584e8d4..7e8fb2cffecb 100644 --- a/tests/fail/function_calls/exported_symbol_abi_mismatch.rs +++ b/tests/fail/function_calls/exported_symbol_abi_mismatch.rs @@ -10,12 +10,16 @@ fn main() { } #[cfg(fn_ptr)] - unsafe { std::mem::transmute::(foo)() } + unsafe { + std::mem::transmute::(foo)() + } //[fn_ptr]~^ ERROR calling a function with calling convention Rust using calling convention C // `Instance` caching should not suppress ABI check. #[cfg(cache)] - unsafe { foo() } + unsafe { + foo() + } { #[cfg_attr(any(cache, fn_ptr), allow(clashing_extern_declarations))] diff --git a/tests/fail/type-too-large.rs b/tests/fail/type-too-large.rs index 2c4ff7013a46..d9e19ed81876 100644 --- a/tests/fail/type-too-large.rs +++ b/tests/fail/type-too-large.rs @@ -1,6 +1,5 @@ // ignore-32bit fn main() { - let _fat: [u8; (1<<61)+(1<<31)] = - [0; (1u64<<61) as usize +(1u64<<31) as usize]; //~ ERROR post-monomorphization error + let _fat: [u8; (1 << 61) + (1 << 31)] = [0; (1u64 << 61) as usize + (1u64 << 31) as usize]; //~ ERROR post-monomorphization error } diff --git a/tests/fail/validity/invalid_char.rs b/tests/fail/validity/invalid_char.rs index 079823f894a8..a868dac8875d 100644 --- a/tests/fail/validity/invalid_char.rs +++ b/tests/fail/validity/invalid_char.rs @@ -1,8 +1,9 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); - let _val = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered 0xffffffff, but expected a valid unicode scalar value - 'a' => {true}, - 'b' => {false}, - _ => {true}, + let _val = match unsafe { std::mem::transmute::(-1) } { + //~ ERROR encountered 0xffffffff, but expected a valid unicode scalar value + 'a' => true, + 'b' => false, + _ => true, }; } diff --git a/tests/pass/0weak_memory_consistency.rs b/tests/pass/0weak_memory_consistency.rs index fc9dce0c986a..ae8d281858c2 100644 --- a/tests/pass/0weak_memory_consistency.rs +++ b/tests/pass/0weak_memory_consistency.rs @@ -60,7 +60,8 @@ fn test_corr() { r2 // | | }); // | | // |synchronizes-with |happens-before - let j3 = spawn(move || { // | | + let j3 = spawn(move || { + // | | acquires_value(&y, 1); // <------------------+ | x.load(Relaxed) // <----------------------------------------------+ // The two reads on x are ordered by hb, so they cannot observe values @@ -84,12 +85,14 @@ fn test_wrc() { x.store(1, Release); // ---------------------+---------------------+ }); // | | // |synchronizes-with | - let j2 = spawn(move || { // | | + let j2 = spawn(move || { + // | | acquires_value(&x, 1); // <------------------+ | y.store(1, Release); // ---------------------+ |happens-before }); // | | // |synchronizes-with | - let j3 = spawn(move || { // | | + let j3 = spawn(move || { + // | | acquires_value(&y, 1); // <------------------+ | x.load(Relaxed) // <-----------------------------------------------+ }); @@ -112,7 +115,8 @@ fn test_message_passing() { y.store(1, Release); // ---------------------+ | }); // | | // |synchronizes-with | happens-before - let j2 = spawn(move || { // | | + let j2 = spawn(move || { + // | | acquires_value(&y, 1); // <------------------+ | unsafe { *x.0 } // <---------------------------------------------+ }); diff --git a/tests/pass/concurrency/linux-futex.rs b/tests/pass/concurrency/linux-futex.rs index 0d30ddff4809..74fec411b4c9 100644 --- a/tests/pass/concurrency/linux-futex.rs +++ b/tests/pass/concurrency/linux-futex.rs @@ -16,25 +16,23 @@ fn wake_nobody() { // Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting. unsafe { - assert_eq!(libc::syscall( - libc::SYS_futex, - &futex as *const i32, - libc::FUTEX_WAKE, - 1, - ), 0); + assert_eq!(libc::syscall(libc::SYS_futex, &futex as *const i32, libc::FUTEX_WAKE, 1,), 0); } // Same, but without omitting the unused arguments. unsafe { - assert_eq!(libc::syscall( - libc::SYS_futex, - &futex as *const i32, - libc::FUTEX_WAKE, - 1, - ptr::null::(), - 0usize, - 0, - ), 0); + assert_eq!( + libc::syscall( + libc::SYS_futex, + &futex as *const i32, + libc::FUTEX_WAKE, + 1, + ptr::null::(), + 0usize, + 0, + ), + 0 + ); } } @@ -45,12 +43,7 @@ fn wake_dangling() { // Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting. unsafe { - assert_eq!(libc::syscall( - libc::SYS_futex, - ptr, - libc::FUTEX_WAKE, - 1, - ), 0); + assert_eq!(libc::syscall(libc::SYS_futex, ptr, libc::FUTEX_WAKE, 1,), 0); } } @@ -59,13 +52,16 @@ fn wait_wrong_val() { // Only wait if the futex value is 456. unsafe { - assert_eq!(libc::syscall( - libc::SYS_futex, - &futex as *const i32, - libc::FUTEX_WAIT, - 456, - ptr::null::(), - ), -1); + assert_eq!( + libc::syscall( + libc::SYS_futex, + &futex as *const i32, + libc::FUTEX_WAIT, + 456, + ptr::null::(), + ), + -1 + ); assert_eq!(*libc::__errno_location(), libc::EAGAIN); } } @@ -77,16 +73,16 @@ fn wait_timeout() { // Wait for 200ms, with nobody waking us up early. unsafe { - assert_eq!(libc::syscall( - libc::SYS_futex, - &futex as *const i32, - libc::FUTEX_WAIT, - 123, - &libc::timespec { - tv_sec: 0, - tv_nsec: 200_000_000, - }, - ), -1); + assert_eq!( + libc::syscall( + libc::SYS_futex, + &futex as *const i32, + libc::FUTEX_WAIT, + 123, + &libc::timespec { tv_sec: 0, tv_nsec: 200_000_000 }, + ), + -1 + ); assert_eq!(*libc::__errno_location(), libc::ETIMEDOUT); } @@ -114,15 +110,18 @@ fn wait_absolute_timeout() { // Wait for 200ms from now, with nobody waking us up early. unsafe { - assert_eq!(libc::syscall( - libc::SYS_futex, - &futex as *const i32, - libc::FUTEX_WAIT_BITSET, - 123, - &timeout, - 0usize, - u32::MAX, - ), -1); + assert_eq!( + libc::syscall( + libc::SYS_futex, + &futex as *const i32, + libc::FUTEX_WAIT_BITSET, + 123, + &timeout, + 0usize, + u32::MAX, + ), + -1 + ); assert_eq!(*libc::__errno_location(), libc::ETIMEDOUT); } @@ -137,23 +136,29 @@ fn wait_wake() { let t = thread::spawn(move || { thread::sleep(Duration::from_millis(200)); unsafe { - assert_eq!(libc::syscall( - libc::SYS_futex, - &FUTEX as *const i32, - libc::FUTEX_WAKE, - 10, // Wake up at most 10 threads. - ), 1); // Woken up one thread. + assert_eq!( + libc::syscall( + libc::SYS_futex, + &FUTEX as *const i32, + libc::FUTEX_WAKE, + 10, // Wake up at most 10 threads. + ), + 1 + ); // Woken up one thread. } }); unsafe { - assert_eq!(libc::syscall( - libc::SYS_futex, - &FUTEX as *const i32, - libc::FUTEX_WAIT, - 0, - ptr::null::(), - ), 0); + assert_eq!( + libc::syscall( + libc::SYS_futex, + &FUTEX as *const i32, + libc::FUTEX_WAIT, + 0, + ptr::null::(), + ), + 0 + ); } assert!((200..1000).contains(&start.elapsed().as_millis())); @@ -168,40 +173,49 @@ fn wait_wake_bitset() { let t = thread::spawn(move || { thread::sleep(Duration::from_millis(200)); unsafe { - assert_eq!(libc::syscall( - libc::SYS_futex, - &FUTEX as *const i32, - libc::FUTEX_WAKE_BITSET, - 10, // Wake up at most 10 threads. - ptr::null::(), - 0usize, - 0b1001, // bitset - ), 0); // Didn't match any thread. + assert_eq!( + libc::syscall( + libc::SYS_futex, + &FUTEX as *const i32, + libc::FUTEX_WAKE_BITSET, + 10, // Wake up at most 10 threads. + ptr::null::(), + 0usize, + 0b1001, // bitset + ), + 0 + ); // Didn't match any thread. } thread::sleep(Duration::from_millis(200)); unsafe { - assert_eq!(libc::syscall( - libc::SYS_futex, - &FUTEX as *const i32, - libc::FUTEX_WAKE_BITSET, - 10, // Wake up at most 10 threads. - ptr::null::(), - 0usize, - 0b0110, // bitset - ), 1); // Woken up one thread. + assert_eq!( + libc::syscall( + libc::SYS_futex, + &FUTEX as *const i32, + libc::FUTEX_WAKE_BITSET, + 10, // Wake up at most 10 threads. + ptr::null::(), + 0usize, + 0b0110, // bitset + ), + 1 + ); // Woken up one thread. } }); unsafe { - assert_eq!(libc::syscall( - libc::SYS_futex, - &FUTEX as *const i32, - libc::FUTEX_WAIT_BITSET, - 0, - ptr::null::(), - 0usize, - 0b0100, // bitset - ), 0); + assert_eq!( + libc::syscall( + libc::SYS_futex, + &FUTEX as *const i32, + libc::FUTEX_WAIT_BITSET, + 0, + ptr::null::(), + 0usize, + 0b0100, // bitset + ), + 0 + ); } assert!((400..1000).contains(&start.elapsed().as_millis())); @@ -237,12 +251,7 @@ fn concurrent_wait_wake() { FUTEX.store(FREE, Ordering::Relaxed); unsafe { - libc::syscall( - libc::SYS_futex, - &FUTEX as *const AtomicI32, - libc::FUTEX_WAKE, - 1, - ); + libc::syscall(libc::SYS_futex, &FUTEX as *const AtomicI32, libc::FUTEX_WAKE, 1); } t.join().unwrap(); diff --git a/tests/pass/deriving-associated-types.rs b/tests/pass/deriving-associated-types.rs index 52104d8486b0..4803792a97ce 100644 --- a/tests/pass/deriving-associated-types.rs +++ b/tests/pass/deriving-associated-types.rs @@ -40,10 +40,15 @@ struct TupleStruct( ::Type, Option<::Type>, ::Type, -) where C: WhereTrait; +) +where + C: WhereTrait; #[derive(PartialEq, Debug)] -pub struct Struct where C: WhereTrait { +pub struct Struct +where + C: WhereTrait, +{ m1: module::Type, m2: Option, a1: A, @@ -62,7 +67,10 @@ pub struct Struct where C: WhereTrait { } #[derive(PartialEq, Debug)] -enum Enum where C: WhereTrait { +enum Enum +where + C: WhereTrait, +{ Unit, Seq( module::Type, @@ -101,35 +109,11 @@ enum Enum where C: WhereTrait { } fn main() { - - let e: Enum< - i32, - i32, - i32, - > = Enum::Seq( - 0, - None, - 0, - PrivateStruct(0), - 0, - 0, - None, - 0, - None, - 0, - 0, - None, - 0, - None, - 0, - ); + let e: Enum = + Enum::Seq(0, None, 0, PrivateStruct(0), 0, 0, None, 0, None, 0, 0, None, 0, None, 0); assert_eq!(e, e); - let e: Enum< - i32, - i32, - i32, - > = Enum::Map { + let e: Enum = Enum::Map { m1: 0, m2: None, a1: 0, @@ -147,52 +131,29 @@ fn main() { d: 0, }; assert_eq!(e, e); - let e: TupleStruct< - i32, - i32, - i32, - > = TupleStruct( - 0, - None, - 0, - PrivateStruct(0), - 0, - 0, - None, - 0, - None, - 0, - 0, - None, - 0, - None, - 0, - ); - assert_eq!(e, e); + let e: TupleStruct = + TupleStruct(0, None, 0, PrivateStruct(0), 0, 0, None, 0, None, 0, 0, None, 0, None, 0); + assert_eq!(e, e); - let e: Struct< - i32, - i32, - i32, - > = Struct { - m1: 0, - m2: None, - a1: 0, - a2: PrivateStruct(0), - b: 0, - b1: 0, - b2: None, - b3: 0, - b4: None, - c: 0, - c1: 0, - c2: None, - c3: 0, - c4: None, - d: 0, - }; - assert_eq!(e, e); + let e: Struct = Struct { + m1: 0, + m2: None, + a1: 0, + a2: PrivateStruct(0), + b: 0, + b1: 0, + b2: None, + b3: 0, + b4: None, + c: 0, + c1: 0, + c2: None, + c3: 0, + c4: None, + d: 0, + }; + assert_eq!(e, e); - let e = Enum::Unit::; - assert_eq!(e, e); + let e = Enum::Unit::; + assert_eq!(e, e); } diff --git a/tests/pass/heap_allocator.rs b/tests/pass/heap_allocator.rs index e428868af78b..a3ab5b21f0b3 100644 --- a/tests/pass/heap_allocator.rs +++ b/tests/pass/heap_allocator.rs @@ -1,58 +1,90 @@ #![feature(allocator_api, slice_ptr_get)] +use std::alloc::{Allocator, Global, Layout, System}; use std::ptr::NonNull; -use std::alloc::{Global, Allocator, Layout, System}; use std::slice; -fn check_alloc(allocator: T) { unsafe { - for &align in &[4, 8, 16, 32] { - let layout_20 = Layout::from_size_align(20, align).unwrap(); - let layout_40 = Layout::from_size_align(40, 4*align).unwrap(); - let layout_10 = Layout::from_size_align(10, align/2).unwrap(); +fn check_alloc(allocator: T) { + unsafe { + for &align in &[4, 8, 16, 32] { + let layout_20 = Layout::from_size_align(20, align).unwrap(); + let layout_40 = Layout::from_size_align(40, 4 * align).unwrap(); + let layout_10 = Layout::from_size_align(10, align / 2).unwrap(); - for _ in 0..32 { - let a = allocator.allocate(layout_20).unwrap().as_non_null_ptr(); - assert_eq!(a.as_ptr() as usize % layout_20.align(), 0, "pointer is incorrectly aligned"); - allocator.deallocate(a, layout_20); + for _ in 0..32 { + let a = allocator.allocate(layout_20).unwrap().as_non_null_ptr(); + assert_eq!( + a.as_ptr() as usize % layout_20.align(), + 0, + "pointer is incorrectly aligned" + ); + allocator.deallocate(a, layout_20); + } + + let p1 = allocator.allocate_zeroed(layout_20).unwrap().as_non_null_ptr(); + assert_eq!( + p1.as_ptr() as usize % layout_20.align(), + 0, + "pointer is incorrectly aligned" + ); + assert_eq!(*p1.as_ptr(), 0); + + // old size < new size + let p2 = allocator.grow(p1, layout_20, layout_40).unwrap().as_non_null_ptr(); + assert_eq!( + p2.as_ptr() as usize % layout_40.align(), + 0, + "pointer is incorrectly aligned" + ); + let slice = slice::from_raw_parts(p2.as_ptr(), 20); + assert_eq!(&slice, &[0_u8; 20]); + + // old size == new size + let p3 = allocator.grow(p2, layout_40, layout_40).unwrap().as_non_null_ptr(); + assert_eq!( + p3.as_ptr() as usize % layout_40.align(), + 0, + "pointer is incorrectly aligned" + ); + let slice = slice::from_raw_parts(p3.as_ptr(), 20); + assert_eq!(&slice, &[0_u8; 20]); + + // old size > new size + let p4 = allocator.shrink(p3, layout_40, layout_10).unwrap().as_non_null_ptr(); + assert_eq!( + p4.as_ptr() as usize % layout_10.align(), + 0, + "pointer is incorrectly aligned" + ); + let slice = slice::from_raw_parts(p4.as_ptr(), 10); + assert_eq!(&slice, &[0_u8; 10]); + + allocator.deallocate(p4, layout_10); } - - let p1 = allocator.allocate_zeroed(layout_20).unwrap().as_non_null_ptr(); - assert_eq!(p1.as_ptr() as usize % layout_20.align(), 0, "pointer is incorrectly aligned"); - assert_eq!(*p1.as_ptr(), 0); - - // old size < new size - let p2 = allocator.grow(p1, layout_20, layout_40).unwrap().as_non_null_ptr(); - assert_eq!(p2.as_ptr() as usize % layout_40.align(), 0, "pointer is incorrectly aligned"); - let slice = slice::from_raw_parts(p2.as_ptr(), 20); - assert_eq!(&slice, &[0_u8; 20]); - - // old size == new size - let p3 = allocator.grow(p2, layout_40, layout_40).unwrap().as_non_null_ptr(); - assert_eq!(p3.as_ptr() as usize % layout_40.align(), 0, "pointer is incorrectly aligned"); - let slice = slice::from_raw_parts(p3.as_ptr(), 20); - assert_eq!(&slice, &[0_u8; 20]); - - // old size > new size - let p4 = allocator.shrink(p3, layout_40, layout_10).unwrap().as_non_null_ptr(); - assert_eq!(p4.as_ptr() as usize % layout_10.align(), 0, "pointer is incorrectly aligned"); - let slice = slice::from_raw_parts(p4.as_ptr(), 10); - assert_eq!(&slice, &[0_u8; 10]); - - allocator.deallocate(p4, layout_10); } -} } +} fn check_align_requests(allocator: T) { - for &size in &[2, 8, 64] { // size less than and bigger than alignment - for &align in &[4, 8, 16, 32] { // Be sure to cover less than and bigger than `MIN_ALIGN` for all architectures + for &size in &[2, 8, 64] { + // size less than and bigger than alignment + for &align in &[4, 8, 16, 32] { + // Be sure to cover less than and bigger than `MIN_ALIGN` for all architectures let iterations = 32; unsafe { - let pointers: Vec<_> = (0..iterations).map(|_| { - allocator.allocate(Layout::from_size_align(size, align).unwrap()).unwrap().as_non_null_ptr() - }).collect(); + let pointers: Vec<_> = (0..iterations) + .map(|_| { + allocator + .allocate(Layout::from_size_align(size, align).unwrap()) + .unwrap() + .as_non_null_ptr() + }) + .collect(); for &ptr in &pointers { - assert_eq!((ptr.as_ptr() as usize) % align, 0, - "Got a pointer less aligned than requested") + assert_eq!( + (ptr.as_ptr() as usize) % align, + 0, + "Got a pointer less aligned than requested" + ) } // Clean up. diff --git a/tests/pass/iter.rs b/tests/pass/iter.rs index 6192dd0d37e8..8ee03d112641 100644 --- a/tests/pass/iter.rs +++ b/tests/pass/iter.rs @@ -1,5 +1,6 @@ fn iter_empty_and_zst() { - for _ in Vec::::new().iter() { // this iterates over a Unique::empty() + for _ in Vec::::new().iter() { + // this iterates over a Unique::empty() panic!("We should never be here."); } @@ -21,13 +22,13 @@ fn test_iterator_step_by_nth() { } fn iter_any() { - let f = |x: &u8| { 10u8 == *x }; + let f = |x: &u8| 10u8 == *x; f(&1u8); - let g = |(), x: &u8| { 10u8 == *x }; + let g = |(), x: &u8| 10u8 == *x; g((), &1u8); - let h = |(), (), x: &u8| { 10u8 == *x }; + let h = |(), (), x: &u8| 10u8 == *x; h((), (), &1u8); [1, 2, 3u8].iter().any(|elt| 10 == *elt); From ba23d37b70253be905349aaeb0781eb6eba05333 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 21 Jun 2022 22:57:06 -0700 Subject: [PATCH 3322/5092] Format tests with rustfmt (288-299 of 299) --- .../fail/unaligned_pointers/dyn_alignment.rs | 7 +- .../unaligned_pointers/reference_to_packed.rs | 8 +- .../fail/unaligned_pointers/unaligned_ptr1.rs | 3 +- .../fail/unaligned_pointers/unaligned_ptr3.rs | 3 +- .../fail/unaligned_pointers/unaligned_ptr4.rs | 3 +- .../unaligned_ptr_addr_of.rs | 3 +- .../unaligned_pointers/unaligned_ptr_zst.rs | 3 +- tests/pass/intrinsics-integer.rs | 276 ++++++++++++------ tests/pass/panic/catch_panic.rs | 39 ++- tests/pass/ptr_int_casts.rs | 22 +- .../regions-lifetime-nonfree-late-bound.rs | 14 +- tests/pass/sums.rs | 9 +- 12 files changed, 252 insertions(+), 138 deletions(-) diff --git a/tests/fail/unaligned_pointers/dyn_alignment.rs b/tests/fail/unaligned_pointers/dyn_alignment.rs index 91d9ec475b1f..39dd6f9e4c07 100644 --- a/tests/fail/unaligned_pointers/dyn_alignment.rs +++ b/tests/fail/unaligned_pointers/dyn_alignment.rs @@ -6,7 +6,8 @@ struct MuchAlign; fn main() { - for _ in 0..10 { // Try many times as this might work by chance. + for _ in 0..10 { + // Try many times as this might work by chance. let buf = [0u32; 256]; // `buf` is sufficiently aligned for `layout.align` on a `dyn Debug`, but not // for the actual alignment required by `MuchAlign`. @@ -14,7 +15,9 @@ fn main() { // as the reference is not aligned to its dynamic alignment requirements. let mut ptr = &MuchAlign as &dyn std::fmt::Debug; // Overwrite the data part of `ptr` so it points to `buf`. - unsafe { (&mut ptr as *mut _ as *mut *const u8).write(&buf as *const _ as *const u8); } + unsafe { + (&mut ptr as *mut _ as *mut *const u8).write(&buf as *const _ as *const u8); + } // Re-borrow that. This should be UB. let _ptr = &*ptr; //~ERROR alignment 256 is required } diff --git a/tests/fail/unaligned_pointers/reference_to_packed.rs b/tests/fail/unaligned_pointers/reference_to_packed.rs index b376859d22c1..74b2f308e230 100644 --- a/tests/fail/unaligned_pointers/reference_to_packed.rs +++ b/tests/fail/unaligned_pointers/reference_to_packed.rs @@ -10,11 +10,9 @@ struct Foo { } fn main() { - for _ in 0..10 { // Try many times as this might work by chance. - let foo = Foo { - x: 42, - y: 99, - }; + for _ in 0..10 { + // Try many times as this might work by chance. + let foo = Foo { x: 42, y: 99 }; let p = &foo.x; let i = *p; //~ERROR alignment 4 is required } diff --git a/tests/fail/unaligned_pointers/unaligned_ptr1.rs b/tests/fail/unaligned_pointers/unaligned_ptr1.rs index 1d72e5170b7c..445eb051ae2d 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr1.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr1.rs @@ -2,7 +2,8 @@ // compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { - for _ in 0..10 { // Try many times as this might work by chance. + for _ in 0..10 { + // Try many times as this might work by chance. let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. diff --git a/tests/fail/unaligned_pointers/unaligned_ptr3.rs b/tests/fail/unaligned_pointers/unaligned_ptr3.rs index ecab83b05a09..f13ae4888675 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr3.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr3.rs @@ -2,7 +2,8 @@ // compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { - for _ in 0..10 { // Try many times as this might work by chance. + for _ in 0..10 { + // Try many times as this might work by chance. let x = [2u16, 3, 4, 5]; // Make it big enough so we don't get an out-of-bounds error. let x = &x[0] as *const _ as *const *const u8; // cast to ptr-to-ptr, so that we load a ptr // This must fail because alignment is violated. Test specifically for loading pointers, diff --git a/tests/fail/unaligned_pointers/unaligned_ptr4.rs b/tests/fail/unaligned_pointers/unaligned_ptr4.rs index 10766746bd42..18ae48b0a1e5 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr4.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr4.rs @@ -4,7 +4,8 @@ fn main() { // Make sure we notice when a u16 is loaded at offset 1 into a u8 allocation. // (This would be missed if u8 allocations are *always* at odd addresses.) - for _ in 0..10 { // Try many times as this might work by chance. + for _ in 0..10 { + // Try many times as this might work by chance. let x = [0u8; 4]; let ptr = x.as_ptr().wrapping_offset(1).cast::(); let _val = unsafe { *ptr }; //~ERROR but alignment diff --git a/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs b/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs index e33f3c8598f3..0604a7eb2d2b 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs @@ -3,7 +3,8 @@ use std::ptr; fn main() { - for _ in 0..10 { // Try many times as this might work by chance. + for _ in 0..10 { + // Try many times as this might work by chance. let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. diff --git a/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs b/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs index 27403c11abc7..983939688f1b 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs @@ -3,7 +3,8 @@ // compile-flags: -Zmir-opt-level=0 -Zmiri-disable-validation fn main() { - for i in 0..10 { // Try many times as this might work by chance. + for i in 0..10 { + // Try many times as this might work by chance. let x = i as u8; let x = &x as *const _ as *const [u32; 0]; // This must fail because alignment is violated. Test specifically for loading ZST. diff --git a/tests/pass/intrinsics-integer.rs b/tests/pass/intrinsics-integer.rs index af3517af6f7a..e8a3056f2c34 100644 --- a/tests/pass/intrinsics-integer.rs +++ b/tests/pass/intrinsics-integer.rs @@ -13,110 +13,194 @@ use std::intrinsics::*; pub fn main() { unsafe { - assert_eq!(ctpop(0u8), 0); assert_eq!(ctpop(0i8), 0); - assert_eq!(ctpop(0u16), 0); assert_eq!(ctpop(0i16), 0); - assert_eq!(ctpop(0u32), 0); assert_eq!(ctpop(0i32), 0); - assert_eq!(ctpop(0u64), 0); assert_eq!(ctpop(0i64), 0); + assert_eq!(ctpop(0u8), 0); + assert_eq!(ctpop(0i8), 0); + assert_eq!(ctpop(0u16), 0); + assert_eq!(ctpop(0i16), 0); + assert_eq!(ctpop(0u32), 0); + assert_eq!(ctpop(0i32), 0); + assert_eq!(ctpop(0u64), 0); + assert_eq!(ctpop(0i64), 0); - assert_eq!(ctpop(1u8), 1); assert_eq!(ctpop(1i8), 1); - assert_eq!(ctpop(1u16), 1); assert_eq!(ctpop(1i16), 1); - assert_eq!(ctpop(1u32), 1); assert_eq!(ctpop(1i32), 1); - assert_eq!(ctpop(1u64), 1); assert_eq!(ctpop(1i64), 1); + assert_eq!(ctpop(1u8), 1); + assert_eq!(ctpop(1i8), 1); + assert_eq!(ctpop(1u16), 1); + assert_eq!(ctpop(1i16), 1); + assert_eq!(ctpop(1u32), 1); + assert_eq!(ctpop(1i32), 1); + assert_eq!(ctpop(1u64), 1); + assert_eq!(ctpop(1i64), 1); - assert_eq!(ctpop(10u8), 2); assert_eq!(ctpop(10i8), 2); - assert_eq!(ctpop(10u16), 2); assert_eq!(ctpop(10i16), 2); - assert_eq!(ctpop(10u32), 2); assert_eq!(ctpop(10i32), 2); - assert_eq!(ctpop(10u64), 2); assert_eq!(ctpop(10i64), 2); + assert_eq!(ctpop(10u8), 2); + assert_eq!(ctpop(10i8), 2); + assert_eq!(ctpop(10u16), 2); + assert_eq!(ctpop(10i16), 2); + assert_eq!(ctpop(10u32), 2); + assert_eq!(ctpop(10i32), 2); + assert_eq!(ctpop(10u64), 2); + assert_eq!(ctpop(10i64), 2); - assert_eq!(ctpop(100u8), 3); assert_eq!(ctpop(100i8), 3); - assert_eq!(ctpop(100u16), 3); assert_eq!(ctpop(100i16), 3); - assert_eq!(ctpop(100u32), 3); assert_eq!(ctpop(100i32), 3); - assert_eq!(ctpop(100u64), 3); assert_eq!(ctpop(100i64), 3); + assert_eq!(ctpop(100u8), 3); + assert_eq!(ctpop(100i8), 3); + assert_eq!(ctpop(100u16), 3); + assert_eq!(ctpop(100i16), 3); + assert_eq!(ctpop(100u32), 3); + assert_eq!(ctpop(100i32), 3); + assert_eq!(ctpop(100u64), 3); + assert_eq!(ctpop(100i64), 3); - assert_eq!(ctpop(-1i8 as u8), 8); assert_eq!(ctpop(-1i8), 8); - assert_eq!(ctpop(-1i16 as u16), 16); assert_eq!(ctpop(-1i16), 16); - assert_eq!(ctpop(-1i32 as u32), 32); assert_eq!(ctpop(-1i32), 32); - assert_eq!(ctpop(-1i64 as u64), 64); assert_eq!(ctpop(-1i64), 64); + assert_eq!(ctpop(-1i8 as u8), 8); + assert_eq!(ctpop(-1i8), 8); + assert_eq!(ctpop(-1i16 as u16), 16); + assert_eq!(ctpop(-1i16), 16); + assert_eq!(ctpop(-1i32 as u32), 32); + assert_eq!(ctpop(-1i32), 32); + assert_eq!(ctpop(-1i64 as u64), 64); + assert_eq!(ctpop(-1i64), 64); - assert_eq!(ctlz(0u8), 8); assert_eq!(ctlz(0i8), 8); - assert_eq!(ctlz(0u16), 16); assert_eq!(ctlz(0i16), 16); - assert_eq!(ctlz(0u32), 32); assert_eq!(ctlz(0i32), 32); - assert_eq!(ctlz(0u64), 64); assert_eq!(ctlz(0i64), 64); + assert_eq!(ctlz(0u8), 8); + assert_eq!(ctlz(0i8), 8); + assert_eq!(ctlz(0u16), 16); + assert_eq!(ctlz(0i16), 16); + assert_eq!(ctlz(0u32), 32); + assert_eq!(ctlz(0i32), 32); + assert_eq!(ctlz(0u64), 64); + assert_eq!(ctlz(0i64), 64); - assert_eq!(ctlz(1u8), 7); assert_eq!(ctlz(1i8), 7); - assert_eq!(ctlz(1u16), 15); assert_eq!(ctlz(1i16), 15); - assert_eq!(ctlz(1u32), 31); assert_eq!(ctlz(1i32), 31); - assert_eq!(ctlz(1u64), 63); assert_eq!(ctlz(1i64), 63); + assert_eq!(ctlz(1u8), 7); + assert_eq!(ctlz(1i8), 7); + assert_eq!(ctlz(1u16), 15); + assert_eq!(ctlz(1i16), 15); + assert_eq!(ctlz(1u32), 31); + assert_eq!(ctlz(1i32), 31); + assert_eq!(ctlz(1u64), 63); + assert_eq!(ctlz(1i64), 63); - assert_eq!(ctlz(10u8), 4); assert_eq!(ctlz(10i8), 4); - assert_eq!(ctlz(10u16), 12); assert_eq!(ctlz(10i16), 12); - assert_eq!(ctlz(10u32), 28); assert_eq!(ctlz(10i32), 28); - assert_eq!(ctlz(10u64), 60); assert_eq!(ctlz(10i64), 60); + assert_eq!(ctlz(10u8), 4); + assert_eq!(ctlz(10i8), 4); + assert_eq!(ctlz(10u16), 12); + assert_eq!(ctlz(10i16), 12); + assert_eq!(ctlz(10u32), 28); + assert_eq!(ctlz(10i32), 28); + assert_eq!(ctlz(10u64), 60); + assert_eq!(ctlz(10i64), 60); - assert_eq!(ctlz(100u8), 1); assert_eq!(ctlz(100i8), 1); - assert_eq!(ctlz(100u16), 9); assert_eq!(ctlz(100i16), 9); - assert_eq!(ctlz(100u32), 25); assert_eq!(ctlz(100i32), 25); - assert_eq!(ctlz(100u64), 57); assert_eq!(ctlz(100i64), 57); + assert_eq!(ctlz(100u8), 1); + assert_eq!(ctlz(100i8), 1); + assert_eq!(ctlz(100u16), 9); + assert_eq!(ctlz(100i16), 9); + assert_eq!(ctlz(100u32), 25); + assert_eq!(ctlz(100i32), 25); + assert_eq!(ctlz(100u64), 57); + assert_eq!(ctlz(100i64), 57); - assert_eq!(ctlz_nonzero(1u8), 7); assert_eq!(ctlz_nonzero(1i8), 7); - assert_eq!(ctlz_nonzero(1u16), 15); assert_eq!(ctlz_nonzero(1i16), 15); - assert_eq!(ctlz_nonzero(1u32), 31); assert_eq!(ctlz_nonzero(1i32), 31); - assert_eq!(ctlz_nonzero(1u64), 63); assert_eq!(ctlz_nonzero(1i64), 63); + assert_eq!(ctlz_nonzero(1u8), 7); + assert_eq!(ctlz_nonzero(1i8), 7); + assert_eq!(ctlz_nonzero(1u16), 15); + assert_eq!(ctlz_nonzero(1i16), 15); + assert_eq!(ctlz_nonzero(1u32), 31); + assert_eq!(ctlz_nonzero(1i32), 31); + assert_eq!(ctlz_nonzero(1u64), 63); + assert_eq!(ctlz_nonzero(1i64), 63); - assert_eq!(ctlz_nonzero(10u8), 4); assert_eq!(ctlz_nonzero(10i8), 4); - assert_eq!(ctlz_nonzero(10u16), 12); assert_eq!(ctlz_nonzero(10i16), 12); - assert_eq!(ctlz_nonzero(10u32), 28); assert_eq!(ctlz_nonzero(10i32), 28); - assert_eq!(ctlz_nonzero(10u64), 60); assert_eq!(ctlz_nonzero(10i64), 60); + assert_eq!(ctlz_nonzero(10u8), 4); + assert_eq!(ctlz_nonzero(10i8), 4); + assert_eq!(ctlz_nonzero(10u16), 12); + assert_eq!(ctlz_nonzero(10i16), 12); + assert_eq!(ctlz_nonzero(10u32), 28); + assert_eq!(ctlz_nonzero(10i32), 28); + assert_eq!(ctlz_nonzero(10u64), 60); + assert_eq!(ctlz_nonzero(10i64), 60); - assert_eq!(ctlz_nonzero(100u8), 1); assert_eq!(ctlz_nonzero(100i8), 1); - assert_eq!(ctlz_nonzero(100u16), 9); assert_eq!(ctlz_nonzero(100i16), 9); - assert_eq!(ctlz_nonzero(100u32), 25); assert_eq!(ctlz_nonzero(100i32), 25); - assert_eq!(ctlz_nonzero(100u64), 57); assert_eq!(ctlz_nonzero(100i64), 57); + assert_eq!(ctlz_nonzero(100u8), 1); + assert_eq!(ctlz_nonzero(100i8), 1); + assert_eq!(ctlz_nonzero(100u16), 9); + assert_eq!(ctlz_nonzero(100i16), 9); + assert_eq!(ctlz_nonzero(100u32), 25); + assert_eq!(ctlz_nonzero(100i32), 25); + assert_eq!(ctlz_nonzero(100u64), 57); + assert_eq!(ctlz_nonzero(100i64), 57); - assert_eq!(cttz(-1i8 as u8), 0); assert_eq!(cttz(-1i8), 0); - assert_eq!(cttz(-1i16 as u16), 0); assert_eq!(cttz(-1i16), 0); - assert_eq!(cttz(-1i32 as u32), 0); assert_eq!(cttz(-1i32), 0); - assert_eq!(cttz(-1i64 as u64), 0); assert_eq!(cttz(-1i64), 0); + assert_eq!(cttz(-1i8 as u8), 0); + assert_eq!(cttz(-1i8), 0); + assert_eq!(cttz(-1i16 as u16), 0); + assert_eq!(cttz(-1i16), 0); + assert_eq!(cttz(-1i32 as u32), 0); + assert_eq!(cttz(-1i32), 0); + assert_eq!(cttz(-1i64 as u64), 0); + assert_eq!(cttz(-1i64), 0); - assert_eq!(cttz(0u8), 8); assert_eq!(cttz(0i8), 8); - assert_eq!(cttz(0u16), 16); assert_eq!(cttz(0i16), 16); - assert_eq!(cttz(0u32), 32); assert_eq!(cttz(0i32), 32); - assert_eq!(cttz(0u64), 64); assert_eq!(cttz(0i64), 64); + assert_eq!(cttz(0u8), 8); + assert_eq!(cttz(0i8), 8); + assert_eq!(cttz(0u16), 16); + assert_eq!(cttz(0i16), 16); + assert_eq!(cttz(0u32), 32); + assert_eq!(cttz(0i32), 32); + assert_eq!(cttz(0u64), 64); + assert_eq!(cttz(0i64), 64); - assert_eq!(cttz(1u8), 0); assert_eq!(cttz(1i8), 0); - assert_eq!(cttz(1u16), 0); assert_eq!(cttz(1i16), 0); - assert_eq!(cttz(1u32), 0); assert_eq!(cttz(1i32), 0); - assert_eq!(cttz(1u64), 0); assert_eq!(cttz(1i64), 0); + assert_eq!(cttz(1u8), 0); + assert_eq!(cttz(1i8), 0); + assert_eq!(cttz(1u16), 0); + assert_eq!(cttz(1i16), 0); + assert_eq!(cttz(1u32), 0); + assert_eq!(cttz(1i32), 0); + assert_eq!(cttz(1u64), 0); + assert_eq!(cttz(1i64), 0); - assert_eq!(cttz(10u8), 1); assert_eq!(cttz(10i8), 1); - assert_eq!(cttz(10u16), 1); assert_eq!(cttz(10i16), 1); - assert_eq!(cttz(10u32), 1); assert_eq!(cttz(10i32), 1); - assert_eq!(cttz(10u64), 1); assert_eq!(cttz(10i64), 1); + assert_eq!(cttz(10u8), 1); + assert_eq!(cttz(10i8), 1); + assert_eq!(cttz(10u16), 1); + assert_eq!(cttz(10i16), 1); + assert_eq!(cttz(10u32), 1); + assert_eq!(cttz(10i32), 1); + assert_eq!(cttz(10u64), 1); + assert_eq!(cttz(10i64), 1); - assert_eq!(cttz(100u8), 2); assert_eq!(cttz(100i8), 2); - assert_eq!(cttz(100u16), 2); assert_eq!(cttz(100i16), 2); - assert_eq!(cttz(100u32), 2); assert_eq!(cttz(100i32), 2); - assert_eq!(cttz(100u64), 2); assert_eq!(cttz(100i64), 2); + assert_eq!(cttz(100u8), 2); + assert_eq!(cttz(100i8), 2); + assert_eq!(cttz(100u16), 2); + assert_eq!(cttz(100i16), 2); + assert_eq!(cttz(100u32), 2); + assert_eq!(cttz(100i32), 2); + assert_eq!(cttz(100u64), 2); + assert_eq!(cttz(100i64), 2); - assert_eq!(cttz_nonzero(-1i8 as u8), 0); assert_eq!(cttz_nonzero(-1i8), 0); - assert_eq!(cttz_nonzero(-1i16 as u16), 0); assert_eq!(cttz_nonzero(-1i16), 0); - assert_eq!(cttz_nonzero(-1i32 as u32), 0); assert_eq!(cttz_nonzero(-1i32), 0); - assert_eq!(cttz_nonzero(-1i64 as u64), 0); assert_eq!(cttz_nonzero(-1i64), 0); + assert_eq!(cttz_nonzero(-1i8 as u8), 0); + assert_eq!(cttz_nonzero(-1i8), 0); + assert_eq!(cttz_nonzero(-1i16 as u16), 0); + assert_eq!(cttz_nonzero(-1i16), 0); + assert_eq!(cttz_nonzero(-1i32 as u32), 0); + assert_eq!(cttz_nonzero(-1i32), 0); + assert_eq!(cttz_nonzero(-1i64 as u64), 0); + assert_eq!(cttz_nonzero(-1i64), 0); - assert_eq!(cttz_nonzero(1u8), 0); assert_eq!(cttz_nonzero(1i8), 0); - assert_eq!(cttz_nonzero(1u16), 0); assert_eq!(cttz_nonzero(1i16), 0); - assert_eq!(cttz_nonzero(1u32), 0); assert_eq!(cttz_nonzero(1i32), 0); - assert_eq!(cttz_nonzero(1u64), 0); assert_eq!(cttz_nonzero(1i64), 0); + assert_eq!(cttz_nonzero(1u8), 0); + assert_eq!(cttz_nonzero(1i8), 0); + assert_eq!(cttz_nonzero(1u16), 0); + assert_eq!(cttz_nonzero(1i16), 0); + assert_eq!(cttz_nonzero(1u32), 0); + assert_eq!(cttz_nonzero(1i32), 0); + assert_eq!(cttz_nonzero(1u64), 0); + assert_eq!(cttz_nonzero(1i64), 0); - assert_eq!(cttz_nonzero(10u8), 1); assert_eq!(cttz_nonzero(10i8), 1); - assert_eq!(cttz_nonzero(10u16), 1); assert_eq!(cttz_nonzero(10i16), 1); - assert_eq!(cttz_nonzero(10u32), 1); assert_eq!(cttz_nonzero(10i32), 1); - assert_eq!(cttz_nonzero(10u64), 1); assert_eq!(cttz_nonzero(10i64), 1); + assert_eq!(cttz_nonzero(10u8), 1); + assert_eq!(cttz_nonzero(10i8), 1); + assert_eq!(cttz_nonzero(10u16), 1); + assert_eq!(cttz_nonzero(10i16), 1); + assert_eq!(cttz_nonzero(10u32), 1); + assert_eq!(cttz_nonzero(10i32), 1); + assert_eq!(cttz_nonzero(10u64), 1); + assert_eq!(cttz_nonzero(10i64), 1); - assert_eq!(cttz_nonzero(100u8), 2); assert_eq!(cttz_nonzero(100i8), 2); - assert_eq!(cttz_nonzero(100u16), 2); assert_eq!(cttz_nonzero(100i16), 2); - assert_eq!(cttz_nonzero(100u32), 2); assert_eq!(cttz_nonzero(100i32), 2); - assert_eq!(cttz_nonzero(100u64), 2); assert_eq!(cttz_nonzero(100i64), 2); + assert_eq!(cttz_nonzero(100u8), 2); + assert_eq!(cttz_nonzero(100i8), 2); + assert_eq!(cttz_nonzero(100u16), 2); + assert_eq!(cttz_nonzero(100i16), 2); + assert_eq!(cttz_nonzero(100u32), 2); + assert_eq!(cttz_nonzero(100i32), 2); + assert_eq!(cttz_nonzero(100u64), 2); + assert_eq!(cttz_nonzero(100i64), 2); assert_eq!(bswap(0x0Au8), 0x0A); // no-op assert_eq!(bswap(0x0Ai8), 0x0A); // no-op @@ -127,20 +211,20 @@ pub fn main() { assert_eq!(bswap(0x0122334455667708u64), 0x0877665544332201); assert_eq!(bswap(0x0122334455667708i64), 0x0877665544332201); - assert_eq!(exact_div(9*9u32, 3), 27); - assert_eq!(exact_div(-9*9i32, 3), -27); - assert_eq!(exact_div(9*9i8, -3), -27); - assert_eq!(exact_div(-9*9i64, -3), 27); + assert_eq!(exact_div(9 * 9u32, 3), 27); + assert_eq!(exact_div(-9 * 9i32, 3), -27); + assert_eq!(exact_div(9 * 9i8, -3), -27); + assert_eq!(exact_div(-9 * 9i64, -3), 27); - assert_eq!(unchecked_div(9*9u32, 2), 40); - assert_eq!(unchecked_div(-9*9i32, 2), -40); - assert_eq!(unchecked_div(9*9i8, -2), -40); - assert_eq!(unchecked_div(-9*9i64, -2), 40); + assert_eq!(unchecked_div(9 * 9u32, 2), 40); + assert_eq!(unchecked_div(-9 * 9i32, 2), -40); + assert_eq!(unchecked_div(9 * 9i8, -2), -40); + assert_eq!(unchecked_div(-9 * 9i64, -2), 40); - assert_eq!(unchecked_rem(9*9u32, 2), 1); - assert_eq!(unchecked_rem(-9*9i32, 2), -1); - assert_eq!(unchecked_rem(9*9i8, -2), 1); - assert_eq!(unchecked_rem(-9*9i64, -2), -1); + assert_eq!(unchecked_rem(9 * 9u32, 2), 1); + assert_eq!(unchecked_rem(-9 * 9i32, 2), -1); + assert_eq!(unchecked_rem(9 * 9i8, -2), 1); + assert_eq!(unchecked_rem(-9 * 9i64, -2), -1); assert_eq!(unchecked_add(23u8, 19), 42); assert_eq!(unchecked_add(5, -10), -5); diff --git a/tests/pass/panic/catch_panic.rs b/tests/pass/panic/catch_panic.rs index 80881948c03c..2fb00391cd79 100644 --- a/tests/pass/panic/catch_panic.rs +++ b/tests/pass/panic/catch_panic.rs @@ -3,8 +3,8 @@ #![feature(never_type)] #![allow(unconditional_panic, non_fmt_panics)] -use std::panic::{catch_unwind, AssertUnwindSafe}; use std::cell::Cell; +use std::panic::{catch_unwind, AssertUnwindSafe}; thread_local! { static MY_COUNTER: Cell = Cell::new(0); @@ -59,23 +59,29 @@ fn main() { test(None, |old_val| core::panic!("Hello from panic: {:?}", old_val)); // Built-in panics; also make sure the message is right. - test( - Some("index out of bounds: the len is 3 but the index is 4"), - |_old_val| { let _val = [0, 1, 2][4]; loop {} }, - ); - test( - Some("attempt to divide by zero"), - |_old_val| { let _val = 1/0; loop {} }, - ); + test(Some("index out of bounds: the len is 3 but the index is 4"), |_old_val| { + let _val = [0, 1, 2][4]; + loop {} + }); + test(Some("attempt to divide by zero"), |_old_val| { + let _val = 1 / 0; + loop {} + }); - test( - Some("align_offset: align is not a power-of-two"), - |_old_val| { (0usize as *const u8).align_offset(3); loop {} }, - ); + test(Some("align_offset: align is not a power-of-two"), |_old_val| { + (0usize as *const u8).align_offset(3); + loop {} + }); // Assertion and debug assertion - test(None, |_old_val| { assert!(false); loop {} }); - test(None, |_old_val| { debug_assert!(false); loop {} }); + test(None, |_old_val| { + assert!(false); + loop {} + }); + test(None, |_old_val| { + debug_assert!(false); + loop {} + }); eprintln!("Success!"); // Make sure we get this in stderr } @@ -89,7 +95,8 @@ fn test(expect_msg: Option<&str>, do_panic: impl FnOnce(usize) -> !) { let res = catch_unwind(AssertUnwindSafe(|| { let _string = "LEAKED FROM CLOSURE".to_string(); do_panic_counter(do_panic) - })).expect_err("do_panic() did not panic!"); + })) + .expect_err("do_panic() did not panic!"); // See if we can extract the panic message. let msg = if let Some(s) = res.downcast_ref::() { diff --git a/tests/pass/ptr_int_casts.rs b/tests/pass/ptr_int_casts.rs index b9815126a8c7..aa60fd0c81ef 100644 --- a/tests/pass/ptr_int_casts.rs +++ b/tests/pass/ptr_int_casts.rs @@ -5,12 +5,14 @@ fn eq_ref(x: &T, y: &T) -> bool { x as *const _ == y as *const _ } -fn f() -> i32 { 42 } +fn f() -> i32 { + 42 +} fn ptr_int_casts() { // int-ptr-int assert_eq!(1 as *const i32 as usize, 1); - assert_eq!((1 as *const i32).wrapping_offset(4) as usize, 1 + 4*4); + assert_eq!((1 as *const i32).wrapping_offset(4) as usize, 1 + 4 * 4); // negative overflowing wrapping_offset (going through memory because // this used to trigger an ICE on 32bit) @@ -18,7 +20,8 @@ fn ptr_int_casts() { *val = (1 as *const u8).wrapping_offset(-4); assert_eq!(*val as usize, usize::MAX - 2); - { // ptr-int-ptr + { + // ptr-int-ptr let x = 13; let mut y = &x as &_ as *const _ as usize; y += 13; @@ -27,13 +30,14 @@ fn ptr_int_casts() { assert!(eq_ref(&x, unsafe { &*y })); } - { // fnptr-int-fnptr - let x : fn() -> i32 = f; - let y : *mut u8 = unsafe { mem::transmute(x as fn() -> i32) }; + { + // fnptr-int-fnptr + let x: fn() -> i32 = f; + let y: *mut u8 = unsafe { mem::transmute(x as fn() -> i32) }; let mut y = y as usize; y += 13; y -= 13; - let x : fn() -> i32 = unsafe { mem::transmute(y as *mut u8) }; + let x: fn() -> i32 = unsafe { mem::transmute(y as *mut u8) }; assert_eq!(x(), 42); } @@ -51,13 +55,13 @@ fn ptr_int_ops() { // bit-operations, covered by alignment assert_eq!(x & 1, 0); assert_eq!(x & 0, 0); - assert_eq!(1 & (x+1), 1); + assert_eq!(1 & (x + 1), 1); let _y = !1 & x; let _y = !0 & x; let _y = x & !1; // remainder, covered by alignment assert_eq!(x % 2, 0); - assert_eq!((x+1) % 2, 1); + assert_eq!((x + 1) % 2, 1); // remainder with 1 is always 0 assert_eq!(x % 1, 0); } diff --git a/tests/pass/regions-lifetime-nonfree-late-bound.rs b/tests/pass/regions-lifetime-nonfree-late-bound.rs index 78aeea64814a..c91ac36ed6b4 100644 --- a/tests/pass/regions-lifetime-nonfree-late-bound.rs +++ b/tests/pass/regions-lifetime-nonfree-late-bound.rs @@ -16,15 +16,23 @@ pub fn main() { fn explicit() { - fn test(_x: Option>) where F: FnMut(Box FnMut(&'a isize)>) {} + fn test(_x: Option>) + where + F: FnMut(Box FnMut(&'a isize)>), + { + } test(Some(box |_f: Box FnMut(&'a isize)>| {})); } // The code below is shorthand for the code above (and more likely // to represent what one encounters in practice). fn implicit() { - fn test(_x: Option>) where F: FnMut(Box) {} - test(Some(box |_f: Box| {})); + fn test(_x: Option>) + where + F: FnMut(Box), + { + } + test(Some(box |_f: Box| {})); } explicit(); diff --git a/tests/pass/sums.rs b/tests/pass/sums.rs index daeba060a78b..84ff96942002 100644 --- a/tests/pass/sums.rs +++ b/tests/pass/sums.rs @@ -1,12 +1,17 @@ #[derive(Debug, PartialEq)] -enum Unit { Unit(()) } // Force non-C-enum representation. +enum Unit { + Unit(()), +} // Force non-C-enum representation. fn return_unit() -> Unit { Unit::Unit(()) } #[derive(Debug, PartialEq)] -enum MyBool { False(()), True(()) } // Force non-C-enum representation. +enum MyBool { + False(()), + True(()), +} // Force non-C-enum representation. fn return_true() -> MyBool { MyBool::True(()) From 639f660dde9936368714a10a80a325a78a1b3a99 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 21 Jun 2022 23:03:34 -0700 Subject: [PATCH 3323/5092] Manual adjustments --- tests/fail/branchless-select-i128-pointer.rs | 2 +- tests/fail/data_race/dealloc_read_race1.rs | 7 +++-- tests/fail/data_race/dealloc_write_race1.rs | 3 +- .../fail/function_calls/check_callback_abi.rs | 2 +- .../exported_symbol_abi_mismatch.rs | 14 ++++++---- tests/fail/type-too-large.rs | 3 +- tests/fail/validity/invalid_char.rs | 2 +- tests/pass/0weak_memory_consistency.rs | 23 ++++++++------- tests/pass/concurrency/linux-futex.rs | 28 +++++++++---------- tests/pass/heap_allocator.rs | 21 +++++++------- tests/pass/iter.rs | 2 +- 11 files changed, 56 insertions(+), 51 deletions(-) diff --git a/tests/fail/branchless-select-i128-pointer.rs b/tests/fail/branchless-select-i128-pointer.rs index b0c9c0fd7282..7e1b969e02cf 100644 --- a/tests/fail/branchless-select-i128-pointer.rs +++ b/tests/fail/branchless-select-i128-pointer.rs @@ -12,7 +12,7 @@ fn main() { // However, it drops provenance when transmuting to TwoPtrs, so this is UB. let val = unsafe { transmute::<_, &str>( - //~ERROR type validation failed: encountered a dangling reference + //~^ ERROR type validation failed: encountered a dangling reference !mask & transmute::<_, TwoPtrs>("false !") | mask & transmute::<_, TwoPtrs>("true !"), ) diff --git a/tests/fail/data_race/dealloc_read_race1.rs b/tests/fail/data_race/dealloc_read_race1.rs index 38bbd81f1e2f..555700a75d3a 100644 --- a/tests/fail/data_race/dealloc_read_race1.rs +++ b/tests/fail/data_race/dealloc_read_race1.rs @@ -18,14 +18,17 @@ pub fn main() { let ptr = EvilSend(pointer); unsafe { - let j1 = spawn(move || *ptr.0); + let j1 = spawn(move || { + let _val = *ptr.0; + }); let j2 = spawn(move || { __rust_dealloc( + //~^ ERROR Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::(), - ); //~ ERROR Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) + ); }); j1.join().unwrap(); diff --git a/tests/fail/data_race/dealloc_write_race1.rs b/tests/fail/data_race/dealloc_write_race1.rs index 1cfaeb2cb25a..44078a044a7f 100644 --- a/tests/fail/data_race/dealloc_write_race1.rs +++ b/tests/fail/data_race/dealloc_write_race1.rs @@ -23,10 +23,11 @@ pub fn main() { let j2 = spawn(move || { __rust_dealloc( + //~^ ERROR Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::(), - ); //~ ERROR Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) + ); }); j1.join().unwrap(); diff --git a/tests/fail/function_calls/check_callback_abi.rs b/tests/fail/function_calls/check_callback_abi.rs index f76839c34f20..0a5a2d48d274 100644 --- a/tests/fail/function_calls/check_callback_abi.rs +++ b/tests/fail/function_calls/check_callback_abi.rs @@ -9,7 +9,7 @@ fn main() { // Make sure we check the ABI when Miri itself invokes a function // as part of a shim implementation. std::intrinsics::r#try( - //~ ERROR calling a function with ABI C using caller ABI Rust + //~^ ERROR calling a function with ABI C using caller ABI Rust std::mem::transmute::(try_fn), std::ptr::null_mut(), |_, _| unreachable!(), diff --git a/tests/fail/function_calls/exported_symbol_abi_mismatch.rs b/tests/fail/function_calls/exported_symbol_abi_mismatch.rs index 7e8fb2cffecb..c337e1f29f16 100644 --- a/tests/fail/function_calls/exported_symbol_abi_mismatch.rs +++ b/tests/fail/function_calls/exported_symbol_abi_mismatch.rs @@ -11,14 +11,14 @@ fn main() { #[cfg(fn_ptr)] unsafe { - std::mem::transmute::(foo)() + std::mem::transmute::(foo)(); + //[fn_ptr]~^ ERROR calling a function with calling convention Rust using calling convention C } - //[fn_ptr]~^ ERROR calling a function with calling convention Rust using calling convention C // `Instance` caching should not suppress ABI check. #[cfg(cache)] unsafe { - foo() + foo(); } { @@ -26,8 +26,10 @@ fn main() { extern "C" { fn foo(); } - unsafe { foo() } - //[no_cache]~^ ERROR calling a function with calling convention Rust using calling convention C - //[cache]~^^ ERROR calling a function with calling convention Rust using calling convention C + unsafe { + foo(); + //[no_cache]~^ ERROR calling a function with calling convention Rust using calling convention C + //[cache]~| ERROR calling a function with calling convention Rust using calling convention C + } } } diff --git a/tests/fail/type-too-large.rs b/tests/fail/type-too-large.rs index d9e19ed81876..08f7a49b0255 100644 --- a/tests/fail/type-too-large.rs +++ b/tests/fail/type-too-large.rs @@ -1,5 +1,6 @@ // ignore-32bit fn main() { - let _fat: [u8; (1 << 61) + (1 << 31)] = [0; (1u64 << 61) as usize + (1u64 << 31) as usize]; //~ ERROR post-monomorphization error + let _fat: [u8; (1 << 61) + (1 << 31)]; + _fat = [0; (1u64 << 61) as usize + (1u64 << 31) as usize]; //~ ERROR post-monomorphization error } diff --git a/tests/fail/validity/invalid_char.rs b/tests/fail/validity/invalid_char.rs index a868dac8875d..80749fd7c791 100644 --- a/tests/fail/validity/invalid_char.rs +++ b/tests/fail/validity/invalid_char.rs @@ -1,7 +1,7 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); let _val = match unsafe { std::mem::transmute::(-1) } { - //~ ERROR encountered 0xffffffff, but expected a valid unicode scalar value + //~^ ERROR encountered 0xffffffff, but expected a valid unicode scalar value 'a' => true, 'b' => false, _ => true, diff --git a/tests/pass/0weak_memory_consistency.rs b/tests/pass/0weak_memory_consistency.rs index ae8d281858c2..0f798d2b575e 100644 --- a/tests/pass/0weak_memory_consistency.rs +++ b/tests/pass/0weak_memory_consistency.rs @@ -54,14 +54,14 @@ fn test_corr() { x.store(2, Relaxed); }); + #[rustfmt::skip] let j2 = spawn(move || { let r2 = x.load(Relaxed); // -------------------------------------+ y.store(1, Release); // ---------------------+ | r2 // | | }); // | | - // |synchronizes-with |happens-before - let j3 = spawn(move || { - // | | + #[rustfmt::skip] // |synchronizes-with |happens-before + let j3 = spawn(move || { // | | acquires_value(&y, 1); // <------------------+ | x.load(Relaxed) // <----------------------------------------------+ // The two reads on x are ordered by hb, so they cannot observe values @@ -81,18 +81,17 @@ fn test_wrc() { let x = static_atomic(0); let y = static_atomic(0); + #[rustfmt::skip] let j1 = spawn(move || { x.store(1, Release); // ---------------------+---------------------+ }); // | | - // |synchronizes-with | - let j2 = spawn(move || { - // | | + #[rustfmt::skip] // |synchronizes-with | + let j2 = spawn(move || { // | | acquires_value(&x, 1); // <------------------+ | y.store(1, Release); // ---------------------+ |happens-before }); // | | - // |synchronizes-with | - let j3 = spawn(move || { - // | | + #[rustfmt::skip] // |synchronizes-with | + let j3 = spawn(move || { // | | acquires_value(&y, 1); // <------------------+ | x.load(Relaxed) // <-----------------------------------------------+ }); @@ -110,13 +109,13 @@ fn test_message_passing() { let x = EvilSend(ptr); let y = static_atomic(0); + #[rustfmt::skip] let j1 = spawn(move || { unsafe { *x.0 = 1 }; // -----------------------------------------+ y.store(1, Release); // ---------------------+ | }); // | | - // |synchronizes-with | happens-before - let j2 = spawn(move || { - // | | + #[rustfmt::skip] // |synchronizes-with | happens-before + let j2 = spawn(move || { // | | acquires_value(&y, 1); // <------------------+ | unsafe { *x.0 } // <---------------------------------------------+ }); diff --git a/tests/pass/concurrency/linux-futex.rs b/tests/pass/concurrency/linux-futex.rs index 74fec411b4c9..2c60df1ee138 100644 --- a/tests/pass/concurrency/linux-futex.rs +++ b/tests/pass/concurrency/linux-futex.rs @@ -16,7 +16,7 @@ fn wake_nobody() { // Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting. unsafe { - assert_eq!(libc::syscall(libc::SYS_futex, &futex as *const i32, libc::FUTEX_WAKE, 1,), 0); + assert_eq!(libc::syscall(libc::SYS_futex, &futex as *const i32, libc::FUTEX_WAKE, 1), 0); } // Same, but without omitting the unused arguments. @@ -31,7 +31,7 @@ fn wake_nobody() { 0usize, 0, ), - 0 + 0, ); } } @@ -43,7 +43,7 @@ fn wake_dangling() { // Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting. unsafe { - assert_eq!(libc::syscall(libc::SYS_futex, ptr, libc::FUTEX_WAKE, 1,), 0); + assert_eq!(libc::syscall(libc::SYS_futex, ptr, libc::FUTEX_WAKE, 1), 0); } } @@ -60,7 +60,7 @@ fn wait_wrong_val() { 456, ptr::null::(), ), - -1 + -1, ); assert_eq!(*libc::__errno_location(), libc::EAGAIN); } @@ -81,7 +81,7 @@ fn wait_timeout() { 123, &libc::timespec { tv_sec: 0, tv_nsec: 200_000_000 }, ), - -1 + -1, ); assert_eq!(*libc::__errno_location(), libc::ETIMEDOUT); } @@ -120,7 +120,7 @@ fn wait_absolute_timeout() { 0usize, u32::MAX, ), - -1 + -1, ); assert_eq!(*libc::__errno_location(), libc::ETIMEDOUT); } @@ -143,8 +143,8 @@ fn wait_wake() { libc::FUTEX_WAKE, 10, // Wake up at most 10 threads. ), - 1 - ); // Woken up one thread. + 1, // Woken up one thread. + ); } }); @@ -157,7 +157,7 @@ fn wait_wake() { 0, ptr::null::(), ), - 0 + 0, ); } @@ -183,8 +183,8 @@ fn wait_wake_bitset() { 0usize, 0b1001, // bitset ), - 0 - ); // Didn't match any thread. + 0, // Didn't match any thread. + ); } thread::sleep(Duration::from_millis(200)); unsafe { @@ -198,8 +198,8 @@ fn wait_wake_bitset() { 0usize, 0b0110, // bitset ), - 1 - ); // Woken up one thread. + 1, // Woken up one thread. + ); } }); @@ -214,7 +214,7 @@ fn wait_wake_bitset() { 0usize, 0b0100, // bitset ), - 0 + 0, ); } diff --git a/tests/pass/heap_allocator.rs b/tests/pass/heap_allocator.rs index a3ab5b21f0b3..2c38dcb49f1c 100644 --- a/tests/pass/heap_allocator.rs +++ b/tests/pass/heap_allocator.rs @@ -16,7 +16,7 @@ fn check_alloc(allocator: T) { assert_eq!( a.as_ptr() as usize % layout_20.align(), 0, - "pointer is incorrectly aligned" + "pointer is incorrectly aligned", ); allocator.deallocate(a, layout_20); } @@ -25,7 +25,7 @@ fn check_alloc(allocator: T) { assert_eq!( p1.as_ptr() as usize % layout_20.align(), 0, - "pointer is incorrectly aligned" + "pointer is incorrectly aligned", ); assert_eq!(*p1.as_ptr(), 0); @@ -34,7 +34,7 @@ fn check_alloc(allocator: T) { assert_eq!( p2.as_ptr() as usize % layout_40.align(), 0, - "pointer is incorrectly aligned" + "pointer is incorrectly aligned", ); let slice = slice::from_raw_parts(p2.as_ptr(), 20); assert_eq!(&slice, &[0_u8; 20]); @@ -44,7 +44,7 @@ fn check_alloc(allocator: T) { assert_eq!( p3.as_ptr() as usize % layout_40.align(), 0, - "pointer is incorrectly aligned" + "pointer is incorrectly aligned", ); let slice = slice::from_raw_parts(p3.as_ptr(), 20); assert_eq!(&slice, &[0_u8; 20]); @@ -54,7 +54,7 @@ fn check_alloc(allocator: T) { assert_eq!( p4.as_ptr() as usize % layout_10.align(), 0, - "pointer is incorrectly aligned" + "pointer is incorrectly aligned", ); let slice = slice::from_raw_parts(p4.as_ptr(), 10); assert_eq!(&slice, &[0_u8; 10]); @@ -65,10 +65,9 @@ fn check_alloc(allocator: T) { } fn check_align_requests(allocator: T) { - for &size in &[2, 8, 64] { - // size less than and bigger than alignment - for &align in &[4, 8, 16, 32] { - // Be sure to cover less than and bigger than `MIN_ALIGN` for all architectures + #[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/3255 + for &size in &[2, 8, 64] { // size less than and bigger than alignment + for &align in &[4, 8, 16, 32] { // Be sure to cover less than and bigger than `MIN_ALIGN` for all architectures let iterations = 32; unsafe { let pointers: Vec<_> = (0..iterations) @@ -83,7 +82,7 @@ fn check_align_requests(allocator: T) { assert_eq!( (ptr.as_ptr() as usize) % align, 0, - "Got a pointer less aligned than requested" + "Got a pointer less aligned than requested", ) } @@ -93,7 +92,7 @@ fn check_align_requests(allocator: T) { } } } - } + }; } fn global_to_box() { diff --git a/tests/pass/iter.rs b/tests/pass/iter.rs index 8ee03d112641..31d0d7442d9d 100644 --- a/tests/pass/iter.rs +++ b/tests/pass/iter.rs @@ -1,6 +1,6 @@ fn iter_empty_and_zst() { + // Iterate over a Unique::empty() for _ in Vec::::new().iter() { - // this iterates over a Unique::empty() panic!("We should never be here."); } From 05893d90269c6cbea4428b570bcfd09c1cb7c063 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 21 Jun 2022 23:21:37 -0700 Subject: [PATCH 3324/5092] Bless stderr files after rustfmt --- tests/fail/branchless-select-i128-pointer.stderr | 4 +++- tests/fail/data_race/dealloc_read_race1.stderr | 9 +++++++-- tests/fail/data_race/dealloc_write_race1.stderr | 9 +++++++-- tests/fail/function_calls/check_callback_abi.stderr | 1 + .../exported_symbol_abi_mismatch.cache.stderr | 4 ++-- .../exported_symbol_abi_mismatch.fn_ptr.stderr | 4 ++-- .../exported_symbol_abi_mismatch.no_cache.stderr | 4 ++-- tests/fail/type-too-large.stderr | 4 ++-- 8 files changed, 26 insertions(+), 13 deletions(-) diff --git a/tests/fail/branchless-select-i128-pointer.stderr b/tests/fail/branchless-select-i128-pointer.stderr index f37dcf955e33..374d6ab06809 100644 --- a/tests/fail/branchless-select-i128-pointer.stderr +++ b/tests/fail/branchless-select-i128-pointer.stderr @@ -2,7 +2,9 @@ error: Undefined Behavior: type validation failed: encountered a dangling refere --> $DIR/branchless-select-i128-pointer.rs:LL:CC | LL | / transmute::<_, &str>( -LL | | !mask & transmute::<_, TwoPtrs>("false !") | mask & transmute::<_, TwoPtrs>("true !"), +LL | | +LL | | !mask & transmute::<_, TwoPtrs>("false !") +LL | | | mask & transmute::<_, TwoPtrs>("true !"), LL | | ) | |_____________^ type validation failed: encountered a dangling reference (address $HEX is unallocated) | diff --git a/tests/fail/data_race/dealloc_read_race1.stderr b/tests/fail/data_race/dealloc_read_race1.stderr index 6b5cf5fc02f6..91a681e74450 100644 --- a/tests/fail/data_race/dealloc_read_race1.stderr +++ b/tests/fail/data_race/dealloc_read_race1.stderr @@ -1,8 +1,13 @@ error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/dealloc_read_race1.rs:LL:CC | -LL | __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +LL | / __rust_dealloc( +LL | | +LL | | ptr.0 as *mut _, +LL | | std::mem::size_of::(), +LL | | std::mem::align_of::(), +LL | | ); + | |_____________^ Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/dealloc_write_race1.stderr b/tests/fail/data_race/dealloc_write_race1.stderr index ac9701d49f5f..dc1a6ed267c6 100644 --- a/tests/fail/data_race/dealloc_write_race1.stderr +++ b/tests/fail/data_race/dealloc_write_race1.stderr @@ -1,8 +1,13 @@ error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/dealloc_write_race1.rs:LL:CC | -LL | __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +LL | / __rust_dealloc( +LL | | +LL | | ptr.0 as *mut _, +LL | | std::mem::size_of::(), +LL | | std::mem::align_of::(), +LL | | ); + | |_____________^ Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/function_calls/check_callback_abi.stderr b/tests/fail/function_calls/check_callback_abi.stderr index ea7c2bb6b4ae..56314e6d2859 100644 --- a/tests/fail/function_calls/check_callback_abi.stderr +++ b/tests/fail/function_calls/check_callback_abi.stderr @@ -2,6 +2,7 @@ error: Undefined Behavior: calling a function with ABI C using caller ABI Rust --> $DIR/check_callback_abi.rs:LL:CC | LL | / std::intrinsics::r#try( +LL | | LL | | std::mem::transmute::(try_fn), LL | | std::ptr::null_mut(), LL | | |_, _| unreachable!(), diff --git a/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr b/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr index bf0d27d91576..dee7f66e0ad9 100644 --- a/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr +++ b/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: calling a function with calling convention Rust using calling convention C --> $DIR/exported_symbol_abi_mismatch.rs:LL:CC | -LL | unsafe { foo() } - | ^^^^^ calling a function with calling convention Rust using calling convention C +LL | foo(); + | ^^^^^ calling a function with calling convention Rust using calling convention C | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr b/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr index ee810af315fc..ebe19796609c 100644 --- a/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr +++ b/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: calling a function with calling convention Rust using calling convention C --> $DIR/exported_symbol_abi_mismatch.rs:LL:CC | -LL | unsafe { std::mem::transmute::(foo)() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with calling convention Rust using calling convention C +LL | std::mem::transmute::(foo)(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with calling convention Rust using calling convention C | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr b/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr index bf0d27d91576..dee7f66e0ad9 100644 --- a/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr +++ b/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: calling a function with calling convention Rust using calling convention C --> $DIR/exported_symbol_abi_mismatch.rs:LL:CC | -LL | unsafe { foo() } - | ^^^^^ calling a function with calling convention Rust using calling convention C +LL | foo(); + | ^^^^^ calling a function with calling convention Rust using calling convention C | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/type-too-large.stderr b/tests/fail/type-too-large.stderr index 3d555da40cc3..cb1d725ec878 100644 --- a/tests/fail/type-too-large.stderr +++ b/tests/fail/type-too-large.stderr @@ -1,8 +1,8 @@ error: post-monomorphization error: values of the type `[u8; 2305843011361177600]` are too big for the current architecture --> $DIR/type-too-large.rs:LL:CC | -LL | [0; (1u64<<61) as usize +(1u64<<31) as usize]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ values of the type `[u8; 2305843011361177600]` are too big for the current architecture +LL | _fat = [0; (1u64 << 61) as usize + (1u64 << 31) as usize]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ values of the type `[u8; 2305843011361177600]` are too big for the current architecture | = note: inside `main` at $DIR/type-too-large.rs:LL:CC From 274085cebdbbe01522818c0b1e5f1f00af97ed9d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 21 Jun 2022 23:48:09 -0700 Subject: [PATCH 3325/5092] Manual adjustments --- .../fail/unaligned_pointers/dyn_alignment.rs | 2 +- .../unaligned_pointers/reference_to_packed.rs | 2 +- .../fail/unaligned_pointers/unaligned_ptr1.rs | 2 +- .../fail/unaligned_pointers/unaligned_ptr3.rs | 2 +- .../fail/unaligned_pointers/unaligned_ptr4.rs | 3 +- .../unaligned_ptr_addr_of.rs | 2 +- .../unaligned_pointers/unaligned_ptr_zst.rs | 2 +- tests/pass/intrinsics-integer.rs | 252 ++++++------------ tests/pass/ptr_int_casts.rs | 4 +- tests/pass/sums.rs | 8 +- 10 files changed, 98 insertions(+), 181 deletions(-) diff --git a/tests/fail/unaligned_pointers/dyn_alignment.rs b/tests/fail/unaligned_pointers/dyn_alignment.rs index 39dd6f9e4c07..730dd87cbb10 100644 --- a/tests/fail/unaligned_pointers/dyn_alignment.rs +++ b/tests/fail/unaligned_pointers/dyn_alignment.rs @@ -6,8 +6,8 @@ struct MuchAlign; fn main() { + // Try many times as this might work by chance. for _ in 0..10 { - // Try many times as this might work by chance. let buf = [0u32; 256]; // `buf` is sufficiently aligned for `layout.align` on a `dyn Debug`, but not // for the actual alignment required by `MuchAlign`. diff --git a/tests/fail/unaligned_pointers/reference_to_packed.rs b/tests/fail/unaligned_pointers/reference_to_packed.rs index 74b2f308e230..c42f0e27aead 100644 --- a/tests/fail/unaligned_pointers/reference_to_packed.rs +++ b/tests/fail/unaligned_pointers/reference_to_packed.rs @@ -10,8 +10,8 @@ struct Foo { } fn main() { + // Try many times as this might work by chance. for _ in 0..10 { - // Try many times as this might work by chance. let foo = Foo { x: 42, y: 99 }; let p = &foo.x; let i = *p; //~ERROR alignment 4 is required diff --git a/tests/fail/unaligned_pointers/unaligned_ptr1.rs b/tests/fail/unaligned_pointers/unaligned_ptr1.rs index 445eb051ae2d..7d192e5d3928 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr1.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr1.rs @@ -2,8 +2,8 @@ // compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { + // Try many times as this might work by chance. for _ in 0..10 { - // Try many times as this might work by chance. let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. diff --git a/tests/fail/unaligned_pointers/unaligned_ptr3.rs b/tests/fail/unaligned_pointers/unaligned_ptr3.rs index f13ae4888675..748a31681a78 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr3.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr3.rs @@ -2,8 +2,8 @@ // compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { + // Try many times as this might work by chance. for _ in 0..10 { - // Try many times as this might work by chance. let x = [2u16, 3, 4, 5]; // Make it big enough so we don't get an out-of-bounds error. let x = &x[0] as *const _ as *const *const u8; // cast to ptr-to-ptr, so that we load a ptr // This must fail because alignment is violated. Test specifically for loading pointers, diff --git a/tests/fail/unaligned_pointers/unaligned_ptr4.rs b/tests/fail/unaligned_pointers/unaligned_ptr4.rs index 18ae48b0a1e5..d01cabfa31cc 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr4.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr4.rs @@ -4,8 +4,9 @@ fn main() { // Make sure we notice when a u16 is loaded at offset 1 into a u8 allocation. // (This would be missed if u8 allocations are *always* at odd addresses.) + // + // Try many times as this might work by chance. for _ in 0..10 { - // Try many times as this might work by chance. let x = [0u8; 4]; let ptr = x.as_ptr().wrapping_offset(1).cast::(); let _val = unsafe { *ptr }; //~ERROR but alignment diff --git a/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs b/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs index 0604a7eb2d2b..dff92d56d70e 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs @@ -3,8 +3,8 @@ use std::ptr; fn main() { + // Try many times as this might work by chance. for _ in 0..10 { - // Try many times as this might work by chance. let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. diff --git a/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs b/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs index 983939688f1b..8252ea83c870 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs @@ -3,8 +3,8 @@ // compile-flags: -Zmir-opt-level=0 -Zmiri-disable-validation fn main() { + // Try many times as this might work by chance. for i in 0..10 { - // Try many times as this might work by chance. let x = i as u8; let x = &x as *const _ as *const [u32; 0]; // This must fail because alignment is violated. Test specifically for loading ZST. diff --git a/tests/pass/intrinsics-integer.rs b/tests/pass/intrinsics-integer.rs index e8a3056f2c34..546931f6ff87 100644 --- a/tests/pass/intrinsics-integer.rs +++ b/tests/pass/intrinsics-integer.rs @@ -13,194 +13,110 @@ use std::intrinsics::*; pub fn main() { unsafe { - assert_eq!(ctpop(0u8), 0); - assert_eq!(ctpop(0i8), 0); - assert_eq!(ctpop(0u16), 0); - assert_eq!(ctpop(0i16), 0); - assert_eq!(ctpop(0u32), 0); - assert_eq!(ctpop(0i32), 0); - assert_eq!(ctpop(0u64), 0); - assert_eq!(ctpop(0i64), 0); + [assert_eq!(ctpop(0u8), 0), assert_eq!(ctpop(0i8), 0)]; + [assert_eq!(ctpop(0u16), 0), assert_eq!(ctpop(0i16), 0)]; + [assert_eq!(ctpop(0u32), 0), assert_eq!(ctpop(0i32), 0)]; + [assert_eq!(ctpop(0u64), 0), assert_eq!(ctpop(0i64), 0)]; - assert_eq!(ctpop(1u8), 1); - assert_eq!(ctpop(1i8), 1); - assert_eq!(ctpop(1u16), 1); - assert_eq!(ctpop(1i16), 1); - assert_eq!(ctpop(1u32), 1); - assert_eq!(ctpop(1i32), 1); - assert_eq!(ctpop(1u64), 1); - assert_eq!(ctpop(1i64), 1); + [assert_eq!(ctpop(1u8), 1), assert_eq!(ctpop(1i8), 1)]; + [assert_eq!(ctpop(1u16), 1), assert_eq!(ctpop(1i16), 1)]; + [assert_eq!(ctpop(1u32), 1), assert_eq!(ctpop(1i32), 1)]; + [assert_eq!(ctpop(1u64), 1), assert_eq!(ctpop(1i64), 1)]; - assert_eq!(ctpop(10u8), 2); - assert_eq!(ctpop(10i8), 2); - assert_eq!(ctpop(10u16), 2); - assert_eq!(ctpop(10i16), 2); - assert_eq!(ctpop(10u32), 2); - assert_eq!(ctpop(10i32), 2); - assert_eq!(ctpop(10u64), 2); - assert_eq!(ctpop(10i64), 2); + [assert_eq!(ctpop(10u8), 2), assert_eq!(ctpop(10i8), 2)]; + [assert_eq!(ctpop(10u16), 2), assert_eq!(ctpop(10i16), 2)]; + [assert_eq!(ctpop(10u32), 2), assert_eq!(ctpop(10i32), 2)]; + [assert_eq!(ctpop(10u64), 2), assert_eq!(ctpop(10i64), 2)]; - assert_eq!(ctpop(100u8), 3); - assert_eq!(ctpop(100i8), 3); - assert_eq!(ctpop(100u16), 3); - assert_eq!(ctpop(100i16), 3); - assert_eq!(ctpop(100u32), 3); - assert_eq!(ctpop(100i32), 3); - assert_eq!(ctpop(100u64), 3); - assert_eq!(ctpop(100i64), 3); + [assert_eq!(ctpop(100u8), 3), assert_eq!(ctpop(100i8), 3)]; + [assert_eq!(ctpop(100u16), 3), assert_eq!(ctpop(100i16), 3)]; + [assert_eq!(ctpop(100u32), 3), assert_eq!(ctpop(100i32), 3)]; + [assert_eq!(ctpop(100u64), 3), assert_eq!(ctpop(100i64), 3)]; - assert_eq!(ctpop(-1i8 as u8), 8); - assert_eq!(ctpop(-1i8), 8); - assert_eq!(ctpop(-1i16 as u16), 16); - assert_eq!(ctpop(-1i16), 16); - assert_eq!(ctpop(-1i32 as u32), 32); - assert_eq!(ctpop(-1i32), 32); - assert_eq!(ctpop(-1i64 as u64), 64); - assert_eq!(ctpop(-1i64), 64); + [assert_eq!(ctpop(-1i8 as u8), 8), assert_eq!(ctpop(-1i8), 8)]; + [assert_eq!(ctpop(-1i16 as u16), 16), assert_eq!(ctpop(-1i16), 16)]; + [assert_eq!(ctpop(-1i32 as u32), 32), assert_eq!(ctpop(-1i32), 32)]; + [assert_eq!(ctpop(-1i64 as u64), 64), assert_eq!(ctpop(-1i64), 64)]; - assert_eq!(ctlz(0u8), 8); - assert_eq!(ctlz(0i8), 8); - assert_eq!(ctlz(0u16), 16); - assert_eq!(ctlz(0i16), 16); - assert_eq!(ctlz(0u32), 32); - assert_eq!(ctlz(0i32), 32); - assert_eq!(ctlz(0u64), 64); - assert_eq!(ctlz(0i64), 64); + [assert_eq!(ctlz(0u8), 8), assert_eq!(ctlz(0i8), 8)]; + [assert_eq!(ctlz(0u16), 16), assert_eq!(ctlz(0i16), 16)]; + [assert_eq!(ctlz(0u32), 32), assert_eq!(ctlz(0i32), 32)]; + [assert_eq!(ctlz(0u64), 64), assert_eq!(ctlz(0i64), 64)]; - assert_eq!(ctlz(1u8), 7); - assert_eq!(ctlz(1i8), 7); - assert_eq!(ctlz(1u16), 15); - assert_eq!(ctlz(1i16), 15); - assert_eq!(ctlz(1u32), 31); - assert_eq!(ctlz(1i32), 31); - assert_eq!(ctlz(1u64), 63); - assert_eq!(ctlz(1i64), 63); + [assert_eq!(ctlz(1u8), 7), assert_eq!(ctlz(1i8), 7)]; + [assert_eq!(ctlz(1u16), 15), assert_eq!(ctlz(1i16), 15)]; + [assert_eq!(ctlz(1u32), 31), assert_eq!(ctlz(1i32), 31)]; + [assert_eq!(ctlz(1u64), 63), assert_eq!(ctlz(1i64), 63)]; - assert_eq!(ctlz(10u8), 4); - assert_eq!(ctlz(10i8), 4); - assert_eq!(ctlz(10u16), 12); - assert_eq!(ctlz(10i16), 12); - assert_eq!(ctlz(10u32), 28); - assert_eq!(ctlz(10i32), 28); - assert_eq!(ctlz(10u64), 60); - assert_eq!(ctlz(10i64), 60); + [assert_eq!(ctlz(10u8), 4), assert_eq!(ctlz(10i8), 4)]; + [assert_eq!(ctlz(10u16), 12), assert_eq!(ctlz(10i16), 12)]; + [assert_eq!(ctlz(10u32), 28), assert_eq!(ctlz(10i32), 28)]; + [assert_eq!(ctlz(10u64), 60), assert_eq!(ctlz(10i64), 60)]; - assert_eq!(ctlz(100u8), 1); - assert_eq!(ctlz(100i8), 1); - assert_eq!(ctlz(100u16), 9); - assert_eq!(ctlz(100i16), 9); - assert_eq!(ctlz(100u32), 25); - assert_eq!(ctlz(100i32), 25); - assert_eq!(ctlz(100u64), 57); - assert_eq!(ctlz(100i64), 57); + [assert_eq!(ctlz(100u8), 1), assert_eq!(ctlz(100i8), 1)]; + [assert_eq!(ctlz(100u16), 9), assert_eq!(ctlz(100i16), 9)]; + [assert_eq!(ctlz(100u32), 25), assert_eq!(ctlz(100i32), 25)]; + [assert_eq!(ctlz(100u64), 57), assert_eq!(ctlz(100i64), 57)]; - assert_eq!(ctlz_nonzero(1u8), 7); - assert_eq!(ctlz_nonzero(1i8), 7); - assert_eq!(ctlz_nonzero(1u16), 15); - assert_eq!(ctlz_nonzero(1i16), 15); - assert_eq!(ctlz_nonzero(1u32), 31); - assert_eq!(ctlz_nonzero(1i32), 31); - assert_eq!(ctlz_nonzero(1u64), 63); - assert_eq!(ctlz_nonzero(1i64), 63); + [assert_eq!(ctlz_nonzero(1u8), 7), assert_eq!(ctlz_nonzero(1i8), 7)]; + [assert_eq!(ctlz_nonzero(1u16), 15), assert_eq!(ctlz_nonzero(1i16), 15)]; + [assert_eq!(ctlz_nonzero(1u32), 31), assert_eq!(ctlz_nonzero(1i32), 31)]; + [assert_eq!(ctlz_nonzero(1u64), 63), assert_eq!(ctlz_nonzero(1i64), 63)]; - assert_eq!(ctlz_nonzero(10u8), 4); - assert_eq!(ctlz_nonzero(10i8), 4); - assert_eq!(ctlz_nonzero(10u16), 12); - assert_eq!(ctlz_nonzero(10i16), 12); - assert_eq!(ctlz_nonzero(10u32), 28); - assert_eq!(ctlz_nonzero(10i32), 28); - assert_eq!(ctlz_nonzero(10u64), 60); - assert_eq!(ctlz_nonzero(10i64), 60); + [assert_eq!(ctlz_nonzero(10u8), 4), assert_eq!(ctlz_nonzero(10i8), 4)]; + [assert_eq!(ctlz_nonzero(10u16), 12), assert_eq!(ctlz_nonzero(10i16), 12)]; + [assert_eq!(ctlz_nonzero(10u32), 28), assert_eq!(ctlz_nonzero(10i32), 28)]; + [assert_eq!(ctlz_nonzero(10u64), 60), assert_eq!(ctlz_nonzero(10i64), 60)]; - assert_eq!(ctlz_nonzero(100u8), 1); - assert_eq!(ctlz_nonzero(100i8), 1); - assert_eq!(ctlz_nonzero(100u16), 9); - assert_eq!(ctlz_nonzero(100i16), 9); - assert_eq!(ctlz_nonzero(100u32), 25); - assert_eq!(ctlz_nonzero(100i32), 25); - assert_eq!(ctlz_nonzero(100u64), 57); - assert_eq!(ctlz_nonzero(100i64), 57); + [assert_eq!(ctlz_nonzero(100u8), 1), assert_eq!(ctlz_nonzero(100i8), 1)]; + [assert_eq!(ctlz_nonzero(100u16), 9), assert_eq!(ctlz_nonzero(100i16), 9)]; + [assert_eq!(ctlz_nonzero(100u32), 25), assert_eq!(ctlz_nonzero(100i32), 25)]; + [assert_eq!(ctlz_nonzero(100u64), 57), assert_eq!(ctlz_nonzero(100i64), 57)]; - assert_eq!(cttz(-1i8 as u8), 0); - assert_eq!(cttz(-1i8), 0); - assert_eq!(cttz(-1i16 as u16), 0); - assert_eq!(cttz(-1i16), 0); - assert_eq!(cttz(-1i32 as u32), 0); - assert_eq!(cttz(-1i32), 0); - assert_eq!(cttz(-1i64 as u64), 0); - assert_eq!(cttz(-1i64), 0); + [assert_eq!(cttz(-1i8 as u8), 0), assert_eq!(cttz(-1i8), 0)]; + [assert_eq!(cttz(-1i16 as u16), 0), assert_eq!(cttz(-1i16), 0)]; + [assert_eq!(cttz(-1i32 as u32), 0), assert_eq!(cttz(-1i32), 0)]; + [assert_eq!(cttz(-1i64 as u64), 0), assert_eq!(cttz(-1i64), 0)]; - assert_eq!(cttz(0u8), 8); - assert_eq!(cttz(0i8), 8); - assert_eq!(cttz(0u16), 16); - assert_eq!(cttz(0i16), 16); - assert_eq!(cttz(0u32), 32); - assert_eq!(cttz(0i32), 32); - assert_eq!(cttz(0u64), 64); - assert_eq!(cttz(0i64), 64); + [assert_eq!(cttz(0u8), 8), assert_eq!(cttz(0i8), 8)]; + [assert_eq!(cttz(0u16), 16), assert_eq!(cttz(0i16), 16)]; + [assert_eq!(cttz(0u32), 32), assert_eq!(cttz(0i32), 32)]; + [assert_eq!(cttz(0u64), 64), assert_eq!(cttz(0i64), 64)]; - assert_eq!(cttz(1u8), 0); - assert_eq!(cttz(1i8), 0); - assert_eq!(cttz(1u16), 0); - assert_eq!(cttz(1i16), 0); - assert_eq!(cttz(1u32), 0); - assert_eq!(cttz(1i32), 0); - assert_eq!(cttz(1u64), 0); - assert_eq!(cttz(1i64), 0); + [assert_eq!(cttz(1u8), 0), assert_eq!(cttz(1i8), 0)]; + [assert_eq!(cttz(1u16), 0), assert_eq!(cttz(1i16), 0)]; + [assert_eq!(cttz(1u32), 0), assert_eq!(cttz(1i32), 0)]; + [assert_eq!(cttz(1u64), 0), assert_eq!(cttz(1i64), 0)]; - assert_eq!(cttz(10u8), 1); - assert_eq!(cttz(10i8), 1); - assert_eq!(cttz(10u16), 1); - assert_eq!(cttz(10i16), 1); - assert_eq!(cttz(10u32), 1); - assert_eq!(cttz(10i32), 1); - assert_eq!(cttz(10u64), 1); - assert_eq!(cttz(10i64), 1); + [assert_eq!(cttz(10u8), 1), assert_eq!(cttz(10i8), 1)]; + [assert_eq!(cttz(10u16), 1), assert_eq!(cttz(10i16), 1)]; + [assert_eq!(cttz(10u32), 1), assert_eq!(cttz(10i32), 1)]; + [assert_eq!(cttz(10u64), 1), assert_eq!(cttz(10i64), 1)]; - assert_eq!(cttz(100u8), 2); - assert_eq!(cttz(100i8), 2); - assert_eq!(cttz(100u16), 2); - assert_eq!(cttz(100i16), 2); - assert_eq!(cttz(100u32), 2); - assert_eq!(cttz(100i32), 2); - assert_eq!(cttz(100u64), 2); - assert_eq!(cttz(100i64), 2); + [assert_eq!(cttz(100u8), 2), assert_eq!(cttz(100i8), 2)]; + [assert_eq!(cttz(100u16), 2), assert_eq!(cttz(100i16), 2)]; + [assert_eq!(cttz(100u32), 2), assert_eq!(cttz(100i32), 2)]; + [assert_eq!(cttz(100u64), 2), assert_eq!(cttz(100i64), 2)]; - assert_eq!(cttz_nonzero(-1i8 as u8), 0); - assert_eq!(cttz_nonzero(-1i8), 0); - assert_eq!(cttz_nonzero(-1i16 as u16), 0); - assert_eq!(cttz_nonzero(-1i16), 0); - assert_eq!(cttz_nonzero(-1i32 as u32), 0); - assert_eq!(cttz_nonzero(-1i32), 0); - assert_eq!(cttz_nonzero(-1i64 as u64), 0); - assert_eq!(cttz_nonzero(-1i64), 0); + [assert_eq!(cttz_nonzero(-1i8 as u8), 0), assert_eq!(cttz_nonzero(-1i8), 0)]; + [assert_eq!(cttz_nonzero(-1i16 as u16), 0), assert_eq!(cttz_nonzero(-1i16), 0)]; + [assert_eq!(cttz_nonzero(-1i32 as u32), 0), assert_eq!(cttz_nonzero(-1i32), 0)]; + [assert_eq!(cttz_nonzero(-1i64 as u64), 0), assert_eq!(cttz_nonzero(-1i64), 0)]; - assert_eq!(cttz_nonzero(1u8), 0); - assert_eq!(cttz_nonzero(1i8), 0); - assert_eq!(cttz_nonzero(1u16), 0); - assert_eq!(cttz_nonzero(1i16), 0); - assert_eq!(cttz_nonzero(1u32), 0); - assert_eq!(cttz_nonzero(1i32), 0); - assert_eq!(cttz_nonzero(1u64), 0); - assert_eq!(cttz_nonzero(1i64), 0); + [assert_eq!(cttz_nonzero(1u8), 0), assert_eq!(cttz_nonzero(1i8), 0)]; + [assert_eq!(cttz_nonzero(1u16), 0), assert_eq!(cttz_nonzero(1i16), 0)]; + [assert_eq!(cttz_nonzero(1u32), 0), assert_eq!(cttz_nonzero(1i32), 0)]; + [assert_eq!(cttz_nonzero(1u64), 0), assert_eq!(cttz_nonzero(1i64), 0)]; - assert_eq!(cttz_nonzero(10u8), 1); - assert_eq!(cttz_nonzero(10i8), 1); - assert_eq!(cttz_nonzero(10u16), 1); - assert_eq!(cttz_nonzero(10i16), 1); - assert_eq!(cttz_nonzero(10u32), 1); - assert_eq!(cttz_nonzero(10i32), 1); - assert_eq!(cttz_nonzero(10u64), 1); - assert_eq!(cttz_nonzero(10i64), 1); + [assert_eq!(cttz_nonzero(10u8), 1), assert_eq!(cttz_nonzero(10i8), 1)]; + [assert_eq!(cttz_nonzero(10u16), 1), assert_eq!(cttz_nonzero(10i16), 1)]; + [assert_eq!(cttz_nonzero(10u32), 1), assert_eq!(cttz_nonzero(10i32), 1)]; + [assert_eq!(cttz_nonzero(10u64), 1), assert_eq!(cttz_nonzero(10i64), 1)]; - assert_eq!(cttz_nonzero(100u8), 2); - assert_eq!(cttz_nonzero(100i8), 2); - assert_eq!(cttz_nonzero(100u16), 2); - assert_eq!(cttz_nonzero(100i16), 2); - assert_eq!(cttz_nonzero(100u32), 2); - assert_eq!(cttz_nonzero(100i32), 2); - assert_eq!(cttz_nonzero(100u64), 2); - assert_eq!(cttz_nonzero(100i64), 2); + [assert_eq!(cttz_nonzero(100u8), 2), assert_eq!(cttz_nonzero(100i8), 2)]; + [assert_eq!(cttz_nonzero(100u16), 2), assert_eq!(cttz_nonzero(100i16), 2)]; + [assert_eq!(cttz_nonzero(100u32), 2), assert_eq!(cttz_nonzero(100i32), 2)]; + [assert_eq!(cttz_nonzero(100u64), 2), assert_eq!(cttz_nonzero(100i64), 2)]; assert_eq!(bswap(0x0Au8), 0x0A); // no-op assert_eq!(bswap(0x0Ai8), 0x0A); // no-op diff --git a/tests/pass/ptr_int_casts.rs b/tests/pass/ptr_int_casts.rs index aa60fd0c81ef..889b6bd04f9d 100644 --- a/tests/pass/ptr_int_casts.rs +++ b/tests/pass/ptr_int_casts.rs @@ -20,8 +20,8 @@ fn ptr_int_casts() { *val = (1 as *const u8).wrapping_offset(-4); assert_eq!(*val as usize, usize::MAX - 2); + // ptr-int-ptr { - // ptr-int-ptr let x = 13; let mut y = &x as &_ as *const _ as usize; y += 13; @@ -30,8 +30,8 @@ fn ptr_int_casts() { assert!(eq_ref(&x, unsafe { &*y })); } + // fnptr-int-fnptr { - // fnptr-int-fnptr let x: fn() -> i32 = f; let y: *mut u8 = unsafe { mem::transmute(x as fn() -> i32) }; let mut y = y as usize; diff --git a/tests/pass/sums.rs b/tests/pass/sums.rs index 84ff96942002..3256d4c65116 100644 --- a/tests/pass/sums.rs +++ b/tests/pass/sums.rs @@ -1,7 +1,7 @@ #[derive(Debug, PartialEq)] enum Unit { - Unit(()), -} // Force non-C-enum representation. + Unit(()), // Force non-C-enum representation. +} fn return_unit() -> Unit { Unit::Unit(()) @@ -9,9 +9,9 @@ fn return_unit() -> Unit { #[derive(Debug, PartialEq)] enum MyBool { - False(()), + False(()), // Force non-C-enum representation. True(()), -} // Force non-C-enum representation. +} fn return_true() -> MyBool { MyBool::True(()) From 599a0cf4fc0440ec391b6d1fc736bb68dd28028b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 22 Jun 2022 08:52:48 -0700 Subject: [PATCH 3326/5092] fmt --- ui_test/src/comments.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index d50d6a534573..43c687e9c9a5 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -31,7 +31,6 @@ pub(crate) struct Comments { pub error_matches: Vec, } - /// The conditions used for "ignore" and "only" filters. #[derive(Debug)] pub(crate) enum Condition { @@ -55,7 +54,9 @@ pub(crate) struct ErrorMatch { impl Condition { fn parse(c: &str) -> Self { if let Some(bits) = c.strip_suffix("bit") { - let bits: u8 = bits.parse().expect("ignore/only filter ending in 'bit' must be of the form 'Nbit' for some integer N"); + let bits: u8 = bits.parse().expect( + "ignore/only filter ending in 'bit' must be of the form 'Nbit' for some integer N", + ); Condition::Bitwidth(bits) } else { Condition::Target(c.to_owned()) From 0eb8e60ed0f4a83f955a0a2433aafd7b1b07b54c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 22 Jun 2022 10:02:33 -0700 Subject: [PATCH 3327/5092] avoid setting both RUSTC and RUSTC_WRAPPER --- cargo-miri/bin.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 6a5e5dc3913a..a7be5843d4e6 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -638,6 +638,14 @@ fn phase_cargo_miri(mut args: env::Args) { ); } cmd.env("RUSTC_WRAPPER", &cargo_miri_path); + // Having both `RUSTC_WRAPPER` and `RUSTC` set does some odd things, so let's avoid that. + // See . + if env::var_os("RUSTC").is_some() && env::var_os("MIRI").is_none() { + println!( + "WARNING: Ignoring `RUSTC` environment variable; set `MIRI` if you want to control the binary used as the driver." + ); + } + cmd.env_remove("RUSTC"); let runner_env_name = |triple: &str| format!("CARGO_TARGET_{}_RUNNER", triple.to_uppercase().replace('-', "_")); From c4ffe680e3fdb2240d810a311327d1268681af1d Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 21 Jun 2022 16:30:45 +0000 Subject: [PATCH 3328/5092] Require local annotations for local diagnostics --- tests/fail/abort-terminator.rs | 3 +-- tests/fail/concurrency/too_few_args.rs | 3 +-- tests/fail/concurrency/too_many_args.rs | 3 +-- tests/fail/concurrency/unwind_top_of_stack.rs | 2 +- .../concurrency/unwind_top_of_stack.stderr | 1 + .../intrinsics/overflowing-unchecked-rsh.rs | 3 +-- .../intrinsics/uninit_uninhabited_type.rs | 2 +- tests/fail/intrinsics/zero_fn_ptr.rs | 3 +-- tests/fail/panic/bad_unwind.rs | 2 +- ...wlock_read_write_deadlock_single_thread.rs | 3 +-- ...wlock_write_read_deadlock_single_thread.rs | 3 +-- ...lock_write_write_deadlock_single_thread.rs | 3 +-- tests/fail/transmute_fat1.rs | 15 +++++++++------ tests/fail/transmute_fat1.stderr | 4 ++-- tests/fail/unaligned_pointers/alignment.rs | 12 ++++++------ .../fail/unaligned_pointers/alignment.stderr | 4 ++-- ui_test/src/lib.rs | 19 +------------------ ui_test/src/rustc_stderr.rs | 2 +- 18 files changed, 33 insertions(+), 54 deletions(-) diff --git a/tests/fail/abort-terminator.rs b/tests/fail/abort-terminator.rs index 20859047c620..fcdeaa0ffea2 100644 --- a/tests/fail/abort-terminator.rs +++ b/tests/fail/abort-terminator.rs @@ -1,7 +1,6 @@ -// error-pattern: the program aborted #![feature(c_unwind)] -extern "C" fn panic_abort() { +extern "C" fn panic_abort() { //~ ERROR: the program aborted panic!() } diff --git a/tests/fail/concurrency/too_few_args.rs b/tests/fail/concurrency/too_few_args.rs index 35412353ace4..23fa38d88128 100644 --- a/tests/fail/concurrency/too_few_args.rs +++ b/tests/fail/concurrency/too_few_args.rs @@ -1,5 +1,4 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// error-pattern: callee has fewer arguments than expected //! The thread function must have exactly one argument. @@ -10,7 +9,7 @@ extern crate libc; use std::{mem, ptr}; extern "C" fn thread_start() -> *mut libc::c_void { - panic!() + panic!() //~ ERROR: callee has fewer arguments than expected } fn main() { diff --git a/tests/fail/concurrency/too_many_args.rs b/tests/fail/concurrency/too_many_args.rs index b6156091b0aa..af5a377a04e4 100644 --- a/tests/fail/concurrency/too_many_args.rs +++ b/tests/fail/concurrency/too_many_args.rs @@ -1,5 +1,4 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// error-pattern: callee has more arguments than expected //! The thread function must have exactly one argument. @@ -10,7 +9,7 @@ extern crate libc; use std::{mem, ptr}; extern "C" fn thread_start(_null: *mut libc::c_void, _x: i32) -> *mut libc::c_void { - panic!() + panic!() //~ ERROR: callee has more arguments than expected } fn main() { diff --git a/tests/fail/concurrency/unwind_top_of_stack.rs b/tests/fail/concurrency/unwind_top_of_stack.rs index e1c17d07b286..9e6088be7a7e 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.rs +++ b/tests/fail/concurrency/unwind_top_of_stack.rs @@ -1,6 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-disable-abi-check -// error-pattern: unwinding past the topmost frame of the stack //! Unwinding past the top frame of a stack is Undefined Behavior. @@ -11,6 +10,7 @@ extern crate libc; use std::{mem, ptr}; extern "C-unwind" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { +//~^ ERROR unwinding past the topmost frame of the stack panic!() } diff --git a/tests/fail/concurrency/unwind_top_of_stack.stderr b/tests/fail/concurrency/unwind_top_of_stack.stderr index 35d6f7c38494..f72f01a9d6e9 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.stderr +++ b/tests/fail/concurrency/unwind_top_of_stack.stderr @@ -4,6 +4,7 @@ error: Undefined Behavior: unwinding past the topmost frame of the stack --> $DIR/unwind_top_of_stack.rs:LL:CC | LL | / extern "C-unwind" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { +LL | | LL | | panic!() LL | | } | |_^ unwinding past the topmost frame of the stack diff --git a/tests/fail/intrinsics/overflowing-unchecked-rsh.rs b/tests/fail/intrinsics/overflowing-unchecked-rsh.rs index 6402f4bb74c6..958a9f90ed98 100644 --- a/tests/fail/intrinsics/overflowing-unchecked-rsh.rs +++ b/tests/fail/intrinsics/overflowing-unchecked-rsh.rs @@ -2,10 +2,9 @@ use std::intrinsics::*; -// error-pattern: overflowing shift by 64 in `unchecked_shr` - fn main() { unsafe { let _n = unchecked_shr(1i64, 64); + //~^ ERROR: overflowing shift by 64 in `unchecked_shr` } } diff --git a/tests/fail/intrinsics/uninit_uninhabited_type.rs b/tests/fail/intrinsics/uninit_uninhabited_type.rs index 2337ff0f6c26..e606d8b283c8 100644 --- a/tests/fail/intrinsics/uninit_uninhabited_type.rs +++ b/tests/fail/intrinsics/uninit_uninhabited_type.rs @@ -1,7 +1,7 @@ -// error-pattern: attempted to instantiate uninhabited type `!` #![feature(never_type)] #[allow(deprecated, invalid_value)] fn main() { unsafe { std::mem::uninitialized::() }; + //~^ ERROR: attempted to instantiate uninhabited type `!` } diff --git a/tests/fail/intrinsics/zero_fn_ptr.rs b/tests/fail/intrinsics/zero_fn_ptr.rs index 098a8e01347f..6d9ae14c5c47 100644 --- a/tests/fail/intrinsics/zero_fn_ptr.rs +++ b/tests/fail/intrinsics/zero_fn_ptr.rs @@ -1,6 +1,5 @@ -// error-pattern: attempted to zero-initialize type `fn()`, which is invalid - #[allow(deprecated, invalid_value)] fn main() { unsafe { std::mem::zeroed::() }; + //~^ ERROR: attempted to zero-initialize type `fn()`, which is invalid } diff --git a/tests/fail/panic/bad_unwind.rs b/tests/fail/panic/bad_unwind.rs index 1feee9a12ae0..370b372a7d37 100644 --- a/tests/fail/panic/bad_unwind.rs +++ b/tests/fail/panic/bad_unwind.rs @@ -1,4 +1,3 @@ -// error-pattern: unwinding past a stack frame that does not allow unwinding #![feature(c_unwind)] //! Unwinding when the caller ABI is "C" (without "-unwind") is UB. @@ -11,4 +10,5 @@ fn main() { let unwind: extern "C-unwind" fn() = unwind; let unwind: extern "C" fn() = unsafe { std::mem::transmute(unwind) }; std::panic::catch_unwind(|| unwind()).unwrap_err(); + //~^ ERROR: unwinding past a stack frame that does not allow unwinding } diff --git a/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs index da45d062d03b..dd4707d60e4c 100644 --- a/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs +++ b/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs @@ -1,5 +1,4 @@ // ignore-windows: No libc on Windows -// error-pattern: deadlock #![feature(rustc_private)] @@ -9,6 +8,6 @@ fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); - libc::pthread_rwlock_wrlock(rw.get()); + libc::pthread_rwlock_wrlock(rw.get()); //~ ERROR: deadlock } } diff --git a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs index ee2e57a9ab37..1b460e7174d2 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs @@ -1,5 +1,4 @@ // ignore-windows: No libc on Windows -// error-pattern: deadlock #![feature(rustc_private)] @@ -9,6 +8,6 @@ fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); - libc::pthread_rwlock_rdlock(rw.get()); + libc::pthread_rwlock_rdlock(rw.get()); //~ ERROR: deadlock } } diff --git a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs index f0404f202e56..cc327ec46bc2 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs @@ -1,5 +1,4 @@ // ignore-windows: No libc on Windows -// error-pattern: deadlock #![feature(rustc_private)] @@ -9,6 +8,6 @@ fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); - libc::pthread_rwlock_wrlock(rw.get()); + libc::pthread_rwlock_wrlock(rw.get()); //~ ERROR: deadlock } } diff --git a/tests/fail/transmute_fat1.rs b/tests/fail/transmute_fat1.rs index f9fa2ace7570..79286f3e27dd 100644 --- a/tests/fail/transmute_fat1.rs +++ b/tests/fail/transmute_fat1.rs @@ -1,10 +1,13 @@ -// error-pattern: type validation failed: encountered a pointer -// normalize-stderr-test: "\[u8; (08|16)\]" -> "$$ARRAY" +#[cfg(target_pointer_width = "64")] +const N: usize = 16; + +#[cfg(target_pointer_width = "32")] +const N: usize = 8; fn main() { - #[cfg(target_pointer_width = "64")] - let bad = unsafe { std::mem::transmute::<&[u8], [u8; 16]>(&[1u8]) }; - #[cfg(target_pointer_width = "32")] - let bad = unsafe { std::mem::transmute::<&[u8], [u8; 08]>(&[1u8]) }; + let bad = unsafe { + std::mem::transmute::<&[u8], [u8; N]>(&[1u8]) + //~^ ERROR: type validation failed: encountered a pointer + }; let _val = bad[0] + bad[bad.len() - 1]; } diff --git a/tests/fail/transmute_fat1.stderr b/tests/fail/transmute_fat1.stderr index 2b095dc3c1c0..baf6195f92ad 100644 --- a/tests/fail/transmute_fat1.stderr +++ b/tests/fail/transmute_fat1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: type validation failed: encountered a pointer, but expected plain (non-pointer) bytes --> $DIR/transmute_fat1.rs:LL:CC | -LL | let bad = unsafe { std::mem::transmute::<&[u8], $ARRAY>(&[1u8]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected plain (non-pointer) bytes +LL | std::mem::transmute::<&[u8], [u8; N]>(&[1u8]) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected plain (non-pointer) bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/unaligned_pointers/alignment.rs b/tests/fail/unaligned_pointers/alignment.rs index e99d8c967cdd..abee75ec71b1 100644 --- a/tests/fail/unaligned_pointers/alignment.rs +++ b/tests/fail/unaligned_pointers/alignment.rs @@ -1,14 +1,14 @@ -// error-pattern: but alignment 4 is required -// normalize-stderr-test: "\.add\(1\)" -> " " +// normalize-stderr-test: "\| +\^+" -> "| ^" fn main() { // No retry needed, this fails reliably. let mut x = [0u8; 20]; let x_ptr: *mut u8 = x.as_mut_ptr(); - // At least one of these is definitely unaligned. + #[rustfmt::skip] unsafe { - *(x_ptr as *mut u32) = 42; - *(x_ptr.add(1) as *mut u32) = 42; - } + // At least one of these is definitely unaligned. + *(x_ptr as *mut u32) = 42; *(x_ptr.add(1) as *mut u32) = 42; + //~^ ERROR: but alignment 4 is required + }; } diff --git a/tests/fail/unaligned_pointers/alignment.stderr b/tests/fail/unaligned_pointers/alignment.stderr index 0e6ca83366ad..5f691d049095 100644 --- a/tests/fail/unaligned_pointers/alignment.stderr +++ b/tests/fail/unaligned_pointers/alignment.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required --> $DIR/alignment.rs:LL:CC | -LL | *(x_ptr as *mut u32) = 42; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required +LL | *(x_ptr as *mut u32) = 42; *(x_ptr.add(1) as *mut u32) = 42; + | ^ accessing memory with alignment ALIGN, but alignment ALIGN is required | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 970622144680..30e1296f7b39 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -374,8 +374,6 @@ fn check_annotations( comments: &Comments, ) { if let Some((ref error_pattern, definition_line)) = comments.error_pattern { - let mut found = false; - // first check the diagnostics messages outside of our file. We check this first, so that // you can mix in-file annotations with // error-pattern annotations, even if there is overlap // in the messages. @@ -384,22 +382,7 @@ fn check_annotations( .position(|msg| msg.message.contains(error_pattern)) { messages_from_unknown_file_or_line.remove(i); - found = true; - } - - // if nothing was found, check the ones inside our file. We permit this because some tests may have - // flaky line numbers for their messages. - if !found { - for line in &mut messages { - if let Some(i) = line.iter().position(|msg| msg.message.contains(error_pattern)) { - line.remove(i); - found = true; - break; - } - } - } - - if !found { + } else { errors.push(Error::PatternNotFound { pattern: error_pattern.to_string(), definition_line, diff --git a/ui_test/src/rustc_stderr.rs b/ui_test/src/rustc_stderr.rs index 203014c50d52..2d3845752e9a 100644 --- a/ui_test/src/rustc_stderr.rs +++ b/ui_test/src/rustc_stderr.rs @@ -116,7 +116,7 @@ impl Span { } pub(crate) fn filter_annotations_from_rendered(rendered: &str) -> std::borrow::Cow<'_, str> { - let annotations = Regex::new(r"\s*//~.*").unwrap(); + let annotations = Regex::new(r"\s*//(\[[^\]]\])?~.*").unwrap(); annotations.replace_all(&rendered, "") } From e286090d7a66f0213aafdc90d5fbd856dd5c05b5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 Jun 2022 13:57:27 -0400 Subject: [PATCH 3329/5092] make rustfmt mandatory and used pinned toolchain --- .github/workflows/ci.yml | 43 ++++++++++++++++------------------------ 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ee65d58dccad..85937a8e4445 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -86,8 +86,8 @@ jobs: - name: Test run: bash ./ci.sh - clippy: - name: clippy + rustdoc + style: + name: style checks runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -95,33 +95,24 @@ jobs: # We need a toolchain that can actually build Miri, just a nightly won't do. run: | cargo install rustup-toolchain-install-master # TODO: cache this? - ./rustup-toolchain "" -c clippy - - name: Clippy (miri) + ./rustup-toolchain "" -c clippy -c rustfmt + - name: rustfmt (miri, ui_test) + run: cargo fmt --all --check + - name: rustfmt (everything else) + # TODO: Add `tests` (work in progress). + # Maybe change to `find . -name '*.rs'`, superseding the previous step. + run: | + find bench-cargo-miri benches cargo-miri test-cargo-miri -name '*.rs' \ + | xargs rustfmt --edition=2021 --config-path ./rustfmt.toml --check + - name: clippy (miri) run: cargo clippy --all-targets -- -D warnings #- name: Clippy (ui_test) # run: cargo clippy --manifest-path ui_test/Cargo.toml --all-targets -- -D warnings - - name: Clippy (cargo-miri) + - name: clippy (cargo-miri) run: cargo clippy --manifest-path cargo-miri/Cargo.toml --all-targets -- -D warnings - - name: Rustdoc + - name: rustdoc run: RUSTDOCFLAGS="-Dwarnings" cargo doc --document-private-items - fmt: - name: formatting (ignored by bors) - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Install latest nightly - run: | - rustup toolchain install nightly --component rustfmt - rustup override set nightly - - name: Formatting (miri, ui_test) - run: cargo fmt --all --check - - name: Formatting (everything else) - # TODO: Add `tests` (work in progress). - # Maybe change to `find . -name '*.rs'`, superseding the previous step. - run: find bench-cargo-miri benches cargo-miri test-cargo-miri -name '*.rs' - | xargs rustfmt --edition=2021 --config-path ./rustfmt.toml --check - # These jobs doesn't actually test anything, but they're only used to tell # bors the build completed, as there is no practical way to detect when a # workflow is successful listening to webhooks only. @@ -131,7 +122,7 @@ jobs: end-success: name: bors build finished runs-on: ubuntu-latest - needs: [build, clippy] + needs: [build, style] if: github.event.pusher.name == 'bors' && success() steps: - name: mark the job as a success @@ -139,7 +130,7 @@ jobs: end-failure: name: bors build finished runs-on: ubuntu-latest - needs: [build, clippy] + needs: [build, style] if: github.event.pusher.name == 'bors' && (failure() || cancelled()) steps: - name: mark the job as a failure @@ -149,7 +140,7 @@ jobs: cron-fail-notify: name: cronjob failure notification runs-on: ubuntu-latest - needs: [build, clippy] + needs: [build, style] if: github.event_name == 'schedule' && (failure() || cancelled()) steps: - name: Install zulip-send From 2cbc461389b27fdc50c06a4e551bdc5ee07c7076 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 22 Jun 2022 05:00:07 -0700 Subject: [PATCH 3330/5092] Add './miri fmt' and use it in CI --- .github/workflows/ci.yml | 12 +++--------- miri | 9 ++++++++- rustup-toolchain | 2 +- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 85937a8e4445..45c0bea370ac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -95,15 +95,9 @@ jobs: # We need a toolchain that can actually build Miri, just a nightly won't do. run: | cargo install rustup-toolchain-install-master # TODO: cache this? - ./rustup-toolchain "" -c clippy -c rustfmt - - name: rustfmt (miri, ui_test) - run: cargo fmt --all --check - - name: rustfmt (everything else) - # TODO: Add `tests` (work in progress). - # Maybe change to `find . -name '*.rs'`, superseding the previous step. - run: | - find bench-cargo-miri benches cargo-miri test-cargo-miri -name '*.rs' \ - | xargs rustfmt --edition=2021 --config-path ./rustfmt.toml --check + ./rustup-toolchain "" -c clippy + - name: rustfmt + run: ./miri fmt --check - name: clippy (miri) run: cargo clippy --all-targets -- -D warnings #- name: Clippy (ui_test) diff --git a/miri b/miri index 5c9cb81885c9..e89a9e380fff 100755 --- a/miri +++ b/miri @@ -21,10 +21,13 @@ to the final `cargo test` invocation. ./miri run : Build miri, set up a sysroot and then run the driver with the given . -All commands also exist in a "-debug" variant (e.g. "./miri run-debug +The commands above also exist in a "-debug" variant (e.g. "./miri run-debug ") which uses debug builds instead of release builds, for faster build times and slower execution times. +./miri fmt : +Format all sources and tests. are passed to `rustfmt`. + ENVIRONMENT VARIABLES MIRI_SYSROOT: @@ -156,6 +159,10 @@ run|run-debug) # Then run the actual command. exec cargo run $CARGO_BUILD_FLAGS -- --sysroot "$MIRI_SYSROOT" "$@" ;; +fmt) + find "$MIRIDIR" -not \( -name target -prune \) -name '*.rs' \ + | xargs rustfmt --edition=2021 --config-path "$MIRIDIR/rustfmt.toml" "$@" + ;; *) if [ -n "$COMMAND" ]; then echo "Unknown command: $COMMAND" diff --git a/rustup-toolchain b/rustup-toolchain index ca5508e225a1..34472c727f62 100755 --- a/rustup-toolchain +++ b/rustup-toolchain @@ -42,7 +42,7 @@ fi # Install and setup new toolchain. rustup toolchain uninstall miri -rustup-toolchain-install-master -n miri -c cargo -c rust-src -c rustc-dev -c llvm-tools "$@" -- "$NEW_COMMIT" +rustup-toolchain-install-master -n miri -c cargo -c rust-src -c rustc-dev -c llvm-tools -c rustfmt "$@" -- "$NEW_COMMIT" rustup override set miri # Cleanup. From a23eb46b5b5f104a3ffe66ae717d6c2563918a95 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 23 Jun 2022 12:50:44 -0700 Subject: [PATCH 3331/5092] Format late arrivals with rustfmt --- tests/fail/abort-terminator.rs | 3 ++- tests/fail/concurrency/unwind_top_of_stack.rs | 2 +- tests/pass/concurrency/sync_nopreempt.rs | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/fail/abort-terminator.rs b/tests/fail/abort-terminator.rs index fcdeaa0ffea2..195be4ca41f8 100644 --- a/tests/fail/abort-terminator.rs +++ b/tests/fail/abort-terminator.rs @@ -1,6 +1,7 @@ #![feature(c_unwind)] -extern "C" fn panic_abort() { //~ ERROR: the program aborted +extern "C" fn panic_abort() { + //~ ERROR: the program aborted panic!() } diff --git a/tests/fail/concurrency/unwind_top_of_stack.rs b/tests/fail/concurrency/unwind_top_of_stack.rs index 9e6088be7a7e..39f7ae8bafb9 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.rs +++ b/tests/fail/concurrency/unwind_top_of_stack.rs @@ -10,7 +10,7 @@ extern crate libc; use std::{mem, ptr}; extern "C-unwind" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { -//~^ ERROR unwinding past the topmost frame of the stack + //~^ ERROR unwinding past the topmost frame of the stack panic!() } diff --git a/tests/pass/concurrency/sync_nopreempt.rs b/tests/pass/concurrency/sync_nopreempt.rs index 38dbeb575d64..8895d62df95f 100644 --- a/tests/pass/concurrency/sync_nopreempt.rs +++ b/tests/pass/concurrency/sync_nopreempt.rs @@ -2,7 +2,7 @@ // We are making scheduler assumptions here. // compile-flags: -Zmiri-strict-provenance -Zmiri-preemption-rate=0 -use std::sync::{Condvar, Mutex, Arc}; +use std::sync::{Arc, Condvar, Mutex}; use std::thread; fn check_conditional_variables_notify_all() { From 8833197a62522cb01f73d0a1074e9a0cfa6ac5da Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 23 Jun 2022 12:51:40 -0700 Subject: [PATCH 3332/5092] Manual adjustments --- tests/fail/abort-terminator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/fail/abort-terminator.rs b/tests/fail/abort-terminator.rs index 195be4ca41f8..c954443a2762 100644 --- a/tests/fail/abort-terminator.rs +++ b/tests/fail/abort-terminator.rs @@ -1,7 +1,7 @@ #![feature(c_unwind)] extern "C" fn panic_abort() { - //~ ERROR: the program aborted + //~^ ERROR: the program aborted panic!() } From e5f40ca9cb8ed9412543df307ba5d20fedb51c8f Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 23 Jun 2022 13:08:12 -0700 Subject: [PATCH 3333/5092] Bless stderr files after rustfmt --- tests/fail/abort-terminator.stderr | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/fail/abort-terminator.stderr b/tests/fail/abort-terminator.stderr index b096775e61d3..ec9ce76685b5 100644 --- a/tests/fail/abort-terminator.stderr +++ b/tests/fail/abort-terminator.stderr @@ -4,6 +4,7 @@ error: abnormal termination: the program aborted execution --> $DIR/abort-terminator.rs:LL:CC | LL | / extern "C" fn panic_abort() { +LL | | LL | | panic!() LL | | } | |_^ the program aborted execution From bb6fcb71c07a21d6655295de4ff0a130596d47f0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 24 Jun 2022 09:13:36 -0400 Subject: [PATCH 3334/5092] only one Zulip cron job topic per month --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 45c0bea370ac..c603d1f5d254 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -145,7 +145,7 @@ jobs: ZULIP_BOT_EMAIL: ${{ secrets.ZULIP_BOT_EMAIL }} ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }} run: | - ~/.local/bin/zulip-send --stream miri --subject "Cron Job Failure $(date -uI)" \ + ~/.local/bin/zulip-send --stream miri --subject "Cron Job Failure (miri, $(date -u +%Y-%m))" \ --message 'Dear @**RalfJ** and @**oli** It would appear that the Miri cron job build failed. Would you mind investigating this issue? From 57ce47b72814f8147d2cddb87628b17aa1084e74 Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Wed, 15 Jun 2022 14:55:21 -0500 Subject: [PATCH 3335/5092] Handle wildcard pointers in SB --- src/machine.rs | 26 +- src/stacked_borrows.rs | 244 +++++++++++++----- src/stacked_borrows/diagnostics.rs | 22 +- .../permissive_provenance_transmute.rs | 2 +- tests/fail/provenance/ptr_int_unexposed.rs | 2 +- tests/pass/ptr_int_from_exposed.rs | 2 +- tests/pass/stacked-borrows/int-to-ptr.rs | 72 +++++- 7 files changed, 282 insertions(+), 88 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index d14ddaa1a6bb..c2a7a34a9cc0 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -489,7 +489,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { type AllocExtra = AllocExtra; type PointerTag = Tag; - type TagExtra = SbTag; + type TagExtra = Option; type MemoryMap = MonoHashMap, Allocation)>; @@ -708,8 +708,24 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ptr: Pointer, ) -> InterpResult<'tcx> { match ptr.provenance { - Tag::Concrete(concrete) => - intptrcast::GlobalStateInner::expose_addr(ecx, concrete.alloc_id), + Tag::Concrete(ConcreteTag { alloc_id, sb }) => { + intptrcast::GlobalStateInner::expose_addr(ecx, alloc_id); + + let (size, _) = + ecx.get_alloc_size_and_align(alloc_id, AllocCheck::MaybeDead).unwrap(); + + // Function pointers and dead objects don't have an alloc_extra so we ignore them. + if let Ok(alloc_extra) = ecx.get_alloc_extra(alloc_id) { + if let Some(stacked_borrows) = &alloc_extra.stacked_borrows { + stacked_borrows.ptr_exposed( + alloc_id, + sb, + alloc_range(Size::from_bytes(0), size), + ecx.machine.stacked_borrows.as_ref().unwrap(), + )?; + } + } + } Tag::Wildcard => { // No need to do anything for wildcard pointers as // their provenances have already been previously exposed. @@ -728,8 +744,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { rel.map(|(alloc_id, size)| { let sb = match ptr.provenance { - Tag::Concrete(ConcreteTag { sb, .. }) => sb, - Tag::Wildcard => SbTag::Untagged, + Tag::Concrete(ConcreteTag { sb, .. }) => Some(sb), + Tag::Wildcard => None, }; (alloc_id, size, sb) }) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 0c537e0d7a5c..ad7569008e20 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -104,6 +104,10 @@ pub struct Stack { /// * Above a `SharedReadOnly` there can only be more `SharedReadOnly`. /// * Except for `Untagged`, no tag occurs in the stack more than once. borrows: Vec, + /// If this is `Some(id)`, then the actual current stack is unknown. What we do know + /// is that `borrows` are at the top of the stack, and below it are arbitrarily many items + /// whose `tag` is either `Untagged` or strictly less than `id`. + unknown_bottom: Option, } /// Extra per-allocation state. @@ -113,6 +117,8 @@ pub struct Stacks { stacks: RefCell>, /// Stores past operations on this allocation history: RefCell, + /// The set of tags that have been exposed + exposed_tags: RefCell>, } /// Extra global state, available to the memory access hooks. @@ -283,32 +289,72 @@ impl Permission { impl<'tcx> Stack { /// Find the item granting the given kind of access to the given tag, and return where /// it is on the stack. - fn find_granting(&self, access: AccessKind, tag: SbTag) -> Option { - self.borrows + // TODO: Doc ok with Some(index) or None if unknown_bottom used + // Err if does not match + fn find_granting( + &self, + access: AccessKind, + tag: Option, + exposed_tags: &FxHashSet, + ) -> Result, ()> { + let res = self + .borrows .iter() .enumerate() // we also need to know *where* in the stack .rev() // search top-to-bottom // Return permission of first item that grants access. // We require a permission with the right tag, ensuring U3 and F3. - .find_map( - |(idx, item)| { - if tag == item.tag && item.perm.grants(access) { Some(idx) } else { None } + .find_map(|(idx, item)| { + match tag { + Some(tag) if tag == item.tag && item.perm.grants(access) => Some(idx), + None if exposed_tags.contains(&item.tag) => Some(idx), + _ => None, + } + }); + + if res.is_some() { + return Ok(res); + } + + match self.unknown_bottom { + Some(id) => + match tag { + Some(tag) => + match tag { + SbTag::Tagged(tag_id) if tag_id < id => Ok(None), + SbTag::Untagged => Ok(None), + _ => Err(()), + }, + None => Ok(None), }, - ) + None => Err(()), + } } /// Find the first write-incompatible item above the given one -- /// i.e, find the height to which the stack will be truncated when writing to `granting`. - fn find_first_write_incompatible(&self, granting: usize) -> usize { - let perm = self.borrows[granting].perm; + fn find_first_write_incompatible(&self, granting: Option) -> usize { + let perm = if let Some(idx) = granting { + self.borrows[idx].perm + } else { + // I assume this has to be it? + Permission::SharedReadWrite + }; + match perm { Permission::SharedReadOnly => bug!("Cannot use SharedReadOnly for writing"), Permission::Disabled => bug!("Cannot use Disabled for anything"), // On a write, everything above us is incompatible. - Permission::Unique => granting + 1, + Permission::Unique => + if let Some(idx) = granting { + idx + 1 + } else { + 0 + }, Permission::SharedReadWrite => { // The SharedReadWrite *just* above us are compatible, to skip those. - let mut idx = granting + 1; + let mut idx = if let Some(idx) = granting { idx + 1 } else { 0 }; + while let Some(item) = self.borrows.get(idx) { if item.perm == Permission::SharedReadWrite { // Go on. @@ -380,58 +426,67 @@ impl<'tcx> Stack { fn access( &mut self, access: AccessKind, - tag: SbTag, + tag: Option, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &mut GlobalStateInner, current_span: &mut CurrentSpan<'_, '_, 'tcx>, alloc_history: &mut AllocHistory, + exposed_tags: &FxHashSet, ) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. - let granting_idx = self.find_granting(access, tag).ok_or_else(|| { + let granting_idx = self.find_granting(access, tag, exposed_tags).map_err(|_| { alloc_history.access_error(access, tag, alloc_id, alloc_range, offset, self) })?; // Step 2: Remove incompatible items above them. Make sure we do not remove protected // items. Behavior differs for reads and writes. - if access == AccessKind::Write { - // Remove everything above the write-compatible items, like a proper stack. This makes sure read-only and unique - // pointers become invalid on write accesses (ensures F2a, and ensures U2 for write accesses). - let first_incompatible_idx = self.find_first_write_incompatible(granting_idx); - for item in self.borrows.drain(first_incompatible_idx..).rev() { - trace!("access: popping item {:?}", item); - Stack::check_protector( - &item, - Some((tag, alloc_range, offset, access)), - global, - alloc_history, - )?; - alloc_history.log_invalidation(item.tag, alloc_range, current_span); - } - } else { - // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses. - // The reason this is not following the stack discipline (by removing the first Unique and - // everything on top of it) is that in `let raw = &mut *x as *mut _; let _val = *x;`, the second statement - // would pop the `Unique` from the reborrow of the first statement, and subsequently also pop the - // `SharedReadWrite` for `raw`. - // This pattern occurs a lot in the standard library: create a raw pointer, then also create a shared - // reference and use that. - // We *disable* instead of removing `Unique` to avoid "connecting" two neighbouring blocks of SRWs. - for idx in ((granting_idx + 1)..self.borrows.len()).rev() { - let item = &mut self.borrows[idx]; - if item.perm == Permission::Unique { - trace!("access: disabling item {:?}", item); + if let Some(tag) = tag { + if access == AccessKind::Write { + // Remove everything above the write-compatible items, like a proper stack. This makes sure read-only and unique + // pointers become invalid on write accesses (ensures F2a, and ensures U2 for write accesses). + let first_incompatible_idx = self.find_first_write_incompatible(granting_idx); + for item in self.borrows.drain(first_incompatible_idx..).rev() { + trace!("access: popping item {:?}", item); Stack::check_protector( - item, + &item, Some((tag, alloc_range, offset, access)), global, alloc_history, )?; - item.perm = Permission::Disabled; alloc_history.log_invalidation(item.tag, alloc_range, current_span); } + } else { + let start_idx = if let Some(idx) = granting_idx { idx + 1 } else { 0 }; + // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses. + // The reason this is not following the stack discipline (by removing the first Unique and + // everything on top of it) is that in `let raw = &mut *x as *mut _; let _val = *x;`, the second statement + // would pop the `Unique` from the reborrow of the first statement, and subsequently also pop the + // `SharedReadWrite` for `raw`. + // This pattern occurs a lot in the standard library: create a raw pointer, then also create a shared + // reference and use that. + // We *disable* instead of removing `Unique` to avoid "connecting" two neighbouring blocks of SRWs. + for idx in (start_idx..self.borrows.len()).rev() { + let item = &mut self.borrows[idx]; + + if item.perm == Permission::Unique { + trace!("access: disabling item {:?}", item); + Stack::check_protector( + item, + Some((tag, alloc_range, offset, access)), + global, + alloc_history, + )?; + item.perm = Permission::Disabled; + alloc_history.log_invalidation(item.tag, alloc_range, current_span); + } + } } + } else { + self.borrows.clear(); + // TODO + // self.borrows.push(ItemOrUnknown::Unknown(global.next_ptr_id)); } // Done. @@ -442,19 +497,20 @@ impl<'tcx> Stack { /// active protectors at all because we will remove all items. fn dealloc( &mut self, - tag: SbTag, + tag: Option, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &GlobalStateInner, alloc_history: &mut AllocHistory, + exposed_tags: &FxHashSet, ) -> InterpResult<'tcx> { // Step 1: Find granting item. - self.find_granting(AccessKind::Write, tag).ok_or_else(|| { + self.find_granting(AccessKind::Write, tag, exposed_tags).map_err(|_| { err_sb_ub(format!( "no item granting write access for deallocation to tag {:?} at {:?} found in borrow stack", tag, alloc_id, ), None, - alloc_history.get_logs_relevant_to(tag, alloc_range, offset, None), + tag.and_then(|tag| alloc_history.get_logs_relevant_to(tag, alloc_range, offset, None)), ) })?; @@ -462,7 +518,6 @@ impl<'tcx> Stack { for item in self.borrows.drain(..).rev() { Stack::check_protector(&item, None, global, alloc_history)?; } - Ok(()) } @@ -474,21 +529,17 @@ impl<'tcx> Stack { /// `range` that we are currently checking. fn grant( &mut self, - derived_from: SbTag, + derived_from: Option, new: Item, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &mut GlobalStateInner, current_span: &mut CurrentSpan<'_, '_, 'tcx>, alloc_history: &mut AllocHistory, + exposed_tags: &FxHashSet, ) -> InterpResult<'tcx> { // Figure out which access `perm` corresponds to. let access = if new.perm.grants(AccessKind::Write) { AccessKind::Write } else { AccessKind::Read }; - // Now we figure out which item grants our parent (`derived_from`) this kind of access. - // We use that to determine where to put the new item. - let granting_idx = self.find_granting(access, derived_from).ok_or_else(|| { - alloc_history.grant_error(derived_from, new, alloc_id, alloc_range, offset, self) - })?; // Compute where to put the new item. // Either way, we ensure that we insert the new item in a way such that between @@ -498,6 +549,21 @@ impl<'tcx> Stack { access == AccessKind::Write, "this case only makes sense for stack-like accesses" ); + + // Now we figure out which item grants our parent (`derived_from`) this kind of access. + // We use that to determine where to put the new item. + let granting_idx = + self.find_granting(access, derived_from, exposed_tags).map_err(|_| { + alloc_history.grant_error( + derived_from, + new, + alloc_id, + alloc_range, + offset, + self, + ) + })?; + // SharedReadWrite can coexist with "existing loans", meaning they don't act like a write // access. Instead of popping the stack, we insert the item at the place the stack would // be popped to (i.e., we insert it above all the write-compatible items). @@ -514,6 +580,7 @@ impl<'tcx> Stack { global, current_span, alloc_history, + exposed_tags, )?; // We insert "as far up as possible": We know only compatible items are remaining @@ -522,7 +589,6 @@ impl<'tcx> Stack { // This ensures U1 and F1. self.borrows.len() }; - // Put the new item there. As an optimization, deduplicate if it is equal to one of its new neighbors. if self.borrows[new_idx - 1] == new || self.borrows.get(new_idx) == Some(&new) { // Optimization applies, done. @@ -531,7 +597,6 @@ impl<'tcx> Stack { trace!("reborrow: adding item {:?}", new); self.borrows.insert(new_idx, new); } - Ok(()) } } @@ -542,11 +607,12 @@ impl<'tcx> Stacks { /// Creates new stack with initial tag. fn new(size: Size, perm: Permission, tag: SbTag) -> Self { let item = Item { perm, tag, protector: None }; - let stack = Stack { borrows: vec![item] }; + let stack = Stack { borrows: vec![item], unknown_bottom: None }; Stacks { stacks: RefCell::new(RangeMap::new(size, stack)), history: RefCell::new(AllocHistory::new()), + exposed_tags: RefCell::new(FxHashSet::default()), } } @@ -554,12 +620,18 @@ impl<'tcx> Stacks { fn for_each( &self, range: AllocRange, - mut f: impl FnMut(Size, &mut Stack, &mut AllocHistory) -> InterpResult<'tcx>, + mut f: impl FnMut( + Size, + &mut Stack, + &mut AllocHistory, + &mut FxHashSet, + ) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { let mut stacks = self.stacks.borrow_mut(); let history = &mut *self.history.borrow_mut(); + let exposed_tags = &mut *self.exposed_tags.borrow_mut(); for (offset, stack) in stacks.iter_mut(range.start, range.size) { - f(offset, stack, history)?; + f(offset, stack, history, exposed_tags)?; } Ok(()) } @@ -568,12 +640,18 @@ impl<'tcx> Stacks { fn for_each_mut( &mut self, range: AllocRange, - mut f: impl FnMut(Size, &mut Stack, &mut AllocHistory) -> InterpResult<'tcx>, + mut f: impl FnMut( + Size, + &mut Stack, + &mut AllocHistory, + &mut FxHashSet, + ) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { let stacks = self.stacks.get_mut(); let history = &mut *self.history.borrow_mut(); + let exposed_tags = self.exposed_tags.get_mut(); for (offset, stack) in stacks.iter_mut(range.start, range.size) { - f(offset, stack, history)?; + f(offset, stack, history, exposed_tags)?; } Ok(()) } @@ -631,11 +709,31 @@ impl Stacks { } #[inline(always)] - pub fn memory_read<'tcx>( + pub fn ptr_exposed<'tcx>( &self, alloc_id: AllocId, tag: SbTag, range: AllocRange, + _state: &GlobalState, + ) -> InterpResult<'tcx> { + trace!( + "allocation exposed with tag {:?}: {:?}, size {}", + tag, + Pointer::new(alloc_id, range.start), + range.size.bytes() + ); + + self.exposed_tags.borrow_mut().insert(tag); + + Ok(()) + } + + #[inline(always)] + pub fn memory_read<'tcx>( + &self, + alloc_id: AllocId, + tag: Option, + range: AllocRange, state: &GlobalState, mut current_span: CurrentSpan<'_, '_, 'tcx>, ) -> InterpResult<'tcx> { @@ -646,7 +744,7 @@ impl Stacks { range.size.bytes() ); let mut state = state.borrow_mut(); - self.for_each(range, |offset, stack, history| { + self.for_each(range, |offset, stack, history, exposed_tags| { stack.access( AccessKind::Read, tag, @@ -654,6 +752,7 @@ impl Stacks { &mut state, &mut current_span, history, + exposed_tags, ) }) } @@ -662,7 +761,7 @@ impl Stacks { pub fn memory_written<'tcx>( &mut self, alloc_id: AllocId, - tag: SbTag, + tag: Option, range: AllocRange, state: &GlobalState, mut current_span: CurrentSpan<'_, '_, 'tcx>, @@ -674,7 +773,7 @@ impl Stacks { range.size.bytes() ); let mut state = state.borrow_mut(); - self.for_each_mut(range, |offset, stack, history| { + self.for_each_mut(range, |offset, stack, history, exposed_tags| { stack.access( AccessKind::Write, tag, @@ -682,6 +781,7 @@ impl Stacks { &mut state, &mut current_span, history, + exposed_tags, ) }) } @@ -690,14 +790,14 @@ impl Stacks { pub fn memory_deallocated<'tcx>( &mut self, alloc_id: AllocId, - tag: SbTag, + tag: Option, range: AllocRange, state: &GlobalState, ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", tag, alloc_id, range.size.bytes()); let state = state.borrow(); - self.for_each_mut(range, |offset, stack, history| { - stack.dealloc(tag, (alloc_id, range, offset), &state, history) + self.for_each_mut(range, |offset, stack, history, exposed_tags| { + stack.dealloc(tag, (alloc_id, range, offset), &state, history, exposed_tags) })?; Ok(()) } @@ -749,7 +849,9 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dangling slices are a common case here; it's valid to get their length but with raw // pointer tagging for example all calls to get_unchecked on them are invalid. if let Ok((alloc_id, base_offset, orig_tag)) = this.ptr_try_get_alloc_id(place.ptr) { - log_creation(this, current_span, alloc_id, base_offset, orig_tag)?; + if let Some(orig_tag) = orig_tag { + log_creation(this, current_span, alloc_id, base_offset, orig_tag)?; + } } trace!( @@ -762,7 +864,9 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(()); } let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?; - log_creation(this, current_span, alloc_id, base_offset, orig_tag)?; + if let Some(orig_tag) = orig_tag { + log_creation(this, current_span, alloc_id, base_offset, orig_tag)?; + } // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). let (alloc_size, _) = @@ -830,7 +934,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; let item = Item { perm, tag: new_tag, protector }; let mut global = this.machine.stacked_borrows.as_ref().unwrap().borrow_mut(); - stacked_borrows.for_each(range, |offset, stack, history| { + stacked_borrows.for_each(range, |offset, stack, history, exposed_tags| { stack.grant( orig_tag, item, @@ -838,6 +942,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut *global, current_span, history, + exposed_tags, ) }) })?; @@ -854,7 +959,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let range = alloc_range(base_offset, size); let mut global = machine.stacked_borrows.as_ref().unwrap().borrow_mut(); let current_span = &mut machine.current_span(); // `get_alloc_extra_mut` invalidated our old `current_span` - stacked_borrows.for_each_mut(range, |offset, stack, history| { + stacked_borrows.for_each_mut(range, |offset, stack, history, exposed_tags| { stack.grant( orig_tag, item, @@ -862,6 +967,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut global, current_span, history, + exposed_tags, ) })?; diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index 5400e9abe503..224954c76159 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -197,7 +197,7 @@ impl AllocHistory { /// Report a descriptive error when `new` could not be granted from `derived_from`. pub fn grant_error<'tcx>( &self, - derived_from: SbTag, + derived_from: Option, new: Item, alloc_id: AllocId, alloc_range: AllocRange, @@ -214,7 +214,9 @@ impl AllocHistory { err_sb_ub( format!("{}{}", action, error_cause(stack, derived_from)), Some(operation_summary("a reborrow", alloc_id, alloc_range)), - self.get_logs_relevant_to(derived_from, alloc_range, error_offset, None), + derived_from.and_then(|derived_from| { + self.get_logs_relevant_to(derived_from, alloc_range, error_offset, None) + }), ) } @@ -222,7 +224,7 @@ impl AllocHistory { pub fn access_error<'tcx>( &self, access: AccessKind, - tag: SbTag, + tag: Option, alloc_id: AllocId, alloc_range: AllocRange, error_offset: Size, @@ -238,7 +240,7 @@ impl AllocHistory { err_sb_ub( format!("{}{}", action, error_cause(stack, tag)), Some(operation_summary("an access", alloc_id, alloc_range)), - self.get_logs_relevant_to(tag, alloc_range, error_offset, None), + tag.and_then(|tag| self.get_logs_relevant_to(tag, alloc_range, error_offset, None)), ) } } @@ -251,10 +253,14 @@ fn operation_summary( format!("this error occurs as part of {} at {:?}{}", operation, alloc_id, HexRange(alloc_range)) } -fn error_cause(stack: &Stack, tag: SbTag) -> &'static str { - if stack.borrows.iter().any(|item| item.tag == tag && item.perm != Permission::Disabled) { - ", but that tag only grants SharedReadOnly permission for this location" +fn error_cause(stack: &Stack, tag: Option) -> &'static str { + if let Some(tag) = tag { + if stack.borrows.iter().any(|item| item.tag == tag && item.perm != Permission::Disabled) { + ", but that tag only grants SharedReadOnly permission for this location" + } else { + ", but that tag does not exist in the borrow stack for this location" + } } else { - ", but that tag does not exist in the borrow stack for this location" + ", but no exposed tags are valid in the borrow stack for this location" } } diff --git a/tests/fail/provenance/permissive_provenance_transmute.rs b/tests/fail/provenance/permissive_provenance_transmute.rs index dbfc5732ed3b..28e6ba623080 100644 --- a/tests/fail/provenance/permissive_provenance_transmute.rs +++ b/tests/fail/provenance/permissive_provenance_transmute.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance -Zmiri-disable-stacked-borrows +// compile-flags: -Zmiri-permissive-provenance #![feature(strict_provenance)] use std::mem; diff --git a/tests/fail/provenance/ptr_int_unexposed.rs b/tests/fail/provenance/ptr_int_unexposed.rs index 310024c1efc7..ad29d38dc3f7 100644 --- a/tests/fail/provenance/ptr_int_unexposed.rs +++ b/tests/fail/provenance/ptr_int_unexposed.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance -Zmiri-disable-stacked-borrows +// compile-flags: -Zmiri-permissive-provenance #![feature(strict_provenance)] fn main() { diff --git a/tests/pass/ptr_int_from_exposed.rs b/tests/pass/ptr_int_from_exposed.rs index e025cf921313..dc9cb393b781 100644 --- a/tests/pass/ptr_int_from_exposed.rs +++ b/tests/pass/ptr_int_from_exposed.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance -Zmiri-disable-stacked-borrows +// compile-flags: -Zmiri-permissive-provenance #![feature(strict_provenance)] use std::ptr; diff --git a/tests/pass/stacked-borrows/int-to-ptr.rs b/tests/pass/stacked-borrows/int-to-ptr.rs index efba0da1b935..dc581d8af618 100644 --- a/tests/pass/stacked-borrows/int-to-ptr.rs +++ b/tests/pass/stacked-borrows/int-to-ptr.rs @@ -1,6 +1,6 @@ -fn main() { - ref_raw_int_raw(); -} +// compile-flags: -Zmiri-permissive-provenance +#![feature(strict_provenance)] +use std::ptr; // Just to make sure that casting a ref to raw, to int and back to raw // and only then using it works. This rules out ideas like "do escape-to-raw lazily"; @@ -11,3 +11,69 @@ fn ref_raw_int_raw() { let xraw = xref as *mut i32 as usize as *mut i32; assert_eq!(unsafe { *xraw }, 3); } + +/// Ensure that we do not just pick the topmost possible item on int2ptr casts. +fn example(variant: bool) { unsafe { + fn not_so_innocent(x: &mut u32) -> usize { + let x_raw4 = x as *mut u32; + x_raw4.expose_addr() + } + + let mut c = 42u32; + + let x_unique1 = &mut c; + // [..., Unique(1)] + + let x_raw2 = x_unique1 as *mut u32; + let x_raw2_addr = x_raw2.expose_addr(); + // [..., Unique(1), SharedRW(2)] + + let x_unique3 = &mut *x_raw2; + // [.., Unique(1), SharedRW(2), Unique(3)] + + assert_eq!(not_so_innocent(x_unique3), x_raw2_addr); + // [.., Unique(1), SharedRW(2), Unique(3), ..., SharedRW(4)] + + // Do an int2ptr cast. This can pick tag 2 or 4 (the two previously exposed tags). + // 4 is the "obvious" choice (topmost tag, what we used to do with untagged pointers). + // And indeed if `variant == true` it is the only possible choice. + // But if `variant == false` then 2 is the only possible choice! + let x_wildcard = ptr::from_exposed_addr_mut::(x_raw2_addr); + + if variant { + // If we picked 2, this will invalidate 3. + *x_wildcard = 10; + // Now we use 3. Only possible if above we picked 4. + *x_unique3 = 12; + } else { + // This invalidates tag 4. + *x_unique3 = 10; + // Now try to write with the "guessed" tag; it must be 2. + *x_wildcard = 12; + } +} } + +fn test() { unsafe { + let root = &mut 42; + let root_raw = root as *mut i32; + let addr1 = root_raw as usize; + let child = &mut *root_raw; + let child_raw = child as *mut i32; + let addr2 = child_raw as usize; + assert_eq!(addr1, addr2); + // First use child. + *(addr2 as *mut i32) -= 2; // picks child_raw + *child -= 2; + // Then use root. + *(addr1 as *mut i32) += 2; // picks root_raw + *root += 2; + // Value should be unchanged. + assert_eq!(*root, 42); +} } + +fn main() { + ref_raw_int_raw(); + example(false); + example(true); + test(); +} From c7feb014b0b73d2e06ccfd3b754171d3fec7eeda Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Wed, 15 Jun 2022 20:53:44 -0500 Subject: [PATCH 3336/5092] Maybe this wil work --- src/stacked_borrows.rs | 49 ++++++++++++++++-------------- src/stacked_borrows/diagnostics.rs | 19 ++++++++++-- 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index ad7569008e20..d28c6425cd42 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -485,8 +485,7 @@ impl<'tcx> Stack { } } else { self.borrows.clear(); - // TODO - // self.borrows.push(ItemOrUnknown::Unknown(global.next_ptr_id)); + self.unknown_bottom = Some(global.next_ptr_id); } // Done. @@ -541,6 +540,20 @@ impl<'tcx> Stack { let access = if new.perm.grants(AccessKind::Write) { AccessKind::Write } else { AccessKind::Read }; + // Now we figure out which item grants our parent (`derived_from`) this kind of access. + // We use that to determine where to put the new item. + let granting_idx = + self.find_granting(access, derived_from, exposed_tags).map_err(|_| { + alloc_history.grant_error( + derived_from, + new, + alloc_id, + alloc_range, + offset, + self, + ) + })?; + // Compute where to put the new item. // Either way, we ensure that we insert the new item in a way such that between // `derived_from` and the new one, there are only items *compatible with* `derived_from`. @@ -550,25 +563,17 @@ impl<'tcx> Stack { "this case only makes sense for stack-like accesses" ); - // Now we figure out which item grants our parent (`derived_from`) this kind of access. - // We use that to determine where to put the new item. - let granting_idx = - self.find_granting(access, derived_from, exposed_tags).map_err(|_| { - alloc_history.grant_error( - derived_from, - new, - alloc_id, - alloc_range, - offset, - self, - ) - })?; - - // SharedReadWrite can coexist with "existing loans", meaning they don't act like a write - // access. Instead of popping the stack, we insert the item at the place the stack would - // be popped to (i.e., we insert it above all the write-compatible items). - // This ensures F2b by adding the new item below any potentially existing `SharedReadOnly`. - self.find_first_write_incompatible(granting_idx) + if derived_from.is_some() { + // SharedReadWrite can coexist with "existing loans", meaning they don't act like a write + // access. Instead of popping the stack, we insert the item at the place the stack would + // be popped to (i.e., we insert it above all the write-compatible items). + // This ensures F2b by adding the new item below any potentially existing `SharedReadOnly`. + self.find_first_write_incompatible(granting_idx) + } else { + // TODO: is this correct + self.borrows.clear(); + 0 + } } else { // A "safe" reborrow for a pointer that actually expects some aliasing guarantees. // Here, creating a reference actually counts as an access. @@ -590,7 +595,7 @@ impl<'tcx> Stack { self.borrows.len() }; // Put the new item there. As an optimization, deduplicate if it is equal to one of its new neighbors. - if self.borrows[new_idx - 1] == new || self.borrows.get(new_idx) == Some(&new) { + if self.borrows.get(new_idx) == Some(&new) || new_idx > 0 && self.borrows.get(new_idx - 1) == Some(&new) { // Optimization applies, done. trace!("reborrow: avoiding adding redundant item {:?}", new); } else { diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index 224954c76159..6a22d9a74392 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -4,6 +4,8 @@ use rustc_middle::mir::interpret::{AllocId, AllocRange}; use rustc_span::{Span, SpanData}; use rustc_target::abi::Size; +use core::fmt::Debug; + use crate::helpers::{CurrentSpan, HexRange}; use crate::stacked_borrows::{err_sb_ub, AccessKind, Permission}; use crate::Item; @@ -204,9 +206,16 @@ impl AllocHistory { error_offset: Size, stack: &Stack, ) -> InterpError<'tcx> { + // TODO: Fix this properly + let z = &derived_from; + let f = if let Some(ref t) = z { + t as &dyn Debug + } else { + &"" as &dyn Debug + }; let action = format!( "trying to reborrow {:?} for {:?} permission at {}[{:#x}]", - derived_from, + f, new.perm, alloc_id, error_offset.bytes(), @@ -230,10 +239,16 @@ impl AllocHistory { error_offset: Size, stack: &Stack, ) -> InterpError<'tcx> { + let z = &tag; + let f = if let Some(ref t) = z { + t as &dyn Debug + } else { + &"" as &dyn Debug + }; let action = format!( "attempting a {} using {:?} at {}[{:#x}]", access, - tag, + f, alloc_id, error_offset.bytes(), ); From d1e7de117c84ccfe611a14791dbb53c5e1520b50 Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Wed, 15 Jun 2022 20:55:54 -0500 Subject: [PATCH 3337/5092] Try fix stuff --- src/stacked_borrows.rs | 17 ++++++----------- src/stacked_borrows/diagnostics.rs | 12 ++---------- 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index d28c6425cd42..75c2ff265879 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -543,16 +543,9 @@ impl<'tcx> Stack { // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. let granting_idx = - self.find_granting(access, derived_from, exposed_tags).map_err(|_| { - alloc_history.grant_error( - derived_from, - new, - alloc_id, - alloc_range, - offset, - self, - ) - })?; + self.find_granting(access, derived_from, exposed_tags).map_err(|_| { + alloc_history.grant_error(derived_from, new, alloc_id, alloc_range, offset, self) + })?; // Compute where to put the new item. // Either way, we ensure that we insert the new item in a way such that between @@ -595,7 +588,9 @@ impl<'tcx> Stack { self.borrows.len() }; // Put the new item there. As an optimization, deduplicate if it is equal to one of its new neighbors. - if self.borrows.get(new_idx) == Some(&new) || new_idx > 0 && self.borrows.get(new_idx - 1) == Some(&new) { + if self.borrows.get(new_idx) == Some(&new) + || new_idx > 0 && self.borrows.get(new_idx - 1) == Some(&new) + { // Optimization applies, done. trace!("reborrow: avoiding adding redundant item {:?}", new); } else { diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index 6a22d9a74392..91dfe22c1964 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -208,11 +208,7 @@ impl AllocHistory { ) -> InterpError<'tcx> { // TODO: Fix this properly let z = &derived_from; - let f = if let Some(ref t) = z { - t as &dyn Debug - } else { - &"" as &dyn Debug - }; + let f = if let Some(ref t) = z { t as &dyn Debug } else { &"" as &dyn Debug }; let action = format!( "trying to reborrow {:?} for {:?} permission at {}[{:#x}]", f, @@ -240,11 +236,7 @@ impl AllocHistory { stack: &Stack, ) -> InterpError<'tcx> { let z = &tag; - let f = if let Some(ref t) = z { - t as &dyn Debug - } else { - &"" as &dyn Debug - }; + let f = if let Some(ref t) = z { t as &dyn Debug } else { &"" as &dyn Debug }; let action = format!( "attempting a {} using {:?} at {}[{:#x}]", access, From 2deb9e5dae5b6d6b66105fda92e2d30e48a0cfab Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 24 Jun 2022 16:21:47 -0400 Subject: [PATCH 3338/5092] add exposed_only_ro test --- tests/fail/stacked_borrows/exposed_only_ro.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/fail/stacked_borrows/exposed_only_ro.rs diff --git a/tests/fail/stacked_borrows/exposed_only_ro.rs b/tests/fail/stacked_borrows/exposed_only_ro.rs new file mode 100644 index 000000000000..b3adb0b855f6 --- /dev/null +++ b/tests/fail/stacked_borrows/exposed_only_ro.rs @@ -0,0 +1,12 @@ +// compile-flags: -Zmiri-permissive-provenance +#![feature(strict_provenance)] + +// If we have only exposed read-only pointers, doing a write through a wildcard ptr should fail. + +fn main() { + let mut x = 0; + let _fool = &mut x as *mut i32; // this would have fooled the old untagged pointer logic + let addr = (&x as *const i32).expose_addr(); + let ptr = std::ptr::from_exposed_addr_mut::(addr); + unsafe { ptr.write(0) }; //~ ERROR: borrow stack +} From c0f7118342ccf77330c92d50222f90856730254b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 24 Jun 2022 16:45:22 -0400 Subject: [PATCH 3339/5092] reorganize exposure code a bit --- src/intptrcast.rs | 7 +++++-- src/machine.rs | 18 ++---------------- src/stacked_borrows.rs | 35 ++++++++++++++--------------------- 3 files changed, 21 insertions(+), 39 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 4a86490ed09a..279bf3d01d2e 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -101,14 +101,17 @@ impl<'mir, 'tcx> GlobalStateInner { } } - pub fn expose_addr(ecx: &MiriEvalContext<'mir, 'tcx>, alloc_id: AllocId) { + pub fn expose_ptr(ecx: &mut MiriEvalContext<'mir, 'tcx>, alloc_id: AllocId, sb: SbTag) { trace!("Exposing allocation id {:?}", alloc_id); - let mut global_state = ecx.machine.intptrcast.borrow_mut(); + let global_state = ecx.machine.intptrcast.get_mut(); // In legacy and strict mode, we don't need this, so we can save some cycles // by not tracking it. if global_state.provenance_mode == ProvenanceMode::Permissive { global_state.exposed.insert(alloc_id); + if ecx.machine.stacked_borrows.is_some() { + ecx.expose_tag(alloc_id, sb); + } } } diff --git a/src/machine.rs b/src/machine.rs index c2a7a34a9cc0..3704a5385141 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -489,6 +489,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { type AllocExtra = AllocExtra; type PointerTag = Tag; + // `None` represents a wildcard pointer. type TagExtra = Option; type MemoryMap = @@ -709,22 +710,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ) -> InterpResult<'tcx> { match ptr.provenance { Tag::Concrete(ConcreteTag { alloc_id, sb }) => { - intptrcast::GlobalStateInner::expose_addr(ecx, alloc_id); - - let (size, _) = - ecx.get_alloc_size_and_align(alloc_id, AllocCheck::MaybeDead).unwrap(); - - // Function pointers and dead objects don't have an alloc_extra so we ignore them. - if let Ok(alloc_extra) = ecx.get_alloc_extra(alloc_id) { - if let Some(stacked_borrows) = &alloc_extra.stacked_borrows { - stacked_borrows.ptr_exposed( - alloc_id, - sb, - alloc_range(Size::from_bytes(0), size), - ecx.machine.stacked_borrows.as_ref().unwrap(), - )?; - } - } + intptrcast::GlobalStateInner::expose_ptr(ecx, alloc_id, sb); } Tag::Wildcard => { // No need to do anything for wildcard pointers as diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 75c2ff265879..b66864b8302a 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -117,7 +117,7 @@ pub struct Stacks { stacks: RefCell>, /// Stores past operations on this allocation history: RefCell, - /// The set of tags that have been exposed + /// The set of tags that have been exposed inside this allocation. exposed_tags: RefCell>, } @@ -708,26 +708,6 @@ impl Stacks { stacks } - #[inline(always)] - pub fn ptr_exposed<'tcx>( - &self, - alloc_id: AllocId, - tag: SbTag, - range: AllocRange, - _state: &GlobalState, - ) -> InterpResult<'tcx> { - trace!( - "allocation exposed with tag {:?}: {:?}, size {}", - tag, - Pointer::new(alloc_id, range.start), - range.size.bytes() - ); - - self.exposed_tags.borrow_mut().insert(tag); - - Ok(()) - } - #[inline(always)] pub fn memory_read<'tcx>( &self, @@ -1096,4 +1076,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } + + /// Mark the given tag as exposed. It was found on a pointer with the given AllocId. + fn expose_tag(&mut self, alloc_id: AllocId, tag: SbTag) { + let this = self.eval_context_mut(); + + // Function pointers and dead objects don't have an alloc_extra so we ignore them. + // This is okay because accessing them is UB anyway, no need for any Stacked Borrows checks. + // FIXME: this catches `InterpError`, which we should not usually do. + // We might need a proper fallible API from `memory.rs` to avoid this though. + if let Ok((alloc_extra, _)) = this.get_alloc_extra_mut(alloc_id) { + alloc_extra.stacked_borrows.as_mut().unwrap().exposed_tags.get_mut().insert(tag); + } + } } From 8d6fdaa024138de464a74ebd5307c706c68a3eef Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 24 Jun 2022 18:02:25 -0400 Subject: [PATCH 3340/5092] make the tests pass (and some formatting) --- README.md | 4 +- src/intptrcast.rs | 3 +- src/lib.rs | 1 + src/stacked_borrows.rs | 223 ++++++++++-------- tests/fail/stacked_borrows/exposed_only_ro.rs | 2 +- .../stacked_borrows/exposed_only_ro.stderr | 18 ++ tests/pass/stacked-borrows/int-to-ptr.rs | 112 ++++----- 7 files changed, 202 insertions(+), 161 deletions(-) create mode 100644 tests/fail/stacked_borrows/exposed_only_ro.stderr diff --git a/README.md b/README.md index 88ac8a135304..f6b2413c65f5 100644 --- a/README.md +++ b/README.md @@ -358,9 +358,7 @@ to Miri failing to detect cases of undefined behavior in a program. for pointer-to-int and int-to-pointer casts, respectively. This will necessarily miss some bugs as those semantics are not efficiently implementable in a sanitizer, but it will only miss bugs that concerns - memory/pointers which is subject to these operations. Also note that this flag - is currently incompatible with Stacked Borrows, so you will have to also pass - `-Zmiri-disable-stacked-borrows` to use this. + memory/pointers which is subject to these operations. * `-Zmiri-symbolic-alignment-check` makes the alignment check more strict. By default, alignment is checked by casting the pointer to an integer, and making sure that is a multiple of the alignment. This can lead to cases where a diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 279bf3d01d2e..9ec96b8f491e 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -102,12 +102,11 @@ impl<'mir, 'tcx> GlobalStateInner { } pub fn expose_ptr(ecx: &mut MiriEvalContext<'mir, 'tcx>, alloc_id: AllocId, sb: SbTag) { - trace!("Exposing allocation id {:?}", alloc_id); - let global_state = ecx.machine.intptrcast.get_mut(); // In legacy and strict mode, we don't need this, so we can save some cycles // by not tracking it. if global_state.provenance_mode == ProvenanceMode::Permissive { + trace!("Exposing allocation id {alloc_id:?}"); global_state.exposed.insert(alloc_id); if ecx.machine.stacked_borrows.is_some() { ecx.expose_tag(alloc_id, sb); diff --git a/src/lib.rs b/src/lib.rs index dc6c0b8dc603..432f469733cb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ #![feature(let_else)] #![feature(io_error_more)] #![feature(yeet_expr)] +#![feature(is_some_with)] #![warn(rust_2018_idioms)] #![allow( clippy::collapsible_else_if, diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index b66864b8302a..8411d85f0e01 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -104,9 +104,10 @@ pub struct Stack { /// * Above a `SharedReadOnly` there can only be more `SharedReadOnly`. /// * Except for `Untagged`, no tag occurs in the stack more than once. borrows: Vec, - /// If this is `Some(id)`, then the actual current stack is unknown. What we do know - /// is that `borrows` are at the top of the stack, and below it are arbitrarily many items - /// whose `tag` is either `Untagged` or strictly less than `id`. + /// If this is `Some(id)`, then the actual current stack is unknown. THis can happen when + /// wildcard pointers are used to access this location. What we do know is that `borrows` are at + /// the top of the stack, and below it are arbitrarily many items whose `tag` is either + /// `Untagged` or strictly less than `id`. unknown_bottom: Option, } @@ -289,72 +290,72 @@ impl Permission { impl<'tcx> Stack { /// Find the item granting the given kind of access to the given tag, and return where /// it is on the stack. - // TODO: Doc ok with Some(index) or None if unknown_bottom used - // Err if does not match + /// `Ok(None)` indicates it matched the "unknown" part of the stack, or it was a wildcard tag + /// and we have no clue what exactly it matched (but it could have matched something) + /// `Err` indicates it was not found. fn find_granting( &self, access: AccessKind, tag: Option, exposed_tags: &FxHashSet, ) -> Result, ()> { - let res = self - .borrows - .iter() - .enumerate() // we also need to know *where* in the stack - .rev() // search top-to-bottom - // Return permission of first item that grants access. - // We require a permission with the right tag, ensuring U3 and F3. - .find_map(|(idx, item)| { - match tag { - Some(tag) if tag == item.tag && item.perm.grants(access) => Some(idx), - None if exposed_tags.contains(&item.tag) => Some(idx), - _ => None, - } - }); + let Some(tag) = tag else { + // Handle the wildcard case. + // Go search the stack for an exposed tag. + let maybe_in_stack = self + .borrows + .iter() + .rev() // search top-to-bottom + .find_map(|item| { + // If the item fits and *might* be this wildcard, use it. + if item.perm.grants(access) && exposed_tags.contains(&item.tag) { + Some(()) + } else { + None + } + }) + .is_some(); + // If we couldn't find it in the stack, check the unknown bottom. + let found = maybe_in_stack || self.unknown_bottom.is_some(); + return if found { Ok(None) } else { Err(()) }; + }; - if res.is_some() { - return Ok(res); + if let Some(idx) = + self.borrows + .iter() + .enumerate() // we also need to know *where* in the stack + .rev() // search top-to-bottom + // Return permission of first item that grants access. + // We require a permission with the right tag, ensuring U3 and F3. + .find_map(|(idx, item)| { + if tag == item.tag && item.perm.grants(access) { Some(idx) } else { None } + }) + { + return Ok(Some(idx)); } - match self.unknown_bottom { - Some(id) => - match tag { - Some(tag) => - match tag { - SbTag::Tagged(tag_id) if tag_id < id => Ok(None), - SbTag::Untagged => Ok(None), - _ => Err(()), - }, - None => Ok(None), - }, - None => Err(()), - } + // Couldn't find it in the stack; but if there is an unknown bottom it might be there. + let found = self.unknown_bottom.is_some_and(|&unknown_limit| { + match tag { + SbTag::Tagged(tag_id) => tag_id < unknown_limit, // unknown_limit is an upper bound for what can be in the unknown bottom. + SbTag::Untagged => true, // yeah whatever + } + }); + if found { Ok(None) } else { Err(()) } } /// Find the first write-incompatible item above the given one -- /// i.e, find the height to which the stack will be truncated when writing to `granting`. - fn find_first_write_incompatible(&self, granting: Option) -> usize { - let perm = if let Some(idx) = granting { - self.borrows[idx].perm - } else { - // I assume this has to be it? - Permission::SharedReadWrite - }; - + fn find_first_write_incompatible(&self, granting: usize) -> usize { + let perm = self.borrows[granting].perm; match perm { Permission::SharedReadOnly => bug!("Cannot use SharedReadOnly for writing"), Permission::Disabled => bug!("Cannot use Disabled for anything"), // On a write, everything above us is incompatible. - Permission::Unique => - if let Some(idx) = granting { - idx + 1 - } else { - 0 - }, + Permission::Unique => granting + 1, Permission::SharedReadWrite => { // The SharedReadWrite *just* above us are compatible, to skip those. - let mut idx = if let Some(idx) = granting { idx + 1 } else { 0 }; - + let mut idx = granting + 1; while let Some(item) = self.borrows.get(idx) { if item.perm == Permission::SharedReadWrite { // Go on. @@ -440,52 +441,57 @@ impl<'tcx> Stack { alloc_history.access_error(access, tag, alloc_id, alloc_range, offset, self) })?; + let Some(granting_idx) = granting_idx else { + // The access used a wildcard pointer or matched the unknown bottom. + // Nobody knows what happened, so forget everything. + trace!("access: clearing stack due to wildcard"); + self.borrows.clear(); + self.unknown_bottom = Some(global.next_ptr_id); + return Ok(()); + }; + let tag = tag.unwrap(); // only precise tags have precise locations + // Step 2: Remove incompatible items above them. Make sure we do not remove protected // items. Behavior differs for reads and writes. - if let Some(tag) = tag { - if access == AccessKind::Write { - // Remove everything above the write-compatible items, like a proper stack. This makes sure read-only and unique - // pointers become invalid on write accesses (ensures F2a, and ensures U2 for write accesses). - let first_incompatible_idx = self.find_first_write_incompatible(granting_idx); - for item in self.borrows.drain(first_incompatible_idx..).rev() { - trace!("access: popping item {:?}", item); + if access == AccessKind::Write { + // Remove everything above the write-compatible items, like a proper stack. This makes sure read-only and unique + // pointers become invalid on write accesses (ensures F2a, and ensures U2 for write accesses). + let first_incompatible_idx = self.find_first_write_incompatible(granting_idx); + for item in self.borrows.drain(first_incompatible_idx..).rev() { + trace!("access: popping item {:?}", item); + Stack::check_protector( + &item, + Some((tag, alloc_range, offset, access)), + global, + alloc_history, + )?; + alloc_history.log_invalidation(item.tag, alloc_range, current_span); + } + } else { + // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses. + // The reason this is not following the stack discipline (by removing the first Unique and + // everything on top of it) is that in `let raw = &mut *x as *mut _; let _val = *x;`, the second statement + // would pop the `Unique` from the reborrow of the first statement, and subsequently also pop the + // `SharedReadWrite` for `raw`. + // This pattern occurs a lot in the standard library: create a raw pointer, then also create a shared + // reference and use that. + // We *disable* instead of removing `Unique` to avoid "connecting" two neighbouring blocks of SRWs. + let first_incompatible_idx = granting_idx + 1; + for idx in (first_incompatible_idx..self.borrows.len()).rev() { + let item = &mut self.borrows[idx]; + + if item.perm == Permission::Unique { + trace!("access: disabling item {:?}", item); Stack::check_protector( - &item, + item, Some((tag, alloc_range, offset, access)), global, alloc_history, )?; + item.perm = Permission::Disabled; alloc_history.log_invalidation(item.tag, alloc_range, current_span); } - } else { - let start_idx = if let Some(idx) = granting_idx { idx + 1 } else { 0 }; - // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses. - // The reason this is not following the stack discipline (by removing the first Unique and - // everything on top of it) is that in `let raw = &mut *x as *mut _; let _val = *x;`, the second statement - // would pop the `Unique` from the reborrow of the first statement, and subsequently also pop the - // `SharedReadWrite` for `raw`. - // This pattern occurs a lot in the standard library: create a raw pointer, then also create a shared - // reference and use that. - // We *disable* instead of removing `Unique` to avoid "connecting" two neighbouring blocks of SRWs. - for idx in (start_idx..self.borrows.len()).rev() { - let item = &mut self.borrows[idx]; - - if item.perm == Permission::Unique { - trace!("access: disabling item {:?}", item); - Stack::check_protector( - item, - Some((tag, alloc_range, offset, access)), - global, - alloc_history, - )?; - item.perm = Permission::Disabled; - alloc_history.log_invalidation(item.tag, alloc_range, current_span); - } - } } - } else { - self.borrows.clear(); - self.unknown_bottom = Some(global.next_ptr_id); } // Done. @@ -502,7 +508,7 @@ impl<'tcx> Stack { alloc_history: &mut AllocHistory, exposed_tags: &FxHashSet, ) -> InterpResult<'tcx> { - // Step 1: Find granting item. + // Step 1: Make sure there is a granting item. self.find_granting(AccessKind::Write, tag, exposed_tags).map_err(|_| { err_sb_ub(format!( "no item granting write access for deallocation to tag {:?} at {:?} found in borrow stack", @@ -556,17 +562,20 @@ impl<'tcx> Stack { "this case only makes sense for stack-like accesses" ); - if derived_from.is_some() { - // SharedReadWrite can coexist with "existing loans", meaning they don't act like a write - // access. Instead of popping the stack, we insert the item at the place the stack would - // be popped to (i.e., we insert it above all the write-compatible items). - // This ensures F2b by adding the new item below any potentially existing `SharedReadOnly`. - self.find_first_write_incompatible(granting_idx) - } else { - // TODO: is this correct + let Some(granting_idx) = granting_idx else { + // The parent is a wildcard pointer or matched the unknown bottom. + // Nobody knows what happened, so forget everything. + trace!("reborrow: clearing stack due to wildcard"); self.borrows.clear(); - 0 - } + self.unknown_bottom = Some(global.next_ptr_id); + return Ok(()); + }; + + // SharedReadWrite can coexist with "existing loans", meaning they don't act like a write + // access. Instead of popping the stack, we insert the item at the place the stack would + // be popped to (i.e., we insert it above all the write-compatible items). + // This ensures F2b by adding the new item below any potentially existing `SharedReadOnly`. + self.find_first_write_incompatible(granting_idx) } else { // A "safe" reborrow for a pointer that actually expects some aliasing guarantees. // Here, creating a reference actually counts as an access. @@ -587,9 +596,11 @@ impl<'tcx> Stack { // This ensures U1 and F1. self.borrows.len() }; + // Put the new item there. As an optimization, deduplicate if it is equal to one of its new neighbors. + // `new_idx` might be 0 if we just cleared the entire stack. if self.borrows.get(new_idx) == Some(&new) - || new_idx > 0 && self.borrows.get(new_idx - 1) == Some(&new) + || (new_idx > 0 && self.borrows[new_idx - 1] == new) { // Optimization applies, done. trace!("reborrow: avoiding adding redundant item {:?}", new); @@ -648,7 +659,7 @@ impl<'tcx> Stacks { ) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { let stacks = self.stacks.get_mut(); - let history = &mut *self.history.borrow_mut(); + let history = &mut *self.history.get_mut(); let exposed_tags = self.exposed_tags.get_mut(); for (offset, stack) in stacks.iter_mut(range.start, range.size) { f(offset, stack, history, exposed_tags)?; @@ -1083,10 +1094,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Function pointers and dead objects don't have an alloc_extra so we ignore them. // This is okay because accessing them is UB anyway, no need for any Stacked Borrows checks. + // NOT using `get_alloc_extra_mut` since this might be a read-only allocation! // FIXME: this catches `InterpError`, which we should not usually do. // We might need a proper fallible API from `memory.rs` to avoid this though. - if let Ok((alloc_extra, _)) = this.get_alloc_extra_mut(alloc_id) { - alloc_extra.stacked_borrows.as_mut().unwrap().exposed_tags.get_mut().insert(tag); + match this.get_alloc_extra(alloc_id) { + Ok(alloc_extra) => { + trace!("Stacked Borrows tag {tag:?} exposed in {alloc_id}"); + alloc_extra.stacked_borrows.as_ref().unwrap().exposed_tags.borrow_mut().insert(tag); + } + Err(err) => { + trace!( + "Not exposing Stacked Borrows tag {tag:?} due to error \ + when accessing {alloc_id}: {err}" + ); + } } } } diff --git a/tests/fail/stacked_borrows/exposed_only_ro.rs b/tests/fail/stacked_borrows/exposed_only_ro.rs index b3adb0b855f6..9b4234499df0 100644 --- a/tests/fail/stacked_borrows/exposed_only_ro.rs +++ b/tests/fail/stacked_borrows/exposed_only_ro.rs @@ -8,5 +8,5 @@ fn main() { let _fool = &mut x as *mut i32; // this would have fooled the old untagged pointer logic let addr = (&x as *const i32).expose_addr(); let ptr = std::ptr::from_exposed_addr_mut::(addr); - unsafe { ptr.write(0) }; //~ ERROR: borrow stack + unsafe { *ptr = 0 }; //~ ERROR: borrow stack } diff --git a/tests/fail/stacked_borrows/exposed_only_ro.stderr b/tests/fail/stacked_borrows/exposed_only_ro.stderr new file mode 100644 index 000000000000..9748fe78c718 --- /dev/null +++ b/tests/fail/stacked_borrows/exposed_only_ro.stderr @@ -0,0 +1,18 @@ +error: Undefined Behavior: attempting a write access using "" at ALLOC[0x0], but no exposed tags are valid in the borrow stack for this location + --> $DIR/exposed_only_ro.rs:LL:CC + | +LL | unsafe { *ptr = 0 }; + | ^^^^^^^^ + | | + | attempting a write access using "" at ALLOC[0x0], but no exposed tags are valid in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information + + = note: inside `main` at $DIR/exposed_only_ro.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/pass/stacked-borrows/int-to-ptr.rs b/tests/pass/stacked-borrows/int-to-ptr.rs index dc581d8af618..dc3675406276 100644 --- a/tests/pass/stacked-borrows/int-to-ptr.rs +++ b/tests/pass/stacked-borrows/int-to-ptr.rs @@ -13,63 +13,67 @@ fn ref_raw_int_raw() { } /// Ensure that we do not just pick the topmost possible item on int2ptr casts. -fn example(variant: bool) { unsafe { - fn not_so_innocent(x: &mut u32) -> usize { - let x_raw4 = x as *mut u32; - x_raw4.expose_addr() +fn example(variant: bool) { + unsafe { + fn not_so_innocent(x: &mut u32) -> usize { + let x_raw4 = x as *mut u32; + x_raw4.expose_addr() + } + + let mut c = 42u32; + + let x_unique1 = &mut c; + // [..., Unique(1)] + + let x_raw2 = x_unique1 as *mut u32; + let x_raw2_addr = x_raw2.expose_addr(); + // [..., Unique(1), SharedRW(2)] + + let x_unique3 = &mut *x_raw2; + // [.., Unique(1), SharedRW(2), Unique(3)] + + assert_eq!(not_so_innocent(x_unique3), x_raw2_addr); + // [.., Unique(1), SharedRW(2), Unique(3), ..., SharedRW(4)] + + // Do an int2ptr cast. This can pick tag 2 or 4 (the two previously exposed tags). + // 4 is the "obvious" choice (topmost tag, what we used to do with untagged pointers). + // And indeed if `variant == true` it is the only possible choice. + // But if `variant == false` then 2 is the only possible choice! + let x_wildcard = ptr::from_exposed_addr_mut::(x_raw2_addr); + + if variant { + // If we picked 2, this will invalidate 3. + *x_wildcard = 10; + // Now we use 3. Only possible if above we picked 4. + *x_unique3 = 12; + } else { + // This invalidates tag 4. + *x_unique3 = 10; + // Now try to write with the "guessed" tag; it must be 2. + *x_wildcard = 12; + } } +} - let mut c = 42u32; - - let x_unique1 = &mut c; - // [..., Unique(1)] - - let x_raw2 = x_unique1 as *mut u32; - let x_raw2_addr = x_raw2.expose_addr(); - // [..., Unique(1), SharedRW(2)] - - let x_unique3 = &mut *x_raw2; - // [.., Unique(1), SharedRW(2), Unique(3)] - - assert_eq!(not_so_innocent(x_unique3), x_raw2_addr); - // [.., Unique(1), SharedRW(2), Unique(3), ..., SharedRW(4)] - - // Do an int2ptr cast. This can pick tag 2 or 4 (the two previously exposed tags). - // 4 is the "obvious" choice (topmost tag, what we used to do with untagged pointers). - // And indeed if `variant == true` it is the only possible choice. - // But if `variant == false` then 2 is the only possible choice! - let x_wildcard = ptr::from_exposed_addr_mut::(x_raw2_addr); - - if variant { - // If we picked 2, this will invalidate 3. - *x_wildcard = 10; - // Now we use 3. Only possible if above we picked 4. - *x_unique3 = 12; - } else { - // This invalidates tag 4. - *x_unique3 = 10; - // Now try to write with the "guessed" tag; it must be 2. - *x_wildcard = 12; +fn test() { + unsafe { + let root = &mut 42; + let root_raw = root as *mut i32; + let addr1 = root_raw as usize; + let child = &mut *root_raw; + let child_raw = child as *mut i32; + let addr2 = child_raw as usize; + assert_eq!(addr1, addr2); + // First use child. + *(addr2 as *mut i32) -= 2; // picks child_raw + *child -= 2; + // Then use root. + *(addr1 as *mut i32) += 2; // picks root_raw + *root += 2; + // Value should be unchanged. + assert_eq!(*root, 42); } -} } - -fn test() { unsafe { - let root = &mut 42; - let root_raw = root as *mut i32; - let addr1 = root_raw as usize; - let child = &mut *root_raw; - let child_raw = child as *mut i32; - let addr2 = child_raw as usize; - assert_eq!(addr1, addr2); - // First use child. - *(addr2 as *mut i32) -= 2; // picks child_raw - *child -= 2; - // Then use root. - *(addr1 as *mut i32) += 2; // picks root_raw - *root += 2; - // Value should be unchanged. - assert_eq!(*root, 42); -} } +} fn main() { ref_raw_int_raw(); From 2f9750783ced5099b90086af4a23f5af000a9f28 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Fri, 24 Jun 2022 19:04:50 -0400 Subject: [PATCH 3341/5092] Update measureme to the latest version --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 29b7e0bec26a..880fa271d97d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -231,9 +231,9 @@ dependencies = [ [[package]] name = "measureme" -version = "9.1.2" +version = "10.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78f7a41bc6f856a2cf0e95094ad5121f82500e2d9a0f3c0171d98f6566d8117d" +checksum = "cbdc226fa10994e8f66a4d2f6f000148bc563a1c671b6dcd2135737018033d8a" dependencies = [ "log", "memmap2", diff --git a/Cargo.toml b/Cargo.toml index cf6f4c8b2ee9..6b7f369ae5a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ smallvec = "1.7" # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` # for more information. rustc-workspace-hack = "1.0.0" -measureme = "9.1.2" +measureme = "10.0.0" # Enable some feature flags that dev-dependencies need but dependencies # do not. This makes `./miri install` after `./miri build` faster. From 4fbb284a99d0eceeefcf7f7fdb5c6c545ea68ae2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 24 Jun 2022 19:45:35 -0400 Subject: [PATCH 3342/5092] implement 'delimited' expose tracking so we still detect some UB --- src/diagnostics.rs | 8 +- src/intptrcast.rs | 8 +- src/lib.rs | 9 +- src/machine.rs | 34 ++- src/stacked_borrows.rs | 227 ++++++++++++------ src/stacked_borrows/diagnostics.rs | 23 +- .../stacked_borrows/exposed_only_ro.stderr | 4 +- .../illegal_read_despite_exposed1.rs | 17 ++ .../illegal_read_despite_exposed1.stderr | 18 ++ .../illegal_read_despite_exposed2.rs | 18 ++ .../illegal_read_despite_exposed2.stderr | 18 ++ .../illegal_write_despite_exposed1.rs | 16 ++ .../illegal_write_despite_exposed1.stderr | 18 ++ 13 files changed, 293 insertions(+), 125 deletions(-) create mode 100644 tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs create mode 100644 tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr create mode 100644 tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs create mode 100644 tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr create mode 100644 tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs create mode 100644 tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 0e3e693e33f9..230f46c569db 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -8,7 +8,7 @@ use rustc_middle::ty; use rustc_span::{source_map::DUMMY_SP, Span, SpanData, Symbol}; use crate::helpers::HexRange; -use crate::stacked_borrows::{diagnostics::TagHistory, AccessKind, SbTag}; +use crate::stacked_borrows::{diagnostics::TagHistory, AccessKind}; use crate::*; /// Details of premature program termination. @@ -61,9 +61,9 @@ impl MachineStopType for TerminationInfo {} /// Miri specific diagnostics pub enum NonHaltingDiagnostic { CreatedPointerTag(NonZeroU64), - /// This `Item` was popped from the borrow stack, either due to a grant of - /// `AccessKind` to `SbTag` or a deallocation when the second argument is `None`. - PoppedPointerTag(Item, Option<(SbTag, AccessKind)>), + /// This `Item` was popped from the borrow stack, either due to an access with the given tag or + /// a deallocation when the second argument is `None`. + PoppedPointerTag(Item, Option<(SbTagExtra, AccessKind)>), CreatedCallId(CallId), CreatedAlloc(AllocId), FreedAlloc(AllocId), diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 9ec96b8f491e..cfaf61f9d5c8 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -142,9 +142,7 @@ impl<'mir, 'tcx> GlobalStateInner { // Determine the allocation this points to at cast time. let alloc_id = Self::alloc_id_from_addr(ecx, addr); Pointer::new( - alloc_id.map(|alloc_id| { - Tag::Concrete(ConcreteTag { alloc_id, sb: SbTag::Untagged }) - }), + alloc_id.map(|alloc_id| Tag::Concrete { alloc_id, sb: SbTag::Untagged }), Size::from_bytes(addr), ) } @@ -222,8 +220,8 @@ impl<'mir, 'tcx> GlobalStateInner { ) -> Option<(AllocId, Size)> { let (tag, addr) = ptr.into_parts(); // addr is absolute (Tag provenance) - let alloc_id = if let Tag::Concrete(concrete) = tag { - concrete.alloc_id + let alloc_id = if let Tag::Concrete { alloc_id, .. } = tag { + alloc_id } else { // A wildcard pointer. assert_eq!(ecx.machine.intptrcast.borrow().provenance_mode, ProvenanceMode::Permissive); diff --git a/src/lib.rs b/src/lib.rs index 432f469733cb..68489c9b47b9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,7 @@ #![feature(io_error_more)] #![feature(yeet_expr)] #![feature(is_some_with)] +#![feature(nonzero_ops)] #![warn(rust_2018_idioms)] #![allow( clippy::collapsible_else_if, @@ -81,15 +82,15 @@ pub use crate::eval::{ pub use crate::helpers::{CurrentSpan, EvalContextExt as HelpersEvalContextExt}; pub use crate::intptrcast::ProvenanceMode; pub use crate::machine::{ - AllocExtra, ConcreteTag, Evaluator, FrameData, MiriEvalContext, MiriEvalContextExt, - MiriMemoryKind, Tag, NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, + AllocExtra, Evaluator, FrameData, MiriEvalContext, MiriEvalContextExt, MiriMemoryKind, Tag, + NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, }; pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ - CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, SbTag, Stack, - Stacks, + CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, SbTag, SbTagExtra, + Stack, Stacks, }; pub use crate::sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId}; pub use crate::thread::{ diff --git a/src/machine.rs b/src/machine.rs index 3704a5385141..5810ac6d7eca 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -130,17 +130,14 @@ impl fmt::Display for MiriMemoryKind { /// Pointer provenance (tag). #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Tag { - Concrete(ConcreteTag), + Concrete { + alloc_id: AllocId, + /// Stacked Borrows tag. + sb: SbTag, + }, Wildcard, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct ConcreteTag { - pub alloc_id: AllocId, - /// Stacked Borrows tag. - pub sb: SbTag, -} - #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(Pointer, 24); // #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] @@ -160,15 +157,15 @@ impl Provenance for Tag { write!(f, "0x{:x}", addr.bytes())?; match tag { - Tag::Concrete(tag) => { + Tag::Concrete { alloc_id, sb } => { // Forward `alternate` flag to `alloc_id` printing. if f.alternate() { - write!(f, "[{:#?}]", tag.alloc_id)?; + write!(f, "[{:#?}]", alloc_id)?; } else { - write!(f, "[{:?}]", tag.alloc_id)?; + write!(f, "[{:?}]", alloc_id)?; } // Print Stacked Borrows tag. - write!(f, "{:?}", tag.sb)?; + write!(f, "{:?}", sb)?; } Tag::Wildcard => { write!(f, "[Wildcard]")?; @@ -180,7 +177,7 @@ impl Provenance for Tag { fn get_alloc_id(self) -> Option { match self { - Tag::Concrete(concrete) => Some(concrete.alloc_id), + Tag::Concrete { alloc_id, .. } => Some(alloc_id), Tag::Wildcard => None, } } @@ -489,8 +486,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { type AllocExtra = AllocExtra; type PointerTag = Tag; - // `None` represents a wildcard pointer. - type TagExtra = Option; + type TagExtra = SbTagExtra; type MemoryMap = MonoHashMap, Allocation)>; @@ -683,7 +679,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { SbTag::Untagged }; Pointer::new( - Tag::Concrete(ConcreteTag { alloc_id: ptr.provenance, sb: sb_tag }), + Tag::Concrete { alloc_id: ptr.provenance, sb: sb_tag }, Size::from_bytes(absolute_addr), ) } @@ -709,7 +705,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ptr: Pointer, ) -> InterpResult<'tcx> { match ptr.provenance { - Tag::Concrete(ConcreteTag { alloc_id, sb }) => { + Tag::Concrete { alloc_id, sb } => { intptrcast::GlobalStateInner::expose_ptr(ecx, alloc_id, sb); } Tag::Wildcard => { @@ -730,8 +726,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { rel.map(|(alloc_id, size)| { let sb = match ptr.provenance { - Tag::Concrete(ConcreteTag { sb, .. }) => Some(sb), - Tag::Wildcard => None, + Tag::Concrete { sb, .. } => SbTagExtra::Concrete(sb), + Tag::Wildcard => SbTagExtra::Wildcard, }; (alloc_id, size, sb) }) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 8411d85f0e01..b7b339ce77bf 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -3,6 +3,7 @@ use log::trace; use std::cell::RefCell; +use std::cmp; use std::fmt; use std::num::NonZeroU64; @@ -60,6 +61,32 @@ impl fmt::Debug for SbTag { } } +/// The "extra" information an SB pointer has over a regular AllocId. +/// Newtype for `Option`. +#[derive(Copy, Clone)] +pub enum SbTagExtra { + Concrete(SbTag), + Wildcard, +} + +impl fmt::Debug for SbTagExtra { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + SbTagExtra::Concrete(tag) => write!(f, "{tag:?}"), + SbTagExtra::Wildcard => write!(f, ""), + } + } +} + +impl SbTagExtra { + fn and_then(self, f: impl FnOnce(SbTag) -> Option) -> Option { + match self { + SbTagExtra::Concrete(tag) => f(tag), + SbTagExtra::Wildcard => None, + } + } +} + /// Indicates which permission is granted (by this item to some pointers) #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum Permission { @@ -108,6 +135,8 @@ pub struct Stack { /// wildcard pointers are used to access this location. What we do know is that `borrows` are at /// the top of the stack, and below it are arbitrarily many items whose `tag` is either /// `Untagged` or strictly less than `id`. + /// When the bottom is unknown, `borrows` always has a `SharedReadOnly` or `Unique` at the bottom; + /// we never have the unknown-to-known boundary in an SRW group. unknown_bottom: Option, } @@ -289,35 +318,37 @@ impl Permission { /// Core per-location operations: access, dealloc, reborrow. impl<'tcx> Stack { /// Find the item granting the given kind of access to the given tag, and return where - /// it is on the stack. - /// `Ok(None)` indicates it matched the "unknown" part of the stack, or it was a wildcard tag - /// and we have no clue what exactly it matched (but it could have matched something) + /// it is on the stack. For wildcard tags, the given index is approximate, but if *no* + /// index is given it means the match was *not* in the known part of the stack. + /// `Ok(None)` indicates it matched the "unknown" part of the stack. /// `Err` indicates it was not found. fn find_granting( &self, access: AccessKind, - tag: Option, + tag: SbTagExtra, exposed_tags: &FxHashSet, ) -> Result, ()> { - let Some(tag) = tag else { + let SbTagExtra::Concrete(tag) = tag else { // Handle the wildcard case. // Go search the stack for an exposed tag. - let maybe_in_stack = self - .borrows - .iter() - .rev() // search top-to-bottom - .find_map(|item| { - // If the item fits and *might* be this wildcard, use it. - if item.perm.grants(access) && exposed_tags.contains(&item.tag) { - Some(()) - } else { - None - } - }) - .is_some(); + if let Some(idx) = + self.borrows + .iter() + .enumerate() // we also need to know *where* in the stack + .rev() // search top-to-bottom + .find_map(|(idx, item)| { + // If the item fits and *might* be this wildcard, use it. + if item.perm.grants(access) && exposed_tags.contains(&item.tag) { + Some(idx) + } else { + None + } + }) + { + return Ok(Some(idx)); + } // If we couldn't find it in the stack, check the unknown bottom. - let found = maybe_in_stack || self.unknown_bottom.is_some(); - return if found { Ok(None) } else { Err(()) }; + return if self.unknown_bottom.is_some() { Ok(None) } else { Err(()) }; }; if let Some(idx) = @@ -351,8 +382,10 @@ impl<'tcx> Stack { match perm { Permission::SharedReadOnly => bug!("Cannot use SharedReadOnly for writing"), Permission::Disabled => bug!("Cannot use Disabled for anything"), - // On a write, everything above us is incompatible. - Permission::Unique => granting + 1, + Permission::Unique => { + // On a write, everything above us is incompatible. + granting + 1 + } Permission::SharedReadWrite => { // The SharedReadWrite *just* above us are compatible, to skip those. let mut idx = granting + 1; @@ -380,7 +413,7 @@ impl<'tcx> Stack { /// currently checking. fn check_protector( item: &Item, - provoking_access: Option<(SbTag, AllocRange, Size, AccessKind)>, // just for debug printing and error messages + provoking_access: Option<(SbTagExtra, AllocRange, Size, AccessKind)>, // just for debug printing and error messages global: &GlobalStateInner, alloc_history: &mut AllocHistory, ) -> InterpResult<'tcx> { @@ -401,12 +434,14 @@ impl<'tcx> Stack { tag, item ), None, - alloc_history.get_logs_relevant_to( - tag, - alloc_range, - offset, - Some(item.tag), - ), + tag.and_then(|tag| { + alloc_history.get_logs_relevant_to( + tag, + alloc_range, + offset, + Some(item.tag), + ) + }), ))? } else { Err(err_sb_ub( @@ -427,7 +462,7 @@ impl<'tcx> Stack { fn access( &mut self, access: AccessKind, - tag: Option, + tag: SbTagExtra, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &mut GlobalStateInner, current_span: &mut CurrentSpan<'_, '_, 'tcx>, @@ -441,22 +476,22 @@ impl<'tcx> Stack { alloc_history.access_error(access, tag, alloc_id, alloc_range, offset, self) })?; - let Some(granting_idx) = granting_idx else { - // The access used a wildcard pointer or matched the unknown bottom. - // Nobody knows what happened, so forget everything. - trace!("access: clearing stack due to wildcard"); - self.borrows.clear(); - self.unknown_bottom = Some(global.next_ptr_id); - return Ok(()); - }; - let tag = tag.unwrap(); // only precise tags have precise locations - // Step 2: Remove incompatible items above them. Make sure we do not remove protected // items. Behavior differs for reads and writes. + // In case of wildcards/unknown matches, we remove everything that is *definitely* gone. if access == AccessKind::Write { // Remove everything above the write-compatible items, like a proper stack. This makes sure read-only and unique // pointers become invalid on write accesses (ensures F2a, and ensures U2 for write accesses). - let first_incompatible_idx = self.find_first_write_incompatible(granting_idx); + let first_incompatible_idx = if let Some(granting_idx) = granting_idx { + // The granting_idx *might* be approximate, but any lower idx would remove more + // things. Even if this is a Unique and the lower idx is an SRW (which removes + // less), there is an SRW group boundary here so strictly more would get removed. + self.find_first_write_incompatible(granting_idx) + } else { + // We are writing to something in the unknown part. + // There is a SRW group boundary between the unknown and the known, so everything is incompatible. + 0 + }; for item in self.borrows.drain(first_incompatible_idx..).rev() { trace!("access: popping item {:?}", item); Stack::check_protector( @@ -476,7 +511,13 @@ impl<'tcx> Stack { // This pattern occurs a lot in the standard library: create a raw pointer, then also create a shared // reference and use that. // We *disable* instead of removing `Unique` to avoid "connecting" two neighbouring blocks of SRWs. - let first_incompatible_idx = granting_idx + 1; + let first_incompatible_idx = if let Some(granting_idx) = granting_idx { + // The granting_idx *might* be approximate, but any lower idx would disable more things. + granting_idx + 1 + } else { + // We are reading from something in the unknown part. That means *all* `Unique` we know about are dead now. + 0 + }; for idx in (first_incompatible_idx..self.borrows.len()).rev() { let item = &mut self.borrows[idx]; @@ -494,6 +535,31 @@ impl<'tcx> Stack { } } + // If this was an approximate action, we now collapse everything into an unknown. + if granting_idx.is_none() || matches!(tag, SbTagExtra::Wildcard) { + // Compute the upper bound of the items that remain. + // (This is why we did all the work above: to reduce the items we have to consider here.) + let mut max = NonZeroU64::new(1).unwrap(); + for item in &self.borrows { + // Skip disabled items, they cannot be matched anyway. + if !matches!(item.perm, Permission::Disabled) { + if let SbTag::Tagged(tag) = item.tag { + // We are looking for a strict upper bound, so add 1 to this tag. + max = cmp::max(tag.checked_add(1).unwrap(), max); + } + } + } + if let Some(unk) = self.unknown_bottom { + max = cmp::max(unk, max); + } + // Use `max` as new strict upper bound for everything. + trace!( + "access: forgetting stack to upper bound {max} due to wildcard or unknown access" + ); + self.borrows.clear(); + self.unknown_bottom = Some(max); + } + // Done. Ok(()) } @@ -502,7 +568,7 @@ impl<'tcx> Stack { /// active protectors at all because we will remove all items. fn dealloc( &mut self, - tag: Option, + tag: SbTagExtra, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &GlobalStateInner, alloc_history: &mut AllocHistory, @@ -534,7 +600,7 @@ impl<'tcx> Stack { /// `range` that we are currently checking. fn grant( &mut self, - derived_from: Option, + derived_from: SbTagExtra, new: Item, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &mut GlobalStateInner, @@ -562,10 +628,12 @@ impl<'tcx> Stack { "this case only makes sense for stack-like accesses" ); - let Some(granting_idx) = granting_idx else { + let (Some(granting_idx), SbTagExtra::Concrete(_)) = (granting_idx, derived_from) else { // The parent is a wildcard pointer or matched the unknown bottom. - // Nobody knows what happened, so forget everything. - trace!("reborrow: clearing stack due to wildcard"); + // This is approximate. Nobody knows what happened, so forget everything. + // The new thing is SRW anyway, so we cannot push it "on top of the unkown part" + // (for all we know, it might join an SRW group inside the unknown). + trace!("reborrow: forgetting stack entirely due to SharedReadWrite reborrow from wildcard or unknown"); self.borrows.clear(); self.unknown_bottom = Some(global.next_ptr_id); return Ok(()); @@ -723,7 +791,7 @@ impl Stacks { pub fn memory_read<'tcx>( &self, alloc_id: AllocId, - tag: Option, + tag: SbTagExtra, range: AllocRange, state: &GlobalState, mut current_span: CurrentSpan<'_, '_, 'tcx>, @@ -752,7 +820,7 @@ impl Stacks { pub fn memory_written<'tcx>( &mut self, alloc_id: AllocId, - tag: Option, + tag: SbTagExtra, range: AllocRange, state: &GlobalState, mut current_span: CurrentSpan<'_, '_, 'tcx>, @@ -781,7 +849,7 @@ impl Stacks { pub fn memory_deallocated<'tcx>( &mut self, alloc_id: AllocId, - tag: Option, + tag: SbTagExtra, range: AllocRange, state: &GlobalState, ) -> InterpResult<'tcx> { @@ -798,6 +866,8 @@ impl Stacks { /// to grant for which references, and when to add protectors. impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + /// Returns the `AllocId` the reborrow was done in, if some actual borrow stack manipulation + /// happened. fn reborrow( &mut self, place: &MPlaceTy<'tcx, Tag>, @@ -805,7 +875,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx kind: RefKind, new_tag: SbTag, protect: bool, - ) -> InterpResult<'tcx> { + ) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); let current_span = &mut this.machine.current_span(); @@ -815,6 +885,10 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx base_offset, orig_tag| -> InterpResult<'tcx> { + let SbTagExtra::Concrete(orig_tag) = orig_tag else { + // FIXME: should we log this? + return Ok(()) + }; let extra = this.get_alloc_extra(alloc_id)?; let stacked_borrows = extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); @@ -832,6 +906,13 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; if size == Size::ZERO { + trace!( + "reborrow of size 0: {} reference {:?} derived from {:?} (pointee {})", + kind, + new_tag, + place.ptr, + place.layout.ty, + ); // Don't update any stacks for a zero-sized access; borrow stacks are per-byte and this // touches no bytes so there is no stack to put this tag in. // However, if the pointer for this operation points at a real allocation we still @@ -840,24 +921,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dangling slices are a common case here; it's valid to get their length but with raw // pointer tagging for example all calls to get_unchecked on them are invalid. if let Ok((alloc_id, base_offset, orig_tag)) = this.ptr_try_get_alloc_id(place.ptr) { - if let Some(orig_tag) = orig_tag { - log_creation(this, current_span, alloc_id, base_offset, orig_tag)?; - } + log_creation(this, current_span, alloc_id, base_offset, orig_tag)?; + return Ok(Some(alloc_id)); } - - trace!( - "reborrow of size 0: {} reference {:?} derived from {:?} (pointee {})", - kind, - new_tag, - place.ptr, - place.layout.ty, - ); - return Ok(()); + // This pointer doesn't come with an AllocId. :shrug: + return Ok(None); } let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?; - if let Some(orig_tag) = orig_tag { - log_creation(this, current_span, alloc_id, base_offset, orig_tag)?; - } + log_creation(this, current_span, alloc_id, base_offset, orig_tag)?; // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). let (alloc_size, _) = @@ -937,7 +1008,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) }) })?; - return Ok(()); + return Ok(Some(alloc_id)); } }; // Here we can avoid `borrow()` calls because we have mutable references. @@ -962,7 +1033,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) })?; - Ok(()) + Ok(Some(alloc_id)) } /// Retags an indidual pointer, returning the retagged version. @@ -997,16 +1068,22 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Reborrow. - this.reborrow(&place, size, kind, new_tag, protect)?; + let alloc_id = this.reborrow(&place, size, kind, new_tag, protect)?; // Adjust pointer. let new_place = place.map_provenance(|p| { - p.map(|t| { - // TODO: Fix this eventually - if let Tag::Concrete(t) = t { - Tag::Concrete(ConcreteTag { sb: new_tag, ..t }) - } else { - t + p.map(|prov| { + match alloc_id { + Some(alloc_id) => { + // If `reborrow` could figure out the AllocId of this ptr, hard-code it into the new one. + // Even if we started out with a wildcard, this newly retagged pointer is tied to that allocation. + Tag::Concrete { alloc_id, sb: new_tag } + } + None => { + // Looks like this has to stay a wildcard pointer. + assert!(matches!(prov, Tag::Wildcard)); + Tag::Wildcard + } } }) }); diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index 91dfe22c1964..d3c706c1404a 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -4,12 +4,11 @@ use rustc_middle::mir::interpret::{AllocId, AllocRange}; use rustc_span::{Span, SpanData}; use rustc_target::abi::Size; -use core::fmt::Debug; - use crate::helpers::{CurrentSpan, HexRange}; use crate::stacked_borrows::{err_sb_ub, AccessKind, Permission}; use crate::Item; use crate::SbTag; +use crate::SbTagExtra; use crate::Stack; use rustc_middle::mir::interpret::InterpError; @@ -199,19 +198,15 @@ impl AllocHistory { /// Report a descriptive error when `new` could not be granted from `derived_from`. pub fn grant_error<'tcx>( &self, - derived_from: Option, + derived_from: SbTagExtra, new: Item, alloc_id: AllocId, alloc_range: AllocRange, error_offset: Size, stack: &Stack, ) -> InterpError<'tcx> { - // TODO: Fix this properly - let z = &derived_from; - let f = if let Some(ref t) = z { t as &dyn Debug } else { &"" as &dyn Debug }; let action = format!( - "trying to reborrow {:?} for {:?} permission at {}[{:#x}]", - f, + "trying to reborrow {derived_from:?} for {:?} permission at {}[{:#x}]", new.perm, alloc_id, error_offset.bytes(), @@ -229,18 +224,14 @@ impl AllocHistory { pub fn access_error<'tcx>( &self, access: AccessKind, - tag: Option, + tag: SbTagExtra, alloc_id: AllocId, alloc_range: AllocRange, error_offset: Size, stack: &Stack, ) -> InterpError<'tcx> { - let z = &tag; - let f = if let Some(ref t) = z { t as &dyn Debug } else { &"" as &dyn Debug }; let action = format!( - "attempting a {} using {:?} at {}[{:#x}]", - access, - f, + "attempting a {access} using {tag:?} at {}[{:#x}]", alloc_id, error_offset.bytes(), ); @@ -260,8 +251,8 @@ fn operation_summary( format!("this error occurs as part of {} at {:?}{}", operation, alloc_id, HexRange(alloc_range)) } -fn error_cause(stack: &Stack, tag: Option) -> &'static str { - if let Some(tag) = tag { +fn error_cause(stack: &Stack, tag: SbTagExtra) -> &'static str { + if let SbTagExtra::Concrete(tag) = tag { if stack.borrows.iter().any(|item| item.tag == tag && item.perm != Permission::Disabled) { ", but that tag only grants SharedReadOnly permission for this location" } else { diff --git a/tests/fail/stacked_borrows/exposed_only_ro.stderr b/tests/fail/stacked_borrows/exposed_only_ro.stderr index 9748fe78c718..ceeca61e5587 100644 --- a/tests/fail/stacked_borrows/exposed_only_ro.stderr +++ b/tests/fail/stacked_borrows/exposed_only_ro.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: attempting a write access using "" at ALLOC[0x0], but no exposed tags are valid in the borrow stack for this location +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but no exposed tags are valid in the borrow stack for this location --> $DIR/exposed_only_ro.rs:LL:CC | LL | unsafe { *ptr = 0 }; | ^^^^^^^^ | | - | attempting a write access using "" at ALLOC[0x0], but no exposed tags are valid in the borrow stack for this location + | attempting a write access using at ALLOC[0x0], but no exposed tags are valid in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs b/tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs new file mode 100644 index 000000000000..61a5e05d34cd --- /dev/null +++ b/tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs @@ -0,0 +1,17 @@ +// compile-flags: -Zmiri-permissive-provenance + +fn main() { + unsafe { + let root = &mut 42; + let addr = root as *mut i32 as usize; + let exposed_ptr = addr as *mut i32; + // From the exposed ptr, we get a new unique ptr. + let root2 = &mut *exposed_ptr; + let _fool = root2 as *mut _; // this would have fooled the old untagged pointer logic + // Stack: Unknown( at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_read_despite_exposed1.rs:LL:CC + | +LL | let _val = *root2; + | ^^^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information + + = note: inside `main` at $DIR/illegal_read_despite_exposed1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs b/tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs new file mode 100644 index 000000000000..b45b7b5d285c --- /dev/null +++ b/tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs @@ -0,0 +1,18 @@ +// compile-flags: -Zmiri-permissive-provenance + +fn main() { + unsafe { + let root = &mut 42; + let addr = root as *mut i32 as usize; + let exposed_ptr = addr as *mut i32; + // From the exposed ptr, we get a new unique ptr. + let root2 = &mut *exposed_ptr; + // let _fool = root2 as *mut _; // this would [fool] us, since SRW(N+1) remains on the stack + // Stack: Unknown( at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_read_despite_exposed2.rs:LL:CC + | +LL | let _val = *root2; + | ^^^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information + + = note: inside `main` at $DIR/illegal_read_despite_exposed2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs b/tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs new file mode 100644 index 000000000000..b50399b9df52 --- /dev/null +++ b/tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs @@ -0,0 +1,16 @@ +// compile-flags: -Zmiri-permissive-provenance + +fn main() { + unsafe { + let root = &mut 42; + let addr = root as *mut i32 as usize; + let exposed_ptr = addr as *mut i32; + // From the exposed ptr, we get a new SRO ptr. + let root2 = &*exposed_ptr; + // Stack: Unknown( at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_write_despite_exposed1.rs:LL:CC + | +LL | let _val = *root2; + | ^^^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information + + = note: inside `main` at $DIR/illegal_write_despite_exposed1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + From 58c79c5b6f2717241ec14aa61442b98ca8b66d00 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 24 Jun 2022 22:02:17 -0400 Subject: [PATCH 3343/5092] tweaks and feedback --- src/machine.rs | 8 +- src/stacked_borrows.rs | 84 ++++++++----------- src/stacked_borrows/diagnostics.rs | 2 +- .../stacked_borrows/exposed_only_ro.stderr | 4 +- .../illegal_read_despite_exposed2.rs | 10 ++- 5 files changed, 48 insertions(+), 60 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 5810ac6d7eca..79414ada5eac 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -646,7 +646,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { let alloc: Allocation = alloc.convert_tag_add_extra( &ecx.tcx, AllocExtra { - stacked_borrows: stacks, + stacked_borrows: stacks.map(RefCell::new), data_race: race_alloc, weak_memory: buffer_alloc, }, @@ -745,7 +745,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { data_race.read(alloc_id, range, machine.data_race.as_ref().unwrap())?; } if let Some(stacked_borrows) = &alloc_extra.stacked_borrows { - stacked_borrows.memory_read( + stacked_borrows.borrow_mut().memory_read( alloc_id, tag, range, @@ -771,7 +771,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { data_race.write(alloc_id, range, machine.data_race.as_mut().unwrap())?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { - stacked_borrows.memory_written( + stacked_borrows.get_mut().memory_written( alloc_id, tag, range, @@ -800,7 +800,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { data_race.deallocate(alloc_id, range, machine.data_race.as_mut().unwrap())?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { - stacked_borrows.memory_deallocated( + stacked_borrows.get_mut().memory_deallocated( alloc_id, tag, range, diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index b7b339ce77bf..6fa70ddfc5d4 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -25,7 +25,8 @@ use diagnostics::{AllocHistory, TagHistory}; pub type PtrId = NonZeroU64; pub type CallId = NonZeroU64; -pub type AllocExtra = Stacks; +// Even reading memory can have effects on the stack, so we need a `RefCell` here. +pub type AllocExtra = RefCell; /// Tracking pointer provenance #[derive(Copy, Clone, Hash, Eq)] @@ -131,7 +132,7 @@ pub struct Stack { /// * Above a `SharedReadOnly` there can only be more `SharedReadOnly`. /// * Except for `Untagged`, no tag occurs in the stack more than once. borrows: Vec, - /// If this is `Some(id)`, then the actual current stack is unknown. THis can happen when + /// If this is `Some(id)`, then the actual current stack is unknown. This can happen when /// wildcard pointers are used to access this location. What we do know is that `borrows` are at /// the top of the stack, and below it are arbitrarily many items whose `tag` is either /// `Untagged` or strictly less than `id`. @@ -144,11 +145,11 @@ pub struct Stack { #[derive(Clone, Debug)] pub struct Stacks { // Even reading memory can have effects on the stack, so we need a `RefCell` here. - stacks: RefCell>, + stacks: RangeMap, /// Stores past operations on this allocation - history: RefCell, + history: AllocHistory, /// The set of tags that have been exposed inside this allocation. - exposed_tags: RefCell>, + exposed_tags: FxHashSet, } /// Extra global state, available to the memory access hooks. @@ -689,34 +690,14 @@ impl<'tcx> Stacks { let stack = Stack { borrows: vec![item], unknown_bottom: None }; Stacks { - stacks: RefCell::new(RangeMap::new(size, stack)), - history: RefCell::new(AllocHistory::new()), - exposed_tags: RefCell::new(FxHashSet::default()), + stacks: RangeMap::new(size, stack), + history: AllocHistory::new(), + exposed_tags: FxHashSet::default(), } } /// Call `f` on every stack in the range. fn for_each( - &self, - range: AllocRange, - mut f: impl FnMut( - Size, - &mut Stack, - &mut AllocHistory, - &mut FxHashSet, - ) -> InterpResult<'tcx>, - ) -> InterpResult<'tcx> { - let mut stacks = self.stacks.borrow_mut(); - let history = &mut *self.history.borrow_mut(); - let exposed_tags = &mut *self.exposed_tags.borrow_mut(); - for (offset, stack) in stacks.iter_mut(range.start, range.size) { - f(offset, stack, history, exposed_tags)?; - } - Ok(()) - } - - /// Call `f` on every stack in the range. - fn for_each_mut( &mut self, range: AllocRange, mut f: impl FnMut( @@ -726,11 +707,8 @@ impl<'tcx> Stacks { &mut FxHashSet, ) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { - let stacks = self.stacks.get_mut(); - let history = &mut *self.history.get_mut(); - let exposed_tags = self.exposed_tags.get_mut(); - for (offset, stack) in stacks.iter_mut(range.start, range.size) { - f(offset, stack, history, exposed_tags)?; + for (offset, stack) in self.stacks.iter_mut(range.start, range.size) { + f(offset, stack, &mut self.history, &mut self.exposed_tags)?; } Ok(()) } @@ -777,8 +755,8 @@ impl Stacks { (tag, Permission::SharedReadWrite) } }; - let stacks = Stacks::new(size, perm, base_tag); - stacks.history.borrow_mut().log_creation( + let mut stacks = Stacks::new(size, perm, base_tag); + stacks.history.log_creation( None, base_tag, alloc_range(Size::ZERO, size), @@ -789,7 +767,7 @@ impl Stacks { #[inline(always)] pub fn memory_read<'tcx>( - &self, + &mut self, alloc_id: AllocId, tag: SbTagExtra, range: AllocRange, @@ -832,7 +810,7 @@ impl Stacks { range.size.bytes() ); let mut state = state.borrow_mut(); - self.for_each_mut(range, |offset, stack, history, exposed_tags| { + self.for_each(range, |offset, stack, history, exposed_tags| { stack.access( AccessKind::Write, tag, @@ -855,7 +833,7 @@ impl Stacks { ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", tag, alloc_id, range.size.bytes()); let state = state.borrow(); - self.for_each_mut(range, |offset, stack, history, exposed_tags| { + self.for_each(range, |offset, stack, history, exposed_tags| { stack.dealloc(tag, (alloc_id, range, offset), &state, history, exposed_tags) })?; Ok(()) @@ -890,17 +868,19 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(()) }; let extra = this.get_alloc_extra(alloc_id)?; - let stacked_borrows = - extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); - let mut alloc_history = stacked_borrows.history.borrow_mut(); - alloc_history.log_creation( + let mut stacked_borrows = extra + .stacked_borrows + .as_ref() + .expect("we should have Stacked Borrows data") + .borrow_mut(); + stacked_borrows.history.log_creation( Some(orig_tag), new_tag, alloc_range(base_offset, size), current_span, ); if protect { - alloc_history.log_protector(orig_tag, new_tag, current_span); + stacked_borrows.history.log_protector(orig_tag, new_tag, current_span); } Ok(()) }; @@ -976,8 +956,11 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We have to use shared references to alloc/memory_extra here since // `visit_freeze_sensitive` needs to access the global state. let extra = this.get_alloc_extra(alloc_id)?; - let stacked_borrows = - extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); + let mut stacked_borrows = extra + .stacked_borrows + .as_ref() + .expect("we should have Stacked Borrows data") + .borrow_mut(); this.visit_freeze_sensitive(place, size, |mut range, frozen| { // Adjust range. range.start += base_offset; @@ -1015,13 +998,16 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Note that this asserts that the allocation is mutable -- but since we are creating a // mutable pointer, that seems reasonable. let (alloc_extra, machine) = this.get_alloc_extra_mut(alloc_id)?; - let stacked_borrows = - alloc_extra.stacked_borrows.as_mut().expect("we should have Stacked Borrows data"); + let mut stacked_borrows = alloc_extra + .stacked_borrows + .as_mut() + .expect("we should have Stacked Borrows data") + .borrow_mut(); let item = Item { perm, tag: new_tag, protector }; let range = alloc_range(base_offset, size); let mut global = machine.stacked_borrows.as_ref().unwrap().borrow_mut(); let current_span = &mut machine.current_span(); // `get_alloc_extra_mut` invalidated our old `current_span` - stacked_borrows.for_each_mut(range, |offset, stack, history, exposed_tags| { + stacked_borrows.for_each(range, |offset, stack, history, exposed_tags| { stack.grant( orig_tag, item, @@ -1177,7 +1163,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match this.get_alloc_extra(alloc_id) { Ok(alloc_extra) => { trace!("Stacked Borrows tag {tag:?} exposed in {alloc_id}"); - alloc_extra.stacked_borrows.as_ref().unwrap().exposed_tags.borrow_mut().insert(tag); + alloc_extra.stacked_borrows.as_ref().unwrap().borrow_mut().exposed_tags.insert(tag); } Err(err) => { trace!( diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index d3c706c1404a..a4a7f5e7a1e3 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -259,6 +259,6 @@ fn error_cause(stack: &Stack, tag: SbTagExtra) -> &'static str { ", but that tag does not exist in the borrow stack for this location" } } else { - ", but no exposed tags are valid in the borrow stack for this location" + ", but no exposed tags have suitable permission in the borrow stack for this location" } } diff --git a/tests/fail/stacked_borrows/exposed_only_ro.stderr b/tests/fail/stacked_borrows/exposed_only_ro.stderr index ceeca61e5587..28fa98b6020c 100644 --- a/tests/fail/stacked_borrows/exposed_only_ro.stderr +++ b/tests/fail/stacked_borrows/exposed_only_ro.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but no exposed tags are valid in the borrow stack for this location +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but no exposed tags have suitable permission in the borrow stack for this location --> $DIR/exposed_only_ro.rs:LL:CC | LL | unsafe { *ptr = 0 }; | ^^^^^^^^ | | - | attempting a write access using at ALLOC[0x0], but no exposed tags are valid in the borrow stack for this location + | attempting a write access using at ALLOC[0x0], but no exposed tags have suitable permission in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs b/tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs index b45b7b5d285c..19d0784591e4 100644 --- a/tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs +++ b/tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs @@ -7,12 +7,14 @@ fn main() { let exposed_ptr = addr as *mut i32; // From the exposed ptr, we get a new unique ptr. let root2 = &mut *exposed_ptr; - // let _fool = root2 as *mut _; // this would [fool] us, since SRW(N+1) remains on the stack - // Stack: Unknown( Date: Mon, 20 Jun 2022 15:16:32 -0400 Subject: [PATCH 3344/5092] Actually pass through the request for --color=always --- cargo-miri/bin.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index a7be5843d4e6..6caa96a4f6f6 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -957,7 +957,10 @@ fn phase_runner(binary: &Path, binary_args: env::Args, phase: RunnerPhase) { // to emit the diagnostic structure that Cargo would consume from rustc to emit colored // diagnostics, and ask rustc to emit them. // See https://github.com/rust-lang/miri/issues/2037 - if arg.split(',').any(|a| a == "diagnostic-rendered-ansi") { + // First skip over the leading `=`, then check for diagnostic-rendered-ansi in the + // comma-separated list + if suffix.strip_prefix('=').unwrap().split(',').any(|a| a == "diagnostic-rendered-ansi") + { cmd.arg("--color=always"); } // But aside from remembering that colored output was requested, drop this argument. From f66c64bed25448af4b732b86255bd0c624dd4bac Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Jun 2022 11:52:29 -0400 Subject: [PATCH 3345/5092] remove a FIXME that is not actually a bug --- src/shims/unix/linux/sync.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/shims/unix/linux/sync.rs b/src/shims/unix/linux/sync.rs index 0fdbde8d6775..6be1e672f85f 100644 --- a/src/shims/unix/linux/sync.rs +++ b/src/shims/unix/linux/sync.rs @@ -172,7 +172,6 @@ pub fn futex<'tcx>( this.atomic_fence(&[], AtomicFenceOp::SeqCst)?; // Read an `i32` through the pointer, regardless of any wrapper types. // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`. - // FIXME: this fails if `addr` is not a pointer type. let futex_val = this .read_scalar_at_offset_atomic( &addr.into(), From 54fbd313a6f08681a02d51fdafa321cb6a14d87e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Jun 2022 12:27:50 -0400 Subject: [PATCH 3346/5092] README: multi-seed loop: also test the 0 seed --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f6b2413c65f5..7f373f078a09 100644 --- a/README.md +++ b/README.md @@ -192,7 +192,7 @@ randomness that is used to determine allocation base addresses. The following snippet calls Miri in a loop with different values for the seed: ``` -for seed in $({ echo obase=16; seq 255; } | bc); do +for seed in $({ echo obase=16; seq 0 255; } | bc); do MIRIFLAGS=-Zmiri-seed=$seed cargo miri test || { echo "Last seed: $seed"; break; }; done ``` From 9124420b2fd64ded303d5e8d8ad41df813d83985 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Jun 2022 15:06:53 -0400 Subject: [PATCH 3347/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 45773390616b..dafb049cc5a8 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a09c668c965f735f4cd59e7158662b9daa0b71ba +8aab472d52ba7314dc193c73abcd384e2586123c From e5022bf48ab9e2fff34754d018bba61e6dd2feb5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Jun 2022 15:17:37 -0400 Subject: [PATCH 3348/5092] join all the threads --- tests/pass/concurrency/sync.rs | 51 ++---------------------- tests/pass/concurrency/sync_nopreempt.rs | 49 ++++++++++++++++++++++- 2 files changed, 51 insertions(+), 49 deletions(-) diff --git a/tests/pass/concurrency/sync.rs b/tests/pass/concurrency/sync.rs index 5b7805ba2265..396c1a97e07e 100644 --- a/tests/pass/concurrency/sync.rs +++ b/tests/pass/concurrency/sync.rs @@ -35,7 +35,7 @@ fn check_conditional_variables_notify_one() { let pair2 = pair.clone(); // Spawn a new thread. - thread::spawn(move || { + let t = thread::spawn(move || { thread::yield_now(); let (lock, cvar) = &*pair2; let mut started = lock.lock().unwrap(); @@ -50,6 +50,8 @@ fn check_conditional_variables_notify_one() { while !*started { started = cvar.wait(started).unwrap(); } + + t.join().unwrap(); } /// Test that waiting on a conditional variable with a timeout does not @@ -191,51 +193,6 @@ fn check_once() { } } -fn check_rwlock_unlock_bug1() { - // There was a bug where when un-read-locking an rwlock that still has other - // readers waiting, we'd accidentally also let a writer in. - // That caused an ICE. - let l = Arc::new(RwLock::new(0)); - - let r1 = l.read().unwrap(); - let r2 = l.read().unwrap(); - - // Make a waiting writer. - let l2 = l.clone(); - thread::spawn(move || { - let mut w = l2.write().unwrap(); - *w += 1; - }); - thread::yield_now(); - - drop(r1); - assert_eq!(*r2, 0); - thread::yield_now(); - thread::yield_now(); - thread::yield_now(); - assert_eq!(*r2, 0); - drop(r2); -} - -fn check_rwlock_unlock_bug2() { - // There was a bug where when un-read-locking an rwlock by letting the last reader leaver, - // we'd forget to wake up a writer. - // That meant the writer thread could never run again. - let l = Arc::new(RwLock::new(0)); - - let r = l.read().unwrap(); - - // Make a waiting writer. - let l2 = l.clone(); - let h = thread::spawn(move || { - let _w = l2.write().unwrap(); - }); - thread::yield_now(); - - drop(r); - h.join().unwrap(); -} - fn park_timeout() { let start = Instant::now(); @@ -277,8 +234,6 @@ fn main() { check_rwlock_write(); check_rwlock_read_no_deadlock(); check_once(); - check_rwlock_unlock_bug1(); - check_rwlock_unlock_bug2(); park_timeout(); park_unpark(); check_condvar(); diff --git a/tests/pass/concurrency/sync_nopreempt.rs b/tests/pass/concurrency/sync_nopreempt.rs index 8895d62df95f..391f65ae5a9c 100644 --- a/tests/pass/concurrency/sync_nopreempt.rs +++ b/tests/pass/concurrency/sync_nopreempt.rs @@ -2,7 +2,7 @@ // We are making scheduler assumptions here. // compile-flags: -Zmiri-strict-provenance -Zmiri-preemption-rate=0 -use std::sync::{Arc, Condvar, Mutex}; +use std::sync::{Arc, Condvar, Mutex, RwLock}; use std::thread; fn check_conditional_variables_notify_all() { @@ -35,6 +35,53 @@ fn check_conditional_variables_notify_all() { } } +fn check_rwlock_unlock_bug1() { + // There was a bug where when un-read-locking an rwlock that still has other + // readers waiting, we'd accidentally also let a writer in. + // That caused an ICE. + let l = Arc::new(RwLock::new(0)); + + let r1 = l.read().unwrap(); + let r2 = l.read().unwrap(); + + // Make a waiting writer. + let l2 = l.clone(); + thread::spawn(move || { + let mut w = l2.write().unwrap(); + *w += 1; + }); + thread::yield_now(); + + drop(r1); + assert_eq!(*r2, 0); + thread::yield_now(); + thread::yield_now(); + thread::yield_now(); + assert_eq!(*r2, 0); + drop(r2); +} + +fn check_rwlock_unlock_bug2() { + // There was a bug where when un-read-locking an rwlock by letting the last reader leaver, + // we'd forget to wake up a writer. + // That meant the writer thread could never run again. + let l = Arc::new(RwLock::new(0)); + + let r = l.read().unwrap(); + + // Make a waiting writer. + let l2 = l.clone(); + let h = thread::spawn(move || { + let _w = l2.write().unwrap(); + }); + thread::yield_now(); + + drop(r); + h.join().unwrap(); +} + fn main() { check_conditional_variables_notify_all(); + check_rwlock_unlock_bug1(); + check_rwlock_unlock_bug2(); } From 7c025a8f0eac5297c1d8cc3daf31dc27cad0694d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Jun 2022 15:45:45 -0400 Subject: [PATCH 3349/5092] test for forgetting locked mutex --- tests/pass/concurrency/mutex_leak.rs | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/pass/concurrency/mutex_leak.rs diff --git a/tests/pass/concurrency/mutex_leak.rs b/tests/pass/concurrency/mutex_leak.rs new file mode 100644 index 000000000000..7fbc6dd30166 --- /dev/null +++ b/tests/pass/concurrency/mutex_leak.rs @@ -0,0 +1,9 @@ +// compile-flags: -Zmiri-ignore-leaks +use std::mem; +use std::sync::Mutex; + +fn main() { + // Test for https://github.com/rust-lang/rust/issues/85434 + let m = Mutex::new(5i32); + mem::forget(m.lock()); +} From d3ca71ba3765a4b12143c963d4db8712ca969a1e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Jun 2022 19:15:11 -0400 Subject: [PATCH 3350/5092] test that &mut !Unpin references are protected --- .../deallocate_against_barrier2.rs | 16 ++++++++ .../deallocate_against_barrier2.stderr | 38 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 tests/fail/stacked_borrows/deallocate_against_barrier2.rs create mode 100644 tests/fail/stacked_borrows/deallocate_against_barrier2.stderr diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier2.rs b/tests/fail/stacked_borrows/deallocate_against_barrier2.rs new file mode 100644 index 000000000000..4680f6769a1c --- /dev/null +++ b/tests/fail/stacked_borrows/deallocate_against_barrier2.rs @@ -0,0 +1,16 @@ +// error-pattern: deallocating while item is protected +use std::marker::PhantomPinned; + +pub struct NotUnpin(i32, PhantomPinned); + +fn inner(x: &mut NotUnpin, f: fn(&mut NotUnpin)) { + // `f` may mutate, but it may not deallocate! + f(x) +} + +fn main() { + inner(Box::leak(Box::new(NotUnpin(0, PhantomPinned))), |x| { + let raw = x as *mut _; + drop(unsafe { Box::from_raw(raw) }); + }); +} diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr b/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr new file mode 100644 index 000000000000..22776656e019 --- /dev/null +++ b/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr @@ -0,0 +1,38 @@ +error: Undefined Behavior: deallocating while item is protected: [SharedReadWrite for (call ID)] + --> RUSTLIB/alloc/src/alloc.rs:LL:CC + | +LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item is protected: [SharedReadWrite for (call ID)] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information + + = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC + = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC + = note: inside `alloc::alloc::box_free::` at RUSTLIB/alloc/src/alloc.rs:LL:CC + = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC + = note: inside `std::mem::drop::>` at RUSTLIB/core/src/mem/mod.rs:LL:CC +note: inside closure at $DIR/deallocate_against_barrier2.rs:LL:CC + --> $DIR/deallocate_against_barrier2.rs:LL:CC + | +LL | drop(unsafe { Box::from_raw(raw) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `<[closure@$DIR/deallocate_against_barrier2.rs:LL:CC] as std::ops::FnOnce<(&mut NotUnpin,)>>::call_once - shim` at RUSTLIB/core/src/ops/function.rs:LL:CC +note: inside `inner` at $DIR/deallocate_against_barrier2.rs:LL:CC + --> $DIR/deallocate_against_barrier2.rs:LL:CC + | +LL | f(x) + | ^^^^ +note: inside `main` at $DIR/deallocate_against_barrier2.rs:LL:CC + --> $DIR/deallocate_against_barrier2.rs:LL:CC + | +LL | / inner(Box::leak(Box::new(NotUnpin(0, PhantomPinned))), |x| { +LL | | let raw = x as *mut _; +LL | | drop(unsafe { Box::from_raw(raw) }); +LL | | }); + | |______^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + From fed0e1639777cf33caf381ac3bc588ad082398eb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Jun 2022 20:01:36 -0400 Subject: [PATCH 3351/5092] don't assert the same thing twice --- cargo-miri/bin.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 6caa96a4f6f6..4d7b7da6634c 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -952,15 +952,14 @@ fn phase_runner(binary: &Path, binary_args: env::Args, phase: RunnerPhase) { assert!(suffix.starts_with('=')); // Drop this argument. } else if let Some(suffix) = arg.strip_prefix(json_flag) { - assert!(suffix.starts_with('=')); + let suffix = suffix.strip_prefix('=').unwrap(); // This is how we pass through --color=always. We detect that Cargo is detecting rustc // to emit the diagnostic structure that Cargo would consume from rustc to emit colored // diagnostics, and ask rustc to emit them. // See https://github.com/rust-lang/miri/issues/2037 // First skip over the leading `=`, then check for diagnostic-rendered-ansi in the // comma-separated list - if suffix.strip_prefix('=').unwrap().split(',').any(|a| a == "diagnostic-rendered-ansi") - { + if suffix.split(',').any(|a| a == "diagnostic-rendered-ansi") { cmd.arg("--color=always"); } // But aside from remembering that colored output was requested, drop this argument. From 5aeba7f86bb099c079c079e5381a3d976e6f5fdc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Jun 2022 23:30:29 -0400 Subject: [PATCH 3352/5092] make a bunch of tests look more like how they did before rustfmt --- tests/fail/box-cell-alias.rs | 4 +--- tests/fail/box-cell-alias.stderr | 10 +++++----- .../dangling_pointers/maybe_null_pointer_write_zst.rs | 4 +--- .../maybe_null_pointer_write_zst.stderr | 4 ++-- tests/fail/intrinsics/exact_div1.rs | 4 +--- tests/fail/intrinsics/exact_div1.stderr | 4 ++-- tests/fail/intrinsics/exact_div2.rs | 4 +--- tests/fail/intrinsics/exact_div2.stderr | 4 ++-- tests/fail/intrinsics/exact_div3.rs | 4 +--- tests/fail/intrinsics/exact_div3.stderr | 4 ++-- tests/fail/intrinsics/exact_div4.rs | 4 +--- tests/fail/intrinsics/exact_div4.stderr | 4 ++-- tests/fail/stacked_borrows/illegal_write1.rs | 4 +--- tests/fail/stacked_borrows/illegal_write1.stderr | 4 ++-- tests/fail/stacked_borrows/illegal_write2.rs | 4 +--- tests/fail/stacked_borrows/illegal_write2.stderr | 10 +++++----- tests/fail/stacked_borrows/illegal_write3.rs | 4 +--- tests/fail/stacked_borrows/illegal_write3.stderr | 10 +++++----- tests/fail/stacked_borrows/illegal_write6.rs | 4 +--- tests/fail/stacked_borrows/illegal_write6.stderr | 7 +++---- tests/fail/stacked_borrows/raw_tracking.rs | 8 ++------ tests/fail/stacked_borrows/raw_tracking.stderr | 10 +++++----- tests/fail/stacked_borrows/transmute-is-no-escape.rs | 4 +--- .../fail/stacked_borrows/transmute-is-no-escape.stderr | 10 +++++----- .../unaligned_pointers/intptrcast_alignment_check.rs | 4 +--- .../intptrcast_alignment_check.stderr | 4 ++-- tests/fail/validity/transmute_through_ptr.rs | 4 +--- tests/fail/zst2.rs | 4 +--- tests/fail/zst2.stderr | 4 ++-- tests/fail/zst3.rs | 8 ++------ tests/fail/zst3.stderr | 4 ++-- tests/pass/concurrency/data_race.rs | 4 +--- 32 files changed, 65 insertions(+), 104 deletions(-) diff --git a/tests/fail/box-cell-alias.rs b/tests/fail/box-cell-alias.rs index c1fec28ae3b7..d3f505d2da5c 100644 --- a/tests/fail/box-cell-alias.rs +++ b/tests/fail/box-cell-alias.rs @@ -6,9 +6,7 @@ use std::cell::Cell; fn helper(val: Box>, ptr: *const Cell) -> u8 { val.set(10); - unsafe { - (*ptr).set(20); //~ ERROR does not exist in the borrow stack - } + unsafe { (*ptr).set(20) }; //~ ERROR does not exist in the borrow stack val.get() } diff --git a/tests/fail/box-cell-alias.stderr b/tests/fail/box-cell-alias.stderr index e5a3ad3d33af..446aafe64012 100644 --- a/tests/fail/box-cell-alias.stderr +++ b/tests/fail/box-cell-alias.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/box-cell-alias.rs:LL:CC | -LL | (*ptr).set(20); - | ^^^^^^^^^^^^^^ - | | - | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x1] +LL | unsafe { (*ptr).set(20) }; + | ^^^^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x1] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs index 3115da436be8..4a8d498aa1f5 100644 --- a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs +++ b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs @@ -7,7 +7,5 @@ fn main() { // Also not assigning directly as that's array initialization, not assignment. let zst_val = [1u8; 0]; let ptr = (&0u8 as *const u8).wrapping_sub(0x800) as *mut [u8; 0]; - unsafe { - *ptr = zst_val; //~ ERROR out-of-bounds - } + unsafe { *ptr = zst_val }; //~ ERROR out-of-bounds } diff --git a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr index 79fd2ba08685..41e54735ca92 100644 --- a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr +++ b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds --> $DIR/maybe_null_pointer_write_zst.rs:LL:CC | -LL | *ptr = zst_val; - | ^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds +LL | unsafe { *ptr = zst_val }; + | ^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/exact_div1.rs b/tests/fail/intrinsics/exact_div1.rs index d8af789e99a2..f926424a4b67 100644 --- a/tests/fail/intrinsics/exact_div1.rs +++ b/tests/fail/intrinsics/exact_div1.rs @@ -1,7 +1,5 @@ #![feature(core_intrinsics)] fn main() { // divison by 0 - unsafe { - std::intrinsics::exact_div(2, 0); //~ ERROR divisor of zero - } + unsafe { std::intrinsics::exact_div(2, 0) }; //~ ERROR divisor of zero } diff --git a/tests/fail/intrinsics/exact_div1.stderr b/tests/fail/intrinsics/exact_div1.stderr index 66f8168fade7..59e853d0ecec 100644 --- a/tests/fail/intrinsics/exact_div1.stderr +++ b/tests/fail/intrinsics/exact_div1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: calculating the remainder with a divisor of zero --> $DIR/exact_div1.rs:LL:CC | -LL | std::intrinsics::exact_div(2, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calculating the remainder with a divisor of zero +LL | unsafe { std::intrinsics::exact_div(2, 0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calculating the remainder with a divisor of zero | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/exact_div2.rs b/tests/fail/intrinsics/exact_div2.rs index 80f9131bab79..fc252aa79857 100644 --- a/tests/fail/intrinsics/exact_div2.rs +++ b/tests/fail/intrinsics/exact_div2.rs @@ -1,7 +1,5 @@ #![feature(core_intrinsics)] fn main() { // divison with a remainder - unsafe { - std::intrinsics::exact_div(2u16, 3); //~ ERROR 2_u16 cannot be divided by 3_u16 without remainder - } + unsafe { std::intrinsics::exact_div(2u16, 3) }; //~ ERROR 2_u16 cannot be divided by 3_u16 without remainder } diff --git a/tests/fail/intrinsics/exact_div2.stderr b/tests/fail/intrinsics/exact_div2.stderr index 2c102dd0b55c..dfbcdd1f34f1 100644 --- a/tests/fail/intrinsics/exact_div2.stderr +++ b/tests/fail/intrinsics/exact_div2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: exact_div: 2_u16 cannot be divided by 3_u16 without remainder --> $DIR/exact_div2.rs:LL:CC | -LL | std::intrinsics::exact_div(2u16, 3); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: 2_u16 cannot be divided by 3_u16 without remainder +LL | unsafe { std::intrinsics::exact_div(2u16, 3) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: 2_u16 cannot be divided by 3_u16 without remainder | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/exact_div3.rs b/tests/fail/intrinsics/exact_div3.rs index 976fca29f9ba..4d2511adc1f5 100644 --- a/tests/fail/intrinsics/exact_div3.rs +++ b/tests/fail/intrinsics/exact_div3.rs @@ -1,7 +1,5 @@ #![feature(core_intrinsics)] fn main() { // signed divison with a remainder - unsafe { - std::intrinsics::exact_div(-19i8, 2); //~ ERROR -19_i8 cannot be divided by 2_i8 without remainder - } + unsafe { std::intrinsics::exact_div(-19i8, 2) }; //~ ERROR -19_i8 cannot be divided by 2_i8 without remainder } diff --git a/tests/fail/intrinsics/exact_div3.stderr b/tests/fail/intrinsics/exact_div3.stderr index 61eacdc65ff3..c3b908ce0ad5 100644 --- a/tests/fail/intrinsics/exact_div3.stderr +++ b/tests/fail/intrinsics/exact_div3.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: exact_div: -19_i8 cannot be divided by 2_i8 without remainder --> $DIR/exact_div3.rs:LL:CC | -LL | std::intrinsics::exact_div(-19i8, 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: -19_i8 cannot be divided by 2_i8 without remainder +LL | unsafe { std::intrinsics::exact_div(-19i8, 2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: -19_i8 cannot be divided by 2_i8 without remainder | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/exact_div4.rs b/tests/fail/intrinsics/exact_div4.rs index 5f4ca587e6d7..df6433d1cb22 100644 --- a/tests/fail/intrinsics/exact_div4.rs +++ b/tests/fail/intrinsics/exact_div4.rs @@ -1,7 +1,5 @@ #![feature(core_intrinsics)] fn main() { // divison of MIN by -1 - unsafe { - std::intrinsics::exact_div(i64::MIN, -1); //~ ERROR overflow in signed remainder (dividing MIN by -1) - } + unsafe { std::intrinsics::exact_div(i64::MIN, -1) }; //~ ERROR overflow in signed remainder (dividing MIN by -1) } diff --git a/tests/fail/intrinsics/exact_div4.stderr b/tests/fail/intrinsics/exact_div4.stderr index a3f5aafbe2d6..b82950674fbc 100644 --- a/tests/fail/intrinsics/exact_div4.stderr +++ b/tests/fail/intrinsics/exact_div4.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow in signed remainder (dividing MIN by -1) --> $DIR/exact_div4.rs:LL:CC | -LL | std::intrinsics::exact_div(i64::MIN, -1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) +LL | unsafe { std::intrinsics::exact_div(i64::MIN, -1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/stacked_borrows/illegal_write1.rs b/tests/fail/stacked_borrows/illegal_write1.rs index 3b67accbbd2e..1f566f18c1f8 100644 --- a/tests/fail/stacked_borrows/illegal_write1.rs +++ b/tests/fail/stacked_borrows/illegal_write1.rs @@ -3,9 +3,7 @@ fn main() { let xref = &*target; { let x: *mut u32 = xref as *const _ as *mut _; - unsafe { - *x = 42; // invalidates shared ref, activates raw - } + unsafe { *x = 42 }; // invalidates shared ref, activates raw } let _x = *xref; //~ ERROR borrow stack } diff --git a/tests/fail/stacked_borrows/illegal_write1.stderr b/tests/fail/stacked_borrows/illegal_write1.stderr index a70a45f2235a..1731e3c1de13 100644 --- a/tests/fail/stacked_borrows/illegal_write1.stderr +++ b/tests/fail/stacked_borrows/illegal_write1.stderr @@ -17,8 +17,8 @@ LL | let xref = &*target; help: was later invalidated at offsets [0x0..0x4] --> $DIR/illegal_write1.rs:LL:CC | -LL | *x = 42; // invalidates shared ref, activates raw - | ^^^^^^^ +LL | unsafe { *x = 42 }; // invalidates shared ref, activates raw + | ^^^^^^^ = note: inside `main` at $DIR/illegal_write1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write2.rs b/tests/fail/stacked_borrows/illegal_write2.rs index a106b4240c3c..32dc474385d6 100644 --- a/tests/fail/stacked_borrows/illegal_write2.rs +++ b/tests/fail/stacked_borrows/illegal_write2.rs @@ -3,8 +3,6 @@ fn main() { let target2 = target as *mut _; drop(&mut *target); // reborrow // Now make sure our ref is still the only one. - unsafe { - *target2 = 13; //~ ERROR borrow stack - } + unsafe { *target2 = 13 }; //~ ERROR borrow stack let _val = *target; } diff --git a/tests/fail/stacked_borrows/illegal_write2.stderr b/tests/fail/stacked_borrows/illegal_write2.stderr index d2a06cc386a1..7e896c530ac7 100644 --- a/tests/fail/stacked_borrows/illegal_write2.stderr +++ b/tests/fail/stacked_borrows/illegal_write2.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/illegal_write2.rs:LL:CC | -LL | *target2 = 13; - | ^^^^^^^^^^^^^ - | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | unsafe { *target2 = 13 }; + | ^^^^^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/illegal_write3.rs b/tests/fail/stacked_borrows/illegal_write3.rs index 5bf651b33aa0..87fdbae70192 100644 --- a/tests/fail/stacked_borrows/illegal_write3.rs +++ b/tests/fail/stacked_borrows/illegal_write3.rs @@ -3,8 +3,6 @@ fn main() { // Make sure raw ptr with raw tag cannot mutate frozen location without breaking the shared ref. let r#ref = ⌖ // freeze let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag - unsafe { - *ptr = 42; //~ ERROR only grants SharedReadOnly permission - } + unsafe { *ptr = 42 }; //~ ERROR only grants SharedReadOnly permission let _val = *r#ref; } diff --git a/tests/fail/stacked_borrows/illegal_write3.stderr b/tests/fail/stacked_borrows/illegal_write3.stderr index fc87557ea9b4..7e9c82769d6a 100644 --- a/tests/fail/stacked_borrows/illegal_write3.stderr +++ b/tests/fail/stacked_borrows/illegal_write3.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location --> $DIR/illegal_write3.rs:LL:CC | -LL | *ptr = 42; - | ^^^^^^^^^ - | | - | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | unsafe { *ptr = 42 }; + | ^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/illegal_write6.rs b/tests/fail/stacked_borrows/illegal_write6.rs index 07d57241205f..c50b7c5816f6 100644 --- a/tests/fail/stacked_borrows/illegal_write6.rs +++ b/tests/fail/stacked_borrows/illegal_write6.rs @@ -7,8 +7,6 @@ fn main() { fn foo(a: &mut u32, y: *mut u32) -> u32 { *a = 1; let _b = &*a; - unsafe { - *y = 2; //~ ERROR: not granting access to tag - } + unsafe { *y = 2 }; //~ ERROR: not granting access to tag return *a; } diff --git a/tests/fail/stacked_borrows/illegal_write6.stderr b/tests/fail/stacked_borrows/illegal_write6.stderr index 3a7fc0ef8116..11757cca9b65 100644 --- a/tests/fail/stacked_borrows/illegal_write6.stderr +++ b/tests/fail/stacked_borrows/illegal_write6.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] --> $DIR/illegal_write6.rs:LL:CC | -LL | *y = 2; - | ^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] +LL | unsafe { *y = 2 }; + | ^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -22,8 +22,7 @@ help: this protector is live for this call LL | / fn foo(a: &mut u32, y: *mut u32) -> u32 { LL | | *a = 1; LL | | let _b = &*a; -LL | | unsafe { -... | +LL | | unsafe { *y = 2 }; LL | | return *a; LL | | } | |_^ diff --git a/tests/fail/stacked_borrows/raw_tracking.rs b/tests/fail/stacked_borrows/raw_tracking.rs index 0a99e4ce47e7..0b9c058f06ef 100644 --- a/tests/fail/stacked_borrows/raw_tracking.rs +++ b/tests/fail/stacked_borrows/raw_tracking.rs @@ -7,10 +7,6 @@ fn main() { let raw2 = &mut l as *mut _; // invalidates raw1 // Without raw pointer tracking, Stacked Borrows cannot distinguish raw1 and raw2, and thus // fails to realize that raw1 should not be used any more. - unsafe { - *raw1 = 13; //~ ERROR does not exist in the borrow stack - } - unsafe { - *raw2 = 13; - } + unsafe { *raw1 = 13 }; //~ ERROR does not exist in the borrow stack + unsafe { *raw2 = 13 }; } diff --git a/tests/fail/stacked_borrows/raw_tracking.stderr b/tests/fail/stacked_borrows/raw_tracking.stderr index 60a277ee057e..d3674893fab8 100644 --- a/tests/fail/stacked_borrows/raw_tracking.stderr +++ b/tests/fail/stacked_borrows/raw_tracking.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/raw_tracking.rs:LL:CC | -LL | *raw1 = 13; - | ^^^^^^^^^^ - | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | unsafe { *raw1 = 13 }; + | ^^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/transmute-is-no-escape.rs b/tests/fail/stacked_borrows/transmute-is-no-escape.rs index e23c893d6aaa..45035683d5c0 100644 --- a/tests/fail/stacked_borrows/transmute-is-no-escape.rs +++ b/tests/fail/stacked_borrows/transmute-is-no-escape.rs @@ -10,7 +10,5 @@ fn main() { let _raw: *mut i32 = unsafe { mem::transmute(&mut x[0]) }; // `raw` still carries a tag, so we get another pointer to the same location that does not carry a tag let raw = (&mut x[1] as *mut i32).wrapping_offset(-1); - unsafe { - *raw = 13; //~ ERROR borrow stack - } + unsafe { *raw = 13 }; //~ ERROR borrow stack } diff --git a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr index c077e37844d1..a9682f806ba2 100644 --- a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr +++ b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/transmute-is-no-escape.rs:LL:CC | -LL | *raw = 13; - | ^^^^^^^^^ - | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | unsafe { *raw = 13 }; + | ^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs b/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs index e96f08fc9a7a..0a326a453e9a 100644 --- a/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs +++ b/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs @@ -12,8 +12,6 @@ fn main() { // Manually make sure the pointer is properly aligned. let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr + 1 }; let u16_ptr = base_addr_aligned as *mut u16; - unsafe { - *u16_ptr = 2; //~ERROR memory with alignment 1, but alignment 2 is required - } + unsafe { *u16_ptr = 2 }; //~ERROR memory with alignment 1, but alignment 2 is required println!("{:?}", x); } diff --git a/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr b/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr index fe63b05a5501..347486187e1b 100644 --- a/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr +++ b/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required --> $DIR/intptrcast_alignment_check.rs:LL:CC | -LL | *u16_ptr = 2; - | ^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required +LL | unsafe { *u16_ptr = 2 }; + | ^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required | = help: this usually indicates that your program performed an invalid operation and caused Undefined Behavior = help: but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives diff --git a/tests/fail/validity/transmute_through_ptr.rs b/tests/fail/validity/transmute_through_ptr.rs index 4af3b8aef6aa..049c57e61939 100644 --- a/tests/fail/validity/transmute_through_ptr.rs +++ b/tests/fail/validity/transmute_through_ptr.rs @@ -6,9 +6,7 @@ enum Bool { fn evil(x: &mut Bool) { let x = x as *mut _ as *mut u32; - unsafe { - *x = 44; // out-of-bounds enum tag - } + unsafe { *x = 44 }; // out-of-bounds enum tag } #[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/5391 diff --git a/tests/fail/zst2.rs b/tests/fail/zst2.rs index 2499f79142db..9f92e8994d26 100644 --- a/tests/fail/zst2.rs +++ b/tests/fail/zst2.rs @@ -11,7 +11,5 @@ fn main() { let mut x_box = Box::new(1u8); let x = &mut *x_box as *mut _ as *mut [u8; 0]; drop(x_box); - unsafe { - *x = zst_val; //~ ERROR dereferenced after this allocation got freed - } + unsafe { *x = zst_val }; //~ ERROR dereferenced after this allocation got freed } diff --git a/tests/fail/zst2.stderr b/tests/fail/zst2.stderr index 0df2098d2e19..3112a87489a9 100644 --- a/tests/fail/zst2.stderr +++ b/tests/fail/zst2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed --> $DIR/zst2.rs:LL:CC | -LL | *x = zst_val; - | ^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed +LL | unsafe { *x = zst_val }; + | ^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/zst3.rs b/tests/fail/zst3.rs index 741374c7ad98..3f3b0af14dbe 100644 --- a/tests/fail/zst3.rs +++ b/tests/fail/zst3.rs @@ -11,12 +11,8 @@ fn main() { let mut x_box = Box::new(1u8); let x = (&mut *x_box as *mut u8).wrapping_offset(1); // This one is just "at the edge", but still okay - unsafe { - *(x as *mut [u8; 0]) = zst_val; - } + unsafe { *(x as *mut [u8; 0]) = zst_val }; // One byte further is OOB. let x = x.wrapping_offset(1); - unsafe { - *(x as *mut [u8; 0]) = zst_val; //~ ERROR out-of-bounds - } + unsafe { *(x as *mut [u8; 0]) = zst_val }; //~ ERROR out-of-bounds } diff --git a/tests/fail/zst3.stderr b/tests/fail/zst3.stderr index dce0d7b3891c..bc3436b14ac0 100644 --- a/tests/fail/zst3.stderr +++ b/tests/fail/zst3.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 1, so pointer at offset 2 is out-of-bounds --> $DIR/zst3.rs:LL:CC | -LL | *(x as *mut [u8; 0]) = zst_val; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 1, so pointer at offset 2 is out-of-bounds +LL | unsafe { *(x as *mut [u8; 0]) = zst_val }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 1, so pointer at offset 2 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/pass/concurrency/data_race.rs b/tests/pass/concurrency/data_race.rs index 071f5bbcdf39..812003ef4d97 100644 --- a/tests/pass/concurrency/data_race.rs +++ b/tests/pass/concurrency/data_race.rs @@ -18,9 +18,7 @@ fn test_fence_sync() { let evil_ptr = EvilSend(ptr); let j1 = spawn(move || { - unsafe { - *evil_ptr.0 = 1; - } + unsafe { *evil_ptr.0 = 1 }; fence(Ordering::Release); SYNC.store(1, Ordering::Relaxed) }); From e667ccb4594b5415626f18dbe34c1713b59e3941 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Jun 2022 23:22:42 -0400 Subject: [PATCH 3353/5092] test that futexes induce appropriate synchronization --- tests/pass/concurrency/linux-futex.rs | 32 +++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/tests/pass/concurrency/linux-futex.rs b/tests/pass/concurrency/linux-futex.rs index 2c60df1ee138..b65dd46d5974 100644 --- a/tests/pass/concurrency/linux-futex.rs +++ b/tests/pass/concurrency/linux-futex.rs @@ -222,11 +222,17 @@ fn wait_wake_bitset() { t.join().unwrap(); } -const FREE: i32 = 0; -const HELD: i32 = 1; fn concurrent_wait_wake() { + const FREE: i32 = 0; + const HELD: i32 = 1; + static FUTEX: AtomicI32 = AtomicI32::new(0); - for _ in 0..20 { + static mut DATA: i32 = 0; + static WOKEN: AtomicI32 = AtomicI32::new(0); + + let rounds = 50; + for _ in 0..rounds { + unsafe { DATA = 0 }; // Reset // Suppose the main thread is holding a lock implemented using futex... FUTEX.store(HELD, Ordering::Relaxed); @@ -239,23 +245,41 @@ fn concurrent_wait_wake() { // the FUTEX is FREE != HELD and return without waiting // or we'll deadlock. unsafe { - libc::syscall( + let ret = libc::syscall( libc::SYS_futex, &FUTEX as *const AtomicI32, libc::FUTEX_WAIT, HELD, ptr::null::(), ); + if ret == 0 { + // We actually slept. And then woke up again. So we should be ordered-after + // what happened-before the FUTEX_WAKE. So this is not a race. + assert_eq!(DATA, 1); + // Also remember that this happened at least once. + WOKEN.fetch_add(1, Ordering::Relaxed); + } } }); + // Increase the chance that the other thread actually goes to sleep. + // (5 yields in a loop seem to make that happen around 40% of the time.) + for _ in 0..5 { + thread::yield_now(); + } FUTEX.store(FREE, Ordering::Relaxed); unsafe { + DATA = 1; libc::syscall(libc::SYS_futex, &FUTEX as *const AtomicI32, libc::FUTEX_WAKE, 1); } t.join().unwrap(); } + + // Make sure we got the interesting case (of having woken a thread) at least once, but not *each* time. + let woken = WOKEN.load(Ordering::Relaxed); + assert!(woken > 0 && woken < rounds); + //eprintln!("waking happened {woken} times"); } fn main() { From 34be937d5f67d789969b1b731967fa26cc490a9c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jun 2022 12:31:53 -0400 Subject: [PATCH 3354/5092] add -Zmiri-report-progress to regularly print a stacktrace of what we are executing --- README.md | 4 ++++ src/bin/miri.rs | 9 +++++++++ src/diagnostics.rs | 3 +++ src/eval.rs | 3 +++ src/machine.rs | 17 +++++++++++++++++ test-cargo-miri/build.rs | 2 +- 6 files changed, 37 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7f373f078a09..117794b77ee6 100644 --- a/README.md +++ b/README.md @@ -292,6 +292,10 @@ environment variable. We first document the most relevant and most commonly used * `-Zmiri-preemption-rate` configures the probability that at the end of a basic block, the active thread will be preempted. The default is `0.01` (i.e., 1%). Setting this to `0` disables preemption. +* `-Zmiri-report-progress` makes Miri print the current stacktrace every now and then, so you can + tell what it is doing when a program just keeps running. You can customize how frequently the + report is printed via `-Zmiri-report-progress=`, which prints the report every N basic + blocks. * `-Zmiri-seed=` configures the seed of the RNG that Miri uses to resolve non-determinism. This RNG is used to pick base addresses for allocations, to determine preemption and failure of `compare_exchange_weak`, and to control store buffering for weak memory emulation. When isolation diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 7dc642365c50..91148400c99b 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -468,6 +468,15 @@ fn main() { ), }; miri_config.preemption_rate = rate; + } else if arg == "-Zmiri-report-progress" { + // This makes it take a few seconds between progress reports on my laptop. + miri_config.report_progress = Some(1_000_000); + } else if let Some(param) = arg.strip_prefix("-Zmiri-report-progress=") { + let interval = match param.parse::() { + Ok(i) => i, + Err(err) => panic!("-Zmiri-report-progress requires a `u32`: {}", err), + }; + miri_config.report_progress = Some(interval); } else if let Some(param) = arg.strip_prefix("-Zmiri-measureme=") { miri_config.measureme_out = Some(param.to_string()); } else if let Some(param) = arg.strip_prefix("-Zmiri-backtrace=") { diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 230f46c569db..6986d9c57271 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -68,6 +68,7 @@ pub enum NonHaltingDiagnostic { CreatedAlloc(AllocId), FreedAlloc(AllocId), RejectedIsolatedOp(String), + ProgressReport, } /// Level of Miri specific diagnostics @@ -465,6 +466,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx FreedAlloc(AllocId(id)) => format!("freed allocation with id {id}"), RejectedIsolatedOp(ref op) => format!("{op} was made to return an error due to isolation"), + ProgressReport => + format!("progress report: current operation being executed is here"), }; let (title, diag_level) = match e { diff --git a/src/eval.rs b/src/eval.rs index db843b851e58..7beb2ec9c4ad 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -124,6 +124,8 @@ pub struct MiriConfig { pub mute_stdout_stderr: bool, /// The probability of the active thread being preempted at the end of each basic block. pub preemption_rate: f64, + /// Report the current instruction being executed every N basic blocks. + pub report_progress: Option, } impl Default for MiriConfig { @@ -154,6 +156,7 @@ impl Default for MiriConfig { provenance_mode: ProvenanceMode::Legacy, mute_stdout_stderr: false, preemption_rate: 0.01, // 1% + report_progress: None, } } } diff --git a/src/machine.rs b/src/machine.rs index 79414ada5eac..3621744e8025 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -333,6 +333,11 @@ pub struct Evaluator<'mir, 'tcx> { /// The probability of the active thread being preempted at the end of each basic block. pub(crate) preemption_rate: f64, + + /// If `Some`, we will report the current stack every N basic blocks. + pub(crate) report_progress: Option, + /// The number of blocks that passed since the last progress report. + pub(crate) since_progress_report: u32, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { @@ -390,6 +395,8 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { mute_stdout_stderr: config.mute_stdout_stderr, weak_memory: config.weak_memory_emulation, preemption_rate: config.preemption_rate, + report_progress: config.report_progress, + since_progress_report: 0, } } @@ -862,6 +869,16 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { + // Possibly report our progress. + if let Some(report_progress) = ecx.machine.report_progress { + if ecx.machine.since_progress_report >= report_progress { + register_diagnostic(NonHaltingDiagnostic::ProgressReport); + ecx.machine.since_progress_report = 0; + } + // Cannot overflow, since it is strictly less than `report_progress`. + ecx.machine.since_progress_report += 1; + } + // These are our preemption points. ecx.maybe_preempt_active_thread(); Ok(()) } diff --git a/test-cargo-miri/build.rs b/test-cargo-miri/build.rs index 72a4ee0de30b..8b1e3af6231a 100644 --- a/test-cargo-miri/build.rs +++ b/test-cargo-miri/build.rs @@ -16,7 +16,7 @@ fn main() { not_in_miri(); // Cargo calls `miri --print=cfg` to populate the `CARGO_CFG_*` env vars. // Make sure that the "miri" flag is set. - assert!(env::var_os("CARGO_CFG_MIRI").is_some()); + assert!(env::var_os("CARGO_CFG_MIRI").is_some(), "cargo failed to tell us about `--cfg miri`"); println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-env-changed=MIRITESTVAR"); println!("cargo:rustc-env=MIRITESTVAR=testval"); From 60570a39c7b0e3a8ed55e934eb7a18792f436bbe Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jun 2022 18:59:48 -0400 Subject: [PATCH 3355/5092] trophy case: add the data race in thread::scope --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 117794b77ee6..50586c9eceaf 100644 --- a/README.md +++ b/README.md @@ -586,6 +586,7 @@ Definite bugs found: * [`crossbeam-epoch` calling `assume_init` on a partly-initialized `MaybeUninit`](https://github.com/crossbeam-rs/crossbeam/pull/779) * [`integer-encoding` dereferencing a misaligned pointer](https://github.com/dermesser/integer-encoding-rs/pull/23) * [`rkyv` constructing a `Box<[u8]>` from an overaligned allocation](https://github.com/rkyv/rkyv/commit/a9417193a34757e12e24263178be8b2eebb72456) +* [Data race in `thread::scope`](https://github.com/rust-lang/rust/issues/98498) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From 9130034337b30e975beb2c265e309187c574561e Mon Sep 17 00:00:00 2001 From: infrandomness Date: Thu, 9 Jun 2022 16:06:07 +0200 Subject: [PATCH 3356/5092] Initial freebsd work --- ci.sh | 1 + src/helpers.rs | 2 +- src/shims/unix/dlsym.rs | 4 +++ src/shims/unix/foreign_items.rs | 1 + src/shims/unix/freebsd/dlsym.rs | 35 +++++++++++++++++++++++++ src/shims/unix/freebsd/foreign_items.rs | 23 ++++++++++++++++ src/shims/unix/freebsd/mod.rs | 2 ++ src/shims/unix/macos/dlsym.rs | 7 ++--- src/shims/unix/mod.rs | 1 + tests/pass/libc.rs | 20 +++++++------- 10 files changed, 80 insertions(+), 16 deletions(-) create mode 100644 src/shims/unix/freebsd/dlsym.rs create mode 100644 src/shims/unix/freebsd/foreign_items.rs create mode 100644 src/shims/unix/freebsd/mod.rs diff --git a/ci.sh b/ci.sh index 01b86ff2f96b..f436e0179ab6 100755 --- a/ci.sh +++ b/ci.sh @@ -50,6 +50,7 @@ case $HOST_TARGET in MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests + MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests ;; x86_64-apple-darwin) MIRI_TEST_TARGET=mips64-unknown-linux-gnuabi64 run_tests # big-endian architecture diff --git a/src/helpers.rs b/src/helpers.rs index 134f556bf120..86823f281788 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -910,5 +910,5 @@ impl std::fmt::Display for HexRange { /// Helper function used inside the shims of foreign functions to check that /// `target_os` is a supported UNIX OS. pub fn target_os_is_unix(target_os: &str) -> bool { - matches!(target_os, "linux" | "macos") + matches!(target_os, "linux" | "macos" | "freebsd") } diff --git a/src/shims/unix/dlsym.rs b/src/shims/unix/dlsym.rs index 578ae488a98e..f183971b59aa 100644 --- a/src/shims/unix/dlsym.rs +++ b/src/shims/unix/dlsym.rs @@ -4,11 +4,13 @@ use rustc_target::spec::abi::Abi; use crate::*; use shims::unix::linux::dlsym as linux; use shims::unix::macos::dlsym as macos; +use shims::unix::freebsd::dlsym as freebsd; #[derive(Debug, Copy, Clone)] pub enum Dlsym { Linux(linux::Dlsym), MacOs(macos::Dlsym), + FreeBSD(freebsd::Dlsym) } impl Dlsym { @@ -18,6 +20,7 @@ impl Dlsym { Ok(match target_os { "linux" => linux::Dlsym::from_str(name)?.map(Dlsym::Linux), "macos" => macos::Dlsym::from_str(name)?.map(Dlsym::MacOs), + "freebsd" => freebsd::Dlsym::from_str(name)?.map(Dlsym::FreeBSD), _ => unreachable!(), }) } @@ -40,6 +43,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match dlsym { Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), + Dlsym::FreeBSD(dlsym) => freebsd::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret) } } } diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index d002ab75b9be..d789b0c64047 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -485,6 +485,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match this.tcx.sess.target.os.as_ref() { "linux" => return shims::unix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), "macos" => return shims::unix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), + "freebsd" => return shims::unix::freebsd::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), _ => unreachable!(), } } diff --git a/src/shims/unix/freebsd/dlsym.rs b/src/shims/unix/freebsd/dlsym.rs new file mode 100644 index 000000000000..57125c14fa0c --- /dev/null +++ b/src/shims/unix/freebsd/dlsym.rs @@ -0,0 +1,35 @@ +use rustc_middle::mir; + +use crate::*; +use helpers::check_arg_count; + +#[derive(Debug, Copy, Clone)] +#[allow(non_camel_case_types)] +pub enum Dlsym { + getentropy, +} + +impl Dlsym { + // Returns an error for unsupported symbols, and None if this symbol + // should become a NULL pointer (pretend it does not exist). + pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { + throw_unsup_format!("unsupported FreeBSD dlsym: {}", name) + } +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn call_dlsym( + &mut self, + dlsym: Dlsym, + _args: &[OpTy<'tcx, Tag>], + _dest: &PlaceTy<'tcx, Tag>, + ret: Option, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let _ret = ret.expect("we don't support any diverging dlsym"); + assert!(this.tcx.sess.target.os == "freebsd"); + + match dlsym {} + } +} diff --git a/src/shims/unix/freebsd/foreign_items.rs b/src/shims/unix/freebsd/foreign_items.rs new file mode 100644 index 000000000000..ac261cecc2e0 --- /dev/null +++ b/src/shims/unix/freebsd/foreign_items.rs @@ -0,0 +1,23 @@ +use rustc_middle::mir; +use rustc_span::Symbol; +use rustc_target::spec::abi::Abi; + +use crate::*; +use shims::foreign_items::EmulateByNameResult; + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} + +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn emulate_foreign_item_by_name( + &mut self, + link_name: Symbol, + abi: Abi, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + _ret: mir::BasicBlock, + ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { + let this = self.eval_context_mut(); + // match + Ok(EmulateByNameResult::NeedsJumping) + } +} \ No newline at end of file diff --git a/src/shims/unix/freebsd/mod.rs b/src/shims/unix/freebsd/mod.rs new file mode 100644 index 000000000000..428d997d787c --- /dev/null +++ b/src/shims/unix/freebsd/mod.rs @@ -0,0 +1,2 @@ +pub mod foreign_items; +pub mod dlsym; \ No newline at end of file diff --git a/src/shims/unix/macos/dlsym.rs b/src/shims/unix/macos/dlsym.rs index 2e97b7918e96..ee0ff01c05ed 100644 --- a/src/shims/unix/macos/dlsym.rs +++ b/src/shims/unix/macos/dlsym.rs @@ -3,12 +3,10 @@ use rustc_middle::mir; use log::trace; use crate::*; -use helpers::check_arg_count; #[derive(Debug, Copy, Clone)] #[allow(non_camel_case_types)] pub enum Dlsym { - getentropy, } impl Dlsym { @@ -16,8 +14,7 @@ impl Dlsym { // should become a NULL pointer (pretend it does not exist). pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { Ok(match name { - "getentropy" => Some(Dlsym::getentropy), - _ => throw_unsup_format!("unsupported macOS dlsym: {}", name), + _ => throw_unsup_format!("unsupported freebsd dlsym: {}", name), }) } } @@ -33,7 +30,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let ret = ret.expect("we don't support any diverging dlsym"); - assert!(this.tcx.sess.target.os == "macos"); + assert!(this.tcx.sess.target.os == "freebsd"); match dlsym { Dlsym::getentropy => { diff --git a/src/shims/unix/mod.rs b/src/shims/unix/mod.rs index f40dfaefb92a..4002b056b4b2 100644 --- a/src/shims/unix/mod.rs +++ b/src/shims/unix/mod.rs @@ -7,5 +7,6 @@ mod thread; mod linux; mod macos; +mod freebsd; pub use fs::{DirHandler, FileHandler}; diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index f97b9dd2b9ea..0b6bc6439534 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -5,14 +5,14 @@ extern crate libc; -#[cfg(target_os = "linux")] +#[cfg(target_os = "linux, freebsd")] fn tmp() -> std::path::PathBuf { std::env::var("MIRI_TEMP") .map(std::path::PathBuf::from) .unwrap_or_else(|_| std::env::temp_dir()) } -#[cfg(target_os = "linux")] +#[cfg(target_os = "linux, freebsd")] fn test_posix_fadvise() { use std::convert::TryInto; use std::fs::{remove_file, File}; @@ -42,7 +42,7 @@ fn test_posix_fadvise() { assert_eq!(result, 0); } -#[cfg(target_os = "linux")] +#[cfg(target_os = "linux, freebsd")] fn test_sync_file_range() { use std::fs::{remove_file, File}; use std::io::Write; @@ -208,7 +208,7 @@ fn test_rwlock_libc_static_initializer() { /// Test whether the `prctl` shim correctly sets the thread name. /// /// Note: `prctl` exists only on Linux. -#[cfg(target_os = "linux")] +#[cfg(target_os = "linux,freebsd")] fn test_prctl_thread_name() { use libc::c_long; use std::ffi::CString; @@ -277,7 +277,7 @@ fn test_thread_local_errno() { } /// Tests whether clock support exists at all -#[cfg(target_os = "linux")] +#[cfg(target_os = "linux,freebsd")] fn test_clocks() { let mut tp = std::mem::MaybeUninit::::uninit(); let is_error = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, tp.as_mut_ptr()) }; @@ -291,10 +291,10 @@ fn test_clocks() { } fn main() { - #[cfg(target_os = "linux")] + #[cfg(target_os = "linux,freebsd")] test_posix_fadvise(); - #[cfg(target_os = "linux")] + #[cfg(target_os = "linux,freebsd")] test_sync_file_range(); test_mutex_libc_init_recursive(); @@ -302,14 +302,14 @@ fn main() { test_mutex_libc_init_errorcheck(); test_rwlock_libc_static_initializer(); - #[cfg(target_os = "linux")] + #[cfg(target_os = "linux,freebsd")] test_mutex_libc_static_initializer_recursive(); - #[cfg(target_os = "linux")] + #[cfg(target_os = "linux,freebsd")] test_prctl_thread_name(); test_thread_local_errno(); - #[cfg(target_os = "linux")] + #[cfg(target_os = "linux,freebsd")] test_clocks(); } From 97a512070aa6d648ddde025a7cc9784fad7624f9 Mon Sep 17 00:00:00 2001 From: infrandomness Date: Thu, 9 Jun 2022 16:50:34 +0200 Subject: [PATCH 3357/5092] Fix pending reviews --- src/shims/unix/dlsym.rs | 7 ++++--- src/shims/unix/freebsd/dlsym.rs | 5 +---- src/shims/unix/freebsd/foreign_items.rs | 2 +- src/shims/unix/freebsd/mod.rs | 2 +- src/shims/unix/macos/dlsym.rs | 7 +++++-- src/shims/unix/mod.rs | 2 +- tests/pass/libc.rs | 20 ++++++++++---------- 7 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/shims/unix/dlsym.rs b/src/shims/unix/dlsym.rs index f183971b59aa..e1f819fb8567 100644 --- a/src/shims/unix/dlsym.rs +++ b/src/shims/unix/dlsym.rs @@ -2,15 +2,15 @@ use rustc_middle::mir; use rustc_target::spec::abi::Abi; use crate::*; +use shims::unix::freebsd::dlsym as freebsd; use shims::unix::linux::dlsym as linux; use shims::unix::macos::dlsym as macos; -use shims::unix::freebsd::dlsym as freebsd; #[derive(Debug, Copy, Clone)] pub enum Dlsym { Linux(linux::Dlsym), MacOs(macos::Dlsym), - FreeBSD(freebsd::Dlsym) + FreeBSD(freebsd::Dlsym), } impl Dlsym { @@ -43,7 +43,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match dlsym { Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), - Dlsym::FreeBSD(dlsym) => freebsd::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret) + Dlsym::FreeBSD(dlsym) => + freebsd::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), } } } diff --git a/src/shims/unix/freebsd/dlsym.rs b/src/shims/unix/freebsd/dlsym.rs index 57125c14fa0c..18347d274e93 100644 --- a/src/shims/unix/freebsd/dlsym.rs +++ b/src/shims/unix/freebsd/dlsym.rs @@ -1,13 +1,10 @@ use rustc_middle::mir; use crate::*; -use helpers::check_arg_count; #[derive(Debug, Copy, Clone)] #[allow(non_camel_case_types)] -pub enum Dlsym { - getentropy, -} +pub enum Dlsym {} impl Dlsym { // Returns an error for unsupported symbols, and None if this symbol diff --git a/src/shims/unix/freebsd/foreign_items.rs b/src/shims/unix/freebsd/foreign_items.rs index ac261cecc2e0..712725238867 100644 --- a/src/shims/unix/freebsd/foreign_items.rs +++ b/src/shims/unix/freebsd/foreign_items.rs @@ -20,4 +20,4 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // match Ok(EmulateByNameResult::NeedsJumping) } -} \ No newline at end of file +} diff --git a/src/shims/unix/freebsd/mod.rs b/src/shims/unix/freebsd/mod.rs index 428d997d787c..434f5f30b5a5 100644 --- a/src/shims/unix/freebsd/mod.rs +++ b/src/shims/unix/freebsd/mod.rs @@ -1,2 +1,2 @@ +pub mod dlsym; pub mod foreign_items; -pub mod dlsym; \ No newline at end of file diff --git a/src/shims/unix/macos/dlsym.rs b/src/shims/unix/macos/dlsym.rs index ee0ff01c05ed..2e97b7918e96 100644 --- a/src/shims/unix/macos/dlsym.rs +++ b/src/shims/unix/macos/dlsym.rs @@ -3,10 +3,12 @@ use rustc_middle::mir; use log::trace; use crate::*; +use helpers::check_arg_count; #[derive(Debug, Copy, Clone)] #[allow(non_camel_case_types)] pub enum Dlsym { + getentropy, } impl Dlsym { @@ -14,7 +16,8 @@ impl Dlsym { // should become a NULL pointer (pretend it does not exist). pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { Ok(match name { - _ => throw_unsup_format!("unsupported freebsd dlsym: {}", name), + "getentropy" => Some(Dlsym::getentropy), + _ => throw_unsup_format!("unsupported macOS dlsym: {}", name), }) } } @@ -30,7 +33,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let ret = ret.expect("we don't support any diverging dlsym"); - assert!(this.tcx.sess.target.os == "freebsd"); + assert!(this.tcx.sess.target.os == "macos"); match dlsym { Dlsym::getentropy => { diff --git a/src/shims/unix/mod.rs b/src/shims/unix/mod.rs index 4002b056b4b2..8e8c70bbd0fa 100644 --- a/src/shims/unix/mod.rs +++ b/src/shims/unix/mod.rs @@ -5,8 +5,8 @@ mod fs; mod sync; mod thread; +mod freebsd; mod linux; mod macos; -mod freebsd; pub use fs::{DirHandler, FileHandler}; diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index 0b6bc6439534..e73e796449cc 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -5,14 +5,14 @@ extern crate libc; -#[cfg(target_os = "linux, freebsd")] +#[cfg(any(target_os = "linux", target_os = "freebsd"))] fn tmp() -> std::path::PathBuf { std::env::var("MIRI_TEMP") .map(std::path::PathBuf::from) .unwrap_or_else(|_| std::env::temp_dir()) } -#[cfg(target_os = "linux, freebsd")] +#[cfg(any(target_os = "linux", target_os = "freebsd"))] fn test_posix_fadvise() { use std::convert::TryInto; use std::fs::{remove_file, File}; @@ -42,7 +42,7 @@ fn test_posix_fadvise() { assert_eq!(result, 0); } -#[cfg(target_os = "linux, freebsd")] +#[cfg(any(target_os = "linux", target_os = "freebsd"))] fn test_sync_file_range() { use std::fs::{remove_file, File}; use std::io::Write; @@ -208,7 +208,7 @@ fn test_rwlock_libc_static_initializer() { /// Test whether the `prctl` shim correctly sets the thread name. /// /// Note: `prctl` exists only on Linux. -#[cfg(target_os = "linux,freebsd")] +#[cfg(any(target_os = "linux", target_os = "freebsd"))] fn test_prctl_thread_name() { use libc::c_long; use std::ffi::CString; @@ -277,7 +277,7 @@ fn test_thread_local_errno() { } /// Tests whether clock support exists at all -#[cfg(target_os = "linux,freebsd")] +#[cfg(any(target_os = "linux", target_os = "freebsd"))] fn test_clocks() { let mut tp = std::mem::MaybeUninit::::uninit(); let is_error = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, tp.as_mut_ptr()) }; @@ -291,10 +291,10 @@ fn test_clocks() { } fn main() { - #[cfg(target_os = "linux,freebsd")] + #[cfg(any(target_os = "linux", target_os = "freebsd"))] test_posix_fadvise(); - #[cfg(target_os = "linux,freebsd")] + #[cfg(any(target_os = "linux", target_os = "freebsd"))] test_sync_file_range(); test_mutex_libc_init_recursive(); @@ -302,14 +302,14 @@ fn main() { test_mutex_libc_init_errorcheck(); test_rwlock_libc_static_initializer(); - #[cfg(target_os = "linux,freebsd")] + #[cfg(any(target_os = "linux", target_os = "freebsd"))] test_mutex_libc_static_initializer_recursive(); - #[cfg(target_os = "linux,freebsd")] + #[cfg(any(target_os = "linux", target_os = "freebsd"))] test_prctl_thread_name(); test_thread_local_errno(); - #[cfg(target_os = "linux,freebsd")] + #[cfg(any(target_os = "linux", target_os = "freebsd"))] test_clocks(); } From e89b4d6df22e2056f2651d685f67d666908d079a Mon Sep 17 00:00:00 2001 From: infrandomness Date: Fri, 10 Jun 2022 12:12:20 +0200 Subject: [PATCH 3358/5092] Fix panicking ui_tests framework --- src/shims/unix/freebsd/foreign_items.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/shims/unix/freebsd/foreign_items.rs b/src/shims/unix/freebsd/foreign_items.rs index 712725238867..0efc44af82ba 100644 --- a/src/shims/unix/freebsd/foreign_items.rs +++ b/src/shims/unix/freebsd/foreign_items.rs @@ -17,7 +17,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ret: mir::BasicBlock, ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); - // match + match link_name.as_str() { + _ => return Ok(EmulateByNameResult::NotSupported), + } Ok(EmulateByNameResult::NeedsJumping) } } From f2cbd3e2bc732186d8aafea9f930fcc3b0c34ce0 Mon Sep 17 00:00:00 2001 From: infrandomness Date: Sun, 12 Jun 2022 11:47:43 +0200 Subject: [PATCH 3359/5092] Add `pthread_attr_getstack` shim --- src/shims/unix/freebsd/foreign_items.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/shims/unix/freebsd/foreign_items.rs b/src/shims/unix/freebsd/foreign_items.rs index 0efc44af82ba..4ff588e51a45 100644 --- a/src/shims/unix/freebsd/foreign_items.rs +++ b/src/shims/unix/freebsd/foreign_items.rs @@ -18,6 +18,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); match link_name.as_str() { + // Querying system information + "pthread_attr_getstack" => { + // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. + let [attr_place, addr_place, size_place] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + this.deref_operand(attr_place)?; + let addr_place = this.deref_operand(addr_place)?; + let size_place = this.deref_operand(size_place)?; + + this.write_scalar( + Scalar::from_uint(STACK_ADDR, this.pointer_size()), + &addr_place.into(), + )?; + this.write_scalar( + Scalar::from_uint(STACK_SIZE, this.pointer_size()), + &size_place.into(), + )?; + + // Return success (`0`). + this.write_null(dest)?; + } _ => return Ok(EmulateByNameResult::NotSupported), } Ok(EmulateByNameResult::NeedsJumping) From 93c61f3905d9ee123dd3ff2e07a48ed428a52e72 Mon Sep 17 00:00:00 2001 From: infrandomness Date: Sun, 12 Jun 2022 11:47:59 +0200 Subject: [PATCH 3360/5092] Add `pthread_attr_get_np` shim --- src/shims/unix/freebsd/foreign_items.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/shims/unix/freebsd/foreign_items.rs b/src/shims/unix/freebsd/foreign_items.rs index 4ff588e51a45..b1d0eed2c0ed 100644 --- a/src/shims/unix/freebsd/foreign_items.rs +++ b/src/shims/unix/freebsd/foreign_items.rs @@ -39,6 +39,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Return success (`0`). this.write_null(dest)?; } + + // Linux's `pthread_getattr_np` equivalent + "pthread_attr_get_np" if this.frame_in_std() => { + let [_thread, _attr] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + this.write_null(dest)?; + } _ => return Ok(EmulateByNameResult::NotSupported), } Ok(EmulateByNameResult::NeedsJumping) From aaa8ebb5765146665cb5b8fdc88d12c9b67d0ca5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jun 2022 16:20:37 -0400 Subject: [PATCH 3361/5092] only test a few tests on FreeBSD --- ci.sh | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index f436e0179ab6..1fa67f52139e 100755 --- a/ci.sh +++ b/ci.sh @@ -42,6 +42,16 @@ function run_tests { echo } +function run_tests_minimal { + if [ -n "${MIRI_TEST_TARGET+exists}" ]; then + echo "Testing MINIMAL foreign architecture $MIRI_TEST_TARGET: only testing $@" + else + echo "Testing MINIMAL host architecture: only testing $@" + fi + + ./miri test --locked -- "$@" +} + # host run_tests @@ -50,7 +60,7 @@ case $HOST_TARGET in MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests - MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests + MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec ;; x86_64-apple-darwin) MIRI_TEST_TARGET=mips64-unknown-linux-gnuabi64 run_tests # big-endian architecture From 84a02787d8cc81f10bc9119dec5239c687915210 Mon Sep 17 00:00:00 2001 From: infrandomness Date: Mon, 27 Jun 2022 01:13:13 +0200 Subject: [PATCH 3362/5092] Address code review - Merge pthread_attr_getstack shim to unix/foreign_items.rs --- src/shims/unix/foreign_items.rs | 22 ++++++++++++++++++++++ src/shims/unix/freebsd/foreign_items.rs | 22 ---------------------- src/shims/unix/linux/foreign_items.rs | 20 -------------------- 3 files changed, 22 insertions(+), 42 deletions(-) diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index d789b0c64047..4993690767c1 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -461,6 +461,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } + // Querying system information + "pthread_attr_getstack" => { + // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. + let [attr_place, addr_place, size_place] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + this.deref_operand(attr_place)?; + let addr_place = this.deref_operand(addr_place)?; + let size_place = this.deref_operand(size_place)?; + + this.write_scalar( + Scalar::from_uint(STACK_ADDR, this.pointer_size()), + &addr_place.into(), + )?; + this.write_scalar( + Scalar::from_uint(STACK_SIZE, this.pointer_size()), + &size_place.into(), + )?; + + // Return success (`0`). + this.write_null(dest)?; + } + | "signal" | "sigaltstack" if this.frame_in_std() => { diff --git a/src/shims/unix/freebsd/foreign_items.rs b/src/shims/unix/freebsd/foreign_items.rs index b1d0eed2c0ed..cad119233740 100644 --- a/src/shims/unix/freebsd/foreign_items.rs +++ b/src/shims/unix/freebsd/foreign_items.rs @@ -18,28 +18,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); match link_name.as_str() { - // Querying system information - "pthread_attr_getstack" => { - // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. - let [attr_place, addr_place, size_place] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - this.deref_operand(attr_place)?; - let addr_place = this.deref_operand(addr_place)?; - let size_place = this.deref_operand(size_place)?; - - this.write_scalar( - Scalar::from_uint(STACK_ADDR, this.pointer_size()), - &addr_place.into(), - )?; - this.write_scalar( - Scalar::from_uint(STACK_SIZE, this.pointer_size()), - &size_place.into(), - )?; - - // Return success (`0`). - this.write_null(dest)?; - } - // Linux's `pthread_getattr_np` equivalent "pthread_attr_get_np" if this.frame_in_std() => { let [_thread, _attr] = diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index ab3f39147c60..500250745c8b 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -80,27 +80,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } - // Querying system information - "pthread_attr_getstack" => { - // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. - let [attr_place, addr_place, size_place] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - this.deref_operand(attr_place)?; - let addr_place = this.deref_operand(addr_place)?; - let size_place = this.deref_operand(size_place)?; - this.write_scalar( - Scalar::from_uint(STACK_ADDR, this.pointer_size()), - &addr_place.into(), - )?; - this.write_scalar( - Scalar::from_uint(STACK_SIZE, this.pointer_size()), - &size_place.into(), - )?; - - // Return success (`0`). - this.write_null(dest)?; - } // Threading "prctl" => { From aa072d72ccf79e313ef28b73a8bced367d9a4a6f Mon Sep 17 00:00:00 2001 From: infrandomness Date: Mon, 27 Jun 2022 01:22:13 +0200 Subject: [PATCH 3363/5092] Cargo fmt --- src/shims/unix/linux/foreign_items.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index 500250745c8b..48abe9bf08c3 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -80,8 +80,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } - - // Threading "prctl" => { // prctl is variadic. (It is not documented like that in the manpage, but defined like that in the libc crate.) From 13d425daebe539b1a48731faecf1d1ba5287aa72 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jun 2022 21:14:18 -0400 Subject: [PATCH 3364/5092] make permissive provenance and raw-ptr tagging the default --- README.md | 25 ++---- src/bin/miri.rs | 7 +- src/diagnostics.rs | 25 +++++- src/eval.rs | 5 +- src/intptrcast.rs | 76 +++++++++---------- src/machine.rs | 3 +- src/stacked_borrows.rs | 8 +- test-cargo-miri/run-test.py | 5 -- .../fail/backtrace/bad-backtrace-flags.stderr | 17 ++++- tests/fail/backtrace/bad-backtrace-ptr.stderr | 17 ++++- .../bad-backtrace-resolve-flags.stderr | 17 ++++- .../bad-backtrace-resolve-names-flags.stderr | 17 ++++- .../thread_local_static_dealloc.stderr | 17 ++++- .../deref-invalid-ptr.stderr | 17 ++++- .../storage_dead_dangling.stderr | 22 +++++- .../wild_pointer_deref.stderr | 17 ++++- .../intrinsics/ptr_offset_0_plus_0.stderr | 17 ++++- .../intrinsics/ptr_offset_int_plus_int.stderr | 17 ++++- .../intrinsics/ptr_offset_int_plus_ptr.stderr | 17 ++++- .../fail/provenance/ptr_legacy_provenance.rs | 22 ------ .../provenance/ptr_legacy_provenance.stderr | 15 ---- .../fail/stacked_borrows/aliasing_mut3.stderr | 8 +- .../box_exclusive_violation1.rs | 4 +- .../box_exclusive_violation1.stderr | 33 ++++---- tests/fail/stacked_borrows/illegal_read3.rs | 2 +- .../fail/stacked_borrows/illegal_read6.stderr | 8 +- tests/fail/stacked_borrows/illegal_write1.rs | 4 +- .../stacked_borrows/illegal_write1.stderr | 21 ++--- .../stacked_borrows/illegal_write2.stderr | 8 +- .../stacked_borrows/illegal_write3.stderr | 6 +- tests/fail/stacked_borrows/illegal_write4.rs | 4 +- .../stacked_borrows/illegal_write4.stderr | 2 +- .../stacked_borrows/illegal_write6.stderr | 8 +- .../invalidate_against_barrier1.stderr | 8 +- .../invalidate_against_barrier2.stderr | 8 +- .../mut_exclusive_violation1.stderr | 8 +- .../stacked_borrows/outdated_local.stderr | 8 +- .../stacked_borrows/pointer_smuggling.stderr | 8 +- tests/fail/stacked_borrows/raw_tracking.rs | 1 - .../shr_frozen_violation1.stderr | 6 +- .../transmute-is-no-escape.stderr | 10 ++- .../stacked_borrows/unescaped_local.stderr | 32 ++++---- .../stacked_borrows/unescaped_static.stderr | 10 ++- .../intptrcast_alignment_check.stderr | 17 ++++- tests/fail/uninit_byte_read.rs | 1 + tests/fail/validity/cast_fn_ptr1.stderr | 17 ++++- tests/fail/validity/cast_fn_ptr2.stderr | 22 +++++- tests/pass/adjacent-allocs.rs | 2 + tests/pass/align.stderr | 20 +++++ tests/pass/box.rs | 2 +- tests/pass/box.stderr | 20 +++++ .../concurrency/tls_pthread_drop_order.rs | 7 +- tests/pass/extern_types.stderr | 15 ++++ tests/pass/intptrcast.rs | 2 + tests/pass/intrinsics.rs | 1 + .../pass/linux-getrandom-without-isolation.rs | 6 +- tests/pass/linux-getrandom.rs | 6 +- tests/pass/panic/catch_panic.rs | 2 +- tests/pass/ptr_int_casts.rs | 1 + tests/pass/ptr_offset.rs | 1 + tests/pass/stacked-borrows/2phase.rs | 2 - .../stacked-borrows/interior_mutability.rs | 1 - tests/pass/stacked-borrows/stacked-borrows.rs | 1 - tests/pass/zst.rs | 1 + 64 files changed, 491 insertions(+), 246 deletions(-) delete mode 100644 tests/fail/provenance/ptr_legacy_provenance.rs delete mode 100644 tests/fail/provenance/ptr_legacy_provenance.stderr create mode 100644 tests/pass/align.stderr create mode 100644 tests/pass/box.stderr create mode 100644 tests/pass/extern_types.stderr diff --git a/README.md b/README.md index 50586c9eceaf..efdbf5143d9f 100644 --- a/README.md +++ b/README.md @@ -306,7 +306,7 @@ environment variable. We first document the most relevant and most commonly used * `-Zmiri-strict-provenance` enables [strict provenance](https://github.com/rust-lang/rust/issues/95228) checking in Miri. This means that casting an integer to a pointer yields a result with 'invalid' provenance, i.e., with provenance - that cannot be used for any memory access. Also implies `-Zmiri-tag-raw-pointers`. + that cannot be used for any memory access. The remaining flags are for advanced use only, and more likely to change or be removed. Some of these are **unsound**, which means they can lead @@ -321,7 +321,7 @@ to Miri failing to detect cases of undefined behavior in a program. integers via `mem::transmute` or union/pointer type punning. This has two effects: it disables the check against integers storing a pointer (i.e., data with provenance), thus allowing pointer-to-integer transmutation, and it treats integer-to-pointer transmutation as equivalent to - a cast. Using this flag is **unsound** and + a cast. Implies `-Zmiri-permissive-provenance`. Using this flag is **unsound** and [deprecated](https://github.com/rust-lang/miri/issues/2188). * `-Zmiri-disable-abi-check` disables checking [function ABI]. Using this flag is **unsound**. @@ -354,15 +354,11 @@ to Miri failing to detect cases of undefined behavior in a program. application instead of raising an error within the context of Miri (and halting execution). Note that code might not expect these operations to ever panic, so this flag can lead to strange (mis)behavior. -* `-Zmiri-permissive-provenance` is **experimental**. This will make Miri do a - best-effort attempt to implement the semantics of - [`expose_addr`](https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.expose_addr) - and - [`ptr::from_exposed_addr`](https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html) - for pointer-to-int and int-to-pointer casts, respectively. This will - necessarily miss some bugs as those semantics are not efficiently - implementable in a sanitizer, but it will only miss bugs that concerns - memory/pointers which is subject to these operations. +* `-Zmiri-permissive-provenance` disables the warning for integer-to-pointer casts and + [`ptr::from_exposed_addr`](https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html). + This will necessarily miss some bugs as those operations are not efficiently and accurately + implementable in a sanitizer, but it will only miss bugs that concern memory/pointers which is + subject to these operations. * `-Zmiri-symbolic-alignment-check` makes the alignment check more strict. By default, alignment is checked by casting the pointer to an integer, and making sure that is a multiple of the alignment. This can lead to cases where a @@ -389,13 +385,6 @@ to Miri failing to detect cases of undefined behavior in a program. happening and where in your code would be a good place to look for it. Specifying this argument multiple times does not overwrite the previous values, instead it appends its values to the list. Listing a tag multiple times has no effect. -* `-Zmiri-tag-raw-pointers` makes Stacked Borrows assign proper tags even for raw pointers. This can - make valid code using int-to-ptr casts fail to pass the checks, but also can help identify latent - aliasing issues in code that Miri accepts by default. You can recognize false positives by - `` occurring in the message -- this indicates a pointer that was cast from an integer, - so Miri was unable to track this pointer. Note that it is not currently guaranteed that code that - works with `-Zmiri-tag-raw-pointers` also works without `-Zmiri-tag-raw-pointers`, but for the - vast majority of code, this will be the case. [function ABI]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 91148400c99b..7bced912645d 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -340,6 +340,7 @@ fn main() { Please let us know at if you rely on this flag." ); miri_config.allow_ptr_int_transmute = true; + miri_config.provenance_mode = ProvenanceMode::Permissive; } else if arg == "-Zmiri-disable-abi-check" { miri_config.check_abi = false; } else if arg == "-Zmiri-disable-isolation" { @@ -374,20 +375,18 @@ fn main() { } else if arg == "-Zmiri-panic-on-unsupported" { miri_config.panic_on_unsupported = true; } else if arg == "-Zmiri-tag-raw-pointers" { - miri_config.tag_raw = true; + eprintln!("WARNING: `-Zmiri-tag-raw-pointers` has no effect; it is enabled by default"); } else if arg == "-Zmiri-strict-provenance" { miri_config.provenance_mode = ProvenanceMode::Strict; - miri_config.tag_raw = true; + miri_config.allow_ptr_int_transmute = false; } else if arg == "-Zmiri-permissive-provenance" { miri_config.provenance_mode = ProvenanceMode::Permissive; - miri_config.tag_raw = true; } else if arg == "-Zmiri-mute-stdout-stderr" { miri_config.mute_stdout_stderr = true; } else if arg == "-Zmiri-track-raw-pointers" { eprintln!( "WARNING: -Zmiri-track-raw-pointers has been renamed to -Zmiri-tag-raw-pointers, the old name is deprecated." ); - miri_config.tag_raw = true; } else if let Some(param) = arg.strip_prefix("-Zmiri-seed=") { if miri_config.seed.is_some() { panic!("Cannot specify -Zmiri-seed multiple times!"); diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 6986d9c57271..d17d1e6ed4c8 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -69,6 +69,7 @@ pub enum NonHaltingDiagnostic { FreedAlloc(AllocId), RejectedIsolatedOp(String), ProgressReport, + Int2Ptr, } /// Level of Miri specific diagnostics @@ -468,15 +469,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx format!("{op} was made to return an error due to isolation"), ProgressReport => format!("progress report: current operation being executed is here"), + Int2Ptr => format!("pointer-to-integer cast"), }; let (title, diag_level) = match e { RejectedIsolatedOp(_) => ("operation rejected by isolation", DiagLevel::Warning), - _ => ("tracking was triggered", DiagLevel::Note), + Int2Ptr => ("pointer-to-integer cast", DiagLevel::Warning), + CreatedPointerTag(..) + | PoppedPointerTag(..) + | CreatedCallId(..) + | CreatedAlloc(..) + | FreedAlloc(..) + | ProgressReport => ("tracking was triggered", DiagLevel::Note), }; - report_msg(this, diag_level, title, vec![msg], vec![], &stacktrace); + let helps = match e { + Int2Ptr => + vec![ + (None, format!("this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`,")), + (None, format!("which means that Miri might miss pointer bugs in this program")), + (None, format!("see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation")), + (None, format!("to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead")), + (None, format!("you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics")), + (None, format!("alternatively, the `-Zmiri-permissive-provenance` flag disables this warning")), + ], + _ => vec![], + }; + + report_msg(this, diag_level, title, vec![msg], helps, &stacktrace); } }); } diff --git a/src/eval.rs b/src/eval.rs index 7beb2ec9c4ad..fa252953fe6e 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -101,8 +101,6 @@ pub struct MiriConfig { pub tracked_call_ids: HashSet, /// The allocation ids to report about. pub tracked_alloc_ids: HashSet, - /// Whether to track raw pointers in stacked borrows. - pub tag_raw: bool, /// Determine if data race detection should be enabled pub data_race_detector: bool, /// Determine if weak memory emulation should be enabled. Requires data race detection to be enabled @@ -146,14 +144,13 @@ impl Default for MiriConfig { tracked_pointer_tags: HashSet::default(), tracked_call_ids: HashSet::default(), tracked_alloc_ids: HashSet::default(), - tag_raw: false, data_race_detector: true, weak_memory_emulation: true, cmpxchg_weak_failure_rate: 0.8, // 80% measureme_out: None, panic_on_unsupported: false, backtrace_style: BacktraceStyle::Short, - provenance_mode: ProvenanceMode::Legacy, + provenance_mode: ProvenanceMode::Default, mute_stdout_stderr: false, preemption_rate: 0.01, // 1% report_progress: None, diff --git a/src/intptrcast.rs b/src/intptrcast.rs index cfaf61f9d5c8..c92954a218ca 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -11,16 +11,13 @@ use crate::*; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum ProvenanceMode { - /// Int2ptr casts return pointers with "wildcard" provenance - /// that basically matches that of all exposed pointers - /// (and SB tags, if enabled). + /// We support `expose_addr`/`from_exposed_addr` via "wildcard" provenance. + /// However, we want on `from_exposed_addr` to alert the user of the precision loss. + Default, + /// Like `Default`, but without the warning. Permissive, - /// Int2ptr casts return pointers with an invalid provenance, - /// i.e., not valid for any memory access. + /// We error on `from_exposed_addr`, ensuring no precision loss. Strict, - /// Int2ptr casts determine the allocation they point to at cast time. - /// All allocations are considered exposed. - Legacy, } pub type GlobalState = RefCell; @@ -66,6 +63,8 @@ impl<'mir, 'tcx> GlobalStateInner { let pos = global_state.int_to_ptr_map.binary_search_by_key(&addr, |(addr, _)| *addr); + // Determine the in-bounds provenance for this pointer. + // (This is only called on an actual access, so in-bounds is the only possible kind of provenance.) let alloc_id = match pos { Ok(pos) => Some(global_state.int_to_ptr_map[pos].1), Err(0) => None, @@ -91,21 +90,14 @@ impl<'mir, 'tcx> GlobalStateInner { } }?; - // In legacy mode, we consider all allocations exposed. - if global_state.provenance_mode == ProvenanceMode::Legacy - || global_state.exposed.contains(&alloc_id) - { - Some(alloc_id) - } else { - None - } + // We only use this provenance if it has been exposed. + if global_state.exposed.contains(&alloc_id) { Some(alloc_id) } else { None } } pub fn expose_ptr(ecx: &mut MiriEvalContext<'mir, 'tcx>, alloc_id: AllocId, sb: SbTag) { let global_state = ecx.machine.intptrcast.get_mut(); - // In legacy and strict mode, we don't need this, so we can save some cycles - // by not tracking it. - if global_state.provenance_mode == ProvenanceMode::Permissive { + // In strict mode, we don't need this, so we can save some cycles by not tracking it. + if global_state.provenance_mode != ProvenanceMode::Strict { trace!("Exposing allocation id {alloc_id:?}"); global_state.exposed.insert(alloc_id); if ecx.machine.stacked_borrows.is_some() { @@ -120,42 +112,43 @@ impl<'mir, 'tcx> GlobalStateInner { ) -> Pointer> { trace!("Transmuting 0x{:x} to a pointer", addr); - if ecx.machine.allow_ptr_int_transmute { - // When we allow transmutes, treat them like casts. - Self::ptr_from_addr_cast(ecx, addr) + let provenance = if ecx.machine.allow_ptr_int_transmute { + // When we allow transmutes, treat them like casts: generating a wildcard pointer. + Some(Tag::Wildcard) } else { - // We consider transmuted pointers to be "invalid" (`None` provenance). - Pointer::new(None, Size::from_bytes(addr)) - } + // Usually, we consider transmuted pointers to be "invalid" (`None` provenance). + None + }; + Pointer::new(provenance, Size::from_bytes(addr)) } pub fn ptr_from_addr_cast( ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, - ) -> Pointer> { + ) -> InterpResult<'tcx, Pointer>> { trace!("Casting 0x{:x} to a pointer", addr); let global_state = ecx.machine.intptrcast.borrow(); match global_state.provenance_mode { - ProvenanceMode::Legacy => { - // Determine the allocation this points to at cast time. - let alloc_id = Self::alloc_id_from_addr(ecx, addr); - Pointer::new( - alloc_id.map(|alloc_id| Tag::Concrete { alloc_id, sb: SbTag::Untagged }), - Size::from_bytes(addr), - ) + ProvenanceMode::Default => { + // The first time this happens, print a warning. + use std::sync::atomic::{AtomicBool, Ordering}; + static FIRST_WARNING: AtomicBool = AtomicBool::new(true); + if FIRST_WARNING.swap(false, Ordering::Relaxed) { + register_diagnostic(NonHaltingDiagnostic::Int2Ptr); + } } ProvenanceMode::Strict => { - // We don't support int2ptr casts in this mode (i.e., we treat them like - // transmutes). - Pointer::new(None, Size::from_bytes(addr)) - } - ProvenanceMode::Permissive => { - // This is how wildcard pointers are born. - Pointer::new(Some(Tag::Wildcard), Size::from_bytes(addr)) + throw_unsup_format!( + "integer-to-pointer casts and `from_exposed_addr` are not supported with `-Zmiri-strict-provenance`; use `with_addr` instead" + ) } + ProvenanceMode::Permissive => {} } + + // This is how wildcard pointers are born. + Ok(Pointer::new(Some(Tag::Wildcard), Size::from_bytes(addr))) } fn alloc_base_addr(ecx: &MiriEvalContext<'mir, 'tcx>, alloc_id: AllocId) -> u64 { @@ -214,6 +207,8 @@ impl<'mir, 'tcx> GlobalStateInner { dl.overflowing_offset(base_addr, offset.bytes()).0 } + /// Whena pointer is used for a memory access, this computes where in which allocation the + /// access is going. pub fn abs_ptr_to_rel( ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer, @@ -224,7 +219,6 @@ impl<'mir, 'tcx> GlobalStateInner { alloc_id } else { // A wildcard pointer. - assert_eq!(ecx.machine.intptrcast.borrow().provenance_mode, ProvenanceMode::Permissive); GlobalStateInner::alloc_id_from_addr(ecx, addr.bytes())? }; diff --git a/src/machine.rs b/src/machine.rs index 3621744e8025..d6a65a2a44c8 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -353,7 +353,6 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { Some(RefCell::new(stacked_borrows::GlobalStateInner::new( config.tracked_pointer_tags.clone(), config.tracked_call_ids.clone(), - config.tag_raw, ))) } else { None @@ -696,7 +695,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, ) -> InterpResult<'tcx, Pointer>> { - Ok(intptrcast::GlobalStateInner::ptr_from_addr_cast(ecx, addr)) + intptrcast::GlobalStateInner::ptr_from_addr_cast(ecx, addr) } #[inline(always)] diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 6fa70ddfc5d4..23408027626c 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -219,11 +219,7 @@ impl fmt::Display for RefKind { /// Utilities for initialization and ID generation impl GlobalStateInner { - pub fn new( - tracked_pointer_tags: HashSet, - tracked_call_ids: HashSet, - tag_raw: bool, - ) -> Self { + pub fn new(tracked_pointer_tags: HashSet, tracked_call_ids: HashSet) -> Self { GlobalStateInner { next_ptr_id: NonZeroU64::new(1).unwrap(), base_ptr_ids: FxHashMap::default(), @@ -231,7 +227,7 @@ impl GlobalStateInner { active_calls: FxHashSet::default(), tracked_pointer_tags, tracked_call_ids, - tag_raw, + tag_raw: true, } } diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 19965639489b..42978c481bff 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -124,11 +124,6 @@ def test_cargo_miri_test(): "test.cross-target.stdout.ref", "test.stderr-empty.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) - test("`cargo miri test` (raw-ptr tracking)", - cargo_miri("test"), - default_ref, "test.stderr-empty.ref", - env={'MIRIFLAGS': "-Zmiri-tag-raw-pointers"}, - ) test("`cargo miri test` (with filter)", cargo_miri("test") + ["--", "--format=pretty", "le1"], filter_ref, "test.stderr-empty.ref", diff --git a/tests/fail/backtrace/bad-backtrace-flags.stderr b/tests/fail/backtrace/bad-backtrace-flags.stderr index f6ffe3c93c89..ba16335fce3a 100644 --- a/tests/fail/backtrace/bad-backtrace-flags.stderr +++ b/tests/fail/backtrace/bad-backtrace-flags.stderr @@ -1,3 +1,18 @@ +warning: pointer-to-integer cast + --> $DIR/bad-backtrace-flags.rs:LL:CC + | +LL | miri_get_backtrace(2, 0 as *mut _); + | ^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main` at $DIR/bad-backtrace-flags.rs:LL:CC + error: unsupported operation: unknown `miri_get_backtrace` flags 2 --> $DIR/bad-backtrace-flags.rs:LL:CC | @@ -10,5 +25,5 @@ LL | miri_get_backtrace(2, 0 as *mut _); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/fail/backtrace/bad-backtrace-ptr.stderr b/tests/fail/backtrace/bad-backtrace-ptr.stderr index ed726a5dcdc2..75268b667142 100644 --- a/tests/fail/backtrace/bad-backtrace-ptr.stderr +++ b/tests/fail/backtrace/bad-backtrace-ptr.stderr @@ -1,3 +1,18 @@ +warning: pointer-to-integer cast + --> $DIR/bad-backtrace-ptr.rs:LL:CC + | +LL | miri_resolve_frame(0 as *mut _, 0); + | ^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main` at $DIR/bad-backtrace-ptr.rs:LL:CC + error: Undefined Behavior: null pointer is not a valid pointer for this operation --> $DIR/bad-backtrace-ptr.rs:LL:CC | @@ -11,5 +26,5 @@ LL | miri_resolve_frame(0 as *mut _, 0); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/fail/backtrace/bad-backtrace-resolve-flags.stderr b/tests/fail/backtrace/bad-backtrace-resolve-flags.stderr index 49495651dfec..fad9ffe11920 100644 --- a/tests/fail/backtrace/bad-backtrace-resolve-flags.stderr +++ b/tests/fail/backtrace/bad-backtrace-resolve-flags.stderr @@ -1,3 +1,18 @@ +warning: pointer-to-integer cast + --> $DIR/bad-backtrace-resolve-flags.rs:LL:CC + | +LL | let mut buf = vec![0 as *mut _; miri_backtrace_size(0)]; + | ^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main` at $DIR/bad-backtrace-resolve-flags.rs:LL:CC + error: unsupported operation: unknown `miri_resolve_frame` flags 2 --> $DIR/bad-backtrace-resolve-flags.rs:LL:CC | @@ -10,5 +25,5 @@ LL | miri_resolve_frame(buf[0], 2); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr b/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr index d575caa4ff4e..18b03df21c6f 100644 --- a/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr +++ b/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr @@ -1,3 +1,18 @@ +warning: pointer-to-integer cast + --> $DIR/bad-backtrace-resolve-names-flags.rs:LL:CC + | +LL | let mut buf = vec![0 as *mut _; miri_backtrace_size(0)]; + | ^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main` at $DIR/bad-backtrace-resolve-names-flags.rs:LL:CC + error: unsupported operation: unknown `miri_resolve_frame_names` flags 2 --> $DIR/bad-backtrace-resolve-names-flags.rs:LL:CC | @@ -10,5 +25,5 @@ LL | ... miri_resolve_frame_names(buf[0], 2, 0 as *mut _, 0 as *mut _); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/fail/concurrency/thread_local_static_dealloc.stderr b/tests/fail/concurrency/thread_local_static_dealloc.stderr index 2a3a8f0f55c3..31a64eec3685 100644 --- a/tests/fail/concurrency/thread_local_static_dealloc.stderr +++ b/tests/fail/concurrency/thread_local_static_dealloc.stderr @@ -1,3 +1,18 @@ +warning: pointer-to-integer cast + --> $DIR/thread_local_static_dealloc.rs:LL:CC + | +LL | let _val = *(dangling_ptr as *const u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main` at $DIR/thread_local_static_dealloc.rs:LL:CC + error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed --> $DIR/thread_local_static_dealloc.rs:LL:CC | @@ -11,5 +26,5 @@ LL | let _val = *(dangling_ptr as *const u8); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/fail/dangling_pointers/deref-invalid-ptr.stderr b/tests/fail/dangling_pointers/deref-invalid-ptr.stderr index f4361d9fefa9..ffd7fb1980dc 100644 --- a/tests/fail/dangling_pointers/deref-invalid-ptr.stderr +++ b/tests/fail/dangling_pointers/deref-invalid-ptr.stderr @@ -1,3 +1,18 @@ +warning: pointer-to-integer cast + --> $DIR/deref-invalid-ptr.rs:LL:CC + | +LL | let x = 16usize as *const u32; + | ^^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main` at $DIR/deref-invalid-ptr.rs:LL:CC + error: Undefined Behavior: dereferencing pointer failed: 0x10 is not a valid pointer --> $DIR/deref-invalid-ptr.rs:LL:CC | @@ -11,5 +26,5 @@ LL | let _y = unsafe { &*x as *const u32 }; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/fail/dangling_pointers/storage_dead_dangling.stderr b/tests/fail/dangling_pointers/storage_dead_dangling.stderr index aed14105ad07..3a94a7fa58ee 100644 --- a/tests/fail/dangling_pointers/storage_dead_dangling.stderr +++ b/tests/fail/dangling_pointers/storage_dead_dangling.stderr @@ -1,3 +1,23 @@ +warning: pointer-to-integer cast + --> $DIR/storage_dead_dangling.rs:LL:CC + | +LL | unsafe { &mut *(LEAK as *mut i32) }; + | ^^^^^^^^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `evil` at $DIR/storage_dead_dangling.rs:LL:CC +note: inside `main` at $DIR/storage_dead_dangling.rs:LL:CC + --> $DIR/storage_dead_dangling.rs:LL:CC + | +LL | evil(); + | ^^^^^^ + error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed --> $DIR/storage_dead_dangling.rs:LL:CC | @@ -16,5 +36,5 @@ LL | evil(); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/fail/dangling_pointers/wild_pointer_deref.stderr b/tests/fail/dangling_pointers/wild_pointer_deref.stderr index b20f310da083..960f9c9ce3e9 100644 --- a/tests/fail/dangling_pointers/wild_pointer_deref.stderr +++ b/tests/fail/dangling_pointers/wild_pointer_deref.stderr @@ -1,3 +1,18 @@ +warning: pointer-to-integer cast + --> $DIR/wild_pointer_deref.rs:LL:CC + | +LL | let p = 44 as *const i32; + | ^^^^^^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main` at $DIR/wild_pointer_deref.rs:LL:CC + error: Undefined Behavior: dereferencing pointer failed: 0x2c is not a valid pointer --> $DIR/wild_pointer_deref.rs:LL:CC | @@ -11,5 +26,5 @@ LL | let x = unsafe { *p }; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr b/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr index 741314ea8a68..2474820545d2 100644 --- a/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr +++ b/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr @@ -1,3 +1,18 @@ +warning: pointer-to-integer cast + --> $DIR/ptr_offset_0_plus_0.rs:LL:CC + | +LL | let x = 0 as *mut i32; + | ^^^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main` at $DIR/ptr_offset_0_plus_0.rs:LL:CC + error: Undefined Behavior: pointer arithmetic failed: null pointer is not a valid pointer --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC | @@ -16,5 +31,5 @@ LL | let _x = unsafe { x.offset(0) }; // UB despite offset 0, NULL is never note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr b/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr index e6b8f102f394..f5cbd4bbbf73 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr +++ b/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr @@ -1,3 +1,18 @@ +warning: pointer-to-integer cast + --> $DIR/ptr_offset_int_plus_int.rs:LL:CC + | +LL | let _val = (1 as *mut u8).offset(1); + | ^^^^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main` at $DIR/ptr_offset_int_plus_int.rs:LL:CC + error: Undefined Behavior: pointer arithmetic failed: 0x1 is not a valid pointer --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC | @@ -16,5 +31,5 @@ LL | let _val = (1 as *mut u8).offset(1); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr index f88ad758d438..577a377f076e 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr +++ b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr @@ -1,3 +1,18 @@ +warning: pointer-to-integer cast + --> $DIR/ptr_offset_int_plus_ptr.rs:LL:CC + | +LL | let _val = (1 as *mut u8).offset(ptr as isize); + | ^^^^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main` at $DIR/ptr_offset_int_plus_ptr.rs:LL:CC + error: Undefined Behavior: pointer arithmetic failed: 0x1 is not a valid pointer --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC | @@ -16,5 +31,5 @@ LL | let _val = (1 as *mut u8).offset(ptr as isize); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/fail/provenance/ptr_legacy_provenance.rs b/tests/fail/provenance/ptr_legacy_provenance.rs deleted file mode 100644 index 538ec4484edb..000000000000 --- a/tests/fail/provenance/ptr_legacy_provenance.rs +++ /dev/null @@ -1,22 +0,0 @@ -// compile-flags: -Zmiri-disable-stacked-borrows -// normalize-stderr-test: "offset -[0-9]+" -> "offset -XX" -#![feature(strict_provenance)] - -use std::ptr; - -// Make sure that with legacy provenance, the allocation id of -// a casted pointer is determined at cast-time -fn main() { - let x: i32 = 0; - let y: i32 = 1; - - let x_ptr = &x as *const i32; - let y_ptr = &y as *const i32; - - let x_usize = x_ptr.expose_addr(); - let y_usize = y_ptr.expose_addr(); - - let ptr = ptr::from_exposed_addr::(y_usize); - let ptr = ptr.with_addr(x_usize); - assert_eq!(unsafe { *ptr }, 0); //~ ERROR is out-of-bounds -} diff --git a/tests/fail/provenance/ptr_legacy_provenance.stderr b/tests/fail/provenance/ptr_legacy_provenance.stderr deleted file mode 100644 index 4552be08145d..000000000000 --- a/tests/fail/provenance/ptr_legacy_provenance.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 4, so pointer to 4 bytes starting at offset -XX is out-of-bounds - --> $DIR/ptr_legacy_provenance.rs:LL:CC - | -LL | assert_eq!(unsafe { *ptr }, 0); - | ^^^^ dereferencing pointer failed: ALLOC has size 4, so pointer to 4 bytes starting at offset -XX is out-of-bounds - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `main` at $DIR/ptr_legacy_provenance.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/stacked_borrows/aliasing_mut3.stderr b/tests/fail/stacked_borrows/aliasing_mut3.stderr index a4187be0a25b..66220cfbfc4d 100644 --- a/tests/fail/stacked_borrows/aliasing_mut3.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut3.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/aliasing_mut3.rs:LL:CC | LL | pub fn safe(_x: &mut i32, _y: &i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: tag was most recently created at offsets [0x0..0x4] +help: was created by a retag at offsets [0x0..0x4] --> $DIR/aliasing_mut3.rs:LL:CC | LL | safe_raw(xraw, xshr); | ^^^^ -help: tag was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] --> $DIR/aliasing_mut3.rs:LL:CC | LL | pub fn safe(_x: &mut i32, _y: &i32) {} diff --git a/tests/fail/stacked_borrows/box_exclusive_violation1.rs b/tests/fail/stacked_borrows/box_exclusive_violation1.rs index 3ca480ae7ab8..66d092d6277c 100644 --- a/tests/fail/stacked_borrows/box_exclusive_violation1.rs +++ b/tests/fail/stacked_borrows/box_exclusive_violation1.rs @@ -8,7 +8,7 @@ fn demo_mut_advanced_unique(mut our: Box) -> i32 { unknown_code_2(); // We know this will return 5 - *our //~ ERROR borrow stack + *our } // Now comes the evil context @@ -24,7 +24,7 @@ fn unknown_code_1(x: &i32) { fn unknown_code_2() { unsafe { - *LEAK = 7; + *LEAK = 7; //~ ERROR borrow stack } } diff --git a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr index 3c3e6bbf1bc7..06c2dc340b7b 100644 --- a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr +++ b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr @@ -1,31 +1,30 @@ -error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/box_exclusive_violation1.rs:LL:CC | -LL | *our - | ^^^^ - | | - | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | *LEAK = 7; + | ^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/box_exclusive_violation1.rs:LL:CC | -LL | / fn demo_mut_advanced_unique(mut our: Box) -> i32 { -LL | | unknown_code_1(&*our); -LL | | -LL | | // This "re-asserts" uniqueness of the reference: After writing, we know -... | -LL | | *our -LL | | } - | |_^ +LL | LEAK = x as *const _ as *mut _; + | ^ help: was later invalidated at offsets [0x0..0x4] --> $DIR/box_exclusive_violation1.rs:LL:CC | -LL | *LEAK = 7; - | ^^^^^^^^^ - = note: inside `demo_mut_advanced_unique` at $DIR/box_exclusive_violation1.rs:LL:CC +LL | *our = 5; + | ^^^^^^^^ + = note: inside `unknown_code_2` at $DIR/box_exclusive_violation1.rs:LL:CC +note: inside `demo_mut_advanced_unique` at $DIR/box_exclusive_violation1.rs:LL:CC + --> $DIR/box_exclusive_violation1.rs:LL:CC + | +LL | unknown_code_2(); + | ^^^^^^^^^^^^^^^^ note: inside `main` at $DIR/box_exclusive_violation1.rs:LL:CC --> $DIR/box_exclusive_violation1.rs:LL:CC | diff --git a/tests/fail/stacked_borrows/illegal_read3.rs b/tests/fail/stacked_borrows/illegal_read3.rs index 3de8f57d6223..0173ca14b22d 100644 --- a/tests/fail/stacked_borrows/illegal_read3.rs +++ b/tests/fail/stacked_borrows/illegal_read3.rs @@ -5,7 +5,7 @@ use std::mem; union HiddenRef { - // We avoid retagging at this type, so shared vs mutable does not matter. + // We avoid retagging at this type, and we only read, so shared vs mutable does not matter. r: &'static i32, } diff --git a/tests/fail/stacked_borrows/illegal_read6.stderr b/tests/fail/stacked_borrows/illegal_read6.stderr index 9782f1aa3a58..2098dbdc6a49 100644 --- a/tests/fail/stacked_borrows/illegal_read6.stderr +++ b/tests/fail/stacked_borrows/illegal_read6.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/illegal_read6.rs:LL:CC | LL | let _val = *raw; | ^^^^ | | - | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: tag was most recently created at offsets [0x0..0x4] +help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_read6.rs:LL:CC | LL | let raw = x as *mut _; | ^ -help: tag was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] --> $DIR/illegal_read6.rs:LL:CC | LL | let x = &mut *x; // kill `raw` diff --git a/tests/fail/stacked_borrows/illegal_write1.rs b/tests/fail/stacked_borrows/illegal_write1.rs index 1f566f18c1f8..58600402e4ed 100644 --- a/tests/fail/stacked_borrows/illegal_write1.rs +++ b/tests/fail/stacked_borrows/illegal_write1.rs @@ -3,7 +3,7 @@ fn main() { let xref = &*target; { let x: *mut u32 = xref as *const _ as *mut _; - unsafe { *x = 42 }; // invalidates shared ref, activates raw + unsafe { *x = 42 }; //~ ERROR only grants SharedReadOnly permission } - let _x = *xref; //~ ERROR borrow stack + let _x = *xref; } diff --git a/tests/fail/stacked_borrows/illegal_write1.stderr b/tests/fail/stacked_borrows/illegal_write1.stderr index 1731e3c1de13..b2084da862fe 100644 --- a/tests/fail/stacked_borrows/illegal_write1.stderr +++ b/tests/fail/stacked_borrows/illegal_write1.stderr @@ -1,24 +1,19 @@ -error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location --> $DIR/illegal_write1.rs:LL:CC | -LL | let _x = *xref; - | ^^^^^ - | | - | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | unsafe { *x = 42 }; + | ^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_write1.rs:LL:CC | -LL | let xref = &*target; - | ^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] - --> $DIR/illegal_write1.rs:LL:CC - | -LL | unsafe { *x = 42 }; // invalidates shared ref, activates raw - | ^^^^^^^ +LL | let x: *mut u32 = xref as *const _ as *mut _; + | ^^^^ = note: inside `main` at $DIR/illegal_write1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write2.stderr b/tests/fail/stacked_borrows/illegal_write2.stderr index 7e896c530ac7..09784bd79a18 100644 --- a/tests/fail/stacked_borrows/illegal_write2.stderr +++ b/tests/fail/stacked_borrows/illegal_write2.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/illegal_write2.rs:LL:CC | LL | unsafe { *target2 = 13 }; | ^^^^^^^^^^^^^ | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: tag was most recently created at offsets [0x0..0x4] +help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_write2.rs:LL:CC | LL | let target2 = target as *mut _; | ^^^^^^ -help: tag was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] --> $DIR/illegal_write2.rs:LL:CC | LL | drop(&mut *target); // reborrow diff --git a/tests/fail/stacked_borrows/illegal_write3.stderr b/tests/fail/stacked_borrows/illegal_write3.stderr index 7e9c82769d6a..983894dad065 100644 --- a/tests/fail/stacked_borrows/illegal_write3.stderr +++ b/tests/fail/stacked_borrows/illegal_write3.stderr @@ -1,15 +1,15 @@ -error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location --> $DIR/illegal_write3.rs:LL:CC | LL | unsafe { *ptr = 42 }; | ^^^^^^^^^ | | - | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location + | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: tag was most recently created at offsets [0x0..0x4] +help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_write3.rs:LL:CC | LL | let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag diff --git a/tests/fail/stacked_borrows/illegal_write4.rs b/tests/fail/stacked_borrows/illegal_write4.rs index be4f89ba289a..654a23d382b8 100644 --- a/tests/fail/stacked_borrows/illegal_write4.rs +++ b/tests/fail/stacked_borrows/illegal_write4.rs @@ -6,8 +6,8 @@ fn main() { // Even just creating it unfreezes. let raw = &mut target as *mut _; // let this leak to raw let reference = unsafe { &*raw }; // freeze - let ptr = reference as *const _ as *mut i32; // raw ptr, with raw tag - let _mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag + let _ptr = reference as *const _ as *mut i32; // raw ptr, with raw tag + let _mut_ref: &mut i32 = unsafe { mem::transmute(raw) }; // &mut, with raw tag // Now we retag, making our ref top-of-stack -- and, in particular, unfreezing. let _val = *reference; //~ ERROR borrow stack } diff --git a/tests/fail/stacked_borrows/illegal_write4.stderr b/tests/fail/stacked_borrows/illegal_write4.stderr index 404e13d1138a..ac4dd68bbc7e 100644 --- a/tests/fail/stacked_borrows/illegal_write4.stderr +++ b/tests/fail/stacked_borrows/illegal_write4.stderr @@ -17,7 +17,7 @@ LL | let reference = unsafe { &*raw }; // freeze help: was later invalidated at offsets [0x0..0x4] --> $DIR/illegal_write4.rs:LL:CC | -LL | let _mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag +LL | let _mut_ref: &mut i32 = unsafe { mem::transmute(raw) }; // &mut, with raw tag | ^^^^^^^^^^^^^^^^^^^ = note: inside `main` at $DIR/illegal_write4.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_write6.stderr b/tests/fail/stacked_borrows/illegal_write6.stderr index 11757cca9b65..563397e062d5 100644 --- a/tests/fail/stacked_borrows/illegal_write6.stderr +++ b/tests/fail/stacked_borrows/illegal_write6.stderr @@ -1,17 +1,17 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] --> $DIR/illegal_write6.rs:LL:CC | LL | unsafe { *y = 2 }; - | ^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] + | ^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: tag was most recently created at offsets [0x0..0x4] +help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_write6.rs:LL:CC | LL | let p = x as *mut u32; | ^ -help: was protected due to a tag which was created here +help: was protected due to which was created here --> $DIR/illegal_write6.rs:LL:CC | LL | foo(x, p); diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr index 08d597ea1895..826cdc9b5f8e 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr @@ -1,17 +1,17 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] --> $DIR/invalidate_against_barrier1.rs:LL:CC | LL | let _val = unsafe { *x }; - | ^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] + | ^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: tag was most recently created at offsets [0x0..0x4] +help: was created by a retag at offsets [0x0..0x4] --> $DIR/invalidate_against_barrier1.rs:LL:CC | LL | let xraw = &mut x as *mut _; | ^^^^^^ -help: was protected due to a tag which was created here +help: was protected due to which was created here --> $DIR/invalidate_against_barrier1.rs:LL:CC | LL | inner(xraw, xref); diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr index 6aefa216ed56..1cf90f91db02 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr @@ -1,17 +1,17 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] --> $DIR/invalidate_against_barrier2.rs:LL:CC | LL | unsafe { *x = 0 }; - | ^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] + | ^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: tag was most recently created at offsets [0x0..0x4] +help: was created by a retag at offsets [0x0..0x4] --> $DIR/invalidate_against_barrier2.rs:LL:CC | LL | let xraw = &mut x as *mut _; | ^^^^^^ -help: was protected due to a tag which was created here +help: was protected due to which was created here --> $DIR/invalidate_against_barrier2.rs:LL:CC | LL | inner(xraw, xref); diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr b/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr index ea14536a3990..8afb4fee18b5 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr +++ b/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/mut_exclusive_violation1.rs:LL:CC | LL | *LEAK = 7; | ^^^^^^^^^ | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: tag was most recently created at offsets [0x0..0x4] +help: was created by a retag at offsets [0x0..0x4] --> $DIR/mut_exclusive_violation1.rs:LL:CC | LL | LEAK = x as *const _ as *mut _; | ^ -help: tag was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] --> $DIR/mut_exclusive_violation1.rs:LL:CC | LL | *our = 5; diff --git a/tests/fail/stacked_borrows/outdated_local.stderr b/tests/fail/stacked_borrows/outdated_local.stderr index fe3bdd00f462..c218d500cf8b 100644 --- a/tests/fail/stacked_borrows/outdated_local.stderr +++ b/tests/fail/stacked_borrows/outdated_local.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/outdated_local.rs:LL:CC | LL | assert_eq!(unsafe { *y }, 1); | ^^ | | - | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: tag was most recently created at offsets [0x0..0x4] +help: was created by a retag at offsets [0x0..0x4] --> $DIR/outdated_local.rs:LL:CC | LL | let y: *const i32 = &x; | ^^ -help: tag was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] --> $DIR/outdated_local.rs:LL:CC | LL | x = 1; // this invalidates y by reactivating the lowermost uniq borrow for this local diff --git a/tests/fail/stacked_borrows/pointer_smuggling.stderr b/tests/fail/stacked_borrows/pointer_smuggling.stderr index 68ac631ec09e..a3ab1b9fc5e5 100644 --- a/tests/fail/stacked_borrows/pointer_smuggling.stderr +++ b/tests/fail/stacked_borrows/pointer_smuggling.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/pointer_smuggling.rs:LL:CC | LL | let _x = unsafe { *PTR }; | ^^^^ | | - | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x1] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: tag was most recently created at offsets [0x0..0x1] +help: was created by a retag at offsets [0x0..0x1] --> $DIR/pointer_smuggling.rs:LL:CC | LL | PTR = x; | ^ -help: tag was later invalidated at offsets [0x0..0x1] +help: was later invalidated at offsets [0x0..0x1] --> $DIR/pointer_smuggling.rs:LL:CC | LL | *val = 2; // this invalidates any raw ptrs `fun1` might have created. diff --git a/tests/fail/stacked_borrows/raw_tracking.rs b/tests/fail/stacked_borrows/raw_tracking.rs index 0b9c058f06ef..49fe98312550 100644 --- a/tests/fail/stacked_borrows/raw_tracking.rs +++ b/tests/fail/stacked_borrows/raw_tracking.rs @@ -1,4 +1,3 @@ -// compile-flags: -Zmiri-tag-raw-pointers //! This demonstrates a provenance problem that requires tracking of raw pointers to be detected. fn main() { diff --git a/tests/fail/stacked_borrows/shr_frozen_violation1.stderr b/tests/fail/stacked_borrows/shr_frozen_violation1.stderr index 0808d8471b45..55872300713a 100644 --- a/tests/fail/stacked_borrows/shr_frozen_violation1.stderr +++ b/tests/fail/stacked_borrows/shr_frozen_violation1.stderr @@ -1,15 +1,15 @@ -error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location --> $DIR/shr_frozen_violation1.rs:LL:CC | LL | *(x as *const i32 as *mut i32) = 7; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location + | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: tag was most recently created at offsets [0x0..0x4] +help: was created by a retag at offsets [0x0..0x4] --> $DIR/shr_frozen_violation1.rs:LL:CC | LL | *(x as *const i32 as *mut i32) = 7; diff --git a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr index a9682f806ba2..91c3ff9f8634 100644 --- a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr +++ b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr @@ -1,15 +1,19 @@ -error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/transmute-is-no-escape.rs:LL:CC | LL | unsafe { *raw = 13 }; | ^^^^^^^^^ | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - +help: was created by a retag at offsets [0x4..0x8] + --> $DIR/transmute-is-no-escape.rs:LL:CC + | +LL | let raw = (&mut x[1] as *mut i32).wrapping_offset(-1); + | ^^^^^^^^^ = note: inside `main` at $DIR/transmute-is-no-escape.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/unescaped_local.stderr b/tests/fail/stacked_borrows/unescaped_local.stderr index 616c60b8aa1b..2f6605c058b2 100644 --- a/tests/fail/stacked_borrows/unescaped_local.stderr +++ b/tests/fail/stacked_borrows/unescaped_local.stderr @@ -1,27 +1,33 @@ -error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +warning: pointer-to-integer cast + --> $DIR/unescaped_local.rs:LL:CC + | +LL | let raw = &mut x as *mut i32 as usize as *mut i32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main` at $DIR/unescaped_local.rs:LL:CC + +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but no exposed tags have suitable permission in the borrow stack for this location --> $DIR/unescaped_local.rs:LL:CC | LL | *raw = 13; | ^^^^^^^^^ | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | attempting a write access using at ALLOC[0x0], but no exposed tags have suitable permission in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: tag was most recently created at offsets [0x0..0x4] - --> $DIR/unescaped_local.rs:LL:CC - | -LL | let raw = &mut x as *mut i32 as usize as *mut i32; - | ^^^^^^ -help: tag was later invalidated at offsets [0x0..0x4] - --> $DIR/unescaped_local.rs:LL:CC - | -LL | let _ptr = &mut x; - | ^^^^^^ + = note: inside `main` at $DIR/unescaped_local.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/fail/stacked_borrows/unescaped_static.stderr b/tests/fail/stacked_borrows/unescaped_static.stderr index a0ac19f04293..621e9617fdfc 100644 --- a/tests/fail/stacked_borrows/unescaped_static.stderr +++ b/tests/fail/stacked_borrows/unescaped_static.stderr @@ -1,15 +1,19 @@ -error: Undefined Behavior: attempting a read access using at ALLOC[0x1], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: attempting a read access using at ALLOC[0x1], but that tag does not exist in the borrow stack for this location --> $DIR/unescaped_static.rs:LL:CC | LL | let _val = unsafe { *ptr_to_first.add(1) }; | ^^^^^^^^^^^^^^^^^^^^ | | - | attempting a read access using at ALLOC[0x1], but that tag does not exist in the borrow stack for this location + | attempting a read access using at ALLOC[0x1], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x1..0x2] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - +help: was created by a retag at offsets [0x0..0x1] + --> $DIR/unescaped_static.rs:LL:CC + | +LL | let ptr_to_first = &ARRAY[0] as *const u8; + | ^^^^^^^^^ = note: inside `main` at $DIR/unescaped_static.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr b/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr index 347486187e1b..bd8d161de832 100644 --- a/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr +++ b/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr @@ -1,3 +1,18 @@ +warning: pointer-to-integer cast + --> $DIR/intptrcast_alignment_check.rs:LL:CC + | +LL | let u16_ptr = base_addr_aligned as *mut u16; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main` at $DIR/intptrcast_alignment_check.rs:LL:CC + error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required --> $DIR/intptrcast_alignment_check.rs:LL:CC | @@ -11,5 +26,5 @@ LL | unsafe { *u16_ptr = 2 }; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/fail/uninit_byte_read.rs b/tests/fail/uninit_byte_read.rs index 6868e5895507..683088e78bff 100644 --- a/tests/fail/uninit_byte_read.rs +++ b/tests/fail/uninit_byte_read.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-disable-stacked-borrows fn main() { let v: Vec = Vec::with_capacity(10); let undef = unsafe { *v.get_unchecked(5) }; //~ ERROR uninitialized diff --git a/tests/fail/validity/cast_fn_ptr1.stderr b/tests/fail/validity/cast_fn_ptr1.stderr index d048377a7793..d75857900052 100644 --- a/tests/fail/validity/cast_fn_ptr1.stderr +++ b/tests/fail/validity/cast_fn_ptr1.stderr @@ -1,3 +1,18 @@ +warning: pointer-to-integer cast + --> $DIR/cast_fn_ptr1.rs:LL:CC + | +LL | g(0usize as *const i32) + | ^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main` at $DIR/cast_fn_ptr1.rs:LL:CC + error: Undefined Behavior: type validation failed: encountered a null reference --> $DIR/cast_fn_ptr1.rs:LL:CC | @@ -11,5 +26,5 @@ LL | g(0usize as *const i32) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/fail/validity/cast_fn_ptr2.stderr b/tests/fail/validity/cast_fn_ptr2.stderr index 10b9b9b8602b..d47b39356ffc 100644 --- a/tests/fail/validity/cast_fn_ptr2.stderr +++ b/tests/fail/validity/cast_fn_ptr2.stderr @@ -1,3 +1,23 @@ +warning: pointer-to-integer cast + --> $DIR/cast_fn_ptr2.rs:LL:CC + | +LL | 0usize as *const i32 + | ^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main::f` at $DIR/cast_fn_ptr2.rs:LL:CC +note: inside `main` at $DIR/cast_fn_ptr2.rs:LL:CC + --> $DIR/cast_fn_ptr2.rs:LL:CC + | +LL | let _x = g(); + | ^^^ + error: Undefined Behavior: type validation failed: encountered a null reference --> $DIR/cast_fn_ptr2.rs:LL:CC | @@ -11,5 +31,5 @@ LL | let _x = g(); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/pass/adjacent-allocs.rs b/tests/pass/adjacent-allocs.rs index 509965fe4fa9..925430ae2030 100644 --- a/tests/pass/adjacent-allocs.rs +++ b/tests/pass/adjacent-allocs.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-permissive-provenance + fn main() { // The slack between allocations is random. // Loop a few times to hit the zero-slack case. diff --git a/tests/pass/align.stderr b/tests/pass/align.stderr new file mode 100644 index 000000000000..9a15ec2cda6c --- /dev/null +++ b/tests/pass/align.stderr @@ -0,0 +1,20 @@ +warning: pointer-to-integer cast + --> $DIR/align.rs:LL:CC + | +LL | let u16_ptr = base_addr_aligned as *mut u16; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `manual_alignment` at $DIR/align.rs:LL:CC +note: inside `main` at $DIR/align.rs:LL:CC + --> $DIR/align.rs:LL:CC + | +LL | manual_alignment(); + | ^^^^^^^^^^^^^^^^^^ + diff --git a/tests/pass/box.rs b/tests/pass/box.rs index c2ecc3707179..7bbe7be516b9 100644 --- a/tests/pass/box.rs +++ b/tests/pass/box.rs @@ -47,7 +47,7 @@ fn boxed_pair_to_vec() { struct Foo(u64); fn reinterstruct(box_pair: Box) -> Vec { let ref_pair = Box::leak(box_pair) as *mut PairFoo; - let ptr_foo = unsafe { &mut (*ref_pair).fst as *mut Foo }; + let ptr_foo = unsafe { std::ptr::addr_of_mut!((*ref_pair).fst) }; unsafe { Vec::from_raw_parts(ptr_foo, 2, 2) } } diff --git a/tests/pass/box.stderr b/tests/pass/box.stderr new file mode 100644 index 000000000000..eac98bf2d124 --- /dev/null +++ b/tests/pass/box.stderr @@ -0,0 +1,20 @@ +warning: pointer-to-integer cast + --> $DIR/box.rs:LL:CC + | +LL | let r2 = ((r as usize) + 0) as *mut i32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `into_raw` at $DIR/box.rs:LL:CC +note: inside `main` at $DIR/box.rs:LL:CC + --> $DIR/box.rs:LL:CC + | +LL | into_raw(); + | ^^^^^^^^^^ + diff --git a/tests/pass/concurrency/tls_pthread_drop_order.rs b/tests/pass/concurrency/tls_pthread_drop_order.rs index 4d69449821cd..29c57bf49a33 100644 --- a/tests/pass/concurrency/tls_pthread_drop_order.rs +++ b/tests/pass/concurrency/tls_pthread_drop_order.rs @@ -4,6 +4,7 @@ extern crate libc; use std::mem; +use std::ptr; pub type Key = libc::pthread_key_t; @@ -11,7 +12,7 @@ static mut RECORD: usize = 0; static mut KEYS: [Key; 2] = [0; 2]; static mut GLOBALS: [u64; 2] = [1, 0]; -static mut CANNARY: *mut u64 = 0 as *mut _; // this serves as a cannary: if TLS dtors are not run properly, this will not get deallocated, making the test fail. +static mut CANNARY: *mut u64 = ptr::null_mut(); // this serves as a cannary: if TLS dtors are not run properly, this will not get deallocated, making the test fail. pub unsafe fn create(dtor: Option) -> Key { let mut key = 0; @@ -30,7 +31,7 @@ pub fn record(r: usize) { } unsafe extern "C" fn dtor(ptr: *mut u64) { - assert!(CANNARY != 0 as *mut _); // make sure we do not get run too often + assert!(CANNARY != ptr::null_mut()); // make sure we do not get run too often let val = *ptr; let which_key = @@ -48,7 +49,7 @@ unsafe extern "C" fn dtor(ptr: *mut u64) { // The correct sequence is: First key 0, then key 1, then key 0. if RECORD == 0_1_0 { drop(Box::from_raw(CANNARY)); - CANNARY = 0 as *mut _; + CANNARY = ptr::null_mut(); } } diff --git a/tests/pass/extern_types.stderr b/tests/pass/extern_types.stderr new file mode 100644 index 000000000000..730a43042535 --- /dev/null +++ b/tests/pass/extern_types.stderr @@ -0,0 +1,15 @@ +warning: pointer-to-integer cast + --> $DIR/extern_types.rs:LL:CC + | +LL | let x: &Foo = unsafe { &*(16 as *const Foo) }; + | ^^^^^^^^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main` at $DIR/extern_types.rs:LL:CC + diff --git a/tests/pass/intptrcast.rs b/tests/pass/intptrcast.rs index aafa90204fc2..a5e1d196529e 100644 --- a/tests/pass/intptrcast.rs +++ b/tests/pass/intptrcast.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-permissive-provenance + // This strips provenance fn transmute_ptr_to_int(x: *const T) -> usize { unsafe { std::mem::transmute(x) } diff --git a/tests/pass/intrinsics.rs b/tests/pass/intrinsics.rs index 9e310082f359..0042872a3b45 100644 --- a/tests/pass/intrinsics.rs +++ b/tests/pass/intrinsics.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-permissive-provenance #![feature(core_intrinsics, const_raw_ptr_comparison)] #![feature(layout_for_ptr)] diff --git a/tests/pass/linux-getrandom-without-isolation.rs b/tests/pass/linux-getrandom-without-isolation.rs index ad1a1f27c771..56a53699477e 100644 --- a/tests/pass/linux-getrandom-without-isolation.rs +++ b/tests/pass/linux-getrandom-without-isolation.rs @@ -3,13 +3,15 @@ #![feature(rustc_private)] extern crate libc; +use std::ptr; + fn main() { let mut buf = [0u8; 5]; unsafe { assert_eq!( libc::syscall( libc::SYS_getrandom, - 0 as *mut libc::c_void, + ptr::null_mut::(), 0 as libc::size_t, 0 as libc::c_uint, ), @@ -26,7 +28,7 @@ fn main() { ); assert_eq!( - libc::getrandom(0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), + libc::getrandom(ptr::null_mut::(), 0 as libc::size_t, 0 as libc::c_uint), 0, ); assert_eq!( diff --git a/tests/pass/linux-getrandom.rs b/tests/pass/linux-getrandom.rs index 7d3f899f4408..a3596e4c7a9c 100644 --- a/tests/pass/linux-getrandom.rs +++ b/tests/pass/linux-getrandom.rs @@ -2,13 +2,15 @@ #![feature(rustc_private)] extern crate libc; +use std::ptr; + fn main() { let mut buf = [0u8; 5]; unsafe { assert_eq!( libc::syscall( libc::SYS_getrandom, - 0 as *mut libc::c_void, + ptr::null_mut::(), 0 as libc::size_t, 0 as libc::c_uint, ), @@ -25,7 +27,7 @@ fn main() { ); assert_eq!( - libc::getrandom(0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), + libc::getrandom(ptr::null_mut::(), 0 as libc::size_t, 0 as libc::c_uint), 0, ); assert_eq!( diff --git a/tests/pass/panic/catch_panic.rs b/tests/pass/panic/catch_panic.rs index 2fb00391cd79..3979fb3b0714 100644 --- a/tests/pass/panic/catch_panic.rs +++ b/tests/pass/panic/catch_panic.rs @@ -1,5 +1,5 @@ // We test the `align_offset` panic below, make sure we test the interpreter impl and not the "real" one. -// compile-flags: -Zmiri-symbolic-alignment-check +// compile-flags: -Zmiri-symbolic-alignment-check -Zmiri-permissive-provenance #![feature(never_type)] #![allow(unconditional_panic, non_fmt_panics)] diff --git a/tests/pass/ptr_int_casts.rs b/tests/pass/ptr_int_casts.rs index 889b6bd04f9d..ffe6a114c66b 100644 --- a/tests/pass/ptr_int_casts.rs +++ b/tests/pass/ptr_int_casts.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-permissive-provenance use std::mem; use std::ptr; diff --git a/tests/pass/ptr_offset.rs b/tests/pass/ptr_offset.rs index 1b25df721452..b16a06a7260b 100644 --- a/tests/pass/ptr_offset.rs +++ b/tests/pass/ptr_offset.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-permissive-provenance use std::{mem, ptr}; fn main() { diff --git a/tests/pass/stacked-borrows/2phase.rs b/tests/pass/stacked-borrows/2phase.rs index 345cb64ccf71..eb543d691e10 100644 --- a/tests/pass/stacked-borrows/2phase.rs +++ b/tests/pass/stacked-borrows/2phase.rs @@ -1,5 +1,3 @@ -// compile-flags: -Zmiri-tag-raw-pointers - trait S: Sized { fn tpb(&mut self, _s: Self) {} } diff --git a/tests/pass/stacked-borrows/interior_mutability.rs b/tests/pass/stacked-borrows/interior_mutability.rs index 9ee8af45aefe..79958ab5539d 100644 --- a/tests/pass/stacked-borrows/interior_mutability.rs +++ b/tests/pass/stacked-borrows/interior_mutability.rs @@ -1,4 +1,3 @@ -// compile-flags: -Zmiri-tag-raw-pointers use std::cell::{Cell, RefCell, UnsafeCell}; use std::mem::{self, MaybeUninit}; diff --git a/tests/pass/stacked-borrows/stacked-borrows.rs b/tests/pass/stacked-borrows/stacked-borrows.rs index 131783ef4fb5..eb0ff167eb12 100644 --- a/tests/pass/stacked-borrows/stacked-borrows.rs +++ b/tests/pass/stacked-borrows/stacked-borrows.rs @@ -1,4 +1,3 @@ -// compile-flags: -Zmiri-tag-raw-pointers use std::ptr; // Test various stacked-borrows-related things. diff --git a/tests/pass/zst.rs b/tests/pass/zst.rs index 3a853e7d8a68..fade1e0dad88 100644 --- a/tests/pass/zst.rs +++ b/tests/pass/zst.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-permissive-provenance #[derive(PartialEq, Debug)] struct A; From 294ef15adbf6b4778a8eb638b31a48744914ec0a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jun 2022 21:26:14 -0400 Subject: [PATCH 3365/5092] more int2ptr cast tests, and fix casting of addresses inside dead allocations --- src/intptrcast.rs | 12 +++++++-- tests/fail/backtrace/bad-backtrace-flags.rs | 2 +- .../fail/backtrace/bad-backtrace-flags.stderr | 21 +++------------ tests/fail/backtrace/bad-backtrace-ptr.rs | 2 +- tests/fail/backtrace/bad-backtrace-ptr.stderr | 21 +++------------ .../backtrace/bad-backtrace-resolve-flags.rs | 2 +- .../bad-backtrace-resolve-flags.stderr | 17 +----------- .../bad-backtrace-resolve-names-flags.rs | 4 +-- .../bad-backtrace-resolve-names-flags.stderr | 21 +++------------ .../thread_local_static_dealloc.rs | 7 +++-- .../thread_local_static_dealloc.stderr | 21 +++------------ .../dangling_pointers/deref-invalid-ptr.rs | 2 +- .../deref-invalid-ptr.stderr | 17 +----------- .../storage_dead_dangling.rs | 6 ++--- .../storage_dead_dangling.stderr | 26 +++--------------- .../dangling_pointers/wild_pointer_deref.rs | 2 ++ .../wild_pointer_deref.stderr | 17 +----------- tests/fail/intrinsics/ptr_offset_0_plus_0.rs | 1 + .../intrinsics/ptr_offset_0_plus_0.stderr | 17 +----------- .../intrinsics/ptr_offset_int_plus_int.rs | 1 + .../intrinsics/ptr_offset_int_plus_int.stderr | 17 +----------- .../intrinsics/ptr_offset_int_plus_ptr.rs | 1 + .../intrinsics/ptr_offset_int_plus_ptr.stderr | 17 +----------- .../permissive_provenance_transmute.stderr | 20 -------------- ...e_transmute.rs => provenance_transmute.rs} | 0 ...ute.stderr => provenance_transmute.stderr} | 8 +++--- .../fail/provenance/strict_provenance_cast.rs | 6 +++++ .../provenance/strict_provenance_cast.stderr | 14 ++++++++++ .../provenance/strict_provenance_transmute.rs | 27 ------------------- tests/fail/stacked_borrows/unescaped_local.rs | 2 ++ .../stacked_borrows/unescaped_local.stderr | 17 +----------- .../intptrcast_alignment_check.rs | 2 +- .../intptrcast_alignment_check.stderr | 17 +----------- tests/fail/validity/cast_fn_ptr1.rs | 2 ++ tests/fail/validity/cast_fn_ptr1.stderr | 17 +----------- tests/fail/validity/cast_fn_ptr2.rs | 2 ++ tests/fail/validity/cast_fn_ptr2.stderr | 22 +-------------- tests/pass/adjacent-allocs.rs | 27 +++++++++++++++++-- tests/pass/align.rs | 2 ++ tests/pass/align.stderr | 20 -------------- tests/pass/intptrcast.rs | 11 ++++++++ 41 files changed, 123 insertions(+), 347 deletions(-) delete mode 100644 tests/fail/provenance/permissive_provenance_transmute.stderr rename tests/fail/provenance/{permissive_provenance_transmute.rs => provenance_transmute.rs} (100%) rename tests/fail/provenance/{strict_provenance_transmute.stderr => provenance_transmute.stderr} (75%) create mode 100644 tests/fail/provenance/strict_provenance_cast.rs create mode 100644 tests/fail/provenance/strict_provenance_cast.stderr delete mode 100644 tests/fail/provenance/strict_provenance_transmute.rs delete mode 100644 tests/pass/align.stderr diff --git a/src/intptrcast.rs b/src/intptrcast.rs index c92954a218ca..cb0d6517b942 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -90,8 +90,16 @@ impl<'mir, 'tcx> GlobalStateInner { } }?; - // We only use this provenance if it has been exposed. - if global_state.exposed.contains(&alloc_id) { Some(alloc_id) } else { None } + // We only use this provenance if it has been exposed, *and* is still live. + if global_state.exposed.contains(&alloc_id) { + // FIXME: this catches `InterpError`, which we should not usually do. + // We might need a proper fallible API from `memory.rs` to avoid this though. + if let Ok(_) = ecx.get_alloc_size_and_align(alloc_id, AllocCheck::Live) { + return Some(alloc_id); + } + } + + None } pub fn expose_ptr(ecx: &mut MiriEvalContext<'mir, 'tcx>, alloc_id: AllocId, sb: SbTag) { diff --git a/tests/fail/backtrace/bad-backtrace-flags.rs b/tests/fail/backtrace/bad-backtrace-flags.rs index 5f30513e931e..9e24d32a3331 100644 --- a/tests/fail/backtrace/bad-backtrace-flags.rs +++ b/tests/fail/backtrace/bad-backtrace-flags.rs @@ -4,6 +4,6 @@ extern "Rust" { fn main() { unsafe { - miri_get_backtrace(2, 0 as *mut _); //~ ERROR unsupported operation: unknown `miri_get_backtrace` flags 2 + miri_get_backtrace(2, std::ptr::null_mut()); //~ ERROR unsupported operation: unknown `miri_get_backtrace` flags 2 } } diff --git a/tests/fail/backtrace/bad-backtrace-flags.stderr b/tests/fail/backtrace/bad-backtrace-flags.stderr index ba16335fce3a..6d62ffc00e51 100644 --- a/tests/fail/backtrace/bad-backtrace-flags.stderr +++ b/tests/fail/backtrace/bad-backtrace-flags.stderr @@ -1,23 +1,8 @@ -warning: pointer-to-integer cast - --> $DIR/bad-backtrace-flags.rs:LL:CC - | -LL | miri_get_backtrace(2, 0 as *mut _); - | ^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `main` at $DIR/bad-backtrace-flags.rs:LL:CC - error: unsupported operation: unknown `miri_get_backtrace` flags 2 --> $DIR/bad-backtrace-flags.rs:LL:CC | -LL | miri_get_backtrace(2, 0 as *mut _); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_get_backtrace` flags 2 +LL | miri_get_backtrace(2, std::ptr::null_mut()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_get_backtrace` flags 2 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support @@ -25,5 +10,5 @@ LL | miri_get_backtrace(2, 0 as *mut _); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/backtrace/bad-backtrace-ptr.rs b/tests/fail/backtrace/bad-backtrace-ptr.rs index c83bf1eb382e..73d3561445d5 100644 --- a/tests/fail/backtrace/bad-backtrace-ptr.rs +++ b/tests/fail/backtrace/bad-backtrace-ptr.rs @@ -4,6 +4,6 @@ extern "Rust" { fn main() { unsafe { - miri_resolve_frame(0 as *mut _, 0); //~ ERROR null pointer is not a valid pointer for this operation + miri_resolve_frame(std::ptr::null_mut(), 0); //~ ERROR null pointer is not a valid pointer for this operation } } diff --git a/tests/fail/backtrace/bad-backtrace-ptr.stderr b/tests/fail/backtrace/bad-backtrace-ptr.stderr index 75268b667142..6911db9de02f 100644 --- a/tests/fail/backtrace/bad-backtrace-ptr.stderr +++ b/tests/fail/backtrace/bad-backtrace-ptr.stderr @@ -1,23 +1,8 @@ -warning: pointer-to-integer cast - --> $DIR/bad-backtrace-ptr.rs:LL:CC - | -LL | miri_resolve_frame(0 as *mut _, 0); - | ^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `main` at $DIR/bad-backtrace-ptr.rs:LL:CC - error: Undefined Behavior: null pointer is not a valid pointer for this operation --> $DIR/bad-backtrace-ptr.rs:LL:CC | -LL | miri_resolve_frame(0 as *mut _, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ null pointer is not a valid pointer for this operation +LL | miri_resolve_frame(std::ptr::null_mut(), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ null pointer is not a valid pointer for this operation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information @@ -26,5 +11,5 @@ LL | miri_resolve_frame(0 as *mut _, 0); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/backtrace/bad-backtrace-resolve-flags.rs b/tests/fail/backtrace/bad-backtrace-resolve-flags.rs index 5a30253a893b..2d4d6195029d 100644 --- a/tests/fail/backtrace/bad-backtrace-resolve-flags.rs +++ b/tests/fail/backtrace/bad-backtrace-resolve-flags.rs @@ -15,7 +15,7 @@ extern "Rust" { fn main() { unsafe { - let mut buf = vec![0 as *mut _; miri_backtrace_size(0)]; + let mut buf = vec![std::ptr::null_mut(); miri_backtrace_size(0)]; miri_get_backtrace(1, buf.as_mut_ptr()); diff --git a/tests/fail/backtrace/bad-backtrace-resolve-flags.stderr b/tests/fail/backtrace/bad-backtrace-resolve-flags.stderr index fad9ffe11920..49495651dfec 100644 --- a/tests/fail/backtrace/bad-backtrace-resolve-flags.stderr +++ b/tests/fail/backtrace/bad-backtrace-resolve-flags.stderr @@ -1,18 +1,3 @@ -warning: pointer-to-integer cast - --> $DIR/bad-backtrace-resolve-flags.rs:LL:CC - | -LL | let mut buf = vec![0 as *mut _; miri_backtrace_size(0)]; - | ^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `main` at $DIR/bad-backtrace-resolve-flags.rs:LL:CC - error: unsupported operation: unknown `miri_resolve_frame` flags 2 --> $DIR/bad-backtrace-resolve-flags.rs:LL:CC | @@ -25,5 +10,5 @@ LL | miri_resolve_frame(buf[0], 2); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/backtrace/bad-backtrace-resolve-names-flags.rs b/tests/fail/backtrace/bad-backtrace-resolve-names-flags.rs index 8e69a275753f..6cea1fec1b24 100644 --- a/tests/fail/backtrace/bad-backtrace-resolve-names-flags.rs +++ b/tests/fail/backtrace/bad-backtrace-resolve-names-flags.rs @@ -6,11 +6,11 @@ extern "Rust" { fn main() { unsafe { - let mut buf = vec![0 as *mut _; miri_backtrace_size(0)]; + let mut buf = vec![std::ptr::null_mut(); miri_backtrace_size(0)]; miri_get_backtrace(1, buf.as_mut_ptr()); // miri_resolve_frame_names will error from an invalid backtrace before it will from invalid flags - miri_resolve_frame_names(buf[0], 2, 0 as *mut _, 0 as *mut _); //~ ERROR unsupported operation: unknown `miri_resolve_frame_names` flags 2 + miri_resolve_frame_names(buf[0], 2, std::ptr::null_mut(), std::ptr::null_mut()); //~ ERROR unsupported operation: unknown `miri_resolve_frame_names` flags 2 } } diff --git a/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr b/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr index 18b03df21c6f..aa470cb9de05 100644 --- a/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr +++ b/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr @@ -1,23 +1,8 @@ -warning: pointer-to-integer cast - --> $DIR/bad-backtrace-resolve-names-flags.rs:LL:CC - | -LL | let mut buf = vec![0 as *mut _; miri_backtrace_size(0)]; - | ^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `main` at $DIR/bad-backtrace-resolve-names-flags.rs:LL:CC - error: unsupported operation: unknown `miri_resolve_frame_names` flags 2 --> $DIR/bad-backtrace-resolve-names-flags.rs:LL:CC | -LL | ... miri_resolve_frame_names(buf[0], 2, 0 as *mut _, 0 as *mut _); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_resolve_frame_names` flags 2 +LL | ... miri_resolve_frame_names(buf[0], 2, std::ptr::null_mut(), std::ptr::null_mut()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_resolve_frame_names` flags 2 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support @@ -25,5 +10,5 @@ LL | ... miri_resolve_frame_names(buf[0], 2, 0 as *mut _, 0 as *mut _); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/concurrency/thread_local_static_dealloc.rs b/tests/fail/concurrency/thread_local_static_dealloc.rs index d5a4bf27f897..e6031b5e4c0c 100644 --- a/tests/fail/concurrency/thread_local_static_dealloc.rs +++ b/tests/fail/concurrency/thread_local_static_dealloc.rs @@ -7,9 +7,12 @@ #[thread_local] static mut TLS: u8 = 0; +struct SendRaw(*const u8); +unsafe impl Send for SendRaw {} + fn main() { unsafe { - let dangling_ptr = std::thread::spawn(|| &TLS as *const u8 as usize).join().unwrap(); - let _val = *(dangling_ptr as *const u8); //~ ERROR dereferenced after this allocation got freed + let dangling_ptr = std::thread::spawn(|| SendRaw(&TLS as *const u8)).join().unwrap(); + let _val = *dangling_ptr.0; //~ ERROR dereferenced after this allocation got freed } } diff --git a/tests/fail/concurrency/thread_local_static_dealloc.stderr b/tests/fail/concurrency/thread_local_static_dealloc.stderr index 31a64eec3685..d54c569de36e 100644 --- a/tests/fail/concurrency/thread_local_static_dealloc.stderr +++ b/tests/fail/concurrency/thread_local_static_dealloc.stderr @@ -1,23 +1,8 @@ -warning: pointer-to-integer cast - --> $DIR/thread_local_static_dealloc.rs:LL:CC - | -LL | let _val = *(dangling_ptr as *const u8); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `main` at $DIR/thread_local_static_dealloc.rs:LL:CC - error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed --> $DIR/thread_local_static_dealloc.rs:LL:CC | -LL | let _val = *(dangling_ptr as *const u8); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed +LL | let _val = *dangling_ptr.0; + | ^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information @@ -26,5 +11,5 @@ LL | let _val = *(dangling_ptr as *const u8); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/dangling_pointers/deref-invalid-ptr.rs b/tests/fail/dangling_pointers/deref-invalid-ptr.rs index 56830e97caa3..cb2bbec8bcf0 100644 --- a/tests/fail/dangling_pointers/deref-invalid-ptr.rs +++ b/tests/fail/dangling_pointers/deref-invalid-ptr.rs @@ -1,5 +1,5 @@ // This should fail even without validation. -// compile-flags: -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation -Zmiri-permissive-provenance fn main() { let x = 16usize as *const u32; diff --git a/tests/fail/dangling_pointers/deref-invalid-ptr.stderr b/tests/fail/dangling_pointers/deref-invalid-ptr.stderr index ffd7fb1980dc..f4361d9fefa9 100644 --- a/tests/fail/dangling_pointers/deref-invalid-ptr.stderr +++ b/tests/fail/dangling_pointers/deref-invalid-ptr.stderr @@ -1,18 +1,3 @@ -warning: pointer-to-integer cast - --> $DIR/deref-invalid-ptr.rs:LL:CC - | -LL | let x = 16usize as *const u32; - | ^^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `main` at $DIR/deref-invalid-ptr.rs:LL:CC - error: Undefined Behavior: dereferencing pointer failed: 0x10 is not a valid pointer --> $DIR/deref-invalid-ptr.rs:LL:CC | @@ -26,5 +11,5 @@ LL | let _y = unsafe { &*x as *const u32 }; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/dangling_pointers/storage_dead_dangling.rs b/tests/fail/dangling_pointers/storage_dead_dangling.rs index c87db4b0225a..370162142de9 100644 --- a/tests/fail/dangling_pointers/storage_dead_dangling.rs +++ b/tests/fail/dangling_pointers/storage_dead_dangling.rs @@ -1,5 +1,5 @@ // This should fail even without validation, but some MIR opts mask the error -// compile-flags: -Zmiri-disable-validation -Zmir-opt-level=0 +// compile-flags: -Zmiri-disable-validation -Zmir-opt-level=0 -Zmiri-permissive-provenance static mut LEAK: usize = 0; @@ -10,7 +10,7 @@ fn fill(v: &mut i32) { } fn evil() { - unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR dereferenced after this allocation got freed + unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR is not a valid pointer } fn main() { @@ -21,6 +21,6 @@ fn main() { _y = x; } // Now we use a pointer to `x` which is no longer in scope, and thus dead (even though the - // `main` stack frame still exists). + // `main` stack frame still exists). We even try going through a `usize` for extra sneakiness! evil(); } diff --git a/tests/fail/dangling_pointers/storage_dead_dangling.stderr b/tests/fail/dangling_pointers/storage_dead_dangling.stderr index 3a94a7fa58ee..d6030643bfaa 100644 --- a/tests/fail/dangling_pointers/storage_dead_dangling.stderr +++ b/tests/fail/dangling_pointers/storage_dead_dangling.stderr @@ -1,28 +1,8 @@ -warning: pointer-to-integer cast +error: Undefined Behavior: dereferencing pointer failed: $HEX is not a valid pointer --> $DIR/storage_dead_dangling.rs:LL:CC | LL | unsafe { &mut *(LEAK as *mut i32) }; - | ^^^^^^^^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `evil` at $DIR/storage_dead_dangling.rs:LL:CC -note: inside `main` at $DIR/storage_dead_dangling.rs:LL:CC - --> $DIR/storage_dead_dangling.rs:LL:CC - | -LL | evil(); - | ^^^^^^ - -error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed - --> $DIR/storage_dead_dangling.rs:LL:CC - | -LL | unsafe { &mut *(LEAK as *mut i32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed + | ^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: $HEX is not a valid pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information @@ -36,5 +16,5 @@ LL | evil(); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/dangling_pointers/wild_pointer_deref.rs b/tests/fail/dangling_pointers/wild_pointer_deref.rs index eebaea48ba67..7c9f5281fbbb 100644 --- a/tests/fail/dangling_pointers/wild_pointer_deref.rs +++ b/tests/fail/dangling_pointers/wild_pointer_deref.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-permissive-provenance + fn main() { let p = 44 as *const i32; let x = unsafe { *p }; //~ ERROR is not a valid pointer diff --git a/tests/fail/dangling_pointers/wild_pointer_deref.stderr b/tests/fail/dangling_pointers/wild_pointer_deref.stderr index 960f9c9ce3e9..b20f310da083 100644 --- a/tests/fail/dangling_pointers/wild_pointer_deref.stderr +++ b/tests/fail/dangling_pointers/wild_pointer_deref.stderr @@ -1,18 +1,3 @@ -warning: pointer-to-integer cast - --> $DIR/wild_pointer_deref.rs:LL:CC - | -LL | let p = 44 as *const i32; - | ^^^^^^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `main` at $DIR/wild_pointer_deref.rs:LL:CC - error: Undefined Behavior: dereferencing pointer failed: 0x2c is not a valid pointer --> $DIR/wild_pointer_deref.rs:LL:CC | @@ -26,5 +11,5 @@ LL | let x = unsafe { *p }; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/intrinsics/ptr_offset_0_plus_0.rs b/tests/fail/intrinsics/ptr_offset_0_plus_0.rs index 248d85d65e24..ca38f39d2515 100644 --- a/tests/fail/intrinsics/ptr_offset_0_plus_0.rs +++ b/tests/fail/intrinsics/ptr_offset_0_plus_0.rs @@ -1,4 +1,5 @@ // error-pattern: pointer arithmetic failed: null pointer is not a valid pointer +// compile-flags: -Zmiri-permissive-provenance fn main() { let x = 0 as *mut i32; diff --git a/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr b/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr index 2474820545d2..741314ea8a68 100644 --- a/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr +++ b/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr @@ -1,18 +1,3 @@ -warning: pointer-to-integer cast - --> $DIR/ptr_offset_0_plus_0.rs:LL:CC - | -LL | let x = 0 as *mut i32; - | ^^^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `main` at $DIR/ptr_offset_0_plus_0.rs:LL:CC - error: Undefined Behavior: pointer arithmetic failed: null pointer is not a valid pointer --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC | @@ -31,5 +16,5 @@ LL | let _x = unsafe { x.offset(0) }; // UB despite offset 0, NULL is never note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_int.rs b/tests/fail/intrinsics/ptr_offset_int_plus_int.rs index e332a9dc624a..809938d99973 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_int.rs +++ b/tests/fail/intrinsics/ptr_offset_int_plus_int.rs @@ -1,4 +1,5 @@ // error-pattern: is not a valid pointer +// compile-flags: -Zmiri-permissive-provenance fn main() { // Can't offset an integer pointer by non-zero offset. diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr b/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr index f5cbd4bbbf73..e6b8f102f394 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr +++ b/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr @@ -1,18 +1,3 @@ -warning: pointer-to-integer cast - --> $DIR/ptr_offset_int_plus_int.rs:LL:CC - | -LL | let _val = (1 as *mut u8).offset(1); - | ^^^^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `main` at $DIR/ptr_offset_int_plus_int.rs:LL:CC - error: Undefined Behavior: pointer arithmetic failed: 0x1 is not a valid pointer --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC | @@ -31,5 +16,5 @@ LL | let _val = (1 as *mut u8).offset(1); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs index 2d27e25a7af1..903f89ff70ec 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs +++ b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs @@ -1,4 +1,5 @@ // error-pattern: is not a valid pointer +// compile-flags: -Zmiri-permissive-provenance fn main() { let ptr = Box::into_raw(Box::new(0u32)); diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr index 577a377f076e..f88ad758d438 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr +++ b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr @@ -1,18 +1,3 @@ -warning: pointer-to-integer cast - --> $DIR/ptr_offset_int_plus_ptr.rs:LL:CC - | -LL | let _val = (1 as *mut u8).offset(ptr as isize); - | ^^^^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `main` at $DIR/ptr_offset_int_plus_ptr.rs:LL:CC - error: Undefined Behavior: pointer arithmetic failed: 0x1 is not a valid pointer --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC | @@ -31,5 +16,5 @@ LL | let _val = (1 as *mut u8).offset(ptr as isize); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/provenance/permissive_provenance_transmute.stderr b/tests/fail/provenance/permissive_provenance_transmute.stderr deleted file mode 100644 index 12f3562011a8..000000000000 --- a/tests/fail/provenance/permissive_provenance_transmute.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: Undefined Behavior: dereferencing pointer failed: $HEX is not a valid pointer - --> $DIR/permissive_provenance_transmute.rs:LL:CC - | -LL | let _val = *left_ptr; - | ^^^^^^^^^ dereferencing pointer failed: $HEX is not a valid pointer - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `deref` at $DIR/permissive_provenance_transmute.rs:LL:CC -note: inside `main` at $DIR/permissive_provenance_transmute.rs:LL:CC - --> $DIR/permissive_provenance_transmute.rs:LL:CC - | -LL | deref(ptr1, ptr2.with_addr(ptr1.addr())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/provenance/permissive_provenance_transmute.rs b/tests/fail/provenance/provenance_transmute.rs similarity index 100% rename from tests/fail/provenance/permissive_provenance_transmute.rs rename to tests/fail/provenance/provenance_transmute.rs diff --git a/tests/fail/provenance/strict_provenance_transmute.stderr b/tests/fail/provenance/provenance_transmute.stderr similarity index 75% rename from tests/fail/provenance/strict_provenance_transmute.stderr rename to tests/fail/provenance/provenance_transmute.stderr index 8df94d50bbac..9cbec077e42c 100644 --- a/tests/fail/provenance/strict_provenance_transmute.stderr +++ b/tests/fail/provenance/provenance_transmute.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: dereferencing pointer failed: $HEX is not a valid pointer - --> $DIR/strict_provenance_transmute.rs:LL:CC + --> $DIR/provenance_transmute.rs:LL:CC | LL | let _val = *left_ptr; | ^^^^^^^^^ dereferencing pointer failed: $HEX is not a valid pointer @@ -7,9 +7,9 @@ LL | let _val = *left_ptr; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `deref` at $DIR/strict_provenance_transmute.rs:LL:CC -note: inside `main` at $DIR/strict_provenance_transmute.rs:LL:CC - --> $DIR/strict_provenance_transmute.rs:LL:CC + = note: inside `deref` at $DIR/provenance_transmute.rs:LL:CC +note: inside `main` at $DIR/provenance_transmute.rs:LL:CC + --> $DIR/provenance_transmute.rs:LL:CC | LL | deref(ptr1, ptr2.with_addr(ptr1.addr())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/fail/provenance/strict_provenance_cast.rs b/tests/fail/provenance/strict_provenance_cast.rs new file mode 100644 index 000000000000..8b2b053bdb59 --- /dev/null +++ b/tests/fail/provenance/strict_provenance_cast.rs @@ -0,0 +1,6 @@ +// compile-flags: -Zmiri-strict-provenance + +fn main() { + let addr = &0 as *const i32 as usize; + let _ptr = addr as *const i32; //~ ERROR integer-to-pointer casts and `from_exposed_addr` are not supported +} diff --git a/tests/fail/provenance/strict_provenance_cast.stderr b/tests/fail/provenance/strict_provenance_cast.stderr new file mode 100644 index 000000000000..32a39b81d9d7 --- /dev/null +++ b/tests/fail/provenance/strict_provenance_cast.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: integer-to-pointer casts and `from_exposed_addr` are not supported with `-Zmiri-strict-provenance`; use `with_addr` instead + --> $DIR/strict_provenance_cast.rs:LL:CC + | +LL | let _ptr = addr as *const i32; + | ^^^^^^^^^^^^^^^^^^ integer-to-pointer casts and `from_exposed_addr` are not supported with `-Zmiri-strict-provenance`; use `with_addr` instead + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/strict_provenance_cast.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/provenance/strict_provenance_transmute.rs b/tests/fail/provenance/strict_provenance_transmute.rs deleted file mode 100644 index 12a141e9ddfe..000000000000 --- a/tests/fail/provenance/strict_provenance_transmute.rs +++ /dev/null @@ -1,27 +0,0 @@ -// compile-flags: -Zmiri-strict-provenance -#![feature(strict_provenance)] - -use std::mem; - -// This is the example from -// . - -unsafe fn deref(left: *const u8, right: *const u8) { - let left_int: usize = mem::transmute(left); - let right_int: usize = mem::transmute(right); - if left_int == right_int { - // The compiler is allowed to replace `left_int` by `right_int` here... - let left_ptr: *const u8 = mem::transmute(left_int); - // ...which however means here it could be dereferencing the wrong pointer. - let _val = *left_ptr; //~ERROR dereferencing pointer failed - } -} - -fn main() { - let ptr1 = &0u8 as *const u8; - let ptr2 = &1u8 as *const u8; - unsafe { - // Two pointers with the same address but different provenance. - deref(ptr1, ptr2.with_addr(ptr1.addr())); - } -} diff --git a/tests/fail/stacked_borrows/unescaped_local.rs b/tests/fail/stacked_borrows/unescaped_local.rs index bfc937bb12b7..c994f6c3818a 100644 --- a/tests/fail/stacked_borrows/unescaped_local.rs +++ b/tests/fail/stacked_borrows/unescaped_local.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-permissive-provenance + // Make sure we cannot use raw ptrs to access a local that // we took the direct address of. fn main() { diff --git a/tests/fail/stacked_borrows/unescaped_local.stderr b/tests/fail/stacked_borrows/unescaped_local.stderr index 2f6605c058b2..464296651c5e 100644 --- a/tests/fail/stacked_borrows/unescaped_local.stderr +++ b/tests/fail/stacked_borrows/unescaped_local.stderr @@ -1,18 +1,3 @@ -warning: pointer-to-integer cast - --> $DIR/unescaped_local.rs:LL:CC - | -LL | let raw = &mut x as *mut i32 as usize as *mut i32; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `main` at $DIR/unescaped_local.rs:LL:CC - error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but no exposed tags have suitable permission in the borrow stack for this location --> $DIR/unescaped_local.rs:LL:CC | @@ -29,5 +14,5 @@ LL | *raw = 13; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs b/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs index 0a326a453e9a..dea9335ab751 100644 --- a/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs +++ b/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-symbolic-alignment-check +// compile-flags: -Zmiri-symbolic-alignment-check -Zmiri-permissive-provenance // With the symbolic alignment check, even with intptrcast and without // validation, we want to be *sure* to catch bugs that arise from pointers being // insufficiently aligned. The only way to achieve that is not not let programs diff --git a/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr b/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr index bd8d161de832..347486187e1b 100644 --- a/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr +++ b/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr @@ -1,18 +1,3 @@ -warning: pointer-to-integer cast - --> $DIR/intptrcast_alignment_check.rs:LL:CC - | -LL | let u16_ptr = base_addr_aligned as *mut u16; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `main` at $DIR/intptrcast_alignment_check.rs:LL:CC - error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required --> $DIR/intptrcast_alignment_check.rs:LL:CC | @@ -26,5 +11,5 @@ LL | unsafe { *u16_ptr = 2 }; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/validity/cast_fn_ptr1.rs b/tests/fail/validity/cast_fn_ptr1.rs index 020e7be34f70..eb5774fe7995 100644 --- a/tests/fail/validity/cast_fn_ptr1.rs +++ b/tests/fail/validity/cast_fn_ptr1.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-permissive-provenance + fn main() { // Cast a function pointer such that on a call, the argument gets transmuted // from raw ptr to reference. This is ABI-compatible, so it's not the call that diff --git a/tests/fail/validity/cast_fn_ptr1.stderr b/tests/fail/validity/cast_fn_ptr1.stderr index d75857900052..d048377a7793 100644 --- a/tests/fail/validity/cast_fn_ptr1.stderr +++ b/tests/fail/validity/cast_fn_ptr1.stderr @@ -1,18 +1,3 @@ -warning: pointer-to-integer cast - --> $DIR/cast_fn_ptr1.rs:LL:CC - | -LL | g(0usize as *const i32) - | ^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `main` at $DIR/cast_fn_ptr1.rs:LL:CC - error: Undefined Behavior: type validation failed: encountered a null reference --> $DIR/cast_fn_ptr1.rs:LL:CC | @@ -26,5 +11,5 @@ LL | g(0usize as *const i32) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/validity/cast_fn_ptr2.rs b/tests/fail/validity/cast_fn_ptr2.rs index 10fc39f56fae..1cf4ca7d19d8 100644 --- a/tests/fail/validity/cast_fn_ptr2.rs +++ b/tests/fail/validity/cast_fn_ptr2.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-permissive-provenance + fn main() { // Cast a function pointer such that when returning, the return value gets transmuted // from raw ptr to reference. This is ABI-compatible, so it's not the call that diff --git a/tests/fail/validity/cast_fn_ptr2.stderr b/tests/fail/validity/cast_fn_ptr2.stderr index d47b39356ffc..10b9b9b8602b 100644 --- a/tests/fail/validity/cast_fn_ptr2.stderr +++ b/tests/fail/validity/cast_fn_ptr2.stderr @@ -1,23 +1,3 @@ -warning: pointer-to-integer cast - --> $DIR/cast_fn_ptr2.rs:LL:CC - | -LL | 0usize as *const i32 - | ^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `main::f` at $DIR/cast_fn_ptr2.rs:LL:CC -note: inside `main` at $DIR/cast_fn_ptr2.rs:LL:CC - --> $DIR/cast_fn_ptr2.rs:LL:CC - | -LL | let _x = g(); - | ^^^ - error: Undefined Behavior: type validation failed: encountered a null reference --> $DIR/cast_fn_ptr2.rs:LL:CC | @@ -31,5 +11,5 @@ LL | let _x = g(); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/pass/adjacent-allocs.rs b/tests/pass/adjacent-allocs.rs index 925430ae2030..b3483a5b4380 100644 --- a/tests/pass/adjacent-allocs.rs +++ b/tests/pass/adjacent-allocs.rs @@ -1,9 +1,9 @@ // compile-flags: -Zmiri-permissive-provenance -fn main() { +fn test1() { // The slack between allocations is random. // Loop a few times to hit the zero-slack case. - for _ in 0..1024 { + for _ in 0..512 { let n = 0u64; let ptr: *const u64 = &n; @@ -22,3 +22,26 @@ fn main() { unsafe { *zst } } } + +fn test2() { + fn foo() -> u64 { + 0 + } + + for _ in 0..512 { + let n = 0u64; + let ptr: *const u64 = &n; + foo(); + let iptr = ptr as usize; + unsafe { + let start = &*std::ptr::slice_from_raw_parts(iptr as *const (), 1); + let end = &*std::ptr::slice_from_raw_parts((iptr + 8) as *const (), 1); + assert_eq!(start.len(), end.len()); + } + } +} + +fn main() { + test1(); + test2(); +} diff --git a/tests/pass/align.rs b/tests/pass/align.rs index 5794b7f54276..f412541bde17 100644 --- a/tests/pass/align.rs +++ b/tests/pass/align.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-permissive-provenance + /// This manually makes sure that we have a pointer with the proper alignment. fn manual_alignment() { let x = &mut [0u8; 3]; diff --git a/tests/pass/align.stderr b/tests/pass/align.stderr deleted file mode 100644 index 9a15ec2cda6c..000000000000 --- a/tests/pass/align.stderr +++ /dev/null @@ -1,20 +0,0 @@ -warning: pointer-to-integer cast - --> $DIR/align.rs:LL:CC - | -LL | let u16_ptr = base_addr_aligned as *mut u16; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `manual_alignment` at $DIR/align.rs:LL:CC -note: inside `main` at $DIR/align.rs:LL:CC - --> $DIR/align.rs:LL:CC - | -LL | manual_alignment(); - | ^^^^^^^^^^^^^^^^^^ - diff --git a/tests/pass/intptrcast.rs b/tests/pass/intptrcast.rs index a5e1d196529e..2417a83493be 100644 --- a/tests/pass/intptrcast.rs +++ b/tests/pass/intptrcast.rs @@ -90,6 +90,16 @@ fn ptr_eq_integer() { assert!(x != 64 as *const i32); } +fn zst_deref_of_dangling() { + let b = Box::new(0); + let addr = &*b as *const _ as usize; + drop(b); + // Now if we cast `addr` to a ptr it might pick up the dangling provenance. + // But if we only do a ZST deref there is no UB here! + let zst = addr as *const (); + let _val = unsafe { *zst }; +} + fn main() { cast(); cast_dangling(); @@ -101,4 +111,5 @@ fn main() { ptr_eq_out_of_bounds(); ptr_eq_out_of_bounds_null(); ptr_eq_integer(); + zst_deref_of_dangling(); } From 5c16713056ceb866c89bb94c344285dee87d9d0d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jun 2022 22:01:03 -0400 Subject: [PATCH 3366/5092] remove support for untagged pointers good riddance! --- src/bin/miri.rs | 2 +- src/diagnostics.rs | 18 ---- src/eval.rs | 2 +- src/lib.rs | 2 +- src/machine.rs | 8 +- src/stacked_borrows.rs | 165 +++++++++-------------------- src/stacked_borrows/diagnostics.rs | 94 +++------------- 7 files changed, 74 insertions(+), 217 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 7bced912645d..a56b4bc6d1b4 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -409,7 +409,7 @@ fn main() { err ), }; - for id in ids.into_iter().map(miri::PtrId::new) { + for id in ids.into_iter().map(miri::SbTag::new) { if let Some(id) = id { miri_config.tracked_pointer_tags.insert(id); } else { diff --git a/src/diagnostics.rs b/src/diagnostics.rs index d17d1e6ed4c8..8176e51338a5 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -178,24 +178,6 @@ pub fn report_error<'tcx, 'mir>( helps.push((Some(*protection_span), "this protector is live for this call".to_string())); } } - Some(TagHistory::Untagged{ recently_created, recently_invalidated, matching_created, protected }) => { - if let Some((range, span)) = recently_created { - let msg = format!("tag was most recently created at offsets {}", HexRange(*range)); - helps.push((Some(*span), msg)); - } - if let Some((range, span)) = recently_invalidated { - let msg = format!("tag was later invalidated at offsets {}", HexRange(*range)); - helps.push((Some(*span), msg)); - } - if let Some((range, span)) = matching_created { - let msg = format!("this tag was also created here at offsets {}", HexRange(*range)); - helps.push((Some(*span), msg)); - } - if let Some((protecting_tag, protecting_tag_span, protection_span)) = protected { - helps.push((Some(*protecting_tag_span), format!("{:?} was protected due to a tag which was created here", protecting_tag))); - helps.push((Some(*protection_span), "this protector is live for this call".to_string())); - } - } None => {} } helps diff --git a/src/eval.rs b/src/eval.rs index fa252953fe6e..12f1f52c78a3 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -96,7 +96,7 @@ pub struct MiriConfig { /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`). pub seed: Option, /// The stacked borrows pointer ids to report about - pub tracked_pointer_tags: HashSet, + pub tracked_pointer_tags: HashSet, /// The stacked borrows call IDs to report about pub tracked_call_ids: HashSet, /// The allocation ids to report about. diff --git a/src/lib.rs b/src/lib.rs index 68489c9b47b9..1633667fcad8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -89,7 +89,7 @@ pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ - CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, SbTag, SbTagExtra, + CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag, SbTagExtra, Stack, Stacks, }; pub use crate::sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId}; diff --git a/src/machine.rs b/src/machine.rs index d6a65a2a44c8..5b1847545897 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -140,8 +140,9 @@ pub enum Tag { #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(Pointer, 24); +// FIXME: this would with in 24bytes but layout optimizations are not smart enough // #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -// static_assert_size!(Pointer>, 24); +//static_assert_size!(Pointer>, 24); #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(ScalarMaybeUninit, 32); @@ -680,9 +681,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } let absolute_addr = intptrcast::GlobalStateInner::rel_ptr_to_addr(ecx, ptr); let sb_tag = if let Some(stacked_borrows) = &ecx.machine.stacked_borrows { - stacked_borrows.borrow_mut().base_tag(ptr.provenance) + stacked_borrows.borrow_mut().base_ptr_tag(ptr.provenance) } else { - SbTag::Untagged + // Value does not matter, SB is disabled + SbTag::default() }; Pointer::new( Tag::Concrete { alloc_id: ptr.provenance, sb: sb_tag }, diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 23408027626c..e79116a28ecf 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -23,42 +23,29 @@ use crate::*; pub mod diagnostics; use diagnostics::{AllocHistory, TagHistory}; -pub type PtrId = NonZeroU64; pub type CallId = NonZeroU64; + // Even reading memory can have effects on the stack, so we need a `RefCell` here. pub type AllocExtra = RefCell; /// Tracking pointer provenance -#[derive(Copy, Clone, Hash, Eq)] -pub enum SbTag { - Tagged(PtrId), - Untagged, -} +#[derive(Copy, Clone, Hash, PartialEq, Eq)] +pub struct SbTag(NonZeroU64); impl SbTag { - fn as_u64(self) -> u64 { - match self { - SbTag::Tagged(id) => id.get(), - SbTag::Untagged => 0, - } + pub fn new(i: u64) -> Option { + NonZeroU64::new(i).map(SbTag) } -} -impl PartialEq for SbTag { - fn eq(&self, other: &Self) -> bool { - // The codegen for the derived Partialeq is bad here and includes a branch. - // Since this code is extremely hot, this is optimized here. - // https://github.com/rust-lang/rust/issues/49892 - self.as_u64() == other.as_u64() + // The default to be used when SB is disabled + pub fn default() -> Self { + Self::new(1).unwrap() } } impl fmt::Debug for SbTag { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - SbTag::Tagged(id) => write!(f, "<{}>", id), - SbTag::Untagged => write!(f, ""), - } + write!(f, "<{}>", self.0) } } @@ -73,7 +60,7 @@ pub enum SbTagExtra { impl fmt::Debug for SbTagExtra { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - SbTagExtra::Concrete(tag) => write!(f, "{tag:?}"), + SbTagExtra::Concrete(pid) => write!(f, "{pid:?}"), SbTagExtra::Wildcard => write!(f, ""), } } @@ -82,7 +69,7 @@ impl fmt::Debug for SbTagExtra { impl SbTagExtra { fn and_then(self, f: impl FnOnce(SbTag) -> Option) -> Option { match self { - SbTagExtra::Concrete(tag) => f(tag), + SbTagExtra::Concrete(pid) => f(pid), SbTagExtra::Wildcard => None, } } @@ -130,15 +117,15 @@ pub struct Stack { /// Used *mostly* as a stack; never empty. /// Invariants: /// * Above a `SharedReadOnly` there can only be more `SharedReadOnly`. - /// * Except for `Untagged`, no tag occurs in the stack more than once. + /// * No tag occurs in the stack more than once. borrows: Vec, /// If this is `Some(id)`, then the actual current stack is unknown. This can happen when /// wildcard pointers are used to access this location. What we do know is that `borrows` are at - /// the top of the stack, and below it are arbitrarily many items whose `tag` is either - /// `Untagged` or strictly less than `id`. + /// the top of the stack, and below it are arbitrarily many items whose `tag` is strictly less + /// than `id`. /// When the bottom is unknown, `borrows` always has a `SharedReadOnly` or `Unique` at the bottom; /// we never have the unknown-to-known boundary in an SRW group. - unknown_bottom: Option, + unknown_bottom: Option, } /// Extra per-allocation state. @@ -156,21 +143,19 @@ pub struct Stacks { #[derive(Debug)] pub struct GlobalStateInner { /// Next unused pointer ID (tag). - next_ptr_id: PtrId, + next_ptr_tag: SbTag, /// Table storing the "base" tag for each allocation. /// The base tag is the one used for the initial pointer. /// We need this in a separate table to handle cyclic statics. - base_ptr_ids: FxHashMap, + base_ptr_tags: FxHashMap, /// Next unused call ID (for protectors). next_call_id: CallId, /// Those call IDs corresponding to functions that are still running. active_calls: FxHashSet, /// The pointer ids to trace - tracked_pointer_tags: HashSet, + tracked_pointer_tags: HashSet, /// The call ids to trace tracked_call_ids: HashSet, - /// Whether to track raw pointers. - tag_raw: bool, } /// We need interior mutable access to the global state. @@ -219,24 +204,23 @@ impl fmt::Display for RefKind { /// Utilities for initialization and ID generation impl GlobalStateInner { - pub fn new(tracked_pointer_tags: HashSet, tracked_call_ids: HashSet) -> Self { + pub fn new(tracked_pointer_tags: HashSet, tracked_call_ids: HashSet) -> Self { GlobalStateInner { - next_ptr_id: NonZeroU64::new(1).unwrap(), - base_ptr_ids: FxHashMap::default(), + next_ptr_tag: SbTag(NonZeroU64::new(1).unwrap()), + base_ptr_tags: FxHashMap::default(), next_call_id: NonZeroU64::new(1).unwrap(), active_calls: FxHashSet::default(), tracked_pointer_tags, tracked_call_ids, - tag_raw: true, } } - fn new_ptr(&mut self) -> PtrId { - let id = self.next_ptr_id; + fn new_ptr(&mut self) -> SbTag { + let id = self.next_ptr_tag; if self.tracked_pointer_tags.contains(&id) { - register_diagnostic(NonHaltingDiagnostic::CreatedPointerTag(id)); + register_diagnostic(NonHaltingDiagnostic::CreatedPointerTag(id.0)); } - self.next_ptr_id = NonZeroU64::new(id.get() + 1).unwrap(); + self.next_ptr_tag = SbTag(NonZeroU64::new(id.0.get() + 1).unwrap()); id } @@ -259,22 +243,14 @@ impl GlobalStateInner { self.active_calls.contains(&id) } - pub fn base_tag(&mut self, id: AllocId) -> SbTag { - self.base_ptr_ids.get(&id).copied().unwrap_or_else(|| { - let tag = SbTag::Tagged(self.new_ptr()); + pub fn base_ptr_tag(&mut self, id: AllocId) -> SbTag { + self.base_ptr_tags.get(&id).copied().unwrap_or_else(|| { + let tag = self.new_ptr(); trace!("New allocation {:?} has base tag {:?}", id, tag); - self.base_ptr_ids.try_insert(id, tag).unwrap(); + self.base_ptr_tags.try_insert(id, tag).unwrap(); tag }) } - - pub fn base_tag_untagged(&mut self, id: AllocId) -> SbTag { - trace!("New allocation {:?} has no base tag (untagged)", id); - let tag = SbTag::Untagged; - // This must only be done on new allocations. - self.base_ptr_ids.try_insert(id, tag).unwrap(); - tag - } } /// Error reporting @@ -364,10 +340,7 @@ impl<'tcx> Stack { // Couldn't find it in the stack; but if there is an unknown bottom it might be there. let found = self.unknown_bottom.is_some_and(|&unknown_limit| { - match tag { - SbTag::Tagged(tag_id) => tag_id < unknown_limit, // unknown_limit is an upper bound for what can be in the unknown bottom. - SbTag::Untagged => true, // yeah whatever - } + tag.0 < unknown_limit.0 // unknown_limit is an upper bound for what can be in the unknown bottom. }); if found { Ok(None) } else { Err(()) } } @@ -408,23 +381,22 @@ impl<'tcx> Stack { /// Within `provoking_access, the `AllocRange` refers the entire operation, and /// the `Size` refers to the specific location in the `AllocRange` that we are /// currently checking. - fn check_protector( + fn item_popped( item: &Item, provoking_access: Option<(SbTagExtra, AllocRange, Size, AccessKind)>, // just for debug printing and error messages global: &GlobalStateInner, alloc_history: &mut AllocHistory, ) -> InterpResult<'tcx> { - if let SbTag::Tagged(id) = item.tag { - if global.tracked_pointer_tags.contains(&id) { - register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag( - *item, - provoking_access.map(|(tag, _alloc_range, _size, access)| (tag, access)), - )); - } + if global.tracked_pointer_tags.contains(&item.tag) { + register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag( + *item, + provoking_access.map(|(tag, _alloc_range, _size, access)| (tag, access)), + )); } + if let Some(call) = item.protector { if global.is_active(call) { - if let Some((tag, alloc_range, offset, _access)) = provoking_access { + if let Some((tag, _alloc_range, _offset, _access)) = provoking_access { Err(err_sb_ub( format!( "not granting access to tag {:?} because incompatible item is protected: {:?}", @@ -434,8 +406,6 @@ impl<'tcx> Stack { tag.and_then(|tag| { alloc_history.get_logs_relevant_to( tag, - alloc_range, - offset, Some(item.tag), ) }), @@ -491,7 +461,7 @@ impl<'tcx> Stack { }; for item in self.borrows.drain(first_incompatible_idx..).rev() { trace!("access: popping item {:?}", item); - Stack::check_protector( + Stack::item_popped( &item, Some((tag, alloc_range, offset, access)), global, @@ -520,7 +490,7 @@ impl<'tcx> Stack { if item.perm == Permission::Unique { trace!("access: disabling item {:?}", item); - Stack::check_protector( + Stack::item_popped( item, Some((tag, alloc_range, offset, access)), global, @@ -540,21 +510,19 @@ impl<'tcx> Stack { for item in &self.borrows { // Skip disabled items, they cannot be matched anyway. if !matches!(item.perm, Permission::Disabled) { - if let SbTag::Tagged(tag) = item.tag { - // We are looking for a strict upper bound, so add 1 to this tag. - max = cmp::max(tag.checked_add(1).unwrap(), max); - } + // We are looking for a strict upper bound, so add 1 to this tag. + max = cmp::max(item.tag.0.checked_add(1).unwrap(), max); } } if let Some(unk) = self.unknown_bottom { - max = cmp::max(unk, max); + max = cmp::max(unk.0, max); } // Use `max` as new strict upper bound for everything. trace!( "access: forgetting stack to upper bound {max} due to wildcard or unknown access" ); self.borrows.clear(); - self.unknown_bottom = Some(max); + self.unknown_bottom = Some(SbTag(max)); } // Done. @@ -566,7 +534,7 @@ impl<'tcx> Stack { fn dealloc( &mut self, tag: SbTagExtra, - (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages + (alloc_id, _alloc_range, _offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &GlobalStateInner, alloc_history: &mut AllocHistory, exposed_tags: &FxHashSet, @@ -578,13 +546,13 @@ impl<'tcx> Stack { tag, alloc_id, ), None, - tag.and_then(|tag| alloc_history.get_logs_relevant_to(tag, alloc_range, offset, None)), + tag.and_then(|tag| alloc_history.get_logs_relevant_to(tag, None)), ) })?; // Step 2: Remove all items. Also checks for protectors. for item in self.borrows.drain(..).rev() { - Stack::check_protector(&item, None, global, alloc_history)?; + Stack::item_popped(&item, None, global, alloc_history)?; } Ok(()) } @@ -632,7 +600,7 @@ impl<'tcx> Stack { // (for all we know, it might join an SRW group inside the unknown). trace!("reborrow: forgetting stack entirely due to SharedReadWrite reborrow from wildcard or unknown"); self.borrows.clear(); - self.unknown_bottom = Some(global.next_ptr_id); + self.unknown_bottom = Some(global.next_ptr_tag); return Ok(()); }; @@ -726,30 +694,9 @@ impl Stacks { // not through a pointer). That is, whenever we directly write to a local, this will pop // everything else off the stack, invalidating all previous pointers, // and in particular, *all* raw pointers. - MemoryKind::Stack => (extra.base_tag(id), Permission::Unique), - // `Global` memory can be referenced by global pointers from `tcx`. - // Thus we call `global_base_ptr` such that the global pointers get the same tag - // as what we use here. - // `ExternStatic` is used for extern statics, so the same reasoning applies. - // The others are various forms of machine-managed special global memory, and we can get - // away with precise tracking there. - // The base pointer is not unique, so the base permission is `SharedReadWrite`. - MemoryKind::CallerLocation - | MemoryKind::Machine( - MiriMemoryKind::Global - | MiriMemoryKind::ExternStatic - | MiriMemoryKind::Tls - | MiriMemoryKind::Runtime - | MiriMemoryKind::Machine, - ) => (extra.base_tag(id), Permission::SharedReadWrite), - // Heap allocations we only track precisely when raw pointers are tagged, for now. - MemoryKind::Machine( - MiriMemoryKind::Rust | MiriMemoryKind::C | MiriMemoryKind::WinHeap, - ) => { - let tag = - if extra.tag_raw { extra.base_tag(id) } else { extra.base_tag_untagged(id) }; - (tag, Permission::SharedReadWrite) - } + MemoryKind::Stack => (extra.base_ptr_tag(id), Permission::Unique), + // Everything else is shared by default. + _ => (extra.base_ptr_tag(id), Permission::SharedReadWrite), }; let mut stacks = Stacks::new(size, perm, base_tag); stacks.history.log_creation( @@ -1039,15 +986,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Compute new borrow. - let new_tag = { - let mem_extra = this.machine.stacked_borrows.as_mut().unwrap().get_mut(); - match kind { - // Give up tracking for raw pointers. - RefKind::Raw { .. } if !mem_extra.tag_raw => SbTag::Untagged, - // All other pointers are properly tracked. - _ => SbTag::Tagged(mem_extra.new_ptr()), - } - }; + let new_tag = this.machine.stacked_borrows.as_mut().unwrap().get_mut().new_ptr(); // Reborrow. let alloc_id = this.reborrow(&place, size, kind, new_tag, protect)?; diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index a4a7f5e7a1e3..0a7edcdc89c1 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -32,7 +32,6 @@ struct Protection { #[derive(Clone, Debug)] struct Event { - time: usize, parent: Option, tag: SbTag, range: AllocRange, @@ -46,12 +45,6 @@ pub enum TagHistory { invalidated: Option<(AllocRange, SpanData)>, protected: Option<(SbTag, SpanData, SpanData)>, }, - Untagged { - recently_created: Option<(AllocRange, SpanData)>, - recently_invalidated: Option<(AllocRange, SpanData)>, - matching_created: Option<(AllocRange, SpanData)>, - protected: Option<(SbTag, SpanData, SpanData)>, - }, } impl AllocHistory { @@ -72,7 +65,7 @@ impl AllocHistory { current_span: &mut CurrentSpan<'_, '_, '_>, ) { let span = current_span.get(); - self.creations.push(Event { parent, tag, range, span, time: self.current_time }); + self.creations.push(Event { parent, tag, range, span }); self.current_time += 1; } @@ -83,7 +76,7 @@ impl AllocHistory { current_span: &mut CurrentSpan<'_, '_, '_>, ) { let span = current_span.get(); - self.invalidations.push(Event { parent: None, tag, range, span, time: self.current_time }); + self.invalidations.push(Event { parent: None, tag, range, span }); self.current_time += 1; } @@ -101,8 +94,6 @@ impl AllocHistory { pub fn get_logs_relevant_to( &self, tag: SbTag, - alloc_range: AllocRange, - offset: Size, protector_tag: Option, ) -> Option { let protected = protector_tag @@ -125,74 +116,17 @@ impl AllocHistory { }) }); - if let SbTag::Tagged(_) = tag { - let get_matching = |events: &[Event]| { - events.iter().rev().find_map(|event| { - if event.tag == tag { Some((event.range, event.span.data())) } else { None } - }) - }; - Some(TagHistory::Tagged { - tag, - created: get_matching(&self.creations)?, - invalidated: get_matching(&self.invalidations), - protected, + let get_matching = |events: &[Event]| { + events.iter().rev().find_map(|event| { + if event.tag == tag { Some((event.range, event.span.data())) } else { None } }) - } else { - let mut created_time = 0; - // Find the most recently created tag that satsfies this offset - let recently_created = self.creations.iter().rev().find_map(|event| { - if event.tag == tag && offset >= event.range.start && offset < event.range.end() { - created_time = event.time; - Some((event.range, event.span.data())) - } else { - None - } - }); - - // Find a different recently created tag that satisfies this whole operation, predates - // the recently created tag, and has a different span. - // We're trying to make a guess at which span the user wanted to provide the tag that - // they're using. - let matching_created = recently_created.and_then(|(_created_range, created_span)| { - self.creations.iter().rev().find_map(|event| { - if event.tag == tag - && alloc_range.start >= event.range.start - && alloc_range.end() <= event.range.end() - && event.span.data() != created_span - && event.time != created_time - { - Some((event.range, event.span.data())) - } else { - None - } - }) - }); - - // Find the most recent invalidation of this tag which post-dates the creation - let recently_invalidated = recently_created.and_then(|_| { - self.invalidations - .iter() - .rev() - .take_while(|event| event.time > created_time) - .find_map(|event| { - if event.tag == tag - && offset >= event.range.start - && offset < event.range.end() - { - Some((event.range, event.span.data())) - } else { - None - } - }) - }); - - Some(TagHistory::Untagged { - recently_created, - matching_created, - recently_invalidated, - protected, - }) - } + }; + Some(TagHistory::Tagged { + tag, + created: get_matching(&self.creations)?, + invalidated: get_matching(&self.invalidations), + protected, + }) } /// Report a descriptive error when `new` could not be granted from `derived_from`. @@ -215,7 +149,7 @@ impl AllocHistory { format!("{}{}", action, error_cause(stack, derived_from)), Some(operation_summary("a reborrow", alloc_id, alloc_range)), derived_from.and_then(|derived_from| { - self.get_logs_relevant_to(derived_from, alloc_range, error_offset, None) + self.get_logs_relevant_to(derived_from, None) }), ) } @@ -238,7 +172,7 @@ impl AllocHistory { err_sb_ub( format!("{}{}", action, error_cause(stack, tag)), Some(operation_summary("an access", alloc_id, alloc_range)), - tag.and_then(|tag| self.get_logs_relevant_to(tag, alloc_range, error_offset, None)), + tag.and_then(|tag| self.get_logs_relevant_to(tag, None)), ) } } From 4120425108855824356019cc3e7f6c2bfff157c1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jun 2022 22:07:02 -0400 Subject: [PATCH 3367/5092] readme: move some things around --- README.md | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index efdbf5143d9f..d7c50e9613fd 100644 --- a/README.md +++ b/README.md @@ -289,6 +289,11 @@ environment variable. We first document the most relevant and most commonly used `-Zmiri-disable-isolation` is set. * `-Zmiri-ignore-leaks` disables the memory leak checker, and also allows some remaining threads to exist when the main thread exits. +* `-Zmiri-permissive-provenance` disables the warning for integer-to-pointer casts and + [`ptr::from_exposed_addr`](https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html). + This will necessarily miss some bugs as those operations are not efficiently and accurately + implementable in a sanitizer, but it will only miss bugs that concern memory/pointers which is + subject to these operations. * `-Zmiri-preemption-rate` configures the probability that at the end of a basic block, the active thread will be preempted. The default is `0.01` (i.e., 1%). Setting this to `0` disables preemption. @@ -307,6 +312,16 @@ environment variable. We first document the most relevant and most commonly used provenance](https://github.com/rust-lang/rust/issues/95228) checking in Miri. This means that casting an integer to a pointer yields a result with 'invalid' provenance, i.e., with provenance that cannot be used for any memory access. +* `-Zmiri-symbolic-alignment-check` makes the alignment check more strict. By default, alignment is + checked by casting the pointer to an integer, and making sure that is a multiple of the alignment. + This can lead to cases where a program passes the alignment check by pure chance, because things + "happened to be" sufficiently aligned -- there is no UB in this execution but there would be UB in + others. To avoid such cases, the symbolic alignment check only takes into account the requested + alignment of the relevant allocation, and the offset into that allocation. This avoids missing + such bugs, but it also incurs some false positives when the code does manual integer arithmetic to + ensure alignment. (The standard library `align_to` method works fine in both modes; under + symbolic alignment it only fills the middle slice when the allocation guarantees sufficient + alignment.) The remaining flags are for advanced use only, and more likely to change or be removed. Some of these are **unsound**, which means they can lead @@ -354,23 +369,6 @@ to Miri failing to detect cases of undefined behavior in a program. application instead of raising an error within the context of Miri (and halting execution). Note that code might not expect these operations to ever panic, so this flag can lead to strange (mis)behavior. -* `-Zmiri-permissive-provenance` disables the warning for integer-to-pointer casts and - [`ptr::from_exposed_addr`](https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html). - This will necessarily miss some bugs as those operations are not efficiently and accurately - implementable in a sanitizer, but it will only miss bugs that concern memory/pointers which is - subject to these operations. -* `-Zmiri-symbolic-alignment-check` makes the alignment check more strict. By - default, alignment is checked by casting the pointer to an integer, and making - sure that is a multiple of the alignment. This can lead to cases where a - program passes the alignment check by pure chance, because things "happened to - be" sufficiently aligned -- there is no UB in this execution but there would - be UB in others. To avoid such cases, the symbolic alignment check only takes - into account the requested alignment of the relevant allocation, and the - offset into that allocation. This avoids missing such bugs, but it also - incurs some false positives when the code does manual integer arithmetic to - ensure alignment. (The standard library `align_to` method works fine in both - modes; under symbolic alignment it only fills the middle slice when the - allocation guarantees sufficient alignment.) * `-Zmiri-track-alloc-id=,,...` shows a backtrace when the given allocations are being allocated or freed. This helps in debugging memory leaks and use after free bugs. Specifying this argument multiple times does not overwrite the previous From 1a5dfbeb7a9c4289bb1e8903a8768603e673f128 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jun 2022 22:27:38 -0400 Subject: [PATCH 3368/5092] fmt --- src/intptrcast.rs | 2 +- src/lib.rs | 4 ++-- src/stacked_borrows.rs | 7 +------ src/stacked_borrows/diagnostics.rs | 4 +--- 4 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index cb0d6517b942..83739c48efc5 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -94,7 +94,7 @@ impl<'mir, 'tcx> GlobalStateInner { if global_state.exposed.contains(&alloc_id) { // FIXME: this catches `InterpError`, which we should not usually do. // We might need a proper fallible API from `memory.rs` to avoid this though. - if let Ok(_) = ecx.get_alloc_size_and_align(alloc_id, AllocCheck::Live) { + if ecx.get_alloc_size_and_align(alloc_id, AllocCheck::Live).is_ok() { return Some(alloc_id); } } diff --git a/src/lib.rs b/src/lib.rs index 1633667fcad8..621af171f4a8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -89,8 +89,8 @@ pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ - CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag, SbTagExtra, - Stack, Stacks, + CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag, SbTagExtra, Stack, + Stacks, }; pub use crate::sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId}; pub use crate::thread::{ diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index e79116a28ecf..ea1132d3e12a 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -403,12 +403,7 @@ impl<'tcx> Stack { tag, item ), None, - tag.and_then(|tag| { - alloc_history.get_logs_relevant_to( - tag, - Some(item.tag), - ) - }), + tag.and_then(|tag| alloc_history.get_logs_relevant_to(tag, Some(item.tag))), ))? } else { Err(err_sb_ub( diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index 0a7edcdc89c1..b1ff864bcd5e 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -148,9 +148,7 @@ impl AllocHistory { err_sb_ub( format!("{}{}", action, error_cause(stack, derived_from)), Some(operation_summary("a reborrow", alloc_id, alloc_range)), - derived_from.and_then(|derived_from| { - self.get_logs_relevant_to(derived_from, None) - }), + derived_from.and_then(|derived_from| self.get_logs_relevant_to(derived_from, None)), ) } From 3abec0e2afdc635b1e2f4cfaf971a7fcd9a9e332 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jun 2022 23:00:54 -0400 Subject: [PATCH 3369/5092] make macOS happy --- test-cargo-miri/run-test.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 42978c481bff..a16019a05e69 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -114,15 +114,16 @@ def test_cargo_miri_test(): default_ref = "test.cross-target.stdout.ref" if is_foreign else "test.default.stdout.ref" filter_ref = "test.filter.cross-target.stdout.ref" if is_foreign else "test.filter.stdout.ref" + # macOS needs permissive provenance inside getrandom. test("`cargo miri test`", cargo_miri("test"), default_ref, "test.stderr-empty.ref", - env={'MIRIFLAGS': "-Zmiri-seed=feed"}, + env={'MIRIFLAGS': "-Zmiri-permissive-provenance -Zmiri-seed=feed"}, ) test("`cargo miri test` (no isolation, no doctests)", cargo_miri("test") + ["--bins", "--tests"], # no `--lib`, we disabled that in `Cargo.toml` "test.cross-target.stdout.ref", "test.stderr-empty.ref", - env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, + env={'MIRIFLAGS': "-Zmiri-permissive-provenance -Zmiri-disable-isolation"}, ) test("`cargo miri test` (with filter)", cargo_miri("test") + ["--", "--format=pretty", "le1"], @@ -131,6 +132,7 @@ def test_cargo_miri_test(): test("`cargo miri test` (test target)", cargo_miri("test") + ["--test", "test", "--", "--format=pretty"], "test.test-target.stdout.ref", "test.stderr-empty.ref", + env={'MIRIFLAGS': "-Zmiri-permissive-provenance"}, ) test("`cargo miri test` (bin target)", cargo_miri("test") + ["--bin", "cargo-miri-test", "--", "--format=pretty"], @@ -148,11 +150,13 @@ def test_cargo_miri_test(): test("`cargo miri test` (custom target dir)", cargo_miri("test") + ["--target-dir=custom-test"], default_ref, "test.stderr-empty.ref", + env={'MIRIFLAGS': "-Zmiri-permissive-provenance"}, ) del os.environ["CARGO_TARGET_DIR"] # this overrides `build.target-dir` passed by `--config`, so unset it test("`cargo miri test` (config-cli)", cargo_miri("test") + ["--config=build.target-dir=\"config-cli\"", "-Zunstable-options"], default_ref, "test.stderr-empty.ref", + env={'MIRIFLAGS': "-Zmiri-permissive-provenance"}, ) os.chdir(os.path.dirname(os.path.realpath(__file__))) From b479f092a86c5524c76088346ac53cd4d0f86e0a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jun 2022 23:14:16 -0400 Subject: [PATCH 3370/5092] avoid unnecessary indirection in miri-track-raw-pointers warning --- src/bin/miri.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index a56b4bc6d1b4..1ccc54d6be19 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -385,7 +385,7 @@ fn main() { miri_config.mute_stdout_stderr = true; } else if arg == "-Zmiri-track-raw-pointers" { eprintln!( - "WARNING: -Zmiri-track-raw-pointers has been renamed to -Zmiri-tag-raw-pointers, the old name is deprecated." + "WARNING: `-Zmiri-track-raw-pointers` has no effect; it is enabled by default" ); } else if let Some(param) = arg.strip_prefix("-Zmiri-seed=") { if miri_config.seed.is_some() { From 513eda0f7bd1461fab01d7c26eb2ecfa364420cd Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 27 Jun 2022 12:37:06 +0200 Subject: [PATCH 3371/5092] make Condvar, Mutex, RwLock const constructors work with unsupported impl --- library/std/src/sys/unsupported/locks/condvar.rs | 1 + library/std/src/sys/unsupported/locks/mutex.rs | 1 + library/std/src/sys/unsupported/locks/rwlock.rs | 1 + library/std/src/sys_common/condvar.rs | 1 + library/std/src/sys_common/condvar/check.rs | 1 + library/std/src/sys_common/mutex.rs | 1 + library/std/src/sys_common/rwlock.rs | 1 + 7 files changed, 7 insertions(+) diff --git a/library/std/src/sys/unsupported/locks/condvar.rs b/library/std/src/sys/unsupported/locks/condvar.rs index e703fd0d2699..527a26a12bce 100644 --- a/library/std/src/sys/unsupported/locks/condvar.rs +++ b/library/std/src/sys/unsupported/locks/condvar.rs @@ -7,6 +7,7 @@ pub type MovableCondvar = Condvar; impl Condvar { #[inline] + #[rustc_const_stable(feature = "const_locks", since = "1.63.0")] pub const fn new() -> Condvar { Condvar {} } diff --git a/library/std/src/sys/unsupported/locks/mutex.rs b/library/std/src/sys/unsupported/locks/mutex.rs index d7cb12e0cf9a..81b49c64caeb 100644 --- a/library/std/src/sys/unsupported/locks/mutex.rs +++ b/library/std/src/sys/unsupported/locks/mutex.rs @@ -12,6 +12,7 @@ unsafe impl Sync for Mutex {} // no threads on this platform impl Mutex { #[inline] + #[rustc_const_stable(feature = "const_locks", since = "1.63.0")] pub const fn new() -> Mutex { Mutex { locked: Cell::new(false) } } diff --git a/library/std/src/sys/unsupported/locks/rwlock.rs b/library/std/src/sys/unsupported/locks/rwlock.rs index aca5fb7152c9..5292691b9555 100644 --- a/library/std/src/sys/unsupported/locks/rwlock.rs +++ b/library/std/src/sys/unsupported/locks/rwlock.rs @@ -12,6 +12,7 @@ unsafe impl Sync for RwLock {} // no threads on this platform impl RwLock { #[inline] + #[rustc_const_stable(feature = "const_locks", since = "1.63.0")] pub const fn new() -> RwLock { RwLock { mode: Cell::new(0) } } diff --git a/library/std/src/sys_common/condvar.rs b/library/std/src/sys_common/condvar.rs index f3ac1061b893..8bc5b24115d1 100644 --- a/library/std/src/sys_common/condvar.rs +++ b/library/std/src/sys_common/condvar.rs @@ -15,6 +15,7 @@ pub struct Condvar { impl Condvar { /// Creates a new condition variable for use. #[inline] + #[rustc_const_stable(feature = "const_locks", since = "1.63.0")] pub const fn new() -> Self { Self { inner: imp::MovableCondvar::new(), check: CondvarCheck::new() } } diff --git a/library/std/src/sys_common/condvar/check.rs b/library/std/src/sys_common/condvar/check.rs index ce8f36704877..4ac9e62bf869 100644 --- a/library/std/src/sys_common/condvar/check.rs +++ b/library/std/src/sys_common/condvar/check.rs @@ -50,6 +50,7 @@ pub struct NoCheck; #[allow(dead_code)] impl NoCheck { + #[rustc_const_stable(feature = "const_locks", since = "1.63.0")] pub const fn new() -> Self { Self } diff --git a/library/std/src/sys_common/mutex.rs b/library/std/src/sys_common/mutex.rs index 48479f5bdb3f..7b9f7ef54878 100644 --- a/library/std/src/sys_common/mutex.rs +++ b/library/std/src/sys_common/mutex.rs @@ -61,6 +61,7 @@ unsafe impl Sync for MovableMutex {} impl MovableMutex { /// Creates a new mutex. #[inline] + #[rustc_const_stable(feature = "const_locks", since = "1.63.0")] pub const fn new() -> Self { Self(imp::MovableMutex::new()) } diff --git a/library/std/src/sys_common/rwlock.rs b/library/std/src/sys_common/rwlock.rs index ba56f3a8f1b5..34e9a91e8748 100644 --- a/library/std/src/sys_common/rwlock.rs +++ b/library/std/src/sys_common/rwlock.rs @@ -75,6 +75,7 @@ pub struct MovableRwLock(imp::MovableRwLock); impl MovableRwLock { /// Creates a new reader-writer lock for use. #[inline] + #[rustc_const_stable(feature = "const_locks", since = "1.63.0")] pub const fn new() -> Self { Self(imp::MovableRwLock::new()) } From d9e7a3ae820b23d54ee9d1145e0295d1486601d6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jun 2022 08:35:25 -0400 Subject: [PATCH 3372/5092] typo Co-authored-by: Oli Scherer --- src/intptrcast.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 83739c48efc5..5e6088303f81 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -215,7 +215,7 @@ impl<'mir, 'tcx> GlobalStateInner { dl.overflowing_offset(base_addr, offset.bytes()).0 } - /// Whena pointer is used for a memory access, this computes where in which allocation the + /// When a pointer is used for a memory access, this computes where in which allocation the /// access is going. pub fn abs_ptr_to_rel( ecx: &MiriEvalContext<'mir, 'tcx>, From fb186a2f2d6ea3851f7e41f7e66a81a0a4f9146f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jun 2022 11:44:45 -0400 Subject: [PATCH 3373/5092] make sure a thread is joined --- tests/pass/concurrency/sync_nopreempt.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/pass/concurrency/sync_nopreempt.rs b/tests/pass/concurrency/sync_nopreempt.rs index 391f65ae5a9c..b5e726dac7b6 100644 --- a/tests/pass/concurrency/sync_nopreempt.rs +++ b/tests/pass/concurrency/sync_nopreempt.rs @@ -46,7 +46,7 @@ fn check_rwlock_unlock_bug1() { // Make a waiting writer. let l2 = l.clone(); - thread::spawn(move || { + let t = thread::spawn(move || { let mut w = l2.write().unwrap(); *w += 1; }); @@ -59,6 +59,7 @@ fn check_rwlock_unlock_bug1() { thread::yield_now(); assert_eq!(*r2, 0); drop(r2); + t.join().unwrap(); } fn check_rwlock_unlock_bug2() { From 5719897fb0ba0a91fd1b094019c5caf7f58e6e9f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jun 2022 13:38:32 -0400 Subject: [PATCH 3374/5092] improve old comment --- src/shims/unix/foreign_items.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 4993690767c1..d0c93ef4cdaf 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -463,10 +463,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_attr_getstack" => { - // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. + // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. Hence we can mostly ignore the input `attr_place`. let [attr_place, addr_place, size_place] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - this.deref_operand(attr_place)?; + let _attr_place = this.deref_operand(attr_place)?; let addr_place = this.deref_operand(addr_place)?; let size_place = this.deref_operand(size_place)?; From 67e89b53e24d6bdf56d5c063f2c8997ab7d2381f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jun 2022 20:04:46 -0400 Subject: [PATCH 3375/5092] fix warning text --- src/diagnostics.rs | 4 ++-- tests/pass/box.stderr | 4 ++-- tests/pass/extern_types.stderr | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 8176e51338a5..1a030bedd928 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -451,13 +451,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx format!("{op} was made to return an error due to isolation"), ProgressReport => format!("progress report: current operation being executed is here"), - Int2Ptr => format!("pointer-to-integer cast"), + Int2Ptr => format!("integer-to-pointer cast"), }; let (title, diag_level) = match e { RejectedIsolatedOp(_) => ("operation rejected by isolation", DiagLevel::Warning), - Int2Ptr => ("pointer-to-integer cast", DiagLevel::Warning), + Int2Ptr => ("integer-to-pointer cast", DiagLevel::Warning), CreatedPointerTag(..) | PoppedPointerTag(..) | CreatedCallId(..) diff --git a/tests/pass/box.stderr b/tests/pass/box.stderr index eac98bf2d124..eeb49eec5c05 100644 --- a/tests/pass/box.stderr +++ b/tests/pass/box.stderr @@ -1,8 +1,8 @@ -warning: pointer-to-integer cast +warning: integer-to-pointer cast --> $DIR/box.rs:LL:CC | LL | let r2 = ((r as usize) + 0) as *mut i32; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast | = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, = help: which means that Miri might miss pointer bugs in this program diff --git a/tests/pass/extern_types.stderr b/tests/pass/extern_types.stderr index 730a43042535..f23526b52b4e 100644 --- a/tests/pass/extern_types.stderr +++ b/tests/pass/extern_types.stderr @@ -1,8 +1,8 @@ -warning: pointer-to-integer cast +warning: integer-to-pointer cast --> $DIR/extern_types.rs:LL:CC | LL | let x: &Foo = unsafe { &*(16 as *const Foo) }; - | ^^^^^^^^^^^^^^^^^^ pointer-to-integer cast + | ^^^^^^^^^^^^^^^^^^ integer-to-pointer cast | = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, = help: which means that Miri might miss pointer bugs in this program From c1eddbc7fefe34bb0213261cb4aa18f4bc11b1c5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jun 2022 20:22:50 -0400 Subject: [PATCH 3376/5092] show int2ptr warning once for each span (but don't duplicate the long help) --- src/diagnostics.rs | 10 ++++++---- src/intptrcast.rs | 17 ++++++++++++----- src/lib.rs | 1 + tests/pass/box.stderr | 13 +++++++++++++ 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 1a030bedd928..83949a75dee0 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -69,7 +69,9 @@ pub enum NonHaltingDiagnostic { FreedAlloc(AllocId), RejectedIsolatedOp(String), ProgressReport, - Int2Ptr, + Int2Ptr { + details: bool, + }, } /// Level of Miri specific diagnostics @@ -451,13 +453,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx format!("{op} was made to return an error due to isolation"), ProgressReport => format!("progress report: current operation being executed is here"), - Int2Ptr => format!("integer-to-pointer cast"), + Int2Ptr { .. } => format!("integer-to-pointer cast"), }; let (title, diag_level) = match e { RejectedIsolatedOp(_) => ("operation rejected by isolation", DiagLevel::Warning), - Int2Ptr => ("integer-to-pointer cast", DiagLevel::Warning), + Int2Ptr { .. } => ("integer-to-pointer cast", DiagLevel::Warning), CreatedPointerTag(..) | PoppedPointerTag(..) | CreatedCallId(..) @@ -467,7 +469,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; let helps = match e { - Int2Ptr => + Int2Ptr { details: true } => vec![ (None, format!("this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`,")), (None, format!("which means that Miri might miss pointer bugs in this program")), diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 5e6088303f81..a95b20868d21 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -5,6 +5,7 @@ use log::trace; use rand::Rng; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_span::Span; use rustc_target::abi::{HasDataLayout, Size}; use crate::*; @@ -140,12 +141,18 @@ impl<'mir, 'tcx> GlobalStateInner { match global_state.provenance_mode { ProvenanceMode::Default => { - // The first time this happens, print a warning. - use std::sync::atomic::{AtomicBool, Ordering}; - static FIRST_WARNING: AtomicBool = AtomicBool::new(true); - if FIRST_WARNING.swap(false, Ordering::Relaxed) { - register_diagnostic(NonHaltingDiagnostic::Int2Ptr); + // The first time this happens at a particular location, print a warning. + thread_local! { + // `Span` is non-`Send`, so we use a thread-local instead. + static PAST_WARNINGS: RefCell> = RefCell::default(); } + PAST_WARNINGS.with_borrow_mut(|past_warnings| { + let first = past_warnings.is_empty(); + if past_warnings.insert(ecx.cur_span()) { + // Newly inserted, so first time we see this span. + register_diagnostic(NonHaltingDiagnostic::Int2Ptr { details: first }); + } + }); } ProvenanceMode::Strict => { throw_unsup_format!( diff --git a/src/lib.rs b/src/lib.rs index 621af171f4a8..e199fae31ee8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,6 +8,7 @@ #![feature(yeet_expr)] #![feature(is_some_with)] #![feature(nonzero_ops)] +#![feature(local_key_cell_methods)] #![warn(rust_2018_idioms)] #![allow( clippy::collapsible_else_if, diff --git a/tests/pass/box.stderr b/tests/pass/box.stderr index eeb49eec5c05..d821fcd9d151 100644 --- a/tests/pass/box.stderr +++ b/tests/pass/box.stderr @@ -18,3 +18,16 @@ note: inside `main` at $DIR/box.rs:LL:CC LL | into_raw(); | ^^^^^^^^^^ +warning: integer-to-pointer cast + --> $DIR/box.rs:LL:CC + | +LL | let r = ((u.as_ptr() as usize) + 0) as *mut i32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast + | + = note: inside `into_unique` at $DIR/box.rs:LL:CC +note: inside `main` at $DIR/box.rs:LL:CC + --> $DIR/box.rs:LL:CC + | +LL | into_unique(); + | ^^^^^^^^^^^^^ + From 098704e10fda8da532022fc9ef91e6a9173fd203 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jun 2022 11:09:28 -0400 Subject: [PATCH 3377/5092] make use of get_alloc_info --- src/intptrcast.rs | 27 ++++++------------- src/shims/mod.rs | 2 +- src/stacked_borrows.rs | 19 ++++++------- tests/fail/function_pointers/deref_fn_ptr.rs | 2 +- .../function_pointers/deref_fn_ptr.stderr | 4 +-- 5 files changed, 20 insertions(+), 34 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index a95b20868d21..0ef5b08f9e40 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -76,27 +76,17 @@ impl<'mir, 'tcx> GlobalStateInner { // This never overflows because `addr >= glb` let offset = addr - glb; // If the offset exceeds the size of the allocation, don't use this `alloc_id`. - - if offset - <= ecx - .get_alloc_size_and_align(alloc_id, AllocCheck::MaybeDead) - .unwrap() - .0 - .bytes() - { - Some(alloc_id) - } else { - None - } + let size = ecx.get_alloc_info(alloc_id).0; + if offset <= size.bytes() { Some(alloc_id) } else { None } } }?; // We only use this provenance if it has been exposed, *and* is still live. if global_state.exposed.contains(&alloc_id) { - // FIXME: this catches `InterpError`, which we should not usually do. - // We might need a proper fallible API from `memory.rs` to avoid this though. - if ecx.get_alloc_size_and_align(alloc_id, AllocCheck::Live).is_ok() { - return Some(alloc_id); + let (_size, _align, kind) = ecx.get_alloc_info(alloc_id); + match kind { + AllocKind::LiveData | AllocKind::Function => return Some(alloc_id), + AllocKind::Dead => {} } } @@ -174,9 +164,8 @@ impl<'mir, 'tcx> GlobalStateInner { Entry::Occupied(entry) => *entry.get(), Entry::Vacant(entry) => { // There is nothing wrong with a raw pointer being cast to an integer only after - // it became dangling. Hence `MaybeDead`. - let (size, align) = - ecx.get_alloc_size_and_align(alloc_id, AllocCheck::MaybeDead).unwrap(); + // it became dangling. Hence we allow dead allocations. + let (size, align, _kind) = ecx.get_alloc_info(alloc_id); // This allocation does not have a base address yet, pick one. // Leave some space to the previous allocation, to give it some chance to be less aligned. diff --git a/src/shims/mod.rs b/src/shims/mod.rs index f2688bb08caa..2423ffaf5fe0 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -87,7 +87,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.read_pointer(ptr_op)?; if let Ok((alloc_id, _offset, _)) = this.ptr_try_get_alloc_id(ptr) { // Only do anything if we can identify the allocation this goes to. - let (_, cur_align) = this.get_alloc_size_and_align(alloc_id, AllocCheck::MaybeDead)?; + let (_size, cur_align, _kind) = this.get_alloc_info(alloc_id); if cur_align.bytes() >= req_align { // If the allocation alignment is at least the required alignment we use the // real implementation. diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index ea1132d3e12a..66f756d7b08d 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -849,8 +849,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx log_creation(this, current_span, alloc_id, base_offset, orig_tag)?; // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). - let (alloc_size, _) = - this.get_alloc_size_and_align(alloc_id, AllocCheck::Dereferenceable)?; + let (alloc_size, _) = this.get_live_alloc_size_and_align(alloc_id)?; if base_offset + size > alloc_size { throw_ub!(PointerOutOfBounds { alloc_id, @@ -1088,18 +1087,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Function pointers and dead objects don't have an alloc_extra so we ignore them. // This is okay because accessing them is UB anyway, no need for any Stacked Borrows checks. // NOT using `get_alloc_extra_mut` since this might be a read-only allocation! - // FIXME: this catches `InterpError`, which we should not usually do. - // We might need a proper fallible API from `memory.rs` to avoid this though. - match this.get_alloc_extra(alloc_id) { - Ok(alloc_extra) => { + let (_size, _align, kind) = this.get_alloc_info(alloc_id); + match kind { + AllocKind::LiveData => { + // This should have alloc_extra data. + let alloc_extra = this.get_alloc_extra(alloc_id).unwrap(); trace!("Stacked Borrows tag {tag:?} exposed in {alloc_id}"); alloc_extra.stacked_borrows.as_ref().unwrap().borrow_mut().exposed_tags.insert(tag); } - Err(err) => { - trace!( - "Not exposing Stacked Borrows tag {tag:?} due to error \ - when accessing {alloc_id}: {err}" - ); + AllocKind::Function | AllocKind::Dead => { + // No stacked borrows on these allocations. } } } diff --git a/tests/fail/function_pointers/deref_fn_ptr.rs b/tests/fail/function_pointers/deref_fn_ptr.rs index e604f96ea16f..f22f73487b48 100644 --- a/tests/fail/function_pointers/deref_fn_ptr.rs +++ b/tests/fail/function_pointers/deref_fn_ptr.rs @@ -2,7 +2,7 @@ fn f() {} fn main() { let x: u8 = unsafe { - *std::mem::transmute::(f) //~ ERROR contains a function + *std::mem::transmute::(f) //~ ERROR out-of-bounds }; panic!("this should never print: {}", x); } diff --git a/tests/fail/function_pointers/deref_fn_ptr.stderr b/tests/fail/function_pointers/deref_fn_ptr.stderr index 1e3da2726d4b..619b58f699a3 100644 --- a/tests/fail/function_pointers/deref_fn_ptr.stderr +++ b/tests/fail/function_pointers/deref_fn_ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: accessing ALLOC which contains a function +error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds --> $DIR/deref_fn_ptr.rs:LL:CC | LL | *std::mem::transmute::(f) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing ALLOC which contains a function + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information From ea30b6baddcdba49fdd47fa21d609011e32b6929 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jun 2022 21:29:40 -0400 Subject: [PATCH 3378/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index dafb049cc5a8..5bda09cfdb2b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8aab472d52ba7314dc193c73abcd384e2586123c +7f08d04d60d03e1a52dae61ce6aa50996898702b From c16b380d6bf3a72a8fcaa2b6ae469f0fa49f9ad5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jun 2022 08:13:55 -0400 Subject: [PATCH 3379/5092] finally we can actually have adjacent allocations :) --- src/intptrcast.rs | 11 ++++---- tests/pass/adjacent-allocs.rs | 16 ++++++++++++ tests/pass/intptrcast.rs | 48 +++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 5 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index a95b20868d21..1a630259cf6a 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -1,4 +1,5 @@ use std::cell::RefCell; +use std::cmp::max; use std::collections::hash_map::Entry; use log::trace; @@ -198,11 +199,11 @@ impl<'mir, 'tcx> GlobalStateInner { slack, ); - // Remember next base address. Leave a gap of at least 1 to avoid two zero-sized allocations - // having the same base address, and to avoid ambiguous provenance for the address between two - // allocations (also see https://github.com/rust-lang/unsafe-code-guidelines/issues/313). - let size_plus_1 = size.bytes().checked_add(1).unwrap(); - global_state.next_base_addr = base_addr.checked_add(size_plus_1).unwrap(); + // Remember next base address. If this allocation is zero-sized, leave a gap + // of at least 1 to avoid two allocations having the same base address. + // (The logic in `alloc_id_from_addr` assumes unique addresses, and function + // pointers to different functions need to be distinguishable!) + global_state.next_base_addr = base_addr.checked_add(max(size.bytes(), 1)).unwrap(); // Given that `next_base_addr` increases in each allocation, pushing the // corresponding tuple keeps `int_to_ptr_map` sorted global_state.int_to_ptr_map.push((base_addr, alloc_id)); diff --git a/tests/pass/adjacent-allocs.rs b/tests/pass/adjacent-allocs.rs index b3483a5b4380..d0dc8b5d8762 100644 --- a/tests/pass/adjacent-allocs.rs +++ b/tests/pass/adjacent-allocs.rs @@ -1,5 +1,20 @@ // compile-flags: -Zmiri-permissive-provenance +fn ensure_allocs_can_be_adjacent() { + for _ in 0..512 { + let n = 0u64; + let ptr: *const u64 = &n; + let ptr2 = { + let m = 0u64; + &m as *const u64 + }; + if ptr.wrapping_add(1) == ptr2 { + return; + } + } + panic!("never saw adjacent stack variables?"); +} + fn test1() { // The slack between allocations is random. // Loop a few times to hit the zero-slack case. @@ -42,6 +57,7 @@ fn test2() { } fn main() { + ensure_allocs_can_be_adjacent(); test1(); test2(); } diff --git a/tests/pass/intptrcast.rs b/tests/pass/intptrcast.rs index 2417a83493be..aebf5b222389 100644 --- a/tests/pass/intptrcast.rs +++ b/tests/pass/intptrcast.rs @@ -1,5 +1,7 @@ // compile-flags: -Zmiri-permissive-provenance +use std::mem; + // This strips provenance fn transmute_ptr_to_int(x: *const T) -> usize { unsafe { std::mem::transmute(x) } @@ -100,6 +102,51 @@ fn zst_deref_of_dangling() { let _val = unsafe { *zst }; } +fn functions() { + // Roundtrip a few functions through integers. Do this multiple times to make sure this does not + // work by chance. If we did not give unique addresses to ZST allocations -- which fn + // allocations are -- then we might be unable to cast back, or we might call the wrong function! + // Every function gets at most one address so doing a loop would not help... + fn fn0() -> i32 { + 0 + } + fn fn1() -> i32 { + 1 + } + fn fn2() -> i32 { + 2 + } + fn fn3() -> i32 { + 3 + } + fn fn4() -> i32 { + 4 + } + fn fn5() -> i32 { + 5 + } + fn fn6() -> i32 { + 6 + } + fn fn7() -> i32 { + 7 + } + let fns = [ + fn0 as fn() -> i32 as *const () as usize, + fn1 as fn() -> i32 as *const () as usize, + fn2 as fn() -> i32 as *const () as usize, + fn3 as fn() -> i32 as *const () as usize, + fn4 as fn() -> i32 as *const () as usize, + fn5 as fn() -> i32 as *const () as usize, + fn6 as fn() -> i32 as *const () as usize, + fn7 as fn() -> i32 as *const () as usize, + ]; + for (idx, &addr) in fns.iter().enumerate() { + let fun: fn() -> i32 = unsafe { mem::transmute(addr as *const ()) }; + assert_eq!(fun(), idx as i32); + } +} + fn main() { cast(); cast_dangling(); @@ -112,4 +159,5 @@ fn main() { ptr_eq_out_of_bounds_null(); ptr_eq_integer(); zst_deref_of_dangling(); + functions(); } From 108fe3473c59984027d6e5caeab1b11caf2531a7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jun 2022 11:16:27 -0400 Subject: [PATCH 3380/5092] update getrandom --- test-cargo-miri/Cargo.lock | 78 ++++++++++++++++--------------------- test-cargo-miri/run-test.py | 2 +- 2 files changed, 35 insertions(+), 45 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 4bece389dc87..d34db9f14dfc 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -16,7 +16,7 @@ dependencies = [ "cdylib", "exported_symbol", "getrandom 0.1.16", - "getrandom 0.2.2", + "getrandom 0.2.7", "issue_1567", "issue_1691", "issue_1705", @@ -64,20 +64,20 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.2" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" dependencies = [ "cfg-if", "libc", - "wasi 0.10.2+wasi-snapshot-preview1", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] name = "hermit-abi" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] @@ -110,15 +110,15 @@ version = "0.1.0" [[package]] name = "libc" -version = "0.2.92" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" [[package]] name = "num_cpus" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" dependencies = [ "hermit-abi", "libc", @@ -136,45 +136,44 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.10" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "proc-macro2" -version = "1.0.26" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] name = "quote" -version = "1.0.9" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" dependencies = [ "proc-macro2", ] [[package]] name = "rand" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", - "rand_hc", ] [[package]] name = "rand_chacha" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", "rand_core", @@ -182,27 +181,18 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ - "getrandom 0.2.2", -] - -[[package]] -name = "rand_hc" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" -dependencies = [ - "rand_core", + "getrandom 0.2.7", ] [[package]] name = "serde_derive" -version = "1.0.125" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" dependencies = [ "proc-macro2", "quote", @@ -218,20 +208,20 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.68" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] -name = "unicode-xid" -version = "0.2.1" +name = "unicode-ident" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" [[package]] name = "wasi" @@ -241,9 +231,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "winapi" diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index a16019a05e69..09e7df39b1c0 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -114,7 +114,7 @@ def test_cargo_miri_test(): default_ref = "test.cross-target.stdout.ref" if is_foreign else "test.default.stdout.ref" filter_ref = "test.filter.cross-target.stdout.ref" if is_foreign else "test.filter.stdout.ref" - # macOS needs permissive provenance inside getrandom. + # macOS needs permissive provenance inside getrandom_1. test("`cargo miri test`", cargo_miri("test"), default_ref, "test.stderr-empty.ref", From 65497649602ca5b56bed9418eda7d2e2be72487d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jun 2022 22:11:09 -0400 Subject: [PATCH 3381/5092] typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d7c50e9613fd..a7ee11e82e0f 100644 --- a/README.md +++ b/README.md @@ -277,7 +277,7 @@ environment variable. We first document the most relevant and most commonly used and `warn-nobacktrace` are the supported actions. The default is to `abort`, which halts the machine. Some (but not all) operations also support continuing execution with a "permission denied" error being returned to the program. - `warn` prints a full backtrace when that happen; `warn-nobacktrace` is less + `warn` prints a full backtrace when that happens; `warn-nobacktrace` is less verbose. `hide` hides the warning entirely. * `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from the host so that it cannot be accessed by the program. Can be used multiple times to exclude several variables. The From 8bd4bbe3e4b4630cb96f238618d1bb7b3aea5502 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 28 Jun 2022 08:52:22 -0400 Subject: [PATCH 3382/5092] tweak int2ptr diagnostics --- src/diagnostics.rs | 25 +++++++++++++------ src/intptrcast.rs | 4 +-- .../fail/provenance/strict_provenance_cast.rs | 2 +- .../provenance/strict_provenance_cast.stderr | 6 ++--- tests/pass/box.stderr | 12 ++++----- tests/pass/extern_types.stderr | 12 ++++----- 6 files changed, 34 insertions(+), 27 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 83949a75dee0..c762b3d8106d 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -21,6 +21,7 @@ pub enum TerminationInfo { help: Option, history: Option, }, + Int2PtrWithStrictProvenance, Deadlock, MultipleSymbolDefinitions { link_name: Symbol, @@ -42,6 +43,11 @@ impl fmt::Display for TerminationInfo { Exit(code) => write!(f, "the evaluated program completed with exit code {}", code), Abort(msg) => write!(f, "{}", msg), UnsupportedInIsolation(msg) => write!(f, "{}", msg), + Int2PtrWithStrictProvenance => + write!( + f, + "integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance`" + ), StackedBorrowsUb { msg, .. } => write!(f, "{}", msg), Deadlock => write!(f, "the evaluated program deadlocked"), MultipleSymbolDefinitions { link_name, .. } => @@ -148,7 +154,8 @@ pub fn report_error<'tcx, 'mir>( let title = match info { Exit(code) => return Some(*code), Abort(_) => Some("abnormal termination"), - UnsupportedInIsolation(_) => Some("unsupported operation"), + UnsupportedInIsolation(_) | Int2PtrWithStrictProvenance => + Some("unsupported operation"), StackedBorrowsUb { .. } => Some("Undefined Behavior"), Deadlock => Some("deadlock"), MultipleSymbolDefinitions { .. } | SymbolShimClashing { .. } => None, @@ -177,7 +184,7 @@ pub fn report_error<'tcx, 'mir>( } if let Some((protecting_tag, protecting_tag_span, protection_span)) = protected { helps.push((Some(*protecting_tag_span), format!("{:?} was protected due to {:?} which was created here", tag, protecting_tag))); - helps.push((Some(*protection_span), "this protector is live for this call".to_string())); + helps.push((Some(*protection_span), format!("this protector is live for this call"))); } } None => {} @@ -191,6 +198,8 @@ pub fn report_error<'tcx, 'mir>( ], SymbolShimClashing { link_name, span } => vec![(Some(*span), format!("the `{}` symbol is defined here", link_name))], + Int2PtrWithStrictProvenance => + vec![(None, format!("use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead"))], _ => vec![], }; (title, helps) @@ -471,12 +480,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let helps = match e { Int2Ptr { details: true } => vec![ - (None, format!("this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`,")), - (None, format!("which means that Miri might miss pointer bugs in this program")), - (None, format!("see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation")), - (None, format!("to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead")), - (None, format!("you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics")), - (None, format!("alternatively, the `-Zmiri-permissive-provenance` flag disables this warning")), + (None, format!("This program is using integer-to-pointer casts or (equivalently) `ptr::from_exposed_addr`,")), + (None, format!("which means that Miri might miss pointer bugs in this program.")), + (None, format!("See https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation.")), + (None, format!("To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead.")), + (None, format!("You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics.")), + (None, format!("Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning.")), ], _ => vec![], }; diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 0ebc62ebbfb1..5a33ada45044 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -146,9 +146,7 @@ impl<'mir, 'tcx> GlobalStateInner { }); } ProvenanceMode::Strict => { - throw_unsup_format!( - "integer-to-pointer casts and `from_exposed_addr` are not supported with `-Zmiri-strict-provenance`; use `with_addr` instead" - ) + throw_machine_stop!(TerminationInfo::Int2PtrWithStrictProvenance); } ProvenanceMode::Permissive => {} } diff --git a/tests/fail/provenance/strict_provenance_cast.rs b/tests/fail/provenance/strict_provenance_cast.rs index 8b2b053bdb59..968c4dfded37 100644 --- a/tests/fail/provenance/strict_provenance_cast.rs +++ b/tests/fail/provenance/strict_provenance_cast.rs @@ -2,5 +2,5 @@ fn main() { let addr = &0 as *const i32 as usize; - let _ptr = addr as *const i32; //~ ERROR integer-to-pointer casts and `from_exposed_addr` are not supported + let _ptr = addr as *const i32; //~ ERROR integer-to-pointer casts and `ptr::from_exposed_addr` are not supported } diff --git a/tests/fail/provenance/strict_provenance_cast.stderr b/tests/fail/provenance/strict_provenance_cast.stderr index 32a39b81d9d7..ab64f2bb288e 100644 --- a/tests/fail/provenance/strict_provenance_cast.stderr +++ b/tests/fail/provenance/strict_provenance_cast.stderr @@ -1,10 +1,10 @@ -error: unsupported operation: integer-to-pointer casts and `from_exposed_addr` are not supported with `-Zmiri-strict-provenance`; use `with_addr` instead +error: unsupported operation: integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance` --> $DIR/strict_provenance_cast.rs:LL:CC | LL | let _ptr = addr as *const i32; - | ^^^^^^^^^^^^^^^^^^ integer-to-pointer casts and `from_exposed_addr` are not supported with `-Zmiri-strict-provenance`; use `with_addr` instead + | ^^^^^^^^^^^^^^^^^^ integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance` | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead = note: inside `main` at $DIR/strict_provenance_cast.rs:LL:CC diff --git a/tests/pass/box.stderr b/tests/pass/box.stderr index d821fcd9d151..41c752d5d0fc 100644 --- a/tests/pass/box.stderr +++ b/tests/pass/box.stderr @@ -4,12 +4,12 @@ warning: integer-to-pointer cast LL | let r2 = ((r as usize) + 0) as *mut i32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + = help: This program is using integer-to-pointer casts or (equivalently) `ptr::from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program. + = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation. + = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead. + = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics. + = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning. = note: inside `into_raw` at $DIR/box.rs:LL:CC note: inside `main` at $DIR/box.rs:LL:CC diff --git a/tests/pass/extern_types.stderr b/tests/pass/extern_types.stderr index f23526b52b4e..3a4acec5ddb9 100644 --- a/tests/pass/extern_types.stderr +++ b/tests/pass/extern_types.stderr @@ -4,12 +4,12 @@ warning: integer-to-pointer cast LL | let x: &Foo = unsafe { &*(16 as *const Foo) }; | ^^^^^^^^^^^^^^^^^^ integer-to-pointer cast | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + = help: This program is using integer-to-pointer casts or (equivalently) `ptr::from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program. + = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation. + = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead. + = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics. + = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning. = note: inside `main` at $DIR/extern_types.rs:LL:CC From 28dea673bec32b5d59545912f53ad22b8944f3a4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 Jun 2022 08:33:06 -0400 Subject: [PATCH 3383/5092] rustup --- rust-version | 2 +- src/diagnostics.rs | 4 + src/shims/intrinsics.rs | 122 +++++++++--------- .../data_race/atomic_read_na_write_race1.rs | 4 +- .../atomic_read_na_write_race1.stderr | 4 +- tests/fail/panic/double_panic.stderr | 1 - tests/fail/panic/panic_abort1.stderr | 1 - tests/fail/panic/panic_abort2.stderr | 1 - tests/fail/panic/panic_abort3.stderr | 2 - tests/fail/panic/panic_abort4.stderr | 1 - .../unaligned_pointers/atomic_unaligned.rs | 2 +- .../atomic_unaligned.stderr | 4 +- 12 files changed, 73 insertions(+), 75 deletions(-) diff --git a/rust-version b/rust-version index 5bda09cfdb2b..4f24d29e34b4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7f08d04d60d03e1a52dae61ce6aa50996898702b +493c960a3e6cdd2e2fbe8b6ea130fadea05f1ab0 diff --git a/src/diagnostics.rs b/src/diagnostics.rs index c762b3d8106d..95252a113429 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -107,6 +107,10 @@ fn prune_stacktrace<'mir, 'tcx>( // bug in the Rust runtime, we don't prune away every frame. let has_local_frame = stacktrace.iter().any(|frame| ecx.machine.is_local(frame)); if has_local_frame { + // Remove all frames marked with `caller_location` -- that attribute indicates we + // usually want to point at the caller, not them. + stacktrace.retain(|frame| !frame.instance.def.requires_caller_location(*ecx.tcx)); + // This is part of the logic that `std` uses to select the relevant part of a // backtrace. But here, we only look for __rust_begin_short_backtrace, not // __rust_end_short_backtrace because the end symbol comes from a call to the default diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 8d4da31fd0d7..fa5a6e9c273e 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -864,95 +864,95 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Atomic operations - "atomic_load" => this.atomic_load(args, dest, AtomicReadOp::SeqCst)?, + "atomic_load_seqcst" => this.atomic_load(args, dest, AtomicReadOp::SeqCst)?, "atomic_load_relaxed" => this.atomic_load(args, dest, AtomicReadOp::Relaxed)?, - "atomic_load_acq" => this.atomic_load(args, dest, AtomicReadOp::Acquire)?, + "atomic_load_acquire" => this.atomic_load(args, dest, AtomicReadOp::Acquire)?, - "atomic_store" => this.atomic_store(args, AtomicWriteOp::SeqCst)?, + "atomic_store_seqcst" => this.atomic_store(args, AtomicWriteOp::SeqCst)?, "atomic_store_relaxed" => this.atomic_store(args, AtomicWriteOp::Relaxed)?, - "atomic_store_rel" => this.atomic_store(args, AtomicWriteOp::Release)?, + "atomic_store_release" => this.atomic_store(args, AtomicWriteOp::Release)?, - "atomic_fence_acq" => this.atomic_fence(args, AtomicFenceOp::Acquire)?, - "atomic_fence_rel" => this.atomic_fence(args, AtomicFenceOp::Release)?, + "atomic_fence_acquire" => this.atomic_fence(args, AtomicFenceOp::Acquire)?, + "atomic_fence_release" => this.atomic_fence(args, AtomicFenceOp::Release)?, "atomic_fence_acqrel" => this.atomic_fence(args, AtomicFenceOp::AcqRel)?, - "atomic_fence" => this.atomic_fence(args, AtomicFenceOp::SeqCst)?, + "atomic_fence_seqcst" => this.atomic_fence(args, AtomicFenceOp::SeqCst)?, - "atomic_singlethreadfence_acq" => this.compiler_fence(args, AtomicFenceOp::Acquire)?, - "atomic_singlethreadfence_rel" => this.compiler_fence(args, AtomicFenceOp::Release)?, + "atomic_singlethreadfence_acquire" => this.compiler_fence(args, AtomicFenceOp::Acquire)?, + "atomic_singlethreadfence_release" => this.compiler_fence(args, AtomicFenceOp::Release)?, "atomic_singlethreadfence_acqrel" => this.compiler_fence(args, AtomicFenceOp::AcqRel)?, - "atomic_singlethreadfence" => this.compiler_fence(args, AtomicFenceOp::SeqCst)?, + "atomic_singlethreadfence_seqcst" => this.compiler_fence(args, AtomicFenceOp::SeqCst)?, - "atomic_xchg" => this.atomic_exchange(args, dest, AtomicRwOp::SeqCst)?, - "atomic_xchg_acq" => this.atomic_exchange(args, dest, AtomicRwOp::Acquire)?, - "atomic_xchg_rel" => this.atomic_exchange(args, dest, AtomicRwOp::Release)?, + "atomic_xchg_seqcst" => this.atomic_exchange(args, dest, AtomicRwOp::SeqCst)?, + "atomic_xchg_acquire" => this.atomic_exchange(args, dest, AtomicRwOp::Acquire)?, + "atomic_xchg_release" => this.atomic_exchange(args, dest, AtomicRwOp::Release)?, "atomic_xchg_acqrel" => this.atomic_exchange(args, dest, AtomicRwOp::AcqRel)?, "atomic_xchg_relaxed" => this.atomic_exchange(args, dest, AtomicRwOp::Relaxed)?, #[rustfmt::skip] - "atomic_cxchg" => + "atomic_cxchg_seqcst_seqcst" => this.atomic_compare_exchange(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::SeqCst)?, #[rustfmt::skip] - "atomic_cxchg_acq" => + "atomic_cxchg_acquire_acquire" => this.atomic_compare_exchange(args, dest, AtomicRwOp::Acquire, AtomicReadOp::Acquire)?, #[rustfmt::skip] - "atomic_cxchg_rel" => + "atomic_cxchg_release_relaxed" => this.atomic_compare_exchange(args, dest, AtomicRwOp::Release, AtomicReadOp::Relaxed)?, #[rustfmt::skip] - "atomic_cxchg_acqrel" => + "atomic_cxchg_acqrel_acquire" => this.atomic_compare_exchange(args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Acquire)?, #[rustfmt::skip] - "atomic_cxchg_relaxed" => + "atomic_cxchg_relaxed_relaxed" => this.atomic_compare_exchange(args, dest, AtomicRwOp::Relaxed, AtomicReadOp::Relaxed)?, #[rustfmt::skip] - "atomic_cxchg_acq_failrelaxed" => + "atomic_cxchg_acquire_relaxed" => this.atomic_compare_exchange(args, dest, AtomicRwOp::Acquire, AtomicReadOp::Relaxed)?, #[rustfmt::skip] - "atomic_cxchg_acqrel_failrelaxed" => + "atomic_cxchg_acqrel_relaxed" => this.atomic_compare_exchange(args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Relaxed)?, #[rustfmt::skip] - "atomic_cxchg_failrelaxed" => + "atomic_cxchg_seqcst_relaxed" => this.atomic_compare_exchange(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Relaxed)?, #[rustfmt::skip] - "atomic_cxchg_failacq" => + "atomic_cxchg_seqcst_acquire" => this.atomic_compare_exchange(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Acquire)?, #[rustfmt::skip] - "atomic_cxchgweak" => + "atomic_cxchgweak_seqcst_seqcst" => this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::SeqCst)?, #[rustfmt::skip] - "atomic_cxchgweak_acq" => + "atomic_cxchgweak_acquire_acquire" => this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::Acquire, AtomicReadOp::Acquire)?, #[rustfmt::skip] - "atomic_cxchgweak_rel" => + "atomic_cxchgweak_release_relaxed" => this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::Release, AtomicReadOp::Relaxed)?, #[rustfmt::skip] - "atomic_cxchgweak_acqrel" => + "atomic_cxchgweak_acqrel_acquire" => this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Acquire)?, #[rustfmt::skip] - "atomic_cxchgweak_relaxed" => + "atomic_cxchgweak_relaxed_relaxed" => this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::Relaxed, AtomicReadOp::Relaxed)?, #[rustfmt::skip] - "atomic_cxchgweak_acq_failrelaxed" => + "atomic_cxchgweak_acquire_relaxed" => this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::Acquire, AtomicReadOp::Relaxed)?, #[rustfmt::skip] - "atomic_cxchgweak_acqrel_failrelaxed" => + "atomic_cxchgweak_acqrel_relaxed" => this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Relaxed)?, #[rustfmt::skip] - "atomic_cxchgweak_failrelaxed" => + "atomic_cxchgweak_seqcst_relaxed" => this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Relaxed)?, #[rustfmt::skip] - "atomic_cxchgweak_failacq" => + "atomic_cxchgweak_seqcst_acquire" => this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Acquire)?, #[rustfmt::skip] - "atomic_or" => + "atomic_or_seqcst" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::SeqCst)?, #[rustfmt::skip] - "atomic_or_acq" => + "atomic_or_acquire" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::Acquire)?, #[rustfmt::skip] - "atomic_or_rel" => + "atomic_or_release" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::Release)?, #[rustfmt::skip] "atomic_or_acqrel" => @@ -961,13 +961,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_or_relaxed" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::Relaxed)?, #[rustfmt::skip] - "atomic_xor" => + "atomic_xor_seqcst" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::SeqCst)?, #[rustfmt::skip] - "atomic_xor_acq" => + "atomic_xor_acquire" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::Acquire)?, #[rustfmt::skip] - "atomic_xor_rel" => + "atomic_xor_release" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::Release)?, #[rustfmt::skip] "atomic_xor_acqrel" => @@ -976,13 +976,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_xor_relaxed" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::Relaxed)?, #[rustfmt::skip] - "atomic_and" => + "atomic_and_seqcst" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::SeqCst)?, #[rustfmt::skip] - "atomic_and_acq" => + "atomic_and_acquire" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::Acquire)?, #[rustfmt::skip] - "atomic_and_rel" => + "atomic_and_release" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::Release)?, #[rustfmt::skip] "atomic_and_acqrel" => @@ -991,13 +991,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_and_relaxed" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::Relaxed)?, #[rustfmt::skip] - "atomic_nand" => + "atomic_nand_seqcst" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::SeqCst)?, #[rustfmt::skip] - "atomic_nand_acq" => + "atomic_nand_acquire" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::Acquire)?, #[rustfmt::skip] - "atomic_nand_rel" => + "atomic_nand_release" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::Release)?, #[rustfmt::skip] "atomic_nand_acqrel" => @@ -1006,13 +1006,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_nand_relaxed" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::Relaxed)?, #[rustfmt::skip] - "atomic_xadd" => + "atomic_xadd_seqcst" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::SeqCst)?, #[rustfmt::skip] - "atomic_xadd_acq" => + "atomic_xadd_acquire" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::Acquire)?, #[rustfmt::skip] - "atomic_xadd_rel" => + "atomic_xadd_release" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::Release)?, #[rustfmt::skip] "atomic_xadd_acqrel" => @@ -1021,13 +1021,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_xadd_relaxed" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::Relaxed)?, #[rustfmt::skip] - "atomic_xsub" => + "atomic_xsub_seqcst" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::SeqCst)?, #[rustfmt::skip] - "atomic_xsub_acq" => + "atomic_xsub_acquire" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::Acquire)?, #[rustfmt::skip] - "atomic_xsub_rel" => + "atomic_xsub_release" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::Release)?, #[rustfmt::skip] "atomic_xsub_acqrel" => @@ -1035,28 +1035,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[rustfmt::skip] "atomic_xsub_relaxed" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::Relaxed)?, - "atomic_min" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, - "atomic_min_acq" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, - "atomic_min_rel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, + "atomic_min_seqcst" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, + "atomic_min_acquire" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, + "atomic_min_release" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, "atomic_min_acqrel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, "atomic_min_relaxed" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Relaxed)?, - "atomic_max" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, - "atomic_max_acq" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, - "atomic_max_rel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, + "atomic_max_seqcst" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, + "atomic_max_acquire" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, + "atomic_max_release" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, "atomic_max_acqrel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, "atomic_max_relaxed" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Relaxed)?, - "atomic_umin" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, - "atomic_umin_acq" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, - "atomic_umin_rel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, + "atomic_umin_seqcst" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, + "atomic_umin_acquire" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, + "atomic_umin_release" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, "atomic_umin_acqrel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, "atomic_umin_relaxed" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Relaxed)?, - "atomic_umax" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, - "atomic_umax_acq" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, - "atomic_umax_rel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, + "atomic_umax_seqcst" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, + "atomic_umax_acquire" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, + "atomic_umax_release" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, "atomic_umax_acqrel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, "atomic_umax_relaxed" => diff --git a/tests/fail/data_race/atomic_read_na_write_race1.rs b/tests/fail/data_race/atomic_read_na_write_race1.rs index 5131e33fef86..5cf2f26bf1f0 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.rs +++ b/tests/fail/data_race/atomic_read_na_write_race1.rs @@ -1,7 +1,7 @@ // ignore-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] -use std::intrinsics::atomic_load; +use std::intrinsics; use std::sync::atomic::AtomicUsize; use std::thread::spawn; @@ -22,7 +22,7 @@ pub fn main() { let j2 = spawn(move || { //Equivalent to: (&*c.0).load(Ordering::SeqCst) - atomic_load(c.0 as *mut usize) //~ ERROR Data race detected between Atomic Load on Thread(id = 2) and Write on Thread(id = 1) + intrinsics::atomic_load_seqcst(c.0 as *mut usize) //~ ERROR Data race detected between Atomic Load on Thread(id = 2) and Write on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_read_na_write_race1.stderr b/tests/fail/data_race/atomic_read_na_write_race1.stderr index 80e79eb553ee..51cdb239507a 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.stderr +++ b/tests/fail/data_race/atomic_read_na_write_race1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: Data race detected between Atomic Load on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/atomic_read_na_write_race1.rs:LL:CC | -LL | atomic_load(c.0 as *mut usize) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Load on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +LL | intrinsics::atomic_load_seqcst(c.0 as *mut usize) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Load on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/panic/double_panic.stderr b/tests/fail/panic/double_panic.stderr index 0dbd68c0984f..c88dfd39e107 100644 --- a/tests/fail/panic/double_panic.stderr +++ b/tests/fail/panic/double_panic.stderr @@ -75,7 +75,6 @@ LL | ABORT(); = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::rt::begin_panic<&str>::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC - = note: inside `std::rt::begin_panic::<&str>` at RUSTLIB/std/src/panicking.rs:LL:CC note: inside `::drop` at RUSTLIB/std/src/panic.rs:LL:CC --> $DIR/double_panic.rs:LL:CC | diff --git a/tests/fail/panic/panic_abort1.stderr b/tests/fail/panic/panic_abort1.stderr index 9610a161280a..808fccaaeca8 100644 --- a/tests/fail/panic/panic_abort1.stderr +++ b/tests/fail/panic/panic_abort1.stderr @@ -12,7 +12,6 @@ LL | ABORT(); = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::rt::begin_panic<&str>::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC - = note: inside `std::rt::begin_panic::<&str>` at RUSTLIB/std/src/panicking.rs:LL:CC note: inside `main` at RUSTLIB/std/src/panic.rs:LL:CC --> $DIR/panic_abort1.rs:LL:CC | diff --git a/tests/fail/panic/panic_abort2.stderr b/tests/fail/panic/panic_abort2.stderr index 0c446323a779..9b86dc92f717 100644 --- a/tests/fail/panic/panic_abort2.stderr +++ b/tests/fail/panic/panic_abort2.stderr @@ -13,7 +13,6 @@ LL | ABORT(); = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::rt::panic_fmt` at RUSTLIB/core/src/panicking.rs:LL:CC note: inside `main` at RUSTLIB/std/src/panic.rs:LL:CC --> $DIR/panic_abort2.rs:LL:CC | diff --git a/tests/fail/panic/panic_abort3.stderr b/tests/fail/panic/panic_abort3.stderr index 2d7b576372e0..2bb50d55bfe4 100644 --- a/tests/fail/panic/panic_abort3.stderr +++ b/tests/fail/panic/panic_abort3.stderr @@ -13,8 +13,6 @@ LL | ABORT(); = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::rt::panic_fmt` at RUSTLIB/core/src/panicking.rs:LL:CC - = note: inside `core::panicking::panic` at RUSTLIB/core/src/panicking.rs:LL:CC note: inside `main` at RUSTLIB/core/src/panic.rs:LL:CC --> $DIR/panic_abort3.rs:LL:CC | diff --git a/tests/fail/panic/panic_abort4.stderr b/tests/fail/panic/panic_abort4.stderr index b0b11248104d..8ab579301612 100644 --- a/tests/fail/panic/panic_abort4.stderr +++ b/tests/fail/panic/panic_abort4.stderr @@ -13,7 +13,6 @@ LL | ABORT(); = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::rt::panic_fmt` at RUSTLIB/core/src/panicking.rs:LL:CC note: inside `main` at RUSTLIB/core/src/panic.rs:LL:CC --> $DIR/panic_abort4.rs:LL:CC | diff --git a/tests/fail/unaligned_pointers/atomic_unaligned.rs b/tests/fail/unaligned_pointers/atomic_unaligned.rs index 7e0704ac6fc0..74dd0b415c93 100644 --- a/tests/fail/unaligned_pointers/atomic_unaligned.rs +++ b/tests/fail/unaligned_pointers/atomic_unaligned.rs @@ -7,7 +7,7 @@ fn main() { let z = [0u32; 2]; let zptr = &z as *const _ as *const u64; unsafe { - ::std::intrinsics::atomic_load(zptr); + ::std::intrinsics::atomic_load_seqcst(zptr); //~^ERROR accessing memory with alignment 4, but alignment 8 is required } } diff --git a/tests/fail/unaligned_pointers/atomic_unaligned.stderr b/tests/fail/unaligned_pointers/atomic_unaligned.stderr index f56e6612fb32..e3b7f4cdbc9a 100644 --- a/tests/fail/unaligned_pointers/atomic_unaligned.stderr +++ b/tests/fail/unaligned_pointers/atomic_unaligned.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required --> $DIR/atomic_unaligned.rs:LL:CC | -LL | ::std::intrinsics::atomic_load(zptr); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required +LL | ::std::intrinsics::atomic_load_seqcst(zptr); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required | = help: this usually indicates that your program performed an invalid operation and caused Undefined Behavior = help: but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives From ea8dba411bdfc9d1ea38a2c9b89e91250137ad29 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 Jun 2022 09:31:11 -0400 Subject: [PATCH 3384/5092] improve atomics test coverage --- tests/pass/atomic.rs | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/tests/pass/atomic.rs b/tests/pass/atomic.rs index 9a9e852ecf50..07b5d5f3d236 100644 --- a/tests/pass/atomic.rs +++ b/tests/pass/atomic.rs @@ -2,7 +2,7 @@ use std::sync::atomic::{compiler_fence, fence, AtomicBool, AtomicIsize, AtomicU6 fn main() { atomic_bool(); - atomic_isize(); + atomic_all_ops(); atomic_u64(); atomic_fences(); weak_sometimes_fails(); @@ -25,6 +25,7 @@ fn atomic_bool() { assert_eq!(*ATOMIC.get_mut(), false); } } + // There isn't a trait to use to make this generic, so just use a macro macro_rules! compare_exchange_weak_loop { ($atom:expr, $from:expr, $to:expr, $succ_order:expr, $fail_order:expr) => { @@ -39,10 +40,40 @@ macro_rules! compare_exchange_weak_loop { } }; } -fn atomic_isize() { - static ATOMIC: AtomicIsize = AtomicIsize::new(0); - // Make sure trans can emit all the intrinsics correctly +/// Make sure we can handle all the intrinsics +fn atomic_all_ops() { + static ATOMIC: AtomicIsize = AtomicIsize::new(0); + static ATOMIC_UNSIGNED: AtomicU64 = AtomicU64::new(0); + + + // loads + for o in [Relaxed, Acquire, SeqCst] { + ATOMIC.load(o); + } + + // stores + for o in [Relaxed, Release, SeqCst] { + ATOMIC.store(1, o); + } + + // most RMWs + for o in [Relaxed, Release, Acquire, AcqRel, SeqCst] { + ATOMIC.swap(0, o); + ATOMIC.fetch_or(0, o); + ATOMIC.fetch_xor(0, o); + ATOMIC.fetch_and(0, o); + ATOMIC.fetch_nand(0, o); + ATOMIC.fetch_add(0, o); + ATOMIC.fetch_sub(0, o); + ATOMIC.fetch_min(0, o); + ATOMIC.fetch_max(0, o); + ATOMIC_UNSIGNED.fetch_min(0, o); + ATOMIC_UNSIGNED.fetch_max(0, o); + } + + // RMWs with deparate failure ordering + ATOMIC.store(0, SeqCst); assert_eq!(ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed), Ok(0)); assert_eq!(ATOMIC.compare_exchange(0, 2, Acquire, Relaxed), Err(1)); assert_eq!(ATOMIC.compare_exchange(0, 1, Release, Relaxed), Err(1)); @@ -59,7 +90,6 @@ fn atomic_isize() { assert_eq!(ATOMIC.compare_exchange_weak(0, 1, Release, Relaxed), Err(1)); compare_exchange_weak_loop!(ATOMIC, 1, 0, AcqRel, Relaxed); assert_eq!(ATOMIC.load(Relaxed), 0); - ATOMIC.compare_exchange_weak(0, 1, AcqRel, Relaxed).ok(); ATOMIC.compare_exchange_weak(0, 1, SeqCst, Relaxed).ok(); ATOMIC.compare_exchange_weak(0, 1, Acquire, Acquire).ok(); ATOMIC.compare_exchange_weak(0, 1, AcqRel, Acquire).ok(); From f389d46b04c42c3f85ceeb182eabeac94a392b7b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 Jun 2022 09:33:12 -0400 Subject: [PATCH 3385/5092] also prune caller_location frames when backtrace=off --- src/diagnostics.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 95252a113429..55598c19ef6b 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -96,6 +96,9 @@ fn prune_stacktrace<'mir, 'tcx>( ) -> (Vec>, bool) { match ecx.machine.backtrace_style { BacktraceStyle::Off => { + // Remove all frames marked with `caller_location` -- that attribute indicates we + // usually want to point at the caller, not them. + stacktrace.retain(|frame| !frame.instance.def.requires_caller_location(*ecx.tcx)); // Retain one frame so that we can print a span for the error itself stacktrace.truncate(1); (stacktrace, false) From 839c120b40bf14cf4dd51b03b0af3ce7eaf0502d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 Jun 2022 10:09:18 -0400 Subject: [PATCH 3386/5092] fmt --- src/shims/intrinsics.rs | 39 ++++++++++++++++++++++++++------------- tests/pass/atomic.rs | 1 - 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index fa5a6e9c273e..592683201158 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -877,11 +877,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_fence_acqrel" => this.atomic_fence(args, AtomicFenceOp::AcqRel)?, "atomic_fence_seqcst" => this.atomic_fence(args, AtomicFenceOp::SeqCst)?, - "atomic_singlethreadfence_acquire" => this.compiler_fence(args, AtomicFenceOp::Acquire)?, - "atomic_singlethreadfence_release" => this.compiler_fence(args, AtomicFenceOp::Release)?, + "atomic_singlethreadfence_acquire" => + this.compiler_fence(args, AtomicFenceOp::Acquire)?, + "atomic_singlethreadfence_release" => + this.compiler_fence(args, AtomicFenceOp::Release)?, "atomic_singlethreadfence_acqrel" => this.compiler_fence(args, AtomicFenceOp::AcqRel)?, - "atomic_singlethreadfence_seqcst" => this.compiler_fence(args, AtomicFenceOp::SeqCst)?, + "atomic_singlethreadfence_seqcst" => + this.compiler_fence(args, AtomicFenceOp::SeqCst)?, "atomic_xchg_seqcst" => this.atomic_exchange(args, dest, AtomicRwOp::SeqCst)?, "atomic_xchg_acquire" => this.atomic_exchange(args, dest, AtomicRwOp::Acquire)?, @@ -1036,27 +1039,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_xsub_relaxed" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::Relaxed)?, "atomic_min_seqcst" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, - "atomic_min_acquire" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, - "atomic_min_release" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, + "atomic_min_acquire" => + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, + "atomic_min_release" => + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, "atomic_min_acqrel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, "atomic_min_relaxed" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Relaxed)?, "atomic_max_seqcst" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, - "atomic_max_acquire" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, - "atomic_max_release" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, + "atomic_max_acquire" => + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, + "atomic_max_release" => + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, "atomic_max_acqrel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, "atomic_max_relaxed" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Relaxed)?, - "atomic_umin_seqcst" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, - "atomic_umin_acquire" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, - "atomic_umin_release" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, + "atomic_umin_seqcst" => + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, + "atomic_umin_acquire" => + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, + "atomic_umin_release" => + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, "atomic_umin_acqrel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, "atomic_umin_relaxed" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Relaxed)?, - "atomic_umax_seqcst" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, - "atomic_umax_acquire" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, - "atomic_umax_release" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, + "atomic_umax_seqcst" => + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, + "atomic_umax_acquire" => + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, + "atomic_umax_release" => + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, "atomic_umax_acqrel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, "atomic_umax_relaxed" => diff --git a/tests/pass/atomic.rs b/tests/pass/atomic.rs index 07b5d5f3d236..b0c3cc889d55 100644 --- a/tests/pass/atomic.rs +++ b/tests/pass/atomic.rs @@ -46,7 +46,6 @@ fn atomic_all_ops() { static ATOMIC: AtomicIsize = AtomicIsize::new(0); static ATOMIC_UNSIGNED: AtomicU64 = AtomicU64::new(0); - // loads for o in [Relaxed, Acquire, SeqCst] { ATOMIC.load(o); From 6f7c0c0a2ab186a2393acbeac4107390d98e2d82 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 Jun 2022 10:14:26 -0400 Subject: [PATCH 3387/5092] revert --color=always changes --- cargo-miri/bin.rs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 4d7b7da6634c..9627adeb2e79 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -952,17 +952,8 @@ fn phase_runner(binary: &Path, binary_args: env::Args, phase: RunnerPhase) { assert!(suffix.starts_with('=')); // Drop this argument. } else if let Some(suffix) = arg.strip_prefix(json_flag) { - let suffix = suffix.strip_prefix('=').unwrap(); - // This is how we pass through --color=always. We detect that Cargo is detecting rustc - // to emit the diagnostic structure that Cargo would consume from rustc to emit colored - // diagnostics, and ask rustc to emit them. - // See https://github.com/rust-lang/miri/issues/2037 - // First skip over the leading `=`, then check for diagnostic-rendered-ansi in the - // comma-separated list - if suffix.split(',').any(|a| a == "diagnostic-rendered-ansi") { - cmd.arg("--color=always"); - } - // But aside from remembering that colored output was requested, drop this argument. + assert!(suffix.starts_with('=')); + // Drop this argument. } else { cmd.arg(arg); } From ad549194f9cb66a884e5a374e1bc491dcdd7f21c Mon Sep 17 00:00:00 2001 From: Christian Legnitto Date: Wed, 29 Jun 2022 13:14:30 -0400 Subject: [PATCH 3388/5092] Update path to passing tests in CONTRIBUTING.md examples This appears to be renamed from `tests/run-pass` to `tests/pass`. --- CONTRIBUTING.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4def6dc1b691..ad8bd2a17a6c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -60,8 +60,8 @@ generation and linking obviously will have no effect) [and more][miri-flags]. For example, you can (cross-)run the driver on a particular file by doing ```sh -./miri run tests/run-pass/format.rs -./miri run tests/run-pass/hello.rs --target i686-unknown-linux-gnu +./miri run tests/pass/format.rs +./miri run tests/pass/hello.rs --target i686-unknown-linux-gnu ``` and you can (cross-)run the entire test suite using: @@ -79,7 +79,7 @@ You can get a trace of which MIR statements are being executed by setting the `MIRI_LOG` environment variable. For example: ```sh -MIRI_LOG=info ./miri run tests/run-pass/vec.rs +MIRI_LOG=info ./miri run tests/pass/vec.rs ``` Setting `MIRI_LOG` like this will configure logging for Miri itself as well as @@ -88,7 +88,7 @@ can also do more targeted configuration, e.g. the following helps debug the stacked borrows implementation: ```sh -MIRI_LOG=rustc_mir::interpret=info,miri::stacked_borrows ./miri run tests/run-pass/vec.rs +MIRI_LOG=rustc_mir::interpret=info,miri::stacked_borrows ./miri run tests/pass/vec.rs ``` In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an From 73a1a27a450c0a7c0bfcab258230bb3165d9c05c Mon Sep 17 00:00:00 2001 From: Christian Legnitto Date: Wed, 29 Jun 2022 13:30:30 -0400 Subject: [PATCH 3389/5092] Support `gettimeofday` on more than macos This appears to be in linux and in openbsd as well: * https://github.com/torvalds/linux/blob/master/lib/vdso/gettimeofday.c * https://github.com/openbsd/src/blob/master/sys/sys/time.h#L439 Co-authored-by: Ralf Jung --- src/shims/time.rs | 2 +- src/shims/unix/foreign_items.rs | 7 +++++++ src/shims/unix/macos/foreign_items.rs | 5 ----- tests/pass/libc.rs | 22 ++++++++++++++++++++++ 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index be453a429ec5..0fd5cebd2345 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -64,7 +64,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.assert_target_os("macos", "gettimeofday"); + this.assert_target_os_is_unix("gettimeofday"); this.check_no_isolation("`gettimeofday`")?; // Using tz is obsolete and should always be null diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index d0c93ef4cdaf..4a452800044f 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -139,6 +139,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } + // Time related shims + "gettimeofday" => { + let [tv, tz] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.gettimeofday(tv, tz)?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + // Allocation "posix_memalign" => { let [ret, align, size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/shims/unix/macos/foreign_items.rs b/src/shims/unix/macos/foreign_items.rs index f7dd38f639b0..e545a4691bf0 100644 --- a/src/shims/unix/macos/foreign_items.rs +++ b/src/shims/unix/macos/foreign_items.rs @@ -78,11 +78,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Time related shims - "gettimeofday" => { - let [tv, tz] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let result = this.gettimeofday(tv, tz)?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } "mach_absolute_time" => { let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.mach_absolute_time()?; diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index e73e796449cc..b108a01dae37 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -290,10 +290,32 @@ fn test_clocks() { assert_eq!(is_error, 0); } +fn test_posix_gettimeofday() { + let mut tp = std::mem::MaybeUninit::::uninit(); + let tz = std::ptr::null_mut::(); + #[cfg(target_os = "macos")] // `tz` has a different type on macOS + let tz = tz as *mut libc::c_void; + let is_error = unsafe { libc::gettimeofday(tp.as_mut_ptr(), tz) }; + assert_eq!(is_error, 0); + let tv = unsafe { tp.assume_init() }; + assert!(tv.tv_sec > 0); + assert!(tv.tv_usec >= 0); // Theoretically this could be 0. + + // Test that non-null tz returns an error. + let mut tz = std::mem::MaybeUninit::::uninit(); + let tz_ptr = tz.as_mut_ptr(); + #[cfg(target_os = "macos")] // `tz` has a different type on macOS + let tz_ptr = tz_ptr as *mut libc::c_void; + let is_error = unsafe { libc::gettimeofday(tp.as_mut_ptr(), tz_ptr) }; + assert_eq!(is_error, -1); +} + fn main() { #[cfg(any(target_os = "linux", target_os = "freebsd"))] test_posix_fadvise(); + test_posix_gettimeofday(); + #[cfg(any(target_os = "linux", target_os = "freebsd"))] test_sync_file_range(); From 02f8cb2d551d06e24b4072c6caf1bf0e129f2eba Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 Jun 2022 18:14:41 -0400 Subject: [PATCH 3390/5092] add ./miri clippy --- .github/workflows/ci.yml | 8 ++------ miri | 8 ++++++++ rustup-toolchain | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c603d1f5d254..7d6e39dc31b2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -98,12 +98,8 @@ jobs: ./rustup-toolchain "" -c clippy - name: rustfmt run: ./miri fmt --check - - name: clippy (miri) - run: cargo clippy --all-targets -- -D warnings - #- name: Clippy (ui_test) - # run: cargo clippy --manifest-path ui_test/Cargo.toml --all-targets -- -D warnings - - name: clippy (cargo-miri) - run: cargo clippy --manifest-path cargo-miri/Cargo.toml --all-targets -- -D warnings + - name: clippy + run: ./miri clippy -- -D warnings - name: rustdoc run: RUSTDOCFLAGS="-Dwarnings" cargo doc --document-private-items diff --git a/miri b/miri index e89a9e380fff..4dd34e0ef6c5 100755 --- a/miri +++ b/miri @@ -28,6 +28,9 @@ times and slower execution times. ./miri fmt : Format all sources and tests. are passed to `rustfmt`. +./miri clippy : +Format all sources and tests. are passed to `cargo clippy`. + ENVIRONMENT VARIABLES MIRI_SYSROOT: @@ -163,6 +166,11 @@ fmt) find "$MIRIDIR" -not \( -name target -prune \) -name '*.rs' \ | xargs rustfmt --edition=2021 --config-path "$MIRIDIR/rustfmt.toml" "$@" ;; +clippy) + cargo clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@" + #cargo clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml --all-targets "$@" + cargo clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" + ;; *) if [ -n "$COMMAND" ]; then echo "Unknown command: $COMMAND" diff --git a/rustup-toolchain b/rustup-toolchain index 34472c727f62..7b9a17145d05 100755 --- a/rustup-toolchain +++ b/rustup-toolchain @@ -42,7 +42,7 @@ fi # Install and setup new toolchain. rustup toolchain uninstall miri -rustup-toolchain-install-master -n miri -c cargo -c rust-src -c rustc-dev -c llvm-tools -c rustfmt "$@" -- "$NEW_COMMIT" +rustup-toolchain-install-master -n miri -c cargo -c rust-src -c rustc-dev -c llvm-tools -c rustfmt -c clippy "$@" -- "$NEW_COMMIT" rustup override set miri # Cleanup. From e33efc75171ca48dfcd30984dfc356cdbfc5c1e4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 Jun 2022 18:17:28 -0400 Subject: [PATCH 3391/5092] make ui_test pass clippy --- miri | 2 +- ui_test/src/comments.rs | 2 +- ui_test/src/lib.rs | 8 +++++--- ui_test/src/rustc_stderr.rs | 6 +++--- ui_test/src/tests.rs | 2 +- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/miri b/miri index 4dd34e0ef6c5..6b7e9dbf03f8 100755 --- a/miri +++ b/miri @@ -168,7 +168,7 @@ fmt) ;; clippy) cargo clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@" - #cargo clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml --all-targets "$@" + cargo clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml --all-targets "$@" cargo clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" ;; *) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 43c687e9c9a5..e7b4968a9ca6 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -90,7 +90,7 @@ impl Comments { path.display() ); this.revisions = - Some(revisions.trim().split_whitespace().map(|s| s.to_string()).collect()); + Some(revisions.split_whitespace().map(|s| s.to_string()).collect()); } if let Some(s) = line.strip_prefix("// ignore-") { let s = s diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 30e1296f7b39..ff0c4e1c8996 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -1,3 +1,5 @@ +#![allow(clippy::enum_variant_names, clippy::useless_format, clippy::too_many_arguments)] + use std::collections::VecDeque; use std::fmt::Write; use std::path::{Path, PathBuf}; @@ -338,17 +340,17 @@ fn check_test_result( revised("stderr"), target, &config.stderr_filters, - &config, + config, comments, ); check_output( - &stdout, + stdout, path, errors, revised("stdout"), target, &config.stdout_filters, - &config, + config, comments, ); // Check error annotations in the source against output diff --git a/ui_test/src/rustc_stderr.rs b/ui_test/src/rustc_stderr.rs index 2d3845752e9a..ea32ce4bd293 100644 --- a/ui_test/src/rustc_stderr.rs +++ b/ui_test/src/rustc_stderr.rs @@ -117,16 +117,16 @@ impl Span { pub(crate) fn filter_annotations_from_rendered(rendered: &str) -> std::borrow::Cow<'_, str> { let annotations = Regex::new(r"\s*//(\[[^\]]\])?~.*").unwrap(); - annotations.replace_all(&rendered, "") + annotations.replace_all(rendered, "") } pub(crate) fn process(file: &Path, stderr: &[u8]) -> Diagnostics { - let stderr = std::str::from_utf8(&stderr).unwrap(); + let stderr = std::str::from_utf8(stderr).unwrap(); let mut rendered = String::new(); let mut messages = vec![]; let mut messages_from_unknown_file_or_line = vec![]; for line in stderr.lines() { - if line.starts_with("{") { + if line.starts_with('{') { match serde_json::from_str::(line) { Ok(msg) => { write!( diff --git a/ui_test/src/tests.rs b/ui_test/src/tests.rs index 7e08a68be7b9..a45f8f8933c9 100644 --- a/ui_test/src/tests.rs +++ b/ui_test/src/tests.rs @@ -29,7 +29,7 @@ fn main() { } "; let path = Path::new("$DIR/"); - let comments = Comments::parse(&path, s); + let comments = Comments::parse(path, s); let mut errors = vec![]; let config = config(); let messages = vec![ From c4e86e103ec7e7c70376d178369eff084db8d237 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 Jun 2022 17:53:09 -0400 Subject: [PATCH 3392/5092] add option for recursive field retagging --- README.md | 3 + rust-version | 2 +- src/bin/miri.rs | 2 + src/eval.rs | 3 + src/machine.rs | 1 + src/stacked_borrows.rs | 69 +++++++++++++++++-- .../fail/stacked_borrows/newtype_retagging.rs | 19 +++++ .../stacked_borrows/newtype_retagging.stderr | 50 ++++++++++++++ .../stacked-borrows/interior_mutability.rs | 1 + tests/pass/stacked-borrows/refcell.rs | 1 + tests/pass/stacked-borrows/stacked-borrows.rs | 1 + 11 files changed, 146 insertions(+), 6 deletions(-) create mode 100644 tests/fail/stacked_borrows/newtype_retagging.rs create mode 100644 tests/fail/stacked_borrows/newtype_retagging.stderr diff --git a/README.md b/README.md index a7ee11e82e0f..bfc32d04a9d1 100644 --- a/README.md +++ b/README.md @@ -369,6 +369,9 @@ to Miri failing to detect cases of undefined behavior in a program. application instead of raising an error within the context of Miri (and halting execution). Note that code might not expect these operations to ever panic, so this flag can lead to strange (mis)behavior. +* `-Zmiri-retag-fields` changes Stacked Borrows retagging to recurse into fields. + This means that references in fields of structs/enums/tuples/arrays/... are retagged, + and in particular, they are protected when passed as function arguments. * `-Zmiri-track-alloc-id=,,...` shows a backtrace when the given allocations are being allocated or freed. This helps in debugging memory leaks and use after free bugs. Specifying this argument multiple times does not overwrite the previous diff --git a/rust-version b/rust-version index 4f24d29e34b4..323af716826d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -493c960a3e6cdd2e2fbe8b6ea130fadea05f1ab0 +ddcbba036aee08f0709f98a92a342a278eae5c05 diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 1ccc54d6be19..4f00e4be18ab 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -383,6 +383,8 @@ fn main() { miri_config.provenance_mode = ProvenanceMode::Permissive; } else if arg == "-Zmiri-mute-stdout-stderr" { miri_config.mute_stdout_stderr = true; + } else if arg == "-Zmiri-retag-fields" { + miri_config.retag_fields = true; } else if arg == "-Zmiri-track-raw-pointers" { eprintln!( "WARNING: `-Zmiri-track-raw-pointers` has no effect; it is enabled by default" diff --git a/src/eval.rs b/src/eval.rs index 12f1f52c78a3..c9fc05500a3c 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -124,6 +124,8 @@ pub struct MiriConfig { pub preemption_rate: f64, /// Report the current instruction being executed every N basic blocks. pub report_progress: Option, + /// Whether Stacked Borrows retagging should recurse into fields of datatypes. + pub retag_fields: bool, } impl Default for MiriConfig { @@ -154,6 +156,7 @@ impl Default for MiriConfig { mute_stdout_stderr: false, preemption_rate: 0.01, // 1% report_progress: None, + retag_fields: false, } } } diff --git a/src/machine.rs b/src/machine.rs index 5b1847545897..4aeb42d3d0fe 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -354,6 +354,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { Some(RefCell::new(stacked_borrows::GlobalStateInner::new( config.tracked_pointer_tags.clone(), config.tracked_call_ids.clone(), + config.retag_fields, ))) } else { None diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 66f756d7b08d..3fc0eaf10c09 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -156,6 +156,8 @@ pub struct GlobalStateInner { tracked_pointer_tags: HashSet, /// The call ids to trace tracked_call_ids: HashSet, + /// Whether to recurse into datatypes when searching for pointers to retag. + retag_fields: bool, } /// We need interior mutable access to the global state. @@ -204,7 +206,11 @@ impl fmt::Display for RefKind { /// Utilities for initialization and ID generation impl GlobalStateInner { - pub fn new(tracked_pointer_tags: HashSet, tracked_call_ids: HashSet) -> Self { + pub fn new( + tracked_pointer_tags: HashSet, + tracked_call_ids: HashSet, + retag_fields: bool, + ) -> Self { GlobalStateInner { next_ptr_tag: SbTag(NonZeroU64::new(1).unwrap()), base_ptr_tags: FxHashMap::default(), @@ -212,6 +218,7 @@ impl GlobalStateInner { active_calls: FxHashSet::default(), tracked_pointer_tags, tracked_call_ids, + retag_fields, } } @@ -1035,17 +1042,69 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - // We only reborrow "bare" references/boxes. - // Not traversing into fields helps with , - // but might also cost us optimization and analyses. We will have to experiment more with this. + // We need a visitor to visit all references. However, that requires + // a `MPlaceTy` (or `OpTy), so we have a fast path for reference types that + // avoids allocating. + if let Some((mutbl, protector)) = qualify(place.layout.ty, kind) { // Fast path. let val = this.read_immediate(&this.place_to_op(place)?)?; let val = this.retag_reference(&val, mutbl, protector)?; this.write_immediate(*val, place)?; + return Ok(()); } - Ok(()) + // If we don't want to recurse, we are already done. + if !this.machine.stacked_borrows.as_mut().unwrap().get_mut().retag_fields { + return Ok(()); + } + + // Skip some types that have no further structure we might care about. + if matches!( + place.layout.ty.kind(), + ty::RawPtr(..) + | ty::Ref(..) + | ty::Int(..) + | ty::Uint(..) + | ty::Float(..) + | ty::Bool + | ty::Char + ) { + return Ok(()); + } + // Now go visit this thing. + let place = this.force_allocation(place)?; + + let mut visitor = RetagVisitor { ecx: this, kind }; + return visitor.visit_value(&place); + + // The actual visitor. + struct RetagVisitor<'ecx, 'mir, 'tcx> { + ecx: &'ecx mut MiriEvalContext<'mir, 'tcx>, + kind: RetagKind, + } + impl<'ecx, 'mir, 'tcx> MutValueVisitor<'mir, 'tcx, Evaluator<'mir, 'tcx>> + for RetagVisitor<'ecx, 'mir, 'tcx> + { + type V = MPlaceTy<'tcx, Tag>; + + #[inline(always)] + fn ecx(&mut self) -> &mut MiriEvalContext<'mir, 'tcx> { + &mut self.ecx + } + + fn visit_value(&mut self, place: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + if let Some((mutbl, protector)) = qualify(place.layout.ty, self.kind) { + let val = self.ecx.read_immediate(&place.into())?; + let val = self.ecx.retag_reference(&val, mutbl, protector)?; + self.ecx.write_immediate(*val, &(*place).into())?; + } else { + // Maybe we need to go deeper. + self.walk_value(place)?; + } + Ok(()) + } + } } /// After a stack frame got pushed, retag the return place so that we are sure diff --git a/tests/fail/stacked_borrows/newtype_retagging.rs b/tests/fail/stacked_borrows/newtype_retagging.rs new file mode 100644 index 000000000000..8f932f08086a --- /dev/null +++ b/tests/fail/stacked_borrows/newtype_retagging.rs @@ -0,0 +1,19 @@ +// compile-flags: -Zmiri-retag-fields +// error-pattern: incompatible item is protected +struct Newtype<'a>(&'a mut i32); + +fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) { + dealloc(); +} + +// Make sure that we protect references inside structs. +fn main() { + let ptr = Box::into_raw(Box::new(0i32)); + #[rustfmt::skip] // I like my newlines + unsafe { + dealloc_while_running( + Newtype(&mut *ptr), + || drop(Box::from_raw(ptr)), + ) + }; +} diff --git a/tests/fail/stacked_borrows/newtype_retagging.stderr b/tests/fail/stacked_borrows/newtype_retagging.stderr new file mode 100644 index 000000000000..f65231b661f9 --- /dev/null +++ b/tests/fail/stacked_borrows/newtype_retagging.stderr @@ -0,0 +1,50 @@ +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] + --> RUSTLIB/alloc/src/boxed.rs:LL:CC + | +LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/newtype_retagging.rs:LL:CC + | +LL | let ptr = Box::into_raw(Box::new(0i32)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: was protected due to which was created here + --> $DIR/newtype_retagging.rs:LL:CC + | +LL | Newtype(&mut *ptr), + | ^^^^^^^^^^^^^^^^^^ +help: this protector is live for this call + --> $DIR/newtype_retagging.rs:LL:CC + | +LL | / fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) { +LL | | dealloc(); +LL | | } + | |_^ + = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC + = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC +note: inside closure at $DIR/newtype_retagging.rs:LL:CC + --> $DIR/newtype_retagging.rs:LL:CC + | +LL | || drop(Box::from_raw(ptr)), + | ^^^^^^^^^^^^^^^^^^ +note: inside `dealloc_while_running::<[closure@$DIR/newtype_retagging.rs:LL:CC]>` at $DIR/newtype_retagging.rs:LL:CC + --> $DIR/newtype_retagging.rs:LL:CC + | +LL | dealloc(); + | ^^^^^^^^^ +note: inside `main` at $DIR/newtype_retagging.rs:LL:CC + --> $DIR/newtype_retagging.rs:LL:CC + | +LL | / dealloc_while_running( +LL | | Newtype(&mut *ptr), +LL | | || drop(Box::from_raw(ptr)), +LL | | ) + | |_________^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/pass/stacked-borrows/interior_mutability.rs b/tests/pass/stacked-borrows/interior_mutability.rs index 79958ab5539d..6ac364b716c5 100644 --- a/tests/pass/stacked-borrows/interior_mutability.rs +++ b/tests/pass/stacked-borrows/interior_mutability.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-retag-fields use std::cell::{Cell, RefCell, UnsafeCell}; use std::mem::{self, MaybeUninit}; diff --git a/tests/pass/stacked-borrows/refcell.rs b/tests/pass/stacked-borrows/refcell.rs index ecb6f48d30b0..e9d7f6715288 100644 --- a/tests/pass/stacked-borrows/refcell.rs +++ b/tests/pass/stacked-borrows/refcell.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-retag-fields use std::cell::{Ref, RefCell, RefMut}; fn main() { diff --git a/tests/pass/stacked-borrows/stacked-borrows.rs b/tests/pass/stacked-borrows/stacked-borrows.rs index eb0ff167eb12..3669a08a1bc4 100644 --- a/tests/pass/stacked-borrows/stacked-borrows.rs +++ b/tests/pass/stacked-borrows/stacked-borrows.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-retag-fields use std::ptr; // Test various stacked-borrows-related things. From 955f961f8327926477ea906a7f4140d5b9dbfa45 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 Jun 2022 17:56:47 -0400 Subject: [PATCH 3393/5092] merge two SB test files --- .../stacked-borrows/interior_mutability.rs | 75 +++++++++++++++++- tests/pass/stacked-borrows/refcell.rs | 78 ------------------- 2 files changed, 74 insertions(+), 79 deletions(-) delete mode 100644 tests/pass/stacked-borrows/refcell.rs diff --git a/tests/pass/stacked-borrows/interior_mutability.rs b/tests/pass/stacked-borrows/interior_mutability.rs index 6ac364b716c5..96ad67505a73 100644 --- a/tests/pass/stacked-borrows/interior_mutability.rs +++ b/tests/pass/stacked-borrows/interior_mutability.rs @@ -1,5 +1,5 @@ // compile-flags: -Zmiri-retag-fields -use std::cell::{Cell, RefCell, UnsafeCell}; +use std::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell}; use std::mem::{self, MaybeUninit}; fn main() { @@ -9,6 +9,10 @@ fn main() { unsafe_cell_2phase(); unsafe_cell_deallocate(); unsafe_cell_invalidate(); + refcell_basic(); + ref_protector(); + ref_mut_protector(); + rust_issue_68303(); } fn aliasing_mut_and_shr() { @@ -100,3 +104,72 @@ fn unsafe_cell_invalidate() { // So using raw1 invalidates raw2. f(unsafe { mem::transmute(raw2) }, raw1); } + +fn refcell_basic() { + let c = RefCell::new(42); + { + let s1 = c.borrow(); + let _x: i32 = *s1; + let s2 = c.borrow(); + let _x: i32 = *s1; + let _y: i32 = *s2; + let _x: i32 = *s1; + let _y: i32 = *s2; + } + { + let mut m = c.borrow_mut(); + let _z: i32 = *m; + { + let s: &i32 = &*m; + let _x = *s; + } + *m = 23; + let _z: i32 = *m; + } + { + let s1 = c.borrow(); + let _x: i32 = *s1; + let s2 = c.borrow(); + let _x: i32 = *s1; + let _y: i32 = *s2; + let _x: i32 = *s1; + let _y: i32 = *s2; + } +} + +// Adding a Stacked Borrows protector for `Ref` would break this +fn ref_protector() { + fn break_it(rc: &RefCell, r: Ref<'_, i32>) { + // `r` has a shared reference, it is passed in as argument and hence + // a protector is added that marks this memory as read-only for the entire + // duration of this function. + drop(r); + // *oops* here we can mutate that memory. + *rc.borrow_mut() = 2; + } + + let rc = RefCell::new(0); + break_it(&rc, rc.borrow()) +} + +fn ref_mut_protector() { + fn break_it(rc: &RefCell, r: RefMut<'_, i32>) { + // `r` has a shared reference, it is passed in as argument and hence + // a protector is added that marks this memory as inaccessible for the entire + // duration of this function + drop(r); + // *oops* here we can mutate that memory. + *rc.borrow_mut() = 2; + } + + let rc = RefCell::new(0); + break_it(&rc, rc.borrow_mut()) +} + +/// Make sure we do not have bad enum layout optimizations. +fn rust_issue_68303() { + let optional = Some(RefCell::new(false)); + let mut handle = optional.as_ref().unwrap().borrow_mut(); + assert!(optional.is_some()); + *handle = true; +} diff --git a/tests/pass/stacked-borrows/refcell.rs b/tests/pass/stacked-borrows/refcell.rs deleted file mode 100644 index e9d7f6715288..000000000000 --- a/tests/pass/stacked-borrows/refcell.rs +++ /dev/null @@ -1,78 +0,0 @@ -// compile-flags: -Zmiri-retag-fields -use std::cell::{Ref, RefCell, RefMut}; - -fn main() { - basic(); - ref_protector(); - ref_mut_protector(); - rust_issue_68303(); -} - -fn basic() { - let c = RefCell::new(42); - { - let s1 = c.borrow(); - let _x: i32 = *s1; - let s2 = c.borrow(); - let _x: i32 = *s1; - let _y: i32 = *s2; - let _x: i32 = *s1; - let _y: i32 = *s2; - } - { - let mut m = c.borrow_mut(); - let _z: i32 = *m; - { - let s: &i32 = &*m; - let _x = *s; - } - *m = 23; - let _z: i32 = *m; - } - { - let s1 = c.borrow(); - let _x: i32 = *s1; - let s2 = c.borrow(); - let _x: i32 = *s1; - let _y: i32 = *s2; - let _x: i32 = *s1; - let _y: i32 = *s2; - } -} - -// Adding a Stacked Borrows protector for `Ref` would break this -fn ref_protector() { - fn break_it(rc: &RefCell, r: Ref<'_, i32>) { - // `r` has a shared reference, it is passed in as argument and hence - // a protector is added that marks this memory as read-only for the entire - // duration of this function. - drop(r); - // *oops* here we can mutate that memory. - *rc.borrow_mut() = 2; - } - - let rc = RefCell::new(0); - break_it(&rc, rc.borrow()) -} - -fn ref_mut_protector() { - fn break_it(rc: &RefCell, r: RefMut<'_, i32>) { - // `r` has a shared reference, it is passed in as argument and hence - // a protector is added that marks this memory as inaccessible for the entire - // duration of this function - drop(r); - // *oops* here we can mutate that memory. - *rc.borrow_mut() = 2; - } - - let rc = RefCell::new(0); - break_it(&rc, rc.borrow_mut()) -} - -/// Make sure we do not have bad enum layout optimizations. -fn rust_issue_68303() { - let optional = Some(RefCell::new(false)); - let mut handle = optional.as_ref().unwrap().borrow_mut(); - assert!(optional.is_some()); - *handle = true; -} From a2e61aeeff0b5522eb8929a60326d0191f168f39 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 Jun 2022 21:31:27 -0400 Subject: [PATCH 3394/5092] rustup --- rust-version | 2 +- tests/fail/branchless-select-i128-pointer.rs | 2 +- tests/fail/branchless-select-i128-pointer.stderr | 4 ++-- tests/fail/issue-miri-1112.stderr | 4 ++-- tests/fail/stacked_borrows/vtable.stderr | 4 ++-- tests/fail/transmute-pair-uninit.stderr | 4 ++-- tests/fail/transmute_fat1.rs | 2 +- tests/fail/transmute_fat1.stderr | 4 ++-- tests/fail/uninit_byte_read.stderr | 4 ++-- tests/fail/uninit_raw_ptr.rs | 2 +- tests/fail/uninit_raw_ptr.stderr | 4 ++-- tests/fail/validity/cast_fn_ptr1.stderr | 4 ++-- tests/fail/validity/cast_fn_ptr2.stderr | 4 ++-- tests/fail/validity/dangling_ref1.stderr | 4 ++-- tests/fail/validity/dangling_ref2.stderr | 4 ++-- tests/fail/validity/dangling_ref3.stderr | 4 ++-- tests/fail/validity/invalid_bool.stderr | 4 ++-- tests/fail/validity/invalid_bool_uninit.stderr | 4 ++-- tests/fail/validity/invalid_char.stderr | 4 ++-- tests/fail/validity/invalid_char_uninit.stderr | 4 ++-- tests/fail/validity/invalid_enum_tag.rs | 2 +- tests/fail/validity/invalid_enum_tag.stderr | 6 +++--- tests/fail/validity/invalid_enum_tag_256variants_uninit.rs | 2 +- .../validity/invalid_enum_tag_256variants_uninit.stderr | 4 ++-- tests/fail/validity/invalid_fnptr_null.stderr | 4 ++-- tests/fail/validity/invalid_fnptr_uninit.stderr | 4 ++-- tests/fail/validity/invalid_wide_raw.stderr | 4 ++-- tests/fail/validity/nonzero.stderr | 4 ++-- tests/fail/validity/ptr_integer_array_transmute.stderr | 4 ++-- tests/fail/validity/ref_to_uninhabited1.stderr | 4 ++-- tests/fail/validity/ref_to_uninhabited2.stderr | 4 ++-- tests/fail/validity/too-big-slice.stderr | 4 ++-- tests/fail/validity/too-big-unsized.stderr | 4 ++-- tests/fail/validity/transmute_through_ptr.rs | 2 +- tests/fail/validity/transmute_through_ptr.stderr | 4 ++-- tests/fail/validity/uninit_float.rs | 2 +- tests/fail/validity/uninit_float.stderr | 4 ++-- tests/fail/validity/uninit_integer.rs | 2 +- tests/fail/validity/uninit_integer.stderr | 4 ++-- tests/fail/validity/uninit_integer_signed.rs | 2 +- tests/fail/validity/uninit_integer_signed.stderr | 4 ++-- 41 files changed, 73 insertions(+), 73 deletions(-) diff --git a/rust-version b/rust-version index 323af716826d..1ab8e6b5a8ce 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -ddcbba036aee08f0709f98a92a342a278eae5c05 +bf45371f262e184b4a77adea88c8ac01ac79759b diff --git a/tests/fail/branchless-select-i128-pointer.rs b/tests/fail/branchless-select-i128-pointer.rs index 7e1b969e02cf..a3b4021ba0c2 100644 --- a/tests/fail/branchless-select-i128-pointer.rs +++ b/tests/fail/branchless-select-i128-pointer.rs @@ -12,7 +12,7 @@ fn main() { // However, it drops provenance when transmuting to TwoPtrs, so this is UB. let val = unsafe { transmute::<_, &str>( - //~^ ERROR type validation failed: encountered a dangling reference + //~^ ERROR constructing invalid value: encountered a dangling reference !mask & transmute::<_, TwoPtrs>("false !") | mask & transmute::<_, TwoPtrs>("true !"), ) diff --git a/tests/fail/branchless-select-i128-pointer.stderr b/tests/fail/branchless-select-i128-pointer.stderr index 374d6ab06809..5cb05f33ddea 100644 --- a/tests/fail/branchless-select-i128-pointer.stderr +++ b/tests/fail/branchless-select-i128-pointer.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: type validation failed: encountered a dangling reference (address $HEX is unallocated) +error: Undefined Behavior: constructing invalid value: encountered a dangling reference (address $HEX is unallocated) --> $DIR/branchless-select-i128-pointer.rs:LL:CC | LL | / transmute::<_, &str>( @@ -6,7 +6,7 @@ LL | | LL | | !mask & transmute::<_, TwoPtrs>("false !") LL | | | mask & transmute::<_, TwoPtrs>("true !"), LL | | ) - | |_____________^ type validation failed: encountered a dangling reference (address $HEX is unallocated) + | |_____________^ constructing invalid value: encountered a dangling reference (address $HEX is unallocated) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/issue-miri-1112.stderr b/tests/fail/issue-miri-1112.stderr index 1dfcad0c147b..cf692bddaf44 100644 --- a/tests/fail/issue-miri-1112.stderr +++ b/tests/fail/issue-miri-1112.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered invalid drop function pointer in vtable (function has incompatible signature) +error: Undefined Behavior: constructing invalid value: encountered invalid drop function pointer in vtable (function has incompatible signature) --> $DIR/issue-miri-1112.rs:LL:CC | LL | let obj = std::mem::transmute::(obj); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (function has incompatible signature) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid drop function pointer in vtable (function has incompatible signature) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/stacked_borrows/vtable.stderr b/tests/fail/stacked_borrows/vtable.stderr index ac3d71045f0c..31c3d5982e5e 100644 --- a/tests/fail/stacked_borrows/vtable.stderr +++ b/tests/fail/stacked_borrows/vtable.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered vtable pointer does not have permission to read drop function pointer +error: Undefined Behavior: constructing invalid value: encountered vtable pointer does not have permission to read drop function pointer --> RUSTLIB/core/src/ptr/metadata.rs:LL:CC | LL | unsafe { PtrRepr { components: PtrComponents { data_address, metadata } }.const_ptr } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered vtable pointer does not have permission to read drop function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered vtable pointer does not have permission to read drop function pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/transmute-pair-uninit.stderr b/tests/fail/transmute-pair-uninit.stderr index 833c3abbb2fb..c1f90c3efb6e 100644 --- a/tests/fail/transmute-pair-uninit.stderr +++ b/tests/fail/transmute-pair-uninit.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered uninitialized bytes, but expected initialized bytes +error: Undefined Behavior: constructing invalid value: encountered uninitialized bytes, but expected initialized bytes --> $DIR/transmute-pair-uninit.rs:LL:CC | LL | let v = unsafe { *z.offset(first_undef) }; - | ^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized bytes + | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected initialized bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/transmute_fat1.rs b/tests/fail/transmute_fat1.rs index 79286f3e27dd..a60efb98f9d8 100644 --- a/tests/fail/transmute_fat1.rs +++ b/tests/fail/transmute_fat1.rs @@ -7,7 +7,7 @@ const N: usize = 8; fn main() { let bad = unsafe { std::mem::transmute::<&[u8], [u8; N]>(&[1u8]) - //~^ ERROR: type validation failed: encountered a pointer + //~^ ERROR: constructing invalid value: encountered a pointer }; let _val = bad[0] + bad[bad.len() - 1]; } diff --git a/tests/fail/transmute_fat1.stderr b/tests/fail/transmute_fat1.stderr index baf6195f92ad..6263427bac5b 100644 --- a/tests/fail/transmute_fat1.stderr +++ b/tests/fail/transmute_fat1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered a pointer, but expected plain (non-pointer) bytes +error: Undefined Behavior: constructing invalid value: encountered a pointer, but expected plain (non-pointer) bytes --> $DIR/transmute_fat1.rs:LL:CC | LL | std::mem::transmute::<&[u8], [u8; N]>(&[1u8]) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a pointer, but expected plain (non-pointer) bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/uninit_byte_read.stderr b/tests/fail/uninit_byte_read.stderr index d150be3e7e78..d15b10dc6ed0 100644 --- a/tests/fail/uninit_byte_read.stderr +++ b/tests/fail/uninit_byte_read.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered uninitialized bytes, but expected initialized bytes +error: Undefined Behavior: constructing invalid value: encountered uninitialized bytes, but expected initialized bytes --> $DIR/uninit_byte_read.rs:LL:CC | LL | let undef = unsafe { *v.get_unchecked(5) }; - | ^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized bytes + | ^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected initialized bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/uninit_raw_ptr.rs b/tests/fail/uninit_raw_ptr.rs index beb9ad127094..c2ede1bb146a 100644 --- a/tests/fail/uninit_raw_ptr.rs +++ b/tests/fail/uninit_raw_ptr.rs @@ -1,4 +1,4 @@ fn main() { let _val = unsafe { std::mem::MaybeUninit::<*const u8>::uninit().assume_init() }; - //~^ ERROR type validation failed at .value: encountered uninitialized raw pointer + //~^ ERROR constructing invalid value at .value: encountered uninitialized raw pointer } diff --git a/tests/fail/uninit_raw_ptr.stderr b/tests/fail/uninit_raw_ptr.stderr index 96074fc1e789..c76f59e13e7f 100644 --- a/tests/fail/uninit_raw_ptr.stderr +++ b/tests/fail/uninit_raw_ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed at .value: encountered uninitialized raw pointer +error: Undefined Behavior: constructing invalid value at .value: encountered uninitialized raw pointer --> $DIR/uninit_raw_ptr.rs:LL:CC | LL | let _val = unsafe { std::mem::MaybeUninit::<*const u8>::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized raw pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value: encountered uninitialized raw pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/cast_fn_ptr1.stderr b/tests/fail/validity/cast_fn_ptr1.stderr index d048377a7793..05c75ac13386 100644 --- a/tests/fail/validity/cast_fn_ptr1.stderr +++ b/tests/fail/validity/cast_fn_ptr1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered a null reference +error: Undefined Behavior: constructing invalid value: encountered a null reference --> $DIR/cast_fn_ptr1.rs:LL:CC | LL | g(0usize as *const i32) - | ^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a null reference + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/cast_fn_ptr2.stderr b/tests/fail/validity/cast_fn_ptr2.stderr index 10b9b9b8602b..8bee099caf3b 100644 --- a/tests/fail/validity/cast_fn_ptr2.stderr +++ b/tests/fail/validity/cast_fn_ptr2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered a null reference +error: Undefined Behavior: constructing invalid value: encountered a null reference --> $DIR/cast_fn_ptr2.rs:LL:CC | LL | let _x = g(); - | ^^^ type validation failed: encountered a null reference + | ^^^ constructing invalid value: encountered a null reference | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/dangling_ref1.stderr b/tests/fail/validity/dangling_ref1.stderr index 0d358fd7f7f9..290963c6d4ee 100644 --- a/tests/fail/validity/dangling_ref1.stderr +++ b/tests/fail/validity/dangling_ref1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated) +error: Undefined Behavior: constructing invalid value: encountered a dangling reference (address 0x10 is unallocated) --> $DIR/dangling_ref1.rs:LL:CC | LL | let _x: &i32 = unsafe { mem::transmute(16usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (address 0x10 is unallocated) + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (address 0x10 is unallocated) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/dangling_ref2.stderr b/tests/fail/validity/dangling_ref2.stderr index e3bbb72fdcf1..ce60f973ffe8 100644 --- a/tests/fail/validity/dangling_ref2.stderr +++ b/tests/fail/validity/dangling_ref2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered a dangling reference (going beyond the bounds of its allocation) +error: Undefined Behavior: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) --> $DIR/dangling_ref2.rs:LL:CC | LL | let _x: &i32 = unsafe { mem::transmute(ptr) }; - | ^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (going beyond the bounds of its allocation) + | ^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/dangling_ref3.stderr b/tests/fail/validity/dangling_ref3.stderr index 5842eca9fc8e..aa25f1656086 100644 --- a/tests/fail/validity/dangling_ref3.stderr +++ b/tests/fail/validity/dangling_ref3.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered a dangling reference (use-after-free) +error: Undefined Behavior: constructing invalid value: encountered a dangling reference (use-after-free) --> $DIR/dangling_ref3.rs:LL:CC | LL | let _x: &i32 = unsafe { mem::transmute(dangling()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (use-after-free) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (use-after-free) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/invalid_bool.stderr b/tests/fail/validity/invalid_bool.stderr index d17319d2dce8..756c094d6e86 100644 --- a/tests/fail/validity/invalid_bool.stderr +++ b/tests/fail/validity/invalid_bool.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered 0x02, but expected a boolean +error: Undefined Behavior: constructing invalid value: encountered 0x02, but expected a boolean --> $DIR/invalid_bool.rs:LL:CC | LL | let _b = unsafe { std::mem::transmute::(2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x02, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x02, but expected a boolean | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/invalid_bool_uninit.stderr b/tests/fail/validity/invalid_bool_uninit.stderr index e262e69dc696..5236cab450b6 100644 --- a/tests/fail/validity/invalid_bool_uninit.stderr +++ b/tests/fail/validity/invalid_bool_uninit.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered uninitialized bytes, but expected a boolean +error: Undefined Behavior: constructing invalid value: encountered uninitialized bytes, but expected a boolean --> $DIR/invalid_bool_uninit.rs:LL:CC | LL | let _b = unsafe { MyUninit { init: () }.uninit }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected a boolean | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/invalid_char.stderr b/tests/fail/validity/invalid_char.stderr index 99f5ce0bb211..538af4aefcab 100644 --- a/tests/fail/validity/invalid_char.stderr +++ b/tests/fail/validity/invalid_char.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered $HEX, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) +error: Undefined Behavior: constructing invalid value: encountered $HEX, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) --> $DIR/invalid_char.rs:LL:CC | LL | let _val = match unsafe { std::mem::transmute::(-1) } { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered $HEX, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered $HEX, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/invalid_char_uninit.stderr b/tests/fail/validity/invalid_char_uninit.stderr index b27c9b2bb69c..12bc0faa5135 100644 --- a/tests/fail/validity/invalid_char_uninit.stderr +++ b/tests/fail/validity/invalid_char_uninit.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) +error: Undefined Behavior: constructing invalid value: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) --> $DIR/invalid_char_uninit.rs:LL:CC | LL | let _b = unsafe { MyUninit { init: () }.uninit }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/invalid_enum_tag.rs b/tests/fail/validity/invalid_enum_tag.rs index 9722e6492c82..4bc60ba51e70 100644 --- a/tests/fail/validity/invalid_enum_tag.rs +++ b/tests/fail/validity/invalid_enum_tag.rs @@ -7,5 +7,5 @@ pub enum Foo { } fn main() { - let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR type validation failed at .: encountered 0x0000002a, but expected a valid enum tag + let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR constructing invalid value at .: encountered 0x0000002a, but expected a valid enum tag } diff --git a/tests/fail/validity/invalid_enum_tag.stderr b/tests/fail/validity/invalid_enum_tag.stderr index c6d862ae1b02..c7014ae71ac2 100644 --- a/tests/fail/validity/invalid_enum_tag.stderr +++ b/tests/fail/validity/invalid_enum_tag.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed at .: encountered $HEX, but expected a valid enum tag +error: Undefined Behavior: constructing invalid value at .: encountered $HEX, but expected a valid enum tag --> $DIR/invalid_enum_tag.rs:LL:CC | -LL | ... { std::mem::transmute::(42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .: encountered $HEX, but expected a valid enum tag +LL | let _f = unsafe { std::mem::transmute::(42) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered $HEX, but expected a valid enum tag | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs b/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs index b6f86698b3fb..7573a64d0eba 100644 --- a/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs +++ b/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs @@ -268,5 +268,5 @@ union MyUninit { } fn main() { - let _a = unsafe { MyUninit { init: () }.uninit }; //~ ERROR type validation failed at .: encountered uninitialized bytes, but expected a valid enum tag + let _a = unsafe { MyUninit { init: () }.uninit }; //~ ERROR constructing invalid value at .: encountered uninitialized bytes, but expected a valid enum tag } diff --git a/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr b/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr index 0e924bb741a9..c9fd312a96ce 100644 --- a/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr +++ b/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr @@ -1,9 +1,9 @@ WARNING: `-Zmiri-allow-uninit-numbers` is deprecated and planned to be removed. Please let us know at if you rely on this flag. -error: Undefined Behavior: type validation failed at .: encountered uninitialized bytes, but expected a valid enum tag +error: Undefined Behavior: constructing invalid value at .: encountered uninitialized bytes, but expected a valid enum tag --> $DIR/invalid_enum_tag_256variants_uninit.rs:LL:CC | LL | let _a = unsafe { MyUninit { init: () }.uninit }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .: encountered uninitialized bytes, but expected a valid enum tag + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered uninitialized bytes, but expected a valid enum tag | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/invalid_fnptr_null.stderr b/tests/fail/validity/invalid_fnptr_null.stderr index e3cea40e0c33..13e8957e615f 100644 --- a/tests/fail/validity/invalid_fnptr_null.stderr +++ b/tests/fail/validity/invalid_fnptr_null.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered a null function pointer +error: Undefined Behavior: constructing invalid value: encountered a null function pointer --> $DIR/invalid_fnptr_null.rs:LL:CC | LL | let _b: fn() = unsafe { std::mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a null function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null function pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/invalid_fnptr_uninit.stderr b/tests/fail/validity/invalid_fnptr_uninit.stderr index 84a5657e7870..b64655fa8189 100644 --- a/tests/fail/validity/invalid_fnptr_uninit.stderr +++ b/tests/fail/validity/invalid_fnptr_uninit.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered uninitialized bytes, but expected a proper pointer or integer value +error: Undefined Behavior: constructing invalid value: encountered uninitialized bytes, but expected a proper pointer or integer value --> $DIR/invalid_fnptr_uninit.rs:LL:CC | LL | let _b = unsafe { MyUninit { init: () }.uninit }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a proper pointer or integer value + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected a proper pointer or integer value | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/invalid_wide_raw.stderr b/tests/fail/validity/invalid_wide_raw.stderr index f64b824d6ba6..633f8f8adbc2 100644 --- a/tests/fail/validity/invalid_wide_raw.stderr +++ b/tests/fail/validity/invalid_wide_raw.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered dangling vtable pointer in wide pointer +error: Undefined Behavior: constructing invalid value: encountered dangling vtable pointer in wide pointer --> $DIR/invalid_wide_raw.rs:LL:CC | LL | dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling vtable pointer in wide pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered dangling vtable pointer in wide pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/nonzero.stderr b/tests/fail/validity/nonzero.stderr index ba01acb6a169..0c6a24172307 100644 --- a/tests/fail/validity/nonzero.stderr +++ b/tests/fail/validity/nonzero.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered 0, but expected something greater or equal to 1 +error: Undefined Behavior: constructing invalid value: encountered 0, but expected something greater or equal to 1 --> $DIR/nonzero.rs:LL:CC | LL | let _x = Some(unsafe { NonZero(0) }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/ptr_integer_array_transmute.stderr b/tests/fail/validity/ptr_integer_array_transmute.stderr index bc2ca54438ff..39b4ebfc8f13 100644 --- a/tests/fail/validity/ptr_integer_array_transmute.stderr +++ b/tests/fail/validity/ptr_integer_array_transmute.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered a pointer, but expected plain (non-pointer) bytes +error: Undefined Behavior: constructing invalid value: encountered a pointer, but expected plain (non-pointer) bytes --> $DIR/ptr_integer_array_transmute.rs:LL:CC | LL | let _i: [usize; 1] = unsafe { std::mem::transmute(r) }; - | ^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a pointer, but expected plain (non-pointer) bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/ref_to_uninhabited1.stderr b/tests/fail/validity/ref_to_uninhabited1.stderr index dbaee46a93b8..526b6a4dc251 100644 --- a/tests/fail/validity/ref_to_uninhabited1.stderr +++ b/tests/fail/validity/ref_to_uninhabited1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered a box pointing to uninhabited type ! +error: Undefined Behavior: constructing invalid value: encountered a box pointing to uninhabited type ! --> $DIR/ref_to_uninhabited1.rs:LL:CC | LL | let x: Box = transmute(&mut 42); - | ^^^^^^^^^^^^^^^^^^ type validation failed: encountered a box pointing to uninhabited type ! + | ^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a box pointing to uninhabited type ! | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/ref_to_uninhabited2.stderr b/tests/fail/validity/ref_to_uninhabited2.stderr index 115cdfedf777..297b0540ab01 100644 --- a/tests/fail/validity/ref_to_uninhabited2.stderr +++ b/tests/fail/validity/ref_to_uninhabited2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered a reference pointing to uninhabited type (i32, Void) +error: Undefined Behavior: constructing invalid value: encountered a reference pointing to uninhabited type (i32, Void) --> $DIR/ref_to_uninhabited2.rs:LL:CC | LL | let _x: &(i32, Void) = transmute(&42); - | ^^^^^^^^^^^^^^ type validation failed: encountered a reference pointing to uninhabited type (i32, Void) + | ^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type (i32, Void) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/too-big-slice.stderr b/tests/fail/validity/too-big-slice.stderr index 9c8d2929bda0..52077f16a1c8 100644 --- a/tests/fail/validity/too-big-slice.stderr +++ b/tests/fail/validity/too-big-slice.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object +error: Undefined Behavior: constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object --> $DIR/too-big-slice.rs:LL:CC | LL | let _x: &[u8] = mem::transmute((ptr, usize::MAX)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/too-big-unsized.stderr b/tests/fail/validity/too-big-unsized.stderr index 18dc5d8b9c18..a20f1de6d57d 100644 --- a/tests/fail/validity/too-big-unsized.stderr +++ b/tests/fail/validity/too-big-unsized.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered invalid reference metadata: total size is bigger than largest supported object +error: Undefined Behavior: constructing invalid value: encountered invalid reference metadata: total size is bigger than largest supported object --> $DIR/too-big-unsized.rs:LL:CC | LL | let _x: &MySlice = mem::transmute((ptr, isize::MAX as usize)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: total size is bigger than largest supported object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: total size is bigger than largest supported object | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/transmute_through_ptr.rs b/tests/fail/validity/transmute_through_ptr.rs index 049c57e61939..9db2ba995304 100644 --- a/tests/fail/validity/transmute_through_ptr.rs +++ b/tests/fail/validity/transmute_through_ptr.rs @@ -14,6 +14,6 @@ fn main() { let mut x = Bool::True; evil(&mut x); let y = x; // reading this ought to be enough to trigger validation - //~^ ERROR type validation failed at .: encountered 0x0000002c, but expected a valid enum tag + //~^ ERROR constructing invalid value at .: encountered 0x0000002c, but expected a valid enum tag println!("{:?}", y); // make sure it is used (and not optimized away) } diff --git a/tests/fail/validity/transmute_through_ptr.stderr b/tests/fail/validity/transmute_through_ptr.stderr index d06dbe3194f5..50f699d7f9b5 100644 --- a/tests/fail/validity/transmute_through_ptr.stderr +++ b/tests/fail/validity/transmute_through_ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed at .: encountered $HEX, but expected a valid enum tag +error: Undefined Behavior: constructing invalid value at .: encountered $HEX, but expected a valid enum tag --> $DIR/transmute_through_ptr.rs:LL:CC | LL | let y = x; // reading this ought to be enough to trigger validation - | ^ type validation failed at .: encountered $HEX, but expected a valid enum tag + | ^ constructing invalid value at .: encountered $HEX, but expected a valid enum tag | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/uninit_float.rs b/tests/fail/validity/uninit_float.rs index e79cbb45f984..43748570d9a4 100644 --- a/tests/fail/validity/uninit_float.rs +++ b/tests/fail/validity/uninit_float.rs @@ -2,5 +2,5 @@ fn main() { let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - //~^ ERROR type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes + //~^ ERROR constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes } diff --git a/tests/fail/validity/uninit_float.stderr b/tests/fail/validity/uninit_float.stderr index 3f244adbabed..946897bd4ea6 100644 --- a/tests/fail/validity/uninit_float.stderr +++ b/tests/fail/validity/uninit_float.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes +error: Undefined Behavior: constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes --> $DIR/uninit_float.rs:LL:CC | LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/uninit_integer.rs b/tests/fail/validity/uninit_integer.rs index bfa25d6ef356..b5a367ba8cb7 100644 --- a/tests/fail/validity/uninit_integer.rs +++ b/tests/fail/validity/uninit_integer.rs @@ -2,5 +2,5 @@ fn main() { let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - //~^ ERROR type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes + //~^ ERROR constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes } diff --git a/tests/fail/validity/uninit_integer.stderr b/tests/fail/validity/uninit_integer.stderr index e3e2f0a17852..7e9d38a4b7bb 100644 --- a/tests/fail/validity/uninit_integer.stderr +++ b/tests/fail/validity/uninit_integer.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes +error: Undefined Behavior: constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes --> $DIR/uninit_integer.rs:LL:CC | LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/uninit_integer_signed.rs b/tests/fail/validity/uninit_integer_signed.rs index 1764120805c4..609bad7e4fb6 100644 --- a/tests/fail/validity/uninit_integer_signed.rs +++ b/tests/fail/validity/uninit_integer_signed.rs @@ -2,5 +2,5 @@ fn main() { let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - //~^ ERROR type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes + //~^ ERROR constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes } diff --git a/tests/fail/validity/uninit_integer_signed.stderr b/tests/fail/validity/uninit_integer_signed.stderr index e6d9b51e40e4..bd8ea42c3a43 100644 --- a/tests/fail/validity/uninit_integer_signed.stderr +++ b/tests/fail/validity/uninit_integer_signed.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes +error: Undefined Behavior: constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes --> $DIR/uninit_integer_signed.rs:LL:CC | LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information From 6a204e2dec621d0cec4b9290733feee67d49b8c8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 Jun 2022 22:17:46 -0400 Subject: [PATCH 3395/5092] use Rust SnakeCase --- src/shims/unix/dlsym.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shims/unix/dlsym.rs b/src/shims/unix/dlsym.rs index e1f819fb8567..2c563a9551f2 100644 --- a/src/shims/unix/dlsym.rs +++ b/src/shims/unix/dlsym.rs @@ -10,7 +10,7 @@ use shims::unix::macos::dlsym as macos; pub enum Dlsym { Linux(linux::Dlsym), MacOs(macos::Dlsym), - FreeBSD(freebsd::Dlsym), + FreeBsd(freebsd::Dlsym), } impl Dlsym { @@ -20,7 +20,7 @@ impl Dlsym { Ok(match target_os { "linux" => linux::Dlsym::from_str(name)?.map(Dlsym::Linux), "macos" => macos::Dlsym::from_str(name)?.map(Dlsym::MacOs), - "freebsd" => freebsd::Dlsym::from_str(name)?.map(Dlsym::FreeBSD), + "freebsd" => freebsd::Dlsym::from_str(name)?.map(Dlsym::FreeBsd), _ => unreachable!(), }) } @@ -43,7 +43,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match dlsym { Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), - Dlsym::FreeBSD(dlsym) => + Dlsym::FreeBsd(dlsym) => freebsd::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), } } From a9f9d48b1a071dd067bdd17bd83d0a06ad2ab923 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 29 Jun 2022 13:29:35 +0000 Subject: [PATCH 3396/5092] Support no-std targets and test it in CI --- CONTRIBUTING.md | 10 ++++++++++ README.md | 2 ++ cargo-miri/bin.rs | 18 ++++++++++-------- ci.sh | 1 + tests/pass/no_std.rs | 21 +++++++++++++++++++++ 5 files changed, 44 insertions(+), 8 deletions(-) create mode 100644 tests/pass/no_std.rs diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ad8bd2a17a6c..7dfa9d73120f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -71,6 +71,16 @@ and you can (cross-)run the entire test suite using: MIRI_TEST_TARGET=i686-unknown-linux-gnu ./miri test ``` +If your target doesn't support libstd, you can run miri with + +``` +MIRI_NO_STD=1 MIRI_TEST_TARGET=thumbv7em-none-eabihf ./miri test tests/fail/alloc/no_global_allocator.rs +MIRI_NO_STD=1 ./miri run tests/pass/no_std.rs --target thumbv7em-none-eabihf +``` + +to avoid attempting (and failing) to build libstd. Note that almost no tests will pass +this way, but you can run individual tests. + `./miri test FILTER` only runs those tests that contain `FILTER` in their filename (including the base directory, e.g. `./miri test fail` will run all compile-fail tests). diff --git a/README.md b/README.md index bfc32d04a9d1..2d9609fb0b70 100644 --- a/README.md +++ b/README.md @@ -419,6 +419,8 @@ Moreover, Miri recognizes some environment variables: * `MIRI_TEST_TARGET` (recognized by the test suite) indicates which target architecture to test against. `miri` and `cargo miri` accept the `--target` flag for the same purpose. +* `MIRI_NO_STD` (recognized by `cargo miri` and the test suite) makes sure that the target's + sysroot is built without libstd. This allows testing and running no_std programs. * `MIRI_BLESS` (recognized by the test suite) overwrite all `stderr` and `stdout` files instead of checking whether the output matches. * `MIRI_SKIP_UI_CHECKS` (recognized by the test suite) don't check whether the diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 9627adeb2e79..4c9f3aabaab4 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -398,11 +398,12 @@ fn setup(subcommand: MiriCommand) { if !dir.exists() { fs::create_dir_all(&dir).unwrap(); } - // The interesting bit: Xargo.toml - File::create(dir.join("Xargo.toml")) - .unwrap() - .write_all( - br#" + let mut xargo_toml = File::create(dir.join("Xargo.toml")).unwrap(); + if std::env::var_os("MIRI_NO_STD").is_none() { + // The interesting bit: Xargo.toml (only needs content if we actually need std) + xargo_toml + .write_all( + br#" [dependencies.std] default_features = false # We support unwinding, so enable that panic runtime. @@ -410,8 +411,9 @@ features = ["panic_unwind", "backtrace"] [dependencies.test] "#, - ) - .unwrap(); + ) + .unwrap(); + } // The boring bits: a dummy project for xargo. // FIXME: With xargo-check, can we avoid doing this? File::create(dir.join("Cargo.toml")) @@ -428,7 +430,7 @@ path = "lib.rs" "#, ) .unwrap(); - File::create(dir.join("lib.rs")).unwrap(); + File::create(dir.join("lib.rs")).unwrap().write_all(b"#![no_std]").unwrap(); // Determine architectures. // We always need to set a target so rustc bootstrap can tell apart host from target crates. diff --git a/ci.sh b/ci.sh index 1fa67f52139e..e3a106308592 100755 --- a/ci.sh +++ b/ci.sh @@ -61,6 +61,7 @@ case $HOST_TARGET in MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec + MIRI_NO_STD=1 ./miri run tests/pass/no_std.rs --target thumbv7em-none-eabihf # no_std embedded architecture minimal test ;; x86_64-apple-darwin) MIRI_TEST_TARGET=mips64-unknown-linux-gnuabi64 run_tests # big-endian architecture diff --git a/tests/pass/no_std.rs b/tests/pass/no_std.rs new file mode 100644 index 000000000000..6808dab8143f --- /dev/null +++ b/tests/pass/no_std.rs @@ -0,0 +1,21 @@ +#![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-windows + +#[start] +fn start(_: isize, _: *const *const u8) -> isize { + for _ in 0..10 {} + + 0 +} + +#[panic_handler] +fn panic_handler(_: &core::panic::PanicInfo) -> ! { + loop {} +} + +#[lang = "eh_personality"] +fn eh_personality() {} From c1d10cdbe0df35840e418fee170adf7aa5cc108c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Jun 2022 10:04:23 -0400 Subject: [PATCH 3397/5092] use run_tests_minimal for the new no-std test --- ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index e3a106308592..e9ebb6f136f4 100755 --- a/ci.sh +++ b/ci.sh @@ -61,7 +61,7 @@ case $HOST_TARGET in MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec - MIRI_NO_STD=1 ./miri run tests/pass/no_std.rs --target thumbv7em-none-eabihf # no_std embedded architecture minimal test + MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture ;; x86_64-apple-darwin) MIRI_TEST_TARGET=mips64-unknown-linux-gnuabi64 run_tests # big-endian architecture From aef78d3a9f2e71d4e7cbd635ea7eb4baa9918e46 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Jun 2022 11:13:26 -0400 Subject: [PATCH 3398/5092] make -Zmiri-env-forward take precedence over -Zmiri-env-exclude --- README.md | 5 +++-- src/shims/env.rs | 8 ++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 2d9609fb0b70..32cbc4f1e458 100644 --- a/README.md +++ b/README.md @@ -285,8 +285,9 @@ environment variable. We first document the most relevant and most commonly used harness](https://github.com/rust-lang/miri/issues/1702). This has no effect unless `-Zmiri-disable-isolation` is also set. * `-Zmiri-env-forward=` forwards the `var` environment variable to the interpreted program. Can - be used multiple times to forward several variables. This has no effect if - `-Zmiri-disable-isolation` is set. + be used multiple times to forward several variables. This takes precedence over + `-Zmiri-env-exclude`: if a variable is both forwarded and exluced, it *will* get forwarded. This + means in particular `-Zmiri-env-forward=TERM` overwrites the default exclusion of `TERM`. * `-Zmiri-ignore-leaks` disables the memory leak checker, and also allows some remaining threads to exist when the main thread exits. * `-Zmiri-permissive-provenance` disables the warning for integer-to-pointer casts and diff --git a/src/shims/env.rs b/src/shims/env.rs index 85ecd2b719f2..f4aaeea2c122 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -50,10 +50,10 @@ impl<'tcx> EnvVars<'tcx> { // Skip the loop entirely if we don't want to forward anything. if ecx.machine.communicate() || !config.forwarded_env_vars.is_empty() { for (name, value) in env::vars_os() { - let forward = match ecx.machine.communicate() { - true => !excluded_env_vars.iter().any(|v| **v == name), - false => config.forwarded_env_vars.iter().any(|v| **v == name), - }; + // Always forward what is in `forwarded_env_vars`; that list can take precedence over excluded_env_vars. + let forward = config.forwarded_env_vars.iter().any(|v| **v == name) + || (ecx.machine.communicate() + && !excluded_env_vars.iter().any(|v| **v == name)); if forward { let var_ptr = match target_os { target if target_os_is_unix(target) => From 7f3fbbdee7cea0b165bd3620d971b78ca35362e7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Jun 2022 18:41:32 -0400 Subject: [PATCH 3399/5092] allocation tracking: also print size, alignment, kind of the allocation --- src/diagnostics.rs | 6 ++++-- src/machine.rs | 9 +++++++-- tests/pass/track-alloc-1.rs | 1 + tests/pass/track-alloc-1.stderr | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 55598c19ef6b..1ffcdc799edf 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -6,6 +6,7 @@ use log::trace; use rustc_middle::ty; use rustc_span::{source_map::DUMMY_SP, Span, SpanData, Symbol}; +use rustc_target::abi::{Align, Size}; use crate::helpers::HexRange; use crate::stacked_borrows::{diagnostics::TagHistory, AccessKind}; @@ -71,7 +72,7 @@ pub enum NonHaltingDiagnostic { /// a deallocation when the second argument is `None`. PoppedPointerTag(Item, Option<(SbTagExtra, AccessKind)>), CreatedCallId(CallId), - CreatedAlloc(AllocId), + CreatedAlloc(AllocId, Size, Align, MemoryKind), FreedAlloc(AllocId), RejectedIsolatedOp(String), ProgressReport, @@ -463,7 +464,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } }, CreatedCallId(id) => format!("function call with id {id}"), - CreatedAlloc(AllocId(id)) => format!("created allocation with id {id}"), + CreatedAlloc(AllocId(id), size, align, kind) => + format!("created {kind} allocation of {} bytes (alignment {} bytes) with id {id}", size.bytes(), align.bytes()), FreedAlloc(AllocId(id)) => format!("freed allocation with id {id}"), RejectedIsolatedOp(ref op) => format!("{op} was made to return an error due to isolation"), diff --git a/src/machine.rs b/src/machine.rs index 4aeb42d3d0fe..abc55cde737e 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -624,11 +624,16 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { alloc: Cow<'b, Allocation>, kind: Option>, ) -> InterpResult<'tcx, Cow<'b, Allocation>> { + let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); if ecx.machine.tracked_alloc_ids.contains(&id) { - register_diagnostic(NonHaltingDiagnostic::CreatedAlloc(id)); + register_diagnostic(NonHaltingDiagnostic::CreatedAlloc( + id, + alloc.size(), + alloc.align, + kind, + )); } - let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); let stacks = if let Some(stacked_borrows) = &ecx.machine.stacked_borrows { Some(Stacks::new_allocation( diff --git a/tests/pass/track-alloc-1.rs b/tests/pass/track-alloc-1.rs index 7bb217309f94..bbd88ed5d53e 100644 --- a/tests/pass/track-alloc-1.rs +++ b/tests/pass/track-alloc-1.rs @@ -2,4 +2,5 @@ // Early allocations are probably part of the runtime and therefore uninteresting, but they // shouldn't cause a crash. // compile-flags: -Zmiri-track-alloc-id=1 +// normalize-stderr-test: "[48] bytes" -> "SIZE bytes" fn main() {} diff --git a/tests/pass/track-alloc-1.stderr b/tests/pass/track-alloc-1.stderr index be96b729838d..7206edbb7010 100644 --- a/tests/pass/track-alloc-1.stderr +++ b/tests/pass/track-alloc-1.stderr @@ -1,5 +1,5 @@ note: tracking was triggered | - = note: created allocation with id 1 + = note: created extern static allocation of SIZE bytes (alignment ALIGN bytes) with id 1 = note: (no span available) From a1fabb94786b0c551a11849383d3a9241254a807 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Jul 2022 07:53:17 -0400 Subject: [PATCH 3400/5092] make miri script work from other working directories --- miri | 60 +++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/miri b/miri index 6b7e9dbf03f8..b84213f93809 100755 --- a/miri +++ b/miri @@ -5,14 +5,14 @@ USAGE=$(cat <<"EOF" ./miri install : Installs the miri driver and cargo-miri. are passed to `cargo -install`. Sets up the rpath such that the installed binary should work in any +install`. Sets up the rpath such that the installed binary should work in any working directory. ./miri build : -Just build miri. are passed to `cargo build`. +Just build miri. are passed to `cargo build`. ./miri check : -Just check miri. are passed to `cargo check`. +Just check miri. are passed to `cargo check`. ./miri test : Build miri, set up a sysroot and then run the test suite. are passed @@ -26,10 +26,10 @@ The commands above also exist in a "-debug" variant (e.g. "./miri run-debug times and slower execution times. ./miri fmt : -Format all sources and tests. are passed to `rustfmt`. +Format all sources and tests. are passed to `rustfmt`. ./miri clippy : -Format all sources and tests. are passed to `cargo clippy`. +Format all sources and tests. are passed to `cargo clippy`. ENVIRONMENT VARIABLES @@ -42,17 +42,23 @@ EOF ) ## Preparation -TARGET=$(rustc --version --verbose | grep "^host:" | cut -d ' ' -f 2) -SYSROOT=$(rustc --print sysroot) -LIBDIR=$SYSROOT/lib/rustlib/$TARGET/lib # macOS does not have a useful readlink/realpath so we have to use Python instead... MIRIDIR=$(dirname "$(python3 -c 'import os, sys; print(os.path.realpath(sys.argv[1]))' "$0")") +# Determine toolchain *in the Miri dir* and use that. +TOOLCHAIN=$(cd "$MIRIDIR"; rustup show active-toolchain | head -n 1 | cut -d ' ' -f 1) +# Determine some toolchain properties +TARGET=$(rustc +$TOOLCHAIN --version --verbose | grep "^host:" | cut -d ' ' -f 2) +SYSROOT=$(rustc +$TOOLCHAIN --print sysroot) +LIBDIR=$SYSROOT/lib/rustlib/$TARGET/lib + if ! test -d "$LIBDIR"; then echo "Something went wrong determining the library dir." echo "I got $LIBDIR but that does not exist." echo "Please report a bug at https://github.com/rust-lang/miri/issues." exit 2 fi + +CARGO="cargo +$TOOLCHAIN" if [ -z "$CARGO_INCREMENTAL" ]; then # Default CARGO_INCREMENTAL to 1. export CARGO_INCREMENTAL=1 @@ -68,15 +74,15 @@ export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR -C debug-assertions -C debugin ## Helper functions -# Build a sysroot and set MIRI_SYSROOT to use it. Arguments are passed to `cargo miri setup`. +# Build a sysroot and set MIRI_SYSROOT to use it. Arguments are passed to `cargo miri setup`. build_sysroot() { # Build once, for the user to see. - cargo run $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -- miri setup "$@" + $CARGO run $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -- miri setup "$@" # Call again, to just set env var. - export MIRI_SYSROOT="$(cargo run $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -q -- miri setup --print-sysroot "$@")" + export MIRI_SYSROOT="$($CARGO run $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -q -- miri setup --print-sysroot "$@")" } -# Prepare and set MIRI_SYSROOT. Respects `MIRI_TEST_TARGET` and takes into account +# Prepare and set MIRI_SYSROOT. Respects `MIRI_TEST_TARGET` and takes into account # locally built vs. distributed rustc. find_sysroot() { if [ -n "$MIRI_SYSROOT" ]; then @@ -116,22 +122,22 @@ case "$COMMAND" in install|install-debug) # "--locked" to respect the Cargo.lock file if it exists, # "--offline" to avoid querying the registry (for yanked packages). - cargo install $CARGO_INSTALL_FLAGS --path "$MIRIDIR" --force --locked --offline "$@" - cargo install $CARGO_INSTALL_FLAGS --path "$MIRIDIR"/cargo-miri --force --locked --offline "$@" + $CARGO install $CARGO_INSTALL_FLAGS --path "$MIRIDIR" --force --locked --offline "$@" + $CARGO install $CARGO_INSTALL_FLAGS --path "$MIRIDIR"/cargo-miri --force --locked --offline "$@" ;; check|check-debug) # Check, and let caller control flags. - cargo check $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@" - cargo check $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" + $CARGO check $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@" + $CARGO check $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" ;; build|build-debug) # Build, and let caller control flags. - cargo build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" - cargo build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" + $CARGO build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" + $CARGO build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" ;; test|test-debug|bless|bless-debug) # First build and get a sysroot. - cargo build $CARGO_BUILD_FLAGS + $CARGO build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml find_sysroot case "$COMMAND" in bless|bless-debug) @@ -140,8 +146,8 @@ test|test-debug|bless|bless-debug) esac # Then test, and let caller control flags. # Only in root project and ui_test as `cargo-miri` has no tests. - cargo test $CARGO_BUILD_FLAGS "$@" - cargo test $CARGO_BUILD_FLAGS --manifest-path ui_test/Cargo.toml "$@" + $CARGO test $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" + $CARGO test $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml "$@" ;; run|run-debug) # Scan for "--target" to set the "MIRI_TEST_TARGET" env var so @@ -157,19 +163,19 @@ run|run-debug) done fi # First build and get a sysroot. - cargo build $CARGO_BUILD_FLAGS + $CARGO build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml find_sysroot # Then run the actual command. - exec cargo run $CARGO_BUILD_FLAGS -- --sysroot "$MIRI_SYSROOT" "$@" + exec $CARGO run $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml -- --sysroot "$MIRI_SYSROOT" "$@" ;; fmt) find "$MIRIDIR" -not \( -name target -prune \) -name '*.rs' \ - | xargs rustfmt --edition=2021 --config-path "$MIRIDIR/rustfmt.toml" "$@" + | xargs rustfmt +$TOOLCHAIN --edition=2021 --config-path "$MIRIDIR/rustfmt.toml" "$@" ;; clippy) - cargo clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@" - cargo clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml --all-targets "$@" - cargo clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" + $CARGO clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@" + $CARGO clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml --all-targets "$@" + $CARGO clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" ;; *) if [ -n "$COMMAND" ]; then From 7d09313727d37841e89713bd4d6f86cd7aa4fda1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Jul 2022 09:55:02 -0400 Subject: [PATCH 3401/5092] add './miri many-seeds', and respect MIRIFLAGS in './miri run' --- miri | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/miri b/miri index b84213f93809..0d3d361af2fa 100755 --- a/miri +++ b/miri @@ -20,6 +20,7 @@ to the final `cargo test` invocation. ./miri run : Build miri, set up a sysroot and then run the driver with the given . +(Also respects MIRIFLAGS environment variable.) The commands above also exist in a "-debug" variant (e.g. "./miri run-debug ") which uses debug builds instead of release builds, for faster build @@ -31,6 +32,11 @@ Format all sources and tests. are passed to `rustfmt`. ./miri clippy : Format all sources and tests. are passed to `cargo clippy`. +./miri many-seeds : +Runs over and over again with different seeds for Miri. The MIRIFLAGS +variable is set to its original value appended with ` -Zmiri-seed=$SEED` for +many different seeds. + ENVIRONMENT VARIABLES MIRI_SYSROOT: @@ -41,6 +47,20 @@ Pass extra flags to all cargo invocations. EOF ) +# Determine command. +COMMAND="$1" +[ $# -gt 0 ] && shift + +## Handle some commands early, since they should *not* alter the environment. +case "$COMMAND" in +many-seeds) + for SEED in $({ echo obase=16; seq 0 255; } | bc); do + MIRIFLAGS="$MIRIFLAGS -Zmiri-seed=$SEED" $@ || { echo "Failing seed: $SEED"; break; } + done + exit 0 + ;; +esac + ## Preparation # macOS does not have a useful readlink/realpath so we have to use Python instead... MIRIDIR=$(dirname "$(python3 -c 'import os, sys; print(os.path.realpath(sys.argv[1]))' "$0")") @@ -99,10 +119,6 @@ find_sysroot() { ## Main -# Determine command. -COMMAND="$1" -[ $# -gt 0 ] && shift - # Determine flags passed to all cargo invocations. # This is a bit more annoying that one would hope due to # . @@ -166,7 +182,7 @@ run|run-debug) $CARGO build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml find_sysroot # Then run the actual command. - exec $CARGO run $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml -- --sysroot "$MIRI_SYSROOT" "$@" + exec $CARGO run $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml -- --sysroot "$MIRI_SYSROOT" $MIRIFLAGS "$@" ;; fmt) find "$MIRIDIR" -not \( -name target -prune \) -name '*.rs' \ From 9bc7938bc27d3757278c55839c1865ee74c50baa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Jul 2022 10:01:00 -0400 Subject: [PATCH 3402/5092] more tweaks --- miri | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/miri b/miri index 0d3d361af2fa..349cf818fb2a 100755 --- a/miri +++ b/miri @@ -63,14 +63,14 @@ esac ## Preparation # macOS does not have a useful readlink/realpath so we have to use Python instead... -MIRIDIR=$(dirname "$(python3 -c 'import os, sys; print(os.path.realpath(sys.argv[1]))' "$0")") +MIRIDIR=$(python3 -c 'import os, sys; print(os.path.dirname(os.path.realpath(sys.argv[1])))' "$0") # Determine toolchain *in the Miri dir* and use that. TOOLCHAIN=$(cd "$MIRIDIR"; rustup show active-toolchain | head -n 1 | cut -d ' ' -f 1) + # Determine some toolchain properties TARGET=$(rustc +$TOOLCHAIN --version --verbose | grep "^host:" | cut -d ' ' -f 2) SYSROOT=$(rustc +$TOOLCHAIN --print sysroot) LIBDIR=$SYSROOT/lib/rustlib/$TARGET/lib - if ! test -d "$LIBDIR"; then echo "Something went wrong determining the library dir." echo "I got $LIBDIR but that does not exist." @@ -78,6 +78,7 @@ if ! test -d "$LIBDIR"; then exit 2 fi +# Prepare flags for cargo and rustc. CARGO="cargo +$TOOLCHAIN" if [ -z "$CARGO_INCREMENTAL" ]; then # Default CARGO_INCREMENTAL to 1. @@ -91,6 +92,19 @@ fi # We enable debug-assertions to get tracing. # We enable line-only debuginfo for backtraces. export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR -C debug-assertions -C debuginfo=1 $RUSTFLAGS" +# Determine flags passed to all cargo invocations. +# This is a bit more annoying that one would hope due to +# . +case "$COMMAND" in +*-debug) + CARGO_INSTALL_FLAGS="--target $TARGET --debug $CARGO_EXTRA_FLAGS" + CARGO_BUILD_FLAGS="--target $TARGET $CARGO_EXTRA_FLAGS" + ;; +*) + CARGO_INSTALL_FLAGS="--target $TARGET $CARGO_EXTRA_FLAGS" + CARGO_BUILD_FLAGS="--target $TARGET --release $CARGO_EXTRA_FLAGS" + ;; +esac ## Helper functions @@ -119,20 +133,6 @@ find_sysroot() { ## Main -# Determine flags passed to all cargo invocations. -# This is a bit more annoying that one would hope due to -# . -case "$COMMAND" in -*-debug) - CARGO_INSTALL_FLAGS="--target $TARGET --debug $CARGO_EXTRA_FLAGS" - CARGO_BUILD_FLAGS="--target $TARGET $CARGO_EXTRA_FLAGS" - ;; -*) - CARGO_INSTALL_FLAGS="--target $TARGET $CARGO_EXTRA_FLAGS" - CARGO_BUILD_FLAGS="--target $TARGET --release $CARGO_EXTRA_FLAGS" - ;; -esac - # Run command. case "$COMMAND" in install|install-debug) From af39709a9c4aa053e31c09a5fbb488ed06cf55b0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Jul 2022 10:14:31 -0400 Subject: [PATCH 3403/5092] rustup --- rust-version | 2 +- src/concurrency/data_race.rs | 10 +++++----- src/stacked_borrows.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rust-version b/rust-version index 1ab8e6b5a8ce..4198e8cf3c08 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -bf45371f262e184b4a77adea88c8ac01ac79759b +ca1e68b3229e710c3948a361ee770d846a88e6da diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index c1bcd2368133..7f6304c3815f 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -535,7 +535,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.validate_overlapping_atomic(dest)?; - this.allow_data_races_mut(move |this| this.write_scalar(val, &(*dest).into()))?; + this.allow_data_races_mut(move |this| this.write_scalar(val, &dest.into()))?; this.validate_atomic_store(dest, atomic)?; // FIXME: it's not possible to get the value before write_scalar. A read_scalar will cause // side effects from a read the program did not perform. So we have to initialise @@ -562,7 +562,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // Atomics wrap around on overflow. let val = this.binary_op(op, &old, rhs)?; let val = if neg { this.unary_op(mir::UnOp::Not, &val)? } else { val }; - this.allow_data_races_mut(|this| this.write_immediate(*val, &(*place).into()))?; + this.allow_data_races_mut(|this| this.write_immediate(*val, &place.into()))?; this.validate_atomic_rmw(place, atomic)?; @@ -587,7 +587,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { this.validate_overlapping_atomic(place)?; let old = this.allow_data_races_mut(|this| this.read_scalar(&place.into()))?; - this.allow_data_races_mut(|this| this.write_scalar(new, &(*place).into()))?; + this.allow_data_races_mut(|this| this.write_scalar(new, &place.into()))?; this.validate_atomic_rmw(place, atomic)?; @@ -616,7 +616,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { if lt { &rhs } else { &old } }; - this.allow_data_races_mut(|this| this.write_immediate(**new_val, &(*place).into()))?; + this.allow_data_races_mut(|this| this.write_immediate(**new_val, &place.into()))?; this.validate_atomic_rmw(place, atomic)?; @@ -675,7 +675,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // if successful, perform a full rw-atomic validation // otherwise treat this as an atomic load with the fail ordering. if cmpxchg_success { - this.allow_data_races_mut(|this| this.write_scalar(new, &(*place).into()))?; + this.allow_data_races_mut(|this| this.write_scalar(new, &place.into()))?; this.validate_atomic_rmw(place, success)?; this.buffered_atomic_rmw(new, place, success, old.to_scalar_or_uninit())?; } else { diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 3fc0eaf10c09..5ca58d90e07d 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -1097,7 +1097,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some((mutbl, protector)) = qualify(place.layout.ty, self.kind) { let val = self.ecx.read_immediate(&place.into())?; let val = self.ecx.retag_reference(&val, mutbl, protector)?; - self.ecx.write_immediate(*val, &(*place).into())?; + self.ecx.write_immediate(*val, &place.into())?; } else { // Maybe we need to go deeper. self.walk_value(place)?; From 12d04ac4c4291c031b7d1cd63707a6cd59c895a8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Jul 2022 12:25:35 -0400 Subject: [PATCH 3404/5092] make clippy happy --- src/concurrency/data_race.rs | 6 +++--- src/eval.rs | 10 +++++----- src/stacked_borrows.rs | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 7f6304c3815f..36178269e025 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -964,7 +964,7 @@ impl VClockAlloc { let (index, clocks) = global.current_thread_state(); let mut alloc_ranges = self.alloc_ranges.borrow_mut(); for (offset, range) in alloc_ranges.iter_mut(range.start, range.size) { - if let Err(DataRace) = range.read_race_detect(&*clocks, index) { + if let Err(DataRace) = range.read_race_detect(&clocks, index) { // Report data-race. return Self::report_data_race( global, @@ -992,7 +992,7 @@ impl VClockAlloc { if global.race_detecting() { let (index, clocks) = global.current_thread_state(); for (offset, range) in self.alloc_ranges.get_mut().iter_mut(range.start, range.size) { - if let Err(DataRace) = range.write_race_detect(&*clocks, index, write_type) { + if let Err(DataRace) = range.write_race_detect(&clocks, index, write_type) { // Report data-race return Self::report_data_race( global, @@ -1072,7 +1072,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { for (offset, range) in alloc_meta.alloc_ranges.borrow_mut().iter_mut(base_offset, size) { - if let Err(DataRace) = op(range, &mut *clocks, index, atomic) { + if let Err(DataRace) = op(range, &mut clocks, index, atomic) { mem::drop(clocks); return VClockAlloc::report_data_race( data_race, diff --git a/src/eval.rs b/src/eval.rs index c9fc05500a3c..1536b826ac46 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -215,7 +215,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let arg_place = ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Machine.into())?; ecx.write_os_str_to_c_str(OsStr::new(arg), arg_place.ptr, size)?; - ecx.mark_immutable(&*arg_place); + ecx.mark_immutable(&arg_place); argvs.push(arg_place.to_ref(&ecx)); } // Make an array with all these pointers, in the Miri memory. @@ -227,7 +227,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let place = ecx.mplace_field(&argvs_place, idx)?; ecx.write_immediate(arg, &place.into())?; } - ecx.mark_immutable(&*argvs_place); + ecx.mark_immutable(&argvs_place); // A pointer to that place is the 3rd argument for main. let argv = argvs_place.to_ref(&ecx); // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`. @@ -235,7 +235,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let argc_place = ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into())?; ecx.write_scalar(argc, &argc_place.into())?; - ecx.mark_immutable(&*argc_place); + ecx.mark_immutable(&argc_place); ecx.machine.argc = Some(*argc_place); let argv_place = ecx.allocate( @@ -243,7 +243,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( MiriMemoryKind::Machine.into(), )?; ecx.write_immediate(argv, &argv_place.into())?; - ecx.mark_immutable(&*argv_place); + ecx.mark_immutable(&argv_place); ecx.machine.argv = Some(*argv_place); } // Store command line as UTF-16 for Windows `GetCommandLineW`. @@ -260,7 +260,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let place = ecx.mplace_field(&cmd_place, idx)?; ecx.write_scalar(Scalar::from_u16(c), &place.into())?; } - ecx.mark_immutable(&*cmd_place); + ecx.mark_immutable(&cmd_place); } argv }; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 5ca58d90e07d..2cf5eb70c171 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -928,7 +928,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx orig_tag, item, (alloc_id, range, offset), - &mut *global, + &mut global, current_span, history, exposed_tags, @@ -1090,7 +1090,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline(always)] fn ecx(&mut self) -> &mut MiriEvalContext<'mir, 'tcx> { - &mut self.ecx + self.ecx } fn visit_value(&mut self, place: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { From dca2bb68b3010a7cd47ae1e79674dcc7812828ce Mon Sep 17 00:00:00 2001 From: InfRandomness Date: Fri, 1 Jul 2022 18:36:14 +0200 Subject: [PATCH 3405/5092] Add `__error` to freebsd shims Signed-off-by: InfRandomness --- src/shims/unix/freebsd/foreign_items.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/shims/unix/freebsd/foreign_items.rs b/src/shims/unix/freebsd/foreign_items.rs index cad119233740..66e339cc4a82 100644 --- a/src/shims/unix/freebsd/foreign_items.rs +++ b/src/shims/unix/freebsd/foreign_items.rs @@ -24,6 +24,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_null(dest)?; } + + // errno + "__error" => { + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let errno_place = this.last_error_place()?; + this.write_scalar(errno_place.to_ref(this).to_scalar()?, dest)?; + } + _ => return Ok(EmulateByNameResult::NotSupported), } Ok(EmulateByNameResult::NeedsJumping) From dc47649d215fea0c850b0c69c204f85c6cbdb77e Mon Sep 17 00:00:00 2001 From: InfRandomness Date: Fri, 1 Jul 2022 18:52:32 +0200 Subject: [PATCH 3406/5092] Add `current_dir_with_isolation` to freebsd tests list Signed-off-by: InfRandomness --- ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index e9ebb6f136f4..816fbb3101ca 100755 --- a/ci.sh +++ b/ci.sh @@ -60,7 +60,7 @@ case $HOST_TARGET in MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests - MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec + MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec current_dir_with_isolation MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture ;; x86_64-apple-darwin) From 734e8903f2b1a3165bda29318d5ab492186473e5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Jul 2022 14:12:25 -0400 Subject: [PATCH 3407/5092] more current_dir tests for freebsd --- ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index 816fbb3101ca..3d6bd817ff17 100755 --- a/ci.sh +++ b/ci.sh @@ -60,7 +60,7 @@ case $HOST_TARGET in MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests - MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec current_dir_with_isolation + MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec current_dir MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture ;; x86_64-apple-darwin) From ab0005bc38fcb6d57d3077adcc5f58c3853fe292 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Jul 2022 14:13:36 -0400 Subject: [PATCH 3408/5092] run data_race tests on bsd --- ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index 3d6bd817ff17..5c7ab545f958 100755 --- a/ci.sh +++ b/ci.sh @@ -60,7 +60,7 @@ case $HOST_TARGET in MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests - MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec current_dir + MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec current_dir data_race MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture ;; x86_64-apple-darwin) From f238513efac3193ed7d05222d03b8052690de0a3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Jul 2022 16:21:46 -0400 Subject: [PATCH 3409/5092] rename some data_race types for more clarity --- src/concurrency/data_race.rs | 56 +++++----- src/concurrency/weak_memory.rs | 24 ++-- src/lib.rs | 2 +- src/shims/intrinsics.rs | 198 ++++++++++++++++----------------- src/shims/unix/linux/sync.rs | 6 +- src/shims/unix/sync.rs | 28 ++--- src/shims/windows/sync.rs | 4 +- 7 files changed, 159 insertions(+), 159 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 36178269e025..ef0920d9698d 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -62,9 +62,9 @@ use super::weak_memory::EvalContextExt as _; pub type AllocExtra = VClockAlloc; -/// Valid atomic read-write operations, alias of atomic::Ordering (not non-exhaustive). +/// Valid atomic read-write orderings, alias of atomic::Ordering (not non-exhaustive). #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum AtomicRwOp { +pub enum AtomicRwOrd { Relaxed, Acquire, Release, @@ -72,25 +72,25 @@ pub enum AtomicRwOp { SeqCst, } -/// Valid atomic read operations, subset of atomic::Ordering. +/// Valid atomic read orderings, subset of atomic::Ordering. #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum AtomicReadOp { +pub enum AtomicReadOrd { Relaxed, Acquire, SeqCst, } -/// Valid atomic write operations, subset of atomic::Ordering. +/// Valid atomic write orderings, subset of atomic::Ordering. #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum AtomicWriteOp { +pub enum AtomicWriteOrd { Relaxed, Release, SeqCst, } -/// Valid atomic fence operations, subset of atomic::Ordering. +/// Valid atomic fence orderings, subset of atomic::Ordering. #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum AtomicFenceOp { +pub enum AtomicFenceOrd { Acquire, Release, AcqRel, @@ -486,7 +486,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { op: &OpTy<'tcx, Tag>, offset: u64, layout: TyAndLayout<'tcx>, - atomic: AtomicReadOp, + atomic: AtomicReadOrd, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_ref(); let value_place = this.deref_operand_and_offset(op, offset, layout)?; @@ -500,7 +500,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { offset: u64, value: impl Into>, layout: TyAndLayout<'tcx>, - atomic: AtomicWriteOp, + atomic: AtomicWriteOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let value_place = this.deref_operand_and_offset(op, offset, layout)?; @@ -511,7 +511,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { fn read_scalar_atomic( &self, place: &MPlaceTy<'tcx, Tag>, - atomic: AtomicReadOp, + atomic: AtomicReadOrd, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_ref(); // This will read from the last store in the modification order of this location. In case @@ -531,7 +531,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { &mut self, val: ScalarMaybeUninit, dest: &MPlaceTy<'tcx, Tag>, - atomic: AtomicWriteOp, + atomic: AtomicWriteOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.validate_overlapping_atomic(dest)?; @@ -552,7 +552,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { rhs: &ImmTy<'tcx, Tag>, op: mir::BinOp, neg: bool, - atomic: AtomicRwOp, + atomic: AtomicRwOrd, ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let this = self.eval_context_mut(); @@ -581,7 +581,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { &mut self, place: &MPlaceTy<'tcx, Tag>, new: ScalarMaybeUninit, - atomic: AtomicRwOp, + atomic: AtomicRwOrd, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_mut(); @@ -602,7 +602,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { place: &MPlaceTy<'tcx, Tag>, rhs: ImmTy<'tcx, Tag>, min: bool, - atomic: AtomicRwOp, + atomic: AtomicRwOrd, ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let this = self.eval_context_mut(); @@ -642,8 +642,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { place: &MPlaceTy<'tcx, Tag>, expect_old: &ImmTy<'tcx, Tag>, new: ScalarMaybeUninit, - success: AtomicRwOp, - fail: AtomicReadOp, + success: AtomicRwOrd, + fail: AtomicReadOrd, can_fail_spuriously: bool, ) -> InterpResult<'tcx, Immediate> { use rand::Rng as _; @@ -696,7 +696,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { fn validate_atomic_load( &self, place: &MPlaceTy<'tcx, Tag>, - atomic: AtomicReadOp, + atomic: AtomicReadOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); this.validate_overlapping_atomic(place)?; @@ -705,7 +705,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic, "Atomic Load", move |memory, clocks, index, atomic| { - if atomic == AtomicReadOp::Relaxed { + if atomic == AtomicReadOrd::Relaxed { memory.load_relaxed(&mut *clocks, index) } else { memory.load_acquire(&mut *clocks, index) @@ -719,7 +719,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { fn validate_atomic_store( &mut self, place: &MPlaceTy<'tcx, Tag>, - atomic: AtomicWriteOp, + atomic: AtomicWriteOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.validate_overlapping_atomic(place)?; @@ -728,7 +728,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic, "Atomic Store", move |memory, clocks, index, atomic| { - if atomic == AtomicWriteOp::Relaxed { + if atomic == AtomicWriteOrd::Relaxed { memory.store_relaxed(clocks, index) } else { memory.store_release(clocks, index) @@ -742,9 +742,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { fn validate_atomic_rmw( &mut self, place: &MPlaceTy<'tcx, Tag>, - atomic: AtomicRwOp, + atomic: AtomicRwOrd, ) -> InterpResult<'tcx> { - use AtomicRwOp::*; + use AtomicRwOrd::*; let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); let release = matches!(atomic, Release | AcqRel | SeqCst); let this = self.eval_context_mut(); @@ -764,7 +764,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { } /// Update the data-race detector for an atomic fence on the current thread. - fn validate_atomic_fence(&mut self, atomic: AtomicFenceOp) -> InterpResult<'tcx> { + fn validate_atomic_fence(&mut self, atomic: AtomicFenceOrd) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if let Some(data_race) = &mut this.machine.data_race { data_race.maybe_perform_sync_operation(|index, mut clocks| { @@ -773,22 +773,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // Apply data-race detection for the current fences // this treats AcqRel and SeqCst as the same as an acquire // and release fence applied in the same timestamp. - if atomic != AtomicFenceOp::Release { + if atomic != AtomicFenceOrd::Release { // Either Acquire | AcqRel | SeqCst clocks.apply_acquire_fence(); } - if atomic != AtomicFenceOp::Acquire { + if atomic != AtomicFenceOrd::Acquire { // Either Release | AcqRel | SeqCst clocks.apply_release_fence(); } - if atomic == AtomicFenceOp::SeqCst { + if atomic == AtomicFenceOrd::SeqCst { data_race.last_sc_fence.borrow_mut().set_at_index(&clocks.clock, index); clocks.fence_seqcst.join(&data_race.last_sc_fence.borrow()); clocks.write_seqcst.join(&data_race.last_sc_write.borrow()); } // Increment timestamp in case of release semantics. - Ok(atomic != AtomicFenceOp::Acquire) + Ok(atomic != AtomicFenceOrd::Acquire) }) } else { Ok(()) diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index e5f58ee5ddd0..28a54c2e3b6c 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -82,7 +82,7 @@ use rustc_const_eval::interpret::{ }; use rustc_data_structures::fx::FxHashMap; -use crate::{AtomicReadOp, AtomicRwOp, AtomicWriteOp, Tag, VClock, VTimestamp, VectorIdx}; +use crate::{AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, Tag, VClock, VTimestamp, VectorIdx}; use super::{ data_race::{GlobalState, ThreadClockSet}, @@ -443,7 +443,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: &mut self, new_val: ScalarMaybeUninit, place: &MPlaceTy<'tcx, Tag>, - atomic: AtomicRwOp, + atomic: AtomicRwOrd, init: ScalarMaybeUninit, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -453,14 +453,14 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: crate::Evaluator { data_race: Some(global), .. }, ) = this.get_alloc_extra_mut(alloc_id)? { - if atomic == AtomicRwOp::SeqCst { + if atomic == AtomicRwOrd::SeqCst { global.sc_read(); global.sc_write(); } let range = alloc_range(base_offset, place.layout.size); let buffer = alloc_buffers.get_or_create_store_buffer_mut(range, init)?; buffer.read_from_last_store(global); - buffer.buffered_write(new_val, global, atomic == AtomicRwOp::SeqCst)?; + buffer.buffered_write(new_val, global, atomic == AtomicRwOrd::SeqCst)?; } Ok(()) } @@ -468,7 +468,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: fn buffered_atomic_read( &self, place: &MPlaceTy<'tcx, Tag>, - atomic: AtomicReadOp, + atomic: AtomicReadOrd, latest_in_mo: ScalarMaybeUninit, validate: impl FnOnce() -> InterpResult<'tcx>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { @@ -476,7 +476,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: if let Some(global) = &this.machine.data_race { let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { - if atomic == AtomicReadOp::SeqCst { + if atomic == AtomicReadOrd::SeqCst { global.sc_read(); } let mut rng = this.machine.rng.borrow_mut(); @@ -486,7 +486,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: )?; let loaded = buffer.buffered_read( global, - atomic == AtomicReadOp::SeqCst, + atomic == AtomicReadOrd::SeqCst, &mut *rng, validate, )?; @@ -504,7 +504,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: &mut self, val: ScalarMaybeUninit, dest: &MPlaceTy<'tcx, Tag>, - atomic: AtomicWriteOp, + atomic: AtomicWriteOrd, init: ScalarMaybeUninit, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -514,7 +514,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: crate::Evaluator { data_race: Some(global), .. }, ) = this.get_alloc_extra_mut(alloc_id)? { - if atomic == AtomicWriteOp::SeqCst { + if atomic == AtomicWriteOrd::SeqCst { global.sc_write(); } @@ -535,7 +535,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: buffer.buffer.pop_front(); } - buffer.buffered_write(val, global, atomic == AtomicWriteOp::SeqCst)?; + buffer.buffered_write(val, global, atomic == AtomicWriteOrd::SeqCst)?; } // Caller should've written to dest with the vanilla scalar write, we do nothing here @@ -548,13 +548,13 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: fn perform_read_on_buffered_latest( &self, place: &MPlaceTy<'tcx, Tag>, - atomic: AtomicReadOp, + atomic: AtomicReadOrd, init: ScalarMaybeUninit, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); if let Some(global) = &this.machine.data_race { - if atomic == AtomicReadOp::SeqCst { + if atomic == AtomicReadOrd::SeqCst { global.sc_read(); } let size = place.layout.size; diff --git a/src/lib.rs b/src/lib.rs index e199fae31ee8..b3d408a6dc07 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -70,7 +70,7 @@ pub use crate::shims::tls::{EvalContextExt as _, TlsData}; pub use crate::shims::EvalContextExt as _; pub use crate::concurrency::data_race::{ - AtomicFenceOp, AtomicReadOp, AtomicRwOp, AtomicWriteOp, + AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, EvalContextExt as DataRaceEvalContextExt, }; pub use crate::diagnostics::{ diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 592683201158..9705f56cd107 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -864,216 +864,216 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Atomic operations - "atomic_load_seqcst" => this.atomic_load(args, dest, AtomicReadOp::SeqCst)?, - "atomic_load_relaxed" => this.atomic_load(args, dest, AtomicReadOp::Relaxed)?, - "atomic_load_acquire" => this.atomic_load(args, dest, AtomicReadOp::Acquire)?, + "atomic_load_seqcst" => this.atomic_load(args, dest, AtomicReadOrd::SeqCst)?, + "atomic_load_relaxed" => this.atomic_load(args, dest, AtomicReadOrd::Relaxed)?, + "atomic_load_acquire" => this.atomic_load(args, dest, AtomicReadOrd::Acquire)?, - "atomic_store_seqcst" => this.atomic_store(args, AtomicWriteOp::SeqCst)?, - "atomic_store_relaxed" => this.atomic_store(args, AtomicWriteOp::Relaxed)?, - "atomic_store_release" => this.atomic_store(args, AtomicWriteOp::Release)?, + "atomic_store_seqcst" => this.atomic_store(args, AtomicWriteOrd::SeqCst)?, + "atomic_store_relaxed" => this.atomic_store(args, AtomicWriteOrd::Relaxed)?, + "atomic_store_release" => this.atomic_store(args, AtomicWriteOrd::Release)?, - "atomic_fence_acquire" => this.atomic_fence(args, AtomicFenceOp::Acquire)?, - "atomic_fence_release" => this.atomic_fence(args, AtomicFenceOp::Release)?, - "atomic_fence_acqrel" => this.atomic_fence(args, AtomicFenceOp::AcqRel)?, - "atomic_fence_seqcst" => this.atomic_fence(args, AtomicFenceOp::SeqCst)?, + "atomic_fence_acquire" => this.atomic_fence(args, AtomicFenceOrd::Acquire)?, + "atomic_fence_release" => this.atomic_fence(args, AtomicFenceOrd::Release)?, + "atomic_fence_acqrel" => this.atomic_fence(args, AtomicFenceOrd::AcqRel)?, + "atomic_fence_seqcst" => this.atomic_fence(args, AtomicFenceOrd::SeqCst)?, "atomic_singlethreadfence_acquire" => - this.compiler_fence(args, AtomicFenceOp::Acquire)?, + this.compiler_fence(args, AtomicFenceOrd::Acquire)?, "atomic_singlethreadfence_release" => - this.compiler_fence(args, AtomicFenceOp::Release)?, + this.compiler_fence(args, AtomicFenceOrd::Release)?, "atomic_singlethreadfence_acqrel" => - this.compiler_fence(args, AtomicFenceOp::AcqRel)?, + this.compiler_fence(args, AtomicFenceOrd::AcqRel)?, "atomic_singlethreadfence_seqcst" => - this.compiler_fence(args, AtomicFenceOp::SeqCst)?, + this.compiler_fence(args, AtomicFenceOrd::SeqCst)?, - "atomic_xchg_seqcst" => this.atomic_exchange(args, dest, AtomicRwOp::SeqCst)?, - "atomic_xchg_acquire" => this.atomic_exchange(args, dest, AtomicRwOp::Acquire)?, - "atomic_xchg_release" => this.atomic_exchange(args, dest, AtomicRwOp::Release)?, - "atomic_xchg_acqrel" => this.atomic_exchange(args, dest, AtomicRwOp::AcqRel)?, - "atomic_xchg_relaxed" => this.atomic_exchange(args, dest, AtomicRwOp::Relaxed)?, + "atomic_xchg_seqcst" => this.atomic_exchange(args, dest, AtomicRwOrd::SeqCst)?, + "atomic_xchg_acquire" => this.atomic_exchange(args, dest, AtomicRwOrd::Acquire)?, + "atomic_xchg_release" => this.atomic_exchange(args, dest, AtomicRwOrd::Release)?, + "atomic_xchg_acqrel" => this.atomic_exchange(args, dest, AtomicRwOrd::AcqRel)?, + "atomic_xchg_relaxed" => this.atomic_exchange(args, dest, AtomicRwOrd::Relaxed)?, #[rustfmt::skip] "atomic_cxchg_seqcst_seqcst" => - this.atomic_compare_exchange(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::SeqCst)?, + this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::SeqCst)?, #[rustfmt::skip] "atomic_cxchg_acquire_acquire" => - this.atomic_compare_exchange(args, dest, AtomicRwOp::Acquire, AtomicReadOp::Acquire)?, + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Acquire)?, #[rustfmt::skip] "atomic_cxchg_release_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOp::Release, AtomicReadOp::Relaxed)?, + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Relaxed)?, #[rustfmt::skip] "atomic_cxchg_acqrel_acquire" => - this.atomic_compare_exchange(args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Acquire)?, + this.atomic_compare_exchange(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Acquire)?, #[rustfmt::skip] "atomic_cxchg_relaxed_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOp::Relaxed, AtomicReadOp::Relaxed)?, + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Relaxed)?, #[rustfmt::skip] "atomic_cxchg_acquire_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOp::Acquire, AtomicReadOp::Relaxed)?, + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Relaxed)?, #[rustfmt::skip] "atomic_cxchg_acqrel_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Relaxed)?, + this.atomic_compare_exchange(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Relaxed)?, #[rustfmt::skip] "atomic_cxchg_seqcst_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Relaxed)?, + this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Relaxed)?, #[rustfmt::skip] "atomic_cxchg_seqcst_acquire" => - this.atomic_compare_exchange(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Acquire)?, + this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Acquire)?, #[rustfmt::skip] "atomic_cxchgweak_seqcst_seqcst" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::SeqCst)?, + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::SeqCst)?, #[rustfmt::skip] "atomic_cxchgweak_acquire_acquire" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::Acquire, AtomicReadOp::Acquire)?, + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Acquire)?, #[rustfmt::skip] "atomic_cxchgweak_release_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::Release, AtomicReadOp::Relaxed)?, + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Relaxed)?, #[rustfmt::skip] "atomic_cxchgweak_acqrel_acquire" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Acquire)?, + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Acquire)?, #[rustfmt::skip] "atomic_cxchgweak_relaxed_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::Relaxed, AtomicReadOp::Relaxed)?, + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Relaxed)?, #[rustfmt::skip] "atomic_cxchgweak_acquire_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::Acquire, AtomicReadOp::Relaxed)?, + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Relaxed)?, #[rustfmt::skip] "atomic_cxchgweak_acqrel_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Relaxed)?, + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Relaxed)?, #[rustfmt::skip] "atomic_cxchgweak_seqcst_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Relaxed)?, + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Relaxed)?, #[rustfmt::skip] "atomic_cxchgweak_seqcst_acquire" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Acquire)?, + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Acquire)?, #[rustfmt::skip] "atomic_or_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::SeqCst)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::SeqCst)?, #[rustfmt::skip] "atomic_or_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::Acquire)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::Acquire)?, #[rustfmt::skip] "atomic_or_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::Release)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::Release)?, #[rustfmt::skip] "atomic_or_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::AcqRel)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::AcqRel)?, #[rustfmt::skip] "atomic_or_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::Relaxed)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::Relaxed)?, #[rustfmt::skip] "atomic_xor_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::SeqCst)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::SeqCst)?, #[rustfmt::skip] "atomic_xor_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::Acquire)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::Acquire)?, #[rustfmt::skip] "atomic_xor_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::Release)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::Release)?, #[rustfmt::skip] "atomic_xor_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::AcqRel)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::AcqRel)?, #[rustfmt::skip] "atomic_xor_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::Relaxed)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::Relaxed)?, #[rustfmt::skip] "atomic_and_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::SeqCst)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::SeqCst)?, #[rustfmt::skip] "atomic_and_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::Acquire)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::Acquire)?, #[rustfmt::skip] "atomic_and_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::Release)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::Release)?, #[rustfmt::skip] "atomic_and_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::AcqRel)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::AcqRel)?, #[rustfmt::skip] "atomic_and_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::Relaxed)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::Relaxed)?, #[rustfmt::skip] "atomic_nand_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::SeqCst)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::SeqCst)?, #[rustfmt::skip] "atomic_nand_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::Acquire)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::Acquire)?, #[rustfmt::skip] "atomic_nand_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::Release)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::Release)?, #[rustfmt::skip] "atomic_nand_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::AcqRel)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::AcqRel)?, #[rustfmt::skip] "atomic_nand_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::Relaxed)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::Relaxed)?, #[rustfmt::skip] "atomic_xadd_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::SeqCst)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::SeqCst)?, #[rustfmt::skip] "atomic_xadd_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::Acquire)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::Acquire)?, #[rustfmt::skip] "atomic_xadd_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::Release)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::Release)?, #[rustfmt::skip] "atomic_xadd_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::AcqRel)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::AcqRel)?, #[rustfmt::skip] "atomic_xadd_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::Relaxed)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::Relaxed)?, #[rustfmt::skip] "atomic_xsub_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::SeqCst)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::SeqCst)?, #[rustfmt::skip] "atomic_xsub_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::Acquire)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::Acquire)?, #[rustfmt::skip] "atomic_xsub_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::Release)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::Release)?, #[rustfmt::skip] "atomic_xsub_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::AcqRel)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::AcqRel)?, #[rustfmt::skip] "atomic_xsub_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::Relaxed)?, - "atomic_min_seqcst" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::Relaxed)?, + "atomic_min_seqcst" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::SeqCst)?, "atomic_min_acquire" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Acquire)?, "atomic_min_release" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, - "atomic_min_acqrel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Release)?, + "atomic_min_acqrel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::AcqRel)?, "atomic_min_relaxed" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Relaxed)?, - "atomic_max_seqcst" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Relaxed)?, + "atomic_max_seqcst" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::SeqCst)?, "atomic_max_acquire" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Acquire)?, "atomic_max_release" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, - "atomic_max_acqrel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Release)?, + "atomic_max_acqrel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::AcqRel)?, "atomic_max_relaxed" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Relaxed)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Relaxed)?, "atomic_umin_seqcst" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::SeqCst)?, "atomic_umin_acquire" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Acquire)?, "atomic_umin_release" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Release)?, "atomic_umin_acqrel" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::AcqRel)?, "atomic_umin_relaxed" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Relaxed)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Relaxed)?, "atomic_umax_seqcst" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::SeqCst)?, "atomic_umax_acquire" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Acquire)?, "atomic_umax_release" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Release)?, "atomic_umax_acqrel" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::AcqRel)?, "atomic_umax_relaxed" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Relaxed)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Relaxed)?, // Other "exact_div" => { @@ -1101,7 +1101,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - atomic: AtomicReadOp, + atomic: AtomicReadOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -1129,7 +1129,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn atomic_store( &mut self, args: &[OpTy<'tcx, Tag>], - atomic: AtomicWriteOp, + atomic: AtomicWriteOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -1156,7 +1156,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn compiler_fence( &mut self, args: &[OpTy<'tcx, Tag>], - atomic: AtomicFenceOp, + atomic: AtomicFenceOrd, ) -> InterpResult<'tcx> { let [] = check_arg_count(args)?; let _ = atomic; @@ -1167,7 +1167,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn atomic_fence( &mut self, args: &[OpTy<'tcx, Tag>], - atomic: AtomicFenceOp, + atomic: AtomicFenceOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let [] = check_arg_count(args)?; @@ -1180,7 +1180,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, atomic_op: AtomicOp, - atomic: AtomicRwOp, + atomic: AtomicRwOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -1226,7 +1226,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - atomic: AtomicRwOp, + atomic: AtomicRwOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -1254,8 +1254,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - success: AtomicRwOp, - fail: AtomicReadOp, + success: AtomicRwOrd, + fail: AtomicReadOrd, can_fail_spuriously: bool, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -1294,8 +1294,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - success: AtomicRwOp, - fail: AtomicReadOp, + success: AtomicRwOrd, + fail: AtomicReadOrd, ) -> InterpResult<'tcx> { self.atomic_compare_exchange_impl(args, dest, success, fail, false) } @@ -1304,8 +1304,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - success: AtomicRwOp, - fail: AtomicReadOp, + success: AtomicRwOrd, + fail: AtomicReadOrd, ) -> InterpResult<'tcx> { self.atomic_compare_exchange_impl(args, dest, success, fail, true) } diff --git a/src/shims/unix/linux/sync.rs b/src/shims/unix/linux/sync.rs index 6be1e672f85f..a0e35c730c3d 100644 --- a/src/shims/unix/linux/sync.rs +++ b/src/shims/unix/linux/sync.rs @@ -169,7 +169,7 @@ pub fn futex<'tcx>( // // Thankfully, preemptions cannot happen inside a Miri shim, so we do not need to // do anything special to guarantee fence-load-comparison atomicity. - this.atomic_fence(&[], AtomicFenceOp::SeqCst)?; + this.atomic_fence(&[], AtomicFenceOrd::SeqCst)?; // Read an `i32` through the pointer, regardless of any wrapper types. // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`. let futex_val = this @@ -177,7 +177,7 @@ pub fn futex<'tcx>( &addr.into(), 0, this.machine.layouts.i32, - AtomicReadOp::Relaxed, + AtomicReadOrd::Relaxed, )? .to_i32()?; if val == futex_val { @@ -240,7 +240,7 @@ pub fn futex<'tcx>( // Together with the SeqCst fence in futex_wait, this makes sure that futex_wait // will see the latest value on addr which could be changed by our caller // before doing the syscall. - this.atomic_fence(&[], AtomicFenceOp::SeqCst)?; + this.atomic_fence(&[], AtomicFenceOrd::SeqCst)?; let mut n = 0; for _ in 0..val { if let Some(thread) = this.futex_wake(addr_usize, bitset) { diff --git a/src/shims/unix/sync.rs b/src/shims/unix/sync.rs index 373996312eaf..ae63907c2c86 100644 --- a/src/shims/unix/sync.rs +++ b/src/shims/unix/sync.rs @@ -68,7 +68,7 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>( mutex_op, offset, ecx.machine.layouts.i32, - AtomicReadOp::Relaxed, + AtomicReadOrd::Relaxed, ) } @@ -83,7 +83,7 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( offset, kind, layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.i32), - AtomicWriteOp::Relaxed, + AtomicWriteOrd::Relaxed, ) } @@ -91,7 +91,7 @@ fn mutex_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - ecx.read_scalar_at_offset_atomic(mutex_op, 4, ecx.machine.layouts.u32, AtomicReadOp::Relaxed) + ecx.read_scalar_at_offset_atomic(mutex_op, 4, ecx.machine.layouts.u32, AtomicReadOrd::Relaxed) } fn mutex_set_id<'mir, 'tcx: 'mir>( @@ -104,7 +104,7 @@ fn mutex_set_id<'mir, 'tcx: 'mir>( 4, id, layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.u32), - AtomicWriteOp::Relaxed, + AtomicWriteOrd::Relaxed, ) } @@ -120,8 +120,8 @@ fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( &value_place, &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), next_id.to_u32_scalar().into(), - AtomicRwOp::Relaxed, - AtomicReadOp::Relaxed, + AtomicRwOrd::Relaxed, + AtomicReadOrd::Relaxed, false, )? .to_scalar_pair() @@ -147,7 +147,7 @@ fn rwlock_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - ecx.read_scalar_at_offset_atomic(rwlock_op, 4, ecx.machine.layouts.u32, AtomicReadOp::Relaxed) + ecx.read_scalar_at_offset_atomic(rwlock_op, 4, ecx.machine.layouts.u32, AtomicReadOrd::Relaxed) } fn rwlock_set_id<'mir, 'tcx: 'mir>( @@ -160,7 +160,7 @@ fn rwlock_set_id<'mir, 'tcx: 'mir>( 4, id, layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.u32), - AtomicWriteOp::Relaxed, + AtomicWriteOrd::Relaxed, ) } @@ -176,8 +176,8 @@ fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( &value_place, &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), next_id.to_u32_scalar().into(), - AtomicRwOp::Relaxed, - AtomicReadOp::Relaxed, + AtomicRwOrd::Relaxed, + AtomicReadOrd::Relaxed, false, )? .to_scalar_pair() @@ -231,7 +231,7 @@ fn cond_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, cond_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - ecx.read_scalar_at_offset_atomic(cond_op, 4, ecx.machine.layouts.u32, AtomicReadOp::Relaxed) + ecx.read_scalar_at_offset_atomic(cond_op, 4, ecx.machine.layouts.u32, AtomicReadOrd::Relaxed) } fn cond_set_id<'mir, 'tcx: 'mir>( @@ -244,7 +244,7 @@ fn cond_set_id<'mir, 'tcx: 'mir>( 4, id, layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.u32), - AtomicWriteOp::Relaxed, + AtomicWriteOrd::Relaxed, ) } @@ -260,8 +260,8 @@ fn cond_get_or_create_id<'mir, 'tcx: 'mir>( &value_place, &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), next_id.to_u32_scalar().into(), - AtomicRwOp::Relaxed, - AtomicReadOp::Relaxed, + AtomicRwOrd::Relaxed, + AtomicReadOrd::Relaxed, false, )? .to_scalar_pair() diff --git a/src/shims/windows/sync.rs b/src/shims/windows/sync.rs index 6a6b2269e62a..35603f7f3863 100644 --- a/src/shims/windows/sync.rs +++ b/src/shims/windows/sync.rs @@ -15,8 +15,8 @@ fn srwlock_get_or_create_id<'mir, 'tcx: 'mir>( &value_place, &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), next_id.to_u32_scalar().into(), - AtomicRwOp::Relaxed, - AtomicReadOp::Relaxed, + AtomicRwOrd::Relaxed, + AtomicReadOrd::Relaxed, false, )? .to_scalar_pair() From dfdedae840a3703fc8fe4e7c958645f416087625 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Jul 2022 17:07:29 -0400 Subject: [PATCH 3410/5092] avoid copying thread manager state in data race detector --- src/concurrency/data_race.rs | 224 +++++++++++++++------------------ src/concurrency/weak_memory.rs | 54 ++++---- src/machine.rs | 28 ++++- src/shims/intrinsics.rs | 12 +- src/thread.rs | 47 ++++--- 5 files changed, 186 insertions(+), 179 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index ef0920d9698d..205b56ca4c07 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -39,11 +39,6 @@ //! so some atomic operations that only perform acquires do not increment the timestamp. Due to shared //! code some atomic operations may increment the timestamp when not necessary but this has no effect //! on the data-race detection code. -//! -//! FIXME: -//! currently we have our own local copy of the currently active thread index and names, this is due -//! in part to the inability to access the current location of threads.active_thread inside the AllocExtra -//! read, write and deallocate functions and should be cleaned up in the future. use std::{ cell::{Cell, Ref, RefCell, RefMut}, @@ -767,7 +762,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { fn validate_atomic_fence(&mut self, atomic: AtomicFenceOrd) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if let Some(data_race) = &mut this.machine.data_race { - data_race.maybe_perform_sync_operation(|index, mut clocks| { + data_race.maybe_perform_sync_operation(&this.machine.threads, |index, mut clocks| { log::trace!("Atomic fence on {:?} with ordering {:?}", index, atomic); // Apply data-race detection for the current fences @@ -807,6 +802,7 @@ impl VClockAlloc { /// Create a new data-race detector for newly allocated memory. pub fn new_allocation( global: &GlobalState, + thread_mgr: &ThreadManager<'_, '_>, len: Size, kind: MemoryKind, ) -> VClockAlloc { @@ -816,7 +812,7 @@ impl VClockAlloc { MiriMemoryKind::Rust | MiriMemoryKind::C | MiriMemoryKind::WinHeap, ) | MemoryKind::Stack => { - let (alloc_index, clocks) = global.current_thread_state(); + let (alloc_index, clocks) = global.current_thread_state(thread_mgr); let alloc_timestamp = clocks.clock[alloc_index]; (alloc_timestamp, alloc_index) } @@ -878,12 +874,13 @@ impl VClockAlloc { #[inline(never)] fn report_data_race<'tcx>( global: &GlobalState, + thread_mgr: &ThreadManager<'_, '_>, range: &MemoryCellClocks, action: &str, is_atomic: bool, ptr_dbg: Pointer, ) -> InterpResult<'tcx> { - let (current_index, current_clocks) = global.current_thread_state(); + let (current_index, current_clocks) = global.current_thread_state(thread_mgr); let write_clock; let (other_action, other_thread, other_clock) = if range.write > current_clocks.clock[range.write_index] @@ -918,8 +915,8 @@ impl VClockAlloc { }; // Load elaborated thread information about the racing thread actions. - let current_thread_info = global.print_thread_metadata(current_index); - let other_thread_info = global.print_thread_metadata(other_thread); + let current_thread_info = global.print_thread_metadata(thread_mgr, current_index); + let other_thread_info = global.print_thread_metadata(thread_mgr, other_thread); // Throw the data-race detection. throw_ub_format!( @@ -936,9 +933,14 @@ impl VClockAlloc { /// Detect racing atomic read and writes (not data races) /// on every byte of the current access range - pub(super) fn race_free_with_atomic(&self, range: AllocRange, global: &GlobalState) -> bool { + pub(super) fn race_free_with_atomic( + &self, + range: AllocRange, + global: &GlobalState, + thread_mgr: &ThreadManager<'_, '_>, + ) -> bool { if global.race_detecting() { - let (_, clocks) = global.current_thread_state(); + let (_, clocks) = global.current_thread_state(thread_mgr); let alloc_ranges = self.alloc_ranges.borrow(); for (_, range) in alloc_ranges.iter(range.start, range.size) { if !range.race_free_with_atomic(&clocks) { @@ -959,15 +961,17 @@ impl VClockAlloc { alloc_id: AllocId, range: AllocRange, global: &GlobalState, + thread_mgr: &ThreadManager<'_, '_>, ) -> InterpResult<'tcx> { if global.race_detecting() { - let (index, clocks) = global.current_thread_state(); + let (index, clocks) = global.current_thread_state(thread_mgr); let mut alloc_ranges = self.alloc_ranges.borrow_mut(); for (offset, range) in alloc_ranges.iter_mut(range.start, range.size) { if let Err(DataRace) = range.read_race_detect(&clocks, index) { // Report data-race. return Self::report_data_race( global, + thread_mgr, range, "Read", false, @@ -988,14 +992,16 @@ impl VClockAlloc { range: AllocRange, write_type: WriteType, global: &mut GlobalState, + thread_mgr: &ThreadManager<'_, '_>, ) -> InterpResult<'tcx> { if global.race_detecting() { - let (index, clocks) = global.current_thread_state(); + let (index, clocks) = global.current_thread_state(thread_mgr); for (offset, range) in self.alloc_ranges.get_mut().iter_mut(range.start, range.size) { if let Err(DataRace) = range.write_race_detect(&clocks, index, write_type) { // Report data-race return Self::report_data_race( global, + thread_mgr, range, write_type.get_descriptor(), false, @@ -1018,8 +1024,9 @@ impl VClockAlloc { alloc_id: AllocId, range: AllocRange, global: &mut GlobalState, + thread_mgr: &ThreadManager<'_, '_>, ) -> InterpResult<'tcx> { - self.unique_access(alloc_id, range, WriteType::Write, global) + self.unique_access(alloc_id, range, WriteType::Write, global, thread_mgr) } /// Detect data-races for an unsynchronized deallocate operation, will not perform @@ -1031,8 +1038,9 @@ impl VClockAlloc { alloc_id: AllocId, range: AllocRange, global: &mut GlobalState, + thread_mgr: &ThreadManager<'_, '_>, ) -> InterpResult<'tcx> { - self.unique_access(alloc_id, range, WriteType::Deallocate, global) + self.unique_access(alloc_id, range, WriteType::Deallocate, global, thread_mgr) } } @@ -1068,26 +1076,30 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ); // Perform the atomic operation. - data_race.maybe_perform_sync_operation(|index, mut clocks| { - for (offset, range) in - alloc_meta.alloc_ranges.borrow_mut().iter_mut(base_offset, size) - { - if let Err(DataRace) = op(range, &mut clocks, index, atomic) { - mem::drop(clocks); - return VClockAlloc::report_data_race( - data_race, - range, - description, - true, - Pointer::new(alloc_id, offset), - ) - .map(|_| true); + data_race.maybe_perform_sync_operation( + &this.machine.threads, + |index, mut clocks| { + for (offset, range) in + alloc_meta.alloc_ranges.borrow_mut().iter_mut(base_offset, size) + { + if let Err(DataRace) = op(range, &mut clocks, index, atomic) { + mem::drop(clocks); + return VClockAlloc::report_data_race( + data_race, + &this.machine.threads, + range, + description, + true, + Pointer::new(alloc_id, offset), + ) + .map(|_| true); + } } - } - // This conservatively assumes all operations have release semantics - Ok(true) - })?; + // This conservatively assumes all operations have release semantics + Ok(true) + }, + )?; // Log changes to atomic memory. if log::log_enabled!(log::Level::Trace) { @@ -1117,11 +1129,6 @@ struct ThreadExtraState { /// read during data-race reporting. vector_index: Option, - /// The name of the thread, updated for better - /// diagnostics when reporting detected data - /// races. - thread_name: Option>, - /// Thread termination vector clock, this /// is set on thread termination and is used /// for joining on threads since the vector_index @@ -1161,9 +1168,6 @@ pub struct GlobalState { /// The mapping of a given thread to associated thread metadata. thread_info: RefCell>, - /// The current vector index being executed. - current_index: Cell, - /// Potential vector indices that could be re-used on thread creation /// values are inserted here on after the thread has terminated and /// been joined with, and hence may potentially become free @@ -1173,12 +1177,6 @@ pub struct GlobalState { /// active vector-clocks catch up with the threads timestamp. reuse_candidates: RefCell>, - /// Counts the number of threads that are currently active - /// if the number of active threads reduces to 1 and then - /// a join operation occurs with the remaining main thread - /// then multi-threaded execution may be disabled. - active_thread_count: Cell, - /// This contains threads that have terminated, but not yet joined /// and so cannot become re-use candidates until a join operation /// occurs. @@ -1203,8 +1201,6 @@ impl GlobalState { vector_clocks: RefCell::new(IndexVec::new()), vector_info: RefCell::new(IndexVec::new()), thread_info: RefCell::new(IndexVec::new()), - current_index: Cell::new(VectorIdx::new(0)), - active_thread_count: Cell::new(1), reuse_candidates: RefCell::new(FxHashSet::default()), terminated_threads: RefCell::new(FxHashMap::default()), last_sc_fence: RefCell::new(VClock::default()), @@ -1216,11 +1212,10 @@ impl GlobalState { // the main-thread a name of "main". let index = global_state.vector_clocks.get_mut().push(ThreadClockSet::default()); global_state.vector_info.get_mut().push(ThreadId::new(0)); - global_state.thread_info.get_mut().push(ThreadExtraState { - vector_index: Some(index), - thread_name: Some("main".to_string().into_boxed_str()), - termination_vector_clock: None, - }); + global_state + .thread_info + .get_mut() + .push(ThreadExtraState { vector_index: Some(index), termination_vector_clock: None }); global_state } @@ -1274,14 +1269,10 @@ impl GlobalState { // Hook for thread creation, enabled multi-threaded execution and marks // the current thread timestamp as happening-before the current thread. #[inline] - pub fn thread_created(&mut self, thread: ThreadId) { - let current_index = self.current_index(); + pub fn thread_created(&mut self, thread_mgr: &ThreadManager<'_, '_>, thread: ThreadId) { + let current_index = self.current_index(thread_mgr); - // Increment the number of active threads. - let active_threads = self.active_thread_count.get(); - self.active_thread_count.set(active_threads + 1); - - // Enable multi-threaded execution, there are now two threads + // Enable multi-threaded execution, there are now at least two threads // so data-races are now possible. self.multi_threaded.set(true); @@ -1339,21 +1330,27 @@ impl GlobalState { created.increment_clock(created_index); } - /// Hook on a thread join to update the implicit happens-before relation - /// between the joined thread and the current thread. + /// Hook on a thread join to update the implicit happens-before relation between the joined + /// thread (the joinee, the thread that someone waited on) and the current thread (the joiner, + /// the thread who was waiting). #[inline] - pub fn thread_joined(&mut self, current_thread: ThreadId, join_thread: ThreadId) { + pub fn thread_joined( + &mut self, + thread_mgr: &ThreadManager<'_, '_>, + joiner: ThreadId, + joinee: ThreadId, + ) { let clocks_vec = self.vector_clocks.get_mut(); let thread_info = self.thread_info.get_mut(); // Load the vector clock of the current thread. - let current_index = thread_info[current_thread] + let current_index = thread_info[joiner] .vector_index .expect("Performed thread join on thread with no assigned vector"); let current = &mut clocks_vec[current_index]; // Load the associated vector clock for the terminated thread. - let join_clock = thread_info[join_thread] + let join_clock = thread_info[joinee] .termination_vector_clock .as_ref() .expect("Joined with thread but thread has not terminated"); @@ -1363,10 +1360,9 @@ impl GlobalState { // Is not a release operation so the clock is not incremented. current.clock.join(join_clock); - // Check the number of active threads, if the value is 1 + // Check the number of live threads, if the value is 1 // then test for potentially disabling multi-threaded execution. - let active_threads = self.active_thread_count.get(); - if active_threads == 1 { + if thread_mgr.get_live_thread_count() == 1 { // May potentially be able to disable multi-threaded execution. let current_clock = &clocks_vec[current_index]; if clocks_vec @@ -1383,7 +1379,7 @@ impl GlobalState { // If the thread is marked as terminated but not joined // then move the thread to the re-use set. let termination = self.terminated_threads.get_mut(); - if let Some(index) = termination.remove(&join_thread) { + if let Some(index) = termination.remove(&joinee) { let reuse = self.reuse_candidates.get_mut(); reuse.insert(index); } @@ -1397,8 +1393,8 @@ impl GlobalState { /// This should be called strictly before any calls to /// `thread_joined`. #[inline] - pub fn thread_terminated(&mut self) { - let current_index = self.current_index(); + pub fn thread_terminated(&mut self, thread_mgr: &ThreadManager<'_, '_>) { + let current_index = self.current_index(thread_mgr); // Increment the clock to a unique termination timestamp. let vector_clocks = self.vector_clocks.get_mut(); @@ -1420,35 +1416,6 @@ impl GlobalState { // occurs. let termination = self.terminated_threads.get_mut(); termination.insert(current_thread, current_index); - - // Reduce the number of active threads, now that a thread has - // terminated. - let mut active_threads = self.active_thread_count.get(); - active_threads -= 1; - self.active_thread_count.set(active_threads); - } - - /// Hook for updating the local tracker of the currently - /// enabled thread, should always be updated whenever - /// `active_thread` in thread.rs is updated. - #[inline] - pub fn thread_set_active(&self, thread: ThreadId) { - let thread_info = self.thread_info.borrow(); - let vector_idx = thread_info[thread] - .vector_index - .expect("Setting thread active with no assigned vector"); - self.current_index.set(vector_idx); - } - - /// Hook for updating the local tracker of the threads name - /// this should always mirror the local value in thread.rs - /// the thread name is used for improved diagnostics - /// during a data-race. - #[inline] - pub fn thread_set_name(&mut self, thread: ThreadId, name: String) { - let name = name.into_boxed_str(); - let thread_info = self.thread_info.get_mut(); - thread_info[thread].thread_name = Some(name); } /// Attempt to perform a synchronized operation, this @@ -1460,12 +1427,13 @@ impl GlobalState { /// operation may create. fn maybe_perform_sync_operation<'tcx>( &self, + thread_mgr: &ThreadManager<'_, '_>, op: impl FnOnce(VectorIdx, RefMut<'_, ThreadClockSet>) -> InterpResult<'tcx, bool>, ) -> InterpResult<'tcx> { if self.multi_threaded.get() { - let (index, clocks) = self.current_thread_state_mut(); + let (index, clocks) = self.current_thread_state_mut(thread_mgr); if op(index, clocks)? { - let (_, mut clocks) = self.current_thread_state_mut(); + let (_, mut clocks) = self.current_thread_state_mut(thread_mgr); clocks.increment_clock(index); } } @@ -1474,15 +1442,18 @@ impl GlobalState { /// Internal utility to identify a thread stored internally /// returns the id and the name for better diagnostics. - fn print_thread_metadata(&self, vector: VectorIdx) -> String { + fn print_thread_metadata( + &self, + thread_mgr: &ThreadManager<'_, '_>, + vector: VectorIdx, + ) -> String { let thread = self.vector_info.borrow()[vector]; - let thread_name = &self.thread_info.borrow()[thread].thread_name; - if let Some(name) = thread_name { - let name: &str = name; - format!("Thread(id = {:?}, name = {:?})", thread.to_u32(), name) - } else { - format!("Thread(id = {:?})", thread.to_u32()) - } + let thread_name = thread_mgr.get_thread_name(); + format!( + "Thread(id = {:?}, name = {:?})", + thread.to_u32(), + String::from_utf8_lossy(thread_name) + ) } /// Acquire a lock, express that the previous call of @@ -1534,8 +1505,11 @@ impl GlobalState { /// Load the current vector clock in use and the current set of thread clocks /// in use for the vector. #[inline] - pub(super) fn current_thread_state(&self) -> (VectorIdx, Ref<'_, ThreadClockSet>) { - let index = self.current_index(); + pub(super) fn current_thread_state( + &self, + thread_mgr: &ThreadManager<'_, '_>, + ) -> (VectorIdx, Ref<'_, ThreadClockSet>) { + let index = self.current_index(thread_mgr); let ref_vector = self.vector_clocks.borrow(); let clocks = Ref::map(ref_vector, |vec| &vec[index]); (index, clocks) @@ -1544,8 +1518,11 @@ impl GlobalState { /// Load the current vector clock in use and the current set of thread clocks /// in use for the vector mutably for modification. #[inline] - pub(super) fn current_thread_state_mut(&self) -> (VectorIdx, RefMut<'_, ThreadClockSet>) { - let index = self.current_index(); + pub(super) fn current_thread_state_mut( + &self, + thread_mgr: &ThreadManager<'_, '_>, + ) -> (VectorIdx, RefMut<'_, ThreadClockSet>) { + let index = self.current_index(thread_mgr); let ref_vector = self.vector_clocks.borrow_mut(); let clocks = RefMut::map(ref_vector, |vec| &mut vec[index]); (index, clocks) @@ -1554,19 +1531,22 @@ impl GlobalState { /// Return the current thread, should be the same /// as the data-race active thread. #[inline] - fn current_index(&self) -> VectorIdx { - self.current_index.get() + fn current_index(&self, thread_mgr: &ThreadManager<'_, '_>) -> VectorIdx { + let active_thread_id = thread_mgr.get_active_thread_id(); + self.thread_info.borrow()[active_thread_id] + .vector_index + .expect("active thread has no assigned vector") } // SC ATOMIC STORE rule in the paper. - pub(super) fn sc_write(&self) { - let (index, clocks) = self.current_thread_state(); + pub(super) fn sc_write(&self, thread_mgr: &ThreadManager<'_, '_>) { + let (index, clocks) = self.current_thread_state(thread_mgr); self.last_sc_write.borrow_mut().set_at_index(&clocks.clock, index); } // SC ATOMIC READ rule in the paper. - pub(super) fn sc_read(&self) { - let (.., mut clocks) = self.current_thread_state_mut(); + pub(super) fn sc_read(&self, thread_mgr: &ThreadManager<'_, '_>) { + let (.., mut clocks) = self.current_thread_state_mut(thread_mgr); clocks.read_seqcst.join(&self.last_sc_fence.borrow()); } } diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index 28a54c2e3b6c..e7ed9ea09a82 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -82,10 +82,12 @@ use rustc_const_eval::interpret::{ }; use rustc_data_structures::fx::FxHashMap; -use crate::{AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, Tag, VClock, VTimestamp, VectorIdx}; +use crate::{ + AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, Tag, ThreadManager, VClock, VTimestamp, VectorIdx, +}; use super::{ - data_race::{GlobalState, ThreadClockSet}, + data_race::{GlobalState as DataRaceState, ThreadClockSet}, range_object_map::{AccessType, RangeObjectMap}, }; @@ -149,7 +151,7 @@ impl StoreBufferAlloc { /// before without data race, we can determine that the non-atomic access fully happens /// after all the prior atomic accesses so the location no longer needs to exhibit /// any weak memory behaviours until further atomic accesses. - pub fn memory_accessed(&self, range: AllocRange, global: &GlobalState) { + pub fn memory_accessed(&self, range: AllocRange, global: &DataRaceState) { if !global.ongoing_action_data_race_free() { let mut buffers = self.store_buffers.borrow_mut(); let access_type = buffers.access_type(range); @@ -236,17 +238,18 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { } /// Reads from the last store in modification order - fn read_from_last_store(&self, global: &GlobalState) { + fn read_from_last_store(&self, global: &DataRaceState, thread_mgr: &ThreadManager<'_, '_>) { let store_elem = self.buffer.back(); if let Some(store_elem) = store_elem { - let (index, clocks) = global.current_thread_state(); + let (index, clocks) = global.current_thread_state(thread_mgr); store_elem.load_impl(index, &clocks); } } fn buffered_read( &self, - global: &GlobalState, + global: &DataRaceState, + thread_mgr: &ThreadManager<'_, '_>, is_seqcst: bool, rng: &mut (impl rand::Rng + ?Sized), validate: impl FnOnce() -> InterpResult<'tcx>, @@ -257,7 +260,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { let store_elem = { // The `clocks` we got here must be dropped before calling validate_atomic_load // as the race detector will update it - let (.., clocks) = global.current_thread_state(); + let (.., clocks) = global.current_thread_state(thread_mgr); // Load from a valid entry in the store buffer self.fetch_store(is_seqcst, &clocks, &mut *rng) }; @@ -268,7 +271,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { // requires access to ThreadClockSet.clock, which is updated by the race detector validate()?; - let (index, clocks) = global.current_thread_state(); + let (index, clocks) = global.current_thread_state(thread_mgr); let loaded = store_elem.load_impl(index, &clocks); Ok(loaded) } @@ -276,10 +279,11 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { fn buffered_write( &mut self, val: ScalarMaybeUninit, - global: &GlobalState, + global: &DataRaceState, + thread_mgr: &ThreadManager<'_, '_>, is_seqcst: bool, ) -> InterpResult<'tcx> { - let (index, clocks) = global.current_thread_state(); + let (index, clocks) = global.current_thread_state(thread_mgr); self.store_impl(val, index, &clocks.clock, is_seqcst); Ok(()) @@ -428,8 +432,11 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: { let range = alloc_range(base_offset, place.layout.size); if alloc_buffers.is_overlapping(range) - && !alloc_clocks - .race_free_with_atomic(range, this.machine.data_race.as_ref().unwrap()) + && !alloc_clocks.race_free_with_atomic( + range, + this.machine.data_race.as_ref().unwrap(), + &this.machine.threads, + ) { throw_unsup_format!( "racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation" @@ -450,17 +457,17 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; if let ( crate::AllocExtra { weak_memory: Some(alloc_buffers), .. }, - crate::Evaluator { data_race: Some(global), .. }, + crate::Evaluator { data_race: Some(global), threads, .. }, ) = this.get_alloc_extra_mut(alloc_id)? { if atomic == AtomicRwOrd::SeqCst { - global.sc_read(); - global.sc_write(); + global.sc_read(threads); + global.sc_write(threads); } let range = alloc_range(base_offset, place.layout.size); let buffer = alloc_buffers.get_or_create_store_buffer_mut(range, init)?; - buffer.read_from_last_store(global); - buffer.buffered_write(new_val, global, atomic == AtomicRwOrd::SeqCst)?; + buffer.read_from_last_store(global, threads); + buffer.buffered_write(new_val, global, threads, atomic == AtomicRwOrd::SeqCst)?; } Ok(()) } @@ -477,7 +484,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { if atomic == AtomicReadOrd::SeqCst { - global.sc_read(); + global.sc_read(&this.machine.threads); } let mut rng = this.machine.rng.borrow_mut(); let buffer = alloc_buffers.get_or_create_store_buffer( @@ -486,6 +493,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: )?; let loaded = buffer.buffered_read( global, + &this.machine.threads, atomic == AtomicReadOrd::SeqCst, &mut *rng, validate, @@ -511,11 +519,11 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(dest.ptr)?; if let ( crate::AllocExtra { weak_memory: Some(alloc_buffers), .. }, - crate::Evaluator { data_race: Some(global), .. }, + crate::Evaluator { data_race: Some(global), threads, .. }, ) = this.get_alloc_extra_mut(alloc_id)? { if atomic == AtomicWriteOrd::SeqCst { - global.sc_write(); + global.sc_write(threads); } // UGLY HACK: in write_scalar_atomic() we don't know the value before our write, @@ -535,7 +543,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: buffer.buffer.pop_front(); } - buffer.buffered_write(val, global, atomic == AtomicWriteOrd::SeqCst)?; + buffer.buffered_write(val, global, threads, atomic == AtomicWriteOrd::SeqCst)?; } // Caller should've written to dest with the vanilla scalar write, we do nothing here @@ -555,14 +563,14 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: if let Some(global) = &this.machine.data_race { if atomic == AtomicReadOrd::SeqCst { - global.sc_read(); + global.sc_read(&this.machine.threads); } let size = place.layout.size; let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { let buffer = alloc_buffers .get_or_create_store_buffer(alloc_range(base_offset, size), init)?; - buffer.read_from_last_store(global); + buffer.read_from_last_store(global, &this.machine.threads); } } Ok(()) diff --git a/src/machine.rs b/src/machine.rs index abc55cde737e..86b174182c1f 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -647,7 +647,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { None }; let race_alloc = if let Some(data_race) = &ecx.machine.data_race { - Some(data_race::AllocExtra::new_allocation(data_race, alloc.size(), kind)) + Some(data_race::AllocExtra::new_allocation( + data_race, + &ecx.machine.threads, + alloc.size(), + kind, + )) } else { None }; @@ -756,7 +761,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { range: AllocRange, ) -> InterpResult<'tcx> { if let Some(data_race) = &alloc_extra.data_race { - data_race.read(alloc_id, range, machine.data_race.as_ref().unwrap())?; + data_race.read( + alloc_id, + range, + machine.data_race.as_ref().unwrap(), + &machine.threads, + )?; } if let Some(stacked_borrows) = &alloc_extra.stacked_borrows { stacked_borrows.borrow_mut().memory_read( @@ -782,7 +792,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { range: AllocRange, ) -> InterpResult<'tcx> { if let Some(data_race) = &mut alloc_extra.data_race { - data_race.write(alloc_id, range, machine.data_race.as_mut().unwrap())?; + data_race.write( + alloc_id, + range, + machine.data_race.as_mut().unwrap(), + &machine.threads, + )?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { stacked_borrows.get_mut().memory_written( @@ -811,7 +826,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { register_diagnostic(NonHaltingDiagnostic::FreedAlloc(alloc_id)); } if let Some(data_race) = &mut alloc_extra.data_race { - data_race.deallocate(alloc_id, range, machine.data_race.as_mut().unwrap())?; + data_race.deallocate( + alloc_id, + range, + machine.data_race.as_mut().unwrap(), + &machine.threads, + )?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { stacked_borrows.get_mut().memory_deallocated( diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 9705f56cd107..d8f6292e9df3 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -1038,20 +1038,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[rustfmt::skip] "atomic_xsub_relaxed" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::Relaxed)?, - "atomic_min_seqcst" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::SeqCst)?, + "atomic_min_seqcst" => + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::SeqCst)?, "atomic_min_acquire" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Acquire)?, "atomic_min_release" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Release)?, - "atomic_min_acqrel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::AcqRel)?, + "atomic_min_acqrel" => + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::AcqRel)?, "atomic_min_relaxed" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Relaxed)?, - "atomic_max_seqcst" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::SeqCst)?, + "atomic_max_seqcst" => + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::SeqCst)?, "atomic_max_acquire" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Acquire)?, "atomic_max_release" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Release)?, - "atomic_max_acqrel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::AcqRel)?, + "atomic_max_acqrel" => + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::AcqRel)?, "atomic_max_relaxed" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Relaxed)?, "atomic_umin_seqcst" => diff --git a/src/thread.rs b/src/thread.rs index 2135806de3ed..7327f2b8114f 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -289,15 +289,21 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Get the id of the currently active thread. - fn get_active_thread_id(&self) -> ThreadId { + pub fn get_active_thread_id(&self) -> ThreadId { self.active_thread } /// Get the total number of threads that were ever spawn by this program. - fn get_total_thread_count(&self) -> usize { + pub fn get_total_thread_count(&self) -> usize { self.threads.len() } + /// Get the total of threads that are currently live, i.e., not yet terminated. + /// (They might be blocked.) + pub fn get_live_thread_count(&self) -> usize { + self.threads.iter().filter(|t| !matches!(t.state, ThreadState::Terminated)).count() + } + /// Has the given thread terminated? fn has_terminated(&self, thread_id: ThreadId) -> bool { self.threads[thread_id].state == ThreadState::Terminated @@ -366,7 +372,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } else { // The thread has already terminated - mark join happens-before if let Some(data_race) = data_race { - data_race.thread_joined(self.active_thread, joined_thread_id); + data_race.thread_joined(self, self.active_thread, joined_thread_id); } } Ok(()) @@ -378,7 +384,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Get the name of the active thread. - fn get_thread_name(&self) -> &[u8] { + pub fn get_thread_name(&self) -> &[u8] { self.active_thread_ref().thread_name() } @@ -460,21 +466,25 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { false }); } - // Set the thread into a terminated state in the data-race detector + // Set the thread into a terminated state in the data-race detector. if let Some(ref mut data_race) = data_race { - data_race.thread_terminated(); + data_race.thread_terminated(self); } // Check if we need to unblock any threads. + let mut joined_threads = vec![]; // store which threads joined, we'll need it for (i, thread) in self.threads.iter_enumerated_mut() { if thread.state == ThreadState::BlockedOnJoin(self.active_thread) { // The thread has terminated, mark happens-before edge to joining thread - if let Some(ref mut data_race) = data_race { - data_race.thread_joined(i, self.active_thread); + if let Some(_) = data_race { + joined_threads.push(i); } trace!("unblocking {:?} because {:?} terminated", i, self.active_thread); thread.state = ThreadState::Enabled; } } + for &i in &joined_threads { + data_race.as_mut().unwrap().thread_joined(self, i, self.active_thread); + } free_tls_statics } @@ -484,10 +494,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// used in stateless model checkers such as Loom: run the active thread as /// long as we can and switch only when we have to (the active thread was /// blocked, terminated, or has explicitly asked to be preempted). - fn schedule( - &mut self, - data_race: &Option, - ) -> InterpResult<'tcx, SchedulingAction> { + fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { // Check whether the thread has **just** terminated (`check_terminated` // checks whether the thread has popped all its stack and if yes, sets // the thread state to terminated). @@ -535,9 +542,6 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { debug_assert_ne!(self.active_thread, id); if thread.state == ThreadState::Enabled { self.active_thread = id; - if let Some(data_race) = data_race { - data_race.thread_set_active(self.active_thread); - } break; } } @@ -598,7 +602,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let id = this.machine.threads.create_thread(); if let Some(data_race) = &mut this.machine.data_race { - data_race.thread_created(id); + data_race.thread_created(&this.machine.threads, id); } id } @@ -619,9 +623,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn set_active_thread(&mut self, thread_id: ThreadId) -> ThreadId { let this = self.eval_context_mut(); - if let Some(data_race) = &this.machine.data_race { - data_race.thread_set_active(thread_id); - } this.machine.threads.set_active_thread_id(thread_id) } @@ -682,11 +683,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn set_active_thread_name(&mut self, new_thread_name: Vec) { let this = self.eval_context_mut(); - if let Some(data_race) = &mut this.machine.data_race { - if let Ok(string) = String::from_utf8(new_thread_name.clone()) { - data_race.thread_set_name(this.machine.threads.active_thread, string); - } - } this.machine.threads.set_thread_name(new_thread_name); } @@ -776,8 +772,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { let this = self.eval_context_mut(); - let data_race = &this.machine.data_race; - this.machine.threads.schedule(data_race) + this.machine.threads.schedule() } /// Handles thread termination of the active thread: wakes up threads joining on this one, From 3bbcafe3b59ee5c4537f65e820835c526531fe59 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 7 Dec 2021 22:05:13 -0500 Subject: [PATCH 3411/5092] Cache lookups into the borrow stack This adds a very simple LRU-like cache which stores the locations of often-used tags. While the implementation is very simple, the cache hit rate is incredible at ~99.9% on most programs, and often the element at position 0 in the cache has a hit rate of 90%. So the sub-optimality of this cache basicaly vanishes into the noise in a profile. Additionally, we keep a range which denotes where there might be an item granting Unique permission in the stack, so that when we invalidate Uniques we do not need to scan much of the stack, and often scan nothing at all. --- Cargo.toml | 5 + src/lib.rs | 4 +- src/stacked_borrows.rs | 139 +++--------- src/stacked_borrows/diagnostics.rs | 5 +- src/stacked_borrows/stack.rs | 349 +++++++++++++++++++++++++++++ ui_test/Cargo.toml | 4 + 6 files changed, 398 insertions(+), 108 deletions(-) create mode 100644 src/stacked_borrows/stack.rs diff --git a/Cargo.toml b/Cargo.toml index 6b7f369ae5a9..0dead9fa28f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,3 +50,8 @@ rustc_private = true [[test]] name = "compiletest" harness = false + +[features] +default = ["stack-cache"] +expensive-debug-assertions = [] +stack-cache = [] diff --git a/src/lib.rs b/src/lib.rs index e199fae31ee8..a98239711ef4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -90,8 +90,8 @@ pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ - CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag, SbTagExtra, Stack, - Stacks, + stack::Stack, CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, + SbTag, SbTagExtra, Stacks, }; pub use crate::sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId}; pub use crate::thread::{ diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 2cf5eb70c171..3a4b4ad65fa1 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -23,6 +23,10 @@ use crate::*; pub mod diagnostics; use diagnostics::{AllocHistory, TagHistory}; +pub mod stack; +use stack::Stack; + +pub type PtrId = NonZeroU64; pub type CallId = NonZeroU64; // Even reading memory can have effects on the stack, so we need a `RefCell` here. @@ -111,23 +115,6 @@ impl fmt::Debug for Item { } } -/// Extra per-location state. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct Stack { - /// Used *mostly* as a stack; never empty. - /// Invariants: - /// * Above a `SharedReadOnly` there can only be more `SharedReadOnly`. - /// * No tag occurs in the stack more than once. - borrows: Vec, - /// If this is `Some(id)`, then the actual current stack is unknown. This can happen when - /// wildcard pointers are used to access this location. What we do know is that `borrows` are at - /// the top of the stack, and below it are arbitrarily many items whose `tag` is strictly less - /// than `id`. - /// When the bottom is unknown, `borrows` always has a `SharedReadOnly` or `Unique` at the bottom; - /// we never have the unknown-to-known boundary in an SRW group. - unknown_bottom: Option, -} - /// Extra per-allocation state. #[derive(Clone, Debug)] pub struct Stacks { @@ -297,65 +284,10 @@ impl Permission { /// Core per-location operations: access, dealloc, reborrow. impl<'tcx> Stack { - /// Find the item granting the given kind of access to the given tag, and return where - /// it is on the stack. For wildcard tags, the given index is approximate, but if *no* - /// index is given it means the match was *not* in the known part of the stack. - /// `Ok(None)` indicates it matched the "unknown" part of the stack. - /// `Err` indicates it was not found. - fn find_granting( - &self, - access: AccessKind, - tag: SbTagExtra, - exposed_tags: &FxHashSet, - ) -> Result, ()> { - let SbTagExtra::Concrete(tag) = tag else { - // Handle the wildcard case. - // Go search the stack for an exposed tag. - if let Some(idx) = - self.borrows - .iter() - .enumerate() // we also need to know *where* in the stack - .rev() // search top-to-bottom - .find_map(|(idx, item)| { - // If the item fits and *might* be this wildcard, use it. - if item.perm.grants(access) && exposed_tags.contains(&item.tag) { - Some(idx) - } else { - None - } - }) - { - return Ok(Some(idx)); - } - // If we couldn't find it in the stack, check the unknown bottom. - return if self.unknown_bottom.is_some() { Ok(None) } else { Err(()) }; - }; - - if let Some(idx) = - self.borrows - .iter() - .enumerate() // we also need to know *where* in the stack - .rev() // search top-to-bottom - // Return permission of first item that grants access. - // We require a permission with the right tag, ensuring U3 and F3. - .find_map(|(idx, item)| { - if tag == item.tag && item.perm.grants(access) { Some(idx) } else { None } - }) - { - return Ok(Some(idx)); - } - - // Couldn't find it in the stack; but if there is an unknown bottom it might be there. - let found = self.unknown_bottom.is_some_and(|&unknown_limit| { - tag.0 < unknown_limit.0 // unknown_limit is an upper bound for what can be in the unknown bottom. - }); - if found { Ok(None) } else { Err(()) } - } - /// Find the first write-incompatible item above the given one -- /// i.e, find the height to which the stack will be truncated when writing to `granting`. fn find_first_write_incompatible(&self, granting: usize) -> usize { - let perm = self.borrows[granting].perm; + let perm = self.get(granting).unwrap().perm; match perm { Permission::SharedReadOnly => bug!("Cannot use SharedReadOnly for writing"), Permission::Disabled => bug!("Cannot use Disabled for anything"), @@ -366,7 +298,7 @@ impl<'tcx> Stack { Permission::SharedReadWrite => { // The SharedReadWrite *just* above us are compatible, to skip those. let mut idx = granting + 1; - while let Some(item) = self.borrows.get(idx) { + while let Some(item) = self.get(idx) { if item.perm == Permission::SharedReadWrite { // Go on. idx += 1; @@ -461,8 +393,7 @@ impl<'tcx> Stack { // There is a SRW group boundary between the unknown and the known, so everything is incompatible. 0 }; - for item in self.borrows.drain(first_incompatible_idx..).rev() { - trace!("access: popping item {:?}", item); + self.pop_items_after(first_incompatible_idx, |item| { Stack::item_popped( &item, Some((tag, alloc_range, offset, access)), @@ -470,7 +401,8 @@ impl<'tcx> Stack { alloc_history, )?; alloc_history.log_invalidation(item.tag, alloc_range, current_span); - } + Ok(()) + })?; } else { // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses. // The reason this is not following the stack discipline (by removing the first Unique and @@ -487,21 +419,16 @@ impl<'tcx> Stack { // We are reading from something in the unknown part. That means *all* `Unique` we know about are dead now. 0 }; - for idx in (first_incompatible_idx..self.borrows.len()).rev() { - let item = &mut self.borrows[idx]; - - if item.perm == Permission::Unique { - trace!("access: disabling item {:?}", item); - Stack::item_popped( - item, - Some((tag, alloc_range, offset, access)), - global, - alloc_history, - )?; - item.perm = Permission::Disabled; - alloc_history.log_invalidation(item.tag, alloc_range, current_span); - } - } + self.disable_uniques_starting_at(first_incompatible_idx, |item| { + Stack::item_popped( + &item, + Some((tag, alloc_range, offset, access)), + global, + alloc_history, + )?; + alloc_history.log_invalidation(item.tag, alloc_range, current_span); + Ok(()) + })?; } // If this was an approximate action, we now collapse everything into an unknown. @@ -509,22 +436,22 @@ impl<'tcx> Stack { // Compute the upper bound of the items that remain. // (This is why we did all the work above: to reduce the items we have to consider here.) let mut max = NonZeroU64::new(1).unwrap(); - for item in &self.borrows { + for i in 0..self.len() { + let item = self.get(i).unwrap(); // Skip disabled items, they cannot be matched anyway. if !matches!(item.perm, Permission::Disabled) { // We are looking for a strict upper bound, so add 1 to this tag. max = cmp::max(item.tag.0.checked_add(1).unwrap(), max); } } - if let Some(unk) = self.unknown_bottom { + if let Some(unk) = self.unknown_bottom() { max = cmp::max(unk.0, max); } // Use `max` as new strict upper bound for everything. trace!( "access: forgetting stack to upper bound {max} due to wildcard or unknown access" ); - self.borrows.clear(); - self.unknown_bottom = Some(SbTag(max)); + self.set_unknown_bottom(SbTag(max)); } // Done. @@ -553,7 +480,8 @@ impl<'tcx> Stack { })?; // Step 2: Remove all items. Also checks for protectors. - for item in self.borrows.drain(..).rev() { + for idx in (0..self.len()).rev() { + let item = self.get(idx).unwrap(); Stack::item_popped(&item, None, global, alloc_history)?; } Ok(()) @@ -601,8 +529,7 @@ impl<'tcx> Stack { // The new thing is SRW anyway, so we cannot push it "on top of the unkown part" // (for all we know, it might join an SRW group inside the unknown). trace!("reborrow: forgetting stack entirely due to SharedReadWrite reborrow from wildcard or unknown"); - self.borrows.clear(); - self.unknown_bottom = Some(global.next_ptr_tag); + self.set_unknown_bottom(global.next_ptr_tag); return Ok(()); }; @@ -629,19 +556,18 @@ impl<'tcx> Stack { // on top of `derived_from`, and we want the new item at the top so that we // get the strongest possible guarantees. // This ensures U1 and F1. - self.borrows.len() + self.len() }; // Put the new item there. As an optimization, deduplicate if it is equal to one of its new neighbors. // `new_idx` might be 0 if we just cleared the entire stack. - if self.borrows.get(new_idx) == Some(&new) - || (new_idx > 0 && self.borrows[new_idx - 1] == new) + if self.get(new_idx) == Some(new) || (new_idx > 0 && self.get(new_idx - 1).unwrap() == new) { // Optimization applies, done. trace!("reborrow: avoiding adding redundant item {:?}", new); } else { trace!("reborrow: adding item {:?}", new); - self.borrows.insert(new_idx, new); + self.insert(new_idx, new); } Ok(()) } @@ -653,8 +579,8 @@ impl<'tcx> Stacks { /// Creates new stack with initial tag. fn new(size: Size, perm: Permission, tag: SbTag) -> Self { let item = Item { perm, tag, protector: None }; - let stack = Stack { borrows: vec![item], unknown_bottom: None }; + let stack = Stack::new(item); Stacks { stacks: RangeMap::new(size, stack), history: AllocHistory::new(), @@ -900,11 +826,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We have to use shared references to alloc/memory_extra here since // `visit_freeze_sensitive` needs to access the global state. let extra = this.get_alloc_extra(alloc_id)?; + let mut stacked_borrows = extra .stacked_borrows .as_ref() .expect("we should have Stacked Borrows data") .borrow_mut(); + let mut current_span = this.machine.current_span(); + this.visit_freeze_sensitive(place, size, |mut range, frozen| { // Adjust range. range.start += base_offset; @@ -929,7 +858,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx item, (alloc_id, range, offset), &mut global, - current_span, + &mut current_span, history, exposed_tags, ) diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index b1ff864bcd5e..a7b8e5f13cea 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -185,7 +185,10 @@ fn operation_summary( fn error_cause(stack: &Stack, tag: SbTagExtra) -> &'static str { if let SbTagExtra::Concrete(tag) = tag { - if stack.borrows.iter().any(|item| item.tag == tag && item.perm != Permission::Disabled) { + if (0..stack.len()) + .map(|i| stack.get(i).unwrap()) + .any(|item| item.tag == tag && item.perm != Permission::Disabled) + { ", but that tag only grants SharedReadOnly permission for this location" } else { ", but that tag does not exist in the borrow stack for this location" diff --git a/src/stacked_borrows/stack.rs b/src/stacked_borrows/stack.rs new file mode 100644 index 000000000000..e6dc507802fd --- /dev/null +++ b/src/stacked_borrows/stack.rs @@ -0,0 +1,349 @@ +use crate::stacked_borrows::{AccessKind, Item, Permission, SbTag, SbTagExtra}; +use rustc_data_structures::fx::FxHashSet; +#[cfg(feature = "stack-cache")] +use std::ops::Range; + +/// Exactly what cache size we should use is a difficult tradeoff. There will always be some +/// workload which has a `SbTag` working set which exceeds the size of the cache, and ends up +/// falling back to linear searches of the borrow stack very often. +/// The cost of making this value too large is that the loop in `Stack::insert` which ensures the +/// entries in the cache stay correct after an insert becomes expensive. +#[cfg(feature = "stack-cache")] +const CACHE_LEN: usize = 32; + +/// Extra per-location state. +#[derive(Clone, Debug)] +pub struct Stack { + /// Used *mostly* as a stack; never empty. + /// Invariants: + /// * Above a `SharedReadOnly` there can only be more `SharedReadOnly`. + /// * Except for `Untagged`, no tag occurs in the stack more than once. + borrows: Vec, + /// If this is `Some(id)`, then the actual current stack is unknown. This can happen when + /// wildcard pointers are used to access this location. What we do know is that `borrows` are at + /// the top of the stack, and below it are arbitrarily many items whose `tag` is strictly less + /// than `id`. + /// When the bottom is unknown, `borrows` always has a `SharedReadOnly` or `Unique` at the bottom; + /// we never have the unknown-to-known boundary in an SRW group. + unknown_bottom: Option, + + /// A small LRU cache of searches of the borrow stack. This only caches accesses of `Tagged`, + /// because those are unique in the stack. + #[cfg(feature = "stack-cache")] + cache: StackCache, + /// On a read, we need to disable all `Unique` above the granting item. We can avoid most of + /// this scan by keeping track of the region of the borrow stack that may contain `Unique`s. + #[cfg(feature = "stack-cache")] + unique_range: Range, +} + +/// A very small cache of searches of the borrow stack +/// This maps tags to locations in the borrow stack. Any use of this still needs to do a +/// probably-cold random access into the borrow stack to figure out what `Permission` an +/// `SbTag` grants. We could avoid this by also storing the `Permission` in the cache, but +/// most lookups into the cache are immediately followed by access of the full borrow stack anyway. +#[cfg(feature = "stack-cache")] +#[derive(Clone, Debug)] +struct StackCache { + tags: [SbTag; CACHE_LEN], // Hot in find_granting + idx: [usize; CACHE_LEN], // Hot in grant +} + +#[cfg(feature = "stack-cache")] +impl StackCache { + fn add(&mut self, idx: usize, tag: SbTag) { + self.tags.copy_within(0..CACHE_LEN - 1, 1); + self.tags[0] = tag; + self.idx.copy_within(0..CACHE_LEN - 1, 1); + self.idx[0] = idx; + } +} + +impl PartialEq for Stack { + fn eq(&self, other: &Self) -> bool { + // All the semantics of Stack are in self.borrows, everything else is caching + self.borrows == other.borrows + } +} + +impl Eq for Stack {} + +impl<'tcx> Stack { + /// Panics if any of the caching mechanisms have broken, + /// - The StackCache indices don't refer to the parallel tags, + /// - There are no Unique tags outside of first_unique..last_unique + #[cfg(feature = "expensive-debug-assertions")] + fn verify_cache_consistency(&self) { + if self.borrows.len() > CACHE_LEN { + for (tag, stack_idx) in self.cache.tags.iter().zip(self.cache.idx.iter()) { + assert_eq!(self.borrows[*stack_idx].tag, *tag); + } + } + + for (idx, item) in self.borrows.iter().enumerate() { + if item.perm == Permission::Unique { + assert!( + self.unique_range.contains(&idx), + "{:?} {:?}", + self.unique_range, + self.borrows + ); + } + } + } + + /// Find the item granting the given kind of access to the given tag, and return where + /// it is on the stack. For wildcard tags, the given index is approximate, but if *no* + /// index is given it means the match was *not* in the known part of the stack. + /// `Ok(None)` indicates it matched the "unknown" part of the stack. + /// `Err` indicates it was not found. + pub fn find_granting( + &mut self, + access: AccessKind, + tag: SbTagExtra, + exposed_tags: &FxHashSet, + ) -> Result, ()> { + #[cfg(feature = "expensive-debug-assertions")] + self.verify_cache_consistency(); + + let SbTagExtra::Concrete(tag) = tag else { + // Handle the wildcard case. + // Go search the stack for an exposed tag. + if let Some(idx) = + self.borrows + .iter() + .enumerate() // we also need to know *where* in the stack + .rev() // search top-to-bottom + .find_map(|(idx, item)| { + // If the item fits and *might* be this wildcard, use it. + if item.perm.grants(access) && exposed_tags.contains(&item.tag) { + Some(idx) + } else { + None + } + }) + { + return Ok(Some(idx)); + } + // If we couldn't find it in the stack, check the unknown bottom. + return if self.unknown_bottom.is_some() { Ok(None) } else { Err(()) }; + }; + + if let Some(idx) = self.find_granting_tagged(access, tag) { + return Ok(Some(idx)); + } + + // Couldn't find it in the stack; but if there is an unknown bottom it might be there. + let found = self.unknown_bottom.is_some_and(|&unknown_limit| { + tag.0 < unknown_limit.0 // unknown_limit is an upper bound for what can be in the unknown bottom. + }); + if found { Ok(None) } else { Err(()) } + } + + fn find_granting_tagged(&mut self, access: AccessKind, tag: SbTag) -> Option { + #[cfg(feature = "stack-cache")] + if let Some(idx) = self.find_granting_cache(access, tag) { + return Some(idx); + } + + // If we didn't find the tag in the cache, fall back to a linear search of the + // whole stack, and add the tag to the stack. + for (stack_idx, item) in self.borrows.iter().enumerate().rev() { + if tag == item.tag && item.perm.grants(access) { + #[cfg(feature = "stack-cache")] + self.cache.add(stack_idx, tag); + return Some(stack_idx); + } + } + None + } + + #[cfg(feature = "stack-cache")] + fn find_granting_cache(&mut self, access: AccessKind, tag: SbTag) -> Option { + // When the borrow stack is empty, there are no tags we could put into the cache that would + // be valid. Additionally, since lookups into the cache are a linear search it doesn't make + // sense to use the cache when it is no smaller than a search of the borrow stack itself. + if self.borrows.len() <= CACHE_LEN { + return None; + } + // Search the cache for the tag we're looking up + let cache_idx = self.cache.tags.iter().position(|t| *t == tag)?; + let stack_idx = self.cache.idx[cache_idx]; + // If we found the tag, look up its position in the stack to see if it grants + // the required permission + if self.borrows[stack_idx].perm.grants(access) { + // If it does, and it's already in the most-recently-used position, move it + // there. + if cache_idx != 0 { + self.cache.add(stack_idx, tag); + } + Some(stack_idx) + } else { + // Tag is in the cache, but it doesn't grant the required permission + None + } + } + + pub fn insert(&mut self, new_idx: usize, new: Item) { + self.borrows.insert(new_idx, new); + + #[cfg(feature = "stack-cache")] + self.insert_cache(new_idx, new); + } + + #[cfg(feature = "stack-cache")] + fn insert_cache(&mut self, new_idx: usize, new: Item) { + // Adjust the possibly-unique range if an insert occurs before or within it + if self.unique_range.start >= new_idx { + self.unique_range.start += 1; + } + if self.unique_range.end >= new_idx { + self.unique_range.end += 1; + } + if new.perm == Permission::Unique { + // Make sure the possibly-unique range contains the new borrow + self.unique_range.start = self.unique_range.start.min(new_idx); + self.unique_range.end = self.unique_range.end.max(new_idx + 1); + } + + // The above insert changes the meaning of every index in the cache >= new_idx, so now + // we need to find every one of those indexes and increment it. + for idx in &mut self.cache.idx { + if *idx >= new_idx { + *idx += 1; + } + } + + // This primes the cache for the next access, which is almost always the just-added tag. + self.cache.add(new_idx, new.tag); + + #[cfg(feature = "expensive-debug-assertions")] + self.verify_cache_consistency(); + } + + /// Construct a new `Stack` using the passed `Item` as the base tag. + pub fn new(item: Item) -> Self { + Stack { + borrows: vec![item], + unknown_bottom: None, + #[cfg(feature = "stack-cache")] + cache: StackCache { idx: [0; CACHE_LEN], tags: [item.tag; CACHE_LEN] }, + #[cfg(feature = "stack-cache")] + unique_range: if item.perm == Permission::Unique { 0..1 } else { 0..0 }, + } + } + + pub fn get(&self, idx: usize) -> Option { + self.borrows.get(idx).cloned() + } + + #[allow(clippy::len_without_is_empty)] // Stacks are never empty + pub fn len(&self) -> usize { + self.borrows.len() + } + + pub fn unknown_bottom(&self) -> Option { + self.unknown_bottom + } + + pub fn set_unknown_bottom(&mut self, tag: SbTag) { + self.borrows.clear(); + self.unknown_bottom = Some(tag); + } + + /// Find all `Unique` elements in this borrow stack above `granting_idx`, pass a copy of them + /// to the `visitor`, then set their `Permission` to `Disabled`. + pub fn disable_uniques_starting_at crate::InterpResult<'tcx>>( + &mut self, + disable_start: usize, + mut visitor: V, + ) -> crate::InterpResult<'tcx> { + #[cfg(feature = "stack-cache")] + let unique_range = self.unique_range.clone(); + #[cfg(not(feature = "stack-cache"))] + let unique_range = 0..self.len(); + + if disable_start <= unique_range.end { + // add 1 so we don't disable the granting item + let lower = unique_range.start.max(disable_start); + let upper = (unique_range.end + 1).min(self.borrows.len()); + for item in &mut self.borrows[lower..upper] { + if item.perm == Permission::Unique { + log::trace!("access: disabling item {:?}", item); + visitor(*item)?; + item.perm = Permission::Disabled; + } + } + } + + #[cfg(feature = "stack-cache")] + if disable_start < self.unique_range.start { + // We disabled all Unique items + self.unique_range.start = 0; + self.unique_range.end = 0; + } else { + // Truncate the range to disable_start. This is + 2 because we are only removing + // elements after disable_start, and this range does not include the end. + self.unique_range.end = self.unique_range.end.min(disable_start + 1); + } + + #[cfg(feature = "expensive-debug-assertions")] + self.verify_cache_consistency(); + + Ok(()) + } + + /// Produces an iterator which iterates over `range` in reverse, and when dropped removes that + /// range of `Item`s from this `Stack`. + pub fn pop_items_after crate::InterpResult<'tcx>>( + &mut self, + start: usize, + mut visitor: V, + ) -> crate::InterpResult<'tcx> { + while self.borrows.len() > start { + let item = self.borrows.pop().unwrap(); + visitor(item)?; + } + + #[cfg(feature = "stack-cache")] + if !self.borrows.is_empty() { + // After we remove from the borrow stack, every aspect of our caching may be invalid, but it is + // also possible that the whole cache is still valid. So we call this method to repair what + // aspects of the cache are now invalid, instead of resetting the whole thing to a trivially + // valid default state. + let base_tag = self.borrows[0].tag; + let mut removed = 0; + let mut cursor = 0; + // Remove invalid entries from the cache by rotating them to the end of the cache, then + // keep track of how many invalid elements there are and overwrite them with the base tag. + // The base tag here serves as a harmless default value. + for _ in 0..CACHE_LEN - 1 { + if self.cache.idx[cursor] >= start { + self.cache.idx[cursor..CACHE_LEN - removed].rotate_left(1); + self.cache.tags[cursor..CACHE_LEN - removed].rotate_left(1); + removed += 1; + } else { + cursor += 1; + } + } + for i in CACHE_LEN - removed - 1..CACHE_LEN { + self.cache.idx[i] = 0; + self.cache.tags[i] = base_tag; + } + + if start < self.unique_range.start.saturating_sub(1) { + // We removed all the Unique items + self.unique_range = 0..0; + } else { + // Ensure the range doesn't extend past the new top of the stack + self.unique_range.end = self.unique_range.end.min(start + 1); + } + } else { + self.unique_range = 0..0; + } + + #[cfg(feature = "expensive-debug-assertions")] + self.verify_cache_consistency(); + Ok(()) + } +} diff --git a/ui_test/Cargo.toml b/ui_test/Cargo.toml index 92c00915cbfe..0838733db2de 100644 --- a/ui_test/Cargo.toml +++ b/ui_test/Cargo.toml @@ -14,3 +14,7 @@ crossbeam = "0.8.1" lazy_static = "1.4.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" + +[features] +# Doesn't do anything, but the miri script wants to pass the same flags to ui_test and miri itself +expensive-debug-assertions = [] From d09db1660b0c7baca06029369bc48b8d9c604f0a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Jul 2022 17:33:17 -0400 Subject: [PATCH 3412/5092] fix and slightly improve data race reports --- src/concurrency/data_race.rs | 17 ++++--------- src/concurrency/weak_memory.rs | 2 +- src/thread.rs | 25 ++++++++++++++----- tests/compiletest.rs | 2 -- tests/fail/data_race/alloc_read_race.rs | 2 +- tests/fail/data_race/alloc_read_race.stderr | 4 +-- tests/fail/data_race/alloc_write_race.rs | 2 +- tests/fail/data_race/alloc_write_race.stderr | 4 +-- .../data_race/atomic_read_na_write_race1.rs | 2 +- .../atomic_read_na_write_race1.stderr | 4 +-- .../data_race/atomic_read_na_write_race2.rs | 2 +- .../atomic_read_na_write_race2.stderr | 4 +-- .../data_race/atomic_write_na_read_race1.rs | 2 +- .../atomic_write_na_read_race1.stderr | 4 +-- .../data_race/atomic_write_na_read_race2.rs | 2 +- .../atomic_write_na_read_race2.stderr | 4 +-- .../data_race/atomic_write_na_write_race1.rs | 2 +- .../atomic_write_na_write_race1.stderr | 4 +-- .../data_race/atomic_write_na_write_race2.rs | 2 +- .../atomic_write_na_write_race2.stderr | 4 +-- .../data_race/dangling_thread_async_race.rs | 2 +- .../dangling_thread_async_race.stderr | 4 +-- tests/fail/data_race/dangling_thread_race.rs | 2 +- .../data_race/dangling_thread_race.stderr | 4 +-- tests/fail/data_race/dealloc_read_race1.rs | 2 +- .../fail/data_race/dealloc_read_race1.stderr | 4 +-- tests/fail/data_race/dealloc_read_race2.rs | 2 +- .../fail/data_race/dealloc_read_race_stack.rs | 2 +- .../data_race/dealloc_read_race_stack.stderr | 4 +-- tests/fail/data_race/dealloc_write_race1.rs | 2 +- .../fail/data_race/dealloc_write_race1.stderr | 4 +-- tests/fail/data_race/dealloc_write_race2.rs | 2 +- .../data_race/dealloc_write_race_stack.rs | 2 +- .../data_race/dealloc_write_race_stack.stderr | 4 +-- .../data_race/enable_after_join_to_main.rs | 2 +- .../enable_after_join_to_main.stderr | 4 +-- tests/fail/data_race/fence_after_load.rs | 2 +- tests/fail/data_race/fence_after_load.stderr | 4 +-- tests/fail/data_race/read_write_race.rs | 2 +- tests/fail/data_race/read_write_race.stderr | 4 +-- tests/fail/data_race/read_write_race_stack.rs | 2 +- .../data_race/read_write_race_stack.stderr | 4 +-- tests/fail/data_race/relax_acquire_race.rs | 2 +- .../fail/data_race/relax_acquire_race.stderr | 4 +-- tests/fail/data_race/release_seq_race.rs | 2 +- tests/fail/data_race/release_seq_race.stderr | 4 +-- .../data_race/release_seq_race_same_thread.rs | 2 +- .../release_seq_race_same_thread.stderr | 4 +-- tests/fail/data_race/rmw_race.rs | 2 +- tests/fail/data_race/rmw_race.stderr | 4 +-- tests/fail/data_race/write_write_race.rs | 2 +- tests/fail/data_race/write_write_race.stderr | 4 +-- .../fail/data_race/write_write_race_stack.rs | 2 +- .../data_race/write_write_race_stack.stderr | 4 +-- tests/pass/libc.rs | 3 ++- 55 files changed, 101 insertions(+), 96 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 205b56ca4c07..4b402b51fc59 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -882,7 +882,7 @@ impl VClockAlloc { ) -> InterpResult<'tcx> { let (current_index, current_clocks) = global.current_thread_state(thread_mgr); let write_clock; - let (other_action, other_thread, other_clock) = if range.write + let (other_action, other_thread, _other_clock) = if range.write > current_clocks.clock[range.write_index] { // Convert the write action into the vector clock it @@ -920,14 +920,12 @@ impl VClockAlloc { // Throw the data-race detection. throw_ub_format!( - "Data race detected between {} on {} and {} on {} at {:?} (current vector clock = {:?}, conflicting timestamp = {:?})", + "Data race detected between {} on {} and {} on {} at {:?}", action, current_thread_info, other_action, other_thread_info, ptr_dbg, - current_clocks.clock, - other_clock ) } @@ -1208,8 +1206,7 @@ impl GlobalState { }; // Setup the main-thread since it is not explicitly created: - // uses vector index and thread-id 0, also the rust runtime gives - // the main-thread a name of "main". + // uses vector index and thread-id 0. let index = global_state.vector_clocks.get_mut().push(ThreadClockSet::default()); global_state.vector_info.get_mut().push(ThreadId::new(0)); global_state @@ -1448,12 +1445,8 @@ impl GlobalState { vector: VectorIdx, ) -> String { let thread = self.vector_info.borrow()[vector]; - let thread_name = thread_mgr.get_thread_name(); - format!( - "Thread(id = {:?}, name = {:?})", - thread.to_u32(), - String::from_utf8_lossy(thread_name) - ) + let thread_name = thread_mgr.get_thread_name(thread); + format!("thread `{}`", String::from_utf8_lossy(thread_name)) } /// Acquire a lock, express that the previous call of diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index e7ed9ea09a82..f7cc9c4732ac 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -9,7 +9,7 @@ //! Note that this implementation does not take into account of C++20's memory model revision to SC accesses //! and fences introduced by P0668 (). //! This implementation is not fully correct under the revised C++20 model and may generate behaviours C++20 -//! disallows. +//! disallows (). //! //! Rust follows the C++20 memory model (except for the Consume ordering and some operations not performable through C++'s //! std::atomic API). It is therefore possible for this implementation to generate behaviours never observable when the diff --git a/src/thread.rs b/src/thread.rs index 7327f2b8114f..420eeb810fd8 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -170,6 +170,14 @@ impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> { } } +impl<'mir, 'tcx> Thread<'mir, 'tcx> { + fn new(name: &str) -> Self { + let mut thread = Thread::default(); + thread.thread_name = Some(Vec::from(name.as_bytes())); + thread + } +} + /// A specific moment in time. #[derive(Debug)] pub enum Time { @@ -230,7 +238,7 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { fn default() -> Self { let mut threads = IndexVec::new(); // Create the main thread and add it to the list of threads. - let mut main_thread = Thread::default(); + let mut main_thread = Thread::new("main"); // The main thread can *not* be joined on. main_thread.join_status = ThreadJoinStatus::Detached; threads.push(main_thread); @@ -379,15 +387,20 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Set the name of the active thread. - fn set_thread_name(&mut self, new_thread_name: Vec) { + fn set_active_thread_name(&mut self, new_thread_name: Vec) { self.active_thread_mut().thread_name = Some(new_thread_name); } /// Get the name of the active thread. - pub fn get_thread_name(&self) -> &[u8] { + pub fn get_active_thread_name(&self) -> &[u8] { self.active_thread_ref().thread_name() } + /// Get the name of the given thread. + pub fn get_thread_name(&self, thread: ThreadId) -> &[u8] { + self.threads[thread].thread_name() + } + /// Put the thread into the blocked state. fn block_thread(&mut self, thread: ThreadId) { let state = &mut self.threads[thread].state; @@ -475,7 +488,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { for (i, thread) in self.threads.iter_enumerated_mut() { if thread.state == ThreadState::BlockedOnJoin(self.active_thread) { // The thread has terminated, mark happens-before edge to joining thread - if let Some(_) = data_race { + if data_race.is_some() { joined_threads.push(i); } trace!("unblocking {:?} because {:?} terminated", i, self.active_thread); @@ -683,7 +696,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn set_active_thread_name(&mut self, new_thread_name: Vec) { let this = self.eval_context_mut(); - this.machine.threads.set_thread_name(new_thread_name); + this.machine.threads.set_active_thread_name(new_thread_name); } #[inline] @@ -692,7 +705,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx 'mir: 'c, { let this = self.eval_context_ref(); - this.machine.threads.get_thread_name() + this.machine.threads.get_active_thread_name() } #[inline] diff --git a/tests/compiletest.rs b/tests/compiletest.rs index e4d8511b51df..754fccd63b13 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -94,8 +94,6 @@ regexes! { "([0-9]+: ) +0x[0-9a-f]+ - (.*)" => "$1$2", // erase long hexadecimals r"0x[0-9a-fA-F]+[0-9a-fA-F]{2,2}" => "$$HEX", - // erase clocks - r"VClock\(\[[^\]]+\]\)" => "VClock", // erase specific alignments "alignment [0-9]+" => "alignment ALIGN", // erase thread caller ids diff --git a/tests/fail/data_race/alloc_read_race.rs b/tests/fail/data_race/alloc_read_race.rs index 12c1b6ec876a..1eac8ce0f26c 100644 --- a/tests/fail/data_race/alloc_read_race.rs +++ b/tests/fail/data_race/alloc_read_race.rs @@ -38,7 +38,7 @@ pub fn main() { let pointer = &*ptr.0; // Note: could also error due to reading uninitialized memory, but the data-race detector triggers first. - *pointer.load(Ordering::Relaxed) //~ ERROR Data race detected between Read on Thread(id = 2) and Allocate on Thread(id = 1) + *pointer.load(Ordering::Relaxed) //~ ERROR Data race detected between Read on thread `` and Allocate on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/alloc_read_race.stderr b/tests/fail/data_race/alloc_read_race.stderr index 52004f2d2d02..2049e4f4a193 100644 --- a/tests/fail/data_race/alloc_read_race.stderr +++ b/tests/fail/data_race/alloc_read_race.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Read on Thread(id = 2) and Allocate on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Read on thread `` and Allocate on thread `` at ALLOC --> $DIR/alloc_read_race.rs:LL:CC | LL | *pointer.load(Ordering::Relaxed) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Read on Thread(id = 2) and Allocate on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Read on thread `` and Allocate on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/alloc_write_race.rs b/tests/fail/data_race/alloc_write_race.rs index c050d24bee10..e618b72a8227 100644 --- a/tests/fail/data_race/alloc_write_race.rs +++ b/tests/fail/data_race/alloc_write_race.rs @@ -36,7 +36,7 @@ pub fn main() { let j2 = spawn(move || { let pointer = &*ptr.0; - *pointer.load(Ordering::Relaxed) = 2; //~ ERROR Data race detected between Write on Thread(id = 2) and Allocate on Thread(id = 1) + *pointer.load(Ordering::Relaxed) = 2; //~ ERROR Data race detected between Write on thread `` and Allocate on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/alloc_write_race.stderr b/tests/fail/data_race/alloc_write_race.stderr index b6c05b34073c..82e3d92479d9 100644 --- a/tests/fail/data_race/alloc_write_race.stderr +++ b/tests/fail/data_race/alloc_write_race.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Allocate on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Write on thread `` and Allocate on thread `` at ALLOC --> $DIR/alloc_write_race.rs:LL:CC | LL | *pointer.load(Ordering::Relaxed) = 2; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Write on Thread(id = 2) and Allocate on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Write on thread `` and Allocate on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/atomic_read_na_write_race1.rs b/tests/fail/data_race/atomic_read_na_write_race1.rs index 5cf2f26bf1f0..3b948eea9805 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.rs +++ b/tests/fail/data_race/atomic_read_na_write_race1.rs @@ -22,7 +22,7 @@ pub fn main() { let j2 = spawn(move || { //Equivalent to: (&*c.0).load(Ordering::SeqCst) - intrinsics::atomic_load_seqcst(c.0 as *mut usize) //~ ERROR Data race detected between Atomic Load on Thread(id = 2) and Write on Thread(id = 1) + intrinsics::atomic_load_seqcst(c.0 as *mut usize) //~ ERROR Data race detected between Atomic Load on thread `` and Write on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_read_na_write_race1.stderr b/tests/fail/data_race/atomic_read_na_write_race1.stderr index 51cdb239507a..4b5355e866e2 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.stderr +++ b/tests/fail/data_race/atomic_read_na_write_race1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Atomic Load on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Atomic Load on thread `` and Write on thread `` at ALLOC --> $DIR/atomic_read_na_write_race1.rs:LL:CC | LL | intrinsics::atomic_load_seqcst(c.0 as *mut usize) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Load on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Load on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/atomic_read_na_write_race2.rs b/tests/fail/data_race/atomic_read_na_write_race2.rs index 1c0146367ad5..44b4eebee805 100644 --- a/tests/fail/data_race/atomic_read_na_write_race2.rs +++ b/tests/fail/data_race/atomic_read_na_write_race2.rs @@ -22,7 +22,7 @@ pub fn main() { let j2 = spawn(move || { let atomic_ref = &mut *c.0; - *atomic_ref.get_mut() = 32; //~ ERROR Data race detected between Write on Thread(id = 2) and Atomic Load on Thread(id = 1) + *atomic_ref.get_mut() = 32; //~ ERROR Data race detected between Write on thread `` and Atomic Load on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_read_na_write_race2.stderr b/tests/fail/data_race/atomic_read_na_write_race2.stderr index 9a432c586afe..3eb9f17bae76 100644 --- a/tests/fail/data_race/atomic_read_na_write_race2.stderr +++ b/tests/fail/data_race/atomic_read_na_write_race2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Atomic Load on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Write on thread `` and Atomic Load on thread `` at ALLOC --> $DIR/atomic_read_na_write_race2.rs:LL:CC | LL | *atomic_ref.get_mut() = 32; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Write on Thread(id = 2) and Atomic Load on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Write on thread `` and Atomic Load on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/atomic_write_na_read_race1.rs b/tests/fail/data_race/atomic_write_na_read_race1.rs index a63aafb0453c..44dc1a908416 100644 --- a/tests/fail/data_race/atomic_write_na_read_race1.rs +++ b/tests/fail/data_race/atomic_write_na_read_race1.rs @@ -22,7 +22,7 @@ pub fn main() { let j2 = spawn(move || { let atomic_ref = &mut *c.0; - *atomic_ref.get_mut() //~ ERROR Data race detected between Read on Thread(id = 2) and Atomic Store on Thread(id = 1) + *atomic_ref.get_mut() //~ ERROR Data race detected between Read on thread `` and Atomic Store on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_write_na_read_race1.stderr b/tests/fail/data_race/atomic_write_na_read_race1.stderr index 8280f43b518f..810fa54d41ce 100644 --- a/tests/fail/data_race/atomic_write_na_read_race1.stderr +++ b/tests/fail/data_race/atomic_write_na_read_race1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Read on Thread(id = 2) and Atomic Store on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Read on thread `` and Atomic Store on thread `` at ALLOC --> $DIR/atomic_write_na_read_race1.rs:LL:CC | LL | *atomic_ref.get_mut() - | ^^^^^^^^^^^^^^^^^^^^^ Data race detected between Read on Thread(id = 2) and Atomic Store on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^^^^^^^^^^^^^ Data race detected between Read on thread `` and Atomic Store on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/atomic_write_na_read_race2.rs b/tests/fail/data_race/atomic_write_na_read_race2.rs index 0b055c9b96ec..b4b21b64fc1f 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.rs +++ b/tests/fail/data_race/atomic_write_na_read_race2.rs @@ -22,7 +22,7 @@ pub fn main() { let j2 = spawn(move || { //Equivalent to: (&*c.0).store(32, Ordering::SeqCst) - atomic_store(c.0 as *mut usize, 32); //~ ERROR Data race detected between Atomic Store on Thread(id = 2) and Read on Thread(id = 1) + atomic_store(c.0 as *mut usize, 32); //~ ERROR Data race detected between Atomic Store on thread `` and Read on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_write_na_read_race2.stderr b/tests/fail/data_race/atomic_write_na_read_race2.stderr index 63d0f5814ef4..77f69e2bc340 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.stderr +++ b/tests/fail/data_race/atomic_write_na_read_race2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Atomic Store on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Atomic Store on thread `` and Read on thread `` at ALLOC --> $DIR/atomic_write_na_read_race2.rs:LL:CC | LL | atomic_store(c.0 as *mut usize, 32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Store on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Store on thread `` and Read on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/atomic_write_na_write_race1.rs b/tests/fail/data_race/atomic_write_na_write_race1.rs index 8268924e3c1a..b1a4cfb98bd1 100644 --- a/tests/fail/data_race/atomic_write_na_write_race1.rs +++ b/tests/fail/data_race/atomic_write_na_write_race1.rs @@ -22,7 +22,7 @@ pub fn main() { let j2 = spawn(move || { //Equivalent to: (&*c.0).store(64, Ordering::SeqCst) - atomic_store(c.0 as *mut usize, 64); //~ ERROR Data race detected between Atomic Store on Thread(id = 2) and Write on Thread(id = 1) + atomic_store(c.0 as *mut usize, 64); //~ ERROR Data race detected between Atomic Store on thread `` and Write on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_write_na_write_race1.stderr b/tests/fail/data_race/atomic_write_na_write_race1.stderr index 332be7406c82..8e70de5e4aff 100644 --- a/tests/fail/data_race/atomic_write_na_write_race1.stderr +++ b/tests/fail/data_race/atomic_write_na_write_race1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Atomic Store on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Atomic Store on thread `` and Write on thread `` at ALLOC --> $DIR/atomic_write_na_write_race1.rs:LL:CC | LL | atomic_store(c.0 as *mut usize, 64); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Store on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Store on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/atomic_write_na_write_race2.rs b/tests/fail/data_race/atomic_write_na_write_race2.rs index 440c72a059d8..dbdce8f6237c 100644 --- a/tests/fail/data_race/atomic_write_na_write_race2.rs +++ b/tests/fail/data_race/atomic_write_na_write_race2.rs @@ -22,7 +22,7 @@ pub fn main() { let j2 = spawn(move || { let atomic_ref = &mut *c.0; - *atomic_ref.get_mut() = 32; //~ ERROR Data race detected between Write on Thread(id = 2) and Atomic Store on Thread(id = 1) + *atomic_ref.get_mut() = 32; //~ ERROR Data race detected between Write on thread `` and Atomic Store on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_write_na_write_race2.stderr b/tests/fail/data_race/atomic_write_na_write_race2.stderr index 024f525b1213..310c2ed7df8a 100644 --- a/tests/fail/data_race/atomic_write_na_write_race2.stderr +++ b/tests/fail/data_race/atomic_write_na_write_race2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Atomic Store on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Write on thread `` and Atomic Store on thread `` at ALLOC --> $DIR/atomic_write_na_write_race2.rs:LL:CC | LL | *atomic_ref.get_mut() = 32; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Write on Thread(id = 2) and Atomic Store on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Write on thread `` and Atomic Store on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/dangling_thread_async_race.rs b/tests/fail/data_race/dangling_thread_async_race.rs index 2656f4b7af14..65325b60f2f3 100644 --- a/tests/fail/data_race/dangling_thread_async_race.rs +++ b/tests/fail/data_race/dangling_thread_async_race.rs @@ -34,7 +34,7 @@ fn main() { let join2 = unsafe { spawn(move || { - *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 3) and Write on Thread(id = 1) + *c.0 = 64; //~ ERROR Data race detected between Write on thread `` and Write on thread `` }) }; diff --git a/tests/fail/data_race/dangling_thread_async_race.stderr b/tests/fail/data_race/dangling_thread_async_race.stderr index 6d31e3971e53..efdc913ce27a 100644 --- a/tests/fail/data_race/dangling_thread_async_race.stderr +++ b/tests/fail/data_race/dangling_thread_async_race.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Write on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Write on thread `` and Write on thread `` at ALLOC --> $DIR/dangling_thread_async_race.rs:LL:CC | LL | *c.0 = 64; - | ^^^^^^^^^ Data race detected between Write on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^ Data race detected between Write on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/dangling_thread_race.rs b/tests/fail/data_race/dangling_thread_race.rs index f1174d8ff6ee..09e7032c9330 100644 --- a/tests/fail/data_race/dangling_thread_race.rs +++ b/tests/fail/data_race/dangling_thread_race.rs @@ -33,6 +33,6 @@ fn main() { spawn(|| ()).join().unwrap(); unsafe { - *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) + *c.0 = 64; //~ ERROR Data race detected between Write on thread `main` and Write on thread `` } } diff --git a/tests/fail/data_race/dangling_thread_race.stderr b/tests/fail/data_race/dangling_thread_race.stderr index ba1ef2760f8f..899cfdd095e3 100644 --- a/tests/fail/data_race/dangling_thread_race.stderr +++ b/tests/fail/data_race/dangling_thread_race.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Write on thread `main` and Write on thread `` at ALLOC --> $DIR/dangling_thread_race.rs:LL:CC | LL | *c.0 = 64; - | ^^^^^^^^^ Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^ Data race detected between Write on thread `main` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/dealloc_read_race1.rs b/tests/fail/data_race/dealloc_read_race1.rs index 555700a75d3a..ff2ac8ca522a 100644 --- a/tests/fail/data_race/dealloc_read_race1.rs +++ b/tests/fail/data_race/dealloc_read_race1.rs @@ -24,7 +24,7 @@ pub fn main() { let j2 = spawn(move || { __rust_dealloc( - //~^ ERROR Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) + //~^ ERROR Data race detected between Deallocate on thread `` and Read on thread `` ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::(), diff --git a/tests/fail/data_race/dealloc_read_race1.stderr b/tests/fail/data_race/dealloc_read_race1.stderr index 91a681e74450..9e35fb7b6bd8 100644 --- a/tests/fail/data_race/dealloc_read_race1.stderr +++ b/tests/fail/data_race/dealloc_read_race1.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Deallocate on thread `` and Read on thread `` at ALLOC --> $DIR/dealloc_read_race1.rs:LL:CC | LL | / __rust_dealloc( @@ -7,7 +7,7 @@ LL | | ptr.0 as *mut _, LL | | std::mem::size_of::(), LL | | std::mem::align_of::(), LL | | ); - | |_____________^ Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | |_____________^ Data race detected between Deallocate on thread `` and Read on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/dealloc_read_race2.rs b/tests/fail/data_race/dealloc_read_race2.rs index 984268dca149..4bb6444f6a62 100644 --- a/tests/fail/data_race/dealloc_read_race2.rs +++ b/tests/fail/data_race/dealloc_read_race2.rs @@ -27,7 +27,7 @@ pub fn main() { }); let j2 = spawn(move || { - // Also an error of the form: Data race detected between Read on Thread(id = 2) and Deallocate on Thread(id = 1) + // Also an error of the form: Data race detected between Read on thread `` and Deallocate on thread `` // but the invalid allocation is detected first. *ptr.0 //~ ERROR dereferenced after this allocation got freed }); diff --git a/tests/fail/data_race/dealloc_read_race_stack.rs b/tests/fail/data_race/dealloc_read_race_stack.rs index cdb6c182307f..e079581a0d89 100644 --- a/tests/fail/data_race/dealloc_read_race_stack.rs +++ b/tests/fail/data_race/dealloc_read_race_stack.rs @@ -36,7 +36,7 @@ pub fn main() { sleep(Duration::from_millis(200)); // Now `stack_var` gets deallocated. - } //~ ERROR Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2) + } //~ ERROR Data race detected between Deallocate on thread `` and Read on thread `` }); let j2 = spawn(move || { diff --git a/tests/fail/data_race/dealloc_read_race_stack.stderr b/tests/fail/data_race/dealloc_read_race_stack.stderr index 1275d1290b0a..b1e7d3649ecb 100644 --- a/tests/fail/data_race/dealloc_read_race_stack.stderr +++ b/tests/fail/data_race/dealloc_read_race_stack.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Deallocate on thread `` and Read on thread `` at ALLOC --> $DIR/dealloc_read_race_stack.rs:LL:CC | LL | } - | ^ Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^ Data race detected between Deallocate on thread `` and Read on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/dealloc_write_race1.rs b/tests/fail/data_race/dealloc_write_race1.rs index 44078a044a7f..9cd0ebc64252 100644 --- a/tests/fail/data_race/dealloc_write_race1.rs +++ b/tests/fail/data_race/dealloc_write_race1.rs @@ -23,7 +23,7 @@ pub fn main() { let j2 = spawn(move || { __rust_dealloc( - //~^ ERROR Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) + //~^ ERROR Data race detected between Deallocate on thread `` and Write on thread `` ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::(), diff --git a/tests/fail/data_race/dealloc_write_race1.stderr b/tests/fail/data_race/dealloc_write_race1.stderr index dc1a6ed267c6..a9ac03eb31db 100644 --- a/tests/fail/data_race/dealloc_write_race1.stderr +++ b/tests/fail/data_race/dealloc_write_race1.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Deallocate on thread `` and Write on thread `` at ALLOC --> $DIR/dealloc_write_race1.rs:LL:CC | LL | / __rust_dealloc( @@ -7,7 +7,7 @@ LL | | ptr.0 as *mut _, LL | | std::mem::size_of::(), LL | | std::mem::align_of::(), LL | | ); - | |_____________^ Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | |_____________^ Data race detected between Deallocate on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/dealloc_write_race2.rs b/tests/fail/data_race/dealloc_write_race2.rs index 2f4b9a194c05..9b1b8f061475 100644 --- a/tests/fail/data_race/dealloc_write_race2.rs +++ b/tests/fail/data_race/dealloc_write_race2.rs @@ -26,7 +26,7 @@ pub fn main() { }); let j2 = spawn(move || { - // Also an error of the form: Data race detected between Write on Thread(id = 2) and Deallocate on Thread(id = 1) + // Also an error of the form: Data race detected between Write on thread `` and Deallocate on thread `` // but the invalid allocation is detected first. *ptr.0 = 2; //~ ERROR dereferenced after this allocation got freed }); diff --git a/tests/fail/data_race/dealloc_write_race_stack.rs b/tests/fail/data_race/dealloc_write_race_stack.rs index a209a2cd7dbf..2f1257089273 100644 --- a/tests/fail/data_race/dealloc_write_race_stack.rs +++ b/tests/fail/data_race/dealloc_write_race_stack.rs @@ -36,7 +36,7 @@ pub fn main() { sleep(Duration::from_millis(200)); // Now `stack_var` gets deallocated. - } //~ ERROR Data race detected between Deallocate on Thread(id = 1) and Write on Thread(id = 2) + } //~ ERROR Data race detected between Deallocate on thread `` and Write on thread `` }); let j2 = spawn(move || { diff --git a/tests/fail/data_race/dealloc_write_race_stack.stderr b/tests/fail/data_race/dealloc_write_race_stack.stderr index 28a131aac07b..622ac25189be 100644 --- a/tests/fail/data_race/dealloc_write_race_stack.stderr +++ b/tests/fail/data_race/dealloc_write_race_stack.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Deallocate on thread `` and Write on thread `` at ALLOC --> $DIR/dealloc_write_race_stack.rs:LL:CC | LL | } - | ^ Data race detected between Deallocate on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^ Data race detected between Deallocate on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/enable_after_join_to_main.rs b/tests/fail/data_race/enable_after_join_to_main.rs index 832158a34a6a..6f0735fac897 100644 --- a/tests/fail/data_race/enable_after_join_to_main.rs +++ b/tests/fail/data_race/enable_after_join_to_main.rs @@ -29,7 +29,7 @@ pub fn main() { }); let j2 = spawn(move || { - *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 6) and Write on Thread(id = 5) + *c.0 = 64; //~ ERROR Data race detected between Write on thread `` and Write on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/enable_after_join_to_main.stderr b/tests/fail/data_race/enable_after_join_to_main.stderr index db7577b0966e..4426952e44b5 100644 --- a/tests/fail/data_race/enable_after_join_to_main.stderr +++ b/tests/fail/data_race/enable_after_join_to_main.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Write on Thread(id = 6) and Write on Thread(id = 5) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Write on thread `` and Write on thread `` at ALLOC --> $DIR/enable_after_join_to_main.rs:LL:CC | LL | *c.0 = 64; - | ^^^^^^^^^ Data race detected between Write on Thread(id = 6) and Write on Thread(id = 5) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^ Data race detected between Write on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/fence_after_load.rs b/tests/fail/data_race/fence_after_load.rs index c209ef181253..5a8c2e585f49 100644 --- a/tests/fail/data_race/fence_after_load.rs +++ b/tests/fail/data_race/fence_after_load.rs @@ -21,5 +21,5 @@ fn main() { // The fence is useless, since it did not happen-after the `store` in the other thread. // Hence this is a data race. // Also see https://github.com/rust-lang/miri/issues/2192. - unsafe { V = 2 } //~ERROR Data race detected + unsafe { V = 2 } //~ERROR Data race detected between Write on thread `main` and Write on thread `` } diff --git a/tests/fail/data_race/fence_after_load.stderr b/tests/fail/data_race/fence_after_load.stderr index 17cc6a82a1c2..b9cffeda27be 100644 --- a/tests/fail/data_race/fence_after_load.stderr +++ b/tests/fail/data_race/fence_after_load.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Write on thread `main` and Write on thread `` at ALLOC --> $DIR/fence_after_load.rs:LL:CC | LL | unsafe { V = 2 } - | ^^^^^ Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^ Data race detected between Write on thread `main` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/read_write_race.rs b/tests/fail/data_race/read_write_race.rs index 9197912ef2e9..eeb49bb42ab7 100644 --- a/tests/fail/data_race/read_write_race.rs +++ b/tests/fail/data_race/read_write_race.rs @@ -18,7 +18,7 @@ pub fn main() { }); let j2 = spawn(move || { - *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 2) and Read on Thread(id = 1) + *c.0 = 64; //~ ERROR Data race detected between Write on thread `` and Read on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/read_write_race.stderr b/tests/fail/data_race/read_write_race.stderr index b775e2b6fdf1..a65e7006cf0a 100644 --- a/tests/fail/data_race/read_write_race.stderr +++ b/tests/fail/data_race/read_write_race.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Write on thread `` and Read on thread `` at ALLOC --> $DIR/read_write_race.rs:LL:CC | LL | *c.0 = 64; - | ^^^^^^^^^ Data race detected between Write on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^ Data race detected between Write on thread `` and Read on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/read_write_race_stack.rs b/tests/fail/data_race/read_write_race_stack.rs index 00c36176a9f1..124f12d1ecd2 100644 --- a/tests/fail/data_race/read_write_race_stack.rs +++ b/tests/fail/data_race/read_write_race_stack.rs @@ -43,7 +43,7 @@ pub fn main() { sleep(Duration::from_millis(200)); - stack_var //~ ERROR Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) + stack_var //~ ERROR Data race detected between Read on thread `` and Write on thread `` }); let j2 = spawn(move || { diff --git a/tests/fail/data_race/read_write_race_stack.stderr b/tests/fail/data_race/read_write_race_stack.stderr index 0f5f4956ffda..390b3ab38ede 100644 --- a/tests/fail/data_race/read_write_race_stack.stderr +++ b/tests/fail/data_race/read_write_race_stack.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Read on thread `` and Write on thread `` at ALLOC --> $DIR/read_write_race_stack.rs:LL:CC | LL | stack_var - | ^^^^^^^^^ Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^ Data race detected between Read on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/relax_acquire_race.rs b/tests/fail/data_race/relax_acquire_race.rs index 3b350f5c89f2..faa23a150e3f 100644 --- a/tests/fail/data_race/relax_acquire_race.rs +++ b/tests/fail/data_race/relax_acquire_race.rs @@ -38,7 +38,7 @@ pub fn main() { let j3 = spawn(move || { if SYNC.load(Ordering::Acquire) == 2 { - *c.0 //~ ERROR Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) + *c.0 //~ ERROR Data race detected between Read on thread `` and Write on thread `` } else { 0 } diff --git a/tests/fail/data_race/relax_acquire_race.stderr b/tests/fail/data_race/relax_acquire_race.stderr index fb376b58f2c1..85de60c02655 100644 --- a/tests/fail/data_race/relax_acquire_race.stderr +++ b/tests/fail/data_race/relax_acquire_race.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Read on thread `` and Write on thread `` at ALLOC --> $DIR/relax_acquire_race.rs:LL:CC | LL | *c.0 - | ^^^^ Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^ Data race detected between Read on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/release_seq_race.rs b/tests/fail/data_race/release_seq_race.rs index ec03888c76b1..ab6926102a2a 100644 --- a/tests/fail/data_race/release_seq_race.rs +++ b/tests/fail/data_race/release_seq_race.rs @@ -42,7 +42,7 @@ pub fn main() { let j3 = spawn(move || { sleep(Duration::from_millis(500)); if SYNC.load(Ordering::Acquire) == 3 { - *c.0 //~ ERROR Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) + *c.0 //~ ERROR Data race detected between Read on thread `` and Write on thread `` } else { 0 } diff --git a/tests/fail/data_race/release_seq_race.stderr b/tests/fail/data_race/release_seq_race.stderr index 1de9c0ac1c7f..db333d756f85 100644 --- a/tests/fail/data_race/release_seq_race.stderr +++ b/tests/fail/data_race/release_seq_race.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Read on thread `` and Write on thread `` at ALLOC --> $DIR/release_seq_race.rs:LL:CC | LL | *c.0 - | ^^^^ Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^ Data race detected between Read on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/release_seq_race_same_thread.rs b/tests/fail/data_race/release_seq_race_same_thread.rs index 187623828947..d3d18f0e2540 100644 --- a/tests/fail/data_race/release_seq_race_same_thread.rs +++ b/tests/fail/data_race/release_seq_race_same_thread.rs @@ -38,7 +38,7 @@ pub fn main() { let j2 = spawn(move || { if SYNC.load(Ordering::Acquire) == 2 { - *c.0 //~ ERROR Data race detected between Read on Thread(id = 2) and Write on Thread(id = 1) + *c.0 //~ ERROR Data race detected between Read on thread `` and Write on thread `` } else { 0 } diff --git a/tests/fail/data_race/release_seq_race_same_thread.stderr b/tests/fail/data_race/release_seq_race_same_thread.stderr index 9bbdd9a47573..f4c38d531500 100644 --- a/tests/fail/data_race/release_seq_race_same_thread.stderr +++ b/tests/fail/data_race/release_seq_race_same_thread.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Read on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Read on thread `` and Write on thread `` at ALLOC --> $DIR/release_seq_race_same_thread.rs:LL:CC | LL | *c.0 - | ^^^^ Data race detected between Read on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^ Data race detected between Read on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/rmw_race.rs b/tests/fail/data_race/rmw_race.rs index 51577b3b7b19..800b1043c00b 100644 --- a/tests/fail/data_race/rmw_race.rs +++ b/tests/fail/data_race/rmw_race.rs @@ -39,7 +39,7 @@ pub fn main() { let j3 = spawn(move || { if SYNC.load(Ordering::Acquire) == 3 { - *c.0 //~ ERROR Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) + *c.0 //~ ERROR Data race detected between Read on thread `` and Write on thread `` } else { 0 } diff --git a/tests/fail/data_race/rmw_race.stderr b/tests/fail/data_race/rmw_race.stderr index 10d3291fa733..346fcc31b9c0 100644 --- a/tests/fail/data_race/rmw_race.stderr +++ b/tests/fail/data_race/rmw_race.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Read on thread `` and Write on thread `` at ALLOC --> $DIR/rmw_race.rs:LL:CC | LL | *c.0 - | ^^^^ Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^ Data race detected between Read on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/write_write_race.rs b/tests/fail/data_race/write_write_race.rs index 61909eda8633..989ae31a6d28 100644 --- a/tests/fail/data_race/write_write_race.rs +++ b/tests/fail/data_race/write_write_race.rs @@ -18,7 +18,7 @@ pub fn main() { }); let j2 = spawn(move || { - *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 2) and Write on Thread(id = 1) + *c.0 = 64; //~ ERROR Data race detected between Write on thread `` and Write on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/write_write_race.stderr b/tests/fail/data_race/write_write_race.stderr index 0054f5bf63a0..e6254281aef3 100644 --- a/tests/fail/data_race/write_write_race.stderr +++ b/tests/fail/data_race/write_write_race.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Write on thread `` and Write on thread `` at ALLOC --> $DIR/write_write_race.rs:LL:CC | LL | *c.0 = 64; - | ^^^^^^^^^ Data race detected between Write on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^ Data race detected between Write on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/write_write_race_stack.rs b/tests/fail/data_race/write_write_race_stack.rs index 49de5db43b72..3c1eabbf251b 100644 --- a/tests/fail/data_race/write_write_race_stack.rs +++ b/tests/fail/data_race/write_write_race_stack.rs @@ -40,7 +40,7 @@ pub fn main() { sleep(Duration::from_millis(200)); - stack_var = 1usize; //~ ERROR Data race detected between Write on Thread(id = 1) and Write on Thread(id = 2) + stack_var = 1usize; //~ ERROR Data race detected between Write on thread `` and Write on thread `` // read to silence errors stack_var diff --git a/tests/fail/data_race/write_write_race_stack.stderr b/tests/fail/data_race/write_write_race_stack.stderr index 2012643431f6..1f7318e6f951 100644 --- a/tests/fail/data_race/write_write_race_stack.stderr +++ b/tests/fail/data_race/write_write_race_stack.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Write on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Write on thread `` and Write on thread `` at ALLOC --> $DIR/write_write_race_stack.rs:LL:CC | LL | stack_var = 1usize; - | ^^^^^^^^^^^^^^^^^^ Data race detected between Write on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^^^^^^^^^^ Data race detected between Write on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index b108a01dae37..bf7a59da973c 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -218,7 +218,8 @@ fn test_prctl_thread_name() { libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), 0, ); - assert_eq!(b"\0", &buf); + // Rust runtime might set thread name, so we allow two options here. + assert!(&buf[..10] == b"\0" || &buf[..5] == b"main\0"); let thread_name = CString::new("hello").expect("CString::new failed"); assert_eq!( libc::prctl( From 17acc3f71cf8a8e4f2b3c82d453982dd08e13d07 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Fri, 1 Jul 2022 20:15:34 -0400 Subject: [PATCH 3413/5092] Document implementation a bit, add some fast paths --- src/stacked_borrows/stack.rs | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/stacked_borrows/stack.rs b/src/stacked_borrows/stack.rs index e6dc507802fd..6e0d166086fc 100644 --- a/src/stacked_borrows/stack.rs +++ b/src/stacked_borrows/stack.rs @@ -51,6 +51,13 @@ struct StackCache { #[cfg(feature = "stack-cache")] impl StackCache { + /// When a tag is used, we call this function to add or refresh it in the cache. + /// + /// We use position in the cache to represent how recently a tag was used; the first position + /// is the most recently used tag. So an add shifts every element towards the end, and inserts + /// the new element at the start. We lose the last element. + /// This strategy is effective at keeping the most-accessed tags in the cache, but it costs a + /// linear shift across the entire cache when we add a new tag. fn add(&mut self, idx: usize, tag: SbTag) { self.tags.copy_within(0..CACHE_LEN - 1, 1); self.tags[0] = tag; @@ -172,9 +179,12 @@ impl<'tcx> Stack { // If we found the tag, look up its position in the stack to see if it grants // the required permission if self.borrows[stack_idx].perm.grants(access) { - // If it does, and it's already in the most-recently-used position, move it - // there. - if cache_idx != 0 { + // If it does, and it's not already in the most-recently-used position, move it there. + // Except if the tag is in position 1, this is equivalent to just a swap, so do that. + if cache_idx == 1 { + self.cache.tags.swap(0, 1); + self.cache.idx.swap(0, 1); + } else if cache_idx > 1 { self.cache.add(stack_idx, tag); } Some(stack_idx) @@ -208,9 +218,13 @@ impl<'tcx> Stack { // The above insert changes the meaning of every index in the cache >= new_idx, so now // we need to find every one of those indexes and increment it. - for idx in &mut self.cache.idx { - if *idx >= new_idx { - *idx += 1; + // But if the insert is at the end (equivalent to a push), we can skip this step because + // it didn't change the position of any other tags. + if new_idx != self.borrows.len() - 1 { + for idx in &mut self.cache.idx { + if *idx >= new_idx { + *idx += 1; + } } } From a1473ea8f5b065a81c046d53e465d1d0b9e01fad Mon Sep 17 00:00:00 2001 From: Christian Legnitto Date: Fri, 1 Jul 2022 20:05:15 -0600 Subject: [PATCH 3414/5092] Support (stat/fstat/lstat)64 on macos "In order to accommodate advanced capabilities of newer file systems, the struct stat, struct statfs, and struct dirent data structures were updated in Mac OSX 10.5." "TRANSITIONAL DESCRIPTION (NOW DEPRECATED) The fstat64, lstat64 and stat64 routines are equivalent to their corresponding non-64-suffixed routine, when 64-bit inodes are in effect. They were added before there was support for the symbol variants, and so are now deprecated. Instead of using these, set the _DARWIN_USE_64_BIT_INODE macro before including header files to force 64-bit inode support. The stat64 structure used by these deprecated routines is the same as the stat structure when 64-bit inodes are in effect (see above)." "HISTORY An lstat() function call appeared in 4.2BSD. The stat64(), fstat64(), and lstat64() system calls first appeared in Mac OS X 10.5 (Leopard) and are now deprecated in favor of the corresponding symbol variants. The fstatat() system call appeared in OS X 10.10" --- src/shims/unix/macos/foreign_items.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shims/unix/macos/foreign_items.rs b/src/shims/unix/macos/foreign_items.rs index e545a4691bf0..5cd885db7099 100644 --- a/src/shims/unix/macos/foreign_items.rs +++ b/src/shims/unix/macos/foreign_items.rs @@ -33,19 +33,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.close(result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "stat" | "stat$INODE64" => { + "stat" | "stat64" | "stat$INODE64" => { let [path, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_stat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "lstat" | "lstat$INODE64" => { + "lstat" | "lstat64" | "lstat$INODE64" => { let [path, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_lstat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "fstat" | "fstat$INODE64" => { + "fstat" | "fstat64" | "fstat$INODE64" => { let [fd, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_fstat(fd, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; From 5ec25359ff620c6f7371c55b4fa778c9127f9be8 Mon Sep 17 00:00:00 2001 From: InfRandomness Date: Fri, 1 Jul 2022 21:24:24 +0200 Subject: [PATCH 3415/5092] Add `environ` extern implementation to freebsd Signed-off-by: InfRandomness --- src/machine.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/machine.rs b/src/machine.rs index 86b174182c1f..1b7fc4ffb963 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -442,6 +442,14 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { Self::add_extern_static(this, name, place.ptr); } } + "freebsd" => { + // "environ" + Self::add_extern_static( + this, + "environ", + this.machine.env_vars.environ.unwrap().ptr, + ); + } "windows" => { // "_tls_used" // This is some obscure hack that is part of the Windows TLS story. It's a `u8`. From a26be7ea5f353a3db9bc7684029b57f8e2c41259 Mon Sep 17 00:00:00 2001 From: InfRandomness Date: Fri, 1 Jul 2022 21:28:45 +0200 Subject: [PATCH 3416/5092] Enable env test on freebsd Signed-off-by: InfRandomness --- ci.sh | 2 +- tests/fail/environ-gets-deallocated.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ci.sh b/ci.sh index 5c7ab545f958..b914477d44a8 100755 --- a/ci.sh +++ b/ci.sh @@ -60,7 +60,7 @@ case $HOST_TARGET in MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests - MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec current_dir data_race + MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec current_dir data_race env MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture ;; x86_64-apple-darwin) diff --git a/tests/fail/environ-gets-deallocated.rs b/tests/fail/environ-gets-deallocated.rs index 4df9be2bf24d..f50a66e2c766 100644 --- a/tests/fail/environ-gets-deallocated.rs +++ b/tests/fail/environ-gets-deallocated.rs @@ -1,6 +1,6 @@ // ignore-windows: Windows does not have a global environ list that the program can access directly -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "linux", target_os = "freebsd"))] fn get_environ() -> *const *const u8 { extern "C" { static mut environ: *const *const u8; From c0cbb662d2103149b7ce3f8ff3e75fc4933e9f3d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Jul 2022 08:38:07 -0400 Subject: [PATCH 3417/5092] rustup --- rust-version | 2 +- tests/fail/erroneous_const2.stderr | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index 4198e8cf3c08..682914e88290 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -ca1e68b3229e710c3948a361ee770d846a88e6da +46b8c23f3eb5e4d0e0aa27eb3f20d5b8fc3ed51f diff --git a/tests/fail/erroneous_const2.stderr b/tests/fail/erroneous_const2.stderr index d5c89a8e82bf..75e3d9bcd211 100644 --- a/tests/fail/erroneous_const2.stderr +++ b/tests/fail/erroneous_const2.stderr @@ -2,9 +2,7 @@ error: any use of this value will cause an error --> $DIR/erroneous_const2.rs:LL:CC | LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; - | ------------------^^^^^--------------------------- - | | - | attempt to compute `5_u32 - 6_u32`, which would overflow + | -------------- ^^^^^ attempt to compute `5_u32 - 6_u32`, which would overflow | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! From 98d20490f4dd104f684f52e33adbdbedc92ab720 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Jul 2022 08:58:04 -0400 Subject: [PATCH 3418/5092] move some POSIX file shims from linux to unix module --- src/shims/unix/foreign_items.rs | 19 +++++++++++++++++-- src/shims/unix/linux/foreign_items.rs | 18 ------------------ src/shims/unix/macos/foreign_items.rs | 12 ++++++++++-- 3 files changed, 27 insertions(+), 22 deletions(-) diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 4a452800044f..43b0f7df7f01 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -62,6 +62,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.open(args)?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "close" => { + let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.close(fd)?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } "fcntl" => { // `fcntl` is variadic. The argument count is checked based on the first argument // in `this.fcntl()`, so we do not use `check_shim` here. @@ -112,17 +117,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.rmdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "opendir" => { + let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.opendir(name)?; + this.write_scalar(result, dest)?; + } "closedir" => { let [dirp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.closedir(dirp)?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "lseek" | "lseek64" => { + "lseek64" => { let [fd, offset, whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.lseek64(fd, offset, whence)?; - // "lseek" is only used on macOS which is 64bit-only, so `i64` always works. this.write_scalar(Scalar::from_i64(result), dest)?; } + "ftruncate64" => { + let [fd, length] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.ftruncate64(fd, length)?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } "fsync" => { let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.fsync(fd)?; diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index 48abe9bf08c3..d89a2c78f4b1 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -30,29 +30,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // File related shims (but also see "syscall" below for statx) - // These symbols have different names on Linux and macOS, which is the only reason they are not - // in the `posix` module. - "close" => { - let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let result = this.close(fd)?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } - "opendir" => { - let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let result = this.opendir(name)?; - this.write_scalar(result, dest)?; - } "readdir64" => { let [dirp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.linux_readdir64(dirp)?; this.write_scalar(result, dest)?; } - "ftruncate64" => { - let [fd, length] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let result = this.ftruncate64(fd, length)?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } // Linux-only "posix_fadvise" => { let [fd, offset, len, advice] = diff --git a/src/shims/unix/macos/foreign_items.rs b/src/shims/unix/macos/foreign_items.rs index 5cd885db7099..089a082fa369 100644 --- a/src/shims/unix/macos/foreign_items.rs +++ b/src/shims/unix/macos/foreign_items.rs @@ -28,7 +28,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // File related shims - "close" | "close$NOCANCEL" => { + "close$NOCANCEL" => { let [result] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.close(result)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -50,7 +50,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.macos_fstat(fd, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "opendir" | "opendir$INODE64" => { + "opendir$INODE64" => { let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; @@ -61,9 +61,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.macos_readdir_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "lseek" => { + let [fd, offset, whence] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + // macOS is 64bit-only, so this is lseek64 + let result = this.lseek64(fd, offset, whence)?; + this.write_scalar(Scalar::from_i64(result), dest)?; + } "ftruncate" => { let [fd, length] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + // macOS is 64bit-only, so this is ftruncate64 let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } From ae51998191313b7191831e831d93a6d3fe0e4238 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Jul 2022 09:06:17 -0400 Subject: [PATCH 3419/5092] male libc.rs at least build on FreeBSD --- tests/pass/libc.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index bf7a59da973c..d08430a43260 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -42,7 +42,7 @@ fn test_posix_fadvise() { assert_eq!(result, 0); } -#[cfg(any(target_os = "linux", target_os = "freebsd"))] +#[cfg(any(target_os = "linux"))] fn test_sync_file_range() { use std::fs::{remove_file, File}; use std::io::Write; @@ -208,7 +208,7 @@ fn test_rwlock_libc_static_initializer() { /// Test whether the `prctl` shim correctly sets the thread name. /// /// Note: `prctl` exists only on Linux. -#[cfg(any(target_os = "linux", target_os = "freebsd"))] +#[cfg(any(target_os = "linux"))] fn test_prctl_thread_name() { use libc::c_long; use std::ffi::CString; @@ -259,9 +259,9 @@ fn test_prctl_thread_name() { /// Tests whether each thread has its own `__errno_location`. fn test_thread_local_errno() { - #[cfg(not(target_os = "macos"))] + #[cfg(target_os = "linux")] use libc::__errno_location; - #[cfg(target_os = "macos")] + #[cfg(any(target_os = "macos", target_os = "freebsd"))] use libc::__error as __errno_location; unsafe { @@ -278,7 +278,7 @@ fn test_thread_local_errno() { } /// Tests whether clock support exists at all -#[cfg(any(target_os = "linux", target_os = "freebsd"))] +#[cfg(any(target_os = "linux"))] fn test_clocks() { let mut tp = std::mem::MaybeUninit::::uninit(); let is_error = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, tp.as_mut_ptr()) }; @@ -317,7 +317,7 @@ fn main() { test_posix_gettimeofday(); - #[cfg(any(target_os = "linux", target_os = "freebsd"))] + #[cfg(any(target_os = "linux"))] test_sync_file_range(); test_mutex_libc_init_recursive(); @@ -325,14 +325,14 @@ fn main() { test_mutex_libc_init_errorcheck(); test_rwlock_libc_static_initializer(); - #[cfg(any(target_os = "linux", target_os = "freebsd"))] + #[cfg(any(target_os = "linux"))] test_mutex_libc_static_initializer_recursive(); - #[cfg(any(target_os = "linux", target_os = "freebsd"))] + #[cfg(any(target_os = "linux"))] test_prctl_thread_name(); test_thread_local_errno(); - #[cfg(any(target_os = "linux", target_os = "freebsd"))] + #[cfg(any(target_os = "linux"))] test_clocks(); } From 5ba2c1e6be8d79837fb439bafe74b9a20500cf22 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Jul 2022 09:06:35 -0400 Subject: [PATCH 3420/5092] posix_fadvise is not Linux-specific --- src/shims/unix/foreign_items.rs | 10 ++++++++++ src/shims/unix/linux/foreign_items.rs | 10 ---------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 43b0f7df7f01..44147433c037 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -153,6 +153,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.readlink(pathname, buf, bufsize)?; this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } + "posix_fadvise" => { + let [fd, offset, len, advice] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + this.read_scalar(fd)?.to_i32()?; + this.read_scalar(offset)?.to_machine_isize(this)?; + this.read_scalar(len)?.to_machine_isize(this)?; + this.read_scalar(advice)?.to_i32()?; + // fadvise is only informational, we can ignore it. + this.write_null(dest)?; + } // Time related shims "gettimeofday" => { diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index d89a2c78f4b1..bbdb1b8a31c4 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -36,16 +36,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(result, dest)?; } // Linux-only - "posix_fadvise" => { - let [fd, offset, len, advice] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - this.read_scalar(fd)?.to_i32()?; - this.read_scalar(offset)?.to_machine_isize(this)?; - this.read_scalar(len)?.to_machine_isize(this)?; - this.read_scalar(advice)?.to_i32()?; - // fadvise is only informational, we can ignore it. - this.write_null(dest)?; - } "sync_file_range" => { let [fd, offset, nbytes, flags] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; From 98254f67af20a67747835f03c314be9c9a42d769 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Jul 2022 10:11:39 -0400 Subject: [PATCH 3421/5092] pointer tag tracking: on creation, log the offsets it is created for --- src/diagnostics.rs | 12 ++++--- src/stacked_borrows.rs | 32 ++++++++++++++----- .../alloc/deallocate-bad-alignment.stderr | 2 +- tests/fail/alloc/deallocate-bad-size.stderr | 2 +- tests/fail/alloc/deallocate-twice.stderr | 2 +- tests/fail/alloc/global_system_mixup.stderr | 2 +- tests/fail/alloc/no_global_allocator.stderr | 2 +- tests/fail/alloc/reallocate-bad-size.stderr | 2 +- .../fail/alloc/reallocate-change-alloc.stderr | 2 +- tests/fail/alloc/reallocate-dangling.stderr | 2 +- tests/fail/alloc/stack_free.stderr | 2 +- .../fail/backtrace/bad-backtrace-decl.stderr | 2 +- .../fail/backtrace/bad-backtrace-flags.stderr | 2 +- tests/fail/backtrace/bad-backtrace-ptr.stderr | 2 +- .../bad-backtrace-resolve-flags.stderr | 2 +- .../bad-backtrace-resolve-names-flags.stderr | 2 +- .../backtrace/bad-backtrace-size-flags.stderr | 2 +- tests/fail/box-cell-alias.stderr | 1 + .../branchless-select-i128-pointer.stderr | 2 +- .../libc_pthread_join_detached.stderr | 2 +- .../libc_pthread_join_joined.stderr | 2 +- .../concurrency/libc_pthread_join_main.stderr | 2 +- .../libc_pthread_join_multiple.stderr | 2 +- .../concurrency/libc_pthread_join_self.stderr | 2 +- tests/fail/concurrency/thread-spawn.stderr | 2 +- .../thread_local_static_dealloc.stderr | 2 +- tests/fail/concurrency/too_few_args.stderr | 2 +- tests/fail/concurrency/too_many_args.stderr | 2 +- .../concurrency/unwind_top_of_stack.stderr | 2 +- .../dangling_pointer_addr_of.stderr | 2 +- .../dangling_pointer_deref.stderr | 2 +- .../dangling_zst_deref.stderr | 2 +- .../deref-invalid-ptr.stderr | 2 +- .../deref-partially-dangling.stderr | 2 +- tests/fail/dangling_pointers/dyn_size.stderr | 2 +- .../maybe_null_pointer_deref_zst.stderr | 2 +- .../maybe_null_pointer_write_zst.stderr | 2 +- .../null_pointer_deref.stderr | 2 +- .../null_pointer_deref_zst.stderr | 2 +- .../null_pointer_write.stderr | 2 +- .../null_pointer_write_zst.stderr | 2 +- .../out_of_bounds_read1.stderr | 2 +- .../out_of_bounds_read2.stderr | 2 +- .../dangling_pointers/stack_temporary.stderr | 2 +- .../storage_dead_dangling.stderr | 2 +- .../wild_pointer_deref.stderr | 2 +- tests/fail/data_race/alloc_read_race.stderr | 2 +- tests/fail/data_race/alloc_write_race.stderr | 2 +- .../atomic_read_na_write_race1.stderr | 2 +- .../atomic_read_na_write_race2.stderr | 2 +- .../atomic_write_na_read_race1.stderr | 2 +- .../atomic_write_na_read_race2.stderr | 2 +- .../atomic_write_na_write_race1.stderr | 2 +- .../atomic_write_na_write_race2.stderr | 2 +- .../dangling_thread_async_race.stderr | 2 +- .../data_race/dangling_thread_race.stderr | 2 +- .../fail/data_race/dealloc_read_race1.stderr | 2 +- .../fail/data_race/dealloc_read_race2.stderr | 2 +- .../data_race/dealloc_read_race_stack.stderr | 2 +- .../fail/data_race/dealloc_write_race1.stderr | 2 +- .../fail/data_race/dealloc_write_race2.stderr | 2 +- .../data_race/dealloc_write_race_stack.stderr | 2 +- .../enable_after_join_to_main.stderr | 2 +- tests/fail/data_race/fence_after_load.stderr | 2 +- tests/fail/data_race/read_write_race.stderr | 2 +- .../data_race/read_write_race_stack.stderr | 2 +- .../fail/data_race/relax_acquire_race.stderr | 2 +- tests/fail/data_race/release_seq_race.stderr | 2 +- .../release_seq_race_same_thread.stderr | 2 +- tests/fail/data_race/rmw_race.stderr | 2 +- tests/fail/data_race/write_write_race.stderr | 2 +- .../data_race/write_write_race_stack.stderr | 2 +- tests/fail/environ-gets-deallocated.stderr | 2 +- tests/fail/extern_static.stderr | 2 +- tests/fail/extern_static_in_const.stderr | 2 +- tests/fail/fast_math_both.stderr | 2 +- tests/fail/fast_math_first.stderr | 2 +- tests/fail/fast_math_second.stderr | 2 +- tests/fail/fs/close_stdout.stderr | 2 +- tests/fail/fs/isolated_file.stderr | 2 +- tests/fail/fs/isolated_stdin.stderr | 2 +- tests/fail/fs/read_from_stdout.stderr | 2 +- .../fs/unix_open_missing_required_mode.stderr | 2 +- tests/fail/fs/write_to_stdin.stderr | 2 +- .../fail/function_calls/check_arg_abi.stderr | 2 +- .../check_arg_count_abort.stderr | 2 +- .../check_arg_count_too_few_args.stderr | 2 +- .../check_arg_count_too_many_args.stderr | 2 +- .../function_calls/check_callback_abi.stderr | 2 +- .../exported_symbol_abi_mismatch.cache.stderr | 2 +- ...exported_symbol_abi_mismatch.fn_ptr.stderr | 2 +- ...ported_symbol_abi_mismatch.no_cache.stderr | 2 +- .../exported_symbol_bad_unwind1.stderr | 2 +- ...ted_symbol_bad_unwind2.extern_block.stderr | 2 +- .../exported_symbol_clashing.stderr | 1 + .../exported_symbol_shim_clashing.stderr | 1 + .../exported_symbol_wrong_arguments.stderr | 2 +- .../exported_symbol_wrong_type.stderr | 2 +- .../cast_box_int_to_fn_ptr.stderr | 2 +- .../function_pointers/cast_fn_ptr1.stderr | 2 +- .../function_pointers/cast_fn_ptr2.stderr | 2 +- .../function_pointers/cast_fn_ptr3.stderr | 2 +- .../function_pointers/cast_fn_ptr4.stderr | 2 +- .../function_pointers/cast_fn_ptr5.stderr | 2 +- .../cast_int_to_fn_ptr.stderr | 2 +- .../function_pointers/deref_fn_ptr.stderr | 2 +- .../function_pointers/execute_memory.stderr | 2 +- .../function_pointers/fn_ptr_offset.stderr | 2 +- tests/fail/generator-pinned-moved.stderr | 2 +- tests/fail/intrinsics/assume.stderr | 2 +- tests/fail/intrinsics/copy_null.stderr | 2 +- tests/fail/intrinsics/copy_overflow.stderr | 2 +- tests/fail/intrinsics/copy_overlapping.stderr | 2 +- tests/fail/intrinsics/copy_unaligned.stderr | 2 +- tests/fail/intrinsics/ctlz_nonzero.stderr | 2 +- tests/fail/intrinsics/cttz_nonzero.stderr | 2 +- tests/fail/intrinsics/div-by-zero.stderr | 2 +- tests/fail/intrinsics/exact_div1.stderr | 2 +- tests/fail/intrinsics/exact_div2.stderr | 2 +- tests/fail/intrinsics/exact_div3.stderr | 2 +- tests/fail/intrinsics/exact_div4.stderr | 2 +- .../intrinsics/float_to_int_32_inf1.stderr | 2 +- .../intrinsics/float_to_int_32_infneg1.stderr | 2 +- .../intrinsics/float_to_int_32_nan.stderr | 2 +- .../intrinsics/float_to_int_32_nanneg.stderr | 2 +- .../intrinsics/float_to_int_32_neg.stderr | 2 +- .../float_to_int_32_too_big1.stderr | 2 +- .../float_to_int_32_too_big2.stderr | 2 +- .../float_to_int_32_too_small1.stderr | 2 +- .../intrinsics/float_to_int_64_inf1.stderr | 2 +- .../intrinsics/float_to_int_64_infneg1.stderr | 2 +- .../intrinsics/float_to_int_64_infneg2.stderr | 2 +- .../intrinsics/float_to_int_64_nan.stderr | 2 +- .../intrinsics/float_to_int_64_neg.stderr | 2 +- .../float_to_int_64_too_big1.stderr | 2 +- .../float_to_int_64_too_big2.stderr | 2 +- .../float_to_int_64_too_big3.stderr | 2 +- .../float_to_int_64_too_big4.stderr | 2 +- .../float_to_int_64_too_big5.stderr | 2 +- .../float_to_int_64_too_big6.stderr | 2 +- .../float_to_int_64_too_big7.stderr | 2 +- .../float_to_int_64_too_small1.stderr | 2 +- .../float_to_int_64_too_small2.stderr | 2 +- .../float_to_int_64_too_small3.stderr | 2 +- .../intrinsics/out_of_bounds_ptr_1.stderr | 2 +- .../intrinsics/out_of_bounds_ptr_2.stderr | 2 +- .../intrinsics/out_of_bounds_ptr_3.stderr | 2 +- .../overflowing-unchecked-rsh.stderr | 2 +- .../intrinsics/ptr_offset_0_plus_0.stderr | 2 +- .../intrinsics/ptr_offset_from_oob.stderr | 2 +- .../intrinsics/ptr_offset_int_plus_int.stderr | 2 +- .../intrinsics/ptr_offset_int_plus_ptr.stderr | 2 +- .../intrinsics/ptr_offset_overflow.stderr | 2 +- .../intrinsics/ptr_offset_ptr_plus_0.stderr | 2 +- tests/fail/intrinsics/rem-by-zero.stderr | 2 +- tests/fail/intrinsics/simd-div-by-zero.stderr | 2 +- .../fail/intrinsics/simd-div-overflow.stderr | 2 +- .../fail/intrinsics/simd-float-to-int.stderr | 2 +- tests/fail/intrinsics/simd-gather.stderr | 2 +- .../simd-reduce-invalid-bool.stderr | 2 +- tests/fail/intrinsics/simd-rem-by-zero.stderr | 2 +- tests/fail/intrinsics/simd-scatter.stderr | 2 +- .../simd-select-bitmask-invalid.stderr | 2 +- .../simd-select-invalid-bool.stderr | 2 +- tests/fail/intrinsics/simd-shl-too-far.stderr | 2 +- tests/fail/intrinsics/simd-shr-too-far.stderr | 2 +- tests/fail/intrinsics/unchecked_add1.stderr | 2 +- tests/fail/intrinsics/unchecked_add2.stderr | 2 +- tests/fail/intrinsics/unchecked_div1.stderr | 2 +- tests/fail/intrinsics/unchecked_mul1.stderr | 2 +- tests/fail/intrinsics/unchecked_mul2.stderr | 2 +- tests/fail/intrinsics/unchecked_sub1.stderr | 2 +- tests/fail/intrinsics/unchecked_sub2.stderr | 2 +- tests/fail/intrinsics/write_bytes_null.stderr | 2 +- .../intrinsics/write_bytes_overflow.stderr | 2 +- tests/fail/invalid_bool.stderr | 2 +- tests/fail/invalid_char.stderr | 2 +- tests/fail/invalid_enum_tag.stderr | 2 +- tests/fail/invalid_int.stderr | 2 +- tests/fail/issue-miri-1112.stderr | 2 +- tests/fail/modifying_constants.stderr | 2 +- tests/fail/never_say_never.stderr | 2 +- tests/fail/never_transmute_humans.stderr | 2 +- tests/fail/never_transmute_void.stderr | 2 +- tests/fail/panic/bad_miri_start_panic.stderr | 2 +- tests/fail/panic/bad_unwind.stderr | 2 +- tests/fail/panic/unwind_panic_abort.stderr | 2 +- tests/fail/pointer_partial_overwrite.stderr | 2 +- .../provenance/provenance_transmute.stderr | 2 +- .../fail/provenance/ptr_int_unexposed.stderr | 2 +- tests/fail/provenance/ptr_invalid.stderr | 2 +- .../fail/provenance/ptr_invalid_offset.stderr | 2 +- .../provenance/strict_provenance_cast.stderr | 2 +- tests/fail/rc_as_ptr.stderr | 2 +- tests/fail/reading_half_a_pointer.stderr | 2 +- tests/fail/shim_arg_size.32bit.stderr | 2 +- tests/fail/shim_arg_size.64bit.stderr | 2 +- tests/fail/should-pass/cpp20_rwc_syncs.stderr | 2 +- .../alias_through_mutation.stderr | 1 + .../fail/stacked_borrows/aliasing_mut1.stderr | 1 + .../fail/stacked_borrows/aliasing_mut2.stderr | 1 + .../fail/stacked_borrows/aliasing_mut3.stderr | 1 + .../fail/stacked_borrows/aliasing_mut4.stderr | 1 + .../box_exclusive_violation1.stderr | 1 + .../stacked_borrows/buggy_as_mut_slice.stderr | 1 + .../stacked_borrows/buggy_split_at_mut.stderr | 1 + .../deallocate_against_barrier1.stderr | 2 +- .../deallocate_against_barrier2.stderr | 2 +- .../stacked_borrows/exposed_only_ro.stderr | 2 +- .../fail/stacked_borrows/illegal_read1.stderr | 1 + .../fail/stacked_borrows/illegal_read2.stderr | 1 + .../fail/stacked_borrows/illegal_read3.stderr | 1 + .../fail/stacked_borrows/illegal_read4.stderr | 1 + .../fail/stacked_borrows/illegal_read5.stderr | 1 + .../fail/stacked_borrows/illegal_read6.stderr | 1 + .../fail/stacked_borrows/illegal_read7.stderr | 1 + .../fail/stacked_borrows/illegal_read8.stderr | 1 + .../illegal_read_despite_exposed1.stderr | 2 +- .../illegal_read_despite_exposed2.stderr | 2 +- .../stacked_borrows/illegal_write1.stderr | 1 + .../stacked_borrows/illegal_write2.stderr | 1 + .../stacked_borrows/illegal_write3.stderr | 1 + .../stacked_borrows/illegal_write4.stderr | 1 + .../stacked_borrows/illegal_write5.stderr | 1 + .../stacked_borrows/illegal_write6.stderr | 1 + .../illegal_write_despite_exposed1.stderr | 2 +- .../fail/stacked_borrows/interior_mut1.stderr | 1 + .../fail/stacked_borrows/interior_mut2.stderr | 1 + .../invalidate_against_barrier1.stderr | 1 + .../invalidate_against_barrier2.stderr | 1 + .../stacked_borrows/issue-miri-1050-1.stderr | 2 +- .../stacked_borrows/issue-miri-1050-2.stderr | 2 +- .../stacked_borrows/load_invalid_mut.stderr | 1 + .../stacked_borrows/load_invalid_shr.stderr | 1 + .../mut_exclusive_violation1.stderr | 1 + .../mut_exclusive_violation2.stderr | 1 + .../stacked_borrows/newtype_retagging.stderr | 1 + .../stacked_borrows/outdated_local.stderr | 1 + .../stacked_borrows/pass_invalid_mut.stderr | 1 + .../stacked_borrows/pass_invalid_shr.stderr | 1 + .../stacked_borrows/pointer_smuggling.stderr | 1 + .../fail/stacked_borrows/raw_tracking.stderr | 1 + .../stacked_borrows/return_invalid_mut.stderr | 1 + .../return_invalid_mut_option.stderr | 1 + .../return_invalid_mut_tuple.stderr | 1 + .../stacked_borrows/return_invalid_shr.stderr | 1 + .../return_invalid_shr_option.stderr | 1 + .../return_invalid_shr_tuple.stderr | 1 + .../shared_rw_borrows_are_weak1.stderr | 1 + .../shared_rw_borrows_are_weak2.stderr | 1 + .../shr_frozen_violation1.stderr | 1 + .../static_memory_modification.stderr | 2 +- .../transmute-is-no-escape.stderr | 1 + .../stacked_borrows/unescaped_local.stderr | 2 +- .../stacked_borrows/unescaped_static.stderr | 1 + tests/fail/stacked_borrows/vtable.stderr | 2 +- tests/fail/stacked_borrows/zst_slice.stderr | 1 + tests/fail/static_memory_modification1.stderr | 2 +- tests/fail/static_memory_modification2.stderr | 2 +- tests/fail/static_memory_modification3.stderr | 2 +- .../libc_pthread_cond_double_destroy.stderr | 2 +- ...ibc_pthread_condattr_double_destroy.stderr | 2 +- .../libc_pthread_mutex_NULL_deadlock.stderr | 2 +- ...libc_pthread_mutex_default_deadlock.stderr | 2 +- .../libc_pthread_mutex_destroy_locked.stderr | 2 +- .../libc_pthread_mutex_double_destroy.stderr | 2 +- ...thread_mutex_normal_unlock_unlocked.stderr | 2 +- .../libc_pthread_mutex_wrong_owner.stderr | 2 +- ...bc_pthread_mutexattr_double_destroy.stderr | 2 +- ..._pthread_rwlock_destroy_read_locked.stderr | 2 +- ...pthread_rwlock_destroy_write_locked.stderr | 2 +- .../libc_pthread_rwlock_double_destroy.stderr | 2 +- ...ibc_pthread_rwlock_read_wrong_owner.stderr | 2 +- ...libc_pthread_rwlock_unlock_unlocked.stderr | 2 +- ...bc_pthread_rwlock_write_wrong_owner.stderr | 2 +- tests/fail/transmute-pair-uninit.stderr | 2 +- tests/fail/transmute_fat1.stderr | 2 +- .../fail/unaligned_pointers/alignment.stderr | 2 +- .../atomic_unaligned.stderr | 2 +- .../unaligned_pointers/dyn_alignment.stderr | 2 +- .../intptrcast_alignment_check.stderr | 2 +- .../reference_to_packed.stderr | 2 +- .../unaligned_pointers/unaligned_ptr1.stderr | 2 +- .../unaligned_pointers/unaligned_ptr2.stderr | 2 +- .../unaligned_pointers/unaligned_ptr3.stderr | 2 +- .../unaligned_pointers/unaligned_ptr4.stderr | 2 +- .../unaligned_ptr_addr_of.stderr | 2 +- .../unaligned_ptr_zst.stderr | 2 +- tests/fail/uninit_buffer.stderr | 2 +- tests/fail/uninit_byte_read.stderr | 2 +- tests/fail/uninit_raw_ptr.stderr | 2 +- tests/fail/unreachable.stderr | 2 +- .../fail/unsupported_foreign_function.stderr | 2 +- tests/fail/unsupported_signal.stderr | 2 +- tests/fail/validity/cast_fn_ptr1.stderr | 2 +- tests/fail/validity/cast_fn_ptr2.stderr | 2 +- tests/fail/validity/dangling_ref1.stderr | 2 +- tests/fail/validity/dangling_ref2.stderr | 2 +- tests/fail/validity/dangling_ref3.stderr | 2 +- tests/fail/validity/invalid_bool.stderr | 2 +- .../fail/validity/invalid_bool_uninit.stderr | 2 +- tests/fail/validity/invalid_char.stderr | 2 +- .../fail/validity/invalid_char_uninit.stderr | 2 +- tests/fail/validity/invalid_enum_tag.stderr | 2 +- ...invalid_enum_tag_256variants_uninit.stderr | 2 +- tests/fail/validity/invalid_fnptr_null.stderr | 2 +- .../fail/validity/invalid_fnptr_uninit.stderr | 2 +- tests/fail/validity/invalid_wide_raw.stderr | 2 +- tests/fail/validity/nonzero.stderr | 2 +- .../ptr_integer_array_transmute.stderr | 2 +- .../fail/validity/ref_to_uninhabited1.stderr | 2 +- .../fail/validity/ref_to_uninhabited2.stderr | 2 +- tests/fail/validity/too-big-slice.stderr | 2 +- tests/fail/validity/too-big-unsized.stderr | 2 +- .../validity/transmute_through_ptr.stderr | 2 +- tests/fail/validity/uninit_float.stderr | 2 +- tests/fail/validity/uninit_integer.stderr | 2 +- .../validity/uninit_integer_signed.stderr | 2 +- .../fail/weak_memory/racing_mixed_size.stderr | 2 +- .../weak_memory/racing_mixed_size_read.stderr | 2 +- tests/fail/zst1.stderr | 2 +- tests/fail/zst2.stderr | 2 +- tests/fail/zst3.stderr | 2 +- tests/pass/box.stderr | 2 +- tests/pass/extern_types.stderr | 2 +- 325 files changed, 354 insertions(+), 285 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 1ffcdc799edf..28d4733718ef 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -67,7 +67,7 @@ impl MachineStopType for TerminationInfo {} /// Miri specific diagnostics pub enum NonHaltingDiagnostic { - CreatedPointerTag(NonZeroU64), + CreatedPointerTag(NonZeroU64, Option<(AllocId, AllocRange)>), /// This `Item` was popped from the borrow stack, either due to an access with the given tag or /// a deallocation when the second argument is `None`. PoppedPointerTag(Item, Option<(SbTagExtra, AccessKind)>), @@ -318,7 +318,7 @@ fn report_msg<'mir, 'tcx>( diag_level: DiagLevel, title: &str, span_msg: Vec, - mut helps: Vec<(Option, String)>, + helps: Vec<(Option, String)>, stacktrace: &[FrameInfo<'tcx>], ) { let span = stacktrace.first().map_or(DUMMY_SP, |fi| fi.span); @@ -344,8 +344,6 @@ fn report_msg<'mir, 'tcx>( // Show help messages. if !helps.is_empty() { - // Add visual separator before backtrace. - helps.last_mut().unwrap().1.push('\n'); for (span_data, help) in helps { if let Some(span_data) = span_data { err.span_help(span_data.span(), &help); @@ -353,6 +351,8 @@ fn report_msg<'mir, 'tcx>( err.help(&help); } } + // Add visual separator before backtrace. + err.note("backtrace:"); } // Add backtrace for (idx, frame_info) in stacktrace.iter().enumerate() { @@ -448,7 +448,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx for e in diagnostics.drain(..) { use NonHaltingDiagnostic::*; let msg = match e { - CreatedPointerTag(tag) => format!("created tag {:?}", tag), + CreatedPointerTag(tag, None) => format!("created tag {tag:?}"), + CreatedPointerTag(tag, Some((alloc_id, range))) => + format!("created tag {tag:?} at {alloc_id}{}", HexRange(range)), PoppedPointerTag(item, tag) => match tag { None => diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 2cf5eb70c171..cc3d099e1c1c 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -222,11 +222,9 @@ impl GlobalStateInner { } } + /// Generates a new pointer tag. Remember to also check track_pointer_tags and log its creation! fn new_ptr(&mut self) -> SbTag { let id = self.next_ptr_tag; - if self.tracked_pointer_tags.contains(&id) { - register_diagnostic(NonHaltingDiagnostic::CreatedPointerTag(id.0)); - } self.next_ptr_tag = SbTag(NonZeroU64::new(id.0.get() + 1).unwrap()); id } @@ -253,6 +251,9 @@ impl GlobalStateInner { pub fn base_ptr_tag(&mut self, id: AllocId) -> SbTag { self.base_ptr_tags.get(&id).copied().unwrap_or_else(|| { let tag = self.new_ptr(); + if self.tracked_pointer_tags.contains(&tag) { + register_diagnostic(NonHaltingDiagnostic::CreatedPointerTag(tag.0, None)); + } trace!("New allocation {:?} has base tag {:?}", id, tag); self.base_ptr_tags.try_insert(id, tag).unwrap(); tag @@ -802,16 +803,30 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let current_span = &mut this.machine.current_span(); + // It is crucial that this gets called on all code paths, to ensure we track tag creation. let log_creation = |this: &MiriEvalContext<'mir, 'tcx>, current_span: &mut CurrentSpan<'_, 'mir, 'tcx>, - alloc_id, - base_offset, - orig_tag| + loc: Option<(AllocId, Size, SbTagExtra)>| // alloc_id, base_offset, orig_tag -> InterpResult<'tcx> { + let global = this.machine.stacked_borrows.as_ref().unwrap().borrow(); + if global.tracked_pointer_tags.contains(&new_tag) { + register_diagnostic(NonHaltingDiagnostic::CreatedPointerTag( + new_tag.0, + loc.map(|(alloc_id, base_offset, _)| (alloc_id, alloc_range(base_offset, size))), + )); + } + drop(global); // don't hold that reference any longer than we have to + + let Some((alloc_id, base_offset, orig_tag)) = loc else { + return Ok(()) + }; + + // The SB history tracking needs a parent tag, so skip if we come from a wildcard. let SbTagExtra::Concrete(orig_tag) = orig_tag else { // FIXME: should we log this? return Ok(()) }; + let extra = this.get_alloc_extra(alloc_id)?; let mut stacked_borrows = extra .stacked_borrows @@ -846,14 +861,15 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dangling slices are a common case here; it's valid to get their length but with raw // pointer tagging for example all calls to get_unchecked on them are invalid. if let Ok((alloc_id, base_offset, orig_tag)) = this.ptr_try_get_alloc_id(place.ptr) { - log_creation(this, current_span, alloc_id, base_offset, orig_tag)?; + log_creation(this, current_span, Some((alloc_id, base_offset, orig_tag)))?; return Ok(Some(alloc_id)); } // This pointer doesn't come with an AllocId. :shrug: + log_creation(this, current_span, None)?; return Ok(None); } let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?; - log_creation(this, current_span, alloc_id, base_offset, orig_tag)?; + log_creation(this, current_span, Some((alloc_id, base_offset, orig_tag)))?; // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). let (alloc_size, _) = this.get_live_alloc_size_and_align(alloc_id)?; diff --git a/tests/fail/alloc/deallocate-bad-alignment.stderr b/tests/fail/alloc/deallocate-bad-alignment.stderr index 52c0310cabaa..e46533ad70d3 100644 --- a/tests/fail/alloc/deallocate-bad-alignment.stderr +++ b/tests/fail/alloc/deallocate-bad-alignment.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/deallocate-bad-alignment.rs:LL:CC --> $DIR/deallocate-bad-alignment.rs:LL:CC diff --git a/tests/fail/alloc/deallocate-bad-size.stderr b/tests/fail/alloc/deallocate-bad-size.stderr index fe0a5130eb54..d3ca2a4544bf 100644 --- a/tests/fail/alloc/deallocate-bad-size.stderr +++ b/tests/fail/alloc/deallocate-bad-size.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/deallocate-bad-size.rs:LL:CC --> $DIR/deallocate-bad-size.rs:LL:CC diff --git a/tests/fail/alloc/deallocate-twice.stderr b/tests/fail/alloc/deallocate-twice.stderr index cca20be6e661..1fadb277a0e4 100644 --- a/tests/fail/alloc/deallocate-twice.stderr +++ b/tests/fail/alloc/deallocate-twice.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/deallocate-twice.rs:LL:CC --> $DIR/deallocate-twice.rs:LL:CC diff --git a/tests/fail/alloc/global_system_mixup.stderr b/tests/fail/alloc/global_system_mixup.stderr index f197bc791785..60b91155f5e5 100644 --- a/tests/fail/alloc/global_system_mixup.stderr +++ b/tests/fail/alloc/global_system_mixup.stderr @@ -6,7 +6,7 @@ LL | FREE(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::sys::PLATFORM::alloc::::dealloc` at RUSTLIB/std/src/sys/PLATFORM/alloc.rs:LL:CC = note: inside `::deallocate` at RUSTLIB/std/src/alloc.rs:LL:CC note: inside `main` at $DIR/global_system_mixup.rs:LL:CC diff --git a/tests/fail/alloc/no_global_allocator.stderr b/tests/fail/alloc/no_global_allocator.stderr index 2a9840ee83c4..5c11df9539c1 100644 --- a/tests/fail/alloc/no_global_allocator.stderr +++ b/tests/fail/alloc/no_global_allocator.stderr @@ -5,7 +5,7 @@ LL | __rust_alloc(1, 1); | ^^^^^^^^^^^^^^^^^^ can't call foreign function: __rust_alloc | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside `start` at $DIR/no_global_allocator.rs:LL:CC error: aborting due to previous error diff --git a/tests/fail/alloc/reallocate-bad-size.stderr b/tests/fail/alloc/reallocate-bad-size.stderr index 04dce05e78f5..abe47e29ed32 100644 --- a/tests/fail/alloc/reallocate-bad-size.stderr +++ b/tests/fail/alloc/reallocate-bad-size.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::alloc::realloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/reallocate-bad-size.rs:LL:CC --> $DIR/reallocate-bad-size.rs:LL:CC diff --git a/tests/fail/alloc/reallocate-change-alloc.stderr b/tests/fail/alloc/reallocate-change-alloc.stderr index d400931379b0..c22e44b754c9 100644 --- a/tests/fail/alloc/reallocate-change-alloc.stderr +++ b/tests/fail/alloc/reallocate-change-alloc.stderr @@ -6,7 +6,7 @@ LL | let _z = *x; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/reallocate-change-alloc.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/alloc/reallocate-dangling.stderr b/tests/fail/alloc/reallocate-dangling.stderr index 84e7b934202a..5eeaab8700c8 100644 --- a/tests/fail/alloc/reallocate-dangling.stderr +++ b/tests/fail/alloc/reallocate-dangling.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::alloc::realloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/reallocate-dangling.rs:LL:CC --> $DIR/reallocate-dangling.rs:LL:CC diff --git a/tests/fail/alloc/stack_free.stderr b/tests/fail/alloc/stack_free.stderr index 073510a6080d..6ce522df58d6 100644 --- a/tests/fail/alloc/stack_free.stderr +++ b/tests/fail/alloc/stack_free.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `alloc::alloc::box_free::` at RUSTLIB/alloc/src/alloc.rs:LL:CC diff --git a/tests/fail/backtrace/bad-backtrace-decl.stderr b/tests/fail/backtrace/bad-backtrace-decl.stderr index 007ef96f72a9..3cb4a8e8a458 100644 --- a/tests/fail/backtrace/bad-backtrace-decl.stderr +++ b/tests/fail/backtrace/bad-backtrace-decl.stderr @@ -6,7 +6,7 @@ LL | ... miri_resolve_frame(*frame, 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/bad-backtrace-decl.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/backtrace/bad-backtrace-flags.stderr b/tests/fail/backtrace/bad-backtrace-flags.stderr index 6d62ffc00e51..f186fb1e5717 100644 --- a/tests/fail/backtrace/bad-backtrace-flags.stderr +++ b/tests/fail/backtrace/bad-backtrace-flags.stderr @@ -5,7 +5,7 @@ LL | miri_get_backtrace(2, std::ptr::null_mut()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_get_backtrace` flags 2 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside `main` at $DIR/bad-backtrace-flags.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/backtrace/bad-backtrace-ptr.stderr b/tests/fail/backtrace/bad-backtrace-ptr.stderr index 6911db9de02f..969523d8b3fe 100644 --- a/tests/fail/backtrace/bad-backtrace-ptr.stderr +++ b/tests/fail/backtrace/bad-backtrace-ptr.stderr @@ -6,7 +6,7 @@ LL | miri_resolve_frame(std::ptr::null_mut(), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/bad-backtrace-ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/backtrace/bad-backtrace-resolve-flags.stderr b/tests/fail/backtrace/bad-backtrace-resolve-flags.stderr index 49495651dfec..cf80488de22d 100644 --- a/tests/fail/backtrace/bad-backtrace-resolve-flags.stderr +++ b/tests/fail/backtrace/bad-backtrace-resolve-flags.stderr @@ -5,7 +5,7 @@ LL | miri_resolve_frame(buf[0], 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_resolve_frame` flags 2 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside `main` at $DIR/bad-backtrace-resolve-flags.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr b/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr index aa470cb9de05..c7e0d41009ad 100644 --- a/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr +++ b/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr @@ -5,7 +5,7 @@ LL | ... miri_resolve_frame_names(buf[0], 2, std::ptr::null_mut(), std::ptr::n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_resolve_frame_names` flags 2 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside `main` at $DIR/bad-backtrace-resolve-names-flags.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/backtrace/bad-backtrace-size-flags.stderr b/tests/fail/backtrace/bad-backtrace-size-flags.stderr index 09f22b74b9c3..0cfe5d7173ce 100644 --- a/tests/fail/backtrace/bad-backtrace-size-flags.stderr +++ b/tests/fail/backtrace/bad-backtrace-size-flags.stderr @@ -5,7 +5,7 @@ LL | miri_backtrace_size(2); | ^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_backtrace_size` flags 2 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside `main` at $DIR/bad-backtrace-size-flags.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/box-cell-alias.stderr b/tests/fail/box-cell-alias.stderr index 446aafe64012..c7fd1c6415e0 100644 --- a/tests/fail/box-cell-alias.stderr +++ b/tests/fail/box-cell-alias.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x1] | LL | let res = helper(val, ptr); | ^^^ + = note: backtrace: = note: inside `helper` at $DIR/box-cell-alias.rs:LL:CC note: inside `main` at $DIR/box-cell-alias.rs:LL:CC --> $DIR/box-cell-alias.rs:LL:CC diff --git a/tests/fail/branchless-select-i128-pointer.stderr b/tests/fail/branchless-select-i128-pointer.stderr index 5cb05f33ddea..15befcd12655 100644 --- a/tests/fail/branchless-select-i128-pointer.stderr +++ b/tests/fail/branchless-select-i128-pointer.stderr @@ -10,7 +10,7 @@ LL | | ) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/branchless-select-i128-pointer.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/libc_pthread_join_detached.stderr b/tests/fail/concurrency/libc_pthread_join_detached.stderr index 44d0f727a395..be9781ff46ea 100644 --- a/tests/fail/concurrency/libc_pthread_join_detached.stderr +++ b/tests/fail/concurrency/libc_pthread_join_detached.stderr @@ -6,7 +6,7 @@ LL | ... assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/libc_pthread_join_detached.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/libc_pthread_join_joined.stderr b/tests/fail/concurrency/libc_pthread_join_joined.stderr index b67974c58eae..5ac35ffe512e 100644 --- a/tests/fail/concurrency/libc_pthread_join_joined.stderr +++ b/tests/fail/concurrency/libc_pthread_join_joined.stderr @@ -6,7 +6,7 @@ LL | ... assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/libc_pthread_join_joined.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/libc_pthread_join_main.stderr b/tests/fail/concurrency/libc_pthread_join_main.stderr index 3e69df508359..fe136549ce51 100644 --- a/tests/fail/concurrency/libc_pthread_join_main.stderr +++ b/tests/fail/concurrency/libc_pthread_join_main.stderr @@ -6,7 +6,7 @@ LL | ... assert_eq!(libc::pthread_join(thread_id, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/libc_pthread_join_main.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/libc_pthread_join_multiple.stderr b/tests/fail/concurrency/libc_pthread_join_multiple.stderr index 997bca9fe422..9b91e5a3d0ed 100644 --- a/tests/fail/concurrency/libc_pthread_join_multiple.stderr +++ b/tests/fail/concurrency/libc_pthread_join_multiple.stderr @@ -6,7 +6,7 @@ LL | ... assert_eq!(libc::pthread_join(native_copy, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/libc_pthread_join_multiple.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/libc_pthread_join_self.stderr b/tests/fail/concurrency/libc_pthread_join_self.stderr index 8d2acb817f93..38e758e46c12 100644 --- a/tests/fail/concurrency/libc_pthread_join_self.stderr +++ b/tests/fail/concurrency/libc_pthread_join_self.stderr @@ -6,7 +6,7 @@ LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/libc_pthread_join_self.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/thread-spawn.stderr b/tests/fail/concurrency/thread-spawn.stderr index eb6c6c9b0bb8..2e4b3a045e69 100644 --- a/tests/fail/concurrency/thread-spawn.stderr +++ b/tests/fail/concurrency/thread-spawn.stderr @@ -12,7 +12,7 @@ LL | | ); | |_________^ can't create threads on Windows | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside `std::sys::PLATFORM::thread::Thread::new` at RUSTLIB/std/src/sys/PLATFORM/thread.rs:LL:CC = note: inside `std::thread::Builder::spawn_unchecked_::<[closure@$DIR/thread-spawn.rs:LL:CC], ()>` at RUSTLIB/std/src/thread/mod.rs:LL:CC = note: inside `std::thread::Builder::spawn_unchecked::<[closure@$DIR/thread-spawn.rs:LL:CC], ()>` at RUSTLIB/std/src/thread/mod.rs:LL:CC diff --git a/tests/fail/concurrency/thread_local_static_dealloc.stderr b/tests/fail/concurrency/thread_local_static_dealloc.stderr index d54c569de36e..58e7cf07348f 100644 --- a/tests/fail/concurrency/thread_local_static_dealloc.stderr +++ b/tests/fail/concurrency/thread_local_static_dealloc.stderr @@ -6,7 +6,7 @@ LL | let _val = *dangling_ptr.0; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/thread_local_static_dealloc.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/too_few_args.stderr b/tests/fail/concurrency/too_few_args.stderr index 9d96b718bc30..093a30768501 100644 --- a/tests/fail/concurrency/too_few_args.stderr +++ b/tests/fail/concurrency/too_few_args.stderr @@ -6,7 +6,7 @@ LL | panic!() | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `thread_start` at RUSTLIB/std/src/panic.rs:LL:CC = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/fail/concurrency/too_many_args.stderr b/tests/fail/concurrency/too_many_args.stderr index 7132b8c453af..87e22ec1dcf6 100644 --- a/tests/fail/concurrency/too_many_args.stderr +++ b/tests/fail/concurrency/too_many_args.stderr @@ -6,7 +6,7 @@ LL | panic!() | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `thread_start` at RUSTLIB/std/src/panic.rs:LL:CC = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/fail/concurrency/unwind_top_of_stack.stderr b/tests/fail/concurrency/unwind_top_of_stack.stderr index f72f01a9d6e9..efd19ef4c51a 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.stderr +++ b/tests/fail/concurrency/unwind_top_of_stack.stderr @@ -11,7 +11,7 @@ LL | | } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `thread_start` at $DIR/unwind_top_of_stack.rs:LL:CC error: aborting due to previous error diff --git a/tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr b/tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr index 1e793f549acd..a6a2ca1507b5 100644 --- a/tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr +++ b/tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr @@ -6,7 +6,7 @@ LL | let x = unsafe { ptr::addr_of!(*p) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at RUSTLIB/core/src/ptr/mod.rs:LL:CC = note: this error originates in the macro `ptr::addr_of` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/fail/dangling_pointers/dangling_pointer_deref.stderr b/tests/fail/dangling_pointers/dangling_pointer_deref.stderr index 69e7af74857a..cca3d0278aec 100644 --- a/tests/fail/dangling_pointers/dangling_pointer_deref.stderr +++ b/tests/fail/dangling_pointers/dangling_pointer_deref.stderr @@ -6,7 +6,7 @@ LL | let x = unsafe { *p }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/dangling_pointer_deref.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/dangling_zst_deref.stderr b/tests/fail/dangling_pointers/dangling_zst_deref.stderr index 658635433c7a..66626a925cc6 100644 --- a/tests/fail/dangling_pointers/dangling_zst_deref.stderr +++ b/tests/fail/dangling_pointers/dangling_zst_deref.stderr @@ -6,7 +6,7 @@ LL | let _x = unsafe { *p }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/dangling_zst_deref.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/deref-invalid-ptr.stderr b/tests/fail/dangling_pointers/deref-invalid-ptr.stderr index f4361d9fefa9..0dc73a6e3b13 100644 --- a/tests/fail/dangling_pointers/deref-invalid-ptr.stderr +++ b/tests/fail/dangling_pointers/deref-invalid-ptr.stderr @@ -6,7 +6,7 @@ LL | let _y = unsafe { &*x as *const u32 }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/deref-invalid-ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/deref-partially-dangling.stderr b/tests/fail/dangling_pointers/deref-partially-dangling.stderr index dc51eae71a3a..e37b6885922b 100644 --- a/tests/fail/dangling_pointers/deref-partially-dangling.stderr +++ b/tests/fail/dangling_pointers/deref-partially-dangling.stderr @@ -6,7 +6,7 @@ LL | let val = unsafe { (*xptr).1 }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/deref-partially-dangling.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/dyn_size.stderr b/tests/fail/dangling_pointers/dyn_size.stderr index 6048a3b4434d..0abcee595e15 100644 --- a/tests/fail/dangling_pointers/dyn_size.stderr +++ b/tests/fail/dangling_pointers/dyn_size.stderr @@ -6,7 +6,7 @@ LL | let _ptr = unsafe { &*ptr }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/dyn_size.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr b/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr index b4da315a5542..222f2a628196 100644 --- a/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr +++ b/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr @@ -6,7 +6,7 @@ LL | let _x: () = unsafe { *ptr }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/maybe_null_pointer_deref_zst.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr index 41e54735ca92..12228bc1d717 100644 --- a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr +++ b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr @@ -6,7 +6,7 @@ LL | unsafe { *ptr = zst_val }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/maybe_null_pointer_write_zst.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/null_pointer_deref.stderr b/tests/fail/dangling_pointers/null_pointer_deref.stderr index 0930160023f1..10f4c0f38416 100644 --- a/tests/fail/dangling_pointers/null_pointer_deref.stderr +++ b/tests/fail/dangling_pointers/null_pointer_deref.stderr @@ -6,7 +6,7 @@ LL | let x: i32 = unsafe { *std::ptr::null() }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/null_pointer_deref.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr b/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr index 25fea50b15af..600b9b425495 100644 --- a/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr +++ b/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr @@ -6,7 +6,7 @@ LL | let x: () = unsafe { *std::ptr::null() }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/null_pointer_deref_zst.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/null_pointer_write.stderr b/tests/fail/dangling_pointers/null_pointer_write.stderr index 5ac8cc7c20fd..803191a7fcfb 100644 --- a/tests/fail/dangling_pointers/null_pointer_write.stderr +++ b/tests/fail/dangling_pointers/null_pointer_write.stderr @@ -6,7 +6,7 @@ LL | unsafe { *std::ptr::null_mut() = 0i32 }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/null_pointer_write.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/null_pointer_write_zst.stderr b/tests/fail/dangling_pointers/null_pointer_write_zst.stderr index ee8afcfb7d90..2b4d26f8edaf 100644 --- a/tests/fail/dangling_pointers/null_pointer_write_zst.stderr +++ b/tests/fail/dangling_pointers/null_pointer_write_zst.stderr @@ -6,7 +6,7 @@ LL | copy_nonoverlapping(&src as *const T, dst, 1); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::ptr::write::<[u8; 0]>` at RUSTLIB/core/src/ptr/mod.rs:LL:CC = note: inside `std::ptr::mut_ptr::::write` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC note: inside `main` at $DIR/null_pointer_write_zst.rs:LL:CC diff --git a/tests/fail/dangling_pointers/out_of_bounds_read1.stderr b/tests/fail/dangling_pointers/out_of_bounds_read1.stderr index 1982b07066b1..2abc7a457b9a 100644 --- a/tests/fail/dangling_pointers/out_of_bounds_read1.stderr +++ b/tests/fail/dangling_pointers/out_of_bounds_read1.stderr @@ -6,7 +6,7 @@ LL | let x = unsafe { *v.as_ptr().wrapping_offset(5) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/out_of_bounds_read1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/out_of_bounds_read2.stderr b/tests/fail/dangling_pointers/out_of_bounds_read2.stderr index b70ce44c48a0..e0735dd1f926 100644 --- a/tests/fail/dangling_pointers/out_of_bounds_read2.stderr +++ b/tests/fail/dangling_pointers/out_of_bounds_read2.stderr @@ -6,7 +6,7 @@ LL | let x = unsafe { *v.as_ptr().wrapping_offset(5) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/out_of_bounds_read2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/stack_temporary.stderr b/tests/fail/dangling_pointers/stack_temporary.stderr index f4f84765be54..dd24e6dd675c 100644 --- a/tests/fail/dangling_pointers/stack_temporary.stderr +++ b/tests/fail/dangling_pointers/stack_temporary.stderr @@ -6,7 +6,7 @@ LL | let val = *x; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/stack_temporary.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/storage_dead_dangling.stderr b/tests/fail/dangling_pointers/storage_dead_dangling.stderr index d6030643bfaa..23b66325571f 100644 --- a/tests/fail/dangling_pointers/storage_dead_dangling.stderr +++ b/tests/fail/dangling_pointers/storage_dead_dangling.stderr @@ -6,7 +6,7 @@ LL | unsafe { &mut *(LEAK as *mut i32) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `evil` at $DIR/storage_dead_dangling.rs:LL:CC note: inside `main` at $DIR/storage_dead_dangling.rs:LL:CC --> $DIR/storage_dead_dangling.rs:LL:CC diff --git a/tests/fail/dangling_pointers/wild_pointer_deref.stderr b/tests/fail/dangling_pointers/wild_pointer_deref.stderr index b20f310da083..67b28e25e1dd 100644 --- a/tests/fail/dangling_pointers/wild_pointer_deref.stderr +++ b/tests/fail/dangling_pointers/wild_pointer_deref.stderr @@ -6,7 +6,7 @@ LL | let x = unsafe { *p }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/wild_pointer_deref.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/alloc_read_race.stderr b/tests/fail/data_race/alloc_read_race.stderr index 2049e4f4a193..b180c30bdf34 100644 --- a/tests/fail/data_race/alloc_read_race.stderr +++ b/tests/fail/data_race/alloc_read_race.stderr @@ -6,7 +6,7 @@ LL | *pointer.load(Ordering::Relaxed) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/alloc_read_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/alloc_write_race.stderr b/tests/fail/data_race/alloc_write_race.stderr index 82e3d92479d9..bae65b6262f4 100644 --- a/tests/fail/data_race/alloc_write_race.stderr +++ b/tests/fail/data_race/alloc_write_race.stderr @@ -6,7 +6,7 @@ LL | *pointer.load(Ordering::Relaxed) = 2; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/alloc_write_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/atomic_read_na_write_race1.stderr b/tests/fail/data_race/atomic_read_na_write_race1.stderr index 4b5355e866e2..2a0ca9260782 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.stderr +++ b/tests/fail/data_race/atomic_read_na_write_race1.stderr @@ -6,7 +6,7 @@ LL | intrinsics::atomic_load_seqcst(c.0 as *mut usize) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/atomic_read_na_write_race1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/atomic_read_na_write_race2.stderr b/tests/fail/data_race/atomic_read_na_write_race2.stderr index 3eb9f17bae76..48a9c8546908 100644 --- a/tests/fail/data_race/atomic_read_na_write_race2.stderr +++ b/tests/fail/data_race/atomic_read_na_write_race2.stderr @@ -6,7 +6,7 @@ LL | *atomic_ref.get_mut() = 32; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/atomic_read_na_write_race2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/atomic_write_na_read_race1.stderr b/tests/fail/data_race/atomic_write_na_read_race1.stderr index 810fa54d41ce..b3e12168255a 100644 --- a/tests/fail/data_race/atomic_write_na_read_race1.stderr +++ b/tests/fail/data_race/atomic_write_na_read_race1.stderr @@ -6,7 +6,7 @@ LL | *atomic_ref.get_mut() | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/atomic_write_na_read_race1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/atomic_write_na_read_race2.stderr b/tests/fail/data_race/atomic_write_na_read_race2.stderr index 77f69e2bc340..69bf6c5f3742 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.stderr +++ b/tests/fail/data_race/atomic_write_na_read_race2.stderr @@ -6,7 +6,7 @@ LL | atomic_store(c.0 as *mut usize, 32); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/atomic_write_na_read_race2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/atomic_write_na_write_race1.stderr b/tests/fail/data_race/atomic_write_na_write_race1.stderr index 8e70de5e4aff..6abcf4fe3d12 100644 --- a/tests/fail/data_race/atomic_write_na_write_race1.stderr +++ b/tests/fail/data_race/atomic_write_na_write_race1.stderr @@ -6,7 +6,7 @@ LL | atomic_store(c.0 as *mut usize, 64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/atomic_write_na_write_race1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/atomic_write_na_write_race2.stderr b/tests/fail/data_race/atomic_write_na_write_race2.stderr index 310c2ed7df8a..2de1c6858888 100644 --- a/tests/fail/data_race/atomic_write_na_write_race2.stderr +++ b/tests/fail/data_race/atomic_write_na_write_race2.stderr @@ -6,7 +6,7 @@ LL | *atomic_ref.get_mut() = 32; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/atomic_write_na_write_race2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dangling_thread_async_race.stderr b/tests/fail/data_race/dangling_thread_async_race.stderr index efdc913ce27a..66bb8b0be404 100644 --- a/tests/fail/data_race/dangling_thread_async_race.stderr +++ b/tests/fail/data_race/dangling_thread_async_race.stderr @@ -6,7 +6,7 @@ LL | *c.0 = 64; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/dangling_thread_async_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dangling_thread_race.stderr b/tests/fail/data_race/dangling_thread_race.stderr index 899cfdd095e3..1fd9afe17633 100644 --- a/tests/fail/data_race/dangling_thread_race.stderr +++ b/tests/fail/data_race/dangling_thread_race.stderr @@ -6,7 +6,7 @@ LL | *c.0 = 64; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/dangling_thread_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dealloc_read_race1.stderr b/tests/fail/data_race/dealloc_read_race1.stderr index 9e35fb7b6bd8..eec74e8b542a 100644 --- a/tests/fail/data_race/dealloc_read_race1.stderr +++ b/tests/fail/data_race/dealloc_read_race1.stderr @@ -11,7 +11,7 @@ LL | | ); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/dealloc_read_race1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dealloc_read_race2.stderr b/tests/fail/data_race/dealloc_read_race2.stderr index f703d1896d91..41a1224101fc 100644 --- a/tests/fail/data_race/dealloc_read_race2.stderr +++ b/tests/fail/data_race/dealloc_read_race2.stderr @@ -6,7 +6,7 @@ LL | *ptr.0 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/dealloc_read_race2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dealloc_read_race_stack.stderr b/tests/fail/data_race/dealloc_read_race_stack.stderr index b1e7d3649ecb..3c125e03a680 100644 --- a/tests/fail/data_race/dealloc_read_race_stack.stderr +++ b/tests/fail/data_race/dealloc_read_race_stack.stderr @@ -6,7 +6,7 @@ LL | } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/dealloc_read_race_stack.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dealloc_write_race1.stderr b/tests/fail/data_race/dealloc_write_race1.stderr index a9ac03eb31db..f16c0040bb8a 100644 --- a/tests/fail/data_race/dealloc_write_race1.stderr +++ b/tests/fail/data_race/dealloc_write_race1.stderr @@ -11,7 +11,7 @@ LL | | ); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/dealloc_write_race1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dealloc_write_race2.stderr b/tests/fail/data_race/dealloc_write_race2.stderr index 37d1c551d493..6f2e829b4297 100644 --- a/tests/fail/data_race/dealloc_write_race2.stderr +++ b/tests/fail/data_race/dealloc_write_race2.stderr @@ -6,7 +6,7 @@ LL | *ptr.0 = 2; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/dealloc_write_race2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dealloc_write_race_stack.stderr b/tests/fail/data_race/dealloc_write_race_stack.stderr index 622ac25189be..ed069bb6fcd6 100644 --- a/tests/fail/data_race/dealloc_write_race_stack.stderr +++ b/tests/fail/data_race/dealloc_write_race_stack.stderr @@ -6,7 +6,7 @@ LL | } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/dealloc_write_race_stack.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/enable_after_join_to_main.stderr b/tests/fail/data_race/enable_after_join_to_main.stderr index 4426952e44b5..cd707bdcfa9c 100644 --- a/tests/fail/data_race/enable_after_join_to_main.stderr +++ b/tests/fail/data_race/enable_after_join_to_main.stderr @@ -6,7 +6,7 @@ LL | *c.0 = 64; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/enable_after_join_to_main.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/fence_after_load.stderr b/tests/fail/data_race/fence_after_load.stderr index b9cffeda27be..878342c1bd9f 100644 --- a/tests/fail/data_race/fence_after_load.stderr +++ b/tests/fail/data_race/fence_after_load.stderr @@ -6,7 +6,7 @@ LL | unsafe { V = 2 } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/fence_after_load.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/read_write_race.stderr b/tests/fail/data_race/read_write_race.stderr index a65e7006cf0a..b87a7a10974e 100644 --- a/tests/fail/data_race/read_write_race.stderr +++ b/tests/fail/data_race/read_write_race.stderr @@ -6,7 +6,7 @@ LL | *c.0 = 64; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/read_write_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/read_write_race_stack.stderr b/tests/fail/data_race/read_write_race_stack.stderr index 390b3ab38ede..29739d5083c4 100644 --- a/tests/fail/data_race/read_write_race_stack.stderr +++ b/tests/fail/data_race/read_write_race_stack.stderr @@ -6,7 +6,7 @@ LL | stack_var | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/read_write_race_stack.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/relax_acquire_race.stderr b/tests/fail/data_race/relax_acquire_race.stderr index 85de60c02655..21f9e6f96035 100644 --- a/tests/fail/data_race/relax_acquire_race.stderr +++ b/tests/fail/data_race/relax_acquire_race.stderr @@ -6,7 +6,7 @@ LL | *c.0 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/relax_acquire_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/release_seq_race.stderr b/tests/fail/data_race/release_seq_race.stderr index db333d756f85..a7bca03547e5 100644 --- a/tests/fail/data_race/release_seq_race.stderr +++ b/tests/fail/data_race/release_seq_race.stderr @@ -6,7 +6,7 @@ LL | *c.0 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/release_seq_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/release_seq_race_same_thread.stderr b/tests/fail/data_race/release_seq_race_same_thread.stderr index f4c38d531500..515ce17e16cd 100644 --- a/tests/fail/data_race/release_seq_race_same_thread.stderr +++ b/tests/fail/data_race/release_seq_race_same_thread.stderr @@ -6,7 +6,7 @@ LL | *c.0 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/release_seq_race_same_thread.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/rmw_race.stderr b/tests/fail/data_race/rmw_race.stderr index 346fcc31b9c0..905592fc2224 100644 --- a/tests/fail/data_race/rmw_race.stderr +++ b/tests/fail/data_race/rmw_race.stderr @@ -6,7 +6,7 @@ LL | *c.0 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/rmw_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/write_write_race.stderr b/tests/fail/data_race/write_write_race.stderr index e6254281aef3..afb9f4c1edb7 100644 --- a/tests/fail/data_race/write_write_race.stderr +++ b/tests/fail/data_race/write_write_race.stderr @@ -6,7 +6,7 @@ LL | *c.0 = 64; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/write_write_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/write_write_race_stack.stderr b/tests/fail/data_race/write_write_race_stack.stderr index 1f7318e6f951..97977bc297c1 100644 --- a/tests/fail/data_race/write_write_race_stack.stderr +++ b/tests/fail/data_race/write_write_race_stack.stderr @@ -6,7 +6,7 @@ LL | stack_var = 1usize; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/write_write_race_stack.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/environ-gets-deallocated.stderr b/tests/fail/environ-gets-deallocated.stderr index 640d953a811d..bb6525fa8061 100644 --- a/tests/fail/environ-gets-deallocated.stderr +++ b/tests/fail/environ-gets-deallocated.stderr @@ -6,7 +6,7 @@ LL | let _y = unsafe { *pointer }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/environ-gets-deallocated.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/extern_static.stderr b/tests/fail/extern_static.stderr index e673d074bc84..0adb996decdb 100644 --- a/tests/fail/extern_static.stderr +++ b/tests/fail/extern_static.stderr @@ -5,7 +5,7 @@ LL | let _val = unsafe { std::ptr::addr_of!(FOO) }; | ^^^ `extern` static `FOO` from crate `extern_static` is not supported by Miri | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside `main` at $DIR/extern_static.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/extern_static_in_const.stderr b/tests/fail/extern_static_in_const.stderr index 8524bb02c054..ebd5dd7fee15 100644 --- a/tests/fail/extern_static_in_const.stderr +++ b/tests/fail/extern_static_in_const.stderr @@ -5,7 +5,7 @@ LL | let _val = X; | ^ `extern` static `E` from crate `extern_static_in_const` is not supported by Miri | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside `main` at $DIR/extern_static_in_const.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/fast_math_both.stderr b/tests/fail/fast_math_both.stderr index 542044df4d9c..902c9a1f8bb5 100644 --- a/tests/fail/fast_math_both.stderr +++ b/tests/fail/fast_math_both.stderr @@ -6,7 +6,7 @@ LL | ...: f32 = core::intrinsics::fsub_fast(f32::NAN, f32::NAN); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/fast_math_both.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/fast_math_first.stderr b/tests/fail/fast_math_first.stderr index 74ba08dc8787..986b487991f9 100644 --- a/tests/fail/fast_math_first.stderr +++ b/tests/fail/fast_math_first.stderr @@ -6,7 +6,7 @@ LL | ... let _x: f32 = core::intrinsics::frem_fast(f32::NAN, 3.2); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/fast_math_first.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/fast_math_second.stderr b/tests/fail/fast_math_second.stderr index cbb059a07f68..c5abb17f8fac 100644 --- a/tests/fail/fast_math_second.stderr +++ b/tests/fail/fast_math_second.stderr @@ -6,7 +6,7 @@ LL | ...f32 = core::intrinsics::fmul_fast(3.4f32, f32::INFINITY); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/fast_math_second.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/fs/close_stdout.stderr b/tests/fail/fs/close_stdout.stderr index 79fa0458b4bd..08f744a5c458 100644 --- a/tests/fail/fs/close_stdout.stderr +++ b/tests/fail/fs/close_stdout.stderr @@ -5,7 +5,7 @@ LL | libc::close(1); | ^^^^^^^^^^^^^^ stdout cannot be closed | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside `main` at $DIR/close_stdout.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/fs/isolated_file.stderr b/tests/fail/fs/isolated_file.stderr index d06698c940dd..e75d7b7c3d93 100644 --- a/tests/fail/fs/isolated_file.stderr +++ b/tests/fail/fs/isolated_file.stderr @@ -6,7 +6,7 @@ LL | let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode a | = help: pass the flag `-Zmiri-disable-isolation` to disable isolation; = help: or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning - + = note: backtrace: = note: inside closure at RUSTLIB/std/src/sys/PLATFORM/fs.rs:LL:CC = note: inside `std::sys::PLATFORM::cvt_r::` at RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC = note: inside `std::sys::PLATFORM::fs::File::open_c` at RUSTLIB/std/src/sys/PLATFORM/fs.rs:LL:CC diff --git a/tests/fail/fs/isolated_stdin.stderr b/tests/fail/fs/isolated_stdin.stderr index 4fbd11e7cd9b..fe9700f07b39 100644 --- a/tests/fail/fs/isolated_stdin.stderr +++ b/tests/fail/fs/isolated_stdin.stderr @@ -6,7 +6,7 @@ LL | libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512); | = help: pass the flag `-Zmiri-disable-isolation` to disable isolation; = help: or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning - + = note: backtrace: = note: inside `main` at $DIR/isolated_stdin.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/fs/read_from_stdout.stderr b/tests/fail/fs/read_from_stdout.stderr index 45573c471e2a..5c16999cbf79 100644 --- a/tests/fail/fs/read_from_stdout.stderr +++ b/tests/fail/fs/read_from_stdout.stderr @@ -5,7 +5,7 @@ LL | libc::read(1, bytes.as_mut_ptr() as *mut libc::c_void, 512); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot read from stdout | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside `main` at $DIR/read_from_stdout.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/fs/unix_open_missing_required_mode.stderr b/tests/fail/fs/unix_open_missing_required_mode.stderr index 700323433124..a7297efaff96 100644 --- a/tests/fail/fs/unix_open_missing_required_mode.stderr +++ b/tests/fail/fs/unix_open_missing_required_mode.stderr @@ -6,7 +6,7 @@ LL | ...safe { libc::open(name_ptr, libc::O_CREAT) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `test_file_open_missing_needed_mode` at $DIR/unix_open_missing_required_mode.rs:LL:CC note: inside `main` at $DIR/unix_open_missing_required_mode.rs:LL:CC --> $DIR/unix_open_missing_required_mode.rs:LL:CC diff --git a/tests/fail/fs/write_to_stdin.stderr b/tests/fail/fs/write_to_stdin.stderr index 1cbc3eef66ae..518d36b5551b 100644 --- a/tests/fail/fs/write_to_stdin.stderr +++ b/tests/fail/fs/write_to_stdin.stderr @@ -5,7 +5,7 @@ LL | libc::write(0, bytes.as_ptr() as *const libc::c_void, 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot write to stdin | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside `main` at $DIR/write_to_stdin.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/check_arg_abi.stderr b/tests/fail/function_calls/check_arg_abi.stderr index 9ee7d301b19f..952acde9ea53 100644 --- a/tests/fail/function_calls/check_arg_abi.stderr +++ b/tests/fail/function_calls/check_arg_abi.stderr @@ -6,7 +6,7 @@ LL | let _ = malloc(0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/check_arg_abi.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/check_arg_count_abort.stderr b/tests/fail/function_calls/check_arg_count_abort.stderr index c7682578f99b..bf24c5c91794 100644 --- a/tests/fail/function_calls/check_arg_count_abort.stderr +++ b/tests/fail/function_calls/check_arg_count_abort.stderr @@ -6,7 +6,7 @@ LL | abort(1); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/check_arg_count_abort.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/check_arg_count_too_few_args.stderr b/tests/fail/function_calls/check_arg_count_too_few_args.stderr index b7d6bbfd5719..ac0ec606dac8 100644 --- a/tests/fail/function_calls/check_arg_count_too_few_args.stderr +++ b/tests/fail/function_calls/check_arg_count_too_few_args.stderr @@ -6,7 +6,7 @@ LL | let _ = malloc(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/check_arg_count_too_few_args.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/check_arg_count_too_many_args.stderr b/tests/fail/function_calls/check_arg_count_too_many_args.stderr index 33cc5750b890..b465b02b6e42 100644 --- a/tests/fail/function_calls/check_arg_count_too_many_args.stderr +++ b/tests/fail/function_calls/check_arg_count_too_many_args.stderr @@ -6,7 +6,7 @@ LL | let _ = malloc(1, 2); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/check_arg_count_too_many_args.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/check_callback_abi.stderr b/tests/fail/function_calls/check_callback_abi.stderr index 56314e6d2859..5d5c30a203ac 100644 --- a/tests/fail/function_calls/check_callback_abi.stderr +++ b/tests/fail/function_calls/check_callback_abi.stderr @@ -11,7 +11,7 @@ LL | | ); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/check_callback_abi.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr b/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr index dee7f66e0ad9..ba2b4de889b7 100644 --- a/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr +++ b/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr @@ -6,7 +6,7 @@ LL | foo(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/exported_symbol_abi_mismatch.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr b/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr index ebe19796609c..358f86c0403b 100644 --- a/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr +++ b/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr @@ -6,7 +6,7 @@ LL | std::mem::transmute::(foo)(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/exported_symbol_abi_mismatch.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr b/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr index dee7f66e0ad9..ba2b4de889b7 100644 --- a/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr +++ b/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr @@ -6,7 +6,7 @@ LL | foo(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/exported_symbol_abi_mismatch.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr b/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr index 8cd74f1fd86d..0b943432c207 100644 --- a/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr +++ b/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr @@ -8,7 +8,7 @@ LL | unsafe { unwind() } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/exported_symbol_bad_unwind1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr b/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr index fac42bf66ae4..f974eb87037a 100644 --- a/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr +++ b/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr @@ -8,7 +8,7 @@ LL | unsafe { nounwind() } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/exported_symbol_bad_unwind2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_clashing.stderr b/tests/fail/function_calls/exported_symbol_clashing.stderr index 1ddd882c4cb3..998b7c415930 100644 --- a/tests/fail/function_calls/exported_symbol_clashing.stderr +++ b/tests/fail/function_calls/exported_symbol_clashing.stderr @@ -14,6 +14,7 @@ help: then it's defined here again, in crate `exported_symbol_clashing` | LL | fn bar() {} | ^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/exported_symbol_clashing.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_shim_clashing.stderr b/tests/fail/function_calls/exported_symbol_shim_clashing.stderr index fa25b4e3f347..69b99b374733 100644 --- a/tests/fail/function_calls/exported_symbol_shim_clashing.stderr +++ b/tests/fail/function_calls/exported_symbol_shim_clashing.stderr @@ -12,6 +12,7 @@ LL | | LL | | unreachable!() LL | | } | |_^ + = note: backtrace: = note: inside `main` at $DIR/exported_symbol_shim_clashing.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr b/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr index fe5498c85d7f..2e80e833710e 100644 --- a/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr +++ b/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr @@ -6,7 +6,7 @@ LL | unsafe { foo(1) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/exported_symbol_wrong_arguments.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_wrong_type.stderr b/tests/fail/function_calls/exported_symbol_wrong_type.stderr index f40270490871..900e23d1212e 100644 --- a/tests/fail/function_calls/exported_symbol_wrong_type.stderr +++ b/tests/fail/function_calls/exported_symbol_wrong_type.stderr @@ -6,7 +6,7 @@ LL | unsafe { FOO() } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/exported_symbol_wrong_type.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_box_int_to_fn_ptr.stderr b/tests/fail/function_pointers/cast_box_int_to_fn_ptr.stderr index 13f8ef378243..436cced9f02e 100644 --- a/tests/fail/function_pointers/cast_box_int_to_fn_ptr.stderr +++ b/tests/fail/function_pointers/cast_box_int_to_fn_ptr.stderr @@ -6,7 +6,7 @@ LL | (*g)(42) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/cast_box_int_to_fn_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_fn_ptr1.stderr b/tests/fail/function_pointers/cast_fn_ptr1.stderr index 765dbb6578ab..972fd9afc8ea 100644 --- a/tests/fail/function_pointers/cast_fn_ptr1.stderr +++ b/tests/fail/function_pointers/cast_fn_ptr1.stderr @@ -6,7 +6,7 @@ LL | g(42) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/cast_fn_ptr1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_fn_ptr2.stderr b/tests/fail/function_pointers/cast_fn_ptr2.stderr index 123d0e1b0bb6..638c4ca6781e 100644 --- a/tests/fail/function_pointers/cast_fn_ptr2.stderr +++ b/tests/fail/function_pointers/cast_fn_ptr2.stderr @@ -6,7 +6,7 @@ LL | g(42) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/cast_fn_ptr2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_fn_ptr3.stderr b/tests/fail/function_pointers/cast_fn_ptr3.stderr index 51f6ca0713d7..e21d1c6b6f73 100644 --- a/tests/fail/function_pointers/cast_fn_ptr3.stderr +++ b/tests/fail/function_pointers/cast_fn_ptr3.stderr @@ -6,7 +6,7 @@ LL | g() | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/cast_fn_ptr3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_fn_ptr4.stderr b/tests/fail/function_pointers/cast_fn_ptr4.stderr index 515f00ec3929..b1acafcebe7e 100644 --- a/tests/fail/function_pointers/cast_fn_ptr4.stderr +++ b/tests/fail/function_pointers/cast_fn_ptr4.stderr @@ -6,7 +6,7 @@ LL | g(&42 as *const i32) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/cast_fn_ptr4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_fn_ptr5.stderr b/tests/fail/function_pointers/cast_fn_ptr5.stderr index 2978866c9290..c4915f905bf3 100644 --- a/tests/fail/function_pointers/cast_fn_ptr5.stderr +++ b/tests/fail/function_pointers/cast_fn_ptr5.stderr @@ -6,7 +6,7 @@ LL | g() | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/cast_fn_ptr5.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr b/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr index 25501e74913d..3a80120a9b92 100644 --- a/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr +++ b/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr @@ -6,7 +6,7 @@ LL | g(42) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/cast_int_to_fn_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/deref_fn_ptr.stderr b/tests/fail/function_pointers/deref_fn_ptr.stderr index 619b58f699a3..ecd001964a1b 100644 --- a/tests/fail/function_pointers/deref_fn_ptr.stderr +++ b/tests/fail/function_pointers/deref_fn_ptr.stderr @@ -6,7 +6,7 @@ LL | *std::mem::transmute::(f) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/deref_fn_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/execute_memory.stderr b/tests/fail/function_pointers/execute_memory.stderr index daa6277b85e4..b6438934b2b3 100644 --- a/tests/fail/function_pointers/execute_memory.stderr +++ b/tests/fail/function_pointers/execute_memory.stderr @@ -6,7 +6,7 @@ LL | f() | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/execute_memory.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/fn_ptr_offset.stderr b/tests/fail/function_pointers/fn_ptr_offset.stderr index 0f3baab1b512..b5164d02ace1 100644 --- a/tests/fail/function_pointers/fn_ptr_offset.stderr +++ b/tests/fail/function_pointers/fn_ptr_offset.stderr @@ -6,7 +6,7 @@ LL | x(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/fn_ptr_offset.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/generator-pinned-moved.stderr b/tests/fail/generator-pinned-moved.stderr index 0ccf3091cde7..f1fb366d0652 100644 --- a/tests/fail/generator-pinned-moved.stderr +++ b/tests/fail/generator-pinned-moved.stderr @@ -6,7 +6,7 @@ LL | *num += 1; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/generator-pinned-moved.rs:LL:CC note: inside ` as std::iter::Iterator>::next` at $DIR/generator-pinned-moved.rs:LL:CC --> $DIR/generator-pinned-moved.rs:LL:CC diff --git a/tests/fail/intrinsics/assume.stderr b/tests/fail/intrinsics/assume.stderr index e5059a699b10..1664e7ad743f 100644 --- a/tests/fail/intrinsics/assume.stderr +++ b/tests/fail/intrinsics/assume.stderr @@ -6,7 +6,7 @@ LL | std::intrinsics::assume(x > 42); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/assume.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/copy_null.stderr b/tests/fail/intrinsics/copy_null.stderr index bb5a8742e909..110408227e18 100644 --- a/tests/fail/intrinsics/copy_null.stderr +++ b/tests/fail/intrinsics/copy_null.stderr @@ -6,7 +6,7 @@ LL | copy_nonoverlapping(std::ptr::null(), ptr, 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/copy_null.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/copy_overflow.stderr b/tests/fail/intrinsics/copy_overflow.stderr index 897ea5ffec5e..76917ae7ea15 100644 --- a/tests/fail/intrinsics/copy_overflow.stderr +++ b/tests/fail/intrinsics/copy_overflow.stderr @@ -6,7 +6,7 @@ LL | copy(src, dst, count) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::intrinsics::copy::` at RUSTLIB/core/src/intrinsics.rs:LL:CC = note: inside `std::ptr::mut_ptr::::copy_from` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC note: inside `main` at $DIR/copy_overflow.rs:LL:CC diff --git a/tests/fail/intrinsics/copy_overlapping.stderr b/tests/fail/intrinsics/copy_overlapping.stderr index cba08d9b5c82..9298a87712bb 100644 --- a/tests/fail/intrinsics/copy_overlapping.stderr +++ b/tests/fail/intrinsics/copy_overlapping.stderr @@ -6,7 +6,7 @@ LL | copy_nonoverlapping(a, b, 2); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/copy_overlapping.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/copy_unaligned.stderr b/tests/fail/intrinsics/copy_unaligned.stderr index b244eaeb4191..890c7b12e03d 100644 --- a/tests/fail/intrinsics/copy_unaligned.stderr +++ b/tests/fail/intrinsics/copy_unaligned.stderr @@ -6,7 +6,7 @@ LL | copy_nonoverlapping(&data[5], ptr, 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/copy_unaligned.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ctlz_nonzero.stderr b/tests/fail/intrinsics/ctlz_nonzero.stderr index 0c895cf138e9..7d4d3dd8e1b8 100644 --- a/tests/fail/intrinsics/ctlz_nonzero.stderr +++ b/tests/fail/intrinsics/ctlz_nonzero.stderr @@ -6,7 +6,7 @@ LL | ctlz_nonzero(0u8); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/ctlz_nonzero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/cttz_nonzero.stderr b/tests/fail/intrinsics/cttz_nonzero.stderr index 5257668d53e9..284bfc1c4c99 100644 --- a/tests/fail/intrinsics/cttz_nonzero.stderr +++ b/tests/fail/intrinsics/cttz_nonzero.stderr @@ -6,7 +6,7 @@ LL | cttz_nonzero(0u8); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/cttz_nonzero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/div-by-zero.stderr b/tests/fail/intrinsics/div-by-zero.stderr index 388f4aef7fa9..061123ddc1de 100644 --- a/tests/fail/intrinsics/div-by-zero.stderr +++ b/tests/fail/intrinsics/div-by-zero.stderr @@ -6,7 +6,7 @@ LL | let _n = unchecked_div(1i64, 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/div-by-zero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/exact_div1.stderr b/tests/fail/intrinsics/exact_div1.stderr index 59e853d0ecec..6564fad475de 100644 --- a/tests/fail/intrinsics/exact_div1.stderr +++ b/tests/fail/intrinsics/exact_div1.stderr @@ -6,7 +6,7 @@ LL | unsafe { std::intrinsics::exact_div(2, 0) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/exact_div1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/exact_div2.stderr b/tests/fail/intrinsics/exact_div2.stderr index dfbcdd1f34f1..7e8e2ee18121 100644 --- a/tests/fail/intrinsics/exact_div2.stderr +++ b/tests/fail/intrinsics/exact_div2.stderr @@ -6,7 +6,7 @@ LL | unsafe { std::intrinsics::exact_div(2u16, 3) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/exact_div2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/exact_div3.stderr b/tests/fail/intrinsics/exact_div3.stderr index c3b908ce0ad5..8b1f15794b7c 100644 --- a/tests/fail/intrinsics/exact_div3.stderr +++ b/tests/fail/intrinsics/exact_div3.stderr @@ -6,7 +6,7 @@ LL | unsafe { std::intrinsics::exact_div(-19i8, 2) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/exact_div3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/exact_div4.stderr b/tests/fail/intrinsics/exact_div4.stderr index b82950674fbc..4da670bc846c 100644 --- a/tests/fail/intrinsics/exact_div4.stderr +++ b/tests/fail/intrinsics/exact_div4.stderr @@ -6,7 +6,7 @@ LL | unsafe { std::intrinsics::exact_div(i64::MIN, -1) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/exact_div4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_inf1.stderr b/tests/fail/intrinsics/float_to_int_32_inf1.stderr index b12fd13b5f4d..88cd4a7c184b 100644 --- a/tests/fail/intrinsics/float_to_int_32_inf1.stderr +++ b/tests/fail/intrinsics/float_to_int_32_inf1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f32::INFINITY); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_32_inf1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_infneg1.stderr b/tests/fail/intrinsics/float_to_int_32_infneg1.stderr index d9223462bfa5..a83300184048 100644 --- a/tests/fail/intrinsics/float_to_int_32_infneg1.stderr +++ b/tests/fail/intrinsics/float_to_int_32_infneg1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f32::NEG_INFINITY); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_32_infneg1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_nan.stderr b/tests/fail/intrinsics/float_to_int_32_nan.stderr index cb8764174abd..9bf312a9ccbd 100644 --- a/tests/fail/intrinsics/float_to_int_32_nan.stderr +++ b/tests/fail/intrinsics/float_to_int_32_nan.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f32::NAN); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_32_nan.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_nanneg.stderr b/tests/fail/intrinsics/float_to_int_32_nanneg.stderr index 49e19bf96356..be105ccdaa71 100644 --- a/tests/fail/intrinsics/float_to_int_32_nanneg.stderr +++ b/tests/fail/intrinsics/float_to_int_32_nanneg.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(-f32::NAN); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_32_nanneg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_neg.stderr b/tests/fail/intrinsics/float_to_int_32_neg.stderr index 5d847166a071..6f926d442bb4 100644 --- a/tests/fail/intrinsics/float_to_int_32_neg.stderr +++ b/tests/fail/intrinsics/float_to_int_32_neg.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(-1.000000001f32); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_32_neg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_too_big1.stderr b/tests/fail/intrinsics/float_to_int_32_too_big1.stderr index be6ad1f381d4..880eb6f48a9b 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_big1.stderr +++ b/tests/fail/intrinsics/float_to_int_32_too_big1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(2147483648.0f32); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_32_too_big1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_too_big2.stderr b/tests/fail/intrinsics/float_to_int_32_too_big2.stderr index d7fbe5a34b52..9ee3e2feed2f 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_big2.stderr +++ b/tests/fail/intrinsics/float_to_int_32_too_big2.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::((u32::MAX - 127) as f32); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_32_too_big2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_too_small1.stderr b/tests/fail/intrinsics/float_to_int_32_too_small1.stderr index 2c225b85ec90..0f23fc05fd72 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_small1.stderr +++ b/tests/fail/intrinsics/float_to_int_32_too_small1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(-2147483904.0f32); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_32_too_small1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_inf1.stderr b/tests/fail/intrinsics/float_to_int_64_inf1.stderr index 7bb1f08afa87..eb493f141cbd 100644 --- a/tests/fail/intrinsics/float_to_int_64_inf1.stderr +++ b/tests/fail/intrinsics/float_to_int_64_inf1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f64::INFINITY); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_inf1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_infneg1.stderr b/tests/fail/intrinsics/float_to_int_64_infneg1.stderr index eb96f6869a14..5e499e271202 100644 --- a/tests/fail/intrinsics/float_to_int_64_infneg1.stderr +++ b/tests/fail/intrinsics/float_to_int_64_infneg1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f64::NEG_INFINITY); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_infneg1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_infneg2.stderr b/tests/fail/intrinsics/float_to_int_64_infneg2.stderr index a2f847be9071..da22fa481727 100644 --- a/tests/fail/intrinsics/float_to_int_64_infneg2.stderr +++ b/tests/fail/intrinsics/float_to_int_64_infneg2.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f64::NEG_INFINITY); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_infneg2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_nan.stderr b/tests/fail/intrinsics/float_to_int_64_nan.stderr index 8da854975820..eff110ad724c 100644 --- a/tests/fail/intrinsics/float_to_int_64_nan.stderr +++ b/tests/fail/intrinsics/float_to_int_64_nan.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f64::NAN); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_nan.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_neg.stderr b/tests/fail/intrinsics/float_to_int_64_neg.stderr index 35bb0aaa22cb..8d8851a9d7bf 100644 --- a/tests/fail/intrinsics/float_to_int_64_neg.stderr +++ b/tests/fail/intrinsics/float_to_int_64_neg.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(-1.0000000000001f64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_neg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_big1.stderr b/tests/fail/intrinsics/float_to_int_64_too_big1.stderr index e031e00709e0..53c999ccba92 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big1.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(2147483648.0f64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_too_big1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_big2.stderr b/tests/fail/intrinsics/float_to_int_64_too_big2.stderr index 8c4478603fbd..4f5927eed59a 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big2.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big2.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(9223372036854775808.0f64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_too_big2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_big3.stderr b/tests/fail/intrinsics/float_to_int_64_too_big3.stderr index d7f97f37de59..d439b8695efb 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big3.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big3.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(18446744073709551616.0f64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_too_big3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_big4.stderr b/tests/fail/intrinsics/float_to_int_64_too_big4.stderr index cfac443f4c9e..56677cd31554 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big4.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big4.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(u128::MAX as f64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_too_big4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_big5.stderr b/tests/fail/intrinsics/float_to_int_64_too_big5.stderr index a0d501dad303..ab5b2c954aec 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big5.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big5.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(2402823669209384634633746074317 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_too_big5.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_big6.stderr b/tests/fail/intrinsics/float_to_int_64_too_big6.stderr index afb5d4ffe722..e64ab2262715 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big6.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big6.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f64::MAX); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_too_big6.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_big7.stderr b/tests/fail/intrinsics/float_to_int_64_too_big7.stderr index 291acf529b4f..e9809e3ba589 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big7.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big7.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f64::MIN); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_too_big7.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_small1.stderr b/tests/fail/intrinsics/float_to_int_64_too_small1.stderr index ceb625972690..714205ca1beb 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small1.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_small1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(-2147483649.0f64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_too_small1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_small2.stderr b/tests/fail/intrinsics/float_to_int_64_too_small2.stderr index f8255c2daca0..b2302bf905ac 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small2.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_small2.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(-9223372036854777856.0f64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_too_small2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_small3.stderr b/tests/fail/intrinsics/float_to_int_64_too_small3.stderr index 6bfb6f1f18d8..bcff0fb63042 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small3.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_small3.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(-240282366920938463463374607431 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_too_small3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr b/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr index 8a7da324ef89..2c4d6bbc50cf 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr +++ b/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr @@ -6,7 +6,7 @@ LL | unsafe { intrinsics::offset(self, count) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC note: inside `main` at $DIR/out_of_bounds_ptr_1.rs:LL:CC --> $DIR/out_of_bounds_ptr_1.rs:LL:CC diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr b/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr index 78a17a2ab7b5..70ce2dc02a82 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr +++ b/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr @@ -6,7 +6,7 @@ LL | unsafe { intrinsics::offset(self, count) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC note: inside `main` at $DIR/out_of_bounds_ptr_2.rs:LL:CC --> $DIR/out_of_bounds_ptr_2.rs:LL:CC diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr b/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr index 9866529eeeb5..075f40b54a2c 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr +++ b/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr @@ -6,7 +6,7 @@ LL | unsafe { intrinsics::offset(self, count) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC note: inside `main` at $DIR/out_of_bounds_ptr_3.rs:LL:CC --> $DIR/out_of_bounds_ptr_3.rs:LL:CC diff --git a/tests/fail/intrinsics/overflowing-unchecked-rsh.stderr b/tests/fail/intrinsics/overflowing-unchecked-rsh.stderr index 0d22b166b267..705ae01188b8 100644 --- a/tests/fail/intrinsics/overflowing-unchecked-rsh.stderr +++ b/tests/fail/intrinsics/overflowing-unchecked-rsh.stderr @@ -6,7 +6,7 @@ LL | let _n = unchecked_shr(1i64, 64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/overflowing-unchecked-rsh.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr b/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr index 741314ea8a68..ae9dd15b1330 100644 --- a/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr +++ b/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr @@ -6,7 +6,7 @@ LL | unsafe { intrinsics::offset(self, count) as *mut T } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::ptr::mut_ptr::::offset` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC note: inside `main` at $DIR/ptr_offset_0_plus_0.rs:LL:CC --> $DIR/ptr_offset_0_plus_0.rs:LL:CC diff --git a/tests/fail/intrinsics/ptr_offset_from_oob.stderr b/tests/fail/intrinsics/ptr_offset_from_oob.stderr index 0e723a5ee395..699ca1a87ae8 100644 --- a/tests/fail/intrinsics/ptr_offset_from_oob.stderr +++ b/tests/fail/intrinsics/ptr_offset_from_oob.stderr @@ -6,7 +6,7 @@ LL | unsafe { ptr_offset_from(end_ptr, end_ptr) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/ptr_offset_from_oob.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr b/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr index e6b8f102f394..49e02651e963 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr +++ b/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr @@ -6,7 +6,7 @@ LL | unsafe { intrinsics::offset(self, count) as *mut T } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::ptr::mut_ptr::::offset` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC note: inside `main` at $DIR/ptr_offset_int_plus_int.rs:LL:CC --> $DIR/ptr_offset_int_plus_int.rs:LL:CC diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr index f88ad758d438..fa7a107ab534 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr +++ b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr @@ -6,7 +6,7 @@ LL | unsafe { intrinsics::offset(self, count) as *mut T } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::ptr::mut_ptr::::offset` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC note: inside `main` at $DIR/ptr_offset_int_plus_ptr.rs:LL:CC --> $DIR/ptr_offset_int_plus_ptr.rs:LL:CC diff --git a/tests/fail/intrinsics/ptr_offset_overflow.stderr b/tests/fail/intrinsics/ptr_offset_overflow.stderr index a144141c3c38..d8596acc33b0 100644 --- a/tests/fail/intrinsics/ptr_offset_overflow.stderr +++ b/tests/fail/intrinsics/ptr_offset_overflow.stderr @@ -6,7 +6,7 @@ LL | unsafe { intrinsics::offset(self, count) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC note: inside `main` at $DIR/ptr_offset_overflow.rs:LL:CC --> $DIR/ptr_offset_overflow.rs:LL:CC diff --git a/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr b/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr index 15e21ee676f7..c9b7f88385d9 100644 --- a/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr +++ b/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr @@ -6,7 +6,7 @@ LL | unsafe { intrinsics::offset(self, count) as *mut T } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::ptr::mut_ptr::::offset` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC note: inside `main` at $DIR/ptr_offset_ptr_plus_0.rs:LL:CC --> $DIR/ptr_offset_ptr_plus_0.rs:LL:CC diff --git a/tests/fail/intrinsics/rem-by-zero.stderr b/tests/fail/intrinsics/rem-by-zero.stderr index 7501aca7b247..1da33d8eaf59 100644 --- a/tests/fail/intrinsics/rem-by-zero.stderr +++ b/tests/fail/intrinsics/rem-by-zero.stderr @@ -6,7 +6,7 @@ LL | let _n = unchecked_rem(3u32, 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/rem-by-zero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-div-by-zero.stderr b/tests/fail/intrinsics/simd-div-by-zero.stderr index 37e1aafec2c0..552749c48ea7 100644 --- a/tests/fail/intrinsics/simd-div-by-zero.stderr +++ b/tests/fail/intrinsics/simd-div-by-zero.stderr @@ -6,7 +6,7 @@ LL | simd_div(x, y); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/simd-div-by-zero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-div-overflow.stderr b/tests/fail/intrinsics/simd-div-overflow.stderr index b5e8e378a0ab..98a3c1516270 100644 --- a/tests/fail/intrinsics/simd-div-overflow.stderr +++ b/tests/fail/intrinsics/simd-div-overflow.stderr @@ -6,7 +6,7 @@ LL | simd_div(x, y); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/simd-div-overflow.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-float-to-int.stderr b/tests/fail/intrinsics/simd-float-to-int.stderr index cfe272d90a1f..233074105b2b 100644 --- a/tests/fail/intrinsics/simd-float-to-int.stderr +++ b/tests/fail/intrinsics/simd-float-to-int.stderr @@ -6,7 +6,7 @@ LL | implement! { f32 } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `core::core_simd::round::>::to_int_unchecked::` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/round.rs:LL:CC note: inside `main` at $DIR/simd-float-to-int.rs:LL:CC --> $DIR/simd-float-to-int.rs:LL:CC diff --git a/tests/fail/intrinsics/simd-gather.stderr b/tests/fail/intrinsics/simd-gather.stderr index 0464e67f80c6..6b935bc6e254 100644 --- a/tests/fail/intrinsics/simd-gather.stderr +++ b/tests/fail/intrinsics/simd-gather.stderr @@ -6,7 +6,7 @@ LL | unsafe { intrinsics::simd_gather(or, ptrs, enable.to_int()) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::simd::Simd::::gather_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC note: inside `main` at $DIR/simd-gather.rs:LL:CC --> $DIR/simd-gather.rs:LL:CC diff --git a/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr b/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr index 15c39500d4cb..5a44861feee1 100644 --- a/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr +++ b/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr @@ -6,7 +6,7 @@ LL | simd_reduce_any(x); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/simd-reduce-invalid-bool.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-rem-by-zero.stderr b/tests/fail/intrinsics/simd-rem-by-zero.stderr index 1adc9f8235ee..dd68d3aa1840 100644 --- a/tests/fail/intrinsics/simd-rem-by-zero.stderr +++ b/tests/fail/intrinsics/simd-rem-by-zero.stderr @@ -6,7 +6,7 @@ LL | simd_rem(x, y); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/simd-rem-by-zero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-scatter.stderr b/tests/fail/intrinsics/simd-scatter.stderr index bc6a06fc88e5..24fc6782f149 100644 --- a/tests/fail/intrinsics/simd-scatter.stderr +++ b/tests/fail/intrinsics/simd-scatter.stderr @@ -6,7 +6,7 @@ LL | intrinsics::simd_scatter(self, ptrs, enable.to_int()) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::simd::Simd::::scatter_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC note: inside `main` at $DIR/simd-scatter.rs:LL:CC --> $DIR/simd-scatter.rs:LL:CC diff --git a/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr b/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr index 0a72ed39827b..7b3b3292ef78 100644 --- a/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr +++ b/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr @@ -6,7 +6,7 @@ LL | simd_select_bitmask(0b11111111u8, x, x); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/simd-select-bitmask-invalid.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-select-invalid-bool.stderr b/tests/fail/intrinsics/simd-select-invalid-bool.stderr index c0ceaac06cdd..ad5a89310681 100644 --- a/tests/fail/intrinsics/simd-select-invalid-bool.stderr +++ b/tests/fail/intrinsics/simd-select-invalid-bool.stderr @@ -6,7 +6,7 @@ LL | simd_select(x, x, x); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/simd-select-invalid-bool.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-shl-too-far.stderr b/tests/fail/intrinsics/simd-shl-too-far.stderr index 1d990e341e68..cea99f681932 100644 --- a/tests/fail/intrinsics/simd-shl-too-far.stderr +++ b/tests/fail/intrinsics/simd-shl-too-far.stderr @@ -6,7 +6,7 @@ LL | simd_shl(x, y); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/simd-shl-too-far.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-shr-too-far.stderr b/tests/fail/intrinsics/simd-shr-too-far.stderr index 58ef3737545a..df3288a805c8 100644 --- a/tests/fail/intrinsics/simd-shr-too-far.stderr +++ b/tests/fail/intrinsics/simd-shr-too-far.stderr @@ -6,7 +6,7 @@ LL | simd_shr(x, y); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/simd-shr-too-far.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_add1.stderr b/tests/fail/intrinsics/unchecked_add1.stderr index 403bbbac5149..9d48590593f5 100644 --- a/tests/fail/intrinsics/unchecked_add1.stderr +++ b/tests/fail/intrinsics/unchecked_add1.stderr @@ -6,7 +6,7 @@ LL | std::intrinsics::unchecked_add(40000u16, 30000); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/unchecked_add1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_add2.stderr b/tests/fail/intrinsics/unchecked_add2.stderr index 4881fce719e7..64691932e712 100644 --- a/tests/fail/intrinsics/unchecked_add2.stderr +++ b/tests/fail/intrinsics/unchecked_add2.stderr @@ -6,7 +6,7 @@ LL | std::intrinsics::unchecked_add(-30000i16, -8000); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/unchecked_add2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_div1.stderr b/tests/fail/intrinsics/unchecked_div1.stderr index 4792608961d3..867c8e0a9d39 100644 --- a/tests/fail/intrinsics/unchecked_div1.stderr +++ b/tests/fail/intrinsics/unchecked_div1.stderr @@ -6,7 +6,7 @@ LL | std::intrinsics::unchecked_div(i16::MIN, -1); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/unchecked_div1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_mul1.stderr b/tests/fail/intrinsics/unchecked_mul1.stderr index e94676fdfed7..4d3a45d41575 100644 --- a/tests/fail/intrinsics/unchecked_mul1.stderr +++ b/tests/fail/intrinsics/unchecked_mul1.stderr @@ -6,7 +6,7 @@ LL | std::intrinsics::unchecked_mul(300u16, 250u16); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/unchecked_mul1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_mul2.stderr b/tests/fail/intrinsics/unchecked_mul2.stderr index 493e04e46634..b64ef116be45 100644 --- a/tests/fail/intrinsics/unchecked_mul2.stderr +++ b/tests/fail/intrinsics/unchecked_mul2.stderr @@ -6,7 +6,7 @@ LL | std::intrinsics::unchecked_mul(1_000_000_000i32, -4); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/unchecked_mul2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_sub1.stderr b/tests/fail/intrinsics/unchecked_sub1.stderr index 838005dc1e31..8454382777a0 100644 --- a/tests/fail/intrinsics/unchecked_sub1.stderr +++ b/tests/fail/intrinsics/unchecked_sub1.stderr @@ -6,7 +6,7 @@ LL | std::intrinsics::unchecked_sub(14u32, 22); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/unchecked_sub1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_sub2.stderr b/tests/fail/intrinsics/unchecked_sub2.stderr index dc4b17019879..2e6fc2e0b64f 100644 --- a/tests/fail/intrinsics/unchecked_sub2.stderr +++ b/tests/fail/intrinsics/unchecked_sub2.stderr @@ -6,7 +6,7 @@ LL | std::intrinsics::unchecked_sub(30000i16, -7000); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/unchecked_sub2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/write_bytes_null.stderr b/tests/fail/intrinsics/write_bytes_null.stderr index 77f675e8fb62..8e8156531b16 100644 --- a/tests/fail/intrinsics/write_bytes_null.stderr +++ b/tests/fail/intrinsics/write_bytes_null.stderr @@ -6,7 +6,7 @@ LL | unsafe { write_bytes::(std::ptr::null_mut(), 0, 0) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/write_bytes_null.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/write_bytes_overflow.stderr b/tests/fail/intrinsics/write_bytes_overflow.stderr index 0d5259dce2f4..1e5381279529 100644 --- a/tests/fail/intrinsics/write_bytes_overflow.stderr +++ b/tests/fail/intrinsics/write_bytes_overflow.stderr @@ -6,7 +6,7 @@ LL | write_bytes(dst, val, count) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::intrinsics::write_bytes::` at RUSTLIB/core/src/intrinsics.rs:LL:CC = note: inside `std::ptr::mut_ptr::::write_bytes` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC note: inside `main` at $DIR/write_bytes_overflow.rs:LL:CC diff --git a/tests/fail/invalid_bool.stderr b/tests/fail/invalid_bool.stderr index 23c5365618b8..26cd41bdca3a 100644 --- a/tests/fail/invalid_bool.stderr +++ b/tests/fail/invalid_bool.stderr @@ -6,7 +6,7 @@ LL | let _x = b == std::hint::black_box(true); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/invalid_bool.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/invalid_char.stderr b/tests/fail/invalid_char.stderr index 69f3ef1f4a6d..d605ae44750b 100644 --- a/tests/fail/invalid_char.stderr +++ b/tests/fail/invalid_char.stderr @@ -6,7 +6,7 @@ LL | let _x = c == 'x'; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/invalid_char.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/invalid_enum_tag.stderr b/tests/fail/invalid_enum_tag.stderr index b5e93d320a86..2f5a4541129c 100644 --- a/tests/fail/invalid_enum_tag.stderr +++ b/tests/fail/invalid_enum_tag.stderr @@ -6,7 +6,7 @@ LL | Discriminant(intrinsics::discriminant_value(v)) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::mem::discriminant::` at RUSTLIB/core/src/mem/mod.rs:LL:CC note: inside `main` at $DIR/invalid_enum_tag.rs:LL:CC --> $DIR/invalid_enum_tag.rs:LL:CC diff --git a/tests/fail/invalid_int.stderr b/tests/fail/invalid_int.stderr index cd7919444f0a..85aa3fb5a08b 100644 --- a/tests/fail/invalid_int.stderr +++ b/tests/fail/invalid_int.stderr @@ -6,7 +6,7 @@ LL | let _x = i + 0; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/invalid_int.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/issue-miri-1112.stderr b/tests/fail/issue-miri-1112.stderr index cf692bddaf44..89dc8dc327f8 100644 --- a/tests/fail/issue-miri-1112.stderr +++ b/tests/fail/issue-miri-1112.stderr @@ -6,7 +6,7 @@ LL | let obj = std::mem::transmute::(obj) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `FunnyPointer::from_data_ptr` at $DIR/issue-miri-1112.rs:LL:CC note: inside `main` at $DIR/issue-miri-1112.rs:LL:CC --> $DIR/issue-miri-1112.rs:LL:CC diff --git a/tests/fail/modifying_constants.stderr b/tests/fail/modifying_constants.stderr index 995011482323..853e3a9015e7 100644 --- a/tests/fail/modifying_constants.stderr +++ b/tests/fail/modifying_constants.stderr @@ -6,7 +6,7 @@ LL | *y = 42; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/modifying_constants.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/never_say_never.stderr b/tests/fail/never_say_never.stderr index 22ad10f13103..4072a0376f5c 100644 --- a/tests/fail/never_say_never.stderr +++ b/tests/fail/never_say_never.stderr @@ -6,7 +6,7 @@ LL | *(y as *const _ as *const !) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/never_say_never.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/never_transmute_humans.stderr b/tests/fail/never_transmute_humans.stderr index 6d8fa37e98ef..2a8ee0a3e9bd 100644 --- a/tests/fail/never_transmute_humans.stderr +++ b/tests/fail/never_transmute_humans.stderr @@ -6,7 +6,7 @@ LL | std::mem::transmute::(Human) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/never_transmute_humans.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/never_transmute_void.stderr b/tests/fail/never_transmute_void.stderr index 8d8a4d0e832f..31614ef3edf8 100644 --- a/tests/fail/never_transmute_void.stderr +++ b/tests/fail/never_transmute_void.stderr @@ -6,7 +6,7 @@ LL | match v.0 {} | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `m::f` at $DIR/never_transmute_void.rs:LL:CC note: inside `main` at $DIR/never_transmute_void.rs:LL:CC --> $DIR/never_transmute_void.rs:LL:CC diff --git a/tests/fail/panic/bad_miri_start_panic.stderr b/tests/fail/panic/bad_miri_start_panic.stderr index dca5d39b7665..a664590e36ae 100644 --- a/tests/fail/panic/bad_miri_start_panic.stderr +++ b/tests/fail/panic/bad_miri_start_panic.stderr @@ -6,7 +6,7 @@ LL | unsafe { miri_start_panic(&mut 0) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/bad_miri_start_panic.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/panic/bad_unwind.stderr b/tests/fail/panic/bad_unwind.stderr index 745cef8be702..be8a3668ac52 100644 --- a/tests/fail/panic/bad_unwind.stderr +++ b/tests/fail/panic/bad_unwind.stderr @@ -8,7 +8,7 @@ LL | std::panic::catch_unwind(|| unwind()).unwrap_err(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/bad_unwind.rs:LL:CC = note: inside `std::panicking::r#try::do_call::<[closure@$DIR/bad_unwind.rs:LL:CC], ()>` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::panicking::r#try::<(), [closure@$DIR/bad_unwind.rs:LL:CC]>` at RUSTLIB/std/src/panicking.rs:LL:CC diff --git a/tests/fail/panic/unwind_panic_abort.stderr b/tests/fail/panic/unwind_panic_abort.stderr index 7094aebd6131..df4b9522f467 100644 --- a/tests/fail/panic/unwind_panic_abort.stderr +++ b/tests/fail/panic/unwind_panic_abort.stderr @@ -6,7 +6,7 @@ LL | miri_start_panic(&mut 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/unwind_panic_abort.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/pointer_partial_overwrite.stderr b/tests/fail/pointer_partial_overwrite.stderr index 6779df99c3fb..cd3c4ddd6ca4 100644 --- a/tests/fail/pointer_partial_overwrite.stderr +++ b/tests/fail/pointer_partial_overwrite.stderr @@ -6,7 +6,7 @@ LL | let x = *p; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/pointer_partial_overwrite.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/provenance/provenance_transmute.stderr b/tests/fail/provenance/provenance_transmute.stderr index 9cbec077e42c..ddbf64f38380 100644 --- a/tests/fail/provenance/provenance_transmute.stderr +++ b/tests/fail/provenance/provenance_transmute.stderr @@ -6,7 +6,7 @@ LL | let _val = *left_ptr; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `deref` at $DIR/provenance_transmute.rs:LL:CC note: inside `main` at $DIR/provenance_transmute.rs:LL:CC --> $DIR/provenance_transmute.rs:LL:CC diff --git a/tests/fail/provenance/ptr_int_unexposed.stderr b/tests/fail/provenance/ptr_int_unexposed.stderr index cdd25d0e638e..f0c47e54859e 100644 --- a/tests/fail/provenance/ptr_int_unexposed.stderr +++ b/tests/fail/provenance/ptr_int_unexposed.stderr @@ -6,7 +6,7 @@ LL | assert_eq!(unsafe { *ptr }, 3); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/ptr_int_unexposed.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/provenance/ptr_invalid.stderr b/tests/fail/provenance/ptr_invalid.stderr index 76a40765eb2f..0d6c0f92d93b 100644 --- a/tests/fail/provenance/ptr_invalid.stderr +++ b/tests/fail/provenance/ptr_invalid.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { *xptr_invalid }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/ptr_invalid.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/provenance/ptr_invalid_offset.stderr b/tests/fail/provenance/ptr_invalid_offset.stderr index 661fabf29afb..8f19d4ec9358 100644 --- a/tests/fail/provenance/ptr_invalid_offset.stderr +++ b/tests/fail/provenance/ptr_invalid_offset.stderr @@ -6,7 +6,7 @@ LL | unsafe { intrinsics::offset(self, count) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC note: inside `main` at $DIR/ptr_invalid_offset.rs:LL:CC --> $DIR/ptr_invalid_offset.rs:LL:CC diff --git a/tests/fail/provenance/strict_provenance_cast.stderr b/tests/fail/provenance/strict_provenance_cast.stderr index ab64f2bb288e..ff6ab1c9e95b 100644 --- a/tests/fail/provenance/strict_provenance_cast.stderr +++ b/tests/fail/provenance/strict_provenance_cast.stderr @@ -5,7 +5,7 @@ LL | let _ptr = addr as *const i32; | ^^^^^^^^^^^^^^^^^^ integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance` | = help: use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead - + = note: backtrace: = note: inside `main` at $DIR/strict_provenance_cast.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/rc_as_ptr.stderr b/tests/fail/rc_as_ptr.stderr index d4864da04e41..f2dd245be345 100644 --- a/tests/fail/rc_as_ptr.stderr +++ b/tests/fail/rc_as_ptr.stderr @@ -6,7 +6,7 @@ LL | assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at RUSTLIB/core/src/macros/mod.rs:LL:CC = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/fail/reading_half_a_pointer.stderr b/tests/fail/reading_half_a_pointer.stderr index 505c8deafb6d..d6690f0c7a01 100644 --- a/tests/fail/reading_half_a_pointer.stderr +++ b/tests/fail/reading_half_a_pointer.stderr @@ -5,7 +5,7 @@ LL | let _x = *d_alias; | ^^^^^^^^ unable to turn pointer into raw bytes | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside `main` at $DIR/reading_half_a_pointer.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shim_arg_size.32bit.stderr b/tests/fail/shim_arg_size.32bit.stderr index 3b54a5b51248..84b09acbac3d 100644 --- a/tests/fail/shim_arg_size.32bit.stderr +++ b/tests/fail/shim_arg_size.32bit.stderr @@ -6,7 +6,7 @@ LL | let _p1 = malloc(42); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/shim_arg_size.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shim_arg_size.64bit.stderr b/tests/fail/shim_arg_size.64bit.stderr index 5e33604c121d..98ed99d6d729 100644 --- a/tests/fail/shim_arg_size.64bit.stderr +++ b/tests/fail/shim_arg_size.64bit.stderr @@ -6,7 +6,7 @@ LL | let _p1 = malloc(42); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/shim_arg_size.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/should-pass/cpp20_rwc_syncs.stderr b/tests/fail/should-pass/cpp20_rwc_syncs.stderr index 5f0e86dc653e..0ab02687e2ae 100644 --- a/tests/fail/should-pass/cpp20_rwc_syncs.stderr +++ b/tests/fail/should-pass/cpp20_rwc_syncs.stderr @@ -6,7 +6,7 @@ LL | unsafe { intrinsics::unreachable() } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::hint::unreachable_unchecked` at RUSTLIB/core/src/hint.rs:LL:CC note: inside `test_cpp20_rwc_syncs` at $DIR/cpp20_rwc_syncs.rs:LL:CC --> $DIR/cpp20_rwc_syncs.rs:LL:CC diff --git a/tests/fail/stacked_borrows/alias_through_mutation.stderr b/tests/fail/stacked_borrows/alias_through_mutation.stderr index eb02136478f2..ec985cb26a99 100644 --- a/tests/fail/stacked_borrows/alias_through_mutation.stderr +++ b/tests/fail/stacked_borrows/alias_through_mutation.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | *target = 13; | ^^^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/alias_through_mutation.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/aliasing_mut1.stderr b/tests/fail/stacked_borrows/aliasing_mut1.stderr index 7282612b6fc3..34a53aa8f307 100644 --- a/tests/fail/stacked_borrows/aliasing_mut1.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut1.stderr @@ -21,6 +21,7 @@ help: this protector is live for this call | LL | pub fn safe(_x: &mut i32, _y: &mut i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `safe` at $DIR/aliasing_mut1.rs:LL:CC note: inside `main` at $DIR/aliasing_mut1.rs:LL:CC --> $DIR/aliasing_mut1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/aliasing_mut2.stderr b/tests/fail/stacked_borrows/aliasing_mut2.stderr index d314fff6222e..7830648ee8f3 100644 --- a/tests/fail/stacked_borrows/aliasing_mut2.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut2.stderr @@ -21,6 +21,7 @@ help: this protector is live for this call | LL | pub fn safe(_x: &i32, _y: &mut i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `safe` at $DIR/aliasing_mut2.rs:LL:CC note: inside `main` at $DIR/aliasing_mut2.rs:LL:CC --> $DIR/aliasing_mut2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/aliasing_mut3.stderr b/tests/fail/stacked_borrows/aliasing_mut3.stderr index 66220cfbfc4d..8e489b738657 100644 --- a/tests/fail/stacked_borrows/aliasing_mut3.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut3.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | pub fn safe(_x: &mut i32, _y: &i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `safe` at $DIR/aliasing_mut3.rs:LL:CC note: inside `main` at $DIR/aliasing_mut3.rs:LL:CC --> $DIR/aliasing_mut3.rs:LL:CC diff --git a/tests/fail/stacked_borrows/aliasing_mut4.stderr b/tests/fail/stacked_borrows/aliasing_mut4.stderr index 0bf5e863bfa3..f62ce1e51964 100644 --- a/tests/fail/stacked_borrows/aliasing_mut4.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut4.stderr @@ -21,6 +21,7 @@ help: this protector is live for this call | LL | pub fn safe(_x: &i32, _y: &mut Cell) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `safe` at $DIR/aliasing_mut4.rs:LL:CC note: inside `main` at $DIR/aliasing_mut4.rs:LL:CC --> $DIR/aliasing_mut4.rs:LL:CC diff --git a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr index 06c2dc340b7b..88ecca87962d 100644 --- a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr +++ b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | *our = 5; | ^^^^^^^^ + = note: backtrace: = note: inside `unknown_code_2` at $DIR/box_exclusive_violation1.rs:LL:CC note: inside `demo_mut_advanced_unique` at $DIR/box_exclusive_violation1.rs:LL:CC --> $DIR/box_exclusive_violation1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr b/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr index 14cede13b7a1..6e78ed6c7298 100644 --- a/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr +++ b/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0xc] | LL | unsafe { from_raw_parts_mut(self_.as_ptr() as *mut T, self_.len()) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/buggy_as_mut_slice.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/buggy_split_at_mut.stderr b/tests/fail/stacked_borrows/buggy_split_at_mut.stderr index 47ab7d6a062a..6e6dc38aaf06 100644 --- a/tests/fail/stacked_borrows/buggy_split_at_mut.stderr +++ b/tests/fail/stacked_borrows/buggy_split_at_mut.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x10] | LL | from_raw_parts_mut(ptr.offset(mid as isize), len - mid), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/buggy_split_at_mut.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr b/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr index 58032fa35a1d..c3ea7a437cdb 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr +++ b/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - + = note: backtrace: = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `alloc::alloc::box_free::` at RUSTLIB/alloc/src/alloc.rs:LL:CC diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr b/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr index 22776656e019..d6c31e0649ec 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr +++ b/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - + = note: backtrace: = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `alloc::alloc::box_free::` at RUSTLIB/alloc/src/alloc.rs:LL:CC diff --git a/tests/fail/stacked_borrows/exposed_only_ro.stderr b/tests/fail/stacked_borrows/exposed_only_ro.stderr index 28fa98b6020c..af76183fb25d 100644 --- a/tests/fail/stacked_borrows/exposed_only_ro.stderr +++ b/tests/fail/stacked_borrows/exposed_only_ro.stderr @@ -9,7 +9,7 @@ LL | unsafe { *ptr = 0 }; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - + = note: backtrace: = note: inside `main` at $DIR/exposed_only_ro.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read1.stderr b/tests/fail/stacked_borrows/illegal_read1.stderr index bf78c62a0e79..3f4ade9a712f 100644 --- a/tests/fail/stacked_borrows/illegal_read1.stderr +++ b/tests/fail/stacked_borrows/illegal_read1.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | let _val = unsafe { *xraw }; | ^^^^^ + = note: backtrace: = note: inside `main` at $DIR/illegal_read1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read2.stderr b/tests/fail/stacked_borrows/illegal_read2.stderr index b0bc3f9a7f0d..cb0ac5602782 100644 --- a/tests/fail/stacked_borrows/illegal_read2.stderr +++ b/tests/fail/stacked_borrows/illegal_read2.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | let shr = unsafe { &*xraw }; | ^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/illegal_read2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read3.stderr b/tests/fail/stacked_borrows/illegal_read3.stderr index 34580dec4ee4..bdeca5f7ec86 100644 --- a/tests/fail/stacked_borrows/illegal_read3.stderr +++ b/tests/fail/stacked_borrows/illegal_read3.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | let _val = unsafe { *xref1.r }; | ^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/illegal_read3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read4.stderr b/tests/fail/stacked_borrows/illegal_read4.stderr index 19c361a19542..59c2088c0c85 100644 --- a/tests/fail/stacked_borrows/illegal_read4.stderr +++ b/tests/fail/stacked_borrows/illegal_read4.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | let _val = unsafe { *xraw }; // use the raw again, this invalidates xref2 *even* with the special read except for uniq refs | ^^^^^ + = note: backtrace: = note: inside `main` at $DIR/illegal_read4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read5.stderr b/tests/fail/stacked_borrows/illegal_read5.stderr index 4af149e3831e..d1506f199684 100644 --- a/tests/fail/stacked_borrows/illegal_read5.stderr +++ b/tests/fail/stacked_borrows/illegal_read5.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [$HEX..$HEX] | LL | mem::forget(unsafe { ptr::read(xshr) }); // but after reading through the shared ref | ^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/illegal_read5.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read6.stderr b/tests/fail/stacked_borrows/illegal_read6.stderr index 2098dbdc6a49..5abea6f611a4 100644 --- a/tests/fail/stacked_borrows/illegal_read6.stderr +++ b/tests/fail/stacked_borrows/illegal_read6.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | let x = &mut *x; // kill `raw` | ^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/illegal_read6.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read7.stderr b/tests/fail/stacked_borrows/illegal_read7.stderr index 3d70945fa6c6..56ebd93918bf 100644 --- a/tests/fail/stacked_borrows/illegal_read7.stderr +++ b/tests/fail/stacked_borrows/illegal_read7.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | let _val = ptr::read(raw); | ^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/illegal_read7.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read8.stderr b/tests/fail/stacked_borrows/illegal_read8.stderr index 7c0cb0066b27..ef150e84f274 100644 --- a/tests/fail/stacked_borrows/illegal_read8.stderr +++ b/tests/fail/stacked_borrows/illegal_read8.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | *y2 += 1; | ^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/illegal_read8.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr b/tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr index fde135f752f7..7c77c62575d7 100644 --- a/tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr +++ b/tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr @@ -9,7 +9,7 @@ LL | let _val = *root2; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - + = note: backtrace: = note: inside `main` at $DIR/illegal_read_despite_exposed1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr b/tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr index 947d9fd70a0d..4fbbd4c6bede 100644 --- a/tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr +++ b/tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr @@ -9,7 +9,7 @@ LL | let _val = *root2; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - + = note: backtrace: = note: inside `main` at $DIR/illegal_read_despite_exposed2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write1.stderr b/tests/fail/stacked_borrows/illegal_write1.stderr index b2084da862fe..f93972051692 100644 --- a/tests/fail/stacked_borrows/illegal_write1.stderr +++ b/tests/fail/stacked_borrows/illegal_write1.stderr @@ -14,6 +14,7 @@ help: was created by a retag at offsets [0x0..0x4] | LL | let x: *mut u32 = xref as *const _ as *mut _; | ^^^^ + = note: backtrace: = note: inside `main` at $DIR/illegal_write1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write2.stderr b/tests/fail/stacked_borrows/illegal_write2.stderr index 09784bd79a18..92dacf214f8c 100644 --- a/tests/fail/stacked_borrows/illegal_write2.stderr +++ b/tests/fail/stacked_borrows/illegal_write2.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | drop(&mut *target); // reborrow | ^^^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/illegal_write2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write3.stderr b/tests/fail/stacked_borrows/illegal_write3.stderr index 983894dad065..bb6d189f8520 100644 --- a/tests/fail/stacked_borrows/illegal_write3.stderr +++ b/tests/fail/stacked_borrows/illegal_write3.stderr @@ -14,6 +14,7 @@ help: was created by a retag at offsets [0x0..0x4] | LL | let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag | ^^^^^ + = note: backtrace: = note: inside `main` at $DIR/illegal_write3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write4.stderr b/tests/fail/stacked_borrows/illegal_write4.stderr index ac4dd68bbc7e..97301d64deb3 100644 --- a/tests/fail/stacked_borrows/illegal_write4.stderr +++ b/tests/fail/stacked_borrows/illegal_write4.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | let _mut_ref: &mut i32 = unsafe { mem::transmute(raw) }; // &mut, with raw tag | ^^^^^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/illegal_write4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write5.stderr b/tests/fail/stacked_borrows/illegal_write5.stderr index b11990814565..9cb32d7bdfd1 100644 --- a/tests/fail/stacked_borrows/illegal_write5.stderr +++ b/tests/fail/stacked_borrows/illegal_write5.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | unsafe { *xraw = 15 }; | ^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/illegal_write5.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write6.stderr b/tests/fail/stacked_borrows/illegal_write6.stderr index 563397e062d5..cbf4a22f23f2 100644 --- a/tests/fail/stacked_borrows/illegal_write6.stderr +++ b/tests/fail/stacked_borrows/illegal_write6.stderr @@ -26,6 +26,7 @@ LL | | unsafe { *y = 2 }; LL | | return *a; LL | | } | |_^ + = note: backtrace: = note: inside `foo` at $DIR/illegal_write6.rs:LL:CC note: inside `main` at $DIR/illegal_write6.rs:LL:CC --> $DIR/illegal_write6.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr b/tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr index ac96c9dac8d8..0f5834077b3d 100644 --- a/tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr +++ b/tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr @@ -9,7 +9,7 @@ LL | let _val = *root2; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - + = note: backtrace: = note: inside `main` at $DIR/illegal_write_despite_exposed1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/interior_mut1.stderr b/tests/fail/stacked_borrows/interior_mut1.stderr index 2490fd3e1e9a..73be074ce91a 100644 --- a/tests/fail/stacked_borrows/interior_mut1.stderr +++ b/tests/fail/stacked_borrows/interior_mut1.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | *c.get() = UnsafeCell::new(1); // invalidates inner_shr | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/interior_mut1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/interior_mut2.stderr b/tests/fail/stacked_borrows/interior_mut2.stderr index 33060a7818ff..74e91d49c418 100644 --- a/tests/fail/stacked_borrows/interior_mut2.stderr +++ b/tests/fail/stacked_borrows/interior_mut2.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | *c.get() = UnsafeCell::new(0); // now inner_shr gets invalidated | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/interior_mut2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr index 826cdc9b5f8e..5f54134a2431 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr @@ -26,6 +26,7 @@ LL | | // unique for the duration of this call. LL | | let _val = unsafe { *x }; LL | | } | |_^ + = note: backtrace: = note: inside `inner` at $DIR/invalidate_against_barrier1.rs:LL:CC note: inside `main` at $DIR/invalidate_against_barrier1.rs:LL:CC --> $DIR/invalidate_against_barrier1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr index 1cf90f91db02..15bc91e869f9 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr @@ -26,6 +26,7 @@ LL | | // immutable for the duration of this call. LL | | unsafe { *x = 0 }; LL | | } | |_^ + = note: backtrace: = note: inside `inner` at $DIR/invalidate_against_barrier2.rs:LL:CC note: inside `main` at $DIR/invalidate_against_barrier2.rs:LL:CC --> $DIR/invalidate_against_barrier2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/issue-miri-1050-1.stderr b/tests/fail/stacked_borrows/issue-miri-1050-1.stderr index c2c471fba881..8180a60a837a 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-1.stderr +++ b/tests/fail/stacked_borrows/issue-miri-1050-1.stderr @@ -6,7 +6,7 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC note: inside `main` at $DIR/issue-miri-1050-1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/issue-miri-1050-2.stderr b/tests/fail/stacked_borrows/issue-miri-1050-2.stderr index c49852cb7f4f..61ce006dc82b 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-2.stderr +++ b/tests/fail/stacked_borrows/issue-miri-1050-2.stderr @@ -6,7 +6,7 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC note: inside `main` at $DIR/issue-miri-1050-2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/load_invalid_mut.stderr b/tests/fail/stacked_borrows/load_invalid_mut.stderr index a15900411ce4..293d85cc9f45 100644 --- a/tests/fail/stacked_borrows/load_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/load_invalid_mut.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ + = note: backtrace: = note: inside `main` at $DIR/load_invalid_mut.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/load_invalid_shr.stderr b/tests/fail/stacked_borrows/load_invalid_shr.stderr index 85cb8ef93ebd..5749daa51fd9 100644 --- a/tests/fail/stacked_borrows/load_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/load_invalid_shr.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | unsafe { *xraw = 42 }; // unfreeze | ^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/load_invalid_shr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr b/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr index 8afb4fee18b5..acc904794fb5 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr +++ b/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | *our = 5; | ^^^^^^^^ + = note: backtrace: = note: inside `unknown_code_2` at $DIR/mut_exclusive_violation1.rs:LL:CC note: inside `demo_mut_advanced_unique` at $DIR/mut_exclusive_violation1.rs:LL:CC --> $DIR/mut_exclusive_violation1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr b/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr index 85baf93613a2..5bbf9bc51847 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr +++ b/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | let _raw2 = ptr2.as_mut(); | ^^^^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/mut_exclusive_violation2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/newtype_retagging.stderr b/tests/fail/stacked_borrows/newtype_retagging.stderr index f65231b661f9..860a628492c7 100644 --- a/tests/fail/stacked_borrows/newtype_retagging.stderr +++ b/tests/fail/stacked_borrows/newtype_retagging.stderr @@ -23,6 +23,7 @@ LL | / fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) { LL | | dealloc(); LL | | } | |_^ + = note: backtrace: = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC note: inside closure at $DIR/newtype_retagging.rs:LL:CC diff --git a/tests/fail/stacked_borrows/outdated_local.stderr b/tests/fail/stacked_borrows/outdated_local.stderr index c218d500cf8b..d2ada6458631 100644 --- a/tests/fail/stacked_borrows/outdated_local.stderr +++ b/tests/fail/stacked_borrows/outdated_local.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | x = 1; // this invalidates y by reactivating the lowermost uniq borrow for this local | ^^^^^ + = note: backtrace: = note: inside `main` at $DIR/outdated_local.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/pass_invalid_mut.stderr b/tests/fail/stacked_borrows/pass_invalid_mut.stderr index 6af914e55f91..933ef1ad5970 100644 --- a/tests/fail/stacked_borrows/pass_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/pass_invalid_mut.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ + = note: backtrace: = note: inside `main` at $DIR/pass_invalid_mut.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/pass_invalid_shr.stderr b/tests/fail/stacked_borrows/pass_invalid_shr.stderr index d38c58273453..02cf62f03326 100644 --- a/tests/fail/stacked_borrows/pass_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/pass_invalid_shr.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | unsafe { *xraw = 42 }; // unfreeze | ^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/pass_invalid_shr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/pointer_smuggling.stderr b/tests/fail/stacked_borrows/pointer_smuggling.stderr index a3ab1b9fc5e5..66427bdf64d6 100644 --- a/tests/fail/stacked_borrows/pointer_smuggling.stderr +++ b/tests/fail/stacked_borrows/pointer_smuggling.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x1] | LL | *val = 2; // this invalidates any raw ptrs `fun1` might have created. | ^^^^^^^^ + = note: backtrace: = note: inside `fun2` at $DIR/pointer_smuggling.rs:LL:CC note: inside `main` at $DIR/pointer_smuggling.rs:LL:CC --> $DIR/pointer_smuggling.rs:LL:CC diff --git a/tests/fail/stacked_borrows/raw_tracking.stderr b/tests/fail/stacked_borrows/raw_tracking.stderr index d3674893fab8..2028a9114272 100644 --- a/tests/fail/stacked_borrows/raw_tracking.stderr +++ b/tests/fail/stacked_borrows/raw_tracking.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | let raw2 = &mut l as *mut _; // invalidates raw1 | ^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/raw_tracking.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/return_invalid_mut.stderr b/tests/fail/stacked_borrows/return_invalid_mut.stderr index 876850590e51..230c3e82ff23 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x8] | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ + = note: backtrace: = note: inside `foo` at $DIR/return_invalid_mut.rs:LL:CC note: inside `main` at $DIR/return_invalid_mut.rs:LL:CC --> $DIR/return_invalid_mut.rs:LL:CC diff --git a/tests/fail/stacked_borrows/return_invalid_mut_option.stderr b/tests/fail/stacked_borrows/return_invalid_mut_option.stderr index 4bee128d68a4..f278113e4257 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_option.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut_option.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x8] | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ + = note: backtrace: = note: inside `main` at $DIR/return_invalid_mut_option.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr b/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr index 3062d821765a..9465fd072ea9 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x8] | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ + = note: backtrace: = note: inside `main` at $DIR/return_invalid_mut_tuple.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/return_invalid_shr.stderr b/tests/fail/stacked_borrows/return_invalid_shr.stderr index aa3f7ddde59e..75ea8bb89ec0 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x8] | LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `foo` at $DIR/return_invalid_shr.rs:LL:CC note: inside `main` at $DIR/return_invalid_shr.rs:LL:CC --> $DIR/return_invalid_shr.rs:LL:CC diff --git a/tests/fail/stacked_borrows/return_invalid_shr_option.stderr b/tests/fail/stacked_borrows/return_invalid_shr_option.stderr index a23c69d12db1..27656b46ccfc 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_option.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr_option.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x8] | LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/return_invalid_shr_option.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr b/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr index 9519f2f6f07b..9fdc87808651 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x8] | LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/return_invalid_shr_tuple.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr index 151654bad5cf..9909778ab28e 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | shr_rw.set(1); | ^^^^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/shared_rw_borrows_are_weak1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr index c0bf809356bd..2c0117577f2e 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [$HEX..$HEX] | LL | shr_rw.replace(1); | ^^^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/shared_rw_borrows_are_weak2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/shr_frozen_violation1.stderr b/tests/fail/stacked_borrows/shr_frozen_violation1.stderr index 55872300713a..47799b18e1f9 100644 --- a/tests/fail/stacked_borrows/shr_frozen_violation1.stderr +++ b/tests/fail/stacked_borrows/shr_frozen_violation1.stderr @@ -14,6 +14,7 @@ help: was created by a retag at offsets [0x0..0x4] | LL | *(x as *const i32 as *mut i32) = 7; | ^ + = note: backtrace: = note: inside `unknown_code` at $DIR/shr_frozen_violation1.rs:LL:CC note: inside `foo` at $DIR/shr_frozen_violation1.rs:LL:CC --> $DIR/shr_frozen_violation1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/static_memory_modification.stderr b/tests/fail/stacked_borrows/static_memory_modification.stderr index 091eb29f64d7..c8a0dc8dca2d 100644 --- a/tests/fail/stacked_borrows/static_memory_modification.stderr +++ b/tests/fail/stacked_borrows/static_memory_modification.stderr @@ -6,7 +6,7 @@ LL | std::mem::transmute::<&usize, &mut usize>(&X) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/static_memory_modification.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr index 91c3ff9f8634..b48abb3df709 100644 --- a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr +++ b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr @@ -14,6 +14,7 @@ help: was created by a retag at offsets [0x4..0x8] | LL | let raw = (&mut x[1] as *mut i32).wrapping_offset(-1); | ^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/transmute-is-no-escape.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/unescaped_local.stderr b/tests/fail/stacked_borrows/unescaped_local.stderr index 464296651c5e..6302ccde9837 100644 --- a/tests/fail/stacked_borrows/unescaped_local.stderr +++ b/tests/fail/stacked_borrows/unescaped_local.stderr @@ -9,7 +9,7 @@ LL | *raw = 13; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - + = note: backtrace: = note: inside `main` at $DIR/unescaped_local.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/unescaped_static.stderr b/tests/fail/stacked_borrows/unescaped_static.stderr index 621e9617fdfc..018ff77b2e93 100644 --- a/tests/fail/stacked_borrows/unescaped_static.stderr +++ b/tests/fail/stacked_borrows/unescaped_static.stderr @@ -14,6 +14,7 @@ help: was created by a retag at offsets [0x0..0x1] | LL | let ptr_to_first = &ARRAY[0] as *const u8; | ^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/unescaped_static.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/vtable.stderr b/tests/fail/stacked_borrows/vtable.stderr index 31c3d5982e5e..534f811e48ab 100644 --- a/tests/fail/stacked_borrows/vtable.stderr +++ b/tests/fail/stacked_borrows/vtable.stderr @@ -6,7 +6,7 @@ LL | unsafe { PtrRepr { components: PtrComponents { data_address, metadata } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::ptr::from_raw_parts::` at RUSTLIB/core/src/ptr/metadata.rs:LL:CC note: inside `uwu` at $DIR/vtable.rs:LL:CC --> $DIR/vtable.rs:LL:CC diff --git a/tests/fail/stacked_borrows/zst_slice.stderr b/tests/fail/stacked_borrows/zst_slice.stderr index 3474f0c2b423..2878f4c069af 100644 --- a/tests/fail/stacked_borrows/zst_slice.stderr +++ b/tests/fail/stacked_borrows/zst_slice.stderr @@ -14,6 +14,7 @@ help: was created by a retag at offsets [0x0..0x0] | LL | assert_eq!(*s.get_unchecked(1), 2); | ^^^^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `core::slice::::get_unchecked::` at RUSTLIB/core/src/slice/mod.rs:LL:CC note: inside `main` at $DIR/zst_slice.rs:LL:CC --> $DIR/zst_slice.rs:LL:CC diff --git a/tests/fail/static_memory_modification1.stderr b/tests/fail/static_memory_modification1.stderr index a37a79fa56f9..47590afc1d1a 100644 --- a/tests/fail/static_memory_modification1.stderr +++ b/tests/fail/static_memory_modification1.stderr @@ -6,7 +6,7 @@ LL | *std::mem::transmute::<&usize, &mut usize>(&X) = 6; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/static_memory_modification1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/static_memory_modification2.stderr b/tests/fail/static_memory_modification2.stderr index d38f3f6342c3..c8fce81ede55 100644 --- a/tests/fail/static_memory_modification2.stderr +++ b/tests/fail/static_memory_modification2.stderr @@ -6,7 +6,7 @@ LL | transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/static_memory_modification2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/static_memory_modification3.stderr b/tests/fail/static_memory_modification3.stderr index 96e3877c54fb..16b06bb3f796 100644 --- a/tests/fail/static_memory_modification3.stderr +++ b/tests/fail/static_memory_modification3.stderr @@ -6,7 +6,7 @@ LL | transmute::<&[u8], &mut [u8]>(bs)[4] = 42; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/static_memory_modification3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_cond_double_destroy.stderr b/tests/fail/sync/libc_pthread_cond_double_destroy.stderr index 362952678139..0e1c776f5965 100644 --- a/tests/fail/sync/libc_pthread_cond_double_destroy.stderr +++ b/tests/fail/sync/libc_pthread_cond_double_destroy.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_cond_destroy(cond.as_mut_ptr()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/libc_pthread_cond_double_destroy.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_condattr_double_destroy.stderr b/tests/fail/sync/libc_pthread_condattr_double_destroy.stderr index 14439445e727..dee50249b6b6 100644 --- a/tests/fail/sync/libc_pthread_condattr_double_destroy.stderr +++ b/tests/fail/sync/libc_pthread_condattr_double_destroy.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_condattr_destroy(attr.as_mut_ptr()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/libc_pthread_condattr_double_destroy.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.stderr b/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.stderr index d42174b9fb74..1b40f39d04bc 100644 --- a/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.stderr +++ b/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_mutex_lock(&mut mutex as *mut _); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/libc_pthread_mutex_NULL_deadlock.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_mutex_default_deadlock.stderr b/tests/fail/sync/libc_pthread_mutex_default_deadlock.stderr index cb5daef68cbe..7606472beb97 100644 --- a/tests/fail/sync/libc_pthread_mutex_default_deadlock.stderr +++ b/tests/fail/sync/libc_pthread_mutex_default_deadlock.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_mutex_lock(&mut mutex as *mut _); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/libc_pthread_mutex_default_deadlock.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_mutex_destroy_locked.stderr b/tests/fail/sync/libc_pthread_mutex_destroy_locked.stderr index 96a3c645ab63..40a7b3de09d5 100644 --- a/tests/fail/sync/libc_pthread_mutex_destroy_locked.stderr +++ b/tests/fail/sync/libc_pthread_mutex_destroy_locked.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_mutex_destroy(&mut mutex as *mut _); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/libc_pthread_mutex_destroy_locked.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_mutex_double_destroy.stderr b/tests/fail/sync/libc_pthread_mutex_double_destroy.stderr index 9df2dd32b804..274d4496266b 100644 --- a/tests/fail/sync/libc_pthread_mutex_double_destroy.stderr +++ b/tests/fail/sync/libc_pthread_mutex_double_destroy.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_mutex_destroy(mutex.as_mut_ptr()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/libc_pthread_mutex_double_destroy.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr index b0858374cd9f..daa9a7c51448 100644 --- a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr +++ b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_mutex_unlock(&mut mutex as *mut _); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/libc_pthread_mutex_normal_unlock_unlocked.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr b/tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr index 86d02c22819e..83c22b2673d6 100644 --- a/tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr +++ b/tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr @@ -6,7 +6,7 @@ LL | ...t_eq!(libc::pthread_mutex_unlock(lock_copy.0.get() as *mut _), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/libc_pthread_mutex_wrong_owner.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_mutexattr_double_destroy.stderr b/tests/fail/sync/libc_pthread_mutexattr_double_destroy.stderr index 21adfa61d115..44a201fe0583 100644 --- a/tests/fail/sync/libc_pthread_mutexattr_double_destroy.stderr +++ b/tests/fail/sync/libc_pthread_mutexattr_double_destroy.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/libc_pthread_mutexattr_double_destroy.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.stderr b/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.stderr index 80a88a773e5c..43f8b2dcca6f 100644 --- a/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.stderr +++ b/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_rwlock_destroy(rw.get()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/libc_pthread_rwlock_destroy_read_locked.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.stderr b/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.stderr index 0fd49a63306c..cbaa2b3fcce9 100644 --- a/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.stderr +++ b/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_rwlock_destroy(rw.get()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/libc_pthread_rwlock_destroy_write_locked.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_rwlock_double_destroy.stderr b/tests/fail/sync/libc_pthread_rwlock_double_destroy.stderr index d60afc67c85b..159e1b9881a9 100644 --- a/tests/fail/sync/libc_pthread_rwlock_double_destroy.stderr +++ b/tests/fail/sync/libc_pthread_rwlock_double_destroy.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_rwlock_destroy(&mut lock); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/libc_pthread_rwlock_double_destroy.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr b/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr index c7c8823eaa37..0921f3d4b506 100644 --- a/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr +++ b/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr @@ -6,7 +6,7 @@ LL | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/libc_pthread_rwlock_read_wrong_owner.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.stderr b/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.stderr index f8454d05587f..67bfde22edcf 100644 --- a/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.stderr +++ b/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_rwlock_unlock(rw.get()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/libc_pthread_rwlock_unlock_unlocked.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr b/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr index a7a17ae71b3a..d066cb687a1a 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr +++ b/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr @@ -6,7 +6,7 @@ LL | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/libc_pthread_rwlock_write_wrong_owner.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/transmute-pair-uninit.stderr b/tests/fail/transmute-pair-uninit.stderr index c1f90c3efb6e..ac6bf8243eee 100644 --- a/tests/fail/transmute-pair-uninit.stderr +++ b/tests/fail/transmute-pair-uninit.stderr @@ -6,7 +6,7 @@ LL | let v = unsafe { *z.offset(first_undef) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/transmute-pair-uninit.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/transmute_fat1.stderr b/tests/fail/transmute_fat1.stderr index 6263427bac5b..a2dcffb255fe 100644 --- a/tests/fail/transmute_fat1.stderr +++ b/tests/fail/transmute_fat1.stderr @@ -6,7 +6,7 @@ LL | std::mem::transmute::<&[u8], [u8; N]>(&[1u8]) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/transmute_fat1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/alignment.stderr b/tests/fail/unaligned_pointers/alignment.stderr index 5f691d049095..f3bd7ca27571 100644 --- a/tests/fail/unaligned_pointers/alignment.stderr +++ b/tests/fail/unaligned_pointers/alignment.stderr @@ -6,7 +6,7 @@ LL | *(x_ptr as *mut u32) = 42; *(x_ptr.add(1) as *mut u32) = 42; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/alignment.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/atomic_unaligned.stderr b/tests/fail/unaligned_pointers/atomic_unaligned.stderr index e3b7f4cdbc9a..bde4ff615c29 100644 --- a/tests/fail/unaligned_pointers/atomic_unaligned.stderr +++ b/tests/fail/unaligned_pointers/atomic_unaligned.stderr @@ -6,7 +6,7 @@ LL | ::std::intrinsics::atomic_load_seqcst(zptr); | = help: this usually indicates that your program performed an invalid operation and caused Undefined Behavior = help: but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives - + = note: backtrace: = note: inside `main` at $DIR/atomic_unaligned.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/dyn_alignment.stderr b/tests/fail/unaligned_pointers/dyn_alignment.stderr index 6c64f0e365e7..930ec994d002 100644 --- a/tests/fail/unaligned_pointers/dyn_alignment.stderr +++ b/tests/fail/unaligned_pointers/dyn_alignment.stderr @@ -6,7 +6,7 @@ LL | let _ptr = &*ptr; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/dyn_alignment.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr b/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr index 347486187e1b..963fa81b655c 100644 --- a/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr +++ b/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr @@ -6,7 +6,7 @@ LL | unsafe { *u16_ptr = 2 }; | = help: this usually indicates that your program performed an invalid operation and caused Undefined Behavior = help: but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives - + = note: backtrace: = note: inside `main` at $DIR/intptrcast_alignment_check.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/reference_to_packed.stderr b/tests/fail/unaligned_pointers/reference_to_packed.stderr index 3dbc47f71d7b..ce667c1e8dec 100644 --- a/tests/fail/unaligned_pointers/reference_to_packed.stderr +++ b/tests/fail/unaligned_pointers/reference_to_packed.stderr @@ -6,7 +6,7 @@ LL | let i = *p; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/reference_to_packed.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/unaligned_ptr1.stderr b/tests/fail/unaligned_pointers/unaligned_ptr1.stderr index afc458e9ccb1..c557ebb11f67 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr1.stderr +++ b/tests/fail/unaligned_pointers/unaligned_ptr1.stderr @@ -6,7 +6,7 @@ LL | let _x = unsafe { *x }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/unaligned_ptr1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/unaligned_ptr2.stderr b/tests/fail/unaligned_pointers/unaligned_ptr2.stderr index ac1ef5c38121..5bff91621317 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr2.stderr +++ b/tests/fail/unaligned_pointers/unaligned_ptr2.stderr @@ -6,7 +6,7 @@ LL | let _x = unsafe { *x }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/unaligned_ptr2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/unaligned_ptr3.stderr b/tests/fail/unaligned_pointers/unaligned_ptr3.stderr index 7075bb4c7b4b..f887f38bec53 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr3.stderr +++ b/tests/fail/unaligned_pointers/unaligned_ptr3.stderr @@ -6,7 +6,7 @@ LL | let _x = unsafe { *x }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/unaligned_ptr3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/unaligned_ptr4.stderr b/tests/fail/unaligned_pointers/unaligned_ptr4.stderr index e72f28682fd7..f2fe961eb6a1 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr4.stderr +++ b/tests/fail/unaligned_pointers/unaligned_ptr4.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { *ptr }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/unaligned_ptr4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.stderr b/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.stderr index 31f9163b3cf0..157eb68b50d8 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.stderr +++ b/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.stderr @@ -6,7 +6,7 @@ LL | let _x = unsafe { ptr::addr_of!(*x) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at RUSTLIB/core/src/ptr/mod.rs:LL:CC = note: this error originates in the macro `ptr::addr_of` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr b/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr index 7ee9a949cc71..da53e922b7a9 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr +++ b/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr @@ -6,7 +6,7 @@ LL | let _x = unsafe { *x }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/unaligned_ptr_zst.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/uninit_buffer.stderr b/tests/fail/uninit_buffer.stderr index 02e4bcb90be6..e684ca8f0771 100644 --- a/tests/fail/uninit_buffer.stderr +++ b/tests/fail/uninit_buffer.stderr @@ -6,7 +6,7 @@ LL | let mut order = unsafe { memcmp(left.as_ptr(), right.as_ptr(), len) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `::compare` at RUSTLIB/core/src/slice/cmp.rs:LL:CC = note: inside `core::slice::cmp::::cmp` at RUSTLIB/core/src/slice/cmp.rs:LL:CC note: inside `main` at $DIR/uninit_buffer.rs:LL:CC diff --git a/tests/fail/uninit_byte_read.stderr b/tests/fail/uninit_byte_read.stderr index d15b10dc6ed0..174d0d2416e3 100644 --- a/tests/fail/uninit_byte_read.stderr +++ b/tests/fail/uninit_byte_read.stderr @@ -6,7 +6,7 @@ LL | let undef = unsafe { *v.get_unchecked(5) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/uninit_byte_read.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/uninit_raw_ptr.stderr b/tests/fail/uninit_raw_ptr.stderr index c76f59e13e7f..7241cf04ae4a 100644 --- a/tests/fail/uninit_raw_ptr.stderr +++ b/tests/fail/uninit_raw_ptr.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { std::mem::MaybeUninit::<*const u8>::uninit().assume | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/uninit_raw_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unreachable.stderr b/tests/fail/unreachable.stderr index 1cad7dd901b7..e9eb3649dea4 100644 --- a/tests/fail/unreachable.stderr +++ b/tests/fail/unreachable.stderr @@ -6,7 +6,7 @@ LL | unsafe { intrinsics::unreachable() } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::hint::unreachable_unchecked` at RUSTLIB/core/src/hint.rs:LL:CC note: inside `main` at $DIR/unreachable.rs:LL:CC --> $DIR/unreachable.rs:LL:CC diff --git a/tests/fail/unsupported_foreign_function.stderr b/tests/fail/unsupported_foreign_function.stderr index b8b1925d2ccc..3298f57dd51e 100644 --- a/tests/fail/unsupported_foreign_function.stderr +++ b/tests/fail/unsupported_foreign_function.stderr @@ -5,7 +5,7 @@ LL | foo(); | ^^^^^ can't call foreign function: foo | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside `main` at $DIR/unsupported_foreign_function.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unsupported_signal.stderr b/tests/fail/unsupported_signal.stderr index 8fcbc7fb4739..622b1876e0f8 100644 --- a/tests/fail/unsupported_signal.stderr +++ b/tests/fail/unsupported_signal.stderr @@ -5,7 +5,7 @@ LL | libc::signal(libc::SIGPIPE, libc::SIG_IGN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't call foreign function: signal | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside `main` at $DIR/unsupported_signal.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/cast_fn_ptr1.stderr b/tests/fail/validity/cast_fn_ptr1.stderr index 05c75ac13386..6ac10b10a003 100644 --- a/tests/fail/validity/cast_fn_ptr1.stderr +++ b/tests/fail/validity/cast_fn_ptr1.stderr @@ -6,7 +6,7 @@ LL | g(0usize as *const i32) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/cast_fn_ptr1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/cast_fn_ptr2.stderr b/tests/fail/validity/cast_fn_ptr2.stderr index 8bee099caf3b..cd73237c867f 100644 --- a/tests/fail/validity/cast_fn_ptr2.stderr +++ b/tests/fail/validity/cast_fn_ptr2.stderr @@ -6,7 +6,7 @@ LL | let _x = g(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/cast_fn_ptr2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/dangling_ref1.stderr b/tests/fail/validity/dangling_ref1.stderr index 290963c6d4ee..52e1ae2acb85 100644 --- a/tests/fail/validity/dangling_ref1.stderr +++ b/tests/fail/validity/dangling_ref1.stderr @@ -6,7 +6,7 @@ LL | let _x: &i32 = unsafe { mem::transmute(16usize) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/dangling_ref1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/dangling_ref2.stderr b/tests/fail/validity/dangling_ref2.stderr index ce60f973ffe8..f9d0ad5515c8 100644 --- a/tests/fail/validity/dangling_ref2.stderr +++ b/tests/fail/validity/dangling_ref2.stderr @@ -6,7 +6,7 @@ LL | let _x: &i32 = unsafe { mem::transmute(ptr) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/dangling_ref2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/dangling_ref3.stderr b/tests/fail/validity/dangling_ref3.stderr index aa25f1656086..37b8d6bce6e8 100644 --- a/tests/fail/validity/dangling_ref3.stderr +++ b/tests/fail/validity/dangling_ref3.stderr @@ -6,7 +6,7 @@ LL | let _x: &i32 = unsafe { mem::transmute(dangling()) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/dangling_ref3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_bool.stderr b/tests/fail/validity/invalid_bool.stderr index 756c094d6e86..31575a439b5b 100644 --- a/tests/fail/validity/invalid_bool.stderr +++ b/tests/fail/validity/invalid_bool.stderr @@ -6,7 +6,7 @@ LL | let _b = unsafe { std::mem::transmute::(2) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/invalid_bool.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_bool_uninit.stderr b/tests/fail/validity/invalid_bool_uninit.stderr index 5236cab450b6..a4f2d844fd26 100644 --- a/tests/fail/validity/invalid_bool_uninit.stderr +++ b/tests/fail/validity/invalid_bool_uninit.stderr @@ -6,7 +6,7 @@ LL | let _b = unsafe { MyUninit { init: () }.uninit }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/invalid_bool_uninit.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_char.stderr b/tests/fail/validity/invalid_char.stderr index 538af4aefcab..a64452041f6f 100644 --- a/tests/fail/validity/invalid_char.stderr +++ b/tests/fail/validity/invalid_char.stderr @@ -6,7 +6,7 @@ LL | let _val = match unsafe { std::mem::transmute::(-1) } { | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/invalid_char.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_char_uninit.stderr b/tests/fail/validity/invalid_char_uninit.stderr index 12bc0faa5135..10dff8423868 100644 --- a/tests/fail/validity/invalid_char_uninit.stderr +++ b/tests/fail/validity/invalid_char_uninit.stderr @@ -6,7 +6,7 @@ LL | let _b = unsafe { MyUninit { init: () }.uninit }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/invalid_char_uninit.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_enum_tag.stderr b/tests/fail/validity/invalid_enum_tag.stderr index c7014ae71ac2..e6a484d7bde3 100644 --- a/tests/fail/validity/invalid_enum_tag.stderr +++ b/tests/fail/validity/invalid_enum_tag.stderr @@ -6,7 +6,7 @@ LL | let _f = unsafe { std::mem::transmute::(42) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/invalid_enum_tag.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr b/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr index c9fd312a96ce..c3ebf462b6d7 100644 --- a/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr +++ b/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr @@ -7,7 +7,7 @@ LL | let _a = unsafe { MyUninit { init: () }.uninit }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/invalid_enum_tag_256variants_uninit.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_fnptr_null.stderr b/tests/fail/validity/invalid_fnptr_null.stderr index 13e8957e615f..6c744f204445 100644 --- a/tests/fail/validity/invalid_fnptr_null.stderr +++ b/tests/fail/validity/invalid_fnptr_null.stderr @@ -6,7 +6,7 @@ LL | let _b: fn() = unsafe { std::mem::transmute(0usize) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/invalid_fnptr_null.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_fnptr_uninit.stderr b/tests/fail/validity/invalid_fnptr_uninit.stderr index b64655fa8189..55307f6b98d1 100644 --- a/tests/fail/validity/invalid_fnptr_uninit.stderr +++ b/tests/fail/validity/invalid_fnptr_uninit.stderr @@ -6,7 +6,7 @@ LL | let _b = unsafe { MyUninit { init: () }.uninit }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/invalid_fnptr_uninit.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_wide_raw.stderr b/tests/fail/validity/invalid_wide_raw.stderr index 633f8f8adbc2..624b9764c9e1 100644 --- a/tests/fail/validity/invalid_wide_raw.stderr +++ b/tests/fail/validity/invalid_wide_raw.stderr @@ -6,7 +6,7 @@ LL | dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/invalid_wide_raw.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/nonzero.stderr b/tests/fail/validity/nonzero.stderr index 0c6a24172307..05b08d99d36d 100644 --- a/tests/fail/validity/nonzero.stderr +++ b/tests/fail/validity/nonzero.stderr @@ -6,7 +6,7 @@ LL | let _x = Some(unsafe { NonZero(0) }); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/nonzero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/ptr_integer_array_transmute.stderr b/tests/fail/validity/ptr_integer_array_transmute.stderr index 39b4ebfc8f13..43eedb70fe65 100644 --- a/tests/fail/validity/ptr_integer_array_transmute.stderr +++ b/tests/fail/validity/ptr_integer_array_transmute.stderr @@ -6,7 +6,7 @@ LL | let _i: [usize; 1] = unsafe { std::mem::transmute(r) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/ptr_integer_array_transmute.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/ref_to_uninhabited1.stderr b/tests/fail/validity/ref_to_uninhabited1.stderr index 526b6a4dc251..ae606d0a8013 100644 --- a/tests/fail/validity/ref_to_uninhabited1.stderr +++ b/tests/fail/validity/ref_to_uninhabited1.stderr @@ -6,7 +6,7 @@ LL | let x: Box = transmute(&mut 42); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/ref_to_uninhabited1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/ref_to_uninhabited2.stderr b/tests/fail/validity/ref_to_uninhabited2.stderr index 297b0540ab01..3db040eeda10 100644 --- a/tests/fail/validity/ref_to_uninhabited2.stderr +++ b/tests/fail/validity/ref_to_uninhabited2.stderr @@ -6,7 +6,7 @@ LL | let _x: &(i32, Void) = transmute(&42); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/ref_to_uninhabited2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/too-big-slice.stderr b/tests/fail/validity/too-big-slice.stderr index 52077f16a1c8..591dc6d7b5c2 100644 --- a/tests/fail/validity/too-big-slice.stderr +++ b/tests/fail/validity/too-big-slice.stderr @@ -6,7 +6,7 @@ LL | let _x: &[u8] = mem::transmute((ptr, usize::MAX)); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/too-big-slice.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/too-big-unsized.stderr b/tests/fail/validity/too-big-unsized.stderr index a20f1de6d57d..3b8b9f50cf87 100644 --- a/tests/fail/validity/too-big-unsized.stderr +++ b/tests/fail/validity/too-big-unsized.stderr @@ -6,7 +6,7 @@ LL | let _x: &MySlice = mem::transmute((ptr, isize::MAX as usize)); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/too-big-unsized.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/transmute_through_ptr.stderr b/tests/fail/validity/transmute_through_ptr.stderr index 50f699d7f9b5..bf79e8649d01 100644 --- a/tests/fail/validity/transmute_through_ptr.stderr +++ b/tests/fail/validity/transmute_through_ptr.stderr @@ -6,7 +6,7 @@ LL | let y = x; // reading this ought to be enough to trigger validation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/transmute_through_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/uninit_float.stderr b/tests/fail/validity/uninit_float.stderr index 946897bd4ea6..2fe27c904329 100644 --- a/tests/fail/validity/uninit_float.stderr +++ b/tests/fail/validity/uninit_float.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init( | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/uninit_float.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/uninit_integer.stderr b/tests/fail/validity/uninit_integer.stderr index 7e9d38a4b7bb..c461fc5afaa3 100644 --- a/tests/fail/validity/uninit_integer.stderr +++ b/tests/fail/validity/uninit_integer.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_ini | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/uninit_integer.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/uninit_integer_signed.stderr b/tests/fail/validity/uninit_integer_signed.stderr index bd8ea42c3a43..c53c96c596e4 100644 --- a/tests/fail/validity/uninit_integer_signed.stderr +++ b/tests/fail/validity/uninit_integer_signed.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init( | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/uninit_integer_signed.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/weak_memory/racing_mixed_size.stderr b/tests/fail/weak_memory/racing_mixed_size.stderr index 0fb23be06bb7..4c53828a6ce6 100644 --- a/tests/fail/weak_memory/racing_mixed_size.stderr +++ b/tests/fail/weak_memory/racing_mixed_size.stderr @@ -5,7 +5,7 @@ LL | std::intrinsics::atomic_load_relaxed(hi); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside closure at $DIR/racing_mixed_size.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/weak_memory/racing_mixed_size_read.stderr b/tests/fail/weak_memory/racing_mixed_size_read.stderr index 6de185161084..9988f4a86d42 100644 --- a/tests/fail/weak_memory/racing_mixed_size_read.stderr +++ b/tests/fail/weak_memory/racing_mixed_size_read.stderr @@ -5,7 +5,7 @@ LL | std::intrinsics::atomic_load_relaxed(hi); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside closure at $DIR/racing_mixed_size_read.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/zst1.stderr b/tests/fail/zst1.stderr index ba13c9d7e52a..eeb2429d4c6f 100644 --- a/tests/fail/zst1.stderr +++ b/tests/fail/zst1.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { *x }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/zst1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/zst2.stderr b/tests/fail/zst2.stderr index 3112a87489a9..8687e8636bfe 100644 --- a/tests/fail/zst2.stderr +++ b/tests/fail/zst2.stderr @@ -6,7 +6,7 @@ LL | unsafe { *x = zst_val }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/zst2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/zst3.stderr b/tests/fail/zst3.stderr index bc3436b14ac0..43233d4d2afd 100644 --- a/tests/fail/zst3.stderr +++ b/tests/fail/zst3.stderr @@ -6,7 +6,7 @@ LL | unsafe { *(x as *mut [u8; 0]) = zst_val }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/zst3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/pass/box.stderr b/tests/pass/box.stderr index 41c752d5d0fc..2c2534fa2b05 100644 --- a/tests/pass/box.stderr +++ b/tests/pass/box.stderr @@ -10,7 +10,7 @@ LL | let r2 = ((r as usize) + 0) as *mut i32; = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead. = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics. = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning. - + = note: backtrace: = note: inside `into_raw` at $DIR/box.rs:LL:CC note: inside `main` at $DIR/box.rs:LL:CC --> $DIR/box.rs:LL:CC diff --git a/tests/pass/extern_types.stderr b/tests/pass/extern_types.stderr index 3a4acec5ddb9..fcb04d951d16 100644 --- a/tests/pass/extern_types.stderr +++ b/tests/pass/extern_types.stderr @@ -10,6 +10,6 @@ LL | let x: &Foo = unsafe { &*(16 as *const Foo) }; = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead. = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics. = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning. - + = note: backtrace: = note: inside `main` at $DIR/extern_types.rs:LL:CC From 7cdbf98f57ed767342f8f9d192f21cfd75ef2a75 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 2 Jul 2022 13:22:22 -0400 Subject: [PATCH 3422/5092] Explain the behavior of the cache upon clear --- src/stacked_borrows/stack.rs | 19 ++++++++++++++----- ui_test/Cargo.toml | 4 ---- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/stacked_borrows/stack.rs b/src/stacked_borrows/stack.rs index 6e0d166086fc..5ad9b5dc5353 100644 --- a/src/stacked_borrows/stack.rs +++ b/src/stacked_borrows/stack.rs @@ -53,7 +53,7 @@ struct StackCache { impl StackCache { /// When a tag is used, we call this function to add or refresh it in the cache. /// - /// We use position in the cache to represent how recently a tag was used; the first position + /// We use the position in the cache to represent how recently a tag was used; the first position /// is the most recently used tag. So an add shifts every element towards the end, and inserts /// the new element at the start. We lose the last element. /// This strategy is effective at keeping the most-accessed tags in the cache, but it costs a @@ -104,7 +104,7 @@ impl<'tcx> Stack { /// index is given it means the match was *not* in the known part of the stack. /// `Ok(None)` indicates it matched the "unknown" part of the stack. /// `Err` indicates it was not found. - pub fn find_granting( + pub(super) fn find_granting( &mut self, access: AccessKind, tag: SbTagExtra, @@ -167,9 +167,15 @@ impl<'tcx> Stack { #[cfg(feature = "stack-cache")] fn find_granting_cache(&mut self, access: AccessKind, tag: SbTag) -> Option { - // When the borrow stack is empty, there are no tags we could put into the cache that would - // be valid. Additionally, since lookups into the cache are a linear search it doesn't make - // sense to use the cache when it is no smaller than a search of the borrow stack itself. + // This looks like a common-sense optimization; we're going to do a linear search of the + // cache or the borrow stack to scan the shorter of the two. This optimization is miniscule + // and this check actually ensures we do not access an invalid cache. + // When a stack is created and when tags are removed from the top of the borrow stack, we + // need some valid value to populate the cache. In both cases, we try to use the bottom + // item. But when the stack is cleared in `set_unknown_bottom` there is nothing we could + // place in the cache that is correct. But due to the way we populate the cache in + // `StackCache::add`, we know that when the borrow stack has grown larger than the cache, + // every slot in the cache is valid. if self.borrows.len() <= CACHE_LEN { return None; } @@ -261,6 +267,9 @@ impl<'tcx> Stack { } pub fn set_unknown_bottom(&mut self, tag: SbTag) { + // We clear the borrow stack but the lookup cache doesn't support clearing per se. Instead, + // there is a check explained in `find_granting_cache` which protects against accessing the + // cache when it has been cleared and not yet refilled. self.borrows.clear(); self.unknown_bottom = Some(tag); } diff --git a/ui_test/Cargo.toml b/ui_test/Cargo.toml index 0838733db2de..92c00915cbfe 100644 --- a/ui_test/Cargo.toml +++ b/ui_test/Cargo.toml @@ -14,7 +14,3 @@ crossbeam = "0.8.1" lazy_static = "1.4.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" - -[features] -# Doesn't do anything, but the miri script wants to pass the same flags to ui_test and miri itself -expensive-debug-assertions = [] From b4520e459159781966d678cc0f65c8d295f523e4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Jul 2022 12:26:00 -0400 Subject: [PATCH 3423/5092] test fs::read_link surface function --- tests/pass/fs.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/pass/fs.rs b/tests/pass/fs.rs index bc78cb560f00..e106ca5d02bb 100644 --- a/tests/pass/fs.rs +++ b/tests/pass/fs.rs @@ -8,7 +8,8 @@ extern crate libc; use std::ffi::CString; use std::fs::{ - create_dir, read_dir, remove_dir, remove_dir_all, remove_file, rename, File, OpenOptions, + create_dir, read_dir, read_link, remove_dir, remove_dir_all, remove_file, rename, File, + OpenOptions, }; use std::io::{Error, ErrorKind, Read, Result, Seek, SeekFrom, Write}; use std::path::{Path, PathBuf}; @@ -317,10 +318,12 @@ fn test_symlink() { assert_eq!(Error::last_os_error().kind(), ErrorKind::NotFound); } - // Test that metadata of a symbolic link is correct. + // Test that metadata of a symbolic link (i.e., the file it points to) is correct. check_metadata(bytes, &symlink_path).unwrap(); // Test that the metadata of a symbolic link is correct when not following it. assert!(symlink_path.symlink_metadata().unwrap().file_type().is_symlink()); + // Check that we can follow the link. + assert_eq!(read_link(&symlink_path).unwrap(), path); // Removing symbolic link should succeed. remove_file(&symlink_path).unwrap(); From 733b141789743f71a7fb1dc8f448a94f771d0849 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Jul 2022 16:06:23 -0400 Subject: [PATCH 3424/5092] ./miri many-seeds: also print the seed before we try it --- miri | 1 + 1 file changed, 1 insertion(+) diff --git a/miri b/miri index 349cf818fb2a..56e3f3034819 100755 --- a/miri +++ b/miri @@ -55,6 +55,7 @@ COMMAND="$1" case "$COMMAND" in many-seeds) for SEED in $({ echo obase=16; seq 0 255; } | bc); do + echo "Trying seed: $SEED" MIRIFLAGS="$MIRIFLAGS -Zmiri-seed=$SEED" $@ || { echo "Failing seed: $SEED"; break; } done exit 0 From d9c441c5abfbe9052a2d682c1ae644513a68b767 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Jul 2022 18:33:03 -0400 Subject: [PATCH 3425/5092] put call to stacked borrows end_call in a more sensible place --- src/machine.rs | 5 ++++- src/shims/panic.rs | 8 ++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 1b7fc4ffb963..716d4bd5b90c 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -930,7 +930,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { unwinding: bool, ) -> InterpResult<'tcx, StackPopJump> { let timing = frame.extra.timing.take(); - let res = ecx.handle_stack_pop(frame.extra, unwinding); + if let Some(stacked_borrows) = &ecx.machine.stacked_borrows { + stacked_borrows.borrow_mut().end_call(frame.extra.call_id); + } + let res = ecx.handle_stack_pop_unwind(frame.extra, unwinding); if let Some(profiler) = ecx.machine.profiler.as_ref() { profiler.finish_recording_interval_event(timing.unwrap()); } diff --git a/src/shims/panic.rs b/src/shims/panic.rs index ed6e72591dd0..2ef0a741d52f 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -115,17 +115,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - fn handle_stack_pop( + fn handle_stack_pop_unwind( &mut self, mut extra: FrameData<'tcx>, unwinding: bool, ) -> InterpResult<'tcx, StackPopJump> { let this = self.eval_context_mut(); - - trace!("handle_stack_pop(extra = {:?}, unwinding = {})", extra, unwinding); - if let Some(stacked_borrows) = &this.machine.stacked_borrows { - stacked_borrows.borrow_mut().end_call(extra.call_id); - } + trace!("handle_stack_pop_unwind(extra = {:?}, unwinding = {})", extra, unwinding); // We only care about `catch_panic` if we're unwinding - if we're doing a normal // return, then we don't need to do anything special. From dcdf4fb6f62245200031fa8f84c19e188e8363df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Jul 2022 18:36:34 -0400 Subject: [PATCH 3426/5092] readme tweaks --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 32cbc4f1e458..4681a3d38214 100644 --- a/README.md +++ b/README.md @@ -65,9 +65,9 @@ in your program, and cannot run all programs: not support networking. System API support varies between targets; if you run on Windows it is a good idea to use `--target x86_64-unknown-linux-gnu` to get better support. -* Weak memory emulation may produce weak behaivours unobservable by compiled - programs running on real hardware when `SeqCst` fences are used, and it cannot - produce all behaviors possibly observable on real hardware. +* Weak memory emulation may [produce weak behaivours](https://github.com/rust-lang/miri/issues/2301) + unobservable by compiled programs running on real hardware when `SeqCst` fences are used, and it + cannot produce all behaviors possibly observable on real hardware. [rust]: https://www.rust-lang.org/ [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md @@ -192,8 +192,9 @@ randomness that is used to determine allocation base addresses. The following snippet calls Miri in a loop with different values for the seed: ``` -for seed in $({ echo obase=16; seq 0 255; } | bc); do - MIRIFLAGS=-Zmiri-seed=$seed cargo miri test || { echo "Last seed: $seed"; break; }; +for SEED in $({ echo obase=16; seq 0 255; } | bc); do + echo "Trying seed: $SEED" + MIRIFLAGS=-Zmiri-seed=$SEED cargo miri test || { echo "Failing seed: $SEED"; break; }; done ``` From f3b479d5569fa013020db1d940aeb38dadc9060b Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 2 Jul 2022 19:44:55 -0400 Subject: [PATCH 3427/5092] Explain cache behavior a bit better, clean up diff --- Cargo.toml | 1 + src/lib.rs | 4 ++-- src/stacked_borrows.rs | 10 +++------- src/stacked_borrows/stack.rs | 22 +++++++++++++++------- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0dead9fa28f7..f612e7a3e9e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,5 +53,6 @@ harness = false [features] default = ["stack-cache"] +# Will be enabled on CI via `--all-features`. expensive-debug-assertions = [] stack-cache = [] diff --git a/src/lib.rs b/src/lib.rs index a98239711ef4..269980ede379 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -90,8 +90,8 @@ pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ - stack::Stack, CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, - SbTag, SbTagExtra, Stacks, + stack::Stack, CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag, + SbTagExtra, Stacks, }; pub use crate::sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId}; pub use crate::thread::{ diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 3a4b4ad65fa1..01d67fcf59e0 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -26,7 +26,6 @@ use diagnostics::{AllocHistory, TagHistory}; pub mod stack; use stack::Stack; -pub type PtrId = NonZeroU64; pub type CallId = NonZeroU64; // Even reading memory can have effects on the stack, so we need a `RefCell` here. @@ -479,7 +478,7 @@ impl<'tcx> Stack { ) })?; - // Step 2: Remove all items. Also checks for protectors. + // Step 2: Consider all items removed. This checks for protectors. for idx in (0..self.len()).rev() { let item = self.get(idx).unwrap(); Stack::item_popped(&item, None, global, alloc_history)?; @@ -579,8 +578,8 @@ impl<'tcx> Stacks { /// Creates new stack with initial tag. fn new(size: Size, perm: Permission, tag: SbTag) -> Self { let item = Item { perm, tag, protector: None }; - let stack = Stack::new(item); + Stacks { stacks: RangeMap::new(size, stack), history: AllocHistory::new(), @@ -826,14 +825,11 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We have to use shared references to alloc/memory_extra here since // `visit_freeze_sensitive` needs to access the global state. let extra = this.get_alloc_extra(alloc_id)?; - let mut stacked_borrows = extra .stacked_borrows .as_ref() .expect("we should have Stacked Borrows data") .borrow_mut(); - let mut current_span = this.machine.current_span(); - this.visit_freeze_sensitive(place, size, |mut range, frozen| { // Adjust range. range.start += base_offset; @@ -858,7 +854,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx item, (alloc_id, range, offset), &mut global, - &mut current_span, + current_span, history, exposed_tags, ) diff --git a/src/stacked_borrows/stack.rs b/src/stacked_borrows/stack.rs index 5ad9b5dc5353..1c3ee0fd573a 100644 --- a/src/stacked_borrows/stack.rs +++ b/src/stacked_borrows/stack.rs @@ -27,8 +27,7 @@ pub struct Stack { /// we never have the unknown-to-known boundary in an SRW group. unknown_bottom: Option, - /// A small LRU cache of searches of the borrow stack. This only caches accesses of `Tagged`, - /// because those are unique in the stack. + /// A small LRU cache of searches of the borrow stack. #[cfg(feature = "stack-cache")] cache: StackCache, /// On a read, we need to disable all `Unique` above the granting item. We can avoid most of @@ -42,6 +41,11 @@ pub struct Stack { /// probably-cold random access into the borrow stack to figure out what `Permission` an /// `SbTag` grants. We could avoid this by also storing the `Permission` in the cache, but /// most lookups into the cache are immediately followed by access of the full borrow stack anyway. +/// +/// It may seem like maintaining this cache is a waste for small stacks, but +/// (a) iterating over small fixed-size arrays is super fast, and (b) empirically this helps *a lot*, +/// probably because runtime is dominated by large stacks. +/// arrays is super fast #[cfg(feature = "stack-cache")] #[derive(Clone, Debug)] struct StackCache { @@ -81,7 +85,9 @@ impl<'tcx> Stack { /// - There are no Unique tags outside of first_unique..last_unique #[cfg(feature = "expensive-debug-assertions")] fn verify_cache_consistency(&self) { - if self.borrows.len() > CACHE_LEN { + // Only a full cache needs to be valid. Also see the comments in find_granting_cache + // and set_unknown_bottom. + if self.borrows.len() >= CACHE_LEN { for (tag, stack_idx) in self.cache.tags.iter().zip(self.cache.idx.iter()) { assert_eq!(self.borrows[*stack_idx].tag, *tag); } @@ -154,7 +160,7 @@ impl<'tcx> Stack { } // If we didn't find the tag in the cache, fall back to a linear search of the - // whole stack, and add the tag to the stack. + // whole stack, and add the tag to the cache. for (stack_idx, item) in self.borrows.iter().enumerate().rev() { if tag == item.tag && item.perm.grants(access) { #[cfg(feature = "stack-cache")] @@ -185,8 +191,11 @@ impl<'tcx> Stack { // If we found the tag, look up its position in the stack to see if it grants // the required permission if self.borrows[stack_idx].perm.grants(access) { - // If it does, and it's not already in the most-recently-used position, move it there. - // Except if the tag is in position 1, this is equivalent to just a swap, so do that. + // If it does, and it's not already in the most-recently-used position, re-insert it at + // the most-recently-used position. This technically reduces the efficiency of the + // cache by duplicating elements, but current benchmarks do not seem to benefit from + // avoiding this duplication. + // But if the tag is in position 1, avoiding the duplicating add is trivial. if cache_idx == 1 { self.cache.tags.swap(0, 1); self.cache.idx.swap(0, 1); @@ -287,7 +296,6 @@ impl<'tcx> Stack { let unique_range = 0..self.len(); if disable_start <= unique_range.end { - // add 1 so we don't disable the granting item let lower = unique_range.start.max(disable_start); let upper = (unique_range.end + 1).min(self.borrows.len()); for item in &mut self.borrows[lower..upper] { From b004a03bdb6affd7b07322114967bd1693208a69 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 2 Jul 2022 20:45:27 -0400 Subject: [PATCH 3428/5092] Typo --- src/stacked_borrows/stack.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/stacked_borrows/stack.rs b/src/stacked_borrows/stack.rs index 1c3ee0fd573a..ccdd85eafd8e 100644 --- a/src/stacked_borrows/stack.rs +++ b/src/stacked_borrows/stack.rs @@ -45,7 +45,6 @@ pub struct Stack { /// It may seem like maintaining this cache is a waste for small stacks, but /// (a) iterating over small fixed-size arrays is super fast, and (b) empirically this helps *a lot*, /// probably because runtime is dominated by large stacks. -/// arrays is super fast #[cfg(feature = "stack-cache")] #[derive(Clone, Debug)] struct StackCache { From 672d721544f4793a20f8c9565bb0808e9991694d Mon Sep 17 00:00:00 2001 From: DQ Date: Sun, 3 Jul 2022 11:32:36 +0200 Subject: [PATCH 3429/5092] Clarify `-Zmiri-track-pointer-tag` to explicitly say it also tracks tag creation --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4681a3d38214..dc297115fa1b 100644 --- a/README.md +++ b/README.md @@ -383,8 +383,8 @@ to Miri failing to detect cases of undefined behavior in a program. Borrows "protectors". Specifying this argument multiple times does not overwrite the previous values, instead it appends its values to the list. Listing an id multiple times has no effect. * `-Zmiri-track-pointer-tag=,,...` shows a backtrace when a given pointer tag - is popped from a borrow stack (which is where the tag becomes invalid and any - future use of it will error). This helps you in finding out why UB is + is created or when it is popped from a borrow stack (which is where the tag becomes invalid + and any future use of it will error). This helps you in finding out why UB is happening and where in your code would be a good place to look for it. Specifying this argument multiple times does not overwrite the previous values, instead it appends its values to the list. Listing a tag multiple times has no effect. From 5f7bc9739b312391d808e2406422a49027f8d68d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Jul 2022 08:13:58 -0400 Subject: [PATCH 3430/5092] move arc_drop test to miri-test-libstd and make weak memory consistency test a bit faster again --- tests/pass/0concurrency_arc_drop.rs | 19 ------------------- tests/pass/0weak_memory_consistency.rs | 2 +- 2 files changed, 1 insertion(+), 20 deletions(-) delete mode 100644 tests/pass/0concurrency_arc_drop.rs diff --git a/tests/pass/0concurrency_arc_drop.rs b/tests/pass/0concurrency_arc_drop.rs deleted file mode 100644 index b5192cd42140..000000000000 --- a/tests/pass/0concurrency_arc_drop.rs +++ /dev/null @@ -1,19 +0,0 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -use std::sync::Arc; -use std::thread; - -/// Test for Arc::drop bug (https://github.com/rust-lang/rust/issues/55005) -fn main() { - // The bug seems to take up to 700 iterations to reproduce with most seeds (tested 0-9). - for _ in 0..700 { - let arc_1 = Arc::new(()); - let arc_2 = arc_1.clone(); - let thread = thread::spawn(|| drop(arc_2)); - let mut i = 0; - while i < 256 { - i += 1; - } - drop(arc_1); - thread.join().unwrap(); - } -} diff --git a/tests/pass/0weak_memory_consistency.rs b/tests/pass/0weak_memory_consistency.rs index d4680130e7fb..0f798d2b575e 100644 --- a/tests/pass/0weak_memory_consistency.rs +++ b/tests/pass/0weak_memory_consistency.rs @@ -217,7 +217,7 @@ fn test_single_thread() { } pub fn main() { - for _ in 0..75 { + for _ in 0..50 { test_single_thread(); test_mixed_access(); test_load_buffering_acq_rel(); From c6f44c1639e6c7ce5f84213649967d8542b51b3b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Jul 2022 08:18:03 -0400 Subject: [PATCH 3431/5092] another one for the trophy case --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 4681a3d38214..48bba6528609 100644 --- a/README.md +++ b/README.md @@ -581,6 +581,7 @@ Definite bugs found: * [`integer-encoding` dereferencing a misaligned pointer](https://github.com/dermesser/integer-encoding-rs/pull/23) * [`rkyv` constructing a `Box<[u8]>` from an overaligned allocation](https://github.com/rkyv/rkyv/commit/a9417193a34757e12e24263178be8b2eebb72456) * [Data race in `thread::scope`](https://github.com/rust-lang/rust/issues/98498) +* [`regex` incorrectly handling unaligned `Vec` buffers](https://www.reddit.com/r/rust/comments/vq3mmu/comment/ienc7t0?context=3) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From e71f8b06304b639133b119829d4cb20b99536d89 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Jul 2022 08:35:44 -0400 Subject: [PATCH 3432/5092] fix ./miri run with MIRI_TEST_TARGET --- README.md | 6 +++--- miri | 24 ++++++++++++++---------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 48bba6528609..d831b4979b25 100644 --- a/README.md +++ b/README.md @@ -418,9 +418,9 @@ Moreover, Miri recognizes some environment variables: sysroot to use. Only set this if you do not want to use the automatically created sysroot. (The `miri` driver sysroot is controlled via the `--sysroot` flag instead.) -* `MIRI_TEST_TARGET` (recognized by the test suite) indicates which target - architecture to test against. `miri` and `cargo miri` accept the `--target` - flag for the same purpose. +* `MIRI_TEST_TARGET` (recognized by the test suite and the `./miri` script) indicates which target + architecture to test against. `miri` and `cargo miri` accept the `--target` flag for the same + purpose. * `MIRI_NO_STD` (recognized by `cargo miri` and the test suite) makes sure that the target's sysroot is built without libstd. This allows testing and running no_std programs. * `MIRI_BLESS` (recognized by the test suite) overwrite all `stderr` and `stdout` files diff --git a/miri b/miri index 56e3f3034819..da5634d6a95c 100755 --- a/miri +++ b/miri @@ -167,17 +167,21 @@ test|test-debug|bless|bless-debug) $CARGO test $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml "$@" ;; run|run-debug) - # Scan for "--target" to set the "MIRI_TEST_TARGET" env var so + # Scan for "--target" to overwrite the "MIRI_TEST_TARGET" env var so # that we set the MIRI_SYSROOT up the right way. - if [ -z "$MIRI_TEST_TARGET" ]; then - for ARG in "$@"; do - if [ "$LAST_ARG" = "--target" ]; then - # Found it! - export MIRI_TEST_TARGET="$ARG" - break - fi - LAST_ARG="$ARG" - done + FOUND_TARGET_OPT=0 + for ARG in "$@"; do + if [ "$LAST_ARG" = "--target" ]; then + # Found it! + export MIRI_TEST_TARGET="$ARG" + FOUND_TARGET_OPT=1 + break + fi + LAST_ARG="$ARG" + done + if [ "$FOUND_TARGET_OPT" = "0" ] && [ -n "$MIRI_TEST_TARGET" ]; then + # Make sure Miri actually uses this target. + MIRIFLAGS="$MIRIFLAGS --target $MIRI_TEST_TARGET" fi # First build and get a sysroot. $CARGO build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml From 1b9e19a39b8f884e4a85011d25641e8bc3480288 Mon Sep 17 00:00:00 2001 From: DQ Date: Sun, 3 Jul 2022 15:47:39 +0200 Subject: [PATCH 3433/5092] clarify that a (tracked) tag may never be popped Co-authored-by: Ralf Jung --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dc297115fa1b..787952b9d746 100644 --- a/README.md +++ b/README.md @@ -383,7 +383,7 @@ to Miri failing to detect cases of undefined behavior in a program. Borrows "protectors". Specifying this argument multiple times does not overwrite the previous values, instead it appends its values to the list. Listing an id multiple times has no effect. * `-Zmiri-track-pointer-tag=,,...` shows a backtrace when a given pointer tag - is created or when it is popped from a borrow stack (which is where the tag becomes invalid + is created and when (if ever) it is popped from a borrow stack (which is where the tag becomes invalid and any future use of it will error). This helps you in finding out why UB is happening and where in your code would be a good place to look for it. Specifying this argument multiple times does not overwrite the previous From 2fc92788181011a1995f055a3fac3296b3028574 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Jul 2022 10:45:39 -0400 Subject: [PATCH 3434/5092] no doctests in ui_test --- ui_test/Cargo.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ui_test/Cargo.toml b/ui_test/Cargo.toml index 92c00915cbfe..f221cc93fa71 100644 --- a/ui_test/Cargo.toml +++ b/ui_test/Cargo.toml @@ -3,7 +3,9 @@ name = "ui_test" version = "0.1.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +test = true # we have unit tests +doctest = false # but no doc tests [dependencies] rustc_version = "0.4" From a4e7e1e6b59e006d5b5599e2d6a181a77bf8ee04 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Jul 2022 11:54:47 -0400 Subject: [PATCH 3435/5092] fix retagging of vtable ptrs --- src/stacked_borrows.rs | 5 +++++ tests/pass/stacked-borrows/stacked-borrows.rs | 14 ++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 3fa001eabfd2..cc2ea0b76d87 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -1039,6 +1039,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val = self.ecx.read_immediate(&place.into())?; let val = self.ecx.retag_reference(&val, mutbl, protector)?; self.ecx.write_immediate(*val, &place.into())?; + } else if matches!(place.layout.ty.kind(), ty::RawPtr(..)) { + // Wide raw pointers *do* have fields and their types are strange. + // vtables have a type like `&[*const (); 3]` or so! + // Do *not* recurse into them. + // (No need to worry about wide references or boxes, those always "qualify".) } else { // Maybe we need to go deeper. self.walk_value(place)?; diff --git a/tests/pass/stacked-borrows/stacked-borrows.rs b/tests/pass/stacked-borrows/stacked-borrows.rs index 3669a08a1bc4..b915a2ddf8f6 100644 --- a/tests/pass/stacked-borrows/stacked-borrows.rs +++ b/tests/pass/stacked-borrows/stacked-borrows.rs @@ -1,4 +1,5 @@ // compile-flags: -Zmiri-retag-fields +#![feature(allocator_api)] use std::ptr; // Test various stacked-borrows-related things. @@ -17,6 +18,7 @@ fn main() { raw_ref_to_part(); array_casts(); mut_below_shr(); + wide_raw_ptr_in_tuple(); } // Make sure that reading from an `&mut` does, like reborrowing to `&`, @@ -205,3 +207,15 @@ fn mut_below_shr() { let r = &**p; let _val = *r; } + +fn wide_raw_ptr_in_tuple() { + let mut x: Box = Box::new("ouch"); + let r = &mut *x as *mut dyn std::any::Any; + // This triggers the visitor-based recursive retagging. It is *not* supposed to retag raw + // pointers, but then the visitor might recurse into the "fields" of a wide raw pointer and + // finds a reference (to a vtable) there that it wants to retag... and that would be Wrong. + let pair = (r, &0); + let r = unsafe { &mut *pair.0 }; + // Make sure the fn ptr part of the vtable is still fine. + r.type_id(); +} From 248a10eaf5cc6df2491a6e708524a41503674ffb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Jul 2022 12:28:57 -0400 Subject: [PATCH 3436/5092] reduce regex features to reduce rebuilds --- Cargo.toml | 3 ++- ui_test/Cargo.toml | 3 ++- ui_test/src/comments.rs | 2 +- ui_test/src/rustc_stderr.rs | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f612e7a3e9e5..af73a7af31c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,8 @@ libc = "0.2" [dev-dependencies] colored = "2" ui_test = { path = "ui_test" } -regex = "1.5.5" +# Features chosen to match those required by env_logger, to avoid rebuilds +regex = { version = "1.5.5", default-features = false, features = ["perf", "std"] } lazy_static = "1.4.0" [package.metadata.rust-analyzer] diff --git a/ui_test/Cargo.toml b/ui_test/Cargo.toml index 92c00915cbfe..dab46c5253c7 100644 --- a/ui_test/Cargo.toml +++ b/ui_test/Cargo.toml @@ -8,7 +8,8 @@ edition = "2021" [dependencies] rustc_version = "0.4" colored = "2" -regex = "1.5.5" +# Features chosen to match those required by env_logger, to avoid rebuilds +regex = { version = "1.5.5", default-features = false, features = ["perf", "std"] } pretty_assertions = "1.2.1" crossbeam = "0.8.1" lazy_static = "1.4.0" diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index e7b4968a9ca6..3fd65d643a1c 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -75,7 +75,7 @@ impl Comments { pub(crate) fn parse(path: &Path, content: &str) -> Self { let mut this = Self::default(); let error_pattern_regex = - Regex::new(r"//(\[(?P[^\]]+)\])?~(?P\||[\^]+)?\s*(?PERROR|HELP|WARN|NOTE)?:?(?P.*)") + Regex::new(r"//(\[(?P[^\]]+)\])?~(?P\||[\^]+)? *(?PERROR|HELP|WARN|NOTE)?:?(?P.*)") .unwrap(); // The line that a `|` will refer to diff --git a/ui_test/src/rustc_stderr.rs b/ui_test/src/rustc_stderr.rs index ea32ce4bd293..fc772c84040b 100644 --- a/ui_test/src/rustc_stderr.rs +++ b/ui_test/src/rustc_stderr.rs @@ -116,7 +116,7 @@ impl Span { } pub(crate) fn filter_annotations_from_rendered(rendered: &str) -> std::borrow::Cow<'_, str> { - let annotations = Regex::new(r"\s*//(\[[^\]]\])?~.*").unwrap(); + let annotations = Regex::new(r" *//(\[[^\]]\])?~.*").unwrap(); annotations.replace_all(rendered, "") } From 0ce1e14c8956a86e2099cf6d1a9b4e2135f52a6f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Jul 2022 12:51:20 -0400 Subject: [PATCH 3437/5092] update vscode settings --- CONTRIBUTING.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7dfa9d73120f..a3bad3d15407 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -154,19 +154,24 @@ to `.vscode/settings.json` in your local Miri clone: ```json { + "rust-analyzer.rustc.source": "discover", + "rust-analyzer.linkedProjects": [ + "./Cargo.toml", + "./cargo-miri/Cargo.toml" + ], "rust-analyzer.checkOnSave.overrideCommand": [ "./miri", "check", "--message-format=json" ], + "rust-analyzer.buildScripts.overrideCommand": [ + "./miri", + "check", + "--message-format=json", + ], "rust-analyzer.rustfmt.extraArgs": [ "+nightly" ], - "rust-analyzer.rustcSource": "discover", - "rust-analyzer.linkedProjects": [ - "./Cargo.toml", - "./cargo-miri/Cargo.toml" - ] } ``` From 22aa7f98c5cfb28aee0205f56ee1a6ee781ab2ba Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Jul 2022 13:46:11 -0400 Subject: [PATCH 3438/5092] call_function: make the unit-return-type case more convenient --- src/eval.rs | 4 ++-- src/helpers.rs | 11 +++++++++-- src/shims/panic.rs | 10 ++++------ src/shims/tls.rs | 9 +++------ src/shims/unix/thread.rs | 2 +- 5 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 1536b826ac46..d75b4f5fa6d2 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -289,7 +289,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( start_instance, Abi::Rust, &[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv], - &ret_place.into(), + Some(&ret_place.into()), StackPopCleanup::Root { cleanup: true }, )?; } @@ -298,7 +298,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( entry_instance, Abi::Rust, &[argc.into(), argv], - &ret_place.into(), + Some(&ret_place.into()), StackPopCleanup::Root { cleanup: true }, )?; } diff --git a/src/helpers.rs b/src/helpers.rs index 86823f281788..c051d44fa256 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -235,12 +235,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Call a function: Push the stack frame and pass the arguments. /// For now, arguments must be scalars (so that the caller does not have to know the layout). + /// + /// If you do not provie a return place, a dangling zero-sized place will be created + /// for your convenience. fn call_function( &mut self, f: ty::Instance<'tcx>, caller_abi: Abi, args: &[Immediate], - dest: &PlaceTy<'tcx, Tag>, + dest: Option<&PlaceTy<'tcx, Tag>>, stack_pop: StackPopCleanup, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -256,7 +259,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Push frame. let mir = this.load_mir(f.def, None)?; - this.push_stack_frame(f, mir, dest, stack_pop)?; + let dest = match dest { + Some(dest) => *dest, + None => MPlaceTy::dangling(this.layout_of(mir.return_ty())?).into(), + }; + this.push_stack_frame(f, mir, &dest, stack_pop)?; // Initialize arguments. let mut callee_args = this.frame().body.args_iter(); diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 2ef0a741d52f..c356dd86676d 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -91,12 +91,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Now we make a function call, and pass `data` as first and only argument. let f_instance = this.get_ptr_fn(try_fn)?.as_instance()?; trace!("try_fn: {:?}", f_instance); - let ret_place = MPlaceTy::dangling(this.machine.layouts.unit).into(); this.call_function( f_instance, Abi::Rust, &[data.into()], - &ret_place, + None, // Directly return to caller. StackPopCleanup::Goto { ret: Some(ret), unwind: StackPopUnwind::Skip }, )?; @@ -144,12 +143,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let f_instance = this.get_ptr_fn(this.scalar_to_ptr(catch_unwind.catch_fn)?)?.as_instance()?; trace!("catch_fn: {:?}", f_instance); - let ret_place = MPlaceTy::dangling(this.machine.layouts.unit).into(); this.call_function( f_instance, Abi::Rust, &[catch_unwind.data.into(), payload.into()], - &ret_place, + None, // Directly return to caller of `try`. StackPopCleanup::Goto { ret: Some(catch_unwind.ret), unwind: StackPopUnwind::Skip }, )?; @@ -175,7 +173,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx panic, Abi::Rust, &[msg.to_ref(this)], - &MPlaceTy::dangling(this.machine.layouts.unit).into(), + None, StackPopCleanup::Goto { ret: None, unwind }, ) } @@ -204,7 +202,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx panic_bounds_check, Abi::Rust, &[index.into(), len.into()], - &MPlaceTy::dangling(this.machine.layouts.unit).into(), + None, StackPopCleanup::Goto { ret: None, unwind: match unwind { diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 6b4e9d4f7533..5a72c872b04d 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -253,12 +253,11 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. let reason = this.eval_path_scalar(&["std", "sys", "windows", "c", "DLL_THREAD_DETACH"])?; - let ret_place = MPlaceTy::dangling(this.machine.layouts.unit).into(); this.call_function( thread_callback, Abi::System { unwind: false }, &[Scalar::null_ptr(this).into(), reason.into(), Scalar::null_ptr(this).into()], - &ret_place, + None, StackPopCleanup::Root { cleanup: true }, )?; @@ -276,12 +275,11 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some((instance, data)) = this.machine.tls.macos_thread_dtors.remove(&thread_id) { trace!("Running macos dtor {:?} on {:?} at {:?}", instance, data, thread_id); - let ret_place = MPlaceTy::dangling(this.machine.layouts.unit).into(); this.call_function( instance, Abi::C { unwind: false }, &[data.into()], - &ret_place, + None, StackPopCleanup::Root { cleanup: true }, )?; @@ -319,12 +317,11 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "data can't be NULL when dtor is called!" ); - let ret_place = MPlaceTy::dangling(this.machine.layouts.unit).into(); this.call_function( instance, Abi::C { unwind: false }, &[ptr.into()], - &ret_place, + None, StackPopCleanup::Root { cleanup: true }, )?; diff --git a/src/shims/unix/thread.rs b/src/shims/unix/thread.rs index 63b9f36d6ffa..8dc5f81354a3 100644 --- a/src/shims/unix/thread.rs +++ b/src/shims/unix/thread.rs @@ -47,7 +47,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx instance, Abi::C { unwind: false }, &[*func_arg], - &ret_place.into(), + Some(&ret_place.into()), StackPopCleanup::Root { cleanup: true }, )?; From 25cbfcc5be6245ffce5fb39474f777b4885e5f61 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Jul 2022 15:11:14 -0400 Subject: [PATCH 3439/5092] delete ancient benchmarks --- benches/fibonacci.rs | 26 -------- benches/helpers/fibonacci_helper.rs | 8 --- benches/helpers/fibonacci_helper_iterative.rs | 15 ----- benches/helpers/miri_helper.rs | 59 ------------------- benches/helpers/mod.rs | 7 --- benches/helpers/repeat.rs | 4 -- benches/helpers/repeat_manual.rs | 9 --- benches/helpers/smoke_helper.rs | 2 - benches/repeat.rs | 16 ----- benches/smoke.rs | 35 ----------- 10 files changed, 181 deletions(-) delete mode 100644 benches/fibonacci.rs delete mode 100644 benches/helpers/fibonacci_helper.rs delete mode 100644 benches/helpers/fibonacci_helper_iterative.rs delete mode 100644 benches/helpers/miri_helper.rs delete mode 100644 benches/helpers/mod.rs delete mode 100644 benches/helpers/repeat.rs delete mode 100644 benches/helpers/repeat_manual.rs delete mode 100644 benches/helpers/smoke_helper.rs delete mode 100644 benches/repeat.rs delete mode 100644 benches/smoke.rs diff --git a/benches/fibonacci.rs b/benches/fibonacci.rs deleted file mode 100644 index 9a68a69e800f..000000000000 --- a/benches/fibonacci.rs +++ /dev/null @@ -1,26 +0,0 @@ -#![feature(test, rustc_private)] - -extern crate test; -use crate::test::Bencher; -mod helpers; -use crate::helpers::*; - -#[bench] -fn fib(bencher: &mut Bencher) { - bencher.iter(fibonacci_helper::main) -} - -#[bench] -fn fib_miri(bencher: &mut Bencher) { - miri_helper::run("fibonacci_helper", bencher); -} - -#[bench] -fn fib_iter(bencher: &mut Bencher) { - bencher.iter(fibonacci_helper_iterative::main) -} - -#[bench] -fn fib_iter_miri(bencher: &mut Bencher) { - miri_helper::run("fibonacci_helper_iterative", bencher); -} diff --git a/benches/helpers/fibonacci_helper.rs b/benches/helpers/fibonacci_helper.rs deleted file mode 100644 index 586f1ce7da4d..000000000000 --- a/benches/helpers/fibonacci_helper.rs +++ /dev/null @@ -1,8 +0,0 @@ -#[inline(never)] -pub fn main() { - assert_eq!(fib(10), 55); -} - -fn fib(n: usize) -> usize { - if n <= 2 { 1 } else { fib(n - 1) + fib(n - 2) } -} diff --git a/benches/helpers/fibonacci_helper_iterative.rs b/benches/helpers/fibonacci_helper_iterative.rs deleted file mode 100644 index 0c2732828966..000000000000 --- a/benches/helpers/fibonacci_helper_iterative.rs +++ /dev/null @@ -1,15 +0,0 @@ -#[inline(never)] -pub fn main() { - assert_eq!(fib(10), 55); -} - -fn fib(n: usize) -> usize { - let mut a = 0; - let mut b = 1; - for _ in 0..n { - let c = a; - a = b; - b += c; - } - a -} diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs deleted file mode 100644 index be542c2bc0a6..000000000000 --- a/benches/helpers/miri_helper.rs +++ /dev/null @@ -1,59 +0,0 @@ -extern crate rustc_driver; -extern crate rustc_hir; -extern crate rustc_interface; - -use rustc_driver::Compilation; -use rustc_interface::{interface, Queries}; - -use crate::test::Bencher; - -struct MiriCompilerCalls<'a> { - bencher: &'a mut Bencher, -} - -impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { - fn after_analysis<'tcx>( - &mut self, - compiler: &interface::Compiler, - queries: &'tcx Queries<'tcx>, - ) -> Compilation { - compiler.session().abort_if_errors(); - - queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { - let (entry_def_id, entry_type) = - tcx.entry_fn(()).expect("no main or start function found"); - - self.bencher.iter(|| { - let config = miri::MiriConfig::default(); - miri::eval_entry(tcx, entry_def_id, entry_type, config); - }); - }); - - compiler.session().abort_if_errors(); - - Compilation::Stop - } -} - -fn find_sysroot() -> String { - // Taken from https://github.com/Manishearth/rust-clippy/pull/911. - let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); - let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); - match (home, toolchain) { - (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain), - _ => - option_env!("RUST_SYSROOT") - .expect("need to specify RUST_SYSROOT env var or use rustup or multirust") - .to_owned(), - } -} - -pub fn run(filename: &str, bencher: &mut Bencher) { - let args = &[ - "miri".to_string(), - format!("benches/helpers/{}.rs", filename), - "--sysroot".to_string(), - find_sysroot(), - ]; - rustc_driver::RunCompiler::new(args, &mut MiriCompilerCalls { bencher }).run().unwrap() -} diff --git a/benches/helpers/mod.rs b/benches/helpers/mod.rs deleted file mode 100644 index 27504a2cc034..000000000000 --- a/benches/helpers/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -// This module gets included in multiple crates, and they each only use part of it. -#![allow(dead_code)] - -pub mod fibonacci_helper; -pub mod fibonacci_helper_iterative; -pub mod miri_helper; -pub mod smoke_helper; diff --git a/benches/helpers/repeat.rs b/benches/helpers/repeat.rs deleted file mode 100644 index 0e8c5980b82b..000000000000 --- a/benches/helpers/repeat.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn main() { - let data: [u8; 1024] = [42; 1024]; - assert_eq!(data.len(), 1024); -} diff --git a/benches/helpers/repeat_manual.rs b/benches/helpers/repeat_manual.rs deleted file mode 100644 index bd5d6b1e1264..000000000000 --- a/benches/helpers/repeat_manual.rs +++ /dev/null @@ -1,9 +0,0 @@ -fn main() { - let mut data: [u8; 1024] = unsafe { std::mem::uninitialized() }; - for i in 0..data.len() { - unsafe { - std::ptr::write(&mut data[i], 0); - } - } - assert_eq!(data.len(), 1024); -} diff --git a/benches/helpers/smoke_helper.rs b/benches/helpers/smoke_helper.rs deleted file mode 100644 index e81db817aeac..000000000000 --- a/benches/helpers/smoke_helper.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[inline(never)] -pub fn main() {} diff --git a/benches/repeat.rs b/benches/repeat.rs deleted file mode 100644 index 0369b1f74cf5..000000000000 --- a/benches/repeat.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![feature(test, rustc_private)] - -extern crate test; -use crate::test::Bencher; -mod helpers; -use crate::helpers::*; - -#[bench] -fn repeat(bencher: &mut Bencher) { - miri_helper::run("repeat", bencher); -} - -#[bench] -fn repeat_manual(bencher: &mut Bencher) { - miri_helper::run("repeat_manual", bencher); -} diff --git a/benches/smoke.rs b/benches/smoke.rs deleted file mode 100644 index 372cd0b22b7a..000000000000 --- a/benches/smoke.rs +++ /dev/null @@ -1,35 +0,0 @@ -#![feature(test, rustc_private)] - -extern crate test; -use crate::test::Bencher; -mod helpers; -use crate::helpers::*; - -#[bench] -fn noop(bencher: &mut Bencher) { - bencher.iter(smoke_helper::main) -} - -/* -// really slow -#[bench] -fn noop_miri_full(bencher: &mut Bencher) { - let path = std::env::var("RUST_SYSROOT").expect("env variable `RUST_SYSROOT` not set"); - bencher.iter(|| { - let mut process = std::process::Command::new("target/release/miri"); - process.arg("benches/smoke_helper.rs") - .arg("--sysroot").arg(&path); - let output = process.output().unwrap(); - if !output.status.success() { - println!("{}", String::from_utf8(output.stdout).unwrap()); - println!("{}", String::from_utf8(output.stderr).unwrap()); - panic!("failed to run miri"); - } - }) -} -*/ - -#[bench] -fn noop_miri_interpreter(bencher: &mut Bencher) { - miri_helper::run("smoke_helper", bencher); -} From 04a0135af772f8ce34a5473dcc7a350c1a80d598 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Jul 2022 15:12:40 -0400 Subject: [PATCH 3440/5092] make unicode benchmark not take 20s --- bench-cargo-miri/unicode/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench-cargo-miri/unicode/src/main.rs b/bench-cargo-miri/unicode/src/main.rs index 3f0ee5ecf6af..3cf25ba9cf6c 100644 --- a/bench-cargo-miri/unicode/src/main.rs +++ b/bench-cargo-miri/unicode/src/main.rs @@ -14,7 +14,7 @@ fn all_valid_chars() -> impl Iterator { fn main() { // Take only the first few chars because we don't want to wait all day - for c in all_valid_chars().take(2_000) { + for c in all_valid_chars().take(1_500) { let _ = UnicodeXID::is_xid_continue(c); } } From d7a9989f52a392425359b81ca094c6e1986d1533 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Jul 2022 15:15:23 -0400 Subject: [PATCH 3441/5092] add command to run our benchmarks --- CONTRIBUTING.md | 6 ++++++ miri | 30 ++++++++++++++++++++++++------ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a3bad3d15407..bde1921eb8ce 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -147,6 +147,12 @@ does not automatically trigger a re-build of the standard library; you have to clear the Miri build cache manually (on Linux, `rm -rf ~/.cache/miri`; and on Windows, `rmdir /S "%LOCALAPPDATA%\rust-lang\miri\cache"`). +### Benchmarking + +Miri comes with a few benchmarks; you can run `./miri bench` to run them with the locally built +Miri. Note: this will run `./miri install` as a side-effect. Also requires `hyperfine` to be +installed (`cargo install hyperfine`). + ## Configuring `rust-analyzer` To configure `rust-analyzer` and VS Code for working on Miri, save the following diff --git a/miri b/miri index da5634d6a95c..2debf70c1664 100755 --- a/miri +++ b/miri @@ -37,6 +37,10 @@ Runs over and over again with different seeds for Miri. The MIRIFLAGS variable is set to its original value appended with ` -Zmiri-seed=$SEED` for many different seeds. +./miri bench : +Runs the benchmarks from bench-cargo-miri in hyperfine. hyperfine needs to be installed. + can explicitly list the benchmarks to run; by default, all of them are run. + ENVIRONMENT VARIABLES MIRI_SYSROOT: @@ -47,6 +51,11 @@ Pass extra flags to all cargo invocations. EOF ) +## Preparation +# macOS does not have a useful readlink/realpath so we have to use Python instead... +MIRIDIR=$(python3 -c 'import os, sys; print(os.path.dirname(os.path.realpath(sys.argv[1])))' "$0") +TOOLCHAIN=$(cd "$MIRIDIR"; rustup show active-toolchain | head -n 1 | cut -d ' ' -f 1) + # Determine command. COMMAND="$1" [ $# -gt 0 ] && shift @@ -60,14 +69,23 @@ many-seeds) done exit 0 ;; +bench) + # Make sure we have an up-to-date Miri installed + "$0" install + # Run the requested benchmarks + if [ -z "$@" ]; then + BENCHES=( $(ls "$MIRIDIR/bench-cargo-miri" ) ) + else + BENCHES=("$@") + fi + for BENCH in "${BENCHES[@]}"; do + hyperfine -w 1 -m 5 --shell=none "cargo +$TOOLCHAIN miri run --manifest-path bench-cargo-miri/$BENCH/Cargo.toml" + done + exit 0 + ;; esac -## Preparation -# macOS does not have a useful readlink/realpath so we have to use Python instead... -MIRIDIR=$(python3 -c 'import os, sys; print(os.path.dirname(os.path.realpath(sys.argv[1])))' "$0") -# Determine toolchain *in the Miri dir* and use that. -TOOLCHAIN=$(cd "$MIRIDIR"; rustup show active-toolchain | head -n 1 | cut -d ' ' -f 1) - +## Prepare the environment # Determine some toolchain properties TARGET=$(rustc +$TOOLCHAIN --version --verbose | grep "^host:" | cut -d ' ' -f 2) SYSROOT=$(rustc +$TOOLCHAIN --print sysroot) From 97dd53d5effb08d61bd737557cce8ce0e3a8567f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Jul 2022 15:26:02 -0400 Subject: [PATCH 3442/5092] remove ancient tex files --- tex/final-presentation/latexmkrc | 12 - tex/final-presentation/rust-logo-512x512.png | Bin 96029 -> 0 bytes tex/final-presentation/slides.tex | 444 ------------- tex/report/latexmkrc | 12 - tex/report/miri-report.tex | 663 ------------------- 5 files changed, 1131 deletions(-) delete mode 100644 tex/final-presentation/latexmkrc delete mode 100644 tex/final-presentation/rust-logo-512x512.png delete mode 100644 tex/final-presentation/slides.tex delete mode 100644 tex/report/latexmkrc delete mode 100644 tex/report/miri-report.tex diff --git a/tex/final-presentation/latexmkrc b/tex/final-presentation/latexmkrc deleted file mode 100644 index 23aa1a481b3e..000000000000 --- a/tex/final-presentation/latexmkrc +++ /dev/null @@ -1,12 +0,0 @@ -# vim: ft=perl - -$pdf_mode = 1; -$pdflatex = 'lualatex --shell-escape %O %S'; -$out_dir = 'out'; - -# This improves latexmk's detection of source files and generated files. -$recorder = 1; - -# Ignore always-regenerated *.pyg files from the minted package when considering -# whether to run pdflatex again. -$hash_calc_ignore_pattern{'pyg'} = '.*'; diff --git a/tex/final-presentation/rust-logo-512x512.png b/tex/final-presentation/rust-logo-512x512.png deleted file mode 100644 index 38484c670e01f3f355672d6c95f79f035a963a44..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 96029 zcmeAS@N?(olHy`uVBq!ia0y~yU}6Aa4mJh`hA$OYelakXJ@IsL45_&FX7BZ|=$qSE ztLz%}EoN&qb4+qb$Z6gftK`LU`@x)3$F{DX!)(c(xWO=?xp>X3H+%hepZ~{V*SP%m z8TAh(^Pj&>ZdAxJ!u84g8(0n4w>5GEr2O-O7;uEK>-~PYy9J7M>K-yIXW~yoOtfJ5 z`26c(>HEK=BDk0sEcW@TGJOs=hS>Mb^yl@j9G~px@zu@PKL_G~ha8dK{TVNQ*L{vC zd}!;J^)35`pWBc7`7(+1ajR1`gkNlD|9<-Zy)SxTM|a*yyL_GRdxOsQDCW}-QI4v-f8k*Mcsk<-SqNLN0K#veZIcf+AwnOJEjL4Z*kmb z{I%zC`8(~F{kzk?uAb=nmPyAIr z{ru|!&B8Y|=NHdbwEAs)>QCv6I0lG=BO9J{ms-zR^F?C!9Jdz%Oc(6Mm6?7?eNtlD zcV`WM-QKGQ_T6((|36hqA>rZYvsK*j>#uEEKb?8qkEZi4zpK_9eBXBd>C^HbU1#JI zItA{tZn%3bf8Iez_ysdwSbyTqyr1fA-3$wE7ke#`UoWrutK#tsvjcW<_NVL|8EW=L z9R2vxOE=G2so*Wg?~;|XYIi*-Kia;!{U-aJ=Z~LCRZ8#sm$bE_`k?%ol?^+u3jDZr zeaB}}m3gc=Gt)PKlhg@~faCYKZTc^Aa{ir$isbV9c~_t7X#XwH6sW9!YEaG3^gLhn z-p&VqD+OxTPv3jJ@Z9lxu{;~frx(umHvM+~>o1i(mbZC7JUq7X!14Ik<#q=P1u_!m z=X2J)w9ZrX6-+p1Y5-2nnd$!-yKe~hoVoez`O26J<#Y7e7R55&=~L&P`$7B7m-zmT z=gs@RrvBcz&pKMN;(G8&3x_ND`Ybo3C;XV*ZJKkJSNy}y;<|6kuAjfZ?(x5KzxUWi zYZkaIbb65Es`9%3zgO&ozgu_B{azr)A-_&GRel|J&7MM^2jNXZ>|cXqR7BZcKbx5Y z&c&BR8KgZo*X|R4VDP)`lf#r3{hEu?=b!A_A9h^#hyR8v_K)7O*YxPvu2y<*_GOoE zgXS9MY=!UFpRayvF`ccdCTH(%8@Bb;f31Ji6mFCI{cGv01G7(WwPvX1{{HaoRE>MF zYd3$G_b*RHAmG@8M-SK>JDYbLN;qya*%y?|Ty`-fsJFdYe{IA2@YG^i)3b?O4Z^l3 zUIKA5h^kq#)!&W_i`2!s5OG~D24DDc$ zuKJV18e#i7b-jX6*u;yMe`|j#QxBW?bN@S?qu;et*MG2$cVt-e;5S30WPZ$RJ^iX$ zyA4~}*qfNo9iCOBs3(|Z=^;~)@#w)?A@*4Y73;Z~i+EZzUKpNFgCyyohBv=OZq|pV z)bETcIk|Y{yY8$tkIS|yRIh%7_))6M%d{K7X))f1?2*Nk3zes{vs%{<>fcl|EARD1e{*Nk`aM~li? zk9(~s2|u#y)=SN%6*nF^vGg?`T3yWe?NyD)dQOeVHL)u;vK*Qv!X{I|doSXg<6JeK zK99tLD{ojpiK??n`PS?9-wxZP4=g*v|7y?w?EdR7>UM|xeXMQubiY!w`lkOijSsGG zsxmop@Y3~@|JJVAx!gOR zMhvUZ41 zsi69R-Reb(WrF&y$oB=TJVfpoyZ49sHzIw^`JNEpI+{o(elh?YZUC}8OC~5JCN@Qf&@9|{q;-3Q12X3c7 z$RY-b*G+m9pAc9!=+h7KvhO1z+**0iTlPC z$`dUL1ld;2S>oD2_RRDB&-S%K zse0nw>K__+wC|a|pFHsvLx^ZF*UfTw)rTLF(a$CQ@} zH3z0O<}-4-9;n%|X@;-63OR^MAd$af}@e>4gtOIJko(I0_#$8+0hSNqqTHv`_d!@coYu zp5N}ZW(f9hW_UB9!XO+}d&q<^3RLUuJsGI#ekV$WZFRNQ>O8@155DDY5&mt@eGUM?wcz7ray}eY~GX z`8B_Cw0qln;c}KEw*D-4OFS6fe?H&(!SZier-!iJ{kVf^A1nJdH0)T<9kY*pL-YBg zfA>FlzTW-TX<4R4Q@VMC)F*D3?yA6~BzsR|ib8>cn?%X(PNw;+z9LUb)DP^IK7Q@~ z|ETkJcXATs^Gyvp7?*J~sz2&zuq&Qwka*~bqssq;J)%29K2JaX+$;UTiqaE)XKD@S z_kY|oCr0C^$6Tq-!zbqGZgyAuFT^6h^&Nj?ivQLMrC;KDTT7LGrYo3ldL$hADy&VH zqm=svqta*HrGk6@e%$l&`Pu7dkIr5nUH9m5g|<{!bX}VM?7Bzy)7Ne7Y3`WI%y(do z>jwdDUAfoAU+nItP2A7)F2A<+)s1=Cns?{q>ffKk8M^Lqwac?8+rOLFrvBabUUplu z9_Jz^#f=so&%|`fe&0BhnSZUEX-%x1%z-5b#d_uU9lh~z_iJ~_BMibx3+z-47bqsJ z6H)V-VbQ^~KtC^S{d88D^sAROtCRZoMXdh))r)tr;NJ7%tLtj4-k+b9+I4J?o$Y4z zL-mZ0D%R!Hq};JteSLwj?fS#!yRY9|x$ayiPs(bKxI{Zv9kah@;!H)o{~U4uIPI_; zRS}c(HPmVzyG-C#0AH_zW%j*n;p#95%>Gv#`yJh*K(pQ z|KDV}ojj>PnDZlR^K@r%Hm<@J$FOpyHE}Cm)|YN9dv5B+ugGF?E%S{*vEhbHm=_e1 zR{w3jp?SJI>Yo?G2je$SukF>Zc|7mVHuvRMT#tX=c5&tWsn7Hxe%iZ~)qC_@Jou`< z&+4C2?`6RiljF|6nVaJOHOF@Lbq~8ko?$mWq-;OF@uK4muBJUNw@p{5pZkFG^b?l_ z>mR6cHhjBu<2^^V*~>0!=6-ChRCjA%xu?#fg^#nZZnK?rbou2s zFD^)5Tzh`{+c&4IT+`xnuD+GM`Il);^}XEw?H{dPly17dxoXwo^NNpqH{S5%2q>Pn z<>B*LZzYZI{%h*kFUiu|c2Lyw8dpeHK+4~sy1K|_=}Q0Y;hQukn56#Hcl`Bgp9)Kc z{{e0(&6d-SyxsaAi#g{!n7n9;@5%RXzx~{Ch;hGp?b#BWmSjU=@sF(sbx!FQ%fz+D zmfl`GU13Mbwf&n_+y&x4aW-ddJLArO^u|Liac0vPo;`kAY%9_q>`-MpGZoYXV-IA= z>Av~@#zp(6-M@Jy|A|+2@X0Rt92tM4`TPCYu-o4rCh8Oq_fBP0<6@x^Lc5 z515nUu5rx1_dG?{k;y^5UQ7IpLx9irY1~4`eh2^fH(9~!kcb15!*OnouII8(WwwMn z+_lr^v=b|vH2>Ip8_)gTo7GtlCW!NPCWy06Elm6y`U^YrNOm@=dh>)tCM6uzWYe=e%FuG)Yq9|I*EhB;4I<2r#aqGUiZFwZI75BhRI&Yc zHvez+JH1=4{PpEsckg*^tmVJ?Pr7D}M||$B#ZRr*vwn2n{;JihEa0&J?u*yPDrxu=n_&ZW^C)0d`1-i9z-(=*4#jKyaO?m7s z@K9LNzpb`#Bg@3a^}P8>M_d>mvi_gL@ORy1h1V%Fnr_Tk@cwSt%s=~n*s9^KUW|8CIaG^zb(Slv-4wXwwDf_BN7rh$&#-#nko=-ajctd5g|sM(hA@X?LEoLm zilhbSTzOLd@5lhP7;kug+OEd1Z{a^rF?;(6cazT_x9*nz@b96z1WF#x} zYI)hPf7CuRsrmxT>U~RN_OLE{oUm$Zlko0R>74>!zW%A^@R<~F;IZQgTzW2&6gl4?|w6W4h)F#;C?dBs4;wRof9j~ikr+dt83u(3kD}w9?}uOcw*Nxq+YLY0rr8PDNB(*Lahm*!;=WhEp1xVT zH7oqa@AX$EZY@%q@3;1{^|!mnK8aarZx7t{;k(fwniL^kUxJZn(yP)eOYHFIH$d03KU$xQNzUI|DdH~ z{z3y!mb07})Q<^0%~?@U5BPxk$&Vhec-Vj9G_6bhxPO0FnqA88d_|^vD|XqvsVyv;r%=0fLi?M)p#paC zN0@JaRo(SDcgcFw_pZ|4Pw58D<_|rR5~A=+X#xKa#y2;NYV4MUow|SPq+F!c#BJOU zj|=d06l_~L#aaEkX6D(?ZI(s6CM$YonmyIzzQ^=c^@1E@)bG~~y$2ZQJ#Bt-w`0bE z?cYl~jvcGytX=ydsakS&zUEeryGr%yFUl1Q6^|ZJxhG_}n~V9+*<&9~4LRHm7w)|~ z)xslIB!}^@!-3X6%?HZ%1U20Yc1TJ%_mZ!~^)BObiHgKdMn#smd6$ncv@jfLmdQ=hJvwJVY&&x6UW*vY2x@2zq z%>dc?o5FWWnJ>B!w~sT3TWR(Cev|2WuG8;!{IZRo;+$OcR&iMkXB=_h z{q^}PTixtK?lpVLey-rv7Vq1zw76aO%v{b0g(USu*I661e=ct-(7Drc(4r&W{ZUcV zYK0qY*FM(2WK;^?6j@}&nA7B7$uif^QNfG#^Cig(-mGEg8T5rU3>};n+=8ZxBklK2 z<<{+z>*#X(es9j&DM#ejzTSV$?_BrFm%-Dm=4QDo%#Mm*{W{}b@axp)Ceim--Q7Mt zdYYa5{^IBi=Ob@Ve46|Dt#Q^Gz70mcYftv=dX#)ZR&rBl`*hjQT*g1{Fu5En?s>7c z!N%^;(;ve1>WBU>baDD|{_Ej6TR8vk)#e#@bkQf7BUd5hM233s|4tdQBBU~}{zlMt)$$2m;} zBAiDZ+8fr!JP=?O+*{sogyFs9huxOUj>T6&rFbL9>V^JMe_n6+@$yAX=>fjTKVjSa zm)u`BcZz!dj@T)4U!D3Em!aJ~^XT*H_p(duUz;_tKPv0Hd-TlNV6oM+j%S>nYj^C~ zmUkxwGuCh6n0M^mmo;^(Vy`??Ue27eak-f6qpdFr4`e*fOnJJOkx@5UUFf>!-~H29 z>3mX;*v=fUAY@lIJv!p`hYmI;6PA5TCfc#5HQR6Qe4uF7cHBoIPcNA{&3iZ|vVqlCrxUmzVlIc+eR+r94E=`$9yVpsFr6)o_vYdmv5@IA9&x%Jsk(<7Js-SMyf=Huj- z4=1)&AFogQF2ySM=&^m@-{!yX+I}T{JAcf1-4EZxf8%Z5WO}n6w-D#M`sU_Msc%9~ ziC-UG+|qLBclPm}1{Ib6IHF%zo=MxqJm=2wNeVkPJ}hU5bUSfCwnLjENPxL&W`bi! zW5>>-83u_-_t|y+$({NZ9=JY^b>-TUZs)RTFMP@)uP=}NE%x$ra?#^8x36w{clPAh zU17HScV01@WqvzI%=y>mBK5t}58XFcU)>m=DZPC5BEjuq{koggFPv9=T_-C3_51R_ zZ$AH=#WJl*=m46>9466$ssehBm|NZ*^!C%t< z4ze{IeEdJbc}MP!z=W22|B5<#nUdA(lOC(rKbv8pYS4Du{ev;*;~y0)^QA2+J9y_< z9Qma>Z{ClYwv7%IHJhf`@=V*vu28A;t9rT3n|CXN%APMd@Lt`^;@`~(Cc_6VAu4|w ze@}9dSQ5(^qj06Dal$H#2xm`4Ev_t`CV6ksMD;&1E4i9J2JE?btQ@_q~+dO-3mbF@bBwx_Z!{!qRcM8O#gfK=^T$xG2fJW{tAaDehe$^SBNjMV+m3>l4m{U z_-OJ05kZUhtK26m=KQ(&KyjamM%N2Q2jhiYjb(;c9lE?K_@KbiLm?)i34z#Sg-}n|pr#TPbwSKhmnBwrTQj|D0db=coQ; z?04={{?y!<@q2*_OTBvC58k@IUAg;QtG(4fUKHHFt!<0fKl3H$3r)B?7B^@g`Mt$a z;K=(U79RFy)!Wi9CM()YAH98X!T}EtVV+z&vny&XPWCN_ga!5rag-|xoRIvX&T=4M zkMEG}opgqHYu4iloHy;i@~Q~2dI_AFr0`;e*M}X!jrN`|6|~syxHMjtz2NHTWXPas zz^$0DPDagV#tDlj-)ya#w$HzJfA#UkTmPoLdQ|Th{rbzTeTN@i_rLgf=03Ak;+>XJ z*X~_N-~4s<;@!_GkK5k0Z~JoegzVL~DzBuQ}y1jKTw~x+`o&Nzub4( z1rZBPL&i(@WIMTf+E(cl8l3CgD0Jx1X}2Za1`YF_`3^i*)8z51+M)d+I$3jf?VclT z?E?IV1;n0+tXZ&MVWEP<%>=>A?3V=!m2R&uQ}`O>ctvrA*DJmq+)V4=+OUO}FF35m z##H^W>hF)+oeUS4T^b%7zpdVN_Ue_E&cBYoTtD5oEBm)2mUCAw^NH8oQK^4S4!O(z z>Hbn@b7}jx*WG)6l^mALa4qMf3f37 z>&VEOYDxQr=ls5X^DX}P!0S!Xn~5iE1k*5!-7H8Bt{;WM7n(OYhm!)p@?}f=RU2|NL5|sSzHyoCHaq@chm%nQtyUPEP z`fY#LZX@rZbcH(gx(Nmb;Ss`WT(kddkLkG2EB&*8HQ^)sk2bppGiC03`}}GD5m#Hf z;@q0YQ*5@M`>XjnDNDUpcFNt?#ow>&*xqtx)~g>MXMGcS*#D?{^{&6NH-3KC+|7Q` z{!wqS{b#q`g`3Vhew%W2^)2h|FEfP`rBh$1UW;U&ay0t*~PQHKzN-ZC&&A&dr$TWb(M&>}}?Pt9umwica{q z{c_RHzHJuI9> zPeDoJ^`4zxP74g#vZqTcu)VsWa>Rk>V7ZDo^T*c4`wzvAbTt;<73H`+VY6q$)Na$G ztEXp~$HlHpUcX*0G5dPoCiCn48@HRknkm54`=;6N-}YRNS=#G3gQa6mzPfAQ%MI%_X7_W?taC~Iy~naQ?RzJO>80=)lV|Q+@jg7l`dcV_ z{T)}E7zP*5dN0`~=kA&hhF3qYY`^HqWT))H~4^$x447 zs?GiI_Gayr55l*XLh)z&KUP4jCK0C(ENQi{gcFx=(R933nX}PteGsZgHiE=HfQ7G7>*ql zjL+6E39E7WFuYmf_vg6oqvgz1b}`n6?!~Wt-2Qpb&XCQU>kI`Vt>fp4DmM81Z=d(J zdvVF>H%Iax2J~#z4|u6i>;I8dbce1=y%?E|{<)j<&J-of?cZtrQSfScB$vSujCePV@NskGm)Tcd@AbG~eryjlj=K$s1+lB7ZGhTbI0QeuKY4!moy392a6L z`284sr6+K_n7pI;cE^h8`f}aMY_E1oNW5R+=g6ZX#skU(WsW=}%?dMe!&0w`0#2;Qg7Fn`KNU17nw#K?tgo%-~Y!=mESMVblOFE_bW|$`JXpFn&nS{C}XDH zotbAE{wz*%7WlVAl*)!1~)Nn)7 z?dKOAX3P^P5NCV$mucNzW=ZpV4=ck>Za;lJ|Mj>fPzeq_wrB9eiiQwJ*(o zwdRrWucWJa%)k4(Z?Jj%-@oCPdBXe4aeop^9vqMQt-9iA@bc=JCq5m1w`6|xru(7? zk29yfk9>LK*!P#4zXqLH+z_k#zAwUJznScc#c|1 zoPL`1?Prqc?~;SZ?G`Y;yW9Fo;!(V-*#|D(B9}j_6TAPc{rhLe{rfJ#@$phm?l0DV zJ9C@D+P~kttY5BvTs)g)2eX3yqhOb5J1T@9x;3Q69I#V}4m?}UVs-PK{SVvwWz#+~ z=U;hs=XaLeeWlun-!`YqC)MTf+DkrsuC;ppDVgYC&0Bw0vio285r+I1~dznoV4bB{GkWX&;c$DF;n=Nx5Z_5>ZgZgP+ER8yxj9ZNlYKi_~2>MmO zD073vjSc-Gr=BNWjn?E1tR~ey??Ph&F<8Om$fGUFW%PND%gAdoA=ubVqZS+)+^kpoM7B5 za7nJwykbp#Y`0wZ>b@<1OEepPhi*8oUf(BI$K3sYW%HNxJ0AAkE%Wtm`lkv`jy&^c zF5{uMmrqVVao6uxnUHk3K*_raGb?BMb=Aye4SnO^U=(Jr+g<&jI>)BUi~?GAkF2r@B6g(moM(x@~4$qkKz6i z_0IWX7i&#mQ*FT>C=sMpvI`Rcyb}wibtW5vI9$P6ysA zv8-wpaEN@M>T=5a__v(D9$UneWl{%{BeGdGoV=PFZ?p zF=PJ5y*;`urz}6NKQQZ0*E8F>UqZLpcmH-d{;lqr@h|3*g5I1b!Z-K1{p#HGM}*V< z>KnV`D)Pa~(^+PGzWn%uaaY6J5|2t7?-NrqB)mP21*RtmBsFaM-|j2=hW`tDK<9&N zg^lh49C_;wSb4DtPGLV5ASbag_18VhkLy*fXaDE3e+=H{|G3iS*Y_W8b}7FN#p;(%dwaS$lxxO^%PK!zBJ&IF z=4C59wwpWSI2X%qLE&W1@4OaA7=E#`rFK53n-Ig;ugc;f;ZwqD@o|4ML%@Ph2OjNI z&S84mI8ma>Ux(*W7vt-k)>R^A{8f>6J~8ZMnp@T15YNTz{}(|v&H?aTL0YRs?i&i$eK z)4X$W#p1^`i;k^N|Gjx#X>IS1)ZY2W7{sGJ3K(Q7<~&d8oNu@6mc8i*!I$^DC%?Vz zVc)oRfApdI(u@3~n9sky`BCA{+l@?0|8qLnXGM6po%!|lutHpxoJ#lu!JSO%rz7Oc zS-mXSKJE_!`RXA{P_+6 z1EvElolYJ7*Zak4r`-L!>+b$*uZ1J+JL2EJiFaCi-|tV{yvpFscWvUYMju)zykDXI z)@A-l%O~!;X0-ZPzV6G79{Z2D{n`BKMdYft`dc!V+*jh`tZJ8QsgK<*Y#;gGr2juh z%KA-zk1zMSG2zU&i&aOB6Eco$#)0fY_Ki;v- zv%9!E@@5oU^pteQ3zNkbrZHBlbF7-o)s*;-BV@DU1cR?!Hm%wp6e1F}`R^P*UYySV zex`s&na0GZSt_%NO%*SQma=@=#LxnBaj0)y*xdVv!*;pO{hu1nD)nc=*YZ%e{wKNG zQ;*c2IQ4_`#T#+=Yr6#gugT4xuT+;?$p8MC_|{shFYQvl<{a_2WqZH-)Xig8rFwt# zZzz9ZB6sw#6Kp>>6XZ8z+i*GbektHr(ai(9$qN;)QW| ztgsrF$~9Tvx|HwxSuXCn{?j`(ynf1$`JSui=f7L*oGo+2J~{Wz<<9uD-@Z&GkK_as zmt4*^{UZ2MKkLZ<{3)9MywyL%u9|ctK3VX8tmmJ$!jLrvDQE-#>mHvwLO4 z_V8@hll=l(kDu)C`{?BQ=fCZ9W`lVZyCw;PoW;LlW53_s%ddWO{Z#q;W!9IV)9*IB zd|_2(a4@l+lViojveM-0QwI|japoqkNr#}2N> zi4uYn<|!{Y#QA#iF!9Q6D8}fBu`X`ro^0KUWIYeL7?Jnm23X4Qa*;feugRGe4ZbyD*`g<&R9wa)uTL zUGZIyl~|?-fB5&Su!rAl!Q*{>z2#x=y*NI|wOTkOn6R2BD812w6m9`c`5(DEzwXt4 zVl@Bx+V%=IzcBmlza8HRUb$R3H~!iW<-+VgSK3GbP+m zns&%-U5k_3qlU>F<_mw|=qO!r_VjuA9jC>)J9(SG{QGlL>f6Vv=GO1mU)|h1FY5Kq ziJ6%Pe$752$h7z+C!;ch&kT(z4%7et-<=}3f5mR?Pup+*RjBS@c>ZZ#rohHi-@f+D z7p{w5YP#Q_x6bTQJGaC3^Ug7QT=Ea5r~L4HwEQlk*vIStn|tT{=kESvuM`u&;o zN4(_I^{hWOkJ%%m)jtbzF0Nbe_u_H;hZmCdn>YMgzJ;%T)lcCm8XXHVKh&nP{w`nN zKiTeKe8qp)+3mKB549i3XZ`8)J;XX=QQG2Um|S&ROMMQ+w)=TAzSKryx_^ zSxJu@@(C;roWiX_3jclQ{t!2LRKEJN_NDE8&z9bdKlRM?(RK6hM-Ow~`2PP@r_lfU z2|xF{aXJY8SHAL#J@NbGzxKi{yBRhbD2w+!>HiXZ{?lg1A1^1=&T`2=SlIaf^k#+| z8YzquiZ4#!EfiQ@TtCB{yXvA&MB_)t{;iP{ezD(+S(`4ez+mU0_<`v!qww6To_8C5 zG$|zf|G7{rT<}2&%dr*)4Kqk_hq3KW@~UJo2IG7W1S?)c}j zqoM18lk)fL!<7G5+^j3}urH6S(>r0uyJ-7C$AE)>I2s&S5`J?_c6H=%x0tvb+^{X+ zg=hElyMJ5N*ldbcCsT*>-Or%UQO3o1Wcj93R0pOQ{HUZz{8n16~hTd$n(E}?IOdeTDW_CpGd(F=}! z&p7&lq2)j_2cwj@ieQ1TLg9wGt&ROWT^kQpZM#ry!F{@?L{VYa|Kl>LjKxPy6Bjiw z9oa8gnDV#j&&gNox5!?ct@lxQ=Kgn|Hr3Bvy{Y4WZMmv?wbDQK4ZqnhJTU)wS~2kX z@=T^z>K;Xh?)_8w+obTjqT|UYOE#u^GG`QbKIg716e&~YiJ51v!jv&nAXl`eqqFh; z1$hUh2WF?3gYTNYxx3Y^@B4M>o3BrQ{j)7L-+YQ*LxTX*;~<_HpwTZ@k+A?GT6_b2=3IS1XF_$Vp;e|PJhP9{aBlt_lZjOERudvqL} z9wcs_zIRWB&aNi;c+9PkNtt!^aU*-c_wf7m3cqhKGTl0_#a8tq zooV*Wy8DNOIc^HGI%{zAIB|U0{?kzR!P9o$yHipdKdx(do6~rGy7Y~d^4`-DNo+|D zT?|#(pyZ$N@$0vbN(vf*bIREl92MT^_KV@x+4pmv`?vn!JU{X4|C`!Ye^%c6e?3yZ zFKY#!q&-f?%P$S^W#@l?Z!kIVOGKWd2+9R z-nzbl^-?<5{roE%-(Sxz-xs_3=f|f-3;tg|x+>uut3$A7i&34@zmppr7Okm2#TxQD z-hFMn;Q#&Any=R<^h+&@{O>T~+V@K@7AXCX5vqUZVJ{kO?|SHdP|N(2|9Mpe3e2vh zHrJ?Z3}lO)qxh4(@omJWHHANSwC%jF-&J?#*#WUU{Zk({dO8L$I|gi?{Krsin#YM{ z8Vc$O0j8YW7I_L>X4)>*D(!Io=2q=1GB-|q^xDZ-SSGaOA>Wglzh5@bd-bUGp2Ph| zJ7@KZKhNGiT~97eU;nyc2Lqenfw=oC?#KQ9T9NYi*+-?rPHNve{`BY7><{x!Ilu3& z#i5h`Z?8>$^f=q}&FQHOze`qj)$VwZ{{GzW8?)oyKYKN^>qJp`<%iVi>Z|=@BL2Qk z`7UhOefQ5)O=0^+K8_&Se=dLO7rwLa-1Tqo;wumPXa0L^zp?Pf-^qm?{}m?G86BD~ zem6Js<#(0SA1<$0&u+A`ez{}Zl%wjp+znH@8|)G;w{FvSz`_^u$5Px!ieb(PCo5E#pES&s5gh{77 ze53yK{tf%rUE5gCxW0<{jpJiQzkgG{_9rZ>*V4%P8~jH>!133Wd;{&d%yD%dPJec0 zJ@fATVtoF?R~`Fwaj6Lo@nRiziVh9dlkO<z_ zyusywwj$HE>pj8=O8rmdTfWMx{(l|F@o9aUyyL(36Tj|%E&61C-Lj^=Z`K|Y-qodB z7T)mZVxqiO>gO4Y=fD22Y3DbiZ5N_8?Y$ASY2$^O75^hYFLdBK63>$JLiV2u!;e3D zf(CCt_&fYDQQc7YQsQ@u#?Mv_3KZWJ12u_gOdBuXWPTZsa#Qe0jwaX=M{hQg@C}kmK zD!^C+*<*X)m&=XarYnE7G0YO1we+?8K_SMt4hDIbhJM{Br33A+ z(?z4*gtk^G9*B!wX>pZtH8!>a!O`rXtDrQaWye0zNI?Q<`4rl;Qie;H`#_nq*mZe4qT#OAt4c*)yxcVQy-pO#>{6>cNThTl3_P4w3KhA5vaiZF*58u6Z z-xp7QecR(cqn2&T19J0gsIwQBC~%|30lw?7}g2^MtO@5m`>E-d;)Ahwaz3FaKoZwNfDDZdknT_jT zZTb;geaDNXT9Idy9+%S&`A&wHYR4HYfcs_3jObTRTTecP7mF8 z=-v7P)&DEL_8)H$7dro=aesh)wA0`J?=B{li9h-OB1Kc$UUlDgrLyh6?4~NHEoCTB zuB)nFwRDew=lqj7_3?dNfo!o3Ep-Ve?ZwwQR2@>-y-4Am3#T~a)i<8A<$0Upu3e8f z=6WExqv?9M2g95PN)2x8?pDkz*X#JHuqiOOd2qCtC<+AiIfQWR*vYs{pu>UXjJM!{ z-%RIL?PDlnHc%|6`+j=8&kPT#_l9Mk#2%}^UNL|DV$P?!Zhu2I-{*R>(lz2Wclw{0 zjdsp^|GP#{`6GVIcF#@!8-FMLneF{3>fhzQHTUzrPe18qznnqixl#gK%bsgb-H*ke z?fmbrk+$ha=b!h7KfV8d^sw8?i~U}lJM<^o#J`kYzR$nA?ZtD;&iRw=_f5QXik7WmaUjN>`>h6L7;*waf2HZgMy*K{c4l9rAG^68NFF7S{=4{7TC<0#nIs**f8k;|6w1s zPeKa+la&5H{cM`?ZS&;+Lbj3pTa*+-~4AO#Bg@0*(dqplAo7zl@(r0OlxX)p7>uT_2-ngr+ema`tOmw)Ae7z zq4DYy|NU*|eO%BkY~TBXcV5G50Tp+}TQ9_o56gdw{QNuEjD3NRo`}|FL3{Qp_Mmld z)BC@?JjDFy{F?={nH}tA?^gbHD`)Zh_f@hd+5}E))9`Q=IAX=<#1Zi9{BNcU{0>SD z_w3x`8-y57Pwy`lG??*lCTpHkLpNh>IfFRU#f^@!EH_#j)R>;_s&zcU8n#4&b_TO~;cQ(-G@b}t& zsr{#Z?SHWGg3o{XulCVj>+Bvqclu@A=VrI+Z+COcB!T^>{;iy;o`19MLB8)FzDqYx zDIb*nbbhnIiD?=h*JTBi7R<7Bia+pve@KyFfp9J3W?Oe1L5Fn*BxW&B&R6jXUu9>hTvOC^Et&o$>)m2zh3iM`%Lqn{Xv`OtJKeWuYPHN^O^q-Kh9rURj>4D ze&5WO{(gUKJ}(!~>^idF`;z*CWAX-C@oXLYIG*gD${kccMXHS9^ZyQgmZGplCwD4L z$UBfch2`BMo)6l;nASOS^psxTbUlb=k5lo3BQFnYu2c6@Vmai*5@6}j!Kld+_ z#MQWxkCCI%_wyO!iPs(W+Ao;=pQ)qV@X5oi|87nby7$oDv#h?m{raEfkMq82Z=Ln` zSnP>JWbP|8@^;t=&)i z{-5)@7i!O$H17%1fqQSv*QNgX#aZ`9#QxQWat;O|7D4ex^Cv&~AKtIf?Fpuy>(cp-USrrIYt@3%{5pTGF_KhF_=Hx3>>r18sysU?ObNAiEi9Y2lmV`7G^v;X#wv~@ofSx*vo?6pImWrm&S<| zF%0GpIA<}-FS4AV#_YlJ<>6Z0N(xIl8zu-aZn94}ZL`|vjpvyy z(^!tqi08E5+ZFc8Z`+hzX@5i2_XY!A~{xdRRXv$c5>|WGK@sDSAPS~$h zx9TsyiQJ=^|7$1w-=I{#Z;gA;=gwbsImPqu?e(9Lv9>_<-^XoUet%kIZvJ`Yw81pv z)t{RJjEyp#3`OEyXX7na_nkeqxJTOby9ZB!pg;r1ilqNXS{SA>*SY31bT))vk?`2f zq-U~0v4=Cwm%~Hdp|c?|mW5-@?DQ#}w%m4)+~@wQId$F9i zh{M0;w@Sv#r|#?e6JHv#Ym&YEXXoYrmwc@~y+a_-{nI4r2WvhGKeQJA?(^Vz)Di#r z{68m|e|xKUTYbXae7+Ailm$N+nC37Zn|ku>f2|i`yEIcAKeV_od=NO>7{a#0ubp$D zxkAyq8LCXv^yJf<3tb$3B`LgOd69QuLk?dH!wci{D#F$33{hU@NA2pA9{zY@?=wO2 zzsj2boDm;fzBmgoiv4U}!yb5EK1baDgXhi-&t;`}N&kvO z+gKuE&}jDUV{#+w%jkkN?|ZFJO}Boe{>PxK-p}>Gx5HOF?@joB@85owQJ^f^NyFwVt6%WCHv+qoP z?%>#w)!8svW*3LY)0(CwP7U1+S+OiRv(x)JZFvRi&-2KBYOeh2+54yS%kkM>J5B8m z8CUOTNc}6ow8}Ey=iKl9PZ#YK*{*Oscv|tKU-JLOcrVqT>gsi}$%*2Rj&oNBkq`~?yBj`{zx`l(LErrA-%KB|zw9@ke%s)hiUF75 z1l33P&3x;sby@fh3tHS^U&B0`&!s_bSN~6M(H4#cY6sz+&MI86}1Oa z{;K&rIm>$@gy)Tyzzd}ZE;WJ^GJYpSIWaIX7$mP$`(~%+e6QEj>TuM$l_IaTj&@d^ z)2%a3O!+UswQ6^L*gFP^t2zJkyZ)SCbn=;t=I`{wir+YT>%YyaFWOyyh*3)aO7@@5 zj`}5@Oni=QNA?>hWc^k1c@xI6F*9C3o*V`Vfy3gdf>83y3i5@rm{1e54$)X ziP*h8U!t^F>Y?^t8jGVn6r4{dW6g{Ix$< zCFI|07tDNK-uJn;>CVp`igTFFSJzLOCJ@*xZ>qLylD*yiSKjSEwlfA#HcnL9uB7m; zBE62)@t0Bpk5YmvtKfo`0}ZFYy8X7un8&NerRMPKf4}rk{*#h_BX6>-5dPoe_OJe1 znET29H~ilm)O^KxK%`NnKKHOEwcMmxd@%LKgoe;4L9q|+EyN>w(NYtqp zR{NyI@@w+j(i_=^3tSG!=2|tl957;GP%PS~*vL?@{ohs7<2KAbBC{AecubE^vQK2% z_D5vxQ`R&Cr4^Iy1^>_A%lM6zx8DE43-_7-4<8e{=Wn34_D@CWze0{imm~7V$Nf(m zE3jEi_<5WE-ht=0|Hyo)>pGGTviF-G%L0`Gi>1B&KedH-bTpVLGOgR)(O}uppq_WL z-u;l;0pHK}%>xY@chxgI+5cGOpW{tthnc@rI2n2vE-Bi({Nv7jI_b}9$A5L*f8-B* zlW%-`UblMttoljk{#7jhoVsJHzTn5jr}rO=_^0OcW+lgi-?C{rZ_3_zxy6PYKPhI}|6vePiq+u^M}qsIzYLC_=bLXl&a@yWc;e=Lx9fcb zO-o;TYtIk+c5V@i!io4Rf8G727Jb@({e!Wzm8fd{KikyF_ji;9%`aZlKSAi@a>L{E z8-8%6{awZ>+^Wfxarv>|qtNr!Dr`R$&ECVS)EOBJKfLUTpH$z_%Wga8&-(=*^Dj95 ztI4;|`nG4E{I}gg_VO>Y*ZLI3|6kWRKOx6lSdGg%Di9k zYW|BgT|Q-@uFH0}$sQa9Yun!k$afw>q0# zvR#;%7*wO}rPZHr6+af`-kx|*YV*@A4kzqC{0#ehE`5Ui zrh31B`Hufy+s1v1n)Kgmy2AgZ1}qNMn$axtN~dg2U%Pb0$>t}sTRCP-J7S;A*$`y5 zwDH-;m1_P+?A>;MNnZ2w#+vvE^^(=Sg8TKKXWa;&@V`5N^*8U6|JKL;{_=17(=7M< z`p%N?mxY7pKVPm}*Y&5^<4?=mI^+BKhmP0@Gq!uO5nJ+7fLhp`;b8*S&A$Na;)m4f$Cu=zXBY^kLe$vWL(2wCv5< zbvnPZ!NZ?-_WQM_PcQ5}_os30`RjbepX%!`&iykz_euOAv1sobOh*4JnL6s%-JJLJ zxbpv#YO7v`bA00eIXUgG@T5P}t@h0Mv;WJr4O9K>)&JMaX{Y)7O-p)n?lh-m0?AfAY<~5Yknr2=4Go~ zr{rh$pZ@YPOONT92g`#hyZUw4dK}+}*6h0b!qID z?>)1BwG7J}$7{W7lt57?3n-Imrujrx<3NDeSiP;ul!KEXU{(W3$6_(zATphF%MLy*(|AR_{OmNcF@s0FF}LSXB{Gp>NgLy z{yO4vf8sm_iA6>X?Lv&Hk91W7XK^U>crhjjGnyQ_8+R~m*9sYjr3`vZWe-?pyiU1y z^8fZ@NgNE{US{e3E)XoOcm0>%`A74&`?LEm6El8oK2g7nccyL5|CM5apXXmZQSUYB zKgZk8>~5AH-Hrc0T=t?uzPS9b7?4K{HE~x{m+Wca=!J9-Yk2}y<*b5ST!G+Jv-#>WEjdA%IsGPc!cu2iQ~`^ z{LmgF>Eo0j__)!FrDwj~oEzWXd-yZBv^rej+)%~zLoLKUpHJrSaTTUxu`UNhymrR0 zbS!fyHcH(0`0(1c6Te@(-`w5Z^(Xc2|B@{)-@B$;zW))=@>72c*X{U;_Usewb>@1S zRQMcNC9kB-ar2wP-lY*d|-C0DsBq~m*GY2T; ze%kc9fH5Qd0M{{QPli3as+xLBu0|;>u=f=-@Zek7%^MG3(Yt+t_@Aw}X%J-=x`Z_Uf}zlKNhPuy?m z+&`V;Mp;+Gl_LkV3_sbg>tDb1>ffH1{NMh6Hjevd z^Jb$_z0&{6t6$t>|84lU+~JJNziA8$CjW9ccjb#aZ{?PjbQ_&FKQ;Yslvv5nVw~N1 zVDS_G8CjxEP4BjMykC9dzwh>IANzONTQY|2bcp&_^Q7g?GLudJ1VaxOrTkxc>o2$f z_*gE^=z1W`MsR|y;e3U& zY5Mh`SQZ{{L5Fqf*Lg4me7?^y(Y{{jX7=AJ5AD5}6cVq!SE&2C-tRGT^nAp&zPXT=hDVEn=~)zu-@u+xNHCER@Sf29n0*m{1rc(YV&)!tG(6F^QPQQ z%O&eiJy|JSKjGZo<)yo({Ji`;Bi?@E-Zh_nPAS(cmyO)-_wSAv)6aSf?Gyi{)Ber> z_b9Pe;`{FIGxN>=noj-5bAQ$6<}dEIj@sC-{p@S``uYa$-Samvvz*<0qJ>kLDM*lU zXBlgfOT%K#fKG;2>@SvQYA99uePL=|Tlf0!!e?DqSR1;99qv#6&gZ}p5M=gBhutLl zX+!R3om-0|_C^Hn;d&iE!9MM;`!|o5f9gH;vLUff{^C#jrElNHzy1_`&Azrq+VuZ@|0$c6U)ky(Cbafbuko$p z*1s<+{7d}Va(2QG(Vw&5)`3pwoBvy}qd~yML8DY~f~?_$gp&ff+%9SL$1jR_FeUut z`o-upi{XMx1FvTc!*(G?Up5Uv2POwo_CB`LYl9kmS+-1(WG~fEUV3`-$4!$@+;48P zPWf}!&g}lnr#I~<*1IVGm)!ZJJ?(G1!;!8(?6)%BES|&NAUOMOe}A+m=b^0jXoD+3 zdDfq%+o^4;7wo(Cce+7f!R+gQSH4_7#at|CnSZzH8aMk*zi!uFi`l>L%JHdxmb#j* zv5yS=fBwL`aD!=6Ifd2k%x#!(ByJbeCe06p(W1YX=Wsol&9t6d{DJHHi5e%pd5(!P zPR-oO5azs~w65WX@PclJNWL3}=jYh+UHRKR{ZP_n`J4Y@7#6&)pEtRFrR%?43=4AR zyZsG0ZlB1~TeFK{MxGdNwX+vPz;@flQ*1N%Bp7~uEG^#j&fof9=9l;7ao_)Qmi`yI z=&F_d`y5}r(%%=a?yWkqwJs{a@$MR~FDb`!Gt>Uc`1_o_-@++;(xt(v?}&q!69ZF& z$A85&f1|U4AKX-qVcBC_KjrM>T`$#`*dBK^nEYb;vdkgd-(hEI#{>~Z!Ov?n8yJ4( ze_FP`z_MH6w|MFQh)?sUeY5Ya;_>*j{7wCY@|tPh)%H>M=P$8q3=8Czn(*Sf0f+Rf zTK|U0|HU6D&ib3z{O7&7Op@~p#tj_z*B+if?bn4Jog$1^a)hqGyT0i!&zm~eKW%?} zXBbTE;^>eSyrZo6A)>3{x9$se3&r1zdS)BUr@y+n``+Q4rb)`aECu1)Z=N_0|leu3IwiAuYb6r2qwbP7}`xgJpNV2BcOInI80YrhvG z%PszdSaEA6GeL(#4pUj#W#|6KlUdH=sW<*y2Z z+{F{~mHvl3{}s#PAl5lQVah5_VKpNG#!?8(iHEDf_hK7U-JxaxPf z=j;38x$hp&{by(9#amgU?ugKQg>}O~&K5hJW~u>z^0By7!lL{-&ujKDjRIdo1@(nt7Kk>mA;u zodrS}-}g@TZs}KXSF~xnn^4}L&wgV{2g6?n0Rzdo-VaPKFORc+RXX+3Ym?JX4KWP6 z*n;d2>`k-ZeJ|o%HB;Dnne==;^9@_Oj~DQ+EfZz*V>Gy-bD*4kOUJy%6sLyo4Xvw| zaC~4rYrL2t+3L+(>2`(%7j5VMd6}|b(5jIC=6)fDzqw_P=^w;? zR{vOLKWq2$zyFdSYAG`O;PN!Qwp{1GA^S_~lk=}J*S`{+`G2kK;pCRC#spQWdsK zB24|WYRVKIt1Bj$eh;*F=$`-gTEMAw^0r6R3VTD96fQ;P+RHOUTKlrSP;T1A(P74O z%eCRho^X?f)AKc58&3Y?zQvlM+wXJonf*nM7Z2Hg6?|I0_qPDU;gqKiA{TV(S3U8s zDBd+|^8a)T2LB6h%DJD^^I!WPaN%**_sebe_a4eG%B{DnF8?o=_IJ1Xzgu?%|L1M~ zTQjk49fy6iOa2L)@J9*3(|G@tsWR^=GkbSb@b*nD{tJl?{Eol)=PEH&bp6_|kTbz% z-SYkkfA8Cb9m=~leZy5_(-?*|u@=YNtWrMDFLp6-W2j(VdHHL^e6a}<5AvFJ@D(#& zh)ccpPizlEhL-N8UH>d?=Irrg5cnyap)8-vB$FY=Tfgd>y3E0NUnmr952+ELM#syN|!U< zTD9i2p*W|nXl+~KcW2E7D@&Xw+KV$BSaIgxN_L00PvocOtEV3SuW>>W=sCko7!f4kzl_3S@ov%iYZx;x+W(fKRS&MUtZ zXL%@nNH^sVL)AYur3C9|U#Gb$J`iEpB~WqcNw3+D#s%`q#sAlC)LABCa6fQsw%`Hp zqkm?d`OZ1xP5pkB6Z>aOuAAI0|I66PyYiN6`~M90t#2*j7;}&G&tZr&ayZX0FQBC6 zy;bCYh5!B={>w*StLNPH@3af^!duUlPu{=gG{v_!R z23Ph77M6y&JJuhJ3#r-$`DK`BhnlXP=geGOX-sSi!Jj zVZU-)z=ConY_{V%L6d2j3^s_|+5 z)iwW@r~GAa{c6ur-ngc&>QHaW&cpWdk^lE8{QK+li+#q2|2Nzy;m!7k&BOc+>yK`FzSOMq-SwUztu>C*h&S@`#IJ2lFdCf2$?J z7xcUs|Ch|wF{(>7kpV%+B`rF;~ll+Fg`tPrch;prt4W0AH z{wvq(|I1>27=P$?U(+&W+W!eT?}B^locsR%eL1Oq;f=qoUVp0ne*NzG@Y!p{LYsvD zTrJG%EFYq7U5PKgDZ<2mi|G#UhK4iu_n9vcn;esLtX?5PaT(JqSIvaKIcsNdS!jDR zzU*SCi9fqg*DPn3{%M9(+rwv5#eQ<{w)gt=m(S2(!9@GgU)rDIkFXr@-TM0erhmno zPnFx>_{-}1XXmCL-x*)Nw^q8(Ez)LSVPMNt;Va5`J8%8b94n^0>r>d*Ufp9@upmr51acH{___wbiC30{eSVp z33GnxZ_ocSnMq;#w0gTu|7ry4{a*cMpYw(Hq&!dIga`F|Dg{n4Rh<2*UcELgn!{!S zlY`?_Cbako)(QJ6nRJQ0}F4pTm!?w{G%p}W|?{plSLRR=6lRPG5ree_pZojI z%MBe&IbTliyu1H?=Y9r{`xEvGvhf9OSbvvck6d>{?)I}YcM36GVK1-`IlbQ9f7V~4 zW_RZYD~-yy&o-zqg`Hb4rFvc8+Bn;TccZR9vv239&|zuV_@AHQ=l2zb_U7Ua6aNSA zv2Q(Q@A|KJ#{cKN^o)zhnY2%_ra6|Qsn)u>?|O#H#Dep!0s+>HKRDMH zN-^D^V}IzHzFe|$iPHiZUY~6|85gE7elz{~eWl=j!*&LV$;$P~pE&Mw7}ZVv>%S#L z;rIWUfBTN@uZ!?>?mQ9iR63E*^Hs;=FM^vVPjJ zpGK&;P@jkb#d+CO+WqB{}=B3+Rt)8>Da%JZ~sLk z|F0KdD3|iO(U9{;`qHewE4rt=QLd9w&1Jaa=6>gch*HA+)W4i>|H*&@yk_z~#q|<@ z=Bb^zf9B9RJ5k2J=dLH}wKAyJ`m)$8?T@b6qc}lcjO9Xv0w;r&$q6+E6TuHIZy7qc z8gv&N=V)Z=>QwVjSh8|W`ht}@m+r@Wdz@K)_1WcZS!P=Nza)#-{Hi^b`={u2adHqt zz&HQXbsc}=OMY4Y{C?0VD7n7ubbMZ~65|D}FxN|3UgnS9hc^gMsQz?5{#ty%k@?4S z{=fJ6wf}vwjDp~W?fk9>mfe1Bbla&xo=>HE16yWueD&1Q+H2-4eTh0B=9Vy~Sp{e< zc)in^!R87}gBp|0o$OD!%(K7Gu9oWxredwf`~cbgs#mEq}G{*b)Ybj>|9YS8+2uXr1=gp5f(Wh6Nk#PyK73bxJt; zU&`m*91V5sn^J!+pZE2B?A-kd9rp1{@=yFdkRbo}{I72_88&z^-V|bb$MnEJ+9hb& z`d?conZ~S_pRcw37?b92b;b|Bd~$oZFRT~bJDXz%|DD`VlQtefr3{TjMV3y#{lYH?7N^f3E=YMxQHrw0$_$=@3?v9^?eV68R9X_nq z`Ni>{jBhHFLcP-G#F8?;_SLSj_dWle4dlsWYViAAUB0hx@B6i>=MUNW{o8K%?fa7{ zEB-DId7uAHO{M-WqsECf_OZMFHwgcCRIYV?#~vi}#$52i{5MivxJ2`e+Ijf}; z%!K(^PM6EEoi>+eJ$+rC{q*noET@|f+z*ymGiRkv)Vp;rqF-sn*WU}=wo^ju_Pl)d zor}5aZJs12XPlGBU7g_aPg&ugVecRHAGvb#zV>H4S#NOZ-E+PJ0WzQJSNXE^G@iJ6 zX@2>E_bYx*X4uic(LVj#dg1+>@12)r*fjIbiFhuCBK3I-Y&PEC^l#0Lzc*F>$=v$$ zd+rzB!2fSs4%P`X&R)6anz1O8%MO<#f4x{ToE+A2)G>)KIA6rb6vMLS`;|rRXQXWz zI4bVsVR*Rj%pZAAnV1YPVX|&2REkKi*0v((d)`%A35e_imnJ%RhZ1>xBO`(ni%O4>o+isljr9 z!{CnB-0yOFEFKI!jLioa+-ElEF*w{}WA)UZlkpwXAE(oe24WnH1^-hdSsF4pYOV#!T63LPe>;f7gRwxI zr9M3Ex7K6v?XIm3Atnz#3ov|FWRde=T;Rg+RV85lA%S0lKMoeXaBgNuI4s-p>g>dG z2M!7`tq$)KSsSzNc2(s^gX+p_=O_F%PWjJs(|-2*6$!<$c4mTNH|^EyC;XUjgyZUO z$1h)wOI=`Lkovzy_|LJB;`nUU;|?;P#8n%(^ccc+z1Xt<){Qszyr1L?uKbw4%YxDB zr|`TjKZ?En%}oCrx#>6eoFCt3AI;~u%F(34@kUut!1JZX+gPr~-?<)}mONgS|EG8t zL-*X!GI57|wkxxkWEBf*%4rgOhGM?AkTek7mce!~B*rdm^_j_aSw zyrM13HCe8hp02#WfA#kMTGCW~h@wiD>{D7g@50`5{-&?XY?B@6o>BlgYN#l3F zAmb74|Mu1S+pf87Tl4msY60h)`mmcNSs6a*8&n%r3c90vUa~B5_i$>MT{Ly=tj$^5 zvUS(LvwxN$U(7k@ZLnUW_XDA0eI15w&rXCan=;90sff^dVgBBYv8mBN_X>V=J(Amt@d{RlUH|-DUe4cC|2bm*5{)m60sQl4 z|N9}wp!cupo4viiJU`Z?A2bK!7U86UQ7=h6#)Mw409CC%tE6`lqyt;eX~Qri7F! z!H3(O9?W%OXgrW}BSRx(4};{N_XomSSr}x3kDE2DV5+GRapKUp*Y@eZW!nGx<~RTQ zrzd{<&D8P#^MZMQn}5{ze&4WuPoj(Fe7Mc%pt^Ye@5p-hAJ$Fx zJEPfH#C1bhE!LlU63xybbC!iiy*^dDVHLyTJzO8+)ASqWa0uM2w`ADB+Bj37wXoe` z{Xqc@-$qtWh6Rz!v<~>b-u-XocmAdIy1&^!hHv_x|8e&lX%2fv2C07zckDeGI!;#B zSAVqcmHPcRJ?XamHo>ADTtY4O`6vE0x4n^Pd?2vtf6bEPg(vsReLO#_hT-gqUvp>t zv3dR3+!^e;Zw-w}-3$)XpXM=`I~@43=F}0kEiLPoa2YU$HU!48I&fUr%TQC#&?mZz zVMDOule~r=1I~A=mN~4}YG7!Xvw~^Pxo^>-j8V6_KlE=`R{AZkbN1i!-#52QD*oGO z{YKpIll$Wa3FC-k&yU%^`7O;;pY}0a>|cf)!-;R3cWm_U_&@!oo$sI2Z~Iwq{{Pr) zt@L}n@1NqU9s9p9R+!$qeqzo3u;%&Qhu$C0*{>WmH$zEa%aO2Mo7xUUIUG>abaYNQ zdDOmGG~w5}9fAffp$#=gKIJiez6=}IbL^I7d6TW&RFt&f{xYr$s~s7b7^)ck6a$xD zblA%ELF3A;Xtskt>yxMct*_;o_(t@meV4ub_uo8^>xCG&E}XUx>#4Wg`bOS#=AT8! zdh2KW3|?@NX~lV~-^ZKn?H%Qx>Fs}UUE!lTgGY;W)Ti%CufH$-Q0}r{_$@E# zJtcN9j;Vo}m!WDUQ-KmAgT34T*+Hxf92vO`4R8K`TJQBOe#skqhjahqpa1gsv+{es z(0_h`pEK=rf1l@0oNoPxd)uS?*&V{O-_-kl`NuusZ?ft_vybcJe)Oj}NFTU5X@58@ zDTXySzSmXwr+NB%h3^8Nol9rjWT|Nm($U_4-E`M>i0|ByMqOV{4#w^e`haq)rMUHdzHk}h1H zRDb!@U)hK6UDRjE3eIOf5PI|a9%%)Id9gQtD(1s@$w{M-K6nTv&IW)zbeL&N-bwGTF_|M%*wc4!D=ZTR?IIF5Bk zPNndJ`*PpQ{(cQS|Mh)w`OW#l<(aSJ3%~Jw`S-ryWBW$?%|DXA)lX~r*vryyEL0r( z$NorF&*pz>AML|p{>v-aIcq{}1W z?H4KEC0OuZua_msO>Z?r{6{y3E%7Y%&*X1xVgB~ea$mnL152Y3LxD>EVHH6ICN_PC zI0uGz`!pR`9YPqD?C-RhpZKRdu;e zyJG)$RsD^d@;f@@hc#2s{D%Cqy;VZ84J))h*|9csubR(U+Q49UT;q4R0>kg$ZCVE; z?sF@wX82!WrLl^^#^}+Dep!|isg76JG=doyxH=er*n7jRA?pC6ByaW0*E?ihNVLQ= z9QZDucUiilKJe_nlVAH86n^~^*}OODnY_$@!Nfn!MZCL|m;R^^@ca49_tE;)e};Ph zWEiS$)Z6n<{_+2{=Y(nh9-RCCr`fuOfAgfjyK}!y-do2N`e$PeOK8)oqxO;UC-*OW z`cF*cU*8UMzZ24uxjdZa(RRixhq8B8@4gmz->RqS#dag-1{uyH(u~&M-#bV@a4%z9 zRv5|p!%|S;q^xIg@$M*#f(o1o&p7|0tLU7$=vxZ&-~RS{cF?Ew+wZ&&n!kVYTXXj(uf@XW zw}ek9;Qsfo+m5-R_^atVE)I(i>=~g9k~g?!aDV1*5ZrU)`tfP+zi*g&a`zkid7qCu z)Z6d{iz*~5{$n?L-FUT@LE`w9zzyqJm`oTBd}DmU6xY4<^TEysXA6x){yj9?$H-7p zKX+&G;?(~M|AMRk&rf*wKlsTyyKn4FehdxVwNpOrw|QQ@Cgp!6Bg3j6$$x%d7U=w6 zZ^J$L$MR$U_)q&uZ>~Q-=ijnT^=#gDant@tPyD+3&hz&vzwdF^uI}0upRn-g!2{-@ z3^M*pZnKK5uMBrQ@a*Q)nbKN~3|*E!mz;7wC(1`Rg&oj;U_UvuVX|cQM|**!{kn&; zj1}tmUwNygiTq!@qAssOe%0X&tutyBtPBbY{}1QZHNUa{>b>WB!oS5!?JK^tZ>rJ! zXRGwvJ@D;9i{K;jz125Y6h6_{p7URbp|10L=bL(tDBfBYhT9kZ>)Skew%@JGo{?df z=S4>?m;VAM-U}>b=yweX{q#NZ+I^>`|8DDiJ1h3%EStMA(u{M4`r5fen?{o zV@$Am@Tk44g88HU@z49`C&>L5-omiri~Pgab@p5g2R7L=9yr6$S?~Aye{tjaSquzE z?X|U-Dt@r<|1RI(tnyFd#`oh#?cFE*o!_-}e_mI;<-_TZ<_o4x>RG`yW4g~9_4YmT z?^mn8&JTRJzqjc=$HMJmcMU7nyWje<@#pcq9VM;j_cFDKwK2tqFdmtt^!W8DAH{H>>|~h3-;Nl+hK4KRM)Id7A7o*8 zDBaMou8grk@5G<=_Q|RYwG4u__y4;KX0#pH)WOn_TzSPk=9RW!eUA8p4%V$qRT;A! zy6OeBcxL>4{AhmiiGPJ3{U0B#KOj)%7j(X-&iC9e>qGBj%ihmB5H57>T7QXTKn9D5 z$;bPlt4=nPg~x!{Abbv<{3OcULVr<&HPB@*tc&-pV^nn zelY9#mwUWvo5BWvwGWKDG!yceJ(wTF)dV;>JZUehYJOv{b2R?+KV>0?A7)D??-a0Z z-Fd?J>7x7Wr|y(8oY1=YU$CbvCH>cnv;*%yGx9PRP565G1I+m{8I8rJ)}dCmF9!kEgC5Y2EvQQ`o5t|q8$&+>-~}Z=Hb|4XDImUY`ve6A!gC%cqWG2XNP~DS;ElpQ{Xp)+W~$qhB+>}N8)REmox5bTJMnd zzwP4w_M*@6e`ngi{n)<$PS+!OZVU1H((_wptNv$8|Jy6_ukS(swuTM;*Cp%NTVE|a zz$sAi;r)l|$qWw`J-fbxU15VYcVxMV!}&U6h9`w80%scDCrTw${#nPyF#mbG4x_`d zzEEz4+PEE}Vp^Bki{u-)7&rctW@vb~jjh3dqIImoKXZ+LtQ$Z7@8D@r{KTNZGRINc zq09c*Oy6(u9fiyf?B&`${`{9-#V|YLpS18Zd&6JtqD@uee=1g!-7dt-t1WHtt;C;hJ5>UFf3KE0lw_G`#n=r&pw#na$$Lti4-GyFI$sU;)2BPv~5ow z$#0*}ZrXGp&Lo3@VJ&Ne-`~o8{0_4i%jLdoEKlCU^+EJZ0|(=N8@X+)4U;q())+PD z6)?O|cV588xba_h$GW~((u@nZkNo%Q+OP9|_3giQC(es9SoEF}bchrD@lVI+QUC1! zVVR%j=l!z|uH*e8X<_txVJEX9gSJrKtiM+#*@tlnFbO&L>i)bw@$2^8AFeC^`pU6S z-0A&Z0skwKb@#6-#C9wt(t?OXu=akhJ+NIGYus|5v&X|cy4s@PyUh2&EU@Xy;nfsoyNYS(mnrL zxjPT=PW!^G_EBHsn0=(EMc@(n$0=d@|LfcO1sS%fe?42Tk48XIQ^JXm8DkevEpStCQi+JE=XvNYcP zv4D|*&*ejw14B<^;@jk3Hbw``mRH}reR2McY6E6328+3m?=SDP|FdiNhcowP$u9C} z{;>S9vJAtc8*FS09xS2^FZ9c%>^pP&tL(ZcqV ze%l)#HUFRZt)A^4!`7w=tBcpJSN_<~s^#3k!VtrA@#L@QQzxGLe7P%Bqkpt+k?&z` zg92`jSM7~yKNt!=PPm)BN>CwSB~wDjOo6v-6V@{R{Q8#tugbp&)*nny>scD^&%1kh zU%!Ha*adNB$DFe*oD2p641EP$34QMw8{Y4Jqp_#iT;MtP*5mWL!^Hm2neq33yy5Tt ztLFZFdh@?#kInI&&Km&^f&Rg4S;p)XCZy~sKcr<20Tz`<@JyMU2_C4`|&;oAG}LJSK|oYrFa zb@0l2)87o2Ht*qTkZO3;&$#x9^a`hvU;p?R7jQpvJN?g>p&*5kL0-P~M*V)trEm5# zNd8|{^eueXfB&O)jhnd`5|sZ<7r5{Eqgy~w;14UukBSG@9Y3!oZe3bmobYr1q#xH` zefnN`?Y>}bdei-!h4J|dKiG@x2$x;K$kHX(UB6`3_1MD>4qtxu3NCr-z`|jy*z75A zn<3MHS+7a*!{3&BY(GrwQ(9OL>oqWR{x55am!HDGu<=6Rw=4yPThfN#|81??uktB?Bszi@fK zf9|G#VPgNXT=rkn**`HUzW>HLQ_ETWoc93}~zuvEOQ3eOWf6^VZ zj-@(0*v-OWAyU8h%lnl-ervq`KKp}t*q7PrKkjw>TH=2wHX?&Xq=K2b&*8x-=a28# zJvYt#d}fE>qW2Zq^B9`EnHf}0{a{$b#K5qeF(`NsZ-Z{*eeq*k%ns=NsfwQPa{0wS z>>D|k{`Z~ucQWII`^-CDX;k*+KiK1c(KBK88+-jDf4uj^8~@LIT0i5jzRQ<4_jUfs zpYTr5{1+~8_v^py%{ST=*J*dz2Q4xFxWDauxAoMdcXIrz*IRN_ER4DTY|Z`CIrpV6 ze)oG5?R-O;o$Fpx|c5=Pe*`eoL&x`P)Zx_H%I@Fgq|U zgE^sqL1MAl0kaDBfDdOUvM~glX%v@LUH|c|#wn*Ds^9tN`T7U{ra!Jf_Njio zF2fv6h6Nq}EnBkPcmsKNY!a^Tu~l!c`69SKZ~gx>4_k{Wr8n1EKl~o>C0{{rtx~9& z+N!>tS_y*_SlX^6N` zWW`V?cbn<+gHM0$RxzD0bNKjEL;iR3r2k^){yHyt`1|sQy|;}MC+jCHNdC9_sc+gp zOKye}+D&m$|NdXx_D6qneGE&=xj%b<)H6(c-?U@fnSX_Umh75TzfqB)fV*|S;mv&y z6YqXgwqIR5`K|!>>f-PFonxF0z9&sOv_9cMyu^inz2(&m46fqwyVv<^HN2QVThXD3 zL5lIL9m5})`MaY(BxftUS%0kBMY>@&W8tA}?tS^()&ITT%;0GXV0|IMu=?D;#e2D5 znH^{{;#=|U-^M@x>vK>2f6Bmc-Cr%zcJ53px27cg*4VP#mOQy%yCYWn}@Smx+r6#ed{ygVf1u>0F_v$&${K@>u5|sWmZU2<}j1SB> z>!&VS@5at>>aYXLqfH+b9;BKctekqlTB3l5NpSj6`=^((Z(N>d*->kLq?eIlLCyYL z3$YL>Yku|wsRixJ80~DOE-ho+X8Q2D;sF~aj;YUPpVQvA>&<@dBmbjLf6=Y_zdT9x zgZ%kJZ{!vJ)vq{R@AC8i6}8{`M|f`5JIh^3`11PJW4C=(bN^khV{N!5R9C*~uMz(X zJ_ZZs#troj2XYMx*jRj<7`HP%IMsUH@E5zycgw~X&v|d!TYO7hwm6do>S)ca**r)o(zl>izD$n?~+T_vp2j&bPCVyBSEBY^M?(bX7yO|k6_pEhr zWq2gj6e@g{iFth#+t))5q6!bB7?!M#`4g?f*o&xm3hXgAKuYSpZE^M@!aD7c+keB{JE(9J)_Qm9~o?Szwb3KQ?qAjh&i+4 zC;#KmF%HZPTRY`%8ZjJrctzIgZ#FAKde`sxj(TTr;|E-C?=|lWiv9fe&tvcX3=Q{N z@1HfQpSrk8mSKe))2?aH-^GV;GyZF6O=EKOHFzM!a3K5rqGOkjJjkf|Yl{vG2S{yUd%F*45LIPjOD+W3(~fR2Ow;`0m&4<0EP z&dBn=*x$ZO@sq%H1_m8r{ug}pJSX1xi+t3dvF_hV4X2y(NB`?zV5?w%wBKuaz4z(= z@;+-BQupQ`J}dd#qw#9j{;y&C3pO)8_{Ld(chP-D2Jw3gOrK5{2cMDnzPj((p~m`z z1IIQC6?*>Jz4jXK^$)l5Uc6>4=eA&E5M?T0O8A=Cz@Q+`FUatRZDGH_r%U_4uw3wE z__1}Wcf*^2c?;MjPN*F+@D$k7xPHF#oqxgycb>Q#qIapdae1kxkjt)6KzLpK9M<_abm`!^f!{#(x6PoK-mU<~JxV1uF;12`K)`Jd5S2bwgG~4s+-08crACiB@S6+*K zcx_+NBYoed8CxGen&0a&VQ-_^fm#Zd4mV}?=PpLw|&zq6$o4@NsM2)uqS zxV6vr>0{lzj1T0*^@lw;s4%=a!_)NR{$j2JVpD!@<#LeZxDl+t z5Y6&aVm)8Sjz){~N7tv=9fw!JMg^P<43btya_oEWJPrKvQAeNQ0B21N zkNvXF{R|Cq>%y`TEQGU^h?vML@CH`AC#M>vYk|?luoWGK*A-iEVGs7c?e&OZ&FMHQ%u4h=F z{O8)C_a8F+*ct9LHzcVt6iD?c9Awt`AjY&to1uQ8*oTp!r}pA!`(xkJ7#J?Pe_VdRwJ_+*T1E#JmF*MnopxGc&U*2O zHFNxY*4_JTU+LHN-rvi{kifw3#`_E3Z=OSI7#l?D85xXzKW7j~X;=7_G4H}rd!P7V z#)dn8ChQdV5%>_;^Z&0p%eud{{0tjd|NeJo;!$RJ;_>G<&!hDW4y#r&G|XlYcK+I7 ze{8Eb!v(>At2X`RW2lH{O^9=kw8*d$*ulkII(z;@)3VT)&m5)-2z(S}c(5$YTb`lA zY73*7;~((_TpvEZeSZ98K=LZ4qpblyZg0Nub^Fe^Z>8V#lo>h{8SbbuIDFJUGBNC3kci8- zdbejbdKV&Ixo@;L>9qfE<08sr!ZlB&DQY!CE%Wg$N0v|j`_1CWKj|a?_s`=G`v2ed z%m4C)|LY@?B;E)!B%JwoKJC{^)`A-?h7NNcx+fm5Pq_6)V~1P$0f~sEAA&nh*K+4E zHQYaP-~LeiPsTI6abGUHV`%8k_x^lYTwqO11v}eUhsMp*8h;xEh_NVr?fhSH9Zu(x&ASXVV=2`jj^Hlp?qoJk68WBvt8qR`51OYu~snTHn6X`^?^%h4+~R&;(~Wi z(?8s@+J4I*!q@Zw6U#nxMuxmqxr_n~59}IN+Rb3uaX84>`OWFq>k?ftjD4Ku#VtFbMVk~3m(&}4bRu)yhn;fy!^ijiV$74H=ud~dz*|NGm@j@nu- z27~LzH`jN}Pp`hY{0YO<|Ng>E3>SLT860-~-?*gSiNWB&@4t@@#p`9oyzgeJmC}9t zckzMb|Nrkh{t;vdxFX09bb;-L{>%Tx3@2u9{vRPflYx~X!9|LLK~v}F^sfCD(w*Oz zuNJTGnH|Q+V1DZF)!o1Dp8uBXvY(k@UMPc{%QTM*+U~{=4s5EukRVaO!6dH7;BYha zu<15dso6cQ%n#>g9gROC_T|@gdA1v?JLA5UEpq?Nm~xOkL9A{o?}C{Oz6ukLzG8T# z_@~C0;mH{W0o}DsPaO06A3N4E>Ah<7{4ig?>EwQ!SE)xUHU8T3ZHS-8a$~wXECgbpT*9)`Ts`-hC_eK)sDpHeL4JQ{w>B+_v$VG*ULO*nrFy(K=A8- z_7i`;+b{a>|NH;)_Y)XDoM2&?Ipe2-zyViHh8QyehIL;r)h|eCeKN0T+NFgbR_FcA z+t2K<_vt?|!GC-V70e8Y%NZW9sqA26`^w;0YY_15enG6H(w=on-=x`Ivo#)5P2PCn zC*RcPs|Ein96st8E%17y;@^wi+==82Yt$6 zXB1;#nE$+BrW})l3p2y_=-d14-~Ijf{HI))&$kWvoG1P;GVN3Oz4ep*v2=mz%zvjB zU*v0*UCpqC!K3G^Cqu)=PM*B~!TZ$G|9{MuG-l{{|C{yLKLLh+%(oac{=H86_dmji zC#CgA`c_Vc#Xsg>n%h_>${-cQ%JA`ga;1E^;d2j_x@WPv47gj z$t${b8;aiOC*S+ze*bnlH^Ywa|KIDkbFyUow?Fe=-s%7TfJ?8<`~J_>Vwli7jp2Z( z%k=g~_jwBsGb*HL|9i@?py|hNF@`gb;^TMTmwg!jIqZk#G;4+juWs-D$$nShOr{AJ zj}$XY-hl?|$(kRcw5;}91_YZXEM#OTXgt3xH|AQiD8vehI8JZ={=-s=QIH`;^gt~`#g*!xw`CX@QvS0re2imes0m|O(7+(@n8AU~ zUb3^G^S8b6<@{TpuB$UF*z%`;;o1MryBWX#U+@3vU;Va}-|_QZzny1PNEWG=d@k2% zFZF-jlAZbfrT=FisV^_v5ccuAEW?i3U$4J=wchtfwpgv|GAo7$dJHbB7#rLenxY*p zI7oQxWM{aR-4>g{{UGb19{Wu7)) z`r48EJd8z>7vwS?GKMgPe6$z3+F-l;fGpz;v-XwDTrvyWw=r&Gm@?7fJ;Q_Z{Z;xF z3|}^^?~K#>zxw8WE(VK#-ID-#F+CGK7JyZ#?A0y&b4KX za$h!=KQ6y{`lH;pRKrvI^p4&*d8jsuBZZYQg4IIkbVJ|KZTp?OFFJTLH0bvODf3&wUt1#p^zm$K^w5K7nVX}BI3&Z^T zZX80}d>AH(os8o%c^1Lo@G{JSkzpgFH^&K$ItCVoo;@p>6ci5pP3KSf9~(cvHLtE# z=m~?t_58?x{}uZFiX@cT&*zwQbG;73gCIH08)i@IIT?J!Qt4lLb%^k;kQyRQA#2@k{sLU@_ChO+L8WoqcyT+RH{;ecm!!#qh2#=CkpmxHc$ z?bqeF@biHJJ444+c1DHjEG9%qRxyz;_??85uTX=miV_3(rZ3WX3n@YuhpHyc2mpt-6{lt;_dF_G+BKr9l0{Ix0 ze`GA1^n{^dqT%%aSO3{dNEofk(7yS9V@DImpC7*u3H*M)J^9V`Ckzq{|BnO-+i(2i zEX$B_G@p~<`8MKc=r1uKNjUPgOGnv?TZ~ni=rGT|(f0TWoIbq1UgE-F&$4 z*DA(G+Zd{ty0(TeUwEs}TR*LFUEPTn+tUx3ur@TxTd!qX@>n@X)rf=P!uc@e#BZ-p zdwxs5!`^Vb_Q_iYMutsX8~CFph%*!{>0w@E&a<3(OM{kS6XP~^zNDJ)hBN;*r!etc z6tZ2#B*A##_VaV?KOg**e6v6EW#j)!Qz!0*57lCf3}){>|NP&?#8Ao2P!RBKdrz(HI>mE}pDNCU zACv1>I>P$pTmG3yyLCTIrT=;SNOoNO)1R?H>d61J+ee+Ht}-;(Z~k|yb^j})`jszM zUu0w`KVttTsyY8|!oGe~#didT}R<}@r7iAxKoEP7(yt$?> zOqSW?nAx-sFRKqsZ|$ouUBa)}SjKoKS$eZ_j;_^-I7WsOtq%7U{GPFyG938Lka<*i zgZg`>g#Y*Vh-jECU}nfTba2gCj|D~I49D38Sy&iiOrKZ?aMTK({-g2h(~t9!ObQH} z>+js0KLL~hs=l3PohkqO$9TZ=+Wc=Cuk+`8 z@V~0`N0y;r;}`zIr)CTl%xq`d7;mp~xcGLz_#M@RIO7<5j*wKLJ#9N26mDF4TzxC^ z6BARO`acnsUyi5cFQ59o(SVUbkEP1^rvGmSJA3J+fd~Bik1SzeaItE9-S~6if-N2# z{YSRipLxaaW5i91t!La=( zdEBxY2vH|x~7R-6Pzvl;g#=Ofjf4pA!?a$m!`}6-^3;chbJNN=&fLJY@cWPE9A&c;_k4K;7(|}6uVnr3^rUT5$Ce_QjAF54%n!3anH0qN zFv@f*J4#yeDrhlpx?i7SEV?0|rJ=jV_#Bh`ab``Mf1eq{8M;5(-}&o*XdT0Wg>SyP zf3*<2X(jo^DL*hb`1kPF{rY;bw9^a>?~i|ETCnebJZnSI-+!kb>AT1o zS11@7bG(_#%%J#h&;EGJ&+CK#Z2ThsEg|IDrMHvz&yL(L{kTSsdw)$vIm3cu+qau` z)+Z|-^i}vEz!ntuSN7oRHQbMu$*`ELkb3asNCMo< ze1VIF!GtMK>PUUZssGkV(hFo*&vaQ#iVr@Zps$dy-ls$BKxJ_Jnx8ivUga!%-?r_) zCqu)&J#qhzPuQNgRhN2I)Hlyby=}_Z1I$a4>(xN>`PHHf z3=1CK5!a78@$WDLgZUOlfhdNh3>TI&FzA1uufZ@u`Lp~KhYY8N`TtCr9OUo+=l>|U zikE}Ida`}y?tXt!h6&wu0c*;04n>}q=g_x&6Y;0~sb)M&!;b{XkNlywkMje+@mGH> z&tzjrSFQiPxz7Cb->sbgOV%E`&)9IQWxw>JJz@{PiwW&vYr2)VfQRFbLy7sL_h;pp z?qqTAxG%JUmBHf-&;92tObiT{E+;U_>^?m0{r8J{4f@@NWgjw{y#6iS&G1WC(V_0I z2V=ver4DWy7T>ROOE4(Zun81MJze)FN6F)R@8{ygePTOOF3Zc`JnhA-5W>LM5;)-) zd%EjY1}&!J2|8043Rr6Ea~R+F-+gG@e=*M4l=0y~zdzeuEsXvovL@smnfRl)ygq`R z;RpM(i4WiJzHR%zh~a_X$@{yD>bKU`sUM18{-T`W!16=yRvB;}j^oB5u}BVvK!!H5fT3`g7!ga@$x_!`^u_mA1JP5$cMN8)ptXDB+v zeha?DG{Ktj%X{yipN`gu?Uiop`LnEHGQ&v$eujo%!_)a}45dsD3d|fBCbYh{pZC1F z?_+V#p~r&XuA4vJ!jkd%pX@A#1D*}eM*}KW&HeRuslAHz$NOSUaVOvQ|E*_f*ehhd zf9lSD{UU=kf0oXF-u3Xk8%Mo!M;w!b@sazhi|U(OGW*x}E!bTtrwwZOIDFjg3>*$KRQ-w_IMmIb4dNVaEI;>?_{S zpSZLxhgaoD3d2ukwk@%YKmLj^Ftsx=+1bjc*2m9Es;{;@bFb;ge(B#6-)aamNU}0~ z(Agl#u+8^j#vOez1%8K>i|;%A2^C%-HA}wX``^_f^*Udd?>YBlEyIF;lj`5{)!TFb zpJe>-JwwCR2hRESQ7t>PL~FM%o*8fz<=&G+~PKhblV(-gcMH$@x6@0t@iml-l?*)D))*#)F zP3#OWm_F{G#4w@#K%j%JOIm;A{)Ji$y3L1TI@Sxdi81}VBhzp|e!|~m)(6@?Ona7c zHpt)9lVI>>aQMOaO_s@FX=MGJ<0=drB3>kyUb>#Qe18tFg~)&Jj@GolcQ5L!<=^}- z>(`$=j{TQ&>Q8RV`Tc=QDM`G$PdQ0CKej(3^y4wBAOY8o_X5)e%mvPz{UEKdgOx?E z!QqC#6~p@597kL)uV!2{Utc-aY&U;YQ^Vc32Hh2MIZh8U6H0{`zB9gfW}nQ;V85J2 zcu&$c_lBglYX^8;mMmQ%e`LS5Jb%o>70GG&Yz$}qo&EiP^D8EWH_wx`85JIU-#+=x z`t|QF8Y-|fOzoV1V;&oWjNB7G#xD#qQv~aKVwZQ0HQD3e)?Y`#s5_tV;w3NP%udSk(L zfd;1D&%ca39&EhdA20s8UX$mLT#1e8hE@kghKaM@G4mhrzry!}_lUeA!|?~@Yi==Y z6xiC#|M2@%VLF{)i4LXZ<_RRbLD z1`VUC8FCH`KiH@I7i1{f{Fj9x+kkO{yde|AR-pq19p%%?Pj~DWW-yrYwRLyA_}_-T zoExe>9{*RjG4OBga)t*f8~snG{N;=J`;~kD_C@zKHr8KGyU3xjV!PD?0hWE+o8&s~ zGP-uWu3E(ydRO?s^EFHiLQEViE@pXq`6^D_yrHm;x9$Di7S9HA1I~u23@i=zkN7rB zTHUbGpqKsK!4^rmPbU|@Jg=4Xgmp)wmqT{fenyr>wa?o#z6dAzFRfSoZQuD-(&&G1 zuD^r+7XG#y@4ICfz8(15&#=MpXgI^^*-RS$EbJ;6uClfC6g}F%mg}$2ibvDzU%qos z+ALfj^(y#o=>BD2zRPZ95MlVR>B;-bYwr{K?#mx~-}<7w<({=cMqKHEXZLSbYG*mE z^aoWoQuFRchdMRvVNYOX2)eRyQp08DAFm(sHEd5VU&*V$_@JcDqb7es7-RmqzKqk2 z8{ST6|F>V{&zw6f8tROT{)Yd&t?=*D+W?1#n}6pAABl_QX_^20!c~6d#{K&D*yRtf z1YC<{YB1Szok1b1^w0A1K|jh{3SQg(d$>yMZ$$dP=5t>E?OwbOXJ*Ko{^#zAUw5^> zS8M(`D_C3K`8S*Yv6-WzZ7$Qt_itBSEj{=`xL}j{0yB;qU2Qpv4owY}(hEcx7A(k5 zYFLnehVS$IT=lff(i^~#%T%~|({y6zQiJjia);65p@*W-md7ViE~w-1(#ZCR>LETirfgH^%#qH53>Q-27v} zc;I}6utT2s5wk`nh8Y5B&ptfxKas<-XYQl*znOjog{e1~8qW{nbzt}**;8NN{IkAi zdkKq&EMrLhx=VHfp{>eVtFIK@J%8?FzRlfe$3OWBT>`par*rC0JMGq8e>ZYJ^TTqZ zbJtho+}FMMzGF}Qg9E+_1q{sFz5cANWfH#rHH7(x&sLezP6#XZ_%p5c|8LF`z+N zR^s-_iP-{wLstL0JA?7S-bwXuBlkzw{(I&1_bbQ#{jT?=9eYhR|8TPA9cbX?xD)kJ zzqOI`1E){SH73TF66_3;QK}6J2@#D90(CaGUnj&LSmybMlVQW2eg*-_2a6jPmmhp! zeyFZiJaxarlnU;G`3+1AG1eOA>NA#a=h?>W!%*O%-q73L^zW<5nSZhj55#j>KDg(y z1lX$UY-bWX(t6PO19Sl3j@Q8os-2GZZj-0Y7kfu#=OBNKCf8e z+aL1>)i3t8FqnM1c<#SKbhSi^zWT2Rzuj*x-){Kr=UL}f0y#66ajP(-EM#ps-S91` zadp{mYgY!1RSXS}`~{!RtoA#ye;)58$p`CCGHzpG*uZDk;4Hy-MvLKqI#1QsRR<_`kQDCV0rf@3b*yW@4DGZFfOdsSLxEQxE2F!nc z|BBLy-i9dCgqF3=S05gAv5)R*v1Hg&cj8-uNI)w?rk)Ffg%{t+d-c&w2P!ogG!{20 zZTRy)Um)G!@&1zc{yEv7)XR7nCIpr? z#S0IlO8mGtvF5jV#lIyAdfGpk%!C)WO>2l%ZP-+|k-b&=N0X{RKoDm~VaJUgmYcIZ zKQQ|62{0tc*tOlaR*T|&m7yrX^f9M)SuEoN0h#_1)_`gM&NB7w{d1&&jbV0h5_>}g zlgj35PM)-n_cz}B)gFIaXk)JOzhAH7n}007_3(WwbHnXN?_;mUue=lAyZQe5L-#oj z)?aOV7_JcTZ|xE*q4yFjN&?T>Cd+l~V`G$JXyJY4V9c_@oaKT{#&&~@=va=Fd#nxV zjpE90o*$JsZ8v+-%>R>&4}Zv3X3)6(|4{B%@iK$c+rOQx`@gZHN0#BhoBcM-H3GWK z3`(ExZ=Uh@e&CV#V||vF=W}YYH_vk4k@5~{ju)5tBN-edIT+?UL~UU-FxXta$?8UdScDGquV3F3 zt>b1~I?hozN#P)~JC`vN!x6Rv-+unK^WuA^_~KH0o!$|ykBm}3CkF}y6wKnuU|68X zXvEN<`TO{!|MPtJ*Pj++D7h@Z>sRJi{WC3(y5hME8n*~Dn5?=VpMS0XcFTS4gYP-2 zj2A4>li1Pp;+;q3U4;Tih6X`tC4YuP3~hM=Th_DWICjok#gM_YW`k(}Ys2@+zl;_< zI?ee_P>pfPkJ;`V{7H;i{@riu|G&SNd!Lcvk(}K;?)bFlY%jGQ)Fn;eV@_pc31P4h zyxMU7^D$M2_Zgf4{d^2&wg3NWF&wz_ef!L>`}5`p&5~r0iuknN_;vog55L{NNbC0K zpFXnM-FV&6(_Z_-yO|q*d@ta;cy(faIKzS!j157Y20A>4?lKr$Qcpae+LAUR}?CneYWxjIX$o;-M$DZNCvitAvui0OC=>4)6 z=1~vsij?XvzSt0;&U0tayDz`*u1%T6$Z#kxQ(!&UlrW}CTdWg8RRgznw%(+a55+rx0E zzIG1BrbBNSP9IxS{auUU$C5q5?>qMx6}_Bh>^$S`#4C}%DEu#P9AUy?KCE*mf&5Z}mJAgRr;h4sRsFZ|1#=G;C~dwTcA z2D4Yot^ZA}{r92Wm%X;2cKx5j$JfvN_UE;F1GD&BW(MKuPmkWO+`oU`r2Wy6`*%OB z({I_ou_?a$!v36(8EHos9J>FuyuwB@wlbwvtaixbHECmI zc~E`kT_VqfGA0IwH9lVj86JFE;Ge(PgsbD`zNJ69Z}ffqYgE0lQHaB$=Ue>q=(7qO zkK$W)Ts#ub*szC*!96KE-jT7PN0p)F#_a0)B<;sVyakyr>+{Xd@Y_DHa-VgYr$D)# z;}>_E{Pn6oClh5E436m4S3c~Y&9GIoA<3Gl!Fcoh-+J}`Q~zG&uHSpJ&Y0!C?!j8a z_qirqJa^cbp1v3N`nR#Q&!_r_3^RiVCxgdPchiUW8~U%>+00_j)#tKmVVGmEfV(k( z)q$acF}cCo!1vqd)1G_`k1{5No?vynDe-PEXT((^iJee)o>*g4!}`eo zU7hcrqbKk8cy8G!TVQl~{XxfbA(9Um49?VvF>K(P%up?OmqBAa=cDHy0UAGUpIRg@ zR97h$bVO`o*oHfsNB93;~apOEU$q8vJH5EA%z^@>JH@VG{Q~sh2A8(sP=w9eh<{&&aUv zf0KG+yzgZpr5Lsp^?wpKRvo*1K+^f?toKp}&i5;9N)TevIPv=(zx1!)u?qj5SDO4( zb^OD~u;IS`QG4mFW^Yn`*3}nh#xotrENWm#$PHp-=xF+u?YxqO<5ff7|1Z*B|7Twi zoA9XLVS{T^oZp|`jkntv9?ZOX{_&dqvaR=X59XUr%x96=!NOt=a=S9)f^KGp_J*%4 zDZd1kGAJl0#7Qz0Ed5X=lRPC{)FmO5(X~$2A&HfriIG9aS+#+IVHLyf096h3eiQqQkaa?<*1_37;9cdn$fGc5XFpEQdhz?^Z>4{wGDp>l?AXR{l8_nSF6 z`u#M#^QQfogNjz9U*V*`uOG=Dv47)X&FHZ8QGE9P`|Bh3-*4F;B)?zz$JtgUc7qA; zPZU1B|6!)9ldbWgYYYDLE7mfG2`H>)C=*CvX$a!*Xbf22^zg&cCk)l5H9GBdnk zVt8_j!NKvX%!$1W7s7A0+Z+7Zn;P11pQB*L-^1}te-66edhV*sxWMXT`R@Dgr~UZt z_~WkF-)SO$+&6D^?Phe8l(4A3xsu7`OYYT0rJB)9VFC)gjb#E2qAWsn3|%65;ys1+ zjbW@F1q=t09lS3yzcHTjfB&A!6MWC#-%R^Cd&X1kV5Y2WhH{pS@61O;55^j7On=t4 zVATQUttQ=W2R;6)wrp2BxH+YOk>P>V(f=xeTnwy2596G};sx^RMH24(+1}2W_nW!E zM$G5teyJHJiy0)+A{iQ7nHqNMWS4Vzgh=xobN-Qk%F&hSI-m43)}y~phcQgKWPkfu z=!9HWhRM_az4~4~_3Q8GAFD!{Exn$8b>S>+;f)?o##m;k`nv4SV946QJcf1e({X^r%-$cEN zLNjp|XSojhwEteL3jG2NlJ;Hum7cLOG933}bznLm_~-cT&i|evOa}~DnHb(N9_Vgp z^KJ+`-SFa%{&(R8KjfXYmDm*$w%5Ek!NN4_hx2|`Z=KtFzFgYI@L<^wea%Pr_pG^J ze<;5D#rCxaeoOGl96G@3a-8Re0mFu-2E%zflO68Y*=BD2DYB_f;D2w%j6aN@IxZ}W z{Np;|rp%7o_#r+uq3C}%d~U|{25mkCQ9U4GZd)(i~I6> z_Uy0b-an+(e(7p_@MUZ{cHn@e%W?4svJ5d&^W*sx7>?TW$v=L=(8qtvfngobJ&}oG z3=O&rYZ&&-d%*Cao1x*2%`X-=uQJA*?o0djiB(M4CXltf`C~B?YpwGG#*`l`=HE18 znD8`|frX*tLg+d%jvqfWGZ+~f99bJ`S8y;WZ1~8)=-}A3pNZkq=bTCL3{&J7PG59T zywZB4L6_ml(WHf&7!>Mkxc|p;Ff8{HRZ{*}?Z+r!bW(BgkHwoWJz;Lh&}PV(^5c5k zr*iw(`7IyJUBBG+cwx)R{NCZgDrUxBCI-1w#fDA)0~P-@vvC+OHPrdd&|TxsiGj#6xRm#e6g1bSjnva2p z;X(D)`il5@ZR@oe86+8mcf8v^UDRPl=*DnH1^d%0UBCS|Tw=UmjNwE_SmV?m@-tR3 zzhJeP$1S{OLE*=UJ^Bh;984c^{4?0zu-&(##E4yO+J0F`s#JyzbwB&(i;X z<*pCj^tbPZIUCoV*2e6PbB+qr?}z0uED&N@vv7tqLqfo3CIOa)-|nx=lK4>Ohthj{;&TRa`n#qJ28UY$Ep9O{R>gHxC^cp z7Z?I3>!m&6obts1_sS#7v;)?HnK73?0$c~ZRZDdABG7B z4sCS+&D%9W(VCz z@pEsU-@RtPXv==VMfU~E`WGIMmDuspq2V{fh9qW&R7D1vzu9abuTN(^x%tovQ4Xfr zNn8xu8P=V@7tHWL@AsFiS$}_Jb%{Rvcq?JT>_0jR2P`B79u)sy;GH$|zlY%e!JXLEEyY|Y!a9n;$r_K|C%W0&2WJ0z!?Vqn8(?S z3>Hj3@&#V5lw)f6V#45XCGHQuP9IC^f-~zm?f;n1@49C%#ZoTh%=U5l{*aElW^pV_ zm>TNO)ScD+eqH&`yp-Rv2luZvC}6(W$T0ohG**TyOpHbG4ktG)kgSWGu zz@CrUUFr`k><;|neDptFzZ$8rpu3{Q{zj|h<~I;38pRP|TnQSlm!g!M;t{;@Dz z;Bt68--Kb?ZIK2RhV4iH$2K3ie|F9N+=u&n7yZAZ{?J?Dg@eOn#)MZzk(JXznHj@Q zH+{&?-kh8uB(uEe|1vg)8uJ5I9luv`G8lYPV=!=LkYv25&>_y6{v%0YS4=mPeYVWc z(_PaT=IuGIFnQMxyFFRe4a(n2nHfSDR2XWuFf%-4)OcXJzhf`^1BWjAlsjSEHGM4+ z!V(X@YcPCxukf#avMvKBgW&H=|2J+56{vqdr{K3TN5)KhSx&C5-wf9n7WDkzs>)yz z_2>2L@7E`P-M;R__O=7ZV|o5FH+36aXk@s~kkECNiE+zY|HcO16&wX0#edTlW^zTD@yYA8b%nVic&q#m#9(;0t*~jlOKV~cZIxAeJzvySe116plg#)GxD_EJ- zrffavJmu@;ALskJWf|QVZYVHt++<)l}Ft?*`muJ zvijFyW`-UAQrH*@{>(qubfIar{P(|~O%Eu>{o2mZP!pr`sL^hJ4CfkVhy8jFoW2+< zB_CgPK%Jps|4fF2%X|zUo-r^rTz#1+xZ_{B_%ChilZir=)(jg2>Qz>6V`>N!`X8`)HB*|V_=9mx|*@U=8H2!g3$jN_YR-$`td^q#OC?CBkR`||B2(SPiD2h_w1sD#tKHZbqZG1Oj*nf|K6+;VhWqA@UPHRfZ-VL zWX4y04O7?{g&2P2Ff=$HSjNO)ovPq)`_J+{=c8DB*;PszPE27sQ0ZIWFkh~HpE5&D z*Y}A(W-~S@FtpxX#Oe_J-{B7@!z0GSDGjO&4b>BsRyiN2pTUrDn1$hZ;N!mxyWh+= z(>vNU>voa%9{1_{vlcxtOgZx}QEu~Jh6C0g*I#-6J^9*wjfd|!_Wf^M;Hgk>Z{p`y z_di&MaD#r2Q4 z6xK6rxhSzuTX*W)Y~3H{XNhcQ*LL-N+;)JEg^@XI_2a`^Bu=m}yo+THx$p2t z+~Lo9L52cO0Y3%-mIXhe85(}dY&iIXT`8B1;f~}2rUUuh-y;eWr=%|6`Sk0af6m)F z{@b-DPAmM#KH1smGbNnS=*R2sRZQ=ErfvRL#xOyTonezJgB{}swkNl_7*>h=FPH1C z-@K_#zvce>MepbRP_yB%Zvw6UXJgT`-V`UzAfdo;2!LVi!;DyAF0Yzf=?Co|N1?B`?rb6nB0_v7h$E(Q@s zjy<1y8h(_E3LRV|!}uhef!&MIp=*EUo__ZAOaUk5nx?TH{ke|e&&S$VxA`}$SNOMI zlVO9^&BJDl4BM2Lx2T@9VT^8!y9|VulR$ zkL7#Mzu)wsTJ_gIq3_R{ow^S=Jnz|{{IUMR-ju@mE@6x%3=JLy3>EpT44Z{>Qqz1g znF|;;G%=Vk>oGIvFfi!&vEOhPW?1kdU-KY8XQ6(BEK3e2!;QJTnz{{jURh6nB^WWO zwd*l5NQEmhedK>Ge9+sDbwN18g^&IY3{U?z&G@K)@}DZh5uIm03u_JXUI{aN*v-%o z&cN_qm7&94qLfFV{_h-yhT300E!+eb-2L}5Vuu|=2iq+UhGqKFivPZT`CU8vtGUY$ zY1JQ{(GtBZOy?aQuq`qc4Ul9|`ZF_>i}Af6gOD4?f|JXa@G)xq(hm3)&v-Ci@X&rY z^`?i9Z*-`#Jn(q%iCLDxuHi?$3WJ22#f0n3+r1W@nY2Li9$SDdgXFJ>%gdx08lL@h zKEN`AiDAb?28MtIGyi`PbFiQK()8nY#)dgTjyISa|Hm>mh%+#FPcFad*24XLT7l!I zc=sP%Nq=X(%y(yCkkYucF~FB$!{s)H5BFFYdPVQy(`wlG`@V0AcnzxC6L8-wM!?WbMuZ2HoFd&Z>;={L9O z{XLzb&G2FJkKgN_+&4N@Z_RSAzTtrx&lOgtyW5!=7KxXgXWy=nAlXu{TGp@Y{J)O% zkPws5hpmx4g$)gt#18D@u@XsH!;+w#U@Da6&B9Pya*>~rA=!DS_yi+Ihg*k4cBq=O zCIwlWpSonwwa?tTVq*8V?dR^BcT}2p{9mf`ezCa&Yr~qIObLk`e?Fzm_{+-hK$zjc z=|F~tkJbzfwQLLvI$FIL4&)uHzkNl{U^{c!n#ap(tI{JFci2A4pZ7XHZRdVbm;afw zTmC03SoZC}PhG|a?|(WU*qH7$Z_sc4v0r>63&RJwRg6zq1q3z-$uBLmKl4veNPuCQ z?h*Ob4A~3}uhkeFoE5h5iOKV9QWws+Cw++_!PY8chtvwE18vVZFF3E`^!seM|MlA= z9!paH7df5~S6EkEoG2m5b2(|jnw_iyo7oyJ|1|i`%JAUvWkH4p`J0b!_~*QKTwmbC z7ZCZRLGRDYq`lFp6MiJmXU*XL&i3F+gDA_EiPhV(7&4~)*zR>LzW+nD<}ZKihe`q_ zOSK9%7jUaF-OFHjz{`^0cE0sK2ctLVJJtw4pMX#X@qaq*R}FUlXBE(S9HCJ2eitLd zhvRKGXP+>rw&8nbE6lKFwjTScP=;b_2T5)nr!D`E9FI%du-d@*!`!fMK`-MO8)n!t z)Xd;NsPVw|+wbngZ@=!%zp;Cx{LO#Oa#@;lF8qwIV=eHv`1gI4$bVT@h7;}+p0GFO ztYV0L%f#?c`2R1jf4)NhvO6Aqp44I8m7b~`SZuS_Zl80EQ%rfof{O+ZI9NVyXJoji zp_Xu6k-?>oQz5~#l_7(3k26EVf%BFO1soBbT?e)?#xb|_$lqW5;c*T5MI^ z3=9lW4Ef8PSs1K41%>|qnap{3UW2dd8G#96R~df%5cRf!N0keQyBb2b5<}Y*f1~a*uu=9Gm~M# z)g$+(PO6{#wC>}9eWm*Z1&--;bTl-r<`cNW$Go+vK{Vr@7-+xugPAN%J&*qJ-T6}{ zuz^GAzn@!;&_4M(zMg-9tPDr~*iQS?YTj_|-=$ag6RlWvmNOUFH(Xt`!1O4`4jIXm z_3znlJiaJb_9J7;+^Gx)7O*mWaCS=ae!#oO|8CVp#)s#n%NQ?wn#af`%D~mhaF_Xq zdB@kz`8T*24lHD7XkuX4!#+V+K!LSx^_dm%CrudgIFE2K{M%!s+fc^R5GGQ;ds4mf zrn=x`Wv_b|EA-rDV#~8KxDX=HaYu|{1sjvcndHS$d%FE2oDL|3Fz^T{9O7c&5oicz z{*b+>aY7B_CN75k>$w+e&f=RSDe?C3di|uS3s{(zo#0=<)WFB69KsnPSjTWUg`rOVz`?2<7YP3(`Oi#GL!0`GI|Ac3PnaiKE_Hec7eN+e#+y1Zd#cPHI^I4`bd?;sW zcqx~~_(qw*;Hu^HN53x5MVF~`V+r>$B*fT-?u(}DE3f#MaIO%adlXXlz(|V+MyZi_W=^&&9faSO56<{ex-dKV=64#{-*;Z~-DbEi z$#CHQqxkZZ_xBdaXt#&wd#8v7g$sUy{k|9n*>6Ljk-IO`HwSAOC%G zvtm9&gXT8#^7UtaChQfxP{z+G@V{83zNKOD5>|$e(1R61KfbpbPMgiSVLJoE>+kP3 z*fKEa{CxbbUWW5X>`Au75B7$>AJ->*EoV5u!E`ju zu_6Azf<}dcd#4ya?DDC;z{hm&=rLVI2c`o;z5jcqk~9q?A8|&^628r}F;?KXtAp?p z?g<-{nix14UI;3D^#8E3p`8Da!oR<7-j+-_@}HR{Z`D?7`87@szZo5jV$Pgr`@!ni z!NakKh2gD^LC5dw%avIeSog3Sbg?%U$bM+B;7AF+)NcPJmt(i9!!-thE4Nt7F4{3X zxR)ru{^yP;8w@d=;W>OmeHXiHTuYJh=bxEZ^J3|Qv zhyBMB;upFc9w>6SM9DI&YHLv0@yD^@{zS!s9=AVQZ#f)-72YvdsDEQhh<;!@_0RiA zrUp}%51S9X-=ge=4Cws7vdNu^s@&aecAdUiY`XQhjH$6(q2THwhJvH>8Lv7sY-LP4=Bk|_qsH)~xXbH*#JA)3YKpv? z8P5C*4PL;*%i!?lX&*ywc!Pxa5@p8{^#eQfB$!w8uV-a=bFNpA;mQ1a=8Oj>tYA7& zo#DOap@iZOjwxXWRFAw}YxG|I(EZOzvITy^^|A~bzO0vITwJr}y#!Cweolr1pZcE4p}s1y7@-B%nX;$ zHhkw`xG4B7sf+o*zr}@RTnrOxjaK^du9+3ZxO$6Bhx371f=ui3R9PG%|JTTS{gzz& zCZCCcfmxKHY=a7a1;7$uxMzotPne@#=_7u zorxir!$gYtEu(`IL&G7N`5YC~H?%Qm+cPjSY!y0o^YcnYriRDq!Eaa?67uWrFfp{1 zI4f}MXJcew*)GQ9@Z|jWqc`p~TCmpW_-fnC__^_|g8fj+fyWFGIt3MxM!x7nCmSVJO^ZyP?G9!@h?t z22BjEn?x8?Sk`zj9N=R9V{Wt8{)AjFtH+;E1`TdTiy)2Fj11~4XDViJ^DORvpmp`t z=|+bqyA{rDX50AuIs>m9!y)gkBW5EG3?ZLU}n(yJKK+Awd3=P3#~rX zJ)5^l+F`#;hi=>Ui-q4RjLyWlx8?-H$#=-04MX0_Y)sCx2y2hJRq!{)lX6%EcG{r@UL^JjX?kJDTZVXO=5t253cGA zV{SUu)bK5T^XgWH2fKg$D(7On!L*^Np-Y^_@x)3ehhvT#Z6|E1FSIS_V^96B#&N)w zQG3~JM(siw+db#+xg5W-xYMBecfpLgdn!B_8uIF`lzrNp)!wdVU}CtI?tYUk<^Swc zR}YkEJ2}{0x;}OKBl+Otf4}sn%FJR^IJWSC!m{J<{o8KHTX6lTn4!zSu;*Cd0rsoC zOp`7+FYD*7H+d)?&LF#vNzA@(cW;9g!=1d3-!)z@7vO)x#}LBS5VDowf{eoleh!N@ zY%Wn84C~IEXH*yXU}hJ}#4zLI?U_^VKa7|kBjUn%mFbVEfsn?p8b^UpUY7-m0Zk0| zMJ!xjH%%{0HJHaSZ~n6Nx@Y}1U7zstd_V7n+J>eK#t(}fnHbXE{$;3ePcXGxH;2b; z9&er|#|gDVu{WPQ2<6*UuFjyK%?MhA!SV5HU`HNPO{|0}!-BvAnb{0CHi`Z>xZN;` zNB7Uhl}tI|V)Z?rZ}T(!6Rg*t^Uv?-|H!wG?lUs*uVy&Q+B}V+F{!(we)`?d3yfG? zrf3~t`N6d8^nKnLb1&F1zGq?4aeC%g$JDc=qlJ(0)vAP@dJ^VrMGxnz)gKV5||6Nfk!y!o%pkRW|Ph#~Dq=)uslEEXI~|2r0oI=G#B|46=V$4Rxr zJok*Hes;fnl+Vskr2HVz=NDs-XoHiH2g3*JBfo#!CJ8aPGkPDDYps$`>Sv1LFl=BF zs1>T`aArO5g!4ur8$tt;iIXJ?od!QTW>@1_6a zwOJlmDD0d5%;644M^nx^Hk~X{21~;R1_Muf_vVHcL54H#%^Q>)1SW*2v%K5vnxU@a z!|%+haDs214T{y9+)j zGdyUNuc@~&PT*%S+{dr5yk_1;hK87$1_lP@zYC`C-Su7h_KaPp%am%{oE<78UT`=# z{j+0j;WFTRIxloQ>bNW&^{TSuYtxO0M!ZELy*wXP((x9*L!&_M0-?aBdL!U!J7Tu#Pvbhi7BD zFr%5hT*~o$`HhE8Yus+-WT>>NaNQ}lBW)H}1fxX+WBq|H1_n+>P2DfujaD2je^?nS z1?m|XPW*8`!@%%Sp|i>^i%07>cj0w4=9H}rtoFxvn}rwzI8+#97z6gOF+|MXbNZXy zH?7?)KfXH1)x3Hja7(~FL#?I%v?N1rtGt?^1`9*ZYr&mo87_D|dcS$ierATPjt6$i zGaQhW_`u8Y!^*Sqdgb30$4{P_ai8AB}uCcO^)=^9_Hhk1yc>ZyU z1}j4WGXuk;^~?-E7+$ozFWe%+@M+dZf6j@2y*WF{8{C|u`?5{@okvL@L)INr5$oJ#8@O59$b@RydTBn;QnW|$bUYD z5O#*d{frKO4KBzC1pMoDtKnmKu7A~5o=@=s@3e1$H(d8HE)3hwJWYamGJj8d^M?%n zum9w`3fLGou_~0aoLKDW9dN7ubHW6kh9CPrJYw9+a4r3P=IW;K94BT56OJV51}&Ct z;>JO%?H?uI@ zpT{f2ut)lL=UW>C<_12-SJNE-)SQoDogw)|w{hl%w;T%VSlt*FNHcOV$V)xvD#EaWg|SN1AzsL2>016ecBTJWR%f2M{dPR@eq%BV1IOpJ4Vyp z`n}&?ueVYDxpR~>1LFf-3C8Wqs&51?>9=8-%D}LfF-yCln#nETOl~wobcJ+6-V_H1 z!TOF1zU&NH;{RuDs^>p)zZsn1m=AmpV`%u5uwbD=!NX*R9Y?O0Y!&!W#W&B@c=A#P zgXPqm`zU3v9~lXZ-Lwf;D14zuN(imHY|!nV1Tc9t4Ci7wldT`+mMWt5j0vF0PD% zf2ZHXyZtL;Zt(y0Z>{D(S%wvyOwVS>y=7pY*L+~<`6Kp8U!~TwGOhT|pE!eO#^YxP zwkw?xSkU!<5r-&KhIc|yRHWFFbv$AW2^@J0HAZp?{_0IC|0JS63xhn9d!#;groaVv z=J%Z!9gG=1XfbSK4EV$E@u&TUW0U;(<{h`b3Nf9NYyFfS&}HAK!NFm%j)`FdR{}%B z3@!%d9DTzh-yS70Gn`;{`ceGv(;R6=|4EF|$_pOu+3@M-!XyD7ZBd3wR)Ku}9H;06 zXUY2U{YCfDRPN8li50&0 zZ|uFcx}D*uL`M_<=l`3u7DzHK3|hc=U{0M~#YGVzrhq@3Fm@sP6i8yxFd= zui;~U2Oq=3YEFigM`qNSURcM)V82bTCEkgFy&*BxyrH3iMZCUdKilJ`l|Lk2T<&0F zD6#2hX1G0=Bf=!`et`f_ckDvC-GRUZUF)HvY<+CzWYJRKW4Oq)C zqo?T-$B)yKH>?%Bz{kLMCe1DkVXqm(2YrbjOQbG@a5P;1z;wiSDd+qsg@z;d4@qb!J~%sP1q%nmgLwT` zhB(HG1L~XygcH~p{uV1U?3pFk^65Xrj2~{M3CGCu)#?i&KH|fPrAb zL*@w!r5ME>|11?Ou)mbP!)!L!%@APCptFOU;U6QDdV0=nY!PW`u<8linZK3MQD2wY=Wkif`b$;{C5 z^{}c+nC%!gKbY=xpz#Bv$b;)g&Nc-7*~q%!9mkCY-*?C>q|E-y z{gFLE;?#XNhJw>yt{-~@Dj*mZoQ`J5uoEzmWXV(b#4GfVjn zSD>NIQKasu#ftj^8#0(VI2LF&8Zk7~HJN|Nw%L1Lo8jhj{+pZ(2lN^mxEO?(N*Dwd zH@?t3AkCPd6|+4`FlQB0j!MW!`NZ7{|2DA}a4>90W?^{tEB?ju}4U0ykh>F?ondVIE{O( z)$)j6U}9fe{$1yPy{rsZZh!xtb+LbTa-AMmJv+mz=7!hDoE(Z97M#4=kj>J#TrP*Z z<$5aDqf4*8z7k=Yvz=*?%Ar(72hO*zKW2U_6I+;Yh=F03V!@nh#)8@pJ#|(QyfGSI zr0U*W{G0eq#+;$)M>1;ych%Q0h6Btl@^!jzw0^3@ItB40{=j6?qxVbQv0s$e(T8Sm61spP?bmv2sqLu~gp& zi7QMz(i2MsvqdIHtvPpBzf-g$Rd-p%nPeaLd)gaa-pe1TPTq6*(LzNrUcrlxay?x% z?|sjRmjh1aeg{1ElJDWc)}Bg-ScORulJE%1SD z)7Mps31ayS2bKi?apYvkn98t6d4foHV}X9dPA-POzo&o5KHJ-VL#cw1i;3Y{n)_DW zMpXfZXZyZ?$PR4yakzNC6O+TqjD#M4<^@0AH@$d&zVSoy6ovx|ryUen1Q?FkGBzB1 zFVD)5AjDoQ$9J4me(^P(C0te<4#N!-w=491aW)`Uk`$7{BNI z`u8cDy`-drnZZwX!E1Zo$UULo=DS@yuG?@!%fRaYM}cMzUIrJQtcgu=XRUUbX{zxu zHsy2t>`$1Pz~K5P+33VSty>Hc|LTKV z`4i^*H2lfF@jd)Jvp2&HhC=_dO+Oy9Im{6$Q2FP^aHE4alIg%IUIv}nj0tjwHU4=s zG0f@sZ!P^XzU1Qx|JB|5+Yjk0Rk8|h>^?s4Sd8t(E6PUw5B4)Q-E?JVv1wH5qne#U2J2VSSN><^#k|0-gEB-6cPr3@A6j0{3d0t{zv?w4VY>FL?9JlI)>lcC@P zk2r(tjenCfbHf{AMH{$(?_gs%?a8r+b%8H?&xPlwOB4$x{raEj<>r24-WsL@zjIeO zJzjF_n~pidBRz(lb@E%T&tBQz?|(Ram0-Ya)`WX(86OyVq>eK_Z|C4hdGbiH&M1PF zVW))0+yC7c4;uftS3gUPY3*Hh`37eOgF9>tjrV&RUmSOu^^t!$gF*9spD<>It{>e6 z#=o}<{Z~EyC_egIeD?kQ%KxUyKf1@|dDp3&`Qlv{h8J4w3{xMO9dIyS&G^;%z?yV{ zfU|WBIlMQR9D?i>TAn$){>$+A4o`-mPzTe0HiicmU1r$MWH`(G@wmr%|1MTX2Cf~t z0>*X1ED!$J_cC*FI4CO|GYSz2_%i+Jae*w>28IMbCWfy4f(#qD7BDoJua95B(89=& z=hf42h$n-A;Vk{a4;T;i88mEXUNL`R?C0QR3@j{vZWsSGdZ7J< z(PxDn!*8>OO7#QNZgA{qoN3=-=jL@pZCdOJ=77|1{kjY*7^bBC|1O*U|NZL||Ne&k zdf!p6eB^#<<7xAqTm`ZGEGA-HdGV$TGzA{~s%z-zl}|WiAoas7n%^cblJ&vc22MVv zEld(T4FdX$_x%4a=HS3|AgjiQnPHFI4>^}RySM_l7+4rBL>r%|4-FU&Y`w`Iu!(yC6GOtuLvMZ^pZnk9T7xumzfKf` z5JO$P(TRV0H4GdK`Dg7Im~E!Sb1nJ$FTJhg<9t~&4*M`Rvm?Jx-L&thFWR&1P5r&M zZ|)yo`rl0WznEYhm%!Pi$&3%~_%dYh2>jSB^&rptfGtPGLq(Q7TURhGus`rFj$tnM zJjv}X4X#4P`#4_YmQ2yLkw`qbQNdeP-SN+2o!uV-q6J(O_uXG5>cB9efk$48<%Q&g zV8+w4et0wN@SpwP#X-> z&ayS^na=RQR-i;-L7+guHqnOb45G#gQYJdio^f7umwfosPZr|z?7Iy&VD#hmYeOc` z@q(GZ83O(=Z;{?9!r--<;fq||dEJX_9^E_tZ#nTVSd3xALIwsdyRCc&OgetgzxZQ2 z-}~#6gn7^Zn;rS<`>OZxe?8;NkKErMxqtbh_v#ECCPEB*ni>B$I&4;0kXgr|`0Z25 zhiskytA&{=^cfTr{9<^POg)&)#&O|0bHdO6a@BteX4p#cJN>u!dDOqrvi`mh!-t{= z)dpX67cNLX#y|6ab;Z5)T>1xAJ>9q<@hpD>cS8=t10kdTA|3U?zPoQpchrl!a2@$S ziP>SsqZ0wF4;UuQe9q4EEkUlH|4dzV;P0LFyE7T?us1M#;8X*xLOAw5z-+%Xf3T>d zsi0g|Q~WDl3xNlU{tU_-OQvkvuk|mCL1Deg!XJ;nIB?lASX_Hp`7M6+$MvSa{>gqU zkN>e+;84=$`RZqx7``Vy_@Dm%?6yZ68ov5Y({GX)K2ONl%^A^qjQ zy9~pEd3D9l)<-c4d`jJwx`z0CJ=G?PS{}=V=q`kwVe)$A#h8@1&{y*{l|NYwc_p%?~ zA6@gG?a_5^h7ViC6&8p)F8F??@jC-!`4jd6MhD5jQw6LCcH4NwOKtH`NYLRZTF=F| z`Gvo_bIiZxYvv#MUt;yPhvQegw9TPlMsF#GD*ksV*nQ4#;9m?1%$?ZC|!@vgOBtPA<% z5B%=wxooz&G4soZE5+X%#Qx;6GDNri$iEalCFRvq4LA1oS#JML7;>Ju=S}^qe_!jj zzrDw|{|2@HG&bnEi`!mKe*z_4fX@ z^;{``RsMW-mE_*SabgA2hYW?8%sXQ*LyorGEQgkX&CL`)mLHegC&>{p;8IvzLWId@l#XUN$CwZl-s~MP96Bn(!jK@wy>@ z;B^KAf7|~tXMP$#zx7~}32Tt|0e*%Pf9=`7*R#I+KQpjrqw^nqfi0XH7#WKE4+M2< zF>Gb1VO$`vH%eDkkAXq||ED>SM8;H@s>fm!&a(eC1H-=q77C09?k{KC!Fyqk*p8!q z4QuKPSR2mN{yJvgVcW>y%%IEZ^v%CME_~7cmmT|=8s2=EoAQ6V?^PK*z8f*z;pMRLjdxh@(C|K_;o{?RMh2I?j0{{%0h}|=_gg)!w-tR5C%fjz z{7v;={%0?4p7Zyz=|1sQ|MxHY#=K^QtD|>T)Pe0>4R7XaF&>L}V5;yySV7^-^!$$w zf1Eq~pJxcpU?`AN_|>lU;_rNerWLChPM`Sq{ICSOjOlfz?JJmA7!GVRVk~+VFT=>< zVj1xx^T>LEFBOP=pZdQ);@5uV%kk=u>+Uc5aewlL*l&lj4+k?e#4$F; zwKTYYWM&CvDC$&WC~(>@C&jSg1vA6v7yrW_Z~9*!;9JQ0Aj3$sAooLuKFftW_SKAB zAI}T?{}unnP>plb`qu*g&zFQB;PmC3Fnd2M!<=Vv)(j71*>gAD`Icw42W z0Bi5hi$QGm3=!sx4SGct4R8K$?5+3T`~JT4qx;2&?q@T6_^Ro6;D>Pr=NBQClDk|F z?){%JqxrzO)zM6;M?OSIP0Va-n8d^o`tQ1K!!s=gh6J9c^*#T66aKufQ9G@8{Qnox zgPidk1`H2gN0mKEGL^5+yt*&8dx1?wDHnsq$2*(_FB%)_R}>z&zgm&4Vd;zdj=cxW z4y@kBupybDVdvNW>%X1;s50E-exW4$wKl`0l`xn0XuQ~1C{7paXCrtRt#ZXg~ z#c+XJ;lo--hHm?_KZE1rkM0qx@AxTmruL6iSk{z(FALcPUVP?G?mg|9w zi=F5E6$YIgFwxfiLvJ*5?J5S-)oL+NxK!!=uAkCsANJ>c$RGKL168aHdh@gx?(nhf6Xn=p zZGS*!=U>kgr2#kNkILK^^H|#$7+>Ge#voM3$)G9Dpu@x<7VvMr4^M{@Lqd8@$Q;K% z{>zL%&13j;dyCeM+iVxa*%jBVT~vOX@5G)}u@!Die;FRw{6EInVB7I8=JMMHISzw& zvJb8v7RgYR5p#OPkzXEIIH8(h4}-x1CZ+lPJC4-HcH7_i|9$db`#U%8J5T$!`}J>o z_K)u?AHFwb;IJ)as5p~#;IXsA^JNF3nH}yiGpMmR+}O+A(B#lCo$2E9B2kBYo}P}K z8wCRo{)m^wEVx;Ji?QI?qyKH&*^3fn3iYqg_-+3E-*s6AhiCJp)5Kpy%`3B7 ztTloE^Nagc4L{$nO#j~>_-lXm<@uujm$NhYpXIpGeYN4X!+|HV&IjghWeT`7|6ul{ z)w~X`>-I7%P;BsN%zBf*ul2`ng##;CbW)U(++zPZPi5d_u-xc1ot;r+R`q{1h63#a z)BfidDSVj!m%-sZx5dj9ydPGb{ONzl|8>_(u1AO0^o2iScy@U2qX{}+o$tKf^X7Q% zYx%|lZ1K-myvshu!J+@}pw5fGIe&NGe)C`L*#0=3zxL@L-!pD}rONOlN%29Z!-3l0 zjA<*U@SFda`TF(bjrKM1haCL=MVc`%bS>`tFfs0A3GC6_e-G75q|C=@bfA7?t z@sER{FFW%4)Pr`D8BX&uR3u*g!^XZSmS5}tWXlPyyJwp9%V3GfE%nkkLIT`Z! zn9j>G-C}0o-p|Lxz{|Lc*P-A+YlBl${NX+O8p@_Jq`Mj%shxKEzv7htzvq6k|H-gt zJFA%^LoCY_-ui7`b;S%jz6jR~y!lD1_^Q#zqI2^na*gyX_ zVcN0sO#N)PpZnj%{&{@;zy8skt{eQmTQ9bH;BY|r^uKg@#ozzKj_yCsvT8cRf^Ra6 z4-8i^_H#3C|IU2I>CIn-hWP4J96jFzSxgud*4_D^?EC0`ps2&t|JfS<#drRZe|E{9 z@qm`r0Y?T0UB*wWdvq^}9(=ey>|}lcA6N6s=06Sj-|8pudw%4f!4}~poe;T|k*`FW z;gNsgMLvcPW%6+hU3+upd;c-7z4q_gRh9$Gq!{m<;q_j;z=%EQ!rk-y)BoB}`uN`S z+uyZ6>=_v|L*_Jb&Llj z70(=VHMP{?()fQ}`^mra-N`%t|JCEZB%rXI>Cq{P6aBSYy6(;W`TnTqx38x0qHET1 zmoYLN`7g0-FLx@-mE4B<^L-uv9c3K9++V~M;4Ym||EBt?QN>fC|KA0EeO6r`9k|@o z@H>MwVE=rE1hGiFng2@u-{)rFVO;8V#<^#%7{gXhgU|NGxdy$hiJQ#gdT;;cARrDB5`(+bfA_RD57n*a6sfAb+9W5Np0 zKjFJ}e0*=X>HqSWU)vx3f5Y(Laxr_u?8XDN4h|caD=HM2TwrG4$a=wq9mk@x+1@z((LZC& z_#=)%D2d~LV<4}^HwK2I`ct3nW-PnFX7Tk6!-b~$mWt_9w=>O~!SG-uM?lWXzyoDB z|1azRFpLXNw_>cK*44;@K1PT(T-i!Ye zuduJ`=>NITA1Cv(yr^aPm0WAy@V)Cn^BL{*E9Y4nF0ZMUxxmlx<+%F?<_#N|8O&~{ z{NJO}F^yI9arunD{k6q6{}&7XS66eGzW3X&hW9UTIUTs%(op@8`M}NlDI6|4=SMNl z`TN??k(sIDdA+4>+UZYm49kTAWF}8%dRQpgz+q!HRVwlG{Vc_I33yxwdUm_8L+jV`U1Ru=yz=}?rX02Zr*avp zR%!(M&I&9gs}< z`FO@(b%q=BPi^=SEPbHXGvJE(@9)hF{0uRQYvd0I{J*ukq31q7!yl(`#=gzHW(W8i z7?~J8F~3QadZ2LG=99S2zx)`6f>Udo%x7@DC^!1U%g>UdVX$Cly--~qTnI1Dr?ZCoR6SL-j&S!#9QtADBEC5;!(|XTD&m z&A-P&`%C=f6Y~#O*3Ww{{QkqYx$F#9jSa@EO!c!TSTp{!wLLPKfjfgar+<~1!?C?T z&&xC1+rjYQNT>M+rY{?R1V?7v-6^$W;@{Ip?TvnyGdOha=VVy@g7@Z||B7Cqti#E$ z=g&082Zf3c1fv)$dRHoP&v%rsYui-)f<8TvKNV&$Im#Zmf8AdE&a4UgnoGd2YGJAR0DT*vmWKCSJjq}TuM6-;YX|8-wyd98I|;&QHnMLdnm zU!Cvc;V?MZ@Q!PNHA5IT=RSUg4S)LA+}Hk>?e#~J;l->I>2v;;=l!XkxAcD@H$$0x zLu-R{IAfa3$8d%PoBl@XeO>-Xor!_nPxOERQ~f9A^>r+uvA`zZeV=?BwCPq%CTJKE^o z@_~ursHB{=F8{XHhT#372Rlx`bo^M)!0hLyUaWFze0M(UulL5XJ6cRPW%6T=a=U%r~TW{`SE=! z!;c?pnGbAdVl)+J_~F3dQ~gfWG1BbaS*gbjLQHqQvt1~2Fk=k+!@y8)Zm*_h_!(Z-??#D1@r2JpKLZGJm=KsTz|JVGmcV^&-WOxzFu_Ksa!QFpr85kbD z5vo7TqY=&gZZ1QgE;*Z^rKFt>T|2_Hs-UDy`hB7m-MSQ4bWO&Hh;>Yk{MmZBt z@t$_c0<%BzNt)l{lfq{*N*~*IJxAuttp8tr|8~n@SYXZM@#p%K7wn7Ok*FT;3X8>1W_Q`JH)gUgG!9FiOO7%F%gOB5%3p0)HglL!l!$g9%6 z_|IN9-QLST+rQGsNn}y;qG?>#&-Q=)l#%QyaOx-b3Ok(##ikr3L97ZN}$$nV|kNWQ~mHy7P(Eq~C&g8|*aY2rOm*EbV!7Y}#3=Cht*Uy$nVEAF4WcX`- z5?|T@-5HGEjW=;E5NDMAG3D>qal(J_hlyKlANawivT`DJRS;|F~OGK{4yzr~Tzh4F?vk;b~O)Gw-?~JA+n{ z{DC#6{-s|qlJM{AsM!&p)7!uC$K;>qOPv*XYIzv8@LpKKvghkZ#tYjVm>QNo(n$ZO z@=uCk)@p`_+DE$c9sj)M_;`<h7auw`JxL_zs;8}oc@0+yMlb}hEMy?{#*OQUYMccqplunm6t%l@-_zt z2VNzws|`{|ZsqF)Y-g|ts46$AyUV8Wo0-9%DT86b#r-;N{}(9+cJg*5PyKuSc(5;n zfjk4ly)XvG1Do9cm@>SnVo2!!!?5(j^K{*R_Dl9xckWR8xZk1k-<+fNPZ}BI89w}A z@L{m{9?4&`jG-a#^Y7a^F@K5+L;mFIF*5w{?_v43{D#-g)eP*60vqxf4m9qXd0{=* zhEYt{eZquIBi^+e!Y&{`rgz%u^da$H=qq{D1z#Moxw} z{)Tw%12sMC{@I>6nO&>DO0e*!nd-lt69jhuFkS^JHoGP|a59|T`#i5^^0N* zr*0mbdho=vvCOsn9mj>&|v6LwKi^bPuJZ| zIzQh}Tl(WSlfy~IhS$xPK75WA{o`y|@^jx6eFnxyvfcIe%?DhcRToa2_K~k}US2Mf zO>pGDmHaGoKHD`MTQr}!fyME_{Lh?Q7~PKCU$u$Xp{^mfhvi*0!-JN`rrdvL3e{{E z+~Du}c;noh{n89p0`>X~YXl5$z4`B%`v0*QLyqWyZA?|%On(?0X8xZQciDtNKw-h3 zcwcoFzQy$++pgdI&$X%i`8J1?-$6eD85gW>5p+~;yz}4v<@~tS;fxGAzoxeRm@S}i z-|J&ILxV(J+~P+25T{IrhKl}+d%7pFG?WXZ=dl);Fg%#c#voLk%c9b}p#S0f6XmiS z7#S)#8RSi@S4Pi}nf`{+GCLkQ~)7i|aT15ykL zTf5)v7c^kIbT+VHj@^?N_mk8AhyBrIxS@3*xUJ#05z9RWh6}I1w=&o>1cWk3@y|JT z`r>{ahJ^IIAepnFN95f8d;EDm_l*7FMfqVYv&5JevO1cxZu;4u$HT&M<>RmVhK(N& zzhO9DSGa?hfu~qzTARHc_s9PRb{`%c|9C-Efq|hRAhhATzza5pnskPSKvo5gfVU0C zAuQ)=cFoT?yd27BgQ7npy2$#EzQA+fgyp_{>xN7#)O-lC-%<%zpwSp{cnHgn=@!|tcbo? zZ^2QK70O`r?W0RWwv>Y&&!VLcd-NIV5hC-Pru;I!iX z9hj}>#=t1Lv#zbdmYJdK<*Em77AXJI&ON%Hk>Rw4sjjrZhL(Q$MSt=)*K7atmt+uO zsoA*b|ChfE z=R+IP7=D~%U?>-T5c8gG!Pf)NHp%yEe%QjvAXPZ0{xHJ_{WzX0`l}fXS267=3T6Bj zo$_y;7K1x8g9%HHgun&6-^V8}nKEU%^OHqvEG|2_K8U#ee`o!B`_g)DhBE61!3_;^ zE152wkaxMaSHh#0{n8=%DKBLiPPiNm;VS-b@XvSo;YStg6#CMiKAP{x*r3P|Kl`Zt z{DQYEHXgK_M@`s!7p`&1MKV!A}mkhECn90 zGu+c^$YcM|+xY77vXu;`*VijPIKa%f-!DKkp@p~cbO>w5pY|IvOSKqk^UN782-NOh z@woktCWFq(dG>Ev3bry%>0Bayrruxk_x4Bsa~T^q}ptE$v2cS?TF8x z#h7p{LeeHZjFE?7!JGYVH|uKxo+$lY6z6NqAj8NY_V7XZv42ep4z+%ZSrv@yg&DT- zeEiPdV6dH8>gN9rX@*lW{=0cUoPM&vLDa!yE8~QT+jE&`2si{Yrm%g9;d{c`V9d(s zZpWaonnC$dy<*+Rl}sBpOfD2qt*ieWAMeiKuyLyFn>By@Pd6B_Wpvpe4YIo?$Z)6Z z%Xx4w)QaIo*n!XMn0zMh>`(ji)y(0`t4v1$cg^+_MHbKOcZr-}XG;6A>VBa5@A*sK z*b51T?y*(+=$_-(W7@e_p5e#t|BLxpE@W5OGBAAOKE)C7Y1)7HGoSt&Gd8R|xE@r0 zu4cHxrl73wNVa9?M$rIW)~3RKqdK$yPoLH?Y?dlW`oYL|<;VPem%h*CvnhKO`R()T zBMQz8tksN4|2wq~e2-yO&}WeT)8*XIu+M?x!?b_juRLb&a6Y2>XvQ(-sW;X;-Dtl1 zKQa9OeMW{=OjCmT^ZsqVxu3N`oryvJZODPoYnTe2Il{-=M* zkM7Bzgzs}QF#I?Y+R*t-t3i(Qig)9=GYjtizo*q;{951j{{;qy%YWauHWV{6t>F6L z-(i2$`p<9UhyPhP{#=b^%~-{-g^fYzud#C9mB%XIPV=#BDgJNHd_bs%vAa)v!S*xt zX1}*HTxb@Uu&wF;8HEKw4Ik8H88RFkHmNeqxXSR2UJ11CZzoTZFlqkM3Mim)$^JDlx7+5atQ3= z`mlI8SArhfq(}O{|1=6SdVP4>TLfkEiMvcL8N@eoE6mOZUMs#i0-JzHO^ z$6%4n@giM#ff@6=hsjdRF=h%2Y#AgTy?1bU!#VwbwIwLo-(hfYY}l*wqH{Y_%+q?I zqIiY_zfBJ3J2>=){R;Zgz_9!OO4SEv{~f=~!@zE=_1pbwg4}`&tGE)F8pPRNl-3A4 z`9F%+pK!x{?v1D01(_M#W-%O?{5SsJQ%jjhR*8&w)&*x9a`!OsFaxvPy;m)4KRjNkb7e2)7%`=Vcc z<-z`V(FEquhS(6sZ$@YH>UkL*m+fa``0|_Sz@+Pc+80zW(wsI&(7~ReOloF(~l&DeszZa>jD4tkG9{rS+9Hk zk-uTM$Eok1JE!F~xbidT1U}2}us^zvkzqF%!>wumPb;hZyMFv>dWAfL8khNk z4B~F04)?eP41{Ln&G_&0@xJqgQ}>x?u$i*RJbJvjXAP5#CBuid8?i&roONGEJr$)!;J-*O&T23v!LK693f*O`KE z@?twPiodNdXSR@QFtcOeW%v^1_xk?cNB$d^`_%t_@!y&u;1e^0@o)K`OdsoiPJdoi zH;ZF01H%zHEB9Y31%iC5u4^~Pyck3$&uMEg4}(Pkql5DA z?>+x(9c!2vVi*|at^csy`aO4TCWC`)AtwXKOP|&Ncb?WHdC)|Jl#m@WM0l^ZmmN z4Wez&IT^~V9(0B=YPoLz!Ct|*L|);p1m~I^+Zlsi)^nZv&$Q{k2}445UDTVsa|L&A zeq7_;5Xbj~ov~Qp@6JCfPW|~9VR%$w0po(c%KEau&M(Y2F<%$>r{B@v!Oh@MWpDlA z(5fG{G9C3Cfz1cvl^EF8@6Xz3e|}$CV`KSwd&UEnkEYx^|F!df?Bv^w_C5SvFHgiD zjrk+`*Wf7M+MFkE?4D?Se{XrUu~F@_JTt?AM!USwfA4u17RmUp1~u}y8Ep5eKRETT zX1<^30mgi`?i>%ETIh48j#NHso6Z`5o89bEjvKcJC-27a>O5uUb z`~P-!3VJ8G4Vcx_Urk-X$TTgeHp%+({U@w9Ocf8D|Fe7*<8NOE0Y0AV-|UsAT`B5h zJul+09#Yai=={lKcWeGfXQu!N@qm+a zH8=fue~qiiSwWZWlq$0}!z$hnqJi!a3+s(Uo8G(@?|5At$Npzo=E3uwj11~4nEqJW zo?-Z~ePtrUf%?vwH?$8N$lmD9FyW)|?@IY%e+HQ{4u+~f=e7SCi7?na{Ph2=`~P=I z@9u-L<}8N?OHDcM)oMS8TgC7+fuTUbftewfPv!dliGRZisG*rWXs9ydTE3Gzl6^Z%JA2Lvg6_!uoGS;HmF_{pvzfnmaS7O@H= z2Y==XAM=ZJbUs~V-0{C%=HvZ&=gjjsbC?+f{_BT%&NpG%vr}o|@}BuojO|lCrl&sh zKgh6v<==PBNY)?8YFf`0)r%UhV9Dv(CuE)3!Xke8=`+mGTV~79a6hSab z3Jux+>QeMmox`GXa5-;-!8>2aFQq=xj*slu9{)Gt@8xLS ze=JPzvYP^RHJGJNMNStCa6F*?dvdLuz=x|W47`j|3@;wFE>`OO%G)`A+2cn=W?KJx zy$+ad`d``9aO8WE_1{~|xh_aCoHd7u8L|DL?{xLkFW!=KmR zudyA_c%b6bFnQ@Qy9PInkL&^$-Zsqnxj9@xPwjGGU^4mUCp@6N>-f_;N|Nrf`ZuqgE zk>UR;zD`z#12TUYq-XHmI9Ur>|e;Y{Xvq&Z`mKbiSM?LWw`Q&)#LX355o4xpDz3rnCbE6`IX)}N#!g1>Z3kZ zJ4yfJU=XMeVUuLg$apQkmFeCgfgPr4Ob*F!@{cS3bLZH_c`BQs=JccWdJI}>wfg^G z3NdKBnS4dA`b{Oz$NI({yS7ShP;x%^*ZGg)gLMrTW(yd^o?)56xb)-tt~d7LvLdcu z{+AnmTi#oL?`=bkwL;wF^hAX(Y5%p>Fn*9^IB=DbAwgWVF6v&gQ^TB(`DcC#v&_-r z__2T4;Ya@&82;JWDy1cIEV+1K>l5uQO!rJu|8FsPA(7vI^@qG|SUH2jo16dVKX_ZW z<@NpBOa|f%mTCvQb}juaU&woSzHaEv*1eOB zLFCdth6TO#M~@h6`p>vA?rc}B)?a0@i3LCJ3SKy9(omaQyNZ49KdGr-zOUTxuU(zF zHowt9LFMTE#)f05_EJoCB2FI|U5?l@Fp5uQH1u8D@S=Q=bb|V0Mux|0`xF=o?lV8Q z|395!f#8%)GygKPbZu!eI=0b4TT@!OK3?#eNJhWyH=8Lx>i2y0Q0S?R`m_AR$@59} zuece4kLEBisK|a)e|&$3(Z7l84&DEECH{GQLjC8i2YieNq!{NLFw`hABz$}>F-@Q$ z;bOVMf!f#i8SU=5|FJPV!{D%y%UQwkfDlh(^a`do5}^&dSsC{JS)Tas@is>8`YWQJ zmu|8AoV+!f&`w@J(dZY}ru{#{0gHH!Z}FzortvA>ViW~1%tdcC*)_vEVI z?6m)=|9jTIJT8XGFP>+Erg4HL80R#7@YniYuWSB_;eg4`f0@thJ1^N+{qJ5HsQx=% zYx$hD4VxJ+uH)J;q5JRce^2J$X#D(N_}BkOJB(EL9x_@e@H24lk7NyawEi$NW6BR} zT|Nc|C7I(H+ySBqc5Pt{JdM_DEN^}=9nih@f7K`ZtxQb}4TsX16Yl=|@^<6#dDQ~- zGya{rem9>j;A4oT~p0`=|+VUcWKl+h>L>US`9G~&s{mpBx1~UdNh8tfU4yRh!QBK6m;Snb2?h?asy@ z^?OfNJ@B;nz1(BR$|?Ml=SQ*{9Nn+YvA~N#l9`cFc;=E5YRXEJJG#!^_71W+_k*A@hZmL73^wp8t-0 zQH-0oK1lns*0hHmC{N;TJD?lN`hi>M@7FgI-v7G)blFAwUM`X1wK9eAVIKvEHuu!1WIO4(=2-{kO(9<~^^o zDd)4ec=*x(muAyhe1rbqV_;atF(Z`WSH+}h{}j}^Gq-XlY*A$hcv&wb5O8jZi z$`|n^1+NwU{#197{rDo(rd095+C0uVXO`M9On7|1G>d)1gUKJJ8!d{u_M4$7SDPXD zW=qTu;r5UG3>)m?g`@M+kA91BJ!84_zuOhBzH{I1IaqaZUNlPas z=}%kBWYhVkp5f;I1Ey2|uH-6UYW&W0z;k0DqlFgl<_GUr%QCQYG1V|K6gI5?p02A^ zS3g^H|COX9wzUnjE^-w(JDd=my@IX8h;hRU#)buN>gD#E6l<*A%E++jdi8GOgseR? z!nXgbb&I+C?p6HsV2RMiNlSC9=XL*xUzI&Azbf^;_*c^`{>o@&mwk2O*IB~1vOD}_ zSn}Kc_3i)5k84JC*{A-WDG~EuSxHv%h(!t4%>PSnxW25fw0XOR_1iHMqn}aQ3@27! zJ@8}BTPK&C>B)XMA(N5{=Qt|l&cC>qi{WUa6+^@Cf5+_@9OUK075<2FGMI=uME{wk z_cODp;n<4%{6BWrpHn?@KRx*ohk;{ggXI<`vkP1|m>5hH7AXF^tra#`%b}VfBmCd| zY(|F7c?=77eC=y^`O%3ZaK4m&jZ@9sMgQiizY}1vc+qC~d(F1zoZR&*ntT4M6}J9Z zvp}KN|Gsso!V#C-FD`H&Sk!-Jf5?LwMYotvuIp(C`tx|vq^=Jq;#EakKTNkY3;bpN zp7q0OrY-CYmD&&Fw&rs`WMc_QVPJVv^&rkx;^yu}Jn`EYQszAQwc|}a)8+Z!SOpjY zt84TD%N6WG*Ip^M=6jZ$6%H z4*l3}Yu+bUze$xLgCir8jfLgHYi-5@>-ZTi{I*W5_6#^b_w$|ER=WQzlMlMb%NzgR zB~%b2mDgcE{ol)1_Zc<+a4~J;R+cH*+27VsTk8CP(`D{DZaX#?0R|Zcv400b7#t70 zukc>m0P2>VdXXJ?K7(VzqxuF5vsDbIS1~=<{;&L`^1poMIsbVW-Y}jpna%J~;_HSq zUS@A=jupMnFL!t!Nk1a`^;C*T%l;qYa!S9=4{u|Bv+>b?hPBN5-~Ux(2sm1CPvz@x z%b-6SxfwF1?Pq1M5IB(C=-#`p-bX~}a1zhb|Eg1-SpJTmA;5h#>GIizeQpP07QHn& zpcS`xHp7A(CWk9(s(Z`sE#3dWN#ME6`XiE$Og>93vVFjCfbrhD#DDek*MGe_{Z~tf zXhJ~h>s~E}vp**PFlM-*TW=sb?}Zn`gQnFC9r9{VLKqqkM7`?$!u%jxR?$y{;YHYi zs4|NUOdGDa{n;yE5T3`t5TCv>DU9{&rab}ytDo4N>v{gV!(ZU{dX9&^ax4r{c1hxe zH$I0jJjmwnsK36pS)t(NHm-oy&h?7_+!nlv*L^0P%Wzyqf`=hEwPtNmrC)Im1C>+%P#lRq!y^3jqaG0yE!k;7mw>|wI&D4;~dgF7* zk^h_AkM56s{Xl6&)eFII2Bo~dpR&wq{|sdX|Az={m{OsewMEsyF`DVOh)&B9 z#eetWEYD1B)2+F4lEopK;l$A;Ka@|a>o>49MCvnCtY(ny{C}6(;p;aBg&ffX^W?<; zi`xeM+JE_l1cO%5v;C?J7ozj68_F11elZBe{F=XD;(iIYe;2;T&px&JNAMZ(;CbDR zQUVUs|LQzlRB=|e@qd6J;)DUec;E8U%%gTH9zua zW!Uf2>Zfm^;{`1G5PM1#p`^(U9^gkbC z!mE1>3z9!>k7KB=l4W>x-uI97H^z`DH~Cfng$X=Z!*WfS@u^b!kH$ELtKan(y`SI7 z^Py&+Sp6r48HfCv?9WSwC=2`&+&Eo2=;j{*t@T0-7Db;exBLub9Hay|D-MMK$IWwFVMAB%MlGJFue_wGq%Qg_rY zqir%D<;z^^j&n0unlt1mzj%MP@;1X3&j4MPNsZU96-hBXnDYOqocoMJVXE@H3~Fq8 zpc&3R+TXg%85%$D*>h}qIn#v~a&H+fFdQ(vafNL`;eKXQ#toCdGB!No;NGkEKcA6f zh0=m#{~57{ROFc`UVHz*_s?rY%v!FVRD;R|C+J}*NItHzQh-iD=TiVYc}it{zT$s}!=P=J;2spEyy&X1?CQa8MwCk%58foVSr*=nR1Z7jp(N6_y#c^-=$;d*c2j zO4cfK{OxOMh}Hd9DfCwaZb_ne_Ma7w$NzL{$~E5@w|U< z^Gp88%}fFcCMnW$e{r_{o?dDB#N`bMdHy*N;+}DGZDn@82&xQ{S@SWut6| z_4Gfs;(rUc70gd8@=LC>`QE?Ym%-uVLaAq32TGn)Z=6*1_y?ngnL*m6lUxs;u{s!u z?dgB$X)V2n^}|1g2A28yA3m_0eRr?+n}1>E{J-D6C@|DiU1JE){Mo%j~OO>(0U7?Ok|8@5Ei5-99+c59a|Gxb{oXy{OJZPRje|fuJ{j5dzelK8V5NBhV zBPmd@NZ~=m(TPnAw|EOY79OczZ}KRI<&M*vi;sVNW;Xq|J@-i8@f+LMi~SGyV`2En zfq{|H@qo{lsS(~^Ed@46GB9+%4P#(uWUy^KeKX=B{ZdCkAL5fr%&G1Yke%|VO;fo{j|R+ixoFom}%5Ce)#Wb*silj zDE(l(F>}&>Hv0ooG5?=1-nb@kK#Bk2IsV-(@#+6JISD+z?tT6Bg3nbmpK=|LI#VC@ zr~JZabH)b?geEc=$ZcHj$zNNyk~f}->4^Vi=M_v60t;3%q~?nzEMR1C%!!|2OLW{>{MP%P1rDsD6pq|37x354oE;n9MH!y~Hn2t-I~`i~9zQ z3b*d+Hq<##bN7vP)Ij#3Z{$F)+v6Xvv z+-$Da0fBD&pA6e>Fjy!tzhD3KaMIkEzXjjdhr9hfD*sVTn1T0WI%rhb{fHt1!z2AZ z9R?dFhBG|Z85o;ZGi0#-Vc@8+zqo>F4*M1+sn7<+msdj<^Of>aZ^7bS4e`8Ml(fM-X+t0sc3=WUv7#Ku^D|k7KSj;-@pZ(QN4vhOU*=>#A z)1x!T?mUtHJNm`W32UTNA6P7IuX zI-@wYtS@7dDc-^OV8ZtQCwDXa5K^4MaMHx1kYnTb=7!|UA{LTq`VOqmrrmm>;C$fG zTn2|#S4|ImXJm*MnBHL}^FOo0)|I!g^GDB)YjO-?ReR!dn;NCN?T@IBIcgyo|@Bg zv_5+3kF7s0|6W~jhLPa_gYCYl*%b_Cq16j?873r7aL)TZd1n2U@IQ0k%=h{)99S6B z8z&#GTxRlfBEth!EynA2xD+@N><hR-FORh&(RV}ad&&tJUv zzm&h}s5fTV;ml>zx&JYT?jipP<;@J0tmm{3Z{jkTE%5uXXCTjh!KWVcXGqElanCex zKH$sXQ1A1dsX%&x$5e)=32%iMZuv1x`5Yd+^bhNz#p>3~j1CLE1RNMHurO|CVz^zr zdHHmP2e0H>e@6LAT$s8~@%;YZLAL)s`t55kV+hc!O#6R2>yG}?b$?v%%kRH^PNm_# z#)6%S6OPE&*1!5b`N!o)@DCr68gWQ{^k6nn6&=_^@TQ)TW|hXc6Q)c+wgk6to?xrpO^($76=7M zJ_$Rp`;GKRy~W`y`=42y-6MGX=Y&-(CTALSKCm&!JY{EQY-nwK3iL*fBNq~zPeX6{XTc4;J!O|UiPn<>tZuM zkHv1;aZ{NWpZ>d?-pe4wRH1c%nZd@gVSRMyvi*-TTGoGGyTtR4cHfW7x(!7p1tDuT z?C9U{BY)M}`qHgG&l@sNo3cVYNl46#lZ`>^H9NDz8sBg7g`N8+|Mj=HxnK7G>(yPFrIxseHwJ{_sHKhGt`M+M}=zp%o za`6*h)?1!x-RJN}P*Jwmi$S5m;lLaYizhSxD^A&XC`pp3-p2A6gTuy2{YET3$DO#C zl=xV5$~6AXWnyqT*{lrlf(vi|t5Nu)FEC$%p(OgjGzNo*#q)RC zezRd>xbn{NkN&#{)w|wRo$3GejWIEdbp+vZAWJRn6sDRsZISF#)9pjr^#WOUurS2LO>v(7 ze)IaQ6%0!>85mv~i!L{cyZ7Y&?ely!HYP{z@$fR1tpBo!sbQ+jibAco4h)qHT@URz z8IzUySaj|%GrWjiH|yO&y&g73hR*+UzipFXddI@B<4=Zn{lTBjzOFevbT+`pvZNBq0h4L{-+eV5;KzN&i8 z=4rA&H_esJVQO#={k7a%Bjf#lp_aMK0tHd0H8@Um?wr!n(D}n5nqvlk)tb3KwlguX ztmXa2aNufe_kL!^sfU(ZGciQhZC)G9@KP2w|D>CAgN`O$p_2C3hR?L-|9NHRPqkxDk|bPQx*2@z&aTG#B=psnz0I~#)pyD7sS z+4CK{HGXezY54f)x-|nsHD|l+UIqqR&3|$nJMy+aS+2^U!2J9!0~f! z$<)xsz|`=0<{k?+mJnGE36aeiyl12ZE}RlC5N9ypc7AZ_$Ba93V>@H-egCiDQTu|A zq2W;9{TrWWJd%IaIqdic5} zZC*aN-OhMVg5is9c*j&39^D#KwX+xdI@bQ#aAWlmj~|-r1o@R#3H6iB;O2eb zJ4_5~1dq=<&eE`Z2jhp+%(d(1NA>>Q%FG~E_-pRr+gaWp^BEZauIqbTK4Te&*Uz34 zD_rfjl;)of|8tii;IwMQkMNNH^}5fuFual2V7s@ptho8VzGUbwMh2;$tEan5GWZEr zU)`eN`rB1eNJuz2(2)D%vNDGUdl>{ugc+WBX}z8nzP-%-IruoBK4?$nxoZJfyEmI-T(MM|CCg0bh||Tz?NBmpKEEJ z{khuU`Tvzn3G-{eeYxUz{(si=)Boxi1UOk5RF9+yv$VJvUeZ^a+?=E*8#a$Yo}ppK zdB-<b^Sn#n>o#B8evxA$ZwO06_ zLto6z15-ZQA6WCB|1#&jC+7V+^CwMi{UmY3_E2{HcHW2aXHObT|9>U-|NVJ#!vCi~ zJF}myA(frw&yoF%3}4EsZH_WHY+S9yD8$qz!E{3SK{amyyK=*qA90B@(xWslFSiUA zX3+Rn)Xbl^s`*EKPBdc%FT=MqhiW-thN@lP-`fg&ot3{*KIuLWLy@3BIG2sV1wMw1 zi{~p8*+2R_{&9~EKS*P6NPJ%Owvy+gzx~ut`^d`M>5c|AVIHlFNM!VGIFF-`LLc&uhvUo>;Rm^!#@Gqg}H(e)Es@*H0x`%0FCF z7t8s7Th!a#$HafD9Fbc4{A|BP{kD}y>SeDs`Z_R$a~A!1zU^1KfBu~2Ll>?e`!t_X zj+KY0VJQQHK{C5QL66obZf6g67hF?{63<<~nDKj!SJ1o5+ z!KlOjUbH-%Iffx2pKZ%?Lxu<2%o*&u8XOPo{}IL*CCQNZFM0BUj}Z%g^dDtDS}!(F zb@Q72%UtSgwbdtaFobzEF!Xp>Ph}7dkzHWcsGjrn{Ji6~zn^~K-lcYFE2DvZ#vR5B zJPh8s3=Nxpzg@YfX$LjWGCASI(3*QvO4{8h!8<`*4$ITE? zFIKJF|H9#bg7X0x$A-v%&sR4Tzxij*=y2}e?&^P~SJ?^}6zsn|U|{&@Z_e1jSIpjU zUFAh4^NsX{w){H($_tqvEN*z+3%WVWmb-aY)jxs%Jl+2%tp5?*+Mu?`=VN^6-#?~{ zwKfEGboXwGeqkQ^gP|doJ@33SvqR>S#rwEsA{+q-kU|=j(7S8yoa3^zv0z>{;O@>$B^8-@8@--;3vwZtt_voQ-!&9fTSD84t z-p@!VmR87}-}%i(f#J?cUeH>7l~-BE>uro5u{QJsJ zG{I#Jd&hoxh6jeb`R>d+ZtFgCpMK1@3gZb|@q;Bx^hSGHiGv_-8>EgCz6+ zIg+CPXL)wm8`xXV=jc57A$!kTVd>19c{g0&INw?N;`q+{X?aXB&$Eq1SuUtK%*ZwC z65JTb;muKT#_&MdqjPx zXYl(k^!}Uq(fUK-e=?t17oqOtEw85W35v4_OU9612 zE0oQSIVBkzH^eJd{%^Q1#~@V8&cLOR+hN~YSJNHM=*<7?^b;MXPon>VW^Z&5XSgv@ zp;}Ie;oU2?1HYKN>sQ?Vw7#B1CQ^mI*?`=xBa|FwcJyg^k0{F848>ka_>GqTW!E1cOjaA;V4_Y zKnjz?8F7X^(f?QUesHcl!pi8~(9n58JFt7d;OT~juV)yh|F|B=8xiuqZP{yIVTL^u zr{*&<@bBlEp(n1GEZ=(bd%mgIjU1LOOC3P2ouzmA;r6@C2b#ZaP`oE^EmnEz!|Z8n zfhX%jLX0>ATYmIwevF@~W%+1-*Y}@X_no42LXTNgmy7*Qk>2~S^zFOn`|5pW{pTvI ze`vm(k%6P_$K{fSxlEg$Uu1Y7q_`)vq4`dO3A2@8YCZ!aLoesLS8p3moDuh4x$MmS z{I~k4->TVI{z!kcc1Yk|WY5Pjqi?U6_sTkUCbQ5t#XKK*Ta9jiXJ^b}e(-snAb+`} zK&SmohQDe5Zm(s}yT_gYDu5J^*k4ikXO+js$p3ARtiJfVKhOR&e`k79d(_@uD)r-e zwL^Lz<7etvJv*>7$tx#d=RT2QvEMl>PuE-vy?LLJLF)fv28J9~j{nm*83gK7|A~}w zotWp&+@LST&}YJM!Ofw=ww;lodT9p>L+Y;RW0Pw)&Uq&LmxZzWr_1Z;{{kUiw@>qT zbN}G|*YM+i?lh%`4hK@cY^|`qrGM=bFGm8y30_kLh1)!grks4P2A)~Z?_Xhyvb zO~SL%l`~ivF1SiaZVZsf=4AN%Gw`F>f(_0Fj2sqPJl*l>DhvT{9^O~wn9;FEjQeEW zMlOyO={yVpf!75R8X9gfADGVa_R;J2AxYo2B`mgzt9kh4-(Q9UUl_MAH9XTgu(a0g z)@KF=g?xrD!vAM89@smZ@nh{?hnU^2drN=LcmG$xYS3vv=ikd6CzK!iCm*X<5*6ER z?7GoDJdGhj=DhX($-y(!BJ}#LQh%*YT9WEne|QGNg0KTx2NF-;VN7sSe5C%bV?}Fy zwcNKkX}_Ep7z&dZ4k-Tmd(Mu5m2r#63x;_Nd{3D#Y&<)eQQ)srkd6o=lf>QVC9i91 z9TN7#j|6m)!Z5DjHuVw@##qeVaAJTqgpB{PEv%Z21GrrWg* zH-Gftex8g8x?*H#I9p20xUfgg{nv%0BiZNPtoRYh8fyMiszmjkbep69 z_y4kn$B(~x*M1;>g>S>XjSf*vE|2`?CwJA))#LdjUN6DESnS{1$^?cJ-(u%TF*p=9 z==^bDWMGwMI4Qh<@c=v1i<4*n*7v;CeU>7fAlu}-pNEfOfvp3>1`dZC58_ujeq#=J zvq0*@!f68g&n`c*zFYERp4CYK14m(|k9L9VEN`k55~8aaMOZFKC^9mHs%98DI3BpZ zyR9K>DZ|I<#s8NvZpfPTe~(}aTTUM1jk^!N-P!(Qe}+(gzV?Ev^S7=OxYMmDkW_bZ z?df{1L;l^T!!A1~DVl1iB?tZK?@Dz4W1pZ?DZO6w(nEWtYg~cf&)B_vYwq>^)=~d@ zw*?z`7REoUX1pWJq+N06k5s7~V~^C#`ZL=9L_i+CQ9SMK?;Zg)7MZ7tua>g0SS&kW zCg3ocan~RJ{XVmAGV&FDnjPA(y;35f=y2b`eD;mq-wyey>ghc*dNh40({X=p$$0`Z zm{@d<-0L_yrG+i*4L4{KG^e6>KiHHRXOMAjc= zVB9b0@cy_Ii(6az*7qVzc}o968t*tw+t2wi zUP@LV_+p(QE5i#$W_Ob7 z-0t5G|8vxAmB6=~ndh75eU7%9b<{61bbIHI~^m2F)}3dY3Ed=dJsHZYj+Zq(%R8&tvFPmf%~Sz_aG)uOmul8nrWhoXsrf6n&bzNV&g#d=Yt%ssyA)7!INZ9LzR9qHK7?dfA~@o0V0 zq_EB^MuiJ6lN*+ZU2Tz{*`5HxO4Qr$~l!M)3+R4 z-}_>J$kTtTx1Fx->Cc@0KPimsqmb9X&np!JJ^8wwdgA2UEMH%LRBtHvSnFvQmspwV zji4=)b^fU_STJr(?{~0#m-6jP{<L5jO2pE;Bgl{bwjn z=r%n#Hz$5`C}VZasXzLP=cadP-><7Rzgc6=@S!q}jiF)ZjP_$c_9@t1`ffSX|8I2c zo8qf0SKpUp4pBHz-s14$zSE!d3-9$8-;eKG>}xSmr2gE}h#xQcCM65qd&5yZRf1v4 zkJDNXJjVY$Q~n=h*bwDqBFS?7uNuRg!UGn|7?a$d$(I`a&#nI`UOjb&DdX+W2G9SN z{CKsGddcSq&Ixq;Do_+ml+kt6J40``B zr!f3x<}gTE^Ss1kVf^B1Rv!)nhXh6OTsDSX_A%f8U)4zXyz9Qx_sNWRbCWNJHctO0 z`PY}bK6Y!DlyY_5dFB0D4i}2oiZZZl;l0Jkz`f(vx$7^D|A}4Na{g5wu;-|e* z{&!^u2kwNuZ*Jc8XK)bz!_v$6sI>V={o*SE^^w2$PyI<&`Il6$q{gTAF2BCh_S=V_ zg=)VZwMV(^neXPq)A`-i!NJkd!A`}Gn_1ymVqwcB>$6XTRU5=uWHaR(Hfm0I&y~Os zAn<^h$(xPgjQFHI@w+)00t5|O@AG`(k_kP;#}e@7(ChBYz$1yM}(@{qJAvTJR_)=Z1np~-*Z)l2S+=i znD#hLF`Aro@5Rge3=CGQnSNBVzS`#cAy>xcc-se?pDclU-u>FSsCCQKiRVS4i`g5h z<{XJT)LfmlK-%$r+VcJ1t5-9uyPx*p(eaM?^WMj^a{OUD_`hA~|9o}f4=k;+3!m@& zbEkuu`O6Qh-v0+pc64zakov$5D8c2IHGqtoebg$fCvA!*Ff~4SbVdY0DH7+vYZW0U{eTGsMYqqgu zaoo^1(PG@wdY+kancxMT|Cj9=b{0wPX9@aJuDC~tMe1+8*30!D_udxbI`P#%yK&{C z51)OQna-&xNxZLI9K}@o=&gi;g7JyH|8wvDUmh3ZnEsuMq2ybB6T@$oHre?NoD3yD z**pK|7`FCjE;T6e`${+2I zWOs_y-F+6s9FFXD}ggZg{ z?(=(ZHi_B#WoR?|Z{H(-==>esUw7BM$z|`a%Vo^hc5p4|yno`t$Q{UISzPx>zi+t?!;Q}j&!4ltTF%Ur#>uou zSMk9PhVZ&=_Zu6WeV8k*vkJ4kkxFzru<1B+!;hxpdWvtZOEG=BdVBlMwjaScsqJ%D z9avWOP5InI?jLtEINvN#4Pavt;5ei5>!{j-1a0N@qSrRg%w=fki)CdJvHnsRb}Vh% zL%|1H47$7rxlb=!B`{%sf~3BfBWPng_5BMwWIxllt8&Vp@PJSA+g^xI z{Ca-z6Myd7x~32RyMFL~{%hUvqv~AzpUkv)?!TLM?L041f5iPr`j+qOJRgLwRAtz1 z-}%2v_2K3}>JP1-UHAG^zIUd5%m0L+PJ5x*lcN^p)ib}@`Tg_hq)*(A2iTdJ^qLeF z7@b+>(A1#3RqIBK_?sC_ybKEAcH0?@n6FD5|H<=lzsr)d?->vMWBM5C%#izd*7>7% z7$$`0G9A%Ny?^R~dv`|E33^bz6Nv-}3S7TlMq9 zmcO|#8g=5EZa$xubnoo>os(_X)& zB}eTvejfidF|$4LN2yHjahb{Yce(%2Ts@t;YLa7NZ^70x3hxxp{JO6AZ@xhI>??8$ z{xW7IEA;;Sc&=WkYLD4fO`nhY?49*nBL6IZ^vI)Yzr|e72#f8{|D9i-?|ymzK3}f? zUJgfi8J}=#@OLMFV`*7xc!8Ob-Lf+MKwaL0to0KASU7eZh=_}JU)|K;pRz~s(1Y%Yu7&N z7E*lew6FeP{mNTL^RK8JKU?+f?WuojkA1(D`-{86Zzs#_mi;q$>)uWMv^Mtdm#2tmnIWNOj6J@rhsk6<^CQUsGQ)!Te|D!~cS+^|Ss(8uQdWTeJVnAL&Q?mo)j* zi&VVPUi7wDZt98Y8QfO{eKTAcre|@*@HH$?6TO84DwM7aVmA;f?t0(D3f5CBp*= zrqrCzx^afji?0{;R=mz+F5zW(=A^JIfQ@m)rWl&-l+d z*8Nj8&x@4rpZ(iP;8Wk`{|%S+dH-mhSG|^@VV|GF>;$p>|Gg!*-cZ*}|IJ;}Eq~-| zzP9Se?N6J2@ILx4r}w{i&z;YK-zEP1VQ}dFAC-LXKeyceiRNs!|HV5@TK)@tOpW&C z&Y7Bgu+4t@kKgUJ8pH z`hSs|VfVAOji>JVC)ZiCvE;0%{OddA;k~PFk_;Lz+7532z%;>pL08rRomGq}5;13a z3^`^nY*-k@99=VaxzV48x<{)b^}Z%tJim+ife;VFl)F>9d-v^+|CYaw<=FEN8j9%- zb&zeV^f0x^@ZBYyiM}>NtRsOx^ z{kZ@0>u$w=iXH!1TmBnAisJtNZb$SVe&3Jo+`@}| z6b7crE7)|Fu~h^)gfXYME_heL?6zb3@xVzNo$_D$F)Dw)&ah!d{zJwO(JU_dOQg7L zrZa?IG|pvZ@Vizz+4k*sVJR-XtGdPaL;eT-HNQS}`l9NM@0XR|=VI8SyjYge;o!+b zvs>=0pa1^(o9Ab1D#O*zztsxetB~+ER|@6}5u^7lT- zd#b$e(f*}rzxOgY?5#fa$6TxT&HsJ#n=o z-@fG1(I)vOrmuf}L@vo%{#m|Rz9uIqO4anEnsYDy&wGP{udvf3%f2n z2z1!O_@OD{sdmd|yT=XhY8kFN88BGP3{~G7_xZfMJlmgZ;iY!GK#p%u_N zpU)JX8cvWm2<;YCV5-28)r`>EEUnY zGu7<>-<(&kOUmlk9PPNjLgIK#z3NBhyR!Rj_p&m?`!GzX{plF~CgDl?ZlUnxD(5%6H_m^vb`(hH z+RrC-|2N~+273mEdgniF7Bd&@WmIHq{Fou{)1(-uzNcy1fmNT_Dysiww`B&*=18}Z zW>k-MwR`&W#tn&xGrJiUWHB6QDP)dPPS$4W-uv@LEa&ZHclFm<)}8Gl|NRu-EUb%L zJLl(|o!kGvfBdtqEAQJ+>qGWhS|@&aCl?0#@O*Zfzv+C8ed^ymLFOJ;GPBb?^xAN z^E)x^is|+J{LlY%1@6ihs@s*>ulGdLB|81D+XW?g-G9H{-wcnbe)Do6^TGd4tD8(& z0z@0C>f#s*${1FB+P|G?!?R$98DPv+a{+9ho1Kk}ca`0tf_#&>^9*VWc4cjv4BDP@60dFYCaxb1zO_X!knA>Q;0@`h#(-JePol*)1l~ zEv#7|*e~ccKHYLrDu6-ZI)k}CBa5@cs-3J0PXCo+>WXD*c(^NXC+j(Xon5-E?6q%? zGc_zbYHY6YcDB-OMV2jhi_eQT>M<;sJ$29B8O+ReevZ#<)+KEbEmeN;nk7smWWN1m zfukWlOCBeR{VVbDJO8Ie>rQ*?njeKLRqmZnJyNE5%VyW|Mehv%ZtT=o_`SZ`xL)_) zl%Kop(r+*|*nayW#h`G6iJd_~Sux?@Rjz{b|ML%i-GBDof5tub43FeX7#sR_ZPZRU z+rZFu_hU=N{t3@>S`-?Rw#&FhGhAkBV94U%!z!Y4Sl%JDY3dt+`+s$h?w4lBU}SUC zK48KewtJV})*F@EZmgAjSEr}G%a);Hxt!HXp*zRcT=y(n<8HS5=dHT!c4f>Ab8Gf3 zU;E(Ol%7J*{j>kOy_Np({>fZ|5qX=Y~Jbc z@p~BKmYMmdFTY>^yK}$Z@5%ND1pXc4tvjs$cJ(^jZ(mMSzGiCZm~q}jp<&(aJ4yZZWhQGMXs7y4V+8hqzp+#hym{b9+UpS$Xhb#AG> zy7la|KyO=$^<)582dIQqdBsmEFj=~^d(&OQH}BKshFX$v&1K4b0I6!J1>UyjL(Yd z8sr@$|H>$6i1)NQ?0ja%Fn#WEt8C6KnvCTv3_2Q>FM0IKHFU~fa(<{=o3~2(E>p|* zL(;$UuPxh`$9RDMP?Ts}v_eY@5uNp{QZ1J7Oe>oVMV>M{4eN6hY{?&gwb zxqnFAvnxN&UHIq7{@DI|!N;aI7+!1G>G!Vw#gqRRd+XJfHavIs3;9r^^Eg|a+j8Q0 zCWc4OixzGB@pg)G-{$#$O!ptYTOT!T=I-x{d;ddyv85H*;O6+rh{N2Q8zH!ex%EOo0s!cNiHZ@BU`^ljJmW za|N6A{C$y}yM!;ta2I~wJ84Jg`djCV3oe`Ph%5MbESK@XXH&JP+(aF5>-T@lFO?OF znTzhqe|zD4_dNbDpT9*jTs?O=vG4QDsk~)BrZXLIpZY8DgEo`jrkjQn<$F84cqHqS z9AqR8tv~)NqxJo+i<`~Mzv@4~`)q&ToWHA>E=Vyvd2blX^yf%??89tuJ@`~6X~}y9 z>jzB@w*EU56qK*CybfzPbFY1lHS;S*$EnS^Qxsp%P*vkFI9h+Zp;7j*K}nbRw)!(F zvXd2#7MZGh3H)Q@=-J`0VAfkUmMDgXz@+ya3{hJdqe2*O&El~>`S0&7rn@N%w`<0; z$4qCvcEBg^2B^AFH-Y(g`~RXC{8#S-4ZhBkgY#Bsu$sGISk&w7@_|f`v(o@m|(}K4!+| zKFxsHf44nkUJ?FC=636b8_QUoDx&p||JbNI|IK~rXY=1PiuoN|{OEAcp1C>I>&`r6 zVsr^>JYeCFprq`$;FcK6pQHOviF1`2HeFknB0puS*ymg^KGEj&-MmuPZ%m}$rc7Bo z+4A3l{gIbXG=GXtMTiyR!P36JSCmd@V*WR4O%y_$4w87yXE0g4&0I`)e zT>TBwER$p%8SaY)OuNo*o)_^t$L;n`s~aNBr=EO~3P1JhjBeRluiGkm%QjTDUO&I} zo>#@~sc)kzxtgZ^-Eyn;!qWN!+Mm*XFBWC6h?cb8HF5pnqfTlJBE`9@SR((=uUTB^ zdzcvv>gyw9CWikhvR1f~=zV~f>GsdWsV~)|m=2h!v7g~OkkuVwti}BL=7t&P`n#5P zu3=<)EVDY;HIGq%BjCcP$xcQ(TFER-t85=|GubgDykRRiwY7>hcePKS%kCNZ91gp0 zzH_n)xFZwz^2sG>VS%XBdvotCOHbRlHtp~2-mj&hy&9Im0{5=DD=^HEmSq0FHYj=1 zp+CD?bKLj!bvm`1f13H0X@06>-FfLYai+ORZQg&k>|D?B@O;lPnTO{WzOj!!*(IO0 zS?}ThhM@m?sdr80weQ(hN)D0HrcvpBed|?sbD7hqL;Fw@- zuA;a=hM%QTcTYiP;PN-~PfaR0nlHezMw(%PIHReN=${tjkdw1HOYjf5siVAmMZMrdM_5&~Rt^4a-|1dnfznHt4Y2BmJ z-nXos`vkR@s?4tV|Nq-Q=GDEqFRQqC8U<_m(j6Z~LfY$N^Q%tg%wE(dZP zSX7vj6ck+vg#-95BE!do^ z8Tu#x@jiUESZ}^dUF8N7^&OGtIXIN=B+81Z>MmNeiF=o5;nEp%b2O&B{q+5mU8ZCj zLjddk%{}{9JM{f~+A`;={}O*kzyEG~bvo}KxfvEX>-U*6|K4#tdLNm)%VhrI&}|;_ ziyGR>Oa^O*P$2h2BbF56TLl^CusG*PY!k~H#13|;&R|nV2$q9;Qo`tnBe!7 z`FLgBg{)^8tUV??eaZ~SWbaqcKG}M3*FN8QE`3uUyKc`Wy` z%ZJ~u{pj{(np(Zy*Z1G&e%otiH}%=_%e88f!Yfl^R3^UiS9abS79qB_cUAw7+p|Mc zb{0+Az+ZYg_sS+YYpH|({{2bN&DXXNW{5XdYB;p+Cxq3VGX<3Cs}DH966wWg300*d-D+qlbLs;7<_gec&^8E zAam2~ns0k8O|3Vp20op>NznS}#yh{~O9?>cMv-`3XHv`*a#|M8;UH-EB zRq(}jj*7iv&MYnrPF)PIL{4Z6DzrM3Rd_b+Vysel92eQD%VOolai`&ozQdp368jHj zQu6U^t`6Rl_kZNRklXpBT2RgLmB@#!!i!ixss=63H@l#=HFUz(EA#aD1Hu+K=w<6` z8>qXlnl|l(_Jj*b3Qs#5R|GFf7dW$=d83V7qD9vAb(1%~-Ba$@xq8~M_e>Jyt?y-* z-EsZ>|!NFV*-}=klfFB>;q&F%3= ziYJ~=o$x4r%HH40w)q?Xei`!K`{Vn(j`Z2CAJ=SK;$i14Y#KQK{Ljmu%I5wPQ2*AZ zR>d{z+x3lXpIKNK=6>59`2W8E!^^)(k1m~IwcuIy>*UvbLHkni8+-pA4Bjuuu-xU} zQdZAD>Mnn@4GY^U_!vLb*naF?zlY}-^MU1Ce||Z>)$*gb60(D|aTdcOk8t10iM zYt{=f{z~zG;y?fO&DXB(91U_O_IGxNJHMB$h?_Ir@744Z9ABK`8g;xFIW<|9NE}$H z+kIJj?jsML3)ffeI1#>irK6T*R$fiWFN>}NOiLNm4OwNMZt}Oa{&%i1@NL87o?o(V z{|^7U*K7Drtn_QAZ{@XhhLj&`DZHM+&iINX!+@zy4Zn7>>sAFZoY?vCH1ncm zlNf8yPCdp~#aP3(>&uI$CJXQV*|Xl{;b%dM@GD~N@Aq!+={&f>{RW@>tSvSY>rAc{ z$YkGn=i*#?i0M&YBy;VlZt;36TZ|fIk7Bw!I{3I(gVE3}`nJF86QcouuS=Q%T7X<|7?P;_P zoB!WpvcS>@64%Pav-HpOZ+v9_UO=bsE`!RZlBoMP&zY~AssG@P`MX-7s%6XOpV#U1 zsq)l0cyNAHfM#9M$IEY3UglqSI#S7 z-E%keVu`5zW4!(EedeG3iofPg(z)3wXJdOVxIVAomHMaU=N3LU;GG}1s$N$yZjHLg z$Hj9h_8IBlyC#s`{f05YK#psl*(US({0dCprn9Cp+vOcOa@=&u$?)e#tT`G#m%in7 z_|ejEj$@9Z-&BDemMeAQ95{UL9{+o2>n)rRtF%Mv6NEL`;* zPGl?mX5L#ivnR2+>cgHJtqq(rMcj4IZ@m7tPeZ)NmaURyp?`=PN2=|oOV1PBw8FQ3 z_}KfiKiz~v9 z_?fD2 z<5L6eB?331h31=!9XbAMkq-AB*T@Gl_ZrNz5wdyY%K^)%HUf?Eg17+PYbI^1Ia?>AW}h()5X;=V~n{>dy~7SL^jwy(Fu? zFyYDK=OwvIRla>MpS#3ASVQ_MPu5R??3=9#Pb$apb27-PFj)0%+1F*+|HpUrgN359zW++9e_7^6r75)@s(Dh^ut0(%_Q%6# z_afsbK5CD;2vYB-UcIa;+uvq&yvZQMG+&X$?x6e!MyCgV&rPaW-g;nm)uZE; zw)6ho{LaZ@>#UM{mhVG1gVDE(ClX^SR;urO?fv<+;fk9F>lnReUOKrmGE9;se#+F- zKLt{(b9^@lGDizAr#w>%o_>byO}=v3lLrgKO}3TVHg_lcyh(ZHV)-wBb&SDkmc}yz zIv&E2nv;c|zS;Cm;Kybbb`M!|=IT379VFOy21q_Od-vn_35FSxEY9`*6aM5sel~x? z8(*vYS3dZ9&EI8pVvoCBUx?7tIX{{_j)^|l zxW~ooSM0y5^!I_py$7E!%QgRyZrs#x^T_oHpMO1fW=fbJ$3Nv;yMc)$(@RB-KYy&O z|JYwn&+g=2@;krdhvwb?S`L5m%Z(TDKdLXEu)DH;#_La0ryZ7rCgu{`FM03CZC!!aX?hF2S^j-IP~vo7d+CvzRbe%EWBAr){bl~hv#8=Cwi=_#+Qvkdx^uY7pI zbl}TBefMquPJY`Ny@jFA^~<%Bb}rupB2~6&a0~mq)K~pb@%&N|kG}4`%=h_;((5dmv+MqzlTfd}&Kb|eaOKNh zKZdN|#(_Q+>i_#@UNY~94@+nN>HqM`efM4ef1MTUsE-!@KToBO@zMT21vBP9)YfVK z= L()H5*_R)XW!xr)jPWTu5o%u<9s!KyWhf6o(Ow$Ex7?yr>eB<(CRo*_0^i`+V zU)*9`BhM=nbeTPwZ+^qB1=5E_->TnmpP3-tlpx#UoRWQP%eJp+W>$jx*gP++y0+g@ z>OX7c1(rh_9M|ZyA38CK(Qi)M1fOXN!qr-@Hr98ZJ<@Z-^Ivq%@_8M1m#RNX__;FX zfz#%@y#@>Jy=7i~WaDgiwFQgV|4rd;zPP3J%L~(O-%4yQe=6pU*ZQ6VD(;4Qx``=>3_~>Vu&dZ;=E#1NY&%A!?Bfk7!_jmT4 zUw$9{V-oKx$#ZP&1?|(8OhvO2JUDpHa=nmzW~Ke$c1GGv=Dlwk(pLqm+}i5WFlVh_ zZj|84@5d&*%}H124_BCYFDk6WY_;Fxh|QH8LQ#`jT#mRzb9KJa=KlZORWvaAkNrlr zz<~bq9cQluZ{$wgz@J#q@jh42UQoBASxoPrZ-=0j=ryks785qhzWm0;$#gzhfMe&< zbt}>(MD8#bZ1KJ~Gm>N3_q|j1v1Y5)d;Y(3Mjoy&g(0S}u6br0~4- z*4-amM8yB8YJF5sQts8`-0@-d)|`xseg+vl?^kCz%@Gx!^ZCo-dF9rv_peR@ii)6E$cE0)CJu&ZXnW5aR4Q8vhNw4C5?6f!B=j3GjpX?bAyVV&I zluTT{u)jLHtmOme-z(2EHrBM+y|ERrow#3@MHsIj(lZ^3-=C%{}x*zJApsM+}O!SwW<#W5$ z=~5Ag3$>0qPAR?cU5e3($@%-`-yN~bU-9nrZi-))Te<41Ubcsvs!;JF|48*J&mS5K zpG=?1Sj7Hx#&hk$kDUE?!;i!_PC7GxS6ltQjXaNUZL(Ok?1I_!36IO4a@>3K$Kz4? z+<%MXqo2C8zUFCyfyDm`nd#z}ISO++8#ELzlyWrA+rGW#nlRH@hv)_3J9jqj^ool~{*^qn zsyFJO*72p6K1@wILc6S`_9TbWdpeapCtDTX${mM?A|fZ(r^CQBpVT zf8*g<9{=|ng#RrK5U79uRH>D*_WX4#pKNVIe+3!krF+}=r}EnGXDIR$ICyK}-S;OW z4$N7>St(H5cb@m>u78#%1szL&KDxAMh3>+shWk~POG`ENOKozFmi6E6RWNsPbgH)Q zKkny0<8Q5T-}+lz`_zW?6Z;+(JU3@jxhLuP!#9|#D5YLXki|aCLEzM+#^>SzFKcH0 zyS}=j_hi2d!$jLw9nXhfHEVV27z+-D^RYF5)cCN5i7_BhNx_SwL{lb`ai{Tt>2h+C;%a}j+RvhC+FFfC<}UXRX5N##l4N&XHhEFBc>>?!vi*Kx>l3!_pKhjf>HLxB z{@DeK*6Vg|H&x}?*Yu(-mD470!{mvF8Xw)Qb1g}%$$t0#)Q!7qy5IiVb>rSG0qd`# zFC7;MZ_^Izmeh9^;1Mzi+-}TQZT+Uo=Ib@-?Y4VWzuVTn<9R#fisMHnm;Yk&!F${S zyzg0eD0zO#IBMN~{E?;0xxhS+Uvlw_t*Xj9G}j9o{MfmPGuVJ>no)nO_!A| zd~bS9OKXw&>I(jDtE2rBR5kxfscp(vo^{mqY5qdXzma>FwBLKSX#0Od37%v2-V7nh z*UuMBly~R&!sK+|UP9Rt{ROhcO`n#Aq(6Q6?ttT;BHt`cNu`eoTS_DznME>Q|L&H` zy=dQkVdlQu0v`n#gT6b;w|K0~6JpnE{J_d``~InhitI&Ox4-3NeCga^Adxm{^W9IA z*>s~8{p9#^?ca}9Oj0zx_qTm6 z&eGi$wO;pehmq~hNaI!JXTy0x@m#P=Xt#}{*Y71>N)AUis9XQ8z;%r07Ll?7# zs=u8n(ya$sukl%xUaSh^%Hm(*AoWe?$V9gw(D|DpPo!tZW{pWD9_%sU*U^yY#2=?1Q@AHEY9EOa6q zSJ!3U2-SS1{BNG9yQpZ*(F6mDezx?jH;!iNs`+`cNGLw&Y`o~?(8*Z;y+LMOP{73_ zN4JG;V&nR$R4BN|Ug2@3i}*+8LgP-34Tq<2r`)m+@Zw12ky+Zh@NH_z>>!&-Hs9CW zWxTh{_PS1e{@?tv4He55T$7ru>ZHBy>M;|66KlBK)ERigj8ty(%(>$GJLd4Jv)k2w zMDI>cVVu=>{D9e`%Cvodl9n)J{FXnjeWW$}v0Po6l>O(b1fjWK)xKQhO1OPc-?zrq z^_Sb62?3^Vm)Y(uPYm1g;JD`>QRhE}g)vhPZvH08bL{cK&sQtH@4TZcC!8L|vExX? zNv<8<%+1})1esNsnq*n-X|9pk@75!;?2?}P{_UqHr!u*vah*sO_#)P08E{NkB$=aq z*FD*UUtji4Jh1G3{f!55Qty)6c&9RLW_}XG@c&nwGDDQ|oiEP+^-fK2nc}$U*~{I# zOl~Rsd=PPW+SePhQ|>SwsN&0W+pFjBE7;)e-vXW&6K#K+oLITAb-BvFMY9qzr>~l2 zwc?(?=0Ag%m$T!9?Ptn`#(WZOKA2!5wI{}ZN&LFwN4vM~_`u0%t-T?Mn^BdmPs>qJ zfV*|Bp$tw#9Q{CcK?{l z;b6OeZs@Un$yfgNA6j1P{Hx-xa+Zv~uYd^}?V@~w0-ya^dEDYh+SJ*;*9b^NBI&1Pn%19QH~ zF46aU`rnD^?cz?ocwGseV~Y>XK6~YB_ARq*69v{U5m@kbadH}~jp2er9F5BRId&Ym z{qpu5^C?`va;yJrP-ki~j1k#!>CZElTT+kWzVj3~pQv9yNo?z@1=r%4GcVt1G<_Z7 zf4Yy4sU_$9iu+q@nA3JnI3wYrBgw_q$rXP7PwcC|6P+|385%DxeOi@Ttu)_urhbUk zhM*rS{@(v)%Jb;|v$^jkUi$v(r@^XS9{*dEzK6_F^7H!4{Ajz!|B#9MVvhf=vGttz zY&C21!HSTI-Fs^){j%LM@4iS2@-Tdm$||&Q&4HIGNe}!ogO?O8x1QE)ouE|0!MI(4 zV^V)CQ%3LPU)PR^iwJGeaXa^EyZAQ?j$2E9$DXTlzE*zo-u666#^bRQz18bJ@94{I z;7MV~XrmrZ<=9 zciOLi#G@F0Sni|trRhiZuj}~V8gqR1BR&SU=8r!<kgbmh>8Frvn{~*4hEv zH!)?au>47SprXUJPLb)|(<3a59}ZtB@%7Q-uqvybHHS(3oY;bC!O%E;_5 zUdX@5G$}gvF&|UIALg@f4n0}^Q;=!FV-9O!CuVIVBLHA$jKO+mn974qYEU)eU5`SS<(vj6?Rk_|VfJ#SxdA?0| zzyFr}n5VD&YqtQC^=U7jipa(Wi3_Stj$sNKY>(^}SeCte{qLalg||YUtS$}y94w1h zSPAxMOh~ge+BGw(&gGcHwPnoexBE&zZMEM%xx3x$JFoTJ>K6an&r=#X1m5McGWc4R zaCP6=b6xDlhA4*E`e^m056zl?8VkHCioe`e{hzGGdVu55cmD}f3fCKdD?IgHd2hXQ zi$1I7Tdjupr)waYEE*8RSF{ptf; zmYZeY#x3@6>tousiDjYOry!dYqbbXieg6q?y8N3slXuA@{p_k<{no$#6obCF{Nr_( zxA9%WeV$3;{GaV%r+7Arf3jP(aZlFXwJQImU7mb)3jVgIWbgS2=GF!8e|Ojgly#ms za3R;-Rz58H-r4gtxy@hpYhLo_Q>-n%^?l;L7nlDZaO9i#{!?hv!2}zxKNr{5{J*8y zt)I)$7#3L5B=JK+k*!9RX;(qsvbtX{IiA>GmcEphvAtT>RiN*#{5{P!&Qr6cUVITh zvfiP=`Lxv5oT6DC^7-r&y}cASL`8)CeXsi8jzubQx6?7lyPv|fFHG6L19Q*K{azq?k!dL^FGn}-lGT?dmXE)cotW8ZqsUo ze$o4N-(D}@KU=fmOMcCg{V$dN_Ne^br&Rk5;do@e`_;@NXXo!- z)gU1dufS&K%v1B}2ty0QkptD5Y&QE3eEs>Y=vVmN*W_B*MJw?rGC6M}=8~ z7+y5G=rIbM5Qr!=UFVoag4SxuuW4bnwR>VOw%F^O zsuX=;u|oXvrr!tRc3iopJyDanV8&eY`SQEho)cr7vT6D8^qNKe)!K{pZVzKIHrq1& zK}Xel_S&Du`yYM%oTY5a`e^@`SHH|&p1!uXbv*=;>tyU)o$qUX3C z(=Lw0NBwcGHE)%)FDzW+;K{|f+T{atWMh1lmesmrzl##O#hW*--Skx8ND_awp&~28 zy;HtzVunAD9d4Rn!?d}BH$VSFnNpL}ufMalJu&U@VCO5>KasycOqtj3MoH0qopcvp zq1uD8C)jetgMPKVpSb6H^^;n);)VZYl9USB1i#!(@w%fTFVC^!Q^ull-K!s`y?(Is zg5TfO@qew@KYs80a=&WH{Ld5rxx4;)RLt(QBl_>Ta5lE)kNcIFE_Gx_bDUVi(8(C8 zw8OD;!Eft#(sS-yPD?nwc@>xCwyR>SyPn_Xi+cKMp5G3Qz9KIcmZOb)6Y6swUDo8V z(oMfOxn3b6OhTE@OLJqeUw4({$~uAlJahhBpYZLwnf9dB@$2K3Wn7G@o>ggoBip_( zN_P9~MJua{CdILwCpi;)|nctdwn1f;SLVl;_YoE-n zOqwmN^!fIk{Emg1f9{40Pp)CPC@+~9R(j?}_}-uUzkX$Tw7&k`l>PND!}RulSv6gu zw#zPQ)_Nu$w&srw1>2XL(@hvO{7l+cY+G9#7%!+ta}-%wE3AyZOiR6t;s_ zrseMhe6x>k(v}i=VU%&|-v67{TdzFa=OrlM`YF)GzUNJ>@i#&HAEIXy3?zCsHioU6 z{rt+M)(LN8S8H8y+1{YBf^`#1GG}wece{7$9$W6qPBfA?_h2#MdY3Uv<5d6q)CArW zbzD#CO!-c_3+3;mHxID?%yY@$OH7zlJ@$||m zksloyI}BdjdtUo?rK`syyG5awbn9Jhe;)|kcHsH)_pkRg|49E(amQt1jmpLALJHOL z7r8IDzyJEk`N&7@nFkXLB!n6N-ZozUw5IG!asG-4fA4+`i4a+%Zu{tCHUpGOO- z?|&Cne>T%`r=ncPijb-^lD0K#!{y3$|Gpp2KWV<>ofeL`$$MtM_Br0STE{%=UbW?8@h#9JLdMNbLAvDxVS9& zk~Km1hiY?NL6ILjPr-LFkHh~b?Ppy1JMT&7J*8jQnHP!YFR?gWym7UYoqKiUyfw!` zzP|l9dGiNnzM{+(AJ>X_i9C7IVy?;a?a!eHG2G0q0jKwuoRZFZWZ(4iQ)6M_rwiNn z9(?&{`qxX%Z+7D=+3Rhk?na5m?-I2<724UfDe8&SAqT;JF;-Tk zrP=~l@-15*vD~fSnkgyvUTpgQ*M-MB_x*pDu)(H%+cVaVxZdku-QG<5S{&^8dG$1~ znc@uY+NCWVZF8RLxjK4C#MI_YtIOt^#%>QA2GU+e#T0)NYAmTv64cjoeSVoDClTfz5ed2{Pp(ArFM^(p39dP=YP17{bv1l!M_b}nhRSW z+_G;zm|#%nrS_nzgW<=wK*{PGD_`~PX2?Vik`CQwf9d~t zay|j%k;h_8!5v%rGV5F}{% - \only<#1>{\pgfkeysalso{highlight}} - \alt<#1->{}{\pgfkeysalso{invisible}} - }, -} - -\title{Miri} -\subtitle{An interpreter for Rust's mid-level intermediate representation} -\author{ - Scott Olson - \texorpdfstring{\\ \scriptsize{Supervisor: Christopher Dutchyn}}{} -} -\institute{ - CMPT 400 \\ - University of Saskatchewan -} -\date{} -\titlegraphic{ - \includegraphics[width=64px,height=64px]{rust-logo-512x512.png} \\ - \scriptsize{\url{https://www.rust-lang.org}} -} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% Intro slides -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\begin{document} - -\maketitle - -\begin{frame}[fragile] - \frametitle{What is Rust? \small{[review]}} - - According to the website\dots - - \begin{quote} - \textbf{Rust} is a systems programming language that runs blazingly fast, - prevents nearly all segfaults, and guarantees thread safety. - \end{quote} - - It's a new programming language from Mozilla, and it looks like this: - - \begin{minted}[ - autogobble, - fontsize=\footnotesize, - mathescape, - xleftmargin=.3in, - ]{rust} - fn factorial(n: u64) -> u64 { - (1..n).fold(1, |a, b| a * b) - } - - fn main() { - for x in 1..6 { - println!("{}", factorial(x)); - } - // $\Rightarrow$ 1 - // $\Rightarrow$ 1 - // $\Rightarrow$ 2 - // $\Rightarrow$ 6 - // $\Rightarrow$ 24 - } - \end{minted} -\end{frame} - -\begin{frame} - \frametitle{How does Rust compile code? \onslide<-6>{\small{[review]}}} - - \begin{center} - \begin{tikzpicture}[x=4cm, y=3.5cm, auto, rounded corners] - \tikzstyle{basic-stage}=[rectangle, draw, thick, align=center] - \tikzstyle{stage}=[basic-stage, font=\tiny] - \tikzstyle{pass}=[thick, -stealth] - \tikzstyle{pass-label}=[font=\footnotesize] - - \node[basic-stage] (src) at (0,0) {Source\\Code}; - \node[basic-stage] (mach) at (2,-1) {Machine\\Code}; - - \draw<1>[pass, out=0, in=180] - (src.east) to node[font=\Huge] {?} (mach.west); - - \node[stage, intro=<2>] (ast) at (1,0) - {\normalsize{AST} \\ Abstract Syntax Tree}; - \draw[pass, intro=<2>] - (src) -- node[pass-label] {Parse} (ast); - - \node[stage, intro=<3>] (hir) at (2,0) - {\normalsize{HIR} \\ High-level Intermediate\\Representation}; - \draw[pass, intro=<3>] - (ast) -- node[pass-label] {Simplify} (hir); - - \node[stage, intro=<4>] (mir) at (0,-1) - {\normalsize{MIR} \\ Mid-level Intermediate\\Representation}; - \path (hir.south) -- coordinate (middle) (mir.north); - \draw[pass, intro=<4>] - (hir.south) |- (middle) -| (mir.north); - \node[pass-label, above, intro=<4>] at (middle) {Lower}; - - \node[stage, intro=<5>] (llvm) at (1,-1) - {\normalsize{LLVM IR} \\ Low-level Intermediate\\Representation}; - \draw[pass, intro=<5>] - (mir) -- node[pass-label] {Translate} (llvm); - - \draw<6->[pass, intro=<6>] - (llvm) -- node[pass-label] {Magic} (mach); - - \node[stage, intro=<7>] (exec) at (1,-1.75) - {\normalsize{Execution}}; - \draw[pass, intro=<7>] - (mach) -- node[pass-label] {CPU} (exec); - - \draw[pass, intro=<8>] - (mir) -- node[pass-label] {Miri} (exec); - \end{tikzpicture} - \end{center} -\end{frame} - -\begin{frame} - \frametitle{Why build Miri?} - \begin{itemize} - \item For fun and learning. - - \item I originally planned to use it for testing the compiler and execution - of unsafe code, but shifted my goals along the way. \pause - - \item Now it serves as an experimental implementation of the upcoming - compile-time function evaluation feature in Rust. \pause - - \begin{itemize} - \item Similar to C++14's \mintinline{cpp}{constexpr} feature. - - \item You can do complicated calculations at compile time and compile - their \emph{results} into the executable. \pause - - \item For example, you can compute a ``perfect hash function'' for a - statically-known map at compile-time and have guaranteed no-collision - lookup at runtime. \pause - - \item Miri actually supports far more of Rust than C++14's - \mintinline{cpp}{constexpr} does of C++ --- even heap allocation and - unsafe code. - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{How was it built?} - - At first I wrote a naive version with a number of downsides: - - \begin{itemize} - \item represented values in a traditional dynamic language format, where - every value was the same size. - - \item didn't work well for aggregates (structs, enums, arrays, etc.). - - \item made unsafe programming tricks that make assumptions about low-level - value layout essentially impossible. - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{How was it built?} - \begin{itemize} - \item Later, a Rust compiler team member proposed a ``Rust abstract - machine'' with specialized value layout which solved my previous problems. - \pause - - \item His proposal was intended for a compile-time function evaluator in the - Rust compiler, so I effectively implemented an experimental version of - that. \pause - - \item After this point, making Miri work well was primarily a software - engineering problem. - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Data layout} - \begin{itemize} - \item Memory in Miri is literally a HashMap from ``allocation IDs'' to - ``abstract allocations''. - - \item Allocations are represented by: \pause - \begin{enumerate} - \item An array of \textbf{raw bytes} with a size based on the type of - the value \pause - \item A set of \textbf{relocations} --- pointers into other abstract - allocations \pause - \item A mask determining which bytes are \textbf{undefined} - \end{enumerate} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{\texttt{square} example} - \begin{center} - \begin{minted}[autogobble,fontsize=\scriptsize]{rust} - // Rust - fn square(n: u64) -> u64 { - n * n - } - - // Generated MIR - fn square(arg0: u64) -> u64 { - let var0: u64; // n // On function entry, Miri creates - // virtual allocations for all the - // arguments, variables, and - // temporaries. - - bb0: { - var0 = arg0; // Copy the argument into `n`. - return = Mul(var0, var0); // Multiply `n` with itself. - goto -> bb1; // Jump to basic block `bb1`. - } - - bb1: { - return; // Return from the current fn. - } - } - \end{minted} - \end{center} -\end{frame} - -\begin{frame}[fragile] - \frametitle{\texttt{sum} example} - \begin{center} - \begin{minted}[autogobble,fontsize=\tiny]{rust} - // Rust - fn sum() -> u64 { - let mut sum = 0; let mut i = 0; - while i < 10 { sum += i; i += 1; } - sum - } - - // Generated MIR - fn sum() -> u64 { - let mut var0: u64; // sum - let mut var1: u64; // i - let mut tmp0: bool; - - bb0: { - // sum = 0; i = 0; - var0 = const 0u64; var1 = const 0u64; goto -> bb1; - } - bb1: { - // if i < 10 { goto bb2; } else { goto bb3; } - tmp0 = Lt(var1, const 10u64); - if(tmp0) -> [true: bb2, false: bb3]; - } - bb2: { - var0 = Add(var0, var1); // sum = sum + i; - var1 = Add(var1, const 1u64); // i = i + 1; - goto -> bb1; - } - bb3: { - return = var0; goto -> bb4; - } - bb4: { return; } - } - \end{minted} - \end{center} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Heap allocations!} - \begin{minted}[autogobble,fontsize=\scriptsize]{rust} - fn make_vec() -> Vec { - // Empty array with space for 4 bytes - allocated on the heap! - let mut vec = Vec::with_capacity(4); - // Initialize the first two slots. - vec.push(1); - vec.push(2); - vec - } - - // For reference: - // struct Vec { capacity: usize, data: *mut T, length: usize } - - // Resulting allocations (on 32-bit little-endian architectures): - // Region A: - // 04 00 00 00 00 00 00 00 02 00 00 00 - // └───(B)───┘ - // - // Region B: - // 01 02 __ __ (underscores denote undefined bytes) - \end{minted} - - \footnotesize{Evaluating the above involves a number of compiler built-ins, - ``unsafe'' code blocks, and more inside the standard library, - but Miri handles it all.} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Unsafe code!} - \begin{minted}[autogobble,fontsize=\scriptsize]{rust} - fn out_of_bounds() -> u8 { - let mut vec = vec![1, 2] - unsafe { *vec.get_unchecked(5) } - } - - // test.rs:3: error: pointer offset outside bounds of allocation - // test.rs:3: unsafe { *vec.get_unchecked(5) } - // ^~~~~~~~~~~~~~~~~~~~~ - - fn undefined_bytes() -> u8 { - let mut vec = Vec::with_capacity(10); - unsafe { *vec.get_unchecked(5) } - } - - // test.rs:3: error: attempted to read undefined bytes - // test.rs:3: unsafe { *vec.get_unchecked(5) } - // ^~~~~~~~~~~~~~~~~~~~~ - \end{minted} -\end{frame} - -\begin{frame} - \frametitle{What can't Miri do?} - \begin{itemize} - \item Miri can't do all the stuff I didn't implement yet. :) - \begin{itemize} - \item non-trivial casts - \item function pointers - \item calling destructors and freeing memory - \item taking target architecture endianess and alignment information - into account when computing data layout - \item handling all constants properly (but, well, Miri might be - replacing the old constants system) - \end{itemize} - \pause - - \item Miri can't do foreign function calls (e.g. calling functions defined - in C or C++), but there is a reasonable way it could be done with libffi. - \begin{itemize} - \item On the other hand, for constant evaluation in the compiler, you - want the evaluator to be deterministic and safe, so FFI calls might be - banned anyway. - \end{itemize} - \pause - - \item Without quite some effort, Miri will probably never handle inline - assembly... - \end{itemize} -\end{frame} - -\begin{frame} - \begin{center} - \LARGE{Questions?} - \end{center} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% Extra slides -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\begin{frame}[fragile] - \frametitle{\texttt{varN} vs. \texttt{argN}} - \begin{center} - \begin{minted}[autogobble,fontsize=\scriptsize]{rust} - // Rust - type Pair = (u64, u64); - fn swap((a, b): Pair) -> Pair { - (b, a) - } - - // Generated MIR - fn swap(arg0: (u64, u64)) -> (u64, u64) { - let var0: u64; // a - let var1: u64; // b - - bb0: { - var0 = arg0.0; // get the 1st part of the pair - var1 = arg0.1; // get the 2nd part of the pair - return = (var1, var0); // build a new pair in the result - goto -> bb1; - } - - bb1: { - return; - } - } - \end{minted} - \end{center} -\end{frame} - -\begin{frame}[fragile] - \frametitle{\texttt{factorial} example} - \begin{center} - \begin{minted}[autogobble,fontsize=\tiny]{rust} - // Rust - fn factorial(n: u64) -> u64 { - (1..n).fold(1, |a, b| a * b) - } - - // Generated MIR - fn factorial(arg0: u64) -> u64 { - let var0: u64; // n - let mut tmp0: Range; // Miri calculates sizes for generics like Range. - let mut tmp1: [closure]; - - bb0: { - var0 = arg0; - - // tmp0 = 1..n - tmp0 = Range { start: const 1u64, end: var0 }; - - // tmp1 = |a, b| a * b - tmp1 = [closure]; - - // This loads the MIR for the `fold` fn from the standard library. - // In general, MIR for any function from any library can be loaded. - // return tmp0.fold(1, tmp1) - return = Range::fold(tmp0, const 1u64, tmp1) -> bb1; - } - - bb1: { - return; - } - } - \end{minted} - \end{center} -\end{frame} - -\end{document} diff --git a/tex/report/latexmkrc b/tex/report/latexmkrc deleted file mode 100644 index 23aa1a481b3e..000000000000 --- a/tex/report/latexmkrc +++ /dev/null @@ -1,12 +0,0 @@ -# vim: ft=perl - -$pdf_mode = 1; -$pdflatex = 'lualatex --shell-escape %O %S'; -$out_dir = 'out'; - -# This improves latexmk's detection of source files and generated files. -$recorder = 1; - -# Ignore always-regenerated *.pyg files from the minted package when considering -# whether to run pdflatex again. -$hash_calc_ignore_pattern{'pyg'} = '.*'; diff --git a/tex/report/miri-report.tex b/tex/report/miri-report.tex deleted file mode 100644 index 27a063de0272..000000000000 --- a/tex/report/miri-report.tex +++ /dev/null @@ -1,663 +0,0 @@ -% vim: tw=100 - -\documentclass[twocolumn]{article} -\usepackage{blindtext} -\usepackage[hypcap]{caption} -\usepackage{fontspec} -\usepackage[colorlinks, urlcolor={blue!80!black}]{hyperref} -\usepackage[outputdir=out]{minted} -\usepackage{relsize} -\usepackage{xcolor} - -\setmonofont{Source Code Pro}[ - BoldFont={* Medium}, - BoldItalicFont={* Medium Italic}, - Scale=MatchLowercase, -] - -\newcommand{\rust}[1]{\mintinline{rust}{#1}} - -\begin{document} - -\title{Miri: \\ \smaller{An interpreter for Rust's mid-level intermediate representation}} -\author{Scott Olson\footnote{\href{mailto:scott@solson.me}{scott@solson.me}} \\ - \smaller{Supervised by Christopher Dutchyn}} -\date{April 12th, 2016} -\maketitle - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\section{Abstract} - -The increasing need for safe low-level code in contexts like operating systems and browsers is -driving the development of Rust\footnote{\url{https://www.rust-lang.org}}, a programming language -promising high performance without the risk of memory unsafety. To make programming more convenient, -it's often desirable to be able to generate code or perform some computation at compile-time. The -former is mostly covered by Rust's existing macro feature or build-time code generation, but the -latter is currently restricted to a limited form of constant evaluation capable of little beyond -simple math. - -The architecture of the compiler at the time the existing constant evaluator was built limited its -potential for future extension. However, a new intermediate representation was recently -added\footnote{\href{https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md}{Rust RFC \#1211: Mid-level IR (MIR)}} -to the Rust compiler between the abstract syntax tree and the back-end LLVM IR, called mid-level -intermediate representation, or MIR for short. This report will demonstrate that writing an -interpreter for MIR is a surprisingly effective approach for supporting a large proportion of Rust's -features in compile-time execution. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\section{Background} - -The Rust compiler generates an instance of \rust{Mir} for each function [\autoref{fig:mir}]. Each -\rust{Mir} structure represents a control-flow graph for a given function, and contains a list of -``basic blocks'' which in turn contain a list of statements followed by a single terminator. Each -statement is of the form \rust{place = rvalue}. An \rust{Place} is used for referencing variables -and calculating addresses such as when dereferencing pointers, accessing fields, or indexing arrays. -An \rust{Rvalue} represents the core set of operations possible in MIR, including reading a value -from an place, performing math operations, creating new pointers, structures, and arrays, and so -on. Finally, a terminator decides where control will flow next, optionally based on the value of a -boolean or integer. - -\begin{figure}[ht] - \begin{minted}[autogobble]{rust} - struct Mir { - basic_blocks: Vec, - // ... - } - - struct BasicBlockData { - statements: Vec, - terminator: Terminator, - // ... - } - - struct Statement { - place: Place, - rvalue: Rvalue - } - - enum Terminator { - Goto { target: BasicBlock }, - If { - cond: Operand, - targets: [BasicBlock; 2] - }, - // ... - } - \end{minted} - \caption{MIR (simplified)} - \label{fig:mir} -\end{figure} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\section{First implementation} - -\subsection{Basic operation} - -To investigate the possibility of executing Rust at compile-time I wrote an interpreter for MIR -called Miri\footnote{\url{https://github.com/solson/miri}}. The structure of the interpreter closely -mirrors the structure of MIR itself. It starts executing a function by iterating the statement list -in the starting basic block, translating the place into a pointer and using the rvalue to decide -what to write into that pointer. Evaluating the rvalue may involve reads (such as for the two sides -of a binary operation) or construction of new values. When the terminator is reached, it is used to -decide which basic block to jump to next. Finally, Miri repeats this entire process, reading -statements from the new block. - -\subsection{Function calls} - -To handle function call terminators\footnote{Calls occur only as terminators, never as rvalues.}, -Miri is required to store some information in a virtual call stack so that it may pick up where it -left off when the callee returns. Each stack frame stores a reference to the \rust{Mir} for the -function being executed, its local variables, its return value location\footnote{Return value -pointers are passed in by callers.}, and the basic block where execution should resume. When Miri -encounters a \rust{Return} terminator in the MIR, it pops one frame off the stack and resumes the -previous function. Miri's execution ends when the function it was initially invoked with returns, -leaving the call stack empty. - -It should be noted that Miri does not itself recurse when a function is called; it merely pushes a -virtual stack frame and jumps to the top of the interpreter loop. Consequently, Miri can interpret -deeply recursive programs without overflowing its native call stack. This approach would allow Miri -to set a virtual stack depth limit and report an error when a program exceeds it. - -\subsection{Flaws} - -This version of Miri supported quite a bit of the Rust language, including booleans, integers, -if-conditions, while-loops, structures, enums, arrays, tuples, pointers, and function calls, -requiring approximately 400 lines of Rust code. However, it had a particularly naive value -representation with a number of downsides. It resembled the data layout of a dynamic language like -Ruby or Python, where every value has the same size\footnote{An \rust{enum} is a discriminated union -with a tag and space to fit the largest variant, regardless of which variant it contains.} in the -interpreter: - -\begin{minted}[autogobble]{rust} - enum Value { - Uninitialized, - Bool(bool), - Int(i64), - Pointer(Pointer), // index into stack - Aggregate { - variant: usize, - data: Pointer, - }, - } -\end{minted} - -This representation did not work well for aggregate types\footnote{That is, structures, enums, -arrays, tuples, and closures.} and required strange hacks to support them. Their contained values -were allocated elsewhere on the stack and pointed to by the aggregate value, which made it more -complicated to implement copying aggregate values from place to place. - -Moreover, while the aggregate issues could be worked around, this value representation made common -unsafe programming tricks (which make assumptions about the low-level value layout) fundamentally -impossible. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\section{Current implementation} - -Roughly halfway through my time working on Miri, Eduard -Burtescu\footnote{\href{https://github.com/eddyb}{eddyb on GitHub}} from the Rust compiler -team\footnote{\url{https://www.rust-lang.org/team.html\#Compiler}} made a post on Rust's internal -forums about a ``Rust Abstract Machine'' -specification\footnote{\href{https://internals.rust-lang.org/t/mir-constant-evaluation/3143/31}{Burtescu's -reply on ``MIR constant evaluation''}} which could be used to implement more powerful compile-time -function execution, similar to what is supported by C++14's \mintinline{cpp}{constexpr} feature. -After clarifying some of the details of the data layout with Burtescu via IRC, I started -implementing it in Miri. - -\subsection{Raw value representation} - -The main difference in the new value representation was to represent values by ``abstract -allocations'' containing arrays of raw bytes with different sizes depending on their types. This -mimics how Rust values are represented when compiled for physical machines. In addition to the raw -bytes, allocations carry information about pointers and undefined bytes. - -\begin{minted}[autogobble]{rust} - struct Memory { - map: HashMap, - next_id: AllocId, - } - - struct Allocation { - bytes: Vec, - relocations: BTreeMap, - undef_mask: UndefMask, - } -\end{minted} - -\subsubsection{Relocations} - -The abstract machine represents pointers through ``relocations'', which are analogous to relocations -in linkers\footnote{\href{https://en.wikipedia.org/wiki/Relocation_(computing)}{Relocation -(computing) - Wikipedia}}. Instead of storing a global memory address in the raw byte representation -like on a physical machine, we store an offset from the start of the target allocation and add an -entry to the relocation table which maps the index of the offset bytes to the target allocation. - -In \autoref{fig:reloc}, the relocation stored at offset 0 in \rust{y} points to offset 2 in \rust{x} -(the 2nd 16-bit integer). Thus, the relocation table for \rust{y} is \texttt{\{0 => -x\}}, meaning the next $N$ bytes after offset 0 denote an offset into allocation \rust{x} where $N$ -is the size of a pointer (4 in this example). The example shows this as a labelled line beneath the -offset bytes. - -In effect, the abstract machine represents pointers as \rust{(allocation_id, offset)} pairs. This -makes it easy to detect when pointer accesses go out of bounds. - -\begin{figure}[hb] - \begin{minted}[autogobble]{rust} - let x: [i16; 3] = [0xAABB, 0xCCDD, 0xEEFF]; - let y = &x[1]; - // x: BB AA DD CC FF EE (6 bytes) - // y: 02 00 00 00 (4 bytes) - // └───(x)───┘ - \end{minted} - \caption{Example relocation on 32-bit little-endian} - \label{fig:reloc} -\end{figure} - -\subsubsection{Undefined byte mask} - -The final piece of an abstract allocation is the undefined byte mask. Logically, we store a boolean -for the definedness of every byte in the allocation, but there are multiple ways to make the storage -more compact. I tried two implementations: one based on the endpoints of alternating ranges of -defined and undefined bytes and the other based on a bitmask. The former is more compact but I found -it surprisingly difficult to update cleanly. I currently use the much simpler bitmask system. - -See \autoref{fig:undef} for an example of an undefined byte in a value, represented by underscores. -Note that there is a value for the second byte in the byte array, but it doesn't matter what it is. -The bitmask would be $10_2$, i.e.\ \rust{[true, false]}. - -\begin{figure}[hb] - \begin{minted}[autogobble]{rust} - let x: [u8; 2] = unsafe { - [1, std::mem::uninitialized()] - }; - // x: 01 __ (2 bytes) - \end{minted} - \caption{Example undefined byte} - \label{fig:undef} -\end{figure} - -\subsection{Computing data layout} - -Currently, the Rust compiler's data layouts for types are hidden from Miri, so it does its own data -layout computation which will not always match what the compiler does, since Miri doesn't take -target type alignments into account. In the future, the Rust compiler may be modified so that Miri -can use the exact same data layout. - -Miri's data layout calculation is a relatively simple transformation from Rust types to a structure -with constant size values for primitives and sets of fields with offsets for aggregate types. These -layouts are cached for performance. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\section{Deterministic execution} -\label{sec:deterministic} - -In order to be effective as a compile-time evaluator, Miri must have \emph{deterministic execution}, -as explained by Burtescu in the ``Rust Abstract Machine'' post. That is, given a function and -arguments to that function, Miri should always produce identical results. This is important for -coherence in the type checker when constant evaluations are involved in types, such as for sizes of -array types: - -\begin{minted}[autogobble,mathescape]{rust} - const fn get_size() -> usize { /* $\ldots$ */ } - let array: [i32; get_size()]; -\end{minted} - -Since Miri allows execution of unsafe code\footnote{In fact, the distinction between safe and unsafe -doesn't exist at the MIR level.}, it is specifically designed to remain safe while interpreting -potentially unsafe code. When Miri encounters an unrecoverable error, it reports it via the Rust -compiler's usual error reporting mechanism, pointing to the part of the original code where the -error occurred. Below is an example from Miri's -repository.\footnote{\href{https://github.com/solson/miri/blob/master/test/errors.rs}{miri/test/errors.rs}} - -\begin{minted}[autogobble]{rust} - let b = Box::new(42); - let p: *const i32 = &*b; - drop(b); - unsafe { *p } - // ~~ error: dangling pointer - // was dereferenced -\end{minted} -\label{dangling-pointer} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\section{Language support} - -In its current state, Miri supports a large proportion of the Rust language, detailed below. The -major exception is a lack of support for FFI\footnote{Foreign Function Interface, e.g.\ calling -functions defined in Assembly, C, or C++.}, which eliminates possibilities like reading and writing -files, user input, graphics, and more. However, for compile-time evaluation in Rust, this limitation -is desired. - -\subsection{Primitives} - -Miri supports booleans, integers of various sizes and signed-ness (i.e.\ \rust{i8}, \rust{i16}, -\rust{i32}, \rust{i64}, \rust{isize}, \rust{u8}, \rust{u16}, \rust{u32}, \rust{u64}, \rust{usize}), -and unary and binary operations over these types. The \rust{isize} and \rust{usize} types will be -sized according to the target machine's pointer size just like in compiled Rust. The \rust{char} and -float types (\rust{f32}, \rust{f64}) are not supported yet, but there are no known barriers to doing -so. - -When examining a boolean in an \rust{if} condition, Miri will report an error if its byte -representation is not precisely 0 or 1, since having any other value for a boolean is undefined -behaviour in Rust. The \rust{char} type will have similar restrictions once it is implemented. - -\subsection{Pointers} - -Both references and raw pointers are supported, with essentially no difference between them in Miri. -It is also possible to do pointer comparisons and math. However, a few operations are considered -errors and a few require special support. - -Firstly, pointers into the same allocations may be compared for ordering, but pointers into -different allocations are considered unordered and Miri will complain if you attempt this. The -reasoning is that different allocations may have different orderings in the global address space at -runtime, making this non-deterministic. However, pointers into different allocations \emph{may} be -compared for direct equality (they are always unequal). - -Secondly, pointers represented using relocations may be compared against pointers casted from -integers (e.g.\ \rust{0 as *const i32}) for things like null pointer checks. To handle these cases, -Miri has a concept of ``integer pointers'' which are always unequal to abstract pointers. Integer -pointers can be compared and operated upon freely. However, note that it is impossible to go from an -integer pointer to an abstract pointer backed by a relocation. It is not valid to dereference an -integer pointer. - -\subsubsection{Slice pointers} - -Rust supports pointers to ``dynamically-sized types'' such as \rust{[T]} and \rust{str} which -represent arrays of indeterminate size. Pointers to such types contain an address \emph{and} the -length of the referenced array. Miri supports these fully. - -\subsubsection{Trait objects} - -Rust also supports pointers to ``trait objects'' which represent some type that implements a trait, -with the specific type unknown at compile-time. These are implemented using virtual dispatch with a -vtable, similar to virtual methods in C++. Miri does not currently support these at all. - -\subsection{Aggregates} - -Aggregates include types declared with \rust{struct} or \rust{enum} as well as tuples, arrays, and -closures. Miri supports all common usage of all of these types. The main missing piece is to handle -\texttt{\#[repr(..)]} annotations which adjust the layout of a \rust{struct} or \rust{enum}. - -\subsection{Place projections} - -This category includes field accesses, dereferencing, accessing data in an \rust{enum} variant, and -indexing arrays. Miri supports all of these, including nested projections such as -\rust{*foo.bar[2]}. - -\subsection{Control flow} - -All of Rust's standard control flow features, including \rust{loop}, \rust{while}, \rust{for}, -\rust{if}, \rust{if let}, \rust{while let}, \rust{match}, \rust{break}, \rust{continue}, and -\rust{return} are supported. In fact, supporting these was quite easy since the Rust compiler -reduces them all down to a small set of control-flow graph primitives in MIR. - -\subsection{Function calls} - -As previously described, Miri supports arbitrary function calls without growing the native stack -(only its virtual call stack). It is somewhat limited by the fact that cross-crate\footnote{A crate -is a single Rust library (or executable).} calls only work for functions whose MIR is stored in -crate metadata. This is currently true for \rust{const}, generic, and inline functions. -A branch of the compiler could be made that stores MIR for all functions. This would be a non-issue -for a compile-time evaluator based on Miri, since it would only call \rust{const fn}s. - -\subsubsection{Method calls} - -Miri supports trait method calls, including invoking all the compiler-internal lookup needed to find -the correct implementation of the method. - -\subsubsection{Closures} - -Calls to closures are also supported with the exception of one edge case\footnote{Calling a closure -that takes a reference to its captures via a closure interface that passes the captures by value is -not yet supported.}. The value part of a closure that holds the captured variables is handled as an -aggregate and the function call part is mostly the same as a trait method call, but with the added -complication that closures use a separate calling convention within the compiler. - -\subsubsection{Function pointers} - -Function pointers are not currently supported by Miri, but there is a relatively simple way they -could be encoded using a relocation with a special reserved allocation identifier. The offset of the -relocation would determine which function it points to in a special array of functions in the -interpreter. - -\subsubsection{Intrinsics} - -To support unsafe code, and in particular to support Rust's standard library, it became clear that -Miri would have to support calls to compiler -intrinsics\footnote{\url{https://doc.rust-lang.org/stable/std/intrinsics/index.html}}. Intrinsics -are function calls which cause the Rust compiler to produce special-purpose code instead of a -regular function call. Miri simply recognizes intrinsic calls by their unique -ABI\footnote{Application Binary Interface, which defines calling conventions. Includes ``C'', -``Rust'', and ``rust-intrinsic''.} and name and runs special-purpose code to handle them. - -An example of an important intrinsic is \rust{size_of} which will cause Miri to write the size of -the type in question to the return value location. The Rust standard library uses intrinsics heavily -to implement various data structures, so this was a major step toward supporting them. Intrinsics -have been implemented on a case-by-case basis as tests which required them were written, and not all -intrinsics are supported yet. - -\subsubsection{Generic function calls} - -Miri needs special support for generic function calls since Rust is a \emph{monomorphizing} -compiler, meaning it generates a special version of each function for each distinct set of type -parameters it gets called with. Since functions in MIR are still polymorphic, Miri has to do the -same thing and substitute function type parameters into all types it encounters to get fully -concrete, monomorphized types. For example, in\ldots - -\begin{minted}[autogobble]{rust} - fn some(t: T) -> Option { Some(t) } -\end{minted} - -\ldots{}Miri needs to know the size of \rust{T} to copy the right amount of bytes from the argument -to the return value. If we call \rust{some(10i32)} Miri will execute \rust{some} knowing that -\rust{T = i32} and generate a representation for \rust{Option}. - -Miri currently does this monomorphization lazily on-demand unlike the Rust back-end which does it -all ahead of time. - -\subsection{Heap allocations} - -The next piece of the puzzle for supporting interesting programs (and the standard library) was heap -allocations. There are two main interfaces for heap allocation in Rust: the built-in \rust{Box} -rvalue in MIR and a set of C ABI foreign functions including \rust{__rust_allocate}, -\rust{__rust_reallocate}, and \rust{__rust_deallocate}. These correspond approximately to -\mintinline{c}{malloc}, \mintinline{c}{realloc}, and \mintinline{c}{free} in C. - -The \rust{Box} rvalue allocates enough space for a single value of a given type. This was easy to -support in Miri. It simply creates a new abstract allocation in the same manner as for -stack-allocated values, since there's no major difference between them in Miri. - -The allocator functions, which are used to implement things like Rust's standard \rust{Vec} type, -were a bit trickier. Rust declares them as \rust{extern "C" fn} so that different allocator -libraries can be linked in at the user's option. Since Miri doesn't actually support FFI and wants -full control of allocations for safety, it ``cheats'' and recognizes these allocator functions in -essentially the same way it recognizes compiler intrinsics. Then, a call to \rust{__rust_allocate} -simply creates another abstract allocation with the requested size and \rust{__rust_reallocate} -grows one. - -In the future, Miri should also track which allocations came from \rust{__rust_allocate} so it can -reject reallocate or deallocate calls on stack allocations. - -\subsection{Destructors} - -When a value which ``owns'' some resource (like a heap allocation or file handle) goes out of scope, -Rust inserts \emph{drop glue} that calls the user-defined destructor for the type if it has one, and -then drops all of the subfields. Destructors for types like \rust{Box} and \rust{Vec} -deallocate heap memory. - -Miri doesn't yet support calling user-defined destructors, but it has most of the machinery in place -to do so already. There \emph{is} support for dropping \rust{Box} types, including deallocating -their associated allocations. This is enough to properly execute the dangling pointer example in -\autoref{sec:deterministic}. - -\subsection{Constants} - -Only basic integer, boolean, string, and byte-string literals are currently supported. Evaluating -more complicated constant expressions in their current form would be a somewhat pointless exercise -for Miri. Instead, we should lower constant expressions to MIR so Miri can run them directly, which -is precisely what would need be done to use Miri as the compiler's constant evaluator. - -\subsection{Static variables} - -Miri doesn't currently support statics, but they would need support similar to constants. Also note -that while it would be invalid to write to static (i.e.\ global) variables in Miri executions, it -would probably be fine to allow reads. - -\subsection{Standard library} - -Throughout the implementation of the above features, I often followed this process: - -\begin{enumerate} - \item Try using a feature from the standard library. - \item See where Miri runs into stuff it can't handle. - \item Fix the problem. - \item Go to 1. -\end{enumerate} - -At present, Miri supports a number of major non-trivial features from the standard library along -with tons of minor features. Smart pointer types such as \rust{Box}, \rust{Rc}\footnote{Reference -counted shared pointer} and \rust{Arc}\footnote{Atomically reference-counted thread-safe shared -pointer} all seem to work. I've also tested using the shared smart pointer types with \rust{Cell} -and \rust{RefCell}\footnote{\href{https://doc.rust-lang.org/stable/std/cell/index.html}{Rust -documentation for cell types}} for internal mutability, and that works as well, although -\rust{RefCell} can't ever be borrowed twice until I implement destructor calls, since a destructor -is what releases the borrow. - -But the standard library collection I spent the most time on was \rust{Vec}, the standard -dynamically-growable array type, similar to C++'s \texttt{std::vector} or Java's -\texttt{java.util.ArrayList}. In Rust, \rust{Vec} is an extremely pervasive collection, so -supporting it is a big win for supporting a larger swath of Rust programs in Miri. - -See \autoref{fig:vec} for an example (working in Miri today) of initializing a \rust{Vec} with a -small amount of space on the heap and then pushing enough elements to force it to reallocate its -data array. This involves cross-crate generic function calls, unsafe code using raw pointers, heap -allocation, handling of uninitialized memory, compiler intrinsics, and more. - -\begin{figure}[t] - \begin{minted}[autogobble]{rust} - struct Vec { - data: *mut T, // 4 byte pointer - capacity: usize, // 4 byte integer - length: usize, // 4 byte integer - } - - let mut v: Vec = - Vec::with_capacity(2); - // v: 00 00 00 00 02 00 00 00 00 00 00 00 - // └─(data)──┘ - // data: __ __ - - v.push(1); - // v: 00 00 00 00 02 00 00 00 01 00 00 00 - // └─(data)──┘ - // data: 01 __ - - v.push(2); - // v: 00 00 00 00 02 00 00 00 02 00 00 00 - // └─(data)──┘ - // data: 01 02 - - v.push(3); - // v: 00 00 00 00 04 00 00 00 03 00 00 00 - // └─(data)──┘ - // data: 01 02 03 __ - \end{minted} - \caption{\rust{Vec} example on 32-bit little-endian} - \label{fig:vec} -\end{figure} - -Miri supports unsafe operations on \rust{Vec} like \rust{v.set_len(10)} or -\rust{v.get_unchecked(2)}, provided that such calls do no invoke undefined behaviour. If a call -\emph{does} invoke undefined behaviour, Miri will abort with an appropriate error message (see -\autoref{fig:vec-error}). - -\begin{figure}[t] - \begin{minted}[autogobble]{rust} - fn out_of_bounds() -> u8 { - let v = vec![1, 2]; - let p = unsafe { v.get_unchecked(5) }; - *p + 10 - // ~~ error: pointer offset outside - // bounds of allocation - } - - fn undefined_bytes() -> u8 { - let v = Vec::::with_capacity(10); - let p = unsafe { v.get_unchecked(5) }; - *p + 10 - // ~~~~~~~ error: attempted to read - // undefined bytes - } - \end{minted} - \caption{\rust{Vec} examples with undefined behaviour} - \label{fig:vec-error} -\end{figure} - -\newpage - -Here is one final code sample Miri can execute that demonstrates many features at once, including -vectors, heap allocation, iterators, closures, raw pointers, and math: - -\begin{minted}[autogobble]{rust} - let x: u8 = vec![1, 2, 3, 4] - .into_iter() - .map(|x| x * x) - .fold(0, |x, y| x + y); - // x: 1e (that is, the hex value - // 0x1e = 30 = 1 + 4 + 9 + 16) -\end{minted} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\section{Future directions} - -\subsection{Finishing the implementation} - -There are a number of pressing items on my to-do list for Miri, including: - -\begin{itemize} - \item A much more comprehensive and automated test suite. - \item User-defined destructor calls. - \item Non-trivial casts between primitive types like integers and pointers. - \item Handling statics and global memory. - \item Reporting errors for all undefined behaviour.\footnote{\href{https://doc.rust-lang.org/reference.html\#behavior-considered-undefined}{The Rust reference on what is considered undefined behaviour}} - \item Function pointers. - \item Accounting for target machine primitive type alignment and endianness. - \item Optimizations (undefined byte masks, tail-calls). - \item Benchmarking Miri vs. unoptimized Rust. - \item Various \texttt{TODO}s and \texttt{FIXME}s left in the code. - \item Integrating into the compiler proper. -\end{itemize} - -\subsection{Future projects} - -Other possible Miri-related projects include: - -\begin{itemize} - \item A read-eval-print-loop (REPL) for Rust, which may be easier to implement on top of Miri than - the usual LLVM back-end. - \item A graphical or text-mode debugger that steps through MIR execution one statement at a time, - for figuring out why some compile-time execution is raising an error or simply learning how Rust - works at a low level. - \item A less restricted version of Miri that is able to run foreign functions from C/C++ and - generally has full access to the operating system. Such an interpreter could be used to more - quickly prototype changes to the Rust language that would otherwise require changes to the LLVM - back-end. - \item Unit-testing the compiler by comparing the results of Miri's execution against the results - of LLVM-compiled machine code's execution. This would help to guarantee that compile-time - execution works the same as runtime execution. - \item Some kind of Miri-based symbolic evaluator that examines multiple possible code paths at - once to determine if undefined behaviour could be observed on any of them. -\end{itemize} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\section{Final thoughts} - -Writing an interpreter which models values of varying sizes, stack and heap allocation, unsafe -memory operations, and more requires some unconventional techniques compared to conventional -interpreters targeting dynamically-typed languages. However, aside from the somewhat complicated -abstract memory model, making Miri work was primarily a software engineering problem, and not a -particularly tricky one. This is a testament to MIR's suitability as an intermediate representation -for Rust---removing enough unnecessary abstraction to keep it simple. For example, Miri doesn't even -need to know that there are different kinds of loops, or how to match patterns in a \rust{match} -expression. - -Another advantage to targeting MIR is that any new features at the syntax-level or type-level -generally require little to no change in Miri. For example, when the new ``question mark'' syntax -for error handling\footnote{ - \href{https://github.com/rust-lang/rfcs/blob/master/text/0243-trait-based-exception-handling.md} - {Question mark syntax RFC}} -was added to rustc, Miri required no change to support it. -When specialization\footnote{ - \href{https://github.com/rust-lang/rfcs/blob/master/text/1210-impl-specialization.md} - {Specialization RFC}} -was added, Miri supported it with just minor changes to trait method lookup. - -Of course, Miri also has limitations. The inability to execute FFI and inline assembly reduces the -amount of Rust programs Miri could ever execute. The good news is that in the constant evaluator, -FFI can be stubbed out in cases where it makes sense, like I did with \rust{__rust_allocate}. For a -version of Miri not intended for constant evaluation, it may be possible to use libffi to call C -functions from the interpreter. - -In conclusion, Miri is a surprisingly effective project, and a lot of fun to implement. Due to MIR's -tendency to collapse multiple source-level features into one, I often ended up supporting features I -hadn't explicitly intended to. I am excited to work with the compiler team going forward to try to -make Miri useful for constant evaluation in Rust. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\section{Thanks} - -A big thanks goes to Eduard Burtescu for writing the abstract machine specification and answering my -incessant questions on IRC, to Niko Matsakis for coming up with the idea for Miri and supporting my -desire to work with the Rust compiler, and to my research supervisor Christopher Dutchyn. Thanks -also to everyone else on the compiler team and on Mozilla IRC who helped me figure stuff out. -Finally, thanks to Daniel Keep and everyone else who helped fix my numerous writing mistakes. - -\end{document} From 722c229c425bdfa249242581f82818c846cd1c5b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Jul 2022 15:58:55 -0400 Subject: [PATCH 3443/5092] add a simple benchmark with concurrency --- bench-cargo-miri/serde2/Cargo.lock | 89 +++++++++++++++++++++++++++++ bench-cargo-miri/serde2/Cargo.toml | 9 +++ bench-cargo-miri/serde2/src/main.rs | 18 ++++++ 3 files changed, 116 insertions(+) create mode 100644 bench-cargo-miri/serde2/Cargo.lock create mode 100644 bench-cargo-miri/serde2/Cargo.toml create mode 100644 bench-cargo-miri/serde2/src/main.rs diff --git a/bench-cargo-miri/serde2/Cargo.lock b/bench-cargo-miri/serde2/Cargo.lock new file mode 100644 index 000000000000..487505761354 --- /dev/null +++ b/bench-cargo-miri/serde2/Cargo.lock @@ -0,0 +1,89 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cargo-miri-test" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "proc-macro2" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + +[[package]] +name = "serde" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "syn" +version = "1.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" diff --git a/bench-cargo-miri/serde2/Cargo.toml b/bench-cargo-miri/serde2/Cargo.toml new file mode 100644 index 000000000000..29f0abff5d73 --- /dev/null +++ b/bench-cargo-miri/serde2/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "cargo-miri-test" +version = "0.1.0" +authors = ["Oliver Schneider "] +edition = "2018" + +[dependencies] +serde = { version = "*", features = ["derive"] } +serde_json = "*" diff --git a/bench-cargo-miri/serde2/src/main.rs b/bench-cargo-miri/serde2/src/main.rs new file mode 100644 index 000000000000..c81b32c13fef --- /dev/null +++ b/bench-cargo-miri/serde2/src/main.rs @@ -0,0 +1,18 @@ +// Like serde1, but in two threads concurrently. And we don't print. +static JSON: &str = r#"{"buffer":[-29,-42,-40,-37,-28,-5,-21,1,-24,-8,-20,4,-18,26,-24,44,-26,66,-30,86,-37,88,-41,72,-46,50,-31,28,23,14,64,16,51,26,32,34,39,42,48,35,58,0,72,-36,69,-59,58,-98,54,-124,36,-103,12,-110,5,-173,-19,-146,-59,-4,-42,51,1,-23,-6,-30,-6,45,46,47,70,6,55,19,60,38,62,42,47,61,46,40,42,-19,22,-34,6,-35,-50,-61,-141,-37,-171,17,-163,26,-180,46,-154,80,-63,48,-4,18,20,50,47,58,53,44,61,57,85,37,80,0,86,-8,106,-95,49,-213,-8,-131,47,49,63,40,-39,-69,-74,-37,-20,63,-12,58,-14,-12,25,-31,41,11,45,76,47,167,5,261,-37,277,-83,183,-172,35,-122,-79,138,-70,266,69,124,228,0,391,-29,594,-84,702,-78,627,-8,551,-13,509,13,372,120,352,125,622,127,691,223,362,126,386,-33,915,198,958,457,456,298,500,233,1027,469,1096,426,918,160,1067,141,1220,189,1245,164,1375,297,1378,503,1299,702,1550,929,1799,855,1752,547,1830,602,1928,832,1736,796,1735,933,1961,1385,1935,1562,2105,1485,2716,1449,2948,1305,2768,1205,2716,1346,2531,1450,2470,1653,3117,2111,3370,2176,2696,1947,2925,2305,3846,2658,2425,2184,-877,1981,-2261,2623,-1645,2908,-1876,2732,-2704,2953,-2484,3116,-2120,2954,-2442,3216,-2466,3499,-2192,3234,-2392,3361,-2497,3869,-2078,3772,-1858,3915,-2066,4438,-2285,2934,-2294,-280,-2066,-1762,-1992,-1412,-2298,-1535,-2399,-1789,-2223,-1419,-2244,-1334,-2092,-1476,-1777,-1396,-2014,-1571,-2199,-1574,-1843,-1167,-1910,-1446,-2007,-1818,-1506,-1331,-2526,-2048,-5535,-4573,-7148,-5828,-6422,-5327,-5840,-5488,-5992,-6144,-6014,-6164,-6109,-6234,-6271,-6388,-6288,-6156,-6517,-6249,-6794,-6602,-6822,-6418,-6788,-6245,-6490,-6560,-6394,-6794,-7920,-6937,-10397,-7140,-11428,-6972,-11019,-6610,-11141,-6665,-11913,-7046,-11979,-7235,-11599,-7015,-11854,-6912,-12161,-7441,-12136,-7761,-12861,-7292,-13390,-7254,-12345,-7809,-12490,-7463,-13983,-6969,-10489,-8465,-2382,-11054,1272,-12247,-270,-12060,-323,-12113,502,-12486,-697,-12251,-1086,-12141,-181,-13116,-670,-13509,-1173,-12592,-443,-12811,-449,-13698,-934,-12850,-747,-13083,-873,-15036,-1161,-11478,-1047,-2669,-1407,1006,-1658,-1146,-1195,-1297,-1421,-73,-1946,-977,-1590,-1499,-1577,-1010,-1862,-1256,-1389,-962,-1692,-509,-2613,-1317,-2087,-1359,-1997,-1034,-2891,-2024,-119,-84,5651,5723,8074,8306,7156,6870,6985,7106,7312,8403,7114,8096,7173,7848,7082,7827,6761,7189,6985,7368,7076,7835,6992,7297,7453,7260,7016,7755,6025,7429,8533,7352,14150,7628,17142,7077,16399,6947,15939,7475,16564,7069,16463,6882,16400,7602,17031,7233,16543,6517,15395,7018,15985,7104,16689,6869,15655,7622,16155,7198,17884,6022,14056,8856,5665,14484,1815,16782,3034,15786,3107,15664,2312,16517,2965,16443,3036,16120,2287,16584,2479,16720,2693,16073,2535,16159,2958,16609,3067,16086,2716,16579,3035,17752,3092,13704,2499,5265,2620,1452,2808,3024,2444,3275,2839,2267,3340,2857,2968,3232,3066,2867,3152,3072,2248,2961,2413,2807,3238,3237,2368,2699,2262,2392,3537,3339,827,823,-5020,-5359,-7095,-7857,-5973,-6274,-6208,-6279,-6934,-7181,-6893,-6647,-7146,-6687,-7026,-7328,-6451,-6924,-6763,-6535,-7109,-6639,-6926,-6559,-7188,-6799,-6727,-6955,-5786,-6554,-8543,-6796,-14465,-7190,-17356,-6641,-16372,-6529,-15941,-6898,-16526,-6434,-16219,-6520,-16222,-7449,-17077,-7097,-16665,-6476,-15675,-7026,-16498,-6848,-17147,-6271,-15894,-7069,-16266,-7032,-17817,-5991,-13796,-8594,-5421,-14349,-1649,-17288,-2847,-16525,-2974,-15945,-2324,-16482,-3022,-16593,-3097,-16451,-2420,-16780,-2649,-16641,-2836,-15900,-2660,-16214,-3050,-16827,-3111,-15993,-2741,-16151,-2994,-17537,-2933,-13812,-2314,-5216,-2475,-1125,-2648,-2801,-2290,-3285,-2796,-2243,-3415,-2642,-3109,-3000,-3271,-2839,-3408,-3161,-2497,-2876,-2603,-2570,-3351,-3173,-2416,-2832,-2235,-2408,-3405,-3186,-613,-768,5271,5201,7376,7644,6241,6176,6366,6275,6964,7124,6831,6508,6998,6566,6836,7230,6277,6777,6589,6376,6934,6536,6819,6494,7160,6749,6736,6900,5822,6476,8593,6747,14520,7204,17448,6637,16490,6483,16033,6906,16600,6511,16304,6568,16279,7438,17079,7072,16624,6463,15577,7028,16343,6877,16990,6331,15760,7121,16140,7023,17719,5944,13748,8575,5401,14336,1645,17210,2880,16419,3036,15896,2382,16483,3074,16584,3143,16425,2443,16782,2650,16695,2825,15978,2632,16272,3015,16880,3084,16096,2709,16289,2965,17641,2932,13887,2323,5330,2474,1286,2656,2954,2309,3410,2803,2373,3414,2795,3106,3151,3263,2952,3403,3241,2483,2969,2568,2681,3316,3245,2383,2837,2199,2390,3396,3165,641,706,-5230,-5323,-7307,-7790,-6136,-6317,-6268,-6419,-6884,-7278,-6766,-6666,-6976,-6731,-6853,-7406,-6308,-6958,-6636,-6553,-6978,-6703,-6829,-6647,-7156,-6883,-6737,-7017,-5814,-6581,-8575,-6833,-14490,-7270,-17411,-6699,-16466,-6539,-16016,-6931,-16571,-6504,-16257,-6551,-16202,-7408,-16983,-7021,-16545,-6410,-15512,-6976,-16305,-6803,-17017,-6243,-15820,-7037,-16197,-6923,-17802,-5820,-13840,-8455,-5475,-14227,-1724,-17099,-2923,-16314,-3008,-15801,-2362,-16392,-3088,-16506,-3163,-16356,-2503,-16700,-2717,-16605,-2855,-15904,-2710,-16226,-3108,-16870,-3089,-16101,-2747,-16257,-3087,-17584,-2975,-13868,-2324,-5343,-2548,-1275,-2673,-2917,-2213,-3363,-2694,-2311,-3251,-2744,-2867,-3129,-3034,-2939,-3190,-3234,-2346,-2964,-2639,-2658,-3558,-3241,-2670,-2892,-2453,-2437,-3564,-3175,-771,-779,5105,5171,7308,7655,6265,6204,6397,6288,7024,7172,6903,6586,7002,6627,6777,7308,6190,6889,6537,6465,7011,6613,6985,6631,7393,6934,7073,7072,6112,6615,8751,6859,14672,7282,17448,6652,16146,6448,15565,6899,16151,6547,15860,6591,16048,7446,17065,7064,16661,6368,15774,6857,16524,6677,16825,6071,15577,6900,16119,7040,17490,6118,13495,8696,5432,14446,1678,17366,3036,16488,3624,15834,3012,16382,3575,16465,3685,16301,2815,16708,2982,16679,3356,15952,2934,16049,3290,16352,3964,15605,3612,16222,3647,17764,4272,13865,3977,5384,3592,1580,3794,3243,3627,3670,3622,2758,4007,3130,3835,3294,3964,3065,4468,3408,3933,3234,3789,3118,4634,3643,4211,3174,4155,3176,5512,4400,2792,1730,-3702,-4499,-5940,-6691,-4265,-5094,-4381,-5215,-4918,-5746,-4217,-4871,-4402,-4981,-4479,-5525,-3732,-4968,-4118,-4924,-4300,-5349,-3422,-5021,-3876,-4886,-4087,-4860,-2790,-4254,-5025,-4196,-10898,-4415,-13419,-4007,-12198,-4121,-11995,-4413,-12471,-3808,-11937,-3920,-11792,-4583,-12284,-3776,-12085,-3107,-11421,-3583,-11226,-3081,-11157,-2768,-10580,-3914,-10424,-3197,-11040,-1715,-9822,-5144,-6189,-11154,-4236,-13029,-5134,-11598,-5507,-10949,-4921,-11142,-4999,-11180,-4883,-11184,-4366,-11090,-4548,-10887,-4818,-10708,-4866,-10534,-5253,-10272,-5179,-9894,-4633,-10029,-4773,-10382,-4977,-8674,-4668,-5292,-4651,-3928,-4629,-4465,-4312,-3994,-4459,-3528,-4570,-4400,-4272,-4601,-4482,-4035,-4627,-4334,-4080,-4498,-4045,-3835,-4204,-3526,-3695,-3646,-4045,-4101,-4856,-4628,-3338,-3235,-673,-508,28,147,-453,-639,11,0,8,-2,7,0,7,-3,11,-8,15,-9,17,-6,17,-5,13,-3,7,0,3,0,-2,0,-4,0,-4,-2,-6,0,-14,-2,-17,-4,-8,0,-7,5,-17,7,-18,10,-7,18,-2,25,-3,27,0,31,4,34,4,34,8,36,8,37,2,36,4,34,8,28,3,15,0,11,0,12,-5,8,-4,10,0,23,-4,31,-8,30,-2,30,0,26,-6,22,-6,20,-12,15,-19,10,-10,13,-14,6,-43,-13,-43,-16,-9,-12,-10,-29,-42,-40,-37,-28,-5,-21,1,-24,-8,-20,4,-18,26,-24,44,-26,66,-30,86,-37,88,-41,72,-46,50,-31,28,23,14,64,16,51,26,32,34,39,42,48,35,58,0,72,-36,69,-59,58,-98,54,-124,36,-103,12,-110,5,-173,-19,-146,-59,-4,-42,51,1,-23,-6,-30,-6,45,46,47,70,6,55,19,60,38,62,42,47,61,46,40,42,-19,22,-34,6,-35,-50,-61,-141,-37,-171,17,-163,26,-180,46,-154,80,-63,48,-4,18,20,50,47,58,53,44,61,57,85,37,80,0,86,-8,106,-95,49,-213,-8,-131,47,49,63,40,-39,-69,-74,-37,-20,63,-12,58,-14,-12,25,-31,41,11,45,76,47,167,5,261,-37,277,-83,183,-172,35,-122,-79,138,-70,266,69,124,228,0,391,-29,594,-84,702,-78,627,-8,551,-13,509,13,372,120,352,125,622,127,691,223,362,126,386,-33,915,198,958,457,456,298,500,233,1027,469,1096,426,918,160,1067,141,1220,189,1245,164,1375,297,1378,503,1299,702,1550,929,1799,855,1752,547,1830,602,1928,832,1736,796,1735,933,1961,1385,1935,1562,2105,1485,2716,1449,2948,1305,2768,1205,2716,1346,2531,1450,2470,1653,3117,2111,3370,2176,2696,1947,2925,2305,3846,2658,2425,2184,-877,1981,-2261,2623,-1645,2908,-1876,2732,-2704,2953,-2484,3116,-2120,2954,-2442,3216,-2466,3499,-2192,3234,-2392,3361,-2497,3869,-2078,3772,-1858,3915,-2066,4438,-2285,2934,-2294,-280,-2066,-1762,-1992,-1412,-2298,-1535,-2399,-1789,-2223,-1419,-2244,-1334,-2092,-1476,-1777,-1396,-2014,-1571,-2199,-1574,-1843,-1167,-1910,-1446,-2007,-1818,-1506,-1331,-2526,-2048,-5535,-4573,-7148,-5828,-6422,-5327,-5840,-5488,-5992,-6144,-6014,-6164,-6109,-6234,-6271,-6388,-6288,-6156,-6517,-6249,-6794,-6602,-6822,-6418,-6788,-6245,-6490,-6560,-6394,-6794,-7920,-6937,-10397,-7140,-11428,-6972,-11019,-6610,-11141,-6665,-11913,-7046,-11979,-7235,-11599,-7015,-11854,-6912,-12161,-7441,-12136,-7761,-12861,-7292,-13390,-7254,-12345,-7809,-12490,-7463,-13983,-6969,-10489,-8465,-2382,-11054,1272,-12247,-270,-12060,-323,-12113,502,-12486,-697,-12251,-1086,-12141,-181,-13116,-670,-13509,-1173,-12592,-443,-12811,-449,-13698,-934,-12850,-747,-13083,-873,-15036,-1161,-11478,-1047,-2669,-1407,1006,-1658,-1146,-1195,-1297,-1421,-73,-1946,-977,-1590,-1499,-1577,-1010,-1862,-1256,-1389,-962,-1692,-509,-2613,-1317,-2087,-1359,-1997,-1034,-2891,-2024,-119,-84,5651,5723,8074,8306,7156,6870,6985,7106,7312,8403,7114,8096,7173,7848,7082,7827,6761,7189,6985,7368]}"#; + +use serde::Deserialize; +use std::thread; + +#[derive(Deserialize)] +struct DeriveStruct { + buffer: Vec, +} + +fn main() { + let t = thread::spawn(|| { + let _info: DeriveStruct = serde_json::from_str(JSON).unwrap(); + }); + let _info: DeriveStruct = serde_json::from_str(JSON).unwrap(); + t.join().unwrap(); +} From 58b6e592a218f28383b40beb7d78b750173ab67d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Jul 2022 16:10:32 -0400 Subject: [PATCH 3444/5092] trophy case++ --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 00d64d8cc704..52934a6cd4bc 100644 --- a/README.md +++ b/README.md @@ -582,6 +582,7 @@ Definite bugs found: * [`rkyv` constructing a `Box<[u8]>` from an overaligned allocation](https://github.com/rkyv/rkyv/commit/a9417193a34757e12e24263178be8b2eebb72456) * [Data race in `thread::scope`](https://github.com/rust-lang/rust/issues/98498) * [`regex` incorrectly handling unaligned `Vec` buffers](https://www.reddit.com/r/rust/comments/vq3mmu/comment/ienc7t0?context=3) +* [Incorrect use of `compare_exchange_weak` in `once_cell`](https://github.com/matklad/once_cell/issues/186) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From 6ec8909fdb76574f0d236a6b4d783d7bbc5fa4b2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Jul 2022 19:26:43 -0400 Subject: [PATCH 3445/5092] less silly Cargo.toml --- bench-cargo-miri/serde1/Cargo.toml | 4 ++-- bench-cargo-miri/serde2/Cargo.toml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bench-cargo-miri/serde1/Cargo.toml b/bench-cargo-miri/serde1/Cargo.toml index 29f0abff5d73..7cb863a7abf3 100644 --- a/bench-cargo-miri/serde1/Cargo.toml +++ b/bench-cargo-miri/serde1/Cargo.toml @@ -5,5 +5,5 @@ authors = ["Oliver Schneider "] edition = "2018" [dependencies] -serde = { version = "*", features = ["derive"] } -serde_json = "*" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" diff --git a/bench-cargo-miri/serde2/Cargo.toml b/bench-cargo-miri/serde2/Cargo.toml index 29f0abff5d73..7cb863a7abf3 100644 --- a/bench-cargo-miri/serde2/Cargo.toml +++ b/bench-cargo-miri/serde2/Cargo.toml @@ -5,5 +5,5 @@ authors = ["Oliver Schneider "] edition = "2018" [dependencies] -serde = { version = "*", features = ["derive"] } -serde_json = "*" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" From b2e64653ebdc7c314fb28a6ef8c944a40888ba00 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Jul 2022 19:40:44 -0400 Subject: [PATCH 3446/5092] ensure that benchmarks can actually run --- ci.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ci.sh b/ci.sh index b914477d44a8..7bdbffd09eee 100755 --- a/ci.sh +++ b/ci.sh @@ -40,6 +40,13 @@ function run_tests { # any interactive questions. ${PYTHON} test-cargo-miri/run-test.py echo + + # Ensure that our benchmarks all work, on the host at least. + if [ -z "${MIRI_TEST_TARGET+exists}" ]; then + for BENCH in $(ls "bench-cargo-miri"); do + cargo miri run --manifest-path bench-cargo-miri/$BENCH/Cargo.toml + done + fi } function run_tests_minimal { From 6083963b4b67279f5f4c2464f944f8e672be409d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Jul 2022 20:05:22 -0400 Subject: [PATCH 3447/5092] do not enable expensive-debug-assertions in installed Miri in CI --- ci.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ci.sh b/ci.sh index 7bdbffd09eee..e7c6ed833c60 100755 --- a/ci.sh +++ b/ci.sh @@ -1,15 +1,16 @@ #!/bin/bash set -euo pipefail +set -x # Determine configuration export RUSTFLAGS="-D warnings" export CARGO_INCREMENTAL=0 -export CARGO_EXTRA_FLAGS="--all-features" +export CARGO_EXTRA_FLAGS="--all-features" # in particular, expensive-debug-assertions # Prepare echo "Build and install miri" -./miri build --all-targets --locked -./miri install # implicitly locked +CARGO_EXTRA_FLAGS="" ./miri install # implicitly locked -- and the *installed* Miri does *not* get the expensive-debug-assertions feature +./miri build --all-targets --locked # the build that all the `./miri test` below will use echo # Test From afb937ab25e17adc5f2b76fcdf64d8804bdd65b9 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 5 Jul 2022 10:17:43 +0000 Subject: [PATCH 3448/5092] Bump rust version --- rust-version | 2 +- src/diagnostics.rs | 2 +- src/helpers.rs | 4 ++-- src/stacked_borrows.rs | 2 +- src/stacked_borrows/diagnostics.rs | 6 ++---- 5 files changed, 7 insertions(+), 9 deletions(-) diff --git a/rust-version b/rust-version index 682914e88290..b726558b7662 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -46b8c23f3eb5e4d0e0aa27eb3f20d5b8fc3ed51f +4045ce641a9eede71cc12031a2cd71692b273890 diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 28d4733718ef..a942390e549f 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -450,7 +450,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let msg = match e { CreatedPointerTag(tag, None) => format!("created tag {tag:?}"), CreatedPointerTag(tag, Some((alloc_id, range))) => - format!("created tag {tag:?} at {alloc_id}{}", HexRange(range)), + format!("created tag {tag:?} at {alloc_id:?}{}", HexRange(range)), PoppedPointerTag(item, tag) => match tag { None => diff --git a/src/helpers.rs b/src/helpers.rs index c051d44fa256..7e702e065619 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -699,7 +699,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: We are re-getting the allocation each time around the loop. // Would be nice if we could somehow "extend" an existing AllocRange. let alloc = this.get_ptr_alloc(ptr.offset(len, this)?, size1, Align::ONE)?.unwrap(); // not a ZST, so we will get a result - let byte = alloc.read_integer(Size::ZERO, size1)?.to_u8()?; + let byte = alloc.read_integer(alloc_range(Size::ZERO, size1))?.to_u8()?; if byte == 0 { break; } else { @@ -721,7 +721,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: We are re-getting the allocation each time around the loop. // Would be nice if we could somehow "extend" an existing AllocRange. let alloc = this.get_ptr_alloc(ptr, size2, align2)?.unwrap(); // not a ZST, so we will get a result - let wchar = alloc.read_integer(Size::ZERO, size2)?.to_u16()?; + let wchar = alloc.read_integer(alloc_range(Size::ZERO, size2))?.to_u16()?; if wchar == 0 { break; } else { diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index cc2ea0b76d87..efc38fdae3f2 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -1097,7 +1097,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx AllocKind::LiveData => { // This should have alloc_extra data. let alloc_extra = this.get_alloc_extra(alloc_id).unwrap(); - trace!("Stacked Borrows tag {tag:?} exposed in {alloc_id}"); + trace!("Stacked Borrows tag {tag:?} exposed in {alloc_id:?}"); alloc_extra.stacked_borrows.as_ref().unwrap().borrow_mut().exposed_tags.insert(tag); } AllocKind::Function | AllocKind::Dead => { diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index a7b8e5f13cea..fe3716a91116 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -140,9 +140,8 @@ impl AllocHistory { stack: &Stack, ) -> InterpError<'tcx> { let action = format!( - "trying to reborrow {derived_from:?} for {:?} permission at {}[{:#x}]", + "trying to reborrow {derived_from:?} for {:?} permission at {alloc_id:?}[{:#x}]", new.perm, - alloc_id, error_offset.bytes(), ); err_sb_ub( @@ -163,8 +162,7 @@ impl AllocHistory { stack: &Stack, ) -> InterpError<'tcx> { let action = format!( - "attempting a {access} using {tag:?} at {}[{:#x}]", - alloc_id, + "attempting a {access} using {tag:?} at {alloc_id:?}[{:#x}]", error_offset.bytes(), ); err_sb_ub( From a07398d44139fe675bbf3560462151a6524d8065 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 Jul 2022 07:38:42 -0400 Subject: [PATCH 3449/5092] we don't need HexRange any more --- src/diagnostics.rs | 33 +++++++++++++++++------------- src/helpers.rs | 9 -------- src/stacked_borrows/diagnostics.rs | 4 ++-- 3 files changed, 21 insertions(+), 25 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index a942390e549f..11b5a21b2af8 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -8,7 +8,6 @@ use rustc_middle::ty; use rustc_span::{source_map::DUMMY_SP, Span, SpanData, Symbol}; use rustc_target::abi::{Align, Size}; -use crate::helpers::HexRange; use crate::stacked_borrows::{diagnostics::TagHistory, AccessKind}; use crate::*; @@ -184,14 +183,14 @@ pub fn report_error<'tcx, 'mir>( ]; match history { Some(TagHistory::Tagged {tag, created: (created_range, created_span), invalidated, protected }) => { - let msg = format!("{:?} was created by a retag at offsets {}", tag, HexRange(*created_range)); + let msg = format!("{tag:?} was created by a retag at offsets {created_range:?}"); helps.push((Some(*created_span), msg)); if let Some((invalidated_range, invalidated_span)) = invalidated { - let msg = format!("{:?} was later invalidated at offsets {}", tag, HexRange(*invalidated_range)); + let msg = format!("{tag:?} was later invalidated at offsets {invalidated_range:?}"); helps.push((Some(*invalidated_span), msg)); } if let Some((protecting_tag, protecting_tag_span, protection_span)) = protected { - helps.push((Some(*protecting_tag_span), format!("{:?} was protected due to {:?} which was created here", tag, protecting_tag))); + helps.push((Some(*protecting_tag_span), format!("{tag:?} was protected due to {protecting_tag:?} which was created here"))); helps.push((Some(*protection_span), format!("this protector is live for this call"))); } } @@ -448,32 +447,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx for e in diagnostics.drain(..) { use NonHaltingDiagnostic::*; let msg = match e { - CreatedPointerTag(tag, None) => format!("created tag {tag:?}"), + CreatedPointerTag(tag, None) => + format!("created tag {tag:?}"), CreatedPointerTag(tag, Some((alloc_id, range))) => - format!("created tag {tag:?} at {alloc_id:?}{}", HexRange(range)), + format!("created tag {tag:?} at {alloc_id:?}{range:?}"), PoppedPointerTag(item, tag) => match tag { None => format!( - "popped tracked tag for item {:?} due to deallocation", - item + "popped tracked tag for item {item:?} due to deallocation", ), Some((tag, access)) => { format!( - "popped tracked tag for item {:?} due to {:?} access for {:?}", - item, access, tag + "popped tracked tag for item {item:?} due to {access:?} access for {tag:?}", ) } }, - CreatedCallId(id) => format!("function call with id {id}"), + CreatedCallId(id) => + format!("function call with id {id}"), CreatedAlloc(AllocId(id), size, align, kind) => - format!("created {kind} allocation of {} bytes (alignment {} bytes) with id {id}", size.bytes(), align.bytes()), - FreedAlloc(AllocId(id)) => format!("freed allocation with id {id}"), + format!( + "created {kind} allocation of {size} bytes (alignment {align} bytes) with id {id}", + size = size.bytes(), + align = align.bytes(), + ), + FreedAlloc(AllocId(id)) => + format!("freed allocation with id {id}"), RejectedIsolatedOp(ref op) => format!("{op} was made to return an error due to isolation"), ProgressReport => format!("progress report: current operation being executed is here"), - Int2Ptr { .. } => format!("integer-to-pointer cast"), + Int2Ptr { .. } => + format!("integer-to-pointer cast"), }; let (title, diag_level) = match e { diff --git a/src/helpers.rs b/src/helpers.rs index 7e702e065619..4b2604afa2c1 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -905,15 +905,6 @@ pub fn get_local_crates(tcx: TyCtxt<'_>) -> Vec { local_crates } -/// Formats an AllocRange like [0x1..0x3], for use in diagnostics. -pub struct HexRange(pub AllocRange); - -impl std::fmt::Display for HexRange { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "[{:#x}..{:#x}]", self.0.start.bytes(), self.0.end().bytes()) - } -} - /// Helper function used inside the shims of foreign functions to check that /// `target_os` is a supported UNIX OS. pub fn target_os_is_unix(target_os: &str) -> bool { diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index fe3716a91116..cee643fdf821 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -4,7 +4,7 @@ use rustc_middle::mir::interpret::{AllocId, AllocRange}; use rustc_span::{Span, SpanData}; use rustc_target::abi::Size; -use crate::helpers::{CurrentSpan, HexRange}; +use crate::helpers::CurrentSpan; use crate::stacked_borrows::{err_sb_ub, AccessKind, Permission}; use crate::Item; use crate::SbTag; @@ -178,7 +178,7 @@ fn operation_summary( alloc_id: AllocId, alloc_range: AllocRange, ) -> String { - format!("this error occurs as part of {} at {:?}{}", operation, alloc_id, HexRange(alloc_range)) + format!("this error occurs as part of {operation} at {alloc_id:?}{alloc_range:?}") } fn error_cause(stack: &Stack, tag: SbTagExtra) -> &'static str { From 2931e0fd63541d6e39ffa9ec75ffc9b614b73a16 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Jul 2022 23:18:27 -0400 Subject: [PATCH 3450/5092] handle Box with allocators --- src/stacked_borrows.rs | 32 +++++++++---- tests/pass/box-custom-alloc.rs | 87 ++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 9 deletions(-) create mode 100644 tests/pass/box-custom-alloc.rs diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index efc38fdae3f2..9969fbdbcd34 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -976,27 +976,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Raw pointers need to be enabled. ty::RawPtr(tym) if kind == RetagKind::Raw => Some((RefKind::Raw { mutable: tym.mutbl == Mutability::Mut }, false)), - // Boxes do not get a protector: protectors reflect that references outlive the call - // they were passed in to; that's just not the case for boxes. - ty::Adt(..) if ty.is_box() => Some((RefKind::Unique { two_phase: false }, false)), + // Boxes are handled separately due to that allocator situation. _ => None, } } // We need a visitor to visit all references. However, that requires - // a `MPlaceTy` (or `OpTy), so we have a fast path for reference types that + // a `MPlaceTy` (or `OpTy`), so we have a fast path for reference types that // avoids allocating. - if let Some((mutbl, protector)) = qualify(place.layout.ty, kind) { + if let Some((ref_kind, protector)) = qualify(place.layout.ty, kind) { // Fast path. let val = this.read_immediate(&this.place_to_op(place)?)?; - let val = this.retag_reference(&val, mutbl, protector)?; + let val = this.retag_reference(&val, ref_kind, protector)?; this.write_immediate(*val, place)?; return Ok(()); } // If we don't want to recurse, we are already done. - if !this.machine.stacked_borrows.as_mut().unwrap().get_mut().retag_fields { + // EXCEPT if this is a `Box`, then we have to recurse because allocators. + // (Yes this means we technically also recursively retag the allocator itself even if field + // retagging is not enabled. *shrug*) + if !this.machine.stacked_borrows.as_mut().unwrap().get_mut().retag_fields + && !place.layout.ty.ty_adt_def().is_some_and(|adt| adt.is_box()) + { return Ok(()); } @@ -1034,10 +1037,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx self.ecx } + fn visit_box(&mut self, place: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + // Boxes do not get a protector: protectors reflect that references outlive the call + // they were passed in to; that's just not the case for boxes. + let (ref_kind, protector) = (RefKind::Unique { two_phase: false }, false); + + let val = self.ecx.read_immediate(&place.into())?; + let val = self.ecx.retag_reference(&val, ref_kind, protector)?; + self.ecx.write_immediate(*val, &place.into())?; + Ok(()) + } + fn visit_value(&mut self, place: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { - if let Some((mutbl, protector)) = qualify(place.layout.ty, self.kind) { + if let Some((ref_kind, protector)) = qualify(place.layout.ty, self.kind) { let val = self.ecx.read_immediate(&place.into())?; - let val = self.ecx.retag_reference(&val, mutbl, protector)?; + let val = self.ecx.retag_reference(&val, ref_kind, protector)?; self.ecx.write_immediate(*val, &place.into())?; } else if matches!(place.layout.ty.kind(), ty::RawPtr(..)) { // Wide raw pointers *do* have fields and their types are strange. diff --git a/tests/pass/box-custom-alloc.rs b/tests/pass/box-custom-alloc.rs new file mode 100644 index 000000000000..ef432a86d460 --- /dev/null +++ b/tests/pass/box-custom-alloc.rs @@ -0,0 +1,87 @@ +#![allow(incomplete_features)] // for trait upcasting +#![feature(allocator_api, trait_upcasting)] + +use std::alloc::Layout; +use std::alloc::{AllocError, Allocator}; +use std::cell::Cell; +use std::mem::MaybeUninit; +use std::ptr::{self, NonNull}; + +struct OnceAlloc<'a> { + space: Cell<&'a mut [MaybeUninit]>, +} + +unsafe impl<'shared, 'a: 'shared> Allocator for &'shared OnceAlloc<'a> { + fn allocate(&self, layout: Layout) -> Result, AllocError> { + let space = self.space.replace(&mut []); + + let (ptr, len) = (space.as_mut_ptr(), space.len()); + + if ptr.align_offset(layout.align()) != 0 || len < layout.size() { + return Err(AllocError); + } + + let slice_ptr = ptr::slice_from_raw_parts_mut(ptr as *mut u8, len); + unsafe { Ok(NonNull::new_unchecked(slice_ptr)) } + } + + unsafe fn deallocate(&self, _ptr: NonNull, _layout: Layout) {} +} + +trait MyTrait { + fn hello(&self) -> u8; +} + +impl MyTrait for [u8; 1] { + fn hello(&self) -> u8 { + self[0] + } +} + +trait TheTrait: MyTrait {} + +impl TheTrait for [u8; 1] {} + +/// `Box` is a `ScalarPair` where the 2nd component is the allocator. +fn test1() { + let mut space = vec![MaybeUninit::new(0); 1]; + let once_alloc = OnceAlloc { space: Cell::new(&mut space[..]) }; + + let boxed = Box::new_in([42u8; 1], &once_alloc); + let _val = *boxed; + let with_dyn: Box = boxed; + assert_eq!(42, with_dyn.hello()); + let with_dyn: Box = with_dyn; // upcast + assert_eq!(42, with_dyn.hello()); +} + +// Make the allocator itself so big that the Box is not even a ScalarPair any more. +struct OnceAllocRef<'s, 'a>(&'s OnceAlloc<'a>, u64); + +unsafe impl<'shared, 'a: 'shared> Allocator for OnceAllocRef<'shared, 'a> { + fn allocate(&self, layout: Layout) -> Result, AllocError> { + self.0.allocate(layout) + } + + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + self.0.deallocate(ptr, layout) + } +} + +/// `Box` is an `Aggregate`. +fn test2() { + let mut space = vec![MaybeUninit::new(0); 1]; + let once_alloc = OnceAlloc { space: Cell::new(&mut space[..]) }; + + let boxed = Box::new_in([42u8; 1], OnceAllocRef(&once_alloc, 0)); + let _val = *boxed; + let with_dyn: Box = boxed; + assert_eq!(42, with_dyn.hello()); + let with_dyn: Box = with_dyn; // upcast + assert_eq!(42, with_dyn.hello()); +} + +fn main() { + test1(); + test2(); +} From f3f4bafa1bc670a0b1f6b182407a5b5ddabd5008 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 Jul 2022 18:16:20 -0400 Subject: [PATCH 3451/5092] rustup --- rust-version | 2 +- src/machine.rs | 5 +++++ tests/fail/backtrace/bad-backtrace-ptr.rs | 2 +- tests/fail/backtrace/bad-backtrace-ptr.stderr | 4 ++-- tests/fail/dangling_pointers/deref-invalid-ptr.rs | 2 +- tests/fail/dangling_pointers/deref-invalid-ptr.stderr | 4 ++-- tests/fail/dangling_pointers/null_pointer_deref.rs | 2 +- tests/fail/dangling_pointers/null_pointer_deref.stderr | 4 ++-- tests/fail/dangling_pointers/null_pointer_deref_zst.rs | 2 +- tests/fail/dangling_pointers/null_pointer_deref_zst.stderr | 4 ++-- tests/fail/dangling_pointers/null_pointer_write.rs | 2 +- tests/fail/dangling_pointers/null_pointer_write.stderr | 4 ++-- tests/fail/dangling_pointers/null_pointer_write_zst.rs | 2 +- tests/fail/dangling_pointers/null_pointer_write_zst.stderr | 4 ++-- tests/fail/dangling_pointers/storage_dead_dangling.rs | 2 +- tests/fail/dangling_pointers/storage_dead_dangling.stderr | 4 ++-- tests/fail/dangling_pointers/wild_pointer_deref.rs | 2 +- tests/fail/dangling_pointers/wild_pointer_deref.stderr | 4 ++-- tests/fail/function_pointers/cast_int_to_fn_ptr.rs | 2 +- tests/fail/function_pointers/cast_int_to_fn_ptr.stderr | 4 ++-- tests/fail/intrinsics/copy_null.rs | 2 +- tests/fail/intrinsics/copy_null.stderr | 4 ++-- tests/fail/intrinsics/out_of_bounds_ptr_1.stderr | 4 ++-- tests/fail/intrinsics/out_of_bounds_ptr_3.stderr | 4 ++-- tests/fail/intrinsics/ptr_offset_0_plus_0.rs | 2 +- tests/fail/intrinsics/ptr_offset_0_plus_0.stderr | 4 ++-- tests/fail/intrinsics/ptr_offset_int_plus_int.rs | 2 +- tests/fail/intrinsics/ptr_offset_int_plus_int.stderr | 4 ++-- tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs | 2 +- tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr | 4 ++-- tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr | 4 ++-- tests/fail/intrinsics/write_bytes_null.rs | 2 +- tests/fail/intrinsics/write_bytes_null.stderr | 4 ++-- tests/fail/provenance/provenance_transmute.stderr | 4 ++-- tests/fail/provenance/ptr_int_unexposed.stderr | 4 ++-- tests/fail/provenance/ptr_invalid.rs | 2 +- tests/fail/provenance/ptr_invalid.stderr | 4 ++-- tests/fail/provenance/ptr_invalid_offset.rs | 2 +- tests/fail/provenance/ptr_invalid_offset.stderr | 4 ++-- tests/fail/stacked_borrows/issue-miri-1050-1.stderr | 4 ++-- tests/fail/stacked_borrows/issue-miri-1050-2.rs | 2 +- tests/fail/stacked_borrows/issue-miri-1050-2.stderr | 4 ++-- 42 files changed, 69 insertions(+), 64 deletions(-) diff --git a/rust-version b/rust-version index b726558b7662..bc4489ab57ca 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4045ce641a9eede71cc12031a2cd71692b273890 +41ad4d9b2dbb895666337d162eda52619a6056db diff --git a/src/machine.rs b/src/machine.rs index 716d4bd5b90c..18b9a074c7c3 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -541,6 +541,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx.machine.enforce_abi } + #[inline(always)] + fn check_binop_checks_overflow(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { + ecx.tcx.sess.overflow_checks() + } + #[inline(always)] fn find_mir_or_eval_fn( ecx: &mut MiriEvalContext<'mir, 'tcx>, diff --git a/tests/fail/backtrace/bad-backtrace-ptr.rs b/tests/fail/backtrace/bad-backtrace-ptr.rs index 73d3561445d5..a435b0a69578 100644 --- a/tests/fail/backtrace/bad-backtrace-ptr.rs +++ b/tests/fail/backtrace/bad-backtrace-ptr.rs @@ -4,6 +4,6 @@ extern "Rust" { fn main() { unsafe { - miri_resolve_frame(std::ptr::null_mut(), 0); //~ ERROR null pointer is not a valid pointer for this operation + miri_resolve_frame(std::ptr::null_mut(), 0); //~ ERROR null pointer is a dangling pointer } } diff --git a/tests/fail/backtrace/bad-backtrace-ptr.stderr b/tests/fail/backtrace/bad-backtrace-ptr.stderr index 969523d8b3fe..72755afb34a7 100644 --- a/tests/fail/backtrace/bad-backtrace-ptr.stderr +++ b/tests/fail/backtrace/bad-backtrace-ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: null pointer is not a valid pointer for this operation +error: Undefined Behavior: out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) --> $DIR/bad-backtrace-ptr.rs:LL:CC | LL | miri_resolve_frame(std::ptr::null_mut(), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ null pointer is not a valid pointer for this operation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/dangling_pointers/deref-invalid-ptr.rs b/tests/fail/dangling_pointers/deref-invalid-ptr.rs index cb2bbec8bcf0..31b52da774b0 100644 --- a/tests/fail/dangling_pointers/deref-invalid-ptr.rs +++ b/tests/fail/dangling_pointers/deref-invalid-ptr.rs @@ -3,5 +3,5 @@ fn main() { let x = 16usize as *const u32; - let _y = unsafe { &*x as *const u32 }; //~ ERROR is not a valid pointer + let _y = unsafe { &*x as *const u32 }; //~ ERROR is a dangling pointer } diff --git a/tests/fail/dangling_pointers/deref-invalid-ptr.stderr b/tests/fail/dangling_pointers/deref-invalid-ptr.stderr index 0dc73a6e3b13..68003284994e 100644 --- a/tests/fail/dangling_pointers/deref-invalid-ptr.stderr +++ b/tests/fail/dangling_pointers/deref-invalid-ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: 0x10 is not a valid pointer +error: Undefined Behavior: dereferencing pointer failed: 0x10[noalloc] is a dangling pointer (it has no provenance) --> $DIR/deref-invalid-ptr.rs:LL:CC | LL | let _y = unsafe { &*x as *const u32 }; - | ^^^ dereferencing pointer failed: 0x10 is not a valid pointer + | ^^^ dereferencing pointer failed: 0x10[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/dangling_pointers/null_pointer_deref.rs b/tests/fail/dangling_pointers/null_pointer_deref.rs index 92c45b183c0c..dad6de85e002 100644 --- a/tests/fail/dangling_pointers/null_pointer_deref.rs +++ b/tests/fail/dangling_pointers/null_pointer_deref.rs @@ -1,5 +1,5 @@ #[allow(deref_nullptr)] fn main() { - let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR null pointer is not a valid pointer + let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR null pointer is a dangling pointer panic!("this should never print: {}", x); } diff --git a/tests/fail/dangling_pointers/null_pointer_deref.stderr b/tests/fail/dangling_pointers/null_pointer_deref.stderr index 10f4c0f38416..fbb922c4c113 100644 --- a/tests/fail/dangling_pointers/null_pointer_deref.stderr +++ b/tests/fail/dangling_pointers/null_pointer_deref.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: null pointer is not a valid pointer +error: Undefined Behavior: dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) --> $DIR/null_pointer_deref.rs:LL:CC | LL | let x: i32 = unsafe { *std::ptr::null() }; - | ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is not a valid pointer + | ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/dangling_pointers/null_pointer_deref_zst.rs b/tests/fail/dangling_pointers/null_pointer_deref_zst.rs index f3830c078e5e..21b0ce37d8df 100644 --- a/tests/fail/dangling_pointers/null_pointer_deref_zst.rs +++ b/tests/fail/dangling_pointers/null_pointer_deref_zst.rs @@ -3,6 +3,6 @@ #[allow(deref_nullptr)] fn main() { - let x: () = unsafe { *std::ptr::null() }; //~ ERROR dereferencing pointer failed: null pointer is not a valid pointer + let x: () = unsafe { *std::ptr::null() }; //~ ERROR dereferencing pointer failed: null pointer is a dangling pointer panic!("this should never print: {:?}", x); } diff --git a/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr b/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr index 600b9b425495..40b8d0899b13 100644 --- a/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr +++ b/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: null pointer is not a valid pointer +error: Undefined Behavior: dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) --> $DIR/null_pointer_deref_zst.rs:LL:CC | LL | let x: () = unsafe { *std::ptr::null() }; - | ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is not a valid pointer + | ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/dangling_pointers/null_pointer_write.rs b/tests/fail/dangling_pointers/null_pointer_write.rs index f8dca6882c2d..c7255baf6642 100644 --- a/tests/fail/dangling_pointers/null_pointer_write.rs +++ b/tests/fail/dangling_pointers/null_pointer_write.rs @@ -1,4 +1,4 @@ #[allow(deref_nullptr)] fn main() { - unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR null pointer is not a valid pointer + unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR null pointer is a dangling pointer } diff --git a/tests/fail/dangling_pointers/null_pointer_write.stderr b/tests/fail/dangling_pointers/null_pointer_write.stderr index 803191a7fcfb..a5bf59e26d25 100644 --- a/tests/fail/dangling_pointers/null_pointer_write.stderr +++ b/tests/fail/dangling_pointers/null_pointer_write.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: null pointer is not a valid pointer +error: Undefined Behavior: dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) --> $DIR/null_pointer_write.rs:LL:CC | LL | unsafe { *std::ptr::null_mut() = 0i32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/dangling_pointers/null_pointer_write_zst.rs b/tests/fail/dangling_pointers/null_pointer_write_zst.rs index 63474d965175..60e2d7c663e0 100644 --- a/tests/fail/dangling_pointers/null_pointer_write_zst.rs +++ b/tests/fail/dangling_pointers/null_pointer_write_zst.rs @@ -1,6 +1,6 @@ // Some optimizations remove ZST accesses, thus masking this UB. // compile-flags: -Zmir-opt-level=0 -// error-pattern: memory access failed: null pointer is not a valid pointer +// error-pattern: memory access failed: null pointer is a dangling pointer #[allow(deref_nullptr)] fn main() { diff --git a/tests/fail/dangling_pointers/null_pointer_write_zst.stderr b/tests/fail/dangling_pointers/null_pointer_write_zst.stderr index 2b4d26f8edaf..0535aaa3e2d1 100644 --- a/tests/fail/dangling_pointers/null_pointer_write_zst.stderr +++ b/tests/fail/dangling_pointers/null_pointer_write_zst.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: null pointer is not a valid pointer +error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance) --> RUSTLIB/core/src/ptr/mod.rs:LL:CC | LL | copy_nonoverlapping(&src as *const T, dst, 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/dangling_pointers/storage_dead_dangling.rs b/tests/fail/dangling_pointers/storage_dead_dangling.rs index 370162142de9..64ed37d15113 100644 --- a/tests/fail/dangling_pointers/storage_dead_dangling.rs +++ b/tests/fail/dangling_pointers/storage_dead_dangling.rs @@ -10,7 +10,7 @@ fn fill(v: &mut i32) { } fn evil() { - unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR is not a valid pointer + unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR is a dangling pointer } fn main() { diff --git a/tests/fail/dangling_pointers/storage_dead_dangling.stderr b/tests/fail/dangling_pointers/storage_dead_dangling.stderr index 23b66325571f..25c12feaa82d 100644 --- a/tests/fail/dangling_pointers/storage_dead_dangling.stderr +++ b/tests/fail/dangling_pointers/storage_dead_dangling.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: $HEX is not a valid pointer +error: Undefined Behavior: dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) --> $DIR/storage_dead_dangling.rs:LL:CC | LL | unsafe { &mut *(LEAK as *mut i32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: $HEX is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/dangling_pointers/wild_pointer_deref.rs b/tests/fail/dangling_pointers/wild_pointer_deref.rs index 7c9f5281fbbb..9f6b370c050f 100644 --- a/tests/fail/dangling_pointers/wild_pointer_deref.rs +++ b/tests/fail/dangling_pointers/wild_pointer_deref.rs @@ -2,6 +2,6 @@ fn main() { let p = 44 as *const i32; - let x = unsafe { *p }; //~ ERROR is not a valid pointer + let x = unsafe { *p }; //~ ERROR is a dangling pointer panic!("this should never print: {}", x); } diff --git a/tests/fail/dangling_pointers/wild_pointer_deref.stderr b/tests/fail/dangling_pointers/wild_pointer_deref.stderr index 67b28e25e1dd..571bbcef6595 100644 --- a/tests/fail/dangling_pointers/wild_pointer_deref.stderr +++ b/tests/fail/dangling_pointers/wild_pointer_deref.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: 0x2c is not a valid pointer +error: Undefined Behavior: dereferencing pointer failed: 0x2c[noalloc] is a dangling pointer (it has no provenance) --> $DIR/wild_pointer_deref.rs:LL:CC | LL | let x = unsafe { *p }; - | ^^ dereferencing pointer failed: 0x2c is not a valid pointer + | ^^ dereferencing pointer failed: 0x2c[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/function_pointers/cast_int_to_fn_ptr.rs b/tests/fail/function_pointers/cast_int_to_fn_ptr.rs index 0adbda50bfe5..e287533ffc74 100644 --- a/tests/fail/function_pointers/cast_int_to_fn_ptr.rs +++ b/tests/fail/function_pointers/cast_int_to_fn_ptr.rs @@ -4,5 +4,5 @@ fn main() { let g = unsafe { std::mem::transmute::(42) }; - g(42) //~ ERROR not a valid pointer + g(42) //~ ERROR is a dangling pointer } diff --git a/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr b/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr index 3a80120a9b92..3d4acbe6f09a 100644 --- a/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr +++ b/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: 0x2a is not a valid pointer +error: Undefined Behavior: out-of-bounds pointer use: 0x2a[noalloc] is a dangling pointer (it has no provenance) --> $DIR/cast_int_to_fn_ptr.rs:LL:CC | LL | g(42) - | ^^^^^ 0x2a is not a valid pointer + | ^^^^^ out-of-bounds pointer use: 0x2a[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/copy_null.rs b/tests/fail/intrinsics/copy_null.rs index 7ab41232498e..237e517f2875 100644 --- a/tests/fail/intrinsics/copy_null.rs +++ b/tests/fail/intrinsics/copy_null.rs @@ -10,6 +10,6 @@ fn main() { let ptr = &mut data[0] as *mut u16; // Even copying 0 elements from NULL should error. unsafe { - copy_nonoverlapping(std::ptr::null(), ptr, 0); //~ ERROR: memory access failed: null pointer is not a valid pointer + copy_nonoverlapping(std::ptr::null(), ptr, 0); //~ ERROR: memory access failed: null pointer is a dangling pointer } } diff --git a/tests/fail/intrinsics/copy_null.stderr b/tests/fail/intrinsics/copy_null.stderr index 110408227e18..d7725064832e 100644 --- a/tests/fail/intrinsics/copy_null.stderr +++ b/tests/fail/intrinsics/copy_null.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: null pointer is not a valid pointer +error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance) --> $DIR/copy_null.rs:LL:CC | LL | copy_nonoverlapping(std::ptr::null(), ptr, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr b/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr index 2c4d6bbc50cf..789e9d1f6cbe 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr +++ b/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: pointer arithmetic failed: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds +error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC | LL | unsafe { intrinsics::offset(self, count) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer arithmetic failed: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr b/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr index 075f40b54a2c..973bf043e155 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr +++ b/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: pointer arithmetic failed: ALLOC has size 4, so pointer to 1 byte starting at offset -1 is out-of-bounds +error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 1 byte starting at offset -1 is out-of-bounds --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC | LL | unsafe { intrinsics::offset(self, count) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer arithmetic failed: ALLOC has size 4, so pointer to 1 byte starting at offset -1 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 1 byte starting at offset -1 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/ptr_offset_0_plus_0.rs b/tests/fail/intrinsics/ptr_offset_0_plus_0.rs index ca38f39d2515..4098d6b0ced2 100644 --- a/tests/fail/intrinsics/ptr_offset_0_plus_0.rs +++ b/tests/fail/intrinsics/ptr_offset_0_plus_0.rs @@ -1,4 +1,4 @@ -// error-pattern: pointer arithmetic failed: null pointer is not a valid pointer +// error-pattern: null pointer is a dangling pointer // compile-flags: -Zmiri-permissive-provenance fn main() { diff --git a/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr b/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr index ae9dd15b1330..cb9b02c84051 100644 --- a/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr +++ b/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: pointer arithmetic failed: null pointer is not a valid pointer +error: Undefined Behavior: out-of-bounds pointer arithmetic: null pointer is a dangling pointer (it has no provenance) --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC | LL | unsafe { intrinsics::offset(self, count) as *mut T } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer arithmetic failed: null pointer is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: null pointer is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_int.rs b/tests/fail/intrinsics/ptr_offset_int_plus_int.rs index 809938d99973..817a8b9801b7 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_int.rs +++ b/tests/fail/intrinsics/ptr_offset_int_plus_int.rs @@ -1,4 +1,4 @@ -// error-pattern: is not a valid pointer +// error-pattern: is a dangling pointer // compile-flags: -Zmiri-permissive-provenance fn main() { diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr b/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr index 49e02651e963..e92b0a321665 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr +++ b/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: pointer arithmetic failed: 0x1 is not a valid pointer +error: Undefined Behavior: out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance) --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC | LL | unsafe { intrinsics::offset(self, count) as *mut T } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer arithmetic failed: 0x1 is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs index 903f89ff70ec..ed6370bf7f17 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs +++ b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs @@ -1,4 +1,4 @@ -// error-pattern: is not a valid pointer +// error-pattern: is a dangling pointer // compile-flags: -Zmiri-permissive-provenance fn main() { diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr index fa7a107ab534..47eac678e2ef 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr +++ b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: pointer arithmetic failed: 0x1 is not a valid pointer +error: Undefined Behavior: out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance) --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC | LL | unsafe { intrinsics::offset(self, count) as *mut T } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer arithmetic failed: 0x1 is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr b/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr index c9b7f88385d9..767ed2fc3c45 100644 --- a/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr +++ b/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: pointer arithmetic failed: ALLOC has size 4, so pointer at offset 32 is out-of-bounds +error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer at offset 32 is out-of-bounds --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC | LL | unsafe { intrinsics::offset(self, count) as *mut T } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer arithmetic failed: ALLOC has size 4, so pointer at offset 32 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer at offset 32 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/write_bytes_null.rs b/tests/fail/intrinsics/write_bytes_null.rs index 60966f0a94c0..81b155da44c3 100644 --- a/tests/fail/intrinsics/write_bytes_null.rs +++ b/tests/fail/intrinsics/write_bytes_null.rs @@ -6,5 +6,5 @@ extern "rust-intrinsic" { } fn main() { - unsafe { write_bytes::(std::ptr::null_mut(), 0, 0) }; //~ ERROR memory access failed: null pointer is not a valid pointer + unsafe { write_bytes::(std::ptr::null_mut(), 0, 0) }; //~ ERROR memory access failed: null pointer is a dangling pointer } diff --git a/tests/fail/intrinsics/write_bytes_null.stderr b/tests/fail/intrinsics/write_bytes_null.stderr index 8e8156531b16..8fd866aa8b32 100644 --- a/tests/fail/intrinsics/write_bytes_null.stderr +++ b/tests/fail/intrinsics/write_bytes_null.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: null pointer is not a valid pointer +error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance) --> $DIR/write_bytes_null.rs:LL:CC | LL | unsafe { write_bytes::(std::ptr::null_mut(), 0, 0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/provenance/provenance_transmute.stderr b/tests/fail/provenance/provenance_transmute.stderr index ddbf64f38380..5b7e9442d7c0 100644 --- a/tests/fail/provenance/provenance_transmute.stderr +++ b/tests/fail/provenance/provenance_transmute.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: $HEX is not a valid pointer +error: Undefined Behavior: dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) --> $DIR/provenance_transmute.rs:LL:CC | LL | let _val = *left_ptr; - | ^^^^^^^^^ dereferencing pointer failed: $HEX is not a valid pointer + | ^^^^^^^^^ dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/provenance/ptr_int_unexposed.stderr b/tests/fail/provenance/ptr_int_unexposed.stderr index f0c47e54859e..f5ea7718c78a 100644 --- a/tests/fail/provenance/ptr_int_unexposed.stderr +++ b/tests/fail/provenance/ptr_int_unexposed.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: $HEX is not a valid pointer +error: Undefined Behavior: dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) --> $DIR/ptr_int_unexposed.rs:LL:CC | LL | assert_eq!(unsafe { *ptr }, 3); - | ^^^^ dereferencing pointer failed: $HEX is not a valid pointer + | ^^^^ dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/provenance/ptr_invalid.rs b/tests/fail/provenance/ptr_invalid.rs index f4f3ed5afa5c..be5666b2efad 100644 --- a/tests/fail/provenance/ptr_invalid.rs +++ b/tests/fail/provenance/ptr_invalid.rs @@ -5,5 +5,5 @@ fn main() { let x = 42; let xptr = &x as *const i32; let xptr_invalid = std::ptr::invalid::(xptr.expose_addr()); - let _val = unsafe { *xptr_invalid }; //~ ERROR is not a valid pointer + let _val = unsafe { *xptr_invalid }; //~ ERROR is a dangling pointer } diff --git a/tests/fail/provenance/ptr_invalid.stderr b/tests/fail/provenance/ptr_invalid.stderr index 0d6c0f92d93b..02bfef3ae73f 100644 --- a/tests/fail/provenance/ptr_invalid.stderr +++ b/tests/fail/provenance/ptr_invalid.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: $HEX is not a valid pointer +error: Undefined Behavior: dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) --> $DIR/ptr_invalid.rs:LL:CC | LL | let _val = unsafe { *xptr_invalid }; - | ^^^^^^^^^^^^^ dereferencing pointer failed: $HEX is not a valid pointer + | ^^^^^^^^^^^^^ dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/provenance/ptr_invalid_offset.rs b/tests/fail/provenance/ptr_invalid_offset.rs index 4447575405bb..08fb57a6569c 100644 --- a/tests/fail/provenance/ptr_invalid_offset.rs +++ b/tests/fail/provenance/ptr_invalid_offset.rs @@ -1,5 +1,5 @@ // compile-flags: -Zmiri-strict-provenance -// error-pattern: not a valid pointer +// error-pattern: is a dangling pointer #![feature(strict_provenance)] fn main() { diff --git a/tests/fail/provenance/ptr_invalid_offset.stderr b/tests/fail/provenance/ptr_invalid_offset.stderr index 8f19d4ec9358..df73689deae8 100644 --- a/tests/fail/provenance/ptr_invalid_offset.stderr +++ b/tests/fail/provenance/ptr_invalid_offset.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: pointer arithmetic failed: $HEX is not a valid pointer +error: Undefined Behavior: out-of-bounds pointer arithmetic: $HEX[noalloc] is a dangling pointer (it has no provenance) --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC | LL | unsafe { intrinsics::offset(self, count) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer arithmetic failed: $HEX is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: $HEX[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/stacked_borrows/issue-miri-1050-1.stderr b/tests/fail/stacked_borrows/issue-miri-1050-1.stderr index 8180a60a837a..946e3e8e6664 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-1.stderr +++ b/tests/fail/stacked_borrows/issue-miri-1050-1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: ALLOC has size 2, so pointer to 4 bytes starting at offset 0 is out-of-bounds +error: Undefined Behavior: out-of-bounds pointer use: ALLOC has size 2, so pointer to 4 bytes starting at offset 0 is out-of-bounds --> RUSTLIB/alloc/src/boxed.rs:LL:CC | LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ALLOC has size 2, so pointer to 4 bytes starting at offset 0 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: ALLOC has size 2, so pointer to 4 bytes starting at offset 0 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/stacked_borrows/issue-miri-1050-2.rs b/tests/fail/stacked_borrows/issue-miri-1050-2.rs index 7d8809cedcd7..2a969686d4da 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-2.rs +++ b/tests/fail/stacked_borrows/issue-miri-1050-2.rs @@ -1,4 +1,4 @@ -// error-pattern: is not a valid pointer +// error-pattern: is a dangling pointer use std::ptr::NonNull; fn main() { diff --git a/tests/fail/stacked_borrows/issue-miri-1050-2.stderr b/tests/fail/stacked_borrows/issue-miri-1050-2.stderr index 61ce006dc82b..33ac31176677 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-2.stderr +++ b/tests/fail/stacked_borrows/issue-miri-1050-2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: 0x4 is not a valid pointer +error: Undefined Behavior: out-of-bounds pointer use: 0x4[noalloc] is a dangling pointer (it has no provenance) --> RUSTLIB/alloc/src/boxed.rs:LL:CC | LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 0x4 is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: 0x4[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information From 6c8ad4abc9e794b412dfe17edf186b28fe2a3e1a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 Jul 2022 21:11:48 -0400 Subject: [PATCH 3452/5092] fix comparing wide raw pointers --- src/operator.rs | 16 +++++++++++++--- tests/pass/pointers.rs | 25 +++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index 61c72270e9f7..33c97e7d3109 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -44,9 +44,19 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { } Lt | Le | Gt | Ge => { - // Just compare the integers. - let left = left.to_scalar()?.to_bits(left.layout.size)?; - let right = right.to_scalar()?.to_bits(right.layout.size)?; + let size = self.pointer_size(); + // Just compare the bits. ScalarPairs are compared lexicographically. + // We thus always compare pairs and simply fill scalars up with 0. + let left = match **left { + Immediate::Scalar(l) => (l.check_init()?.to_bits(size)?, 0), + Immediate::ScalarPair(l1, l2) => + (l1.check_init()?.to_bits(size)?, l2.check_init()?.to_bits(size)?), + }; + let right = match **right { + Immediate::Scalar(r) => (r.check_init()?.to_bits(size)?, 0), + Immediate::ScalarPair(r1, r2) => + (r1.check_init()?.to_bits(size)?, r2.check_init()?.to_bits(size)?), + }; let res = match bin_op { Lt => left < right, Le => left <= right, diff --git a/tests/pass/pointers.rs b/tests/pass/pointers.rs index 898ecc0faf75..a0c20af42697 100644 --- a/tests/pass/pointers.rs +++ b/tests/pass/pointers.rs @@ -1,3 +1,5 @@ +use std::mem::transmute; + fn one_line_ref() -> i16 { *&1 } @@ -48,6 +50,27 @@ fn dangling_pointer() -> *const i32 { &b.0 as *const i32 } +fn wide_ptr_ops() { + let a: *const dyn Send = &1 as &dyn Send; + let b: *const dyn Send = &1 as &dyn Send; + let _val = a == b; + let _val = a != b; + let _val = a < b; + let _val = a <= b; + let _val = a > b; + let _val = a >= b; + + let a: *const [u8] = unsafe { transmute((1usize, 1usize)) }; + let b: *const [u8] = unsafe { transmute((1usize, 2usize)) }; + // confirmed with rustc. + assert!(!(a == b)); + assert!(a != b); + assert!(a <= b); + assert!(a < b); + assert!(!(a >= b)); + assert!(!(a > b)); +} + fn main() { assert_eq!(one_line_ref(), 1); assert_eq!(basic_ref(), 1); @@ -91,4 +114,6 @@ fn main() { assert!(dangling > 2); assert!(dangling > 3); assert!(dangling >= 4); + + wide_ptr_ops(); } From de2915bba709c96c902d7666d5173b8196349e81 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 Jul 2022 22:29:38 -0400 Subject: [PATCH 3453/5092] rustup --- rust-version | 2 +- tests/pass/enums.rs | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index bc4489ab57ca..123c4a5b5b56 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -41ad4d9b2dbb895666337d162eda52619a6056db +f342bea9d19f14616c6559312552e6d0ee529cfd diff --git a/tests/pass/enums.rs b/tests/pass/enums.rs index d2dc06525475..ac7aafc1bb2e 100644 --- a/tests/pass/enums.rs +++ b/tests/pass/enums.rs @@ -119,6 +119,18 @@ fn more_discriminant_overflow() { } } +fn overaligned_casts() { + #[allow(dead_code)] + #[repr(align(8))] + enum Aligned { + Zero = 0, + One = 1, + } + + let aligned = Aligned::Zero; + assert_eq!(aligned as u8, 0); +} + fn main() { test(MyEnum::MyEmptyVariant); test(MyEnum::MyNewtypeVariant(42)); @@ -127,4 +139,5 @@ fn main() { discriminant_overflow(); more_discriminant_overflow(); + overaligned_casts(); } From 907a003f14cb34e8b429f23bfb86a4a33634ea68 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Jul 2022 09:47:48 -0400 Subject: [PATCH 3454/5092] tweak format strings --- src/diagnostics.rs | 31 ++++++++++-------------- src/intptrcast.rs | 4 ++-- src/machine.rs | 2 +- src/shims/intrinsics.rs | 38 ++++++++++++------------------ src/stacked_borrows/diagnostics.rs | 10 ++++---- tests/fail/uninit_buffer.stderr | 2 +- 6 files changed, 37 insertions(+), 50 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 11b5a21b2af8..289c46a5d2ef 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -40,24 +40,20 @@ impl fmt::Display for TerminationInfo { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use TerminationInfo::*; match self { - Exit(code) => write!(f, "the evaluated program completed with exit code {}", code), - Abort(msg) => write!(f, "{}", msg), - UnsupportedInIsolation(msg) => write!(f, "{}", msg), + Exit(code) => write!(f, "the evaluated program completed with exit code {code}"), + Abort(msg) => write!(f, "{msg}"), + UnsupportedInIsolation(msg) => write!(f, "{msg}"), Int2PtrWithStrictProvenance => write!( f, "integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance`" ), - StackedBorrowsUb { msg, .. } => write!(f, "{}", msg), + StackedBorrowsUb { msg, .. } => write!(f, "{msg}"), Deadlock => write!(f, "the evaluated program deadlocked"), MultipleSymbolDefinitions { link_name, .. } => - write!(f, "multiple definitions of symbol `{}`", link_name), + write!(f, "multiple definitions of symbol `{link_name}`"), SymbolShimClashing { link_name, .. } => - write!( - f, - "found `{}` symbol definition that clashes with a built-in shim", - link_name - ), + write!(f, "found `{link_name}` symbol definition that clashes with a built-in shim",), } } } @@ -200,11 +196,11 @@ pub fn report_error<'tcx, 'mir>( } MultipleSymbolDefinitions { first, first_crate, second, second_crate, .. } => vec![ - (Some(*first), format!("it's first defined here, in crate `{}`", first_crate)), - (Some(*second), format!("then it's defined here again, in crate `{}`", second_crate)), + (Some(*first), format!("it's first defined here, in crate `{first_crate}`")), + (Some(*second), format!("then it's defined here again, in crate `{second_crate}`")), ], SymbolShimClashing { link_name, span } => - vec![(Some(*span), format!("the `{}` symbol is defined here", link_name))], + vec![(Some(*span), format!("the `{link_name}` symbol is defined here"))], Int2PtrWithStrictProvenance => vec![(None, format!("use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead"))], _ => vec![], @@ -227,7 +223,7 @@ pub fn report_error<'tcx, 'mir>( ) => "post-monomorphization error", kind => - bug!("This error should be impossible in Miri: {:?}", kind), + bug!("This error should be impossible in Miri: {kind:?}"), }; #[rustfmt::skip] let helps = match e.kind() { @@ -235,7 +231,7 @@ pub fn report_error<'tcx, 'mir>( UnsupportedOpInfo::ThreadLocalStatic(_) | UnsupportedOpInfo::ReadExternStatic(_) ) => - panic!("Error should never be raised by Miri: {:?}", e.kind()), + panic!("Error should never be raised by Miri: {kind:?}", kind = e.kind()), Unsupported( UnsupportedOpInfo::Unsupported(_) | UnsupportedOpInfo::PartialPointerOverwrite(_) | @@ -295,9 +291,8 @@ pub fn report_error<'tcx, 'mir>( match e.kind() { UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) => { eprintln!( - "Uninitialized read occurred at offsets 0x{:x}..0x{:x} into this allocation:", - access.uninit_offset.bytes(), - access.uninit_offset.bytes() + access.uninit_size.bytes(), + "Uninitialized read occurred at {alloc_id:?}{range:?}, in this allocation:", + range = alloc_range(access.uninit_offset, access.uninit_size), ); eprintln!("{:?}", ecx.dump_alloc(*alloc_id)); } diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 5a33ada45044..e569960f68fb 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -110,7 +110,7 @@ impl<'mir, 'tcx> GlobalStateInner { ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, ) -> Pointer> { - trace!("Transmuting 0x{:x} to a pointer", addr); + trace!("Transmuting {:#x} to a pointer", addr); let provenance = if ecx.machine.allow_ptr_int_transmute { // When we allow transmutes, treat them like casts: generating a wildcard pointer. @@ -126,7 +126,7 @@ impl<'mir, 'tcx> GlobalStateInner { ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, ) -> InterpResult<'tcx, Pointer>> { - trace!("Casting 0x{:x} to a pointer", addr); + trace!("Casting {:#x} to a pointer", addr); let global_state = ecx.machine.intptrcast.borrow(); diff --git a/src/machine.rs b/src/machine.rs index 18b9a074c7c3..029c32cad917 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -155,7 +155,7 @@ impl Provenance for Tag { fn fmt(ptr: &Pointer, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (tag, addr) = ptr.into_parts(); // address is absolute - write!(f, "0x{:x}", addr.bytes())?; + write!(f, "{:#x}", addr.bytes())?; match tag { Tag::Concrete { alloc_id, sb } => { diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index d8f6292e9df3..652f5c94cb37 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -36,7 +36,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let intrinsic_name = this.tcx.item_name(instance.def_id()); let intrinsic_name = intrinsic_name.as_str(); let ret = match ret { - None => throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name), + None => throw_unsup_format!("unimplemented (diverging) intrinsic: `{intrinsic_name}`"), Some(p) => p, }; @@ -86,7 +86,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `checked_mul` enforces a too small bound (the correct one would probably be machine_isize_max), // but no actual allocation can be big enough for the difference to be noticeable. let byte_count = ty_layout.size.checked_mul(count, this).ok_or_else(|| { - err_ub_format!("overflow computing total size of `{}`", intrinsic_name) + err_ub_format!("overflow computing total size of `{intrinsic_name}`") })?; this.write_bytes_ptr( ptr, @@ -200,24 +200,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ty::Float(FloatTy::F32) => x.to_scalar()?.to_f32()?.is_finite(), ty::Float(FloatTy::F64) => x.to_scalar()?.to_f64()?.is_finite(), _ => bug!( - "`{}` called with non-float input type {:?}", - intrinsic_name, - x.layout.ty + "`{intrinsic_name}` called with non-float input type {ty:?}", + ty = x.layout.ty, ), }) }; match (float_finite(a)?, float_finite(b)?) { (false, false) => throw_ub_format!( - "`{}` intrinsic called with non-finite value as both parameters", - intrinsic_name, + "`{intrinsic_name}` intrinsic called with non-finite value as both parameters", ), (false, _) => throw_ub_format!( - "`{}` intrinsic called with non-finite value as first parameter", - intrinsic_name, + "`{intrinsic_name}` intrinsic called with non-finite value as first parameter", ), (_, false) => throw_ub_format!( - "`{}` intrinsic called with non-finite value as second parameter", - intrinsic_name, + "`{intrinsic_name}` intrinsic called with non-finite value as second parameter", ), _ => {} } @@ -494,7 +490,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // See . if overflowed { let r_val = right.to_scalar()?.to_bits(right.layout.size)?; - throw_ub_format!("overflowing shift by {} in `{}` in SIMD lane {}", r_val, intrinsic_name, i); + throw_ub_format!("overflowing shift by {r_val} in `{intrinsic_name}` in SIMD lane {i}"); } } if matches!(mir_op, BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge) { @@ -751,9 +747,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.float_to_int_unchecked(op.to_scalar()?.to_f64()?, dest.layout.ty)?.into(), _ => throw_unsup_format!( - "Unsupported SIMD cast from element type {} to {}", - op.layout.ty, - dest.layout.ty + "Unsupported SIMD cast from element type {from_ty} to {to_ty}", + from_ty = op.layout.ty, + to_ty = dest.layout.ty, ), }; this.write_immediate(val, &dest.into())?; @@ -1093,7 +1089,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_machine_stop!(TerminationInfo::Abort("Trace/breakpoint trap".to_string())) } - name => throw_unsup_format!("unimplemented intrinsic: {}", name), + name => throw_unsup_format!("unimplemented intrinsic: `{name}`"), } trace!("{:?}", this.dump_place(**dest)); @@ -1340,9 +1336,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { // `f` was not representable in this integer type. throw_ub_format!( - "`float_to_int_unchecked` intrinsic called on {} which cannot be represented in target type `{:?}`", - f, - dest_ty, + "`float_to_int_unchecked` intrinsic called on {f} which cannot be represented in target type `{dest_ty:?}`", ); } } @@ -1356,14 +1350,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { // `f` was not representable in this integer type. throw_ub_format!( - "`float_to_int_unchecked` intrinsic called on {} which cannot be represented in target type `{:?}`", - f, - dest_ty, + "`float_to_int_unchecked` intrinsic called on {f} which cannot be represented in target type `{dest_ty:?}`", ); } } // Nothing else - _ => bug!("`float_to_int_unchecked` called with non-int output type {:?}", dest_ty), + _ => bug!("`float_to_int_unchecked` called with non-int output type {dest_ty:?}"), }) } } diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index cee643fdf821..d787865c4e2d 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -140,9 +140,9 @@ impl AllocHistory { stack: &Stack, ) -> InterpError<'tcx> { let action = format!( - "trying to reborrow {derived_from:?} for {:?} permission at {alloc_id:?}[{:#x}]", - new.perm, - error_offset.bytes(), + "trying to reborrow {derived_from:?} for {new_perm:?} permission at {alloc_id:?}[{offset:#x}]", + new_perm = new.perm, + offset = error_offset.bytes(), ); err_sb_ub( format!("{}{}", action, error_cause(stack, derived_from)), @@ -162,8 +162,8 @@ impl AllocHistory { stack: &Stack, ) -> InterpError<'tcx> { let action = format!( - "attempting a {access} using {tag:?} at {alloc_id:?}[{:#x}]", - error_offset.bytes(), + "attempting a {access} using {tag:?} at {alloc_id:?}[{offset:#x}]", + offset = error_offset.bytes(), ); err_sb_ub( format!("{}{}", action, error_cause(stack, tag)), diff --git a/tests/fail/uninit_buffer.stderr b/tests/fail/uninit_buffer.stderr index e684ca8f0771..e8faf8dd8b97 100644 --- a/tests/fail/uninit_buffer.stderr +++ b/tests/fail/uninit_buffer.stderr @@ -17,7 +17,7 @@ LL | drop(slice1.cmp(slice2)); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -Uninitialized read occurred at offsets 0x4..0x10 into this allocation: +Uninitialized read occurred at ALLOC[0x4..0x10], in this allocation: ALLOC (Rust heap, size: 32, align: 8) { 0x00 │ 41 42 43 44 __ __ __ __ __ __ __ __ __ __ __ __ │ ABCD░░░░░░░░░░░░ 0x10 │ 00 __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ .░░░░░░░░░░░░░░░ From 7913b8543e90602e98092f23be31259841671ff1 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 16 Jun 2022 09:37:01 -0400 Subject: [PATCH 3455/5092] unit tests that inspect LLVM output directly. This relies on a human being to confirm that the entries actually correspond to what is specified in each of the respective ABIs... updated to incorporate feedback: fix x86_64/i686 tests to use correct name for the corresponding llvm component. --- .../some-abis-do-extend-params-to-32-bits.rs | 204 ++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 src/test/codegen/some-abis-do-extend-params-to-32-bits.rs diff --git a/src/test/codegen/some-abis-do-extend-params-to-32-bits.rs b/src/test/codegen/some-abis-do-extend-params-to-32-bits.rs new file mode 100644 index 000000000000..7fc34af3da72 --- /dev/null +++ b/src/test/codegen/some-abis-do-extend-params-to-32-bits.rs @@ -0,0 +1,204 @@ +// compile-flags: -Cno-prepopulate-passes + +// revisions:x86_64 i686 aarch64-apple aarch64-windows aarch64-linux arm riscv + +//[x86_64] compile-flags: --target x86_64-unknown-uefi +//[x86_64] needs-llvm-components: x86 +//[i686] compile-flags: --target i686-unknown-linux-musl +//[i686] needs-llvm-components: x86 +//[aarch64-windows] compile-flags: --target aarch64-pc-windows-msvc +//[aarch64-windows] needs-llvm-components: aarch64 +//[aarch64-linux] compile-flags: --target aarch64-unknown-linux-gnu +//[aarch64-linux] needs-llvm-components: aarch64 +//[aarch64-apple] compile-flags: --target aarch64-apple-darwin +//[aarch64-apple] needs-llvm-components: aarch64 +//[arm] compile-flags: --target armv7r-none-eabi +//[arm] needs-llvm-components: arm +//[riscv] compile-flags: --target riscv64gc-unknown-none-elf +//[riscv] needs-llvm-components: riscv + +// See bottom of file for a corresponding C source file that is meant to yield +// equivalent declarations. +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_std] +#![no_core] + +#[lang="sized"] trait Sized { } +#[lang="freeze"] trait Freeze { } +#[lang="copy"] trait Copy { } + +// The patterns in this file are written in the style of a table to make the +// uniformities and distinctions more apparent. +// +// ZERO/SIGN-EXTENDING TO 32 BITS NON-EXTENDING +// ============================== ======================= +// x86_64: void @c_arg_u8(i8 zeroext %_a) +// i686: void @c_arg_u8(i8 zeroext %_a) +// aarch64-apple: void @c_arg_u8(i8 zeroext %_a) +// aarch64-windows: void @c_arg_u8(i8 %_a) +// aarch64-linux: void @c_arg_u8(i8 %_a) +// arm: void @c_arg_u8(i8 zeroext %_a) +// riscv: void @c_arg_u8(i8 zeroext %_a) +#[no_mangle] pub extern "C" fn c_arg_u8(_a: u8) { } + +// x86_64: void @c_arg_u16(i16 zeroext %_a) +// i686: void @c_arg_u16(i16 zeroext %_a) +// aarch64-apple: void @c_arg_u16(i16 zeroext %_a) +// aarch64-windows: void @c_arg_u16(i16 %_a) +// aarch64-linux: void @c_arg_u16(i16 %_a) +// arm: void @c_arg_u16(i16 zeroext %_a) +// riscv: void @c_arg_u16(i16 zeroext %_a) +#[no_mangle] pub extern "C" fn c_arg_u16(_a: u16) { } + +// x86_64: void @c_arg_u32(i32 %_a) +// i686: void @c_arg_u32(i32 %_a) +// aarch64-apple: void @c_arg_u32(i32 %_a) +// aarch64-windows: void @c_arg_u32(i32 %_a) +// aarch64-linux: void @c_arg_u32(i32 %_a) +// arm: void @c_arg_u32(i32 %_a) +// riscv: void @c_arg_u32(i32 signext %_a) +#[no_mangle] pub extern "C" fn c_arg_u32(_a: u32) { } + +// x86_64: void @c_arg_u64(i64 %_a) +// i686: void @c_arg_u64(i64 %_a) +// aarch64-apple: void @c_arg_u64(i64 %_a) +// aarch64-windows: void @c_arg_u64(i64 %_a) +// aarch64-linux: void @c_arg_u64(i64 %_a) +// arm: void @c_arg_u64(i64 %_a) +// riscv: void @c_arg_u64(i64 %_a) +#[no_mangle] pub extern "C" fn c_arg_u64(_a: u64) { } + +// x86_64: void @c_arg_i8(i8 signext %_a) +// i686: void @c_arg_i8(i8 signext %_a) +// aarch64-apple: void @c_arg_i8(i8 signext %_a) +// aarch64-windows: void @c_arg_i8(i8 %_a) +// aarch64-linux: void @c_arg_i8(i8 %_a) +// arm: void @c_arg_i8(i8 signext %_a) +// riscv: void @c_arg_i8(i8 signext %_a) +#[no_mangle] pub extern "C" fn c_arg_i8(_a: i8) { } + +// x86_64: void @c_arg_i16(i16 signext %_a) +// i686: void @c_arg_i16(i16 signext %_a) +// aarch64-apple: void @c_arg_i16(i16 signext %_a) +// aarch64-windows: void @c_arg_i16(i16 %_a) +// aarch64-linux: void @c_arg_i16(i16 %_a) +// arm: void @c_arg_i16(i16 signext %_a) +// riscv: void @c_arg_i16(i16 signext %_a) +#[no_mangle] pub extern "C" fn c_arg_i16(_a: i16) { } + +// x86_64: void @c_arg_i32(i32 %_a) +// i686: void @c_arg_i32(i32 %_a) +// aarch64-apple: void @c_arg_i32(i32 %_a) +// aarch64-windows: void @c_arg_i32(i32 %_a) +// aarch64-linux: void @c_arg_i32(i32 %_a) +// arm: void @c_arg_i32(i32 %_a) +// riscv: void @c_arg_i32(i32 signext %_a) +#[no_mangle] pub extern "C" fn c_arg_i32(_a: i32) { } + +// x86_64: void @c_arg_i64(i64 %_a) +// i686: void @c_arg_i64(i64 %_a) +// aarch64-apple: void @c_arg_i64(i64 %_a) +// aarch64-windows: void @c_arg_i64(i64 %_a) +// aarch64-linux: void @c_arg_i64(i64 %_a) +// arm: void @c_arg_i64(i64 %_a) +// riscv: void @c_arg_i64(i64 %_a) +#[no_mangle] pub extern "C" fn c_arg_i64(_a: i64) { } + +// x86_64: zeroext i8 @c_ret_u8() +// i686: zeroext i8 @c_ret_u8() +// aarch64-apple: zeroext i8 @c_ret_u8() +// aarch64-windows: i8 @c_ret_u8() +// aarch64-linux: i8 @c_ret_u8() +// arm: zeroext i8 @c_ret_u8() +// riscv: zeroext i8 @c_ret_u8() +#[no_mangle] pub extern "C" fn c_ret_u8() -> u8 { 0 } + +// x86_64: zeroext i16 @c_ret_u16() +// i686: zeroext i16 @c_ret_u16() +// aarch64-apple: zeroext i16 @c_ret_u16() +// aarch64-windows: i16 @c_ret_u16() +// aarch64-linux: i16 @c_ret_u16() +// arm: zeroext i16 @c_ret_u16() +// riscv: zeroext i16 @c_ret_u16() +#[no_mangle] pub extern "C" fn c_ret_u16() -> u16 { 0 } + +// x86_64: i32 @c_ret_u32() +// i686: i32 @c_ret_u32() +// aarch64-apple: i32 @c_ret_u32() +// aarch64-windows: i32 @c_ret_u32() +// aarch64-linux: i32 @c_ret_u32() +// arm: i32 @c_ret_u32() +// riscv: signext i32 @c_ret_u32() +#[no_mangle] pub extern "C" fn c_ret_u32() -> u32 { 0 } + +// x86_64: i64 @c_ret_u64() +// i686: i64 @c_ret_u64() +// aarch64-apple: i64 @c_ret_u64() +// aarch64-windows: i64 @c_ret_u64() +// aarch64-linux: i64 @c_ret_u64() +// arm: i64 @c_ret_u64() +// riscv: i64 @c_ret_u64() +#[no_mangle] pub extern "C" fn c_ret_u64() -> u64 { 0 } + +// x86_64: signext i8 @c_ret_i8() +// i686: signext i8 @c_ret_i8() +// aarch64-apple: signext i8 @c_ret_i8() +// aarch64-windows: i8 @c_ret_i8() +// aarch64-linux: i8 @c_ret_i8() +// arm: signext i8 @c_ret_i8() +// riscv: signext i8 @c_ret_i8() +#[no_mangle] pub extern "C" fn c_ret_i8() -> i8 { 0 } + +// x86_64: signext i16 @c_ret_i16() +// i686: signext i16 @c_ret_i16() +// aarch64-apple: signext i16 @c_ret_i16() +// aarch64-windows: i16 @c_ret_i16() +// aarch64-linux: i16 @c_ret_i16() +// arm: signext i16 @c_ret_i16() +// riscv: signext i16 @c_ret_i16() +#[no_mangle] pub extern "C" fn c_ret_i16() -> i16 { 0 } + +// x86_64: i32 @c_ret_i32() +// i686: i32 @c_ret_i32() +// aarch64-apple: i32 @c_ret_i32() +// aarch64-windows: i32 @c_ret_i32() +// aarch64-linux: i32 @c_ret_i32() +// arm: i32 @c_ret_i32() +// riscv: signext i32 @c_ret_i32() +#[no_mangle] pub extern "C" fn c_ret_i32() -> i32 { 0 } + +// x86_64: i64 @c_ret_i64() +// i686: i64 @c_ret_i64() +// aarch64-apple: i64 @c_ret_i64() +// aarch64-windows: i64 @c_ret_i64() +// aarch64-linux: i64 @c_ret_i64() +// arm: i64 @c_ret_i64() +// riscv: i64 @c_ret_i64() +#[no_mangle] pub extern "C" fn c_ret_i64() -> i64 { 0 } + +const C_SOURCE_FILE: &'static str = r##" +#include +#include +#include + +void c_arg_u8(uint8_t _a) { } +void c_arg_u16(uint16_t _a) { } +void c_arg_u32(uint32_t _a) { } +void c_arg_u64(uint64_t _a) { } + +void c_arg_i8(int8_t _a) { } +void c_arg_i16(int16_t _a) { } +void c_arg_i32(int32_t _a) { } +void c_arg_i64(int64_t _a) { } + +uint8_t c_ret_u8() { return 0; } +uint16_t c_ret_u16() { return 0; } +uint32_t c_ret_u32() { return 0; } +uint64_t c_ret_u64() { return 0; } + +int8_t c_ret_i8() { return 0; } +int16_t c_ret_i16() { return 0; } +int32_t c_ret_i32() { return 0; } +int64_t c_ret_i64() { return 0; } +"##; From b2777aba757dd92042932d79309132bd953e130d Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 6 Jun 2022 12:39:58 -0400 Subject: [PATCH 3456/5092] End-to-end regression test for 97463. incorporated review feedback, with comment explaining why this is calling CC instead of COMPILE_OBJ or NATIVE_STATICLIB. As drive-by, removed some other unnecessary commands from the recipe. --- .../issue-97463-abi-param-passing/Makefile | 12 ++++++ .../issue-97463-abi-param-passing/bad.c | 24 ++++++++++++ .../param_passing.rs | 38 +++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 src/test/run-make-fulldeps/issue-97463-abi-param-passing/Makefile create mode 100644 src/test/run-make-fulldeps/issue-97463-abi-param-passing/bad.c create mode 100644 src/test/run-make-fulldeps/issue-97463-abi-param-passing/param_passing.rs diff --git a/src/test/run-make-fulldeps/issue-97463-abi-param-passing/Makefile b/src/test/run-make-fulldeps/issue-97463-abi-param-passing/Makefile new file mode 100644 index 000000000000..b3db6bcb3f63 --- /dev/null +++ b/src/test/run-make-fulldeps/issue-97463-abi-param-passing/Makefile @@ -0,0 +1,12 @@ +-include ../tools.mk + +# The issue exercised by this test, rust-lang/rust#97463, explicitly needs `-O` +# flags (like `-O3`) to reproduce. Thus, we call $(CC) instead of nicer +# alternatives provided by tools.mk like using `COMPILE_OBJ` or using a +# `NATIVE_STATICLIB` dependency. + +all: + $(CC) -c -O3 -o $(TMPDIR)/bad.o bad.c + $(AR) rcs $(TMPDIR)/libbad.a $(TMPDIR)/bad.o + $(RUSTC) param_passing.rs -L$(TMPDIR) -lbad -C opt-level=3 + $(call RUN,param_passing) diff --git a/src/test/run-make-fulldeps/issue-97463-abi-param-passing/bad.c b/src/test/run-make-fulldeps/issue-97463-abi-param-passing/bad.c new file mode 100644 index 000000000000..013314ab20dc --- /dev/null +++ b/src/test/run-make-fulldeps/issue-97463-abi-param-passing/bad.c @@ -0,0 +1,24 @@ +#include +#include +#include + + +struct bloc { + uint16_t a; + uint16_t b; + uint16_t c; +}; + +uint16_t c_read_value(uint32_t a, uint32_t b, uint32_t c) { + struct bloc *data = malloc(sizeof(struct bloc)); + + data->a = a & 0xFFFF; + data->b = b & 0xFFFF; + data->c = c & 0xFFFF; + + printf("C struct: a = %u, b = %u, c = %u\n", + (unsigned) data->a, (unsigned) data->b, (unsigned) data->c); + printf("C function returns %u\n", (unsigned) data->b); + + return data->b; /* leak data */ +} diff --git a/src/test/run-make-fulldeps/issue-97463-abi-param-passing/param_passing.rs b/src/test/run-make-fulldeps/issue-97463-abi-param-passing/param_passing.rs new file mode 100644 index 000000000000..b4744a3b96e7 --- /dev/null +++ b/src/test/run-make-fulldeps/issue-97463-abi-param-passing/param_passing.rs @@ -0,0 +1,38 @@ +// NOTE: Exposing the bug encoded in this test is sensitive to +// LLVM optimization choices. See additional note below for an +// example. + +#[link(name = "bad")] +extern "C" { + pub fn c_read_value(a: u32, b: u32, c: u32) -> u16; +} + +fn main() { + const C1: usize = 0x327b23c6; + const C2: usize = C1 & 0xFFFF; + + let r1: usize = 0x0; + let r2: usize = C1; + let r3: usize = 0x0; + let value: u16 = unsafe { c_read_value(r1 as u32, r2 as u32, r3 as u32) }; + + // NOTE: as an example of the sensitivity of this test to optimization choices, + // uncommenting this block of code makes the bug go away on pnkfeix's machine. + // (But observing via `dbg!` doesn't hide the bug. At least sometimes.) + /* + println!("{}", value); + println!("{}", value as usize); + println!("{}", usize::from(value)); + println!("{}", (value as usize) & 0xFFFF); + */ + + let d1 = value; + let d2 = value as usize; + let d3 = usize::from(value); + let d4 = (value as usize) & 0xFFFF; + + let d = (&d1, &d2, &d3, &d4); + let d_ = (d1, d2, d3, d4); + + assert_eq!(((&(C2 as u16), &C2, &C2, &C2), (C2 as u16, C2, C2, C2)), (d, d_)); +} From 8ae5a55ba55a434995d2e2e87f8ef15237ff8124 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 6 Jun 2022 12:40:10 -0400 Subject: [PATCH 3457/5092] fix issue 97463 using change suggested by nbdd0121. parameterized on target details to decide value-extension policy on calls, in order to address how Apple's aarch64 ABI differs from that on Linux and Windows. Updated to incorporate review feedback: adjust comment on new enum specifying param extension policy. Updated to incorporate review feedback: shorten enum names and those of its variants to make it less unwieldy. placate tidy. --- compiler/rustc_target/src/abi/call/aarch64.rs | 41 +++++++++++++++---- compiler/rustc_target/src/abi/call/mod.rs | 9 +++- compiler/rustc_target/src/spec/mod.rs | 2 + 3 files changed, 44 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_target/src/abi/call/aarch64.rs b/compiler/rustc_target/src/abi/call/aarch64.rs index 4613a459c51d..b307cc3e0beb 100644 --- a/compiler/rustc_target/src/abi/call/aarch64.rs +++ b/compiler/rustc_target/src/abi/call/aarch64.rs @@ -1,6 +1,27 @@ use crate::abi::call::{ArgAbi, FnAbi, Reg, RegKind, Uniform}; use crate::abi::{HasDataLayout, TyAbiInterface}; +/// Given integer-types M and register width N (e.g. M=u16 and N=32 bits), the +/// `ParamExtension` policy specifies how a uM value should be treated when +/// passed via register or stack-slot of width N. See also rust-lang/rust#97463. +#[derive(Copy, Clone, PartialEq)] +pub enum ParamExtension { + /// Indicates that when passing an i8/i16, either as a function argument or + /// as a return value, it must be sign-extended to 32 bits, and likewise a + /// u8/u16 must be zero-extended to 32-bits. (This variant is here to + /// accommodate Apple's deviation from the usual AArch64 ABI as defined by + /// ARM.) + /// + /// See also: https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Pass-Arguments-to-Functions-Correctly + ExtendTo32Bits, + + /// Indicates that no sign- nor zero-extension is performed: if a value of + /// type with bitwidth M is passed as function argument or return value, + /// then M bits are copied into the least significant M bits, and the + /// remaining bits of the register (or word of memory) are untouched. + NoExtension, +} + fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Option where Ty: TyAbiInterface<'a, C> + Copy, @@ -24,13 +45,16 @@ where }) } -fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>) +fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, param_policy: ParamExtension) where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, { if !ret.layout.is_aggregate() { - ret.extend_integer_width_to(32); + match param_policy { + ParamExtension::ExtendTo32Bits => ret.extend_integer_width_to(32), + ParamExtension::NoExtension => {} + } return; } if let Some(uniform) = is_homogeneous_aggregate(cx, ret) { @@ -46,13 +70,16 @@ where ret.make_indirect(); } -fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) +fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, param_policy: ParamExtension) where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, { if !arg.layout.is_aggregate() { - arg.extend_integer_width_to(32); + match param_policy { + ParamExtension::ExtendTo32Bits => arg.extend_integer_width_to(32), + ParamExtension::NoExtension => {} + } return; } if let Some(uniform) = is_homogeneous_aggregate(cx, arg) { @@ -68,19 +95,19 @@ where arg.make_indirect(); } -pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) +pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, param_policy: ParamExtension) where Ty: TyAbiInterface<'a, C> + Copy, C: HasDataLayout, { if !fn_abi.ret.is_ignore() { - classify_ret(cx, &mut fn_abi.ret); + classify_ret(cx, &mut fn_abi.ret, param_policy); } for arg in &mut fn_abi.args { if arg.is_ignore() { continue; } - classify_arg(cx, arg); + classify_arg(cx, arg, param_policy); } } diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index ca1d1302ec68..c87c726cb877 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -687,7 +687,14 @@ impl<'a, Ty> FnAbi<'a, Ty> { } } }, - "aarch64" => aarch64::compute_abi_info(cx, self), + "aarch64" => { + let param_policy = if cx.target_spec().is_like_osx { + aarch64::ParamExtension::ExtendTo32Bits + } else { + aarch64::ParamExtension::NoExtension + }; + aarch64::compute_abi_info(cx, self, param_policy) + } "amdgpu" => amdgpu::compute_abi_info(cx, self), "arm" => arm::compute_abi_info(cx, self), "avr" => avr::compute_abi_info(self), diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index a08603da0409..e78fefdcfad2 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1250,6 +1250,8 @@ pub struct TargetOptions { pub abi_return_struct_as_int: bool, /// Whether the target toolchain is like macOS's. Only useful for compiling against iOS/macOS, /// in particular running dsymutil and some other stuff like `-dead_strip`. Defaults to false. + /// Also indiates whether to use Apple-specific ABI changes, such as extending function + /// parameters to 32-bits. pub is_like_osx: bool, /// Whether the target toolchain is like Solaris's. /// Only useful for compiling against Illumos/Solaris, From dfdb017a9bb6284f58ff8447cd2a49c778552f62 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 30 Jun 2022 00:31:41 -0400 Subject: [PATCH 3458/5092] experiment: trying to encode the end-to-end test as a ui test via rust_test_helpers. This instance is almost certainly insufficient because we need to force optimization flags for both the C and Rust sides of the code. but lets find out for sure. --- src/test/auxiliary/rust_test_helpers.c | 12 ++++++ ...sue-97463-broken-abi-leaked-uninit-data.rs | 38 +++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 src/test/ui/abi/issues/issue-97463-broken-abi-leaked-uninit-data.rs diff --git a/src/test/auxiliary/rust_test_helpers.c b/src/test/auxiliary/rust_test_helpers.c index 92b7dd4b7c51..977ea487a980 100644 --- a/src/test/auxiliary/rust_test_helpers.c +++ b/src/test/auxiliary/rust_test_helpers.c @@ -1,6 +1,7 @@ // Helper functions used only in tests #include +#include #include #include @@ -415,3 +416,14 @@ rust_dbg_unpack_option_u64u64(struct U8TaggedEnumOptionU64U64 o, uint64_t *a, ui return 0; } } + +uint16_t issue_97463_leak_uninit_data(uint32_t a, uint32_t b, uint32_t c) { + struct bloc { uint16_t a; uint16_t b; uint16_t c; }; + struct bloc *data = malloc(sizeof(struct bloc)); + + data->a = a & 0xFFFF; + data->b = b & 0xFFFF; + data->c = c & 0xFFFF; + + return data->b; /* leak data */ +} diff --git a/src/test/ui/abi/issues/issue-97463-broken-abi-leaked-uninit-data.rs b/src/test/ui/abi/issues/issue-97463-broken-abi-leaked-uninit-data.rs new file mode 100644 index 000000000000..d04375acb30a --- /dev/null +++ b/src/test/ui/abi/issues/issue-97463-broken-abi-leaked-uninit-data.rs @@ -0,0 +1,38 @@ +// run-pass +#![allow(dead_code)] +#![allow(improper_ctypes)] + +#[link(name = "rust_test_helpers", kind = "static")] +extern "C" { + pub fn issue_97463_leak_uninit_data(a: u32, b: u32, c: u32) -> u16; +} + +fn main() { + const C1: usize = 0x327b23c6; + const C2: usize = C1 & 0xFFFF; + + let r1: usize = 0x0; + let r2: usize = C1; + let r3: usize = 0x0; + let value: u16 = unsafe { issue_97463_leak_uninit_data(r1 as u32, r2 as u32, r3 as u32) }; + + // NOTE: as an example of the sensitivity of this test to optimization choices, + // uncommenting this block of code makes the bug go away on pnkfeix's machine. + // (But observing via `dbg!` doesn't hide the bug. At least sometimes.) + /* + println!("{}", value); + println!("{}", value as usize); + println!("{}", usize::from(value)); + println!("{}", (value as usize) & 0xFFFF); + */ + + let d1 = value; + let d2 = value as usize; + let d3 = usize::from(value); + let d4 = (value as usize) & 0xFFFF; + + let d = (&d1, &d2, &d3, &d4); + let d_ = (d1, d2, d3, d4); + + assert_eq!(((&(C2 as u16), &C2, &C2, &C2), (C2 as u16, C2, C2, C2)), (d, d_)); +} From 501a6b4687a73068ff86c01a37d009c6ea2743dc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Jul 2022 14:06:15 -0400 Subject: [PATCH 3459/5092] rustup --- rust-version | 2 +- src/machine.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 123c4a5b5b56..da7e1a1ae7d2 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -f342bea9d19f14616c6559312552e6d0ee529cfd +049308cf8b48e9d67e54d6d0b01c10c79d1efc3a diff --git a/src/machine.rs b/src/machine.rs index 029c32cad917..a2d9e9ced1a1 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -542,7 +542,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } #[inline(always)] - fn check_binop_checks_overflow(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { + fn checked_binop_checks_overflow(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { ecx.tcx.sess.overflow_checks() } From d5f1c263806880280a3e4d9b01170791d360c618 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Jul 2022 21:28:47 -0400 Subject: [PATCH 3460/5092] rustup; ptr atomics --- rust-version | 2 +- src/helpers.rs | 4 +-- src/operator.rs | 66 ++++++++++++++++++++--------------------- src/shims/intrinsics.rs | 31 +++++++++++-------- tests/pass/atomic.rs | 55 +++++++++++++++++++++++++++++++++- 5 files changed, 107 insertions(+), 51 deletions(-) diff --git a/rust-version b/rust-version index da7e1a1ae7d2..8f3b1d39fd04 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -049308cf8b48e9d67e54d6d0b01c10c79d1efc3a +7665c3543079ebc3710b676d0fd6951bedfd4b29 diff --git a/src/helpers.rs b/src/helpers.rs index 4b2604afa2c1..29bf92af3faf 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -195,9 +195,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Test if this pointer equals 0. fn ptr_is_null(&self, ptr: Pointer>) -> InterpResult<'tcx, bool> { - let this = self.eval_context_ref(); - let null = Scalar::null_ptr(this); - this.ptr_eq(Scalar::from_maybe_pointer(ptr, this), null) + Ok(ptr.addr().bytes() == 0) } /// Get the `Place` for a local diff --git a/src/operator.rs b/src/operator.rs index 33c97e7d3109..e7a43ac95520 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,6 +1,7 @@ use log::trace; use rustc_middle::{mir, ty::Ty}; +use rustc_target::abi::Size; use crate::*; @@ -11,8 +12,6 @@ pub trait EvalContextExt<'tcx> { left: &ImmTy<'tcx, Tag>, right: &ImmTy<'tcx, Tag>, ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)>; - - fn ptr_eq(&self, left: Scalar, right: Scalar) -> InterpResult<'tcx, bool>; } impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { @@ -27,23 +26,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); Ok(match bin_op { - Eq | Ne => { - // This supports fat pointers. - #[rustfmt::skip] - let eq = match (**left, **right) { - (Immediate::Scalar(left), Immediate::Scalar(right)) => { - self.ptr_eq(left.check_init()?, right.check_init()?)? - } - (Immediate::ScalarPair(left1, left2), Immediate::ScalarPair(right1, right2)) => { - self.ptr_eq(left1.check_init()?, right1.check_init()?)? - && self.ptr_eq(left2.check_init()?, right2.check_init()?)? - } - _ => bug!("Type system should not allow comparing Scalar with ScalarPair"), - }; - (Scalar::from_bool(if bin_op == Eq { eq } else { !eq }), false, self.tcx.types.bool) - } - - Lt | Le | Gt | Ge => { + Eq | Ne | Lt | Le | Gt | Ge => { + assert_eq!(left.layout.abi, right.layout.abi); // types an differ, e.g. fn ptrs with different `for` let size = self.pointer_size(); // Just compare the bits. ScalarPairs are compared lexicographically. // We thus always compare pairs and simply fill scalars up with 0. @@ -58,35 +42,49 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { (r1.check_init()?.to_bits(size)?, r2.check_init()?.to_bits(size)?), }; let res = match bin_op { + Eq => left == right, + Ne => left != right, Lt => left < right, Le => left <= right, Gt => left > right, Ge => left >= right, - _ => bug!("We already established it has to be one of these operators."), + _ => bug!(), }; (Scalar::from_bool(res), false, self.tcx.types.bool) } Offset => { + assert!(left.layout.ty.is_unsafe_ptr()); + let ptr = self.scalar_to_ptr(left.to_scalar()?)?; + let offset = right.to_scalar()?.to_machine_isize(self)?; + let pointee_ty = left.layout.ty.builtin_deref(true).expect("Offset called on non-ptr type").ty; - let ptr = self.ptr_offset_inbounds( - self.scalar_to_ptr(left.to_scalar()?)?, - pointee_ty, - right.to_scalar()?.to_machine_isize(self)?, - )?; + let ptr = self.ptr_offset_inbounds(ptr, pointee_ty, offset)?; (Scalar::from_maybe_pointer(ptr, self), false, left.layout.ty) } - _ => bug!("Invalid operator on pointers: {:?}", bin_op), + // Some more operations are possible with atomics. + // The return value always has the provenance of the *left* operand. + Add | Sub | BitOr | BitAnd | BitXor => { + assert!(left.layout.ty.is_unsafe_ptr()); + assert!(right.layout.ty.is_unsafe_ptr()); + let ptr = self.scalar_to_ptr(left.to_scalar()?)?; + // We do the actual operation with usize-typed scalars. + let left = ImmTy::from_uint(ptr.addr().bytes(), self.machine.layouts.usize); + let right = ImmTy::from_uint( + right.to_scalar()?.to_machine_usize(self)?, + self.machine.layouts.usize, + ); + let (result, overflowing, _ty) = + self.overflowing_binary_op(bin_op, &left, &right)?; + // Construct a new pointer with the provenance of `ptr` (the LHS). + let result_ptr = + Pointer::new(ptr.provenance, Size::from_bytes(result.to_machine_usize(self)?)); + (Scalar::from_maybe_pointer(result_ptr, self), overflowing, left.layout.ty) + } + + _ => span_bug!(self.cur_span(), "Invalid operator on pointers: {:?}", bin_op), }) } - - fn ptr_eq(&self, left: Scalar, right: Scalar) -> InterpResult<'tcx, bool> { - let size = self.pointer_size(); - // Just compare the integers. - let left = left.to_bits(size)?; - let right = right.to_bits(size)?; - Ok(left == right) - } } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 652f5c94cb37..9cf9461715f1 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -314,7 +314,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ty::Float(FloatTy::F64) => this.float_to_int_unchecked(val.to_scalar()?.to_f64()?, dest.layout.ty)?, _ => - bug!( + span_bug!( + this.cur_span(), "`float_to_int_unchecked` called with non-float input type {:?}", val.layout.ty ), @@ -371,7 +372,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Op::Abs => { // Works for f32 and f64. let ty::Float(float_ty) = op.layout.ty.kind() else { - bug!("{} operand is not a float", intrinsic_name) + span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name) }; let op = op.to_scalar()?; match float_ty { @@ -381,7 +382,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Op::HostOp(host_op) => { let ty::Float(float_ty) = op.layout.ty.kind() else { - bug!("{} operand is not a float", intrinsic_name) + span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name) }; // FIXME using host floats match float_ty { @@ -546,7 +547,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Works for f32 and f64. let ty::Float(float_ty) = dest.layout.ty.kind() else { - bug!("{} operand is not a float", intrinsic_name) + span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name) }; let val = match float_ty { FloatTy::F32 => @@ -763,7 +764,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `index` is an array, not a SIMD type let ty::Array(_, index_len) = index.layout.ty.kind() else { - bug!("simd_shuffle index argument has non-array type {}", index.layout.ty) + span_bug!(this.cur_span(), "simd_shuffle index argument has non-array type {}", index.layout.ty) }; let index_len = index_len.eval_usize(*this.tcx, this.param_env()); @@ -785,10 +786,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &this.mplace_index(&right, src_index - left_len)?.into(), )? } else { - bug!( - "simd_shuffle index {} is out of bounds for 2 vectors of size {}", - src_index, - left_len + span_bug!( + this.cur_span(), + "simd_shuffle index {src_index} is out of bounds for 2 vectors of size {left_len}", ); }; this.write_immediate(*val, &dest.into())?; @@ -1187,8 +1187,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [place, rhs] = check_arg_count(args)?; let place = this.deref_operand(place)?; - if !place.layout.ty.is_integral() { - bug!("Atomic arithmetic operations only work on integer types"); + if !place.layout.ty.is_integral() && !place.layout.ty.is_unsafe_ptr() { + span_bug!( + this.cur_span(), + "atomic arithmetic operations only work on integer and raw pointer types", + ); } let rhs = this.read_immediate(rhs)?; @@ -1355,7 +1358,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } // Nothing else - _ => bug!("`float_to_int_unchecked` called with non-int output type {dest_ty:?}"), + _ => + span_bug!( + this.cur_span(), + "`float_to_int_unchecked` called with non-int output type {dest_ty:?}" + ), }) } } diff --git a/tests/pass/atomic.rs b/tests/pass/atomic.rs index b0c3cc889d55..75e9cbdf1326 100644 --- a/tests/pass/atomic.rs +++ b/tests/pass/atomic.rs @@ -1,10 +1,15 @@ -use std::sync::atomic::{compiler_fence, fence, AtomicBool, AtomicIsize, AtomicU64, Ordering::*}; +// compile-flags: -Zmiri-strict-provenance +#![feature(strict_provenance, strict_provenance_atomic_ptr)] +use std::sync::atomic::{ + compiler_fence, fence, AtomicBool, AtomicIsize, AtomicPtr, AtomicU64, Ordering::*, +}; fn main() { atomic_bool(); atomic_all_ops(); atomic_u64(); atomic_fences(); + atomic_ptr(); weak_sometimes_fails(); } @@ -130,6 +135,54 @@ fn atomic_fences() { compiler_fence(AcqRel); } +fn atomic_ptr() { + use std::ptr; + let array: Vec = (0..100).into_iter().collect(); // a target to point to, to test provenance things + let x = array.as_ptr() as *mut i32; + + let ptr = AtomicPtr::::new(ptr::null_mut()); + assert!(ptr.load(Relaxed).addr() == 0); + ptr.store(ptr::invalid_mut(13), SeqCst); + assert!(ptr.swap(x, Relaxed).addr() == 13); + unsafe { assert!(*ptr.load(Acquire) == 0) }; + + // comparison ignores provenance + assert_eq!( + ptr.compare_exchange( + (&mut 0 as *mut i32).with_addr(x.addr()), + ptr::invalid_mut(0), + SeqCst, + SeqCst + ) + .unwrap() + .addr(), + x.addr(), + ); + assert_eq!( + ptr.compare_exchange( + (&mut 0 as *mut i32).with_addr(x.addr()), + ptr::invalid_mut(0), + SeqCst, + SeqCst + ) + .unwrap_err() + .addr(), + 0, + ); + ptr.store(x, Relaxed); + + assert_eq!(ptr.fetch_ptr_add(13, AcqRel).addr(), x.addr()); + unsafe { assert_eq!(*ptr.load(SeqCst), 13) }; // points to index 13 now + assert_eq!(ptr.fetch_ptr_sub(4, AcqRel).addr(), x.addr() + 13 * 4); + unsafe { assert_eq!(*ptr.load(SeqCst), 9) }; + assert_eq!(ptr.fetch_or(3, AcqRel).addr(), x.addr() + 9 * 4); // ptr is 4-aligned, so set the last 2 bits + assert_eq!(ptr.fetch_and(!3, AcqRel).addr(), (x.addr() + 9 * 4) | 3); // and unset them again + unsafe { assert_eq!(*ptr.load(SeqCst), 9) }; + assert_eq!(ptr.fetch_xor(0xdeadbeef, AcqRel).addr(), x.addr() + 9 * 4); + assert_eq!(ptr.fetch_xor(0xdeadbeef, AcqRel).addr(), (x.addr() + 9 * 4) ^ 0xdeadbeef); + unsafe { assert_eq!(*ptr.load(SeqCst), 9) }; // after XORing twice with the same thing, we get our ptr back +} + fn weak_sometimes_fails() { let atomic = AtomicBool::new(false); let tries = 100; From e5df0cc770893d3139f7b5610e09eebe5df79ae1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Jul 2022 20:10:44 -0400 Subject: [PATCH 3461/5092] adjust tests for removal of unsized_locals --- tests/fail/unsized-local.rs | 23 ++++++++++++++++++++ tests/fail/unsized-local.stderr | 14 ++++++++++++ tests/pass/dyn-traits.rs | 12 ++++------- tests/pass/unsized-tuple-impls.rs | 13 ----------- tests/pass/unsized.rs | 36 +++++++++++++++++++++++++++++++ 5 files changed, 77 insertions(+), 21 deletions(-) create mode 100644 tests/fail/unsized-local.rs create mode 100644 tests/fail/unsized-local.stderr delete mode 100644 tests/pass/unsized-tuple-impls.rs create mode 100644 tests/pass/unsized.rs diff --git a/tests/fail/unsized-local.rs b/tests/fail/unsized-local.rs new file mode 100644 index 000000000000..8dd07c585c62 --- /dev/null +++ b/tests/fail/unsized-local.rs @@ -0,0 +1,23 @@ +#![feature(unsized_locals)] +#![allow(incomplete_features)] + +fn main() { + pub trait Foo { + fn foo(self) -> String; + } + + struct A; + + impl Foo for A { + fn foo(self) -> String { + format!("hello") + } + } + + let x = *(Box::new(A) as Box); //~ERROR unsized locals are not supported + assert_eq!(x.foo(), format!("hello")); + + // I'm not sure whether we want this to work + let x = Box::new(A) as Box; + assert_eq!(x.foo(), format!("hello")); +} diff --git a/tests/fail/unsized-local.stderr b/tests/fail/unsized-local.stderr new file mode 100644 index 000000000000..8277bc4546cb --- /dev/null +++ b/tests/fail/unsized-local.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: unsized locals are not supported + --> $DIR/unsized-local.rs:LL:CC + | +LL | let x = *(Box::new(A) as Box); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsized locals are not supported + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = note: backtrace: + = note: inside `main` at $DIR/unsized-local.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/pass/dyn-traits.rs b/tests/pass/dyn-traits.rs index 00667757b048..908d521a0d81 100644 --- a/tests/pass/dyn-traits.rs +++ b/tests/pass/dyn-traits.rs @@ -1,6 +1,3 @@ -#![feature(unsized_locals, unsized_fn_params)] -#![allow(incomplete_features)] - fn ref_box_dyn() { struct Struct(i32); @@ -75,6 +72,9 @@ fn box_box_trait() { assert!(unsafe { DROPPED }); } +// Disabled for now: unsized locals are not supported, +// their current MIR encoding is just not great. +/* fn unsized_dyn() { pub trait Foo { fn foo(self) -> String; @@ -95,7 +95,6 @@ fn unsized_dyn() { let x = Box::new(A) as Box; assert_eq!(x.foo(), format!("hello")); } - fn unsized_dyn_autoderef() { pub trait Foo { fn foo(self) -> String; @@ -140,12 +139,9 @@ fn unsized_dyn_autoderef() { let x = Box::new(|| "hello".to_owned()) as Box String>; assert_eq!(&x.foo() as &str, "hello"); } +*/ fn main() { ref_box_dyn(); box_box_trait(); - - // "exotic" receivers - unsized_dyn(); - unsized_dyn_autoderef(); } diff --git a/tests/pass/unsized-tuple-impls.rs b/tests/pass/unsized-tuple-impls.rs deleted file mode 100644 index bbab1125a0af..000000000000 --- a/tests/pass/unsized-tuple-impls.rs +++ /dev/null @@ -1,13 +0,0 @@ -#![feature(unsized_tuple_coercion)] -use std::mem; - -fn main() { - let x: &(i32, i32, [i32]) = &(0, 1, [2, 3]); - let y: &(i32, i32, [i32]) = &(0, 1, [2, 3, 4]); - let mut a = [y, x]; - a.sort(); - assert_eq!(a, [x, y]); - - assert_eq!(&format!("{:?}", a), "[(0, 1, [2, 3]), (0, 1, [2, 3, 4])]"); - assert_eq!(mem::size_of_val(x), 16); -} diff --git a/tests/pass/unsized.rs b/tests/pass/unsized.rs new file mode 100644 index 000000000000..c7e0c7925753 --- /dev/null +++ b/tests/pass/unsized.rs @@ -0,0 +1,36 @@ +#![feature(unsized_tuple_coercion)] +#![feature(unsized_fn_params)] + +use std::mem; + +fn unsized_tuple() { + let x: &(i32, i32, [i32]) = &(0, 1, [2, 3]); + let y: &(i32, i32, [i32]) = &(0, 1, [2, 3, 4]); + let mut a = [y, x]; + a.sort(); + assert_eq!(a, [x, y]); + + assert_eq!(&format!("{:?}", a), "[(0, 1, [2, 3]), (0, 1, [2, 3, 4])]"); + assert_eq!(mem::size_of_val(x), 16); +} + +fn unsized_params() { + pub fn f0(_f: dyn FnOnce()) {} + pub fn f1(_s: str) {} + pub fn f2(_x: i32, _y: [i32]) {} + pub fn f3(_p: dyn Send) {} + + let c: Box = Box::new(|| {}); + f0(*c); + let foo = "foo".to_string().into_boxed_str(); + f1(*foo); + let sl: Box::<[i32]> = [0, 1, 2].to_vec().into_boxed_slice(); + f2(5, *sl); + let p: Box = Box::new((1, 2)); + f3(*p); +} + +fn main() { + unsized_tuple(); + unsized_params(); +} From e9176c747e626383e37832514130d078b611f995 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Jul 2022 20:28:39 -0400 Subject: [PATCH 3462/5092] test for better error location on stack pop --- tests/fail/data_race/stack_pop_race.rs | 22 ++++++++++++++++++++++ tests/fail/data_race/stack_pop_race.stderr | 20 ++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 tests/fail/data_race/stack_pop_race.rs create mode 100644 tests/fail/data_race/stack_pop_race.stderr diff --git a/tests/fail/data_race/stack_pop_race.rs b/tests/fail/data_race/stack_pop_race.rs new file mode 100644 index 000000000000..fa81306b78ca --- /dev/null +++ b/tests/fail/data_race/stack_pop_race.rs @@ -0,0 +1,22 @@ +// compile-flags: -Zmiri-preemption-rate=0 +use std::thread; + +#[derive(Copy, Clone)] +struct MakeSend(*const i32); +unsafe impl Send for MakeSend {} + +fn main() { race(0); } + +// Using an argument for the ptr to point to, since those do not get StorageDead. +fn race(local: i32) { + let ptr = MakeSend(&local as *const i32); + thread::spawn(move || { + let ptr = ptr; + let _val = unsafe { *ptr.0 }; + }); + // Make the other thread go first so that it does not UAF. + thread::yield_now(); + // Deallocating the local (when `main` returns) + // races with the read in the other thread. + // Make sure the error points at this function's end, not just the call site. +} //~ERROR Data race detected between Deallocate on thread `main` and Read on thread `` diff --git a/tests/fail/data_race/stack_pop_race.stderr b/tests/fail/data_race/stack_pop_race.stderr new file mode 100644 index 000000000000..e7e2ba7e8bd9 --- /dev/null +++ b/tests/fail/data_race/stack_pop_race.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: Data race detected between Deallocate on thread `main` and Read on thread `` at ALLOC + --> $DIR/stack_pop_race.rs:LL:CC + | +LL | } + | ^ Data race detected between Deallocate on thread `main` and Read on thread `` at ALLOC + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: backtrace: + = note: inside `race` at $DIR/stack_pop_race.rs:LL:CC +note: inside `main` at $DIR/stack_pop_race.rs:LL:CC + --> $DIR/stack_pop_race.rs:LL:CC + | +LL | fn main() { race(0); } + | ^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + From 5fed3ebc26ae0a9b17c0099fa71df636644f7312 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Jul 2022 21:17:35 -0400 Subject: [PATCH 3463/5092] adjust code for copy_op changes --- src/machine.rs | 2 +- src/shims/intrinsics.rs | 4 ++-- tests/pass/transmute_fat.rs | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index a2d9e9ced1a1..12df9e271fb9 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -169,7 +169,7 @@ impl Provenance for Tag { write!(f, "{:?}", sb)?; } Tag::Wildcard => { - write!(f, "[Wildcard]")?; + write!(f, "[wildcard]")?; } } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 9cf9461715f1..ab79438c734d 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -68,12 +68,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "volatile_load" => { let [place] = check_arg_count(args)?; let place = this.deref_operand(place)?; - this.copy_op(&place.into(), dest)?; + this.copy_op(&place.into(), dest, /*allow_transmute*/ false)?; } "volatile_store" => { let [place, dest] = check_arg_count(args)?; let place = this.deref_operand(place)?; - this.copy_op(dest, &place.into())?; + this.copy_op(dest, &place.into(), /*allow_transmute*/ false)?; } "write_bytes" | "volatile_set_memory" => { diff --git a/tests/pass/transmute_fat.rs b/tests/pass/transmute_fat.rs index 1d2ec92a8038..b752e5504d4c 100644 --- a/tests/pass/transmute_fat.rs +++ b/tests/pass/transmute_fat.rs @@ -3,6 +3,7 @@ fn main() { // If we are careful, we can exploit data layout... + // This is a tricky case since we are transmuting a ScalarPair type to a non-ScalarPair type. let raw = unsafe { std::mem::transmute::<&[u8], [*const u8; 2]>(&[42]) }; let ptr: *const u8 = unsafe { std::mem::transmute_copy(&raw) }; assert_eq!(unsafe { *ptr }, 42); From b6602f5d11fb9da3de05eefc856d7ec102c23139 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Jul 2022 21:45:47 -0400 Subject: [PATCH 3464/5092] rustup --- rust-version | 2 +- src/operator.rs | 2 ++ tests/fail/data_race/stack_pop_race.rs | 5 ++++- tests/fail/data_race/stack_pop_race.stderr | 4 ++-- tests/pass/unsized.rs | 2 +- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 8f3b1d39fd04..37d1eb0fbdec 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7665c3543079ebc3710b676d0fd6951bedfd4b29 +8824d131619e58a38bde8bcf56401629b91a204a diff --git a/src/operator.rs b/src/operator.rs index e7a43ac95520..2c77830a6d14 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -35,11 +35,13 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { Immediate::Scalar(l) => (l.check_init()?.to_bits(size)?, 0), Immediate::ScalarPair(l1, l2) => (l1.check_init()?.to_bits(size)?, l2.check_init()?.to_bits(size)?), + Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)), }; let right = match **right { Immediate::Scalar(r) => (r.check_init()?.to_bits(size)?, 0), Immediate::ScalarPair(r1, r2) => (r1.check_init()?.to_bits(size)?, r2.check_init()?.to_bits(size)?), + Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)), }; let res = match bin_op { Eq => left == right, diff --git a/tests/fail/data_race/stack_pop_race.rs b/tests/fail/data_race/stack_pop_race.rs index fa81306b78ca..bae885600142 100644 --- a/tests/fail/data_race/stack_pop_race.rs +++ b/tests/fail/data_race/stack_pop_race.rs @@ -1,3 +1,4 @@ +// ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-preemption-rate=0 use std::thread; @@ -5,7 +6,9 @@ use std::thread; struct MakeSend(*const i32); unsafe impl Send for MakeSend {} -fn main() { race(0); } +fn main() { + race(0); +} // Using an argument for the ptr to point to, since those do not get StorageDead. fn race(local: i32) { diff --git a/tests/fail/data_race/stack_pop_race.stderr b/tests/fail/data_race/stack_pop_race.stderr index e7e2ba7e8bd9..ba830753f6ee 100644 --- a/tests/fail/data_race/stack_pop_race.stderr +++ b/tests/fail/data_race/stack_pop_race.stderr @@ -11,8 +11,8 @@ LL | } note: inside `main` at $DIR/stack_pop_race.rs:LL:CC --> $DIR/stack_pop_race.rs:LL:CC | -LL | fn main() { race(0); } - | ^^^^^^^ +LL | race(0); + | ^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/pass/unsized.rs b/tests/pass/unsized.rs index c7e0c7925753..d9beac4327d7 100644 --- a/tests/pass/unsized.rs +++ b/tests/pass/unsized.rs @@ -24,7 +24,7 @@ fn unsized_params() { f0(*c); let foo = "foo".to_string().into_boxed_str(); f1(*foo); - let sl: Box::<[i32]> = [0, 1, 2].to_vec().into_boxed_slice(); + let sl: Box<[i32]> = [0, 1, 2].to_vec().into_boxed_slice(); f2(5, *sl); let p: Box = Box::new((1, 2)); f3(*p); From 6b3986f44d2e7fa388e80bb03abd6d26b1e573a4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Jul 2022 07:42:31 -0400 Subject: [PATCH 3465/5092] remove a dead optimization --- src/stacked_borrows.rs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 9969fbdbcd34..4e83c2c8aa96 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -559,16 +559,9 @@ impl<'tcx> Stack { self.len() }; - // Put the new item there. As an optimization, deduplicate if it is equal to one of its new neighbors. - // `new_idx` might be 0 if we just cleared the entire stack. - if self.get(new_idx) == Some(new) || (new_idx > 0 && self.get(new_idx - 1).unwrap() == new) - { - // Optimization applies, done. - trace!("reborrow: avoiding adding redundant item {:?}", new); - } else { - trace!("reborrow: adding item {:?}", new); - self.insert(new_idx, new); - } + // Put the new item there. + trace!("reborrow: adding item {:?}", new); + self.insert(new_idx, new); Ok(()) } } From 52abae6826277f350723823968ce468d061c3a1d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Jul 2022 08:20:24 -0400 Subject: [PATCH 3466/5092] fix comment in ./miri --- miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri b/miri index 2debf70c1664..f0d92b6a2b53 100755 --- a/miri +++ b/miri @@ -30,7 +30,7 @@ times and slower execution times. Format all sources and tests. are passed to `rustfmt`. ./miri clippy : -Format all sources and tests. are passed to `cargo clippy`. +Runs clippy on all sources. are passed to `cargo clippy`. ./miri many-seeds : Runs over and over again with different seeds for Miri. The MIRIFLAGS From 23d1f1a5a3cccd4a0867833b4f0dc6e3ad5ad532 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Jul 2022 20:12:30 -0400 Subject: [PATCH 3467/5092] rustup --- rust-version | 2 +- src/diagnostics.rs | 4 ++-- tests/fail/uninit_buffer.rs | 2 +- tests/fail/uninit_buffer.stderr | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rust-version b/rust-version index 37d1eb0fbdec..53e7908f42c8 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8824d131619e58a38bde8bcf56401629b91a204a +1517f5de01c445b5124b30f02257b02b4c5ef3b2 diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 289c46a5d2ef..4dfa7bd07cbe 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -291,8 +291,8 @@ pub fn report_error<'tcx, 'mir>( match e.kind() { UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) => { eprintln!( - "Uninitialized read occurred at {alloc_id:?}{range:?}, in this allocation:", - range = alloc_range(access.uninit_offset, access.uninit_size), + "Uninitialized memory occurred at {alloc_id:?}{range:?}, in this allocation:", + range = access.uninit, ); eprintln!("{:?}", ecx.dump_alloc(*alloc_id)); } diff --git a/tests/fail/uninit_buffer.rs b/tests/fail/uninit_buffer.rs index 351181016e4b..c8ebd835d36a 100644 --- a/tests/fail/uninit_buffer.rs +++ b/tests/fail/uninit_buffer.rs @@ -1,4 +1,4 @@ -// error-pattern: 12 bytes are uninitialized +// error-pattern: memory is uninitialized at [0x4..0x10] use std::alloc::{alloc, dealloc, Layout}; use std::slice::from_raw_parts; diff --git a/tests/fail/uninit_buffer.stderr b/tests/fail/uninit_buffer.stderr index e8faf8dd8b97..879c827eb884 100644 --- a/tests/fail/uninit_buffer.stderr +++ b/tests/fail/uninit_buffer.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: reading 16 bytes of memory starting at ALLOC, but 12 bytes are uninitialized starting at ALLOC+0x4, and this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x0..0x10], but memory is uninitialized at [0x4..0x10], and this operation requires initialized memory --> RUSTLIB/core/src/slice/cmp.rs:LL:CC | LL | let mut order = unsafe { memcmp(left.as_ptr(), right.as_ptr(), len) as isize }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading 16 bytes of memory starting at ALLOC, but 12 bytes are uninitialized starting at ALLOC+0x4, and this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC[0x0..0x10], but memory is uninitialized at [0x4..0x10], and this operation requires initialized memory | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information @@ -17,7 +17,7 @@ LL | drop(slice1.cmp(slice2)); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -Uninitialized read occurred at ALLOC[0x4..0x10], in this allocation: +Uninitialized memory occurred at ALLOC[0x4..0x10], in this allocation: ALLOC (Rust heap, size: 32, align: 8) { 0x00 │ 41 42 43 44 __ __ __ __ __ __ __ __ __ __ __ __ │ ABCD░░░░░░░░░░░░ 0x10 │ 00 __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ .░░░░░░░░░░░░░░░ From 4bd4838c15f75c693840d33b9c48ad7d6a310791 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 5 Jul 2022 09:08:00 +0000 Subject: [PATCH 3468/5092] Implement strict comment parsing for ui tests --- miri | 2 +- ui_test/src/comments.rs | 244 +++++++++++++++++++++++++++++----- ui_test/src/comments/tests.rs | 25 ++++ 3 files changed, 237 insertions(+), 34 deletions(-) diff --git a/miri b/miri index f0d92b6a2b53..be51535d59bf 100755 --- a/miri +++ b/miri @@ -181,8 +181,8 @@ test|test-debug|bless|bless-debug) esac # Then test, and let caller control flags. # Only in root project and ui_test as `cargo-miri` has no tests. - $CARGO test $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" $CARGO test $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml "$@" + $CARGO test $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" ;; run|run-debug) # Scan for "--target" to overwrite the "MIRI_TEST_TARGET" env var so diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 3fd65d643a1c..d4ee3efd1404 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -64,6 +64,43 @@ impl Condition { } } +macro_rules! checked { + ($path:expr, $l:expr) => { + let path = $path; + let l = $l; + #[allow(unused_macros)] + macro_rules! exit { + ($fmt:expr $$(,$args:expr)*) => {{ + eprint!("{}:{l}: ", path.display()); + eprintln!($fmt, $$($args,)*); + #[cfg(not(test))] + std::process::exit(1); + #[cfg(test)] + panic!(); + }}; + } + #[allow(unused_macros)] + macro_rules! check { + ($cond:expr, $fmt:expr $$(,$args:expr)*) => {{ + if !$cond { + exit!($fmt $$(,$args)*); + } + }}; + } + #[allow(unused_macros)] + macro_rules! unwrap { + ($cond:expr, $fmt:expr $$(,$args:expr)*) => {{ + match $cond { + Some(val) => val, + None => { + exit!($fmt $$(,$args)*); + } + } + }}; + } + }; +} + impl Comments { pub(crate) fn parse_file(path: &Path) -> Self { let content = std::fs::read_to_string(path).unwrap(); @@ -72,14 +109,45 @@ impl Comments { /// Parse comments in `content`. /// `path` is only used to emit diagnostics if parsing fails. - pub(crate) fn parse(path: &Path, content: &str) -> Self { + /// + /// This function will only parse `//@` and `//~` style comments + /// and ignore all others + fn parse_checked(path: &Path, content: &str) -> Self { let mut this = Self::default(); - let error_pattern_regex = - Regex::new(r"//(\[(?P[^\]]+)\])?~(?P\||[\^]+)? *(?PERROR|HELP|WARN|NOTE)?:?(?P.*)") - .unwrap(); // The line that a `|` will refer to let mut fallthrough_to = None; + for (l, line) in content.lines().enumerate() { + let l = l + 1; // enumerate starts at 0, but line numbers start at 1 + if let Some((_, command)) = line.split_once("//@") { + let command = command.trim(); + if let Some((command, args)) = command.split_once(':') { + this.parse_command_with_args(command, args, path, l); + } else if let Some((command, _comments)) = command.split_once(' ') { + this.parse_command(command, path, l) + } else { + this.parse_command(command, path, l) + } + } else if let Some((_, pattern)) = line.split_once("//~") { + this.parse_pattern(pattern, &mut fallthrough_to, path, l) + } else if let Some((_, pattern)) = line.split_once("//[") { + this.parse_revisioned_pattern(pattern, &mut fallthrough_to, path, l) + } else { + fallthrough_to = None; + } + } + this + } + + /// Parse comments in `content`. + /// `path` is only used to emit diagnostics if parsing fails. + pub(crate) fn parse(path: &Path, content: &str) -> Self { + let mut this = Self::parse_checked(path, content); + if content.contains("//@") { + // Migration mode: if new syntax is used, ignore all old syntax + return this; + } + for (l, line) in content.lines().enumerate() { let l = l + 1; // enumerate starts at 0, but line numbers start at 1 if let Some(revisions) = line.strip_prefix("// revisions:") { @@ -140,36 +208,146 @@ impl Comments { ); this.error_pattern = Some((s.trim().to_string(), l)); } - if let Some(captures) = error_pattern_regex.captures(line) { - // FIXME: check that the error happens on the marked line - let matched = captures["text"].trim().to_string(); - - let revision = captures.name("revision").map(|rev| rev.as_str().to_string()); - - let level = captures.name("level").map(|rev| rev.as_str().parse().unwrap()); - - let match_line = match captures.name("offset").map(|rev| rev.as_str()) { - Some("|") => fallthrough_to.expect("`//~|` pattern without preceding line"), - Some(pat) => { - debug_assert!(pat.chars().all(|c| c == '^')); - l - pat.len() - } - None => l, - }; - - fallthrough_to = Some(match_line); - - this.error_matches.push(ErrorMatch { - matched, - revision, - level, - definition_line: l, - line: match_line, - }); - } else { - fallthrough_to = None; - } } this } + + fn parse_command_with_args(&mut self, command: &str, args: &str, path: &Path, l: usize) { + checked!(path, l); + match command { + "revisions" => { + check!(self.revisions.is_none(), "cannot specifiy revisions twice"); + self.revisions = Some(args.split_whitespace().map(|s| s.to_string()).collect()); + } + "compile-flags" => { + self.compile_flags.extend(args.split_whitespace().map(|s| s.to_string())); + } + "rustc-env" => + for env in args.split_whitespace() { + let (k, v) = unwrap!( + env.split_once('='), + "environment variables must be key/value pairs separated by a `=`" + ); + self.env_vars.push((k.to_string(), v.to_string())); + }, + "normalize-stderr-test" => { + let (from, to) = + unwrap!(args.split_once("->"), "normalize-stderr-test needs a `->`"); + let from = from.trim().trim_matches('"'); + let to = to.trim().trim_matches('"'); + let from = unwrap!(Regex::new(from).ok(), "invalid regex"); + self.normalize_stderr.push((from, to.to_string())); + } + "error-pattern" => { + check!( + self.error_pattern.is_none(), + "cannot specifiy error_pattern twice, previous: {:?}", + self.error_pattern + ); + self.error_pattern = Some((args.trim().to_string(), l)); + } + _ => exit!("unknown command {command} with args {args}"), + } + } + + fn parse_command(&mut self, command: &str, path: &Path, l: usize) { + checked!(path, l); + + if let Some(s) = command.strip_prefix("ignore-") { + self.ignore.push(Condition::parse(s)); + return; + } + + if let Some(s) = command.strip_prefix("only-") { + self.only.push(Condition::parse(s)); + return; + } + + if command.starts_with("stderr-per-bitwidth") { + check!(!self.stderr_per_bitwidth, "cannot specifiy stderr-per-bitwidth twice"); + self.stderr_per_bitwidth = true; + return; + } + + exit!("unknown command {command}"); + } + + fn parse_pattern( + &mut self, + pattern: &str, + fallthrough_to: &mut Option, + path: &Path, + l: usize, + ) { + self.parse_pattern_inner(pattern, fallthrough_to, None, path, l) + } + + fn parse_revisioned_pattern( + &mut self, + pattern: &str, + fallthrough_to: &mut Option, + path: &Path, + l: usize, + ) { + checked!(path, l); + let (revision, pattern) = + unwrap!(pattern.split_once(']'), "`//[` without corresponding `]`"); + if pattern.starts_with('~') { + self.parse_pattern_inner( + &pattern[1..], + fallthrough_to, + Some(revision.to_owned()), + path, + l, + ) + } else { + exit!("revisioned pattern must have `~` following the `]`"); + } + } + + // parse something like (?P\||[\^]+)? *(?PERROR|HELP|WARN|NOTE)?:?(?P.*) + fn parse_pattern_inner( + &mut self, + pattern: &str, + fallthrough_to: &mut Option, + revision: Option, + path: &Path, + l: usize, + ) { + checked!(path, l); + // FIXME: check that the error happens on the marked line + + let (match_line, pattern) = match unwrap!(pattern.chars().next(), "no pattern specified") { + '|' => + (*unwrap!(fallthrough_to, "`//~|` pattern without preceding line"), &pattern[1..]), + '^' => { + let offset = pattern.chars().take_while(|&c| c == '^').count(); + (l - offset, &pattern[offset..]) + } + _ => (l, pattern), + }; + + let (level, pattern) = match pattern.trim_start().split_once(|c| matches!(c, ':' | ' ')) { + None => (None, pattern), + Some((level, pattern_without_level)) => + match level.parse().ok() { + Some(level) => (Some(level), pattern_without_level), + None => (None, pattern), + }, + }; + + let matched = pattern.trim().to_string(); + + check!(!matched.is_empty(), "no pattern specified"); + + *fallthrough_to = Some(match_line); + + self.error_matches.push(ErrorMatch { + matched, + revision, + level, + definition_line: l, + line: match_line, + }); + } } diff --git a/ui_test/src/comments/tests.rs b/ui_test/src/comments/tests.rs index ef9662241424..dc69a5d4d600 100644 --- a/ui_test/src/comments/tests.rs +++ b/ui_test/src/comments/tests.rs @@ -20,3 +20,28 @@ fn main() { "encountered a dangling reference (address $HEX is unallocated)" ); } + +#[test] +fn parse_slash_slash_at() { + let s = r" +//@ error-pattern: foomp +use std::mem; + + "; + let comments = Comments::parse(Path::new(""), s); + println!("parsed comments: {:#?}", comments); + assert_eq!(comments.error_pattern, Some(("foomp".to_string(), 2))); +} + +#[test] +#[should_panic] +fn parse_slash_slash_at_fail() { + let s = r" +//@ error-pattern foomp +use std::mem; + + "; + let comments = Comments::parse(Path::new(""), s); + println!("parsed comments: {:#?}", comments); + assert_eq!(comments.error_pattern, Some(("foomp".to_string(), 2))); +} From 389915e09b2c5759865e829050cf0574d2cbe587 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 5 Jul 2022 09:15:22 +0000 Subject: [PATCH 3469/5092] Replace all //error-pattern comments with strict syntax and fix other comments in the same files --- tests/fail/alloc/deallocate-bad-alignment.rs | 2 +- tests/fail/alloc/deallocate-bad-size.rs | 2 +- tests/fail/alloc/deallocate-twice.rs | 2 +- tests/fail/alloc/global_system_mixup.rs | 8 ++++---- tests/fail/alloc/reallocate-bad-size.rs | 2 +- tests/fail/alloc/reallocate-dangling.rs | 2 +- tests/fail/alloc/stack_free.rs | 4 ++-- .../libc_pthread_create_main_terminate.rs | 4 ++-- tests/fail/concurrency/thread-spawn.rs | 4 ++-- .../dangling_pointers/null_pointer_write_zst.rs | 4 ++-- tests/fail/fs/isolated_file.rs | 4 ++-- tests/fail/intrinsics/copy_overflow.rs | 2 +- tests/fail/intrinsics/out_of_bounds_ptr_1.rs | 2 +- tests/fail/intrinsics/out_of_bounds_ptr_2.rs | 2 +- tests/fail/intrinsics/out_of_bounds_ptr_3.rs | 2 +- tests/fail/intrinsics/ptr_offset_0_plus_0.rs | 4 ++-- tests/fail/intrinsics/ptr_offset_int_plus_int.rs | 4 ++-- tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs | 4 ++-- tests/fail/intrinsics/ptr_offset_overflow.rs | 2 +- tests/fail/intrinsics/ptr_offset_ptr_plus_0.rs | 2 +- tests/fail/intrinsics/simd-float-to-int.rs | 2 +- tests/fail/intrinsics/simd-gather.rs | 2 +- tests/fail/intrinsics/simd-scatter.rs | 2 +- tests/fail/intrinsics/write_bytes_overflow.rs | 2 +- tests/fail/invalid_enum_tag.rs | 4 ++-- tests/fail/memleak.rs | 4 ++-- tests/fail/memleak_rc.rs | 6 +++--- tests/fail/memleak_rc.stderr | 11 +++++++++++ tests/fail/no_main.rs | 2 +- tests/fail/panic/double_panic.rs | 6 +++--- tests/fail/panic/panic_abort1.rs | 8 ++++---- tests/fail/panic/panic_abort2.rs | 8 ++++---- tests/fail/panic/panic_abort3.rs | 8 ++++---- tests/fail/panic/panic_abort4.rs | 8 ++++---- tests/fail/provenance/ptr_invalid_offset.rs | 4 ++-- tests/fail/should-pass/cpp20_rwc_syncs.rs | 6 +++--- .../stacked_borrows/deallocate_against_barrier1.rs | 2 +- .../stacked_borrows/deallocate_against_barrier2.rs | 2 +- tests/fail/stacked_borrows/issue-miri-1050-1.rs | 2 +- tests/fail/stacked_borrows/issue-miri-1050-2.rs | 2 +- tests/fail/stacked_borrows/newtype_retagging.rs | 4 ++-- tests/fail/stacked_borrows/vtable.rs | 2 +- tests/fail/stacked_borrows/zst_slice.rs | 2 +- tests/fail/uninit_buffer.rs | 2 +- tests/fail/unreachable.rs | 2 +- ui_test/README.md | 4 +--- ui_test/src/comments.rs | 13 ++++--------- ui_test/src/lib.rs | 2 +- 48 files changed, 94 insertions(+), 90 deletions(-) create mode 100644 tests/fail/memleak_rc.stderr diff --git a/tests/fail/alloc/deallocate-bad-alignment.rs b/tests/fail/alloc/deallocate-bad-alignment.rs index 852a0660217e..a07d8254ad3d 100644 --- a/tests/fail/alloc/deallocate-bad-alignment.rs +++ b/tests/fail/alloc/deallocate-bad-alignment.rs @@ -1,6 +1,6 @@ use std::alloc::{alloc, dealloc, Layout}; -// error-pattern: has size 1 and alignment 1, but gave size 1 and alignment 2 +//@error-pattern: has size 1 and alignment 1, but gave size 1 and alignment 2 fn main() { unsafe { diff --git a/tests/fail/alloc/deallocate-bad-size.rs b/tests/fail/alloc/deallocate-bad-size.rs index 167cc015c2da..47aaef1935e9 100644 --- a/tests/fail/alloc/deallocate-bad-size.rs +++ b/tests/fail/alloc/deallocate-bad-size.rs @@ -1,6 +1,6 @@ use std::alloc::{alloc, dealloc, Layout}; -// error-pattern: has size 1 and alignment 1, but gave size 2 and alignment 1 +//@error-pattern: has size 1 and alignment 1, but gave size 2 and alignment 1 fn main() { unsafe { diff --git a/tests/fail/alloc/deallocate-twice.rs b/tests/fail/alloc/deallocate-twice.rs index 67312b0d96dd..1eb9bbf91ca5 100644 --- a/tests/fail/alloc/deallocate-twice.rs +++ b/tests/fail/alloc/deallocate-twice.rs @@ -1,6 +1,6 @@ use std::alloc::{alloc, dealloc, Layout}; -// error-pattern: dereferenced after this allocation got freed +//@error-pattern: dereferenced after this allocation got freed fn main() { unsafe { diff --git a/tests/fail/alloc/global_system_mixup.rs b/tests/fail/alloc/global_system_mixup.rs index 735c52500af6..01db2f1a225d 100644 --- a/tests/fail/alloc/global_system_mixup.rs +++ b/tests/fail/alloc/global_system_mixup.rs @@ -1,10 +1,10 @@ // Make sure we detect when the `Global` and `System` allocators are mixed // (even when the default `Global` uses `System`). -// error-pattern: which is Rust heap memory, using +//@error-pattern: which is Rust heap memory, using -// normalize-stderr-test: "using [A-Za-z]+ heap deallocation operation" -> "using PLATFORM heap deallocation operation" -// normalize-stderr-test: "\| +\^+" -> "| ^" -// normalize-stderr-test: "libc::free\([^()]*\)|unsafe \{ HeapFree\([^()]*\) \};" -> "FREE();" +//@normalize-stderr-test: "using [A-Za-z]+ heap deallocation operation" -> "using PLATFORM heap deallocation operation" +//@normalize-stderr-test: "\| +\^+" -> "| ^" +//@normalize-stderr-test: "libc::free\([^()]*\)|unsafe \{ HeapFree\([^()]*\) \};" -> "FREE();" #![feature(allocator_api, slice_ptr_get)] diff --git a/tests/fail/alloc/reallocate-bad-size.rs b/tests/fail/alloc/reallocate-bad-size.rs index d6a27c930a28..145c3393d677 100644 --- a/tests/fail/alloc/reallocate-bad-size.rs +++ b/tests/fail/alloc/reallocate-bad-size.rs @@ -1,6 +1,6 @@ use std::alloc::{alloc, realloc, Layout}; -// error-pattern: has size 1 and alignment 1, but gave size 2 and alignment 1 +//@error-pattern: has size 1 and alignment 1, but gave size 2 and alignment 1 fn main() { unsafe { diff --git a/tests/fail/alloc/reallocate-dangling.rs b/tests/fail/alloc/reallocate-dangling.rs index 62eb7582a2f7..34f1658344a5 100644 --- a/tests/fail/alloc/reallocate-dangling.rs +++ b/tests/fail/alloc/reallocate-dangling.rs @@ -1,6 +1,6 @@ use std::alloc::{alloc, dealloc, realloc, Layout}; -// error-pattern: dereferenced after this allocation got freed +//@error-pattern: dereferenced after this allocation got freed fn main() { unsafe { diff --git a/tests/fail/alloc/stack_free.rs b/tests/fail/alloc/stack_free.rs index d854fa993a79..a97431bc2f05 100644 --- a/tests/fail/alloc/stack_free.rs +++ b/tests/fail/alloc/stack_free.rs @@ -1,7 +1,7 @@ // Validation/SB changes why we fail -// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -// error-pattern: which is stack variable memory, using Rust heap deallocation operation +//@error-pattern: which is stack variable memory, using Rust heap deallocation operation fn main() { let x = 42; diff --git a/tests/fail/concurrency/libc_pthread_create_main_terminate.rs b/tests/fail/concurrency/libc_pthread_create_main_terminate.rs index 9b576bbb0868..ab80cdd205bc 100644 --- a/tests/fail/concurrency/libc_pthread_create_main_terminate.rs +++ b/tests/fail/concurrency/libc_pthread_create_main_terminate.rs @@ -1,5 +1,5 @@ -// ignore-windows: No libc on Windows -// error-pattern: the main thread terminated without waiting for all remaining threads +//@ignore-windows: No libc on Windows +//@error-pattern: the main thread terminated without waiting for all remaining threads // Check that we terminate the program when the main thread terminates. diff --git a/tests/fail/concurrency/thread-spawn.rs b/tests/fail/concurrency/thread-spawn.rs index 948ce946d894..650a42b43b5d 100644 --- a/tests/fail/concurrency/thread-spawn.rs +++ b/tests/fail/concurrency/thread-spawn.rs @@ -1,8 +1,8 @@ -// only-windows: Only Windows is not supported. +//@only-windows: Only Windows is not supported. use std::thread; -// error-pattern: can't create threads on Windows +//@error-pattern: can't create threads on Windows fn main() { thread::spawn(|| {}); diff --git a/tests/fail/dangling_pointers/null_pointer_write_zst.rs b/tests/fail/dangling_pointers/null_pointer_write_zst.rs index 60e2d7c663e0..7181a5979b44 100644 --- a/tests/fail/dangling_pointers/null_pointer_write_zst.rs +++ b/tests/fail/dangling_pointers/null_pointer_write_zst.rs @@ -1,6 +1,6 @@ // Some optimizations remove ZST accesses, thus masking this UB. -// compile-flags: -Zmir-opt-level=0 -// error-pattern: memory access failed: null pointer is a dangling pointer +//@compile-flags: -Zmir-opt-level=0 +//@error-pattern: memory access failed: null pointer is a dangling pointer #[allow(deref_nullptr)] fn main() { diff --git a/tests/fail/fs/isolated_file.rs b/tests/fail/fs/isolated_file.rs index 5b7270f18931..00bb492147a8 100644 --- a/tests/fail/fs/isolated_file.rs +++ b/tests/fail/fs/isolated_file.rs @@ -1,5 +1,5 @@ -// ignore-windows: File handling is not implemented yet -// error-pattern: `open` not available when isolation is enabled +//@ignore-windows: File handling is not implemented yet +//@error-pattern: `open` not available when isolation is enabled fn main() { let _file = std::fs::File::open("file.txt").unwrap(); diff --git a/tests/fail/intrinsics/copy_overflow.rs b/tests/fail/intrinsics/copy_overflow.rs index b09aedcf7470..c4ce192c449c 100644 --- a/tests/fail/intrinsics/copy_overflow.rs +++ b/tests/fail/intrinsics/copy_overflow.rs @@ -1,4 +1,4 @@ -// error-pattern: overflow computing total size +//@error-pattern: overflow computing total size use std::mem; fn main() { diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_1.rs b/tests/fail/intrinsics/out_of_bounds_ptr_1.rs index d200b3eb0297..0109bff69688 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_1.rs +++ b/tests/fail/intrinsics/out_of_bounds_ptr_1.rs @@ -1,4 +1,4 @@ -// error-pattern: pointer to 5 bytes starting at offset 0 is out-of-bounds +//@error-pattern: pointer to 5 bytes starting at offset 0 is out-of-bounds fn main() { let v = [0i8; 4]; let x = &v as *const i8; diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_2.rs b/tests/fail/intrinsics/out_of_bounds_ptr_2.rs index 52b385b8e3b4..74d391dc2120 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_2.rs +++ b/tests/fail/intrinsics/out_of_bounds_ptr_2.rs @@ -1,4 +1,4 @@ -// error-pattern: overflowing in-bounds pointer arithmetic +//@error-pattern: overflowing in-bounds pointer arithmetic fn main() { let v = [0i8; 4]; let x = &v as *const i8; diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_3.rs b/tests/fail/intrinsics/out_of_bounds_ptr_3.rs index cd0861efe5d9..b54cf3dd25c0 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_3.rs +++ b/tests/fail/intrinsics/out_of_bounds_ptr_3.rs @@ -1,4 +1,4 @@ -// error-pattern: pointer to 1 byte starting at offset -1 is out-of-bounds +//@error-pattern: pointer to 1 byte starting at offset -1 is out-of-bounds fn main() { let v = [0i8; 4]; let x = &v as *const i8; diff --git a/tests/fail/intrinsics/ptr_offset_0_plus_0.rs b/tests/fail/intrinsics/ptr_offset_0_plus_0.rs index 4098d6b0ced2..32974a825a54 100644 --- a/tests/fail/intrinsics/ptr_offset_0_plus_0.rs +++ b/tests/fail/intrinsics/ptr_offset_0_plus_0.rs @@ -1,5 +1,5 @@ -// error-pattern: null pointer is a dangling pointer -// compile-flags: -Zmiri-permissive-provenance +//@error-pattern: null pointer is a dangling pointer +//@compile-flags: -Zmiri-permissive-provenance fn main() { let x = 0 as *mut i32; diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_int.rs b/tests/fail/intrinsics/ptr_offset_int_plus_int.rs index 817a8b9801b7..f51e00746e2f 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_int.rs +++ b/tests/fail/intrinsics/ptr_offset_int_plus_int.rs @@ -1,5 +1,5 @@ -// error-pattern: is a dangling pointer -// compile-flags: -Zmiri-permissive-provenance +//@error-pattern: is a dangling pointer +//@compile-flags: -Zmiri-permissive-provenance fn main() { // Can't offset an integer pointer by non-zero offset. diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs index ed6370bf7f17..8fc4d7fe7350 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs +++ b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs @@ -1,5 +1,5 @@ -// error-pattern: is a dangling pointer -// compile-flags: -Zmiri-permissive-provenance +//@error-pattern: is a dangling pointer +//@compile-flags: -Zmiri-permissive-provenance fn main() { let ptr = Box::into_raw(Box::new(0u32)); diff --git a/tests/fail/intrinsics/ptr_offset_overflow.rs b/tests/fail/intrinsics/ptr_offset_overflow.rs index 734547b6013b..829cf90c855d 100644 --- a/tests/fail/intrinsics/ptr_offset_overflow.rs +++ b/tests/fail/intrinsics/ptr_offset_overflow.rs @@ -1,4 +1,4 @@ -// error-pattern: overflowing in-bounds pointer arithmetic +//@error-pattern: overflowing in-bounds pointer arithmetic fn main() { let v = [1i8, 2]; let x = &v[1] as *const i8; diff --git a/tests/fail/intrinsics/ptr_offset_ptr_plus_0.rs b/tests/fail/intrinsics/ptr_offset_ptr_plus_0.rs index 8760345409c8..f8ee7d0b5092 100644 --- a/tests/fail/intrinsics/ptr_offset_ptr_plus_0.rs +++ b/tests/fail/intrinsics/ptr_offset_ptr_plus_0.rs @@ -1,4 +1,4 @@ -// error-pattern: pointer at offset 32 is out-of-bounds +//@error-pattern: pointer at offset 32 is out-of-bounds fn main() { let x = Box::into_raw(Box::new(0u32)); diff --git a/tests/fail/intrinsics/simd-float-to-int.rs b/tests/fail/intrinsics/simd-float-to-int.rs index bb9adf07c9e9..a5bae36d92a4 100644 --- a/tests/fail/intrinsics/simd-float-to-int.rs +++ b/tests/fail/intrinsics/simd-float-to-int.rs @@ -1,4 +1,4 @@ -// error-pattern: cannot be represented in target type `i32` +//@error-pattern: cannot be represented in target type `i32` #![feature(portable_simd)] use std::simd::*; diff --git a/tests/fail/intrinsics/simd-gather.rs b/tests/fail/intrinsics/simd-gather.rs index ab9cb56ed0bd..e394cce9a4fe 100644 --- a/tests/fail/intrinsics/simd-gather.rs +++ b/tests/fail/intrinsics/simd-gather.rs @@ -1,4 +1,4 @@ -// error-pattern: pointer to 1 byte starting at offset 9 is out-of-bounds +//@error-pattern: pointer to 1 byte starting at offset 9 is out-of-bounds #![feature(portable_simd)] use std::simd::*; diff --git a/tests/fail/intrinsics/simd-scatter.rs b/tests/fail/intrinsics/simd-scatter.rs index d7a7e344aa30..d2bc73399548 100644 --- a/tests/fail/intrinsics/simd-scatter.rs +++ b/tests/fail/intrinsics/simd-scatter.rs @@ -1,4 +1,4 @@ -// error-pattern: pointer to 1 byte starting at offset 9 is out-of-bounds +//@error-pattern: pointer to 1 byte starting at offset 9 is out-of-bounds #![feature(portable_simd)] use std::simd::*; diff --git a/tests/fail/intrinsics/write_bytes_overflow.rs b/tests/fail/intrinsics/write_bytes_overflow.rs index a6bf2acb16f3..5c49dc00165c 100644 --- a/tests/fail/intrinsics/write_bytes_overflow.rs +++ b/tests/fail/intrinsics/write_bytes_overflow.rs @@ -1,4 +1,4 @@ -// error-pattern: overflow computing total size of `write_bytes` +//@error-pattern: overflow computing total size of `write_bytes` use std::mem; fn main() { diff --git a/tests/fail/invalid_enum_tag.rs b/tests/fail/invalid_enum_tag.rs index 7ba4da9018a7..92cc1d1d34e4 100644 --- a/tests/fail/invalid_enum_tag.rs +++ b/tests/fail/invalid_enum_tag.rs @@ -1,8 +1,8 @@ // Validation makes this fail in the wrong place // Make sure we find these even with many checks disabled. -// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation -// error-pattern: enum value has invalid tag +//@error-pattern: enum value has invalid tag use std::mem; diff --git a/tests/fail/memleak.rs b/tests/fail/memleak.rs index 7dee9ddf1c98..d384caf81a57 100644 --- a/tests/fail/memleak.rs +++ b/tests/fail/memleak.rs @@ -1,5 +1,5 @@ -// error-pattern: the evaluated program leaked memory -// normalize-stderr-test: ".*│.*" -> "$$stripped$$" +//@error-pattern: the evaluated program leaked memory +//@normalize-stderr-test: ".*│.*" -> "$$stripped$$" fn main() { std::mem::forget(Box::new(42)); diff --git a/tests/fail/memleak_rc.rs b/tests/fail/memleak_rc.rs index 9ea809f76299..76ecd71b011a 100644 --- a/tests/fail/memleak_rc.rs +++ b/tests/fail/memleak_rc.rs @@ -1,6 +1,6 @@ -// error-pattern: the evaluated program leaked memory -// stderr-per-bitwidth -// normalize-stderr-test: ".*│.*" -> "$$stripped$$" +//@error-pattern: the evaluated program leaked memory +//@stderr-per-bitwidth +//@normalize-stderr-test: ".*│.*" -> "$$stripped$$" use std::cell::RefCell; use std::rc::Rc; diff --git a/tests/fail/memleak_rc.stderr b/tests/fail/memleak_rc.stderr new file mode 100644 index 000000000000..290de49c82c0 --- /dev/null +++ b/tests/fail/memleak_rc.stderr @@ -0,0 +1,11 @@ +The following memory was leaked: ALLOC (Rust heap, size: 32, align: 8) { + 0x00 │ 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ ................ + 0x10 │ 00 00 00 00 00 00 00 00 ╾$HEX[a1765]─╼ │ ........╾──────╼ +} + +error: the evaluated program leaked memory + +note: pass `-Zmiri-ignore-leaks` to disable this check + +error: aborting due to previous error + diff --git a/tests/fail/no_main.rs b/tests/fail/no_main.rs index a9e8e816828c..e28205040871 100644 --- a/tests/fail/no_main.rs +++ b/tests/fail/no_main.rs @@ -1,2 +1,2 @@ -// error-pattern: miri can only run programs that have a main function +//@error-pattern: miri can only run programs that have a main function #![no_main] diff --git a/tests/fail/panic/double_panic.rs b/tests/fail/panic/double_panic.rs index f3af66a79abc..8919d51bb2f7 100644 --- a/tests/fail/panic/double_panic.rs +++ b/tests/fail/panic/double_panic.rs @@ -1,6 +1,6 @@ -// error-pattern: the program aborted -// normalize-stderr-test: "\| +\^+" -> "| ^" -// normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" +//@error-pattern: the program aborted +//@normalize-stderr-test: "\| +\^+" -> "| ^" +//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" struct Foo; impl Drop for Foo { diff --git a/tests/fail/panic/panic_abort1.rs b/tests/fail/panic/panic_abort1.rs index 9c094c659837..00a01ce6e813 100644 --- a/tests/fail/panic/panic_abort1.rs +++ b/tests/fail/panic/panic_abort1.rs @@ -1,7 +1,7 @@ -// error-pattern: the program aborted execution -// normalize-stderr-test: "\| +\^+" -> "| ^" -// normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();" -// compile-flags: -C panic=abort +//@error-pattern: the program aborted execution +//@normalize-stderr-test: "\| +\^+" -> "| ^" +//@normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();" +//@compile-flags: -C panic=abort fn main() { std::panic!("panicking from libstd"); diff --git a/tests/fail/panic/panic_abort2.rs b/tests/fail/panic/panic_abort2.rs index 7eb9a3c24aa2..dee0de96703a 100644 --- a/tests/fail/panic/panic_abort2.rs +++ b/tests/fail/panic/panic_abort2.rs @@ -1,7 +1,7 @@ -// error-pattern: the program aborted execution -// normalize-stderr-test: "\| +\^+" -> "| ^" -// normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();" -// compile-flags: -C panic=abort +//@error-pattern: the program aborted execution +//@normalize-stderr-test: "\| +\^+" -> "| ^" +//@normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();" +//@compile-flags: -C panic=abort fn main() { std::panic!("{}-panicking from libstd", 42); diff --git a/tests/fail/panic/panic_abort3.rs b/tests/fail/panic/panic_abort3.rs index 1940b48bad78..a448aab3ea45 100644 --- a/tests/fail/panic/panic_abort3.rs +++ b/tests/fail/panic/panic_abort3.rs @@ -1,7 +1,7 @@ -// error-pattern: the program aborted execution -// normalize-stderr-test: "\| +\^+" -> "| ^" -// normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();" -// compile-flags: -C panic=abort +//@error-pattern: the program aborted execution +//@normalize-stderr-test: "\| +\^+" -> "| ^" +//@normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();" +//@compile-flags: -C panic=abort fn main() { core::panic!("panicking from libcore"); diff --git a/tests/fail/panic/panic_abort4.rs b/tests/fail/panic/panic_abort4.rs index e5190ea0765d..4995dad9d71a 100644 --- a/tests/fail/panic/panic_abort4.rs +++ b/tests/fail/panic/panic_abort4.rs @@ -1,7 +1,7 @@ -// error-pattern: the program aborted execution -// normalize-stderr-test: "\| +\^+" -> "| ^" -// normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();" -// compile-flags: -C panic=abort +//@error-pattern: the program aborted execution +//@normalize-stderr-test: "\| +\^+" -> "| ^" +//@normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();" +//@compile-flags: -C panic=abort fn main() { core::panic!("{}-panicking from libcore", 42); diff --git a/tests/fail/provenance/ptr_invalid_offset.rs b/tests/fail/provenance/ptr_invalid_offset.rs index 08fb57a6569c..a3510d8e8929 100644 --- a/tests/fail/provenance/ptr_invalid_offset.rs +++ b/tests/fail/provenance/ptr_invalid_offset.rs @@ -1,5 +1,5 @@ -// compile-flags: -Zmiri-strict-provenance -// error-pattern: is a dangling pointer +//@compile-flags: -Zmiri-strict-provenance +//@error-pattern: is a dangling pointer #![feature(strict_provenance)] fn main() { diff --git a/tests/fail/should-pass/cpp20_rwc_syncs.rs b/tests/fail/should-pass/cpp20_rwc_syncs.rs index 85c24246dbeb..6478f446accc 100644 --- a/tests/fail/should-pass/cpp20_rwc_syncs.rs +++ b/tests/fail/should-pass/cpp20_rwc_syncs.rs @@ -1,6 +1,6 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-ignore-leaks -// error-pattern: unreachable +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-ignore-leaks +//@error-pattern: unreachable // https://plv.mpi-sws.org/scfix/paper.pdf // 2.2 Second Problem: SC Fences are Too Weak diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier1.rs b/tests/fail/stacked_borrows/deallocate_against_barrier1.rs index bf18c9a058cf..0798f863ce11 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier1.rs +++ b/tests/fail/stacked_borrows/deallocate_against_barrier1.rs @@ -1,4 +1,4 @@ -// error-pattern: deallocating while item is protected +//@error-pattern: deallocating while item is protected fn inner(x: &mut i32, f: fn(&mut i32)) { // `f` may mutate, but it may not deallocate! diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier2.rs b/tests/fail/stacked_borrows/deallocate_against_barrier2.rs index 4680f6769a1c..23c54c8d8988 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier2.rs +++ b/tests/fail/stacked_borrows/deallocate_against_barrier2.rs @@ -1,4 +1,4 @@ -// error-pattern: deallocating while item is protected +//@error-pattern: deallocating while item is protected use std::marker::PhantomPinned; pub struct NotUnpin(i32, PhantomPinned); diff --git a/tests/fail/stacked_borrows/issue-miri-1050-1.rs b/tests/fail/stacked_borrows/issue-miri-1050-1.rs index c1fc695e0d65..6e14b9af146c 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-1.rs +++ b/tests/fail/stacked_borrows/issue-miri-1050-1.rs @@ -1,4 +1,4 @@ -// error-pattern: pointer to 4 bytes starting at offset 0 is out-of-bounds +//@error-pattern: pointer to 4 bytes starting at offset 0 is out-of-bounds fn main() { unsafe { diff --git a/tests/fail/stacked_borrows/issue-miri-1050-2.rs b/tests/fail/stacked_borrows/issue-miri-1050-2.rs index 2a969686d4da..571cb6213fec 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-2.rs +++ b/tests/fail/stacked_borrows/issue-miri-1050-2.rs @@ -1,4 +1,4 @@ -// error-pattern: is a dangling pointer +//@error-pattern: is a dangling pointer use std::ptr::NonNull; fn main() { diff --git a/tests/fail/stacked_borrows/newtype_retagging.rs b/tests/fail/stacked_borrows/newtype_retagging.rs index 8f932f08086a..4786cd02d954 100644 --- a/tests/fail/stacked_borrows/newtype_retagging.rs +++ b/tests/fail/stacked_borrows/newtype_retagging.rs @@ -1,5 +1,5 @@ -// compile-flags: -Zmiri-retag-fields -// error-pattern: incompatible item is protected +//@compile-flags: -Zmiri-retag-fields +//@error-pattern: incompatible item is protected struct Newtype<'a>(&'a mut i32); fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) { diff --git a/tests/fail/stacked_borrows/vtable.rs b/tests/fail/stacked_borrows/vtable.rs index dd9ba1dfb2bd..27e035c404ba 100644 --- a/tests/fail/stacked_borrows/vtable.rs +++ b/tests/fail/stacked_borrows/vtable.rs @@ -1,4 +1,4 @@ -// error-pattern: vtable pointer does not have permission +//@error-pattern: vtable pointer does not have permission #![feature(ptr_metadata)] trait Foo {} diff --git a/tests/fail/stacked_borrows/zst_slice.rs b/tests/fail/stacked_borrows/zst_slice.rs index d45b3dcac087..336b1041df09 100644 --- a/tests/fail/stacked_borrows/zst_slice.rs +++ b/tests/fail/stacked_borrows/zst_slice.rs @@ -1,5 +1,5 @@ // compile-flags: -Zmiri-strict-provenance -// error-pattern: does not exist in the borrow stack +//@error-pattern: does not exist in the borrow stack fn main() { unsafe { diff --git a/tests/fail/uninit_buffer.rs b/tests/fail/uninit_buffer.rs index c8ebd835d36a..d21371225e57 100644 --- a/tests/fail/uninit_buffer.rs +++ b/tests/fail/uninit_buffer.rs @@ -1,4 +1,4 @@ -// error-pattern: memory is uninitialized at [0x4..0x10] +//@error-pattern: memory is uninitialized at [0x4..0x10] use std::alloc::{alloc, dealloc, Layout}; use std::slice::from_raw_parts; diff --git a/tests/fail/unreachable.rs b/tests/fail/unreachable.rs index 245ef29cad35..ef2bb42c65cc 100644 --- a/tests/fail/unreachable.rs +++ b/tests/fail/unreachable.rs @@ -1,4 +1,4 @@ -// error-pattern: entering unreachable code +//@error-pattern: entering unreachable code fn main() { unsafe { std::hint::unreachable_unchecked() } } diff --git a/ui_test/README.md b/ui_test/README.md index 07a0a67b9143..f7852c82e44b 100644 --- a/ui_test/README.md +++ b/ui_test/README.md @@ -7,14 +7,12 @@ A smaller version of compiletest-rs ## Supported magic comment annotations -Note that the space after `//`, when it is present, is *not* optional -- it must be exactly one. - * `// ignore-XXX` avoids running the test on targets whose triple contains `XXX` * `XXX` can also be one of `64bit`, `32bit` or `16bit` * `// only-XXX` avoids running the test on targets whose triple **does not** contain `XXX` * `XXX` can also be one of `64bit`, `32bit` or `16bit` * `// stderr-per-bitwidth` produces one stderr file per bitwidth, as they may differ significantly sometimes -* `// error-pattern: XXX` make sure the stderr output contains `XXX` +* `//@error-pattern: XXX` make sure the stderr output contains `XXX` * `//~ ERROR: XXX` make sure the stderr output contains `XXX` for an error in the line where this comment is written * Also supports `HELP`, `WARN` or `NOTE` for different kind of message * if one of those levels is specified explicitly, *all* diagnostics of this level or higher need an annotation. If you want to avoid this, just leave out the all caps level note entirely. diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index d4ee3efd1404..569dad5a2570 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -246,7 +246,8 @@ impl Comments { ); self.error_pattern = Some((args.trim().to_string(), l)); } - _ => exit!("unknown command {command} with args {args}"), + // Maybe the user just left a comment explaining a command without arguments + _ => self.parse_command(command, path, l), } } @@ -292,14 +293,8 @@ impl Comments { checked!(path, l); let (revision, pattern) = unwrap!(pattern.split_once(']'), "`//[` without corresponding `]`"); - if pattern.starts_with('~') { - self.parse_pattern_inner( - &pattern[1..], - fallthrough_to, - Some(revision.to_owned()), - path, - l, - ) + if let Some(pattern) = pattern.strip_prefix('~') { + self.parse_pattern_inner(pattern, fallthrough_to, Some(revision.to_owned()), path, l) } else { exit!("revisioned pattern must have `~` following the `]`"); } diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index ff0c4e1c8996..21b8c54ff20f 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -377,7 +377,7 @@ fn check_annotations( ) { if let Some((ref error_pattern, definition_line)) = comments.error_pattern { // first check the diagnostics messages outside of our file. We check this first, so that - // you can mix in-file annotations with // error-pattern annotations, even if there is overlap + // you can mix in-file annotations with //@error-pattern annotations, even if there is overlap // in the messages. if let Some(i) = messages_from_unknown_file_or_line .iter() From b3e64c252a3834ba880daf478dd0630bb61365d3 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 6 Jul 2022 08:42:32 +0000 Subject: [PATCH 3470/5092] Revert testing ui_test before ui tests --- miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri b/miri index be51535d59bf..f0d92b6a2b53 100755 --- a/miri +++ b/miri @@ -181,8 +181,8 @@ test|test-debug|bless|bless-debug) esac # Then test, and let caller control flags. # Only in root project and ui_test as `cargo-miri` has no tests. - $CARGO test $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml "$@" $CARGO test $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" + $CARGO test $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml "$@" ;; run|run-debug) # Scan for "--target" to overwrite the "MIRI_TEST_TARGET" env var so From 570032b0dd8042243721b78f50d186577a52a3a9 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 6 Jul 2022 09:09:53 +0000 Subject: [PATCH 3471/5092] Introduce a proper error handling framework --- Cargo.lock | 194 ++++++++++++++++++++++++++++++++++ tests/compiletest.rs | 20 ++-- ui_test/Cargo.lock | 194 ++++++++++++++++++++++++++++++++++ ui_test/Cargo.toml | 2 + ui_test/src/comments.rs | 18 ++-- ui_test/src/comments/tests.rs | 28 +++-- ui_test/src/lib.rs | 10 +- ui_test/src/tests.rs | 55 ++++++---- 8 files changed, 471 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 880fa271d97d..cc707c630e54 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aho-corasick" version = "0.7.18" @@ -37,18 +52,66 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "color-eyre" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ebf286c900a6d5867aeff75cfee3192857bb7f24b547d4f0df2ed6baa812c90" +dependencies = [ + "backtrace", + "color-spantrace", + "eyre", + "indenter", + "once_cell", + "owo-colors", + "tracing-error", +] + +[[package]] +name = "color-spantrace" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba75b3d9449ecdccb27ecbc479fdc0b87fa2dd43d2f8298f9bf0e59aacc8dce" +dependencies = [ + "once_cell", + "owo-colors", + "tracing-core", + "tracing-error", +] + [[package]] name = "colored" version = "2.0.0" @@ -158,6 +221,16 @@ dependencies = [ "termcolor", ] +[[package]] +name = "eyre" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" +dependencies = [ + "indenter", + "once_cell", +] + [[package]] name = "getrandom" version = "0.2.3" @@ -169,6 +242,12 @@ dependencies = [ "wasi", ] +[[package]] +name = "gimli" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -184,6 +263,12 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + [[package]] name = "instant" version = "0.1.12" @@ -267,6 +352,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "miniz_oxide" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" +dependencies = [ + "adler", +] + [[package]] name = "miri" version = "0.1.0" @@ -286,6 +380,21 @@ dependencies = [ "ui_test", ] +[[package]] +name = "object" +version = "0.28.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" + [[package]] name = "output_vt100" version = "0.1.3" @@ -295,6 +404,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "owo-colors" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "decf7381921fea4dcb2549c5667eda59b3ec297ab7e2b5fc33eac69d2e7da87b" + [[package]] name = "parking_lot" version = "0.11.2" @@ -329,6 +444,12 @@ dependencies = [ "libc", ] +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + [[package]] name = "ppv-lite86" version = "0.2.15" @@ -431,6 +552,12 @@ version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + [[package]] name = "rustc-hash" version = "1.1.0" @@ -501,6 +628,15 @@ dependencies = [ "serde", ] +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + [[package]] name = "shell-escape" version = "0.1.5" @@ -533,10 +669,62 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "thread_local" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tracing" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-error" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +dependencies = [ + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a713421342a5a666b7577783721d3117f1b69a393df803ee17bb73b1e122a59" +dependencies = [ + "sharded-slab", + "thread_local", + "tracing-core", +] + [[package]] name = "ui_test" version = "0.1.0" dependencies = [ + "color-eyre", "colored", "crossbeam", "lazy_static", @@ -553,6 +741,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 754fccd63b13..9537fb993c47 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -2,13 +2,13 @@ use colored::*; use regex::Regex; use std::env; use std::path::PathBuf; -use ui_test::{Config, Mode, OutputConflictHandling}; +use ui_test::{Config, Mode, OutputConflictHandling, color_eyre::Result}; fn miri_path() -> PathBuf { PathBuf::from(option_env!("MIRI").unwrap_or(env!("CARGO_BIN_EXE_miri"))) } -fn run_tests(mode: Mode, path: &str, target: Option) { +fn run_tests(mode: Mode, path: &str, target: Option) -> Result<()> { let in_rustc_test_suite = option_env!("RUSTC_STAGE").is_some(); // Add some flags we always want. @@ -108,7 +108,7 @@ regexes! { "sys/[a-z]+/" => "sys/PLATFORM/", } -fn ui(mode: Mode, path: &str) { +fn ui(mode: Mode, path: &str) -> Result<()> { let target = get_target(); let msg = format!( @@ -117,20 +117,24 @@ fn ui(mode: Mode, path: &str) { ); eprintln!("{}", msg.green().bold()); - run_tests(mode, path, target); + run_tests(mode, path, target) } fn get_target() -> Option { env::var("MIRI_TEST_TARGET").ok() } -fn main() { +fn main() -> Result<()> { + ui_test::color_eyre::install()?; + // Add a test env var to do environment communication tests. env::set_var("MIRI_ENV_VAR_TEST", "0"); // Let the tests know where to store temp files (they might run for a different target, which can make this hard to find). env::set_var("MIRI_TEMP", env::temp_dir()); - ui(Mode::Pass, "tests/pass"); - ui(Mode::Panic, "tests/panic"); - ui(Mode::Fail, "tests/fail"); + ui(Mode::Pass, "tests/pass")?; + ui(Mode::Panic, "tests/panic")?; + ui(Mode::Fail, "tests/fail")?; + + Ok(()) } diff --git a/ui_test/Cargo.lock b/ui_test/Cargo.lock index 5a4cdb892713..2065cc34bef8 100644 --- a/ui_test/Cargo.lock +++ b/ui_test/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aho-corasick" version = "0.7.18" @@ -37,12 +52,60 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "color-eyre" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ebf286c900a6d5867aeff75cfee3192857bb7f24b547d4f0df2ed6baa812c90" +dependencies = [ + "backtrace", + "color-spantrace", + "eyre", + "indenter", + "once_cell", + "owo-colors", + "tracing-error", +] + +[[package]] +name = "color-spantrace" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba75b3d9449ecdccb27ecbc479fdc0b87fa2dd43d2f8298f9bf0e59aacc8dce" +dependencies = [ + "once_cell", + "owo-colors", + "tracing-core", + "tracing-error", +] + [[package]] name = "colored" version = "2.0.0" @@ -139,6 +202,22 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" +[[package]] +name = "eyre" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "gimli" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -148,6 +227,12 @@ dependencies = [ "libc", ] +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + [[package]] name = "itoa" version = "1.0.2" @@ -181,6 +266,30 @@ dependencies = [ "autocfg", ] +[[package]] +name = "miniz_oxide" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" +dependencies = [ + "adler", +] + +[[package]] +name = "object" +version = "0.28.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" + [[package]] name = "output_vt100" version = "0.1.3" @@ -190,6 +299,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "owo-colors" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "decf7381921fea4dcb2549c5667eda59b3ec297ab7e2b5fc33eac69d2e7da87b" + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + [[package]] name = "pretty_assertions" version = "1.2.1" @@ -237,6 +358,12 @@ version = "0.6.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + [[package]] name = "rustc_version" version = "0.4.0" @@ -295,6 +422,15 @@ dependencies = [ "serde", ] +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + [[package]] name = "syn" version = "1.0.95" @@ -306,10 +442,62 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "thread_local" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tracing" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-error" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +dependencies = [ + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a713421342a5a666b7577783721d3117f1b69a393df803ee17bb73b1e122a59" +dependencies = [ + "sharded-slab", + "thread_local", + "tracing-core", +] + [[package]] name = "ui_test" version = "0.1.0" dependencies = [ + "color-eyre", "colored", "crossbeam", "lazy_static", @@ -326,6 +514,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "winapi" version = "0.3.9" diff --git a/ui_test/Cargo.toml b/ui_test/Cargo.toml index 1d480b693814..94c5acb6b70b 100644 --- a/ui_test/Cargo.toml +++ b/ui_test/Cargo.toml @@ -17,3 +17,5 @@ crossbeam = "0.8.1" lazy_static = "1.4.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" +color-eyre = "0.6.1" + diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 569dad5a2570..fcbcae33f2d7 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -4,6 +4,8 @@ use regex::Regex; use crate::rustc_stderr::Level; +use color_eyre::eyre::Result; + #[cfg(test)] mod tests; @@ -102,8 +104,8 @@ macro_rules! checked { } impl Comments { - pub(crate) fn parse_file(path: &Path) -> Self { - let content = std::fs::read_to_string(path).unwrap(); + pub(crate) fn parse_file(path: &Path) -> Result { + let content = std::fs::read_to_string(path)?; Self::parse(path, &content) } @@ -112,7 +114,7 @@ impl Comments { /// /// This function will only parse `//@` and `//~` style comments /// and ignore all others - fn parse_checked(path: &Path, content: &str) -> Self { + fn parse_checked(path: &Path, content: &str) -> Result { let mut this = Self::default(); // The line that a `|` will refer to @@ -136,16 +138,16 @@ impl Comments { fallthrough_to = None; } } - this + Ok(this) } /// Parse comments in `content`. /// `path` is only used to emit diagnostics if parsing fails. - pub(crate) fn parse(path: &Path, content: &str) -> Self { - let mut this = Self::parse_checked(path, content); + pub(crate) fn parse(path: &Path, content: &str) -> Result { + let mut this = Self::parse_checked(path, content)?; if content.contains("//@") { // Migration mode: if new syntax is used, ignore all old syntax - return this; + return Ok(this); } for (l, line) in content.lines().enumerate() { @@ -209,7 +211,7 @@ impl Comments { this.error_pattern = Some((s.trim().to_string(), l)); } } - this + Ok(this) } fn parse_command_with_args(&mut self, command: &str, args: &str, path: &Path, l: usize) { diff --git a/ui_test/src/comments/tests.rs b/ui_test/src/comments/tests.rs index dc69a5d4d600..0573ee8ba706 100644 --- a/ui_test/src/comments/tests.rs +++ b/ui_test/src/comments/tests.rs @@ -1,9 +1,13 @@ -use std::path::Path; +use std::{path::Path, panic::catch_unwind}; use super::Comments; +use color_eyre::eyre::{Result, bail}; +use crate::tests::init; + #[test] -fn parse_simple_comment() { +fn parse_simple_comment() -> Result<()> { + init(); let s = r" use std::mem; @@ -11,7 +15,7 @@ fn main() { let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address $HEX is unallocated) } "; - let comments = Comments::parse(Path::new(""), s); + let comments = Comments::parse(Path::new(""), s)?; println!("parsed comments: {:#?}", comments); assert_eq!(comments.error_matches[0].definition_line, 5); assert_eq!(comments.error_matches[0].revision, None); @@ -19,29 +23,33 @@ fn main() { comments.error_matches[0].matched, "encountered a dangling reference (address $HEX is unallocated)" ); + Ok(()) } #[test] -fn parse_slash_slash_at() { +fn parse_slash_slash_at() -> Result<()> { + init(); let s = r" //@ error-pattern: foomp use std::mem; "; - let comments = Comments::parse(Path::new(""), s); + let comments = Comments::parse(Path::new(""), s)?; println!("parsed comments: {:#?}", comments); assert_eq!(comments.error_pattern, Some(("foomp".to_string(), 2))); + Ok(()) } #[test] -#[should_panic] -fn parse_slash_slash_at_fail() { +fn parse_slash_slash_at_fail() -> Result<()> { + init(); let s = r" //@ error-pattern foomp use std::mem; "; - let comments = Comments::parse(Path::new(""), s); - println!("parsed comments: {:#?}", comments); - assert_eq!(comments.error_pattern, Some(("foomp".to_string(), 2))); + match catch_unwind(|| Comments::parse(Path::new(""), s)) { + Ok(_) => bail!("expected parsing to panic"), + Err(_) => Ok(()), + } } diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 21b8c54ff20f..90e7669f62aa 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -11,6 +11,8 @@ use colored::*; use comments::ErrorMatch; use regex::Regex; use rustc_stderr::{Level, Message}; +use color_eyre::eyre::Result; +pub use color_eyre; use crate::comments::{Comments, Condition}; @@ -51,7 +53,7 @@ pub enum OutputConflictHandling { pub type Filter = Vec<(Regex, &'static str)>; -pub fn run_tests(config: Config) { +pub fn run_tests(config: Config) -> Result<()> { eprintln!(" Compiler flags: {:?}", config.args); // Get the triple with which to run the tests @@ -94,7 +96,7 @@ pub fn run_tests(config: Config) { // Create N worker threads that receive files to test. for _ in 0..std::thread::available_parallelism().unwrap().get() { - s.spawn(|_| { + s.spawn(|_| -> Result<()> { for path in &receive { if !config.path_filter.is_empty() { let path_display = path.display().to_string(); @@ -103,7 +105,7 @@ pub fn run_tests(config: Config) { continue; } } - let comments = Comments::parse_file(&path); + let comments = Comments::parse_file(&path)?; // Ignore file if only/ignore rules do (not) apply if !test_file_conditions(&comments, &target) { ignored.fetch_add(1, Ordering::Relaxed); @@ -142,6 +144,7 @@ pub fn run_tests(config: Config) { } } } + Ok(()) }); } }) @@ -246,6 +249,7 @@ pub fn run_tests(config: Config) { filtered.to_string().yellow(), ); eprintln!(); + Ok(()) } #[derive(Debug)] diff --git a/ui_test/src/tests.rs b/ui_test/src/tests.rs index a45f8f8933c9..13a242f8d8a7 100644 --- a/ui_test/src/tests.rs +++ b/ui_test/src/tests.rs @@ -20,7 +20,8 @@ fn config() -> Config { } #[test] -fn issue_2156() { +fn issue_2156() -> Result<()> { + init(); let s = r" use std::mem; @@ -29,7 +30,7 @@ fn main() { } "; let path = Path::new("$DIR/"); - let comments = Comments::parse(path, s); + let comments = Comments::parse(path, s)?; let mut errors = vec![]; let config = config(); let messages = vec![ @@ -46,13 +47,14 @@ fn main() { [ Error::PatternNotFound { definition_line: 5, .. }, Error::ErrorsWithoutPattern { path: Some((_, 5)), .. }, - ] => {} + ] => Ok(()), _ => panic!("{:#?}", errors), } } #[test] -fn find_pattern() { +fn find_pattern() -> Result<()> { + init(); let s = r" use std::mem; @@ -60,7 +62,7 @@ fn main() { let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) } "; - let comments = Comments::parse(Path::new(""), s); + let comments = Comments::parse(Path::new(""), s)?; let config = config(); { let messages = vec![vec![], vec![], vec![], vec![], vec![], vec![ @@ -137,14 +139,15 @@ fn main() { ); match &errors[..] { // Note no `ErrorsWithoutPattern`, because there are no `//~NOTE` in the test file, so we ignore them - [Error::PatternNotFound { definition_line: 5, .. }] => {} + [Error::PatternNotFound { definition_line: 5, .. }] => Ok(()), _ => panic!("not the expected error: {:#?}", errors), } } } #[test] -fn duplicate_pattern() { +fn duplicate_pattern() -> Result<()> { + init(); let s = r" use std::mem; @@ -153,7 +156,7 @@ fn main() { //~^ ERROR encountered a dangling reference (address 0x10 is unallocated) } "; - let comments = Comments::parse(Path::new(""), s); + let comments = Comments::parse(Path::new(""), s)?; let config = config(); let messages = vec![ vec![], vec![], vec![], vec![], vec![], @@ -167,13 +170,14 @@ fn main() { let mut errors = vec![]; check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); match &errors[..] { - [Error::PatternNotFound { definition_line: 6, .. }] => {} + [Error::PatternNotFound { definition_line: 6, .. }] => Ok(()), _ => panic!("{:#?}", errors), } } #[test] -fn missing_pattern() { +fn missing_pattern() -> Result<()> { + init(); let s = r" use std::mem; @@ -181,7 +185,7 @@ fn main() { let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) } "; - let comments = Comments::parse(Path::new(""), s); + let comments = Comments::parse(Path::new(""), s)?; let config = config(); let messages = vec![ vec![], vec![], vec![], vec![], vec![], @@ -199,13 +203,14 @@ fn main() { let mut errors = vec![]; check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); match &errors[..] { - [Error::ErrorsWithoutPattern { path: Some((_, 5)), .. }] => {} + [Error::ErrorsWithoutPattern { path: Some((_, 5)), .. }] => Ok(()), _ => panic!("{:#?}", errors), } } #[test] -fn missing_warn_pattern() { +fn missing_warn_pattern() -> Result<()> { + init(); let s = r" use std::mem; @@ -214,7 +219,7 @@ fn main() { //~^ WARN cake } "; - let comments = Comments::parse(Path::new(""), s); + let comments = Comments::parse(Path::new(""), s)?; let config = config(); let messages= vec![ vec![], @@ -242,7 +247,7 @@ fn main() { match &errors[..] { [Error::ErrorsWithoutPattern { path: Some((_, 5)), msgs, .. }] => match &msgs[..] { - [Message { message, level: Level::Warn }] if message == "kaboom" => {} + [Message { message, level: Level::Warn }] if message == "kaboom" => Ok(()), _ => panic!("{:#?}", msgs), }, _ => panic!("{:#?}", errors), @@ -250,7 +255,8 @@ fn main() { } #[test] -fn missing_implicit_warn_pattern() { +fn missing_implicit_warn_pattern() -> Result<()> { + init(); let s = r" use std::mem; @@ -259,7 +265,7 @@ fn main() { //~^ cake } "; - let comments = Comments::parse(Path::new(""), s); + let comments = Comments::parse(Path::new(""), s)?; let config = config(); let messages = vec![ vec![], @@ -285,13 +291,14 @@ fn main() { let mut errors = vec![]; check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); match &errors[..] { - [] => {} + [] => Ok(()), _ => panic!("{:#?}", errors), } } #[test] -fn implicit_err_pattern() { +fn implicit_err_pattern() -> Result<()> { + init(); let s = r" use std::mem; @@ -299,7 +306,7 @@ fn main() { let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ encountered a dangling reference (address 0x10 is unallocated) } "; - let comments = Comments::parse(Path::new(""), s); + let comments = Comments::parse(Path::new(""), s)?; let config = config(); let messages = vec![ vec![], @@ -317,7 +324,13 @@ fn main() { let mut errors = vec![]; check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); match &errors[..] { - [Error::ErrorPatternWithoutErrorAnnotation(_, 5)] => {} + [Error::ErrorPatternWithoutErrorAnnotation(_, 5)] => Ok(()), _ => panic!("{:#?}", errors), } } + +static INIT: std::sync::Once = std::sync::Once::new(); + +pub fn init() { + INIT.call_once(|| color_eyre::install().unwrap()); +} From 54b6b034104ce81a8d02800b9fc7d5181389b4df Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 6 Jul 2022 09:44:03 +0000 Subject: [PATCH 3472/5092] Actually use eyre and get rid of the ad-hoc macros emulating error handling --- tests/compiletest.rs | 2 +- ui_test/src/comments.rs | 168 +++++++++++++++------------------- ui_test/src/comments/tests.rs | 8 +- ui_test/src/lib.rs | 18 ++-- 4 files changed, 89 insertions(+), 107 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 9537fb993c47..008fc7806457 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -2,7 +2,7 @@ use colored::*; use regex::Regex; use std::env; use std::path::PathBuf; -use ui_test::{Config, Mode, OutputConflictHandling, color_eyre::Result}; +use ui_test::{color_eyre::Result, Config, Mode, OutputConflictHandling}; fn miri_path() -> PathBuf { PathBuf::from(option_env!("MIRI").unwrap_or(env!("CARGO_BIN_EXE_miri"))) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index fcbcae33f2d7..481565cfea0a 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -4,7 +4,7 @@ use regex::Regex; use crate::rustc_stderr::Level; -use color_eyre::eyre::Result; +use color_eyre::eyre::{bail, ensure, eyre, Result}; #[cfg(test)] mod tests; @@ -66,43 +66,6 @@ impl Condition { } } -macro_rules! checked { - ($path:expr, $l:expr) => { - let path = $path; - let l = $l; - #[allow(unused_macros)] - macro_rules! exit { - ($fmt:expr $$(,$args:expr)*) => {{ - eprint!("{}:{l}: ", path.display()); - eprintln!($fmt, $$($args,)*); - #[cfg(not(test))] - std::process::exit(1); - #[cfg(test)] - panic!(); - }}; - } - #[allow(unused_macros)] - macro_rules! check { - ($cond:expr, $fmt:expr $$(,$args:expr)*) => {{ - if !$cond { - exit!($fmt $$(,$args)*); - } - }}; - } - #[allow(unused_macros)] - macro_rules! unwrap { - ($cond:expr, $fmt:expr $$(,$args:expr)*) => {{ - match $cond { - Some(val) => val, - None => { - exit!($fmt $$(,$args)*); - } - } - }}; - } - }; -} - impl Comments { pub(crate) fn parse_file(path: &Path) -> Result { let content = std::fs::read_to_string(path)?; @@ -121,26 +84,38 @@ impl Comments { let mut fallthrough_to = None; for (l, line) in content.lines().enumerate() { let l = l + 1; // enumerate starts at 0, but line numbers start at 1 - if let Some((_, command)) = line.split_once("//@") { - let command = command.trim(); - if let Some((command, args)) = command.split_once(':') { - this.parse_command_with_args(command, args, path, l); - } else if let Some((command, _comments)) = command.split_once(' ') { - this.parse_command(command, path, l) - } else { - this.parse_command(command, path, l) - } - } else if let Some((_, pattern)) = line.split_once("//~") { - this.parse_pattern(pattern, &mut fallthrough_to, path, l) - } else if let Some((_, pattern)) = line.split_once("//[") { - this.parse_revisioned_pattern(pattern, &mut fallthrough_to, path, l) - } else { - fallthrough_to = None; - } + this.parse_checked_line(l, &mut fallthrough_to, line).map_err(|err| { + err.wrap_err(format!("{}:{l}: failed to parse annotation", path.display())) + })?; } Ok(this) } + fn parse_checked_line( + &mut self, + l: usize, + fallthrough_to: &mut Option, + line: &str, + ) -> Result<()> { + if let Some((_, command)) = line.split_once("//@") { + let command = command.trim(); + if let Some((command, args)) = command.split_once(':') { + self.parse_command_with_args(command, args, l) + } else if let Some((command, _comments)) = command.split_once(' ') { + self.parse_command(command) + } else { + self.parse_command(command) + } + } else if let Some((_, pattern)) = line.split_once("//~") { + self.parse_pattern(pattern, fallthrough_to, l) + } else if let Some((_, pattern)) = line.split_once("//[") { + self.parse_revisioned_pattern(pattern, fallthrough_to, l) + } else { + *fallthrough_to = None; + Ok(()) + } + } + /// Parse comments in `content`. /// `path` is only used to emit diagnostics if parsing fails. pub(crate) fn parse(path: &Path, content: &str) -> Result { @@ -214,11 +189,10 @@ impl Comments { Ok(this) } - fn parse_command_with_args(&mut self, command: &str, args: &str, path: &Path, l: usize) { - checked!(path, l); + fn parse_command_with_args(&mut self, command: &str, args: &str, l: usize) -> Result<()> { match command { "revisions" => { - check!(self.revisions.is_none(), "cannot specifiy revisions twice"); + ensure!(self.revisions.is_none(), "cannot specifiy revisions twice"); self.revisions = Some(args.split_whitespace().map(|s| s.to_string()).collect()); } "compile-flags" => { @@ -226,22 +200,22 @@ impl Comments { } "rustc-env" => for env in args.split_whitespace() { - let (k, v) = unwrap!( - env.split_once('='), - "environment variables must be key/value pairs separated by a `=`" - ); + let (k, v) = env.split_once('=').ok_or_else(|| { + eyre!("environment variables must be key/value pairs separated by a `=`") + })?; self.env_vars.push((k.to_string(), v.to_string())); }, "normalize-stderr-test" => { - let (from, to) = - unwrap!(args.split_once("->"), "normalize-stderr-test needs a `->`"); + let (from, to) = args + .split_once("->") + .ok_or_else(|| eyre!("normalize-stderr-test needs a `->`"))?; let from = from.trim().trim_matches('"'); let to = to.trim().trim_matches('"'); - let from = unwrap!(Regex::new(from).ok(), "invalid regex"); + let from = Regex::new(from).ok().ok_or_else(|| eyre!("invalid regex"))?; self.normalize_stderr.push((from, to.to_string())); } "error-pattern" => { - check!( + ensure!( self.error_pattern.is_none(), "cannot specifiy error_pattern twice, previous: {:?}", self.error_pattern @@ -249,56 +223,52 @@ impl Comments { self.error_pattern = Some((args.trim().to_string(), l)); } // Maybe the user just left a comment explaining a command without arguments - _ => self.parse_command(command, path, l), + _ => self.parse_command(command)?, } + Ok(()) } - fn parse_command(&mut self, command: &str, path: &Path, l: usize) { - checked!(path, l); - + fn parse_command(&mut self, command: &str) -> Result<()> { if let Some(s) = command.strip_prefix("ignore-") { self.ignore.push(Condition::parse(s)); - return; + return Ok(()); } if let Some(s) = command.strip_prefix("only-") { self.only.push(Condition::parse(s)); - return; + return Ok(()); } if command.starts_with("stderr-per-bitwidth") { - check!(!self.stderr_per_bitwidth, "cannot specifiy stderr-per-bitwidth twice"); + ensure!(!self.stderr_per_bitwidth, "cannot specifiy stderr-per-bitwidth twice"); self.stderr_per_bitwidth = true; - return; + return Ok(()); } - exit!("unknown command {command}"); + bail!("unknown command {command}"); } fn parse_pattern( &mut self, pattern: &str, fallthrough_to: &mut Option, - path: &Path, l: usize, - ) { - self.parse_pattern_inner(pattern, fallthrough_to, None, path, l) + ) -> Result<()> { + self.parse_pattern_inner(pattern, fallthrough_to, None, l) } fn parse_revisioned_pattern( &mut self, pattern: &str, fallthrough_to: &mut Option, - path: &Path, l: usize, - ) { - checked!(path, l); + ) -> Result<()> { let (revision, pattern) = - unwrap!(pattern.split_once(']'), "`//[` without corresponding `]`"); + pattern.split_once(']').ok_or_else(|| eyre!("`//[` without corresponding `]`"))?; if let Some(pattern) = pattern.strip_prefix('~') { - self.parse_pattern_inner(pattern, fallthrough_to, Some(revision.to_owned()), path, l) + self.parse_pattern_inner(pattern, fallthrough_to, Some(revision.to_owned()), l) } else { - exit!("revisioned pattern must have `~` following the `]`"); + bail!("revisioned pattern must have `~` following the `]`"); } } @@ -308,21 +278,25 @@ impl Comments { pattern: &str, fallthrough_to: &mut Option, revision: Option, - path: &Path, l: usize, - ) { - checked!(path, l); + ) -> Result<()> { // FIXME: check that the error happens on the marked line - let (match_line, pattern) = match unwrap!(pattern.chars().next(), "no pattern specified") { - '|' => - (*unwrap!(fallthrough_to, "`//~|` pattern without preceding line"), &pattern[1..]), - '^' => { - let offset = pattern.chars().take_while(|&c| c == '^').count(); - (l - offset, &pattern[offset..]) - } - _ => (l, pattern), - }; + let (match_line, pattern) = + match pattern.chars().next().ok_or_else(|| eyre!("no pattern specified"))? { + '|' => + ( + *fallthrough_to + .as_mut() + .ok_or_else(|| eyre!("`//~|` pattern without preceding line"))?, + &pattern[1..], + ), + '^' => { + let offset = pattern.chars().take_while(|&c| c == '^').count(); + (l - offset, &pattern[offset..]) + } + _ => (l, pattern), + }; let (level, pattern) = match pattern.trim_start().split_once(|c| matches!(c, ':' | ' ')) { None => (None, pattern), @@ -335,7 +309,7 @@ impl Comments { let matched = pattern.trim().to_string(); - check!(!matched.is_empty(), "no pattern specified"); + ensure!(!matched.is_empty(), "no pattern specified"); *fallthrough_to = Some(match_line); @@ -346,5 +320,7 @@ impl Comments { definition_line: l, line: match_line, }); + + Ok(()) } } diff --git a/ui_test/src/comments/tests.rs b/ui_test/src/comments/tests.rs index 0573ee8ba706..cdd81aa99053 100644 --- a/ui_test/src/comments/tests.rs +++ b/ui_test/src/comments/tests.rs @@ -1,9 +1,9 @@ -use std::{path::Path, panic::catch_unwind}; +use std::path::Path; use super::Comments; -use color_eyre::eyre::{Result, bail}; use crate::tests::init; +use color_eyre::eyre::{bail, Result}; #[test] fn parse_simple_comment() -> Result<()> { @@ -48,8 +48,8 @@ fn parse_slash_slash_at_fail() -> Result<()> { use std::mem; "; - match catch_unwind(|| Comments::parse(Path::new(""), s)) { - Ok(_) => bail!("expected parsing to panic"), + match Comments::parse(Path::new(""), s) { + Ok(_) => bail!("expected parsing to fail"), Err(_) => Ok(()), } } diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 90e7669f62aa..da562fcac7d2 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -7,12 +7,12 @@ use std::process::{Command, ExitStatus}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Mutex; +pub use color_eyre; +use color_eyre::eyre::Result; use colored::*; use comments::ErrorMatch; use regex::Regex; use rustc_stderr::{Level, Message}; -use color_eyre::eyre::Result; -pub use color_eyre; use crate::comments::{Comments, Condition}; @@ -68,7 +68,7 @@ pub fn run_tests(config: Config) -> Result<()> { let ignored = AtomicUsize::default(); let filtered = AtomicUsize::default(); - crossbeam::scope(|s| { + crossbeam::scope(|s| -> Result<()> { // Create a thread that is in charge of walking the directory and submitting jobs. // It closes the channel when it is done. s.spawn(|_| { @@ -94,9 +94,11 @@ pub fn run_tests(config: Config) -> Result<()> { drop(submit); }); + let mut threads = vec![]; + // Create N worker threads that receive files to test. for _ in 0..std::thread::available_parallelism().unwrap().get() { - s.spawn(|_| -> Result<()> { + threads.push(s.spawn(|_| -> Result<()> { for path in &receive { if !config.path_filter.is_empty() { let path_display = path.display().to_string(); @@ -145,10 +147,14 @@ pub fn run_tests(config: Config) -> Result<()> { } } Ok(()) - }); + })); } + for thread in threads { + thread.join().unwrap()?; + } + Ok(()) }) - .unwrap(); + .unwrap()?; // Print all errors in a single thread to show reliable output let failures = failures.into_inner().unwrap(); From 63916d6f0429718112661e47fac37b2fcfea338e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 6 Jul 2022 09:53:52 +0000 Subject: [PATCH 3473/5092] Document all the things --- ui_test/README.md | 38 +++++++++++++++++++++++++------------- ui_test/src/comments.rs | 2 +- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/ui_test/README.md b/ui_test/README.md index f7852c82e44b..fef2c6d44ba6 100644 --- a/ui_test/README.md +++ b/ui_test/README.md @@ -7,25 +7,37 @@ A smaller version of compiletest-rs ## Supported magic comment annotations -* `// ignore-XXX` avoids running the test on targets whose triple contains `XXX` +If your test tests for failure, you need to add a `//~` annotation where the error is happening +to make sure that the test will always keep failing with a specific message at the annotated line. + +`//~ ERROR: XXX` make sure the stderr output contains `XXX` for an error in the line where this comment is written + +* Also supports `HELP`, `WARN` or `NOTE` for different kind of message + * if one of those levels is specified explicitly, *all* diagnostics of this level or higher need an annotation. If you want to avoid this, just leave out the all caps level note entirely. +* If the all caps note is left out, a message of any level is matched. Leaving it out is not allowed for `ERROR` levels. +* This checks the output *before* normalization, so you can check things that get normalized away, but need to + be careful not to accidentally have a pattern that differs between platforms. + +In order to change how a single test is tested, you can add various `//@` comments to the test. +Any other comments will be ignored, and all `//@` comments must be formatted precisely as +their command specifies, or the test will fail without even being run. + +* `//@ignore-XXX` avoids running the test on targets whose triple contains `XXX` * `XXX` can also be one of `64bit`, `32bit` or `16bit` -* `// only-XXX` avoids running the test on targets whose triple **does not** contain `XXX` +* `//@only-XXX` avoids running the test on targets whose triple **does not** contain `XXX` * `XXX` can also be one of `64bit`, `32bit` or `16bit` -* `// stderr-per-bitwidth` produces one stderr file per bitwidth, as they may differ significantly sometimes +* `//@stderr-per-bitwidth` produces one stderr file per bitwidth, as they may differ significantly sometimes * `//@error-pattern: XXX` make sure the stderr output contains `XXX` -* `//~ ERROR: XXX` make sure the stderr output contains `XXX` for an error in the line where this comment is written - * Also supports `HELP`, `WARN` or `NOTE` for different kind of message - * if one of those levels is specified explicitly, *all* diagnostics of this level or higher need an annotation. If you want to avoid this, just leave out the all caps level note entirely. - * If the all caps note is left out, a message of any level is matched. Leaving it out is not allowed for `ERROR` levels. - * This checks the output *before* normalization, so you can check things that get normalized away, but need to - be careful not to accidentally have a pattern that differs between platforms. -* `// revisions: XXX YYY` runs the test once for each space separated name in the list +* `//@revisions: XXX YYY` runs the test once for each space separated name in the list * emits one stderr file per revision * `//~` comments can be restricted to specific revisions by adding the revision name before the `~` in square brackets: `//[XXX]~` -* `// compile-flags: XXX` appends `XXX` to the command line arguments passed to the rustc driver -* `// rustc-env: XXX=YYY` sets the env var `XXX` to `YYY` for the rustc driver execution. +* `//@compile-flags: XXX` appends `XXX` to the command line arguments passed to the rustc driver + * you can specify this multiple times, and all the flags will accumulate +* `//@rustc-env: XXX=YYY` sets the env var `XXX` to `YYY` for the rustc driver execution. * for Miri these env vars are used during compilation via rustc and during the emulation of the program -* `// normalize-stderr-test: "REGEX" -> "REPLACEMENT"` replaces all matches of `REGEX` in the stderr with `REPLACEMENT`. The replacement may specify `$1` and similar backreferences to paste captures. + * you can specify this multiple times, accumulating all the env vars +* `//@normalize-stderr-test: "REGEX" -> "REPLACEMENT"` replaces all matches of `REGEX` in the stderr with `REPLACEMENT`. The replacement may specify `$1` and similar backreferences to paste captures. + * you can specify multiple such commands, there is no need to create a single regex that handles multiple replacements that you want to perform. ## Significant differences to compiletest-rs diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 481565cfea0a..dd6ca9581ab2 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -75,7 +75,7 @@ impl Comments { /// Parse comments in `content`. /// `path` is only used to emit diagnostics if parsing fails. /// - /// This function will only parse `//@` and `//~` style comments + /// This function will only parse `//@` and `//~` style comments (and the `//[xxx]~` variant) /// and ignore all others fn parse_checked(path: &Path, content: &str) -> Result { let mut this = Self::default(); From f15a56d9bcc9712bca842f182e160df1942aea98 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 6 Jul 2022 10:17:21 +0000 Subject: [PATCH 3474/5092] Implement a proper command parser... ... that grabs things from the front instead of splitting at spaces and colons and hoping for the best --- ui_test/src/comments.rs | 65 ++++++++++++++++++----------------- ui_test/src/comments/tests.rs | 2 +- 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index dd6ca9581ab2..fa46b5497000 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -98,14 +98,7 @@ impl Comments { line: &str, ) -> Result<()> { if let Some((_, command)) = line.split_once("//@") { - let command = command.trim(); - if let Some((command, args)) = command.split_once(':') { - self.parse_command_with_args(command, args, l) - } else if let Some((command, _comments)) = command.split_once(' ') { - self.parse_command(command) - } else { - self.parse_command(command) - } + self.parse_command(command.trim(), l) } else if let Some((_, pattern)) = line.split_once("//~") { self.parse_pattern(pattern, fallthrough_to, l) } else if let Some((_, pattern)) = line.split_once("//[") { @@ -189,7 +182,22 @@ impl Comments { Ok(this) } - fn parse_command_with_args(&mut self, command: &str, args: &str, l: usize) -> Result<()> { + fn parse_command(&mut self, command: &str, l: usize) -> Result<()> { + // Commands are letters or dashes, grab everything until the first character that is neither of those. + let (command, args) = match command.chars().position(|c: char| !c.is_alphabetic() && c != '-') { + None => (command, ""), + Some(i) => { + let (command, args) = command.split_at(i); + let mut args = args.chars(); + let next = args.next().expect("the `position` above guarantees that there is at least one char"); + let args = match next { + ':' | ' ' => args.as_str(), + _ => bail!("expected space or `:`, got `{next}`"), + }; + (command, args) + } + }; + match command { "revisions" => { ensure!(self.revisions.is_none(), "cannot specifiy revisions twice"); @@ -222,32 +230,27 @@ impl Comments { ); self.error_pattern = Some((args.trim().to_string(), l)); } - // Maybe the user just left a comment explaining a command without arguments - _ => self.parse_command(command)?, + "stderr-per-bitwidth" => { + ensure!(!self.stderr_per_bitwidth, "cannot specifiy stderr-per-bitwidth twice"); + self.stderr_per_bitwidth = true; + } + command => { + if let Some(s) = command.strip_prefix("ignore-") { + self.ignore.push(Condition::parse(s)); + return Ok(()); + } + + if let Some(s) = command.strip_prefix("only-") { + self.only.push(Condition::parse(s)); + return Ok(()); + } + bail!("unknown command {command}"); + } } + Ok(()) } - fn parse_command(&mut self, command: &str) -> Result<()> { - if let Some(s) = command.strip_prefix("ignore-") { - self.ignore.push(Condition::parse(s)); - return Ok(()); - } - - if let Some(s) = command.strip_prefix("only-") { - self.only.push(Condition::parse(s)); - return Ok(()); - } - - if command.starts_with("stderr-per-bitwidth") { - ensure!(!self.stderr_per_bitwidth, "cannot specifiy stderr-per-bitwidth twice"); - self.stderr_per_bitwidth = true; - return Ok(()); - } - - bail!("unknown command {command}"); - } - fn parse_pattern( &mut self, pattern: &str, diff --git a/ui_test/src/comments/tests.rs b/ui_test/src/comments/tests.rs index cdd81aa99053..15a0aae247b1 100644 --- a/ui_test/src/comments/tests.rs +++ b/ui_test/src/comments/tests.rs @@ -44,7 +44,7 @@ use std::mem; fn parse_slash_slash_at_fail() -> Result<()> { init(); let s = r" -//@ error-pattern foomp +//@ error-patttern foomp use std::mem; "; From eab02b69e51165274af4b1e1df9625df5347a6a5 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 6 Jul 2022 10:38:14 +0000 Subject: [PATCH 3475/5092] rustfmt --- ui_test/src/comments.rs | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index fa46b5497000..727e6a2aa237 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -184,19 +184,22 @@ impl Comments { fn parse_command(&mut self, command: &str, l: usize) -> Result<()> { // Commands are letters or dashes, grab everything until the first character that is neither of those. - let (command, args) = match command.chars().position(|c: char| !c.is_alphabetic() && c != '-') { - None => (command, ""), - Some(i) => { - let (command, args) = command.split_at(i); - let mut args = args.chars(); - let next = args.next().expect("the `position` above guarantees that there is at least one char"); - let args = match next { - ':' | ' ' => args.as_str(), - _ => bail!("expected space or `:`, got `{next}`"), - }; - (command, args) - } - }; + let (command, args) = + match command.chars().position(|c: char| !c.is_alphabetic() && c != '-') { + None => (command, ""), + Some(i) => { + let (command, args) = command.split_at(i); + let mut args = args.chars(); + let next = args + .next() + .expect("the `position` above guarantees that there is at least one char"); + let args = match next { + ':' | ' ' => args.as_str(), + _ => bail!("expected space or `:`, got `{next}`"), + }; + (command, args) + } + }; match command { "revisions" => { From cc35d809c1d7585e03044524d9b2838200880791 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 7 Jul 2022 08:07:50 +0000 Subject: [PATCH 3476/5092] Remove an outdated comment --- ui_test/src/comments.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 727e6a2aa237..0727c182a304 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -286,8 +286,6 @@ impl Comments { revision: Option, l: usize, ) -> Result<()> { - // FIXME: check that the error happens on the marked line - let (match_line, pattern) = match pattern.chars().next().ok_or_else(|| eyre!("no pattern specified"))? { '|' => From a1e0d0df79d58aba78d2aabe783647e5cd80ba81 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 7 Jul 2022 08:13:24 +0000 Subject: [PATCH 3477/5092] Add some comments --- ui_test/src/comments.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 0727c182a304..905ce96c50aa 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -80,8 +80,7 @@ impl Comments { fn parse_checked(path: &Path, content: &str) -> Result { let mut this = Self::default(); - // The line that a `|` will refer to - let mut fallthrough_to = None; + let mut fallthrough_to = None; // The line that a `|` will refer to. for (l, line) in content.lines().enumerate() { let l = l + 1; // enumerate starts at 0, but line numbers start at 1 this.parse_checked_line(l, &mut fallthrough_to, line).map_err(|err| { @@ -190,6 +189,7 @@ impl Comments { Some(i) => { let (command, args) = command.split_at(i); let mut args = args.chars(); + // Commands are separated from their arguments by ':' or ' ' let next = args .next() .expect("the `position` above guarantees that there is at least one char"); From bc07c19961b889fbecbfea9f7bca43b6174cffdb Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 7 Jul 2022 08:15:21 +0000 Subject: [PATCH 3478/5092] Explain `tests::init` function --- ui_test/src/tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui_test/src/tests.rs b/ui_test/src/tests.rs index 13a242f8d8a7..11a3d6aca278 100644 --- a/ui_test/src/tests.rs +++ b/ui_test/src/tests.rs @@ -329,8 +329,8 @@ fn main() { } } -static INIT: std::sync::Once = std::sync::Once::new(); - +/// Call this from every test to initialize eyre only once across all tests. pub fn init() { + static INIT: std::sync::Once = std::sync::Once::new(); INIT.call_once(|| color_eyre::install().unwrap()); } From 9b71180e52bda136230b8185823728a7497556bb Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 7 Jul 2022 08:55:24 +0000 Subject: [PATCH 3479/5092] Create a proper normalization regex parser --- ui_test/src/comments.rs | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 905ce96c50aa..63a14ce13b56 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -197,7 +197,7 @@ impl Comments { ':' | ' ' => args.as_str(), _ => bail!("expected space or `:`, got `{next}`"), }; - (command, args) + (command, args.trim()) } }; @@ -217,12 +217,37 @@ impl Comments { self.env_vars.push((k.to_string(), v.to_string())); }, "normalize-stderr-test" => { - let (from, to) = args - .split_once("->") - .ok_or_else(|| eyre!("normalize-stderr-test needs a `->`"))?; - let from = from.trim().trim_matches('"'); - let to = to.trim().trim_matches('"'); - let from = Regex::new(from).ok().ok_or_else(|| eyre!("invalid regex"))?; + fn parse_str(s: &str) -> Result<(&str, &str)> { + let mut chars = s.char_indices(); + match chars.next().ok_or_else(|| eyre!("missing arguments"))?.1 { + '"' => { + let s = chars.as_str(); + let mut escaped = false; + for (i, c) in chars { + if escaped { + escaped = false; + } else if c == '"' { + return Ok((&s[..(i - 1)], s[i..].trim_start())) + } else { + escaped = c == '\\'; + } + } + bail!("no closing quotes found for {s}") + } + c => bail!("expected '\"', got {c}"), + } + } + + let (from, rest) = parse_str(args)?; + + let to = rest.strip_prefix("->").ok_or_else(|| { + eyre!("normalize-stderr-test needs a pattern and replacement separated by `->`") + })?.trim_start(); + let (to, rest) = parse_str(to)?; + + ensure!(rest.is_empty(), "trailing text after pattern replacement: {rest}"); + + let from = Regex::new(from)?; self.normalize_stderr.push((from, to.to_string())); } "error-pattern" => { From af798232eb9ab5f7c8c8c5760d2c96d4612e0d7c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 7 Jul 2022 09:20:48 +0000 Subject: [PATCH 3480/5092] Rustfmt --- ui_test/src/comments.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 63a14ce13b56..6f2d8aa086d9 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -227,7 +227,7 @@ impl Comments { if escaped { escaped = false; } else if c == '"' { - return Ok((&s[..(i - 1)], s[i..].trim_start())) + return Ok((&s[..(i - 1)], s[i..].trim_start())); } else { escaped = c == '\\'; } From 334aa3d7f84f66bd96a94dda499d5300f3333b15 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 8 Jul 2022 15:14:25 +0000 Subject: [PATCH 3481/5092] Add FIXME --- ui_test/src/comments.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 6f2d8aa086d9..080a887d9e74 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -193,6 +193,7 @@ impl Comments { let next = args .next() .expect("the `position` above guarantees that there is at least one char"); + // FIXME: this replicates the existing flexibility in our syntax. Consider requiring the colon. let args = match next { ':' | ' ' => args.as_str(), _ => bail!("expected space or `:`, got `{next}`"), From 1597cec887c0716fd0fa4e537d786b8a8d62829d Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 8 Jul 2022 15:16:16 +0000 Subject: [PATCH 3482/5092] Documentation --- ui_test/src/comments.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 080a887d9e74..2b6108f255f8 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -218,6 +218,9 @@ impl Comments { self.env_vars.push((k.to_string(), v.to_string())); }, "normalize-stderr-test" => { + /// Parses a string literal. `s` has to start with `"`; everything until the next `"` is + /// returned in the first component. `\` can be used to escape arbitrary character. + /// Second return component is the rest of the string with leading whitespace removed. fn parse_str(s: &str) -> Result<(&str, &str)> { let mut chars = s.char_indices(); match chars.next().ok_or_else(|| eyre!("missing arguments"))?.1 { @@ -226,6 +229,7 @@ impl Comments { let mut escaped = false; for (i, c) in chars { if escaped { + // Accept any character as literal after a `\`. escaped = false; } else if c == '"' { return Ok((&s[..(i - 1)], s[i..].trim_start())); From e4f7c6845ce09da759bad521d4dd23cf70632874 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 8 Jul 2022 15:20:28 +0000 Subject: [PATCH 3483/5092] Hide regular backtrace information from user-facing errors --- ui_test/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui_test/Cargo.toml b/ui_test/Cargo.toml index 94c5acb6b70b..cdc5e5db472c 100644 --- a/ui_test/Cargo.toml +++ b/ui_test/Cargo.toml @@ -17,5 +17,5 @@ crossbeam = "0.8.1" lazy_static = "1.4.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -color-eyre = "0.6.1" +color-eyre = { version = "0.6.1", default-features = false, features = ["capture-spantrace"] } From 6e106617f10b2431aeb0fdb84d50cbdcb0d4dad8 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 8 Jul 2022 16:08:32 +0000 Subject: [PATCH 3484/5092] Port all tests --- tests/fail/box-cell-alias.rs | 2 +- .../concurrency/libc_pthread_join_detached.rs | 2 +- .../concurrency/libc_pthread_join_joined.rs | 2 +- .../concurrency/libc_pthread_join_main.rs | 2 +- .../concurrency/libc_pthread_join_multiple.rs | 2 +- .../concurrency/libc_pthread_join_self.rs | 4 +- .../thread_local_static_dealloc.rs | 2 +- tests/fail/concurrency/too_few_args.rs | 2 +- tests/fail/concurrency/too_many_args.rs | 2 +- tests/fail/concurrency/unwind_top_of_stack.rs | 4 +- .../dangling_pointer_addr_of.rs | 2 +- .../dangling_pointer_deref.rs | 2 +- .../dangling_pointers/dangling_zst_deref.rs | 2 +- .../dangling_pointers/deref-invalid-ptr.rs | 2 +- tests/fail/dangling_pointers/dyn_size.rs | 2 +- .../maybe_null_pointer_deref_zst.rs | 2 +- .../maybe_null_pointer_write_zst.rs | 2 +- .../null_pointer_deref_zst.rs | 2 +- .../fail/dangling_pointers/stack_temporary.rs | 2 +- .../storage_dead_dangling.rs | 2 +- .../dangling_pointers/wild_pointer_deref.rs | 2 +- tests/fail/data_race/alloc_read_race.rs | 4 +- tests/fail/data_race/alloc_write_race.rs | 4 +- .../data_race/atomic_read_na_write_race1.rs | 2 +- .../data_race/atomic_read_na_write_race2.rs | 2 +- .../data_race/atomic_write_na_read_race1.rs | 2 +- .../data_race/atomic_write_na_read_race2.rs | 2 +- .../data_race/atomic_write_na_write_race1.rs | 2 +- .../data_race/atomic_write_na_write_race2.rs | 2 +- .../data_race/dangling_thread_async_race.rs | 4 +- tests/fail/data_race/dangling_thread_race.rs | 4 +- tests/fail/data_race/dealloc_read_race1.rs | 2 +- tests/fail/data_race/dealloc_read_race2.rs | 2 +- .../fail/data_race/dealloc_read_race_stack.rs | 4 +- tests/fail/data_race/dealloc_write_race1.rs | 2 +- tests/fail/data_race/dealloc_write_race2.rs | 2 +- .../data_race/dealloc_write_race_stack.rs | 4 +- .../data_race/enable_after_join_to_main.rs | 2 +- tests/fail/data_race/fence_after_load.rs | 4 +- tests/fail/data_race/read_write_race.rs | 2 +- tests/fail/data_race/read_write_race_stack.rs | 4 +- tests/fail/data_race/relax_acquire_race.rs | 4 +- tests/fail/data_race/release_seq_race.rs | 4 +- .../data_race/release_seq_race_same_thread.rs | 4 +- tests/fail/data_race/rmw_race.rs | 4 +- tests/fail/data_race/stack_pop_race.rs | 4 +- tests/fail/data_race/write_write_race.rs | 2 +- .../fail/data_race/write_write_race_stack.rs | 4 +- tests/fail/environ-gets-deallocated.rs | 2 +- tests/fail/erroneous_const.rs | 2 +- tests/fail/fs/close_stdout.rs | 4 +- tests/fail/fs/isolated_stdin.rs | 2 +- tests/fail/fs/read_from_stdout.rs | 4 +- .../fs/unix_open_missing_required_mode.rs | 4 +- tests/fail/fs/write_to_stdin.rs | 2 +- .../exported_symbol_abi_mismatch.rs | 2 +- .../exported_symbol_bad_unwind1.rs | 2 +- .../exported_symbol_bad_unwind2.rs | 2 +- .../cast_box_int_to_fn_ptr.rs | 2 +- .../function_pointers/cast_int_to_fn_ptr.rs | 2 +- .../fail/function_pointers/execute_memory.rs | 2 +- tests/fail/function_pointers/fn_ptr_offset.rs | 2 +- tests/fail/generator-pinned-moved.rs | 2 +- tests/fail/invalid_bool.rs | 2 +- tests/fail/invalid_char.rs | 2 +- tests/fail/invalid_int.rs | 2 +- tests/fail/modifying_constants.rs | 2 +- tests/fail/never_say_never.rs | 2 +- tests/fail/never_transmute_humans.rs | 2 +- tests/fail/never_transmute_void.rs | 2 +- tests/fail/panic/bad_miri_start_panic.rs | 2 +- tests/fail/panic/unwind_panic_abort.rs | 2 +- tests/fail/pointer_partial_overwrite.rs | 2 +- tests/fail/provenance/provenance_transmute.rs | 2 +- tests/fail/provenance/ptr_int_unexposed.rs | 2 +- .../fail/provenance/strict_provenance_cast.rs | 2 +- tests/fail/rc_as_ptr.rs | 2 +- tests/fail/shim_arg_size.rs | 2 +- tests/fail/stacked_borrows/exposed_only_ro.rs | 2 +- tests/fail/stacked_borrows/illegal_read5.rs | 2 +- .../illegal_read_despite_exposed1.rs | 2 +- .../illegal_read_despite_exposed2.rs | 2 +- .../illegal_write_despite_exposed1.rs | 2 +- .../fail/stacked_borrows/load_invalid_mut.rs | 2 +- .../fail/stacked_borrows/load_invalid_shr.rs | 2 +- .../shared_rw_borrows_are_weak2.rs | 2 +- tests/fail/stacked_borrows/unescaped_local.rs | 2 +- tests/fail/stacked_borrows/zst_slice.rs | 2 +- tests/fail/static_memory_modification1.rs | 2 +- tests/fail/static_memory_modification2.rs | 2 +- tests/fail/static_memory_modification3.rs | 2 +- .../sync/libc_pthread_cond_double_destroy.rs | 2 +- .../libc_pthread_condattr_double_destroy.rs | 2 +- .../sync/libc_pthread_mutex_NULL_deadlock.rs | 2 +- .../fail/sync/libc_pthread_mutex_deadlock.rs | 2 +- .../libc_pthread_mutex_default_deadlock.rs | 2 +- .../sync/libc_pthread_mutex_destroy_locked.rs | 2 +- .../sync/libc_pthread_mutex_double_destroy.rs | 2 +- .../libc_pthread_mutex_normal_deadlock.rs | 2 +- ...bc_pthread_mutex_normal_unlock_unlocked.rs | 2 +- .../sync/libc_pthread_mutex_wrong_owner.rs | 2 +- .../libc_pthread_mutexattr_double_destroy.rs | 2 +- ...libc_pthread_rwlock_destroy_read_locked.rs | 2 +- ...ibc_pthread_rwlock_destroy_write_locked.rs | 2 +- .../libc_pthread_rwlock_double_destroy.rs | 2 +- ...wlock_read_write_deadlock_single_thread.rs | 2 +- .../libc_pthread_rwlock_read_wrong_owner.rs | 2 +- .../libc_pthread_rwlock_unlock_unlocked.rs | 2 +- ...libc_pthread_rwlock_write_read_deadlock.rs | 2 +- ...wlock_write_read_deadlock_single_thread.rs | 2 +- ...ibc_pthread_rwlock_write_write_deadlock.rs | 2 +- ...lock_write_write_deadlock_single_thread.rs | 2 +- .../libc_pthread_rwlock_write_wrong_owner.rs | 2 +- tests/fail/type-too-large.rs | 2 +- tests/fail/unaligned_pointers/alignment.rs | 2 +- .../unaligned_pointers/atomic_unaligned.rs | 2 +- .../fail/unaligned_pointers/dyn_alignment.rs | 2 +- .../intptrcast_alignment_check.rs | 2 +- .../unaligned_pointers/reference_to_packed.rs | 2 +- .../fail/unaligned_pointers/unaligned_ptr1.rs | 2 +- .../fail/unaligned_pointers/unaligned_ptr2.rs | 2 +- .../fail/unaligned_pointers/unaligned_ptr3.rs | 2 +- .../fail/unaligned_pointers/unaligned_ptr4.rs | 2 +- .../unaligned_ptr_addr_of.rs | 2 +- .../unaligned_pointers/unaligned_ptr_zst.rs | 2 +- tests/fail/uninit_byte_read.rs | 2 +- tests/fail/unsupported_signal.rs | 2 +- tests/fail/validity/cast_fn_ptr1.rs | 2 +- tests/fail/validity/cast_fn_ptr2.rs | 2 +- tests/fail/validity/dangling_ref1.rs | 2 +- tests/fail/validity/dangling_ref2.rs | 2 +- tests/fail/validity/dangling_ref3.rs | 2 +- .../invalid_enum_tag_256variants_uninit.rs | 2 +- tests/fail/validity/nonzero.rs | 2 +- tests/fail/weak_memory/racing_mixed_size.rs | 2 +- .../weak_memory/racing_mixed_size_read.rs | 2 +- tests/fail/zst2.rs | 2 +- tests/fail/zst3.rs | 2 +- tests/panic/panic/panic1.rs | 4 +- .../panic/unsupported_foreign_function.rs | 2 +- tests/panic/panic/unsupported_syscall.rs | 6 +- tests/pass/0weak_memory_consistency.rs | 4 +- tests/pass/adjacent-allocs.rs | 2 +- tests/pass/align.rs | 2 +- tests/pass/align_offset_symbolic.rs | 2 +- ...atomic-compare-exchange-weak-never-fail.rs | 2 +- tests/pass/atomic.rs | 2 +- tests/pass/backtrace/backtrace-api-v0.rs | 2 +- tests/pass/backtrace/backtrace-api-v1.rs | 2 +- .../pass/backtrace/backtrace-global-alloc.rs | 2 +- tests/pass/backtrace/backtrace-std.rs | 2 +- tests/pass/btreemap.rs | 2 +- tests/pass/calloc.rs | 2 +- tests/pass/concurrency/channels.rs | 4 +- .../concurrency/concurrent_caller_location.rs | 2 +- tests/pass/concurrency/data_race.rs | 4 +- .../concurrency/disable_data_race_detector.rs | 4 +- tests/pass/concurrency/issue1643.rs | 2 +- tests/pass/concurrency/libc_pthread_cond.rs | 6 +- tests/pass/concurrency/linux-futex.rs | 4 +- tests/pass/concurrency/mutex_leak.rs | 2 +- tests/pass/concurrency/simple.rs | 4 +- tests/pass/concurrency/spin_loop.rs | 2 +- .../pass/concurrency/spin_loops_nopreempt.rs | 4 +- tests/pass/concurrency/sync.rs | 4 +- tests/pass/concurrency/sync_nopreempt.rs | 4 +- tests/pass/concurrency/thread_locals.rs | 4 +- tests/pass/concurrency/tls_lib_drop.rs | 2 +- .../concurrency/tls_pthread_drop_order.rs | 2 +- tests/pass/current_dir.rs | 2 +- tests/pass/current_dir_with_isolation.rs | 6 +- tests/pass/disable-alignment-check.rs | 2 +- tests/pass/enum_discriminant_ptr_value.rs | 2 +- tests/pass/env-exclude.rs | 2 +- tests/pass/env-forward.rs | 2 +- tests/pass/env-without-isolation.rs | 2 +- tests/pass/fs.rs | 4 +- tests/pass/fs_with_isolation.rs | 6 +- .../pass/function_calls/disable_abi_check.rs | 2 +- tests/pass/getpid.rs | 2 +- tests/pass/hide_stdout.rs | 2 +- tests/pass/integer-ops.rs | 2 +- tests/pass/intptrcast.rs | 2 +- tests/pass/intrinsics.rs | 2 +- tests/pass/issues/issue-miri-1925.rs | 2 +- tests/pass/issues/issue-miri-2068-2.rs | 2 +- tests/pass/libc.rs | 4 +- .../pass/linux-getrandom-without-isolation.rs | 4 +- tests/pass/linux-getrandom.rs | 2 +- tests/pass/malloc.rs | 2 +- tests/pass/memleak_ignored.rs | 2 +- tests/pass/move-uninit-primval.rs | 2 +- tests/pass/no_std.rs | 2 +- tests/pass/observed_local_mut.rs | 2 +- tests/pass/overflow_checks_off.rs | 2 +- tests/pass/panic/catch_panic.rs | 2 +- tests/pass/panic/concurrent-panic.rs | 4 +- tests/pass/portable-simd.rs | 2 +- tests/pass/ptr_int_casts.rs | 2 +- tests/pass/ptr_int_from_exposed.rs | 2 +- tests/pass/ptr_offset.rs | 2 +- tests/pass/rc.rs | 2 +- tests/pass/slices.rs | 2 +- tests/pass/stacked-borrows/int-to-ptr.rs | 2 +- .../stacked-borrows/interior_mutability.rs | 2 +- tests/pass/stacked-borrows/stacked-borrows.rs | 2 +- tests/pass/strings.rs | 2 +- tests/pass/threadleak_ignored.rs | 4 +- tests/pass/time.rs | 2 +- tests/pass/track-alloc-1.rs | 4 +- tests/pass/transmute_fat.rs | 2 +- tests/pass/uninit_number_ignored.rs | 2 +- tests/pass/vec.rs | 2 +- tests/pass/vecdeque.rs | 2 +- tests/pass/weak_memory/extra_cpp.rs | 4 +- tests/pass/weak_memory/extra_cpp_unsafe.rs | 4 +- tests/pass/weak_memory/weak.rs | 4 +- tests/pass/without-validation.rs | 2 +- tests/pass/wtf8.rs | 2 +- tests/pass/zst.rs | 2 +- ui_test/src/comments.rs | 80 +------------------ 221 files changed, 269 insertions(+), 345 deletions(-) diff --git a/tests/fail/box-cell-alias.rs b/tests/fail/box-cell-alias.rs index d3f505d2da5c..319845d86a63 100644 --- a/tests/fail/box-cell-alias.rs +++ b/tests/fail/box-cell-alias.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance +//@compile-flags: -Zmiri-strict-provenance // Taken from . diff --git a/tests/fail/concurrency/libc_pthread_join_detached.rs b/tests/fail/concurrency/libc_pthread_join_detached.rs index dcd06596de13..1ec1d630ecb9 100644 --- a/tests/fail/concurrency/libc_pthread_join_detached.rs +++ b/tests/fail/concurrency/libc_pthread_join_detached.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows // Joining a detached thread is undefined behavior. diff --git a/tests/fail/concurrency/libc_pthread_join_joined.rs b/tests/fail/concurrency/libc_pthread_join_joined.rs index 26f33f1f5f94..b067556e51b0 100644 --- a/tests/fail/concurrency/libc_pthread_join_joined.rs +++ b/tests/fail/concurrency/libc_pthread_join_joined.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows // Joining an already joined thread is undefined behavior. diff --git a/tests/fail/concurrency/libc_pthread_join_main.rs b/tests/fail/concurrency/libc_pthread_join_main.rs index 15e43776ab82..ebfe8c865e3d 100644 --- a/tests/fail/concurrency/libc_pthread_join_main.rs +++ b/tests/fail/concurrency/libc_pthread_join_main.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows // Joining the main thread is undefined behavior. diff --git a/tests/fail/concurrency/libc_pthread_join_multiple.rs b/tests/fail/concurrency/libc_pthread_join_multiple.rs index d86233a67643..39cd9ff77976 100644 --- a/tests/fail/concurrency/libc_pthread_join_multiple.rs +++ b/tests/fail/concurrency/libc_pthread_join_multiple.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows // Joining the same thread from multiple threads is undefined behavior. diff --git a/tests/fail/concurrency/libc_pthread_join_self.rs b/tests/fail/concurrency/libc_pthread_join_self.rs index db45b33c1468..7b91560ab6b1 100644 --- a/tests/fail/concurrency/libc_pthread_join_self.rs +++ b/tests/fail/concurrency/libc_pthread_join_self.rs @@ -1,6 +1,6 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows // We are making scheduler assumptions here. -// compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-preemption-rate=0 // Joining itself is undefined behavior. diff --git a/tests/fail/concurrency/thread_local_static_dealloc.rs b/tests/fail/concurrency/thread_local_static_dealloc.rs index e6031b5e4c0c..8cca1eba2d86 100644 --- a/tests/fail/concurrency/thread_local_static_dealloc.rs +++ b/tests/fail/concurrency/thread_local_static_dealloc.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. //! Ensure that thread-local statics get deallocated when the thread dies. diff --git a/tests/fail/concurrency/too_few_args.rs b/tests/fail/concurrency/too_few_args.rs index 23fa38d88128..5d173b384807 100644 --- a/tests/fail/concurrency/too_few_args.rs +++ b/tests/fail/concurrency/too_few_args.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. //! The thread function must have exactly one argument. diff --git a/tests/fail/concurrency/too_many_args.rs b/tests/fail/concurrency/too_many_args.rs index af5a377a04e4..8305765a37a3 100644 --- a/tests/fail/concurrency/too_many_args.rs +++ b/tests/fail/concurrency/too_many_args.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. //! The thread function must have exactly one argument. diff --git a/tests/fail/concurrency/unwind_top_of_stack.rs b/tests/fail/concurrency/unwind_top_of_stack.rs index 39f7ae8bafb9..d5dfcd0871d8 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.rs +++ b/tests/fail/concurrency/unwind_top_of_stack.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-abi-check +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-abi-check //! Unwinding past the top frame of a stack is Undefined Behavior. diff --git a/tests/fail/dangling_pointers/dangling_pointer_addr_of.rs b/tests/fail/dangling_pointers/dangling_pointer_addr_of.rs index 5de413871171..a38a44c18f47 100644 --- a/tests/fail/dangling_pointers/dangling_pointer_addr_of.rs +++ b/tests/fail/dangling_pointers/dangling_pointer_addr_of.rs @@ -1,5 +1,5 @@ // Make sure we find these even with many checks disabled. -// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation use std::ptr; fn main() { diff --git a/tests/fail/dangling_pointers/dangling_pointer_deref.rs b/tests/fail/dangling_pointers/dangling_pointer_deref.rs index e088a5532581..55b5205a8b30 100644 --- a/tests/fail/dangling_pointers/dangling_pointer_deref.rs +++ b/tests/fail/dangling_pointers/dangling_pointer_deref.rs @@ -1,5 +1,5 @@ // Make sure we find these even with many checks disabled. -// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation fn main() { let p = { diff --git a/tests/fail/dangling_pointers/dangling_zst_deref.rs b/tests/fail/dangling_pointers/dangling_zst_deref.rs index 01e864213df7..2a09dc4b0e89 100644 --- a/tests/fail/dangling_pointers/dangling_zst_deref.rs +++ b/tests/fail/dangling_pointers/dangling_zst_deref.rs @@ -1,6 +1,6 @@ // Make sure we find these even with many checks disabled. // Some optimizations remove ZST accesses, thus masking this UB. -// compile-flags: -Zmir-opt-level=0 -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +//@compile-flags: -Zmir-opt-level=0 -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation fn main() { let p = { diff --git a/tests/fail/dangling_pointers/deref-invalid-ptr.rs b/tests/fail/dangling_pointers/deref-invalid-ptr.rs index 31b52da774b0..924021e8cb93 100644 --- a/tests/fail/dangling_pointers/deref-invalid-ptr.rs +++ b/tests/fail/dangling_pointers/deref-invalid-ptr.rs @@ -1,5 +1,5 @@ // This should fail even without validation. -// compile-flags: -Zmiri-disable-validation -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-disable-validation -Zmiri-permissive-provenance fn main() { let x = 16usize as *const u32; diff --git a/tests/fail/dangling_pointers/dyn_size.rs b/tests/fail/dangling_pointers/dyn_size.rs index 56de3970f1bb..adb7febe5074 100644 --- a/tests/fail/dangling_pointers/dyn_size.rs +++ b/tests/fail/dangling_pointers/dyn_size.rs @@ -1,5 +1,5 @@ // should find the bug even without these, but gets masked by optimizations -// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Zmir-opt-level=0 +//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Zmir-opt-level=0 struct SliceWithHead(u8, [u8]); diff --git a/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.rs b/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.rs index 357eadf91c7f..37fb91e28f29 100644 --- a/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.rs +++ b/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.rs @@ -1,5 +1,5 @@ // Some optimizations remove ZST accesses, thus masking this UB. -// compile-flags: -Zmir-opt-level=0 +//@compile-flags: -Zmir-opt-level=0 fn main() { // This pointer *could* be NULL so we cannot load from it, not even at ZST diff --git a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs index 4a8d498aa1f5..de8034bbbac3 100644 --- a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs +++ b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs @@ -1,5 +1,5 @@ // Some optimizations remove ZST accesses, thus masking this UB. -// compile-flags: -Zmir-opt-level=0 +//@compile-flags: -Zmir-opt-level=0 fn main() { // This pointer *could* be NULL so we cannot load from it, not even at ZST. diff --git a/tests/fail/dangling_pointers/null_pointer_deref_zst.rs b/tests/fail/dangling_pointers/null_pointer_deref_zst.rs index 21b0ce37d8df..1f73983a8161 100644 --- a/tests/fail/dangling_pointers/null_pointer_deref_zst.rs +++ b/tests/fail/dangling_pointers/null_pointer_deref_zst.rs @@ -1,5 +1,5 @@ // Some optimizations remove ZST accesses, thus masking this UB. -// compile-flags: -Zmir-opt-level=0 +//@compile-flags: -Zmir-opt-level=0 #[allow(deref_nullptr)] fn main() { diff --git a/tests/fail/dangling_pointers/stack_temporary.rs b/tests/fail/dangling_pointers/stack_temporary.rs index cbd788bbf414..dc446ca4b3c8 100644 --- a/tests/fail/dangling_pointers/stack_temporary.rs +++ b/tests/fail/dangling_pointers/stack_temporary.rs @@ -1,5 +1,5 @@ // This should fail even without validation, but some MIR opts mask the error -// compile-flags: -Zmiri-disable-validation -Zmir-opt-level=0 +//@compile-flags: -Zmiri-disable-validation -Zmir-opt-level=0 unsafe fn make_ref<'a>(x: *mut i32) -> &'a mut i32 { &mut *x diff --git a/tests/fail/dangling_pointers/storage_dead_dangling.rs b/tests/fail/dangling_pointers/storage_dead_dangling.rs index 64ed37d15113..10c6e7f97d2e 100644 --- a/tests/fail/dangling_pointers/storage_dead_dangling.rs +++ b/tests/fail/dangling_pointers/storage_dead_dangling.rs @@ -1,5 +1,5 @@ // This should fail even without validation, but some MIR opts mask the error -// compile-flags: -Zmiri-disable-validation -Zmir-opt-level=0 -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-disable-validation -Zmir-opt-level=0 -Zmiri-permissive-provenance static mut LEAK: usize = 0; diff --git a/tests/fail/dangling_pointers/wild_pointer_deref.rs b/tests/fail/dangling_pointers/wild_pointer_deref.rs index 9f6b370c050f..15d71a6bcccd 100644 --- a/tests/fail/dangling_pointers/wild_pointer_deref.rs +++ b/tests/fail/dangling_pointers/wild_pointer_deref.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance fn main() { let p = 44 as *const i32; diff --git a/tests/fail/data_race/alloc_read_race.rs b/tests/fail/data_race/alloc_read_race.rs index 1eac8ce0f26c..e3c003a343a0 100644 --- a/tests/fail/data_race/alloc_read_race.rs +++ b/tests/fail/data_race/alloc_read_race.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 #![feature(new_uninit)] use std::mem::MaybeUninit; diff --git a/tests/fail/data_race/alloc_write_race.rs b/tests/fail/data_race/alloc_write_race.rs index e618b72a8227..4ad03ee87dda 100644 --- a/tests/fail/data_race/alloc_write_race.rs +++ b/tests/fail/data_race/alloc_write_race.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 #![feature(new_uninit)] use std::ptr::null_mut; diff --git a/tests/fail/data_race/atomic_read_na_write_race1.rs b/tests/fail/data_race/atomic_read_na_write_race1.rs index 3b948eea9805..71d7a66597d1 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.rs +++ b/tests/fail/data_race/atomic_read_na_write_race1.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] use std::intrinsics; diff --git a/tests/fail/data_race/atomic_read_na_write_race2.rs b/tests/fail/data_race/atomic_read_na_write_race2.rs index 44b4eebee805..a490f47da7c3 100644 --- a/tests/fail/data_race/atomic_read_na_write_race2.rs +++ b/tests/fail/data_race/atomic_read_na_write_race2.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; diff --git a/tests/fail/data_race/atomic_write_na_read_race1.rs b/tests/fail/data_race/atomic_write_na_read_race1.rs index 44dc1a908416..40066d91b1ff 100644 --- a/tests/fail/data_race/atomic_write_na_read_race1.rs +++ b/tests/fail/data_race/atomic_write_na_read_race1.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; diff --git a/tests/fail/data_race/atomic_write_na_read_race2.rs b/tests/fail/data_race/atomic_write_na_read_race2.rs index b4b21b64fc1f..0bfadcba3ed3 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.rs +++ b/tests/fail/data_race/atomic_write_na_read_race2.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] use std::intrinsics::atomic_store; diff --git a/tests/fail/data_race/atomic_write_na_write_race1.rs b/tests/fail/data_race/atomic_write_na_write_race1.rs index b1a4cfb98bd1..258f5dd142ef 100644 --- a/tests/fail/data_race/atomic_write_na_write_race1.rs +++ b/tests/fail/data_race/atomic_write_na_write_race1.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] use std::intrinsics::atomic_store; diff --git a/tests/fail/data_race/atomic_write_na_write_race2.rs b/tests/fail/data_race/atomic_write_na_write_race2.rs index dbdce8f6237c..51068262d588 100644 --- a/tests/fail/data_race/atomic_write_na_write_race2.rs +++ b/tests/fail/data_race/atomic_write_na_write_race2.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; diff --git a/tests/fail/data_race/dangling_thread_async_race.rs b/tests/fail/data_race/dangling_thread_async_race.rs index 65325b60f2f3..7bb20adfcd5f 100644 --- a/tests/fail/data_race/dangling_thread_async_race.rs +++ b/tests/fail/data_race/dangling_thread_async_race.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-isolation use std::mem; use std::thread::{sleep, spawn}; diff --git a/tests/fail/data_race/dangling_thread_race.rs b/tests/fail/data_race/dangling_thread_race.rs index 09e7032c9330..7e198eef6e94 100644 --- a/tests/fail/data_race/dangling_thread_race.rs +++ b/tests/fail/data_race/dangling_thread_race.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-isolation use std::mem; use std::thread::{sleep, spawn}; diff --git a/tests/fail/data_race/dealloc_read_race1.rs b/tests/fail/data_race/dealloc_read_race1.rs index ff2ac8ca522a..634904cbfdce 100644 --- a/tests/fail/data_race/dealloc_read_race1.rs +++ b/tests/fail/data_race/dealloc_read_race1.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_read_race2.rs b/tests/fail/data_race/dealloc_read_race2.rs index 4bb6444f6a62..91ec3c2bd872 100644 --- a/tests/fail/data_race/dealloc_read_race2.rs +++ b/tests/fail/data_race/dealloc_read_race2.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_read_race_stack.rs b/tests/fail/data_race/dealloc_read_race_stack.rs index e079581a0d89..a43c96a6701e 100644 --- a/tests/fail/data_race/dealloc_read_race_stack.rs +++ b/tests/fail/data_race/dealloc_read_race_stack.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::ptr::null_mut; use std::sync::atomic::{AtomicPtr, Ordering}; diff --git a/tests/fail/data_race/dealloc_write_race1.rs b/tests/fail/data_race/dealloc_write_race1.rs index 9cd0ebc64252..f95a9be17274 100644 --- a/tests/fail/data_race/dealloc_write_race1.rs +++ b/tests/fail/data_race/dealloc_write_race1.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_write_race2.rs b/tests/fail/data_race/dealloc_write_race2.rs index 9b1b8f061475..922738354fb0 100644 --- a/tests/fail/data_race/dealloc_write_race2.rs +++ b/tests/fail/data_race/dealloc_write_race2.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_write_race_stack.rs b/tests/fail/data_race/dealloc_write_race_stack.rs index 2f1257089273..6b87cbe61cad 100644 --- a/tests/fail/data_race/dealloc_write_race_stack.rs +++ b/tests/fail/data_race/dealloc_write_race_stack.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::ptr::null_mut; use std::sync::atomic::{AtomicPtr, Ordering}; diff --git a/tests/fail/data_race/enable_after_join_to_main.rs b/tests/fail/data_race/enable_after_join_to_main.rs index 6f0735fac897..757a41adc932 100644 --- a/tests/fail/data_race/enable_after_join_to_main.rs +++ b/tests/fail/data_race/enable_after_join_to_main.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/fence_after_load.rs b/tests/fail/data_race/fence_after_load.rs index 5a8c2e585f49..7a8d66bf8f29 100644 --- a/tests/fail/data_race/fence_after_load.rs +++ b/tests/fail/data_race/fence_after_load.rs @@ -1,6 +1,6 @@ // We want to control preemption here. -// compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 -// ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 +//@ignore-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::{fence, AtomicUsize, Ordering}; use std::sync::Arc; use std::thread; diff --git a/tests/fail/data_race/read_write_race.rs b/tests/fail/data_race/read_write_race.rs index eeb49bb42ab7..cffbba1a70f3 100644 --- a/tests/fail/data_race/read_write_race.rs +++ b/tests/fail/data_race/read_write_race.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/read_write_race_stack.rs b/tests/fail/data_race/read_write_race_stack.rs index 124f12d1ecd2..3999c57bcf42 100644 --- a/tests/fail/data_race/read_write_race_stack.rs +++ b/tests/fail/data_race/read_write_race_stack.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 // Note: mir-opt-level set to 0 to prevent the read of stack_var in thread 1 // from being optimized away and preventing the detection of the data-race. diff --git a/tests/fail/data_race/relax_acquire_race.rs b/tests/fail/data_race/relax_acquire_race.rs index faa23a150e3f..3038efe99efa 100644 --- a/tests/fail/data_race/relax_acquire_race.rs +++ b/tests/fail/data_race/relax_acquire_race.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/tests/fail/data_race/release_seq_race.rs b/tests/fail/data_race/release_seq_race.rs index ab6926102a2a..ca227bf5ad29 100644 --- a/tests/fail/data_race/release_seq_race.rs +++ b/tests/fail/data_race/release_seq_race.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::{sleep, spawn}; diff --git a/tests/fail/data_race/release_seq_race_same_thread.rs b/tests/fail/data_race/release_seq_race_same_thread.rs index d3d18f0e2540..c9b0cd7773ef 100644 --- a/tests/fail/data_race/release_seq_race_same_thread.rs +++ b/tests/fail/data_race/release_seq_race_same_thread.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/tests/fail/data_race/rmw_race.rs b/tests/fail/data_race/rmw_race.rs index 800b1043c00b..ca8123177ab3 100644 --- a/tests/fail/data_race/rmw_race.rs +++ b/tests/fail/data_race/rmw_race.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/tests/fail/data_race/stack_pop_race.rs b/tests/fail/data_race/stack_pop_race.rs index bae885600142..a31c434604bb 100644 --- a/tests/fail/data_race/stack_pop_race.rs +++ b/tests/fail/data_race/stack_pop_race.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-preemption-rate=0 +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-preemption-rate=0 use std::thread; #[derive(Copy, Clone)] diff --git a/tests/fail/data_race/write_write_race.rs b/tests/fail/data_race/write_write_race.rs index 989ae31a6d28..ddd710bce08d 100644 --- a/tests/fail/data_race/write_write_race.rs +++ b/tests/fail/data_race/write_write_race.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/write_write_race_stack.rs b/tests/fail/data_race/write_write_race_stack.rs index 3c1eabbf251b..96b40affaed0 100644 --- a/tests/fail/data_race/write_write_race_stack.rs +++ b/tests/fail/data_race/write_write_race_stack.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::ptr::null_mut; use std::sync::atomic::{AtomicPtr, Ordering}; diff --git a/tests/fail/environ-gets-deallocated.rs b/tests/fail/environ-gets-deallocated.rs index f50a66e2c766..34941b944923 100644 --- a/tests/fail/environ-gets-deallocated.rs +++ b/tests/fail/environ-gets-deallocated.rs @@ -1,4 +1,4 @@ -// ignore-windows: Windows does not have a global environ list that the program can access directly +//@ignore-windows: Windows does not have a global environ list that the program can access directly #[cfg(any(target_os = "linux", target_os = "freebsd"))] fn get_environ() -> *const *const u8 { diff --git a/tests/fail/erroneous_const.rs b/tests/fail/erroneous_const.rs index 8975694f51cc..ce1392d102b7 100644 --- a/tests/fail/erroneous_const.rs +++ b/tests/fail/erroneous_const.rs @@ -1,7 +1,7 @@ //! Make sure we detect erroneous constants post-monomorphization even when they are unused. //! (https://github.com/rust-lang/miri/issues/1382) // Inlining changes the error location -// compile-flags: -Zmir-opt-level=0 +//@compile-flags: -Zmir-opt-level=0 #![feature(never_type)] #![warn(warnings, const_err)] diff --git a/tests/fail/fs/close_stdout.rs b/tests/fail/fs/close_stdout.rs index 4f10d5e0c990..273701112877 100644 --- a/tests/fail/fs/close_stdout.rs +++ b/tests/fail/fs/close_stdout.rs @@ -1,5 +1,5 @@ -// ignore-windows: No libc on Windows -// compile-flags: -Zmiri-disable-isolation +//@ignore-windows: No libc on Windows +//@compile-flags: -Zmiri-disable-isolation // FIXME: standard handles cannot be closed (https://github.com/rust-lang/rust/issues/40032) diff --git a/tests/fail/fs/isolated_stdin.rs b/tests/fail/fs/isolated_stdin.rs index 4098a104761e..b41534c5c3a8 100644 --- a/tests/fail/fs/isolated_stdin.rs +++ b/tests/fail/fs/isolated_stdin.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/fs/read_from_stdout.rs b/tests/fail/fs/read_from_stdout.rs index 17f1735f6ade..4862bf0a162c 100644 --- a/tests/fail/fs/read_from_stdout.rs +++ b/tests/fail/fs/read_from_stdout.rs @@ -1,5 +1,5 @@ -// compile-flags: -Zmiri-disable-isolation -// ignore-windows: No libc on Windows +//@compile-flags: -Zmiri-disable-isolation +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/fs/unix_open_missing_required_mode.rs b/tests/fail/fs/unix_open_missing_required_mode.rs index bd2ae6094be1..e714d26e7835 100644 --- a/tests/fail/fs/unix_open_missing_required_mode.rs +++ b/tests/fail/fs/unix_open_missing_required_mode.rs @@ -1,5 +1,5 @@ -// ignore-windows: No libc on Windows -// compile-flags: -Zmiri-disable-isolation +//@ignore-windows: No libc on Windows +//@compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] diff --git a/tests/fail/fs/write_to_stdin.rs b/tests/fail/fs/write_to_stdin.rs index c2754636c860..9d55a60b64b8 100644 --- a/tests/fail/fs/write_to_stdin.rs +++ b/tests/fail/fs/write_to_stdin.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/function_calls/exported_symbol_abi_mismatch.rs b/tests/fail/function_calls/exported_symbol_abi_mismatch.rs index c337e1f29f16..e7372d5ec50a 100644 --- a/tests/fail/function_calls/exported_symbol_abi_mismatch.rs +++ b/tests/fail/function_calls/exported_symbol_abi_mismatch.rs @@ -1,4 +1,4 @@ -// revisions: no_cache cache fn_ptr +//@revisions: no_cache cache fn_ptr #[no_mangle] fn foo() {} diff --git a/tests/fail/function_calls/exported_symbol_bad_unwind1.rs b/tests/fail/function_calls/exported_symbol_bad_unwind1.rs index 91b0e8fc03f2..0a5636138d80 100644 --- a/tests/fail/function_calls/exported_symbol_bad_unwind1.rs +++ b/tests/fail/function_calls/exported_symbol_bad_unwind1.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-disable-abi-check +//@compile-flags: -Zmiri-disable-abi-check #![feature(c_unwind)] #[no_mangle] diff --git a/tests/fail/function_calls/exported_symbol_bad_unwind2.rs b/tests/fail/function_calls/exported_symbol_bad_unwind2.rs index e80a79d1028d..861789f862e6 100644 --- a/tests/fail/function_calls/exported_symbol_bad_unwind2.rs +++ b/tests/fail/function_calls/exported_symbol_bad_unwind2.rs @@ -1,4 +1,4 @@ -// revisions: extern_block definition both +//@revisions: extern_block definition both #![feature(rustc_attrs, c_unwind)] #[cfg_attr(any(definition, both), rustc_allocator_nounwind)] diff --git a/tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs b/tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs index f7640cadcbcf..6edf88a543de 100644 --- a/tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs +++ b/tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-validation fn main() { let b = Box::new(42); diff --git a/tests/fail/function_pointers/cast_int_to_fn_ptr.rs b/tests/fail/function_pointers/cast_int_to_fn_ptr.rs index e287533ffc74..272376307d7c 100644 --- a/tests/fail/function_pointers/cast_int_to_fn_ptr.rs +++ b/tests/fail/function_pointers/cast_int_to_fn_ptr.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-validation fn main() { let g = unsafe { std::mem::transmute::(42) }; diff --git a/tests/fail/function_pointers/execute_memory.rs b/tests/fail/function_pointers/execute_memory.rs index 2e6b58a753cd..0ca29a3594e5 100644 --- a/tests/fail/function_pointers/execute_memory.rs +++ b/tests/fail/function_pointers/execute_memory.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-validation #![feature(box_syntax)] diff --git a/tests/fail/function_pointers/fn_ptr_offset.rs b/tests/fail/function_pointers/fn_ptr_offset.rs index 04c54c015922..5f269760f110 100644 --- a/tests/fail/function_pointers/fn_ptr_offset.rs +++ b/tests/fail/function_pointers/fn_ptr_offset.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-validation use std::mem; diff --git a/tests/fail/generator-pinned-moved.rs b/tests/fail/generator-pinned-moved.rs index 8c8e82847004..915dcdea82e4 100644 --- a/tests/fail/generator-pinned-moved.rs +++ b/tests/fail/generator-pinned-moved.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-validation #![feature(generators, generator_trait)] use std::{ diff --git a/tests/fail/invalid_bool.rs b/tests/fail/invalid_bool.rs index c0c982b8ca21..b2052d982ed8 100644 --- a/tests/fail/invalid_bool.rs +++ b/tests/fail/invalid_bool.rs @@ -1,6 +1,6 @@ // Validation makes this fail in the wrong place // Make sure we find these even with many checks disabled. -// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation #![feature(bench_black_box)] fn main() { diff --git a/tests/fail/invalid_char.rs b/tests/fail/invalid_char.rs index 9d485b73f246..8d814fd92e0c 100644 --- a/tests/fail/invalid_char.rs +++ b/tests/fail/invalid_char.rs @@ -1,6 +1,6 @@ // Validation makes this fail in the wrong place // Make sure we find these even with many checks disabled. -// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation fn main() { let c = 0xFFFFFFu32; diff --git a/tests/fail/invalid_int.rs b/tests/fail/invalid_int.rs index 26a85802079b..6914c66faec3 100644 --- a/tests/fail/invalid_int.rs +++ b/tests/fail/invalid_int.rs @@ -1,6 +1,6 @@ // Validation makes this fail in the wrong place // Make sure we find these even with many checks disabled. -// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation fn main() { let i = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; diff --git a/tests/fail/modifying_constants.rs b/tests/fail/modifying_constants.rs index 0c884142bf1d..3c47661a4b2d 100644 --- a/tests/fail/modifying_constants.rs +++ b/tests/fail/modifying_constants.rs @@ -1,5 +1,5 @@ // This should fail even without validation/SB -// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { let x = &1; // the `&1` is promoted to a constant, but it used to be that only the pointer is marked static, not the pointee diff --git a/tests/fail/never_say_never.rs b/tests/fail/never_say_never.rs index 7aae8a29211e..6beaada56e9a 100644 --- a/tests/fail/never_say_never.rs +++ b/tests/fail/never_say_never.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-validation #![feature(never_type)] #![allow(unreachable_code)] diff --git a/tests/fail/never_transmute_humans.rs b/tests/fail/never_transmute_humans.rs index 8a7d7bfcc682..010c9d4146d8 100644 --- a/tests/fail/never_transmute_humans.rs +++ b/tests/fail/never_transmute_humans.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-validation #![feature(never_type)] diff --git a/tests/fail/never_transmute_void.rs b/tests/fail/never_transmute_void.rs index f5d0f914dac7..d9c34aa7a5ca 100644 --- a/tests/fail/never_transmute_void.rs +++ b/tests/fail/never_transmute_void.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-validation #![feature(never_type)] #![allow(unused, invalid_value)] diff --git a/tests/fail/panic/bad_miri_start_panic.rs b/tests/fail/panic/bad_miri_start_panic.rs index 089cd86f1b8f..9beeccd1d220 100644 --- a/tests/fail/panic/bad_miri_start_panic.rs +++ b/tests/fail/panic/bad_miri_start_panic.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-disable-abi-check +//@compile-flags: -Zmiri-disable-abi-check // This feature is required to trigger the error using the "C" ABI. #![feature(c_unwind)] diff --git a/tests/fail/panic/unwind_panic_abort.rs b/tests/fail/panic/unwind_panic_abort.rs index 6afcd7ae7ff1..40dcf1bc2a3a 100644 --- a/tests/fail/panic/unwind_panic_abort.rs +++ b/tests/fail/panic/unwind_panic_abort.rs @@ -1,4 +1,4 @@ -// compile-flags: -Cpanic=abort +//@compile-flags: -Cpanic=abort //! Unwinding despite `-C panic=abort` is an error. diff --git a/tests/fail/pointer_partial_overwrite.rs b/tests/fail/pointer_partial_overwrite.rs index 1bbb33aa2bbd..95af3569f35b 100644 --- a/tests/fail/pointer_partial_overwrite.rs +++ b/tests/fail/pointer_partial_overwrite.rs @@ -1,5 +1,5 @@ // Make sure we find these even with many checks disabled. -// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation // Test what happens when we overwrite parts of a pointer. // Also see . diff --git a/tests/fail/provenance/provenance_transmute.rs b/tests/fail/provenance/provenance_transmute.rs index 28e6ba623080..90208c88d694 100644 --- a/tests/fail/provenance/provenance_transmute.rs +++ b/tests/fail/provenance/provenance_transmute.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance #![feature(strict_provenance)] use std::mem; diff --git a/tests/fail/provenance/ptr_int_unexposed.rs b/tests/fail/provenance/ptr_int_unexposed.rs index ad29d38dc3f7..5522aa33c741 100644 --- a/tests/fail/provenance/ptr_int_unexposed.rs +++ b/tests/fail/provenance/ptr_int_unexposed.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance #![feature(strict_provenance)] fn main() { diff --git a/tests/fail/provenance/strict_provenance_cast.rs b/tests/fail/provenance/strict_provenance_cast.rs index 968c4dfded37..bca7ea90a31d 100644 --- a/tests/fail/provenance/strict_provenance_cast.rs +++ b/tests/fail/provenance/strict_provenance_cast.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance +//@compile-flags: -Zmiri-strict-provenance fn main() { let addr = &0 as *const i32 as usize; diff --git a/tests/fail/rc_as_ptr.rs b/tests/fail/rc_as_ptr.rs index 049330ef363c..9aafa2628425 100644 --- a/tests/fail/rc_as_ptr.rs +++ b/tests/fail/rc_as_ptr.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-validation use std::ptr; use std::rc::{Rc, Weak}; diff --git a/tests/fail/shim_arg_size.rs b/tests/fail/shim_arg_size.rs index 37557de0a5e4..d1ffdf8cddb4 100644 --- a/tests/fail/shim_arg_size.rs +++ b/tests/fail/shim_arg_size.rs @@ -1,4 +1,4 @@ -// stderr-per-bitwidth +//@stderr-per-bitwidth fn main() { extern "C" { diff --git a/tests/fail/stacked_borrows/exposed_only_ro.rs b/tests/fail/stacked_borrows/exposed_only_ro.rs index 9b4234499df0..f2fdc213b143 100644 --- a/tests/fail/stacked_borrows/exposed_only_ro.rs +++ b/tests/fail/stacked_borrows/exposed_only_ro.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance #![feature(strict_provenance)] // If we have only exposed read-only pointers, doing a write through a wildcard ptr should fail. diff --git a/tests/fail/stacked_borrows/illegal_read5.rs b/tests/fail/stacked_borrows/illegal_read5.rs index 71af84e5b5f5..8f86a4f0a6b5 100644 --- a/tests/fail/stacked_borrows/illegal_read5.rs +++ b/tests/fail/stacked_borrows/illegal_read5.rs @@ -1,6 +1,6 @@ // We *can* have aliasing &RefCell and &mut T, but we cannot read through the former. // Else we couldn't optimize based on the assumption that `xref` below is truly unique. -// normalize-stderr-test: "0x[0-9a-fA-F]+" -> "$$HEX" +//@normalize-stderr-test: "0x[0-9a-fA-F]+" -> "$$HEX" use std::cell::RefCell; use std::{mem, ptr}; diff --git a/tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs b/tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs index 61a5e05d34cd..d779d4e44657 100644 --- a/tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs +++ b/tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance fn main() { unsafe { diff --git a/tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs b/tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs index 19d0784591e4..20b44e9e027b 100644 --- a/tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs +++ b/tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance fn main() { unsafe { diff --git a/tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs b/tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs index b50399b9df52..f14fcb14793c 100644 --- a/tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs +++ b/tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance fn main() { unsafe { diff --git a/tests/fail/stacked_borrows/load_invalid_mut.rs b/tests/fail/stacked_borrows/load_invalid_mut.rs index c2c4ce6726df..f0ae77f86101 100644 --- a/tests/fail/stacked_borrows/load_invalid_mut.rs +++ b/tests/fail/stacked_borrows/load_invalid_mut.rs @@ -1,5 +1,5 @@ // Make sure we catch this even without validation -// compile-flags: -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-validation // Make sure that we cannot load from memory a `&mut` that got already invalidated. fn main() { diff --git a/tests/fail/stacked_borrows/load_invalid_shr.rs b/tests/fail/stacked_borrows/load_invalid_shr.rs index 7d681f649a10..36ffef656e7f 100644 --- a/tests/fail/stacked_borrows/load_invalid_shr.rs +++ b/tests/fail/stacked_borrows/load_invalid_shr.rs @@ -1,5 +1,5 @@ // Make sure we catch this even without validation -// compile-flags: -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-validation // Make sure that we cannot load from memory a `&` that got already invalidated. fn main() { diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs index 07163456cebe..2fc05c2bf4cc 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs @@ -1,7 +1,7 @@ // We want to test that granting a SharedReadWrite will be added // *below* an already granted SharedReadWrite -- so writing to // the SharedReadWrite will invalidate the SharedReadWrite. -// normalize-stderr-test: "0x[0-9a-fA-F]+" -> "$$HEX" +//@normalize-stderr-test: "0x[0-9a-fA-F]+" -> "$$HEX" use std::cell::RefCell; use std::mem; diff --git a/tests/fail/stacked_borrows/unescaped_local.rs b/tests/fail/stacked_borrows/unescaped_local.rs index c994f6c3818a..e6cd8f09b1ad 100644 --- a/tests/fail/stacked_borrows/unescaped_local.rs +++ b/tests/fail/stacked_borrows/unescaped_local.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance // Make sure we cannot use raw ptrs to access a local that // we took the direct address of. diff --git a/tests/fail/stacked_borrows/zst_slice.rs b/tests/fail/stacked_borrows/zst_slice.rs index 336b1041df09..3e27f514bc88 100644 --- a/tests/fail/stacked_borrows/zst_slice.rs +++ b/tests/fail/stacked_borrows/zst_slice.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance +//@compile-flags: -Zmiri-strict-provenance //@error-pattern: does not exist in the borrow stack fn main() { diff --git a/tests/fail/static_memory_modification1.rs b/tests/fail/static_memory_modification1.rs index 6284fec1601a..38e8af4c4f1a 100644 --- a/tests/fail/static_memory_modification1.rs +++ b/tests/fail/static_memory_modification1.rs @@ -1,5 +1,5 @@ // Stacked Borrows detects that we are casting & to &mut and so it changes why we fail -// compile-flags: -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-stacked-borrows static X: usize = 5; diff --git a/tests/fail/static_memory_modification2.rs b/tests/fail/static_memory_modification2.rs index 558070d8a791..2e9d123c6d39 100644 --- a/tests/fail/static_memory_modification2.rs +++ b/tests/fail/static_memory_modification2.rs @@ -1,5 +1,5 @@ // Stacked Borrows detects that we are casting & to &mut and so it changes why we fail -// compile-flags: -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-stacked-borrows use std::mem::transmute; diff --git a/tests/fail/static_memory_modification3.rs b/tests/fail/static_memory_modification3.rs index 93df1c594534..34ccd13c429d 100644 --- a/tests/fail/static_memory_modification3.rs +++ b/tests/fail/static_memory_modification3.rs @@ -1,5 +1,5 @@ // Stacked Borrows detects that we are casting & to &mut and so it changes why we fail -// compile-flags: -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-stacked-borrows use std::mem::transmute; diff --git a/tests/fail/sync/libc_pthread_cond_double_destroy.rs b/tests/fail/sync/libc_pthread_cond_double_destroy.rs index 18be75b308cf..d358b3d4f631 100644 --- a/tests/fail/sync/libc_pthread_cond_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_cond_double_destroy.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] /// Test that destroying a pthread_cond twice fails, even without a check for number validity diff --git a/tests/fail/sync/libc_pthread_condattr_double_destroy.rs b/tests/fail/sync/libc_pthread_condattr_double_destroy.rs index 1543a5841ad2..bf6b038a212f 100644 --- a/tests/fail/sync/libc_pthread_condattr_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_condattr_double_destroy.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] /// Test that destroying a pthread_condattr twice fails, even without a check for number validity diff --git a/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs index 3a737b2e3e15..22dd656023b7 100644 --- a/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows // // Check that if we pass NULL attribute, then we get the default mutex type. diff --git a/tests/fail/sync/libc_pthread_mutex_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_deadlock.rs index 5d04635a36c8..597d7721b12d 100644 --- a/tests/fail/sync/libc_pthread_mutex_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_deadlock.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs index 0f6f570d70b0..e34dfe5e367e 100644 --- a/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows // // Check that if we do not set the mutex type, it is the default. diff --git a/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs b/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs index 85a37db341fa..ada3d311134d 100644 --- a/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs +++ b/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_mutex_double_destroy.rs b/tests/fail/sync/libc_pthread_mutex_double_destroy.rs index 3710810cd2c3..4cf006437b39 100644 --- a/tests/fail/sync/libc_pthread_mutex_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_mutex_double_destroy.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] /// Test that destroying a pthread_mutex twice fails, even without a check for number validity diff --git a/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs index 7e29a41920ea..8ecad494cfee 100644 --- a/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs index 1f1a2ef34b72..0109907a1186 100644 --- a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs +++ b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_mutex_wrong_owner.rs b/tests/fail/sync/libc_pthread_mutex_wrong_owner.rs index d69929d4ed46..d91245104b0e 100644 --- a/tests/fail/sync/libc_pthread_mutex_wrong_owner.rs +++ b/tests/fail/sync/libc_pthread_mutex_wrong_owner.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs b/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs index c232780ee2ea..ffa786b65893 100644 --- a/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] /// Test that destroying a pthread_mutexattr twice fails, even without a check for number validity diff --git a/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs b/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs index 8750a7388fca..6a9f548d1a30 100644 --- a/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs +++ b/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs b/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs index aecccfa50310..5f5f16d2cf0e 100644 --- a/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs +++ b/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs b/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs index 055bb1af489f..1ba89fb22cf3 100644 --- a/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] /// Test that destroying a pthread_rwlock twice fails, even without a check for number validity diff --git a/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs index dd4707d60e4c..9c8d22310cab 100644 --- a/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs +++ b/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs b/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs index a73a8496a329..361cc7cdd850 100644 --- a/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs +++ b/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs b/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs index 8b3de53828df..7918a9665a03 100644 --- a/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs +++ b/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs index 19dce431c8b1..3158b944a7f7 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs index 1b460e7174d2..c6b468eb89b1 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs index 098c1c2fe26c..91adaf85499f 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs index cc327ec46bc2..13a7ceefc7bb 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs b/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs index 663dedb6f6fc..a205bbcb6b55 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/type-too-large.rs b/tests/fail/type-too-large.rs index 08f7a49b0255..932964ebdd7b 100644 --- a/tests/fail/type-too-large.rs +++ b/tests/fail/type-too-large.rs @@ -1,4 +1,4 @@ -// ignore-32bit +//@ignore-32bit fn main() { let _fat: [u8; (1 << 61) + (1 << 31)]; diff --git a/tests/fail/unaligned_pointers/alignment.rs b/tests/fail/unaligned_pointers/alignment.rs index abee75ec71b1..438e74e5b8d5 100644 --- a/tests/fail/unaligned_pointers/alignment.rs +++ b/tests/fail/unaligned_pointers/alignment.rs @@ -1,4 +1,4 @@ -// normalize-stderr-test: "\| +\^+" -> "| ^" +//@normalize-stderr-test: "\| +\^+" -> "| ^" fn main() { // No retry needed, this fails reliably. diff --git a/tests/fail/unaligned_pointers/atomic_unaligned.rs b/tests/fail/unaligned_pointers/atomic_unaligned.rs index 74dd0b415c93..68b0efdbfeb4 100644 --- a/tests/fail/unaligned_pointers/atomic_unaligned.rs +++ b/tests/fail/unaligned_pointers/atomic_unaligned.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-symbolic-alignment-check +//@compile-flags: -Zmiri-symbolic-alignment-check #![feature(core_intrinsics)] fn main() { diff --git a/tests/fail/unaligned_pointers/dyn_alignment.rs b/tests/fail/unaligned_pointers/dyn_alignment.rs index 730dd87cbb10..fe9c39523029 100644 --- a/tests/fail/unaligned_pointers/dyn_alignment.rs +++ b/tests/fail/unaligned_pointers/dyn_alignment.rs @@ -1,5 +1,5 @@ // should find the bug even without validation and stacked borrows, but gets masked by optimizations -// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Zmir-opt-level=0 +//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Zmir-opt-level=0 #[repr(align(256))] #[derive(Debug)] diff --git a/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs b/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs index dea9335ab751..172461424ec0 100644 --- a/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs +++ b/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-symbolic-alignment-check -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-symbolic-alignment-check -Zmiri-permissive-provenance // With the symbolic alignment check, even with intptrcast and without // validation, we want to be *sure* to catch bugs that arise from pointers being // insufficiently aligned. The only way to achieve that is not not let programs diff --git a/tests/fail/unaligned_pointers/reference_to_packed.rs b/tests/fail/unaligned_pointers/reference_to_packed.rs index c42f0e27aead..b4659805745a 100644 --- a/tests/fail/unaligned_pointers/reference_to_packed.rs +++ b/tests/fail/unaligned_pointers/reference_to_packed.rs @@ -1,5 +1,5 @@ // This should fail even without validation/SB -// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows #![allow(dead_code, unused_variables, unaligned_references)] diff --git a/tests/fail/unaligned_pointers/unaligned_ptr1.rs b/tests/fail/unaligned_pointers/unaligned_ptr1.rs index 7d192e5d3928..a3b483281139 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr1.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr1.rs @@ -1,5 +1,5 @@ // This should fail even without validation or Stacked Borrows. -// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { // Try many times as this might work by chance. diff --git a/tests/fail/unaligned_pointers/unaligned_ptr2.rs b/tests/fail/unaligned_pointers/unaligned_ptr2.rs index 49612e2b8a09..88fcd30278d7 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr2.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr2.rs @@ -1,5 +1,5 @@ // This should fail even without validation or Stacked Borrows. -// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { // No retry needed, this fails reliably. diff --git a/tests/fail/unaligned_pointers/unaligned_ptr3.rs b/tests/fail/unaligned_pointers/unaligned_ptr3.rs index 748a31681a78..3a4b1497ae6b 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr3.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr3.rs @@ -1,5 +1,5 @@ // This should fail even without validation or Stacked Borrows. -// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { // Try many times as this might work by chance. diff --git a/tests/fail/unaligned_pointers/unaligned_ptr4.rs b/tests/fail/unaligned_pointers/unaligned_ptr4.rs index d01cabfa31cc..659fbf1470ce 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr4.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr4.rs @@ -1,5 +1,5 @@ // This should fail even without validation or Stacked Borrows. -// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { // Make sure we notice when a u16 is loaded at offset 1 into a u8 allocation. diff --git a/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs b/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs index dff92d56d70e..28a58556eb39 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs @@ -1,5 +1,5 @@ // This should fail even without validation or Stacked Borrows. -// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows use std::ptr; fn main() { diff --git a/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs b/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs index 8252ea83c870..26c315d34bf5 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs @@ -1,6 +1,6 @@ // This should fail even without validation // Some optimizations remove ZST accesses, thus masking this UB. -// compile-flags: -Zmir-opt-level=0 -Zmiri-disable-validation +//@compile-flags: -Zmir-opt-level=0 -Zmiri-disable-validation fn main() { // Try many times as this might work by chance. diff --git a/tests/fail/uninit_byte_read.rs b/tests/fail/uninit_byte_read.rs index 683088e78bff..e08d34d13856 100644 --- a/tests/fail/uninit_byte_read.rs +++ b/tests/fail/uninit_byte_read.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-stacked-borrows fn main() { let v: Vec = Vec::with_capacity(10); let undef = unsafe { *v.get_unchecked(5) }; //~ ERROR uninitialized diff --git a/tests/fail/unsupported_signal.rs b/tests/fail/unsupported_signal.rs index 3e76d1c3f384..9cdf3cfdc664 100644 --- a/tests/fail/unsupported_signal.rs +++ b/tests/fail/unsupported_signal.rs @@ -1,6 +1,6 @@ //! `signal()` is special on Linux and macOS that it's only supported within libstd. //! The implementation is not complete enough to permit user code to call it. -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] extern crate libc; diff --git a/tests/fail/validity/cast_fn_ptr1.rs b/tests/fail/validity/cast_fn_ptr1.rs index eb5774fe7995..1bd889e89994 100644 --- a/tests/fail/validity/cast_fn_ptr1.rs +++ b/tests/fail/validity/cast_fn_ptr1.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance fn main() { // Cast a function pointer such that on a call, the argument gets transmuted diff --git a/tests/fail/validity/cast_fn_ptr2.rs b/tests/fail/validity/cast_fn_ptr2.rs index 1cf4ca7d19d8..7e7ad4710f5c 100644 --- a/tests/fail/validity/cast_fn_ptr2.rs +++ b/tests/fail/validity/cast_fn_ptr2.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance fn main() { // Cast a function pointer such that when returning, the return value gets transmuted diff --git a/tests/fail/validity/dangling_ref1.rs b/tests/fail/validity/dangling_ref1.rs index 78425cde4a8a..cc94cc6ca0ed 100644 --- a/tests/fail/validity/dangling_ref1.rs +++ b/tests/fail/validity/dangling_ref1.rs @@ -1,5 +1,5 @@ // Make sure we catch this even without Stacked Borrows -// compile-flags: -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-stacked-borrows use std::mem; fn main() { diff --git a/tests/fail/validity/dangling_ref2.rs b/tests/fail/validity/dangling_ref2.rs index 7aff1a49785c..eba026fdda86 100644 --- a/tests/fail/validity/dangling_ref2.rs +++ b/tests/fail/validity/dangling_ref2.rs @@ -1,5 +1,5 @@ // Make sure we catch this even without Stacked Borrows -// compile-flags: -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-stacked-borrows use std::mem; fn main() { diff --git a/tests/fail/validity/dangling_ref3.rs b/tests/fail/validity/dangling_ref3.rs index 495a266a85dc..8decc845ecb4 100644 --- a/tests/fail/validity/dangling_ref3.rs +++ b/tests/fail/validity/dangling_ref3.rs @@ -1,5 +1,5 @@ // Make sure we catch this even without Stacked Borrows -// compile-flags: -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-stacked-borrows use std::mem; fn dangling() -> *const u8 { diff --git a/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs b/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs index 7573a64d0eba..10e30cf85fe6 100644 --- a/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs +++ b/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs @@ -1,5 +1,5 @@ // Even when uninit numbers are allowed, this enum is not. -// compile-flags: -Zmiri-allow-uninit-numbers +//@compile-flags: -Zmiri-allow-uninit-numbers #![allow(unused, deprecated, invalid_value)] #[derive(Copy, Clone)] diff --git a/tests/fail/validity/nonzero.rs b/tests/fail/validity/nonzero.rs index 8ff19a2b4386..6344bb61ae25 100644 --- a/tests/fail/validity/nonzero.rs +++ b/tests/fail/validity/nonzero.rs @@ -1,5 +1,5 @@ // gets masked by optimizations -// compile-flags: -Zmir-opt-level=0 +//@compile-flags: -Zmir-opt-level=0 #![feature(rustc_attrs)] #![allow(unused_attributes)] diff --git a/tests/fail/weak_memory/racing_mixed_size.rs b/tests/fail/weak_memory/racing_mixed_size.rs index 6d53670a4e92..3608377e9199 100644 --- a/tests/fail/weak_memory/racing_mixed_size.rs +++ b/tests/fail/weak_memory/racing_mixed_size.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] diff --git a/tests/fail/weak_memory/racing_mixed_size_read.rs b/tests/fail/weak_memory/racing_mixed_size_read.rs index 0129b55aff61..e87b6d6fd01f 100644 --- a/tests/fail/weak_memory/racing_mixed_size_read.rs +++ b/tests/fail/weak_memory/racing_mixed_size_read.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] diff --git a/tests/fail/zst2.rs b/tests/fail/zst2.rs index 9f92e8994d26..55c78fe8f944 100644 --- a/tests/fail/zst2.rs +++ b/tests/fail/zst2.rs @@ -1,5 +1,5 @@ // Some optimizations remove ZST accesses, thus masking this UB. -// compile-flags: -Zmir-opt-level=0 +//@compile-flags: -Zmir-opt-level=0 fn main() { // Not using the () type here, as writes of that type do not even have MIR generated. diff --git a/tests/fail/zst3.rs b/tests/fail/zst3.rs index 3f3b0af14dbe..47a7c0d3c2a4 100644 --- a/tests/fail/zst3.rs +++ b/tests/fail/zst3.rs @@ -1,5 +1,5 @@ // Some optimizations remove ZST accesses, thus masking this UB. -// compile-flags: -Zmir-opt-level=0 +//@compile-flags: -Zmir-opt-level=0 fn main() { // Not using the () type here, as writes of that type do not even have MIR generated. diff --git a/tests/panic/panic/panic1.rs b/tests/panic/panic/panic1.rs index e15d7656de83..dbddf41fdbf7 100644 --- a/tests/panic/panic/panic1.rs +++ b/tests/panic/panic/panic1.rs @@ -1,5 +1,5 @@ -// rustc-env: RUST_BACKTRACE=1 -// compile-flags: -Zmiri-disable-isolation +//@rustc-env: RUST_BACKTRACE=1 +//@compile-flags: -Zmiri-disable-isolation fn main() { std::panic!("panicking from libstd"); diff --git a/tests/panic/panic/unsupported_foreign_function.rs b/tests/panic/panic/unsupported_foreign_function.rs index bc3d02c5f279..a78646528fb1 100644 --- a/tests/panic/panic/unsupported_foreign_function.rs +++ b/tests/panic/panic/unsupported_foreign_function.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-panic-on-unsupported +//@compile-flags: -Zmiri-panic-on-unsupported fn main() { extern "Rust" { diff --git a/tests/panic/panic/unsupported_syscall.rs b/tests/panic/panic/unsupported_syscall.rs index 2e62a5d8ae8d..3338c46c04ef 100644 --- a/tests/panic/panic/unsupported_syscall.rs +++ b/tests/panic/panic/unsupported_syscall.rs @@ -1,6 +1,6 @@ -// ignore-windows: No libc on Windows -// ignore-apple: `syscall` is not supported on macOS -// compile-flags: -Zmiri-panic-on-unsupported +//@ignore-windows: No libc on Windows +//@ignore-apple: `syscall` is not supported on macOS +//@compile-flags: -Zmiri-panic-on-unsupported #![feature(rustc_private)] extern crate libc; diff --git a/tests/pass/0weak_memory_consistency.rs b/tests/pass/0weak_memory_consistency.rs index 0f798d2b575e..19e19b47cfed 100644 --- a/tests/pass/0weak_memory_consistency.rs +++ b/tests/pass/0weak_memory_consistency.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows // The following tests check whether our weak memory emulation produces // any inconsistent execution outcomes diff --git a/tests/pass/adjacent-allocs.rs b/tests/pass/adjacent-allocs.rs index d0dc8b5d8762..0051c62121cd 100644 --- a/tests/pass/adjacent-allocs.rs +++ b/tests/pass/adjacent-allocs.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance fn ensure_allocs_can_be_adjacent() { for _ in 0..512 { diff --git a/tests/pass/align.rs b/tests/pass/align.rs index f412541bde17..997abd733922 100644 --- a/tests/pass/align.rs +++ b/tests/pass/align.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance /// This manually makes sure that we have a pointer with the proper alignment. fn manual_alignment() { diff --git a/tests/pass/align_offset_symbolic.rs b/tests/pass/align_offset_symbolic.rs index b57a23ab8368..b3e573383639 100644 --- a/tests/pass/align_offset_symbolic.rs +++ b/tests/pass/align_offset_symbolic.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-symbolic-alignment-check +//@compile-flags: -Zmiri-symbolic-alignment-check fn test_align_offset() { let d = Box::new([0u32; 4]); diff --git a/tests/pass/atomic-compare-exchange-weak-never-fail.rs b/tests/pass/atomic-compare-exchange-weak-never-fail.rs index 2c2d4e61d9f5..8d3d71869f42 100644 --- a/tests/pass/atomic-compare-exchange-weak-never-fail.rs +++ b/tests/pass/atomic-compare-exchange-weak-never-fail.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-compare-exchange-weak-failure-rate=0.0 +//@compile-flags: -Zmiri-compare-exchange-weak-failure-rate=0.0 use std::sync::atomic::{AtomicBool, Ordering::*}; // Ensure that compare_exchange_weak never fails. diff --git a/tests/pass/atomic.rs b/tests/pass/atomic.rs index 75e9cbdf1326..9b82e006fa16 100644 --- a/tests/pass/atomic.rs +++ b/tests/pass/atomic.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance +//@compile-flags: -Zmiri-strict-provenance #![feature(strict_provenance, strict_provenance_atomic_ptr)] use std::sync::atomic::{ compiler_fence, fence, AtomicBool, AtomicIsize, AtomicPtr, AtomicU64, Ordering::*, diff --git a/tests/pass/backtrace/backtrace-api-v0.rs b/tests/pass/backtrace/backtrace-api-v0.rs index 32fd47d8c581..5cd12959ca40 100644 --- a/tests/pass/backtrace/backtrace-api-v0.rs +++ b/tests/pass/backtrace/backtrace-api-v0.rs @@ -1,4 +1,4 @@ -// normalize-stderr-test: "::<.*>" -> "" +//@normalize-stderr-test: "::<.*>" -> "" #[inline(never)] fn func_a() -> Box<[*mut ()]> { diff --git a/tests/pass/backtrace/backtrace-api-v1.rs b/tests/pass/backtrace/backtrace-api-v1.rs index c24a5f3e8125..1e35574b39b6 100644 --- a/tests/pass/backtrace/backtrace-api-v1.rs +++ b/tests/pass/backtrace/backtrace-api-v1.rs @@ -1,4 +1,4 @@ -// normalize-stderr-test: "::<.*>" -> "" +//@normalize-stderr-test: "::<.*>" -> "" #[inline(never)] fn func_a() -> Box<[*mut ()]> { diff --git a/tests/pass/backtrace/backtrace-global-alloc.rs b/tests/pass/backtrace/backtrace-global-alloc.rs index 8c51bf62706e..45d6535bc139 100644 --- a/tests/pass/backtrace/backtrace-global-alloc.rs +++ b/tests/pass/backtrace/backtrace-global-alloc.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-disable-isolation +//@compile-flags: -Zmiri-disable-isolation #![feature(backtrace)] diff --git a/tests/pass/backtrace/backtrace-std.rs b/tests/pass/backtrace/backtrace-std.rs index 5de7cdd6a54d..488b87ede8fc 100644 --- a/tests/pass/backtrace/backtrace-std.rs +++ b/tests/pass/backtrace/backtrace-std.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-disable-isolation +//@compile-flags: -Zmiri-disable-isolation #![feature(backtrace)] diff --git a/tests/pass/btreemap.rs b/tests/pass/btreemap.rs index 413d7ef53d1c..040c648d4747 100644 --- a/tests/pass/btreemap.rs +++ b/tests/pass/btreemap.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance +//@compile-flags: -Zmiri-strict-provenance #![feature(btree_drain_filter)] use std::collections::{BTreeMap, BTreeSet}; use std::mem; diff --git a/tests/pass/calloc.rs b/tests/pass/calloc.rs index 9f614ce971ba..a75bb0606118 100644 --- a/tests/pass/calloc.rs +++ b/tests/pass/calloc.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/pass/concurrency/channels.rs b/tests/pass/concurrency/channels.rs index 0d6c1749eb51..e94c69b286d6 100644 --- a/tests/pass/concurrency/channels.rs +++ b/tests/pass/concurrency/channels.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-strict-provenance +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-strict-provenance use std::sync::mpsc::{channel, sync_channel}; use std::thread; diff --git a/tests/pass/concurrency/concurrent_caller_location.rs b/tests/pass/concurrency/concurrent_caller_location.rs index 003b9e9ca9f4..6bd601abd56e 100644 --- a/tests/pass/concurrency/concurrent_caller_location.rs +++ b/tests/pass/concurrency/concurrent_caller_location.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. use std::panic::Location; use std::thread::spawn; diff --git a/tests/pass/concurrency/data_race.rs b/tests/pass/concurrency/data_race.rs index 812003ef4d97..69b6c53a2b79 100644 --- a/tests/pass/concurrency/data_race.rs +++ b/tests/pass/concurrency/data_race.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-weak-memory-emulation +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-weak-memory-emulation use std::sync::atomic::{fence, AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/tests/pass/concurrency/disable_data_race_detector.rs b/tests/pass/concurrency/disable_data_race_detector.rs index 14e2d5651de0..a3c1e4621a3a 100644 --- a/tests/pass/concurrency/disable_data_race_detector.rs +++ b/tests/pass/concurrency/disable_data_race_detector.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-data-race-detector +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-data-race-detector use std::thread::spawn; diff --git a/tests/pass/concurrency/issue1643.rs b/tests/pass/concurrency/issue1643.rs index 1238a1bd6f5e..cfe9cf4cc2f7 100644 --- a/tests/pass/concurrency/issue1643.rs +++ b/tests/pass/concurrency/issue1643.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/pass/concurrency/libc_pthread_cond.rs b/tests/pass/concurrency/libc_pthread_cond.rs index 1f6f46cbeb51..8d245e2f8ddd 100644 --- a/tests/pass/concurrency/libc_pthread_cond.rs +++ b/tests/pass/concurrency/libc_pthread_cond.rs @@ -1,6 +1,6 @@ -// ignore-windows: No libc on Windows -// ignore-apple: pthread_condattr_setclock is not supported on MacOS. -// compile-flags: -Zmiri-disable-isolation +//@ignore-windows: No libc on Windows +//@ignore-apple: pthread_condattr_setclock is not supported on MacOS. +//@compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] diff --git a/tests/pass/concurrency/linux-futex.rs b/tests/pass/concurrency/linux-futex.rs index b65dd46d5974..1ec0ec599f7b 100644 --- a/tests/pass/concurrency/linux-futex.rs +++ b/tests/pass/concurrency/linux-futex.rs @@ -1,5 +1,5 @@ -// only-linux -// compile-flags: -Zmiri-disable-isolation +//@only-linux +//@compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] extern crate libc; diff --git a/tests/pass/concurrency/mutex_leak.rs b/tests/pass/concurrency/mutex_leak.rs index 7fbc6dd30166..3ac0c9336b7b 100644 --- a/tests/pass/concurrency/mutex_leak.rs +++ b/tests/pass/concurrency/mutex_leak.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-ignore-leaks +//@compile-flags: -Zmiri-ignore-leaks use std::mem; use std::sync::Mutex; diff --git a/tests/pass/concurrency/simple.rs b/tests/pass/concurrency/simple.rs index 48c1f3d9fb52..ac268dab5e94 100644 --- a/tests/pass/concurrency/simple.rs +++ b/tests/pass/concurrency/simple.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-strict-provenance +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-strict-provenance use std::thread; diff --git a/tests/pass/concurrency/spin_loop.rs b/tests/pass/concurrency/spin_loop.rs index e11f0789bb5d..e1c472589904 100644 --- a/tests/pass/concurrency/spin_loop.rs +++ b/tests/pass/concurrency/spin_loop.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread; diff --git a/tests/pass/concurrency/spin_loops_nopreempt.rs b/tests/pass/concurrency/spin_loops_nopreempt.rs index 99a5410c95df..823d2ec76540 100644 --- a/tests/pass/concurrency/spin_loops_nopreempt.rs +++ b/tests/pass/concurrency/spin_loops_nopreempt.rs @@ -1,6 +1,6 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. // This specifically tests behavior *without* preemption. -// compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-preemption-rate=0 use std::cell::Cell; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; diff --git a/tests/pass/concurrency/sync.rs b/tests/pass/concurrency/sync.rs index 396c1a97e07e..b7e6f229faae 100644 --- a/tests/pass/concurrency/sync.rs +++ b/tests/pass/concurrency/sync.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock}; use std::thread; diff --git a/tests/pass/concurrency/sync_nopreempt.rs b/tests/pass/concurrency/sync_nopreempt.rs index b5e726dac7b6..e6ee4fe594f1 100644 --- a/tests/pass/concurrency/sync_nopreempt.rs +++ b/tests/pass/concurrency/sync_nopreempt.rs @@ -1,6 +1,6 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. // We are making scheduler assumptions here. -// compile-flags: -Zmiri-strict-provenance -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-strict-provenance -Zmiri-preemption-rate=0 use std::sync::{Arc, Condvar, Mutex, RwLock}; use std::thread; diff --git a/tests/pass/concurrency/thread_locals.rs b/tests/pass/concurrency/thread_locals.rs index 5b11539f7f11..82ce61d958d8 100644 --- a/tests/pass/concurrency/thread_locals.rs +++ b/tests/pass/concurrency/thread_locals.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-strict-provenance +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-strict-provenance //! The main purpose of this test is to check that if we take a pointer to //! thread's `t1` thread-local `A` and send it to another thread `t2`, diff --git a/tests/pass/concurrency/tls_lib_drop.rs b/tests/pass/concurrency/tls_lib_drop.rs index fe46406c283c..74ba8ee76207 100644 --- a/tests/pass/concurrency/tls_lib_drop.rs +++ b/tests/pass/concurrency/tls_lib_drop.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. use std::cell::RefCell; use std::thread; diff --git a/tests/pass/concurrency/tls_pthread_drop_order.rs b/tests/pass/concurrency/tls_pthread_drop_order.rs index 29c57bf49a33..b265e7da0b25 100644 --- a/tests/pass/concurrency/tls_pthread_drop_order.rs +++ b/tests/pass/concurrency/tls_pthread_drop_order.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] extern crate libc; diff --git a/tests/pass/current_dir.rs b/tests/pass/current_dir.rs index a88f820951ca..069b462ab371 100644 --- a/tests/pass/current_dir.rs +++ b/tests/pass/current_dir.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-disable-isolation +//@compile-flags: -Zmiri-disable-isolation use std::env; use std::io::ErrorKind; diff --git a/tests/pass/current_dir_with_isolation.rs b/tests/pass/current_dir_with_isolation.rs index 98c44d57b65a..9dbcfeae2d64 100644 --- a/tests/pass/current_dir_with_isolation.rs +++ b/tests/pass/current_dir_with_isolation.rs @@ -1,6 +1,6 @@ -// compile-flags: -Zmiri-isolation-error=warn-nobacktrace -// normalize-stderr-test: "(getcwd|GetCurrentDirectoryW)" -> "$$GETCWD" -// normalize-stderr-test: "(chdir|SetCurrentDirectoryW)" -> "$$SETCWD" +//@compile-flags: -Zmiri-isolation-error=warn-nobacktrace +//@normalize-stderr-test: "(getcwd|GetCurrentDirectoryW)" -> "$$GETCWD" +//@normalize-stderr-test: "(chdir|SetCurrentDirectoryW)" -> "$$SETCWD" use std::env; use std::io::ErrorKind; diff --git a/tests/pass/disable-alignment-check.rs b/tests/pass/disable-alignment-check.rs index 2fb0dd8369df..366aff4a9f8e 100644 --- a/tests/pass/disable-alignment-check.rs +++ b/tests/pass/disable-alignment-check.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-disable-alignment-check +//@compile-flags: -Zmiri-disable-alignment-check fn main() { let mut x = [0u8; 20]; diff --git a/tests/pass/enum_discriminant_ptr_value.rs b/tests/pass/enum_discriminant_ptr_value.rs index 618d503cd5f2..4a3820777cff 100644 --- a/tests/pass/enum_discriminant_ptr_value.rs +++ b/tests/pass/enum_discriminant_ptr_value.rs @@ -1,6 +1,6 @@ // A niche-optimized enum where the discriminant is a pointer value -- relies on ptr-to-int casts in // the niche handling code. -// compile-flags: -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-stacked-borrows -Zmiri-disable-validation fn main() { let x = 42; diff --git a/tests/pass/env-exclude.rs b/tests/pass/env-exclude.rs index 1e251084f022..14ad827463a4 100644 --- a/tests/pass/env-exclude.rs +++ b/tests/pass/env-exclude.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-disable-isolation -Zmiri-env-exclude=MIRI_ENV_VAR_TEST +//@compile-flags: -Zmiri-disable-isolation -Zmiri-env-exclude=MIRI_ENV_VAR_TEST fn main() { assert!(std::env::var("MIRI_ENV_VAR_TEST").is_err()); diff --git a/tests/pass/env-forward.rs b/tests/pass/env-forward.rs index 8eebc45f55a7..da7730b00f08 100644 --- a/tests/pass/env-forward.rs +++ b/tests/pass/env-forward.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-env-forward=MIRI_ENV_VAR_TEST +//@compile-flags: -Zmiri-env-forward=MIRI_ENV_VAR_TEST fn main() { assert_eq!(std::env::var("MIRI_ENV_VAR_TEST"), Ok("0".to_owned())); diff --git a/tests/pass/env-without-isolation.rs b/tests/pass/env-without-isolation.rs index 638476209888..3d7461eecfe8 100644 --- a/tests/pass/env-without-isolation.rs +++ b/tests/pass/env-without-isolation.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-disable-isolation +//@compile-flags: -Zmiri-disable-isolation fn main() { assert_eq!(std::env::var("MIRI_ENV_VAR_TEST"), Ok("0".to_owned())); diff --git a/tests/pass/fs.rs b/tests/pass/fs.rs index e106ca5d02bb..ced7831568e7 100644 --- a/tests/pass/fs.rs +++ b/tests/pass/fs.rs @@ -1,5 +1,5 @@ -// ignore-windows: File handling is not implemented yet -// compile-flags: -Zmiri-disable-isolation +//@ignore-windows: File handling is not implemented yet +//@compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] #![feature(io_error_more)] diff --git a/tests/pass/fs_with_isolation.rs b/tests/pass/fs_with_isolation.rs index 6753145e92b2..719882702cdd 100644 --- a/tests/pass/fs_with_isolation.rs +++ b/tests/pass/fs_with_isolation.rs @@ -1,6 +1,6 @@ -// ignore-windows: File handling is not implemented yet -// compile-flags: -Zmiri-isolation-error=warn-nobacktrace -// normalize-stderr-test: "(stat(x)?)" -> "$$STAT" +//@ignore-windows: File handling is not implemented yet +//@compile-flags: -Zmiri-isolation-error=warn-nobacktrace +//@normalize-stderr-test: "(stat(x)?)" -> "$$STAT" #![feature(rustc_private)] diff --git a/tests/pass/function_calls/disable_abi_check.rs b/tests/pass/function_calls/disable_abi_check.rs index 1f8554741376..e6251b535588 100644 --- a/tests/pass/function_calls/disable_abi_check.rs +++ b/tests/pass/function_calls/disable_abi_check.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-disable-abi-check +//@compile-flags: -Zmiri-disable-abi-check #![feature(core_intrinsics)] fn main() { diff --git a/tests/pass/getpid.rs b/tests/pass/getpid.rs index 258fdeaa8497..733545462ebc 100644 --- a/tests/pass/getpid.rs +++ b/tests/pass/getpid.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-disable-isolation +//@compile-flags: -Zmiri-disable-isolation fn getpid() -> u32 { std::process::id() diff --git a/tests/pass/hide_stdout.rs b/tests/pass/hide_stdout.rs index 3ee68d01f43d..cfd05a8396cb 100644 --- a/tests/pass/hide_stdout.rs +++ b/tests/pass/hide_stdout.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-mute-stdout-stderr +//@compile-flags: -Zmiri-mute-stdout-stderr fn main() { println!("print to stdout"); diff --git a/tests/pass/integer-ops.rs b/tests/pass/integer-ops.rs index 8e2799d68905..8608d12d4d87 100644 --- a/tests/pass/integer-ops.rs +++ b/tests/pass/integer-ops.rs @@ -1,4 +1,4 @@ -// compile-flags: -Coverflow-checks=off +//@compile-flags: -Coverflow-checks=off #![feature(int_log)] #![allow(arithmetic_overflow)] diff --git a/tests/pass/intptrcast.rs b/tests/pass/intptrcast.rs index aebf5b222389..e7ff90cb6bf0 100644 --- a/tests/pass/intptrcast.rs +++ b/tests/pass/intptrcast.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance use std::mem; diff --git a/tests/pass/intrinsics.rs b/tests/pass/intrinsics.rs index 0042872a3b45..756744badaf9 100644 --- a/tests/pass/intrinsics.rs +++ b/tests/pass/intrinsics.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance #![feature(core_intrinsics, const_raw_ptr_comparison)] #![feature(layout_for_ptr)] diff --git a/tests/pass/issues/issue-miri-1925.rs b/tests/pass/issues/issue-miri-1925.rs index 262889f56eae..865568134919 100644 --- a/tests/pass/issues/issue-miri-1925.rs +++ b/tests/pass/issues/issue-miri-1925.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-symbolic-alignment-check +//@compile-flags: -Zmiri-symbolic-alignment-check use std::mem::size_of; diff --git a/tests/pass/issues/issue-miri-2068-2.rs b/tests/pass/issues/issue-miri-2068-2.rs index 204a4dd05642..f33806e8b443 100644 --- a/tests/pass/issues/issue-miri-2068-2.rs +++ b/tests/pass/issues/issue-miri-2068-2.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-validation use std::mem::MaybeUninit; diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index d08430a43260..53c85d2b07d1 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -1,5 +1,5 @@ -// ignore-windows: No libc on Windows -// compile-flags: -Zmiri-disable-isolation +//@ignore-windows: No libc on Windows +//@compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] diff --git a/tests/pass/linux-getrandom-without-isolation.rs b/tests/pass/linux-getrandom-without-isolation.rs index 56a53699477e..90e054533c14 100644 --- a/tests/pass/linux-getrandom-without-isolation.rs +++ b/tests/pass/linux-getrandom-without-isolation.rs @@ -1,5 +1,5 @@ -// only-linux -// compile-flags: -Zmiri-disable-isolation +//@only-linux +//@compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] extern crate libc; diff --git a/tests/pass/linux-getrandom.rs b/tests/pass/linux-getrandom.rs index a3596e4c7a9c..70c106f6460a 100644 --- a/tests/pass/linux-getrandom.rs +++ b/tests/pass/linux-getrandom.rs @@ -1,4 +1,4 @@ -// only-linux +//@only-linux #![feature(rustc_private)] extern crate libc; diff --git a/tests/pass/malloc.rs b/tests/pass/malloc.rs index 72abc68bb96b..c0a6a89fbed0 100644 --- a/tests/pass/malloc.rs +++ b/tests/pass/malloc.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/pass/memleak_ignored.rs b/tests/pass/memleak_ignored.rs index fddf14121ef3..60e06094e177 100644 --- a/tests/pass/memleak_ignored.rs +++ b/tests/pass/memleak_ignored.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-ignore-leaks +//@compile-flags: -Zmiri-ignore-leaks fn main() { std::mem::forget(Box::new(42)); diff --git a/tests/pass/move-uninit-primval.rs b/tests/pass/move-uninit-primval.rs index 1ca3873d1d36..220470b637fc 100644 --- a/tests/pass/move-uninit-primval.rs +++ b/tests/pass/move-uninit-primval.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-allow-uninit-numbers +//@compile-flags: -Zmiri-allow-uninit-numbers #![allow(deprecated)] struct Foo { diff --git a/tests/pass/no_std.rs b/tests/pass/no_std.rs index 6808dab8143f..d8a462daf5a9 100644 --- a/tests/pass/no_std.rs +++ b/tests/pass/no_std.rs @@ -3,7 +3,7 @@ // 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-windows +//@ignore-windows #[start] fn start(_: isize, _: *const *const u8) -> isize { diff --git a/tests/pass/observed_local_mut.rs b/tests/pass/observed_local_mut.rs index 888b6f85e3fd..ca0f569860b8 100644 --- a/tests/pass/observed_local_mut.rs +++ b/tests/pass/observed_local_mut.rs @@ -1,5 +1,5 @@ // Stacked Borrows catches this (correctly) as UB. -// compile-flags: -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-stacked-borrows // This test is intended to guard against the problem described in commit // 39bb1254d1eaf74f45a4e741097e33fc942168d5. diff --git a/tests/pass/overflow_checks_off.rs b/tests/pass/overflow_checks_off.rs index 2896d3161f76..79aa510ef97f 100644 --- a/tests/pass/overflow_checks_off.rs +++ b/tests/pass/overflow_checks_off.rs @@ -1,4 +1,4 @@ -// compile-flags: -C overflow-checks=off +//@compile-flags: -C overflow-checks=off // Check that we correctly implement the intended behavior of these operators // when they are not being overflow-checked. diff --git a/tests/pass/panic/catch_panic.rs b/tests/pass/panic/catch_panic.rs index 3979fb3b0714..308904406538 100644 --- a/tests/pass/panic/catch_panic.rs +++ b/tests/pass/panic/catch_panic.rs @@ -1,5 +1,5 @@ // We test the `align_offset` panic below, make sure we test the interpreter impl and not the "real" one. -// compile-flags: -Zmiri-symbolic-alignment-check -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-symbolic-alignment-check -Zmiri-permissive-provenance #![feature(never_type)] #![allow(unconditional_panic, non_fmt_panics)] diff --git a/tests/pass/panic/concurrent-panic.rs b/tests/pass/panic/concurrent-panic.rs index 7b17ac4fa79c..1231760865fb 100644 --- a/tests/pass/panic/concurrent-panic.rs +++ b/tests/pass/panic/concurrent-panic.rs @@ -1,6 +1,6 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. // We are making scheduler assumptions here. -// compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-preemption-rate=0 //! Cause a panic in one thread while another thread is unwinding. This checks //! that separate threads have their own panicking state. diff --git a/tests/pass/portable-simd.rs b/tests/pass/portable-simd.rs index ffbaa1832ecb..0dfe617bd8dc 100644 --- a/tests/pass/portable-simd.rs +++ b/tests/pass/portable-simd.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance +//@compile-flags: -Zmiri-strict-provenance #![feature(portable_simd, platform_intrinsics)] use std::simd::*; diff --git a/tests/pass/ptr_int_casts.rs b/tests/pass/ptr_int_casts.rs index ffe6a114c66b..3044ac092b7d 100644 --- a/tests/pass/ptr_int_casts.rs +++ b/tests/pass/ptr_int_casts.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance use std::mem; use std::ptr; diff --git a/tests/pass/ptr_int_from_exposed.rs b/tests/pass/ptr_int_from_exposed.rs index dc9cb393b781..ef7ff34d26b2 100644 --- a/tests/pass/ptr_int_from_exposed.rs +++ b/tests/pass/ptr_int_from_exposed.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance #![feature(strict_provenance)] use std::ptr; diff --git a/tests/pass/ptr_offset.rs b/tests/pass/ptr_offset.rs index b16a06a7260b..5270e8663b2d 100644 --- a/tests/pass/ptr_offset.rs +++ b/tests/pass/ptr_offset.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance use std::{mem, ptr}; fn main() { diff --git a/tests/pass/rc.rs b/tests/pass/rc.rs index 260e350f27ac..569dbc459a5b 100644 --- a/tests/pass/rc.rs +++ b/tests/pass/rc.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance +//@compile-flags: -Zmiri-strict-provenance #![feature(new_uninit)] #![feature(get_mut_unchecked)] diff --git a/tests/pass/slices.rs b/tests/pass/slices.rs index 3a13ec59a02e..a56b97a5088f 100644 --- a/tests/pass/slices.rs +++ b/tests/pass/slices.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance +//@compile-flags: -Zmiri-strict-provenance #![feature(new_uninit)] #![feature(slice_as_chunks)] #![feature(slice_partition_dedup)] diff --git a/tests/pass/stacked-borrows/int-to-ptr.rs b/tests/pass/stacked-borrows/int-to-ptr.rs index dc3675406276..c3e30627a7ce 100644 --- a/tests/pass/stacked-borrows/int-to-ptr.rs +++ b/tests/pass/stacked-borrows/int-to-ptr.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance #![feature(strict_provenance)] use std::ptr; diff --git a/tests/pass/stacked-borrows/interior_mutability.rs b/tests/pass/stacked-borrows/interior_mutability.rs index 96ad67505a73..c6373a7eaf13 100644 --- a/tests/pass/stacked-borrows/interior_mutability.rs +++ b/tests/pass/stacked-borrows/interior_mutability.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-retag-fields +//@compile-flags: -Zmiri-retag-fields use std::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell}; use std::mem::{self, MaybeUninit}; diff --git a/tests/pass/stacked-borrows/stacked-borrows.rs b/tests/pass/stacked-borrows/stacked-borrows.rs index b915a2ddf8f6..ef6eb346c17b 100644 --- a/tests/pass/stacked-borrows/stacked-borrows.rs +++ b/tests/pass/stacked-borrows/stacked-borrows.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-retag-fields +//@compile-flags: -Zmiri-retag-fields #![feature(allocator_api)] use std::ptr; diff --git a/tests/pass/strings.rs b/tests/pass/strings.rs index ccefc69bd180..5e2d2e9b5b5c 100644 --- a/tests/pass/strings.rs +++ b/tests/pass/strings.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance +//@compile-flags: -Zmiri-strict-provenance fn empty() -> &'static str { "" diff --git a/tests/pass/threadleak_ignored.rs b/tests/pass/threadleak_ignored.rs index 36d39a72b799..2ba0b453ff39 100644 --- a/tests/pass/threadleak_ignored.rs +++ b/tests/pass/threadleak_ignored.rs @@ -1,6 +1,6 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. // FIXME: disallow preemption to work around https://github.com/rust-lang/rust/issues/55005 -// compile-flags: -Zmiri-ignore-leaks -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-preemption-rate=0 //! Test that leaking threads works, and that their destructors are not executed. diff --git a/tests/pass/time.rs b/tests/pass/time.rs index 38e846309d72..e1094006fb1f 100644 --- a/tests/pass/time.rs +++ b/tests/pass/time.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-disable-isolation +//@compile-flags: -Zmiri-disable-isolation use std::time::{Duration, Instant, SystemTime}; diff --git a/tests/pass/track-alloc-1.rs b/tests/pass/track-alloc-1.rs index bbd88ed5d53e..427c800dc51d 100644 --- a/tests/pass/track-alloc-1.rs +++ b/tests/pass/track-alloc-1.rs @@ -1,6 +1,6 @@ // Ensure that tracking early allocations doesn't ICE Miri. // Early allocations are probably part of the runtime and therefore uninteresting, but they // shouldn't cause a crash. -// compile-flags: -Zmiri-track-alloc-id=1 -// normalize-stderr-test: "[48] bytes" -> "SIZE bytes" +//@compile-flags: -Zmiri-track-alloc-id=1 +//@normalize-stderr-test: "[48] bytes" -> "SIZE bytes" fn main() {} diff --git a/tests/pass/transmute_fat.rs b/tests/pass/transmute_fat.rs index b752e5504d4c..dfd78ace520c 100644 --- a/tests/pass/transmute_fat.rs +++ b/tests/pass/transmute_fat.rs @@ -1,5 +1,5 @@ // Stacked Borrows disallows this becuase the reference is never cast to a raw pointer. -// compile-flags: -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-stacked-borrows fn main() { // If we are careful, we can exploit data layout... diff --git a/tests/pass/uninit_number_ignored.rs b/tests/pass/uninit_number_ignored.rs index 13aac61ba84c..44f6fa267985 100644 --- a/tests/pass/uninit_number_ignored.rs +++ b/tests/pass/uninit_number_ignored.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-allow-uninit-numbers +//@compile-flags: -Zmiri-allow-uninit-numbers // This test is adapted from https://github.com/rust-lang/miri/issues/1340#issue-600900312. fn main() { diff --git a/tests/pass/vec.rs b/tests/pass/vec.rs index 89c2561acd97..26732cec5eb9 100644 --- a/tests/pass/vec.rs +++ b/tests/pass/vec.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance +//@compile-flags: -Zmiri-strict-provenance // Gather all references from a mutable iterator and make sure Miri notices if // using them is dangerous. fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { diff --git a/tests/pass/vecdeque.rs b/tests/pass/vecdeque.rs index d2295a7afb59..6f56f9d103e9 100644 --- a/tests/pass/vecdeque.rs +++ b/tests/pass/vecdeque.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance +//@compile-flags: -Zmiri-strict-provenance use std::collections::VecDeque; fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { diff --git a/tests/pass/weak_memory/extra_cpp.rs b/tests/pass/weak_memory/extra_cpp.rs index 750c628458b8..61ba1ab92248 100644 --- a/tests/pass/weak_memory/extra_cpp.rs +++ b/tests/pass/weak_memory/extra_cpp.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-ignore-leaks +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-ignore-leaks // Tests operations not perfomable through C++'s atomic API // but doable in safe (at least sound) Rust. diff --git a/tests/pass/weak_memory/extra_cpp_unsafe.rs b/tests/pass/weak_memory/extra_cpp_unsafe.rs index d77a090e6e43..0aff70ab7b78 100644 --- a/tests/pass/weak_memory/extra_cpp_unsafe.rs +++ b/tests/pass/weak_memory/extra_cpp_unsafe.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-ignore-leaks +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-ignore-leaks // Tests operations not perfomable through C++'s atomic API // but doable in unsafe Rust which we think *should* be fine. diff --git a/tests/pass/weak_memory/weak.rs b/tests/pass/weak_memory/weak.rs index b9ceb61f0c9f..1d82b85844f4 100644 --- a/tests/pass/weak_memory/weak.rs +++ b/tests/pass/weak_memory/weak.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-ignore-leaks -Zmiri-preemption-rate=0 +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-preemption-rate=0 // Tests showing weak memory behaviours are exhibited. All tests // return true when the desired behaviour is seen. diff --git a/tests/pass/without-validation.rs b/tests/pass/without-validation.rs index 8cff3a5c4b2e..934c44a7deb4 100644 --- a/tests/pass/without-validation.rs +++ b/tests/pass/without-validation.rs @@ -1,5 +1,5 @@ // When we notice something breaks only without validation, we add a test here. -// compile-flags: -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-validation use std::cell::*; fn refcell_unsize() { diff --git a/tests/pass/wtf8.rs b/tests/pass/wtf8.rs index e31b00e95244..bf23f65c7f0c 100644 --- a/tests/pass/wtf8.rs +++ b/tests/pass/wtf8.rs @@ -1,4 +1,4 @@ -// only-windows +//@only-windows use std::ffi::{OsStr, OsString}; use std::os::windows::ffi::{OsStrExt, OsStringExt}; diff --git a/tests/pass/zst.rs b/tests/pass/zst.rs index fade1e0dad88..a56386a691f8 100644 --- a/tests/pass/zst.rs +++ b/tests/pass/zst.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance #[derive(PartialEq, Debug)] struct A; diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 2b6108f255f8..4046a9fc0ddf 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -74,10 +74,7 @@ impl Comments { /// Parse comments in `content`. /// `path` is only used to emit diagnostics if parsing fails. - /// - /// This function will only parse `//@` and `//~` style comments (and the `//[xxx]~` variant) - /// and ignore all others - fn parse_checked(path: &Path, content: &str) -> Result { + pub(crate) fn parse(path: &Path, content: &str) -> Result { let mut this = Self::default(); let mut fallthrough_to = None; // The line that a `|` will refer to. @@ -108,83 +105,10 @@ impl Comments { } } - /// Parse comments in `content`. - /// `path` is only used to emit diagnostics if parsing fails. - pub(crate) fn parse(path: &Path, content: &str) -> Result { - let mut this = Self::parse_checked(path, content)?; - if content.contains("//@") { - // Migration mode: if new syntax is used, ignore all old syntax - return Ok(this); - } - - for (l, line) in content.lines().enumerate() { - let l = l + 1; // enumerate starts at 0, but line numbers start at 1 - if let Some(revisions) = line.strip_prefix("// revisions:") { - assert_eq!( - this.revisions, - None, - "{}:{l}, cannot specifiy revisions twice", - path.display() - ); - this.revisions = - Some(revisions.split_whitespace().map(|s| s.to_string()).collect()); - } - if let Some(s) = line.strip_prefix("// ignore-") { - let s = s - .split_once(|c: char| c == ':' || c.is_whitespace()) - .map(|(s, _)| s) - .unwrap_or(s); - this.ignore.push(Condition::parse(s)); - } - if let Some(s) = line.strip_prefix("// only-") { - let s = s - .split_once(|c: char| c == ':' || c.is_whitespace()) - .map(|(s, _)| s) - .unwrap_or(s); - this.only.push(Condition::parse(s)); - } - if line.starts_with("// stderr-per-bitwidth") { - assert!( - !this.stderr_per_bitwidth, - "{}:{l}, cannot specifiy stderr-per-bitwidth twice", - path.display() - ); - this.stderr_per_bitwidth = true; - } - if let Some(s) = line.strip_prefix("// compile-flags:") { - this.compile_flags.extend(s.split_whitespace().map(|s| s.to_string())); - } - if let Some(s) = line.strip_prefix("// rustc-env:") { - for env in s.split_whitespace() { - if let Some((k, v)) = env.split_once('=') { - this.env_vars.push((k.to_string(), v.to_string())); - } - } - } - if let Some(s) = line.strip_prefix("// normalize-stderr-test:") { - let (from, to) = s.split_once("->").expect("normalize-stderr-test needs a `->`"); - let from = from.trim().trim_matches('"'); - let to = to.trim().trim_matches('"'); - let from = Regex::new(from).unwrap(); - this.normalize_stderr.push((from, to.to_string())); - } - if let Some(s) = line.strip_prefix("// error-pattern:") { - assert_eq!( - this.error_pattern, - None, - "{}:{l}, cannot specifiy error_pattern twice", - path.display() - ); - this.error_pattern = Some((s.trim().to_string(), l)); - } - } - Ok(this) - } - fn parse_command(&mut self, command: &str, l: usize) -> Result<()> { // Commands are letters or dashes, grab everything until the first character that is neither of those. let (command, args) = - match command.chars().position(|c: char| !c.is_alphabetic() && c != '-') { + match command.chars().position(|c: char| !c.is_alphanumeric() && c != '-') { None => (command, ""), Some(i) => { let (command, args) = command.split_at(i); From fdffaf740bf15dbcedd630b0ac6bd81293202bc8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Jul 2022 17:17:44 -0400 Subject: [PATCH 3485/5092] ui_test: require colon after command --- ui_test/src/comments.rs | 11 +++++------ ui_test/src/comments/tests.rs | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 4046a9fc0ddf..12f0864d9ab8 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -117,12 +117,8 @@ impl Comments { let next = args .next() .expect("the `position` above guarantees that there is at least one char"); - // FIXME: this replicates the existing flexibility in our syntax. Consider requiring the colon. - let args = match next { - ':' | ' ' => args.as_str(), - _ => bail!("expected space or `:`, got `{next}`"), - }; - (command, args.trim()) + ensure!(next == ':', "test command must be followed by : (or end the line)"); + (command, args.as_str().trim()) } }; @@ -188,16 +184,19 @@ impl Comments { self.error_pattern = Some((args.trim().to_string(), l)); } "stderr-per-bitwidth" => { + // args are ignored (can be sue as comment) ensure!(!self.stderr_per_bitwidth, "cannot specifiy stderr-per-bitwidth twice"); self.stderr_per_bitwidth = true; } command => { if let Some(s) = command.strip_prefix("ignore-") { + // args are ignored (can be sue as comment) self.ignore.push(Condition::parse(s)); return Ok(()); } if let Some(s) = command.strip_prefix("only-") { + // args are ignored (can be sue as comment) self.only.push(Condition::parse(s)); return Ok(()); } diff --git a/ui_test/src/comments/tests.rs b/ui_test/src/comments/tests.rs index 15a0aae247b1..096cc8eab965 100644 --- a/ui_test/src/comments/tests.rs +++ b/ui_test/src/comments/tests.rs @@ -53,3 +53,17 @@ use std::mem; Err(_) => Ok(()), } } + +#[test] +fn missing_colon_fail() -> Result<()> { + init(); + let s = r" +//@stderr-per-bitwidth hello +use std::mem; + + "; + match Comments::parse(Path::new(""), s) { + Ok(_) => bail!("expected parsing to fail"), + Err(_) => Ok(()), + } +} From d260dffa19515495a6b7dcd21770826f57179bb1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Jul 2022 17:18:17 -0400 Subject: [PATCH 3486/5092] =?UTF-8?q?rename=20ui=5Ftest::comments=20?= =?UTF-8?q?=E2=86=92=20parser?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui_test/src/lib.rs | 6 +++--- ui_test/src/{comments.rs => parser.rs} | 0 ui_test/src/{comments => parser}/tests.rs | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename ui_test/src/{comments.rs => parser.rs} (100%) rename ui_test/src/{comments => parser}/tests.rs (100%) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index da562fcac7d2..bebda768babe 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -10,13 +10,13 @@ use std::sync::Mutex; pub use color_eyre; use color_eyre::eyre::Result; use colored::*; -use comments::ErrorMatch; +use parser::ErrorMatch; use regex::Regex; use rustc_stderr::{Level, Message}; -use crate::comments::{Comments, Condition}; +use crate::parser::{Comments, Condition}; -mod comments; +mod parser; mod rustc_stderr; #[cfg(test)] mod tests; diff --git a/ui_test/src/comments.rs b/ui_test/src/parser.rs similarity index 100% rename from ui_test/src/comments.rs rename to ui_test/src/parser.rs diff --git a/ui_test/src/comments/tests.rs b/ui_test/src/parser/tests.rs similarity index 100% rename from ui_test/src/comments/tests.rs rename to ui_test/src/parser/tests.rs From 2850db9f6b2172e11b5e7d9b4b685fd288797886 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Jul 2022 07:51:06 -0400 Subject: [PATCH 3487/5092] typo Co-authored-by: Oli Scherer --- ui_test/src/parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui_test/src/parser.rs b/ui_test/src/parser.rs index 12f0864d9ab8..72ccc0136201 100644 --- a/ui_test/src/parser.rs +++ b/ui_test/src/parser.rs @@ -184,7 +184,7 @@ impl Comments { self.error_pattern = Some((args.trim().to_string(), l)); } "stderr-per-bitwidth" => { - // args are ignored (can be sue as comment) + // args are ignored (can be used as comment) ensure!(!self.stderr_per_bitwidth, "cannot specifiy stderr-per-bitwidth twice"); self.stderr_per_bitwidth = true; } From c9b207eba63b814cf39652fc9573318a7efc938b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Jul 2022 12:49:37 -0400 Subject: [PATCH 3488/5092] extend a comment in readlink --- src/shims/unix/fs.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index c68845571034..c7d7789f03ab 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -1639,6 +1639,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = std::fs::read_link(pathname); match result { Ok(resolved) => { + // 'readlink' truncates the resolved path if the provided buffer is not large + // enough, and does *not* add a null terminator. That means we cannot use the usual + // `write_path_to_c_str` and have to re-implement parts of it ourselves. let resolved = this.convert_path_separator( Cow::Borrowed(resolved.as_ref()), crate::shims::os_str::PathConversion::HostToTarget, @@ -1648,8 +1651,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if path_bytes.len() > bufsize { path_bytes = &path_bytes[..bufsize] } - // 'readlink' truncates the resolved path if - // the provided buffer is not large enough. this.write_bytes_ptr(buf, path_bytes.iter().copied())?; Ok(path_bytes.len().try_into().unwrap()) } From bf5af84640f5494e6e915c00adadf83ce1d62637 Mon Sep 17 00:00:00 2001 From: TechiePi <48295028+Techie-Pi@users.noreply.github.com> Date: Sun, 10 Jul 2022 23:41:35 +0200 Subject: [PATCH 3489/5092] Fix README typo "behaivours" -> "behaviours". Just something I noticed while reading --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 52934a6cd4bc..7679537e7f88 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ in your program, and cannot run all programs: not support networking. System API support varies between targets; if you run on Windows it is a good idea to use `--target x86_64-unknown-linux-gnu` to get better support. -* Weak memory emulation may [produce weak behaivours](https://github.com/rust-lang/miri/issues/2301) +* Weak memory emulation may [produce weak behaviours](https://github.com/rust-lang/miri/issues/2301) unobservable by compiled programs running on real hardware when `SeqCst` fences are used, and it cannot produce all behaviors possibly observable on real hardware. From 45abee46be9223dd4bbe895f836093c04ead1e89 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 Jul 2022 20:15:35 -0400 Subject: [PATCH 3490/5092] make a test deterministic --- rust-version | 2 +- tests/fail/data_race/enable_after_join_to_main.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 53e7908f42c8..2a26cb608235 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1517f5de01c445b5124b30f02257b02b4c5ef3b2 +c396bb3b8a16b1f2762b7c6078dc3e023f6a2493 diff --git a/tests/fail/data_race/enable_after_join_to_main.rs b/tests/fail/data_race/enable_after_join_to_main.rs index 757a41adc932..290589690a38 100644 --- a/tests/fail/data_race/enable_after_join_to_main.rs +++ b/tests/fail/data_race/enable_after_join_to_main.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; From 444ba75ac5fb0754b306b56b2fc2427d008f6b06 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 Jul 2022 20:19:41 -0400 Subject: [PATCH 3491/5092] make more tests deterministic --- tests/fail/data_race/atomic_read_na_write_race1.rs | 2 ++ tests/fail/data_race/atomic_read_na_write_race2.rs | 2 ++ tests/fail/data_race/atomic_write_na_read_race1.rs | 2 ++ tests/fail/data_race/atomic_write_na_read_race2.rs | 2 ++ tests/fail/data_race/atomic_write_na_write_race1.rs | 2 ++ tests/fail/data_race/atomic_write_na_write_race2.rs | 2 ++ tests/fail/data_race/dangling_thread_async_race.rs | 3 ++- tests/fail/data_race/dangling_thread_race.rs | 3 ++- tests/fail/data_race/dealloc_read_race1.rs | 2 ++ tests/fail/data_race/dealloc_read_race2.rs | 2 ++ tests/fail/data_race/dealloc_write_race1.rs | 2 ++ tests/fail/data_race/dealloc_write_race2.rs | 2 ++ tests/fail/data_race/read_write_race.rs | 2 ++ tests/fail/data_race/write_write_race.rs | 2 ++ tests/fail/weak_memory/racing_mixed_size.rs | 2 ++ tests/fail/weak_memory/racing_mixed_size_read.rs | 2 ++ 16 files changed, 32 insertions(+), 2 deletions(-) diff --git a/tests/fail/data_race/atomic_read_na_write_race1.rs b/tests/fail/data_race/atomic_read_na_write_race1.rs index 71d7a66597d1..ada25173f255 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.rs +++ b/tests/fail/data_race/atomic_read_na_write_race1.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] diff --git a/tests/fail/data_race/atomic_read_na_write_race2.rs b/tests/fail/data_race/atomic_read_na_write_race2.rs index a490f47da7c3..b355e4816dde 100644 --- a/tests/fail/data_race/atomic_read_na_write_race2.rs +++ b/tests/fail/data_race/atomic_read_na_write_race2.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::AtomicUsize; diff --git a/tests/fail/data_race/atomic_write_na_read_race1.rs b/tests/fail/data_race/atomic_write_na_read_race1.rs index 40066d91b1ff..53305c68cb76 100644 --- a/tests/fail/data_race/atomic_write_na_read_race1.rs +++ b/tests/fail/data_race/atomic_write_na_read_race1.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::AtomicUsize; diff --git a/tests/fail/data_race/atomic_write_na_read_race2.rs b/tests/fail/data_race/atomic_write_na_read_race2.rs index 0bfadcba3ed3..21b0abbcaba9 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.rs +++ b/tests/fail/data_race/atomic_write_na_read_race2.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] diff --git a/tests/fail/data_race/atomic_write_na_write_race1.rs b/tests/fail/data_race/atomic_write_na_write_race1.rs index 258f5dd142ef..a8ac18f32136 100644 --- a/tests/fail/data_race/atomic_write_na_write_race1.rs +++ b/tests/fail/data_race/atomic_write_na_write_race1.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] diff --git a/tests/fail/data_race/atomic_write_na_write_race2.rs b/tests/fail/data_race/atomic_write_na_write_race2.rs index 51068262d588..e3b3e226d8c7 100644 --- a/tests/fail/data_race/atomic_write_na_write_race2.rs +++ b/tests/fail/data_race/atomic_write_na_write_race2.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::AtomicUsize; diff --git a/tests/fail/data_race/dangling_thread_async_race.rs b/tests/fail/data_race/dangling_thread_async_race.rs index 7bb20adfcd5f..be06740201d2 100644 --- a/tests/fail/data_race/dangling_thread_async_race.rs +++ b/tests/fail/data_race/dangling_thread_async_race.rs @@ -1,5 +1,6 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. -//@compile-flags: -Zmiri-disable-isolation use std::mem; use std::thread::{sleep, spawn}; diff --git a/tests/fail/data_race/dangling_thread_race.rs b/tests/fail/data_race/dangling_thread_race.rs index 7e198eef6e94..90957e4026e3 100644 --- a/tests/fail/data_race/dangling_thread_race.rs +++ b/tests/fail/data_race/dangling_thread_race.rs @@ -1,5 +1,6 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. -//@compile-flags: -Zmiri-disable-isolation use std::mem; use std::thread::{sleep, spawn}; diff --git a/tests/fail/data_race/dealloc_read_race1.rs b/tests/fail/data_race/dealloc_read_race1.rs index 634904cbfdce..b37f4fda2bd4 100644 --- a/tests/fail/data_race/dealloc_read_race1.rs +++ b/tests/fail/data_race/dealloc_read_race1.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_read_race2.rs b/tests/fail/data_race/dealloc_read_race2.rs index 91ec3c2bd872..280b86924be8 100644 --- a/tests/fail/data_race/dealloc_read_race2.rs +++ b/tests/fail/data_race/dealloc_read_race2.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_write_race1.rs b/tests/fail/data_race/dealloc_write_race1.rs index f95a9be17274..17fb444f9c63 100644 --- a/tests/fail/data_race/dealloc_write_race1.rs +++ b/tests/fail/data_race/dealloc_write_race1.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_write_race2.rs b/tests/fail/data_race/dealloc_write_race2.rs index 922738354fb0..6afb1182a029 100644 --- a/tests/fail/data_race/dealloc_write_race2.rs +++ b/tests/fail/data_race/dealloc_write_race2.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/read_write_race.rs b/tests/fail/data_race/read_write_race.rs index cffbba1a70f3..4c1d87746d72 100644 --- a/tests/fail/data_race/read_write_race.rs +++ b/tests/fail/data_race/read_write_race.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/write_write_race.rs b/tests/fail/data_race/write_write_race.rs index ddd710bce08d..de4d4d70c500 100644 --- a/tests/fail/data_race/write_write_race.rs +++ b/tests/fail/data_race/write_write_race.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/weak_memory/racing_mixed_size.rs b/tests/fail/weak_memory/racing_mixed_size.rs index 3608377e9199..d697e5f8fbea 100644 --- a/tests/fail/weak_memory/racing_mixed_size.rs +++ b/tests/fail/weak_memory/racing_mixed_size.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] diff --git a/tests/fail/weak_memory/racing_mixed_size_read.rs b/tests/fail/weak_memory/racing_mixed_size_read.rs index e87b6d6fd01f..0eacaeeaa9ee 100644 --- a/tests/fail/weak_memory/racing_mixed_size_read.rs +++ b/tests/fail/weak_memory/racing_mixed_size_read.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] From f3496cbe4bf917032220b14a4bc4a89b406a5a85 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 11:44:55 +0000 Subject: [PATCH 3492/5092] require level and colon in `//~` style comments --- tests/fail/alloc/reallocate-change-alloc.rs | 2 +- tests/fail/backtrace/bad-backtrace-decl.rs | 2 +- tests/fail/backtrace/bad-backtrace-flags.rs | 2 +- tests/fail/backtrace/bad-backtrace-ptr.rs | 2 +- .../backtrace/bad-backtrace-resolve-flags.rs | 2 +- .../bad-backtrace-resolve-names-flags.rs | 2 +- .../backtrace/bad-backtrace-size-flags.rs | 2 +- tests/fail/box-cell-alias.rs | 2 +- tests/fail/branchless-select-i128-pointer.rs | 2 +- tests/fail/breakpoint.rs | 2 +- .../thread_local_static_dealloc.rs | 2 +- tests/fail/concurrency/unwind_top_of_stack.rs | 2 +- .../dangling_pointer_addr_of.rs | 2 +- .../dangling_pointer_deref.rs | 2 +- .../dangling_pointers/dangling_zst_deref.rs | 2 +- .../dangling_pointers/deref-invalid-ptr.rs | 2 +- .../deref-partially-dangling.rs | 2 +- tests/fail/dangling_pointers/dyn_size.rs | 2 +- .../maybe_null_pointer_deref_zst.rs | 2 +- .../maybe_null_pointer_write_zst.rs | 2 +- .../dangling_pointers/null_pointer_deref.rs | 2 +- .../null_pointer_deref_zst.rs | 2 +- .../dangling_pointers/null_pointer_write.rs | 2 +- .../dangling_pointers/out_of_bounds_read1.rs | 2 +- .../dangling_pointers/out_of_bounds_read2.rs | 2 +- .../fail/dangling_pointers/stack_temporary.rs | 2 +- .../storage_dead_dangling.rs | 2 +- .../dangling_pointers/wild_pointer_deref.rs | 2 +- tests/fail/data_race/alloc_read_race.rs | 2 +- tests/fail/data_race/alloc_write_race.rs | 2 +- .../data_race/atomic_read_na_write_race1.rs | 2 +- .../data_race/atomic_read_na_write_race2.rs | 2 +- .../data_race/atomic_write_na_read_race1.rs | 2 +- .../data_race/atomic_write_na_read_race2.rs | 2 +- .../data_race/atomic_write_na_write_race1.rs | 2 +- .../data_race/atomic_write_na_write_race2.rs | 2 +- .../data_race/dangling_thread_async_race.rs | 2 +- tests/fail/data_race/dangling_thread_race.rs | 2 +- tests/fail/data_race/dealloc_read_race1.rs | 2 +- tests/fail/data_race/dealloc_read_race2.rs | 2 +- .../fail/data_race/dealloc_read_race_stack.rs | 2 +- tests/fail/data_race/dealloc_write_race1.rs | 2 +- tests/fail/data_race/dealloc_write_race2.rs | 2 +- .../data_race/dealloc_write_race_stack.rs | 2 +- .../data_race/enable_after_join_to_main.rs | 2 +- tests/fail/data_race/fence_after_load.rs | 2 +- tests/fail/data_race/read_write_race.rs | 2 +- tests/fail/data_race/read_write_race_stack.rs | 2 +- tests/fail/data_race/relax_acquire_race.rs | 2 +- tests/fail/data_race/release_seq_race.rs | 2 +- .../data_race/release_seq_race_same_thread.rs | 2 +- tests/fail/data_race/rmw_race.rs | 2 +- tests/fail/data_race/stack_pop_race.rs | 2 +- tests/fail/data_race/write_write_race.rs | 2 +- .../fail/data_race/write_write_race_stack.rs | 2 +- tests/fail/environ-gets-deallocated.rs | 2 +- tests/fail/erroneous_const.rs | 4 +- tests/fail/erroneous_const2.rs | 12 +-- tests/fail/extern_static.rs | 2 +- tests/fail/extern_static_in_const.rs | 2 +- tests/fail/fast_math_both.rs | 2 +- tests/fail/fast_math_first.rs | 2 +- tests/fail/fast_math_second.rs | 2 +- tests/fail/fs/close_stdout.rs | 2 +- tests/fail/fs/isolated_stdin.rs | 2 +- tests/fail/fs/read_from_stdout.rs | 2 +- .../fs/unix_open_missing_required_mode.rs | 2 +- tests/fail/fs/write_to_stdin.rs | 2 +- tests/fail/function_calls/check_arg_abi.rs | 2 +- .../function_calls/check_arg_count_abort.rs | 2 +- .../check_arg_count_too_few_args.rs | 2 +- .../check_arg_count_too_many_args.rs | 2 +- .../fail/function_calls/check_callback_abi.rs | 2 +- .../exported_symbol_abi_mismatch.rs | 6 +- .../exported_symbol_bad_unwind1.rs | 2 +- .../exported_symbol_bad_unwind2.both.stderr | 4 +- ...orted_symbol_bad_unwind2.definition.stderr | 4 +- .../exported_symbol_bad_unwind2.rs | 6 +- .../exported_symbol_clashing.rs | 6 +- .../exported_symbol_shim_clashing.rs | 4 +- .../exported_symbol_wrong_arguments.rs | 2 +- .../exported_symbol_wrong_type.rs | 2 +- .../cast_box_int_to_fn_ptr.rs | 2 +- tests/fail/function_pointers/cast_fn_ptr1.rs | 2 +- tests/fail/function_pointers/cast_fn_ptr2.rs | 2 +- tests/fail/function_pointers/cast_fn_ptr3.rs | 2 +- tests/fail/function_pointers/cast_fn_ptr4.rs | 2 +- tests/fail/function_pointers/cast_fn_ptr5.rs | 2 +- .../function_pointers/cast_int_to_fn_ptr.rs | 2 +- tests/fail/function_pointers/deref_fn_ptr.rs | 2 +- .../fail/function_pointers/execute_memory.rs | 2 +- tests/fail/function_pointers/fn_ptr_offset.rs | 2 +- tests/fail/generator-pinned-moved.rs | 2 +- tests/fail/intrinsics/assume.rs | 2 +- tests/fail/intrinsics/copy_overlapping.rs | 2 +- tests/fail/intrinsics/copy_unaligned.rs | 2 +- tests/fail/intrinsics/ctlz_nonzero.rs | 2 +- tests/fail/intrinsics/cttz_nonzero.rs | 2 +- tests/fail/intrinsics/div-by-zero.rs | 2 +- tests/fail/intrinsics/exact_div1.rs | 2 +- tests/fail/intrinsics/exact_div2.rs | 2 +- tests/fail/intrinsics/exact_div3.rs | 2 +- tests/fail/intrinsics/exact_div4.rs | 2 +- tests/fail/intrinsics/ptr_offset_from_oob.rs | 2 +- tests/fail/intrinsics/rem-by-zero.rs | 2 +- tests/fail/intrinsics/simd-div-by-zero.rs | 2 +- tests/fail/intrinsics/simd-div-overflow.rs | 2 +- .../intrinsics/simd-reduce-invalid-bool.rs | 2 +- tests/fail/intrinsics/simd-rem-by-zero.rs | 2 +- .../intrinsics/simd-select-bitmask-invalid.rs | 2 +- .../intrinsics/simd-select-invalid-bool.rs | 2 +- tests/fail/intrinsics/simd-shl-too-far.rs | 2 +- tests/fail/intrinsics/simd-shr-too-far.rs | 2 +- tests/fail/intrinsics/unchecked_add1.rs | 2 +- tests/fail/intrinsics/unchecked_add2.rs | 2 +- tests/fail/intrinsics/unchecked_div1.rs | 2 +- tests/fail/intrinsics/unchecked_mul1.rs | 2 +- tests/fail/intrinsics/unchecked_mul2.rs | 2 +- tests/fail/intrinsics/unchecked_sub1.rs | 2 +- tests/fail/intrinsics/unchecked_sub2.rs | 2 +- tests/fail/intrinsics/write_bytes_null.rs | 2 +- tests/fail/invalid_bool.rs | 2 +- tests/fail/invalid_char.rs | 2 +- tests/fail/invalid_int.rs | 2 +- tests/fail/issue-miri-1112.rs | 2 +- tests/fail/modifying_constants.rs | 2 +- tests/fail/never_say_never.rs | 2 +- tests/fail/never_transmute_humans.rs | 2 +- tests/fail/never_transmute_void.rs | 5 +- tests/fail/panic/bad_miri_start_panic.rs | 2 +- tests/fail/panic/unwind_panic_abort.rs | 2 +- tests/fail/pointer_partial_overwrite.rs | 2 +- tests/fail/provenance/provenance_transmute.rs | 2 +- tests/fail/provenance/ptr_int_unexposed.rs | 2 +- tests/fail/provenance/ptr_invalid.rs | 2 +- .../fail/provenance/strict_provenance_cast.rs | 2 +- tests/fail/rc_as_ptr.rs | 2 +- tests/fail/reading_half_a_pointer.rs | 2 +- tests/fail/rustc-error.rs | 2 +- tests/fail/shim_arg_size.rs | 2 +- .../stacked_borrows/alias_through_mutation.rs | 2 +- tests/fail/stacked_borrows/aliasing_mut1.rs | 2 +- tests/fail/stacked_borrows/aliasing_mut2.rs | 2 +- tests/fail/stacked_borrows/aliasing_mut3.rs | 2 +- tests/fail/stacked_borrows/aliasing_mut4.rs | 2 +- .../box_exclusive_violation1.rs | 2 +- .../stacked_borrows/buggy_as_mut_slice.rs | 2 +- .../stacked_borrows/buggy_split_at_mut.rs | 2 +- tests/fail/stacked_borrows/illegal_read4.rs | 2 +- tests/fail/stacked_borrows/illegal_read5.rs | 2 +- tests/fail/stacked_borrows/illegal_read6.rs | 2 +- tests/fail/stacked_borrows/illegal_read7.rs | 2 +- tests/fail/stacked_borrows/illegal_read8.rs | 2 +- tests/fail/stacked_borrows/illegal_write1.rs | 2 +- tests/fail/stacked_borrows/illegal_write2.rs | 2 +- tests/fail/stacked_borrows/illegal_write3.rs | 2 +- tests/fail/stacked_borrows/illegal_write4.rs | 2 +- tests/fail/stacked_borrows/interior_mut1.rs | 2 +- tests/fail/stacked_borrows/interior_mut2.rs | 2 +- .../invalidate_against_barrier1.rs | 2 +- .../invalidate_against_barrier2.rs | 2 +- .../fail/stacked_borrows/load_invalid_mut.rs | 2 +- .../fail/stacked_borrows/load_invalid_shr.rs | 2 +- .../mut_exclusive_violation1.rs | 2 +- .../mut_exclusive_violation2.rs | 2 +- tests/fail/stacked_borrows/outdated_local.rs | 2 +- .../fail/stacked_borrows/pass_invalid_mut.rs | 2 +- .../fail/stacked_borrows/pass_invalid_shr.rs | 2 +- .../fail/stacked_borrows/pointer_smuggling.rs | 2 +- tests/fail/stacked_borrows/raw_tracking.rs | 2 +- .../stacked_borrows/return_invalid_mut.rs | 2 +- .../return_invalid_mut_option.rs | 2 +- .../stacked_borrows/return_invalid_shr.rs | 2 +- .../return_invalid_shr_option.rs | 2 +- .../return_invalid_shr_tuple.rs | 2 +- .../shared_rw_borrows_are_weak1.rs | 2 +- .../shared_rw_borrows_are_weak2.rs | 2 +- .../stacked_borrows/shr_frozen_violation1.rs | 2 +- .../static_memory_modification.rs | 2 +- .../stacked_borrows/transmute-is-no-escape.rs | 2 +- tests/fail/stacked_borrows/unescaped_local.rs | 2 +- .../fail/stacked_borrows/unescaped_static.rs | 2 +- tests/fail/static_memory_modification1.rs | 2 +- tests/fail/static_memory_modification2.rs | 2 +- tests/fail/static_memory_modification3.rs | 2 +- .../sync/libc_pthread_cond_double_destroy.rs | 2 +- .../libc_pthread_condattr_double_destroy.rs | 2 +- .../sync/libc_pthread_mutex_NULL_deadlock.rs | 2 +- .../libc_pthread_mutex_default_deadlock.rs | 2 +- .../sync/libc_pthread_mutex_destroy_locked.rs | 2 +- .../sync/libc_pthread_mutex_double_destroy.rs | 2 +- .../libc_pthread_mutex_normal_deadlock.rs | 2 +- ...bc_pthread_mutex_normal_unlock_unlocked.rs | 2 +- .../libc_pthread_mutexattr_double_destroy.rs | 2 +- ...libc_pthread_rwlock_destroy_read_locked.rs | 2 +- ...ibc_pthread_rwlock_destroy_write_locked.rs | 2 +- .../libc_pthread_rwlock_double_destroy.rs | 2 +- .../libc_pthread_rwlock_unlock_unlocked.rs | 2 +- tests/fail/transmute-pair-uninit.rs | 2 +- tests/fail/type-too-large.rs | 2 +- .../unaligned_pointers/atomic_unaligned.rs | 2 +- .../fail/unaligned_pointers/dyn_alignment.rs | 2 +- .../intptrcast_alignment_check.rs | 2 +- .../unaligned_pointers/reference_to_packed.rs | 2 +- .../fail/unaligned_pointers/unaligned_ptr1.rs | 2 +- .../fail/unaligned_pointers/unaligned_ptr2.rs | 2 +- .../fail/unaligned_pointers/unaligned_ptr3.rs | 2 +- .../fail/unaligned_pointers/unaligned_ptr4.rs | 2 +- .../unaligned_ptr_addr_of.rs | 2 +- .../unaligned_pointers/unaligned_ptr_zst.rs | 2 +- tests/fail/uninit_byte_read.rs | 2 +- tests/fail/uninit_raw_ptr.rs | 2 +- tests/fail/unsized-local.rs | 2 +- tests/fail/unsupported_foreign_function.rs | 2 +- tests/fail/unsupported_signal.rs | 2 +- tests/fail/validity/cast_fn_ptr1.rs | 2 +- tests/fail/validity/cast_fn_ptr2.rs | 2 +- tests/fail/validity/dangling_ref1.rs | 2 +- tests/fail/validity/dangling_ref2.rs | 2 +- tests/fail/validity/dangling_ref3.rs | 2 +- tests/fail/validity/invalid_bool.rs | 2 +- tests/fail/validity/invalid_bool_uninit.rs | 2 +- tests/fail/validity/invalid_char.rs | 2 +- tests/fail/validity/invalid_char_uninit.rs | 2 +- tests/fail/validity/invalid_enum_tag.rs | 2 +- .../invalid_enum_tag_256variants_uninit.rs | 2 +- tests/fail/validity/invalid_fnptr_null.rs | 2 +- tests/fail/validity/invalid_fnptr_uninit.rs | 2 +- tests/fail/validity/nonzero.rs | 2 +- .../validity/ptr_integer_array_transmute.rs | 2 +- tests/fail/validity/ref_to_uninhabited1.rs | 2 +- tests/fail/validity/ref_to_uninhabited2.rs | 2 +- tests/fail/validity/transmute_through_ptr.rs | 2 +- tests/fail/validity/uninit_float.rs | 2 +- tests/fail/validity/uninit_integer.rs | 2 +- tests/fail/validity/uninit_integer_signed.rs | 2 +- tests/fail/zst1.rs | 2 +- tests/fail/zst2.rs | 2 +- tests/fail/zst3.rs | 2 +- ui_test/src/lib.rs | 40 +++---- ui_test/src/parser.rs | 31 ++++-- ui_test/src/parser/tests.rs | 46 ++++---- ui_test/src/rustc_stderr.rs | 5 +- ui_test/src/tests.rs | 101 +++++------------- 244 files changed, 348 insertions(+), 386 deletions(-) diff --git a/tests/fail/alloc/reallocate-change-alloc.rs b/tests/fail/alloc/reallocate-change-alloc.rs index 14d05e745751..3ad56da2c2ff 100644 --- a/tests/fail/alloc/reallocate-change-alloc.rs +++ b/tests/fail/alloc/reallocate-change-alloc.rs @@ -4,6 +4,6 @@ fn main() { unsafe { let x = alloc(Layout::from_size_align_unchecked(1, 1)); let _y = realloc(x, Layout::from_size_align_unchecked(1, 1), 1); - let _z = *x; //~ ERROR dereferenced after this allocation got freed + let _z = *x; //~ ERROR: dereferenced after this allocation got freed } } diff --git a/tests/fail/backtrace/bad-backtrace-decl.rs b/tests/fail/backtrace/bad-backtrace-decl.rs index 23379992d5ec..97a70103e646 100644 --- a/tests/fail/backtrace/bad-backtrace-decl.rs +++ b/tests/fail/backtrace/bad-backtrace-decl.rs @@ -7,7 +7,7 @@ fn main() { let frames = unsafe { miri_get_backtrace(0) }; for frame in frames.into_iter() { unsafe { - miri_resolve_frame(*frame, 0); //~ ERROR Undefined Behavior: bad declaration of miri_resolve_frame - should return a struct with 5 fields + miri_resolve_frame(*frame, 0); //~ ERROR: Undefined Behavior: bad declaration of miri_resolve_frame - should return a struct with 5 fields } } } diff --git a/tests/fail/backtrace/bad-backtrace-flags.rs b/tests/fail/backtrace/bad-backtrace-flags.rs index 9e24d32a3331..a4e186eaa98a 100644 --- a/tests/fail/backtrace/bad-backtrace-flags.rs +++ b/tests/fail/backtrace/bad-backtrace-flags.rs @@ -4,6 +4,6 @@ extern "Rust" { fn main() { unsafe { - miri_get_backtrace(2, std::ptr::null_mut()); //~ ERROR unsupported operation: unknown `miri_get_backtrace` flags 2 + miri_get_backtrace(2, std::ptr::null_mut()); //~ ERROR: unsupported operation: unknown `miri_get_backtrace` flags 2 } } diff --git a/tests/fail/backtrace/bad-backtrace-ptr.rs b/tests/fail/backtrace/bad-backtrace-ptr.rs index a435b0a69578..843d0d11873d 100644 --- a/tests/fail/backtrace/bad-backtrace-ptr.rs +++ b/tests/fail/backtrace/bad-backtrace-ptr.rs @@ -4,6 +4,6 @@ extern "Rust" { fn main() { unsafe { - miri_resolve_frame(std::ptr::null_mut(), 0); //~ ERROR null pointer is a dangling pointer + miri_resolve_frame(std::ptr::null_mut(), 0); //~ ERROR: null pointer is a dangling pointer } } diff --git a/tests/fail/backtrace/bad-backtrace-resolve-flags.rs b/tests/fail/backtrace/bad-backtrace-resolve-flags.rs index 2d4d6195029d..31e3915f3d64 100644 --- a/tests/fail/backtrace/bad-backtrace-resolve-flags.rs +++ b/tests/fail/backtrace/bad-backtrace-resolve-flags.rs @@ -20,6 +20,6 @@ fn main() { miri_get_backtrace(1, buf.as_mut_ptr()); // miri_resolve_frame will error from an invalid backtrace before it will from invalid flags - miri_resolve_frame(buf[0], 2); //~ ERROR unsupported operation: unknown `miri_resolve_frame` flags 2 + miri_resolve_frame(buf[0], 2); //~ ERROR: unsupported operation: unknown `miri_resolve_frame` flags 2 } } diff --git a/tests/fail/backtrace/bad-backtrace-resolve-names-flags.rs b/tests/fail/backtrace/bad-backtrace-resolve-names-flags.rs index 6cea1fec1b24..44c3c025043b 100644 --- a/tests/fail/backtrace/bad-backtrace-resolve-names-flags.rs +++ b/tests/fail/backtrace/bad-backtrace-resolve-names-flags.rs @@ -11,6 +11,6 @@ fn main() { miri_get_backtrace(1, buf.as_mut_ptr()); // miri_resolve_frame_names will error from an invalid backtrace before it will from invalid flags - miri_resolve_frame_names(buf[0], 2, std::ptr::null_mut(), std::ptr::null_mut()); //~ ERROR unsupported operation: unknown `miri_resolve_frame_names` flags 2 + miri_resolve_frame_names(buf[0], 2, std::ptr::null_mut(), std::ptr::null_mut()); //~ ERROR: unsupported operation: unknown `miri_resolve_frame_names` flags 2 } } diff --git a/tests/fail/backtrace/bad-backtrace-size-flags.rs b/tests/fail/backtrace/bad-backtrace-size-flags.rs index 25eded9e48df..bba74c71a5e8 100644 --- a/tests/fail/backtrace/bad-backtrace-size-flags.rs +++ b/tests/fail/backtrace/bad-backtrace-size-flags.rs @@ -4,6 +4,6 @@ extern "Rust" { fn main() { unsafe { - miri_backtrace_size(2); //~ ERROR unsupported operation: unknown `miri_backtrace_size` flags 2 + miri_backtrace_size(2); //~ ERROR: unsupported operation: unknown `miri_backtrace_size` flags 2 } } diff --git a/tests/fail/box-cell-alias.rs b/tests/fail/box-cell-alias.rs index 319845d86a63..1a4a3b97ea3f 100644 --- a/tests/fail/box-cell-alias.rs +++ b/tests/fail/box-cell-alias.rs @@ -6,7 +6,7 @@ use std::cell::Cell; fn helper(val: Box>, ptr: *const Cell) -> u8 { val.set(10); - unsafe { (*ptr).set(20) }; //~ ERROR does not exist in the borrow stack + unsafe { (*ptr).set(20) }; //~ ERROR: does not exist in the borrow stack val.get() } diff --git a/tests/fail/branchless-select-i128-pointer.rs b/tests/fail/branchless-select-i128-pointer.rs index a3b4021ba0c2..2b861e5447b0 100644 --- a/tests/fail/branchless-select-i128-pointer.rs +++ b/tests/fail/branchless-select-i128-pointer.rs @@ -12,7 +12,7 @@ fn main() { // However, it drops provenance when transmuting to TwoPtrs, so this is UB. let val = unsafe { transmute::<_, &str>( - //~^ ERROR constructing invalid value: encountered a dangling reference + //~^ ERROR: constructing invalid value: encountered a dangling reference !mask & transmute::<_, TwoPtrs>("false !") | mask & transmute::<_, TwoPtrs>("true !"), ) diff --git a/tests/fail/breakpoint.rs b/tests/fail/breakpoint.rs index d0a0239eb933..fb1d4d958ee6 100644 --- a/tests/fail/breakpoint.rs +++ b/tests/fail/breakpoint.rs @@ -2,6 +2,6 @@ fn main() { unsafe { - core::intrinsics::breakpoint() //~ ERROR Trace/breakpoint trap + core::intrinsics::breakpoint() //~ ERROR: Trace/breakpoint trap }; } diff --git a/tests/fail/concurrency/thread_local_static_dealloc.rs b/tests/fail/concurrency/thread_local_static_dealloc.rs index 8cca1eba2d86..f638e21901dd 100644 --- a/tests/fail/concurrency/thread_local_static_dealloc.rs +++ b/tests/fail/concurrency/thread_local_static_dealloc.rs @@ -13,6 +13,6 @@ unsafe impl Send for SendRaw {} fn main() { unsafe { let dangling_ptr = std::thread::spawn(|| SendRaw(&TLS as *const u8)).join().unwrap(); - let _val = *dangling_ptr.0; //~ ERROR dereferenced after this allocation got freed + let _val = *dangling_ptr.0; //~ ERROR: dereferenced after this allocation got freed } } diff --git a/tests/fail/concurrency/unwind_top_of_stack.rs b/tests/fail/concurrency/unwind_top_of_stack.rs index d5dfcd0871d8..3bd9284c7c8a 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.rs +++ b/tests/fail/concurrency/unwind_top_of_stack.rs @@ -10,7 +10,7 @@ extern crate libc; use std::{mem, ptr}; extern "C-unwind" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { - //~^ ERROR unwinding past the topmost frame of the stack + //~^ ERROR: unwinding past the topmost frame of the stack panic!() } diff --git a/tests/fail/dangling_pointers/dangling_pointer_addr_of.rs b/tests/fail/dangling_pointers/dangling_pointer_addr_of.rs index a38a44c18f47..4249c1cbf017 100644 --- a/tests/fail/dangling_pointers/dangling_pointer_addr_of.rs +++ b/tests/fail/dangling_pointers/dangling_pointer_addr_of.rs @@ -7,6 +7,6 @@ fn main() { let b = Box::new(42); &*b as *const i32 }; - let x = unsafe { ptr::addr_of!(*p) }; //~ ERROR dereferenced after this allocation got freed + let x = unsafe { ptr::addr_of!(*p) }; //~ ERROR: dereferenced after this allocation got freed panic!("this should never print: {:?}", x); } diff --git a/tests/fail/dangling_pointers/dangling_pointer_deref.rs b/tests/fail/dangling_pointers/dangling_pointer_deref.rs index 55b5205a8b30..ad2a599b60b4 100644 --- a/tests/fail/dangling_pointers/dangling_pointer_deref.rs +++ b/tests/fail/dangling_pointers/dangling_pointer_deref.rs @@ -6,6 +6,6 @@ fn main() { let b = Box::new(42); &*b as *const i32 }; - let x = unsafe { *p }; //~ ERROR dereferenced after this allocation got freed + let x = unsafe { *p }; //~ ERROR: dereferenced after this allocation got freed panic!("this should never print: {}", x); } diff --git a/tests/fail/dangling_pointers/dangling_zst_deref.rs b/tests/fail/dangling_pointers/dangling_zst_deref.rs index 2a09dc4b0e89..534d7d5f42f3 100644 --- a/tests/fail/dangling_pointers/dangling_zst_deref.rs +++ b/tests/fail/dangling_pointers/dangling_zst_deref.rs @@ -7,5 +7,5 @@ fn main() { let b = Box::new(42); &*b as *const i32 as *const () }; - let _x = unsafe { *p }; //~ ERROR dereferenced after this allocation got freed + let _x = unsafe { *p }; //~ ERROR: dereferenced after this allocation got freed } diff --git a/tests/fail/dangling_pointers/deref-invalid-ptr.rs b/tests/fail/dangling_pointers/deref-invalid-ptr.rs index 924021e8cb93..57e95ef19dc9 100644 --- a/tests/fail/dangling_pointers/deref-invalid-ptr.rs +++ b/tests/fail/dangling_pointers/deref-invalid-ptr.rs @@ -3,5 +3,5 @@ fn main() { let x = 16usize as *const u32; - let _y = unsafe { &*x as *const u32 }; //~ ERROR is a dangling pointer + let _y = unsafe { &*x as *const u32 }; //~ ERROR: is a dangling pointer } diff --git a/tests/fail/dangling_pointers/deref-partially-dangling.rs b/tests/fail/dangling_pointers/deref-partially-dangling.rs index b7fcf4559e0a..27040c26dc21 100644 --- a/tests/fail/dangling_pointers/deref-partially-dangling.rs +++ b/tests/fail/dangling_pointers/deref-partially-dangling.rs @@ -3,6 +3,6 @@ fn main() { let x = (1, 13); let xptr = &x as *const _ as *const (i32, i32, i32); - let val = unsafe { (*xptr).1 }; //~ ERROR pointer to 12 bytes starting at offset 0 is out-of-bounds + let val = unsafe { (*xptr).1 }; //~ ERROR: pointer to 12 bytes starting at offset 0 is out-of-bounds assert_eq!(val, 13); } diff --git a/tests/fail/dangling_pointers/dyn_size.rs b/tests/fail/dangling_pointers/dyn_size.rs index adb7febe5074..54f353ebebeb 100644 --- a/tests/fail/dangling_pointers/dyn_size.rs +++ b/tests/fail/dangling_pointers/dyn_size.rs @@ -9,5 +9,5 @@ fn main() { // That should be UB, as the reference is not fully dereferencable. let ptr: *const SliceWithHead = unsafe { std::mem::transmute((&buf, 4usize)) }; // Re-borrow that. This should be UB. - let _ptr = unsafe { &*ptr }; //~ ERROR pointer to 5 bytes starting at offset 0 is out-of-bounds + let _ptr = unsafe { &*ptr }; //~ ERROR: pointer to 5 bytes starting at offset 0 is out-of-bounds } diff --git a/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.rs b/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.rs index 37fb91e28f29..a48a3189db2e 100644 --- a/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.rs +++ b/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.rs @@ -4,5 +4,5 @@ fn main() { // This pointer *could* be NULL so we cannot load from it, not even at ZST let ptr = (&0u8 as *const u8).wrapping_sub(0x800) as *const (); - let _x: () = unsafe { *ptr }; //~ ERROR out-of-bounds + let _x: () = unsafe { *ptr }; //~ ERROR: out-of-bounds } diff --git a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs index de8034bbbac3..449c65d218a0 100644 --- a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs +++ b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs @@ -7,5 +7,5 @@ fn main() { // Also not assigning directly as that's array initialization, not assignment. let zst_val = [1u8; 0]; let ptr = (&0u8 as *const u8).wrapping_sub(0x800) as *mut [u8; 0]; - unsafe { *ptr = zst_val }; //~ ERROR out-of-bounds + unsafe { *ptr = zst_val }; //~ ERROR: out-of-bounds } diff --git a/tests/fail/dangling_pointers/null_pointer_deref.rs b/tests/fail/dangling_pointers/null_pointer_deref.rs index dad6de85e002..a0773c63cf6b 100644 --- a/tests/fail/dangling_pointers/null_pointer_deref.rs +++ b/tests/fail/dangling_pointers/null_pointer_deref.rs @@ -1,5 +1,5 @@ #[allow(deref_nullptr)] fn main() { - let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR null pointer is a dangling pointer + let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR: null pointer is a dangling pointer panic!("this should never print: {}", x); } diff --git a/tests/fail/dangling_pointers/null_pointer_deref_zst.rs b/tests/fail/dangling_pointers/null_pointer_deref_zst.rs index 1f73983a8161..d6a607c61cbe 100644 --- a/tests/fail/dangling_pointers/null_pointer_deref_zst.rs +++ b/tests/fail/dangling_pointers/null_pointer_deref_zst.rs @@ -3,6 +3,6 @@ #[allow(deref_nullptr)] fn main() { - let x: () = unsafe { *std::ptr::null() }; //~ ERROR dereferencing pointer failed: null pointer is a dangling pointer + let x: () = unsafe { *std::ptr::null() }; //~ ERROR: dereferencing pointer failed: null pointer is a dangling pointer panic!("this should never print: {:?}", x); } diff --git a/tests/fail/dangling_pointers/null_pointer_write.rs b/tests/fail/dangling_pointers/null_pointer_write.rs index c7255baf6642..954596f57542 100644 --- a/tests/fail/dangling_pointers/null_pointer_write.rs +++ b/tests/fail/dangling_pointers/null_pointer_write.rs @@ -1,4 +1,4 @@ #[allow(deref_nullptr)] fn main() { - unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR null pointer is a dangling pointer + unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR: null pointer is a dangling pointer } diff --git a/tests/fail/dangling_pointers/out_of_bounds_read1.rs b/tests/fail/dangling_pointers/out_of_bounds_read1.rs index ef5cdeec9967..58a64eecace8 100644 --- a/tests/fail/dangling_pointers/out_of_bounds_read1.rs +++ b/tests/fail/dangling_pointers/out_of_bounds_read1.rs @@ -1,5 +1,5 @@ fn main() { let v: Vec = vec![1, 2]; - let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR out-of-bounds + let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR: out-of-bounds panic!("this should never print: {}", x); } diff --git a/tests/fail/dangling_pointers/out_of_bounds_read2.rs b/tests/fail/dangling_pointers/out_of_bounds_read2.rs index ef5cdeec9967..58a64eecace8 100644 --- a/tests/fail/dangling_pointers/out_of_bounds_read2.rs +++ b/tests/fail/dangling_pointers/out_of_bounds_read2.rs @@ -1,5 +1,5 @@ fn main() { let v: Vec = vec![1, 2]; - let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR out-of-bounds + let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR: out-of-bounds panic!("this should never print: {}", x); } diff --git a/tests/fail/dangling_pointers/stack_temporary.rs b/tests/fail/dangling_pointers/stack_temporary.rs index dc446ca4b3c8..1373773f68d5 100644 --- a/tests/fail/dangling_pointers/stack_temporary.rs +++ b/tests/fail/dangling_pointers/stack_temporary.rs @@ -8,7 +8,7 @@ unsafe fn make_ref<'a>(x: *mut i32) -> &'a mut i32 { fn main() { unsafe { let x = make_ref(&mut 0); // The temporary storing "0" is deallocated at the ";"! - let val = *x; //~ ERROR dereferenced after this allocation got freed + let val = *x; //~ ERROR: dereferenced after this allocation got freed println!("{}", val); } } diff --git a/tests/fail/dangling_pointers/storage_dead_dangling.rs b/tests/fail/dangling_pointers/storage_dead_dangling.rs index 10c6e7f97d2e..03113585d146 100644 --- a/tests/fail/dangling_pointers/storage_dead_dangling.rs +++ b/tests/fail/dangling_pointers/storage_dead_dangling.rs @@ -10,7 +10,7 @@ fn fill(v: &mut i32) { } fn evil() { - unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR is a dangling pointer + unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR: is a dangling pointer } fn main() { diff --git a/tests/fail/dangling_pointers/wild_pointer_deref.rs b/tests/fail/dangling_pointers/wild_pointer_deref.rs index 15d71a6bcccd..9ffc68146550 100644 --- a/tests/fail/dangling_pointers/wild_pointer_deref.rs +++ b/tests/fail/dangling_pointers/wild_pointer_deref.rs @@ -2,6 +2,6 @@ fn main() { let p = 44 as *const i32; - let x = unsafe { *p }; //~ ERROR is a dangling pointer + let x = unsafe { *p }; //~ ERROR: is a dangling pointer panic!("this should never print: {}", x); } diff --git a/tests/fail/data_race/alloc_read_race.rs b/tests/fail/data_race/alloc_read_race.rs index e3c003a343a0..bdd38ea05693 100644 --- a/tests/fail/data_race/alloc_read_race.rs +++ b/tests/fail/data_race/alloc_read_race.rs @@ -38,7 +38,7 @@ pub fn main() { let pointer = &*ptr.0; // Note: could also error due to reading uninitialized memory, but the data-race detector triggers first. - *pointer.load(Ordering::Relaxed) //~ ERROR Data race detected between Read on thread `` and Allocate on thread `` + *pointer.load(Ordering::Relaxed) //~ ERROR: Data race detected between Read on thread `` and Allocate on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/alloc_write_race.rs b/tests/fail/data_race/alloc_write_race.rs index 4ad03ee87dda..1322f727e6f0 100644 --- a/tests/fail/data_race/alloc_write_race.rs +++ b/tests/fail/data_race/alloc_write_race.rs @@ -36,7 +36,7 @@ pub fn main() { let j2 = spawn(move || { let pointer = &*ptr.0; - *pointer.load(Ordering::Relaxed) = 2; //~ ERROR Data race detected between Write on thread `` and Allocate on thread `` + *pointer.load(Ordering::Relaxed) = 2; //~ ERROR: Data race detected between Write on thread `` and Allocate on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_read_na_write_race1.rs b/tests/fail/data_race/atomic_read_na_write_race1.rs index ada25173f255..3cdb9d4a6543 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.rs +++ b/tests/fail/data_race/atomic_read_na_write_race1.rs @@ -24,7 +24,7 @@ pub fn main() { let j2 = spawn(move || { //Equivalent to: (&*c.0).load(Ordering::SeqCst) - intrinsics::atomic_load_seqcst(c.0 as *mut usize) //~ ERROR Data race detected between Atomic Load on thread `` and Write on thread `` + intrinsics::atomic_load_seqcst(c.0 as *mut usize) //~ ERROR: Data race detected between Atomic Load on thread `` and Write on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_read_na_write_race2.rs b/tests/fail/data_race/atomic_read_na_write_race2.rs index b355e4816dde..79f9cceb5c9c 100644 --- a/tests/fail/data_race/atomic_read_na_write_race2.rs +++ b/tests/fail/data_race/atomic_read_na_write_race2.rs @@ -24,7 +24,7 @@ pub fn main() { let j2 = spawn(move || { let atomic_ref = &mut *c.0; - *atomic_ref.get_mut() = 32; //~ ERROR Data race detected between Write on thread `` and Atomic Load on thread `` + *atomic_ref.get_mut() = 32; //~ ERROR: Data race detected between Write on thread `` and Atomic Load on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_write_na_read_race1.rs b/tests/fail/data_race/atomic_write_na_read_race1.rs index 53305c68cb76..6e9f37a9c43b 100644 --- a/tests/fail/data_race/atomic_write_na_read_race1.rs +++ b/tests/fail/data_race/atomic_write_na_read_race1.rs @@ -24,7 +24,7 @@ pub fn main() { let j2 = spawn(move || { let atomic_ref = &mut *c.0; - *atomic_ref.get_mut() //~ ERROR Data race detected between Read on thread `` and Atomic Store on thread `` + *atomic_ref.get_mut() //~ ERROR: Data race detected between Read on thread `` and Atomic Store on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_write_na_read_race2.rs b/tests/fail/data_race/atomic_write_na_read_race2.rs index 21b0abbcaba9..4ab5abd5a3ee 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.rs +++ b/tests/fail/data_race/atomic_write_na_read_race2.rs @@ -24,7 +24,7 @@ pub fn main() { let j2 = spawn(move || { //Equivalent to: (&*c.0).store(32, Ordering::SeqCst) - atomic_store(c.0 as *mut usize, 32); //~ ERROR Data race detected between Atomic Store on thread `` and Read on thread `` + atomic_store(c.0 as *mut usize, 32); //~ ERROR: Data race detected between Atomic Store on thread `` and Read on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_write_na_write_race1.rs b/tests/fail/data_race/atomic_write_na_write_race1.rs index a8ac18f32136..4c4ec0865cc9 100644 --- a/tests/fail/data_race/atomic_write_na_write_race1.rs +++ b/tests/fail/data_race/atomic_write_na_write_race1.rs @@ -24,7 +24,7 @@ pub fn main() { let j2 = spawn(move || { //Equivalent to: (&*c.0).store(64, Ordering::SeqCst) - atomic_store(c.0 as *mut usize, 64); //~ ERROR Data race detected between Atomic Store on thread `` and Write on thread `` + atomic_store(c.0 as *mut usize, 64); //~ ERROR: Data race detected between Atomic Store on thread `` and Write on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_write_na_write_race2.rs b/tests/fail/data_race/atomic_write_na_write_race2.rs index e3b3e226d8c7..715c2d44b260 100644 --- a/tests/fail/data_race/atomic_write_na_write_race2.rs +++ b/tests/fail/data_race/atomic_write_na_write_race2.rs @@ -24,7 +24,7 @@ pub fn main() { let j2 = spawn(move || { let atomic_ref = &mut *c.0; - *atomic_ref.get_mut() = 32; //~ ERROR Data race detected between Write on thread `` and Atomic Store on thread `` + *atomic_ref.get_mut() = 32; //~ ERROR: Data race detected between Write on thread `` and Atomic Store on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/dangling_thread_async_race.rs b/tests/fail/data_race/dangling_thread_async_race.rs index be06740201d2..732e89c89907 100644 --- a/tests/fail/data_race/dangling_thread_async_race.rs +++ b/tests/fail/data_race/dangling_thread_async_race.rs @@ -35,7 +35,7 @@ fn main() { let join2 = unsafe { spawn(move || { - *c.0 = 64; //~ ERROR Data race detected between Write on thread `` and Write on thread `` + *c.0 = 64; //~ ERROR: Data race detected between Write on thread `` and Write on thread `` }) }; diff --git a/tests/fail/data_race/dangling_thread_race.rs b/tests/fail/data_race/dangling_thread_race.rs index 90957e4026e3..170fa8b77440 100644 --- a/tests/fail/data_race/dangling_thread_race.rs +++ b/tests/fail/data_race/dangling_thread_race.rs @@ -34,6 +34,6 @@ fn main() { spawn(|| ()).join().unwrap(); unsafe { - *c.0 = 64; //~ ERROR Data race detected between Write on thread `main` and Write on thread `` + *c.0 = 64; //~ ERROR: Data race detected between Write on thread `main` and Write on thread `` } } diff --git a/tests/fail/data_race/dealloc_read_race1.rs b/tests/fail/data_race/dealloc_read_race1.rs index b37f4fda2bd4..80a0fe2111ec 100644 --- a/tests/fail/data_race/dealloc_read_race1.rs +++ b/tests/fail/data_race/dealloc_read_race1.rs @@ -26,7 +26,7 @@ pub fn main() { let j2 = spawn(move || { __rust_dealloc( - //~^ ERROR Data race detected between Deallocate on thread `` and Read on thread `` + //~^ ERROR: Data race detected between Deallocate on thread `` and Read on thread `` ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::(), diff --git a/tests/fail/data_race/dealloc_read_race2.rs b/tests/fail/data_race/dealloc_read_race2.rs index 280b86924be8..898588a1a0e8 100644 --- a/tests/fail/data_race/dealloc_read_race2.rs +++ b/tests/fail/data_race/dealloc_read_race2.rs @@ -31,7 +31,7 @@ pub fn main() { let j2 = spawn(move || { // Also an error of the form: Data race detected between Read on thread `` and Deallocate on thread `` // but the invalid allocation is detected first. - *ptr.0 //~ ERROR dereferenced after this allocation got freed + *ptr.0 //~ ERROR: dereferenced after this allocation got freed }); j1.join().unwrap(); diff --git a/tests/fail/data_race/dealloc_read_race_stack.rs b/tests/fail/data_race/dealloc_read_race_stack.rs index a43c96a6701e..475379a02ecf 100644 --- a/tests/fail/data_race/dealloc_read_race_stack.rs +++ b/tests/fail/data_race/dealloc_read_race_stack.rs @@ -36,7 +36,7 @@ pub fn main() { sleep(Duration::from_millis(200)); // Now `stack_var` gets deallocated. - } //~ ERROR Data race detected between Deallocate on thread `` and Read on thread `` + } //~ ERROR: Data race detected between Deallocate on thread `` and Read on thread `` }); let j2 = spawn(move || { diff --git a/tests/fail/data_race/dealloc_write_race1.rs b/tests/fail/data_race/dealloc_write_race1.rs index 17fb444f9c63..711b7ba9d4eb 100644 --- a/tests/fail/data_race/dealloc_write_race1.rs +++ b/tests/fail/data_race/dealloc_write_race1.rs @@ -25,7 +25,7 @@ pub fn main() { let j2 = spawn(move || { __rust_dealloc( - //~^ ERROR Data race detected between Deallocate on thread `` and Write on thread `` + //~^ ERROR: Data race detected between Deallocate on thread `` and Write on thread `` ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::(), diff --git a/tests/fail/data_race/dealloc_write_race2.rs b/tests/fail/data_race/dealloc_write_race2.rs index 6afb1182a029..e7b7d558ed9d 100644 --- a/tests/fail/data_race/dealloc_write_race2.rs +++ b/tests/fail/data_race/dealloc_write_race2.rs @@ -30,7 +30,7 @@ pub fn main() { let j2 = spawn(move || { // Also an error of the form: Data race detected between Write on thread `` and Deallocate on thread `` // but the invalid allocation is detected first. - *ptr.0 = 2; //~ ERROR dereferenced after this allocation got freed + *ptr.0 = 2; //~ ERROR: dereferenced after this allocation got freed }); j1.join().unwrap(); diff --git a/tests/fail/data_race/dealloc_write_race_stack.rs b/tests/fail/data_race/dealloc_write_race_stack.rs index 6b87cbe61cad..7f6beb7f32d8 100644 --- a/tests/fail/data_race/dealloc_write_race_stack.rs +++ b/tests/fail/data_race/dealloc_write_race_stack.rs @@ -36,7 +36,7 @@ pub fn main() { sleep(Duration::from_millis(200)); // Now `stack_var` gets deallocated. - } //~ ERROR Data race detected between Deallocate on thread `` and Write on thread `` + } //~ ERROR: Data race detected between Deallocate on thread `` and Write on thread `` }); let j2 = spawn(move || { diff --git a/tests/fail/data_race/enable_after_join_to_main.rs b/tests/fail/data_race/enable_after_join_to_main.rs index 290589690a38..2e9fce198d1d 100644 --- a/tests/fail/data_race/enable_after_join_to_main.rs +++ b/tests/fail/data_race/enable_after_join_to_main.rs @@ -31,7 +31,7 @@ pub fn main() { }); let j2 = spawn(move || { - *c.0 = 64; //~ ERROR Data race detected between Write on thread `` and Write on thread `` + *c.0 = 64; //~ ERROR: Data race detected between Write on thread `` and Write on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/fence_after_load.rs b/tests/fail/data_race/fence_after_load.rs index 7a8d66bf8f29..f41c7a25523e 100644 --- a/tests/fail/data_race/fence_after_load.rs +++ b/tests/fail/data_race/fence_after_load.rs @@ -21,5 +21,5 @@ fn main() { // The fence is useless, since it did not happen-after the `store` in the other thread. // Hence this is a data race. // Also see https://github.com/rust-lang/miri/issues/2192. - unsafe { V = 2 } //~ERROR Data race detected between Write on thread `main` and Write on thread `` + unsafe { V = 2 } //~ERROR: Data race detected between Write on thread `main` and Write on thread `` } diff --git a/tests/fail/data_race/read_write_race.rs b/tests/fail/data_race/read_write_race.rs index 4c1d87746d72..e1134669f782 100644 --- a/tests/fail/data_race/read_write_race.rs +++ b/tests/fail/data_race/read_write_race.rs @@ -20,7 +20,7 @@ pub fn main() { }); let j2 = spawn(move || { - *c.0 = 64; //~ ERROR Data race detected between Write on thread `` and Read on thread `` + *c.0 = 64; //~ ERROR: Data race detected between Write on thread `` and Read on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/read_write_race_stack.rs b/tests/fail/data_race/read_write_race_stack.rs index 3999c57bcf42..802e90d222af 100644 --- a/tests/fail/data_race/read_write_race_stack.rs +++ b/tests/fail/data_race/read_write_race_stack.rs @@ -43,7 +43,7 @@ pub fn main() { sleep(Duration::from_millis(200)); - stack_var //~ ERROR Data race detected between Read on thread `` and Write on thread `` + stack_var //~ ERROR: Data race detected between Read on thread `` and Write on thread `` }); let j2 = spawn(move || { diff --git a/tests/fail/data_race/relax_acquire_race.rs b/tests/fail/data_race/relax_acquire_race.rs index 3038efe99efa..4238372f21fa 100644 --- a/tests/fail/data_race/relax_acquire_race.rs +++ b/tests/fail/data_race/relax_acquire_race.rs @@ -38,7 +38,7 @@ pub fn main() { let j3 = spawn(move || { if SYNC.load(Ordering::Acquire) == 2 { - *c.0 //~ ERROR Data race detected between Read on thread `` and Write on thread `` + *c.0 //~ ERROR: Data race detected between Read on thread `` and Write on thread `` } else { 0 } diff --git a/tests/fail/data_race/release_seq_race.rs b/tests/fail/data_race/release_seq_race.rs index ca227bf5ad29..cd11aac95955 100644 --- a/tests/fail/data_race/release_seq_race.rs +++ b/tests/fail/data_race/release_seq_race.rs @@ -42,7 +42,7 @@ pub fn main() { let j3 = spawn(move || { sleep(Duration::from_millis(500)); if SYNC.load(Ordering::Acquire) == 3 { - *c.0 //~ ERROR Data race detected between Read on thread `` and Write on thread `` + *c.0 //~ ERROR: Data race detected between Read on thread `` and Write on thread `` } else { 0 } diff --git a/tests/fail/data_race/release_seq_race_same_thread.rs b/tests/fail/data_race/release_seq_race_same_thread.rs index c9b0cd7773ef..854ea09f11eb 100644 --- a/tests/fail/data_race/release_seq_race_same_thread.rs +++ b/tests/fail/data_race/release_seq_race_same_thread.rs @@ -38,7 +38,7 @@ pub fn main() { let j2 = spawn(move || { if SYNC.load(Ordering::Acquire) == 2 { - *c.0 //~ ERROR Data race detected between Read on thread `` and Write on thread `` + *c.0 //~ ERROR: Data race detected between Read on thread `` and Write on thread `` } else { 0 } diff --git a/tests/fail/data_race/rmw_race.rs b/tests/fail/data_race/rmw_race.rs index ca8123177ab3..2f7f8986a49e 100644 --- a/tests/fail/data_race/rmw_race.rs +++ b/tests/fail/data_race/rmw_race.rs @@ -39,7 +39,7 @@ pub fn main() { let j3 = spawn(move || { if SYNC.load(Ordering::Acquire) == 3 { - *c.0 //~ ERROR Data race detected between Read on thread `` and Write on thread `` + *c.0 //~ ERROR: Data race detected between Read on thread `` and Write on thread `` } else { 0 } diff --git a/tests/fail/data_race/stack_pop_race.rs b/tests/fail/data_race/stack_pop_race.rs index a31c434604bb..444c28d50aaf 100644 --- a/tests/fail/data_race/stack_pop_race.rs +++ b/tests/fail/data_race/stack_pop_race.rs @@ -22,4 +22,4 @@ fn race(local: i32) { // Deallocating the local (when `main` returns) // races with the read in the other thread. // Make sure the error points at this function's end, not just the call site. -} //~ERROR Data race detected between Deallocate on thread `main` and Read on thread `` +} //~ERROR: Data race detected between Deallocate on thread `main` and Read on thread `` diff --git a/tests/fail/data_race/write_write_race.rs b/tests/fail/data_race/write_write_race.rs index de4d4d70c500..fae4582e7e47 100644 --- a/tests/fail/data_race/write_write_race.rs +++ b/tests/fail/data_race/write_write_race.rs @@ -20,7 +20,7 @@ pub fn main() { }); let j2 = spawn(move || { - *c.0 = 64; //~ ERROR Data race detected between Write on thread `` and Write on thread `` + *c.0 = 64; //~ ERROR: Data race detected between Write on thread `` and Write on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/write_write_race_stack.rs b/tests/fail/data_race/write_write_race_stack.rs index 96b40affaed0..4b83413b3922 100644 --- a/tests/fail/data_race/write_write_race_stack.rs +++ b/tests/fail/data_race/write_write_race_stack.rs @@ -40,7 +40,7 @@ pub fn main() { sleep(Duration::from_millis(200)); - stack_var = 1usize; //~ ERROR Data race detected between Write on thread `` and Write on thread `` + stack_var = 1usize; //~ ERROR: Data race detected between Write on thread `` and Write on thread `` // read to silence errors stack_var diff --git a/tests/fail/environ-gets-deallocated.rs b/tests/fail/environ-gets-deallocated.rs index 34941b944923..39629610c632 100644 --- a/tests/fail/environ-gets-deallocated.rs +++ b/tests/fail/environ-gets-deallocated.rs @@ -20,5 +20,5 @@ fn main() { let pointer = get_environ(); let _x = unsafe { *pointer }; std::env::set_var("FOO", "BAR"); - let _y = unsafe { *pointer }; //~ ERROR dereferenced after this allocation got freed + let _y = unsafe { *pointer }; //~ ERROR: dereferenced after this allocation got freed } diff --git a/tests/fail/erroneous_const.rs b/tests/fail/erroneous_const.rs index ce1392d102b7..c35a90503593 100644 --- a/tests/fail/erroneous_const.rs +++ b/tests/fail/erroneous_const.rs @@ -7,12 +7,12 @@ struct PrintName(T); impl PrintName { - const VOID: ! = panic!(); //~ERROR evaluation of `PrintName::::VOID` failed + const VOID: ! = panic!(); //~ERROR: evaluation of `PrintName::::VOID` failed } fn no_codegen() { if false { - let _ = PrintName::::VOID; //~ERROR post-monomorphization error + let _ = PrintName::::VOID; //~ERROR: post-monomorphization error } } fn main() { diff --git a/tests/fail/erroneous_const2.rs b/tests/fail/erroneous_const2.rs index dc68cd64d738..6628166cfacd 100644 --- a/tests/fail/erroneous_const2.rs +++ b/tests/fail/erroneous_const2.rs @@ -1,13 +1,13 @@ const X: u32 = 5; const Y: u32 = 6; const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; -//~^ERROR any use of this value -//~|WARN previously accepted +//~^ERROR: any use of this value +//~|WARN: previously accepted #[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/5391 fn main() { - println!("{}", FOO); //~ERROR post-monomorphization error - //~|ERROR evaluation of constant value failed - //~|ERROR erroneous constant used - //~|WARN previously accepted + println!("{}", FOO); //~ERROR: post-monomorphization error + //~|ERROR: evaluation of constant value failed + //~|ERROR: erroneous constant used + //~|WARN: previously accepted } diff --git a/tests/fail/extern_static.rs b/tests/fail/extern_static.rs index f3466d5e7180..f8805db8d143 100644 --- a/tests/fail/extern_static.rs +++ b/tests/fail/extern_static.rs @@ -5,5 +5,5 @@ extern "C" { } fn main() { - let _val = unsafe { std::ptr::addr_of!(FOO) }; //~ ERROR is not supported by Miri + let _val = unsafe { std::ptr::addr_of!(FOO) }; //~ ERROR: is not supported by Miri } diff --git a/tests/fail/extern_static_in_const.rs b/tests/fail/extern_static_in_const.rs index 4c1de6ace51d..31c192bf44be 100644 --- a/tests/fail/extern_static_in_const.rs +++ b/tests/fail/extern_static_in_const.rs @@ -7,5 +7,5 @@ extern "C" { static X: &'static [u8; 0] = unsafe { &E }; fn main() { - let _val = X; //~ ERROR is not supported by Miri + let _val = X; //~ ERROR: is not supported by Miri } diff --git a/tests/fail/fast_math_both.rs b/tests/fail/fast_math_both.rs index 844e4e95211f..dd2787bf40f4 100644 --- a/tests/fail/fast_math_both.rs +++ b/tests/fail/fast_math_both.rs @@ -2,6 +2,6 @@ fn main() { unsafe { - let _x: f32 = core::intrinsics::fsub_fast(f32::NAN, f32::NAN); //~ ERROR `fsub_fast` intrinsic called with non-finite value as both parameters + let _x: f32 = core::intrinsics::fsub_fast(f32::NAN, f32::NAN); //~ ERROR: `fsub_fast` intrinsic called with non-finite value as both parameters } } diff --git a/tests/fail/fast_math_first.rs b/tests/fail/fast_math_first.rs index 470ebe620050..e495498ab286 100644 --- a/tests/fail/fast_math_first.rs +++ b/tests/fail/fast_math_first.rs @@ -2,6 +2,6 @@ fn main() { unsafe { - let _x: f32 = core::intrinsics::frem_fast(f32::NAN, 3.2); //~ ERROR `frem_fast` intrinsic called with non-finite value as first parameter + let _x: f32 = core::intrinsics::frem_fast(f32::NAN, 3.2); //~ ERROR: `frem_fast` intrinsic called with non-finite value as first parameter } } diff --git a/tests/fail/fast_math_second.rs b/tests/fail/fast_math_second.rs index e8d70a4a79e7..408c461077fc 100644 --- a/tests/fail/fast_math_second.rs +++ b/tests/fail/fast_math_second.rs @@ -2,6 +2,6 @@ fn main() { unsafe { - let _x: f32 = core::intrinsics::fmul_fast(3.4f32, f32::INFINITY); //~ ERROR `fmul_fast` intrinsic called with non-finite value as second parameter + let _x: f32 = core::intrinsics::fmul_fast(3.4f32, f32::INFINITY); //~ ERROR: `fmul_fast` intrinsic called with non-finite value as second parameter } } diff --git a/tests/fail/fs/close_stdout.rs b/tests/fail/fs/close_stdout.rs index 273701112877..3271722de0f9 100644 --- a/tests/fail/fs/close_stdout.rs +++ b/tests/fail/fs/close_stdout.rs @@ -9,6 +9,6 @@ extern crate libc; fn main() { unsafe { - libc::close(1); //~ ERROR stdout cannot be closed + libc::close(1); //~ ERROR: stdout cannot be closed } } diff --git a/tests/fail/fs/isolated_stdin.rs b/tests/fail/fs/isolated_stdin.rs index b41534c5c3a8..27c66c58eb2f 100644 --- a/tests/fail/fs/isolated_stdin.rs +++ b/tests/fail/fs/isolated_stdin.rs @@ -7,7 +7,7 @@ extern crate libc; fn main() -> std::io::Result<()> { let mut bytes = [0u8; 512]; unsafe { - libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512); //~ ERROR `read` from stdin not available when isolation is enabled + libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512); //~ ERROR: `read` from stdin not available when isolation is enabled } Ok(()) } diff --git a/tests/fail/fs/read_from_stdout.rs b/tests/fail/fs/read_from_stdout.rs index 4862bf0a162c..d78bc9f34d7d 100644 --- a/tests/fail/fs/read_from_stdout.rs +++ b/tests/fail/fs/read_from_stdout.rs @@ -8,7 +8,7 @@ extern crate libc; fn main() -> std::io::Result<()> { let mut bytes = [0u8; 512]; unsafe { - libc::read(1, bytes.as_mut_ptr() as *mut libc::c_void, 512); //~ ERROR cannot read from stdout + libc::read(1, bytes.as_mut_ptr() as *mut libc::c_void, 512); //~ ERROR: cannot read from stdout } Ok(()) } diff --git a/tests/fail/fs/unix_open_missing_required_mode.rs b/tests/fail/fs/unix_open_missing_required_mode.rs index e714d26e7835..03993db81f57 100644 --- a/tests/fail/fs/unix_open_missing_required_mode.rs +++ b/tests/fail/fs/unix_open_missing_required_mode.rs @@ -12,5 +12,5 @@ fn main() { fn test_file_open_missing_needed_mode() { let name = b"missing_arg.txt\0"; let name_ptr = name.as_ptr().cast::(); - let _fd = unsafe { libc::open(name_ptr, libc::O_CREAT) }; //~ ERROR Undefined Behavior: incorrect number of arguments for `open` with `O_CREAT`: got 2, expected at least 3 + let _fd = unsafe { libc::open(name_ptr, libc::O_CREAT) }; //~ ERROR: Undefined Behavior: incorrect number of arguments for `open` with `O_CREAT`: got 2, expected at least 3 } diff --git a/tests/fail/fs/write_to_stdin.rs b/tests/fail/fs/write_to_stdin.rs index 9d55a60b64b8..78ea0f4a18bd 100644 --- a/tests/fail/fs/write_to_stdin.rs +++ b/tests/fail/fs/write_to_stdin.rs @@ -7,7 +7,7 @@ extern crate libc; fn main() -> std::io::Result<()> { let bytes = b"hello"; unsafe { - libc::write(0, bytes.as_ptr() as *const libc::c_void, 5); //~ ERROR cannot write to stdin + libc::write(0, bytes.as_ptr() as *const libc::c_void, 5); //~ ERROR: cannot write to stdin } Ok(()) } diff --git a/tests/fail/function_calls/check_arg_abi.rs b/tests/fail/function_calls/check_arg_abi.rs index 5656c7a0e4cb..ffa0443ce507 100644 --- a/tests/fail/function_calls/check_arg_abi.rs +++ b/tests/fail/function_calls/check_arg_abi.rs @@ -4,6 +4,6 @@ fn main() { } unsafe { - let _ = malloc(0); //~ ERROR calling a function with ABI C using caller ABI Rust + let _ = malloc(0); //~ ERROR: calling a function with ABI C using caller ABI Rust }; } diff --git a/tests/fail/function_calls/check_arg_count_abort.rs b/tests/fail/function_calls/check_arg_count_abort.rs index 85e1b9deeb36..967a78bf8318 100644 --- a/tests/fail/function_calls/check_arg_count_abort.rs +++ b/tests/fail/function_calls/check_arg_count_abort.rs @@ -5,6 +5,6 @@ fn main() { unsafe { abort(1); - //~^ ERROR Undefined Behavior: incorrect number of arguments: got 1, expected 0 + //~^ ERROR: Undefined Behavior: incorrect number of arguments: got 1, expected 0 } } diff --git a/tests/fail/function_calls/check_arg_count_too_few_args.rs b/tests/fail/function_calls/check_arg_count_too_few_args.rs index e1cea99eb90b..223c95ffca46 100644 --- a/tests/fail/function_calls/check_arg_count_too_few_args.rs +++ b/tests/fail/function_calls/check_arg_count_too_few_args.rs @@ -4,6 +4,6 @@ fn main() { } unsafe { - let _ = malloc(); //~ ERROR Undefined Behavior: incorrect number of arguments: got 0, expected 1 + let _ = malloc(); //~ ERROR: Undefined Behavior: incorrect number of arguments: got 0, expected 1 }; } diff --git a/tests/fail/function_calls/check_arg_count_too_many_args.rs b/tests/fail/function_calls/check_arg_count_too_many_args.rs index c4028b940ff0..7ee9c40bf7a4 100644 --- a/tests/fail/function_calls/check_arg_count_too_many_args.rs +++ b/tests/fail/function_calls/check_arg_count_too_many_args.rs @@ -4,6 +4,6 @@ fn main() { } unsafe { - let _ = malloc(1, 2); //~ ERROR Undefined Behavior: incorrect number of arguments: got 2, expected 1 + let _ = malloc(1, 2); //~ ERROR: Undefined Behavior: incorrect number of arguments: got 2, expected 1 }; } diff --git a/tests/fail/function_calls/check_callback_abi.rs b/tests/fail/function_calls/check_callback_abi.rs index 0a5a2d48d274..883d5ae8096b 100644 --- a/tests/fail/function_calls/check_callback_abi.rs +++ b/tests/fail/function_calls/check_callback_abi.rs @@ -9,7 +9,7 @@ fn main() { // Make sure we check the ABI when Miri itself invokes a function // as part of a shim implementation. std::intrinsics::r#try( - //~^ ERROR calling a function with ABI C using caller ABI Rust + //~^ ERROR: calling a function with ABI C using caller ABI Rust std::mem::transmute::(try_fn), std::ptr::null_mut(), |_, _| unreachable!(), diff --git a/tests/fail/function_calls/exported_symbol_abi_mismatch.rs b/tests/fail/function_calls/exported_symbol_abi_mismatch.rs index e7372d5ec50a..dbf72b5b61ad 100644 --- a/tests/fail/function_calls/exported_symbol_abi_mismatch.rs +++ b/tests/fail/function_calls/exported_symbol_abi_mismatch.rs @@ -12,7 +12,7 @@ fn main() { #[cfg(fn_ptr)] unsafe { std::mem::transmute::(foo)(); - //[fn_ptr]~^ ERROR calling a function with calling convention Rust using calling convention C + //[fn_ptr]~^ ERROR: calling a function with calling convention Rust using calling convention C } // `Instance` caching should not suppress ABI check. @@ -28,8 +28,8 @@ fn main() { } unsafe { foo(); - //[no_cache]~^ ERROR calling a function with calling convention Rust using calling convention C - //[cache]~| ERROR calling a function with calling convention Rust using calling convention C + //[no_cache]~^ ERROR: calling a function with calling convention Rust using calling convention C + //[cache]~| ERROR: calling a function with calling convention Rust using calling convention C } } } diff --git a/tests/fail/function_calls/exported_symbol_bad_unwind1.rs b/tests/fail/function_calls/exported_symbol_bad_unwind1.rs index 0a5636138d80..5f4df7c6a1ef 100644 --- a/tests/fail/function_calls/exported_symbol_bad_unwind1.rs +++ b/tests/fail/function_calls/exported_symbol_bad_unwind1.rs @@ -11,5 +11,5 @@ fn main() { fn unwind(); } unsafe { unwind() } - //~^ ERROR unwinding past a stack frame that does not allow unwinding + //~^ ERROR: unwinding past a stack frame that does not allow unwinding } diff --git a/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr b/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr index 48df075ba622..74f1d2b11310 100644 --- a/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr +++ b/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr @@ -4,8 +4,8 @@ error: abnormal termination: the program aborted execution --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC | LL | / extern "C-unwind" fn nounwind() { -LL | | //[definition]~^ ERROR abnormal termination: the program aborted execution -LL | | //[both]~^^ ERROR abnormal termination: the program aborted execution +LL | | //[definition]~^ ERROR: abnormal termination: the program aborted execution +LL | | //[both]~^^ ERROR: abnormal termination: the program aborted execution LL | | panic!(); LL | | } | |_^ the program aborted execution diff --git a/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr b/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr index 48df075ba622..74f1d2b11310 100644 --- a/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr +++ b/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr @@ -4,8 +4,8 @@ error: abnormal termination: the program aborted execution --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC | LL | / extern "C-unwind" fn nounwind() { -LL | | //[definition]~^ ERROR abnormal termination: the program aborted execution -LL | | //[both]~^^ ERROR abnormal termination: the program aborted execution +LL | | //[definition]~^ ERROR: abnormal termination: the program aborted execution +LL | | //[both]~^^ ERROR: abnormal termination: the program aborted execution LL | | panic!(); LL | | } | |_^ the program aborted execution diff --git a/tests/fail/function_calls/exported_symbol_bad_unwind2.rs b/tests/fail/function_calls/exported_symbol_bad_unwind2.rs index 861789f862e6..d9aacdb8aea4 100644 --- a/tests/fail/function_calls/exported_symbol_bad_unwind2.rs +++ b/tests/fail/function_calls/exported_symbol_bad_unwind2.rs @@ -4,8 +4,8 @@ #[cfg_attr(any(definition, both), rustc_allocator_nounwind)] #[no_mangle] extern "C-unwind" fn nounwind() { - //[definition]~^ ERROR abnormal termination: the program aborted execution - //[both]~^^ ERROR abnormal termination: the program aborted execution + //[definition]~^ ERROR: abnormal termination: the program aborted execution + //[both]~^^ ERROR: abnormal termination: the program aborted execution panic!(); } @@ -15,5 +15,5 @@ fn main() { fn nounwind(); } unsafe { nounwind() } - //[extern_block]~^ ERROR unwinding past a stack frame that does not allow unwinding + //[extern_block]~^ ERROR: unwinding past a stack frame that does not allow unwinding } diff --git a/tests/fail/function_calls/exported_symbol_clashing.rs b/tests/fail/function_calls/exported_symbol_clashing.rs index 0e64778d8909..45ad412e7a55 100644 --- a/tests/fail/function_calls/exported_symbol_clashing.rs +++ b/tests/fail/function_calls/exported_symbol_clashing.rs @@ -1,15 +1,15 @@ #[no_mangle] fn foo() {} -//~^ HELP it's first defined here, in crate `exported_symbol_clashing` +//~^ HELP: it's first defined here, in crate `exported_symbol_clashing` #[export_name = "foo"] fn bar() {} -//~^ HELP then it's defined here again, in crate `exported_symbol_clashing` +//~^ HELP: then it's defined here again, in crate `exported_symbol_clashing` fn main() { extern "Rust" { fn foo(); } unsafe { foo() } - //~^ ERROR multiple definitions of symbol `foo` + //~^ ERROR: multiple definitions of symbol `foo` } diff --git a/tests/fail/function_calls/exported_symbol_shim_clashing.rs b/tests/fail/function_calls/exported_symbol_shim_clashing.rs index c46d57cee0dd..dffae7adbb97 100644 --- a/tests/fail/function_calls/exported_symbol_shim_clashing.rs +++ b/tests/fail/function_calls/exported_symbol_shim_clashing.rs @@ -1,6 +1,6 @@ #[no_mangle] extern "C" fn malloc(_: usize) -> *mut std::ffi::c_void { - //~^ HELP the `malloc` symbol is defined here + //~^ HELP: the `malloc` symbol is defined here unreachable!() } @@ -10,6 +10,6 @@ fn main() { } unsafe { malloc(0); - //~^ ERROR found `malloc` symbol definition that clashes with a built-in shim + //~^ ERROR: found `malloc` symbol definition that clashes with a built-in shim } } diff --git a/tests/fail/function_calls/exported_symbol_wrong_arguments.rs b/tests/fail/function_calls/exported_symbol_wrong_arguments.rs index 8fb364bb9bd1..a108944c5e43 100644 --- a/tests/fail/function_calls/exported_symbol_wrong_arguments.rs +++ b/tests/fail/function_calls/exported_symbol_wrong_arguments.rs @@ -5,5 +5,5 @@ fn main() { extern "Rust" { fn foo(_: i32); } - unsafe { foo(1) } //~ ERROR calling a function with more arguments than it expected + unsafe { foo(1) } //~ ERROR: calling a function with more arguments than it expected } diff --git a/tests/fail/function_calls/exported_symbol_wrong_type.rs b/tests/fail/function_calls/exported_symbol_wrong_type.rs index 3ffd506c94bb..e273e354334f 100644 --- a/tests/fail/function_calls/exported_symbol_wrong_type.rs +++ b/tests/fail/function_calls/exported_symbol_wrong_type.rs @@ -5,5 +5,5 @@ fn main() { extern "C" { fn FOO(); } - unsafe { FOO() } //~ ERROR attempt to call an exported symbol that is not defined as a function + unsafe { FOO() } //~ ERROR: attempt to call an exported symbol that is not defined as a function } diff --git a/tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs b/tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs index 6edf88a543de..9815569b607f 100644 --- a/tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs +++ b/tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs @@ -5,5 +5,5 @@ fn main() { let b = Box::new(42); let g = unsafe { std::mem::transmute::<&Box, &fn(i32)>(&b) }; - (*g)(42) //~ ERROR it does not point to a function + (*g)(42) //~ ERROR: it does not point to a function } diff --git a/tests/fail/function_pointers/cast_fn_ptr1.rs b/tests/fail/function_pointers/cast_fn_ptr1.rs index e4463210dda9..c0e96a43cc52 100644 --- a/tests/fail/function_pointers/cast_fn_ptr1.rs +++ b/tests/fail/function_pointers/cast_fn_ptr1.rs @@ -3,5 +3,5 @@ fn main() { let g = unsafe { std::mem::transmute::(f) }; - g(42) //~ ERROR calling a function with more arguments than it expected + g(42) //~ ERROR: calling a function with more arguments than it expected } diff --git a/tests/fail/function_pointers/cast_fn_ptr2.rs b/tests/fail/function_pointers/cast_fn_ptr2.rs index 5d3222548a7d..20384f0965b8 100644 --- a/tests/fail/function_pointers/cast_fn_ptr2.rs +++ b/tests/fail/function_pointers/cast_fn_ptr2.rs @@ -3,5 +3,5 @@ fn main() { let g = unsafe { std::mem::transmute::(f) }; - g(42) //~ ERROR calling a function with argument of type (i32, i32) passing data of type i32 + g(42) //~ ERROR: calling a function with argument of type (i32, i32) passing data of type i32 } diff --git a/tests/fail/function_pointers/cast_fn_ptr3.rs b/tests/fail/function_pointers/cast_fn_ptr3.rs index 943175c34702..920fb51abb64 100644 --- a/tests/fail/function_pointers/cast_fn_ptr3.rs +++ b/tests/fail/function_pointers/cast_fn_ptr3.rs @@ -3,5 +3,5 @@ fn main() { let g = unsafe { std::mem::transmute::(f) }; - g() //~ ERROR calling a function with fewer arguments than it requires + g() //~ ERROR: calling a function with fewer arguments than it requires } diff --git a/tests/fail/function_pointers/cast_fn_ptr4.rs b/tests/fail/function_pointers/cast_fn_ptr4.rs index 238b09b162d2..f0ea5ccfe0f5 100644 --- a/tests/fail/function_pointers/cast_fn_ptr4.rs +++ b/tests/fail/function_pointers/cast_fn_ptr4.rs @@ -3,5 +3,5 @@ fn main() { let g = unsafe { std::mem::transmute::(f) }; - g(&42 as *const i32) //~ ERROR calling a function with argument of type *const [i32] passing data of type *const i32 + g(&42 as *const i32) //~ ERROR: calling a function with argument of type *const [i32] passing data of type *const i32 } diff --git a/tests/fail/function_pointers/cast_fn_ptr5.rs b/tests/fail/function_pointers/cast_fn_ptr5.rs index effbd6db1884..0fdab49b94b6 100644 --- a/tests/fail/function_pointers/cast_fn_ptr5.rs +++ b/tests/fail/function_pointers/cast_fn_ptr5.rs @@ -5,5 +5,5 @@ fn main() { let g = unsafe { std::mem::transmute:: u32, fn()>(f) }; - g() //~ ERROR calling a function with return type u32 passing return place of type () + g() //~ ERROR: calling a function with return type u32 passing return place of type () } diff --git a/tests/fail/function_pointers/cast_int_to_fn_ptr.rs b/tests/fail/function_pointers/cast_int_to_fn_ptr.rs index 272376307d7c..dbf8a560fb7a 100644 --- a/tests/fail/function_pointers/cast_int_to_fn_ptr.rs +++ b/tests/fail/function_pointers/cast_int_to_fn_ptr.rs @@ -4,5 +4,5 @@ fn main() { let g = unsafe { std::mem::transmute::(42) }; - g(42) //~ ERROR is a dangling pointer + g(42) //~ ERROR: is a dangling pointer } diff --git a/tests/fail/function_pointers/deref_fn_ptr.rs b/tests/fail/function_pointers/deref_fn_ptr.rs index f22f73487b48..f071b63902fe 100644 --- a/tests/fail/function_pointers/deref_fn_ptr.rs +++ b/tests/fail/function_pointers/deref_fn_ptr.rs @@ -2,7 +2,7 @@ fn f() {} fn main() { let x: u8 = unsafe { - *std::mem::transmute::(f) //~ ERROR out-of-bounds + *std::mem::transmute::(f) //~ ERROR: out-of-bounds }; panic!("this should never print: {}", x); } diff --git a/tests/fail/function_pointers/execute_memory.rs b/tests/fail/function_pointers/execute_memory.rs index 0ca29a3594e5..967933e769b8 100644 --- a/tests/fail/function_pointers/execute_memory.rs +++ b/tests/fail/function_pointers/execute_memory.rs @@ -7,6 +7,6 @@ fn main() { let x = box 42; unsafe { let f = std::mem::transmute::, fn()>(x); - f() //~ ERROR function pointer but it does not point to a function + f() //~ ERROR: function pointer but it does not point to a function } } diff --git a/tests/fail/function_pointers/fn_ptr_offset.rs b/tests/fail/function_pointers/fn_ptr_offset.rs index 5f269760f110..eba0953ac863 100644 --- a/tests/fail/function_pointers/fn_ptr_offset.rs +++ b/tests/fail/function_pointers/fn_ptr_offset.rs @@ -10,5 +10,5 @@ fn main() { let y: *mut u8 = unsafe { mem::transmute(x) }; let y = y.wrapping_offset(1); let x: fn() = unsafe { mem::transmute(y) }; - x(); //~ ERROR function pointer but it does not point to a function + x(); //~ ERROR: function pointer but it does not point to a function } diff --git a/tests/fail/generator-pinned-moved.rs b/tests/fail/generator-pinned-moved.rs index 915dcdea82e4..240ae18cc45a 100644 --- a/tests/fail/generator-pinned-moved.rs +++ b/tests/fail/generator-pinned-moved.rs @@ -12,7 +12,7 @@ fn firstn() -> impl Generator { let num = &mut num; yield *num; - *num += 1; //~ ERROR dereferenced after this allocation got freed + *num += 1; //~ ERROR: dereferenced after this allocation got freed } } diff --git a/tests/fail/intrinsics/assume.rs b/tests/fail/intrinsics/assume.rs index ad193d849918..be06d0a7a554 100644 --- a/tests/fail/intrinsics/assume.rs +++ b/tests/fail/intrinsics/assume.rs @@ -5,6 +5,6 @@ fn main() { unsafe { std::intrinsics::assume(x < 10); std::intrinsics::assume(x > 1); - std::intrinsics::assume(x > 42); //~ ERROR `assume` intrinsic called with `false` + std::intrinsics::assume(x > 42); //~ ERROR: `assume` intrinsic called with `false` } } diff --git a/tests/fail/intrinsics/copy_overlapping.rs b/tests/fail/intrinsics/copy_overlapping.rs index 8d3c68139317..3df881bd43ca 100644 --- a/tests/fail/intrinsics/copy_overlapping.rs +++ b/tests/fail/intrinsics/copy_overlapping.rs @@ -10,6 +10,6 @@ fn main() { unsafe { let a = data.as_mut_ptr(); let b = a.wrapping_offset(1) as *mut _; - copy_nonoverlapping(a, b, 2); //~ ERROR copy_nonoverlapping called on overlapping ranges + copy_nonoverlapping(a, b, 2); //~ ERROR: copy_nonoverlapping called on overlapping ranges } } diff --git a/tests/fail/intrinsics/copy_unaligned.rs b/tests/fail/intrinsics/copy_unaligned.rs index 162f06bfacd9..281217f06f51 100644 --- a/tests/fail/intrinsics/copy_unaligned.rs +++ b/tests/fail/intrinsics/copy_unaligned.rs @@ -10,6 +10,6 @@ fn main() { let ptr = (&mut data[0] as *mut u16 as *mut u8).wrapping_add(1) as *mut u16; // Even copying 0 elements to something unaligned should error unsafe { - copy_nonoverlapping(&data[5], ptr, 0); //~ ERROR accessing memory with alignment 1, but alignment 2 is required + copy_nonoverlapping(&data[5], ptr, 0); //~ ERROR: accessing memory with alignment 1, but alignment 2 is required } } diff --git a/tests/fail/intrinsics/ctlz_nonzero.rs b/tests/fail/intrinsics/ctlz_nonzero.rs index e82ed89da18a..c26cd4cadb53 100644 --- a/tests/fail/intrinsics/ctlz_nonzero.rs +++ b/tests/fail/intrinsics/ctlz_nonzero.rs @@ -10,6 +10,6 @@ pub fn main() { unsafe { use crate::rusti::*; - ctlz_nonzero(0u8); //~ ERROR `ctlz_nonzero` called on 0 + ctlz_nonzero(0u8); //~ ERROR: `ctlz_nonzero` called on 0 } } diff --git a/tests/fail/intrinsics/cttz_nonzero.rs b/tests/fail/intrinsics/cttz_nonzero.rs index 205b55208114..25a0501fdd80 100644 --- a/tests/fail/intrinsics/cttz_nonzero.rs +++ b/tests/fail/intrinsics/cttz_nonzero.rs @@ -10,6 +10,6 @@ pub fn main() { unsafe { use crate::rusti::*; - cttz_nonzero(0u8); //~ ERROR `cttz_nonzero` called on 0 + cttz_nonzero(0u8); //~ ERROR: `cttz_nonzero` called on 0 } } diff --git a/tests/fail/intrinsics/div-by-zero.rs b/tests/fail/intrinsics/div-by-zero.rs index d67d06dc1e67..78c05c543a8f 100644 --- a/tests/fail/intrinsics/div-by-zero.rs +++ b/tests/fail/intrinsics/div-by-zero.rs @@ -4,6 +4,6 @@ use std::intrinsics::*; fn main() { unsafe { - let _n = unchecked_div(1i64, 0); //~ERROR dividing by zero + let _n = unchecked_div(1i64, 0); //~ERROR: dividing by zero } } diff --git a/tests/fail/intrinsics/exact_div1.rs b/tests/fail/intrinsics/exact_div1.rs index f926424a4b67..3dda9d1090de 100644 --- a/tests/fail/intrinsics/exact_div1.rs +++ b/tests/fail/intrinsics/exact_div1.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // divison by 0 - unsafe { std::intrinsics::exact_div(2, 0) }; //~ ERROR divisor of zero + unsafe { std::intrinsics::exact_div(2, 0) }; //~ ERROR: divisor of zero } diff --git a/tests/fail/intrinsics/exact_div2.rs b/tests/fail/intrinsics/exact_div2.rs index fc252aa79857..00064fa0b9c1 100644 --- a/tests/fail/intrinsics/exact_div2.rs +++ b/tests/fail/intrinsics/exact_div2.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // divison with a remainder - unsafe { std::intrinsics::exact_div(2u16, 3) }; //~ ERROR 2_u16 cannot be divided by 3_u16 without remainder + unsafe { std::intrinsics::exact_div(2u16, 3) }; //~ ERROR: 2_u16 cannot be divided by 3_u16 without remainder } diff --git a/tests/fail/intrinsics/exact_div3.rs b/tests/fail/intrinsics/exact_div3.rs index 4d2511adc1f5..a61abcd137e1 100644 --- a/tests/fail/intrinsics/exact_div3.rs +++ b/tests/fail/intrinsics/exact_div3.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // signed divison with a remainder - unsafe { std::intrinsics::exact_div(-19i8, 2) }; //~ ERROR -19_i8 cannot be divided by 2_i8 without remainder + unsafe { std::intrinsics::exact_div(-19i8, 2) }; //~ ERROR: -19_i8 cannot be divided by 2_i8 without remainder } diff --git a/tests/fail/intrinsics/exact_div4.rs b/tests/fail/intrinsics/exact_div4.rs index df6433d1cb22..b5b60190b4ec 100644 --- a/tests/fail/intrinsics/exact_div4.rs +++ b/tests/fail/intrinsics/exact_div4.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // divison of MIN by -1 - unsafe { std::intrinsics::exact_div(i64::MIN, -1) }; //~ ERROR overflow in signed remainder (dividing MIN by -1) + unsafe { std::intrinsics::exact_div(i64::MIN, -1) }; //~ ERROR: overflow in signed remainder (dividing MIN by -1) } diff --git a/tests/fail/intrinsics/ptr_offset_from_oob.rs b/tests/fail/intrinsics/ptr_offset_from_oob.rs index ef1ca1e2729d..1fd5100a97b9 100644 --- a/tests/fail/intrinsics/ptr_offset_from_oob.rs +++ b/tests/fail/intrinsics/ptr_offset_from_oob.rs @@ -7,5 +7,5 @@ fn main() { let length = 10; let end_ptr = start_ptr.wrapping_add(length); // Even if the offset is 0, a dangling OOB pointer is not allowed. - unsafe { ptr_offset_from(end_ptr, end_ptr) }; //~ERROR pointer at offset 10 is out-of-bounds + unsafe { ptr_offset_from(end_ptr, end_ptr) }; //~ERROR: pointer at offset 10 is out-of-bounds } diff --git a/tests/fail/intrinsics/rem-by-zero.rs b/tests/fail/intrinsics/rem-by-zero.rs index e904049e3b46..ac80852e8dcf 100644 --- a/tests/fail/intrinsics/rem-by-zero.rs +++ b/tests/fail/intrinsics/rem-by-zero.rs @@ -4,6 +4,6 @@ use std::intrinsics::*; fn main() { unsafe { - let _n = unchecked_rem(3u32, 0); //~ ERROR calculating the remainder with a divisor of zero + let _n = unchecked_rem(3u32, 0); //~ ERROR: calculating the remainder with a divisor of zero } } diff --git a/tests/fail/intrinsics/simd-div-by-zero.rs b/tests/fail/intrinsics/simd-div-by-zero.rs index 6fdcb875acc1..5fa6f69d0059 100644 --- a/tests/fail/intrinsics/simd-div-by-zero.rs +++ b/tests/fail/intrinsics/simd-div-by-zero.rs @@ -12,6 +12,6 @@ fn main() { unsafe { let x = i32x2(1, 1); let y = i32x2(1, 0); - simd_div(x, y); //~ERROR Undefined Behavior: dividing by zero + simd_div(x, y); //~ERROR: Undefined Behavior: dividing by zero } } diff --git a/tests/fail/intrinsics/simd-div-overflow.rs b/tests/fail/intrinsics/simd-div-overflow.rs index 6d52a72e4c6e..57712b1b836b 100644 --- a/tests/fail/intrinsics/simd-div-overflow.rs +++ b/tests/fail/intrinsics/simd-div-overflow.rs @@ -12,6 +12,6 @@ fn main() { unsafe { let x = i32x2(1, i32::MIN); let y = i32x2(1, -1); - simd_div(x, y); //~ERROR Undefined Behavior: overflow in signed division + simd_div(x, y); //~ERROR: Undefined Behavior: overflow in signed division } } diff --git a/tests/fail/intrinsics/simd-reduce-invalid-bool.rs b/tests/fail/intrinsics/simd-reduce-invalid-bool.rs index c697fd526f86..354f8213120a 100644 --- a/tests/fail/intrinsics/simd-reduce-invalid-bool.rs +++ b/tests/fail/intrinsics/simd-reduce-invalid-bool.rs @@ -11,6 +11,6 @@ struct i32x2(i32, i32); fn main() { unsafe { let x = i32x2(0, 1); - simd_reduce_any(x); //~ERROR must be all-0-bits or all-1-bits + simd_reduce_any(x); //~ERROR: must be all-0-bits or all-1-bits } } diff --git a/tests/fail/intrinsics/simd-rem-by-zero.rs b/tests/fail/intrinsics/simd-rem-by-zero.rs index 82cbaed462c6..625889bb67b5 100644 --- a/tests/fail/intrinsics/simd-rem-by-zero.rs +++ b/tests/fail/intrinsics/simd-rem-by-zero.rs @@ -12,6 +12,6 @@ fn main() { unsafe { let x = i32x2(1, 1); let y = i32x2(1, 0); - simd_rem(x, y); //~ERROR Undefined Behavior: calculating the remainder with a divisor of zero + simd_rem(x, y); //~ERROR: Undefined Behavior: calculating the remainder with a divisor of zero } } diff --git a/tests/fail/intrinsics/simd-select-bitmask-invalid.rs b/tests/fail/intrinsics/simd-select-bitmask-invalid.rs index cc9170c64646..8a3895ac14cf 100644 --- a/tests/fail/intrinsics/simd-select-bitmask-invalid.rs +++ b/tests/fail/intrinsics/simd-select-bitmask-invalid.rs @@ -12,6 +12,6 @@ struct i32x2(i32, i32); fn main() { unsafe { let x = i32x2(0, 1); - simd_select_bitmask(0b11111111u8, x, x); //~ERROR bitmask less than 8 bits long must be filled with 0s for the remaining bits + simd_select_bitmask(0b11111111u8, x, x); //~ERROR: bitmask less than 8 bits long must be filled with 0s for the remaining bits } } diff --git a/tests/fail/intrinsics/simd-select-invalid-bool.rs b/tests/fail/intrinsics/simd-select-invalid-bool.rs index 8ccf4c362c90..7f7ee3af4951 100644 --- a/tests/fail/intrinsics/simd-select-invalid-bool.rs +++ b/tests/fail/intrinsics/simd-select-invalid-bool.rs @@ -12,6 +12,6 @@ struct i32x2(i32, i32); fn main() { unsafe { let x = i32x2(0, 1); - simd_select(x, x, x); //~ERROR must be all-0-bits or all-1-bits + simd_select(x, x, x); //~ERROR: must be all-0-bits or all-1-bits } } diff --git a/tests/fail/intrinsics/simd-shl-too-far.rs b/tests/fail/intrinsics/simd-shl-too-far.rs index e971b042066c..5c517c17b3a4 100644 --- a/tests/fail/intrinsics/simd-shl-too-far.rs +++ b/tests/fail/intrinsics/simd-shl-too-far.rs @@ -12,6 +12,6 @@ fn main() { unsafe { let x = i32x2(1, 1); let y = i32x2(100, 0); - simd_shl(x, y); //~ERROR overflowing shift by 100 in `simd_shl` in SIMD lane 0 + simd_shl(x, y); //~ERROR: overflowing shift by 100 in `simd_shl` in SIMD lane 0 } } diff --git a/tests/fail/intrinsics/simd-shr-too-far.rs b/tests/fail/intrinsics/simd-shr-too-far.rs index ae071f0b7ea1..5f1475a67781 100644 --- a/tests/fail/intrinsics/simd-shr-too-far.rs +++ b/tests/fail/intrinsics/simd-shr-too-far.rs @@ -12,6 +12,6 @@ fn main() { unsafe { let x = i32x2(1, 1); let y = i32x2(20, 40); - simd_shr(x, y); //~ERROR overflowing shift by 40 in `simd_shr` in SIMD lane 1 + simd_shr(x, y); //~ERROR: overflowing shift by 40 in `simd_shr` in SIMD lane 1 } } diff --git a/tests/fail/intrinsics/unchecked_add1.rs b/tests/fail/intrinsics/unchecked_add1.rs index 5409f66e805e..25dbb817fae0 100644 --- a/tests/fail/intrinsics/unchecked_add1.rs +++ b/tests/fail/intrinsics/unchecked_add1.rs @@ -2,6 +2,6 @@ fn main() { // MAX overflow unsafe { - std::intrinsics::unchecked_add(40000u16, 30000); //~ ERROR overflow executing `unchecked_add` + std::intrinsics::unchecked_add(40000u16, 30000); //~ ERROR: overflow executing `unchecked_add` } } diff --git a/tests/fail/intrinsics/unchecked_add2.rs b/tests/fail/intrinsics/unchecked_add2.rs index 5deef7ee5ccd..a454f6478059 100644 --- a/tests/fail/intrinsics/unchecked_add2.rs +++ b/tests/fail/intrinsics/unchecked_add2.rs @@ -2,6 +2,6 @@ fn main() { // MIN overflow unsafe { - std::intrinsics::unchecked_add(-30000i16, -8000); //~ ERROR overflow executing `unchecked_add` + std::intrinsics::unchecked_add(-30000i16, -8000); //~ ERROR: overflow executing `unchecked_add` } } diff --git a/tests/fail/intrinsics/unchecked_div1.rs b/tests/fail/intrinsics/unchecked_div1.rs index c06a5bdce93e..6706cee30ef5 100644 --- a/tests/fail/intrinsics/unchecked_div1.rs +++ b/tests/fail/intrinsics/unchecked_div1.rs @@ -2,6 +2,6 @@ fn main() { // MIN/-1 cannot be represented unsafe { - std::intrinsics::unchecked_div(i16::MIN, -1); //~ ERROR overflow in signed division (dividing MIN by -1) + std::intrinsics::unchecked_div(i16::MIN, -1); //~ ERROR: overflow in signed division (dividing MIN by -1) } } diff --git a/tests/fail/intrinsics/unchecked_mul1.rs b/tests/fail/intrinsics/unchecked_mul1.rs index 140bc9e6c75b..514eb60602da 100644 --- a/tests/fail/intrinsics/unchecked_mul1.rs +++ b/tests/fail/intrinsics/unchecked_mul1.rs @@ -2,6 +2,6 @@ fn main() { // MAX overflow unsafe { - std::intrinsics::unchecked_mul(300u16, 250u16); //~ ERROR overflow executing `unchecked_mul` + std::intrinsics::unchecked_mul(300u16, 250u16); //~ ERROR: overflow executing `unchecked_mul` } } diff --git a/tests/fail/intrinsics/unchecked_mul2.rs b/tests/fail/intrinsics/unchecked_mul2.rs index c4d16084b3f0..e103c1e7ad17 100644 --- a/tests/fail/intrinsics/unchecked_mul2.rs +++ b/tests/fail/intrinsics/unchecked_mul2.rs @@ -2,6 +2,6 @@ fn main() { // MIN overflow unsafe { - std::intrinsics::unchecked_mul(1_000_000_000i32, -4); //~ ERROR overflow executing `unchecked_mul` + std::intrinsics::unchecked_mul(1_000_000_000i32, -4); //~ ERROR: overflow executing `unchecked_mul` } } diff --git a/tests/fail/intrinsics/unchecked_sub1.rs b/tests/fail/intrinsics/unchecked_sub1.rs index cff79f9135f1..e99f88edc863 100644 --- a/tests/fail/intrinsics/unchecked_sub1.rs +++ b/tests/fail/intrinsics/unchecked_sub1.rs @@ -2,6 +2,6 @@ fn main() { // MIN overflow unsafe { - std::intrinsics::unchecked_sub(14u32, 22); //~ ERROR overflow executing `unchecked_sub` + std::intrinsics::unchecked_sub(14u32, 22); //~ ERROR: overflow executing `unchecked_sub` } } diff --git a/tests/fail/intrinsics/unchecked_sub2.rs b/tests/fail/intrinsics/unchecked_sub2.rs index 9b741c2663d8..f83f6843c9ec 100644 --- a/tests/fail/intrinsics/unchecked_sub2.rs +++ b/tests/fail/intrinsics/unchecked_sub2.rs @@ -2,6 +2,6 @@ fn main() { // MAX overflow unsafe { - std::intrinsics::unchecked_sub(30000i16, -7000); //~ ERROR overflow executing `unchecked_sub` + std::intrinsics::unchecked_sub(30000i16, -7000); //~ ERROR: overflow executing `unchecked_sub` } } diff --git a/tests/fail/intrinsics/write_bytes_null.rs b/tests/fail/intrinsics/write_bytes_null.rs index 81b155da44c3..2f46c820fb73 100644 --- a/tests/fail/intrinsics/write_bytes_null.rs +++ b/tests/fail/intrinsics/write_bytes_null.rs @@ -6,5 +6,5 @@ extern "rust-intrinsic" { } fn main() { - unsafe { write_bytes::(std::ptr::null_mut(), 0, 0) }; //~ ERROR memory access failed: null pointer is a dangling pointer + unsafe { write_bytes::(std::ptr::null_mut(), 0, 0) }; //~ ERROR: memory access failed: null pointer is a dangling pointer } diff --git a/tests/fail/invalid_bool.rs b/tests/fail/invalid_bool.rs index b2052d982ed8..525f8831c1c0 100644 --- a/tests/fail/invalid_bool.rs +++ b/tests/fail/invalid_bool.rs @@ -5,5 +5,5 @@ fn main() { let b = unsafe { std::mem::transmute::(2) }; - let _x = b == std::hint::black_box(true); //~ ERROR interpreting an invalid 8-bit value as a bool + let _x = b == std::hint::black_box(true); //~ ERROR: interpreting an invalid 8-bit value as a bool } diff --git a/tests/fail/invalid_char.rs b/tests/fail/invalid_char.rs index 8d814fd92e0c..699248229445 100644 --- a/tests/fail/invalid_char.rs +++ b/tests/fail/invalid_char.rs @@ -6,5 +6,5 @@ fn main() { let c = 0xFFFFFFu32; assert!(std::char::from_u32(c).is_none()); let c = unsafe { std::mem::transmute::(c) }; - let _x = c == 'x'; //~ ERROR interpreting an invalid 32-bit value as a char + let _x = c == 'x'; //~ ERROR: interpreting an invalid 32-bit value as a char } diff --git a/tests/fail/invalid_int.rs b/tests/fail/invalid_int.rs index 6914c66faec3..4f76f8b6d948 100644 --- a/tests/fail/invalid_int.rs +++ b/tests/fail/invalid_int.rs @@ -4,5 +4,5 @@ fn main() { let i = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - let _x = i + 0; //~ ERROR this operation requires initialized memory + let _x = i + 0; //~ ERROR: this operation requires initialized memory } diff --git a/tests/fail/issue-miri-1112.rs b/tests/fail/issue-miri-1112.rs index caf2b28c5a86..abf627bb2a76 100644 --- a/tests/fail/issue-miri-1112.rs +++ b/tests/fail/issue-miri-1112.rs @@ -28,7 +28,7 @@ impl FunnyPointer { data: data as *const _ as *const (), vtable: ptr as *const _ as *const (), }; - let obj = std::mem::transmute::(obj); //~ ERROR invalid drop function pointer in vtable + let obj = std::mem::transmute::(obj); //~ ERROR: invalid drop function pointer in vtable &*obj } } diff --git a/tests/fail/modifying_constants.rs b/tests/fail/modifying_constants.rs index 3c47661a4b2d..2783ebd155ff 100644 --- a/tests/fail/modifying_constants.rs +++ b/tests/fail/modifying_constants.rs @@ -4,6 +4,6 @@ fn main() { let x = &1; // the `&1` is promoted to a constant, but it used to be that only the pointer is marked static, not the pointee let y = unsafe { &mut *(x as *const i32 as *mut i32) }; - *y = 42; //~ ERROR read-only + *y = 42; //~ ERROR: read-only assert_eq!(*x, 42); } diff --git a/tests/fail/never_say_never.rs b/tests/fail/never_say_never.rs index 6beaada56e9a..f6d3dc790bf0 100644 --- a/tests/fail/never_say_never.rs +++ b/tests/fail/never_say_never.rs @@ -7,7 +7,7 @@ fn main() { let y = &5; let x: ! = unsafe { - *(y as *const _ as *const !) //~ ERROR entering unreachable code + *(y as *const _ as *const !) //~ ERROR: entering unreachable code }; f(x) } diff --git a/tests/fail/never_transmute_humans.rs b/tests/fail/never_transmute_humans.rs index 010c9d4146d8..de723433dc28 100644 --- a/tests/fail/never_transmute_humans.rs +++ b/tests/fail/never_transmute_humans.rs @@ -7,6 +7,6 @@ struct Human; fn main() { let _x: ! = unsafe { - std::mem::transmute::(Human) //~ ERROR transmuting to uninhabited + std::mem::transmute::(Human) //~ ERROR: transmuting to uninhabited }; } diff --git a/tests/fail/never_transmute_void.rs b/tests/fail/never_transmute_void.rs index d9c34aa7a5ca..19473e9ac214 100644 --- a/tests/fail/never_transmute_void.rs +++ b/tests/fail/never_transmute_void.rs @@ -1,5 +1,6 @@ // This should fail even without validation //@compile-flags: -Zmiri-disable-validation +//@require-annotations-for-level: ERROR #![feature(never_type)] #![allow(unused, invalid_value)] @@ -9,11 +10,11 @@ mod m { pub struct Void(VoidI); pub fn f(v: Void) -> ! { - match v.0 {} //~ ERROR entering unreachable code + match v.0 {} //~ ERROR: entering unreachable code } } fn main() { let v = unsafe { std::mem::transmute::<(), m::Void>(()) }; - m::f(v); //~ inside `main` + m::f(v); //~ NOTE: inside `main` } diff --git a/tests/fail/panic/bad_miri_start_panic.rs b/tests/fail/panic/bad_miri_start_panic.rs index 9beeccd1d220..4b0ae60b1010 100644 --- a/tests/fail/panic/bad_miri_start_panic.rs +++ b/tests/fail/panic/bad_miri_start_panic.rs @@ -8,5 +8,5 @@ extern "C" { fn main() { unsafe { miri_start_panic(&mut 0) } - //~^ ERROR unwinding past a stack frame that does not allow unwinding + //~^ ERROR: unwinding past a stack frame that does not allow unwinding } diff --git a/tests/fail/panic/unwind_panic_abort.rs b/tests/fail/panic/unwind_panic_abort.rs index 40dcf1bc2a3a..c21fa85a9043 100644 --- a/tests/fail/panic/unwind_panic_abort.rs +++ b/tests/fail/panic/unwind_panic_abort.rs @@ -8,6 +8,6 @@ extern "Rust" { fn main() { unsafe { - miri_start_panic(&mut 0); //~ ERROR unwinding past a stack frame that does not allow unwinding + miri_start_panic(&mut 0); //~ ERROR: unwinding past a stack frame that does not allow unwinding } } diff --git a/tests/fail/pointer_partial_overwrite.rs b/tests/fail/pointer_partial_overwrite.rs index 95af3569f35b..63f0649b8ed3 100644 --- a/tests/fail/pointer_partial_overwrite.rs +++ b/tests/fail/pointer_partial_overwrite.rs @@ -12,6 +12,6 @@ fn main() { // "attempted to interpret some raw bytes as a pointer address" instead of // "attempted to read undefined bytes" } - let x = *p; //~ ERROR this operation requires initialized memory + let x = *p; //~ ERROR: this operation requires initialized memory panic!("this should never print: {}", x); } diff --git a/tests/fail/provenance/provenance_transmute.rs b/tests/fail/provenance/provenance_transmute.rs index 90208c88d694..abcfc060e52b 100644 --- a/tests/fail/provenance/provenance_transmute.rs +++ b/tests/fail/provenance/provenance_transmute.rs @@ -13,7 +13,7 @@ unsafe fn deref(left: *const u8, right: *const u8) { // The compiler is allowed to replace `left_int` by `right_int` here... let left_ptr: *const u8 = mem::transmute(left_int); // ...which however means here it could be dereferencing the wrong pointer. - let _val = *left_ptr; //~ERROR dereferencing pointer failed + let _val = *left_ptr; //~ERROR: dereferencing pointer failed } } diff --git a/tests/fail/provenance/ptr_int_unexposed.rs b/tests/fail/provenance/ptr_int_unexposed.rs index 5522aa33c741..dd8d52b2d2e2 100644 --- a/tests/fail/provenance/ptr_int_unexposed.rs +++ b/tests/fail/provenance/ptr_int_unexposed.rs @@ -8,5 +8,5 @@ fn main() { let x_usize: usize = x_ptr.addr(); // Cast back an address that did *not* get exposed. let ptr = std::ptr::from_exposed_addr::(x_usize); - assert_eq!(unsafe { *ptr }, 3); //~ ERROR Undefined Behavior: dereferencing pointer failed + assert_eq!(unsafe { *ptr }, 3); //~ ERROR: Undefined Behavior: dereferencing pointer failed } diff --git a/tests/fail/provenance/ptr_invalid.rs b/tests/fail/provenance/ptr_invalid.rs index be5666b2efad..d7d32d83e077 100644 --- a/tests/fail/provenance/ptr_invalid.rs +++ b/tests/fail/provenance/ptr_invalid.rs @@ -5,5 +5,5 @@ fn main() { let x = 42; let xptr = &x as *const i32; let xptr_invalid = std::ptr::invalid::(xptr.expose_addr()); - let _val = unsafe { *xptr_invalid }; //~ ERROR is a dangling pointer + let _val = unsafe { *xptr_invalid }; //~ ERROR: is a dangling pointer } diff --git a/tests/fail/provenance/strict_provenance_cast.rs b/tests/fail/provenance/strict_provenance_cast.rs index bca7ea90a31d..0016e7879254 100644 --- a/tests/fail/provenance/strict_provenance_cast.rs +++ b/tests/fail/provenance/strict_provenance_cast.rs @@ -2,5 +2,5 @@ fn main() { let addr = &0 as *const i32 as usize; - let _ptr = addr as *const i32; //~ ERROR integer-to-pointer casts and `ptr::from_exposed_addr` are not supported + let _ptr = addr as *const i32; //~ ERROR: integer-to-pointer casts and `ptr::from_exposed_addr` are not supported } diff --git a/tests/fail/rc_as_ptr.rs b/tests/fail/rc_as_ptr.rs index 9aafa2628425..6aea1870748c 100644 --- a/tests/fail/rc_as_ptr.rs +++ b/tests/fail/rc_as_ptr.rs @@ -16,5 +16,5 @@ fn main() { drop(strong); // But not any more. We can do Weak::as_raw(&weak), but accessing the pointer would lead to // undefined behaviour. - assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); //~ ERROR dereferenced after this allocation got freed + assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); //~ ERROR: dereferenced after this allocation got freed } diff --git a/tests/fail/reading_half_a_pointer.rs b/tests/fail/reading_half_a_pointer.rs index 2a3b096b2f5a..a8cdb11f40ba 100644 --- a/tests/fail/reading_half_a_pointer.rs +++ b/tests/fail/reading_half_a_pointer.rs @@ -24,6 +24,6 @@ fn main() { // starts 1 byte to the right, so using it would actually be wrong! let d_alias = &mut w.data as *mut _ as *mut *const u8; unsafe { - let _x = *d_alias; //~ ERROR unable to turn pointer into raw bytes + let _x = *d_alias; //~ ERROR: unable to turn pointer into raw bytes } } diff --git a/tests/fail/rustc-error.rs b/tests/fail/rustc-error.rs index 3579a143f53b..7fc73bf365d5 100644 --- a/tests/fail/rustc-error.rs +++ b/tests/fail/rustc-error.rs @@ -1,4 +1,4 @@ // Make sure we exit with non-0 status code when the program fails to build. fn main() { - println("Hello, world!"); //~ ERROR expected function, found macro + println("Hello, world!"); //~ ERROR: expected function, found macro } diff --git a/tests/fail/shim_arg_size.rs b/tests/fail/shim_arg_size.rs index d1ffdf8cddb4..383df286d4c8 100644 --- a/tests/fail/shim_arg_size.rs +++ b/tests/fail/shim_arg_size.rs @@ -12,6 +12,6 @@ fn main() { } unsafe { - let _p1 = malloc(42); //~ ERROR Undefined Behavior: scalar size mismatch + let _p1 = malloc(42); //~ ERROR: Undefined Behavior: scalar size mismatch }; } diff --git a/tests/fail/stacked_borrows/alias_through_mutation.rs b/tests/fail/stacked_borrows/alias_through_mutation.rs index 15d8e45f8b8b..dfadeec6c9e9 100644 --- a/tests/fail/stacked_borrows/alias_through_mutation.rs +++ b/tests/fail/stacked_borrows/alias_through_mutation.rs @@ -11,5 +11,5 @@ fn main() { retarget(&mut target_alias, target); // now `target_alias` points to the same thing as `target` *target = 13; - let _val = *target_alias; //~ ERROR borrow stack + let _val = *target_alias; //~ ERROR: borrow stack } diff --git a/tests/fail/stacked_borrows/aliasing_mut1.rs b/tests/fail/stacked_borrows/aliasing_mut1.rs index ebee134a8acb..14a27d8e9dd6 100644 --- a/tests/fail/stacked_borrows/aliasing_mut1.rs +++ b/tests/fail/stacked_borrows/aliasing_mut1.rs @@ -1,6 +1,6 @@ use std::mem; -pub fn safe(_x: &mut i32, _y: &mut i32) {} //~ ERROR protect +pub fn safe(_x: &mut i32, _y: &mut i32) {} //~ ERROR: protect fn main() { let mut x = 0; diff --git a/tests/fail/stacked_borrows/aliasing_mut2.rs b/tests/fail/stacked_borrows/aliasing_mut2.rs index 971dbb63a9d6..84d901f83bbc 100644 --- a/tests/fail/stacked_borrows/aliasing_mut2.rs +++ b/tests/fail/stacked_borrows/aliasing_mut2.rs @@ -1,6 +1,6 @@ use std::mem; -pub fn safe(_x: &i32, _y: &mut i32) {} //~ ERROR protect +pub fn safe(_x: &i32, _y: &mut i32) {} //~ ERROR: protect fn main() { let mut x = 0; diff --git a/tests/fail/stacked_borrows/aliasing_mut3.rs b/tests/fail/stacked_borrows/aliasing_mut3.rs index 91904b0b1d14..f1ba06b6e4f7 100644 --- a/tests/fail/stacked_borrows/aliasing_mut3.rs +++ b/tests/fail/stacked_borrows/aliasing_mut3.rs @@ -1,6 +1,6 @@ use std::mem; -pub fn safe(_x: &mut i32, _y: &i32) {} //~ ERROR borrow stack +pub fn safe(_x: &mut i32, _y: &i32) {} //~ ERROR: borrow stack fn main() { let mut x = 0; diff --git a/tests/fail/stacked_borrows/aliasing_mut4.rs b/tests/fail/stacked_borrows/aliasing_mut4.rs index 79caed5dd6b4..52081b56223d 100644 --- a/tests/fail/stacked_borrows/aliasing_mut4.rs +++ b/tests/fail/stacked_borrows/aliasing_mut4.rs @@ -2,7 +2,7 @@ use std::cell::Cell; use std::mem; // Make sure &mut UnsafeCell also is exclusive -pub fn safe(_x: &i32, _y: &mut Cell) {} //~ ERROR protect +pub fn safe(_x: &i32, _y: &mut Cell) {} //~ ERROR: protect fn main() { let mut x = 0; diff --git a/tests/fail/stacked_borrows/box_exclusive_violation1.rs b/tests/fail/stacked_borrows/box_exclusive_violation1.rs index 66d092d6277c..ce7ff8f9e2aa 100644 --- a/tests/fail/stacked_borrows/box_exclusive_violation1.rs +++ b/tests/fail/stacked_borrows/box_exclusive_violation1.rs @@ -24,7 +24,7 @@ fn unknown_code_1(x: &i32) { fn unknown_code_2() { unsafe { - *LEAK = 7; //~ ERROR borrow stack + *LEAK = 7; //~ ERROR: borrow stack } } diff --git a/tests/fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/fail/stacked_borrows/buggy_as_mut_slice.rs index 6744e4ef4481..5eeec933c7c8 100644 --- a/tests/fail/stacked_borrows/buggy_as_mut_slice.rs +++ b/tests/fail/stacked_borrows/buggy_as_mut_slice.rs @@ -11,5 +11,5 @@ fn main() { let v1 = safe::as_mut_slice(&v); let _v2 = safe::as_mut_slice(&v); v1[1] = 5; - //~^ ERROR borrow stack + //~^ ERROR: borrow stack } diff --git a/tests/fail/stacked_borrows/buggy_split_at_mut.rs b/tests/fail/stacked_borrows/buggy_split_at_mut.rs index a2ef0fcf178d..92380a4bf496 100644 --- a/tests/fail/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/fail/stacked_borrows/buggy_split_at_mut.rs @@ -19,7 +19,7 @@ mod safe { fn main() { let mut array = [1, 2, 3, 4]; let (a, b) = safe::split_at_mut(&mut array, 0); - //~^ ERROR borrow stack + //~^ ERROR: borrow stack a[1] = 5; b[1] = 6; } diff --git a/tests/fail/stacked_borrows/illegal_read4.rs b/tests/fail/stacked_borrows/illegal_read4.rs index d7e281e3ffe5..2d4e395a4270 100644 --- a/tests/fail/stacked_borrows/illegal_read4.rs +++ b/tests/fail/stacked_borrows/illegal_read4.rs @@ -5,5 +5,5 @@ fn main() { let xraw = xref1 as *mut _; let xref2 = unsafe { &mut *xraw }; let _val = unsafe { *xraw }; // use the raw again, this invalidates xref2 *even* with the special read except for uniq refs - let _illegal = *xref2; //~ ERROR borrow stack + let _illegal = *xref2; //~ ERROR: borrow stack } diff --git a/tests/fail/stacked_borrows/illegal_read5.rs b/tests/fail/stacked_borrows/illegal_read5.rs index 8f86a4f0a6b5..49556e618d27 100644 --- a/tests/fail/stacked_borrows/illegal_read5.rs +++ b/tests/fail/stacked_borrows/illegal_read5.rs @@ -14,5 +14,5 @@ fn main() { let _val = *xref; // we can even still use our mutable reference mem::forget(unsafe { ptr::read(xshr) }); // but after reading through the shared ref let _val = *xref; // the mutable one is dead and gone - //~^ ERROR borrow stack + //~^ ERROR: borrow stack } diff --git a/tests/fail/stacked_borrows/illegal_read6.rs b/tests/fail/stacked_borrows/illegal_read6.rs index af89566f6507..943a61af4f6e 100644 --- a/tests/fail/stacked_borrows/illegal_read6.rs +++ b/tests/fail/stacked_borrows/illegal_read6.rs @@ -5,6 +5,6 @@ fn main() { let raw = x as *mut _; let x = &mut *x; // kill `raw` let _y = &*x; // this should not activate `raw` again - let _val = *raw; //~ ERROR borrow stack + let _val = *raw; //~ ERROR: borrow stack } } diff --git a/tests/fail/stacked_borrows/illegal_read7.rs b/tests/fail/stacked_borrows/illegal_read7.rs index e960bd5388c0..e263e8b70a91 100644 --- a/tests/fail/stacked_borrows/illegal_read7.rs +++ b/tests/fail/stacked_borrows/illegal_read7.rs @@ -17,6 +17,6 @@ fn main() { // without invalidating `x`. That would be bad! It would mean that creating `shr` // leaked `x` to `raw`. let _val = ptr::read(raw); - let _val = *x.get_mut(); //~ ERROR borrow stack + let _val = *x.get_mut(); //~ ERROR: borrow stack } } diff --git a/tests/fail/stacked_borrows/illegal_read8.rs b/tests/fail/stacked_borrows/illegal_read8.rs index 9fef673fe6c1..13c12cc75d77 100644 --- a/tests/fail/stacked_borrows/illegal_read8.rs +++ b/tests/fail/stacked_borrows/illegal_read8.rs @@ -10,6 +10,6 @@ fn main() { let _val = *y2; let _val = *y1; *y2 += 1; - let _fail = *y1; //~ ERROR borrow stack + let _fail = *y1; //~ ERROR: borrow stack } } diff --git a/tests/fail/stacked_borrows/illegal_write1.rs b/tests/fail/stacked_borrows/illegal_write1.rs index 58600402e4ed..7abf2f5a9b8f 100644 --- a/tests/fail/stacked_borrows/illegal_write1.rs +++ b/tests/fail/stacked_borrows/illegal_write1.rs @@ -3,7 +3,7 @@ fn main() { let xref = &*target; { let x: *mut u32 = xref as *const _ as *mut _; - unsafe { *x = 42 }; //~ ERROR only grants SharedReadOnly permission + unsafe { *x = 42 }; //~ ERROR: only grants SharedReadOnly permission } let _x = *xref; } diff --git a/tests/fail/stacked_borrows/illegal_write2.rs b/tests/fail/stacked_borrows/illegal_write2.rs index 32dc474385d6..62074bcdbdc1 100644 --- a/tests/fail/stacked_borrows/illegal_write2.rs +++ b/tests/fail/stacked_borrows/illegal_write2.rs @@ -3,6 +3,6 @@ fn main() { let target2 = target as *mut _; drop(&mut *target); // reborrow // Now make sure our ref is still the only one. - unsafe { *target2 = 13 }; //~ ERROR borrow stack + unsafe { *target2 = 13 }; //~ ERROR: borrow stack let _val = *target; } diff --git a/tests/fail/stacked_borrows/illegal_write3.rs b/tests/fail/stacked_borrows/illegal_write3.rs index 87fdbae70192..cb143340dedb 100644 --- a/tests/fail/stacked_borrows/illegal_write3.rs +++ b/tests/fail/stacked_borrows/illegal_write3.rs @@ -3,6 +3,6 @@ fn main() { // Make sure raw ptr with raw tag cannot mutate frozen location without breaking the shared ref. let r#ref = ⌖ // freeze let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag - unsafe { *ptr = 42 }; //~ ERROR only grants SharedReadOnly permission + unsafe { *ptr = 42 }; //~ ERROR: only grants SharedReadOnly permission let _val = *r#ref; } diff --git a/tests/fail/stacked_borrows/illegal_write4.rs b/tests/fail/stacked_borrows/illegal_write4.rs index 654a23d382b8..082eebcba1ba 100644 --- a/tests/fail/stacked_borrows/illegal_write4.rs +++ b/tests/fail/stacked_borrows/illegal_write4.rs @@ -9,5 +9,5 @@ fn main() { let _ptr = reference as *const _ as *mut i32; // raw ptr, with raw tag let _mut_ref: &mut i32 = unsafe { mem::transmute(raw) }; // &mut, with raw tag // Now we retag, making our ref top-of-stack -- and, in particular, unfreezing. - let _val = *reference; //~ ERROR borrow stack + let _val = *reference; //~ ERROR: borrow stack } diff --git a/tests/fail/stacked_borrows/interior_mut1.rs b/tests/fail/stacked_borrows/interior_mut1.rs index 1ef78edbb7ce..a27295fbf2cc 100644 --- a/tests/fail/stacked_borrows/interior_mut1.rs +++ b/tests/fail/stacked_borrows/interior_mut1.rs @@ -12,6 +12,6 @@ fn main() { *c.get() = UnsafeCell::new(1); // invalidates inner_shr // stack: [c: SharedReadWrite] - let _val = *inner_shr.get(); //~ ERROR borrow stack + let _val = *inner_shr.get(); //~ ERROR: borrow stack } } diff --git a/tests/fail/stacked_borrows/interior_mut2.rs b/tests/fail/stacked_borrows/interior_mut2.rs index 4433f28e3459..ba5eb63084e0 100644 --- a/tests/fail/stacked_borrows/interior_mut2.rs +++ b/tests/fail/stacked_borrows/interior_mut2.rs @@ -25,6 +25,6 @@ fn main() { // stack: [c: SharedReadWrite] // now this does not work any more - let _val = *inner_shr.get(); //~ ERROR borrow stack + let _val = *inner_shr.get(); //~ ERROR: borrow stack } } diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier1.rs b/tests/fail/stacked_borrows/invalidate_against_barrier1.rs index 3a214a75b505..d0f43510c28f 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier1.rs +++ b/tests/fail/stacked_borrows/invalidate_against_barrier1.rs @@ -2,7 +2,7 @@ fn inner(x: *mut i32, _y: &mut i32) { // If `x` and `y` alias, retagging is fine with this... but we really // shouldn't be allowed to use `x` at all because `y` was assumed to be // unique for the duration of this call. - let _val = unsafe { *x }; //~ ERROR protect + let _val = unsafe { *x }; //~ ERROR: protect } fn main() { diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier2.rs b/tests/fail/stacked_borrows/invalidate_against_barrier2.rs index 86e4a84287ec..f4e767302fd0 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier2.rs +++ b/tests/fail/stacked_borrows/invalidate_against_barrier2.rs @@ -2,7 +2,7 @@ fn inner(x: *mut i32, _y: &i32) { // If `x` and `y` alias, retagging is fine with this... but we really // shouldn't be allowed to write to `x` at all because `y` was assumed to be // immutable for the duration of this call. - unsafe { *x = 0 }; //~ ERROR protect + unsafe { *x = 0 }; //~ ERROR: protect } fn main() { diff --git a/tests/fail/stacked_borrows/load_invalid_mut.rs b/tests/fail/stacked_borrows/load_invalid_mut.rs index f0ae77f86101..ec69b08a1f8a 100644 --- a/tests/fail/stacked_borrows/load_invalid_mut.rs +++ b/tests/fail/stacked_borrows/load_invalid_mut.rs @@ -8,5 +8,5 @@ fn main() { let xref = unsafe { &mut *xraw }; let xref_in_mem = Box::new(xref); let _val = unsafe { *xraw }; // invalidate xref - let _val = *xref_in_mem; //~ ERROR borrow stack + let _val = *xref_in_mem; //~ ERROR: borrow stack } diff --git a/tests/fail/stacked_borrows/load_invalid_shr.rs b/tests/fail/stacked_borrows/load_invalid_shr.rs index 36ffef656e7f..6de857acffaa 100644 --- a/tests/fail/stacked_borrows/load_invalid_shr.rs +++ b/tests/fail/stacked_borrows/load_invalid_shr.rs @@ -8,5 +8,5 @@ fn main() { let xref = unsafe { &*xraw }; let xref_in_mem = Box::new(xref); unsafe { *xraw = 42 }; // unfreeze - let _val = *xref_in_mem; //~ ERROR borrow stack + let _val = *xref_in_mem; //~ ERROR: borrow stack } diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation1.rs b/tests/fail/stacked_borrows/mut_exclusive_violation1.rs index a1cb7107eee0..c2c13855fcb5 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation1.rs +++ b/tests/fail/stacked_borrows/mut_exclusive_violation1.rs @@ -24,7 +24,7 @@ fn unknown_code_1(x: &i32) { fn unknown_code_2() { unsafe { - *LEAK = 7; //~ ERROR borrow stack + *LEAK = 7; //~ ERROR: borrow stack } } diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation2.rs b/tests/fail/stacked_borrows/mut_exclusive_violation2.rs index a5bf8353bae8..980ffad3c160 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation2.rs +++ b/tests/fail/stacked_borrows/mut_exclusive_violation2.rs @@ -7,6 +7,6 @@ fn main() { let mut ptr2 = ptr1.clone(); let raw1 = ptr1.as_mut(); let _raw2 = ptr2.as_mut(); - let _val = *raw1; //~ ERROR borrow stack + let _val = *raw1; //~ ERROR: borrow stack } } diff --git a/tests/fail/stacked_borrows/outdated_local.rs b/tests/fail/stacked_borrows/outdated_local.rs index 4cb655366ef1..1d4007cf0c43 100644 --- a/tests/fail/stacked_borrows/outdated_local.rs +++ b/tests/fail/stacked_borrows/outdated_local.rs @@ -3,7 +3,7 @@ fn main() { let y: *const i32 = &x; x = 1; // this invalidates y by reactivating the lowermost uniq borrow for this local - assert_eq!(unsafe { *y }, 1); //~ ERROR borrow stack + assert_eq!(unsafe { *y }, 1); //~ ERROR: borrow stack assert_eq!(x, 1); } diff --git a/tests/fail/stacked_borrows/pass_invalid_mut.rs b/tests/fail/stacked_borrows/pass_invalid_mut.rs index d8a53b7a9630..b2e5b8495073 100644 --- a/tests/fail/stacked_borrows/pass_invalid_mut.rs +++ b/tests/fail/stacked_borrows/pass_invalid_mut.rs @@ -6,5 +6,5 @@ fn main() { let xraw = x as *mut _; let xref = unsafe { &mut *xraw }; let _val = unsafe { *xraw }; // invalidate xref - foo(xref); //~ ERROR borrow stack + foo(xref); //~ ERROR: borrow stack } diff --git a/tests/fail/stacked_borrows/pass_invalid_shr.rs b/tests/fail/stacked_borrows/pass_invalid_shr.rs index 091604a283b9..539ebb430a3e 100644 --- a/tests/fail/stacked_borrows/pass_invalid_shr.rs +++ b/tests/fail/stacked_borrows/pass_invalid_shr.rs @@ -6,5 +6,5 @@ fn main() { let xraw = x as *mut _; let xref = unsafe { &*xraw }; unsafe { *xraw = 42 }; // unfreeze - foo(xref); //~ ERROR borrow stack + foo(xref); //~ ERROR: borrow stack } diff --git a/tests/fail/stacked_borrows/pointer_smuggling.rs b/tests/fail/stacked_borrows/pointer_smuggling.rs index f724cdd2a769..839e8b5abdee 100644 --- a/tests/fail/stacked_borrows/pointer_smuggling.rs +++ b/tests/fail/stacked_borrows/pointer_smuggling.rs @@ -8,7 +8,7 @@ fn fun1(x: &mut u8) { fn fun2() { // Now we use a pointer we are not allowed to use - let _x = unsafe { *PTR }; //~ ERROR borrow stack + let _x = unsafe { *PTR }; //~ ERROR: borrow stack } fn main() { diff --git a/tests/fail/stacked_borrows/raw_tracking.rs b/tests/fail/stacked_borrows/raw_tracking.rs index 49fe98312550..5950e910b8a6 100644 --- a/tests/fail/stacked_borrows/raw_tracking.rs +++ b/tests/fail/stacked_borrows/raw_tracking.rs @@ -6,6 +6,6 @@ fn main() { let raw2 = &mut l as *mut _; // invalidates raw1 // Without raw pointer tracking, Stacked Borrows cannot distinguish raw1 and raw2, and thus // fails to realize that raw1 should not be used any more. - unsafe { *raw1 = 13 }; //~ ERROR does not exist in the borrow stack + unsafe { *raw1 = 13 }; //~ ERROR: does not exist in the borrow stack unsafe { *raw2 = 13 }; } diff --git a/tests/fail/stacked_borrows/return_invalid_mut.rs b/tests/fail/stacked_borrows/return_invalid_mut.rs index 54004ec43882..acdc7a4ace69 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut.rs +++ b/tests/fail/stacked_borrows/return_invalid_mut.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> &mut i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &mut (*xraw).1 }; let _val = unsafe { *xraw }; // invalidate xref - ret //~ ERROR borrow stack + ret //~ ERROR: borrow stack } fn main() { diff --git a/tests/fail/stacked_borrows/return_invalid_mut_option.rs b/tests/fail/stacked_borrows/return_invalid_mut_option.rs index ccdb3dc50579..931b420166e7 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_option.rs +++ b/tests/fail/stacked_borrows/return_invalid_mut_option.rs @@ -10,7 +10,7 @@ fn foo(x: &mut (i32, i32)) -> Option<&mut i32> { fn main() { match foo(&mut (1, 2)) { - Some(_x) => {} //~ ERROR borrow stack + Some(_x) => {} //~ ERROR: borrow stack None => {} } } diff --git a/tests/fail/stacked_borrows/return_invalid_shr.rs b/tests/fail/stacked_borrows/return_invalid_shr.rs index eab026f9a47c..a595b91c834c 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr.rs +++ b/tests/fail/stacked_borrows/return_invalid_shr.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> &i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &(*xraw).1 }; unsafe { *xraw = (42, 23) }; // unfreeze - ret //~ ERROR borrow stack + ret //~ ERROR: borrow stack } fn main() { diff --git a/tests/fail/stacked_borrows/return_invalid_shr_option.rs b/tests/fail/stacked_borrows/return_invalid_shr_option.rs index 42b4871c4674..56af567f6e8f 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_option.rs +++ b/tests/fail/stacked_borrows/return_invalid_shr_option.rs @@ -9,7 +9,7 @@ fn foo(x: &mut (i32, i32)) -> Option<&i32> { fn main() { match foo(&mut (1, 2)) { - Some(_x) => {} //~ ERROR borrow stack + Some(_x) => {} //~ ERROR: borrow stack None => {} } } diff --git a/tests/fail/stacked_borrows/return_invalid_shr_tuple.rs b/tests/fail/stacked_borrows/return_invalid_shr_tuple.rs index d7494d6ee653..38f01d7cc20b 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_tuple.rs +++ b/tests/fail/stacked_borrows/return_invalid_shr_tuple.rs @@ -8,5 +8,5 @@ fn foo(x: &mut (i32, i32)) -> (&i32,) { } fn main() { - foo(&mut (1, 2)).0; //~ ERROR borrow stack + foo(&mut (1, 2)).0; //~ ERROR: borrow stack } diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs index a08d2b716ee7..91994d286b95 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs @@ -11,6 +11,6 @@ fn main() { let y: &mut Cell = mem::transmute(&mut *x); // launder lifetime let shr_rw = &*x; // thanks to interior mutability this will be a SharedReadWrite shr_rw.set(1); - y.get_mut(); //~ ERROR borrow stack + y.get_mut(); //~ ERROR: borrow stack } } diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs index 2fc05c2bf4cc..ee44ebbb0718 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs @@ -12,6 +12,6 @@ fn main() { let y: &i32 = mem::transmute(&*x.borrow()); // launder lifetime let shr_rw = &*x; // thanks to interior mutability this will be a SharedReadWrite shr_rw.replace(1); - let _val = *y; //~ ERROR borrow stack + let _val = *y; //~ ERROR: borrow stack } } diff --git a/tests/fail/stacked_borrows/shr_frozen_violation1.rs b/tests/fail/stacked_borrows/shr_frozen_violation1.rs index a6dd9ef4c2ee..11082da6ea3a 100644 --- a/tests/fail/stacked_borrows/shr_frozen_violation1.rs +++ b/tests/fail/stacked_borrows/shr_frozen_violation1.rs @@ -10,6 +10,6 @@ fn main() { fn unknown_code(x: &i32) { unsafe { - *(x as *const i32 as *mut i32) = 7; //~ ERROR only grants SharedReadOnly permission + *(x as *const i32 as *mut i32) = 7; //~ ERROR: only grants SharedReadOnly permission } } diff --git a/tests/fail/stacked_borrows/static_memory_modification.rs b/tests/fail/stacked_borrows/static_memory_modification.rs index 417a03bb0335..84d7878b264e 100644 --- a/tests/fail/stacked_borrows/static_memory_modification.rs +++ b/tests/fail/stacked_borrows/static_memory_modification.rs @@ -3,6 +3,6 @@ static X: usize = 5; #[allow(mutable_transmutes)] fn main() { let _x = unsafe { - std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR writing to alloc1 which is read-only + std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR: writing to alloc1 which is read-only }; } diff --git a/tests/fail/stacked_borrows/transmute-is-no-escape.rs b/tests/fail/stacked_borrows/transmute-is-no-escape.rs index 45035683d5c0..c7d609023201 100644 --- a/tests/fail/stacked_borrows/transmute-is-no-escape.rs +++ b/tests/fail/stacked_borrows/transmute-is-no-escape.rs @@ -10,5 +10,5 @@ fn main() { let _raw: *mut i32 = unsafe { mem::transmute(&mut x[0]) }; // `raw` still carries a tag, so we get another pointer to the same location that does not carry a tag let raw = (&mut x[1] as *mut i32).wrapping_offset(-1); - unsafe { *raw = 13 }; //~ ERROR borrow stack + unsafe { *raw = 13 }; //~ ERROR: borrow stack } diff --git a/tests/fail/stacked_borrows/unescaped_local.rs b/tests/fail/stacked_borrows/unescaped_local.rs index e6cd8f09b1ad..5b808472b4e6 100644 --- a/tests/fail/stacked_borrows/unescaped_local.rs +++ b/tests/fail/stacked_borrows/unescaped_local.rs @@ -7,6 +7,6 @@ fn main() { let raw = &mut x as *mut i32 as usize as *mut i32; let _ptr = &mut x; unsafe { - *raw = 13; //~ ERROR borrow stack + *raw = 13; //~ ERROR: borrow stack } } diff --git a/tests/fail/stacked_borrows/unescaped_static.rs b/tests/fail/stacked_borrows/unescaped_static.rs index 0f0467fc5cb9..66641d648d86 100644 --- a/tests/fail/stacked_borrows/unescaped_static.rs +++ b/tests/fail/stacked_borrows/unescaped_static.rs @@ -3,5 +3,5 @@ static ARRAY: [u8; 2] = [0, 1]; fn main() { let ptr_to_first = &ARRAY[0] as *const u8; // Illegally use this to access the 2nd element. - let _val = unsafe { *ptr_to_first.add(1) }; //~ ERROR borrow stack + let _val = unsafe { *ptr_to_first.add(1) }; //~ ERROR: borrow stack } diff --git a/tests/fail/static_memory_modification1.rs b/tests/fail/static_memory_modification1.rs index 38e8af4c4f1a..66794e7535a4 100644 --- a/tests/fail/static_memory_modification1.rs +++ b/tests/fail/static_memory_modification1.rs @@ -6,7 +6,7 @@ static X: usize = 5; #[allow(mutable_transmutes)] fn main() { unsafe { - *std::mem::transmute::<&usize, &mut usize>(&X) = 6; //~ ERROR read-only + *std::mem::transmute::<&usize, &mut usize>(&X) = 6; //~ ERROR: read-only assert_eq!(X, 6); } } diff --git a/tests/fail/static_memory_modification2.rs b/tests/fail/static_memory_modification2.rs index 2e9d123c6d39..d8ae3a57c51e 100644 --- a/tests/fail/static_memory_modification2.rs +++ b/tests/fail/static_memory_modification2.rs @@ -7,6 +7,6 @@ use std::mem::transmute; fn main() { unsafe { let s = "this is a test"; - transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; //~ ERROR read-only + transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; //~ ERROR: read-only } } diff --git a/tests/fail/static_memory_modification3.rs b/tests/fail/static_memory_modification3.rs index 34ccd13c429d..b8e2c6470ff2 100644 --- a/tests/fail/static_memory_modification3.rs +++ b/tests/fail/static_memory_modification3.rs @@ -7,6 +7,6 @@ use std::mem::transmute; fn main() { unsafe { let bs = b"this is a test"; - transmute::<&[u8], &mut [u8]>(bs)[4] = 42; //~ ERROR read-only + transmute::<&[u8], &mut [u8]>(bs)[4] = 42; //~ ERROR: read-only } } diff --git a/tests/fail/sync/libc_pthread_cond_double_destroy.rs b/tests/fail/sync/libc_pthread_cond_double_destroy.rs index d358b3d4f631..77235d485cde 100644 --- a/tests/fail/sync/libc_pthread_cond_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_cond_double_destroy.rs @@ -17,6 +17,6 @@ fn main() { libc::pthread_cond_destroy(cond.as_mut_ptr()); libc::pthread_cond_destroy(cond.as_mut_ptr()); - //~^ ERROR Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory } } diff --git a/tests/fail/sync/libc_pthread_condattr_double_destroy.rs b/tests/fail/sync/libc_pthread_condattr_double_destroy.rs index bf6b038a212f..3b4522fb046c 100644 --- a/tests/fail/sync/libc_pthread_condattr_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_condattr_double_destroy.rs @@ -14,6 +14,6 @@ fn main() { libc::pthread_condattr_destroy(attr.as_mut_ptr()); libc::pthread_condattr_destroy(attr.as_mut_ptr()); - //~^ ERROR Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory } } diff --git a/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs index 22dd656023b7..ade9903b9dd5 100644 --- a/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs @@ -11,6 +11,6 @@ fn main() { let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, std::ptr::null() as *const _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR Undefined Behavior: trying to acquire already locked default mutex + libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR: Undefined Behavior: trying to acquire already locked default mutex } } diff --git a/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs index e34dfe5e367e..dee5c80e9c40 100644 --- a/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs @@ -12,6 +12,6 @@ fn main() { let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR Undefined Behavior: trying to acquire already locked default mutex + libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR: Undefined Behavior: trying to acquire already locked default mutex } } diff --git a/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs b/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs index ada3d311134d..a7ef5e44c9da 100644 --- a/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs +++ b/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs @@ -14,6 +14,6 @@ fn main() { let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - libc::pthread_mutex_destroy(&mut mutex as *mut _); //~ ERROR destroyed a locked mutex + libc::pthread_mutex_destroy(&mut mutex as *mut _); //~ ERROR: destroyed a locked mutex } } diff --git a/tests/fail/sync/libc_pthread_mutex_double_destroy.rs b/tests/fail/sync/libc_pthread_mutex_double_destroy.rs index 4cf006437b39..8f60409b0052 100644 --- a/tests/fail/sync/libc_pthread_mutex_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_mutex_double_destroy.rs @@ -18,6 +18,6 @@ fn main() { libc::pthread_mutex_destroy(mutex.as_mut_ptr()); libc::pthread_mutex_destroy(mutex.as_mut_ptr()); - //~^ ERROR Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory } } diff --git a/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs index 8ecad494cfee..45475249befc 100644 --- a/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs @@ -14,6 +14,6 @@ fn main() { let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR deadlock: the evaluated program deadlocked + libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR: deadlock: the evaluated program deadlocked } } diff --git a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs index 0109907a1186..da23819ebc31 100644 --- a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs +++ b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs @@ -15,6 +15,6 @@ fn main() { assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - libc::pthread_mutex_unlock(&mut mutex as *mut _); //~ ERROR was not locked + libc::pthread_mutex_unlock(&mut mutex as *mut _); //~ ERROR: was not locked } } diff --git a/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs b/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs index ffa786b65893..8fb7cc3ea603 100644 --- a/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs @@ -14,6 +14,6 @@ fn main() { libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); - //~^ ERROR Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory } } diff --git a/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs b/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs index 6a9f548d1a30..0efb6724c177 100644 --- a/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs +++ b/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs @@ -8,6 +8,6 @@ fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); - libc::pthread_rwlock_destroy(rw.get()); //~ ERROR destroyed a locked rwlock + libc::pthread_rwlock_destroy(rw.get()); //~ ERROR: destroyed a locked rwlock } } diff --git a/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs b/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs index 5f5f16d2cf0e..11c09c1b1342 100644 --- a/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs +++ b/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs @@ -8,6 +8,6 @@ fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); - libc::pthread_rwlock_destroy(rw.get()); //~ ERROR destroyed a locked rwlock + libc::pthread_rwlock_destroy(rw.get()); //~ ERROR: destroyed a locked rwlock } } diff --git a/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs b/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs index 1ba89fb22cf3..9de0383f9daf 100644 --- a/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs @@ -11,6 +11,6 @@ fn main() { libc::pthread_rwlock_destroy(&mut lock); libc::pthread_rwlock_destroy(&mut lock); - //~^ ERROR Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory } } diff --git a/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs b/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs index 7918a9665a03..9d3ca275cb04 100644 --- a/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs +++ b/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs @@ -7,6 +7,6 @@ extern crate libc; fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { - libc::pthread_rwlock_unlock(rw.get()); //~ ERROR was not locked + libc::pthread_rwlock_unlock(rw.get()); //~ ERROR: was not locked } } diff --git a/tests/fail/transmute-pair-uninit.rs b/tests/fail/transmute-pair-uninit.rs index 0835287b9e4f..bc95f3cb7ad3 100644 --- a/tests/fail/transmute-pair-uninit.rs +++ b/tests/fail/transmute-pair-uninit.rs @@ -17,7 +17,7 @@ fn main() { assert_eq!(byte, 0); } let v = unsafe { *z.offset(first_undef) }; - //~^ ERROR uninitialized + //~^ ERROR: uninitialized if v == 0 { println!("it is zero"); } diff --git a/tests/fail/type-too-large.rs b/tests/fail/type-too-large.rs index 932964ebdd7b..21b272f8ec39 100644 --- a/tests/fail/type-too-large.rs +++ b/tests/fail/type-too-large.rs @@ -2,5 +2,5 @@ fn main() { let _fat: [u8; (1 << 61) + (1 << 31)]; - _fat = [0; (1u64 << 61) as usize + (1u64 << 31) as usize]; //~ ERROR post-monomorphization error + _fat = [0; (1u64 << 61) as usize + (1u64 << 31) as usize]; //~ ERROR: post-monomorphization error } diff --git a/tests/fail/unaligned_pointers/atomic_unaligned.rs b/tests/fail/unaligned_pointers/atomic_unaligned.rs index 68b0efdbfeb4..9dd652fd8217 100644 --- a/tests/fail/unaligned_pointers/atomic_unaligned.rs +++ b/tests/fail/unaligned_pointers/atomic_unaligned.rs @@ -8,6 +8,6 @@ fn main() { let zptr = &z as *const _ as *const u64; unsafe { ::std::intrinsics::atomic_load_seqcst(zptr); - //~^ERROR accessing memory with alignment 4, but alignment 8 is required + //~^ERROR: accessing memory with alignment 4, but alignment 8 is required } } diff --git a/tests/fail/unaligned_pointers/dyn_alignment.rs b/tests/fail/unaligned_pointers/dyn_alignment.rs index fe9c39523029..b943c7db7ccd 100644 --- a/tests/fail/unaligned_pointers/dyn_alignment.rs +++ b/tests/fail/unaligned_pointers/dyn_alignment.rs @@ -19,6 +19,6 @@ fn main() { (&mut ptr as *mut _ as *mut *const u8).write(&buf as *const _ as *const u8); } // Re-borrow that. This should be UB. - let _ptr = &*ptr; //~ERROR alignment 256 is required + let _ptr = &*ptr; //~ERROR: alignment 256 is required } } diff --git a/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs b/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs index 172461424ec0..da4cadc1c876 100644 --- a/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs +++ b/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs @@ -12,6 +12,6 @@ fn main() { // Manually make sure the pointer is properly aligned. let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr + 1 }; let u16_ptr = base_addr_aligned as *mut u16; - unsafe { *u16_ptr = 2 }; //~ERROR memory with alignment 1, but alignment 2 is required + unsafe { *u16_ptr = 2 }; //~ERROR: memory with alignment 1, but alignment 2 is required println!("{:?}", x); } diff --git a/tests/fail/unaligned_pointers/reference_to_packed.rs b/tests/fail/unaligned_pointers/reference_to_packed.rs index b4659805745a..752210dca46e 100644 --- a/tests/fail/unaligned_pointers/reference_to_packed.rs +++ b/tests/fail/unaligned_pointers/reference_to_packed.rs @@ -14,6 +14,6 @@ fn main() { for _ in 0..10 { let foo = Foo { x: 42, y: 99 }; let p = &foo.x; - let i = *p; //~ERROR alignment 4 is required + let i = *p; //~ERROR: alignment 4 is required } } diff --git a/tests/fail/unaligned_pointers/unaligned_ptr1.rs b/tests/fail/unaligned_pointers/unaligned_ptr1.rs index a3b483281139..73adc4dc4491 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr1.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr1.rs @@ -7,6 +7,6 @@ fn main() { let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. - let _x = unsafe { *x }; //~ERROR memory with alignment 2, but alignment 4 is required + let _x = unsafe { *x }; //~ERROR: memory with alignment 2, but alignment 4 is required } } diff --git a/tests/fail/unaligned_pointers/unaligned_ptr2.rs b/tests/fail/unaligned_pointers/unaligned_ptr2.rs index 88fcd30278d7..c252944ffb7b 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr2.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr2.rs @@ -8,5 +8,5 @@ fn main() { let x = (x.as_ptr() as *const u8).wrapping_offset(3) as *const u32; // This must fail because alignment is violated: the offset is not sufficiently aligned. // Also make the offset not a power of 2, that used to ICE. - let _x = unsafe { *x }; //~ERROR memory with alignment 1, but alignment 4 is required + let _x = unsafe { *x }; //~ERROR: memory with alignment 1, but alignment 4 is required } diff --git a/tests/fail/unaligned_pointers/unaligned_ptr3.rs b/tests/fail/unaligned_pointers/unaligned_ptr3.rs index 3a4b1497ae6b..7605dd175a98 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr3.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr3.rs @@ -8,6 +8,6 @@ fn main() { let x = &x[0] as *const _ as *const *const u8; // cast to ptr-to-ptr, so that we load a ptr // This must fail because alignment is violated. Test specifically for loading pointers, // which have special code in miri's memory. - let _x = unsafe { *x }; //~ERROR but alignment + let _x = unsafe { *x }; //~ERROR: but alignment } } diff --git a/tests/fail/unaligned_pointers/unaligned_ptr4.rs b/tests/fail/unaligned_pointers/unaligned_ptr4.rs index 659fbf1470ce..852febe4c04c 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr4.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr4.rs @@ -9,6 +9,6 @@ fn main() { for _ in 0..10 { let x = [0u8; 4]; let ptr = x.as_ptr().wrapping_offset(1).cast::(); - let _val = unsafe { *ptr }; //~ERROR but alignment + let _val = unsafe { *ptr }; //~ERROR: but alignment } } diff --git a/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs b/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs index 28a58556eb39..e439cf2b03b9 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs @@ -9,6 +9,6 @@ fn main() { let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. // The deref is UB even if we just put the result into a raw pointer. - let _x = unsafe { ptr::addr_of!(*x) }; //~ ERROR memory with alignment 2, but alignment 4 is required + let _x = unsafe { ptr::addr_of!(*x) }; //~ ERROR: memory with alignment 2, but alignment 4 is required } } diff --git a/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs b/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs index 26c315d34bf5..9076581b55bb 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs @@ -8,6 +8,6 @@ fn main() { let x = i as u8; let x = &x as *const _ as *const [u32; 0]; // This must fail because alignment is violated. Test specifically for loading ZST. - let _x = unsafe { *x }; //~ERROR alignment 4 is required + let _x = unsafe { *x }; //~ERROR: alignment 4 is required } } diff --git a/tests/fail/uninit_byte_read.rs b/tests/fail/uninit_byte_read.rs index e08d34d13856..f1dace0cff9b 100644 --- a/tests/fail/uninit_byte_read.rs +++ b/tests/fail/uninit_byte_read.rs @@ -1,7 +1,7 @@ //@compile-flags: -Zmiri-disable-stacked-borrows fn main() { let v: Vec = Vec::with_capacity(10); - let undef = unsafe { *v.get_unchecked(5) }; //~ ERROR uninitialized + let undef = unsafe { *v.get_unchecked(5) }; //~ ERROR: uninitialized let x = undef + 1; panic!("this should never print: {}", x); } diff --git a/tests/fail/uninit_raw_ptr.rs b/tests/fail/uninit_raw_ptr.rs index c2ede1bb146a..e5a34f4a261c 100644 --- a/tests/fail/uninit_raw_ptr.rs +++ b/tests/fail/uninit_raw_ptr.rs @@ -1,4 +1,4 @@ fn main() { let _val = unsafe { std::mem::MaybeUninit::<*const u8>::uninit().assume_init() }; - //~^ ERROR constructing invalid value at .value: encountered uninitialized raw pointer + //~^ ERROR: constructing invalid value at .value: encountered uninitialized raw pointer } diff --git a/tests/fail/unsized-local.rs b/tests/fail/unsized-local.rs index 8dd07c585c62..ceccae4e3e76 100644 --- a/tests/fail/unsized-local.rs +++ b/tests/fail/unsized-local.rs @@ -14,7 +14,7 @@ fn main() { } } - let x = *(Box::new(A) as Box); //~ERROR unsized locals are not supported + let x = *(Box::new(A) as Box); //~ERROR: unsized locals are not supported assert_eq!(x.foo(), format!("hello")); // I'm not sure whether we want this to work diff --git a/tests/fail/unsupported_foreign_function.rs b/tests/fail/unsupported_foreign_function.rs index b7f4d9038ec6..dfd099e734b9 100644 --- a/tests/fail/unsupported_foreign_function.rs +++ b/tests/fail/unsupported_foreign_function.rs @@ -4,6 +4,6 @@ fn main() { } unsafe { - foo(); //~ ERROR unsupported operation: can't call foreign function: foo + foo(); //~ ERROR: unsupported operation: can't call foreign function: foo } } diff --git a/tests/fail/unsupported_signal.rs b/tests/fail/unsupported_signal.rs index 9cdf3cfdc664..4319dc7c69fe 100644 --- a/tests/fail/unsupported_signal.rs +++ b/tests/fail/unsupported_signal.rs @@ -8,6 +8,6 @@ extern crate libc; fn main() { unsafe { libc::signal(libc::SIGPIPE, libc::SIG_IGN); - //~^ ERROR unsupported operation: can't call foreign function: signal + //~^ ERROR: unsupported operation: can't call foreign function: signal } } diff --git a/tests/fail/validity/cast_fn_ptr1.rs b/tests/fail/validity/cast_fn_ptr1.rs index 1bd889e89994..6ab73569c634 100644 --- a/tests/fail/validity/cast_fn_ptr1.rs +++ b/tests/fail/validity/cast_fn_ptr1.rs @@ -9,5 +9,5 @@ fn main() { let g: fn(*const i32) = unsafe { std::mem::transmute(f as fn(&i32)) }; g(0usize as *const i32) - //~^ ERROR encountered a null reference + //~^ ERROR: encountered a null reference } diff --git a/tests/fail/validity/cast_fn_ptr2.rs b/tests/fail/validity/cast_fn_ptr2.rs index 7e7ad4710f5c..64ddb563be53 100644 --- a/tests/fail/validity/cast_fn_ptr2.rs +++ b/tests/fail/validity/cast_fn_ptr2.rs @@ -11,5 +11,5 @@ fn main() { let g: fn() -> &'static i32 = unsafe { std::mem::transmute(f as fn() -> *const i32) }; let _x = g(); - //~^ ERROR encountered a null reference + //~^ ERROR: encountered a null reference } diff --git a/tests/fail/validity/dangling_ref1.rs b/tests/fail/validity/dangling_ref1.rs index cc94cc6ca0ed..6bf2d9295a37 100644 --- a/tests/fail/validity/dangling_ref1.rs +++ b/tests/fail/validity/dangling_ref1.rs @@ -3,5 +3,5 @@ use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address 0x10 is unallocated) } diff --git a/tests/fail/validity/dangling_ref2.rs b/tests/fail/validity/dangling_ref2.rs index eba026fdda86..77d2358ae777 100644 --- a/tests/fail/validity/dangling_ref2.rs +++ b/tests/fail/validity/dangling_ref2.rs @@ -5,5 +5,5 @@ use std::mem; fn main() { let val = 14; let ptr = (&val as *const i32).wrapping_offset(1); - let _x: &i32 = unsafe { mem::transmute(ptr) }; //~ ERROR dangling reference (going beyond the bounds of its allocation) + let _x: &i32 = unsafe { mem::transmute(ptr) }; //~ ERROR: dangling reference (going beyond the bounds of its allocation) } diff --git a/tests/fail/validity/dangling_ref3.rs b/tests/fail/validity/dangling_ref3.rs index 8decc845ecb4..8e8a75bd7ec0 100644 --- a/tests/fail/validity/dangling_ref3.rs +++ b/tests/fail/validity/dangling_ref3.rs @@ -8,5 +8,5 @@ fn dangling() -> *const u8 { } fn main() { - let _x: &i32 = unsafe { mem::transmute(dangling()) }; //~ ERROR dangling reference (use-after-free) + let _x: &i32 = unsafe { mem::transmute(dangling()) }; //~ ERROR: dangling reference (use-after-free) } diff --git a/tests/fail/validity/invalid_bool.rs b/tests/fail/validity/invalid_bool.rs index df6c19df7f23..4f11bb2629f5 100644 --- a/tests/fail/validity/invalid_bool.rs +++ b/tests/fail/validity/invalid_bool.rs @@ -1,3 +1,3 @@ fn main() { - let _b = unsafe { std::mem::transmute::(2) }; //~ ERROR expected a boolean + let _b = unsafe { std::mem::transmute::(2) }; //~ ERROR: expected a boolean } diff --git a/tests/fail/validity/invalid_bool_uninit.rs b/tests/fail/validity/invalid_bool_uninit.rs index 89b57b2d50d1..f90fae3ab92c 100644 --- a/tests/fail/validity/invalid_bool_uninit.rs +++ b/tests/fail/validity/invalid_bool_uninit.rs @@ -6,5 +6,5 @@ union MyUninit { } fn main() { - let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR encountered uninitialized bytes, but expected a boolean + let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: encountered uninitialized bytes, but expected a boolean } diff --git a/tests/fail/validity/invalid_char.rs b/tests/fail/validity/invalid_char.rs index 80749fd7c791..568892e59109 100644 --- a/tests/fail/validity/invalid_char.rs +++ b/tests/fail/validity/invalid_char.rs @@ -1,7 +1,7 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); let _val = match unsafe { std::mem::transmute::(-1) } { - //~^ ERROR encountered 0xffffffff, but expected a valid unicode scalar value + //~^ ERROR: encountered 0xffffffff, but expected a valid unicode scalar value 'a' => true, 'b' => false, _ => true, diff --git a/tests/fail/validity/invalid_char_uninit.rs b/tests/fail/validity/invalid_char_uninit.rs index cb885d001cff..cb82ce746376 100644 --- a/tests/fail/validity/invalid_char_uninit.rs +++ b/tests/fail/validity/invalid_char_uninit.rs @@ -6,5 +6,5 @@ union MyUninit { } fn main() { - let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR encountered uninitialized bytes, but expected a valid unicode scalar value + let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: encountered uninitialized bytes, but expected a valid unicode scalar value } diff --git a/tests/fail/validity/invalid_enum_tag.rs b/tests/fail/validity/invalid_enum_tag.rs index 4bc60ba51e70..fa115e1e78e4 100644 --- a/tests/fail/validity/invalid_enum_tag.rs +++ b/tests/fail/validity/invalid_enum_tag.rs @@ -7,5 +7,5 @@ pub enum Foo { } fn main() { - let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR constructing invalid value at .: encountered 0x0000002a, but expected a valid enum tag + let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR: constructing invalid value at .: encountered 0x0000002a, but expected a valid enum tag } diff --git a/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs b/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs index 10e30cf85fe6..708e0cafa90d 100644 --- a/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs +++ b/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs @@ -268,5 +268,5 @@ union MyUninit { } fn main() { - let _a = unsafe { MyUninit { init: () }.uninit }; //~ ERROR constructing invalid value at .: encountered uninitialized bytes, but expected a valid enum tag + let _a = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: constructing invalid value at .: encountered uninitialized bytes, but expected a valid enum tag } diff --git a/tests/fail/validity/invalid_fnptr_null.rs b/tests/fail/validity/invalid_fnptr_null.rs index 0634fba36a33..8d2045ca4a65 100644 --- a/tests/fail/validity/invalid_fnptr_null.rs +++ b/tests/fail/validity/invalid_fnptr_null.rs @@ -1,5 +1,5 @@ #![allow(invalid_value)] fn main() { - let _b: fn() = unsafe { std::mem::transmute(0usize) }; //~ ERROR encountered a null function pointer + let _b: fn() = unsafe { std::mem::transmute(0usize) }; //~ ERROR: encountered a null function pointer } diff --git a/tests/fail/validity/invalid_fnptr_uninit.rs b/tests/fail/validity/invalid_fnptr_uninit.rs index 2d479dd319f3..26f958bd64fe 100644 --- a/tests/fail/validity/invalid_fnptr_uninit.rs +++ b/tests/fail/validity/invalid_fnptr_uninit.rs @@ -6,5 +6,5 @@ union MyUninit { } fn main() { - let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR encountered uninitialized bytes + let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: encountered uninitialized bytes } diff --git a/tests/fail/validity/nonzero.rs b/tests/fail/validity/nonzero.rs index 6344bb61ae25..384c94a55699 100644 --- a/tests/fail/validity/nonzero.rs +++ b/tests/fail/validity/nonzero.rs @@ -9,5 +9,5 @@ pub(crate) struct NonZero(pub(crate) T); fn main() { // Make sure that we detect this even when no function call is happening along the way - let _x = Some(unsafe { NonZero(0) }); //~ ERROR encountered 0, but expected something greater or equal to 1 + let _x = Some(unsafe { NonZero(0) }); //~ ERROR: encountered 0, but expected something greater or equal to 1 } diff --git a/tests/fail/validity/ptr_integer_array_transmute.rs b/tests/fail/validity/ptr_integer_array_transmute.rs index 92c635ff2218..c8613d274c81 100644 --- a/tests/fail/validity/ptr_integer_array_transmute.rs +++ b/tests/fail/validity/ptr_integer_array_transmute.rs @@ -1,4 +1,4 @@ fn main() { let r = &mut 42; - let _i: [usize; 1] = unsafe { std::mem::transmute(r) }; //~ ERROR encountered a pointer, but expected plain (non-pointer) bytes + let _i: [usize; 1] = unsafe { std::mem::transmute(r) }; //~ ERROR: encountered a pointer, but expected plain (non-pointer) bytes } diff --git a/tests/fail/validity/ref_to_uninhabited1.rs b/tests/fail/validity/ref_to_uninhabited1.rs index a46ce017c5a0..2e6be8b971c6 100644 --- a/tests/fail/validity/ref_to_uninhabited1.rs +++ b/tests/fail/validity/ref_to_uninhabited1.rs @@ -3,7 +3,7 @@ use std::mem::{forget, transmute}; fn main() { unsafe { - let x: Box = transmute(&mut 42); //~ERROR encountered a box pointing to uninhabited type ! + let x: Box = transmute(&mut 42); //~ERROR: encountered a box pointing to uninhabited type ! forget(x); } } diff --git a/tests/fail/validity/ref_to_uninhabited2.rs b/tests/fail/validity/ref_to_uninhabited2.rs index 0a791d1e7fee..8934a06b5d73 100644 --- a/tests/fail/validity/ref_to_uninhabited2.rs +++ b/tests/fail/validity/ref_to_uninhabited2.rs @@ -4,6 +4,6 @@ enum Void {} fn main() { unsafe { - let _x: &(i32, Void) = transmute(&42); //~ERROR encountered a reference pointing to uninhabited type (i32, Void) + let _x: &(i32, Void) = transmute(&42); //~ERROR: encountered a reference pointing to uninhabited type (i32, Void) } } diff --git a/tests/fail/validity/transmute_through_ptr.rs b/tests/fail/validity/transmute_through_ptr.rs index 9db2ba995304..60b3bdd6cd69 100644 --- a/tests/fail/validity/transmute_through_ptr.rs +++ b/tests/fail/validity/transmute_through_ptr.rs @@ -14,6 +14,6 @@ fn main() { let mut x = Bool::True; evil(&mut x); let y = x; // reading this ought to be enough to trigger validation - //~^ ERROR constructing invalid value at .: encountered 0x0000002c, but expected a valid enum tag + //~^ ERROR: constructing invalid value at .: encountered 0x0000002c, but expected a valid enum tag println!("{:?}", y); // make sure it is used (and not optimized away) } diff --git a/tests/fail/validity/uninit_float.rs b/tests/fail/validity/uninit_float.rs index 43748570d9a4..3e7c14786e35 100644 --- a/tests/fail/validity/uninit_float.rs +++ b/tests/fail/validity/uninit_float.rs @@ -2,5 +2,5 @@ fn main() { let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - //~^ ERROR constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes + //~^ ERROR: constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes } diff --git a/tests/fail/validity/uninit_integer.rs b/tests/fail/validity/uninit_integer.rs index b5a367ba8cb7..0a1253b5b96b 100644 --- a/tests/fail/validity/uninit_integer.rs +++ b/tests/fail/validity/uninit_integer.rs @@ -2,5 +2,5 @@ fn main() { let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - //~^ ERROR constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes + //~^ ERROR: constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes } diff --git a/tests/fail/validity/uninit_integer_signed.rs b/tests/fail/validity/uninit_integer_signed.rs index 609bad7e4fb6..fa484413784c 100644 --- a/tests/fail/validity/uninit_integer_signed.rs +++ b/tests/fail/validity/uninit_integer_signed.rs @@ -2,5 +2,5 @@ fn main() { let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - //~^ ERROR constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes + //~^ ERROR: constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes } diff --git a/tests/fail/zst1.rs b/tests/fail/zst1.rs index d400fba5d0c2..cc81481e4fa4 100644 --- a/tests/fail/zst1.rs +++ b/tests/fail/zst1.rs @@ -1,5 +1,5 @@ fn main() { // make sure ZST locals cannot be accessed let x = &() as *const () as *const i8; - let _val = unsafe { *x }; //~ ERROR out-of-bounds + let _val = unsafe { *x }; //~ ERROR: out-of-bounds } diff --git a/tests/fail/zst2.rs b/tests/fail/zst2.rs index 55c78fe8f944..82470866f179 100644 --- a/tests/fail/zst2.rs +++ b/tests/fail/zst2.rs @@ -11,5 +11,5 @@ fn main() { let mut x_box = Box::new(1u8); let x = &mut *x_box as *mut _ as *mut [u8; 0]; drop(x_box); - unsafe { *x = zst_val }; //~ ERROR dereferenced after this allocation got freed + unsafe { *x = zst_val }; //~ ERROR: dereferenced after this allocation got freed } diff --git a/tests/fail/zst3.rs b/tests/fail/zst3.rs index 47a7c0d3c2a4..a511f38998fe 100644 --- a/tests/fail/zst3.rs +++ b/tests/fail/zst3.rs @@ -14,5 +14,5 @@ fn main() { unsafe { *(x as *mut [u8; 0]) = zst_val }; // One byte further is OOB. let x = x.wrapping_offset(1); - unsafe { *(x as *mut [u8; 0]) = zst_val }; //~ ERROR out-of-bounds + unsafe { *(x as *mut [u8; 0]) = zst_val }; //~ ERROR: out-of-bounds } diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index bebda768babe..b2e71b762bea 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -215,12 +215,6 @@ pub fn run_tests(config: Config) -> Result<()> { eprintln!(" {level:?}: {message}") } } - Error::ErrorPatternWithoutErrorAnnotation(path, line) => { - eprintln!( - "Annotation at {}:{line} matched an error diagnostic but did not have `ERROR` before its message", - path.display() - ); - } } eprintln!(); } @@ -280,7 +274,6 @@ enum Error { msgs: Vec, path: Option<(PathBuf, usize)>, }, - ErrorPatternWithoutErrorAnnotation(PathBuf, usize), } type Errors = Vec; @@ -414,27 +407,17 @@ fn check_annotations( continue; } } - if let Some(level) = level { - // If we found a diagnostic with a level annotation, make sure that all - // diagnostics of that level have annotations, even if we don't end up finding a matching diagnostic - // for this pattern. - lowest_annotation_level = std::cmp::min(lowest_annotation_level, level); - } + + // If we found a diagnostic with a level annotation, make sure that all + // diagnostics of that level have annotations, even if we don't end up finding a matching diagnostic + // for this pattern. + lowest_annotation_level = std::cmp::min(lowest_annotation_level, level); if let Some(msgs) = messages.get_mut(line) { - let found = msgs.iter().position(|msg| { - msg.message.contains(matched) - // in case there is no level on the annotation, match any level. - && level.map_or(true, |level| { - msg.level == level - }) - }); + let found = + msgs.iter().position(|msg| msg.message.contains(matched) && msg.level == level); if let Some(found) = found { - let msg = msgs.remove(found); - if msg.level == Level::Error && level.is_none() { - errors - .push(Error::ErrorPatternWithoutErrorAnnotation(path.to_path_buf(), line)); - } + msgs.remove(found); continue; } } @@ -443,7 +426,12 @@ fn check_annotations( } let filter = |msgs: Vec| -> Vec<_> { - msgs.into_iter().filter(|msg| msg.level >= lowest_annotation_level).collect() + msgs.into_iter() + .filter(|msg| { + msg.level + >= comments.require_annotations_for_level.unwrap_or(lowest_annotation_level) + }) + .collect() }; let messages_from_unknown_file_or_line = filter(messages_from_unknown_file_or_line); diff --git a/ui_test/src/parser.rs b/ui_test/src/parser.rs index 72ccc0136201..5b666eef66ef 100644 --- a/ui_test/src/parser.rs +++ b/ui_test/src/parser.rs @@ -31,6 +31,9 @@ pub(crate) struct Comments { /// An arbitrary pattern to look for in the stderr. pub error_pattern: Option<(String, usize)>, pub error_matches: Vec, + /// Ignore diagnostics below this level. + /// `None` means pick the lowest level from the `error_pattern`s. + pub require_annotations_for_level: Option, } /// The conditions used for "ignore" and "only" filters. @@ -46,7 +49,7 @@ pub(crate) enum Condition { pub(crate) struct ErrorMatch { pub matched: String, pub revision: Option, - pub level: Option, + pub level: Level, /// The line where the message was defined, for reporting issues with it (e.g. in case it wasn't found). pub definition_line: usize, /// The line this pattern is expecting to find a message in. @@ -188,6 +191,13 @@ impl Comments { ensure!(!self.stderr_per_bitwidth, "cannot specifiy stderr-per-bitwidth twice"); self.stderr_per_bitwidth = true; } + "require-annotations-for-level" => { + ensure!( + self.require_annotations_for_level.is_none(), + "cannot specify `require-annotations-for-level` twice" + ); + self.require_annotations_for_level = Some(args.trim().parse()?); + } command => { if let Some(s) = command.strip_prefix("ignore-") { // args are ignored (can be sue as comment) @@ -231,7 +241,7 @@ impl Comments { } } - // parse something like (?P\||[\^]+)? *(?PERROR|HELP|WARN|NOTE)?:?(?P.*) + // parse something like (?P\||[\^]+)? *(?PERROR|HELP|WARN|NOTE): (?P.*) fn parse_pattern_inner( &mut self, pattern: &str, @@ -255,14 +265,15 @@ impl Comments { _ => (l, pattern), }; - let (level, pattern) = match pattern.trim_start().split_once(|c| matches!(c, ':' | ' ')) { - None => (None, pattern), - Some((level, pattern_without_level)) => - match level.parse().ok() { - Some(level) => (Some(level), pattern_without_level), - None => (None, pattern), - }, - }; + let pattern = pattern.trim_start(); + let offset = pattern + .chars() + .position(|c| !matches!(c, 'A'..='Z' | 'a'..='z')) + .ok_or_else(|| eyre!("pattern without level"))?; + + let level = pattern[..offset].parse()?; + let pattern = &pattern[offset..]; + let pattern = pattern.strip_prefix(':').ok_or_else(|| eyre!("no `:` after level found"))?; let matched = pattern.trim().to_string(); diff --git a/ui_test/src/parser/tests.rs b/ui_test/src/parser/tests.rs index 096cc8eab965..31a9ec2639eb 100644 --- a/ui_test/src/parser/tests.rs +++ b/ui_test/src/parser/tests.rs @@ -2,20 +2,16 @@ use std::path::Path; use super::Comments; -use crate::tests::init; -use color_eyre::eyre::{bail, Result}; - #[test] -fn parse_simple_comment() -> Result<()> { - init(); +fn parse_simple_comment() { let s = r" use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address $HEX is unallocated) + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address $HEX is unallocated) } "; - let comments = Comments::parse(Path::new(""), s)?; + let comments = Comments::parse(Path::new(""), s).unwrap(); println!("parsed comments: {:#?}", comments); assert_eq!(comments.error_matches[0].definition_line, 5); assert_eq!(comments.error_matches[0].revision, None); @@ -23,47 +19,57 @@ fn main() { comments.error_matches[0].matched, "encountered a dangling reference (address $HEX is unallocated)" ); - Ok(()) } #[test] -fn parse_slash_slash_at() -> Result<()> { - init(); +fn parse_missing_level() { + let s = r" +use std::mem; + +fn main() { + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ encountered a dangling reference (address $HEX is unallocated) +} + "; + match Comments::parse(Path::new(""), s) { + Ok(_) => panic!("expected parsing to fail"), + Err(_) => {} + } +} + +#[test] +fn parse_slash_slash_at() { let s = r" //@ error-pattern: foomp use std::mem; "; - let comments = Comments::parse(Path::new(""), s)?; + let comments = Comments::parse(Path::new(""), s).unwrap(); println!("parsed comments: {:#?}", comments); assert_eq!(comments.error_pattern, Some(("foomp".to_string(), 2))); - Ok(()) } #[test] -fn parse_slash_slash_at_fail() -> Result<()> { - init(); +fn parse_slash_slash_at_fail() { let s = r" //@ error-patttern foomp use std::mem; "; match Comments::parse(Path::new(""), s) { - Ok(_) => bail!("expected parsing to fail"), - Err(_) => Ok(()), + Ok(_) => panic!("expected parsing to fail"), + Err(_) => {} } } #[test] -fn missing_colon_fail() -> Result<()> { - init(); +fn missing_colon_fail() { let s = r" //@stderr-per-bitwidth hello use std::mem; "; match Comments::parse(Path::new(""), s) { - Ok(_) => bail!("expected parsing to fail"), - Err(_) => Ok(()), + Ok(_) => panic!("expected parsing to fail"), + Err(_) => {} } } diff --git a/ui_test/src/rustc_stderr.rs b/ui_test/src/rustc_stderr.rs index fc772c84040b..a216731c7556 100644 --- a/ui_test/src/rustc_stderr.rs +++ b/ui_test/src/rustc_stderr.rs @@ -3,6 +3,7 @@ use std::{ path::{Path, PathBuf}, }; +use color_eyre::eyre::{eyre, Error}; use regex::Regex; #[derive(serde::Deserialize, Debug)] @@ -45,7 +46,7 @@ struct Span { } impl std::str::FromStr for Level { - type Err = String; + type Err = Error; fn from_str(s: &str) -> Result { match s { "ERROR" | "error" => Ok(Self::Error), @@ -54,7 +55,7 @@ impl std::str::FromStr for Level { "NOTE" | "note" => Ok(Self::Note), "failure-note" => Ok(Self::FailureNote), "error: internal compiler error" => Ok(Self::Ice), - _ => Err(format!("unknown level `{s}`")), + _ => Err(eyre!("unknown level `{s}`")), } } } diff --git a/ui_test/src/tests.rs b/ui_test/src/tests.rs index 11a3d6aca278..96c0f362b675 100644 --- a/ui_test/src/tests.rs +++ b/ui_test/src/tests.rs @@ -20,17 +20,16 @@ fn config() -> Config { } #[test] -fn issue_2156() -> Result<()> { - init(); +fn issue_2156() { let s = r" use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address $HEX is unallocated) + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address $HEX is unallocated) } "; let path = Path::new("$DIR/"); - let comments = Comments::parse(path, s)?; + let comments = Comments::parse(path, s).unwrap(); let mut errors = vec![]; let config = config(); let messages = vec![ @@ -47,22 +46,21 @@ fn main() { [ Error::PatternNotFound { definition_line: 5, .. }, Error::ErrorsWithoutPattern { path: Some((_, 5)), .. }, - ] => Ok(()), + ] => {} _ => panic!("{:#?}", errors), } } #[test] -fn find_pattern() -> Result<()> { - init(); +fn find_pattern() { let s = r" use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address 0x10 is unallocated) } "; - let comments = Comments::parse(Path::new(""), s)?; + let comments = Comments::parse(Path::new(""), s).unwrap(); let config = config(); { let messages = vec![vec![], vec![], vec![], vec![], vec![], vec![ @@ -139,24 +137,23 @@ fn main() { ); match &errors[..] { // Note no `ErrorsWithoutPattern`, because there are no `//~NOTE` in the test file, so we ignore them - [Error::PatternNotFound { definition_line: 5, .. }] => Ok(()), + [Error::PatternNotFound { definition_line: 5, .. }] => {} _ => panic!("not the expected error: {:#?}", errors), } } } #[test] -fn duplicate_pattern() -> Result<()> { - init(); +fn duplicate_pattern() { let s = r" use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) - //~^ ERROR encountered a dangling reference (address 0x10 is unallocated) + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address 0x10 is unallocated) + //~^ ERROR: encountered a dangling reference (address 0x10 is unallocated) } "; - let comments = Comments::parse(Path::new(""), s)?; + let comments = Comments::parse(Path::new(""), s).unwrap(); let config = config(); let messages = vec![ vec![], vec![], vec![], vec![], vec![], @@ -170,22 +167,21 @@ fn main() { let mut errors = vec![]; check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); match &errors[..] { - [Error::PatternNotFound { definition_line: 6, .. }] => Ok(()), + [Error::PatternNotFound { definition_line: 6, .. }] => {} _ => panic!("{:#?}", errors), } } #[test] -fn missing_pattern() -> Result<()> { - init(); +fn missing_pattern() { let s = r" use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address 0x10 is unallocated) } "; - let comments = Comments::parse(Path::new(""), s)?; + let comments = Comments::parse(Path::new(""), s).unwrap(); let config = config(); let messages = vec![ vec![], vec![], vec![], vec![], vec![], @@ -203,23 +199,22 @@ fn main() { let mut errors = vec![]; check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); match &errors[..] { - [Error::ErrorsWithoutPattern { path: Some((_, 5)), .. }] => Ok(()), + [Error::ErrorsWithoutPattern { path: Some((_, 5)), .. }] => {} _ => panic!("{:#?}", errors), } } #[test] -fn missing_warn_pattern() -> Result<()> { - init(); +fn missing_warn_pattern() { let s = r" use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) - //~^ WARN cake + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address 0x10 is unallocated) + //~^ WARN: cake } "; - let comments = Comments::parse(Path::new(""), s)?; + let comments = Comments::parse(Path::new(""), s).unwrap(); let config = config(); let messages= vec![ vec![], @@ -247,7 +242,7 @@ fn main() { match &errors[..] { [Error::ErrorsWithoutPattern { path: Some((_, 5)), msgs, .. }] => match &msgs[..] { - [Message { message, level: Level::Warn }] if message == "kaboom" => Ok(()), + [Message { message, level: Level::Warn }] if message == "kaboom" => {} _ => panic!("{:#?}", msgs), }, _ => panic!("{:#?}", errors), @@ -255,17 +250,16 @@ fn main() { } #[test] -fn missing_implicit_warn_pattern() -> Result<()> { - init(); +fn missing_implicit_warn_pattern() { let s = r" use std::mem; - +//@require-annotations-for-level: ERROR fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) - //~^ cake + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address 0x10 is unallocated) + //~^ WARN: cake } "; - let comments = Comments::parse(Path::new(""), s)?; + let comments = Comments::parse(Path::new(""), s).unwrap(); let config = config(); let messages = vec![ vec![], @@ -291,46 +285,7 @@ fn main() { let mut errors = vec![]; check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); match &errors[..] { - [] => Ok(()), + [] => {} _ => panic!("{:#?}", errors), } } - -#[test] -fn implicit_err_pattern() -> Result<()> { - init(); - let s = r" -use std::mem; - -fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ encountered a dangling reference (address 0x10 is unallocated) -} - "; - let comments = Comments::parse(Path::new(""), s)?; - let config = config(); - let messages = vec![ - vec![], - vec![], - vec![], - vec![], - vec![], - vec![ - Message { - message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), - level: Level::Error, - }, - ], - ]; - let mut errors = vec![]; - check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); - match &errors[..] { - [Error::ErrorPatternWithoutErrorAnnotation(_, 5)] => Ok(()), - _ => panic!("{:#?}", errors), - } -} - -/// Call this from every test to initialize eyre only once across all tests. -pub fn init() { - static INIT: std::sync::Once = std::sync::Once::new(); - INIT.call_once(|| color_eyre::install().unwrap()); -} From a64f9e7250021aed25a3f87a8aacc44cb3529d6b Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 11:50:33 +0000 Subject: [PATCH 3493/5092] Remove error annotations stderr they still showed up in multiline messages --- tests/compiletest.rs | 2 ++ .../function_calls/exported_symbol_bad_unwind2.both.stderr | 4 ++-- .../exported_symbol_bad_unwind2.definition.stderr | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 008fc7806457..4270c60c4c3c 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -106,6 +106,8 @@ regexes! { "[^ `]*/(rust[^/]*|checkout)/library/" => "RUSTLIB/", // erase platform file paths "sys/[a-z]+/" => "sys/PLATFORM/", + // erase error annotations + "//(\\[[a-z,]+\\])?~.*" => "", } fn ui(mode: Mode, path: &str) -> Result<()> { diff --git a/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr b/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr index 74f1d2b11310..9bc70225c56b 100644 --- a/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr +++ b/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr @@ -4,8 +4,8 @@ error: abnormal termination: the program aborted execution --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC | LL | / extern "C-unwind" fn nounwind() { -LL | | //[definition]~^ ERROR: abnormal termination: the program aborted execution -LL | | //[both]~^^ ERROR: abnormal termination: the program aborted execution +LL | | +LL | | LL | | panic!(); LL | | } | |_^ the program aborted execution diff --git a/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr b/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr index 74f1d2b11310..9bc70225c56b 100644 --- a/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr +++ b/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr @@ -4,8 +4,8 @@ error: abnormal termination: the program aborted execution --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC | LL | / extern "C-unwind" fn nounwind() { -LL | | //[definition]~^ ERROR: abnormal termination: the program aborted execution -LL | | //[both]~^^ ERROR: abnormal termination: the program aborted execution +LL | | +LL | | LL | | panic!(); LL | | } | |_^ the program aborted execution From 01253437ea41dc72eb04c0e443e0bda2584224c5 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 12:21:02 +0000 Subject: [PATCH 3494/5092] Pacify clippy --- ui_test/src/parser/tests.rs | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/ui_test/src/parser/tests.rs b/ui_test/src/parser/tests.rs index 31a9ec2639eb..f41c2f234ab8 100644 --- a/ui_test/src/parser/tests.rs +++ b/ui_test/src/parser/tests.rs @@ -30,10 +30,7 @@ fn main() { let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ encountered a dangling reference (address $HEX is unallocated) } "; - match Comments::parse(Path::new(""), s) { - Ok(_) => panic!("expected parsing to fail"), - Err(_) => {} - } + assert!(Comments::parse(Path::new(""), s).is_err(), "expected parsing to fail"); } #[test] @@ -55,10 +52,7 @@ fn parse_slash_slash_at_fail() { use std::mem; "; - match Comments::parse(Path::new(""), s) { - Ok(_) => panic!("expected parsing to fail"), - Err(_) => {} - } + assert!(Comments::parse(Path::new(""), s).is_err(), "expected parsing to fail"); } #[test] @@ -68,8 +62,5 @@ fn missing_colon_fail() { use std::mem; "; - match Comments::parse(Path::new(""), s) { - Ok(_) => panic!("expected parsing to fail"), - Err(_) => {} - } + assert!(Comments::parse(Path::new(""), s).is_err(), "expected parsing to fail"); } From 1ca8d60734cc75b56b3001fe04657723a6974a0d Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 17:19:10 +0000 Subject: [PATCH 3495/5092] Fix annotation filtering with revisions --- tests/compiletest.rs | 2 -- .../function_calls/exported_symbol_bad_unwind2.both.stderr | 4 ++-- .../exported_symbol_bad_unwind2.definition.stderr | 4 ++-- ui_test/src/rustc_stderr.rs | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 4270c60c4c3c..008fc7806457 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -106,8 +106,6 @@ regexes! { "[^ `]*/(rust[^/]*|checkout)/library/" => "RUSTLIB/", // erase platform file paths "sys/[a-z]+/" => "sys/PLATFORM/", - // erase error annotations - "//(\\[[a-z,]+\\])?~.*" => "", } fn ui(mode: Mode, path: &str) -> Result<()> { diff --git a/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr b/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr index 9bc70225c56b..7d9302e3e3ad 100644 --- a/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr +++ b/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr @@ -4,8 +4,8 @@ error: abnormal termination: the program aborted execution --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC | LL | / extern "C-unwind" fn nounwind() { -LL | | -LL | | +LL | | +LL | | LL | | panic!(); LL | | } | |_^ the program aborted execution diff --git a/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr b/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr index 9bc70225c56b..7d9302e3e3ad 100644 --- a/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr +++ b/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr @@ -4,8 +4,8 @@ error: abnormal termination: the program aborted execution --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC | LL | / extern "C-unwind" fn nounwind() { -LL | | -LL | | +LL | | +LL | | LL | | panic!(); LL | | } | |_^ the program aborted execution diff --git a/ui_test/src/rustc_stderr.rs b/ui_test/src/rustc_stderr.rs index a216731c7556..8e031947581b 100644 --- a/ui_test/src/rustc_stderr.rs +++ b/ui_test/src/rustc_stderr.rs @@ -117,7 +117,7 @@ impl Span { } pub(crate) fn filter_annotations_from_rendered(rendered: &str) -> std::borrow::Cow<'_, str> { - let annotations = Regex::new(r" *//(\[[^\]]\])?~.*").unwrap(); + let annotations = Regex::new(r" *//(\[[a-z,]+\])?~.*").unwrap(); annotations.replace_all(rendered, "") } From bfc23e2cdd4d096eecd1d1160a4029aa88667274 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 17:25:56 +0000 Subject: [PATCH 3496/5092] Document require-annotations-for-level --- ui_test/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui_test/README.md b/ui_test/README.md index fef2c6d44ba6..24c5940382d1 100644 --- a/ui_test/README.md +++ b/ui_test/README.md @@ -38,6 +38,8 @@ their command specifies, or the test will fail without even being run. * you can specify this multiple times, accumulating all the env vars * `//@normalize-stderr-test: "REGEX" -> "REPLACEMENT"` replaces all matches of `REGEX` in the stderr with `REPLACEMENT`. The replacement may specify `$1` and similar backreferences to paste captures. * you can specify multiple such commands, there is no need to create a single regex that handles multiple replacements that you want to perform. +* `//@require-annotations-for-level: LEVEL` can be used to change the level of diagnostics that require a corresponding annotation. + * this is only useful if there are any annotations like `HELP`, `WARN` or `NOTE`, as these would automatically require annotations for all other diagnostics of the same or higher level. ## Significant differences to compiletest-rs From c6061116e99dfa15fc2f787cba589ba87cb2c6c4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 11 Jul 2022 21:27:05 -0400 Subject: [PATCH 3497/5092] set up triagebot --- triagebot.toml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 triagebot.toml diff --git a/triagebot.toml b/triagebot.toml new file mode 100644 index 000000000000..264f0da7d33d --- /dev/null +++ b/triagebot.toml @@ -0,0 +1,2 @@ +# Gives us the commands 'ready', 'author', 'blocked' +[shortcut] From 49a6c230cb6ebfbafa282d59d119500c4064215e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Jul 2022 10:13:19 -0400 Subject: [PATCH 3498/5092] remove deprecated options --- README.md | 11 - src/bin/miri.rs | 14 - src/eval.rs | 6 - src/intptrcast.rs | 12 +- src/machine.rs | 17 +- .../invalid_enum_tag_256variants_uninit.rs | 272 ------------------ ...invalid_enum_tag_256variants_uninit.stderr | 16 -- tests/pass/move-uninit-primval.rs | 7 +- tests/pass/move-uninit-primval.stderr | 1 - tests/pass/uninit_number_ignored.rs | 8 - tests/pass/uninit_number_ignored.stderr | 1 - 11 files changed, 11 insertions(+), 354 deletions(-) delete mode 100644 tests/fail/validity/invalid_enum_tag_256variants_uninit.rs delete mode 100644 tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr delete mode 100644 tests/pass/move-uninit-primval.stderr delete mode 100644 tests/pass/uninit_number_ignored.rs delete mode 100644 tests/pass/uninit_number_ignored.stderr diff --git a/README.md b/README.md index 7679537e7f88..d1dde153c478 100644 --- a/README.md +++ b/README.md @@ -329,17 +329,6 @@ The remaining flags are for advanced use only, and more likely to change or be r Some of these are **unsound**, which means they can lead to Miri failing to detect cases of undefined behavior in a program. -* `-Zmiri-allow-uninit-numbers` disables the check to ensure that number types (integer and float - types) always hold initialized data. (They must still be initialized when any actual operation, - such as arithmetic, is performed.) Using this flag is **unsound** and - [deprecated](https://github.com/rust-lang/miri/issues/2187). This has no effect when - `-Zmiri-disable-validation` is present. -* `-Zmiri-allow-ptr-int-transmute` makes Miri more accepting of transmutation between pointers and - integers via `mem::transmute` or union/pointer type punning. This has two effects: it disables the - check against integers storing a pointer (i.e., data with provenance), thus allowing - pointer-to-integer transmutation, and it treats integer-to-pointer transmutation as equivalent to - a cast. Implies `-Zmiri-permissive-provenance`. Using this flag is **unsound** and - [deprecated](https://github.com/rust-lang/miri/issues/2188). * `-Zmiri-disable-abi-check` disables checking [function ABI]. Using this flag is **unsound**. * `-Zmiri-disable-alignment-check` disables checking pointer alignment, so you diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 4f00e4be18ab..0f464da175d0 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -328,19 +328,6 @@ fn main() { "WARNING: the flag `-Zmiri-check-number-validity` no longer has any effect \ since it is now enabled by default" ); - } else if arg == "-Zmiri-allow-uninit-numbers" { - eprintln!( - "WARNING: `-Zmiri-allow-uninit-numbers` is deprecated and planned to be removed. \ - Please let us know at if you rely on this flag." - ); - miri_config.allow_uninit_numbers = true; - } else if arg == "-Zmiri-allow-ptr-int-transmute" { - eprintln!( - "WARNING: `-Zmiri-allow-ptr-int-transmute` is deprecated and planned to be removed. \ - Please let us know at if you rely on this flag." - ); - miri_config.allow_ptr_int_transmute = true; - miri_config.provenance_mode = ProvenanceMode::Permissive; } else if arg == "-Zmiri-disable-abi-check" { miri_config.check_abi = false; } else if arg == "-Zmiri-disable-isolation" { @@ -378,7 +365,6 @@ fn main() { eprintln!("WARNING: `-Zmiri-tag-raw-pointers` has no effect; it is enabled by default"); } else if arg == "-Zmiri-strict-provenance" { miri_config.provenance_mode = ProvenanceMode::Strict; - miri_config.allow_ptr_int_transmute = false; } else if arg == "-Zmiri-permissive-provenance" { miri_config.provenance_mode = ProvenanceMode::Permissive; } else if arg == "-Zmiri-mute-stdout-stderr" { diff --git a/src/eval.rs b/src/eval.rs index d75b4f5fa6d2..0ab85ef264d9 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -77,10 +77,6 @@ pub struct MiriConfig { pub stacked_borrows: bool, /// Controls alignment checking. pub check_alignment: AlignmentCheck, - /// Controls integer and float validity initialization checking. - pub allow_uninit_numbers: bool, - /// Controls how we treat ptr2int and int2ptr transmutes. - pub allow_ptr_int_transmute: bool, /// Controls function [ABI](Abi) checking. pub check_abi: bool, /// Action for an op requiring communication with the host. @@ -134,8 +130,6 @@ impl Default for MiriConfig { validate: true, stacked_borrows: true, check_alignment: AlignmentCheck::Int, - allow_uninit_numbers: false, - allow_ptr_int_transmute: false, check_abi: true, isolated_op: IsolatedOp::Reject(RejectOpWith::Abort), ignore_leaks: false, diff --git a/src/intptrcast.rs b/src/intptrcast.rs index e569960f68fb..0ffa067059f5 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -107,19 +107,13 @@ impl<'mir, 'tcx> GlobalStateInner { } pub fn ptr_from_addr_transmute( - ecx: &MiriEvalContext<'mir, 'tcx>, + _ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, ) -> Pointer> { trace!("Transmuting {:#x} to a pointer", addr); - let provenance = if ecx.machine.allow_ptr_int_transmute { - // When we allow transmutes, treat them like casts: generating a wildcard pointer. - Some(Tag::Wildcard) - } else { - // Usually, we consider transmuted pointers to be "invalid" (`None` provenance). - None - }; - Pointer::new(provenance, Size::from_bytes(addr)) + // We consider transmuted pointers to be "invalid" (`None` provenance). + Pointer::new(None, Size::from_bytes(addr)) } pub fn ptr_from_addr_cast( diff --git a/src/machine.rs b/src/machine.rs index 12df9e271fb9..9d35b43cc56f 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -260,13 +260,6 @@ pub struct Evaluator<'mir, 'tcx> { /// Whether to enforce the validity invariant. pub(crate) validate: bool, - /// Whether to allow uninitialized numbers (integers and floats). - pub(crate) allow_uninit_numbers: bool, - - /// Whether to allow ptr2int transmutes, and whether to allow *dereferencing* the result of an - /// int2ptr transmute. - pub(crate) allow_ptr_int_transmute: bool, - /// Whether to enforce [ABI](Abi) of function calls. pub(crate) enforce_abi: bool, @@ -373,8 +366,6 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { tls: TlsData::default(), isolated_op: config.isolated_op, validate: config.validate, - allow_uninit_numbers: config.allow_uninit_numbers, - allow_ptr_int_transmute: config.allow_ptr_int_transmute, enforce_abi: config.check_abi, file_handler: FileHandler::new(config.mute_stdout_stderr), dir_handler: Default::default(), @@ -527,13 +518,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } #[inline(always)] - fn enforce_number_init(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { - !ecx.machine.allow_uninit_numbers + fn enforce_number_init(_ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { + true } #[inline(always)] - fn enforce_number_no_provenance(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { - !ecx.machine.allow_ptr_int_transmute + fn enforce_number_no_provenance(_ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { + true } #[inline(always)] diff --git a/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs b/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs deleted file mode 100644 index 708e0cafa90d..000000000000 --- a/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs +++ /dev/null @@ -1,272 +0,0 @@ -// Even when uninit numbers are allowed, this enum is not. -//@compile-flags: -Zmiri-allow-uninit-numbers -#![allow(unused, deprecated, invalid_value)] - -#[derive(Copy, Clone)] -enum A { - A0, - A1, - A2, - A3, - A4, - A5, - A6, - A7, - A8, - A9, - A10, - A11, - A12, - A13, - A14, - A15, - A16, - A17, - A18, - A19, - A20, - A21, - A22, - A23, - A24, - A25, - A26, - A27, - A28, - A29, - A30, - A31, - A32, - A33, - A34, - A35, - A36, - A37, - A38, - A39, - A40, - A41, - A42, - A43, - A44, - A45, - A46, - A47, - A48, - A49, - A50, - A51, - A52, - A53, - A54, - A55, - A56, - A57, - A58, - A59, - A60, - A61, - A62, - A63, - A64, - A65, - A66, - A67, - A68, - A69, - A70, - A71, - A72, - A73, - A74, - A75, - A76, - A77, - A78, - A79, - A80, - A81, - A82, - A83, - A84, - A85, - A86, - A87, - A88, - A89, - A90, - A91, - A92, - A93, - A94, - A95, - A96, - A97, - A98, - A99, - A100, - A101, - A102, - A103, - A104, - A105, - A106, - A107, - A108, - A109, - A110, - A111, - A112, - A113, - A114, - A115, - A116, - A117, - A118, - A119, - A120, - A121, - A122, - A123, - A124, - A125, - A126, - A127, - A128, - A129, - A130, - A131, - A132, - A133, - A134, - A135, - A136, - A137, - A138, - A139, - A140, - A141, - A142, - A143, - A144, - A145, - A146, - A147, - A148, - A149, - A150, - A151, - A152, - A153, - A154, - A155, - A156, - A157, - A158, - A159, - A160, - A161, - A162, - A163, - A164, - A165, - A166, - A167, - A168, - A169, - A170, - A171, - A172, - A173, - A174, - A175, - A176, - A177, - A178, - A179, - A180, - A181, - A182, - A183, - A184, - A185, - A186, - A187, - A188, - A189, - A190, - A191, - A192, - A193, - A194, - A195, - A196, - A197, - A198, - A199, - A200, - A201, - A202, - A203, - A204, - A205, - A206, - A207, - A208, - A209, - A210, - A211, - A212, - A213, - A214, - A215, - A216, - A217, - A218, - A219, - A220, - A221, - A222, - A223, - A224, - A225, - A226, - A227, - A228, - A229, - A230, - A231, - A232, - A233, - A234, - A235, - A236, - A237, - A238, - A239, - A240, - A241, - A242, - A243, - A244, - A245, - A246, - A247, - A248, - A249, - A250, - A251, - A252, - A253, - A254, - A255, -} - -union MyUninit { - init: (), - uninit: A, -} - -fn main() { - let _a = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: constructing invalid value at .: encountered uninitialized bytes, but expected a valid enum tag -} diff --git a/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr b/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr deleted file mode 100644 index c3ebf462b6d7..000000000000 --- a/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr +++ /dev/null @@ -1,16 +0,0 @@ -WARNING: `-Zmiri-allow-uninit-numbers` is deprecated and planned to be removed. Please let us know at if you rely on this flag. -error: Undefined Behavior: constructing invalid value at .: encountered uninitialized bytes, but expected a valid enum tag - --> $DIR/invalid_enum_tag_256variants_uninit.rs:LL:CC - | -LL | let _a = unsafe { MyUninit { init: () }.uninit }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered uninitialized bytes, but expected a valid enum tag - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: - = note: inside `main` at $DIR/invalid_enum_tag_256variants_uninit.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/pass/move-uninit-primval.rs b/tests/pass/move-uninit-primval.rs index 220470b637fc..f5fd27fa0d4e 100644 --- a/tests/pass/move-uninit-primval.rs +++ b/tests/pass/move-uninit-primval.rs @@ -1,13 +1,14 @@ -//@compile-flags: -Zmiri-allow-uninit-numbers #![allow(deprecated)] +use std::mem; + struct Foo { - _inner: i32, + _inner: mem::MaybeUninit, } fn main() { unsafe { - let foo = Foo { _inner: std::mem::uninitialized() }; + let foo = Foo { _inner: mem::uninitialized() }; let _bar = foo; } } diff --git a/tests/pass/move-uninit-primval.stderr b/tests/pass/move-uninit-primval.stderr deleted file mode 100644 index d9f2331fe7fa..000000000000 --- a/tests/pass/move-uninit-primval.stderr +++ /dev/null @@ -1 +0,0 @@ -WARNING: `-Zmiri-allow-uninit-numbers` is deprecated and planned to be removed. Please let us know at if you rely on this flag. diff --git a/tests/pass/uninit_number_ignored.rs b/tests/pass/uninit_number_ignored.rs deleted file mode 100644 index 44f6fa267985..000000000000 --- a/tests/pass/uninit_number_ignored.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@compile-flags: -Zmiri-allow-uninit-numbers -// This test is adapted from https://github.com/rust-lang/miri/issues/1340#issue-600900312. - -fn main() { - let _val1 = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - let _val2 = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - let _val3 = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; -} diff --git a/tests/pass/uninit_number_ignored.stderr b/tests/pass/uninit_number_ignored.stderr deleted file mode 100644 index d9f2331fe7fa..000000000000 --- a/tests/pass/uninit_number_ignored.stderr +++ /dev/null @@ -1 +0,0 @@ -WARNING: `-Zmiri-allow-uninit-numbers` is deprecated and planned to be removed. Please let us know at if you rely on this flag. From 9f1cab53a724cfb61cdd49c884e142a8d7007cda Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 11 Jul 2022 22:55:59 -0400 Subject: [PATCH 3499/5092] allow some relabeling as well --- triagebot.toml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index 264f0da7d33d..21a154cafd40 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1,2 +1,11 @@ +[relabel] +allow-unauthenticated = [ + "A-*", + "C-*", + "E-*", + "I-*", + "S-*", + ] + # Gives us the commands 'ready', 'author', 'blocked' [shortcut] From cd3535d25664f02cbf66863a3ccfa682d8082629 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 12 Jul 2022 09:49:11 -0400 Subject: [PATCH 3500/5092] test that we also find bad uses of mem::uninitialized --- tests/fail/validity/uninit_float.rs | 4 +++- tests/fail/validity/uninit_float.stderr | 4 ++-- tests/fail/validity/uninit_integer_signed.rs | 6 ------ tests/fail/validity/uninit_integer_signed.stderr | 15 --------------- 4 files changed, 5 insertions(+), 24 deletions(-) delete mode 100644 tests/fail/validity/uninit_integer_signed.rs delete mode 100644 tests/fail/validity/uninit_integer_signed.stderr diff --git a/tests/fail/validity/uninit_float.rs b/tests/fail/validity/uninit_float.rs index 3e7c14786e35..0f4a22cf5b77 100644 --- a/tests/fail/validity/uninit_float.rs +++ b/tests/fail/validity/uninit_float.rs @@ -1,6 +1,8 @@ +#![allow(deprecated)] // This test is adapted from https://github.com/rust-lang/miri/issues/1340#issue-600900312. fn main() { - let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + // Deliberately using `mem::uninitialized` to make sure that despite all the mitigations, we consider this UB. + let _val: f32 = unsafe { std::mem::uninitialized() }; //~^ ERROR: constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes } diff --git a/tests/fail/validity/uninit_float.stderr b/tests/fail/validity/uninit_float.stderr index 2fe27c904329..d9611af79eeb 100644 --- a/tests/fail/validity/uninit_float.stderr +++ b/tests/fail/validity/uninit_float.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes --> $DIR/uninit_float.rs:LL:CC | -LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes +LL | let _val: f32 = unsafe { std::mem::uninitialized() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/uninit_integer_signed.rs b/tests/fail/validity/uninit_integer_signed.rs deleted file mode 100644 index fa484413784c..000000000000 --- a/tests/fail/validity/uninit_integer_signed.rs +++ /dev/null @@ -1,6 +0,0 @@ -// This test is adapted from https://github.com/rust-lang/miri/issues/1340#issue-600900312. - -fn main() { - let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - //~^ ERROR: constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes -} diff --git a/tests/fail/validity/uninit_integer_signed.stderr b/tests/fail/validity/uninit_integer_signed.stderr deleted file mode 100644 index c53c96c596e4..000000000000 --- a/tests/fail/validity/uninit_integer_signed.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes - --> $DIR/uninit_integer_signed.rs:LL:CC - | -LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: - = note: inside `main` at $DIR/uninit_integer_signed.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - From afa1dddcf97cf6008cfb447739b4b61e04f86660 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 2 Jul 2022 14:38:23 -0400 Subject: [PATCH 3501/5092] Store protectors outside Item, pack Tag and Perm Previously, Item was a struct of a NonZeroU64, an Option which was usually unset or irrelevant, and a 4-variant enum. So collectively, the size of an Item was 24 bytes, but only 8 bytes were used for the most part. So this takes advantage of the fact that it is probably impossible to exhaust the total space of SbTags, and steals 3 bits from it to pack the whole struct into a single u64. This bit-packing means that we reduce peak memory usage when Miri goes memory-bound by ~3x. We also get CPU performance improvements of varying size, because not only are we simply accessing less memory, we can now compare a Vec using a memcmp because it does not have any padding. --- src/machine.rs | 12 +- src/stacked_borrows.rs | 228 +++++++++++++----- src/stacked_borrows/diagnostics.rs | 4 +- src/stacked_borrows/stack.rs | 65 ++--- src/thread.rs | 4 + .../fail/stacked_borrows/aliasing_mut1.stderr | 4 +- .../fail/stacked_borrows/aliasing_mut2.stderr | 4 +- .../fail/stacked_borrows/aliasing_mut4.stderr | 4 +- .../deallocate_against_barrier1.stderr | 4 +- .../deallocate_against_barrier2.stderr | 4 +- .../stacked_borrows/illegal_write6.stderr | 4 +- .../invalidate_against_barrier1.stderr | 4 +- .../invalidate_against_barrier2.stderr | 4 +- .../stacked_borrows/newtype_retagging.stderr | 4 +- 14 files changed, 234 insertions(+), 115 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 12df9e271fb9..122bee2970e2 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -54,15 +54,18 @@ pub struct FrameData<'tcx> { /// for the start of this frame. When we finish executing this frame, /// we use this to register a completed event with `measureme`. pub timing: Option, + + pub protected_tags: Vec, } impl<'tcx> std::fmt::Debug for FrameData<'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // Omitting `timing`, it does not support `Debug`. - let FrameData { call_id, catch_unwind, timing: _ } = self; + let FrameData { call_id, catch_unwind, timing: _, protected_tags } = self; f.debug_struct("FrameData") .field("call_id", call_id) .field("catch_unwind", catch_unwind) + .field("protected_tags", protected_tags) .finish() } } @@ -788,6 +791,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { range, machine.stacked_borrows.as_ref().unwrap(), machine.current_span(), + &machine.threads, )?; } if let Some(weak_memory) = &alloc_extra.weak_memory { @@ -819,6 +823,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { range, machine.stacked_borrows.as_ref().unwrap(), machine.current_span(), + &machine.threads, )?; } if let Some(weak_memory) = &alloc_extra.weak_memory { @@ -852,6 +857,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { tag, range, machine.stacked_borrows.as_ref().unwrap(), + &machine.threads, ) } else { Ok(()) @@ -892,7 +898,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { stacked_borrows.borrow_mut().new_call() }); - let extra = FrameData { call_id, catch_unwind: None, timing }; + let extra = FrameData { call_id, catch_unwind: None, timing, protected_tags: Vec::new() }; Ok(frame.with_extra(extra)) } @@ -936,7 +942,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ) -> InterpResult<'tcx, StackPopJump> { let timing = frame.extra.timing.take(); if let Some(stacked_borrows) = &ecx.machine.stacked_borrows { - stacked_borrows.borrow_mut().end_call(frame.extra.call_id); + stacked_borrows.borrow_mut().end_call(&frame.extra); } let res = ecx.handle_stack_pop_unwind(frame.extra, unwinding); if let Some(profiler) = ecx.machine.profiler.as_ref() { diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 4e83c2c8aa96..8996754be367 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -92,28 +92,100 @@ pub enum Permission { Disabled, } -/// An item in the per-location borrow stack. -#[derive(Copy, Clone, Hash, PartialEq, Eq)] -pub struct Item { - /// The permission this item grants. - perm: Permission, - /// The pointers the permission is granted to. - tag: SbTag, - /// An optional protector, ensuring the item cannot get popped until `CallId` is over. - protector: Option, -} +impl Permission { + const UNIQUE: u64 = 0; + const SHARED_READ_WRITE: u64 = 1; + const SHARED_READ_ONLY: u64 = 2; + const DISABLED: u64 = 3; -impl fmt::Debug for Item { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "[{:?} for {:?}", self.perm, self.tag)?; - if let Some(call) = self.protector { - write!(f, " (call {})", call)?; + fn to_bits(self) -> u64 { + match self { + Permission::Unique => Self::UNIQUE, + Permission::SharedReadWrite => Self::SHARED_READ_WRITE, + Permission::SharedReadOnly => Self::SHARED_READ_ONLY, + Permission::Disabled => Self::DISABLED, + } + } + + fn from_bits(perm: u64) -> Self { + match perm { + Self::UNIQUE => Permission::Unique, + Self::SHARED_READ_WRITE => Permission::SharedReadWrite, + Self::SHARED_READ_ONLY => Permission::SharedReadOnly, + Self::DISABLED => Permission::Disabled, + _ => unreachable!(), } - write!(f, "]")?; - Ok(()) } } +mod item { + use super::{Permission, SbTag}; + use std::fmt; + use std::num::NonZeroU64; + + /// An item in the per-location borrow stack. + #[derive(Copy, Clone, Hash, PartialEq, Eq)] + pub struct Item(u64); + + // An Item contains 3 bitfields: + // * Bits 0-61 store an SbTag + // * Bits 61-63 store a Permission + // * Bit 64 stores a flag which indicates if we have a protector + const TAG_MASK: u64 = u64::MAX >> 3; + const PERM_MASK: u64 = 0x3 << 61; + const PROTECTED_MASK: u64 = 0x1 << 63; + + const PERM_SHIFT: u64 = 61; + const PROTECTED_SHIFT: u64 = 63; + + impl Item { + pub fn new(tag: SbTag, perm: Permission, protected: bool) -> Self { + assert!(tag.0.get() <= TAG_MASK); + let packed_tag = tag.0.get(); + let packed_perm = perm.to_bits() << PERM_SHIFT; + let packed_protected = (protected as u64) << PROTECTED_SHIFT; + + let new = Self(packed_tag | packed_perm | packed_protected); + + debug_assert!(new.tag() == tag); + debug_assert!(new.perm() == perm); + debug_assert!(new.protected() == protected); + + new + } + + /// The pointers the permission is granted to. + pub fn tag(self) -> SbTag { + SbTag(NonZeroU64::new(self.0 & TAG_MASK).unwrap()) + } + + /// The permission this item grants. + pub fn perm(self) -> Permission { + Permission::from_bits((self.0 & PERM_MASK) >> PERM_SHIFT) + } + + /// Whether or not there is a protector for this tag + pub fn protected(self) -> bool { + self.0 & PROTECTED_MASK > 0 + } + + /// Set the Permission stored in this Item to Permission::Disabled + pub fn set_disabled(&mut self) { + // Clear the current set permission + self.0 &= !PERM_MASK; + // Write Permission::Disabled to the Permission bits + self.0 |= Permission::Disabled.to_bits() << PERM_SHIFT; + } + } + + impl fmt::Debug for Item { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{:?} for {:?}]", self.perm(), self.tag()) + } + } +} +pub use item::Item; + /// Extra per-allocation state. #[derive(Clone, Debug)] pub struct Stacks { @@ -136,8 +208,8 @@ pub struct GlobalStateInner { base_ptr_tags: FxHashMap, /// Next unused call ID (for protectors). next_call_id: CallId, - /// Those call IDs corresponding to functions that are still running. - active_calls: FxHashSet, + /// All tags currently protected + protected_tags: FxHashSet, /// The pointer ids to trace tracked_pointer_tags: HashSet, /// The call ids to trace @@ -201,7 +273,7 @@ impl GlobalStateInner { next_ptr_tag: SbTag(NonZeroU64::new(1).unwrap()), base_ptr_tags: FxHashMap::default(), next_call_id: NonZeroU64::new(1).unwrap(), - active_calls: FxHashSet::default(), + protected_tags: FxHashSet::default(), tracked_pointer_tags, tracked_call_ids, retag_fields, @@ -221,17 +293,14 @@ impl GlobalStateInner { if self.tracked_call_ids.contains(&id) { register_diagnostic(NonHaltingDiagnostic::CreatedCallId(id)); } - assert!(self.active_calls.insert(id)); self.next_call_id = NonZeroU64::new(id.get() + 1).unwrap(); id } - pub fn end_call(&mut self, id: CallId) { - assert!(self.active_calls.remove(&id)); - } - - fn is_active(&self, id: CallId) -> bool { - self.active_calls.contains(&id) + pub fn end_call(&mut self, frame: &machine::FrameData<'_>) { + for tag in &frame.protected_tags { + self.protected_tags.remove(tag); + } } pub fn base_ptr_tag(&mut self, id: AllocId) -> SbTag { @@ -287,7 +356,7 @@ impl<'tcx> Stack { /// Find the first write-incompatible item above the given one -- /// i.e, find the height to which the stack will be truncated when writing to `granting`. fn find_first_write_incompatible(&self, granting: usize) -> usize { - let perm = self.get(granting).unwrap().perm; + let perm = self.get(granting).unwrap().perm(); match perm { Permission::SharedReadOnly => bug!("Cannot use SharedReadOnly for writing"), Permission::Disabled => bug!("Cannot use Disabled for anything"), @@ -299,7 +368,7 @@ impl<'tcx> Stack { // The SharedReadWrite *just* above us are compatible, to skip those. let mut idx = granting + 1; while let Some(item) = self.get(idx) { - if item.perm == Permission::SharedReadWrite { + if item.perm() == Permission::SharedReadWrite { // Go on. idx += 1; } else { @@ -325,32 +394,44 @@ impl<'tcx> Stack { provoking_access: Option<(SbTagExtra, AllocRange, Size, AccessKind)>, // just for debug printing and error messages global: &GlobalStateInner, alloc_history: &mut AllocHistory, + threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { - if global.tracked_pointer_tags.contains(&item.tag) { + if global.tracked_pointer_tags.contains(&item.tag()) { register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag( *item, provoking_access.map(|(tag, _alloc_range, _size, access)| (tag, access)), )); } - if let Some(call) = item.protector { - if global.is_active(call) { - if let Some((tag, _alloc_range, _offset, _access)) = provoking_access { - Err(err_sb_ub( - format!( - "not granting access to tag {:?} because incompatible item is protected: {:?}", - tag, item - ), - None, - tag.and_then(|tag| alloc_history.get_logs_relevant_to(tag, Some(item.tag))), - ))? - } else { - Err(err_sb_ub( - format!("deallocating while item is protected: {:?}", item), - None, - None, - ))? - } + if !item.protected() { + return Ok(()); + } + + if global.protected_tags.contains(&item.tag()) { + let call_id = threads + .all_stacks() + .flatten() + .find(|t| t.extra.protected_tags.contains(&item.tag())) + .map(|frame| frame.extra.call_id) + .unwrap(); // FIXME: Surely we should find something, but a panic seems wrong here? + if let Some((tag, _alloc_range, _offset, _access)) = provoking_access { + Err(err_sb_ub( + format!( + "not granting access to tag {:?} because incompatible item is protected: {:?} (call {:?})", + tag, item, call_id + ), + None, + tag.and_then(|tag| alloc_history.get_logs_relevant_to(tag, Some(item.tag()))), + ))? + } else { + Err(err_sb_ub( + format!( + "deallocating while item is protected: {:?} (call {:?})", + item, call_id + ), + None, + None, + ))? } } Ok(()) @@ -369,6 +450,7 @@ impl<'tcx> Stack { current_span: &mut CurrentSpan<'_, '_, 'tcx>, alloc_history: &mut AllocHistory, exposed_tags: &FxHashSet, + threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. @@ -399,8 +481,9 @@ impl<'tcx> Stack { Some((tag, alloc_range, offset, access)), global, alloc_history, + threads, )?; - alloc_history.log_invalidation(item.tag, alloc_range, current_span); + alloc_history.log_invalidation(item.tag(), alloc_range, current_span); Ok(()) })?; } else { @@ -425,8 +508,9 @@ impl<'tcx> Stack { Some((tag, alloc_range, offset, access)), global, alloc_history, + threads, )?; - alloc_history.log_invalidation(item.tag, alloc_range, current_span); + alloc_history.log_invalidation(item.tag(), alloc_range, current_span); Ok(()) })?; } @@ -439,9 +523,9 @@ impl<'tcx> Stack { for i in 0..self.len() { let item = self.get(i).unwrap(); // Skip disabled items, they cannot be matched anyway. - if !matches!(item.perm, Permission::Disabled) { + if !matches!(item.perm(), Permission::Disabled) { // We are looking for a strict upper bound, so add 1 to this tag. - max = cmp::max(item.tag.0.checked_add(1).unwrap(), max); + max = cmp::max(item.tag().0.checked_add(1).unwrap(), max); } } if let Some(unk) = self.unknown_bottom() { @@ -467,6 +551,7 @@ impl<'tcx> Stack { global: &GlobalStateInner, alloc_history: &mut AllocHistory, exposed_tags: &FxHashSet, + threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { // Step 1: Make sure there is a granting item. self.find_granting(AccessKind::Write, tag, exposed_tags).map_err(|_| { @@ -482,7 +567,7 @@ impl<'tcx> Stack { // Step 2: Consider all items removed. This checks for protectors. for idx in (0..self.len()).rev() { let item = self.get(idx).unwrap(); - Stack::item_popped(&item, None, global, alloc_history)?; + Stack::item_popped(&item, None, global, alloc_history, threads)?; } Ok(()) } @@ -502,10 +587,11 @@ impl<'tcx> Stack { current_span: &mut CurrentSpan<'_, '_, 'tcx>, alloc_history: &mut AllocHistory, exposed_tags: &FxHashSet, + threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { // Figure out which access `perm` corresponds to. let access = - if new.perm.grants(AccessKind::Write) { AccessKind::Write } else { AccessKind::Read }; + if new.perm().grants(AccessKind::Write) { AccessKind::Write } else { AccessKind::Read }; // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. @@ -517,7 +603,7 @@ impl<'tcx> Stack { // Compute where to put the new item. // Either way, we ensure that we insert the new item in a way such that between // `derived_from` and the new one, there are only items *compatible with* `derived_from`. - let new_idx = if new.perm == Permission::SharedReadWrite { + let new_idx = if new.perm() == Permission::SharedReadWrite { assert!( access == AccessKind::Write, "this case only makes sense for stack-like accesses" @@ -550,6 +636,7 @@ impl<'tcx> Stack { current_span, alloc_history, exposed_tags, + threads, )?; // We insert "as far up as possible": We know only compatible items are remaining @@ -571,7 +658,7 @@ impl<'tcx> Stack { impl<'tcx> Stacks { /// Creates new stack with initial tag. fn new(size: Size, perm: Permission, tag: SbTag) -> Self { - let item = Item { perm, tag, protector: None }; + let item = Item::new(tag, perm, false); let stack = Stack::new(item); Stacks { @@ -637,6 +724,7 @@ impl Stacks { range: AllocRange, state: &GlobalState, mut current_span: CurrentSpan<'_, '_, 'tcx>, + threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { trace!( "read access with tag {:?}: {:?}, size {}", @@ -654,6 +742,7 @@ impl Stacks { &mut current_span, history, exposed_tags, + threads, ) }) } @@ -666,6 +755,7 @@ impl Stacks { range: AllocRange, state: &GlobalState, mut current_span: CurrentSpan<'_, '_, 'tcx>, + threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { trace!( "write access with tag {:?}: {:?}, size {}", @@ -683,6 +773,7 @@ impl Stacks { &mut current_span, history, exposed_tags, + threads, ) }) } @@ -694,11 +785,12 @@ impl Stacks { tag: SbTagExtra, range: AllocRange, state: &GlobalState, + threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", tag, alloc_id, range.size.bytes()); let state = state.borrow(); self.for_each(range, |offset, stack, history, exposed_tags| { - stack.dealloc(tag, (alloc_id, range, offset), &state, history, exposed_tags) + stack.dealloc(tag, (alloc_id, range, offset), &state, history, exposed_tags, threads) })?; Ok(()) } @@ -801,7 +893,6 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }); } - let protector = if protect { Some(this.frame().extra.call_id) } else { None }; trace!( "reborrow: {} reference {:?} derived from {:?} (pointee {}): {:?}, size {}", kind, @@ -812,6 +903,13 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size.bytes() ); + if protect { + this.frame_mut().extra.protected_tags.push(new_tag); + this.machine.stacked_borrows.as_mut().unwrap().get_mut().protected_tags.insert(new_tag); + } + // FIXME: can't hold the current span handle across the borrows of self above + let current_span = &mut this.machine.current_span(); + // Update the stacks. // Make sure that raw pointers and mutable shared references are reborrowed "weak": // There could be existing unique pointers reborrowed from them that should remain valid! @@ -848,15 +946,16 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { Permission::SharedReadWrite }; - let protector = if frozen { - protector + let protected = if frozen { + protect } else { // We do not protect inside UnsafeCell. // This fixes https://github.com/rust-lang/rust/issues/55005. - None + false }; - let item = Item { perm, tag: new_tag, protector }; + let item = Item::new(new_tag, perm, protected); let mut global = this.machine.stacked_borrows.as_ref().unwrap().borrow_mut(); + let threads = &this.machine.threads; stacked_borrows.for_each(range, |offset, stack, history, exposed_tags| { stack.grant( orig_tag, @@ -866,6 +965,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx current_span, history, exposed_tags, + threads, ) }) })?; @@ -881,9 +981,10 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .as_mut() .expect("we should have Stacked Borrows data") .borrow_mut(); - let item = Item { perm, tag: new_tag, protector }; + let item = Item::new(new_tag, perm, protect); let range = alloc_range(base_offset, size); let mut global = machine.stacked_borrows.as_ref().unwrap().borrow_mut(); + let threads = &machine.threads; let current_span = &mut machine.current_span(); // `get_alloc_extra_mut` invalidated our old `current_span` stacked_borrows.for_each(range, |offset, stack, history, exposed_tags| { stack.grant( @@ -894,6 +995,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx current_span, history, exposed_tags, + threads, ) })?; diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index d787865c4e2d..1fa619a3ae4d 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -141,7 +141,7 @@ impl AllocHistory { ) -> InterpError<'tcx> { let action = format!( "trying to reborrow {derived_from:?} for {new_perm:?} permission at {alloc_id:?}[{offset:#x}]", - new_perm = new.perm, + new_perm = new.perm(), offset = error_offset.bytes(), ); err_sb_ub( @@ -185,7 +185,7 @@ fn error_cause(stack: &Stack, tag: SbTagExtra) -> &'static str { if let SbTagExtra::Concrete(tag) = tag { if (0..stack.len()) .map(|i| stack.get(i).unwrap()) - .any(|item| item.tag == tag && item.perm != Permission::Disabled) + .any(|item| item.tag() == tag && item.perm() != Permission::Disabled) { ", but that tag only grants SharedReadOnly permission for this location" } else { diff --git a/src/stacked_borrows/stack.rs b/src/stacked_borrows/stack.rs index ccdd85eafd8e..0863f8023277 100644 --- a/src/stacked_borrows/stack.rs +++ b/src/stacked_borrows/stack.rs @@ -37,7 +37,7 @@ pub struct Stack { } /// A very small cache of searches of the borrow stack -/// This maps tags to locations in the borrow stack. Any use of this still needs to do a +/// This maps items to locations in the borrow stack. Any use of this still needs to do a /// probably-cold random access into the borrow stack to figure out what `Permission` an /// `SbTag` grants. We could avoid this by also storing the `Permission` in the cache, but /// most lookups into the cache are immediately followed by access of the full borrow stack anyway. @@ -48,7 +48,7 @@ pub struct Stack { #[cfg(feature = "stack-cache")] #[derive(Clone, Debug)] struct StackCache { - tags: [SbTag; CACHE_LEN], // Hot in find_granting + items: [Item; CACHE_LEN], // Hot in find_granting idx: [usize; CACHE_LEN], // Hot in grant } @@ -59,11 +59,11 @@ impl StackCache { /// We use the position in the cache to represent how recently a tag was used; the first position /// is the most recently used tag. So an add shifts every element towards the end, and inserts /// the new element at the start. We lose the last element. - /// This strategy is effective at keeping the most-accessed tags in the cache, but it costs a + /// This strategy is effective at keeping the most-accessed items in the cache, but it costs a /// linear shift across the entire cache when we add a new tag. - fn add(&mut self, idx: usize, tag: SbTag) { - self.tags.copy_within(0..CACHE_LEN - 1, 1); - self.tags[0] = tag; + fn add(&mut self, idx: usize, item: Item) { + self.items.copy_within(0..CACHE_LEN - 1, 1); + self.items[0] = item; self.idx.copy_within(0..CACHE_LEN - 1, 1); self.idx[0] = idx; } @@ -80,20 +80,20 @@ impl Eq for Stack {} impl<'tcx> Stack { /// Panics if any of the caching mechanisms have broken, - /// - The StackCache indices don't refer to the parallel tags, - /// - There are no Unique tags outside of first_unique..last_unique + /// - The StackCache indices don't refer to the parallel items, + /// - There are no Unique items outside of first_unique..last_unique #[cfg(feature = "expensive-debug-assertions")] fn verify_cache_consistency(&self) { // Only a full cache needs to be valid. Also see the comments in find_granting_cache // and set_unknown_bottom. if self.borrows.len() >= CACHE_LEN { - for (tag, stack_idx) in self.cache.tags.iter().zip(self.cache.idx.iter()) { - assert_eq!(self.borrows[*stack_idx].tag, *tag); + for (tag, stack_idx) in self.cache.items.iter().zip(self.cache.idx.iter()) { + assert_eq!(self.borrows[*stack_idx], *tag); } } for (idx, item) in self.borrows.iter().enumerate() { - if item.perm == Permission::Unique { + if item.perm() == Permission::Unique { assert!( self.unique_range.contains(&idx), "{:?} {:?}", @@ -128,7 +128,7 @@ impl<'tcx> Stack { .rev() // search top-to-bottom .find_map(|(idx, item)| { // If the item fits and *might* be this wildcard, use it. - if item.perm.grants(access) && exposed_tags.contains(&item.tag) { + if item.perm().grants(access) && exposed_tags.contains(&item.tag()) { Some(idx) } else { None @@ -161,9 +161,9 @@ impl<'tcx> Stack { // If we didn't find the tag in the cache, fall back to a linear search of the // whole stack, and add the tag to the cache. for (stack_idx, item) in self.borrows.iter().enumerate().rev() { - if tag == item.tag && item.perm.grants(access) { + if tag == item.tag() && item.perm().grants(access) { #[cfg(feature = "stack-cache")] - self.cache.add(stack_idx, tag); + self.cache.add(stack_idx, *item); return Some(stack_idx); } } @@ -175,7 +175,7 @@ impl<'tcx> Stack { // This looks like a common-sense optimization; we're going to do a linear search of the // cache or the borrow stack to scan the shorter of the two. This optimization is miniscule // and this check actually ensures we do not access an invalid cache. - // When a stack is created and when tags are removed from the top of the borrow stack, we + // When a stack is created and when items are removed from the top of the borrow stack, we // need some valid value to populate the cache. In both cases, we try to use the bottom // item. But when the stack is cleared in `set_unknown_bottom` there is nothing we could // place in the cache that is correct. But due to the way we populate the cache in @@ -185,21 +185,23 @@ impl<'tcx> Stack { return None; } // Search the cache for the tag we're looking up - let cache_idx = self.cache.tags.iter().position(|t| *t == tag)?; + let cache_idx = self.cache.items.iter().position(|t| t.tag() == tag)?; let stack_idx = self.cache.idx[cache_idx]; // If we found the tag, look up its position in the stack to see if it grants // the required permission - if self.borrows[stack_idx].perm.grants(access) { + if self.cache.items[cache_idx].perm().grants(access) { // If it does, and it's not already in the most-recently-used position, re-insert it at // the most-recently-used position. This technically reduces the efficiency of the // cache by duplicating elements, but current benchmarks do not seem to benefit from // avoiding this duplication. // But if the tag is in position 1, avoiding the duplicating add is trivial. + // If it does, and it's not already in the most-recently-used position, move it there. + // Except if the tag is in position 1, this is equivalent to just a swap, so do that. if cache_idx == 1 { - self.cache.tags.swap(0, 1); + self.cache.items.swap(0, 1); self.cache.idx.swap(0, 1); } else if cache_idx > 1 { - self.cache.add(stack_idx, tag); + self.cache.add(stack_idx, self.cache.items[cache_idx]); } Some(stack_idx) } else { @@ -224,7 +226,7 @@ impl<'tcx> Stack { if self.unique_range.end >= new_idx { self.unique_range.end += 1; } - if new.perm == Permission::Unique { + if new.perm() == Permission::Unique { // Make sure the possibly-unique range contains the new borrow self.unique_range.start = self.unique_range.start.min(new_idx); self.unique_range.end = self.unique_range.end.max(new_idx + 1); @@ -233,7 +235,7 @@ impl<'tcx> Stack { // The above insert changes the meaning of every index in the cache >= new_idx, so now // we need to find every one of those indexes and increment it. // But if the insert is at the end (equivalent to a push), we can skip this step because - // it didn't change the position of any other tags. + // it didn't change the position of any other items. if new_idx != self.borrows.len() - 1 { for idx in &mut self.cache.idx { if *idx >= new_idx { @@ -243,7 +245,7 @@ impl<'tcx> Stack { } // This primes the cache for the next access, which is almost always the just-added tag. - self.cache.add(new_idx, new.tag); + self.cache.add(new_idx, new); #[cfg(feature = "expensive-debug-assertions")] self.verify_cache_consistency(); @@ -255,9 +257,9 @@ impl<'tcx> Stack { borrows: vec![item], unknown_bottom: None, #[cfg(feature = "stack-cache")] - cache: StackCache { idx: [0; CACHE_LEN], tags: [item.tag; CACHE_LEN] }, + cache: StackCache { idx: [0; CACHE_LEN], items: [item; CACHE_LEN] }, #[cfg(feature = "stack-cache")] - unique_range: if item.perm == Permission::Unique { 0..1 } else { 0..0 }, + unique_range: if item.perm() == Permission::Unique { 0..1 } else { 0..0 }, } } @@ -298,10 +300,15 @@ impl<'tcx> Stack { let lower = unique_range.start.max(disable_start); let upper = (unique_range.end + 1).min(self.borrows.len()); for item in &mut self.borrows[lower..upper] { - if item.perm == Permission::Unique { + if item.perm() == Permission::Unique { log::trace!("access: disabling item {:?}", item); visitor(*item)?; - item.perm = Permission::Disabled; + item.set_disabled(); + for t in &mut self.cache.items { + if t.tag() == item.tag() { + t.set_disabled(); + } + } } } } @@ -341,7 +348,7 @@ impl<'tcx> Stack { // also possible that the whole cache is still valid. So we call this method to repair what // aspects of the cache are now invalid, instead of resetting the whole thing to a trivially // valid default state. - let base_tag = self.borrows[0].tag; + let base_tag = self.borrows[0]; let mut removed = 0; let mut cursor = 0; // Remove invalid entries from the cache by rotating them to the end of the cache, then @@ -350,7 +357,7 @@ impl<'tcx> Stack { for _ in 0..CACHE_LEN - 1 { if self.cache.idx[cursor] >= start { self.cache.idx[cursor..CACHE_LEN - removed].rotate_left(1); - self.cache.tags[cursor..CACHE_LEN - removed].rotate_left(1); + self.cache.items[cursor..CACHE_LEN - removed].rotate_left(1); removed += 1; } else { cursor += 1; @@ -358,7 +365,7 @@ impl<'tcx> Stack { } for i in CACHE_LEN - removed - 1..CACHE_LEN { self.cache.idx[i] = 0; - self.cache.tags[i] = base_tag; + self.cache.items[i] = base_tag; } if start < self.unique_range.start.saturating_sub(1) { diff --git a/src/thread.rs b/src/thread.rs index 420eeb810fd8..96135d093d96 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -281,6 +281,10 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { &mut self.threads[self.active_thread].stack } + pub fn all_stacks(&self) -> impl Iterator>]> { + self.threads.iter().map(|t| &t.stack[..]) + } + /// Create a new thread and returns its id. fn create_thread(&mut self) -> ThreadId { let new_thread_id = ThreadId::new(self.threads.len()); diff --git a/tests/fail/stacked_borrows/aliasing_mut1.stderr b/tests/fail/stacked_borrows/aliasing_mut1.stderr index 34a53aa8f307..82c504cd836f 100644 --- a/tests/fail/stacked_borrows/aliasing_mut1.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for ] (call ID) --> $DIR/aliasing_mut1.rs:LL:CC | LL | pub fn safe(_x: &mut i32, _y: &mut i32) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [Unique for ] (call ID) | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/aliasing_mut2.stderr b/tests/fail/stacked_borrows/aliasing_mut2.stderr index 7830648ee8f3..2973e22b2b79 100644 --- a/tests/fail/stacked_borrows/aliasing_mut2.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for ] (call ID) --> $DIR/aliasing_mut2.rs:LL:CC | LL | pub fn safe(_x: &i32, _y: &mut i32) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for ] (call ID) | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/aliasing_mut4.stderr b/tests/fail/stacked_borrows/aliasing_mut4.stderr index f62ce1e51964..b9a7b810dbd8 100644 --- a/tests/fail/stacked_borrows/aliasing_mut4.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut4.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for ] (call ID) --> $DIR/aliasing_mut4.rs:LL:CC | LL | pub fn safe(_x: &i32, _y: &mut Cell) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for ] (call ID) | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr b/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr index c3ea7a437cdb..124731e85bd5 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr +++ b/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: deallocating while item is protected: [Unique for (call ID)] +error: Undefined Behavior: deallocating while item is protected: [Unique for ] (call ID) --> RUSTLIB/alloc/src/alloc.rs:LL:CC | LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item is protected: [Unique for (call ID)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item is protected: [Unique for ] (call ID) | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr b/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr index d6c31e0649ec..e09158dfb408 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr +++ b/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: deallocating while item is protected: [SharedReadWrite for (call ID)] +error: Undefined Behavior: deallocating while item is protected: [SharedReadWrite for ] (call ID) --> RUSTLIB/alloc/src/alloc.rs:LL:CC | LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item is protected: [SharedReadWrite for (call ID)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item is protected: [SharedReadWrite for ] (call ID) | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/illegal_write6.stderr b/tests/fail/stacked_borrows/illegal_write6.stderr index cbf4a22f23f2..cab6f392d1b1 100644 --- a/tests/fail/stacked_borrows/illegal_write6.stderr +++ b/tests/fail/stacked_borrows/illegal_write6.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for ] (call ID) --> $DIR/illegal_write6.rs:LL:CC | LL | unsafe { *y = 2 }; - | ^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] + | ^^^^^^ not granting access to tag because incompatible item is protected: [Unique for ] (call ID) | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr index 5f54134a2431..40d5147cadff 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for ] (call ID) --> $DIR/invalidate_against_barrier1.rs:LL:CC | LL | let _val = unsafe { *x }; - | ^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] + | ^^ not granting access to tag because incompatible item is protected: [Unique for ] (call ID) | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr index 15bc91e869f9..30148396cc5d 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for ] (call ID) --> $DIR/invalidate_against_barrier2.rs:LL:CC | LL | unsafe { *x = 0 }; - | ^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] + | ^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for ] (call ID) | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/newtype_retagging.stderr b/tests/fail/stacked_borrows/newtype_retagging.stderr index 860a628492c7..337a22967c7d 100644 --- a/tests/fail/stacked_borrows/newtype_retagging.stderr +++ b/tests/fail/stacked_borrows/newtype_retagging.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for ] (call ID) --> RUSTLIB/alloc/src/boxed.rs:LL:CC | LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [Unique for ] (call ID) | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information From 4eff60ad6e37cd8f37e994d42c8c1ce271670bd4 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Mon, 11 Jul 2022 20:54:31 -0400 Subject: [PATCH 3502/5092] Rearrange and document the new implementation stacked_borrow now has an item module, and its own FrameExtra. These serve to protect the implementation of Item (which is a bunch of bit-packing tricks) from the primary logic of Stacked Borrows, and the FrameExtra we have separates Stacked Borrows more cleanly from the interpreter itself. The new strategy for checking protectors also makes some subtle performance tradeoffs, so they are now documented in Stack::item_popped because that function primarily benefits from them, and it also touches every aspect of them. Also separating the actual CallId that is protecting a Tag from the Tag makes it inconvienent to reproduce exactly the same protector errors, so this also takes the opportunity to use some slightly cleaner English in those errors. We need to make some change, might as well make it good. --- src/lib.rs | 4 +- src/machine.rs | 19 +- src/stacked_borrows.rs | 187 ++++++------------ src/stacked_borrows/item.rs | 104 ++++++++++ src/stacked_borrows/stack.rs | 9 +- tests/compiletest.rs | 2 +- .../fail/stacked_borrows/aliasing_mut1.stderr | 4 +- .../fail/stacked_borrows/aliasing_mut2.stderr | 4 +- .../fail/stacked_borrows/aliasing_mut4.stderr | 4 +- .../deallocate_against_barrier1.rs | 2 +- .../deallocate_against_barrier1.stderr | 4 +- .../deallocate_against_barrier2.rs | 2 +- .../deallocate_against_barrier2.stderr | 4 +- .../stacked_borrows/illegal_write6.stderr | 4 +- .../invalidate_against_barrier1.stderr | 4 +- .../invalidate_against_barrier2.stderr | 4 +- .../fail/stacked_borrows/newtype_retagging.rs | 2 +- .../stacked_borrows/newtype_retagging.stderr | 4 +- 18 files changed, 206 insertions(+), 161 deletions(-) create mode 100644 src/stacked_borrows/item.rs diff --git a/src/lib.rs b/src/lib.rs index f3e6e0eef70a..b3d408a6dc07 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -90,8 +90,8 @@ pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ - stack::Stack, CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag, - SbTagExtra, Stacks, + CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag, SbTagExtra, Stack, + Stacks, }; pub use crate::sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId}; pub use crate::thread::{ diff --git a/src/machine.rs b/src/machine.rs index 122bee2970e2..e31d7ba0105d 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -5,7 +5,6 @@ use std::borrow::Cow; use std::cell::RefCell; use std::collections::HashSet; use std::fmt; -use std::num::NonZeroU64; use std::time::Instant; use rand::rngs::StdRng; @@ -43,7 +42,7 @@ pub const NUM_CPUS: u64 = 1; /// Extra data stored with each stack frame pub struct FrameData<'tcx> { /// Extra data for Stacked Borrows. - pub call_id: stacked_borrows::CallId, + pub stacked_borrows: Option, /// If this is Some(), then this is a special "catch unwind" frame (the frame of `try_fn` /// called by `try`). When this frame is popped during unwinding a panic, @@ -54,18 +53,15 @@ pub struct FrameData<'tcx> { /// for the start of this frame. When we finish executing this frame, /// we use this to register a completed event with `measureme`. pub timing: Option, - - pub protected_tags: Vec, } impl<'tcx> std::fmt::Debug for FrameData<'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // Omitting `timing`, it does not support `Debug`. - let FrameData { call_id, catch_unwind, timing: _, protected_tags } = self; + let FrameData { stacked_borrows, catch_unwind, timing: _ } = self; f.debug_struct("FrameData") - .field("call_id", call_id) + .field("stacked_borrows", stacked_borrows) .field("catch_unwind", catch_unwind) - .field("protected_tags", protected_tags) .finish() } } @@ -894,11 +890,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { }; let stacked_borrows = ecx.machine.stacked_borrows.as_ref(); - let call_id = stacked_borrows.map_or(NonZeroU64::new(1).unwrap(), |stacked_borrows| { - stacked_borrows.borrow_mut().new_call() - }); - let extra = FrameData { call_id, catch_unwind: None, timing, protected_tags: Vec::new() }; + let extra = FrameData { + stacked_borrows: stacked_borrows.map(|sb| sb.borrow_mut().new_frame()), + catch_unwind: None, + timing, + }; Ok(frame.with_extra(extra)) } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 8996754be367..4cae27ecd219 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -16,6 +16,7 @@ use rustc_middle::ty::{ }; use rustc_span::DUMMY_SP; use rustc_target::abi::Size; +use smallvec::SmallVec; use std::collections::HashSet; use crate::*; @@ -23,8 +24,10 @@ use crate::*; pub mod diagnostics; use diagnostics::{AllocHistory, TagHistory}; -pub mod stack; -use stack::Stack; +mod item; +pub use item::{Item, Permission}; +mod stack; +pub use stack::Stack; pub type CallId = NonZeroU64; @@ -78,114 +81,22 @@ impl SbTagExtra { } } -/// Indicates which permission is granted (by this item to some pointers) -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -pub enum Permission { - /// Grants unique mutable access. - Unique, - /// Grants shared mutable access. - SharedReadWrite, - /// Grants shared read-only access. - SharedReadOnly, - /// Grants no access, but separates two groups of SharedReadWrite so they are not - /// all considered mutually compatible. - Disabled, +#[derive(Debug)] +pub struct FrameExtra { + /// The ID of the call this frame corresponds to. + call_id: CallId, + + /// If this frame is protecting any tags, they are listed here. We use this list to do + /// incremental updates of the global list of protected tags stored in the + /// `stacked_borrows::GlobalState` upon function return, and if we attempt to pop a protected + /// tag, to identify which call is responsible for protecting the tag. + /// See `Stack::item_popped` for more explanation. + /// + /// This will contain one tag per reference passed to the function, so + /// a size of 2 is enough for the vast majority of functions. + protected_tags: SmallVec<[SbTag; 2]>, } -impl Permission { - const UNIQUE: u64 = 0; - const SHARED_READ_WRITE: u64 = 1; - const SHARED_READ_ONLY: u64 = 2; - const DISABLED: u64 = 3; - - fn to_bits(self) -> u64 { - match self { - Permission::Unique => Self::UNIQUE, - Permission::SharedReadWrite => Self::SHARED_READ_WRITE, - Permission::SharedReadOnly => Self::SHARED_READ_ONLY, - Permission::Disabled => Self::DISABLED, - } - } - - fn from_bits(perm: u64) -> Self { - match perm { - Self::UNIQUE => Permission::Unique, - Self::SHARED_READ_WRITE => Permission::SharedReadWrite, - Self::SHARED_READ_ONLY => Permission::SharedReadOnly, - Self::DISABLED => Permission::Disabled, - _ => unreachable!(), - } - } -} - -mod item { - use super::{Permission, SbTag}; - use std::fmt; - use std::num::NonZeroU64; - - /// An item in the per-location borrow stack. - #[derive(Copy, Clone, Hash, PartialEq, Eq)] - pub struct Item(u64); - - // An Item contains 3 bitfields: - // * Bits 0-61 store an SbTag - // * Bits 61-63 store a Permission - // * Bit 64 stores a flag which indicates if we have a protector - const TAG_MASK: u64 = u64::MAX >> 3; - const PERM_MASK: u64 = 0x3 << 61; - const PROTECTED_MASK: u64 = 0x1 << 63; - - const PERM_SHIFT: u64 = 61; - const PROTECTED_SHIFT: u64 = 63; - - impl Item { - pub fn new(tag: SbTag, perm: Permission, protected: bool) -> Self { - assert!(tag.0.get() <= TAG_MASK); - let packed_tag = tag.0.get(); - let packed_perm = perm.to_bits() << PERM_SHIFT; - let packed_protected = (protected as u64) << PROTECTED_SHIFT; - - let new = Self(packed_tag | packed_perm | packed_protected); - - debug_assert!(new.tag() == tag); - debug_assert!(new.perm() == perm); - debug_assert!(new.protected() == protected); - - new - } - - /// The pointers the permission is granted to. - pub fn tag(self) -> SbTag { - SbTag(NonZeroU64::new(self.0 & TAG_MASK).unwrap()) - } - - /// The permission this item grants. - pub fn perm(self) -> Permission { - Permission::from_bits((self.0 & PERM_MASK) >> PERM_SHIFT) - } - - /// Whether or not there is a protector for this tag - pub fn protected(self) -> bool { - self.0 & PROTECTED_MASK > 0 - } - - /// Set the Permission stored in this Item to Permission::Disabled - pub fn set_disabled(&mut self) { - // Clear the current set permission - self.0 &= !PERM_MASK; - // Write Permission::Disabled to the Permission bits - self.0 |= Permission::Disabled.to_bits() << PERM_SHIFT; - } - } - - impl fmt::Debug for Item { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "[{:?} for {:?}]", self.perm(), self.tag()) - } - } -} -pub use item::Item; - /// Extra per-allocation state. #[derive(Clone, Debug)] pub struct Stacks { @@ -208,7 +119,11 @@ pub struct GlobalStateInner { base_ptr_tags: FxHashMap, /// Next unused call ID (for protectors). next_call_id: CallId, - /// All tags currently protected + /// All currently protected tags. + /// An item is protected if its tag is in this set, *and* it has the "protected" bit set. + /// We add tags to this when they are created with a protector in `reborrow`, and + /// we remove tags from this when the call which is protecting them returns, in + /// `GlobalStateInner::end_call`. See `Stack::item_popped` for more details. protected_tags: FxHashSet, /// The pointer ids to trace tracked_pointer_tags: HashSet, @@ -287,18 +202,23 @@ impl GlobalStateInner { id } - pub fn new_call(&mut self) -> CallId { - let id = self.next_call_id; - trace!("new_call: Assigning ID {}", id); - if self.tracked_call_ids.contains(&id) { - register_diagnostic(NonHaltingDiagnostic::CreatedCallId(id)); + pub fn new_frame(&mut self) -> FrameExtra { + let call_id = self.next_call_id; + trace!("new_frame: Assigning call ID {}", call_id); + if self.tracked_call_ids.contains(&call_id) { + register_diagnostic(NonHaltingDiagnostic::CreatedCallId(call_id)); } - self.next_call_id = NonZeroU64::new(id.get() + 1).unwrap(); - id + self.next_call_id = NonZeroU64::new(call_id.get() + 1).unwrap(); + FrameExtra { call_id, protected_tags: SmallVec::new() } } pub fn end_call(&mut self, frame: &machine::FrameData<'_>) { - for tag in &frame.protected_tags { + for tag in &frame + .stacked_borrows + .as_ref() + .expect("we should have Stacked Borrows data") + .protected_tags + { self.protected_tags.remove(tag); } } @@ -407,17 +327,40 @@ impl<'tcx> Stack { return Ok(()); } + // We store tags twice, once in global.protected_tags and once in each call frame. + // We do this because consulting a single global set in this function is faster + // than attempting to search all call frames in the program for the `FrameExtra` + // (if any) which is protecting the popped tag. + // + // This duplication trades off making `end_call` slower to make this function faster. This + // trade-off is profitable in practice for a combination of two reasons. + // 1. A single protected tag can (and does in some programs) protect thousands of `Item`s. + // Therefore, adding overhead to in function call/return is profitable even if it only + // saves a little work in this function. + // 2. Most frames protect only one or two tags. So this duplicative global turns a search + // which ends up about linear in the number of protected tags in the program into a + // constant time check (and a slow linear, because the tags in the frames aren't contiguous). if global.protected_tags.contains(&item.tag()) { + // This path is cold because it is fatal to the program. So here it is fine to do the + // more expensive search to figure out which call is responsible for protecting this + // tag. let call_id = threads .all_stacks() .flatten() - .find(|t| t.extra.protected_tags.contains(&item.tag())) - .map(|frame| frame.extra.call_id) + .map(|frame| { + frame + .extra + .stacked_borrows + .as_ref() + .expect("we should have Stacked Borrows data") + }) + .find(|frame| frame.protected_tags.contains(&item.tag())) + .map(|frame| frame.call_id) .unwrap(); // FIXME: Surely we should find something, but a panic seems wrong here? if let Some((tag, _alloc_range, _offset, _access)) = provoking_access { Err(err_sb_ub( format!( - "not granting access to tag {:?} because incompatible item is protected: {:?} (call {:?})", + "not granting access to tag {:?} because incompatible item {:?} is protected by call {:?}", tag, item, call_id ), None, @@ -426,7 +369,7 @@ impl<'tcx> Stack { } else { Err(err_sb_ub( format!( - "deallocating while item is protected: {:?} (call {:?})", + "deallocating while item {:?} is protected by call {:?}", item, call_id ), None, @@ -904,7 +847,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); if protect { - this.frame_mut().extra.protected_tags.push(new_tag); + this.frame_mut().extra.stacked_borrows.as_mut().unwrap().protected_tags.push(new_tag); this.machine.stacked_borrows.as_mut().unwrap().get_mut().protected_tags.insert(new_tag); } // FIXME: can't hold the current span handle across the borrows of self above diff --git a/src/stacked_borrows/item.rs b/src/stacked_borrows/item.rs new file mode 100644 index 000000000000..ad1b9b075b40 --- /dev/null +++ b/src/stacked_borrows/item.rs @@ -0,0 +1,104 @@ +use crate::stacked_borrows::SbTag; +use std::fmt; +use std::num::NonZeroU64; + +/// An item in the per-location borrow stack. +#[derive(Copy, Clone, Hash, PartialEq, Eq)] +pub struct Item(u64); + +// An Item contains 3 bitfields: +// * Bits 0-61 store an SbTag +// * Bits 61-63 store a Permission +// * Bit 64 stores a flag which indicates if we have a protector +const TAG_MASK: u64 = u64::MAX >> 3; +const PERM_MASK: u64 = 0x3 << 61; +const PROTECTED_MASK: u64 = 0x1 << 63; + +const PERM_SHIFT: u64 = 61; +const PROTECTED_SHIFT: u64 = 63; + +impl Item { + pub fn new(tag: SbTag, perm: Permission, protected: bool) -> Self { + assert!(tag.0.get() <= TAG_MASK); + let packed_tag = tag.0.get(); + let packed_perm = perm.to_bits() << PERM_SHIFT; + let packed_protected = (protected as u64) << PROTECTED_SHIFT; + + let new = Self(packed_tag | packed_perm | packed_protected); + + debug_assert!(new.tag() == tag); + debug_assert!(new.perm() == perm); + debug_assert!(new.protected() == protected); + + new + } + + /// The pointers the permission is granted to. + pub fn tag(self) -> SbTag { + SbTag(NonZeroU64::new(self.0 & TAG_MASK).unwrap()) + } + + /// The permission this item grants. + pub fn perm(self) -> Permission { + Permission::from_bits((self.0 & PERM_MASK) >> PERM_SHIFT) + } + + /// Whether or not there is a protector for this tag + pub fn protected(self) -> bool { + self.0 & PROTECTED_MASK > 0 + } + + /// Set the Permission stored in this Item + pub fn set_permission(&mut self, perm: Permission) { + // Clear the current set permission + self.0 &= !PERM_MASK; + // Write Permission::Disabled to the Permission bits + self.0 |= perm.to_bits() << PERM_SHIFT; + } +} + +impl fmt::Debug for Item { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{:?} for {:?}]", self.perm(), self.tag()) + } +} + +/// Indicates which permission is granted (by this item to some pointers) +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub enum Permission { + /// Grants unique mutable access. + Unique, + /// Grants shared mutable access. + SharedReadWrite, + /// Grants shared read-only access. + SharedReadOnly, + /// Grants no access, but separates two groups of SharedReadWrite so they are not + /// all considered mutually compatible. + Disabled, +} + +impl Permission { + const UNIQUE: u64 = 0; + const SHARED_READ_WRITE: u64 = 1; + const SHARED_READ_ONLY: u64 = 2; + const DISABLED: u64 = 3; + + fn to_bits(self) -> u64 { + match self { + Permission::Unique => Self::UNIQUE, + Permission::SharedReadWrite => Self::SHARED_READ_WRITE, + Permission::SharedReadOnly => Self::SHARED_READ_ONLY, + Permission::Disabled => Self::DISABLED, + } + } + + fn from_bits(perm: u64) -> Self { + match perm { + Self::UNIQUE => Permission::Unique, + Self::SHARED_READ_WRITE => Permission::SharedReadWrite, + Self::SHARED_READ_ONLY => Permission::SharedReadOnly, + Self::DISABLED => Permission::Disabled, + _ => unreachable!(), + } + } +} diff --git a/src/stacked_borrows/stack.rs b/src/stacked_borrows/stack.rs index 0863f8023277..1b05471618a5 100644 --- a/src/stacked_borrows/stack.rs +++ b/src/stacked_borrows/stack.rs @@ -303,10 +303,11 @@ impl<'tcx> Stack { if item.perm() == Permission::Unique { log::trace!("access: disabling item {:?}", item); visitor(*item)?; - item.set_disabled(); - for t in &mut self.cache.items { - if t.tag() == item.tag() { - t.set_disabled(); + item.set_permission(Permission::Disabled); + // Also update all copies of this item in the cache. + for it in &mut self.cache.items { + if it.tag() == item.tag() { + it.set_permission(Permission::Disabled); } } } diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 008fc7806457..c568d1c50434 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -97,7 +97,7 @@ regexes! { // erase specific alignments "alignment [0-9]+" => "alignment ALIGN", // erase thread caller ids - r"\(call [0-9]+\)" => "(call ID)", + r"call [0-9]+" => "call ID", // erase platform module paths "sys::[a-z]+::" => "sys::PLATFORM::", // Windows file paths diff --git a/tests/fail/stacked_borrows/aliasing_mut1.stderr b/tests/fail/stacked_borrows/aliasing_mut1.stderr index 82c504cd836f..b821d1e6edb4 100644 --- a/tests/fail/stacked_borrows/aliasing_mut1.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for ] (call ID) +error: Undefined Behavior: not granting access to tag because incompatible item [Unique for ] is protected by call ID --> $DIR/aliasing_mut1.rs:LL:CC | LL | pub fn safe(_x: &mut i32, _y: &mut i32) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [Unique for ] (call ID) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item [Unique for ] is protected by call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/aliasing_mut2.stderr b/tests/fail/stacked_borrows/aliasing_mut2.stderr index 2973e22b2b79..594b578fc09a 100644 --- a/tests/fail/stacked_borrows/aliasing_mut2.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for ] (call ID) +error: Undefined Behavior: not granting access to tag because incompatible item [SharedReadOnly for ] is protected by call ID --> $DIR/aliasing_mut2.rs:LL:CC | LL | pub fn safe(_x: &i32, _y: &mut i32) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for ] (call ID) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item [SharedReadOnly for ] is protected by call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/aliasing_mut4.stderr b/tests/fail/stacked_borrows/aliasing_mut4.stderr index b9a7b810dbd8..0c7d85ae5756 100644 --- a/tests/fail/stacked_borrows/aliasing_mut4.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut4.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for ] (call ID) +error: Undefined Behavior: not granting access to tag because incompatible item [SharedReadOnly for ] is protected by call ID --> $DIR/aliasing_mut4.rs:LL:CC | LL | pub fn safe(_x: &i32, _y: &mut Cell) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for ] (call ID) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item [SharedReadOnly for ] is protected by call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier1.rs b/tests/fail/stacked_borrows/deallocate_against_barrier1.rs index 0798f863ce11..20e026df7b9b 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier1.rs +++ b/tests/fail/stacked_borrows/deallocate_against_barrier1.rs @@ -1,4 +1,4 @@ -//@error-pattern: deallocating while item is protected +//@error-pattern: deallocating while item fn inner(x: &mut i32, f: fn(&mut i32)) { // `f` may mutate, but it may not deallocate! diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr b/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr index 124731e85bd5..689c0a5deae6 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr +++ b/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: deallocating while item is protected: [Unique for ] (call ID) +error: Undefined Behavior: deallocating while item [Unique for ] is protected by call ID --> RUSTLIB/alloc/src/alloc.rs:LL:CC | LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item is protected: [Unique for ] (call ID) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item [Unique for ] is protected by call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier2.rs b/tests/fail/stacked_borrows/deallocate_against_barrier2.rs index 23c54c8d8988..9cb2d52bf2e9 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier2.rs +++ b/tests/fail/stacked_borrows/deallocate_against_barrier2.rs @@ -1,4 +1,4 @@ -//@error-pattern: deallocating while item is protected +//@error-pattern: deallocating while item use std::marker::PhantomPinned; pub struct NotUnpin(i32, PhantomPinned); diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr b/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr index e09158dfb408..a1a7ce0c6bb6 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr +++ b/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: deallocating while item is protected: [SharedReadWrite for ] (call ID) +error: Undefined Behavior: deallocating while item [SharedReadWrite for ] is protected by call ID --> RUSTLIB/alloc/src/alloc.rs:LL:CC | LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item is protected: [SharedReadWrite for ] (call ID) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item [SharedReadWrite for ] is protected by call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/illegal_write6.stderr b/tests/fail/stacked_borrows/illegal_write6.stderr index cab6f392d1b1..42f7b3f8b54b 100644 --- a/tests/fail/stacked_borrows/illegal_write6.stderr +++ b/tests/fail/stacked_borrows/illegal_write6.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for ] (call ID) +error: Undefined Behavior: not granting access to tag because incompatible item [Unique for ] is protected by call ID --> $DIR/illegal_write6.rs:LL:CC | LL | unsafe { *y = 2 }; - | ^^^^^^ not granting access to tag because incompatible item is protected: [Unique for ] (call ID) + | ^^^^^^ not granting access to tag because incompatible item [Unique for ] is protected by call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr index 40d5147cadff..4a1b14e46094 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for ] (call ID) +error: Undefined Behavior: not granting access to tag because incompatible item [Unique for ] is protected by call ID --> $DIR/invalidate_against_barrier1.rs:LL:CC | LL | let _val = unsafe { *x }; - | ^^ not granting access to tag because incompatible item is protected: [Unique for ] (call ID) + | ^^ not granting access to tag because incompatible item [Unique for ] is protected by call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr index 30148396cc5d..c6f158316f51 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for ] (call ID) +error: Undefined Behavior: not granting access to tag because incompatible item [SharedReadOnly for ] is protected by call ID --> $DIR/invalidate_against_barrier2.rs:LL:CC | LL | unsafe { *x = 0 }; - | ^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for ] (call ID) + | ^^^^^^ not granting access to tag because incompatible item [SharedReadOnly for ] is protected by call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/newtype_retagging.rs b/tests/fail/stacked_borrows/newtype_retagging.rs index 4786cd02d954..f9cceb761af3 100644 --- a/tests/fail/stacked_borrows/newtype_retagging.rs +++ b/tests/fail/stacked_borrows/newtype_retagging.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-retag-fields -//@error-pattern: incompatible item is protected +//@error-pattern: is protected by call struct Newtype<'a>(&'a mut i32); fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) { diff --git a/tests/fail/stacked_borrows/newtype_retagging.stderr b/tests/fail/stacked_borrows/newtype_retagging.stderr index 337a22967c7d..d9aebecfda73 100644 --- a/tests/fail/stacked_borrows/newtype_retagging.stderr +++ b/tests/fail/stacked_borrows/newtype_retagging.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for ] (call ID) +error: Undefined Behavior: not granting access to tag because incompatible item [Unique for ] is protected by call ID --> RUSTLIB/alloc/src/boxed.rs:LL:CC | LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [Unique for ] (call ID) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item [Unique for ] is protected by call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information From 7d9f04f7a8b3ef3c0e00a50e58f86fa8d8cf34ea Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 9 Jul 2022 19:53:21 -0400 Subject: [PATCH 3503/5092] Add a benchmark of the hang-on-test-failure code path --- bench-cargo-miri/slice-get-unchecked/Cargo.lock | 7 +++++++ bench-cargo-miri/slice-get-unchecked/Cargo.toml | 8 ++++++++ bench-cargo-miri/slice-get-unchecked/src/main.rs | 12 ++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 bench-cargo-miri/slice-get-unchecked/Cargo.lock create mode 100644 bench-cargo-miri/slice-get-unchecked/Cargo.toml create mode 100644 bench-cargo-miri/slice-get-unchecked/src/main.rs diff --git a/bench-cargo-miri/slice-get-unchecked/Cargo.lock b/bench-cargo-miri/slice-get-unchecked/Cargo.lock new file mode 100644 index 000000000000..a375afaed309 --- /dev/null +++ b/bench-cargo-miri/slice-get-unchecked/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "slice-get-unchecked" +version = "0.1.0" diff --git a/bench-cargo-miri/slice-get-unchecked/Cargo.toml b/bench-cargo-miri/slice-get-unchecked/Cargo.toml new file mode 100644 index 000000000000..1ac2276866ff --- /dev/null +++ b/bench-cargo-miri/slice-get-unchecked/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "slice-get-unchecked" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/bench-cargo-miri/slice-get-unchecked/src/main.rs b/bench-cargo-miri/slice-get-unchecked/src/main.rs new file mode 100644 index 000000000000..a72083bd9de3 --- /dev/null +++ b/bench-cargo-miri/slice-get-unchecked/src/main.rs @@ -0,0 +1,12 @@ +//! This is a stripped-down version of the code pattern that causes runtime blowup when printing +//! backtraces in a failed test under cargo miri test with -Zmiri-disable-isolation. +//! See https://github.com/rust-lang/miri/issues/2273 + +fn main() { + let x = vec![0u8; 4096]; + let mut i = 0; + while i < x.len() { + let _element = unsafe { *x.get_unchecked(i) }; + i += 1; + } +} From 837bf8427165d6e56783a97a57061416d1ac2fec Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 13 Jul 2022 13:09:23 +0000 Subject: [PATCH 3504/5092] Error patterns can be regexes --- .../deallocate_against_barrier1.rs | 2 +- .../deallocate_against_barrier2.rs | 2 +- ui_test/README.md | 1 + ui_test/src/lib.rs | 24 ++++++------ ui_test/src/parser.rs | 39 ++++++++++++++++--- ui_test/src/parser/tests.rs | 29 +++++++++++--- 6 files changed, 73 insertions(+), 24 deletions(-) diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier1.rs b/tests/fail/stacked_borrows/deallocate_against_barrier1.rs index 20e026df7b9b..9b710424c55c 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier1.rs +++ b/tests/fail/stacked_borrows/deallocate_against_barrier1.rs @@ -1,4 +1,4 @@ -//@error-pattern: deallocating while item +//@error-pattern: /deallocating while item \[Unique for .*\] is protected/ fn inner(x: &mut i32, f: fn(&mut i32)) { // `f` may mutate, but it may not deallocate! diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier2.rs b/tests/fail/stacked_borrows/deallocate_against_barrier2.rs index 9cb2d52bf2e9..36e133e38365 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier2.rs +++ b/tests/fail/stacked_borrows/deallocate_against_barrier2.rs @@ -1,4 +1,4 @@ -//@error-pattern: deallocating while item +//@error-pattern: /deallocating while item \[SharedReadWrite for .*\] is protected/ use std::marker::PhantomPinned; pub struct NotUnpin(i32, PhantomPinned); diff --git a/ui_test/README.md b/ui_test/README.md index 24c5940382d1..55639c9589e1 100644 --- a/ui_test/README.md +++ b/ui_test/README.md @@ -17,6 +17,7 @@ to make sure that the test will always keep failing with a specific message at t * If the all caps note is left out, a message of any level is matched. Leaving it out is not allowed for `ERROR` levels. * This checks the output *before* normalization, so you can check things that get normalized away, but need to be careful not to accidentally have a pattern that differs between platforms. +* if `XXX` is of the form `/XXX/` it is treated as a regex instead of a substring and will succeed if the regex matches. In order to change how a single test is tested, you can add various `//@` comments to the test. Any other comments will be ignored, and all `//@` comments must be formatted precisely as diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index b2e71b762bea..32c04290bca2 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -10,7 +10,7 @@ use std::sync::Mutex; pub use color_eyre; use color_eyre::eyre::Result; use colored::*; -use parser::ErrorMatch; +use parser::{ErrorMatch, Pattern}; use regex::Regex; use rustc_stderr::{Level, Message}; @@ -177,7 +177,12 @@ pub fn run_tests(config: Config) -> Result<()> { match error { Error::ExitStatus(mode, exit_status) => eprintln!("{mode:?} got {exit_status}"), Error::PatternNotFound { pattern, definition_line } => { - eprintln!("`{pattern}` {} in stderr output", "not found".red()); + match pattern { + Pattern::SubString(s) => + eprintln!("substring `{s}` {} in stderr output", "not found".red()), + Pattern::Regex(r) => + eprintln!("`/{r}/` does {} stderr output", "not match".red()), + } eprintln!( "expected because of pattern here: {}:{definition_line}", path.display().to_string().bold() @@ -257,7 +262,7 @@ enum Error { /// Got an invalid exit status for the given mode. ExitStatus(Mode, ExitStatus), PatternNotFound { - pattern: String, + pattern: Pattern, definition_line: usize, }, /// A ui test checking for failure does not have any failure patterns @@ -384,14 +389,11 @@ fn check_annotations( // in the messages. if let Some(i) = messages_from_unknown_file_or_line .iter() - .position(|msg| msg.message.contains(error_pattern)) + .position(|msg| error_pattern.matches(&msg.message)) { messages_from_unknown_file_or_line.remove(i); } else { - errors.push(Error::PatternNotFound { - pattern: error_pattern.to_string(), - definition_line, - }); + errors.push(Error::PatternNotFound { pattern: error_pattern.clone(), definition_line }); } } @@ -399,7 +401,7 @@ fn check_annotations( // We will ensure that *all* diagnostics of level at least `lowest_annotation_level` // are matched. let mut lowest_annotation_level = Level::Error; - for &ErrorMatch { ref matched, revision: ref rev, definition_line, line, level } in + for &ErrorMatch { ref pattern, revision: ref rev, definition_line, line, level } in &comments.error_matches { if let Some(rev) = rev { @@ -415,14 +417,14 @@ fn check_annotations( if let Some(msgs) = messages.get_mut(line) { let found = - msgs.iter().position(|msg| msg.message.contains(matched) && msg.level == level); + msgs.iter().position(|msg| pattern.matches(&msg.message) && msg.level == level); if let Some(found) = found { msgs.remove(found); continue; } } - errors.push(Error::PatternNotFound { pattern: matched.to_string(), definition_line }); + errors.push(Error::PatternNotFound { pattern: pattern.clone(), definition_line }); } let filter = |msgs: Vec| -> Vec<_> { diff --git a/ui_test/src/parser.rs b/ui_test/src/parser.rs index 5b666eef66ef..7d810a95e412 100644 --- a/ui_test/src/parser.rs +++ b/ui_test/src/parser.rs @@ -29,7 +29,7 @@ pub(crate) struct Comments { /// Normalizations to apply to the stderr output before emitting it to disk pub normalize_stderr: Vec<(Regex, String)>, /// An arbitrary pattern to look for in the stderr. - pub error_pattern: Option<(String, usize)>, + pub error_pattern: Option<(Pattern, usize)>, pub error_matches: Vec, /// Ignore diagnostics below this level. /// `None` means pick the lowest level from the `error_pattern`s. @@ -45,9 +45,15 @@ pub(crate) enum Condition { Bitwidth(u8), } +#[derive(Debug, Clone)] +pub(crate) enum Pattern { + SubString(String), + Regex(Regex), +} + #[derive(Debug)] pub(crate) struct ErrorMatch { - pub matched: String, + pub pattern: Pattern, pub revision: Option, pub level: Level, /// The line where the message was defined, for reporting issues with it (e.g. in case it wasn't found). @@ -184,7 +190,7 @@ impl Comments { "cannot specifiy error_pattern twice, previous: {:?}", self.error_pattern ); - self.error_pattern = Some((args.trim().to_string(), l)); + self.error_pattern = Some((Pattern::parse(args.trim())?, l)); } "stderr-per-bitwidth" => { // args are ignored (can be used as comment) @@ -275,14 +281,16 @@ impl Comments { let pattern = &pattern[offset..]; let pattern = pattern.strip_prefix(':').ok_or_else(|| eyre!("no `:` after level found"))?; - let matched = pattern.trim().to_string(); + let pattern = pattern.trim(); - ensure!(!matched.is_empty(), "no pattern specified"); + ensure!(!pattern.is_empty(), "no pattern specified"); + + let pattern = Pattern::parse(pattern)?; *fallthrough_to = Some(match_line); self.error_matches.push(ErrorMatch { - matched, + pattern, revision, level, definition_line: l, @@ -292,3 +300,22 @@ impl Comments { Ok(()) } } + +impl Pattern { + pub(crate) fn matches(&self, message: &str) -> bool { + match self { + Pattern::SubString(s) => message.contains(s), + Pattern::Regex(r) => r.is_match(message), + } + } + + pub(crate) fn parse(pattern: &str) -> Result { + if let Some(pattern) = pattern.strip_prefix('/') { + let regex = + pattern.strip_suffix('/').ok_or_else(|| eyre!("regex must end with `/`"))?; + Ok(Pattern::Regex(Regex::new(regex)?)) + } else { + Ok(Pattern::SubString(pattern.to_string())) + } + } +} diff --git a/ui_test/src/parser/tests.rs b/ui_test/src/parser/tests.rs index f41c2f234ab8..343857d44bd3 100644 --- a/ui_test/src/parser/tests.rs +++ b/ui_test/src/parser/tests.rs @@ -1,5 +1,7 @@ use std::path::Path; +use crate::parser::Pattern; + use super::Comments; #[test] @@ -15,10 +17,11 @@ fn main() { println!("parsed comments: {:#?}", comments); assert_eq!(comments.error_matches[0].definition_line, 5); assert_eq!(comments.error_matches[0].revision, None); - assert_eq!( - comments.error_matches[0].matched, - "encountered a dangling reference (address $HEX is unallocated)" - ); + match &comments.error_matches[0].pattern { + Pattern::SubString(s) => + assert_eq!(s, "encountered a dangling reference (address $HEX is unallocated)"), + other => panic!("expected substring, got {other:?}"), + } } #[test] @@ -42,7 +45,23 @@ use std::mem; "; let comments = Comments::parse(Path::new(""), s).unwrap(); println!("parsed comments: {:#?}", comments); - assert_eq!(comments.error_pattern, Some(("foomp".to_string(), 2))); + let pat = comments.error_pattern.unwrap(); + assert_eq!(format!("{:?}", pat.0), r#"SubString("foomp")"#); + assert_eq!(pat.1, 2); +} + +#[test] +fn parse_regex_error_pattern() { + let s = r" +//@ error-pattern: /foomp/ +use std::mem; + + "; + let comments = Comments::parse(Path::new(""), s).unwrap(); + println!("parsed comments: {:#?}", comments); + let pat = comments.error_pattern.unwrap(); + assert_eq!(format!("{:?}", pat.0), r#"Regex(foomp)"#); + assert_eq!(pat.1, 2); } #[test] From 3bd0e8a2cac5b6141261b11c0d8b12e94ca908d3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Jul 2022 14:53:54 -0400 Subject: [PATCH 3505/5092] move checking ptr tracking on item pop into cold helper function --- src/stacked_borrows.rs | 101 +++++++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 39 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 4cae27ecd219..d9ccc773a018 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -316,11 +316,22 @@ impl<'tcx> Stack { alloc_history: &mut AllocHistory, threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { - if global.tracked_pointer_tags.contains(&item.tag()) { - register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag( - *item, - provoking_access.map(|(tag, _alloc_range, _size, access)| (tag, access)), - )); + if !global.tracked_pointer_tags.is_empty() { + check_tracked(item, &provoking_access, global); + + #[inline(never)] // cold path + fn check_tracked( + item: &Item, + provoking_access: &Option<(SbTagExtra, AllocRange, Size, AccessKind)>, + global: &GlobalStateInner, + ) { + if global.tracked_pointer_tags.contains(&item.tag()) { + register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag( + *item, + provoking_access.map(|(tag, _alloc_range, _size, access)| (tag, access)), + )); + } + } } if !item.protected() { @@ -341,40 +352,52 @@ impl<'tcx> Stack { // which ends up about linear in the number of protected tags in the program into a // constant time check (and a slow linear, because the tags in the frames aren't contiguous). if global.protected_tags.contains(&item.tag()) { - // This path is cold because it is fatal to the program. So here it is fine to do the - // more expensive search to figure out which call is responsible for protecting this - // tag. - let call_id = threads - .all_stacks() - .flatten() - .map(|frame| { - frame - .extra - .stacked_borrows - .as_ref() - .expect("we should have Stacked Borrows data") - }) - .find(|frame| frame.protected_tags.contains(&item.tag())) - .map(|frame| frame.call_id) - .unwrap(); // FIXME: Surely we should find something, but a panic seems wrong here? - if let Some((tag, _alloc_range, _offset, _access)) = provoking_access { - Err(err_sb_ub( - format!( - "not granting access to tag {:?} because incompatible item {:?} is protected by call {:?}", - tag, item, call_id - ), - None, - tag.and_then(|tag| alloc_history.get_logs_relevant_to(tag, Some(item.tag()))), - ))? - } else { - Err(err_sb_ub( - format!( - "deallocating while item {:?} is protected by call {:?}", - item, call_id - ), - None, - None, - ))? + return Err(protector_error(item, &provoking_access, alloc_history, threads)); + + #[inline(never)] // cold path + fn protector_error<'tcx>( + item: &Item, + provoking_access: &Option<(SbTagExtra, AllocRange, Size, AccessKind)>, + alloc_history: &mut AllocHistory, + threads: &ThreadManager<'_, 'tcx>, + ) -> InterpErrorInfo<'tcx> { + // This path is cold because it is fatal to the program. So here it is fine to do the + // more expensive search to figure out which call is responsible for protecting this + // tag. + let call_id = threads + .all_stacks() + .flatten() + .map(|frame| { + frame + .extra + .stacked_borrows + .as_ref() + .expect("we should have Stacked Borrows data") + }) + .find(|frame| frame.protected_tags.contains(&item.tag())) + .map(|frame| frame.call_id) + .unwrap(); // FIXME: Surely we should find something, but a panic seems wrong here? + if let Some((tag, _alloc_range, _offset, _access)) = provoking_access { + err_sb_ub( + format!( + "not granting access to tag {:?} because incompatible item {:?} is protected by call {:?}", + tag, item, call_id + ), + None, + tag.and_then(|tag| { + alloc_history.get_logs_relevant_to(tag, Some(item.tag())) + }), + ) + } else { + err_sb_ub( + format!( + "deallocating while item {:?} is protected by call {:?}", + item, call_id + ), + None, + None, + ) + }.into() } } Ok(()) From 757e88c901f7b8fed41829729b6a23317be12b3e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Jul 2022 18:59:33 -0400 Subject: [PATCH 3506/5092] use ui_test regex capabilities --- tests/fail/alloc/global_system_mixup.rs | 2 +- tests/fail/alloc/stack_free.rs | 2 +- tests/fail/provenance/ptr_int_unexposed.rs | 2 +- tests/fail/stacked_borrows/alias_through_mutation.rs | 2 +- tests/fail/stacked_borrows/box_exclusive_violation1.rs | 6 +++--- tests/fail/stacked_borrows/box_exclusive_violation1.stderr | 4 ++-- tests/fail/stacked_borrows/buggy_as_mut_slice.rs | 2 +- tests/fail/stacked_borrows/buggy_split_at_mut.rs | 2 +- tests/fail/stacked_borrows/exposed_only_ro.rs | 2 +- tests/fail/stacked_borrows/illegal_read1.rs | 2 +- tests/fail/stacked_borrows/illegal_read2.rs | 2 +- tests/fail/stacked_borrows/illegal_read3.rs | 2 +- tests/fail/stacked_borrows/illegal_read4.rs | 2 +- tests/fail/stacked_borrows/illegal_read5.rs | 2 +- tests/fail/stacked_borrows/illegal_read6.rs | 2 +- tests/fail/stacked_borrows/illegal_read7.rs | 2 +- tests/fail/stacked_borrows/illegal_read8.rs | 2 +- tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs | 2 +- tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs | 2 +- tests/fail/stacked_borrows/illegal_write1.rs | 2 +- tests/fail/stacked_borrows/illegal_write2.rs | 2 +- tests/fail/stacked_borrows/illegal_write3.rs | 2 +- tests/fail/stacked_borrows/illegal_write4.rs | 2 +- tests/fail/stacked_borrows/illegal_write5.rs | 2 +- tests/fail/stacked_borrows/illegal_write6.rs | 2 +- .../fail/stacked_borrows/illegal_write_despite_exposed1.rs | 3 ++- tests/fail/stacked_borrows/interior_mut1.rs | 2 +- tests/fail/stacked_borrows/interior_mut2.rs | 2 +- tests/fail/stacked_borrows/load_invalid_mut.rs | 2 +- tests/fail/stacked_borrows/load_invalid_shr.rs | 2 +- tests/fail/stacked_borrows/mut_exclusive_violation1.rs | 2 +- tests/fail/stacked_borrows/mut_exclusive_violation2.rs | 2 +- tests/fail/stacked_borrows/outdated_local.rs | 2 +- tests/fail/stacked_borrows/pass_invalid_mut.rs | 2 +- tests/fail/stacked_borrows/pass_invalid_shr.rs | 2 +- tests/fail/stacked_borrows/pointer_smuggling.rs | 2 +- tests/fail/stacked_borrows/raw_tracking.rs | 2 +- tests/fail/stacked_borrows/return_invalid_mut.rs | 2 +- tests/fail/stacked_borrows/return_invalid_mut_option.rs | 2 +- tests/fail/stacked_borrows/return_invalid_mut_tuple.rs | 2 +- tests/fail/stacked_borrows/return_invalid_shr.rs | 2 +- tests/fail/stacked_borrows/return_invalid_shr_option.rs | 2 +- tests/fail/stacked_borrows/return_invalid_shr_tuple.rs | 2 +- tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs | 2 +- tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs | 2 +- tests/fail/stacked_borrows/shr_frozen_violation1.rs | 2 +- tests/fail/stacked_borrows/transmute-is-no-escape.rs | 2 +- tests/fail/stacked_borrows/unescaped_local.rs | 2 +- tests/fail/stacked_borrows/unescaped_static.rs | 2 +- tests/fail/stacked_borrows/zst_slice.rs | 2 +- 50 files changed, 54 insertions(+), 53 deletions(-) diff --git a/tests/fail/alloc/global_system_mixup.rs b/tests/fail/alloc/global_system_mixup.rs index 01db2f1a225d..47b098c71a2b 100644 --- a/tests/fail/alloc/global_system_mixup.rs +++ b/tests/fail/alloc/global_system_mixup.rs @@ -1,6 +1,6 @@ // Make sure we detect when the `Global` and `System` allocators are mixed // (even when the default `Global` uses `System`). -//@error-pattern: which is Rust heap memory, using +//@error-pattern: /deallocating .*, which is Rust heap memory, using .* heap deallocation operation/ //@normalize-stderr-test: "using [A-Za-z]+ heap deallocation operation" -> "using PLATFORM heap deallocation operation" //@normalize-stderr-test: "\| +\^+" -> "| ^" diff --git a/tests/fail/alloc/stack_free.rs b/tests/fail/alloc/stack_free.rs index a97431bc2f05..baf53decc441 100644 --- a/tests/fail/alloc/stack_free.rs +++ b/tests/fail/alloc/stack_free.rs @@ -1,7 +1,7 @@ // Validation/SB changes why we fail //@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -//@error-pattern: which is stack variable memory, using Rust heap deallocation operation +//@error-pattern: /deallocating .*, which is stack variable memory, using Rust heap deallocation operation/ fn main() { let x = 42; diff --git a/tests/fail/provenance/ptr_int_unexposed.rs b/tests/fail/provenance/ptr_int_unexposed.rs index dd8d52b2d2e2..07de41d10a03 100644 --- a/tests/fail/provenance/ptr_int_unexposed.rs +++ b/tests/fail/provenance/ptr_int_unexposed.rs @@ -8,5 +8,5 @@ fn main() { let x_usize: usize = x_ptr.addr(); // Cast back an address that did *not* get exposed. let ptr = std::ptr::from_exposed_addr::(x_usize); - assert_eq!(unsafe { *ptr }, 3); //~ ERROR: Undefined Behavior: dereferencing pointer failed + assert_eq!(unsafe { *ptr }, 3); //~ ERROR: is a dangling pointer } diff --git a/tests/fail/stacked_borrows/alias_through_mutation.rs b/tests/fail/stacked_borrows/alias_through_mutation.rs index dfadeec6c9e9..73095bb2fc94 100644 --- a/tests/fail/stacked_borrows/alias_through_mutation.rs +++ b/tests/fail/stacked_borrows/alias_through_mutation.rs @@ -11,5 +11,5 @@ fn main() { retarget(&mut target_alias, target); // now `target_alias` points to the same thing as `target` *target = 13; - let _val = *target_alias; //~ ERROR: borrow stack + let _val = *target_alias; //~ ERROR: /read access .* tag does not exist in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/box_exclusive_violation1.rs b/tests/fail/stacked_borrows/box_exclusive_violation1.rs index ce7ff8f9e2aa..87a6b7bbd67e 100644 --- a/tests/fail/stacked_borrows/box_exclusive_violation1.rs +++ b/tests/fail/stacked_borrows/box_exclusive_violation1.rs @@ -1,4 +1,4 @@ -fn demo_mut_advanced_unique(mut our: Box) -> i32 { +fn demo_box_advanced_unique(mut our: Box) -> i32 { unknown_code_1(&*our); // This "re-asserts" uniqueness of the reference: After writing, we know @@ -24,10 +24,10 @@ fn unknown_code_1(x: &i32) { fn unknown_code_2() { unsafe { - *LEAK = 7; //~ ERROR: borrow stack + *LEAK = 7; //~ ERROR: /write access .* tag does not exist in the borrow stack/ } } fn main() { - demo_mut_advanced_unique(Box::new(0)); + demo_box_advanced_unique(Box::new(0)); } diff --git a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr index 88ecca87962d..7214ef27be33 100644 --- a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr +++ b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr @@ -21,7 +21,7 @@ LL | *our = 5; | ^^^^^^^^ = note: backtrace: = note: inside `unknown_code_2` at $DIR/box_exclusive_violation1.rs:LL:CC -note: inside `demo_mut_advanced_unique` at $DIR/box_exclusive_violation1.rs:LL:CC +note: inside `demo_box_advanced_unique` at $DIR/box_exclusive_violation1.rs:LL:CC --> $DIR/box_exclusive_violation1.rs:LL:CC | LL | unknown_code_2(); @@ -29,7 +29,7 @@ LL | unknown_code_2(); note: inside `main` at $DIR/box_exclusive_violation1.rs:LL:CC --> $DIR/box_exclusive_violation1.rs:LL:CC | -LL | demo_mut_advanced_unique(Box::new(0)); +LL | demo_box_advanced_unique(Box::new(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/fail/stacked_borrows/buggy_as_mut_slice.rs index 5eeec933c7c8..8615a9a58ad9 100644 --- a/tests/fail/stacked_borrows/buggy_as_mut_slice.rs +++ b/tests/fail/stacked_borrows/buggy_as_mut_slice.rs @@ -11,5 +11,5 @@ fn main() { let v1 = safe::as_mut_slice(&v); let _v2 = safe::as_mut_slice(&v); v1[1] = 5; - //~^ ERROR: borrow stack + //~^ ERROR: /write access .* tag does not exist in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/buggy_split_at_mut.rs b/tests/fail/stacked_borrows/buggy_split_at_mut.rs index 92380a4bf496..db64d559c517 100644 --- a/tests/fail/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/fail/stacked_borrows/buggy_split_at_mut.rs @@ -19,7 +19,7 @@ mod safe { fn main() { let mut array = [1, 2, 3, 4]; let (a, b) = safe::split_at_mut(&mut array, 0); - //~^ ERROR: borrow stack + //~^ ERROR: /reborrow .* tag does not exist in the borrow stack/ a[1] = 5; b[1] = 6; } diff --git a/tests/fail/stacked_borrows/exposed_only_ro.rs b/tests/fail/stacked_borrows/exposed_only_ro.rs index f2fdc213b143..0b4fb0ccd33b 100644 --- a/tests/fail/stacked_borrows/exposed_only_ro.rs +++ b/tests/fail/stacked_borrows/exposed_only_ro.rs @@ -8,5 +8,5 @@ fn main() { let _fool = &mut x as *mut i32; // this would have fooled the old untagged pointer logic let addr = (&x as *const i32).expose_addr(); let ptr = std::ptr::from_exposed_addr_mut::(addr); - unsafe { *ptr = 0 }; //~ ERROR: borrow stack + unsafe { *ptr = 0 }; //~ ERROR: /write access using .* no exposed tags have suitable permission in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/illegal_read1.rs b/tests/fail/stacked_borrows/illegal_read1.rs index b5734964060e..1dea282739ce 100644 --- a/tests/fail/stacked_borrows/illegal_read1.rs +++ b/tests/fail/stacked_borrows/illegal_read1.rs @@ -8,7 +8,7 @@ fn main() { let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. - //~^ ERROR: borrow stack + //~^ ERROR: /read access .* tag does not exist in the borrow stack/ } fn callee(xraw: *mut i32) { diff --git a/tests/fail/stacked_borrows/illegal_read2.rs b/tests/fail/stacked_borrows/illegal_read2.rs index ed6972c1deb9..b765b4d9ce99 100644 --- a/tests/fail/stacked_borrows/illegal_read2.rs +++ b/tests/fail/stacked_borrows/illegal_read2.rs @@ -8,7 +8,7 @@ fn main() { let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. - //~^ ERROR: borrow stack + //~^ ERROR: /read access .* tag does not exist in the borrow stack/ } fn callee(xraw: *mut i32) { diff --git a/tests/fail/stacked_borrows/illegal_read3.rs b/tests/fail/stacked_borrows/illegal_read3.rs index 0173ca14b22d..43ea0a0e84da 100644 --- a/tests/fail/stacked_borrows/illegal_read3.rs +++ b/tests/fail/stacked_borrows/illegal_read3.rs @@ -18,7 +18,7 @@ fn main() { callee(xref1_sneaky); // ... though any use of it will invalidate our ref. let _val = *xref2; - //~^ ERROR: borrow stack + //~^ ERROR: /read access .* tag does not exist in the borrow stack/ } fn callee(xref1: HiddenRef) { diff --git a/tests/fail/stacked_borrows/illegal_read4.rs b/tests/fail/stacked_borrows/illegal_read4.rs index 2d4e395a4270..a9ecb88d3520 100644 --- a/tests/fail/stacked_borrows/illegal_read4.rs +++ b/tests/fail/stacked_borrows/illegal_read4.rs @@ -5,5 +5,5 @@ fn main() { let xraw = xref1 as *mut _; let xref2 = unsafe { &mut *xraw }; let _val = unsafe { *xraw }; // use the raw again, this invalidates xref2 *even* with the special read except for uniq refs - let _illegal = *xref2; //~ ERROR: borrow stack + let _illegal = *xref2; //~ ERROR: /read access .* tag does not exist in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/illegal_read5.rs b/tests/fail/stacked_borrows/illegal_read5.rs index 49556e618d27..228c15f72e17 100644 --- a/tests/fail/stacked_borrows/illegal_read5.rs +++ b/tests/fail/stacked_borrows/illegal_read5.rs @@ -14,5 +14,5 @@ fn main() { let _val = *xref; // we can even still use our mutable reference mem::forget(unsafe { ptr::read(xshr) }); // but after reading through the shared ref let _val = *xref; // the mutable one is dead and gone - //~^ ERROR: borrow stack + //~^ ERROR: /read access .* tag does not exist in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/illegal_read6.rs b/tests/fail/stacked_borrows/illegal_read6.rs index 943a61af4f6e..4af22580ab64 100644 --- a/tests/fail/stacked_borrows/illegal_read6.rs +++ b/tests/fail/stacked_borrows/illegal_read6.rs @@ -5,6 +5,6 @@ fn main() { let raw = x as *mut _; let x = &mut *x; // kill `raw` let _y = &*x; // this should not activate `raw` again - let _val = *raw; //~ ERROR: borrow stack + let _val = *raw; //~ ERROR: /read access .* tag does not exist in the borrow stack/ } } diff --git a/tests/fail/stacked_borrows/illegal_read7.rs b/tests/fail/stacked_borrows/illegal_read7.rs index e263e8b70a91..c0d3816f4475 100644 --- a/tests/fail/stacked_borrows/illegal_read7.rs +++ b/tests/fail/stacked_borrows/illegal_read7.rs @@ -17,6 +17,6 @@ fn main() { // without invalidating `x`. That would be bad! It would mean that creating `shr` // leaked `x` to `raw`. let _val = ptr::read(raw); - let _val = *x.get_mut(); //~ ERROR: borrow stack + let _val = *x.get_mut(); //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ } } diff --git a/tests/fail/stacked_borrows/illegal_read8.rs b/tests/fail/stacked_borrows/illegal_read8.rs index 13c12cc75d77..f0a1658a5a23 100644 --- a/tests/fail/stacked_borrows/illegal_read8.rs +++ b/tests/fail/stacked_borrows/illegal_read8.rs @@ -10,6 +10,6 @@ fn main() { let _val = *y2; let _val = *y1; *y2 += 1; - let _fail = *y1; //~ ERROR: borrow stack + let _fail = *y1; //~ ERROR: /read access .* tag does not exist in the borrow stack/ } } diff --git a/tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs b/tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs index d779d4e44657..76516b7d924b 100644 --- a/tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs +++ b/tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs @@ -12,6 +12,6 @@ fn main() { // And we test that it has uniqueness by doing a conflicting write. *exposed_ptr = 0; // Stack: Unknown( u32 { *a = 1; let _b = &*a; - unsafe { *y = 2 }; //~ ERROR: not granting access to tag + unsafe { *y = 2 }; //~ ERROR: /not granting access .* because incompatible item .* is protected/ return *a; } diff --git a/tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs b/tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs index f14fcb14793c..0e34c5c98fc1 100644 --- a/tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs +++ b/tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs @@ -9,8 +9,9 @@ fn main() { let root2 = &*exposed_ptr; // Stack: Unknown( &mut i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &mut (*xraw).1 }; let _val = unsafe { *xraw }; // invalidate xref - ret //~ ERROR: borrow stack + ret //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ } fn main() { diff --git a/tests/fail/stacked_borrows/return_invalid_mut_option.rs b/tests/fail/stacked_borrows/return_invalid_mut_option.rs index 931b420166e7..da3401260e1e 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_option.rs +++ b/tests/fail/stacked_borrows/return_invalid_mut_option.rs @@ -10,7 +10,7 @@ fn foo(x: &mut (i32, i32)) -> Option<&mut i32> { fn main() { match foo(&mut (1, 2)) { - Some(_x) => {} //~ ERROR: borrow stack + Some(_x) => {} //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ None => {} } } diff --git a/tests/fail/stacked_borrows/return_invalid_mut_tuple.rs b/tests/fail/stacked_borrows/return_invalid_mut_tuple.rs index fbd9a6e5d269..2184d20b1cfa 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_tuple.rs +++ b/tests/fail/stacked_borrows/return_invalid_mut_tuple.rs @@ -8,5 +8,5 @@ fn foo(x: &mut (i32, i32)) -> (&mut i32,) { } fn main() { - foo(&mut (1, 2)).0; //~ ERROR: borrow stack + foo(&mut (1, 2)).0; //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/return_invalid_shr.rs b/tests/fail/stacked_borrows/return_invalid_shr.rs index a595b91c834c..b1d16c025ebf 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr.rs +++ b/tests/fail/stacked_borrows/return_invalid_shr.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> &i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &(*xraw).1 }; unsafe { *xraw = (42, 23) }; // unfreeze - ret //~ ERROR: borrow stack + ret //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ } fn main() { diff --git a/tests/fail/stacked_borrows/return_invalid_shr_option.rs b/tests/fail/stacked_borrows/return_invalid_shr_option.rs index 56af567f6e8f..e9faa945206e 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_option.rs +++ b/tests/fail/stacked_borrows/return_invalid_shr_option.rs @@ -9,7 +9,7 @@ fn foo(x: &mut (i32, i32)) -> Option<&i32> { fn main() { match foo(&mut (1, 2)) { - Some(_x) => {} //~ ERROR: borrow stack + Some(_x) => {} //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ None => {} } } diff --git a/tests/fail/stacked_borrows/return_invalid_shr_tuple.rs b/tests/fail/stacked_borrows/return_invalid_shr_tuple.rs index 38f01d7cc20b..11eb4de56c9f 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_tuple.rs +++ b/tests/fail/stacked_borrows/return_invalid_shr_tuple.rs @@ -8,5 +8,5 @@ fn foo(x: &mut (i32, i32)) -> (&i32,) { } fn main() { - foo(&mut (1, 2)).0; //~ ERROR: borrow stack + foo(&mut (1, 2)).0; //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs index 91994d286b95..01b2775d9d36 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs @@ -11,6 +11,6 @@ fn main() { let y: &mut Cell = mem::transmute(&mut *x); // launder lifetime let shr_rw = &*x; // thanks to interior mutability this will be a SharedReadWrite shr_rw.set(1); - y.get_mut(); //~ ERROR: borrow stack + y.get_mut(); //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ } } diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs index ee44ebbb0718..012e9561ca84 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs @@ -12,6 +12,6 @@ fn main() { let y: &i32 = mem::transmute(&*x.borrow()); // launder lifetime let shr_rw = &*x; // thanks to interior mutability this will be a SharedReadWrite shr_rw.replace(1); - let _val = *y; //~ ERROR: borrow stack + let _val = *y; //~ ERROR: /read access .* tag does not exist in the borrow stack/ } } diff --git a/tests/fail/stacked_borrows/shr_frozen_violation1.rs b/tests/fail/stacked_borrows/shr_frozen_violation1.rs index 11082da6ea3a..d1322dc6e57b 100644 --- a/tests/fail/stacked_borrows/shr_frozen_violation1.rs +++ b/tests/fail/stacked_borrows/shr_frozen_violation1.rs @@ -10,6 +10,6 @@ fn main() { fn unknown_code(x: &i32) { unsafe { - *(x as *const i32 as *mut i32) = 7; //~ ERROR: only grants SharedReadOnly permission + *(x as *const i32 as *mut i32) = 7; //~ ERROR: /write access .* only grants SharedReadOnly permission/ } } diff --git a/tests/fail/stacked_borrows/transmute-is-no-escape.rs b/tests/fail/stacked_borrows/transmute-is-no-escape.rs index c7d609023201..233b927dfc7e 100644 --- a/tests/fail/stacked_borrows/transmute-is-no-escape.rs +++ b/tests/fail/stacked_borrows/transmute-is-no-escape.rs @@ -10,5 +10,5 @@ fn main() { let _raw: *mut i32 = unsafe { mem::transmute(&mut x[0]) }; // `raw` still carries a tag, so we get another pointer to the same location that does not carry a tag let raw = (&mut x[1] as *mut i32).wrapping_offset(-1); - unsafe { *raw = 13 }; //~ ERROR: borrow stack + unsafe { *raw = 13 }; //~ ERROR: /write access .* tag does not exist in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/unescaped_local.rs b/tests/fail/stacked_borrows/unescaped_local.rs index 5b808472b4e6..49c0e66d8570 100644 --- a/tests/fail/stacked_borrows/unescaped_local.rs +++ b/tests/fail/stacked_borrows/unescaped_local.rs @@ -7,6 +7,6 @@ fn main() { let raw = &mut x as *mut i32 as usize as *mut i32; let _ptr = &mut x; unsafe { - *raw = 13; //~ ERROR: borrow stack + *raw = 13; //~ ERROR: /write access .* no exposed tags/ } } diff --git a/tests/fail/stacked_borrows/unescaped_static.rs b/tests/fail/stacked_borrows/unescaped_static.rs index 66641d648d86..a25d9b5162ec 100644 --- a/tests/fail/stacked_borrows/unescaped_static.rs +++ b/tests/fail/stacked_borrows/unescaped_static.rs @@ -3,5 +3,5 @@ static ARRAY: [u8; 2] = [0, 1]; fn main() { let ptr_to_first = &ARRAY[0] as *const u8; // Illegally use this to access the 2nd element. - let _val = unsafe { *ptr_to_first.add(1) }; //~ ERROR: borrow stack + let _val = unsafe { *ptr_to_first.add(1) }; //~ ERROR: /read access .* tag does not exist in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/zst_slice.rs b/tests/fail/stacked_borrows/zst_slice.rs index 3e27f514bc88..11065186fc49 100644 --- a/tests/fail/stacked_borrows/zst_slice.rs +++ b/tests/fail/stacked_borrows/zst_slice.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-strict-provenance -//@error-pattern: does not exist in the borrow stack +//@error-pattern: /reborrow .* tag does not exist in the borrow stack/ fn main() { unsafe { From 83b9172774a9894ee484e4eb693368282d8f0a32 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Jul 2022 19:37:41 -0400 Subject: [PATCH 3507/5092] move stacked_borrows.rs together with the other files of its module --- src/{stacked_borrows.rs => stacked_borrows/mod.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{stacked_borrows.rs => stacked_borrows/mod.rs} (100%) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows/mod.rs similarity index 100% rename from src/stacked_borrows.rs rename to src/stacked_borrows/mod.rs From cc42cb1b21c31af582ee109d7069224f91c9f278 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Jul 2022 19:40:53 -0400 Subject: [PATCH 3508/5092] reborrow error: clarify that we are reborrowing *from* that tag --- src/stacked_borrows/diagnostics.rs | 2 +- tests/fail/box-cell-alias.stderr | 4 ++-- tests/fail/stacked_borrows/aliasing_mut3.stderr | 4 ++-- tests/fail/stacked_borrows/buggy_split_at_mut.stderr | 4 ++-- tests/fail/stacked_borrows/illegal_read7.stderr | 4 ++-- tests/fail/stacked_borrows/interior_mut1.stderr | 4 ++-- tests/fail/stacked_borrows/interior_mut2.stderr | 4 ++-- tests/fail/stacked_borrows/load_invalid_mut.stderr | 4 ++-- tests/fail/stacked_borrows/load_invalid_shr.stderr | 4 ++-- tests/fail/stacked_borrows/pass_invalid_mut.stderr | 4 ++-- tests/fail/stacked_borrows/pass_invalid_shr.stderr | 4 ++-- tests/fail/stacked_borrows/return_invalid_mut.stderr | 4 ++-- tests/fail/stacked_borrows/return_invalid_mut_option.stderr | 4 ++-- tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr | 4 ++-- tests/fail/stacked_borrows/return_invalid_shr.stderr | 4 ++-- tests/fail/stacked_borrows/return_invalid_shr_option.stderr | 4 ++-- tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr | 4 ++-- tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr | 4 ++-- tests/fail/stacked_borrows/zst_slice.stderr | 4 ++-- 19 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index 1fa619a3ae4d..133164f390df 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -140,7 +140,7 @@ impl AllocHistory { stack: &Stack, ) -> InterpError<'tcx> { let action = format!( - "trying to reborrow {derived_from:?} for {new_perm:?} permission at {alloc_id:?}[{offset:#x}]", + "trying to reborrow from {derived_from:?} for {new_perm:?} permission at {alloc_id:?}[{offset:#x}]", new_perm = new.perm(), offset = error_offset.bytes(), ); diff --git a/tests/fail/box-cell-alias.stderr b/tests/fail/box-cell-alias.stderr index c7fd1c6415e0..705348ba0f06 100644 --- a/tests/fail/box-cell-alias.stderr +++ b/tests/fail/box-cell-alias.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/box-cell-alias.rs:LL:CC | LL | unsafe { (*ptr).set(20) }; | ^^^^^^^^^^^^^^ | | - | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x1] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/aliasing_mut3.stderr b/tests/fail/stacked_borrows/aliasing_mut3.stderr index 8e489b738657..0bb7b8d3a85c 100644 --- a/tests/fail/stacked_borrows/aliasing_mut3.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut3.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/aliasing_mut3.rs:LL:CC | LL | pub fn safe(_x: &mut i32, _y: &i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/buggy_split_at_mut.stderr b/tests/fail/stacked_borrows/buggy_split_at_mut.stderr index 6e6dc38aaf06..41ab9cfa92ae 100644 --- a/tests/fail/stacked_borrows/buggy_split_at_mut.stderr +++ b/tests/fail/stacked_borrows/buggy_split_at_mut.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/buggy_split_at_mut.rs:LL:CC | LL | let (a, b) = safe::split_at_mut(&mut array, 0); | ^ | | - | trying to reborrow for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x10] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/illegal_read7.stderr b/tests/fail/stacked_borrows/illegal_read7.stderr index 56ebd93918bf..11335df4da0a 100644 --- a/tests/fail/stacked_borrows/illegal_read7.stderr +++ b/tests/fail/stacked_borrows/illegal_read7.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/illegal_read7.rs:LL:CC | LL | let _val = *x.get_mut(); | ^^^^^^^^^^^ | | - | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/interior_mut1.stderr b/tests/fail/stacked_borrows/interior_mut1.stderr index 73be074ce91a..a2643841eac1 100644 --- a/tests/fail/stacked_borrows/interior_mut1.stderr +++ b/tests/fail/stacked_borrows/interior_mut1.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/interior_mut1.rs:LL:CC | LL | let _val = *inner_shr.get(); | ^^^^^^^^^^^^^^^ | | - | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/interior_mut2.stderr b/tests/fail/stacked_borrows/interior_mut2.stderr index 74e91d49c418..0dbf6e2ea9f9 100644 --- a/tests/fail/stacked_borrows/interior_mut2.stderr +++ b/tests/fail/stacked_borrows/interior_mut2.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/interior_mut2.rs:LL:CC | LL | let _val = *inner_shr.get(); | ^^^^^^^^^^^^^^^ | | - | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/load_invalid_mut.stderr b/tests/fail/stacked_borrows/load_invalid_mut.stderr index 293d85cc9f45..f8e03c631eee 100644 --- a/tests/fail/stacked_borrows/load_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/load_invalid_mut.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/load_invalid_mut.rs:LL:CC | LL | let _val = *xref_in_mem; | ^^^^^^^^^^^^ | | - | trying to reborrow for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/load_invalid_shr.stderr b/tests/fail/stacked_borrows/load_invalid_shr.stderr index 5749daa51fd9..a9546c9a7680 100644 --- a/tests/fail/stacked_borrows/load_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/load_invalid_shr.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/load_invalid_shr.rs:LL:CC | LL | let _val = *xref_in_mem; | ^^^^^^^^^^^^ | | - | trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/pass_invalid_mut.stderr b/tests/fail/stacked_borrows/pass_invalid_mut.stderr index 933ef1ad5970..f254fd16dcbe 100644 --- a/tests/fail/stacked_borrows/pass_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/pass_invalid_mut.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/pass_invalid_mut.rs:LL:CC | LL | foo(xref); | ^^^^ | | - | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/pass_invalid_shr.stderr b/tests/fail/stacked_borrows/pass_invalid_shr.stderr index 02cf62f03326..28500836aa8d 100644 --- a/tests/fail/stacked_borrows/pass_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/pass_invalid_shr.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/pass_invalid_shr.rs:LL:CC | LL | foo(xref); | ^^^^ | | - | trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/return_invalid_mut.stderr b/tests/fail/stacked_borrows/return_invalid_mut.stderr index 230c3e82ff23..7c8007044370 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> $DIR/return_invalid_mut.rs:LL:CC | LL | ret | ^^^ | | - | trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/return_invalid_mut_option.stderr b/tests/fail/stacked_borrows/return_invalid_mut_option.stderr index f278113e4257..cab997b47357 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_option.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut_option.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> $DIR/return_invalid_mut_option.rs:LL:CC | LL | Some(_x) => {} | ^^ | | - | trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr b/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr index 9465fd072ea9..46ef6a737a63 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> $DIR/return_invalid_mut_tuple.rs:LL:CC | LL | foo(&mut (1, 2)).0; | ^^^^^^^^^^^^^^^^^^ | | - | trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/return_invalid_shr.stderr b/tests/fail/stacked_borrows/return_invalid_shr.stderr index 75ea8bb89ec0..6f745b69fc72 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> $DIR/return_invalid_shr.rs:LL:CC | LL | ret | ^^^ | | - | trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/return_invalid_shr_option.stderr b/tests/fail/stacked_borrows/return_invalid_shr_option.stderr index 27656b46ccfc..2441c9aa1c51 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_option.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr_option.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> $DIR/return_invalid_shr_option.rs:LL:CC | LL | Some(_x) => {} | ^^ | | - | trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr b/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr index 9fdc87808651..5102f7cb53c4 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> $DIR/return_invalid_shr_tuple.rs:LL:CC | LL | foo(&mut (1, 2)).0; | ^^^^^^^^^^^^^^^^^^ | | - | trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr index 9909778ab28e..a412add67e02 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/shared_rw_borrows_are_weak1.rs:LL:CC | LL | y.get_mut(); | ^^^^^^^^^^^ | | - | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/zst_slice.stderr b/tests/fail/stacked_borrows/zst_slice.stderr index 2878f4c069af..d47e967b543b 100644 --- a/tests/fail/stacked_borrows/zst_slice.stderr +++ b/tests/fail/stacked_borrows/zst_slice.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> RUSTLIB/core/src/slice/mod.rs:LL:CC | LL | unsafe { &*index.get_unchecked(self) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental From a272ca2cf7f4cfa227d9d9ffddf910aa2e0fb169 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Jul 2022 20:18:45 -0400 Subject: [PATCH 3509/5092] add another weak mem consistency test --- tests/pass/0weak_memory_consistency.rs | 51 +++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/tests/pass/0weak_memory_consistency.rs b/tests/pass/0weak_memory_consistency.rs index 19e19b47cfed..668635d7ff8a 100644 --- a/tests/pass/0weak_memory_consistency.rs +++ b/tests/pass/0weak_memory_consistency.rs @@ -20,8 +20,8 @@ // "Mathematizing C++ concurrency", ACM SIGPLAN Notices, vol. 46, no. 1, pp. 55-66, 2011. // Available: https://ss265.host.cs.st-andrews.ac.uk/papers/n3132.pdf. -use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::*; +use std::sync::atomic::{fence, AtomicBool, AtomicI32}; use std::thread::spawn; #[derive(Copy, Clone)] @@ -32,13 +32,17 @@ unsafe impl Sync for EvilSend {} // We can't create static items because we need to run each test // multiple times -fn static_atomic(val: usize) -> &'static AtomicUsize { - let ret = Box::leak(Box::new(AtomicUsize::new(val))); +fn static_atomic(val: i32) -> &'static AtomicI32 { + let ret = Box::leak(Box::new(AtomicI32::new(val))); + ret +} +fn static_atomic_bool(val: bool) -> &'static AtomicBool { + let ret = Box::leak(Box::new(AtomicBool::new(val))); ret } // Spins until it acquires a pre-determined value. -fn acquires_value(loc: &AtomicUsize, val: usize) -> usize { +fn acquires_value(loc: &AtomicI32, val: i32) -> i32 { while loc.load(Acquire) != val { std::hint::spin_loop(); } @@ -207,7 +211,7 @@ fn test_sc_store_buffering() { } fn test_single_thread() { - let x = AtomicUsize::new(42); + let x = AtomicI32::new(42); assert_eq!(x.load(Relaxed), 42); @@ -216,6 +220,42 @@ fn test_single_thread() { assert_eq!(x.load(Relaxed), 43); } +fn test_sync_through_rmw_and_fences() { + // Example from https://github.com/llvm/llvm-project/issues/56450#issuecomment-1183695905 + #[no_mangle] + pub fn rdmw(storing: &AtomicI32, sync: &AtomicI32, loading: &AtomicI32) -> i32 { + storing.store(1, Relaxed); + fence(Release); + sync.fetch_add(0, Relaxed); + fence(Acquire); + loading.load(Relaxed) + } + + let x = static_atomic(0); + let y = static_atomic(0); + let z = static_atomic(0); + + // Since each thread is so short, we need to make sure that they truely run at the same time + // Otherwise t1 will finish before t2 even starts + let go = static_atomic_bool(false); + + let t1 = spawn(move || { + while !go.load(Relaxed) {} + rdmw(y, x, z) + }); + + let t2 = spawn(move || { + while !go.load(Relaxed) {} + rdmw(z, x, y) + }); + + go.store(true, Relaxed); + + let a = t1.join().unwrap(); + let b = t2.join().unwrap(); + assert_ne!((a, b), (0, 0)); +} + pub fn main() { for _ in 0..50 { test_single_thread(); @@ -225,5 +265,6 @@ pub fn main() { test_wrc(); test_corr(); test_sc_store_buffering(); + test_sync_through_rmw_and_fences(); } } From bd69a92b4b794bde4900385d6befaf644accb496 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Jul 2022 22:35:45 -0400 Subject: [PATCH 3510/5092] rustup --- rust-version | 2 +- tests/pass/union-overwrite.rs | 2 -- tests/pass/union.rs | 3 +-- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 2a26cb608235..3b418bcb11d1 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c396bb3b8a16b1f2762b7c6078dc3e023f6a2493 +cbb07c27a4d78f95557a6b9cdcc32f98d67a0c22 diff --git a/tests/pass/union-overwrite.rs b/tests/pass/union-overwrite.rs index d3c81834bc4b..f1d3d9d48101 100644 --- a/tests/pass/union-overwrite.rs +++ b/tests/pass/union-overwrite.rs @@ -1,5 +1,3 @@ -#![feature(untagged_unions)] - #[repr(C)] #[derive(Clone, Copy)] struct Pair(T, U); diff --git a/tests/pass/union.rs b/tests/pass/union.rs index f98a21310285..8a6dd49f4503 100644 --- a/tests/pass/union.rs +++ b/tests/pass/union.rs @@ -1,5 +1,3 @@ -#![feature(untagged_unions)] - fn main() { a(); b(); @@ -22,6 +20,7 @@ fn a() { } fn b() { + #[derive(Copy, Clone)] struct S { x: u32, y: u32, From 11f2b834648bb07ce64c1dcd3c4b7dd0252ab9bb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Jul 2022 07:29:20 -0400 Subject: [PATCH 3511/5092] fix a missing thread join --- tests/pass/concurrency/sync.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/pass/concurrency/sync.rs b/tests/pass/concurrency/sync.rs index b7e6f229faae..64bd7ebb27fd 100644 --- a/tests/pass/concurrency/sync.rs +++ b/tests/pass/concurrency/sync.rs @@ -219,10 +219,8 @@ fn park_unpark() { // know Miri's timed synchronization primitives do not do that. assert!((200..1000).contains(&start.elapsed().as_millis())); -} -fn check_condvar() { - let _ = std::sync::Condvar::new(); + t2.join().unwrap(); } fn main() { @@ -236,5 +234,4 @@ fn main() { check_once(); park_timeout(); park_unpark(); - check_condvar(); } From 820f322b86772fe3fdadebb587cc877efff4e61c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Jul 2022 08:07:59 -0400 Subject: [PATCH 3512/5092] add work-around for #2164 --- tests/pass/0weak_memory_consistency.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/pass/0weak_memory_consistency.rs b/tests/pass/0weak_memory_consistency.rs index 668635d7ff8a..8b7ce50d2d42 100644 --- a/tests/pass/0weak_memory_consistency.rs +++ b/tests/pass/0weak_memory_consistency.rs @@ -34,10 +34,12 @@ unsafe impl Sync for EvilSend {} // multiple times fn static_atomic(val: i32) -> &'static AtomicI32 { let ret = Box::leak(Box::new(AtomicI32::new(val))); + ret.store(val, Relaxed); // work around https://github.com/rust-lang/miri/issues/2164 ret } fn static_atomic_bool(val: bool) -> &'static AtomicBool { let ret = Box::leak(Box::new(AtomicBool::new(val))); + ret.store(val, Relaxed); // work around https://github.com/rust-lang/miri/issues/2164 ret } From 07c3e42bd7c21be29227646dfce465cb57827465 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Jul 2022 08:13:24 -0400 Subject: [PATCH 3513/5092] replace a macro by a function --- tests/pass/weak_memory/weak.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/tests/pass/weak_memory/weak.rs b/tests/pass/weak_memory/weak.rs index 1d82b85844f4..5e2e78882de5 100644 --- a/tests/pass/weak_memory/weak.rs +++ b/tests/pass/weak_memory/weak.rs @@ -72,7 +72,7 @@ fn seq_cst() -> bool { fn initialization_write() -> bool { let x = static_atomic(11); - assert_eq!(x.load(Relaxed), 11); + assert_eq!(x.load(Relaxed), 11); // work around https://github.com/rust-lang/miri/issues/2164 let wait = static_atomic(0); @@ -94,15 +94,13 @@ fn initialization_write() -> bool { r2 == 11 } -// Asserts that the function returns true at least once in 100 runs -macro_rules! assert_once { - ($f:ident) => { - assert!(std::iter::repeat_with(|| $f()).take(100).any(|x| x)); - }; +/// Asserts that the function returns true at least once in 100 runs +fn assert_once(f: fn() -> bool) { + assert!(std::iter::repeat_with(|| f()).take(100).any(|x| x)); } pub fn main() { - assert_once!(relaxed); - assert_once!(seq_cst); - assert_once!(initialization_write); + assert_once(relaxed); + assert_once(seq_cst); + assert_once(initialization_write); } From b8a0c49e51a65aff7189da95583fb5273c02ce37 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Jul 2022 08:23:04 -0400 Subject: [PATCH 3514/5092] test that we can see this weak behavior --- tests/pass/weak_memory/weak.rs | 51 ++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/tests/pass/weak_memory/weak.rs b/tests/pass/weak_memory/weak.rs index 5e2e78882de5..71d57dd11ec7 100644 --- a/tests/pass/weak_memory/weak.rs +++ b/tests/pass/weak_memory/weak.rs @@ -8,8 +8,8 @@ // Spurious failure is possible, if you are really unlucky with // the RNG and always read the latest value from the store buffer. -use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::*; +use std::sync::atomic::{fence, AtomicUsize}; use std::thread::spawn; #[derive(Copy, Clone)] @@ -70,7 +70,7 @@ fn seq_cst() -> bool { r3 == 1 } -fn initialization_write() -> bool { +fn initialization_write(add_fence: bool) -> bool { let x = static_atomic(11); assert_eq!(x.load(Relaxed), 11); // work around https://github.com/rust-lang/miri/issues/2164 @@ -85,6 +85,9 @@ fn initialization_write() -> bool { let j2 = spawn(move || { reads_value(wait, 1); + if add_fence { + fence(AcqRel); + } x.load(Relaxed) }); @@ -94,6 +97,46 @@ fn initialization_write() -> bool { r2 == 11 } +fn faa_replaced_by_load() -> bool { + // Example from https://github.com/llvm/llvm-project/issues/56450#issuecomment-1183695905 + #[no_mangle] + pub fn rdmw(storing: &AtomicUsize, sync: &AtomicUsize, loading: &AtomicUsize) -> usize { + storing.store(1, Relaxed); + fence(Release); + // sync.fetch_add(0, Relaxed); + sync.load(Relaxed); + fence(Acquire); + loading.load(Relaxed) + } + + let x = static_atomic(0); + assert_eq!(x.load(Relaxed), 0); // work around https://github.com/rust-lang/miri/issues/2164 + let y = static_atomic(0); + assert_eq!(y.load(Relaxed), 0); // work around https://github.com/rust-lang/miri/issues/2164 + let z = static_atomic(0); + assert_eq!(z.load(Relaxed), 0); // work around https://github.com/rust-lang/miri/issues/2164 + + // Since each thread is so short, we need to make sure that they truely run at the same time + // Otherwise t1 will finish before t2 even starts + let go = static_atomic(0); + + let t1 = spawn(move || { + while go.load(Relaxed) == 0 {} + rdmw(y, x, z) + }); + + let t2 = spawn(move || { + while go.load(Relaxed) == 0 {} + rdmw(z, x, y) + }); + + go.store(1, Relaxed); + + let a = t1.join().unwrap(); + let b = t2.join().unwrap(); + (a, b) == (0, 0) +} + /// Asserts that the function returns true at least once in 100 runs fn assert_once(f: fn() -> bool) { assert!(std::iter::repeat_with(|| f()).take(100).any(|x| x)); @@ -102,5 +145,7 @@ fn assert_once(f: fn() -> bool) { pub fn main() { assert_once(relaxed); assert_once(seq_cst); - assert_once(initialization_write); + assert_once(|| initialization_write(false)); + assert_once(|| initialization_write(true)); + assert_once(faa_replaced_by_load); } From eaa7f10cb1087bed06f96a84c55253881bfdeb15 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Jul 2022 09:54:20 -0400 Subject: [PATCH 3515/5092] rustup --- rust-version | 2 +- src/shims/backtrace.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 3b418bcb11d1..45abe7e8c653 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -cbb07c27a4d78f95557a6b9cdcc32f98d67a0c22 +0ed9c64c3e63acac9bd77abce62501696c390450 diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 339aa4d57e22..4aa58b45662d 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -48,7 +48,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut span = frame.current_span(); // Match the behavior of runtime backtrace spans // by using a non-macro span in our backtrace. See `FunctionCx::debug_loc`. - if span.from_expansion() && !tcx.sess.opts.debugging_opts.debug_macros { + if span.from_expansion() && !tcx.sess.opts.unstable_opts.debug_macros { span = rustc_span::hygiene::walk_chain(span, frame.body.span.ctxt()) } data.push((frame.instance, span.lo())); From efc76af1342c55fde2f0bb316f126cd96558fc76 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Jul 2022 19:22:22 -0400 Subject: [PATCH 3516/5092] don't forcefully enable debug assertions, but make -debug mode usable still set those flags on CI though, we want to catch overflow there --- Cargo.toml | 3 +++ ci.sh | 2 +- miri | 4 +--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index af73a7af31c7..b6e1cdf5ca87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,3 +57,6 @@ default = ["stack-cache"] # Will be enabled on CI via `--all-features`. expensive-debug-assertions = [] stack-cache = [] + +[profile.dev] +opt-level = 2 # because it's too slow otherwise diff --git a/ci.sh b/ci.sh index e7c6ed833c60..05a3ee358ce4 100755 --- a/ci.sh +++ b/ci.sh @@ -3,7 +3,7 @@ set -euo pipefail set -x # Determine configuration -export RUSTFLAGS="-D warnings" +export RUSTFLAGS="-D warnings -C debug-assertions -C debuginfo=1" export CARGO_INCREMENTAL=0 export CARGO_EXTRA_FLAGS="--all-features" # in particular, expensive-debug-assertions diff --git a/miri b/miri index f0d92b6a2b53..a1931485f691 100755 --- a/miri +++ b/miri @@ -108,9 +108,7 @@ if [ -z "$CARGO_TARGET_DIR" ]; then export CARGO_TARGET_DIR="$MIRIDIR/target" fi # We set the rpath so that Miri finds the private rustc libraries it needs. -# We enable debug-assertions to get tracing. -# We enable line-only debuginfo for backtraces. -export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR -C debug-assertions -C debuginfo=1 $RUSTFLAGS" +export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR $RUSTFLAGS" # Determine flags passed to all cargo invocations. # This is a bit more annoying that one would hope due to # . From 5d5999ab13e849c66f39b23a685512110e0d8eee Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Jul 2022 08:06:37 -0400 Subject: [PATCH 3517/5092] make cache consistency checks into regular debug assertions --- Cargo.toml | 2 -- ci.sh | 4 ++-- src/stacked_borrows/stack.rs | 10 +++++----- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b6e1cdf5ca87..a2a880f8e308 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,8 +54,6 @@ harness = false [features] default = ["stack-cache"] -# Will be enabled on CI via `--all-features`. -expensive-debug-assertions = [] stack-cache = [] [profile.dev] diff --git a/ci.sh b/ci.sh index 05a3ee358ce4..68da8addc2c8 100755 --- a/ci.sh +++ b/ci.sh @@ -5,11 +5,11 @@ set -x # Determine configuration export RUSTFLAGS="-D warnings -C debug-assertions -C debuginfo=1" export CARGO_INCREMENTAL=0 -export CARGO_EXTRA_FLAGS="--all-features" # in particular, expensive-debug-assertions +export CARGO_EXTRA_FLAGS="--all-features" # Prepare echo "Build and install miri" -CARGO_EXTRA_FLAGS="" ./miri install # implicitly locked -- and the *installed* Miri does *not* get the expensive-debug-assertions feature +RUSTFLAGS="" ./miri install # implicitly locked, and explicitly without debug assertions ./miri build --all-targets --locked # the build that all the `./miri test` below will use echo diff --git a/src/stacked_borrows/stack.rs b/src/stacked_borrows/stack.rs index 1b05471618a5..bc7ffd4faea5 100644 --- a/src/stacked_borrows/stack.rs +++ b/src/stacked_borrows/stack.rs @@ -82,7 +82,7 @@ impl<'tcx> Stack { /// Panics if any of the caching mechanisms have broken, /// - The StackCache indices don't refer to the parallel items, /// - There are no Unique items outside of first_unique..last_unique - #[cfg(feature = "expensive-debug-assertions")] + #[cfg(debug_assertions)] fn verify_cache_consistency(&self) { // Only a full cache needs to be valid. Also see the comments in find_granting_cache // and set_unknown_bottom. @@ -115,7 +115,7 @@ impl<'tcx> Stack { tag: SbTagExtra, exposed_tags: &FxHashSet, ) -> Result, ()> { - #[cfg(feature = "expensive-debug-assertions")] + #[cfg(debug_assertions)] self.verify_cache_consistency(); let SbTagExtra::Concrete(tag) = tag else { @@ -247,7 +247,7 @@ impl<'tcx> Stack { // This primes the cache for the next access, which is almost always the just-added tag. self.cache.add(new_idx, new); - #[cfg(feature = "expensive-debug-assertions")] + #[cfg(debug_assertions)] self.verify_cache_consistency(); } @@ -325,7 +325,7 @@ impl<'tcx> Stack { self.unique_range.end = self.unique_range.end.min(disable_start + 1); } - #[cfg(feature = "expensive-debug-assertions")] + #[cfg(debug_assertions)] self.verify_cache_consistency(); Ok(()) @@ -380,7 +380,7 @@ impl<'tcx> Stack { self.unique_range = 0..0; } - #[cfg(feature = "expensive-debug-assertions")] + #[cfg(debug_assertions)] self.verify_cache_consistency(); Ok(()) } From fa7811bbe1532f06aea058700433c20fc31f5e39 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Jul 2022 13:08:09 -0400 Subject: [PATCH 3518/5092] use the cargo default for debug/release builds --- ci.sh | 4 ++-- miri | 72 +++++++++++++++++++++-------------------------------------- 2 files changed, 27 insertions(+), 49 deletions(-) diff --git a/ci.sh b/ci.sh index 68da8addc2c8..8c63a57a4f49 100755 --- a/ci.sh +++ b/ci.sh @@ -3,13 +3,13 @@ set -euo pipefail set -x # Determine configuration -export RUSTFLAGS="-D warnings -C debug-assertions -C debuginfo=1" +export RUSTFLAGS="-D warnings" export CARGO_INCREMENTAL=0 export CARGO_EXTRA_FLAGS="--all-features" # Prepare echo "Build and install miri" -RUSTFLAGS="" ./miri install # implicitly locked, and explicitly without debug assertions +./miri install # implicitly locked ./miri build --all-targets --locked # the build that all the `./miri test` below will use echo diff --git a/miri b/miri index a1931485f691..7b53b802db62 100755 --- a/miri +++ b/miri @@ -6,7 +6,8 @@ USAGE=$(cat <<"EOF" ./miri install : Installs the miri driver and cargo-miri. are passed to `cargo install`. Sets up the rpath such that the installed binary should work in any -working directory. +working directory. However, the rustup toolchain when invoking `cargo miri` +needs to be the same one used for `./miri install`. ./miri build : Just build miri. are passed to `cargo build`. @@ -22,10 +23,6 @@ to the final `cargo test` invocation. Build miri, set up a sysroot and then run the driver with the given . (Also respects MIRIFLAGS environment variable.) -The commands above also exist in a "-debug" variant (e.g. "./miri run-debug -") which uses debug builds instead of release builds, for faster build -times and slower execution times. - ./miri fmt : Format all sources and tests. are passed to `rustfmt`. @@ -99,38 +96,21 @@ fi # Prepare flags for cargo and rustc. CARGO="cargo +$TOOLCHAIN" -if [ -z "$CARGO_INCREMENTAL" ]; then - # Default CARGO_INCREMENTAL to 1. - export CARGO_INCREMENTAL=1 -fi if [ -z "$CARGO_TARGET_DIR" ]; then # Share target dir between `miri` and `cargo-miri`. export CARGO_TARGET_DIR="$MIRIDIR/target" fi # We set the rpath so that Miri finds the private rustc libraries it needs. export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR $RUSTFLAGS" -# Determine flags passed to all cargo invocations. -# This is a bit more annoying that one would hope due to -# . -case "$COMMAND" in -*-debug) - CARGO_INSTALL_FLAGS="--target $TARGET --debug $CARGO_EXTRA_FLAGS" - CARGO_BUILD_FLAGS="--target $TARGET $CARGO_EXTRA_FLAGS" - ;; -*) - CARGO_INSTALL_FLAGS="--target $TARGET $CARGO_EXTRA_FLAGS" - CARGO_BUILD_FLAGS="--target $TARGET --release $CARGO_EXTRA_FLAGS" - ;; -esac ## Helper functions # Build a sysroot and set MIRI_SYSROOT to use it. Arguments are passed to `cargo miri setup`. build_sysroot() { # Build once, for the user to see. - $CARGO run $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -- miri setup "$@" + $CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -- miri setup "$@" # Call again, to just set env var. - export MIRI_SYSROOT="$($CARGO run $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -q -- miri setup --print-sysroot "$@")" + export MIRI_SYSROOT="$($CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -q -- miri setup --print-sysroot "$@")" } # Prepare and set MIRI_SYSROOT. Respects `MIRI_TEST_TARGET` and takes into account @@ -152,37 +132,35 @@ find_sysroot() { # Run command. case "$COMMAND" in -install|install-debug) +install) # "--locked" to respect the Cargo.lock file if it exists, # "--offline" to avoid querying the registry (for yanked packages). - $CARGO install $CARGO_INSTALL_FLAGS --path "$MIRIDIR" --force --locked --offline "$@" - $CARGO install $CARGO_INSTALL_FLAGS --path "$MIRIDIR"/cargo-miri --force --locked --offline "$@" + $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR" --force --locked --offline "$@" + $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR"/cargo-miri --force --locked --offline "$@" ;; -check|check-debug) +check) # Check, and let caller control flags. - $CARGO check $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@" - $CARGO check $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" + $CARGO check $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@" + $CARGO check $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" ;; -build|build-debug) +build) # Build, and let caller control flags. - $CARGO build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" - $CARGO build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" + $CARGO build $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" + $CARGO build $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" ;; -test|test-debug|bless|bless-debug) +test|bless) # First build and get a sysroot. - $CARGO build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml + $CARGO build $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml find_sysroot - case "$COMMAND" in - bless|bless-debug) + if [ "$COMMAND" = "bless" ]; then export MIRI_BLESS="Gesundheit" - ;; - esac + fi # Then test, and let caller control flags. # Only in root project and ui_test as `cargo-miri` has no tests. - $CARGO test $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" - $CARGO test $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml "$@" + $CARGO test $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" + $CARGO test $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml "$@" ;; -run|run-debug) +run) # Scan for "--target" to overwrite the "MIRI_TEST_TARGET" env var so # that we set the MIRI_SYSROOT up the right way. FOUND_TARGET_OPT=0 @@ -200,19 +178,19 @@ run|run-debug) MIRIFLAGS="$MIRIFLAGS --target $MIRI_TEST_TARGET" fi # First build and get a sysroot. - $CARGO build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml + $CARGO build $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml find_sysroot # Then run the actual command. - exec $CARGO run $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml -- --sysroot "$MIRI_SYSROOT" $MIRIFLAGS "$@" + exec $CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml -- --sysroot "$MIRI_SYSROOT" $MIRIFLAGS "$@" ;; fmt) find "$MIRIDIR" -not \( -name target -prune \) -name '*.rs' \ | xargs rustfmt +$TOOLCHAIN --edition=2021 --config-path "$MIRIDIR/rustfmt.toml" "$@" ;; clippy) - $CARGO clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@" - $CARGO clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml --all-targets "$@" - $CARGO clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" + $CARGO clippy $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@" + $CARGO clippy $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml --all-targets "$@" + $CARGO clippy $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" ;; *) if [ -n "$COMMAND" ]; then From 421f92bee65452600c3ecdf63de5395809d78e55 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Jul 2022 13:23:35 -0400 Subject: [PATCH 3519/5092] make some debug assertions in RangeObjectMap be full assertions --- src/concurrency/range_object_map.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/concurrency/range_object_map.rs b/src/concurrency/range_object_map.rs index 2bb328030239..50d3f8c9b20e 100644 --- a/src/concurrency/range_object_map.rs +++ b/src/concurrency/range_object_map.rs @@ -117,11 +117,11 @@ impl RangeObjectMap { self.v.insert(pos, Elem { range, data }); // If we aren't the first element, then our start must be greater than the preivous element's end if pos > 0 { - debug_assert!(self.v[pos - 1].range.end() <= range.start); + assert!(self.v[pos - 1].range.end() <= range.start); } // If we aren't the last element, then our end must be smaller than next element's start if pos < self.v.len() - 1 { - debug_assert!(range.end() <= self.v[pos + 1].range.start); + assert!(range.end() <= self.v[pos + 1].range.start); } } From d6cbe5d014c8c02ed4077ee702d34ea442c62e47 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Jul 2022 14:27:24 -0400 Subject: [PATCH 3520/5092] ensure that RangeMap panics on OOB --- src/range_map.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/range_map.rs b/src/range_map.rs index 474ad9dcccd9..c77ea63b0873 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -77,6 +77,10 @@ impl RangeMap { }; // The first offset that is not included any more. let end = offset + len; + assert!( + end <= self.v.last().unwrap().range.end, + "iterating beyond the bounds of this RangeMap" + ); slice .iter() .take_while(move |elem| elem.range.start < end) @@ -279,4 +283,18 @@ mod tests { assert_eq!(map.v.len(), 5); assert_eq!(to_vec(&map, 10, 10), vec![23, 42, 23, 23, 23, 19, 19, 19, 19, 19]); } + + #[test] + #[should_panic] + fn out_of_range_iter_mut() { + let mut map = RangeMap::::new(Size::from_bytes(20), -1); + let _ = map.iter_mut(Size::from_bytes(11), Size::from_bytes(11)); + } + + #[test] + #[should_panic] + fn out_of_range_iter() { + let map = RangeMap::::new(Size::from_bytes(20), -1); + let _ = map.iter(Size::from_bytes(11), Size::from_bytes(11)); + } } From 8c13a9ccd376a82c695f32123c407fe16d6663e5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 15 Jul 2022 08:02:13 -0400 Subject: [PATCH 3521/5092] clarify how to run the manually installed Miri --- CONTRIBUTING.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bde1921eb8ce..a57ef09e7db9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,11 +28,6 @@ install that exact version of rustc as a toolchain: This will set up a rustup toolchain called `miri` and set it as an override for the current directory. -If you want to also have `clippy` installed, you need to run this: -``` -./rustup-toolchain "" -c clippy -``` - [`rustup-toolchain-install-master`]: https://github.com/kennytm/rustup-toolchain-install-master ## Building and testing Miri @@ -131,6 +126,8 @@ development version of Miri using and then you can use it as if it was installed by `rustup`. Make sure you use the same toolchain when calling `cargo miri` that you used when installing Miri! +Usually this means you have to write `cargo +miri miri ...` to select the `miri` +toolchain that was installed by `./rustup-toolchain`. There's a test for the cargo wrapper in the `test-cargo-miri` directory; run `./run-test.py` in there to execute it. Like `./miri test`, this respects the From 98c401977bfd0e8a807481e53de6dbaae8cb0974 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 15 Jul 2022 08:09:43 -0400 Subject: [PATCH 3522/5092] rustup --- rust-version | 2 +- src/helpers.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 45abe7e8c653..86a09bfa57bf 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0ed9c64c3e63acac9bd77abce62501696c390450 +6077b7cda466afa2b75a62b232ab46dbeb148bcb diff --git a/src/helpers.rs b/src/helpers.rs index 29bf92af3faf..d0b0852d010c 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -259,7 +259,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mir = this.load_mir(f.def, None)?; let dest = match dest { Some(dest) => *dest, - None => MPlaceTy::dangling(this.layout_of(mir.return_ty())?).into(), + None => MPlaceTy::fake_alloc_zst(this.layout_of(mir.return_ty())?).into(), }; this.push_stack_frame(f, mir, &dest, stack_pop)?; From 9782b7b039ce1fb585c933d8ce64610256399c59 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 16 Jul 2022 23:40:36 -0400 Subject: [PATCH 3523/5092] rustup --- rust-version | 2 +- src/helpers.rs | 2 +- src/shims/backtrace.rs | 2 +- src/shims/windows/foreign_items.rs | 2 -- tests/fail/stacked_borrows/issue-miri-1050-1.rs | 2 +- tests/fail/stacked_borrows/issue-miri-1050-1.stderr | 4 ++-- tests/fail/stacked_borrows/issue-miri-1050-2.rs | 2 +- tests/fail/stacked_borrows/issue-miri-1050-2.stderr | 4 ++-- 8 files changed, 9 insertions(+), 11 deletions(-) diff --git a/rust-version b/rust-version index 86a09bfa57bf..5396b338cecb 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6077b7cda466afa2b75a62b232ab46dbeb148bcb +db41351753df840773ca628d8daa040e95d00eef diff --git a/src/helpers.rs b/src/helpers.rs index d0b0852d010c..b650e2ddf225 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -631,7 +631,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Ensure that the access is within bounds. assert!(op_place.layout.size >= offset + layout.size); - let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; + let value_place = op_place.offset(offset, layout, this)?; Ok(value_place) } diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 4aa58b45662d..62e5afbca8bc 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -105,7 +105,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let offset = ptr_layout.size * i.try_into().unwrap(); let op_place = - buf_place.offset(offset, MemPlaceMeta::None, ptr_layout, this)?; + buf_place.offset(offset, ptr_layout, this)?; this.write_pointer(ptr, &op_place.into())?; } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 0bb082dba9b2..689d1873d58f 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -154,7 +154,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Set page size. let page_size = system_info.offset( field_offsets[2], - MemPlaceMeta::None, dword_layout, &this.tcx, )?; @@ -165,7 +164,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Set number of processors. let num_cpus = system_info.offset( field_offsets[6], - MemPlaceMeta::None, dword_layout, &this.tcx, )?; diff --git a/tests/fail/stacked_borrows/issue-miri-1050-1.rs b/tests/fail/stacked_borrows/issue-miri-1050-1.rs index 6e14b9af146c..1e44cc6c800e 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-1.rs +++ b/tests/fail/stacked_borrows/issue-miri-1050-1.rs @@ -3,6 +3,6 @@ fn main() { unsafe { let ptr = Box::into_raw(Box::new(0u16)); - Box::from_raw(ptr as *mut u32); + drop(Box::from_raw(ptr as *mut u32)); } } diff --git a/tests/fail/stacked_borrows/issue-miri-1050-1.stderr b/tests/fail/stacked_borrows/issue-miri-1050-1.stderr index 946e3e8e6664..4d8488fa7684 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-1.stderr +++ b/tests/fail/stacked_borrows/issue-miri-1050-1.stderr @@ -12,8 +12,8 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) note: inside `main` at $DIR/issue-miri-1050-1.rs:LL:CC --> $DIR/issue-miri-1050-1.rs:LL:CC | -LL | Box::from_raw(ptr as *mut u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | drop(Box::from_raw(ptr as *mut u32)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/issue-miri-1050-2.rs b/tests/fail/stacked_borrows/issue-miri-1050-2.rs index 571cb6213fec..6e90559a9ef5 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-2.rs +++ b/tests/fail/stacked_borrows/issue-miri-1050-2.rs @@ -4,6 +4,6 @@ use std::ptr::NonNull; fn main() { unsafe { let ptr = NonNull::::dangling(); - Box::from_raw(ptr.as_ptr()); + drop(Box::from_raw(ptr.as_ptr())); } } diff --git a/tests/fail/stacked_borrows/issue-miri-1050-2.stderr b/tests/fail/stacked_borrows/issue-miri-1050-2.stderr index 33ac31176677..562a82fb610b 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-2.stderr +++ b/tests/fail/stacked_borrows/issue-miri-1050-2.stderr @@ -12,8 +12,8 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) note: inside `main` at $DIR/issue-miri-1050-2.rs:LL:CC --> $DIR/issue-miri-1050-2.rs:LL:CC | -LL | Box::from_raw(ptr.as_ptr()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | drop(Box::from_raw(ptr.as_ptr())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace From 43100f5f4b8b8c0b437bfe8b380198cb99e62cc3 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Sun, 17 Jul 2022 07:46:02 +0000 Subject: [PATCH 3524/5092] Remove `--offline` from `./miri install` as otherwise we can't add more dependencies to miri as CI will fail. if you want this locally, pass it to your invocation. --- miri | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/miri b/miri index 7b53b802db62..bb2fc5b12318 100755 --- a/miri +++ b/miri @@ -133,10 +133,9 @@ find_sysroot() { # Run command. case "$COMMAND" in install) - # "--locked" to respect the Cargo.lock file if it exists, - # "--offline" to avoid querying the registry (for yanked packages). - $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR" --force --locked --offline "$@" - $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR"/cargo-miri --force --locked --offline "$@" + # "--locked" to respect the Cargo.lock file if it exists. + $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR" --force --locked "$@" + $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR"/cargo-miri --force --locked "$@" ;; check) # Check, and let caller control flags. From 444841bba9c31f1fe5b7b419ee82eb27e37a344e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Sun, 17 Jul 2022 07:56:57 +0000 Subject: [PATCH 3525/5092] Add test flag for running a test only on the host --- ui_test/README.md | 2 ++ ui_test/src/lib.rs | 11 ++++++----- ui_test/src/parser.rs | 6 ++++++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/ui_test/README.md b/ui_test/README.md index 55639c9589e1..4ecebcc8ddb2 100644 --- a/ui_test/README.md +++ b/ui_test/README.md @@ -25,8 +25,10 @@ their command specifies, or the test will fail without even being run. * `//@ignore-XXX` avoids running the test on targets whose triple contains `XXX` * `XXX` can also be one of `64bit`, `32bit` or `16bit` + * `XXX` can also be `on-host`, which will only run the test during cross compilation testing. * `//@only-XXX` avoids running the test on targets whose triple **does not** contain `XXX` * `XXX` can also be one of `64bit`, `32bit` or `16bit` + * `XXX` can also be `on-host`, which will not run the test during cross compilation testing * `//@stderr-per-bitwidth` produces one stderr file per bitwidth, as they may differ significantly sometimes * `//@error-pattern: XXX` make sure the stderr output contains `XXX` * `//@revisions: XXX YYY` runs the test once for each space separated name in the list diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 32c04290bca2..16f7be30f8b2 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -109,7 +109,7 @@ pub fn run_tests(config: Config) -> Result<()> { } let comments = Comments::parse_file(&path)?; // Ignore file if only/ignore rules do (not) apply - if !test_file_conditions(&comments, &target) { + if !test_file_conditions(&comments, &target, &config) { ignored.fetch_add(1, Ordering::Relaxed); eprintln!( "{} ... {}", @@ -499,19 +499,20 @@ fn output_path(path: &Path, comments: &Comments, kind: String, target: &str) -> path.with_extension(kind) } -fn test_condition(condition: &Condition, target: &str) -> bool { +fn test_condition(condition: &Condition, target: &str, config: &Config) -> bool { match condition { Condition::Bitwidth(bits) => get_pointer_width(target) == *bits, Condition::Target(t) => target.contains(t), + Condition::OnHost => config.target.is_none(), } } /// Returns whether according to the in-file conditions, this file should be run. -fn test_file_conditions(comments: &Comments, target: &str) -> bool { - if comments.ignore.iter().any(|c| test_condition(c, target)) { +fn test_file_conditions(comments: &Comments, target: &str, config: &Config) -> bool { + if comments.ignore.iter().any(|c| test_condition(c, target, config)) { return false; } - comments.only.iter().all(|c| test_condition(c, target)) + comments.only.iter().all(|c| test_condition(c, target, config)) } // Taken 1:1 from compiletest-rs diff --git a/ui_test/src/parser.rs b/ui_test/src/parser.rs index 7d810a95e412..994c0800fcc1 100644 --- a/ui_test/src/parser.rs +++ b/ui_test/src/parser.rs @@ -43,6 +43,8 @@ pub(crate) enum Condition { Target(String), /// Tests that the bitwidth is the given one. Bitwidth(u8), + /// Tests that the target is the host. + OnHost, } #[derive(Debug, Clone)] @@ -64,6 +66,10 @@ pub(crate) struct ErrorMatch { impl Condition { fn parse(c: &str) -> Self { + match c { + "on-host" => return Condition::OnHost, + _ => {} + } if let Some(bits) = c.strip_suffix("bit") { let bits: u8 = bits.parse().expect( "ignore/only filter ending in 'bit' must be of the form 'Nbit' for some integer N", From 8527bfc63b8c6eb9451e1adb08c39cc4d54c1bc5 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Sun, 17 Jul 2022 08:07:26 +0000 Subject: [PATCH 3526/5092] clippy --- ui_test/src/parser.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ui_test/src/parser.rs b/ui_test/src/parser.rs index 994c0800fcc1..e7fb484434d7 100644 --- a/ui_test/src/parser.rs +++ b/ui_test/src/parser.rs @@ -66,11 +66,9 @@ pub(crate) struct ErrorMatch { impl Condition { fn parse(c: &str) -> Self { - match c { - "on-host" => return Condition::OnHost, - _ => {} - } - if let Some(bits) = c.strip_suffix("bit") { + if c == "on-host" { + Condition::OnHost + } else if let Some(bits) = c.strip_suffix("bit") { let bits: u8 = bits.parse().expect( "ignore/only filter ending in 'bit' must be of the form 'Nbit' for some integer N", ); From e8ab64e424a377cdb5d6373b10d4d6ed68e38f13 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 16 Jul 2022 23:44:37 -0400 Subject: [PATCH 3527/5092] make unused flags work like they used to --- src/shims/backtrace.rs | 3 +-- src/shims/windows/foreign_items.rs | 12 ++---------- tests/compiletest.rs | 3 ++- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 62e5afbca8bc..5b39f2a48aae 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -104,8 +104,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx for (i, ptr) in ptrs.into_iter().enumerate() { let offset = ptr_layout.size * i.try_into().unwrap(); - let op_place = - buf_place.offset(offset, ptr_layout, this)?; + let op_place = buf_place.offset(offset, ptr_layout, this)?; this.write_pointer(ptr, &op_place.into())?; } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 689d1873d58f..28e60a68048c 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -152,21 +152,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .collect(); // Set page size. - let page_size = system_info.offset( - field_offsets[2], - dword_layout, - &this.tcx, - )?; + let page_size = system_info.offset(field_offsets[2], dword_layout, &this.tcx)?; this.write_scalar( Scalar::from_int(PAGE_SIZE, dword_layout.size), &page_size.into(), )?; // Set number of processors. - let num_cpus = system_info.offset( - field_offsets[6], - dword_layout, - &this.tcx, - )?; + let num_cpus = system_info.offset(field_offsets[6], dword_layout, &this.tcx)?; this.write_scalar(Scalar::from_int(NUM_CPUS, dword_layout.size), &num_cpus.into())?; } diff --git a/tests/compiletest.rs b/tests/compiletest.rs index c568d1c50434..ec49e80ca963 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -19,9 +19,10 @@ fn run_tests(mode: Mode, path: &str, target: Option) -> Result<()> { // Less aggressive warnings to make the rustc toolstate management less painful. // (We often get warnings when e.g. a feature gets stabilized or some lint gets added/improved.) flags.push("-Astable-features".to_owned()); + flags.push("-Aunused".to_owned()); } else { flags.push("-Dwarnings".to_owned()); - flags.push("-Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs + flags.push("-Dunused".to_owned()); } if let Ok(sysroot) = env::var("MIRI_SYSROOT") { flags.push("--sysroot".to_string()); From 68510600a3f8f69fab24bbb256918b4fe46ba639 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Jul 2022 10:19:29 -0400 Subject: [PATCH 3528/5092] use PlaceTy visitor --- src/stacked_borrows/mod.rs | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/src/stacked_borrows/mod.rs b/src/stacked_borrows/mod.rs index d9ccc773a018..d1e9ae1c5704 100644 --- a/src/stacked_borrows/mod.rs +++ b/src/stacked_borrows/mod.rs @@ -1037,17 +1037,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Raw pointers need to be enabled. ty::RawPtr(tym) if kind == RetagKind::Raw => Some((RefKind::Raw { mutable: tym.mutbl == Mutability::Mut }, false)), - // Boxes are handled separately due to that allocator situation. + // Boxes are handled separately due to that allocator situation, + // see the visitor below. _ => None, } } - // We need a visitor to visit all references. However, that requires - // a `MPlaceTy` (or `OpTy`), so we have a fast path for reference types that - // avoids allocating. - + // For some types we can do the work without starting up the visitor infrastructure. if let Some((ref_kind, protector)) = qualify(place.layout.ty, kind) { - // Fast path. let val = this.read_immediate(&this.place_to_op(place)?)?; let val = this.retag_reference(&val, ref_kind, protector)?; this.write_immediate(*val, place)?; @@ -1077,11 +1074,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) { return Ok(()); } - // Now go visit this thing. - let place = this.force_allocation(place)?; + // Now go visit this thing. let mut visitor = RetagVisitor { ecx: this, kind }; - return visitor.visit_value(&place); + return visitor.visit_value(place); // The actual visitor. struct RetagVisitor<'ecx, 'mir, 'tcx> { @@ -1091,36 +1087,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx impl<'ecx, 'mir, 'tcx> MutValueVisitor<'mir, 'tcx, Evaluator<'mir, 'tcx>> for RetagVisitor<'ecx, 'mir, 'tcx> { - type V = MPlaceTy<'tcx, Tag>; + type V = PlaceTy<'tcx, Tag>; #[inline(always)] fn ecx(&mut self) -> &mut MiriEvalContext<'mir, 'tcx> { self.ecx } - fn visit_box(&mut self, place: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn visit_box(&mut self, place: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { // Boxes do not get a protector: protectors reflect that references outlive the call // they were passed in to; that's just not the case for boxes. let (ref_kind, protector) = (RefKind::Unique { two_phase: false }, false); - - let val = self.ecx.read_immediate(&place.into())?; + let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?; let val = self.ecx.retag_reference(&val, ref_kind, protector)?; - self.ecx.write_immediate(*val, &place.into())?; + self.ecx.write_immediate(*val, place)?; Ok(()) } - fn visit_value(&mut self, place: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn visit_value(&mut self, place: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { if let Some((ref_kind, protector)) = qualify(place.layout.ty, self.kind) { - let val = self.ecx.read_immediate(&place.into())?; + let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?; let val = self.ecx.retag_reference(&val, ref_kind, protector)?; - self.ecx.write_immediate(*val, &place.into())?; + self.ecx.write_immediate(*val, place)?; } else if matches!(place.layout.ty.kind(), ty::RawPtr(..)) { // Wide raw pointers *do* have fields and their types are strange. // vtables have a type like `&[*const (); 3]` or so! // Do *not* recurse into them. - // (No need to worry about wide references or boxes, those always "qualify".) + // (No need to worry about wide references, those always "qualify". And Boxes + // are handles specially by the visitor anyway.) } else { - // Maybe we need to go deeper. + // Recurse deeper. self.walk_value(place)?; } Ok(()) From 39866f817a002505f63f0e5d7ff06b9e99453015 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Jul 2022 10:32:03 -0400 Subject: [PATCH 3529/5092] remove a fastpath that does not seem to actually help --- src/stacked_borrows/mod.rs | 77 +++++++++++++++----------------------- 1 file changed, 31 insertions(+), 46 deletions(-) diff --git a/src/stacked_borrows/mod.rs b/src/stacked_borrows/mod.rs index d1e9ae1c5704..9040d03632ed 100644 --- a/src/stacked_borrows/mod.rs +++ b/src/stacked_borrows/mod.rs @@ -1021,6 +1021,10 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn retag(&mut self, kind: RetagKind, place: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + let retag_fields = this.machine.stacked_borrows.as_mut().unwrap().get_mut().retag_fields; + let mut visitor = RetagVisitor { ecx: this, kind, retag_fields }; + return visitor.visit_value(place); + // Determine mutability and whether to add a protector. // Cannot use `builtin_deref` because that reports *immutable* for `Box`, // making it useless. @@ -1043,46 +1047,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - // For some types we can do the work without starting up the visitor infrastructure. - if let Some((ref_kind, protector)) = qualify(place.layout.ty, kind) { - let val = this.read_immediate(&this.place_to_op(place)?)?; - let val = this.retag_reference(&val, ref_kind, protector)?; - this.write_immediate(*val, place)?; - return Ok(()); - } - - // If we don't want to recurse, we are already done. - // EXCEPT if this is a `Box`, then we have to recurse because allocators. - // (Yes this means we technically also recursively retag the allocator itself even if field - // retagging is not enabled. *shrug*) - if !this.machine.stacked_borrows.as_mut().unwrap().get_mut().retag_fields - && !place.layout.ty.ty_adt_def().is_some_and(|adt| adt.is_box()) - { - return Ok(()); - } - - // Skip some types that have no further structure we might care about. - if matches!( - place.layout.ty.kind(), - ty::RawPtr(..) - | ty::Ref(..) - | ty::Int(..) - | ty::Uint(..) - | ty::Float(..) - | ty::Bool - | ty::Char - ) { - return Ok(()); - } - - // Now go visit this thing. - let mut visitor = RetagVisitor { ecx: this, kind }; - return visitor.visit_value(place); - // The actual visitor. struct RetagVisitor<'ecx, 'mir, 'tcx> { ecx: &'ecx mut MiriEvalContext<'mir, 'tcx>, kind: RetagKind, + retag_fields: bool, + } + impl<'ecx, 'mir, 'tcx> RetagVisitor<'ecx, 'mir, 'tcx> { + #[inline(always)] // yes this helps in our benchmarks + fn retag_place( + &mut self, + place: &PlaceTy<'tcx, Tag>, + ref_kind: RefKind, + protector: bool, + ) -> InterpResult<'tcx> { + let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?; + let val = self.ecx.retag_reference(&val, ref_kind, protector)?; + self.ecx.write_immediate(*val, place)?; + Ok(()) + } } impl<'ecx, 'mir, 'tcx> MutValueVisitor<'mir, 'tcx, Evaluator<'mir, 'tcx>> for RetagVisitor<'ecx, 'mir, 'tcx> @@ -1097,26 +1080,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn visit_box(&mut self, place: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { // Boxes do not get a protector: protectors reflect that references outlive the call // they were passed in to; that's just not the case for boxes. - let (ref_kind, protector) = (RefKind::Unique { two_phase: false }, false); - let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?; - let val = self.ecx.retag_reference(&val, ref_kind, protector)?; - self.ecx.write_immediate(*val, place)?; - Ok(()) + self.retag_place( + place, + RefKind::Unique { two_phase: false }, + /*protector*/ false, + ) } fn visit_value(&mut self, place: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { if let Some((ref_kind, protector)) = qualify(place.layout.ty, self.kind) { - let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?; - let val = self.ecx.retag_reference(&val, ref_kind, protector)?; - self.ecx.write_immediate(*val, place)?; + self.retag_place(place, ref_kind, protector)?; } else if matches!(place.layout.ty.kind(), ty::RawPtr(..)) { // Wide raw pointers *do* have fields and their types are strange. // vtables have a type like `&[*const (); 3]` or so! // Do *not* recurse into them. // (No need to worry about wide references, those always "qualify". And Boxes // are handles specially by the visitor anyway.) - } else { - // Recurse deeper. + } else if self.retag_fields + || place.layout.ty.ty_adt_def().is_some_and(|adt| adt.is_box()) + { + // Recurse deeper. Need to always recurse for `Box` to even hit `visit_box`. + // (Yes this means we technically also recursively retag the allocator itself + // even if field retagging is not enabled. *shrug*) self.walk_value(place)?; } Ok(()) From 2f84cb34c11b4a6127b687ae6c353f33e3edeee7 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Fri, 8 Jul 2022 14:48:26 -0400 Subject: [PATCH 3530/5092] Pass through isatty if the host is also unix --- src/shims/unix/foreign_items.rs | 8 ++--- src/shims/unix/fs.rs | 61 +++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 44147433c037..57dfd6f1810c 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -440,12 +440,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscellaneous "isatty" => { let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - this.read_scalar(fd)?.to_i32()?; - // "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error" - // FIXME: we just say nothing is a terminal. - let enotty = this.eval_libc("ENOTTY")?; - this.set_last_error(enotty)?; - this.write_null(dest)?; + let result = this.isatty(fd)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_atfork" => { let [prepare, parent, child] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index c7d7789f03ab..3fdf82ebc6a7 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -50,6 +50,9 @@ trait FileDescriptor: std::fmt::Debug { ) -> InterpResult<'tcx, io::Result>; fn dup(&mut self) -> io::Result>; + + #[cfg(unix)] + fn as_unix_host_fd(&self) -> Option; } impl FileDescriptor for FileHandle { @@ -114,6 +117,12 @@ impl FileDescriptor for FileHandle { let duplicated = self.file.try_clone()?; Ok(Box::new(FileHandle { file: duplicated, writable: self.writable })) } + + #[cfg(unix)] + fn as_unix_host_fd(&self) -> Option { + use std::os::unix::io::AsRawFd; + Some(self.file.as_raw_fd()) + } } impl FileDescriptor for io::Stdin { @@ -159,6 +168,11 @@ impl FileDescriptor for io::Stdin { fn dup(&mut self) -> io::Result> { Ok(Box::new(io::stdin())) } + + #[cfg(unix)] + fn as_unix_host_fd(&self) -> Option { + Some(libc::STDIN_FILENO) + } } impl FileDescriptor for io::Stdout { @@ -209,6 +223,11 @@ impl FileDescriptor for io::Stdout { fn dup(&mut self) -> io::Result> { Ok(Box::new(io::stdout())) } + + #[cfg(unix)] + fn as_unix_host_fd(&self) -> Option { + Some(libc::STDOUT_FILENO) + } } impl FileDescriptor for io::Stderr { @@ -252,6 +271,11 @@ impl FileDescriptor for io::Stderr { fn dup(&mut self) -> io::Result> { Ok(Box::new(io::stderr())) } + + #[cfg(unix)] + fn as_unix_host_fd(&self) -> Option { + Some(libc::STDERR_FILENO) + } } #[derive(Debug)] @@ -297,6 +321,11 @@ impl FileDescriptor for DummyOutput { fn dup<'tcx>(&mut self) -> io::Result> { Ok(Box::new(DummyOutput)) } + + #[cfg(unix)] + fn as_unix_host_fd(&self) -> Option { + None + } } #[derive(Debug)] @@ -1660,6 +1689,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } + + #[cfg_attr(not(unix), allow(unused))] + fn isatty(&mut self, miri_fd: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + #[cfg(unix)] + { + let miri_fd = this.read_scalar(miri_fd)?.to_i32()?; + if let Some(host_fd) = + this.machine.file_handler.handles.get(&miri_fd).and_then(|fd| fd.as_unix_host_fd()) + { + // "returns 1 if fd is an open file descriptor referring to a terminal; + // otherwise 0 is returned, and errno is set to indicate the error" + // SAFETY: isatty has no preconditions + let is_tty = unsafe { libc::isatty(host_fd) }; + if is_tty == 0 { + let errno = std::io::Error::last_os_error() + .raw_os_error() + .map(Scalar::from_i32) + .unwrap(); + this.set_last_error(errno)?; + } + return Ok(is_tty); + } + } + // We are attemping to use a Unix interface on a non-Unix platform, or we are on a Unix + // platform and the passed file descriptor is not open. + // FIXME: It should be possible to emulate this at least on Windows by using + // GetConsoleMode. + let enotty = this.eval_libc("ENOTTY")?; + this.set_last_error(enotty)?; + Ok(0) + } } /// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch when From eefdeacdb1aa2515359ba3cedfb04c81d74e783a Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 17 Jul 2022 21:13:59 -0400 Subject: [PATCH 3531/5092] Test that isatty doesn't crash --- tests/pass/libc.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index 53c85d2b07d1..6da527927071 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -311,6 +311,17 @@ fn test_posix_gettimeofday() { assert_eq!(is_error, -1); } +fn test_isatty() { + // Testing whether our isatty shim returns the right value would require controlling whether + // these streams are actually TTYs, which is hard. + // For now, we just check that these calls are supported at all. + unsafe { + libc::isatty(libc::STDIN_FILENO); + libc::isatty(libc::STDOUT_FILENO); + libc::isatty(libc::STDERR_FILENO); + } +} + fn main() { #[cfg(any(target_os = "linux", target_os = "freebsd"))] test_posix_fadvise(); @@ -335,4 +346,6 @@ fn main() { #[cfg(any(target_os = "linux"))] test_clocks(); + + test_isatty(); } From 896f558f2b8e0bd29cc08f5af5e0edfe07783042 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Jul 2022 21:50:10 -0400 Subject: [PATCH 3532/5092] with isolation we want to be fully deterministic --- src/shims/unix/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index 3fdf82ebc6a7..1420279247f4 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -1694,7 +1694,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn isatty(&mut self, miri_fd: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); #[cfg(unix)] - { + if matches!(this.machine.isolated_op, IsolatedOp::Allow) { let miri_fd = this.read_scalar(miri_fd)?.to_i32()?; if let Some(host_fd) = this.machine.file_handler.handles.get(&miri_fd).and_then(|fd| fd.as_unix_host_fd()) @@ -1714,7 +1714,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } // We are attemping to use a Unix interface on a non-Unix platform, or we are on a Unix - // platform and the passed file descriptor is not open. + // platform and the passed file descriptor is not open, or isolation is enabled // FIXME: It should be possible to emulate this at least on Windows by using // GetConsoleMode. let enotty = this.eval_libc("ENOTTY")?; From 1c85975768d42e21ec5ead95b5b301f3137c80cf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Jul 2022 21:54:10 -0400 Subject: [PATCH 3533/5092] ui_test: more robust syntax for target filtering --- .../libc_pthread_create_main_terminate.rs | 2 +- .../fail/concurrency/libc_pthread_join_detached.rs | 2 +- tests/fail/concurrency/libc_pthread_join_joined.rs | 2 +- tests/fail/concurrency/libc_pthread_join_main.rs | 2 +- .../fail/concurrency/libc_pthread_join_multiple.rs | 2 +- tests/fail/concurrency/libc_pthread_join_self.rs | 2 +- tests/fail/concurrency/thread-spawn.rs | 2 +- .../concurrency/thread_local_static_dealloc.rs | 2 +- tests/fail/concurrency/too_few_args.rs | 2 +- tests/fail/concurrency/too_many_args.rs | 2 +- tests/fail/concurrency/unwind_top_of_stack.rs | 2 +- tests/fail/data_race/alloc_read_race.rs | 2 +- tests/fail/data_race/alloc_write_race.rs | 2 +- tests/fail/data_race/atomic_read_na_write_race1.rs | 2 +- tests/fail/data_race/atomic_read_na_write_race2.rs | 2 +- tests/fail/data_race/atomic_write_na_read_race1.rs | 2 +- tests/fail/data_race/atomic_write_na_read_race2.rs | 2 +- .../fail/data_race/atomic_write_na_write_race1.rs | 2 +- .../fail/data_race/atomic_write_na_write_race2.rs | 2 +- tests/fail/data_race/dangling_thread_async_race.rs | 2 +- tests/fail/data_race/dangling_thread_race.rs | 2 +- tests/fail/data_race/dealloc_read_race1.rs | 2 +- tests/fail/data_race/dealloc_read_race2.rs | 2 +- tests/fail/data_race/dealloc_read_race_stack.rs | 2 +- tests/fail/data_race/dealloc_write_race1.rs | 2 +- tests/fail/data_race/dealloc_write_race2.rs | 2 +- tests/fail/data_race/dealloc_write_race_stack.rs | 2 +- tests/fail/data_race/enable_after_join_to_main.rs | 2 +- tests/fail/data_race/fence_after_load.rs | 2 +- tests/fail/data_race/read_write_race.rs | 2 +- tests/fail/data_race/read_write_race_stack.rs | 2 +- tests/fail/data_race/relax_acquire_race.rs | 2 +- tests/fail/data_race/release_seq_race.rs | 2 +- .../fail/data_race/release_seq_race_same_thread.rs | 2 +- tests/fail/data_race/rmw_race.rs | 2 +- tests/fail/data_race/stack_pop_race.rs | 2 +- tests/fail/data_race/write_write_race.rs | 2 +- tests/fail/data_race/write_write_race_stack.rs | 2 +- tests/fail/environ-gets-deallocated.rs | 2 +- tests/fail/fs/close_stdout.rs | 2 +- tests/fail/fs/isolated_file.rs | 2 +- tests/fail/fs/isolated_stdin.rs | 2 +- tests/fail/fs/read_from_stdout.rs | 2 +- tests/fail/fs/unix_open_missing_required_mode.rs | 2 +- tests/fail/fs/write_to_stdin.rs | 2 +- tests/fail/should-pass/cpp20_rwc_syncs.rs | 2 +- .../fail/sync/libc_pthread_cond_double_destroy.rs | 2 +- .../sync/libc_pthread_condattr_double_destroy.rs | 2 +- .../fail/sync/libc_pthread_mutex_NULL_deadlock.rs | 2 +- tests/fail/sync/libc_pthread_mutex_deadlock.rs | 2 +- .../sync/libc_pthread_mutex_default_deadlock.rs | 2 +- .../fail/sync/libc_pthread_mutex_destroy_locked.rs | 2 +- .../fail/sync/libc_pthread_mutex_double_destroy.rs | 2 +- .../sync/libc_pthread_mutex_normal_deadlock.rs | 2 +- .../libc_pthread_mutex_normal_unlock_unlocked.rs | 2 +- tests/fail/sync/libc_pthread_mutex_wrong_owner.rs | 2 +- .../sync/libc_pthread_mutexattr_double_destroy.rs | 2 +- .../libc_pthread_rwlock_destroy_read_locked.rs | 2 +- .../libc_pthread_rwlock_destroy_write_locked.rs | 2 +- .../sync/libc_pthread_rwlock_double_destroy.rs | 2 +- ...ead_rwlock_read_write_deadlock_single_thread.rs | 2 +- .../sync/libc_pthread_rwlock_read_wrong_owner.rs | 2 +- .../sync/libc_pthread_rwlock_unlock_unlocked.rs | 2 +- .../libc_pthread_rwlock_write_read_deadlock.rs | 2 +- ...ead_rwlock_write_read_deadlock_single_thread.rs | 2 +- .../libc_pthread_rwlock_write_write_deadlock.rs | 2 +- ...ad_rwlock_write_write_deadlock_single_thread.rs | 2 +- .../sync/libc_pthread_rwlock_write_wrong_owner.rs | 2 +- tests/fail/unsupported_signal.rs | 2 +- tests/fail/weak_memory/racing_mixed_size.rs | 2 +- tests/fail/weak_memory/racing_mixed_size_read.rs | 2 +- tests/panic/panic/unsupported_syscall.rs | 4 ++-- tests/pass/0weak_memory_consistency.rs | 2 +- tests/pass/calloc.rs | 2 +- tests/pass/concurrency/channels.rs | 2 +- .../pass/concurrency/concurrent_caller_location.rs | 2 +- tests/pass/concurrency/data_race.rs | 2 +- .../pass/concurrency/disable_data_race_detector.rs | 2 +- tests/pass/concurrency/issue1643.rs | 2 +- tests/pass/concurrency/libc_pthread_cond.rs | 4 ++-- tests/pass/concurrency/linux-futex.rs | 2 +- tests/pass/concurrency/simple.rs | 2 +- tests/pass/concurrency/spin_loop.rs | 2 +- tests/pass/concurrency/spin_loops_nopreempt.rs | 2 +- tests/pass/concurrency/sync.rs | 2 +- tests/pass/concurrency/sync_nopreempt.rs | 2 +- tests/pass/concurrency/thread_locals.rs | 2 +- tests/pass/concurrency/tls_lib_drop.rs | 2 +- tests/pass/concurrency/tls_pthread_drop_order.rs | 2 +- tests/pass/fs.rs | 2 +- tests/pass/fs_with_isolation.rs | 2 +- tests/pass/libc.rs | 2 +- tests/pass/linux-getrandom-without-isolation.rs | 2 +- tests/pass/linux-getrandom.rs | 2 +- tests/pass/malloc.rs | 2 +- tests/pass/no_std.rs | 2 +- tests/pass/panic/concurrent-panic.rs | 2 +- tests/pass/threadleak_ignored.rs | 2 +- tests/pass/weak_memory/extra_cpp.rs | 2 +- tests/pass/weak_memory/extra_cpp_unsafe.rs | 2 +- tests/pass/weak_memory/weak.rs | 2 +- tests/pass/wtf8.rs | 2 +- ui_test/src/parser.rs | 14 ++++++++------ 103 files changed, 112 insertions(+), 110 deletions(-) diff --git a/tests/fail/concurrency/libc_pthread_create_main_terminate.rs b/tests/fail/concurrency/libc_pthread_create_main_terminate.rs index ab80cdd205bc..169a021215d5 100644 --- a/tests/fail/concurrency/libc_pthread_create_main_terminate.rs +++ b/tests/fail/concurrency/libc_pthread_create_main_terminate.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows //@error-pattern: the main thread terminated without waiting for all remaining threads // Check that we terminate the program when the main thread terminates. diff --git a/tests/fail/concurrency/libc_pthread_join_detached.rs b/tests/fail/concurrency/libc_pthread_join_detached.rs index 1ec1d630ecb9..6f0d45e2dc09 100644 --- a/tests/fail/concurrency/libc_pthread_join_detached.rs +++ b/tests/fail/concurrency/libc_pthread_join_detached.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows // Joining a detached thread is undefined behavior. diff --git a/tests/fail/concurrency/libc_pthread_join_joined.rs b/tests/fail/concurrency/libc_pthread_join_joined.rs index b067556e51b0..77f59fabca5e 100644 --- a/tests/fail/concurrency/libc_pthread_join_joined.rs +++ b/tests/fail/concurrency/libc_pthread_join_joined.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows // Joining an already joined thread is undefined behavior. diff --git a/tests/fail/concurrency/libc_pthread_join_main.rs b/tests/fail/concurrency/libc_pthread_join_main.rs index ebfe8c865e3d..aff28bcc9b57 100644 --- a/tests/fail/concurrency/libc_pthread_join_main.rs +++ b/tests/fail/concurrency/libc_pthread_join_main.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows // Joining the main thread is undefined behavior. diff --git a/tests/fail/concurrency/libc_pthread_join_multiple.rs b/tests/fail/concurrency/libc_pthread_join_multiple.rs index 39cd9ff77976..d4d54d3a23fd 100644 --- a/tests/fail/concurrency/libc_pthread_join_multiple.rs +++ b/tests/fail/concurrency/libc_pthread_join_multiple.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows // Joining the same thread from multiple threads is undefined behavior. diff --git a/tests/fail/concurrency/libc_pthread_join_self.rs b/tests/fail/concurrency/libc_pthread_join_self.rs index 7b91560ab6b1..b911b2db3a16 100644 --- a/tests/fail/concurrency/libc_pthread_join_self.rs +++ b/tests/fail/concurrency/libc_pthread_join_self.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows // We are making scheduler assumptions here. //@compile-flags: -Zmiri-preemption-rate=0 diff --git a/tests/fail/concurrency/thread-spawn.rs b/tests/fail/concurrency/thread-spawn.rs index 650a42b43b5d..84848e35a0f3 100644 --- a/tests/fail/concurrency/thread-spawn.rs +++ b/tests/fail/concurrency/thread-spawn.rs @@ -1,4 +1,4 @@ -//@only-windows: Only Windows is not supported. +//@only-target-windows: Only Windows is not supported. use std::thread; diff --git a/tests/fail/concurrency/thread_local_static_dealloc.rs b/tests/fail/concurrency/thread_local_static_dealloc.rs index f638e21901dd..7c54e3bca7c1 100644 --- a/tests/fail/concurrency/thread_local_static_dealloc.rs +++ b/tests/fail/concurrency/thread_local_static_dealloc.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //! Ensure that thread-local statics get deallocated when the thread dies. diff --git a/tests/fail/concurrency/too_few_args.rs b/tests/fail/concurrency/too_few_args.rs index 5d173b384807..11e97ca290f4 100644 --- a/tests/fail/concurrency/too_few_args.rs +++ b/tests/fail/concurrency/too_few_args.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //! The thread function must have exactly one argument. diff --git a/tests/fail/concurrency/too_many_args.rs b/tests/fail/concurrency/too_many_args.rs index 8305765a37a3..dd44207a6255 100644 --- a/tests/fail/concurrency/too_many_args.rs +++ b/tests/fail/concurrency/too_many_args.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //! The thread function must have exactly one argument. diff --git a/tests/fail/concurrency/unwind_top_of_stack.rs b/tests/fail/concurrency/unwind_top_of_stack.rs index 3bd9284c7c8a..179ff9c146e8 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.rs +++ b/tests/fail/concurrency/unwind_top_of_stack.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-abi-check //! Unwinding past the top frame of a stack is Undefined Behavior. diff --git a/tests/fail/data_race/alloc_read_race.rs b/tests/fail/data_race/alloc_read_race.rs index bdd38ea05693..f3f63aeb2b83 100644 --- a/tests/fail/data_race/alloc_read_race.rs +++ b/tests/fail/data_race/alloc_read_race.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 #![feature(new_uninit)] diff --git a/tests/fail/data_race/alloc_write_race.rs b/tests/fail/data_race/alloc_write_race.rs index 1322f727e6f0..a2738c3879b3 100644 --- a/tests/fail/data_race/alloc_write_race.rs +++ b/tests/fail/data_race/alloc_write_race.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 #![feature(new_uninit)] diff --git a/tests/fail/data_race/atomic_read_na_write_race1.rs b/tests/fail/data_race/atomic_read_na_write_race1.rs index 3cdb9d4a6543..1ef021edc8cc 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.rs +++ b/tests/fail/data_race/atomic_read_na_write_race1.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] use std::intrinsics; diff --git a/tests/fail/data_race/atomic_read_na_write_race2.rs b/tests/fail/data_race/atomic_read_na_write_race2.rs index 79f9cceb5c9c..493985f6cf17 100644 --- a/tests/fail/data_race/atomic_read_na_write_race2.rs +++ b/tests/fail/data_race/atomic_read_na_write_race2.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; diff --git a/tests/fail/data_race/atomic_write_na_read_race1.rs b/tests/fail/data_race/atomic_write_na_read_race1.rs index 6e9f37a9c43b..ca9c28abf1a9 100644 --- a/tests/fail/data_race/atomic_write_na_read_race1.rs +++ b/tests/fail/data_race/atomic_write_na_read_race1.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; diff --git a/tests/fail/data_race/atomic_write_na_read_race2.rs b/tests/fail/data_race/atomic_write_na_read_race2.rs index 4ab5abd5a3ee..77b2945f7371 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.rs +++ b/tests/fail/data_race/atomic_write_na_read_race2.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] use std::intrinsics::atomic_store; diff --git a/tests/fail/data_race/atomic_write_na_write_race1.rs b/tests/fail/data_race/atomic_write_na_write_race1.rs index 4c4ec0865cc9..34922dd595ed 100644 --- a/tests/fail/data_race/atomic_write_na_write_race1.rs +++ b/tests/fail/data_race/atomic_write_na_write_race1.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] use std::intrinsics::atomic_store; diff --git a/tests/fail/data_race/atomic_write_na_write_race2.rs b/tests/fail/data_race/atomic_write_na_write_race2.rs index 715c2d44b260..1d242ff3cdd6 100644 --- a/tests/fail/data_race/atomic_write_na_write_race2.rs +++ b/tests/fail/data_race/atomic_write_na_write_race2.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; diff --git a/tests/fail/data_race/dangling_thread_async_race.rs b/tests/fail/data_race/dangling_thread_async_race.rs index 732e89c89907..6264255265f6 100644 --- a/tests/fail/data_race/dangling_thread_async_race.rs +++ b/tests/fail/data_race/dangling_thread_async_race.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::mem; use std::thread::{sleep, spawn}; diff --git a/tests/fail/data_race/dangling_thread_race.rs b/tests/fail/data_race/dangling_thread_race.rs index 170fa8b77440..6f44fc69dbb7 100644 --- a/tests/fail/data_race/dangling_thread_race.rs +++ b/tests/fail/data_race/dangling_thread_race.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::mem; use std::thread::{sleep, spawn}; diff --git a/tests/fail/data_race/dealloc_read_race1.rs b/tests/fail/data_race/dealloc_read_race1.rs index 80a0fe2111ec..5349073ec3b7 100644 --- a/tests/fail/data_race/dealloc_read_race1.rs +++ b/tests/fail/data_race/dealloc_read_race1.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_read_race2.rs b/tests/fail/data_race/dealloc_read_race2.rs index 898588a1a0e8..bb9070ef7503 100644 --- a/tests/fail/data_race/dealloc_read_race2.rs +++ b/tests/fail/data_race/dealloc_read_race2.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_read_race_stack.rs b/tests/fail/data_race/dealloc_read_race_stack.rs index 475379a02ecf..e114fbb8b4f1 100644 --- a/tests/fail/data_race/dealloc_read_race_stack.rs +++ b/tests/fail/data_race/dealloc_read_race_stack.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::ptr::null_mut; diff --git a/tests/fail/data_race/dealloc_write_race1.rs b/tests/fail/data_race/dealloc_write_race1.rs index 711b7ba9d4eb..35949920e102 100644 --- a/tests/fail/data_race/dealloc_write_race1.rs +++ b/tests/fail/data_race/dealloc_write_race1.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_write_race2.rs b/tests/fail/data_race/dealloc_write_race2.rs index e7b7d558ed9d..b569086c8c34 100644 --- a/tests/fail/data_race/dealloc_write_race2.rs +++ b/tests/fail/data_race/dealloc_write_race2.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_write_race_stack.rs b/tests/fail/data_race/dealloc_write_race_stack.rs index 7f6beb7f32d8..0c74c7adf59c 100644 --- a/tests/fail/data_race/dealloc_write_race_stack.rs +++ b/tests/fail/data_race/dealloc_write_race_stack.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::ptr::null_mut; diff --git a/tests/fail/data_race/enable_after_join_to_main.rs b/tests/fail/data_race/enable_after_join_to_main.rs index 2e9fce198d1d..f2235b95257b 100644 --- a/tests/fail/data_race/enable_after_join_to_main.rs +++ b/tests/fail/data_race/enable_after_join_to_main.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/fence_after_load.rs b/tests/fail/data_race/fence_after_load.rs index f41c7a25523e..8acbe12e82d6 100644 --- a/tests/fail/data_race/fence_after_load.rs +++ b/tests/fail/data_race/fence_after_load.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::{fence, AtomicUsize, Ordering}; use std::sync::Arc; use std::thread; diff --git a/tests/fail/data_race/read_write_race.rs b/tests/fail/data_race/read_write_race.rs index e1134669f782..cff868fb699f 100644 --- a/tests/fail/data_race/read_write_race.rs +++ b/tests/fail/data_race/read_write_race.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/read_write_race_stack.rs b/tests/fail/data_race/read_write_race_stack.rs index 802e90d222af..b22173fa5a94 100644 --- a/tests/fail/data_race/read_write_race_stack.rs +++ b/tests/fail/data_race/read_write_race_stack.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 // Note: mir-opt-level set to 0 to prevent the read of stack_var in thread 1 diff --git a/tests/fail/data_race/relax_acquire_race.rs b/tests/fail/data_race/relax_acquire_race.rs index 4238372f21fa..b99388b8923c 100644 --- a/tests/fail/data_race/relax_acquire_race.rs +++ b/tests/fail/data_race/relax_acquire_race.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/release_seq_race.rs b/tests/fail/data_race/release_seq_race.rs index cd11aac95955..31fc5d9a479f 100644 --- a/tests/fail/data_race/release_seq_race.rs +++ b/tests/fail/data_race/release_seq_race.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/release_seq_race_same_thread.rs b/tests/fail/data_race/release_seq_race_same_thread.rs index 854ea09f11eb..c0ce437047a8 100644 --- a/tests/fail/data_race/release_seq_race_same_thread.rs +++ b/tests/fail/data_race/release_seq_race_same_thread.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/rmw_race.rs b/tests/fail/data_race/rmw_race.rs index 2f7f8986a49e..540b01b0935d 100644 --- a/tests/fail/data_race/rmw_race.rs +++ b/tests/fail/data_race/rmw_race.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/stack_pop_race.rs b/tests/fail/data_race/stack_pop_race.rs index 444c28d50aaf..8f371a680f11 100644 --- a/tests/fail/data_race/stack_pop_race.rs +++ b/tests/fail/data_race/stack_pop_race.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-preemption-rate=0 use std::thread; diff --git a/tests/fail/data_race/write_write_race.rs b/tests/fail/data_race/write_write_race.rs index fae4582e7e47..ac75c771e475 100644 --- a/tests/fail/data_race/write_write_race.rs +++ b/tests/fail/data_race/write_write_race.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/write_write_race_stack.rs b/tests/fail/data_race/write_write_race_stack.rs index 4b83413b3922..5193b155512c 100644 --- a/tests/fail/data_race/write_write_race_stack.rs +++ b/tests/fail/data_race/write_write_race_stack.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::ptr::null_mut; diff --git a/tests/fail/environ-gets-deallocated.rs b/tests/fail/environ-gets-deallocated.rs index 39629610c632..e4597140b844 100644 --- a/tests/fail/environ-gets-deallocated.rs +++ b/tests/fail/environ-gets-deallocated.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Windows does not have a global environ list that the program can access directly +//@ignore-target-windows: Windows does not have a global environ list that the program can access directly #[cfg(any(target_os = "linux", target_os = "freebsd"))] fn get_environ() -> *const *const u8 { diff --git a/tests/fail/fs/close_stdout.rs b/tests/fail/fs/close_stdout.rs index 3271722de0f9..bc709fe36d57 100644 --- a/tests/fail/fs/close_stdout.rs +++ b/tests/fail/fs/close_stdout.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows //@compile-flags: -Zmiri-disable-isolation // FIXME: standard handles cannot be closed (https://github.com/rust-lang/rust/issues/40032) diff --git a/tests/fail/fs/isolated_file.rs b/tests/fail/fs/isolated_file.rs index 00bb492147a8..9b664ffe52ac 100644 --- a/tests/fail/fs/isolated_file.rs +++ b/tests/fail/fs/isolated_file.rs @@ -1,4 +1,4 @@ -//@ignore-windows: File handling is not implemented yet +//@ignore-target-windows: File handling is not implemented yet //@error-pattern: `open` not available when isolation is enabled fn main() { diff --git a/tests/fail/fs/isolated_stdin.rs b/tests/fail/fs/isolated_stdin.rs index 27c66c58eb2f..cd54de3bcecc 100644 --- a/tests/fail/fs/isolated_stdin.rs +++ b/tests/fail/fs/isolated_stdin.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/fs/read_from_stdout.rs b/tests/fail/fs/read_from_stdout.rs index d78bc9f34d7d..949fe88f4333 100644 --- a/tests/fail/fs/read_from_stdout.rs +++ b/tests/fail/fs/read_from_stdout.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-disable-isolation -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/fs/unix_open_missing_required_mode.rs b/tests/fail/fs/unix_open_missing_required_mode.rs index 03993db81f57..1f6beadcb82f 100644 --- a/tests/fail/fs/unix_open_missing_required_mode.rs +++ b/tests/fail/fs/unix_open_missing_required_mode.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows //@compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] diff --git a/tests/fail/fs/write_to_stdin.rs b/tests/fail/fs/write_to_stdin.rs index 78ea0f4a18bd..4ad7b648e1cf 100644 --- a/tests/fail/fs/write_to_stdin.rs +++ b/tests/fail/fs/write_to_stdin.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/should-pass/cpp20_rwc_syncs.rs b/tests/fail/should-pass/cpp20_rwc_syncs.rs index 6478f446accc..dbac6469fbab 100644 --- a/tests/fail/should-pass/cpp20_rwc_syncs.rs +++ b/tests/fail/should-pass/cpp20_rwc_syncs.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-ignore-leaks //@error-pattern: unreachable diff --git a/tests/fail/sync/libc_pthread_cond_double_destroy.rs b/tests/fail/sync/libc_pthread_cond_double_destroy.rs index 77235d485cde..d0a4ac46cb33 100644 --- a/tests/fail/sync/libc_pthread_cond_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_cond_double_destroy.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] /// Test that destroying a pthread_cond twice fails, even without a check for number validity diff --git a/tests/fail/sync/libc_pthread_condattr_double_destroy.rs b/tests/fail/sync/libc_pthread_condattr_double_destroy.rs index 3b4522fb046c..c64b32381384 100644 --- a/tests/fail/sync/libc_pthread_condattr_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_condattr_double_destroy.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] /// Test that destroying a pthread_condattr twice fails, even without a check for number validity diff --git a/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs index ade9903b9dd5..8797e895d8c8 100644 --- a/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows // // Check that if we pass NULL attribute, then we get the default mutex type. diff --git a/tests/fail/sync/libc_pthread_mutex_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_deadlock.rs index 597d7721b12d..7da6e5160000 100644 --- a/tests/fail/sync/libc_pthread_mutex_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_deadlock.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs index dee5c80e9c40..70a85aa0f989 100644 --- a/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows // // Check that if we do not set the mutex type, it is the default. diff --git a/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs b/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs index a7ef5e44c9da..fc69ace36993 100644 --- a/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs +++ b/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_mutex_double_destroy.rs b/tests/fail/sync/libc_pthread_mutex_double_destroy.rs index 8f60409b0052..9b539afc1992 100644 --- a/tests/fail/sync/libc_pthread_mutex_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_mutex_double_destroy.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] /// Test that destroying a pthread_mutex twice fails, even without a check for number validity diff --git a/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs index 45475249befc..944e86e106d7 100644 --- a/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs index da23819ebc31..c2bdce82b6f8 100644 --- a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs +++ b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_mutex_wrong_owner.rs b/tests/fail/sync/libc_pthread_mutex_wrong_owner.rs index d91245104b0e..eea4db711597 100644 --- a/tests/fail/sync/libc_pthread_mutex_wrong_owner.rs +++ b/tests/fail/sync/libc_pthread_mutex_wrong_owner.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs b/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs index 8fb7cc3ea603..620dbb94a78a 100644 --- a/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] /// Test that destroying a pthread_mutexattr twice fails, even without a check for number validity diff --git a/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs b/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs index 0efb6724c177..67b77ff28647 100644 --- a/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs +++ b/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs b/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs index 11c09c1b1342..5bc5fe3c6bc4 100644 --- a/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs +++ b/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs b/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs index 9de0383f9daf..7e756c5bb88f 100644 --- a/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] /// Test that destroying a pthread_rwlock twice fails, even without a check for number validity diff --git a/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs index 9c8d22310cab..76fceb315f44 100644 --- a/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs +++ b/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs b/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs index 361cc7cdd850..e971fd8c302a 100644 --- a/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs +++ b/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs b/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs index 9d3ca275cb04..29cfd36cafc2 100644 --- a/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs +++ b/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs index 3158b944a7f7..e9c5c17f3eba 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs index c6b468eb89b1..5ed25344e7c7 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs index 91adaf85499f..3d15370e83dd 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs index 13a7ceefc7bb..14361bee54c0 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs b/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs index a205bbcb6b55..668ccb3ecaef 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/unsupported_signal.rs b/tests/fail/unsupported_signal.rs index 4319dc7c69fe..e9bd340fcafb 100644 --- a/tests/fail/unsupported_signal.rs +++ b/tests/fail/unsupported_signal.rs @@ -1,6 +1,6 @@ //! `signal()` is special on Linux and macOS that it's only supported within libstd. //! The implementation is not complete enough to permit user code to call it. -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] extern crate libc; diff --git a/tests/fail/weak_memory/racing_mixed_size.rs b/tests/fail/weak_memory/racing_mixed_size.rs index d697e5f8fbea..a7c5a4191762 100644 --- a/tests/fail/weak_memory/racing_mixed_size.rs +++ b/tests/fail/weak_memory/racing_mixed_size.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] diff --git a/tests/fail/weak_memory/racing_mixed_size_read.rs b/tests/fail/weak_memory/racing_mixed_size_read.rs index 0eacaeeaa9ee..aeaa6b68f6c8 100644 --- a/tests/fail/weak_memory/racing_mixed_size_read.rs +++ b/tests/fail/weak_memory/racing_mixed_size_read.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] diff --git a/tests/panic/panic/unsupported_syscall.rs b/tests/panic/panic/unsupported_syscall.rs index 3338c46c04ef..a68917281466 100644 --- a/tests/panic/panic/unsupported_syscall.rs +++ b/tests/panic/panic/unsupported_syscall.rs @@ -1,5 +1,5 @@ -//@ignore-windows: No libc on Windows -//@ignore-apple: `syscall` is not supported on macOS +//@ignore-target-windows: No libc on Windows +//@ignore-target-apple: `syscall` is not supported on macOS //@compile-flags: -Zmiri-panic-on-unsupported #![feature(rustc_private)] diff --git a/tests/pass/0weak_memory_consistency.rs b/tests/pass/0weak_memory_consistency.rs index 8b7ce50d2d42..b5b6b83cce1b 100644 --- a/tests/pass/0weak_memory_consistency.rs +++ b/tests/pass/0weak_memory_consistency.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows // The following tests check whether our weak memory emulation produces diff --git a/tests/pass/calloc.rs b/tests/pass/calloc.rs index a75bb0606118..a9efb776b69e 100644 --- a/tests/pass/calloc.rs +++ b/tests/pass/calloc.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/pass/concurrency/channels.rs b/tests/pass/concurrency/channels.rs index e94c69b286d6..40d729f042d1 100644 --- a/tests/pass/concurrency/channels.rs +++ b/tests/pass/concurrency/channels.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-strict-provenance use std::sync::mpsc::{channel, sync_channel}; diff --git a/tests/pass/concurrency/concurrent_caller_location.rs b/tests/pass/concurrency/concurrent_caller_location.rs index 6bd601abd56e..a07f6b13e6d7 100644 --- a/tests/pass/concurrency/concurrent_caller_location.rs +++ b/tests/pass/concurrency/concurrent_caller_location.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::panic::Location; use std::thread::spawn; diff --git a/tests/pass/concurrency/data_race.rs b/tests/pass/concurrency/data_race.rs index 69b6c53a2b79..5d1e1bb266ca 100644 --- a/tests/pass/concurrency/data_race.rs +++ b/tests/pass/concurrency/data_race.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-weak-memory-emulation use std::sync::atomic::{fence, AtomicUsize, Ordering}; diff --git a/tests/pass/concurrency/disable_data_race_detector.rs b/tests/pass/concurrency/disable_data_race_detector.rs index a3c1e4621a3a..a4852b4674e8 100644 --- a/tests/pass/concurrency/disable_data_race_detector.rs +++ b/tests/pass/concurrency/disable_data_race_detector.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-data-race-detector use std::thread::spawn; diff --git a/tests/pass/concurrency/issue1643.rs b/tests/pass/concurrency/issue1643.rs index cfe9cf4cc2f7..f4fe43d88cb1 100644 --- a/tests/pass/concurrency/issue1643.rs +++ b/tests/pass/concurrency/issue1643.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/pass/concurrency/libc_pthread_cond.rs b/tests/pass/concurrency/libc_pthread_cond.rs index 8d245e2f8ddd..eb491486be70 100644 --- a/tests/pass/concurrency/libc_pthread_cond.rs +++ b/tests/pass/concurrency/libc_pthread_cond.rs @@ -1,5 +1,5 @@ -//@ignore-windows: No libc on Windows -//@ignore-apple: pthread_condattr_setclock is not supported on MacOS. +//@ignore-target-windows: No libc on Windows +//@ignore-target-apple: pthread_condattr_setclock is not supported on MacOS. //@compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] diff --git a/tests/pass/concurrency/linux-futex.rs b/tests/pass/concurrency/linux-futex.rs index 1ec0ec599f7b..f9c87e0723c5 100644 --- a/tests/pass/concurrency/linux-futex.rs +++ b/tests/pass/concurrency/linux-futex.rs @@ -1,4 +1,4 @@ -//@only-linux +//@only-target-linux //@compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] diff --git a/tests/pass/concurrency/simple.rs b/tests/pass/concurrency/simple.rs index ac268dab5e94..1d85c7fc9bd0 100644 --- a/tests/pass/concurrency/simple.rs +++ b/tests/pass/concurrency/simple.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-strict-provenance use std::thread; diff --git a/tests/pass/concurrency/spin_loop.rs b/tests/pass/concurrency/spin_loop.rs index e1c472589904..5f34168dbb1e 100644 --- a/tests/pass/concurrency/spin_loop.rs +++ b/tests/pass/concurrency/spin_loop.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread; diff --git a/tests/pass/concurrency/spin_loops_nopreempt.rs b/tests/pass/concurrency/spin_loops_nopreempt.rs index 823d2ec76540..34be0dd39481 100644 --- a/tests/pass/concurrency/spin_loops_nopreempt.rs +++ b/tests/pass/concurrency/spin_loops_nopreempt.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. // This specifically tests behavior *without* preemption. //@compile-flags: -Zmiri-preemption-rate=0 diff --git a/tests/pass/concurrency/sync.rs b/tests/pass/concurrency/sync.rs index 64bd7ebb27fd..268153b612ae 100644 --- a/tests/pass/concurrency/sync.rs +++ b/tests/pass/concurrency/sync.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock}; diff --git a/tests/pass/concurrency/sync_nopreempt.rs b/tests/pass/concurrency/sync_nopreempt.rs index e6ee4fe594f1..a53f143fef67 100644 --- a/tests/pass/concurrency/sync_nopreempt.rs +++ b/tests/pass/concurrency/sync_nopreempt.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. // We are making scheduler assumptions here. //@compile-flags: -Zmiri-strict-provenance -Zmiri-preemption-rate=0 diff --git a/tests/pass/concurrency/thread_locals.rs b/tests/pass/concurrency/thread_locals.rs index 82ce61d958d8..34431def33f8 100644 --- a/tests/pass/concurrency/thread_locals.rs +++ b/tests/pass/concurrency/thread_locals.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-strict-provenance //! The main purpose of this test is to check that if we take a pointer to diff --git a/tests/pass/concurrency/tls_lib_drop.rs b/tests/pass/concurrency/tls_lib_drop.rs index 74ba8ee76207..6c66cd3a62fb 100644 --- a/tests/pass/concurrency/tls_lib_drop.rs +++ b/tests/pass/concurrency/tls_lib_drop.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::cell::RefCell; use std::thread; diff --git a/tests/pass/concurrency/tls_pthread_drop_order.rs b/tests/pass/concurrency/tls_pthread_drop_order.rs index b265e7da0b25..c9e8b9271ccf 100644 --- a/tests/pass/concurrency/tls_pthread_drop_order.rs +++ b/tests/pass/concurrency/tls_pthread_drop_order.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] extern crate libc; diff --git a/tests/pass/fs.rs b/tests/pass/fs.rs index ced7831568e7..aa5cd83c69cd 100644 --- a/tests/pass/fs.rs +++ b/tests/pass/fs.rs @@ -1,4 +1,4 @@ -//@ignore-windows: File handling is not implemented yet +//@ignore-target-windows: File handling is not implemented yet //@compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] diff --git a/tests/pass/fs_with_isolation.rs b/tests/pass/fs_with_isolation.rs index 719882702cdd..41ada94e276e 100644 --- a/tests/pass/fs_with_isolation.rs +++ b/tests/pass/fs_with_isolation.rs @@ -1,4 +1,4 @@ -//@ignore-windows: File handling is not implemented yet +//@ignore-target-windows: File handling is not implemented yet //@compile-flags: -Zmiri-isolation-error=warn-nobacktrace //@normalize-stderr-test: "(stat(x)?)" -> "$$STAT" diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index 53c85d2b07d1..486ae4b3cfae 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows //@compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] diff --git a/tests/pass/linux-getrandom-without-isolation.rs b/tests/pass/linux-getrandom-without-isolation.rs index 90e054533c14..fea3bb3fdce9 100644 --- a/tests/pass/linux-getrandom-without-isolation.rs +++ b/tests/pass/linux-getrandom-without-isolation.rs @@ -1,4 +1,4 @@ -//@only-linux +//@only-target-linux //@compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] extern crate libc; diff --git a/tests/pass/linux-getrandom.rs b/tests/pass/linux-getrandom.rs index 70c106f6460a..1d0ab6ed746a 100644 --- a/tests/pass/linux-getrandom.rs +++ b/tests/pass/linux-getrandom.rs @@ -1,4 +1,4 @@ -//@only-linux +//@only-target-linux #![feature(rustc_private)] extern crate libc; diff --git a/tests/pass/malloc.rs b/tests/pass/malloc.rs index c0a6a89fbed0..d20ceddbb8ed 100644 --- a/tests/pass/malloc.rs +++ b/tests/pass/malloc.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/pass/no_std.rs b/tests/pass/no_std.rs index d8a462daf5a9..10632c2cce49 100644 --- a/tests/pass/no_std.rs +++ b/tests/pass/no_std.rs @@ -3,7 +3,7 @@ // 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-windows +//@ignore-target-windows #[start] fn start(_: isize, _: *const *const u8) -> isize { diff --git a/tests/pass/panic/concurrent-panic.rs b/tests/pass/panic/concurrent-panic.rs index 1231760865fb..1acae69b8d3b 100644 --- a/tests/pass/panic/concurrent-panic.rs +++ b/tests/pass/panic/concurrent-panic.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. // We are making scheduler assumptions here. //@compile-flags: -Zmiri-preemption-rate=0 diff --git a/tests/pass/threadleak_ignored.rs b/tests/pass/threadleak_ignored.rs index 2ba0b453ff39..077d8d083753 100644 --- a/tests/pass/threadleak_ignored.rs +++ b/tests/pass/threadleak_ignored.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. // FIXME: disallow preemption to work around https://github.com/rust-lang/rust/issues/55005 //@compile-flags: -Zmiri-ignore-leaks -Zmiri-preemption-rate=0 diff --git a/tests/pass/weak_memory/extra_cpp.rs b/tests/pass/weak_memory/extra_cpp.rs index 61ba1ab92248..52c13cbdced3 100644 --- a/tests/pass/weak_memory/extra_cpp.rs +++ b/tests/pass/weak_memory/extra_cpp.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-ignore-leaks // Tests operations not perfomable through C++'s atomic API diff --git a/tests/pass/weak_memory/extra_cpp_unsafe.rs b/tests/pass/weak_memory/extra_cpp_unsafe.rs index 0aff70ab7b78..1c6c370ced3b 100644 --- a/tests/pass/weak_memory/extra_cpp_unsafe.rs +++ b/tests/pass/weak_memory/extra_cpp_unsafe.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-ignore-leaks // Tests operations not perfomable through C++'s atomic API diff --git a/tests/pass/weak_memory/weak.rs b/tests/pass/weak_memory/weak.rs index 71d57dd11ec7..dc7982991b69 100644 --- a/tests/pass/weak_memory/weak.rs +++ b/tests/pass/weak_memory/weak.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-ignore-leaks -Zmiri-preemption-rate=0 // Tests showing weak memory behaviours are exhibited. All tests diff --git a/tests/pass/wtf8.rs b/tests/pass/wtf8.rs index bf23f65c7f0c..be8348654a32 100644 --- a/tests/pass/wtf8.rs +++ b/tests/pass/wtf8.rs @@ -1,4 +1,4 @@ -//@only-windows +//@only-target-windows use std::ffi::{OsStr, OsString}; use std::os::windows::ffi::{OsStrExt, OsStringExt}; diff --git a/ui_test/src/parser.rs b/ui_test/src/parser.rs index e7fb484434d7..528486268877 100644 --- a/ui_test/src/parser.rs +++ b/ui_test/src/parser.rs @@ -65,16 +65,18 @@ pub(crate) struct ErrorMatch { } impl Condition { - fn parse(c: &str) -> Self { + fn parse(c: &str) -> Result { if c == "on-host" { - Condition::OnHost + Ok(Condition::OnHost) } else if let Some(bits) = c.strip_suffix("bit") { let bits: u8 = bits.parse().expect( "ignore/only filter ending in 'bit' must be of the form 'Nbit' for some integer N", ); - Condition::Bitwidth(bits) + Ok(Condition::Bitwidth(bits)) + } else if let Some(target) = c.strip_prefix("target-") { + Ok(Condition::Target(target.to_owned())) } else { - Condition::Target(c.to_owned()) + Err(eyre!("invalid ignore/only condition {c:?}")) } } } @@ -211,13 +213,13 @@ impl Comments { command => { if let Some(s) = command.strip_prefix("ignore-") { // args are ignored (can be sue as comment) - self.ignore.push(Condition::parse(s)); + self.ignore.push(Condition::parse(s)?); return Ok(()); } if let Some(s) = command.strip_prefix("only-") { // args are ignored (can be sue as comment) - self.only.push(Condition::parse(s)); + self.only.push(Condition::parse(s)?); return Ok(()); } bail!("unknown command {command}"); From 090f2892143ef872e561334907115c5e26eeef76 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Jul 2022 21:57:56 -0400 Subject: [PATCH 3534/5092] make an expect into proper error reporting --- ui_test/src/parser.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui_test/src/parser.rs b/ui_test/src/parser.rs index 528486268877..d583e625face 100644 --- a/ui_test/src/parser.rs +++ b/ui_test/src/parser.rs @@ -69,9 +69,9 @@ impl Condition { if c == "on-host" { Ok(Condition::OnHost) } else if let Some(bits) = c.strip_suffix("bit") { - let bits: u8 = bits.parse().expect( - "ignore/only filter ending in 'bit' must be of the form 'Nbit' for some integer N", - ); + let bits: u8 = bits.parse().map_err(|_err| { + eyre!("invalid ignore/only filter ending in 'bit': {c:?} is not a valid bitwdith") + })?; Ok(Condition::Bitwidth(bits)) } else if let Some(target) = c.strip_prefix("target-") { Ok(Condition::Target(target.to_owned())) From e30dd07139aa5bda7d690b20e9336edae3f42e4f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Jul 2022 21:51:52 -0400 Subject: [PATCH 3535/5092] libc test: also call isatty on an actual file --- tests/pass/libc.rs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index 6da527927071..ea3848a9749a 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -1,11 +1,12 @@ //@ignore-windows: No libc on Windows //@compile-flags: -Zmiri-disable-isolation - #![feature(rustc_private)] +use std::fs::{remove_file, File}; +use std::os::unix::io::AsRawFd; + extern crate libc; -#[cfg(any(target_os = "linux", target_os = "freebsd"))] fn tmp() -> std::path::PathBuf { std::env::var("MIRI_TEMP") .map(std::path::PathBuf::from) @@ -15,9 +16,7 @@ fn tmp() -> std::path::PathBuf { #[cfg(any(target_os = "linux", target_os = "freebsd"))] fn test_posix_fadvise() { use std::convert::TryInto; - use std::fs::{remove_file, File}; use std::io::Write; - use std::os::unix::io::AsRawFd; let path = tmp().join("miri_test_libc_posix_fadvise.txt"); // Cleanup before test @@ -44,9 +43,7 @@ fn test_posix_fadvise() { #[cfg(any(target_os = "linux"))] fn test_sync_file_range() { - use std::fs::{remove_file, File}; use std::io::Write; - use std::os::unix::io::AsRawFd; let path = tmp().join("miri_test_libc_sync_file_range.txt"); // Cleanup before test. @@ -319,6 +316,19 @@ fn test_isatty() { libc::isatty(libc::STDIN_FILENO); libc::isatty(libc::STDOUT_FILENO); libc::isatty(libc::STDERR_FILENO); + + // But when we open a file, it is definitely not a TTY. + let path = tmp().join("notatty.txt"); + // Cleanup before test. + remove_file(&path).ok(); + let file = File::create(&path).unwrap(); + + assert_eq!(libc::isatty(file.as_raw_fd()), 0); + assert_eq!(std::io::Error::last_os_error().raw_os_error().unwrap(), libc::ENOTTY); + + // Cleanup after test. + drop(file); + remove_file(&path).unwrap(); } } From 52a6ac96b0a2a270400d75ba9ed3aa829826b5db Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Jul 2022 07:55:11 -0400 Subject: [PATCH 3536/5092] move atomic intrinsics to their own file --- rust-version | 2 +- src/lib.rs | 1 + src/shims/intrinsics/atomic.rs | 437 ++++++++++++++++ .../{intrinsics.rs => intrinsics/mod.rs} | 481 ++---------------- 4 files changed, 473 insertions(+), 448 deletions(-) create mode 100644 src/shims/intrinsics/atomic.rs rename src/shims/{intrinsics.rs => intrinsics/mod.rs} (68%) diff --git a/rust-version b/rust-version index 5396b338cecb..362bcc35eade 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -db41351753df840773ca628d8daa040e95d00eef +880416180b0a9ee1141c07d4d17667edb77daebd diff --git a/src/lib.rs b/src/lib.rs index b3d408a6dc07..80281d37de9a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,6 +62,7 @@ pub use rustc_const_eval::interpret::{self, AllocMap, PlaceTy}; pub use crate::shims::dlsym::{Dlsym, EvalContextExt as _}; pub use crate::shims::env::{EnvVars, EvalContextExt as _}; pub use crate::shims::foreign_items::EvalContextExt as _; +pub use crate::shims::intrinsics::atomic::EvalContextExt as _; pub use crate::shims::intrinsics::EvalContextExt as _; pub use crate::shims::os_str::EvalContextExt as _; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _}; diff --git a/src/shims/intrinsics/atomic.rs b/src/shims/intrinsics/atomic.rs new file mode 100644 index 000000000000..2ba591127cea --- /dev/null +++ b/src/shims/intrinsics/atomic.rs @@ -0,0 +1,437 @@ +use rustc_middle::{mir, mir::BinOp}; +use rustc_target::abi::Align; + +use crate::*; +use helpers::check_arg_count; + +pub enum AtomicOp { + MirOp(mir::BinOp, bool), + Max, + Min, +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + /// Calls the atomic intrinsic `intrinsic`; the `atomic_` prefix has already been removed. + fn emulate_atomic_intrinsic( + &mut self, + intrinsic_name: &str, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + match intrinsic_name { + // Atomic operations + "load_seqcst" => this.atomic_load(args, dest, AtomicReadOrd::SeqCst)?, + "load_relaxed" => this.atomic_load(args, dest, AtomicReadOrd::Relaxed)?, + "load_acquire" => this.atomic_load(args, dest, AtomicReadOrd::Acquire)?, + + "store_seqcst" => this.atomic_store(args, AtomicWriteOrd::SeqCst)?, + "store_relaxed" => this.atomic_store(args, AtomicWriteOrd::Relaxed)?, + "store_release" => this.atomic_store(args, AtomicWriteOrd::Release)?, + + "fence_acquire" => this.atomic_fence(args, AtomicFenceOrd::Acquire)?, + "fence_release" => this.atomic_fence(args, AtomicFenceOrd::Release)?, + "fence_acqrel" => this.atomic_fence(args, AtomicFenceOrd::AcqRel)?, + "fence_seqcst" => this.atomic_fence(args, AtomicFenceOrd::SeqCst)?, + + "singlethreadfence_acquire" => this.compiler_fence(args, AtomicFenceOrd::Acquire)?, + "singlethreadfence_release" => this.compiler_fence(args, AtomicFenceOrd::Release)?, + "singlethreadfence_acqrel" => this.compiler_fence(args, AtomicFenceOrd::AcqRel)?, + "singlethreadfence_seqcst" => this.compiler_fence(args, AtomicFenceOrd::SeqCst)?, + + "xchg_seqcst" => this.atomic_exchange(args, dest, AtomicRwOrd::SeqCst)?, + "xchg_acquire" => this.atomic_exchange(args, dest, AtomicRwOrd::Acquire)?, + "xchg_release" => this.atomic_exchange(args, dest, AtomicRwOrd::Release)?, + "xchg_acqrel" => this.atomic_exchange(args, dest, AtomicRwOrd::AcqRel)?, + "xchg_relaxed" => this.atomic_exchange(args, dest, AtomicRwOrd::Relaxed)?, + + #[rustfmt::skip] + "cxchg_seqcst_seqcst" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::SeqCst)?, + #[rustfmt::skip] + "cxchg_acquire_acquire" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Acquire)?, + #[rustfmt::skip] + "cxchg_release_relaxed" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchg_acqrel_acquire" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Acquire)?, + #[rustfmt::skip] + "cxchg_relaxed_relaxed" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchg_acquire_relaxed" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchg_acqrel_relaxed" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchg_seqcst_relaxed" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchg_seqcst_acquire" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Acquire)?, + + #[rustfmt::skip] + "cxchgweak_seqcst_seqcst" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::SeqCst)?, + #[rustfmt::skip] + "cxchgweak_acquire_acquire" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Acquire)?, + #[rustfmt::skip] + "cxchgweak_release_relaxed" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchgweak_acqrel_acquire" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Acquire)?, + #[rustfmt::skip] + "cxchgweak_relaxed_relaxed" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchgweak_acquire_relaxed" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchgweak_acqrel_relaxed" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchgweak_seqcst_relaxed" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchgweak_seqcst_acquire" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Acquire)?, + + #[rustfmt::skip] + "or_seqcst" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::SeqCst)?, + #[rustfmt::skip] + "or_acquire" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::Acquire)?, + #[rustfmt::skip] + "or_release" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::Release)?, + #[rustfmt::skip] + "or_acqrel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::AcqRel)?, + #[rustfmt::skip] + "or_relaxed" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::Relaxed)?, + #[rustfmt::skip] + "xor_seqcst" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::SeqCst)?, + #[rustfmt::skip] + "xor_acquire" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::Acquire)?, + #[rustfmt::skip] + "xor_release" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::Release)?, + #[rustfmt::skip] + "xor_acqrel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::AcqRel)?, + #[rustfmt::skip] + "xor_relaxed" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::Relaxed)?, + #[rustfmt::skip] + "and_seqcst" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::SeqCst)?, + #[rustfmt::skip] + "and_acquire" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::Acquire)?, + #[rustfmt::skip] + "and_release" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::Release)?, + #[rustfmt::skip] + "and_acqrel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::AcqRel)?, + #[rustfmt::skip] + "and_relaxed" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::Relaxed)?, + #[rustfmt::skip] + "nand_seqcst" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::SeqCst)?, + #[rustfmt::skip] + "nand_acquire" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::Acquire)?, + #[rustfmt::skip] + "nand_release" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::Release)?, + #[rustfmt::skip] + "nand_acqrel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::AcqRel)?, + #[rustfmt::skip] + "nand_relaxed" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::Relaxed)?, + #[rustfmt::skip] + "xadd_seqcst" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::SeqCst)?, + #[rustfmt::skip] + "xadd_acquire" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::Acquire)?, + #[rustfmt::skip] + "xadd_release" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::Release)?, + #[rustfmt::skip] + "xadd_acqrel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::AcqRel)?, + #[rustfmt::skip] + "xadd_relaxed" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::Relaxed)?, + #[rustfmt::skip] + "xsub_seqcst" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::SeqCst)?, + #[rustfmt::skip] + "xsub_acquire" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::Acquire)?, + #[rustfmt::skip] + "xsub_release" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::Release)?, + #[rustfmt::skip] + "xsub_acqrel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::AcqRel)?, + #[rustfmt::skip] + "xsub_relaxed" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::Relaxed)?, + + "min_seqcst" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::SeqCst)?, + "min_acquire" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Acquire)?, + "min_release" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Release)?, + "min_acqrel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::AcqRel)?, + "min_relaxed" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Relaxed)?, + "max_seqcst" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::SeqCst)?, + "max_acquire" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Acquire)?, + "max_release" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Release)?, + "max_acqrel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::AcqRel)?, + "max_relaxed" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Relaxed)?, + "umin_seqcst" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::SeqCst)?, + "umin_acquire" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Acquire)?, + "umin_release" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Release)?, + "umin_acqrel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::AcqRel)?, + "umin_relaxed" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Relaxed)?, + "umax_seqcst" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::SeqCst)?, + "umax_acquire" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Acquire)?, + "umax_release" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Release)?, + "umax_acqrel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::AcqRel)?, + "umax_relaxed" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Relaxed)?, + + name => throw_unsup_format!("unimplemented intrinsic: `atomic_{name}`"), + } + Ok(()) + } + + fn atomic_load( + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + atomic: AtomicReadOrd, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let [place] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + + // make sure it fits into a scalar; otherwise it cannot be atomic + let val = this.read_scalar_atomic(&place, atomic)?; + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.check_ptr_access_align( + place.ptr, + place.layout.size, + align, + CheckInAllocMsg::MemoryAccessTest, + )?; + // Perform regular access. + this.write_scalar(val, dest)?; + Ok(()) + } + + fn atomic_store( + &mut self, + args: &[OpTy<'tcx, Tag>], + atomic: AtomicWriteOrd, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let [place, val] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + let val = this.read_scalar(val)?; // make sure it fits into a scalar; otherwise it cannot be atomic + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.check_ptr_access_align( + place.ptr, + place.layout.size, + align, + CheckInAllocMsg::MemoryAccessTest, + )?; + + // Perform atomic store + this.write_scalar_atomic(val, &place, atomic)?; + Ok(()) + } + + fn compiler_fence( + &mut self, + args: &[OpTy<'tcx, Tag>], + atomic: AtomicFenceOrd, + ) -> InterpResult<'tcx> { + let [] = check_arg_count(args)?; + let _ = atomic; + //FIXME: compiler fences are currently ignored + Ok(()) + } + + fn atomic_fence( + &mut self, + args: &[OpTy<'tcx, Tag>], + atomic: AtomicFenceOrd, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let [] = check_arg_count(args)?; + this.validate_atomic_fence(atomic)?; + Ok(()) + } + + fn atomic_op( + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + atomic_op: AtomicOp, + atomic: AtomicRwOrd, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let [place, rhs] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + + if !place.layout.ty.is_integral() && !place.layout.ty.is_unsafe_ptr() { + span_bug!( + this.cur_span(), + "atomic arithmetic operations only work on integer and raw pointer types", + ); + } + let rhs = this.read_immediate(rhs)?; + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.check_ptr_access_align( + place.ptr, + place.layout.size, + align, + CheckInAllocMsg::MemoryAccessTest, + )?; + + match atomic_op { + AtomicOp::Min => { + let old = this.atomic_min_max_scalar(&place, rhs, true, atomic)?; + this.write_immediate(*old, dest)?; // old value is returned + Ok(()) + } + AtomicOp::Max => { + let old = this.atomic_min_max_scalar(&place, rhs, false, atomic)?; + this.write_immediate(*old, dest)?; // old value is returned + Ok(()) + } + AtomicOp::MirOp(op, neg) => { + let old = this.atomic_op_immediate(&place, &rhs, op, neg, atomic)?; + this.write_immediate(*old, dest)?; // old value is returned + Ok(()) + } + } + } + + fn atomic_exchange( + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + atomic: AtomicRwOrd, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let [place, new] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + let new = this.read_scalar(new)?; + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.check_ptr_access_align( + place.ptr, + place.layout.size, + align, + CheckInAllocMsg::MemoryAccessTest, + )?; + + let old = this.atomic_exchange_scalar(&place, new, atomic)?; + this.write_scalar(old, dest)?; // old value is returned + Ok(()) + } + + fn atomic_compare_exchange_impl( + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + success: AtomicRwOrd, + fail: AtomicReadOrd, + can_fail_spuriously: bool, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let [place, expect_old, new] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + let expect_old = this.read_immediate(expect_old)?; // read as immediate for the sake of `binary_op()` + let new = this.read_scalar(new)?; + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.check_ptr_access_align( + place.ptr, + place.layout.size, + align, + CheckInAllocMsg::MemoryAccessTest, + )?; + + let old = this.atomic_compare_exchange_scalar( + &place, + &expect_old, + new, + success, + fail, + can_fail_spuriously, + )?; + + // Return old value. + this.write_immediate(old, dest)?; + Ok(()) + } + + fn atomic_compare_exchange( + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + success: AtomicRwOrd, + fail: AtomicReadOrd, + ) -> InterpResult<'tcx> { + self.atomic_compare_exchange_impl(args, dest, success, fail, false) + } + + fn atomic_compare_exchange_weak( + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + success: AtomicRwOrd, + fail: AtomicReadOrd, + ) -> InterpResult<'tcx> { + self.atomic_compare_exchange_impl(args, dest, success, fail, true) + } +} diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics/mod.rs similarity index 68% rename from src/shims/intrinsics.rs rename to src/shims/intrinsics/mod.rs index ab79438c734d..6195147259af 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics/mod.rs @@ -1,21 +1,17 @@ +pub mod atomic; + use std::iter; use log::trace; use rustc_apfloat::{Float, Round}; use rustc_middle::ty::layout::{HasParamEnv, IntegerExt, LayoutOf}; -use rustc_middle::{mir, mir::BinOp, ty, ty::FloatTy}; -use rustc_target::abi::{Align, Endian, HasDataLayout, Integer, Size}; +use rustc_middle::{mir, ty, ty::FloatTy}; +use rustc_target::abi::{Endian, HasDataLayout, Integer, Size}; use crate::*; use helpers::check_arg_count; -pub enum AtomicOp { - MirOp(mir::BinOp, bool), - Max, - Min, -} - impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn call_intrinsic( @@ -28,11 +24,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + // See if the core engine can handle this intrinsic. if this.emulate_intrinsic(instance, args, dest, ret)? { return Ok(()); } - // All supported intrinsics have a return place. + // All remaining supported intrinsics have a return place. let intrinsic_name = this.tcx.item_name(instance.def_id()); let intrinsic_name = intrinsic_name.as_str(); let ret = match ret { @@ -40,7 +37,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(p) => p, }; - // Then handle terminating intrinsics. + // Some intrinsics are special and need the "ret". + match intrinsic_name { + "try" => return this.handle_try(args, dest, ret), + _ => {} + } + + // The rest jumps to `ret` immediately. + this.emulate_intrinsic_by_name(intrinsic_name, args, dest)?; + + trace!("{:?}", this.dump_place(**dest)); + this.go_to_block(ret); + Ok(()) + } + + /// Emulates a Miri-supported intrinsic (not supported by the core engine). + fn emulate_intrinsic_by_name( + &mut self, + intrinsic_name: &str, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + if let Some(name) = intrinsic_name.strip_prefix("atomic_") { + return this.emulate_atomic_intrinsic(name, args, dest); + } + match intrinsic_name { // Miri overwriting CTFE intrinsics. "ptr_guaranteed_eq" => { @@ -78,7 +101,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "write_bytes" | "volatile_set_memory" => { let [ptr, val_byte, count] = check_arg_count(args)?; - let ty = instance.substs.type_at(0); + let ty = ptr.layout.ty.builtin_deref(true).unwrap().ty; let ty_layout = this.layout_of(ty)?; let val_byte = this.read_scalar(val_byte)?.to_u8()?; let ptr = this.read_pointer(ptr)?; @@ -859,230 +882,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_int(res, dest)?; } - // Atomic operations - "atomic_load_seqcst" => this.atomic_load(args, dest, AtomicReadOrd::SeqCst)?, - "atomic_load_relaxed" => this.atomic_load(args, dest, AtomicReadOrd::Relaxed)?, - "atomic_load_acquire" => this.atomic_load(args, dest, AtomicReadOrd::Acquire)?, - - "atomic_store_seqcst" => this.atomic_store(args, AtomicWriteOrd::SeqCst)?, - "atomic_store_relaxed" => this.atomic_store(args, AtomicWriteOrd::Relaxed)?, - "atomic_store_release" => this.atomic_store(args, AtomicWriteOrd::Release)?, - - "atomic_fence_acquire" => this.atomic_fence(args, AtomicFenceOrd::Acquire)?, - "atomic_fence_release" => this.atomic_fence(args, AtomicFenceOrd::Release)?, - "atomic_fence_acqrel" => this.atomic_fence(args, AtomicFenceOrd::AcqRel)?, - "atomic_fence_seqcst" => this.atomic_fence(args, AtomicFenceOrd::SeqCst)?, - - "atomic_singlethreadfence_acquire" => - this.compiler_fence(args, AtomicFenceOrd::Acquire)?, - "atomic_singlethreadfence_release" => - this.compiler_fence(args, AtomicFenceOrd::Release)?, - "atomic_singlethreadfence_acqrel" => - this.compiler_fence(args, AtomicFenceOrd::AcqRel)?, - "atomic_singlethreadfence_seqcst" => - this.compiler_fence(args, AtomicFenceOrd::SeqCst)?, - - "atomic_xchg_seqcst" => this.atomic_exchange(args, dest, AtomicRwOrd::SeqCst)?, - "atomic_xchg_acquire" => this.atomic_exchange(args, dest, AtomicRwOrd::Acquire)?, - "atomic_xchg_release" => this.atomic_exchange(args, dest, AtomicRwOrd::Release)?, - "atomic_xchg_acqrel" => this.atomic_exchange(args, dest, AtomicRwOrd::AcqRel)?, - "atomic_xchg_relaxed" => this.atomic_exchange(args, dest, AtomicRwOrd::Relaxed)?, - - #[rustfmt::skip] - "atomic_cxchg_seqcst_seqcst" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::SeqCst)?, - #[rustfmt::skip] - "atomic_cxchg_acquire_acquire" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "atomic_cxchg_release_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_cxchg_acqrel_acquire" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "atomic_cxchg_relaxed_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_cxchg_acquire_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_cxchg_acqrel_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_cxchg_seqcst_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_cxchg_seqcst_acquire" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Acquire)?, - - #[rustfmt::skip] - "atomic_cxchgweak_seqcst_seqcst" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::SeqCst)?, - #[rustfmt::skip] - "atomic_cxchgweak_acquire_acquire" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "atomic_cxchgweak_release_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_cxchgweak_acqrel_acquire" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "atomic_cxchgweak_relaxed_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_cxchgweak_acquire_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_cxchgweak_acqrel_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_cxchgweak_seqcst_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_cxchgweak_seqcst_acquire" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Acquire)?, - - #[rustfmt::skip] - "atomic_or_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::SeqCst)?, - #[rustfmt::skip] - "atomic_or_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::Acquire)?, - #[rustfmt::skip] - "atomic_or_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::Release)?, - #[rustfmt::skip] - "atomic_or_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::AcqRel)?, - #[rustfmt::skip] - "atomic_or_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_xor_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::SeqCst)?, - #[rustfmt::skip] - "atomic_xor_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::Acquire)?, - #[rustfmt::skip] - "atomic_xor_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::Release)?, - #[rustfmt::skip] - "atomic_xor_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::AcqRel)?, - #[rustfmt::skip] - "atomic_xor_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_and_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::SeqCst)?, - #[rustfmt::skip] - "atomic_and_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::Acquire)?, - #[rustfmt::skip] - "atomic_and_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::Release)?, - #[rustfmt::skip] - "atomic_and_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::AcqRel)?, - #[rustfmt::skip] - "atomic_and_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_nand_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::SeqCst)?, - #[rustfmt::skip] - "atomic_nand_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::Acquire)?, - #[rustfmt::skip] - "atomic_nand_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::Release)?, - #[rustfmt::skip] - "atomic_nand_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::AcqRel)?, - #[rustfmt::skip] - "atomic_nand_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_xadd_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::SeqCst)?, - #[rustfmt::skip] - "atomic_xadd_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::Acquire)?, - #[rustfmt::skip] - "atomic_xadd_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::Release)?, - #[rustfmt::skip] - "atomic_xadd_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::AcqRel)?, - #[rustfmt::skip] - "atomic_xadd_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_xsub_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::SeqCst)?, - #[rustfmt::skip] - "atomic_xsub_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::Acquire)?, - #[rustfmt::skip] - "atomic_xsub_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::Release)?, - #[rustfmt::skip] - "atomic_xsub_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::AcqRel)?, - #[rustfmt::skip] - "atomic_xsub_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::Relaxed)?, - "atomic_min_seqcst" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::SeqCst)?, - "atomic_min_acquire" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Acquire)?, - "atomic_min_release" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Release)?, - "atomic_min_acqrel" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::AcqRel)?, - "atomic_min_relaxed" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Relaxed)?, - "atomic_max_seqcst" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::SeqCst)?, - "atomic_max_acquire" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Acquire)?, - "atomic_max_release" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Release)?, - "atomic_max_acqrel" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::AcqRel)?, - "atomic_max_relaxed" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Relaxed)?, - "atomic_umin_seqcst" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::SeqCst)?, - "atomic_umin_acquire" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Acquire)?, - "atomic_umin_release" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Release)?, - "atomic_umin_acqrel" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::AcqRel)?, - "atomic_umin_relaxed" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Relaxed)?, - "atomic_umax_seqcst" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::SeqCst)?, - "atomic_umax_acquire" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Acquire)?, - "atomic_umax_release" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Release)?, - "atomic_umax_acqrel" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::AcqRel)?, - "atomic_umax_relaxed" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Relaxed)?, - // Other "exact_div" => { let [num, denom] = check_arg_count(args)?; this.exact_div(&this.read_immediate(num)?, &this.read_immediate(denom)?, dest)?; } - "try" => return this.handle_try(args, dest, ret), - "breakpoint" => { let [] = check_arg_count(args)?; // normally this would raise a SIGTRAP, which aborts if no debugger is connected @@ -1092,227 +897,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name => throw_unsup_format!("unimplemented intrinsic: `{name}`"), } - trace!("{:?}", this.dump_place(**dest)); - this.go_to_block(ret); Ok(()) } - fn atomic_load( - &mut self, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, - atomic: AtomicReadOrd, - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - - let [place] = check_arg_count(args)?; - let place = this.deref_operand(place)?; - - // make sure it fits into a scalar; otherwise it cannot be atomic - let val = this.read_scalar_atomic(&place, atomic)?; - - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.check_ptr_access_align( - place.ptr, - place.layout.size, - align, - CheckInAllocMsg::MemoryAccessTest, - )?; - // Perform regular access. - this.write_scalar(val, dest)?; - Ok(()) - } - - fn atomic_store( - &mut self, - args: &[OpTy<'tcx, Tag>], - atomic: AtomicWriteOrd, - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - - let [place, val] = check_arg_count(args)?; - let place = this.deref_operand(place)?; - let val = this.read_scalar(val)?; // make sure it fits into a scalar; otherwise it cannot be atomic - - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.check_ptr_access_align( - place.ptr, - place.layout.size, - align, - CheckInAllocMsg::MemoryAccessTest, - )?; - - // Perform atomic store - this.write_scalar_atomic(val, &place, atomic)?; - Ok(()) - } - - fn compiler_fence( - &mut self, - args: &[OpTy<'tcx, Tag>], - atomic: AtomicFenceOrd, - ) -> InterpResult<'tcx> { - let [] = check_arg_count(args)?; - let _ = atomic; - //FIXME: compiler fences are currently ignored - Ok(()) - } - - fn atomic_fence( - &mut self, - args: &[OpTy<'tcx, Tag>], - atomic: AtomicFenceOrd, - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - let [] = check_arg_count(args)?; - this.validate_atomic_fence(atomic)?; - Ok(()) - } - - fn atomic_op( - &mut self, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, - atomic_op: AtomicOp, - atomic: AtomicRwOrd, - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - - let [place, rhs] = check_arg_count(args)?; - let place = this.deref_operand(place)?; - - if !place.layout.ty.is_integral() && !place.layout.ty.is_unsafe_ptr() { - span_bug!( - this.cur_span(), - "atomic arithmetic operations only work on integer and raw pointer types", - ); - } - let rhs = this.read_immediate(rhs)?; - - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.check_ptr_access_align( - place.ptr, - place.layout.size, - align, - CheckInAllocMsg::MemoryAccessTest, - )?; - - match atomic_op { - AtomicOp::Min => { - let old = this.atomic_min_max_scalar(&place, rhs, true, atomic)?; - this.write_immediate(*old, dest)?; // old value is returned - Ok(()) - } - AtomicOp::Max => { - let old = this.atomic_min_max_scalar(&place, rhs, false, atomic)?; - this.write_immediate(*old, dest)?; // old value is returned - Ok(()) - } - AtomicOp::MirOp(op, neg) => { - let old = this.atomic_op_immediate(&place, &rhs, op, neg, atomic)?; - this.write_immediate(*old, dest)?; // old value is returned - Ok(()) - } - } - } - - fn atomic_exchange( - &mut self, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, - atomic: AtomicRwOrd, - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - - let [place, new] = check_arg_count(args)?; - let place = this.deref_operand(place)?; - let new = this.read_scalar(new)?; - - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.check_ptr_access_align( - place.ptr, - place.layout.size, - align, - CheckInAllocMsg::MemoryAccessTest, - )?; - - let old = this.atomic_exchange_scalar(&place, new, atomic)?; - this.write_scalar(old, dest)?; // old value is returned - Ok(()) - } - - fn atomic_compare_exchange_impl( - &mut self, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, - success: AtomicRwOrd, - fail: AtomicReadOrd, - can_fail_spuriously: bool, - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - - let [place, expect_old, new] = check_arg_count(args)?; - let place = this.deref_operand(place)?; - let expect_old = this.read_immediate(expect_old)?; // read as immediate for the sake of `binary_op()` - let new = this.read_scalar(new)?; - - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.check_ptr_access_align( - place.ptr, - place.layout.size, - align, - CheckInAllocMsg::MemoryAccessTest, - )?; - - let old = this.atomic_compare_exchange_scalar( - &place, - &expect_old, - new, - success, - fail, - can_fail_spuriously, - )?; - - // Return old value. - this.write_immediate(old, dest)?; - Ok(()) - } - - fn atomic_compare_exchange( - &mut self, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, - success: AtomicRwOrd, - fail: AtomicReadOrd, - ) -> InterpResult<'tcx> { - self.atomic_compare_exchange_impl(args, dest, success, fail, false) - } - - fn atomic_compare_exchange_weak( - &mut self, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, - success: AtomicRwOrd, - fail: AtomicReadOrd, - ) -> InterpResult<'tcx> { - self.atomic_compare_exchange_impl(args, dest, success, fail, true) - } - fn float_to_int_unchecked( &self, f: F, From 53ead1b8c960a63a9422725d54d405c65756a1bb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Jul 2022 08:00:36 -0400 Subject: [PATCH 3537/5092] move simd intrinsics to their own file --- src/shims/intrinsics/atomic.rs | 1 - src/shims/intrinsics/mod.rs | 599 +------------------------------- src/shims/intrinsics/simd.rs | 613 +++++++++++++++++++++++++++++++++ 3 files changed, 620 insertions(+), 593 deletions(-) create mode 100644 src/shims/intrinsics/simd.rs diff --git a/src/shims/intrinsics/atomic.rs b/src/shims/intrinsics/atomic.rs index 2ba591127cea..e51fd98c5522 100644 --- a/src/shims/intrinsics/atomic.rs +++ b/src/shims/intrinsics/atomic.rs @@ -21,7 +21,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); match intrinsic_name { - // Atomic operations "load_seqcst" => this.atomic_load(args, dest, AtomicReadOrd::SeqCst)?, "load_relaxed" => this.atomic_load(args, dest, AtomicReadOrd::Relaxed)?, "load_acquire" => this.atomic_load(args, dest, AtomicReadOrd::Acquire)?, diff --git a/src/shims/intrinsics/mod.rs b/src/shims/intrinsics/mod.rs index 6195147259af..a8b8b807bd82 100644 --- a/src/shims/intrinsics/mod.rs +++ b/src/shims/intrinsics/mod.rs @@ -1,16 +1,18 @@ pub mod atomic; +mod simd; use std::iter; use log::trace; use rustc_apfloat::{Float, Round}; -use rustc_middle::ty::layout::{HasParamEnv, IntegerExt, LayoutOf}; +use rustc_middle::ty::layout::{IntegerExt, LayoutOf}; use rustc_middle::{mir, ty, ty::FloatTy}; -use rustc_target::abi::{Endian, HasDataLayout, Integer, Size}; +use rustc_target::abi::Integer; use crate::*; use helpers::check_arg_count; +use simd::EvalContextExt as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -63,6 +65,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(name) = intrinsic_name.strip_prefix("atomic_") { return this.emulate_atomic_intrinsic(name, args, dest); } + if let Some(name) = intrinsic_name.strip_prefix("simd_") { + return this.emulate_simd_intrinsic(name, args, dest); + } match intrinsic_name { // Miri overwriting CTFE intrinsics. @@ -347,541 +352,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } - // SIMD operations - #[rustfmt::skip] - | "simd_neg" - | "simd_fabs" - | "simd_ceil" - | "simd_floor" - | "simd_round" - | "simd_trunc" - | "simd_fsqrt" => { - let [op] = check_arg_count(args)?; - let (op, op_len) = this.operand_to_simd(op)?; - let (dest, dest_len) = this.place_to_simd(dest)?; - - assert_eq!(dest_len, op_len); - - #[derive(Copy, Clone)] - enum HostFloatOp { - Ceil, - Floor, - Round, - Trunc, - Sqrt, - } - #[derive(Copy, Clone)] - enum Op { - MirOp(mir::UnOp), - Abs, - HostOp(HostFloatOp), - } - let which = match intrinsic_name { - "simd_neg" => Op::MirOp(mir::UnOp::Neg), - "simd_fabs" => Op::Abs, - "simd_ceil" => Op::HostOp(HostFloatOp::Ceil), - "simd_floor" => Op::HostOp(HostFloatOp::Floor), - "simd_round" => Op::HostOp(HostFloatOp::Round), - "simd_trunc" => Op::HostOp(HostFloatOp::Trunc), - "simd_fsqrt" => Op::HostOp(HostFloatOp::Sqrt), - _ => unreachable!(), - }; - - for i in 0..dest_len { - let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; - let dest = this.mplace_index(&dest, i)?; - let val = match which { - Op::MirOp(mir_op) => this.unary_op(mir_op, &op)?.to_scalar()?, - Op::Abs => { - // Works for f32 and f64. - let ty::Float(float_ty) = op.layout.ty.kind() else { - span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name) - }; - let op = op.to_scalar()?; - match float_ty { - FloatTy::F32 => Scalar::from_f32(op.to_f32()?.abs()), - FloatTy::F64 => Scalar::from_f64(op.to_f64()?.abs()), - } - } - Op::HostOp(host_op) => { - let ty::Float(float_ty) = op.layout.ty.kind() else { - span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name) - }; - // FIXME using host floats - match float_ty { - FloatTy::F32 => { - let f = f32::from_bits(op.to_scalar()?.to_u32()?); - let res = match host_op { - HostFloatOp::Ceil => f.ceil(), - HostFloatOp::Floor => f.floor(), - HostFloatOp::Round => f.round(), - HostFloatOp::Trunc => f.trunc(), - HostFloatOp::Sqrt => f.sqrt(), - }; - Scalar::from_u32(res.to_bits()) - } - FloatTy::F64 => { - let f = f64::from_bits(op.to_scalar()?.to_u64()?); - let res = match host_op { - HostFloatOp::Ceil => f.ceil(), - HostFloatOp::Floor => f.floor(), - HostFloatOp::Round => f.round(), - HostFloatOp::Trunc => f.trunc(), - HostFloatOp::Sqrt => f.sqrt(), - }; - Scalar::from_u64(res.to_bits()) - } - } - - } - }; - this.write_scalar(val, &dest.into())?; - } - } - #[rustfmt::skip] - | "simd_add" - | "simd_sub" - | "simd_mul" - | "simd_div" - | "simd_rem" - | "simd_shl" - | "simd_shr" - | "simd_and" - | "simd_or" - | "simd_xor" - | "simd_eq" - | "simd_ne" - | "simd_lt" - | "simd_le" - | "simd_gt" - | "simd_ge" - | "simd_fmax" - | "simd_fmin" - | "simd_saturating_add" - | "simd_saturating_sub" - | "simd_arith_offset" => { - use mir::BinOp; - - let [left, right] = check_arg_count(args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.place_to_simd(dest)?; - - assert_eq!(dest_len, left_len); - assert_eq!(dest_len, right_len); - - enum Op { - MirOp(BinOp), - SaturatingOp(BinOp), - FMax, - FMin, - WrappingOffset, - } - let which = match intrinsic_name { - "simd_add" => Op::MirOp(BinOp::Add), - "simd_sub" => Op::MirOp(BinOp::Sub), - "simd_mul" => Op::MirOp(BinOp::Mul), - "simd_div" => Op::MirOp(BinOp::Div), - "simd_rem" => Op::MirOp(BinOp::Rem), - "simd_shl" => Op::MirOp(BinOp::Shl), - "simd_shr" => Op::MirOp(BinOp::Shr), - "simd_and" => Op::MirOp(BinOp::BitAnd), - "simd_or" => Op::MirOp(BinOp::BitOr), - "simd_xor" => Op::MirOp(BinOp::BitXor), - "simd_eq" => Op::MirOp(BinOp::Eq), - "simd_ne" => Op::MirOp(BinOp::Ne), - "simd_lt" => Op::MirOp(BinOp::Lt), - "simd_le" => Op::MirOp(BinOp::Le), - "simd_gt" => Op::MirOp(BinOp::Gt), - "simd_ge" => Op::MirOp(BinOp::Ge), - "simd_fmax" => Op::FMax, - "simd_fmin" => Op::FMin, - "simd_saturating_add" => Op::SaturatingOp(BinOp::Add), - "simd_saturating_sub" => Op::SaturatingOp(BinOp::Sub), - "simd_arith_offset" => Op::WrappingOffset, - _ => unreachable!(), - }; - - for i in 0..dest_len { - let left = this.read_immediate(&this.mplace_index(&left, i)?.into())?; - let right = this.read_immediate(&this.mplace_index(&right, i)?.into())?; - let dest = this.mplace_index(&dest, i)?; - let val = match which { - Op::MirOp(mir_op) => { - let (val, overflowed, ty) = this.overflowing_binary_op(mir_op, &left, &right)?; - if matches!(mir_op, BinOp::Shl | BinOp::Shr) { - // Shifts have extra UB as SIMD operations that the MIR binop does not have. - // See . - if overflowed { - let r_val = right.to_scalar()?.to_bits(right.layout.size)?; - throw_ub_format!("overflowing shift by {r_val} in `{intrinsic_name}` in SIMD lane {i}"); - } - } - if matches!(mir_op, BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge) { - // Special handling for boolean-returning operations - assert_eq!(ty, this.tcx.types.bool); - let val = val.to_bool().unwrap(); - bool_to_simd_element(val, dest.layout.size) - } else { - assert_ne!(ty, this.tcx.types.bool); - assert_eq!(ty, dest.layout.ty); - val - } - } - Op::SaturatingOp(mir_op) => { - this.saturating_arith(mir_op, &left, &right)? - } - Op::WrappingOffset => { - let ptr = this.scalar_to_ptr(left.to_scalar()?)?; - let offset_count = right.to_scalar()?.to_machine_isize(this)?; - let pointee_ty = left.layout.ty.builtin_deref(true).unwrap().ty; - - let pointee_size = i64::try_from(this.layout_of(pointee_ty)?.size.bytes()).unwrap(); - let offset_bytes = offset_count.wrapping_mul(pointee_size); - let offset_ptr = ptr.wrapping_signed_offset(offset_bytes, this); - Scalar::from_maybe_pointer(offset_ptr, this) - } - Op::FMax => { - fmax_op(&left, &right)? - } - Op::FMin => { - fmin_op(&left, &right)? - } - }; - this.write_scalar(val, &dest.into())?; - } - } - "simd_fma" => { - let [a, b, c] = check_arg_count(args)?; - let (a, a_len) = this.operand_to_simd(a)?; - let (b, b_len) = this.operand_to_simd(b)?; - let (c, c_len) = this.operand_to_simd(c)?; - let (dest, dest_len) = this.place_to_simd(dest)?; - - assert_eq!(dest_len, a_len); - assert_eq!(dest_len, b_len); - assert_eq!(dest_len, c_len); - - for i in 0..dest_len { - let a = this.read_immediate(&this.mplace_index(&a, i)?.into())?.to_scalar()?; - let b = this.read_immediate(&this.mplace_index(&b, i)?.into())?.to_scalar()?; - let c = this.read_immediate(&this.mplace_index(&c, i)?.into())?.to_scalar()?; - let dest = this.mplace_index(&dest, i)?; - - // Works for f32 and f64. - let ty::Float(float_ty) = dest.layout.ty.kind() else { - span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name) - }; - let val = match float_ty { - FloatTy::F32 => - Scalar::from_f32(a.to_f32()?.mul_add(b.to_f32()?, c.to_f32()?).value), - FloatTy::F64 => - Scalar::from_f64(a.to_f64()?.mul_add(b.to_f64()?, c.to_f64()?).value), - }; - this.write_scalar(val, &dest.into())?; - } - } - #[rustfmt::skip] - | "simd_reduce_and" - | "simd_reduce_or" - | "simd_reduce_xor" - | "simd_reduce_any" - | "simd_reduce_all" - | "simd_reduce_max" - | "simd_reduce_min" => { - use mir::BinOp; - - let [op] = check_arg_count(args)?; - let (op, op_len) = this.operand_to_simd(op)?; - - let imm_from_bool = - |b| ImmTy::from_scalar(Scalar::from_bool(b), this.machine.layouts.bool); - - enum Op { - MirOp(BinOp), - MirOpBool(BinOp), - Max, - Min, - } - let which = match intrinsic_name { - "simd_reduce_and" => Op::MirOp(BinOp::BitAnd), - "simd_reduce_or" => Op::MirOp(BinOp::BitOr), - "simd_reduce_xor" => Op::MirOp(BinOp::BitXor), - "simd_reduce_any" => Op::MirOpBool(BinOp::BitOr), - "simd_reduce_all" => Op::MirOpBool(BinOp::BitAnd), - "simd_reduce_max" => Op::Max, - "simd_reduce_min" => Op::Min, - _ => unreachable!(), - }; - - // Initialize with first lane, then proceed with the rest. - let mut res = this.read_immediate(&this.mplace_index(&op, 0)?.into())?; - if matches!(which, Op::MirOpBool(_)) { - // Convert to `bool` scalar. - res = imm_from_bool(simd_element_to_bool(res)?); - } - for i in 1..op_len { - let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; - res = match which { - Op::MirOp(mir_op) => { - this.binary_op(mir_op, &res, &op)? - } - Op::MirOpBool(mir_op) => { - let op = imm_from_bool(simd_element_to_bool(op)?); - this.binary_op(mir_op, &res, &op)? - } - Op::Max => { - if matches!(res.layout.ty.kind(), ty::Float(_)) { - ImmTy::from_scalar(fmax_op(&res, &op)?, res.layout) - } else { - // Just boring integers, so NaNs to worry about - if this.binary_op(BinOp::Ge, &res, &op)?.to_scalar()?.to_bool()? { - res - } else { - op - } - } - } - Op::Min => { - if matches!(res.layout.ty.kind(), ty::Float(_)) { - ImmTy::from_scalar(fmin_op(&res, &op)?, res.layout) - } else { - // Just boring integers, so NaNs to worry about - if this.binary_op(BinOp::Le, &res, &op)?.to_scalar()?.to_bool()? { - res - } else { - op - } - } - } - }; - } - this.write_immediate(*res, dest)?; - } - #[rustfmt::skip] - | "simd_reduce_add_ordered" - | "simd_reduce_mul_ordered" => { - use mir::BinOp; - - let [op, init] = check_arg_count(args)?; - let (op, op_len) = this.operand_to_simd(op)?; - let init = this.read_immediate(init)?; - - let mir_op = match intrinsic_name { - "simd_reduce_add_ordered" => BinOp::Add, - "simd_reduce_mul_ordered" => BinOp::Mul, - _ => unreachable!(), - }; - - let mut res = init; - for i in 0..op_len { - let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; - res = this.binary_op(mir_op, &res, &op)?; - } - this.write_immediate(*res, dest)?; - } - "simd_select" => { - let [mask, yes, no] = check_arg_count(args)?; - let (mask, mask_len) = this.operand_to_simd(mask)?; - let (yes, yes_len) = this.operand_to_simd(yes)?; - let (no, no_len) = this.operand_to_simd(no)?; - let (dest, dest_len) = this.place_to_simd(dest)?; - - assert_eq!(dest_len, mask_len); - assert_eq!(dest_len, yes_len); - assert_eq!(dest_len, no_len); - - for i in 0..dest_len { - let mask = this.read_immediate(&this.mplace_index(&mask, i)?.into())?; - let yes = this.read_immediate(&this.mplace_index(&yes, i)?.into())?; - let no = this.read_immediate(&this.mplace_index(&no, i)?.into())?; - let dest = this.mplace_index(&dest, i)?; - - let val = if simd_element_to_bool(mask)? { yes } else { no }; - this.write_immediate(*val, &dest.into())?; - } - } - "simd_select_bitmask" => { - let [mask, yes, no] = check_arg_count(args)?; - let (yes, yes_len) = this.operand_to_simd(yes)?; - let (no, no_len) = this.operand_to_simd(no)?; - let (dest, dest_len) = this.place_to_simd(dest)?; - let bitmask_len = dest_len.max(8); - - assert!(mask.layout.ty.is_integral()); - assert!(bitmask_len <= 64); - assert_eq!(bitmask_len, mask.layout.size.bits()); - assert_eq!(dest_len, yes_len); - assert_eq!(dest_len, no_len); - - let mask: u64 = this - .read_scalar(mask)? - .check_init()? - .to_bits(mask.layout.size)? - .try_into() - .unwrap(); - for i in 0..dest_len { - let mask = - mask & (1 << simd_bitmask_index(i, dest_len, this.data_layout().endian)); - let yes = this.read_immediate(&this.mplace_index(&yes, i)?.into())?; - let no = this.read_immediate(&this.mplace_index(&no, i)?.into())?; - let dest = this.mplace_index(&dest, i)?; - - let val = if mask != 0 { yes } else { no }; - this.write_immediate(*val, &dest.into())?; - } - for i in dest_len..bitmask_len { - // If the mask is "padded", ensure that padding is all-zero. - let mask = mask & (1 << i); - if mask != 0 { - throw_ub_format!( - "a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits" - ); - } - } - } - #[rustfmt::skip] - "simd_cast" | "simd_as" => { - let [op] = check_arg_count(args)?; - let (op, op_len) = this.operand_to_simd(op)?; - let (dest, dest_len) = this.place_to_simd(dest)?; - - assert_eq!(dest_len, op_len); - - let safe_cast = intrinsic_name == "simd_as"; - - for i in 0..dest_len { - let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; - let dest = this.mplace_index(&dest, i)?; - - let val = match (op.layout.ty.kind(), dest.layout.ty.kind()) { - // Int-to-(int|float): always safe - (ty::Int(_) | ty::Uint(_), ty::Int(_) | ty::Uint(_) | ty::Float(_)) => - this.misc_cast(&op, dest.layout.ty)?, - // Float-to-float: always safe - (ty::Float(_), ty::Float(_)) => - this.misc_cast(&op, dest.layout.ty)?, - // Float-to-int in safe mode - (ty::Float(_), ty::Int(_) | ty::Uint(_)) if safe_cast => - this.misc_cast(&op, dest.layout.ty)?, - // Float-to-int in unchecked mode - (ty::Float(FloatTy::F32), ty::Int(_) | ty::Uint(_)) if !safe_cast => - this.float_to_int_unchecked(op.to_scalar()?.to_f32()?, dest.layout.ty)?.into(), - (ty::Float(FloatTy::F64), ty::Int(_) | ty::Uint(_)) if !safe_cast => - this.float_to_int_unchecked(op.to_scalar()?.to_f64()?, dest.layout.ty)?.into(), - _ => - throw_unsup_format!( - "Unsupported SIMD cast from element type {from_ty} to {to_ty}", - from_ty = op.layout.ty, - to_ty = dest.layout.ty, - ), - }; - this.write_immediate(val, &dest.into())?; - } - } - "simd_shuffle" => { - let [left, right, index] = check_arg_count(args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.place_to_simd(dest)?; - - // `index` is an array, not a SIMD type - let ty::Array(_, index_len) = index.layout.ty.kind() else { - span_bug!(this.cur_span(), "simd_shuffle index argument has non-array type {}", index.layout.ty) - }; - let index_len = index_len.eval_usize(*this.tcx, this.param_env()); - - assert_eq!(left_len, right_len); - assert_eq!(index_len, dest_len); - - for i in 0..dest_len { - let src_index: u64 = this - .read_immediate(&this.operand_index(index, i)?)? - .to_scalar()? - .to_u32()? - .into(); - let dest = this.mplace_index(&dest, i)?; - - let val = if src_index < left_len { - this.read_immediate(&this.mplace_index(&left, src_index)?.into())? - } else if src_index < left_len.checked_add(right_len).unwrap() { - this.read_immediate( - &this.mplace_index(&right, src_index - left_len)?.into(), - )? - } else { - span_bug!( - this.cur_span(), - "simd_shuffle index {src_index} is out of bounds for 2 vectors of size {left_len}", - ); - }; - this.write_immediate(*val, &dest.into())?; - } - } - "simd_gather" => { - let [passthru, ptrs, mask] = check_arg_count(args)?; - let (passthru, passthru_len) = this.operand_to_simd(passthru)?; - let (ptrs, ptrs_len) = this.operand_to_simd(ptrs)?; - let (mask, mask_len) = this.operand_to_simd(mask)?; - let (dest, dest_len) = this.place_to_simd(dest)?; - - assert_eq!(dest_len, passthru_len); - assert_eq!(dest_len, ptrs_len); - assert_eq!(dest_len, mask_len); - - for i in 0..dest_len { - let passthru = this.read_immediate(&this.mplace_index(&passthru, i)?.into())?; - let ptr = this.read_immediate(&this.mplace_index(&ptrs, i)?.into())?; - let mask = this.read_immediate(&this.mplace_index(&mask, i)?.into())?; - let dest = this.mplace_index(&dest, i)?; - - let val = if simd_element_to_bool(mask)? { - let place = this.deref_operand(&ptr.into())?; - this.read_immediate(&place.into())? - } else { - passthru - }; - this.write_immediate(*val, &dest.into())?; - } - } - "simd_scatter" => { - let [value, ptrs, mask] = check_arg_count(args)?; - let (value, value_len) = this.operand_to_simd(value)?; - let (ptrs, ptrs_len) = this.operand_to_simd(ptrs)?; - let (mask, mask_len) = this.operand_to_simd(mask)?; - - assert_eq!(ptrs_len, value_len); - assert_eq!(ptrs_len, mask_len); - - for i in 0..ptrs_len { - let value = this.read_immediate(&this.mplace_index(&value, i)?.into())?; - let ptr = this.read_immediate(&this.mplace_index(&ptrs, i)?.into())?; - let mask = this.read_immediate(&this.mplace_index(&mask, i)?.into())?; - - if simd_element_to_bool(mask)? { - let place = this.deref_operand(&ptr.into())?; - this.write_immediate(*value, &place.into())?; - } - } - } - "simd_bitmask" => { - let [op] = check_arg_count(args)?; - let (op, op_len) = this.operand_to_simd(op)?; - let bitmask_len = op_len.max(8); - - assert!(dest.layout.ty.is_integral()); - assert!(bitmask_len <= 64); - assert_eq!(bitmask_len, dest.layout.size.bits()); - - let mut res = 0u64; - for i in 0..op_len { - let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; - if simd_element_to_bool(op)? { - res |= 1 << simd_bitmask_index(i, op_len, this.data_layout().endian); - } - } - this.write_int(res, dest)?; - } - // Other "exact_div" => { let [num, denom] = check_arg_count(args)?; @@ -953,58 +423,3 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) } } - -fn fmax_op<'tcx>( - left: &ImmTy<'tcx, Tag>, - right: &ImmTy<'tcx, Tag>, -) -> InterpResult<'tcx, Scalar> { - assert_eq!(left.layout.ty, right.layout.ty); - let ty::Float(float_ty) = left.layout.ty.kind() else { - bug!("fmax operand is not a float") - }; - let left = left.to_scalar()?; - let right = right.to_scalar()?; - Ok(match float_ty { - FloatTy::F32 => Scalar::from_f32(left.to_f32()?.max(right.to_f32()?)), - FloatTy::F64 => Scalar::from_f64(left.to_f64()?.max(right.to_f64()?)), - }) -} - -fn fmin_op<'tcx>( - left: &ImmTy<'tcx, Tag>, - right: &ImmTy<'tcx, Tag>, -) -> InterpResult<'tcx, Scalar> { - assert_eq!(left.layout.ty, right.layout.ty); - let ty::Float(float_ty) = left.layout.ty.kind() else { - bug!("fmin operand is not a float") - }; - let left = left.to_scalar()?; - let right = right.to_scalar()?; - Ok(match float_ty { - FloatTy::F32 => Scalar::from_f32(left.to_f32()?.min(right.to_f32()?)), - FloatTy::F64 => Scalar::from_f64(left.to_f64()?.min(right.to_f64()?)), - }) -} - -fn bool_to_simd_element(b: bool, size: Size) -> Scalar { - // SIMD uses all-1 as pattern for "true" - let val = if b { -1 } else { 0 }; - Scalar::from_int(val, size) -} - -fn simd_element_to_bool(elem: ImmTy<'_, Tag>) -> InterpResult<'_, bool> { - let val = elem.to_scalar()?.to_int(elem.layout.size)?; - Ok(match val { - 0 => false, - -1 => true, - _ => throw_ub_format!("each element of a SIMD mask must be all-0-bits or all-1-bits"), - }) -} - -fn simd_bitmask_index(idx: u64, vec_len: u64, endianess: Endian) -> u64 { - assert!(idx < vec_len); - match endianess { - Endian::Little => idx, - Endian::Big => vec_len - 1 - idx, // reverse order of bits - } -} diff --git a/src/shims/intrinsics/simd.rs b/src/shims/intrinsics/simd.rs new file mode 100644 index 000000000000..fe5250ed0843 --- /dev/null +++ b/src/shims/intrinsics/simd.rs @@ -0,0 +1,613 @@ +use rustc_apfloat::Float; +use rustc_middle::ty::layout::{HasParamEnv, LayoutOf}; +use rustc_middle::{mir, ty, ty::FloatTy}; +use rustc_target::abi::{Endian, HasDataLayout, Size}; + +use crate::*; +use helpers::check_arg_count; + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + /// Calls the simd intrinsic `intrinsic`; the `simd_` prefix has already been removed. + fn emulate_simd_intrinsic( + &mut self, + intrinsic_name: &str, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + match intrinsic_name { + #[rustfmt::skip] + | "neg" + | "fabs" + | "ceil" + | "floor" + | "round" + | "trunc" + | "fsqrt" => { + let [op] = check_arg_count(args)?; + let (op, op_len) = this.operand_to_simd(op)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + assert_eq!(dest_len, op_len); + + #[derive(Copy, Clone)] + enum HostFloatOp { + Ceil, + Floor, + Round, + Trunc, + Sqrt, + } + #[derive(Copy, Clone)] + enum Op { + MirOp(mir::UnOp), + Abs, + HostOp(HostFloatOp), + } + let which = match intrinsic_name { + "neg" => Op::MirOp(mir::UnOp::Neg), + "fabs" => Op::Abs, + "ceil" => Op::HostOp(HostFloatOp::Ceil), + "floor" => Op::HostOp(HostFloatOp::Floor), + "round" => Op::HostOp(HostFloatOp::Round), + "trunc" => Op::HostOp(HostFloatOp::Trunc), + "fsqrt" => Op::HostOp(HostFloatOp::Sqrt), + _ => unreachable!(), + }; + + for i in 0..dest_len { + let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; + let dest = this.mplace_index(&dest, i)?; + let val = match which { + Op::MirOp(mir_op) => this.unary_op(mir_op, &op)?.to_scalar()?, + Op::Abs => { + // Works for f32 and f64. + let ty::Float(float_ty) = op.layout.ty.kind() else { + span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name) + }; + let op = op.to_scalar()?; + match float_ty { + FloatTy::F32 => Scalar::from_f32(op.to_f32()?.abs()), + FloatTy::F64 => Scalar::from_f64(op.to_f64()?.abs()), + } + } + Op::HostOp(host_op) => { + let ty::Float(float_ty) = op.layout.ty.kind() else { + span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name) + }; + // FIXME using host floats + match float_ty { + FloatTy::F32 => { + let f = f32::from_bits(op.to_scalar()?.to_u32()?); + let res = match host_op { + HostFloatOp::Ceil => f.ceil(), + HostFloatOp::Floor => f.floor(), + HostFloatOp::Round => f.round(), + HostFloatOp::Trunc => f.trunc(), + HostFloatOp::Sqrt => f.sqrt(), + }; + Scalar::from_u32(res.to_bits()) + } + FloatTy::F64 => { + let f = f64::from_bits(op.to_scalar()?.to_u64()?); + let res = match host_op { + HostFloatOp::Ceil => f.ceil(), + HostFloatOp::Floor => f.floor(), + HostFloatOp::Round => f.round(), + HostFloatOp::Trunc => f.trunc(), + HostFloatOp::Sqrt => f.sqrt(), + }; + Scalar::from_u64(res.to_bits()) + } + } + + } + }; + this.write_scalar(val, &dest.into())?; + } + } + #[rustfmt::skip] + | "add" + | "sub" + | "mul" + | "div" + | "rem" + | "shl" + | "shr" + | "and" + | "or" + | "xor" + | "eq" + | "ne" + | "lt" + | "le" + | "gt" + | "ge" + | "fmax" + | "fmin" + | "saturating_add" + | "saturating_sub" + | "arith_offset" => { + use mir::BinOp; + + let [left, right] = check_arg_count(args)?; + let (left, left_len) = this.operand_to_simd(left)?; + let (right, right_len) = this.operand_to_simd(right)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + assert_eq!(dest_len, left_len); + assert_eq!(dest_len, right_len); + + enum Op { + MirOp(BinOp), + SaturatingOp(BinOp), + FMax, + FMin, + WrappingOffset, + } + let which = match intrinsic_name { + "add" => Op::MirOp(BinOp::Add), + "sub" => Op::MirOp(BinOp::Sub), + "mul" => Op::MirOp(BinOp::Mul), + "div" => Op::MirOp(BinOp::Div), + "rem" => Op::MirOp(BinOp::Rem), + "shl" => Op::MirOp(BinOp::Shl), + "shr" => Op::MirOp(BinOp::Shr), + "and" => Op::MirOp(BinOp::BitAnd), + "or" => Op::MirOp(BinOp::BitOr), + "xor" => Op::MirOp(BinOp::BitXor), + "eq" => Op::MirOp(BinOp::Eq), + "ne" => Op::MirOp(BinOp::Ne), + "lt" => Op::MirOp(BinOp::Lt), + "le" => Op::MirOp(BinOp::Le), + "gt" => Op::MirOp(BinOp::Gt), + "ge" => Op::MirOp(BinOp::Ge), + "fmax" => Op::FMax, + "fmin" => Op::FMin, + "saturating_add" => Op::SaturatingOp(BinOp::Add), + "saturating_sub" => Op::SaturatingOp(BinOp::Sub), + "arith_offset" => Op::WrappingOffset, + _ => unreachable!(), + }; + + for i in 0..dest_len { + let left = this.read_immediate(&this.mplace_index(&left, i)?.into())?; + let right = this.read_immediate(&this.mplace_index(&right, i)?.into())?; + let dest = this.mplace_index(&dest, i)?; + let val = match which { + Op::MirOp(mir_op) => { + let (val, overflowed, ty) = this.overflowing_binary_op(mir_op, &left, &right)?; + if matches!(mir_op, BinOp::Shl | BinOp::Shr) { + // Shifts have extra UB as SIMD operations that the MIR binop does not have. + // See . + if overflowed { + let r_val = right.to_scalar()?.to_bits(right.layout.size)?; + throw_ub_format!("overflowing shift by {r_val} in `simd_{intrinsic_name}` in SIMD lane {i}"); + } + } + if matches!(mir_op, BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge) { + // Special handling for boolean-returning operations + assert_eq!(ty, this.tcx.types.bool); + let val = val.to_bool().unwrap(); + bool_to_simd_element(val, dest.layout.size) + } else { + assert_ne!(ty, this.tcx.types.bool); + assert_eq!(ty, dest.layout.ty); + val + } + } + Op::SaturatingOp(mir_op) => { + this.saturating_arith(mir_op, &left, &right)? + } + Op::WrappingOffset => { + let ptr = this.scalar_to_ptr(left.to_scalar()?)?; + let offset_count = right.to_scalar()?.to_machine_isize(this)?; + let pointee_ty = left.layout.ty.builtin_deref(true).unwrap().ty; + + let pointee_size = i64::try_from(this.layout_of(pointee_ty)?.size.bytes()).unwrap(); + let offset_bytes = offset_count.wrapping_mul(pointee_size); + let offset_ptr = ptr.wrapping_signed_offset(offset_bytes, this); + Scalar::from_maybe_pointer(offset_ptr, this) + } + Op::FMax => { + fmax_op(&left, &right)? + } + Op::FMin => { + fmin_op(&left, &right)? + } + }; + this.write_scalar(val, &dest.into())?; + } + } + "fma" => { + let [a, b, c] = check_arg_count(args)?; + let (a, a_len) = this.operand_to_simd(a)?; + let (b, b_len) = this.operand_to_simd(b)?; + let (c, c_len) = this.operand_to_simd(c)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + assert_eq!(dest_len, a_len); + assert_eq!(dest_len, b_len); + assert_eq!(dest_len, c_len); + + for i in 0..dest_len { + let a = this.read_immediate(&this.mplace_index(&a, i)?.into())?.to_scalar()?; + let b = this.read_immediate(&this.mplace_index(&b, i)?.into())?.to_scalar()?; + let c = this.read_immediate(&this.mplace_index(&c, i)?.into())?.to_scalar()?; + let dest = this.mplace_index(&dest, i)?; + + // Works for f32 and f64. + let ty::Float(float_ty) = dest.layout.ty.kind() else { + span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name) + }; + let val = match float_ty { + FloatTy::F32 => + Scalar::from_f32(a.to_f32()?.mul_add(b.to_f32()?, c.to_f32()?).value), + FloatTy::F64 => + Scalar::from_f64(a.to_f64()?.mul_add(b.to_f64()?, c.to_f64()?).value), + }; + this.write_scalar(val, &dest.into())?; + } + } + #[rustfmt::skip] + | "reduce_and" + | "reduce_or" + | "reduce_xor" + | "reduce_any" + | "reduce_all" + | "reduce_max" + | "reduce_min" => { + use mir::BinOp; + + let [op] = check_arg_count(args)?; + let (op, op_len) = this.operand_to_simd(op)?; + + let imm_from_bool = + |b| ImmTy::from_scalar(Scalar::from_bool(b), this.machine.layouts.bool); + + enum Op { + MirOp(BinOp), + MirOpBool(BinOp), + Max, + Min, + } + let which = match intrinsic_name { + "reduce_and" => Op::MirOp(BinOp::BitAnd), + "reduce_or" => Op::MirOp(BinOp::BitOr), + "reduce_xor" => Op::MirOp(BinOp::BitXor), + "reduce_any" => Op::MirOpBool(BinOp::BitOr), + "reduce_all" => Op::MirOpBool(BinOp::BitAnd), + "reduce_max" => Op::Max, + "reduce_min" => Op::Min, + _ => unreachable!(), + }; + + // Initialize with first lane, then proceed with the rest. + let mut res = this.read_immediate(&this.mplace_index(&op, 0)?.into())?; + if matches!(which, Op::MirOpBool(_)) { + // Convert to `bool` scalar. + res = imm_from_bool(simd_element_to_bool(res)?); + } + for i in 1..op_len { + let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; + res = match which { + Op::MirOp(mir_op) => { + this.binary_op(mir_op, &res, &op)? + } + Op::MirOpBool(mir_op) => { + let op = imm_from_bool(simd_element_to_bool(op)?); + this.binary_op(mir_op, &res, &op)? + } + Op::Max => { + if matches!(res.layout.ty.kind(), ty::Float(_)) { + ImmTy::from_scalar(fmax_op(&res, &op)?, res.layout) + } else { + // Just boring integers, so NaNs to worry about + if this.binary_op(BinOp::Ge, &res, &op)?.to_scalar()?.to_bool()? { + res + } else { + op + } + } + } + Op::Min => { + if matches!(res.layout.ty.kind(), ty::Float(_)) { + ImmTy::from_scalar(fmin_op(&res, &op)?, res.layout) + } else { + // Just boring integers, so NaNs to worry about + if this.binary_op(BinOp::Le, &res, &op)?.to_scalar()?.to_bool()? { + res + } else { + op + } + } + } + }; + } + this.write_immediate(*res, dest)?; + } + #[rustfmt::skip] + | "reduce_add_ordered" + | "reduce_mul_ordered" => { + use mir::BinOp; + + let [op, init] = check_arg_count(args)?; + let (op, op_len) = this.operand_to_simd(op)?; + let init = this.read_immediate(init)?; + + let mir_op = match intrinsic_name { + "reduce_add_ordered" => BinOp::Add, + "reduce_mul_ordered" => BinOp::Mul, + _ => unreachable!(), + }; + + let mut res = init; + for i in 0..op_len { + let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; + res = this.binary_op(mir_op, &res, &op)?; + } + this.write_immediate(*res, dest)?; + } + "select" => { + let [mask, yes, no] = check_arg_count(args)?; + let (mask, mask_len) = this.operand_to_simd(mask)?; + let (yes, yes_len) = this.operand_to_simd(yes)?; + let (no, no_len) = this.operand_to_simd(no)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + assert_eq!(dest_len, mask_len); + assert_eq!(dest_len, yes_len); + assert_eq!(dest_len, no_len); + + for i in 0..dest_len { + let mask = this.read_immediate(&this.mplace_index(&mask, i)?.into())?; + let yes = this.read_immediate(&this.mplace_index(&yes, i)?.into())?; + let no = this.read_immediate(&this.mplace_index(&no, i)?.into())?; + let dest = this.mplace_index(&dest, i)?; + + let val = if simd_element_to_bool(mask)? { yes } else { no }; + this.write_immediate(*val, &dest.into())?; + } + } + "select_bitmask" => { + let [mask, yes, no] = check_arg_count(args)?; + let (yes, yes_len) = this.operand_to_simd(yes)?; + let (no, no_len) = this.operand_to_simd(no)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + let bitmask_len = dest_len.max(8); + + assert!(mask.layout.ty.is_integral()); + assert!(bitmask_len <= 64); + assert_eq!(bitmask_len, mask.layout.size.bits()); + assert_eq!(dest_len, yes_len); + assert_eq!(dest_len, no_len); + + let mask: u64 = this + .read_scalar(mask)? + .check_init()? + .to_bits(mask.layout.size)? + .try_into() + .unwrap(); + for i in 0..dest_len { + let mask = + mask & (1 << simd_bitmask_index(i, dest_len, this.data_layout().endian)); + let yes = this.read_immediate(&this.mplace_index(&yes, i)?.into())?; + let no = this.read_immediate(&this.mplace_index(&no, i)?.into())?; + let dest = this.mplace_index(&dest, i)?; + + let val = if mask != 0 { yes } else { no }; + this.write_immediate(*val, &dest.into())?; + } + for i in dest_len..bitmask_len { + // If the mask is "padded", ensure that padding is all-zero. + let mask = mask & (1 << i); + if mask != 0 { + throw_ub_format!( + "a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits" + ); + } + } + } + #[rustfmt::skip] + "cast" | "as" => { + let [op] = check_arg_count(args)?; + let (op, op_len) = this.operand_to_simd(op)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + assert_eq!(dest_len, op_len); + + let safe_cast = intrinsic_name == "as"; + + for i in 0..dest_len { + let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; + let dest = this.mplace_index(&dest, i)?; + + let val = match (op.layout.ty.kind(), dest.layout.ty.kind()) { + // Int-to-(int|float): always safe + (ty::Int(_) | ty::Uint(_), ty::Int(_) | ty::Uint(_) | ty::Float(_)) => + this.misc_cast(&op, dest.layout.ty)?, + // Float-to-float: always safe + (ty::Float(_), ty::Float(_)) => + this.misc_cast(&op, dest.layout.ty)?, + // Float-to-int in safe mode + (ty::Float(_), ty::Int(_) | ty::Uint(_)) if safe_cast => + this.misc_cast(&op, dest.layout.ty)?, + // Float-to-int in unchecked mode + (ty::Float(FloatTy::F32), ty::Int(_) | ty::Uint(_)) if !safe_cast => + this.float_to_int_unchecked(op.to_scalar()?.to_f32()?, dest.layout.ty)?.into(), + (ty::Float(FloatTy::F64), ty::Int(_) | ty::Uint(_)) if !safe_cast => + this.float_to_int_unchecked(op.to_scalar()?.to_f64()?, dest.layout.ty)?.into(), + _ => + throw_unsup_format!( + "Unsupported SIMD cast from element type {from_ty} to {to_ty}", + from_ty = op.layout.ty, + to_ty = dest.layout.ty, + ), + }; + this.write_immediate(val, &dest.into())?; + } + } + "shuffle" => { + let [left, right, index] = check_arg_count(args)?; + let (left, left_len) = this.operand_to_simd(left)?; + let (right, right_len) = this.operand_to_simd(right)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + // `index` is an array, not a SIMD type + let ty::Array(_, index_len) = index.layout.ty.kind() else { + span_bug!(this.cur_span(), "simd_shuffle index argument has non-array type {}", index.layout.ty) + }; + let index_len = index_len.eval_usize(*this.tcx, this.param_env()); + + assert_eq!(left_len, right_len); + assert_eq!(index_len, dest_len); + + for i in 0..dest_len { + let src_index: u64 = this + .read_immediate(&this.operand_index(index, i)?)? + .to_scalar()? + .to_u32()? + .into(); + let dest = this.mplace_index(&dest, i)?; + + let val = if src_index < left_len { + this.read_immediate(&this.mplace_index(&left, src_index)?.into())? + } else if src_index < left_len.checked_add(right_len).unwrap() { + this.read_immediate( + &this.mplace_index(&right, src_index - left_len)?.into(), + )? + } else { + span_bug!( + this.cur_span(), + "simd_shuffle index {src_index} is out of bounds for 2 vectors of size {left_len}", + ); + }; + this.write_immediate(*val, &dest.into())?; + } + } + "gather" => { + let [passthru, ptrs, mask] = check_arg_count(args)?; + let (passthru, passthru_len) = this.operand_to_simd(passthru)?; + let (ptrs, ptrs_len) = this.operand_to_simd(ptrs)?; + let (mask, mask_len) = this.operand_to_simd(mask)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + assert_eq!(dest_len, passthru_len); + assert_eq!(dest_len, ptrs_len); + assert_eq!(dest_len, mask_len); + + for i in 0..dest_len { + let passthru = this.read_immediate(&this.mplace_index(&passthru, i)?.into())?; + let ptr = this.read_immediate(&this.mplace_index(&ptrs, i)?.into())?; + let mask = this.read_immediate(&this.mplace_index(&mask, i)?.into())?; + let dest = this.mplace_index(&dest, i)?; + + let val = if simd_element_to_bool(mask)? { + let place = this.deref_operand(&ptr.into())?; + this.read_immediate(&place.into())? + } else { + passthru + }; + this.write_immediate(*val, &dest.into())?; + } + } + "scatter" => { + let [value, ptrs, mask] = check_arg_count(args)?; + let (value, value_len) = this.operand_to_simd(value)?; + let (ptrs, ptrs_len) = this.operand_to_simd(ptrs)?; + let (mask, mask_len) = this.operand_to_simd(mask)?; + + assert_eq!(ptrs_len, value_len); + assert_eq!(ptrs_len, mask_len); + + for i in 0..ptrs_len { + let value = this.read_immediate(&this.mplace_index(&value, i)?.into())?; + let ptr = this.read_immediate(&this.mplace_index(&ptrs, i)?.into())?; + let mask = this.read_immediate(&this.mplace_index(&mask, i)?.into())?; + + if simd_element_to_bool(mask)? { + let place = this.deref_operand(&ptr.into())?; + this.write_immediate(*value, &place.into())?; + } + } + } + "bitmask" => { + let [op] = check_arg_count(args)?; + let (op, op_len) = this.operand_to_simd(op)?; + let bitmask_len = op_len.max(8); + + assert!(dest.layout.ty.is_integral()); + assert!(bitmask_len <= 64); + assert_eq!(bitmask_len, dest.layout.size.bits()); + + let mut res = 0u64; + for i in 0..op_len { + let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; + if simd_element_to_bool(op)? { + res |= 1 << simd_bitmask_index(i, op_len, this.data_layout().endian); + } + } + this.write_int(res, dest)?; + } + + name => throw_unsup_format!("unimplemented intrinsic: `simd_{name}`"), + } + Ok(()) + } +} + +fn bool_to_simd_element(b: bool, size: Size) -> Scalar { + // SIMD uses all-1 as pattern for "true" + let val = if b { -1 } else { 0 }; + Scalar::from_int(val, size) +} + +fn simd_element_to_bool(elem: ImmTy<'_, Tag>) -> InterpResult<'_, bool> { + let val = elem.to_scalar()?.to_int(elem.layout.size)?; + Ok(match val { + 0 => false, + -1 => true, + _ => throw_ub_format!("each element of a SIMD mask must be all-0-bits or all-1-bits"), + }) +} + +fn simd_bitmask_index(idx: u64, vec_len: u64, endianess: Endian) -> u64 { + assert!(idx < vec_len); + match endianess { + Endian::Little => idx, + Endian::Big => vec_len - 1 - idx, // reverse order of bits + } +} + +fn fmax_op<'tcx>( + left: &ImmTy<'tcx, Tag>, + right: &ImmTy<'tcx, Tag>, +) -> InterpResult<'tcx, Scalar> { + assert_eq!(left.layout.ty, right.layout.ty); + let ty::Float(float_ty) = left.layout.ty.kind() else { + bug!("fmax operand is not a float") + }; + let left = left.to_scalar()?; + let right = right.to_scalar()?; + Ok(match float_ty { + FloatTy::F32 => Scalar::from_f32(left.to_f32()?.max(right.to_f32()?)), + FloatTy::F64 => Scalar::from_f64(left.to_f64()?.max(right.to_f64()?)), + }) +} + +fn fmin_op<'tcx>( + left: &ImmTy<'tcx, Tag>, + right: &ImmTy<'tcx, Tag>, +) -> InterpResult<'tcx, Scalar> { + assert_eq!(left.layout.ty, right.layout.ty); + let ty::Float(float_ty) = left.layout.ty.kind() else { + bug!("fmin operand is not a float") + }; + let left = left.to_scalar()?; + let right = right.to_scalar()?; + Ok(match float_ty { + FloatTy::F32 => Scalar::from_f32(left.to_f32()?.min(right.to_f32()?)), + FloatTy::F64 => Scalar::from_f64(left.to_f64()?.min(right.to_f64()?)), + }) +} From 1174cda4f1d3aff6d2a34e7300d5ea12769de0f5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Jul 2022 08:05:46 -0400 Subject: [PATCH 3538/5092] remove ret param from foreign_item hierarchy --- src/shims/foreign_items.rs | 9 ++++----- src/shims/unix/foreign_items.rs | 8 +++----- src/shims/unix/freebsd/foreign_items.rs | 2 -- src/shims/unix/linux/foreign_items.rs | 2 -- src/shims/unix/macos/foreign_items.rs | 2 -- src/shims/windows/foreign_items.rs | 2 -- 6 files changed, 7 insertions(+), 18 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index cd4fedad0fba..8d82c912f380 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -297,8 +297,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(p) => p, }; - // Second: functions that return. - match this.emulate_foreign_item_by_name(link_name, abi, args, dest, ret)? { + // Second: functions that return immediately. + match this.emulate_foreign_item_by_name(link_name, abi, args, dest)? { EmulateByNameResult::NeedsJumping => { trace!("{:?}", this.dump_place(**dest)); this.go_to_block(ret); @@ -355,7 +355,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - ret: mir::BasicBlock, ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); @@ -702,8 +701,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Platform-specific shims _ => match this.tcx.sess.target.os.as_ref() { - target if target_os_is_unix(target) => return shims::unix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), - "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), + target if target_os_is_unix(target) => return shims::unix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest), + "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest), target => throw_unsup_format!("the target `{}` is not supported", target), } }; diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 57dfd6f1810c..cf34b4baec7f 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -2,7 +2,6 @@ use std::ffi::OsStr; use log::trace; -use rustc_middle::mir; use rustc_middle::ty::layout::LayoutOf; use rustc_span::Symbol; use rustc_target::abi::{Align, Size}; @@ -22,7 +21,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - ret: mir::BasicBlock, ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); @@ -533,9 +531,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Platform-specific shims _ => { match this.tcx.sess.target.os.as_ref() { - "linux" => return shims::unix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), - "macos" => return shims::unix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), - "freebsd" => return shims::unix::freebsd::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), + "linux" => return shims::unix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest), + "macos" => return shims::unix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest), + "freebsd" => return shims::unix::freebsd::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest), _ => unreachable!(), } } diff --git a/src/shims/unix/freebsd/foreign_items.rs b/src/shims/unix/freebsd/foreign_items.rs index 66e339cc4a82..2350e5a12c11 100644 --- a/src/shims/unix/freebsd/foreign_items.rs +++ b/src/shims/unix/freebsd/foreign_items.rs @@ -1,4 +1,3 @@ -use rustc_middle::mir; use rustc_span::Symbol; use rustc_target::spec::abi::Abi; @@ -14,7 +13,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - _ret: mir::BasicBlock, ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); match link_name.as_str() { diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index bbdb1b8a31c4..efd4e2a8c03d 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -1,4 +1,3 @@ -use rustc_middle::mir; use rustc_span::Symbol; use rustc_target::spec::abi::Abi; @@ -17,7 +16,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - _ret: mir::BasicBlock, ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); diff --git a/src/shims/unix/macos/foreign_items.rs b/src/shims/unix/macos/foreign_items.rs index 089a082fa369..58dd40cda301 100644 --- a/src/shims/unix/macos/foreign_items.rs +++ b/src/shims/unix/macos/foreign_items.rs @@ -1,4 +1,3 @@ -use rustc_middle::mir; use rustc_span::Symbol; use rustc_target::spec::abi::Abi; @@ -15,7 +14,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - _ret: mir::BasicBlock, ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 28e60a68048c..65634342417b 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -1,6 +1,5 @@ use std::iter; -use rustc_middle::mir; use rustc_span::Symbol; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; @@ -18,7 +17,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - _ret: mir::BasicBlock, ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); From c850ffe01a4d3d8eef74f2c5220a65ec8d167b72 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Jul 2022 08:20:06 -0400 Subject: [PATCH 3539/5092] add support for new RMW orders --- src/shims/intrinsics/atomic.rs | 112 ++++++++++++++++++++++----------- tests/pass/atomic.rs | 45 ++++++------- 2 files changed, 93 insertions(+), 64 deletions(-) diff --git a/src/shims/intrinsics/atomic.rs b/src/shims/intrinsics/atomic.rs index e51fd98c5522..d446eff537f3 100644 --- a/src/shims/intrinsics/atomic.rs +++ b/src/shims/intrinsics/atomic.rs @@ -49,57 +49,93 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "cxchg_seqcst_seqcst" => this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::SeqCst)?, #[rustfmt::skip] - "cxchg_acquire_acquire" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "cxchg_release_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "cxchg_acqrel_acquire" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "cxchg_relaxed_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "cxchg_acquire_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "cxchg_acqrel_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Relaxed)?, + "cxchg_seqcst_acquire" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Acquire)?, #[rustfmt::skip] "cxchg_seqcst_relaxed" => this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Relaxed)?, #[rustfmt::skip] - "cxchg_seqcst_acquire" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Acquire)?, + "cxchg_acqrel_seqcst" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::SeqCst)?, + #[rustfmt::skip] + "cxchg_acqrel_acquire" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Acquire)?, + #[rustfmt::skip] + "cxchg_acqrel_relaxed" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchg_acquire_seqcst" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::SeqCst)?, + #[rustfmt::skip] + "cxchg_acquire_acquire" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Acquire)?, + #[rustfmt::skip] + "cxchg_acquire_relaxed" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchg_release_seqcst" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Release, AtomicReadOrd::SeqCst)?, + #[rustfmt::skip] + "cxchg_release_acquire" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Acquire)?, + #[rustfmt::skip] + "cxchg_release_relaxed" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchg_relaxed_seqcst" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::SeqCst)?, + #[rustfmt::skip] + "cxchg_relaxed_acquire" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Acquire)?, + #[rustfmt::skip] + "cxchg_relaxed_relaxed" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Relaxed)?, #[rustfmt::skip] "cxchgweak_seqcst_seqcst" => this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::SeqCst)?, #[rustfmt::skip] - "cxchgweak_acquire_acquire" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "cxchgweak_release_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "cxchgweak_acqrel_acquire" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "cxchgweak_relaxed_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "cxchgweak_acquire_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "cxchgweak_acqrel_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Relaxed)?, + "cxchgweak_seqcst_acquire" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Acquire)?, #[rustfmt::skip] "cxchgweak_seqcst_relaxed" => this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Relaxed)?, #[rustfmt::skip] - "cxchgweak_seqcst_acquire" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Acquire)?, + "cxchgweak_acqrel_seqcst" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::SeqCst)?, + #[rustfmt::skip] + "cxchgweak_acqrel_acquire" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Acquire)?, + #[rustfmt::skip] + "cxchgweak_acqrel_relaxed" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchgweak_acquire_seqcst" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::SeqCst)?, + #[rustfmt::skip] + "cxchgweak_acquire_acquire" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Acquire)?, + #[rustfmt::skip] + "cxchgweak_acquire_relaxed" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchgweak_release_seqcst" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Release, AtomicReadOrd::SeqCst)?, + #[rustfmt::skip] + "cxchgweak_release_acquire" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Acquire)?, + #[rustfmt::skip] + "cxchgweak_release_relaxed" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchgweak_relaxed_seqcst" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::SeqCst)?, + #[rustfmt::skip] + "cxchgweak_relaxed_acquire" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Acquire)?, + #[rustfmt::skip] + "cxchgweak_relaxed_relaxed" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Relaxed)?, #[rustfmt::skip] "or_seqcst" => diff --git a/tests/pass/atomic.rs b/tests/pass/atomic.rs index 9b82e006fa16..e3d80a78916f 100644 --- a/tests/pass/atomic.rs +++ b/tests/pass/atomic.rs @@ -51,18 +51,22 @@ fn atomic_all_ops() { static ATOMIC: AtomicIsize = AtomicIsize::new(0); static ATOMIC_UNSIGNED: AtomicU64 = AtomicU64::new(0); + let load_orders = [Relaxed, Acquire, SeqCst]; + let stored_orders = [Relaxed, Release, SeqCst]; + let rmw_orders = [Relaxed, Release, Acquire, AcqRel, SeqCst]; + // loads - for o in [Relaxed, Acquire, SeqCst] { + for o in load_orders { ATOMIC.load(o); } // stores - for o in [Relaxed, Release, SeqCst] { + for o in stored_orders { ATOMIC.store(1, o); } // most RMWs - for o in [Relaxed, Release, Acquire, AcqRel, SeqCst] { + for o in rmw_orders { ATOMIC.swap(0, o); ATOMIC.fetch_or(0, o); ATOMIC.fetch_xor(0, o); @@ -76,29 +80,13 @@ fn atomic_all_ops() { ATOMIC_UNSIGNED.fetch_max(0, o); } - // RMWs with deparate failure ordering - ATOMIC.store(0, SeqCst); - assert_eq!(ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed), Ok(0)); - assert_eq!(ATOMIC.compare_exchange(0, 2, Acquire, Relaxed), Err(1)); - assert_eq!(ATOMIC.compare_exchange(0, 1, Release, Relaxed), Err(1)); - assert_eq!(ATOMIC.compare_exchange(1, 0, AcqRel, Relaxed), Ok(1)); - ATOMIC.compare_exchange(0, 1, SeqCst, Relaxed).ok(); - ATOMIC.compare_exchange(0, 1, Acquire, Acquire).ok(); - ATOMIC.compare_exchange(0, 1, AcqRel, Acquire).ok(); - ATOMIC.compare_exchange(0, 1, SeqCst, Acquire).ok(); - ATOMIC.compare_exchange(0, 1, SeqCst, SeqCst).ok(); - - ATOMIC.store(0, SeqCst); - compare_exchange_weak_loop!(ATOMIC, 0, 1, Relaxed, Relaxed); - assert_eq!(ATOMIC.compare_exchange_weak(0, 2, Acquire, Relaxed), Err(1)); - assert_eq!(ATOMIC.compare_exchange_weak(0, 1, Release, Relaxed), Err(1)); - compare_exchange_weak_loop!(ATOMIC, 1, 0, AcqRel, Relaxed); - assert_eq!(ATOMIC.load(Relaxed), 0); - ATOMIC.compare_exchange_weak(0, 1, SeqCst, Relaxed).ok(); - ATOMIC.compare_exchange_weak(0, 1, Acquire, Acquire).ok(); - ATOMIC.compare_exchange_weak(0, 1, AcqRel, Acquire).ok(); - ATOMIC.compare_exchange_weak(0, 1, SeqCst, Acquire).ok(); - ATOMIC.compare_exchange_weak(0, 1, SeqCst, SeqCst).ok(); + // RMWs with separate failure ordering + for o1 in rmw_orders { + for o2 in load_orders { + let _res = ATOMIC.compare_exchange(0, 0, o1, o2); + let _res = ATOMIC.compare_exchange_weak(0, 0, o1, o2); + } + } } fn atomic_u64() { @@ -106,7 +94,12 @@ fn atomic_u64() { ATOMIC.store(1, SeqCst); assert_eq!(ATOMIC.compare_exchange(0, 0x100, AcqRel, Acquire), Err(1)); + assert_eq!(ATOMIC.compare_exchange(0, 1, Release, Relaxed), Err(1)); + assert_eq!(ATOMIC.compare_exchange(1, 0, AcqRel, Relaxed), Ok(1)); + assert_eq!(ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed), Ok(0)); compare_exchange_weak_loop!(ATOMIC, 1, 0x100, AcqRel, Acquire); + assert_eq!(ATOMIC.compare_exchange_weak(0, 2, Acquire, Relaxed), Err(0x100)); + assert_eq!(ATOMIC.compare_exchange_weak(0, 1, Release, Relaxed), Err(0x100)); assert_eq!(ATOMIC.load(Relaxed), 0x100); assert_eq!(ATOMIC.fetch_max(0x10, SeqCst), 0x100); From ad3010c449572d86bb668ed1dc53bac5df041374 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Jul 2022 08:22:27 -0400 Subject: [PATCH 3540/5092] make atomic intrinsic impl details private --- src/lib.rs | 1 - src/shims/intrinsics/mod.rs | 3 ++- src/shims/unix/linux/sync.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 80281d37de9a..b3d408a6dc07 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,7 +62,6 @@ pub use rustc_const_eval::interpret::{self, AllocMap, PlaceTy}; pub use crate::shims::dlsym::{Dlsym, EvalContextExt as _}; pub use crate::shims::env::{EnvVars, EvalContextExt as _}; pub use crate::shims::foreign_items::EvalContextExt as _; -pub use crate::shims::intrinsics::atomic::EvalContextExt as _; pub use crate::shims::intrinsics::EvalContextExt as _; pub use crate::shims::os_str::EvalContextExt as _; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _}; diff --git a/src/shims/intrinsics/mod.rs b/src/shims/intrinsics/mod.rs index a8b8b807bd82..9ffa40f33353 100644 --- a/src/shims/intrinsics/mod.rs +++ b/src/shims/intrinsics/mod.rs @@ -1,4 +1,4 @@ -pub mod atomic; +mod atomic; mod simd; use std::iter; @@ -11,6 +11,7 @@ use rustc_middle::{mir, ty, ty::FloatTy}; use rustc_target::abi::Integer; use crate::*; +use atomic::EvalContextExt as _; use helpers::check_arg_count; use simd::EvalContextExt as _; diff --git a/src/shims/unix/linux/sync.rs b/src/shims/unix/linux/sync.rs index a0e35c730c3d..a81fdb5e9988 100644 --- a/src/shims/unix/linux/sync.rs +++ b/src/shims/unix/linux/sync.rs @@ -169,7 +169,7 @@ pub fn futex<'tcx>( // // Thankfully, preemptions cannot happen inside a Miri shim, so we do not need to // do anything special to guarantee fence-load-comparison atomicity. - this.atomic_fence(&[], AtomicFenceOrd::SeqCst)?; + this.validate_atomic_fence(AtomicFenceOrd::SeqCst)?; // Read an `i32` through the pointer, regardless of any wrapper types. // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`. let futex_val = this @@ -240,7 +240,7 @@ pub fn futex<'tcx>( // Together with the SeqCst fence in futex_wait, this makes sure that futex_wait // will see the latest value on addr which could be changed by our caller // before doing the syscall. - this.atomic_fence(&[], AtomicFenceOrd::SeqCst)?; + this.validate_atomic_fence(AtomicFenceOrd::SeqCst)?; let mut n = 0; for _ in 0..val { if let Some(thread) = this.futex_wake(addr_usize, bitset) { From 6ab64620a60f958883ef9dfee8515a776001b85d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Jul 2022 08:55:50 -0400 Subject: [PATCH 3541/5092] refactor atomic intrinsic handling to actually parse the intrinsic name --- src/shims/intrinsics/atomic.rs | 314 ++++++++++----------------------- 1 file changed, 91 insertions(+), 223 deletions(-) diff --git a/src/shims/intrinsics/atomic.rs b/src/shims/intrinsics/atomic.rs index d446eff537f3..78e13a498ce1 100644 --- a/src/shims/intrinsics/atomic.rs +++ b/src/shims/intrinsics/atomic.rs @@ -1,10 +1,12 @@ -use rustc_middle::{mir, mir::BinOp}; +use rustc_middle::{mir, mir::BinOp, ty}; use rustc_target::abi::Align; use crate::*; use helpers::check_arg_count; pub enum AtomicOp { + /// The `bool` indicates whether the result of the operation should be negated + /// (must be a boolean-typed operation). MirOp(mir::BinOp, bool), Max, Min, @@ -20,236 +22,99 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - match intrinsic_name { - "load_seqcst" => this.atomic_load(args, dest, AtomicReadOrd::SeqCst)?, - "load_relaxed" => this.atomic_load(args, dest, AtomicReadOrd::Relaxed)?, - "load_acquire" => this.atomic_load(args, dest, AtomicReadOrd::Acquire)?, - "store_seqcst" => this.atomic_store(args, AtomicWriteOrd::SeqCst)?, - "store_relaxed" => this.atomic_store(args, AtomicWriteOrd::Relaxed)?, - "store_release" => this.atomic_store(args, AtomicWriteOrd::Release)?, + let intrinsic_structure: Vec<_> = intrinsic_name.split('_').collect(); - "fence_acquire" => this.atomic_fence(args, AtomicFenceOrd::Acquire)?, - "fence_release" => this.atomic_fence(args, AtomicFenceOrd::Release)?, - "fence_acqrel" => this.atomic_fence(args, AtomicFenceOrd::AcqRel)?, - "fence_seqcst" => this.atomic_fence(args, AtomicFenceOrd::SeqCst)?, + fn read_ord<'tcx>(ord: &str) -> InterpResult<'tcx, AtomicReadOrd> { + Ok(match ord { + "seqcst" => AtomicReadOrd::SeqCst, + "acquire" => AtomicReadOrd::Acquire, + "relaxed" => AtomicReadOrd::Relaxed, + _ => throw_unsup_format!("unsupported read ordering `{ord}`"), + }) + } - "singlethreadfence_acquire" => this.compiler_fence(args, AtomicFenceOrd::Acquire)?, - "singlethreadfence_release" => this.compiler_fence(args, AtomicFenceOrd::Release)?, - "singlethreadfence_acqrel" => this.compiler_fence(args, AtomicFenceOrd::AcqRel)?, - "singlethreadfence_seqcst" => this.compiler_fence(args, AtomicFenceOrd::SeqCst)?, + fn write_ord<'tcx>(ord: &str) -> InterpResult<'tcx, AtomicWriteOrd> { + Ok(match ord { + "seqcst" => AtomicWriteOrd::SeqCst, + "release" => AtomicWriteOrd::Release, + "relaxed" => AtomicWriteOrd::Relaxed, + _ => throw_unsup_format!("unsupported write ordering `{ord}`"), + }) + } - "xchg_seqcst" => this.atomic_exchange(args, dest, AtomicRwOrd::SeqCst)?, - "xchg_acquire" => this.atomic_exchange(args, dest, AtomicRwOrd::Acquire)?, - "xchg_release" => this.atomic_exchange(args, dest, AtomicRwOrd::Release)?, - "xchg_acqrel" => this.atomic_exchange(args, dest, AtomicRwOrd::AcqRel)?, - "xchg_relaxed" => this.atomic_exchange(args, dest, AtomicRwOrd::Relaxed)?, + fn rw_ord<'tcx>(ord: &str) -> InterpResult<'tcx, AtomicRwOrd> { + Ok(match ord { + "seqcst" => AtomicRwOrd::SeqCst, + "acqrel" => AtomicRwOrd::AcqRel, + "acquire" => AtomicRwOrd::Acquire, + "release" => AtomicRwOrd::Release, + "relaxed" => AtomicRwOrd::Relaxed, + _ => throw_unsup_format!("unsupported read-write ordering `{ord}`"), + }) + } - #[rustfmt::skip] - "cxchg_seqcst_seqcst" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::SeqCst)?, - #[rustfmt::skip] - "cxchg_seqcst_acquire" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "cxchg_seqcst_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "cxchg_acqrel_seqcst" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::SeqCst)?, - #[rustfmt::skip] - "cxchg_acqrel_acquire" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "cxchg_acqrel_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "cxchg_acquire_seqcst" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::SeqCst)?, - #[rustfmt::skip] - "cxchg_acquire_acquire" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "cxchg_acquire_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "cxchg_release_seqcst" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Release, AtomicReadOrd::SeqCst)?, - #[rustfmt::skip] - "cxchg_release_acquire" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "cxchg_release_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "cxchg_relaxed_seqcst" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::SeqCst)?, - #[rustfmt::skip] - "cxchg_relaxed_acquire" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "cxchg_relaxed_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Relaxed)?, + fn fence_ord<'tcx>(ord: &str) -> InterpResult<'tcx, AtomicFenceOrd> { + Ok(match ord { + "seqcst" => AtomicFenceOrd::SeqCst, + "acqrel" => AtomicFenceOrd::AcqRel, + "acquire" => AtomicFenceOrd::Acquire, + "release" => AtomicFenceOrd::Release, + _ => throw_unsup_format!("unsupported fence ordering `{ord}`"), + }) + } - #[rustfmt::skip] - "cxchgweak_seqcst_seqcst" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::SeqCst)?, - #[rustfmt::skip] - "cxchgweak_seqcst_acquire" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "cxchgweak_seqcst_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "cxchgweak_acqrel_seqcst" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::SeqCst)?, - #[rustfmt::skip] - "cxchgweak_acqrel_acquire" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "cxchgweak_acqrel_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "cxchgweak_acquire_seqcst" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::SeqCst)?, - #[rustfmt::skip] - "cxchgweak_acquire_acquire" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "cxchgweak_acquire_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "cxchgweak_release_seqcst" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Release, AtomicReadOrd::SeqCst)?, - #[rustfmt::skip] - "cxchgweak_release_acquire" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "cxchgweak_release_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "cxchgweak_relaxed_seqcst" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::SeqCst)?, - #[rustfmt::skip] - "cxchgweak_relaxed_acquire" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "cxchgweak_relaxed_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Relaxed)?, + match &*intrinsic_structure { + ["load", ord] => this.atomic_load(args, dest, read_ord(ord)?)?, + ["store", ord] => this.atomic_store(args, write_ord(ord)?)?, - #[rustfmt::skip] - "or_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::SeqCst)?, - #[rustfmt::skip] - "or_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::Acquire)?, - #[rustfmt::skip] - "or_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::Release)?, - #[rustfmt::skip] - "or_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::AcqRel)?, - #[rustfmt::skip] - "or_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::Relaxed)?, - #[rustfmt::skip] - "xor_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::SeqCst)?, - #[rustfmt::skip] - "xor_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::Acquire)?, - #[rustfmt::skip] - "xor_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::Release)?, - #[rustfmt::skip] - "xor_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::AcqRel)?, - #[rustfmt::skip] - "xor_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::Relaxed)?, - #[rustfmt::skip] - "and_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::SeqCst)?, - #[rustfmt::skip] - "and_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::Acquire)?, - #[rustfmt::skip] - "and_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::Release)?, - #[rustfmt::skip] - "and_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::AcqRel)?, - #[rustfmt::skip] - "and_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::Relaxed)?, - #[rustfmt::skip] - "nand_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::SeqCst)?, - #[rustfmt::skip] - "nand_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::Acquire)?, - #[rustfmt::skip] - "nand_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::Release)?, - #[rustfmt::skip] - "nand_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::AcqRel)?, - #[rustfmt::skip] - "nand_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::Relaxed)?, - #[rustfmt::skip] - "xadd_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::SeqCst)?, - #[rustfmt::skip] - "xadd_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::Acquire)?, - #[rustfmt::skip] - "xadd_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::Release)?, - #[rustfmt::skip] - "xadd_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::AcqRel)?, - #[rustfmt::skip] - "xadd_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::Relaxed)?, - #[rustfmt::skip] - "xsub_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::SeqCst)?, - #[rustfmt::skip] - "xsub_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::Acquire)?, - #[rustfmt::skip] - "xsub_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::Release)?, - #[rustfmt::skip] - "xsub_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::AcqRel)?, - #[rustfmt::skip] - "xsub_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::Relaxed)?, + ["fence", ord] => this.atomic_fence(args, fence_ord(ord)?)?, + ["singlethreadfence", ord] => this.compiler_fence(args, fence_ord(ord)?)?, - "min_seqcst" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::SeqCst)?, - "min_acquire" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Acquire)?, - "min_release" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Release)?, - "min_acqrel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::AcqRel)?, - "min_relaxed" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Relaxed)?, - "max_seqcst" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::SeqCst)?, - "max_acquire" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Acquire)?, - "max_release" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Release)?, - "max_acqrel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::AcqRel)?, - "max_relaxed" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Relaxed)?, - "umin_seqcst" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::SeqCst)?, - "umin_acquire" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Acquire)?, - "umin_release" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Release)?, - "umin_acqrel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::AcqRel)?, - "umin_relaxed" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Relaxed)?, - "umax_seqcst" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::SeqCst)?, - "umax_acquire" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Acquire)?, - "umax_release" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Release)?, - "umax_acqrel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::AcqRel)?, - "umax_relaxed" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Relaxed)?, + ["xchg", ord] => this.atomic_exchange(args, dest, rw_ord(ord)?)?, + ["cxchg", ord1, ord2] => + this.atomic_compare_exchange(args, dest, rw_ord(ord1)?, read_ord(ord2)?)?, + ["cxchgweak", ord1, ord2] => + this.atomic_compare_exchange_weak(args, dest, rw_ord(ord1)?, read_ord(ord2)?)?, - name => throw_unsup_format!("unimplemented intrinsic: `atomic_{name}`"), + ["or", ord] => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), rw_ord(ord)?)?, + ["xor", ord] => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), rw_ord(ord)?)?, + ["and", ord] => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), rw_ord(ord)?)?, + ["nand", ord] => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), rw_ord(ord)?)?, + ["xadd", ord] => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), rw_ord(ord)?)?, + ["xsub", ord] => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), rw_ord(ord)?)?, + ["min", ord] => { + // Later we will use the type to indicate signed vs unsigned, + // so make sure it matches the intrinsic name. + assert!(matches!(args[1].layout.ty.kind(), ty::Int(_))); + this.atomic_op(args, dest, AtomicOp::Min, rw_ord(ord)?)?; + } + ["umin", ord] => { + // Later we will use the type to indicate signed vs unsigned, + // so make sure it matches the intrinsic name. + assert!(matches!(args[1].layout.ty.kind(), ty::Uint(_))); + this.atomic_op(args, dest, AtomicOp::Min, rw_ord(ord)?)?; + } + ["max", ord] => { + // Later we will use the type to indicate signed vs unsigned, + // so make sure it matches the intrinsic name. + assert!(matches!(args[1].layout.ty.kind(), ty::Int(_))); + this.atomic_op(args, dest, AtomicOp::Max, rw_ord(ord)?)?; + } + ["umax", ord] => { + // Later we will use the type to indicate signed vs unsigned, + // so make sure it matches the intrinsic name. + assert!(matches!(args[1].layout.ty.kind(), ty::Uint(_))); + this.atomic_op(args, dest, AtomicOp::Max, rw_ord(ord)?)?; + } + + _ => throw_unsup_format!("unimplemented intrinsic: `atomic_{intrinsic_name}`"), } Ok(()) } @@ -343,6 +208,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [place, rhs] = check_arg_count(args)?; let place = this.deref_operand(place)?; + let rhs = this.read_immediate(rhs)?; if !place.layout.ty.is_integral() && !place.layout.ty.is_unsafe_ptr() { span_bug!( @@ -350,7 +216,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic arithmetic operations only work on integer and raw pointer types", ); } - let rhs = this.read_immediate(rhs)?; + if rhs.layout.ty != place.layout.ty { + span_bug!(this.cur_span(), "atomic arithmetic operation type mismatch"); + } // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must From bfd148b783febe248f4d601c8d9d542348345bf0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Jul 2022 17:47:32 -0400 Subject: [PATCH 3542/5092] use env vars, not Cargo.toml, to configure out dev profile --- Cargo.toml | 5 +++-- miri | 6 +++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a2a880f8e308..208b3a764436 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,5 +56,6 @@ harness = false default = ["stack-cache"] stack-cache = [] -[profile.dev] -opt-level = 2 # because it's too slow otherwise +# Be aware that this file is inside a workspace when used via the +# submodule in the rustc repo. That means there are many cargo features +# we cannot use, such as profiles. diff --git a/miri b/miri index bb2fc5b12318..04d441b60780 100755 --- a/miri +++ b/miri @@ -96,10 +96,14 @@ fi # Prepare flags for cargo and rustc. CARGO="cargo +$TOOLCHAIN" +# Share target dir between `miri` and `cargo-miri`. if [ -z "$CARGO_TARGET_DIR" ]; then - # Share target dir between `miri` and `cargo-miri`. export CARGO_TARGET_DIR="$MIRIDIR/target" fi +# We configure dev builds to not be unusably slow. +if [ -z "$CARGO_PROFILE_DEV_OPT_LEVEL" ]; then + export CARGO_PROFILE_DEV_OPT_LEVEL=2 +fi # We set the rpath so that Miri finds the private rustc libraries it needs. export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR $RUSTFLAGS" From 56fefe19bfcdc9a3ce631615859c7cc5cdd0ee58 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Jul 2022 19:50:03 -0400 Subject: [PATCH 3543/5092] cargo-miri: write the Xargo project files atomically --- cargo-miri/bin.rs | 47 ++++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 4c9f3aabaab4..c4ed92d03852 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -319,6 +319,23 @@ fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { } } +/// Writes the given content to the given file *cross-process atomically*, in the sense that another +/// process concurrently reading that file will see either the old content or the new content, but +/// not some intermediate (e.g., empty) state. +/// +/// We assume no other parts of this same process are trying to read or write that file. +fn write_to_file(filename: &Path, content: &str) { + // Create a temporary file with the desired contents. + let mut temp_filename = filename.as_os_str().to_os_string(); + temp_filename.push(&format!(".{}", std::process::id())); + let mut temp_file = File::create(&temp_filename).unwrap(); + temp_file.write_all(content.as_bytes()).unwrap(); + drop(temp_file); + + // Move file to the desired location. + fs::rename(temp_filename, filename).unwrap(); +} + /// Performs the setup required to make `cargo miri` work: Getting a custom-built libstd. Then sets /// `MIRI_SYSROOT`. Skipped if `MIRI_SYSROOT` is already set, in which case we expect the user has /// done all this already. @@ -398,28 +415,25 @@ fn setup(subcommand: MiriCommand) { if !dir.exists() { fs::create_dir_all(&dir).unwrap(); } - let mut xargo_toml = File::create(dir.join("Xargo.toml")).unwrap(); - if std::env::var_os("MIRI_NO_STD").is_none() { - // The interesting bit: Xargo.toml (only needs content if we actually need std) - xargo_toml - .write_all( - br#" + // The interesting bit: Xargo.toml (only needs content if we actually need std) + let xargo_toml = if std::env::var_os("MIRI_NO_STD").is_some() { + "" + } else { + r#" [dependencies.std] default_features = false # We support unwinding, so enable that panic runtime. features = ["panic_unwind", "backtrace"] [dependencies.test] -"#, - ) - .unwrap(); - } +"# + }; + write_to_file(&dir.join("Xargo.toml"), xargo_toml); // The boring bits: a dummy project for xargo. // FIXME: With xargo-check, can we avoid doing this? - File::create(dir.join("Cargo.toml")) - .unwrap() - .write_all( - br#" + write_to_file( + &dir.join("Cargo.toml"), + r#" [package] name = "miri-xargo" description = "A dummy project for building libstd with xargo." @@ -428,9 +442,8 @@ version = "0.0.0" [lib] path = "lib.rs" "#, - ) - .unwrap(); - File::create(dir.join("lib.rs")).unwrap().write_all(b"#![no_std]").unwrap(); + ); + write_to_file(&dir.join("lib.rs"), "#![no_std]"); // Determine architectures. // We always need to set a target so rustc bootstrap can tell apart host from target crates. From bec3a545a55590dd8029bad61d5ea18416c4caf8 Mon Sep 17 00:00:00 2001 From: jam1garner Date: Mon, 18 Jul 2022 20:40:41 -0400 Subject: [PATCH 3544/5092] Add support for MIPS VZ ISA extension --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 4 ++++ compiler/rustc_codegen_ssa/src/target_features.rs | 7 +++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index a0a640473eb5..47590c8578c5 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -165,6 +165,10 @@ pub fn time_trace_profiler_finish(file_name: &Path) { // // To find a list of LLVM's names, check llvm-project/llvm/include/llvm/Support/*TargetParser.def // where the * matches the architecture's name +// +// For targets not present in the above location, see llvm-project/llvm/lib/Target/{ARCH}/*.td +// where `{ARCH}` is the architecture name. Look for instances of `SubtargetFeature`. +// // Beware to not use the llvm github project for this, but check the git submodule // found in src/llvm-project // Though note that Rust can also be build with an external precompiled version of LLVM diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index bfdef2dc0e80..a3ad6a3fcbd4 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -210,8 +210,11 @@ const POWERPC_ALLOWED_FEATURES: &[(&str, Option)] = &[ ("vsx", Some(sym::powerpc_target_feature)), ]; -const MIPS_ALLOWED_FEATURES: &[(&str, Option)] = - &[("fp64", Some(sym::mips_target_feature)), ("msa", Some(sym::mips_target_feature))]; +const MIPS_ALLOWED_FEATURES: &[(&str, Option)] = &[ + ("fp64", Some(sym::mips_target_feature)), + ("msa", Some(sym::mips_target_feature)), + ("virt", Some(sym::mips_target_feature)), +]; const RISCV_ALLOWED_FEATURES: &[(&str, Option)] = &[ ("m", Some(sym::riscv_target_feature)), From 04b66ce34282a3b510cbc6a1cdd28da44f9d33f3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Jul 2022 21:42:50 -0400 Subject: [PATCH 3545/5092] update ui_test readme --- ui_test/README.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/ui_test/README.md b/ui_test/README.md index 4ecebcc8ddb2..f1b1a5d67e0a 100644 --- a/ui_test/README.md +++ b/ui_test/README.md @@ -23,12 +23,11 @@ In order to change how a single test is tested, you can add various `//@` commen Any other comments will be ignored, and all `//@` comments must be formatted precisely as their command specifies, or the test will fail without even being run. -* `//@ignore-XXX` avoids running the test on targets whose triple contains `XXX` - * `XXX` can also be one of `64bit`, `32bit` or `16bit` - * `XXX` can also be `on-host`, which will only run the test during cross compilation testing. -* `//@only-XXX` avoids running the test on targets whose triple **does not** contain `XXX` - * `XXX` can also be one of `64bit`, `32bit` or `16bit` - * `XXX` can also be `on-host`, which will not run the test during cross compilation testing +* `//@ignore-C` avoids running the test when condition `C` is met. + * `C` can be `target-XXX`, which checks whether the target triple contains `XXX`. + * `C` can also be one of `64bit`, `32bit` or `16bit`. + * `C` can also be `on-host`, which will only run the test during cross compilation testing. +* `//@only-C` **only** runs the test when condition `C` is met. The conditions are the same as with `ignore`. * `//@stderr-per-bitwidth` produces one stderr file per bitwidth, as they may differ significantly sometimes * `//@error-pattern: XXX` make sure the stderr output contains `XXX` * `//@revisions: XXX YYY` runs the test once for each space separated name in the list @@ -46,5 +45,5 @@ their command specifies, or the test will fail without even being run. ## Significant differences to compiletest-rs -* `ignore-*` and `only-*` opereate solely on the triple, instead of supporting things like `macos` +* `ignore-target-*` and `only-target-*` opereate solely on the triple, instead of supporting things like `macos` * only `//~` comments can be individualized per revision From 1d5cfb565ca70109dc2c6eb69b8c3d72b4ca8dcd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Jul 2022 08:03:39 -0400 Subject: [PATCH 3546/5092] rustup --- rust-version | 2 +- tests/fail/concurrency/too_few_args.stderr | 2 +- tests/fail/concurrency/too_many_args.stderr | 2 +- tests/fail/erroneous_const.stderr | 2 +- tests/fail/erroneous_const2.stderr | 2 +- tests/fail/panic/double_panic.stderr | 2 +- tests/fail/panic/panic_abort1.stderr | 2 +- tests/fail/panic/panic_abort2.stderr | 2 +- tests/fail/panic/panic_abort3.stderr | 2 +- tests/fail/panic/panic_abort4.stderr | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/rust-version b/rust-version index 362bcc35eade..f4afa4353455 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -880416180b0a9ee1141c07d4d17667edb77daebd +4603ac31b0655793a82f110f544dc1c6abc57bb7 diff --git a/tests/fail/concurrency/too_few_args.stderr b/tests/fail/concurrency/too_few_args.stderr index 093a30768501..c1eb4d8cb6b6 100644 --- a/tests/fail/concurrency/too_few_args.stderr +++ b/tests/fail/concurrency/too_few_args.stderr @@ -8,7 +8,7 @@ LL | panic!() = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: = note: inside `thread_start` at RUSTLIB/std/src/panic.rs:LL:CC - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/tests/fail/concurrency/too_many_args.stderr b/tests/fail/concurrency/too_many_args.stderr index 87e22ec1dcf6..42a96ae62636 100644 --- a/tests/fail/concurrency/too_many_args.stderr +++ b/tests/fail/concurrency/too_many_args.stderr @@ -8,7 +8,7 @@ LL | panic!() = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: = note: inside `thread_start` at RUSTLIB/std/src/panic.rs:LL:CC - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/tests/fail/erroneous_const.stderr b/tests/fail/erroneous_const.stderr index d4b8f25e0385..8138d69f4031 100644 --- a/tests/fail/erroneous_const.stderr +++ b/tests/fail/erroneous_const.stderr @@ -4,7 +4,7 @@ error[E0080]: evaluation of `PrintName::::VOID` failed LL | const VOID: ! = panic!(); | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/erroneous_const.rs:LL:CC | - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) error: post-monomorphization error: referenced constant has errors --> $DIR/erroneous_const.rs:LL:CC diff --git a/tests/fail/erroneous_const2.stderr b/tests/fail/erroneous_const2.stderr index 75e3d9bcd211..05ed8ea1c14b 100644 --- a/tests/fail/erroneous_const2.stderr +++ b/tests/fail/erroneous_const2.stderr @@ -22,7 +22,7 @@ LL | println!("{}", FOO); | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 - = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: post-monomorphization error: referenced constant has errors --> $DIR/erroneous_const2.rs:LL:CC diff --git a/tests/fail/panic/double_panic.stderr b/tests/fail/panic/double_panic.stderr index c88dfd39e107..f1d2b4de97cc 100644 --- a/tests/fail/panic/double_panic.stderr +++ b/tests/fail/panic/double_panic.stderr @@ -86,7 +86,7 @@ note: inside `main` at $DIR/double_panic.rs:LL:CC | LL | } | ^ - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/panic/panic_abort1.stderr b/tests/fail/panic/panic_abort1.stderr index 808fccaaeca8..754719945464 100644 --- a/tests/fail/panic/panic_abort1.stderr +++ b/tests/fail/panic/panic_abort1.stderr @@ -17,7 +17,7 @@ note: inside `main` at RUSTLIB/std/src/panic.rs:LL:CC | LL | std::panic!("panicking from libstd"); | ^ - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `std::panic` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/panic/panic_abort2.stderr b/tests/fail/panic/panic_abort2.stderr index 9b86dc92f717..2fdf889d798a 100644 --- a/tests/fail/panic/panic_abort2.stderr +++ b/tests/fail/panic/panic_abort2.stderr @@ -18,7 +18,7 @@ note: inside `main` at RUSTLIB/std/src/panic.rs:LL:CC | LL | std::panic!("{}-panicking from libstd", 42); | ^ - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `std::panic` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/panic/panic_abort3.stderr b/tests/fail/panic/panic_abort3.stderr index 2bb50d55bfe4..8704b0d940b7 100644 --- a/tests/fail/panic/panic_abort3.stderr +++ b/tests/fail/panic/panic_abort3.stderr @@ -18,7 +18,7 @@ note: inside `main` at RUSTLIB/core/src/panic.rs:LL:CC | LL | core::panic!("panicking from libcore"); | ^ - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `core::panic` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/panic/panic_abort4.stderr b/tests/fail/panic/panic_abort4.stderr index 8ab579301612..1d75d72c0317 100644 --- a/tests/fail/panic/panic_abort4.stderr +++ b/tests/fail/panic/panic_abort4.stderr @@ -18,7 +18,7 @@ note: inside `main` at RUSTLIB/core/src/panic.rs:LL:CC | LL | core::panic!("{}-panicking from libcore", 42); | ^ - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `core::panic` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace From 9dba78a76b7343ac70321b4224746f5e412df088 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Jul 2022 13:19:00 -0400 Subject: [PATCH 3547/5092] show a better error when running Miri with the wrong sysroot --- cargo-miri/bin.rs | 15 +++++++++------ src/bin/miri.rs | 32 +++++++++++++++++++++++++------- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index c4ed92d03852..233d81826eec 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -374,12 +374,15 @@ fn setup(subcommand: MiriCommand) { } None => { // Check for `rust-src` rustup component. - let sysroot = miri() - .args(&["--print", "sysroot"]) - .output() - .expect("failed to determine sysroot") - .stdout; - let sysroot = std::str::from_utf8(&sysroot).unwrap(); + let output = + miri().args(&["--print", "sysroot"]).output().expect("failed to determine sysroot"); + if !output.status.success() { + show_error(format!( + "Failed to determine sysroot; Miri said:\n{}", + String::from_utf8_lossy(&output.stderr).trim_end() + )); + } + let sysroot = std::str::from_utf8(&output.stdout).unwrap(); let sysroot = Path::new(sysroot.trim_end_matches('\n')); // Check for `$SYSROOT/lib/rustlib/src/rust/library`; test if that contains `std/Cargo.toml`. let rustup_src = diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 4f00e4be18ab..5131f3ae9ca9 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -1,5 +1,5 @@ #![feature(rustc_private, stmt_expr_attributes)] -#![allow(clippy::manual_range_contains)] +#![allow(clippy::manual_range_contains, clippy::useless_format)] extern crate rustc_data_structures; extern crate rustc_driver; @@ -143,6 +143,11 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { } } +fn show_error(msg: String) -> ! { + eprintln!("fatal error: {}", msg); + std::process::exit(1) +} + fn init_early_loggers() { // Note that our `extern crate log` is *not* the same as rustc's; as a result, we have to // initialize them both, and we always initialize `miri`'s first. @@ -214,13 +219,26 @@ fn compile_time_sysroot() -> Option { let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); Some(match (home, toolchain) { - (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain), - _ => - option_env!("RUST_SYSROOT") - .expect( + (Some(home), Some(toolchain)) => { + // Check that at runtime, we are still in this toolchain. + let toolchain_runtime = + env::var_os("RUSTUP_TOOLCHAIN").or_else(|| env::var_os("MULTIRUST_TOOLCHAIN")); + if !matches!(toolchain_runtime, Some(r) if r == toolchain) { + show_error(format!( + "This Miri got built with local toolchain `{toolchain}`, but now is being run under a different toolchain. \n\ + Make sure to run Miri in the toolchain it got built with, e.g. via `cargo +{toolchain} miri`." + )); + } + + format!("{}/toolchains/{}", home, toolchain) + } + _ => option_env!("RUST_SYSROOT") + .unwrap_or_else(|| { + show_error(format!( "To build Miri without rustup, set the `RUST_SYSROOT` env var at build time", - ) - .to_owned(), + )) + }) + .to_owned(), }) } From 5cf7ed1e04dc7834d7e8030937a0f8195beed6cb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Jul 2022 13:31:43 -0400 Subject: [PATCH 3548/5092] show where the interpreter was interpreting when an ICE occurs --- src/diagnostics.rs | 18 ++++++++++++++++++ src/eval.rs | 13 +++++++++---- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 4dfa7bd07cbe..1c6cfa096863 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -505,4 +505,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } }); } + + /// We had a panic in Miri itself, try to print something useful. + fn handle_ice(&self) { + eprintln!(); + eprintln!( + "Miri caused an ICE during evaluation. Here's the interpreter backtrace at the time of the panic:" + ); + let this = self.eval_context_ref(); + let stacktrace = this.generate_stacktrace(); + report_msg( + this, + DiagLevel::Note, + "the place in the program where the ICE was triggered", + vec![], + vec![], + &stacktrace, + ); + } } diff --git a/src/eval.rs b/src/eval.rs index d75b4f5fa6d2..87ee50387c2f 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -1,7 +1,10 @@ //! Main evaluator loop and setting up the initial stack frame. +use std::collections::HashSet; use std::ffi::OsStr; use std::iter; +use std::panic::{self, AssertUnwindSafe}; +use std::thread; use log::info; @@ -15,8 +18,6 @@ use rustc_target::spec::abi::Abi; use rustc_session::config::EntryFnType; -use std::collections::HashSet; - use crate::*; #[derive(Copy, Clone, Debug, PartialEq)] @@ -332,7 +333,7 @@ pub fn eval_entry<'tcx>( }; // Perform the main execution. - let res: InterpResult<'_, i64> = (|| { + let res: thread::Result> = panic::catch_unwind(AssertUnwindSafe(|| { // Main loop. loop { let info = ecx.preprocess_diagnostics(); @@ -362,7 +363,11 @@ pub fn eval_entry<'tcx>( } let return_code = ecx.read_scalar(&ret_place.into())?.to_machine_isize(&ecx)?; Ok(return_code) - })(); + })); + let res = res.unwrap_or_else(|panic_payload| { + ecx.handle_ice(); + panic::resume_unwind(panic_payload) + }); // Machine cleanup. // Execution of the program has halted so any memory access we do here From fb3ac74696d64f02e3e75e563a9e378b8b3886bc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Jul 2022 14:40:17 -0400 Subject: [PATCH 3549/5092] on an error, always print the unnormalized stderr --- ui_test/src/lib.rs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 16f7be30f8b2..568e39f5670f 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -172,7 +172,6 @@ pub fn run_tests(config: Config) -> Result<()> { eprintln!(); eprintln!("command: {:?}", miri); eprintln!(); - let mut dump_stderr = true; for error in errors { match error { Error::ExitStatus(mode, exit_status) => eprintln!("{mode:?} got {exit_status}"), @@ -194,9 +193,6 @@ pub fn run_tests(config: Config) -> Result<()> { Error::PatternFoundInPassTest => eprintln!("{}", "error pattern found in success test".red()), Error::OutputDiffers { path, actual, expected } => { - if path.extension().unwrap() == "stderr" { - dump_stderr = false; - } eprintln!("actual output differed from expected {}", path.display()); eprintln!("{}", pretty_assertions::StrComparison::new(expected, actual)); eprintln!() @@ -223,12 +219,9 @@ pub fn run_tests(config: Config) -> Result<()> { } eprintln!(); } - // Unless we already dumped the stderr via an OutputDiffers diff, let's dump it here. - if dump_stderr { - eprintln!("actual stderr:"); - eprintln!("{}", stderr); - eprintln!(); - } + eprintln!("full stderr:"); + eprintln!("{}", stderr); + eprintln!(); } eprintln!("{}", "failures:".red().underline()); for (path, _miri, _revision, _errors, _stderr) in &failures { From 9f9aa00f5d4900c2ec4071fd80ac184f9f95f718 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Jul 2022 14:44:00 -0400 Subject: [PATCH 3550/5092] tweak failure output a little --- ui_test/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 568e39f5670f..917e382379ab 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -164,11 +164,11 @@ pub fn run_tests(config: Config) -> Result<()> { if !failures.is_empty() { for (path, miri, revision, errors, stderr) in &failures { eprintln!(); - eprint!("{}", path.display().to_string().underline()); + eprint!("{}", path.display().to_string().underline().bold()); if !revision.is_empty() { eprint!(" (revision `{}`)", revision); } - eprint!(" {}", "FAILED".red()); + eprint!(" {}", "FAILED:".red().bold()); eprintln!(); eprintln!("command: {:?}", miri); eprintln!(); @@ -223,7 +223,7 @@ pub fn run_tests(config: Config) -> Result<()> { eprintln!("{}", stderr); eprintln!(); } - eprintln!("{}", "failures:".red().underline()); + eprintln!("{}", "FAILURES:".red().underline().bold()); for (path, _miri, _revision, _errors, _stderr) in &failures { eprintln!(" {}", path.display()); } From 5721927afe9ccae2d09691d20223e68d8669fb0c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Jul 2022 15:44:47 -0400 Subject: [PATCH 3551/5092] rustup --- rust-version | 2 +- src/helpers.rs | 2 +- src/shims/intrinsics/mod.rs | 4 ++-- src/shims/panic.rs | 2 +- src/shims/unix/linux/sync.rs | 2 +- src/shims/unix/sync.rs | 3 +-- src/stacked_borrows/mod.rs | 6 +++--- 7 files changed, 10 insertions(+), 11 deletions(-) diff --git a/rust-version b/rust-version index f4afa4353455..38f4b2bda5f2 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4603ac31b0655793a82f110f544dc1c6abc57bb7 +29c5a028b0c92aa5da6a8eb6d6585a389fcf1035 diff --git a/src/helpers.rs b/src/helpers.rs index b650e2ddf225..190eb2098ad0 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -258,7 +258,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Push frame. let mir = this.load_mir(f.def, None)?; let dest = match dest { - Some(dest) => *dest, + Some(dest) => dest.clone(), None => MPlaceTy::fake_alloc_zst(this.layout_of(mir.return_ty())?).into(), }; this.push_stack_frame(f, mir, &dest, stack_pop)?; diff --git a/src/shims/intrinsics/mod.rs b/src/shims/intrinsics/mod.rs index 9ffa40f33353..97f9a7b93cac 100644 --- a/src/shims/intrinsics/mod.rs +++ b/src/shims/intrinsics/mod.rs @@ -224,7 +224,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "frem_fast" => mir::BinOp::Rem, _ => bug!(), }; - let float_finite = |x: ImmTy<'tcx, _>| -> InterpResult<'tcx, bool> { + let float_finite = |x: &ImmTy<'tcx, _>| -> InterpResult<'tcx, bool> { Ok(match x.layout.ty.kind() { ty::Float(FloatTy::F32) => x.to_scalar()?.to_f32()?.is_finite(), ty::Float(FloatTy::F64) => x.to_scalar()?.to_f64()?.is_finite(), @@ -234,7 +234,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ), }) }; - match (float_finite(a)?, float_finite(b)?) { + match (float_finite(&a)?, float_finite(&b)?) { (false, false) => throw_ub_format!( "`{intrinsic_name}` intrinsic called with non-finite value as both parameters", ), diff --git a/src/shims/panic.rs b/src/shims/panic.rs index c356dd86676d..42264f6ff344 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -108,7 +108,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // when we pop this frame. if this.tcx.sess.panic_strategy() == PanicStrategy::Unwind { this.frame_mut().extra.catch_unwind = - Some(CatchUnwindData { catch_fn, data, dest: *dest, ret }); + Some(CatchUnwindData { catch_fn, data, dest: dest.clone(), ret }); } Ok(()) diff --git a/src/shims/unix/linux/sync.rs b/src/shims/unix/linux/sync.rs index a81fdb5e9988..d921b66afbd0 100644 --- a/src/shims/unix/linux/sync.rs +++ b/src/shims/unix/linux/sync.rs @@ -188,8 +188,8 @@ pub fn futex<'tcx>( this.write_scalar(Scalar::from_machine_isize(0, this), dest)?; // Register a timeout callback if a timeout was specified. // This callback will override the return value when the timeout triggers. - let dest = *dest; if let Some(timeout_time) = timeout_time { + let dest = dest.clone(); this.register_timeout_callback( thread, timeout_time, diff --git a/src/shims/unix/sync.rs b/src/shims/unix/sync.rs index ae63907c2c86..590bc1bf0056 100644 --- a/src/shims/unix/sync.rs +++ b/src/shims/unix/sync.rs @@ -828,9 +828,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We return success for now and override it in the timeout callback. this.write_scalar(Scalar::from_i32(0), dest)?; - let dest = *dest; - // Register the timeout callback. + let dest = dest.clone(); this.register_timeout_callback( active_thread, timeout_time, diff --git a/src/stacked_borrows/mod.rs b/src/stacked_borrows/mod.rs index 9040d03632ed..fb40291302d6 100644 --- a/src/stacked_borrows/mod.rs +++ b/src/stacked_borrows/mod.rs @@ -985,7 +985,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // See https://github.com/rust-lang/unsafe-code-guidelines/issues/276. let size = match size { Some(size) => size, - None => return Ok(*val), + None => return Ok(val.clone()), }; // Compute new borrow. @@ -1116,13 +1116,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// explicit. Also see . fn retag_return_place(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let return_place = this.frame_mut().return_place; + let return_place = &this.frame().return_place; if return_place.layout.is_zst() { // There may not be any memory here, nothing to do. return Ok(()); } // We need this to be in-memory to use tagged pointers. - let return_place = this.force_allocation(&return_place)?; + let return_place = this.force_allocation(&return_place.clone())?; // We have to turn the place into a pointer to use the existing code. // (The pointer type does not matter, so we use a raw pointer.) From 4d220c31a4aa1567d66263b368554ef160a9e01e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Jul 2022 19:39:30 -0400 Subject: [PATCH 3552/5092] add some dyn upcasting tests --- tests/pass/upcast.rs | 418 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 418 insertions(+) create mode 100644 tests/pass/upcast.rs diff --git a/tests/pass/upcast.rs b/tests/pass/upcast.rs new file mode 100644 index 000000000000..030c2a7cbf62 --- /dev/null +++ b/tests/pass/upcast.rs @@ -0,0 +1,418 @@ +#![feature(trait_upcasting)] +#![allow(incomplete_features)] + +fn main() { + basic(); + diamond(); + struct_(); + replace_vptr(); +} + +fn basic() { + trait Foo: PartialEq + std::fmt::Debug + Send + Sync { + fn a(&self) -> i32 { + 10 + } + + fn z(&self) -> i32 { + 11 + } + + fn y(&self) -> i32 { + 12 + } + } + + trait Bar: Foo { + fn b(&self) -> i32 { + 20 + } + + fn w(&self) -> i32 { + 21 + } + } + + trait Baz: Bar { + fn c(&self) -> i32 { + 30 + } + } + + impl Foo for i32 { + fn a(&self) -> i32 { + 100 + } + } + + impl Bar for i32 { + fn b(&self) -> i32 { + 200 + } + } + + impl Baz for i32 { + fn c(&self) -> i32 { + 300 + } + } + + let baz: &dyn Baz = &1; + let _: &dyn std::fmt::Debug = baz; + assert_eq!(*baz, 1); + assert_eq!(baz.a(), 100); + assert_eq!(baz.b(), 200); + assert_eq!(baz.c(), 300); + assert_eq!(baz.z(), 11); + assert_eq!(baz.y(), 12); + assert_eq!(baz.w(), 21); + + let bar: &dyn Bar = baz; + let _: &dyn std::fmt::Debug = bar; + assert_eq!(*bar, 1); + assert_eq!(bar.a(), 100); + assert_eq!(bar.b(), 200); + assert_eq!(bar.z(), 11); + assert_eq!(bar.y(), 12); + assert_eq!(bar.w(), 21); + + let foo: &dyn Foo = baz; + let _: &dyn std::fmt::Debug = foo; + assert_eq!(*foo, 1); + assert_eq!(foo.a(), 100); + assert_eq!(foo.z(), 11); + assert_eq!(foo.y(), 12); + + let foo: &dyn Foo = bar; + let _: &dyn std::fmt::Debug = foo; + assert_eq!(*foo, 1); + assert_eq!(foo.a(), 100); + assert_eq!(foo.z(), 11); + assert_eq!(foo.y(), 12); +} + +fn diamond() { + trait Foo: PartialEq + std::fmt::Debug + Send + Sync { + fn a(&self) -> i32 { + 10 + } + + fn z(&self) -> i32 { + 11 + } + + fn y(&self) -> i32 { + 12 + } + } + + trait Bar1: Foo { + fn b(&self) -> i32 { + 20 + } + + fn w(&self) -> i32 { + 21 + } + } + + trait Bar2: Foo { + fn c(&self) -> i32 { + 30 + } + + fn v(&self) -> i32 { + 31 + } + } + + trait Baz: Bar1 + Bar2 { + fn d(&self) -> i32 { + 40 + } + } + + impl Foo for i32 { + fn a(&self) -> i32 { + 100 + } + } + + impl Bar1 for i32 { + fn b(&self) -> i32 { + 200 + } + } + + impl Bar2 for i32 { + fn c(&self) -> i32 { + 300 + } + } + + impl Baz for i32 { + fn d(&self) -> i32 { + 400 + } + } + + let baz: &dyn Baz = &1; + let _: &dyn std::fmt::Debug = baz; + assert_eq!(*baz, 1); + assert_eq!(baz.a(), 100); + assert_eq!(baz.b(), 200); + assert_eq!(baz.c(), 300); + assert_eq!(baz.d(), 400); + assert_eq!(baz.z(), 11); + assert_eq!(baz.y(), 12); + assert_eq!(baz.w(), 21); + assert_eq!(baz.v(), 31); + + let bar1: &dyn Bar1 = baz; + let _: &dyn std::fmt::Debug = bar1; + assert_eq!(*bar1, 1); + assert_eq!(bar1.a(), 100); + assert_eq!(bar1.b(), 200); + assert_eq!(bar1.z(), 11); + assert_eq!(bar1.y(), 12); + assert_eq!(bar1.w(), 21); + + let bar2: &dyn Bar2 = baz; + let _: &dyn std::fmt::Debug = bar2; + assert_eq!(*bar2, 1); + assert_eq!(bar2.a(), 100); + assert_eq!(bar2.c(), 300); + assert_eq!(bar2.z(), 11); + assert_eq!(bar2.y(), 12); + assert_eq!(bar2.v(), 31); + + let foo: &dyn Foo = baz; + let _: &dyn std::fmt::Debug = foo; + assert_eq!(*foo, 1); + assert_eq!(foo.a(), 100); + + let foo: &dyn Foo = bar1; + let _: &dyn std::fmt::Debug = foo; + assert_eq!(*foo, 1); + assert_eq!(foo.a(), 100); + + let foo: &dyn Foo = bar2; + let _: &dyn std::fmt::Debug = foo; + assert_eq!(*foo, 1); + assert_eq!(foo.a(), 100); +} + +fn struct_() { + use std::rc::Rc; + use std::sync::Arc; + + trait Foo: PartialEq + std::fmt::Debug + Send + Sync { + fn a(&self) -> i32 { + 10 + } + + fn z(&self) -> i32 { + 11 + } + + fn y(&self) -> i32 { + 12 + } + } + + trait Bar: Foo { + fn b(&self) -> i32 { + 20 + } + + fn w(&self) -> i32 { + 21 + } + } + + trait Baz: Bar { + fn c(&self) -> i32 { + 30 + } + } + + impl Foo for i32 { + fn a(&self) -> i32 { + 100 + } + } + + impl Bar for i32 { + fn b(&self) -> i32 { + 200 + } + } + + impl Baz for i32 { + fn c(&self) -> i32 { + 300 + } + } + + fn test_box() { + let v = Box::new(1); + + let baz: Box = v.clone(); + assert_eq!(*baz, 1); + assert_eq!(baz.a(), 100); + assert_eq!(baz.b(), 200); + assert_eq!(baz.c(), 300); + assert_eq!(baz.z(), 11); + assert_eq!(baz.y(), 12); + assert_eq!(baz.w(), 21); + + let baz: Box = v.clone(); + let bar: Box = baz; + assert_eq!(*bar, 1); + assert_eq!(bar.a(), 100); + assert_eq!(bar.b(), 200); + assert_eq!(bar.z(), 11); + assert_eq!(bar.y(), 12); + assert_eq!(bar.w(), 21); + + let baz: Box = v.clone(); + let foo: Box = baz; + assert_eq!(*foo, 1); + assert_eq!(foo.a(), 100); + assert_eq!(foo.z(), 11); + assert_eq!(foo.y(), 12); + + let baz: Box = v.clone(); + let bar: Box = baz; + let foo: Box = bar; + assert_eq!(*foo, 1); + assert_eq!(foo.a(), 100); + assert_eq!(foo.z(), 11); + assert_eq!(foo.y(), 12); + } + + fn test_rc() { + let v = Rc::new(1); + + let baz: Rc = v.clone(); + assert_eq!(*baz, 1); + assert_eq!(baz.a(), 100); + assert_eq!(baz.b(), 200); + assert_eq!(baz.c(), 300); + assert_eq!(baz.z(), 11); + assert_eq!(baz.y(), 12); + assert_eq!(baz.w(), 21); + + let baz: Rc = v.clone(); + let bar: Rc = baz; + assert_eq!(*bar, 1); + assert_eq!(bar.a(), 100); + assert_eq!(bar.b(), 200); + assert_eq!(bar.z(), 11); + assert_eq!(bar.y(), 12); + assert_eq!(bar.w(), 21); + + let baz: Rc = v.clone(); + let foo: Rc = baz; + assert_eq!(*foo, 1); + assert_eq!(foo.a(), 100); + assert_eq!(foo.z(), 11); + assert_eq!(foo.y(), 12); + + let baz: Rc = v.clone(); + let bar: Rc = baz; + let foo: Rc = bar; + assert_eq!(*foo, 1); + assert_eq!(foo.a(), 100); + assert_eq!(foo.z(), 11); + assert_eq!(foo.y(), 12); + assert_eq!(foo.z(), 11); + assert_eq!(foo.y(), 12); + } + + fn test_arc() { + let v = Arc::new(1); + + let baz: Arc = v.clone(); + assert_eq!(*baz, 1); + assert_eq!(baz.a(), 100); + assert_eq!(baz.b(), 200); + assert_eq!(baz.c(), 300); + assert_eq!(baz.z(), 11); + assert_eq!(baz.y(), 12); + assert_eq!(baz.w(), 21); + + let baz: Arc = v.clone(); + let bar: Arc = baz; + assert_eq!(*bar, 1); + assert_eq!(bar.a(), 100); + assert_eq!(bar.b(), 200); + assert_eq!(bar.z(), 11); + assert_eq!(bar.y(), 12); + assert_eq!(bar.w(), 21); + + let baz: Arc = v.clone(); + let foo: Arc = baz; + assert_eq!(*foo, 1); + assert_eq!(foo.a(), 100); + assert_eq!(foo.z(), 11); + assert_eq!(foo.y(), 12); + + let baz: Arc = v.clone(); + let bar: Arc = baz; + let foo: Arc = bar; + assert_eq!(*foo, 1); + assert_eq!(foo.a(), 100); + assert_eq!(foo.z(), 11); + assert_eq!(foo.y(), 12); + } + + test_box(); + test_rc(); + test_arc(); +} + +fn replace_vptr() { + trait A { + fn foo_a(&self); + } + + trait B { + fn foo_b(&self); + } + + trait C: A + B { + fn foo_c(&self); + } + + struct S(i32); + + impl A for S { + fn foo_a(&self) { + unreachable!(); + } + } + + impl B for S { + fn foo_b(&self) { + assert_eq!(42, self.0); + } + } + + impl C for S { + fn foo_c(&self) { + unreachable!(); + } + } + + fn invoke_inner(b: &dyn B) { + b.foo_b(); + } + + fn invoke_outer(c: &dyn C) { + invoke_inner(c); + } + + let s = S(42); + invoke_outer(&s); +} From db93abe8234ad14d8adca09b5d6f93030a82d4b6 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 19 Jul 2022 17:08:17 -0400 Subject: [PATCH 3553/5092] Fix bugs where unique_range became invalid And also expand the cache integrity checks to cover this case, and generally assert a lot more about the unique_range, then tighten up sloppy implementation scenarios that this uncovered. --- src/stacked_borrows/stack.rs | 42 +++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/src/stacked_borrows/stack.rs b/src/stacked_borrows/stack.rs index bc7ffd4faea5..9fab5433d84c 100644 --- a/src/stacked_borrows/stack.rs +++ b/src/stacked_borrows/stack.rs @@ -92,6 +92,7 @@ impl<'tcx> Stack { } } + // Check that all Unique items fall within unique_range. for (idx, item) in self.borrows.iter().enumerate() { if item.perm() == Permission::Unique { assert!( @@ -102,6 +103,18 @@ impl<'tcx> Stack { ); } } + + // Check that the unique_range is a valid index into the borrow stack. + let uniques = &self.borrows[self.unique_range.clone()]; + + // Check that the start of the unique_range is precise. + if let Some(first_unique) = uniques.first() { + assert_eq!(first_unique.perm(), Permission::Unique); + } + // We cannot assert that the unique range is exact on the upper end. + // When we pop items within the unique range, setting the end of the range precisely + // require doing a linear search of the borrow stack, which is exactly the kind of + // operation that all this caching exists to avoid. } /// Find the item granting the given kind of access to the given tag, and return where @@ -227,9 +240,14 @@ impl<'tcx> Stack { self.unique_range.end += 1; } if new.perm() == Permission::Unique { - // Make sure the possibly-unique range contains the new borrow - self.unique_range.start = self.unique_range.start.min(new_idx); - self.unique_range.end = self.unique_range.end.max(new_idx + 1); + // If this is the first Unique, set the range to contain just the new item. + if self.unique_range == (0..0) { + self.unique_range = new_idx..new_idx + 1; + } else { + // We already have other Unique items, expand the range to include the new item + self.unique_range.start = self.unique_range.start.min(new_idx); + self.unique_range.end = self.unique_range.end.max(new_idx + 1); + } } // The above insert changes the meaning of every index in the cache >= new_idx, so now @@ -282,6 +300,10 @@ impl<'tcx> Stack { // cache when it has been cleared and not yet refilled. self.borrows.clear(); self.unknown_bottom = Some(tag); + #[cfg(feature = "stack-cache")] + { + self.unique_range = 0..0; + } } /// Find all `Unique` elements in this borrow stack above `granting_idx`, pass a copy of them @@ -298,7 +320,7 @@ impl<'tcx> Stack { if disable_start <= unique_range.end { let lower = unique_range.start.max(disable_start); - let upper = (unique_range.end + 1).min(self.borrows.len()); + let upper = self.unique_range.end; for item in &mut self.borrows[lower..upper] { if item.perm() == Permission::Unique { log::trace!("access: disabling item {:?}", item); @@ -315,14 +337,14 @@ impl<'tcx> Stack { } #[cfg(feature = "stack-cache")] - if disable_start < self.unique_range.start { + if disable_start <= self.unique_range.start { // We disabled all Unique items self.unique_range.start = 0; self.unique_range.end = 0; } else { - // Truncate the range to disable_start. This is + 2 because we are only removing - // elements after disable_start, and this range does not include the end. - self.unique_range.end = self.unique_range.end.min(disable_start + 1); + // Truncate the range to only include items up to the index that we started disabling + // at. + self.unique_range.end = self.unique_range.end.min(disable_start); } #[cfg(debug_assertions)] @@ -369,12 +391,12 @@ impl<'tcx> Stack { self.cache.items[i] = base_tag; } - if start < self.unique_range.start.saturating_sub(1) { + if start <= self.unique_range.start { // We removed all the Unique items self.unique_range = 0..0; } else { // Ensure the range doesn't extend past the new top of the stack - self.unique_range.end = self.unique_range.end.min(start + 1); + self.unique_range.end = self.unique_range.end.min(start); } } else { self.unique_range = 0..0; From 3e93045c8781bff244c119302a349a1be6bff83f Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 19 Jul 2022 20:22:04 -0400 Subject: [PATCH 3554/5092] Add a minimal reproducer of the ICE Co-authored-by: Ralf Jung --- tests/pass/issues/issue-miri-2389.rs | 17 +++++++++++++++++ tests/pass/issues/issue-miri-2389.stderr | 15 +++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 tests/pass/issues/issue-miri-2389.rs create mode 100644 tests/pass/issues/issue-miri-2389.stderr diff --git a/tests/pass/issues/issue-miri-2389.rs b/tests/pass/issues/issue-miri-2389.rs new file mode 100644 index 000000000000..469122095e51 --- /dev/null +++ b/tests/pass/issues/issue-miri-2389.rs @@ -0,0 +1,17 @@ +use std::cell::Cell; + +fn main() { + unsafe { + let root0 = Cell::new(42); + let wildcard = &root0 as *const Cell as usize as *const Cell; + // empty the stack to unknown (via SRW reborrow from wildcard) + let _ref0 = &*wildcard; + // Do a non-SRW reborrow from wildcard to start building up a stack again. + // Now new refs start being inserted at idx 0, pushing the unique_range up. + let _refn = &*&*&*&*&*(wildcard.cast::()); + // empty the stack again, but this time with unique_range.start sitting at some high index. + let _ref0 = &*wildcard; + // and do a read which tries to clear the uniques + wildcard.cast::().read(); + } +} diff --git a/tests/pass/issues/issue-miri-2389.stderr b/tests/pass/issues/issue-miri-2389.stderr new file mode 100644 index 000000000000..2ff931f23157 --- /dev/null +++ b/tests/pass/issues/issue-miri-2389.stderr @@ -0,0 +1,15 @@ +warning: integer-to-pointer cast + --> $DIR/issue-miri-2389.rs:LL:CC + | +LL | let wildcard = &root0 as *const Cell as usize as *const Cell; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast + | + = help: This program is using integer-to-pointer casts or (equivalently) `ptr::from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program. + = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation. + = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead. + = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics. + = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning. + = note: backtrace: + = note: inside `main` at $DIR/issue-miri-2389.rs:LL:CC + From 4268918a502f899c4bc9041e7610c3bbc4d76517 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 19 Jul 2022 20:53:48 -0400 Subject: [PATCH 3555/5092] Clarify implementation a bit --- src/stacked_borrows/stack.rs | 7 ++++--- tests/pass/{issues => stacked-borrows}/issue-miri-2389.rs | 0 .../{issues => stacked-borrows}/issue-miri-2389.stderr | 0 3 files changed, 4 insertions(+), 3 deletions(-) rename tests/pass/{issues => stacked-borrows}/issue-miri-2389.rs (100%) rename tests/pass/{issues => stacked-borrows}/issue-miri-2389.stderr (100%) diff --git a/src/stacked_borrows/stack.rs b/src/stacked_borrows/stack.rs index 9fab5433d84c..32c1be5fb1e2 100644 --- a/src/stacked_borrows/stack.rs +++ b/src/stacked_borrows/stack.rs @@ -105,6 +105,7 @@ impl<'tcx> Stack { } // Check that the unique_range is a valid index into the borrow stack. + // This asserts that the unique_range's start <= end. let uniques = &self.borrows[self.unique_range.clone()]; // Check that the start of the unique_range is precise. @@ -113,7 +114,7 @@ impl<'tcx> Stack { } // We cannot assert that the unique range is exact on the upper end. // When we pop items within the unique range, setting the end of the range precisely - // require doing a linear search of the borrow stack, which is exactly the kind of + // requires doing a linear search of the borrow stack, which is exactly the kind of // operation that all this caching exists to avoid. } @@ -240,8 +241,8 @@ impl<'tcx> Stack { self.unique_range.end += 1; } if new.perm() == Permission::Unique { - // If this is the first Unique, set the range to contain just the new item. - if self.unique_range == (0..0) { + // If this is the only Unique, set the range to contain just the new item. + if self.unique_range.is_empty() { self.unique_range = new_idx..new_idx + 1; } else { // We already have other Unique items, expand the range to include the new item diff --git a/tests/pass/issues/issue-miri-2389.rs b/tests/pass/stacked-borrows/issue-miri-2389.rs similarity index 100% rename from tests/pass/issues/issue-miri-2389.rs rename to tests/pass/stacked-borrows/issue-miri-2389.rs diff --git a/tests/pass/issues/issue-miri-2389.stderr b/tests/pass/stacked-borrows/issue-miri-2389.stderr similarity index 100% rename from tests/pass/issues/issue-miri-2389.stderr rename to tests/pass/stacked-borrows/issue-miri-2389.stderr From 5fbf036670592d79eae81c4617141502b53a09a8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Jul 2022 21:44:45 -0400 Subject: [PATCH 3556/5092] only do env var cleanup if all threads have stopped --- src/concurrency/data_race.rs | 78 ++++++++++++++++++------------------ src/eval.rs | 13 +++--- 2 files changed, 45 insertions(+), 46 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 4b402b51fc59..8ee8df7445b3 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -436,45 +436,6 @@ impl MemoryCellClocks { /// Evaluation context extensions. impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { - /// Temporarily allow data-races to occur. This should only be used in - /// one of these cases: - /// - One of the appropriate `validate_atomic` functions will be called to - /// to treat a memory access as atomic. - /// - The memory being accessed should be treated as internal state, that - /// cannot be accessed by the interpreted program. - /// - Execution of the interpreted program execution has halted. - #[inline] - fn allow_data_races_ref(&self, op: impl FnOnce(&MiriEvalContext<'mir, 'tcx>) -> R) -> R { - let this = self.eval_context_ref(); - if let Some(data_race) = &this.machine.data_race { - data_race.ongoing_action_data_race_free.set(true); - } - let result = op(this); - if let Some(data_race) = &this.machine.data_race { - data_race.ongoing_action_data_race_free.set(false); - } - result - } - - /// Same as `allow_data_races_ref`, this temporarily disables any data-race detection and - /// so should only be used for atomic operations or internal state that the program cannot - /// access. - #[inline] - fn allow_data_races_mut( - &mut self, - op: impl FnOnce(&mut MiriEvalContext<'mir, 'tcx>) -> R, - ) -> R { - let this = self.eval_context_mut(); - if let Some(data_race) = &this.machine.data_race { - data_race.ongoing_action_data_race_free.set(true); - } - let result = op(this); - if let Some(data_race) = &this.machine.data_race { - data_race.ongoing_action_data_race_free.set(false); - } - result - } - /// Atomic variant of read_scalar_at_offset. fn read_scalar_at_offset_atomic( &self, @@ -1044,6 +1005,45 @@ impl VClockAlloc { impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { + /// Temporarily allow data-races to occur. This should only be used in + /// one of these cases: + /// - One of the appropriate `validate_atomic` functions will be called to + /// to treat a memory access as atomic. + /// - The memory being accessed should be treated as internal state, that + /// cannot be accessed by the interpreted program. + /// - Execution of the interpreted program execution has halted. + #[inline] + fn allow_data_races_ref(&self, op: impl FnOnce(&MiriEvalContext<'mir, 'tcx>) -> R) -> R { + let this = self.eval_context_ref(); + if let Some(data_race) = &this.machine.data_race { + data_race.ongoing_action_data_race_free.set(true); + } + let result = op(this); + if let Some(data_race) = &this.machine.data_race { + data_race.ongoing_action_data_race_free.set(false); + } + result + } + + /// Same as `allow_data_races_ref`, this temporarily disables any data-race detection and + /// so should only be used for atomic operations or internal state that the program cannot + /// access. + #[inline] + fn allow_data_races_mut( + &mut self, + op: impl FnOnce(&mut MiriEvalContext<'mir, 'tcx>) -> R, + ) -> R { + let this = self.eval_context_mut(); + if let Some(data_race) = &this.machine.data_race { + data_race.ongoing_action_data_race_free.set(true); + } + let result = op(this); + if let Some(data_race) = &this.machine.data_race { + data_race.ongoing_action_data_race_free.set(false); + } + result + } + /// Generic atomic operation implementation fn validate_atomic_op( &self, diff --git a/src/eval.rs b/src/eval.rs index 44459621e393..996d04a2c57c 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -363,13 +363,12 @@ pub fn eval_entry<'tcx>( panic::resume_unwind(panic_payload) }); - // Machine cleanup. - // Execution of the program has halted so any memory access we do here - // cannot produce a real data race. If we do not do something to disable - // data race detection here, some uncommon combination of errors will - // cause a data race to be detected: - // https://github.com/rust-lang/miri/issues/2020 - ecx.allow_data_races_mut(|ecx| EnvVars::cleanup(ecx).unwrap()); + // Machine cleanup. Only do this if all threads have terminated; threads that are still running + // might cause data races (https://github.com/rust-lang/miri/issues/2020) or Stacked Borrows + // errors (https://github.com/rust-lang/miri/issues/2396) if we deallocate here. + if ecx.have_all_terminated() { + EnvVars::cleanup(&mut ecx).unwrap(); + } // Process the result. match res { From e12a721d84a612fe0e31e2c450f46f0907f6ec37 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Jul 2022 07:42:08 -0400 Subject: [PATCH 3557/5092] no need for an exhaustive enum of subcommands --- cargo-miri/bin.rs | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 233d81826eec..2ab854b906a4 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -1,3 +1,4 @@ +#![feature(let_else)] #![allow(clippy::useless_format, clippy::derive_partial_eq_without_eq)] mod version; @@ -34,11 +35,12 @@ Examples: cargo miri test -- test-suite-filter "#; -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug)] enum MiriCommand { - Run, - Test, + /// Our own special 'setup' command. Setup, + /// A command to be forwarded to cargo. + Forward(String), } /// The information to run a crate with the given environment. @@ -339,9 +341,10 @@ fn write_to_file(filename: &Path, content: &str) { /// Performs the setup required to make `cargo miri` work: Getting a custom-built libstd. Then sets /// `MIRI_SYSROOT`. Skipped if `MIRI_SYSROOT` is already set, in which case we expect the user has /// done all this already. -fn setup(subcommand: MiriCommand) { +fn setup(subcommand: &MiriCommand) { + let only_setup = matches!(subcommand, MiriCommand::Setup); if std::env::var_os("MIRI_SYSROOT").is_some() { - if subcommand == MiriCommand::Setup { + if only_setup { println!("WARNING: MIRI_SYSROOT already set, not doing anything.") } return; @@ -349,7 +352,7 @@ fn setup(subcommand: MiriCommand) { // Subcommands other than `setup` will do a setup if necessary, but // interactively confirm first. - let ask_user = subcommand != MiriCommand::Setup; + let ask_user = !only_setup; // First, we need xargo. if xargo_version().map_or(true, |v| v < XARGO_MIN_VERSION) { @@ -495,11 +498,11 @@ path = "lib.rs" let sysroot = if target == &host { dir.join("HOST") } else { PathBuf::from(dir) }; std::env::set_var("MIRI_SYSROOT", &sysroot); // pass the env var to the processes we spawn, which will turn it into "--sysroot" flags // Figure out what to print. - let print_sysroot = subcommand == MiriCommand::Setup && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path + let print_sysroot = only_setup && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path if print_sysroot { // Print just the sysroot and nothing else; this way we do not need any escaping. println!("{}", sysroot.display()); - } else if subcommand == MiriCommand::Setup { + } else if only_setup { println!("A libstd for Miri is now available in `{}`.", sysroot.display()); } } @@ -573,10 +576,12 @@ fn phase_cargo_miri(mut args: env::Args) { // Require a subcommand before any flags. // We cannot know which of those flags take arguments and which do not, // so we cannot detect subcommands later. - let subcommand = match args.next().as_deref() { - Some("test" | "t") => MiriCommand::Test, - Some("run" | "r") => MiriCommand::Run, - Some("setup") => MiriCommand::Setup, + let Some(subcommand) = args.next() else { + show_error(format!("`cargo miri` needs to be called with a subcommand (`run`, `test`)")); + }; + let subcommand = match &*subcommand { + "setup" => MiriCommand::Setup, + "test" | "t" | "run" | "r" => MiriCommand::Forward(subcommand), // Invalid command. _ => show_error(format!( @@ -586,7 +591,7 @@ fn phase_cargo_miri(mut args: env::Args) { let verbose = has_arg_flag("-v"); // We always setup. - setup(subcommand); + setup(&subcommand); // Invoke actual cargo for the job, but with different flags. // We re-use `cargo test` and `cargo run`, which makes target and binary handling very easy but @@ -596,8 +601,7 @@ fn phase_cargo_miri(mut args: env::Args) { // harder. let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); let cargo_cmd = match subcommand { - MiriCommand::Test => "test", - MiriCommand::Run => "run", + MiriCommand::Forward(s) => s, MiriCommand::Setup => return, // `cargo miri setup` stops here. }; let mut cmd = cargo(); From e0514508b4b7cb4042683e6524df8f3ec9f0104f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Jul 2022 11:27:04 -0400 Subject: [PATCH 3558/5092] fix test file name --- tests/pass/{upcast.rs => dyn-upcast.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/pass/{upcast.rs => dyn-upcast.rs} (100%) diff --git a/tests/pass/upcast.rs b/tests/pass/dyn-upcast.rs similarity index 100% rename from tests/pass/upcast.rs rename to tests/pass/dyn-upcast.rs From ab6fb9d2aa440a48723d311bcd065be9552a27f0 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 14 Jul 2022 10:03:08 +0000 Subject: [PATCH 3559/5092] Allow tests to have dependencies --- Cargo.lock | 35 ++ cargo-miri/bin.rs | 62 ++- test-cargo-miri/Cargo.lock | 23 +- test-cargo-miri/Cargo.toml | 2 - test-cargo-miri/run-test.py | 28 +- test-cargo-miri/tests/test.rs | 8 +- test_dependencies/Cargo.lock | 376 ++++++++++++++++++ test_dependencies/Cargo.toml | 19 + test_dependencies/src/main.rs | 1 + tests/compiletest.rs | 49 ++- .../libc_pthread_create_main_terminate.rs | 2 - .../concurrency/libc_pthread_join_detached.rs | 2 - .../concurrency/libc_pthread_join_joined.rs | 2 - .../concurrency/libc_pthread_join_main.rs | 2 - .../concurrency/libc_pthread_join_multiple.rs | 2 - .../concurrency/libc_pthread_join_self.rs | 2 - tests/fail/concurrency/too_few_args.rs | 2 - tests/fail/concurrency/too_many_args.rs | 2 - tests/fail/concurrency/unwind_top_of_stack.rs | 2 - tests/fail/fs/close_stdout.rs | 2 - tests/fail/fs/isolated_stdin.rs | 2 - tests/fail/fs/read_from_stdout.rs | 2 - .../fs/unix_open_missing_required_mode.rs | 2 - tests/fail/fs/write_to_stdin.rs | 2 - .../sync/libc_pthread_cond_double_destroy.rs | 1 - .../libc_pthread_condattr_double_destroy.rs | 1 - .../sync/libc_pthread_mutex_NULL_deadlock.rs | 2 - .../fail/sync/libc_pthread_mutex_deadlock.rs | 2 - .../libc_pthread_mutex_default_deadlock.rs | 2 - .../sync/libc_pthread_mutex_destroy_locked.rs | 2 - .../sync/libc_pthread_mutex_double_destroy.rs | 1 - .../libc_pthread_mutex_normal_deadlock.rs | 2 - ...bc_pthread_mutex_normal_unlock_unlocked.rs | 2 - .../sync/libc_pthread_mutex_wrong_owner.rs | 2 - .../libc_pthread_mutexattr_double_destroy.rs | 1 - ...libc_pthread_rwlock_destroy_read_locked.rs | 2 - ...ibc_pthread_rwlock_destroy_write_locked.rs | 2 - .../libc_pthread_rwlock_double_destroy.rs | 1 - ...wlock_read_write_deadlock_single_thread.rs | 2 - .../libc_pthread_rwlock_read_wrong_owner.rs | 2 - .../libc_pthread_rwlock_unlock_unlocked.rs | 2 - ...libc_pthread_rwlock_write_read_deadlock.rs | 2 - ...wlock_write_read_deadlock_single_thread.rs | 2 - ...ibc_pthread_rwlock_write_write_deadlock.rs | 2 - ...lock_write_write_deadlock_single_thread.rs | 2 - .../libc_pthread_rwlock_write_wrong_owner.rs | 2 - tests/fail/tokio_mvp.rs | 7 + tests/fail/tokio_mvp.stderr | 19 + tests/fail/unsupported_signal.rs | 2 - tests/panic/panic/unsupported_syscall.rs | 2 - tests/pass/calloc.rs | 2 - tests/pass/concurrency/libc_pthread_cond.rs | 2 - tests/pass/concurrency/linux-futex.rs | 1 - .../concurrency/tls_pthread_drop_order.rs | 1 - tests/pass/foreign-fn-linkname.rs | 2 - tests/pass/fs.rs | 2 - tests/pass/fs_with_isolation.rs | 2 - tests/pass/libc.rs | 2 - .../pass/linux-getrandom-without-isolation.rs | 1 - tests/pass/linux-getrandom.rs | 1 - tests/pass/malloc.rs | 2 - tests/pass/random.rs | 22 + tests/pass/regions-mock-trans.rs | 2 - ui_test/Cargo.lock | 35 ++ ui_test/Cargo.toml | 2 +- ui_test/README.md | 2 + ui_test/src/dependencies.rs | 137 +++++++ ui_test/src/lib.rs | 37 +- ui_test/src/tests.rs | 2 + 69 files changed, 792 insertions(+), 165 deletions(-) create mode 100644 test_dependencies/Cargo.lock create mode 100644 test_dependencies/Cargo.toml create mode 100644 test_dependencies/src/main.rs create mode 100644 tests/fail/tokio_mvp.rs create mode 100644 tests/fail/tokio_mvp.stderr create mode 100644 tests/pass/random.rs create mode 100644 ui_test/src/dependencies.rs diff --git a/Cargo.lock b/Cargo.lock index cc707c630e54..f660ed77620a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -73,6 +73,37 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "camino" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "869119e97797867fd90f5e22af7d0bd274bd4635ebb9eb68c04f3f513ae6c412" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3abb7553d5b9b8421c6de7cb02606ff15e0c6eea7d8eadd75ef013fd636bec36" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", +] + [[package]] name = "cc" version = "1.0.73" @@ -596,6 +627,9 @@ name = "semver" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" +dependencies = [ + "serde", +] [[package]] name = "serde" @@ -724,6 +758,7 @@ dependencies = [ name = "ui_test" version = "0.1.0" dependencies = [ + "cargo_metadata", "color-eyre", "colored", "crossbeam", diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 2ab854b906a4..6e140ab7143d 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -3,6 +3,7 @@ mod version; +use std::collections::HashMap; use std::env; use std::ffi::{OsStr, OsString}; use std::fmt::Write as _; @@ -114,10 +115,14 @@ fn show_error(msg: String) -> ! { std::process::exit(1) } -// Determines whether a `--flag` is present. +/// Determines whether a `--flag` is present. fn has_arg_flag(name: &str) -> bool { - let mut args = std::env::args().take_while(|val| val != "--"); - args.any(|val| val == name) + num_arg_flag(name) > 0 +} + +/// Determines how many times a `--flag` is present. +fn num_arg_flag(name: &str) -> usize { + std::env::args().take_while(|val| val != "--").filter(|val| val == name).count() } /// Yields all values of command line flag `name` as `Ok(arg)`, and all other arguments except @@ -588,7 +593,7 @@ fn phase_cargo_miri(mut args: env::Args) { "`cargo miri` supports the following subcommands: `run`, `test`, and `setup`." )), }; - let verbose = has_arg_flag("-v"); + let verbose = num_arg_flag("-v"); // We always setup. setup(&subcommand); @@ -685,7 +690,7 @@ fn phase_cargo_miri(mut args: env::Args) { cmd.env("MIRI_LOCAL_CRATES", local_crates(&metadata)); // Run cargo. - if verbose { + if verbose > 0 { eprintln!("[cargo-miri miri] RUSTC_WRAPPER={:?}", cargo_miri_path); eprintln!("[cargo-miri miri] {}={:?}", target_runner_env_name, cargo_miri_path); if *target != host { @@ -693,7 +698,7 @@ fn phase_cargo_miri(mut args: env::Args) { } eprintln!("[cargo-miri miri] RUSTDOC={:?}", cargo_miri_path); eprintln!("[cargo-miri miri] {:?}", cmd); - cmd.env("MIRI_VERBOSE", ""); // This makes the other phases verbose. + cmd.env("MIRI_VERBOSE", verbose.to_string()); // This makes the other phases verbose. } exec(cmd) } @@ -752,7 +757,8 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { } } - let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); + let verbose = std::env::var("MIRI_VERBOSE") + .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); let target_crate = is_target_crate(); let print = get_arg_flag_value("--print").is_some() || has_arg_flag("-vV"); // whether this is cargo/xargo invoking rustc to get some infos @@ -761,13 +767,13 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { // https://github.com/rust-lang/miri/issues/1724#issuecomment-787115693 // As we store a JSON file instead of building the crate here, an empty file is fine. let dep_info_name = out_filename("", ".d"); - if verbose { + if verbose > 0 { eprintln!("[cargo-miri rustc] writing stub dep-info to `{}`", dep_info_name.display()); } File::create(dep_info_name).expect("failed to create fake .d file"); let filename = out_filename("", ""); - if verbose { + if verbose > 0 { eprintln!("[cargo-miri rustc] writing run info to `{}`", filename.display()); } info.store(&filename); @@ -810,7 +816,7 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { cmd.args(&env.args); cmd.env("MIRI_BE_RUSTC", "target"); - if verbose { + if verbose > 0 { eprintln!( "[cargo-miri rustc] captured input:\n{}", std::str::from_utf8(&env.stdin).unwrap() @@ -877,6 +883,15 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { cmd.arg("-C").arg("panic=abort"); } } else { + // For host crates (but not when we are printing), we might still have to set the sysroot. + if !print { + // When we're running `cargo-miri` from `x.py` we need to pass the sysroot explicitly as rustc + // can't figure out the sysroot on its own unless it's from rustup. + if let Some(sysroot) = std::env::var_os("SYSROOT") { + cmd.arg("--sysroot").arg(sysroot); + } + } + // For host crates or when we are printing, just forward everything. cmd.args(args); } @@ -888,8 +903,14 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { cmd.env("MIRI_BE_RUSTC", if target_crate { "target" } else { "host" }); // Run it. - if verbose { - eprintln!("[cargo-miri rustc] {:?}", cmd); + if verbose > 0 { + eprint!("[cargo-miri rustc] "); + if verbose > 1 { + for (key, value) in env_vars_from_cmd(&cmd) { + eprintln!("{key}={value:?} \\"); + } + } + eprintln!("{:?}", cmd); } exec(cmd); @@ -908,6 +929,23 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { } } +fn env_vars_from_cmd(cmd: &Command) -> Vec<(String, String)> { + let mut envs = HashMap::new(); + for (key, value) in std::env::vars() { + envs.insert(key, value); + } + for (key, value) in cmd.get_envs() { + if let Some(value) = value { + envs.insert(key.to_str().unwrap().into(), value.to_str().unwrap().to_owned()); + } else { + envs.remove(key.to_str().unwrap()); + } + } + let mut envs: Vec<_> = envs.into_iter().collect(); + envs.sort(); + envs +} + #[derive(Debug, Copy, Clone, PartialEq)] enum RunnerPhase { /// `cargo` is running a binary diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index d34db9f14dfc..4cf58d723a25 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -15,8 +15,6 @@ dependencies = [ "byteorder", "cdylib", "exported_symbol", - "getrandom 0.1.16", - "getrandom 0.2.7", "issue_1567", "issue_1691", "issue_1705", @@ -51,17 +49,6 @@ dependencies = [ name = "exported_symbol_dep" version = "0.1.0" -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.7" @@ -70,7 +57,7 @@ checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", ] [[package]] @@ -185,7 +172,7 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ - "getrandom 0.2.7", + "getrandom", ] [[package]] @@ -223,12 +210,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 2193d354d5d2..89a8463e4b32 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -19,8 +19,6 @@ issue_rust_86261 = { path = "issue-rust-86261" } [dev-dependencies] rand = { version = "0.8", features = ["small_rng"] } -getrandom_1 = { package = "getrandom", version = "0.1" } -getrandom_2 = { package = "getrandom", version = "0.2" } serde_derive = "1.0" # not actually used, but exercises some unique code path (`--extern` .so file) page_size = "0.4.1" diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 09e7df39b1c0..bc0046ffb148 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -5,7 +5,7 @@ Assumes the `MIRI_SYSROOT` env var to be set appropriately, and the working directory to contain the cargo-miri-test project. ''' -import sys, subprocess, os, re +import sys, subprocess, os, re, difflib CGREEN = '\33[32m' CBOLD = '\33[1m' @@ -27,6 +27,17 @@ def normalize_stdout(str): str = str.replace("src\\", "src/") # normalize paths across platforms return re.sub("finished in \d+\.\d\ds", "finished in $TIME", str) +def check_output(actual, path, name): + expected = open(path).read() + if expected == actual: + return True + print(f"{path} did not match reference!") + print(f"--- BEGIN diff {name} ---") + for text in difflib.unified_diff(expected.split("\n"), actual.split("\n")): + print(text) + print(f"--- END diff {name} ---") + return False + def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): print("Testing {}...".format(name)) ## Call `cargo miri`, capture all output @@ -42,17 +53,14 @@ def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): (stdout, stderr) = p.communicate(input=stdin) stdout = stdout.decode("UTF-8") stderr = stderr.decode("UTF-8") - if p.returncode == 0 and normalize_stdout(stdout) == open(stdout_ref).read() and stderr == open(stderr_ref).read(): + stdout = normalize_stdout(stdout) + + stdout_matches = check_output(stdout, stdout_ref, "stdout") + stderr_matches = check_output(stderr, stderr_ref, "stderr") + + if p.returncode == 0 and stdout_matches and stderr_matches: # All good! return - # Show output - print("Test stdout or stderr did not match reference!") - print("--- BEGIN test stdout ---") - print(stdout, end="") - print("--- END test stdout ---") - print("--- BEGIN test stderr ---") - print(stderr, end="") - print("--- END test stderr ---") fail("exit code was {}".format(p.returncode)) def test_no_rebuild(name, cmd, env={}): diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 8a938ef3c25f..eb31058e1c19 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -20,15 +20,9 @@ fn does_not_work_on_miri() { assert!(&x as *const _ as usize % 4 < 4); } -// We also use this to test some external crates, that we cannot depend on in the compiletest suite. - +// Make sure integration tests can access dev-dependencies #[test] fn entropy_rng() { - // Test `getrandom` directly (in multiple different versions). - let mut data = vec![0; 16]; - getrandom_1::getrandom(&mut data).unwrap(); - getrandom_2::getrandom(&mut data).unwrap(); - // Try seeding with "real" entropy. let mut rng = SmallRng::from_entropy(); let _val = rng.gen::(); diff --git a/test_dependencies/Cargo.lock b/test_dependencies/Cargo.lock new file mode 100644 index 000000000000..6b5e8c942244 --- /dev/null +++ b/test_dependencies/Cargo.lock @@ -0,0 +1,376 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "mio" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys", +] + +[[package]] +name = "miri-test-deps" +version = "0.1.0" +dependencies = [ + "getrandom 0.1.16", + "getrandom 0.2.7", + "libc", + "rand", + "tokio", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "proc-macro2" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom 0.2.7", +] + +[[package]] +name = "redox_syscall" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + +[[package]] +name = "smallvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" + +[[package]] +name = "socket2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "syn" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tokio" +version = "1.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c51a52ed6686dd62c320f9b89299e9dfb46f730c7a48e635c19f21d116cb1439" +dependencies = [ + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "once_cell", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" diff --git a/test_dependencies/Cargo.toml b/test_dependencies/Cargo.toml new file mode 100644 index 000000000000..edaa6a692603 --- /dev/null +++ b/test_dependencies/Cargo.toml @@ -0,0 +1,19 @@ +[package] +authors = ["Miri Team"] +description = "dependencies that unit tests can have" +license = "MIT OR Apache-2.0" +name = "miri-test-deps" +repository = "https://github.com/rust-lang/miri" +version = "0.1.0" +edition = "2021" + +[dependencies] +# all dependencies (and their transitive ones) listed here can be used in `tests/`. +tokio = { version = "1.0", features = ["full"] } +libc = "0.2" + +getrandom_1 = { package = "getrandom", version = "0.1" } +getrandom_2 = { package = "getrandom", version = "0.2" } +rand = { version = "0.8", features = ["small_rng"] } + +[workspace] diff --git a/test_dependencies/src/main.rs b/test_dependencies/src/main.rs new file mode 100644 index 000000000000..f328e4d9d04c --- /dev/null +++ b/test_dependencies/src/main.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/tests/compiletest.rs b/tests/compiletest.rs index ec49e80ca963..37b9de7327a2 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -1,8 +1,8 @@ use colored::*; use regex::Regex; -use std::env; -use std::path::PathBuf; -use ui_test::{color_eyre::Result, Config, Mode, OutputConflictHandling}; +use std::path::{Path, PathBuf}; +use std::{env, ffi::OsString}; +use ui_test::{color_eyre::Result, Config, DependencyBuilder, Mode, OutputConflictHandling}; fn miri_path() -> PathBuf { PathBuf::from(option_env!("MIRI").unwrap_or(env!("CARGO_BIN_EXE_miri"))) @@ -12,31 +12,31 @@ fn run_tests(mode: Mode, path: &str, target: Option) -> Result<()> { let in_rustc_test_suite = option_env!("RUSTC_STAGE").is_some(); // Add some flags we always want. - let mut flags = Vec::new(); - flags.push("--edition".to_owned()); - flags.push("2018".to_owned()); + let mut flags: Vec = Vec::new(); + flags.push("--edition".into()); + flags.push("2018".into()); if in_rustc_test_suite { // Less aggressive warnings to make the rustc toolstate management less painful. // (We often get warnings when e.g. a feature gets stabilized or some lint gets added/improved.) - flags.push("-Astable-features".to_owned()); - flags.push("-Aunused".to_owned()); + flags.push("-Astable-features".into()); + flags.push("-Aunused".into()); } else { - flags.push("-Dwarnings".to_owned()); - flags.push("-Dunused".to_owned()); + flags.push("-Dwarnings".into()); + flags.push("-Dunused".into()); } - if let Ok(sysroot) = env::var("MIRI_SYSROOT") { - flags.push("--sysroot".to_string()); + if let Some(sysroot) = env::var_os("MIRI_SYSROOT") { + flags.push("--sysroot".into()); flags.push(sysroot); } if let Ok(extra_flags) = env::var("MIRIFLAGS") { for flag in extra_flags.split_whitespace() { - flags.push(flag.to_string()); + flags.push(flag.into()); } } - flags.push("-Zui-testing".to_string()); + flags.push("-Zui-testing".into()); if let Some(target) = &target { - flags.push("--target".to_string()); - flags.push(target.clone()); + flags.push("--target".into()); + flags.push(target.into()); } let skip_ui_checks = env::var_os("MIRI_SKIP_UI_CHECKS").is_some(); @@ -51,6 +51,8 @@ fn run_tests(mode: Mode, path: &str, target: Option) -> Result<()> { // Pass on all arguments as filters. let path_filter = std::env::args().skip(1); + let use_std = env::var_os("MIRI_NO_STD").is_none(); + let config = Config { args: flags, target, @@ -61,6 +63,19 @@ fn run_tests(mode: Mode, path: &str, target: Option) -> Result<()> { path_filter: path_filter.collect(), program: miri_path(), output_conflict_handling, + dependencies_crate_manifest_path: use_std + .then(|| Path::new("test_dependencies").join("Cargo.toml")), + dependency_builder: Some(DependencyBuilder { + program: std::env::var_os("CARGO").unwrap().into(), + args: vec![ + "run".into(), + "--manifest-path".into(), + "cargo-miri/Cargo.toml".into(), + "--".into(), + "miri".into(), + ], + envs: vec![], + }), }; ui_test::run_tests(config) } @@ -107,6 +122,8 @@ regexes! { "[^ `]*/(rust[^/]*|checkout)/library/" => "RUSTLIB/", // erase platform file paths "sys/[a-z]+/" => "sys/PLATFORM/", + // erase paths into the crate registry + r"[^ ]*/\.cargo/registry/.*/(.*\.rs)" => "CARGO_REGISTRY/$1", } fn ui(mode: Mode, path: &str) -> Result<()> { diff --git a/tests/fail/concurrency/libc_pthread_create_main_terminate.rs b/tests/fail/concurrency/libc_pthread_create_main_terminate.rs index 169a021215d5..9da9fbf2029d 100644 --- a/tests/fail/concurrency/libc_pthread_create_main_terminate.rs +++ b/tests/fail/concurrency/libc_pthread_create_main_terminate.rs @@ -5,8 +5,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::{mem, ptr}; extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { diff --git a/tests/fail/concurrency/libc_pthread_join_detached.rs b/tests/fail/concurrency/libc_pthread_join_detached.rs index 6f0d45e2dc09..e81978fc9953 100644 --- a/tests/fail/concurrency/libc_pthread_join_detached.rs +++ b/tests/fail/concurrency/libc_pthread_join_detached.rs @@ -4,8 +4,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::{mem, ptr}; extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { diff --git a/tests/fail/concurrency/libc_pthread_join_joined.rs b/tests/fail/concurrency/libc_pthread_join_joined.rs index 77f59fabca5e..11e00429c6ce 100644 --- a/tests/fail/concurrency/libc_pthread_join_joined.rs +++ b/tests/fail/concurrency/libc_pthread_join_joined.rs @@ -4,8 +4,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::{mem, ptr}; extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { diff --git a/tests/fail/concurrency/libc_pthread_join_main.rs b/tests/fail/concurrency/libc_pthread_join_main.rs index aff28bcc9b57..f029f08772f2 100644 --- a/tests/fail/concurrency/libc_pthread_join_main.rs +++ b/tests/fail/concurrency/libc_pthread_join_main.rs @@ -4,8 +4,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::{ptr, thread}; fn main() { diff --git a/tests/fail/concurrency/libc_pthread_join_multiple.rs b/tests/fail/concurrency/libc_pthread_join_multiple.rs index d4d54d3a23fd..017036ab01e1 100644 --- a/tests/fail/concurrency/libc_pthread_join_multiple.rs +++ b/tests/fail/concurrency/libc_pthread_join_multiple.rs @@ -4,8 +4,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::thread; use std::{mem, ptr}; diff --git a/tests/fail/concurrency/libc_pthread_join_self.rs b/tests/fail/concurrency/libc_pthread_join_self.rs index b911b2db3a16..ae6148893173 100644 --- a/tests/fail/concurrency/libc_pthread_join_self.rs +++ b/tests/fail/concurrency/libc_pthread_join_self.rs @@ -6,8 +6,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::{ptr, thread}; fn main() { diff --git a/tests/fail/concurrency/too_few_args.rs b/tests/fail/concurrency/too_few_args.rs index 11e97ca290f4..4760fbb6b051 100644 --- a/tests/fail/concurrency/too_few_args.rs +++ b/tests/fail/concurrency/too_few_args.rs @@ -4,8 +4,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::{mem, ptr}; extern "C" fn thread_start() -> *mut libc::c_void { diff --git a/tests/fail/concurrency/too_many_args.rs b/tests/fail/concurrency/too_many_args.rs index dd44207a6255..6abe767dc8a7 100644 --- a/tests/fail/concurrency/too_many_args.rs +++ b/tests/fail/concurrency/too_many_args.rs @@ -4,8 +4,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::{mem, ptr}; extern "C" fn thread_start(_null: *mut libc::c_void, _x: i32) -> *mut libc::c_void { diff --git a/tests/fail/concurrency/unwind_top_of_stack.rs b/tests/fail/concurrency/unwind_top_of_stack.rs index 179ff9c146e8..bd49401e61f5 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.rs +++ b/tests/fail/concurrency/unwind_top_of_stack.rs @@ -5,8 +5,6 @@ #![feature(rustc_private, c_unwind)] -extern crate libc; - use std::{mem, ptr}; extern "C-unwind" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { diff --git a/tests/fail/fs/close_stdout.rs b/tests/fail/fs/close_stdout.rs index bc709fe36d57..86a6239f5f36 100644 --- a/tests/fail/fs/close_stdout.rs +++ b/tests/fail/fs/close_stdout.rs @@ -5,8 +5,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() { unsafe { libc::close(1); //~ ERROR: stdout cannot be closed diff --git a/tests/fail/fs/isolated_stdin.rs b/tests/fail/fs/isolated_stdin.rs index cd54de3bcecc..86b04a038354 100644 --- a/tests/fail/fs/isolated_stdin.rs +++ b/tests/fail/fs/isolated_stdin.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() -> std::io::Result<()> { let mut bytes = [0u8; 512]; unsafe { diff --git a/tests/fail/fs/read_from_stdout.rs b/tests/fail/fs/read_from_stdout.rs index 949fe88f4333..0fd8ba2fc419 100644 --- a/tests/fail/fs/read_from_stdout.rs +++ b/tests/fail/fs/read_from_stdout.rs @@ -3,8 +3,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() -> std::io::Result<()> { let mut bytes = [0u8; 512]; unsafe { diff --git a/tests/fail/fs/unix_open_missing_required_mode.rs b/tests/fail/fs/unix_open_missing_required_mode.rs index 1f6beadcb82f..4740dcebe920 100644 --- a/tests/fail/fs/unix_open_missing_required_mode.rs +++ b/tests/fail/fs/unix_open_missing_required_mode.rs @@ -3,8 +3,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() { test_file_open_missing_needed_mode(); } diff --git a/tests/fail/fs/write_to_stdin.rs b/tests/fail/fs/write_to_stdin.rs index 4ad7b648e1cf..0e9109fc6e23 100644 --- a/tests/fail/fs/write_to_stdin.rs +++ b/tests/fail/fs/write_to_stdin.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() -> std::io::Result<()> { let bytes = b"hello"; unsafe { diff --git a/tests/fail/sync/libc_pthread_cond_double_destroy.rs b/tests/fail/sync/libc_pthread_cond_double_destroy.rs index d0a4ac46cb33..90d5997f8712 100644 --- a/tests/fail/sync/libc_pthread_cond_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_cond_double_destroy.rs @@ -2,7 +2,6 @@ #![feature(rustc_private)] /// Test that destroying a pthread_cond twice fails, even without a check for number validity -extern crate libc; fn main() { unsafe { diff --git a/tests/fail/sync/libc_pthread_condattr_double_destroy.rs b/tests/fail/sync/libc_pthread_condattr_double_destroy.rs index c64b32381384..028a924196f2 100644 --- a/tests/fail/sync/libc_pthread_condattr_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_condattr_double_destroy.rs @@ -2,7 +2,6 @@ #![feature(rustc_private)] /// Test that destroying a pthread_condattr twice fails, even without a check for number validity -extern crate libc; fn main() { unsafe { diff --git a/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs index 8797e895d8c8..d87455877abc 100644 --- a/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs @@ -4,8 +4,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() { unsafe { let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); diff --git a/tests/fail/sync/libc_pthread_mutex_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_deadlock.rs index 7da6e5160000..f77f5c2e2022 100644 --- a/tests/fail/sync/libc_pthread_mutex_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_deadlock.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::cell::UnsafeCell; use std::sync::Arc; use std::thread; diff --git a/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs index 70a85aa0f989..b28101e20b24 100644 --- a/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs @@ -4,8 +4,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() { unsafe { let mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); diff --git a/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs b/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs index fc69ace36993..0f74446fa27e 100644 --- a/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs +++ b/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() { unsafe { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); diff --git a/tests/fail/sync/libc_pthread_mutex_double_destroy.rs b/tests/fail/sync/libc_pthread_mutex_double_destroy.rs index 9b539afc1992..89022f3b5625 100644 --- a/tests/fail/sync/libc_pthread_mutex_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_mutex_double_destroy.rs @@ -2,7 +2,6 @@ #![feature(rustc_private)] /// Test that destroying a pthread_mutex twice fails, even without a check for number validity -extern crate libc; fn main() { unsafe { diff --git a/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs index 944e86e106d7..ab6d9c7739d7 100644 --- a/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() { unsafe { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); diff --git a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs index c2bdce82b6f8..f259a4dee7d8 100644 --- a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs +++ b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() { unsafe { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); diff --git a/tests/fail/sync/libc_pthread_mutex_wrong_owner.rs b/tests/fail/sync/libc_pthread_mutex_wrong_owner.rs index eea4db711597..b8e57f8f74e9 100644 --- a/tests/fail/sync/libc_pthread_mutex_wrong_owner.rs +++ b/tests/fail/sync/libc_pthread_mutex_wrong_owner.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::cell::UnsafeCell; use std::sync::Arc; use std::thread; diff --git a/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs b/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs index 620dbb94a78a..ac6292570e49 100644 --- a/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs @@ -2,7 +2,6 @@ #![feature(rustc_private)] /// Test that destroying a pthread_mutexattr twice fails, even without a check for number validity -extern crate libc; fn main() { unsafe { diff --git a/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs b/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs index 67b77ff28647..ae7c1bbde72a 100644 --- a/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs +++ b/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { diff --git a/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs b/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs index 5bc5fe3c6bc4..9642595ca4e0 100644 --- a/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs +++ b/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { diff --git a/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs b/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs index 7e756c5bb88f..81b1661ce8d4 100644 --- a/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs @@ -2,7 +2,6 @@ #![feature(rustc_private)] /// Test that destroying a pthread_rwlock twice fails, even without a check for number validity -extern crate libc; fn main() { unsafe { diff --git a/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs index 76fceb315f44..158dd8c1cda3 100644 --- a/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs +++ b/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { diff --git a/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs b/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs index e971fd8c302a..23dda68c6a42 100644 --- a/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs +++ b/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::cell::UnsafeCell; use std::sync::Arc; use std::thread; diff --git a/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs b/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs index 29cfd36cafc2..fdcf8e41d36f 100644 --- a/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs +++ b/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { diff --git a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs index e9c5c17f3eba..adbb95fc28e8 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::cell::UnsafeCell; use std::sync::Arc; use std::thread; diff --git a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs index 5ed25344e7c7..a7d16caa7a49 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { diff --git a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs index 3d15370e83dd..070373255d32 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::cell::UnsafeCell; use std::sync::Arc; use std::thread; diff --git a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs index 14361bee54c0..867c6272c463 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { diff --git a/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs b/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs index 668ccb3ecaef..cff2a7a2e98c 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::cell::UnsafeCell; use std::sync::Arc; use std::thread; diff --git a/tests/fail/tokio_mvp.rs b/tests/fail/tokio_mvp.rs new file mode 100644 index 000000000000..7cb42c09a967 --- /dev/null +++ b/tests/fail/tokio_mvp.rs @@ -0,0 +1,7 @@ +//@compile-flags: -Zmiri-disable-isolation +//@error-pattern: can't call foreign function: epoll_create1 +//@normalize-stderr-test: " = note: inside .*\n" -> "" +//@only-target-linux: the errors differ too much between platforms + +#[tokio::main] +async fn main() {} diff --git a/tests/fail/tokio_mvp.stderr b/tests/fail/tokio_mvp.stderr new file mode 100644 index 000000000000..cff948f36408 --- /dev/null +++ b/tests/fail/tokio_mvp.stderr @@ -0,0 +1,19 @@ +error: unsupported operation: can't call foreign function: epoll_create1 + --> CARGO_REGISTRY/epoll.rs:LL:CC + | +LL | syscall!(epoll_create1(flag)).map(|ep| Selector { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't call foreign function: epoll_create1 + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = note: backtrace: +note: inside `main` at $DIR/tokio_mvp.rs:LL:CC + --> $DIR/tokio_mvp.rs:LL:CC + | +LL | #[tokio::main] + | ^^^^^^^^^^^^^^ + = note: this error originates in the macro `syscall` which comes from the expansion of the attribute macro `tokio::main` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/unsupported_signal.rs b/tests/fail/unsupported_signal.rs index e9bd340fcafb..20ebcc9bc473 100644 --- a/tests/fail/unsupported_signal.rs +++ b/tests/fail/unsupported_signal.rs @@ -3,8 +3,6 @@ //@ignore-target-windows: No libc on Windows #![feature(rustc_private)] -extern crate libc; - fn main() { unsafe { libc::signal(libc::SIGPIPE, libc::SIG_IGN); diff --git a/tests/panic/panic/unsupported_syscall.rs b/tests/panic/panic/unsupported_syscall.rs index a68917281466..27595bf1071f 100644 --- a/tests/panic/panic/unsupported_syscall.rs +++ b/tests/panic/panic/unsupported_syscall.rs @@ -3,8 +3,6 @@ //@compile-flags: -Zmiri-panic-on-unsupported #![feature(rustc_private)] -extern crate libc; - fn main() { unsafe { libc::syscall(0); diff --git a/tests/pass/calloc.rs b/tests/pass/calloc.rs index a9efb776b69e..e155d53ce812 100644 --- a/tests/pass/calloc.rs +++ b/tests/pass/calloc.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - use core::slice; fn main() { diff --git a/tests/pass/concurrency/libc_pthread_cond.rs b/tests/pass/concurrency/libc_pthread_cond.rs index eb491486be70..c5b0e86666a0 100644 --- a/tests/pass/concurrency/libc_pthread_cond.rs +++ b/tests/pass/concurrency/libc_pthread_cond.rs @@ -6,8 +6,6 @@ /// Test that conditional variable timeouts are working properly with both /// monotonic and system clocks. -extern crate libc; - use std::mem::MaybeUninit; use std::time::Instant; diff --git a/tests/pass/concurrency/linux-futex.rs b/tests/pass/concurrency/linux-futex.rs index f9c87e0723c5..43216481e76f 100644 --- a/tests/pass/concurrency/linux-futex.rs +++ b/tests/pass/concurrency/linux-futex.rs @@ -2,7 +2,6 @@ //@compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] -extern crate libc; use std::mem::MaybeUninit; use std::ptr; diff --git a/tests/pass/concurrency/tls_pthread_drop_order.rs b/tests/pass/concurrency/tls_pthread_drop_order.rs index c9e8b9271ccf..1ccc57da25fa 100644 --- a/tests/pass/concurrency/tls_pthread_drop_order.rs +++ b/tests/pass/concurrency/tls_pthread_drop_order.rs @@ -1,7 +1,6 @@ //@ignore-target-windows: No libc on Windows #![feature(rustc_private)] -extern crate libc; use std::mem; use std::ptr; diff --git a/tests/pass/foreign-fn-linkname.rs b/tests/pass/foreign-fn-linkname.rs index 391b182fda03..40aeb2ef6313 100644 --- a/tests/pass/foreign-fn-linkname.rs +++ b/tests/pass/foreign-fn-linkname.rs @@ -1,8 +1,6 @@ //ignore-windows: Uses POSIX APIs #![feature(rustc_private)] -extern crate libc; - use std::ffi::CString; mod mlibc { diff --git a/tests/pass/fs.rs b/tests/pass/fs.rs index aa5cd83c69cd..9d59fedb20ed 100644 --- a/tests/pass/fs.rs +++ b/tests/pass/fs.rs @@ -4,8 +4,6 @@ #![feature(rustc_private)] #![feature(io_error_more)] -extern crate libc; - use std::ffi::CString; use std::fs::{ create_dir, read_dir, read_link, remove_dir, remove_dir_all, remove_file, rename, File, diff --git a/tests/pass/fs_with_isolation.rs b/tests/pass/fs_with_isolation.rs index 41ada94e276e..f73e64ad17a2 100644 --- a/tests/pass/fs_with_isolation.rs +++ b/tests/pass/fs_with_isolation.rs @@ -4,8 +4,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::ffi::CString; use std::fs::{self, File}; use std::io::{Error, ErrorKind}; diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index 99b7c3f249f5..9b83ab45b0c0 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -5,8 +5,6 @@ use std::fs::{remove_file, File}; use std::os::unix::io::AsRawFd; -extern crate libc; - fn tmp() -> std::path::PathBuf { std::env::var("MIRI_TEMP") .map(std::path::PathBuf::from) diff --git a/tests/pass/linux-getrandom-without-isolation.rs b/tests/pass/linux-getrandom-without-isolation.rs index fea3bb3fdce9..12b42552bd5d 100644 --- a/tests/pass/linux-getrandom-without-isolation.rs +++ b/tests/pass/linux-getrandom-without-isolation.rs @@ -1,7 +1,6 @@ //@only-target-linux //@compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] -extern crate libc; use std::ptr; diff --git a/tests/pass/linux-getrandom.rs b/tests/pass/linux-getrandom.rs index 1d0ab6ed746a..e3309f480d36 100644 --- a/tests/pass/linux-getrandom.rs +++ b/tests/pass/linux-getrandom.rs @@ -1,6 +1,5 @@ //@only-target-linux #![feature(rustc_private)] -extern crate libc; use std::ptr; diff --git a/tests/pass/malloc.rs b/tests/pass/malloc.rs index d20ceddbb8ed..9066e2af25fa 100644 --- a/tests/pass/malloc.rs +++ b/tests/pass/malloc.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - use core::{ptr, slice}; fn main() { diff --git a/tests/pass/random.rs b/tests/pass/random.rs new file mode 100644 index 000000000000..808d1006d4f3 --- /dev/null +++ b/tests/pass/random.rs @@ -0,0 +1,22 @@ +use rand::{rngs::SmallRng, Rng, SeedableRng}; +// mac-os `getrandom_1` does some pointer shenanigans +//@compile-flags: -Zmiri-permissive-provenance + +fn main() { + // Test `getrandom` directly (in multiple different versions). + let mut data = vec![0; 16]; + getrandom_1::getrandom(&mut data).unwrap(); + getrandom_2::getrandom(&mut data).unwrap(); + + // Try seeding with "real" entropy. + let mut rng = SmallRng::from_entropy(); + let _val = rng.gen::(); + let _val = rng.gen::(); + let _val = rng.gen::(); + + // Also try per-thread RNG. + let mut rng = rand::thread_rng(); + let _val = rng.gen::(); + let _val = rng.gen::(); + let _val = rng.gen::(); +} diff --git a/tests/pass/regions-mock-trans.rs b/tests/pass/regions-mock-trans.rs index 5dafc88756f1..7432ea958261 100644 --- a/tests/pass/regions-mock-trans.rs +++ b/tests/pass/regions-mock-trans.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::mem; struct Arena(()); diff --git a/ui_test/Cargo.lock b/ui_test/Cargo.lock index 2065cc34bef8..9addea9b19d0 100644 --- a/ui_test/Cargo.lock +++ b/ui_test/Cargo.lock @@ -67,6 +67,37 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "camino" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "869119e97797867fd90f5e22af7d0bd274bd4635ebb9eb68c04f3f513ae6c412" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3abb7553d5b9b8421c6de7cb02606ff15e0c6eea7d8eadd75ef013fd636bec36" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", +] + [[package]] name = "cc" version = "1.0.73" @@ -390,6 +421,9 @@ name = "semver" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" +dependencies = [ + "serde", +] [[package]] name = "serde" @@ -497,6 +531,7 @@ dependencies = [ name = "ui_test" version = "0.1.0" dependencies = [ + "cargo_metadata", "color-eyre", "colored", "crossbeam", diff --git a/ui_test/Cargo.toml b/ui_test/Cargo.toml index cdc5e5db472c..bb14eb7ecfe3 100644 --- a/ui_test/Cargo.toml +++ b/ui_test/Cargo.toml @@ -18,4 +18,4 @@ lazy_static = "1.4.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" color-eyre = { version = "0.6.1", default-features = false, features = ["capture-spantrace"] } - +cargo_metadata = "0.15" diff --git a/ui_test/README.md b/ui_test/README.md index f1b1a5d67e0a..3db3361faa53 100644 --- a/ui_test/README.md +++ b/ui_test/README.md @@ -47,3 +47,5 @@ their command specifies, or the test will fail without even being run. * `ignore-target-*` and `only-target-*` opereate solely on the triple, instead of supporting things like `macos` * only `//~` comments can be individualized per revision +* only supports `ui` tests +* tests are run in named order, so you can prefix slow tests with `0` in order to make them get run first diff --git a/ui_test/src/dependencies.rs b/ui_test/src/dependencies.rs new file mode 100644 index 000000000000..ab3a0156595f --- /dev/null +++ b/ui_test/src/dependencies.rs @@ -0,0 +1,137 @@ +use color_eyre::eyre::{bail, Result}; +use std::{ + collections::{HashMap, HashSet}, + path::{Path, PathBuf}, + process::Command, +}; + +use crate::Config; + +#[derive(Default, Debug)] +pub struct Dependencies { + /// All paths that must be imported with `-L dependency=`. This is for + /// finding proc macros run on the host and dependencies for the target. + pub import_paths: Vec, + /// The name as chosen in the `Cargo.toml` and its corresponding rmeta file. + pub dependencies: Vec<(String, PathBuf)>, +} + +/// Compiles dependencies and returns the crate names and corresponding rmeta files. +pub fn build_dependencies(config: &Config) -> Result { + let manifest_path = match &config.dependencies_crate_manifest_path { + Some(path) => path, + None => return Ok(Default::default()), + }; + let (program, args, envs): (&Path, &[_], &[_]) = match &config.dependency_builder { + Some(db) => (&db.program, &db.args, &db.envs), + None => (Path::new("cargo"), &[], &[]), + }; + let mut build = Command::new(program); + build.args(args); + // HACK: we're using `cargo run` (or `cargo miri run`), because the latter does not + // support `cargo miri build` yet. + build.arg("run"); + + if let Some(target) = &config.target { + build.arg(format!("--target={target}")); + } + + // Reusable closure for setting up the environment both for artifact generation and `cargo_metadata` + let setup_command = |cmd: &mut Command| { + cmd.envs(envs.iter().map(|(k, v)| (k, v))); + cmd.arg("--manifest-path").arg(manifest_path); + }; + + setup_command(&mut build); + build + .arg("--target-dir=target/test_dependencies") + .arg("--message-format=json") + .arg("-Zunstable-options"); + + let output = build.output()?; + + if !output.status.success() { + let stdout = String::from_utf8(output.stdout)?; + let stderr = String::from_utf8(output.stderr)?; + bail!("failed to compile dependencies:\nstderr:\n{stderr}\n\nstdout:{stdout}"); + } + + // Collect all artifacts generated + let output = output.stdout; + let output = String::from_utf8(output)?; + let mut import_paths: HashSet = HashSet::new(); + let mut artifacts: HashMap<_, _> = output + .lines() + .filter_map(|line| { + let message = serde_json::from_str::(line).ok()?; + if let cargo_metadata::Message::CompilerArtifact(artifact) = message { + for filename in &artifact.filenames { + import_paths.insert(filename.parent().unwrap().into()); + } + let filename = artifact + .filenames + .into_iter() + .find(|filename| filename.extension() == Some("rmeta"))?; + Some((artifact.package_id, filename.into_std_path_buf())) + } else { + None + } + }) + .collect(); + + // Check which crates are mentioned in the crate itself + let mut metadata = cargo_metadata::MetadataCommand::new().cargo_command(); + setup_command(&mut metadata); + let output = metadata.output()?; + + if !output.status.success() { + let stdout = String::from_utf8(output.stdout)?; + let stderr = String::from_utf8(output.stderr)?; + bail!("failed to run cargo-metadata:\nstderr:\n{stderr}\n\nstdout:{stdout}"); + } + + let output = output.stdout; + let output = String::from_utf8(output)?; + + for line in output.lines() { + if !line.starts_with('{') { + continue; + } + let metadata: cargo_metadata::Metadata = serde_json::from_str(line)?; + // Only take artifacts that are defined in the Cargo.toml + + // First, find the root artifact + let root = metadata + .packages + .iter() + .find(|package| { + package.manifest_path.as_std_path().canonicalize().unwrap() + == manifest_path.canonicalize().unwrap() + }) + .unwrap(); + + // Then go over all of its dependencies + let dependencies = root + .dependencies + .iter() + .map(|package| { + // Get the id for the package matching the version requirement of the dep + let id = &metadata + .packages + .iter() + .find(|&dep| dep.name == package.name && package.req.matches(&dep.version)) + .expect("dependency does not exist") + .id; + // Return the name chosen in `Cargo.toml` and the path to the corresponding artifact + ( + package.rename.clone().unwrap_or_else(|| package.name.clone()), + artifacts.remove(id).expect("package without artifact"), + ) + }) + .collect(); + let import_paths = import_paths.into_iter().collect(); + return Ok(Dependencies { dependencies, import_paths }); + } + + bail!("no json found in cargo-metadata output") +} diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 917e382379ab..4318e8a8e034 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -1,6 +1,7 @@ #![allow(clippy::enum_variant_names, clippy::useless_format, clippy::too_many_arguments)] use std::collections::VecDeque; +use std::ffi::OsString; use std::fmt::Write; use std::path::{Path, PathBuf}; use std::process::{Command, ExitStatus}; @@ -14,8 +15,10 @@ use parser::{ErrorMatch, Pattern}; use regex::Regex; use rustc_stderr::{Level, Message}; +use crate::dependencies::build_dependencies; use crate::parser::{Comments, Condition}; +mod dependencies; mod parser; mod rustc_stderr; #[cfg(test)] @@ -24,7 +27,7 @@ mod tests; #[derive(Debug)] pub struct Config { /// Arguments passed to the binary that is executed. - pub args: Vec, + pub args: Vec, /// `None` to run on the host, otherwise a target triple pub target: Option, /// Filters applied to stderr output before processing it @@ -38,6 +41,18 @@ pub struct Config { pub output_conflict_handling: OutputConflictHandling, /// Only run tests with one of these strings in their path/name pub path_filter: Vec, + /// Path to a `Cargo.toml` that describes which dependencies the tests can access. + pub dependencies_crate_manifest_path: Option, + /// Can be used to override what command to run instead of `cargo` to build the + /// dependencies in `manifest_path` + pub dependency_builder: Option, +} + +#[derive(Debug)] +pub struct DependencyBuilder { + pub program: PathBuf, + pub args: Vec, + pub envs: Vec<(String, String)>, } #[derive(Debug)] @@ -53,12 +68,26 @@ pub enum OutputConflictHandling { pub type Filter = Vec<(Regex, &'static str)>; -pub fn run_tests(config: Config) -> Result<()> { +pub fn run_tests(mut config: Config) -> Result<()> { eprintln!(" Compiler flags: {:?}", config.args); // Get the triple with which to run the tests let target = config.target.clone().unwrap_or_else(|| config.get_host()); + let dependencies = build_dependencies(&config)?; + for (name, dependency) in dependencies.dependencies { + config.args.push("--extern".into()); + let mut dep = OsString::from(name); + dep.push("="); + dep.push(dependency); + config.args.push(dep); + } + for import_path in dependencies.import_paths { + config.args.push("-L".into()); + config.args.push(import_path.into()); + } + let config = config; + // A channel for files to process let (submit, receive) = crossbeam::channel::unbounded(); @@ -294,9 +323,7 @@ fn run_test( for arg in &comments.compile_flags { miri.arg(arg); } - for (k, v) in &comments.env_vars { - miri.env(k, v); - } + miri.envs(comments.env_vars.iter().map(|(k, v)| (k, v))); let output = miri.output().expect("could not execute miri"); let mut errors = config.mode.ok(output.status); let stderr = check_test_result( diff --git a/ui_test/src/tests.rs b/ui_test/src/tests.rs index 96c0f362b675..8b0bd517a105 100644 --- a/ui_test/src/tests.rs +++ b/ui_test/src/tests.rs @@ -16,6 +16,8 @@ fn config() -> Config { path_filter: vec![], program: PathBuf::from("cake"), output_conflict_handling: OutputConflictHandling::Error, + dependencies_crate_manifest_path: None, + dependency_builder: None, } } From c81cfe240ab478b79d6167ebba28eb8fba3cd24c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Jul 2022 15:47:09 -0400 Subject: [PATCH 3560/5092] cargo-miri: reorder --target to after the user-defined commands --- cargo-miri/bin.rs | 48 ++++++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 4c9f3aabaab4..d294bc5b127a 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -584,9 +584,31 @@ fn phase_cargo_miri(mut args: env::Args) { MiriCommand::Run => "run", MiriCommand::Setup => return, // `cargo miri setup` stops here. }; + let metadata = get_cargo_metadata(); let mut cmd = cargo(); cmd.arg(cargo_cmd); + // Forward all arguments before `--` other than `--target-dir` and its value to Cargo. + let mut target_dir = None; + for arg in ArgSplitFlagValue::new(&mut args, "--target-dir") { + match arg { + Ok(value) => { + if target_dir.is_some() { + show_error(format!("`--target-dir` is provided more than once")); + } + target_dir = Some(value.into()); + } + Err(arg) => { + cmd.arg(arg); + } + } + } + // Detect the target directory if it's not specified via `--target-dir`. + let target_dir = target_dir.get_or_insert_with(|| metadata.target_directory.clone()); + // Set `--target-dir` to `miri` inside the original target directory. + target_dir.push("miri"); + cmd.arg("--target-dir").arg(target_dir); + // Make sure we know the build target, and cargo does, too. // This is needed to make the `CARGO_TARGET_*_RUNNER` env var do something, // and it later helps us detect which crates are proc-macro/build-script @@ -602,32 +624,6 @@ fn phase_cargo_miri(mut args: env::Args) { &host }; - let mut target_dir = None; - - // Forward all arguments before `--` other than `--target-dir` and its value to Cargo. - for arg in ArgSplitFlagValue::new(&mut args, "--target-dir") { - match arg { - Ok(value) => { - if target_dir.is_some() { - show_error(format!("`--target-dir` is provided more than once")); - } - target_dir = Some(value.into()); - } - Err(arg) => { - cmd.arg(arg); - } - } - } - - let metadata = get_cargo_metadata(); - - // Detect the target directory if it's not specified via `--target-dir`. - let target_dir = target_dir.get_or_insert_with(|| metadata.target_directory.clone()); - - // Set `--target-dir` to `miri` inside the original target directory. - target_dir.push("miri"); - cmd.arg("--target-dir").arg(target_dir); - // Forward all further arguments after `--` to cargo. cmd.arg("--").args(args); From ff4666f39cfa48d5a887a62f49c5f0c04b44642a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Jul 2022 16:02:06 -0400 Subject: [PATCH 3561/5092] rustup --- rust-version | 2 +- src/concurrency/data_race.rs | 50 +++---- src/concurrency/weak_memory.rs | 50 ++++--- src/diagnostics.rs | 2 +- src/eval.rs | 4 +- src/helpers.rs | 105 ++++++++------ src/intptrcast.rs | 10 +- src/lib.rs | 9 +- src/machine.rs | 151 +++++++++++--------- src/operator.rs | 12 +- src/shims/backtrace.rs | 16 +-- src/shims/dlsym.rs | 4 +- src/shims/env.rs | 49 ++++--- src/shims/foreign_items.rs | 20 +-- src/shims/intrinsics/atomic.rs | 34 ++--- src/shims/intrinsics/mod.rs | 12 +- src/shims/intrinsics/simd.rs | 20 +-- src/shims/mod.rs | 10 +- src/shims/os_str.rs | 23 +-- src/shims/panic.rs | 12 +- src/shims/time.rs | 23 +-- src/shims/tls.rs | 12 +- src/shims/unix/dlsym.rs | 4 +- src/shims/unix/foreign_items.rs | 4 +- src/shims/unix/freebsd/dlsym.rs | 4 +- src/shims/unix/freebsd/foreign_items.rs | 4 +- src/shims/unix/fs.rs | 112 ++++++++------- src/shims/unix/linux/dlsym.rs | 4 +- src/shims/unix/linux/foreign_items.rs | 12 +- src/shims/unix/linux/sync.rs | 4 +- src/shims/unix/macos/dlsym.rs | 4 +- src/shims/unix/macos/foreign_items.rs | 4 +- src/shims/unix/sync.rs | 177 +++++++++++++++--------- src/shims/unix/thread.rs | 20 +-- src/shims/windows/dlsym.rs | 4 +- src/shims/windows/foreign_items.rs | 4 +- src/shims/windows/sync.rs | 20 ++- src/stacked_borrows/diagnostics.rs | 15 +- src/stacked_borrows/mod.rs | 74 ++++------ src/stacked_borrows/stack.rs | 11 +- src/sync.rs | 2 +- src/thread.rs | 34 +++-- 42 files changed, 627 insertions(+), 520 deletions(-) diff --git a/rust-version b/rust-version index 38f4b2bda5f2..f456ded7f462 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -29c5a028b0c92aa5da6a8eb6d6585a389fcf1035 +a7468c60f8dbf5feb23ad840b174d7e57113a846 diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 8ee8df7445b3..3f05925d3438 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -439,11 +439,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// Atomic variant of read_scalar_at_offset. fn read_scalar_at_offset_atomic( &self, - op: &OpTy<'tcx, Tag>, + op: &OpTy<'tcx, Provenance>, offset: u64, layout: TyAndLayout<'tcx>, atomic: AtomicReadOrd, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { + ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_ref(); let value_place = this.deref_operand_and_offset(op, offset, layout)?; this.read_scalar_atomic(&value_place, atomic) @@ -452,9 +452,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// Atomic variant of write_scalar_at_offset. fn write_scalar_at_offset_atomic( &mut self, - op: &OpTy<'tcx, Tag>, + op: &OpTy<'tcx, Provenance>, offset: u64, - value: impl Into>, + value: impl Into>, layout: TyAndLayout<'tcx>, atomic: AtomicWriteOrd, ) -> InterpResult<'tcx> { @@ -466,9 +466,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// Perform an atomic read operation at the memory location. fn read_scalar_atomic( &self, - place: &MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Provenance>, atomic: AtomicReadOrd, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { + ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_ref(); // This will read from the last store in the modification order of this location. In case // weak memory emulation is enabled, this may not be the store we will pick to actually read from and return. @@ -485,8 +485,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// Perform an atomic write operation at the memory location. fn write_scalar_atomic( &mut self, - val: ScalarMaybeUninit, - dest: &MPlaceTy<'tcx, Tag>, + val: ScalarMaybeUninit, + dest: &MPlaceTy<'tcx, Provenance>, atomic: AtomicWriteOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -504,12 +504,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// Perform an atomic operation on a memory location. fn atomic_op_immediate( &mut self, - place: &MPlaceTy<'tcx, Tag>, - rhs: &ImmTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Provenance>, + rhs: &ImmTy<'tcx, Provenance>, op: mir::BinOp, neg: bool, atomic: AtomicRwOrd, - ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { + ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { let this = self.eval_context_mut(); this.validate_overlapping_atomic(place)?; @@ -535,10 +535,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// scalar value, the old value is returned. fn atomic_exchange_scalar( &mut self, - place: &MPlaceTy<'tcx, Tag>, - new: ScalarMaybeUninit, + place: &MPlaceTy<'tcx, Provenance>, + new: ScalarMaybeUninit, atomic: AtomicRwOrd, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { + ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_mut(); this.validate_overlapping_atomic(place)?; @@ -555,11 +555,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// scalar value, the old value is returned. fn atomic_min_max_scalar( &mut self, - place: &MPlaceTy<'tcx, Tag>, - rhs: ImmTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Provenance>, + rhs: ImmTy<'tcx, Provenance>, min: bool, atomic: AtomicRwOrd, - ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { + ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { let this = self.eval_context_mut(); this.validate_overlapping_atomic(place)?; @@ -595,13 +595,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// identical. fn atomic_compare_exchange_scalar( &mut self, - place: &MPlaceTy<'tcx, Tag>, - expect_old: &ImmTy<'tcx, Tag>, - new: ScalarMaybeUninit, + place: &MPlaceTy<'tcx, Provenance>, + expect_old: &ImmTy<'tcx, Provenance>, + new: ScalarMaybeUninit, success: AtomicRwOrd, fail: AtomicReadOrd, can_fail_spuriously: bool, - ) -> InterpResult<'tcx, Immediate> { + ) -> InterpResult<'tcx, Immediate> { use rand::Rng as _; let this = self.eval_context_mut(); @@ -651,7 +651,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// associated memory-place and on the current thread. fn validate_atomic_load( &self, - place: &MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Provenance>, atomic: AtomicReadOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); @@ -674,7 +674,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// associated memory-place and on the current thread. fn validate_atomic_store( &mut self, - place: &MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Provenance>, atomic: AtomicWriteOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -697,7 +697,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// at the associated memory place and on the current thread. fn validate_atomic_rmw( &mut self, - place: &MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Provenance>, atomic: AtomicRwOrd, ) -> InterpResult<'tcx> { use AtomicRwOrd::*; @@ -1047,7 +1047,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// Generic atomic operation implementation fn validate_atomic_op( &self, - place: &MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Provenance>, atomic: A, description: &str, mut op: impl FnMut( diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index f7cc9c4732ac..137a9f43d4ee 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -83,7 +83,8 @@ use rustc_const_eval::interpret::{ use rustc_data_structures::fx::FxHashMap; use crate::{ - AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, Tag, ThreadManager, VClock, VTimestamp, VectorIdx, + AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, Provenance, ThreadManager, VClock, VTimestamp, + VectorIdx, }; use super::{ @@ -127,7 +128,7 @@ struct StoreElement { // FIXME: this means the store is either fully initialized or fully uninitialized; // we will have to change this if we want to support atomics on // partially initialized data. - val: ScalarMaybeUninit, + val: ScalarMaybeUninit, /// Timestamp of first loads from this store element by each thread /// Behind a RefCell to keep load op take &self @@ -174,7 +175,7 @@ impl StoreBufferAlloc { fn get_or_create_store_buffer<'tcx>( &self, range: AllocRange, - init: ScalarMaybeUninit, + init: ScalarMaybeUninit, ) -> InterpResult<'tcx, Ref<'_, StoreBuffer>> { let access_type = self.store_buffers.borrow().access_type(range); let pos = match access_type { @@ -199,7 +200,7 @@ impl StoreBufferAlloc { fn get_or_create_store_buffer_mut<'tcx>( &mut self, range: AllocRange, - init: ScalarMaybeUninit, + init: ScalarMaybeUninit, ) -> InterpResult<'tcx, &mut StoreBuffer> { let buffers = self.store_buffers.get_mut(); let access_type = buffers.access_type(range); @@ -220,7 +221,7 @@ impl StoreBufferAlloc { } impl<'mir, 'tcx: 'mir> StoreBuffer { - fn new(init: ScalarMaybeUninit) -> Self { + fn new(init: ScalarMaybeUninit) -> Self { let mut buffer = VecDeque::new(); buffer.reserve(STORE_BUFFER_LIMIT); let mut ret = Self { buffer }; @@ -253,7 +254,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { is_seqcst: bool, rng: &mut (impl rand::Rng + ?Sized), validate: impl FnOnce() -> InterpResult<'tcx>, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { + ) -> InterpResult<'tcx, ScalarMaybeUninit> { // Having a live borrow to store_buffer while calling validate_atomic_load is fine // because the race detector doesn't touch store_buffer @@ -278,7 +279,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { fn buffered_write( &mut self, - val: ScalarMaybeUninit, + val: ScalarMaybeUninit, global: &DataRaceState, thread_mgr: &ThreadManager<'_, '_>, is_seqcst: bool, @@ -366,7 +367,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { /// ATOMIC STORE IMPL in the paper (except we don't need the location's vector clock) fn store_impl( &mut self, - val: ScalarMaybeUninit, + val: ScalarMaybeUninit, index: VectorIdx, thread_clock: &VClock, is_seqcst: bool, @@ -408,7 +409,11 @@ impl StoreElement { /// buffer regardless of subsequent loads by the same thread; if the earliest load of another /// thread doesn't happen before the current one, then no subsequent load by the other thread /// can happen before the current one. - fn load_impl(&self, index: VectorIdx, clocks: &ThreadClockSet) -> ScalarMaybeUninit { + fn load_impl( + &self, + index: VectorIdx, + clocks: &ThreadClockSet, + ) -> ScalarMaybeUninit { let _ = self.loads.borrow_mut().try_insert(index, clocks.clock[index]); self.val } @@ -421,7 +426,10 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: // If weak memory emulation is enabled, check if this atomic op imperfectly overlaps with a previous // atomic read or write. If it does, then we require it to be ordered (non-racy) with all previous atomic // accesses on all the bytes in range - fn validate_overlapping_atomic(&self, place: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn validate_overlapping_atomic( + &self, + place: &MPlaceTy<'tcx, Provenance>, + ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; if let crate::AllocExtra { @@ -448,10 +456,10 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: fn buffered_atomic_rmw( &mut self, - new_val: ScalarMaybeUninit, - place: &MPlaceTy<'tcx, Tag>, + new_val: ScalarMaybeUninit, + place: &MPlaceTy<'tcx, Provenance>, atomic: AtomicRwOrd, - init: ScalarMaybeUninit, + init: ScalarMaybeUninit, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; @@ -474,11 +482,11 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: fn buffered_atomic_read( &self, - place: &MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Provenance>, atomic: AtomicReadOrd, - latest_in_mo: ScalarMaybeUninit, + latest_in_mo: ScalarMaybeUninit, validate: impl FnOnce() -> InterpResult<'tcx>, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { + ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_ref(); if let Some(global) = &this.machine.data_race { let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; @@ -510,10 +518,10 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: fn buffered_atomic_write( &mut self, - val: ScalarMaybeUninit, - dest: &MPlaceTy<'tcx, Tag>, + val: ScalarMaybeUninit, + dest: &MPlaceTy<'tcx, Provenance>, atomic: AtomicWriteOrd, - init: ScalarMaybeUninit, + init: ScalarMaybeUninit, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(dest.ptr)?; @@ -555,9 +563,9 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: /// to perform load_impl on the latest store element fn perform_read_on_buffered_latest( &self, - place: &MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Provenance>, atomic: AtomicReadOrd, - init: ScalarMaybeUninit, + init: ScalarMaybeUninit, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 1c6cfa096863..6a692059be92 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -65,7 +65,7 @@ pub enum NonHaltingDiagnostic { CreatedPointerTag(NonZeroU64, Option<(AllocId, AllocRange)>), /// This `Item` was popped from the borrow stack, either due to an access with the given tag or /// a deallocation when the second argument is `None`. - PoppedPointerTag(Item, Option<(SbTagExtra, AccessKind)>), + PoppedPointerTag(Item, Option<(ProvenanceExtra, AccessKind)>), CreatedCallId(CallId), CreatedAlloc(AllocId, Size, Align, MemoryKind), FreedAlloc(AllocId), diff --git a/src/eval.rs b/src/eval.rs index 996d04a2c57c..0f354aa54949 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -165,7 +165,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( entry_id: DefId, entry_type: EntryFnType, config: &MiriConfig, -) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, MPlaceTy<'tcx, Tag>)> { +) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, MPlaceTy<'tcx, Provenance>)> { let param_env = ty::ParamEnv::reveal_all(); let layout_cx = LayoutCx { tcx, param_env }; let mut ecx = InterpCx::new( @@ -202,7 +202,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Third argument (`argv`): created from `config.args`. let argv = { // Put each argument in memory, collect pointers. - let mut argvs = Vec::>::new(); + let mut argvs = Vec::>::new(); for arg in config.args.iter() { // Make space for `0` terminator. let size = u64::try_from(arg.len()).unwrap().checked_add(1).unwrap(); diff --git a/src/helpers.rs b/src/helpers.rs index 190eb2098ad0..01fc8e0df3f0 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -84,7 +84,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Evaluates the scalar at the specified path. Returns Some(val) /// if the path could be resolved, and None otherwise - fn eval_path_scalar(&self, path: &[&str]) -> InterpResult<'tcx, Scalar> { + fn eval_path_scalar(&self, path: &[&str]) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_ref(); let instance = this.resolve_path(path); let cid = GlobalId { instance, promoted: None }; @@ -94,7 +94,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Helper function to get a `libc` constant as a `Scalar`. - fn eval_libc(&self, name: &str) -> InterpResult<'tcx, Scalar> { + fn eval_libc(&self, name: &str) -> InterpResult<'tcx, Scalar> { self.eval_path_scalar(&["libc", name]) } @@ -105,7 +105,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Helper function to get a `windows` constant as a `Scalar`. - fn eval_windows(&self, module: &str, name: &str) -> InterpResult<'tcx, Scalar> { + fn eval_windows(&self, module: &str, name: &str) -> InterpResult<'tcx, Scalar> { self.eval_context_ref().eval_path_scalar(&["std", "sys", "windows", module, name]) } @@ -134,9 +134,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Project to the given *named* field of the mplace (which must be a struct or union type). fn mplace_field_named( &self, - mplace: &MPlaceTy<'tcx, Tag>, + mplace: &MPlaceTy<'tcx, Provenance>, name: &str, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, Tag>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> { let this = self.eval_context_ref(); let adt = mplace.layout.ty.ty_adt_def().unwrap(); for (idx, field) in adt.non_enum_variant().fields.iter().enumerate() { @@ -150,7 +150,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Write an int of the appropriate size to `dest`. The target type may be signed or unsigned, /// we try to do the right thing anyway. `i128` can fit all integer types except for `u128` so /// this method is fine for almost all integer types. - fn write_int(&mut self, i: impl Into, dest: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn write_int( + &mut self, + i: impl Into, + dest: &PlaceTy<'tcx, Provenance>, + ) -> InterpResult<'tcx> { assert!(dest.layout.abi.is_scalar(), "write_int on non-scalar type {}", dest.layout.ty); let val = if dest.layout.abi.is_signed() { Scalar::from_int(i, dest.layout.size) @@ -164,7 +168,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_int_fields( &mut self, values: &[i128], - dest: &MPlaceTy<'tcx, Tag>, + dest: &MPlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); for (idx, &val) in values.iter().enumerate() { @@ -178,7 +182,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_int_fields_named( &mut self, values: &[(&str, i128)], - dest: &MPlaceTy<'tcx, Tag>, + dest: &MPlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); for &(name, val) in values.iter() { @@ -189,24 +193,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Write a 0 of the appropriate size to `dest`. - fn write_null(&mut self, dest: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn write_null(&mut self, dest: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { self.write_int(0, dest) } /// Test if this pointer equals 0. - fn ptr_is_null(&self, ptr: Pointer>) -> InterpResult<'tcx, bool> { + fn ptr_is_null(&self, ptr: Pointer>) -> InterpResult<'tcx, bool> { Ok(ptr.addr().bytes() == 0) } /// Get the `Place` for a local - fn local_place(&mut self, local: mir::Local) -> InterpResult<'tcx, PlaceTy<'tcx, Tag>> { + fn local_place(&mut self, local: mir::Local) -> InterpResult<'tcx, PlaceTy<'tcx, Provenance>> { let this = self.eval_context_mut(); let place = mir::Place { local, projection: List::empty() }; this.eval_place(place) } /// Generate some random bytes, and write them to `dest`. - fn gen_random(&mut self, ptr: Pointer>, len: u64) -> InterpResult<'tcx> { + fn gen_random(&mut self, ptr: Pointer>, len: u64) -> InterpResult<'tcx> { // Some programs pass in a null pointer and a length of 0 // to their platform's random-generation function (e.g. getrandom()) // on Linux. For compatibility with these programs, we don't perform @@ -240,8 +244,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, f: ty::Instance<'tcx>, caller_abi: Abi, - args: &[Immediate], - dest: Option<&PlaceTy<'tcx, Tag>>, + args: &[Immediate], + dest: Option<&PlaceTy<'tcx, Provenance>>, stack_pop: StackPopCleanup, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -285,7 +289,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// The range is relative to `place`. fn visit_freeze_sensitive( &self, - place: &MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Provenance>, size: Size, mut action: impl FnMut(AllocRange, bool) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { @@ -304,7 +308,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut cur_addr = start_addr; // Called when we detected an `UnsafeCell` at the given offset and size. // Calls `action` and advances `cur_ptr`. - let mut unsafe_cell_action = |unsafe_cell_ptr: &Pointer>, + let mut unsafe_cell_action = |unsafe_cell_ptr: &Pointer>, unsafe_cell_size: Size| { // We assume that we are given the fields in increasing offset order, // and nothing else changes. @@ -359,7 +363,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// whether we are inside an `UnsafeCell` or not. struct UnsafeCellVisitor<'ecx, 'mir, 'tcx, F> where - F: FnMut(&MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>, + F: FnMut(&MPlaceTy<'tcx, Provenance>) -> InterpResult<'tcx>, { ecx: &'ecx MiriEvalContext<'mir, 'tcx>, unsafe_cell_action: F, @@ -368,9 +372,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx impl<'ecx, 'mir, 'tcx: 'mir, F> ValueVisitor<'mir, 'tcx, Evaluator<'mir, 'tcx>> for UnsafeCellVisitor<'ecx, 'mir, 'tcx, F> where - F: FnMut(&MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>, + F: FnMut(&MPlaceTy<'tcx, Provenance>) -> InterpResult<'tcx>, { - type V = MPlaceTy<'tcx, Tag>; + type V = MPlaceTy<'tcx, Provenance>; #[inline(always)] fn ecx(&self) -> &MiriEvalContext<'mir, 'tcx> { @@ -378,7 +382,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Hook to detect `UnsafeCell`. - fn visit_value(&mut self, v: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn visit_value(&mut self, v: &MPlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty); let is_unsafe_cell = match v.layout.ty.kind() { ty::Adt(adt, _) => @@ -421,8 +425,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Make sure we visit aggregrates in increasing offset order. fn visit_aggregate( &mut self, - place: &MPlaceTy<'tcx, Tag>, - fields: impl Iterator>>, + place: &MPlaceTy<'tcx, Provenance>, + fields: impl Iterator>>, ) -> InterpResult<'tcx> { match place.layout.fields { FieldsShape::Array { .. } => { @@ -432,8 +436,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } FieldsShape::Arbitrary { .. } => { // Gather the subplaces and sort them before visiting. - let mut places = - fields.collect::>>>()?; + let mut places = fields + .collect::>>>()?; // we just compare offsets, the abs. value never matters places.sort_by_key(|place| place.ptr.addr()); self.walk_aggregate(place, places.into_iter().map(Ok)) @@ -447,7 +451,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn visit_union( &mut self, - _v: &MPlaceTy<'tcx, Tag>, + _v: &MPlaceTy<'tcx, Provenance>, _fields: NonZeroUsize, ) -> InterpResult<'tcx> { bug!("we should have already handled unions in `visit_value`") @@ -511,7 +515,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Get last error variable as a place, lazily allocating thread-local storage for it if /// necessary. - fn last_error_place(&mut self) -> InterpResult<'tcx, MPlaceTy<'tcx, Tag>> { + fn last_error_place(&mut self) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> { let this = self.eval_context_mut(); if let Some(errno_place) = this.active_thread_ref().last_error { Ok(errno_place) @@ -526,14 +530,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Sets the last error variable. - fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { + fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let errno_place = this.last_error_place()?; this.write_scalar(scalar, &errno_place.into()) } /// Gets the last error variable. - fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { + fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let errno_place = this.last_error_place()?; this.read_scalar(&errno_place.into())?.check_init() @@ -541,7 +545,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// This function tries to produce the most similar OS error from the `std::io::ErrorKind` /// as a platform-specific errnum. - fn io_error_to_errnum(&self, err_kind: std::io::ErrorKind) -> InterpResult<'tcx, Scalar> { + fn io_error_to_errnum( + &self, + err_kind: std::io::ErrorKind, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_ref(); let target = &this.tcx.sess.target; if target.families.iter().any(|f| f == "unix") { @@ -575,7 +582,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// The inverse of `io_error_to_errnum`. - fn errnum_to_io_error(&self, errnum: Scalar) -> InterpResult<'tcx, std::io::ErrorKind> { + fn errnum_to_io_error( + &self, + errnum: Scalar, + ) -> InterpResult<'tcx, std::io::ErrorKind> { let this = self.eval_context_ref(); let target = &this.tcx.sess.target; if target.families.iter().any(|f| f == "unix") { @@ -621,10 +631,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Calculates the MPlaceTy given the offset and layout of an access on an operand fn deref_operand_and_offset( &self, - op: &OpTy<'tcx, Tag>, + op: &OpTy<'tcx, Provenance>, offset: u64, layout: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, Tag>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> { let this = self.eval_context_ref(); let op_place = this.deref_operand(op)?; let offset = Size::from_bytes(offset); @@ -637,10 +647,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn read_scalar_at_offset( &self, - op: &OpTy<'tcx, Tag>, + op: &OpTy<'tcx, Provenance>, offset: u64, layout: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { + ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_ref(); let value_place = this.deref_operand_and_offset(op, offset, layout)?; this.read_scalar(&value_place.into()) @@ -648,9 +658,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_scalar_at_offset( &mut self, - op: &OpTy<'tcx, Tag>, + op: &OpTy<'tcx, Provenance>, offset: u64, - value: impl Into>, + value: impl Into>, layout: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, ()> { let this = self.eval_context_mut(); @@ -661,7 +671,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Parse a `timespec` struct and return it as a `std::time::Duration`. It returns `None` /// if the value in the `timespec` struct is invalid. Some libc functions will return /// `EINVAL` in this case. - fn read_timespec(&mut self, tp: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx, Option> { + fn read_timespec( + &mut self, + tp: &MPlaceTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); let seconds_place = this.mplace_field(tp, 0)?; let seconds_scalar = this.read_scalar(&seconds_place.into())?; @@ -683,7 +696,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) } - fn read_c_str<'a>(&'a self, ptr: Pointer>) -> InterpResult<'tcx, &'a [u8]> + fn read_c_str<'a>(&'a self, ptr: Pointer>) -> InterpResult<'tcx, &'a [u8]> where 'tcx: 'a, 'mir: 'a, @@ -709,7 +722,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.read_bytes_ptr(ptr, len) } - fn read_wide_str(&self, mut ptr: Pointer>) -> InterpResult<'tcx, Vec> { + fn read_wide_str(&self, mut ptr: Pointer>) -> InterpResult<'tcx, Vec> { let this = self.eval_context_ref(); let size2 = Size::from_bytes(2); let align2 = Align::from_bytes(2).unwrap(); @@ -801,17 +814,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx abi: Abi, exp_abi: Abi, link_name: Symbol, - args: &'a [OpTy<'tcx, Tag>], - ) -> InterpResult<'tcx, &'a [OpTy<'tcx, Tag>; N]> + args: &'a [OpTy<'tcx, Provenance>], + ) -> InterpResult<'tcx, &'a [OpTy<'tcx, Provenance>; N]> where - &'a [OpTy<'tcx, Tag>; N]: TryFrom<&'a [OpTy<'tcx, Tag>]>, + &'a [OpTy<'tcx, Provenance>; N]: TryFrom<&'a [OpTy<'tcx, Provenance>]>, { self.check_abi_and_shim_symbol_clash(abi, exp_abi, link_name)?; check_arg_count(args) } /// Mark a machine allocation that was just created as immutable. - fn mark_immutable(&mut self, mplace: &MemPlace) { + fn mark_immutable(&mut self, mplace: &MemPlace) { let this = self.eval_context_mut(); // This got just allocated, so there definitely is a pointer here. let provenance = mplace.ptr.into_pointer_or_addr().unwrap().provenance; @@ -866,10 +879,10 @@ impl<'a, 'mir, 'tcx> CurrentSpan<'a, 'mir, 'tcx> { /// Check that the number of args is what we expect. pub fn check_arg_count<'a, 'tcx, const N: usize>( - args: &'a [OpTy<'tcx, Tag>], -) -> InterpResult<'tcx, &'a [OpTy<'tcx, Tag>; N]> + args: &'a [OpTy<'tcx, Provenance>], +) -> InterpResult<'tcx, &'a [OpTy<'tcx, Provenance>; N]> where - &'a [OpTy<'tcx, Tag>; N]: TryFrom<&'a [OpTy<'tcx, Tag>]>, + &'a [OpTy<'tcx, Provenance>; N]: TryFrom<&'a [OpTy<'tcx, Provenance>]>, { if let Ok(ops) = args.try_into() { return Ok(ops); diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 0ffa067059f5..4272966ae6cc 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -109,7 +109,7 @@ impl<'mir, 'tcx> GlobalStateInner { pub fn ptr_from_addr_transmute( _ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, - ) -> Pointer> { + ) -> Pointer> { trace!("Transmuting {:#x} to a pointer", addr); // We consider transmuted pointers to be "invalid" (`None` provenance). @@ -119,7 +119,7 @@ impl<'mir, 'tcx> GlobalStateInner { pub fn ptr_from_addr_cast( ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, - ) -> InterpResult<'tcx, Pointer>> { + ) -> InterpResult<'tcx, Pointer>> { trace!("Casting {:#x} to a pointer", addr); let global_state = ecx.machine.intptrcast.borrow(); @@ -146,7 +146,7 @@ impl<'mir, 'tcx> GlobalStateInner { } // This is how wildcard pointers are born. - Ok(Pointer::new(Some(Tag::Wildcard), Size::from_bytes(addr))) + Ok(Pointer::new(Some(Provenance::Wildcard), Size::from_bytes(addr))) } fn alloc_base_addr(ecx: &MiriEvalContext<'mir, 'tcx>, alloc_id: AllocId) -> u64 { @@ -208,11 +208,11 @@ impl<'mir, 'tcx> GlobalStateInner { /// access is going. pub fn abs_ptr_to_rel( ecx: &MiriEvalContext<'mir, 'tcx>, - ptr: Pointer, + ptr: Pointer, ) -> Option<(AllocId, Size)> { let (tag, addr) = ptr.into_parts(); // addr is absolute (Tag provenance) - let alloc_id = if let Tag::Concrete { alloc_id, .. } = tag { + let alloc_id = if let Provenance::Concrete { alloc_id, .. } = tag { alloc_id } else { // A wildcard pointer. diff --git a/src/lib.rs b/src/lib.rs index b3d408a6dc07..35351664caf4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,7 +57,7 @@ mod vector_clock; // Make all those symbols available in the same place as our own. pub use rustc_const_eval::interpret::*; // Resolve ambiguity. -pub use rustc_const_eval::interpret::{self, AllocMap, PlaceTy}; +pub use rustc_const_eval::interpret::{self, AllocMap, PlaceTy, Provenance as _}; pub use crate::shims::dlsym::{Dlsym, EvalContextExt as _}; pub use crate::shims::env::{EnvVars, EvalContextExt as _}; @@ -83,15 +83,14 @@ pub use crate::eval::{ pub use crate::helpers::{CurrentSpan, EvalContextExt as HelpersEvalContextExt}; pub use crate::intptrcast::ProvenanceMode; pub use crate::machine::{ - AllocExtra, Evaluator, FrameData, MiriEvalContext, MiriEvalContextExt, MiriMemoryKind, Tag, - NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, + AllocExtra, Evaluator, FrameData, MiriEvalContext, MiriEvalContextExt, MiriMemoryKind, + Provenance, ProvenanceExtra, NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, }; pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ - CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag, SbTagExtra, Stack, - Stacks, + CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag, Stack, Stacks, }; pub use crate::sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId}; pub use crate::thread::{ diff --git a/src/machine.rs b/src/machine.rs index 00d41cfb70a3..1adfb8377811 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -126,9 +126,9 @@ impl fmt::Display for MiriMemoryKind { } } -/// Pointer provenance (tag). +/// Pointer provenance. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum Tag { +pub enum Provenance { Concrete { alloc_id: AllocId, /// Stacked Borrows tag. @@ -137,27 +137,34 @@ pub enum Tag { Wildcard, } +/// The "extra" information a pointer has over a regular AllocId. +#[derive(Copy, Clone)] +pub enum ProvenanceExtra { + Concrete(SbTag), + Wildcard, +} + #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(Pointer, 24); +static_assert_size!(Pointer, 24); // FIXME: this would with in 24bytes but layout optimizations are not smart enough // #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -//static_assert_size!(Pointer>, 24); +//static_assert_size!(Pointer>, 24); #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(ScalarMaybeUninit, 32); +static_assert_size!(ScalarMaybeUninit, 32); -impl Provenance for Tag { - /// We use absolute addresses in the `offset` of a `Pointer`. +impl interpret::Provenance for Provenance { + /// We use absolute addresses in the `offset` of a `Pointer`. const OFFSET_IS_ADDR: bool = true; /// We cannot err on partial overwrites, it happens too often in practice (due to unions). const ERR_ON_PARTIAL_PTR_OVERWRITE: bool = false; fn fmt(ptr: &Pointer, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let (tag, addr) = ptr.into_parts(); // address is absolute + let (prov, addr) = ptr.into_parts(); // address is absolute write!(f, "{:#x}", addr.bytes())?; - match tag { - Tag::Concrete { alloc_id, sb } => { + match prov { + Provenance::Concrete { alloc_id, sb } => { // Forward `alternate` flag to `alloc_id` printing. if f.alternate() { write!(f, "[{:#?}]", alloc_id)?; @@ -167,7 +174,7 @@ impl Provenance for Tag { // Print Stacked Borrows tag. write!(f, "{:?}", sb)?; } - Tag::Wildcard => { + Provenance::Wildcard => { write!(f, "[wildcard]")?; } } @@ -177,8 +184,26 @@ impl Provenance for Tag { fn get_alloc_id(self) -> Option { match self { - Tag::Concrete { alloc_id, .. } => Some(alloc_id), - Tag::Wildcard => None, + Provenance::Concrete { alloc_id, .. } => Some(alloc_id), + Provenance::Wildcard => None, + } + } +} + +impl fmt::Debug for ProvenanceExtra { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ProvenanceExtra::Concrete(pid) => write!(f, "{pid:?}"), + ProvenanceExtra::Wildcard => write!(f, ""), + } + } +} + +impl ProvenanceExtra { + pub fn and_then(self, f: impl FnOnce(SbTag) -> Option) -> Option { + match self { + ProvenanceExtra::Concrete(pid) => f(pid), + ProvenanceExtra::Wildcard => None, } } } @@ -244,9 +269,9 @@ pub struct Evaluator<'mir, 'tcx> { /// Program arguments (`Option` because we can only initialize them after creating the ecx). /// These are *pointers* to argc/argv because macOS. /// We also need the full command line as one string because of Windows. - pub(crate) argc: Option>, - pub(crate) argv: Option>, - pub(crate) cmd_line: Option>, + pub(crate) argc: Option>, + pub(crate) argv: Option>, + pub(crate) cmd_line: Option>, /// TLS state. pub(crate) tls: TlsData<'tcx>, @@ -302,7 +327,7 @@ pub struct Evaluator<'mir, 'tcx> { pub(crate) local_crates: Vec, /// Mapping extern static names to their base pointer. - extern_statics: FxHashMap>, + extern_statics: FxHashMap>, /// The random number generator used for resolving non-determinism. /// Needs to be queried by ptr_to_int, hence needs interior mutability. @@ -403,7 +428,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { fn add_extern_static( this: &mut MiriEvalContext<'mir, 'tcx>, name: &str, - ptr: Pointer>, + ptr: Pointer>, ) { // This got just allocated, so there definitely is a pointer here. let ptr = ptr.into_pointer_or_addr().unwrap(); @@ -491,11 +516,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { type FrameExtra = FrameData<'tcx>; type AllocExtra = AllocExtra; - type PointerTag = Tag; - type TagExtra = SbTagExtra; + type Provenance = Provenance; + type ProvenanceExtra = ProvenanceExtra; - type MemoryMap = - MonoHashMap, Allocation)>; + type MemoryMap = MonoHashMap< + AllocId, + (MemoryKind, Allocation), + >; const GLOBAL_KIND: Option = Some(MiriMemoryKind::Global); @@ -541,8 +568,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx: &mut MiriEvalContext<'mir, 'tcx>, instance: ty::Instance<'tcx>, abi: Abi, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ret: Option, unwind: StackPopUnwind, ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { @@ -554,8 +581,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx: &mut MiriEvalContext<'mir, 'tcx>, fn_val: Dlsym, abi: Abi, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ret: Option, _unwind: StackPopUnwind, ) -> InterpResult<'tcx> { @@ -566,8 +593,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn call_intrinsic( ecx: &mut MiriEvalContext<'mir, 'tcx>, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ret: Option, unwind: StackPopUnwind, ) -> InterpResult<'tcx> { @@ -592,23 +619,23 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn binary_ptr_op( ecx: &MiriEvalContext<'mir, 'tcx>, bin_op: mir::BinOp, - left: &ImmTy<'tcx, Tag>, - right: &ImmTy<'tcx, Tag>, - ) -> InterpResult<'tcx, (Scalar, bool, ty::Ty<'tcx>)> { + left: &ImmTy<'tcx, Provenance>, + right: &ImmTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, (Scalar, bool, ty::Ty<'tcx>)> { ecx.binary_ptr_op(bin_op, left, right) } fn thread_local_static_base_pointer( ecx: &mut MiriEvalContext<'mir, 'tcx>, def_id: DefId, - ) -> InterpResult<'tcx, Pointer> { + ) -> InterpResult<'tcx, Pointer> { ecx.get_or_create_thread_local_alloc(def_id) } fn extern_static_base_pointer( ecx: &MiriEvalContext<'mir, 'tcx>, def_id: DefId, - ) -> InterpResult<'tcx, Pointer> { + ) -> InterpResult<'tcx, Pointer> { let link_name = ecx.item_link_name(def_id); if let Some(&ptr) = ecx.machine.extern_statics.get(&link_name) { Ok(ptr) @@ -621,12 +648,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } } - fn init_allocation_extra<'b>( + fn adjust_allocation<'b>( ecx: &MiriEvalContext<'mir, 'tcx>, id: AllocId, alloc: Cow<'b, Allocation>, kind: Option>, - ) -> InterpResult<'tcx, Cow<'b, Allocation>> { + ) -> InterpResult<'tcx, Cow<'b, Allocation>> { let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); if ecx.machine.tracked_alloc_ids.contains(&id) { register_diagnostic(NonHaltingDiagnostic::CreatedAlloc( @@ -664,7 +691,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } else { None }; - let alloc: Allocation = alloc.convert_tag_add_extra( + let alloc: Allocation = alloc.adjust_from_tcx( &ecx.tcx, AllocExtra { stacked_borrows: stacks.map(RefCell::new), @@ -676,19 +703,19 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { Ok(Cow::Owned(alloc)) } - fn tag_alloc_base_pointer( + fn adjust_alloc_base_pointer( ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer, - ) -> Pointer { + ) -> Pointer { if cfg!(debug_assertions) { // The machine promises to never call us on thread-local or extern statics. let alloc_id = ptr.provenance; match ecx.tcx.get_global_alloc(alloc_id) { Some(GlobalAlloc::Static(def_id)) if ecx.tcx.is_thread_local_static(def_id) => { - panic!("tag_alloc_base_pointer called on thread-local static") + panic!("adjust_alloc_base_pointer called on thread-local static") } Some(GlobalAlloc::Static(def_id)) if ecx.tcx.is_foreign_item(def_id) => { - panic!("tag_alloc_base_pointer called on extern static") + panic!("adjust_alloc_base_pointer called on extern static") } _ => {} } @@ -701,7 +728,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { SbTag::default() }; Pointer::new( - Tag::Concrete { alloc_id: ptr.provenance, sb: sb_tag }, + Provenance::Concrete { alloc_id: ptr.provenance, sb: sb_tag }, Size::from_bytes(absolute_addr), ) } @@ -710,7 +737,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn ptr_from_addr_cast( ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, - ) -> InterpResult<'tcx, Pointer>> { + ) -> InterpResult<'tcx, Pointer>> { intptrcast::GlobalStateInner::ptr_from_addr_cast(ecx, addr) } @@ -718,19 +745,19 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn ptr_from_addr_transmute( ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, - ) -> Pointer> { + ) -> Pointer> { intptrcast::GlobalStateInner::ptr_from_addr_transmute(ecx, addr) } fn expose_ptr( ecx: &mut InterpCx<'mir, 'tcx, Self>, - ptr: Pointer, + ptr: Pointer, ) -> InterpResult<'tcx> { match ptr.provenance { - Tag::Concrete { alloc_id, sb } => { + Provenance::Concrete { alloc_id, sb } => { intptrcast::GlobalStateInner::expose_ptr(ecx, alloc_id, sb); } - Tag::Wildcard => { + Provenance::Wildcard => { // No need to do anything for wildcard pointers as // their provenances have already been previously exposed. } @@ -742,14 +769,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { /// or a `None` with an absolute address if that conversion is not possible. fn ptr_get_alloc( ecx: &MiriEvalContext<'mir, 'tcx>, - ptr: Pointer, - ) -> Option<(AllocId, Size, Self::TagExtra)> { + ptr: Pointer, + ) -> Option<(AllocId, Size, Self::ProvenanceExtra)> { let rel = intptrcast::GlobalStateInner::abs_ptr_to_rel(ecx, ptr); rel.map(|(alloc_id, size)| { let sb = match ptr.provenance { - Tag::Concrete { sb, .. } => SbTagExtra::Concrete(sb), - Tag::Wildcard => SbTagExtra::Wildcard, + Provenance::Concrete { sb, .. } => ProvenanceExtra::Concrete(sb), + Provenance::Wildcard => ProvenanceExtra::Wildcard, }; (alloc_id, size, sb) }) @@ -760,7 +787,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { _tcx: TyCtxt<'tcx>, machine: &Self, alloc_extra: &AllocExtra, - (alloc_id, tag): (AllocId, Self::TagExtra), + (alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra), range: AllocRange, ) -> InterpResult<'tcx> { if let Some(data_race) = &alloc_extra.data_race { @@ -774,7 +801,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { if let Some(stacked_borrows) = &alloc_extra.stacked_borrows { stacked_borrows.borrow_mut().memory_read( alloc_id, - tag, + prov_extra, range, machine.stacked_borrows.as_ref().unwrap(), machine.current_span(), @@ -792,7 +819,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { _tcx: TyCtxt<'tcx>, machine: &mut Self, alloc_extra: &mut AllocExtra, - (alloc_id, tag): (AllocId, Self::TagExtra), + (alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra), range: AllocRange, ) -> InterpResult<'tcx> { if let Some(data_race) = &mut alloc_extra.data_race { @@ -806,7 +833,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { stacked_borrows.get_mut().memory_written( alloc_id, - tag, + prov_extra, range, machine.stacked_borrows.as_ref().unwrap(), machine.current_span(), @@ -824,7 +851,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { _tcx: TyCtxt<'tcx>, machine: &mut Self, alloc_extra: &mut AllocExtra, - (alloc_id, tag): (AllocId, Self::TagExtra), + (alloc_id, prove_extra): (AllocId, Self::ProvenanceExtra), range: AllocRange, ) -> InterpResult<'tcx> { if machine.tracked_alloc_ids.contains(&alloc_id) { @@ -841,7 +868,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { stacked_borrows.get_mut().memory_deallocated( alloc_id, - tag, + prove_extra, range, machine.stacked_borrows.as_ref().unwrap(), &machine.threads, @@ -855,7 +882,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn retag( ecx: &mut InterpCx<'mir, 'tcx, Self>, kind: mir::RetagKind, - place: &PlaceTy<'tcx, Tag>, + place: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx> { if ecx.machine.stacked_borrows.is_some() { ecx.retag(kind, place) } else { Ok(()) } } @@ -863,8 +890,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn init_frame_extra( ecx: &mut InterpCx<'mir, 'tcx, Self>, - frame: Frame<'mir, 'tcx, Tag>, - ) -> InterpResult<'tcx, Frame<'mir, 'tcx, Tag, FrameData<'tcx>>> { + frame: Frame<'mir, 'tcx, Provenance>, + ) -> InterpResult<'tcx, Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>> { // Start recording our event before doing anything else let timing = if let Some(profiler) = ecx.machine.profiler.as_ref() { let fn_name = frame.instance.to_string(); @@ -892,13 +919,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn stack<'a>( ecx: &'a InterpCx<'mir, 'tcx, Self>, - ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] { + ) -> &'a [Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>] { ecx.active_thread_stack() } fn stack_mut<'a>( ecx: &'a mut InterpCx<'mir, 'tcx, Self>, - ) -> &'a mut Vec> { + ) -> &'a mut Vec> { ecx.active_thread_stack_mut() } @@ -925,7 +952,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn after_stack_pop( ecx: &mut InterpCx<'mir, 'tcx, Self>, - mut frame: Frame<'mir, 'tcx, Tag, FrameData<'tcx>>, + mut frame: Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>, unwinding: bool, ) -> InterpResult<'tcx, StackPopJump> { let timing = frame.extra.timing.take(); diff --git a/src/operator.rs b/src/operator.rs index 2c77830a6d14..758e747d2786 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -9,18 +9,18 @@ pub trait EvalContextExt<'tcx> { fn binary_ptr_op( &self, bin_op: mir::BinOp, - left: &ImmTy<'tcx, Tag>, - right: &ImmTy<'tcx, Tag>, - ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)>; + left: &ImmTy<'tcx, Provenance>, + right: &ImmTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)>; } impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { fn binary_ptr_op( &self, bin_op: mir::BinOp, - left: &ImmTy<'tcx, Tag>, - right: &ImmTy<'tcx, Tag>, - ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { + left: &ImmTy<'tcx, Provenance>, + right: &ImmTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { use rustc_middle::mir::BinOp::*; trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 5b39f2a48aae..3c15165d67be 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -11,8 +11,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, abi: Abi, link_name: Symbol, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let [flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; @@ -31,8 +31,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, abi: Abi, link_name: Symbol, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let tcx = this.tcx; @@ -117,7 +117,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn resolve_frame_pointer( &mut self, - ptr: &OpTy<'tcx, Tag>, + ptr: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, (Instance<'tcx>, Loc, String, String)> { let this = self.eval_context_mut(); @@ -145,8 +145,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, abi: Abi, link_name: Symbol, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let [ptr, flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; @@ -228,7 +228,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, abi: Abi, link_name: Symbol, - args: &[OpTy<'tcx, Tag>], + args: &[OpTy<'tcx, Provenance>], ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 499e9f8a201f..5cb3c99e3d19 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -33,8 +33,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, dlsym: Dlsym, abi: Abi, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ret: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/shims/env.rs b/src/shims/env.rs index f4aaeea2c122..f0818e71b667 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -30,10 +30,10 @@ fn windows_check_buffer_size((success, len): (bool, u64)) -> u32 { pub struct EnvVars<'tcx> { /// Stores pointers to the environment variables. These variables must be stored as /// null-terminated target strings (c_str or wide_str) with the `"{name}={value}"` format. - map: FxHashMap>>, + map: FxHashMap>>, /// Place where the `environ` static is stored. Lazily initialized, but then never changes. - pub(crate) environ: Option>, + pub(crate) environ: Option>, } impl<'tcx> EnvVars<'tcx> { @@ -92,7 +92,7 @@ fn alloc_env_var_as_c_str<'mir, 'tcx>( name: &OsStr, value: &OsStr, ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, -) -> InterpResult<'tcx, Pointer>> { +) -> InterpResult<'tcx, Pointer>> { let mut name_osstring = name.to_os_string(); name_osstring.push("="); name_osstring.push(value); @@ -103,7 +103,7 @@ fn alloc_env_var_as_wide_str<'mir, 'tcx>( name: &OsStr, value: &OsStr, ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, -) -> InterpResult<'tcx, Pointer>> { +) -> InterpResult<'tcx, Pointer>> { let mut name_osstring = name.to_os_string(); name_osstring.push("="); name_osstring.push(value); @@ -112,7 +112,10 @@ fn alloc_env_var_as_wide_str<'mir, 'tcx>( impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn getenv(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, Pointer>> { + fn getenv( + &mut self, + name_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, Pointer>> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("getenv"); @@ -133,9 +136,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn GetEnvironmentVariableW( &mut self, - name_op: &OpTy<'tcx, Tag>, // LPCWSTR - buf_op: &OpTy<'tcx, Tag>, // LPWSTR - size_op: &OpTy<'tcx, Tag>, // DWORD + name_op: &OpTy<'tcx, Provenance>, // LPCWSTR + buf_op: &OpTy<'tcx, Provenance>, // LPWSTR + size_op: &OpTy<'tcx, Provenance>, // DWORD ) -> InterpResult<'tcx, u32> { // ^ Returns DWORD (u32 on Windows) @@ -168,7 +171,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn GetEnvironmentStringsW(&mut self) -> InterpResult<'tcx, Pointer>> { + fn GetEnvironmentStringsW(&mut self) -> InterpResult<'tcx, Pointer>> { let this = self.eval_context_mut(); this.assert_target_os("windows", "GetEnvironmentStringsW"); @@ -191,7 +194,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn FreeEnvironmentStringsW( &mut self, - env_block_op: &OpTy<'tcx, Tag>, + env_block_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("windows", "FreeEnvironmentStringsW"); @@ -204,8 +207,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn setenv( &mut self, - name_op: &OpTy<'tcx, Tag>, - value_op: &OpTy<'tcx, Tag>, + name_op: &OpTy<'tcx, Provenance>, + value_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("setenv"); @@ -239,8 +242,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn SetEnvironmentVariableW( &mut self, - name_op: &OpTy<'tcx, Tag>, // LPCWSTR - value_op: &OpTy<'tcx, Tag>, // LPCWSTR + name_op: &OpTy<'tcx, Provenance>, // LPCWSTR + value_op: &OpTy<'tcx, Provenance>, // LPCWSTR ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("windows", "SetEnvironmentVariableW"); @@ -276,7 +279,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn unsetenv(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn unsetenv(&mut self, name_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("unsetenv"); @@ -304,9 +307,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn getcwd( &mut self, - buf_op: &OpTy<'tcx, Tag>, - size_op: &OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, Pointer>> { + buf_op: &OpTy<'tcx, Provenance>, + size_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, Pointer>> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("getcwd"); @@ -337,8 +340,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn GetCurrentDirectoryW( &mut self, - size_op: &OpTy<'tcx, Tag>, // DWORD - buf_op: &OpTy<'tcx, Tag>, // LPTSTR + size_op: &OpTy<'tcx, Provenance>, // DWORD + buf_op: &OpTy<'tcx, Provenance>, // LPTSTR ) -> InterpResult<'tcx, u32> { let this = self.eval_context_mut(); this.assert_target_os("windows", "GetCurrentDirectoryW"); @@ -361,7 +364,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn chdir(&mut self, path_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn chdir(&mut self, path_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("chdir"); @@ -386,7 +389,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn SetCurrentDirectoryW( &mut self, - path_op: &OpTy<'tcx, Tag>, // LPCTSTR + path_op: &OpTy<'tcx, Provenance>, // LPCTSTR ) -> InterpResult<'tcx, i32> { // ^ Returns BOOL (i32 on Windows) @@ -428,7 +431,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Collect all the pointers to each variable in a vector. - let mut vars: Vec>> = + let mut vars: Vec>> = this.machine.env_vars.map.values().copied().collect(); // Add the trailing null pointer. vars.push(Pointer::null()); diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 8d82c912f380..99f061716219 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -74,7 +74,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, zero_init: bool, kind: MiriMemoryKind, - ) -> InterpResult<'tcx, Pointer>> { + ) -> InterpResult<'tcx, Pointer>> { let this = self.eval_context_mut(); if size == 0 { Ok(Pointer::null()) @@ -89,7 +89,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn free(&mut self, ptr: Pointer>, kind: MiriMemoryKind) -> InterpResult<'tcx> { + fn free( + &mut self, + ptr: Pointer>, + kind: MiriMemoryKind, + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if !this.ptr_is_null(ptr)? { this.deallocate_ptr(ptr, None, kind.into())?; @@ -99,10 +103,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn realloc( &mut self, - old_ptr: Pointer>, + old_ptr: Pointer>, new_size: u64, kind: MiriMemoryKind, - ) -> InterpResult<'tcx, Pointer>> { + ) -> InterpResult<'tcx, Pointer>> { let this = self.eval_context_mut(); let new_align = this.min_align(new_size, kind); if this.ptr_is_null(old_ptr)? { @@ -231,8 +235,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, def_id: DefId, abi: Abi, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ret: Option, unwind: StackPopUnwind, ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { @@ -353,8 +357,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); diff --git a/src/shims/intrinsics/atomic.rs b/src/shims/intrinsics/atomic.rs index 78e13a498ce1..8e0bb746e3cd 100644 --- a/src/shims/intrinsics/atomic.rs +++ b/src/shims/intrinsics/atomic.rs @@ -18,8 +18,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_atomic_intrinsic( &mut self, intrinsic_name: &str, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -121,8 +121,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn atomic_load( &mut self, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, atomic: AtomicReadOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -150,7 +150,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn atomic_store( &mut self, - args: &[OpTy<'tcx, Tag>], + args: &[OpTy<'tcx, Provenance>], atomic: AtomicWriteOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -177,7 +177,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn compiler_fence( &mut self, - args: &[OpTy<'tcx, Tag>], + args: &[OpTy<'tcx, Provenance>], atomic: AtomicFenceOrd, ) -> InterpResult<'tcx> { let [] = check_arg_count(args)?; @@ -188,7 +188,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn atomic_fence( &mut self, - args: &[OpTy<'tcx, Tag>], + args: &[OpTy<'tcx, Provenance>], atomic: AtomicFenceOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -199,8 +199,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn atomic_op( &mut self, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, atomic_op: AtomicOp, atomic: AtomicRwOrd, ) -> InterpResult<'tcx> { @@ -252,8 +252,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn atomic_exchange( &mut self, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, atomic: AtomicRwOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -280,8 +280,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn atomic_compare_exchange_impl( &mut self, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, success: AtomicRwOrd, fail: AtomicReadOrd, can_fail_spuriously: bool, @@ -320,8 +320,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn atomic_compare_exchange( &mut self, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, success: AtomicRwOrd, fail: AtomicReadOrd, ) -> InterpResult<'tcx> { @@ -330,8 +330,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn atomic_compare_exchange_weak( &mut self, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, success: AtomicRwOrd, fail: AtomicReadOrd, ) -> InterpResult<'tcx> { diff --git a/src/shims/intrinsics/mod.rs b/src/shims/intrinsics/mod.rs index 97f9a7b93cac..c07ed8b29489 100644 --- a/src/shims/intrinsics/mod.rs +++ b/src/shims/intrinsics/mod.rs @@ -20,8 +20,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn call_intrinsic( &mut self, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ret: Option, _unwind: StackPopUnwind, ) -> InterpResult<'tcx> { @@ -58,8 +58,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_intrinsic_by_name( &mut self, intrinsic_name: &str, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -375,9 +375,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &self, f: F, dest_ty: ty::Ty<'tcx>, - ) -> InterpResult<'tcx, Scalar> + ) -> InterpResult<'tcx, Scalar> where - F: Float + Into>, + F: Float + Into>, { let this = self.eval_context_ref(); diff --git a/src/shims/intrinsics/simd.rs b/src/shims/intrinsics/simd.rs index fe5250ed0843..96e97d79358b 100644 --- a/src/shims/intrinsics/simd.rs +++ b/src/shims/intrinsics/simd.rs @@ -12,8 +12,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_simd_intrinsic( &mut self, intrinsic_name: &str, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); match intrinsic_name { @@ -557,13 +557,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } -fn bool_to_simd_element(b: bool, size: Size) -> Scalar { +fn bool_to_simd_element(b: bool, size: Size) -> Scalar { // SIMD uses all-1 as pattern for "true" let val = if b { -1 } else { 0 }; Scalar::from_int(val, size) } -fn simd_element_to_bool(elem: ImmTy<'_, Tag>) -> InterpResult<'_, bool> { +fn simd_element_to_bool(elem: ImmTy<'_, Provenance>) -> InterpResult<'_, bool> { let val = elem.to_scalar()?.to_int(elem.layout.size)?; Ok(match val { 0 => false, @@ -581,9 +581,9 @@ fn simd_bitmask_index(idx: u64, vec_len: u64, endianess: Endian) -> u64 { } fn fmax_op<'tcx>( - left: &ImmTy<'tcx, Tag>, - right: &ImmTy<'tcx, Tag>, -) -> InterpResult<'tcx, Scalar> { + left: &ImmTy<'tcx, Provenance>, + right: &ImmTy<'tcx, Provenance>, +) -> InterpResult<'tcx, Scalar> { assert_eq!(left.layout.ty, right.layout.ty); let ty::Float(float_ty) = left.layout.ty.kind() else { bug!("fmax operand is not a float") @@ -597,9 +597,9 @@ fn fmax_op<'tcx>( } fn fmin_op<'tcx>( - left: &ImmTy<'tcx, Tag>, - right: &ImmTy<'tcx, Tag>, -) -> InterpResult<'tcx, Scalar> { + left: &ImmTy<'tcx, Provenance>, + right: &ImmTy<'tcx, Provenance>, +) -> InterpResult<'tcx, Scalar> { assert_eq!(left.layout.ty, right.layout.ty); let ty::Float(float_ty) = left.layout.ty.kind() else { bug!("fmin operand is not a float") diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 2423ffaf5fe0..f5b4de30a570 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -27,8 +27,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, instance: ty::Instance<'tcx>, abi: Abi, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ret: Option, unwind: StackPopUnwind, ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { @@ -62,9 +62,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// the actual MIR of `align_offset`. fn align_offset( &mut self, - ptr_op: &OpTy<'tcx, Tag>, - align_op: &OpTy<'tcx, Tag>, - dest: &PlaceTy<'tcx, Tag>, + ptr_op: &OpTy<'tcx, Provenance>, + align_op: &OpTy<'tcx, Provenance>, + dest: &PlaceTy<'tcx, Provenance>, ret: Option, unwind: StackPopUnwind, ) -> InterpResult<'tcx, bool> { diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index d6669b21a731..71824bee346e 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -52,7 +52,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// the Unix APIs usually handle. fn read_os_str_from_c_str<'a>( &'a self, - ptr: Pointer>, + ptr: Pointer>, ) -> InterpResult<'tcx, &'a OsStr> where 'tcx: 'a, @@ -67,7 +67,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// which is what the Windows APIs usually handle. fn read_os_str_from_wide_str<'a>( &'a self, - ptr: Pointer>, + ptr: Pointer>, ) -> InterpResult<'tcx, OsString> where 'tcx: 'a, @@ -96,7 +96,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_os_str_to_c_str( &mut self, os_str: &OsStr, - ptr: Pointer>, + ptr: Pointer>, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let bytes = os_str_to_bytes(os_str)?; @@ -119,7 +119,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_os_str_to_wide_str( &mut self, os_str: &OsStr, - ptr: Pointer>, + ptr: Pointer>, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { #[cfg(windows)] @@ -165,7 +165,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, os_str: &OsStr, memkind: MemoryKind, - ) -> InterpResult<'tcx, Pointer>> { + ) -> InterpResult<'tcx, Pointer>> { let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0` terminator. let this = self.eval_context_mut(); @@ -180,7 +180,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, os_str: &OsStr, memkind: MemoryKind, - ) -> InterpResult<'tcx, Pointer>> { + ) -> InterpResult<'tcx, Pointer>> { let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0x0000` terminator. let this = self.eval_context_mut(); @@ -193,7 +193,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Read a null-terminated sequence of bytes, and perform path separator conversion if needed. fn read_path_from_c_str<'a>( &'a self, - ptr: Pointer>, + ptr: Pointer>, ) -> InterpResult<'tcx, Cow<'a, Path>> where 'tcx: 'a, @@ -209,7 +209,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Read a null-terminated sequence of `u16`s, and perform path separator conversion if needed. - fn read_path_from_wide_str(&self, ptr: Pointer>) -> InterpResult<'tcx, PathBuf> { + fn read_path_from_wide_str( + &self, + ptr: Pointer>, + ) -> InterpResult<'tcx, PathBuf> { let this = self.eval_context_ref(); let os_str = this.read_os_str_from_wide_str(ptr)?; @@ -224,7 +227,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_path_to_c_str( &mut self, path: &Path, - ptr: Pointer>, + ptr: Pointer>, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); @@ -238,7 +241,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_path_to_wide_str( &mut self, path: &Path, - ptr: Pointer>, + ptr: Pointer>, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 42264f6ff344..362b929eabfe 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -26,11 +26,11 @@ use helpers::check_arg_count; #[derive(Debug)] pub struct CatchUnwindData<'tcx> { /// The `catch_fn` callback to call in case of a panic. - catch_fn: Scalar, + catch_fn: Scalar, /// The `data` argument for that callback. - data: Scalar, + data: Scalar, /// The return place from the original call to `try`. - dest: PlaceTy<'tcx, Tag>, + dest: PlaceTy<'tcx, Provenance>, /// The return block from the original call to `try`. ret: mir::BasicBlock, } @@ -43,7 +43,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, abi: Abi, link_name: Symbol, - args: &[OpTy<'tcx, Tag>], + args: &[OpTy<'tcx, Provenance>], unwind: StackPopUnwind, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -65,8 +65,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Handles the `try` intrinsic, the underlying implementation of `std::panicking::try`. fn handle_try( &mut self, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ret: mir::BasicBlock, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/shims/time.rs b/src/shims/time.rs index 0fd5cebd2345..a2cbd84bc2db 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -13,8 +13,8 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn clock_gettime( &mut self, - clk_id_op: &OpTy<'tcx, Tag>, - tp_op: &OpTy<'tcx, Tag>, + clk_id_op: &OpTy<'tcx, Provenance>, + tp_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { // This clock support is deliberately minimal because a lot of clock types have fiddly // properties (is it possible for Miri to be suspended independently of the host?). If you @@ -59,8 +59,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn gettimeofday( &mut self, - tv_op: &OpTy<'tcx, Tag>, - tz_op: &OpTy<'tcx, Tag>, + tv_op: &OpTy<'tcx, Provenance>, + tz_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -85,7 +85,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn GetSystemTimeAsFileTime(&mut self, LPFILETIME_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn GetSystemTimeAsFileTime( + &mut self, + LPFILETIME_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.assert_target_os("windows", "GetSystemTimeAsFileTime"); @@ -115,7 +118,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn QueryPerformanceCounter( &mut self, - lpPerformanceCount_op: &OpTy<'tcx, Tag>, + lpPerformanceCount_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -138,7 +141,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn QueryPerformanceFrequency( &mut self, - lpFrequency_op: &OpTy<'tcx, Tag>, + lpFrequency_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -172,7 +175,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) } - fn mach_timebase_info(&mut self, info_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn mach_timebase_info(&mut self, info_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("macos", "mach_timebase_info"); @@ -190,8 +193,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn nanosleep( &mut self, - req_op: &OpTy<'tcx, Tag>, - _rem: &OpTy<'tcx, Tag>, + req_op: &OpTy<'tcx, Provenance>, + _rem: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { // Signal handlers are not supported, so rem will never be written to. diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 5a72c872b04d..13af447f76c6 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -19,7 +19,7 @@ pub type TlsKey = u128; pub struct TlsEntry<'tcx> { /// The data for this key. None is used to represent NULL. /// (We normalize this early to avoid having to do a NULL-ptr-test each time we access the data.) - data: BTreeMap>, + data: BTreeMap>, dtor: Option>, } @@ -41,7 +41,7 @@ pub struct TlsData<'tcx> { /// A single per thread destructor of the thread local storage (that's how /// things work on macOS) with a data argument. - macos_thread_dtors: BTreeMap, Scalar)>, + macos_thread_dtors: BTreeMap, Scalar)>, /// State for currently running TLS dtors. If this map contains a key for a /// specific thread, it means that we are in the "destruct" phase, during @@ -94,7 +94,7 @@ impl<'tcx> TlsData<'tcx> { key: TlsKey, thread_id: ThreadId, cx: &impl HasDataLayout, - ) -> InterpResult<'tcx, Scalar> { + ) -> InterpResult<'tcx, Scalar> { match self.keys.get(&key) { Some(TlsEntry { data, .. }) => { let value = data.get(&thread_id).copied(); @@ -109,7 +109,7 @@ impl<'tcx> TlsData<'tcx> { &mut self, key: TlsKey, thread_id: ThreadId, - new_data: Scalar, + new_data: Scalar, cx: &impl HasDataLayout, ) -> InterpResult<'tcx> { match self.keys.get_mut(&key) { @@ -140,7 +140,7 @@ impl<'tcx> TlsData<'tcx> { &mut self, thread: ThreadId, dtor: ty::Instance<'tcx>, - data: Scalar, + data: Scalar, ) -> InterpResult<'tcx> { if self.dtors_running.contains_key(&thread) { // UB, according to libstd docs. @@ -179,7 +179,7 @@ impl<'tcx> TlsData<'tcx> { &mut self, key: Option, thread_id: ThreadId, - ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { + ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { use std::ops::Bound::*; let thread_local = &mut self.keys; diff --git a/src/shims/unix/dlsym.rs b/src/shims/unix/dlsym.rs index 2c563a9551f2..a806c16e28bb 100644 --- a/src/shims/unix/dlsym.rs +++ b/src/shims/unix/dlsym.rs @@ -32,8 +32,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, dlsym: Dlsym, abi: Abi, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ret: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index cf34b4baec7f..2a051fb77539 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -19,8 +19,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); diff --git a/src/shims/unix/freebsd/dlsym.rs b/src/shims/unix/freebsd/dlsym.rs index 18347d274e93..74c322c666d4 100644 --- a/src/shims/unix/freebsd/dlsym.rs +++ b/src/shims/unix/freebsd/dlsym.rs @@ -19,8 +19,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn call_dlsym( &mut self, dlsym: Dlsym, - _args: &[OpTy<'tcx, Tag>], - _dest: &PlaceTy<'tcx, Tag>, + _args: &[OpTy<'tcx, Provenance>], + _dest: &PlaceTy<'tcx, Provenance>, ret: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/shims/unix/freebsd/foreign_items.rs b/src/shims/unix/freebsd/foreign_items.rs index 2350e5a12c11..658711526d00 100644 --- a/src/shims/unix/freebsd/foreign_items.rs +++ b/src/shims/unix/freebsd/foreign_items.rs @@ -11,8 +11,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); match link_name.as_str() { diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index 1420279247f4..50a2053078f8 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -386,7 +386,7 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' fn macos_stat_write_buf( &mut self, metadata: FileMetadata, - buf_op: &OpTy<'tcx, Tag>, + buf_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -493,7 +493,7 @@ pub struct OpenDir { /// The directory reader on the host. read_dir: ReadDir, /// The most recent entry returned by readdir() - entry: Pointer>, + entry: Pointer>, } impl OpenDir { @@ -556,7 +556,7 @@ fn maybe_sync_file( impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn open(&mut self, args: &[OpTy<'tcx, Tag>]) -> InterpResult<'tcx, i32> { + fn open(&mut self, args: &[OpTy<'tcx, Provenance>]) -> InterpResult<'tcx, i32> { if args.len() < 2 { throw_ub_format!( "incorrect number of arguments for `open`: got {}, expected at least 2", @@ -667,7 +667,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.try_unwrap_io_result(fd) } - fn fcntl(&mut self, args: &[OpTy<'tcx, Tag>]) -> InterpResult<'tcx, i32> { + fn fcntl(&mut self, args: &[OpTy<'tcx, Provenance>]) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); if args.len() < 2 { @@ -741,7 +741,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn close(&mut self, fd_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn close(&mut self, fd_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -754,7 +754,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn read(&mut self, fd: i32, buf: Pointer>, count: u64) -> InterpResult<'tcx, i64> { + fn read( + &mut self, + fd: i32, + buf: Pointer>, + count: u64, + ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); // Isolation check is done via `FileDescriptor` trait. @@ -802,7 +807,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn write(&mut self, fd: i32, buf: Pointer>, count: u64) -> InterpResult<'tcx, i64> { + fn write( + &mut self, + fd: i32, + buf: Pointer>, + count: u64, + ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); // Isolation check is done via `FileDescriptor` trait. @@ -832,9 +842,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn lseek64( &mut self, - fd_op: &OpTy<'tcx, Tag>, - offset_op: &OpTy<'tcx, Tag>, - whence_op: &OpTy<'tcx, Tag>, + fd_op: &OpTy<'tcx, Provenance>, + offset_op: &OpTy<'tcx, Provenance>, + whence_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); @@ -867,7 +877,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn unlink(&mut self, path_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn unlink(&mut self, path_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; @@ -885,8 +895,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn symlink( &mut self, - target_op: &OpTy<'tcx, Tag>, - linkpath_op: &OpTy<'tcx, Tag>, + target_op: &OpTy<'tcx, Provenance>, + linkpath_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { #[cfg(unix)] fn create_link(src: &Path, dst: &Path) -> std::io::Result<()> { @@ -916,8 +926,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn macos_stat( &mut self, - path_op: &OpTy<'tcx, Tag>, - buf_op: &OpTy<'tcx, Tag>, + path_op: &OpTy<'tcx, Provenance>, + buf_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("macos", "stat"); @@ -945,8 +955,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `lstat` is used to get symlink metadata. fn macos_lstat( &mut self, - path_op: &OpTy<'tcx, Tag>, - buf_op: &OpTy<'tcx, Tag>, + path_op: &OpTy<'tcx, Provenance>, + buf_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("macos", "lstat"); @@ -972,8 +982,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn macos_fstat( &mut self, - fd_op: &OpTy<'tcx, Tag>, - buf_op: &OpTy<'tcx, Tag>, + fd_op: &OpTy<'tcx, Provenance>, + buf_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -997,11 +1007,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn linux_statx( &mut self, - dirfd_op: &OpTy<'tcx, Tag>, // Should be an `int` - pathname_op: &OpTy<'tcx, Tag>, // Should be a `const char *` - flags_op: &OpTy<'tcx, Tag>, // Should be an `int` - mask_op: &OpTy<'tcx, Tag>, // Should be an `unsigned int` - statxbuf_op: &OpTy<'tcx, Tag>, // Should be a `struct statx *` + dirfd_op: &OpTy<'tcx, Provenance>, // Should be an `int` + pathname_op: &OpTy<'tcx, Provenance>, // Should be a `const char *` + flags_op: &OpTy<'tcx, Provenance>, // Should be an `int` + mask_op: &OpTy<'tcx, Provenance>, // Should be an `unsigned int` + statxbuf_op: &OpTy<'tcx, Provenance>, // Should be a `struct statx *` ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -1188,8 +1198,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn rename( &mut self, - oldpath_op: &OpTy<'tcx, Tag>, - newpath_op: &OpTy<'tcx, Tag>, + oldpath_op: &OpTy<'tcx, Provenance>, + newpath_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -1219,8 +1229,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn mkdir( &mut self, - path_op: &OpTy<'tcx, Tag>, - mode_op: &OpTy<'tcx, Tag>, + path_op: &OpTy<'tcx, Provenance>, + mode_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -1256,7 +1266,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.try_unwrap_io_result(result) } - fn rmdir(&mut self, path_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn rmdir(&mut self, path_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; @@ -1273,7 +1283,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.try_unwrap_io_result(result) } - fn opendir(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { + fn opendir( + &mut self, + name_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let name = this.read_path_from_c_str(this.read_pointer(name_op)?)?; @@ -1304,7 +1317,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn linux_readdir64(&mut self, dirp_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { + fn linux_readdir64( + &mut self, + dirp_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("linux", "readdir64"); @@ -1393,9 +1409,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn macos_readdir_r( &mut self, - dirp_op: &OpTy<'tcx, Tag>, - entry_op: &OpTy<'tcx, Tag>, - result_op: &OpTy<'tcx, Tag>, + dirp_op: &OpTy<'tcx, Provenance>, + entry_op: &OpTy<'tcx, Provenance>, + result_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -1490,7 +1506,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn closedir(&mut self, dirp_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn closedir(&mut self, dirp_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; @@ -1513,8 +1529,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn ftruncate64( &mut self, - fd_op: &OpTy<'tcx, Tag>, - length_op: &OpTy<'tcx, Tag>, + fd_op: &OpTy<'tcx, Provenance>, + length_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -1551,7 +1567,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn fsync(&mut self, fd_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn fsync(&mut self, fd_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { // On macOS, `fsync` (unlike `fcntl(F_FULLFSYNC)`) does not wait for the // underlying disk to finish writing. In the interest of host compatibility, // we conservatively implement this with `sync_all`, which @@ -1578,7 +1594,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn fdatasync(&mut self, fd_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn fdatasync(&mut self, fd_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -1602,10 +1618,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn sync_file_range( &mut self, - fd_op: &OpTy<'tcx, Tag>, - offset_op: &OpTy<'tcx, Tag>, - nbytes_op: &OpTy<'tcx, Tag>, - flags_op: &OpTy<'tcx, Tag>, + fd_op: &OpTy<'tcx, Provenance>, + offset_op: &OpTy<'tcx, Provenance>, + nbytes_op: &OpTy<'tcx, Provenance>, + flags_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -1647,9 +1663,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn readlink( &mut self, - pathname_op: &OpTy<'tcx, Tag>, - buf_op: &OpTy<'tcx, Tag>, - bufsize_op: &OpTy<'tcx, Tag>, + pathname_op: &OpTy<'tcx, Provenance>, + buf_op: &OpTy<'tcx, Provenance>, + bufsize_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); @@ -1691,7 +1707,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[cfg_attr(not(unix), allow(unused))] - fn isatty(&mut self, miri_fd: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn isatty(&mut self, miri_fd: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); #[cfg(unix)] if matches!(this.machine.isolated_op, IsolatedOp::Allow) { @@ -1740,7 +1756,7 @@ fn extract_sec_and_nsec<'tcx>( /// Stores a file's metadata in order to avoid code duplication in the different metadata related /// shims. struct FileMetadata { - mode: Scalar, + mode: Scalar, size: u64, created: Option<(u64, u32)>, accessed: Option<(u64, u32)>, diff --git a/src/shims/unix/linux/dlsym.rs b/src/shims/unix/linux/dlsym.rs index 01bf17db9f09..44d51c4a0b3a 100644 --- a/src/shims/unix/linux/dlsym.rs +++ b/src/shims/unix/linux/dlsym.rs @@ -23,8 +23,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn call_dlsym( &mut self, dlsym: Dlsym, - _args: &[OpTy<'tcx, Tag>], - _dest: &PlaceTy<'tcx, Tag>, + _args: &[OpTy<'tcx, Provenance>], + _dest: &PlaceTy<'tcx, Provenance>, ret: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index efd4e2a8c03d..bae3780b460c 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -14,8 +14,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); @@ -165,10 +165,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Shims the linux `getrandom` syscall. fn getrandom<'tcx>( this: &mut MiriEvalContext<'_, 'tcx>, - ptr: &OpTy<'tcx, Tag>, - len: &OpTy<'tcx, Tag>, - flags: &OpTy<'tcx, Tag>, - dest: &PlaceTy<'tcx, Tag>, + ptr: &OpTy<'tcx, Provenance>, + len: &OpTy<'tcx, Provenance>, + flags: &OpTy<'tcx, Provenance>, + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx> { let ptr = this.read_pointer(ptr)?; let len = this.read_scalar(len)?.to_machine_usize(this)?; diff --git a/src/shims/unix/linux/sync.rs b/src/shims/unix/linux/sync.rs index d921b66afbd0..a11aa8ed849c 100644 --- a/src/shims/unix/linux/sync.rs +++ b/src/shims/unix/linux/sync.rs @@ -7,8 +7,8 @@ use std::time::{Instant, SystemTime}; /// `args` is the arguments *after* the syscall number. pub fn futex<'tcx>( this: &mut MiriEvalContext<'_, 'tcx>, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx> { // The amount of arguments used depends on the type of futex operation. // The full futex syscall takes six arguments (excluding the syscall diff --git a/src/shims/unix/macos/dlsym.rs b/src/shims/unix/macos/dlsym.rs index 2e97b7918e96..f21f1ae9af6d 100644 --- a/src/shims/unix/macos/dlsym.rs +++ b/src/shims/unix/macos/dlsym.rs @@ -27,8 +27,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn call_dlsym( &mut self, dlsym: Dlsym, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ret: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/shims/unix/macos/foreign_items.rs b/src/shims/unix/macos/foreign_items.rs index 58dd40cda301..21c7762c3ca1 100644 --- a/src/shims/unix/macos/foreign_items.rs +++ b/src/shims/unix/macos/foreign_items.rs @@ -12,8 +12,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); diff --git a/src/shims/unix/sync.rs b/src/shims/unix/sync.rs index 590bc1bf0056..18226c2b8cf6 100644 --- a/src/shims/unix/sync.rs +++ b/src/shims/unix/sync.rs @@ -21,14 +21,14 @@ const PTHREAD_MUTEX_NORMAL_FLAG: i32 = 0x8000000; fn is_mutex_kind_default<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - kind: Scalar, + kind: Scalar, ) -> InterpResult<'tcx, bool> { Ok(kind == ecx.eval_libc("PTHREAD_MUTEX_DEFAULT")?) } fn is_mutex_kind_normal<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - kind: Scalar, + kind: Scalar, ) -> InterpResult<'tcx, bool> { let kind = kind.to_i32()?; let mutex_normal_kind = ecx.eval_libc("PTHREAD_MUTEX_NORMAL")?.to_i32()?; @@ -37,15 +37,15 @@ fn is_mutex_kind_normal<'mir, 'tcx: 'mir>( fn mutexattr_get_kind<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, - attr_op: &OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { + attr_op: &OpTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset(attr_op, 0, ecx.machine.layouts.i32) } fn mutexattr_set_kind<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - attr_op: &OpTy<'tcx, Tag>, - kind: impl Into>, + attr_op: &OpTy<'tcx, Provenance>, + kind: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset(attr_op, 0, kind, layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.i32)) } @@ -61,8 +61,8 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( fn mutex_get_kind<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, - mutex_op: &OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { + mutex_op: &OpTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ScalarMaybeUninit> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; ecx.read_scalar_at_offset_atomic( mutex_op, @@ -74,8 +74,8 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>( fn mutex_set_kind<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - mutex_op: &OpTy<'tcx, Tag>, - kind: impl Into>, + mutex_op: &OpTy<'tcx, Provenance>, + kind: impl Into>, ) -> InterpResult<'tcx, ()> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; ecx.write_scalar_at_offset_atomic( @@ -89,15 +89,15 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( fn mutex_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, - mutex_op: &OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { + mutex_op: &OpTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset_atomic(mutex_op, 4, ecx.machine.layouts.u32, AtomicReadOrd::Relaxed) } fn mutex_set_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - mutex_op: &OpTy<'tcx, Tag>, - id: impl Into>, + mutex_op: &OpTy<'tcx, Provenance>, + id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset_atomic( mutex_op, @@ -110,7 +110,7 @@ fn mutex_set_id<'mir, 'tcx: 'mir>( fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - mutex_op: &OpTy<'tcx, Tag>, + mutex_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, MutexId> { let value_place = ecx.deref_operand_and_offset(mutex_op, 4, ecx.machine.layouts.u32)?; @@ -145,15 +145,15 @@ fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( fn rwlock_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, - rwlock_op: &OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { + rwlock_op: &OpTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset_atomic(rwlock_op, 4, ecx.machine.layouts.u32, AtomicReadOrd::Relaxed) } fn rwlock_set_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - rwlock_op: &OpTy<'tcx, Tag>, - id: impl Into>, + rwlock_op: &OpTy<'tcx, Provenance>, + id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset_atomic( rwlock_op, @@ -166,7 +166,7 @@ fn rwlock_set_id<'mir, 'tcx: 'mir>( fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - rwlock_op: &OpTy<'tcx, Tag>, + rwlock_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, RwLockId> { let value_place = ecx.deref_operand_and_offset(rwlock_op, 4, ecx.machine.layouts.u32)?; @@ -200,15 +200,15 @@ fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( fn condattr_get_clock_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, - attr_op: &OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { + attr_op: &OpTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset(attr_op, 0, ecx.machine.layouts.i32) } fn condattr_set_clock_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - attr_op: &OpTy<'tcx, Tag>, - clock_id: impl Into>, + attr_op: &OpTy<'tcx, Provenance>, + clock_id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset( attr_op, @@ -229,15 +229,15 @@ fn condattr_set_clock_id<'mir, 'tcx: 'mir>( fn cond_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, - cond_op: &OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { + cond_op: &OpTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset_atomic(cond_op, 4, ecx.machine.layouts.u32, AtomicReadOrd::Relaxed) } fn cond_set_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - cond_op: &OpTy<'tcx, Tag>, - id: impl Into>, + cond_op: &OpTy<'tcx, Provenance>, + id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset_atomic( cond_op, @@ -250,7 +250,7 @@ fn cond_set_id<'mir, 'tcx: 'mir>( fn cond_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - cond_op: &OpTy<'tcx, Tag>, + cond_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, CondvarId> { let value_place = ecx.deref_operand_and_offset(cond_op, 4, ecx.machine.layouts.u32)?; @@ -278,15 +278,15 @@ fn cond_get_or_create_id<'mir, 'tcx: 'mir>( fn cond_get_clock_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, - cond_op: &OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { + cond_op: &OpTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset(cond_op, 8, ecx.machine.layouts.i32) } fn cond_set_clock_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - cond_op: &OpTy<'tcx, Tag>, - clock_id: impl Into>, + cond_op: &OpTy<'tcx, Provenance>, + clock_id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset( cond_op, @@ -347,7 +347,10 @@ fn release_cond_mutex_and_block<'mir, 'tcx: 'mir>( impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn pthread_mutexattr_init(&mut self, attr_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_mutexattr_init( + &mut self, + attr_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let default_kind = this.eval_libc("PTHREAD_MUTEX_DEFAULT")?; @@ -358,8 +361,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutexattr_settype( &mut self, - attr_op: &OpTy<'tcx, Tag>, - kind_op: &OpTy<'tcx, Tag>, + attr_op: &OpTy<'tcx, Provenance>, + kind_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -397,7 +400,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_mutexattr_destroy(&mut self, attr_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_mutexattr_destroy( + &mut self, + attr_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); // Destroying an uninit pthread_mutexattr is UB, so check to make sure it's not uninit. @@ -423,8 +429,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_init( &mut self, - mutex_op: &OpTy<'tcx, Tag>, - attr_op: &OpTy<'tcx, Tag>, + mutex_op: &OpTy<'tcx, Provenance>, + attr_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -443,7 +449,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_mutex_lock(&mut self, mutex_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_mutex_lock(&mut self, mutex_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let kind = mutex_get_kind(this, mutex_op)?.check_init()?; @@ -480,7 +486,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn pthread_mutex_trylock(&mut self, mutex_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_mutex_trylock( + &mut self, + mutex_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let kind = mutex_get_kind(this, mutex_op)?.check_init()?; @@ -513,7 +522,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn pthread_mutex_unlock(&mut self, mutex_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_mutex_unlock( + &mut self, + mutex_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let kind = mutex_get_kind(this, mutex_op)?.check_init()?; @@ -545,7 +557,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn pthread_mutex_destroy(&mut self, mutex_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_mutex_destroy( + &mut self, + mutex_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = mutex_get_or_create_id(this, mutex_op)?; @@ -566,7 +581,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_rwlock_rdlock(&mut self, rwlock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_rdlock( + &mut self, + rwlock_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; @@ -581,7 +599,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_tryrdlock( + &mut self, + rwlock_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; @@ -595,7 +616,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn pthread_rwlock_wrlock(&mut self, rwlock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_wrlock( + &mut self, + rwlock_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; @@ -622,7 +646,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_rwlock_trywrlock(&mut self, rwlock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_trywrlock( + &mut self, + rwlock_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; @@ -636,7 +663,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn pthread_rwlock_unlock(&mut self, rwlock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_unlock( + &mut self, + rwlock_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; @@ -652,7 +682,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn pthread_rwlock_destroy(&mut self, rwlock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_destroy( + &mut self, + rwlock_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; @@ -671,7 +704,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_condattr_init(&mut self, attr_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_condattr_init( + &mut self, + attr_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); // The default value of the clock attribute shall refer to the system @@ -685,8 +721,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_condattr_setclock( &mut self, - attr_op: &OpTy<'tcx, Tag>, - clock_id_op: &OpTy<'tcx, Tag>, + attr_op: &OpTy<'tcx, Provenance>, + clock_id_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -705,8 +741,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_condattr_getclock( &mut self, - attr_op: &OpTy<'tcx, Tag>, - clk_id_op: &OpTy<'tcx, Tag>, + attr_op: &OpTy<'tcx, Provenance>, + clk_id_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -716,7 +752,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_condattr_destroy(&mut self, attr_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_condattr_destroy( + &mut self, + attr_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); // Destroying an uninit pthread_condattr is UB, so check to make sure it's not uninit. @@ -730,8 +769,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_cond_init( &mut self, - cond_op: &OpTy<'tcx, Tag>, - attr_op: &OpTy<'tcx, Tag>, + cond_op: &OpTy<'tcx, Provenance>, + attr_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -750,7 +789,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_cond_signal(&mut self, cond_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_cond_signal(&mut self, cond_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = cond_get_or_create_id(this, cond_op)?; if let Some((thread, mutex)) = this.condvar_signal(id) { @@ -760,7 +799,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_cond_broadcast(&mut self, cond_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_cond_broadcast( + &mut self, + cond_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = cond_get_or_create_id(this, cond_op)?; @@ -773,8 +815,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_cond_wait( &mut self, - cond_op: &OpTy<'tcx, Tag>, - mutex_op: &OpTy<'tcx, Tag>, + cond_op: &OpTy<'tcx, Provenance>, + mutex_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -790,10 +832,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_cond_timedwait( &mut self, - cond_op: &OpTy<'tcx, Tag>, - mutex_op: &OpTy<'tcx, Tag>, - abstime_op: &OpTy<'tcx, Tag>, - dest: &PlaceTy<'tcx, Tag>, + cond_op: &OpTy<'tcx, Provenance>, + mutex_op: &OpTy<'tcx, Provenance>, + abstime_op: &OpTy<'tcx, Provenance>, + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -852,7 +894,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - fn pthread_cond_destroy(&mut self, cond_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_cond_destroy( + &mut self, + cond_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = cond_get_or_create_id(this, cond_op)?; diff --git a/src/shims/unix/thread.rs b/src/shims/unix/thread.rs index 8dc5f81354a3..1a8531e88047 100644 --- a/src/shims/unix/thread.rs +++ b/src/shims/unix/thread.rs @@ -6,10 +6,10 @@ impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tc pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn pthread_create( &mut self, - thread: &OpTy<'tcx, Tag>, - _attr: &OpTy<'tcx, Tag>, - start_routine: &OpTy<'tcx, Tag>, - arg: &OpTy<'tcx, Tag>, + thread: &OpTy<'tcx, Provenance>, + _attr: &OpTy<'tcx, Provenance>, + start_routine: &OpTy<'tcx, Provenance>, + arg: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -59,8 +59,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_join( &mut self, - thread: &OpTy<'tcx, Tag>, - retval: &OpTy<'tcx, Tag>, + thread: &OpTy<'tcx, Provenance>, + retval: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -75,7 +75,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_detach(&mut self, thread: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_detach(&mut self, thread: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let thread_id = this.read_scalar(thread)?.to_machine_usize(this)?; @@ -84,14 +84,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_self(&mut self, dest: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn pthread_self(&mut self, dest: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let thread_id = this.get_active_thread(); this.write_scalar(Scalar::from_uint(thread_id.to_u32(), dest.layout.size), dest) } - fn prctl(&mut self, args: &[OpTy<'tcx, Tag>]) -> InterpResult<'tcx, i32> { + fn prctl(&mut self, args: &[OpTy<'tcx, Provenance>]) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("linux", "prctl"); @@ -138,7 +138,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_setname_np(&mut self, name: Pointer>) -> InterpResult<'tcx> { + fn pthread_setname_np(&mut self, name: Pointer>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.assert_target_os("macos", "pthread_setname_np"); diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 60ef11b79608..ee4f39227772 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -31,8 +31,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, dlsym: Dlsym, abi: Abi, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ret: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 65634342417b..3f4b8b14002e 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -15,8 +15,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); diff --git a/src/shims/windows/sync.rs b/src/shims/windows/sync.rs index 35603f7f3863..878b9b94a639 100644 --- a/src/shims/windows/sync.rs +++ b/src/shims/windows/sync.rs @@ -5,7 +5,7 @@ use crate::*; fn srwlock_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - lock_op: &OpTy<'tcx, Tag>, + lock_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, RwLockId> { let value_place = ecx.deref_operand_and_offset(lock_op, 0, ecx.machine.layouts.u32)?; @@ -34,7 +34,7 @@ fn srwlock_get_or_create_id<'mir, 'tcx: 'mir>( impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { #[allow(non_snake_case)] - fn AcquireSRWLockExclusive(&mut self, lock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn AcquireSRWLockExclusive(&mut self, lock_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; let active_thread = this.get_active_thread(); @@ -56,7 +56,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn TryAcquireSRWLockExclusive(&mut self, lock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, u8> { + fn TryAcquireSRWLockExclusive( + &mut self, + lock_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, u8> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; let active_thread = this.get_active_thread(); @@ -71,7 +74,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn ReleaseSRWLockExclusive(&mut self, lock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn ReleaseSRWLockExclusive(&mut self, lock_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; let active_thread = this.get_active_thread(); @@ -87,7 +90,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn AcquireSRWLockShared(&mut self, lock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn AcquireSRWLockShared(&mut self, lock_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; let active_thread = this.get_active_thread(); @@ -102,7 +105,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn TryAcquireSRWLockShared(&mut self, lock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, u8> { + fn TryAcquireSRWLockShared( + &mut self, + lock_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, u8> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; let active_thread = this.get_active_thread(); @@ -116,7 +122,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn ReleaseSRWLockShared(&mut self, lock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn ReleaseSRWLockShared(&mut self, lock_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; let active_thread = this.get_active_thread(); diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index 133164f390df..6521f0772112 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -5,11 +5,8 @@ use rustc_span::{Span, SpanData}; use rustc_target::abi::Size; use crate::helpers::CurrentSpan; -use crate::stacked_borrows::{err_sb_ub, AccessKind, Permission}; -use crate::Item; -use crate::SbTag; -use crate::SbTagExtra; -use crate::Stack; +use crate::stacked_borrows::{err_sb_ub, AccessKind}; +use crate::*; use rustc_middle::mir::interpret::InterpError; @@ -132,7 +129,7 @@ impl AllocHistory { /// Report a descriptive error when `new` could not be granted from `derived_from`. pub fn grant_error<'tcx>( &self, - derived_from: SbTagExtra, + derived_from: ProvenanceExtra, new: Item, alloc_id: AllocId, alloc_range: AllocRange, @@ -155,7 +152,7 @@ impl AllocHistory { pub fn access_error<'tcx>( &self, access: AccessKind, - tag: SbTagExtra, + tag: ProvenanceExtra, alloc_id: AllocId, alloc_range: AllocRange, error_offset: Size, @@ -181,8 +178,8 @@ fn operation_summary( format!("this error occurs as part of {operation} at {alloc_id:?}{alloc_range:?}") } -fn error_cause(stack: &Stack, tag: SbTagExtra) -> &'static str { - if let SbTagExtra::Concrete(tag) = tag { +fn error_cause(stack: &Stack, prov_extra: ProvenanceExtra) -> &'static str { + if let ProvenanceExtra::Concrete(tag) = prov_extra { if (0..stack.len()) .map(|i| stack.get(i).unwrap()) .any(|item| item.tag() == tag && item.perm() != Permission::Disabled) diff --git a/src/stacked_borrows/mod.rs b/src/stacked_borrows/mod.rs index fb40291302d6..c20927013b0b 100644 --- a/src/stacked_borrows/mod.rs +++ b/src/stacked_borrows/mod.rs @@ -55,32 +55,6 @@ impl fmt::Debug for SbTag { } } -/// The "extra" information an SB pointer has over a regular AllocId. -/// Newtype for `Option`. -#[derive(Copy, Clone)] -pub enum SbTagExtra { - Concrete(SbTag), - Wildcard, -} - -impl fmt::Debug for SbTagExtra { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - SbTagExtra::Concrete(pid) => write!(f, "{pid:?}"), - SbTagExtra::Wildcard => write!(f, ""), - } - } -} - -impl SbTagExtra { - fn and_then(self, f: impl FnOnce(SbTag) -> Option) -> Option { - match self { - SbTagExtra::Concrete(pid) => f(pid), - SbTagExtra::Wildcard => None, - } - } -} - #[derive(Debug)] pub struct FrameExtra { /// The ID of the call this frame corresponds to. @@ -311,7 +285,7 @@ impl<'tcx> Stack { /// currently checking. fn item_popped( item: &Item, - provoking_access: Option<(SbTagExtra, AllocRange, Size, AccessKind)>, // just for debug printing and error messages + provoking_access: Option<(ProvenanceExtra, AllocRange, Size, AccessKind)>, // just for debug printing and error messages global: &GlobalStateInner, alloc_history: &mut AllocHistory, threads: &ThreadManager<'_, 'tcx>, @@ -322,7 +296,7 @@ impl<'tcx> Stack { #[inline(never)] // cold path fn check_tracked( item: &Item, - provoking_access: &Option<(SbTagExtra, AllocRange, Size, AccessKind)>, + provoking_access: &Option<(ProvenanceExtra, AllocRange, Size, AccessKind)>, global: &GlobalStateInner, ) { if global.tracked_pointer_tags.contains(&item.tag()) { @@ -357,7 +331,7 @@ impl<'tcx> Stack { #[inline(never)] // cold path fn protector_error<'tcx>( item: &Item, - provoking_access: &Option<(SbTagExtra, AllocRange, Size, AccessKind)>, + provoking_access: &Option<(ProvenanceExtra, AllocRange, Size, AccessKind)>, alloc_history: &mut AllocHistory, threads: &ThreadManager<'_, 'tcx>, ) -> InterpErrorInfo<'tcx> { @@ -410,7 +384,7 @@ impl<'tcx> Stack { fn access( &mut self, access: AccessKind, - tag: SbTagExtra, + tag: ProvenanceExtra, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &mut GlobalStateInner, current_span: &mut CurrentSpan<'_, '_, 'tcx>, @@ -482,7 +456,7 @@ impl<'tcx> Stack { } // If this was an approximate action, we now collapse everything into an unknown. - if granting_idx.is_none() || matches!(tag, SbTagExtra::Wildcard) { + if granting_idx.is_none() || matches!(tag, ProvenanceExtra::Wildcard) { // Compute the upper bound of the items that remain. // (This is why we did all the work above: to reduce the items we have to consider here.) let mut max = NonZeroU64::new(1).unwrap(); @@ -512,7 +486,7 @@ impl<'tcx> Stack { /// active protectors at all because we will remove all items. fn dealloc( &mut self, - tag: SbTagExtra, + tag: ProvenanceExtra, (alloc_id, _alloc_range, _offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &GlobalStateInner, alloc_history: &mut AllocHistory, @@ -546,7 +520,7 @@ impl<'tcx> Stack { /// `range` that we are currently checking. fn grant( &mut self, - derived_from: SbTagExtra, + derived_from: ProvenanceExtra, new: Item, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &mut GlobalStateInner, @@ -575,7 +549,7 @@ impl<'tcx> Stack { "this case only makes sense for stack-like accesses" ); - let (Some(granting_idx), SbTagExtra::Concrete(_)) = (granting_idx, derived_from) else { + let (Some(granting_idx), ProvenanceExtra::Concrete(_)) = (granting_idx, derived_from) else { // The parent is a wildcard pointer or matched the unknown bottom. // This is approximate. Nobody knows what happened, so forget everything. // The new thing is SRW anyway, so we cannot push it "on top of the unkown part" @@ -686,7 +660,7 @@ impl Stacks { pub fn memory_read<'tcx>( &mut self, alloc_id: AllocId, - tag: SbTagExtra, + tag: ProvenanceExtra, range: AllocRange, state: &GlobalState, mut current_span: CurrentSpan<'_, '_, 'tcx>, @@ -717,7 +691,7 @@ impl Stacks { pub fn memory_written<'tcx>( &mut self, alloc_id: AllocId, - tag: SbTagExtra, + tag: ProvenanceExtra, range: AllocRange, state: &GlobalState, mut current_span: CurrentSpan<'_, '_, 'tcx>, @@ -748,7 +722,7 @@ impl Stacks { pub fn memory_deallocated<'tcx>( &mut self, alloc_id: AllocId, - tag: SbTagExtra, + tag: ProvenanceExtra, range: AllocRange, state: &GlobalState, threads: &ThreadManager<'_, 'tcx>, @@ -770,7 +744,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// happened. fn reborrow( &mut self, - place: &MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Provenance>, size: Size, kind: RefKind, new_tag: SbTag, @@ -782,7 +756,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // It is crucial that this gets called on all code paths, to ensure we track tag creation. let log_creation = |this: &MiriEvalContext<'mir, 'tcx>, current_span: &mut CurrentSpan<'_, 'mir, 'tcx>, - loc: Option<(AllocId, Size, SbTagExtra)>| // alloc_id, base_offset, orig_tag + loc: Option<(AllocId, Size, ProvenanceExtra)>| // alloc_id, base_offset, orig_tag -> InterpResult<'tcx> { let global = this.machine.stacked_borrows.as_ref().unwrap().borrow(); if global.tracked_pointer_tags.contains(&new_tag) { @@ -798,7 +772,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // The SB history tracking needs a parent tag, so skip if we come from a wildcard. - let SbTagExtra::Concrete(orig_tag) = orig_tag else { + let ProvenanceExtra::Concrete(orig_tag) = orig_tag else { // FIXME: should we log this? return Ok(()) }; @@ -972,10 +946,10 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// `mutbl` can be `None` to make this a raw pointer. fn retag_reference( &mut self, - val: &ImmTy<'tcx, Tag>, + val: &ImmTy<'tcx, Provenance>, kind: RefKind, protect: bool, - ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { + ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { let this = self.eval_context_mut(); // We want a place for where the ptr *points to*, so we get one. let place = this.ref_to_mplace(val)?; @@ -1001,12 +975,12 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(alloc_id) => { // If `reborrow` could figure out the AllocId of this ptr, hard-code it into the new one. // Even if we started out with a wildcard, this newly retagged pointer is tied to that allocation. - Tag::Concrete { alloc_id, sb: new_tag } + Provenance::Concrete { alloc_id, sb: new_tag } } None => { // Looks like this has to stay a wildcard pointer. - assert!(matches!(prov, Tag::Wildcard)); - Tag::Wildcard + assert!(matches!(prov, Provenance::Wildcard)); + Provenance::Wildcard } } }) @@ -1019,7 +993,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn retag(&mut self, kind: RetagKind, place: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn retag(&mut self, kind: RetagKind, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let retag_fields = this.machine.stacked_borrows.as_mut().unwrap().get_mut().retag_fields; let mut visitor = RetagVisitor { ecx: this, kind, retag_fields }; @@ -1057,7 +1031,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline(always)] // yes this helps in our benchmarks fn retag_place( &mut self, - place: &PlaceTy<'tcx, Tag>, + place: &PlaceTy<'tcx, Provenance>, ref_kind: RefKind, protector: bool, ) -> InterpResult<'tcx> { @@ -1070,14 +1044,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx impl<'ecx, 'mir, 'tcx> MutValueVisitor<'mir, 'tcx, Evaluator<'mir, 'tcx>> for RetagVisitor<'ecx, 'mir, 'tcx> { - type V = PlaceTy<'tcx, Tag>; + type V = PlaceTy<'tcx, Provenance>; #[inline(always)] fn ecx(&mut self) -> &mut MiriEvalContext<'mir, 'tcx> { self.ecx } - fn visit_box(&mut self, place: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn visit_box(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { // Boxes do not get a protector: protectors reflect that references outlive the call // they were passed in to; that's just not the case for boxes. self.retag_place( @@ -1087,7 +1061,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) } - fn visit_value(&mut self, place: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn visit_value(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { if let Some((ref_kind, protector)) = qualify(place.layout.ty, self.kind) { self.retag_place(place, ref_kind, protector)?; } else if matches!(place.layout.ty.kind(), ty::RawPtr(..)) { diff --git a/src/stacked_borrows/stack.rs b/src/stacked_borrows/stack.rs index 32c1be5fb1e2..c0d4d0d291f3 100644 --- a/src/stacked_borrows/stack.rs +++ b/src/stacked_borrows/stack.rs @@ -1,8 +1,11 @@ -use crate::stacked_borrows::{AccessKind, Item, Permission, SbTag, SbTagExtra}; -use rustc_data_structures::fx::FxHashSet; #[cfg(feature = "stack-cache")] use std::ops::Range; +use rustc_data_structures::fx::FxHashSet; + +use crate::stacked_borrows::{AccessKind, Item, Permission, SbTag}; +use crate::ProvenanceExtra; + /// Exactly what cache size we should use is a difficult tradeoff. There will always be some /// workload which has a `SbTag` working set which exceeds the size of the cache, and ends up /// falling back to linear searches of the borrow stack very often. @@ -126,13 +129,13 @@ impl<'tcx> Stack { pub(super) fn find_granting( &mut self, access: AccessKind, - tag: SbTagExtra, + tag: ProvenanceExtra, exposed_tags: &FxHashSet, ) -> Result, ()> { #[cfg(debug_assertions)] self.verify_cache_consistency(); - let SbTagExtra::Concrete(tag) = tag else { + let ProvenanceExtra::Concrete(tag) = tag else { // Handle the wildcard case. // Go search the stack for an exposed tag. if let Some(idx) = diff --git a/src/sync.rs b/src/sync.rs index 0eebe4f654e4..5571bbd8f2dc 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -42,7 +42,7 @@ macro_rules! declare_id { } impl $name { - pub fn to_u32_scalar<'tcx>(&self) -> Scalar { + pub fn to_u32_scalar<'tcx>(&self) -> Scalar { Scalar::from_u32(self.0.get()) } } diff --git a/src/thread.rs b/src/thread.rs index 96135d093d96..683694f482ea 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -70,7 +70,7 @@ impl From for ThreadId { } impl ThreadId { - pub fn to_u32_scalar(&self) -> Scalar { + pub fn to_u32_scalar(&self) -> Scalar { Scalar::from_u32(self.0) } } @@ -112,7 +112,7 @@ pub struct Thread<'mir, 'tcx> { thread_name: Option>, /// The virtual call stack. - stack: Vec>>, + stack: Vec>>, /// The join status. join_status: ThreadJoinStatus, @@ -120,10 +120,10 @@ pub struct Thread<'mir, 'tcx> { /// The temporary used for storing the argument of /// the call to `miri_start_panic` (the panic payload) when unwinding. /// This is pointer-sized, and matches the `Payload` type in `src/libpanic_unwind/miri.rs`. - pub(crate) panic_payload: Option>, + pub(crate) panic_payload: Option>, /// Last OS error location in memory. It is a 32-bit integer. - pub(crate) last_error: Option>, + pub(crate) last_error: Option>, } impl<'mir, 'tcx> Thread<'mir, 'tcx> { @@ -227,7 +227,7 @@ pub struct ThreadManager<'mir, 'tcx> { pub(crate) sync: SynchronizationState, /// A mapping from a thread-local static to an allocation id of a thread /// specific allocation. - thread_local_alloc_ids: RefCell>>, + thread_local_alloc_ids: RefCell>>, /// A flag that indicates that we should change the active thread. yield_active_thread: bool, /// Callbacks that are called once the specified time passes. @@ -256,7 +256,7 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Check if we have an allocation for the given thread local static for the /// active thread. - fn get_thread_local_alloc_id(&self, def_id: DefId) -> Option> { + fn get_thread_local_alloc_id(&self, def_id: DefId) -> Option> { self.thread_local_alloc_ids.borrow().get(&(def_id, self.active_thread)).cloned() } @@ -264,7 +264,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// static for the active thread. /// /// Panics if a thread local is initialized twice for the same thread. - fn set_thread_local_alloc(&self, def_id: DefId, ptr: Pointer) { + fn set_thread_local_alloc(&self, def_id: DefId, ptr: Pointer) { self.thread_local_alloc_ids .borrow_mut() .try_insert((def_id, self.active_thread), ptr) @@ -272,16 +272,20 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Borrow the stack of the active thread. - pub fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] { + pub fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>] { &self.threads[self.active_thread].stack } /// Mutably borrow the stack of the active thread. - fn active_thread_stack_mut(&mut self) -> &mut Vec>> { + fn active_thread_stack_mut( + &mut self, + ) -> &mut Vec>> { &mut self.threads[self.active_thread].stack } - pub fn all_stacks(&self) -> impl Iterator>]> { + pub fn all_stacks( + &self, + ) -> impl Iterator>]> { self.threads.iter().map(|t| &t.stack[..]) } @@ -468,7 +472,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { fn thread_terminated( &mut self, mut data_race: Option<&mut data_race::GlobalState>, - ) -> Vec> { + ) -> Vec> { let mut free_tls_statics = Vec::new(); { let mut thread_local_statics = self.thread_local_alloc_ids.borrow_mut(); @@ -589,7 +593,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn get_or_create_thread_local_alloc( &mut self, def_id: DefId, - ) -> InterpResult<'tcx, Pointer> { + ) -> InterpResult<'tcx, Pointer> { let this = self.eval_context_mut(); let tcx = this.tcx; if let Some(old_alloc) = this.machine.threads.get_thread_local_alloc_id(def_id) { @@ -686,13 +690,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[inline] - fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] { + fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>] { let this = self.eval_context_ref(); this.machine.threads.active_thread_stack() } #[inline] - fn active_thread_stack_mut(&mut self) -> &mut Vec>> { + fn active_thread_stack_mut( + &mut self, + ) -> &mut Vec>> { let this = self.eval_context_mut(); this.machine.threads.active_thread_stack_mut() } From 59f9a918eddcf9d131f55c2ef96d9e82a5706cf0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Jul 2022 17:40:49 -0400 Subject: [PATCH 3562/5092] handle get_alloc_extra the same throughout Stacked Borrows --- src/intptrcast.rs | 9 +++++-- src/machine.rs | 7 +++--- src/stacked_borrows/mod.rs | 48 ++++++++++++++++++++++++-------------- 3 files changed, 41 insertions(+), 23 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 4272966ae6cc..442c201e8ece 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -94,16 +94,21 @@ impl<'mir, 'tcx> GlobalStateInner { None } - pub fn expose_ptr(ecx: &mut MiriEvalContext<'mir, 'tcx>, alloc_id: AllocId, sb: SbTag) { + pub fn expose_ptr( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + alloc_id: AllocId, + sb: SbTag, + ) -> InterpResult<'tcx> { let global_state = ecx.machine.intptrcast.get_mut(); // In strict mode, we don't need this, so we can save some cycles by not tracking it. if global_state.provenance_mode != ProvenanceMode::Strict { trace!("Exposing allocation id {alloc_id:?}"); global_state.exposed.insert(alloc_id); if ecx.machine.stacked_borrows.is_some() { - ecx.expose_tag(alloc_id, sb); + ecx.expose_tag(alloc_id, sb)?; } } + Ok(()) } pub fn ptr_from_addr_transmute( diff --git a/src/machine.rs b/src/machine.rs index 1adfb8377811..1ac60e2ad84b 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -754,15 +754,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ptr: Pointer, ) -> InterpResult<'tcx> { match ptr.provenance { - Provenance::Concrete { alloc_id, sb } => { - intptrcast::GlobalStateInner::expose_ptr(ecx, alloc_id, sb); - } + Provenance::Concrete { alloc_id, sb } => + intptrcast::GlobalStateInner::expose_ptr(ecx, alloc_id, sb), Provenance::Wildcard => { // No need to do anything for wildcard pointers as // their provenances have already been previously exposed. + Ok(()) } } - Ok(()) } /// Convert a pointer with provenance into an allocation-offset pair, diff --git a/src/stacked_borrows/mod.rs b/src/stacked_borrows/mod.rs index c20927013b0b..38a73929a036 100644 --- a/src/stacked_borrows/mod.rs +++ b/src/stacked_borrows/mod.rs @@ -777,20 +777,31 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(()) }; - let extra = this.get_alloc_extra(alloc_id)?; - let mut stacked_borrows = extra - .stacked_borrows - .as_ref() - .expect("we should have Stacked Borrows data") - .borrow_mut(); - stacked_borrows.history.log_creation( - Some(orig_tag), - new_tag, - alloc_range(base_offset, size), - current_span, - ); - if protect { - stacked_borrows.history.log_protector(orig_tag, new_tag, current_span); + let (_size, _align, kind) = this.get_alloc_info(alloc_id); + match kind { + AllocKind::LiveData => { + // This should have alloc_extra data, but `get_alloc_extra` can still fail + // if converting this alloc_id from a global to a local one + // uncovers a non-supported `extern static`. + let extra = this.get_alloc_extra(alloc_id)?; + let mut stacked_borrows = extra + .stacked_borrows + .as_ref() + .expect("we should have Stacked Borrows data") + .borrow_mut(); + stacked_borrows.history.log_creation( + Some(orig_tag), + new_tag, + alloc_range(base_offset, size), + current_span, + ); + if protect { + stacked_borrows.history.log_protector(orig_tag, new_tag, current_span); + } + } + AllocKind::Function | AllocKind::Dead => { + // No stacked borrows on these allocations. + } } Ok(()) }; @@ -1116,7 +1127,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Mark the given tag as exposed. It was found on a pointer with the given AllocId. - fn expose_tag(&mut self, alloc_id: AllocId, tag: SbTag) { + fn expose_tag(&mut self, alloc_id: AllocId, tag: SbTag) -> InterpResult<'tcx> { let this = self.eval_context_mut(); // Function pointers and dead objects don't have an alloc_extra so we ignore them. @@ -1125,8 +1136,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (_size, _align, kind) = this.get_alloc_info(alloc_id); match kind { AllocKind::LiveData => { - // This should have alloc_extra data. - let alloc_extra = this.get_alloc_extra(alloc_id).unwrap(); + // This should have alloc_extra data, but `get_alloc_extra` can still fail + // if converting this alloc_id from a global to a local one + // uncovers a non-supported `extern static`. + let alloc_extra = this.get_alloc_extra(alloc_id)?; trace!("Stacked Borrows tag {tag:?} exposed in {alloc_id:?}"); alloc_extra.stacked_borrows.as_ref().unwrap().borrow_mut().exposed_tags.insert(tag); } @@ -1134,5 +1147,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // No stacked borrows on these allocations. } } + Ok(()) } } From e649a9acfb64bb3117a1695945f46c92f0a68d1a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Jul 2022 17:40:27 -0400 Subject: [PATCH 3563/5092] check for extern static size mismatches --- src/machine.rs | 29 +++++++++++++++++++--- tests/fail/extern_static_wrong_size.rs | 10 ++++++++ tests/fail/extern_static_wrong_size.stderr | 14 +++++++++++ 3 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 tests/fail/extern_static_wrong_size.rs create mode 100644 tests/fail/extern_static_wrong_size.stderr diff --git a/src/machine.rs b/src/machine.rs index 1ac60e2ad84b..67a6c997e990 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -638,12 +638,35 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ) -> InterpResult<'tcx, Pointer> { let link_name = ecx.item_link_name(def_id); if let Some(&ptr) = ecx.machine.extern_statics.get(&link_name) { + // Various parts of the engine rely on `get_alloc_info` for size and alignment + // information. That uses the type information of this static. + // Make sure it matches the Miri allocation for this. + let Provenance::Concrete { alloc_id, .. } = ptr.provenance else { + panic!("extern_statics cannot contain wildcards") + }; + let (shim_size, shim_align, _kind) = ecx.get_alloc_info(alloc_id); + let extern_decl_layout = + ecx.tcx.layout_of(ty::ParamEnv::empty().and(ecx.tcx.type_of(def_id))).unwrap(); + if extern_decl_layout.size != shim_size || extern_decl_layout.align.abi != shim_align { + throw_unsup_format!( + "`extern` static `{name}` from crate `{krate}` has been declared \ + with a size of {decl_size} bytes and alignment of {decl_align} bytes, \ + but Miri emulates it via an extern static shim \ + with a size of {shim_size} bytes and alignment of {shim_align} bytes", + name = ecx.tcx.def_path_str(def_id), + krate = ecx.tcx.crate_name(def_id.krate), + decl_size = extern_decl_layout.size.bytes(), + decl_align = extern_decl_layout.align.abi.bytes(), + shim_size = shim_size.bytes(), + shim_align = shim_align.bytes(), + ) + } Ok(ptr) } else { throw_unsup_format!( - "`extern` static `{}` from crate `{}` is not supported by Miri", - ecx.tcx.def_path_str(def_id), - ecx.tcx.crate_name(def_id.krate), + "`extern` static `{name}` from crate `{krate}` is not supported by Miri", + name = ecx.tcx.def_path_str(def_id), + krate = ecx.tcx.crate_name(def_id.krate), ) } } diff --git a/tests/fail/extern_static_wrong_size.rs b/tests/fail/extern_static_wrong_size.rs new file mode 100644 index 000000000000..17061f0e5c81 --- /dev/null +++ b/tests/fail/extern_static_wrong_size.rs @@ -0,0 +1,10 @@ +//@ only-target-linux: we need a specific extern supported on this target +//@normalize-stderr-test: "[48] bytes" -> "N bytes" + +extern "C" { + static mut environ: i8; +} + +fn main() { + let _val = unsafe { environ }; //~ ERROR: /has been declared with a size of 1 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of [48] bytes and alignment of [48] bytes/ +} diff --git a/tests/fail/extern_static_wrong_size.stderr b/tests/fail/extern_static_wrong_size.stderr new file mode 100644 index 000000000000..fdeb7bb5f688 --- /dev/null +++ b/tests/fail/extern_static_wrong_size.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: `extern` static `environ` from crate `extern_static_wrong_size` has been declared with a size of 1 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of N bytes and alignment of N bytes + --> $DIR/extern_static_wrong_size.rs:LL:CC + | +LL | let _val = unsafe { environ }; + | ^^^^^^^ `extern` static `environ` from crate `extern_static_wrong_size` has been declared with a size of 1 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of N bytes and alignment of N bytes + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = note: backtrace: + = note: inside `main` at $DIR/extern_static_wrong_size.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + From 9f99d1068959abdd7a51b0c43bcc54f83bc7ca30 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Jul 2022 18:31:44 -0400 Subject: [PATCH 3564/5092] =?UTF-8?q?some=20stray=20tag=20=E2=86=92=20prov?= =?UTF-8?q?=20renames?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/concurrency/data_race.rs | 2 +- src/shims/backtrace.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 3f05925d3438..90b38225105d 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -1061,7 +1061,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { if let Some(data_race) = &this.machine.data_race { if data_race.race_detecting() { let size = place.layout.size; - let (alloc_id, base_offset, _tag) = this.ptr_get_alloc_id(place.ptr)?; + let (alloc_id, base_offset, _prov) = this.ptr_get_alloc_id(place.ptr)?; // Load and log the atomic operation. // Note that atomic loads are possible even from read-only allocations, so `get_alloc_extra_mut` is not an option. let alloc_meta = this.get_alloc_extra(alloc_id)?.data_race.as_ref().unwrap(); diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 3c15165d67be..c5aab255aaf8 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -123,7 +123,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.read_pointer(ptr)?; // Take apart the pointer, we need its pieces. - let (alloc_id, offset, _tag) = this.ptr_get_alloc_id(ptr)?; + let (alloc_id, offset, _prov) = this.ptr_get_alloc_id(ptr)?; let fn_instance = if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(alloc_id) { From 517e1d78b8a2daf7285ddf24f8642a922df02f89 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 20 Jul 2022 12:38:27 +0000 Subject: [PATCH 3565/5092] Add a scheme for always using the default toolchain, running clippy and fmt before running any other command --- .gitignore | 1 + CONTRIBUTING.md | 13 +++++++++++++ miri | 19 +++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/.gitignore b/.gitignore index dcefbc62c70b..185ff4f756c1 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ tex/*/out perf.data perf.data.old flamegraph.svg +.auto-* diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a57ef09e7db9..47864d822c4f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,6 +28,11 @@ install that exact version of rustc as a toolchain: This will set up a rustup toolchain called `miri` and set it as an override for the current directory. +You can also create a `.auto-everything` file (contents don't matter, can be empty), which +will cause any `./miri` command to automatically call `rustup-toolchain`, `clippy` and `rustfmt` +for you. If you don't want all of these to happen, you can add individual `.auto-toolchain`, +`.auto-clippy` and `.auto-fmt` files respectively. + [`rustup-toolchain-install-master`]: https://github.com/kennytm/rustup-toolchain-install-master ## Building and testing Miri @@ -244,6 +249,14 @@ rustup toolchain link stage2 build/x86_64-unknown-linux-gnu/stage2 rustup override set stage2 ``` +Note: When you are working with a locally built rustc or any other toolchain that +is not the same as the one in `rust-version`, you should not have `.auto-everything` or +`.auto-toolchain` as that will keep resetting your toolchain. + +``` +rm -f .auto-everything .auto-toolchain +``` + Important: You need to delete the Miri cache when you change the stdlib; otherwise the old, chached version will be used. On Linux, the cache is located at `~/.cache/miri`, and on Windows, it is located at `%LOCALAPPDATA%\rust-lang\miri\cache`; the exact diff --git a/miri b/miri index 04d441b60780..19925e14be63 100755 --- a/miri +++ b/miri @@ -48,6 +48,25 @@ Pass extra flags to all cargo invocations. EOF ) +## Run the subcommands that the user requested to always run first +if [ -z "$AUTO_OPS" ]; then + export AUTO_OPS=42 + + # Run this first, so that the toolchain doesn't change after + # other code has run. + if [ -f ".auto-everything" ] || [ -f ".auto-toolchain" ] ; then + "$MIRIDIR"/rustup-toolchain + fi + + if [ -f ".auto-everything" ] || [ -f ".auto-fmt" ] ; then + $0 fmt + fi + + if [ -f ".auto-everything" ] || [ -f ".auto-clippy" ] ; then + $0 clippy -- -D warnings + fi +fi + ## Preparation # macOS does not have a useful readlink/realpath so we have to use Python instead... MIRIDIR=$(python3 -c 'import os, sys; print(os.path.dirname(os.path.realpath(sys.argv[1])))' "$0") From 4d4eeca8a8da67c3dd6e27dd8665b4f11763fd87 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Jul 2022 20:37:54 -0400 Subject: [PATCH 3566/5092] fix miri script --- miri | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/miri b/miri index 19925e14be63..2a9be1de3629 100755 --- a/miri +++ b/miri @@ -48,33 +48,34 @@ Pass extra flags to all cargo invocations. EOF ) -## Run the subcommands that the user requested to always run first +## We need to know where we are. +# macOS does not have a useful readlink/realpath so we have to use Python instead... +MIRIDIR=$(python3 -c 'import os, sys; print(os.path.dirname(os.path.realpath(sys.argv[1])))' "$0") + +## Run the auto-things. if [ -z "$AUTO_OPS" ]; then export AUTO_OPS=42 # Run this first, so that the toolchain doesn't change after # other code has run. - if [ -f ".auto-everything" ] || [ -f ".auto-toolchain" ] ; then + if [ -f "$MIRIDIR/.auto-everything" ] || [ -f "$MIRIDIR/.auto-toolchain" ] ; then "$MIRIDIR"/rustup-toolchain fi - if [ -f ".auto-everything" ] || [ -f ".auto-fmt" ] ; then + if [ -f "$MIRIDIR/.auto-everything" ] || [ -f "$MIRIDIR/.auto-fmt" ] ; then $0 fmt fi - if [ -f ".auto-everything" ] || [ -f ".auto-clippy" ] ; then + if [ -f "$MIRIDIR/.auto-everything" ] || [ -f "$MIRIDIR/.auto-clippy" ] ; then $0 clippy -- -D warnings fi fi -## Preparation -# macOS does not have a useful readlink/realpath so we have to use Python instead... -MIRIDIR=$(python3 -c 'import os, sys; print(os.path.dirname(os.path.realpath(sys.argv[1])))' "$0") -TOOLCHAIN=$(cd "$MIRIDIR"; rustup show active-toolchain | head -n 1 | cut -d ' ' -f 1) - -# Determine command. +## Determine command and toolchain. COMMAND="$1" [ $# -gt 0 ] && shift +# Doing this *after* auto-toolchain logic above, since that might change the toolchain. +TOOLCHAIN=$(cd "$MIRIDIR"; rustup show active-toolchain | head -n 1 | cut -d ' ' -f 1) ## Handle some commands early, since they should *not* alter the environment. case "$COMMAND" in From 88ad9ca9067ea1ce04313d7384c14fc24d1adbee Mon Sep 17 00:00:00 2001 From: Rain Date: Tue, 19 Jul 2022 19:37:24 -0700 Subject: [PATCH 3567/5092] [cargo-miri] support nextest Add the ability to run the `list` and `run` nextest commands, which enable per-test isolation. --- cargo-miri/bin.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index ecce1dece028..9f6603f80b7e 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -27,6 +27,7 @@ Usage: Subcommands: run, r Run binaries test, t Run tests + nextest Run tests with nextest (requires cargo-nextest installed) setup Only perform automatic setup, but without asking questions (for getting a proper libstd) The cargo options are exactly the same as for `cargo run` and `cargo test`, respectively. @@ -586,11 +587,10 @@ fn phase_cargo_miri(mut args: env::Args) { }; let subcommand = match &*subcommand { "setup" => MiriCommand::Setup, - "test" | "t" | "run" | "r" => MiriCommand::Forward(subcommand), - // Invalid command. + "test" | "t" | "run" | "r" | "nextest" => MiriCommand::Forward(subcommand), _ => show_error(format!( - "`cargo miri` supports the following subcommands: `run`, `test`, and `setup`." + "`cargo miri` supports the following subcommands: `run`, `test`, `nextest`, and `setup`." )), }; let verbose = num_arg_flag("-v"); From 30931eeecb047d1729d7c709af4036e20f20c5ea Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 18 Jul 2022 09:02:40 +0000 Subject: [PATCH 3568/5092] Add a dedicated thread for output printing --- ui_test/src/lib.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 4318e8a8e034..ee20920e54ff 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -123,11 +123,22 @@ pub fn run_tests(mut config: Config) -> Result<()> { drop(submit); }); + // A channel for the messages emitted by the individual test threads. + let (finish_file, finished_files) = crossbeam::channel::unbounded(); + + s.spawn(|_| { + for msg in finished_files { + eprintln!("{msg}"); + } + }); + let mut threads = vec![]; // Create N worker threads that receive files to test. for _ in 0..std::thread::available_parallelism().unwrap().get() { + let finish_file = finish_file.clone(); threads.push(s.spawn(|_| -> Result<()> { + let finish_file = finish_file; for path in &receive { if !config.path_filter.is_empty() { let path_display = path.display().to_string(); @@ -140,11 +151,12 @@ pub fn run_tests(mut config: Config) -> Result<()> { // Ignore file if only/ignore rules do (not) apply if !test_file_conditions(&comments, &target, &config) { ignored.fetch_add(1, Ordering::Relaxed); - eprintln!( + let msg = format!( "{} ... {}", path.display(), "ignored (in-test comment)".yellow() ); + finish_file.send(msg)?; continue; } // Run the test for all revisions @@ -161,10 +173,10 @@ pub fn run_tests(mut config: Config) -> Result<()> { } write!(msg, "... ").unwrap(); if errors.is_empty() { - eprintln!("{msg}{}", "ok".green()); + write!(msg, "{}", "ok".green()).unwrap(); succeeded.fetch_add(1, Ordering::Relaxed); } else { - eprintln!("{msg}{}", "FAILED".red().bold()); + write!(msg, "{}", "FAILED".red().bold()).unwrap(); failures.lock().unwrap().push(( path.clone(), m, @@ -173,11 +185,13 @@ pub fn run_tests(mut config: Config) -> Result<()> { stderr, )); } + finish_file.send(msg)?; } } Ok(()) })); } + for thread in threads { thread.join().unwrap()?; } From 68041b42fc4a915321c31895f4544e8e70a0c4c8 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 18 Jul 2022 09:19:20 +0000 Subject: [PATCH 3569/5092] Print one character per test instead of one line --- tests/compiletest.rs | 14 +++++++++++-- ui_test/src/lib.rs | 47 +++++++++++++++++++++++++++++++++----------- ui_test/src/tests.rs | 1 + 3 files changed, 48 insertions(+), 14 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 37b9de7327a2..72aa140d66a2 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -48,8 +48,17 @@ fn run_tests(mode: Mode, path: &str, target: Option) -> Result<()> { (true, true) => panic!("cannot use MIRI_BLESS and MIRI_SKIP_UI_CHECKS at the same time"), }; - // Pass on all arguments as filters. - let path_filter = std::env::args().skip(1); + // Pass on all unknown arguments as filters. + let mut quiet = false; + let path_filter = std::env::args().skip(1).filter(|arg| { + match &**arg { + "--quiet" => { + quiet = true; + false + } + _ => true, + } + }); let use_std = env::var_os("MIRI_NO_STD").is_none(); @@ -76,6 +85,7 @@ fn run_tests(mode: Mode, path: &str, target: Option) -> Result<()> { ], envs: vec![], }), + quiet, }; ui_test::run_tests(config) } diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index ee20920e54ff..f33f8cd83f33 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -46,6 +46,8 @@ pub struct Config { /// Can be used to override what command to run instead of `cargo` to build the /// dependencies in `manifest_path` pub dependency_builder: Option, + /// Print one character per test instead of one line + pub quiet: bool, } #[derive(Debug)] @@ -125,10 +127,38 @@ pub fn run_tests(mut config: Config) -> Result<()> { // A channel for the messages emitted by the individual test threads. let (finish_file, finished_files) = crossbeam::channel::unbounded(); + enum TestResult { + Ok, + Failed, + Ignored, + } s.spawn(|_| { - for msg in finished_files { - eprintln!("{msg}"); + if config.quiet { + for (i, (_, result)) in finished_files.into_iter().enumerate() { + // Humans start counting at 1 + let i = i + 1; + match result { + TestResult::Ok => eprint!("{}", ".".green()), + TestResult::Failed => eprint!("{}", "F".red().bold()), + TestResult::Ignored => eprint!("{}", "i".yellow()), + } + if i % 100 == 0 { + eprintln!(" {i}"); + } + } + } else { + for (msg, result) in finished_files { + eprint!("{msg} ... "); + eprintln!( + "{}", + match result { + TestResult::Ok => "ok".green(), + TestResult::Failed => "FAILED".red().bold(), + TestResult::Ignored => "ignored (in-test comment)".yellow(), + } + ); + } } }); @@ -151,12 +181,7 @@ pub fn run_tests(mut config: Config) -> Result<()> { // Ignore file if only/ignore rules do (not) apply if !test_file_conditions(&comments, &target, &config) { ignored.fetch_add(1, Ordering::Relaxed); - let msg = format!( - "{} ... {}", - path.display(), - "ignored (in-test comment)".yellow() - ); - finish_file.send(msg)?; + finish_file.send((path.display().to_string(), TestResult::Ignored))?; continue; } // Run the test for all revisions @@ -171,12 +196,11 @@ pub fn run_tests(mut config: Config) -> Result<()> { if !revision.is_empty() { write!(msg, "(revision `{revision}`) ").unwrap(); } - write!(msg, "... ").unwrap(); if errors.is_empty() { - write!(msg, "{}", "ok".green()).unwrap(); + finish_file.send((msg, TestResult::Ok))?; succeeded.fetch_add(1, Ordering::Relaxed); } else { - write!(msg, "{}", "FAILED".red().bold()).unwrap(); + finish_file.send((msg, TestResult::Failed))?; failures.lock().unwrap().push(( path.clone(), m, @@ -185,7 +209,6 @@ pub fn run_tests(mut config: Config) -> Result<()> { stderr, )); } - finish_file.send(msg)?; } } Ok(()) diff --git a/ui_test/src/tests.rs b/ui_test/src/tests.rs index 8b0bd517a105..2032988ed384 100644 --- a/ui_test/src/tests.rs +++ b/ui_test/src/tests.rs @@ -18,6 +18,7 @@ fn config() -> Config { output_conflict_handling: OutputConflictHandling::Error, dependencies_crate_manifest_path: None, dependency_builder: None, + quiet: false, } } From ecacc56843ae0bd1ba264a9abf95c31ee66a9f8b Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 21 Jul 2022 07:39:54 +0000 Subject: [PATCH 3570/5092] Use names suggestive of channel endpoints --- ui_test/src/lib.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index f33f8cd83f33..06a84cfbf32e 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -126,7 +126,7 @@ pub fn run_tests(mut config: Config) -> Result<()> { }); // A channel for the messages emitted by the individual test threads. - let (finish_file, finished_files) = crossbeam::channel::unbounded(); + let (finished_files_sender, finished_files_recv) = crossbeam::channel::unbounded(); enum TestResult { Ok, Failed, @@ -135,7 +135,7 @@ pub fn run_tests(mut config: Config) -> Result<()> { s.spawn(|_| { if config.quiet { - for (i, (_, result)) in finished_files.into_iter().enumerate() { + for (i, (_, result)) in finished_files_recv.into_iter().enumerate() { // Humans start counting at 1 let i = i + 1; match result { @@ -148,7 +148,7 @@ pub fn run_tests(mut config: Config) -> Result<()> { } } } else { - for (msg, result) in finished_files { + for (msg, result) in finished_files_recv { eprint!("{msg} ... "); eprintln!( "{}", @@ -166,9 +166,9 @@ pub fn run_tests(mut config: Config) -> Result<()> { // Create N worker threads that receive files to test. for _ in 0..std::thread::available_parallelism().unwrap().get() { - let finish_file = finish_file.clone(); + let finished_files_sender = finished_files_sender.clone(); threads.push(s.spawn(|_| -> Result<()> { - let finish_file = finish_file; + let finished_files_sender = finished_files_sender; for path in &receive { if !config.path_filter.is_empty() { let path_display = path.display().to_string(); @@ -181,7 +181,8 @@ pub fn run_tests(mut config: Config) -> Result<()> { // Ignore file if only/ignore rules do (not) apply if !test_file_conditions(&comments, &target, &config) { ignored.fetch_add(1, Ordering::Relaxed); - finish_file.send((path.display().to_string(), TestResult::Ignored))?; + finished_files_sender + .send((path.display().to_string(), TestResult::Ignored))?; continue; } // Run the test for all revisions @@ -197,10 +198,10 @@ pub fn run_tests(mut config: Config) -> Result<()> { write!(msg, "(revision `{revision}`) ").unwrap(); } if errors.is_empty() { - finish_file.send((msg, TestResult::Ok))?; + finished_files_sender.send((msg, TestResult::Ok))?; succeeded.fetch_add(1, Ordering::Relaxed); } else { - finish_file.send((msg, TestResult::Failed))?; + finished_files_sender.send((msg, TestResult::Failed))?; failures.lock().unwrap().push(( path.clone(), m, From 7c30ba183c9903362ffc93921d659dda665f5039 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 07:19:56 -0400 Subject: [PATCH 3571/5092] fix auto-toolchain pwd --- miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri b/miri index 2a9be1de3629..38f8e546aecb 100755 --- a/miri +++ b/miri @@ -59,7 +59,7 @@ if [ -z "$AUTO_OPS" ]; then # Run this first, so that the toolchain doesn't change after # other code has run. if [ -f "$MIRIDIR/.auto-everything" ] || [ -f "$MIRIDIR/.auto-toolchain" ] ; then - "$MIRIDIR"/rustup-toolchain + (cd "$MIRIDIR" && ./rustup-toolchain) fi if [ -f "$MIRIDIR/.auto-everything" ] || [ -f "$MIRIDIR/.auto-fmt" ] ; then From 8fa15428786e1e618791566b474e5b3bcf34775d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 08:06:11 -0400 Subject: [PATCH 3572/5092] make test-cargo-miri only about cargo remove rand (large dependency) and page-size (testing the dependency, not cargo-miri). keep only byteorder as a "demo" dependency, it is a leaf and builds quickly. --- test-cargo-miri/Cargo.lock | 108 ++---------------- test-cargo-miri/Cargo.toml | 3 +- test-cargo-miri/cdylib/Cargo.toml | 2 +- test-cargo-miri/run-test.py | 2 +- test-cargo-miri/src/main.rs | 11 +- test-cargo-miri/test.bin-target.stdout.ref | 2 +- test-cargo-miri/test.cross-target.stdout.ref | 6 +- test-cargo-miri/test.default.stdout.ref | 6 +- .../test.filter.cross-target.stdout.ref | 4 +- test-cargo-miri/test.filter.stdout.ref | 4 +- test-cargo-miri/test.test-target.stdout.ref | 10 +- test-cargo-miri/tests/test.rs | 46 +++----- 12 files changed, 45 insertions(+), 159 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 4cf58d723a25..3f61fb3d5408 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "byteorder" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" + [[package]] name = "byteorder" version = "1.4.3" @@ -12,7 +18,8 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" name = "cargo-miri-test" version = "0.1.0" dependencies = [ - "byteorder", + "byteorder 0.5.3", + "byteorder 1.4.3", "cdylib", "exported_symbol", "issue_1567", @@ -20,8 +27,6 @@ dependencies = [ "issue_1705", "issue_1760", "issue_rust_86261", - "page_size", - "rand", "serde_derive", ] @@ -29,15 +34,9 @@ dependencies = [ name = "cdylib" version = "0.1.0" dependencies = [ - "byteorder", + "byteorder 1.4.3", ] -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - [[package]] name = "exported_symbol" version = "0.1.0" @@ -49,17 +48,6 @@ dependencies = [ name = "exported_symbol_dep" version = "0.1.0" -[[package]] -name = "getrandom" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - [[package]] name = "hermit-abi" version = "0.1.19" @@ -73,7 +61,7 @@ dependencies = [ name = "issue_1567" version = "0.1.0" dependencies = [ - "byteorder", + "byteorder 1.4.3", ] [[package]] @@ -84,7 +72,7 @@ version = "0.1.0" name = "issue_1705" version = "0.1.0" dependencies = [ - "byteorder", + "byteorder 1.4.3", ] [[package]] @@ -111,22 +99,6 @@ dependencies = [ "libc", ] -[[package]] -name = "page_size" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eebde548fbbf1ea81a99b128872779c437752fb99f217c45245e1a61dcd9edcd" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" - [[package]] name = "proc-macro2" version = "1.0.40" @@ -145,36 +117,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" -dependencies = [ - "getrandom", -] - [[package]] name = "serde_derive" version = "1.0.137" @@ -209,31 +151,3 @@ name = "unicode-ident" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 89a8463e4b32..51967c54e15c 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -18,9 +18,8 @@ issue_1760 = { path = "issue-1760" } issue_rust_86261 = { path = "issue-rust-86261" } [dev-dependencies] -rand = { version = "0.8", features = ["small_rng"] } +byteorder_2 = { package = "byteorder", version = "0.5" } # to test dev-dependencies behave as expected, with renaming serde_derive = "1.0" # not actually used, but exercises some unique code path (`--extern` .so file) -page_size = "0.4.1" [lib] test = false # test that this is respected (will show in the output) diff --git a/test-cargo-miri/cdylib/Cargo.toml b/test-cargo-miri/cdylib/Cargo.toml index 4e5b5601a56c..527602e0a888 100644 --- a/test-cargo-miri/cdylib/Cargo.toml +++ b/test-cargo-miri/cdylib/Cargo.toml @@ -9,4 +9,4 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -byteorder = "1.0" +byteorder = "1.0" # to test dependencies of sub-crates diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index bc0046ffb148..ab43c7251158 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -134,7 +134,7 @@ def test_cargo_miri_test(): env={'MIRIFLAGS': "-Zmiri-permissive-provenance -Zmiri-disable-isolation"}, ) test("`cargo miri test` (with filter)", - cargo_miri("test") + ["--", "--format=pretty", "le1"], + cargo_miri("test") + ["--", "--format=pretty", "pl"], filter_ref, "test.stderr-empty.ref", ) test("`cargo miri test` (test target)", diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index 5807d0765fb3..41c52b701702 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -45,17 +45,12 @@ fn main() { #[cfg(test)] mod test { - use rand::{Rng, SeedableRng}; + use byteorder_2::{BigEndian, ByteOrder}; // Make sure in-crate tests with dev-dependencies work #[test] - fn rng() { - let mut rng = rand::rngs::StdRng::seed_from_u64(0xcafebeef); - let x: u32 = rng.gen(); - let y: usize = rng.gen(); - let z: u128 = rng.gen(); - assert_ne!(x as usize, y); - assert_ne!(y as u128, z); + fn dev_dependency() { + let _n = ::read_u64(&[1, 2, 3, 4, 5, 6, 7, 8]); } #[test] diff --git a/test-cargo-miri/test.bin-target.stdout.ref b/test-cargo-miri/test.bin-target.stdout.ref index 62cfd1d37a17..5264530160bc 100644 --- a/test-cargo-miri/test.bin-target.stdout.ref +++ b/test-cargo-miri/test.bin-target.stdout.ref @@ -1,7 +1,7 @@ running 2 tests +test test::dev_dependency ... ok test test::exported_symbol ... ok -test test::rng ... ok test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/test.cross-target.stdout.ref b/test-cargo-miri/test.cross-target.stdout.ref index 3673e5549d8c..8c543e479f4e 100644 --- a/test-cargo-miri/test.cross-target.stdout.ref +++ b/test-cargo-miri/test.cross-target.stdout.ref @@ -5,7 +5,7 @@ test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out imported main -running 8 tests -..i..... -test result: ok. 7 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out +running 6 tests +...i.. +test result: ok. 5 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/test.default.stdout.ref b/test-cargo-miri/test.default.stdout.ref index a59108efb332..9a17f3d61b6a 100644 --- a/test-cargo-miri/test.default.stdout.ref +++ b/test-cargo-miri/test.default.stdout.ref @@ -5,9 +5,9 @@ test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out imported main -running 8 tests -..i..... -test result: ok. 7 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out +running 6 tests +...i.. +test result: ok. 5 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out running 4 tests diff --git a/test-cargo-miri/test.filter.cross-target.stdout.ref b/test-cargo-miri/test.filter.cross-target.stdout.ref index 9fb7670d0649..bb0282d6c916 100644 --- a/test-cargo-miri/test.filter.cross-target.stdout.ref +++ b/test-cargo-miri/test.filter.cross-target.stdout.ref @@ -6,7 +6,7 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out imported main running 1 test -test simple1 ... ok +test simple ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 7 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 5 filtered out diff --git a/test-cargo-miri/test.filter.stdout.ref b/test-cargo-miri/test.filter.stdout.ref index 4b598960a096..c618956656a8 100644 --- a/test-cargo-miri/test.filter.stdout.ref +++ b/test-cargo-miri/test.filter.stdout.ref @@ -6,9 +6,9 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out imported main running 1 test -test simple1 ... ok +test simple ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 7 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 5 filtered out running 0 tests diff --git a/test-cargo-miri/test.test-target.stdout.ref b/test-cargo-miri/test.test-target.stdout.ref index ca069b702eba..dd59b32b780c 100644 --- a/test-cargo-miri/test.test-target.stdout.ref +++ b/test-cargo-miri/test.test-target.stdout.ref @@ -1,13 +1,11 @@ -running 8 tests +running 6 tests test cargo_env ... ok +test deps ... ok test do_panic - should panic ... ok test does_not_work_on_miri ... ignored -test entropy_rng ... ok test fail_index_check - should panic ... ok -test page_size ... ok -test simple1 ... ok -test simple2 ... ok +test simple ... ok -test result: ok. 7 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out +test result: ok. 5 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index eb31058e1c19..1d8282accc02 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -1,39 +1,26 @@ -use rand::{rngs::SmallRng, Rng, SeedableRng}; - -// Having more than 1 test does seem to make a difference -// (i.e., this calls ptr::swap which having just one test does not). #[test] -fn simple1() { +fn simple() { assert_eq!(4, 4); } -#[test] -fn simple2() { - assert_ne!(42, 24); -} - // A test that won't work on miri (tests disabling tests). #[test] #[cfg_attr(miri, ignore)] fn does_not_work_on_miri() { - let x = 0u8; - assert!(&x as *const _ as usize % 4 < 4); + unsafe { std::arch::asm!("") }; } -// Make sure integration tests can access dev-dependencies +// Make sure integration tests can access both dependencies and dev-dependencies #[test] -fn entropy_rng() { - // Try seeding with "real" entropy. - let mut rng = SmallRng::from_entropy(); - let _val = rng.gen::(); - let _val = rng.gen::(); - let _val = rng.gen::(); - - // Also try per-thread RNG. - let mut rng = rand::thread_rng(); - let _val = rng.gen::(); - let _val = rng.gen::(); - let _val = rng.gen::(); +fn deps() { + { + use byteorder::{BigEndian, ByteOrder}; + let _n = ::read_u64(&[1, 2, 3, 4, 5, 6, 7, 8]); + } + { + use byteorder_2::{BigEndian, ByteOrder}; + let _n = ::read_u64(&[1, 2, 3, 4, 5, 6, 7, 8]); + } } #[test] @@ -49,17 +36,10 @@ fn do_panic() // In large, friendly letters :) panic!("Explicit panic from test!"); } +// A different way of raising a panic #[test] #[allow(unconditional_panic)] #[should_panic(expected = "the len is 0 but the index is 42")] fn fail_index_check() { [][42] } - -#[test] -fn page_size() { - let page_size = page_size::get(); - - // In particular, this checks that it is not 0. - assert!(page_size.is_power_of_two(), "page size not a power of two: {}", page_size); -} From b1b368c30ebc55b752e69ac687791504e62851cc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 08:14:41 -0400 Subject: [PATCH 3573/5092] test page_size via test dependency support and move crate tests to their own folders --- test_dependencies/Cargo.lock | 11 +++++++++++ test_dependencies/Cargo.toml | 1 + tests/fail/{ => crates}/tokio_mvp.rs | 0 tests/fail/{ => crates}/tokio_mvp.stderr | 0 tests/pass/crates/page_size.rs | 6 ++++++ tests/pass/{ => crates}/random.rs | 0 6 files changed, 18 insertions(+) rename tests/fail/{ => crates}/tokio_mvp.rs (100%) rename tests/fail/{ => crates}/tokio_mvp.stderr (100%) create mode 100644 tests/pass/crates/page_size.rs rename tests/pass/{ => crates}/random.rs (100%) diff --git a/test_dependencies/Cargo.lock b/test_dependencies/Cargo.lock index 6b5e8c942244..a492deba4c52 100644 --- a/test_dependencies/Cargo.lock +++ b/test_dependencies/Cargo.lock @@ -107,6 +107,7 @@ dependencies = [ "getrandom 0.1.16", "getrandom 0.2.7", "libc", + "page_size", "rand", "tokio", ] @@ -127,6 +128,16 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" +[[package]] +name = "page_size" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eebde548fbbf1ea81a99b128872779c437752fb99f217c45245e1a61dcd9edcd" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "parking_lot" version = "0.12.1" diff --git a/test_dependencies/Cargo.toml b/test_dependencies/Cargo.toml index edaa6a692603..0bf43aefebff 100644 --- a/test_dependencies/Cargo.toml +++ b/test_dependencies/Cargo.toml @@ -11,6 +11,7 @@ edition = "2021" # all dependencies (and their transitive ones) listed here can be used in `tests/`. tokio = { version = "1.0", features = ["full"] } libc = "0.2" +page_size = "0.4.1" getrandom_1 = { package = "getrandom", version = "0.1" } getrandom_2 = { package = "getrandom", version = "0.2" } diff --git a/tests/fail/tokio_mvp.rs b/tests/fail/crates/tokio_mvp.rs similarity index 100% rename from tests/fail/tokio_mvp.rs rename to tests/fail/crates/tokio_mvp.rs diff --git a/tests/fail/tokio_mvp.stderr b/tests/fail/crates/tokio_mvp.stderr similarity index 100% rename from tests/fail/tokio_mvp.stderr rename to tests/fail/crates/tokio_mvp.stderr diff --git a/tests/pass/crates/page_size.rs b/tests/pass/crates/page_size.rs new file mode 100644 index 000000000000..cdcabf333381 --- /dev/null +++ b/tests/pass/crates/page_size.rs @@ -0,0 +1,6 @@ +fn main() { + let page_size = page_size::get(); + + // In particular, this checks that it is not 0. + assert!(page_size.is_power_of_two(), "page size not a power of two: {}", page_size); +} diff --git a/tests/pass/random.rs b/tests/pass/crates/random.rs similarity index 100% rename from tests/pass/random.rs rename to tests/pass/crates/random.rs From 800273c1d9005c6433098735f663bd8e362ce69b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 09:14:11 -0400 Subject: [PATCH 3574/5092] cargo-miri: set RUSTC to us --- cargo-miri/bin.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 9f6603f80b7e..d2c772d7d922 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -661,14 +661,17 @@ fn phase_cargo_miri(mut args: env::Args) { ); } cmd.env("RUSTC_WRAPPER", &cargo_miri_path); - // Having both `RUSTC_WRAPPER` and `RUSTC` set does some odd things, so let's avoid that. - // See . + // We are going to invoke `MIRI` for everything, not `RUSTC`. if env::var_os("RUSTC").is_some() && env::var_os("MIRI").is_none() { println!( "WARNING: Ignoring `RUSTC` environment variable; set `MIRI` if you want to control the binary used as the driver." ); } - cmd.env_remove("RUSTC"); + // We'd prefer to just clear this env var, but cargo does not always honor `RUSTC_WRAPPER` + // (https://github.com/rust-lang/cargo/issues/10885). There is no good way to single out these invocations; + // some build scripts use the RUSTC env var as well. So we set it directly to the `miri` driver and + // hope that all they do is ask for the version number -- things could quickly go downhill from here. + cmd.env("RUSTC", &find_miri()); let runner_env_name = |triple: &str| format!("CARGO_TARGET_{}_RUNNER", triple.to_uppercase().replace('-', "_")); @@ -1173,8 +1176,14 @@ fn main() { match args.next().as_deref() { Some("miri") => phase_cargo_miri(args), - Some("rustc") => phase_rustc(args, RustcPhase::Build), Some(arg) => { + // If the first arg is equal to the RUSTC variable (which should be set at this point), + // then we need to behave as rustc. This is the somewhat counter-intuitive behavior of + // having both RUSTC and RUSTC_WRAPPER set (see + // https://github.com/rust-lang/cargo/issues/10886). + if arg == env::var_os("RUSTC").unwrap() { + return phase_rustc(args, RustcPhase::Build); + } // We have to distinguish the "runner" and "rustdoc" cases. // As runner, the first argument is the binary (a file that should exist, with an absolute path); // as rustdoc, the first argument is a flag (`--something`). From 7cd1d78a4769995546967e413dbbd672c11a153e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 09:30:09 -0400 Subject: [PATCH 3575/5092] only complain about runtime toolchain mismatch when there actually is a runtime toolchain --- src/bin/miri.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 8bd33b591d72..516c730e3fbd 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -220,16 +220,17 @@ fn compile_time_sysroot() -> Option { let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); Some(match (home, toolchain) { (Some(home), Some(toolchain)) => { - // Check that at runtime, we are still in this toolchain. - let toolchain_runtime = - env::var_os("RUSTUP_TOOLCHAIN").or_else(|| env::var_os("MULTIRUST_TOOLCHAIN")); - if !matches!(toolchain_runtime, Some(r) if r == toolchain) { - show_error(format!( - "This Miri got built with local toolchain `{toolchain}`, but now is being run under a different toolchain. \n\ + // Check that at runtime, we are still in this toolchain (if there is any toolchain). + if let Some(toolchain_runtime) = + env::var_os("RUSTUP_TOOLCHAIN").or_else(|| env::var_os("MULTIRUST_TOOLCHAIN")) + { + if toolchain_runtime != toolchain { + show_error(format!( + "This Miri got built with local toolchain `{toolchain}`, but now is being run under a different toolchain. \n\ Make sure to run Miri in the toolchain it got built with, e.g. via `cargo +{toolchain} miri`." - )); + )); + } } - format!("{}/toolchains/{}", home, toolchain) } _ => option_env!("RUST_SYSROOT") From 929712c49c112e20332cbb87acc3f6941450979b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 09:36:59 -0400 Subject: [PATCH 3576/5092] reduce chance of RUSTC collisions --- cargo-miri/bin.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index d2c772d7d922..53d348c16d71 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -671,7 +671,10 @@ fn phase_cargo_miri(mut args: env::Args) { // (https://github.com/rust-lang/cargo/issues/10885). There is no good way to single out these invocations; // some build scripts use the RUSTC env var as well. So we set it directly to the `miri` driver and // hope that all they do is ask for the version number -- things could quickly go downhill from here. - cmd.env("RUSTC", &find_miri()); + // In `main`, we need the value of `RUSTC` to distinguish RUSTC_WRAPPER invocations from rustdoc + // or TARGET_RUNNER invocations, so we canonicalize it here to make it exceedingly unlikely that + // there would be a collision. + cmd.env("RUSTC", &fs::canonicalize(find_miri()).unwrap()); let runner_env_name = |triple: &str| format!("CARGO_TARGET_{}_RUNNER", triple.to_uppercase().replace('-', "_")); From 0a9feb3c9f93eb66d75a731dfd41151af16252b5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 09:58:00 -0400 Subject: [PATCH 3577/5092] some more debug output --- cargo-miri/bin.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 53d348c16d71..9c964829dd13 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -820,10 +820,10 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { if verbose > 0 { eprintln!( - "[cargo-miri rustc] captured input:\n{}", + "[cargo-miri rustc inside rustdoc] captured input:\n{}", std::str::from_utf8(&env.stdin).unwrap() ); - eprintln!("[cargo-miri rustc] {:?}", cmd); + eprintln!("[cargo-miri rustc inside rustdoc] going to run:\n{:?}", cmd); } exec_with_pipe(cmd, &env.stdin); @@ -906,7 +906,10 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { // Run it. if verbose > 0 { - eprint!("[cargo-miri rustc] "); + eprintln!( + "[cargo-miri rustc] target_crate={target_crate} runnable_crate={runnable_crate} print={print}" + ); + eprintln!("[cargo-miri rustc] going to run:"); if verbose > 1 { for (key, value) in env_vars_from_cmd(&cmd) { eprintln!("{key}={value:?} \\"); From bb52965b73bb5885591fdd5b596a8d8f36d75f4e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 10:36:55 -0400 Subject: [PATCH 3578/5092] make the find_miri returned path actually exist --- cargo-miri/bin.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 9c964829dd13..48beb7c935d6 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -212,7 +212,11 @@ fn find_miri() -> PathBuf { return path.into(); } let mut path = std::env::current_exe().expect("current executable path invalid"); - path.set_file_name("miri"); + if cfg!(windows) { + path.set_file_name("miri.exe"); + } else { + path.set_file_name("miri"); + } path } From 5e4b64645712b0cefd3de751907d00210f735ed0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 10:48:41 -0400 Subject: [PATCH 3579/5092] aarch inline asm is not stable yet --- test-cargo-miri/tests/test.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 1d8282accc02..9ed215289396 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -7,7 +7,11 @@ fn simple() { #[test] #[cfg_attr(miri, ignore)] fn does_not_work_on_miri() { - unsafe { std::arch::asm!("") }; + // Only do this where inline assembly is stable. + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + unsafe { + std::arch::asm!("foo"); + } } // Make sure integration tests can access both dependencies and dev-dependencies From 392342fcaf4c08c060d7ea7db2c03f3b5830def9 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 21 Jul 2022 11:45:22 +0000 Subject: [PATCH 3580/5092] Avoid rustformatting on autosave --- CONTRIBUTING.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 47864d822c4f..f6147bbbe535 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -168,11 +168,15 @@ to `.vscode/settings.json` in your local Miri clone: "./cargo-miri/Cargo.toml" ], "rust-analyzer.checkOnSave.overrideCommand": [ + "env", + "AUTO_OPS=42", "./miri", "check", "--message-format=json" ], "rust-analyzer.buildScripts.overrideCommand": [ + "env", + "AUTO_OPS=42", "./miri", "check", "--message-format=json", From bfa2ff646c5830de1662576658f4ae69e207ffca Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 21 Jul 2022 12:24:13 +0000 Subject: [PATCH 3581/5092] Use a MIRI namespaced env var name for auto ops --- CONTRIBUTING.md | 4 ++-- miri | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f6147bbbe535..42f77b5cbc0e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -169,14 +169,14 @@ to `.vscode/settings.json` in your local Miri clone: ], "rust-analyzer.checkOnSave.overrideCommand": [ "env", - "AUTO_OPS=42", + "MIRI_AUTO_OPS=no", "./miri", "check", "--message-format=json" ], "rust-analyzer.buildScripts.overrideCommand": [ "env", - "AUTO_OPS=42", + "MIRI_AUTO_OPS=no", "./miri", "check", "--message-format=json", diff --git a/miri b/miri index 38f8e546aecb..463e4607baed 100755 --- a/miri +++ b/miri @@ -53,8 +53,8 @@ EOF MIRIDIR=$(python3 -c 'import os, sys; print(os.path.dirname(os.path.realpath(sys.argv[1])))' "$0") ## Run the auto-things. -if [ -z "$AUTO_OPS" ]; then - export AUTO_OPS=42 +if [ -z "$MIRI_AUTO_OPS" ]; then + export MIRI_AUTO_OPS=42 # Run this first, so that the toolchain doesn't change after # other code has run. From 9e7f3cdc36fdef06647f5c35a91dc4631f0b92d7 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 21 Jul 2022 15:07:07 +0000 Subject: [PATCH 3582/5092] Document MIRI_AUTO_OPS --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index d1dde153c478..2214bcf4c59c 100644 --- a/README.md +++ b/README.md @@ -393,6 +393,9 @@ Some native rustc `-Z` flags are also very relevant for Miri: Moreover, Miri recognizes some environment variables: +* `MIRI_AUTO_OPS` indicates whether the automatic execution of rustfmt, clippy and rustup-toolchain + should be skipped. If it is set to any value, they are skipped. This is used for avoiding + infinite recursion in `./miri` and to allow automated IDE actions to avoid the auto ops. * `MIRI_LOG`, `MIRI_BACKTRACE` control logging and backtrace printing during Miri executions, also [see "Testing the Miri driver" in `CONTRIBUTING.md`][testing-miri]. * `MIRIFLAGS` (recognized by `cargo miri` and the test suite) defines extra From 309413717fbeb6a9eb56ebe63726c6fe305117b8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 12:04:17 -0400 Subject: [PATCH 3583/5092] cargo-miri debugging improvements --- cargo-miri/bin.rs | 103 +++++++++++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 46 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 48beb7c935d6..113b0c04a3ae 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -572,7 +572,51 @@ fn local_crates(metadata: &Metadata) -> String { local_crates } -fn phase_cargo_miri(mut args: env::Args) { +fn env_vars_from_cmd(cmd: &Command) -> Vec<(String, String)> { + let mut envs = HashMap::new(); + for (key, value) in std::env::vars() { + envs.insert(key, value); + } + for (key, value) in cmd.get_envs() { + if let Some(value) = value { + envs.insert(key.to_string_lossy().to_string(), value.to_string_lossy().to_string()); + } else { + envs.remove(&key.to_string_lossy().to_string()); + } + } + let mut envs: Vec<_> = envs.into_iter().collect(); + envs.sort(); + envs +} + +/// Debug-print a command that is going to be run. +fn debug_cmd(prefix: &str, verbose: usize, cmd: &Command) { + if verbose == 0 { + return; + } + // We only do a single `eprintln!` call to minimize concurrency interactions. + let mut out = prefix.to_string(); + writeln!(out, " running command: env \\").unwrap(); + if verbose > 1 { + // Print the full environment this will be called in. + for (key, value) in env_vars_from_cmd(cmd) { + writeln!(out, "{key}={value:?} \\").unwrap(); + } + } else { + // Print only what has been changed for this `cmd`. + for (var, val) in cmd.get_envs() { + if let Some(val) = val { + writeln!(out, "{}={:?} \\", var.to_string_lossy(), val).unwrap(); + } else { + writeln!(out, "--unset={}", var.to_string_lossy()).unwrap(); + } + } + } + write!(out, "{cmd:?}").unwrap(); + eprintln!("{}", out); +} + +fn phase_cargo_miri(mut args: impl Iterator) { // Check for version and help flags even when invoked as `cargo-miri`. if has_arg_flag("--help") || has_arg_flag("-h") { show_help(); @@ -694,18 +738,12 @@ fn phase_cargo_miri(mut args: env::Args) { cmd.env("RUSTDOC", &cargo_miri_path); cmd.env("MIRI_LOCAL_CRATES", local_crates(&metadata)); - - // Run cargo. if verbose > 0 { - eprintln!("[cargo-miri miri] RUSTC_WRAPPER={:?}", cargo_miri_path); - eprintln!("[cargo-miri miri] {}={:?}", target_runner_env_name, cargo_miri_path); - if *target != host { - eprintln!("[cargo-miri miri] {}={:?}", host_runner_env_name, cargo_miri_path); - } - eprintln!("[cargo-miri miri] RUSTDOC={:?}", cargo_miri_path); - eprintln!("[cargo-miri miri] {:?}", cmd); cmd.env("MIRI_VERBOSE", verbose.to_string()); // This makes the other phases verbose. } + + // Run cargo. + debug_cmd("[cargo-miri miri]", verbose, &cmd); exec(cmd) } @@ -913,14 +951,8 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { eprintln!( "[cargo-miri rustc] target_crate={target_crate} runnable_crate={runnable_crate} print={print}" ); - eprintln!("[cargo-miri rustc] going to run:"); - if verbose > 1 { - for (key, value) in env_vars_from_cmd(&cmd) { - eprintln!("{key}={value:?} \\"); - } - } - eprintln!("{:?}", cmd); } + debug_cmd("[cargo-miri rustc]", verbose, &cmd); exec(cmd); // Create a stub .rlib file if "link" was requested by cargo. @@ -938,23 +970,6 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { } } -fn env_vars_from_cmd(cmd: &Command) -> Vec<(String, String)> { - let mut envs = HashMap::new(); - for (key, value) in std::env::vars() { - envs.insert(key, value); - } - for (key, value) in cmd.get_envs() { - if let Some(value) = value { - envs.insert(key.to_str().unwrap().into(), value.to_str().unwrap().to_owned()); - } else { - envs.remove(key.to_str().unwrap()); - } - } - let mut envs: Vec<_> = envs.into_iter().collect(); - envs.sort(); - envs -} - #[derive(Debug, Copy, Clone, PartialEq)] enum RunnerPhase { /// `cargo` is running a binary @@ -963,8 +978,9 @@ enum RunnerPhase { Rustdoc, } -fn phase_runner(binary: &Path, binary_args: env::Args, phase: RunnerPhase) { - let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); +fn phase_runner(binary: &Path, binary_args: impl Iterator, phase: RunnerPhase) { + let verbose = std::env::var("MIRI_VERBOSE") + .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); let file = File::open(&binary) .unwrap_or_else(|_| show_error(format!("file {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary))); @@ -991,7 +1007,7 @@ fn phase_runner(binary: &Path, binary_args: env::Args, phase: RunnerPhase) { // Set missing env vars. We prefer build-time env vars over run-time ones; see // for the kind of issue that fixes. for (name, val) in info.env { - if verbose { + if verbose > 0 { if let Some(old_val) = env::var_os(&name) { if old_val != val { eprintln!( @@ -1048,10 +1064,7 @@ fn phase_runner(binary: &Path, binary_args: env::Args, phase: RunnerPhase) { cmd.env("MIRI_CWD", env::current_dir().unwrap()); // Run it. - if verbose { - eprintln!("[cargo-miri runner] {:?}", cmd); - } - + debug_cmd("[cargo-miri runner]", verbose, &cmd); match phase { RunnerPhase::Rustdoc => exec_with_pipe(cmd, &info.stdin), RunnerPhase::Cargo => exec(cmd), @@ -1059,7 +1072,8 @@ fn phase_runner(binary: &Path, binary_args: env::Args, phase: RunnerPhase) { } fn phase_rustdoc(fst_arg: &str, mut args: env::Args) { - let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); + let verbose = std::env::var("MIRI_VERBOSE") + .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); // phase_cargo_miri sets the RUSTDOC env var to ourselves, so we can't use that here; // just default to a straight-forward invocation for now: @@ -1126,10 +1140,7 @@ fn phase_rustdoc(fst_arg: &str, mut args: env::Args) { cmd.arg("--test-builder").arg(&cargo_miri_path); // invoked by forwarding most arguments cmd.arg("--runtool").arg(&cargo_miri_path); // invoked with just a single path argument - if verbose { - eprintln!("[cargo-miri rustdoc] {:?}", cmd); - } - + debug_cmd("[cargo-miri rustdoc]", verbose, &cmd); exec(cmd) } From d43e12e412bda35b519dc5038d3344dd2d2d2b22 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 12:43:30 -0400 Subject: [PATCH 3584/5092] say what we are doing --- ui_test/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 06a84cfbf32e..7fd053eace18 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -76,6 +76,7 @@ pub fn run_tests(mut config: Config) -> Result<()> { // Get the triple with which to run the tests let target = config.target.clone().unwrap_or_else(|| config.get_host()); + eprintln!(" Building test dependencies..."); let dependencies = build_dependencies(&config)?; for (name, dependency) in dependencies.dependencies { config.args.push("--extern".into()); From 4030210aa1e817f7abc8638d5a8d0643a6216d1f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 13:44:16 -0400 Subject: [PATCH 3585/5092] we don't need unstable options --- ui_test/src/dependencies.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ui_test/src/dependencies.rs b/ui_test/src/dependencies.rs index ab3a0156595f..1d6bf7af32ef 100644 --- a/ui_test/src/dependencies.rs +++ b/ui_test/src/dependencies.rs @@ -45,8 +45,7 @@ pub fn build_dependencies(config: &Config) -> Result { setup_command(&mut build); build .arg("--target-dir=target/test_dependencies") - .arg("--message-format=json") - .arg("-Zunstable-options"); + .arg("--message-format=json"); let output = build.output()?; From e286dfa7d3e4f8cf298f3002d15630a15df963d0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 14:03:58 -0400 Subject: [PATCH 3586/5092] don't force target-dir (cargo-miri already deconflicts that) --- ui_test/src/dependencies.rs | 4 +--- ui_test/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/ui_test/src/dependencies.rs b/ui_test/src/dependencies.rs index 1d6bf7af32ef..8ec7090b96a6 100644 --- a/ui_test/src/dependencies.rs +++ b/ui_test/src/dependencies.rs @@ -43,9 +43,7 @@ pub fn build_dependencies(config: &Config) -> Result { }; setup_command(&mut build); - build - .arg("--target-dir=target/test_dependencies") - .arg("--message-format=json"); + build.arg("--message-format=json"); let output = build.output()?; diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 7fd053eace18..bcc48b4b6316 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -54,7 +54,7 @@ pub struct Config { pub struct DependencyBuilder { pub program: PathBuf, pub args: Vec, - pub envs: Vec<(String, String)>, + pub envs: Vec<(String, OsString)>, } #[derive(Debug)] From e3018b8a97f4fb8b67ccd449f4eebb7dd2e204dd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 15:34:32 -0400 Subject: [PATCH 3587/5092] normalize stronger --- tests/compiletest.rs | 2 +- tests/fail/crates/tokio_mvp.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 72aa140d66a2..0f0179de5d24 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -133,7 +133,7 @@ regexes! { // erase platform file paths "sys/[a-z]+/" => "sys/PLATFORM/", // erase paths into the crate registry - r"[^ ]*/\.cargo/registry/.*/(.*\.rs)" => "CARGO_REGISTRY/$1", + r"[^ ]*/\.?cargo/registry/.*/(.*\.rs)" => "CARGO_REGISTRY/.../$1", } fn ui(mode: Mode, path: &str) -> Result<()> { diff --git a/tests/fail/crates/tokio_mvp.stderr b/tests/fail/crates/tokio_mvp.stderr index cff948f36408..8df83662aa02 100644 --- a/tests/fail/crates/tokio_mvp.stderr +++ b/tests/fail/crates/tokio_mvp.stderr @@ -1,5 +1,5 @@ error: unsupported operation: can't call foreign function: epoll_create1 - --> CARGO_REGISTRY/epoll.rs:LL:CC + --> CARGO_REGISTRY/.../epoll.rs:LL:CC | LL | syscall!(epoll_create1(flag)).map(|ep| Selector { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't call foreign function: epoll_create1 From 7c99f90271932500deb6a2147561e7c00dcce716 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 16:58:16 -0400 Subject: [PATCH 3588/5092] cargo-miri: clean up phase dispatching a bit --- cargo-miri/bin.rs | 95 +++++++++++++++++++---------------------------- 1 file changed, 38 insertions(+), 57 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 113b0c04a3ae..c02847dfdd97 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -60,7 +60,7 @@ struct CrateRunEnv { impl CrateRunEnv { /// Gather all the information we need. - fn collect(args: env::Args, capture_stdin: bool) -> Self { + fn collect(args: impl Iterator, capture_stdin: bool) -> Self { let args = args.collect(); let env = env::vars_os().collect(); let current_dir = env::current_dir().unwrap().into_os_string(); @@ -757,7 +757,7 @@ enum RustcPhase { Rustdoc, } -fn phase_rustc(mut args: env::Args, phase: RustcPhase) { +fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { /// Determines if we are being invoked (as rustc) to build a crate for /// the "target" architecture, in contrast to the "host" architecture. /// Host crates are for build scripts and proc macros and still need to @@ -978,10 +978,11 @@ enum RunnerPhase { Rustdoc, } -fn phase_runner(binary: &Path, binary_args: impl Iterator, phase: RunnerPhase) { +fn phase_runner(mut binary_args: impl Iterator, phase: RunnerPhase) { let verbose = std::env::var("MIRI_VERBOSE") .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); + let binary = binary_args.next().unwrap(); let file = File::open(&binary) .unwrap_or_else(|_| show_error(format!("file {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary))); let file = BufReader::new(file); @@ -1071,7 +1072,7 @@ fn phase_runner(binary: &Path, binary_args: impl Iterator, phase: } } -fn phase_rustdoc(fst_arg: &str, mut args: env::Args) { +fn phase_rustdoc(mut args: impl Iterator) { let verbose = std::env::var("MIRI_VERBOSE") .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); @@ -1079,17 +1080,8 @@ fn phase_rustdoc(fst_arg: &str, mut args: env::Args) { // just default to a straight-forward invocation for now: let mut cmd = Command::new("rustdoc"); - // Because of the way the main function is structured, we have to take the first argument spearately - // from the rest; to simplify the following argument patching loop, we'll just skip that one. - // This is fine for now, because cargo will never pass --extern arguments in the first position, - // but we should defensively assert that this will work. let extern_flag = "--extern"; - assert!(fst_arg != extern_flag); - cmd.arg(fst_arg); - let runtool_flag = "--runtool"; - // `crossmode` records if *any* argument matches `runtool_flag`; here we check the first one. - let mut crossmode = fst_arg == runtool_flag; while let Some(arg) = args.next() { if arg == extern_flag { // Patch --extern arguments to use *.rmeta files, since phase_cargo_rustc only creates stub *.rlib files. @@ -1098,17 +1090,12 @@ fn phase_rustdoc(fst_arg: &str, mut args: env::Args) { // An existing --runtool flag indicates cargo is running in cross-target mode, which we don't support. // Note that this is only passed when cargo is run with the unstable -Zdoctest-xcompile flag; // otherwise, we won't be called as rustdoc at all. - crossmode = true; - break; + show_error(format!("cross-interpreting doctests is not currently supported by Miri.")); } else { cmd.arg(arg); } } - if crossmode { - show_error(format!("cross-interpreting doctests is not currently supported by Miri.")); - } - // Doctests of `proc-macro` crates (and their dependencies) are always built for the host, // so we are not able to run them in Miri. if ArgFlagValueIter::new("--crate-type").any(|crate_type| crate_type == "proc-macro") { @@ -1178,16 +1165,7 @@ fn main() { // since we don't specify any runtool-args, and rustdoc supplies multiple arguments to // the test-builder unconditionally, we can just check the number of remaining arguments: if args.len() == 1 { - let arg = args.next().unwrap(); - let binary = Path::new(&arg); - if binary.exists() { - phase_runner(binary, args, RunnerPhase::Rustdoc); - } else { - show_error(format!( - "`cargo-miri` called with non-existing path argument `{}` in rustdoc mode; please invoke this binary through `cargo miri`", - arg - )); - } + phase_runner(args, RunnerPhase::Rustdoc); } else { phase_rustc(args, RustcPhase::Rustdoc); } @@ -1195,35 +1173,38 @@ fn main() { return; } - match args.next().as_deref() { - Some("miri") => phase_cargo_miri(args), - Some(arg) => { - // If the first arg is equal to the RUSTC variable (which should be set at this point), - // then we need to behave as rustc. This is the somewhat counter-intuitive behavior of - // having both RUSTC and RUSTC_WRAPPER set (see - // https://github.com/rust-lang/cargo/issues/10886). - if arg == env::var_os("RUSTC").unwrap() { - return phase_rustc(args, RustcPhase::Build); - } - // We have to distinguish the "runner" and "rustdoc" cases. - // As runner, the first argument is the binary (a file that should exist, with an absolute path); - // as rustdoc, the first argument is a flag (`--something`). - let binary = Path::new(arg); - if binary.exists() { - assert!(!arg.starts_with("--")); // not a flag - phase_runner(binary, args, RunnerPhase::Cargo); - } else if arg.starts_with("--") { - phase_rustdoc(arg, args); - } else { - show_error(format!( - "`cargo-miri` called with unexpected first argument `{}`; please only invoke this binary through `cargo miri`", - arg - )); - } + let mut args = args.peekable(); + if args.next_if(|a| a == "miri").is_some() { + phase_cargo_miri(args); + } else if let Some(arg) = args.peek().cloned() { + // Cargo calls us for everything it does. We could be invoked as rustc, rustdoc, or the runner. + + // If the first arg is equal to the RUSTC variable (which should be set at this point), + // then we need to behave as rustc. This is the somewhat counter-intuitive behavior of + // having both RUSTC and RUSTC_WRAPPER set (see + // https://github.com/rust-lang/cargo/issues/10886). + if arg == env::var("RUSTC").unwrap() { + args.next().unwrap(); // consume wrapped RUSTC command. + return phase_rustc(args, RustcPhase::Build); } - _ => + // We have to distinguish the "runner" and "rustdoc" cases. + // As runner, the first argument is the binary (a file that should exist, with an absolute path); + // as rustdoc, the first argument is a flag (`--something`). + let binary = Path::new(&arg); + if binary.exists() { + assert!(!arg.starts_with("--")); // not a flag + phase_runner(args, RunnerPhase::Cargo); + } else if arg.starts_with("--") { + phase_rustdoc(args); + } else { show_error(format!( - "`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`" - )), + "`cargo-miri` called with unexpected first argument `{}`; please only invoke this binary through `cargo miri`", + arg + )); + } + } else { + show_error(format!( + "`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`" + )); } } From fb428dfee3252f378f796c7497a8fb29753c795d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 17:04:04 -0400 Subject: [PATCH 3589/5092] avoid redundant setting of env vars in phase_runner --- cargo-miri/bin.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index c02847dfdd97..8b60d90520ab 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -1008,14 +1008,16 @@ fn phase_runner(mut binary_args: impl Iterator, phase: RunnerPhas // Set missing env vars. We prefer build-time env vars over run-time ones; see // for the kind of issue that fixes. for (name, val) in info.env { - if verbose > 0 { - if let Some(old_val) = env::var_os(&name) { - if old_val != val { - eprintln!( - "[cargo-miri runner] Overwriting run-time env var {:?}={:?} with build-time value {:?}", - name, old_val, val - ); - } + if let Some(old_val) = env::var_os(&name) { + if old_val == val { + // This one did not actually change, no need to re-set it. + // (This keeps the `debug_cmd` below more manageable.) + continue; + } else if verbose > 0 { + eprintln!( + "[cargo-miri runner] Overwriting run-time env var {:?}={:?} with build-time value {:?}", + name, old_val, val + ); } } cmd.env(name, val); From 4fdf43f23fbd4fb69960c9136dc796d8e64be785 Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Thu, 21 Jul 2022 13:06:08 -0400 Subject: [PATCH 3590/5092] `special_module_name`: ignore inline modules --- compiler/rustc_lint/src/builtin.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 961e1e9507b9..e9841b7f0713 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -3299,7 +3299,11 @@ declare_lint_pass!(SpecialModuleName => [SPECIAL_MODULE_NAME]); impl EarlyLintPass for SpecialModuleName { fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &ast::Crate) { for item in &krate.items { - if let ast::ItemKind::Mod(..) = item.kind { + if let ast::ItemKind::Mod( + _, + ast::ModKind::Unloaded | ast::ModKind::Loaded(_, ast::Inline::No, _), + ) = item.kind + { if item.attrs.iter().any(|a| a.has_name(sym::path)) { continue; } From e2866c0a673ebe073ebfdd4b48b5f09508d143f6 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Fri, 22 Jul 2022 01:48:30 +0000 Subject: [PATCH 3591/5092] Add simd_cast_ptr, simd_expose_addr, and simd_from_exposed_addr intrinsics --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 79 ++++++++++++++++++++ compiler/rustc_span/src/symbol.rs | 3 + compiler/rustc_typeck/src/check/intrinsic.rs | 6 +- src/test/ui/simd/intrinsic/ptr-cast.rs | 33 ++++++++ 4 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/simd/intrinsic/ptr-cast.rs diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index a18f5b9dd7f9..78afbdfc521f 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1704,6 +1704,85 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, bitwise_red!(simd_reduce_all: vector_reduce_and, true); bitwise_red!(simd_reduce_any: vector_reduce_or, true); + if name == sym::simd_cast_ptr { + require_simd!(ret_ty, "return"); + let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx()); + require!( + in_len == out_len, + "expected return type with length {} (same as input type `{}`), \ + found `{}` with length {}", + in_len, + in_ty, + ret_ty, + out_len + ); + + match in_elem.kind() { + ty::RawPtr(_) => {} + _ => return_error!("expected pointer, got `{}`", in_elem), + } + match out_elem.kind() { + ty::RawPtr(_) => {} + _ => return_error!("expected pointer, got `{}`", out_elem), + } + + if in_elem == out_elem { + return Ok(args[0].immediate()); + } else { + return Ok(bx.pointercast(args[0].immediate(), llret_ty)); + } + } + + if name == sym::simd_expose_addr { + require_simd!(ret_ty, "return"); + let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx()); + require!( + in_len == out_len, + "expected return type with length {} (same as input type `{}`), \ + found `{}` with length {}", + in_len, + in_ty, + ret_ty, + out_len + ); + + match in_elem.kind() { + ty::RawPtr(_) => {} + _ => return_error!("expected pointer, got `{}`", in_elem), + } + match out_elem.kind() { + ty::Uint(ty::UintTy::Usize) => {} + _ => return_error!("expected `usize`, got `{}`", out_elem), + } + + return Ok(bx.ptrtoint(args[0].immediate(), llret_ty)); + } + + if name == sym::simd_from_exposed_addr { + require_simd!(ret_ty, "return"); + let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx()); + require!( + in_len == out_len, + "expected return type with length {} (same as input type `{}`), \ + found `{}` with length {}", + in_len, + in_ty, + ret_ty, + out_len + ); + + match in_elem.kind() { + ty::Uint(ty::UintTy::Usize) => {} + _ => return_error!("expected `usize`, got `{}`", in_elem), + } + match out_elem.kind() { + ty::RawPtr(_) => {} + _ => return_error!("expected pointer, got `{}`", out_elem), + } + + return Ok(bx.inttoptr(args[0].immediate(), llret_ty)); + } + if name == sym::simd_cast || name == sym::simd_as { require_simd!(ret_ty, "return"); let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx()); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8a6941a45162..73e0e784ea24 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1275,9 +1275,11 @@ symbols! { simd_as, simd_bitmask, simd_cast, + simd_cast_ptr, simd_ceil, simd_div, simd_eq, + simd_expose_addr, simd_extract, simd_fabs, simd_fcos, @@ -1293,6 +1295,7 @@ symbols! { simd_fmin, simd_fpow, simd_fpowi, + simd_from_exposed_addr, simd_fsin, simd_fsqrt, simd_gather, diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs index 7fe710cf8f4f..d92fd475f90e 100644 --- a/compiler/rustc_typeck/src/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -461,7 +461,11 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) sym::simd_scatter => (3, vec![param(0), param(1), param(2)], tcx.mk_unit()), sym::simd_insert => (2, vec![param(0), tcx.types.u32, param(1)], param(0)), sym::simd_extract => (2, vec![param(0), tcx.types.u32], param(1)), - sym::simd_cast | sym::simd_as => (2, vec![param(0)], param(1)), + sym::simd_cast + | sym::simd_as + | sym::simd_cast_ptr + | sym::simd_expose_addr + | sym::simd_from_exposed_addr => (2, vec![param(0)], param(1)), sym::simd_bitmask => (2, vec![param(0)], param(1)), sym::simd_select | sym::simd_select_bitmask => { (2, vec![param(0), param(1), param(1)], param(1)) diff --git a/src/test/ui/simd/intrinsic/ptr-cast.rs b/src/test/ui/simd/intrinsic/ptr-cast.rs new file mode 100644 index 000000000000..1d13720bcd31 --- /dev/null +++ b/src/test/ui/simd/intrinsic/ptr-cast.rs @@ -0,0 +1,33 @@ +// run-pass + +#![feature(repr_simd, platform_intrinsics)] + +extern "platform-intrinsic" { + fn simd_cast_ptr(x: T) -> U; + fn simd_expose_addr(x: T) -> U; + fn simd_from_exposed_addr(x: T) -> U; +} + +#[derive(Copy, Clone)] +#[repr(simd)] +struct V([T; 2]); + +fn main() { + unsafe { + let mut foo = 4i8; + let ptr = &mut foo as *mut i8; + + let ptrs = V::<*mut i8>([ptr, core::ptr::null_mut()]); + + // change constness and type + let const_ptrs: V<*const u8> = simd_cast_ptr(ptrs); + + let exposed_addr: V = simd_expose_addr(const_ptrs); + + let from_exposed_addr: V<*mut i8> = simd_from_exposed_addr(exposed_addr); + + assert!(const_ptrs.0 == [ptr as *const u8, core::ptr::null()]); + assert!(exposed_addr.0 == [ptr as usize, 0]); + assert!(from_exposed_addr.0 == ptrs.0); + } +} From a6b35412d817dfcb6d4333fb290460044eff742d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Jul 2022 10:38:26 -0400 Subject: [PATCH 3592/5092] adjust for symbolic vtables --- src/intptrcast.rs | 8 +++--- src/machine.rs | 2 +- src/shims/backtrace.rs | 16 ++++++------ src/stacked_borrows/mod.rs | 4 +-- tests/fail/issue-miri-1112.rs | 2 +- tests/fail/issue-miri-1112.stderr | 4 +-- tests/fail/stacked_borrows/vtable.stderr | 25 ------------------- tests/fail/validity/invalid_wide_raw.rs | 2 +- tests/fail/validity/invalid_wide_raw.stderr | 4 +-- .../issues/issue-miri-2123.rs} | 10 +++++--- tests/pass/pointers.rs | 19 +++++++++++++- 11 files changed, 47 insertions(+), 49 deletions(-) delete mode 100644 tests/fail/stacked_borrows/vtable.stderr rename tests/{fail/stacked_borrows/vtable.rs => pass/issues/issue-miri-2123.rs} (54%) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 442c201e8ece..aa7111cb81fc 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -86,7 +86,9 @@ impl<'mir, 'tcx> GlobalStateInner { if global_state.exposed.contains(&alloc_id) { let (_size, _align, kind) = ecx.get_alloc_info(alloc_id); match kind { - AllocKind::LiveData | AllocKind::Function => return Some(alloc_id), + AllocKind::LiveData | AllocKind::Function | AllocKind::VTable => { + return Some(alloc_id); + } AllocKind::Dead => {} } } @@ -187,8 +189,8 @@ impl<'mir, 'tcx> GlobalStateInner { // Remember next base address. If this allocation is zero-sized, leave a gap // of at least 1 to avoid two allocations having the same base address. - // (The logic in `alloc_id_from_addr` assumes unique addresses, and function - // pointers to different functions need to be distinguishable!) + // (The logic in `alloc_id_from_addr` assumes unique addresses, and different + // function/vtable pointers need to be distinguishable!) global_state.next_base_addr = base_addr.checked_add(max(size.bytes(), 1)).unwrap(); // Given that `next_base_addr` increases in each allocation, pushing the // corresponding tuple keeps `int_to_ptr_map` sorted diff --git a/src/machine.rs b/src/machine.rs index 67a6c997e990..40f4c9ed90c0 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -733,7 +733,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { if cfg!(debug_assertions) { // The machine promises to never call us on thread-local or extern statics. let alloc_id = ptr.provenance; - match ecx.tcx.get_global_alloc(alloc_id) { + match ecx.tcx.try_get_global_alloc(alloc_id) { Some(GlobalAlloc::Static(def_id)) if ecx.tcx.is_thread_local_static(def_id) => { panic!("adjust_alloc_base_pointer called on thread-local static") } diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index c5aab255aaf8..54ab8665ce35 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -122,15 +122,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let ptr = this.read_pointer(ptr)?; - // Take apart the pointer, we need its pieces. + // Take apart the pointer, we need its pieces. The offset encodes the span. let (alloc_id, offset, _prov) = this.ptr_get_alloc_id(ptr)?; - let fn_instance = - if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(alloc_id) { - instance - } else { - throw_ub_format!("expected function pointer, found {:?}", ptr); - }; + // This has to be an actual global fn ptr, not a dlsym function. + let fn_instance = if let Some(GlobalAlloc::Function(instance)) = + this.tcx.try_get_global_alloc(alloc_id) + { + instance + } else { + throw_ub_format!("expected static function pointer, found {:?}", ptr); + }; let lo = this.tcx.sess.source_map().lookup_char_pos(BytePos(offset.bytes().try_into().unwrap())); diff --git a/src/stacked_borrows/mod.rs b/src/stacked_borrows/mod.rs index 38a73929a036..624b32dfd495 100644 --- a/src/stacked_borrows/mod.rs +++ b/src/stacked_borrows/mod.rs @@ -799,7 +799,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx stacked_borrows.history.log_protector(orig_tag, new_tag, current_span); } } - AllocKind::Function | AllocKind::Dead => { + AllocKind::Function | AllocKind::VTable | AllocKind::Dead => { // No stacked borrows on these allocations. } } @@ -1143,7 +1143,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("Stacked Borrows tag {tag:?} exposed in {alloc_id:?}"); alloc_extra.stacked_borrows.as_ref().unwrap().borrow_mut().exposed_tags.insert(tag); } - AllocKind::Function | AllocKind::Dead => { + AllocKind::Function | AllocKind::VTable | AllocKind::Dead => { // No stacked borrows on these allocations. } } diff --git a/tests/fail/issue-miri-1112.rs b/tests/fail/issue-miri-1112.rs index abf627bb2a76..387253a3f987 100644 --- a/tests/fail/issue-miri-1112.rs +++ b/tests/fail/issue-miri-1112.rs @@ -28,7 +28,7 @@ impl FunnyPointer { data: data as *const _ as *const (), vtable: ptr as *const _ as *const (), }; - let obj = std::mem::transmute::(obj); //~ ERROR: invalid drop function pointer in vtable + let obj = std::mem::transmute::(obj); //~ ERROR: expected a vtable pointer &*obj } } diff --git a/tests/fail/issue-miri-1112.stderr b/tests/fail/issue-miri-1112.stderr index 89dc8dc327f8..4a2bdb0f414d 100644 --- a/tests/fail/issue-miri-1112.stderr +++ b/tests/fail/issue-miri-1112.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: constructing invalid value: encountered invalid drop function pointer in vtable (function has incompatible signature) +error: Undefined Behavior: constructing invalid value: encountered $HEX[ALLOC], but expected a vtable pointer --> $DIR/issue-miri-1112.rs:LL:CC | LL | let obj = std::mem::transmute::(obj); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid drop function pointer in vtable (function has incompatible signature) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered $HEX[ALLOC], but expected a vtable pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/stacked_borrows/vtable.stderr b/tests/fail/stacked_borrows/vtable.stderr deleted file mode 100644 index 534f811e48ab..000000000000 --- a/tests/fail/stacked_borrows/vtable.stderr +++ /dev/null @@ -1,25 +0,0 @@ -error: Undefined Behavior: constructing invalid value: encountered vtable pointer does not have permission to read drop function pointer - --> RUSTLIB/core/src/ptr/metadata.rs:LL:CC - | -LL | unsafe { PtrRepr { components: PtrComponents { data_address, metadata } }.const_ptr } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered vtable pointer does not have permission to read drop function pointer - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: - = note: inside `std::ptr::from_raw_parts::` at RUSTLIB/core/src/ptr/metadata.rs:LL:CC -note: inside `uwu` at $DIR/vtable.rs:LL:CC - --> $DIR/vtable.rs:LL:CC - | -LL | core::ptr::from_raw_parts(thin, unsafe { core::mem::transmute(meta) }) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: inside `main` at $DIR/vtable.rs:LL:CC - --> $DIR/vtable.rs:LL:CC - | -LL | let _ = uwu(ptr, core::mem::transmute(meta)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/validity/invalid_wide_raw.rs b/tests/fail/validity/invalid_wide_raw.rs index 0a2f6f5b152c..2ad972a9d4d7 100644 --- a/tests/fail/validity/invalid_wide_raw.rs +++ b/tests/fail/validity/invalid_wide_raw.rs @@ -7,5 +7,5 @@ fn main() { #[allow(dead_code)] x: *mut dyn T, } - dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); //~ ERROR: encountered dangling vtable pointer in wide pointer + dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); //~ ERROR: encountered null pointer, but expected a vtable pointer } diff --git a/tests/fail/validity/invalid_wide_raw.stderr b/tests/fail/validity/invalid_wide_raw.stderr index 624b9764c9e1..304008f65163 100644 --- a/tests/fail/validity/invalid_wide_raw.stderr +++ b/tests/fail/validity/invalid_wide_raw.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: constructing invalid value: encountered dangling vtable pointer in wide pointer +error: Undefined Behavior: constructing invalid value: encountered null pointer, but expected a vtable pointer --> $DIR/invalid_wide_raw.rs:LL:CC | LL | dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered dangling vtable pointer in wide pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/stacked_borrows/vtable.rs b/tests/pass/issues/issue-miri-2123.rs similarity index 54% rename from tests/fail/stacked_borrows/vtable.rs rename to tests/pass/issues/issue-miri-2123.rs index 27e035c404ba..9740d2c9ee8e 100644 --- a/tests/fail/stacked_borrows/vtable.rs +++ b/tests/pass/issues/issue-miri-2123.rs @@ -1,12 +1,13 @@ -//@error-pattern: vtable pointer does not have permission -#![feature(ptr_metadata)] +#![feature(ptr_metadata, layout_for_ptr)] + +use std::{mem, ptr}; trait Foo {} impl Foo for u32 {} fn uwu(thin: *const (), meta: &'static ()) -> *const dyn Foo { - core::ptr::from_raw_parts(thin, unsafe { core::mem::transmute(meta) }) + ptr::from_raw_parts(thin, unsafe { mem::transmute(meta) }) } fn main() { @@ -14,6 +15,7 @@ fn main() { let orig = 1_u32; let x = &orig as &dyn Foo; let (ptr, meta) = (x as *const dyn Foo).to_raw_parts(); - let _ = uwu(ptr, core::mem::transmute(meta)); + let ptr = uwu(ptr, mem::transmute(meta)); + mem::size_of_val_raw(ptr); } } diff --git a/tests/pass/pointers.rs b/tests/pass/pointers.rs index a0c20af42697..a271e764d9f4 100644 --- a/tests/pass/pointers.rs +++ b/tests/pass/pointers.rs @@ -1,4 +1,7 @@ -use std::mem::transmute; +#![feature(ptr_metadata)] + +use std::mem::{self, transmute}; +use std::ptr; fn one_line_ref() -> i16 { *&1 @@ -71,6 +74,19 @@ fn wide_ptr_ops() { assert!(!(a > b)); } +fn metadata_vtable() { + let p = &0i32 as &dyn std::fmt::Debug; + let meta: ptr::DynMetadata<_> = ptr::metadata(p as *const _); + assert_eq!(meta.size_of(), mem::size_of::()); + assert_eq!(meta.align_of(), mem::align_of::()); + + type T = [i32; 16]; + let p = &T::default() as &dyn std::fmt::Debug; + let meta: ptr::DynMetadata<_> = ptr::metadata(p as *const _); + assert_eq!(meta.size_of(), mem::size_of::()); + assert_eq!(meta.align_of(), mem::align_of::()); +} + fn main() { assert_eq!(one_line_ref(), 1); assert_eq!(basic_ref(), 1); @@ -116,4 +132,5 @@ fn main() { assert!(dangling >= 4); wide_ptr_ops(); + metadata_vtable(); } From bd441b1eb93475107717ffca59202c11263b5e5e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Jul 2022 19:51:19 -0400 Subject: [PATCH 3593/5092] test for some bad use of vtables --- tests/fail/dyn-call-trait-mismatch.rs | 16 ++++++ tests/fail/dyn-call-trait-mismatch.stderr | 15 ++++++ tests/fail/dyn-upcast-trait-mismatch.rs | 58 +++++++++++++++++++++ tests/fail/dyn-upcast-trait-mismatch.stderr | 15 ++++++ 4 files changed, 104 insertions(+) create mode 100644 tests/fail/dyn-call-trait-mismatch.rs create mode 100644 tests/fail/dyn-call-trait-mismatch.stderr create mode 100644 tests/fail/dyn-upcast-trait-mismatch.rs create mode 100644 tests/fail/dyn-upcast-trait-mismatch.stderr diff --git a/tests/fail/dyn-call-trait-mismatch.rs b/tests/fail/dyn-call-trait-mismatch.rs new file mode 100644 index 000000000000..0e7c3dbcc040 --- /dev/null +++ b/tests/fail/dyn-call-trait-mismatch.rs @@ -0,0 +1,16 @@ +trait T1 { + fn method1(self: Box); +} +trait T2 { + fn method2(self: Box); +} + +impl T1 for i32 { + fn method1(self: Box) {} +} + +fn main() { + let r = Box::new(0) as Box; + let r2: Box = unsafe { std::mem::transmute(r) }; + r2.method2(); //~ERROR: call on a pointer whose vtable does not match its type +} diff --git a/tests/fail/dyn-call-trait-mismatch.stderr b/tests/fail/dyn-call-trait-mismatch.stderr new file mode 100644 index 000000000000..2673a22a3df2 --- /dev/null +++ b/tests/fail/dyn-call-trait-mismatch.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `dyn` call on a pointer whose vtable does not match its type + --> $DIR/dyn-call-trait-mismatch.rs:LL:CC + | +LL | r2.method2(); + | ^^^^^^^^^^^^ `dyn` call on a pointer whose vtable does not match its type + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: backtrace: + = note: inside `main` at $DIR/dyn-call-trait-mismatch.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/dyn-upcast-trait-mismatch.rs b/tests/fail/dyn-upcast-trait-mismatch.rs new file mode 100644 index 000000000000..f53e9a03f4be --- /dev/null +++ b/tests/fail/dyn-upcast-trait-mismatch.rs @@ -0,0 +1,58 @@ +#![feature(trait_upcasting)] +#![allow(incomplete_features)] + +trait Foo: PartialEq + std::fmt::Debug + Send + Sync { + fn a(&self) -> i32 { + 10 + } + + fn z(&self) -> i32 { + 11 + } + + fn y(&self) -> i32 { + 12 + } +} + +trait Bar: Foo { + fn b(&self) -> i32 { + 20 + } + + fn w(&self) -> i32 { + 21 + } +} + +trait Baz: Bar { + fn c(&self) -> i32 { + 30 + } +} + +impl Foo for i32 { + fn a(&self) -> i32 { + 100 + } +} + +impl Bar for i32 { + fn b(&self) -> i32 { + 200 + } +} + +impl Baz for i32 { + fn c(&self) -> i32 { + 300 + } +} + +fn main() { + let baz: &dyn Baz = &1; + // We already fail on the implicit upcast inserted here. + let baz_fake: &dyn Bar = unsafe { std::mem::transmute(baz) }; + //~^ERROR: upcast on a pointer whose vtable does not match its type + let _err = baz_fake as &dyn Foo; +} diff --git a/tests/fail/dyn-upcast-trait-mismatch.stderr b/tests/fail/dyn-upcast-trait-mismatch.stderr new file mode 100644 index 000000000000..0e5e22b9b4b9 --- /dev/null +++ b/tests/fail/dyn-upcast-trait-mismatch.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: upcast on a pointer whose vtable does not match its type + --> $DIR/dyn-upcast-trait-mismatch.rs:LL:CC + | +LL | let baz_fake: &dyn Bar = unsafe { std::mem::transmute(baz) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ upcast on a pointer whose vtable does not match its type + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: backtrace: + = note: inside `main` at $DIR/dyn-upcast-trait-mismatch.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + From 16b15ec9c9fe92d71824182d766c837012b20028 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 22 Jul 2022 07:52:32 -0400 Subject: [PATCH 3594/5092] rustup --- rust-version | 2 +- tests/fail/intrinsics/simd-float-to-int.stderr | 2 +- tests/fail/intrinsics/simd-gather.stderr | 2 +- tests/fail/intrinsics/simd-scatter.stderr | 2 +- tests/pass/issues/issue-miri-2123.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index f456ded7f462..22b5b1a34a65 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a7468c60f8dbf5feb23ad840b174d7e57113a846 +e7a9c1141698bc4557b9da3d3fce2bf75339427f diff --git a/tests/fail/intrinsics/simd-float-to-int.stderr b/tests/fail/intrinsics/simd-float-to-int.stderr index 233074105b2b..ddeda599214f 100644 --- a/tests/fail/intrinsics/simd-float-to-int.stderr +++ b/tests/fail/intrinsics/simd-float-to-int.stderr @@ -7,7 +7,7 @@ LL | implement! { f32 } = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `core::core_simd::round::>::to_int_unchecked::` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/round.rs:LL:CC + = note: inside `core::core_simd::round::>::to_int_unchecked::` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/round.rs:LL:CC note: inside `main` at $DIR/simd-float-to-int.rs:LL:CC --> $DIR/simd-float-to-int.rs:LL:CC | diff --git a/tests/fail/intrinsics/simd-gather.stderr b/tests/fail/intrinsics/simd-gather.stderr index 6b935bc6e254..a23307c05ffb 100644 --- a/tests/fail/intrinsics/simd-gather.stderr +++ b/tests/fail/intrinsics/simd-gather.stderr @@ -7,7 +7,7 @@ LL | unsafe { intrinsics::simd_gather(or, ptrs, enable.to_int()) } = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::simd::Simd::::gather_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC + = note: inside `std::simd::Simd::::gather_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC note: inside `main` at $DIR/simd-gather.rs:LL:CC --> $DIR/simd-gather.rs:LL:CC | diff --git a/tests/fail/intrinsics/simd-scatter.stderr b/tests/fail/intrinsics/simd-scatter.stderr index 24fc6782f149..ba8c8f347060 100644 --- a/tests/fail/intrinsics/simd-scatter.stderr +++ b/tests/fail/intrinsics/simd-scatter.stderr @@ -7,7 +7,7 @@ LL | intrinsics::simd_scatter(self, ptrs, enable.to_int()) = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::simd::Simd::::scatter_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC + = note: inside `std::simd::Simd::::scatter_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC note: inside `main` at $DIR/simd-scatter.rs:LL:CC --> $DIR/simd-scatter.rs:LL:CC | diff --git a/tests/pass/issues/issue-miri-2123.rs b/tests/pass/issues/issue-miri-2123.rs index 9740d2c9ee8e..e39e5fe454a2 100644 --- a/tests/pass/issues/issue-miri-2123.rs +++ b/tests/pass/issues/issue-miri-2123.rs @@ -16,6 +16,6 @@ fn main() { let x = &orig as &dyn Foo; let (ptr, meta) = (x as *const dyn Foo).to_raw_parts(); let ptr = uwu(ptr, mem::transmute(meta)); - mem::size_of_val_raw(ptr); + let _size = mem::size_of_val_raw(ptr); } } From 83cbbd7bce12684f044b3c9d6c321723b0a737e7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 16:49:41 -0400 Subject: [PATCH 3595/5092] support MIRI_HOST_SYSROOT env var for stage 0 builds Together with a patch on the rustc side, this makes './x.py test src/tools/miri --stage 0' work again. :) --- README.md | 2 ++ cargo-miri/bin.rs | 10 ++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2214bcf4c59c..0741f373bb67 100644 --- a/README.md +++ b/README.md @@ -445,6 +445,8 @@ binaries, and as such worth documenting: crate currently being compiled. * `MIRI_VERBOSE` when set to any value tells the various `cargo-miri` phases to perform verbose logging. +* `MIRI_HOST_SYSROOT` is set by bootstrap to tell `cargo-miri` which sysroot to use for *host* + operations. [testing-miri]: CONTRIBUTING.md#testing-the-miri-driver diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 8b60d90520ab..bb2eb54ffebc 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -721,7 +721,9 @@ fn phase_cargo_miri(mut args: impl Iterator) { // hope that all they do is ask for the version number -- things could quickly go downhill from here. // In `main`, we need the value of `RUSTC` to distinguish RUSTC_WRAPPER invocations from rustdoc // or TARGET_RUNNER invocations, so we canonicalize it here to make it exceedingly unlikely that - // there would be a collision. + // there would be a collision with other invocations of cargo-miri (as rustdoc or as runner). + // We explicitly do this even if RUSTC_STAGE is set, since for these builds we do *not* want the + // bootstrap `rustc` thing in our way! Instead, we have MIRI_HOST_SYSROOT to use for host builds. cmd.env("RUSTC", &fs::canonicalize(find_miri()).unwrap()); let runner_env_name = @@ -929,9 +931,9 @@ fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { } else { // For host crates (but not when we are printing), we might still have to set the sysroot. if !print { - // When we're running `cargo-miri` from `x.py` we need to pass the sysroot explicitly as rustc - // can't figure out the sysroot on its own unless it's from rustup. - if let Some(sysroot) = std::env::var_os("SYSROOT") { + // When we're running `cargo-miri` from `x.py` we need to pass the sysroot explicitly + // due to bootstrap complications. + if let Some(sysroot) = std::env::var_os("MIRI_HOST_SYSROOT") { cmd.arg("--sysroot").arg(sysroot); } } From e8b3d56565e1ba5f47f5154b1147acafedad6b5a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Mar 2022 09:15:38 -0400 Subject: [PATCH 3596/5092] test bitmasks smaller than a byte --- tests/pass/portable-simd.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/pass/portable-simd.rs b/tests/pass/portable-simd.rs index 0dfe617bd8dc..ceefd180dffe 100644 --- a/tests/pass/portable-simd.rs +++ b/tests/pass/portable-simd.rs @@ -201,7 +201,7 @@ fn simd_mask() { let values = [false, false, false, true]; let mask = Mask::::from_array(values); let bitmask = mask.to_bitmask(); - // FIXME fails until https://github.com/rust-lang/portable-simd/pull/267 lands: assert_eq!(bitmask, 0b1000); + assert_eq!(bitmask, 0b1000); assert_eq!(Mask::::from_bitmask(bitmask), mask); } From 45eeaa362bfd3193b508123fac1163c8c3a1ab3b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 22 Jul 2022 08:49:03 -0400 Subject: [PATCH 3597/5092] rustup --- rust-version | 2 +- .../fail/intrinsics/simd-float-to-int.stderr | 9 ++- tests/pass/portable-simd.rs | 56 +++++++++---------- 3 files changed, 33 insertions(+), 34 deletions(-) diff --git a/rust-version b/rust-version index 22b5b1a34a65..b54ff9e100ed 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e7a9c1141698bc4557b9da3d3fce2bf75339427f +41419e70366962c9a878bfe673ef4df38db6f7f1 diff --git a/tests/fail/intrinsics/simd-float-to-int.stderr b/tests/fail/intrinsics/simd-float-to-int.stderr index ddeda599214f..d29b356d268d 100644 --- a/tests/fail/intrinsics/simd-float-to-int.stderr +++ b/tests/fail/intrinsics/simd-float-to-int.stderr @@ -1,19 +1,18 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 3.40282347E+38 which cannot be represented in target type `i32` - --> RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/round.rs:LL:CC + --> RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC | -LL | implement! { f32 } - | ^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 3.40282347E+38 which cannot be represented in target type `i32` +LL | unsafe { intrinsics::simd_cast(self) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 3.40282347E+38 which cannot be represented in target type `i32` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `core::core_simd::round::>::to_int_unchecked::` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/round.rs:LL:CC + = note: inside `std::simd::Simd::::to_int_unchecked::` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC note: inside `main` at $DIR/simd-float-to-int.rs:LL:CC --> $DIR/simd-float-to-int.rs:LL:CC | LL | let _x: i32x2 = f32x2::from_array([f32::MAX, f32::MIN]).to_int_unchecked(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `implement` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/pass/portable-simd.rs b/tests/pass/portable-simd.rs index ceefd180dffe..ec70eea6b177 100644 --- a/tests/pass/portable-simd.rs +++ b/tests/pass/portable-simd.rs @@ -13,20 +13,20 @@ fn simd_ops_f32() { assert_eq!(a / f32x4::splat(2.0), f32x4::splat(5.0)); assert_eq!(a % b, f32x4::from_array([0.0, 0.0, 1.0, 2.0])); assert_eq!(b.abs(), f32x4::from_array([1.0, 2.0, 3.0, 4.0])); - assert_eq!(a.max(b * f32x4::splat(4.0)), f32x4::from_array([10.0, 10.0, 12.0, 10.0])); - assert_eq!(a.min(b * f32x4::splat(4.0)), f32x4::from_array([4.0, 8.0, 10.0, -16.0])); + assert_eq!(a.simd_max(b * f32x4::splat(4.0)), f32x4::from_array([10.0, 10.0, 12.0, 10.0])); + assert_eq!(a.simd_min(b * f32x4::splat(4.0)), f32x4::from_array([4.0, 8.0, 10.0, -16.0])); assert_eq!(a.mul_add(b, a), (a * b) + a); assert_eq!(b.mul_add(b, a), (b * b) + a); assert_eq!((a * a).sqrt(), a); assert_eq!((b * b).sqrt(), b.abs()); - assert_eq!(a.lanes_eq(f32x4::splat(5.0) * b), Mask::from_array([false, true, false, false])); - assert_eq!(a.lanes_ne(f32x4::splat(5.0) * b), Mask::from_array([true, false, true, true])); - assert_eq!(a.lanes_le(f32x4::splat(5.0) * b), Mask::from_array([false, true, true, false])); - assert_eq!(a.lanes_lt(f32x4::splat(5.0) * b), Mask::from_array([false, false, true, false])); - assert_eq!(a.lanes_ge(f32x4::splat(5.0) * b), Mask::from_array([true, true, false, true])); - assert_eq!(a.lanes_gt(f32x4::splat(5.0) * b), Mask::from_array([true, false, false, true])); + assert_eq!(a.simd_eq(f32x4::splat(5.0) * b), Mask::from_array([false, true, false, false])); + assert_eq!(a.simd_ne(f32x4::splat(5.0) * b), Mask::from_array([true, false, true, true])); + assert_eq!(a.simd_le(f32x4::splat(5.0) * b), Mask::from_array([false, true, true, false])); + assert_eq!(a.simd_lt(f32x4::splat(5.0) * b), Mask::from_array([false, false, true, false])); + assert_eq!(a.simd_ge(f32x4::splat(5.0) * b), Mask::from_array([true, true, false, true])); + assert_eq!(a.simd_gt(f32x4::splat(5.0) * b), Mask::from_array([true, false, false, true])); assert_eq!(a.reduce_sum(), 40.0); assert_eq!(b.reduce_sum(), 2.0); @@ -38,13 +38,13 @@ fn simd_ops_f32() { assert_eq!(b.reduce_min(), -4.0); assert_eq!( - f32x2::from_array([0.0, f32::NAN]).max(f32x2::from_array([f32::NAN, 0.0])), + f32x2::from_array([0.0, f32::NAN]).simd_max(f32x2::from_array([f32::NAN, 0.0])), f32x2::from_array([0.0, 0.0]) ); assert_eq!(f32x2::from_array([0.0, f32::NAN]).reduce_max(), 0.0); assert_eq!(f32x2::from_array([f32::NAN, 0.0]).reduce_max(), 0.0); assert_eq!( - f32x2::from_array([0.0, f32::NAN]).min(f32x2::from_array([f32::NAN, 0.0])), + f32x2::from_array([0.0, f32::NAN]).simd_min(f32x2::from_array([f32::NAN, 0.0])), f32x2::from_array([0.0, 0.0]) ); assert_eq!(f32x2::from_array([0.0, f32::NAN]).reduce_min(), 0.0); @@ -62,20 +62,20 @@ fn simd_ops_f64() { assert_eq!(a / f64x4::splat(2.0), f64x4::splat(5.0)); assert_eq!(a % b, f64x4::from_array([0.0, 0.0, 1.0, 2.0])); assert_eq!(b.abs(), f64x4::from_array([1.0, 2.0, 3.0, 4.0])); - assert_eq!(a.max(b * f64x4::splat(4.0)), f64x4::from_array([10.0, 10.0, 12.0, 10.0])); - assert_eq!(a.min(b * f64x4::splat(4.0)), f64x4::from_array([4.0, 8.0, 10.0, -16.0])); + assert_eq!(a.simd_max(b * f64x4::splat(4.0)), f64x4::from_array([10.0, 10.0, 12.0, 10.0])); + assert_eq!(a.simd_min(b * f64x4::splat(4.0)), f64x4::from_array([4.0, 8.0, 10.0, -16.0])); assert_eq!(a.mul_add(b, a), (a * b) + a); assert_eq!(b.mul_add(b, a), (b * b) + a); assert_eq!((a * a).sqrt(), a); assert_eq!((b * b).sqrt(), b.abs()); - assert_eq!(a.lanes_eq(f64x4::splat(5.0) * b), Mask::from_array([false, true, false, false])); - assert_eq!(a.lanes_ne(f64x4::splat(5.0) * b), Mask::from_array([true, false, true, true])); - assert_eq!(a.lanes_le(f64x4::splat(5.0) * b), Mask::from_array([false, true, true, false])); - assert_eq!(a.lanes_lt(f64x4::splat(5.0) * b), Mask::from_array([false, false, true, false])); - assert_eq!(a.lanes_ge(f64x4::splat(5.0) * b), Mask::from_array([true, true, false, true])); - assert_eq!(a.lanes_gt(f64x4::splat(5.0) * b), Mask::from_array([true, false, false, true])); + assert_eq!(a.simd_eq(f64x4::splat(5.0) * b), Mask::from_array([false, true, false, false])); + assert_eq!(a.simd_ne(f64x4::splat(5.0) * b), Mask::from_array([true, false, true, true])); + assert_eq!(a.simd_le(f64x4::splat(5.0) * b), Mask::from_array([false, true, true, false])); + assert_eq!(a.simd_lt(f64x4::splat(5.0) * b), Mask::from_array([false, false, true, false])); + assert_eq!(a.simd_ge(f64x4::splat(5.0) * b), Mask::from_array([true, true, false, true])); + assert_eq!(a.simd_gt(f64x4::splat(5.0) * b), Mask::from_array([true, false, false, true])); assert_eq!(a.reduce_sum(), 40.0); assert_eq!(b.reduce_sum(), 2.0); @@ -87,13 +87,13 @@ fn simd_ops_f64() { assert_eq!(b.reduce_min(), -4.0); assert_eq!( - f64x2::from_array([0.0, f64::NAN]).max(f64x2::from_array([f64::NAN, 0.0])), + f64x2::from_array([0.0, f64::NAN]).simd_max(f64x2::from_array([f64::NAN, 0.0])), f64x2::from_array([0.0, 0.0]) ); assert_eq!(f64x2::from_array([0.0, f64::NAN]).reduce_max(), 0.0); assert_eq!(f64x2::from_array([f64::NAN, 0.0]).reduce_max(), 0.0); assert_eq!( - f64x2::from_array([0.0, f64::NAN]).min(f64x2::from_array([f64::NAN, 0.0])), + f64x2::from_array([0.0, f64::NAN]).simd_min(f64x2::from_array([f64::NAN, 0.0])), f64x2::from_array([0.0, 0.0]) ); assert_eq!(f64x2::from_array([0.0, f64::NAN]).reduce_min(), 0.0); @@ -113,8 +113,8 @@ fn simd_ops_i32() { assert_eq!(a % b, i32x4::from_array([0, 0, 1, 2])); assert_eq!(i32x2::splat(i32::MIN) % i32x2::splat(-1), i32x2::splat(0)); assert_eq!(b.abs(), i32x4::from_array([1, 2, 3, 4])); - assert_eq!(a.max(b * i32x4::splat(4)), i32x4::from_array([10, 10, 12, 10])); - assert_eq!(a.min(b * i32x4::splat(4)), i32x4::from_array([4, 8, 10, -16])); + assert_eq!(a.simd_max(b * i32x4::splat(4)), i32x4::from_array([10, 10, 12, 10])); + assert_eq!(a.simd_min(b * i32x4::splat(4)), i32x4::from_array([4, 8, 10, -16])); assert_eq!( i8x4::from_array([i8::MAX, -23, 23, i8::MIN]).saturating_add(i8x4::from_array([ @@ -160,12 +160,12 @@ fn simd_ops_i32() { assert_eq!(b | i32x4::splat(2), i32x4::from_array([3, 2, 3, -2])); assert_eq!(b ^ i32x4::splat(2), i32x4::from_array([3, 0, 1, -2])); - assert_eq!(a.lanes_eq(i32x4::splat(5) * b), Mask::from_array([false, true, false, false])); - assert_eq!(a.lanes_ne(i32x4::splat(5) * b), Mask::from_array([true, false, true, true])); - assert_eq!(a.lanes_le(i32x4::splat(5) * b), Mask::from_array([false, true, true, false])); - assert_eq!(a.lanes_lt(i32x4::splat(5) * b), Mask::from_array([false, false, true, false])); - assert_eq!(a.lanes_ge(i32x4::splat(5) * b), Mask::from_array([true, true, false, true])); - assert_eq!(a.lanes_gt(i32x4::splat(5) * b), Mask::from_array([true, false, false, true])); + assert_eq!(a.simd_eq(i32x4::splat(5) * b), Mask::from_array([false, true, false, false])); + assert_eq!(a.simd_ne(i32x4::splat(5) * b), Mask::from_array([true, false, true, true])); + assert_eq!(a.simd_le(i32x4::splat(5) * b), Mask::from_array([false, true, true, false])); + assert_eq!(a.simd_lt(i32x4::splat(5) * b), Mask::from_array([false, false, true, false])); + assert_eq!(a.simd_ge(i32x4::splat(5) * b), Mask::from_array([true, true, false, true])); + assert_eq!(a.simd_gt(i32x4::splat(5) * b), Mask::from_array([true, false, false, true])); assert_eq!(a.reduce_sum(), 40); assert_eq!(b.reduce_sum(), 2); From 1787c731abdb2bf395ffdd83b8cfbc6e8420065c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 22 Jul 2022 10:34:52 -0400 Subject: [PATCH 3598/5092] add more track_caller tests --- tests/pass/track-caller-attribute.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/pass/track-caller-attribute.rs b/tests/pass/track-caller-attribute.rs index dd1e2f809adf..6694764a234d 100644 --- a/tests/pass/track-caller-attribute.rs +++ b/tests/pass/track-caller-attribute.rs @@ -66,6 +66,27 @@ fn test_trait_obj() { assert_eq!(location.column(), 28); } +fn test_trait_obj2() { + // track_caller on the impl but not the trait. + pub trait Foo { + fn foo(&self) -> &'static Location<'static>; + } + + struct Bar; + impl Foo for Bar { + #[track_caller] + fn foo(&self) -> &'static Location<'static> { + std::panic::Location::caller() + } + } + let expected_line = line!() - 4; // the `fn` signature above + + let f = &Bar as &dyn Foo; + let loc = f.foo(); // trait doesn't track, so we don't point at this call site + assert_eq!(loc.file(), file!()); + assert_eq!(loc.line(), expected_line); +} + fn main() { let location = Location::caller(); let expected_line = line!() - 1; @@ -105,4 +126,5 @@ fn main() { test_fn_ptr(); test_trait_obj(); + test_trait_obj2(); } From bcf780e2ba00dbe5a81502ef541dbc0f4fb76ebb Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 22 Jul 2022 08:50:31 -0700 Subject: [PATCH 3599/5092] Recover error strings on Unix from_lossy_utf8 Some language settings can result in unreliable UTF-8 being produced. This can result in failing to emit the error string, panicking instead. from_lossy_utf8 allows us to assume these strings usually will be fine. --- library/std/src/sys/unix/os.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index 7252ad321844..3009a9b1f01c 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -125,7 +125,9 @@ pub fn error_string(errno: i32) -> String { } let p = p as *const _; - str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned() + // We can't always expect a UTF-8 environment. When we don't get that luxury, + // it's better to give a low-quality error message than none at all. + String::from_utf8_lossy(CStr::from_ptr(p).to_bytes()).into() } } From 00b382d1a5854ccefad7378968b1f6df66bf2da9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 22 Jul 2022 20:53:20 -0400 Subject: [PATCH 3600/5092] add num_cpus crate test --- test_dependencies/Cargo.lock | 1 + test_dependencies/Cargo.toml | 1 + tests/pass/crates/num_cpus.rs | 5 +++++ tests/pass/crates/random.rs | 2 +- 4 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 tests/pass/crates/num_cpus.rs diff --git a/test_dependencies/Cargo.lock b/test_dependencies/Cargo.lock index a492deba4c52..d4b32e2c29a2 100644 --- a/test_dependencies/Cargo.lock +++ b/test_dependencies/Cargo.lock @@ -107,6 +107,7 @@ dependencies = [ "getrandom 0.1.16", "getrandom 0.2.7", "libc", + "num_cpus", "page_size", "rand", "tokio", diff --git a/test_dependencies/Cargo.toml b/test_dependencies/Cargo.toml index 0bf43aefebff..58f731f91d0f 100644 --- a/test_dependencies/Cargo.toml +++ b/test_dependencies/Cargo.toml @@ -12,6 +12,7 @@ edition = "2021" tokio = { version = "1.0", features = ["full"] } libc = "0.2" page_size = "0.4.1" +num_cpus = "1.10.1" getrandom_1 = { package = "getrandom", version = "0.1" } getrandom_2 = { package = "getrandom", version = "0.2" } diff --git a/tests/pass/crates/num_cpus.rs b/tests/pass/crates/num_cpus.rs new file mode 100644 index 000000000000..84339feb11e1 --- /dev/null +++ b/tests/pass/crates/num_cpus.rs @@ -0,0 +1,5 @@ +//@compile-flags: -Zmiri-disable-isolation + +fn main() { + assert_eq!(num_cpus::get(), 1); +} diff --git a/tests/pass/crates/random.rs b/tests/pass/crates/random.rs index 808d1006d4f3..5eccf3b0ea11 100644 --- a/tests/pass/crates/random.rs +++ b/tests/pass/crates/random.rs @@ -1,6 +1,6 @@ -use rand::{rngs::SmallRng, Rng, SeedableRng}; // mac-os `getrandom_1` does some pointer shenanigans //@compile-flags: -Zmiri-permissive-provenance +use rand::{rngs::SmallRng, Rng, SeedableRng}; fn main() { // Test `getrandom` directly (in multiple different versions). From 34922be8013235f37de66cf79573ed2bd2678d85 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 22 Jul 2022 20:53:31 -0400 Subject: [PATCH 3601/5092] remove num_cpus test from test-cargo-miri --- test-cargo-miri/Cargo.lock | 27 +-------------------------- test-cargo-miri/subcrate/Cargo.toml | 2 +- test-cargo-miri/subcrate/test.rs | 6 ++++-- 3 files changed, 6 insertions(+), 29 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 3f61fb3d5408..38bfb2ac6207 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -48,15 +48,6 @@ dependencies = [ name = "exported_symbol_dep" version = "0.1.0" -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "issue_1567" version = "0.1.0" @@ -83,22 +74,6 @@ version = "0.1.0" name = "issue_rust_86261" version = "0.1.0" -[[package]] -name = "libc" -version = "0.2.126" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" - -[[package]] -name = "num_cpus" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "proc-macro2" version = "1.0.40" @@ -132,7 +107,7 @@ dependencies = [ name = "subcrate" version = "0.1.0" dependencies = [ - "num_cpus", + "byteorder 1.4.3", ] [[package]] diff --git a/test-cargo-miri/subcrate/Cargo.toml b/test-cargo-miri/subcrate/Cargo.toml index ea2936d52a05..06b1ce1cba4b 100644 --- a/test-cargo-miri/subcrate/Cargo.toml +++ b/test-cargo-miri/subcrate/Cargo.toml @@ -18,4 +18,4 @@ path = "test.rs" harness = false [dev-dependencies] -num_cpus = "1.10.1" +byteorder = "1.0" diff --git a/test-cargo-miri/subcrate/test.rs b/test-cargo-miri/subcrate/test.rs index fdab9402813b..77e3c2878ca0 100644 --- a/test-cargo-miri/subcrate/test.rs +++ b/test-cargo-miri/subcrate/test.rs @@ -1,5 +1,7 @@ use std::env; +use byteorder::{ByteOrder, LittleEndian}; + fn main() { println!("subcrate testing"); @@ -11,6 +13,6 @@ fn main() { let crate_dir = crate_dir.to_string_lossy().replace("\\", "/"); assert_eq!(env_dir, crate_dir); - // Make sure we can call `num_cpus`. - num_cpus::get(); + // Make sure we can call dev-dependencies. + let _n = ::read_u32(&[1, 2, 3, 4]); } From 3f0fdf290fe523fdbb6be21eafe4915638373fe8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jul 2022 08:24:33 -0400 Subject: [PATCH 3602/5092] pass clippy::cast_lossless --- src/lib.rs | 3 ++- src/shims/env.rs | 2 +- src/shims/tls.rs | 2 +- src/stacked_borrows/item.rs | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 35351664caf4..1a07ce9aa12b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,7 +9,7 @@ #![feature(is_some_with)] #![feature(nonzero_ops)] #![feature(local_key_cell_methods)] -#![warn(rust_2018_idioms)] +// Configure clippy and other lints #![allow( clippy::collapsible_else_if, clippy::collapsible_if, @@ -24,6 +24,7 @@ clippy::derive_hash_xor_eq, clippy::too_many_arguments )] +#![warn(rust_2018_idioms, clippy::cast_lossless)] extern crate rustc_apfloat; extern crate rustc_ast; diff --git a/src/shims/env.rs b/src/shims/env.rs index f0818e71b667..c1d39dc09286 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -202,7 +202,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let env_block_ptr = this.read_pointer(env_block_op)?; let result = this.deallocate_ptr(env_block_ptr, None, MiriMemoryKind::Runtime.into()); // If the function succeeds, the return value is nonzero. - Ok(result.is_ok() as i32) + Ok(i32::from(result.is_ok())) } fn setenv( diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 13af447f76c6..9d19160b84d6 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -73,7 +73,7 @@ impl<'tcx> TlsData<'tcx> { self.keys.try_insert(new_key, TlsEntry { data: Default::default(), dtor }).unwrap(); trace!("New TLS key allocated: {} with dtor {:?}", new_key, dtor); - if max_size.bits() < 128 && new_key >= (1u128 << max_size.bits() as u128) { + if max_size.bits() < 128 && new_key >= (1u128 << max_size.bits()) { throw_unsup_format!("we ran out of TLS key space"); } Ok(new_key) diff --git a/src/stacked_borrows/item.rs b/src/stacked_borrows/item.rs index ad1b9b075b40..709b27d191b2 100644 --- a/src/stacked_borrows/item.rs +++ b/src/stacked_borrows/item.rs @@ -22,7 +22,7 @@ impl Item { assert!(tag.0.get() <= TAG_MASK); let packed_tag = tag.0.get(); let packed_perm = perm.to_bits() << PERM_SHIFT; - let packed_protected = (protected as u64) << PROTECTED_SHIFT; + let packed_protected = u64::from(protected) << PROTECTED_SHIFT; let new = Self(packed_tag | packed_perm | packed_protected); From b67a6ff09911736f331933074939dd4fb7b38200 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jul 2022 08:35:45 -0400 Subject: [PATCH 3603/5092] pass clippy::cast_sign_loss and clippy::cast_possible_wrap --- src/intptrcast.rs | 1 + src/lib.rs | 7 ++++++- src/shims/env.rs | 2 +- src/shims/foreign_items.rs | 12 ++++++++++-- src/shims/unix/fs.rs | 8 ++++++-- src/shims/windows/dlsym.rs | 2 +- 6 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index aa7111cb81fc..99fc086a229c 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -230,6 +230,7 @@ impl<'mir, 'tcx> GlobalStateInner { // Wrapping "addr - base_addr" let dl = ecx.data_layout(); + #[allow(clippy::cast_possible_wrap)] // we want to wrap here let neg_base_addr = (base_addr as i64).wrapping_neg(); Some(( alloc_id, diff --git a/src/lib.rs b/src/lib.rs index 1a07ce9aa12b..c1b0c4afca68 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,7 +24,12 @@ clippy::derive_hash_xor_eq, clippy::too_many_arguments )] -#![warn(rust_2018_idioms, clippy::cast_lossless)] +#![warn( + rust_2018_idioms, + clippy::cast_possible_wrap, // unsigned -> signed + clippy::cast_sign_loss, // signed -> unsigned + clippy::cast_lossless, +)] extern crate rustc_apfloat; extern crate rustc_ast; diff --git a/src/shims/env.rs b/src/shims/env.rs index c1d39dc09286..db1ddf6291fd 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -459,7 +459,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // The reason we need to do this wacky of a conversion is because // `libc::getpid` returns an i32, however, `std::process::id()` return an u32. // So we un-do the conversion that stdlib does and turn it back into an i32. - + #[allow(clippy::cast_possible_wrap)] Ok(std::process::id() as i32) } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 99f061716219..317eab082c0c 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -526,8 +526,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "memrchr" => { let [ptr, val, num] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let ptr = this.read_pointer(ptr)?; - let val = this.read_scalar(val)?.to_i32()? as u8; + let val = this.read_scalar(val)?.to_i32()?; let num = this.read_scalar(num)?.to_machine_usize(this)?; + // The docs say val is "interpreted as unsigned char". + #[allow(clippy::cast_sign_loss)] + let val = val as u8; + if let Some(idx) = this .read_bytes_ptr(ptr, Size::from_bytes(num))? .iter() @@ -543,8 +547,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "memchr" => { let [ptr, val, num] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let ptr = this.read_pointer(ptr)?; - let val = this.read_scalar(val)?.to_i32()? as u8; + let val = this.read_scalar(val)?.to_i32()?; let num = this.read_scalar(num)?.to_machine_usize(this)?; + // The docs say val is "interpreted as unsigned char". + #[allow(clippy::cast_sign_loss)] + let val = val as u8; + let idx = this .read_bytes_ptr(ptr, Size::from_bytes(num))? .iter() diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index 50a2053078f8..3b82cb3c4eb8 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -776,7 +776,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We cap the number of read bytes to the largest value that we are able to fit in both the // host's and target's `isize`. This saves us from having to handle overflows later. - let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64); + let count = count + .min(u64::try_from(this.machine_isize_max()).unwrap()) + .min(u64::try_from(isize::MAX).unwrap()); let communicate = this.machine.communicate(); if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { @@ -827,7 +829,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We cap the number of written bytes to the largest value that we are able to fit in both the // host's and target's `isize`. This saves us from having to handle overflows later. - let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64); + let count = count + .min(u64::try_from(this.machine_isize_max()).unwrap()) + .min(u64::try_from(isize::MAX).unwrap()); let communicate = this.machine.communicate(); if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index ee4f39227772..51b0e3b83d47 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -102,7 +102,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Return whether this was a success. >= 0 is success. // For the error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR. this.write_scalar( - Scalar::from_i32(if written.is_some() { 0 } else { 0xC0000185u32 as i32 }), + Scalar::from_u32(if written.is_some() { 0 } else { 0xC0000185u32 }), dest, )?; } From 7f6034862d0a22c7337eb428c67fcdb23b9168ae Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jul 2022 08:44:16 -0400 Subject: [PATCH 3604/5092] pass clippy::cast_possible_truncation --- src/lib.rs | 1 + src/shims/backtrace.rs | 6 ++++-- src/shims/foreign_items.rs | 12 ++++++++---- src/shims/intrinsics/mod.rs | 5 +---- src/shims/unix/fs.rs | 4 ++-- src/shims/windows/dlsym.rs | 3 ++- src/shims/windows/foreign_items.rs | 2 +- 7 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c1b0c4afca68..caae17b20223 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,6 +29,7 @@ clippy::cast_possible_wrap, // unsigned -> signed clippy::cast_sign_loss, // signed -> unsigned clippy::cast_lossless, + clippy::cast_possible_truncation, )] extern crate rustc_apfloat; diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 54ab8665ce35..9182b2a72173 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -171,9 +171,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); } - let lineno: u32 = lo.line as u32; + // `u32` is not enough to fit line/colno, which can be `usize`. It seems unlikely that a + // file would have more than 2^32 lines or columns, but whatever, just default to 0. + let lineno: u32 = u32::try_from(lo.line).unwrap_or(0); // `lo.col` is 0-based - add 1 to make it 1-based for the caller. - let colno: u32 = lo.col.0 as u32 + 1; + let colno: u32 = u32::try_from(lo.col.0 + 1).unwrap_or(0); let dest = this.force_allocation(dest)?; if let ty::Adt(adt, _) = dest.layout.ty.kind() { diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 317eab082c0c..208e7ea788f7 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -82,8 +82,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let align = this.min_align(size, kind); let ptr = this.allocate_ptr(Size::from_bytes(size), align, kind.into())?; if zero_init { - // We just allocated this, the access is definitely in-bounds. - this.write_bytes_ptr(ptr.into(), iter::repeat(0u8).take(size as usize)).unwrap(); + // We just allocated this, the access is definitely in-bounds and fits into our address space. + this.write_bytes_ptr( + ptr.into(), + iter::repeat(0u8).take(usize::try_from(size).unwrap()), + ) + .unwrap(); } Ok(ptr.into()) } @@ -529,7 +533,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val = this.read_scalar(val)?.to_i32()?; let num = this.read_scalar(num)?.to_machine_usize(this)?; // The docs say val is "interpreted as unsigned char". - #[allow(clippy::cast_sign_loss)] + #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)] let val = val as u8; if let Some(idx) = this @@ -550,7 +554,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val = this.read_scalar(val)?.to_i32()?; let num = this.read_scalar(num)?.to_machine_usize(this)?; // The docs say val is "interpreted as unsigned char". - #[allow(clippy::cast_sign_loss)] + #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)] let val = val as u8; let idx = this diff --git a/src/shims/intrinsics/mod.rs b/src/shims/intrinsics/mod.rs index c07ed8b29489..4c2d08ffceab 100644 --- a/src/shims/intrinsics/mod.rs +++ b/src/shims/intrinsics/mod.rs @@ -117,10 +117,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let byte_count = ty_layout.size.checked_mul(count, this).ok_or_else(|| { err_ub_format!("overflow computing total size of `{intrinsic_name}`") })?; - this.write_bytes_ptr( - ptr, - iter::repeat(val_byte).take(byte_count.bytes() as usize), - )?; + this.write_bytes_ptr(ptr, iter::repeat(val_byte).take(byte_count.bytes_usize()))?; } // Floating-point operations diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index 3b82cb3c4eb8..dc31237a3199 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -785,8 +785,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("read: FD mapped to {:?}", file_descriptor); // We want to read at most `count` bytes. We are sure that `count` is not negative // because it was a target's `usize`. Also we are sure that its smaller than - // `usize::MAX` because it is a host's `isize`. - let mut bytes = vec![0; count as usize]; + // `usize::MAX` because it is bounded by the host's `isize`. + let mut bytes = vec![0; usize::try_from(count).unwrap()]; // `File::read` never returns a value larger than `count`, // so this cannot fail. let result = diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 51b0e3b83d47..eab5f99c8785 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -84,7 +84,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { io::stderr().write(buf_cont) }; - res.ok().map(|n| n as u32) + // We write at most `n` bytes, which is a `u32`, so we cannot have written more than that. + res.ok().map(|n| u32::try_from(n).unwrap()) } else { throw_unsup_format!( "on Windows, writing to anything except stdout/stderr is not supported" diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 3f4b8b14002e..29afe52cafd6 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -116,7 +116,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Initialize with `0`. this.write_bytes_ptr( system_info.ptr, - iter::repeat(0u8).take(system_info.layout.size.bytes() as usize), + iter::repeat(0u8).take(system_info.layout.size.bytes_usize()), )?; // Set selected fields. let word_layout = this.machine.layouts.u16; From 649b2164824c47419ffeffa7266f18a9cc84824e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jul 2022 09:36:59 -0400 Subject: [PATCH 3605/5092] add a flag to print a diagnostic when an outdated value is returned from an atomic load --- README.md | 3 +++ src/bin/miri.rs | 2 ++ src/concurrency/data_race.rs | 6 +++++- src/concurrency/weak_memory.rs | 34 ++++++++++++++++++++++------------ src/diagnostics.rs | 7 ++++++- src/eval.rs | 3 +++ src/machine.rs | 7 +++++-- 7 files changed, 46 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 0741f373bb67..fa235a45f509 100644 --- a/README.md +++ b/README.md @@ -377,6 +377,9 @@ to Miri failing to detect cases of undefined behavior in a program. happening and where in your code would be a good place to look for it. Specifying this argument multiple times does not overwrite the previous values, instead it appends its values to the list. Listing a tag multiple times has no effect. +* `-Zmiri-track-weak-memory-loads` shows a backtrace when weak memory emulation returns an outdated + value from a load. This can help diagnose problems that disappear under + `-Zmiri-disable-weak-memory-emulation`. [function ABI]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 516c730e3fbd..14694ac7b053 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -358,6 +358,8 @@ fn main() { miri_config.isolated_op = miri::IsolatedOp::Allow; } else if arg == "-Zmiri-disable-weak-memory-emulation" { miri_config.weak_memory_emulation = false; + } else if arg == "-Zmiri-track-weak-memory-loads" { + miri_config.track_outdated_loads = true; } else if let Some(param) = arg.strip_prefix("-Zmiri-isolation-error=") { if matches!(isolation_enabled, Some(false)) { panic!("-Zmiri-isolation-error cannot be used along with -Zmiri-disable-isolation"); diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 90b38225105d..6ea87a82cb92 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -1187,12 +1187,15 @@ pub struct GlobalState { /// The timestamp of last SC write performed by each thread last_sc_write: RefCell, + + /// Track when an outdated (weak memory) load happens. + pub track_outdated_loads: bool, } impl GlobalState { /// Create a new global state, setup with just thread-id=0 /// advanced to timestamp = 1. - pub fn new() -> Self { + pub fn new(config: &MiriConfig) -> Self { let mut global_state = GlobalState { multi_threaded: Cell::new(false), ongoing_action_data_race_free: Cell::new(false), @@ -1203,6 +1206,7 @@ impl GlobalState { terminated_threads: RefCell::new(FxHashMap::default()), last_sc_fence: RefCell::new(VClock::default()), last_sc_write: RefCell::new(VClock::default()), + track_outdated_loads: config.track_outdated_loads, }; // Setup the main-thread since it is not explicitly created: diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index 137a9f43d4ee..317258a028d0 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -82,10 +82,7 @@ use rustc_const_eval::interpret::{ }; use rustc_data_structures::fx::FxHashMap; -use crate::{ - AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, Provenance, ThreadManager, VClock, VTimestamp, - VectorIdx, -}; +use crate::*; use super::{ data_race::{GlobalState as DataRaceState, ThreadClockSet}, @@ -113,6 +110,13 @@ pub(super) struct StoreBuffer { buffer: VecDeque, } +/// Whether a load returned the latest value or not. +#[derive(PartialEq, Eq)] +enum LoadRecency { + Latest, + Outdated, +} + #[derive(Debug, Clone, PartialEq, Eq)] struct StoreElement { /// The identifier of the vector index, corresponding to a thread @@ -254,11 +258,11 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { is_seqcst: bool, rng: &mut (impl rand::Rng + ?Sized), validate: impl FnOnce() -> InterpResult<'tcx>, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { + ) -> InterpResult<'tcx, (ScalarMaybeUninit, LoadRecency)> { // Having a live borrow to store_buffer while calling validate_atomic_load is fine // because the race detector doesn't touch store_buffer - let store_elem = { + let (store_elem, recency) = { // The `clocks` we got here must be dropped before calling validate_atomic_load // as the race detector will update it let (.., clocks) = global.current_thread_state(thread_mgr); @@ -274,7 +278,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { let (index, clocks) = global.current_thread_state(thread_mgr); let loaded = store_elem.load_impl(index, &clocks); - Ok(loaded) + Ok((loaded, recency)) } fn buffered_write( @@ -296,7 +300,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { is_seqcst: bool, clocks: &ThreadClockSet, rng: &mut R, - ) -> &StoreElement { + ) -> (&StoreElement, LoadRecency) { use rand::seq::IteratorRandom; let mut found_sc = false; // FIXME: we want an inclusive take_while (stops after a false predicate, but @@ -359,9 +363,12 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { } }); - candidates - .choose(rng) - .expect("store buffer cannot be empty, an element is populated on construction") + let chosen = candidates.choose(rng).expect("store buffer cannot be empty"); + if std::ptr::eq(chosen, self.buffer.back().expect("store buffer cannot be empty")) { + (chosen, LoadRecency::Latest) + } else { + (chosen, LoadRecency::Outdated) + } } /// ATOMIC STORE IMPL in the paper (except we don't need the location's vector clock) @@ -499,13 +506,16 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: alloc_range(base_offset, place.layout.size), latest_in_mo, )?; - let loaded = buffer.buffered_read( + let (loaded, recency) = buffer.buffered_read( global, &this.machine.threads, atomic == AtomicReadOrd::SeqCst, &mut *rng, validate, )?; + if global.track_outdated_loads && recency == LoadRecency::Outdated { + register_diagnostic(NonHaltingDiagnostic::WeakMemoryOutdatedLoad); + } return Ok(loaded); } diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 6a692059be92..a378df0ad82b 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -74,6 +74,7 @@ pub enum NonHaltingDiagnostic { Int2Ptr { details: bool, }, + WeakMemoryOutdatedLoad, } /// Level of Miri specific diagnostics @@ -474,6 +475,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx format!("progress report: current operation being executed is here"), Int2Ptr { .. } => format!("integer-to-pointer cast"), + WeakMemoryOutdatedLoad => + format!("weak memory emulation: outdated value returned from load"), }; let (title, diag_level) = match e { @@ -485,7 +488,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | CreatedCallId(..) | CreatedAlloc(..) | FreedAlloc(..) - | ProgressReport => ("tracking was triggered", DiagLevel::Note), + | ProgressReport + | WeakMemoryOutdatedLoad => + ("tracking was triggered", DiagLevel::Note), }; let helps = match e { diff --git a/src/eval.rs b/src/eval.rs index 0f354aa54949..53264bd46591 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -102,6 +102,8 @@ pub struct MiriConfig { pub data_race_detector: bool, /// Determine if weak memory emulation should be enabled. Requires data race detection to be enabled pub weak_memory_emulation: bool, + /// Track when an outdated (weak memory) load happens. + pub track_outdated_loads: bool, /// Rate of spurious failures for compare_exchange_weak atomic operations, /// between 0.0 and 1.0, defaulting to 0.8 (80% chance of failure). pub cmpxchg_weak_failure_rate: f64, @@ -143,6 +145,7 @@ impl Default for MiriConfig { tracked_alloc_ids: HashSet::default(), data_race_detector: true, weak_memory_emulation: true, + track_outdated_loads: false, cmpxchg_weak_failure_rate: 0.8, // 80% measureme_out: None, panic_on_unsupported: false, diff --git a/src/machine.rs b/src/machine.rs index 40f4c9ed90c0..c77de4ec51ff 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -376,8 +376,11 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { } else { None }; - let data_race = - if config.data_race_detector { Some(data_race::GlobalState::new()) } else { None }; + let data_race = if config.data_race_detector { + Some(data_race::GlobalState::new(config)) + } else { + None + }; Evaluator { stacked_borrows, data_race, From b08e51d79a0a4051eab997007ff36d9ca1ee4ace Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jul 2022 11:54:07 -0400 Subject: [PATCH 3606/5092] refactor away some 'else { None }' --- src/machine.rs | 42 ++++++++++++++---------------------------- 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index c77de4ec51ff..3e45f77d54c3 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -367,20 +367,14 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { measureme::Profiler::new(out).expect("Couldn't create `measureme` profiler") }); let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0)); - let stacked_borrows = if config.stacked_borrows { - Some(RefCell::new(stacked_borrows::GlobalStateInner::new( + let stacked_borrows = config.stacked_borrows.then(|| { + RefCell::new(stacked_borrows::GlobalStateInner::new( config.tracked_pointer_tags.clone(), config.tracked_call_ids.clone(), config.retag_fields, - ))) - } else { - None - }; - let data_race = if config.data_race_detector { - Some(data_race::GlobalState::new(config)) - } else { - None - }; + )) + }); + let data_race = config.data_race_detector.then(|| data_race::GlobalState::new(config)); Evaluator { stacked_borrows, data_race, @@ -691,32 +685,24 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } let alloc = alloc.into_owned(); - let stacks = if let Some(stacked_borrows) = &ecx.machine.stacked_borrows { - Some(Stacks::new_allocation( + let stacks = ecx.machine.stacked_borrows.as_ref().map(|stacked_borrows| { + Stacks::new_allocation( id, alloc.size(), stacked_borrows, kind, ecx.machine.current_span(), - )) - } else { - None - }; - let race_alloc = if let Some(data_race) = &ecx.machine.data_race { - Some(data_race::AllocExtra::new_allocation( + ) + }); + let race_alloc = ecx.machine.data_race.as_ref().map(|data_race| { + data_race::AllocExtra::new_allocation( data_race, &ecx.machine.threads, alloc.size(), kind, - )) - } else { - None - }; - let buffer_alloc = if ecx.machine.weak_memory { - Some(weak_memory::AllocExtra::new_allocation()) - } else { - None - }; + ) + }); + let buffer_alloc = ecx.machine.weak_memory.then(weak_memory::AllocExtra::new_allocation); let alloc: Allocation = alloc.adjust_from_tcx( &ecx.tcx, AllocExtra { From 6c0398da7d74ec7bf16e4f48a900036aecfd714c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jul 2022 12:47:26 -0400 Subject: [PATCH 3607/5092] don't dump xargo output onto users of 'cargo miri test' --- cargo-miri/bin.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index bb2eb54ffebc..72e56daf57eb 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -497,9 +497,24 @@ path = "lib.rs" // Disable debug assertions in the standard library -- Miri is already slow enough. // But keep the overflow checks, they are cheap. command.env("RUSTFLAGS", "-Cdebug-assertions=off -Coverflow-checks=on"); + // Manage the output the user sees. + if only_setup { + eprintln!("Preparing a sysroot for Miri..."); + } else { + eprint!("Preparing a sysroot for Miri... "); + command.stdout(process::Stdio::null()); + command.stderr(process::Stdio::null()); + } // Finally run it! if command.status().expect("failed to run xargo").success().not() { - show_error(format!("failed to run xargo")); + if only_setup { + show_error(format!("failed to run xargo, see error details above")) + } else { + show_error(format!("failed to run xargo; run `cargo miri setup` to see the error details")) + } + } + if !only_setup { + eprintln!("done"); } // That should be it! But we need to figure out where xargo built stuff. @@ -510,10 +525,10 @@ path = "lib.rs" // Figure out what to print. let print_sysroot = only_setup && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path if print_sysroot { - // Print just the sysroot and nothing else; this way we do not need any escaping. + // Print just the sysroot and nothing else to stdout; this way we do not need any escaping. println!("{}", sysroot.display()); } else if only_setup { - println!("A libstd for Miri is now available in `{}`.", sysroot.display()); + eprintln!("A sysroot for Miri is now available in `{}`.", sysroot.display()); } } From 0c5392f4354ba06028155c318fca1d3b287f83ea Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jul 2022 13:28:44 -0400 Subject: [PATCH 3608/5092] now test-cargo-miri will actually work even without a hot cache :D --- cargo-miri/bin.rs | 4 +++- ci.sh | 5 ++--- test-cargo-miri/run-test.py | 16 ++++++++-------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 72e56daf57eb..4c0b9e41d3bf 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -510,7 +510,9 @@ path = "lib.rs" if only_setup { show_error(format!("failed to run xargo, see error details above")) } else { - show_error(format!("failed to run xargo; run `cargo miri setup` to see the error details")) + show_error(format!( + "failed to run xargo; run `cargo miri setup` to see the error details" + )) } } if !only_setup { diff --git a/ci.sh b/ci.sh index 8c63a57a4f49..7bd131405bd5 100755 --- a/ci.sh +++ b/ci.sh @@ -21,6 +21,7 @@ function run_tests { echo "Testing host architecture" fi + ## ui test suite ./miri test --locked if [ -z "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with optimizations (`-O` is what cargo passes, but crank MIR @@ -30,15 +31,13 @@ function run_tests { MIRIFLAGS="-O -Zmir-opt-level=4" MIRI_SKIP_UI_CHECKS=1 ./miri test --locked -- tests/{pass,panic} fi + ## test-cargo-miri # On Windows, there is always "python", not "python3" or "python2". if command -v python3 > /dev/null; then PYTHON=python3 else PYTHON=python fi - - # "miri test" has built the sysroot for us, now this should pass without - # any interactive questions. ${PYTHON} test-cargo-miri/run-test.py echo diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index ab43c7251158..3805bd19777f 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -25,7 +25,12 @@ def cargo_miri(cmd, quiet = True): def normalize_stdout(str): str = str.replace("src\\", "src/") # normalize paths across platforms - return re.sub("finished in \d+\.\d\ds", "finished in $TIME", str) + str = re.sub("finished in \d+\.\d\ds", "finished in $TIME", str) # the time keeps changing, obviously + return str + +def normalize_stderr(str): + str = str.replace("Preparing a sysroot for Miri... done\n", "") # remove leading cargo-miri setup output + return str def check_output(actual, path, name): expected = open(path).read() @@ -51,9 +56,8 @@ def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): env=p_env, ) (stdout, stderr) = p.communicate(input=stdin) - stdout = stdout.decode("UTF-8") - stderr = stderr.decode("UTF-8") - stdout = normalize_stdout(stdout) + stdout = normalize_stdout(stdout.decode("UTF-8")) + stderr = normalize_stderr(stderr.decode("UTF-8")) stdout_matches = check_output(stdout, stdout_ref, "stdout") stderr_matches = check_output(stderr, stderr_ref, "stderr") @@ -175,10 +179,6 @@ os.environ["RUST_TEST_THREADS"] = "1" # avoid non-deterministic output due to co target_str = " for target {}".format(os.environ['MIRI_TEST_TARGET']) if 'MIRI_TEST_TARGET' in os.environ else "" print(CGREEN + CBOLD + "## Running `cargo miri` tests{}".format(target_str) + CEND) -if not 'MIRI_SYSROOT' in os.environ: - # Make sure we got a working sysroot. - # (If the sysroot gets built later when output is compared, that leads to test failures.) - subprocess.run(cargo_miri("setup"), check=True) test_cargo_miri_run() test_cargo_miri_test() # Ensure we did not create anything outside the expected target dir. From dd01870657fa415bb5f1fa1b66dc7d7b1aa3e08c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jul 2022 17:36:42 -0400 Subject: [PATCH 3609/5092] cargo-miri: use '--config target.runner' rather than the TARGET_RUNNER env vars --- cargo-miri/bin.rs | 91 ++++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 4c0b9e41d3bf..202ac890fabd 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -9,7 +9,7 @@ use std::ffi::{OsStr, OsString}; use std::fmt::Write as _; use std::fs::{self, File}; use std::io::{self, BufRead, BufReader, BufWriter, Read, Write}; -use std::iter::TakeWhile; +use std::iter::{self, TakeWhile}; use std::ops::Not; use std::path::{Path, PathBuf}; use std::process::{self, Command}; @@ -206,6 +206,14 @@ fn forward_miri_sysroot(cmd: &mut Command) { cmd.arg(sysroot); } +/// Escapes `s` in a way that is suitable for using it as a string literal in TOML syntax. +fn escape_for_toml(s: &str) -> String { + // We want to surround this string in quotes `"`. So we first escape all quotes, + // and also all backslashes (that are used to escape quotes). + let s = s.replace('\\', r#"\\"#).replace('"', r#"\""#); + format!("\"{}\"", s) +} + /// Returns the path to the `miri` binary fn find_miri() -> PathBuf { if let Some(path) = env::var_os("MIRI") { @@ -669,7 +677,11 @@ fn phase_cargo_miri(mut args: impl Iterator) { // describes an alternative // approach that uses `cargo check`, making that part easier but target and binary handling // harder. - let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); + let cargo_miri_path = std::env::current_exe() + .expect("current executable path invalid") + .into_os_string() + .into_string() + .expect("current executable path is not valid UTF-8"); let cargo_cmd = match subcommand { MiriCommand::Forward(s) => s, MiriCommand::Setup => return, // `cargo miri setup` stops here. @@ -699,8 +711,8 @@ fn phase_cargo_miri(mut args: impl Iterator) { target_dir.push("miri"); cmd.arg("--target-dir").arg(target_dir); - // Make sure we know the build target, and cargo does, too. - // This is needed to make the `CARGO_TARGET_*_RUNNER` env var do something, + // Make sure the build target is explicitly set. + // This is needed to make the `target.runner` settings do something, // and it later helps us detect which crates are proc-macro/build-script // (host crates) and which crates are needed for the program itself. let host = version_info().host; @@ -714,6 +726,18 @@ fn phase_cargo_miri(mut args: impl Iterator) { &host }; + let cargo_miri_path_for_toml = escape_for_toml(&cargo_miri_path); + cmd.arg("--config") + .arg(format!("target.{target}.runner=[{cargo_miri_path_for_toml}, 'runner']",)); + if &host != target { + // Set ourselves as runner for host and target. (Unit tests of `proc-macro` crates are run on + // the host, so we set the host runner to us in order to skip them.) + // But only do that if host and target are different; setting this command twice otherwise + // makes cargo concatenate the two arrays. + cmd.arg("--config") + .arg(format!("target.{host}.runner=[{cargo_miri_path_for_toml}, 'runner']",)); + } + // Forward all further arguments after `--` to cargo. cmd.arg("--").args(args); @@ -743,16 +767,6 @@ fn phase_cargo_miri(mut args: impl Iterator) { // bootstrap `rustc` thing in our way! Instead, we have MIRI_HOST_SYSROOT to use for host builds. cmd.env("RUSTC", &fs::canonicalize(find_miri()).unwrap()); - let runner_env_name = - |triple: &str| format!("CARGO_TARGET_{}_RUNNER", triple.to_uppercase().replace('-', "_")); - let host_runner_env_name = runner_env_name(&host); - let target_runner_env_name = runner_env_name(target); - // Set the target runner to us, so we can interpret the binaries. - cmd.env(&target_runner_env_name, &cargo_miri_path); - // Unit tests of `proc-macro` crates are run on the host, so we set the host runner to - // us in order to skip them. - cmd.env(&host_runner_env_name, &cargo_miri_path); - // Set rustdoc to us as well, so we can run doctests. cmd.env("RUSTDOC", &cargo_miri_path); @@ -1194,38 +1208,25 @@ fn main() { return; } - let mut args = args.peekable(); - if args.next_if(|a| a == "miri").is_some() { - phase_cargo_miri(args); - } else if let Some(arg) = args.peek().cloned() { - // Cargo calls us for everything it does. We could be invoked as rustc, rustdoc, or the runner. - - // If the first arg is equal to the RUSTC variable (which should be set at this point), - // then we need to behave as rustc. This is the somewhat counter-intuitive behavior of - // having both RUSTC and RUSTC_WRAPPER set (see - // https://github.com/rust-lang/cargo/issues/10886). - if arg == env::var("RUSTC").unwrap() { - args.next().unwrap(); // consume wrapped RUSTC command. - return phase_rustc(args, RustcPhase::Build); - } - // We have to distinguish the "runner" and "rustdoc" cases. - // As runner, the first argument is the binary (a file that should exist, with an absolute path); - // as rustdoc, the first argument is a flag (`--something`). - let binary = Path::new(&arg); - if binary.exists() { - assert!(!arg.starts_with("--")); // not a flag - phase_runner(args, RunnerPhase::Cargo); - } else if arg.starts_with("--") { - phase_rustdoc(args); - } else { - show_error(format!( - "`cargo-miri` called with unexpected first argument `{}`; please only invoke this binary through `cargo miri`", - arg - )); - } - } else { + let Some(first) = args.next() else { show_error(format!( "`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`" - )); + )) + }; + match first.as_str() { + "miri" => phase_cargo_miri(args), + "runner" => phase_runner(args, RunnerPhase::Cargo), + arg if arg == env::var("RUSTC").unwrap() => { + // If the first arg is equal to the RUSTC env ariable (which should be set at this + // point), then we need to behave as rustc. This is the somewhat counter-intuitive + // behavior of having both RUSTC and RUSTC_WRAPPER set + // (see https://github.com/rust-lang/cargo/issues/10886). + phase_rustc(args, RustcPhase::Build) + } + _ => { + // Everything else must be rustdoc. But we need to get `first` "back onto the iterator", + // it is some part of the rustdoc invocation. + phase_rustdoc(iter::once(first).chain(args)); + } } } From e14df0537025b660adf23edeb069954a25a23611 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jul 2022 17:46:02 -0400 Subject: [PATCH 3610/5092] set runner for all targets via 'all()' --- cargo-miri/bin.rs | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 202ac890fabd..ff3361899c4b 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -715,28 +715,17 @@ fn phase_cargo_miri(mut args: impl Iterator) { // This is needed to make the `target.runner` settings do something, // and it later helps us detect which crates are proc-macro/build-script // (host crates) and which crates are needed for the program itself. - let host = version_info().host; - let target = get_arg_flag_value("--target"); - let target = if let Some(ref target) = target { - target - } else { - // No target given. Pick default and tell cargo about it. + if get_arg_flag_value("--target").is_none() { + // No target given. Explicitly pick the host. cmd.arg("--target"); - cmd.arg(&host); - &host - }; + cmd.arg(version_info().host); + } + // Set ourselves as runner for al binaries invoked by cargo. + // We use `all()` since `true` is not a thing in cfg-lang, but the empty conjunction is. :) let cargo_miri_path_for_toml = escape_for_toml(&cargo_miri_path); cmd.arg("--config") - .arg(format!("target.{target}.runner=[{cargo_miri_path_for_toml}, 'runner']",)); - if &host != target { - // Set ourselves as runner for host and target. (Unit tests of `proc-macro` crates are run on - // the host, so we set the host runner to us in order to skip them.) - // But only do that if host and target are different; setting this command twice otherwise - // makes cargo concatenate the two arrays. - cmd.arg("--config") - .arg(format!("target.{host}.runner=[{cargo_miri_path_for_toml}, 'runner']",)); - } + .arg(format!("target.'cfg(all())'.runner=[{cargo_miri_path_for_toml}, 'runner']")); // Forward all further arguments after `--` to cargo. cmd.arg("--").args(args); From b93fcd99e84f31becfb205c858b2054a9ce9b902 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jul 2022 17:58:20 -0400 Subject: [PATCH 3611/5092] avoid spurious 'Preparing a sysroot for Miri...' in 'cargo miri setup --print-sysroot' also clean up sysroot building printing logic a bit --- cargo-miri/bin.rs | 28 ++++++++++++++++++---------- miri | 3 --- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index ff3361899c4b..1b14d4da9cc4 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -35,6 +35,11 @@ The cargo options are exactly the same as for `cargo run` and `cargo test`, resp Examples: cargo miri run cargo miri test -- test-suite-filter + + cargo miri setup --print sysroot + This will print the path to the generated sysroot (and nothing else) on stdout. + stderr will still contain progress information about how the build is doing. + "#; #[derive(Clone, Debug)] @@ -361,6 +366,8 @@ fn write_to_file(filename: &Path, content: &str) { /// done all this already. fn setup(subcommand: &MiriCommand) { let only_setup = matches!(subcommand, MiriCommand::Setup); + let ask_user = !only_setup; + let print_sysroot = only_setup && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path if std::env::var_os("MIRI_SYSROOT").is_some() { if only_setup { println!("WARNING: MIRI_SYSROOT already set, not doing anything.") @@ -368,10 +375,6 @@ fn setup(subcommand: &MiriCommand) { return; } - // Subcommands other than `setup` will do a setup if necessary, but - // interactively confirm first. - let ask_user = !only_setup; - // First, we need xargo. if xargo_version().map_or(true, |v| v < XARGO_MIN_VERSION) { if std::env::var_os("XARGO_CHECK").is_some() { @@ -507,8 +510,14 @@ path = "lib.rs" command.env("RUSTFLAGS", "-Cdebug-assertions=off -Coverflow-checks=on"); // Manage the output the user sees. if only_setup { + // We want to be explicit. eprintln!("Preparing a sysroot for Miri..."); + if print_sysroot { + // Be extra sure there is no noise on stdout. + command.stdout(process::Stdio::null()); + } } else { + // We want to be quiet, but still let the user know that something is happening. eprint!("Preparing a sysroot for Miri... "); command.stdout(process::Stdio::null()); command.stderr(process::Stdio::null()); @@ -523,9 +532,6 @@ path = "lib.rs" )) } } - if !only_setup { - eprintln!("done"); - } // That should be it! But we need to figure out where xargo built stuff. // Unfortunately, it puts things into a different directory when the @@ -533,12 +539,14 @@ path = "lib.rs" let sysroot = if target == &host { dir.join("HOST") } else { PathBuf::from(dir) }; std::env::set_var("MIRI_SYSROOT", &sysroot); // pass the env var to the processes we spawn, which will turn it into "--sysroot" flags // Figure out what to print. - let print_sysroot = only_setup && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path + if only_setup { + eprintln!("A sysroot for Miri is now available in `{}`.", sysroot.display()); + } else { + eprintln!("done"); + } if print_sysroot { // Print just the sysroot and nothing else to stdout; this way we do not need any escaping. println!("{}", sysroot.display()); - } else if only_setup { - eprintln!("A sysroot for Miri is now available in `{}`.", sysroot.display()); } } diff --git a/miri b/miri index 463e4607baed..8bef9d1291a9 100755 --- a/miri +++ b/miri @@ -131,9 +131,6 @@ export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR $RUSTFLAGS" # Build a sysroot and set MIRI_SYSROOT to use it. Arguments are passed to `cargo miri setup`. build_sysroot() { - # Build once, for the user to see. - $CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -- miri setup "$@" - # Call again, to just set env var. export MIRI_SYSROOT="$($CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -q -- miri setup --print-sysroot "$@")" } From 8b643809ccd3f9e124ee0dcd2fd5cc10d4ec969a Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sat, 23 Jul 2022 22:27:05 +0200 Subject: [PATCH 3612/5092] Fix outdated docs in sb stack cache Since `Item` is bitpacked now, the full `Item` is stored in the cache. --- src/stacked_borrows/stack.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/stacked_borrows/stack.rs b/src/stacked_borrows/stack.rs index c0d4d0d291f3..6fd8d85f2b5f 100644 --- a/src/stacked_borrows/stack.rs +++ b/src/stacked_borrows/stack.rs @@ -39,11 +39,7 @@ pub struct Stack { unique_range: Range, } -/// A very small cache of searches of the borrow stack -/// This maps items to locations in the borrow stack. Any use of this still needs to do a -/// probably-cold random access into the borrow stack to figure out what `Permission` an -/// `SbTag` grants. We could avoid this by also storing the `Permission` in the cache, but -/// most lookups into the cache are immediately followed by access of the full borrow stack anyway. +/// A very small cache of searches of a borrow stack, mapping `Item`s to their position in said stack. /// /// It may seem like maintaining this cache is a waste for small stacks, but /// (a) iterating over small fixed-size arrays is super fast, and (b) empirically this helps *a lot*, From 25b11f6424d928b1c6876ed3d49655fc4b1f6ffc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jul 2022 19:22:02 -0400 Subject: [PATCH 3613/5092] attempt to overwrite globally set build.rustc-wrapper --- cargo-miri/bin.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 4c0b9e41d3bf..2478e331191c 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -488,14 +488,14 @@ path = "lib.rs" command.env("RUSTC", &cargo_miri_path); } command.env("MIRI_CALLED_FROM_XARGO", "1"); - // Make sure there are no other wrappers or flags getting in our way - // (Cc https://github.com/rust-lang/miri/issues/1421). - // This is consistent with normal `cargo build` that does not apply `RUSTFLAGS` - // to the sysroot either. - command.env_remove("RUSTC_WRAPPER"); - command.env_remove("RUSTFLAGS"); - // Disable debug assertions in the standard library -- Miri is already slow enough. - // But keep the overflow checks, they are cheap. + // Make sure there are no other wrappers getting in our way + // (Cc https://github.com/rust-lang/miri/issues/1421, https://github.com/rust-lang/miri/issues/2429). + // Looks like setting `RUSTC_WRAPPER` to the empty string overwrites `build.rustc-wrapper` set via `config.toml`. + command.env("RUSTC_WRAPPER", ""); + // Disable debug assertions in the standard library -- Miri is already slow enough. But keep the + // overflow checks, they are cheap. This completely overwrites flags the user might have set, + // which is consistent with normal `cargo build` that does not apply `RUSTFLAGS` to the sysroot + // either. command.env("RUSTFLAGS", "-Cdebug-assertions=off -Coverflow-checks=on"); // Manage the output the user sees. if only_setup { From 7267e0d4c5eb8ce2d445bb8c28104de489a2c79e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jul 2022 19:30:15 -0400 Subject: [PATCH 3614/5092] attempt to test RUSTC and RUSTC_WRAPPER shenanigans on CI --- cargo-miri/bin.rs | 1 + ci.sh | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 2478e331191c..9cba2e772bcd 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -483,6 +483,7 @@ path = "lib.rs" // The `MIRI_CALLED_FROM_XARGO` will mean we dispatch to `phase_setup_rustc`. let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); if env::var_os("RUSTC_STAGE").is_some() { + assert!(env::var_os("RUSTC").is_some()); command.env("RUSTC_REAL", &cargo_miri_path); } else { command.env("RUSTC", &cargo_miri_path); diff --git a/ci.sh b/ci.sh index 7bd131405bd5..f93c218f1b0e 100755 --- a/ci.sh +++ b/ci.sh @@ -38,8 +38,21 @@ function run_tests { else PYTHON=python fi + # Some environment setup that attempts to confuse the heck out of cargo-miri. + if [ "$HOST_TARGET" = x86_64-unknown-linux-gnu ]; then + # These act up on Windows (`which miri` produces a filename that does not exist?!?), + # so let's do this only on Linux. Also makes sure things work without these set. + export RUSTC=$(which rustc) + export MIRI=$(which miri) + fi + mkdir -p .cargo + echo 'build.rustc-wrapper = "thisdoesnotexist"' > .cargo/config.toml + # Run the actual test ${PYTHON} test-cargo-miri/run-test.py echo + # Clean up + unset RUSTC MIRI + rm -rf .cargo # Ensure that our benchmarks all work, on the host at least. if [ -z "${MIRI_TEST_TARGET+exists}" ]; then From 5c52a7695c26a96cd8d2a54e0756730c207b3240 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 Jul 2022 07:37:10 -0400 Subject: [PATCH 3615/5092] ui_test: build dependencies in locked mode unless bless is enabled --- ui_test/src/dependencies.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ui_test/src/dependencies.rs b/ui_test/src/dependencies.rs index 8ec7090b96a6..582641b97ae1 100644 --- a/ui_test/src/dependencies.rs +++ b/ui_test/src/dependencies.rs @@ -5,7 +5,7 @@ use std::{ process::Command, }; -use crate::Config; +use crate::{Config, OutputConflictHandling}; #[derive(Default, Debug)] pub struct Dependencies { @@ -40,6 +40,9 @@ pub fn build_dependencies(config: &Config) -> Result { let setup_command = |cmd: &mut Command| { cmd.envs(envs.iter().map(|(k, v)| (k, v))); cmd.arg("--manifest-path").arg(manifest_path); + if matches!(config.output_conflict_handling, OutputConflictHandling::Error) { + cmd.arg("--locked"); + } }; setup_command(&mut build); From c33fc24566da5e342e03183c07314c910b690d25 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 Jul 2022 08:37:29 -0400 Subject: [PATCH 3616/5092] rustup --- rust-version | 2 +- .../dangling_pointers/null_pointer_write_zst.rs | 2 +- .../null_pointer_write_zst.stderr | 14 ++++---------- tests/fail/intrinsics/write_bytes_overflow.rs | 2 +- tests/fail/intrinsics/write_bytes_overflow.stderr | 14 ++++---------- 5 files changed, 11 insertions(+), 23 deletions(-) diff --git a/rust-version b/rust-version index b54ff9e100ed..c710735735c7 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -41419e70366962c9a878bfe673ef4df38db6f7f1 +35a061724802377a21fc6dac1ebcbb9b8d1f558a diff --git a/tests/fail/dangling_pointers/null_pointer_write_zst.rs b/tests/fail/dangling_pointers/null_pointer_write_zst.rs index 7181a5979b44..c00344b6de23 100644 --- a/tests/fail/dangling_pointers/null_pointer_write_zst.rs +++ b/tests/fail/dangling_pointers/null_pointer_write_zst.rs @@ -1,6 +1,5 @@ // Some optimizations remove ZST accesses, thus masking this UB. //@compile-flags: -Zmir-opt-level=0 -//@error-pattern: memory access failed: null pointer is a dangling pointer #[allow(deref_nullptr)] fn main() { @@ -8,4 +7,5 @@ fn main() { // Also not assigning directly as that's array initialization, not assignment. let zst_val = [1u8; 0]; unsafe { std::ptr::null_mut::<[u8; 0]>().write(zst_val) }; + //~^ERROR: memory access failed: null pointer is a dangling pointer } diff --git a/tests/fail/dangling_pointers/null_pointer_write_zst.stderr b/tests/fail/dangling_pointers/null_pointer_write_zst.stderr index 0535aaa3e2d1..17ac04a706ff 100644 --- a/tests/fail/dangling_pointers/null_pointer_write_zst.stderr +++ b/tests/fail/dangling_pointers/null_pointer_write_zst.stderr @@ -1,19 +1,13 @@ error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance) - --> RUSTLIB/core/src/ptr/mod.rs:LL:CC + --> $DIR/null_pointer_write_zst.rs:LL:CC | -LL | copy_nonoverlapping(&src as *const T, dst, 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) +LL | unsafe { std::ptr::null_mut::<[u8; 0]>().write(zst_val) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::ptr::write::<[u8; 0]>` at RUSTLIB/core/src/ptr/mod.rs:LL:CC - = note: inside `std::ptr::mut_ptr::::write` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC -note: inside `main` at $DIR/null_pointer_write_zst.rs:LL:CC - --> $DIR/null_pointer_write_zst.rs:LL:CC - | -LL | unsafe { std::ptr::null_mut::<[u8; 0]>().write(zst_val) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/null_pointer_write_zst.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/write_bytes_overflow.rs b/tests/fail/intrinsics/write_bytes_overflow.rs index 5c49dc00165c..08bc096d6c36 100644 --- a/tests/fail/intrinsics/write_bytes_overflow.rs +++ b/tests/fail/intrinsics/write_bytes_overflow.rs @@ -1,9 +1,9 @@ -//@error-pattern: overflow computing total size of `write_bytes` use std::mem; fn main() { let mut y = 0; unsafe { (&mut y as *mut i32).write_bytes(0u8, 1usize << (mem::size_of::() * 8 - 1)); + //~^ ERROR: overflow computing total size of `write_bytes` } } diff --git a/tests/fail/intrinsics/write_bytes_overflow.stderr b/tests/fail/intrinsics/write_bytes_overflow.stderr index 1e5381279529..47610b062301 100644 --- a/tests/fail/intrinsics/write_bytes_overflow.stderr +++ b/tests/fail/intrinsics/write_bytes_overflow.stderr @@ -1,19 +1,13 @@ error: Undefined Behavior: overflow computing total size of `write_bytes` - --> RUSTLIB/core/src/intrinsics.rs:LL:CC + --> $DIR/write_bytes_overflow.rs:LL:CC | -LL | write_bytes(dst, val, count) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `write_bytes` +LL | (&mut y as *mut i32).write_bytes(0u8, 1usize << (mem::size_of::() * 8 - 1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `write_bytes` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::intrinsics::write_bytes::` at RUSTLIB/core/src/intrinsics.rs:LL:CC - = note: inside `std::ptr::mut_ptr::::write_bytes` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC -note: inside `main` at $DIR/write_bytes_overflow.rs:LL:CC - --> $DIR/write_bytes_overflow.rs:LL:CC - | -LL | (&mut y as *mut i32).write_bytes(0u8, 1usize << (mem::size_of::() * 8 - 1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/write_bytes_overflow.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace From 3ee56989c7f3d355b32f194fca03c0e47a3bd445 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 Jul 2022 08:48:58 -0400 Subject: [PATCH 3617/5092] get rid of some uses of core_intrinsics --- tests/fail/data_race/atomic_read_na_write_race1.rs | 7 ++----- tests/fail/data_race/atomic_read_na_write_race1.stderr | 4 ++-- tests/fail/data_race/atomic_write_na_read_race2.rs | 7 ++----- tests/fail/data_race/atomic_write_na_read_race2.stderr | 2 +- tests/fail/data_race/atomic_write_na_write_race1.rs | 7 ++----- tests/fail/data_race/atomic_write_na_write_race1.stderr | 2 +- tests/fail/weak_memory/racing_mixed_size_read.rs | 8 +++----- tests/fail/weak_memory/racing_mixed_size_read.stderr | 4 ++-- tests/pass/weak_memory/extra_cpp.rs | 1 - tests/pass/weak_memory/extra_cpp_unsafe.rs | 3 +-- 10 files changed, 16 insertions(+), 29 deletions(-) diff --git a/tests/fail/data_race/atomic_read_na_write_race1.rs b/tests/fail/data_race/atomic_read_na_write_race1.rs index 1ef021edc8cc..30900a85d003 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.rs +++ b/tests/fail/data_race/atomic_read_na_write_race1.rs @@ -1,10 +1,8 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 //@ignore-target-windows: Concurrency on Windows is not supported yet. -#![feature(core_intrinsics)] -use std::intrinsics; -use std::sync::atomic::AtomicUsize; +use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; #[derive(Copy, Clone)] @@ -23,8 +21,7 @@ pub fn main() { }); let j2 = spawn(move || { - //Equivalent to: (&*c.0).load(Ordering::SeqCst) - intrinsics::atomic_load_seqcst(c.0 as *mut usize) //~ ERROR: Data race detected between Atomic Load on thread `` and Write on thread `` + (&*c.0).load(Ordering::SeqCst) //~ ERROR: Data race detected between Atomic Load on thread `` and Write on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_read_na_write_race1.stderr b/tests/fail/data_race/atomic_read_na_write_race1.stderr index 2a0ca9260782..e7a219e12352 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.stderr +++ b/tests/fail/data_race/atomic_read_na_write_race1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: Data race detected between Atomic Load on thread `` and Write on thread `` at ALLOC --> $DIR/atomic_read_na_write_race1.rs:LL:CC | -LL | intrinsics::atomic_load_seqcst(c.0 as *mut usize) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Load on thread `` and Write on thread `` at ALLOC +LL | (&*c.0).load(Ordering::SeqCst) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Load on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/atomic_write_na_read_race2.rs b/tests/fail/data_race/atomic_write_na_read_race2.rs index 77b2945f7371..1a79dde0b08a 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.rs +++ b/tests/fail/data_race/atomic_write_na_read_race2.rs @@ -1,10 +1,8 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 //@ignore-target-windows: Concurrency on Windows is not supported yet. -#![feature(core_intrinsics)] -use std::intrinsics::atomic_store; -use std::sync::atomic::AtomicUsize; +use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; #[derive(Copy, Clone)] @@ -23,8 +21,7 @@ pub fn main() { }); let j2 = spawn(move || { - //Equivalent to: (&*c.0).store(32, Ordering::SeqCst) - atomic_store(c.0 as *mut usize, 32); //~ ERROR: Data race detected between Atomic Store on thread `` and Read on thread `` + (&*c.0).store(32, Ordering::SeqCst); //~ ERROR: Data race detected between Atomic Store on thread `` and Read on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_write_na_read_race2.stderr b/tests/fail/data_race/atomic_write_na_read_race2.stderr index 69bf6c5f3742..e9c6005f27e6 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.stderr +++ b/tests/fail/data_race/atomic_write_na_read_race2.stderr @@ -1,7 +1,7 @@ error: Undefined Behavior: Data race detected between Atomic Store on thread `` and Read on thread `` at ALLOC --> $DIR/atomic_write_na_read_race2.rs:LL:CC | -LL | atomic_store(c.0 as *mut usize, 32); +LL | (&*c.0).store(32, Ordering::SeqCst); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Store on thread `` and Read on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior diff --git a/tests/fail/data_race/atomic_write_na_write_race1.rs b/tests/fail/data_race/atomic_write_na_write_race1.rs index 34922dd595ed..04015c2d1420 100644 --- a/tests/fail/data_race/atomic_write_na_write_race1.rs +++ b/tests/fail/data_race/atomic_write_na_write_race1.rs @@ -1,10 +1,8 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 //@ignore-target-windows: Concurrency on Windows is not supported yet. -#![feature(core_intrinsics)] -use std::intrinsics::atomic_store; -use std::sync::atomic::AtomicUsize; +use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; #[derive(Copy, Clone)] @@ -23,8 +21,7 @@ pub fn main() { }); let j2 = spawn(move || { - //Equivalent to: (&*c.0).store(64, Ordering::SeqCst) - atomic_store(c.0 as *mut usize, 64); //~ ERROR: Data race detected between Atomic Store on thread `` and Write on thread `` + (&*c.0).store(64, Ordering::SeqCst); //~ ERROR: Data race detected between Atomic Store on thread `` and Write on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_write_na_write_race1.stderr b/tests/fail/data_race/atomic_write_na_write_race1.stderr index 6abcf4fe3d12..5ecc4ca04026 100644 --- a/tests/fail/data_race/atomic_write_na_write_race1.stderr +++ b/tests/fail/data_race/atomic_write_na_write_race1.stderr @@ -1,7 +1,7 @@ error: Undefined Behavior: Data race detected between Atomic Store on thread `` and Write on thread `` at ALLOC --> $DIR/atomic_write_na_write_race1.rs:LL:CC | -LL | atomic_store(c.0 as *mut usize, 64); +LL | (&*c.0).store(64, Ordering::SeqCst); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Store on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior diff --git a/tests/fail/weak_memory/racing_mixed_size_read.rs b/tests/fail/weak_memory/racing_mixed_size_read.rs index aeaa6b68f6c8..1c0b1c2be8fd 100644 --- a/tests/fail/weak_memory/racing_mixed_size_read.rs +++ b/tests/fail/weak_memory/racing_mixed_size_read.rs @@ -2,10 +2,8 @@ //@compile-flags: -Zmiri-preemption-rate=0 //@ignore-target-windows: Concurrency on Windows is not supported yet. -#![feature(core_intrinsics)] - -use std::sync::atomic::AtomicU32; use std::sync::atomic::Ordering::*; +use std::sync::atomic::{AtomicU16, AtomicU32}; use std::thread::spawn; fn static_atomic(val: u32) -> &'static AtomicU32 { @@ -31,8 +29,8 @@ pub fn main() { let x_ptr = x as *const AtomicU32 as *const u32; let x_split = split_u32_ptr(x_ptr); unsafe { - let hi = &(*x_split)[0] as *const u16; - std::intrinsics::atomic_load_relaxed(hi); //~ ERROR: imperfectly overlapping + let hi = x_split as *const u16 as *const AtomicU16; + (*hi).load(Relaxed); //~ ERROR: imperfectly overlapping } }); diff --git a/tests/fail/weak_memory/racing_mixed_size_read.stderr b/tests/fail/weak_memory/racing_mixed_size_read.stderr index 9988f4a86d42..8dbf9e6948bd 100644 --- a/tests/fail/weak_memory/racing_mixed_size_read.stderr +++ b/tests/fail/weak_memory/racing_mixed_size_read.stderr @@ -1,8 +1,8 @@ error: unsupported operation: racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation --> $DIR/racing_mixed_size_read.rs:LL:CC | -LL | std::intrinsics::atomic_load_relaxed(hi); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation +LL | (*hi).load(Relaxed); + | ^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support = note: backtrace: diff --git a/tests/pass/weak_memory/extra_cpp.rs b/tests/pass/weak_memory/extra_cpp.rs index 52c13cbdced3..d98fba26ffa8 100644 --- a/tests/pass/weak_memory/extra_cpp.rs +++ b/tests/pass/weak_memory/extra_cpp.rs @@ -5,7 +5,6 @@ // but doable in safe (at least sound) Rust. #![feature(atomic_from_mut)] -#![feature(core_intrinsics)] use std::sync::atomic::Ordering::*; use std::sync::atomic::{AtomicU16, AtomicU32}; diff --git a/tests/pass/weak_memory/extra_cpp_unsafe.rs b/tests/pass/weak_memory/extra_cpp_unsafe.rs index 1c6c370ced3b..f5c6021a4a85 100644 --- a/tests/pass/weak_memory/extra_cpp_unsafe.rs +++ b/tests/pass/weak_memory/extra_cpp_unsafe.rs @@ -7,7 +7,6 @@ // memory model in the future. #![feature(atomic_from_mut)] -#![feature(core_intrinsics)] use std::sync::atomic::AtomicU32; use std::sync::atomic::Ordering::*; @@ -27,7 +26,7 @@ fn racing_mixed_atomicity_read() { let j2 = spawn(move || { let x_ptr = x as *const AtomicU32 as *const u32; - unsafe { std::intrinsics::atomic_load_relaxed(x_ptr) } + unsafe { x_ptr.read() } }); let r1 = j1.join().unwrap(); From d905901d65a2725992fba6a634147b3ddaafaa1d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 Jul 2022 10:06:49 -0400 Subject: [PATCH 3618/5092] make miri a better RUSTC by default inside cargo-miri this requires a change in sysroot handling: miri driver now requires MIRI_SYSROOT to be set when it is in 'target' mode, rather than relying on `--sysroot` always being present. --- README.md | 5 +-- cargo-miri/bin.rs | 87 +++++++++++++++++++++----------------- miri | 8 +++- src/bin/miri.rs | 58 +++++++++++++++---------- test-cargo-miri/Cargo.lock | 7 +++ test-cargo-miri/Cargo.toml | 3 ++ test-cargo-miri/build.rs | 5 +++ tests/compiletest.rs | 4 -- 8 files changed, 107 insertions(+), 70 deletions(-) diff --git a/README.md b/README.md index fa235a45f509..1ab081bfe235 100644 --- a/README.md +++ b/README.md @@ -409,10 +409,9 @@ Moreover, Miri recognizes some environment variables: checkout. Note that changing files in that directory does not automatically trigger a re-build of the standard library; you have to clear the Miri build cache manually (on Linux, `rm -rf ~/.cache/miri`). -* `MIRI_SYSROOT` (recognized by `cargo miri` and the test suite) indicates the +* `MIRI_SYSROOT` (recognized by `cargo miri` and the Miri driver) indicates the sysroot to use. Only set this if you do not want to use the automatically - created sysroot. (The `miri` driver sysroot is controlled via the `--sysroot` - flag instead.) + created sysroot. * `MIRI_TEST_TARGET` (recognized by the test suite and the `./miri` script) indicates which target architecture to test against. `miri` and `cargo miri` accept the `--target` flag for the same purpose. diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 216584ac9b02..7bfd99a7f1ed 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -205,12 +205,6 @@ fn forward_patched_extern_arg(args: &mut impl Iterator, cmd: &mut } } -fn forward_miri_sysroot(cmd: &mut Command) { - let sysroot = env::var_os("MIRI_SYSROOT").expect("the wrapper should have set MIRI_SYSROOT"); - cmd.arg("--sysroot"); - cmd.arg(sysroot); -} - /// Escapes `s` in a way that is suitable for using it as a string literal in TOML syntax. fn escape_for_toml(s: &str) -> String { // We want to surround this string in quotes `"`. So we first escape all quotes, @@ -237,8 +231,15 @@ fn miri() -> Command { Command::new(find_miri()) } +fn miri_for_host() -> Command { + let mut cmd = miri(); + cmd.env("MIRI_BE_RUSTC", "host"); + cmd +} + fn version_info() -> VersionMeta { - VersionMeta::for_command(miri()).expect("failed to determine underlying rustc version of Miri") + VersionMeta::for_command(miri_for_host()) + .expect("failed to determine underlying rustc version of Miri") } fn cargo() -> Command { @@ -336,7 +337,7 @@ fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { a => show_error(format!("invalid answer `{}`", a)), }; } else { - println!("Running `{:?}` to {}.", cmd, text); + eprintln!("Running `{:?}` to {}.", cmd, text); } if cmd.status().unwrap_or_else(|_| panic!("failed to execute {:?}", cmd)).success().not() { @@ -364,7 +365,7 @@ fn write_to_file(filename: &Path, content: &str) { /// Performs the setup required to make `cargo miri` work: Getting a custom-built libstd. Then sets /// `MIRI_SYSROOT`. Skipped if `MIRI_SYSROOT` is already set, in which case we expect the user has /// done all this already. -fn setup(subcommand: &MiriCommand) { +fn setup(subcommand: &MiriCommand, host: &str, target: &str) { let only_setup = matches!(subcommand, MiriCommand::Setup); let ask_user = !only_setup; let print_sysroot = only_setup && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path @@ -398,8 +399,10 @@ fn setup(subcommand: &MiriCommand) { } None => { // Check for `rust-src` rustup component. - let output = - miri().args(&["--print", "sysroot"]).output().expect("failed to determine sysroot"); + let output = miri_for_host() + .args(&["--print", "sysroot"]) + .output() + .expect("failed to determine sysroot"); if !output.status.success() { show_error(format!( "Failed to determine sysroot; Miri said:\n{}", @@ -472,18 +475,21 @@ path = "lib.rs" ); write_to_file(&dir.join("lib.rs"), "#![no_std]"); - // Determine architectures. - // We always need to set a target so rustc bootstrap can tell apart host from target crates. - let host = version_info().host; - let target = get_arg_flag_value("--target"); - let target = target.as_ref().unwrap_or(&host); + // Figure out where xargo will build its stuff. + // Unfortunately, it puts things into a different directory when the + // architecture matches the host. + let sysroot = if target == host { dir.join("HOST") } else { PathBuf::from(dir) }; + // Make sure all target-level Miri invocations know their sysroot. + std::env::set_var("MIRI_SYSROOT", &sysroot); + // Now invoke xargo. let mut command = xargo_check(); command.arg("check").arg("-q"); - command.arg("--target").arg(target); command.current_dir(&dir); command.env("XARGO_HOME", &dir); command.env("XARGO_RUST_SRC", &rust_src); + // We always need to set a target so rustc bootstrap can tell apart host from target crates. + command.arg("--target").arg(target); // Use Miri as rustc to build a libstd compatible with us (and use the right flags). // However, when we are running in bootstrap, we cannot just overwrite `RUSTC`, // because we still need bootstrap to distinguish between host and target crates. @@ -523,6 +529,7 @@ path = "lib.rs" command.stdout(process::Stdio::null()); command.stderr(process::Stdio::null()); } + // Finally run it! if command.status().expect("failed to run xargo").success().not() { if only_setup { @@ -534,11 +541,6 @@ path = "lib.rs" } } - // That should be it! But we need to figure out where xargo built stuff. - // Unfortunately, it puts things into a different directory when the - // architecture matches the host. - let sysroot = if target == &host { dir.join("HOST") } else { PathBuf::from(dir) }; - std::env::set_var("MIRI_SYSROOT", &sysroot); // pass the env var to the processes we spawn, which will turn it into "--sysroot" flags // Figure out what to print. if only_setup { eprintln!("A sysroot for Miri is now available in `{}`.", sysroot.display()); @@ -677,8 +679,13 @@ fn phase_cargo_miri(mut args: impl Iterator) { }; let verbose = num_arg_flag("-v"); + // Determine the involved architectures. + let host = version_info().host; + let target = get_arg_flag_value("--target"); + let target = target.as_ref().unwrap_or(&host); + // We always setup. - setup(&subcommand); + setup(&subcommand, &host, target); // Invoke actual cargo for the job, but with different flags. // We re-use `cargo test` and `cargo run`, which makes target and binary handling very easy but @@ -727,7 +734,7 @@ fn phase_cargo_miri(mut args: impl Iterator) { if get_arg_flag_value("--target").is_none() { // No target given. Explicitly pick the host. cmd.arg("--target"); - cmd.arg(version_info().host); + cmd.arg(&host); } // Set ourselves as runner for al binaries invoked by cargo. @@ -754,16 +761,19 @@ fn phase_cargo_miri(mut args: impl Iterator) { "WARNING: Ignoring `RUSTC` environment variable; set `MIRI` if you want to control the binary used as the driver." ); } - // We'd prefer to just clear this env var, but cargo does not always honor `RUSTC_WRAPPER` - // (https://github.com/rust-lang/cargo/issues/10885). There is no good way to single out these invocations; - // some build scripts use the RUSTC env var as well. So we set it directly to the `miri` driver and - // hope that all they do is ask for the version number -- things could quickly go downhill from here. + // Build scripts (and also cargo: https://github.com/rust-lang/cargo/issues/10885) will invoke `rustc` even when `RUSTC_WRAPPER` is set. + // To make sure everything is coherent, we want that to be the Miri driver, but acting as rustc, on the target level. + // (Target, rather than host, is needed for cross-interpretation situations.) This is not a + // perfect emulation of real rustc (it might be unable to produce binaries since the sysroot is + // check-only), but it's as close as we can get, and it's good enough for autocfg. + // // In `main`, we need the value of `RUSTC` to distinguish RUSTC_WRAPPER invocations from rustdoc // or TARGET_RUNNER invocations, so we canonicalize it here to make it exceedingly unlikely that // there would be a collision with other invocations of cargo-miri (as rustdoc or as runner). // We explicitly do this even if RUSTC_STAGE is set, since for these builds we do *not* want the // bootstrap `rustc` thing in our way! Instead, we have MIRI_HOST_SYSROOT to use for host builds. cmd.env("RUSTC", &fs::canonicalize(find_miri()).unwrap()); + cmd.env("MIRI_BE_RUSTC", "target"); // we better remember to *unset* this in the other phases! // Set rustdoc to us as well, so we can run doctests. cmd.env("RUSTDOC", &cargo_miri_path); @@ -832,6 +842,11 @@ fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { } } + // phase_cargo_miri set `MIRI_BE_RUSTC` for when build scripts directly invoke the driver; + // however, if we get called back by cargo here, we'll carefully compute the right flags + // ourselves, so we first un-do what the earlier phase did. + env::remove_var("MIRI_BE_RUSTC"); + let verbose = std::env::var("MIRI_VERBOSE") .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); let target_crate = is_target_crate(); @@ -946,11 +961,6 @@ fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { } } - // Use our custom sysroot (but not if that is what we are currently building). - if phase != RustcPhase::Setup { - forward_miri_sysroot(&mut cmd); - } - // During setup, patch the panic runtime for `libpanic_abort` (mirroring what bootstrap usually does). if phase == RustcPhase::Setup && get_arg_flag_value("--crate-name").as_deref() == Some("panic_abort") @@ -1010,6 +1020,11 @@ enum RunnerPhase { } fn phase_runner(mut binary_args: impl Iterator, phase: RunnerPhase) { + // phase_cargo_miri set `MIRI_BE_RUSTC` for when build scripts directly invoke the driver; + // however, if we get called back by cargo here, we'll carefully compute the right flags + // ourselves, so we first un-do what the earlier phase did. + env::remove_var("MIRI_BE_RUSTC"); + let verbose = std::env::var("MIRI_VERBOSE") .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); @@ -1077,10 +1092,6 @@ fn phase_runner(mut binary_args: impl Iterator, phase: RunnerPhas cmd.arg(arg); } } - // Set sysroot (if we are inside rustdoc, we already did that in `phase_cargo_rustdoc`). - if phase != RunnerPhase::Rustdoc { - forward_miri_sysroot(&mut cmd); - } // Respect `MIRIFLAGS`. if let Ok(a) = env::var("MIRIFLAGS") { // This code is taken from `RUSTFLAGS` handling in cargo. @@ -1151,7 +1162,7 @@ fn phase_rustdoc(mut args: impl Iterator) { cmd.arg("-Z").arg("unstable-options"); // rustdoc needs to know the right sysroot. - forward_miri_sysroot(&mut cmd); + cmd.arg("--sysroot").arg(env::var_os("MIRI_SYSROOT").unwrap()); // make sure the 'miri' flag is set for rustdoc cmd.arg("--cfg").arg("miri"); diff --git a/miri b/miri index 8bef9d1291a9..956b8cca75b8 100755 --- a/miri +++ b/miri @@ -131,7 +131,11 @@ export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR $RUSTFLAGS" # Build a sysroot and set MIRI_SYSROOT to use it. Arguments are passed to `cargo miri setup`. build_sysroot() { - export MIRI_SYSROOT="$($CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -q -- miri setup --print-sysroot "$@")" + if ! MIRI_SYSROOT="$($CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -q -- miri setup --print-sysroot "$@")"; then + echo "'cargo miri setup' failed" + exit 1 + fi + export MIRI_SYSROOT } # Prepare and set MIRI_SYSROOT. Respects `MIRI_TEST_TARGET` and takes into account @@ -201,7 +205,7 @@ run) $CARGO build $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml find_sysroot # Then run the actual command. - exec $CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml -- --sysroot "$MIRI_SYSROOT" $MIRIFLAGS "$@" + exec $CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml -- $MIRIFLAGS "$@" ;; fmt) find "$MIRIDIR" -not \( -name target -prune \) -name '*.rs' \ diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 14694ac7b053..489eb959906c 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -27,7 +27,7 @@ use rustc_middle::{ }, ty::{query::ExternProviders, TyCtxt}, }; -use rustc_session::{search_paths::PathKind, CtfeBacktrace}; +use rustc_session::{config::CrateType, search_paths::PathKind, CtfeBacktrace}; use miri::{BacktraceStyle, ProvenanceMode}; @@ -60,6 +60,10 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { init_late_loggers(tcx); + if !tcx.sess.crate_types().contains(&CrateType::Executable) { + tcx.sess.fatal("miri only makes sense on bin crates"); + } + let (entry_def_id, entry_type) = if let Some(entry_def) = tcx.entry_fn(()) { entry_def } else { @@ -204,9 +208,9 @@ fn init_late_loggers(tcx: TyCtxt<'_>) { } } -/// Returns the "default sysroot" that Miri will use if no `--sysroot` flag is set. +/// Returns the "default sysroot" that Miri will use for host things if no `--sysroot` flag is set. /// Should be a compile-time constant. -fn compile_time_sysroot() -> Option { +fn host_sysroot() -> Option { if option_env!("RUSTC_STAGE").is_some() { // This is being built as part of rustc, and gets shipped with rustup. // We can rely on the sysroot computation in librustc_session. @@ -227,7 +231,7 @@ fn compile_time_sysroot() -> Option { if toolchain_runtime != toolchain { show_error(format!( "This Miri got built with local toolchain `{toolchain}`, but now is being run under a different toolchain. \n\ - Make sure to run Miri in the toolchain it got built with, e.g. via `cargo +{toolchain} miri`." + Make sure to run Miri in the toolchain it got built with, e.g. via `cargo +{toolchain} miri`." )); } } @@ -246,25 +250,42 @@ fn compile_time_sysroot() -> Option { /// Execute a compiler with the given CLI arguments and callbacks. fn run_compiler( mut args: Vec, + target_crate: bool, callbacks: &mut (dyn rustc_driver::Callbacks + Send), - insert_default_args: bool, ) -> ! { // Make sure we use the right default sysroot. The default sysroot is wrong, // because `get_or_default_sysroot` in `librustc_session` bases that on `current_exe`. // - // Make sure we always call `compile_time_sysroot` as that also does some sanity-checks - // of the environment we were built in. - // FIXME: Ideally we'd turn a bad build env into a compile-time error via CTFE or so. - if let Some(sysroot) = compile_time_sysroot() { - let sysroot_flag = "--sysroot"; - if !args.iter().any(|e| e == sysroot_flag) { + // Make sure we always call `host_sysroot` as that also does some sanity-checks + // of the environment we were built in and whether it matches what we are running in. + let host_default_sysroot = host_sysroot(); + // Now see if we even need to set something. + let sysroot_flag = "--sysroot"; + if !args.iter().any(|e| e == sysroot_flag) { + // No sysroot was set, let's see if we have a custom default we want to configure. + let default_sysroot = if target_crate { + // Using the built-in default here would be plain wrong, so we *require* + // the env var to make sure things make sense. + Some(env::var("MIRI_SYSROOT").unwrap_or_else(|_| { + show_error(format!( + "Miri was invoked in 'target' mode without `MIRI_SYSROOT` or `--sysroot` being set" + )) + })) + } else { + host_default_sysroot + }; + if let Some(sysroot) = default_sysroot { // We need to overwrite the default that librustc_session would compute. args.push(sysroot_flag.to_owned()); args.push(sysroot); } } - if insert_default_args { + // Don't insert `MIRI_DEFAULT_ARGS`, in particular, `--cfg=miri`, if we are building + // a "host" crate. That may cause procedural macros (and probably build scripts) to + // depend on Miri-only symbols, such as `miri_resolve_frame`: + // https://github.com/rust-lang/miri/issues/1760 + if target_crate { // Some options have different defaults in Miri than in plain rustc; apply those by making // them the first arguments after the binary name (but later arguments can overwrite them). args.splice(1..1, miri::MIRI_DEFAULT_ARGS.iter().map(ToString::to_string)); @@ -302,13 +323,8 @@ fn main() { // We cannot use `rustc_driver::main` as we need to adjust the CLI arguments. run_compiler( env::args().collect(), + target_crate, &mut MiriBeRustCompilerCalls { target_crate }, - // Don't insert `MIRI_DEFAULT_ARGS`, in particular, `--cfg=miri`, if we are building - // a "host" crate. That may cause procedural macros (and probably build scripts) to - // depend on Miri-only symbols, such as `miri_resolve_frame`: - // https://github.com/rust-lang/miri/issues/1760 - #[rustfmt::skip] - /* insert_default_args: */ target_crate, ) } @@ -502,9 +518,5 @@ fn main() { debug!("rustc arguments: {:?}", rustc_args); debug!("crate arguments: {:?}", miri_config.args); - run_compiler( - rustc_args, - &mut MiriCompilerCalls { miri_config }, - /* insert_default_args: */ true, - ) + run_compiler(rustc_args, /* target_crate: */ true, &mut MiriCompilerCalls { miri_config }) } diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 38bfb2ac6207..a297dd27dbc9 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + [[package]] name = "byteorder" version = "0.5.3" @@ -18,6 +24,7 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" name = "cargo-miri-test" version = "0.1.0" dependencies = [ + "autocfg", "byteorder 0.5.3", "byteorder 1.4.3", "cdylib", diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 51967c54e15c..5d9e5d143b3b 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -21,6 +21,9 @@ issue_rust_86261 = { path = "issue-rust-86261" } byteorder_2 = { package = "byteorder", version = "0.5" } # to test dev-dependencies behave as expected, with renaming serde_derive = "1.0" # not actually used, but exercises some unique code path (`--extern` .so file) +[build-dependencies] +autocfg = "1" + [lib] test = false # test that this is respected (will show in the output) diff --git a/test-cargo-miri/build.rs b/test-cargo-miri/build.rs index 8b1e3af6231a..5a01aab12300 100644 --- a/test-cargo-miri/build.rs +++ b/test-cargo-miri/build.rs @@ -20,4 +20,9 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-env-changed=MIRITESTVAR"); println!("cargo:rustc-env=MIRITESTVAR=testval"); + + // Test that autocfg works. This invokes RUSTC. + let a = autocfg::new(); + assert!(a.probe_sysroot_crate("std")); + assert!(!a.probe_sysroot_crate("doesnotexist")); } diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 0f0179de5d24..48e0ae855be3 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -24,10 +24,6 @@ fn run_tests(mode: Mode, path: &str, target: Option) -> Result<()> { flags.push("-Dwarnings".into()); flags.push("-Dunused".into()); } - if let Some(sysroot) = env::var_os("MIRI_SYSROOT") { - flags.push("--sysroot".into()); - flags.push(sysroot); - } if let Ok(extra_flags) = env::var("MIRIFLAGS") { for flag in extra_flags.split_whitespace() { flags.push(flag.into()); From 0b1d5a495718027ed28d20491223adc16f29cfc5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 Jul 2022 10:17:33 -0400 Subject: [PATCH 3619/5092] test all of the autocfg queries --- README.md | 6 +++--- test-cargo-miri/build.rs | 12 ++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1ab081bfe235..5fbf89c86b96 100644 --- a/README.md +++ b/README.md @@ -409,9 +409,9 @@ Moreover, Miri recognizes some environment variables: checkout. Note that changing files in that directory does not automatically trigger a re-build of the standard library; you have to clear the Miri build cache manually (on Linux, `rm -rf ~/.cache/miri`). -* `MIRI_SYSROOT` (recognized by `cargo miri` and the Miri driver) indicates the - sysroot to use. Only set this if you do not want to use the automatically - created sysroot. +* `MIRI_SYSROOT` (recognized by `cargo miri` and the Miri driver) indicates the sysroot to use. When + using `cargo miri`, only set this if you do not want to use the automatically created sysroot. For + directly invoking the Miri driver, this variable (or a `--sysroot` flag) is mandatory. * `MIRI_TEST_TARGET` (recognized by the test suite and the `./miri` script) indicates which target architecture to test against. `miri` and `cargo miri` accept the `--target` flag for the same purpose. diff --git a/test-cargo-miri/build.rs b/test-cargo-miri/build.rs index 5a01aab12300..6c1f4d80d339 100644 --- a/test-cargo-miri/build.rs +++ b/test-cargo-miri/build.rs @@ -25,4 +25,16 @@ fn main() { let a = autocfg::new(); assert!(a.probe_sysroot_crate("std")); assert!(!a.probe_sysroot_crate("doesnotexist")); + assert!(a.probe_rustc_version(1, 0)); + assert!(!a.probe_rustc_version(2, 0)); + assert!(a.probe_type("i128")); + assert!(!a.probe_type("doesnotexist")); + assert!(a.probe_trait("Send")); + assert!(!a.probe_trait("doesnotexist")); + assert!(a.probe_path("std::num")); + assert!(!a.probe_path("doesnotexist")); + assert!(a.probe_constant("i32::MAX")); + assert!(!a.probe_constant("doesnotexist")); + assert!(a.probe_expression("Box::new(0)")); + assert!(!a.probe_expression("doesnotexist")); } From 9406b6da68762ec26d9e60b03b38722fee6395ef Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 Jul 2022 13:58:14 -0400 Subject: [PATCH 3620/5092] fmt --- cargo-miri/bin.rs | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 7bfd99a7f1ed..8aeeb044d3c1 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -761,17 +761,19 @@ fn phase_cargo_miri(mut args: impl Iterator) { "WARNING: Ignoring `RUSTC` environment variable; set `MIRI` if you want to control the binary used as the driver." ); } - // Build scripts (and also cargo: https://github.com/rust-lang/cargo/issues/10885) will invoke `rustc` even when `RUSTC_WRAPPER` is set. - // To make sure everything is coherent, we want that to be the Miri driver, but acting as rustc, on the target level. - // (Target, rather than host, is needed for cross-interpretation situations.) This is not a - // perfect emulation of real rustc (it might be unable to produce binaries since the sysroot is - // check-only), but it's as close as we can get, and it's good enough for autocfg. + // Build scripts (and also cargo: https://github.com/rust-lang/cargo/issues/10885) will invoke + // `rustc` even when `RUSTC_WRAPPER` is set. To make sure everything is coherent, we want that + // to be the Miri driver, but acting as rustc, on the target level. (Target, rather than host, + // is needed for cross-interpretation situations.) This is not a perfect emulation of real rustc + // (it might be unable to produce binaries since the sysroot is check-only), but it's as close + // as we can get, and it's good enough for autocfg. // // In `main`, we need the value of `RUSTC` to distinguish RUSTC_WRAPPER invocations from rustdoc // or TARGET_RUNNER invocations, so we canonicalize it here to make it exceedingly unlikely that - // there would be a collision with other invocations of cargo-miri (as rustdoc or as runner). - // We explicitly do this even if RUSTC_STAGE is set, since for these builds we do *not* want the - // bootstrap `rustc` thing in our way! Instead, we have MIRI_HOST_SYSROOT to use for host builds. + // there would be a collision with other invocations of cargo-miri (as rustdoc or as runner). We + // explicitly do this even if RUSTC_STAGE is set, since for these builds we do *not* want the + // bootstrap `rustc` thing in our way! Instead, we have MIRI_HOST_SYSROOT to use for host + // builds. cmd.env("RUSTC", &fs::canonicalize(find_miri()).unwrap()); cmd.env("MIRI_BE_RUSTC", "target"); // we better remember to *unset* this in the other phases! @@ -850,7 +852,8 @@ fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { let verbose = std::env::var("MIRI_VERBOSE") .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); let target_crate = is_target_crate(); - let print = get_arg_flag_value("--print").is_some() || has_arg_flag("-vV"); // whether this is cargo/xargo invoking rustc to get some infos + // Determine whether this is cargo/xargo invoking rustc to get some infos. + let info_query = get_arg_flag_value("--print").is_some() || has_arg_flag("-vV"); let store_json = |info: CrateRunInfo| { // Create a stub .d file to stop Cargo from "rebuilding" the crate: @@ -872,7 +875,7 @@ fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { info.store(&out_filename("", ".exe")); }; - let runnable_crate = !print && is_runnable_crate(); + let runnable_crate = !info_query && is_runnable_crate(); if runnable_crate && target_crate { assert!( @@ -934,7 +937,7 @@ fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { let mut emit_link_hack = false; // Arguments are treated very differently depending on whether this crate is // for interpretation by Miri, or for use by a build script / proc macro. - if !print && target_crate { + if !info_query && target_crate { // Forward arguments, but remove "link" from "--emit" to make this a check-only build. let emit_flag = "--emit"; while let Some(arg) = args.next() { @@ -968,8 +971,9 @@ fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { cmd.arg("-C").arg("panic=abort"); } } else { - // For host crates (but not when we are printing), we might still have to set the sysroot. - if !print { + // For host crates (but not when we are just printing some info), + // we might still have to set the sysroot. + if !info_query { // When we're running `cargo-miri` from `x.py` we need to pass the sysroot explicitly // due to bootstrap complications. if let Some(sysroot) = std::env::var_os("MIRI_HOST_SYSROOT") { @@ -990,7 +994,7 @@ fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { // Run it. if verbose > 0 { eprintln!( - "[cargo-miri rustc] target_crate={target_crate} runnable_crate={runnable_crate} print={print}" + "[cargo-miri rustc] target_crate={target_crate} runnable_crate={runnable_crate} info_query={info_query}" ); } debug_cmd("[cargo-miri rustc]", verbose, &cmd); @@ -1030,7 +1034,9 @@ fn phase_runner(mut binary_args: impl Iterator, phase: RunnerPhas let binary = binary_args.next().unwrap(); let file = File::open(&binary) - .unwrap_or_else(|_| show_error(format!("file {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary))); + .unwrap_or_else(|_| show_error(format!( + "file {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary + ))); let file = BufReader::new(file); let info = serde_json::from_reader(file).unwrap_or_else(|_| { From 8f3b594d1ee94e5e908ea6a775560f3c7ab695e7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 Jul 2022 15:23:39 -0400 Subject: [PATCH 3621/5092] more tests for ptr_offset_from_unsinged --- .../ptr_offset_from_unsigned_neg.rs | 9 +++++++++ .../ptr_offset_from_unsigned_neg.stderr | 20 +++++++++++++++++++ tests/pass/intrinsics.rs | 9 ++------- tests/pass/pointers.rs | 9 ++++++++- tests/pass/ptr_offset.rs | 18 +++++++++++++++++ 5 files changed, 57 insertions(+), 8 deletions(-) create mode 100644 tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs create mode 100644 tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr diff --git a/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs b/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs new file mode 100644 index 000000000000..d6413faf74bf --- /dev/null +++ b/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs @@ -0,0 +1,9 @@ +//@error-pattern: first pointer has smaller offset than second: 0 < 4 +#![feature(ptr_sub_ptr)] + +fn main() { + let arr = [0u8; 8]; + let ptr1 = arr.as_ptr(); + let ptr2 = ptr1.wrapping_add(4); + let _val = unsafe { ptr1.sub_ptr(ptr2) }; +} diff --git a/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr b/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr new file mode 100644 index 000000000000..bb68f9f5c18c --- /dev/null +++ b/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: ptr_offset_from_unsigned called when first pointer has smaller offset than second: 0 < 4 + --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC + | +LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ptr_offset_from_unsigned called when first pointer has smaller offset than second: 0 < 4 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: backtrace: + = note: inside `std::ptr::const_ptr::::sub_ptr` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC +note: inside `main` at $DIR/ptr_offset_from_unsigned_neg.rs:LL:CC + --> $DIR/ptr_offset_from_unsigned_neg.rs:LL:CC + | +LL | let _val = unsafe { ptr1.sub_ptr(ptr2) }; + | ^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/pass/intrinsics.rs b/tests/pass/intrinsics.rs index 756744badaf9..6267e6e6bc11 100644 --- a/tests/pass/intrinsics.rs +++ b/tests/pass/intrinsics.rs @@ -1,6 +1,6 @@ //@compile-flags: -Zmiri-permissive-provenance -#![feature(core_intrinsics, const_raw_ptr_comparison)] -#![feature(layout_for_ptr)] +#![feature(core_intrinsics, layout_for_ptr)] +//! Tests for various intrinsics that do not fit anywhere else. use std::intrinsics; use std::mem::{size_of, size_of_val, size_of_val_raw}; @@ -39,9 +39,4 @@ fn main() { let _v = intrinsics::discriminant_value(&0); let _v = intrinsics::discriminant_value(&true); let _v = intrinsics::discriminant_value(&vec![1, 2, 3]); - - let addr = &13 as *const i32; - let addr2 = (addr as usize).wrapping_add(usize::MAX).wrapping_add(1); - assert!(addr.guaranteed_eq(addr2 as *const _)); - assert!(addr.guaranteed_ne(0x100 as *const _)); } diff --git a/tests/pass/pointers.rs b/tests/pass/pointers.rs index a271e764d9f4..b2e6f4556fa2 100644 --- a/tests/pass/pointers.rs +++ b/tests/pass/pointers.rs @@ -1,4 +1,5 @@ -#![feature(ptr_metadata)] +//@compile-flags: -Zmiri-permissive-provenance +#![feature(ptr_metadata, const_raw_ptr_comparison)] use std::mem::{self, transmute}; use std::ptr; @@ -131,6 +132,12 @@ fn main() { assert!(dangling > 3); assert!(dangling >= 4); + // CTFE-specific equality tests, need to also work at runtime. + let addr = &13 as *const i32; + let addr2 = (addr as usize).wrapping_add(usize::MAX).wrapping_add(1); + assert!(addr.guaranteed_eq(addr2 as *const _)); + assert!(addr.guaranteed_ne(0x100 as *const _)); + wide_ptr_ops(); metadata_vtable(); } diff --git a/tests/pass/ptr_offset.rs b/tests/pass/ptr_offset.rs index 5270e8663b2d..95eac8522fb4 100644 --- a/tests/pass/ptr_offset.rs +++ b/tests/pass/ptr_offset.rs @@ -1,7 +1,9 @@ //@compile-flags: -Zmiri-permissive-provenance +#![feature(ptr_sub_ptr)] use std::{mem, ptr}; fn main() { + smoke(); test_offset_from(); test_vec_into_iter(); ptr_arith_offset(); @@ -9,6 +11,20 @@ fn main() { ptr_offset(); } +fn smoke() { + // Smoke-test various offsetting operations. + let ptr = &5; + let ptr = ptr as *const i32; + let _val = ptr.wrapping_offset(0); + let _val = unsafe { ptr.offset(0) }; + let _val = ptr.wrapping_add(0); + let _val = unsafe { ptr.add(0) }; + let _val = ptr.wrapping_sub(0); + let _val = unsafe { ptr.sub(0) }; + let _val = unsafe { ptr.offset_from(ptr) }; + let _val = unsafe { ptr.sub_ptr(ptr) }; +} + fn test_offset_from() { unsafe { let buf = [0u32; 4]; @@ -17,12 +33,14 @@ fn test_offset_from() { let y = x.offset(12); assert_eq!(y.offset_from(x), 12); + assert_eq!(y.sub_ptr(x), 12); assert_eq!(x.offset_from(y), -12); assert_eq!((y as *const u32).offset_from(x as *const u32), 12 / 4); assert_eq!((x as *const u32).offset_from(y as *const u32), -12 / 4); let x = (((x as usize) * 2) / 2) as *const u8; assert_eq!(y.offset_from(x), 12); + assert_eq!(y.sub_ptr(x), 12); assert_eq!(x.offset_from(y), -12); } } From cbff63a6944b3285a9525881dc85870e694fb055 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 Jul 2022 17:51:29 -0400 Subject: [PATCH 3622/5092] rustup --- rust-version | 2 +- src/machine.rs | 13 ------------- src/operator.rs | 4 ++-- src/shims/intrinsics/simd.rs | 2 +- src/shims/panic.rs | 7 +++---- src/shims/tls.rs | 13 ++++--------- src/shims/unix/linux/sync.rs | 2 +- 7 files changed, 12 insertions(+), 31 deletions(-) diff --git a/rust-version b/rust-version index c710735735c7..b70ab6fdd46e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -35a061724802377a21fc6dac1ebcbb9b8d1f558a +7fe022f5aa32bbbb33c3a58755729d6667a461a9 diff --git a/src/machine.rs b/src/machine.rs index 3e45f77d54c3..2c9bfe803ad2 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -545,11 +545,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { true } - #[inline(always)] - fn enforce_number_no_provenance(_ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { - true - } - #[inline(always)] fn enforce_abi(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { ecx.machine.enforce_abi @@ -753,14 +748,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { intptrcast::GlobalStateInner::ptr_from_addr_cast(ecx, addr) } - #[inline(always)] - fn ptr_from_addr_transmute( - ecx: &MiriEvalContext<'mir, 'tcx>, - addr: u64, - ) -> Pointer> { - intptrcast::GlobalStateInner::ptr_from_addr_transmute(ecx, addr) - } - fn expose_ptr( ecx: &mut InterpCx<'mir, 'tcx, Self>, ptr: Pointer, diff --git a/src/operator.rs b/src/operator.rs index 758e747d2786..679686b4005e 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -57,7 +57,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { Offset => { assert!(left.layout.ty.is_unsafe_ptr()); - let ptr = self.scalar_to_ptr(left.to_scalar()?)?; + let ptr = left.to_scalar()?.to_pointer(self)?; let offset = right.to_scalar()?.to_machine_isize(self)?; let pointee_ty = @@ -71,7 +71,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { Add | Sub | BitOr | BitAnd | BitXor => { assert!(left.layout.ty.is_unsafe_ptr()); assert!(right.layout.ty.is_unsafe_ptr()); - let ptr = self.scalar_to_ptr(left.to_scalar()?)?; + let ptr = left.to_scalar()?.to_pointer(self)?; // We do the actual operation with usize-typed scalars. let left = ImmTy::from_uint(ptr.addr().bytes(), self.machine.layouts.usize); let right = ImmTy::from_uint( diff --git a/src/shims/intrinsics/simd.rs b/src/shims/intrinsics/simd.rs index 96e97d79358b..d467c3c509f5 100644 --- a/src/shims/intrinsics/simd.rs +++ b/src/shims/intrinsics/simd.rs @@ -201,7 +201,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.saturating_arith(mir_op, &left, &right)? } Op::WrappingOffset => { - let ptr = this.scalar_to_ptr(left.to_scalar()?)?; + let ptr = left.to_scalar()?.to_pointer(this)?; let offset_count = right.to_scalar()?.to_machine_isize(this)?; let pointee_ty = left.layout.ty.builtin_deref(true).unwrap().ty; diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 362b929eabfe..687c84308a97 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -26,7 +26,7 @@ use helpers::check_arg_count; #[derive(Debug)] pub struct CatchUnwindData<'tcx> { /// The `catch_fn` callback to call in case of a panic. - catch_fn: Scalar, + catch_fn: Pointer>, /// The `data` argument for that callback. data: Scalar, /// The return place from the original call to `try`. @@ -86,7 +86,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [try_fn, data, catch_fn] = check_arg_count(args)?; let try_fn = this.read_pointer(try_fn)?; let data = this.read_scalar(data)?.check_init()?; - let catch_fn = this.read_scalar(catch_fn)?.check_init()?; + let catch_fn = this.read_pointer(catch_fn)?; // Now we make a function call, and pass `data` as first and only argument. let f_instance = this.get_ptr_fn(try_fn)?.as_instance()?; @@ -140,8 +140,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let payload = this.active_thread_mut().panic_payload.take().unwrap(); // Push the `catch_fn` stackframe. - let f_instance = - this.get_ptr_fn(this.scalar_to_ptr(catch_unwind.catch_fn)?)?.as_instance()?; + let f_instance = this.get_ptr_fn(catch_unwind.catch_fn)?.as_instance()?; trace!("catch_fn: {:?}", f_instance); this.call_function( f_instance, diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 13af447f76c6..2f0fb41b9e92 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -241,15 +241,10 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'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. - let thread_callback = this.eval_path_scalar(&[ - "std", - "sys", - "windows", - "thread_local_key", - "p_thread_callback", - ])?; - let thread_callback = - this.get_ptr_fn(this.scalar_to_ptr(thread_callback)?)?.as_instance()?; + let thread_callback = this + .eval_path_scalar(&["std", "sys", "windows", "thread_local_key", "p_thread_callback"])? + .to_pointer(this)?; + let thread_callback = this.get_ptr_fn(thread_callback)?.as_instance()?; // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. let reason = this.eval_path_scalar(&["std", "sys", "windows", "c", "DLL_THREAD_DETACH"])?; diff --git a/src/shims/unix/linux/sync.rs b/src/shims/unix/linux/sync.rs index a11aa8ed849c..59de10498745 100644 --- a/src/shims/unix/linux/sync.rs +++ b/src/shims/unix/linux/sync.rs @@ -121,7 +121,7 @@ pub fn futex<'tcx>( // The API requires `addr` to be a 4-byte aligned pointer, and will // use the 4 bytes at the given address as an (atomic) i32. this.check_ptr_access_align( - this.scalar_to_ptr(addr_scalar)?, + addr_scalar.to_pointer(this)?, Size::from_bytes(4), Align::from_bytes(4).unwrap(), CheckInAllocMsg::MemoryAccessTest, From b514667c36f559317a316a5d9b8cd019328be581 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 Jul 2022 14:28:45 -0400 Subject: [PATCH 3623/5092] adjust for more backtrace pruning --- tests/fail/intrinsics/copy_overflow.rs | 2 +- tests/fail/intrinsics/copy_overflow.stderr | 14 ++++---------- tests/fail/intrinsics/out_of_bounds_ptr_1.rs | 3 +-- tests/fail/intrinsics/out_of_bounds_ptr_1.stderr | 13 ++++--------- tests/fail/intrinsics/out_of_bounds_ptr_2.rs | 3 +-- tests/fail/intrinsics/out_of_bounds_ptr_2.stderr | 13 ++++--------- tests/fail/intrinsics/out_of_bounds_ptr_3.rs | 3 +-- tests/fail/intrinsics/out_of_bounds_ptr_3.stderr | 13 ++++--------- tests/fail/intrinsics/overflowing-unchecked-rsh.rs | 6 ++---- .../intrinsics/overflowing-unchecked-rsh.stderr | 4 ++-- tests/fail/intrinsics/ptr_offset_0_plus_0.rs | 3 ++- tests/fail/intrinsics/ptr_offset_0_plus_0.stderr | 13 ++++--------- tests/fail/intrinsics/ptr_offset_from_oob.rs | 6 +----- tests/fail/intrinsics/ptr_offset_from_oob.stderr | 4 ++-- tests/fail/intrinsics/ptr_offset_int_plus_int.rs | 3 +-- .../fail/intrinsics/ptr_offset_int_plus_int.stderr | 13 ++++--------- tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs | 3 +-- .../fail/intrinsics/ptr_offset_int_plus_ptr.stderr | 13 ++++--------- tests/fail/intrinsics/ptr_offset_overflow.rs | 3 +-- tests/fail/intrinsics/ptr_offset_overflow.stderr | 13 ++++--------- tests/fail/intrinsics/ptr_offset_ptr_plus_0.rs | 4 ++-- tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr | 13 ++++--------- tests/fail/intrinsics/unchecked_add1.rs | 7 +++---- tests/fail/intrinsics/unchecked_add1.stderr | 4 ++-- tests/fail/intrinsics/unchecked_add2.rs | 7 +++---- tests/fail/intrinsics/unchecked_add2.stderr | 4 ++-- tests/fail/intrinsics/unchecked_mul1.rs | 6 ++---- tests/fail/intrinsics/unchecked_mul1.stderr | 4 ++-- tests/fail/intrinsics/unchecked_mul2.rs | 6 ++---- tests/fail/intrinsics/unchecked_mul2.stderr | 4 ++-- tests/fail/intrinsics/unchecked_sub1.rs | 6 ++---- tests/fail/intrinsics/unchecked_sub1.stderr | 4 ++-- tests/fail/intrinsics/unchecked_sub2.rs | 6 ++---- tests/fail/intrinsics/unchecked_sub2.stderr | 4 ++-- tests/fail/invalid_enum_tag.rs | 4 +--- tests/fail/invalid_enum_tag.stderr | 13 ++++--------- tests/fail/provenance/ptr_invalid_offset.rs | 3 +-- tests/fail/provenance/ptr_invalid_offset.stderr | 13 ++++--------- tests/fail/should-pass/cpp20_rwc_syncs.rs | 3 +-- tests/fail/should-pass/cpp20_rwc_syncs.stderr | 13 ++++--------- tests/fail/unreachable.rs | 3 +-- tests/fail/unreachable.stderr | 13 ++++--------- tests/fail/weak_memory/racing_mixed_size.rs | 3 ++- 43 files changed, 102 insertions(+), 193 deletions(-) diff --git a/tests/fail/intrinsics/copy_overflow.rs b/tests/fail/intrinsics/copy_overflow.rs index c4ce192c449c..e64a1f909021 100644 --- a/tests/fail/intrinsics/copy_overflow.rs +++ b/tests/fail/intrinsics/copy_overflow.rs @@ -1,4 +1,3 @@ -//@error-pattern: overflow computing total size use std::mem; fn main() { @@ -6,5 +5,6 @@ fn main() { let mut y = 0; unsafe { (&mut y as *mut i32).copy_from(&x, 1usize << (mem::size_of::() * 8 - 1)); + //~^ERROR: overflow computing total size } } diff --git a/tests/fail/intrinsics/copy_overflow.stderr b/tests/fail/intrinsics/copy_overflow.stderr index 76917ae7ea15..3534f4d1fb85 100644 --- a/tests/fail/intrinsics/copy_overflow.stderr +++ b/tests/fail/intrinsics/copy_overflow.stderr @@ -1,19 +1,13 @@ error: Undefined Behavior: overflow computing total size of `copy` - --> RUSTLIB/core/src/intrinsics.rs:LL:CC + --> $DIR/copy_overflow.rs:LL:CC | -LL | copy(src, dst, count) - | ^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy` +LL | (&mut y as *mut i32).copy_from(&x, 1usize << (mem::size_of::() * 8 - 1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::intrinsics::copy::` at RUSTLIB/core/src/intrinsics.rs:LL:CC - = note: inside `std::ptr::mut_ptr::::copy_from` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC -note: inside `main` at $DIR/copy_overflow.rs:LL:CC - --> $DIR/copy_overflow.rs:LL:CC - | -LL | (&mut y as *mut i32).copy_from(&x, 1usize << (mem::size_of::() * 8 - 1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/copy_overflow.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_1.rs b/tests/fail/intrinsics/out_of_bounds_ptr_1.rs index 0109bff69688..b6a110ee84d2 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_1.rs +++ b/tests/fail/intrinsics/out_of_bounds_ptr_1.rs @@ -1,8 +1,7 @@ -//@error-pattern: pointer to 5 bytes starting at offset 0 is out-of-bounds fn main() { let v = [0i8; 4]; let x = &v as *const i8; // The error is inside another function, so we cannot match it by line - let x = unsafe { x.offset(5) }; + let x = unsafe { x.offset(5) }; //~ERROR: pointer to 5 bytes starting at offset 0 is out-of-bounds panic!("this should never print: {:?}", x); } diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr b/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr index 789e9d1f6cbe..afa2c8306466 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr +++ b/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr @@ -1,18 +1,13 @@ error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds - --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC + --> $DIR/out_of_bounds_ptr_1.rs:LL:CC | -LL | unsafe { intrinsics::offset(self, count) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds +LL | let x = unsafe { x.offset(5) }; + | ^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC -note: inside `main` at $DIR/out_of_bounds_ptr_1.rs:LL:CC - --> $DIR/out_of_bounds_ptr_1.rs:LL:CC - | -LL | let x = unsafe { x.offset(5) }; - | ^^^^^^^^^^^ + = note: inside `main` at $DIR/out_of_bounds_ptr_1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_2.rs b/tests/fail/intrinsics/out_of_bounds_ptr_2.rs index 74d391dc2120..0d4eea9a5bde 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_2.rs +++ b/tests/fail/intrinsics/out_of_bounds_ptr_2.rs @@ -1,7 +1,6 @@ -//@error-pattern: overflowing in-bounds pointer arithmetic fn main() { let v = [0i8; 4]; let x = &v as *const i8; - let x = unsafe { x.offset(isize::MIN) }; + let x = unsafe { x.offset(isize::MIN) }; //~ERROR: overflowing in-bounds pointer arithmetic panic!("this should never print: {:?}", x); } diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr b/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr index 70ce2dc02a82..a32b50a18e6a 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr +++ b/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr @@ -1,18 +1,13 @@ error: Undefined Behavior: overflowing in-bounds pointer arithmetic - --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC + --> $DIR/out_of_bounds_ptr_2.rs:LL:CC | -LL | unsafe { intrinsics::offset(self, count) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing in-bounds pointer arithmetic +LL | let x = unsafe { x.offset(isize::MIN) }; + | ^^^^^^^^^^^^^^^^^^^^ overflowing in-bounds pointer arithmetic | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC -note: inside `main` at $DIR/out_of_bounds_ptr_2.rs:LL:CC - --> $DIR/out_of_bounds_ptr_2.rs:LL:CC - | -LL | let x = unsafe { x.offset(isize::MIN) }; - | ^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/out_of_bounds_ptr_2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_3.rs b/tests/fail/intrinsics/out_of_bounds_ptr_3.rs index b54cf3dd25c0..701bc33a645e 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_3.rs +++ b/tests/fail/intrinsics/out_of_bounds_ptr_3.rs @@ -1,7 +1,6 @@ -//@error-pattern: pointer to 1 byte starting at offset -1 is out-of-bounds fn main() { let v = [0i8; 4]; let x = &v as *const i8; - let x = unsafe { x.offset(-1) }; + let x = unsafe { x.offset(-1) }; //~ERROR: pointer to 1 byte starting at offset -1 is out-of-bounds panic!("this should never print: {:?}", x); } diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr b/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr index 973bf043e155..d06c33beb48a 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr +++ b/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr @@ -1,18 +1,13 @@ error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 1 byte starting at offset -1 is out-of-bounds - --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC + --> $DIR/out_of_bounds_ptr_3.rs:LL:CC | -LL | unsafe { intrinsics::offset(self, count) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 1 byte starting at offset -1 is out-of-bounds +LL | let x = unsafe { x.offset(-1) }; + | ^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 1 byte starting at offset -1 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC -note: inside `main` at $DIR/out_of_bounds_ptr_3.rs:LL:CC - --> $DIR/out_of_bounds_ptr_3.rs:LL:CC - | -LL | let x = unsafe { x.offset(-1) }; - | ^^^^^^^^^^^^ + = note: inside `main` at $DIR/out_of_bounds_ptr_3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/overflowing-unchecked-rsh.rs b/tests/fail/intrinsics/overflowing-unchecked-rsh.rs index 958a9f90ed98..fe2e85be6986 100644 --- a/tests/fail/intrinsics/overflowing-unchecked-rsh.rs +++ b/tests/fail/intrinsics/overflowing-unchecked-rsh.rs @@ -1,10 +1,8 @@ -#![feature(core_intrinsics)] - -use std::intrinsics::*; +#![feature(unchecked_math)] fn main() { unsafe { - let _n = unchecked_shr(1i64, 64); + let _n = 1i64.unchecked_shr(64); //~^ ERROR: overflowing shift by 64 in `unchecked_shr` } } diff --git a/tests/fail/intrinsics/overflowing-unchecked-rsh.stderr b/tests/fail/intrinsics/overflowing-unchecked-rsh.stderr index 705ae01188b8..bba92602285a 100644 --- a/tests/fail/intrinsics/overflowing-unchecked-rsh.stderr +++ b/tests/fail/intrinsics/overflowing-unchecked-rsh.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflowing shift by 64 in `unchecked_shr` --> $DIR/overflowing-unchecked-rsh.rs:LL:CC | -LL | let _n = unchecked_shr(1i64, 64); - | ^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 64 in `unchecked_shr` +LL | let _n = 1i64.unchecked_shr(64); + | ^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 64 in `unchecked_shr` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/ptr_offset_0_plus_0.rs b/tests/fail/intrinsics/ptr_offset_0_plus_0.rs index 32974a825a54..e2329c131398 100644 --- a/tests/fail/intrinsics/ptr_offset_0_plus_0.rs +++ b/tests/fail/intrinsics/ptr_offset_0_plus_0.rs @@ -1,8 +1,9 @@ -//@error-pattern: null pointer is a dangling pointer //@compile-flags: -Zmiri-permissive-provenance +#[rustfmt::skip] // fails with "left behind trailing whitespace" fn main() { let x = 0 as *mut i32; let _x = x.wrapping_offset(8); // ok, this has no inbounds tag let _x = unsafe { x.offset(0) }; // UB despite offset 0, NULL is never inbounds + //~^ERROR: null pointer is a dangling pointer } diff --git a/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr b/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr index cb9b02c84051..40a5022351dd 100644 --- a/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr +++ b/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr @@ -1,18 +1,13 @@ error: Undefined Behavior: out-of-bounds pointer arithmetic: null pointer is a dangling pointer (it has no provenance) - --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC + --> $DIR/ptr_offset_0_plus_0.rs:LL:CC | -LL | unsafe { intrinsics::offset(self, count) as *mut T } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: null pointer is a dangling pointer (it has no provenance) +LL | let _x = unsafe { x.offset(0) }; // UB despite offset 0, NULL is never inbounds + | ^^^^^^^^^^^ out-of-bounds pointer arithmetic: null pointer is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::ptr::mut_ptr::::offset` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC -note: inside `main` at $DIR/ptr_offset_0_plus_0.rs:LL:CC - --> $DIR/ptr_offset_0_plus_0.rs:LL:CC - | -LL | let _x = unsafe { x.offset(0) }; // UB despite offset 0, NULL is never inbounds - | ^^^^^^^^^^^ + = note: inside `main` at $DIR/ptr_offset_0_plus_0.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ptr_offset_from_oob.rs b/tests/fail/intrinsics/ptr_offset_from_oob.rs index 1fd5100a97b9..0e5acf08b203 100644 --- a/tests/fail/intrinsics/ptr_offset_from_oob.rs +++ b/tests/fail/intrinsics/ptr_offset_from_oob.rs @@ -1,11 +1,7 @@ -#![feature(core_intrinsics)] - -use std::intrinsics::ptr_offset_from; - fn main() { let start_ptr = &4 as *const _ as *const u8; let length = 10; let end_ptr = start_ptr.wrapping_add(length); // Even if the offset is 0, a dangling OOB pointer is not allowed. - unsafe { ptr_offset_from(end_ptr, end_ptr) }; //~ERROR: pointer at offset 10 is out-of-bounds + unsafe { end_ptr.offset_from(end_ptr) }; //~ERROR: pointer at offset 10 is out-of-bounds } diff --git a/tests/fail/intrinsics/ptr_offset_from_oob.stderr b/tests/fail/intrinsics/ptr_offset_from_oob.stderr index 699ca1a87ae8..546245a499e1 100644 --- a/tests/fail/intrinsics/ptr_offset_from_oob.stderr +++ b/tests/fail/intrinsics/ptr_offset_from_oob.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: out-of-bounds offset_from: ALLOC has size 4, so pointer at offset 10 is out-of-bounds --> $DIR/ptr_offset_from_oob.rs:LL:CC | -LL | unsafe { ptr_offset_from(end_ptr, end_ptr) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: ALLOC has size 4, so pointer at offset 10 is out-of-bounds +LL | unsafe { end_ptr.offset_from(end_ptr) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: ALLOC has size 4, so pointer at offset 10 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_int.rs b/tests/fail/intrinsics/ptr_offset_int_plus_int.rs index f51e00746e2f..19bd265c1435 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_int.rs +++ b/tests/fail/intrinsics/ptr_offset_int_plus_int.rs @@ -1,9 +1,8 @@ -//@error-pattern: is a dangling pointer //@compile-flags: -Zmiri-permissive-provenance fn main() { // Can't offset an integer pointer by non-zero offset. unsafe { - let _val = (1 as *mut u8).offset(1); + let _val = (1 as *mut u8).offset(1); //~ERROR: is a dangling pointer } } diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr b/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr index e92b0a321665..a96717a06707 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr +++ b/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr @@ -1,18 +1,13 @@ error: Undefined Behavior: out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance) - --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC + --> $DIR/ptr_offset_int_plus_int.rs:LL:CC | -LL | unsafe { intrinsics::offset(self, count) as *mut T } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance) +LL | let _val = (1 as *mut u8).offset(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::ptr::mut_ptr::::offset` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC -note: inside `main` at $DIR/ptr_offset_int_plus_int.rs:LL:CC - --> $DIR/ptr_offset_int_plus_int.rs:LL:CC - | -LL | let _val = (1 as *mut u8).offset(1); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/ptr_offset_int_plus_int.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs index 8fc4d7fe7350..fd3c9b44615c 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs +++ b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs @@ -1,10 +1,9 @@ -//@error-pattern: is a dangling pointer //@compile-flags: -Zmiri-permissive-provenance fn main() { let ptr = Box::into_raw(Box::new(0u32)); // Can't start with an integer pointer and get to something usable unsafe { - let _val = (1 as *mut u8).offset(ptr as isize); + let _val = (1 as *mut u8).offset(ptr as isize); //~ERROR: is a dangling pointer } } diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr index 47eac678e2ef..c1abe01dcea5 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr +++ b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr @@ -1,18 +1,13 @@ error: Undefined Behavior: out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance) - --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC + --> $DIR/ptr_offset_int_plus_ptr.rs:LL:CC | -LL | unsafe { intrinsics::offset(self, count) as *mut T } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance) +LL | let _val = (1 as *mut u8).offset(ptr as isize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::ptr::mut_ptr::::offset` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC -note: inside `main` at $DIR/ptr_offset_int_plus_ptr.rs:LL:CC - --> $DIR/ptr_offset_int_plus_ptr.rs:LL:CC - | -LL | let _val = (1 as *mut u8).offset(ptr as isize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/ptr_offset_int_plus_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ptr_offset_overflow.rs b/tests/fail/intrinsics/ptr_offset_overflow.rs index 829cf90c855d..c3db1e23b9bf 100644 --- a/tests/fail/intrinsics/ptr_offset_overflow.rs +++ b/tests/fail/intrinsics/ptr_offset_overflow.rs @@ -1,6 +1,5 @@ -//@error-pattern: overflowing in-bounds pointer arithmetic fn main() { let v = [1i8, 2]; let x = &v[1] as *const i8; - let _val = unsafe { x.offset(isize::MIN) }; + let _val = unsafe { x.offset(isize::MIN) }; //~ERROR: overflowing in-bounds pointer arithmetic } diff --git a/tests/fail/intrinsics/ptr_offset_overflow.stderr b/tests/fail/intrinsics/ptr_offset_overflow.stderr index d8596acc33b0..d5935006e43b 100644 --- a/tests/fail/intrinsics/ptr_offset_overflow.stderr +++ b/tests/fail/intrinsics/ptr_offset_overflow.stderr @@ -1,18 +1,13 @@ error: Undefined Behavior: overflowing in-bounds pointer arithmetic - --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC + --> $DIR/ptr_offset_overflow.rs:LL:CC | -LL | unsafe { intrinsics::offset(self, count) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing in-bounds pointer arithmetic +LL | let _val = unsafe { x.offset(isize::MIN) }; + | ^^^^^^^^^^^^^^^^^^^^ overflowing in-bounds pointer arithmetic | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC -note: inside `main` at $DIR/ptr_offset_overflow.rs:LL:CC - --> $DIR/ptr_offset_overflow.rs:LL:CC - | -LL | let _val = unsafe { x.offset(isize::MIN) }; - | ^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/ptr_offset_overflow.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ptr_offset_ptr_plus_0.rs b/tests/fail/intrinsics/ptr_offset_ptr_plus_0.rs index f8ee7d0b5092..575e28854b1a 100644 --- a/tests/fail/intrinsics/ptr_offset_ptr_plus_0.rs +++ b/tests/fail/intrinsics/ptr_offset_ptr_plus_0.rs @@ -1,7 +1,7 @@ -//@error-pattern: pointer at offset 32 is out-of-bounds - +#[rustfmt::skip] // fails with "left behind trailing whitespace" fn main() { let x = Box::into_raw(Box::new(0u32)); let x = x.wrapping_offset(8); // ok, this has no inbounds tag let _x = unsafe { x.offset(0) }; // UB despite offset 0, the pointer is not inbounds of the only object it can point to + //~^ERROR: pointer at offset 32 is out-of-bounds } diff --git a/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr b/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr index 767ed2fc3c45..5c516d5a490f 100644 --- a/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr +++ b/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr @@ -1,18 +1,13 @@ error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer at offset 32 is out-of-bounds - --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC + --> $DIR/ptr_offset_ptr_plus_0.rs:LL:CC | -LL | unsafe { intrinsics::offset(self, count) as *mut T } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer at offset 32 is out-of-bounds +LL | let _x = unsafe { x.offset(0) }; // UB despite offset 0, the pointer is not inbounds of the only object it can point to + | ^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer at offset 32 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::ptr::mut_ptr::::offset` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC -note: inside `main` at $DIR/ptr_offset_ptr_plus_0.rs:LL:CC - --> $DIR/ptr_offset_ptr_plus_0.rs:LL:CC - | -LL | let _x = unsafe { x.offset(0) }; // UB despite offset 0, the pointer is not inbounds of the only object it can point to - | ^^^^^^^^^^^ + = note: inside `main` at $DIR/ptr_offset_ptr_plus_0.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_add1.rs b/tests/fail/intrinsics/unchecked_add1.rs index 25dbb817fae0..13265d0fb0ee 100644 --- a/tests/fail/intrinsics/unchecked_add1.rs +++ b/tests/fail/intrinsics/unchecked_add1.rs @@ -1,7 +1,6 @@ -#![feature(core_intrinsics)] +#![feature(unchecked_math)] + fn main() { // MAX overflow - unsafe { - std::intrinsics::unchecked_add(40000u16, 30000); //~ ERROR: overflow executing `unchecked_add` - } + let _val = unsafe { 40000u16.unchecked_add(30000) }; //~ ERROR: overflow executing `unchecked_add` } diff --git a/tests/fail/intrinsics/unchecked_add1.stderr b/tests/fail/intrinsics/unchecked_add1.stderr index 9d48590593f5..062acbb8de8c 100644 --- a/tests/fail/intrinsics/unchecked_add1.stderr +++ b/tests/fail/intrinsics/unchecked_add1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow executing `unchecked_add` --> $DIR/unchecked_add1.rs:LL:CC | -LL | std::intrinsics::unchecked_add(40000u16, 30000); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_add` +LL | let _val = unsafe { 40000u16.unchecked_add(30000) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_add` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/unchecked_add2.rs b/tests/fail/intrinsics/unchecked_add2.rs index a454f6478059..229f50321d7d 100644 --- a/tests/fail/intrinsics/unchecked_add2.rs +++ b/tests/fail/intrinsics/unchecked_add2.rs @@ -1,7 +1,6 @@ -#![feature(core_intrinsics)] +#![feature(unchecked_math)] + fn main() { // MIN overflow - unsafe { - std::intrinsics::unchecked_add(-30000i16, -8000); //~ ERROR: overflow executing `unchecked_add` - } + let _val = unsafe { (-30000i16).unchecked_add(-8000) }; //~ ERROR: overflow executing `unchecked_add` } diff --git a/tests/fail/intrinsics/unchecked_add2.stderr b/tests/fail/intrinsics/unchecked_add2.stderr index 64691932e712..09b622d6e296 100644 --- a/tests/fail/intrinsics/unchecked_add2.stderr +++ b/tests/fail/intrinsics/unchecked_add2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow executing `unchecked_add` --> $DIR/unchecked_add2.rs:LL:CC | -LL | std::intrinsics::unchecked_add(-30000i16, -8000); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_add` +LL | let _val = unsafe { (-30000i16).unchecked_add(-8000) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_add` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/unchecked_mul1.rs b/tests/fail/intrinsics/unchecked_mul1.rs index 514eb60602da..810d3418dc8f 100644 --- a/tests/fail/intrinsics/unchecked_mul1.rs +++ b/tests/fail/intrinsics/unchecked_mul1.rs @@ -1,7 +1,5 @@ -#![feature(core_intrinsics)] +#![feature(unchecked_math)] fn main() { // MAX overflow - unsafe { - std::intrinsics::unchecked_mul(300u16, 250u16); //~ ERROR: overflow executing `unchecked_mul` - } + let _val = unsafe { 300u16.unchecked_mul(250u16) }; //~ ERROR: overflow executing `unchecked_mul` } diff --git a/tests/fail/intrinsics/unchecked_mul1.stderr b/tests/fail/intrinsics/unchecked_mul1.stderr index 4d3a45d41575..e260c343c4e6 100644 --- a/tests/fail/intrinsics/unchecked_mul1.stderr +++ b/tests/fail/intrinsics/unchecked_mul1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow executing `unchecked_mul` --> $DIR/unchecked_mul1.rs:LL:CC | -LL | std::intrinsics::unchecked_mul(300u16, 250u16); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_mul` +LL | let _val = unsafe { 300u16.unchecked_mul(250u16) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_mul` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/unchecked_mul2.rs b/tests/fail/intrinsics/unchecked_mul2.rs index e103c1e7ad17..421019542a95 100644 --- a/tests/fail/intrinsics/unchecked_mul2.rs +++ b/tests/fail/intrinsics/unchecked_mul2.rs @@ -1,7 +1,5 @@ -#![feature(core_intrinsics)] +#![feature(unchecked_math)] fn main() { // MIN overflow - unsafe { - std::intrinsics::unchecked_mul(1_000_000_000i32, -4); //~ ERROR: overflow executing `unchecked_mul` - } + let _val = unsafe { 1_000_000_000i32.unchecked_mul(-4) }; //~ ERROR: overflow executing `unchecked_mul` } diff --git a/tests/fail/intrinsics/unchecked_mul2.stderr b/tests/fail/intrinsics/unchecked_mul2.stderr index b64ef116be45..88b3a49b98ec 100644 --- a/tests/fail/intrinsics/unchecked_mul2.stderr +++ b/tests/fail/intrinsics/unchecked_mul2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow executing `unchecked_mul` --> $DIR/unchecked_mul2.rs:LL:CC | -LL | std::intrinsics::unchecked_mul(1_000_000_000i32, -4); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_mul` +LL | let _val = unsafe { 1_000_000_000i32.unchecked_mul(-4) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_mul` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/unchecked_sub1.rs b/tests/fail/intrinsics/unchecked_sub1.rs index e99f88edc863..c6e006667441 100644 --- a/tests/fail/intrinsics/unchecked_sub1.rs +++ b/tests/fail/intrinsics/unchecked_sub1.rs @@ -1,7 +1,5 @@ -#![feature(core_intrinsics)] +#![feature(unchecked_math)] fn main() { // MIN overflow - unsafe { - std::intrinsics::unchecked_sub(14u32, 22); //~ ERROR: overflow executing `unchecked_sub` - } + let _val = unsafe { 14u32.unchecked_sub(22) }; //~ ERROR: overflow executing `unchecked_sub` } diff --git a/tests/fail/intrinsics/unchecked_sub1.stderr b/tests/fail/intrinsics/unchecked_sub1.stderr index 8454382777a0..ebd7bc10eb41 100644 --- a/tests/fail/intrinsics/unchecked_sub1.stderr +++ b/tests/fail/intrinsics/unchecked_sub1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow executing `unchecked_sub` --> $DIR/unchecked_sub1.rs:LL:CC | -LL | std::intrinsics::unchecked_sub(14u32, 22); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_sub` +LL | let _val = unsafe { 14u32.unchecked_sub(22) }; + | ^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_sub` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/unchecked_sub2.rs b/tests/fail/intrinsics/unchecked_sub2.rs index f83f6843c9ec..65aa292e212d 100644 --- a/tests/fail/intrinsics/unchecked_sub2.rs +++ b/tests/fail/intrinsics/unchecked_sub2.rs @@ -1,7 +1,5 @@ -#![feature(core_intrinsics)] +#![feature(unchecked_math)] fn main() { // MAX overflow - unsafe { - std::intrinsics::unchecked_sub(30000i16, -7000); //~ ERROR: overflow executing `unchecked_sub` - } + let _val = unsafe { 30000i16.unchecked_sub(-7000) }; //~ ERROR: overflow executing `unchecked_sub` } diff --git a/tests/fail/intrinsics/unchecked_sub2.stderr b/tests/fail/intrinsics/unchecked_sub2.stderr index 2e6fc2e0b64f..73d7c4d86bc0 100644 --- a/tests/fail/intrinsics/unchecked_sub2.stderr +++ b/tests/fail/intrinsics/unchecked_sub2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow executing `unchecked_sub` --> $DIR/unchecked_sub2.rs:LL:CC | -LL | std::intrinsics::unchecked_sub(30000i16, -7000); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_sub` +LL | let _val = unsafe { 30000i16.unchecked_sub(-7000) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_sub` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/invalid_enum_tag.rs b/tests/fail/invalid_enum_tag.rs index 92cc1d1d34e4..84fa2c297390 100644 --- a/tests/fail/invalid_enum_tag.rs +++ b/tests/fail/invalid_enum_tag.rs @@ -2,8 +2,6 @@ // Make sure we find these even with many checks disabled. //@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation -//@error-pattern: enum value has invalid tag - use std::mem; #[repr(C)] @@ -16,5 +14,5 @@ pub enum Foo { fn main() { let f = unsafe { std::mem::transmute::(42) }; - let _val = mem::discriminant(&f); + let _val = mem::discriminant(&f); //~ERROR: enum value has invalid tag } diff --git a/tests/fail/invalid_enum_tag.stderr b/tests/fail/invalid_enum_tag.stderr index 2f5a4541129c..eff59cbfc8c2 100644 --- a/tests/fail/invalid_enum_tag.stderr +++ b/tests/fail/invalid_enum_tag.stderr @@ -1,18 +1,13 @@ error: Undefined Behavior: enum value has invalid tag: $HEX - --> RUSTLIB/core/src/mem/mod.rs:LL:CC + --> $DIR/invalid_enum_tag.rs:LL:CC | -LL | Discriminant(intrinsics::discriminant_value(v)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ enum value has invalid tag: $HEX +LL | let _val = mem::discriminant(&f); + | ^^^^^^^^^^^^^^^^^^^^^ enum value has invalid tag: $HEX | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::mem::discriminant::` at RUSTLIB/core/src/mem/mod.rs:LL:CC -note: inside `main` at $DIR/invalid_enum_tag.rs:LL:CC - --> $DIR/invalid_enum_tag.rs:LL:CC - | -LL | let _val = mem::discriminant(&f); - | ^^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/invalid_enum_tag.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/provenance/ptr_invalid_offset.rs b/tests/fail/provenance/ptr_invalid_offset.rs index a3510d8e8929..91ba18f76805 100644 --- a/tests/fail/provenance/ptr_invalid_offset.rs +++ b/tests/fail/provenance/ptr_invalid_offset.rs @@ -1,5 +1,4 @@ //@compile-flags: -Zmiri-strict-provenance -//@error-pattern: is a dangling pointer #![feature(strict_provenance)] fn main() { @@ -7,5 +6,5 @@ fn main() { let ptr = &x as *const _ as *const u8; let roundtrip = std::ptr::invalid::(ptr as usize); // Not even offsetting this is allowed. - let _ = unsafe { roundtrip.offset(1) }; + let _ = unsafe { roundtrip.offset(1) }; //~ERROR: is a dangling pointer } diff --git a/tests/fail/provenance/ptr_invalid_offset.stderr b/tests/fail/provenance/ptr_invalid_offset.stderr index df73689deae8..813a6515b771 100644 --- a/tests/fail/provenance/ptr_invalid_offset.stderr +++ b/tests/fail/provenance/ptr_invalid_offset.stderr @@ -1,18 +1,13 @@ error: Undefined Behavior: out-of-bounds pointer arithmetic: $HEX[noalloc] is a dangling pointer (it has no provenance) - --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC + --> $DIR/ptr_invalid_offset.rs:LL:CC | -LL | unsafe { intrinsics::offset(self, count) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: $HEX[noalloc] is a dangling pointer (it has no provenance) +LL | let _ = unsafe { roundtrip.offset(1) }; + | ^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: $HEX[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC -note: inside `main` at $DIR/ptr_invalid_offset.rs:LL:CC - --> $DIR/ptr_invalid_offset.rs:LL:CC - | -LL | let _ = unsafe { roundtrip.offset(1) }; - | ^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/ptr_invalid_offset.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/should-pass/cpp20_rwc_syncs.rs b/tests/fail/should-pass/cpp20_rwc_syncs.rs index dbac6469fbab..6a7622671b59 100644 --- a/tests/fail/should-pass/cpp20_rwc_syncs.rs +++ b/tests/fail/should-pass/cpp20_rwc_syncs.rs @@ -1,6 +1,5 @@ //@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-ignore-leaks -//@error-pattern: unreachable // https://plv.mpi-sws.org/scfix/paper.pdf // 2.2 Second Problem: SC Fences are Too Weak @@ -77,7 +76,7 @@ fn test_cpp20_rwc_syncs() { if (b, c) == (0, 0) { // This *should* be unreachable, but Miri will reach it. unsafe { - std::hint::unreachable_unchecked(); + std::hint::unreachable_unchecked(); //~ERROR: unreachable } } } diff --git a/tests/fail/should-pass/cpp20_rwc_syncs.stderr b/tests/fail/should-pass/cpp20_rwc_syncs.stderr index 0ab02687e2ae..17573a33b3d7 100644 --- a/tests/fail/should-pass/cpp20_rwc_syncs.stderr +++ b/tests/fail/should-pass/cpp20_rwc_syncs.stderr @@ -1,18 +1,13 @@ error: Undefined Behavior: entering unreachable code - --> RUSTLIB/core/src/hint.rs:LL:CC + --> $DIR/cpp20_rwc_syncs.rs:LL:CC | -LL | unsafe { intrinsics::unreachable() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code +LL | std::hint::unreachable_unchecked(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::hint::unreachable_unchecked` at RUSTLIB/core/src/hint.rs:LL:CC -note: inside `test_cpp20_rwc_syncs` at $DIR/cpp20_rwc_syncs.rs:LL:CC - --> $DIR/cpp20_rwc_syncs.rs:LL:CC - | -LL | std::hint::unreachable_unchecked(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `test_cpp20_rwc_syncs` at $DIR/cpp20_rwc_syncs.rs:LL:CC note: inside `main` at $DIR/cpp20_rwc_syncs.rs:LL:CC --> $DIR/cpp20_rwc_syncs.rs:LL:CC | diff --git a/tests/fail/unreachable.rs b/tests/fail/unreachable.rs index ef2bb42c65cc..3389d5b9ddea 100644 --- a/tests/fail/unreachable.rs +++ b/tests/fail/unreachable.rs @@ -1,4 +1,3 @@ -//@error-pattern: entering unreachable code fn main() { - unsafe { std::hint::unreachable_unchecked() } + unsafe { std::hint::unreachable_unchecked() } //~ERROR: entering unreachable code } diff --git a/tests/fail/unreachable.stderr b/tests/fail/unreachable.stderr index e9eb3649dea4..b487b4374756 100644 --- a/tests/fail/unreachable.stderr +++ b/tests/fail/unreachable.stderr @@ -1,18 +1,13 @@ error: Undefined Behavior: entering unreachable code - --> RUSTLIB/core/src/hint.rs:LL:CC + --> $DIR/unreachable.rs:LL:CC | -LL | unsafe { intrinsics::unreachable() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code +LL | unsafe { std::hint::unreachable_unchecked() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::hint::unreachable_unchecked` at RUSTLIB/core/src/hint.rs:LL:CC -note: inside `main` at $DIR/unreachable.rs:LL:CC - --> $DIR/unreachable.rs:LL:CC - | -LL | unsafe { std::hint::unreachable_unchecked() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/unreachable.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/weak_memory/racing_mixed_size.rs b/tests/fail/weak_memory/racing_mixed_size.rs index a7c5a4191762..95a10510713c 100644 --- a/tests/fail/weak_memory/racing_mixed_size.rs +++ b/tests/fail/weak_memory/racing_mixed_size.rs @@ -4,6 +4,7 @@ #![feature(core_intrinsics)] +use std::ptr; use std::sync::atomic::AtomicU32; use std::sync::atomic::Ordering::*; use std::thread::spawn; @@ -30,7 +31,7 @@ pub fn main() { let x_ptr = x as *const AtomicU32 as *const u32; let x_split = split_u32_ptr(x_ptr); unsafe { - let hi = &(*x_split)[0] as *const u16; + let hi = ptr::addr_of!((*x_split)[0]); std::intrinsics::atomic_load_relaxed(hi); //~ ERROR: imperfectly overlapping } }); From 39d8c4de357c2846c586d7d3794163da8a63578a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 Jul 2022 10:35:07 -0400 Subject: [PATCH 3624/5092] rustup --- rust-version | 2 +- .../fail/intrinsics/ptr_offset_from_unsigned_neg.rs | 5 +++-- .../intrinsics/ptr_offset_from_unsigned_neg.stderr | 13 ++++--------- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/rust-version b/rust-version index b70ab6fdd46e..b948bc8b4e6a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7fe022f5aa32bbbb33c3a58755729d6667a461a9 +2fdbf075cf502431ca9fee6616331b32e34f25de diff --git a/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs b/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs index d6413faf74bf..67aa60e785b1 100644 --- a/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs +++ b/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs @@ -1,9 +1,10 @@ -//@error-pattern: first pointer has smaller offset than second: 0 < 4 +// Preparing for a rustc behavior change that'll happen soon: (FIXME remove this after the next submodule bump succeeded) +//@normalize-stderr-test: "`(ptr_offset_from_unsigned)`" -> "$1" #![feature(ptr_sub_ptr)] fn main() { let arr = [0u8; 8]; let ptr1 = arr.as_ptr(); let ptr2 = ptr1.wrapping_add(4); - let _val = unsafe { ptr1.sub_ptr(ptr2) }; + let _val = unsafe { ptr1.sub_ptr(ptr2) }; //~ERROR: first pointer has smaller offset than second: 0 < 4 } diff --git a/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr b/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr index bb68f9f5c18c..93a05fe8d9e9 100644 --- a/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr +++ b/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr @@ -1,18 +1,13 @@ error: Undefined Behavior: ptr_offset_from_unsigned called when first pointer has smaller offset than second: 0 < 4 - --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC + --> $DIR/ptr_offset_from_unsigned_neg.rs:LL:CC | -LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ptr_offset_from_unsigned called when first pointer has smaller offset than second: 0 < 4 +LL | let _val = unsafe { ptr1.sub_ptr(ptr2) }; + | ^^^^^^^^^^^^^^^^^^ ptr_offset_from_unsigned called when first pointer has smaller offset than second: 0 < 4 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::ptr::const_ptr::::sub_ptr` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC -note: inside `main` at $DIR/ptr_offset_from_unsigned_neg.rs:LL:CC - --> $DIR/ptr_offset_from_unsigned_neg.rs:LL:CC - | -LL | let _val = unsafe { ptr1.sub_ptr(ptr2) }; - | ^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/ptr_offset_from_unsigned_neg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace From cd6b723bb66c7cc32a1436db43079dc4236eaa90 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 25 Jul 2022 17:55:45 +0000 Subject: [PATCH 3625/5092] Add default impls for `FileDescriptor` methods --- src/shims/unix/fs.rs | 155 ++++++++---------------------- tests/fail/fs/close_stdout.rs | 2 +- tests/fail/fs/close_stdout.stderr | 4 +- 3 files changed, 41 insertions(+), 120 deletions(-) diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index dc31237a3199..c9f35c048917 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -24,38 +24,56 @@ struct FileHandle { } trait FileDescriptor: std::fmt::Debug { - fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle>; + fn name(&self) -> &'static str; + + fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { + throw_unsup_format!("{} cannot be used as FileHandle", self.name()); + } fn read<'tcx>( &mut self, - communicate_allowed: bool, - bytes: &mut [u8], - ) -> InterpResult<'tcx, io::Result>; + _communicate_allowed: bool, + _bytes: &mut [u8], + ) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("cannot read from {}", self.name()); + } fn write<'tcx>( &self, - communicate_allowed: bool, - bytes: &[u8], - ) -> InterpResult<'tcx, io::Result>; + _communicate_allowed: bool, + _bytes: &[u8], + ) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("cannot write to {}", self.name()); + } fn seek<'tcx>( &mut self, - communicate_allowed: bool, - offset: SeekFrom, - ) -> InterpResult<'tcx, io::Result>; + _communicate_allowed: bool, + _offset: SeekFrom, + ) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("cannot seek on {}", self.name()); + } fn close<'tcx>( self: Box, _communicate_allowed: bool, - ) -> InterpResult<'tcx, io::Result>; + ) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("cannot close {}", self.name()); + } fn dup(&mut self) -> io::Result>; #[cfg(unix)] - fn as_unix_host_fd(&self) -> Option; + fn as_unix_host_fd(&self) -> Option { + None + } } impl FileDescriptor for FileHandle { + fn name(&self) -> &'static str { + "FILE" + } + fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { Ok(self) } @@ -126,8 +144,8 @@ impl FileDescriptor for FileHandle { } impl FileDescriptor for io::Stdin { - fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { - throw_unsup_format!("stdin cannot be used as FileHandle"); + fn name(&self) -> &'static str { + "stdin" } fn read<'tcx>( @@ -142,29 +160,6 @@ impl FileDescriptor for io::Stdin { Ok(Read::read(self, bytes)) } - fn write<'tcx>( - &self, - _communicate_allowed: bool, - _bytes: &[u8], - ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("cannot write to stdin"); - } - - fn seek<'tcx>( - &mut self, - _communicate_allowed: bool, - _offset: SeekFrom, - ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("cannot seek on stdin"); - } - - fn close<'tcx>( - self: Box, - _communicate_allowed: bool, - ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("stdin cannot be closed"); - } - fn dup(&mut self) -> io::Result> { Ok(Box::new(io::stdin())) } @@ -176,16 +171,8 @@ impl FileDescriptor for io::Stdin { } impl FileDescriptor for io::Stdout { - fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { - throw_unsup_format!("stdout cannot be used as FileHandle"); - } - - fn read<'tcx>( - &mut self, - _communicate_allowed: bool, - _bytes: &mut [u8], - ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("cannot read from stdout"); + fn name(&self) -> &'static str { + "stdout" } fn write<'tcx>( @@ -205,21 +192,6 @@ impl FileDescriptor for io::Stdout { Ok(result) } - fn seek<'tcx>( - &mut self, - _communicate_allowed: bool, - _offset: SeekFrom, - ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("cannot seek on stdout"); - } - - fn close<'tcx>( - self: Box, - _communicate_allowed: bool, - ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("stdout cannot be closed"); - } - fn dup(&mut self) -> io::Result> { Ok(Box::new(io::stdout())) } @@ -231,16 +203,8 @@ impl FileDescriptor for io::Stdout { } impl FileDescriptor for io::Stderr { - fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { - throw_unsup_format!("stderr cannot be used as FileHandle"); - } - - fn read<'tcx>( - &mut self, - _communicate_allowed: bool, - _bytes: &mut [u8], - ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("cannot read from stderr"); + fn name(&self) -> &'static str { + "stderr" } fn write<'tcx>( @@ -253,21 +217,6 @@ impl FileDescriptor for io::Stderr { Ok(Write::write(&mut { self }, bytes)) } - fn seek<'tcx>( - &mut self, - _communicate_allowed: bool, - _offset: SeekFrom, - ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("cannot seek on stderr"); - } - - fn close<'tcx>( - self: Box, - _communicate_allowed: bool, - ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("stderr cannot be closed"); - } - fn dup(&mut self) -> io::Result> { Ok(Box::new(io::stderr())) } @@ -282,16 +231,8 @@ impl FileDescriptor for io::Stderr { struct DummyOutput; impl FileDescriptor for DummyOutput { - fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { - throw_unsup_format!("stderr and stdout cannot be used as FileHandle"); - } - - fn read<'tcx>( - &mut self, - _communicate_allowed: bool, - _bytes: &mut [u8], - ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("cannot read from stderr or stdout"); + fn name(&self) -> &'static str { + "stderr and stdout" } fn write<'tcx>( @@ -303,29 +244,9 @@ impl FileDescriptor for DummyOutput { Ok(Ok(bytes.len())) } - fn seek<'tcx>( - &mut self, - _communicate_allowed: bool, - _offset: SeekFrom, - ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("cannot seek on stderr or stdout"); - } - - fn close<'tcx>( - self: Box, - _communicate_allowed: bool, - ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("stderr and stdout cannot be closed"); - } - fn dup<'tcx>(&mut self) -> io::Result> { Ok(Box::new(DummyOutput)) } - - #[cfg(unix)] - fn as_unix_host_fd(&self) -> Option { - None - } } #[derive(Debug)] diff --git a/tests/fail/fs/close_stdout.rs b/tests/fail/fs/close_stdout.rs index 86a6239f5f36..e4eab5fd6964 100644 --- a/tests/fail/fs/close_stdout.rs +++ b/tests/fail/fs/close_stdout.rs @@ -7,6 +7,6 @@ fn main() { unsafe { - libc::close(1); //~ ERROR: stdout cannot be closed + libc::close(1); //~ ERROR: cannot close stdout } } diff --git a/tests/fail/fs/close_stdout.stderr b/tests/fail/fs/close_stdout.stderr index 08f744a5c458..eb2c54e05f1f 100644 --- a/tests/fail/fs/close_stdout.stderr +++ b/tests/fail/fs/close_stdout.stderr @@ -1,8 +1,8 @@ -error: unsupported operation: stdout cannot be closed +error: unsupported operation: cannot close stdout --> $DIR/close_stdout.rs:LL:CC | LL | libc::close(1); - | ^^^^^^^^^^^^^^ stdout cannot be closed + | ^^^^^^^^^^^^^^ cannot close stdout | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support = note: backtrace: From 5875c0d220c594b38b962a54386cc462060031f5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 Jul 2022 22:40:56 -0400 Subject: [PATCH 3626/5092] add test for dyn call issue --- rust-version | 2 +- tests/fail/issue-miri-2432.rs | 19 +++++++++++++++++++ tests/fail/issue-miri-2432.stderr | 15 +++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 tests/fail/issue-miri-2432.rs create mode 100644 tests/fail/issue-miri-2432.stderr diff --git a/rust-version b/rust-version index b948bc8b4e6a..927ced2a2d13 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -2fdbf075cf502431ca9fee6616331b32e34f25de +a86705942c4cfaaee60f2e7308ca2bca703a710f diff --git a/tests/fail/issue-miri-2432.rs b/tests/fail/issue-miri-2432.rs new file mode 100644 index 000000000000..f822479c4368 --- /dev/null +++ b/tests/fail/issue-miri-2432.rs @@ -0,0 +1,19 @@ +#![allow(where_clauses_object_safety)] + +trait Trait {} + +trait X { + fn foo(&self) + where + Self: Trait; +} + +impl X for () { + fn foo(&self) {} +} + +impl Trait for dyn X {} + +pub fn main() { + ::foo(&()); //~ERROR: trying to call something that is not a method +} diff --git a/tests/fail/issue-miri-2432.stderr b/tests/fail/issue-miri-2432.stderr new file mode 100644 index 000000000000..a5c9300fb07c --- /dev/null +++ b/tests/fail/issue-miri-2432.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `dyn` call trying to call something that is not a method + --> $DIR/issue-miri-2432.rs:LL:CC + | +LL | ::foo(&()); + | ^^^^^^^^^^^^^^^^^^^^^^ `dyn` call trying to call something that is not a method + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: backtrace: + = note: inside `main` at $DIR/issue-miri-2432.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + From dd3b8e8b1bfe1bad169cb0050d60b3c4bb9c2a7a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 26 Jul 2022 20:38:25 -0400 Subject: [PATCH 3627/5092] rustup --- rust-version | 2 +- tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs | 2 -- tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr | 4 ++-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 927ced2a2d13..5f09f4f35b13 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a86705942c4cfaaee60f2e7308ca2bca703a710f +c11207ec89b856164bba03b8ecfe07b0b234ed21 diff --git a/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs b/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs index 67aa60e785b1..06d13d9bdbaf 100644 --- a/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs +++ b/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs @@ -1,5 +1,3 @@ -// Preparing for a rustc behavior change that'll happen soon: (FIXME remove this after the next submodule bump succeeded) -//@normalize-stderr-test: "`(ptr_offset_from_unsigned)`" -> "$1" #![feature(ptr_sub_ptr)] fn main() { diff --git a/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr b/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr index 93a05fe8d9e9..419b7497a2f9 100644 --- a/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr +++ b/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: ptr_offset_from_unsigned called when first pointer has smaller offset than second: 0 < 4 +error: Undefined Behavior: `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: 0 < 4 --> $DIR/ptr_offset_from_unsigned_neg.rs:LL:CC | LL | let _val = unsafe { ptr1.sub_ptr(ptr2) }; - | ^^^^^^^^^^^^^^^^^^ ptr_offset_from_unsigned called when first pointer has smaller offset than second: 0 < 4 + | ^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: 0 < 4 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information From 622613f957e07ffe1398fa17bc84f185e62df27f Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 23 Jul 2022 13:59:08 -0400 Subject: [PATCH 3628/5092] Use real exec on cfg(unix) targets When cargo-miri is executed as a cargo test runner or rustdoc runtool, external tools expect what they launch as the runner/runtool to be the process actually running the test. But in the implementation, we launch the Miri interpreter as a subprocess using std::process::Command. This tends to confuse other tools (like nextest) and users (like the author). What we really want is to call POSIX exec so that the cargo-miri process becomes the interpreter. So this implements just that; we call execve via a cfg(unix) extension trait. Windows has no such mechanism, but it also doesn't have POSIX signals, which is the primary tripping hazard this change fixes. --- cargo-miri/bin.rs | 84 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 61 insertions(+), 23 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 216584ac9b02..ce7328e2e6c5 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -51,7 +51,7 @@ enum MiriCommand { } /// The information to run a crate with the given environment. -#[derive(Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize)] struct CrateRunEnv { /// The command-line arguments. args: Vec, @@ -249,27 +249,56 @@ fn xargo_check() -> Command { Command::new(env::var_os("XARGO_CHECK").unwrap_or_else(|| OsString::from("xargo-check"))) } -/// Execute the command. If it fails, fail this process with the same exit code. -/// Otherwise, continue. -fn exec(mut cmd: Command) { - let exit_status = cmd.status().expect("failed to run command"); - if exit_status.success().not() { +/// Execute the `Command`, where possible by replacing the current process with a new process +/// described by the `Command`. Then exit this process with the exit code of the new process. +fn exec(mut cmd: Command) -> ! { + // On non-Unix imitate POSIX exec as closely as we can + #[cfg(not(unix))] + { + let exit_status = cmd.status().expect("failed to run command"); std::process::exit(exit_status.code().unwrap_or(-1)) } + // On Unix targets, actually exec. + // If exec returns, process setup has failed. This is the same error condition as the expect in + // the non-Unix case. + #[cfg(unix)] + { + use std::os::unix::process::CommandExt; + let error = cmd.exec(); + Err(error).expect("failed to run command") + } } -/// Execute the command and pipe `input` into its stdin. -/// If it fails, fail this process with the same exit code. -/// Otherwise, continue. -fn exec_with_pipe(mut cmd: Command, input: &[u8]) { - cmd.stdin(process::Stdio::piped()); - let mut child = cmd.spawn().expect("failed to spawn process"); +/// Execute the `Command`, where possible by replacing the current process with a new process +/// described by the `Command`. Then exit this process with the exit code of the new process. +/// `input` is also piped to the new process's stdin, on cfg(unix) platforms by writing its +/// contents to `path` first, then setting stdin to that file. +fn exec_with_pipe

(mut cmd: Command, input: &[u8], path: P) -> ! +where + P: AsRef, +{ + #[cfg(unix)] { - let stdin = child.stdin.as_mut().expect("failed to open stdin"); - stdin.write_all(input).expect("failed to write out test source"); + // Write the bytes we want to send to stdin out to a file + std::fs::write(&path, input).unwrap(); + // Open the file for reading, and set our new stdin to it + let stdin = File::open(&path).unwrap(); + cmd.stdin(stdin); + // Unlink the file so that it is fully cleaned up as soon as the new process exits + std::fs::remove_file(&path).unwrap(); + // Finally, we can hand off control. + exec(cmd) } - let exit_status = child.wait().expect("failed to run command"); - if exit_status.success().not() { + #[cfg(not(unix))] + { + drop(path); // We don't need the path, we can pipe the bytes directly + cmd.stdin(process::Stdio::piped()); + let mut child = cmd.spawn().expect("failed to spawn process"); + { + let stdin = child.stdin.as_mut().expect("failed to open stdin"); + stdin.write_all(input).expect("failed to write out test source"); + } + let exit_status = child.wait().expect("failed to run command"); std::process::exit(exit_status.code().unwrap_or(-1)) } } @@ -872,6 +901,8 @@ fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { // and environment variables; this is used when cargo calls us again in the CARGO_TARGET_RUNNER phase. let env = CrateRunEnv::collect(args, inside_rustdoc); + store_json(CrateRunInfo::RunWith(env.clone())); + // Rustdoc expects us to exit with an error code if the test is marked as `compile_fail`, // just creating the JSON file is not enough: we need to detect syntax errors, // so we need to run Miri with `MIRI_BE_RUSTC` for a check-only build. @@ -888,7 +919,15 @@ fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { cmd.arg("--emit=metadata"); } - cmd.args(&env.args); + // Alter the `-o` parameter so that it does not overwrite the JSON file we stored above. + let mut args = env.args.clone(); + for i in 0..args.len() { + if args[i] == "-o" { + args[i + 1].push_str(".miri"); + } + } + + cmd.args(&args); cmd.env("MIRI_BE_RUSTC", "target"); if verbose > 0 { @@ -899,11 +938,9 @@ fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { eprintln!("[cargo-miri rustc inside rustdoc] going to run:\n{:?}", cmd); } - exec_with_pipe(cmd, &env.stdin); + exec_with_pipe(cmd, &env.stdin, format!("{}.stdin", out_filename("", "").display())); } - store_json(CrateRunInfo::RunWith(env)); - return; } @@ -983,8 +1020,6 @@ fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { "[cargo-miri rustc] target_crate={target_crate} runnable_crate={runnable_crate} print={print}" ); } - debug_cmd("[cargo-miri rustc]", verbose, &cmd); - exec(cmd); // Create a stub .rlib file if "link" was requested by cargo. // This is necessary to prevent cargo from doing rebuilds all the time. @@ -999,6 +1034,9 @@ fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { File::create(out_filename("", ".dll")).expect("failed to create fake .dll file"); File::create(out_filename("", ".lib")).expect("failed to create fake .lib file"); } + + debug_cmd("[cargo-miri rustc]", verbose, &cmd); + exec(cmd); } #[derive(Debug, Copy, Clone, PartialEq)] @@ -1100,7 +1138,7 @@ fn phase_runner(mut binary_args: impl Iterator, phase: RunnerPhas // Run it. debug_cmd("[cargo-miri runner]", verbose, &cmd); match phase { - RunnerPhase::Rustdoc => exec_with_pipe(cmd, &info.stdin), + RunnerPhase::Rustdoc => exec_with_pipe(cmd, &info.stdin, format!("{}.stdin", binary)), RunnerPhase::Cargo => exec(cmd), } } From 38e7bcf7f18d5617f43c7b84f050f7a87f3c5308 Mon Sep 17 00:00:00 2001 From: Aleksei Trifonov Date: Fri, 29 Jul 2022 05:25:59 +0300 Subject: [PATCH 3629/5092] Use cargo_metadata in cargo-miri --- cargo-miri/Cargo.lock | 75 +++++++++++++++++++++++++++++++------------ cargo-miri/Cargo.toml | 1 + cargo-miri/bin.rs | 45 ++++++++++---------------- 3 files changed, 73 insertions(+), 48 deletions(-) diff --git a/cargo-miri/Cargo.lock b/cargo-miri/Cargo.lock index abb60080b786..95c2bda505c5 100644 --- a/cargo-miri/Cargo.lock +++ b/cargo-miri/Cargo.lock @@ -20,10 +20,20 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "camino" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "869119e97797867fd90f5e22af7d0bd274bd4635ebb9eb68c04f3f513ae6c412" +dependencies = [ + "serde", +] + [[package]] name = "cargo-miri" version = "0.1.0" dependencies = [ + "cargo_metadata", "directories", "rustc-workspace-hack", "rustc_version", @@ -32,6 +42,28 @@ dependencies = [ "vergen", ] +[[package]] +name = "cargo-platform" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3abb7553d5b9b8421c6de7cb02606ff15e0c6eea7d8eadd75ef013fd636bec36" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", +] + [[package]] name = "cc" version = "1.0.72" @@ -274,11 +306,11 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.33" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb37d2df5df740e582f28f8560cf425f52bb267d872fe58358eadb554909f07a" +checksum = "c278e965f1d8cf32d6e0e96de3d3e79712178ae67986d9cf9151f51e95aac89b" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] @@ -338,24 +370,27 @@ checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" [[package]] name = "semver" -version = "1.0.4" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" +checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1" +dependencies = [ + "serde", +] [[package]] name = "serde" -version = "1.0.131" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ad69dfbd3e45369132cc64e6748c2d65cdfb001a2b1c232d128b4ad60561c1" +checksum = "fc855a42c7967b7c369eb5860f7164ef1f6f81c20c7cc1141f2a604e18723b03" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.131" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b710a83c4e0dff6a3d511946b95274ad9ca9e5d3ae497b63fda866ac955358d2" +checksum = "6f2122636b9fe3b81f1cb25099fcf2d3f542cdb1d45940d56c713158884a05da" dependencies = [ "proc-macro2", "quote", @@ -364,9 +399,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.73" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcbd0344bc6533bc7ec56df11d42fb70f1b912351c0825ccb7211b59d8af7cf5" +checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" dependencies = [ "itoa", "ryu", @@ -375,13 +410,13 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.82" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] @@ -435,6 +470,12 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" +[[package]] +name = "unicode-ident" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" + [[package]] name = "unicode-normalization" version = "0.1.19" @@ -444,12 +485,6 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "unicode-xid" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" - [[package]] name = "url" version = "2.2.2" diff --git a/cargo-miri/Cargo.toml b/cargo-miri/Cargo.toml index eb926525305c..8bcd77c70b01 100644 --- a/cargo-miri/Cargo.toml +++ b/cargo-miri/Cargo.toml @@ -17,6 +17,7 @@ doctest = false # and no doc tests directories = "3" rustc_version = "0.4" serde_json = "1.0.40" +cargo_metadata = "0.15.0" # A noop dependency that changes in the Rust repository, it's a bit of a hack. # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index faa116ff7e38..d11d3f15b885 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -16,6 +16,7 @@ use std::process::{self, Command}; use rustc_version::VersionMeta; use serde::{Deserialize, Serialize}; +use cargo_metadata::{MetadataCommand, Metadata}; use version::*; @@ -582,41 +583,29 @@ path = "lib.rs" } } -#[derive(Deserialize)] -struct Metadata { - target_directory: PathBuf, - workspace_members: Vec, -} - fn get_cargo_metadata() -> Metadata { - let mut cmd = cargo(); - // `-Zunstable-options` is required by `--config`. - cmd.args(["metadata", "--no-deps", "--format-version=1", "-Zunstable-options"]); // The `build.target-dir` config can be passed by `--config` flags, so forward them to // `cargo metadata`. + let mut additional_options = Vec::new(); + // `-Zunstable-options` is required by `--config`. + additional_options.push("-Zunstable-options".to_string()); + let config_flag = "--config"; for arg in ArgSplitFlagValue::new( env::args().skip(3), // skip the program name, "miri" and "run" / "test" config_flag, - ) - // Only look at `Ok` - .flatten() - { - cmd.arg(config_flag).arg(arg); + ).flatten() { // Only look at `Ok` + additional_options.push(config_flag.to_string()); + additional_options.push(arg); } - let mut child = cmd - .stdin(process::Stdio::null()) - .stdout(process::Stdio::piped()) - .spawn() - .expect("failed ro run `cargo metadata`"); - // Check this `Result` after `status.success()` is checked, so we don't print the error - // to stderr if `cargo metadata` is also printing to stderr. - let metadata: Result = serde_json::from_reader(child.stdout.take().unwrap()); - let status = child.wait().expect("failed to wait for `cargo metadata` to exit"); - if !status.success() { - std::process::exit(status.code().unwrap_or(-1)); - } - metadata.unwrap_or_else(|e| show_error(format!("invalid `cargo metadata` output: {}", e))) + + let metadata = MetadataCommand::new() + .no_deps() + .other_options(additional_options) + .exec() + .unwrap(); + + metadata } /// Pulls all the crates in this workspace from the cargo metadata. @@ -627,7 +616,7 @@ fn local_crates(metadata: &Metadata) -> String { assert!(!metadata.workspace_members.is_empty()); let mut local_crates = String::new(); for member in &metadata.workspace_members { - let name = member.split(' ').next().unwrap(); + let name = member.repr.split(' ').next().unwrap(); let name = name.replace('-', "_"); local_crates.push_str(&name); local_crates.push(','); From 01a6109925151228f755a7fce7b384ca34dad13c Mon Sep 17 00:00:00 2001 From: Aleksei Trifonov Date: Fri, 29 Jul 2022 14:42:42 +0300 Subject: [PATCH 3630/5092] Fix formatting --- cargo-miri/bin.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index d11d3f15b885..9c98542be879 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -14,9 +14,9 @@ use std::ops::Not; use std::path::{Path, PathBuf}; use std::process::{self, Command}; +use cargo_metadata::{Metadata, MetadataCommand}; use rustc_version::VersionMeta; use serde::{Deserialize, Serialize}; -use cargo_metadata::{MetadataCommand, Metadata}; use version::*; @@ -594,16 +594,16 @@ fn get_cargo_metadata() -> Metadata { for arg in ArgSplitFlagValue::new( env::args().skip(3), // skip the program name, "miri" and "run" / "test" config_flag, - ).flatten() { // Only look at `Ok` + ) + // Only look at `Ok` + .flatten() + { additional_options.push(config_flag.to_string()); additional_options.push(arg); } - let metadata = MetadataCommand::new() - .no_deps() - .other_options(additional_options) - .exec() - .unwrap(); + let metadata = + MetadataCommand::new().no_deps().other_options(additional_options).exec().unwrap(); metadata } From 66f6fa68fa7e49d13a3fcf4128790a38220651d6 Mon Sep 17 00:00:00 2001 From: Hiroki6 Date: Sun, 31 Jul 2022 16:08:27 +0200 Subject: [PATCH 3631/5092] Fix typo in eval.rs --- src/eval.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 53264bd46591..c6fde1e683e0 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -246,7 +246,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } // Store command line as UTF-16 for Windows `GetCommandLineW`. { - // Construct a command string with all the aguments. + // Construct a command string with all the arguments. let cmd_utf16: Vec = args_to_utf16_command_string(config.args.iter()); let cmd_type = tcx.mk_array(tcx.types.u16, u64::try_from(cmd_utf16.len()).unwrap()); @@ -311,7 +311,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( /// Evaluates the entry function specified by `entry_id`. /// Returns `Some(return_code)` if program executed completed. -/// Returns `None` if an evaluation error occured. +/// Returns `None` if an evaluation error occurred. pub fn eval_entry<'tcx>( tcx: TyCtxt<'tcx>, entry_id: DefId, From f6badf037ec423bf41e64b815749a6be8b09dea6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 1 Aug 2022 09:13:34 -0400 Subject: [PATCH 3632/5092] rustup --- cargo-miri/bin.rs | 4 ++-- rust-version | 2 +- test-cargo-miri/run-test.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 9c98542be879..4ddf2295362a 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -548,14 +548,14 @@ path = "lib.rs" // Manage the output the user sees. if only_setup { // We want to be explicit. - eprintln!("Preparing a sysroot for Miri..."); + eprintln!("Preparing a sysroot for Miri (target: {target})..."); if print_sysroot { // Be extra sure there is no noise on stdout. command.stdout(process::Stdio::null()); } } else { // We want to be quiet, but still let the user know that something is happening. - eprint!("Preparing a sysroot for Miri... "); + eprint!("Preparing a sysroot for Miri (target: {target})... "); command.stdout(process::Stdio::null()); command.stderr(process::Stdio::null()); } diff --git a/rust-version b/rust-version index 5f09f4f35b13..22daf00bd05d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c11207ec89b856164bba03b8ecfe07b0b234ed21 +1f5d8d49eb6111931091f700d07518cd2b80bc18 diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 3805bd19777f..4485d3252ccc 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -29,7 +29,7 @@ def normalize_stdout(str): return str def normalize_stderr(str): - str = str.replace("Preparing a sysroot for Miri... done\n", "") # remove leading cargo-miri setup output + str = re.sub("Preparing a sysroot for Miri \(target: [a-z0-9_-]+\)\.\.\. done\n", "", str) # remove leading cargo-miri setup output return str def check_output(actual, path, name): From 9ffea913b8f116b4dcda1b1998b5bfcf50a6dc14 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 1 Aug 2022 09:27:10 -0400 Subject: [PATCH 3633/5092] clippy --- src/eval.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/eval.rs b/src/eval.rs index c6fde1e683e0..cb24dea3a88d 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -312,6 +312,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( /// Evaluates the entry function specified by `entry_id`. /// Returns `Some(return_code)` if program executed completed. /// Returns `None` if an evaluation error occurred. +#[allow(clippy::needless_lifetimes)] pub fn eval_entry<'tcx>( tcx: TyCtxt<'tcx>, entry_id: DefId, From 171d082433904096a7c563d937c860d52ba9b25f Mon Sep 17 00:00:00 2001 From: Allen Hsu Date: Tue, 12 Jul 2022 22:29:12 +1000 Subject: [PATCH 3634/5092] Compare where predicates to trait bounds. - only compare where predicates to trait bounds when generating where clause specific message to fix #9151 - use comparable_trait_ref to account for trait bound generics to fix #8757 --- clippy_lints/src/trait_bounds.rs | 71 ++++++++++++++------- tests/ui/trait_duplication_in_bounds.stderr | 50 +-------------- 2 files changed, 50 insertions(+), 71 deletions(-) diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 0a42a31fb8cf..537e6eafb175 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -4,7 +4,7 @@ use clippy_utils::{SpanlessEq, SpanlessHash}; use core::hash::{Hash, Hasher}; use if_chain::if_chain; use itertools::Itertools; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::unhash::UnhashMap; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -238,31 +238,58 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { return; } - let mut map = FxHashMap::<_, Vec<_>>::default(); - for predicate in gen.predicates { + // Explanation: + // fn bad_foo(arg0: T, arg1: Z) + // where T: Clone + Default, { unimplemented!(); } + // ^^^^^^^^^^^^^^^^^^ + // | + // collects each of these where clauses into a set keyed by generic name and comparable trait + // eg. (T, Clone) + let where_predicates = gen + .predicates + .iter() + .filter_map(|pred| { + if_chain! { + if pred.in_where_clause(); + if let WherePredicate::BoundPredicate(bound_predicate) = pred; + if let TyKind::Path(QPath::Resolved(_, path)) = bound_predicate.bounded_ty.kind; + then { + return Some(bound_predicate.bounds.iter().filter_map(|t| { + Some((path.res, into_comparable_trait_ref(t.trait_ref()?))) + })) + } + } + None + }) + .flatten() + .collect::>(); + + // Explanation: + // fn bad_foo(arg0: T, arg1: Z) ... + // ^^^^^^^^^^^^^^^^^^ ^^^^^^^ + // | + // compare trait bounds keyed by generic name and comparable trait to collected where + // predicates eg. (T, Clone) + for predicate in gen.predicates.iter().filter(|pred| !pred.in_where_clause()) { if_chain! { - if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate; + if let WherePredicate::BoundPredicate(bound_predicate) = predicate; if bound_predicate.origin != PredicateOrigin::ImplTrait; if !bound_predicate.span.from_expansion(); - if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind; - if let Some(segment) = segments.first(); + if let TyKind::Path(QPath::Resolved(_, path)) = bound_predicate.bounded_ty.kind; then { - for (res_where, _, span_where) in bound_predicate.bounds.iter().filter_map(get_trait_info_from_bound) { - let trait_resolutions_direct = map.entry(segment.ident).or_default(); - if let Some((_, span_direct)) = trait_resolutions_direct - .iter() - .find(|(res_direct, _)| *res_direct == res_where) { - span_lint_and_help( - cx, - TRAIT_DUPLICATION_IN_BOUNDS, - *span_direct, - "this trait bound is already specified in the where clause", - None, - "consider removing this trait bound", - ); - } - else { - trait_resolutions_direct.push((res_where, span_where)); + for t in bound_predicate.bounds { + if let Some(trait_ref) = t.trait_ref() { + let key = (path.res, into_comparable_trait_ref(trait_ref)); + if where_predicates.contains(&key) { + span_lint_and_help( + cx, + TRAIT_DUPLICATION_IN_BOUNDS, + t.span(), + "this trait bound is already specified in the where clause", + None, + "consider removing this trait bound", + ); + } } } } diff --git a/tests/ui/trait_duplication_in_bounds.stderr b/tests/ui/trait_duplication_in_bounds.stderr index 7ef04e52708f..9b603fdea327 100644 --- a/tests/ui/trait_duplication_in_bounds.stderr +++ b/tests/ui/trait_duplication_in_bounds.stderr @@ -67,28 +67,12 @@ LL | Self: Iterator, | = help: consider removing this trait bound -error: this trait bound is already specified in the where clause - --> $DIR/trait_duplication_in_bounds.rs:103:19 - | -LL | fn bad_foo(arg0: T, argo1: U) { - | ^^^^^ - | - = help: consider removing this trait bound - error: these bounds contain repeated elements --> $DIR/trait_duplication_in_bounds.rs:103:19 | LL | fn bad_foo(arg0: T, argo1: U) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` -error: this trait bound is already specified in the where clause - --> $DIR/trait_duplication_in_bounds.rs:109:12 - | -LL | T: Clone + Clone + Clone + Copy, - | ^^^^^ - | - = help: consider removing this trait bound - error: these where clauses contain repeated elements --> $DIR/trait_duplication_in_bounds.rs:109:12 | @@ -107,14 +91,6 @@ error: these where clauses contain repeated elements LL | Self: Clone + Clone + Clone; | ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone` -error: this trait bound is already specified in the where clause - --> $DIR/trait_duplication_in_bounds.rs:158:28 - | -LL | trait BadTraitBound { - | ^^^^^ - | - = help: consider removing this trait bound - error: these bounds contain repeated elements --> $DIR/trait_duplication_in_bounds.rs:158:28 | @@ -127,41 +103,17 @@ error: these where clauses contain repeated elements LL | T: Clone + Clone + Clone + Copy, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` -error: this trait bound is already specified in the where clause - --> $DIR/trait_duplication_in_bounds.rs:195:24 - | -LL | fn good_generic + GenericTrait>(arg0: T) { - | ^^^^^^^^^^^^^^^^^ - | - = help: consider removing this trait bound - -error: this trait bound is already specified in the where clause - --> $DIR/trait_duplication_in_bounds.rs:199:23 - | -LL | fn bad_generic + GenericTrait + GenericTrait>(arg0: T) { - | ^^^^^^^^^^^^^^^^^ - | - = help: consider removing this trait bound - error: these bounds contain repeated elements --> $DIR/trait_duplication_in_bounds.rs:199:23 | LL | fn bad_generic + GenericTrait + GenericTrait>(arg0: T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `GenericTrait + GenericTrait` -error: this trait bound is already specified in the where clause - --> $DIR/trait_duplication_in_bounds.rs:207:26 - | -LL | fn qualified_path(arg0: T) { - | ^^^^^^^^^^^^^^^^^ - | - = help: consider removing this trait bound - error: these bounds contain repeated elements --> $DIR/trait_duplication_in_bounds.rs:207:26 | LL | fn qualified_path(arg0: T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + foo::Clone` -error: aborting due to 22 previous errors +error: aborting due to 16 previous errors From b96842d7d7b6fbb8509471fb30dfaa8f5877fcb2 Mon Sep 17 00:00:00 2001 From: Allen Hsu Date: Wed, 13 Jul 2022 21:25:19 +1000 Subject: [PATCH 3635/5092] Split unfixable lints. --- tests/compile-test.rs | 1 - tests/ui/trait_duplication_in_bounds.fixed | 112 +++++++++ tests/ui/trait_duplication_in_bounds.rs | 230 +++++------------- tests/ui/trait_duplication_in_bounds.stderr | 137 +++-------- .../trait_duplication_in_bounds_unfixable.rs | 101 ++++++++ ...ait_duplication_in_bounds_unfixable.stderr | 71 ++++++ 6 files changed, 386 insertions(+), 266 deletions(-) create mode 100644 tests/ui/trait_duplication_in_bounds.fixed create mode 100644 tests/ui/trait_duplication_in_bounds_unfixable.rs create mode 100644 tests/ui/trait_duplication_in_bounds_unfixable.stderr diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 92ac1a2be561..610f1f14563d 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -394,7 +394,6 @@ const RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS: &[&str] = &[ "single_component_path_imports_nested_first.rs", "string_add.rs", "toplevel_ref_arg_non_rustfix.rs", - "trait_duplication_in_bounds.rs", "unit_arg.rs", "unnecessary_clone.rs", "unnecessary_lazy_eval_unfixable.rs", diff --git a/tests/ui/trait_duplication_in_bounds.fixed b/tests/ui/trait_duplication_in_bounds.fixed new file mode 100644 index 000000000000..b4e6bf0ea1c2 --- /dev/null +++ b/tests/ui/trait_duplication_in_bounds.fixed @@ -0,0 +1,112 @@ +// run-rustfix +#![deny(clippy::trait_duplication_in_bounds)] +#![allow(unused)] + +fn bad_foo(arg0: T, argo1: U) { + unimplemented!(); +} + +fn bad_bar(arg0: T, arg1: U) +where + T: Clone + Copy, + U: Clone + Copy, +{ + unimplemented!(); +} + +fn good_bar(arg0: T, arg1: U) { + unimplemented!(); +} + +fn good_foo(arg0: T, arg1: U) +where + T: Clone + Copy, + U: Clone + Copy, +{ + unimplemented!(); +} + +trait GoodSelfTraitBound: Clone + Copy { + fn f(); +} + +trait GoodSelfWhereClause { + fn f() + where + Self: Clone + Copy; +} + +trait BadSelfTraitBound: Clone { + fn f(); +} + +trait BadSelfWhereClause { + fn f() + where + Self: Clone; +} + +trait GoodTraitBound { + fn f(); +} + +trait GoodWhereClause { + fn f() + where + T: Clone + Copy, + U: Clone + Copy; +} + +trait BadTraitBound { + fn f(); +} + +trait BadWhereClause { + fn f() + where + T: Clone + Copy, + U: Clone + Copy; +} + +struct GoodStructBound { + t: T, + u: U, +} + +impl GoodTraitBound for GoodStructBound { + // this should not warn + fn f() {} +} + +struct GoodStructWhereClause; + +impl GoodTraitBound for GoodStructWhereClause +where + T: Clone + Copy, + U: Clone + Copy, +{ + // this should not warn + fn f() {} +} + +fn no_error_separate_arg_bounds(program: impl AsRef<()>, dir: impl AsRef<()>, args: &[impl AsRef<()>]) {} + +trait GenericTrait {} + +fn good_generic + GenericTrait>(arg0: T) { + unimplemented!(); +} + +fn bad_generic + GenericTrait>(arg0: T) { + unimplemented!(); +} + +mod foo { + pub trait Clone {} +} + +fn qualified_path(arg0: T) { + unimplemented!(); +} + +fn main() {} diff --git a/tests/ui/trait_duplication_in_bounds.rs b/tests/ui/trait_duplication_in_bounds.rs index a5751c58aab8..7f2e96a22e66 100644 --- a/tests/ui/trait_duplication_in_bounds.rs +++ b/tests/ui/trait_duplication_in_bounds.rs @@ -1,212 +1,112 @@ +// run-rustfix #![deny(clippy::trait_duplication_in_bounds)] #![allow(unused)] -use std::collections::BTreeMap; -use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; +fn bad_foo(arg0: T, argo1: U) { + unimplemented!(); +} -fn bad_foo(arg0: T, arg1: Z) +fn bad_bar(arg0: T, arg1: U) where - T: Clone, - T: Default, + T: Clone + Clone + Clone + Copy, + U: Clone + Copy, { unimplemented!(); } -fn good_bar(arg: T) { +fn good_bar(arg0: T, arg1: U) { unimplemented!(); } -fn good_foo(arg: T) +fn good_foo(arg0: T, arg1: U) where - T: Clone + Default, + T: Clone + Copy, + U: Clone + Copy, { unimplemented!(); } -fn good_foobar(arg: T) -where - T: Clone, -{ - unimplemented!(); +trait GoodSelfTraitBound: Clone + Copy { + fn f(); } -trait T: Default { +trait GoodSelfWhereClause { fn f() where - Self: Default; + Self: Clone + Copy; } -trait U: Default { +trait BadSelfTraitBound: Clone + Clone + Clone { + fn f(); +} + +trait BadSelfWhereClause { fn f() where - Self: Clone; + Self: Clone + Clone + Clone; } -trait ZZ: Default { - fn g(); - fn h(); +trait GoodTraitBound { + fn f(); +} + +trait GoodWhereClause { fn f() where - Self: Default + Clone; + T: Clone + Copy, + U: Clone + Copy; } -trait BadTrait: Default + Clone { +trait BadTraitBound { + fn f(); +} + +trait BadWhereClause { fn f() - where - Self: Default + Clone; - fn g() - where - Self: Default; - fn h() - where - Self: Copy; -} - -#[derive(Default, Clone)] -struct Life; - -impl T for Life { - // this should not warn - fn f() {} -} - -impl U for Life { - // this should not warn - fn f() {} -} - -// should not warn -trait Iter: Iterator { - fn into_group_btreemap(self) -> BTreeMap> - where - Self: Iterator + Sized, - K: Ord + Eq, - { - unimplemented!(); - } -} - -struct Foo; - -trait FooIter: Iterator { - fn bar() - where - Self: Iterator, - { - } -} - -// This should not lint -fn impl_trait(_: impl AsRef, _: impl AsRef) {} - -mod repeated_where_clauses_or_trait_bounds { - fn bad_foo(arg0: T, argo1: U) { - unimplemented!(); - } - - fn bad_bar(arg0: T, arg1: U) where T: Clone + Clone + Clone + Copy, - U: Clone + Copy, - { - unimplemented!(); - } + U: Clone + Copy; +} - fn good_bar(arg0: T, arg1: U) { - unimplemented!(); - } +struct GoodStructBound { + t: T, + u: U, +} - fn good_foo(arg0: T, arg1: U) - where - T: Clone + Copy, - U: Clone + Copy, - { - unimplemented!(); - } +impl GoodTraitBound for GoodStructBound { + // this should not warn + fn f() {} +} - trait GoodSelfTraitBound: Clone + Copy { - fn f(); - } +struct GoodStructWhereClause; - trait GoodSelfWhereClause { - fn f() - where - Self: Clone + Copy; - } +impl GoodTraitBound for GoodStructWhereClause +where + T: Clone + Copy, + U: Clone + Copy, +{ + // this should not warn + fn f() {} +} - trait BadSelfTraitBound: Clone + Clone + Clone { - fn f(); - } +fn no_error_separate_arg_bounds(program: impl AsRef<()>, dir: impl AsRef<()>, args: &[impl AsRef<()>]) {} - trait BadSelfWhereClause { - fn f() - where - Self: Clone + Clone + Clone; - } +trait GenericTrait {} - trait GoodTraitBound { - fn f(); - } +fn good_generic + GenericTrait>(arg0: T) { + unimplemented!(); +} - trait GoodWhereClause { - fn f() - where - T: Clone + Copy, - U: Clone + Copy; - } +fn bad_generic + GenericTrait + GenericTrait>(arg0: T) { + unimplemented!(); +} - trait BadTraitBound { - fn f(); - } +mod foo { + pub trait Clone {} +} - trait BadWhereClause { - fn f() - where - T: Clone + Clone + Clone + Copy, - U: Clone + Copy; - } - - struct GoodStructBound { - t: T, - u: U, - } - - impl GoodTraitBound for GoodStructBound { - // this should not warn - fn f() {} - } - - struct GoodStructWhereClause; - - impl GoodTraitBound for GoodStructWhereClause - where - T: Clone + Copy, - U: Clone + Copy, - { - // this should not warn - fn f() {} - } - - fn no_error_separate_arg_bounds(program: impl AsRef<()>, dir: impl AsRef<()>, args: &[impl AsRef<()>]) {} - - trait GenericTrait {} - - // This should not warn but currently does see #8757 - fn good_generic + GenericTrait>(arg0: T) { - unimplemented!(); - } - - fn bad_generic + GenericTrait + GenericTrait>(arg0: T) { - unimplemented!(); - } - - mod foo { - pub trait Clone {} - } - - fn qualified_path(arg0: T) { - unimplemented!(); - } +fn qualified_path(arg0: T) { + unimplemented!(); } fn main() {} diff --git a/tests/ui/trait_duplication_in_bounds.stderr b/tests/ui/trait_duplication_in_bounds.stderr index 9b603fdea327..86c593811a74 100644 --- a/tests/ui/trait_duplication_in_bounds.stderr +++ b/tests/ui/trait_duplication_in_bounds.stderr @@ -1,119 +1,56 @@ -error: this trait bound is already specified in the where clause - --> $DIR/trait_duplication_in_bounds.rs:7:15 +error: these bounds contain repeated elements + --> $DIR/trait_duplication_in_bounds.rs:5:15 | -LL | fn bad_foo(arg0: T, arg1: Z) - | ^^^^^ +LL | fn bad_foo(arg0: T, argo1: U) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` | note: the lint level is defined here - --> $DIR/trait_duplication_in_bounds.rs:1:9 + --> $DIR/trait_duplication_in_bounds.rs:2:9 | LL | #![deny(clippy::trait_duplication_in_bounds)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: consider removing this trait bound - -error: this trait bound is already specified in the where clause - --> $DIR/trait_duplication_in_bounds.rs:7:23 - | -LL | fn bad_foo(arg0: T, arg1: Z) - | ^^^^^^^ - | - = help: consider removing this trait bound - -error: this trait bound is already specified in trait declaration - --> $DIR/trait_duplication_in_bounds.rs:36:15 - | -LL | Self: Default; - | ^^^^^^^ - | - = help: consider removing this trait bound - -error: this trait bound is already specified in trait declaration - --> $DIR/trait_duplication_in_bounds.rs:50:15 - | -LL | Self: Default + Clone; - | ^^^^^^^ - | - = help: consider removing this trait bound - -error: this trait bound is already specified in trait declaration - --> $DIR/trait_duplication_in_bounds.rs:56:15 - | -LL | Self: Default + Clone; - | ^^^^^^^ - | - = help: consider removing this trait bound - -error: this trait bound is already specified in trait declaration - --> $DIR/trait_duplication_in_bounds.rs:56:25 - | -LL | Self: Default + Clone; - | ^^^^^ - | - = help: consider removing this trait bound - -error: this trait bound is already specified in trait declaration - --> $DIR/trait_duplication_in_bounds.rs:59:15 - | -LL | Self: Default; - | ^^^^^^^ - | - = help: consider removing this trait bound - -error: this trait bound is already specified in trait declaration - --> $DIR/trait_duplication_in_bounds.rs:94:15 - | -LL | Self: Iterator, - | ^^^^^^^^^^^^^^^^^^^^ - | - = help: consider removing this trait bound - -error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:103:19 - | -LL | fn bad_foo(arg0: T, argo1: U) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` error: these where clauses contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:109:12 + --> $DIR/trait_duplication_in_bounds.rs:11:8 + | +LL | T: Clone + Clone + Clone + Copy, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` + +error: these bounds contain repeated elements + --> $DIR/trait_duplication_in_bounds.rs:39:26 + | +LL | trait BadSelfTraitBound: Clone + Clone + Clone { + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone` + +error: these where clauses contain repeated elements + --> $DIR/trait_duplication_in_bounds.rs:46:15 + | +LL | Self: Clone + Clone + Clone; + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone` + +error: these bounds contain repeated elements + --> $DIR/trait_duplication_in_bounds.rs:60:24 + | +LL | trait BadTraitBound { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` + +error: these where clauses contain repeated elements + --> $DIR/trait_duplication_in_bounds.rs:67:12 | LL | T: Clone + Clone + Clone + Copy, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:137:30 + --> $DIR/trait_duplication_in_bounds.rs:100:19 | -LL | trait BadSelfTraitBound: Clone + Clone + Clone { - | ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone` - -error: these where clauses contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:144:19 - | -LL | Self: Clone + Clone + Clone; - | ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone` +LL | fn bad_generic + GenericTrait + GenericTrait>(arg0: T) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `GenericTrait + GenericTrait` error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:158:28 + --> $DIR/trait_duplication_in_bounds.rs:108:22 | -LL | trait BadTraitBound { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` +LL | fn qualified_path(arg0: T) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + foo::Clone` -error: these where clauses contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:165:16 - | -LL | T: Clone + Clone + Clone + Copy, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` - -error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:199:23 - | -LL | fn bad_generic + GenericTrait + GenericTrait>(arg0: T) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `GenericTrait + GenericTrait` - -error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:207:26 - | -LL | fn qualified_path(arg0: T) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + foo::Clone` - -error: aborting due to 16 previous errors +error: aborting due to 8 previous errors diff --git a/tests/ui/trait_duplication_in_bounds_unfixable.rs b/tests/ui/trait_duplication_in_bounds_unfixable.rs new file mode 100644 index 000000000000..a21d4c5d637d --- /dev/null +++ b/tests/ui/trait_duplication_in_bounds_unfixable.rs @@ -0,0 +1,101 @@ +#![deny(clippy::trait_duplication_in_bounds)] + +use std::collections::BTreeMap; +use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; + +fn bad_foo(arg0: T, arg1: Z) +where + T: Clone, + T: Default, +{ + unimplemented!(); +} + +fn good_bar(arg: T) { + unimplemented!(); +} + +fn good_foo(arg: T) +where + T: Clone + Default, +{ + unimplemented!(); +} + +fn good_foobar(arg: T) +where + T: Clone, +{ + unimplemented!(); +} + +trait T: Default { + fn f() + where + Self: Default; +} + +trait U: Default { + fn f() + where + Self: Clone; +} + +trait ZZ: Default { + fn g(); + fn h(); + fn f() + where + Self: Default + Clone; +} + +trait BadTrait: Default + Clone { + fn f() + where + Self: Default + Clone; + fn g() + where + Self: Default; + fn h() + where + Self: Copy; +} + +#[derive(Default, Clone)] +struct Life; + +impl T for Life { + // this should not warn + fn f() {} +} + +impl U for Life { + // this should not warn + fn f() {} +} + +// should not warn +trait Iter: Iterator { + fn into_group_btreemap(self) -> BTreeMap> + where + Self: Iterator + Sized, + K: Ord + Eq, + { + unimplemented!(); + } +} + +struct Foo; + +trait FooIter: Iterator { + fn bar() + where + Self: Iterator, + { + } +} + +// This should not lint +fn impl_trait(_: impl AsRef, _: impl AsRef) {} + +fn main() {} diff --git a/tests/ui/trait_duplication_in_bounds_unfixable.stderr b/tests/ui/trait_duplication_in_bounds_unfixable.stderr new file mode 100644 index 000000000000..fbd9abb005f1 --- /dev/null +++ b/tests/ui/trait_duplication_in_bounds_unfixable.stderr @@ -0,0 +1,71 @@ +error: this trait bound is already specified in the where clause + --> $DIR/trait_duplication_in_bounds_unfixable.rs:6:15 + | +LL | fn bad_foo(arg0: T, arg1: Z) + | ^^^^^ + | +note: the lint level is defined here + --> $DIR/trait_duplication_in_bounds_unfixable.rs:1:9 + | +LL | #![deny(clippy::trait_duplication_in_bounds)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: consider removing this trait bound + +error: this trait bound is already specified in the where clause + --> $DIR/trait_duplication_in_bounds_unfixable.rs:6:23 + | +LL | fn bad_foo(arg0: T, arg1: Z) + | ^^^^^^^ + | + = help: consider removing this trait bound + +error: this trait bound is already specified in trait declaration + --> $DIR/trait_duplication_in_bounds_unfixable.rs:35:15 + | +LL | Self: Default; + | ^^^^^^^ + | + = help: consider removing this trait bound + +error: this trait bound is already specified in trait declaration + --> $DIR/trait_duplication_in_bounds_unfixable.rs:49:15 + | +LL | Self: Default + Clone; + | ^^^^^^^ + | + = help: consider removing this trait bound + +error: this trait bound is already specified in trait declaration + --> $DIR/trait_duplication_in_bounds_unfixable.rs:55:15 + | +LL | Self: Default + Clone; + | ^^^^^^^ + | + = help: consider removing this trait bound + +error: this trait bound is already specified in trait declaration + --> $DIR/trait_duplication_in_bounds_unfixable.rs:55:25 + | +LL | Self: Default + Clone; + | ^^^^^ + | + = help: consider removing this trait bound + +error: this trait bound is already specified in trait declaration + --> $DIR/trait_duplication_in_bounds_unfixable.rs:58:15 + | +LL | Self: Default; + | ^^^^^^^ + | + = help: consider removing this trait bound + +error: this trait bound is already specified in trait declaration + --> $DIR/trait_duplication_in_bounds_unfixable.rs:93:15 + | +LL | Self: Iterator, + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider removing this trait bound + +error: aborting due to 8 previous errors + From 3ddc04f4db1f768f74fe9e21a4ef119c186295a0 Mon Sep 17 00:00:00 2001 From: Allen Hsu Date: Wed, 13 Jul 2022 21:39:52 +1000 Subject: [PATCH 3636/5092] Add extra test cases from #8771, #8757, #9076. --- .../trait_duplication_in_bounds_unfixable.rs | 67 ++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/tests/ui/trait_duplication_in_bounds_unfixable.rs b/tests/ui/trait_duplication_in_bounds_unfixable.rs index a21d4c5d637d..5630a0345adb 100644 --- a/tests/ui/trait_duplication_in_bounds_unfixable.rs +++ b/tests/ui/trait_duplication_in_bounds_unfixable.rs @@ -95,7 +95,72 @@ trait FooIter: Iterator { } } -// This should not lint +// The below should not lint and exist to guard against false positives fn impl_trait(_: impl AsRef, _: impl AsRef) {} +pub mod one { + #[derive(Clone, Debug)] + struct MultiProductIter + where + I: Iterator + Clone, + I::Item: Clone, + { + _marker: I, + } + + pub struct MultiProduct(Vec>) + where + I: Iterator + Clone, + I::Item: Clone; + + pub fn multi_cartesian_product(_: H) -> MultiProduct<::IntoIter> + where + H: Iterator, + H::Item: IntoIterator, + ::IntoIter: Clone, + ::Item: Clone, + { + todo!() + } +} + +pub mod two { + use std::iter::Peekable; + + pub struct MergeBy + where + I: Iterator, + J: Iterator, + { + _i: Peekable, + _j: Peekable, + _f: F, + } + + impl Clone for MergeBy + where + I: Iterator, + J: Iterator, + std::iter::Peekable: Clone, + std::iter::Peekable: Clone, + F: Clone, + { + fn clone(&self) -> Self { + Self { + _i: self._i.clone(), + _j: self._j.clone(), + _f: self._f.clone(), + } + } + } +} + +pub trait Trait {} + +pub fn f(_a: impl Trait, _b: impl Trait) {} + +pub trait ImplTrait {} + +impl ImplTrait<(A, B)> for Foo where Foo: ImplTrait + ImplTrait {} + fn main() {} From b43bede93826f459e210957c8fd12fc1dd77d678 Mon Sep 17 00:00:00 2001 From: Christian Legnitto Date: Thu, 30 Jun 2022 13:10:31 -0400 Subject: [PATCH 3637/5092] Add shim for `realpath` on unix --- src/helpers.rs | 1 + src/shims/unix/foreign_items.rs | 5 + src/shims/unix/fs.rs | 62 ++++++++++++ src/shims/unix/macos/foreign_items.rs | 6 ++ tests/pass/fs.rs | 19 ++++ tests/pass/libc.rs | 133 +++++++++++++++++++++++++- 6 files changed, 224 insertions(+), 2 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 01fc8e0df3f0..766a3cba734b 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -37,6 +37,7 @@ const UNIX_IO_ERROR_TABLE: &[(std::io::ErrorKind, &str)] = { (NotFound, "ENOENT"), (Interrupted, "EINTR"), (InvalidInput, "EINVAL"), + (InvalidFilename, "ENAMETOOLONG"), (TimedOut, "ETIMEDOUT"), (AlreadyExists, "EEXIST"), (WouldBlock, "EWOULDBLOCK"), diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 2a051fb77539..5eb2d0a6cac2 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -161,6 +161,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // fadvise is only informational, we can ignore it. this.write_null(dest)?; } + "realpath" => { + let [path, resolved_path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.realpath(path, resolved_path)?; + this.write_pointer(result, dest)?; + } // Time related shims "gettimeofday" => { diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index c9f35c048917..76c170987912 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -1,5 +1,6 @@ use std::borrow::Cow; use std::collections::BTreeMap; +use std::convert::TryInto; use std::fs::{ read_dir, remove_dir, remove_file, rename, DirBuilder, File, FileType, OpenOptions, ReadDir, }; @@ -1662,6 +1663,67 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.set_last_error(enotty)?; Ok(0) } + + fn realpath( + &mut self, + path_op: &OpTy<'tcx, Provenance>, + processed_path_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, Pointer>> { + let this = self.eval_context_mut(); + this.assert_target_os_is_unix("realpath"); + + let pathname = this.read_path_from_c_str(this.read_pointer(path_op)?)?; + let processed_ptr = this.read_pointer(processed_path_op)?; + + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`realpath`", reject_with)?; + let eacc = this.eval_libc("EACCES")?; + this.set_last_error(eacc)?; + return Ok(Pointer::null()); + } + + let result = std::fs::canonicalize(pathname); + match result { + Ok(resolved) => { + let path_max = this + .eval_libc_i32("PATH_MAX")? + .try_into() + .expect("PATH_MAX does not fit in u64"); + let dest = if this.ptr_is_null(processed_ptr)? { + // POSIX says behavior when passing a null pointer is implementation-defined, + // but GNU/linux, freebsd, netbsd, bionic/android, and macos all treat a null pointer + // similarly to: + // + // "If resolved_path is specified as NULL, then realpath() uses + // malloc(3) to allocate a buffer of up to PATH_MAX bytes to hold + // the resolved pathname, and returns a pointer to this buffer. The + // caller should deallocate this buffer using free(3)." + // + this.alloc_os_str_as_c_str(resolved.as_os_str(), MiriMemoryKind::C.into())? + } else { + let (wrote_path, _) = + this.write_path_to_c_str(&resolved, processed_ptr, path_max)?; + + if !wrote_path { + // Note that we do not explicitly handle `FILENAME_MAX` + // (different from `PATH_MAX` above) as it is Linux-specific and + // seems like a bit of a mess anyway: . + let enametoolong = this.eval_libc("ENAMETOOLONG")?; + this.set_last_error(enametoolong)?; + return Ok(Pointer::null()); + } + processed_ptr + }; + + Ok(dest) + } + Err(e) => { + this.set_last_error_from_io_error(e.kind())?; + Ok(Pointer::null()) + } + } + } } /// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch when diff --git a/src/shims/unix/macos/foreign_items.rs b/src/shims/unix/macos/foreign_items.rs index 21c7762c3ca1..fb545d8b5847 100644 --- a/src/shims/unix/macos/foreign_items.rs +++ b/src/shims/unix/macos/foreign_items.rs @@ -73,6 +73,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "realpath$DARWIN_EXTSN" => { + let [path, resolved_path] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.realpath(path, resolved_path)?; + this.write_pointer(result, dest)?; + } // Environment related shims "_NSGetEnviron" => { diff --git a/tests/pass/fs.rs b/tests/pass/fs.rs index 9d59fedb20ed..a8025007bf5f 100644 --- a/tests/pass/fs.rs +++ b/tests/pass/fs.rs @@ -24,6 +24,7 @@ fn main() { test_errors(); test_rename(); test_directory(); + test_canonicalize(); test_dup_stdout_stderr(); // These all require unix, if the test is changed to no longer `ignore-windows`, move these to a unix test @@ -365,6 +366,24 @@ fn test_rename() { remove_file(&path2).unwrap(); } +fn test_canonicalize() { + use std::fs::canonicalize; + let dir_path = prepare_dir("miri_test_fs_dir"); + create_dir(&dir_path).unwrap(); + let path = dir_path.join("test_file"); + drop(File::create(&path).unwrap()); + + let p = canonicalize(format!("{}/./test_file", dir_path.to_string_lossy())).unwrap(); + assert_eq!(p.to_string_lossy().find('.'), None); + + remove_dir_all(&dir_path).unwrap(); + + // Make sure we get an error for long paths. + use std::convert::TryInto; + let too_long = "x/".repeat(libc::PATH_MAX.try_into().unwrap()); + assert!(canonicalize(too_long).is_err()); +} + fn test_directory() { let dir_path = prepare_dir("miri_test_fs_dir"); // Creating a directory should succeed. diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index 9b83ab45b0c0..2735e5b25bc3 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -1,16 +1,141 @@ //@ignore-target-windows: No libc on Windows //@compile-flags: -Zmiri-disable-isolation +#![feature(io_error_more)] #![feature(rustc_private)] use std::fs::{remove_file, File}; use std::os::unix::io::AsRawFd; +use std::path::PathBuf; -fn tmp() -> std::path::PathBuf { +fn tmp() -> PathBuf { std::env::var("MIRI_TEMP") - .map(std::path::PathBuf::from) + .map(|tmp| { + // MIRI_TEMP is set outside of our emulated + // program, so it may have path separators that don't + // correspond to our target platform. We normalize them here + // before constructing a `PathBuf` + return PathBuf::from(tmp.replace("\\", "/")); + }) .unwrap_or_else(|_| std::env::temp_dir()) } +/// Test allocating variant of `realpath`. +fn test_posix_realpath_alloc() { + use std::ffi::OsString; + use std::ffi::{CStr, CString}; + use std::fs::{remove_file, File}; + use std::os::unix::ffi::OsStrExt; + use std::os::unix::ffi::OsStringExt; + + let buf; + let path = tmp().join("miri_test_libc_posix_realpath_alloc"); + let c_path = CString::new(path.as_os_str().as_bytes()).expect("CString::new failed"); + + // Cleanup before test. + remove_file(&path).ok(); + // Create file. + drop(File::create(&path).unwrap()); + unsafe { + let r = libc::realpath(c_path.as_ptr(), std::ptr::null_mut()); + assert!(!r.is_null()); + buf = CStr::from_ptr(r).to_bytes().to_vec(); + libc::free(r as *mut _); + } + let canonical = PathBuf::from(OsString::from_vec(buf)); + assert_eq!(path.file_name(), canonical.file_name()); + + // Cleanup after test. + remove_file(&path).unwrap(); +} + +/// Test non-allocating variant of `realpath`. +fn test_posix_realpath_noalloc() { + use std::ffi::{CStr, CString}; + use std::fs::{remove_file, File}; + use std::os::unix::ffi::OsStrExt; + + let path = tmp().join("miri_test_libc_posix_realpath_noalloc"); + let c_path = CString::new(path.as_os_str().as_bytes()).expect("CString::new failed"); + + let mut v = vec![0; libc::PATH_MAX as usize]; + + // Cleanup before test. + remove_file(&path).ok(); + // Create file. + drop(File::create(&path).unwrap()); + unsafe { + let r = libc::realpath(c_path.as_ptr(), v.as_mut_ptr()); + assert!(!r.is_null()); + } + let c = unsafe { CStr::from_ptr(v.as_ptr()) }; + let canonical = PathBuf::from(c.to_str().expect("CStr to str")); + + assert_eq!(path.file_name(), canonical.file_name()); + + // Cleanup after test. + remove_file(&path).unwrap(); +} + +/// Test failure cases for `realpath`. +fn test_posix_realpath_errors() { + use std::convert::TryInto; + use std::ffi::CString; + use std::fs::{create_dir_all, remove_dir_all}; + use std::io::ErrorKind; + use std::os::unix::ffi::OsStrExt; + use std::os::unix::fs::symlink; + + // Test non-existent path returns an error. + let c_path = CString::new("./nothing_to_see_here").expect("CString::new failed"); + let r = unsafe { libc::realpath(c_path.as_ptr(), std::ptr::null_mut()) }; + assert!(r.is_null()); + let e = std::io::Error::last_os_error(); + assert_eq!(e.raw_os_error(), Some(libc::ENOENT)); + assert_eq!(e.kind(), ErrorKind::NotFound); + + // Test that a long path returns an error. + // + // Linux first checks if the path exists and macos does not. + // Using an existing path ensures all platforms return `ENAMETOOLONG` given a long path. + // + // Rather than creating a bunch of directories, we create two directories containing symlinks. + // Sadly we can't avoid creating directories and instead use a path like "./././././" or "./../../" as linux + // appears to collapse "." and ".." before checking path length. + let path = tmp().join("posix_realpath_errors"); + // Cleanup before test. + remove_dir_all(&path).ok(); + + // The directories we will put symlinks in. + let x = path.join("x/"); + let y = path.join("y/"); + + // The symlinks in each directory pointing to each other. + let yx_sym = y.join("x"); + let xy_sym = x.join("y"); + + // Create directories. + create_dir_all(&x).expect("dir x"); + create_dir_all(&y).expect("dir y"); + + // Create symlinks between directories. + symlink(&x, &yx_sym).expect("symlink x"); + symlink(&y, &xy_sym).expect("symlink y "); + + // This path exists due to the symlinks created above. + let too_long = path.join("x/y/".repeat(libc::PATH_MAX.try_into().unwrap())); + + let c_path = CString::new(too_long.into_os_string().as_bytes()).expect("CString::new failed"); + let r = unsafe { libc::realpath(c_path.as_ptr(), std::ptr::null_mut()) }; + let e = std::io::Error::last_os_error(); + + assert!(r.is_null()); + assert_eq!(e.raw_os_error(), Some(libc::ENAMETOOLONG)); + assert_eq!(e.kind(), ErrorKind::InvalidFilename); + + // Cleanup after test. + remove_dir_all(&path).ok(); +} + #[cfg(any(target_os = "linux", target_os = "freebsd"))] fn test_posix_fadvise() { use std::convert::TryInto; @@ -336,6 +461,10 @@ fn main() { test_posix_gettimeofday(); + test_posix_realpath_alloc(); + test_posix_realpath_noalloc(); + test_posix_realpath_errors(); + #[cfg(any(target_os = "linux"))] test_sync_file_range(); From 8356f4cc23ea4c2403011b6c2c619738fce7e32a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Aug 2022 18:08:43 -0400 Subject: [PATCH 3638/5092] output realpath as a path, and remove a bogus test --- src/helpers.rs | 1 + src/shims/os_str.rs | 13 ++++++++++++ src/shims/unix/fs.rs | 2 +- tests/pass/libc.rs | 48 -------------------------------------------- 4 files changed, 15 insertions(+), 49 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 766a3cba734b..acc2367afa28 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -42,6 +42,7 @@ const UNIX_IO_ERROR_TABLE: &[(std::io::ErrorKind, &str)] = { (AlreadyExists, "EEXIST"), (WouldBlock, "EWOULDBLOCK"), (DirectoryNotEmpty, "ENOTEMPTY"), + (FilesystemLoop, "ELOOP"), ] }; diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 71824bee346e..b9f3a435ea42 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -250,6 +250,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_os_str_to_wide_str(&os_str, ptr, size) } + /// Allocate enough memory to store a Path as a null-terminated sequence of bytes, + /// adjusting path separators if needed. + fn alloc_path_as_c_str( + &mut self, + path: &Path, + memkind: MemoryKind, + ) -> InterpResult<'tcx, Pointer>> { + let this = self.eval_context_mut(); + let os_str = this + .convert_path_separator(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); + this.alloc_os_str_as_c_str(&os_str, memkind) + } + fn convert_path_separator<'a>( &self, os_str: Cow<'a, OsStr>, diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index 76c170987912..36be1ec4f6fa 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -1700,7 +1700,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // the resolved pathname, and returns a pointer to this buffer. The // caller should deallocate this buffer using free(3)." // - this.alloc_os_str_as_c_str(resolved.as_os_str(), MiriMemoryKind::C.into())? + this.alloc_path_as_c_str(&resolved, MiriMemoryKind::C.into())? } else { let (wrote_path, _) = this.write_path_to_c_str(&resolved, processed_ptr, path_max)?; diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index 2735e5b25bc3..c7331b110e9a 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -23,7 +23,6 @@ fn tmp() -> PathBuf { fn test_posix_realpath_alloc() { use std::ffi::OsString; use std::ffi::{CStr, CString}; - use std::fs::{remove_file, File}; use std::os::unix::ffi::OsStrExt; use std::os::unix::ffi::OsStringExt; @@ -51,7 +50,6 @@ fn test_posix_realpath_alloc() { /// Test non-allocating variant of `realpath`. fn test_posix_realpath_noalloc() { use std::ffi::{CStr, CString}; - use std::fs::{remove_file, File}; use std::os::unix::ffi::OsStrExt; let path = tmp().join("miri_test_libc_posix_realpath_noalloc"); @@ -78,12 +76,8 @@ fn test_posix_realpath_noalloc() { /// Test failure cases for `realpath`. fn test_posix_realpath_errors() { - use std::convert::TryInto; use std::ffi::CString; - use std::fs::{create_dir_all, remove_dir_all}; use std::io::ErrorKind; - use std::os::unix::ffi::OsStrExt; - use std::os::unix::fs::symlink; // Test non-existent path returns an error. let c_path = CString::new("./nothing_to_see_here").expect("CString::new failed"); @@ -92,48 +86,6 @@ fn test_posix_realpath_errors() { let e = std::io::Error::last_os_error(); assert_eq!(e.raw_os_error(), Some(libc::ENOENT)); assert_eq!(e.kind(), ErrorKind::NotFound); - - // Test that a long path returns an error. - // - // Linux first checks if the path exists and macos does not. - // Using an existing path ensures all platforms return `ENAMETOOLONG` given a long path. - // - // Rather than creating a bunch of directories, we create two directories containing symlinks. - // Sadly we can't avoid creating directories and instead use a path like "./././././" or "./../../" as linux - // appears to collapse "." and ".." before checking path length. - let path = tmp().join("posix_realpath_errors"); - // Cleanup before test. - remove_dir_all(&path).ok(); - - // The directories we will put symlinks in. - let x = path.join("x/"); - let y = path.join("y/"); - - // The symlinks in each directory pointing to each other. - let yx_sym = y.join("x"); - let xy_sym = x.join("y"); - - // Create directories. - create_dir_all(&x).expect("dir x"); - create_dir_all(&y).expect("dir y"); - - // Create symlinks between directories. - symlink(&x, &yx_sym).expect("symlink x"); - symlink(&y, &xy_sym).expect("symlink y "); - - // This path exists due to the symlinks created above. - let too_long = path.join("x/y/".repeat(libc::PATH_MAX.try_into().unwrap())); - - let c_path = CString::new(too_long.into_os_string().as_bytes()).expect("CString::new failed"); - let r = unsafe { libc::realpath(c_path.as_ptr(), std::ptr::null_mut()) }; - let e = std::io::Error::last_os_error(); - - assert!(r.is_null()); - assert_eq!(e.raw_os_error(), Some(libc::ENAMETOOLONG)); - assert_eq!(e.kind(), ErrorKind::InvalidFilename); - - // Cleanup after test. - remove_dir_all(&path).ok(); } #[cfg(any(target_os = "linux", target_os = "freebsd"))] From 87b9075920ae46aeb5e97220ea02cd88fa1d5652 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Aug 2022 18:27:06 -0400 Subject: [PATCH 3639/5092] avoid double-space in test logging --- ui_test/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index bcc48b4b6316..9206c0f3d8e5 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -194,9 +194,9 @@ pub fn run_tests(mut config: Config) -> Result<()> { run_test(&path, &config, &target, &revision, &comments); // Using a single `eprintln!` to prevent messages from threads from getting intermingled. - let mut msg = format!("{} ", path.display()); + let mut msg = format!("{}", path.display()); if !revision.is_empty() { - write!(msg, "(revision `{revision}`) ").unwrap(); + write!(msg, " (revision `{revision}`) ").unwrap(); } if errors.is_empty() { finished_files_sender.send((msg, TestResult::Ok))?; From b29e7b8e4e4539eb1d916cf14123595858b79185 Mon Sep 17 00:00:00 2001 From: Christian Legnitto Date: Fri, 8 Jul 2022 01:51:16 -0400 Subject: [PATCH 3640/5092] Add `mkstemp` shim for unix Co-authored-by: Ralf Jung --- src/shims/unix/foreign_items.rs | 5 + src/shims/unix/fs.rs | 130 ++++++++++++++++++++- tests/fail/fs/mkstemp_immutable_arg.rs | 13 +++ tests/fail/fs/mkstemp_immutable_arg.stderr | 20 ++++ tests/pass/libc.rs | 45 +++++++ 5 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 tests/fail/fs/mkstemp_immutable_arg.rs create mode 100644 tests/fail/fs/mkstemp_immutable_arg.stderr diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 5eb2d0a6cac2..83815cccb0c4 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -166,6 +166,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.realpath(path, resolved_path)?; this.write_pointer(result, dest)?; } + "mkstemp" => { + let [template] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.mkstemp(template)?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } // Time related shims "gettimeofday" => { diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index 36be1ec4f6fa..9b00579d873b 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -5,7 +5,7 @@ use std::fs::{ read_dir, remove_dir, remove_file, rename, DirBuilder, File, FileType, OpenOptions, ReadDir, }; use std::io::{self, ErrorKind, Read, Seek, SeekFrom, Write}; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::time::SystemTime; use log::trace; @@ -14,6 +14,7 @@ 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; use crate::*; use shims::os_str::os_str_to_bytes; use shims::time::system_time_to_duration; @@ -1724,6 +1725,133 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } + fn mkstemp(&mut self, template_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + use rand::seq::SliceRandom; + + // POSIX defines the template string. + const TEMPFILE_TEMPLATE_STR: &str = "XXXXXX"; + + let this = self.eval_context_mut(); + this.assert_target_os_is_unix("mkstemp"); + + // POSIX defines the maximum number of attempts before failure. + // + // `mkstemp()` relies on `tmpnam()` which in turn relies on `TMP_MAX`. + // POSIX says this about `TMP_MAX`: + // * Minimum number of unique filenames generated by `tmpnam()`. + // * Maximum number of times an application can call `tmpnam()` reliably. + // * The value of `TMP_MAX` is at least 25. + // * On XSI-conformant systems, the value of `TMP_MAX` is at least 10000. + // See . + let max_attempts = this.eval_libc("TMP_MAX")?.to_u32()?; + + // Get the raw bytes from the template -- as a byte slice, this is a string in the target + // (and the target is unix, so a byte slice is the right representation). + let template_ptr = this.read_pointer(template_op)?; + let mut template = this.eval_context_ref().read_c_str(template_ptr)?.to_owned(); + let template_bytes = template.as_mut_slice(); + + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`mkstemp`", reject_with)?; + let eacc = this.eval_libc("EACCES")?; + this.set_last_error(eacc)?; + return Ok(-1); + } + + // Get the bytes of the suffix we expect in _target_ encoding. + let suffix_bytes = TEMPFILE_TEMPLATE_STR.as_bytes(); + + // At this point we have one `&[u8]` that represents the template and one `&[u8]` + // that represents the expected suffix. + + // Now we figure out the index of the slice we expect to contain the suffix. + let start_pos = template_bytes.len().saturating_sub(suffix_bytes.len()); + let end_pos = template_bytes.len(); + let last_six_char_bytes = &template_bytes[start_pos..end_pos]; + + // If we don't find the suffix, it is an error. + if last_six_char_bytes != suffix_bytes { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + return Ok(-1); + } + + // At this point we know we have 6 ASCII 'X' characters as a suffix. + + // From + const SUBSTITUTIONS: &[char; 62] = &[ + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', + 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', + 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + ]; + + // The file is opened with specific options, which Rust does not expose in a portable way. + // So we use specific APIs depending on the host OS. + let mut fopts = OpenOptions::new(); + fopts.read(true).write(true).create_new(true); + + #[cfg(unix)] + { + use std::os::unix::fs::OpenOptionsExt; + fopts.mode(0o600); + // Do not allow others to read or modify this file. + fopts.custom_flags(libc::O_EXCL); + } + #[cfg(windows)] + { + use std::os::windows::fs::OpenOptionsExt; + // Do not allow others to read or modify this file. + fopts.share_mode(0); + } + + // If the generated file already exists, we will try again `max_attempts` many times. + for _ in 0..max_attempts { + let rng = this.machine.rng.get_mut(); + + // Generate a random unique suffix. + let unique_suffix = SUBSTITUTIONS.choose_multiple(rng, 6).collect::(); + + // Replace the template string with the random string. + template_bytes[start_pos..end_pos].copy_from_slice(unique_suffix.as_bytes()); + + // Write the modified template back to the passed in pointer to maintain POSIX semantics. + this.write_bytes_ptr(template_ptr, template_bytes.iter().copied())?; + + // To actually open the file, turn this into a host OsString. + let p = bytes_to_os_str(template_bytes)?.to_os_string(); + + let possibly_unique = std::env::temp_dir().join::(p.into()); + + let file = fopts.open(&possibly_unique); + + match file { + Ok(f) => { + let fh = &mut this.machine.file_handler; + let fd = fh.insert_fd(Box::new(FileHandle { file: f, writable: true })); + return Ok(fd); + } + Err(e) => + match e.kind() { + // If the random file already exists, keep trying. + ErrorKind::AlreadyExists => continue, + // Any other errors are returned to the caller. + _ => { + // "On error, -1 is returned, and errno is set to + // indicate the error" + this.set_last_error_from_io_error(e.kind())?; + return Ok(-1); + } + }, + } + } + + // We ran out of attempts to create the file, return an error. + let eexist = this.eval_libc("EEXIST")?; + this.set_last_error(eexist)?; + Ok(-1) + } } /// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch when diff --git a/tests/fail/fs/mkstemp_immutable_arg.rs b/tests/fail/fs/mkstemp_immutable_arg.rs new file mode 100644 index 000000000000..5be1fb394b90 --- /dev/null +++ b/tests/fail/fs/mkstemp_immutable_arg.rs @@ -0,0 +1,13 @@ +//@ignore-target-windows: No libc on Windows +//@compile-flags: -Zmiri-disable-isolation + +#![feature(rustc_private)] + +fn main() { + test_mkstemp_immutable_arg(); +} + +fn test_mkstemp_immutable_arg() { + let s: *mut libc::c_char = b"fooXXXXXX\0" as *const _ as *mut _; + let _fd = unsafe { libc::mkstemp(s) }; //~ ERROR: Undefined Behavior: writing to alloc1 which is read-only +} diff --git a/tests/fail/fs/mkstemp_immutable_arg.stderr b/tests/fail/fs/mkstemp_immutable_arg.stderr new file mode 100644 index 000000000000..0bd91f90a10f --- /dev/null +++ b/tests/fail/fs/mkstemp_immutable_arg.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: writing to ALLOC which is read-only + --> $DIR/mkstemp_immutable_arg.rs:LL:CC + | +LL | let _fd = unsafe { libc::mkstemp(s) }; + | ^^^^^^^^^^^^^^^^ writing to ALLOC which is read-only + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: backtrace: + = note: inside `test_mkstemp_immutable_arg` at $DIR/mkstemp_immutable_arg.rs:LL:CC +note: inside `main` at $DIR/mkstemp_immutable_arg.rs:LL:CC + --> $DIR/mkstemp_immutable_arg.rs:LL:CC + | +LL | test_mkstemp_immutable_arg(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index c7331b110e9a..468da0845a88 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -407,11 +407,56 @@ fn test_isatty() { } } +fn test_posix_mkstemp() { + use std::ffi::CString; + use std::ffi::OsStr; + use std::os::unix::ffi::OsStrExt; + use std::os::unix::io::FromRawFd; + use std::path::Path; + + let valid_template = "fooXXXXXX"; + // C needs to own this as `mkstemp(3)` says: + // "Since it will be modified, `template` must not be a string constant, but + // should be declared as a character array." + // There seems to be no `as_mut_ptr` on `CString` so we need to use `into_raw`. + let ptr = CString::new(valid_template).unwrap().into_raw(); + let fd = unsafe { libc::mkstemp(ptr) }; + // Take ownership back in Rust to not leak memory. + let slice = unsafe { CString::from_raw(ptr) }; + assert!(fd > 0); + let osstr = OsStr::from_bytes(slice.to_bytes()); + let path: &Path = osstr.as_ref(); + let name = path.file_name().unwrap().to_string_lossy(); + assert!(name.ne("fooXXXXXX")); + assert!(name.starts_with("foo")); + assert_eq!(name.len(), 9); + assert_eq!( + name.chars().skip(3).filter(char::is_ascii_alphanumeric).collect::>().len(), + 6 + ); + let file = unsafe { File::from_raw_fd(fd) }; + assert!(file.set_len(0).is_ok()); + + let invalid_templates = vec!["foo", "barXX", "XXXXXXbaz", "whatXXXXXXever", "X"]; + for t in invalid_templates { + let ptr = CString::new(t).unwrap().into_raw(); + let fd = unsafe { libc::mkstemp(ptr) }; + let _ = unsafe { CString::from_raw(ptr) }; + // "On error, -1 is returned, and errno is set to + // indicate the error" + assert_eq!(fd, -1); + let e = std::io::Error::last_os_error(); + assert_eq!(e.raw_os_error(), Some(libc::EINVAL)); + assert_eq!(e.kind(), std::io::ErrorKind::InvalidInput); + } +} + fn main() { #[cfg(any(target_os = "linux", target_os = "freebsd"))] test_posix_fadvise(); test_posix_gettimeofday(); + test_posix_mkstemp(); test_posix_realpath_alloc(); test_posix_realpath_noalloc(); From 29e9a8aa1a3639393681f2d1bd471a38eb08e318 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Aug 2022 21:41:26 -0400 Subject: [PATCH 3641/5092] split cargo-miri into multiple files also greatly extend the 'who calls who' comment --- .github/workflows/ci.yml | 2 +- cargo-miri/Cargo.toml | 2 +- cargo-miri/bin.rs | 1274 ------------------------------- cargo-miri/src/main.rs | 95 +++ cargo-miri/src/phases.rs | 601 +++++++++++++++ cargo-miri/src/setup.rs | 247 ++++++ cargo-miri/src/util.rs | 375 +++++++++ cargo-miri/{ => src}/version.rs | 0 8 files changed, 1320 insertions(+), 1276 deletions(-) delete mode 100644 cargo-miri/bin.rs create mode 100644 cargo-miri/src/main.rs create mode 100644 cargo-miri/src/phases.rs create mode 100644 cargo-miri/src/setup.rs create mode 100644 cargo-miri/src/util.rs rename cargo-miri/{ => src}/version.rs (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7d6e39dc31b2..95303a592c8a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,7 +58,7 @@ jobs: # contains package information of crates installed via `cargo install`. ~/.cargo/.crates.toml ~/.cargo/.crates2.json - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock', 'cargo-miri/version.rs') }} + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock', 'cargo-miri/src/version.rs') }} restore-keys: ${{ runner.os }}-cargo - name: Install rustup-toolchain-install-master and xargo diff --git a/cargo-miri/Cargo.toml b/cargo-miri/Cargo.toml index 8bcd77c70b01..9ac170c5b537 100644 --- a/cargo-miri/Cargo.toml +++ b/cargo-miri/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" [[bin]] name = "cargo-miri" -path = "bin.rs" +path = "src/main.rs" test = false # we have no unit tests doctest = false # and no doc tests diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs deleted file mode 100644 index 4ddf2295362a..000000000000 --- a/cargo-miri/bin.rs +++ /dev/null @@ -1,1274 +0,0 @@ -#![feature(let_else)] -#![allow(clippy::useless_format, clippy::derive_partial_eq_without_eq)] - -mod version; - -use std::collections::HashMap; -use std::env; -use std::ffi::{OsStr, OsString}; -use std::fmt::Write as _; -use std::fs::{self, File}; -use std::io::{self, BufRead, BufReader, BufWriter, Read, Write}; -use std::iter::{self, TakeWhile}; -use std::ops::Not; -use std::path::{Path, PathBuf}; -use std::process::{self, Command}; - -use cargo_metadata::{Metadata, MetadataCommand}; -use rustc_version::VersionMeta; -use serde::{Deserialize, Serialize}; - -use version::*; - -const CARGO_MIRI_HELP: &str = r#"Runs binary crates and tests in Miri - -Usage: - cargo miri [subcommand] [...] [--] [...] - -Subcommands: - run, r Run binaries - test, t Run tests - nextest Run tests with nextest (requires cargo-nextest installed) - setup Only perform automatic setup, but without asking questions (for getting a proper libstd) - -The cargo options are exactly the same as for `cargo run` and `cargo test`, respectively. - -Examples: - cargo miri run - cargo miri test -- test-suite-filter - - cargo miri setup --print sysroot - This will print the path to the generated sysroot (and nothing else) on stdout. - stderr will still contain progress information about how the build is doing. - -"#; - -#[derive(Clone, Debug)] -enum MiriCommand { - /// Our own special 'setup' command. - Setup, - /// A command to be forwarded to cargo. - Forward(String), -} - -/// The information to run a crate with the given environment. -#[derive(Clone, Serialize, Deserialize)] -struct CrateRunEnv { - /// The command-line arguments. - args: Vec, - /// The environment. - env: Vec<(OsString, OsString)>, - /// The current working directory. - current_dir: OsString, - /// The contents passed via standard input. - stdin: Vec, -} - -impl CrateRunEnv { - /// Gather all the information we need. - fn collect(args: impl Iterator, capture_stdin: bool) -> Self { - let args = args.collect(); - let env = env::vars_os().collect(); - let current_dir = env::current_dir().unwrap().into_os_string(); - - let mut stdin = Vec::new(); - if capture_stdin { - std::io::stdin().lock().read_to_end(&mut stdin).expect("cannot read stdin"); - } - - CrateRunEnv { args, env, current_dir, stdin } - } -} - -/// The information Miri needs to run a crate. Stored as JSON when the crate is "compiled". -#[derive(Serialize, Deserialize)] -enum CrateRunInfo { - /// Run it with the given environment. - RunWith(CrateRunEnv), - /// Skip it as Miri does not support interpreting such kind of crates. - SkipProcMacroTest, -} - -impl CrateRunInfo { - fn store(&self, filename: &Path) { - let file = File::create(filename) - .unwrap_or_else(|_| show_error(format!("cannot create `{}`", filename.display()))); - let file = BufWriter::new(file); - serde_json::ser::to_writer(file, self) - .unwrap_or_else(|_| show_error(format!("cannot write to `{}`", filename.display()))); - } -} - -fn show_help() { - println!("{}", CARGO_MIRI_HELP); -} - -fn show_version() { - let mut version = format!("miri {}", env!("CARGO_PKG_VERSION")); - // Only use `option_env` on vergen variables to ensure the build succeeds - // when vergen failed to find the git info. - if let Some(sha) = option_env!("VERGEN_GIT_SHA_SHORT") { - // This `unwrap` can never fail because if VERGEN_GIT_SHA_SHORT exists, then so does - // VERGEN_GIT_COMMIT_DATE. - #[allow(clippy::option_env_unwrap)] - write!(&mut version, " ({} {})", sha, option_env!("VERGEN_GIT_COMMIT_DATE").unwrap()) - .unwrap(); - } - println!("{}", version); -} - -fn show_error(msg: String) -> ! { - eprintln!("fatal error: {}", msg); - std::process::exit(1) -} - -/// Determines whether a `--flag` is present. -fn has_arg_flag(name: &str) -> bool { - num_arg_flag(name) > 0 -} - -/// Determines how many times a `--flag` is present. -fn num_arg_flag(name: &str) -> usize { - std::env::args().take_while(|val| val != "--").filter(|val| val == name).count() -} - -/// Yields all values of command line flag `name` as `Ok(arg)`, and all other arguments except -/// the flag as `Err(arg)`. (The flag `name` itself is not yielded at all, only its values are.) -struct ArgSplitFlagValue<'a, I> { - args: TakeWhile bool>, - name: &'a str, -} - -impl<'a, I: Iterator> ArgSplitFlagValue<'a, I> { - fn new(args: I, name: &'a str) -> Self { - Self { - // Stop searching at `--`. - args: args.take_while(|val| val != "--"), - name, - } - } -} - -impl> Iterator for ArgSplitFlagValue<'_, I> { - type Item = Result; - - fn next(&mut self) -> Option { - let arg = self.args.next()?; - if let Some(suffix) = arg.strip_prefix(self.name) { - // Strip leading `name`. - if suffix.is_empty() { - // This argument is exactly `name`; the next one is the value. - return self.args.next().map(Ok); - } else if let Some(suffix) = suffix.strip_prefix('=') { - // This argument is `name=value`; get the value. - return Some(Ok(suffix.to_owned())); - } - } - Some(Err(arg)) - } -} - -/// Yields all values of command line flag `name`. -struct ArgFlagValueIter<'a>(ArgSplitFlagValue<'a, env::Args>); - -impl<'a> ArgFlagValueIter<'a> { - fn new(name: &'a str) -> Self { - Self(ArgSplitFlagValue::new(env::args(), name)) - } -} - -impl Iterator for ArgFlagValueIter<'_> { - type Item = String; - - fn next(&mut self) -> Option { - loop { - if let Ok(value) = self.0.next()? { - return Some(value); - } - } - } -} - -/// Gets the value of a `--flag`. -fn get_arg_flag_value(name: &str) -> Option { - ArgFlagValueIter::new(name).next() -} - -fn forward_patched_extern_arg(args: &mut impl Iterator, cmd: &mut Command) { - cmd.arg("--extern"); // always forward flag, but adjust filename: - let path = args.next().expect("`--extern` should be followed by a filename"); - if let Some(lib) = path.strip_suffix(".rlib") { - // If this is an rlib, make it an rmeta. - cmd.arg(format!("{}.rmeta", lib)); - } else { - // Some other extern file (e.g. a `.so`). Forward unchanged. - cmd.arg(path); - } -} - -/// Escapes `s` in a way that is suitable for using it as a string literal in TOML syntax. -fn escape_for_toml(s: &str) -> String { - // We want to surround this string in quotes `"`. So we first escape all quotes, - // and also all backslashes (that are used to escape quotes). - let s = s.replace('\\', r#"\\"#).replace('"', r#"\""#); - format!("\"{}\"", s) -} - -/// Returns the path to the `miri` binary -fn find_miri() -> PathBuf { - if let Some(path) = env::var_os("MIRI") { - return path.into(); - } - let mut path = std::env::current_exe().expect("current executable path invalid"); - if cfg!(windows) { - path.set_file_name("miri.exe"); - } else { - path.set_file_name("miri"); - } - path -} - -fn miri() -> Command { - Command::new(find_miri()) -} - -fn miri_for_host() -> Command { - let mut cmd = miri(); - cmd.env("MIRI_BE_RUSTC", "host"); - cmd -} - -fn version_info() -> VersionMeta { - VersionMeta::for_command(miri_for_host()) - .expect("failed to determine underlying rustc version of Miri") -} - -fn cargo() -> Command { - Command::new(env::var_os("CARGO").unwrap_or_else(|| OsString::from("cargo"))) -} - -fn xargo_check() -> Command { - Command::new(env::var_os("XARGO_CHECK").unwrap_or_else(|| OsString::from("xargo-check"))) -} - -/// Execute the `Command`, where possible by replacing the current process with a new process -/// described by the `Command`. Then exit this process with the exit code of the new process. -fn exec(mut cmd: Command) -> ! { - // On non-Unix imitate POSIX exec as closely as we can - #[cfg(not(unix))] - { - let exit_status = cmd.status().expect("failed to run command"); - std::process::exit(exit_status.code().unwrap_or(-1)) - } - // On Unix targets, actually exec. - // If exec returns, process setup has failed. This is the same error condition as the expect in - // the non-Unix case. - #[cfg(unix)] - { - use std::os::unix::process::CommandExt; - let error = cmd.exec(); - Err(error).expect("failed to run command") - } -} - -/// Execute the `Command`, where possible by replacing the current process with a new process -/// described by the `Command`. Then exit this process with the exit code of the new process. -/// `input` is also piped to the new process's stdin, on cfg(unix) platforms by writing its -/// contents to `path` first, then setting stdin to that file. -fn exec_with_pipe

(mut cmd: Command, input: &[u8], path: P) -> ! -where - P: AsRef, -{ - #[cfg(unix)] - { - // Write the bytes we want to send to stdin out to a file - std::fs::write(&path, input).unwrap(); - // Open the file for reading, and set our new stdin to it - let stdin = File::open(&path).unwrap(); - cmd.stdin(stdin); - // Unlink the file so that it is fully cleaned up as soon as the new process exits - std::fs::remove_file(&path).unwrap(); - // Finally, we can hand off control. - exec(cmd) - } - #[cfg(not(unix))] - { - drop(path); // We don't need the path, we can pipe the bytes directly - cmd.stdin(process::Stdio::piped()); - let mut child = cmd.spawn().expect("failed to spawn process"); - { - let stdin = child.stdin.as_mut().expect("failed to open stdin"); - stdin.write_all(input).expect("failed to write out test source"); - } - let exit_status = child.wait().expect("failed to run command"); - std::process::exit(exit_status.code().unwrap_or(-1)) - } -} - -fn xargo_version() -> Option<(u32, u32, u32)> { - let out = xargo_check().arg("--version").output().ok()?; - if !out.status.success() { - return None; - } - // Parse output. The first line looks like "xargo 0.3.12 (b004f1c 2018-12-13)". - let line = out - .stderr - .lines() - .next() - .expect("malformed `xargo --version` output: not at least one line") - .expect("malformed `xargo --version` output: error reading first line"); - let (name, version) = { - let mut split = line.split(' '); - ( - split.next().expect("malformed `xargo --version` output: empty"), - split.next().expect("malformed `xargo --version` output: not at least two words"), - ) - }; - if name != "xargo" { - // This is some fork of xargo - return None; - } - let mut version_pieces = version.split('.'); - let major = version_pieces - .next() - .expect("malformed `xargo --version` output: not a major version piece") - .parse() - .expect("malformed `xargo --version` output: major version is not an integer"); - let minor = version_pieces - .next() - .expect("malformed `xargo --version` output: not a minor version piece") - .parse() - .expect("malformed `xargo --version` output: minor version is not an integer"); - let patch = version_pieces - .next() - .expect("malformed `xargo --version` output: not a patch version piece") - .parse() - .expect("malformed `xargo --version` output: patch version is not an integer"); - if version_pieces.next().is_some() { - panic!("malformed `xargo --version` output: more than three pieces in version"); - } - Some((major, minor, patch)) -} - -fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { - // Disable interactive prompts in CI (GitHub Actions, Travis, AppVeyor, etc). - // Azure doesn't set `CI` though (nothing to see here, just Microsoft being Microsoft), - // so we also check their `TF_BUILD`. - let is_ci = env::var_os("CI").is_some() || env::var_os("TF_BUILD").is_some(); - if ask && !is_ci { - let mut buf = String::new(); - print!("I will run `{:?}` to {}. Proceed? [Y/n] ", cmd, text); - io::stdout().flush().unwrap(); - io::stdin().read_line(&mut buf).unwrap(); - match buf.trim().to_lowercase().as_ref() { - // Proceed. - "" | "y" | "yes" => {} - "n" | "no" => show_error(format!("aborting as per your request")), - a => show_error(format!("invalid answer `{}`", a)), - }; - } else { - eprintln!("Running `{:?}` to {}.", cmd, text); - } - - if cmd.status().unwrap_or_else(|_| panic!("failed to execute {:?}", cmd)).success().not() { - show_error(format!("failed to {}", text)); - } -} - -/// Writes the given content to the given file *cross-process atomically*, in the sense that another -/// process concurrently reading that file will see either the old content or the new content, but -/// not some intermediate (e.g., empty) state. -/// -/// We assume no other parts of this same process are trying to read or write that file. -fn write_to_file(filename: &Path, content: &str) { - // Create a temporary file with the desired contents. - let mut temp_filename = filename.as_os_str().to_os_string(); - temp_filename.push(&format!(".{}", std::process::id())); - let mut temp_file = File::create(&temp_filename).unwrap(); - temp_file.write_all(content.as_bytes()).unwrap(); - drop(temp_file); - - // Move file to the desired location. - fs::rename(temp_filename, filename).unwrap(); -} - -/// Performs the setup required to make `cargo miri` work: Getting a custom-built libstd. Then sets -/// `MIRI_SYSROOT`. Skipped if `MIRI_SYSROOT` is already set, in which case we expect the user has -/// done all this already. -fn setup(subcommand: &MiriCommand, host: &str, target: &str) { - let only_setup = matches!(subcommand, MiriCommand::Setup); - let ask_user = !only_setup; - let print_sysroot = only_setup && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path - if std::env::var_os("MIRI_SYSROOT").is_some() { - if only_setup { - println!("WARNING: MIRI_SYSROOT already set, not doing anything.") - } - return; - } - - // First, we need xargo. - if xargo_version().map_or(true, |v| v < XARGO_MIN_VERSION) { - if std::env::var_os("XARGO_CHECK").is_some() { - // The user manually gave us a xargo binary; don't do anything automatically. - show_error(format!("xargo is too old; please upgrade to the latest version")) - } - let mut cmd = cargo(); - cmd.args(&["install", "xargo"]); - ask_to_run(cmd, ask_user, "install a recent enough xargo"); - } - - // Determine where the rust sources are located. The env vars manually setting the source - // (`MIRI_LIB_SRC`, `XARGO_RUST_SRC`) trump auto-detection. - let rust_src_env_var = - std::env::var_os("MIRI_LIB_SRC").or_else(|| std::env::var_os("XARGO_RUST_SRC")); - let rust_src = match rust_src_env_var { - Some(path) => { - let path = PathBuf::from(path); - // Make path absolute if possible. - path.canonicalize().unwrap_or(path) - } - None => { - // Check for `rust-src` rustup component. - let output = miri_for_host() - .args(&["--print", "sysroot"]) - .output() - .expect("failed to determine sysroot"); - if !output.status.success() { - show_error(format!( - "Failed to determine sysroot; Miri said:\n{}", - String::from_utf8_lossy(&output.stderr).trim_end() - )); - } - let sysroot = std::str::from_utf8(&output.stdout).unwrap(); - let sysroot = Path::new(sysroot.trim_end_matches('\n')); - // Check for `$SYSROOT/lib/rustlib/src/rust/library`; test if that contains `std/Cargo.toml`. - let rustup_src = - sysroot.join("lib").join("rustlib").join("src").join("rust").join("library"); - if !rustup_src.join("std").join("Cargo.toml").exists() { - // Ask the user to install the `rust-src` component, and use that. - let mut cmd = Command::new("rustup"); - cmd.args(&["component", "add", "rust-src"]); - ask_to_run( - cmd, - ask_user, - "install the `rust-src` component for the selected toolchain", - ); - } - rustup_src - } - }; - if !rust_src.exists() { - show_error(format!("given Rust source directory `{}` does not exist.", rust_src.display())); - } - if rust_src.file_name().and_then(OsStr::to_str) != Some("library") { - show_error(format!( - "given Rust source directory `{}` does not seem to be the `library` subdirectory of \ - a Rust source checkout.", - rust_src.display() - )); - } - - // Next, we need our own libstd. Prepare a xargo project for that purpose. - // We will do this work in whatever is a good cache dir for this platform. - let dirs = directories::ProjectDirs::from("org", "rust-lang", "miri").unwrap(); - let dir = dirs.cache_dir(); - if !dir.exists() { - fs::create_dir_all(&dir).unwrap(); - } - // The interesting bit: Xargo.toml (only needs content if we actually need std) - let xargo_toml = if std::env::var_os("MIRI_NO_STD").is_some() { - "" - } else { - r#" -[dependencies.std] -default_features = false -# We support unwinding, so enable that panic runtime. -features = ["panic_unwind", "backtrace"] - -[dependencies.test] -"# - }; - write_to_file(&dir.join("Xargo.toml"), xargo_toml); - // The boring bits: a dummy project for xargo. - // FIXME: With xargo-check, can we avoid doing this? - write_to_file( - &dir.join("Cargo.toml"), - r#" -[package] -name = "miri-xargo" -description = "A dummy project for building libstd with xargo." -version = "0.0.0" - -[lib] -path = "lib.rs" -"#, - ); - write_to_file(&dir.join("lib.rs"), "#![no_std]"); - - // Figure out where xargo will build its stuff. - // Unfortunately, it puts things into a different directory when the - // architecture matches the host. - let sysroot = if target == host { dir.join("HOST") } else { PathBuf::from(dir) }; - // Make sure all target-level Miri invocations know their sysroot. - std::env::set_var("MIRI_SYSROOT", &sysroot); - - // Now invoke xargo. - let mut command = xargo_check(); - command.arg("check").arg("-q"); - command.current_dir(&dir); - command.env("XARGO_HOME", &dir); - command.env("XARGO_RUST_SRC", &rust_src); - // We always need to set a target so rustc bootstrap can tell apart host from target crates. - command.arg("--target").arg(target); - // Use Miri as rustc to build a libstd compatible with us (and use the right flags). - // However, when we are running in bootstrap, we cannot just overwrite `RUSTC`, - // because we still need bootstrap to distinguish between host and target crates. - // In that case we overwrite `RUSTC_REAL` instead which determines the rustc used - // for target crates. - // We set ourselves (`cargo-miri`) instead of Miri directly to be able to patch the flags - // for `libpanic_abort` (usually this is done by bootstrap but we have to do it ourselves). - // The `MIRI_CALLED_FROM_XARGO` will mean we dispatch to `phase_setup_rustc`. - let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); - if env::var_os("RUSTC_STAGE").is_some() { - assert!(env::var_os("RUSTC").is_some()); - command.env("RUSTC_REAL", &cargo_miri_path); - } else { - command.env("RUSTC", &cargo_miri_path); - } - command.env("MIRI_CALLED_FROM_XARGO", "1"); - // Make sure there are no other wrappers getting in our way - // (Cc https://github.com/rust-lang/miri/issues/1421, https://github.com/rust-lang/miri/issues/2429). - // Looks like setting `RUSTC_WRAPPER` to the empty string overwrites `build.rustc-wrapper` set via `config.toml`. - command.env("RUSTC_WRAPPER", ""); - // Disable debug assertions in the standard library -- Miri is already slow enough. But keep the - // overflow checks, they are cheap. This completely overwrites flags the user might have set, - // which is consistent with normal `cargo build` that does not apply `RUSTFLAGS` to the sysroot - // either. - command.env("RUSTFLAGS", "-Cdebug-assertions=off -Coverflow-checks=on"); - // Manage the output the user sees. - if only_setup { - // We want to be explicit. - eprintln!("Preparing a sysroot for Miri (target: {target})..."); - if print_sysroot { - // Be extra sure there is no noise on stdout. - command.stdout(process::Stdio::null()); - } - } else { - // We want to be quiet, but still let the user know that something is happening. - eprint!("Preparing a sysroot for Miri (target: {target})... "); - command.stdout(process::Stdio::null()); - command.stderr(process::Stdio::null()); - } - - // Finally run it! - if command.status().expect("failed to run xargo").success().not() { - if only_setup { - show_error(format!("failed to run xargo, see error details above")) - } else { - show_error(format!( - "failed to run xargo; run `cargo miri setup` to see the error details" - )) - } - } - - // Figure out what to print. - if only_setup { - eprintln!("A sysroot for Miri is now available in `{}`.", sysroot.display()); - } else { - eprintln!("done"); - } - if print_sysroot { - // Print just the sysroot and nothing else to stdout; this way we do not need any escaping. - println!("{}", sysroot.display()); - } -} - -fn get_cargo_metadata() -> Metadata { - // The `build.target-dir` config can be passed by `--config` flags, so forward them to - // `cargo metadata`. - let mut additional_options = Vec::new(); - // `-Zunstable-options` is required by `--config`. - additional_options.push("-Zunstable-options".to_string()); - - let config_flag = "--config"; - for arg in ArgSplitFlagValue::new( - env::args().skip(3), // skip the program name, "miri" and "run" / "test" - config_flag, - ) - // Only look at `Ok` - .flatten() - { - additional_options.push(config_flag.to_string()); - additional_options.push(arg); - } - - let metadata = - MetadataCommand::new().no_deps().other_options(additional_options).exec().unwrap(); - - metadata -} - -/// Pulls all the crates in this workspace from the cargo metadata. -/// Workspace members are emitted like "miri 0.1.0 (path+file:///path/to/miri)" -/// Additionally, somewhere between cargo metadata and TyCtxt, '-' gets replaced with '_' so we -/// make that same transformation here. -fn local_crates(metadata: &Metadata) -> String { - assert!(!metadata.workspace_members.is_empty()); - let mut local_crates = String::new(); - for member in &metadata.workspace_members { - let name = member.repr.split(' ').next().unwrap(); - let name = name.replace('-', "_"); - local_crates.push_str(&name); - local_crates.push(','); - } - local_crates.pop(); // Remove the trailing ',' - - local_crates -} - -fn env_vars_from_cmd(cmd: &Command) -> Vec<(String, String)> { - let mut envs = HashMap::new(); - for (key, value) in std::env::vars() { - envs.insert(key, value); - } - for (key, value) in cmd.get_envs() { - if let Some(value) = value { - envs.insert(key.to_string_lossy().to_string(), value.to_string_lossy().to_string()); - } else { - envs.remove(&key.to_string_lossy().to_string()); - } - } - let mut envs: Vec<_> = envs.into_iter().collect(); - envs.sort(); - envs -} - -/// Debug-print a command that is going to be run. -fn debug_cmd(prefix: &str, verbose: usize, cmd: &Command) { - if verbose == 0 { - return; - } - // We only do a single `eprintln!` call to minimize concurrency interactions. - let mut out = prefix.to_string(); - writeln!(out, " running command: env \\").unwrap(); - if verbose > 1 { - // Print the full environment this will be called in. - for (key, value) in env_vars_from_cmd(cmd) { - writeln!(out, "{key}={value:?} \\").unwrap(); - } - } else { - // Print only what has been changed for this `cmd`. - for (var, val) in cmd.get_envs() { - if let Some(val) = val { - writeln!(out, "{}={:?} \\", var.to_string_lossy(), val).unwrap(); - } else { - writeln!(out, "--unset={}", var.to_string_lossy()).unwrap(); - } - } - } - write!(out, "{cmd:?}").unwrap(); - eprintln!("{}", out); -} - -fn phase_cargo_miri(mut args: impl Iterator) { - // Check for version and help flags even when invoked as `cargo-miri`. - if has_arg_flag("--help") || has_arg_flag("-h") { - show_help(); - return; - } - if has_arg_flag("--version") || has_arg_flag("-V") { - show_version(); - return; - } - - // Require a subcommand before any flags. - // We cannot know which of those flags take arguments and which do not, - // so we cannot detect subcommands later. - let Some(subcommand) = args.next() else { - show_error(format!("`cargo miri` needs to be called with a subcommand (`run`, `test`)")); - }; - let subcommand = match &*subcommand { - "setup" => MiriCommand::Setup, - "test" | "t" | "run" | "r" | "nextest" => MiriCommand::Forward(subcommand), - _ => - show_error(format!( - "`cargo miri` supports the following subcommands: `run`, `test`, `nextest`, and `setup`." - )), - }; - let verbose = num_arg_flag("-v"); - - // Determine the involved architectures. - let host = version_info().host; - let target = get_arg_flag_value("--target"); - let target = target.as_ref().unwrap_or(&host); - - // We always setup. - setup(&subcommand, &host, target); - - // Invoke actual cargo for the job, but with different flags. - // We re-use `cargo test` and `cargo run`, which makes target and binary handling very easy but - // requires some extra work to make the build check-only (see all the `--emit` hacks below). - // describes an alternative - // approach that uses `cargo check`, making that part easier but target and binary handling - // harder. - let cargo_miri_path = std::env::current_exe() - .expect("current executable path invalid") - .into_os_string() - .into_string() - .expect("current executable path is not valid UTF-8"); - let cargo_cmd = match subcommand { - MiriCommand::Forward(s) => s, - MiriCommand::Setup => return, // `cargo miri setup` stops here. - }; - let metadata = get_cargo_metadata(); - let mut cmd = cargo(); - cmd.arg(cargo_cmd); - - // Forward all arguments before `--` other than `--target-dir` and its value to Cargo. - let mut target_dir = None; - for arg in ArgSplitFlagValue::new(&mut args, "--target-dir") { - match arg { - Ok(value) => { - if target_dir.is_some() { - show_error(format!("`--target-dir` is provided more than once")); - } - target_dir = Some(value.into()); - } - Err(arg) => { - cmd.arg(arg); - } - } - } - // Detect the target directory if it's not specified via `--target-dir`. - let target_dir = target_dir.get_or_insert_with(|| metadata.target_directory.clone()); - // Set `--target-dir` to `miri` inside the original target directory. - target_dir.push("miri"); - cmd.arg("--target-dir").arg(target_dir); - - // Make sure the build target is explicitly set. - // This is needed to make the `target.runner` settings do something, - // and it later helps us detect which crates are proc-macro/build-script - // (host crates) and which crates are needed for the program itself. - if get_arg_flag_value("--target").is_none() { - // No target given. Explicitly pick the host. - cmd.arg("--target"); - cmd.arg(&host); - } - - // Set ourselves as runner for al binaries invoked by cargo. - // We use `all()` since `true` is not a thing in cfg-lang, but the empty conjunction is. :) - let cargo_miri_path_for_toml = escape_for_toml(&cargo_miri_path); - cmd.arg("--config") - .arg(format!("target.'cfg(all())'.runner=[{cargo_miri_path_for_toml}, 'runner']")); - - // Forward all further arguments after `--` to cargo. - cmd.arg("--").args(args); - - // Set `RUSTC_WRAPPER` to ourselves. Cargo will prepend that binary to its usual invocation, - // i.e., the first argument is `rustc` -- which is what we use in `main` to distinguish - // the two codepaths. (That extra argument is why we prefer this over setting `RUSTC`.) - if env::var_os("RUSTC_WRAPPER").is_some() { - println!( - "WARNING: Ignoring `RUSTC_WRAPPER` environment variable, Miri does not support wrapping." - ); - } - cmd.env("RUSTC_WRAPPER", &cargo_miri_path); - // We are going to invoke `MIRI` for everything, not `RUSTC`. - if env::var_os("RUSTC").is_some() && env::var_os("MIRI").is_none() { - println!( - "WARNING: Ignoring `RUSTC` environment variable; set `MIRI` if you want to control the binary used as the driver." - ); - } - // Build scripts (and also cargo: https://github.com/rust-lang/cargo/issues/10885) will invoke - // `rustc` even when `RUSTC_WRAPPER` is set. To make sure everything is coherent, we want that - // to be the Miri driver, but acting as rustc, on the target level. (Target, rather than host, - // is needed for cross-interpretation situations.) This is not a perfect emulation of real rustc - // (it might be unable to produce binaries since the sysroot is check-only), but it's as close - // as we can get, and it's good enough for autocfg. - // - // In `main`, we need the value of `RUSTC` to distinguish RUSTC_WRAPPER invocations from rustdoc - // or TARGET_RUNNER invocations, so we canonicalize it here to make it exceedingly unlikely that - // there would be a collision with other invocations of cargo-miri (as rustdoc or as runner). We - // explicitly do this even if RUSTC_STAGE is set, since for these builds we do *not* want the - // bootstrap `rustc` thing in our way! Instead, we have MIRI_HOST_SYSROOT to use for host - // builds. - cmd.env("RUSTC", &fs::canonicalize(find_miri()).unwrap()); - cmd.env("MIRI_BE_RUSTC", "target"); // we better remember to *unset* this in the other phases! - - // Set rustdoc to us as well, so we can run doctests. - cmd.env("RUSTDOC", &cargo_miri_path); - - cmd.env("MIRI_LOCAL_CRATES", local_crates(&metadata)); - if verbose > 0 { - cmd.env("MIRI_VERBOSE", verbose.to_string()); // This makes the other phases verbose. - } - - // Run cargo. - debug_cmd("[cargo-miri miri]", verbose, &cmd); - exec(cmd) -} - -#[derive(Debug, Copy, Clone, PartialEq)] -enum RustcPhase { - /// `rustc` called via `xargo` for sysroot build. - Setup, - /// `rustc` called by `cargo` for regular build. - Build, - /// `rustc` called by `rustdoc` for doctest. - Rustdoc, -} - -fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { - /// Determines if we are being invoked (as rustc) to build a crate for - /// the "target" architecture, in contrast to the "host" architecture. - /// Host crates are for build scripts and proc macros and still need to - /// be built like normal; target crates need to be built for or interpreted - /// by Miri. - /// - /// Currently, we detect this by checking for "--target=", which is - /// never set for host crates. This matches what rustc bootstrap does, - /// which hopefully makes it "reliable enough". This relies on us always - /// invoking cargo itself with `--target`, which `in_cargo_miri` ensures. - fn is_target_crate() -> bool { - get_arg_flag_value("--target").is_some() - } - - /// Returns whether or not Cargo invoked the wrapper (this binary) to compile - /// the final, binary crate (either a test for 'cargo test', or a binary for 'cargo run') - /// Cargo does not give us this information directly, so we need to check - /// various command-line flags. - fn is_runnable_crate() -> bool { - let is_bin = get_arg_flag_value("--crate-type").as_deref().unwrap_or("bin") == "bin"; - let is_test = has_arg_flag("--test"); - is_bin || is_test - } - - fn out_filename(prefix: &str, suffix: &str) -> PathBuf { - if let Some(out_dir) = get_arg_flag_value("--out-dir") { - let mut path = PathBuf::from(out_dir); - path.push(format!( - "{}{}{}{}", - prefix, - get_arg_flag_value("--crate-name").unwrap(), - // This is technically a `-C` flag but the prefix seems unique enough... - // (and cargo passes this before the filename so it should be unique) - get_arg_flag_value("extra-filename").unwrap_or_default(), - suffix, - )); - path - } else { - let out_file = get_arg_flag_value("-o").unwrap(); - PathBuf::from(out_file) - } - } - - // phase_cargo_miri set `MIRI_BE_RUSTC` for when build scripts directly invoke the driver; - // however, if we get called back by cargo here, we'll carefully compute the right flags - // ourselves, so we first un-do what the earlier phase did. - env::remove_var("MIRI_BE_RUSTC"); - - let verbose = std::env::var("MIRI_VERBOSE") - .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); - let target_crate = is_target_crate(); - // Determine whether this is cargo/xargo invoking rustc to get some infos. - let info_query = get_arg_flag_value("--print").is_some() || has_arg_flag("-vV"); - - let store_json = |info: CrateRunInfo| { - // Create a stub .d file to stop Cargo from "rebuilding" the crate: - // https://github.com/rust-lang/miri/issues/1724#issuecomment-787115693 - // As we store a JSON file instead of building the crate here, an empty file is fine. - let dep_info_name = out_filename("", ".d"); - if verbose > 0 { - eprintln!("[cargo-miri rustc] writing stub dep-info to `{}`", dep_info_name.display()); - } - File::create(dep_info_name).expect("failed to create fake .d file"); - - let filename = out_filename("", ""); - if verbose > 0 { - eprintln!("[cargo-miri rustc] writing run info to `{}`", filename.display()); - } - info.store(&filename); - // For Windows, do the same thing again with `.exe` appended to the filename. - // (Need to do this here as cargo moves that "binary" to a different place before running it.) - info.store(&out_filename("", ".exe")); - }; - - let runnable_crate = !info_query && is_runnable_crate(); - - if runnable_crate && target_crate { - assert!( - phase != RustcPhase::Setup, - "there should be no interpretation during sysroot build" - ); - let inside_rustdoc = phase == RustcPhase::Rustdoc; - // This is the binary or test crate that we want to interpret under Miri. - // But we cannot run it here, as cargo invoked us as a compiler -- our stdin and stdout are not - // like we want them. - // Instead of compiling, we write JSON into the output file with all the relevant command-line flags - // and environment variables; this is used when cargo calls us again in the CARGO_TARGET_RUNNER phase. - let env = CrateRunEnv::collect(args, inside_rustdoc); - - store_json(CrateRunInfo::RunWith(env.clone())); - - // Rustdoc expects us to exit with an error code if the test is marked as `compile_fail`, - // just creating the JSON file is not enough: we need to detect syntax errors, - // so we need to run Miri with `MIRI_BE_RUSTC` for a check-only build. - if inside_rustdoc { - let mut cmd = miri(); - - // Ensure --emit argument for a check-only build is present. - // We cannot use the usual helpers since we need to check specifically in `env.args`. - if let Some(i) = env.args.iter().position(|arg| arg.starts_with("--emit=")) { - // For `no_run` tests, rustdoc passes a `--emit` flag; make sure it has the right shape. - assert_eq!(env.args[i], "--emit=metadata"); - } else { - // For all other kinds of tests, we can just add our flag. - cmd.arg("--emit=metadata"); - } - - // Alter the `-o` parameter so that it does not overwrite the JSON file we stored above. - let mut args = env.args.clone(); - for i in 0..args.len() { - if args[i] == "-o" { - args[i + 1].push_str(".miri"); - } - } - - cmd.args(&args); - cmd.env("MIRI_BE_RUSTC", "target"); - - if verbose > 0 { - eprintln!( - "[cargo-miri rustc inside rustdoc] captured input:\n{}", - std::str::from_utf8(&env.stdin).unwrap() - ); - eprintln!("[cargo-miri rustc inside rustdoc] going to run:\n{:?}", cmd); - } - - exec_with_pipe(cmd, &env.stdin, format!("{}.stdin", out_filename("", "").display())); - } - - return; - } - - if runnable_crate && ArgFlagValueIter::new("--extern").any(|krate| krate == "proc_macro") { - // This is a "runnable" `proc-macro` crate (unit tests). We do not support - // interpreting that under Miri now, so we write a JSON file to (display a - // helpful message and) skip it in the runner phase. - store_json(CrateRunInfo::SkipProcMacroTest); - return; - } - - let mut cmd = miri(); - let mut emit_link_hack = false; - // Arguments are treated very differently depending on whether this crate is - // for interpretation by Miri, or for use by a build script / proc macro. - if !info_query && target_crate { - // Forward arguments, but remove "link" from "--emit" to make this a check-only build. - let emit_flag = "--emit"; - while let Some(arg) = args.next() { - if let Some(val) = arg.strip_prefix(emit_flag) { - // Patch this argument. First, extract its value. - let val = - val.strip_prefix('=').expect("`cargo` should pass `--emit=X` as one argument"); - let mut val: Vec<_> = val.split(',').collect(); - // Now make sure "link" is not in there, but "metadata" is. - if let Some(i) = val.iter().position(|&s| s == "link") { - emit_link_hack = true; - val.remove(i); - if !val.iter().any(|&s| s == "metadata") { - val.push("metadata"); - } - } - cmd.arg(format!("{}={}", emit_flag, val.join(","))); - } else if arg == "--extern" { - // Patch `--extern` filenames, since Cargo sometimes passes stub `.rlib` files: - // https://github.com/rust-lang/miri/issues/1705 - forward_patched_extern_arg(&mut args, &mut cmd); - } else { - cmd.arg(arg); - } - } - - // During setup, patch the panic runtime for `libpanic_abort` (mirroring what bootstrap usually does). - if phase == RustcPhase::Setup - && get_arg_flag_value("--crate-name").as_deref() == Some("panic_abort") - { - cmd.arg("-C").arg("panic=abort"); - } - } else { - // For host crates (but not when we are just printing some info), - // we might still have to set the sysroot. - if !info_query { - // When we're running `cargo-miri` from `x.py` we need to pass the sysroot explicitly - // due to bootstrap complications. - if let Some(sysroot) = std::env::var_os("MIRI_HOST_SYSROOT") { - cmd.arg("--sysroot").arg(sysroot); - } - } - - // For host crates or when we are printing, just forward everything. - cmd.args(args); - } - - // We want to compile, not interpret. We still use Miri to make sure the compiler version etc - // are the exact same as what is used for interpretation. - // MIRI_DEFAULT_ARGS should not be used to build host crates, hence setting "target" or "host" - // as the value here to help Miri differentiate them. - cmd.env("MIRI_BE_RUSTC", if target_crate { "target" } else { "host" }); - - // Run it. - if verbose > 0 { - eprintln!( - "[cargo-miri rustc] target_crate={target_crate} runnable_crate={runnable_crate} info_query={info_query}" - ); - } - - // Create a stub .rlib file if "link" was requested by cargo. - // This is necessary to prevent cargo from doing rebuilds all the time. - if emit_link_hack { - // Some platforms prepend "lib", some do not... let's just create both files. - File::create(out_filename("lib", ".rlib")).expect("failed to create fake .rlib file"); - File::create(out_filename("", ".rlib")).expect("failed to create fake .rlib file"); - // Just in case this is a cdylib or staticlib, also create those fake files. - File::create(out_filename("lib", ".so")).expect("failed to create fake .so file"); - File::create(out_filename("lib", ".a")).expect("failed to create fake .a file"); - File::create(out_filename("lib", ".dylib")).expect("failed to create fake .dylib file"); - File::create(out_filename("", ".dll")).expect("failed to create fake .dll file"); - File::create(out_filename("", ".lib")).expect("failed to create fake .lib file"); - } - - debug_cmd("[cargo-miri rustc]", verbose, &cmd); - exec(cmd); -} - -#[derive(Debug, Copy, Clone, PartialEq)] -enum RunnerPhase { - /// `cargo` is running a binary - Cargo, - /// `rustdoc` is running a binary - Rustdoc, -} - -fn phase_runner(mut binary_args: impl Iterator, phase: RunnerPhase) { - // phase_cargo_miri set `MIRI_BE_RUSTC` for when build scripts directly invoke the driver; - // however, if we get called back by cargo here, we'll carefully compute the right flags - // ourselves, so we first un-do what the earlier phase did. - env::remove_var("MIRI_BE_RUSTC"); - - let verbose = std::env::var("MIRI_VERBOSE") - .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); - - let binary = binary_args.next().unwrap(); - let file = File::open(&binary) - .unwrap_or_else(|_| show_error(format!( - "file {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary - ))); - let file = BufReader::new(file); - - let info = serde_json::from_reader(file).unwrap_or_else(|_| { - show_error(format!( - "file {:?} contains outdated or invalid JSON; try `cargo clean`", - binary - )) - }); - let info = match info { - CrateRunInfo::RunWith(info) => info, - CrateRunInfo::SkipProcMacroTest => { - eprintln!( - "Running unit tests of `proc-macro` crates is not currently supported by Miri." - ); - return; - } - }; - - let mut cmd = miri(); - - // Set missing env vars. We prefer build-time env vars over run-time ones; see - // for the kind of issue that fixes. - for (name, val) in info.env { - if let Some(old_val) = env::var_os(&name) { - if old_val == val { - // This one did not actually change, no need to re-set it. - // (This keeps the `debug_cmd` below more manageable.) - continue; - } else if verbose > 0 { - eprintln!( - "[cargo-miri runner] Overwriting run-time env var {:?}={:?} with build-time value {:?}", - name, old_val, val - ); - } - } - cmd.env(name, val); - } - - // Forward rustc arguments. - // We need to patch "--extern" filenames because we forced a check-only - // build without cargo knowing about that: replace `.rlib` suffix by - // `.rmeta`. - // We also need to remove `--error-format` as cargo specifies that to be JSON, - // but when we run here, cargo does not interpret the JSON any more. `--json` - // then also nees to be dropped. - let mut args = info.args.into_iter(); - let error_format_flag = "--error-format"; - let json_flag = "--json"; - while let Some(arg) = args.next() { - if arg == "--extern" { - forward_patched_extern_arg(&mut args, &mut cmd); - } else if let Some(suffix) = arg.strip_prefix(error_format_flag) { - assert!(suffix.starts_with('=')); - // Drop this argument. - } else if let Some(suffix) = arg.strip_prefix(json_flag) { - assert!(suffix.starts_with('=')); - // Drop this argument. - } else { - cmd.arg(arg); - } - } - // Respect `MIRIFLAGS`. - if let Ok(a) = env::var("MIRIFLAGS") { - // This code is taken from `RUSTFLAGS` handling in cargo. - let args = a.split(' ').map(str::trim).filter(|s| !s.is_empty()).map(str::to_string); - cmd.args(args); - } - - // Then pass binary arguments. - cmd.arg("--"); - cmd.args(binary_args); - - // Make sure we use the build-time working directory for interpreting Miri/rustc arguments. - // But then we need to switch to the run-time one, which we instruct Miri do do by setting `MIRI_CWD`. - cmd.current_dir(info.current_dir); - cmd.env("MIRI_CWD", env::current_dir().unwrap()); - - // Run it. - debug_cmd("[cargo-miri runner]", verbose, &cmd); - match phase { - RunnerPhase::Rustdoc => exec_with_pipe(cmd, &info.stdin, format!("{}.stdin", binary)), - RunnerPhase::Cargo => exec(cmd), - } -} - -fn phase_rustdoc(mut args: impl Iterator) { - let verbose = std::env::var("MIRI_VERBOSE") - .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); - - // phase_cargo_miri sets the RUSTDOC env var to ourselves, so we can't use that here; - // just default to a straight-forward invocation for now: - let mut cmd = Command::new("rustdoc"); - - let extern_flag = "--extern"; - let runtool_flag = "--runtool"; - while let Some(arg) = args.next() { - if arg == extern_flag { - // Patch --extern arguments to use *.rmeta files, since phase_cargo_rustc only creates stub *.rlib files. - forward_patched_extern_arg(&mut args, &mut cmd); - } else if arg == runtool_flag { - // An existing --runtool flag indicates cargo is running in cross-target mode, which we don't support. - // Note that this is only passed when cargo is run with the unstable -Zdoctest-xcompile flag; - // otherwise, we won't be called as rustdoc at all. - show_error(format!("cross-interpreting doctests is not currently supported by Miri.")); - } else { - cmd.arg(arg); - } - } - - // Doctests of `proc-macro` crates (and their dependencies) are always built for the host, - // so we are not able to run them in Miri. - if ArgFlagValueIter::new("--crate-type").any(|crate_type| crate_type == "proc-macro") { - eprintln!("Running doctests of `proc-macro` crates is not currently supported by Miri."); - return; - } - - // For each doctest, rustdoc starts two child processes: first the test is compiled, - // then the produced executable is invoked. We want to reroute both of these to cargo-miri, - // such that the first time we'll enter phase_cargo_rustc, and phase_cargo_runner second. - // - // rustdoc invokes the test-builder by forwarding most of its own arguments, which makes - // it difficult to determine when phase_cargo_rustc should run instead of phase_cargo_rustdoc. - // Furthermore, the test code is passed via stdin, rather than a temporary file, so we need - // to let phase_cargo_rustc know to expect that. We'll use this environment variable as a flag: - cmd.env("MIRI_CALLED_FROM_RUSTDOC", "1"); - - // The `--test-builder` and `--runtool` arguments are unstable rustdoc features, - // which are disabled by default. We first need to enable them explicitly: - cmd.arg("-Z").arg("unstable-options"); - - // rustdoc needs to know the right sysroot. - cmd.arg("--sysroot").arg(env::var_os("MIRI_SYSROOT").unwrap()); - // make sure the 'miri' flag is set for rustdoc - cmd.arg("--cfg").arg("miri"); - - // Make rustdoc call us back. - let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); - cmd.arg("--test-builder").arg(&cargo_miri_path); // invoked by forwarding most arguments - cmd.arg("--runtool").arg(&cargo_miri_path); // invoked with just a single path argument - - debug_cmd("[cargo-miri rustdoc]", verbose, &cmd); - exec(cmd) -} - -fn main() { - // Rustc does not support non-UTF-8 arguments so we make no attempt either. - // (We do support non-UTF-8 environment variables though.) - let mut args = std::env::args(); - // Skip binary name. - args.next().unwrap(); - - // Dispatch to `cargo-miri` phase. There are four phases: - // - When we are called via `cargo miri`, we run as the frontend and invoke the underlying - // cargo. We set RUSTDOC, RUSTC_WRAPPER and CARGO_TARGET_RUNNER to ourselves. - // - When we are executed due to RUSTDOC, we run rustdoc and set both `--test-builder` and - // `--runtool` to ourselves. - // - When we are executed due to RUSTC_WRAPPER (or as the rustdoc test builder), we build crates - // or store the flags of binary crates for later interpretation. - // - When we are executed due to CARGO_TARGET_RUNNER (or as the rustdoc runtool), we start - // interpretation based on the flags that were stored earlier. - // - // Additionally, we also set ourselves as RUSTC when calling xargo to build the sysroot, which - // has to be treated slightly differently than when we build regular crates. - - // Dispatch running as part of sysroot compilation. - if env::var_os("MIRI_CALLED_FROM_XARGO").is_some() { - phase_rustc(args, RustcPhase::Setup); - return; - } - - // The way rustdoc invokes rustc is indistuingishable from the way cargo invokes rustdoc by the - // arguments alone. `phase_cargo_rustdoc` sets this environment variable to let us disambiguate. - if env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some() { - // ...however, we then also see this variable when rustdoc invokes us as the testrunner! - // The runner is invoked as `$runtool ($runtool-arg)* output_file`; - // since we don't specify any runtool-args, and rustdoc supplies multiple arguments to - // the test-builder unconditionally, we can just check the number of remaining arguments: - if args.len() == 1 { - phase_runner(args, RunnerPhase::Rustdoc); - } else { - phase_rustc(args, RustcPhase::Rustdoc); - } - - return; - } - - let Some(first) = args.next() else { - show_error(format!( - "`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`" - )) - }; - match first.as_str() { - "miri" => phase_cargo_miri(args), - "runner" => phase_runner(args, RunnerPhase::Cargo), - arg if arg == env::var("RUSTC").unwrap() => { - // If the first arg is equal to the RUSTC env ariable (which should be set at this - // point), then we need to behave as rustc. This is the somewhat counter-intuitive - // behavior of having both RUSTC and RUSTC_WRAPPER set - // (see https://github.com/rust-lang/cargo/issues/10886). - phase_rustc(args, RustcPhase::Build) - } - _ => { - // Everything else must be rustdoc. But we need to get `first` "back onto the iterator", - // it is some part of the rustdoc invocation. - phase_rustdoc(iter::once(first).chain(args)); - } - } -} diff --git a/cargo-miri/src/main.rs b/cargo-miri/src/main.rs new file mode 100644 index 000000000000..9c07f90a4078 --- /dev/null +++ b/cargo-miri/src/main.rs @@ -0,0 +1,95 @@ +#![feature(let_else)] +#![allow(clippy::useless_format, clippy::derive_partial_eq_without_eq)] + +mod phases; +mod setup; +mod util; +mod version; + +use std::{env, iter}; + +use crate::{phases::*, util::*}; + +fn main() { + // Rustc does not support non-UTF-8 arguments so we make no attempt either. + // (We do support non-UTF-8 environment variables though.) + let mut args = std::env::args(); + // Skip binary name. + args.next().unwrap(); + + // Dispatch to `cargo-miri` phase. Here is a rough idea of "who calls who". + // + // Initially, we are invoked as `cargo-miri miri run/test`. We first run the setup phase: + // - We call `xargo`, and set `RUSTC` back to us, together with `MIRI_CALLED_FROM_XARGO`, + // so that xargo's rustc invocations end up in `phase_rustc` with `RustcPhase::Setup`. + // There we then call the Miri driver with `MIRI_BE_RUSTC` to perform the actual build. + // + // Then we call `cargo run/test`, exactly forwarding all user flags, plus some configuration so + // that we control every binary invoked by cargo: + // - We set RUSTC_WRAPPER to ourselves, so for (almost) all rustc invocations, we end up in + // `phase_rustc` with `RustcPhase::Build`. This will in turn either determine that a + // dependency needs to be built (for which it invokes the Miri driver with `MIRI_BE_RUSTC`), + // or determine that this is a binary Miri should run, in which case we generate a JSON file + // with all the information needed to build and run this crate. + // (We don't run it yet since cargo thinks this is a build step, not a run step -- running the + // binary here would lead to a bad user experience.) + // - We set RUSTC to the Miri driver and also set `MIRI_BE_RUSTC`, so that gets called by build + // scripts (and cargo uses it for the version query). + // - We set `target.*.runner` to `cargo-miri runner`, which ends up calling `phase_runner` for + // `RunnerPhase::Cargo`. This parses the JSON file written in `phase_rustc` and then invokes + // the actual Miri driver for interpretation. + // - We set RUSTDOC to ourselves, which ends up in `phase_rustdoc`. There we call regular + // rustdoc with some extra flags, and we set `MIRI_CALLED_FROM_RUSTDOC` to recognize this + // phase in our recursive invocations: + // - We set the `--test-builder` flag of rustdoc to ourselves, which ends up in `phase_rustc` + // with `RustcPhase::Rustdoc`. There we perform a check-build (needed to get the expected + // build failures for `compile_fail` doctests) and then store a JSON file with the + // information needed to run this test. + // - We also set `--runtool` to ourselves, which ends up in `phase_runner` with + // `RunnerPhase::Rustdoc`. There we parse the JSON file written in `phase_rustc` and invoke + // the Miri driver for interpretation. + + // Dispatch running as part of sysroot compilation. + if env::var_os("MIRI_CALLED_FROM_XARGO").is_some() { + phase_rustc(args, RustcPhase::Setup); + return; + } + + // The way rustdoc invokes rustc is indistuingishable from the way cargo invokes rustdoc by the + // arguments alone. `phase_cargo_rustdoc` sets this environment variable to let us disambiguate. + if env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some() { + // ...however, we then also see this variable when rustdoc invokes us as the testrunner! + // The runner is invoked as `$runtool ($runtool-arg)* output_file`; + // since we don't specify any runtool-args, and rustdoc supplies multiple arguments to + // the test-builder unconditionally, we can just check the number of remaining arguments: + if args.len() == 1 { + phase_runner(args, RunnerPhase::Rustdoc); + } else { + phase_rustc(args, RustcPhase::Rustdoc); + } + + return; + } + + let Some(first) = args.next() else { + show_error(format!( + "`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`" + )) + }; + match first.as_str() { + "miri" => phase_cargo_miri(args), + "runner" => phase_runner(args, RunnerPhase::Cargo), + arg if arg == env::var("RUSTC").unwrap() => { + // If the first arg is equal to the RUSTC env ariable (which should be set at this + // point), then we need to behave as rustc. This is the somewhat counter-intuitive + // behavior of having both RUSTC and RUSTC_WRAPPER set + // (see https://github.com/rust-lang/cargo/issues/10886). + phase_rustc(args, RustcPhase::Build) + } + _ => { + // Everything else must be rustdoc. But we need to get `first` "back onto the iterator", + // it is some part of the rustdoc invocation. + phase_rustdoc(iter::once(first).chain(args)); + } + } +} diff --git a/cargo-miri/src/phases.rs b/cargo-miri/src/phases.rs new file mode 100644 index 000000000000..4ba627de482c --- /dev/null +++ b/cargo-miri/src/phases.rs @@ -0,0 +1,601 @@ +//! Implements the various phases of `cargo miri run/test`. + +use std::env; +use std::fmt::Write as _; +use std::fs::{self, File}; +use std::io::BufReader; +use std::path::PathBuf; +use std::process::Command; + +use crate::{setup::*, util::*}; + +const CARGO_MIRI_HELP: &str = r#"Runs binary crates and tests in Miri + +Usage: + cargo miri [subcommand] [...] [--] [...] + +Subcommands: + run, r Run binaries + test, t Run tests + nextest Run tests with nextest (requires cargo-nextest installed) + setup Only perform automatic setup, but without asking questions (for getting a proper libstd) + +The cargo options are exactly the same as for `cargo run` and `cargo test`, respectively. + +Examples: + cargo miri run + cargo miri test -- test-suite-filter + + cargo miri setup --print sysroot + This will print the path to the generated sysroot (and nothing else) on stdout. + stderr will still contain progress information about how the build is doing. + +"#; + +fn show_help() { + println!("{}", CARGO_MIRI_HELP); +} + +fn show_version() { + let mut version = format!("miri {}", env!("CARGO_PKG_VERSION")); + // Only use `option_env` on vergen variables to ensure the build succeeds + // when vergen failed to find the git info. + if let Some(sha) = option_env!("VERGEN_GIT_SHA_SHORT") { + // This `unwrap` can never fail because if VERGEN_GIT_SHA_SHORT exists, then so does + // VERGEN_GIT_COMMIT_DATE. + #[allow(clippy::option_env_unwrap)] + write!(&mut version, " ({} {})", sha, option_env!("VERGEN_GIT_COMMIT_DATE").unwrap()) + .unwrap(); + } + println!("{}", version); +} + +fn forward_patched_extern_arg(args: &mut impl Iterator, cmd: &mut Command) { + cmd.arg("--extern"); // always forward flag, but adjust filename: + let path = args.next().expect("`--extern` should be followed by a filename"); + if let Some(lib) = path.strip_suffix(".rlib") { + // If this is an rlib, make it an rmeta. + cmd.arg(format!("{}.rmeta", lib)); + } else { + // Some other extern file (e.g. a `.so`). Forward unchanged. + cmd.arg(path); + } +} + +pub fn phase_cargo_miri(mut args: impl Iterator) { + // Check for version and help flags even when invoked as `cargo-miri`. + if has_arg_flag("--help") || has_arg_flag("-h") { + show_help(); + return; + } + if has_arg_flag("--version") || has_arg_flag("-V") { + show_version(); + return; + } + + // Require a subcommand before any flags. + // We cannot know which of those flags take arguments and which do not, + // so we cannot detect subcommands later. + let Some(subcommand) = args.next() else { + show_error(format!("`cargo miri` needs to be called with a subcommand (`run`, `test`)")); + }; + let subcommand = match &*subcommand { + "setup" => MiriCommand::Setup, + "test" | "t" | "run" | "r" | "nextest" => MiriCommand::Forward(subcommand), + _ => + show_error(format!( + "`cargo miri` supports the following subcommands: `run`, `test`, `nextest`, and `setup`." + )), + }; + let verbose = num_arg_flag("-v"); + + // Determine the involved architectures. + let host = version_info().host; + let target = get_arg_flag_value("--target"); + let target = target.as_ref().unwrap_or(&host); + + // We always setup. + setup(&subcommand, &host, target); + + // Invoke actual cargo for the job, but with different flags. + // We re-use `cargo test` and `cargo run`, which makes target and binary handling very easy but + // requires some extra work to make the build check-only (see all the `--emit` hacks below). + // describes an alternative + // approach that uses `cargo check`, making that part easier but target and binary handling + // harder. + let cargo_miri_path = std::env::current_exe() + .expect("current executable path invalid") + .into_os_string() + .into_string() + .expect("current executable path is not valid UTF-8"); + let cargo_cmd = match subcommand { + MiriCommand::Forward(s) => s, + MiriCommand::Setup => return, // `cargo miri setup` stops here. + }; + let metadata = get_cargo_metadata(); + let mut cmd = cargo(); + cmd.arg(cargo_cmd); + + // Forward all arguments before `--` other than `--target-dir` and its value to Cargo. + let mut target_dir = None; + for arg in ArgSplitFlagValue::new(&mut args, "--target-dir") { + match arg { + Ok(value) => { + if target_dir.is_some() { + show_error(format!("`--target-dir` is provided more than once")); + } + target_dir = Some(value.into()); + } + Err(arg) => { + cmd.arg(arg); + } + } + } + // Detect the target directory if it's not specified via `--target-dir`. + let target_dir = target_dir.get_or_insert_with(|| metadata.target_directory.clone()); + // Set `--target-dir` to `miri` inside the original target directory. + target_dir.push("miri"); + cmd.arg("--target-dir").arg(target_dir); + + // Make sure the build target is explicitly set. + // This is needed to make the `target.runner` settings do something, + // and it later helps us detect which crates are proc-macro/build-script + // (host crates) and which crates are needed for the program itself. + if get_arg_flag_value("--target").is_none() { + // No target given. Explicitly pick the host. + cmd.arg("--target"); + cmd.arg(&host); + } + + // Set ourselves as runner for al binaries invoked by cargo. + // We use `all()` since `true` is not a thing in cfg-lang, but the empty conjunction is. :) + let cargo_miri_path_for_toml = escape_for_toml(&cargo_miri_path); + cmd.arg("--config") + .arg(format!("target.'cfg(all())'.runner=[{cargo_miri_path_for_toml}, 'runner']")); + + // Forward all further arguments after `--` to cargo. + cmd.arg("--").args(args); + + // Set `RUSTC_WRAPPER` to ourselves. Cargo will prepend that binary to its usual invocation, + // i.e., the first argument is `rustc` -- which is what we use in `main` to distinguish + // the two codepaths. (That extra argument is why we prefer this over setting `RUSTC`.) + if env::var_os("RUSTC_WRAPPER").is_some() { + println!( + "WARNING: Ignoring `RUSTC_WRAPPER` environment variable, Miri does not support wrapping." + ); + } + cmd.env("RUSTC_WRAPPER", &cargo_miri_path); + // We are going to invoke `MIRI` for everything, not `RUSTC`. + if env::var_os("RUSTC").is_some() && env::var_os("MIRI").is_none() { + println!( + "WARNING: Ignoring `RUSTC` environment variable; set `MIRI` if you want to control the binary used as the driver." + ); + } + // Build scripts (and also cargo: https://github.com/rust-lang/cargo/issues/10885) will invoke + // `rustc` even when `RUSTC_WRAPPER` is set. To make sure everything is coherent, we want that + // to be the Miri driver, but acting as rustc, on the target level. (Target, rather than host, + // is needed for cross-interpretation situations.) This is not a perfect emulation of real rustc + // (it might be unable to produce binaries since the sysroot is check-only), but it's as close + // as we can get, and it's good enough for autocfg. + // + // In `main`, we need the value of `RUSTC` to distinguish RUSTC_WRAPPER invocations from rustdoc + // or TARGET_RUNNER invocations, so we canonicalize it here to make it exceedingly unlikely that + // there would be a collision with other invocations of cargo-miri (as rustdoc or as runner). We + // explicitly do this even if RUSTC_STAGE is set, since for these builds we do *not* want the + // bootstrap `rustc` thing in our way! Instead, we have MIRI_HOST_SYSROOT to use for host + // builds. + cmd.env("RUSTC", &fs::canonicalize(find_miri()).unwrap()); + cmd.env("MIRI_BE_RUSTC", "target"); // we better remember to *unset* this in the other phases! + + // Set rustdoc to us as well, so we can run doctests. + cmd.env("RUSTDOC", &cargo_miri_path); + + cmd.env("MIRI_LOCAL_CRATES", local_crates(&metadata)); + if verbose > 0 { + cmd.env("MIRI_VERBOSE", verbose.to_string()); // This makes the other phases verbose. + } + + // Run cargo. + debug_cmd("[cargo-miri miri]", verbose, &cmd); + exec(cmd) +} + +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum RustcPhase { + /// `rustc` called via `xargo` for sysroot build. + Setup, + /// `rustc` called by `cargo` for regular build. + Build, + /// `rustc` called by `rustdoc` for doctest. + Rustdoc, +} + +pub fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { + /// Determines if we are being invoked (as rustc) to build a crate for + /// the "target" architecture, in contrast to the "host" architecture. + /// Host crates are for build scripts and proc macros and still need to + /// be built like normal; target crates need to be built for or interpreted + /// by Miri. + /// + /// Currently, we detect this by checking for "--target=", which is + /// never set for host crates. This matches what rustc bootstrap does, + /// which hopefully makes it "reliable enough". This relies on us always + /// invoking cargo itself with `--target`, which `in_cargo_miri` ensures. + fn is_target_crate() -> bool { + get_arg_flag_value("--target").is_some() + } + + /// Returns whether or not Cargo invoked the wrapper (this binary) to compile + /// the final, binary crate (either a test for 'cargo test', or a binary for 'cargo run') + /// Cargo does not give us this information directly, so we need to check + /// various command-line flags. + fn is_runnable_crate() -> bool { + let is_bin = get_arg_flag_value("--crate-type").as_deref().unwrap_or("bin") == "bin"; + let is_test = has_arg_flag("--test"); + is_bin || is_test + } + + fn out_filename(prefix: &str, suffix: &str) -> PathBuf { + if let Some(out_dir) = get_arg_flag_value("--out-dir") { + let mut path = PathBuf::from(out_dir); + path.push(format!( + "{}{}{}{}", + prefix, + get_arg_flag_value("--crate-name").unwrap(), + // This is technically a `-C` flag but the prefix seems unique enough... + // (and cargo passes this before the filename so it should be unique) + get_arg_flag_value("extra-filename").unwrap_or_default(), + suffix, + )); + path + } else { + let out_file = get_arg_flag_value("-o").unwrap(); + PathBuf::from(out_file) + } + } + + // phase_cargo_miri set `MIRI_BE_RUSTC` for when build scripts directly invoke the driver; + // however, if we get called back by cargo here, we'll carefully compute the right flags + // ourselves, so we first un-do what the earlier phase did. + env::remove_var("MIRI_BE_RUSTC"); + + let verbose = std::env::var("MIRI_VERBOSE") + .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); + let target_crate = is_target_crate(); + // Determine whether this is cargo/xargo invoking rustc to get some infos. + let info_query = get_arg_flag_value("--print").is_some() || has_arg_flag("-vV"); + + let store_json = |info: CrateRunInfo| { + // Create a stub .d file to stop Cargo from "rebuilding" the crate: + // https://github.com/rust-lang/miri/issues/1724#issuecomment-787115693 + // As we store a JSON file instead of building the crate here, an empty file is fine. + let dep_info_name = out_filename("", ".d"); + if verbose > 0 { + eprintln!("[cargo-miri rustc] writing stub dep-info to `{}`", dep_info_name.display()); + } + File::create(dep_info_name).expect("failed to create fake .d file"); + + let filename = out_filename("", ""); + if verbose > 0 { + eprintln!("[cargo-miri rustc] writing run info to `{}`", filename.display()); + } + info.store(&filename); + // For Windows, do the same thing again with `.exe` appended to the filename. + // (Need to do this here as cargo moves that "binary" to a different place before running it.) + info.store(&out_filename("", ".exe")); + }; + + let runnable_crate = !info_query && is_runnable_crate(); + + if runnable_crate && target_crate { + assert!( + phase != RustcPhase::Setup, + "there should be no interpretation during sysroot build" + ); + let inside_rustdoc = phase == RustcPhase::Rustdoc; + // This is the binary or test crate that we want to interpret under Miri. + // But we cannot run it here, as cargo invoked us as a compiler -- our stdin and stdout are not + // like we want them. + // Instead of compiling, we write JSON into the output file with all the relevant command-line flags + // and environment variables; this is used when cargo calls us again in the CARGO_TARGET_RUNNER phase. + let env = CrateRunEnv::collect(args, inside_rustdoc); + + store_json(CrateRunInfo::RunWith(env.clone())); + + // Rustdoc expects us to exit with an error code if the test is marked as `compile_fail`, + // just creating the JSON file is not enough: we need to detect syntax errors, + // so we need to run Miri with `MIRI_BE_RUSTC` for a check-only build. + if inside_rustdoc { + let mut cmd = miri(); + + // Ensure --emit argument for a check-only build is present. + // We cannot use the usual helpers since we need to check specifically in `env.args`. + if let Some(i) = env.args.iter().position(|arg| arg.starts_with("--emit=")) { + // For `no_run` tests, rustdoc passes a `--emit` flag; make sure it has the right shape. + assert_eq!(env.args[i], "--emit=metadata"); + } else { + // For all other kinds of tests, we can just add our flag. + cmd.arg("--emit=metadata"); + } + + // Alter the `-o` parameter so that it does not overwrite the JSON file we stored above. + let mut args = env.args.clone(); + for i in 0..args.len() { + if args[i] == "-o" { + args[i + 1].push_str(".miri"); + } + } + + cmd.args(&args); + cmd.env("MIRI_BE_RUSTC", "target"); + + if verbose > 0 { + eprintln!( + "[cargo-miri rustc inside rustdoc] captured input:\n{}", + std::str::from_utf8(&env.stdin).unwrap() + ); + eprintln!("[cargo-miri rustc inside rustdoc] going to run:\n{:?}", cmd); + } + + exec_with_pipe(cmd, &env.stdin, format!("{}.stdin", out_filename("", "").display())); + } + + return; + } + + if runnable_crate && ArgFlagValueIter::new("--extern").any(|krate| krate == "proc_macro") { + // This is a "runnable" `proc-macro` crate (unit tests). We do not support + // interpreting that under Miri now, so we write a JSON file to (display a + // helpful message and) skip it in the runner phase. + store_json(CrateRunInfo::SkipProcMacroTest); + return; + } + + let mut cmd = miri(); + let mut emit_link_hack = false; + // Arguments are treated very differently depending on whether this crate is + // for interpretation by Miri, or for use by a build script / proc macro. + if !info_query && target_crate { + // Forward arguments, but remove "link" from "--emit" to make this a check-only build. + let emit_flag = "--emit"; + while let Some(arg) = args.next() { + if let Some(val) = arg.strip_prefix(emit_flag) { + // Patch this argument. First, extract its value. + let val = + val.strip_prefix('=').expect("`cargo` should pass `--emit=X` as one argument"); + let mut val: Vec<_> = val.split(',').collect(); + // Now make sure "link" is not in there, but "metadata" is. + if let Some(i) = val.iter().position(|&s| s == "link") { + emit_link_hack = true; + val.remove(i); + if !val.iter().any(|&s| s == "metadata") { + val.push("metadata"); + } + } + cmd.arg(format!("{}={}", emit_flag, val.join(","))); + } else if arg == "--extern" { + // Patch `--extern` filenames, since Cargo sometimes passes stub `.rlib` files: + // https://github.com/rust-lang/miri/issues/1705 + forward_patched_extern_arg(&mut args, &mut cmd); + } else { + cmd.arg(arg); + } + } + + // During setup, patch the panic runtime for `libpanic_abort` (mirroring what bootstrap usually does). + if phase == RustcPhase::Setup + && get_arg_flag_value("--crate-name").as_deref() == Some("panic_abort") + { + cmd.arg("-C").arg("panic=abort"); + } + } else { + // For host crates (but not when we are just printing some info), + // we might still have to set the sysroot. + if !info_query { + // When we're running `cargo-miri` from `x.py` we need to pass the sysroot explicitly + // due to bootstrap complications. + if let Some(sysroot) = std::env::var_os("MIRI_HOST_SYSROOT") { + cmd.arg("--sysroot").arg(sysroot); + } + } + + // For host crates or when we are printing, just forward everything. + cmd.args(args); + } + + // We want to compile, not interpret. We still use Miri to make sure the compiler version etc + // are the exact same as what is used for interpretation. + // MIRI_DEFAULT_ARGS should not be used to build host crates, hence setting "target" or "host" + // as the value here to help Miri differentiate them. + cmd.env("MIRI_BE_RUSTC", if target_crate { "target" } else { "host" }); + + // Run it. + if verbose > 0 { + eprintln!( + "[cargo-miri rustc] target_crate={target_crate} runnable_crate={runnable_crate} info_query={info_query}" + ); + } + + // Create a stub .rlib file if "link" was requested by cargo. + // This is necessary to prevent cargo from doing rebuilds all the time. + if emit_link_hack { + // Some platforms prepend "lib", some do not... let's just create both files. + File::create(out_filename("lib", ".rlib")).expect("failed to create fake .rlib file"); + File::create(out_filename("", ".rlib")).expect("failed to create fake .rlib file"); + // Just in case this is a cdylib or staticlib, also create those fake files. + File::create(out_filename("lib", ".so")).expect("failed to create fake .so file"); + File::create(out_filename("lib", ".a")).expect("failed to create fake .a file"); + File::create(out_filename("lib", ".dylib")).expect("failed to create fake .dylib file"); + File::create(out_filename("", ".dll")).expect("failed to create fake .dll file"); + File::create(out_filename("", ".lib")).expect("failed to create fake .lib file"); + } + + debug_cmd("[cargo-miri rustc]", verbose, &cmd); + exec(cmd); +} + +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum RunnerPhase { + /// `cargo` is running a binary + Cargo, + /// `rustdoc` is running a binary + Rustdoc, +} + +pub fn phase_runner(mut binary_args: impl Iterator, phase: RunnerPhase) { + // phase_cargo_miri set `MIRI_BE_RUSTC` for when build scripts directly invoke the driver; + // however, if we get called back by cargo here, we'll carefully compute the right flags + // ourselves, so we first un-do what the earlier phase did. + env::remove_var("MIRI_BE_RUSTC"); + + let verbose = std::env::var("MIRI_VERBOSE") + .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); + + let binary = binary_args.next().unwrap(); + let file = File::open(&binary) + .unwrap_or_else(|_| show_error(format!( + "file {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary + ))); + let file = BufReader::new(file); + + let info = serde_json::from_reader(file).unwrap_or_else(|_| { + show_error(format!( + "file {:?} contains outdated or invalid JSON; try `cargo clean`", + binary + )) + }); + let info = match info { + CrateRunInfo::RunWith(info) => info, + CrateRunInfo::SkipProcMacroTest => { + eprintln!( + "Running unit tests of `proc-macro` crates is not currently supported by Miri." + ); + return; + } + }; + + let mut cmd = miri(); + + // Set missing env vars. We prefer build-time env vars over run-time ones; see + // for the kind of issue that fixes. + for (name, val) in info.env { + if let Some(old_val) = env::var_os(&name) { + if old_val == val { + // This one did not actually change, no need to re-set it. + // (This keeps the `debug_cmd` below more manageable.) + continue; + } else if verbose > 0 { + eprintln!( + "[cargo-miri runner] Overwriting run-time env var {:?}={:?} with build-time value {:?}", + name, old_val, val + ); + } + } + cmd.env(name, val); + } + + // Forward rustc arguments. + // We need to patch "--extern" filenames because we forced a check-only + // build without cargo knowing about that: replace `.rlib` suffix by + // `.rmeta`. + // We also need to remove `--error-format` as cargo specifies that to be JSON, + // but when we run here, cargo does not interpret the JSON any more. `--json` + // then also nees to be dropped. + let mut args = info.args.into_iter(); + let error_format_flag = "--error-format"; + let json_flag = "--json"; + while let Some(arg) = args.next() { + if arg == "--extern" { + forward_patched_extern_arg(&mut args, &mut cmd); + } else if let Some(suffix) = arg.strip_prefix(error_format_flag) { + assert!(suffix.starts_with('=')); + // Drop this argument. + } else if let Some(suffix) = arg.strip_prefix(json_flag) { + assert!(suffix.starts_with('=')); + // Drop this argument. + } else { + cmd.arg(arg); + } + } + // Respect `MIRIFLAGS`. + if let Ok(a) = env::var("MIRIFLAGS") { + // This code is taken from `RUSTFLAGS` handling in cargo. + let args = a.split(' ').map(str::trim).filter(|s| !s.is_empty()).map(str::to_string); + cmd.args(args); + } + + // Then pass binary arguments. + cmd.arg("--"); + cmd.args(binary_args); + + // Make sure we use the build-time working directory for interpreting Miri/rustc arguments. + // But then we need to switch to the run-time one, which we instruct Miri do do by setting `MIRI_CWD`. + cmd.current_dir(info.current_dir); + cmd.env("MIRI_CWD", env::current_dir().unwrap()); + + // Run it. + debug_cmd("[cargo-miri runner]", verbose, &cmd); + match phase { + RunnerPhase::Rustdoc => exec_with_pipe(cmd, &info.stdin, format!("{}.stdin", binary)), + RunnerPhase::Cargo => exec(cmd), + } +} + +pub fn phase_rustdoc(mut args: impl Iterator) { + let verbose = std::env::var("MIRI_VERBOSE") + .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); + + // phase_cargo_miri sets the RUSTDOC env var to ourselves, so we can't use that here; + // just default to a straight-forward invocation for now: + let mut cmd = Command::new("rustdoc"); + + let extern_flag = "--extern"; + let runtool_flag = "--runtool"; + while let Some(arg) = args.next() { + if arg == extern_flag { + // Patch --extern arguments to use *.rmeta files, since phase_cargo_rustc only creates stub *.rlib files. + forward_patched_extern_arg(&mut args, &mut cmd); + } else if arg == runtool_flag { + // An existing --runtool flag indicates cargo is running in cross-target mode, which we don't support. + // Note that this is only passed when cargo is run with the unstable -Zdoctest-xcompile flag; + // otherwise, we won't be called as rustdoc at all. + show_error(format!("cross-interpreting doctests is not currently supported by Miri.")); + } else { + cmd.arg(arg); + } + } + + // Doctests of `proc-macro` crates (and their dependencies) are always built for the host, + // so we are not able to run them in Miri. + if ArgFlagValueIter::new("--crate-type").any(|crate_type| crate_type == "proc-macro") { + eprintln!("Running doctests of `proc-macro` crates is not currently supported by Miri."); + return; + } + + // For each doctest, rustdoc starts two child processes: first the test is compiled, + // then the produced executable is invoked. We want to reroute both of these to cargo-miri, + // such that the first time we'll enter phase_cargo_rustc, and phase_cargo_runner second. + // + // rustdoc invokes the test-builder by forwarding most of its own arguments, which makes + // it difficult to determine when phase_cargo_rustc should run instead of phase_cargo_rustdoc. + // Furthermore, the test code is passed via stdin, rather than a temporary file, so we need + // to let phase_cargo_rustc know to expect that. We'll use this environment variable as a flag: + cmd.env("MIRI_CALLED_FROM_RUSTDOC", "1"); + + // The `--test-builder` and `--runtool` arguments are unstable rustdoc features, + // which are disabled by default. We first need to enable them explicitly: + cmd.arg("-Z").arg("unstable-options"); + + // rustdoc needs to know the right sysroot. + cmd.arg("--sysroot").arg(env::var_os("MIRI_SYSROOT").unwrap()); + // make sure the 'miri' flag is set for rustdoc + cmd.arg("--cfg").arg("miri"); + + // Make rustdoc call us back. + let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); + cmd.arg("--test-builder").arg(&cargo_miri_path); // invoked by forwarding most arguments + cmd.arg("--runtool").arg(&cargo_miri_path); // invoked with just a single path argument + + debug_cmd("[cargo-miri rustdoc]", verbose, &cmd); + exec(cmd) +} diff --git a/cargo-miri/src/setup.rs b/cargo-miri/src/setup.rs new file mode 100644 index 000000000000..1211b47e3ba2 --- /dev/null +++ b/cargo-miri/src/setup.rs @@ -0,0 +1,247 @@ +//! Implements `cargo miri setup` via xargo + +use std::env; +use std::ffi::OsStr; +use std::fs::{self}; +use std::io::BufRead; +use std::ops::Not; +use std::path::{Path, PathBuf}; +use std::process::{self, Command}; + +use crate::{util::*, version::*}; + +fn xargo_version() -> Option<(u32, u32, u32)> { + let out = xargo_check().arg("--version").output().ok()?; + if !out.status.success() { + return None; + } + // Parse output. The first line looks like "xargo 0.3.12 (b004f1c 2018-12-13)". + let line = out + .stderr + .lines() + .next() + .expect("malformed `xargo --version` output: not at least one line") + .expect("malformed `xargo --version` output: error reading first line"); + let (name, version) = { + let mut split = line.split(' '); + ( + split.next().expect("malformed `xargo --version` output: empty"), + split.next().expect("malformed `xargo --version` output: not at least two words"), + ) + }; + if name != "xargo" { + // This is some fork of xargo + return None; + } + let mut version_pieces = version.split('.'); + let major = version_pieces + .next() + .expect("malformed `xargo --version` output: not a major version piece") + .parse() + .expect("malformed `xargo --version` output: major version is not an integer"); + let minor = version_pieces + .next() + .expect("malformed `xargo --version` output: not a minor version piece") + .parse() + .expect("malformed `xargo --version` output: minor version is not an integer"); + let patch = version_pieces + .next() + .expect("malformed `xargo --version` output: not a patch version piece") + .parse() + .expect("malformed `xargo --version` output: patch version is not an integer"); + if version_pieces.next().is_some() { + panic!("malformed `xargo --version` output: more than three pieces in version"); + } + Some((major, minor, patch)) +} + +/// Performs the setup required to make `cargo miri` work: Getting a custom-built libstd. Then sets +/// `MIRI_SYSROOT`. Skipped if `MIRI_SYSROOT` is already set, in which case we expect the user has +/// done all this already. +pub fn setup(subcommand: &MiriCommand, host: &str, target: &str) { + let only_setup = matches!(subcommand, MiriCommand::Setup); + let ask_user = !only_setup; + let print_sysroot = only_setup && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path + if std::env::var_os("MIRI_SYSROOT").is_some() { + if only_setup { + println!("WARNING: MIRI_SYSROOT already set, not doing anything.") + } + return; + } + + // First, we need xargo. + if xargo_version().map_or(true, |v| v < XARGO_MIN_VERSION) { + if std::env::var_os("XARGO_CHECK").is_some() { + // The user manually gave us a xargo binary; don't do anything automatically. + show_error(format!("xargo is too old; please upgrade to the latest version")) + } + let mut cmd = cargo(); + cmd.args(&["install", "xargo"]); + ask_to_run(cmd, ask_user, "install a recent enough xargo"); + } + + // Determine where the rust sources are located. The env vars manually setting the source + // (`MIRI_LIB_SRC`, `XARGO_RUST_SRC`) trump auto-detection. + let rust_src_env_var = + std::env::var_os("MIRI_LIB_SRC").or_else(|| std::env::var_os("XARGO_RUST_SRC")); + let rust_src = match rust_src_env_var { + Some(path) => { + let path = PathBuf::from(path); + // Make path absolute if possible. + path.canonicalize().unwrap_or(path) + } + None => { + // Check for `rust-src` rustup component. + let output = miri_for_host() + .args(&["--print", "sysroot"]) + .output() + .expect("failed to determine sysroot"); + if !output.status.success() { + show_error(format!( + "Failed to determine sysroot; Miri said:\n{}", + String::from_utf8_lossy(&output.stderr).trim_end() + )); + } + let sysroot = std::str::from_utf8(&output.stdout).unwrap(); + let sysroot = Path::new(sysroot.trim_end_matches('\n')); + // Check for `$SYSROOT/lib/rustlib/src/rust/library`; test if that contains `std/Cargo.toml`. + let rustup_src = + sysroot.join("lib").join("rustlib").join("src").join("rust").join("library"); + if !rustup_src.join("std").join("Cargo.toml").exists() { + // Ask the user to install the `rust-src` component, and use that. + let mut cmd = Command::new("rustup"); + cmd.args(&["component", "add", "rust-src"]); + ask_to_run( + cmd, + ask_user, + "install the `rust-src` component for the selected toolchain", + ); + } + rustup_src + } + }; + if !rust_src.exists() { + show_error(format!("given Rust source directory `{}` does not exist.", rust_src.display())); + } + if rust_src.file_name().and_then(OsStr::to_str) != Some("library") { + show_error(format!( + "given Rust source directory `{}` does not seem to be the `library` subdirectory of \ + a Rust source checkout.", + rust_src.display() + )); + } + + // Next, we need our own libstd. Prepare a xargo project for that purpose. + // We will do this work in whatever is a good cache dir for this platform. + let dirs = directories::ProjectDirs::from("org", "rust-lang", "miri").unwrap(); + let dir = dirs.cache_dir(); + if !dir.exists() { + fs::create_dir_all(&dir).unwrap(); + } + // The interesting bit: Xargo.toml (only needs content if we actually need std) + let xargo_toml = if std::env::var_os("MIRI_NO_STD").is_some() { + "" + } else { + r#" +[dependencies.std] +default_features = false +# We support unwinding, so enable that panic runtime. +features = ["panic_unwind", "backtrace"] + +[dependencies.test] +"# + }; + write_to_file(&dir.join("Xargo.toml"), xargo_toml); + // The boring bits: a dummy project for xargo. + // FIXME: With xargo-check, can we avoid doing this? + write_to_file( + &dir.join("Cargo.toml"), + r#" +[package] +name = "miri-xargo" +description = "A dummy project for building libstd with xargo." +version = "0.0.0" + +[lib] +path = "lib.rs" +"#, + ); + write_to_file(&dir.join("lib.rs"), "#![no_std]"); + + // Figure out where xargo will build its stuff. + // Unfortunately, it puts things into a different directory when the + // architecture matches the host. + let sysroot = if target == host { dir.join("HOST") } else { PathBuf::from(dir) }; + // Make sure all target-level Miri invocations know their sysroot. + std::env::set_var("MIRI_SYSROOT", &sysroot); + + // Now invoke xargo. + let mut command = xargo_check(); + command.arg("check").arg("-q"); + command.current_dir(&dir); + command.env("XARGO_HOME", &dir); + command.env("XARGO_RUST_SRC", &rust_src); + // We always need to set a target so rustc bootstrap can tell apart host from target crates. + command.arg("--target").arg(target); + // Use Miri as rustc to build a libstd compatible with us (and use the right flags). + // However, when we are running in bootstrap, we cannot just overwrite `RUSTC`, + // because we still need bootstrap to distinguish between host and target crates. + // In that case we overwrite `RUSTC_REAL` instead which determines the rustc used + // for target crates. + // We set ourselves (`cargo-miri`) instead of Miri directly to be able to patch the flags + // for `libpanic_abort` (usually this is done by bootstrap but we have to do it ourselves). + // The `MIRI_CALLED_FROM_XARGO` will mean we dispatch to `phase_setup_rustc`. + let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); + if env::var_os("RUSTC_STAGE").is_some() { + assert!(env::var_os("RUSTC").is_some()); + command.env("RUSTC_REAL", &cargo_miri_path); + } else { + command.env("RUSTC", &cargo_miri_path); + } + command.env("MIRI_CALLED_FROM_XARGO", "1"); + // Make sure there are no other wrappers getting in our way + // (Cc https://github.com/rust-lang/miri/issues/1421, https://github.com/rust-lang/miri/issues/2429). + // Looks like setting `RUSTC_WRAPPER` to the empty string overwrites `build.rustc-wrapper` set via `config.toml`. + command.env("RUSTC_WRAPPER", ""); + // Disable debug assertions in the standard library -- Miri is already slow enough. But keep the + // overflow checks, they are cheap. This completely overwrites flags the user might have set, + // which is consistent with normal `cargo build` that does not apply `RUSTFLAGS` to the sysroot + // either. + command.env("RUSTFLAGS", "-Cdebug-assertions=off -Coverflow-checks=on"); + // Manage the output the user sees. + if only_setup { + // We want to be explicit. + eprintln!("Preparing a sysroot for Miri (target: {target})..."); + if print_sysroot { + // Be extra sure there is no noise on stdout. + command.stdout(process::Stdio::null()); + } + } else { + // We want to be quiet, but still let the user know that something is happening. + eprint!("Preparing a sysroot for Miri (target: {target})... "); + command.stdout(process::Stdio::null()); + command.stderr(process::Stdio::null()); + } + + // Finally run it! + if command.status().expect("failed to run xargo").success().not() { + if only_setup { + show_error(format!("failed to run xargo, see error details above")) + } else { + show_error(format!( + "failed to run xargo; run `cargo miri setup` to see the error details" + )) + } + } + + // Figure out what to print. + if only_setup { + eprintln!("A sysroot for Miri is now available in `{}`.", sysroot.display()); + } else { + eprintln!("done"); + } + if print_sysroot { + // Print just the sysroot and nothing else to stdout; this way we do not need any escaping. + println!("{}", sysroot.display()); + } +} diff --git a/cargo-miri/src/util.rs b/cargo-miri/src/util.rs new file mode 100644 index 000000000000..d6a42a2f855d --- /dev/null +++ b/cargo-miri/src/util.rs @@ -0,0 +1,375 @@ +use std::collections::HashMap; +use std::env; +use std::ffi::OsString; +use std::fmt::Write as _; +use std::fs::{self, File}; +use std::io::{self, BufWriter, Read, Write}; +use std::iter::TakeWhile; +use std::ops::Not; +use std::path::{Path, PathBuf}; +use std::process::Command; + +use cargo_metadata::{Metadata, MetadataCommand}; +use rustc_version::VersionMeta; +use serde::{Deserialize, Serialize}; + +/// The information to run a crate with the given environment. +#[derive(Clone, Serialize, Deserialize)] +pub struct CrateRunEnv { + /// The command-line arguments. + pub args: Vec, + /// The environment. + pub env: Vec<(OsString, OsString)>, + /// The current working directory. + pub current_dir: OsString, + /// The contents passed via standard input. + pub stdin: Vec, +} + +impl CrateRunEnv { + /// Gather all the information we need. + pub fn collect(args: impl Iterator, capture_stdin: bool) -> Self { + let args = args.collect(); + let env = env::vars_os().collect(); + let current_dir = env::current_dir().unwrap().into_os_string(); + + let mut stdin = Vec::new(); + if capture_stdin { + std::io::stdin().lock().read_to_end(&mut stdin).expect("cannot read stdin"); + } + + CrateRunEnv { args, env, current_dir, stdin } + } +} + +/// The information Miri needs to run a crate. Stored as JSON when the crate is "compiled". +#[derive(Serialize, Deserialize)] +pub enum CrateRunInfo { + /// Run it with the given environment. + RunWith(CrateRunEnv), + /// Skip it as Miri does not support interpreting such kind of crates. + SkipProcMacroTest, +} + +impl CrateRunInfo { + pub fn store(&self, filename: &Path) { + let file = File::create(filename) + .unwrap_or_else(|_| show_error(format!("cannot create `{}`", filename.display()))); + let file = BufWriter::new(file); + serde_json::ser::to_writer(file, self) + .unwrap_or_else(|_| show_error(format!("cannot write to `{}`", filename.display()))); + } +} + +#[derive(Clone, Debug)] +pub enum MiriCommand { + /// Our own special 'setup' command. + Setup, + /// A command to be forwarded to cargo. + Forward(String), +} + +pub fn show_error(msg: String) -> ! { + eprintln!("fatal error: {}", msg); + std::process::exit(1) +} + +/// Determines whether a `--flag` is present. +pub fn has_arg_flag(name: &str) -> bool { + num_arg_flag(name) > 0 +} + +/// Determines how many times a `--flag` is present. +pub fn num_arg_flag(name: &str) -> usize { + std::env::args().take_while(|val| val != "--").filter(|val| val == name).count() +} + +/// Yields all values of command line flag `name` as `Ok(arg)`, and all other arguments except +/// the flag as `Err(arg)`. (The flag `name` itself is not yielded at all, only its values are.) +pub struct ArgSplitFlagValue<'a, I> { + args: TakeWhile bool>, + name: &'a str, +} + +impl<'a, I: Iterator> ArgSplitFlagValue<'a, I> { + pub fn new(args: I, name: &'a str) -> Self { + Self { + // Stop searching at `--`. + args: args.take_while(|val| val != "--"), + name, + } + } +} + +impl> Iterator for ArgSplitFlagValue<'_, I> { + type Item = Result; + + fn next(&mut self) -> Option { + let arg = self.args.next()?; + if let Some(suffix) = arg.strip_prefix(self.name) { + // Strip leading `name`. + if suffix.is_empty() { + // This argument is exactly `name`; the next one is the value. + return self.args.next().map(Ok); + } else if let Some(suffix) = suffix.strip_prefix('=') { + // This argument is `name=value`; get the value. + return Some(Ok(suffix.to_owned())); + } + } + Some(Err(arg)) + } +} + +/// Yields all values of command line flag `name`. +pub struct ArgFlagValueIter<'a>(ArgSplitFlagValue<'a, env::Args>); + +impl<'a> ArgFlagValueIter<'a> { + pub fn new(name: &'a str) -> Self { + Self(ArgSplitFlagValue::new(env::args(), name)) + } +} + +impl Iterator for ArgFlagValueIter<'_> { + type Item = String; + + fn next(&mut self) -> Option { + loop { + if let Ok(value) = self.0.next()? { + return Some(value); + } + } + } +} + +/// Gets the value of a `--flag`. +pub fn get_arg_flag_value(name: &str) -> Option { + ArgFlagValueIter::new(name).next() +} + +/// Escapes `s` in a way that is suitable for using it as a string literal in TOML syntax. +pub fn escape_for_toml(s: &str) -> String { + // We want to surround this string in quotes `"`. So we first escape all quotes, + // and also all backslashes (that are used to escape quotes). + let s = s.replace('\\', r#"\\"#).replace('"', r#"\""#); + format!("\"{}\"", s) +} + +/// Returns the path to the `miri` binary +pub fn find_miri() -> PathBuf { + if let Some(path) = env::var_os("MIRI") { + return path.into(); + } + let mut path = std::env::current_exe().expect("current executable path invalid"); + if cfg!(windows) { + path.set_file_name("miri.exe"); + } else { + path.set_file_name("miri"); + } + path +} + +pub fn miri() -> Command { + Command::new(find_miri()) +} + +pub fn miri_for_host() -> Command { + let mut cmd = miri(); + cmd.env("MIRI_BE_RUSTC", "host"); + cmd +} + +pub fn version_info() -> VersionMeta { + VersionMeta::for_command(miri_for_host()) + .expect("failed to determine underlying rustc version of Miri") +} + +pub fn cargo() -> Command { + Command::new(env::var_os("CARGO").unwrap_or_else(|| OsString::from("cargo"))) +} + +pub fn xargo_check() -> Command { + Command::new(env::var_os("XARGO_CHECK").unwrap_or_else(|| OsString::from("xargo-check"))) +} + +/// Execute the `Command`, where possible by replacing the current process with a new process +/// described by the `Command`. Then exit this process with the exit code of the new process. +pub fn exec(mut cmd: Command) -> ! { + // On non-Unix imitate POSIX exec as closely as we can + #[cfg(not(unix))] + { + let exit_status = cmd.status().expect("failed to run command"); + std::process::exit(exit_status.code().unwrap_or(-1)) + } + // On Unix targets, actually exec. + // If exec returns, process setup has failed. This is the same error condition as the expect in + // the non-Unix case. + #[cfg(unix)] + { + use std::os::unix::process::CommandExt; + let error = cmd.exec(); + Err(error).expect("failed to run command") + } +} + +/// Execute the `Command`, where possible by replacing the current process with a new process +/// described by the `Command`. Then exit this process with the exit code of the new process. +/// `input` is also piped to the new process's stdin, on cfg(unix) platforms by writing its +/// contents to `path` first, then setting stdin to that file. +pub fn exec_with_pipe

(mut cmd: Command, input: &[u8], path: P) -> ! +where + P: AsRef, +{ + #[cfg(unix)] + { + // Write the bytes we want to send to stdin out to a file + std::fs::write(&path, input).unwrap(); + // Open the file for reading, and set our new stdin to it + let stdin = File::open(&path).unwrap(); + cmd.stdin(stdin); + // Unlink the file so that it is fully cleaned up as soon as the new process exits + std::fs::remove_file(&path).unwrap(); + // Finally, we can hand off control. + exec(cmd) + } + #[cfg(not(unix))] + { + drop(path); // We don't need the path, we can pipe the bytes directly + cmd.stdin(std::process::Stdio::piped()); + let mut child = cmd.spawn().expect("failed to spawn process"); + { + let stdin = child.stdin.as_mut().expect("failed to open stdin"); + stdin.write_all(input).expect("failed to write out test source"); + } + let exit_status = child.wait().expect("failed to run command"); + std::process::exit(exit_status.code().unwrap_or(-1)) + } +} + +pub fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { + // Disable interactive prompts in CI (GitHub Actions, Travis, AppVeyor, etc). + // Azure doesn't set `CI` though (nothing to see here, just Microsoft being Microsoft), + // so we also check their `TF_BUILD`. + let is_ci = env::var_os("CI").is_some() || env::var_os("TF_BUILD").is_some(); + if ask && !is_ci { + let mut buf = String::new(); + print!("I will run `{:?}` to {}. Proceed? [Y/n] ", cmd, text); + io::stdout().flush().unwrap(); + io::stdin().read_line(&mut buf).unwrap(); + match buf.trim().to_lowercase().as_ref() { + // Proceed. + "" | "y" | "yes" => {} + "n" | "no" => show_error(format!("aborting as per your request")), + a => show_error(format!("invalid answer `{}`", a)), + }; + } else { + eprintln!("Running `{:?}` to {}.", cmd, text); + } + + if cmd.status().unwrap_or_else(|_| panic!("failed to execute {:?}", cmd)).success().not() { + show_error(format!("failed to {}", text)); + } +} + +/// Writes the given content to the given file *cross-process atomically*, in the sense that another +/// process concurrently reading that file will see either the old content or the new content, but +/// not some intermediate (e.g., empty) state. +/// +/// We assume no other parts of this same process are trying to read or write that file. +pub fn write_to_file(filename: &Path, content: &str) { + // Create a temporary file with the desired contents. + let mut temp_filename = filename.as_os_str().to_os_string(); + temp_filename.push(&format!(".{}", std::process::id())); + let mut temp_file = File::create(&temp_filename).unwrap(); + temp_file.write_all(content.as_bytes()).unwrap(); + drop(temp_file); + + // Move file to the desired location. + fs::rename(temp_filename, filename).unwrap(); +} + +pub fn get_cargo_metadata() -> Metadata { + // The `build.target-dir` config can be passed by `--config` flags, so forward them to + // `cargo metadata`. + let mut additional_options = Vec::new(); + // `-Zunstable-options` is required by `--config`. + additional_options.push("-Zunstable-options".to_string()); + + let config_flag = "--config"; + for arg in ArgSplitFlagValue::new( + env::args().skip(3), // skip the program name, "miri" and "run" / "test" + config_flag, + ) + // Only look at `Ok` + .flatten() + { + additional_options.push(config_flag.to_string()); + additional_options.push(arg); + } + + let metadata = + MetadataCommand::new().no_deps().other_options(additional_options).exec().unwrap(); + + metadata +} + +/// Pulls all the crates in this workspace from the cargo metadata. +/// Workspace members are emitted like "miri 0.1.0 (path+file:///path/to/miri)" +/// Additionally, somewhere between cargo metadata and TyCtxt, '-' gets replaced with '_' so we +/// make that same transformation here. +pub fn local_crates(metadata: &Metadata) -> String { + assert!(!metadata.workspace_members.is_empty()); + let mut local_crates = String::new(); + for member in &metadata.workspace_members { + let name = member.repr.split(' ').next().unwrap(); + let name = name.replace('-', "_"); + local_crates.push_str(&name); + local_crates.push(','); + } + local_crates.pop(); // Remove the trailing ',' + + local_crates +} + +fn env_vars_from_cmd(cmd: &Command) -> Vec<(String, String)> { + let mut envs = HashMap::new(); + for (key, value) in std::env::vars() { + envs.insert(key, value); + } + for (key, value) in cmd.get_envs() { + if let Some(value) = value { + envs.insert(key.to_string_lossy().to_string(), value.to_string_lossy().to_string()); + } else { + envs.remove(&key.to_string_lossy().to_string()); + } + } + let mut envs: Vec<_> = envs.into_iter().collect(); + envs.sort(); + envs +} + +/// Debug-print a command that is going to be run. +pub fn debug_cmd(prefix: &str, verbose: usize, cmd: &Command) { + if verbose == 0 { + return; + } + // We only do a single `eprintln!` call to minimize concurrency interactions. + let mut out = prefix.to_string(); + writeln!(out, " running command: env \\").unwrap(); + if verbose > 1 { + // Print the full environment this will be called in. + for (key, value) in env_vars_from_cmd(cmd) { + writeln!(out, "{key}={value:?} \\").unwrap(); + } + } else { + // Print only what has been changed for this `cmd`. + for (var, val) in cmd.get_envs() { + if let Some(val) = val { + writeln!(out, "{}={:?} \\", var.to_string_lossy(), val).unwrap(); + } else { + writeln!(out, "--unset={}", var.to_string_lossy()).unwrap(); + } + } + } + write!(out, "{cmd:?}").unwrap(); + eprintln!("{}", out); +} diff --git a/cargo-miri/version.rs b/cargo-miri/src/version.rs similarity index 100% rename from cargo-miri/version.rs rename to cargo-miri/src/version.rs From 9154f8b22c56c071e78e1f3d706fd75f43ff218c Mon Sep 17 00:00:00 2001 From: Christian Legnitto Date: Wed, 3 Aug 2022 10:39:43 -0400 Subject: [PATCH 3642/5092] Add additional raw error mappings for the nightly `io_error_more` feature Some crates are using nightly and failing when mapping these errors, for example : ``` error: unsupported operation: io error NotADirectory cannot be translated into a raw os error --> /root/.rustup/toolchains/miri/lib/rustlib/src/rust/library/std/src/sys/unix/fs.rs:1203:19 ``` --- src/helpers.rs | 47 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index acc2367afa28..ee2c39b51154 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -23,26 +23,49 @@ use crate::*; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +// This mapping is the reverse of `decode_error_kind` in +// +// and should be kept in sync. const UNIX_IO_ERROR_TABLE: &[(std::io::ErrorKind, &str)] = { use std::io::ErrorKind::*; &[ + (ArgumentListTooLong, "E2BIG"), + (AddrInUse, "EADDRINUSE"), + (AddrNotAvailable, "EADDRNOTAVAIL"), + (ResourceBusy, "EBUSY"), + (ConnectionAborted, "ECONNABORTED"), (ConnectionRefused, "ECONNREFUSED"), (ConnectionReset, "ECONNRESET"), - (PermissionDenied, "EPERM"), - (BrokenPipe, "EPIPE"), - (NotConnected, "ENOTCONN"), - (ConnectionAborted, "ECONNABORTED"), - (AddrNotAvailable, "EADDRNOTAVAIL"), - (AddrInUse, "EADDRINUSE"), - (NotFound, "ENOENT"), + (Deadlock, "EDEADLK"), + (FilesystemQuotaExceeded, "EDQUOT"), + (AlreadyExists, "EEXIST"), + (FileTooLarge, "EFBIG"), + (HostUnreachable, "EHOSTUNREACH"), (Interrupted, "EINTR"), (InvalidInput, "EINVAL"), - (InvalidFilename, "ENAMETOOLONG"), - (TimedOut, "ETIMEDOUT"), - (AlreadyExists, "EEXIST"), - (WouldBlock, "EWOULDBLOCK"), - (DirectoryNotEmpty, "ENOTEMPTY"), + (IsADirectory, "EISDIR"), (FilesystemLoop, "ELOOP"), + (NotFound, "ENOENT"), + (OutOfMemory, "ENOMEM"), + (StorageFull, "ENOSPC"), + (Unsupported, "ENOSYS"), + (TooManyLinks, "EMLINK"), + (InvalidFilename, "ENAMETOOLONG"), + (NetworkDown, "ENETDOWN"), + (NetworkUnreachable, "ENETUNREACH"), + (NotConnected, "ENOTCONN"), + (NotADirectory, "ENOTDIR"), + (DirectoryNotEmpty, "ENOTEMPTY"), + (BrokenPipe, "EPIPE"), + (ReadOnlyFilesystem, "EROFS"), + (NotSeekable, "ESPIPE"), + (StaleNetworkFileHandle, "ESTALE"), + (TimedOut, "ETIMEDOUT"), + (ExecutableFileBusy, "ETXTBSY"), + (CrossesDevices, "EXDEV"), + // The following have two valid options...we pick one. + (PermissionDenied, "EPERM"), + (WouldBlock, "EWOULDBLOCK"), ] }; From e1e1f42f39801c4f9195443fc5f1ac6e8505310e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Aug 2022 11:51:39 -0400 Subject: [PATCH 3643/5092] make errno table syntactically more similar to rustc library code --- src/helpers.rs | 88 ++++++++++++++++++++++++++------------------------ 1 file changed, 45 insertions(+), 43 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index ee2c39b51154..8523af84d066 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -23,49 +23,51 @@ use crate::*; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} -// This mapping is the reverse of `decode_error_kind` in -// -// and should be kept in sync. -const UNIX_IO_ERROR_TABLE: &[(std::io::ErrorKind, &str)] = { +// This mapping should match `decode_error_kind` in +// . +const UNIX_IO_ERROR_TABLE: &[(&str, std::io::ErrorKind)] = { use std::io::ErrorKind::*; &[ - (ArgumentListTooLong, "E2BIG"), - (AddrInUse, "EADDRINUSE"), - (AddrNotAvailable, "EADDRNOTAVAIL"), - (ResourceBusy, "EBUSY"), - (ConnectionAborted, "ECONNABORTED"), - (ConnectionRefused, "ECONNREFUSED"), - (ConnectionReset, "ECONNRESET"), - (Deadlock, "EDEADLK"), - (FilesystemQuotaExceeded, "EDQUOT"), - (AlreadyExists, "EEXIST"), - (FileTooLarge, "EFBIG"), - (HostUnreachable, "EHOSTUNREACH"), - (Interrupted, "EINTR"), - (InvalidInput, "EINVAL"), - (IsADirectory, "EISDIR"), - (FilesystemLoop, "ELOOP"), - (NotFound, "ENOENT"), - (OutOfMemory, "ENOMEM"), - (StorageFull, "ENOSPC"), - (Unsupported, "ENOSYS"), - (TooManyLinks, "EMLINK"), - (InvalidFilename, "ENAMETOOLONG"), - (NetworkDown, "ENETDOWN"), - (NetworkUnreachable, "ENETUNREACH"), - (NotConnected, "ENOTCONN"), - (NotADirectory, "ENOTDIR"), - (DirectoryNotEmpty, "ENOTEMPTY"), - (BrokenPipe, "EPIPE"), - (ReadOnlyFilesystem, "EROFS"), - (NotSeekable, "ESPIPE"), - (StaleNetworkFileHandle, "ESTALE"), - (TimedOut, "ETIMEDOUT"), - (ExecutableFileBusy, "ETXTBSY"), - (CrossesDevices, "EXDEV"), - // The following have two valid options...we pick one. - (PermissionDenied, "EPERM"), - (WouldBlock, "EWOULDBLOCK"), + ("E2BIG", ArgumentListTooLong), + ("EADDRINUSE", AddrInUse), + ("EADDRNOTAVAIL", AddrNotAvailable), + ("EBUSY", ResourceBusy), + ("ECONNABORTED", ConnectionAborted), + ("ECONNREFUSED", ConnectionRefused), + ("ECONNRESET", ConnectionReset), + ("EDEADLK", Deadlock), + ("EDQUOT", FilesystemQuotaExceeded), + ("EEXIST", AlreadyExists), + ("EFBIG", FileTooLarge), + ("EHOSTUNREACH", HostUnreachable), + ("EINTR", Interrupted), + ("EINVAL", InvalidInput), + ("EISDIR", IsADirectory), + ("ELOOP", FilesystemLoop), + ("ENOENT", NotFound), + ("ENOMEM", OutOfMemory), + ("ENOSPC", StorageFull), + ("ENOSYS", Unsupported), + ("EMLINK", TooManyLinks), + ("ENAMETOOLONG", InvalidFilename), + ("ENETDOWN", NetworkDown), + ("ENETUNREACH", NetworkUnreachable), + ("ENOTCONN", NotConnected), + ("ENOTDIR", NotADirectory), + ("ENOTEMPTY", DirectoryNotEmpty), + ("EPIPE", BrokenPipe), + ("EROFS", ReadOnlyFilesystem), + ("ESPIPE", NotSeekable), + ("ESTALE", StaleNetworkFileHandle), + ("ETIMEDOUT", TimedOut), + ("ETXTBSY", ExecutableFileBusy), + ("EXDEV", CrossesDevices), + // The following have two valid options. We have both for the forwards mapping; only the + // first one will be used for the backwards mapping. + ("EPERM", PermissionDenied), + ("EACCES", PermissionDenied), + ("EWOULDBLOCK", WouldBlock), + ("EAGAIN", WouldBlock), ] }; @@ -577,7 +579,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); let target = &this.tcx.sess.target; if target.families.iter().any(|f| f == "unix") { - for &(kind, name) in UNIX_IO_ERROR_TABLE { + for &(name, kind) in UNIX_IO_ERROR_TABLE { if err_kind == kind { return this.eval_libc(name); } @@ -615,7 +617,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let target = &this.tcx.sess.target; if target.families.iter().any(|f| f == "unix") { let errnum = errnum.to_i32()?; - for &(kind, name) in UNIX_IO_ERROR_TABLE { + for &(name, kind) in UNIX_IO_ERROR_TABLE { if errnum == this.eval_libc_i32(name)? { return Ok(kind); } From b426bd52a167a55eee029a45b42e7c0eece1f1c0 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 3 Aug 2022 13:16:04 -0400 Subject: [PATCH 3644/5092] Don't lint `transmute_undefined_repr` when the the first field of a `repr(C)` type is compatible with the other type --- .../src/transmute/transmute_undefined_repr.rs | 29 +++++++++++-------- tests/ui/transmute_undefined_repr.rs | 8 +++++ tests/ui/transmute_undefined_repr.stderr | 22 ++++++++++++-- 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/clippy_lints/src/transmute/transmute_undefined_repr.rs b/clippy_lints/src/transmute/transmute_undefined_repr.rs index 20b348fc14f7..bf1cfb859bc3 100644 --- a/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -164,9 +164,18 @@ pub(super) fn check<'tcx>( ); return true; }, + // `Repr(C)` <-> unordered type. + // If the first field of the `Repr(C)` type matches then the transmute is ok + (ReducedTy::OrderedFields(_, Some(from_sub_ty)), ReducedTy::UnorderedFields(to_sub_ty)) + | (ReducedTy::UnorderedFields(from_sub_ty), ReducedTy::OrderedFields(_, Some(to_sub_ty))) + | (ReducedTy::Ref(from_sub_ty), ReducedTy::Ref(to_sub_ty)) => { + from_ty = from_sub_ty; + to_ty = to_sub_ty; + continue; + }, ( ReducedTy::UnorderedFields(from_ty), - ReducedTy::Other(_) | ReducedTy::OrderedFields(_) | ReducedTy::Ref(_), + ReducedTy::Other(_) | ReducedTy::OrderedFields(..) | ReducedTy::Ref(_), ) => { span_lint_and_then( cx, @@ -182,7 +191,7 @@ pub(super) fn check<'tcx>( return true; }, ( - ReducedTy::Other(_) | ReducedTy::OrderedFields(_) | ReducedTy::Ref(_), + ReducedTy::Other(_) | ReducedTy::OrderedFields(..) | ReducedTy::Ref(_), ReducedTy::UnorderedFields(to_ty), ) => { span_lint_and_then( @@ -198,14 +207,9 @@ pub(super) fn check<'tcx>( ); return true; }, - (ReducedTy::Ref(from_sub_ty), ReducedTy::Ref(to_sub_ty)) => { - from_ty = from_sub_ty; - to_ty = to_sub_ty; - continue; - }, ( - ReducedTy::OrderedFields(_) | ReducedTy::Ref(_) | ReducedTy::Other(_) | ReducedTy::Param, - ReducedTy::OrderedFields(_) | ReducedTy::Ref(_) | ReducedTy::Other(_) | ReducedTy::Param, + ReducedTy::OrderedFields(..) | ReducedTy::Ref(_) | ReducedTy::Other(_) | ReducedTy::Param, + ReducedTy::OrderedFields(..) | ReducedTy::Ref(_) | ReducedTy::Other(_) | ReducedTy::Param, ) | ( ReducedTy::UnorderedFields(_) | ReducedTy::Param, @@ -269,7 +273,8 @@ enum ReducedTy<'tcx> { TypeErasure, /// The type is a struct containing either zero non-zero sized fields, or multiple non-zero /// sized fields with a defined order. - OrderedFields(Ty<'tcx>), + /// The second value is the first non-zero sized type. + OrderedFields(Ty<'tcx>, Option>), /// The type is a struct containing multiple non-zero sized fields with no defined order. UnorderedFields(Ty<'tcx>), /// The type is a reference to the contained type. @@ -294,7 +299,7 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx> ty::Tuple(args) => { let mut iter = args.iter(); let Some(sized_ty) = iter.find(|&ty| !is_zero_sized_ty(cx, ty)) else { - return ReducedTy::OrderedFields(ty); + return ReducedTy::OrderedFields(ty, None); }; if iter.all(|ty| is_zero_sized_ty(cx, ty)) { ty = sized_ty; @@ -316,7 +321,7 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx> continue; } if def.repr().inhibit_struct_field_reordering_opt() { - ReducedTy::OrderedFields(ty) + ReducedTy::OrderedFields(ty, Some(sized_ty)) } else { ReducedTy::UnorderedFields(ty) } diff --git a/tests/ui/transmute_undefined_repr.rs b/tests/ui/transmute_undefined_repr.rs index ebcaa7a84cfb..6df8ed8feeac 100644 --- a/tests/ui/transmute_undefined_repr.rs +++ b/tests/ui/transmute_undefined_repr.rs @@ -109,6 +109,14 @@ fn main() { let _: Ty2 = transmute(value::>>()); // Ok let _: Ty<&[u32]> = transmute::<&[u32], _>(value::<&Vec>()); // Ok + + let _: *const Ty2 = transmute(value::<*const Ty2C, u32>>()); // Ok + let _: *const Ty2C, u32> = transmute(value::<*const Ty2>()); // Ok + let _: *const Ty2 = transmute(value::<*const Ty2C<(), Ty2>>()); // Ok + let _: *const Ty2C<(), Ty2> = transmute(value::<*const Ty2>()); // Ok + + let _: *const Ty2 = transmute(value::<*const Ty2C>>()); // Err + let _: *const Ty2C> = transmute(value::<*const Ty2>()); // Err } } diff --git a/tests/ui/transmute_undefined_repr.stderr b/tests/ui/transmute_undefined_repr.stderr index 28bfba6c7571..8319f71a83dc 100644 --- a/tests/ui/transmute_undefined_repr.stderr +++ b/tests/ui/transmute_undefined_repr.stderr @@ -60,8 +60,24 @@ LL | let _: Box> = transmute(value::<&'static mut Ty2` which has an undefined layout + --> $DIR/transmute_undefined_repr.rs:118:39 + | +LL | let _: *const Ty2 = transmute(value::<*const Ty2C>>()); // Err + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the contained type `Ty2` has an undefined layout + +error: transmute from `*const Ty2` which has an undefined layout + --> $DIR/transmute_undefined_repr.rs:119:50 + | +LL | let _: *const Ty2C> = transmute(value::<*const Ty2>()); // Err + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the contained type `Ty2` has an undefined layout + error: transmute from `std::vec::Vec>` to `std::vec::Vec>`, both of which have an undefined layout - --> $DIR/transmute_undefined_repr.rs:138:35 + --> $DIR/transmute_undefined_repr.rs:146:35 | LL | let _: Vec> = transmute(value::>>()); // Err | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -69,12 +85,12 @@ LL | let _: Vec> = transmute(value::>>()); / = note: two instances of the same generic type (`Vec`) may have different layouts error: transmute from `std::vec::Vec>` to `std::vec::Vec>`, both of which have an undefined layout - --> $DIR/transmute_undefined_repr.rs:139:35 + --> $DIR/transmute_undefined_repr.rs:147:35 | LL | let _: Vec> = transmute(value::>>()); // Err | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: two instances of the same generic type (`Vec`) may have different layouts -error: aborting due to 10 previous errors +error: aborting due to 12 previous errors From 80f0f280df446d5b4169d1cf1314b030f52c02c1 Mon Sep 17 00:00:00 2001 From: Michael Krasnitski Date: Wed, 3 Aug 2022 23:06:12 -0400 Subject: [PATCH 3645/5092] Extend `if_then_some_else_none` to also suggest `bool::then_some` --- clippy_lints/src/if_then_some_else_none.rs | 82 ++++++++++++---------- tests/ui/if_then_some_else_none.stderr | 8 +-- 2 files changed, 47 insertions(+), 43 deletions(-) diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index b8d227855d97..20fcba90773b 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::source::snippet_with_macro_callsite; use clippy_utils::{contains_return, higher, is_else_clause, is_lang_ctor, meets_msrv, msrvs, peel_blocks}; -use if_chain::if_chain; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -56,7 +56,7 @@ impl IfThenSomeElseNone { impl_lint_pass!(IfThenSomeElseNone => [IF_THEN_SOME_ELSE_NONE]); impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if !meets_msrv(self.msrv, msrvs::BOOL_THEN) { return; } @@ -70,43 +70,47 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { return; } - if_chain! { - if let Some(higher::If { cond, then, r#else: Some(els) }) = higher::If::hir(expr); - if let ExprKind::Block(then_block, _) = then.kind; - if let Some(then_expr) = then_block.expr; - if let ExprKind::Call(then_call, [then_arg]) = then_expr.kind; - if let ExprKind::Path(ref then_call_qpath) = then_call.kind; - if is_lang_ctor(cx, then_call_qpath, OptionSome); - if let ExprKind::Path(ref qpath) = peel_blocks(els).kind; - if is_lang_ctor(cx, qpath, OptionNone); - if !stmts_contains_early_return(then_block.stmts); - then { - let cond_snip = snippet_with_macro_callsite(cx, cond.span, "[condition]"); - let cond_snip = if matches!(cond.kind, ExprKind::Unary(_, _) | ExprKind::Binary(_, _, _)) { - format!("({})", cond_snip) - } else { - cond_snip.into_owned() - }; - let arg_snip = snippet_with_macro_callsite(cx, then_arg.span, ""); - let closure_body = if then_block.stmts.is_empty() { - arg_snip.into_owned() - } else { - format!("{{ /* snippet */ {} }}", arg_snip) - }; - let help = format!( - "consider using `bool::then` like: `{}.then(|| {})`", - cond_snip, - closure_body, - ); - span_lint_and_help( - cx, - IF_THEN_SOME_ELSE_NONE, - expr.span, - "this could be simplified with `bool::then`", - None, - &help, - ); - } + if let Some(higher::If { cond, then, r#else: Some(els) }) = higher::If::hir(expr) + && let ExprKind::Block(then_block, _) = then.kind + && let Some(then_expr) = then_block.expr + && let ExprKind::Call(then_call, [then_arg]) = then_expr.kind + && let ExprKind::Path(ref then_call_qpath) = then_call.kind + && is_lang_ctor(cx, then_call_qpath, OptionSome) + && let ExprKind::Path(ref qpath) = peel_blocks(els).kind + && is_lang_ctor(cx, qpath, OptionNone) + && !stmts_contains_early_return(then_block.stmts) + { + let cond_snip = snippet_with_macro_callsite(cx, cond.span, "[condition]"); + let cond_snip = if matches!(cond.kind, ExprKind::Unary(_, _) | ExprKind::Binary(_, _, _)) { + format!("({})", cond_snip) + } else { + cond_snip.into_owned() + }; + let arg_snip = snippet_with_macro_callsite(cx, then_arg.span, ""); + let mut method_body = if then_block.stmts.is_empty() { + arg_snip.into_owned() + } else { + format!("{{ /* snippet */ {} }}", arg_snip) + }; + let method_name = if switch_to_eager_eval(cx, expr) && meets_msrv(self.msrv, msrvs::BOOL_THEN_SOME) { + "then_some" + } else { + method_body.insert_str(0, "|| "); + "then" + }; + + let help = format!( + "consider using `bool::{}` like: `{}.{}({})`", + method_name, cond_snip, method_name, method_body, + ); + span_lint_and_help( + cx, + IF_THEN_SOME_ELSE_NONE, + expr.span, + &format!("this could be simplified with `bool::{}`", method_name), + None, + &help, + ); } } diff --git a/tests/ui/if_then_some_else_none.stderr b/tests/ui/if_then_some_else_none.stderr index 8cb22d569f4c..c22ace30d2dc 100644 --- a/tests/ui/if_then_some_else_none.stderr +++ b/tests/ui/if_then_some_else_none.stderr @@ -27,21 +27,21 @@ LL | | }; | = help: consider using `bool::then` like: `matches!(true, true).then(|| { /* snippet */ matches!(true, false) })` -error: this could be simplified with `bool::then` +error: this could be simplified with `bool::then_some` --> $DIR/if_then_some_else_none.rs:23:28 | LL | let _ = x.and_then(|o| if o < 32 { Some(o) } else { None }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider using `bool::then` like: `(o < 32).then(|| o)` + = help: consider using `bool::then_some` like: `(o < 32).then_some(o)` -error: this could be simplified with `bool::then` +error: this could be simplified with `bool::then_some` --> $DIR/if_then_some_else_none.rs:27:13 | LL | let _ = if !x { Some(0) } else { None }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider using `bool::then` like: `(!x).then(|| 0)` + = help: consider using `bool::then_some` like: `(!x).then_some(0)` error: this could be simplified with `bool::then` --> $DIR/if_then_some_else_none.rs:82:13 From d00928aa69512c02490fcb228a70ad5c3f865613 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Thu, 4 Aug 2022 03:49:16 +0000 Subject: [PATCH 3646/5092] Require pointers to be sized --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 78afbdfc521f..45463f96b8b8 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1718,11 +1718,19 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, ); match in_elem.kind() { - ty::RawPtr(_) => {} + ty::RawPtr(p) => require!( + p.ty.is_sized(bx.tcx.at(span), ty::ParamEnv::reveal_all()), + "cannot cast pointer to unsized type `{}`", + in_elem + ), _ => return_error!("expected pointer, got `{}`", in_elem), } match out_elem.kind() { - ty::RawPtr(_) => {} + ty::RawPtr(p) => require!( + p.ty.is_sized(bx.tcx.at(span), ty::ParamEnv::reveal_all()), + "cannot cast to pointer to unsized type `{}`", + out_elem + ), _ => return_error!("expected pointer, got `{}`", out_elem), } From 99c0f91a4dd235824c353a11a2e75c462c9bbb74 Mon Sep 17 00:00:00 2001 From: Felix S Klock II Date: Thu, 4 Aug 2022 10:41:47 -0400 Subject: [PATCH 3647/5092] fix typo, thanks wesley Co-authored-by: Wesley Wiser --- .../issue-97463-abi-param-passing/param_passing.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/run-make-fulldeps/issue-97463-abi-param-passing/param_passing.rs b/src/test/run-make-fulldeps/issue-97463-abi-param-passing/param_passing.rs index b4744a3b96e7..c11f3cc72bdf 100644 --- a/src/test/run-make-fulldeps/issue-97463-abi-param-passing/param_passing.rs +++ b/src/test/run-make-fulldeps/issue-97463-abi-param-passing/param_passing.rs @@ -17,7 +17,7 @@ fn main() { let value: u16 = unsafe { c_read_value(r1 as u32, r2 as u32, r3 as u32) }; // NOTE: as an example of the sensitivity of this test to optimization choices, - // uncommenting this block of code makes the bug go away on pnkfeix's machine. + // uncommenting this block of code makes the bug go away on pnkfelix's machine. // (But observing via `dbg!` doesn't hide the bug. At least sometimes.) /* println!("{}", value); From a9f1b7bd2a25e34de29eb88f81550690f4fec5dc Mon Sep 17 00:00:00 2001 From: Aaron Kofsky Date: Thu, 4 Aug 2022 17:00:48 -0400 Subject: [PATCH 3648/5092] Explain why let-underscoring a lock guard is incorrect. Currently, the let_underscore_lock lint simply tells what is wrong, but not why it is wrong. We fix this by using a `MultiSpan` to explain specifically that doing `let _ = ` immediately drops the lock guard because it does not assign the lock guard to a binding. --- compiler/rustc_lint/src/let_underscore.rs | 13 +++++++++++-- .../lint/let_underscore/let_underscore_lock.stderr | 6 ++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index 2ba79aacace8..79d1443dc353 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -1,5 +1,5 @@ use crate::{LateContext, LateLintPass, LintContext}; -use rustc_errors::Applicability; +use rustc_errors::{Applicability, MultiSpan}; use rustc_hir as hir; use rustc_middle::{lint::LintDiagnosticBuilder, ty}; use rustc_span::Symbol; @@ -119,7 +119,16 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { }; if is_sync_lock { - cx.struct_span_lint(LET_UNDERSCORE_LOCK, local.span, |lint| { + let mut span = MultiSpan::from_spans(vec![local.pat.span, init.span]); + span.push_span_label( + local.pat.span, + "this lock is not assigned to a binding and is immediately dropped".to_string(), + ); + span.push_span_label( + init.span, + "this binding will immediately drop the value assigned to it".to_string(), + ); + cx.struct_span_lint(LET_UNDERSCORE_LOCK, span, |lint| { build_and_emit_lint( lint, local, diff --git a/src/test/ui/lint/let_underscore/let_underscore_lock.stderr b/src/test/ui/lint/let_underscore/let_underscore_lock.stderr index 7aa119003b4b..fb58af0a42f8 100644 --- a/src/test/ui/lint/let_underscore/let_underscore_lock.stderr +++ b/src/test/ui/lint/let_underscore/let_underscore_lock.stderr @@ -1,8 +1,10 @@ error: non-binding let on a synchronization lock - --> $DIR/let_underscore_lock.rs:6:5 + --> $DIR/let_underscore_lock.rs:6:9 | LL | let _ = data.lock().unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ ^^^^^^^^^^^^^^^^^^^^ this binding will immediately drop the value assigned to it + | | + | this lock is not assigned to a binding and is immediately dropped | = note: `#[deny(let_underscore_lock)]` on by default help: consider binding to an unused variable to avoid immediately dropping the value From d355ec94ff0ef409bfa953f715987a98de13fd64 Mon Sep 17 00:00:00 2001 From: Aaron Kofsky Date: Thu, 4 Aug 2022 17:31:08 -0400 Subject: [PATCH 3649/5092] Fix imports. I'm not really sure why this is nessecary to do, but the checks on the PR do not seem to work if do not do this. --- compiler/rustc_lint/src/let_underscore.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index 79d1443dc353..7e885e6c51aa 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -1,7 +1,7 @@ use crate::{LateContext, LateLintPass, LintContext}; -use rustc_errors::{Applicability, MultiSpan}; +use rustc_errors::{Applicability, LintDiagnosticBuilder, MultiSpan}; use rustc_hir as hir; -use rustc_middle::{lint::LintDiagnosticBuilder, ty}; +use rustc_middle::ty; use rustc_span::Symbol; declare_lint! { From 9bf3d5a82b689484b12bc5cc053d10f632ea6095 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Fri, 5 Aug 2022 10:15:59 -0400 Subject: [PATCH 3650/5092] Ignore test on wasm --- .../ui/abi/issues/issue-97463-broken-abi-leaked-uninit-data.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/ui/abi/issues/issue-97463-broken-abi-leaked-uninit-data.rs b/src/test/ui/abi/issues/issue-97463-broken-abi-leaked-uninit-data.rs index d04375acb30a..da782f8bbbf8 100644 --- a/src/test/ui/abi/issues/issue-97463-broken-abi-leaked-uninit-data.rs +++ b/src/test/ui/abi/issues/issue-97463-broken-abi-leaked-uninit-data.rs @@ -1,4 +1,5 @@ // run-pass +// ignore-wasm #![allow(dead_code)] #![allow(improper_ctypes)] From 76c90c3015a7e3ad6f0e6b807839ff59f17eba89 Mon Sep 17 00:00:00 2001 From: Aaron Kofsky Date: Fri, 5 Aug 2022 13:20:43 -0400 Subject: [PATCH 3651/5092] Use `#![warn(let_underscore_drop)]` in tests. --- src/test/ui/lint/let_underscore/let_underscore_drop.rs | 2 +- src/test/ui/lint/let_underscore/let_underscore_drop.stderr | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/test/ui/lint/let_underscore/let_underscore_drop.rs b/src/test/ui/lint/let_underscore/let_underscore_drop.rs index 85ca5dd2880a..f298871f122d 100644 --- a/src/test/ui/lint/let_underscore/let_underscore_drop.rs +++ b/src/test/ui/lint/let_underscore/let_underscore_drop.rs @@ -1,5 +1,5 @@ // check-pass -// compile-flags: -W let_underscore_drop +#![warn(let_underscore_drop)] struct NontrivialDrop; diff --git a/src/test/ui/lint/let_underscore/let_underscore_drop.stderr b/src/test/ui/lint/let_underscore/let_underscore_drop.stderr index cf7b882e946d..7b7de202e462 100644 --- a/src/test/ui/lint/let_underscore/let_underscore_drop.stderr +++ b/src/test/ui/lint/let_underscore/let_underscore_drop.stderr @@ -4,7 +4,11 @@ warning: non-binding let on a type that implements `Drop` LL | let _ = NontrivialDrop; | ^^^^^^^^^^^^^^^^^^^^^^^ | - = note: requested on the command line with `-W let-underscore-drop` +note: the lint level is defined here + --> $DIR/let_underscore_drop.rs:2:9 + | +LL | #![warn(let_underscore_drop)] + | ^^^^^^^^^^^^^^^^^^^ help: consider binding to an unused variable to avoid immediately dropping the value | LL | let _unused = NontrivialDrop; From 315d12d73d511efb277426c813e5d40157a0d70a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 5 Aug 2022 23:51:33 +0000 Subject: [PATCH 3652/5092] Fix ReErased leaking into typeck due to typeof recovery --- compiler/rustc_typeck/src/astconv/mod.rs | 5 ++++- src/test/ui/typeof/issue-100183.rs | 6 ++++++ src/test/ui/typeof/issue-100183.stderr | 14 ++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/typeof/issue-100183.rs create mode 100644 src/test/ui/typeof/issue-100183.stderr diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 8a5c7fee697d..c094594648cb 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -2667,7 +2667,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.normalize_ty(ast_ty.span, array_ty) } hir::TyKind::Typeof(ref e) => { - let ty = tcx.type_of(tcx.hir().local_def_id(e.hir_id)); + let ty_erased = tcx.type_of(tcx.hir().local_def_id(e.hir_id)); + let ty = tcx.fold_regions(ty_erased, |r, _| { + if r.is_erased() { tcx.lifetimes.re_static } else { r } + }); let span = ast_ty.span; tcx.sess.emit_err(TypeofReservedKeywordUsed { span, diff --git a/src/test/ui/typeof/issue-100183.rs b/src/test/ui/typeof/issue-100183.rs new file mode 100644 index 000000000000..13e9493eaa59 --- /dev/null +++ b/src/test/ui/typeof/issue-100183.rs @@ -0,0 +1,6 @@ +struct Struct { + y: (typeof("hey"),), + //~^ ERROR `typeof` is a reserved keyword but unimplemented +} + +fn main() {} diff --git a/src/test/ui/typeof/issue-100183.stderr b/src/test/ui/typeof/issue-100183.stderr new file mode 100644 index 000000000000..01d3079b246d --- /dev/null +++ b/src/test/ui/typeof/issue-100183.stderr @@ -0,0 +1,14 @@ +error[E0516]: `typeof` is a reserved keyword but unimplemented + --> $DIR/issue-100183.rs:2:9 + | +LL | y: (typeof("hey"),), + | ^^^^^^^^^^^^^ reserved keyword + | +help: consider replacing `typeof(...)` with an actual type + | +LL | y: (&'static str,), + | ~~~~~~~~~~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0516`. From 6d14a5e2a7c17f1fec43c319cc9317ded44701ea Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Aug 2022 19:21:47 -0400 Subject: [PATCH 3653/5092] avoid strerror_r failure on unknown errnum --- src/helpers.rs | 11 +++++++---- src/shims/unix/foreign_items.rs | 7 +++++-- tests/pass/fs.rs | 10 ++++++++++ 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 8523af84d066..220347ff1b96 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -609,20 +609,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// The inverse of `io_error_to_errnum`. - fn errnum_to_io_error( + #[allow(clippy::needless_return)] + fn try_errnum_to_io_error( &self, errnum: Scalar, - ) -> InterpResult<'tcx, std::io::ErrorKind> { + ) -> InterpResult<'tcx, Option> { let this = self.eval_context_ref(); let target = &this.tcx.sess.target; if target.families.iter().any(|f| f == "unix") { let errnum = errnum.to_i32()?; for &(name, kind) in UNIX_IO_ERROR_TABLE { if errnum == this.eval_libc_i32(name)? { - return Ok(kind); + return Ok(Some(kind)); } } - throw_unsup_format!("raw errnum {:?} cannot be translated into io::Error", errnum) + // Our table is as complete as the mapping in std, so we are okay with saying "that's a + // strange one" here. + return Ok(None); } else { throw_unsup_format!( "converting errnum into io::Error is unsupported for OS {}", diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 83815cccb0c4..dc80d592a0c1 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -465,8 +465,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.read_pointer(buf)?; let buflen = this.read_scalar(buflen)?.to_machine_usize(this)?; - let error = this.errnum_to_io_error(errnum)?; - let formatted = error.to_string(); + let error = this.try_errnum_to_io_error(errnum)?; + let formatted = match error { + Some(err) => format!("{err}"), + None => format!(""), + }; let (complete, _) = this.write_os_str_to_c_str(OsStr::new(&formatted), buf, buflen)?; let ret = if complete { 0 } else { this.eval_libc_i32("ERANGE")? }; this.write_int(ret, dest)?; diff --git a/tests/pass/fs.rs b/tests/pass/fs.rs index a8025007bf5f..af9f854ce527 100644 --- a/tests/pass/fs.rs +++ b/tests/pass/fs.rs @@ -3,6 +3,7 @@ #![feature(rustc_private)] #![feature(io_error_more)] +#![feature(io_error_uncategorized)] use std::ffi::CString; use std::fs::{ @@ -26,6 +27,7 @@ fn main() { test_directory(); test_canonicalize(); test_dup_stdout_stderr(); + test_from_raw_os_error(); // These all require unix, if the test is changed to no longer `ignore-windows`, move these to a unix test test_file_open_unix_allow_two_args(); @@ -434,3 +436,11 @@ fn test_dup_stdout_stderr() { libc::write(new_stderr, bytes.as_ptr() as *const libc::c_void, bytes.len()); } } + +fn test_from_raw_os_error() { + let code = 6; // not a code that std or Miri know + let error = Error::from_raw_os_error(code); + assert!(matches!(error.kind(), ErrorKind::Uncategorized)); + // Make sure we can also format this. + format!("{error:?}"); +} From d7875ea53008f2af7a4318503ae42204e6c17a67 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Aug 2022 20:17:14 -0400 Subject: [PATCH 3654/5092] fix an ICE in nanosleep() --- src/shims/time.rs | 6 +++++- tests/pass/sleep_long.rs | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 tests/pass/sleep_long.rs diff --git a/src/shims/time.rs b/src/shims/time.rs index a2cbd84bc2db..d9edbe3d7bdf 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -210,7 +210,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } }; - let timeout_time = Time::Monotonic(Instant::now().checked_add(duration).unwrap()); + // If adding the duration overflows, let's just sleep for an hour. Waking up early is always acceptable. + let timeout_time = Instant::now() + .checked_add(duration) + .unwrap_or_else(|| Instant::now().checked_add(Duration::from_secs(3600)).unwrap()); + let timeout_time = Time::Monotonic(timeout_time); let active_thread = this.get_active_thread(); this.block_thread(active_thread); diff --git a/tests/pass/sleep_long.rs b/tests/pass/sleep_long.rs new file mode 100644 index 000000000000..dd4a1843942c --- /dev/null +++ b/tests/pass/sleep_long.rs @@ -0,0 +1,18 @@ +//@ignore-target-windows: no threads nor sleep on Windows +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-disable-isolation +use std::sync::{Arc, Mutex}; +use std::thread; +use std::time::Duration; + +fn main() { + let finished = Arc::new(Mutex::new(false)); + let t_finished = finished.clone(); + thread::spawn(move || { + // Sleep very, very long. + thread::sleep(Duration::new(u64::MAX, 0)); + *t_finished.lock().unwrap() = true; + }); + thread::sleep(Duration::from_millis(100)); + assert_eq!(*finished.lock().unwrap(), false); + // Stopping the main thread will also kill the sleeper. +} From d61e55a1d4f5c00e3f1b7ab025683f50a8c075d2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 08:17:19 -0400 Subject: [PATCH 3655/5092] add support for env::home_dir and a bit of cleanup --- src/shims/unix/foreign_items.rs | 36 ++++++++++++------- src/shims/unix/fs.rs | 50 +++++++++++++++------------ src/shims/unix/linux/foreign_items.rs | 35 +++++++++++++++++++ src/shims/unix/mod.rs | 3 ++ src/shims/windows/foreign_items.rs | 1 + tests/pass/home.rs | 9 +++++ 6 files changed, 99 insertions(+), 35 deletions(-) create mode 100644 tests/pass/home.rs diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index dc80d592a0c1..7dde2d7d2c19 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -228,16 +228,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let name = this.read_scalar(name)?.to_i32()?; - let sysconfs = &[ - ("_SC_PAGESIZE", Scalar::from_int(PAGE_SIZE, this.pointer_size())), - ("_SC_NPROCESSORS_CONF", Scalar::from_int(NUM_CPUS, this.pointer_size())), - ("_SC_NPROCESSORS_ONLN", Scalar::from_int(NUM_CPUS, this.pointer_size())), + // FIXME: Which of these are POSIX, and which are GNU/Linux? + // At least the names seem to all also exist on macOS. + let sysconfs: &[(&str, fn(&MiriEvalContext<'_, '_>) -> Scalar)] = &[ + ("_SC_PAGESIZE", |this| Scalar::from_int(PAGE_SIZE, this.pointer_size())), + ("_SC_NPROCESSORS_CONF", |this| Scalar::from_int(NUM_CPUS, this.pointer_size())), + ("_SC_NPROCESSORS_ONLN", |this| Scalar::from_int(NUM_CPUS, this.pointer_size())), + // 512 seems to be a reasonable default. The value is not critical, in + // the sense that getpwuid_r takes and checks the buffer length. + ("_SC_GETPW_R_SIZE_MAX", |this| Scalar::from_int(512, this.pointer_size())) ]; let mut result = None; for &(sysconf_name, value) in sysconfs { let sysconf_name = this.eval_libc_i32(sysconf_name)?; if sysconf_name == name { - result = Some(value); + result = Some(value(this)); break; } } @@ -474,6 +479,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ret = if complete { 0 } else { this.eval_libc_i32("ERANGE")? }; this.write_int(ret, dest)?; } + "getpid" => { + let [] = this.check_shim(abi, Abi::C { unwind: false}, link_name, args)?; + let result = this.getpid()?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. @@ -500,9 +510,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - // Querying system information - "pthread_attr_getstack" => { - // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. Hence we can mostly ignore the input `attr_place`. + "pthread_attr_getstack" + if this.frame_in_std() => { + // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. + // Hence we can mostly ignore the input `attr_place`. let [attr_place, addr_place, size_place] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let _attr_place = this.deref_operand(attr_place)?; @@ -535,10 +546,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - "getpid" => { - let [] = this.check_shim(abi, Abi::C { unwind: false}, link_name, args)?; - let result = this.getpid()?; - this.write_scalar(Scalar::from_i32(result), dest)?; + "getuid" + if this.frame_in_std() => { + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + // FOr now, just pretend we always have this fixed UID. + this.write_int(super::UID, dest)?; } // Platform-specific shims diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index 9b00579d873b..3dccdd5e74f1 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -1091,31 +1091,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ], &statxbuf, )?; - this.write_int_fields( + #[rustfmt::skip] + this.write_int_fields_named( &[ - access_sec.into(), // stx_atime.tv_sec - access_nsec.into(), // stx_atime.tv_nsec + ("tv_sec", access_sec.into()), + ("tv_nsec", access_nsec.into()), ], &this.mplace_field_named(&statxbuf, "stx_atime")?, )?; - this.write_int_fields( + #[rustfmt::skip] + this.write_int_fields_named( &[ - created_sec.into(), // stx_btime.tv_sec - created_nsec.into(), // stx_btime.tv_nsec + ("tv_sec", created_sec.into()), + ("tv_nsec", created_nsec.into()), ], &this.mplace_field_named(&statxbuf, "stx_btime")?, )?; - this.write_int_fields( + #[rustfmt::skip] + this.write_int_fields_named( &[ - 0.into(), // stx_ctime.tv_sec - 0.into(), // stx_ctime.tv_nsec + ("tv_sec", 0.into()), + ("tv_nsec", 0.into()), ], &this.mplace_field_named(&statxbuf, "stx_ctime")?, )?; - this.write_int_fields( + #[rustfmt::skip] + this.write_int_fields_named( &[ - modified_sec.into(), // stx_mtime.tv_sec - modified_nsec.into(), // stx_mtime.tv_nsec + ("tv_sec", modified_sec.into()), + ("tv_nsec", modified_nsec.into()), ], &this.mplace_field_named(&statxbuf, "stx_mtime")?, )?; @@ -1302,12 +1306,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let file_type = this.file_type_to_d_type(dir_entry.file_type())?; - this.write_int_fields( + this.write_int_fields_named( &[ - ino.into(), // d_ino - 0, // d_off - size.into(), // d_reclen - file_type.into(), // d_type + ("d_ino", ino.into()), + ("d_off", 0), + ("d_reclen", size.into()), + ("d_type", file_type.into()), ], &MPlaceTy::from_aligned_ptr(entry, dirent64_layout), )?; @@ -1398,13 +1402,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let file_type = this.file_type_to_d_type(dir_entry.file_type())?; - this.write_int_fields( + this.write_int_fields_named( &[ - ino.into(), // d_ino - 0, // d_seekoff - 0, // d_reclen - file_name_len.into(), // d_namlen - file_type.into(), // d_type + ("d_ino", ino.into()), + ("d_seekoff", 0), + ("d_reclen", 0), + ("d_namlen", file_name_len.into()), + ("d_type", file_type.into()), ], &entry_place, )?; diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index bae3780b460c..61016c424954 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -155,6 +155,41 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } + "getpwuid_r" if this.frame_in_std() => { + let [uid, pwd, buf, buflen, result] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + this.check_no_isolation("`getpwuid_r`")?; + + let uid = this.read_scalar(uid)?.to_u32()?; + let pwd = this.deref_operand(pwd)?; + let buf = this.read_pointer(buf)?; + let buflen = this.read_scalar(buflen)?.to_machine_usize(this)?; + let result = this.deref_operand(result)?; + + // Must be for "us". + if uid != crate::shims::unix::UID { + throw_unsup_format!("`getpwuid_r` on other users is not supported"); + } + + // Reset all fields to `uninit` to make sure nobody reads them. + this.write_uninit(&pwd.into())?; + + // We only set the home_dir field. + #[allow(deprecated)] + let home_dir = std::env::home_dir().unwrap(); + let (written, _) = this.write_path_to_c_str(&home_dir, buf, buflen)?; + let pw_dir = this.mplace_field_named(&pwd, "pw_dir")?; + this.write_pointer(buf, &pw_dir.into())?; + + if written { + this.write_pointer(pwd.ptr, &result.into())?; + this.write_null(dest)?; + } else { + this.write_null(&result.into())?; + this.write_scalar(this.eval_libc("ERANGE")?, dest)?; + } + } + _ => return Ok(EmulateByNameResult::NotSupported), }; diff --git a/src/shims/unix/mod.rs b/src/shims/unix/mod.rs index 8e8c70bbd0fa..35380fc06d79 100644 --- a/src/shims/unix/mod.rs +++ b/src/shims/unix/mod.rs @@ -10,3 +10,6 @@ mod linux; mod macos; pub use fs::{DirHandler, FileHandler}; + +// Make up some constants. +const UID: u32 = 1000; diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 29afe52cafd6..6520609b76f4 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -110,6 +110,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "GetSystemInfo" => { + // Also called from `page_size` crate. let [system_info] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let system_info = this.deref_operand(system_info)?; diff --git a/tests/pass/home.rs b/tests/pass/home.rs new file mode 100644 index 000000000000..0fb69aad0077 --- /dev/null +++ b/tests/pass/home.rs @@ -0,0 +1,9 @@ +//@only-target-linux: home_dir is only supported on Linux +//@compile-flags: -Zmiri-disable-isolation +use std::env; + +fn main() { + env::remove_var("HOME"); // make sure we enter the interesting codepath + #[allow(deprecated)] + env::home_dir().unwrap(); +} From 889c073aa66049d28d7bb243cd9d774cfa96f4ae Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 09:03:33 -0400 Subject: [PATCH 3656/5092] really, clippy?!? --- src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index caae17b20223..8b1c18a499f6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,7 +22,8 @@ clippy::useless_format, clippy::derive_partial_eq_without_eq, clippy::derive_hash_xor_eq, - clippy::too_many_arguments + clippy::too_many_arguments, + clippy::type_complexity )] #![warn( rust_2018_idioms, From 5a4ac1ebf0e30b415b90a57904e4c2cb32f35068 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 10:30:55 -0400 Subject: [PATCH 3657/5092] work around apfloat bug in FMA by using host floats instead --- src/shims/foreign_items.rs | 18 +++++++++--------- src/shims/intrinsics/mod.rs | 34 ++++++++++++++++++++-------------- src/shims/intrinsics/simd.rs | 19 +++++++++++++++---- tests/pass/intrinsics-math.rs | 2 ++ tests/pass/portable-simd.rs | 10 ++++++++++ 5 files changed, 56 insertions(+), 27 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 208e7ea788f7..9a985b245039 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -588,7 +588,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); - let f = match link_name.as_str() { + let res = match link_name.as_str() { "cbrtf" => f.cbrt(), "coshf" => f.cosh(), "sinhf" => f.sinh(), @@ -598,7 +598,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atanf" => f.atan(), _ => bug!(), }; - this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?; + this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?; } #[rustfmt::skip] | "_hypotf" @@ -611,12 +611,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: Using host floats. let f1 = f32::from_bits(this.read_scalar(f1)?.to_u32()?); let f2 = f32::from_bits(this.read_scalar(f2)?.to_u32()?); - let n = match link_name.as_str() { + let res = match link_name.as_str() { "_hypotf" | "hypotf" => f1.hypot(f2), "atan2f" => f1.atan2(f2), _ => bug!(), }; - this.write_scalar(Scalar::from_u32(n.to_bits()), dest)?; + this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?; } #[rustfmt::skip] | "cbrt" @@ -630,7 +630,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); - let f = match link_name.as_str() { + let res = match link_name.as_str() { "cbrt" => f.cbrt(), "cosh" => f.cosh(), "sinh" => f.sinh(), @@ -640,7 +640,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atan" => f.atan(), _ => bug!(), }; - this.write_scalar(Scalar::from_u64(f.to_bits()), dest)?; + this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?; } #[rustfmt::skip] | "_hypot" @@ -651,12 +651,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: Using host floats. let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?); let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?); - let n = match link_name.as_str() { + let res = match link_name.as_str() { "_hypot" | "hypot" => f1.hypot(f2), "atan2" => f1.atan2(f2), _ => bug!(), }; - this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?; + this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?; } #[rustfmt::skip] | "_ldexp" @@ -668,7 +668,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let x = this.read_scalar(x)?.to_f64()?; let exp = this.read_scalar(exp)?.to_i32()?; - // Saturating cast to i16. Even those are outside the valid exponent range to + // Saturating cast to i16. Even those are outside the valid exponent range so // `scalbn` below will do its over/underflow handling. let exp = if exp > i32::from(i16::MAX) { i16::MAX diff --git a/src/shims/intrinsics/mod.rs b/src/shims/intrinsics/mod.rs index 4c2d08ffceab..08a6e0fcc0ee 100644 --- a/src/shims/intrinsics/mod.rs +++ b/src/shims/intrinsics/mod.rs @@ -285,7 +285,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let f2 = f32::from_bits(this.read_scalar(f2)?.to_u32()?); - this.write_scalar(Scalar::from_u32(f.powf(f2).to_bits()), dest)?; + let res = f.powf(f2); + this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?; } "powf64" => { @@ -293,25 +294,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?); - this.write_scalar(Scalar::from_u64(f.powf(f2).to_bits()), dest)?; + let res = f.powf(f2); + this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?; } "fmaf32" => { let [a, b, c] = check_arg_count(args)?; - let a = this.read_scalar(a)?.to_f32()?; - let b = this.read_scalar(b)?.to_f32()?; - let c = this.read_scalar(c)?.to_f32()?; - let res = a.mul_add(b, c).value; - this.write_scalar(Scalar::from_f32(res), dest)?; + // FIXME: Using host floats, to work around https://github.com/rust-lang/miri/issues/2468. + let a = f32::from_bits(this.read_scalar(a)?.to_u32()?); + let b = f32::from_bits(this.read_scalar(b)?.to_u32()?); + let c = f32::from_bits(this.read_scalar(c)?.to_u32()?); + let res = a.mul_add(b, c); + this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?; } "fmaf64" => { let [a, b, c] = check_arg_count(args)?; - let a = this.read_scalar(a)?.to_f64()?; - let b = this.read_scalar(b)?.to_f64()?; - let c = this.read_scalar(c)?.to_f64()?; - let res = a.mul_add(b, c).value; - this.write_scalar(Scalar::from_f64(res), dest)?; + // FIXME: Using host floats, to work around https://github.com/rust-lang/miri/issues/2468. + let a = f64::from_bits(this.read_scalar(a)?.to_u64()?); + let b = f64::from_bits(this.read_scalar(b)?.to_u64()?); + let c = f64::from_bits(this.read_scalar(c)?.to_u64()?); + let res = a.mul_add(b, c); + this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?; } "powif32" => { @@ -319,7 +323,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let i = this.read_scalar(i)?.to_i32()?; - this.write_scalar(Scalar::from_u32(f.powi(i).to_bits()), dest)?; + let res = f.powi(i); + this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?; } "powif64" => { @@ -327,7 +332,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let i = this.read_scalar(i)?.to_i32()?; - this.write_scalar(Scalar::from_u64(f.powi(i).to_bits()), dest)?; + let res = f.powi(i); + this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?; } "float_to_int_unchecked" => { diff --git a/src/shims/intrinsics/simd.rs b/src/shims/intrinsics/simd.rs index d467c3c509f5..0c3241683a18 100644 --- a/src/shims/intrinsics/simd.rs +++ b/src/shims/intrinsics/simd.rs @@ -238,14 +238,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dest = this.mplace_index(&dest, i)?; // Works for f32 and f64. + // FIXME: using host floats to work around https://github.com/rust-lang/miri/issues/2468. let ty::Float(float_ty) = dest.layout.ty.kind() else { span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name) }; let val = match float_ty { - FloatTy::F32 => - Scalar::from_f32(a.to_f32()?.mul_add(b.to_f32()?, c.to_f32()?).value), - FloatTy::F64 => - Scalar::from_f64(a.to_f64()?.mul_add(b.to_f64()?, c.to_f64()?).value), + FloatTy::F32 => { + let a = f32::from_bits(a.to_u32()?); + let b = f32::from_bits(b.to_u32()?); + let c = f32::from_bits(c.to_u32()?); + let res = a.mul_add(b, c); + Scalar::from_u32(res.to_bits()) + } + FloatTy::F64 => { + let a = f64::from_bits(a.to_u64()?); + let b = f64::from_bits(b.to_u64()?); + let c = f64::from_bits(c.to_u64()?); + let res = a.mul_add(b, c); + Scalar::from_u64(res.to_bits()) + } }; this.write_scalar(val, &dest.into())?; } diff --git a/tests/pass/intrinsics-math.rs b/tests/pass/intrinsics-math.rs index 0cb42580fcb2..fad01047b9c6 100644 --- a/tests/pass/intrinsics-math.rs +++ b/tests/pass/intrinsics-math.rs @@ -60,6 +60,8 @@ pub fn main() { assert_eq!(0.0f32.mul_add(-2.0, f32::consts::E), f32::consts::E); assert_approx_eq!(3.0f64.mul_add(2.0, 5.0), 11.0); assert_eq!(0.0f64.mul_add(-2.0f64, f64::consts::E), f64::consts::E); + assert_eq!((-3.2f32).mul_add(2.4, f32::NEG_INFINITY), f32::NEG_INFINITY); + assert_eq!((-3.2f64).mul_add(2.4, f64::NEG_INFINITY), f64::NEG_INFINITY); assert_approx_eq!((-1.0f32).abs(), 1.0f32); assert_approx_eq!(34.2f64.abs(), 34.2f64); diff --git a/tests/pass/portable-simd.rs b/tests/pass/portable-simd.rs index ec70eea6b177..173ac654b03d 100644 --- a/tests/pass/portable-simd.rs +++ b/tests/pass/portable-simd.rs @@ -18,6 +18,11 @@ fn simd_ops_f32() { assert_eq!(a.mul_add(b, a), (a * b) + a); assert_eq!(b.mul_add(b, a), (b * b) + a); + assert_eq!(a.mul_add(b, b), (a * b) + b); + assert_eq!( + f32x4::splat(-3.2).mul_add(b, f32x4::splat(f32::NEG_INFINITY)), + f32x4::splat(f32::NEG_INFINITY) + ); assert_eq!((a * a).sqrt(), a); assert_eq!((b * b).sqrt(), b.abs()); @@ -67,6 +72,11 @@ fn simd_ops_f64() { assert_eq!(a.mul_add(b, a), (a * b) + a); assert_eq!(b.mul_add(b, a), (b * b) + a); + assert_eq!(a.mul_add(b, b), (a * b) + b); + assert_eq!( + f64x4::splat(-3.2).mul_add(b, f64x4::splat(f64::NEG_INFINITY)), + f64x4::splat(f64::NEG_INFINITY) + ); assert_eq!((a * a).sqrt(), a); assert_eq!((b * b).sqrt(), b.abs()); From b1316eca922655f5d81559c1c26f457693aa5c2b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 09:33:08 -0400 Subject: [PATCH 3658/5092] support and test some more math functions --- src/shims/foreign_items.rs | 20 +++++++- tests/pass/intrinsics-math.rs | 87 +++++++++++++++++++++++------------ 2 files changed, 77 insertions(+), 30 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 9a985b245039..e7cfd43f1b1e 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -575,15 +575,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_usize(u64::try_from(n).unwrap(), this), dest)?; } - // math functions + // math functions (note that there are also intrinsics for some other functions) #[rustfmt::skip] | "cbrtf" | "coshf" | "sinhf" | "tanf" + | "tanhf" | "acosf" | "asinf" | "atanf" + | "log1pf" + | "expm1f" => { let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. @@ -593,9 +596,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "coshf" => f.cosh(), "sinhf" => f.sinh(), "tanf" => f.tan(), + "tanhf" => f.tanh(), "acosf" => f.acos(), "asinf" => f.asin(), "atanf" => f.atan(), + "log1pf" => f.ln_1p(), + "expm1f" => f.exp_m1(), _ => bug!(), }; this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?; @@ -604,6 +610,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "_hypotf" | "hypotf" | "atan2f" + | "fdimf" => { let [f1, f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // underscore case for windows, here and below @@ -614,6 +621,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let res = match link_name.as_str() { "_hypotf" | "hypotf" => f1.hypot(f2), "atan2f" => f1.atan2(f2), + #[allow(deprecated)] + "fdimf" => f1.abs_sub(f2), _ => bug!(), }; this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?; @@ -623,9 +632,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "cosh" | "sinh" | "tan" + | "tanh" | "acos" | "asin" | "atan" + | "log1p" + | "expm1" => { let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. @@ -635,9 +647,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "cosh" => f.cosh(), "sinh" => f.sinh(), "tan" => f.tan(), + "tanh" => f.tanh(), "acos" => f.acos(), "asin" => f.asin(), "atan" => f.atan(), + "log1p" => f.ln_1p(), + "expm1" => f.exp_m1(), _ => bug!(), }; this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?; @@ -646,6 +661,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "_hypot" | "hypot" | "atan2" + | "fdim" => { let [f1, f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. @@ -654,6 +670,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let res = match link_name.as_str() { "_hypot" | "hypot" => f1.hypot(f2), "atan2" => f1.atan2(f2), + #[allow(deprecated)] + "fdim" => f1.abs_sub(f2), _ => bug!(), }; this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?; diff --git a/tests/pass/intrinsics-math.rs b/tests/pass/intrinsics-math.rs index fad01047b9c6..5973f4cd197f 100644 --- a/tests/pass/intrinsics-math.rs +++ b/tests/pass/intrinsics-math.rs @@ -32,24 +32,24 @@ pub fn main() { assert_approx_eq!(25f32.powi(-2), 0.0016f32); assert_approx_eq!(23.2f64.powi(2), 538.24f64); - assert_approx_eq!(0f32.sin(), 0f32); - assert_approx_eq!((f64::consts::PI / 2f64).sin(), 1f64); - - assert_approx_eq!(0f32.cos(), 1f32); - assert_approx_eq!((f64::consts::PI * 2f64).cos(), 1f64); - assert_approx_eq!(25f32.powf(-2f32), 0.0016f32); assert_approx_eq!(400f64.powf(0.5f64), 20f64); - assert_approx_eq!((1f32.exp() - f32::consts::E).abs(), 0f32); + assert_approx_eq!(1f32.exp(), f32::consts::E); assert_approx_eq!(1f64.exp(), f64::consts::E); + assert_approx_eq!(1f32.exp_m1(), f32::consts::E - 1.0); + assert_approx_eq!(1f64.exp_m1(), f64::consts::E - 1.0); + assert_approx_eq!(10f32.exp2(), 1024f32); assert_approx_eq!(50f64.exp2(), 1125899906842624f64); - assert_approx_eq!((f32::consts::E.ln() - 1f32).abs(), 0f32); + assert_approx_eq!(f32::consts::E.ln(), 1f32); assert_approx_eq!(1f64.ln(), 0f64); + assert_approx_eq!(0f32.ln_1p(), 0f32); + assert_approx_eq!(0f64.ln_1p(), 0f64); + assert_approx_eq!(10f32.log10(), 1f32); assert_approx_eq!(f64::consts::E.log10(), f64::consts::LOG10_E); @@ -66,6 +66,12 @@ pub fn main() { assert_approx_eq!((-1.0f32).abs(), 1.0f32); assert_approx_eq!(34.2f64.abs(), 34.2f64); + #[allow(deprecated)] + { + assert_approx_eq!(5.0f32.abs_sub(3.0), 2.0); + assert_approx_eq!(3.0f64.abs_sub(5.0), 0.0); + } + assert_approx_eq!(3.8f32.floor(), 3.0f32); assert_approx_eq!((-1.1f64).floor(), -2.0f64); @@ -81,31 +87,54 @@ pub fn main() { assert_approx_eq!(3.0f32.hypot(4.0f32), 5.0f32); assert_approx_eq!(3.0f64.hypot(4.0f64), 5.0f64); - assert_approx_eq!(1.0f32.atan2(2.0f32), 0.46364761f32); - assert_approx_eq!(1.0f32.atan2(2.0f32), 0.46364761f32); - - assert_approx_eq!(1.0f32.cosh(), 1.54308f32); - assert_approx_eq!(1.0f64.cosh(), 1.54308f64); - - assert_approx_eq!(1.0f32.sinh(), 1.1752012f32); - assert_approx_eq!(1.0f64.sinh(), 1.1752012f64); - - assert_approx_eq!(1.0f32.tan(), 1.557408f32); - assert_approx_eq!(1.0f64.tan(), 1.557408f64); - - assert_approx_eq!(f32::consts::FRAC_PI_4.cos().acos(), f32::consts::FRAC_PI_4); - assert_approx_eq!(f64::consts::FRAC_PI_4.cos().acos(), f64::consts::FRAC_PI_4); - - assert_approx_eq!(f32::consts::FRAC_PI_4.sin().asin(), f32::consts::FRAC_PI_4); - assert_approx_eq!(f64::consts::FRAC_PI_4.sin().asin(), f64::consts::FRAC_PI_4); - - assert_approx_eq!(1.0_f32, 1.0_f32.tan().atan()); - assert_approx_eq!(1.0_f64, 1.0_f64.tan().atan()); - assert_eq!(3.3_f32.round(), 3.0); assert_eq!(3.3_f64.round(), 3.0); assert_eq!(ldexp(0.65f64, 3i32), 5.2f64); assert_eq!(ldexp(1.42, 0xFFFF), f64::INFINITY); assert_eq!(ldexp(1.42, -0xFFFF), 0f64); + + // Trigonometric functions. + + assert_approx_eq!(0f32.sin(), 0f32); + assert_approx_eq!((f64::consts::PI / 2f64).sin(), 1f64); + assert_approx_eq!(f32::consts::FRAC_PI_6.sin(), 0.5); + assert_approx_eq!(f64::consts::FRAC_PI_6.sin(), 0.5); + assert_approx_eq!(f32::consts::FRAC_PI_4.sin().asin(), f32::consts::FRAC_PI_4); + assert_approx_eq!(f64::consts::FRAC_PI_4.sin().asin(), f64::consts::FRAC_PI_4); + + assert_approx_eq!(1.0f32.sinh(), 1.1752012f32); + assert_approx_eq!(1.0f64.sinh(), 1.1752012f64); + assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32); + assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64); + + assert_approx_eq!(0f32.cos(), 1f32); + assert_approx_eq!((f64::consts::PI * 2f64).cos(), 1f64); + assert_approx_eq!(f32::consts::FRAC_PI_3.cos(), 0.5); + assert_approx_eq!(f64::consts::FRAC_PI_3.cos(), 0.5); + assert_approx_eq!(f32::consts::FRAC_PI_4.cos().acos(), f32::consts::FRAC_PI_4); + assert_approx_eq!(f64::consts::FRAC_PI_4.cos().acos(), f64::consts::FRAC_PI_4); + + assert_approx_eq!(1.0f32.cosh(), 1.54308f32); + assert_approx_eq!(1.0f64.cosh(), 1.54308f64); + assert_approx_eq!(2.0f32.acosh(), 1.31695789692481670862504634730796844f32); + assert_approx_eq!(3.0f64.acosh(), 1.76274717403908605046521864995958461f64); + + assert_approx_eq!(1.0f32.tan(), 1.557408f32); + assert_approx_eq!(1.0f64.tan(), 1.557408f64); + assert_approx_eq!(1.0_f32, 1.0_f32.tan().atan()); + assert_approx_eq!(1.0_f64, 1.0_f64.tan().atan()); + assert_approx_eq!(1.0f32.atan2(2.0f32), 0.46364761f32); + assert_approx_eq!(1.0f32.atan2(2.0f32), 0.46364761f32); + + assert_approx_eq!( + 1.0f32.tanh(), + (1.0 - f32::consts::E.powi(-2)) / (1.0 + f32::consts::E.powi(-2)) + ); + assert_approx_eq!( + 1.0f64.tanh(), + (1.0 - f64::consts::E.powi(-2)) / (1.0 + f64::consts::E.powi(-2)) + ); + assert_approx_eq!(0.5f32.atanh(), 0.54930614433405484569762261846126285f32); + assert_approx_eq!(0.5f64.atanh(), 0.54930614433405484569762261846126285f64); } From 61be3bae40ffe16dff1fc2e0147ecf125064fde3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 11:47:14 -0400 Subject: [PATCH 3659/5092] support current_exe on macOS, and fix write_os_str length logic --- src/shims/env.rs | 4 ++-- src/shims/os_str.rs | 10 ++++++---- src/shims/unix/fs.rs | 3 ++- src/shims/unix/macos/foreign_items.rs | 27 +++++++++++++++++++++++++++ tests/pass/current_exe.rs | 8 ++++++++ 5 files changed, 45 insertions(+), 7 deletions(-) create mode 100644 tests/pass/current_exe.rs diff --git a/src/shims/env.rs b/src/shims/env.rs index db1ddf6291fd..d333e78e5240 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -18,11 +18,11 @@ fn windows_check_buffer_size((success, len): (bool, u64)) -> u32 { if success { // If the function succeeds, the return value is the number of characters stored in the target buffer, // not including the terminating null character. - u32::try_from(len).unwrap() + u32::try_from(len.checked_sub(1).unwrap()).unwrap() } else { // If the target buffer was not large enough to hold the data, the return value is the buffer size, in characters, // required to hold the string and its terminating null character. - u32::try_from(len.checked_add(1).unwrap()).unwrap() + u32::try_from(len).unwrap() } } diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index b9f3a435ea42..f99e2d174b53 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -92,7 +92,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// the Unix APIs usually handle. This function returns `Ok((false, length))` without trying /// to write if `size` is not large enough to fit the contents of `os_string` plus a null /// terminator. It returns `Ok((true, length))` if the writing process was successful. The - /// string length returned does not include the null terminator. + /// string length returned does include the null terminator. fn write_os_str_to_c_str( &mut self, os_str: &OsStr, @@ -103,7 +103,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null // terminator to memory using the `ptr` pointer would cause an out-of-bounds access. let string_length = u64::try_from(bytes.len()).unwrap(); - if size <= string_length { + let string_length = string_length.checked_add(1).unwrap(); + if size < string_length { return Ok((false, string_length)); } self.eval_context_mut() @@ -115,7 +116,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// the Windows APIs usually handle. This function returns `Ok((false, length))` without trying /// to write if `size` is not large enough to fit the contents of `os_string` plus a null /// terminator. It returns `Ok((true, length))` if the writing process was successful. The - /// string length returned does not include the null terminator. + /// string length returned does include the null terminator. Length is measured in units of + /// `u16.` fn write_os_str_to_wide_str( &mut self, os_str: &OsStr, @@ -157,7 +159,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx alloc .write_scalar(alloc_range(size2 * offset, size2), Scalar::from_u16(wchar).into())?; } - Ok((true, string_length - 1)) + Ok((true, string_length)) } /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes. diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index 3dccdd5e74f1..951ddae2c14d 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -1380,11 +1380,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_place = this.mplace_field(&entry_place, 5)?; let file_name = dir_entry.file_name(); // not a Path as there are no separators! - let (name_fits, file_name_len) = this.write_os_str_to_c_str( + let (name_fits, file_name_buf_len) = this.write_os_str_to_c_str( &file_name, name_place.ptr, name_place.layout.size.bytes(), )?; + let file_name_len = file_name_buf_len.checked_sub(1).unwrap(); if !name_fits { throw_unsup_format!( "a directory entry had a name too large to fit in libc::dirent" diff --git a/src/shims/unix/macos/foreign_items.rs b/src/shims/unix/macos/foreign_items.rs index fb545d8b5847..35751d5818ab 100644 --- a/src/shims/unix/macos/foreign_items.rs +++ b/src/shims/unix/macos/foreign_items.rs @@ -117,6 +117,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest, )?; } + "_NSGetExecutablePath" => { + let [buf, bufsize] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + this.check_no_isolation("`_NSGetExecutablePath`")?; + + let buf_ptr = this.read_pointer(buf)?; + let bufsize = this.deref_operand(bufsize)?; + + // Using the host current_exe is a bit off, but consistent with Linux + // (where stdlib reads /proc/self/exe). + let path = std::env::current_exe().unwrap(); + let (written, size_needed) = this.write_path_to_c_str( + &path, + buf_ptr, + this.read_scalar(&bufsize.into())?.to_u32()?.into(), + )?; + + if written { + this.write_null(dest)?; + } else { + this.write_scalar( + Scalar::from_u32(size_needed.try_into().unwrap()), + &bufsize.into(), + )?; + this.write_int(-1, dest)?; + } + } // Thread-local storage "_tlv_atexit" => { diff --git a/tests/pass/current_exe.rs b/tests/pass/current_exe.rs new file mode 100644 index 000000000000..64f62b230e48 --- /dev/null +++ b/tests/pass/current_exe.rs @@ -0,0 +1,8 @@ +//@ignore-target-windows +//@compile-flags: -Zmiri-disable-isolation +use std::env; + +fn main() { + // The actual value we get is a bit odd: we get the Miri binary that interprets us. + env::current_exe().unwrap(); +} From 6b68921ca0d25690e9d7d3b5d6f442fb1bda1fcc Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 6 Aug 2022 18:04:52 +0300 Subject: [PATCH 3660/5092] Change implementation of `-Z gcc-ld` and `lld-wrapper` again --- compiler/rustc_codegen_ssa/src/back/link.rs | 32 ++++++++++--------- src/bootstrap/compile.rs | 4 ++- src/bootstrap/dist.rs | 7 +++-- src/bootstrap/lib.rs | 3 ++ src/tools/lld-wrapper/src/main.rs | 35 +++++++++++---------- 5 files changed, 48 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 63207803e327..085057c3bf3f 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2777,20 +2777,24 @@ fn add_gcc_ld_path(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { if let LinkerFlavor::Gcc = flavor { match ld_impl { LdImpl::Lld => { - let tools_path = sess.get_tools_search_paths(false); - let gcc_ld_dir = tools_path - .into_iter() - .map(|p| p.join("gcc-ld")) - .find(|p| { - p.join(if sess.host.is_like_windows { "ld.exe" } else { "ld" }).exists() - }) - .unwrap_or_else(|| sess.fatal("rust-lld (as ld) not found")); - cmd.arg({ - let mut arg = OsString::from("-B"); - arg.push(gcc_ld_dir); - arg - }); - cmd.arg(format!("-Wl,-rustc-lld-flavor={}", sess.target.lld_flavor.as_str())); + // Implement the "self-contained" part of -Zgcc-ld + // by adding rustc distribution directories to the tool search path. + for path in sess.get_tools_search_paths(false) { + cmd.arg({ + let mut arg = OsString::from("-B"); + arg.push(path.join("gcc-ld")); + arg + }); + } + // Implement the "linker flavor" part of -Zgcc-ld + // by asking cc to use some kind of lld. + cmd.arg("-fuse-ld=lld"); + if sess.target.lld_flavor != LldFlavor::Ld { + // Tell clang to use a non-default LLD flavor. + // Gcc doesn't understand the target option, but we currently assume + // that gcc is not used for Apple and Wasm targets (#97402). + cmd.arg(format!("--target={}", sess.target.llvm_target)); + } } } } else { diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index dd2b9d59366e..0d89e0a4f25c 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -1276,7 +1276,9 @@ impl Step for Assemble { compiler: build_compiler, target: target_compiler.host, }); - builder.copy(&lld_wrapper_exe, &gcc_ld_dir.join(exe("ld", target_compiler.host))); + for name in crate::LLD_FILE_NAMES { + builder.copy(&lld_wrapper_exe, &gcc_ld_dir.join(exe(name, target_compiler.host))); + } } if builder.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) { diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 6291b204e485..31f71759e249 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -423,8 +423,11 @@ impl Step for Rustc { let gcc_lld_src_dir = src_dir.join("gcc-ld"); let gcc_lld_dst_dir = dst_dir.join("gcc-ld"); t!(fs::create_dir(&gcc_lld_dst_dir)); - let exe_name = exe("ld", compiler.host); - builder.copy(&gcc_lld_src_dir.join(&exe_name), &gcc_lld_dst_dir.join(&exe_name)); + for name in crate::LLD_FILE_NAMES { + let exe_name = exe(name, compiler.host); + builder + .copy(&gcc_lld_src_dir.join(&exe_name), &gcc_lld_dst_dir.join(&exe_name)); + } } // Man pages diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index f84de73297ac..797e84673317 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -186,6 +186,9 @@ const LLVM_TOOLS: &[&str] = &[ "opt", // used to optimize LLVM bytecode ]; +/// LLD file names for all flavors. +const LLD_FILE_NAMES: &[&str] = &["ld.lld", "ld64.lld", "lld-link", "wasm-ld"]; + pub const VERSION: usize = 2; /// Extra --check-cfg to add when building diff --git a/src/tools/lld-wrapper/src/main.rs b/src/tools/lld-wrapper/src/main.rs index 90bd24a75e06..1795f3d7fe5b 100644 --- a/src/tools/lld-wrapper/src/main.rs +++ b/src/tools/lld-wrapper/src/main.rs @@ -8,8 +8,8 @@ //! make gcc/clang pass `-flavor ` as the first two arguments in the linker invocation //! and since Windows does not support symbolic links for files this wrapper is used in place of a //! symbolic link. It execs `../rust-lld -flavor ` by propagating the flavor argument -//! passed to the wrapper as the first two arguments. On Windows it spawns a `..\rust-lld.exe` -//! child process. +//! obtained from the wrapper's name as the first two arguments. +//! On Windows it spawns a `..\rust-lld.exe` child process. use std::fmt::Display; use std::path::{Path, PathBuf}; @@ -53,29 +53,32 @@ fn get_rust_lld_path(current_exe_path: &Path) -> PathBuf { rust_lld_path } +/// Extract LLD flavor name from the lld-wrapper executable name. +fn get_lld_flavor(current_exe_path: &Path) -> Result<&'static str, String> { + let stem = current_exe_path.file_stem(); + Ok(match stem.and_then(|s| s.to_str()) { + Some("ld.lld") => "gnu", + Some("ld64.lld") => "darwin", + Some("lld-link") => "link", + Some("wasm-ld") => "wasm", + _ => return Err(format!("{:?}", stem)), + }) +} + /// Returns the command for invoking rust-lld with the correct flavor. -/// LLD only accepts the flavor argument at the first two arguments, so move it there. +/// LLD only accepts the flavor argument at the first two arguments, so pass it there. /// /// Exits on error. fn get_rust_lld_command(current_exe_path: &Path) -> process::Command { let rust_lld_path = get_rust_lld_path(current_exe_path); let mut command = process::Command::new(rust_lld_path); - let mut flavor = None; - let args = env::args_os() - .skip(1) - .filter(|arg| match arg.to_str().and_then(|s| s.strip_prefix("-rustc-lld-flavor=")) { - Some(suffix) => { - flavor = Some(suffix.to_string()); - false - } - None => true, - }) - .collect::>(); + let flavor = + get_lld_flavor(current_exe_path).unwrap_or_exit_with("executable has unexpected name"); command.arg("-flavor"); - command.arg(flavor.unwrap_or_exit_with("-rustc-lld-flavor= is not passed")); - command.args(args); + command.arg(flavor); + command.args(env::args_os().skip(1)); command } From f8449c2c78366d9ce016bb0b8be788d76ed9528e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 14:31:11 -0400 Subject: [PATCH 3661/5092] stop excluding TERM env var on Unix --- README.md | 5 ++--- src/shims/env.rs | 7 ++++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 5fbf89c86b96..c7a3200dbd90 100644 --- a/README.md +++ b/README.md @@ -282,9 +282,8 @@ environment variable. We first document the most relevant and most commonly used verbose. `hide` hides the warning entirely. * `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from the host so that it cannot be accessed by the program. Can be used multiple times to exclude several variables. The - `TERM` environment variable is excluded by default to [speed up the test - harness](https://github.com/rust-lang/miri/issues/1702). This has no effect unless - `-Zmiri-disable-isolation` is also set. + `TERM` environment variable is excluded by default in Windows to prevent the libtest harness from + accessing the file system. This has no effect unless `-Zmiri-disable-isolation` is also set. * `-Zmiri-env-forward=` forwards the `var` environment variable to the interpreted program. Can be used multiple times to forward several variables. This takes precedence over `-Zmiri-env-exclude`: if a variable is both forwarded and exluced, it *will* get forwarded. This diff --git a/src/shims/env.rs b/src/shims/env.rs index db1ddf6291fd..3dd0b65d0290 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -42,10 +42,11 @@ impl<'tcx> EnvVars<'tcx> { config: &MiriConfig, ) -> InterpResult<'tcx> { let target_os = ecx.tcx.sess.target.os.as_ref(); - // HACK: Exclude `TERM` var to avoid terminfo trying to open the termcap file. - // This is (a) very slow and (b) does not work on Windows. let mut excluded_env_vars = config.excluded_env_vars.clone(); - excluded_env_vars.push("TERM".to_owned()); + if target_os == "windows" { + // HACK: Exclude `TERM` var to avoid terminfo trying to open the termcap file. + excluded_env_vars.push("TERM".to_owned()); + } // Skip the loop entirely if we don't want to forward anything. if ecx.machine.communicate() || !config.forwarded_env_vars.is_empty() { From 437d2414124b9f7409c00ceb86008c1945e1fb7a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 11:53:18 -0400 Subject: [PATCH 3662/5092] move tests covering the env:: module into their own directory --- ci.sh | 2 +- tests/pass/{ => env}/args.rs | 0 tests/pass/{ => env}/args.stdout | 0 tests/pass/{ => env}/current_dir.rs | 0 tests/pass/{ => env}/current_dir_with_isolation.rs | 0 tests/pass/{ => env}/current_dir_with_isolation.stderr | 0 tests/pass/{ => env}/current_exe.rs | 1 + tests/pass/{ => env}/home.rs | 0 tests/pass/{env-exclude.rs => env/var-exclude.rs} | 0 tests/pass/{env-forward.rs => env/var-forward.rs} | 0 .../var-without-isolation.rs} | 0 tests/pass/{env.rs => env/var.rs} | 0 tests/pass/{env.stdout => env/var.stdout} | 0 tests/pass/libc.rs | 4 ++-- 14 files changed, 4 insertions(+), 3 deletions(-) rename tests/pass/{ => env}/args.rs (100%) rename tests/pass/{ => env}/args.stdout (100%) rename tests/pass/{ => env}/current_dir.rs (100%) rename tests/pass/{ => env}/current_dir_with_isolation.rs (100%) rename tests/pass/{ => env}/current_dir_with_isolation.stderr (100%) rename tests/pass/{ => env}/current_exe.rs (68%) rename tests/pass/{ => env}/home.rs (100%) rename tests/pass/{env-exclude.rs => env/var-exclude.rs} (100%) rename tests/pass/{env-forward.rs => env/var-forward.rs} (100%) rename tests/pass/{env-without-isolation.rs => env/var-without-isolation.rs} (100%) rename tests/pass/{env.rs => env/var.rs} (100%) rename tests/pass/{env.stdout => env/var.stdout} (100%) diff --git a/ci.sh b/ci.sh index f93c218f1b0e..67cbed4f826d 100755 --- a/ci.sh +++ b/ci.sh @@ -80,7 +80,7 @@ case $HOST_TARGET in MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests - MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec current_dir data_race env + MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec data_race env/var MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture ;; x86_64-apple-darwin) diff --git a/tests/pass/args.rs b/tests/pass/env/args.rs similarity index 100% rename from tests/pass/args.rs rename to tests/pass/env/args.rs diff --git a/tests/pass/args.stdout b/tests/pass/env/args.stdout similarity index 100% rename from tests/pass/args.stdout rename to tests/pass/env/args.stdout diff --git a/tests/pass/current_dir.rs b/tests/pass/env/current_dir.rs similarity index 100% rename from tests/pass/current_dir.rs rename to tests/pass/env/current_dir.rs diff --git a/tests/pass/current_dir_with_isolation.rs b/tests/pass/env/current_dir_with_isolation.rs similarity index 100% rename from tests/pass/current_dir_with_isolation.rs rename to tests/pass/env/current_dir_with_isolation.rs diff --git a/tests/pass/current_dir_with_isolation.stderr b/tests/pass/env/current_dir_with_isolation.stderr similarity index 100% rename from tests/pass/current_dir_with_isolation.stderr rename to tests/pass/env/current_dir_with_isolation.stderr diff --git a/tests/pass/current_exe.rs b/tests/pass/env/current_exe.rs similarity index 68% rename from tests/pass/current_exe.rs rename to tests/pass/env/current_exe.rs index 64f62b230e48..15ea6a52b7b6 100644 --- a/tests/pass/current_exe.rs +++ b/tests/pass/env/current_exe.rs @@ -1,4 +1,5 @@ //@ignore-target-windows +//@only-on-host: the Linux std implementation opens /proc/self/exe, which doesn't work cross-target //@compile-flags: -Zmiri-disable-isolation use std::env; diff --git a/tests/pass/home.rs b/tests/pass/env/home.rs similarity index 100% rename from tests/pass/home.rs rename to tests/pass/env/home.rs diff --git a/tests/pass/env-exclude.rs b/tests/pass/env/var-exclude.rs similarity index 100% rename from tests/pass/env-exclude.rs rename to tests/pass/env/var-exclude.rs diff --git a/tests/pass/env-forward.rs b/tests/pass/env/var-forward.rs similarity index 100% rename from tests/pass/env-forward.rs rename to tests/pass/env/var-forward.rs diff --git a/tests/pass/env-without-isolation.rs b/tests/pass/env/var-without-isolation.rs similarity index 100% rename from tests/pass/env-without-isolation.rs rename to tests/pass/env/var-without-isolation.rs diff --git a/tests/pass/env.rs b/tests/pass/env/var.rs similarity index 100% rename from tests/pass/env.rs rename to tests/pass/env/var.rs diff --git a/tests/pass/env.stdout b/tests/pass/env/var.stdout similarity index 100% rename from tests/pass/env.stdout rename to tests/pass/env/var.stdout diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index 468da0845a88..b58485602148 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -88,7 +88,7 @@ fn test_posix_realpath_errors() { assert_eq!(e.kind(), ErrorKind::NotFound); } -#[cfg(any(target_os = "linux", target_os = "freebsd"))] +#[cfg(any(target_os = "linux"))] fn test_posix_fadvise() { use std::convert::TryInto; use std::io::Write; @@ -452,7 +452,7 @@ fn test_posix_mkstemp() { } fn main() { - #[cfg(any(target_os = "linux", target_os = "freebsd"))] + #[cfg(any(target_os = "linux"))] test_posix_fadvise(); test_posix_gettimeofday(); From 79d147edb75299f9d4789b689f9c7f34a7db7709 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 14:34:44 -0400 Subject: [PATCH 3663/5092] make home_dir work on macOS --- src/shims/unix/foreign_items.rs | 36 +++++++++++++++++++++++++++ src/shims/unix/linux/foreign_items.rs | 35 -------------------------- tests/pass/env/home.rs | 2 +- 3 files changed, 37 insertions(+), 36 deletions(-) diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 7dde2d7d2c19..6ea10de0b8a8 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -553,6 +553,42 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_int(super::UID, dest)?; } + "getpwuid_r" if this.frame_in_std() => { + let [uid, pwd, buf, buflen, result] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + this.check_no_isolation("`getpwuid_r`")?; + + let uid = this.read_scalar(uid)?.to_u32()?; + let pwd = this.deref_operand(pwd)?; + let buf = this.read_pointer(buf)?; + let buflen = this.read_scalar(buflen)?.to_machine_usize(this)?; + let result = this.deref_operand(result)?; + + // Must be for "us". + if uid != crate::shims::unix::UID { + throw_unsup_format!("`getpwuid_r` on other users is not supported"); + } + + // Reset all fields to `uninit` to make sure nobody reads them. + // (This is a std-only shim so we are okay with such hacks.) + this.write_uninit(&pwd.into())?; + + // We only set the home_dir field. + #[allow(deprecated)] + let home_dir = std::env::home_dir().unwrap(); + let (written, _) = this.write_path_to_c_str(&home_dir, buf, buflen)?; + let pw_dir = this.mplace_field_named(&pwd, "pw_dir")?; + this.write_pointer(buf, &pw_dir.into())?; + + if written { + this.write_pointer(pwd.ptr, &result.into())?; + this.write_null(dest)?; + } else { + this.write_null(&result.into())?; + this.write_scalar(this.eval_libc("ERANGE")?, dest)?; + } + } + // Platform-specific shims _ => { match this.tcx.sess.target.os.as_ref() { diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index 61016c424954..bae3780b460c 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -155,41 +155,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - "getpwuid_r" if this.frame_in_std() => { - let [uid, pwd, buf, buflen, result] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - this.check_no_isolation("`getpwuid_r`")?; - - let uid = this.read_scalar(uid)?.to_u32()?; - let pwd = this.deref_operand(pwd)?; - let buf = this.read_pointer(buf)?; - let buflen = this.read_scalar(buflen)?.to_machine_usize(this)?; - let result = this.deref_operand(result)?; - - // Must be for "us". - if uid != crate::shims::unix::UID { - throw_unsup_format!("`getpwuid_r` on other users is not supported"); - } - - // Reset all fields to `uninit` to make sure nobody reads them. - this.write_uninit(&pwd.into())?; - - // We only set the home_dir field. - #[allow(deprecated)] - let home_dir = std::env::home_dir().unwrap(); - let (written, _) = this.write_path_to_c_str(&home_dir, buf, buflen)?; - let pw_dir = this.mplace_field_named(&pwd, "pw_dir")?; - this.write_pointer(buf, &pw_dir.into())?; - - if written { - this.write_pointer(pwd.ptr, &result.into())?; - this.write_null(dest)?; - } else { - this.write_null(&result.into())?; - this.write_scalar(this.eval_libc("ERANGE")?, dest)?; - } - } - _ => return Ok(EmulateByNameResult::NotSupported), }; diff --git a/tests/pass/env/home.rs b/tests/pass/env/home.rs index 0fb69aad0077..9eb9c3af569d 100644 --- a/tests/pass/env/home.rs +++ b/tests/pass/env/home.rs @@ -1,4 +1,4 @@ -//@only-target-linux: home_dir is only supported on Linux +//@ignore-target-windows: home_dir is not supported on Windows //@compile-flags: -Zmiri-disable-isolation use std::env; From 353f7d539ae628a46ecfa1c316d963633e17e780 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 4 Aug 2022 09:55:18 -0400 Subject: [PATCH 3664/5092] add special exception for std_miri_test crate to call std-only functions --- src/helpers.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/helpers.rs b/src/helpers.rs index 220347ff1b96..7c9f8740eb42 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -803,7 +803,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Fall back to the instance of the function itself. let instance = instance.unwrap_or(frame.instance); // Now check if this is in the same crate as start_fn. - this.tcx.def_path(instance.def_id()).krate == this.tcx.def_path(start_fn).krate + // As a special exception we also allow unit tests from + // to call these + // shims. + let frame_crate = this.tcx.def_path(instance.def_id()).krate; + frame_crate == this.tcx.def_path(start_fn).krate + || this.tcx.crate_name(frame_crate).as_str() == "std_miri_test" } /// Handler that should be called when unsupported functionality is encountered. From 76d99c37c90496425fb7f3f8e2be4e9c16f276af Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 15:21:08 -0400 Subject: [PATCH 3665/5092] fix RUSTC_BACKTRACE always being set --- src/bin/miri.rs | 7 +++++++ src/eval.rs | 6 +++++- src/shims/env.rs | 8 ++++---- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 489eb959906c..430f9e2f637b 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -306,6 +306,11 @@ fn parse_comma_list(input: &str) -> Result, T::Err> { } fn main() { + // Snapshot a copy of the environment before `rustc` starts messing with it. + // (`install_ice_hook` might change `RUST_BACKTRACE`.) + let env_snapshot = env::vars_os().collect::>(); + + // Earliest rustc setup. rustc_driver::install_ice_hook(); // If the environment asks us to actually be rustc, then do that. @@ -333,6 +338,8 @@ fn main() { // Parse our arguments and split them across `rustc` and `miri`. let mut miri_config = miri::MiriConfig::default(); + miri_config.env = env_snapshot; + let mut rustc_args = vec![]; let mut after_dashdash = false; diff --git a/src/eval.rs b/src/eval.rs index cb24dea3a88d..981776e3eebd 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -1,7 +1,7 @@ //! Main evaluator loop and setting up the initial stack frame. use std::collections::HashSet; -use std::ffi::OsStr; +use std::ffi::{OsStr, OsString}; use std::iter; use std::panic::{self, AssertUnwindSafe}; use std::thread; @@ -72,6 +72,9 @@ pub enum BacktraceStyle { /// Configuration needed to spawn a Miri instance. #[derive(Clone)] pub struct MiriConfig { + /// The host environment snapshot to use as basis for what is provided to the interpreted program. + /// (This is still subject to isolation as well as `excluded_env_vars` and `forwarded_env_vars`.) + pub env: Vec<(OsString, OsString)>, /// Determine if validity checking is enabled. pub validate: bool, /// Determines if Stacked Borrows is enabled. @@ -130,6 +133,7 @@ pub struct MiriConfig { impl Default for MiriConfig { fn default() -> MiriConfig { MiriConfig { + env: vec![], validate: true, stacked_borrows: true, check_alignment: AlignmentCheck::Int, diff --git a/src/shims/env.rs b/src/shims/env.rs index db1ddf6291fd..07b9cf18192c 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -49,11 +49,11 @@ impl<'tcx> EnvVars<'tcx> { // Skip the loop entirely if we don't want to forward anything. if ecx.machine.communicate() || !config.forwarded_env_vars.is_empty() { - for (name, value) in env::vars_os() { + for (name, value) in &config.env { // Always forward what is in `forwarded_env_vars`; that list can take precedence over excluded_env_vars. - let forward = config.forwarded_env_vars.iter().any(|v| **v == name) + let forward = config.forwarded_env_vars.iter().any(|v| **v == *name) || (ecx.machine.communicate() - && !excluded_env_vars.iter().any(|v| **v == name)); + && !excluded_env_vars.iter().any(|v| **v == *name)); if forward { let var_ptr = match target_os { target if target_os_is_unix(target) => @@ -65,7 +65,7 @@ impl<'tcx> EnvVars<'tcx> { unsupported ), }; - ecx.machine.env_vars.map.insert(name, var_ptr); + ecx.machine.env_vars.map.insert(name.clone(), var_ptr); } } } From d2ba40e9e1ff18f14b2d75462c0f7d7afcae7e76 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 15:29:43 -0400 Subject: [PATCH 3666/5092] make tests pass again --- src/bin/miri.rs | 6 +++++- tests/pass/backtrace/backtrace-global-alloc.rs | 1 + tests/pass/backtrace/backtrace-std.rs | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 430f9e2f637b..dcccdecc6cf1 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -1,5 +1,9 @@ #![feature(rustc_private, stmt_expr_attributes)] -#![allow(clippy::manual_range_contains, clippy::useless_format)] +#![allow( + clippy::manual_range_contains, + clippy::useless_format, + clippy::field_reassign_with_default +)] extern crate rustc_data_structures; extern crate rustc_driver; diff --git a/tests/pass/backtrace/backtrace-global-alloc.rs b/tests/pass/backtrace/backtrace-global-alloc.rs index 45d6535bc139..406a5b62333d 100644 --- a/tests/pass/backtrace/backtrace-global-alloc.rs +++ b/tests/pass/backtrace/backtrace-global-alloc.rs @@ -1,4 +1,5 @@ //@compile-flags: -Zmiri-disable-isolation +//@rustc-env: RUST_BACKTRACE=1 #![feature(backtrace)] diff --git a/tests/pass/backtrace/backtrace-std.rs b/tests/pass/backtrace/backtrace-std.rs index 488b87ede8fc..9106310e513d 100644 --- a/tests/pass/backtrace/backtrace-std.rs +++ b/tests/pass/backtrace/backtrace-std.rs @@ -1,4 +1,5 @@ //@compile-flags: -Zmiri-disable-isolation +//@rustc-env: RUST_BACKTRACE=1 #![feature(backtrace)] From 141d5a6396d1763d2e753edd60d3e6311c13c4c9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 15:30:00 -0400 Subject: [PATCH 3667/5092] avoid panic/panic folder --- tests/panic/{panic => }/div-by-zero-2.rs | 0 tests/panic/{panic => }/div-by-zero-2.stderr | 0 tests/panic/{panic => }/overflowing-lsh-neg.rs | 0 tests/panic/{panic => }/overflowing-lsh-neg.stderr | 0 tests/panic/{panic => }/overflowing-rsh-1.rs | 0 tests/panic/{panic => }/overflowing-rsh-1.stderr | 0 tests/panic/{panic => }/overflowing-rsh-2.rs | 0 tests/panic/{panic => }/overflowing-rsh-2.stderr | 0 tests/panic/{panic => }/panic1.rs | 0 tests/panic/{panic => }/panic1.stderr | 0 tests/panic/{panic => }/panic2.rs | 0 tests/panic/{panic => }/panic2.stderr | 0 tests/panic/{panic => }/panic3.rs | 0 tests/panic/{panic => }/panic3.stderr | 0 tests/panic/{panic => }/panic4.rs | 0 tests/panic/{panic => }/panic4.stderr | 0 tests/panic/{panic => }/unsupported_foreign_function.rs | 0 tests/panic/{panic => }/unsupported_foreign_function.stderr | 0 tests/panic/{panic => }/unsupported_syscall.rs | 0 tests/panic/{panic => }/unsupported_syscall.stderr | 0 20 files changed, 0 insertions(+), 0 deletions(-) rename tests/panic/{panic => }/div-by-zero-2.rs (100%) rename tests/panic/{panic => }/div-by-zero-2.stderr (100%) rename tests/panic/{panic => }/overflowing-lsh-neg.rs (100%) rename tests/panic/{panic => }/overflowing-lsh-neg.stderr (100%) rename tests/panic/{panic => }/overflowing-rsh-1.rs (100%) rename tests/panic/{panic => }/overflowing-rsh-1.stderr (100%) rename tests/panic/{panic => }/overflowing-rsh-2.rs (100%) rename tests/panic/{panic => }/overflowing-rsh-2.stderr (100%) rename tests/panic/{panic => }/panic1.rs (100%) rename tests/panic/{panic => }/panic1.stderr (100%) rename tests/panic/{panic => }/panic2.rs (100%) rename tests/panic/{panic => }/panic2.stderr (100%) rename tests/panic/{panic => }/panic3.rs (100%) rename tests/panic/{panic => }/panic3.stderr (100%) rename tests/panic/{panic => }/panic4.rs (100%) rename tests/panic/{panic => }/panic4.stderr (100%) rename tests/panic/{panic => }/unsupported_foreign_function.rs (100%) rename tests/panic/{panic => }/unsupported_foreign_function.stderr (100%) rename tests/panic/{panic => }/unsupported_syscall.rs (100%) rename tests/panic/{panic => }/unsupported_syscall.stderr (100%) diff --git a/tests/panic/panic/div-by-zero-2.rs b/tests/panic/div-by-zero-2.rs similarity index 100% rename from tests/panic/panic/div-by-zero-2.rs rename to tests/panic/div-by-zero-2.rs diff --git a/tests/panic/panic/div-by-zero-2.stderr b/tests/panic/div-by-zero-2.stderr similarity index 100% rename from tests/panic/panic/div-by-zero-2.stderr rename to tests/panic/div-by-zero-2.stderr diff --git a/tests/panic/panic/overflowing-lsh-neg.rs b/tests/panic/overflowing-lsh-neg.rs similarity index 100% rename from tests/panic/panic/overflowing-lsh-neg.rs rename to tests/panic/overflowing-lsh-neg.rs diff --git a/tests/panic/panic/overflowing-lsh-neg.stderr b/tests/panic/overflowing-lsh-neg.stderr similarity index 100% rename from tests/panic/panic/overflowing-lsh-neg.stderr rename to tests/panic/overflowing-lsh-neg.stderr diff --git a/tests/panic/panic/overflowing-rsh-1.rs b/tests/panic/overflowing-rsh-1.rs similarity index 100% rename from tests/panic/panic/overflowing-rsh-1.rs rename to tests/panic/overflowing-rsh-1.rs diff --git a/tests/panic/panic/overflowing-rsh-1.stderr b/tests/panic/overflowing-rsh-1.stderr similarity index 100% rename from tests/panic/panic/overflowing-rsh-1.stderr rename to tests/panic/overflowing-rsh-1.stderr diff --git a/tests/panic/panic/overflowing-rsh-2.rs b/tests/panic/overflowing-rsh-2.rs similarity index 100% rename from tests/panic/panic/overflowing-rsh-2.rs rename to tests/panic/overflowing-rsh-2.rs diff --git a/tests/panic/panic/overflowing-rsh-2.stderr b/tests/panic/overflowing-rsh-2.stderr similarity index 100% rename from tests/panic/panic/overflowing-rsh-2.stderr rename to tests/panic/overflowing-rsh-2.stderr diff --git a/tests/panic/panic/panic1.rs b/tests/panic/panic1.rs similarity index 100% rename from tests/panic/panic/panic1.rs rename to tests/panic/panic1.rs diff --git a/tests/panic/panic/panic1.stderr b/tests/panic/panic1.stderr similarity index 100% rename from tests/panic/panic/panic1.stderr rename to tests/panic/panic1.stderr diff --git a/tests/panic/panic/panic2.rs b/tests/panic/panic2.rs similarity index 100% rename from tests/panic/panic/panic2.rs rename to tests/panic/panic2.rs diff --git a/tests/panic/panic/panic2.stderr b/tests/panic/panic2.stderr similarity index 100% rename from tests/panic/panic/panic2.stderr rename to tests/panic/panic2.stderr diff --git a/tests/panic/panic/panic3.rs b/tests/panic/panic3.rs similarity index 100% rename from tests/panic/panic/panic3.rs rename to tests/panic/panic3.rs diff --git a/tests/panic/panic/panic3.stderr b/tests/panic/panic3.stderr similarity index 100% rename from tests/panic/panic/panic3.stderr rename to tests/panic/panic3.stderr diff --git a/tests/panic/panic/panic4.rs b/tests/panic/panic4.rs similarity index 100% rename from tests/panic/panic/panic4.rs rename to tests/panic/panic4.rs diff --git a/tests/panic/panic/panic4.stderr b/tests/panic/panic4.stderr similarity index 100% rename from tests/panic/panic/panic4.stderr rename to tests/panic/panic4.stderr diff --git a/tests/panic/panic/unsupported_foreign_function.rs b/tests/panic/unsupported_foreign_function.rs similarity index 100% rename from tests/panic/panic/unsupported_foreign_function.rs rename to tests/panic/unsupported_foreign_function.rs diff --git a/tests/panic/panic/unsupported_foreign_function.stderr b/tests/panic/unsupported_foreign_function.stderr similarity index 100% rename from tests/panic/panic/unsupported_foreign_function.stderr rename to tests/panic/unsupported_foreign_function.stderr diff --git a/tests/panic/panic/unsupported_syscall.rs b/tests/panic/unsupported_syscall.rs similarity index 100% rename from tests/panic/panic/unsupported_syscall.rs rename to tests/panic/unsupported_syscall.rs diff --git a/tests/panic/panic/unsupported_syscall.stderr b/tests/panic/unsupported_syscall.stderr similarity index 100% rename from tests/panic/panic/unsupported_syscall.stderr rename to tests/panic/unsupported_syscall.stderr From 1c7c792ddafe2a1aaa76e2ddee4fa9b2187dcfcb Mon Sep 17 00:00:00 2001 From: Nika Layzell Date: Mon, 25 Jul 2022 00:43:33 -0400 Subject: [PATCH 3668/5092] proc_macro/bridge: send diagnostics over the bridge as a struct This removes some RPC when creating and emitting diagnostics, and simplifies the bridge slightly. After this change, there are no remaining methods which take advantage of the support for `&mut` references to objects in the store as arguments, meaning that support for them could technically be removed if we wanted. The only remaining uses of immutable references into the store are `TokenStream` and `SourceFile`. --- .../rustc_expand/src/proc_macro_server.rs | 53 ++++++----------- library/proc_macro/src/bridge/client.rs | 2 - library/proc_macro/src/bridge/mod.rs | 29 ++++----- library/proc_macro/src/bridge/server.rs | 2 - library/proc_macro/src/diagnostic.rs | 21 +++---- .../src/abis/abi_sysroot/ra_server.rs | 59 ++----------------- 6 files changed, 41 insertions(+), 125 deletions(-) diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 7d9a4aed0bf5..2ac19a89ab70 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -6,7 +6,7 @@ use rustc_ast::tokenstream::{self, Spacing::*, TokenStream}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; -use rustc_errors::{Diagnostic, MultiSpan, PResult}; +use rustc_errors::{MultiSpan, PResult}; use rustc_parse::lexer::nfc_normalize; use rustc_parse::parse_stream_from_source_str; use rustc_session::parse::ParseSess; @@ -15,7 +15,7 @@ use rustc_span::symbol::{self, sym, Symbol}; use rustc_span::{BytePos, FileName, Pos, SourceFile, Span}; use pm::bridge::{ - server, DelimSpan, ExpnGlobals, Group, Ident, LitKind, Literal, Punct, TokenTree, + server, DelimSpan, Diagnostic, ExpnGlobals, Group, Ident, LitKind, Literal, Punct, TokenTree, }; use pm::{Delimiter, Level, LineColumn}; use std::ops::Bound; @@ -368,8 +368,6 @@ impl server::Types for Rustc<'_, '_> { type FreeFunctions = FreeFunctions; type TokenStream = TokenStream; type SourceFile = Lrc; - type MultiSpan = Vec; - type Diagnostic = Diagnostic; type Span = Span; type Symbol = Symbol; } @@ -436,6 +434,21 @@ impl server::FreeFunctions for Rustc<'_, '_> { span: self.call_site, }) } + + fn emit_diagnostic(&mut self, diagnostic: Diagnostic) { + let mut diag = + rustc_errors::Diagnostic::new(diagnostic.level.to_internal(), diagnostic.message); + diag.set_span(MultiSpan::from_spans(diagnostic.spans)); + for child in diagnostic.children { + diag.sub( + child.level.to_internal(), + child.message, + MultiSpan::from_spans(child.spans), + None, + ); + } + self.sess().span_diagnostic.emit_diagnostic(&mut diag); + } } impl server::TokenStream for Rustc<'_, '_> { @@ -577,38 +590,6 @@ impl server::SourceFile for Rustc<'_, '_> { } } -impl server::MultiSpan for Rustc<'_, '_> { - fn new(&mut self) -> Self::MultiSpan { - vec![] - } - - fn push(&mut self, spans: &mut Self::MultiSpan, span: Self::Span) { - spans.push(span) - } -} - -impl server::Diagnostic for Rustc<'_, '_> { - fn new(&mut self, level: Level, msg: &str, spans: Self::MultiSpan) -> Self::Diagnostic { - let mut diag = Diagnostic::new(level.to_internal(), msg); - diag.set_span(MultiSpan::from_spans(spans)); - diag - } - - fn sub( - &mut self, - diag: &mut Self::Diagnostic, - level: Level, - msg: &str, - spans: Self::MultiSpan, - ) { - diag.sub(level.to_internal(), msg, MultiSpan::from_spans(spans), None); - } - - fn emit(&mut self, mut diag: Self::Diagnostic) { - self.sess().span_diagnostic.emit_diagnostic(&mut diag); - } -} - impl server::Span for Rustc<'_, '_> { fn debug(&mut self, span: Self::Span) -> String { if self.ecx.ecfg.span_debug { diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index 1516f084ab8b..4461b21802ad 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -176,8 +176,6 @@ define_handles! { FreeFunctions, TokenStream, SourceFile, - MultiSpan, - Diagnostic, 'interned: Span, diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index 5cde966bf173..4c1e196b5ad1 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -57,6 +57,7 @@ macro_rules! with_api { fn track_env_var(var: &str, value: Option<&str>); fn track_path(path: &str); fn literal_from_str(s: &str) -> Result, ()>; + fn emit_diagnostic(diagnostic: Diagnostic<$S::Span>); }, TokenStream { fn drop($self: $S::TokenStream); @@ -87,22 +88,6 @@ macro_rules! with_api { fn path($self: &$S::SourceFile) -> String; fn is_real($self: &$S::SourceFile) -> bool; }, - MultiSpan { - fn drop($self: $S::MultiSpan); - fn new() -> $S::MultiSpan; - fn push($self: &mut $S::MultiSpan, span: $S::Span); - }, - Diagnostic { - fn drop($self: $S::Diagnostic); - fn new(level: Level, msg: &str, span: $S::MultiSpan) -> $S::Diagnostic; - fn sub( - $self: &mut $S::Diagnostic, - level: Level, - msg: &str, - span: $S::MultiSpan, - ); - fn emit($self: $S::Diagnostic); - }, Span { fn debug($self: $S::Span) -> String; fn source_file($self: $S::Span) -> $S::SourceFile; @@ -510,6 +495,18 @@ compound_traits!( } ); +#[derive(Clone, Debug)] +pub struct Diagnostic { + pub level: Level, + pub message: String, + pub spans: Vec, + pub children: Vec>, +} + +compound_traits!( + struct Diagnostic { level, message, spans, children } +); + /// Globals provided alongside the initial inputs for a macro expansion. /// Provides values such as spans which are used frequently to avoid RPC. #[derive(Clone)] diff --git a/library/proc_macro/src/bridge/server.rs b/library/proc_macro/src/bridge/server.rs index e068ec60b6af..e47a77f6c135 100644 --- a/library/proc_macro/src/bridge/server.rs +++ b/library/proc_macro/src/bridge/server.rs @@ -11,8 +11,6 @@ pub trait Types { type FreeFunctions: 'static; type TokenStream: 'static + Clone; type SourceFile: 'static + Clone; - type MultiSpan: 'static; - type Diagnostic: 'static; type Span: 'static + Copy + Eq + Hash; type Symbol: 'static; } diff --git a/library/proc_macro/src/diagnostic.rs b/library/proc_macro/src/diagnostic.rs index 6e46dc0367d0..5a209f7c7aa1 100644 --- a/library/proc_macro/src/diagnostic.rs +++ b/library/proc_macro/src/diagnostic.rs @@ -161,22 +161,15 @@ impl Diagnostic { /// Emit the diagnostic. #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] pub fn emit(self) { - fn to_internal(spans: Vec) -> crate::bridge::client::MultiSpan { - let mut multi_span = crate::bridge::client::MultiSpan::new(); - for span in spans { - multi_span.push(span.0); + fn to_internal(diag: Diagnostic) -> crate::bridge::Diagnostic { + crate::bridge::Diagnostic { + level: diag.level, + message: diag.message, + spans: diag.spans.into_iter().map(|s| s.0).collect(), + children: diag.children.into_iter().map(to_internal).collect(), } - multi_span } - let mut diag = crate::bridge::client::Diagnostic::new( - self.level, - &self.message[..], - to_internal(self.spans), - ); - for c in self.children { - diag.sub(c.level, &c.message[..], to_internal(c.spans)); - } - diag.emit(); + crate::bridge::client::FreeFunctions::emit_diagnostic(to_internal(self)); } } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs index 46882845a807..c1f8615aaf20 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs @@ -37,23 +37,6 @@ pub struct SourceFile { type Level = super::proc_macro::Level; type LineColumn = super::proc_macro::LineColumn; -/// A structure representing a diagnostic message and associated children -/// messages. -#[derive(Clone, Debug)] -pub struct Diagnostic { - level: Level, - message: String, - spans: Vec, - children: Vec, -} - -impl Diagnostic { - /// Creates a new diagnostic with the given `level` and `message`. - pub fn new>(level: Level, message: T) -> Diagnostic { - Diagnostic { level, message: message.into(), spans: vec![], children: vec![] } - } -} - pub struct FreeFunctions; #[derive(Default)] @@ -65,8 +48,6 @@ impl server::Types for RustAnalyzer { type FreeFunctions = FreeFunctions; type TokenStream = TokenStream; type SourceFile = SourceFile; - type MultiSpan = Vec; - type Diagnostic = Diagnostic; type Span = Span; type Symbol = Symbol; } @@ -90,6 +71,10 @@ impl server::FreeFunctions for RustAnalyzer { span: tt::TokenId::unspecified(), }) } + + fn emit_diagnostic(&mut self, _: bridge::Diagnostic) { + // FIXME handle diagnostic + } } impl server::TokenStream for RustAnalyzer { @@ -282,30 +267,6 @@ impl server::SourceFile for RustAnalyzer { } } -impl server::Diagnostic for RustAnalyzer { - fn new(&mut self, level: Level, msg: &str, spans: Self::MultiSpan) -> Self::Diagnostic { - let mut diag = Diagnostic::new(level, msg); - diag.spans = spans; - diag - } - - fn sub( - &mut self, - _diag: &mut Self::Diagnostic, - _level: Level, - _msg: &str, - _spans: Self::MultiSpan, - ) { - // FIXME handle diagnostic - // - } - - fn emit(&mut self, _diag: Self::Diagnostic) { - // FIXME handle diagnostic - // diag.emit() - } -} - impl server::Span for RustAnalyzer { fn debug(&mut self, span: Self::Span) -> String { format!("{:?}", span.0) @@ -372,18 +333,6 @@ impl server::Span for RustAnalyzer { } } -impl server::MultiSpan for RustAnalyzer { - fn new(&mut self) -> Self::MultiSpan { - // FIXME handle span - vec![] - } - - fn push(&mut self, other: &mut Self::MultiSpan, span: Self::Span) { - //TODP - other.push(span) - } -} - impl server::Symbol for RustAnalyzer { fn normalize_and_validate_ident(&mut self, string: &str) -> Result { // FIXME: nfc-normalize and validate idents From e12df0f4043f89bc59eb40e351fdb58f0b545abb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 19:31:20 -0400 Subject: [PATCH 3669/5092] also forward --manifest-path to 'cargo metadata' --- cargo-miri/src/phases.rs | 1 + cargo-miri/src/util.rs | 38 +++++++++++++++++++++----------------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/cargo-miri/src/phases.rs b/cargo-miri/src/phases.rs index 4ba627de482c..376b191192f4 100644 --- a/cargo-miri/src/phases.rs +++ b/cargo-miri/src/phases.rs @@ -117,6 +117,7 @@ pub fn phase_cargo_miri(mut args: impl Iterator) { cmd.arg(cargo_cmd); // Forward all arguments before `--` other than `--target-dir` and its value to Cargo. + // (We want to *change* the target-dir value, so we must not forward it.) let mut target_dir = None; for arg in ArgSplitFlagValue::new(&mut args, "--target-dir") { match arg { diff --git a/cargo-miri/src/util.rs b/cargo-miri/src/util.rs index d6a42a2f855d..729794ed9930 100644 --- a/cargo-miri/src/util.rs +++ b/cargo-miri/src/util.rs @@ -287,29 +287,33 @@ pub fn write_to_file(filename: &Path, content: &str) { fs::rename(temp_filename, filename).unwrap(); } -pub fn get_cargo_metadata() -> Metadata { - // The `build.target-dir` config can be passed by `--config` flags, so forward them to - // `cargo metadata`. - let mut additional_options = Vec::new(); +// Computes the extra flags that need to be passed to cargo to make it behave like the current +// cargo invocation. +fn cargo_extra_flags() -> Vec { + let mut flags = Vec::new(); // `-Zunstable-options` is required by `--config`. - additional_options.push("-Zunstable-options".to_string()); + flags.push("-Zunstable-options".to_string()); + // Forward `--config` flags. let config_flag = "--config"; - for arg in ArgSplitFlagValue::new( - env::args().skip(3), // skip the program name, "miri" and "run" / "test" - config_flag, - ) - // Only look at `Ok` - .flatten() - { - additional_options.push(config_flag.to_string()); - additional_options.push(arg); + for arg in ArgFlagValueIter::new(config_flag) { + flags.push(config_flag.to_string()); + flags.push(arg); } - let metadata = - MetadataCommand::new().no_deps().other_options(additional_options).exec().unwrap(); + // Forward `--manifest-path`. + let manifest_flag = "--manifest-path"; + if let Some(manifest) = get_arg_flag_value(manifest_flag) { + flags.push(manifest_flag.to_string()); + flags.push(manifest); + } - metadata + flags +} + +pub fn get_cargo_metadata() -> Metadata { + // This will honor the `CARGO` env var the same way our `cargo()` does. + MetadataCommand::new().no_deps().other_options(cargo_extra_flags()).exec().unwrap() } /// Pulls all the crates in this workspace from the cargo metadata. From 465538245a3a8768b9bf33d4fdd448cf32f29921 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 19:41:31 -0400 Subject: [PATCH 3670/5092] reuse arg flag parse logic in rustdoc handling --- cargo-miri/src/phases.rs | 12 ++++++------ cargo-miri/src/util.rs | 21 +++++++++++++-------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/cargo-miri/src/phases.rs b/cargo-miri/src/phases.rs index 376b191192f4..38bc62436956 100644 --- a/cargo-miri/src/phases.rs +++ b/cargo-miri/src/phases.rs @@ -310,17 +310,17 @@ pub fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { let mut cmd = miri(); // Ensure --emit argument for a check-only build is present. - // We cannot use the usual helpers since we need to check specifically in `env.args`. - if let Some(i) = env.args.iter().position(|arg| arg.starts_with("--emit=")) { + if let Some(val) = ArgFlagValueIter::new(env.args.clone().into_iter(), "--emit").next() + { // For `no_run` tests, rustdoc passes a `--emit` flag; make sure it has the right shape. - assert_eq!(env.args[i], "--emit=metadata"); + assert_eq!(val, "metadata"); } else { // For all other kinds of tests, we can just add our flag. cmd.arg("--emit=metadata"); } // Alter the `-o` parameter so that it does not overwrite the JSON file we stored above. - let mut args = env.args.clone(); + let mut args = env.args; for i in 0..args.len() { if args[i] == "-o" { args[i + 1].push_str(".miri"); @@ -344,7 +344,7 @@ pub fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { return; } - if runnable_crate && ArgFlagValueIter::new("--extern").any(|krate| krate == "proc_macro") { + if runnable_crate && get_arg_flag_values("--extern").any(|krate| krate == "proc_macro") { // This is a "runnable" `proc-macro` crate (unit tests). We do not support // interpreting that under Miri now, so we write a JSON file to (display a // helpful message and) skip it in the runner phase. @@ -568,7 +568,7 @@ pub fn phase_rustdoc(mut args: impl Iterator) { // Doctests of `proc-macro` crates (and their dependencies) are always built for the host, // so we are not able to run them in Miri. - if ArgFlagValueIter::new("--crate-type").any(|crate_type| crate_type == "proc-macro") { + if get_arg_flag_values("--crate-type").any(|crate_type| crate_type == "proc-macro") { eprintln!("Running doctests of `proc-macro` crates is not currently supported by Miri."); return; } diff --git a/cargo-miri/src/util.rs b/cargo-miri/src/util.rs index 729794ed9930..27e312a4662a 100644 --- a/cargo-miri/src/util.rs +++ b/cargo-miri/src/util.rs @@ -81,7 +81,7 @@ pub fn has_arg_flag(name: &str) -> bool { /// Determines how many times a `--flag` is present. pub fn num_arg_flag(name: &str) -> usize { - std::env::args().take_while(|val| val != "--").filter(|val| val == name).count() + env::args().take_while(|val| val != "--").filter(|val| val == name).count() } /// Yields all values of command line flag `name` as `Ok(arg)`, and all other arguments except @@ -121,15 +121,15 @@ impl> Iterator for ArgSplitFlagValue<'_, I> { } /// Yields all values of command line flag `name`. -pub struct ArgFlagValueIter<'a>(ArgSplitFlagValue<'a, env::Args>); +pub struct ArgFlagValueIter<'a, I>(ArgSplitFlagValue<'a, I>); -impl<'a> ArgFlagValueIter<'a> { - pub fn new(name: &'a str) -> Self { - Self(ArgSplitFlagValue::new(env::args(), name)) +impl<'a, I: Iterator> ArgFlagValueIter<'a, I> { + pub fn new(args: I, name: &'a str) -> Self { + Self(ArgSplitFlagValue::new(args, name)) } } -impl Iterator for ArgFlagValueIter<'_> { +impl> Iterator for ArgFlagValueIter<'_, I> { type Item = String; fn next(&mut self) -> Option { @@ -141,9 +141,14 @@ impl Iterator for ArgFlagValueIter<'_> { } } +/// Gets the values of a `--flag`. +pub fn get_arg_flag_values<'a>(name: &'a str) -> impl Iterator + 'a { + ArgFlagValueIter::new(env::args(), name) +} + /// Gets the value of a `--flag`. pub fn get_arg_flag_value(name: &str) -> Option { - ArgFlagValueIter::new(name).next() + get_arg_flag_values(name).next() } /// Escapes `s` in a way that is suitable for using it as a string literal in TOML syntax. @@ -296,7 +301,7 @@ fn cargo_extra_flags() -> Vec { // Forward `--config` flags. let config_flag = "--config"; - for arg in ArgFlagValueIter::new(config_flag) { + for arg in get_arg_flag_values(config_flag) { flags.push(config_flag.to_string()); flags.push(arg); } From 08e7d945629b32b32c34d5df84d881292e6f0451 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 21:17:54 -0400 Subject: [PATCH 3671/5092] avoid some string copies... --- cargo-miri/src/arg.rs | 134 +++++++++++++++++++++++++++++++++++++++ cargo-miri/src/main.rs | 1 + cargo-miri/src/phases.rs | 5 +- cargo-miri/src/util.rs | 80 +---------------------- 4 files changed, 140 insertions(+), 80 deletions(-) create mode 100644 cargo-miri/src/arg.rs diff --git a/cargo-miri/src/arg.rs b/cargo-miri/src/arg.rs new file mode 100644 index 000000000000..e8bac4625f71 --- /dev/null +++ b/cargo-miri/src/arg.rs @@ -0,0 +1,134 @@ +//! Utilities for dealing with argument flags + +use std::borrow::Cow; +use std::env; + +/// Determines whether a `--flag` is present. +pub fn has_arg_flag(name: &str) -> bool { + num_arg_flag(name) > 0 +} + +/// Determines how many times a `--flag` is present. +pub fn num_arg_flag(name: &str) -> usize { + env::args().take_while(|val| val != "--").filter(|val| val == name).count() +} + +/// Yields all values of command line flag `name` as `Ok(arg)`, and all other arguments except +/// the flag as `Err(arg)`. (The flag `name` itself is not yielded at all, only its values are.) +pub struct ArgSplitFlagValue<'a, I> { + args: Option, + name: &'a str, +} + +impl<'a, I: Iterator> ArgSplitFlagValue<'a, I> { + fn new(args: I, name: &'a str) -> Self { + Self { args: Some(args), name } + } +} + +impl<'s, I: Iterator>> Iterator for ArgSplitFlagValue<'_, I> { + // If the original iterator was all `Owned`, then we will only ever yield `Owned` + // (so `into_owned()` is cheap). + type Item = Result, Cow<'s, str>>; + + fn next(&mut self) -> Option { + let Some(args) = self.args.as_mut() else { + // We already canceled this iterator. + return None; + }; + let arg = args.next()?; + if arg == "--" { + // Stop searching at `--`. + self.args = None; + return None; + } + // These branches cannot be merged if we want to avoid the allocation in the `Borrowed` branch. + match &arg { + Cow::Borrowed(arg) => + if let Some(suffix) = arg.strip_prefix(self.name) { + // Strip leading `name`. + if suffix.is_empty() { + // This argument is exactly `name`; the next one is the value. + return args.next().map(Ok); + } else if let Some(suffix) = suffix.strip_prefix('=') { + // This argument is `name=value`; get the value. + return Some(Ok(Cow::Borrowed(suffix))); + } + }, + Cow::Owned(arg) => + if let Some(suffix) = arg.strip_prefix(self.name) { + // Strip leading `name`. + if suffix.is_empty() { + // This argument is exactly `name`; the next one is the value. + return args.next().map(Ok); + } else if let Some(suffix) = suffix.strip_prefix('=') { + // This argument is `name=value`; get the value. We need to do an allocation + // here as a `String` cannot be subsliced (what would the lifetime be?). + return Some(Ok(Cow::Owned(suffix.to_owned()))); + } + }, + } + Some(Err(arg)) + } +} + +impl<'a, I: Iterator + 'a> ArgSplitFlagValue<'a, I> { + pub fn from_string_iter( + args: I, + name: &'a str, + ) -> impl Iterator> + 'a { + ArgSplitFlagValue::new(args.map(Cow::Owned), name).map(|x| { + match x { + Ok(Cow::Owned(s)) => Ok(s), + Err(Cow::Owned(s)) => Err(s), + _ => panic!("iterator converted owned to borrowed"), + } + }) + } +} + +impl<'x: 'a, 'a, I: Iterator + 'a> ArgSplitFlagValue<'a, I> { + pub fn from_str_iter( + args: I, + name: &'a str, + ) -> impl Iterator> + 'a { + ArgSplitFlagValue::new(args.map(Cow::Borrowed), name).map(|x| { + match x { + Ok(Cow::Borrowed(s)) => Ok(s), + Err(Cow::Borrowed(s)) => Err(s), + _ => panic!("iterator converted borrowed to owned"), + } + }) + } +} + +/// Yields all values of command line flag `name`. +pub struct ArgFlagValueIter; + +impl ArgFlagValueIter { + pub fn from_string_iter<'a, I: Iterator + 'a>( + args: I, + name: &'a str, + ) -> impl Iterator + 'a { + ArgSplitFlagValue::from_string_iter(args, name).filter_map(Result::ok) + } +} + +impl ArgFlagValueIter { + pub fn from_str_iter<'x: 'a, 'a, I: Iterator + 'a>( + args: I, + name: &'a str, + ) -> impl Iterator + 'a { + ArgSplitFlagValue::from_str_iter(args, name).filter_map(Result::ok) + } +} + +/// Gets the values of a `--flag`. +pub fn get_arg_flag_values(name: &str) -> impl Iterator + '_ { + ArgFlagValueIter::from_string_iter(env::args(), name) +} + +/// Gets the value of a `--flag`. +pub fn get_arg_flag_value(name: &str) -> Option { + get_arg_flag_values(name).next() +} diff --git a/cargo-miri/src/main.rs b/cargo-miri/src/main.rs index 9c07f90a4078..f809eecf96af 100644 --- a/cargo-miri/src/main.rs +++ b/cargo-miri/src/main.rs @@ -1,6 +1,7 @@ #![feature(let_else)] #![allow(clippy::useless_format, clippy::derive_partial_eq_without_eq)] +mod arg; mod phases; mod setup; mod util; diff --git a/cargo-miri/src/phases.rs b/cargo-miri/src/phases.rs index 38bc62436956..d0c0dafe071a 100644 --- a/cargo-miri/src/phases.rs +++ b/cargo-miri/src/phases.rs @@ -119,7 +119,7 @@ pub fn phase_cargo_miri(mut args: impl Iterator) { // Forward all arguments before `--` other than `--target-dir` and its value to Cargo. // (We want to *change* the target-dir value, so we must not forward it.) let mut target_dir = None; - for arg in ArgSplitFlagValue::new(&mut args, "--target-dir") { + for arg in ArgSplitFlagValue::from_string_iter(&mut args, "--target-dir") { match arg { Ok(value) => { if target_dir.is_some() { @@ -310,7 +310,8 @@ pub fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { let mut cmd = miri(); // Ensure --emit argument for a check-only build is present. - if let Some(val) = ArgFlagValueIter::new(env.args.clone().into_iter(), "--emit").next() + if let Some(val) = + ArgFlagValueIter::from_str_iter(env.args.iter().map(|s| s as &str), "--emit").next() { // For `no_run` tests, rustdoc passes a `--emit` flag; make sure it has the right shape. assert_eq!(val, "metadata"); diff --git a/cargo-miri/src/util.rs b/cargo-miri/src/util.rs index 27e312a4662a..04cfd2077bb7 100644 --- a/cargo-miri/src/util.rs +++ b/cargo-miri/src/util.rs @@ -4,7 +4,6 @@ use std::ffi::OsString; use std::fmt::Write as _; use std::fs::{self, File}; use std::io::{self, BufWriter, Read, Write}; -use std::iter::TakeWhile; use std::ops::Not; use std::path::{Path, PathBuf}; use std::process::Command; @@ -13,6 +12,8 @@ use cargo_metadata::{Metadata, MetadataCommand}; use rustc_version::VersionMeta; use serde::{Deserialize, Serialize}; +pub use crate::arg::*; + /// The information to run a crate with the given environment. #[derive(Clone, Serialize, Deserialize)] pub struct CrateRunEnv { @@ -74,83 +75,6 @@ pub fn show_error(msg: String) -> ! { std::process::exit(1) } -/// Determines whether a `--flag` is present. -pub fn has_arg_flag(name: &str) -> bool { - num_arg_flag(name) > 0 -} - -/// Determines how many times a `--flag` is present. -pub fn num_arg_flag(name: &str) -> usize { - env::args().take_while(|val| val != "--").filter(|val| val == name).count() -} - -/// Yields all values of command line flag `name` as `Ok(arg)`, and all other arguments except -/// the flag as `Err(arg)`. (The flag `name` itself is not yielded at all, only its values are.) -pub struct ArgSplitFlagValue<'a, I> { - args: TakeWhile bool>, - name: &'a str, -} - -impl<'a, I: Iterator> ArgSplitFlagValue<'a, I> { - pub fn new(args: I, name: &'a str) -> Self { - Self { - // Stop searching at `--`. - args: args.take_while(|val| val != "--"), - name, - } - } -} - -impl> Iterator for ArgSplitFlagValue<'_, I> { - type Item = Result; - - fn next(&mut self) -> Option { - let arg = self.args.next()?; - if let Some(suffix) = arg.strip_prefix(self.name) { - // Strip leading `name`. - if suffix.is_empty() { - // This argument is exactly `name`; the next one is the value. - return self.args.next().map(Ok); - } else if let Some(suffix) = suffix.strip_prefix('=') { - // This argument is `name=value`; get the value. - return Some(Ok(suffix.to_owned())); - } - } - Some(Err(arg)) - } -} - -/// Yields all values of command line flag `name`. -pub struct ArgFlagValueIter<'a, I>(ArgSplitFlagValue<'a, I>); - -impl<'a, I: Iterator> ArgFlagValueIter<'a, I> { - pub fn new(args: I, name: &'a str) -> Self { - Self(ArgSplitFlagValue::new(args, name)) - } -} - -impl> Iterator for ArgFlagValueIter<'_, I> { - type Item = String; - - fn next(&mut self) -> Option { - loop { - if let Ok(value) = self.0.next()? { - return Some(value); - } - } - } -} - -/// Gets the values of a `--flag`. -pub fn get_arg_flag_values<'a>(name: &'a str) -> impl Iterator + 'a { - ArgFlagValueIter::new(env::args(), name) -} - -/// Gets the value of a `--flag`. -pub fn get_arg_flag_value(name: &str) -> Option { - get_arg_flag_values(name).next() -} - /// Escapes `s` in a way that is suitable for using it as a string literal in TOML syntax. pub fn escape_for_toml(s: &str) -> String { // We want to surround this string in quotes `"`. So we first escape all quotes, From 04744a2935ba5c3e01af396ff91e24afba212acb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 22:45:25 -0400 Subject: [PATCH 3672/5092] fix CI benchmark checks --- ci.sh | 4 ++-- miri | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ci.sh b/ci.sh index 67cbed4f826d..a29fc3deca58 100755 --- a/ci.sh +++ b/ci.sh @@ -54,8 +54,8 @@ function run_tests { unset RUSTC MIRI rm -rf .cargo - # Ensure that our benchmarks all work, on the host at least. - if [ -z "${MIRI_TEST_TARGET+exists}" ]; then + # Ensure that our benchmarks all work, but only on Linux hosts. + if [ -z "${MIRI_TEST_TARGET+exists}" ] && [ "$HOST_TARGET" = x86_64-unknown-linux-gnu ] ; then for BENCH in $(ls "bench-cargo-miri"); do cargo miri run --manifest-path bench-cargo-miri/$BENCH/Cargo.toml done diff --git a/miri b/miri index 956b8cca75b8..0295fc3ab3ac 100755 --- a/miri +++ b/miri @@ -90,13 +90,13 @@ bench) # Make sure we have an up-to-date Miri installed "$0" install # Run the requested benchmarks - if [ -z "$@" ]; then + if [ -z "${1+exists}" ]; then BENCHES=( $(ls "$MIRIDIR/bench-cargo-miri" ) ) else BENCHES=("$@") fi for BENCH in "${BENCHES[@]}"; do - hyperfine -w 1 -m 5 --shell=none "cargo +$TOOLCHAIN miri run --manifest-path bench-cargo-miri/$BENCH/Cargo.toml" + hyperfine -w 1 -m 5 --shell=none "cargo +$TOOLCHAIN miri run --manifest-path $MIRIDIR/bench-cargo-miri/$BENCH/Cargo.toml" done exit 0 ;; From 70255029cf49928862c5b5603e731668ade5fa85 Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Sun, 7 Aug 2022 17:09:36 +0530 Subject: [PATCH 3673/5092] clippy: make generated code nice to read Feel free to close if this is too minor. --- crates/syntax/src/tests/sourcegen_ast.rs | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/crates/syntax/src/tests/sourcegen_ast.rs b/crates/syntax/src/tests/sourcegen_ast.rs index 6d2766225103..daad939f82e0 100644 --- a/crates/syntax/src/tests/sourcegen_ast.rs +++ b/crates/syntax/src/tests/sourcegen_ast.rs @@ -410,24 +410,17 @@ fn generate_syntax_kinds(grammar: KindsSrc<'_>) -> String { impl SyntaxKind { pub fn is_keyword(self) -> bool { - match self { - #(#all_keywords)|* => true, - _ => false, - } + matches!(self, #(#all_keywords)|*) } pub fn is_punct(self) -> bool { - match self { - #(#punctuation)|* => true, - _ => false, - } + + matches!(self, #(#punctuation)|*) + } pub fn is_literal(self) -> bool { - match self { - #(#literals)|* => true, - _ => false, - } + matches!(self, #(#literals)|*) } pub fn from_keyword(ident: &str) -> Option { From a3fc4dbb04e9e9fd639ad5c0988af6c9c540b9a0 Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Sun, 7 Aug 2022 17:37:50 +0530 Subject: [PATCH 3674/5092] more matches! sites --- crates/syntax/src/tests/sourcegen_ast.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/crates/syntax/src/tests/sourcegen_ast.rs b/crates/syntax/src/tests/sourcegen_ast.rs index daad939f82e0..70b54843dbaa 100644 --- a/crates/syntax/src/tests/sourcegen_ast.rs +++ b/crates/syntax/src/tests/sourcegen_ast.rs @@ -169,10 +169,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String { quote! { impl AstNode for #name { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - #(#kinds)|* => true, - _ => false, - } + matches!(kind, #(#kinds)|*) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { @@ -253,10 +250,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String { } impl AstNode for #name { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - #(#kinds)|* => true, - _ => false, - } + matches!(kind, #(#kinds)|*) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| #name { syntax }) From bcab4be9383f5dc3d177ec585df85e2becf2512b Mon Sep 17 00:00:00 2001 From: Kartavya Vashishtha Date: Sun, 7 Aug 2022 17:38:20 +0530 Subject: [PATCH 3675/5092] regenerate files with new syntax --- crates/parser/src/syntax_kind/generated.rs | 130 +++++-- crates/syntax/src/ast/generated/nodes.rs | 410 ++++++++++++--------- 2 files changed, 345 insertions(+), 195 deletions(-) diff --git a/crates/parser/src/syntax_kind/generated.rs b/crates/parser/src/syntax_kind/generated.rs index 628fa745e752..c84f45f1f8e4 100644 --- a/crates/parser/src/syntax_kind/generated.rs +++ b/crates/parser/src/syntax_kind/generated.rs @@ -262,33 +262,117 @@ pub enum SyntaxKind { use self::SyntaxKind::*; impl SyntaxKind { pub fn is_keyword(self) -> bool { - match self { - AS_KW | ASYNC_KW | AWAIT_KW | BOX_KW | BREAK_KW | CONST_KW | CONTINUE_KW | CRATE_KW - | DYN_KW | ELSE_KW | ENUM_KW | EXTERN_KW | FALSE_KW | FN_KW | FOR_KW | IF_KW - | IMPL_KW | IN_KW | LET_KW | LOOP_KW | MACRO_KW | MATCH_KW | MOD_KW | MOVE_KW - | MUT_KW | PUB_KW | REF_KW | RETURN_KW | SELF_KW | SELF_TYPE_KW | STATIC_KW - | STRUCT_KW | SUPER_KW | TRAIT_KW | TRUE_KW | TRY_KW | TYPE_KW | UNSAFE_KW | USE_KW - | WHERE_KW | WHILE_KW | YIELD_KW | AUTO_KW | DEFAULT_KW | EXISTENTIAL_KW | UNION_KW - | RAW_KW | MACRO_RULES_KW => true, - _ => false, - } + matches!( + self, + AS_KW + | ASYNC_KW + | AWAIT_KW + | BOX_KW + | BREAK_KW + | CONST_KW + | CONTINUE_KW + | CRATE_KW + | DYN_KW + | ELSE_KW + | ENUM_KW + | EXTERN_KW + | FALSE_KW + | FN_KW + | FOR_KW + | IF_KW + | IMPL_KW + | IN_KW + | LET_KW + | LOOP_KW + | MACRO_KW + | MATCH_KW + | MOD_KW + | MOVE_KW + | MUT_KW + | PUB_KW + | REF_KW + | RETURN_KW + | SELF_KW + | SELF_TYPE_KW + | STATIC_KW + | STRUCT_KW + | SUPER_KW + | TRAIT_KW + | TRUE_KW + | TRY_KW + | TYPE_KW + | UNSAFE_KW + | USE_KW + | WHERE_KW + | WHILE_KW + | YIELD_KW + | AUTO_KW + | DEFAULT_KW + | EXISTENTIAL_KW + | UNION_KW + | RAW_KW + | MACRO_RULES_KW + ) } pub fn is_punct(self) -> bool { - match self { - SEMICOLON | COMMA | L_PAREN | R_PAREN | L_CURLY | R_CURLY | L_BRACK | R_BRACK - | L_ANGLE | R_ANGLE | AT | POUND | TILDE | QUESTION | DOLLAR | AMP | PIPE | PLUS - | STAR | SLASH | CARET | PERCENT | UNDERSCORE | DOT | DOT2 | DOT3 | DOT2EQ | COLON - | COLON2 | EQ | EQ2 | FAT_ARROW | BANG | NEQ | MINUS | THIN_ARROW | LTEQ | GTEQ - | PLUSEQ | MINUSEQ | PIPEEQ | AMPEQ | CARETEQ | SLASHEQ | STAREQ | PERCENTEQ | AMP2 - | PIPE2 | SHL | SHR | SHLEQ | SHREQ => true, - _ => false, - } + matches!( + self, + SEMICOLON + | COMMA + | L_PAREN + | R_PAREN + | L_CURLY + | R_CURLY + | L_BRACK + | R_BRACK + | L_ANGLE + | R_ANGLE + | AT + | POUND + | TILDE + | QUESTION + | DOLLAR + | AMP + | PIPE + | PLUS + | STAR + | SLASH + | CARET + | PERCENT + | UNDERSCORE + | DOT + | DOT2 + | DOT3 + | DOT2EQ + | COLON + | COLON2 + | EQ + | EQ2 + | FAT_ARROW + | BANG + | NEQ + | MINUS + | THIN_ARROW + | LTEQ + | GTEQ + | PLUSEQ + | MINUSEQ + | PIPEEQ + | AMPEQ + | CARETEQ + | SLASHEQ + | STAREQ + | PERCENTEQ + | AMP2 + | PIPE2 + | SHL + | SHR + | SHLEQ + | SHREQ + ) } pub fn is_literal(self) -> bool { - match self { - INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE | STRING | BYTE_STRING => true, - _ => false, - } + matches!(self, INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE | STRING | BYTE_STRING) } pub fn from_keyword(ident: &str) -> Option { let kw = match ident { diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index 63309a155219..8c4825ad69eb 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs @@ -3169,10 +3169,7 @@ impl From for GenericArg { } impl AstNode for GenericArg { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - TYPE_ARG | ASSOC_TYPE_ARG | LIFETIME_ARG | CONST_ARG => true, - _ => false, - } + matches!(kind, TYPE_ARG | ASSOC_TYPE_ARG | LIFETIME_ARG | CONST_ARG) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { @@ -3237,12 +3234,23 @@ impl From for Type { } impl AstNode for Type { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - ARRAY_TYPE | DYN_TRAIT_TYPE | FN_PTR_TYPE | FOR_TYPE | IMPL_TRAIT_TYPE | INFER_TYPE - | MACRO_TYPE | NEVER_TYPE | PAREN_TYPE | PATH_TYPE | PTR_TYPE | REF_TYPE - | SLICE_TYPE | TUPLE_TYPE => true, - _ => false, - } + matches!( + kind, + ARRAY_TYPE + | DYN_TRAIT_TYPE + | FN_PTR_TYPE + | FOR_TYPE + | IMPL_TRAIT_TYPE + | INFER_TYPE + | MACRO_TYPE + | NEVER_TYPE + | PAREN_TYPE + | PATH_TYPE + | PTR_TYPE + | REF_TYPE + | SLICE_TYPE + | TUPLE_TYPE + ) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { @@ -3384,15 +3392,42 @@ impl From for Expr { } impl AstNode for Expr { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - ARRAY_EXPR | AWAIT_EXPR | BIN_EXPR | BLOCK_EXPR | BOX_EXPR | BREAK_EXPR | CALL_EXPR - | CAST_EXPR | CLOSURE_EXPR | CONTINUE_EXPR | FIELD_EXPR | FOR_EXPR | IF_EXPR - | INDEX_EXPR | LITERAL | LOOP_EXPR | MACRO_EXPR | MACRO_STMTS | MATCH_EXPR - | METHOD_CALL_EXPR | PAREN_EXPR | PATH_EXPR | PREFIX_EXPR | RANGE_EXPR - | RECORD_EXPR | REF_EXPR | RETURN_EXPR | TRY_EXPR | TUPLE_EXPR | WHILE_EXPR - | YIELD_EXPR | LET_EXPR | UNDERSCORE_EXPR => true, - _ => false, - } + matches!( + kind, + ARRAY_EXPR + | AWAIT_EXPR + | BIN_EXPR + | BLOCK_EXPR + | BOX_EXPR + | BREAK_EXPR + | CALL_EXPR + | CAST_EXPR + | CLOSURE_EXPR + | CONTINUE_EXPR + | FIELD_EXPR + | FOR_EXPR + | IF_EXPR + | INDEX_EXPR + | LITERAL + | LOOP_EXPR + | MACRO_EXPR + | MACRO_STMTS + | MATCH_EXPR + | METHOD_CALL_EXPR + | PAREN_EXPR + | PATH_EXPR + | PREFIX_EXPR + | RANGE_EXPR + | RECORD_EXPR + | REF_EXPR + | RETURN_EXPR + | TRY_EXPR + | TUPLE_EXPR + | WHILE_EXPR + | YIELD_EXPR + | LET_EXPR + | UNDERSCORE_EXPR + ) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { @@ -3521,11 +3556,25 @@ impl From for Item { } impl AstNode for Item { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - CONST | ENUM | EXTERN_BLOCK | EXTERN_CRATE | FN | IMPL | MACRO_CALL | MACRO_RULES - | MACRO_DEF | MODULE | STATIC | STRUCT | TRAIT | TYPE_ALIAS | UNION | USE => true, - _ => false, - } + matches!( + kind, + CONST + | ENUM + | EXTERN_BLOCK + | EXTERN_CRATE + | FN + | IMPL + | MACRO_CALL + | MACRO_RULES + | MACRO_DEF + | MODULE + | STATIC + | STRUCT + | TRAIT + | TYPE_ALIAS + | UNION + | USE + ) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { @@ -3629,12 +3678,25 @@ impl From for Pat { } impl AstNode for Pat { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - IDENT_PAT | BOX_PAT | REST_PAT | LITERAL_PAT | MACRO_PAT | OR_PAT | PAREN_PAT - | PATH_PAT | WILDCARD_PAT | RANGE_PAT | RECORD_PAT | REF_PAT | SLICE_PAT - | TUPLE_PAT | TUPLE_STRUCT_PAT | CONST_BLOCK_PAT => true, - _ => false, - } + matches!( + kind, + IDENT_PAT + | BOX_PAT + | REST_PAT + | LITERAL_PAT + | MACRO_PAT + | OR_PAT + | PAREN_PAT + | PATH_PAT + | WILDCARD_PAT + | RANGE_PAT + | RECORD_PAT + | REF_PAT + | SLICE_PAT + | TUPLE_PAT + | TUPLE_STRUCT_PAT + | CONST_BLOCK_PAT + ) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { @@ -3686,12 +3748,7 @@ impl From for FieldList { fn from(node: TupleFieldList) -> FieldList { FieldList::TupleFieldList(node) } } impl AstNode for FieldList { - fn can_cast(kind: SyntaxKind) -> bool { - match kind { - RECORD_FIELD_LIST | TUPLE_FIELD_LIST => true, - _ => false, - } - } + fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, RECORD_FIELD_LIST | TUPLE_FIELD_LIST) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { RECORD_FIELD_LIST => FieldList::RecordFieldList(RecordFieldList { syntax }), @@ -3717,12 +3774,7 @@ impl From for Adt { fn from(node: Union) -> Adt { Adt::Union(node) } } impl AstNode for Adt { - fn can_cast(kind: SyntaxKind) -> bool { - match kind { - ENUM | STRUCT | UNION => true, - _ => false, - } - } + fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, ENUM | STRUCT | UNION) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { ENUM => Adt::Enum(Enum { syntax }), @@ -3753,12 +3805,7 @@ impl From for AssocItem { fn from(node: TypeAlias) -> AssocItem { AssocItem::TypeAlias(node) } } impl AstNode for AssocItem { - fn can_cast(kind: SyntaxKind) -> bool { - match kind { - CONST | FN | MACRO_CALL | TYPE_ALIAS => true, - _ => false, - } - } + fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, CONST | FN | MACRO_CALL | TYPE_ALIAS) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { CONST => AssocItem::Const(Const { syntax }), @@ -3791,12 +3838,7 @@ impl From for ExternItem { fn from(node: TypeAlias) -> ExternItem { ExternItem::TypeAlias(node) } } impl AstNode for ExternItem { - fn can_cast(kind: SyntaxKind) -> bool { - match kind { - FN | MACRO_CALL | STATIC | TYPE_ALIAS => true, - _ => false, - } - } + fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, FN | MACRO_CALL | STATIC | TYPE_ALIAS) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { FN => ExternItem::Fn(Fn { syntax }), @@ -3827,10 +3869,7 @@ impl From for GenericParam { } impl AstNode for GenericParam { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - CONST_PARAM | LIFETIME_PARAM | TYPE_PARAM => true, - _ => false, - } + matches!(kind, CONST_PARAM | LIFETIME_PARAM | TYPE_PARAM) } fn cast(syntax: SyntaxNode) -> Option { let res = match syntax.kind() { @@ -3856,12 +3895,7 @@ impl AnyHasArgList { } } impl AstNode for AnyHasArgList { - fn can_cast(kind: SyntaxKind) -> bool { - match kind { - CALL_EXPR | METHOD_CALL_EXPR => true, - _ => false, - } - } + fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, CALL_EXPR | METHOD_CALL_EXPR) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| AnyHasArgList { syntax }) } @@ -3875,76 +3909,76 @@ impl AnyHasAttrs { } impl AstNode for AnyHasAttrs { fn can_cast(kind: SyntaxKind) -> bool { - match kind { + matches!( + kind, MACRO_CALL - | SOURCE_FILE - | CONST - | ENUM - | EXTERN_BLOCK - | EXTERN_CRATE - | FN - | IMPL - | MACRO_RULES - | MACRO_DEF - | MODULE - | STATIC - | STRUCT - | TRAIT - | TYPE_ALIAS - | UNION - | USE - | ITEM_LIST - | BLOCK_EXPR - | SELF_PARAM - | PARAM - | RECORD_FIELD - | TUPLE_FIELD - | VARIANT - | ASSOC_ITEM_LIST - | EXTERN_ITEM_LIST - | CONST_PARAM - | LIFETIME_PARAM - | TYPE_PARAM - | LET_STMT - | ARRAY_EXPR - | AWAIT_EXPR - | BIN_EXPR - | BOX_EXPR - | BREAK_EXPR - | CALL_EXPR - | CAST_EXPR - | CLOSURE_EXPR - | CONTINUE_EXPR - | FIELD_EXPR - | FOR_EXPR - | IF_EXPR - | INDEX_EXPR - | LITERAL - | LOOP_EXPR - | MATCH_EXPR - | METHOD_CALL_EXPR - | PAREN_EXPR - | PATH_EXPR - | PREFIX_EXPR - | RANGE_EXPR - | REF_EXPR - | RETURN_EXPR - | TRY_EXPR - | TUPLE_EXPR - | WHILE_EXPR - | YIELD_EXPR - | LET_EXPR - | UNDERSCORE_EXPR - | STMT_LIST - | RECORD_EXPR_FIELD_LIST - | RECORD_EXPR_FIELD - | MATCH_ARM_LIST - | MATCH_ARM - | IDENT_PAT - | REST_PAT - | RECORD_PAT_FIELD => true, - _ => false, - } + | SOURCE_FILE + | CONST + | ENUM + | EXTERN_BLOCK + | EXTERN_CRATE + | FN + | IMPL + | MACRO_RULES + | MACRO_DEF + | MODULE + | STATIC + | STRUCT + | TRAIT + | TYPE_ALIAS + | UNION + | USE + | ITEM_LIST + | BLOCK_EXPR + | SELF_PARAM + | PARAM + | RECORD_FIELD + | TUPLE_FIELD + | VARIANT + | ASSOC_ITEM_LIST + | EXTERN_ITEM_LIST + | CONST_PARAM + | LIFETIME_PARAM + | TYPE_PARAM + | LET_STMT + | ARRAY_EXPR + | AWAIT_EXPR + | BIN_EXPR + | BOX_EXPR + | BREAK_EXPR + | CALL_EXPR + | CAST_EXPR + | CLOSURE_EXPR + | CONTINUE_EXPR + | FIELD_EXPR + | FOR_EXPR + | IF_EXPR + | INDEX_EXPR + | LITERAL + | LOOP_EXPR + | MATCH_EXPR + | METHOD_CALL_EXPR + | PAREN_EXPR + | PATH_EXPR + | PREFIX_EXPR + | RANGE_EXPR + | REF_EXPR + | RETURN_EXPR + | TRY_EXPR + | TUPLE_EXPR + | WHILE_EXPR + | YIELD_EXPR + | LET_EXPR + | UNDERSCORE_EXPR + | STMT_LIST + | RECORD_EXPR_FIELD_LIST + | RECORD_EXPR_FIELD + | MATCH_ARM_LIST + | MATCH_ARM + | IDENT_PAT + | REST_PAT + | RECORD_PAT_FIELD + ) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| AnyHasAttrs { syntax }) @@ -3959,12 +3993,29 @@ impl AnyHasDocComments { } impl AstNode for AnyHasDocComments { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - MACRO_CALL | SOURCE_FILE | CONST | ENUM | EXTERN_BLOCK | EXTERN_CRATE | FN | IMPL - | MACRO_RULES | MACRO_DEF | MODULE | STATIC | STRUCT | TRAIT | TYPE_ALIAS | UNION - | USE | RECORD_FIELD | TUPLE_FIELD | VARIANT => true, - _ => false, - } + matches!( + kind, + MACRO_CALL + | SOURCE_FILE + | CONST + | ENUM + | EXTERN_BLOCK + | EXTERN_CRATE + | FN + | IMPL + | MACRO_RULES + | MACRO_DEF + | MODULE + | STATIC + | STRUCT + | TRAIT + | TYPE_ALIAS + | UNION + | USE + | RECORD_FIELD + | TUPLE_FIELD + | VARIANT + ) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| AnyHasDocComments { syntax }) @@ -3979,10 +4030,7 @@ impl AnyHasGenericParams { } impl AstNode for AnyHasGenericParams { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - ENUM | FN | IMPL | STRUCT | TRAIT | TYPE_ALIAS | UNION => true, - _ => false, - } + matches!(kind, ENUM | FN | IMPL | STRUCT | TRAIT | TYPE_ALIAS | UNION) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| AnyHasGenericParams { syntax }) @@ -3996,12 +4044,7 @@ impl AnyHasLoopBody { } } impl AstNode for AnyHasLoopBody { - fn can_cast(kind: SyntaxKind) -> bool { - match kind { - FOR_EXPR | LOOP_EXPR | WHILE_EXPR => true, - _ => false, - } - } + fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, FOR_EXPR | LOOP_EXPR | WHILE_EXPR) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| AnyHasLoopBody { syntax }) } @@ -4014,12 +4057,7 @@ impl AnyHasModuleItem { } } impl AstNode for AnyHasModuleItem { - fn can_cast(kind: SyntaxKind) -> bool { - match kind { - MACRO_ITEMS | SOURCE_FILE | ITEM_LIST => true, - _ => false, - } - } + fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, MACRO_ITEMS | SOURCE_FILE | ITEM_LIST) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| AnyHasModuleItem { syntax }) } @@ -4033,12 +4071,27 @@ impl AnyHasName { } impl AstNode for AnyHasName { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - CONST | ENUM | FN | MACRO_RULES | MACRO_DEF | MODULE | STATIC | STRUCT | TRAIT - | TYPE_ALIAS | UNION | RENAME | SELF_PARAM | RECORD_FIELD | VARIANT | CONST_PARAM - | TYPE_PARAM | IDENT_PAT => true, - _ => false, - } + matches!( + kind, + CONST + | ENUM + | FN + | MACRO_RULES + | MACRO_DEF + | MODULE + | STATIC + | STRUCT + | TRAIT + | TYPE_ALIAS + | UNION + | RENAME + | SELF_PARAM + | RECORD_FIELD + | VARIANT + | CONST_PARAM + | TYPE_PARAM + | IDENT_PAT + ) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| AnyHasName { syntax }) @@ -4053,10 +4106,10 @@ impl AnyHasTypeBounds { } impl AstNode for AnyHasTypeBounds { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - ASSOC_TYPE_ARG | TRAIT | TYPE_ALIAS | LIFETIME_PARAM | TYPE_PARAM | WHERE_PRED => true, - _ => false, - } + matches!( + kind, + ASSOC_TYPE_ARG | TRAIT | TYPE_ALIAS | LIFETIME_PARAM | TYPE_PARAM | WHERE_PRED + ) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| AnyHasTypeBounds { syntax }) @@ -4071,13 +4124,26 @@ impl AnyHasVisibility { } impl AstNode for AnyHasVisibility { fn can_cast(kind: SyntaxKind) -> bool { - match kind { - CONST | ENUM | EXTERN_CRATE | FN | IMPL | MACRO_RULES | MACRO_DEF | MODULE | STATIC - | STRUCT | TRAIT | TYPE_ALIAS | UNION | USE | RECORD_FIELD | TUPLE_FIELD | VARIANT => { - true - } - _ => false, - } + matches!( + kind, + CONST + | ENUM + | EXTERN_CRATE + | FN + | IMPL + | MACRO_RULES + | MACRO_DEF + | MODULE + | STATIC + | STRUCT + | TRAIT + | TYPE_ALIAS + | UNION + | USE + | RECORD_FIELD + | TUPLE_FIELD + | VARIANT + ) } fn cast(syntax: SyntaxNode) -> Option { Self::can_cast(syntax.kind()).then(|| AnyHasVisibility { syntax }) From 366d11b2d8d1d5c51bc4a5f056debac77a01c071 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 7 Aug 2022 09:17:16 -0400 Subject: [PATCH 3676/5092] enable rustc lints (but not in cargo-miri and ui_test) --- cargo-miri/src/main.rs | 2 +- miri | 2 ++ ui_test/src/lib.rs | 7 ++++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/cargo-miri/src/main.rs b/cargo-miri/src/main.rs index f809eecf96af..7b16af6f0c64 100644 --- a/cargo-miri/src/main.rs +++ b/cargo-miri/src/main.rs @@ -1,5 +1,5 @@ #![feature(let_else)] -#![allow(clippy::useless_format, clippy::derive_partial_eq_without_eq)] +#![allow(clippy::useless_format, clippy::derive_partial_eq_without_eq, rustc::internal)] mod arg; mod phases; diff --git a/miri b/miri index 0295fc3ab3ac..5893d0ca05f2 100755 --- a/miri +++ b/miri @@ -124,6 +124,8 @@ fi if [ -z "$CARGO_PROFILE_DEV_OPT_LEVEL" ]; then export CARGO_PROFILE_DEV_OPT_LEVEL=2 fi +# Enable rustc-specific lints +export RUSTFLAGS="-Zunstable-options -Wrustc::internal $RUSTFLAGS" # We set the rpath so that Miri finds the private rustc libraries it needs. export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR $RUSTFLAGS" diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 9206c0f3d8e5..871574c4936d 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -1,4 +1,9 @@ -#![allow(clippy::enum_variant_names, clippy::useless_format, clippy::too_many_arguments)] +#![allow( + clippy::enum_variant_names, + clippy::useless_format, + clippy::too_many_arguments, + rustc::internal +)] use std::collections::VecDeque; use std::ffi::OsString; From b36b5e38b73e8253e15ed94a7194e335572f4e57 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 7 Aug 2022 09:46:52 -0400 Subject: [PATCH 3677/5092] fix rustc lints in Miri --- miri | 2 +- src/bin/miri.rs | 5 +++-- src/eval.rs | 14 +++++++------- src/lib.rs | 4 +++- src/machine.rs | 9 ++++----- src/shims/intrinsics/mod.rs | 7 +++++-- src/stacked_borrows/mod.rs | 12 ++++++------ src/sync.rs | 7 ++++--- 8 files changed, 33 insertions(+), 27 deletions(-) diff --git a/miri b/miri index 5893d0ca05f2..5088a9ceffdb 100755 --- a/miri +++ b/miri @@ -124,7 +124,7 @@ fi if [ -z "$CARGO_PROFILE_DEV_OPT_LEVEL" ]; then export CARGO_PROFILE_DEV_OPT_LEVEL=2 fi -# Enable rustc-specific lints +# Enable rustc-specific lints (ignored without `-Zunstable-options`). export RUSTFLAGS="-Zunstable-options -Wrustc::internal $RUSTFLAGS" # We set the rpath so that Miri finds the private rustc libraries it needs. export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR $RUSTFLAGS" diff --git a/src/bin/miri.rs b/src/bin/miri.rs index dcccdecc6cf1..b5a45d162f21 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -101,13 +101,14 @@ struct MiriBeRustCompilerCalls { } impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { + #[allow(rustc::potential_query_instability)] // rustc_codegen_ssa (where this code is copied from) also allows this lint fn config(&mut self, config: &mut Config) { if config.opts.prints.is_empty() && self.target_crate { // Queries overriden here affect the data stored in `rmeta` files of dependencies, // which will be used later in non-`MIRI_BE_RUSTC` mode. config.override_queries = Some(|_, local_providers, _| { - // `exported_symbols()` provided by rustc always returns empty result if - // `tcx.sess.opts.output_types.should_codegen()` is false. + // `exported_symbols` and `reachable_non_generics` provided by rustc always returns + // an empty result if `tcx.sess.opts.output_types.should_codegen()` is false. local_providers.exported_symbols = |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); tcx.arena.alloc_from_iter( diff --git a/src/eval.rs b/src/eval.rs index 981776e3eebd..12e895852d22 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -1,6 +1,5 @@ //! Main evaluator loop and setting up the initial stack frame. -use std::collections::HashSet; use std::ffi::{OsStr, OsString}; use std::iter; use std::panic::{self, AssertUnwindSafe}; @@ -8,6 +7,7 @@ use std::thread; use log::info; +use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::DefId; use rustc_middle::ty::{ self, @@ -96,11 +96,11 @@ pub struct MiriConfig { /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`). pub seed: Option, /// The stacked borrows pointer ids to report about - pub tracked_pointer_tags: HashSet, + pub tracked_pointer_tags: FxHashSet, /// The stacked borrows call IDs to report about - pub tracked_call_ids: HashSet, + pub tracked_call_ids: FxHashSet, /// The allocation ids to report about. - pub tracked_alloc_ids: HashSet, + pub tracked_alloc_ids: FxHashSet, /// Determine if data race detection should be enabled pub data_race_detector: bool, /// Determine if weak memory emulation should be enabled. Requires data race detection to be enabled @@ -144,9 +144,9 @@ impl Default for MiriConfig { forwarded_env_vars: vec![], args: vec![], seed: None, - tracked_pointer_tags: HashSet::default(), - tracked_call_ids: HashSet::default(), - tracked_alloc_ids: HashSet::default(), + tracked_pointer_tags: FxHashSet::default(), + tracked_call_ids: FxHashSet::default(), + tracked_alloc_ids: FxHashSet::default(), data_race_detector: true, weak_memory_emulation: true, track_outdated_loads: false, diff --git a/src/lib.rs b/src/lib.rs index 8b1c18a499f6..94958b2ff5fb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,7 +23,9 @@ clippy::derive_partial_eq_without_eq, clippy::derive_hash_xor_eq, clippy::too_many_arguments, - clippy::type_complexity + clippy::type_complexity, + // We are not implementing queries here so it's fine + rustc::potential_query_instability )] #![warn( rust_2018_idioms, diff --git a/src/machine.rs b/src/machine.rs index 2c9bfe803ad2..14df64d8aa30 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -3,7 +3,6 @@ use std::borrow::Cow; use std::cell::RefCell; -use std::collections::HashSet; use std::fmt; use std::time::Instant; @@ -11,7 +10,7 @@ use rand::rngs::StdRng; use rand::SeedableRng; use rustc_ast::ast::Mutability; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; #[allow(unused)] use rustc_data_structures::static_assert_size; use rustc_middle::{ @@ -19,7 +18,7 @@ use rustc_middle::{ ty::{ self, layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout}, - Instance, TyCtxt, TypeAndMut, + Instance, Ty, TyCtxt, TypeAndMut, }, }; use rustc_span::def_id::{CrateNum, DefId}; @@ -335,7 +334,7 @@ pub struct Evaluator<'mir, 'tcx> { /// The allocation IDs to report when they are being allocated /// (helps for debugging memory leaks and use after free bugs). - tracked_alloc_ids: HashSet, + tracked_alloc_ids: FxHashSet, /// Controls whether alignment of memory accesses is being checked. pub(crate) check_alignment: AlignmentCheck, @@ -613,7 +612,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { bin_op: mir::BinOp, left: &ImmTy<'tcx, Provenance>, right: &ImmTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, (Scalar, bool, ty::Ty<'tcx>)> { + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { ecx.binary_ptr_op(bin_op, left, right) } diff --git a/src/shims/intrinsics/mod.rs b/src/shims/intrinsics/mod.rs index 08a6e0fcc0ee..6b311707c35d 100644 --- a/src/shims/intrinsics/mod.rs +++ b/src/shims/intrinsics/mod.rs @@ -7,7 +7,10 @@ use log::trace; use rustc_apfloat::{Float, Round}; use rustc_middle::ty::layout::{IntegerExt, LayoutOf}; -use rustc_middle::{mir, ty, ty::FloatTy}; +use rustc_middle::{ + mir, + ty::{self, FloatTy, Ty}, +}; use rustc_target::abi::Integer; use crate::*; @@ -377,7 +380,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn float_to_int_unchecked( &self, f: F, - dest_ty: ty::Ty<'tcx>, + dest_ty: Ty<'tcx>, ) -> InterpResult<'tcx, Scalar> where F: Float + Into>, diff --git a/src/stacked_borrows/mod.rs b/src/stacked_borrows/mod.rs index 624b32dfd495..e0cc3e81cf0b 100644 --- a/src/stacked_borrows/mod.rs +++ b/src/stacked_borrows/mod.rs @@ -13,11 +13,11 @@ use rustc_middle::mir::RetagKind; use rustc_middle::ty::{ self, layout::{HasParamEnv, LayoutOf}, + Ty, }; use rustc_span::DUMMY_SP; use rustc_target::abi::Size; use smallvec::SmallVec; -use std::collections::HashSet; use crate::*; @@ -100,9 +100,9 @@ pub struct GlobalStateInner { /// `GlobalStateInner::end_call`. See `Stack::item_popped` for more details. protected_tags: FxHashSet, /// The pointer ids to trace - tracked_pointer_tags: HashSet, + tracked_pointer_tags: FxHashSet, /// The call ids to trace - tracked_call_ids: HashSet, + tracked_call_ids: FxHashSet, /// Whether to recurse into datatypes when searching for pointers to retag. retag_fields: bool, } @@ -154,8 +154,8 @@ impl fmt::Display for RefKind { /// Utilities for initialization and ID generation impl GlobalStateInner { pub fn new( - tracked_pointer_tags: HashSet, - tracked_call_ids: HashSet, + tracked_pointer_tags: FxHashSet, + tracked_call_ids: FxHashSet, retag_fields: bool, ) -> Self { GlobalStateInner { @@ -1013,7 +1013,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Determine mutability and whether to add a protector. // Cannot use `builtin_deref` because that reports *immutable* for `Box`, // making it useless. - fn qualify(ty: ty::Ty<'_>, kind: RetagKind) -> Option<(RefKind, bool)> { + fn qualify(ty: Ty<'_>, kind: RetagKind) -> Option<(RefKind, bool)> { match ty.kind() { // References are simple. ty::Ref(_, _, Mutability::Mut) => diff --git a/src/sync.rs b/src/sync.rs index 5571bbd8f2dc..de7d528d3346 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -1,9 +1,10 @@ -use std::collections::{hash_map::Entry, HashMap, VecDeque}; +use std::collections::{hash_map::Entry, VecDeque}; use std::num::NonZeroU32; use std::ops::Not; use log::trace; +use rustc_data_structures::fx::FxHashMap; use rustc_index::vec::{Idx, IndexVec}; use crate::*; @@ -77,7 +78,7 @@ struct RwLock { writer: Option, /// The readers that currently own the lock and how many times they acquired /// the lock. - readers: HashMap, + readers: FxHashMap, /// The queue of writer threads waiting for this lock. writer_queue: VecDeque, /// The queue of reader threads waiting for this lock. @@ -153,7 +154,7 @@ pub(super) struct SynchronizationState { mutexes: IndexVec, rwlocks: IndexVec, condvars: IndexVec, - futexes: HashMap, + futexes: FxHashMap, } // Private extension trait for local helper methods From 0f1ce435020f111982351d70d8bfe9e7ae2a6bb8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 7 Aug 2022 11:53:25 -0400 Subject: [PATCH 3678/5092] clarifying comments for target-dir handling --- cargo-miri/src/phases.rs | 1 + cargo-miri/src/util.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/cargo-miri/src/phases.rs b/cargo-miri/src/phases.rs index d0c0dafe071a..8635661323d1 100644 --- a/cargo-miri/src/phases.rs +++ b/cargo-miri/src/phases.rs @@ -133,6 +133,7 @@ pub fn phase_cargo_miri(mut args: impl Iterator) { } } // Detect the target directory if it's not specified via `--target-dir`. + // (`cargo metadata` does not support `--target-dir`, that's why we have to handle this ourselves.) let target_dir = target_dir.get_or_insert_with(|| metadata.target_directory.clone()); // Set `--target-dir` to `miri` inside the original target directory. target_dir.push("miri"); diff --git a/cargo-miri/src/util.rs b/cargo-miri/src/util.rs index 04cfd2077bb7..b5401d71671d 100644 --- a/cargo-miri/src/util.rs +++ b/cargo-miri/src/util.rs @@ -237,6 +237,8 @@ fn cargo_extra_flags() -> Vec { flags.push(manifest); } + // Forwarding `--target-dir` would make sense, but `cargo metadata` does not support that flag. + flags } From 99e77d07b2856fccd083d5810a9756e07cc4c524 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 7 Aug 2022 17:47:24 -0400 Subject: [PATCH 3679/5092] Allow type erasure using `*const/mut int_type` in `transmute_undefined_repr` --- .../src/transmute/transmute_undefined_repr.rs | 397 ++++++++---------- tests/ui/transmute_undefined_repr.rs | 4 + tests/ui/transmute_undefined_repr.stderr | 24 +- 3 files changed, 195 insertions(+), 230 deletions(-) diff --git a/clippy_lints/src/transmute/transmute_undefined_repr.rs b/clippy_lints/src/transmute/transmute_undefined_repr.rs index bf1cfb859bc3..b6d7d9f5b42e 100644 --- a/clippy_lints/src/transmute/transmute_undefined_repr.rs +++ b/clippy_lints/src/transmute/transmute_undefined_repr.rs @@ -5,9 +5,9 @@ use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::subst::{Subst, SubstsRef}; use rustc_middle::ty::{self, IntTy, Ty, TypeAndMut, UintTy}; -use rustc_span::Span; +use rustc_span::DUMMY_SP; -#[allow(clippy::too_many_lines)] +#[expect(clippy::too_many_lines)] pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, @@ -18,116 +18,89 @@ pub(super) fn check<'tcx>( let mut to_ty = cx.tcx.erase_regions(to_ty_orig); while from_ty != to_ty { - match reduce_refs(cx, e.span, from_ty, to_ty) { - ReducedTys::FromFatPtr { - unsized_ty, - to_ty: to_sub_ty, - } => match reduce_ty(cx, to_sub_ty) { - ReducedTy::TypeErasure => break, - ReducedTy::UnorderedFields(ty) if is_size_pair(ty) => break, - ReducedTy::Ref(to_sub_ty) => { - from_ty = unsized_ty; - to_ty = to_sub_ty; - continue; - }, - _ => { - span_lint_and_then( - cx, - TRANSMUTE_UNDEFINED_REPR, - e.span, - &format!("transmute from `{}` which has an undefined layout", from_ty_orig), - |diag| { - if from_ty_orig.peel_refs() != unsized_ty { - diag.note(&format!("the contained type `&{}` has an undefined layout", unsized_ty)); - } - }, - ); - return true; - }, + let reduced_tys = reduce_refs(cx, from_ty, to_ty); + match (reduce_ty(cx, reduced_tys.from_ty), reduce_ty(cx, reduced_tys.to_ty)) { + // Various forms of type erasure. + (ReducedTy::TypeErasure { raw_ptr_only: false }, _) + | (_, ReducedTy::TypeErasure { raw_ptr_only: false }) => return false, + (ReducedTy::TypeErasure { .. }, _) if reduced_tys.from_raw_ptr => return false, + (_, ReducedTy::TypeErasure { .. }) if reduced_tys.to_raw_ptr => return false, + + // `Repr(C)` <-> unordered type. + // If the first field of the `Repr(C)` type matches then the transmute is ok + (ReducedTy::OrderedFields(_, Some(from_sub_ty)), ReducedTy::UnorderedFields(to_sub_ty)) + | (ReducedTy::UnorderedFields(from_sub_ty), ReducedTy::OrderedFields(_, Some(to_sub_ty))) => { + from_ty = from_sub_ty; + to_ty = to_sub_ty; + continue; }, - ReducedTys::ToFatPtr { - unsized_ty, - from_ty: from_sub_ty, - } => match reduce_ty(cx, from_sub_ty) { - ReducedTy::TypeErasure => break, - ReducedTy::UnorderedFields(ty) if is_size_pair(ty) => break, - ReducedTy::Ref(from_sub_ty) => { - from_ty = from_sub_ty; - to_ty = unsized_ty; - continue; - }, - _ => { - span_lint_and_then( - cx, - TRANSMUTE_UNDEFINED_REPR, - e.span, - &format!("transmute to `{}` which has an undefined layout", to_ty_orig), - |diag| { - if to_ty_orig.peel_refs() != unsized_ty { - diag.note(&format!("the contained type `&{}` has an undefined layout", unsized_ty)); - } - }, - ); - return true; - }, + (ReducedTy::OrderedFields(_, Some(from_sub_ty)), ReducedTy::Other(to_sub_ty)) if reduced_tys.to_fat_ptr => { + from_ty = from_sub_ty; + to_ty = to_sub_ty; + continue; }, - ReducedTys::ToPtr { - from_ty: from_sub_ty, - to_ty: to_sub_ty, - } => match reduce_ty(cx, from_sub_ty) { - ReducedTy::UnorderedFields(from_ty) => { - span_lint_and_then( - cx, - TRANSMUTE_UNDEFINED_REPR, - e.span, - &format!("transmute from `{}` which has an undefined layout", from_ty_orig), - |diag| { - if from_ty_orig.peel_refs() != from_ty { - diag.note(&format!("the contained type `{}` has an undefined layout", from_ty)); - } - }, - ); - return true; - }, - ReducedTy::Ref(from_sub_ty) => { - from_ty = from_sub_ty; - to_ty = to_sub_ty; - continue; - }, - _ => break, + (ReducedTy::Other(from_sub_ty), ReducedTy::OrderedFields(_, Some(to_sub_ty))) + if reduced_tys.from_fat_ptr => + { + from_ty = from_sub_ty; + to_ty = to_sub_ty; + continue; }, - ReducedTys::FromPtr { - from_ty: from_sub_ty, - to_ty: to_sub_ty, - } => match reduce_ty(cx, to_sub_ty) { - ReducedTy::UnorderedFields(to_ty) => { - span_lint_and_then( - cx, - TRANSMUTE_UNDEFINED_REPR, - e.span, - &format!("transmute to `{}` which has an undefined layout", to_ty_orig), - |diag| { - if to_ty_orig.peel_refs() != to_ty { - diag.note(&format!("the contained type `{}` has an undefined layout", to_ty)); - } - }, - ); - return true; - }, - ReducedTy::Ref(to_sub_ty) => { - from_ty = from_sub_ty; - to_ty = to_sub_ty; - continue; - }, - _ => break, + + // ptr <-> ptr + (ReducedTy::Other(from_sub_ty), ReducedTy::Other(to_sub_ty)) + if matches!(from_sub_ty.kind(), ty::Ref(..) | ty::RawPtr(_)) + && matches!(to_sub_ty.kind(), ty::Ref(..) | ty::RawPtr(_)) => + { + from_ty = from_sub_ty; + to_ty = to_sub_ty; + continue; }, - ReducedTys::Other { - from_ty: from_sub_ty, - to_ty: to_sub_ty, - } => match (reduce_ty(cx, from_sub_ty), reduce_ty(cx, to_sub_ty)) { - (ReducedTy::TypeErasure, _) | (_, ReducedTy::TypeErasure) => return false, - (ReducedTy::UnorderedFields(from_ty), ReducedTy::UnorderedFields(to_ty)) if from_ty != to_ty => { - let same_adt_did = if let (ty::Adt(from_def, from_subs), ty::Adt(to_def, to_subs)) + + // fat ptr <-> (*size, *size) + (ReducedTy::Other(_), ReducedTy::UnorderedFields(to_ty)) + if reduced_tys.from_fat_ptr && is_size_pair(to_ty) => + { + return false; + }, + (ReducedTy::UnorderedFields(from_ty), ReducedTy::Other(_)) + if reduced_tys.to_fat_ptr && is_size_pair(from_ty) => + { + return false; + }, + + // fat ptr -> some struct | some struct -> fat ptr + (ReducedTy::Other(_), _) if reduced_tys.from_fat_ptr => { + span_lint_and_then( + cx, + TRANSMUTE_UNDEFINED_REPR, + e.span, + &format!("transmute from `{}` which has an undefined layout", from_ty_orig), + |diag| { + if from_ty_orig.peel_refs() != from_ty.peel_refs() { + diag.note(&format!("the contained type `{}` has an undefined layout", from_ty)); + } + }, + ); + return true; + }, + (_, ReducedTy::Other(_)) if reduced_tys.to_fat_ptr => { + span_lint_and_then( + cx, + TRANSMUTE_UNDEFINED_REPR, + e.span, + &format!("transmute to `{}` which has an undefined layout", to_ty_orig), + |diag| { + if to_ty_orig.peel_refs() != to_ty.peel_refs() { + diag.note(&format!("the contained type `{}` has an undefined layout", to_ty)); + } + }, + ); + return true; + }, + + (ReducedTy::UnorderedFields(from_ty), ReducedTy::UnorderedFields(to_ty)) if from_ty != to_ty => { + let same_adt_did = if let (ty::Adt(from_def, from_subs), ty::Adt(to_def, to_subs)) = (from_ty.kind(), to_ty.kind()) && from_def == to_def { @@ -138,83 +111,72 @@ pub(super) fn check<'tcx>( } else { None }; - span_lint_and_then( - cx, - TRANSMUTE_UNDEFINED_REPR, - e.span, - &format!( - "transmute from `{}` to `{}`, both of which have an undefined layout", - from_ty_orig, to_ty_orig - ), - |diag| { - if let Some(same_adt_did) = same_adt_did { - diag.note(&format!( - "two instances of the same generic type (`{}`) may have different layouts", - cx.tcx.item_name(same_adt_did) - )); - } else { - if from_ty_orig.peel_refs() != from_ty { - diag.note(&format!("the contained type `{}` has an undefined layout", from_ty)); - } - if to_ty_orig.peel_refs() != to_ty { - diag.note(&format!("the contained type `{}` has an undefined layout", to_ty)); - } - } - }, - ); - return true; - }, - // `Repr(C)` <-> unordered type. - // If the first field of the `Repr(C)` type matches then the transmute is ok - (ReducedTy::OrderedFields(_, Some(from_sub_ty)), ReducedTy::UnorderedFields(to_sub_ty)) - | (ReducedTy::UnorderedFields(from_sub_ty), ReducedTy::OrderedFields(_, Some(to_sub_ty))) - | (ReducedTy::Ref(from_sub_ty), ReducedTy::Ref(to_sub_ty)) => { - from_ty = from_sub_ty; - to_ty = to_sub_ty; - continue; - }, - ( - ReducedTy::UnorderedFields(from_ty), - ReducedTy::Other(_) | ReducedTy::OrderedFields(..) | ReducedTy::Ref(_), - ) => { - span_lint_and_then( - cx, - TRANSMUTE_UNDEFINED_REPR, - e.span, - &format!("transmute from `{}` which has an undefined layout", from_ty_orig), - |diag| { + span_lint_and_then( + cx, + TRANSMUTE_UNDEFINED_REPR, + e.span, + &format!( + "transmute from `{}` to `{}`, both of which have an undefined layout", + from_ty_orig, to_ty_orig + ), + |diag| { + if let Some(same_adt_did) = same_adt_did { + diag.note(&format!( + "two instances of the same generic type (`{}`) may have different layouts", + cx.tcx.item_name(same_adt_did) + )); + } else { if from_ty_orig.peel_refs() != from_ty { diag.note(&format!("the contained type `{}` has an undefined layout", from_ty)); } - }, - ); - return true; - }, - ( - ReducedTy::Other(_) | ReducedTy::OrderedFields(..) | ReducedTy::Ref(_), - ReducedTy::UnorderedFields(to_ty), - ) => { - span_lint_and_then( - cx, - TRANSMUTE_UNDEFINED_REPR, - e.span, - &format!("transmute into `{}` which has an undefined layout", to_ty_orig), - |diag| { if to_ty_orig.peel_refs() != to_ty { diag.note(&format!("the contained type `{}` has an undefined layout", to_ty)); } - }, - ); - return true; - }, - ( - ReducedTy::OrderedFields(..) | ReducedTy::Ref(_) | ReducedTy::Other(_) | ReducedTy::Param, - ReducedTy::OrderedFields(..) | ReducedTy::Ref(_) | ReducedTy::Other(_) | ReducedTy::Param, - ) - | ( - ReducedTy::UnorderedFields(_) | ReducedTy::Param, - ReducedTy::UnorderedFields(_) | ReducedTy::Param, - ) => break, + } + }, + ); + return true; + }, + ( + ReducedTy::UnorderedFields(from_ty), + ReducedTy::Other(_) | ReducedTy::OrderedFields(..) | ReducedTy::TypeErasure { raw_ptr_only: true }, + ) => { + span_lint_and_then( + cx, + TRANSMUTE_UNDEFINED_REPR, + e.span, + &format!("transmute from `{}` which has an undefined layout", from_ty_orig), + |diag| { + if from_ty_orig.peel_refs() != from_ty { + diag.note(&format!("the contained type `{}` has an undefined layout", from_ty)); + } + }, + ); + return true; + }, + ( + ReducedTy::Other(_) | ReducedTy::OrderedFields(..) | ReducedTy::TypeErasure { raw_ptr_only: true }, + ReducedTy::UnorderedFields(to_ty), + ) => { + span_lint_and_then( + cx, + TRANSMUTE_UNDEFINED_REPR, + e.span, + &format!("transmute into `{}` which has an undefined layout", to_ty_orig), + |diag| { + if to_ty_orig.peel_refs() != to_ty { + diag.note(&format!("the contained type `{}` has an undefined layout", to_ty)); + } + }, + ); + return true; + }, + ( + ReducedTy::OrderedFields(..) | ReducedTy::Other(_) | ReducedTy::TypeErasure { raw_ptr_only: true }, + ReducedTy::OrderedFields(..) | ReducedTy::Other(_) | ReducedTy::TypeErasure { raw_ptr_only: true }, + ) + | (ReducedTy::UnorderedFields(_), ReducedTy::UnorderedFields(_)) => { + break; }, } } @@ -222,65 +184,64 @@ pub(super) fn check<'tcx>( false } -enum ReducedTys<'tcx> { - FromFatPtr { unsized_ty: Ty<'tcx>, to_ty: Ty<'tcx> }, - ToFatPtr { unsized_ty: Ty<'tcx>, from_ty: Ty<'tcx> }, - ToPtr { from_ty: Ty<'tcx>, to_ty: Ty<'tcx> }, - FromPtr { from_ty: Ty<'tcx>, to_ty: Ty<'tcx> }, - Other { from_ty: Ty<'tcx>, to_ty: Ty<'tcx> }, +#[expect(clippy::struct_excessive_bools)] +struct ReducedTys<'tcx> { + from_ty: Ty<'tcx>, + to_ty: Ty<'tcx>, + from_raw_ptr: bool, + to_raw_ptr: bool, + from_fat_ptr: bool, + to_fat_ptr: bool, } /// Remove references so long as both types are references. -fn reduce_refs<'tcx>( - cx: &LateContext<'tcx>, - span: Span, - mut from_ty: Ty<'tcx>, - mut to_ty: Ty<'tcx>, -) -> ReducedTys<'tcx> { - loop { - return match (from_ty.kind(), to_ty.kind()) { +fn reduce_refs<'tcx>(cx: &LateContext<'tcx>, mut from_ty: Ty<'tcx>, mut to_ty: Ty<'tcx>) -> ReducedTys<'tcx> { + let mut from_raw_ptr = false; + let mut to_raw_ptr = false; + let (from_fat_ptr, to_fat_ptr) = loop { + break match (from_ty.kind(), to_ty.kind()) { ( &(ty::Ref(_, from_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: from_sub_ty, .. })), &(ty::Ref(_, to_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: to_sub_ty, .. })), ) => { + from_raw_ptr = matches!(*from_ty.kind(), ty::RawPtr(_)); from_ty = from_sub_ty; + to_raw_ptr = matches!(*to_ty.kind(), ty::RawPtr(_)); to_ty = to_sub_ty; continue; }, (&(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })), _) - if !unsized_ty.is_sized(cx.tcx.at(span), cx.param_env) => + if !unsized_ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env) => { - ReducedTys::FromFatPtr { unsized_ty, to_ty } + (true, false) }, (_, &(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. }))) - if !unsized_ty.is_sized(cx.tcx.at(span), cx.param_env) => + if !unsized_ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env) => { - ReducedTys::ToFatPtr { unsized_ty, from_ty } + (false, true) }, - (&(ty::Ref(_, from_ty, _) | ty::RawPtr(TypeAndMut { ty: from_ty, .. })), _) => { - ReducedTys::FromPtr { from_ty, to_ty } - }, - (_, &(ty::Ref(_, to_ty, _) | ty::RawPtr(TypeAndMut { ty: to_ty, .. }))) => { - ReducedTys::ToPtr { from_ty, to_ty } - }, - _ => ReducedTys::Other { from_ty, to_ty }, + _ => (false, false), }; + }; + ReducedTys { + from_ty, + to_ty, + from_raw_ptr, + to_raw_ptr, + from_fat_ptr, + to_fat_ptr, } } enum ReducedTy<'tcx> { /// The type can be used for type erasure. - TypeErasure, + TypeErasure { raw_ptr_only: bool }, /// The type is a struct containing either zero non-zero sized fields, or multiple non-zero /// sized fields with a defined order. /// The second value is the first non-zero sized type. OrderedFields(Ty<'tcx>, Option>), /// The type is a struct containing multiple non-zero sized fields with no defined order. UnorderedFields(Ty<'tcx>), - /// The type is a reference to the contained type. - Ref(Ty<'tcx>), - /// The type is a generic parameter. - Param, /// Any other type. Other(Ty<'tcx>), } @@ -290,12 +251,14 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx> loop { ty = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty).unwrap_or(ty); return match *ty.kind() { - ty::Array(sub_ty, _) if matches!(sub_ty.kind(), ty::Int(_) | ty::Uint(_)) => ReducedTy::TypeErasure, + ty::Array(sub_ty, _) if matches!(sub_ty.kind(), ty::Int(_) | ty::Uint(_)) => { + ReducedTy::TypeErasure { raw_ptr_only: false } + }, ty::Array(sub_ty, _) | ty::Slice(sub_ty) => { ty = sub_ty; continue; }, - ty::Tuple(args) if args.is_empty() => ReducedTy::TypeErasure, + ty::Tuple(args) if args.is_empty() => ReducedTy::TypeErasure { raw_ptr_only: false }, ty::Tuple(args) => { let mut iter = args.iter(); let Some(sized_ty) = iter.find(|&ty| !is_zero_sized_ty(cx, ty)) else { @@ -314,7 +277,7 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx> .iter() .map(|f| cx.tcx.bound_type_of(f.did).subst(cx.tcx, substs)); let Some(sized_ty) = iter.find(|&ty| !is_zero_sized_ty(cx, ty)) else { - return ReducedTy::TypeErasure; + return ReducedTy::TypeErasure { raw_ptr_only: false }; }; if iter.all(|ty| is_zero_sized_ty(cx, ty)) { ty = sized_ty; @@ -327,14 +290,12 @@ fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx> } }, ty::Adt(def, _) if def.is_enum() && (def.variants().is_empty() || is_c_void(cx, ty)) => { - ReducedTy::TypeErasure + ReducedTy::TypeErasure { raw_ptr_only: false } }, // TODO: Check if the conversion to or from at least one of a union's fields is valid. - ty::Adt(def, _) if def.is_union() => ReducedTy::TypeErasure, - ty::Foreign(_) => ReducedTy::TypeErasure, - ty::Ref(_, ty, _) => ReducedTy::Ref(ty), - ty::RawPtr(ty) => ReducedTy::Ref(ty.ty), - ty::Param(_) => ReducedTy::Param, + ty::Adt(def, _) if def.is_union() => ReducedTy::TypeErasure { raw_ptr_only: false }, + ty::Foreign(_) | ty::Param(_) => ReducedTy::TypeErasure { raw_ptr_only: false }, + ty::Int(_) | ty::Uint(_) => ReducedTy::TypeErasure { raw_ptr_only: true }, _ => ReducedTy::Other(ty), }; } diff --git a/tests/ui/transmute_undefined_repr.rs b/tests/ui/transmute_undefined_repr.rs index 6df8ed8feeac..5aad0b44270a 100644 --- a/tests/ui/transmute_undefined_repr.rs +++ b/tests/ui/transmute_undefined_repr.rs @@ -4,6 +4,7 @@ use core::any::TypeId; use core::ffi::c_void; use core::mem::{size_of, transmute, MaybeUninit}; +use core::ptr::NonNull; fn value() -> T { unimplemented!() @@ -117,6 +118,9 @@ fn main() { let _: *const Ty2 = transmute(value::<*const Ty2C>>()); // Err let _: *const Ty2C> = transmute(value::<*const Ty2>()); // Err + + let _: NonNull = transmute(value::>()); // Ok + let _: NonNull<(String, String)> = transmute(value::>()); // Ok } } diff --git a/tests/ui/transmute_undefined_repr.stderr b/tests/ui/transmute_undefined_repr.stderr index 8319f71a83dc..e50a773290e1 100644 --- a/tests/ui/transmute_undefined_repr.stderr +++ b/tests/ui/transmute_undefined_repr.stderr @@ -1,5 +1,5 @@ error: transmute from `Ty2` which has an undefined layout - --> $DIR/transmute_undefined_repr.rs:27:33 + --> $DIR/transmute_undefined_repr.rs:28:33 | LL | let _: Ty2C = transmute(value::>()); // Lint, Ty2 is unordered | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,13 +7,13 @@ LL | let _: Ty2C = transmute(value::>()); // Lin = note: `-D clippy::transmute-undefined-repr` implied by `-D warnings` error: transmute into `Ty2` which has an undefined layout - --> $DIR/transmute_undefined_repr.rs:28:32 + --> $DIR/transmute_undefined_repr.rs:29:32 | LL | let _: Ty2 = transmute(value::>()); // Lint, Ty2 is unordered | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from `Ty>` to `Ty2`, both of which have an undefined layout - --> $DIR/transmute_undefined_repr.rs:33:32 + --> $DIR/transmute_undefined_repr.rs:34:32 | LL | let _: Ty2 = transmute(value::>>()); // Lint, different Ty2 instances | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -21,7 +21,7 @@ LL | let _: Ty2 = transmute(value::>>()); // = note: two instances of the same generic type (`Ty2`) may have different layouts error: transmute from `Ty2` to `Ty>`, both of which have an undefined layout - --> $DIR/transmute_undefined_repr.rs:34:36 + --> $DIR/transmute_undefined_repr.rs:35:36 | LL | let _: Ty> = transmute(value::>()); // Lint, different Ty2 instances | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -29,7 +29,7 @@ LL | let _: Ty> = transmute(value::>()); // = note: two instances of the same generic type (`Ty2`) may have different layouts error: transmute from `Ty<&Ty2>` to `&Ty2`, both of which have an undefined layout - --> $DIR/transmute_undefined_repr.rs:39:33 + --> $DIR/transmute_undefined_repr.rs:40:33 | LL | let _: &Ty2 = transmute(value::>>()); // Lint, different Ty2 instances | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL | let _: &Ty2 = transmute(value::>>()); / = note: two instances of the same generic type (`Ty2`) may have different layouts error: transmute from `&Ty2` to `Ty<&Ty2>`, both of which have an undefined layout - --> $DIR/transmute_undefined_repr.rs:40:37 + --> $DIR/transmute_undefined_repr.rs:41:37 | LL | let _: Ty<&Ty2> = transmute(value::<&Ty2>()); // Lint, different Ty2 instances | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -45,7 +45,7 @@ LL | let _: Ty<&Ty2> = transmute(value::<&Ty2>()); / = note: two instances of the same generic type (`Ty2`) may have different layouts error: transmute from `std::boxed::Box>` to `&mut Ty2`, both of which have an undefined layout - --> $DIR/transmute_undefined_repr.rs:57:45 + --> $DIR/transmute_undefined_repr.rs:58:45 | LL | let _: &'static mut Ty2 = transmute(value::>>()); // Lint, different Ty2 instances | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -53,7 +53,7 @@ LL | let _: &'static mut Ty2 = transmute(value::` to `std::boxed::Box>`, both of which have an undefined layout - --> $DIR/transmute_undefined_repr.rs:58:37 + --> $DIR/transmute_undefined_repr.rs:59:37 | LL | let _: Box> = transmute(value::<&'static mut Ty2>()); // Lint, different Ty2 instances | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL | let _: Box> = transmute(value::<&'static mut Ty2` which has an undefined layout - --> $DIR/transmute_undefined_repr.rs:118:39 + --> $DIR/transmute_undefined_repr.rs:119:39 | LL | let _: *const Ty2 = transmute(value::<*const Ty2C>>()); // Err | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -69,7 +69,7 @@ LL | let _: *const Ty2 = transmute(value::<*const Ty2C` has an undefined layout error: transmute from `*const Ty2` which has an undefined layout - --> $DIR/transmute_undefined_repr.rs:119:50 + --> $DIR/transmute_undefined_repr.rs:120:50 | LL | let _: *const Ty2C> = transmute(value::<*const Ty2>()); // Err | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -77,7 +77,7 @@ LL | let _: *const Ty2C> = transmute(value::<*const T = note: the contained type `Ty2` has an undefined layout error: transmute from `std::vec::Vec>` to `std::vec::Vec>`, both of which have an undefined layout - --> $DIR/transmute_undefined_repr.rs:146:35 + --> $DIR/transmute_undefined_repr.rs:150:35 | LL | let _: Vec> = transmute(value::>>()); // Err | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL | let _: Vec> = transmute(value::>>()); / = note: two instances of the same generic type (`Vec`) may have different layouts error: transmute from `std::vec::Vec>` to `std::vec::Vec>`, both of which have an undefined layout - --> $DIR/transmute_undefined_repr.rs:147:35 + --> $DIR/transmute_undefined_repr.rs:151:35 | LL | let _: Vec> = transmute(value::>>()); // Err | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 6b2eab231056da3734e90bd35f11e257dc0bc138 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 30 Jul 2022 01:53:29 +0000 Subject: [PATCH 3680/5092] Add Tuple marker trait --- compiler/rustc_hir/src/lang_items.rs | 2 ++ compiler/rustc_span/src/symbol.rs | 1 + library/core/src/marker.rs | 9 +++++++++ 3 files changed, 12 insertions(+) diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index c337be12ae49..03e204eb7d80 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -290,6 +290,8 @@ language_item_table! { Try, sym::Try, try_trait, Target::Trait, GenericRequirement::None; + Tuple, sym::tuple_trait, tuple_trait, Target::Trait, GenericRequirement::Exact(0); + SliceLen, sym::slice_len_fn, slice_len_fn, Target::Method(MethodKind::Inherent), GenericRequirement::None; // Language items from AST lowering diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index f81a69c1cce0..4120717a6814 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1481,6 +1481,7 @@ symbols! { tuple, tuple_from_req, tuple_indexing, + tuple_trait, two_phase, ty, type_alias_enum_variants, diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 2c57897956fc..63096bf14d75 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -800,6 +800,15 @@ impl Unpin for *mut T {} #[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)] pub trait Destruct {} +/// A marker for tuple types. +/// +/// The implementation of this trait is built-in and cannot be implemented +/// for any user type. +#[unstable(feature = "tuple_trait", issue = "none")] +#[cfg_attr(not(bootstrap), lang = "tuple_trait")] +#[rustc_on_unimplemented(message = "`{Self}` is not a tuple")] +pub trait Tuple {} + /// Implementations of `Copy` for primitive types. /// /// Implementations that cannot be described in Rust From d0e4c679ff1772e7ec0f9ca983ac229ffd3db2dc Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 30 Jul 2022 01:33:51 +0000 Subject: [PATCH 3681/5092] Built-in implementation of Tuple trait --- compiler/rustc_middle/src/traits/mod.rs | 11 ++++- compiler/rustc_middle/src/traits/select.rs | 3 ++ .../src/traits/structural_impls.rs | 2 + .../src/traits/project.rs | 6 ++- .../src/traits/select/candidate_assembly.rs | 44 +++++++++++++++++++ .../src/traits/select/confirmation.rs | 2 + .../src/traits/select/mod.rs | 9 ++-- compiler/rustc_ty_utils/src/instance.rs | 3 +- 8 files changed, 72 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 72b848c3ee2d..53d22eb00706 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -634,6 +634,10 @@ pub enum ImplSource<'tcx, N> { /// ImplSource for a `const Drop` implementation. ConstDestruct(ImplSourceConstDestructData), + + /// ImplSource for a `std::marker::Tuple` implementation. + /// This has no nested predicates ever, so no data. + Tuple, } impl<'tcx, N> ImplSource<'tcx, N> { @@ -648,7 +652,8 @@ impl<'tcx, N> ImplSource<'tcx, N> { ImplSource::Object(d) => d.nested, ImplSource::FnPointer(d) => d.nested, ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) - | ImplSource::Pointee(ImplSourcePointeeData) => Vec::new(), + | ImplSource::Pointee(ImplSourcePointeeData) + | ImplSource::Tuple => Vec::new(), ImplSource::TraitAlias(d) => d.nested, ImplSource::TraitUpcasting(d) => d.nested, ImplSource::ConstDestruct(i) => i.nested, @@ -666,7 +671,8 @@ impl<'tcx, N> ImplSource<'tcx, N> { ImplSource::Object(d) => &d.nested, ImplSource::FnPointer(d) => &d.nested, ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) - | ImplSource::Pointee(ImplSourcePointeeData) => &[], + | ImplSource::Pointee(ImplSourcePointeeData) + | ImplSource::Tuple => &[], ImplSource::TraitAlias(d) => &d.nested, ImplSource::TraitUpcasting(d) => &d.nested, ImplSource::ConstDestruct(i) => &i.nested, @@ -733,6 +739,7 @@ impl<'tcx, N> ImplSource<'tcx, N> { nested: i.nested.into_iter().map(f).collect(), }) } + ImplSource::Tuple => ImplSource::Tuple, } } } diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index e836ba47eed7..53af3e905341 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -160,6 +160,9 @@ pub enum SelectionCandidate<'tcx> { /// Implementation of `const Destruct`, optionally from a custom `impl const Drop`. ConstDestructCandidate(Option), + + /// Witnesses the fact that a type is a tuple. + TupleCandidate, } /// The result of trait evaluation. The order is important diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs index 7fbd57ac7354..c526344e1f26 100644 --- a/compiler/rustc_middle/src/traits/structural_impls.rs +++ b/compiler/rustc_middle/src/traits/structural_impls.rs @@ -34,6 +34,8 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> { super::ImplSource::TraitUpcasting(ref d) => write!(f, "{:?}", d), super::ImplSource::ConstDestruct(ref d) => write!(f, "{:?}", d), + + super::ImplSource::Tuple => write!(f, "ImplSource::Tuple"), } } } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index adf47ece69d9..f73dce397646 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1625,7 +1625,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( super::ImplSource::AutoImpl(..) | super::ImplSource::Builtin(..) | super::ImplSource::TraitUpcasting(_) - | super::ImplSource::ConstDestruct(_) => { + | super::ImplSource::ConstDestruct(_) + | super::ImplSource::Tuple => { // These traits have no associated types. selcx.tcx().sess.delay_span_bug( obligation.cause.span, @@ -1700,7 +1701,8 @@ fn confirm_select_candidate<'cx, 'tcx>( | super::ImplSource::Builtin(..) | super::ImplSource::TraitUpcasting(_) | super::ImplSource::TraitAlias(..) - | super::ImplSource::ConstDestruct(_) => { + | super::ImplSource::ConstDestruct(_) + | super::ImplSource::Tuple => { // we don't create Select candidates with this kind of resolution span_bug!( obligation.cause.span, diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 50e9b95a445f..4d738a49468d 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -309,6 +309,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // User-defined transmutability impls are permitted. self.assemble_candidates_from_impls(obligation, &mut candidates); self.assemble_candidates_for_transmutability(obligation, &mut candidates); + } else if lang_items.tuple_trait() == Some(def_id) { + self.assemble_candidate_for_tuple(obligation, &mut candidates); } else { if lang_items.clone_trait() == Some(def_id) { // Same builtin conditions as `Copy`, i.e., every type which has builtin support @@ -1009,4 +1011,46 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } } + + fn assemble_candidate_for_tuple( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + let self_ty = self.infcx().shallow_resolve(obligation.self_ty().skip_binder()); + match self_ty.kind() { + ty::Tuple(_) => { + candidates.vec.push(TupleCandidate); + } + ty::Infer(ty::TyVar(_)) => { + candidates.ambiguous = true; + } + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(_, _) + | ty::Foreign(_) + | ty::Str + | ty::Array(_, _) + | ty::Slice(_) + | ty::RawPtr(_) + | ty::Ref(_, _, _) + | ty::FnDef(_, _) + | ty::FnPtr(_) + | ty::Dynamic(_, _) + | ty::Closure(_, _) + | ty::Generator(_, _, _) + | ty::GeneratorWitness(_) + | ty::Never + | ty::Projection(_) + | ty::Opaque(_, _) + | ty::Param(_) + | ty::Bound(_, _) + | ty::Error(_) + | ty::Infer(_) + | ty::Placeholder(_) => {} + } + } } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 2a1099fc82ab..ef6311674782 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -126,6 +126,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let data = self.confirm_const_destruct_candidate(obligation, def_id)?; ImplSource::ConstDestruct(data) } + + TupleCandidate => ImplSource::Tuple, }; if !obligation.predicate.is_const_if_const() { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index c01ac1979910..561a3e1c0383 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1618,7 +1618,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; // (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`, - // `DiscriminantKindCandidate`, and `ConstDestructCandidate` to anything else. + // `DiscriminantKindCandidate`, `ConstDestructCandidate`, and `TupleCandidate` + // to anything else. // // This is a fix for #53123 and prevents winnowing from accidentally extending the // lifetime of a variable. @@ -1638,7 +1639,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate | PointeeCandidate - | ConstDestructCandidate(_), + | ConstDestructCandidate(_) + | TupleCandidate, _, ) => true, ( @@ -1646,7 +1648,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate | PointeeCandidate - | ConstDestructCandidate(_), + | ConstDestructCandidate(_) + | TupleCandidate, ) => false, (ParamCandidate(other), ParamCandidate(victim)) => { diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index bd1d568cd9a0..8075cb77757a 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -397,7 +397,8 @@ fn resolve_associated_item<'tcx>( | traits::ImplSource::DiscriminantKind(..) | traits::ImplSource::Pointee(..) | traits::ImplSource::TraitUpcasting(_) - | traits::ImplSource::ConstDestruct(_) => None, + | traits::ImplSource::ConstDestruct(_) + | traits::ImplSource::Tuple => None, }) } From 109cc1de9201e0523a24de1ad543f9baa23b57dc Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 7 Aug 2022 16:52:46 -0700 Subject: [PATCH 3682/5092] Add tuple trait tests --- src/test/ui/explore-issue-38412.stderr | 6 +-- src/test/ui/tuple/builtin-fail.rs | 19 +++++++++ src/test/ui/tuple/builtin-fail.stderr | 55 ++++++++++++++++++++++++++ src/test/ui/tuple/builtin.rs | 20 ++++++++++ 4 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/tuple/builtin-fail.rs create mode 100644 src/test/ui/tuple/builtin-fail.stderr create mode 100644 src/test/ui/tuple/builtin.rs diff --git a/src/test/ui/explore-issue-38412.stderr b/src/test/ui/explore-issue-38412.stderr index e3f82137ab3b..08dadb4db851 100644 --- a/src/test/ui/explore-issue-38412.stderr +++ b/src/test/ui/explore-issue-38412.stderr @@ -43,19 +43,19 @@ LL | t.2; = note: see issue #38412 for more information = help: add `#![feature(unstable_undeclared)]` to the crate attributes to enable -error[E0616]: field `3` of struct `Tuple` is private +error[E0616]: field `3` of struct `pub_and_stability::Tuple` is private --> $DIR/explore-issue-38412.rs:36:7 | LL | t.3; | ^ private field -error[E0616]: field `4` of struct `Tuple` is private +error[E0616]: field `4` of struct `pub_and_stability::Tuple` is private --> $DIR/explore-issue-38412.rs:37:7 | LL | t.4; | ^ private field -error[E0616]: field `5` of struct `Tuple` is private +error[E0616]: field `5` of struct `pub_and_stability::Tuple` is private --> $DIR/explore-issue-38412.rs:38:7 | LL | t.5; diff --git a/src/test/ui/tuple/builtin-fail.rs b/src/test/ui/tuple/builtin-fail.rs new file mode 100644 index 000000000000..31208096151d --- /dev/null +++ b/src/test/ui/tuple/builtin-fail.rs @@ -0,0 +1,19 @@ +#![feature(tuple_trait)] + +fn assert_is_tuple() {} + +struct TupleStruct(i32, i32); + +fn from_param_env() { + assert_is_tuple::(); + //~^ ERROR `T` is not a tuple +} + +fn main() { + assert_is_tuple::(); + //~^ ERROR `i32` is not a tuple + assert_is_tuple::<(i32)>(); + //~^ ERROR `i32` is not a tuple + assert_is_tuple::(); + //~^ ERROR `TupleStruct` is not a tuple +} diff --git a/src/test/ui/tuple/builtin-fail.stderr b/src/test/ui/tuple/builtin-fail.stderr new file mode 100644 index 000000000000..e3e29a73fdc0 --- /dev/null +++ b/src/test/ui/tuple/builtin-fail.stderr @@ -0,0 +1,55 @@ +error[E0277]: `T` is not a tuple + --> $DIR/builtin-fail.rs:8:23 + | +LL | assert_is_tuple::(); + | ^ the trait `Tuple` is not implemented for `T` + | +note: required by a bound in `assert_is_tuple` + --> $DIR/builtin-fail.rs:3:23 + | +LL | fn assert_is_tuple() {} + | ^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_tuple` +help: consider restricting type parameter `T` + | +LL | fn from_param_env() { + | ++++++++++++++++++++ + +error[E0277]: `i32` is not a tuple + --> $DIR/builtin-fail.rs:13:23 + | +LL | assert_is_tuple::(); + | ^^^ the trait `Tuple` is not implemented for `i32` + | +note: required by a bound in `assert_is_tuple` + --> $DIR/builtin-fail.rs:3:23 + | +LL | fn assert_is_tuple() {} + | ^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_tuple` + +error[E0277]: `i32` is not a tuple + --> $DIR/builtin-fail.rs:15:24 + | +LL | assert_is_tuple::<(i32)>(); + | ^^^ the trait `Tuple` is not implemented for `i32` + | +note: required by a bound in `assert_is_tuple` + --> $DIR/builtin-fail.rs:3:23 + | +LL | fn assert_is_tuple() {} + | ^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_tuple` + +error[E0277]: `TupleStruct` is not a tuple + --> $DIR/builtin-fail.rs:17:23 + | +LL | assert_is_tuple::(); + | ^^^^^^^^^^^ the trait `Tuple` is not implemented for `TupleStruct` + | +note: required by a bound in `assert_is_tuple` + --> $DIR/builtin-fail.rs:3:23 + | +LL | fn assert_is_tuple() {} + | ^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_tuple` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/tuple/builtin.rs b/src/test/ui/tuple/builtin.rs new file mode 100644 index 000000000000..d87ce526357e --- /dev/null +++ b/src/test/ui/tuple/builtin.rs @@ -0,0 +1,20 @@ +// check-pass + +#![feature(tuple_trait)] + +fn assert_is_tuple() {} + +struct Unsized([u8]); + +fn from_param_env() { + assert_is_tuple::(); +} + +fn main() { + assert_is_tuple::<()>(); + assert_is_tuple::<(i32,)>(); + assert_is_tuple::<(Unsized,)>(); + from_param_env::<()>(); + from_param_env::<(i32,)>(); + from_param_env::<(Unsized,)>(); +} From 5ead47e623ccaf16aaf5d5932e14212c6bb3f9a8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 7 Aug 2022 20:36:57 -0400 Subject: [PATCH 3683/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 22daf00bd05d..cac0155e3ce4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1f5d8d49eb6111931091f700d07518cd2b80bc18 +93ab13b4e894ab74258c40aaf29872db2b17b6b4 From 12e3f75fd49e094ba5ec2f51576a78a88f2bafeb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 8 Aug 2022 11:32:31 -0400 Subject: [PATCH 3684/5092] don't make it qutie so easy to get Miri to panic --- src/bin/miri.rs | 58 ++++++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index b5a45d162f21..3325fc97d825 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -152,11 +152,15 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { } } -fn show_error(msg: String) -> ! { - eprintln!("fatal error: {}", msg); +fn show_error(msg: &str) -> ! { + eprintln!("fatal error: {msg}"); std::process::exit(1) } +macro_rules! show_error { + ($($tt:tt)*) => { show_error(&format!($($tt)*)) }; +} + fn init_early_loggers() { // Note that our `extern crate log` is *not* the same as rustc's; as a result, we have to // initialize them both, and we always initialize `miri`'s first. @@ -234,19 +238,19 @@ fn host_sysroot() -> Option { env::var_os("RUSTUP_TOOLCHAIN").or_else(|| env::var_os("MULTIRUST_TOOLCHAIN")) { if toolchain_runtime != toolchain { - show_error(format!( + show_error!( "This Miri got built with local toolchain `{toolchain}`, but now is being run under a different toolchain. \n\ Make sure to run Miri in the toolchain it got built with, e.g. via `cargo +{toolchain} miri`." - )); + ) } } format!("{}/toolchains/{}", home, toolchain) } _ => option_env!("RUST_SYSROOT") .unwrap_or_else(|| { - show_error(format!( + show_error!( "To build Miri without rustup, set the `RUST_SYSROOT` env var at build time", - )) + ) }) .to_owned(), }) @@ -272,9 +276,9 @@ fn run_compiler( // Using the built-in default here would be plain wrong, so we *require* // the env var to make sure things make sense. Some(env::var("MIRI_SYSROOT").unwrap_or_else(|_| { - show_error(format!( + show_error!( "Miri was invoked in 'target' mode without `MIRI_SYSROOT` or `--sysroot` being set" - )) + ) })) } else { host_default_sysroot @@ -379,7 +383,9 @@ fn main() { miri_config.check_abi = false; } else if arg == "-Zmiri-disable-isolation" { if matches!(isolation_enabled, Some(true)) { - panic!("-Zmiri-disable-isolation cannot be used along with -Zmiri-isolation-error"); + show_error!( + "-Zmiri-disable-isolation cannot be used along with -Zmiri-isolation-error" + ); } else { isolation_enabled = Some(false); } @@ -390,7 +396,9 @@ fn main() { miri_config.track_outdated_loads = true; } else if let Some(param) = arg.strip_prefix("-Zmiri-isolation-error=") { if matches!(isolation_enabled, Some(false)) { - panic!("-Zmiri-isolation-error cannot be used along with -Zmiri-disable-isolation"); + show_error!( + "-Zmiri-isolation-error cannot be used along with -Zmiri-disable-isolation" + ); } else { isolation_enabled = Some(true); } @@ -402,7 +410,7 @@ fn main() { "warn-nobacktrace" => miri::IsolatedOp::Reject(miri::RejectOpWith::WarningWithoutBacktrace), _ => - panic!( + show_error!( "-Zmiri-isolation-error must be `abort`, `hide`, `warn`, or `warn-nobacktrace`" ), }; @@ -426,11 +434,11 @@ fn main() { ); } else if let Some(param) = arg.strip_prefix("-Zmiri-seed=") { if miri_config.seed.is_some() { - panic!("Cannot specify -Zmiri-seed multiple times!"); + show_error!("Cannot specify -Zmiri-seed multiple times!"); } let seed = u64::from_str_radix(param, 16) - .unwrap_or_else(|_| panic!( - "-Zmiri-seed should only contain valid hex digits [0-9a-fA-F] and fit into a u64 (max 16 characters)" + .unwrap_or_else(|_| show_error!( + "-Zmiri-seed should only contain valid hex digits [0-9a-fA-F] and must fit into a u64 (max 16 characters)" )); miri_config.seed = Some(seed); } else if let Some(param) = arg.strip_prefix("-Zmiri-env-exclude=") { @@ -441,7 +449,7 @@ fn main() { let ids: Vec = match parse_comma_list(param) { Ok(ids) => ids, Err(err) => - panic!( + show_error!( "-Zmiri-track-pointer-tag requires a comma separated list of valid `u64` arguments: {}", err ), @@ -450,14 +458,14 @@ fn main() { if let Some(id) = id { miri_config.tracked_pointer_tags.insert(id); } else { - panic!("-Zmiri-track-pointer-tag requires nonzero arguments"); + show_error!("-Zmiri-track-pointer-tag requires nonzero arguments"); } } } else if let Some(param) = arg.strip_prefix("-Zmiri-track-call-id=") { let ids: Vec = match parse_comma_list(param) { Ok(ids) => ids, Err(err) => - panic!( + show_error!( "-Zmiri-track-call-id requires a comma separated list of valid `u64` arguments: {}", err ), @@ -466,14 +474,14 @@ fn main() { if let Some(id) = id { miri_config.tracked_call_ids.insert(id); } else { - panic!("-Zmiri-track-call-id requires a nonzero argument"); + show_error!("-Zmiri-track-call-id requires a nonzero argument"); } } } else if let Some(param) = arg.strip_prefix("-Zmiri-track-alloc-id=") { let ids: Vec = match parse_comma_list::(param) { Ok(ids) => ids.into_iter().map(miri::AllocId).collect(), Err(err) => - panic!( + show_error!( "-Zmiri-track-alloc-id requires a comma separated list of valid non-zero `u64` arguments: {}", err ), @@ -483,11 +491,11 @@ fn main() { let rate = match param.parse::() { Ok(rate) if rate >= 0.0 && rate <= 1.0 => rate, Ok(_) => - panic!( + show_error!( "-Zmiri-compare-exchange-weak-failure-rate must be between `0.0` and `1.0`" ), Err(err) => - panic!( + show_error!( "-Zmiri-compare-exchange-weak-failure-rate requires a `f64` between `0.0` and `1.0`: {}", err ), @@ -496,9 +504,9 @@ fn main() { } else if let Some(param) = arg.strip_prefix("-Zmiri-preemption-rate=") { let rate = match param.parse::() { Ok(rate) if rate >= 0.0 && rate <= 1.0 => rate, - Ok(_) => panic!("-Zmiri-preemption-rate must be between `0.0` and `1.0`"), + Ok(_) => show_error!("-Zmiri-preemption-rate must be between `0.0` and `1.0`"), Err(err) => - panic!( + show_error!( "-Zmiri-preemption-rate requires a `f64` between `0.0` and `1.0`: {}", err ), @@ -510,7 +518,7 @@ fn main() { } else if let Some(param) = arg.strip_prefix("-Zmiri-report-progress=") { let interval = match param.parse::() { Ok(i) => i, - Err(err) => panic!("-Zmiri-report-progress requires a `u32`: {}", err), + Err(err) => show_error!("-Zmiri-report-progress requires a `u32`: {}", err), }; miri_config.report_progress = Some(interval); } else if let Some(param) = arg.strip_prefix("-Zmiri-measureme=") { @@ -520,7 +528,7 @@ fn main() { "0" => BacktraceStyle::Off, "1" => BacktraceStyle::Short, "full" => BacktraceStyle::Full, - _ => panic!("-Zmiri-backtrace may only be 0, 1, or full"), + _ => show_error!("-Zmiri-backtrace may only be 0, 1, or full"), }; } else { // Forward to rustc. From 1164815750a4149443b244da68e4408033a3cb5e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 8 Aug 2022 11:32:49 -0400 Subject: [PATCH 3685/5092] make cargo-miri show_error a bit nicer to use --- cargo-miri/src/main.rs | 8 +++++--- cargo-miri/src/phases.rs | 19 ++++++++----------- cargo-miri/src/setup.rs | 18 ++++++++---------- cargo-miri/src/util.rs | 24 ++++++++++++++---------- 4 files changed, 35 insertions(+), 34 deletions(-) diff --git a/cargo-miri/src/main.rs b/cargo-miri/src/main.rs index 7b16af6f0c64..30b03c57dbab 100644 --- a/cargo-miri/src/main.rs +++ b/cargo-miri/src/main.rs @@ -1,10 +1,12 @@ #![feature(let_else)] #![allow(clippy::useless_format, clippy::derive_partial_eq_without_eq, rustc::internal)] +#[macro_use] +mod util; + mod arg; mod phases; mod setup; -mod util; mod version; use std::{env, iter}; @@ -73,9 +75,9 @@ fn main() { } let Some(first) = args.next() else { - show_error(format!( + show_error!( "`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`" - )) + ) }; match first.as_str() { "miri" => phase_cargo_miri(args), diff --git a/cargo-miri/src/phases.rs b/cargo-miri/src/phases.rs index 8635661323d1..93eb3cb17465 100644 --- a/cargo-miri/src/phases.rs +++ b/cargo-miri/src/phases.rs @@ -77,15 +77,15 @@ pub fn phase_cargo_miri(mut args: impl Iterator) { // We cannot know which of those flags take arguments and which do not, // so we cannot detect subcommands later. let Some(subcommand) = args.next() else { - show_error(format!("`cargo miri` needs to be called with a subcommand (`run`, `test`)")); + show_error!("`cargo miri` needs to be called with a subcommand (`run`, `test`)"); }; let subcommand = match &*subcommand { "setup" => MiriCommand::Setup, "test" | "t" | "run" | "r" | "nextest" => MiriCommand::Forward(subcommand), _ => - show_error(format!( + show_error!( "`cargo miri` supports the following subcommands: `run`, `test`, `nextest`, and `setup`." - )), + ), }; let verbose = num_arg_flag("-v"); @@ -123,7 +123,7 @@ pub fn phase_cargo_miri(mut args: impl Iterator) { match arg { Ok(value) => { if target_dir.is_some() { - show_error(format!("`--target-dir` is provided more than once")); + show_error!("`--target-dir` is provided more than once"); } target_dir = Some(value.into()); } @@ -456,16 +456,13 @@ pub fn phase_runner(mut binary_args: impl Iterator, phase: Runner let binary = binary_args.next().unwrap(); let file = File::open(&binary) - .unwrap_or_else(|_| show_error(format!( + .unwrap_or_else(|_| show_error!( "file {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary - ))); + )); let file = BufReader::new(file); let info = serde_json::from_reader(file).unwrap_or_else(|_| { - show_error(format!( - "file {:?} contains outdated or invalid JSON; try `cargo clean`", - binary - )) + show_error!("file {:?} contains outdated or invalid JSON; try `cargo clean`", binary) }); let info = match info { CrateRunInfo::RunWith(info) => info, @@ -562,7 +559,7 @@ pub fn phase_rustdoc(mut args: impl Iterator) { // An existing --runtool flag indicates cargo is running in cross-target mode, which we don't support. // Note that this is only passed when cargo is run with the unstable -Zdoctest-xcompile flag; // otherwise, we won't be called as rustdoc at all. - show_error(format!("cross-interpreting doctests is not currently supported by Miri.")); + show_error!("cross-interpreting doctests is not currently supported by Miri."); } else { cmd.arg(arg); } diff --git a/cargo-miri/src/setup.rs b/cargo-miri/src/setup.rs index 1211b47e3ba2..62d6e25a53e0 100644 --- a/cargo-miri/src/setup.rs +++ b/cargo-miri/src/setup.rs @@ -73,7 +73,7 @@ pub fn setup(subcommand: &MiriCommand, host: &str, target: &str) { if xargo_version().map_or(true, |v| v < XARGO_MIN_VERSION) { if std::env::var_os("XARGO_CHECK").is_some() { // The user manually gave us a xargo binary; don't do anything automatically. - show_error(format!("xargo is too old; please upgrade to the latest version")) + show_error!("xargo is too old; please upgrade to the latest version") } let mut cmd = cargo(); cmd.args(&["install", "xargo"]); @@ -97,10 +97,10 @@ pub fn setup(subcommand: &MiriCommand, host: &str, target: &str) { .output() .expect("failed to determine sysroot"); if !output.status.success() { - show_error(format!( + show_error!( "Failed to determine sysroot; Miri said:\n{}", String::from_utf8_lossy(&output.stderr).trim_end() - )); + ); } let sysroot = std::str::from_utf8(&output.stdout).unwrap(); let sysroot = Path::new(sysroot.trim_end_matches('\n')); @@ -121,14 +121,14 @@ pub fn setup(subcommand: &MiriCommand, host: &str, target: &str) { } }; if !rust_src.exists() { - show_error(format!("given Rust source directory `{}` does not exist.", rust_src.display())); + show_error!("given Rust source directory `{}` does not exist.", rust_src.display()); } if rust_src.file_name().and_then(OsStr::to_str) != Some("library") { - show_error(format!( + show_error!( "given Rust source directory `{}` does not seem to be the `library` subdirectory of \ a Rust source checkout.", rust_src.display() - )); + ); } // Next, we need our own libstd. Prepare a xargo project for that purpose. @@ -226,11 +226,9 @@ path = "lib.rs" // Finally run it! if command.status().expect("failed to run xargo").success().not() { if only_setup { - show_error(format!("failed to run xargo, see error details above")) + show_error!("failed to run xargo, see error details above") } else { - show_error(format!( - "failed to run xargo; run `cargo miri setup` to see the error details" - )) + show_error!("failed to run xargo; run `cargo miri setup` to see the error details") } } diff --git a/cargo-miri/src/util.rs b/cargo-miri/src/util.rs index b5401d71671d..8095958d21d1 100644 --- a/cargo-miri/src/util.rs +++ b/cargo-miri/src/util.rs @@ -14,6 +14,15 @@ use serde::{Deserialize, Serialize}; pub use crate::arg::*; +pub fn show_error(msg: &str) -> ! { + eprintln!("fatal error: {msg}"); + std::process::exit(1) +} + +macro_rules! show_error { + ($($tt:tt)*) => { show_error(&format!($($tt)*)) }; +} + /// The information to run a crate with the given environment. #[derive(Clone, Serialize, Deserialize)] pub struct CrateRunEnv { @@ -55,10 +64,10 @@ pub enum CrateRunInfo { impl CrateRunInfo { pub fn store(&self, filename: &Path) { let file = File::create(filename) - .unwrap_or_else(|_| show_error(format!("cannot create `{}`", filename.display()))); + .unwrap_or_else(|_| show_error!("cannot create `{}`", filename.display())); let file = BufWriter::new(file); serde_json::ser::to_writer(file, self) - .unwrap_or_else(|_| show_error(format!("cannot write to `{}`", filename.display()))); + .unwrap_or_else(|_| show_error!("cannot write to `{}`", filename.display())); } } @@ -70,11 +79,6 @@ pub enum MiriCommand { Forward(String), } -pub fn show_error(msg: String) -> ! { - eprintln!("fatal error: {}", msg); - std::process::exit(1) -} - /// Escapes `s` in a way that is suitable for using it as a string literal in TOML syntax. pub fn escape_for_toml(s: &str) -> String { // We want to surround this string in quotes `"`. So we first escape all quotes, @@ -187,15 +191,15 @@ pub fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { match buf.trim().to_lowercase().as_ref() { // Proceed. "" | "y" | "yes" => {} - "n" | "no" => show_error(format!("aborting as per your request")), - a => show_error(format!("invalid answer `{}`", a)), + "n" | "no" => show_error!("aborting as per your request"), + a => show_error!("invalid answer `{}`", a), }; } else { eprintln!("Running `{:?}` to {}.", cmd, text); } if cmd.status().unwrap_or_else(|_| panic!("failed to execute {:?}", cmd)).success().not() { - show_error(format!("failed to {}", text)); + show_error!("failed to {}", text); } } From b99d7bc77f1b7986954ec8bd2f1c9f80664e8fd4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 8 Aug 2022 11:35:54 -0400 Subject: [PATCH 3686/5092] avoid intermediate allocations in show_error macro --- cargo-miri/src/main.rs | 2 +- cargo-miri/src/util.rs | 4 ++-- src/bin/miri.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cargo-miri/src/main.rs b/cargo-miri/src/main.rs index 30b03c57dbab..09e2cd3c2867 100644 --- a/cargo-miri/src/main.rs +++ b/cargo-miri/src/main.rs @@ -11,7 +11,7 @@ mod version; use std::{env, iter}; -use crate::{phases::*, util::*}; +use crate::phases::*; fn main() { // Rustc does not support non-UTF-8 arguments so we make no attempt either. diff --git a/cargo-miri/src/util.rs b/cargo-miri/src/util.rs index 8095958d21d1..8f29eebaac10 100644 --- a/cargo-miri/src/util.rs +++ b/cargo-miri/src/util.rs @@ -14,13 +14,13 @@ use serde::{Deserialize, Serialize}; pub use crate::arg::*; -pub fn show_error(msg: &str) -> ! { +pub fn show_error(msg: &impl std::fmt::Display) -> ! { eprintln!("fatal error: {msg}"); std::process::exit(1) } macro_rules! show_error { - ($($tt:tt)*) => { show_error(&format!($($tt)*)) }; + ($($tt:tt)*) => { crate::util::show_error(&format_args!($($tt)*)) }; } /// The information to run a crate with the given environment. diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 3325fc97d825..ca0787b22983 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -152,13 +152,13 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { } } -fn show_error(msg: &str) -> ! { +fn show_error(msg: &impl std::fmt::Display) -> ! { eprintln!("fatal error: {msg}"); std::process::exit(1) } macro_rules! show_error { - ($($tt:tt)*) => { show_error(&format!($($tt)*)) }; + ($($tt:tt)*) => { show_error(&format_args!($($tt)*)) }; } fn init_early_loggers() { From 73cd95465e85f878fc5c30a79ce76a9fb59d690c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Sat, 16 Jul 2022 10:22:43 +0200 Subject: [PATCH 3687/5092] Add iter_once and iter_empty lints --- CHANGELOG.md | 2 + clippy_lints/src/iter_once_empty.rs | 164 ++++++++++++++++++++++ clippy_lints/src/lib.register_lints.rs | 2 + clippy_lints/src/lib.register_nursery.rs | 2 + clippy_lints/src/lib.register_pedantic.rs | 2 + clippy_lints/src/lib.rs | 2 + clippy_utils/src/lib.rs | 1 + tests/ui/iter_empty.fixed | 32 +++++ tests/ui/iter_empty.rs | 32 +++++ tests/ui/iter_empty.stderr | 40 ++++++ tests/ui/iter_once.fixed | 32 +++++ tests/ui/iter_once.rs | 32 +++++ tests/ui/iter_once.stderr | 40 ++++++ 13 files changed, 383 insertions(+) create mode 100644 clippy_lints/src/iter_once_empty.rs create mode 100644 tests/ui/iter_empty.fixed create mode 100644 tests/ui/iter_empty.rs create mode 100644 tests/ui/iter_empty.stderr create mode 100644 tests/ui/iter_once.fixed create mode 100644 tests/ui/iter_once.rs create mode 100644 tests/ui/iter_once.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ea7e76ee108..94f71eba0a29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3651,11 +3651,13 @@ Released 2018-09-13 [`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements [`iter_cloned_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect [`iter_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_count +[`iter_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_empty [`iter_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop [`iter_next_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_slice [`iter_not_returning_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_not_returning_iterator [`iter_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth [`iter_nth_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth_zero +[`iter_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_once [`iter_overeager_cloned`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_overeager_cloned [`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next [`iter_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_with_drain diff --git a/clippy_lints/src/iter_once_empty.rs b/clippy_lints/src/iter_once_empty.rs new file mode 100644 index 000000000000..098960011123 --- /dev/null +++ b/clippy_lints/src/iter_once_empty.rs @@ -0,0 +1,164 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use rustc_ast::ast::{Expr, ExprKind}; +use rustc_errors::Applicability; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for usage of: + /// + /// - `[foo].iter()` + /// - `[foo].iter_mut()` + /// - `[foo].into_iter()` + /// - `Some(foo).iter()` + /// - `Some(foo).iter_mut()` + /// - `Some(foo).into_iter()` + /// + /// ### Why is this bad? + /// + /// It is simpler to use the once function from the standard library: + /// + /// ### Example + /// + /// ```rust + /// let a = [123].iter(); + /// let b = Some(123).into_iter(); + /// ``` + /// Use instead: + /// ```rust + /// use std::iter; + /// let a = iter::once(&123); + /// let b = iter::once(123); + /// ``` + /// + /// ### Known problems + /// + /// The type of the resulting iterator might become incompatible with its usage + #[clippy::version = "1.64.0"] + pub ITER_ONCE, + nursery, + "Iterator for array of length 1" +} + +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for usage of: + /// + /// - `[].iter()` + /// - `[].iter_mut()` + /// - `[].into_iter()` + /// - `None.iter()` + /// - `None.iter_mut()` + /// - `None.into_iter()` + /// + /// ### Why is this bad? + /// + /// It is simpler to use the empty function from the standard library: + /// + /// ### Example + /// + /// ```rust + /// use std::{slice, option}; + /// let a: slice::Iter = [].iter(); + /// let f: option::IntoIter = None.into_iter(); + /// ``` + /// Use instead: + /// ```rust + /// use std::iter; + /// let a: iter::Empty = iter::empty(); + /// let b: iter::Empty = iter::empty(); + /// ``` + /// + /// ### Known problems + /// + /// The type of the resulting iterator might become incompatible with its usage + #[clippy::version = "1.64.0"] + pub ITER_EMPTY, + nursery, + "Iterator for empty array" +} + +declare_lint_pass!(IterOnceEmpty => [ITER_ONCE, ITER_EMPTY]); + +impl EarlyLintPass for IterOnceEmpty { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + if expr.span.from_expansion() { + // Don't lint match expressions present in + // macro_rules! block + return; + } + + let (method_name, args) = if let ExprKind::MethodCall(seg, args, _) = &expr.kind { + (seg.ident.as_str(), args) + } else { + return; + }; + let arg = if args.len() == 1 { + &args[0] + } else { + return; + }; + + let item = match &arg.kind { + ExprKind::Array(v) if v.len() <= 1 => v.first(), + ExprKind::Path(None, p) => { + if p.segments.len() == 1 && p.segments[0].ident.name == rustc_span::sym::None { + None + } else { + return; + } + }, + ExprKind::Call(f, some_args) if some_args.len() == 1 => { + if let ExprKind::Path(None, p) = &f.kind { + if p.segments.len() == 1 && p.segments[0].ident.name == rustc_span::sym::Some { + Some(&some_args[0]) + } else { + return; + } + } else { + return; + } + }, + _ => return, + }; + + if let Some(i) = item { + let (sugg, msg) = match method_name { + "iter" => ( + format!("std::iter::once(&{})", snippet(cx, i.span, "...")), + "this `iter` call can be replaced with std::iter::once", + ), + "iter_mut" => ( + format!("std::iter::once(&mut {})", snippet(cx, i.span, "...")), + "this `iter_mut` call can be replaced with std::iter::once", + ), + "into_iter" => ( + format!("std::iter::once({})", snippet(cx, i.span, "...")), + "this `into_iter` call can be replaced with std::iter::once", + ), + _ => return, + }; + span_lint_and_sugg(cx, ITER_ONCE, expr.span, msg, "try", sugg, Applicability::Unspecified); + } else { + let msg = match method_name { + "iter" => "this `iter call` can be replaced with std::iter::empty", + "iter_mut" => "this `iter_mut` call can be replaced with std::iter::empty", + "into_iter" => "this `into_iter` call can be replaced with std::iter::empty", + _ => return, + }; + span_lint_and_sugg( + cx, + ITER_EMPTY, + expr.span, + msg, + "try", + "std::iter::empty()".to_string(), + Applicability::Unspecified, + ); + } + } +} diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index d83508a2d6ca..49fc3a895274 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -200,6 +200,8 @@ store.register_lints(&[ invalid_utf8_in_unchecked::INVALID_UTF8_IN_UNCHECKED, items_after_statements::ITEMS_AFTER_STATEMENTS, iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR, + iter_once_empty::ITER_EMPTY, + iter_once_empty::ITER_ONCE, large_const_arrays::LARGE_CONST_ARRAYS, large_enum_variant::LARGE_ENUM_VARIANT, large_include_file::LARGE_INCLUDE_FILE, diff --git a/clippy_lints/src/lib.register_nursery.rs b/clippy_lints/src/lib.register_nursery.rs index 7d731d52dbbd..9953aca43ee2 100644 --- a/clippy_lints/src/lib.register_nursery.rs +++ b/clippy_lints/src/lib.register_nursery.rs @@ -14,6 +14,8 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(index_refutable_slice::INDEX_REFUTABLE_SLICE), LintId::of(let_if_seq::USELESS_LET_IF_SEQ), LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE), + LintId::of(methods::ITER_EMPTY), + LintId::of(methods::ITER_ONCE), LintId::of(methods::ITER_WITH_DRAIN), LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN), LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index 4250ee055e6c..6063fb00a7b6 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -41,6 +41,8 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS), LintId::of(items_after_statements::ITEMS_AFTER_STATEMENTS), LintId::of(iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR), + LintId::of(iter_once_empty::ITER_EMPTY), + LintId::of(iter_once_empty::ITER_ONCE), LintId::of(large_stack_arrays::LARGE_STACK_ARRAYS), LintId::of(let_underscore::LET_UNDERSCORE_DROP), LintId::of(literal_representation::LARGE_DIGIT_GROUPS), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 88c1a727f8dc..78279db9ad54 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -258,6 +258,7 @@ mod invalid_upcast_comparisons; mod invalid_utf8_in_unchecked; mod items_after_statements; mod iter_not_returning_iterator; +mod iter_once_empty; mod large_const_arrays; mod large_enum_variant; mod large_include_file; @@ -931,6 +932,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked)); store.register_late_pass(|| Box::new(std_instead_of_core::StdReexports::default())); store.register_late_pass(|| Box::new(manual_instant_elapsed::ManualInstantElapsed)); + store.register_early_pass(|| Box::new(iter_once_empty::IterOnceEmpty)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index dcfc03475b42..9c58978a0703 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -484,6 +484,7 @@ pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res { } fn find_primitive<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator + 'tcx { let single = |ty| tcx.incoherent_impls(ty).iter().copied(); + #[allow(clippy::iter_empty)] let empty = || [].iter().copied(); match name { "bool" => single(BoolSimplifiedType), diff --git a/tests/ui/iter_empty.fixed b/tests/ui/iter_empty.fixed new file mode 100644 index 000000000000..fb7118f0d4a0 --- /dev/null +++ b/tests/ui/iter_empty.fixed @@ -0,0 +1,32 @@ +// run-rustfix +#![warn(clippy::iter_empty)] +#![allow(clippy::iter_next_slice, clippy::redundant_clone)] + +fn array() { + assert_eq!(std::iter::empty().next(), Option::::None); + assert_eq!(std::iter::empty().next(), Option::<&mut i32>::None); + assert_eq!(std::iter::empty().next(), Option::<&i32>::None); + assert_eq!(std::iter::empty().next(), Option::::None); + assert_eq!(std::iter::empty().next(), Option::<&mut i32>::None); + assert_eq!(std::iter::empty().next(), Option::<&i32>::None); + + // Don't trigger on non-iter methods + let _: Option = None.clone(); + let _: [String; 0] = [].clone(); +} + +macro_rules! in_macros { + () => { + assert_eq!([].into_iter().next(), Option::::None); + assert_eq!([].iter_mut().next(), Option::<&mut i32>::None); + assert_eq!([].iter().next(), Option::<&i32>::None); + assert_eq!(None.into_iter().next(), Option::::None); + assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None); + assert_eq!(None.iter().next(), Option::<&i32>::None); + }; +} + +fn main() { + array(); + in_macros!(); +} diff --git a/tests/ui/iter_empty.rs b/tests/ui/iter_empty.rs new file mode 100644 index 000000000000..bb192fe16d1f --- /dev/null +++ b/tests/ui/iter_empty.rs @@ -0,0 +1,32 @@ +// run-rustfix +#![warn(clippy::iter_empty)] +#![allow(clippy::iter_next_slice, clippy::redundant_clone)] + +fn array() { + assert_eq!([].into_iter().next(), Option::::None); + assert_eq!([].iter_mut().next(), Option::<&mut i32>::None); + assert_eq!([].iter().next(), Option::<&i32>::None); + assert_eq!(None.into_iter().next(), Option::::None); + assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None); + assert_eq!(None.iter().next(), Option::<&i32>::None); + + // Don't trigger on non-iter methods + let _: Option = None.clone(); + let _: [String; 0] = [].clone(); +} + +macro_rules! in_macros { + () => { + assert_eq!([].into_iter().next(), Option::::None); + assert_eq!([].iter_mut().next(), Option::<&mut i32>::None); + assert_eq!([].iter().next(), Option::<&i32>::None); + assert_eq!(None.into_iter().next(), Option::::None); + assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None); + assert_eq!(None.iter().next(), Option::<&i32>::None); + }; +} + +fn main() { + array(); + in_macros!(); +} diff --git a/tests/ui/iter_empty.stderr b/tests/ui/iter_empty.stderr new file mode 100644 index 000000000000..f4f06e93b237 --- /dev/null +++ b/tests/ui/iter_empty.stderr @@ -0,0 +1,40 @@ +error: this `into_iter` call can be replaced with std::iter::empty + --> $DIR/iter_empty.rs:6:16 + | +LL | assert_eq!([].into_iter().next(), Option::::None); + | ^^^^^^^^^^^^^^ help: try: `std::iter::empty()` + | + = note: `-D clippy::iter-empty` implied by `-D warnings` + +error: this `iter_mut` call can be replaced with std::iter::empty + --> $DIR/iter_empty.rs:7:16 + | +LL | assert_eq!([].iter_mut().next(), Option::<&mut i32>::None); + | ^^^^^^^^^^^^^ help: try: `std::iter::empty()` + +error: this `iter call` can be replaced with std::iter::empty + --> $DIR/iter_empty.rs:8:16 + | +LL | assert_eq!([].iter().next(), Option::<&i32>::None); + | ^^^^^^^^^ help: try: `std::iter::empty()` + +error: this `into_iter` call can be replaced with std::iter::empty + --> $DIR/iter_empty.rs:9:16 + | +LL | assert_eq!(None.into_iter().next(), Option::::None); + | ^^^^^^^^^^^^^^^^ help: try: `std::iter::empty()` + +error: this `iter_mut` call can be replaced with std::iter::empty + --> $DIR/iter_empty.rs:10:16 + | +LL | assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None); + | ^^^^^^^^^^^^^^^ help: try: `std::iter::empty()` + +error: this `iter call` can be replaced with std::iter::empty + --> $DIR/iter_empty.rs:11:16 + | +LL | assert_eq!(None.iter().next(), Option::<&i32>::None); + | ^^^^^^^^^^^ help: try: `std::iter::empty()` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/iter_once.fixed b/tests/ui/iter_once.fixed new file mode 100644 index 000000000000..7247e34d7e86 --- /dev/null +++ b/tests/ui/iter_once.fixed @@ -0,0 +1,32 @@ +// run-rustfix +#![warn(clippy::iter_once)] +#![allow(clippy::iter_next_slice, clippy::redundant_clone)] + +fn array() { + assert_eq!(std::iter::once(123).next(), Some(123)); + assert_eq!(std::iter::once(&mut 123).next(), Some(&mut 123)); + assert_eq!(std::iter::once(&123).next(), Some(&123)); + assert_eq!(std::iter::once(123).next(), Some(123)); + assert_eq!(std::iter::once(&mut 123).next(), Some(&mut 123)); + assert_eq!(std::iter::once(&123).next(), Some(&123)); + + // Don't trigger on non-iter methods + let _: Option = Some("test".to_string()).clone(); + let _: [String; 1] = ["test".to_string()].clone(); +} + +macro_rules! in_macros { + () => { + assert_eq!([123].into_iter().next(), Some(123)); + assert_eq!([123].iter_mut().next(), Some(&mut 123)); + assert_eq!([123].iter().next(), Some(&123)); + assert_eq!(Some(123).into_iter().next(), Some(123)); + assert_eq!(Some(123).iter_mut().next(), Some(&mut 123)); + assert_eq!(Some(123).iter().next(), Some(&123)); + }; +} + +fn main() { + array(); + in_macros!(); +} diff --git a/tests/ui/iter_once.rs b/tests/ui/iter_once.rs new file mode 100644 index 000000000000..3a2b9c95cc53 --- /dev/null +++ b/tests/ui/iter_once.rs @@ -0,0 +1,32 @@ +// run-rustfix +#![warn(clippy::iter_once)] +#![allow(clippy::iter_next_slice, clippy::redundant_clone)] + +fn array() { + assert_eq!([123].into_iter().next(), Some(123)); + assert_eq!([123].iter_mut().next(), Some(&mut 123)); + assert_eq!([123].iter().next(), Some(&123)); + assert_eq!(Some(123).into_iter().next(), Some(123)); + assert_eq!(Some(123).iter_mut().next(), Some(&mut 123)); + assert_eq!(Some(123).iter().next(), Some(&123)); + + // Don't trigger on non-iter methods + let _: Option = Some("test".to_string()).clone(); + let _: [String; 1] = ["test".to_string()].clone(); +} + +macro_rules! in_macros { + () => { + assert_eq!([123].into_iter().next(), Some(123)); + assert_eq!([123].iter_mut().next(), Some(&mut 123)); + assert_eq!([123].iter().next(), Some(&123)); + assert_eq!(Some(123).into_iter().next(), Some(123)); + assert_eq!(Some(123).iter_mut().next(), Some(&mut 123)); + assert_eq!(Some(123).iter().next(), Some(&123)); + }; +} + +fn main() { + array(); + in_macros!(); +} diff --git a/tests/ui/iter_once.stderr b/tests/ui/iter_once.stderr new file mode 100644 index 000000000000..d9e8f96f7639 --- /dev/null +++ b/tests/ui/iter_once.stderr @@ -0,0 +1,40 @@ +error: this `into_iter` call can be replaced with std::iter::once + --> $DIR/iter_once.rs:6:16 + | +LL | assert_eq!([123].into_iter().next(), Some(123)); + | ^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(123)` + | + = note: `-D clippy::iter-once` implied by `-D warnings` + +error: this `iter_mut` call can be replaced with std::iter::once + --> $DIR/iter_once.rs:7:16 + | +LL | assert_eq!([123].iter_mut().next(), Some(&mut 123)); + | ^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&mut 123)` + +error: this `iter` call can be replaced with std::iter::once + --> $DIR/iter_once.rs:8:16 + | +LL | assert_eq!([123].iter().next(), Some(&123)); + | ^^^^^^^^^^^^ help: try: `std::iter::once(&123)` + +error: this `into_iter` call can be replaced with std::iter::once + --> $DIR/iter_once.rs:9:16 + | +LL | assert_eq!(Some(123).into_iter().next(), Some(123)); + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(123)` + +error: this `iter_mut` call can be replaced with std::iter::once + --> $DIR/iter_once.rs:10:16 + | +LL | assert_eq!(Some(123).iter_mut().next(), Some(&mut 123)); + | ^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&mut 123)` + +error: this `iter` call can be replaced with std::iter::once + --> $DIR/iter_once.rs:11:16 + | +LL | assert_eq!(Some(123).iter().next(), Some(&123)); + | ^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&123)` + +error: aborting due to 6 previous errors + From 332e03146e456ccedc1ab960fcdd739dd45080b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Sat, 16 Jul 2022 12:44:33 +0200 Subject: [PATCH 3688/5092] Fix the lint in clippy itself --- clippy_lints/src/dereference.rs | 2 +- clippy_lints/src/derive.rs | 5 ++++- clippy_lints/src/redundant_slicing.rs | 4 +++- clippy_lints/src/types/mod.rs | 1 + clippy_lints/src/utils/conf.rs | 2 +- clippy_lints/src/utils/internal_lints/metadata_collector.rs | 2 +- 6 files changed, 11 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 5d41c63928df..e0b94f7190af 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -760,7 +760,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & .and_then(|subs| subs.get(1..)) { Some(subs) => cx.tcx.mk_substs(subs.iter().copied()), - None => cx.tcx.mk_substs([].iter()), + None => cx.tcx.mk_substs(std::iter::empty::>()), } && let impl_ty = if cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref() { // Trait methods taking `&self` sub_ty diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index a982990e4186..9ca443b7dff6 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -516,7 +516,10 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> tcx.mk_predicates(ty_predicates.iter().map(|&(p, _)| p).chain( params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| { tcx.mk_predicate(Binder::dummy(PredicateKind::Trait(TraitPredicate { - trait_ref: TraitRef::new(eq_trait_id, tcx.mk_substs([tcx.mk_param_from_def(param)].into_iter())), + trait_ref: TraitRef::new( + eq_trait_id, + tcx.mk_substs(std::iter::once(tcx.mk_param_from_def(param))), + ), constness: BoundConstness::NotConst, polarity: ImplPolarity::Positive, }))) diff --git a/clippy_lints/src/redundant_slicing.rs b/clippy_lints/src/redundant_slicing.rs index db6c97f3739c..8693ca9af830 100644 --- a/clippy_lints/src/redundant_slicing.rs +++ b/clippy_lints/src/redundant_slicing.rs @@ -11,6 +11,8 @@ use rustc_middle::ty::adjustment::{Adjust, AutoBorrow, AutoBorrowMutability}; use rustc_middle::ty::subst::GenericArg; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use std::iter; + declare_clippy_lint! { /// ### What it does /// Checks for redundant slicing expressions which use the full range, and @@ -134,7 +136,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { } else if let Some(target_id) = cx.tcx.lang_items().deref_target() { if let Ok(deref_ty) = cx.tcx.try_normalize_erasing_regions( cx.param_env, - cx.tcx.mk_projection(target_id, cx.tcx.mk_substs([GenericArg::from(indexed_ty)].into_iter())), + cx.tcx.mk_projection(target_id, cx.tcx.mk_substs(iter::once(GenericArg::from(indexed_ty)))), ) { if deref_ty == expr_ty { let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0; diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index 353a6f6b899e..f3ba096237f5 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -490,6 +490,7 @@ impl Types { } } } + #[allow(clippy::iter_empty)] match *qpath { QPath::Resolved(Some(ty), p) => { context.is_nested_call = true; diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 3faae9ac0d2b..47b72f4783e3 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -350,7 +350,7 @@ define_Conf! { /// Lint: DISALLOWED_SCRIPT_IDENTS. /// /// The list of unicode scripts allowed to be used in the scope. - (allowed_scripts: Vec = ["Latin"].iter().map(ToString::to_string).collect()), + (allowed_scripts: Vec = vec!["Latin".to_string()]), /// Lint: NON_SEND_FIELDS_IN_SEND_TY. /// /// Whether to apply the raw pointer heuristic to determine if a type is `Send`. diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 92cf42c7ad43..b1148bccc2a2 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -797,7 +797,7 @@ fn get_lint_group_and_level_or_lint( let result = cx.lint_store.check_lint_name( lint_name, Some(sym::clippy), - &[Ident::with_dummy_span(sym::clippy)].into_iter().collect(), + &std::iter::once(Ident::with_dummy_span(sym::clippy)).collect(), ); if let CheckLintNameResult::Tool(Ok(lint_lst)) = result { if let Some(group) = get_lint_group(cx, lint_lst[0]) { From f3f86d8fd96dfa5986ffe10d0837169e473b9b83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Sat, 16 Jul 2022 23:07:06 +0200 Subject: [PATCH 3689/5092] Move iter_once and iter_empty to methods as a late pass This enables more thorough checking of types to avoid triggering on custom Some and None enum variants --- clippy_lints/src/iter_once_empty.rs | 164 -------------------- clippy_lints/src/lib.register_lints.rs | 4 +- clippy_lints/src/lib.register_pedantic.rs | 2 - clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/iter_once_empty.rs | 70 +++++++++ clippy_lints/src/methods/mod.rs | 81 ++++++++++ tests/ui/iter_empty.fixed | 23 +++ tests/ui/iter_empty.rs | 23 +++ tests/ui/iter_once.fixed | 23 +++ tests/ui/iter_once.rs | 23 +++ 10 files changed, 245 insertions(+), 170 deletions(-) delete mode 100644 clippy_lints/src/iter_once_empty.rs create mode 100644 clippy_lints/src/methods/iter_once_empty.rs diff --git a/clippy_lints/src/iter_once_empty.rs b/clippy_lints/src/iter_once_empty.rs deleted file mode 100644 index 098960011123..000000000000 --- a/clippy_lints/src/iter_once_empty.rs +++ /dev/null @@ -1,164 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet; -use rustc_ast::ast::{Expr, ExprKind}; -use rustc_errors::Applicability; -use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -declare_clippy_lint! { - /// ### What it does - /// - /// Checks for usage of: - /// - /// - `[foo].iter()` - /// - `[foo].iter_mut()` - /// - `[foo].into_iter()` - /// - `Some(foo).iter()` - /// - `Some(foo).iter_mut()` - /// - `Some(foo).into_iter()` - /// - /// ### Why is this bad? - /// - /// It is simpler to use the once function from the standard library: - /// - /// ### Example - /// - /// ```rust - /// let a = [123].iter(); - /// let b = Some(123).into_iter(); - /// ``` - /// Use instead: - /// ```rust - /// use std::iter; - /// let a = iter::once(&123); - /// let b = iter::once(123); - /// ``` - /// - /// ### Known problems - /// - /// The type of the resulting iterator might become incompatible with its usage - #[clippy::version = "1.64.0"] - pub ITER_ONCE, - nursery, - "Iterator for array of length 1" -} - -declare_clippy_lint! { - /// ### What it does - /// - /// Checks for usage of: - /// - /// - `[].iter()` - /// - `[].iter_mut()` - /// - `[].into_iter()` - /// - `None.iter()` - /// - `None.iter_mut()` - /// - `None.into_iter()` - /// - /// ### Why is this bad? - /// - /// It is simpler to use the empty function from the standard library: - /// - /// ### Example - /// - /// ```rust - /// use std::{slice, option}; - /// let a: slice::Iter = [].iter(); - /// let f: option::IntoIter = None.into_iter(); - /// ``` - /// Use instead: - /// ```rust - /// use std::iter; - /// let a: iter::Empty = iter::empty(); - /// let b: iter::Empty = iter::empty(); - /// ``` - /// - /// ### Known problems - /// - /// The type of the resulting iterator might become incompatible with its usage - #[clippy::version = "1.64.0"] - pub ITER_EMPTY, - nursery, - "Iterator for empty array" -} - -declare_lint_pass!(IterOnceEmpty => [ITER_ONCE, ITER_EMPTY]); - -impl EarlyLintPass for IterOnceEmpty { - fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { - if expr.span.from_expansion() { - // Don't lint match expressions present in - // macro_rules! block - return; - } - - let (method_name, args) = if let ExprKind::MethodCall(seg, args, _) = &expr.kind { - (seg.ident.as_str(), args) - } else { - return; - }; - let arg = if args.len() == 1 { - &args[0] - } else { - return; - }; - - let item = match &arg.kind { - ExprKind::Array(v) if v.len() <= 1 => v.first(), - ExprKind::Path(None, p) => { - if p.segments.len() == 1 && p.segments[0].ident.name == rustc_span::sym::None { - None - } else { - return; - } - }, - ExprKind::Call(f, some_args) if some_args.len() == 1 => { - if let ExprKind::Path(None, p) = &f.kind { - if p.segments.len() == 1 && p.segments[0].ident.name == rustc_span::sym::Some { - Some(&some_args[0]) - } else { - return; - } - } else { - return; - } - }, - _ => return, - }; - - if let Some(i) = item { - let (sugg, msg) = match method_name { - "iter" => ( - format!("std::iter::once(&{})", snippet(cx, i.span, "...")), - "this `iter` call can be replaced with std::iter::once", - ), - "iter_mut" => ( - format!("std::iter::once(&mut {})", snippet(cx, i.span, "...")), - "this `iter_mut` call can be replaced with std::iter::once", - ), - "into_iter" => ( - format!("std::iter::once({})", snippet(cx, i.span, "...")), - "this `into_iter` call can be replaced with std::iter::once", - ), - _ => return, - }; - span_lint_and_sugg(cx, ITER_ONCE, expr.span, msg, "try", sugg, Applicability::Unspecified); - } else { - let msg = match method_name { - "iter" => "this `iter call` can be replaced with std::iter::empty", - "iter_mut" => "this `iter_mut` call can be replaced with std::iter::empty", - "into_iter" => "this `into_iter` call can be replaced with std::iter::empty", - _ => return, - }; - span_lint_and_sugg( - cx, - ITER_EMPTY, - expr.span, - msg, - "try", - "std::iter::empty()".to_string(), - Applicability::Unspecified, - ); - } - } -} diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 49fc3a895274..e49321d83fa5 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -200,8 +200,6 @@ store.register_lints(&[ invalid_utf8_in_unchecked::INVALID_UTF8_IN_UNCHECKED, items_after_statements::ITEMS_AFTER_STATEMENTS, iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR, - iter_once_empty::ITER_EMPTY, - iter_once_empty::ITER_ONCE, large_const_arrays::LARGE_CONST_ARRAYS, large_enum_variant::LARGE_ENUM_VARIANT, large_include_file::LARGE_INCLUDE_FILE, @@ -314,9 +312,11 @@ store.register_lints(&[ methods::ITERATOR_STEP_BY_ZERO, methods::ITER_CLONED_COLLECT, methods::ITER_COUNT, + methods::ITER_EMPTY, methods::ITER_NEXT_SLICE, methods::ITER_NTH, methods::ITER_NTH_ZERO, + methods::ITER_ONCE, methods::ITER_OVEREAGER_CLONED, methods::ITER_SKIP_NEXT, methods::ITER_WITH_DRAIN, diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index 6063fb00a7b6..4250ee055e6c 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -41,8 +41,6 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS), LintId::of(items_after_statements::ITEMS_AFTER_STATEMENTS), LintId::of(iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR), - LintId::of(iter_once_empty::ITER_EMPTY), - LintId::of(iter_once_empty::ITER_ONCE), LintId::of(large_stack_arrays::LARGE_STACK_ARRAYS), LintId::of(let_underscore::LET_UNDERSCORE_DROP), LintId::of(literal_representation::LARGE_DIGIT_GROUPS), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 78279db9ad54..88c1a727f8dc 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -258,7 +258,6 @@ mod invalid_upcast_comparisons; mod invalid_utf8_in_unchecked; mod items_after_statements; mod iter_not_returning_iterator; -mod iter_once_empty; mod large_const_arrays; mod large_enum_variant; mod large_include_file; @@ -932,7 +931,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked)); store.register_late_pass(|| Box::new(std_instead_of_core::StdReexports::default())); store.register_late_pass(|| Box::new(manual_instant_elapsed::ManualInstantElapsed)); - store.register_early_pass(|| Box::new(iter_once_empty::IterOnceEmpty)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/methods/iter_once_empty.rs b/clippy_lints/src/methods/iter_once_empty.rs new file mode 100644 index 000000000000..d45dfc67880e --- /dev/null +++ b/clippy_lints/src/methods/iter_once_empty.rs @@ -0,0 +1,70 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_lang_ctor; +use clippy_utils::source::snippet; + +use rustc_errors::Applicability; +use rustc_hir::LangItem::{OptionNone, OptionSome}; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; + +use super::{ITER_EMPTY, ITER_ONCE}; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, method_name: &str, recv: &Expr<'_>) { + let item = match &recv.kind { + ExprKind::Array(v) if v.len() <= 1 => v.first(), + ExprKind::Path(p) => { + if is_lang_ctor(cx, p, OptionNone) { + None + } else { + return; + } + }, + ExprKind::Call(f, some_args) if some_args.len() == 1 => { + if let ExprKind::Path(p) = &f.kind { + if is_lang_ctor(cx, p, OptionSome) { + Some(&some_args[0]) + } else { + return; + } + } else { + return; + } + }, + _ => return, + }; + + if let Some(i) = item { + let (sugg, msg) = match method_name { + "iter" => ( + format!("std::iter::once(&{})", snippet(cx, i.span, "...")), + "this `iter` call can be replaced with std::iter::once", + ), + "iter_mut" => ( + format!("std::iter::once(&mut {})", snippet(cx, i.span, "...")), + "this `iter_mut` call can be replaced with std::iter::once", + ), + "into_iter" => ( + format!("std::iter::once({})", snippet(cx, i.span, "...")), + "this `into_iter` call can be replaced with std::iter::once", + ), + _ => return, + }; + span_lint_and_sugg(cx, ITER_ONCE, expr.span, msg, "try", sugg, Applicability::Unspecified); + } else { + let msg = match method_name { + "iter" => "this `iter call` can be replaced with std::iter::empty", + "iter_mut" => "this `iter_mut` call can be replaced with std::iter::empty", + "into_iter" => "this `into_iter` call can be replaced with std::iter::empty", + _ => return, + }; + span_lint_and_sugg( + cx, + ITER_EMPTY, + expr.span, + msg, + "try", + "std::iter::empty()".to_string(), + Applicability::Unspecified, + ); + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5ac6b09f0aa2..e449ae0e4247 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -33,6 +33,7 @@ mod iter_count; mod iter_next_slice; mod iter_nth; mod iter_nth_zero; +mod iter_once_empty; mod iter_overeager_cloned; mod iter_skip_next; mod iter_with_drain; @@ -2304,6 +2305,83 @@ declare_clippy_lint! { more clearly with `if .. else ..`" } +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for usage of: + /// + /// - `[foo].iter()` + /// - `[foo].iter_mut()` + /// - `[foo].into_iter()` + /// - `Some(foo).iter()` + /// - `Some(foo).iter_mut()` + /// - `Some(foo).into_iter()` + /// + /// ### Why is this bad? + /// + /// It is simpler to use the once function from the standard library: + /// + /// ### Example + /// + /// ```rust + /// let a = [123].iter(); + /// let b = Some(123).into_iter(); + /// ``` + /// Use instead: + /// ```rust + /// use std::iter; + /// let a = iter::once(&123); + /// let b = iter::once(123); + /// ``` + /// + /// ### Known problems + /// + /// The type of the resulting iterator might become incompatible with its usage + #[clippy::version = "1.64.0"] + pub ITER_ONCE, + nursery, + "Iterator for array of length 1" +} + +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for usage of: + /// + /// - `[].iter()` + /// - `[].iter_mut()` + /// - `[].into_iter()` + /// - `None.iter()` + /// - `None.iter_mut()` + /// - `None.into_iter()` + /// + /// ### Why is this bad? + /// + /// It is simpler to use the empty function from the standard library: + /// + /// ### Example + /// + /// ```rust + /// use std::{slice, option}; + /// let a: slice::Iter = [].iter(); + /// let f: option::IntoIter = None.into_iter(); + /// ``` + /// Use instead: + /// ```rust + /// use std::iter; + /// let a: iter::Empty = iter::empty(); + /// let b: iter::Empty = iter::empty(); + /// ``` + /// + /// ### Known problems + /// + /// The type of the resulting iterator might become incompatible with its usage + #[clippy::version = "1.64.0"] + pub ITER_EMPTY, + nursery, + "Iterator for empty array" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2406,6 +2484,8 @@ impl_lint_pass!(Methods => [ NEEDLESS_OPTION_TAKE, NO_EFFECT_REPLACE, OBFUSCATED_IF_ELSE, + ITER_ONCE, + ITER_EMPTY ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2708,6 +2788,7 @@ impl Methods { ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv), ("is_none", []) => check_is_some_is_none(cx, expr, recv, false), ("is_some", []) => check_is_some_is_none(cx, expr, recv, true), + ("iter" | "iter_mut" | "into_iter", []) => iter_once_empty::check(cx, expr, name, recv), ("join", [join_arg]) => { if let Some(("collect", _, span)) = method_call(recv) { unnecessary_join::check(cx, expr, recv, join_arg, span); diff --git a/tests/ui/iter_empty.fixed b/tests/ui/iter_empty.fixed index fb7118f0d4a0..690da5a87615 100644 --- a/tests/ui/iter_empty.fixed +++ b/tests/ui/iter_empty.fixed @@ -26,7 +26,30 @@ macro_rules! in_macros { }; } +// Don't trigger on a `None` that isn't std's option +mod custom_option { + #[allow(unused)] + enum CustomOption { + Some(i32), + None, + } + + impl CustomOption { + fn iter(&self) {} + fn iter_mut(&mut self) {} + fn into_iter(self) {} + } + use CustomOption::*; + + pub fn custom_option() { + None.iter(); + None.iter_mut(); + None.into_iter(); + } +} + fn main() { array(); + custom_option::custom_option(); in_macros!(); } diff --git a/tests/ui/iter_empty.rs b/tests/ui/iter_empty.rs index bb192fe16d1f..f8b56898f2d5 100644 --- a/tests/ui/iter_empty.rs +++ b/tests/ui/iter_empty.rs @@ -26,7 +26,30 @@ macro_rules! in_macros { }; } +// Don't trigger on a `None` that isn't std's option +mod custom_option { + #[allow(unused)] + enum CustomOption { + Some(i32), + None, + } + + impl CustomOption { + fn iter(&self) {} + fn iter_mut(&mut self) {} + fn into_iter(self) {} + } + use CustomOption::*; + + pub fn custom_option() { + None.iter(); + None.iter_mut(); + None.into_iter(); + } +} + fn main() { array(); + custom_option::custom_option(); in_macros!(); } diff --git a/tests/ui/iter_once.fixed b/tests/ui/iter_once.fixed index 7247e34d7e86..0c82ab20be1c 100644 --- a/tests/ui/iter_once.fixed +++ b/tests/ui/iter_once.fixed @@ -26,7 +26,30 @@ macro_rules! in_macros { }; } +// Don't trigger on a `Some` that isn't std's option +mod custom_option { + #[allow(unused)] + enum CustomOption { + Some(i32), + None, + } + + impl CustomOption { + fn iter(&self) {} + fn iter_mut(&mut self) {} + fn into_iter(self) {} + } + use CustomOption::*; + + pub fn custom_option() { + Some(3).iter(); + Some(3).iter_mut(); + Some(3).into_iter(); + } +} + fn main() { array(); + custom_option::custom_option(); in_macros!(); } diff --git a/tests/ui/iter_once.rs b/tests/ui/iter_once.rs index 3a2b9c95cc53..d561bf27c1df 100644 --- a/tests/ui/iter_once.rs +++ b/tests/ui/iter_once.rs @@ -26,7 +26,30 @@ macro_rules! in_macros { }; } +// Don't trigger on a `Some` that isn't std's option +mod custom_option { + #[allow(unused)] + enum CustomOption { + Some(i32), + None, + } + + impl CustomOption { + fn iter(&self) {} + fn iter_mut(&mut self) {} + fn into_iter(self) {} + } + use CustomOption::*; + + pub fn custom_option() { + Some(3).iter(); + Some(3).iter_mut(); + Some(3).into_iter(); + } +} + fn main() { array(); + custom_option::custom_option(); in_macros!(); } From f30d7c2495b3188bfa0cf8bd6dbbf76494c9845e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Tue, 19 Jul 2022 22:08:03 +0200 Subject: [PATCH 3690/5092] Improve suggestions --- clippy_lints/src/methods/iter_once_empty.rs | 70 +++++++++++++-------- clippy_lints/src/methods/mod.rs | 18 +----- tests/ui/iter_empty.stderr | 12 ++-- tests/ui/iter_once.stderr | 12 ++-- 4 files changed, 59 insertions(+), 53 deletions(-) diff --git a/clippy_lints/src/methods/iter_once_empty.rs b/clippy_lints/src/methods/iter_once_empty.rs index d45dfc67880e..82fafb8a45ee 100644 --- a/clippy_lints/src/methods/iter_once_empty.rs +++ b/clippy_lints/src/methods/iter_once_empty.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_lang_ctor; +use clippy_utils::is_no_std_crate; use clippy_utils::source::snippet; use rustc_errors::Applicability; @@ -9,6 +10,22 @@ use rustc_lint::LateContext; use super::{ITER_EMPTY, ITER_ONCE}; +enum IterType { + Iter, + IterMut, + IntoIter, +} + +impl IterType { + fn ref_prefix(&self) -> &'static str { + match self { + Self::Iter => "&", + Self::IterMut => "&mut ", + Self::IntoIter => "", + } + } +} + pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, method_name: &str, recv: &Expr<'_>) { let item = match &recv.kind { ExprKind::Array(v) if v.len() <= 1 => v.first(), @@ -32,39 +49,42 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, method_name: }, _ => return, }; + let iter_type = match method_name { + "iter" => IterType::Iter, + "iter_mut" => IterType::IterMut, + "into_iter" => IterType::IntoIter, + _ => return, + }; if let Some(i) = item { - let (sugg, msg) = match method_name { - "iter" => ( - format!("std::iter::once(&{})", snippet(cx, i.span, "...")), - "this `iter` call can be replaced with std::iter::once", - ), - "iter_mut" => ( - format!("std::iter::once(&mut {})", snippet(cx, i.span, "...")), - "this `iter_mut` call can be replaced with std::iter::once", - ), - "into_iter" => ( - format!("std::iter::once({})", snippet(cx, i.span, "...")), - "this `into_iter` call can be replaced with std::iter::once", - ), - _ => return, - }; - span_lint_and_sugg(cx, ITER_ONCE, expr.span, msg, "try", sugg, Applicability::Unspecified); + let sugg = format!( + "{}::iter::once({}{})", + if is_no_std_crate(cx) { "core" } else { "std" }, + iter_type.ref_prefix(), + snippet(cx, i.span, "...") + ); + span_lint_and_sugg( + cx, + ITER_ONCE, + expr.span, + &format!("`{method_name}` call on a collection with only one item"), + "try", + sugg, + Applicability::MaybeIncorrect, + ); } else { - let msg = match method_name { - "iter" => "this `iter call` can be replaced with std::iter::empty", - "iter_mut" => "this `iter_mut` call can be replaced with std::iter::empty", - "into_iter" => "this `into_iter` call can be replaced with std::iter::empty", - _ => return, - }; span_lint_and_sugg( cx, ITER_EMPTY, expr.span, - msg, + &format!("`{method_name}` call on an empty collection"), "try", - "std::iter::empty()".to_string(), - Applicability::Unspecified, + if is_no_std_crate(cx) { + "core::iter::empty()".to_string() + } else { + "std::iter::empty()".to_string() + }, + Applicability::MaybeIncorrect, ); } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e449ae0e4247..015cd094a9e0 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2308,14 +2308,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does /// - /// Checks for usage of: - /// - /// - `[foo].iter()` - /// - `[foo].iter_mut()` - /// - `[foo].into_iter()` - /// - `Some(foo).iter()` - /// - `Some(foo).iter_mut()` - /// - `Some(foo).into_iter()` + /// Checks for calls to `iter`, `iter_mut` or `into_iter` on collections containing a single item /// /// ### Why is this bad? /// @@ -2346,14 +2339,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does /// - /// Checks for usage of: - /// - /// - `[].iter()` - /// - `[].iter_mut()` - /// - `[].into_iter()` - /// - `None.iter()` - /// - `None.iter_mut()` - /// - `None.into_iter()` + /// Checks for calls to `iter`, `iter_mut` or `into_iter` on empty collections /// /// ### Why is this bad? /// diff --git a/tests/ui/iter_empty.stderr b/tests/ui/iter_empty.stderr index f4f06e93b237..40c08e6f82bd 100644 --- a/tests/ui/iter_empty.stderr +++ b/tests/ui/iter_empty.stderr @@ -1,4 +1,4 @@ -error: this `into_iter` call can be replaced with std::iter::empty +error: `into_iter` call on an empty collection --> $DIR/iter_empty.rs:6:16 | LL | assert_eq!([].into_iter().next(), Option::::None); @@ -6,31 +6,31 @@ LL | assert_eq!([].into_iter().next(), Option::::None); | = note: `-D clippy::iter-empty` implied by `-D warnings` -error: this `iter_mut` call can be replaced with std::iter::empty +error: `iter_mut` call on an empty collection --> $DIR/iter_empty.rs:7:16 | LL | assert_eq!([].iter_mut().next(), Option::<&mut i32>::None); | ^^^^^^^^^^^^^ help: try: `std::iter::empty()` -error: this `iter call` can be replaced with std::iter::empty +error: `iter` call on an empty collection --> $DIR/iter_empty.rs:8:16 | LL | assert_eq!([].iter().next(), Option::<&i32>::None); | ^^^^^^^^^ help: try: `std::iter::empty()` -error: this `into_iter` call can be replaced with std::iter::empty +error: `into_iter` call on an empty collection --> $DIR/iter_empty.rs:9:16 | LL | assert_eq!(None.into_iter().next(), Option::::None); | ^^^^^^^^^^^^^^^^ help: try: `std::iter::empty()` -error: this `iter_mut` call can be replaced with std::iter::empty +error: `iter_mut` call on an empty collection --> $DIR/iter_empty.rs:10:16 | LL | assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None); | ^^^^^^^^^^^^^^^ help: try: `std::iter::empty()` -error: this `iter call` can be replaced with std::iter::empty +error: `iter` call on an empty collection --> $DIR/iter_empty.rs:11:16 | LL | assert_eq!(None.iter().next(), Option::<&i32>::None); diff --git a/tests/ui/iter_once.stderr b/tests/ui/iter_once.stderr index d9e8f96f7639..b22c8a99f10b 100644 --- a/tests/ui/iter_once.stderr +++ b/tests/ui/iter_once.stderr @@ -1,4 +1,4 @@ -error: this `into_iter` call can be replaced with std::iter::once +error: `into_iter` call on a collection with only one item --> $DIR/iter_once.rs:6:16 | LL | assert_eq!([123].into_iter().next(), Some(123)); @@ -6,31 +6,31 @@ LL | assert_eq!([123].into_iter().next(), Some(123)); | = note: `-D clippy::iter-once` implied by `-D warnings` -error: this `iter_mut` call can be replaced with std::iter::once +error: `iter_mut` call on a collection with only one item --> $DIR/iter_once.rs:7:16 | LL | assert_eq!([123].iter_mut().next(), Some(&mut 123)); | ^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&mut 123)` -error: this `iter` call can be replaced with std::iter::once +error: `iter` call on a collection with only one item --> $DIR/iter_once.rs:8:16 | LL | assert_eq!([123].iter().next(), Some(&123)); | ^^^^^^^^^^^^ help: try: `std::iter::once(&123)` -error: this `into_iter` call can be replaced with std::iter::once +error: `into_iter` call on a collection with only one item --> $DIR/iter_once.rs:9:16 | LL | assert_eq!(Some(123).into_iter().next(), Some(123)); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(123)` -error: this `iter_mut` call can be replaced with std::iter::once +error: `iter_mut` call on a collection with only one item --> $DIR/iter_once.rs:10:16 | LL | assert_eq!(Some(123).iter_mut().next(), Some(&mut 123)); | ^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&mut 123)` -error: this `iter` call can be replaced with std::iter::once +error: `iter` call on a collection with only one item --> $DIR/iter_once.rs:11:16 | LL | assert_eq!(Some(123).iter().next(), Some(&123)); From b247594a39cb8e2c3d8d193860eac0eb1c63e1ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Thu, 28 Jul 2022 22:54:23 +0200 Subject: [PATCH 3691/5092] Prevent some false positives --- clippy_lints/src/methods/iter_once_empty.rs | 23 ++++++++++++++++++--- clippy_lints/src/types/mod.rs | 1 - clippy_utils/src/lib.rs | 1 - tests/ui/iter_empty.fixed | 8 +++++++ tests/ui/iter_empty.rs | 8 +++++++ tests/ui/iter_once.fixed | 8 +++++++ tests/ui/iter_once.rs | 8 +++++++ 7 files changed, 52 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/methods/iter_once_empty.rs b/clippy_lints/src/methods/iter_once_empty.rs index 82fafb8a45ee..96b1484528c7 100644 --- a/clippy_lints/src/methods/iter_once_empty.rs +++ b/clippy_lints/src/methods/iter_once_empty.rs @@ -1,11 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_lang_ctor; -use clippy_utils::is_no_std_crate; use clippy_utils::source::snippet; +use clippy_utils::{get_expr_use_or_unification_node, is_lang_ctor, is_no_std_crate}; use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionNone, OptionSome}; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, Node}; use rustc_lint::LateContext; use super::{ITER_EMPTY, ITER_ONCE}; @@ -56,6 +55,24 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, method_name: _ => return, }; + let is_unified = match get_expr_use_or_unification_node(cx.tcx, expr) { + Some((Node::Expr(parent), child_id)) => match parent.kind { + ExprKind::If(e, _, _) | ExprKind::Match(e, _, _) if e.hir_id == child_id => false, + ExprKind::If(_, _, _) + | ExprKind::Match(_, _, _) + | ExprKind::Closure(_) + | ExprKind::Ret(_) + | ExprKind::Break(_, _) => true, + _ => false, + }, + Some((Node::Stmt(_) | Node::Local(_), _)) => false, + _ => true, + }; + + if is_unified { + return; + } + if let Some(i) = item { let sugg = format!( "{}::iter::once({}{})", diff --git a/clippy_lints/src/types/mod.rs b/clippy_lints/src/types/mod.rs index f3ba096237f5..353a6f6b899e 100644 --- a/clippy_lints/src/types/mod.rs +++ b/clippy_lints/src/types/mod.rs @@ -490,7 +490,6 @@ impl Types { } } } - #[allow(clippy::iter_empty)] match *qpath { QPath::Resolved(Some(ty), p) => { context.is_nested_call = true; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 9c58978a0703..dcfc03475b42 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -484,7 +484,6 @@ pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res { } fn find_primitive<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator + 'tcx { let single = |ty| tcx.incoherent_impls(ty).iter().copied(); - #[allow(clippy::iter_empty)] let empty = || [].iter().copied(); match name { "bool" => single(BoolSimplifiedType), diff --git a/tests/ui/iter_empty.fixed b/tests/ui/iter_empty.fixed index 690da5a87615..ad1e106d2b1c 100644 --- a/tests/ui/iter_empty.fixed +++ b/tests/ui/iter_empty.fixed @@ -13,6 +13,14 @@ fn array() { // Don't trigger on non-iter methods let _: Option = None.clone(); let _: [String; 0] = [].clone(); + + // Don't trigger on match or if branches + let _ = match 123 { + 123 => [].iter(), + _ => ["test"].iter(), + }; + + let _ = if false { ["test"].iter() } else { [].iter() }; } macro_rules! in_macros { diff --git a/tests/ui/iter_empty.rs b/tests/ui/iter_empty.rs index f8b56898f2d5..625149b5da51 100644 --- a/tests/ui/iter_empty.rs +++ b/tests/ui/iter_empty.rs @@ -13,6 +13,14 @@ fn array() { // Don't trigger on non-iter methods let _: Option = None.clone(); let _: [String; 0] = [].clone(); + + // Don't trigger on match or if branches + let _ = match 123 { + 123 => [].iter(), + _ => ["test"].iter(), + }; + + let _ = if false { ["test"].iter() } else { [].iter() }; } macro_rules! in_macros { diff --git a/tests/ui/iter_once.fixed b/tests/ui/iter_once.fixed index 0c82ab20be1c..0495bc47e4b2 100644 --- a/tests/ui/iter_once.fixed +++ b/tests/ui/iter_once.fixed @@ -13,6 +13,14 @@ fn array() { // Don't trigger on non-iter methods let _: Option = Some("test".to_string()).clone(); let _: [String; 1] = ["test".to_string()].clone(); + + // Don't trigger on match or if branches + let _ = match 123 { + 123 => [].iter(), + _ => ["test"].iter(), + }; + + let _ = if false { ["test"].iter() } else { [].iter() }; } macro_rules! in_macros { diff --git a/tests/ui/iter_once.rs b/tests/ui/iter_once.rs index d561bf27c1df..96641109bb98 100644 --- a/tests/ui/iter_once.rs +++ b/tests/ui/iter_once.rs @@ -13,6 +13,14 @@ fn array() { // Don't trigger on non-iter methods let _: Option = Some("test".to_string()).clone(); let _: [String; 1] = ["test".to_string()].clone(); + + // Don't trigger on match or if branches + let _ = match 123 { + 123 => [].iter(), + _ => ["test"].iter(), + }; + + let _ = if false { ["test"].iter() } else { [].iter() }; } macro_rules! in_macros { From af4885c0cde76bf1faace76dc8fb53d3d4791422 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Sat, 30 Jul 2022 13:39:55 +0200 Subject: [PATCH 3692/5092] Rename new lints to iter_on_empty_collections and iter_on_single_items --- CHANGELOG.md | 4 ++-- clippy_lints/src/lib.register_lints.rs | 4 ++-- clippy_lints/src/lib.register_nursery.rs | 4 ++-- ...y.rs => iter_on_single_or_empty_collections.rs} | 6 +++--- clippy_lints/src/methods/mod.rs | 14 ++++++++------ ...empty.fixed => iter_on_empty_collections.fixed} | 2 +- ...{iter_empty.rs => iter_on_empty_collections.rs} | 2 +- ...pty.stderr => iter_on_empty_collections.stderr} | 14 +++++++------- ...{iter_once.fixed => iter_on_single_items.fixed} | 2 +- tests/ui/{iter_once.rs => iter_on_single_items.rs} | 2 +- ...ter_once.stderr => iter_on_single_items.stderr} | 14 +++++++------- 11 files changed, 35 insertions(+), 33 deletions(-) rename clippy_lints/src/methods/{iter_once_empty.rs => iter_on_single_or_empty_collections.rs} (95%) rename tests/ui/{iter_empty.fixed => iter_on_empty_collections.fixed} (97%) rename tests/ui/{iter_empty.rs => iter_on_empty_collections.rs} (97%) rename tests/ui/{iter_empty.stderr => iter_on_empty_collections.stderr} (76%) rename tests/ui/{iter_once.fixed => iter_on_single_items.fixed} (97%) rename tests/ui/{iter_once.rs => iter_on_single_items.rs} (97%) rename tests/ui/{iter_once.stderr => iter_on_single_items.stderr} (79%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94f71eba0a29..03a76ccf6071 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3651,13 +3651,13 @@ Released 2018-09-13 [`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements [`iter_cloned_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect [`iter_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_count -[`iter_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_empty [`iter_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop [`iter_next_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_slice [`iter_not_returning_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_not_returning_iterator [`iter_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth [`iter_nth_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth_zero -[`iter_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_once +[`iter_on_empty_collections`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_on_empty_collections +[`iter_on_single_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_on_single_items [`iter_overeager_cloned`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_overeager_cloned [`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next [`iter_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_with_drain diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index e49321d83fa5..b697eb76290d 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -312,11 +312,11 @@ store.register_lints(&[ methods::ITERATOR_STEP_BY_ZERO, methods::ITER_CLONED_COLLECT, methods::ITER_COUNT, - methods::ITER_EMPTY, methods::ITER_NEXT_SLICE, methods::ITER_NTH, methods::ITER_NTH_ZERO, - methods::ITER_ONCE, + methods::ITER_ON_EMPTY_COLLECTIONS, + methods::ITER_ON_SINGLE_ITEMS, methods::ITER_OVEREAGER_CLONED, methods::ITER_SKIP_NEXT, methods::ITER_WITH_DRAIN, diff --git a/clippy_lints/src/lib.register_nursery.rs b/clippy_lints/src/lib.register_nursery.rs index 9953aca43ee2..d65901926553 100644 --- a/clippy_lints/src/lib.register_nursery.rs +++ b/clippy_lints/src/lib.register_nursery.rs @@ -14,8 +14,8 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(index_refutable_slice::INDEX_REFUTABLE_SLICE), LintId::of(let_if_seq::USELESS_LET_IF_SEQ), LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE), - LintId::of(methods::ITER_EMPTY), - LintId::of(methods::ITER_ONCE), + LintId::of(methods::ITER_ON_EMPTY_COLLECTIONS), + LintId::of(methods::ITER_ON_SINGLE_ITEMS), LintId::of(methods::ITER_WITH_DRAIN), LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN), LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), diff --git a/clippy_lints/src/methods/iter_once_empty.rs b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs similarity index 95% rename from clippy_lints/src/methods/iter_once_empty.rs rename to clippy_lints/src/methods/iter_on_single_or_empty_collections.rs index 96b1484528c7..cea7b0d82ff3 100644 --- a/clippy_lints/src/methods/iter_once_empty.rs +++ b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs @@ -7,7 +7,7 @@ use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Expr, ExprKind, Node}; use rustc_lint::LateContext; -use super::{ITER_EMPTY, ITER_ONCE}; +use super::{ITER_ON_EMPTY_COLLECTIONS, ITER_ON_SINGLE_ITEMS}; enum IterType { Iter, @@ -82,7 +82,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, method_name: ); span_lint_and_sugg( cx, - ITER_ONCE, + ITER_ON_SINGLE_ITEMS, expr.span, &format!("`{method_name}` call on a collection with only one item"), "try", @@ -92,7 +92,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, method_name: } else { span_lint_and_sugg( cx, - ITER_EMPTY, + ITER_ON_EMPTY_COLLECTIONS, expr.span, &format!("`{method_name}` call on an empty collection"), "try", diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 015cd094a9e0..0936a3f48ca2 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -33,7 +33,7 @@ mod iter_count; mod iter_next_slice; mod iter_nth; mod iter_nth_zero; -mod iter_once_empty; +mod iter_on_single_or_empty_collections; mod iter_overeager_cloned; mod iter_skip_next; mod iter_with_drain; @@ -2331,7 +2331,7 @@ declare_clippy_lint! { /// /// The type of the resulting iterator might become incompatible with its usage #[clippy::version = "1.64.0"] - pub ITER_ONCE, + pub ITER_ON_SINGLE_ITEMS, nursery, "Iterator for array of length 1" } @@ -2363,7 +2363,7 @@ declare_clippy_lint! { /// /// The type of the resulting iterator might become incompatible with its usage #[clippy::version = "1.64.0"] - pub ITER_EMPTY, + pub ITER_ON_EMPTY_COLLECTIONS, nursery, "Iterator for empty array" } @@ -2470,8 +2470,8 @@ impl_lint_pass!(Methods => [ NEEDLESS_OPTION_TAKE, NO_EFFECT_REPLACE, OBFUSCATED_IF_ELSE, - ITER_ONCE, - ITER_EMPTY + ITER_ON_SINGLE_ITEMS, + ITER_ON_EMPTY_COLLECTIONS ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2774,7 +2774,9 @@ impl Methods { ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv), ("is_none", []) => check_is_some_is_none(cx, expr, recv, false), ("is_some", []) => check_is_some_is_none(cx, expr, recv, true), - ("iter" | "iter_mut" | "into_iter", []) => iter_once_empty::check(cx, expr, name, recv), + ("iter" | "iter_mut" | "into_iter", []) => { + iter_on_single_or_empty_collections::check(cx, expr, name, recv); + }, ("join", [join_arg]) => { if let Some(("collect", _, span)) = method_call(recv) { unnecessary_join::check(cx, expr, recv, join_arg, span); diff --git a/tests/ui/iter_empty.fixed b/tests/ui/iter_on_empty_collections.fixed similarity index 97% rename from tests/ui/iter_empty.fixed rename to tests/ui/iter_on_empty_collections.fixed index ad1e106d2b1c..bd9b07aefbfb 100644 --- a/tests/ui/iter_empty.fixed +++ b/tests/ui/iter_on_empty_collections.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![warn(clippy::iter_empty)] +#![warn(clippy::iter_on_empty_collections)] #![allow(clippy::iter_next_slice, clippy::redundant_clone)] fn array() { diff --git a/tests/ui/iter_empty.rs b/tests/ui/iter_on_empty_collections.rs similarity index 97% rename from tests/ui/iter_empty.rs rename to tests/ui/iter_on_empty_collections.rs index 625149b5da51..e15ba94bd465 100644 --- a/tests/ui/iter_empty.rs +++ b/tests/ui/iter_on_empty_collections.rs @@ -1,5 +1,5 @@ // run-rustfix -#![warn(clippy::iter_empty)] +#![warn(clippy::iter_on_empty_collections)] #![allow(clippy::iter_next_slice, clippy::redundant_clone)] fn array() { diff --git a/tests/ui/iter_empty.stderr b/tests/ui/iter_on_empty_collections.stderr similarity index 76% rename from tests/ui/iter_empty.stderr rename to tests/ui/iter_on_empty_collections.stderr index 40c08e6f82bd..cbd611769569 100644 --- a/tests/ui/iter_empty.stderr +++ b/tests/ui/iter_on_empty_collections.stderr @@ -1,37 +1,37 @@ error: `into_iter` call on an empty collection - --> $DIR/iter_empty.rs:6:16 + --> $DIR/iter_on_empty_collections.rs:6:16 | LL | assert_eq!([].into_iter().next(), Option::::None); | ^^^^^^^^^^^^^^ help: try: `std::iter::empty()` | - = note: `-D clippy::iter-empty` implied by `-D warnings` + = note: `-D clippy::iter-on-empty-collections` implied by `-D warnings` error: `iter_mut` call on an empty collection - --> $DIR/iter_empty.rs:7:16 + --> $DIR/iter_on_empty_collections.rs:7:16 | LL | assert_eq!([].iter_mut().next(), Option::<&mut i32>::None); | ^^^^^^^^^^^^^ help: try: `std::iter::empty()` error: `iter` call on an empty collection - --> $DIR/iter_empty.rs:8:16 + --> $DIR/iter_on_empty_collections.rs:8:16 | LL | assert_eq!([].iter().next(), Option::<&i32>::None); | ^^^^^^^^^ help: try: `std::iter::empty()` error: `into_iter` call on an empty collection - --> $DIR/iter_empty.rs:9:16 + --> $DIR/iter_on_empty_collections.rs:9:16 | LL | assert_eq!(None.into_iter().next(), Option::::None); | ^^^^^^^^^^^^^^^^ help: try: `std::iter::empty()` error: `iter_mut` call on an empty collection - --> $DIR/iter_empty.rs:10:16 + --> $DIR/iter_on_empty_collections.rs:10:16 | LL | assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None); | ^^^^^^^^^^^^^^^ help: try: `std::iter::empty()` error: `iter` call on an empty collection - --> $DIR/iter_empty.rs:11:16 + --> $DIR/iter_on_empty_collections.rs:11:16 | LL | assert_eq!(None.iter().next(), Option::<&i32>::None); | ^^^^^^^^^^^ help: try: `std::iter::empty()` diff --git a/tests/ui/iter_once.fixed b/tests/ui/iter_on_single_items.fixed similarity index 97% rename from tests/ui/iter_once.fixed rename to tests/ui/iter_on_single_items.fixed index 0495bc47e4b2..1fa4b03641bc 100644 --- a/tests/ui/iter_once.fixed +++ b/tests/ui/iter_on_single_items.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![warn(clippy::iter_once)] +#![warn(clippy::iter_on_single_items)] #![allow(clippy::iter_next_slice, clippy::redundant_clone)] fn array() { diff --git a/tests/ui/iter_once.rs b/tests/ui/iter_on_single_items.rs similarity index 97% rename from tests/ui/iter_once.rs rename to tests/ui/iter_on_single_items.rs index 96641109bb98..ea96d8066c56 100644 --- a/tests/ui/iter_once.rs +++ b/tests/ui/iter_on_single_items.rs @@ -1,5 +1,5 @@ // run-rustfix -#![warn(clippy::iter_once)] +#![warn(clippy::iter_on_single_items)] #![allow(clippy::iter_next_slice, clippy::redundant_clone)] fn array() { diff --git a/tests/ui/iter_once.stderr b/tests/ui/iter_on_single_items.stderr similarity index 79% rename from tests/ui/iter_once.stderr rename to tests/ui/iter_on_single_items.stderr index b22c8a99f10b..d6c547116363 100644 --- a/tests/ui/iter_once.stderr +++ b/tests/ui/iter_on_single_items.stderr @@ -1,37 +1,37 @@ error: `into_iter` call on a collection with only one item - --> $DIR/iter_once.rs:6:16 + --> $DIR/iter_on_single_items.rs:6:16 | LL | assert_eq!([123].into_iter().next(), Some(123)); | ^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(123)` | - = note: `-D clippy::iter-once` implied by `-D warnings` + = note: `-D clippy::iter-on-single-items` implied by `-D warnings` error: `iter_mut` call on a collection with only one item - --> $DIR/iter_once.rs:7:16 + --> $DIR/iter_on_single_items.rs:7:16 | LL | assert_eq!([123].iter_mut().next(), Some(&mut 123)); | ^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&mut 123)` error: `iter` call on a collection with only one item - --> $DIR/iter_once.rs:8:16 + --> $DIR/iter_on_single_items.rs:8:16 | LL | assert_eq!([123].iter().next(), Some(&123)); | ^^^^^^^^^^^^ help: try: `std::iter::once(&123)` error: `into_iter` call on a collection with only one item - --> $DIR/iter_once.rs:9:16 + --> $DIR/iter_on_single_items.rs:9:16 | LL | assert_eq!(Some(123).into_iter().next(), Some(123)); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(123)` error: `iter_mut` call on a collection with only one item - --> $DIR/iter_once.rs:10:16 + --> $DIR/iter_on_single_items.rs:10:16 | LL | assert_eq!(Some(123).iter_mut().next(), Some(&mut 123)); | ^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&mut 123)` error: `iter` call on a collection with only one item - --> $DIR/iter_once.rs:11:16 + --> $DIR/iter_on_single_items.rs:11:16 | LL | assert_eq!(Some(123).iter().next(), Some(&123)); | ^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&123)` From d630671a33942988391a6a5b52ae0346057e2cf7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Aug 2022 16:27:44 -0400 Subject: [PATCH 3693/5092] move atomic access alginment check to helper function and inside atomic access lib --- src/concurrency/data_race.rs | 27 ++++++++++++++- src/shims/intrinsics/atomic.rs | 63 +++------------------------------- 2 files changed, 30 insertions(+), 60 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 6ea87a82cb92..65f198f3c9dd 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -49,7 +49,7 @@ use std::{ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::{mir, ty::layout::TyAndLayout}; -use rustc_target::abi::Size; +use rustc_target::abi::{Align, Size}; use crate::*; @@ -463,6 +463,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { this.write_scalar_atomic(value.into(), &value_place, atomic) } + /// Checks that an atomic access is legal at the given place. + fn atomic_access_check(&self, place: &MPlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { + let this = self.eval_context_ref(); + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.check_ptr_access_align( + place.ptr, + place.layout.size, + align, + CheckInAllocMsg::MemoryAccessTest, + )?; + Ok(()) + } + /// Perform an atomic read operation at the memory location. fn read_scalar_atomic( &self, @@ -470,6 +486,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicReadOrd, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_ref(); + this.atomic_access_check(place)?; // This will read from the last store in the modification order of this location. In case // weak memory emulation is enabled, this may not be the store we will pick to actually read from and return. // This is fine with StackedBorrow and race checks because they don't concern metadata on @@ -490,6 +507,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicWriteOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + this.atomic_access_check(dest)?; + this.validate_overlapping_atomic(dest)?; this.allow_data_races_mut(move |this| this.write_scalar(val, &dest.into()))?; this.validate_atomic_store(dest, atomic)?; @@ -511,6 +530,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicRwOrd, ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { let this = self.eval_context_mut(); + this.atomic_access_check(place)?; this.validate_overlapping_atomic(place)?; let old = this.allow_data_races_mut(|this| this.read_immediate(&place.into()))?; @@ -540,6 +560,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicRwOrd, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_mut(); + this.atomic_access_check(place)?; this.validate_overlapping_atomic(place)?; let old = this.allow_data_races_mut(|this| this.read_scalar(&place.into()))?; @@ -561,6 +582,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicRwOrd, ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { let this = self.eval_context_mut(); + this.atomic_access_check(place)?; this.validate_overlapping_atomic(place)?; let old = this.allow_data_races_mut(|this| this.read_immediate(&place.into()))?; @@ -604,6 +626,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> InterpResult<'tcx, Immediate> { use rand::Rng as _; let this = self.eval_context_mut(); + this.atomic_access_check(place)?; this.validate_overlapping_atomic(place)?; // Failure ordering cannot be stronger than success ordering, therefore first attempt @@ -1016,6 +1039,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { fn allow_data_races_ref(&self, op: impl FnOnce(&MiriEvalContext<'mir, 'tcx>) -> R) -> R { let this = self.eval_context_ref(); if let Some(data_race) = &this.machine.data_race { + assert!(!data_race.ongoing_action_data_race_free.get(), "cannot nest allow_data_races"); data_race.ongoing_action_data_race_free.set(true); } let result = op(this); @@ -1035,6 +1059,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> R { let this = self.eval_context_mut(); if let Some(data_race) = &this.machine.data_race { + assert!(!data_race.ongoing_action_data_race_free.get(), "cannot nest allow_data_races"); data_race.ongoing_action_data_race_free.set(true); } let result = op(this); diff --git a/src/shims/intrinsics/atomic.rs b/src/shims/intrinsics/atomic.rs index 8e0bb746e3cd..752bc0e302e7 100644 --- a/src/shims/intrinsics/atomic.rs +++ b/src/shims/intrinsics/atomic.rs @@ -1,5 +1,4 @@ use rustc_middle::{mir, mir::BinOp, ty}; -use rustc_target::abi::Align; use crate::*; use helpers::check_arg_count; @@ -130,20 +129,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [place] = check_arg_count(args)?; let place = this.deref_operand(place)?; - // make sure it fits into a scalar; otherwise it cannot be atomic + // Perform atomic load. let val = this.read_scalar_atomic(&place, atomic)?; - - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.check_ptr_access_align( - place.ptr, - place.layout.size, - align, - CheckInAllocMsg::MemoryAccessTest, - )?; - // Perform regular access. + // Perform regular store. this.write_scalar(val, dest)?; Ok(()) } @@ -157,19 +145,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [place, val] = check_arg_count(args)?; let place = this.deref_operand(place)?; - let val = this.read_scalar(val)?; // make sure it fits into a scalar; otherwise it cannot be atomic - - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.check_ptr_access_align( - place.ptr, - place.layout.size, - align, - CheckInAllocMsg::MemoryAccessTest, - )?; + // Perform regular load. + let val = this.read_scalar(val)?; // Perform atomic store this.write_scalar_atomic(val, &place, atomic)?; Ok(()) @@ -220,17 +198,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx span_bug!(this.cur_span(), "atomic arithmetic operation type mismatch"); } - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.check_ptr_access_align( - place.ptr, - place.layout.size, - align, - CheckInAllocMsg::MemoryAccessTest, - )?; - match atomic_op { AtomicOp::Min => { let old = this.atomic_min_max_scalar(&place, rhs, true, atomic)?; @@ -262,17 +229,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let place = this.deref_operand(place)?; let new = this.read_scalar(new)?; - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.check_ptr_access_align( - place.ptr, - place.layout.size, - align, - CheckInAllocMsg::MemoryAccessTest, - )?; - let old = this.atomic_exchange_scalar(&place, new, atomic)?; this.write_scalar(old, dest)?; // old value is returned Ok(()) @@ -293,17 +249,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let expect_old = this.read_immediate(expect_old)?; // read as immediate for the sake of `binary_op()` let new = this.read_scalar(new)?; - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.check_ptr_access_align( - place.ptr, - place.layout.size, - align, - CheckInAllocMsg::MemoryAccessTest, - )?; - let old = this.atomic_compare_exchange_scalar( &place, &expect_old, From cd2edbfd098b6c9351f8c168c8f36c190ce5e675 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Aug 2022 17:47:28 -0400 Subject: [PATCH 3694/5092] ensure atomics happen on mutable allocations, and fix futex test --- src/concurrency/data_race.rs | 12 ++++++++++++ .../fail/concurrency/read_only_atomic_cmpxchg.rs | 11 +++++++++++ .../concurrency/read_only_atomic_cmpxchg.stderr | 15 +++++++++++++++ tests/fail/concurrency/read_only_atomic_load.rs | 13 +++++++++++++ .../fail/concurrency/read_only_atomic_load.stderr | 15 +++++++++++++++ tests/pass/concurrency/linux-futex.rs | 6 +++--- 6 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 tests/fail/concurrency/read_only_atomic_cmpxchg.rs create mode 100644 tests/fail/concurrency/read_only_atomic_cmpxchg.stderr create mode 100644 tests/fail/concurrency/read_only_atomic_load.rs create mode 100644 tests/fail/concurrency/read_only_atomic_load.stderr diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 65f198f3c9dd..51105ec98df0 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -46,6 +46,7 @@ use std::{ mem, }; +use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::{mir, ty::layout::TyAndLayout}; @@ -476,6 +477,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { align, CheckInAllocMsg::MemoryAccessTest, )?; + // Ensure the allocation is mutable. Even failing (read-only) compare_exchange need mutable + // memory on many targets (i.e., they segfault if taht memory is mapped read-only), and + // atomic loads can be implemented via compare_exchange on some targets. See + // . + // We avoid `get_ptr_alloc` since we do *not* want to run the access hooks -- the actual + // access will happen later. + let (alloc_id, _offset, _prov) = + this.ptr_try_get_alloc_id(place.ptr).expect("there are no zero-sized atomic accesses"); + if this.get_alloc_mutability(alloc_id)? == Mutability::Not { + throw_ub_format!("atomic operations cannot be performed on read-only memory"); + } Ok(()) } diff --git a/tests/fail/concurrency/read_only_atomic_cmpxchg.rs b/tests/fail/concurrency/read_only_atomic_cmpxchg.rs new file mode 100644 index 000000000000..cb6aeea665d3 --- /dev/null +++ b/tests/fail/concurrency/read_only_atomic_cmpxchg.rs @@ -0,0 +1,11 @@ +// Should not rely on the aliasing model for its failure. +//@compile-flags: -Zmiri-disable-stacked-borrows + +use std::sync::atomic::{AtomicI32, Ordering}; + +fn main() { + static X: i32 = 0; + let x = &X as *const i32 as *const AtomicI32; + let x = unsafe { &*x }; + x.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed).unwrap_err(); //~ERROR: atomic operations cannot be performed on read-only memory +} diff --git a/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr b/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr new file mode 100644 index 000000000000..2753c492266b --- /dev/null +++ b/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: atomic operations cannot be performed on read-only memory + --> $DIR/read_only_atomic_cmpxchg.rs:LL:CC + | +LL | x.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed).unwrap_err(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ atomic operations cannot be performed on read-only memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: backtrace: + = note: inside `main` at $DIR/read_only_atomic_cmpxchg.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/concurrency/read_only_atomic_load.rs b/tests/fail/concurrency/read_only_atomic_load.rs new file mode 100644 index 000000000000..6e92453e3c19 --- /dev/null +++ b/tests/fail/concurrency/read_only_atomic_load.rs @@ -0,0 +1,13 @@ +// Should not rely on the aliasing model for its failure. +//@compile-flags: -Zmiri-disable-stacked-borrows + +use std::sync::atomic::{AtomicI32, Ordering}; + +fn main() { + static X: i32 = 0; + let x = &X as *const i32 as *const AtomicI32; + let x = unsafe { &*x }; + // Some targets can implement atomic loads via compare_exchange, so we cannot allow them on + // read-only memory. + x.load(Ordering::Relaxed); //~ERROR: atomic operations cannot be performed on read-only memory +} diff --git a/tests/fail/concurrency/read_only_atomic_load.stderr b/tests/fail/concurrency/read_only_atomic_load.stderr new file mode 100644 index 000000000000..588081afc62c --- /dev/null +++ b/tests/fail/concurrency/read_only_atomic_load.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: atomic operations cannot be performed on read-only memory + --> $DIR/read_only_atomic_load.rs:LL:CC + | +LL | x.load(Ordering::Relaxed); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ atomic operations cannot be performed on read-only memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: backtrace: + = note: inside `main` at $DIR/read_only_atomic_load.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/pass/concurrency/linux-futex.rs b/tests/pass/concurrency/linux-futex.rs index 43216481e76f..2c99bfa1000c 100644 --- a/tests/pass/concurrency/linux-futex.rs +++ b/tests/pass/concurrency/linux-futex.rs @@ -130,7 +130,7 @@ fn wait_absolute_timeout() { fn wait_wake() { let start = Instant::now(); - static FUTEX: i32 = 0; + static mut FUTEX: i32 = 0; let t = thread::spawn(move || { thread::sleep(Duration::from_millis(200)); @@ -167,7 +167,7 @@ fn wait_wake() { fn wait_wake_bitset() { let start = Instant::now(); - static FUTEX: i32 = 0; + static mut FUTEX: i32 = 0; let t = thread::spawn(move || { thread::sleep(Duration::from_millis(200)); @@ -277,8 +277,8 @@ fn concurrent_wait_wake() { // Make sure we got the interesting case (of having woken a thread) at least once, but not *each* time. let woken = WOKEN.load(Ordering::Relaxed); - assert!(woken > 0 && woken < rounds); //eprintln!("waking happened {woken} times"); + assert!(woken > 0 && woken < rounds); } fn main() { From 927ab19cfc67f96f7543aa929bd1a01c8f226dc2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Aug 2022 17:53:18 -0400 Subject: [PATCH 3695/5092] make some operations private to the data race detector / atomic intrinsic file --- src/concurrency/data_race.rs | 200 ++++++++++++++++----------------- src/shims/intrinsics/atomic.rs | 13 ++- src/shims/unix/linux/sync.rs | 4 +- 3 files changed, 110 insertions(+), 107 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 51105ec98df0..bcbdb616514f 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -464,33 +464,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { this.write_scalar_atomic(value.into(), &value_place, atomic) } - /// Checks that an atomic access is legal at the given place. - fn atomic_access_check(&self, place: &MPlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { - let this = self.eval_context_ref(); - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.check_ptr_access_align( - place.ptr, - place.layout.size, - align, - CheckInAllocMsg::MemoryAccessTest, - )?; - // Ensure the allocation is mutable. Even failing (read-only) compare_exchange need mutable - // memory on many targets (i.e., they segfault if taht memory is mapped read-only), and - // atomic loads can be implemented via compare_exchange on some targets. See - // . - // We avoid `get_ptr_alloc` since we do *not* want to run the access hooks -- the actual - // access will happen later. - let (alloc_id, _offset, _prov) = - this.ptr_try_get_alloc_id(place.ptr).expect("there are no zero-sized atomic accesses"); - if this.get_alloc_mutability(alloc_id)? == Mutability::Not { - throw_ub_format!("atomic operations cannot be performed on read-only memory"); - } - Ok(()) - } - /// Perform an atomic read operation at the memory location. fn read_scalar_atomic( &self, @@ -682,80 +655,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { Ok(res) } - /// Update the data-race detector for an atomic read occurring at the - /// associated memory-place and on the current thread. - fn validate_atomic_load( - &self, - place: &MPlaceTy<'tcx, Provenance>, - atomic: AtomicReadOrd, - ) -> InterpResult<'tcx> { - let this = self.eval_context_ref(); - this.validate_overlapping_atomic(place)?; - this.validate_atomic_op( - place, - atomic, - "Atomic Load", - move |memory, clocks, index, atomic| { - if atomic == AtomicReadOrd::Relaxed { - memory.load_relaxed(&mut *clocks, index) - } else { - memory.load_acquire(&mut *clocks, index) - } - }, - ) - } - - /// Update the data-race detector for an atomic write occurring at the - /// associated memory-place and on the current thread. - fn validate_atomic_store( - &mut self, - place: &MPlaceTy<'tcx, Provenance>, - atomic: AtomicWriteOrd, - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - this.validate_overlapping_atomic(place)?; - this.validate_atomic_op( - place, - atomic, - "Atomic Store", - move |memory, clocks, index, atomic| { - if atomic == AtomicWriteOrd::Relaxed { - memory.store_relaxed(clocks, index) - } else { - memory.store_release(clocks, index) - } - }, - ) - } - - /// Update the data-race detector for an atomic read-modify-write occurring - /// at the associated memory place and on the current thread. - fn validate_atomic_rmw( - &mut self, - place: &MPlaceTy<'tcx, Provenance>, - atomic: AtomicRwOrd, - ) -> InterpResult<'tcx> { - use AtomicRwOrd::*; - let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); - let release = matches!(atomic, Release | AcqRel | SeqCst); - let this = self.eval_context_mut(); - this.validate_overlapping_atomic(place)?; - this.validate_atomic_op(place, atomic, "Atomic RMW", move |memory, clocks, index, _| { - if acquire { - memory.load_acquire(clocks, index)?; - } else { - memory.load_relaxed(clocks, index)?; - } - if release { - memory.rmw_release(clocks, index) - } else { - memory.rmw_relaxed(clocks, index) - } - }) - } - /// Update the data-race detector for an atomic fence on the current thread. - fn validate_atomic_fence(&mut self, atomic: AtomicFenceOrd) -> InterpResult<'tcx> { + fn atomic_fence(&mut self, atomic: AtomicFenceOrd) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if let Some(data_race) = &mut this.machine.data_race { data_race.maybe_perform_sync_operation(&this.machine.threads, |index, mut clocks| { @@ -1081,6 +982,105 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { result } + /// Checks that an atomic access is legal at the given place. + fn atomic_access_check(&self, place: &MPlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { + let this = self.eval_context_ref(); + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.check_ptr_access_align( + place.ptr, + place.layout.size, + align, + CheckInAllocMsg::MemoryAccessTest, + )?; + // Ensure the allocation is mutable. Even failing (read-only) compare_exchange need mutable + // memory on many targets (i.e., they segfault if taht memory is mapped read-only), and + // atomic loads can be implemented via compare_exchange on some targets. See + // . + // We avoid `get_ptr_alloc` since we do *not* want to run the access hooks -- the actual + // access will happen later. + let (alloc_id, _offset, _prov) = + this.ptr_try_get_alloc_id(place.ptr).expect("there are no zero-sized atomic accesses"); + if this.get_alloc_mutability(alloc_id)? == Mutability::Not { + throw_ub_format!("atomic operations cannot be performed on read-only memory"); + } + Ok(()) + } + + /// Update the data-race detector for an atomic read occurring at the + /// associated memory-place and on the current thread. + fn validate_atomic_load( + &self, + place: &MPlaceTy<'tcx, Provenance>, + atomic: AtomicReadOrd, + ) -> InterpResult<'tcx> { + let this = self.eval_context_ref(); + this.validate_overlapping_atomic(place)?; + this.validate_atomic_op( + place, + atomic, + "Atomic Load", + move |memory, clocks, index, atomic| { + if atomic == AtomicReadOrd::Relaxed { + memory.load_relaxed(&mut *clocks, index) + } else { + memory.load_acquire(&mut *clocks, index) + } + }, + ) + } + + /// Update the data-race detector for an atomic write occurring at the + /// associated memory-place and on the current thread. + fn validate_atomic_store( + &mut self, + place: &MPlaceTy<'tcx, Provenance>, + atomic: AtomicWriteOrd, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + this.validate_overlapping_atomic(place)?; + this.validate_atomic_op( + place, + atomic, + "Atomic Store", + move |memory, clocks, index, atomic| { + if atomic == AtomicWriteOrd::Relaxed { + memory.store_relaxed(clocks, index) + } else { + memory.store_release(clocks, index) + } + }, + ) + } + + /// Update the data-race detector for an atomic read-modify-write occurring + /// at the associated memory place and on the current thread. + fn validate_atomic_rmw( + &mut self, + place: &MPlaceTy<'tcx, Provenance>, + atomic: AtomicRwOrd, + ) -> InterpResult<'tcx> { + use AtomicRwOrd::*; + let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); + let release = matches!(atomic, Release | AcqRel | SeqCst); + let this = self.eval_context_mut(); + this.validate_overlapping_atomic(place)?; + this.validate_atomic_op(place, atomic, "Atomic RMW", move |memory, clocks, index, _| { + if acquire { + memory.load_acquire(clocks, index)?; + } else { + memory.load_relaxed(clocks, index)?; + } + if release { + memory.rmw_release(clocks, index) + } else { + memory.rmw_relaxed(clocks, index) + } + }) + } + /// Generic atomic operation implementation fn validate_atomic_op( &self, diff --git a/src/shims/intrinsics/atomic.rs b/src/shims/intrinsics/atomic.rs index 752bc0e302e7..86f132f73fc8 100644 --- a/src/shims/intrinsics/atomic.rs +++ b/src/shims/intrinsics/atomic.rs @@ -67,8 +67,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ["load", ord] => this.atomic_load(args, dest, read_ord(ord)?)?, ["store", ord] => this.atomic_store(args, write_ord(ord)?)?, - ["fence", ord] => this.atomic_fence(args, fence_ord(ord)?)?, - ["singlethreadfence", ord] => this.compiler_fence(args, fence_ord(ord)?)?, + ["fence", ord] => this.atomic_fence_intrinsic(args, fence_ord(ord)?)?, + ["singlethreadfence", ord] => this.compiler_fence_intrinsic(args, fence_ord(ord)?)?, ["xchg", ord] => this.atomic_exchange(args, dest, rw_ord(ord)?)?, ["cxchg", ord1, ord2] => @@ -117,7 +117,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(()) } +} +impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} +trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { fn atomic_load( &mut self, args: &[OpTy<'tcx, Provenance>], @@ -153,7 +156,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - fn compiler_fence( + fn compiler_fence_intrinsic( &mut self, args: &[OpTy<'tcx, Provenance>], atomic: AtomicFenceOrd, @@ -164,14 +167,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - fn atomic_fence( + fn atomic_fence_intrinsic( &mut self, args: &[OpTy<'tcx, Provenance>], atomic: AtomicFenceOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let [] = check_arg_count(args)?; - this.validate_atomic_fence(atomic)?; + this.atomic_fence(atomic)?; Ok(()) } diff --git a/src/shims/unix/linux/sync.rs b/src/shims/unix/linux/sync.rs index 59de10498745..b33553f4663b 100644 --- a/src/shims/unix/linux/sync.rs +++ b/src/shims/unix/linux/sync.rs @@ -169,7 +169,7 @@ pub fn futex<'tcx>( // // Thankfully, preemptions cannot happen inside a Miri shim, so we do not need to // do anything special to guarantee fence-load-comparison atomicity. - this.validate_atomic_fence(AtomicFenceOrd::SeqCst)?; + this.atomic_fence(AtomicFenceOrd::SeqCst)?; // Read an `i32` through the pointer, regardless of any wrapper types. // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`. let futex_val = this @@ -240,7 +240,7 @@ pub fn futex<'tcx>( // Together with the SeqCst fence in futex_wait, this makes sure that futex_wait // will see the latest value on addr which could be changed by our caller // before doing the syscall. - this.validate_atomic_fence(AtomicFenceOrd::SeqCst)?; + this.atomic_fence(AtomicFenceOrd::SeqCst)?; let mut n = 0; for _ in 0..val { if let Some(thread) = this.futex_wake(addr_usize, bitset) { From 43d39636724616b752b18088b95d0e2e61c84844 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 7 Aug 2022 08:00:39 -0400 Subject: [PATCH 3696/5092] more detailed error message --- src/concurrency/data_race.rs | 15 ++++++++++++--- .../concurrency/read_only_atomic_cmpxchg.stderr | 6 ++++++ .../fail/concurrency/read_only_atomic_load.stderr | 6 ++++++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index bcbdb616514f..410c2b9c3ddf 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -997,14 +997,23 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { )?; // Ensure the allocation is mutable. Even failing (read-only) compare_exchange need mutable // memory on many targets (i.e., they segfault if taht memory is mapped read-only), and - // atomic loads can be implemented via compare_exchange on some targets. See - // . + // atomic loads can be implemented via compare_exchange on some targets. There could + // possibly be some very specific exceptions to this, see + // for details. // We avoid `get_ptr_alloc` since we do *not* want to run the access hooks -- the actual // access will happen later. let (alloc_id, _offset, _prov) = this.ptr_try_get_alloc_id(place.ptr).expect("there are no zero-sized atomic accesses"); if this.get_alloc_mutability(alloc_id)? == Mutability::Not { - throw_ub_format!("atomic operations cannot be performed on read-only memory"); + // FIXME: make this prettier, once these messages have separate title/span/help messages. + throw_ub_format!( + "atomic operations cannot be performed on read-only memory\n\ + many platforms require atomic read-modify-write instructions to be performed on writeable memory, even if the operation fails \ + (and is hence nominally read-only)\n\ + some platforms implement (some) atomic loads via compare-exchange, which means they do not work on read-only memory; \ + it is possible that we could have an exception permitting this for specific kinds of loads\n\ + please report an issue at if this is a problem for you" + ); } Ok(()) } diff --git a/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr b/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr index 2753c492266b..b90dc5c9d6cd 100644 --- a/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr +++ b/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr @@ -1,8 +1,14 @@ error: Undefined Behavior: atomic operations cannot be performed on read-only memory + many platforms require atomic read-modify-write instructions to be performed on writeable memory, even if the operation fails (and is hence nominally read-only) + some platforms implement (some) atomic loads via compare-exchange, which means they do not work on read-only memory; it is possible that we could have an exception permitting this for specific kinds of loads + please report an issue at if this is a problem for you --> $DIR/read_only_atomic_cmpxchg.rs:LL:CC | LL | x.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed).unwrap_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ atomic operations cannot be performed on read-only memory +many platforms require atomic read-modify-write instructions to be performed on writeable memory, even if the operation fails (and is hence nominally read-only) +some platforms implement (some) atomic loads via compare-exchange, which means they do not work on read-only memory; it is possible that we could have an exception permitting this for specific kinds of loads +please report an issue at if this is a problem for you | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/concurrency/read_only_atomic_load.stderr b/tests/fail/concurrency/read_only_atomic_load.stderr index 588081afc62c..b19d3755fbb0 100644 --- a/tests/fail/concurrency/read_only_atomic_load.stderr +++ b/tests/fail/concurrency/read_only_atomic_load.stderr @@ -1,8 +1,14 @@ error: Undefined Behavior: atomic operations cannot be performed on read-only memory + many platforms require atomic read-modify-write instructions to be performed on writeable memory, even if the operation fails (and is hence nominally read-only) + some platforms implement (some) atomic loads via compare-exchange, which means they do not work on read-only memory; it is possible that we could have an exception permitting this for specific kinds of loads + please report an issue at if this is a problem for you --> $DIR/read_only_atomic_load.rs:LL:CC | LL | x.load(Ordering::Relaxed); | ^^^^^^^^^^^^^^^^^^^^^^^^^ atomic operations cannot be performed on read-only memory +many platforms require atomic read-modify-write instructions to be performed on writeable memory, even if the operation fails (and is hence nominally read-only) +some platforms implement (some) atomic loads via compare-exchange, which means they do not work on read-only memory; it is possible that we could have an exception permitting this for specific kinds of loads +please report an issue at if this is a problem for you | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information From a1f5a75c80a325804b96d9a9f2d2f862ad29c736 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 9 Aug 2022 13:59:43 -0400 Subject: [PATCH 3697/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index cac0155e3ce4..eb973aa08156 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -93ab13b4e894ab74258c40aaf29872db2b17b6b4 +6d3f1beae1720055e5a30f4dbe7a9e7fb810c65e From 9ffddf563c0380abbfc7b77274d89a1cb71573ae Mon Sep 17 00:00:00 2001 From: miam-miam100 <49870539+miam-miam100@users.noreply.github.com> Date: Thu, 23 Jun 2022 20:09:47 +0100 Subject: [PATCH 3698/5092] Add new lint [`positional_named_format_parameters`] --- CHANGELOG.md | 1 + clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_suspicious.rs | 1 + clippy_lints/src/write.rs | 129 +++++- .../positional_named_format_parameters.fixed | 56 +++ .../ui/positional_named_format_parameters.rs | 56 +++ .../positional_named_format_parameters.stderr | 418 ++++++++++++++++++ 8 files changed, 657 insertions(+), 6 deletions(-) create mode 100644 tests/ui/positional_named_format_parameters.fixed create mode 100644 tests/ui/positional_named_format_parameters.rs create mode 100644 tests/ui/positional_named_format_parameters.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 2278a8dc16ba..569020db5b70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3823,6 +3823,7 @@ Released 2018-09-13 [`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl [`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite [`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch +[`positional_named_format_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#positional_named_format_parameters [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma [`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence [`print_in_format_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_in_format_impl diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 5be1c417bf8f..88b2dd487dd6 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -345,6 +345,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(vec::USELESS_VEC), LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH), LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO), + LintId::of(write::POSITIONAL_NAMED_FORMAT_PARAMETERS), LintId::of(write::PRINTLN_EMPTY_STRING), LintId::of(write::PRINT_LITERAL), LintId::of(write::PRINT_WITH_NEWLINE), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 99bde35cf152..dacdae0c4a9f 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -583,6 +583,7 @@ store.register_lints(&[ verbose_file_reads::VERBOSE_FILE_READS, wildcard_imports::ENUM_GLOB_USE, wildcard_imports::WILDCARD_IMPORTS, + write::POSITIONAL_NAMED_FORMAT_PARAMETERS, write::PRINTLN_EMPTY_STRING, write::PRINT_LITERAL, write::PRINT_STDERR, diff --git a/clippy_lints/src/lib.register_suspicious.rs b/clippy_lints/src/lib.register_suspicious.rs index f7558f870981..2aea0bf8c459 100644 --- a/clippy_lints/src/lib.register_suspicious.rs +++ b/clippy_lints/src/lib.register_suspicious.rs @@ -33,4 +33,5 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec! LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), LintId::of(swap_ptr_to_ref::SWAP_PTR_TO_REF), + LintId::of(write::POSITIONAL_NAMED_FORMAT_PARAMETERS), ]) diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 08b889475201..31890707644b 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -3,8 +3,9 @@ use std::iter; use std::ops::{Deref, Range}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet_opt, snippet_with_applicability}; +use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; use rustc_ast::ast::{Expr, ExprKind, Impl, Item, ItemKind, MacCall, Path, StrLit, StrStyle}; +use rustc_ast::ptr::P; use rustc_ast::token::{self, LitKind}; use rustc_ast::tokenstream::TokenStream; use rustc_errors::{Applicability, DiagnosticBuilder}; @@ -256,6 +257,28 @@ declare_clippy_lint! { "writing a literal with a format string" } +declare_clippy_lint! { + /// ### What it does + /// This lint warns when a named parameter in a format string is used as a positional one. + /// + /// ### Why is this bad? + /// It may be confused for an assignment and obfuscates which parameter is being used. + /// + /// ### Example + /// ```rust + /// println!("{}", x = 10); + /// ``` + /// + /// Use instead: + /// ```rust + /// println!("{x}", x = 10); + /// ``` + #[clippy::version = "1.63.0"] + pub POSITIONAL_NAMED_FORMAT_PARAMETERS, + suspicious, + "named parameter in a format string is used positionally" +} + #[derive(Default)] pub struct Write { in_debug_impl: bool, @@ -270,7 +293,8 @@ impl_lint_pass!(Write => [ PRINT_LITERAL, WRITE_WITH_NEWLINE, WRITELN_EMPTY_STRING, - WRITE_LITERAL + WRITE_LITERAL, + POSITIONAL_NAMED_FORMAT_PARAMETERS, ]); impl EarlyLintPass for Write { @@ -408,6 +432,7 @@ fn newline_span(fmtstr: &StrLit) -> (Span, bool) { #[derive(Default)] struct SimpleFormatArgs { unnamed: Vec>, + complex_unnamed: Vec>, named: Vec<(Symbol, Vec)>, } impl SimpleFormatArgs { @@ -419,6 +444,10 @@ impl SimpleFormatArgs { }) } + fn get_complex_unnamed(&self) -> impl Iterator { + self.complex_unnamed.iter().map(Vec::as_slice) + } + fn get_named(&self, n: &Path) -> &[Span] { self.named.iter().find(|x| *n == x.0).map_or(&[], |x| x.1.as_slice()) } @@ -479,6 +508,61 @@ impl SimpleFormatArgs { }, }; } + + fn push_to_complex(&mut self, span: Span, position: usize) { + if self.complex_unnamed.len() <= position { + self.complex_unnamed.resize_with(position, Vec::new); + self.complex_unnamed.push(vec![span]); + } else { + let args: &mut Vec = &mut self.complex_unnamed[position]; + args.push(span); + } + } + + fn push_complex( + &mut self, + cx: &EarlyContext<'_>, + arg: rustc_parse_format::Argument<'_>, + str_lit_span: Span, + fmt_span: Span, + ) { + use rustc_parse_format::{ArgumentImplicitlyIs, ArgumentIs, CountIsParam}; + + let snippet = snippet_opt(cx, fmt_span); + + let end = snippet + .as_ref() + .and_then(|s| s.find(':')) + .or_else(|| fmt_span.hi().0.checked_sub(fmt_span.lo().0 + 1).map(|u| u as usize)); + + if let (ArgumentIs(n) | ArgumentImplicitlyIs(n), Some(end)) = (arg.position, end) { + let span = fmt_span.from_inner(InnerSpan::new(1, end)); + self.push_to_complex(span, n); + }; + + if let (CountIsParam(n), Some(span)) = (arg.format.precision, arg.format.precision_span) { + // We need to do this hack as precision spans should be converted from .* to .foo$ + let hack = if snippet.as_ref().and_then(|s| s.find('*')).is_some() { + 0 + } else { + 1 + }; + + let span = str_lit_span.from_inner(InnerSpan { + start: span.start + 1, + end: span.end - hack, + }); + self.push_to_complex(span, n); + }; + + if let (CountIsParam(n), Some(span)) = (arg.format.width, arg.format.width_span) { + let span = str_lit_span.from_inner(InnerSpan { + start: span.start, + end: span.end - 1, + }); + self.push_to_complex(span, n); + }; + } } impl Write { @@ -511,8 +595,8 @@ impl Write { // FIXME: modify rustc's fmt string parser to give us the current span span_lint(cx, USE_DEBUG, span, "use of `Debug`-based formatting"); } - args.push(arg, span); + args.push_complex(cx, arg, str_lit.span, span); } parser.errors.is_empty().then_some(args) @@ -566,6 +650,7 @@ impl Write { let lint = if is_write { WRITE_LITERAL } else { PRINT_LITERAL }; let mut unnamed_args = args.get_unnamed(); + let mut complex_unnamed_args = args.get_complex_unnamed(); loop { if !parser.eat(&token::Comma) { return (Some(fmtstr), expr); @@ -577,11 +662,20 @@ impl Write { } else { return (Some(fmtstr), None); }; + let complex_unnamed_arg = complex_unnamed_args.next(); + let (fmt_spans, lit) = match &token_expr.kind { ExprKind::Lit(lit) => (unnamed_args.next().unwrap_or(&[]), lit), - ExprKind::Assign(lhs, rhs, _) => match (&lhs.kind, &rhs.kind) { - (ExprKind::Path(_, p), ExprKind::Lit(lit)) => (args.get_named(p), lit), - _ => continue, + ExprKind::Assign(lhs, rhs, _) => { + if let Some(span) = complex_unnamed_arg { + for x in span { + Self::report_positional_named_param(cx, *x, lhs, rhs); + } + } + match (&lhs.kind, &rhs.kind) { + (ExprKind::Path(_, p), ExprKind::Lit(lit)) => (args.get_named(p), lit), + _ => continue, + } }, _ => { unnamed_args.next(); @@ -637,6 +731,29 @@ impl Write { } } + fn report_positional_named_param(cx: &EarlyContext<'_>, span: Span, lhs: &P, _rhs: &P) { + if let ExprKind::Path(_, _p) = &lhs.kind { + let mut applicability = Applicability::MachineApplicable; + let name = snippet_with_applicability(cx, lhs.span, "name", &mut applicability); + // We need to do this hack as precision spans should be converted from .* to .foo$ + let hack = snippet(cx, span, "").contains('*'); + + span_lint_and_sugg( + cx, + POSITIONAL_NAMED_FORMAT_PARAMETERS, + span, + &format!("named parameter {} is used as a positional parameter", name), + "replace it with", + if hack { + format!("{}$", name) + } else { + format!("{}", name) + }, + applicability, + ); + }; + } + fn lint_println_empty_string(&self, cx: &EarlyContext<'_>, mac: &MacCall) { if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) { if fmt_str.symbol == kw::Empty { diff --git a/tests/ui/positional_named_format_parameters.fixed b/tests/ui/positional_named_format_parameters.fixed new file mode 100644 index 000000000000..4170e1098204 --- /dev/null +++ b/tests/ui/positional_named_format_parameters.fixed @@ -0,0 +1,56 @@ +// run-rustfix +#![allow(unused_must_use)] +#![allow(named_arguments_used_positionally)] // Unstable at time of writing. +#![warn(clippy::positional_named_format_parameters)] + +use std::io::Write; + +fn main() { + let mut v = Vec::new(); + let hello = "Hello"; + + println!("{hello:.foo$}", foo = 2); + writeln!(v, "{hello:.foo$}", foo = 2); + + // Warnings + println!("{zero} {one:?}", zero = 0, one = 1); + println!("This is a test {zero} {one:?}", zero = 0, one = 1); + println!("Hello {one} is {two:.zero$}", zero = 5, one = hello, two = 0.01); + println!("Hello {one:zero$}!", zero = 5, one = 1); + println!("Hello {zero:one$}!", zero = 4, one = 1); + println!("Hello {zero:0one$}!", zero = 4, one = 1); + println!("Hello is {one:.zero$}", zero = 5, one = 0.01); + println!("Hello is {one:<6.zero$}", zero = 5, one = 0.01); + println!("{zero}, `{two:>8.one$}` has 3", zero = hello, one = 3, two = hello); + println!("Hello {one} is {two:.zero$}", zero = 5, one = hello, two = 0.01); + println!("Hello {world} {world}!", world = 5); + + writeln!(v, "{zero} {one:?}", zero = 0, one = 1); + writeln!(v, "This is a test {zero} {one:?}", zero = 0, one = 1); + writeln!(v, "Hello {one} is {two:.zero$}", zero = 5, one = hello, two = 0.01); + writeln!(v, "Hello {one:zero$}!", zero = 4, one = 1); + writeln!(v, "Hello {zero:one$}!", zero = 4, one = 1); + writeln!(v, "Hello {zero:0one$}!", zero = 4, one = 1); + writeln!(v, "Hello is {one:.zero$}", zero = 3, one = 0.01); + writeln!(v, "Hello is {one:<6.zero$}", zero = 2, one = 0.01); + writeln!(v, "{zero}, `{two:>8.one$}` has 3", zero = hello, one = 3, two = hello); + writeln!(v, "Hello {one} is {two:.zero$}", zero = 1, one = hello, two = 0.01); + writeln!(v, "Hello {world} {world}!", world = 0); + + // Tests from other files + println!("{w:w$}", w = 1); + println!("{p:.p$}", p = 1); + println!("{v}", v = 1); + println!("{v:v$}", v = 1); + println!("{v:v$}", v = 1); + println!("{v:v$.v$}", v = 1); + println!("{v:v$.v$}", v = 1); + println!("{v:v$.v$}", v = 1); + println!("{v:v$.v$}", v = 1); + println!("{v:v$.v$}", v = 1); + println!("{v:v$.v$}", v = 1); + println!("{v:v$.v$}", v = 1); + println!("{w:w$}", w = 1); + println!("{p:.p$}", p = 1); + println!("{:p$.w$}", 1, w = 1, p = 1); +} diff --git a/tests/ui/positional_named_format_parameters.rs b/tests/ui/positional_named_format_parameters.rs new file mode 100644 index 000000000000..553d8494ecc0 --- /dev/null +++ b/tests/ui/positional_named_format_parameters.rs @@ -0,0 +1,56 @@ +// run-rustfix +#![allow(unused_must_use)] +#![allow(named_arguments_used_positionally)] // Unstable at time of writing. +#![warn(clippy::positional_named_format_parameters)] + +use std::io::Write; + +fn main() { + let mut v = Vec::new(); + let hello = "Hello"; + + println!("{hello:.foo$}", foo = 2); + writeln!(v, "{hello:.foo$}", foo = 2); + + // Warnings + println!("{} {1:?}", zero = 0, one = 1); + println!("This is a test { } {000001:?}", zero = 0, one = 1); + println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); + println!("Hello {1:0$}!", zero = 5, one = 1); + println!("Hello {0:1$}!", zero = 4, one = 1); + println!("Hello {0:01$}!", zero = 4, one = 1); + println!("Hello is {1:.*}", zero = 5, one = 0.01); + println!("Hello is {:<6.*}", zero = 5, one = 0.01); + println!("{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello); + println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); + println!("Hello {world} {}!", world = 5); + + writeln!(v, "{} {1:?}", zero = 0, one = 1); + writeln!(v, "This is a test { } {000001:?}", zero = 0, one = 1); + writeln!(v, "Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); + writeln!(v, "Hello {1:0$}!", zero = 4, one = 1); + writeln!(v, "Hello {0:1$}!", zero = 4, one = 1); + writeln!(v, "Hello {0:01$}!", zero = 4, one = 1); + writeln!(v, "Hello is {1:.*}", zero = 3, one = 0.01); + writeln!(v, "Hello is {:<6.*}", zero = 2, one = 0.01); + writeln!(v, "{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello); + writeln!(v, "Hello {1} is {2:.0$}", zero = 1, one = hello, two = 0.01); + writeln!(v, "Hello {world} {}!", world = 0); + + // Tests from other files + println!("{:w$}", w = 1); + println!("{:.p$}", p = 1); + println!("{}", v = 1); + println!("{:0$}", v = 1); + println!("{0:0$}", v = 1); + println!("{:0$.0$}", v = 1); + println!("{0:0$.0$}", v = 1); + println!("{0:0$.v$}", v = 1); + println!("{0:v$.0$}", v = 1); + println!("{v:0$.0$}", v = 1); + println!("{v:v$.0$}", v = 1); + println!("{v:0$.v$}", v = 1); + println!("{:w$}", w = 1); + println!("{:.p$}", p = 1); + println!("{:p$.w$}", 1, w = 1, p = 1); +} diff --git a/tests/ui/positional_named_format_parameters.stderr b/tests/ui/positional_named_format_parameters.stderr new file mode 100644 index 000000000000..48ddb6d67ad2 --- /dev/null +++ b/tests/ui/positional_named_format_parameters.stderr @@ -0,0 +1,418 @@ +error: named parameter zero is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:16:16 + | +LL | println!("{} {1:?}", zero = 0, one = 1); + | ^ help: replace it with: `zero` + | + = note: `-D clippy::positional-named-format-parameters` implied by `-D warnings` + +error: named parameter one is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:16:19 + | +LL | println!("{} {1:?}", zero = 0, one = 1); + | ^ help: replace it with: `one` + +error: named parameter zero is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:17:31 + | +LL | println!("This is a test { } {000001:?}", zero = 0, one = 1); + | ^ help: replace it with: `zero` + +error: named parameter one is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:17:35 + | +LL | println!("This is a test { } {000001:?}", zero = 0, one = 1); + | ^^^^^^ help: replace it with: `one` + +error: named parameter zero is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:18:32 + | +LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); + | ^ help: replace it with: `zero` + +error: named parameter one is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:18:22 + | +LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); + | ^ help: replace it with: `one` + +error: named parameter two is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:18:29 + | +LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); + | ^ help: replace it with: `two` + +error: named parameter zero is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:19:24 + | +LL | println!("Hello {1:0$}!", zero = 5, one = 1); + | ^ help: replace it with: `zero` + +error: named parameter one is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:19:22 + | +LL | println!("Hello {1:0$}!", zero = 5, one = 1); + | ^ help: replace it with: `one` + +error: named parameter zero is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:20:22 + | +LL | println!("Hello {0:1$}!", zero = 4, one = 1); + | ^ help: replace it with: `zero` + +error: named parameter one is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:20:24 + | +LL | println!("Hello {0:1$}!", zero = 4, one = 1); + | ^ help: replace it with: `one` + +error: named parameter zero is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:21:22 + | +LL | println!("Hello {0:01$}!", zero = 4, one = 1); + | ^ help: replace it with: `zero` + +error: named parameter one is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:21:25 + | +LL | println!("Hello {0:01$}!", zero = 4, one = 1); + | ^ help: replace it with: `one` + +error: named parameter zero is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:22:28 + | +LL | println!("Hello is {1:.*}", zero = 5, one = 0.01); + | ^ help: replace it with: `zero$` + +error: named parameter one is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:22:25 + | +LL | println!("Hello is {1:.*}", zero = 5, one = 0.01); + | ^ help: replace it with: `one` + +error: named parameter zero is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:23:29 + | +LL | println!("Hello is {:<6.*}", zero = 5, one = 0.01); + | ^ help: replace it with: `zero$` + +error: named parameter one is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:23:25 + | +LL | println!("Hello is {:<6.*}", zero = 5, one = 0.01); + | ^ help: replace it with: `one` + +error: named parameter zero is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:24:16 + | +LL | println!("{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello); + | ^ help: replace it with: `zero` + +error: named parameter one is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:24:28 + | +LL | println!("{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello); + | ^ help: replace it with: `one$` + +error: named parameter zero is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:25:32 + | +LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); + | ^ help: replace it with: `zero` + +error: named parameter one is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:25:22 + | +LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); + | ^ help: replace it with: `one` + +error: named parameter two is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:25:29 + | +LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); + | ^ help: replace it with: `two` + +error: named parameter world is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:26:30 + | +LL | println!("Hello {world} {}!", world = 5); + | ^ help: replace it with: `world` + +error: named parameter zero is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:28:19 + | +LL | writeln!(v, "{} {1:?}", zero = 0, one = 1); + | ^ help: replace it with: `zero` + +error: named parameter one is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:28:22 + | +LL | writeln!(v, "{} {1:?}", zero = 0, one = 1); + | ^ help: replace it with: `one` + +error: named parameter zero is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:29:34 + | +LL | writeln!(v, "This is a test { } {000001:?}", zero = 0, one = 1); + | ^ help: replace it with: `zero` + +error: named parameter one is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:29:38 + | +LL | writeln!(v, "This is a test { } {000001:?}", zero = 0, one = 1); + | ^^^^^^ help: replace it with: `one` + +error: named parameter zero is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:30:35 + | +LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); + | ^ help: replace it with: `zero` + +error: named parameter one is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:30:25 + | +LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); + | ^ help: replace it with: `one` + +error: named parameter two is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:30:32 + | +LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); + | ^ help: replace it with: `two` + +error: named parameter zero is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:31:27 + | +LL | writeln!(v, "Hello {1:0$}!", zero = 4, one = 1); + | ^ help: replace it with: `zero` + +error: named parameter one is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:31:25 + | +LL | writeln!(v, "Hello {1:0$}!", zero = 4, one = 1); + | ^ help: replace it with: `one` + +error: named parameter zero is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:32:25 + | +LL | writeln!(v, "Hello {0:1$}!", zero = 4, one = 1); + | ^ help: replace it with: `zero` + +error: named parameter one is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:32:27 + | +LL | writeln!(v, "Hello {0:1$}!", zero = 4, one = 1); + | ^ help: replace it with: `one` + +error: named parameter zero is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:33:25 + | +LL | writeln!(v, "Hello {0:01$}!", zero = 4, one = 1); + | ^ help: replace it with: `zero` + +error: named parameter one is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:33:28 + | +LL | writeln!(v, "Hello {0:01$}!", zero = 4, one = 1); + | ^ help: replace it with: `one` + +error: named parameter zero is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:34:31 + | +LL | writeln!(v, "Hello is {1:.*}", zero = 3, one = 0.01); + | ^ help: replace it with: `zero$` + +error: named parameter one is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:34:28 + | +LL | writeln!(v, "Hello is {1:.*}", zero = 3, one = 0.01); + | ^ help: replace it with: `one` + +error: named parameter zero is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:35:32 + | +LL | writeln!(v, "Hello is {:<6.*}", zero = 2, one = 0.01); + | ^ help: replace it with: `zero$` + +error: named parameter one is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:35:28 + | +LL | writeln!(v, "Hello is {:<6.*}", zero = 2, one = 0.01); + | ^ help: replace it with: `one` + +error: named parameter zero is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:36:19 + | +LL | writeln!(v, "{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello); + | ^ help: replace it with: `zero` + +error: named parameter one is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:36:31 + | +LL | writeln!(v, "{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello); + | ^ help: replace it with: `one$` + +error: named parameter zero is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:37:35 + | +LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 1, one = hello, two = 0.01); + | ^ help: replace it with: `zero` + +error: named parameter one is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:37:25 + | +LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 1, one = hello, two = 0.01); + | ^ help: replace it with: `one` + +error: named parameter two is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:37:32 + | +LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 1, one = hello, two = 0.01); + | ^ help: replace it with: `two` + +error: named parameter world is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:38:33 + | +LL | writeln!(v, "Hello {world} {}!", world = 0); + | ^ help: replace it with: `world` + +error: named parameter w is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:41:16 + | +LL | println!("{:w$}", w = 1); + | ^ help: replace it with: `w` + +error: named parameter p is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:42:16 + | +LL | println!("{:.p$}", p = 1); + | ^ help: replace it with: `p` + +error: named parameter v is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:43:16 + | +LL | println!("{}", v = 1); + | ^ help: replace it with: `v` + +error: named parameter v is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:44:16 + | +LL | println!("{:0$}", v = 1); + | ^ help: replace it with: `v` + +error: named parameter v is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:44:17 + | +LL | println!("{:0$}", v = 1); + | ^ help: replace it with: `v` + +error: named parameter v is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:45:16 + | +LL | println!("{0:0$}", v = 1); + | ^ help: replace it with: `v` + +error: named parameter v is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:45:18 + | +LL | println!("{0:0$}", v = 1); + | ^ help: replace it with: `v` + +error: named parameter v is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:46:16 + | +LL | println!("{:0$.0$}", v = 1); + | ^ help: replace it with: `v` + +error: named parameter v is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:46:20 + | +LL | println!("{:0$.0$}", v = 1); + | ^ help: replace it with: `v` + +error: named parameter v is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:46:17 + | +LL | println!("{:0$.0$}", v = 1); + | ^ help: replace it with: `v` + +error: named parameter v is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:47:16 + | +LL | println!("{0:0$.0$}", v = 1); + | ^ help: replace it with: `v` + +error: named parameter v is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:47:21 + | +LL | println!("{0:0$.0$}", v = 1); + | ^ help: replace it with: `v` + +error: named parameter v is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:47:18 + | +LL | println!("{0:0$.0$}", v = 1); + | ^ help: replace it with: `v` + +error: named parameter v is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:48:16 + | +LL | println!("{0:0$.v$}", v = 1); + | ^ help: replace it with: `v` + +error: named parameter v is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:48:18 + | +LL | println!("{0:0$.v$}", v = 1); + | ^ help: replace it with: `v` + +error: named parameter v is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:49:16 + | +LL | println!("{0:v$.0$}", v = 1); + | ^ help: replace it with: `v` + +error: named parameter v is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:49:21 + | +LL | println!("{0:v$.0$}", v = 1); + | ^ help: replace it with: `v` + +error: named parameter v is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:50:21 + | +LL | println!("{v:0$.0$}", v = 1); + | ^ help: replace it with: `v` + +error: named parameter v is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:50:18 + | +LL | println!("{v:0$.0$}", v = 1); + | ^ help: replace it with: `v` + +error: named parameter v is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:51:21 + | +LL | println!("{v:v$.0$}", v = 1); + | ^ help: replace it with: `v` + +error: named parameter v is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:52:18 + | +LL | println!("{v:0$.v$}", v = 1); + | ^ help: replace it with: `v` + +error: named parameter w is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:53:16 + | +LL | println!("{:w$}", w = 1); + | ^ help: replace it with: `w` + +error: named parameter p is used as a positional parameter + --> $DIR/positional_named_format_parameters.rs:54:16 + | +LL | println!("{:.p$}", p = 1); + | ^ help: replace it with: `p` + +error: aborting due to 69 previous errors + From 591274bbd9506e88ac9280dc79d0db38cb11707b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 10 Aug 2022 08:03:00 -0400 Subject: [PATCH 3699/5092] rustup --- rust-version | 2 +- tests/pass/backtrace/backtrace-global-alloc.rs | 2 -- tests/pass/backtrace/backtrace-std.rs | 2 -- tests/pass/integer-ops.rs | 14 ++++++++------ 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/rust-version b/rust-version index eb973aa08156..71d06eff494c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6d3f1beae1720055e5a30f4dbe7a9e7fb810c65e +1603a70f82240ba2d27f72f964e36614d7620ad3 diff --git a/tests/pass/backtrace/backtrace-global-alloc.rs b/tests/pass/backtrace/backtrace-global-alloc.rs index 406a5b62333d..6660e5bb57c0 100644 --- a/tests/pass/backtrace/backtrace-global-alloc.rs +++ b/tests/pass/backtrace/backtrace-global-alloc.rs @@ -1,8 +1,6 @@ //@compile-flags: -Zmiri-disable-isolation //@rustc-env: RUST_BACKTRACE=1 -#![feature(backtrace)] - use std::alloc::System; use std::backtrace::Backtrace; diff --git a/tests/pass/backtrace/backtrace-std.rs b/tests/pass/backtrace/backtrace-std.rs index 9106310e513d..b2a5ac180298 100644 --- a/tests/pass/backtrace/backtrace-std.rs +++ b/tests/pass/backtrace/backtrace-std.rs @@ -1,8 +1,6 @@ //@compile-flags: -Zmiri-disable-isolation //@rustc-env: RUST_BACKTRACE=1 -#![feature(backtrace)] - use std::backtrace::Backtrace; #[inline(never)] diff --git a/tests/pass/integer-ops.rs b/tests/pass/integer-ops.rs index 8608d12d4d87..724be9efc9f8 100644 --- a/tests/pass/integer-ops.rs +++ b/tests/pass/integer-ops.rs @@ -176,10 +176,12 @@ pub fn main() { // Logarithms macro_rules! test_log { ($type:ident, $max_log2:expr, $max_log10:expr) => { - assert_eq!($type::MIN.checked_log2(), None); - assert_eq!($type::MIN.checked_log10(), None); - assert_eq!($type::MAX.checked_log2(), Some($max_log2)); - assert_eq!($type::MAX.checked_log10(), Some($max_log10)); + assert_eq!($type::MIN.checked_ilog2(), None); + assert_eq!($type::MIN.checked_ilog10(), None); + assert_eq!($type::MAX.checked_ilog2(), Some($max_log2)); + assert_eq!($type::MAX.checked_ilog10(), Some($max_log10)); + assert_eq!($type::MAX.ilog2(), $max_log2); + assert_eq!($type::MAX.ilog10(), $max_log10); }; } @@ -195,9 +197,9 @@ pub fn main() { test_log!(u128, 127, 38); for i in (1..=i16::MAX).step_by(i8::MAX as usize) { - assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as u32)); + assert_eq!(i.checked_ilog(13), Some((i as f32).log(13.0) as u32)); } for i in (1..=u16::MAX).step_by(i8::MAX as usize) { - assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as u32)); + assert_eq!(i.checked_ilog(13), Some((i as f32).log(13.0) as u32)); } } From cf3f71d2a22f6ca884428b47b4c3eb5c77f1dae3 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 7 Aug 2022 15:21:11 +0200 Subject: [PATCH 3700/5092] Do not consider method call receiver as an argument in AST. --- clippy_lints/src/double_parens.rs | 5 ++--- clippy_lints/src/option_env_unwrap.rs | 4 ++-- clippy_lints/src/precedence.rs | 4 ++-- clippy_lints/src/suspicious_operation_groupings.rs | 2 +- clippy_lints/src/unused_rounding.rs | 5 ++--- clippy_utils/src/ast_utils.rs | 4 +++- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/clippy_lints/src/double_parens.rs b/clippy_lints/src/double_parens.rs index a33ef5ce6e37..0f1d701865e7 100644 --- a/clippy_lints/src/double_parens.rs +++ b/clippy_lints/src/double_parens.rs @@ -61,9 +61,8 @@ impl EarlyLintPass for DoubleParens { } } }, - ExprKind::MethodCall(_, ref params, _) => { - if params.len() == 2 { - let param = ¶ms[1]; + ExprKind::MethodCall(_, _, ref params, _) => { + if let [ref param] = params[..] { if let ExprKind::Paren(_) = param.kind { span_lint(cx, DOUBLE_PARENS, param.span, msg); } diff --git a/clippy_lints/src/option_env_unwrap.rs b/clippy_lints/src/option_env_unwrap.rs index 3f5286ba097b..d9ee031c9f97 100644 --- a/clippy_lints/src/option_env_unwrap.rs +++ b/clippy_lints/src/option_env_unwrap.rs @@ -37,9 +37,9 @@ declare_lint_pass!(OptionEnvUnwrap => [OPTION_ENV_UNWRAP]); impl EarlyLintPass for OptionEnvUnwrap { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { if_chain! { - if let ExprKind::MethodCall(path_segment, args, _) = &expr.kind; + if let ExprKind::MethodCall(path_segment, receiver, _, _) = &expr.kind; if matches!(path_segment.ident.name, sym::expect | sym::unwrap); - if let ExprKind::Call(caller, _) = &args[0].kind; + if let ExprKind::Call(caller, _) = &receiver.kind; if is_direct_expn_of(caller.span, "option_env").is_some(); then { span_lint_and_help( diff --git a/clippy_lints/src/precedence.rs b/clippy_lints/src/precedence.rs index cc0533c9f5d1..e6e3ad05ad70 100644 --- a/clippy_lints/src/precedence.rs +++ b/clippy_lints/src/precedence.rs @@ -109,12 +109,12 @@ impl EarlyLintPass for Precedence { let mut arg = operand; let mut all_odd = true; - while let ExprKind::MethodCall(path_segment, args, _) = &arg.kind { + while let ExprKind::MethodCall(path_segment, receiver, _, _) = &arg.kind { let path_segment_str = path_segment.ident.name.as_str(); all_odd &= ALLOWED_ODD_FUNCTIONS .iter() .any(|odd_function| **odd_function == *path_segment_str); - arg = args.first().expect("A method always has a receiver."); + arg = receiver; } if_chain! { diff --git a/clippy_lints/src/suspicious_operation_groupings.rs b/clippy_lints/src/suspicious_operation_groupings.rs index fe8859905953..5d36f0f5ff8b 100644 --- a/clippy_lints/src/suspicious_operation_groupings.rs +++ b/clippy_lints/src/suspicious_operation_groupings.rs @@ -595,7 +595,7 @@ fn ident_difference_expr_with_base_location( | (Unary(_, _), Unary(_, _)) | (Binary(_, _, _), Binary(_, _, _)) | (Tup(_), Tup(_)) - | (MethodCall(_, _, _), MethodCall(_, _, _)) + | (MethodCall(_, _, _, _), MethodCall(_, _, _, _)) | (Call(_, _), Call(_, _)) | (ConstBlock(_), ConstBlock(_)) | (Array(_), Array(_)) diff --git a/clippy_lints/src/unused_rounding.rs b/clippy_lints/src/unused_rounding.rs index 306afe441484..e1ec357838db 100644 --- a/clippy_lints/src/unused_rounding.rs +++ b/clippy_lints/src/unused_rounding.rs @@ -30,11 +30,10 @@ declare_clippy_lint! { declare_lint_pass!(UnusedRounding => [UNUSED_ROUNDING]); fn is_useless_rounding(expr: &Expr) -> Option<(&str, String)> { - if let ExprKind::MethodCall(name_ident, args, _) = &expr.kind + if let ExprKind::MethodCall(name_ident, receiver, _, _) = &expr.kind && let method_name = name_ident.ident.name.as_str() && (method_name == "ceil" || method_name == "round" || method_name == "floor") - && !args.is_empty() - && let ExprKind::Lit(spanned) = &args[0].kind + && let ExprKind::Lit(spanned) = &receiver.kind && let LitKind::Float(symbol, ty) = spanned.kind { let f = symbol.as_str().parse::().unwrap(); let f_str = symbol.to_string() + if let LitFloatType::Suffixed(ty) = ty { diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index b226026323be..9f74729bdfa1 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -147,7 +147,9 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { (Array(l), Array(r)) | (Tup(l), Tup(r)) => over(l, r, |l, r| eq_expr(l, r)), (Repeat(le, ls), Repeat(re, rs)) => eq_expr(le, re) && eq_expr(&ls.value, &rs.value), (Call(lc, la), Call(rc, ra)) => eq_expr(lc, rc) && over(la, ra, |l, r| eq_expr(l, r)), - (MethodCall(lc, la, _), MethodCall(rc, ra, _)) => eq_path_seg(lc, rc) && over(la, ra, |l, r| eq_expr(l, r)), + (MethodCall(lc, ls, la, _), MethodCall(rc, rs, ra, _)) => { + eq_path_seg(lc, rc) && eq_expr(ls, rs) && over(la, ra, |l, r| eq_expr(l, r)) + }, (Binary(lo, ll, lr), Binary(ro, rl, rr)) => lo.node == ro.node && eq_expr(ll, rl) && eq_expr(lr, rr), (Unary(lo, l), Unary(ro, r)) => mem::discriminant(lo) == mem::discriminant(ro) && eq_expr(l, r), (Lit(l), Lit(r)) => l.kind == r.kind, From 6a73a454186c6795e692108b878492f8e25cd558 Mon Sep 17 00:00:00 2001 From: Lukas Lueg Date: Wed, 10 Aug 2022 19:40:42 +0200 Subject: [PATCH 3701/5092] Fix if_let_mutex not checking Mutexes behind refs Fixes #9193 --- clippy_lints/src/if_let_mutex.rs | 2 +- tests/ui/if_let_mutex.rs | 8 ++++++++ tests/ui/if_let_mutex.stderr | 14 +++++++++++++- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs index e95017007849..7c12a638529d 100644 --- a/clippy_lints/src/if_let_mutex.rs +++ b/clippy_lints/src/if_let_mutex.rs @@ -129,7 +129,7 @@ fn is_mutex_lock_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Opt if_chain! { if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind; if path.ident.as_str() == "lock"; - let ty = cx.typeck_results().expr_ty(self_arg); + let ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); if is_type_diagnostic_item(cx, ty, sym::Mutex); then { Some(self_arg) diff --git a/tests/ui/if_let_mutex.rs b/tests/ui/if_let_mutex.rs index 6cbfafbb38b9..321feb0224ed 100644 --- a/tests/ui/if_let_mutex.rs +++ b/tests/ui/if_let_mutex.rs @@ -39,4 +39,12 @@ fn if_let_different_mutex() { }; } +fn mutex_ref(mutex: &Mutex) { + if let Ok(i) = mutex.lock() { + do_stuff(i); + } else { + let _x = mutex.lock(); + }; +} + fn main() {} diff --git a/tests/ui/if_let_mutex.stderr b/tests/ui/if_let_mutex.stderr index e9c4d9163328..a831090c1f98 100644 --- a/tests/ui/if_let_mutex.stderr +++ b/tests/ui/if_let_mutex.stderr @@ -25,5 +25,17 @@ LL | | }; | = help: move the lock call outside of the `if let ...` expression -error: aborting due to 2 previous errors +error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock + --> $DIR/if_let_mutex.rs:43:5 + | +LL | / if let Ok(i) = mutex.lock() { +LL | | do_stuff(i); +LL | | } else { +LL | | let _x = mutex.lock(); +LL | | }; + | |_____^ + | + = help: move the lock call outside of the `if let ...` expression + +error: aborting due to 3 previous errors From 0428f0d234319649ce7b7d1571ec169d58a6642e Mon Sep 17 00:00:00 2001 From: Lukas Lueg Date: Wed, 10 Aug 2022 20:56:44 +0200 Subject: [PATCH 3702/5092] Add labels to if_let_mutex --- clippy_lints/src/if_let_mutex.rs | 48 +++++++++++++++++--------------- tests/ui/if_let_mutex.stderr | 18 ++++++++++-- 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs index 7c12a638529d..b6f9fefdee99 100644 --- a/clippy_lints/src/if_let_mutex.rs +++ b/clippy_lints/src/if_let_mutex.rs @@ -1,8 +1,9 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::SpanlessEq; use if_chain::if_chain; +use rustc_errors::Diagnostic; use rustc_hir::intravisit::{self as visit, Visitor}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -45,16 +46,8 @@ declare_lint_pass!(IfLetMutex => [IF_LET_MUTEX]); impl<'tcx> LateLintPass<'tcx> for IfLetMutex { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - let mut arm_visit = ArmVisitor { - mutex_lock_called: false, - found_mutex: None, - cx, - }; - let mut op_visit = OppVisitor { - mutex_lock_called: false, - found_mutex: None, - cx, - }; + let mut arm_visit = ArmVisitor { found_mutex: None, cx }; + let mut op_visit = OppVisitor { found_mutex: None, cx }; if let Some(higher::IfLet { let_expr, if_then, @@ -63,18 +56,28 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex { }) = higher::IfLet::hir(cx, expr) { op_visit.visit_expr(let_expr); - if op_visit.mutex_lock_called { + if let Some(op_mutex) = op_visit.found_mutex { arm_visit.visit_expr(if_then); arm_visit.visit_expr(if_else); - if arm_visit.mutex_lock_called && arm_visit.same_mutex(cx, op_visit.found_mutex.unwrap()) { - span_lint_and_help( + if let Some(arm_mutex) = arm_visit.found_mutex_if_same_as(op_mutex) { + let diag = |diag: &mut Diagnostic| { + diag.span_label( + op_mutex.span, + "This Mutex will remain locked for the entire `if let`-block...", + ); + diag.span_label( + arm_mutex.span, + "... and is tried to lock again here, which will always deadlock.", + ); + diag.help("move the lock call outside of the `if let ...` expression"); + }; + span_lint_and_then( cx, IF_LET_MUTEX, expr.span, "calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock", - None, - "move the lock call outside of the `if let ...` expression", + diag, ); } } @@ -84,7 +87,6 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex { /// Checks if `Mutex::lock` is called in the `if let` expr. pub struct OppVisitor<'a, 'tcx> { - mutex_lock_called: bool, found_mutex: Option<&'tcx Expr<'tcx>>, cx: &'a LateContext<'tcx>, } @@ -93,7 +95,6 @@ impl<'tcx> Visitor<'tcx> for OppVisitor<'_, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { if let Some(mutex) = is_mutex_lock_call(self.cx, expr) { self.found_mutex = Some(mutex); - self.mutex_lock_called = true; return; } visit::walk_expr(self, expr); @@ -102,7 +103,6 @@ impl<'tcx> Visitor<'tcx> for OppVisitor<'_, 'tcx> { /// Checks if `Mutex::lock` is called in any of the branches. pub struct ArmVisitor<'a, 'tcx> { - mutex_lock_called: bool, found_mutex: Option<&'tcx Expr<'tcx>>, cx: &'a LateContext<'tcx>, } @@ -111,7 +111,6 @@ impl<'tcx> Visitor<'tcx> for ArmVisitor<'_, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { if let Some(mutex) = is_mutex_lock_call(self.cx, expr) { self.found_mutex = Some(mutex); - self.mutex_lock_called = true; return; } visit::walk_expr(self, expr); @@ -119,9 +118,12 @@ impl<'tcx> Visitor<'tcx> for ArmVisitor<'_, 'tcx> { } impl<'tcx, 'l> ArmVisitor<'tcx, 'l> { - fn same_mutex(&self, cx: &LateContext<'_>, op_mutex: &Expr<'_>) -> bool { - self.found_mutex - .map_or(false, |arm_mutex| SpanlessEq::new(cx).eq_expr(op_mutex, arm_mutex)) + fn found_mutex_if_same_as(&self, op_mutex: &Expr<'_>) -> Option<&Expr<'_>> { + self.found_mutex.and_then(|arm_mutex| { + SpanlessEq::new(self.cx) + .eq_expr(op_mutex, arm_mutex) + .then_some(arm_mutex) + }) } } diff --git a/tests/ui/if_let_mutex.stderr b/tests/ui/if_let_mutex.stderr index a831090c1f98..6dbfc4be4127 100644 --- a/tests/ui/if_let_mutex.stderr +++ b/tests/ui/if_let_mutex.stderr @@ -1,10 +1,14 @@ error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock --> $DIR/if_let_mutex.rs:10:5 | -LL | / if let Err(locked) = m.lock() { +LL | if let Err(locked) = m.lock() { + | ^ - This Mutex will remain locked for the entire `if let`-block... + | _____| + | | LL | | do_stuff(locked); LL | | } else { LL | | let lock = m.lock().unwrap(); + | | - ... and is tried to lock again here, which will always deadlock. LL | | do_stuff(lock); LL | | }; | |_____^ @@ -15,10 +19,14 @@ LL | | }; error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock --> $DIR/if_let_mutex.rs:22:5 | -LL | / if let Some(locked) = m.lock().unwrap().deref() { +LL | if let Some(locked) = m.lock().unwrap().deref() { + | ^ - This Mutex will remain locked for the entire `if let`-block... + | _____| + | | LL | | do_stuff(locked); LL | | } else { LL | | let lock = m.lock().unwrap(); + | | - ... and is tried to lock again here, which will always deadlock. LL | | do_stuff(lock); LL | | }; | |_____^ @@ -28,10 +36,14 @@ LL | | }; error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock --> $DIR/if_let_mutex.rs:43:5 | -LL | / if let Ok(i) = mutex.lock() { +LL | if let Ok(i) = mutex.lock() { + | ^ ----- This Mutex will remain locked for the entire `if let`-block... + | _____| + | | LL | | do_stuff(i); LL | | } else { LL | | let _x = mutex.lock(); + | | ----- ... and is tried to lock again here, which will always deadlock. LL | | }; | |_____^ | From eb688958d3d87fb1c91d181dc5fbfbef7cfa634d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 11 Aug 2022 11:05:26 +1000 Subject: [PATCH 3703/5092] Simplify `rustc_ast::visit::Visitor::visit_poly_trait_ref`. It is passed an argument that is never used. --- clippy_lints/src/unused_unit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/unused_unit.rs b/clippy_lints/src/unused_unit.rs index 52585e59566c..cd1d90e860b9 100644 --- a/clippy_lints/src/unused_unit.rs +++ b/clippy_lints/src/unused_unit.rs @@ -89,7 +89,7 @@ impl EarlyLintPass for UnusedUnit { } } - fn check_poly_trait_ref(&mut self, cx: &EarlyContext<'_>, poly: &ast::PolyTraitRef, _: &ast::TraitBoundModifier) { + fn check_poly_trait_ref(&mut self, cx: &EarlyContext<'_>, poly: &ast::PolyTraitRef) { let segments = &poly.trait_ref.path.segments; if_chain! { From 459821b1914248180cac691128dd35d945bfde88 Mon Sep 17 00:00:00 2001 From: tamaron Date: Sat, 2 Jul 2022 12:57:57 +0900 Subject: [PATCH 3704/5092] fix --- clippy_lints/src/matches/needless_match.rs | 4 ++- tests/ui/needless_match.fixed | 26 +++++++++++++++++ tests/ui/needless_match.rs | 33 ++++++++++++++++++++++ tests/ui/needless_match.stderr | 23 ++++++++++++++- 4 files changed, 84 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/matches/needless_match.rs b/clippy_lints/src/matches/needless_match.rs index fa19cddd35ec..53a4a91d0e76 100644 --- a/clippy_lints/src/matches/needless_match.rs +++ b/clippy_lints/src/matches/needless_match.rs @@ -66,7 +66,9 @@ fn check_all_arms(cx: &LateContext<'_>, match_expr: &Expr<'_>, arms: &[Arm<'_>]) for arm in arms { let arm_expr = peel_blocks_with_stmt(arm.body); if let PatKind::Wild = arm.pat.kind { - return eq_expr_value(cx, match_expr, strip_return(arm_expr)); + if !eq_expr_value(cx, match_expr, strip_return(arm_expr)) { + return false; + } } else if !pat_same_as_expr(arm.pat, arm_expr) { return false; } diff --git a/tests/ui/needless_match.fixed b/tests/ui/needless_match.fixed index 0c9178fb85ef..9d4427f1df27 100644 --- a/tests/ui/needless_match.fixed +++ b/tests/ui/needless_match.fixed @@ -207,4 +207,30 @@ impl Tr for Result { } } +mod issue9084 { + fn wildcard_if() { + let some_bool = true; + let e = Some(1); + + // should lint + let _ = e; + + // should lint + let _ = e; + + // should not lint + let _ = match e { + _ if some_bool => e, + _ => Some(2), + }; + + // should not lint + let _ = match e { + Some(i) => Some(i + 1), + _ if some_bool => e, + _ => e, + }; + } +} + fn main() {} diff --git a/tests/ui/needless_match.rs b/tests/ui/needless_match.rs index f66f01d7ccaf..cae850fb0591 100644 --- a/tests/ui/needless_match.rs +++ b/tests/ui/needless_match.rs @@ -244,4 +244,37 @@ impl Tr for Result { } } +mod issue9084 { + fn wildcard_if() { + let some_bool = true; + let e = Some(1); + + // should lint + let _ = match e { + _ if some_bool => e, + _ => e, + }; + + // should lint + let _ = match e { + Some(i) => Some(i), + _ if some_bool => e, + _ => e, + }; + + // should not lint + let _ = match e { + _ if some_bool => e, + _ => Some(2), + }; + + // should not lint + let _ = match e { + Some(i) => Some(i + 1), + _ if some_bool => e, + _ => e, + }; + } +} + fn main() {} diff --git a/tests/ui/needless_match.stderr b/tests/ui/needless_match.stderr index 5bc79800a1a7..a173bbe4d77f 100644 --- a/tests/ui/needless_match.stderr +++ b/tests/ui/needless_match.stderr @@ -109,5 +109,26 @@ LL | | Complex::D(E::VariantB(ea, eb), b) => Complex::D(E::VariantB( LL | | }; | |_________^ help: replace it with: `ce` -error: aborting due to 11 previous errors +error: this match expression is unnecessary + --> $DIR/needless_match.rs:252:17 + | +LL | let _ = match e { + | _________________^ +LL | | _ if some_bool => e, +LL | | _ => e, +LL | | }; + | |_________^ help: replace it with: `e` + +error: this match expression is unnecessary + --> $DIR/needless_match.rs:258:17 + | +LL | let _ = match e { + | _________________^ +LL | | Some(i) => Some(i), +LL | | _ if some_bool => e, +LL | | _ => e, +LL | | }; + | |_________^ help: replace it with: `e` + +error: aborting due to 13 previous errors From 45084eeefb4edb981ce437c7fee6a07e61ff224b Mon Sep 17 00:00:00 2001 From: tamaron Date: Thu, 11 Aug 2022 12:00:46 +0900 Subject: [PATCH 3705/5092] give up when gurad has side effects --- clippy_lints/src/matches/needless_match.rs | 18 +++++++++++++++++- tests/ui/needless_match.fixed | 15 ++++++++++++++- tests/ui/needless_match.rs | 15 ++++++++++++++- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/matches/needless_match.rs b/clippy_lints/src/matches/needless_match.rs index 53a4a91d0e76..6f037339ec75 100644 --- a/clippy_lints/src/matches/needless_match.rs +++ b/clippy_lints/src/matches/needless_match.rs @@ -8,7 +8,7 @@ use clippy_utils::{ }; use rustc_errors::Applicability; use rustc_hir::LangItem::OptionNone; -use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, FnRetTy, Node, Pat, PatKind, Path, QPath}; +use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, FnRetTy, Guard, Node, Pat, PatKind, Path, QPath}; use rustc_lint::LateContext; use rustc_span::sym; use rustc_typeck::hir_ty_to_ty; @@ -65,6 +65,22 @@ pub(crate) fn check_if_let<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'_>, if_let: fn check_all_arms(cx: &LateContext<'_>, match_expr: &Expr<'_>, arms: &[Arm<'_>]) -> bool { for arm in arms { let arm_expr = peel_blocks_with_stmt(arm.body); + + if let Some(guard_expr) = &arm.guard { + match guard_expr { + // gives up if `pat if expr` can have side effects + Guard::If(if_cond) => { + if if_cond.can_have_side_effects() { + return false; + } + }, + // gives up `pat if let ...` arm + Guard::IfLet(_) => { + return false; + }, + }; + } + if let PatKind::Wild = arm.pat.kind { if !eq_expr_value(cx, match_expr, strip_return(arm_expr)) { return false; diff --git a/tests/ui/needless_match.fixed b/tests/ui/needless_match.fixed index 9d4427f1df27..7e47406798cf 100644 --- a/tests/ui/needless_match.fixed +++ b/tests/ui/needless_match.fixed @@ -209,7 +209,7 @@ impl Tr for Result { mod issue9084 { fn wildcard_if() { - let some_bool = true; + let mut some_bool = true; let e = Some(1); // should lint @@ -230,6 +230,19 @@ mod issue9084 { _ if some_bool => e, _ => e, }; + + // should not lint (guard has side effects) + let _ = match e { + Some(i) => Some(i), + _ if { + some_bool = false; + some_bool + } => + { + e + }, + _ => e, + }; } } diff --git a/tests/ui/needless_match.rs b/tests/ui/needless_match.rs index cae850fb0591..809c694bf400 100644 --- a/tests/ui/needless_match.rs +++ b/tests/ui/needless_match.rs @@ -246,7 +246,7 @@ impl Tr for Result { mod issue9084 { fn wildcard_if() { - let some_bool = true; + let mut some_bool = true; let e = Some(1); // should lint @@ -274,6 +274,19 @@ mod issue9084 { _ if some_bool => e, _ => e, }; + + // should not lint (guard has side effects) + let _ = match e { + Some(i) => Some(i), + _ if { + some_bool = false; + some_bool + } => + { + e + }, + _ => e, + }; } } From dc29cfb8d5338af23e6b06aaff6cc0229e688da0 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 11 Aug 2022 19:42:16 +0200 Subject: [PATCH 3706/5092] Merge commit '2b2190cb5667cdd276a24ef8b9f3692209c54a89' into clippyup --- CHANGELOG.md | 8 +- CONTRIBUTING.md | 6 +- Cargo.toml | 2 +- README.md | 2 +- book/src/configuration.md | 2 +- clippy_dev/src/new_lint.rs | 2 +- clippy_dev/src/update_lints.rs | 6 +- clippy_lints/Cargo.toml | 2 +- .../src/assertions_on_result_states.rs | 11 +- clippy_lints/src/booleans.rs | 6 +- .../src/casts/cast_abs_to_unsigned.rs | 2 +- clippy_lints/src/checked_conversions.rs | 5 +- clippy_lints/src/create_dir.rs | 4 +- clippy_lints/src/default.rs | 5 +- clippy_lints/src/dereference.rs | 334 +++++++++++------- ...lacklisted_name.rs => disallowed_names.rs} | 26 +- clippy_lints/src/formatting.rs | 6 +- clippy_lints/src/from_str_radix_10.rs | 11 +- clippy_lints/src/lib.register_all.rs | 6 +- clippy_lints/src/lib.register_correctness.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 6 +- clippy_lints/src/lib.register_nursery.rs | 1 + clippy_lints/src/lib.register_pedantic.rs | 1 + clippy_lints/src/lib.register_style.rs | 3 +- clippy_lints/src/lib.register_suspicious.rs | 1 - clippy_lints/src/lib.rs | 21 +- clippy_lints/src/loops/manual_memcpy.rs | 10 +- clippy_lints/src/loops/needless_range_loop.rs | 5 +- clippy_lints/src/manual_instant_elapsed.rs | 69 ++++ clippy_lints/src/manual_ok_or.rs | 11 +- clippy_lints/src/map_err_ignore.rs | 6 +- clippy_lints/src/map_unit_fn.rs | 6 +- clippy_lints/src/matches/match_as_ref.rs | 6 +- clippy_lints/src/matches/mod.rs | 8 +- clippy_lints/src/matches/try_err.rs | 6 +- clippy_lints/src/mem_replace.rs | 6 +- clippy_lints/src/methods/clone_on_copy.rs | 7 +- clippy_lints/src/methods/expect_used.rs | 10 +- clippy_lints/src/methods/mod.rs | 11 + clippy_lints/src/methods/unwrap_used.rs | 27 +- clippy_lints/src/missing_const_for_fn.rs | 18 +- clippy_lints/src/missing_doc.rs | 41 ++- clippy_lints/src/partialeq_to_none.rs | 104 ++++++ clippy_lints/src/path_buf_push_overwrite.rs | 6 +- clippy_lints/src/question_mark.rs | 3 +- clippy_lints/src/ranges.rs | 14 +- clippy_lints/src/redundant_closure_call.rs | 21 +- clippy_lints/src/regex.rs | 11 +- clippy_lints/src/renamed_lints.rs | 2 + .../src/slow_vector_initialization.rs | 9 +- clippy_lints/src/stable_sort_primitive.rs | 5 +- clippy_lints/src/unit_types/mod.rs | 2 +- clippy_lints/src/unit_types/unit_arg.rs | 5 +- clippy_lints/src/useless_conversion.rs | 23 +- clippy_lints/src/utils/conf.rs | 49 ++- clippy_lints/src/utils/internal_lints.rs | 16 +- .../internal_lints/metadata_collector.rs | 4 +- clippy_lints/src/verbose_file_reads.rs | 6 +- clippy_utils/Cargo.toml | 2 +- clippy_utils/src/check_proc_macro.rs | 329 +++++++++++++++++ clippy_utils/src/lib.rs | 2 + clippy_utils/src/numeric_literal.rs | 10 +- clippy_utils/src/paths.rs | 2 + clippy_utils/src/source.rs | 18 - clippy_utils/src/sugg.rs | 6 + clippy_utils/src/ty.rs | 54 +-- rust-toolchain | 2 +- .../check_clippy_version_attribute.stderr | 4 +- tests/ui-toml/bad_toml_type/clippy.toml | 2 +- .../bad_toml_type/conf_bad_type.stderr | 2 +- .../blacklisted_names.stderr | 16 - .../blacklisted_names_append/clippy.toml | 1 - .../blacklisted_names.stderr | 10 - .../blacklisted_names_replace/clippy.toml | 1 - tests/ui-toml/conf_deprecated_key/clippy.toml | 5 +- .../conf_deprecated_key.rs | 10 + .../conf_deprecated_key.stderr | 15 +- .../disallowed_names_append/clippy.toml | 1 + .../disallowed_names.rs} | 4 +- .../disallowed_names.stderr | 16 + .../disallowed_names_replace/clippy.toml | 1 + .../disallowed_names.rs} | 4 +- .../disallowed_names.stderr | 10 + tests/ui-toml/duplicated_keys/clippy.toml | 5 + .../duplicated_keys/duplicated_keys.rs | 1 + .../duplicated_keys/duplicated_keys.stderr | 8 + tests/ui-toml/expect_used/expect_used.stderr | 2 +- tests/ui-toml/toml_blacklist/clippy.toml | 1 - .../conf_french_blacklisted_name.stderr | 46 --- tests/ui-toml/toml_disallow/clippy.toml | 1 + .../conf_french_disallowed_name.rs} | 2 +- .../conf_french_disallowed_name.stderr | 46 +++ .../toml_unknown_key/conf_unknown_key.stderr | 1 + tests/ui/assertions_on_result_states.fixed | 8 + tests/ui/assertions_on_result_states.rs | 8 + tests/ui/assertions_on_result_states.stderr | 10 +- tests/ui/blacklisted_name.stderr | 88 ----- tests/ui/borrow_box.rs | 2 +- tests/ui/box_collection.rs | 2 +- tests/ui/cast_abs_to_unsigned.fixed | 2 + tests/ui/cast_abs_to_unsigned.rs | 2 + tests/ui/cast_abs_to_unsigned.stderr | 8 +- tests/ui/clone_on_copy.fixed | 7 +- tests/ui/clone_on_copy.rs | 7 +- tests/ui/clone_on_copy.stderr | 8 +- tests/ui/crashes/ice-2760.rs | 2 +- tests/ui/crashes/ice-3462.rs | 2 +- tests/ui/crashes/regressions.rs | 2 +- tests/ui/def_id_nocore.rs | 1 - tests/ui/def_id_nocore.stderr | 2 +- tests/ui/default_trait_access.fixed | 6 + tests/ui/default_trait_access.rs | 6 + tests/ui/default_trait_access.stderr | 18 +- ...lacklisted_name.rs => disallowed_names.rs} | 4 +- tests/ui/disallowed_names.stderr | 88 +++++ tests/ui/diverging_sub_expression.rs | 2 +- tests/ui/empty_loop_no_std.rs | 1 - tests/ui/empty_loop_no_std.stderr | 4 +- tests/ui/expect.stderr | 2 +- tests/ui/expect_tool_lint_rfc_2383.rs | 4 +- tests/ui/expect_tool_lint_rfc_2383.stderr | 4 +- tests/ui/explicit_auto_deref.fixed | 51 +++ tests/ui/explicit_auto_deref.rs | 51 +++ tests/ui/explicit_auto_deref.stderr | 144 +++++--- tests/ui/if_same_then_else.rs | 2 +- tests/ui/if_same_then_else2.rs | 2 +- tests/ui/ifs_same_cond.rs | 4 +- tests/ui/iter_skip_next.fixed | 2 +- tests/ui/iter_skip_next.rs | 2 +- tests/ui/let_if_seq.rs | 2 +- tests/ui/manual_assert.edition2018.fixed | 2 +- tests/ui/manual_assert.edition2021.fixed | 2 +- tests/ui/manual_assert.fixed | 2 +- tests/ui/manual_assert.rs | 2 +- tests/ui/manual_instant_elapsed.fixed | 27 ++ tests/ui/manual_instant_elapsed.rs | 27 ++ tests/ui/manual_instant_elapsed.stderr | 16 + tests/ui/manual_ok_or.fixed | 2 +- tests/ui/manual_ok_or.rs | 2 +- tests/ui/match_same_arms2.rs | 2 +- tests/ui/methods.rs | 2 +- tests/ui/mismatching_type_param_order.rs | 2 +- .../ui/missing_const_for_fn/cant_be_const.rs | 9 + tests/ui/{missing-doc.rs => missing_doc.rs} | 13 + ...{missing-doc.stderr => missing_doc.stderr} | 48 +-- ...sing-doc-crate.rs => missing_doc_crate.rs} | 0 ...issing.rs => missing_doc_crate_missing.rs} | 0 ...tderr => missing_doc_crate_missing.stderr} | 2 +- ...issing-doc-impl.rs => missing_doc_impl.rs} | 15 + ...oc-impl.stderr => missing_doc_impl.stderr} | 30 +- tests/ui/mistyped_literal_suffix.fixed | 6 + tests/ui/mistyped_literal_suffix.rs | 6 + tests/ui/mistyped_literal_suffix.stderr | 32 +- tests/ui/mixed_read_write_in_expression.rs | 2 +- tests/ui/op_ref.rs | 2 +- ...gic_bug.rs => overly_complex_bool_expr.rs} | 4 +- ...stderr => overly_complex_bool_expr.stderr} | 22 +- tests/ui/partialeq_to_none.fixed | 62 ++++ tests/ui/partialeq_to_none.rs | 62 ++++ tests/ui/partialeq_to_none.stderr | 110 ++++++ tests/ui/rc_mutex.rs | 2 +- tests/ui/redundant_allocation.rs | 12 +- tests/ui/redundant_allocation.stderr | 40 +-- tests/ui/redundant_allocation_fixable.fixed | 2 +- tests/ui/redundant_allocation_fixable.rs | 2 +- tests/ui/redundant_closure_call_fixable.fixed | 20 ++ tests/ui/redundant_closure_call_fixable.rs | 20 ++ .../ui/redundant_closure_call_fixable.stderr | 50 ++- tests/ui/rename.fixed | 4 + tests/ui/rename.rs | 4 + tests/ui/rename.stderr | 90 +++-- tests/ui/same_functions_in_if_condition.rs | 4 +- .../ui/same_functions_in_if_condition.stderr | 8 +- tests/ui/skip_while_next.rs | 2 +- tests/ui/swap.fixed | 2 +- tests/ui/swap.rs | 2 +- tests/ui/trivially_copy_pass_by_ref.rs | 2 +- tests/ui/unit_arg.rs | 12 +- tests/ui/unit_arg.stderr | 20 +- tests/ui/unwrap_expect_used.rs | 10 + tests/ui/unwrap_expect_used.stderr | 36 ++ tests/ui/used_underscore_binding.rs | 2 +- 182 files changed, 2240 insertions(+), 827 deletions(-) rename clippy_lints/src/{blacklisted_name.rs => disallowed_names.rs} (72%) create mode 100644 clippy_lints/src/manual_instant_elapsed.rs create mode 100644 clippy_lints/src/partialeq_to_none.rs create mode 100644 clippy_utils/src/check_proc_macro.rs delete mode 100644 tests/ui-toml/blacklisted_names_append/blacklisted_names.stderr delete mode 100644 tests/ui-toml/blacklisted_names_append/clippy.toml delete mode 100644 tests/ui-toml/blacklisted_names_replace/blacklisted_names.stderr delete mode 100644 tests/ui-toml/blacklisted_names_replace/clippy.toml create mode 100644 tests/ui-toml/disallowed_names_append/clippy.toml rename tests/ui-toml/{blacklisted_names_replace/blacklisted_names.rs => disallowed_names_append/disallowed_names.rs} (72%) create mode 100644 tests/ui-toml/disallowed_names_append/disallowed_names.stderr create mode 100644 tests/ui-toml/disallowed_names_replace/clippy.toml rename tests/ui-toml/{blacklisted_names_append/blacklisted_names.rs => disallowed_names_replace/disallowed_names.rs} (72%) create mode 100644 tests/ui-toml/disallowed_names_replace/disallowed_names.stderr create mode 100644 tests/ui-toml/duplicated_keys/clippy.toml create mode 100644 tests/ui-toml/duplicated_keys/duplicated_keys.rs create mode 100644 tests/ui-toml/duplicated_keys/duplicated_keys.stderr delete mode 100644 tests/ui-toml/toml_blacklist/clippy.toml delete mode 100644 tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr create mode 100644 tests/ui-toml/toml_disallow/clippy.toml rename tests/ui-toml/{toml_blacklist/conf_french_blacklisted_name.rs => toml_disallow/conf_french_disallowed_name.rs} (90%) create mode 100644 tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr delete mode 100644 tests/ui/blacklisted_name.stderr rename tests/ui/{blacklisted_name.rs => disallowed_names.rs} (92%) create mode 100644 tests/ui/disallowed_names.stderr create mode 100644 tests/ui/manual_instant_elapsed.fixed create mode 100644 tests/ui/manual_instant_elapsed.rs create mode 100644 tests/ui/manual_instant_elapsed.stderr rename tests/ui/{missing-doc.rs => missing_doc.rs} (82%) rename tests/ui/{missing-doc.stderr => missing_doc.stderr} (79%) rename tests/ui/{missing-doc-crate.rs => missing_doc_crate.rs} (100%) rename tests/ui/{missing-doc-crate-missing.rs => missing_doc_crate_missing.rs} (100%) rename tests/ui/{missing-doc-crate-missing.stderr => missing_doc_crate_missing.stderr} (86%) rename tests/ui/{missing-doc-impl.rs => missing_doc_impl.rs} (83%) rename tests/ui/{missing-doc-impl.stderr => missing_doc_impl.stderr} (78%) rename tests/ui/{logic_bug.rs => overly_complex_bool_expr.rs} (90%) rename tests/ui/{logic_bug.stderr => overly_complex_bool_expr.stderr} (76%) create mode 100644 tests/ui/partialeq_to_none.fixed create mode 100644 tests/ui/partialeq_to_none.rs create mode 100644 tests/ui/partialeq_to_none.stderr create mode 100644 tests/ui/unwrap_expect_used.rs create mode 100644 tests/ui/unwrap_expect_used.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 2278a8dc16ba..380cd451987b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -965,7 +965,7 @@ Released 2021-09-09 [#7407](https://github.com/rust-lang/rust-clippy/pull/7407) * [`redundant_allocation`]: Now additionally supports the `Arc<>` type [#7308](https://github.com/rust-lang/rust-clippy/pull/7308) -* [`blacklisted_name`]: Now allows blacklisted names in test code +* [`disallowed_names`]: Now allows disallowed names in test code [#7379](https://github.com/rust-lang/rust-clippy/pull/7379) * [`redundant_closure`]: Suggests `&mut` for `FnMut` [#7437](https://github.com/rust-lang/rust-clippy/pull/7437) @@ -2066,7 +2066,7 @@ Released 2020-08-27 [#5692](https://github.com/rust-lang/rust-clippy/pull/5692) * [`if_same_then_else`]: Don't assume multiplication is always commutative [#5702](https://github.com/rust-lang/rust-clippy/pull/5702) -* [`blacklisted_name`]: Remove `bar` from the default configuration +* [`disallowed_names`]: Remove `bar` from the default configuration [#5712](https://github.com/rust-lang/rust-clippy/pull/5712) * [`redundant_pattern_matching`]: Avoid suggesting non-`const fn` calls in const contexts [#5724](https://github.com/rust-lang/rust-clippy/pull/5724) @@ -3522,6 +3522,7 @@ Released 2018-09-13 [`derive_partial_eq_without_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_partial_eq_without_eq [`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method [`disallowed_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods +[`disallowed_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names [`disallowed_script_idents`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_script_idents [`disallowed_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_type [`disallowed_types`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types @@ -3685,6 +3686,7 @@ Released 2018-09-13 [`manual_find`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find [`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map [`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten +[`manual_instant_elapsed`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_instant_elapsed [`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy [`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive @@ -3816,11 +3818,13 @@ Released 2018-09-13 [`or_then_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#or_then_unwrap [`out_of_bounds_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#out_of_bounds_indexing [`overflow_check_conditional`]: https://rust-lang.github.io/rust-clippy/master/index.html#overflow_check_conditional +[`overly_complex_bool_expr`]: https://rust-lang.github.io/rust-clippy/master/index.html#overly_complex_bool_expr [`panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic [`panic_in_result_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_in_result_fn [`panic_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_params [`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap [`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl +[`partialeq_to_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_to_none [`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite [`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6e15133d267b..28b4cfd5f099 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -30,10 +30,10 @@ All contributors are expected to follow the [Rust Code of Conduct]. ## The Clippy book If you're new to Clippy and don't know where to start the [Clippy book] includes -a developer guide and is a good place to start your journey. +a [developer guide] and is a good place to start your journey. - -[Clippy book]: book/src +[Clippy book]: https://doc.rust-lang.org/nightly/clippy/index.html +[developer guide]: https://doc.rust-lang.org/nightly/clippy/development/index.html ## High level approach diff --git a/Cargo.toml b/Cargo.toml index 1c875c3adcf5..b7e136ce9b29 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.1.64" +version = "0.1.65" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/README.md b/README.md index 2c3defeaa830..1193771ff736 100644 --- a/README.md +++ b/README.md @@ -144,7 +144,7 @@ value` mapping e.g. ```toml avoid-breaking-exported-api = false -blacklisted-names = ["toto", "tata", "titi"] +disallowed-names = ["toto", "tata", "titi"] cognitive-complexity-threshold = 30 ``` diff --git a/book/src/configuration.md b/book/src/configuration.md index 6e295ac3181d..77f1d2e8797a 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -7,7 +7,7 @@ basic `variable = value` mapping eg. ```toml avoid-breaking-exported-api = false -blacklisted-names = ["toto", "tata", "titi"] +disallowed-names = ["toto", "tata", "titi"] cognitive-complexity-threshold = 30 ``` diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 03d2ef3d19ed..10a8f31f4573 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -438,7 +438,7 @@ fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str> let mut lint_context = None; let mut iter = rustc_lexer::tokenize(&file_contents).map(|t| { - let range = offset..offset + t.len; + let range = offset..offset + t.len as usize; offset = range.end; LintDeclSearchResult { diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index aed38bc28176..05e79a241884 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -836,7 +836,7 @@ pub(crate) struct LintDeclSearchResult<'a> { fn parse_contents(contents: &str, module: &str, lints: &mut Vec) { let mut offset = 0usize; let mut iter = tokenize(contents).map(|t| { - let range = offset..offset + t.len; + let range = offset..offset + t.len as usize; offset = range.end; LintDeclSearchResult { @@ -899,7 +899,7 @@ fn parse_contents(contents: &str, module: &str, lints: &mut Vec) { fn parse_deprecated_contents(contents: &str, lints: &mut Vec) { let mut offset = 0usize; let mut iter = tokenize(contents).map(|t| { - let range = offset..offset + t.len; + let range = offset..offset + t.len as usize; offset = range.end; LintDeclSearchResult { @@ -946,7 +946,7 @@ fn parse_renamed_contents(contents: &str, lints: &mut Vec) { for line in contents.lines() { let mut offset = 0usize; let mut iter = tokenize(line).map(|t| { - let range = offset..offset + t.len; + let range = offset..offset + t.len as usize; offset = range.end; LintDeclSearchResult { diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml index 79a56dc405d1..738562ef8559 100644 --- a/clippy_lints/Cargo.toml +++ b/clippy_lints/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_lints" -version = "0.1.64" +version = "0.1.65" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/clippy_lints/src/assertions_on_result_states.rs b/clippy_lints/src/assertions_on_result_states.rs index 4caab6230909..6a6554f968b3 100644 --- a/clippy_lints/src/assertions_on_result_states.rs +++ b/clippy_lints/src/assertions_on_result_states.rs @@ -53,13 +53,14 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { if result_type_with_refs != result_type { return; } else if let Res::Local(binding_id) = path_res(cx, recv) - && local_used_after_expr(cx, binding_id, recv) { + && local_used_after_expr(cx, binding_id, recv) + { return; } } let mut app = Applicability::MachineApplicable; match method_segment.ident.as_str() { - "is_ok" if has_debug_impl(cx, substs.type_at(1)) => { + "is_ok" if type_suitable_to_unwrap(cx, substs.type_at(1)) => { span_lint_and_sugg( cx, ASSERTIONS_ON_RESULT_STATES, @@ -73,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { app, ); } - "is_err" if has_debug_impl(cx, substs.type_at(0)) => { + "is_err" if type_suitable_to_unwrap(cx, substs.type_at(0)) => { span_lint_and_sugg( cx, ASSERTIONS_ON_RESULT_STATES, @@ -99,3 +100,7 @@ fn has_debug_impl<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { .get_diagnostic_item(sym::Debug) .map_or(false, |debug| implements_trait(cx, ty, debug, &[])) } + +fn type_suitable_to_unwrap<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + has_debug_impl(cx, ty) && !ty.is_unit() && !ty.is_never() +} diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 526ee2f891a1..6eb78d21e826 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -64,7 +64,7 @@ declare_clippy_lint! { /// if a {} /// ``` #[clippy::version = "pre 1.29.0"] - pub LOGIC_BUG, + pub OVERLY_COMPLEX_BOOL_EXPR, correctness, "boolean expressions that contain terminals which can be eliminated" } @@ -72,7 +72,7 @@ declare_clippy_lint! { // For each pairs, both orders are considered. const METHODS_WITH_NEGATION: [(&str, &str); 2] = [("is_some", "is_none"), ("is_err", "is_ok")]; -declare_lint_pass!(NonminimalBool => [NONMINIMAL_BOOL, LOGIC_BUG]); +declare_lint_pass!(NonminimalBool => [NONMINIMAL_BOOL, OVERLY_COMPLEX_BOOL_EXPR]); impl<'tcx> LateLintPass<'tcx> for NonminimalBool { fn check_fn( @@ -396,7 +396,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { if stats.terminals[i] != 0 && simplified_stats.terminals[i] == 0 { span_lint_hir_and_then( self.cx, - LOGIC_BUG, + OVERLY_COMPLEX_BOOL_EXPR, e.hir_id, e.span, "this boolean expression contains a logic bug", diff --git a/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/clippy_lints/src/casts/cast_abs_to_unsigned.rs index 64ea326b75a0..6426e8c25ac1 100644 --- a/clippy_lints/src/casts/cast_abs_to_unsigned.rs +++ b/clippy_lints/src/casts/cast_abs_to_unsigned.rs @@ -37,7 +37,7 @@ pub(super) fn check( span, &format!("casting the result of `{cast_from}::abs()` to {cast_to}"), "replace with", - format!("{}.unsigned_abs()", Sugg::hir(cx, &args[0], "..")), + format!("{}.unsigned_abs()", Sugg::hir(cx, &args[0], "..").maybe_par()), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/checked_conversions.rs b/clippy_lints/src/checked_conversions.rs index 17fc81951f95..37b2fdcff09f 100644 --- a/clippy_lints/src/checked_conversions.rs +++ b/clippy_lints/src/checked_conversions.rs @@ -270,10 +270,7 @@ fn get_types_from_cast<'a>( let limit_from: Option<(&Expr<'_>, &str)> = call_from_cast.or_else(|| { if_chain! { // `from_type::from, to_type::max_value()` - if let ExprKind::Call(from_func, args) = &expr.kind; - // `to_type::max_value()` - if args.len() == 1; - if let limit = &args[0]; + if let ExprKind::Call(from_func, [limit]) = &expr.kind; // `from_type::from` if let ExprKind::Path(ref path) = &from_func.kind; if let Some(from_sym) = get_implementing_type(path, INTS, "from"); diff --git a/clippy_lints/src/create_dir.rs b/clippy_lints/src/create_dir.rs index 18d34370a7b8..878248a6bdc8 100644 --- a/clippy_lints/src/create_dir.rs +++ b/clippy_lints/src/create_dir.rs @@ -34,7 +34,7 @@ declare_lint_pass!(CreateDir => [CREATE_DIR]); impl LateLintPass<'_> for CreateDir { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { - if let ExprKind::Call(func, args) = expr.kind; + if let ExprKind::Call(func, [arg, ..]) = expr.kind; if let ExprKind::Path(ref path) = func.kind; if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id(); if match_def_path(cx, def_id, &paths::STD_FS_CREATE_DIR); @@ -45,7 +45,7 @@ impl LateLintPass<'_> for CreateDir { expr.span, "calling `std::fs::create_dir` where there may be a better way", "consider calling `std::fs::create_dir_all` instead", - format!("create_dir_all({})", snippet(cx, args[0].span, "..")), + format!("create_dir_all({})", snippet(cx, arg.span, "..")), Applicability::MaybeIncorrect, ) } diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index d99a1aa29694..74f7df611778 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -1,7 +1,9 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; use clippy_utils::source::snippet_with_macro_callsite; use clippy_utils::ty::{has_drop, is_copy}; -use clippy_utils::{any_parent_is_automatically_derived, contains_name, get_parent_expr, match_def_path, paths}; +use clippy_utils::{ + any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro, match_def_path, paths, +}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -94,6 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { if let QPath::Resolved(None, _path) = qpath; let expr_ty = cx.typeck_results().expr_ty(expr); if let ty::Adt(def, ..) = expr_ty.kind(); + if !is_from_proc_macro(cx, expr); then { // TODO: Work out a way to put "whatever the imported way of referencing // this type in this file" rather than a fully-qualified type. diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index a90f894a7b19..5d41c63928df 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; -use clippy_utils::ty::{expr_sig, peel_mid_ty_refs, variant_of_res}; +use clippy_utils::ty::{expr_sig, peel_mid_ty_refs, ty_sig, variant_of_res}; use clippy_utils::{get_parent_expr, is_lint_allowed, path_to_local, walk_to_expr_usage}; use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX}; use rustc_data_structures::fx::FxIndexMap; @@ -15,9 +15,9 @@ use rustc_hir::{ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable, TypeckResults}; +use rustc_middle::ty::{self, Binder, BoundVariableKind, List, Ty, TyCtxt, TypeVisitable, TypeckResults}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::{symbol::sym, Span, Symbol}; +use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP}; use rustc_trait_selection::infer::InferCtxtExt; declare_clippy_lint! { @@ -183,24 +183,24 @@ enum State { }, DerefedBorrow(DerefedBorrow), ExplicitDeref { - // Span and id of the top-level deref expression if the parent expression is a borrow. - deref_span_id: Option<(Span, HirId)>, + mutability: Option, }, ExplicitDerefField { name: Symbol, }, Reborrow { - deref_span: Span, - deref_hir_id: HirId, + mutability: Mutability, + }, + Borrow { + mutability: Mutability, }, - Borrow, } // A reference operation considered by this lint pass enum RefOp { Method(Mutability), Deref, - AddrOf, + AddrOf(Mutability), } struct RefPat { @@ -263,7 +263,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { )); } else if position.is_deref_stable() { self.state = Some(( - State::ExplicitDeref { deref_span_id: None }, + State::ExplicitDeref { mutability: None }, StateData { span: expr.span, hir_id: expr.hir_id, position }, )); } @@ -289,7 +289,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { }, )); }, - RefOp::AddrOf => { + RefOp::AddrOf(mutability) => { // Find the number of times the borrow is auto-derefed. let mut iter = adjustments.iter(); let mut deref_count = 0usize; @@ -357,9 +357,13 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { }), StateData { span: expr.span, hir_id: expr.hir_id, position }, )); - } else if position.is_deref_stable() { + } else if position.is_deref_stable() + // Auto-deref doesn't combine with other adjustments + && next_adjust.map_or(true, |a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_))) + && iter.all(|a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_))) + { self.state = Some(( - State::Borrow, + State::Borrow { mutability }, StateData { span: expr.span, hir_id: expr.hir_id, @@ -395,7 +399,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { data, )); }, - (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf) if state.count != 0 => { + (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf(_)) if state.count != 0 => { self.state = Some(( State::DerefedBorrow(DerefedBorrow { count: state.count - 1, @@ -404,12 +408,12 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { data, )); }, - (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf) => { + (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf(mutability)) => { let position = data.position; report(cx, expr, State::DerefedBorrow(state), data); if position.is_deref_stable() { self.state = Some(( - State::Borrow, + State::Borrow { mutability }, StateData { span: expr.span, hir_id: expr.hir_id, @@ -430,43 +434,28 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { )); } else if position.is_deref_stable() { self.state = Some(( - State::ExplicitDeref { deref_span_id: None }, + State::ExplicitDeref { mutability: None }, StateData { span: expr.span, hir_id: expr.hir_id, position }, )); } }, - (Some((State::Borrow, data)), RefOp::Deref) => { + (Some((State::Borrow { mutability }, data)), RefOp::Deref) => { if typeck.expr_ty(sub_expr).is_ref() { - self.state = Some(( - State::Reborrow { - deref_span: expr.span, - deref_hir_id: expr.hir_id, - }, - data, - )); + self.state = Some((State::Reborrow { mutability }, data)); } else { self.state = Some(( State::ExplicitDeref { - deref_span_id: Some((expr.span, expr.hir_id)), + mutability: Some(mutability), }, data, )); } }, - ( - Some(( - State::Reborrow { - deref_span, - deref_hir_id, - }, - data, - )), - RefOp::Deref, - ) => { + (Some((State::Reborrow { mutability }, data)), RefOp::Deref) => { self.state = Some(( State::ExplicitDeref { - deref_span_id: Some((deref_span, deref_hir_id)), + mutability: Some(mutability), }, data, )); @@ -573,7 +562,7 @@ fn try_parse_ref_op<'tcx>( ExprKind::Unary(UnOp::Deref, sub_expr) if !typeck.expr_ty(sub_expr).is_unsafe_ptr() => { return Some((RefOp::Deref, sub_expr)); }, - ExprKind::AddrOf(BorrowKind::Ref, _, sub_expr) => return Some((RefOp::AddrOf, sub_expr)), + ExprKind::AddrOf(BorrowKind::Ref, mutability, sub_expr) => return Some((RefOp::AddrOf(mutability), sub_expr)), _ => return None, }; if tcx.is_diagnostic_item(sym::deref_method, def_id) { @@ -609,18 +598,21 @@ enum Position { Postfix, Deref, /// Any other location which will trigger auto-deref to a specific time. - DerefStable(i8), + /// Contains the precedence of the parent expression and whether the target type is sized. + DerefStable(i8, bool), /// Any other location which will trigger auto-reborrowing. + /// Contains the precedence of the parent expression. ReborrowStable(i8), + /// Contains the precedence of the parent expression. Other(i8), } impl Position { fn is_deref_stable(self) -> bool { - matches!(self, Self::DerefStable(_)) + matches!(self, Self::DerefStable(..)) } fn is_reborrow_stable(self) -> bool { - matches!(self, Self::DerefStable(_) | Self::ReborrowStable(_)) + matches!(self, Self::DerefStable(..) | Self::ReborrowStable(_)) } fn can_auto_borrow(self) -> bool { @@ -628,7 +620,7 @@ impl Position { } fn lint_explicit_deref(self) -> bool { - matches!(self, Self::Other(_) | Self::DerefStable(_) | Self::ReborrowStable(_)) + matches!(self, Self::Other(_) | Self::DerefStable(..) | Self::ReborrowStable(_)) } fn precedence(self) -> i8 { @@ -639,7 +631,7 @@ impl Position { | Self::FieldAccess(_) | Self::Postfix => PREC_POSTFIX, Self::Deref => PREC_PREFIX, - Self::DerefStable(p) | Self::ReborrowStable(p) | Self::Other(p) => p, + Self::DerefStable(p, _) | Self::ReborrowStable(p) | Self::Other(p) => p, } } } @@ -659,7 +651,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & } match parent { Node::Local(Local { ty: Some(ty), span, .. }) if span.ctxt() == ctxt => { - Some(binding_ty_auto_deref_stability(ty, precedence)) + Some(binding_ty_auto_deref_stability(cx, ty, precedence, List::empty())) }, Node::Item(&Item { kind: ItemKind::Static(..) | ItemKind::Const(..), @@ -680,11 +672,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & .. }) if span.ctxt() == ctxt => { let ty = cx.tcx.type_of(def_id); - Some(if ty.is_ref() { - Position::DerefStable(precedence) - } else { - Position::Other(precedence) - }) + Some(ty_auto_deref_stability(cx, ty, precedence).position_for_result(cx)) }, Node::Item(&Item { @@ -705,45 +693,38 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & span, .. }) if span.ctxt() == ctxt => { - let output = cx.tcx.fn_sig(def_id.to_def_id()).skip_binder().output(); - Some(if !output.is_ref() { - Position::Other(precedence) - } else if output.has_placeholders() || output.has_opaque_types() { - Position::ReborrowStable(precedence) - } else { - Position::DerefStable(precedence) - }) + let output = cx + .tcx + .erase_late_bound_regions(cx.tcx.fn_sig(def_id.to_def_id()).output()); + Some(ty_auto_deref_stability(cx, output, precedence).position_for_result(cx)) }, Node::Expr(parent) if parent.span.ctxt() == ctxt => match parent.kind { ExprKind::Ret(_) => { let owner_id = cx.tcx.hir().body_owner(cx.enclosing_body.unwrap()); Some( - if let Node::Expr(Expr { - kind: ExprKind::Closure(&Closure { fn_decl, .. }), - .. - }) = cx.tcx.hir().get(owner_id) + if let Node::Expr( + closure_expr @ Expr { + kind: ExprKind::Closure(closure), + .. + }, + ) = cx.tcx.hir().get(owner_id) { - match fn_decl.output { - FnRetTy::Return(ty) => binding_ty_auto_deref_stability(ty, precedence), - FnRetTy::DefaultReturn(_) => Position::Other(precedence), - } + closure_result_position(cx, closure, cx.typeck_results().expr_ty(closure_expr), precedence) } else { let output = cx .tcx - .fn_sig(cx.tcx.hir().local_def_id(owner_id)) - .skip_binder() - .output(); - if !output.is_ref() { - Position::Other(precedence) - } else if output.has_placeholders() || output.has_opaque_types() { - Position::ReborrowStable(precedence) - } else { - Position::DerefStable(precedence) - } + .erase_late_bound_regions(cx.tcx.fn_sig(cx.tcx.hir().local_def_id(owner_id)).output()); + ty_auto_deref_stability(cx, output, precedence).position_for_result(cx) }, ) }, + ExprKind::Closure(closure) => Some(closure_result_position( + cx, + closure, + cx.typeck_results().expr_ty(parent), + precedence, + )), ExprKind::Call(func, _) if func.hir_id == child_id => { (child_id == e.hir_id).then_some(Position::Callee) }, @@ -755,8 +736,9 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & .map(|(hir_ty, ty)| match hir_ty { // Type inference for closures can depend on how they're called. Only go by the explicit // types here. - Some(ty) => binding_ty_auto_deref_stability(ty, precedence), - None => param_auto_deref_stability(ty.skip_binder(), precedence), + Some(hir_ty) => binding_ty_auto_deref_stability(cx, hir_ty, precedence, ty.bound_vars()), + None => ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence) + .position_for_arg(), }), ExprKind::MethodCall(_, args, _) => { let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap(); @@ -797,7 +779,12 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & Position::MethodReceiver } } else { - param_auto_deref_stability(cx.tcx.fn_sig(id).skip_binder().inputs()[i], precedence) + ty_auto_deref_stability( + cx, + cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)), + precedence, + ) + .position_for_arg() } }) }, @@ -808,7 +795,9 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & .find(|f| f.expr.hir_id == child_id) .zip(variant) .and_then(|(field, variant)| variant.fields.iter().find(|f| f.name == field.ident.name)) - .map(|field| param_auto_deref_stability(cx.tcx.type_of(field.did), precedence)) + .map(|field| { + ty_auto_deref_stability(cx, cx.tcx.type_of(field.did), precedence).position_for_arg() + }) }, ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess(name.name)), ExprKind::Unary(UnOp::Deref, child) if child.hir_id == e.hir_id => Some(Position::Deref), @@ -831,6 +820,26 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & (position, adjustments) } +fn closure_result_position<'tcx>( + cx: &LateContext<'tcx>, + closure: &'tcx Closure<'_>, + ty: Ty<'tcx>, + precedence: i8, +) -> Position { + match closure.fn_decl.output { + FnRetTy::Return(hir_ty) => { + if let Some(sig) = ty_sig(cx, ty) + && let Some(output) = sig.output() + { + binding_ty_auto_deref_stability(cx, hir_ty, precedence, output.bound_vars()) + } else { + Position::Other(precedence) + } + }, + FnRetTy::DefaultReturn(_) => Position::Other(precedence), + } +} + // Checks the stability of auto-deref when assigned to a binding with the given explicit type. // // e.g. @@ -840,7 +849,12 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & // // Here `y1` and `y2` would resolve to different types, so the type `&Box<_>` is not stable when // switching to auto-dereferencing. -fn binding_ty_auto_deref_stability(ty: &hir::Ty<'_>, precedence: i8) -> Position { +fn binding_ty_auto_deref_stability<'tcx>( + cx: &LateContext<'tcx>, + ty: &'tcx hir::Ty<'_>, + precedence: i8, + binder_args: &'tcx List, +) -> Position { let TyKind::Rptr(_, ty) = &ty.kind else { return Position::Other(precedence); }; @@ -870,21 +884,33 @@ fn binding_ty_auto_deref_stability(ty: &hir::Ty<'_>, precedence: i8) -> Position { Position::ReborrowStable(precedence) } else { - Position::DerefStable(precedence) + Position::DerefStable( + precedence, + cx.tcx + .erase_late_bound_regions(Binder::bind_with_vars( + cx.typeck_results().node_type(ty.ty.hir_id), + binder_args, + )) + .is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()), + ) } }, - TyKind::Slice(_) - | TyKind::Array(..) - | TyKind::BareFn(_) - | TyKind::Never + TyKind::Slice(_) => Position::DerefStable(precedence, false), + TyKind::Array(..) | TyKind::Ptr(_) | TyKind::BareFn(_) => Position::DerefStable(precedence, true), + TyKind::Never | TyKind::Tup(_) - | TyKind::Ptr(_) - | TyKind::TraitObject(..) - | TyKind::Path(_) => Position::DerefStable(precedence), - TyKind::OpaqueDef(..) - | TyKind::Infer - | TyKind::Typeof(..) - | TyKind::Err => Position::ReborrowStable(precedence), + | TyKind::Path(_) => Position::DerefStable( + precedence, + cx.tcx + .erase_late_bound_regions(Binder::bind_with_vars( + cx.typeck_results().node_type(ty.ty.hir_id), + binder_args, + )) + .is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()), + ), + TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::Err => { + Position::ReborrowStable(precedence) + }, }; } } @@ -920,10 +946,39 @@ fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool { v.0 } +struct TyPosition<'tcx> { + position: Position, + ty: Option>, +} +impl From for TyPosition<'_> { + fn from(position: Position) -> Self { + Self { position, ty: None } + } +} +impl<'tcx> TyPosition<'tcx> { + fn new_deref_stable_for_result(precedence: i8, ty: Ty<'tcx>) -> Self { + Self { + position: Position::ReborrowStable(precedence), + ty: Some(ty), + } + } + fn position_for_result(self, cx: &LateContext<'tcx>) -> Position { + match (self.position, self.ty) { + (Position::ReborrowStable(precedence), Some(ty)) => { + Position::DerefStable(precedence, ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env)) + }, + (position, _) => position, + } + } + fn position_for_arg(self) -> Position { + self.position + } +} + // Checks whether a type is stable when switching to auto dereferencing, -fn param_auto_deref_stability(ty: Ty<'_>, precedence: i8) -> Position { +fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedence: i8) -> TyPosition<'tcx> { let ty::Ref(_, mut ty, _) = *ty.kind() else { - return Position::Other(precedence); + return Position::Other(precedence).into(); }; loop { @@ -932,35 +987,38 @@ fn param_auto_deref_stability(ty: Ty<'_>, precedence: i8) -> Position { ty = ref_ty; continue; }, - ty::Infer(_) - | ty::Error(_) - | ty::Param(_) - | ty::Bound(..) - | ty::Opaque(..) - | ty::Placeholder(_) - | ty::Dynamic(..) => Position::ReborrowStable(precedence), - ty::Adt(..) if ty.has_placeholders() || ty.has_param_types_or_consts() => { - Position::ReborrowStable(precedence) + ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty), + ty::Infer(_) | ty::Error(_) | ty::Bound(..) | ty::Opaque(..) | ty::Placeholder(_) | ty::Dynamic(..) => { + Position::ReborrowStable(precedence).into() }, - ty::Adt(..) - | ty::Bool + ty::Adt(..) if ty.has_placeholders() || ty.has_opaque_types() => { + Position::ReborrowStable(precedence).into() + }, + ty::Adt(_, substs) if substs.has_param_types_or_consts() => { + TyPosition::new_deref_stable_for_result(precedence, ty) + }, + ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) - | ty::Float(_) - | ty::Foreign(_) - | ty::Str | ty::Array(..) - | ty::Slice(..) + | ty::Float(_) | ty::RawPtr(..) + | ty::FnPtr(_) => Position::DerefStable(precedence, true).into(), + ty::Str | ty::Slice(..) => Position::DerefStable(precedence, false).into(), + ty::Adt(..) + | ty::Foreign(_) | ty::FnDef(..) - | ty::FnPtr(_) - | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::Closure(..) | ty::Never | ty::Tuple(_) - | ty::Projection(_) => Position::DerefStable(precedence), + | ty::Projection(_) => Position::DerefStable( + precedence, + ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()), + ) + .into(), }; } } @@ -1040,34 +1098,64 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data diag.span_suggestion(data.span, "change this to", sugg, app); }); }, - State::ExplicitDeref { deref_span_id } => { - let (span, hir_id, precedence) = if let Some((span, hir_id)) = deref_span_id + State::ExplicitDeref { mutability } => { + if matches!( + expr.kind, + ExprKind::Block(..) + | ExprKind::ConstBlock(_) + | ExprKind::If(..) + | ExprKind::Loop(..) + | ExprKind::Match(..) + ) && matches!(data.position, Position::DerefStable(_, true)) + { + // Rustc bug: auto deref doesn't work on block expression when targeting sized types. + return; + } + + let (prefix, precedence) = if let Some(mutability) = mutability && !cx.typeck_results().expr_ty(expr).is_ref() { - (span, hir_id, PREC_PREFIX) + let prefix = match mutability { + Mutability::Not => "&", + Mutability::Mut => "&mut ", + }; + (prefix, 0) } else { - (data.span, data.hir_id, data.position.precedence()) + ("", data.position.precedence()) }; span_lint_hir_and_then( cx, EXPLICIT_AUTO_DEREF, - hir_id, - span, + data.hir_id, + data.span, "deref which would be done by auto-deref", |diag| { let mut app = Applicability::MachineApplicable; - let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, span.ctxt(), "..", &mut app); + let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app); let sugg = if !snip_is_macro && expr.precedence().order() < precedence && !has_enclosing_paren(&snip) { - format!("({})", snip) + format!("{}({})", prefix, snip) } else { - snip.into() + format!("{}{}", prefix, snip) }; - diag.span_suggestion(span, "try this", sugg, app); + diag.span_suggestion(data.span, "try this", sugg, app); }, ); }, State::ExplicitDerefField { .. } => { + if matches!( + expr.kind, + ExprKind::Block(..) + | ExprKind::ConstBlock(_) + | ExprKind::If(..) + | ExprKind::Loop(..) + | ExprKind::Match(..) + ) && matches!(data.position, Position::DerefStable(_, true)) + { + // Rustc bug: auto deref doesn't work on block expression when targeting sized types. + return; + } + span_lint_hir_and_then( cx, EXPLICIT_AUTO_DEREF, @@ -1081,7 +1169,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data }, ); }, - State::Borrow | State::Reborrow { .. } => (), + State::Borrow { .. } | State::Reborrow { .. } => (), } } diff --git a/clippy_lints/src/blacklisted_name.rs b/clippy_lints/src/disallowed_names.rs similarity index 72% rename from clippy_lints/src/blacklisted_name.rs rename to clippy_lints/src/disallowed_names.rs index 1600fb25d89e..6e6615f08ee7 100644 --- a/clippy_lints/src/blacklisted_name.rs +++ b/clippy_lints/src/disallowed_names.rs @@ -6,7 +6,7 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { /// ### What it does - /// Checks for usage of blacklisted names for variables, such + /// Checks for usage of disallowed names for variables, such /// as `foo`. /// /// ### Why is this bad? @@ -18,21 +18,21 @@ declare_clippy_lint! { /// let foo = 3.14; /// ``` #[clippy::version = "pre 1.29.0"] - pub BLACKLISTED_NAME, + pub DISALLOWED_NAMES, style, - "usage of a blacklisted/placeholder name" + "usage of a disallowed/placeholder name" } #[derive(Clone, Debug)] -pub struct BlacklistedName { - blacklist: FxHashSet, +pub struct DisallowedNames { + disallow: FxHashSet, test_modules_deep: u32, } -impl BlacklistedName { - pub fn new(blacklist: FxHashSet) -> Self { +impl DisallowedNames { + pub fn new(disallow: FxHashSet) -> Self { Self { - blacklist, + disallow, test_modules_deep: 0, } } @@ -42,9 +42,9 @@ impl BlacklistedName { } } -impl_lint_pass!(BlacklistedName => [BLACKLISTED_NAME]); +impl_lint_pass!(DisallowedNames => [DISALLOWED_NAMES]); -impl<'tcx> LateLintPass<'tcx> for BlacklistedName { +impl<'tcx> LateLintPass<'tcx> for DisallowedNames { fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { if is_test_module_or_function(cx.tcx, item) { self.test_modules_deep = self.test_modules_deep.saturating_add(1); @@ -58,12 +58,12 @@ impl<'tcx> LateLintPass<'tcx> for BlacklistedName { } if let PatKind::Binding(.., ident, _) = pat.kind { - if self.blacklist.contains(&ident.name.to_string()) { + if self.disallow.contains(&ident.name.to_string()) { span_lint( cx, - BLACKLISTED_NAME, + DISALLOWED_NAMES, ident.span, - &format!("use of a blacklisted/placeholder name `{}`", ident.name), + &format!("use of a disallowed/placeholder name `{}`", ident.name), ); } } diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs index db0166da57f0..01cefe4af853 100644 --- a/clippy_lints/src/formatting.rs +++ b/clippy_lints/src/formatting.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note}; +use clippy_utils::is_span_if; use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp}; @@ -297,12 +298,11 @@ fn check_array(cx: &EarlyContext<'_>, expr: &Expr) { fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) { if_chain! { if !first.span.from_expansion() && !second.span.from_expansion(); - if let ExprKind::If(cond_expr, ..) = &first.kind; + if matches!(first.kind, ExprKind::If(..)); if is_block(second) || is_if(second); // Proc-macros can give weird spans. Make sure this is actually an `if`. - if let Some(if_snip) = snippet_opt(cx, first.span.until(cond_expr.span)); - if if_snip.starts_with("if"); + if is_span_if(cx, first.span); // If there is a line break between the two expressions, don't lint. // If there is a non-whitespace character, this span came from a proc-macro. diff --git a/clippy_lints/src/from_str_radix_10.rs b/clippy_lints/src/from_str_radix_10.rs index 57b075132052..74941d817be3 100644 --- a/clippy_lints/src/from_str_radix_10.rs +++ b/clippy_lints/src/from_str_radix_10.rs @@ -46,7 +46,7 @@ declare_lint_pass!(FromStrRadix10 => [FROM_STR_RADIX_10]); impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 { fn check_expr(&mut self, cx: &LateContext<'tcx>, exp: &Expr<'tcx>) { if_chain! { - if let ExprKind::Call(maybe_path, arguments) = &exp.kind; + if let ExprKind::Call(maybe_path, [src, radix]) = &exp.kind; if let ExprKind::Path(QPath::TypeRelative(ty, pathseg)) = &maybe_path.kind; // check if the first part of the path is some integer primitive @@ -60,20 +60,19 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 { if pathseg.ident.name.as_str() == "from_str_radix"; // check if the second argument is a primitive `10` - if arguments.len() == 2; - if let ExprKind::Lit(lit) = &arguments[1].kind; + if let ExprKind::Lit(lit) = &radix.kind; if let rustc_ast::ast::LitKind::Int(10, _) = lit.node; then { - let expr = if let ExprKind::AddrOf(_, _, expr) = &arguments[0].kind { + let expr = if let ExprKind::AddrOf(_, _, expr) = &src.kind { let ty = cx.typeck_results().expr_ty(expr); if is_ty_stringish(cx, ty) { expr } else { - &arguments[0] + &src } } else { - &arguments[0] + &src }; let sugg = Sugg::hir_with_applicability( diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 0ba9b7ae7e58..01082cc8eeb6 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -15,11 +15,10 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE), LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK), LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF), - LintId::of(blacklisted_name::BLACKLISTED_NAME), LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON), - LintId::of(booleans::LOGIC_BUG), LintId::of(booleans::NONMINIMAL_BOOL), + LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR), LintId::of(borrow_deref_ref::BORROW_DEREF_REF), LintId::of(bytes_count_to_len::BYTES_COUNT_TO_LEN), LintId::of(casts::CAST_ABS_TO_UNSIGNED), @@ -46,6 +45,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD), LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ), LintId::of(disallowed_methods::DISALLOWED_METHODS), + LintId::of(disallowed_names::DISALLOWED_NAMES), LintId::of(disallowed_types::DISALLOWED_TYPES), LintId::of(doc::MISSING_SAFETY_DOC), LintId::of(doc::NEEDLESS_DOCTEST_MAIN), @@ -144,7 +144,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(matches::MATCH_STR_CASE_MISMATCH), LintId::of(matches::NEEDLESS_MATCH), LintId::of(matches::REDUNDANT_PATTERN_MATCHING), - LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE), LintId::of(matches::SINGLE_MATCH), LintId::of(matches::WILDCARD_IN_OR_PATTERNS), LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE), @@ -267,6 +266,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP), LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL), + LintId::of(partialeq_to_none::PARTIALEQ_TO_NONE), LintId::of(precedence::PRECEDENCE), LintId::of(ptr::CMP_NULL), LintId::of(ptr::INVALID_NULL_PTR_USAGE), diff --git a/clippy_lints/src/lib.register_correctness.rs b/clippy_lints/src/lib.register_correctness.rs index 9975859c54fe..006275d1383f 100644 --- a/clippy_lints/src/lib.register_correctness.rs +++ b/clippy_lints/src/lib.register_correctness.rs @@ -8,7 +8,7 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve LintId::of(attrs::DEPRECATED_SEMVER), LintId::of(attrs::MISMATCHED_TARGET_OS), LintId::of(attrs::USELESS_ATTRIBUTE), - LintId::of(booleans::LOGIC_BUG), + LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR), LintId::of(casts::CAST_REF_TO_MUT), LintId::of(casts::CAST_SLICE_DIFFERENT_SIZES), LintId::of(copies::IFS_SAME_COND), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 99bde35cf152..c540573b8022 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -55,11 +55,10 @@ store.register_lints(&[ await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE, await_holding_invalid::AWAIT_HOLDING_LOCK, await_holding_invalid::AWAIT_HOLDING_REFCELL_REF, - blacklisted_name::BLACKLISTED_NAME, blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS, bool_assert_comparison::BOOL_ASSERT_COMPARISON, - booleans::LOGIC_BUG, booleans::NONMINIMAL_BOOL, + booleans::OVERLY_COMPLEX_BOOL_EXPR, borrow_as_ptr::BORROW_AS_PTR, borrow_deref_ref::BORROW_DEREF_REF, bytecount::NAIVE_BYTECOUNT, @@ -116,6 +115,7 @@ store.register_lints(&[ derive::EXPL_IMPL_CLONE_ON_COPY, derive::UNSAFE_DERIVE_DESERIALIZE, disallowed_methods::DISALLOWED_METHODS, + disallowed_names::DISALLOWED_NAMES, disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS, disallowed_types::DISALLOWED_TYPES, doc::DOC_MARKDOWN, @@ -244,6 +244,7 @@ store.register_lints(&[ manual_assert::MANUAL_ASSERT, manual_async_fn::MANUAL_ASYNC_FN, manual_bits::MANUAL_BITS, + manual_instant_elapsed::MANUAL_INSTANT_ELAPSED, manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE, manual_ok_or::MANUAL_OK_OR, manual_rem_euclid::MANUAL_REM_EUCLID, @@ -453,6 +454,7 @@ store.register_lints(&[ panic_unimplemented::UNIMPLEMENTED, panic_unimplemented::UNREACHABLE, partialeq_ne_impl::PARTIALEQ_NE_IMPL, + partialeq_to_none::PARTIALEQ_TO_NONE, pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE, pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF, path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE, diff --git a/clippy_lints/src/lib.register_nursery.rs b/clippy_lints/src/lib.register_nursery.rs index 642d629971d9..91210b23afe3 100644 --- a/clippy_lints/src/lib.register_nursery.rs +++ b/clippy_lints/src/lib.register_nursery.rs @@ -13,6 +13,7 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(future_not_send::FUTURE_NOT_SEND), LintId::of(index_refutable_slice::INDEX_REFUTABLE_SLICE), LintId::of(let_if_seq::USELESS_LET_IF_SEQ), + LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE), LintId::of(methods::ITER_WITH_DRAIN), LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN), LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index a1b546658149..bd7d1a15ab4e 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -49,6 +49,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(loops::EXPLICIT_ITER_LOOP), LintId::of(macro_use::MACRO_USE_IMPORTS), LintId::of(manual_assert::MANUAL_ASSERT), + LintId::of(manual_instant_elapsed::MANUAL_INSTANT_ELAPSED), LintId::of(manual_ok_or::MANUAL_OK_OR), LintId::of(matches::MATCH_BOOL), LintId::of(matches::MATCH_ON_VEC_ITEMS), diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs index e95bab1d0454..bfa654238f13 100644 --- a/clippy_lints/src/lib.register_style.rs +++ b/clippy_lints/src/lib.register_style.rs @@ -4,7 +4,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS), - LintId::of(blacklisted_name::BLACKLISTED_NAME), LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON), LintId::of(casts::FN_TO_NUMERIC_CAST), @@ -17,6 +16,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(dereference::NEEDLESS_BORROW), LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ), LintId::of(disallowed_methods::DISALLOWED_METHODS), + LintId::of(disallowed_names::DISALLOWED_NAMES), LintId::of(disallowed_types::DISALLOWED_TYPES), LintId::of(doc::MISSING_SAFETY_DOC), LintId::of(doc::NEEDLESS_DOCTEST_MAIN), @@ -100,6 +100,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(operators::ASSIGN_OP_PATTERN), LintId::of(operators::OP_REF), LintId::of(operators::PTR_EQ), + LintId::of(partialeq_to_none::PARTIALEQ_TO_NONE), LintId::of(ptr::CMP_NULL), LintId::of(ptr::PTR_ARG), LintId::of(question_mark::QUESTION_MARK), diff --git a/clippy_lints/src/lib.register_suspicious.rs b/clippy_lints/src/lib.register_suspicious.rs index f7558f870981..964992bd94fe 100644 --- a/clippy_lints/src/lib.register_suspicious.rs +++ b/clippy_lints/src/lib.register_suspicious.rs @@ -22,7 +22,6 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec! LintId::of(loops::EMPTY_LOOP), LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES), LintId::of(loops::MUT_RANGE_BOUND), - LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE), LintId::of(methods::NO_EFFECT_REPLACE), LintId::of(methods::SUSPICIOUS_MAP), LintId::of(mut_key::MUTABLE_KEY_TYPE), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index eb3841272b17..2975399a8bbb 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -178,7 +178,6 @@ mod assertions_on_result_states; mod async_yields_async; mod attrs; mod await_holding_invalid; -mod blacklisted_name; mod blocks_in_if_conditions; mod bool_assert_comparison; mod booleans; @@ -206,6 +205,7 @@ mod dereference; mod derivable_impls; mod derive; mod disallowed_methods; +mod disallowed_names; mod disallowed_script_idents; mod disallowed_types; mod doc; @@ -274,6 +274,7 @@ mod main_recursion; mod manual_assert; mod manual_async_fn; mod manual_bits; +mod manual_instant_elapsed; mod manual_non_exhaustive; mod manual_ok_or; mod manual_rem_euclid; @@ -332,6 +333,7 @@ mod overflow_check_conditional; mod panic_in_result_fn; mod panic_unimplemented; mod partialeq_ne_impl; +mod partialeq_to_none; mod pass_by_ref_or_value; mod path_buf_push_overwrite; mod pattern_type_mismatch; @@ -487,7 +489,7 @@ pub fn read_conf(sess: &Session) -> Conf { }, }; - let TryConf { conf, errors } = utils::conf::read(&file_name); + let TryConf { conf, errors, warnings } = utils::conf::read(&file_name); // all conf errors are non-fatal, we just use the default conf in case of error for error in errors { sess.err(&format!( @@ -497,6 +499,15 @@ pub fn read_conf(sess: &Session) -> Conf { )); } + for warning in warnings { + sess.struct_warn(&format!( + "error reading Clippy's configuration file `{}`: {}", + file_name.display(), + format_error(warning) + )) + .emit(); + } + conf } @@ -675,8 +686,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(swap::Swap)); store.register_late_pass(|| Box::new(overflow_check_conditional::OverflowCheckConditional)); store.register_late_pass(|| Box::new(new_without_default::NewWithoutDefault::default())); - let blacklisted_names = conf.blacklisted_names.iter().cloned().collect::>(); - store.register_late_pass(move || Box::new(blacklisted_name::BlacklistedName::new(blacklisted_names.clone()))); + let disallowed_names = conf.disallowed_names.iter().cloned().collect::>(); + store.register_late_pass(move || Box::new(disallowed_names::DisallowedNames::new(disallowed_names.clone()))); let too_many_arguments_threshold = conf.too_many_arguments_threshold; let too_many_lines_threshold = conf.too_many_lines_threshold; store.register_late_pass(move || { @@ -921,6 +932,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || Box::new(operators::Operators::new(verbose_bit_mask_threshold))); store.register_late_pass(|| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked)); store.register_late_pass(|| Box::new(std_instead_of_core::StdReexports::default())); + store.register_late_pass(|| Box::new(manual_instant_elapsed::ManualInstantElapsed)); + store.register_late_pass(|| Box::new(partialeq_to_none::PartialeqToNone)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/loops/manual_memcpy.rs b/clippy_lints/src/loops/manual_memcpy.rs index b31015d195b5..a65df48e413e 100644 --- a/clippy_lints/src/loops/manual_memcpy.rs +++ b/clippy_lints/src/loops/manual_memcpy.rs @@ -119,11 +119,9 @@ fn build_manual_memcpy_suggestion<'tcx>( let print_limit = |end: &Expr<'_>, end_str: &str, base: &Expr<'_>, sugg: MinifyingSugg<'static>| { if_chain! { - if let ExprKind::MethodCall(method, len_args, _) = end.kind; + if let ExprKind::MethodCall(method, [recv], _) = end.kind; if method.ident.name == sym::len; - if len_args.len() == 1; - if let Some(arg) = len_args.get(0); - if path_to_local(arg) == path_to_local(base); + if path_to_local(recv) == path_to_local(base); then { if sugg.to_string() == end_str { sugg::EMPTY.into() @@ -343,10 +341,8 @@ fn get_slice_like_element_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Opti fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> { if_chain! { - if let ExprKind::MethodCall(method, args, _) = expr.kind; + if let ExprKind::MethodCall(method, [arg], _) = expr.kind; if method.ident.name == sym::clone; - if args.len() == 1; - if let Some(arg) = args.get(0); then { arg } else { expr } } } diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index a7ef562b21fc..7ca4a7c4ebfc 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -188,10 +188,9 @@ pub(super) fn check<'tcx>( fn is_len_call(expr: &Expr<'_>, var: Symbol) -> bool { if_chain! { - if let ExprKind::MethodCall(method, len_args, _) = expr.kind; - if len_args.len() == 1; + if let ExprKind::MethodCall(method, [recv], _) = expr.kind; if method.ident.name == sym::len; - if let ExprKind::Path(QPath::Resolved(_, path)) = len_args[0].kind; + if let ExprKind::Path(QPath::Resolved(_, path)) = recv.kind; if path.segments.len() == 1; if path.segments[0].ident.name == var; then { diff --git a/clippy_lints/src/manual_instant_elapsed.rs b/clippy_lints/src/manual_instant_elapsed.rs new file mode 100644 index 000000000000..331cda1db899 --- /dev/null +++ b/clippy_lints/src/manual_instant_elapsed.rs @@ -0,0 +1,69 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::source_map::Spanned; + +declare_clippy_lint! { + /// ### What it does + /// Lints subtraction between `Instant::now()` and another `Instant`. + /// + /// ### Why is this bad? + /// It is easy to accidentally write `prev_instant - Instant::now()`, which will always be 0ns + /// as `Instant` subtraction saturates. + /// + /// `prev_instant.elapsed()` also more clearly signals intention. + /// + /// ### Example + /// ```rust + /// use std::time::Instant; + /// let prev_instant = Instant::now(); + /// let duration = Instant::now() - prev_instant; + /// ``` + /// Use instead: + /// ```rust + /// use std::time::Instant; + /// let prev_instant = Instant::now(); + /// let duration = prev_instant.elapsed(); + /// ``` + #[clippy::version = "1.64.0"] + pub MANUAL_INSTANT_ELAPSED, + pedantic, + "subtraction between `Instant::now()` and previous `Instant`" +} + +declare_lint_pass!(ManualInstantElapsed => [MANUAL_INSTANT_ELAPSED]); + +impl LateLintPass<'_> for ManualInstantElapsed { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { + if let ExprKind::Binary(Spanned {node: BinOpKind::Sub, ..}, lhs, rhs) = expr.kind + && check_instant_now_call(cx, lhs) + && let ty_resolved = cx.typeck_results().expr_ty(rhs) + && let rustc_middle::ty::Adt(def, _) = ty_resolved.kind() + && clippy_utils::match_def_path(cx, def.did(), &clippy_utils::paths::INSTANT) + && let Some(sugg) = clippy_utils::sugg::Sugg::hir_opt(cx, rhs) + { + span_lint_and_sugg( + cx, + MANUAL_INSTANT_ELAPSED, + expr.span, + "manual implementation of `Instant::elapsed`", + "try", + format!("{}.elapsed()", sugg.maybe_par()), + Applicability::MachineApplicable, + ); + } + } +} + +fn check_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool { + if let ExprKind::Call(fn_expr, []) = expr_block.kind + && let Some(fn_id) = clippy_utils::path_def_id(cx, fn_expr) + && clippy_utils::match_def_path(cx, fn_id, &clippy_utils::paths::INSTANT_NOW) + { + true + } else { + false + } +} diff --git a/clippy_lints/src/manual_ok_or.rs b/clippy_lints/src/manual_ok_or.rs index 9abf2507b921..cf5004399b88 100644 --- a/clippy_lints/src/manual_ok_or.rs +++ b/clippy_lints/src/manual_ok_or.rs @@ -47,17 +47,14 @@ impl<'tcx> LateLintPass<'tcx> for ManualOkOr { } if_chain! { - if let ExprKind::MethodCall(method_segment, args, _) = scrutinee.kind; + if let ExprKind::MethodCall(method_segment, [receiver, or_expr, map_expr], _) = scrutinee.kind; if method_segment.ident.name == sym!(map_or); - if args.len() == 3; - let method_receiver = &args[0]; - let ty = cx.typeck_results().expr_ty(method_receiver); + let ty = cx.typeck_results().expr_ty(receiver); if is_type_diagnostic_item(cx, ty, sym::Option); - let or_expr = &args[1]; - if is_ok_wrapping(cx, &args[2]); + if is_ok_wrapping(cx, map_expr); if let ExprKind::Call(Expr { kind: ExprKind::Path(err_path), .. }, &[ref err_arg]) = or_expr.kind; if is_lang_ctor(cx, err_path, ResultErr); - if let Some(method_receiver_snippet) = snippet_opt(cx, method_receiver.span); + if let Some(method_receiver_snippet) = snippet_opt(cx, receiver.span); if let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span); if let Some(indent) = indent_of(cx, scrutinee.span); then { diff --git a/clippy_lints/src/map_err_ignore.rs b/clippy_lints/src/map_err_ignore.rs index 21d0e19eb0a4..1e542447c96e 100644 --- a/clippy_lints/src/map_err_ignore.rs +++ b/clippy_lints/src/map_err_ignore.rs @@ -113,10 +113,10 @@ impl<'tcx> LateLintPass<'tcx> for MapErrIgnore { } // check if this is a method call (e.g. x.foo()) - if let ExprKind::MethodCall(method, args, _) = e.kind { + if let ExprKind::MethodCall(method, [_, arg], _) = e.kind { // only work if the method name is `map_err` and there are only 2 arguments (e.g. x.map_err(|_|[1] // Enum::Variant[2])) - if method.ident.as_str() == "map_err" && args.len() == 2 { + if method.ident.name == sym!(map_err) { // make sure the first argument is a closure, and grab the CaptureRef, BodyId, and fn_decl_span // fields if let ExprKind::Closure(&Closure { @@ -124,7 +124,7 @@ impl<'tcx> LateLintPass<'tcx> for MapErrIgnore { body, fn_decl_span, .. - }) = args[1].kind + }) = arg.kind { // check if this is by Reference (meaning there's no move statement) if capture_clause == CaptureBy::Ref { diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index af9d948af00e..6db852c3ffe7 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -97,11 +97,7 @@ declare_clippy_lint! { declare_lint_pass!(MapUnit => [OPTION_MAP_UNIT_FN, RESULT_MAP_UNIT_FN]); fn is_unit_type(ty: Ty<'_>) -> bool { - match ty.kind() { - ty::Tuple(slice) => slice.is_empty(), - ty::Never => true, - _ => false, - } + ty.is_unit() || ty.is_never() } fn is_unit_function(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { diff --git a/clippy_lints/src/matches/match_as_ref.rs b/clippy_lints/src/matches/match_as_ref.rs index d914eba01716..a0efdecec67f 100644 --- a/clippy_lints/src/matches/match_as_ref.rs +++ b/clippy_lints/src/matches/match_as_ref.rs @@ -72,10 +72,10 @@ fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option LateLintPass<'tcx> for Matches { let from_expansion = expr.span.from_expansion(); if let ExprKind::Match(ex, arms, source) = expr.kind { - if source == MatchSource::Normal && !span_starts_with(cx, expr.span, "match") { + if source == MatchSource::Normal && !is_span_match(cx, expr.span) { return; } if matches!(source, MatchSource::Normal | MatchSource::ForLoopDesugar) { diff --git a/clippy_lints/src/matches/try_err.rs b/clippy_lints/src/matches/try_err.rs index 0491a0679f37..663277d11365 100644 --- a/clippy_lints/src/matches/try_err.rs +++ b/clippy_lints/src/matches/try_err.rs @@ -23,12 +23,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine // val, // }; if_chain! { - if let ExprKind::Call(match_fun, try_args) = scrutinee.kind; + if let ExprKind::Call(match_fun, [try_arg, ..]) = scrutinee.kind; if let ExprKind::Path(ref match_fun_path) = match_fun.kind; if matches!(match_fun_path, QPath::LangItem(LangItem::TryTraitBranch, ..)); - if let Some(try_arg) = try_args.get(0); - if let ExprKind::Call(err_fun, err_args) = try_arg.kind; - if let Some(err_arg) = err_args.get(0); + if let ExprKind::Call(err_fun, [err_arg, ..]) = try_arg.kind; if let ExprKind::Path(ref err_fun_path) = err_fun.kind; if is_lang_ctor(cx, err_fun_path, ResultErr); if let Some(return_ty) = find_return_type(cx, &expr.kind); diff --git a/clippy_lints/src/mem_replace.rs b/clippy_lints/src/mem_replace.rs index 41073d40f3d7..cad3ea2a176c 100644 --- a/clippy_lints/src/mem_replace.rs +++ b/clippy_lints/src/mem_replace.rs @@ -163,8 +163,7 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<' } if_chain! { - if let ExprKind::Call(repl_func, repl_args) = src.kind; - if repl_args.is_empty(); + if let ExprKind::Call(repl_func, []) = src.kind; if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind; if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id(); then { @@ -246,11 +245,10 @@ impl<'tcx> LateLintPass<'tcx> for MemReplace { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { // Check that `expr` is a call to `mem::replace()` - if let ExprKind::Call(func, func_args) = expr.kind; + if let ExprKind::Call(func, [dest, src]) = expr.kind; if let ExprKind::Path(ref func_qpath) = func.kind; if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); if cx.tcx.is_diagnostic_item(sym::mem_replace, def_id); - if let [dest, src] = func_args; then { check_replace_option_with_none(cx, src, dest, expr.span); check_replace_with_uninit(cx, src, dest, expr.span); diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index 0b38a07204e8..60e1355f9b92 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet_with_context; use clippy_utils::sugg; use clippy_utils::ty::is_copy; use rustc_errors::Applicability; -use rustc_hir::{BindingAnnotation, Expr, ExprKind, MatchSource, Node, PatKind}; +use rustc_hir::{BindingAnnotation, Expr, ExprKind, MatchSource, Node, PatKind, QPath}; use rustc_lint::LateContext; use rustc_middle::ty::{self, adjustment::Adjust}; use rustc_span::symbol::{sym, Symbol}; @@ -86,6 +86,11 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, { return; }, + // ? is a Call, makes sure not to rec *x?, but rather (*x)? + ExprKind::Call(hir_callee, _) => matches!( + hir_callee.kind, + ExprKind::Path(QPath::LangItem(rustc_hir::LangItem::TryTraitBranch, _, _)) + ), ExprKind::MethodCall(_, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true, ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar) | ExprKind::Field(..) diff --git a/clippy_lints/src/methods/expect_used.rs b/clippy_lints/src/methods/expect_used.rs index fbc3348f1855..5ef08ca6290b 100644 --- a/clippy_lints/src/methods/expect_used.rs +++ b/clippy_lints/src/methods/expect_used.rs @@ -12,9 +12,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) { - Some((EXPECT_USED, "an Option", "None")) + Some((EXPECT_USED, "an Option", "None", "")) } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) { - Some((EXPECT_USED, "a Result", "Err")) + Some((EXPECT_USED, "a Result", "Err", "an ")) } else { None }; @@ -23,14 +23,14 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr return; } - if let Some((lint, kind, none_value)) = mess { + if let Some((lint, kind, none_value, none_prefix)) = mess { span_lint_and_help( cx, lint, expr.span, - &format!("used `expect()` on `{}` value", kind,), + &format!("used `expect()` on `{kind}` value"), None, - &format!("if this value is an `{}`, it will panic", none_value,), + &format!("if this value is {none_prefix}`{none_value}`, it will panic"), ); } } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 202fbc1f7f66..5ac6b09f0aa2 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -204,6 +204,17 @@ declare_clippy_lint! { /// option.expect("more helpful message"); /// result.expect("more helpful message"); /// ``` + /// + /// If [expect_used](#expect_used) is enabled, instead: + /// ```rust,ignore + /// # let option = Some(1); + /// # let result: Result = Ok(1); + /// option?; + /// + /// // or + /// + /// result?; + /// ``` #[clippy::version = "1.45.0"] pub UNWRAP_USED, restriction, diff --git a/clippy_lints/src/methods/unwrap_used.rs b/clippy_lints/src/methods/unwrap_used.rs index 5c761014927c..ce1a52e5480a 100644 --- a/clippy_lints/src/methods/unwrap_used.rs +++ b/clippy_lints/src/methods/unwrap_used.rs @@ -1,20 +1,20 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::is_in_test_function; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_in_test_function, is_lint_allowed}; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::sym; -use super::UNWRAP_USED; +use super::{EXPECT_USED, UNWRAP_USED}; /// lint use of `unwrap()` for `Option`s and `Result`s pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, allow_unwrap_in_tests: bool) { let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) { - Some((UNWRAP_USED, "an Option", "None")) + Some((UNWRAP_USED, "an Option", "None", "")) } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) { - Some((UNWRAP_USED, "a Result", "Err")) + Some((UNWRAP_USED, "a Result", "Err", "an ")) } else { None }; @@ -23,18 +23,23 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr return; } - if let Some((lint, kind, none_value)) = mess { + if let Some((lint, kind, none_value, none_prefix)) = mess { + let help = if is_lint_allowed(cx, EXPECT_USED, expr.hir_id) { + format!( + "if you don't want to handle the `{none_value}` case gracefully, consider \ + using `expect()` to provide a better panic message" + ) + } else { + format!("if this value is {none_prefix}`{none_value}`, it will panic") + }; + span_lint_and_help( cx, lint, expr.span, - &format!("used `unwrap()` on `{}` value", kind,), + &format!("used `unwrap()` on `{kind}` value"), None, - &format!( - "if you don't want to handle the `{}` case gracefully, consider \ - using `expect()` to provide a better panic message", - none_value, - ), + &help, ); } } diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs index 16d65966c100..bc304c081b90 100644 --- a/clippy_lints/src/missing_const_for_fn.rs +++ b/clippy_lints/src/missing_const_for_fn.rs @@ -1,7 +1,9 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::qualify_min_const_fn::is_min_const_fn; use clippy_utils::ty::has_drop; -use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, meets_msrv, msrvs, trait_ref_of_method}; +use clippy_utils::{ + fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, meets_msrv, msrvs, trait_ref_of_method, +}; use rustc_hir as hir; use rustc_hir::def_id::CRATE_DEF_ID; use rustc_hir::intravisit::FnKind; @@ -86,10 +88,10 @@ impl MissingConstForFn { impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { fn check_fn( &mut self, - cx: &LateContext<'_>, - kind: FnKind<'_>, + cx: &LateContext<'tcx>, + kind: FnKind<'tcx>, _: &FnDecl<'_>, - _: &Body<'_>, + body: &Body<'tcx>, span: Span, hir_id: HirId, ) { @@ -124,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { FnKind::Method(_, sig, ..) => { if trait_ref_of_method(cx, def_id).is_some() || already_const(sig.header) - || method_accepts_dropable(cx, sig.decl.inputs) + || method_accepts_droppable(cx, sig.decl.inputs) { return; } @@ -144,6 +146,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { } } + if is_from_proc_macro(cx, &(&kind, body, hir_id, span)) { + return; + } + let mir = cx.tcx.optimized_mir(def_id); if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, self.msrv) { @@ -159,7 +165,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { /// Returns true if any of the method parameters is a type that implements `Drop`. The method /// can't be made const then, because `drop` can't be const-evaluated. -fn method_accepts_dropable(cx: &LateContext<'_>, param_tys: &[hir::Ty<'_>]) -> bool { +fn method_accepts_droppable(cx: &LateContext<'_>, param_tys: &[hir::Ty<'_>]) -> bool { // If any of the params are droppable, return true param_tys.iter().any(|hir_ty| { let ty_ty = hir_ty_to_ty(cx.tcx, hir_ty); diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 88ba002927a9..3701fdb4adbf 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -7,7 +7,8 @@ use clippy_utils::attrs::is_doc_hidden; use clippy_utils::diagnostics::span_lint; -use rustc_ast::ast; +use clippy_utils::is_from_proc_macro; +use rustc_ast::ast::{self, MetaItem, MetaItemKind}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::DefIdTree; @@ -57,6 +58,20 @@ impl MissingDoc { *self.doc_hidden_stack.last().expect("empty doc_hidden_stack") } + fn has_include(meta: Option) -> bool { + if_chain! { + if let Some(meta) = meta; + if let MetaItemKind::List(list) = meta.kind; + if let Some(meta) = list.get(0); + if let Some(name) = meta.ident(); + then { + name.name == sym::include + } else { + false + } + } + } + fn check_missing_docs_attrs( &self, cx: &LateContext<'_>, @@ -80,7 +95,9 @@ impl MissingDoc { return; } - let has_doc = attrs.iter().any(|a| a.doc_str().is_some()); + let has_doc = attrs + .iter() + .any(|a| a.doc_str().is_some() || Self::has_include(a.meta())); if !has_doc { span_lint( cx, @@ -141,14 +158,18 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id()); let attrs = cx.tcx.hir().attrs(it.hir_id()); - self.check_missing_docs_attrs(cx, attrs, it.span, article, desc); + if !is_from_proc_macro(cx, it) { + self.check_missing_docs_attrs(cx, attrs, it.span, article, desc); + } } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx hir::TraitItem<'_>) { let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id()); let attrs = cx.tcx.hir().attrs(trait_item.hir_id()); - self.check_missing_docs_attrs(cx, attrs, trait_item.span, article, desc); + if !is_from_proc_macro(cx, trait_item) { + self.check_missing_docs_attrs(cx, attrs, trait_item.span, article, desc); + } } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) { @@ -163,18 +184,24 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id()); let attrs = cx.tcx.hir().attrs(impl_item.hir_id()); - self.check_missing_docs_attrs(cx, attrs, impl_item.span, article, desc); + if !is_from_proc_macro(cx, impl_item) { + self.check_missing_docs_attrs(cx, attrs, impl_item.span, article, desc); + } } fn check_field_def(&mut self, cx: &LateContext<'tcx>, sf: &'tcx hir::FieldDef<'_>) { if !sf.is_positional() { let attrs = cx.tcx.hir().attrs(sf.hir_id); - self.check_missing_docs_attrs(cx, attrs, sf.span, "a", "struct field"); + if !is_from_proc_macro(cx, sf) { + self.check_missing_docs_attrs(cx, attrs, sf.span, "a", "struct field"); + } } } fn check_variant(&mut self, cx: &LateContext<'tcx>, v: &'tcx hir::Variant<'_>) { let attrs = cx.tcx.hir().attrs(v.id); - self.check_missing_docs_attrs(cx, attrs, v.span, "a", "variant"); + if !is_from_proc_macro(cx, v) { + self.check_missing_docs_attrs(cx, attrs, v.span, "a", "variant"); + } } } diff --git a/clippy_lints/src/partialeq_to_none.rs b/clippy_lints/src/partialeq_to_none.rs new file mode 100644 index 000000000000..eee7642068d6 --- /dev/null +++ b/clippy_lints/src/partialeq_to_none.rs @@ -0,0 +1,104 @@ +use clippy_utils::{ + diagnostics::span_lint_and_sugg, is_lang_ctor, peel_hir_expr_refs, peel_ref_operators, sugg, + ty::is_type_diagnostic_item, +}; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; + +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for binary comparisons to a literal `Option::None`. + /// + /// ### Why is this bad? + /// + /// A programmer checking if some `foo` is `None` via a comparison `foo == None` + /// is usually inspired from other programming languages (e.g. `foo is None` + /// in Python). + /// Checking if a value of type `Option` is (not) equal to `None` in that + /// way relies on `T: PartialEq` to do the comparison, which is unneeded. + /// + /// ### Example + /// ```rust + /// fn foo(f: Option) -> &'static str { + /// if f != None { "yay" } else { "nay" } + /// } + /// ``` + /// Use instead: + /// ```rust + /// fn foo(f: Option) -> &'static str { + /// if f.is_some() { "yay" } else { "nay" } + /// } + /// ``` + #[clippy::version = "1.64.0"] + pub PARTIALEQ_TO_NONE, + style, + "Binary comparison to `Option::None` relies on `T: PartialEq`, which is unneeded" +} +declare_lint_pass!(PartialeqToNone => [PARTIALEQ_TO_NONE]); + +impl<'tcx> LateLintPass<'tcx> for PartialeqToNone { + fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { + // Skip expanded code, as we have no control over it anyway... + if e.span.from_expansion() { + return; + } + + // If the expression is of type `Option` + let is_ty_option = + |expr: &Expr<'_>| is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr).peel_refs(), sym::Option); + + // If the expression is a literal `Option::None` + let is_none_ctor = |expr: &Expr<'_>| { + matches!(&peel_hir_expr_refs(expr).0.kind, + ExprKind::Path(p) if is_lang_ctor(cx, p, LangItem::OptionNone)) + }; + + let mut applicability = Applicability::MachineApplicable; + + if let ExprKind::Binary(op, left_side, right_side) = e.kind { + // All other comparisons (e.g. `>= None`) have special meaning wrt T + let is_eq = match op.node { + BinOpKind::Eq => true, + BinOpKind::Ne => false, + _ => return, + }; + + // We are only interested in comparisons between `Option` and a literal `Option::None` + let scrutinee = match ( + is_none_ctor(left_side) && is_ty_option(right_side), + is_none_ctor(right_side) && is_ty_option(left_side), + ) { + (true, false) => right_side, + (false, true) => left_side, + _ => return, + }; + + // Peel away refs/derefs (as long as we don't cross manual deref impls), as + // autoref/autoderef will take care of those + let sugg = format!( + "{}.{}", + sugg::Sugg::hir_with_applicability(cx, peel_ref_operators(cx, scrutinee), "..", &mut applicability) + .maybe_par(), + if is_eq { "is_none()" } else { "is_some()" } + ); + + span_lint_and_sugg( + cx, + PARTIALEQ_TO_NONE, + e.span, + "binary comparison to literal `Option::None`", + if is_eq { + "use `Option::is_none()` instead" + } else { + "use `Option::is_some()` instead" + }, + sugg, + applicability, + ); + } + } +} diff --git a/clippy_lints/src/path_buf_push_overwrite.rs b/clippy_lints/src/path_buf_push_overwrite.rs index 3f940ce61c03..bc6a918f7035 100644 --- a/clippy_lints/src/path_buf_push_overwrite.rs +++ b/clippy_lints/src/path_buf_push_overwrite.rs @@ -46,11 +46,9 @@ declare_lint_pass!(PathBufPushOverwrite => [PATH_BUF_PUSH_OVERWRITE]); impl<'tcx> LateLintPass<'tcx> for PathBufPushOverwrite { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { - if let ExprKind::MethodCall(path, args, _) = expr.kind; + if let ExprKind::MethodCall(path, [recv, get_index_arg], _) = expr.kind; if path.ident.name == sym!(push); - if args.len() == 2; - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]).peel_refs(), sym::PathBuf); - if let Some(get_index_arg) = args.get(1); + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv).peel_refs(), sym::PathBuf); if let ExprKind::Lit(ref lit) = get_index_arg.kind; if let LitKind::Str(ref path_lit, _) = lit.node; if let pushed_path = Path::new(path_lit.as_str()); diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index fd0a53839e6e..964a057f00d3 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -86,8 +86,7 @@ fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Ex if_chain! { if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr); if !is_else_clause(cx.tcx, expr); - if let ExprKind::MethodCall(segment, args, _) = &cond.kind; - if let Some(caller) = args.get(0); + if let ExprKind::MethodCall(segment, [caller, ..], _) = &cond.kind; let caller_ty = cx.typeck_results().expr_ty(caller); let if_block = IfBlockType::IfIs(caller, caller_ty, segment.ident.name, then, r#else); if is_early_return(sym::Option, cx, &if_block) || is_early_return(sym::Result, cx, &if_block); diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 547d4da81872..fbf842c339e4 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -385,24 +385,24 @@ fn check_range_zip_with_len(cx: &LateContext<'_>, path: &PathSegment<'_>, args: if path.ident.as_str() == "zip"; if let [iter, zip_arg] = args; // `.iter()` call - if let ExprKind::MethodCall(iter_path, iter_args, _) = iter.kind; + if let ExprKind::MethodCall(iter_path, [iter_caller, ..], _) = iter.kind; if iter_path.ident.name == sym::iter; // range expression in `.zip()` call: `0..x.len()` if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg); if is_integer_const(cx, start, 0); // `.len()` call - if let ExprKind::MethodCall(len_path, len_args, _) = end.kind; - if len_path.ident.name == sym::len && len_args.len() == 1; + if let ExprKind::MethodCall(len_path, [len_caller], _) = end.kind; + if len_path.ident.name == sym::len; // `.iter()` and `.len()` called on same `Path` - if let ExprKind::Path(QPath::Resolved(_, iter_path)) = iter_args[0].kind; - if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_args[0].kind; - if SpanlessEq::new(cx).eq_path_segments(&iter_path.segments, &len_path.segments); + if let ExprKind::Path(QPath::Resolved(_, iter_path)) = iter_caller.kind; + if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_caller.kind; + if SpanlessEq::new(cx).eq_path_segments(iter_path.segments, len_path.segments); then { span_lint(cx, RANGE_ZIP_WITH_LEN, span, &format!("it is more idiomatic to use `{}.iter().enumerate()`", - snippet(cx, iter_args[0].span, "_")) + snippet(cx, iter_caller.span, "_")) ); } } diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs index f5a93cebab8c..74eea6de4bbe 100644 --- a/clippy_lints/src/redundant_closure_call.rs +++ b/clippy_lints/src/redundant_closure_call.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::sugg::Sugg; use if_chain::if_chain; use rustc_ast::ast; use rustc_ast::visit as ast_visit; @@ -69,7 +69,7 @@ impl EarlyLintPass for RedundantClosureCall { if_chain! { if let ast::ExprKind::Call(ref paren, _) = expr.kind; if let ast::ExprKind::Paren(ref closure) = paren.kind; - if let ast::ExprKind::Closure(_, _, _, _, ref decl, ref block, _) = closure.kind; + if let ast::ExprKind::Closure(_, _, ref r#async, _, ref decl, ref block, _) = closure.kind; then { let mut visitor = ReturnVisitor::new(); visitor.visit_expr(block); @@ -81,10 +81,19 @@ impl EarlyLintPass for RedundantClosureCall { "try not to call a closure in the expression where it is declared", |diag| { if decl.inputs.is_empty() { - let mut app = Applicability::MachineApplicable; - let hint = - snippet_with_applicability(cx, block.span, "..", &mut app).into_owned(); - diag.span_suggestion(expr.span, "try doing something like", hint, app); + let app = Applicability::MachineApplicable; + let mut hint = Sugg::ast(cx, block, ".."); + + if r#async.is_async() { + // `async x` is a syntax error, so it becomes `async { x }` + if !matches!(block.kind, ast::ExprKind::Block(_, _)) { + hint = hint.blockify(); + } + + hint = hint.asyncify(); + } + + diag.span_suggestion(expr.span, "try doing something like", hint.to_string(), app); } }, ); diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index f9a9b0691935..6bcae0da8f48 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -57,21 +57,20 @@ declare_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX]); impl<'tcx> LateLintPass<'tcx> for Regex { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { - if let ExprKind::Call(fun, args) = expr.kind; + if let ExprKind::Call(fun, [arg]) = expr.kind; if let ExprKind::Path(ref qpath) = fun.kind; - if args.len() == 1; if let Some(def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id(); then { if match_def_path(cx, def_id, &paths::REGEX_NEW) || match_def_path(cx, def_id, &paths::REGEX_BUILDER_NEW) { - check_regex(cx, &args[0], true); + check_regex(cx, arg, true); } else if match_def_path(cx, def_id, &paths::REGEX_BYTES_NEW) || match_def_path(cx, def_id, &paths::REGEX_BYTES_BUILDER_NEW) { - check_regex(cx, &args[0], false); + check_regex(cx, arg, false); } else if match_def_path(cx, def_id, &paths::REGEX_SET_NEW) { - check_set(cx, &args[0], true); + check_set(cx, arg, true); } else if match_def_path(cx, def_id, &paths::REGEX_BYTES_SET_NEW) { - check_set(cx, &args[0], false); + check_set(cx, arg, false); } } } diff --git a/clippy_lints/src/renamed_lints.rs b/clippy_lints/src/renamed_lints.rs index ba03ef937211..6bea6dc0773d 100644 --- a/clippy_lints/src/renamed_lints.rs +++ b/clippy_lints/src/renamed_lints.rs @@ -2,6 +2,7 @@ #[rustfmt::skip] pub static RENAMED_LINTS: &[(&str, &str)] = &[ + ("clippy::blacklisted_name", "clippy::disallowed_names"), ("clippy::block_in_if_condition_expr", "clippy::blocks_in_if_conditions"), ("clippy::block_in_if_condition_stmt", "clippy::blocks_in_if_conditions"), ("clippy::box_vec", "clippy::box_collection"), @@ -14,6 +15,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[ ("clippy::for_loop_over_result", "clippy::for_loops_over_fallibles"), ("clippy::identity_conversion", "clippy::useless_conversion"), ("clippy::if_let_some_result", "clippy::match_result_ok"), + ("clippy::logic_bug", "clippy::overly_complex_bool_expr"), ("clippy::new_without_default_derive", "clippy::new_without_default"), ("clippy::option_and_then_some", "clippy::bind_instead_of_map"), ("clippy::option_expect_used", "clippy::expect_used"), diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index 2c8aa17e80db..b59a25e3a400 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -233,15 +233,10 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { /// Returns `true` if give expression is `repeat(0).take(...)` fn is_repeat_take(&self, expr: &Expr<'_>) -> bool { if_chain! { - if let ExprKind::MethodCall(take_path, take_args, _) = expr.kind; + if let ExprKind::MethodCall(take_path, [recv, len_arg, ..], _) = expr.kind; if take_path.ident.name == sym!(take); - // Check that take is applied to `repeat(0)` - if let Some(repeat_expr) = take_args.get(0); - if self.is_repeat_zero(repeat_expr); - - if let Some(len_arg) = take_args.get(1); - + if self.is_repeat_zero(recv); then { // Check that len expression is equals to `with_capacity` expression if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) { diff --git a/clippy_lints/src/stable_sort_primitive.rs b/clippy_lints/src/stable_sort_primitive.rs index a6c685df721d..6d54935f81ab 100644 --- a/clippy_lints/src/stable_sort_primitive.rs +++ b/clippy_lints/src/stable_sort_primitive.rs @@ -97,12 +97,11 @@ struct LintDetection { fn detect_stable_sort_primitive(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { if_chain! { - if let ExprKind::MethodCall(method_name, args, _) = &expr.kind; - if let Some(slice) = &args.get(0); + if let ExprKind::MethodCall(method_name, [slice, args @ ..], _) = &expr.kind; if let Some(method) = SortingKind::from_stable_name(method_name.ident.name.as_str()); if let Some(slice_type) = is_slice_of_primitives(cx, slice); then { - let args_str = args.iter().skip(1).map(|arg| Sugg::hir(cx, arg, "..").to_string()).collect::>().join(", "); + let args_str = args.iter().map(|arg| Sugg::hir(cx, arg, "..").to_string()).collect::>().join(", "); Some(LintDetection { slice_name: Sugg::hir(cx, slice, "..").to_string(), method, method_args: args_str, slice_type }) } else { None diff --git a/clippy_lints/src/unit_types/mod.rs b/clippy_lints/src/unit_types/mod.rs index 6aa86a57c9bd..546242ebd9a4 100644 --- a/clippy_lints/src/unit_types/mod.rs +++ b/clippy_lints/src/unit_types/mod.rs @@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitTypes { let_unit_value::check(cx, local); } - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { unit_cmp::check(cx, expr); unit_arg::check(cx, expr); } diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index 97d92f10e1cb..16da2f11b81a 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_from_proc_macro; use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; use if_chain::if_chain; use rustc_errors::Applicability; @@ -7,7 +8,7 @@ use rustc_lint::LateContext; use super::{utils, UNIT_ARG}; -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if expr.span.from_expansion() { return; } @@ -44,7 +45,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { } }) .collect::>(); - if !args_to_recover.is_empty() { + if !args_to_recover.is_empty() && !is_from_proc_macro(cx, expr) { lint_unit_args(cx, expr, &args_to_recover); } }, diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index fe29bf29d0ca..b6738e2891d3 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -59,17 +59,17 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { ExprKind::Ret(Some(e)) | ExprKind::Break(_, Some(e)) => e, _ => return, }; - if let ExprKind::Call(_, args) = e.kind { - self.try_desugar_arm.push(args[0].hir_id); + if let ExprKind::Call(_, [arg, ..]) = e.kind { + self.try_desugar_arm.push(arg.hir_id); } }, - ExprKind::MethodCall(name, .., args, _) => { + ExprKind::MethodCall(name, .., [recv, ..], _) => { if is_trait_method(cx, e, sym::Into) && name.ident.as_str() == "into" { let a = cx.typeck_results().expr_ty(e); - let b = cx.typeck_results().expr_ty(&args[0]); + let b = cx.typeck_results().expr_ty(recv); if same_type_and_consts(a, b) { - let sugg = snippet_with_macro_callsite(cx, args[0].span, "").to_string(); + let sugg = snippet_with_macro_callsite(cx, recv.span, "").to_string(); span_lint_and_sugg( cx, USELESS_CONVERSION, @@ -90,9 +90,9 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { } } let a = cx.typeck_results().expr_ty(e); - let b = cx.typeck_results().expr_ty(&args[0]); + let b = cx.typeck_results().expr_ty(recv); if same_type_and_consts(a, b) { - let sugg = snippet(cx, args[0].span, "").into_owned(); + let sugg = snippet(cx, recv.span, "").into_owned(); span_lint_and_sugg( cx, USELESS_CONVERSION, @@ -107,7 +107,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if_chain! { if is_trait_method(cx, e, sym::TryInto) && name.ident.name == sym::try_into; let a = cx.typeck_results().expr_ty(e); - let b = cx.typeck_results().expr_ty(&args[0]); + let b = cx.typeck_results().expr_ty(recv); if is_type_diagnostic_item(cx, a, sym::Result); if let ty::Adt(_, substs) = a.kind(); if let Some(a_type) = substs.types().next(); @@ -126,14 +126,13 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { } }, - ExprKind::Call(path, args) => { + ExprKind::Call(path, [arg]) => { if_chain! { - if args.len() == 1; if let ExprKind::Path(ref qpath) = path.kind; if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id(); then { let a = cx.typeck_results().expr_ty(e); - let b = cx.typeck_results().expr_ty(&args[0]); + let b = cx.typeck_results().expr_ty(arg); if_chain! { if match_def_path(cx, def_id, &paths::TRY_FROM); if is_type_diagnostic_item(cx, a, sym::Result); @@ -159,7 +158,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if same_type_and_consts(a, b); then { - let sugg = Sugg::hir_with_macro_callsite(cx, &args[0], "").maybe_par(); + let sugg = Sugg::hir_with_macro_callsite(cx, arg, "").maybe_par(); let sugg_msg = format!("consider removing `{}()`", snippet(cx, path.span, "From::from")); span_lint_and_sugg( diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 6e033b3be2d8..3faae9ac0d2b 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -30,7 +30,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[ "MinGW", "CamelCase", ]; -const DEFAULT_BLACKLISTED_NAMES: &[&str] = &["foo", "baz", "quux"]; +const DEFAULT_DISALLOWED_NAMES: &[&str] = &["foo", "baz", "quux"]; /// Holds information used by `MISSING_ENFORCED_IMPORT_RENAMES` lint. #[derive(Clone, Debug, Deserialize)] @@ -68,6 +68,7 @@ pub enum DisallowedType { pub struct TryConf { pub conf: Conf, pub errors: Vec>, + pub warnings: Vec>, } impl TryConf { @@ -75,6 +76,7 @@ impl TryConf { Self { conf: Conf::default(), errors: vec![Box::new(error)], + warnings: vec![], } } } @@ -90,14 +92,14 @@ impl fmt::Display for ConfError { impl Error for ConfError {} -fn conf_error(s: String) -> Box { - Box::new(ConfError(s)) +fn conf_error(s: impl Into) -> Box { + Box::new(ConfError(s.into())) } macro_rules! define_Conf { ($( $(#[doc = $doc:literal])+ - $(#[conf_deprecated($dep:literal)])? + $(#[conf_deprecated($dep:literal, $new_conf:ident)])? ($name:ident: $ty:ty = $default:expr), )*) => { /// Clippy lint configuration @@ -137,17 +139,29 @@ macro_rules! define_Conf { fn visit_map(self, mut map: V) -> Result where V: MapAccess<'de> { let mut errors = Vec::new(); + let mut warnings = Vec::new(); $(let mut $name = None;)* // could get `Field` here directly, but get `str` first for diagnostics while let Some(name) = map.next_key::<&str>()? { match Field::deserialize(name.into_deserializer())? { $(Field::$name => { - $(errors.push(conf_error(format!("deprecated field `{}`. {}", name, $dep)));)? + $(warnings.push(conf_error(format!("deprecated field `{}`. {}", name, $dep)));)? match map.next_value() { Err(e) => errors.push(conf_error(e.to_string())), Ok(value) => match $name { Some(_) => errors.push(conf_error(format!("duplicate field `{}`", name))), - None => $name = Some(value), + None => { + $name = Some(value); + // $new_conf is the same as one of the defined `$name`s, so + // this variable is defined in line 2 of this function. + $(match $new_conf { + Some(_) => errors.push(conf_error(concat!( + "duplicate field `", stringify!($new_conf), + "` (provided as `", stringify!($name), "`)" + ))), + None => $new_conf = $name.clone(), + })? + }, } } })* @@ -156,7 +170,7 @@ macro_rules! define_Conf { } } let conf = Conf { $($name: $name.unwrap_or_else(defaults::$name),)* }; - Ok(TryConf { conf, errors }) + Ok(TryConf { conf, errors, warnings }) } } @@ -203,12 +217,11 @@ define_Conf! { /// /// The minimum rust version that the project supports (msrv: Option = None), - /// Lint: BLACKLISTED_NAME. + /// DEPRECATED LINT: BLACKLISTED_NAME. /// - /// The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses. The value - /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the - /// default configuration of Clippy. By default any configuraction will replace the default value. - (blacklisted_names: Vec = super::DEFAULT_BLACKLISTED_NAMES.iter().map(ToString::to_string).collect()), + /// Use the Disallowed Names lint instead + #[conf_deprecated("Please use `disallowed-names` instead", disallowed_names)] + (blacklisted_names: Vec = Vec::new()), /// Lint: COGNITIVE_COMPLEXITY. /// /// The maximum cognitive complexity a function can have @@ -216,8 +229,14 @@ define_Conf! { /// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY. /// /// Use the Cognitive Complexity lint instead. - #[conf_deprecated("Please use `cognitive-complexity-threshold` instead")] - (cyclomatic_complexity_threshold: Option = None), + #[conf_deprecated("Please use `cognitive-complexity-threshold` instead", cognitive_complexity_threshold)] + (cyclomatic_complexity_threshold: u64 = 25), + /// Lint: DISALLOWED_NAMES. + /// + /// The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value + /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the + /// default configuration of Clippy. By default any configuration will replace the default value. + (disallowed_names: Vec = super::DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()), /// Lint: DOC_MARKDOWN. /// /// The list of words this lint should not consider as identifiers needing ticks. The value @@ -420,7 +439,7 @@ pub fn read(path: &Path) -> TryConf { match toml::from_str::(&content) { Ok(mut conf) => { extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS); - extend_vec_if_indicator_present(&mut conf.conf.blacklisted_names, DEFAULT_BLACKLISTED_NAMES); + extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES); conf }, diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index b309653291b1..5dcacd604be4 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -496,12 +496,14 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { cx, }; let body_id = cx.tcx.hir().body_owned_by( - impl_item_refs - .iter() - .find(|iiref| iiref.ident.as_str() == "get_lints") - .expect("LintPass needs to implement get_lints") - .id - .hir_id(), + cx.tcx.hir().local_def_id( + impl_item_refs + .iter() + .find(|iiref| iiref.ident.as_str() == "get_lints") + .expect("LintPass needs to implement get_lints") + .id + .hir_id(), + ), ); collector.visit_expr(&cx.tcx.hir().body(body_id).value); } @@ -569,7 +571,7 @@ fn check_invalid_clippy_version_attribute(cx: &LateContext<'_>, item: &'_ Item<' item.span, "this item has an invalid `clippy::version` attribute", None, - "please use a valid sematic version, see `doc/adding_lints.md`", + "please use a valid semantic version, see `doc/adding_lints.md`", ); } } else { diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 92934c16d4b4..92cf42c7ad43 100644 --- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -619,7 +619,7 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector { if_chain! { // item validation if is_lint_ref_type(cx, ty); - // blacklist check + // disallow check let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase(); if !BLACK_LISTED_LINTS.contains(&lint_name.as_str()); // metadata extraction @@ -644,7 +644,7 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector { if_chain! { if is_deprecated_lint(cx, ty); - // blacklist check + // disallow check let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase(); if !BLACK_LISTED_LINTS.contains(&lint_name.as_str()); // Metadata the little we can get from a deprecated lint diff --git a/clippy_lints/src/verbose_file_reads.rs b/clippy_lints/src/verbose_file_reads.rs index 8e2ddd225fdb..afd0077a6580 100644 --- a/clippy_lints/src/verbose_file_reads.rs +++ b/clippy_lints/src/verbose_file_reads.rs @@ -61,10 +61,10 @@ impl<'tcx> LateLintPass<'tcx> for VerboseFileReads { fn is_file_read_to_end<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { if_chain! { - if let ExprKind::MethodCall(method_name, exprs, _) = expr.kind; + if let ExprKind::MethodCall(method_name, [recv, ..], _) = expr.kind; if method_name.ident.as_str() == "read_to_end"; - if let ExprKind::Path(QPath::Resolved(None, _)) = &exprs[0].kind; - let ty = cx.typeck_results().expr_ty(&exprs[0]); + if let ExprKind::Path(QPath::Resolved(None, _)) = &recv.kind; + let ty = cx.typeck_results().expr_ty(recv); if match_type(cx, ty, &paths::FILE); then { return true diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index bb443bdc1168..a688050f63a6 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_utils" -version = "0.1.64" +version = "0.1.65" edition = "2021" publish = false diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs new file mode 100644 index 000000000000..8335ffae81eb --- /dev/null +++ b/clippy_utils/src/check_proc_macro.rs @@ -0,0 +1,329 @@ +//! This module handles checking if the span given is from a proc-macro or not. +//! +//! Proc-macros are capable of setting the span of every token they output to a few possible spans. +//! This includes spans we can detect easily as coming from a proc-macro (e.g. the call site +//! or the def site), and spans we can't easily detect as such (e.g. the span of any token +//! passed into the proc macro). This capability means proc-macros are capable of generating code +//! with a span that looks like it was written by the user, but which should not be linted by clippy +//! as it was generated by an external macro. +//! +//! That brings us to this module. The current approach is to determine a small bit of text which +//! must exist at both the start and the end of an item (e.g. an expression or a path) assuming the +//! code was written, and check if the span contains that text. Note this will only work correctly +//! if the span is not from a `macro_rules` based macro. + +use rustc_ast::ast::{IntTy, LitIntType, LitKind, StrStyle, UintTy}; +use rustc_hir::{ + intravisit::FnKind, Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, HirId, + Impl, ImplItem, ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, Node, QPath, TraitItem, + TraitItemKind, UnOp, UnsafeSource, Unsafety, Variant, VariantData, YieldSource, +}; +use rustc_lint::{LateContext, LintContext}; +use rustc_middle::ty::TyCtxt; +use rustc_session::Session; +use rustc_span::{Span, Symbol}; +use rustc_target::spec::abi::Abi; + +/// The search pattern to look for. Used by `span_matches_pat` +#[derive(Clone, Copy)] +pub enum Pat { + /// A single string. + Str(&'static str), + /// Any of the given strings. + MultiStr(&'static [&'static str]), + /// The string representation of the symbol. + Sym(Symbol), + /// Any decimal or hexadecimal digit depending on the location. + Num, +} + +/// Checks if the start and the end of the span's text matches the patterns. This will return false +/// if the span crosses multiple files or if source is not available. +fn span_matches_pat(sess: &Session, span: Span, start_pat: Pat, end_pat: Pat) -> bool { + let pos = sess.source_map().lookup_byte_offset(span.lo()); + let Some(ref src) = pos.sf.src else { + return false; + }; + let end = span.hi() - pos.sf.start_pos; + src.get(pos.pos.0 as usize..end.0 as usize).map_or(false, |s| { + // Spans can be wrapped in a mixture or parenthesis, whitespace, and trailing commas. + let start_str = s.trim_start_matches(|c: char| c.is_whitespace() || c == '('); + let end_str = s.trim_end_matches(|c: char| c.is_whitespace() || c == ')' || c == ','); + (match start_pat { + Pat::Str(text) => start_str.starts_with(text), + Pat::MultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)), + Pat::Sym(sym) => start_str.starts_with(sym.as_str()), + Pat::Num => start_str.as_bytes().first().map_or(false, u8::is_ascii_digit), + } && match end_pat { + Pat::Str(text) => end_str.ends_with(text), + Pat::MultiStr(texts) => texts.iter().any(|s| start_str.ends_with(s)), + Pat::Sym(sym) => end_str.ends_with(sym.as_str()), + Pat::Num => end_str.as_bytes().last().map_or(false, u8::is_ascii_hexdigit), + }) + }) +} + +/// Get the search patterns to use for the given literal +fn lit_search_pat(lit: &LitKind) -> (Pat, Pat) { + match lit { + LitKind::Str(_, StrStyle::Cooked) => (Pat::Str("\""), Pat::Str("\"")), + LitKind::Str(_, StrStyle::Raw(0)) => (Pat::Str("r"), Pat::Str("\"")), + LitKind::Str(_, StrStyle::Raw(_)) => (Pat::Str("r#"), Pat::Str("#")), + LitKind::ByteStr(_) => (Pat::Str("b\""), Pat::Str("\"")), + LitKind::Byte(_) => (Pat::Str("b'"), Pat::Str("'")), + LitKind::Char(_) => (Pat::Str("'"), Pat::Str("'")), + LitKind::Int(_, LitIntType::Signed(IntTy::Isize)) => (Pat::Num, Pat::Str("isize")), + LitKind::Int(_, LitIntType::Unsigned(UintTy::Usize)) => (Pat::Num, Pat::Str("usize")), + LitKind::Int(..) => (Pat::Num, Pat::Num), + LitKind::Float(..) => (Pat::Num, Pat::Str("")), + LitKind::Bool(true) => (Pat::Str("true"), Pat::Str("true")), + LitKind::Bool(false) => (Pat::Str("false"), Pat::Str("false")), + _ => (Pat::Str(""), Pat::Str("")), + } +} + +/// Get the search patterns to use for the given path +fn qpath_search_pat(path: &QPath<'_>) -> (Pat, Pat) { + match path { + QPath::Resolved(ty, path) => { + let start = if ty.is_some() { + Pat::Str("<") + } else { + path.segments + .first() + .map_or(Pat::Str(""), |seg| Pat::Sym(seg.ident.name)) + }; + let end = path.segments.last().map_or(Pat::Str(""), |seg| { + if seg.args.is_some() { + Pat::Str(">") + } else { + Pat::Sym(seg.ident.name) + } + }); + (start, end) + }, + QPath::TypeRelative(_, name) => (Pat::Str(""), Pat::Sym(name.ident.name)), + QPath::LangItem(..) => (Pat::Str(""), Pat::Str("")), + } +} + +/// Get the search patterns to use for the given expression +fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) { + match e.kind { + ExprKind::Box(e) => (Pat::Str("box"), expr_search_pat(tcx, e).1), + ExprKind::ConstBlock(_) => (Pat::Str("const"), Pat::Str("}")), + ExprKind::Tup([]) => (Pat::Str(")"), Pat::Str("(")), + ExprKind::Unary(UnOp::Deref, e) => (Pat::Str("*"), expr_search_pat(tcx, e).1), + ExprKind::Unary(UnOp::Not, e) => (Pat::Str("!"), expr_search_pat(tcx, e).1), + ExprKind::Unary(UnOp::Neg, e) => (Pat::Str("-"), expr_search_pat(tcx, e).1), + ExprKind::Lit(ref lit) => lit_search_pat(&lit.node), + ExprKind::Array(_) | ExprKind::Repeat(..) => (Pat::Str("["), Pat::Str("]")), + ExprKind::Call(e, []) | ExprKind::MethodCall(_, [e], _) => (expr_search_pat(tcx, e).0, Pat::Str("(")), + ExprKind::Call(first, [.., last]) + | ExprKind::MethodCall(_, [first, .., last], _) + | ExprKind::Binary(_, first, last) + | ExprKind::Tup([first, .., last]) + | ExprKind::Assign(first, last, _) + | ExprKind::AssignOp(_, first, last) => (expr_search_pat(tcx, first).0, expr_search_pat(tcx, last).1), + ExprKind::Tup([e]) | ExprKind::DropTemps(e) => expr_search_pat(tcx, e), + ExprKind::Cast(e, _) | ExprKind::Type(e, _) => (expr_search_pat(tcx, e).0, Pat::Str("")), + ExprKind::Let(let_expr) => (Pat::Str("let"), expr_search_pat(tcx, let_expr.init).1), + ExprKind::If(..) => (Pat::Str("if"), Pat::Str("}")), + ExprKind::Loop(_, Some(_), _, _) | ExprKind::Block(_, Some(_)) => (Pat::Str("'"), Pat::Str("}")), + ExprKind::Loop(_, None, LoopSource::Loop, _) => (Pat::Str("loop"), Pat::Str("}")), + ExprKind::Loop(_, None, LoopSource::While, _) => (Pat::Str("while"), Pat::Str("}")), + ExprKind::Loop(_, None, LoopSource::ForLoop, _) | ExprKind::Match(_, _, MatchSource::ForLoopDesugar) => { + (Pat::Str("for"), Pat::Str("}")) + }, + ExprKind::Match(_, _, MatchSource::Normal) => (Pat::Str("match"), Pat::Str("}")), + ExprKind::Match(e, _, MatchSource::TryDesugar) => (expr_search_pat(tcx, e).0, Pat::Str("?")), + ExprKind::Match(e, _, MatchSource::AwaitDesugar) | ExprKind::Yield(e, YieldSource::Await { .. }) => { + (expr_search_pat(tcx, e).0, Pat::Str("await")) + }, + ExprKind::Closure(&Closure { body, .. }) => (Pat::Str(""), expr_search_pat(tcx, &tcx.hir().body(body).value).1), + ExprKind::Block( + Block { + rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided), + .. + }, + None, + ) => (Pat::Str("unsafe"), Pat::Str("}")), + ExprKind::Block(_, None) => (Pat::Str("{"), Pat::Str("}")), + ExprKind::Field(e, name) => (expr_search_pat(tcx, e).0, Pat::Sym(name.name)), + ExprKind::Index(e, _) => (expr_search_pat(tcx, e).0, Pat::Str("]")), + ExprKind::Path(ref path) => qpath_search_pat(path), + ExprKind::AddrOf(_, _, e) => (Pat::Str("&"), expr_search_pat(tcx, e).1), + ExprKind::Break(Destination { label: None, .. }, None) => (Pat::Str("break"), Pat::Str("break")), + ExprKind::Break(Destination { label: Some(name), .. }, None) => (Pat::Str("break"), Pat::Sym(name.ident.name)), + ExprKind::Break(_, Some(e)) => (Pat::Str("break"), expr_search_pat(tcx, e).1), + ExprKind::Continue(Destination { label: None, .. }) => (Pat::Str("continue"), Pat::Str("continue")), + ExprKind::Continue(Destination { label: Some(name), .. }) => (Pat::Str("continue"), Pat::Sym(name.ident.name)), + ExprKind::Ret(None) => (Pat::Str("return"), Pat::Str("return")), + ExprKind::Ret(Some(e)) => (Pat::Str("return"), expr_search_pat(tcx, e).1), + ExprKind::Struct(path, _, _) => (qpath_search_pat(path).0, Pat::Str("}")), + ExprKind::Yield(e, YieldSource::Yield) => (Pat::Str("yield"), expr_search_pat(tcx, e).1), + _ => (Pat::Str(""), Pat::Str("")), + } +} + +fn fn_header_search_pat(header: FnHeader) -> Pat { + if header.is_async() { + Pat::Str("async") + } else if header.is_const() { + Pat::Str("const") + } else if header.is_unsafe() { + Pat::Str("unsafe") + } else if header.abi != Abi::Rust { + Pat::Str("extern") + } else { + Pat::MultiStr(&["fn", "extern"]) + } +} + +fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) { + let (start_pat, end_pat) = match &item.kind { + ItemKind::ExternCrate(_) => (Pat::Str("extern"), Pat::Str(";")), + ItemKind::Static(..) => (Pat::Str("static"), Pat::Str(";")), + ItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")), + ItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")), + ItemKind::ForeignMod { .. } => (Pat::Str("extern"), Pat::Str("}")), + ItemKind::TyAlias(..) | ItemKind::OpaqueTy(_) => (Pat::Str("type"), Pat::Str(";")), + ItemKind::Enum(..) => (Pat::Str("enum"), Pat::Str("}")), + ItemKind::Struct(VariantData::Struct(..), _) => (Pat::Str("struct"), Pat::Str("}")), + ItemKind::Struct(..) => (Pat::Str("struct"), Pat::Str(";")), + ItemKind::Union(..) => (Pat::Str("union"), Pat::Str("}")), + ItemKind::Trait(_, Unsafety::Unsafe, ..) + | ItemKind::Impl(Impl { + unsafety: Unsafety::Unsafe, + .. + }) => (Pat::Str("unsafe"), Pat::Str("}")), + ItemKind::Trait(IsAuto::Yes, ..) => (Pat::Str("auto"), Pat::Str("}")), + ItemKind::Trait(..) => (Pat::Str("trait"), Pat::Str("}")), + ItemKind::Impl(_) => (Pat::Str("impl"), Pat::Str("}")), + _ => return (Pat::Str(""), Pat::Str("")), + }; + if item.vis_span.is_empty() { + (start_pat, end_pat) + } else { + (Pat::Str("pub"), end_pat) + } +} + +fn trait_item_search_pat(item: &TraitItem<'_>) -> (Pat, Pat) { + match &item.kind { + TraitItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")), + TraitItemKind::Type(..) => (Pat::Str("type"), Pat::Str(";")), + TraitItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")), + } +} + +fn impl_item_search_pat(item: &ImplItem<'_>) -> (Pat, Pat) { + let (start_pat, end_pat) = match &item.kind { + ImplItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")), + ImplItemKind::TyAlias(..) => (Pat::Str("type"), Pat::Str(";")), + ImplItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")), + }; + if item.vis_span.is_empty() { + (start_pat, end_pat) + } else { + (Pat::Str("pub"), end_pat) + } +} + +fn field_def_search_pat(def: &FieldDef<'_>) -> (Pat, Pat) { + if def.vis_span.is_empty() { + if def.is_positional() { + (Pat::Str(""), Pat::Str("")) + } else { + (Pat::Sym(def.ident.name), Pat::Str("")) + } + } else { + (Pat::Str("pub"), Pat::Str("")) + } +} + +fn variant_search_pat(v: &Variant<'_>) -> (Pat, Pat) { + match v.data { + VariantData::Struct(..) => (Pat::Sym(v.ident.name), Pat::Str("}")), + VariantData::Tuple(..) => (Pat::Sym(v.ident.name), Pat::Str("")), + VariantData::Unit(..) => (Pat::Sym(v.ident.name), Pat::Sym(v.ident.name)), + } +} + +fn fn_kind_pat(tcx: TyCtxt<'_>, kind: &FnKind<'_>, body: &Body<'_>, hir_id: HirId) -> (Pat, Pat) { + let (start_pat, end_pat) = match kind { + FnKind::ItemFn(.., header) => (fn_header_search_pat(*header), Pat::Str("")), + FnKind::Method(.., sig) => (fn_header_search_pat(sig.header), Pat::Str("")), + FnKind::Closure => return (Pat::Str(""), expr_search_pat(tcx, &body.value).1), + }; + let start_pat = match tcx.hir().get(hir_id) { + Node::Item(Item { vis_span, .. }) | Node::ImplItem(ImplItem { vis_span, .. }) => { + if vis_span.is_empty() { + start_pat + } else { + Pat::Str("pub") + } + }, + Node::TraitItem(_) => start_pat, + _ => Pat::Str(""), + }; + (start_pat, end_pat) +} + +pub trait WithSearchPat { + type Context: LintContext; + fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat); + fn span(&self) -> Span; +} +macro_rules! impl_with_search_pat { + ($cx:ident: $ty:ident with $fn:ident $(($tcx:ident))?) => { + impl<'cx> WithSearchPat for $ty<'cx> { + type Context = $cx<'cx>; + #[allow(unused_variables)] + fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat) { + $(let $tcx = cx.tcx;)? + $fn($($tcx,)? self) + } + fn span(&self) -> Span { + self.span + } + } + }; +} +impl_with_search_pat!(LateContext: Expr with expr_search_pat(tcx)); +impl_with_search_pat!(LateContext: Item with item_search_pat); +impl_with_search_pat!(LateContext: TraitItem with trait_item_search_pat); +impl_with_search_pat!(LateContext: ImplItem with impl_item_search_pat); +impl_with_search_pat!(LateContext: FieldDef with field_def_search_pat); +impl_with_search_pat!(LateContext: Variant with variant_search_pat); + +impl<'cx> WithSearchPat for (&FnKind<'cx>, &Body<'cx>, HirId, Span) { + type Context = LateContext<'cx>; + + fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat) { + fn_kind_pat(cx.tcx, self.0, self.1, self.2) + } + + fn span(&self) -> Span { + self.3 + } +} + +/// Checks if the item likely came from a proc-macro. +/// +/// This should be called after `in_external_macro` and the initial pattern matching of the ast as +/// it is significantly slower than both of those. +pub fn is_from_proc_macro(cx: &T::Context, item: &T) -> bool { + let (start_pat, end_pat) = item.search_pat(cx); + !span_matches_pat(cx.sess(), item.span(), start_pat, end_pat) +} + +/// Checks if the span actually refers to a match expression +pub fn is_span_match(cx: &impl LintContext, span: Span) -> bool { + span_matches_pat(cx.sess(), span, Pat::Str("match"), Pat::Str("}")) +} + +/// Checks if the span actually refers to an if expression +pub fn is_span_if(cx: &impl LintContext, span: Span) -> bool { + span_matches_pat(cx.sess(), span, Pat::Str("if"), Pat::Str("}")) +} diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 7493a8685dff..2616a578bb88 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -39,6 +39,7 @@ pub mod sym_helper; pub mod ast_utils; pub mod attrs; +mod check_proc_macro; pub mod comparisons; pub mod consts; pub mod diagnostics; @@ -59,6 +60,7 @@ pub mod usage; pub mod visitors; pub use self::attrs::*; +pub use self::check_proc_macro::{is_from_proc_macro, is_span_if, is_span_match}; pub use self::hir_utils::{ both, count_eq, eq_expr_value, hash_expr, hash_stmt, over, HirEqInterExpr, SpanlessEq, SpanlessHash, }; diff --git a/clippy_utils/src/numeric_literal.rs b/clippy_utils/src/numeric_literal.rs index 3fb5415ce029..80098d9766c6 100644 --- a/clippy_utils/src/numeric_literal.rs +++ b/clippy_utils/src/numeric_literal.rs @@ -223,10 +223,12 @@ impl<'a> NumericLiteral<'a> { fn split_suffix<'a>(src: &'a str, lit_kind: &LitKind) -> (&'a str, Option<&'a str>) { debug_assert!(lit_kind.is_numeric()); - lit_suffix_length(lit_kind).map_or((src, None), |suffix_length| { - let (unsuffixed, suffix) = src.split_at(src.len() - suffix_length); - (unsuffixed, Some(suffix)) - }) + lit_suffix_length(lit_kind) + .and_then(|suffix_length| src.len().checked_sub(suffix_length)) + .map_or((src, None), |split_pos| { + let (unsuffixed, suffix) = src.split_at(split_pos); + (unsuffixed, Some(suffix)) + }) } fn lit_suffix_length(lit_kind: &LitKind) -> Option { diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 05429d05d9eb..8d697a301c44 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -194,3 +194,5 @@ pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"]; pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"]; pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"]; pub const PTR_NON_NULL: [&str; 4] = ["core", "ptr", "non_null", "NonNull"]; +pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"]; +pub const INSTANT: [&str; 3] = ["std", "time", "Instant"]; diff --git a/clippy_utils/src/source.rs b/clippy_utils/src/source.rs index 1197fe914de4..d85f591fb9a4 100644 --- a/clippy_utils/src/source.rs +++ b/clippy_utils/src/source.rs @@ -11,24 +11,6 @@ use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, Pos, Span, SpanData, SyntaxContext}; use std::borrow::Cow; -/// Checks if the span starts with the given text. This will return false if the span crosses -/// multiple files or if source is not available. -/// -/// This is used to check for proc macros giving unhelpful spans to things. -pub fn span_starts_with(cx: &T, span: Span, text: &str) -> bool { - fn helper(sm: &SourceMap, span: Span, text: &str) -> bool { - let pos = sm.lookup_byte_offset(span.lo()); - let Some(ref src) = pos.sf.src else { - return false; - }; - let end = span.hi() - pos.sf.start_pos; - src.get(pos.pos.0 as usize..end.0 as usize) - // Expression spans can include wrapping parenthesis. Remove them first. - .map_or(false, |s| s.trim_start_matches('(').starts_with(text)) - } - helper(cx.sess().source_map(), span, text) -} - /// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`. /// Also takes an `Option` which can be put inside the braces. pub fn expr_block<'a, T: LintContext>( diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index bad291dfc251..081c98e2f3ce 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -315,6 +315,12 @@ impl<'a> Sugg<'a> { Sugg::NonParen(Cow::Owned(format!("{{ {} }}", self))) } + /// Convenience method to prefix the expression with the `async` keyword. + /// Can be used after `blockify` to create an async block. + pub fn asyncify(self) -> Sugg<'static> { + Sugg::NonParen(Cow::Owned(format!("async {}", self))) + } + /// Convenience method to create the `..` or `...` /// suggestion. pub fn range(self, end: &Self, limit: ast::RangeLimits) -> Sugg<'static> { diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index a05d633d980c..e7d670766a05 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -503,7 +503,7 @@ pub fn all_predicates_of(tcx: TyCtxt<'_>, id: DefId) -> impl Iterator { Sig(Binder<'tcx, FnSig<'tcx>>, Option), Closure(Option<&'tcx FnDecl<'tcx>>, Binder<'tcx, FnSig<'tcx>>), - Trait(Binder<'tcx, Ty<'tcx>>, Option>>), + Trait(Binder<'tcx, Ty<'tcx>>, Option>>, Option), } impl<'tcx> ExprFnSig<'tcx> { /// Gets the argument type at the given offset. This will return `None` when the index is out of @@ -518,7 +518,7 @@ impl<'tcx> ExprFnSig<'tcx> { } }, Self::Closure(_, sig) => Some(sig.input(0).map_bound(|ty| ty.tuple_fields()[i])), - Self::Trait(inputs, _) => Some(inputs.map_bound(|ty| ty.tuple_fields()[i])), + Self::Trait(inputs, _, _) => Some(inputs.map_bound(|ty| ty.tuple_fields()[i])), } } @@ -541,7 +541,7 @@ impl<'tcx> ExprFnSig<'tcx> { decl.and_then(|decl| decl.inputs.get(i)), sig.input(0).map_bound(|ty| ty.tuple_fields()[i]), )), - Self::Trait(inputs, _) => Some((None, inputs.map_bound(|ty| ty.tuple_fields()[i]))), + Self::Trait(inputs, _, _) => Some((None, inputs.map_bound(|ty| ty.tuple_fields()[i]))), } } @@ -550,12 +550,16 @@ impl<'tcx> ExprFnSig<'tcx> { pub fn output(self) -> Option>> { match self { Self::Sig(sig, _) | Self::Closure(_, sig) => Some(sig.output()), - Self::Trait(_, output) => output, + Self::Trait(_, output, _) => output, } } pub fn predicates_id(&self) -> Option { - if let ExprFnSig::Sig(_, id) = *self { id } else { None } + if let ExprFnSig::Sig(_, id) | ExprFnSig::Trait(_, _, id) = *self { + id + } else { + None + } } } @@ -568,7 +572,8 @@ pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { +/// If the type is function like, get the signature for it. +pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { if ty.is_box() { return ty_sig(cx, ty.boxed_ty()); } @@ -580,7 +585,7 @@ fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> Some(ExprFnSig::Closure(decl, subs.as_closure().sig())) }, ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))), - ty::Opaque(id, _) => ty_sig(cx, cx.tcx.type_of(id)), + ty::Opaque(id, _) => sig_from_bounds(cx, ty, cx.tcx.item_bounds(id), cx.tcx.opt_parent(id)), ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)), ty::Dynamic(bounds, _) => { let lang_items = cx.tcx.lang_items(); @@ -594,26 +599,31 @@ fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> .projection_bounds() .find(|p| lang_items.fn_once_output().map_or(false, |id| id == p.item_def_id())) .map(|p| p.map_bound(|p| p.term.ty().unwrap())); - Some(ExprFnSig::Trait(bound.map_bound(|b| b.substs.type_at(0)), output)) + Some(ExprFnSig::Trait(bound.map_bound(|b| b.substs.type_at(0)), output, None)) }, _ => None, } }, ty::Projection(proj) => match cx.tcx.try_normalize_erasing_regions(cx.param_env, ty) { Ok(normalized_ty) if normalized_ty != ty => ty_sig(cx, normalized_ty), - _ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty)), + _ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None)), }, - ty::Param(_) => sig_from_bounds(cx, ty), + ty::Param(_) => sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None), _ => None, } } -fn sig_from_bounds<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { +fn sig_from_bounds<'tcx>( + cx: &LateContext<'tcx>, + ty: Ty<'tcx>, + predicates: &'tcx [Predicate<'tcx>], + predicates_id: Option, +) -> Option> { let mut inputs = None; let mut output = None; let lang_items = cx.tcx.lang_items(); - for (pred, _) in all_predicates_of(cx.tcx, cx.typeck_results().hir_owner.to_def_id()) { + for pred in predicates { match pred.kind().skip_binder() { PredicateKind::Trait(p) if (lang_items.fn_trait() == Some(p.def_id()) @@ -621,11 +631,12 @@ fn sig_from_bounds<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option { - if inputs.is_some() { + let i = pred.kind().rebind(p.trait_ref.substs.type_at(1)); + if inputs.map_or(false, |inputs| i != inputs) { // Multiple different fn trait impls. Is this even allowed? return None; } - inputs = Some(pred.kind().rebind(p.trait_ref.substs.type_at(1))); + inputs = Some(i); }, PredicateKind::Projection(p) if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() @@ -641,7 +652,7 @@ fn sig_from_bounds<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> Option> { @@ -661,14 +672,15 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> O || lang_items.fn_mut_trait() == Some(p.def_id()) || lang_items.fn_once_trait() == Some(p.def_id())) => { - if inputs.is_some() { + let i = pred + .map_bound(|pred| pred.kind().rebind(p.trait_ref.substs.type_at(1))) + .subst(cx.tcx, ty.substs); + + if inputs.map_or(false, |inputs| inputs != i) { // Multiple different fn trait impls. Is this even allowed? return None; } - inputs = Some( - pred.map_bound(|pred| pred.kind().rebind(p.trait_ref.substs.type_at(1))) - .subst(cx.tcx, ty.substs), - ); + inputs = Some(i); }, PredicateKind::Projection(p) if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() => { if output.is_some() { @@ -684,7 +696,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> O } } - inputs.map(|ty| ExprFnSig::Trait(ty, output)) + inputs.map(|ty| ExprFnSig::Trait(ty, output, None)) } #[derive(Clone, Copy)] diff --git a/rust-toolchain b/rust-toolchain index 23ba7c712779..7e14df4feea6 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2022-07-28" +channel = "nightly-2022-08-11" components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/tests/ui-internal/check_clippy_version_attribute.stderr b/tests/ui-internal/check_clippy_version_attribute.stderr index 5331075885c1..2aa4de490bcf 100644 --- a/tests/ui-internal/check_clippy_version_attribute.stderr +++ b/tests/ui-internal/check_clippy_version_attribute.stderr @@ -16,7 +16,7 @@ note: the lint level is defined here LL | #![deny(clippy::internal)] | ^^^^^^^^^^^^^^^^ = note: `#[deny(clippy::invalid_clippy_version_attribute)]` implied by `#[deny(clippy::internal)]` - = help: please use a valid sematic version, see `doc/adding_lints.md` + = help: please use a valid semantic version, see `doc/adding_lints.md` = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) error: this item has an invalid `clippy::version` attribute @@ -31,7 +31,7 @@ LL | | report_in_external_macro: true LL | | } | |_^ | - = help: please use a valid sematic version, see `doc/adding_lints.md` + = help: please use a valid semantic version, see `doc/adding_lints.md` = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) error: this lint is missing the `clippy::version` attribute or version value diff --git a/tests/ui-toml/bad_toml_type/clippy.toml b/tests/ui-toml/bad_toml_type/clippy.toml index 168675394d7f..d48bab08f690 100644 --- a/tests/ui-toml/bad_toml_type/clippy.toml +++ b/tests/ui-toml/bad_toml_type/clippy.toml @@ -1 +1 @@ -blacklisted-names = 42 +disallowed-names = 42 diff --git a/tests/ui-toml/bad_toml_type/conf_bad_type.stderr b/tests/ui-toml/bad_toml_type/conf_bad_type.stderr index c7bc261de6c5..e3ec60192040 100644 --- a/tests/ui-toml/bad_toml_type/conf_bad_type.stderr +++ b/tests/ui-toml/bad_toml_type/conf_bad_type.stderr @@ -1,4 +1,4 @@ -error: error reading Clippy's configuration file `$DIR/clippy.toml`: invalid type: integer `42`, expected a sequence for key `blacklisted-names` +error: error reading Clippy's configuration file `$DIR/clippy.toml`: invalid type: integer `42`, expected a sequence for key `disallowed-names` error: aborting due to previous error diff --git a/tests/ui-toml/blacklisted_names_append/blacklisted_names.stderr b/tests/ui-toml/blacklisted_names_append/blacklisted_names.stderr deleted file mode 100644 index 9169bb0e866a..000000000000 --- a/tests/ui-toml/blacklisted_names_append/blacklisted_names.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error: use of a blacklisted/placeholder name `foo` - --> $DIR/blacklisted_names.rs:5:9 - | -LL | let foo = "bar"; - | ^^^ - | - = note: `-D clippy::blacklisted-name` implied by `-D warnings` - -error: use of a blacklisted/placeholder name `ducks` - --> $DIR/blacklisted_names.rs:7:9 - | -LL | let ducks = ["quack", "quack"]; - | ^^^^^ - -error: aborting due to 2 previous errors - diff --git a/tests/ui-toml/blacklisted_names_append/clippy.toml b/tests/ui-toml/blacklisted_names_append/clippy.toml deleted file mode 100644 index 0e052ef50f07..000000000000 --- a/tests/ui-toml/blacklisted_names_append/clippy.toml +++ /dev/null @@ -1 +0,0 @@ -blacklisted-names = ["ducks", ".."] diff --git a/tests/ui-toml/blacklisted_names_replace/blacklisted_names.stderr b/tests/ui-toml/blacklisted_names_replace/blacklisted_names.stderr deleted file mode 100644 index ec6f7f084f2a..000000000000 --- a/tests/ui-toml/blacklisted_names_replace/blacklisted_names.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: use of a blacklisted/placeholder name `ducks` - --> $DIR/blacklisted_names.rs:7:9 - | -LL | let ducks = ["quack", "quack"]; - | ^^^^^ - | - = note: `-D clippy::blacklisted-name` implied by `-D warnings` - -error: aborting due to previous error - diff --git a/tests/ui-toml/blacklisted_names_replace/clippy.toml b/tests/ui-toml/blacklisted_names_replace/clippy.toml deleted file mode 100644 index 4582f1c06674..000000000000 --- a/tests/ui-toml/blacklisted_names_replace/clippy.toml +++ /dev/null @@ -1 +0,0 @@ -blacklisted-names = ["ducks"] diff --git a/tests/ui-toml/conf_deprecated_key/clippy.toml b/tests/ui-toml/conf_deprecated_key/clippy.toml index ac47b195042e..d79a98d05af4 100644 --- a/tests/ui-toml/conf_deprecated_key/clippy.toml +++ b/tests/ui-toml/conf_deprecated_key/clippy.toml @@ -1,5 +1,6 @@ -# that one is an error -cyclomatic-complexity-threshold = 42 +# Expect errors from these deprecated configs +cyclomatic-complexity-threshold = 2 +blacklisted-names = [ "..", "wibble" ] # that one is white-listed [third-party] diff --git a/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs b/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs index f328e4d9d04c..b4e677ea124b 100644 --- a/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs +++ b/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs @@ -1 +1,11 @@ fn main() {} + +#[warn(clippy::cognitive_complexity)] +fn cognitive_complexity() { + let x = vec![1, 2, 3]; + for i in x { + if i == 1 { + println!("{}", i); + } + } +} diff --git a/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr b/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr index 90021a034a3d..4c560299ebdd 100644 --- a/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr +++ b/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr @@ -1,4 +1,15 @@ -error: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead +warning: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead -error: aborting due to previous error +warning: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `blacklisted-names`. Please use `disallowed-names` instead + +error: the function has a cognitive complexity of (3/2) + --> $DIR/conf_deprecated_key.rs:4:4 + | +LL | fn cognitive_complexity() { + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::cognitive-complexity` implied by `-D warnings` + = help: you could split it up into multiple smaller functions + +error: aborting due to previous error; 2 warnings emitted diff --git a/tests/ui-toml/disallowed_names_append/clippy.toml b/tests/ui-toml/disallowed_names_append/clippy.toml new file mode 100644 index 000000000000..6df96a3c214b --- /dev/null +++ b/tests/ui-toml/disallowed_names_append/clippy.toml @@ -0,0 +1 @@ +disallowed-names = ["ducks", ".."] diff --git a/tests/ui-toml/blacklisted_names_replace/blacklisted_names.rs b/tests/ui-toml/disallowed_names_append/disallowed_names.rs similarity index 72% rename from tests/ui-toml/blacklisted_names_replace/blacklisted_names.rs rename to tests/ui-toml/disallowed_names_append/disallowed_names.rs index fb2395cf90be..a2e2b46c4269 100644 --- a/tests/ui-toml/blacklisted_names_replace/blacklisted_names.rs +++ b/tests/ui-toml/disallowed_names_append/disallowed_names.rs @@ -1,9 +1,9 @@ -#[warn(clippy::blacklisted_name)] +#[warn(clippy::disallowed_names)] fn main() { // `foo` is part of the default configuration let foo = "bar"; - // `ducks` was unrightfully blacklisted + // `ducks` was unrightfully disallowed let ducks = ["quack", "quack"]; // `fox` is okay let fox = ["what", "does", "the", "fox", "say", "?"]; diff --git a/tests/ui-toml/disallowed_names_append/disallowed_names.stderr b/tests/ui-toml/disallowed_names_append/disallowed_names.stderr new file mode 100644 index 000000000000..23c3e96a8d08 --- /dev/null +++ b/tests/ui-toml/disallowed_names_append/disallowed_names.stderr @@ -0,0 +1,16 @@ +error: use of a disallowed/placeholder name `foo` + --> $DIR/disallowed_names.rs:5:9 + | +LL | let foo = "bar"; + | ^^^ + | + = note: `-D clippy::disallowed-names` implied by `-D warnings` + +error: use of a disallowed/placeholder name `ducks` + --> $DIR/disallowed_names.rs:7:9 + | +LL | let ducks = ["quack", "quack"]; + | ^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui-toml/disallowed_names_replace/clippy.toml b/tests/ui-toml/disallowed_names_replace/clippy.toml new file mode 100644 index 000000000000..a1c515652d3c --- /dev/null +++ b/tests/ui-toml/disallowed_names_replace/clippy.toml @@ -0,0 +1 @@ +disallowed-names = ["ducks"] diff --git a/tests/ui-toml/blacklisted_names_append/blacklisted_names.rs b/tests/ui-toml/disallowed_names_replace/disallowed_names.rs similarity index 72% rename from tests/ui-toml/blacklisted_names_append/blacklisted_names.rs rename to tests/ui-toml/disallowed_names_replace/disallowed_names.rs index fb2395cf90be..a2e2b46c4269 100644 --- a/tests/ui-toml/blacklisted_names_append/blacklisted_names.rs +++ b/tests/ui-toml/disallowed_names_replace/disallowed_names.rs @@ -1,9 +1,9 @@ -#[warn(clippy::blacklisted_name)] +#[warn(clippy::disallowed_names)] fn main() { // `foo` is part of the default configuration let foo = "bar"; - // `ducks` was unrightfully blacklisted + // `ducks` was unrightfully disallowed let ducks = ["quack", "quack"]; // `fox` is okay let fox = ["what", "does", "the", "fox", "say", "?"]; diff --git a/tests/ui-toml/disallowed_names_replace/disallowed_names.stderr b/tests/ui-toml/disallowed_names_replace/disallowed_names.stderr new file mode 100644 index 000000000000..d961fa34074b --- /dev/null +++ b/tests/ui-toml/disallowed_names_replace/disallowed_names.stderr @@ -0,0 +1,10 @@ +error: use of a disallowed/placeholder name `ducks` + --> $DIR/disallowed_names.rs:7:9 + | +LL | let ducks = ["quack", "quack"]; + | ^^^^^ + | + = note: `-D clippy::disallowed-names` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui-toml/duplicated_keys/clippy.toml b/tests/ui-toml/duplicated_keys/clippy.toml new file mode 100644 index 000000000000..63a893cc6c79 --- /dev/null +++ b/tests/ui-toml/duplicated_keys/clippy.toml @@ -0,0 +1,5 @@ +cognitive-complexity-threshold = 2 +# This is the deprecated name for the same key +cyclomatic-complexity-threshold = 3 +# Check we get duplication warning regardless of order +cognitive-complexity-threshold = 4 diff --git a/tests/ui-toml/duplicated_keys/duplicated_keys.rs b/tests/ui-toml/duplicated_keys/duplicated_keys.rs new file mode 100644 index 000000000000..f328e4d9d04c --- /dev/null +++ b/tests/ui-toml/duplicated_keys/duplicated_keys.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/tests/ui-toml/duplicated_keys/duplicated_keys.stderr b/tests/ui-toml/duplicated_keys/duplicated_keys.stderr new file mode 100644 index 000000000000..d99490a242d4 --- /dev/null +++ b/tests/ui-toml/duplicated_keys/duplicated_keys.stderr @@ -0,0 +1,8 @@ +error: error reading Clippy's configuration file `$DIR/clippy.toml`: duplicate field `cognitive_complexity_threshold` (provided as `cyclomatic_complexity_threshold`) + +error: error reading Clippy's configuration file `$DIR/clippy.toml`: duplicate field `cognitive-complexity-threshold` + +warning: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead + +error: aborting due to 2 previous errors; 1 warning emitted + diff --git a/tests/ui-toml/expect_used/expect_used.stderr b/tests/ui-toml/expect_used/expect_used.stderr index 9cb2199ed21c..c5d95cb8a147 100644 --- a/tests/ui-toml/expect_used/expect_used.stderr +++ b/tests/ui-toml/expect_used/expect_used.stderr @@ -5,7 +5,7 @@ LL | let _ = opt.expect(""); | ^^^^^^^^^^^^^^ | = note: `-D clippy::expect-used` implied by `-D warnings` - = help: if this value is an `None`, it will panic + = help: if this value is `None`, it will panic error: used `expect()` on `a Result` value --> $DIR/expect_used.rs:11:13 diff --git a/tests/ui-toml/toml_blacklist/clippy.toml b/tests/ui-toml/toml_blacklist/clippy.toml deleted file mode 100644 index 6abe5a3bbc27..000000000000 --- a/tests/ui-toml/toml_blacklist/clippy.toml +++ /dev/null @@ -1 +0,0 @@ -blacklisted-names = ["toto", "tata", "titi"] diff --git a/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr b/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr deleted file mode 100644 index 84ba77851f77..000000000000 --- a/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr +++ /dev/null @@ -1,46 +0,0 @@ -error: use of a blacklisted/placeholder name `toto` - --> $DIR/conf_french_blacklisted_name.rs:6:9 - | -LL | fn test(toto: ()) {} - | ^^^^ - | - = note: `-D clippy::blacklisted-name` implied by `-D warnings` - -error: use of a blacklisted/placeholder name `toto` - --> $DIR/conf_french_blacklisted_name.rs:9:9 - | -LL | let toto = 42; - | ^^^^ - -error: use of a blacklisted/placeholder name `tata` - --> $DIR/conf_french_blacklisted_name.rs:10:9 - | -LL | let tata = 42; - | ^^^^ - -error: use of a blacklisted/placeholder name `titi` - --> $DIR/conf_french_blacklisted_name.rs:11:9 - | -LL | let titi = 42; - | ^^^^ - -error: use of a blacklisted/placeholder name `toto` - --> $DIR/conf_french_blacklisted_name.rs:17:10 - | -LL | (toto, Some(tata), titi @ Some(_)) => (), - | ^^^^ - -error: use of a blacklisted/placeholder name `tata` - --> $DIR/conf_french_blacklisted_name.rs:17:21 - | -LL | (toto, Some(tata), titi @ Some(_)) => (), - | ^^^^ - -error: use of a blacklisted/placeholder name `titi` - --> $DIR/conf_french_blacklisted_name.rs:17:28 - | -LL | (toto, Some(tata), titi @ Some(_)) => (), - | ^^^^ - -error: aborting due to 7 previous errors - diff --git a/tests/ui-toml/toml_disallow/clippy.toml b/tests/ui-toml/toml_disallow/clippy.toml new file mode 100644 index 000000000000..e4f0cb6df57a --- /dev/null +++ b/tests/ui-toml/toml_disallow/clippy.toml @@ -0,0 +1 @@ +disallowed-names = ["toto", "tata", "titi"] diff --git a/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs b/tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs similarity index 90% rename from tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs rename to tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs index cb35d0e8589d..2f86b3eda4c5 100644 --- a/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs +++ b/tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs @@ -1,7 +1,7 @@ #![allow(dead_code)] #![allow(clippy::single_match)] #![allow(unused_variables)] -#![warn(clippy::blacklisted_name)] +#![warn(clippy::disallowed_names)] fn test(toto: ()) {} diff --git a/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr b/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr new file mode 100644 index 000000000000..9082c1c54c36 --- /dev/null +++ b/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr @@ -0,0 +1,46 @@ +error: use of a disallowed/placeholder name `toto` + --> $DIR/conf_french_disallowed_name.rs:6:9 + | +LL | fn test(toto: ()) {} + | ^^^^ + | + = note: `-D clippy::disallowed-names` implied by `-D warnings` + +error: use of a disallowed/placeholder name `toto` + --> $DIR/conf_french_disallowed_name.rs:9:9 + | +LL | let toto = 42; + | ^^^^ + +error: use of a disallowed/placeholder name `tata` + --> $DIR/conf_french_disallowed_name.rs:10:9 + | +LL | let tata = 42; + | ^^^^ + +error: use of a disallowed/placeholder name `titi` + --> $DIR/conf_french_disallowed_name.rs:11:9 + | +LL | let titi = 42; + | ^^^^ + +error: use of a disallowed/placeholder name `toto` + --> $DIR/conf_french_disallowed_name.rs:17:10 + | +LL | (toto, Some(tata), titi @ Some(_)) => (), + | ^^^^ + +error: use of a disallowed/placeholder name `tata` + --> $DIR/conf_french_disallowed_name.rs:17:21 + | +LL | (toto, Some(tata), titi @ Some(_)) => (), + | ^^^^ + +error: use of a disallowed/placeholder name `titi` + --> $DIR/conf_french_disallowed_name.rs:17:28 + | +LL | (toto, Some(tata), titi @ Some(_)) => (), + | ^^^^ + +error: aborting due to 7 previous errors + diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index fe5139c47680..9f8e778b3b9d 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -12,6 +12,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie cognitive-complexity-threshold cyclomatic-complexity-threshold disallowed-methods + disallowed-names disallowed-types doc-valid-idents enable-raw-pointer-heuristic-for-send diff --git a/tests/ui/assertions_on_result_states.fixed b/tests/ui/assertions_on_result_states.fixed index 7bde72e4b6b5..795f435f24cd 100644 --- a/tests/ui/assertions_on_result_states.fixed +++ b/tests/ui/assertions_on_result_states.fixed @@ -27,6 +27,14 @@ fn main() { let r: Result = Ok(Foo); assert!(r.is_ok()); + // test ok with some messages + let r: Result = Ok(Foo); + assert!(r.is_ok(), "oops"); + + // test ok with unit error + let r: Result = Ok(Foo); + assert!(r.is_ok()); + // test temporary ok fn get_ok() -> Result { Ok(Foo) diff --git a/tests/ui/assertions_on_result_states.rs b/tests/ui/assertions_on_result_states.rs index 4c5af81efc23..1101aec1e1b3 100644 --- a/tests/ui/assertions_on_result_states.rs +++ b/tests/ui/assertions_on_result_states.rs @@ -27,6 +27,14 @@ fn main() { let r: Result = Ok(Foo); assert!(r.is_ok()); + // test ok with some messages + let r: Result = Ok(Foo); + assert!(r.is_ok(), "oops"); + + // test ok with unit error + let r: Result = Ok(Foo); + assert!(r.is_ok()); + // test temporary ok fn get_ok() -> Result { Ok(Foo) diff --git a/tests/ui/assertions_on_result_states.stderr b/tests/ui/assertions_on_result_states.stderr index 13c2dd877a97..97a5f3dfca4a 100644 --- a/tests/ui/assertions_on_result_states.stderr +++ b/tests/ui/assertions_on_result_states.stderr @@ -7,31 +7,31 @@ LL | assert!(r.is_ok()); = note: `-D clippy::assertions-on-result-states` implied by `-D warnings` error: called `assert!` with `Result::is_ok` - --> $DIR/assertions_on_result_states.rs:34:5 + --> $DIR/assertions_on_result_states.rs:42:5 | LL | assert!(get_ok().is_ok()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `get_ok().unwrap()` error: called `assert!` with `Result::is_ok` - --> $DIR/assertions_on_result_states.rs:37:5 + --> $DIR/assertions_on_result_states.rs:45:5 | LL | assert!(get_ok_macro!().is_ok()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `get_ok_macro!().unwrap()` error: called `assert!` with `Result::is_ok` - --> $DIR/assertions_on_result_states.rs:50:5 + --> $DIR/assertions_on_result_states.rs:58:5 | LL | assert!(r.is_ok()); | ^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap()` error: called `assert!` with `Result::is_ok` - --> $DIR/assertions_on_result_states.rs:56:9 + --> $DIR/assertions_on_result_states.rs:64:9 | LL | assert!(r.is_ok()); | ^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap()` error: called `assert!` with `Result::is_err` - --> $DIR/assertions_on_result_states.rs:64:5 + --> $DIR/assertions_on_result_states.rs:72:5 | LL | assert!(r.is_err()); | ^^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap_err()` diff --git a/tests/ui/blacklisted_name.stderr b/tests/ui/blacklisted_name.stderr deleted file mode 100644 index 70dbdaece8b6..000000000000 --- a/tests/ui/blacklisted_name.stderr +++ /dev/null @@ -1,88 +0,0 @@ -error: use of a blacklisted/placeholder name `foo` - --> $DIR/blacklisted_name.rs:11:9 - | -LL | fn test(foo: ()) {} - | ^^^ - | - = note: `-D clippy::blacklisted-name` implied by `-D warnings` - -error: use of a blacklisted/placeholder name `foo` - --> $DIR/blacklisted_name.rs:14:9 - | -LL | let foo = 42; - | ^^^ - -error: use of a blacklisted/placeholder name `baz` - --> $DIR/blacklisted_name.rs:15:9 - | -LL | let baz = 42; - | ^^^ - -error: use of a blacklisted/placeholder name `quux` - --> $DIR/blacklisted_name.rs:16:9 - | -LL | let quux = 42; - | ^^^^ - -error: use of a blacklisted/placeholder name `foo` - --> $DIR/blacklisted_name.rs:27:10 - | -LL | (foo, Some(baz), quux @ Some(_)) => (), - | ^^^ - -error: use of a blacklisted/placeholder name `baz` - --> $DIR/blacklisted_name.rs:27:20 - | -LL | (foo, Some(baz), quux @ Some(_)) => (), - | ^^^ - -error: use of a blacklisted/placeholder name `quux` - --> $DIR/blacklisted_name.rs:27:26 - | -LL | (foo, Some(baz), quux @ Some(_)) => (), - | ^^^^ - -error: use of a blacklisted/placeholder name `foo` - --> $DIR/blacklisted_name.rs:32:19 - | -LL | fn issue_1647(mut foo: u8) { - | ^^^ - -error: use of a blacklisted/placeholder name `baz` - --> $DIR/blacklisted_name.rs:33:13 - | -LL | let mut baz = 0; - | ^^^ - -error: use of a blacklisted/placeholder name `quux` - --> $DIR/blacklisted_name.rs:34:21 - | -LL | if let Some(mut quux) = Some(42) {} - | ^^^^ - -error: use of a blacklisted/placeholder name `baz` - --> $DIR/blacklisted_name.rs:38:13 - | -LL | let ref baz = 0; - | ^^^ - -error: use of a blacklisted/placeholder name `quux` - --> $DIR/blacklisted_name.rs:39:21 - | -LL | if let Some(ref quux) = Some(42) {} - | ^^^^ - -error: use of a blacklisted/placeholder name `baz` - --> $DIR/blacklisted_name.rs:43:17 - | -LL | let ref mut baz = 0; - | ^^^ - -error: use of a blacklisted/placeholder name `quux` - --> $DIR/blacklisted_name.rs:44:25 - | -LL | if let Some(ref mut quux) = Some(42) {} - | ^^^^ - -error: aborting due to 14 previous errors - diff --git a/tests/ui/borrow_box.rs b/tests/ui/borrow_box.rs index b606f773cfba..35ed87b0f182 100644 --- a/tests/ui/borrow_box.rs +++ b/tests/ui/borrow_box.rs @@ -1,5 +1,5 @@ #![deny(clippy::borrowed_box)] -#![allow(clippy::blacklisted_name)] +#![allow(clippy::disallowed_names)] #![allow(unused_variables)] #![allow(dead_code)] diff --git a/tests/ui/box_collection.rs b/tests/ui/box_collection.rs index 1a74cdb3ff65..0780c8f0586e 100644 --- a/tests/ui/box_collection.rs +++ b/tests/ui/box_collection.rs @@ -2,7 +2,7 @@ #![allow( clippy::boxed_local, clippy::needless_pass_by_value, - clippy::blacklisted_name, + clippy::disallowed_names, unused )] diff --git a/tests/ui/cast_abs_to_unsigned.fixed b/tests/ui/cast_abs_to_unsigned.fixed index a68b32b097e8..7ecefd7b1343 100644 --- a/tests/ui/cast_abs_to_unsigned.fixed +++ b/tests/ui/cast_abs_to_unsigned.fixed @@ -26,4 +26,6 @@ fn main() { let _ = a.unsigned_abs() as u32; let _ = a.unsigned_abs() as u64; let _ = a.unsigned_abs() as u128; + + let _ = (x as i64 - y as i64).unsigned_abs() as u32; } diff --git a/tests/ui/cast_abs_to_unsigned.rs b/tests/ui/cast_abs_to_unsigned.rs index 110fbc6c2dfb..30c603fca9a1 100644 --- a/tests/ui/cast_abs_to_unsigned.rs +++ b/tests/ui/cast_abs_to_unsigned.rs @@ -26,4 +26,6 @@ fn main() { let _ = a.abs() as u32; let _ = a.abs() as u64; let _ = a.abs() as u128; + + let _ = (x as i64 - y as i64).abs() as u32; } diff --git a/tests/ui/cast_abs_to_unsigned.stderr b/tests/ui/cast_abs_to_unsigned.stderr index 02c24e10659a..045537745267 100644 --- a/tests/ui/cast_abs_to_unsigned.stderr +++ b/tests/ui/cast_abs_to_unsigned.stderr @@ -96,5 +96,11 @@ error: casting the result of `isize::abs()` to u128 LL | let _ = a.abs() as u128; | ^^^^^^^ help: replace with: `a.unsigned_abs()` -error: aborting due to 16 previous errors +error: casting the result of `i64::abs()` to u32 + --> $DIR/cast_abs_to_unsigned.rs:30:13 + | +LL | let _ = (x as i64 - y as i64).abs() as u32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `(x as i64 - y as i64).unsigned_abs()` + +error: aborting due to 17 previous errors diff --git a/tests/ui/clone_on_copy.fixed b/tests/ui/clone_on_copy.fixed index dc062762604e..72b122270981 100644 --- a/tests/ui/clone_on_copy.fixed +++ b/tests/ui/clone_on_copy.fixed @@ -21,7 +21,7 @@ fn is_ascii(ch: char) -> bool { ch.is_ascii() } -fn clone_on_copy() { +fn clone_on_copy() -> Option<(i32)> { 42; vec![1].clone(); // ok, not a Copy type @@ -71,4 +71,9 @@ fn clone_on_copy() { // Issue #5436 let mut vec = Vec::new(); vec.push(42); + + // Issue #9277 + let opt: &Option = &None; + let value = (*opt)?; // operator precedence needed (*opt)? + None } diff --git a/tests/ui/clone_on_copy.rs b/tests/ui/clone_on_copy.rs index 8c39d0d55dd8..03e210ebad98 100644 --- a/tests/ui/clone_on_copy.rs +++ b/tests/ui/clone_on_copy.rs @@ -21,7 +21,7 @@ fn is_ascii(ch: char) -> bool { ch.is_ascii() } -fn clone_on_copy() { +fn clone_on_copy() -> Option<(i32)> { 42.clone(); vec![1].clone(); // ok, not a Copy type @@ -71,4 +71,9 @@ fn clone_on_copy() { // Issue #5436 let mut vec = Vec::new(); vec.push(42.clone()); + + // Issue #9277 + let opt: &Option = &None; + let value = opt.clone()?; // operator precedence needed (*opt)? + None } diff --git a/tests/ui/clone_on_copy.stderr b/tests/ui/clone_on_copy.stderr index 861543d0aa90..42ae227777c7 100644 --- a/tests/ui/clone_on_copy.stderr +++ b/tests/ui/clone_on_copy.stderr @@ -48,5 +48,11 @@ error: using `clone` on type `i32` which implements the `Copy` trait LL | vec.push(42.clone()); | ^^^^^^^^^^ help: try removing the `clone` call: `42` -error: aborting due to 8 previous errors +error: using `clone` on type `std::option::Option` which implements the `Copy` trait + --> $DIR/clone_on_copy.rs:77:17 + | +LL | let value = opt.clone()?; // operator precedence needed (*opt)? + | ^^^^^^^^^^^ help: try dereferencing it: `(*opt)` + +error: aborting due to 9 previous errors diff --git a/tests/ui/crashes/ice-2760.rs b/tests/ui/crashes/ice-2760.rs index f1a229f3f4fa..61ef24804986 100644 --- a/tests/ui/crashes/ice-2760.rs +++ b/tests/ui/crashes/ice-2760.rs @@ -1,6 +1,6 @@ #![allow( unused_variables, - clippy::blacklisted_name, + clippy::disallowed_names, clippy::needless_pass_by_value, dead_code )] diff --git a/tests/ui/crashes/ice-3462.rs b/tests/ui/crashes/ice-3462.rs index 02c49aa0d7c1..b402052882ad 100644 --- a/tests/ui/crashes/ice-3462.rs +++ b/tests/ui/crashes/ice-3462.rs @@ -1,5 +1,5 @@ #![warn(clippy::all)] -#![allow(clippy::blacklisted_name, clippy::equatable_if_let)] +#![allow(clippy::disallowed_names, clippy::equatable_if_let)] #![allow(unused)] /// Test for https://github.com/rust-lang/rust-clippy/issues/3462 diff --git a/tests/ui/crashes/regressions.rs b/tests/ui/crashes/regressions.rs index 6f9d98bbfe7f..55a8b403407c 100644 --- a/tests/ui/crashes/regressions.rs +++ b/tests/ui/crashes/regressions.rs @@ -1,4 +1,4 @@ -#![allow(clippy::blacklisted_name)] +#![allow(clippy::disallowed_names)] pub fn foo(bar: *const u8) { println!("{:#p}", bar); diff --git a/tests/ui/def_id_nocore.rs b/tests/ui/def_id_nocore.rs index 156c88e2e45b..a7da8f89aa3d 100644 --- a/tests/ui/def_id_nocore.rs +++ b/tests/ui/def_id_nocore.rs @@ -1,4 +1,3 @@ -// ignore-windows // ignore-macos #![feature(no_core, lang_items, start)] diff --git a/tests/ui/def_id_nocore.stderr b/tests/ui/def_id_nocore.stderr index 40d355e9a2e3..6210d7c6cfd8 100644 --- a/tests/ui/def_id_nocore.stderr +++ b/tests/ui/def_id_nocore.stderr @@ -1,5 +1,5 @@ error: methods called `as_*` usually take `self` by reference or `self` by mutable reference - --> $DIR/def_id_nocore.rs:28:19 + --> $DIR/def_id_nocore.rs:27:19 | LL | pub fn as_ref(self) -> &'static str { | ^^^^ diff --git a/tests/ui/default_trait_access.fixed b/tests/ui/default_trait_access.fixed index 264dd4efaeb8..fce66eb17596 100644 --- a/tests/ui/default_trait_access.fixed +++ b/tests/ui/default_trait_access.fixed @@ -1,8 +1,12 @@ // run-rustfix +// aux-build: proc_macro_with_span.rs #![allow(unused_imports, dead_code)] #![deny(clippy::default_trait_access)] +extern crate proc_macro_with_span; + +use proc_macro_with_span::with_span; use std::default; use std::default::Default as D2; use std::string; @@ -51,6 +55,8 @@ fn main() { ..Default::default() }; + let _s21: String = with_span!(s Default::default()); + println!( "[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}]", s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s20, diff --git a/tests/ui/default_trait_access.rs b/tests/ui/default_trait_access.rs index a0930fab8e7c..3e8e898b7bc6 100644 --- a/tests/ui/default_trait_access.rs +++ b/tests/ui/default_trait_access.rs @@ -1,8 +1,12 @@ // run-rustfix +// aux-build: proc_macro_with_span.rs #![allow(unused_imports, dead_code)] #![deny(clippy::default_trait_access)] +extern crate proc_macro_with_span; + +use proc_macro_with_span::with_span; use std::default; use std::default::Default as D2; use std::string; @@ -51,6 +55,8 @@ fn main() { ..Default::default() }; + let _s21: String = with_span!(s Default::default()); + println!( "[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}]", s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s20, diff --git a/tests/ui/default_trait_access.stderr b/tests/ui/default_trait_access.stderr index df8a5b94ddcf..3493de37a55b 100644 --- a/tests/ui/default_trait_access.stderr +++ b/tests/ui/default_trait_access.stderr @@ -1,53 +1,53 @@ error: calling `std::string::String::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:11:22 + --> $DIR/default_trait_access.rs:15:22 | LL | let s1: String = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` | note: the lint level is defined here - --> $DIR/default_trait_access.rs:4:9 + --> $DIR/default_trait_access.rs:5:9 | LL | #![deny(clippy::default_trait_access)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: calling `std::string::String::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:15:22 + --> $DIR/default_trait_access.rs:19:22 | LL | let s3: String = D2::default(); | ^^^^^^^^^^^^^ help: try: `std::string::String::default()` error: calling `std::string::String::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:17:22 + --> $DIR/default_trait_access.rs:21:22 | LL | let s4: String = std::default::Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` error: calling `std::string::String::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:21:22 + --> $DIR/default_trait_access.rs:25:22 | LL | let s6: String = default::Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` error: calling `GenericDerivedDefault::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:31:46 + --> $DIR/default_trait_access.rs:35:46 | LL | let s11: GenericDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `GenericDerivedDefault::default()` error: calling `TupleDerivedDefault::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:37:36 + --> $DIR/default_trait_access.rs:41:36 | LL | let s14: TupleDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `TupleDerivedDefault::default()` error: calling `ArrayDerivedDefault::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:39:36 + --> $DIR/default_trait_access.rs:43:36 | LL | let s15: ArrayDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `ArrayDerivedDefault::default()` error: calling `TupleStructDerivedDefault::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:43:42 + --> $DIR/default_trait_access.rs:47:42 | LL | let s17: TupleStructDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `TupleStructDerivedDefault::default()` diff --git a/tests/ui/blacklisted_name.rs b/tests/ui/disallowed_names.rs similarity index 92% rename from tests/ui/blacklisted_name.rs rename to tests/ui/disallowed_names.rs index 27df732a0880..e937c49f3897 100644 --- a/tests/ui/blacklisted_name.rs +++ b/tests/ui/disallowed_names.rs @@ -6,7 +6,7 @@ unused_mut, unused_variables )] -#![warn(clippy::blacklisted_name)] +#![warn(clippy::disallowed_names)] fn test(foo: ()) {} @@ -46,7 +46,7 @@ fn issue_1647_ref_mut() { mod tests { fn issue_7305() { - // `blacklisted_name` lint should not be triggered inside of the test code. + // `disallowed_names` lint should not be triggered inside of the test code. let foo = 0; // Check that even in nested functions warning is still not triggered. diff --git a/tests/ui/disallowed_names.stderr b/tests/ui/disallowed_names.stderr new file mode 100644 index 000000000000..78cb55096ff0 --- /dev/null +++ b/tests/ui/disallowed_names.stderr @@ -0,0 +1,88 @@ +error: use of a disallowed/placeholder name `foo` + --> $DIR/disallowed_names.rs:11:9 + | +LL | fn test(foo: ()) {} + | ^^^ + | + = note: `-D clippy::disallowed-names` implied by `-D warnings` + +error: use of a disallowed/placeholder name `foo` + --> $DIR/disallowed_names.rs:14:9 + | +LL | let foo = 42; + | ^^^ + +error: use of a disallowed/placeholder name `baz` + --> $DIR/disallowed_names.rs:15:9 + | +LL | let baz = 42; + | ^^^ + +error: use of a disallowed/placeholder name `quux` + --> $DIR/disallowed_names.rs:16:9 + | +LL | let quux = 42; + | ^^^^ + +error: use of a disallowed/placeholder name `foo` + --> $DIR/disallowed_names.rs:27:10 + | +LL | (foo, Some(baz), quux @ Some(_)) => (), + | ^^^ + +error: use of a disallowed/placeholder name `baz` + --> $DIR/disallowed_names.rs:27:20 + | +LL | (foo, Some(baz), quux @ Some(_)) => (), + | ^^^ + +error: use of a disallowed/placeholder name `quux` + --> $DIR/disallowed_names.rs:27:26 + | +LL | (foo, Some(baz), quux @ Some(_)) => (), + | ^^^^ + +error: use of a disallowed/placeholder name `foo` + --> $DIR/disallowed_names.rs:32:19 + | +LL | fn issue_1647(mut foo: u8) { + | ^^^ + +error: use of a disallowed/placeholder name `baz` + --> $DIR/disallowed_names.rs:33:13 + | +LL | let mut baz = 0; + | ^^^ + +error: use of a disallowed/placeholder name `quux` + --> $DIR/disallowed_names.rs:34:21 + | +LL | if let Some(mut quux) = Some(42) {} + | ^^^^ + +error: use of a disallowed/placeholder name `baz` + --> $DIR/disallowed_names.rs:38:13 + | +LL | let ref baz = 0; + | ^^^ + +error: use of a disallowed/placeholder name `quux` + --> $DIR/disallowed_names.rs:39:21 + | +LL | if let Some(ref quux) = Some(42) {} + | ^^^^ + +error: use of a disallowed/placeholder name `baz` + --> $DIR/disallowed_names.rs:43:17 + | +LL | let ref mut baz = 0; + | ^^^ + +error: use of a disallowed/placeholder name `quux` + --> $DIR/disallowed_names.rs:44:25 + | +LL | if let Some(ref mut quux) = Some(42) {} + | ^^^^ + +error: aborting due to 14 previous errors + diff --git a/tests/ui/diverging_sub_expression.rs b/tests/ui/diverging_sub_expression.rs index e27f9fea708e..e8f992e6dded 100644 --- a/tests/ui/diverging_sub_expression.rs +++ b/tests/ui/diverging_sub_expression.rs @@ -1,5 +1,5 @@ #![warn(clippy::diverging_sub_expression)] -#![allow(clippy::match_same_arms, clippy::logic_bug)] +#![allow(clippy::match_same_arms, clippy::overly_complex_bool_expr)] #[allow(clippy::empty_loop)] fn diverge() -> ! { loop {} diff --git a/tests/ui/empty_loop_no_std.rs b/tests/ui/empty_loop_no_std.rs index 235e0fc51799..e742b396fcde 100644 --- a/tests/ui/empty_loop_no_std.rs +++ b/tests/ui/empty_loop_no_std.rs @@ -1,6 +1,5 @@ // compile-flags: -Clink-arg=-nostartfiles // ignore-macos -// ignore-windows #![warn(clippy::empty_loop)] #![feature(lang_items, start, libc)] diff --git a/tests/ui/empty_loop_no_std.stderr b/tests/ui/empty_loop_no_std.stderr index 520248fcb689..5ded35a6f0d8 100644 --- a/tests/ui/empty_loop_no_std.stderr +++ b/tests/ui/empty_loop_no_std.stderr @@ -1,5 +1,5 @@ error: empty `loop {}` wastes CPU cycles - --> $DIR/empty_loop_no_std.rs:14:5 + --> $DIR/empty_loop_no_std.rs:13:5 | LL | loop {} | ^^^^^^^ @@ -8,7 +8,7 @@ LL | loop {} = help: you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body error: empty `loop {}` wastes CPU cycles - --> $DIR/empty_loop_no_std.rs:26:5 + --> $DIR/empty_loop_no_std.rs:25:5 | LL | loop {} | ^^^^^^^ diff --git a/tests/ui/expect.stderr b/tests/ui/expect.stderr index 9d3fc7df15cc..ab28aac45563 100644 --- a/tests/ui/expect.stderr +++ b/tests/ui/expect.stderr @@ -5,7 +5,7 @@ LL | let _ = opt.expect(""); | ^^^^^^^^^^^^^^ | = note: `-D clippy::expect-used` implied by `-D warnings` - = help: if this value is an `None`, it will panic + = help: if this value is `None`, it will panic error: used `expect()` on `a Result` value --> $DIR/expect.rs:10:13 diff --git a/tests/ui/expect_tool_lint_rfc_2383.rs b/tests/ui/expect_tool_lint_rfc_2383.rs index 28b37f96e911..0415e33b3fa1 100644 --- a/tests/ui/expect_tool_lint_rfc_2383.rs +++ b/tests/ui/expect_tool_lint_rfc_2383.rs @@ -98,7 +98,7 @@ mod clippy_ok { let _ = if true { 42 } else { 42 }; } - #[expect(clippy::logic_bug)] + #[expect(clippy::overly_complex_bool_expr)] fn burger() { let a = false; let b = true; @@ -127,7 +127,7 @@ mod clippy_warn { let _ = if true { 33 } else { 42 }; } - #[expect(clippy::logic_bug)] + #[expect(clippy::overly_complex_bool_expr)] fn burger() { let a = false; let b = true; diff --git a/tests/ui/expect_tool_lint_rfc_2383.stderr b/tests/ui/expect_tool_lint_rfc_2383.stderr index db29e85a8219..7ce9e855b5e0 100644 --- a/tests/ui/expect_tool_lint_rfc_2383.stderr +++ b/tests/ui/expect_tool_lint_rfc_2383.stderr @@ -33,8 +33,8 @@ LL | #[expect(clippy::if_same_then_else)] error: this lint expectation is unfulfilled --> $DIR/expect_tool_lint_rfc_2383.rs:130:14 | -LL | #[expect(clippy::logic_bug)] - | ^^^^^^^^^^^^^^^^^ +LL | #[expect(clippy::overly_complex_bool_expr)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/tests/ui/explicit_auto_deref.fixed b/tests/ui/explicit_auto_deref.fixed index a650fdc1f897..d1d35e5c0eb4 100644 --- a/tests/ui/explicit_auto_deref.fixed +++ b/tests/ui/explicit_auto_deref.fixed @@ -1,5 +1,6 @@ // run-rustfix +#![feature(closure_lifetime_binder)] #![warn(clippy::explicit_auto_deref)] #![allow( dead_code, @@ -67,6 +68,8 @@ fn main() { let s = String::new(); let _: &str = &s; + let _: &str = &{ String::new() }; + let _: &str = &mut { String::new() }; let _ = &*s; // Don't lint. Inferred type would change. let _: &_ = &*s; // Don't lint. Inferred type would change. @@ -215,4 +218,52 @@ fn main() { let s = &"str"; let _ = || return *s; let _ = || -> &'static str { return s }; + + struct X; + struct Y(X); + impl core::ops::Deref for Y { + type Target = X; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + let _: &X = &*{ Y(X) }; + let _: &X = &*match 0 { + #[rustfmt::skip] + 0 => { Y(X) }, + _ => panic!(), + }; + let _: &X = &*if true { Y(X) } else { panic!() }; + + fn deref_to_u>(x: &T) -> &U { + x + } + + let _ = |x: &'static Box>| -> &'static dyn Iterator { &**x }; + fn ret_any(x: &Box) -> &dyn std::any::Any { + &**x + } + + let x = String::new(); + let _: *const str = &*x; + + struct S7([u32; 1]); + impl core::ops::Deref for S7 { + type Target = [u32; 1]; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + let x = S7([0]); + let _: &[u32] = &*x; + + let c1 = |_: &Vec<&u32>| {}; + let x = &&vec![&1u32]; + c1(x); + let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> { + if b { + return x; + } + x + }; } diff --git a/tests/ui/explicit_auto_deref.rs b/tests/ui/explicit_auto_deref.rs index 8f4f352576a7..deedafad153b 100644 --- a/tests/ui/explicit_auto_deref.rs +++ b/tests/ui/explicit_auto_deref.rs @@ -1,5 +1,6 @@ // run-rustfix +#![feature(closure_lifetime_binder)] #![warn(clippy::explicit_auto_deref)] #![allow( dead_code, @@ -67,6 +68,8 @@ fn main() { let s = String::new(); let _: &str = &*s; + let _: &str = &*{ String::new() }; + let _: &str = &mut *{ String::new() }; let _ = &*s; // Don't lint. Inferred type would change. let _: &_ = &*s; // Don't lint. Inferred type would change. @@ -215,4 +218,52 @@ fn main() { let s = &"str"; let _ = || return *s; let _ = || -> &'static str { return *s }; + + struct X; + struct Y(X); + impl core::ops::Deref for Y { + type Target = X; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + let _: &X = &*{ Y(X) }; + let _: &X = &*match 0 { + #[rustfmt::skip] + 0 => { Y(X) }, + _ => panic!(), + }; + let _: &X = &*if true { Y(X) } else { panic!() }; + + fn deref_to_u>(x: &T) -> &U { + &**x + } + + let _ = |x: &'static Box>| -> &'static dyn Iterator { &**x }; + fn ret_any(x: &Box) -> &dyn std::any::Any { + &**x + } + + let x = String::new(); + let _: *const str = &*x; + + struct S7([u32; 1]); + impl core::ops::Deref for S7 { + type Target = [u32; 1]; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + let x = S7([0]); + let _: &[u32] = &*x; + + let c1 = |_: &Vec<&u32>| {}; + let x = &&vec![&1u32]; + c1(*x); + let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> { + if b { + return *x; + } + *x + }; } diff --git a/tests/ui/explicit_auto_deref.stderr b/tests/ui/explicit_auto_deref.stderr index 92765307ea73..91863abcc5d2 100644 --- a/tests/ui/explicit_auto_deref.stderr +++ b/tests/ui/explicit_auto_deref.stderr @@ -1,202 +1,238 @@ error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:69:20 + --> $DIR/explicit_auto_deref.rs:70:19 | LL | let _: &str = &*s; - | ^^ help: try this: `s` + | ^^^ help: try this: `&s` | = note: `-D clippy::explicit-auto-deref` implied by `-D warnings` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:73:12 + --> $DIR/explicit_auto_deref.rs:71:19 + | +LL | let _: &str = &*{ String::new() }; + | ^^^^^^^^^^^^^^^^^^^ help: try this: `&{ String::new() }` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:72:19 + | +LL | let _: &str = &mut *{ String::new() }; + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut { String::new() }` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:76:11 | LL | f_str(&*s); - | ^^ help: try this: `s` + | ^^^ help: try this: `&s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:77:14 + --> $DIR/explicit_auto_deref.rs:80:13 | LL | f_str_t(&*s, &*s); // Don't lint second param. - | ^^ help: try this: `s` + | ^^^ help: try this: `&s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:80:25 + --> $DIR/explicit_auto_deref.rs:83:24 | LL | let _: &Box = &**b; - | ^^^ help: try this: `b` + | ^^^^ help: try this: `&b` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:86:8 + --> $DIR/explicit_auto_deref.rs:89:7 | LL | c(&*s); - | ^^ help: try this: `s` + | ^^^ help: try this: `&s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:92:9 + --> $DIR/explicit_auto_deref.rs:95:9 | LL | &**x | ^^^^ help: try this: `x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:96:11 + --> $DIR/explicit_auto_deref.rs:99:11 | LL | { &**x } | ^^^^ help: try this: `x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:100:9 + --> $DIR/explicit_auto_deref.rs:103:9 | LL | &**{ x } | ^^^^^^^^ help: try this: `{ x }` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:104:9 + --> $DIR/explicit_auto_deref.rs:107:9 | LL | &***x | ^^^^^ help: try this: `x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:121:13 + --> $DIR/explicit_auto_deref.rs:124:12 | LL | f1(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:122:13 + --> $DIR/explicit_auto_deref.rs:125:12 | LL | f2(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:123:13 + --> $DIR/explicit_auto_deref.rs:126:12 | LL | f3(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:124:28 + --> $DIR/explicit_auto_deref.rs:127:27 | LL | f4.callable_str()(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:125:13 + --> $DIR/explicit_auto_deref.rs:128:12 | LL | f5(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:126:13 + --> $DIR/explicit_auto_deref.rs:129:12 | LL | f6(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:127:28 + --> $DIR/explicit_auto_deref.rs:130:27 | LL | f7.callable_str()(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:128:26 + --> $DIR/explicit_auto_deref.rs:131:25 | LL | f8.callable_t()(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:129:13 + --> $DIR/explicit_auto_deref.rs:132:12 | LL | f9(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:130:14 + --> $DIR/explicit_auto_deref.rs:133:13 | LL | f10(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:131:27 + --> $DIR/explicit_auto_deref.rs:134:26 | LL | f11.callable_t()(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:135:17 + --> $DIR/explicit_auto_deref.rs:138:16 | LL | let _ = S1(&*s); - | ^^ help: try this: `s` + | ^^^ help: try this: `&s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:140:22 + --> $DIR/explicit_auto_deref.rs:143:21 | LL | let _ = S2 { s: &*s }; - | ^^ help: try this: `s` + | ^^^ help: try this: `&s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:156:30 + --> $DIR/explicit_auto_deref.rs:159:30 | LL | let _ = Self::S1(&**s); | ^^^^ help: try this: `s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:157:35 + --> $DIR/explicit_auto_deref.rs:160:35 | LL | let _ = Self::S2 { s: &**s }; | ^^^^ help: try this: `s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:160:21 + --> $DIR/explicit_auto_deref.rs:163:20 | LL | let _ = E1::S1(&*s); - | ^^ help: try this: `s` + | ^^^ help: try this: `&s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:161:26 + --> $DIR/explicit_auto_deref.rs:164:25 | LL | let _ = E1::S2 { s: &*s }; - | ^^ help: try this: `s` + | ^^^ help: try this: `&s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:179:13 + --> $DIR/explicit_auto_deref.rs:182:13 | LL | let _ = (*b).foo; | ^^^^ help: try this: `b` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:180:13 + --> $DIR/explicit_auto_deref.rs:183:13 | LL | let _ = (**b).foo; | ^^^^^ help: try this: `b` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:195:19 + --> $DIR/explicit_auto_deref.rs:198:19 | LL | let _ = f_str(*ref_str); | ^^^^^^^^ help: try this: `ref_str` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:197:19 + --> $DIR/explicit_auto_deref.rs:200:19 | LL | let _ = f_str(**ref_ref_str); | ^^^^^^^^^^^^^ help: try this: `ref_ref_str` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:207:13 + --> $DIR/explicit_auto_deref.rs:210:13 | LL | f_str(&&*ref_str); // `needless_borrow` will suggest removing both references | ^^^^^^^^ help: try this: `ref_str` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:208:12 + --> $DIR/explicit_auto_deref.rs:211:12 | LL | f_str(&&**ref_str); // `needless_borrow` will suggest removing only one reference | ^^^^^^^^^^ help: try this: `ref_str` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:217:41 + --> $DIR/explicit_auto_deref.rs:220:41 | LL | let _ = || -> &'static str { return *s }; | ^^ help: try this: `s` -error: aborting due to 33 previous errors +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:239:9 + | +LL | &**x + | ^^^^ help: try this: `x` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:262:8 + | +LL | c1(*x); + | ^^ help: try this: `x` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:265:20 + | +LL | return *x; + | ^^ help: try this: `x` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:267:9 + | +LL | *x + | ^^ help: try this: `x` + +error: aborting due to 39 previous errors diff --git a/tests/ui/if_same_then_else.rs b/tests/ui/if_same_then_else.rs index 2598c2ab426d..07d2002eb27f 100644 --- a/tests/ui/if_same_then_else.rs +++ b/tests/ui/if_same_then_else.rs @@ -1,6 +1,6 @@ #![warn(clippy::if_same_then_else)] #![allow( - clippy::blacklisted_name, + clippy::disallowed_names, clippy::eq_op, clippy::never_loop, clippy::no_effect, diff --git a/tests/ui/if_same_then_else2.rs b/tests/ui/if_same_then_else2.rs index 0016009a02f5..58167f4446db 100644 --- a/tests/ui/if_same_then_else2.rs +++ b/tests/ui/if_same_then_else2.rs @@ -1,6 +1,6 @@ #![warn(clippy::if_same_then_else)] #![allow( - clippy::blacklisted_name, + clippy::disallowed_names, clippy::collapsible_else_if, clippy::equatable_if_let, clippy::collapsible_if, diff --git a/tests/ui/ifs_same_cond.rs b/tests/ui/ifs_same_cond.rs index 80e9839ff40b..9850fc0919e1 100644 --- a/tests/ui/ifs_same_cond.rs +++ b/tests/ui/ifs_same_cond.rs @@ -32,9 +32,9 @@ fn ifs_same_cond() { }; let mut v = vec![1]; - if v.pop() == None { + if v.pop().is_none() { // ok, functions - } else if v.pop() == None { + } else if v.pop().is_none() { } if v.len() == 42 { diff --git a/tests/ui/iter_skip_next.fixed b/tests/ui/iter_skip_next.fixed index 2db4c2bee7f2..d56d623b5268 100644 --- a/tests/ui/iter_skip_next.fixed +++ b/tests/ui/iter_skip_next.fixed @@ -2,7 +2,7 @@ // aux-build:option_helpers.rs #![warn(clippy::iter_skip_next)] -#![allow(clippy::blacklisted_name)] +#![allow(clippy::disallowed_names)] #![allow(clippy::iter_nth)] #![allow(unused_mut, dead_code)] diff --git a/tests/ui/iter_skip_next.rs b/tests/ui/iter_skip_next.rs index 692edb9aed93..3ec5d1b82142 100644 --- a/tests/ui/iter_skip_next.rs +++ b/tests/ui/iter_skip_next.rs @@ -2,7 +2,7 @@ // aux-build:option_helpers.rs #![warn(clippy::iter_skip_next)] -#![allow(clippy::blacklisted_name)] +#![allow(clippy::disallowed_names)] #![allow(clippy::iter_nth)] #![allow(unused_mut, dead_code)] diff --git a/tests/ui/let_if_seq.rs b/tests/ui/let_if_seq.rs index c5cb2eb1fe1c..959567f68670 100644 --- a/tests/ui/let_if_seq.rs +++ b/tests/ui/let_if_seq.rs @@ -2,7 +2,7 @@ unused_variables, unused_assignments, clippy::similar_names, - clippy::blacklisted_name, + clippy::disallowed_names, clippy::branches_sharing_code, clippy::needless_late_init )] diff --git a/tests/ui/manual_assert.edition2018.fixed b/tests/ui/manual_assert.edition2018.fixed index d0bc640db889..65598f1eaccc 100644 --- a/tests/ui/manual_assert.edition2018.fixed +++ b/tests/ui/manual_assert.edition2018.fixed @@ -17,7 +17,7 @@ fn main() { let c = Some(2); if !a.is_empty() && a.len() == 3 - && c != None + && c.is_some() && !a.is_empty() && a.len() == 3 && !a.is_empty() diff --git a/tests/ui/manual_assert.edition2021.fixed b/tests/ui/manual_assert.edition2021.fixed index d0bc640db889..65598f1eaccc 100644 --- a/tests/ui/manual_assert.edition2021.fixed +++ b/tests/ui/manual_assert.edition2021.fixed @@ -17,7 +17,7 @@ fn main() { let c = Some(2); if !a.is_empty() && a.len() == 3 - && c != None + && c.is_some() && !a.is_empty() && a.len() == 3 && !a.is_empty() diff --git a/tests/ui/manual_assert.fixed b/tests/ui/manual_assert.fixed index 6c2a25c37d8d..a2393674fe61 100644 --- a/tests/ui/manual_assert.fixed +++ b/tests/ui/manual_assert.fixed @@ -11,7 +11,7 @@ fn main() { let c = Some(2); if !a.is_empty() && a.len() == 3 - && c != None + && c.is_some() && !a.is_empty() && a.len() == 3 && !a.is_empty() diff --git a/tests/ui/manual_assert.rs b/tests/ui/manual_assert.rs index 027747d83863..4d2706dd6211 100644 --- a/tests/ui/manual_assert.rs +++ b/tests/ui/manual_assert.rs @@ -17,7 +17,7 @@ fn main() { let c = Some(2); if !a.is_empty() && a.len() == 3 - && c != None + && c.is_some() && !a.is_empty() && a.len() == 3 && !a.is_empty() diff --git a/tests/ui/manual_instant_elapsed.fixed b/tests/ui/manual_instant_elapsed.fixed new file mode 100644 index 000000000000..0fa776b7b2e4 --- /dev/null +++ b/tests/ui/manual_instant_elapsed.fixed @@ -0,0 +1,27 @@ +// run-rustfix +#![warn(clippy::manual_instant_elapsed)] +#![allow(clippy::unnecessary_operation)] +#![allow(unused_variables)] +#![allow(unused_must_use)] + +use std::time::Instant; + +fn main() { + let prev_instant = Instant::now(); + + { + // don't influence + let another_instant = Instant::now(); + } + + let duration = prev_instant.elapsed(); + + // don't catch + let duration = prev_instant.elapsed(); + + Instant::now() - duration; + + let ref_to_instant = &Instant::now(); + + (*ref_to_instant).elapsed(); // to ensure parens are added correctly +} diff --git a/tests/ui/manual_instant_elapsed.rs b/tests/ui/manual_instant_elapsed.rs new file mode 100644 index 000000000000..5b11b84535dd --- /dev/null +++ b/tests/ui/manual_instant_elapsed.rs @@ -0,0 +1,27 @@ +// run-rustfix +#![warn(clippy::manual_instant_elapsed)] +#![allow(clippy::unnecessary_operation)] +#![allow(unused_variables)] +#![allow(unused_must_use)] + +use std::time::Instant; + +fn main() { + let prev_instant = Instant::now(); + + { + // don't influence + let another_instant = Instant::now(); + } + + let duration = Instant::now() - prev_instant; + + // don't catch + let duration = prev_instant.elapsed(); + + Instant::now() - duration; + + let ref_to_instant = &Instant::now(); + + Instant::now() - *ref_to_instant; // to ensure parens are added correctly +} diff --git a/tests/ui/manual_instant_elapsed.stderr b/tests/ui/manual_instant_elapsed.stderr new file mode 100644 index 000000000000..5537f5642a23 --- /dev/null +++ b/tests/ui/manual_instant_elapsed.stderr @@ -0,0 +1,16 @@ +error: manual implementation of `Instant::elapsed` + --> $DIR/manual_instant_elapsed.rs:17:20 + | +LL | let duration = Instant::now() - prev_instant; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `prev_instant.elapsed()` + | + = note: `-D clippy::manual-instant-elapsed` implied by `-D warnings` + +error: manual implementation of `Instant::elapsed` + --> $DIR/manual_instant_elapsed.rs:26:5 + | +LL | Instant::now() - *ref_to_instant; // to ensure parens are added correctly + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*ref_to_instant).elapsed()` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/manual_ok_or.fixed b/tests/ui/manual_ok_or.fixed index 887a97d7a017..d864f8554534 100644 --- a/tests/ui/manual_ok_or.fixed +++ b/tests/ui/manual_ok_or.fixed @@ -1,6 +1,6 @@ // run-rustfix #![warn(clippy::manual_ok_or)] -#![allow(clippy::blacklisted_name)] +#![allow(clippy::disallowed_names)] #![allow(clippy::redundant_closure)] #![allow(dead_code)] #![allow(unused_must_use)] diff --git a/tests/ui/manual_ok_or.rs b/tests/ui/manual_ok_or.rs index 3c99872f5022..6264768460ef 100644 --- a/tests/ui/manual_ok_or.rs +++ b/tests/ui/manual_ok_or.rs @@ -1,6 +1,6 @@ // run-rustfix #![warn(clippy::manual_ok_or)] -#![allow(clippy::blacklisted_name)] +#![allow(clippy::disallowed_names)] #![allow(clippy::redundant_closure)] #![allow(dead_code)] #![allow(unused_must_use)] diff --git a/tests/ui/match_same_arms2.rs b/tests/ui/match_same_arms2.rs index 7aba5b447d55..61793e80c98d 100644 --- a/tests/ui/match_same_arms2.rs +++ b/tests/ui/match_same_arms2.rs @@ -1,5 +1,5 @@ #![warn(clippy::match_same_arms)] -#![allow(clippy::blacklisted_name, clippy::diverging_sub_expression)] +#![allow(clippy::disallowed_names, clippy::diverging_sub_expression)] fn bar(_: T) {} fn foo() -> bool { diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index 1970c2eae531..6f22366eab29 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -2,7 +2,7 @@ #![warn(clippy::all, clippy::pedantic)] #![allow( - clippy::blacklisted_name, + clippy::disallowed_names, clippy::default_trait_access, clippy::missing_docs_in_private_items, clippy::missing_safety_doc, diff --git a/tests/ui/mismatching_type_param_order.rs b/tests/ui/mismatching_type_param_order.rs index 8c0da84d8e97..40c1fcae1fd3 100644 --- a/tests/ui/mismatching_type_param_order.rs +++ b/tests/ui/mismatching_type_param_order.rs @@ -1,5 +1,5 @@ #![warn(clippy::mismatching_type_param_order)] -#![allow(clippy::blacklisted_name)] +#![allow(clippy::disallowed_names)] fn main() { struct Foo { diff --git a/tests/ui/missing_const_for_fn/cant_be_const.rs b/tests/ui/missing_const_for_fn/cant_be_const.rs index aa60d0504e5e..b950248ef942 100644 --- a/tests/ui/missing_const_for_fn/cant_be_const.rs +++ b/tests/ui/missing_const_for_fn/cant_be_const.rs @@ -3,12 +3,16 @@ //! The .stderr output of this test should be empty. Otherwise it's a bug somewhere. // aux-build:helper.rs +// aux-build:../../auxiliary/proc_macro_with_span.rs #![warn(clippy::missing_const_for_fn)] #![feature(start)] #![feature(custom_inner_attributes)] extern crate helper; +extern crate proc_macro_with_span; + +use proc_macro_with_span::with_span; struct Game; @@ -119,3 +123,8 @@ mod const_fn_stabilized_after_msrv { byte.is_ascii_digit(); } } + +with_span! { + span + fn dont_check_in_proc_macro() {} +} diff --git a/tests/ui/missing-doc.rs b/tests/ui/missing_doc.rs similarity index 82% rename from tests/ui/missing-doc.rs rename to tests/ui/missing_doc.rs index 6e2e710e21c8..29cc026a8fd3 100644 --- a/tests/ui/missing-doc.rs +++ b/tests/ui/missing_doc.rs @@ -1,3 +1,5 @@ +// aux-build: proc_macro_with_span.rs + #![warn(clippy::missing_docs_in_private_items)] // When denying at the crate level, be sure to not get random warnings from the // injected intrinsics by the compiler. @@ -5,6 +7,9 @@ //! Some garbage docs for the crate here #![doc = "More garbage"] +extern crate proc_macro_with_span; + +use proc_macro_with_span::with_span; use std::arch::global_asm; type Typedef = String; @@ -100,3 +105,11 @@ fn main() {} // Ensure global asm doesn't require documentation. global_asm! { "" } + +// Don't lint proc macro output with an unexpected span. +with_span!(span pub struct FooPm { pub field: u32}); +with_span!(span pub struct FooPm2;); +with_span!(span pub enum FooPm3 { A, B(u32), C { field: u32 }}); +with_span!(span pub fn foo_pm() {}); +with_span!(span pub static FOO_PM: u32 = 0;); +with_span!(span pub const FOO2_PM: u32 = 0;); diff --git a/tests/ui/missing-doc.stderr b/tests/ui/missing_doc.stderr similarity index 79% rename from tests/ui/missing-doc.stderr rename to tests/ui/missing_doc.stderr index a876dc078ebf..6c8e66f46437 100644 --- a/tests/ui/missing-doc.stderr +++ b/tests/ui/missing_doc.stderr @@ -1,5 +1,5 @@ error: missing documentation for a type alias - --> $DIR/missing-doc.rs:10:1 + --> $DIR/missing_doc.rs:15:1 | LL | type Typedef = String; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -7,37 +7,37 @@ LL | type Typedef = String; = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings` error: missing documentation for a type alias - --> $DIR/missing-doc.rs:11:1 + --> $DIR/missing_doc.rs:16:1 | LL | pub type PubTypedef = String; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a module - --> $DIR/missing-doc.rs:13:1 + --> $DIR/missing_doc.rs:18:1 | LL | mod module_no_dox {} | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a module - --> $DIR/missing-doc.rs:14:1 + --> $DIR/missing_doc.rs:19:1 | LL | pub mod pub_module_no_dox {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:18:1 + --> $DIR/missing_doc.rs:23:1 | LL | pub fn foo2() {} | ^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:19:1 + --> $DIR/missing_doc.rs:24:1 | LL | fn foo3() {} | ^^^^^^^^^^^^ error: missing documentation for an enum - --> $DIR/missing-doc.rs:33:1 + --> $DIR/missing_doc.rs:38:1 | LL | / enum Baz { LL | | BazA { a: isize, b: isize }, @@ -46,31 +46,31 @@ LL | | } | |_^ error: missing documentation for a variant - --> $DIR/missing-doc.rs:34:5 + --> $DIR/missing_doc.rs:39:5 | LL | BazA { a: isize, b: isize }, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a struct field - --> $DIR/missing-doc.rs:34:12 + --> $DIR/missing_doc.rs:39:12 | LL | BazA { a: isize, b: isize }, | ^^^^^^^^ error: missing documentation for a struct field - --> $DIR/missing-doc.rs:34:22 + --> $DIR/missing_doc.rs:39:22 | LL | BazA { a: isize, b: isize }, | ^^^^^^^^ error: missing documentation for a variant - --> $DIR/missing-doc.rs:35:5 + --> $DIR/missing_doc.rs:40:5 | LL | BarB, | ^^^^ error: missing documentation for an enum - --> $DIR/missing-doc.rs:38:1 + --> $DIR/missing_doc.rs:43:1 | LL | / pub enum PubBaz { LL | | PubBazA { a: isize }, @@ -78,43 +78,43 @@ LL | | } | |_^ error: missing documentation for a variant - --> $DIR/missing-doc.rs:39:5 + --> $DIR/missing_doc.rs:44:5 | LL | PubBazA { a: isize }, | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a struct field - --> $DIR/missing-doc.rs:39:15 + --> $DIR/missing_doc.rs:44:15 | LL | PubBazA { a: isize }, | ^^^^^^^^ error: missing documentation for a constant - --> $DIR/missing-doc.rs:59:1 + --> $DIR/missing_doc.rs:64:1 | LL | const FOO: u32 = 0; | ^^^^^^^^^^^^^^^^^^^ error: missing documentation for a constant - --> $DIR/missing-doc.rs:66:1 + --> $DIR/missing_doc.rs:71:1 | LL | pub const FOO4: u32 = 0; | ^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a static - --> $DIR/missing-doc.rs:68:1 + --> $DIR/missing_doc.rs:73:1 | LL | static BAR: u32 = 0; | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a static - --> $DIR/missing-doc.rs:75:1 + --> $DIR/missing_doc.rs:80:1 | LL | pub static BAR4: u32 = 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a module - --> $DIR/missing-doc.rs:77:1 + --> $DIR/missing_doc.rs:82:1 | LL | / mod internal_impl { LL | | /// dox @@ -126,31 +126,31 @@ LL | | } | |_^ error: missing documentation for a function - --> $DIR/missing-doc.rs:80:5 + --> $DIR/missing_doc.rs:85:5 | LL | pub fn undocumented1() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:81:5 + --> $DIR/missing_doc.rs:86:5 | LL | pub fn undocumented2() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:82:5 + --> $DIR/missing_doc.rs:87:5 | LL | fn undocumented3() {} | ^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:87:9 + --> $DIR/missing_doc.rs:92:9 | LL | pub fn also_undocumented1() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:88:9 + --> $DIR/missing_doc.rs:93:9 | LL | fn also_undocumented2() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/missing-doc-crate.rs b/tests/ui/missing_doc_crate.rs similarity index 100% rename from tests/ui/missing-doc-crate.rs rename to tests/ui/missing_doc_crate.rs diff --git a/tests/ui/missing-doc-crate-missing.rs b/tests/ui/missing_doc_crate_missing.rs similarity index 100% rename from tests/ui/missing-doc-crate-missing.rs rename to tests/ui/missing_doc_crate_missing.rs diff --git a/tests/ui/missing-doc-crate-missing.stderr b/tests/ui/missing_doc_crate_missing.stderr similarity index 86% rename from tests/ui/missing-doc-crate-missing.stderr rename to tests/ui/missing_doc_crate_missing.stderr index d56c5cc4c3ae..19516bf5fab0 100644 --- a/tests/ui/missing-doc-crate-missing.stderr +++ b/tests/ui/missing_doc_crate_missing.stderr @@ -1,5 +1,5 @@ error: missing documentation for the crate - --> $DIR/missing-doc-crate-missing.rs:1:1 + --> $DIR/missing_doc_crate_missing.rs:1:1 | LL | / #![warn(clippy::missing_docs_in_private_items)] LL | | diff --git a/tests/ui/missing-doc-impl.rs b/tests/ui/missing_doc_impl.rs similarity index 83% rename from tests/ui/missing-doc-impl.rs rename to tests/ui/missing_doc_impl.rs index d5724bf661c6..0396d1193ff5 100644 --- a/tests/ui/missing-doc-impl.rs +++ b/tests/ui/missing_doc_impl.rs @@ -1,3 +1,5 @@ +// aux-build: proc_macro_with_span.rs + #![warn(clippy::missing_docs_in_private_items)] #![allow(dead_code)] #![feature(associated_type_defaults)] @@ -5,6 +7,9 @@ //! Some garbage docs for the crate here #![doc = "More garbage"] +extern crate proc_macro_with_span; +use proc_macro_with_span::with_span; + struct Foo { a: isize, b: isize, @@ -90,3 +95,13 @@ impl F for Foo { } fn main() {} + +// don't lint proc macro output +with_span!(span + pub struct FooPm; + impl FooPm { + pub fn foo() {} + pub const fn bar() {} + pub const X: u32 = 0; + } +); diff --git a/tests/ui/missing-doc-impl.stderr b/tests/ui/missing_doc_impl.stderr similarity index 78% rename from tests/ui/missing-doc-impl.stderr rename to tests/ui/missing_doc_impl.stderr index bda63d66a174..f22fa19dbcab 100644 --- a/tests/ui/missing-doc-impl.stderr +++ b/tests/ui/missing_doc_impl.stderr @@ -1,5 +1,5 @@ error: missing documentation for a struct - --> $DIR/missing-doc-impl.rs:8:1 + --> $DIR/missing_doc_impl.rs:13:1 | LL | / struct Foo { LL | | a: isize, @@ -10,19 +10,19 @@ LL | | } = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings` error: missing documentation for a struct field - --> $DIR/missing-doc-impl.rs:9:5 + --> $DIR/missing_doc_impl.rs:14:5 | LL | a: isize, | ^^^^^^^^ error: missing documentation for a struct field - --> $DIR/missing-doc-impl.rs:10:5 + --> $DIR/missing_doc_impl.rs:15:5 | LL | b: isize, | ^^^^^^^^ error: missing documentation for a struct - --> $DIR/missing-doc-impl.rs:13:1 + --> $DIR/missing_doc_impl.rs:18:1 | LL | / pub struct PubFoo { LL | | pub a: isize, @@ -31,19 +31,19 @@ LL | | } | |_^ error: missing documentation for a struct field - --> $DIR/missing-doc-impl.rs:14:5 + --> $DIR/missing_doc_impl.rs:19:5 | LL | pub a: isize, | ^^^^^^^^^^^^ error: missing documentation for a struct field - --> $DIR/missing-doc-impl.rs:15:5 + --> $DIR/missing_doc_impl.rs:20:5 | LL | b: isize, | ^^^^^^^^ error: missing documentation for a trait - --> $DIR/missing-doc-impl.rs:38:1 + --> $DIR/missing_doc_impl.rs:43:1 | LL | / pub trait C { LL | | fn foo(&self); @@ -52,31 +52,31 @@ LL | | } | |_^ error: missing documentation for an associated function - --> $DIR/missing-doc-impl.rs:39:5 + --> $DIR/missing_doc_impl.rs:44:5 | LL | fn foo(&self); | ^^^^^^^^^^^^^^ error: missing documentation for an associated function - --> $DIR/missing-doc-impl.rs:40:5 + --> $DIR/missing_doc_impl.rs:45:5 | LL | fn foo_with_impl(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for an associated type - --> $DIR/missing-doc-impl.rs:50:5 + --> $DIR/missing_doc_impl.rs:55:5 | LL | type AssociatedType; | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for an associated type - --> $DIR/missing-doc-impl.rs:51:5 + --> $DIR/missing_doc_impl.rs:56:5 | LL | type AssociatedTypeDef = Self; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for an associated function - --> $DIR/missing-doc-impl.rs:62:5 + --> $DIR/missing_doc_impl.rs:67:5 | LL | / pub fn new() -> Self { LL | | Foo { a: 0, b: 0 } @@ -84,19 +84,19 @@ LL | | } | |_____^ error: missing documentation for an associated function - --> $DIR/missing-doc-impl.rs:65:5 + --> $DIR/missing_doc_impl.rs:70:5 | LL | fn bar() {} | ^^^^^^^^^^^ error: missing documentation for an associated function - --> $DIR/missing-doc-impl.rs:69:5 + --> $DIR/missing_doc_impl.rs:74:5 | LL | pub fn foo() {} | ^^^^^^^^^^^^^^^ error: missing documentation for an associated function - --> $DIR/missing-doc-impl.rs:73:5 + --> $DIR/missing_doc_impl.rs:78:5 | LL | / fn foo2() -> u32 { LL | | 1 diff --git a/tests/ui/mistyped_literal_suffix.fixed b/tests/ui/mistyped_literal_suffix.fixed index a7b36d53cd26..becb9562a849 100644 --- a/tests/ui/mistyped_literal_suffix.fixed +++ b/tests/ui/mistyped_literal_suffix.fixed @@ -1,4 +1,5 @@ // run-rustfix +// aux-build: proc_macro_with_span.rs #![allow( dead_code, @@ -9,6 +10,9 @@ clippy::unusual_byte_groupings )] +extern crate proc_macro_with_span; +use proc_macro_with_span::with_span; + fn main() { let fail14 = 2_i32; let fail15 = 4_i64; @@ -40,4 +44,6 @@ fn main() { let ok38 = 124_64.0; let _ = 1.123_45E1_f32; + + let _ = with_span!(1 2_u32); } diff --git a/tests/ui/mistyped_literal_suffix.rs b/tests/ui/mistyped_literal_suffix.rs index c97b31965c75..ee841bcd7e4e 100644 --- a/tests/ui/mistyped_literal_suffix.rs +++ b/tests/ui/mistyped_literal_suffix.rs @@ -1,4 +1,5 @@ // run-rustfix +// aux-build: proc_macro_with_span.rs #![allow( dead_code, @@ -9,6 +10,9 @@ clippy::unusual_byte_groupings )] +extern crate proc_macro_with_span; +use proc_macro_with_span::with_span; + fn main() { let fail14 = 2_32; let fail15 = 4_64; @@ -40,4 +44,6 @@ fn main() { let ok38 = 124_64.0; let _ = 1.12345E1_32; + + let _ = with_span!(1 2_u32); } diff --git a/tests/ui/mistyped_literal_suffix.stderr b/tests/ui/mistyped_literal_suffix.stderr index fb761d9bde45..ef8e6a33d28f 100644 --- a/tests/ui/mistyped_literal_suffix.stderr +++ b/tests/ui/mistyped_literal_suffix.stderr @@ -1,5 +1,5 @@ error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:13:18 + --> $DIR/mistyped_literal_suffix.rs:17:18 | LL | let fail14 = 2_32; | ^^^^ help: did you mean to write: `2_i32` @@ -7,91 +7,91 @@ LL | let fail14 = 2_32; = note: `#[deny(clippy::mistyped_literal_suffixes)]` on by default error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:14:18 + --> $DIR/mistyped_literal_suffix.rs:18:18 | LL | let fail15 = 4_64; | ^^^^ help: did you mean to write: `4_i64` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:15:18 + --> $DIR/mistyped_literal_suffix.rs:19:18 | LL | let fail16 = 7_8; // | ^^^ help: did you mean to write: `7_i8` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:16:18 + --> $DIR/mistyped_literal_suffix.rs:20:18 | LL | let fail17 = 23_16; // | ^^^^^ help: did you mean to write: `23_i16` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:19:18 + --> $DIR/mistyped_literal_suffix.rs:23:18 | LL | let fail20 = 2__8; // | ^^^^ help: did you mean to write: `2_i8` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:20:18 + --> $DIR/mistyped_literal_suffix.rs:24:18 | LL | let fail21 = 4___16; // | ^^^^^^ help: did you mean to write: `4_i16` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:23:18 + --> $DIR/mistyped_literal_suffix.rs:27:18 | LL | let fail25 = 1E2_32; | ^^^^^^ help: did you mean to write: `1E2_f32` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:24:18 + --> $DIR/mistyped_literal_suffix.rs:28:18 | LL | let fail26 = 43E7_64; | ^^^^^^^ help: did you mean to write: `43E7_f64` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:25:18 + --> $DIR/mistyped_literal_suffix.rs:29:18 | LL | let fail27 = 243E17_32; | ^^^^^^^^^ help: did you mean to write: `243E17_f32` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:26:18 + --> $DIR/mistyped_literal_suffix.rs:30:18 | LL | let fail28 = 241251235E723_64; | ^^^^^^^^^^^^^^^^ help: did you mean to write: `241_251_235E723_f64` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:30:18 + --> $DIR/mistyped_literal_suffix.rs:34:18 | LL | let fail30 = 127_8; // should be i8 | ^^^^^ help: did you mean to write: `127_i8` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:31:18 + --> $DIR/mistyped_literal_suffix.rs:35:18 | LL | let fail31 = 240_8; // should be u8 | ^^^^^ help: did you mean to write: `240_u8` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:33:18 + --> $DIR/mistyped_literal_suffix.rs:37:18 | LL | let fail33 = 0x1234_16; | ^^^^^^^^^ help: did you mean to write: `0x1234_i16` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:34:18 + --> $DIR/mistyped_literal_suffix.rs:38:18 | LL | let fail34 = 0xABCD_16; | ^^^^^^^^^ help: did you mean to write: `0xABCD_u16` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:36:18 + --> $DIR/mistyped_literal_suffix.rs:40:18 | LL | let fail36 = 0xFFFF_FFFF_FFFF_FFFF_64; // u64 | ^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to write: `0xFFFF_FFFF_FFFF_FFFF_u64` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:42:13 + --> $DIR/mistyped_literal_suffix.rs:46:13 | LL | let _ = 1.12345E1_32; | ^^^^^^^^^^^^ help: did you mean to write: `1.123_45E1_f32` diff --git a/tests/ui/mixed_read_write_in_expression.rs b/tests/ui/mixed_read_write_in_expression.rs index 7640057ab6e3..6efc7657ec0c 100644 --- a/tests/ui/mixed_read_write_in_expression.rs +++ b/tests/ui/mixed_read_write_in_expression.rs @@ -4,7 +4,7 @@ unused_variables, clippy::no_effect, dead_code, - clippy::blacklisted_name + clippy::disallowed_names )] fn main() { let mut x = 0; diff --git a/tests/ui/op_ref.rs b/tests/ui/op_ref.rs index d8bf66603d9f..07226b0a1a83 100644 --- a/tests/ui/op_ref.rs +++ b/tests/ui/op_ref.rs @@ -1,4 +1,4 @@ -#![allow(unused_variables, clippy::blacklisted_name)] +#![allow(unused_variables, clippy::disallowed_names)] #![warn(clippy::op_ref)] use std::collections::HashSet; use std::ops::{BitAnd, Mul}; diff --git a/tests/ui/logic_bug.rs b/tests/ui/overly_complex_bool_expr.rs similarity index 90% rename from tests/ui/logic_bug.rs rename to tests/ui/overly_complex_bool_expr.rs index dd6b1db5f70a..04a30a83250e 100644 --- a/tests/ui/logic_bug.rs +++ b/tests/ui/overly_complex_bool_expr.rs @@ -1,6 +1,6 @@ #![feature(lint_reasons)] #![allow(unused, clippy::diverging_sub_expression)] -#![warn(clippy::logic_bug)] +#![warn(clippy::overly_complex_bool_expr)] fn main() { let a: bool = unimplemented!(); @@ -29,6 +29,6 @@ fn equality_stuff() { fn check_expect() { let a: i32 = unimplemented!(); let b: i32 = unimplemented!(); - #[expect(clippy::logic_bug)] + #[expect(clippy::overly_complex_bool_expr)] let _ = a < b && a >= b; } diff --git a/tests/ui/logic_bug.stderr b/tests/ui/overly_complex_bool_expr.stderr similarity index 76% rename from tests/ui/logic_bug.stderr rename to tests/ui/overly_complex_bool_expr.stderr index 4021fbf45705..158cae8b8f37 100644 --- a/tests/ui/logic_bug.stderr +++ b/tests/ui/overly_complex_bool_expr.stderr @@ -1,60 +1,60 @@ error: this boolean expression contains a logic bug - --> $DIR/logic_bug.rs:11:13 + --> $DIR/overly_complex_bool_expr.rs:11:13 | LL | let _ = a && b || a; | ^^^^^^^^^^^ help: it would look like the following: `a` | - = note: `-D clippy::logic-bug` implied by `-D warnings` + = note: `-D clippy::overly-complex-bool-expr` implied by `-D warnings` help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/logic_bug.rs:11:18 + --> $DIR/overly_complex_bool_expr.rs:11:18 | LL | let _ = a && b || a; | ^ error: this boolean expression contains a logic bug - --> $DIR/logic_bug.rs:13:13 + --> $DIR/overly_complex_bool_expr.rs:13:13 | LL | let _ = false && a; | ^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/logic_bug.rs:13:22 + --> $DIR/overly_complex_bool_expr.rs:13:22 | LL | let _ = false && a; | ^ error: this boolean expression contains a logic bug - --> $DIR/logic_bug.rs:23:13 + --> $DIR/overly_complex_bool_expr.rs:23:13 | LL | let _ = a == b && a != b; | ^^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/logic_bug.rs:23:13 + --> $DIR/overly_complex_bool_expr.rs:23:13 | LL | let _ = a == b && a != b; | ^^^^^^ error: this boolean expression contains a logic bug - --> $DIR/logic_bug.rs:24:13 + --> $DIR/overly_complex_bool_expr.rs:24:13 | LL | let _ = a < b && a >= b; | ^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/logic_bug.rs:24:13 + --> $DIR/overly_complex_bool_expr.rs:24:13 | LL | let _ = a < b && a >= b; | ^^^^^ error: this boolean expression contains a logic bug - --> $DIR/logic_bug.rs:25:13 + --> $DIR/overly_complex_bool_expr.rs:25:13 | LL | let _ = a > b && a <= b; | ^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/logic_bug.rs:25:13 + --> $DIR/overly_complex_bool_expr.rs:25:13 | LL | let _ = a > b && a <= b; | ^^^^^ diff --git a/tests/ui/partialeq_to_none.fixed b/tests/ui/partialeq_to_none.fixed new file mode 100644 index 000000000000..f3e4c58d6949 --- /dev/null +++ b/tests/ui/partialeq_to_none.fixed @@ -0,0 +1,62 @@ +// run-rustfix +#![warn(clippy::partialeq_to_none)] + +struct Foobar; + +impl PartialEq> for Foobar { + fn eq(&self, _: &Option<()>) -> bool { + false + } +} + +#[allow(dead_code)] +fn foo(f: Option) -> &'static str { + if f.is_some() { "yay" } else { "nay" } +} + +fn foobar() -> Option<()> { + None +} + +fn bar() -> Result<(), ()> { + Ok(()) +} + +fn optref() -> &'static &'static Option<()> { + &&None +} + +fn main() { + let x = Some(0); + + let _ = x.is_none(); + let _ = x.is_some(); + let _ = x.is_none(); + let _ = x.is_some(); + + if foobar().is_none() {} + + if bar().ok().is_some() {} + + let _ = Some(1 + 2).is_some(); + + let _ = { Some(0) }.is_none(); + + let _ = { + /* + This comment runs long + */ + Some(1) + }.is_some(); + + // Should not trigger, as `Foobar` is not an `Option` and has no `is_none` + let _ = Foobar == None; + + let _ = optref().is_none(); + let _ = optref().is_some(); + let _ = optref().is_none(); + let _ = optref().is_some(); + + let x = Box::new(Option::<()>::None); + let _ = (*x).is_some(); +} diff --git a/tests/ui/partialeq_to_none.rs b/tests/ui/partialeq_to_none.rs new file mode 100644 index 000000000000..767b2a38bcc1 --- /dev/null +++ b/tests/ui/partialeq_to_none.rs @@ -0,0 +1,62 @@ +// run-rustfix +#![warn(clippy::partialeq_to_none)] + +struct Foobar; + +impl PartialEq> for Foobar { + fn eq(&self, _: &Option<()>) -> bool { + false + } +} + +#[allow(dead_code)] +fn foo(f: Option) -> &'static str { + if f != None { "yay" } else { "nay" } +} + +fn foobar() -> Option<()> { + None +} + +fn bar() -> Result<(), ()> { + Ok(()) +} + +fn optref() -> &'static &'static Option<()> { + &&None +} + +fn main() { + let x = Some(0); + + let _ = x == None; + let _ = x != None; + let _ = None == x; + let _ = None != x; + + if foobar() == None {} + + if bar().ok() != None {} + + let _ = Some(1 + 2) != None; + + let _ = { Some(0) } == None; + + let _ = { + /* + This comment runs long + */ + Some(1) + } != None; + + // Should not trigger, as `Foobar` is not an `Option` and has no `is_none` + let _ = Foobar == None; + + let _ = optref() == &&None; + let _ = &&None != optref(); + let _ = **optref() == None; + let _ = &None != *optref(); + + let x = Box::new(Option::<()>::None); + let _ = None != *x; +} diff --git a/tests/ui/partialeq_to_none.stderr b/tests/ui/partialeq_to_none.stderr new file mode 100644 index 000000000000..de15a9f7baaf --- /dev/null +++ b/tests/ui/partialeq_to_none.stderr @@ -0,0 +1,110 @@ +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:14:8 + | +LL | if f != None { "yay" } else { "nay" } + | ^^^^^^^^^ help: use `Option::is_some()` instead: `f.is_some()` + | + = note: `-D clippy::partialeq-to-none` implied by `-D warnings` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:32:13 + | +LL | let _ = x == None; + | ^^^^^^^^^ help: use `Option::is_none()` instead: `x.is_none()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:33:13 + | +LL | let _ = x != None; + | ^^^^^^^^^ help: use `Option::is_some()` instead: `x.is_some()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:34:13 + | +LL | let _ = None == x; + | ^^^^^^^^^ help: use `Option::is_none()` instead: `x.is_none()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:35:13 + | +LL | let _ = None != x; + | ^^^^^^^^^ help: use `Option::is_some()` instead: `x.is_some()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:37:8 + | +LL | if foobar() == None {} + | ^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `foobar().is_none()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:39:8 + | +LL | if bar().ok() != None {} + | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `bar().ok().is_some()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:41:13 + | +LL | let _ = Some(1 + 2) != None; + | ^^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `Some(1 + 2).is_some()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:43:13 + | +LL | let _ = { Some(0) } == None; + | ^^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `{ Some(0) }.is_none()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:45:13 + | +LL | let _ = { + | _____________^ +LL | | /* +LL | | This comment runs long +LL | | */ +LL | | Some(1) +LL | | } != None; + | |_____________^ + | +help: use `Option::is_some()` instead + | +LL ~ let _ = { +LL + /* +LL + This comment runs long +LL + */ +LL + Some(1) +LL ~ }.is_some(); + | + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:55:13 + | +LL | let _ = optref() == &&None; + | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `optref().is_none()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:56:13 + | +LL | let _ = &&None != optref(); + | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `optref().is_some()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:57:13 + | +LL | let _ = **optref() == None; + | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `optref().is_none()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:58:13 + | +LL | let _ = &None != *optref(); + | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `optref().is_some()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:61:13 + | +LL | let _ = None != *x; + | ^^^^^^^^^^ help: use `Option::is_some()` instead: `(*x).is_some()` + +error: aborting due to 15 previous errors + diff --git a/tests/ui/rc_mutex.rs b/tests/ui/rc_mutex.rs index 18e8a2e01e02..432972bbc317 100644 --- a/tests/ui/rc_mutex.rs +++ b/tests/ui/rc_mutex.rs @@ -1,5 +1,5 @@ #![warn(clippy::rc_mutex)] -#![allow(unused, clippy::blacklisted_name)] +#![allow(unused, clippy::disallowed_names)] use std::rc::Rc; use std::sync::Mutex; diff --git a/tests/ui/redundant_allocation.rs b/tests/ui/redundant_allocation.rs index cf7d8c6e349a..574d34aed2d8 100644 --- a/tests/ui/redundant_allocation.rs +++ b/tests/ui/redundant_allocation.rs @@ -1,7 +1,5 @@ #![warn(clippy::all)] -#![allow(clippy::boxed_local, clippy::needless_pass_by_value)] -#![allow(clippy::blacklisted_name, unused_variables, dead_code)] -#![allow(unused_imports)] +#![allow(clippy::boxed_local, clippy::disallowed_names)] pub struct MyStruct; @@ -9,13 +7,7 @@ pub struct SubT { foo: T, } -pub enum MyEnum { - One, - Two, -} - mod outer_box { - use crate::MyEnum; use crate::MyStruct; use crate::SubT; use std::boxed::Box; @@ -36,7 +28,6 @@ mod outer_box { } mod outer_rc { - use crate::MyEnum; use crate::MyStruct; use crate::SubT; use std::boxed::Box; @@ -57,7 +48,6 @@ mod outer_rc { } mod outer_arc { - use crate::MyEnum; use crate::MyStruct; use crate::SubT; use std::boxed::Box; diff --git a/tests/ui/redundant_allocation.stderr b/tests/ui/redundant_allocation.stderr index fab1b069fcbc..54d4d88dba81 100644 --- a/tests/ui/redundant_allocation.stderr +++ b/tests/ui/redundant_allocation.stderr @@ -1,5 +1,5 @@ error: usage of `Box>` - --> $DIR/redundant_allocation.rs:25:30 + --> $DIR/redundant_allocation.rs:17:30 | LL | pub fn box_test6(foo: Box>) {} | ^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | pub fn box_test6(foo: Box>) {} = help: consider using just `Box` or `Rc` error: usage of `Box>` - --> $DIR/redundant_allocation.rs:27:30 + --> $DIR/redundant_allocation.rs:19:30 | LL | pub fn box_test7(foo: Box>) {} | ^^^^^^^^^^^ @@ -18,7 +18,7 @@ LL | pub fn box_test7(foo: Box>) {} = help: consider using just `Box` or `Arc` error: usage of `Box>>` - --> $DIR/redundant_allocation.rs:29:27 + --> $DIR/redundant_allocation.rs:21:27 | LL | pub fn box_test8() -> Box>> { | ^^^^^^^^^^^^^^^^^^^^ @@ -27,7 +27,7 @@ LL | pub fn box_test8() -> Box>> { = help: consider using just `Box>` or `Rc>` error: usage of `Box>` - --> $DIR/redundant_allocation.rs:33:30 + --> $DIR/redundant_allocation.rs:25:30 | LL | pub fn box_test9(foo: Box>) -> Box>> { | ^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL | pub fn box_test9(foo: Box>) -> Box>> { = help: consider using just `Box` or `Arc` error: usage of `Box>>` - --> $DIR/redundant_allocation.rs:33:46 + --> $DIR/redundant_allocation.rs:25:46 | LL | pub fn box_test9(foo: Box>) -> Box>> { | ^^^^^^^^^^^^^^^^^ @@ -45,7 +45,7 @@ LL | pub fn box_test9(foo: Box>) -> Box>> { = help: consider using just `Box>` or `Arc>` error: usage of `Rc>` - --> $DIR/redundant_allocation.rs:46:24 + --> $DIR/redundant_allocation.rs:37:24 | LL | pub fn rc_test5(a: Rc>) {} | ^^^^^^^^^^^^^ @@ -54,7 +54,7 @@ LL | pub fn rc_test5(a: Rc>) {} = help: consider using just `Rc` or `Box` error: usage of `Rc>` - --> $DIR/redundant_allocation.rs:48:24 + --> $DIR/redundant_allocation.rs:39:24 | LL | pub fn rc_test7(a: Rc>) {} | ^^^^^^^^^^^^^ @@ -63,7 +63,7 @@ LL | pub fn rc_test7(a: Rc>) {} = help: consider using just `Rc` or `Arc` error: usage of `Rc>>` - --> $DIR/redundant_allocation.rs:50:26 + --> $DIR/redundant_allocation.rs:41:26 | LL | pub fn rc_test8() -> Rc>> { | ^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | pub fn rc_test8() -> Rc>> { = help: consider using just `Rc>` or `Box>` error: usage of `Rc>` - --> $DIR/redundant_allocation.rs:54:29 + --> $DIR/redundant_allocation.rs:45:29 | LL | pub fn rc_test9(foo: Rc>) -> Rc>> { | ^^^^^^^^^^ @@ -81,7 +81,7 @@ LL | pub fn rc_test9(foo: Rc>) -> Rc>> { = help: consider using just `Rc` or `Arc` error: usage of `Rc>>` - --> $DIR/redundant_allocation.rs:54:44 + --> $DIR/redundant_allocation.rs:45:44 | LL | pub fn rc_test9(foo: Rc>) -> Rc>> { | ^^^^^^^^^^^^^^^^ @@ -90,7 +90,7 @@ LL | pub fn rc_test9(foo: Rc>) -> Rc>> { = help: consider using just `Rc>` or `Arc>` error: usage of `Arc>` - --> $DIR/redundant_allocation.rs:67:25 + --> $DIR/redundant_allocation.rs:57:25 | LL | pub fn arc_test5(a: Arc>) {} | ^^^^^^^^^^^^^^ @@ -99,7 +99,7 @@ LL | pub fn arc_test5(a: Arc>) {} = help: consider using just `Arc` or `Box` error: usage of `Arc>` - --> $DIR/redundant_allocation.rs:69:25 + --> $DIR/redundant_allocation.rs:59:25 | LL | pub fn arc_test6(a: Arc>) {} | ^^^^^^^^^^^^^ @@ -108,7 +108,7 @@ LL | pub fn arc_test6(a: Arc>) {} = help: consider using just `Arc` or `Rc` error: usage of `Arc>>` - --> $DIR/redundant_allocation.rs:71:27 + --> $DIR/redundant_allocation.rs:61:27 | LL | pub fn arc_test8() -> Arc>> { | ^^^^^^^^^^^^^^^^^^^^^ @@ -117,7 +117,7 @@ LL | pub fn arc_test8() -> Arc>> { = help: consider using just `Arc>` or `Box>` error: usage of `Arc>` - --> $DIR/redundant_allocation.rs:75:30 + --> $DIR/redundant_allocation.rs:65:30 | LL | pub fn arc_test9(foo: Arc>) -> Arc>> { | ^^^^^^^^^^ @@ -126,7 +126,7 @@ LL | pub fn arc_test9(foo: Arc>) -> Arc>> { = help: consider using just `Arc` or `Rc` error: usage of `Arc>>` - --> $DIR/redundant_allocation.rs:75:45 + --> $DIR/redundant_allocation.rs:65:45 | LL | pub fn arc_test9(foo: Arc>) -> Arc>> { | ^^^^^^^^^^^^^^^^ @@ -135,7 +135,7 @@ LL | pub fn arc_test9(foo: Arc>) -> Arc>> { = help: consider using just `Arc>` or `Rc>` error: usage of `Rc>>` - --> $DIR/redundant_allocation.rs:97:27 + --> $DIR/redundant_allocation.rs:87:27 | LL | pub fn test_rc_box(_: Rc>>) {} | ^^^^^^^^^^^^^^^^^^^ @@ -144,7 +144,7 @@ LL | pub fn test_rc_box(_: Rc>>) {} = help: consider using just `Rc>` or `Box>` error: usage of `Rc>>` - --> $DIR/redundant_allocation.rs:129:31 + --> $DIR/redundant_allocation.rs:119:31 | LL | pub fn test_rc_box_str(_: Rc>>) {} | ^^^^^^^^^^^^^^^^^ @@ -153,7 +153,7 @@ LL | pub fn test_rc_box_str(_: Rc>>) {} = help: consider using just `Rc>` or `Box>` error: usage of `Rc>>` - --> $DIR/redundant_allocation.rs:130:33 + --> $DIR/redundant_allocation.rs:120:33 | LL | pub fn test_rc_box_slice(_: Rc>>) {} | ^^^^^^^^^^^^^^^^^^^^^ @@ -162,7 +162,7 @@ LL | pub fn test_rc_box_slice(_: Rc>>) {} = help: consider using just `Rc>` or `Box>` error: usage of `Rc>>` - --> $DIR/redundant_allocation.rs:131:32 + --> $DIR/redundant_allocation.rs:121:32 | LL | pub fn test_rc_box_path(_: Rc>>) {} | ^^^^^^^^^^^^^^^^^^ @@ -171,7 +171,7 @@ LL | pub fn test_rc_box_path(_: Rc>>) {} = help: consider using just `Rc>` or `Box>` error: usage of `Rc>>` - --> $DIR/redundant_allocation.rs:132:34 + --> $DIR/redundant_allocation.rs:122:34 | LL | pub fn test_rc_box_custom(_: Rc>>) {} | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/redundant_allocation_fixable.fixed b/tests/ui/redundant_allocation_fixable.fixed index e7ed84731c02..6db02718c70b 100644 --- a/tests/ui/redundant_allocation_fixable.fixed +++ b/tests/ui/redundant_allocation_fixable.fixed @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::all)] #![allow(clippy::boxed_local, clippy::needless_pass_by_value)] -#![allow(clippy::blacklisted_name, unused_variables, dead_code)] +#![allow(clippy::disallowed_names, unused_variables, dead_code)] #![allow(unused_imports)] pub struct MyStruct; diff --git a/tests/ui/redundant_allocation_fixable.rs b/tests/ui/redundant_allocation_fixable.rs index de763f98b5c8..c15806f30c04 100644 --- a/tests/ui/redundant_allocation_fixable.rs +++ b/tests/ui/redundant_allocation_fixable.rs @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::all)] #![allow(clippy::boxed_local, clippy::needless_pass_by_value)] -#![allow(clippy::blacklisted_name, unused_variables, dead_code)] +#![allow(clippy::disallowed_names, unused_variables, dead_code)] #![allow(unused_imports)] pub struct MyStruct; diff --git a/tests/ui/redundant_closure_call_fixable.fixed b/tests/ui/redundant_closure_call_fixable.fixed index 0abca6fca061..7cd687c95a00 100644 --- a/tests/ui/redundant_closure_call_fixable.fixed +++ b/tests/ui/redundant_closure_call_fixable.fixed @@ -1,8 +1,28 @@ // run-rustfix +#![feature(async_closure)] #![warn(clippy::redundant_closure_call)] #![allow(unused)] +async fn something() -> u32 { + 21 +} + +async fn something_else() -> u32 { + 2 +} + fn main() { let a = 42; + let b = async { + let x = something().await; + let y = something_else().await; + x * y + }; + let c = { + let x = 21; + let y = 2; + x * y + }; + let d = async { something().await }; } diff --git a/tests/ui/redundant_closure_call_fixable.rs b/tests/ui/redundant_closure_call_fixable.rs index f8b9d37a5cc4..37e4d2238641 100644 --- a/tests/ui/redundant_closure_call_fixable.rs +++ b/tests/ui/redundant_closure_call_fixable.rs @@ -1,8 +1,28 @@ // run-rustfix +#![feature(async_closure)] #![warn(clippy::redundant_closure_call)] #![allow(unused)] +async fn something() -> u32 { + 21 +} + +async fn something_else() -> u32 { + 2 +} + fn main() { let a = (|| 42)(); + let b = (async || { + let x = something().await; + let y = something_else().await; + x * y + })(); + let c = (|| { + let x = 21; + let y = 2; + x * y + })(); + let d = (async || something().await)(); } diff --git a/tests/ui/redundant_closure_call_fixable.stderr b/tests/ui/redundant_closure_call_fixable.stderr index afd704ef12a9..56a8e57c0c36 100644 --- a/tests/ui/redundant_closure_call_fixable.stderr +++ b/tests/ui/redundant_closure_call_fixable.stderr @@ -1,10 +1,56 @@ error: try not to call a closure in the expression where it is declared - --> $DIR/redundant_closure_call_fixable.rs:7:13 + --> $DIR/redundant_closure_call_fixable.rs:16:13 | LL | let a = (|| 42)(); | ^^^^^^^^^ help: try doing something like: `42` | = note: `-D clippy::redundant-closure-call` implied by `-D warnings` -error: aborting due to previous error +error: try not to call a closure in the expression where it is declared + --> $DIR/redundant_closure_call_fixable.rs:17:13 + | +LL | let b = (async || { + | _____________^ +LL | | let x = something().await; +LL | | let y = something_else().await; +LL | | x * y +LL | | })(); + | |________^ + | +help: try doing something like + | +LL ~ let b = async { +LL + let x = something().await; +LL + let y = something_else().await; +LL + x * y +LL ~ }; + | + +error: try not to call a closure in the expression where it is declared + --> $DIR/redundant_closure_call_fixable.rs:22:13 + | +LL | let c = (|| { + | _____________^ +LL | | let x = 21; +LL | | let y = 2; +LL | | x * y +LL | | })(); + | |________^ + | +help: try doing something like + | +LL ~ let c = { +LL + let x = 21; +LL + let y = 2; +LL + x * y +LL ~ }; + | + +error: try not to call a closure in the expression where it is declared + --> $DIR/redundant_closure_call_fixable.rs:27:13 + | +LL | let d = (async || something().await)(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `async { something().await }` + +error: aborting due to 4 previous errors diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed index 53288be9404c..9cbad2269a09 100644 --- a/tests/ui/rename.fixed +++ b/tests/ui/rename.fixed @@ -4,6 +4,7 @@ // run-rustfix +#![allow(clippy::disallowed_names)] #![allow(clippy::blocks_in_if_conditions)] #![allow(clippy::box_collection)] #![allow(clippy::redundant_static_lifetimes)] @@ -14,6 +15,7 @@ #![allow(clippy::for_loops_over_fallibles)] #![allow(clippy::useless_conversion)] #![allow(clippy::match_result_ok)] +#![allow(clippy::overly_complex_bool_expr)] #![allow(clippy::new_without_default)] #![allow(clippy::bind_instead_of_map)] #![allow(clippy::expect_used)] @@ -33,6 +35,7 @@ #![allow(temporary_cstring_as_ptr)] #![allow(unknown_lints)] #![allow(unused_labels)] +#![warn(clippy::disallowed_names)] #![warn(clippy::blocks_in_if_conditions)] #![warn(clippy::blocks_in_if_conditions)] #![warn(clippy::box_collection)] @@ -45,6 +48,7 @@ #![warn(clippy::for_loops_over_fallibles)] #![warn(clippy::useless_conversion)] #![warn(clippy::match_result_ok)] +#![warn(clippy::overly_complex_bool_expr)] #![warn(clippy::new_without_default)] #![warn(clippy::bind_instead_of_map)] #![warn(clippy::expect_used)] diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs index 539f34f847ac..9153c0dab029 100644 --- a/tests/ui/rename.rs +++ b/tests/ui/rename.rs @@ -4,6 +4,7 @@ // run-rustfix +#![allow(clippy::disallowed_names)] #![allow(clippy::blocks_in_if_conditions)] #![allow(clippy::box_collection)] #![allow(clippy::redundant_static_lifetimes)] @@ -14,6 +15,7 @@ #![allow(clippy::for_loops_over_fallibles)] #![allow(clippy::useless_conversion)] #![allow(clippy::match_result_ok)] +#![allow(clippy::overly_complex_bool_expr)] #![allow(clippy::new_without_default)] #![allow(clippy::bind_instead_of_map)] #![allow(clippy::expect_used)] @@ -33,6 +35,7 @@ #![allow(temporary_cstring_as_ptr)] #![allow(unknown_lints)] #![allow(unused_labels)] +#![warn(clippy::blacklisted_name)] #![warn(clippy::block_in_if_condition_expr)] #![warn(clippy::block_in_if_condition_stmt)] #![warn(clippy::box_vec)] @@ -45,6 +48,7 @@ #![warn(clippy::for_loop_over_result)] #![warn(clippy::identity_conversion)] #![warn(clippy::if_let_some_result)] +#![warn(clippy::logic_bug)] #![warn(clippy::new_without_default_derive)] #![warn(clippy::option_and_then_some)] #![warn(clippy::option_expect_used)] diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr index 8ea46b580a8c..9c03ea914bb6 100644 --- a/tests/ui/rename.stderr +++ b/tests/ui/rename.stderr @@ -1,214 +1,226 @@ -error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:36:9 +error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` + --> $DIR/rename.rs:38:9 | -LL | #![warn(clippy::block_in_if_condition_expr)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` +LL | #![warn(clippy::blacklisted_name)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` | = note: `-D renamed-and-removed-lints` implied by `-D warnings` +error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions` + --> $DIR/rename.rs:39:9 + | +LL | #![warn(clippy::block_in_if_condition_expr)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` + error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:37:9 + --> $DIR/rename.rs:40:9 | LL | #![warn(clippy::block_in_if_condition_stmt)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` - --> $DIR/rename.rs:38:9 + --> $DIR/rename.rs:41:9 | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> $DIR/rename.rs:39:9 + --> $DIR/rename.rs:42:9 | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> $DIR/rename.rs:40:9 + --> $DIR/rename.rs:43:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> $DIR/rename.rs:41:9 + --> $DIR/rename.rs:44:9 | LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` - --> $DIR/rename.rs:42:9 + --> $DIR/rename.rs:45:9 | LL | #![warn(clippy::disallowed_type)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` - --> $DIR/rename.rs:43:9 + --> $DIR/rename.rs:46:9 | LL | #![warn(clippy::eval_order_dependence)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` error: lint `clippy::for_loop_over_option` has been renamed to `clippy::for_loops_over_fallibles` - --> $DIR/rename.rs:44:9 + --> $DIR/rename.rs:47:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `clippy::for_loops_over_fallibles` - --> $DIR/rename.rs:45:9 + --> $DIR/rename.rs:48:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> $DIR/rename.rs:46:9 + --> $DIR/rename.rs:49:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> $DIR/rename.rs:47:9 + --> $DIR/rename.rs:50:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` +error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` + --> $DIR/rename.rs:51:9 + | +LL | #![warn(clippy::logic_bug)] + | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` + error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> $DIR/rename.rs:48:9 + --> $DIR/rename.rs:52:9 | LL | #![warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` - --> $DIR/rename.rs:49:9 + --> $DIR/rename.rs:53:9 | LL | #![warn(clippy::option_and_then_some)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:50:9 + --> $DIR/rename.rs:54:9 | LL | #![warn(clippy::option_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:51:9 + --> $DIR/rename.rs:55:9 | LL | #![warn(clippy::option_map_unwrap_or)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:52:9 + --> $DIR/rename.rs:56:9 | LL | #![warn(clippy::option_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:53:9 + --> $DIR/rename.rs:57:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` - --> $DIR/rename.rs:54:9 + --> $DIR/rename.rs:58:9 | LL | #![warn(clippy::ref_in_deref)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:55:9 + --> $DIR/rename.rs:59:9 | LL | #![warn(clippy::result_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:56:9 + --> $DIR/rename.rs:60:9 | LL | #![warn(clippy::result_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:57:9 + --> $DIR/rename.rs:61:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> $DIR/rename.rs:58:9 + --> $DIR/rename.rs:62:9 | LL | #![warn(clippy::single_char_push_str)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> $DIR/rename.rs:59:9 + --> $DIR/rename.rs:63:9 | LL | #![warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` - --> $DIR/rename.rs:60:9 + --> $DIR/rename.rs:64:9 | LL | #![warn(clippy::to_string_in_display)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> $DIR/rename.rs:61:9 + --> $DIR/rename.rs:65:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> $DIR/rename.rs:62:9 + --> $DIR/rename.rs:66:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> $DIR/rename.rs:63:9 + --> $DIR/rename.rs:67:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> $DIR/rename.rs:64:9 + --> $DIR/rename.rs:68:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> $DIR/rename.rs:65:9 + --> $DIR/rename.rs:69:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:66:9 + --> $DIR/rename.rs:70:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> $DIR/rename.rs:67:9 + --> $DIR/rename.rs:71:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> $DIR/rename.rs:68:9 + --> $DIR/rename.rs:72:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> $DIR/rename.rs:69:9 + --> $DIR/rename.rs:73:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> $DIR/rename.rs:70:9 + --> $DIR/rename.rs:74:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` -error: aborting due to 35 previous errors +error: aborting due to 37 previous errors diff --git a/tests/ui/same_functions_in_if_condition.rs b/tests/ui/same_functions_in_if_condition.rs index 3d2295912c9f..a48829caac01 100644 --- a/tests/ui/same_functions_in_if_condition.rs +++ b/tests/ui/same_functions_in_if_condition.rs @@ -48,9 +48,9 @@ fn ifs_same_cond_fn() { } let mut v = vec![1]; - if v.pop() == None { + if v.pop().is_none() { //~ ERROR ifs same condition - } else if v.pop() == None { + } else if v.pop().is_none() { } if v.len() == 42 { diff --git a/tests/ui/same_functions_in_if_condition.stderr b/tests/ui/same_functions_in_if_condition.stderr index 71e82910ef75..cd438b830401 100644 --- a/tests/ui/same_functions_in_if_condition.stderr +++ b/tests/ui/same_functions_in_if_condition.stderr @@ -50,14 +50,14 @@ LL | if obj.method_arg(a) { error: this `if` has the same function call as a previous `if` --> $DIR/same_functions_in_if_condition.rs:53:15 | -LL | } else if v.pop() == None { - | ^^^^^^^^^^^^^^^ +LL | } else if v.pop().is_none() { + | ^^^^^^^^^^^^^^^^^ | note: same as this --> $DIR/same_functions_in_if_condition.rs:51:8 | -LL | if v.pop() == None { - | ^^^^^^^^^^^^^^^ +LL | if v.pop().is_none() { + | ^^^^^^^^^^^^^^^^^ error: this `if` has the same function call as a previous `if` --> $DIR/same_functions_in_if_condition.rs:58:15 diff --git a/tests/ui/skip_while_next.rs b/tests/ui/skip_while_next.rs index a522c0f08b20..a551c19d98bc 100644 --- a/tests/ui/skip_while_next.rs +++ b/tests/ui/skip_while_next.rs @@ -1,7 +1,7 @@ // aux-build:option_helpers.rs #![warn(clippy::skip_while_next)] -#![allow(clippy::blacklisted_name)] +#![allow(clippy::disallowed_names)] extern crate option_helpers; use option_helpers::IteratorFalsePositives; diff --git a/tests/ui/swap.fixed b/tests/ui/swap.fixed index 3329efbd4ff4..24b229235d33 100644 --- a/tests/ui/swap.fixed +++ b/tests/ui/swap.fixed @@ -2,7 +2,7 @@ #![warn(clippy::all)] #![allow( - clippy::blacklisted_name, + clippy::disallowed_names, clippy::no_effect, clippy::redundant_clone, redundant_semicolons, diff --git a/tests/ui/swap.rs b/tests/ui/swap.rs index 8179ac1f2ab0..a318c27919c8 100644 --- a/tests/ui/swap.rs +++ b/tests/ui/swap.rs @@ -2,7 +2,7 @@ #![warn(clippy::all)] #![allow( - clippy::blacklisted_name, + clippy::disallowed_names, clippy::no_effect, clippy::redundant_clone, redundant_semicolons, diff --git a/tests/ui/trivially_copy_pass_by_ref.rs b/tests/ui/trivially_copy_pass_by_ref.rs index 8f78f16a0a1a..c0c64ebcabfb 100644 --- a/tests/ui/trivially_copy_pass_by_ref.rs +++ b/tests/ui/trivially_copy_pass_by_ref.rs @@ -2,7 +2,7 @@ // normalize-stderr-test "\(limit: \d+ byte\)" -> "(limit: N byte)" #![deny(clippy::trivially_copy_pass_by_ref)] -#![allow(clippy::blacklisted_name, clippy::redundant_field_names)] +#![allow(clippy::disallowed_names, clippy::redundant_field_names)] #[derive(Copy, Clone)] struct Foo(u32); diff --git a/tests/ui/unit_arg.rs b/tests/ui/unit_arg.rs index 38be87bddf19..7bf3adc07ac5 100644 --- a/tests/ui/unit_arg.rs +++ b/tests/ui/unit_arg.rs @@ -1,3 +1,5 @@ +// aux-build: proc_macro_with_span.rs + #![warn(clippy::unit_arg)] #![allow( clippy::no_effect, @@ -8,9 +10,13 @@ clippy::or_fun_call, clippy::needless_question_mark, clippy::self_named_constructors, - clippy::let_unit_value + clippy::let_unit_value, + clippy::never_loop )] +extern crate proc_macro_with_span; + +use proc_macro_with_span::with_span; use std::fmt::Debug; fn foo(t: T) { @@ -127,6 +133,10 @@ fn returning_expr() -> Option<()> { fn taking_multiple_units(a: (), b: ()) {} +fn proc_macro() { + with_span!(span taking_multiple_units(unsafe { (); }, 'x: loop { break 'x (); })); +} + fn main() { bad(); ok(); diff --git a/tests/ui/unit_arg.stderr b/tests/ui/unit_arg.stderr index 11cfe66a30e8..1de9d44bb0d6 100644 --- a/tests/ui/unit_arg.stderr +++ b/tests/ui/unit_arg.stderr @@ -1,5 +1,5 @@ error: passing a unit value to a function - --> $DIR/unit_arg.rs:57:5 + --> $DIR/unit_arg.rs:63:5 | LL | / foo({ LL | | 1; @@ -20,7 +20,7 @@ LL ~ foo(()); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:60:5 + --> $DIR/unit_arg.rs:66:5 | LL | foo(foo(1)); | ^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL ~ foo(()); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:61:5 + --> $DIR/unit_arg.rs:67:5 | LL | / foo({ LL | | foo(1); @@ -54,7 +54,7 @@ LL ~ foo(()); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:66:5 + --> $DIR/unit_arg.rs:72:5 | LL | / b.bar({ LL | | 1; @@ -74,7 +74,7 @@ LL ~ b.bar(()); | error: passing unit values to a function - --> $DIR/unit_arg.rs:69:5 + --> $DIR/unit_arg.rs:75:5 | LL | taking_multiple_units(foo(0), foo(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -87,7 +87,7 @@ LL ~ taking_multiple_units((), ()); | error: passing unit values to a function - --> $DIR/unit_arg.rs:70:5 + --> $DIR/unit_arg.rs:76:5 | LL | / taking_multiple_units(foo(0), { LL | | foo(1); @@ -110,7 +110,7 @@ LL ~ taking_multiple_units((), ()); | error: passing unit values to a function - --> $DIR/unit_arg.rs:74:5 + --> $DIR/unit_arg.rs:80:5 | LL | / taking_multiple_units( LL | | { @@ -146,7 +146,7 @@ LL ~ ); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:85:13 + --> $DIR/unit_arg.rs:91:13 | LL | None.or(Some(foo(2))); | ^^^^^^^^^^^^ @@ -160,7 +160,7 @@ LL ~ }); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:88:5 + --> $DIR/unit_arg.rs:94:5 | LL | foo(foo(())); | ^^^^^^^^^^^^ @@ -172,7 +172,7 @@ LL ~ foo(()); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:125:5 + --> $DIR/unit_arg.rs:131:5 | LL | Some(foo(1)) | ^^^^^^^^^^^^ diff --git a/tests/ui/unwrap_expect_used.rs b/tests/ui/unwrap_expect_used.rs new file mode 100644 index 000000000000..0d4a0504a6e0 --- /dev/null +++ b/tests/ui/unwrap_expect_used.rs @@ -0,0 +1,10 @@ +#![warn(clippy::unwrap_used, clippy::expect_used)] + +fn main() { + Some(3).unwrap(); + Some(3).expect("Hello world!"); + + let a: Result = Ok(3); + a.unwrap(); + a.expect("Hello world!"); +} diff --git a/tests/ui/unwrap_expect_used.stderr b/tests/ui/unwrap_expect_used.stderr new file mode 100644 index 000000000000..f54bfd617c4e --- /dev/null +++ b/tests/ui/unwrap_expect_used.stderr @@ -0,0 +1,36 @@ +error: used `unwrap()` on `an Option` value + --> $DIR/unwrap_expect_used.rs:4:5 + | +LL | Some(3).unwrap(); + | ^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::unwrap-used` implied by `-D warnings` + = help: if this value is `None`, it will panic + +error: used `expect()` on `an Option` value + --> $DIR/unwrap_expect_used.rs:5:5 + | +LL | Some(3).expect("Hello world!"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::expect-used` implied by `-D warnings` + = help: if this value is `None`, it will panic + +error: used `unwrap()` on `a Result` value + --> $DIR/unwrap_expect_used.rs:8:5 + | +LL | a.unwrap(); + | ^^^^^^^^^^ + | + = help: if this value is an `Err`, it will panic + +error: used `expect()` on `a Result` value + --> $DIR/unwrap_expect_used.rs:9:5 + | +LL | a.expect("Hello world!"); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: if this value is an `Err`, it will panic + +error: aborting due to 4 previous errors + diff --git a/tests/ui/used_underscore_binding.rs b/tests/ui/used_underscore_binding.rs index d20977d55d29..322083511ac1 100644 --- a/tests/ui/used_underscore_binding.rs +++ b/tests/ui/used_underscore_binding.rs @@ -2,7 +2,7 @@ #![feature(rustc_private)] #![warn(clippy::all)] -#![allow(clippy::blacklisted_name, clippy::eq_op)] +#![allow(clippy::disallowed_names, clippy::eq_op)] #![warn(clippy::used_underscore_binding)] #[macro_use] From 23cd7b863ff0ca4fba9e28402a067f3f75772d26 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Aug 2022 19:01:19 -0400 Subject: [PATCH 3707/5092] rustup for pthread_setname_np on Linux --- rust-version | 2 +- src/shims/unix/foreign_items.rs | 3 ++- src/shims/unix/linux/foreign_items.rs | 9 +++++++ src/shims/unix/macos/foreign_items.rs | 4 ++-- src/shims/unix/thread.rs | 34 ++++++++++++++++----------- src/thread.rs | 25 ++++++++------------ 6 files changed, 44 insertions(+), 33 deletions(-) diff --git a/rust-version b/rust-version index 71d06eff494c..0bcadc0a366f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1603a70f82240ba2d27f72f964e36614d7620ad3 +20ffea6938b5839c390252e07940b99e3b6a889a diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 6ea10de0b8a8..0ca838b2103f 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -437,7 +437,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "pthread_self" => { let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - this.pthread_self(dest)?; + let res = this.pthread_self()?; + this.write_scalar(res, dest)?; } "sched_yield" => { let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index bae3780b460c..817bfc7d1cc9 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -69,6 +69,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.pthread_condattr_getclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "pthread_setname_np" => { + let [thread, name] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let res = this.pthread_setname_np( + this.read_scalar(thread)?.check_init()?, + this.read_scalar(name)?.check_init()?, + )?; + this.write_scalar(res, dest)?; + } // Dynamically invoked syscalls "syscall" => { diff --git a/src/shims/unix/macos/foreign_items.rs b/src/shims/unix/macos/foreign_items.rs index 35751d5818ab..da8e8a63bfe8 100644 --- a/src/shims/unix/macos/foreign_items.rs +++ b/src/shims/unix/macos/foreign_items.rs @@ -173,8 +173,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_setname_np" => { let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let name = this.read_pointer(name)?; - this.pthread_setname_np(name)?; + let thread = this.pthread_self()?; + this.pthread_setname_np(thread, this.read_scalar(name)?.check_init()?)?; } // Incomplete shims that we "stub out" just to get pre-main initialization code to work. diff --git a/src/shims/unix/thread.rs b/src/shims/unix/thread.rs index 1a8531e88047..22114eae6724 100644 --- a/src/shims/unix/thread.rs +++ b/src/shims/unix/thread.rs @@ -84,11 +84,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_self(&mut self, dest: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { + fn pthread_self(&mut self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let thread_id = this.get_active_thread(); - this.write_scalar(Scalar::from_uint(thread_id.to_u32(), dest.layout.size), dest) + Ok(Scalar::from_machine_usize(thread_id.into(), this)) + } + + fn pthread_setname_np( + &mut self, + thread: Scalar, + name: Scalar, + ) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + + let thread = ThreadId::try_from(thread.to_machine_usize(this)?).unwrap(); + let name = name.to_pointer(this)?; + + let name = this.read_c_str(name)?.to_owned(); + this.set_thread_name(thread, name); + + Ok(Scalar::from_u32(0)) } fn prctl(&mut self, args: &[OpTy<'tcx, Provenance>]) -> InterpResult<'tcx, i32> { @@ -117,7 +133,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // byte. Since `read_c_str` returns the string without the null // byte, we need to truncate to 15. name.truncate(15); - this.set_active_thread_name(name); + this.set_thread_name(this.get_active_thread(), name); } else if option == this.eval_libc_i32("PR_GET_NAME")? { if args.len() < 2 { throw_ub_format!( @@ -127,7 +143,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let address = this.read_pointer(&args[1])?; - let mut name = this.get_active_thread_name().to_vec(); + let mut name = this.get_thread_name(this.get_active_thread()).to_vec(); name.push(0u8); assert!(name.len() <= 16); this.write_bytes_ptr(address, name)?; @@ -138,16 +154,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_setname_np(&mut self, name: Pointer>) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - this.assert_target_os("macos", "pthread_setname_np"); - - let name = this.read_c_str(name)?.to_owned(); - this.set_active_thread_name(name); - - Ok(()) - } - fn sched_yield(&mut self) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); diff --git a/src/thread.rs b/src/thread.rs index 683694f482ea..6f394fa42fc9 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -69,9 +69,9 @@ impl From for ThreadId { } } -impl ThreadId { - pub fn to_u32_scalar(&self) -> Scalar { - Scalar::from_u32(self.0) +impl From for u64 { + fn from(t: ThreadId) -> Self { + t.0.into() } } @@ -394,14 +394,9 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { Ok(()) } - /// Set the name of the active thread. - fn set_active_thread_name(&mut self, new_thread_name: Vec) { - self.active_thread_mut().thread_name = Some(new_thread_name); - } - - /// Get the name of the active thread. - pub fn get_active_thread_name(&self) -> &[u8] { - self.active_thread_ref().thread_name() + /// Set the name of the given thread. + pub fn set_thread_name(&mut self, thread: ThreadId, new_thread_name: Vec) { + self.threads[thread].thread_name = Some(new_thread_name); } /// Get the name of the given thread. @@ -704,18 +699,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[inline] - fn set_active_thread_name(&mut self, new_thread_name: Vec) { + fn set_thread_name(&mut self, thread: ThreadId, new_thread_name: Vec) { let this = self.eval_context_mut(); - this.machine.threads.set_active_thread_name(new_thread_name); + this.machine.threads.set_thread_name(thread, new_thread_name); } #[inline] - fn get_active_thread_name<'c>(&'c self) -> &'c [u8] + fn get_thread_name<'c>(&'c self, thread: ThreadId) -> &'c [u8] where 'mir: 'c, { let this = self.eval_context_ref(); - this.machine.threads.get_active_thread_name() + this.machine.threads.get_thread_name(thread) } #[inline] From 38a495346f89b04653b552e0aaff201065bd8038 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Aug 2022 19:04:44 -0400 Subject: [PATCH 3708/5092] remove prctl, now that std does not use it any more it is a terrible variadic function... --- src/shims/unix/linux/foreign_items.rs | 6 --- src/shims/unix/thread.rs | 47 ----------------------- tests/pass/libc.rs | 55 --------------------------- 3 files changed, 108 deletions(-) diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index 817bfc7d1cc9..8c569fb34bba 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -51,12 +51,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Threading - "prctl" => { - // prctl is variadic. (It is not documented like that in the manpage, but defined like that in the libc crate.) - this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?; - let result = this.prctl(args)?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } "pthread_condattr_setclock" => { let [attr, clock_id] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/shims/unix/thread.rs b/src/shims/unix/thread.rs index 22114eae6724..0df70543fac8 100644 --- a/src/shims/unix/thread.rs +++ b/src/shims/unix/thread.rs @@ -107,53 +107,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(Scalar::from_u32(0)) } - fn prctl(&mut self, args: &[OpTy<'tcx, Provenance>]) -> InterpResult<'tcx, i32> { - let this = self.eval_context_mut(); - this.assert_target_os("linux", "prctl"); - - if args.is_empty() { - throw_ub_format!( - "incorrect number of arguments for `prctl`: got {}, expected at least 1", - args.len() - ); - } - - let option = this.read_scalar(&args[0])?.to_i32()?; - if option == this.eval_libc_i32("PR_SET_NAME")? { - if args.len() < 2 { - throw_ub_format!( - "incorrect number of arguments for `prctl` with `PR_SET_NAME`: got {}, expected at least 2", - args.len() - ); - } - - let address = this.read_pointer(&args[1])?; - let mut name = this.read_c_str(address)?.to_owned(); - // The name should be no more than 16 bytes, including the null - // byte. Since `read_c_str` returns the string without the null - // byte, we need to truncate to 15. - name.truncate(15); - this.set_thread_name(this.get_active_thread(), name); - } else if option == this.eval_libc_i32("PR_GET_NAME")? { - if args.len() < 2 { - throw_ub_format!( - "incorrect number of arguments for `prctl` with `PR_SET_NAME`: got {}, expected at least 2", - args.len() - ); - } - - let address = this.read_pointer(&args[1])?; - let mut name = this.get_thread_name(this.get_active_thread()).to_vec(); - name.push(0u8); - assert!(name.len() <= 16); - this.write_bytes_ptr(address, name)?; - } else { - throw_unsup_format!("unsupported prctl option {}", option); - } - - Ok(0) - } - fn sched_yield(&mut self) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index b58485602148..f3aaccd57411 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -277,58 +277,6 @@ fn test_rwlock_libc_static_initializer() { } } -/// Test whether the `prctl` shim correctly sets the thread name. -/// -/// Note: `prctl` exists only on Linux. -#[cfg(any(target_os = "linux"))] -fn test_prctl_thread_name() { - use libc::c_long; - use std::ffi::CString; - unsafe { - let mut buf = [255; 10]; - assert_eq!( - libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), - 0, - ); - // Rust runtime might set thread name, so we allow two options here. - assert!(&buf[..10] == b"\0" || &buf[..5] == b"main\0"); - let thread_name = CString::new("hello").expect("CString::new failed"); - assert_eq!( - libc::prctl( - libc::PR_SET_NAME, - thread_name.as_ptr(), - 0 as c_long, - 0 as c_long, - 0 as c_long, - ), - 0, - ); - let mut buf = [255; 6]; - assert_eq!( - libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), - 0, - ); - assert_eq!(b"hello\0", &buf); - let long_thread_name = CString::new("01234567890123456789").expect("CString::new failed"); - assert_eq!( - libc::prctl( - libc::PR_SET_NAME, - long_thread_name.as_ptr(), - 0 as c_long, - 0 as c_long, - 0 as c_long, - ), - 0, - ); - let mut buf = [255; 16]; - assert_eq!( - libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), - 0, - ); - assert_eq!(b"012345678901234\0", &buf); - } -} - /// Tests whether each thread has its own `__errno_location`. fn test_thread_local_errno() { #[cfg(target_os = "linux")] @@ -473,9 +421,6 @@ fn main() { #[cfg(any(target_os = "linux"))] test_mutex_libc_static_initializer_recursive(); - #[cfg(any(target_os = "linux"))] - test_prctl_thread_name(); - test_thread_local_errno(); #[cfg(any(target_os = "linux"))] From 96049ef88eb38af624134ee465d87eb91717b903 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Aug 2022 19:27:15 -0400 Subject: [PATCH 3709/5092] move a bunch of type information into the respective shim --- src/shims/time.rs | 21 ++-- src/shims/unix/foreign_items.rs | 8 +- src/shims/unix/fs.rs | 136 ++++++++++++++------------ src/shims/unix/linux/foreign_items.rs | 8 +- src/shims/unix/macos/foreign_items.rs | 20 ++-- src/shims/unix/sync.rs | 10 +- 6 files changed, 106 insertions(+), 97 deletions(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index d9edbe3d7bdf..c3eb0161c210 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -15,7 +15,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, clk_id_op: &OpTy<'tcx, Provenance>, tp_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + ) -> InterpResult<'tcx, Scalar> { // This clock support is deliberately minimal because a lot of clock types have fiddly // properties (is it possible for Miri to be suspended independently of the host?). If you // have a use for another clock type, please open an issue. @@ -46,7 +46,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; - return Ok(-1); + return Ok(Scalar::from_i32(-1)); }; let tv_sec = duration.as_secs(); @@ -54,7 +54,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_int_fields(&[tv_sec.into(), tv_nsec.into()], &this.deref_operand(tp_op)?)?; - Ok(0) + Ok(Scalar::from_i32(0)) } fn gettimeofday( @@ -160,7 +160,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(-1) // Return non-zero on success } - fn mach_absolute_time(&self) -> InterpResult<'tcx, u64> { + fn mach_absolute_time(&self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_ref(); this.assert_target_os("macos", "mach_absolute_time"); @@ -169,13 +169,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This returns a u64, with time units determined dynamically by `mach_timebase_info`. // We return plain nanoseconds. let duration = Instant::now().duration_since(this.machine.time_anchor); - u64::try_from(duration.as_nanos()).map_err(|_| { + let res = u64::try_from(duration.as_nanos()).map_err(|_| { err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported") - .into() - }) + })?; + Ok(Scalar::from_u64(res)) } - fn mach_timebase_info(&mut self, info_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + fn mach_timebase_info( + &mut self, + info_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("macos", "mach_timebase_info"); @@ -188,7 +191,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (numer, denom) = (1, 1); this.write_int_fields(&[numer.into(), denom.into()], &info)?; - Ok(0) // KERN_SUCCESS + Ok(Scalar::from_i32(0)) // KERN_SUCCESS } fn nanosleep( diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 0ca838b2103f..3dea8f203bb7 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -63,7 +63,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "close" => { let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.close(fd)?; - this.write_scalar(Scalar::from_i32(result), dest)?; + this.write_scalar(result, dest)?; } "fcntl" => { // `fcntl` is variadic. The argument count is checked based on the first argument @@ -128,13 +128,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "lseek64" => { let [fd, offset, whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.lseek64(fd, offset, whence)?; - this.write_scalar(Scalar::from_i64(result), dest)?; + this.write_scalar(result, dest)?; } "ftruncate64" => { let [fd, length] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.ftruncate64(fd, length)?; - this.write_scalar(Scalar::from_i32(result), dest)?; + this.write_scalar(result, dest)?; } "fsync" => { let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; @@ -164,7 +164,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "realpath" => { let [path, resolved_path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.realpath(path, resolved_path)?; - this.write_pointer(result, dest)?; + this.write_scalar(result, dest)?; } "mkstemp" => { let [template] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index 951ddae2c14d..2a6499ce9994 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -664,17 +664,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn close(&mut self, fd_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + fn close(&mut self, fd_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let fd = this.read_scalar(fd_op)?.to_i32()?; - if let Some(file_descriptor) = this.machine.file_handler.handles.remove(&fd) { - let result = file_descriptor.close(this.machine.communicate())?; - this.try_unwrap_io_result(result) - } else { - this.handle_not_found() - } + Ok(Scalar::from_i32( + if let Some(file_descriptor) = this.machine.file_handler.handles.remove(&fd) { + let result = file_descriptor.close(this.machine.communicate())?; + this.try_unwrap_io_result(result)? + } else { + this.handle_not_found()? + }, + )) } fn read( @@ -772,7 +774,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fd_op: &OpTy<'tcx, Provenance>, offset_op: &OpTy<'tcx, Provenance>, whence_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i64> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); // Isolation check is done via `FileDescriptor` trait. @@ -790,18 +792,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; - return Ok(-1); + return Ok(Scalar::from_i64(-1)); }; let communicate = this.machine.communicate(); - if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { - let result = file_descriptor - .seek(communicate, seek_from)? - .map(|offset| i64::try_from(offset).unwrap()); - this.try_unwrap_io_result(result) - } else { - this.handle_not_found() - } + Ok(Scalar::from_i64( + if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { + let result = file_descriptor + .seek(communicate, seek_from)? + .map(|offset| i64::try_from(offset).unwrap()); + this.try_unwrap_io_result(result)? + } else { + this.handle_not_found()? + }, + )) } fn unlink(&mut self, path_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { @@ -855,7 +859,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, path_op: &OpTy<'tcx, Provenance>, buf_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("macos", "stat"); @@ -867,16 +871,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.reject_in_isolation("`stat`", reject_with)?; let eacc = this.eval_libc("EACCES")?; this.set_last_error(eacc)?; - return Ok(-1); + return Ok(Scalar::from_i32(-1)); } // `stat` always follows symlinks. let metadata = match FileMetadata::from_path(this, &path, true)? { Some(metadata) => metadata, - None => return Ok(-1), + None => return Ok(Scalar::from_i32(-1)), // `FileMetadata` has set errno }; - this.macos_stat_write_buf(metadata, buf_op) + Ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?)) } // `lstat` is used to get symlink metadata. @@ -884,7 +888,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, path_op: &OpTy<'tcx, Provenance>, buf_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("macos", "lstat"); @@ -896,22 +900,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.reject_in_isolation("`lstat`", reject_with)?; let eacc = this.eval_libc("EACCES")?; this.set_last_error(eacc)?; - return Ok(-1); + return Ok(Scalar::from_i32(-1)); } let metadata = match FileMetadata::from_path(this, &path, false)? { Some(metadata) => metadata, - None => return Ok(-1), + None => return Ok(Scalar::from_i32(-1)), // `FileMetadata` has set errno }; - this.macos_stat_write_buf(metadata, buf_op) + Ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?)) } fn macos_fstat( &mut self, fd_op: &OpTy<'tcx, Provenance>, buf_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("macos", "fstat"); @@ -922,14 +926,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`fstat`", reject_with)?; // Set error code as "EBADF" (bad fd) - return this.handle_not_found(); + return Ok(Scalar::from_i32(this.handle_not_found()?)); } let metadata = match FileMetadata::from_fd(this, fd)? { Some(metadata) => metadata, - None => return Ok(-1), + None => return Ok(Scalar::from_i32(-1)), }; - this.macos_stat_write_buf(metadata, buf_op) + Ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?)) } fn linux_statx( @@ -1343,7 +1347,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dirp_op: &OpTy<'tcx, Provenance>, entry_op: &OpTy<'tcx, Provenance>, result_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("macos", "readdir_r"); @@ -1354,13 +1358,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`readdir_r`", reject_with)?; // Set error code as "EBADF" (bad fd) - return this.handle_not_found(); + return Ok(Scalar::from_i32(this.handle_not_found()?)); } let open_dir = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { err_unsup_format!("the DIR pointer passed to readdir_r did not come from opendir") })?; - match open_dir.read_dir.next() { + Ok(Scalar::from_i32(match open_dir.read_dir.next() { Some(Ok(dir_entry)) => { // Write into entry, write pointer to result, return 0 on success. // The name is written with write_os_str_to_c_str, while the rest of the @@ -1417,17 +1421,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result_place = this.deref_operand(result_op)?; this.write_scalar(this.read_scalar(entry_op)?, &result_place.into())?; - Ok(0) + 0 } None => { // end of stream: return 0, assign *result=NULL this.write_null(&this.deref_operand(result_op)?.into())?; - Ok(0) + 0 } Some(Err(e)) => match e.raw_os_error() { // return positive error number on error - Some(error) => Ok(error), + Some(error) => error, None => { throw_unsup_format!( "the error {} couldn't be converted to a return value", @@ -1435,7 +1439,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) } }, - } + })) } fn closedir(&mut self, dirp_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { @@ -1463,7 +1467,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, fd_op: &OpTy<'tcx, Provenance>, length_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -1473,30 +1477,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`ftruncate64`", reject_with)?; // Set error code as "EBADF" (bad fd) - return this.handle_not_found(); + return Ok(Scalar::from_i32(this.handle_not_found()?)); } - if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { - // FIXME: Support ftruncate64 for all FDs - let FileHandle { file, writable } = file_descriptor.as_file_handle()?; - if *writable { - if let Ok(length) = length.try_into() { - let result = file.set_len(length); - this.try_unwrap_io_result(result.map(|_| 0i32)) + Ok(Scalar::from_i32( + if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { + // FIXME: Support ftruncate64 for all FDs + let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + if *writable { + if let Ok(length) = length.try_into() { + let result = file.set_len(length); + this.try_unwrap_io_result(result.map(|_| 0i32))? + } else { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + -1 + } } else { + // The file is not writable let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; - Ok(-1) + -1 } } else { - // The file is not writable - let einval = this.eval_libc("EINVAL")?; - this.set_last_error(einval)?; - Ok(-1) - } - } else { - this.handle_not_found() - } + this.handle_not_found()? + }, + )) } fn fsync(&mut self, fd_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { @@ -1554,7 +1560,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx offset_op: &OpTy<'tcx, Provenance>, nbytes_op: &OpTy<'tcx, Provenance>, flags_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -1565,7 +1571,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if offset < 0 || nbytes < 0 { let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; - return Ok(-1); + return Ok(Scalar::from_i32(-1)); } let allowed_flags = this.eval_libc_i32("SYNC_FILE_RANGE_WAIT_BEFORE")? | this.eval_libc_i32("SYNC_FILE_RANGE_WRITE")? @@ -1573,23 +1579,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if flags & allowed_flags != flags { let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; - return Ok(-1); + return Ok(Scalar::from_i32(-1)); } // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`sync_file_range`", reject_with)?; // Set error code as "EBADF" (bad fd) - return this.handle_not_found(); + return Ok(Scalar::from_i32(this.handle_not_found()?)); } if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support sync_data_range for all FDs let FileHandle { file, writable } = file_descriptor.as_file_handle()?; let io_result = maybe_sync_file(file, *writable, File::sync_data); - this.try_unwrap_io_result(io_result) + Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?)) } else { - this.handle_not_found() + Ok(Scalar::from_i32(this.handle_not_found()?)) } } @@ -1674,7 +1680,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, path_op: &OpTy<'tcx, Provenance>, processed_path_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Pointer>> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("realpath"); @@ -1686,7 +1692,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.reject_in_isolation("`realpath`", reject_with)?; let eacc = this.eval_libc("EACCES")?; this.set_last_error(eacc)?; - return Ok(Pointer::null()); + return Ok(Scalar::from_machine_usize(0, this)); } let result = std::fs::canonicalize(pathname); @@ -1717,16 +1723,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // seems like a bit of a mess anyway: . let enametoolong = this.eval_libc("ENAMETOOLONG")?; this.set_last_error(enametoolong)?; - return Ok(Pointer::null()); + return Ok(Scalar::from_machine_usize(0, this)); } processed_ptr }; - Ok(dest) + Ok(Scalar::from_maybe_pointer(dest, this)) } Err(e) => { this.set_last_error_from_io_error(e.kind())?; - Ok(Pointer::null()) + Ok(Scalar::from_machine_usize(0, this)) } } } diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index 8c569fb34bba..6881d829c150 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -38,7 +38,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [fd, offset, nbytes, flags] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.sync_file_range(fd, offset, nbytes, flags)?; - this.write_scalar(Scalar::from_i32(result), dest)?; + this.write_scalar(result, dest)?; } // Time related shims @@ -47,7 +47,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [clk_id, tp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.clock_gettime(clk_id, tp)?; - this.write_scalar(Scalar::from_i32(result), dest)?; + this.write_scalar(result, dest)?; } // Threading @@ -55,13 +55,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [attr, clock_id] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_condattr_setclock(attr, clock_id)?; - this.write_scalar(Scalar::from_i32(result), dest)?; + this.write_scalar(result, dest)?; } "pthread_condattr_getclock" => { let [attr, clock_id] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_condattr_getclock(attr, clock_id)?; - this.write_scalar(Scalar::from_i32(result), dest)?; + this.write_scalar(result, dest)?; } "pthread_setname_np" => { let [thread, name] = diff --git a/src/shims/unix/macos/foreign_items.rs b/src/shims/unix/macos/foreign_items.rs index da8e8a63bfe8..fd7d5fb763ee 100644 --- a/src/shims/unix/macos/foreign_items.rs +++ b/src/shims/unix/macos/foreign_items.rs @@ -29,24 +29,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "close$NOCANCEL" => { let [result] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.close(result)?; - this.write_scalar(Scalar::from_i32(result), dest)?; + this.write_scalar(result, dest)?; } "stat" | "stat64" | "stat$INODE64" => { let [path, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_stat(path, buf)?; - this.write_scalar(Scalar::from_i32(result), dest)?; + this.write_scalar(result, dest)?; } "lstat" | "lstat64" | "lstat$INODE64" => { let [path, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_lstat(path, buf)?; - this.write_scalar(Scalar::from_i32(result), dest)?; + this.write_scalar(result, dest)?; } "fstat" | "fstat64" | "fstat$INODE64" => { let [fd, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_fstat(fd, buf)?; - this.write_scalar(Scalar::from_i32(result), dest)?; + this.write_scalar(result, dest)?; } "opendir$INODE64" => { let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; @@ -57,27 +57,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [dirp, entry, result] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_readdir_r(dirp, entry, result)?; - this.write_scalar(Scalar::from_i32(result), dest)?; + this.write_scalar(result, dest)?; } "lseek" => { let [fd, offset, whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // macOS is 64bit-only, so this is lseek64 let result = this.lseek64(fd, offset, whence)?; - this.write_scalar(Scalar::from_i64(result), dest)?; + this.write_scalar(result, dest)?; } "ftruncate" => { let [fd, length] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // macOS is 64bit-only, so this is ftruncate64 let result = this.ftruncate64(fd, length)?; - this.write_scalar(Scalar::from_i32(result), dest)?; + this.write_scalar(result, dest)?; } "realpath$DARWIN_EXTSN" => { let [path, resolved_path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.realpath(path, resolved_path)?; - this.write_pointer(result, dest)?; + this.write_scalar(result, dest)?; } // Environment related shims @@ -93,13 +93,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "mach_absolute_time" => { let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.mach_absolute_time()?; - this.write_scalar(Scalar::from_u64(result), dest)?; + this.write_scalar(result, dest)?; } "mach_timebase_info" => { let [info] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.mach_timebase_info(info)?; - this.write_scalar(Scalar::from_i32(result), dest)?; + this.write_scalar(result, dest)?; } // Access to command-line arguments diff --git a/src/shims/unix/sync.rs b/src/shims/unix/sync.rs index 18226c2b8cf6..69e632915b17 100644 --- a/src/shims/unix/sync.rs +++ b/src/shims/unix/sync.rs @@ -723,7 +723,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, attr_op: &OpTy<'tcx, Provenance>, clock_id_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let clock_id = this.read_scalar(clock_id_op)?.check_init()?; @@ -733,23 +733,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx condattr_set_clock_id(this, attr_op, clock_id)?; } else { let einval = this.eval_libc_i32("EINVAL")?; - return Ok(einval); + return Ok(Scalar::from_i32(einval)); } - Ok(0) + Ok(Scalar::from_i32(0)) } fn pthread_condattr_getclock( &mut self, attr_op: &OpTy<'tcx, Provenance>, clk_id_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let clock_id = condattr_get_clock_id(this, attr_op)?; this.write_scalar(clock_id, &this.deref_operand(clk_id_op)?.into())?; - Ok(0) + Ok(Scalar::from_i32(0)) } fn pthread_condattr_destroy( From f7f60b82e8d9ce281f67cef8b95019482ff47298 Mon Sep 17 00:00:00 2001 From: Michael Krasnitski Date: Thu, 11 Aug 2022 22:41:25 -0400 Subject: [PATCH 3710/5092] Adjust lint description for better clarity --- clippy_lints/src/if_then_some_else_none.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index 20fcba90773b..11c43247868c 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -11,10 +11,12 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { /// ### What it does - /// Checks for if-else that could be written to `bool::then`. + /// Checks for if-else that could be written using either `bool::then` or `bool::then_some`. /// /// ### Why is this bad? - /// Looks a little redundant. Using `bool::then` helps it have less lines of code. + /// Looks a little redundant. Using `bool::then` is more concise and incurs no loss of clarity. + /// For simple calculations and known values, use `bool::then_some`, which is eagerly evaluated + /// in comparison to `bool::then`. /// /// ### Example /// ```rust @@ -39,7 +41,7 @@ declare_clippy_lint! { #[clippy::version = "1.53.0"] pub IF_THEN_SOME_ELSE_NONE, restriction, - "Finds if-else that could be written using `bool::then`" + "Finds if-else that could be written using either `bool::then` or `bool::then_some`" } pub struct IfThenSomeElseNone { From 8bae517c2d540dcf62bff12ba7404a23a4233d99 Mon Sep 17 00:00:00 2001 From: Allen Hsu Date: Fri, 12 Aug 2022 12:51:58 +1000 Subject: [PATCH 3711/5092] Lint trait duplication in one pass. --- clippy_lints/src/trait_bounds.rs | 55 +++++++------------ ...ait_duplication_in_bounds_unfixable.stderr | 8 +-- 2 files changed, 23 insertions(+), 40 deletions(-) diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 537e6eafb175..0434720f79b5 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -103,7 +103,6 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { fn check_generics(&mut self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) { self.check_type_repetition(cx, gen); check_trait_bound_duplication(cx, gen); - check_bounds_or_where_duplication(cx, gen); } fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { @@ -234,7 +233,7 @@ impl TraitBounds { } fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { - if gen.span.from_expansion() || gen.params.is_empty() || gen.predicates.is_empty() { + if gen.span.from_expansion() { return; } @@ -254,9 +253,9 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { if let WherePredicate::BoundPredicate(bound_predicate) = pred; if let TyKind::Path(QPath::Resolved(_, path)) = bound_predicate.bounded_ty.kind; then { - return Some(bound_predicate.bounds.iter().filter_map(|t| { - Some((path.res, into_comparable_trait_ref(t.trait_ref()?))) - })) + return Some( + rollup_traits(cx, bound_predicate.bounds, "these where clauses contain repeated elements") + .into_keys().map(|trait_ref| (path.res, trait_ref))) } } None @@ -277,19 +276,18 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { if !bound_predicate.span.from_expansion(); if let TyKind::Path(QPath::Resolved(_, path)) = bound_predicate.bounded_ty.kind; then { - for t in bound_predicate.bounds { - if let Some(trait_ref) = t.trait_ref() { - let key = (path.res, into_comparable_trait_ref(trait_ref)); - if where_predicates.contains(&key) { - span_lint_and_help( - cx, - TRAIT_DUPLICATION_IN_BOUNDS, - t.span(), - "this trait bound is already specified in the where clause", - None, - "consider removing this trait bound", - ); - } + let traits = rollup_traits(cx, bound_predicate.bounds, "these bounds contain repeated elements"); + for (trait_ref, span) in traits { + let key = (path.res, trait_ref); + if where_predicates.contains(&key) { + span_lint_and_help( + cx, + TRAIT_DUPLICATION_IN_BOUNDS, + span, + "this trait bound is already specified in the where clause", + None, + "consider removing this trait bound", + ); } } } @@ -300,23 +298,6 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { #[derive(PartialEq, Eq, Hash, Debug)] struct ComparableTraitRef(Res, Vec); -fn check_bounds_or_where_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { - if gen.span.from_expansion() { - return; - } - - for predicate in gen.predicates { - if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate { - let msg = if predicate.in_where_clause() { - "these where clauses contain repeated elements" - } else { - "these bounds contain repeated elements" - }; - rollup_traits(cx, bound_predicate.bounds, msg); - } - } -} - fn get_trait_info_from_bound<'a>(bound: &'a GenericBound<'_>) -> Option<(Res, &'a [PathSegment<'a>], Span)> { if let GenericBound::Trait(t, tbm) = bound { let trait_path = t.trait_ref.path; @@ -358,7 +339,7 @@ fn into_comparable_trait_ref(trait_ref: &TraitRef<'_>) -> ComparableTraitRef { ) } -fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) { +fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) -> FxHashMap { let mut map = FxHashMap::default(); let mut repeated_res = false; @@ -400,4 +381,6 @@ fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) { ); } } + + map } diff --git a/tests/ui/trait_duplication_in_bounds_unfixable.stderr b/tests/ui/trait_duplication_in_bounds_unfixable.stderr index fbd9abb005f1..aa44114eb6c5 100644 --- a/tests/ui/trait_duplication_in_bounds_unfixable.stderr +++ b/tests/ui/trait_duplication_in_bounds_unfixable.stderr @@ -1,8 +1,8 @@ error: this trait bound is already specified in the where clause - --> $DIR/trait_duplication_in_bounds_unfixable.rs:6:15 + --> $DIR/trait_duplication_in_bounds_unfixable.rs:6:23 | LL | fn bad_foo(arg0: T, arg1: Z) - | ^^^^^ + | ^^^^^^^ | note: the lint level is defined here --> $DIR/trait_duplication_in_bounds_unfixable.rs:1:9 @@ -12,10 +12,10 @@ LL | #![deny(clippy::trait_duplication_in_bounds)] = help: consider removing this trait bound error: this trait bound is already specified in the where clause - --> $DIR/trait_duplication_in_bounds_unfixable.rs:6:23 + --> $DIR/trait_duplication_in_bounds_unfixable.rs:6:15 | LL | fn bad_foo(arg0: T, arg1: Z) - | ^^^^^^^ + | ^^^^^ | = help: consider removing this trait bound From 3c4aec500f4d47e99f35837a3da82115d3af3a89 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 31 Jul 2022 14:22:27 -0700 Subject: [PATCH 3712/5092] Update clippy for introduction of Node::ExprField --- clippy_lints/src/dereference.rs | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 5d41c63928df..59f10247a11d 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; use clippy_utils::ty::{expr_sig, peel_mid_ty_refs, ty_sig, variant_of_res}; -use clippy_utils::{get_parent_expr, is_lint_allowed, path_to_local, walk_to_expr_usage}; +use clippy_utils::{get_parent_expr, get_parent_expr_for_hir, is_lint_allowed, path_to_local, walk_to_expr_usage}; use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX}; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::Applicability; @@ -699,6 +699,19 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & Some(ty_auto_deref_stability(cx, output, precedence).position_for_result(cx)) }, + Node::ExprField(field) if field.span.ctxt() == ctxt => match get_parent_expr_for_hir(cx, field.hir_id) { + Some(Expr { + hir_id, + kind: ExprKind::Struct(path, ..), + .. + }) => variant_of_res(cx, cx.qpath_res(path, *hir_id)) + .and_then(|variant| variant.fields.iter().find(|f| f.name == field.ident.name)) + .map(|field_def| { + ty_auto_deref_stability(cx, cx.tcx.type_of(field_def.did), precedence).position_for_arg() + }), + _ => None, + }, + Node::Expr(parent) if parent.span.ctxt() == ctxt => match parent.kind { ExprKind::Ret(_) => { let owner_id = cx.tcx.hir().body_owner(cx.enclosing_body.unwrap()); @@ -788,17 +801,6 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & } }) }, - ExprKind::Struct(path, fields, _) => { - let variant = variant_of_res(cx, cx.qpath_res(path, parent.hir_id)); - fields - .iter() - .find(|f| f.expr.hir_id == child_id) - .zip(variant) - .and_then(|(field, variant)| variant.fields.iter().find(|f| f.name == field.ident.name)) - .map(|field| { - ty_auto_deref_stability(cx, cx.tcx.type_of(field.did), precedence).position_for_arg() - }) - }, ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess(name.name)), ExprKind::Unary(UnOp::Deref, child) if child.hir_id == e.hir_id => Some(Position::Deref), ExprKind::Match(child, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar) From 74e87b1dc573c2488c6cd319216f08b0c39d7e6f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 12 Aug 2022 11:24:55 -0400 Subject: [PATCH 3713/5092] add test for raw_eq on a pointer --- tests/fail/intrinsics/raw_eq_on_ptr.rs | 11 +++++++++++ tests/fail/intrinsics/raw_eq_on_ptr.stderr | 14 ++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 tests/fail/intrinsics/raw_eq_on_ptr.rs create mode 100644 tests/fail/intrinsics/raw_eq_on_ptr.stderr diff --git a/tests/fail/intrinsics/raw_eq_on_ptr.rs b/tests/fail/intrinsics/raw_eq_on_ptr.rs new file mode 100644 index 000000000000..675b7cf9224b --- /dev/null +++ b/tests/fail/intrinsics/raw_eq_on_ptr.rs @@ -0,0 +1,11 @@ +#![feature(intrinsics)] + +extern "rust-intrinsic" { + fn raw_eq(a: &T, b: &T) -> bool; +} + +fn main() { + let x = &0; + // FIXME: the error message is not great (should be UB rather than 'unsupported') + unsafe { raw_eq(&x, &x) }; //~ERROR: unsupported operation +} diff --git a/tests/fail/intrinsics/raw_eq_on_ptr.stderr b/tests/fail/intrinsics/raw_eq_on_ptr.stderr new file mode 100644 index 000000000000..6c5e618315c8 --- /dev/null +++ b/tests/fail/intrinsics/raw_eq_on_ptr.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: unable to turn pointer into raw bytes + --> $DIR/raw_eq_on_ptr.rs:LL:CC + | +LL | unsafe { raw_eq(&x, &x) }; + | ^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = note: backtrace: + = note: inside `main` at $DIR/raw_eq_on_ptr.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + From 1a3192a331395e31973bb6d4e384a842172a9bda Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Tue, 9 Aug 2022 09:56:13 -0400 Subject: [PATCH 3714/5092] Adjust cfgs --- clippy_dev/src/lib.rs | 1 - clippy_lints/src/lib.rs | 1 - clippy_utils/src/lib.rs | 1 - src/driver.rs | 2 +- 4 files changed, 1 insertion(+), 4 deletions(-) diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index 8536e2429926..8a6bd1cbdf56 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -1,4 +1,3 @@ -#![cfg_attr(bootstrap, feature(let_chains))] #![feature(let_else)] #![feature(once_cell)] #![feature(rustc_private)] diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 2975399a8bbb..e6a405f8170d 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -4,7 +4,6 @@ #![feature(control_flow_enum)] #![feature(drain_filter)] #![feature(iter_intersperse)] -#![cfg_attr(bootstrap, feature(let_chains))] #![feature(let_else)] #![feature(lint_reasons)] #![feature(never_type)] diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 2616a578bb88..dc772e5efeef 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2,7 +2,6 @@ #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(let_else)] -#![cfg_attr(bootstrap, feature(let_chains))] #![feature(lint_reasons)] #![feature(once_cell)] #![feature(rustc_private)] diff --git a/src/driver.rs b/src/driver.rs index c1ec2bd5bd66..235eae5af1ec 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -95,7 +95,7 @@ struct ClippyCallbacks { impl rustc_driver::Callbacks for ClippyCallbacks { // JUSTIFICATION: necessary in clippy driver to set `mir_opt_level` - #[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] + #[allow(rustc::bad_opt_access)] fn config(&mut self, config: &mut interface::Config) { let previous = config.register_lints.take(); let clippy_args_var = self.clippy_args_var.take(); From 35486cb6610ec3423911db4a546a77472eac0e72 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Mon, 8 Aug 2022 21:42:27 +0200 Subject: [PATCH 3715/5092] Update Changelog to 1.63 --- CHANGELOG.md | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 148 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ea7e76ee108..a5014831fa2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,157 @@ document. ## Unreleased / In Rust Nightly -[7c21f91b...master](https://github.com/rust-lang/rust-clippy/compare/7c21f91b...master) +[d7b5cbf0...master](https://github.com/rust-lang/rust-clippy/compare/d7b5cbf0...master) + +## Rust 1.63 + +Current stable, released 2022-08-11 + +[7c21f91b...d7b5cbf0](https://github.com/rust-lang/rust-clippy/compare/7c21f91b...d7b5cbf0) + +### New Lints + +* [`borrow_deref_ref`] + [#7930](https://github.com/rust-lang/rust-clippy/pull/7930) +* [`doc_link_with_quotes`] + [#8385](https://github.com/rust-lang/rust-clippy/pull/8385) +* [`no_effect_replace`] + [#8754](https://github.com/rust-lang/rust-clippy/pull/8754) +* [`rc_clone_in_vec_init`] + [#8769](https://github.com/rust-lang/rust-clippy/pull/8769) +* [`derive_partial_eq_without_eq`] + [#8796](https://github.com/rust-lang/rust-clippy/pull/8796) +* [`mismatching_type_param_order`] + [#8831](https://github.com/rust-lang/rust-clippy/pull/8831) +* [`duplicate_mod`] [#8832](https://github.com/rust-lang/rust-clippy/pull/8832) +* [`unused_rounding`] + [#8866](https://github.com/rust-lang/rust-clippy/pull/8866) +* [`get_first`] [#8882](https://github.com/rust-lang/rust-clippy/pull/8882) +* [`swap_ptr_to_ref`] + [#8916](https://github.com/rust-lang/rust-clippy/pull/8916) +* [`almost_complete_letter_range`] + [#8918](https://github.com/rust-lang/rust-clippy/pull/8918) +* [`needless_parens_on_range_literals`] + [#8933](https://github.com/rust-lang/rust-clippy/pull/8933) +* [`as_underscore`] [#8934](https://github.com/rust-lang/rust-clippy/pull/8934) + +### Moves and Deprecations + +* Rename `eval_order_dependence` to [`mixed_read_write_in_expression`], move to + `nursery` [#8621](https://github.com/rust-lang/rust-clippy/pull/8621) + +### Enhancements + +* [`undocumented_unsafe_blocks`]: Now also lints on unsafe trait implementations + [#8761](https://github.com/rust-lang/rust-clippy/pull/8761) +* [`empty_line_after_outer_attr`]: Now also lints on argumentless macros + [#8790](https://github.com/rust-lang/rust-clippy/pull/8790) +* [`expect_used`]: Now can be disabled in tests with the `allow-expect-in-tests` + option [#8802](https://github.com/rust-lang/rust-clippy/pull/8802) +* [`unwrap_used`]: Now can be disabled in tests with the `allow-unwrap-in-tests` + option [#8802](https://github.com/rust-lang/rust-clippy/pull/8802) +* [`disallowed_methods`]: Now also lints indirect usages + [#8852](https://github.com/rust-lang/rust-clippy/pull/8852) +* [`get_last_with_len`]: Now also lints `VecDeque` and any deref to slice + [#8862](https://github.com/rust-lang/rust-clippy/pull/8862) +* [`manual_range_contains`]: Now also lints on chains of `&&` and `||` + [#8884](https://github.com/rust-lang/rust-clippy/pull/8884) +* [`rc_clone_in_vec_init`]: Now also lints on `Weak` + [#8885](https://github.com/rust-lang/rust-clippy/pull/8885) +* [`dbg_macro`]: Introduce `allow-dbg-in-tests` config option + [#8897](https://github.com/rust-lang/rust-clippy/pull/8897) +* [`use_self`]: Now also lints on `TupleStruct` and `Struct` patterns + [#8899](https://github.com/rust-lang/rust-clippy/pull/8899) +* [`manual_find_map`] and [`manual_filter_map`]: Now also lints on more complex + method chains inside `map` + [#8930](https://github.com/rust-lang/rust-clippy/pull/8930) +* [`needless_return`]: Now also lints on macro expressions in return statements + [#8932](https://github.com/rust-lang/rust-clippy/pull/8932) +* [`doc_markdown`]: Users can now indicate, that the `doc-valid-idents` config + should extend the default and not replace it + [#8944](https://github.com/rust-lang/rust-clippy/pull/8944) +* [`disallowed_names`]: Users can now indicate, that the `disallowed-names` + config should extend the default and not replace it + [#8944](https://github.com/rust-lang/rust-clippy/pull/8944) +* [`never_loop`]: Now checks for `continue` in struct expression + [#9002](https://github.com/rust-lang/rust-clippy/pull/9002) + +### False Positive Fixes + +* [`useless_transmute`]: No longer lints on types with erased regions + [#8564](https://github.com/rust-lang/rust-clippy/pull/8564) +* [`vec_init_then_push`]: No longer lints when further extended + [#8699](https://github.com/rust-lang/rust-clippy/pull/8699) +* [`cmp_owned`]: No longer lints on `From::from` for `Copy` types + [#8807](https://github.com/rust-lang/rust-clippy/pull/8807) +* [`redundant_allocation`]: No longer lints on fat pointers that would become + thin pointers [#8813](https://github.com/rust-lang/rust-clippy/pull/8813) +* [`derive_partial_eq_without_eq`]: + * Handle differing predicates applied by `#[derive(PartialEq)]` and + `#[derive(Eq)]` + [#8869](https://github.com/rust-lang/rust-clippy/pull/8869) + * No longer lints on non-public types and better handles generics + [#8950](https://github.com/rust-lang/rust-clippy/pull/8950) +* [`empty_line_after_outer_attr`]: No longer lints empty lines in inner + string values [#8892](https://github.com/rust-lang/rust-clippy/pull/8892) +* [`branches_sharing_code`]: No longer lints when using different binding names + [#8901](https://github.com/rust-lang/rust-clippy/pull/8901) +* [`significant_drop_in_scrutinee`]: No longer lints on Try `?` and `await` + desugared expressions [#8902](https://github.com/rust-lang/rust-clippy/pull/8902) +* [`checked_conversions`]: No longer lints in `const` contexts + [#8907](https://github.com/rust-lang/rust-clippy/pull/8907) +* [`iter_overeager_cloned`]: No longer lints on `.cloned().flatten()` when + `T::Item` doesn't implement `IntoIterator` + [#8960](https://github.com/rust-lang/rust-clippy/pull/8960) + +### Suggestion Fixes/Improvements + +* [`vec_init_then_push`]: Suggest to remove `mut` binding when possible + [#8699](https://github.com/rust-lang/rust-clippy/pull/8699) +* [`manual_range_contains`]: Fix suggestion for integers with different signs + [#8763](https://github.com/rust-lang/rust-clippy/pull/8763) +* [`identity_op`]: Add parenthesis to suggestions where required + [#8786](https://github.com/rust-lang/rust-clippy/pull/8786) +* [`cast_lossless`]: No longer gives wrong suggestion on `usize`/`isize`->`f64` + [#8778](https://github.com/rust-lang/rust-clippy/pull/8778) +* [`rc_clone_in_vec_init`]: Add suggestion + [#8814](https://github.com/rust-lang/rust-clippy/pull/8814) +* The "unknown field" error messages for config files now wraps the field names + [#8823](https://github.com/rust-lang/rust-clippy/pull/8823) +* [`cast_abs_to_unsigned`]: Do not remove cast if it's required + [#8876](https://github.com/rust-lang/rust-clippy/pull/8876) +* [`significant_drop_in_scrutinee`]: Improve lint message for types that are not + references and not trivially clone-able + [#8902](https://github.com/rust-lang/rust-clippy/pull/8902) +* [`for_loops_over_fallibles`]: Now suggests the correct variant of `iter()`, + `iter_mut()` or `into_iter()` + [#8941](https://github.com/rust-lang/rust-clippy/pull/8941) + +### ICE Fixes + +* Fix ICE in [`let_unit_value`] when calling a `static`/`const` callable type + [#8835](https://github.com/rust-lang/rust-clippy/pull/8835) +* Fix ICEs on callable `static`/`const`s + [#8896](https://github.com/rust-lang/rust-clippy/pull/8896) +* [`needless_late_init`] + [#8912](https://github.com/rust-lang/rust-clippy/pull/8912) +* Fix ICE in shadow lints + [#8913](https://github.com/rust-lang/rust-clippy/pull/8913) + +### Documentation Improvements + +* Clippy has a [Book](https://doc.rust-lang.org/nightly/clippy/) now! + [#7359](https://github.com/rust-lang/rust-clippy/pull/7359) +* Add a *copy lint name*-button to Clippy's lint list + [#8839](https://github.com/rust-lang/rust-clippy/pull/8839) +* Display past names of renamed lints on Clippy's lint list + [#8843](https://github.com/rust-lang/rust-clippy/pull/8843) +* Add the ability to show the lint output in the lint list + [#8947](https://github.com/rust-lang/rust-clippy/pull/8947) ## Rust 1.62 -Current stable, released 2022-06-30 +Released 2022-06-30 [d0cf3481...7c21f91b](https://github.com/rust-lang/rust-clippy/compare/d0cf3481...7c21f91b) From f18cd274be3595c5b065fdba2b75ce9e8adc6c25 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Fri, 12 Aug 2022 23:19:53 +0200 Subject: [PATCH 3716/5092] Update lint versions for 1.63 release --- clippy_lints/src/borrow_deref_ref.rs | 2 +- clippy_lints/src/doc_link_with_quotes.rs | 2 +- clippy_lints/src/duplicate_mod.rs | 2 +- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/mismatching_type_param_order.rs | 2 +- clippy_lints/src/rc_clone_in_vec_init.rs | 2 +- clippy_lints/src/unused_rounding.rs | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs index 937765b66147..e65b67c655ec 100644 --- a/clippy_lints/src/borrow_deref_ref.rs +++ b/clippy_lints/src/borrow_deref_ref.rs @@ -44,7 +44,7 @@ declare_clippy_lint! { /// let a: &String = s; /// foo(&**s); /// ``` - #[clippy::version = "1.59.0"] + #[clippy::version = "1.63.0"] pub BORROW_DEREF_REF, complexity, "deref on an immutable reference returns the same type as itself" diff --git a/clippy_lints/src/doc_link_with_quotes.rs b/clippy_lints/src/doc_link_with_quotes.rs index cb07f57e8700..0ff1d2755daf 100644 --- a/clippy_lints/src/doc_link_with_quotes.rs +++ b/clippy_lints/src/doc_link_with_quotes.rs @@ -21,7 +21,7 @@ declare_clippy_lint! { /// /// See also: [`foo`] /// fn bar() {} /// ``` - #[clippy::version = "1.60.0"] + #[clippy::version = "1.63.0"] pub DOC_LINK_WITH_QUOTES, pedantic, "possible typo for an intra-doc link" diff --git a/clippy_lints/src/duplicate_mod.rs b/clippy_lints/src/duplicate_mod.rs index e1eb3b6324c7..7ff7068f0b05 100644 --- a/clippy_lints/src/duplicate_mod.rs +++ b/clippy_lints/src/duplicate_mod.rs @@ -39,7 +39,7 @@ declare_clippy_lint! { /// // a.rs /// use crate::b; /// ``` - #[clippy::version = "1.62.0"] + #[clippy::version = "1.63.0"] pub DUPLICATE_MOD, suspicious, "file loaded as module multiple times" diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5ac6b09f0aa2..b8dba5ba165f 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2269,7 +2269,7 @@ declare_clippy_lint! { /// "1234".replace("12", "12"); /// "1234".replacen("12", "12", 1); /// ``` - #[clippy::version = "1.62.0"] + #[clippy::version = "1.63.0"] pub NO_EFFECT_REPLACE, suspicious, "replace with no effect" diff --git a/clippy_lints/src/mismatching_type_param_order.rs b/clippy_lints/src/mismatching_type_param_order.rs index f763e0d24c94..020efeaebf02 100644 --- a/clippy_lints/src/mismatching_type_param_order.rs +++ b/clippy_lints/src/mismatching_type_param_order.rs @@ -40,7 +40,7 @@ declare_clippy_lint! { /// } /// impl Foo {} /// ``` - #[clippy::version = "1.62.0"] + #[clippy::version = "1.63.0"] pub MISMATCHING_TYPE_PARAM_ORDER, pedantic, "type parameter positioned inconsistently between type def and impl block" diff --git a/clippy_lints/src/rc_clone_in_vec_init.rs b/clippy_lints/src/rc_clone_in_vec_init.rs index 8db8c4e9b787..e82aa3a7b989 100644 --- a/clippy_lints/src/rc_clone_in_vec_init.rs +++ b/clippy_lints/src/rc_clone_in_vec_init.rs @@ -41,7 +41,7 @@ declare_clippy_lint! { /// let data = std::rc::Rc::new("some data".to_string()); /// let v = vec![data; 100]; /// ``` - #[clippy::version = "1.62.0"] + #[clippy::version = "1.63.0"] pub RC_CLONE_IN_VEC_INIT, suspicious, "initializing reference-counted pointer in `vec![elem; len]`" diff --git a/clippy_lints/src/unused_rounding.rs b/clippy_lints/src/unused_rounding.rs index 306afe441484..72d8a4431fd3 100644 --- a/clippy_lints/src/unused_rounding.rs +++ b/clippy_lints/src/unused_rounding.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// ```rust /// let x = 1f32; /// ``` - #[clippy::version = "1.62.0"] + #[clippy::version = "1.63.0"] pub UNUSED_ROUNDING, nursery, "Uselessly rounding a whole number floating-point literal" From e75b2c8543ee08abed6f3d072447afc514af13bb Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Sat, 13 Aug 2022 13:20:56 +0100 Subject: [PATCH 3717/5092] Breaking posix_memalign precondition is not UB --- src/shims/unix/foreign_items.rs | 34 ++++++-------- tests/pass/posix_memalign.rs | 83 +++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 19 deletions(-) create mode 100644 tests/pass/posix_memalign.rs diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 3dea8f203bb7..877a144963a2 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -186,27 +186,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let align = this.read_scalar(align)?.to_machine_usize(this)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; // Align must be power of 2, and also at least ptr-sized (POSIX rules). - if !align.is_power_of_two() { - throw_ub_format!("posix_memalign: alignment must be a power of two, but is {}", align); - } - if align < this.pointer_size().bytes() { - throw_ub_format!( - "posix_memalign: alignment must be at least the size of a pointer, but is {}", - align, - ); - } - - if size == 0 { - this.write_null(&ret.into())?; + // But failure to adhere to this is not UB, it's an error condition. + if !align.is_power_of_two() || align < this.pointer_size().bytes() { + let einval = this.eval_libc_i32("EINVAL")?; + this.write_int(einval, dest)?; } else { - let ptr = this.allocate_ptr( - Size::from_bytes(size), - Align::from_bytes(align).unwrap(), - MiriMemoryKind::C.into(), - )?; - this.write_pointer(ptr, &ret.into())?; + if size == 0 { + this.write_null(&ret.into())?; + } else { + let ptr = this.allocate_ptr( + Size::from_bytes(size), + Align::from_bytes(align).unwrap(), + MiriMemoryKind::C.into(), + )?; + this.write_pointer(ptr, &ret.into())?; + } + this.write_null(dest)?; } - this.write_null(dest)?; } // Dynamic symbol loading diff --git a/tests/pass/posix_memalign.rs b/tests/pass/posix_memalign.rs new file mode 100644 index 000000000000..5dadb62436d6 --- /dev/null +++ b/tests/pass/posix_memalign.rs @@ -0,0 +1,83 @@ +//@ignore-target-windows: No libc on Windows + +#![feature(rustc_private)] +#![feature(pointer_is_aligned)] +#![feature(strict_provenance)] + +use core::ptr; + +fn main() { + // A normal allocation. + unsafe { + let mut ptr: *mut libc::c_void = ptr::null_mut(); + let align = 8; + let size = 64; + assert_eq!(libc::posix_memalign(&mut ptr, align, size), 0); + assert!(!ptr.is_null()); + assert!(ptr.is_aligned_to(align)); + ptr.cast::().write_bytes(1, size); + libc::free(ptr); + } + + // Align > size. + unsafe { + let mut ptr: *mut libc::c_void = ptr::null_mut(); + let align = 64; + let size = 8; + assert_eq!(libc::posix_memalign(&mut ptr, align, size), 0); + assert!(!ptr.is_null()); + assert!(ptr.is_aligned_to(align)); + ptr.cast::().write_bytes(1, size); + libc::free(ptr); + } + + // Size not multiple of align + unsafe { + let mut ptr: *mut libc::c_void = ptr::null_mut(); + let align = 16; + let size = 31; + assert_eq!(libc::posix_memalign(&mut ptr, align, size), 0); + assert!(!ptr.is_null()); + assert!(ptr.is_aligned_to(align)); + ptr.cast::().write_bytes(1, size); + libc::free(ptr); + } + + // Size == 0 + unsafe { + let mut ptr: *mut libc::c_void = ptr::null_mut(); + let align = 64; + let size = 0; + assert_eq!(libc::posix_memalign(&mut ptr, align, size), 0); + // We are not required to return null if size == 0, but we currently do. + // It's fine to remove this assert if we start returning non-null pointers. + assert!(ptr.is_null()); + assert!(ptr.is_aligned_to(align)); + // Regardless of what we return, it must be `free`able. + libc::free(ptr); + } + + // Non-power of 2 align + unsafe { + let mut ptr: *mut libc::c_void = ptr::invalid_mut(0x1234567); + let align = 15; + let size = 8; + assert_eq!(libc::posix_memalign(&mut ptr, align, size), libc::EINVAL); + // The pointer is not modified on failure, posix_memalign(3) says: + // > On Linux (and other systems), posix_memalign() does not modify memptr on failure. + // > A requirement standardizing this behavior was added in POSIX.1-2008 TC2. + assert_eq!(ptr.addr(), 0x1234567); + } + + // Too small align (smaller than ptr) + unsafe { + let mut ptr: *mut libc::c_void = ptr::invalid_mut(0x1234567); + let align = std::mem::size_of::() / 2; + let size = 8; + assert_eq!(libc::posix_memalign(&mut ptr, align, size), libc::EINVAL); + // The pointer is not modified on failure, posix_memalign(3) says: + // > On Linux (and other systems), posix_memalign() does not modify memptr on failure. + // > A requirement standardizing this behavior was added in POSIX.1-2008 TC2. + assert_eq!(ptr.addr(), 0x1234567); + } +} From 7df41a77b821946e2f187d938e4bc9ef49e03f79 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 13 Aug 2022 08:22:19 -0400 Subject: [PATCH 3718/5092] rustup --- rust-version | 2 +- src/lib.rs | 1 + tests/fail/const-ub-checks.rs | 11 +++++++++++ tests/fail/const-ub-checks.stderr | 9 +++++++++ 4 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 tests/fail/const-ub-checks.rs create mode 100644 tests/fail/const-ub-checks.stderr diff --git a/rust-version b/rust-version index 0bcadc0a366f..fdd18704d184 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -20ffea6938b5839c390252e07940b99e3b6a889a +75b7e52e92c3b00fc891b47f5b2efdff0a2be55a diff --git a/src/lib.rs b/src/lib.rs index 94958b2ff5fb..ba337f28311e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -116,4 +116,5 @@ pub const MIRI_DEFAULT_ARGS: &[&str] = &[ "-Zmir-opt-level=0", "--cfg=miri", "-Cdebug-assertions=on", + "-Zextra-const-ub-checks", ]; diff --git a/tests/fail/const-ub-checks.rs b/tests/fail/const-ub-checks.rs new file mode 100644 index 000000000000..fa522c30cbd0 --- /dev/null +++ b/tests/fail/const-ub-checks.rs @@ -0,0 +1,11 @@ +#![feature(const_ptr_read)] + +const UNALIGNED_READ: () = unsafe { + let x = &[0u8; 4]; + let ptr = x.as_ptr().cast::(); + ptr.read(); //~ERROR: evaluation of constant value failed +}; + +fn main() { + let _x = UNALIGNED_READ; +} diff --git a/tests/fail/const-ub-checks.stderr b/tests/fail/const-ub-checks.stderr new file mode 100644 index 000000000000..a8b7ea242b97 --- /dev/null +++ b/tests/fail/const-ub-checks.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const-ub-checks.rs:LL:CC + | +LL | ptr.read(); + | ^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. From d59bad95fdd0157df3bfcbfb878bc7c451d0bee2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 13 Aug 2022 09:03:30 -0400 Subject: [PATCH 3719/5092] fix data_race test --- tests/pass/concurrency/data_race.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/pass/concurrency/data_race.rs b/tests/pass/concurrency/data_race.rs index 5d1e1bb266ca..9c7030db3db8 100644 --- a/tests/pass/concurrency/data_race.rs +++ b/tests/pass/concurrency/data_race.rs @@ -1,5 +1,5 @@ //@ignore-target-windows: Concurrency on Windows is not supported yet. -//@compile-flags: -Zmiri-disable-weak-memory-emulation +//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::sync::atomic::{fence, AtomicUsize, Ordering}; use std::thread::spawn; @@ -10,9 +10,9 @@ struct EvilSend(pub T); unsafe impl Send for EvilSend {} unsafe impl Sync for EvilSend {} -static SYNC: AtomicUsize = AtomicUsize::new(0); - fn test_fence_sync() { + static SYNC: AtomicUsize = AtomicUsize::new(0); + let mut var = 0u32; let ptr = &mut var as *mut u32; let evil_ptr = EvilSend(ptr); @@ -28,7 +28,7 @@ fn test_fence_sync() { fence(Ordering::Acquire); unsafe { *evil_ptr.0 } } else { - 0 + panic!(); // relies on thread 2 going last } }); @@ -56,6 +56,8 @@ fn test_multiple_reads() { } pub fn test_rmw_no_block() { + static SYNC: AtomicUsize = AtomicUsize::new(0); + let mut a = 0u32; let b = &mut a as *mut u32; let c = EvilSend(b); @@ -77,11 +79,13 @@ pub fn test_rmw_no_block() { j1.join().unwrap(); j2.join().unwrap(); let v = j3.join().unwrap(); - assert!(v == 1 || v == 2); + assert!(v == 1 || v == 2); // relies on thread 3 going last } } pub fn test_simple_release() { + static SYNC: AtomicUsize = AtomicUsize::new(0); + let mut a = 0u32; let b = &mut a as *mut u32; let c = EvilSend(b); @@ -95,7 +99,7 @@ pub fn test_simple_release() { let j2 = spawn(move || if SYNC.load(Ordering::Acquire) == 1 { *c.0 } else { 0 }); j1.join().unwrap(); - assert_eq!(j2.join().unwrap(), 1); + assert_eq!(j2.join().unwrap(), 1); // relies on thread 2 going last } } From 66dcf5dfee0942d09d7a030a5c891d0a79cd8426 Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Sun, 14 Aug 2022 10:37:03 +0100 Subject: [PATCH 3720/5092] Enable eager checks for memory sanitizer --- .../rustc_llvm/llvm-wrapper/PassWrapper.cpp | 15 +++++++- src/test/ui/sanitize/memory-eager.rs | 35 +++++++++++++++++++ src/test/ui/sanitize/memory.rs | 6 ++-- 3 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/sanitize/memory-eager.rs diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 0a6bd49992d9..37494623e3a8 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -131,7 +131,12 @@ extern "C" LLVMPassRef LLVMRustCreateMemorySanitizerPass(int TrackOrigins, bool const bool CompileKernel = false; return wrap(createMemorySanitizerLegacyPassPass( - MemorySanitizerOptions{TrackOrigins, Recover, CompileKernel})); +#if LLVM_VERSION_GE(14, 0) + MemorySanitizerOptions{TrackOrigins, Recover, CompileKernel, /*EagerChecks=*/true} +#else + MemorySanitizerOptions{TrackOrigins, Recover, CompileKernel} +#endif + )); #else report_fatal_error("Legacy PM not supported with LLVM 15"); #endif @@ -931,10 +936,18 @@ LLVMRustOptimizeWithNewPassManager( if (SanitizerOptions) { if (SanitizerOptions->SanitizeMemory) { +#if LLVM_VERSION_GE(14, 0) + MemorySanitizerOptions Options( + SanitizerOptions->SanitizeMemoryTrackOrigins, + SanitizerOptions->SanitizeMemoryRecover, + /*CompileKernel=*/false, + /*EagerChecks=*/true); +#else MemorySanitizerOptions Options( SanitizerOptions->SanitizeMemoryTrackOrigins, SanitizerOptions->SanitizeMemoryRecover, /*CompileKernel=*/false); +#endif OptimizerLastEPCallbacks.push_back( [Options](ModulePassManager &MPM, OptimizationLevel Level) { #if LLVM_VERSION_GE(14, 0) diff --git a/src/test/ui/sanitize/memory-eager.rs b/src/test/ui/sanitize/memory-eager.rs new file mode 100644 index 000000000000..0c51ed6d1c72 --- /dev/null +++ b/src/test/ui/sanitize/memory-eager.rs @@ -0,0 +1,35 @@ +// needs-sanitizer-support +// needs-sanitizer-memory +// min-llvm-version: 14.0.0 +// +// compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins -O +// +// run-fail +// error-pattern: MemorySanitizer: use-of-uninitialized-value +// error-pattern: Uninitialized value was created by an allocation +// error-pattern: in the stack frame of function 'random' +// +// This test case intentionally limits the usage of the std, +// since it will be linked with an uninstrumented version of it. + +#![feature(core_intrinsics)] +#![feature(start)] +#![feature(bench_black_box)] + +use std::hint::black_box; +use std::mem::MaybeUninit; + +#[inline(never)] +#[no_mangle] +#[allow(invalid_value)] +fn random() -> char { + let r = unsafe { MaybeUninit::uninit().assume_init() }; + // Avoid optimizing everything out. + black_box(r) +} + +#[start] +fn main(_: isize, _: *const *const u8) -> isize { + random(); + 0 +} diff --git a/src/test/ui/sanitize/memory.rs b/src/test/ui/sanitize/memory.rs index 83f79679c6e6..85d34668d1ba 100644 --- a/src/test/ui/sanitize/memory.rs +++ b/src/test/ui/sanitize/memory.rs @@ -21,9 +21,9 @@ use std::mem::MaybeUninit; #[inline(never)] #[no_mangle] fn random() -> [isize; 32] { - let r = unsafe { MaybeUninit::uninit().assume_init() }; + let r = MaybeUninit::uninit(); // Avoid optimizing everything out. - black_box(r) + unsafe { std::intrinsics::volatile_load(r.as_ptr()) } } #[inline(never)] @@ -38,6 +38,6 @@ fn xor(a: &[isize]) -> isize { #[start] fn main(_: isize, _: *const *const u8) -> isize { - let r = random(); + let r = black_box(random as fn() -> [isize; 32])(); xor(&r) } From 16525cc4c34649c564e9544ec1d9c45c4c4f4e52 Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Sat, 16 Jul 2022 12:08:48 +0100 Subject: [PATCH 3721/5092] Emit noundef even for unoptimised code if msan is on --- compiler/rustc_codegen_llvm/src/abi.rs | 8 ++++++++ src/test/ui/sanitize/memory-eager.rs | 5 ++++- src/test/ui/sanitize/memory.rs | 5 ++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 9eb3574e77b0..461be98f2100 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -19,6 +19,7 @@ use rustc_target::abi::call::ArgAbi; pub use rustc_target::abi::call::*; use rustc_target::abi::{self, HasDataLayout, Int}; pub use rustc_target::spec::abi::Abi; +use rustc_target::spec::SanitizerSet; use libc::c_uint; use smallvec::SmallVec; @@ -90,6 +91,13 @@ fn get_attrs<'ll>(this: &ArgAttributes, cx: &CodegenCx<'ll, '_>) -> SmallVec<[&' if regular.contains(ArgAttribute::NoAliasMutRef) && should_use_mutable_noalias(cx) { attrs.push(llvm::AttributeKind::NoAlias.create_attr(cx.llcx)); } + } else if cx.tcx.sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::MEMORY) { + // If we're not optimising, *but* memory sanitizer is on, emit noundef, since it affects + // memory sanitizer's behavior. + + if regular.contains(ArgAttribute::NoUndef) { + attrs.push(llvm::AttributeKind::NoUndef.create_attr(cx.llcx)); + } } attrs diff --git a/src/test/ui/sanitize/memory-eager.rs b/src/test/ui/sanitize/memory-eager.rs index 0c51ed6d1c72..8a0590bf16c5 100644 --- a/src/test/ui/sanitize/memory-eager.rs +++ b/src/test/ui/sanitize/memory-eager.rs @@ -2,7 +2,10 @@ // needs-sanitizer-memory // min-llvm-version: 14.0.0 // -// compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins -O +// revisions: unoptimized optimized +// +// [optimized]compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins -O +// [unoptimized]compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins // // run-fail // error-pattern: MemorySanitizer: use-of-uninitialized-value diff --git a/src/test/ui/sanitize/memory.rs b/src/test/ui/sanitize/memory.rs index 85d34668d1ba..ecb1a05504b9 100644 --- a/src/test/ui/sanitize/memory.rs +++ b/src/test/ui/sanitize/memory.rs @@ -1,7 +1,10 @@ // needs-sanitizer-support // needs-sanitizer-memory // -// compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins -O +// revisions: unoptimized optimized +// +// [optimized]compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins -O +// [unoptimized]compile-flags: -Z sanitizer=memory -Zsanitizer-memory-track-origins // // run-fail // error-pattern: MemorySanitizer: use-of-uninitialized-value From e70473d9442d17de7f7d38d3d7e8606226d1c4fa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Aug 2022 07:51:45 -0400 Subject: [PATCH 3722/5092] rustup --- rust-version | 2 +- tests/fail/provenance/strict_provenance_cast.rs | 3 ++- tests/fail/provenance/strict_provenance_cast.stderr | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index fdd18704d184..aaf664f44e3e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -75b7e52e92c3b00fc891b47f5b2efdff0a2be55a +2fbc08e2ce64dee45a29cb6133da6b32366268aa diff --git a/tests/fail/provenance/strict_provenance_cast.rs b/tests/fail/provenance/strict_provenance_cast.rs index 0016e7879254..04552d0c332f 100644 --- a/tests/fail/provenance/strict_provenance_cast.rs +++ b/tests/fail/provenance/strict_provenance_cast.rs @@ -1,6 +1,7 @@ //@compile-flags: -Zmiri-strict-provenance +#![feature(strict_provenance)] fn main() { let addr = &0 as *const i32 as usize; - let _ptr = addr as *const i32; //~ ERROR: integer-to-pointer casts and `ptr::from_exposed_addr` are not supported + let _ptr = std::ptr::from_exposed_addr::(addr); //~ ERROR: integer-to-pointer casts and `ptr::from_exposed_addr` are not supported } diff --git a/tests/fail/provenance/strict_provenance_cast.stderr b/tests/fail/provenance/strict_provenance_cast.stderr index ff6ab1c9e95b..5796a3196dc6 100644 --- a/tests/fail/provenance/strict_provenance_cast.stderr +++ b/tests/fail/provenance/strict_provenance_cast.stderr @@ -1,8 +1,8 @@ error: unsupported operation: integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance` --> $DIR/strict_provenance_cast.rs:LL:CC | -LL | let _ptr = addr as *const i32; - | ^^^^^^^^^^^^^^^^^^ integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance` +LL | let _ptr = std::ptr::from_exposed_addr::(addr); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance` | = help: use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead = note: backtrace: From 80826c3944df4233fd532ee8cf465851dfe1b0fc Mon Sep 17 00:00:00 2001 From: Guilherme-Vasconcelos <49197151+Guilherme-Vasconcelos@users.noreply.github.com> Date: Sun, 17 Jul 2022 21:20:51 -0300 Subject: [PATCH 3723/5092] Implement clippy::manual_empty_string_creations lint --- CHANGELOG.md | 1 + clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_style.rs | 1 + clippy_lints/src/lib.rs | 2 + .../src/manual_empty_string_creations.rs | 141 ++++++++++++++++++ clippy_utils/src/msrvs.rs | 2 +- tests/ui/manual_empty_string_creations.fixed | 63 ++++++++ tests/ui/manual_empty_string_creations.rs | 63 ++++++++ tests/ui/manual_empty_string_creations.stderr | 58 +++++++ 10 files changed, 332 insertions(+), 1 deletion(-) create mode 100644 clippy_lints/src/manual_empty_string_creations.rs create mode 100644 tests/ui/manual_empty_string_creations.fixed create mode 100644 tests/ui/manual_empty_string_creations.rs create mode 100644 tests/ui/manual_empty_string_creations.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index d74ec71a0e8b..eedbe10320d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3828,6 +3828,7 @@ Released 2018-09-13 [`manual_assert`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_assert [`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn [`manual_bits`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits +[`manual_empty_string_creations`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_empty_string_creations [`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map [`manual_find`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find [`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 01082cc8eeb6..e253f656b0de 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -124,6 +124,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(main_recursion::MAIN_RECURSION), LintId::of(manual_async_fn::MANUAL_ASYNC_FN), LintId::of(manual_bits::MANUAL_BITS), + LintId::of(manual_empty_string_creations::MANUAL_EMPTY_STRING_CREATIONS), LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE), LintId::of(manual_rem_euclid::MANUAL_REM_EUCLID), LintId::of(manual_retain::MANUAL_RETAIN), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index c540573b8022..29d923a0d8d7 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -244,6 +244,7 @@ store.register_lints(&[ manual_assert::MANUAL_ASSERT, manual_async_fn::MANUAL_ASYNC_FN, manual_bits::MANUAL_BITS, + manual_empty_string_creations::MANUAL_EMPTY_STRING_CREATIONS, manual_instant_elapsed::MANUAL_INSTANT_ELAPSED, manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE, manual_ok_or::MANUAL_OK_OR, diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs index bfa654238f13..6972c75597aa 100644 --- a/clippy_lints/src/lib.register_style.rs +++ b/clippy_lints/src/lib.register_style.rs @@ -44,6 +44,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(main_recursion::MAIN_RECURSION), LintId::of(manual_async_fn::MANUAL_ASYNC_FN), LintId::of(manual_bits::MANUAL_BITS), + LintId::of(manual_empty_string_creations::MANUAL_EMPTY_STRING_CREATIONS), LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE), LintId::of(map_clone::MAP_CLONE), LintId::of(match_result_ok::MATCH_RESULT_OK), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index e6a405f8170d..4201cd9c0bf1 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -273,6 +273,7 @@ mod main_recursion; mod manual_assert; mod manual_async_fn; mod manual_bits; +mod manual_empty_string_creations; mod manual_instant_elapsed; mod manual_non_exhaustive; mod manual_ok_or; @@ -933,6 +934,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(std_instead_of_core::StdReexports::default())); store.register_late_pass(|| Box::new(manual_instant_elapsed::ManualInstantElapsed)); store.register_late_pass(|| Box::new(partialeq_to_none::PartialeqToNone)); + store.register_late_pass(|| Box::new(manual_empty_string_creations::ManualEmptyStringCreations)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/manual_empty_string_creations.rs b/clippy_lints/src/manual_empty_string_creations.rs new file mode 100644 index 000000000000..dd602a89b4f6 --- /dev/null +++ b/clippy_lints/src/manual_empty_string_creations.rs @@ -0,0 +1,141 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use rustc_ast::LitKind; +use rustc_errors::Applicability::MachineApplicable; +use rustc_hir::{Expr, ExprKind, PathSegment, QPath, TyKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::{sym, symbol, Span}; + +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for usage of `""` to create a `String`, such as `"".to_string()`, `"".to_owned()`, + /// `String::from("")` and others. + /// + /// ### Why is this bad? + /// + /// Different ways of creating an empty string makes your code less standardized, which can + /// be confusing. + /// + /// ### Example + /// ```rust + /// let a = "".to_string(); + /// let b: String = "".into(); + /// ``` + /// Use instead: + /// ```rust + /// let a = String::new(); + /// let b = String::new(); + /// ``` + #[clippy::version = "1.65.0"] + pub MANUAL_EMPTY_STRING_CREATIONS, + style, + "empty String is being created manually" +} +declare_lint_pass!(ManualEmptyStringCreations => [MANUAL_EMPTY_STRING_CREATIONS]); + +impl LateLintPass<'_> for ManualEmptyStringCreations { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + if expr.span.from_expansion() { + return; + } + + let ty = cx.typeck_results().expr_ty(expr); + match ty.kind() { + ty::Adt(adt_def, _) if adt_def.is_struct() => { + if !cx.tcx.is_diagnostic_item(sym::String, adt_def.did()) { + return; + } + }, + _ => return, + } + + match expr.kind { + ExprKind::Call(func, args) => { + parse_call(cx, expr.span, func, args); + }, + ExprKind::MethodCall(path_segment, args, _) => { + parse_method_call(cx, expr.span, path_segment, args); + }, + _ => (), + } + } +} + +/// Checks if an expression's kind corresponds to an empty &str. +fn is_expr_kind_empty_str(expr_kind: &ExprKind<'_>) -> bool { + if let ExprKind::Lit(lit) = expr_kind && + let LitKind::Str(value, _) = lit.node && + value == symbol::kw::Empty + { + return true; + } + + false +} + +/// Emits the `MANUAL_EMPTY_STRING_CREATION` warning and suggests the appropriate fix. +fn warn_then_suggest(cx: &LateContext<'_>, span: Span) { + span_lint_and_sugg( + cx, + MANUAL_EMPTY_STRING_CREATIONS, + span, + "empty String is being created manually", + "consider using", + "String::new()".into(), + MachineApplicable, + ); +} + +/// Tries to parse an expression as a method call, emiting the warning if necessary. +fn parse_method_call(cx: &LateContext<'_>, span: Span, path_segment: &PathSegment<'_>, args: &[Expr<'_>]) { + if args.is_empty() { + // When parsing TryFrom::try_from(...).expect(...), we will have more than 1 arg. + return; + } + + let ident = path_segment.ident.as_str(); + let method_arg_kind = &args[0].kind; + if ["to_string", "to_owned", "into"].contains(&ident) && is_expr_kind_empty_str(method_arg_kind) { + warn_then_suggest(cx, span); + } else if let ExprKind::Call(func, args) = method_arg_kind { + // If our first argument is a function call itself, it could be an `unwrap`-like function. + // E.g. String::try_from("hello").unwrap(), TryFrom::try_from("").expect("hello"), etc. + parse_call(cx, span, func, args); + } +} + +/// Tries to parse an expression as a function call, emiting the warning if necessary. +fn parse_call(cx: &LateContext<'_>, span: Span, func: &Expr<'_>, args: &[Expr<'_>]) { + if args.len() != 1 { + return; + } + + let arg_kind = &args[0].kind; + if let ExprKind::Path(qpath) = &func.kind { + if let QPath::TypeRelative(_, _) = qpath { + // String::from(...) or String::try_from(...) + if let QPath::TypeRelative(ty, path_seg) = qpath && + [sym::from, sym::try_from].contains(&path_seg.ident.name) && + let TyKind::Path(qpath) = &ty.kind && + let QPath::Resolved(_, path) = qpath && + let [path_seg] = path.segments && + path_seg.ident.name == sym::String && + is_expr_kind_empty_str(arg_kind) + { + warn_then_suggest(cx, span); + } + } else if let QPath::Resolved(_, path) = qpath { + // From::from(...) or TryFrom::try_from(...) + if let [path_seg1, path_seg2] = path.segments && + is_expr_kind_empty_str(arg_kind) && ( + (path_seg1.ident.name == sym::From && path_seg2.ident.name == sym::from) || + (path_seg1.ident.name == sym::TryFrom && path_seg2.ident.name == sym::try_from) + ) + { + warn_then_suggest(cx, span); + } + } + } +} diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 9e238c6f1ac0..d539d11a39f3 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -32,8 +32,8 @@ msrv_aliases! { 1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES } 1,28,0 { FROM_BOOL } 1,26,0 { RANGE_INCLUSIVE, STRING_RETAIN } + 1,24,0 { IS_ASCII_DIGIT } 1,18,0 { HASH_MAP_RETAIN, HASH_SET_RETAIN } 1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST, EXPECT_ERR } 1,16,0 { STR_REPEAT } - 1,24,0 { IS_ASCII_DIGIT } } diff --git a/tests/ui/manual_empty_string_creations.fixed b/tests/ui/manual_empty_string_creations.fixed new file mode 100644 index 000000000000..3516312ee0c5 --- /dev/null +++ b/tests/ui/manual_empty_string_creations.fixed @@ -0,0 +1,63 @@ +// run-rustfix + +#![warn(clippy::manual_empty_string_creations)] + +macro_rules! create_strings_from_macro { + // When inside a macro, nothing should warn to prevent false positives. + ($some_str:expr) => { + let _: String = $some_str.into(); + let _ = $some_str.to_string(); + } +} + +fn main() { + // Method calls + let _ = String::new(); + let _ = "no warning".to_string(); + + let _ = String::new(); + let _ = "no warning".to_owned(); + + let _: String = String::new(); + let _: String = "no warning".into(); + + let _: SomeOtherStruct = "no warning".into(); + let _: SomeOtherStruct = "".into(); // No warning too. We are not converting into String. + + // Calls + let _ = String::new(); + let _ = String::new(); + let _ = String::from("no warning"); + let _ = SomeOtherStruct::from("no warning"); + let _ = SomeOtherStruct::from(""); // Again: no warning. + + let _ = String::new(); + let _ = String::try_from("no warning").unwrap(); + let _ = String::try_from("no warning").expect("this should not warn"); + let _ = SomeOtherStruct::try_from("no warning").unwrap(); + let _ = SomeOtherStruct::try_from("").unwrap(); // Again: no warning. + + let _: String = String::new(); + let _: String = From::from("no warning"); + let _: SomeOtherStruct = From::from("no warning"); + let _: SomeOtherStruct = From::from(""); // Again: no warning. + + let _: String = String::new(); + let _: String = TryFrom::try_from("no warning").unwrap(); + let _: String = TryFrom::try_from("no warning").expect("this should not warn"); + let _: String = String::new(); + let _: SomeOtherStruct = TryFrom::try_from("no_warning").unwrap(); + let _: SomeOtherStruct = TryFrom::try_from("").unwrap(); // Again: no warning. + + // Macros (never warn) + create_strings_from_macro!(""); + create_strings_from_macro!("Hey"); +} + +struct SomeOtherStruct {} + +impl From<&str> for SomeOtherStruct { + fn from(_value: &str) -> Self { + Self {} + } +} diff --git a/tests/ui/manual_empty_string_creations.rs b/tests/ui/manual_empty_string_creations.rs new file mode 100644 index 000000000000..ed39a05ed5c4 --- /dev/null +++ b/tests/ui/manual_empty_string_creations.rs @@ -0,0 +1,63 @@ +// run-rustfix + +#![warn(clippy::manual_empty_string_creations)] + +macro_rules! create_strings_from_macro { + // When inside a macro, nothing should warn to prevent false positives. + ($some_str:expr) => { + let _: String = $some_str.into(); + let _ = $some_str.to_string(); + }; +} + +fn main() { + // Method calls + let _ = "".to_string(); + let _ = "no warning".to_string(); + + let _ = "".to_owned(); + let _ = "no warning".to_owned(); + + let _: String = "".into(); + let _: String = "no warning".into(); + + let _: SomeOtherStruct = "no warning".into(); + let _: SomeOtherStruct = "".into(); // No warning too. We are not converting into String. + + // Calls + let _ = String::from(""); + let _ = ::from(""); + let _ = String::from("no warning"); + let _ = SomeOtherStruct::from("no warning"); + let _ = SomeOtherStruct::from(""); // Again: no warning. + + let _ = String::try_from("").unwrap(); + let _ = String::try_from("no warning").unwrap(); + let _ = String::try_from("no warning").expect("this should not warn"); + let _ = SomeOtherStruct::try_from("no warning").unwrap(); + let _ = SomeOtherStruct::try_from("").unwrap(); // Again: no warning. + + let _: String = From::from(""); + let _: String = From::from("no warning"); + let _: SomeOtherStruct = From::from("no warning"); + let _: SomeOtherStruct = From::from(""); // Again: no warning. + + let _: String = TryFrom::try_from("").unwrap(); + let _: String = TryFrom::try_from("no warning").unwrap(); + let _: String = TryFrom::try_from("no warning").expect("this should not warn"); + let _: String = TryFrom::try_from("").expect("this should warn"); + let _: SomeOtherStruct = TryFrom::try_from("no_warning").unwrap(); + let _: SomeOtherStruct = TryFrom::try_from("").unwrap(); // Again: no warning. + + // Macros (never warn) + create_strings_from_macro!(""); + create_strings_from_macro!("Hey"); +} + +struct SomeOtherStruct {} + +impl From<&str> for SomeOtherStruct { + fn from(_value: &str) -> Self { + Self {} + } +} diff --git a/tests/ui/manual_empty_string_creations.stderr b/tests/ui/manual_empty_string_creations.stderr new file mode 100644 index 000000000000..f38ba02a508f --- /dev/null +++ b/tests/ui/manual_empty_string_creations.stderr @@ -0,0 +1,58 @@ +error: empty String is being created manually + --> $DIR/manual_empty_string_creations.rs:15:13 + | +LL | let _ = "".to_string(); + | ^^^^^^^^^^^^^^ help: consider using: `String::new()` + | + = note: `-D clippy::manual-empty-string-creations` implied by `-D warnings` + +error: empty String is being created manually + --> $DIR/manual_empty_string_creations.rs:18:13 + | +LL | let _ = "".to_owned(); + | ^^^^^^^^^^^^^ help: consider using: `String::new()` + +error: empty String is being created manually + --> $DIR/manual_empty_string_creations.rs:21:21 + | +LL | let _: String = "".into(); + | ^^^^^^^^^ help: consider using: `String::new()` + +error: empty String is being created manually + --> $DIR/manual_empty_string_creations.rs:28:13 + | +LL | let _ = String::from(""); + | ^^^^^^^^^^^^^^^^ help: consider using: `String::new()` + +error: empty String is being created manually + --> $DIR/manual_empty_string_creations.rs:29:13 + | +LL | let _ = ::from(""); + | ^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()` + +error: empty String is being created manually + --> $DIR/manual_empty_string_creations.rs:34:13 + | +LL | let _ = String::try_from("").unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()` + +error: empty String is being created manually + --> $DIR/manual_empty_string_creations.rs:40:21 + | +LL | let _: String = From::from(""); + | ^^^^^^^^^^^^^^ help: consider using: `String::new()` + +error: empty String is being created manually + --> $DIR/manual_empty_string_creations.rs:45:21 + | +LL | let _: String = TryFrom::try_from("").unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()` + +error: empty String is being created manually + --> $DIR/manual_empty_string_creations.rs:48:21 + | +LL | let _: String = TryFrom::try_from("").expect("this should warn"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()` + +error: aborting due to 9 previous errors + From 1bf88414790bacf5773bd7f19f0c58e183d0ca7c Mon Sep 17 00:00:00 2001 From: Guilherme-Vasconcelos <49197151+Guilherme-Vasconcelos@users.noreply.github.com> Date: Fri, 5 Aug 2022 20:59:50 -0300 Subject: [PATCH 3724/5092] Update all tests to comply with clippy::manual_empty_string_creations --- clippy_dev/src/new_lint.rs | 2 +- clippy_lints/src/manual_async_fn.rs | 2 +- clippy_lints/src/methods/option_map_unwrap_or.rs | 2 +- .../src/misc_early/unneeded_wildcard_pattern.rs | 2 +- clippy_lints/src/unnecessary_wraps.rs | 2 +- .../ui/case_sensitive_file_extension_comparisons.rs | 10 +++++----- .../case_sensitive_file_extension_comparisons.stderr | 12 ++++++------ tests/ui/format.fixed | 2 +- tests/ui/format.rs | 2 +- tests/ui/identity_op.fixed | 2 +- tests/ui/identity_op.rs | 2 +- tests/ui/manual_empty_string_creations.fixed | 2 +- tests/ui/or_fun_call.fixed | 4 ++-- tests/ui/or_fun_call.rs | 4 ++-- tests/ui/or_fun_call.stderr | 6 +++--- tests/ui/string_add.rs | 4 ++-- tests/ui/string_add_assign.fixed | 4 ++-- tests/ui/string_add_assign.rs | 4 ++-- tests/ui/unnecessary_owned_empty_strings.fixed | 1 + tests/ui/unnecessary_owned_empty_strings.rs | 1 + tests/ui/unnecessary_owned_empty_strings.stderr | 2 +- tests/ui/useless_conversion_try.rs | 4 ++-- tests/ui/useless_conversion_try.stderr | 2 +- 23 files changed, 40 insertions(+), 38 deletions(-) diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 10a8f31f4573..be05e67d724d 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -155,7 +155,7 @@ fn to_camel_case(name: &str) -> String { name.split('_') .map(|s| { if s.is_empty() { - String::from("") + String::new() } else { [&s[0..1].to_uppercase(), &s[1..]].concat() } diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index a0ca7e6ff1e2..2502c8f880dd 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -192,7 +192,7 @@ fn suggested_ret(cx: &LateContext<'_>, output: &Ty<'_>) -> Option<(&'static str, match output.kind { TyKind::Tup(tys) if tys.is_empty() => { let sugg = "remove the return type"; - Some((sugg, "".into())) + Some((sugg, String::new())) }, _ => { let sugg = "return the output of the future directly"; diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index 6c641af59f92..3c4002a3aef9 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -78,7 +78,7 @@ pub(super) fn check<'tcx>( map_span, String::from(if unwrap_snippet_none { "and_then" } else { "map_or" }), ), - (expr.span.with_lo(unwrap_recv.span.hi()), String::from("")), + (expr.span.with_lo(unwrap_recv.span.hi()), String::new()), ]; if !unwrap_snippet_none { diff --git a/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs b/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs index df044538fe19..7c4ae746e90e 100644 --- a/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs +++ b/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs @@ -46,7 +46,7 @@ fn span_lint(cx: &EarlyContext<'_>, span: Span, only_one: bool) { "these patterns are unneeded as the `..` pattern can match those elements" }, if only_one { "remove it" } else { "remove them" }, - "".to_string(), + String::new(), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/unnecessary_wraps.rs b/clippy_lints/src/unnecessary_wraps.rs index f4f5a4336a39..a5afbb8ff9da 100644 --- a/clippy_lints/src/unnecessary_wraps.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -130,7 +130,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { ( ret_expr.span, if inner_type.is_unit() { - "".to_string() + String::new() } else { snippet(cx, arg.span.source_callsite(), "..").to_string() } diff --git a/tests/ui/case_sensitive_file_extension_comparisons.rs b/tests/ui/case_sensitive_file_extension_comparisons.rs index 0d65071af15e..6f0485b5279b 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.rs +++ b/tests/ui/case_sensitive_file_extension_comparisons.rs @@ -14,31 +14,31 @@ fn is_rust_file(filename: &str) -> bool { fn main() { // std::string::String and &str should trigger the lint failure with .ext12 - let _ = String::from("").ends_with(".ext12"); + let _ = String::new().ends_with(".ext12"); let _ = "str".ends_with(".ext12"); // The test struct should not trigger the lint failure with .ext12 TestStruct {}.ends_with(".ext12"); // std::string::String and &str should trigger the lint failure with .EXT12 - let _ = String::from("").ends_with(".EXT12"); + let _ = String::new().ends_with(".EXT12"); let _ = "str".ends_with(".EXT12"); // The test struct should not trigger the lint failure with .EXT12 TestStruct {}.ends_with(".EXT12"); // Should not trigger the lint failure with .eXT12 - let _ = String::from("").ends_with(".eXT12"); + let _ = String::new().ends_with(".eXT12"); let _ = "str".ends_with(".eXT12"); TestStruct {}.ends_with(".eXT12"); // Should not trigger the lint failure with .EXT123 (too long) - let _ = String::from("").ends_with(".EXT123"); + let _ = String::new().ends_with(".EXT123"); let _ = "str".ends_with(".EXT123"); TestStruct {}.ends_with(".EXT123"); // Shouldn't fail if it doesn't start with a dot - let _ = String::from("").ends_with("a.ext"); + let _ = String::new().ends_with("a.ext"); let _ = "str".ends_with("a.extA"); TestStruct {}.ends_with("a.ext"); } diff --git a/tests/ui/case_sensitive_file_extension_comparisons.stderr b/tests/ui/case_sensitive_file_extension_comparisons.stderr index 05b98169f2d1..5d9a043edb9a 100644 --- a/tests/ui/case_sensitive_file_extension_comparisons.stderr +++ b/tests/ui/case_sensitive_file_extension_comparisons.stderr @@ -8,10 +8,10 @@ LL | filename.ends_with(".rs") = help: consider using a case-insensitive comparison instead error: case-sensitive file extension comparison - --> $DIR/case_sensitive_file_extension_comparisons.rs:17:30 + --> $DIR/case_sensitive_file_extension_comparisons.rs:17:27 | -LL | let _ = String::from("").ends_with(".ext12"); - | ^^^^^^^^^^^^^^^^^^^ +LL | let _ = String::new().ends_with(".ext12"); + | ^^^^^^^^^^^^^^^^^^^ | = help: consider using a case-insensitive comparison instead @@ -24,10 +24,10 @@ LL | let _ = "str".ends_with(".ext12"); = help: consider using a case-insensitive comparison instead error: case-sensitive file extension comparison - --> $DIR/case_sensitive_file_extension_comparisons.rs:24:30 + --> $DIR/case_sensitive_file_extension_comparisons.rs:24:27 | -LL | let _ = String::from("").ends_with(".EXT12"); - | ^^^^^^^^^^^^^^^^^^^ +LL | let _ = String::new().ends_with(".EXT12"); + | ^^^^^^^^^^^^^^^^^^^ | = help: consider using a case-insensitive comparison instead diff --git a/tests/ui/format.fixed b/tests/ui/format.fixed index 6b754f3bd710..b56d6aec508d 100644 --- a/tests/ui/format.fixed +++ b/tests/ui/format.fixed @@ -33,7 +33,7 @@ fn main() { format!("foo {}", "bar"); format!("{} bar", "foo"); - let arg: String = "".to_owned(); + let arg = String::new(); arg.to_string(); format!("{:?}", arg); // Don't warn about debug. format!("{:8}", arg); diff --git a/tests/ui/format.rs b/tests/ui/format.rs index ca9826b356ec..4c1a3a840ed9 100644 --- a/tests/ui/format.rs +++ b/tests/ui/format.rs @@ -35,7 +35,7 @@ fn main() { format!("foo {}", "bar"); format!("{} bar", "foo"); - let arg: String = "".to_owned(); + let arg = String::new(); format!("{}", arg); format!("{:?}", arg); // Don't warn about debug. format!("{:8}", arg); diff --git a/tests/ui/identity_op.fixed b/tests/ui/identity_op.fixed index 5f9cebe212ab..fa564e23cd27 100644 --- a/tests/ui/identity_op.fixed +++ b/tests/ui/identity_op.fixed @@ -68,7 +68,7 @@ fn main() { &x; x; - let mut a = A("".into()); + let mut a = A(String::new()); let b = a << 0; // no error: non-integer 1 * Meter; // no error: non-integer diff --git a/tests/ui/identity_op.rs b/tests/ui/identity_op.rs index ca799c9cfac0..3d06d2a73b62 100644 --- a/tests/ui/identity_op.rs +++ b/tests/ui/identity_op.rs @@ -68,7 +68,7 @@ fn main() { &x >> 0; x >> &0; - let mut a = A("".into()); + let mut a = A(String::new()); let b = a << 0; // no error: non-integer 1 * Meter; // no error: non-integer diff --git a/tests/ui/manual_empty_string_creations.fixed b/tests/ui/manual_empty_string_creations.fixed index 3516312ee0c5..caf0c657c81a 100644 --- a/tests/ui/manual_empty_string_creations.fixed +++ b/tests/ui/manual_empty_string_creations.fixed @@ -7,7 +7,7 @@ macro_rules! create_strings_from_macro { ($some_str:expr) => { let _: String = $some_str.into(); let _ = $some_str.to_string(); - } + }; } fn main() { diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index fdb08d953ff1..18ea4e550292 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -90,8 +90,8 @@ fn or_fun_call() { let mut btree_vec = BTreeMap::>::new(); btree_vec.entry(42).or_insert(vec![]); - let stringy = Some(String::from("")); - let _ = stringy.unwrap_or_else(|| "".to_owned()); + let stringy = Some(String::new()); + let _ = stringy.unwrap_or_default(); let opt = Some(1); let hello = "Hello"; diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index 57ab5f03ee28..c353b41e4495 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -90,8 +90,8 @@ fn or_fun_call() { let mut btree_vec = BTreeMap::>::new(); btree_vec.entry(42).or_insert(vec![]); - let stringy = Some(String::from("")); - let _ = stringy.unwrap_or("".to_owned()); + let stringy = Some(String::new()); + let _ = stringy.unwrap_or(String::new()); let opt = Some(1); let hello = "Hello"; diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index 4c5938ab88b9..887f23ac9761 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -66,11 +66,11 @@ error: use of `unwrap_or` followed by a function call LL | without_default.unwrap_or(Foo::new()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)` -error: use of `unwrap_or` followed by a function call +error: use of `unwrap_or` followed by a call to `new` --> $DIR/or_fun_call.rs:94:21 | -LL | let _ = stringy.unwrap_or("".to_owned()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())` +LL | let _ = stringy.unwrap_or(String::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` error: use of `unwrap_or` followed by a function call --> $DIR/or_fun_call.rs:102:21 diff --git a/tests/ui/string_add.rs b/tests/ui/string_add.rs index 30fd17c59e51..16673c01e630 100644 --- a/tests/ui/string_add.rs +++ b/tests/ui/string_add.rs @@ -7,13 +7,13 @@ extern crate macro_rules; #[allow(clippy::string_add_assign, unused)] fn main() { // ignores assignment distinction - let mut x = "".to_owned(); + let mut x = String::new(); for _ in 1..3 { x = x + "."; } - let y = "".to_owned(); + let y = String::new(); let z = y + "..."; assert_eq!(&x, &z); diff --git a/tests/ui/string_add_assign.fixed b/tests/ui/string_add_assign.fixed index db71bab1e521..b687f43b2541 100644 --- a/tests/ui/string_add_assign.fixed +++ b/tests/ui/string_add_assign.fixed @@ -4,13 +4,13 @@ #[warn(clippy::string_add_assign)] fn main() { // ignores assignment distinction - let mut x = "".to_owned(); + let mut x = String::new(); for _ in 1..3 { x += "."; } - let y = "".to_owned(); + let y = String::new(); let z = y + "..."; assert_eq!(&x, &z); diff --git a/tests/ui/string_add_assign.rs b/tests/ui/string_add_assign.rs index 644991945cbe..e5dbde108fbd 100644 --- a/tests/ui/string_add_assign.rs +++ b/tests/ui/string_add_assign.rs @@ -4,13 +4,13 @@ #[warn(clippy::string_add_assign)] fn main() { // ignores assignment distinction - let mut x = "".to_owned(); + let mut x = String::new(); for _ in 1..3 { x = x + "."; } - let y = "".to_owned(); + let y = String::new(); let z = y + "..."; assert_eq!(&x, &z); diff --git a/tests/ui/unnecessary_owned_empty_strings.fixed b/tests/ui/unnecessary_owned_empty_strings.fixed index f95f91329a2f..c390618ca98b 100644 --- a/tests/ui/unnecessary_owned_empty_strings.fixed +++ b/tests/ui/unnecessary_owned_empty_strings.fixed @@ -12,6 +12,7 @@ fn main() { ref_str_argument(""); // should be linted + #[allow(clippy::manual_empty_string_creations)] ref_str_argument(""); // should not be linted diff --git a/tests/ui/unnecessary_owned_empty_strings.rs b/tests/ui/unnecessary_owned_empty_strings.rs index 0cbdc151ed9b..4a9d6125eb12 100644 --- a/tests/ui/unnecessary_owned_empty_strings.rs +++ b/tests/ui/unnecessary_owned_empty_strings.rs @@ -12,6 +12,7 @@ fn main() { ref_str_argument(&String::new()); // should be linted + #[allow(clippy::manual_empty_string_creations)] ref_str_argument(&String::from("")); // should not be linted diff --git a/tests/ui/unnecessary_owned_empty_strings.stderr b/tests/ui/unnecessary_owned_empty_strings.stderr index 46bc4597b335..1eb198a8675e 100644 --- a/tests/ui/unnecessary_owned_empty_strings.stderr +++ b/tests/ui/unnecessary_owned_empty_strings.stderr @@ -7,7 +7,7 @@ LL | ref_str_argument(&String::new()); = note: `-D clippy::unnecessary-owned-empty-strings` implied by `-D warnings` error: usage of `&String::from("")` for a function expecting a `&str` argument - --> $DIR/unnecessary_owned_empty_strings.rs:15:22 + --> $DIR/unnecessary_owned_empty_strings.rs:16:22 | LL | ref_str_argument(&String::from("")); | ^^^^^^^^^^^^^^^^^ help: try: `""` diff --git a/tests/ui/useless_conversion_try.rs b/tests/ui/useless_conversion_try.rs index 39f54c27bee1..4acf5b5fa2d1 100644 --- a/tests/ui/useless_conversion_try.rs +++ b/tests/ui/useless_conversion_try.rs @@ -29,10 +29,10 @@ fn main() { let _ = String::try_from("foo".to_string()).unwrap(); let _ = String::try_from(format!("A: {:04}", 123)).unwrap(); let _: String = format!("Hello {}", "world").try_into().unwrap(); - let _: String = "".to_owned().try_into().unwrap(); + let _: String = String::new().try_into().unwrap(); let _: String = match String::from("_").try_into() { Ok(a) => a, - Err(_) => "".into(), + Err(_) => String::new(), }; // FIXME this is a false negative #[allow(clippy::cmp_owned)] diff --git a/tests/ui/useless_conversion_try.stderr b/tests/ui/useless_conversion_try.stderr index b691c13f7dbb..12e74d614717 100644 --- a/tests/ui/useless_conversion_try.stderr +++ b/tests/ui/useless_conversion_try.stderr @@ -62,7 +62,7 @@ LL | let _: String = format!("Hello {}", "world").try_into().unwrap(); error: useless conversion to the same type: `std::string::String` --> $DIR/useless_conversion_try.rs:32:21 | -LL | let _: String = "".to_owned().try_into().unwrap(); +LL | let _: String = String::new().try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider removing `.try_into()` From 1a2aaf68de4989eaacf5b669da00b50dca8b41e0 Mon Sep 17 00:00:00 2001 From: xphoniex Date: Sun, 14 Aug 2022 16:29:26 +0000 Subject: [PATCH 3725/5092] Skip `unnecessary_to_owned` when `t != t.to_string()` Signed-off-by: xphoniex --- .../src/methods/unnecessary_to_owned.rs | 17 +++++++++-- tests/ui/unnecessary_to_owned.fixed | 28 +++++++++++++++++++ tests/ui/unnecessary_to_owned.rs | 28 +++++++++++++++++++ 3 files changed, 71 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index b3276f1394ed..99b56da7a50c 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -3,7 +3,8 @@ use super::unnecessary_iter_cloned::{self, is_into_iter}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{ - contains_ty, get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs, + contains_ty, get_associated_type, get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, + peel_mid_ty_refs, }; use clippy_utils::{meets_msrv, msrvs}; @@ -279,7 +280,19 @@ fn check_other_call_arg<'tcx>( &trait_predicate.trait_ref.substs.iter().skip(1).collect::>()[..], call_substs, ); - implements_trait(cx, receiver_ty, as_ref_trait_id, &composed_substs) + // if `expr` is a `String` and generic target is [u8], skip + // (https://github.com/rust-lang/rust-clippy/issues/9317). + if let [subst] = composed_substs[..] + && let GenericArgKind::Type(arg_ty) = subst.unpack() + && arg_ty.is_slice() + && let inner_ty = arg_ty.builtin_index().unwrap() + && let ty::Uint(ty::UintTy::U8) = inner_ty.kind() + && let self_ty = cx.typeck_results().expr_ty(expr).peel_refs() + && is_type_diagnostic_item(cx, self_ty, sym::String) { + false + } else { + implements_trait(cx, receiver_ty, as_ref_trait_id, &composed_substs) + } } else { false }; diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed index f4f76cd3dd49..9cd5bc73b1ec 100644 --- a/tests/ui/unnecessary_to_owned.fixed +++ b/tests/ui/unnecessary_to_owned.fixed @@ -329,3 +329,31 @@ mod issue_8759_variant { rw.set_view(&rw.default_view().to_owned()); } } + +mod issue_9317 { + #![allow(dead_code)] + + struct Bytes {} + + impl ToString for Bytes { + fn to_string(&self) -> String { + "123".to_string() + } + } + + impl AsRef<[u8]> for Bytes { + fn as_ref(&self) -> &[u8] { + &[1, 2, 3] + } + } + + fn consume>(c: C) { + let _ = c; + } + + pub fn main() { + let b = Bytes {}; + // Should not lint. + consume(b.to_string()); + } +} diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index fe09a489ab0a..7f62ba3ab5d5 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -329,3 +329,31 @@ mod issue_8759_variant { rw.set_view(&rw.default_view().to_owned()); } } + +mod issue_9317 { + #![allow(dead_code)] + + struct Bytes {} + + impl ToString for Bytes { + fn to_string(&self) -> String { + "123".to_string() + } + } + + impl AsRef<[u8]> for Bytes { + fn as_ref(&self) -> &[u8] { + &[1, 2, 3] + } + } + + fn consume>(c: C) { + let _ = c; + } + + pub fn main() { + let b = Bytes {}; + // Should not lint. + consume(b.to_string()); + } +} From 6de4bdfa8e36bcf5c814b0d43afc1cefb0630533 Mon Sep 17 00:00:00 2001 From: lukaslueg Date: Mon, 15 Aug 2022 20:13:31 +0200 Subject: [PATCH 3726/5092] Fix label not starting with lcase-letter Co-authored-by: Fridtjof Stoldt --- clippy_lints/src/if_let_mutex.rs | 2 +- tests/ui/if_let_mutex.stderr | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs index b6f9fefdee99..4d703d691acc 100644 --- a/clippy_lints/src/if_let_mutex.rs +++ b/clippy_lints/src/if_let_mutex.rs @@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex { let diag = |diag: &mut Diagnostic| { diag.span_label( op_mutex.span, - "This Mutex will remain locked for the entire `if let`-block...", + "this Mutex will remain locked for the entire `if let`-block...", ); diag.span_label( arm_mutex.span, diff --git a/tests/ui/if_let_mutex.stderr b/tests/ui/if_let_mutex.stderr index 6dbfc4be4127..8a4d5dbac592 100644 --- a/tests/ui/if_let_mutex.stderr +++ b/tests/ui/if_let_mutex.stderr @@ -2,7 +2,7 @@ error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a --> $DIR/if_let_mutex.rs:10:5 | LL | if let Err(locked) = m.lock() { - | ^ - This Mutex will remain locked for the entire `if let`-block... + | ^ - this Mutex will remain locked for the entire `if let`-block... | _____| | | LL | | do_stuff(locked); @@ -20,7 +20,7 @@ error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a --> $DIR/if_let_mutex.rs:22:5 | LL | if let Some(locked) = m.lock().unwrap().deref() { - | ^ - This Mutex will remain locked for the entire `if let`-block... + | ^ - this Mutex will remain locked for the entire `if let`-block... | _____| | | LL | | do_stuff(locked); @@ -37,7 +37,7 @@ error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a --> $DIR/if_let_mutex.rs:43:5 | LL | if let Ok(i) = mutex.lock() { - | ^ ----- This Mutex will remain locked for the entire `if let`-block... + | ^ ----- this Mutex will remain locked for the entire `if let`-block... | _____| | | LL | | do_stuff(i); From 7727c303e5eaef93dbccc75a0b9004d9c75d3a62 Mon Sep 17 00:00:00 2001 From: Stanislav Tkach Date: Sat, 13 Aug 2022 16:04:30 +0200 Subject: [PATCH 3727/5092] Simplify the borrow_deref_ref lint example --- clippy_lints/src/borrow_deref_ref.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs index e65b67c655ec..c4520d003928 100644 --- a/clippy_lints/src/borrow_deref_ref.rs +++ b/clippy_lints/src/borrow_deref_ref.rs @@ -29,20 +29,15 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// fn foo(_x: &str) {} - /// /// let s = &String::new(); /// /// let a: &String = &* s; - /// foo(&*s); /// ``` /// /// Use instead: /// ```rust - /// # fn foo(_x: &str) {} /// # let s = &String::new(); /// let a: &String = s; - /// foo(&**s); /// ``` #[clippy::version = "1.63.0"] pub BORROW_DEREF_REF, From 297ddffff3248c0d60a07a8a96cb2d06d6191a2b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 15 Aug 2022 18:31:40 -0400 Subject: [PATCH 3728/5092] add test that we do not merge neighboring SRW --- .../disable_mut_does_not_merge_srw.rs | 17 +++++++++++ .../disable_mut_does_not_merge_srw.stderr | 28 +++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.rs create mode 100644 tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr diff --git a/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.rs b/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.rs new file mode 100644 index 000000000000..1dcd7621acd2 --- /dev/null +++ b/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.rs @@ -0,0 +1,17 @@ +// This tests demonstrates the effect of 'Disabling' mutable references on reads, rather than +// removing them from the stack -- the latter would 'merge' neighboring SRW groups which we would +// like to avoid. +fn main() { + unsafe { + let mut mem = 0; + let base = &mut mem as *mut i32; // the base pointer we build the rest of the stack on + let mutref = &mut *base; + let raw = mutref as *mut i32; + // in the stack, we now have [base, mutref, raw] + let _val = *base; + // now mutref is disabled + *base = 1; + // this should pop raw from the stack, since it is in a different SRW group + let _val = *raw; //~ERROR: that tag does not exist in the borrow stack + } +} diff --git a/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr b/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr new file mode 100644 index 000000000000..b3f0204c09fa --- /dev/null +++ b/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr @@ -0,0 +1,28 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/disable_mut_does_not_merge_srw.rs:LL:CC + | +LL | let _val = *raw; + | ^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/disable_mut_does_not_merge_srw.rs:LL:CC + | +LL | let raw = mutref as *mut i32; + | ^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/disable_mut_does_not_merge_srw.rs:LL:CC + | +LL | *base = 1; + | ^^^^^^^^^ + = note: backtrace: + = note: inside `main` at $DIR/disable_mut_does_not_merge_srw.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + From 79ebfa25dcde23f3eb95238a23707b69cc01a528 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 15 Aug 2022 18:35:11 -0400 Subject: [PATCH 3729/5092] make Miri build without the stack-cache feature --- src/stacked_borrows/stack.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/stacked_borrows/stack.rs b/src/stacked_borrows/stack.rs index 6fd8d85f2b5f..4a9a13d35b52 100644 --- a/src/stacked_borrows/stack.rs +++ b/src/stacked_borrows/stack.rs @@ -81,7 +81,7 @@ impl<'tcx> Stack { /// Panics if any of the caching mechanisms have broken, /// - The StackCache indices don't refer to the parallel items, /// - There are no Unique items outside of first_unique..last_unique - #[cfg(debug_assertions)] + #[cfg(all(feature = "stack-cache", debug_assertions))] fn verify_cache_consistency(&self) { // Only a full cache needs to be valid. Also see the comments in find_granting_cache // and set_unknown_bottom. @@ -128,7 +128,7 @@ impl<'tcx> Stack { tag: ProvenanceExtra, exposed_tags: &FxHashSet, ) -> Result, ()> { - #[cfg(debug_assertions)] + #[cfg(all(feature = "stack-cache", debug_assertions))] self.verify_cache_consistency(); let ProvenanceExtra::Concrete(tag) = tag else { @@ -320,13 +320,14 @@ impl<'tcx> Stack { if disable_start <= unique_range.end { let lower = unique_range.start.max(disable_start); - let upper = self.unique_range.end; + let upper = unique_range.end; for item in &mut self.borrows[lower..upper] { if item.perm() == Permission::Unique { log::trace!("access: disabling item {:?}", item); visitor(*item)?; item.set_permission(Permission::Disabled); // Also update all copies of this item in the cache. + #[cfg(feature = "stack-cache")] for it in &mut self.cache.items { if it.tag() == item.tag() { it.set_permission(Permission::Disabled); @@ -347,7 +348,7 @@ impl<'tcx> Stack { self.unique_range.end = self.unique_range.end.min(disable_start); } - #[cfg(debug_assertions)] + #[cfg(all(feature = "stack-cache", debug_assertions))] self.verify_cache_consistency(); Ok(()) @@ -402,7 +403,7 @@ impl<'tcx> Stack { self.unique_range = 0..0; } - #[cfg(debug_assertions)] + #[cfg(all(feature = "stack-cache", debug_assertions))] self.verify_cache_consistency(); Ok(()) } From 2e3da5d8c30238cddbc63131776af485d2d10cda Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 15 Aug 2022 19:33:07 -0400 Subject: [PATCH 3730/5092] check no-default-features and all-features build on CI --- ci.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index a29fc3deca58..8189596dba77 100755 --- a/ci.sh +++ b/ci.sh @@ -5,11 +5,12 @@ set -x # Determine configuration export RUSTFLAGS="-D warnings" export CARGO_INCREMENTAL=0 -export CARGO_EXTRA_FLAGS="--all-features" # Prepare echo "Build and install miri" ./miri install # implicitly locked +./miri check --no-default-features # make sure this can be built +./miri check --all-features # and this, too ./miri build --all-targets --locked # the build that all the `./miri test` below will use echo From db43ee5714900900a52ad5050b77993288472ce2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 15 Aug 2022 20:23:19 -0400 Subject: [PATCH 3731/5092] defend test against overly smart Miri --- .../stacked_borrows/disable_mut_does_not_merge_srw.rs | 11 ++++++++--- .../disable_mut_does_not_merge_srw.stderr | 4 ++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.rs b/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.rs index 1dcd7621acd2..fed5cd26f4d6 100644 --- a/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.rs +++ b/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.rs @@ -5,9 +5,14 @@ fn main() { unsafe { let mut mem = 0; let base = &mut mem as *mut i32; // the base pointer we build the rest of the stack on - let mutref = &mut *base; - let raw = mutref as *mut i32; - // in the stack, we now have [base, mutref, raw] + let raw = { + let mutref = &mut *base; + mutref as *mut i32 + }; + // In the stack, we now have [base, mutref, raw]. + // We do this in a weird way where `mutref` is out of scope here, just in case + // Miri decides to get smart and argue that items for tags that are no longer + // used by any pointer stored anywhere in the machine can be removed. let _val = *base; // now mutref is disabled *base = 1; diff --git a/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr b/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr index b3f0204c09fa..9f5182ae98ff 100644 --- a/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr +++ b/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr @@ -12,8 +12,8 @@ LL | let _val = *raw; help: was created by a retag at offsets [0x0..0x4] --> $DIR/disable_mut_does_not_merge_srw.rs:LL:CC | -LL | let raw = mutref as *mut i32; - | ^^^^^^ +LL | mutref as *mut i32 + | ^^^^^^ help: was later invalidated at offsets [0x0..0x4] --> $DIR/disable_mut_does_not_merge_srw.rs:LL:CC | From 6e5f90ae46dd290aea287067cf6083d2d02f3bf5 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 11 Aug 2022 21:06:11 +1000 Subject: [PATCH 3732/5092] Shrink `ast::Attribute`. --- clippy_lints/src/crate_in_macro_def.rs | 4 ++-- clippy_utils/src/ast_utils.rs | 2 +- clippy_utils/src/attrs.rs | 4 ++-- clippy_utils/src/lib.rs | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/crate_in_macro_def.rs b/clippy_lints/src/crate_in_macro_def.rs index 454ec23388af..20cc330e035f 100644 --- a/clippy_lints/src/crate_in_macro_def.rs +++ b/clippy_lints/src/crate_in_macro_def.rs @@ -74,8 +74,8 @@ impl EarlyLintPass for CrateInMacroDef { fn is_macro_export(attr: &Attribute) -> bool { if_chain! { - if let AttrKind::Normal(attr_item, _) = &attr.kind; - if let [segment] = attr_item.path.segments.as_slice(); + if let AttrKind::Normal(normal) = &attr.kind; + if let [segment] = normal.item.path.segments.as_slice(); then { segment.ident.name == sym::macro_export } else { diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs index 9f74729bdfa1..493991f30e87 100644 --- a/clippy_utils/src/ast_utils.rs +++ b/clippy_utils/src/ast_utils.rs @@ -695,7 +695,7 @@ pub fn eq_attr(l: &Attribute, r: &Attribute) -> bool { l.style == r.style && match (&l.kind, &r.kind) { (DocComment(l1, l2), DocComment(r1, r2)) => l1 == r1 && l2 == r2, - (Normal(l, _), Normal(r, _)) => eq_path(&l.path, &r.path) && eq_mac_args(&l.args, &r.args), + (Normal(l), Normal(r)) => eq_path(&l.item.path, &r.item.path) && eq_mac_args(&l.item.args, &r.item.args), _ => false, } } diff --git a/clippy_utils/src/attrs.rs b/clippy_utils/src/attrs.rs index 186bba09d201..8ab77c881663 100644 --- a/clippy_utils/src/attrs.rs +++ b/clippy_utils/src/attrs.rs @@ -59,8 +59,8 @@ pub fn get_attr<'a>( name: &'static str, ) -> impl Iterator { attrs.iter().filter(move |attr| { - let attr = if let ast::AttrKind::Normal(ref attr, _) = attr.kind { - attr + let attr = if let ast::AttrKind::Normal(ref normal) = attr.kind { + &normal.item } else { return false; }; diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index dc772e5efeef..f716f009ff3f 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1893,8 +1893,8 @@ pub fn std_or_core(cx: &LateContext<'_>) -> Option<&'static str> { pub fn is_no_std_crate(cx: &LateContext<'_>) -> bool { cx.tcx.hir().attrs(hir::CRATE_HIR_ID).iter().any(|attr| { - if let ast::AttrKind::Normal(ref attr, _) = attr.kind { - attr.path == sym::no_std + if let ast::AttrKind::Normal(ref normal) = attr.kind { + normal.item.path == sym::no_std } else { false } @@ -1903,8 +1903,8 @@ pub fn is_no_std_crate(cx: &LateContext<'_>) -> bool { pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool { cx.tcx.hir().attrs(hir::CRATE_HIR_ID).iter().any(|attr| { - if let ast::AttrKind::Normal(ref attr, _) = attr.kind { - attr.path == sym::no_core + if let ast::AttrKind::Normal(ref normal) = attr.kind { + normal.item.path == sym::no_core } else { false } From e92183c2869d433dc14f5784cffce2e36591ed92 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 1 Aug 2022 16:46:08 +1000 Subject: [PATCH 3733/5092] Rename some things related to literals. - Rename `ast::Lit::token` as `ast::Lit::token_lit`, because its type is `token::Lit`, which is not a token. (This has been confusing me for a long time.) reasonable because we have an `ast::token::Lit` inside an `ast::Lit`. - Rename `LitKind::{from,to}_lit_token` as `LitKind::{from,to}_token_lit`, to match the above change and `token::Lit`. --- clippy_lints/src/octal_escapes.rs | 8 ++++---- clippy_lints/src/write.rs | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/octal_escapes.rs b/clippy_lints/src/octal_escapes.rs index 6ad6837f0e35..bffbf20b4d28 100644 --- a/clippy_lints/src/octal_escapes.rs +++ b/clippy_lints/src/octal_escapes.rs @@ -57,10 +57,10 @@ impl EarlyLintPass for OctalEscapes { } if let ExprKind::Lit(lit) = &expr.kind { - if matches!(lit.token.kind, LitKind::Str) { - check_lit(cx, &lit.token, lit.span, true); - } else if matches!(lit.token.kind, LitKind::ByteStr) { - check_lit(cx, &lit.token, lit.span, false); + if matches!(lit.token_lit.kind, LitKind::Str) { + check_lit(cx, &lit.token_lit, lit.span, true); + } else if matches!(lit.token_lit.kind, LitKind::ByteStr) { + check_lit(cx, &lit.token_lit, lit.span, false); } } } diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 32718200c0b3..fa2383066f3f 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -589,12 +589,12 @@ impl Write { }, }; - let replacement: String = match lit.token.kind { + let replacement: String = match lit.token_lit.kind { LitKind::StrRaw(_) | LitKind::ByteStrRaw(_) if matches!(fmtstr.style, StrStyle::Raw(_)) => { - lit.token.symbol.as_str().replace('{', "{{").replace('}', "}}") + lit.token_lit.symbol.as_str().replace('{', "{{").replace('}', "}}") }, LitKind::Str | LitKind::ByteStr if matches!(fmtstr.style, StrStyle::Cooked) => { - lit.token.symbol.as_str().replace('{', "{{").replace('}', "}}") + lit.token_lit.symbol.as_str().replace('{', "{{").replace('}', "}}") }, LitKind::StrRaw(_) | LitKind::Str @@ -603,7 +603,7 @@ impl Write { | LitKind::Integer | LitKind::Float | LitKind::Err => continue, - LitKind::Byte | LitKind::Char => match lit.token.symbol.as_str() { + LitKind::Byte | LitKind::Char => match lit.token_lit.symbol.as_str() { "\"" if matches!(fmtstr.style, StrStyle::Cooked) => "\\\"", "\"" if matches!(fmtstr.style, StrStyle::Raw(0)) => continue, "\\\\" if matches!(fmtstr.style, StrStyle::Raw(_)) => "\\", @@ -614,7 +614,7 @@ impl Write { x => x, } .into(), - LitKind::Bool => lit.token.symbol.as_str().deref().into(), + LitKind::Bool => lit.token_lit.symbol.as_str().deref().into(), }; if !fmt_spans.is_empty() { From 9e9b3ddf69d28bcfd8564a1e31637e6b135ab69b Mon Sep 17 00:00:00 2001 From: alexey semenyuk Date: Tue, 16 Aug 2022 12:50:53 +0300 Subject: [PATCH 3734/5092] Fix example --- clippy_lints/src/escape.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index 1ac7bfba06ba..0a4a0ebb3f9c 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -30,18 +30,12 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// # fn foo(bar: usize) {} - /// let x = Box::new(1); - /// foo(*x); - /// println!("{}", *x); + /// fn foo(x: Box) {} /// ``` /// /// Use instead: /// ```rust - /// # fn foo(bar: usize) {} - /// let x = 1; - /// foo(x); - /// println!("{}", x); + /// fn foo(x: u32) {} /// ``` #[clippy::version = "pre 1.29.0"] pub BOXED_LOCAL, From 7c18b38e04f61442ad74533d7b4ed2907238fade Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Mon, 15 Aug 2022 18:13:11 -0400 Subject: [PATCH 3735/5092] Rename memory hooks --- src/machine.rs | 12 ++++++------ src/stacked_borrows/mod.rs | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 14df64d8aa30..4ebf7dceab83 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -780,7 +780,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } #[inline(always)] - fn memory_read( + fn before_memory_read( _tcx: TyCtxt<'tcx>, machine: &Self, alloc_extra: &AllocExtra, @@ -796,7 +796,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { )?; } if let Some(stacked_borrows) = &alloc_extra.stacked_borrows { - stacked_borrows.borrow_mut().memory_read( + stacked_borrows.borrow_mut().before_memory_read( alloc_id, prov_extra, range, @@ -812,7 +812,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } #[inline(always)] - fn memory_written( + fn before_memory_write( _tcx: TyCtxt<'tcx>, machine: &mut Self, alloc_extra: &mut AllocExtra, @@ -828,7 +828,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { )?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { - stacked_borrows.get_mut().memory_written( + stacked_borrows.get_mut().before_memory_write( alloc_id, prov_extra, range, @@ -844,7 +844,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } #[inline(always)] - fn memory_deallocated( + fn before_memory_deallocation( _tcx: TyCtxt<'tcx>, machine: &mut Self, alloc_extra: &mut AllocExtra, @@ -863,7 +863,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { )?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { - stacked_borrows.get_mut().memory_deallocated( + stacked_borrows.get_mut().before_memory_deallocation( alloc_id, prove_extra, range, diff --git a/src/stacked_borrows/mod.rs b/src/stacked_borrows/mod.rs index e0cc3e81cf0b..b6b03f166999 100644 --- a/src/stacked_borrows/mod.rs +++ b/src/stacked_borrows/mod.rs @@ -657,7 +657,7 @@ impl Stacks { } #[inline(always)] - pub fn memory_read<'tcx>( + pub fn before_memory_read<'tcx>( &mut self, alloc_id: AllocId, tag: ProvenanceExtra, @@ -688,7 +688,7 @@ impl Stacks { } #[inline(always)] - pub fn memory_written<'tcx>( + pub fn before_memory_write<'tcx>( &mut self, alloc_id: AllocId, tag: ProvenanceExtra, @@ -719,7 +719,7 @@ impl Stacks { } #[inline(always)] - pub fn memory_deallocated<'tcx>( + pub fn before_memory_deallocation<'tcx>( &mut self, alloc_id: AllocId, tag: ProvenanceExtra, From 3992f067283dbfb9e2996d3fcee5ad2d2fac9c24 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 16 Aug 2022 08:07:46 -0400 Subject: [PATCH 3736/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index aaf664f44e3e..7317986eaea4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -2fbc08e2ce64dee45a29cb6133da6b32366268aa +8556e6620e4866526b3cea767ad8c20ae877a569 From ecb8ac5cf41bcb20921df6be22caad07fb74136a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Aug 2022 08:54:20 -0400 Subject: [PATCH 3737/5092] make sure all builds are locked on CI --- ci.sh | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/ci.sh b/ci.sh index 8189596dba77..51cec8fe1619 100755 --- a/ci.sh +++ b/ci.sh @@ -2,16 +2,18 @@ set -euo pipefail set -x -# Determine configuration +# Determine configuration for installed build +echo "Installing release version of Miri" export RUSTFLAGS="-D warnings" export CARGO_INCREMENTAL=0 - -# Prepare -echo "Build and install miri" ./miri install # implicitly locked + +# Prepare debug build for direct `./miri` invocations +echo "Building debug version of Miri" +export CARGO_EXTRA_FLAGS="--locked" ./miri check --no-default-features # make sure this can be built ./miri check --all-features # and this, too -./miri build --all-targets --locked # the build that all the `./miri test` below will use +./miri build --all-targets # the build that all the `./miri test` below will use echo # Test @@ -23,13 +25,13 @@ function run_tests { fi ## ui test suite - ./miri test --locked + ./miri test if [ -z "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with optimizations (`-O` is what cargo passes, but crank MIR # optimizations up all the way). # Optimizations change diagnostics (mostly backtraces), so we don't check them #FIXME(#2155): we want to only run the pass and panic tests here, not the fail tests. - MIRIFLAGS="-O -Zmir-opt-level=4" MIRI_SKIP_UI_CHECKS=1 ./miri test --locked -- tests/{pass,panic} + MIRIFLAGS="-O -Zmir-opt-level=4" MIRI_SKIP_UI_CHECKS=1 ./miri test -- tests/{pass,panic} fi ## test-cargo-miri @@ -70,7 +72,7 @@ function run_tests_minimal { echo "Testing MINIMAL host architecture: only testing $@" fi - ./miri test --locked -- "$@" + ./miri test -- "$@" } # host From c1e04352bd220d2b912715aa07e1d04fe97d84f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Mon, 15 Aug 2022 20:30:30 +0200 Subject: [PATCH 3738/5092] unwrap_used and expect_used: trigger on uses of their _err variants --- clippy_lints/src/methods/expect_used.rs | 18 ++++++++++++----- clippy_lints/src/methods/mod.rs | 10 ++++++---- clippy_lints/src/methods/unwrap_used.rs | 18 ++++++++++++----- tests/ui/unwrap_expect_used.rs | 25 ++++++++++++++++++++++++ tests/ui/unwrap_expect_used.stderr | 26 ++++++++++++++++++++----- 5 files changed, 78 insertions(+), 19 deletions(-) diff --git a/clippy_lints/src/methods/expect_used.rs b/clippy_lints/src/methods/expect_used.rs index 5ef08ca6290b..d59fefa1ddc0 100644 --- a/clippy_lints/src/methods/expect_used.rs +++ b/clippy_lints/src/methods/expect_used.rs @@ -7,18 +7,26 @@ use rustc_span::sym; use super::EXPECT_USED; -/// lint use of `expect()` for `Option`s and `Result`s -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, allow_expect_in_tests: bool) { +/// lint use of `expect()` or `expect_err` for `Result` and `expect()` for `Option`. +pub(super) fn check( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + recv: &hir::Expr<'_>, + is_err: bool, + allow_expect_in_tests: bool, +) { let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); - let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) { + let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err { Some((EXPECT_USED, "an Option", "None", "")) } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) { - Some((EXPECT_USED, "a Result", "Err", "an ")) + Some((EXPECT_USED, "a Result", if is_err { "Ok" } else { "Err" }, "an ")) } else { None }; + let method = if is_err { "expect_err" } else { "expect" }; + if allow_expect_in_tests && is_in_test_function(cx.tcx, expr.hir_id) { return; } @@ -28,7 +36,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr cx, lint, expr.span, - &format!("used `expect()` on `{kind}` value"), + &format!("used `{method}()` on `{kind}` value"), None, &format!("if this value is {none_prefix}`{none_value}`, it will panic"), ); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 99aae5800ff7..b68a2651e1bd 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -174,7 +174,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for `.unwrap()` calls on `Option`s and on `Result`s. + /// Checks for `.unwrap()` or `.unwrap_err()` calls on `Result`s and `.unwrap()` call on `Option`s. /// /// ### Why is this bad? /// It is better to handle the `None` or `Err` case, @@ -224,7 +224,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for `.expect()` calls on `Option`s and `Result`s. + /// Checks for `.expect()` or `.expect_err()` calls on `Result`s and `.expect()` call on `Option`s. /// /// ### Why is this bad? /// Usually it is better to handle the `None` or `Err` case. @@ -2740,8 +2740,9 @@ impl Methods { ("expect", [_]) => match method_call(recv) { Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv), Some(("err", [recv], err_span)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span), - _ => expect_used::check(cx, expr, recv, self.allow_expect_in_tests), + _ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests), }, + ("expect_err", [_]) => expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests), ("extend", [arg]) => { string_extend_chars::check(cx, expr, recv, arg); extend_with_drain::check(cx, expr, recv, arg); @@ -2874,8 +2875,9 @@ impl Methods { }, _ => {}, } - unwrap_used::check(cx, expr, recv, self.allow_unwrap_in_tests); + unwrap_used::check(cx, expr, recv, false, self.allow_unwrap_in_tests); }, + ("unwrap_err", []) => unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests), ("unwrap_or", [u_arg]) => match method_call(recv) { Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => { manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]); diff --git a/clippy_lints/src/methods/unwrap_used.rs b/clippy_lints/src/methods/unwrap_used.rs index ce1a52e5480a..05915c141090 100644 --- a/clippy_lints/src/methods/unwrap_used.rs +++ b/clippy_lints/src/methods/unwrap_used.rs @@ -7,18 +7,26 @@ use rustc_span::sym; use super::{EXPECT_USED, UNWRAP_USED}; -/// lint use of `unwrap()` for `Option`s and `Result`s -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, allow_unwrap_in_tests: bool) { +/// lint use of `unwrap()` or `unwrap_err` for `Result` and `unwrap()` for `Option`. +pub(super) fn check( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + recv: &hir::Expr<'_>, + is_err: bool, + allow_unwrap_in_tests: bool, +) { let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); - let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) { + let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err { Some((UNWRAP_USED, "an Option", "None", "")) } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) { - Some((UNWRAP_USED, "a Result", "Err", "an ")) + Some((UNWRAP_USED, "a Result", if is_err { "Ok" } else { "Err" }, "an ")) } else { None }; + let method = if is_err { "unwrap_err" } else { "unwrap" }; + if allow_unwrap_in_tests && is_in_test_function(cx.tcx, expr.hir_id) { return; } @@ -37,7 +45,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr cx, lint, expr.span, - &format!("used `unwrap()` on `{kind}` value"), + &format!("used `{method}()` on `{kind}` value"), None, &help, ); diff --git a/tests/ui/unwrap_expect_used.rs b/tests/ui/unwrap_expect_used.rs index 0d4a0504a6e0..9f27fef82494 100644 --- a/tests/ui/unwrap_expect_used.rs +++ b/tests/ui/unwrap_expect_used.rs @@ -1,10 +1,35 @@ #![warn(clippy::unwrap_used, clippy::expect_used)] +trait OptionExt { + type Item; + + fn unwrap_err(self) -> Self::Item; + + fn expect_err(self, msg: &str) -> Self::Item; +} + +impl OptionExt for Option { + type Item = T; + fn unwrap_err(self) -> T { + panic!(); + } + + fn expect_err(self, msg: &str) -> T { + panic!(); + } +} + fn main() { Some(3).unwrap(); Some(3).expect("Hello world!"); + // Don't trigger on unwrap_err on an option + Some(3).unwrap_err(); + Some(3).expect_err("Hellow none!"); + let a: Result = Ok(3); a.unwrap(); a.expect("Hello world!"); + a.unwrap_err(); + a.expect_err("Hello error!"); } diff --git a/tests/ui/unwrap_expect_used.stderr b/tests/ui/unwrap_expect_used.stderr index f54bfd617c4e..1a19459b2c17 100644 --- a/tests/ui/unwrap_expect_used.stderr +++ b/tests/ui/unwrap_expect_used.stderr @@ -1,5 +1,5 @@ error: used `unwrap()` on `an Option` value - --> $DIR/unwrap_expect_used.rs:4:5 + --> $DIR/unwrap_expect_used.rs:23:5 | LL | Some(3).unwrap(); | ^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | Some(3).unwrap(); = help: if this value is `None`, it will panic error: used `expect()` on `an Option` value - --> $DIR/unwrap_expect_used.rs:5:5 + --> $DIR/unwrap_expect_used.rs:24:5 | LL | Some(3).expect("Hello world!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | Some(3).expect("Hello world!"); = help: if this value is `None`, it will panic error: used `unwrap()` on `a Result` value - --> $DIR/unwrap_expect_used.rs:8:5 + --> $DIR/unwrap_expect_used.rs:31:5 | LL | a.unwrap(); | ^^^^^^^^^^ @@ -25,12 +25,28 @@ LL | a.unwrap(); = help: if this value is an `Err`, it will panic error: used `expect()` on `a Result` value - --> $DIR/unwrap_expect_used.rs:9:5 + --> $DIR/unwrap_expect_used.rs:32:5 | LL | a.expect("Hello world!"); | ^^^^^^^^^^^^^^^^^^^^^^^^ | = help: if this value is an `Err`, it will panic -error: aborting due to 4 previous errors +error: used `unwrap_err()` on `a Result` value + --> $DIR/unwrap_expect_used.rs:33:5 + | +LL | a.unwrap_err(); + | ^^^^^^^^^^^^^^ + | + = help: if this value is an `Ok`, it will panic + +error: used `expect_err()` on `a Result` value + --> $DIR/unwrap_expect_used.rs:34:5 + | +LL | a.expect_err("Hello error!"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: if this value is an `Ok`, it will panic + +error: aborting due to 6 previous errors From bd121eff8ac3bc1a65f13c7528dddbabd7a32207 Mon Sep 17 00:00:00 2001 From: Serial <69764315+Serial-ATA@users.noreply.github.com> Date: Fri, 12 Aug 2022 20:02:57 -0400 Subject: [PATCH 3739/5092] Fix [`non_ascii_literal`] in tests --- clippy_lints/src/unicode.rs | 7 ++++++ tests/ui/unicode.fixed | 48 +++++++++++++++++++++++++++---------- tests/ui/unicode.rs | 48 +++++++++++++++++++++++++++---------- tests/ui/unicode.stderr | 46 +++++++++++++++++++++++------------ 4 files changed, 110 insertions(+), 39 deletions(-) diff --git a/clippy_lints/src/unicode.rs b/clippy_lints/src/unicode.rs index cc64d17be055..8980283e5c82 100644 --- a/clippy_lints/src/unicode.rs +++ b/clippy_lints/src/unicode.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_lint_allowed; +use clippy_utils::macros::span_is_local; use clippy_utils::source::snippet; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -98,6 +99,10 @@ fn escape>(s: T) -> String { } fn check_str(cx: &LateContext<'_>, span: Span, id: HirId) { + if !span_is_local(span) { + return; + } + let string = snippet(cx, span, ""); if string.chars().any(|c| ['\u{200B}', '\u{ad}', '\u{2060}'].contains(&c)) { span_lint_and_sugg( @@ -113,6 +118,7 @@ fn check_str(cx: &LateContext<'_>, span: Span, id: HirId) { Applicability::MachineApplicable, ); } + if string.chars().any(|c| c as u32 > 0x7F) { span_lint_and_sugg( cx, @@ -128,6 +134,7 @@ fn check_str(cx: &LateContext<'_>, span: Span, id: HirId) { Applicability::MachineApplicable, ); } + if is_lint_allowed(cx, NON_ASCII_LITERAL, id) && string.chars().zip(string.nfc()).any(|(a, b)| a != b) { span_lint_and_sugg( cx, diff --git a/tests/ui/unicode.fixed b/tests/ui/unicode.fixed index 328cda369e11..94b4723452fa 100644 --- a/tests/ui/unicode.fixed +++ b/tests/ui/unicode.fixed @@ -1,4 +1,7 @@ // run-rustfix +// compile-flags: --test +#![allow(dead_code)] + #[warn(clippy::invisible_characters)] fn zero() { print!("Here >\u{200B}< is a ZWS, and \u{200B}another"); @@ -15,22 +18,43 @@ fn canon() { print!("a\u{0300}h?"); // also ok } -#[warn(clippy::non_ascii_literal)] -fn uni() { - print!("\u{dc}ben!"); - print!("\u{DC}ben!"); // this is ok -} +mod non_ascii_literal { + #![deny(clippy::non_ascii_literal)] -// issue 8013 -#[warn(clippy::non_ascii_literal)] -fn single_quote() { - const _EMPTY_BLOCK: char = '\u{25b1}'; - const _FULL_BLOCK: char = '\u{25b0}'; + fn uni() { + print!("\u{dc}ben!"); + print!("\u{DC}ben!"); // this is ok + } + + // issue 8013 + fn single_quote() { + const _EMPTY_BLOCK: char = '\u{25b1}'; + const _FULL_BLOCK: char = '\u{25b0}'; + } + + #[test] + pub fn issue_7739() { + // Ryū crate: https://github.com/dtolnay/ryu + } + + mod issue_8263 { + #![deny(clippy::non_ascii_literal)] + + // Re-allow for a single test + #[test] + #[allow(clippy::non_ascii_literal)] + fn allowed() { + let _ = "悲しいかな、ここに日本語を書くことはできない。"; + } + + #[test] + fn denied() { + let _ = "\u{60b2}\u{3057}\u{3044}\u{304b}\u{306a}\u{3001}\u{3053}\u{3053}\u{306b}\u{65e5}\u{672c}\u{8a9e}\u{3092}\u{66f8}\u{304f}\u{3053}\u{3068}\u{306f}\u{3067}\u{304d}\u{306a}\u{3044}\u{3002}"; + } + } } fn main() { zero(); - uni(); canon(); - single_quote(); } diff --git a/tests/ui/unicode.rs b/tests/ui/unicode.rs index 7828d6bcbea7..6ad0b255b948 100644 --- a/tests/ui/unicode.rs +++ b/tests/ui/unicode.rs @@ -1,4 +1,7 @@ // run-rustfix +// compile-flags: --test +#![allow(dead_code)] + #[warn(clippy::invisible_characters)] fn zero() { print!("Here >​< is a ZWS, and ​another"); @@ -15,22 +18,43 @@ fn canon() { print!("a\u{0300}h?"); // also ok } -#[warn(clippy::non_ascii_literal)] -fn uni() { - print!("Üben!"); - print!("\u{DC}ben!"); // this is ok -} +mod non_ascii_literal { + #![deny(clippy::non_ascii_literal)] -// issue 8013 -#[warn(clippy::non_ascii_literal)] -fn single_quote() { - const _EMPTY_BLOCK: char = '▱'; - const _FULL_BLOCK: char = '▰'; + fn uni() { + print!("Üben!"); + print!("\u{DC}ben!"); // this is ok + } + + // issue 8013 + fn single_quote() { + const _EMPTY_BLOCK: char = '▱'; + const _FULL_BLOCK: char = '▰'; + } + + #[test] + pub fn issue_7739() { + // Ryū crate: https://github.com/dtolnay/ryu + } + + mod issue_8263 { + #![deny(clippy::non_ascii_literal)] + + // Re-allow for a single test + #[test] + #[allow(clippy::non_ascii_literal)] + fn allowed() { + let _ = "悲しいかな、ここに日本語を書くことはできない。"; + } + + #[test] + fn denied() { + let _ = "悲しいかな、ここに日本語を書くことはできない。"; + } + } } fn main() { zero(); - uni(); canon(); - single_quote(); } diff --git a/tests/ui/unicode.stderr b/tests/ui/unicode.stderr index 01d3f3c02967..ea74a81451e3 100644 --- a/tests/ui/unicode.stderr +++ b/tests/ui/unicode.stderr @@ -1,5 +1,5 @@ error: invisible character detected - --> $DIR/unicode.rs:4:12 + --> $DIR/unicode.rs:7:12 | LL | print!("Here >​< is a ZWS, and ​another"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{200B}< is a ZWS, and /u{200B}another"` @@ -7,19 +7,19 @@ LL | print!("Here >​< is a ZWS, and ​another"); = note: `-D clippy::invisible-characters` implied by `-D warnings` error: invisible character detected - --> $DIR/unicode.rs:6:12 + --> $DIR/unicode.rs:9:12 | LL | print!("Here >­< is a SHY, and ­another"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{AD}< is a SHY, and /u{AD}another"` error: invisible character detected - --> $DIR/unicode.rs:8:12 + --> $DIR/unicode.rs:11:12 | LL | print!("Here >⁠< is a WJ, and ⁠another"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{2060}< is a WJ, and /u{2060}another"` error: non-NFC Unicode sequence detected - --> $DIR/unicode.rs:14:12 + --> $DIR/unicode.rs:17:12 | LL | print!("̀àh?"); | ^^^^^ help: consider replacing the string with: `"̀àh?"` @@ -27,24 +27,40 @@ LL | print!("̀àh?"); = note: `-D clippy::unicode-not-nfc` implied by `-D warnings` error: literal non-ASCII character detected - --> $DIR/unicode.rs:20:12 + --> $DIR/unicode.rs:25:16 | -LL | print!("Üben!"); - | ^^^^^^^ help: consider replacing the string with: `"/u{dc}ben!"` +LL | print!("Üben!"); + | ^^^^^^^ help: consider replacing the string with: `"/u{dc}ben!"` | - = note: `-D clippy::non-ascii-literal` implied by `-D warnings` +note: the lint level is defined here + --> $DIR/unicode.rs:22:13 + | +LL | #![deny(clippy::non_ascii_literal)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: literal non-ASCII character detected - --> $DIR/unicode.rs:27:32 + --> $DIR/unicode.rs:31:36 | -LL | const _EMPTY_BLOCK: char = '▱'; - | ^^^ help: consider replacing the string with: `'/u{25b1}'` +LL | const _EMPTY_BLOCK: char = '▱'; + | ^^^ help: consider replacing the string with: `'/u{25b1}'` error: literal non-ASCII character detected - --> $DIR/unicode.rs:28:31 + --> $DIR/unicode.rs:32:35 | -LL | const _FULL_BLOCK: char = '▰'; - | ^^^ help: consider replacing the string with: `'/u{25b0}'` +LL | const _FULL_BLOCK: char = '▰'; + | ^^^ help: consider replacing the string with: `'/u{25b0}'` -error: aborting due to 7 previous errors +error: literal non-ASCII character detected + --> $DIR/unicode.rs:52:21 + | +LL | let _ = "悲しいかな、ここに日本語を書くことはできない。"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"/u{60b2}/u{3057}/u{3044}/u{304b}/u{306a}/u{3001}/u{3053}/u{3053}/u{306b}/u{65e5}/u{672c}/u{8a9e}/u{3092}/u{66f8}/u{304f}/u{3053}/u{3068}/u{306f}/u{3067}/u{304d}/u{306a}/u{3044}/u{3002}"` + | +note: the lint level is defined here + --> $DIR/unicode.rs:41:17 + | +LL | #![deny(clippy::non_ascii_literal)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 8 previous errors From bfeaae89304443894c5f64a73188015f938fc97d Mon Sep 17 00:00:00 2001 From: Brian Caswell Date: Tue, 16 Aug 2022 16:03:23 -0400 Subject: [PATCH 3740/5092] suggest map_or in case_sensitive_file_extension_comparisons Currently, case_sensitive_file_extension_comparisons suggests using `map(..).unwrap_or(..)` which trips up `map_unwrap_or`. This updates the suggestion to use map_or. --- clippy_lints/src/case_sensitive_file_extension_comparisons.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clippy_lints/src/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/case_sensitive_file_extension_comparisons.rs index 7eff71d50074..bef196565a2a 100644 --- a/clippy_lints/src/case_sensitive_file_extension_comparisons.rs +++ b/clippy_lints/src/case_sensitive_file_extension_comparisons.rs @@ -26,8 +26,7 @@ declare_clippy_lint! { /// fn is_rust_file(filename: &str) -> bool { /// let filename = std::path::Path::new(filename); /// filename.extension() - /// .map(|ext| ext.eq_ignore_ascii_case("rs")) - /// .unwrap_or(false) + /// .map_or(false, |ext| ext.eq_ignore_ascii_case("rs")) /// } /// ``` #[clippy::version = "1.51.0"] From 343476df0f8cd09e1b49063ba75cb42304336887 Mon Sep 17 00:00:00 2001 From: Serial <69764315+Serial-ATA@users.noreply.github.com> Date: Tue, 16 Aug 2022 17:17:21 -0400 Subject: [PATCH 3741/5092] Use `CARGO_TARGET_DIR` in compile-test --- tests/compile-test.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 610f1f14563d..6ef90c030b7e 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -403,7 +403,8 @@ const RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS: &[&str] = &[ ]; fn check_rustfix_coverage() { - let missing_coverage_path = Path::new("target/debug/test/ui/rustfix_missing_coverage.txt"); + let target_dir = PathBuf::from(std::env::var("CARGO_TARGET_DIR").unwrap()); + let missing_coverage_path = target_dir.join("debug/test/ui/rustfix_missing_coverage.txt"); if let Ok(missing_coverage_contents) = std::fs::read_to_string(missing_coverage_path) { assert!(RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS.iter().is_sorted_by_key(Path::new)); From a05cb74d3080f0359a97c7380913edd2a5ebe7ee Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius III" Date: Fri, 8 Jul 2022 05:29:10 -0400 Subject: [PATCH 3742/5092] Enhance `needless_borrow` to consider trait implementations --- clippy_lints/src/dereference.rs | 307 ++++++++++++++++-- clippy_lints/src/lib.rs | 2 +- .../src/methods/unnecessary_to_owned.rs | 19 +- clippy_utils/src/msrvs.rs | 2 +- tests/ui/needless_borrow.fixed | 117 ++++++- tests/ui/needless_borrow.rs | 117 ++++++- tests/ui/needless_borrow.stderr | 48 ++- 7 files changed, 559 insertions(+), 53 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index e0b94f7190af..e38704701ea6 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1,24 +1,31 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; -use clippy_utils::ty::{expr_sig, peel_mid_ty_refs, ty_sig, variant_of_res}; -use clippy_utils::{get_parent_expr, is_lint_allowed, path_to_local, walk_to_expr_usage}; +use clippy_utils::ty::{contains_ty, expr_sig, is_copy, peel_mid_ty_refs, ty_sig, variant_of_res}; +use clippy_utils::{fn_def_id, get_parent_expr, is_lint_allowed, meets_msrv, msrvs, path_to_local, walk_to_expr_usage}; use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX}; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_ty, Visitor}; use rustc_hir::{ - self as hir, BindingAnnotation, Body, BodyId, BorrowKind, Closure, Expr, ExprKind, FnRetTy, GenericArg, HirId, - ImplItem, ImplItemKind, Item, ItemKind, Local, MatchSource, Mutability, Node, Pat, PatKind, Path, QPath, TraitItem, - TraitItemKind, TyKind, UnOp, + self as hir, def_id::DefId, BindingAnnotation, Body, BodyId, BorrowKind, Closure, Expr, ExprKind, FnRetTy, + GenericArg, HirId, ImplItem, ImplItemKind, Item, ItemKind, Local, MatchSource, Mutability, Node, Pat, PatKind, + Path, QPath, TraitItem, TraitItemKind, TyKind, UnOp, }; +use rustc_index::bit_set::BitSet; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; -use rustc_middle::ty::{self, Binder, BoundVariableKind, List, Ty, TyCtxt, TypeVisitable, TypeckResults}; +use rustc_middle::ty::{ + self, subst::Subst, Binder, BoundVariableKind, EarlyBinder, FnSig, GenericArgKind, List, ParamTy, PredicateKind, + ProjectionPredicate, Ty, TyCtxt, TypeVisitable, TypeckResults, +}; +use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP}; -use rustc_trait_selection::infer::InferCtxtExt; +use rustc_trait_selection::infer::InferCtxtExt as _; +use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause}; +use std::collections::VecDeque; declare_clippy_lint! { /// ### What it does @@ -151,6 +158,7 @@ pub struct Dereferencing { /// been finished. Note we can't lint at the end of every body as they can be nested within each /// other. current_body: Option, + /// The list of locals currently being checked by the lint. /// If the value is `None`, then the binding has been seen as a ref pattern, but is not linted. /// This is needed for or patterns where one of the branches can be linted, but another can not @@ -158,6 +166,19 @@ pub struct Dereferencing { /// /// e.g. `m!(x) | Foo::Bar(ref x)` ref_locals: FxIndexMap>, + + // `IntoIterator` for arrays requires Rust 1.53. + msrv: Option, +} + +impl Dereferencing { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { + msrv, + ..Dereferencing::default() + } + } } struct StateData { @@ -170,6 +191,7 @@ struct StateData { struct DerefedBorrow { count: usize, msg: &'static str, + snip_expr: Option, } enum State { @@ -250,7 +272,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { match (self.state.take(), kind) { (None, kind) => { let expr_ty = typeck.expr_ty(expr); - let (position, adjustments) = walk_parents(cx, expr); + let (position, adjustments) = walk_parents(cx, expr, self.msrv); match kind { RefOp::Deref => { @@ -331,20 +353,23 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { let deref_msg = "this expression creates a reference which is immediately dereferenced by the compiler"; let borrow_msg = "this expression borrows a value the compiler would automatically borrow"; + let impl_msg = "the borrowed expression implements the required traits"; - let (required_refs, msg) = if position.can_auto_borrow() { - (1, if deref_count == 1 { borrow_msg } else { deref_msg }) + let (required_refs, msg, snip_expr) = if position.can_auto_borrow() { + (1, if deref_count == 1 { borrow_msg } else { deref_msg }, None) + } else if let Position::ImplArg(hir_id) = position { + (0, impl_msg, Some(hir_id)) } else if let Some(&Adjust::Borrow(AutoBorrow::Ref(_, mutability))) = next_adjust.map(|a| &a.kind) { if matches!(mutability, AutoBorrowMutability::Mut { .. }) && !position.is_reborrow_stable() { - (3, deref_msg) + (3, deref_msg, None) } else { - (2, deref_msg) + (2, deref_msg, None) } } else { - (2, deref_msg) + (2, deref_msg, None) }; if deref_count >= required_refs { @@ -354,6 +379,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { // can't be removed without breaking the code. See earlier comment. count: deref_count - required_refs, msg, + snip_expr, }), StateData { span: expr.span, hir_id: expr.hir_id, position }, )); @@ -510,7 +536,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { spans: vec![pat.span], app, replacements: vec![(pat.span, snip.into())], - hir_id: pat.hir_id + hir_id: pat.hir_id, }), ); } @@ -542,6 +568,8 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { self.current_body = None; } } + + extract_msrv_attr!(LateContext); } fn try_parse_ref_op<'tcx>( @@ -594,6 +622,7 @@ enum Position { /// The method is defined on a reference type. e.g. `impl Foo for &T` MethodReceiverRefImpl, Callee, + ImplArg(HirId), FieldAccess(Symbol), Postfix, Deref, @@ -630,7 +659,7 @@ impl Position { | Self::Callee | Self::FieldAccess(_) | Self::Postfix => PREC_POSTFIX, - Self::Deref => PREC_PREFIX, + Self::ImplArg(_) | Self::Deref => PREC_PREFIX, Self::DerefStable(p, _) | Self::ReborrowStable(p) | Self::Other(p) => p, } } @@ -639,8 +668,12 @@ impl Position { /// Walks up the parent expressions attempting to determine both how stable the auto-deref result /// is, and which adjustments will be applied to it. Note this will not consider auto-borrow /// locations as those follow different rules. -#[allow(clippy::too_many_lines)] -fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &'tcx [Adjustment<'tcx>]) { +#[expect(clippy::too_many_lines)] +fn walk_parents<'tcx>( + cx: &LateContext<'tcx>, + e: &'tcx Expr<'_>, + msrv: Option, +) -> (Position, &'tcx [Adjustment<'tcx>]) { let mut adjustments = [].as_slice(); let mut precedence = 0i8; let ctxt = e.span.ctxt(); @@ -732,13 +765,20 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & .iter() .position(|arg| arg.hir_id == child_id) .zip(expr_sig(cx, func)) - .and_then(|(i, sig)| sig.input_with_hir(i)) - .map(|(hir_ty, ty)| match hir_ty { - // Type inference for closures can depend on how they're called. Only go by the explicit - // types here. - Some(hir_ty) => binding_ty_auto_deref_stability(cx, hir_ty, precedence, ty.bound_vars()), - None => ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence) - .position_for_arg(), + .and_then(|(i, sig)| { + sig.input_with_hir(i).map(|(hir_ty, ty)| match hir_ty { + // Type inference for closures can depend on how they're called. Only go by the explicit + // types here. + Some(hir_ty) => binding_ty_auto_deref_stability(cx, hir_ty, precedence, ty.bound_vars()), + None => { + if let ty::Param(param_ty) = ty.skip_binder().kind() { + needless_borrow_impl_arg_position(cx, parent, i, *param_ty, e, precedence, msrv) + } else { + ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence) + .position_for_arg() + } + }, + }) }), ExprKind::MethodCall(_, args, _) => { let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap(); @@ -779,12 +819,17 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & Position::MethodReceiver } } else { - ty_auto_deref_stability( - cx, - cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)), - precedence, - ) - .position_for_arg() + let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i]; + if let ty::Param(param_ty) = ty.kind() { + needless_borrow_impl_arg_position(cx, parent, i, *param_ty, e, precedence, msrv) + } else { + ty_auto_deref_stability( + cx, + cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)), + precedence, + ) + .position_for_arg() + } } }) }, @@ -946,6 +991,205 @@ fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool { v.0 } +// Checks whether: +// * child is an expression of the form `&e` in an argument position requiring an `impl Trait` +// * `e`'s type implements `Trait` and is copyable +// If the conditions are met, returns `Some(Position::ImplArg(..))`; otherwise, returns `None`. +// The "is copyable" condition is to avoid the case where removing the `&` means `e` would have to +// be moved, but it cannot be. +fn needless_borrow_impl_arg_position<'tcx>( + cx: &LateContext<'tcx>, + parent: &Expr<'tcx>, + arg_index: usize, + param_ty: ParamTy, + mut expr: &Expr<'tcx>, + precedence: i8, + msrv: Option, +) -> Position { + let destruct_trait_def_id = cx.tcx.lang_items().destruct_trait(); + let sized_trait_def_id = cx.tcx.lang_items().sized_trait(); + + let Some(callee_def_id) = fn_def_id(cx, parent) else { return Position::Other(precedence) }; + let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder(); + let substs_with_expr_ty = cx + .typeck_results() + .node_substs(if let ExprKind::Call(callee, _) = parent.kind { + callee.hir_id + } else { + parent.hir_id + }); + + let predicates = cx.tcx.param_env(callee_def_id).caller_bounds(); + let projection_predicates = predicates + .iter() + .filter_map(|predicate| { + if let PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() { + Some(projection_predicate) + } else { + None + } + }) + .collect::>(); + + let mut trait_with_ref_mut_self_method = false; + + // If no traits were found, or only the `Destruct`, `Sized`, or `Any` traits were found, return. + if predicates + .iter() + .filter_map(|predicate| { + if let PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder() + && trait_predicate.trait_ref.self_ty() == param_ty.to_ty(cx.tcx) + { + Some(trait_predicate.trait_ref.def_id) + } else { + None + } + }) + .inspect(|trait_def_id| { + trait_with_ref_mut_self_method |= has_ref_mut_self_method(cx, *trait_def_id); + }) + .all(|trait_def_id| { + Some(trait_def_id) == destruct_trait_def_id + || Some(trait_def_id) == sized_trait_def_id + || cx.tcx.is_diagnostic_item(sym::Any, trait_def_id) + }) + { + return Position::Other(precedence); + } + + // `substs_with_referent_ty` can be constructed outside of `check_referent` because the same + // elements are modified each time `check_referent` is called. + let mut substs_with_referent_ty = substs_with_expr_ty.to_vec(); + + let mut check_referent = |referent| { + let referent_ty = cx.typeck_results().expr_ty(referent); + + if !is_copy(cx, referent_ty) { + return false; + } + + // https://github.com/rust-lang/rust-clippy/pull/9136#pullrequestreview-1037379321 + if trait_with_ref_mut_self_method && !matches!(referent_ty.kind(), ty::Ref(_, _, Mutability::Mut)) { + return false; + } + + if !replace_types( + cx, + param_ty, + referent_ty, + fn_sig, + arg_index, + &projection_predicates, + &mut substs_with_referent_ty, + ) { + return false; + } + + predicates.iter().all(|predicate| { + if let PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder() + && cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_predicate.trait_ref.def_id) + && let ty::Param(param_ty) = trait_predicate.self_ty().kind() + && let GenericArgKind::Type(ty) = substs_with_referent_ty[param_ty.index as usize].unpack() + && ty.is_array() + && !meets_msrv(msrv, msrvs::ARRAY_INTO_ITERATOR) + { + return false; + } + + let predicate = EarlyBinder(predicate).subst(cx.tcx, &substs_with_referent_ty); + let obligation = Obligation::new(ObligationCause::dummy(), cx.param_env, predicate); + cx.tcx + .infer_ctxt() + .enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation)) + }) + }; + + let mut needless_borrow = false; + while let ExprKind::AddrOf(_, _, referent) = expr.kind { + if !check_referent(referent) { + break; + } + expr = referent; + needless_borrow = true; + } + + if needless_borrow { + Position::ImplArg(expr.hir_id) + } else { + Position::Other(precedence) + } +} + +fn has_ref_mut_self_method(cx: &LateContext<'_>, trait_def_id: DefId) -> bool { + cx.tcx + .associated_items(trait_def_id) + .in_definition_order() + .any(|assoc_item| { + if assoc_item.fn_has_self_parameter { + let self_ty = cx.tcx.fn_sig(assoc_item.def_id).skip_binder().inputs()[0]; + matches!(self_ty.kind(), ty::Ref(_, _, Mutability::Mut)) + } else { + false + } + }) +} + +// Iteratively replaces `param_ty` with `new_ty` in `substs`, and similarly for each resulting +// projected type that is a type parameter. Returns `false` if replacing the types would have an +// effect on the function signature beyond substituting `new_ty` for `param_ty`. +// See: https://github.com/rust-lang/rust-clippy/pull/9136#discussion_r927212757 +fn replace_types<'tcx>( + cx: &LateContext<'tcx>, + param_ty: ParamTy, + new_ty: Ty<'tcx>, + fn_sig: FnSig<'tcx>, + arg_index: usize, + projection_predicates: &[ProjectionPredicate<'tcx>], + substs: &mut [ty::GenericArg<'tcx>], +) -> bool { + let mut replaced = BitSet::new_empty(substs.len()); + + let mut deque = VecDeque::with_capacity(substs.len()); + deque.push_back((param_ty, new_ty)); + + while let Some((param_ty, new_ty)) = deque.pop_front() { + // If `replaced.is_empty()`, then `param_ty` and `new_ty` are those initially passed in. + if !fn_sig + .inputs_and_output + .iter() + .enumerate() + .all(|(i, ty)| (replaced.is_empty() && i == arg_index) || !contains_ty(ty, param_ty.to_ty(cx.tcx))) + { + return false; + } + + substs[param_ty.index as usize] = ty::GenericArg::from(new_ty); + + // The `replaced.insert(...)` check provides some protection against infinite loops. + if replaced.insert(param_ty.index) { + for projection_predicate in projection_predicates { + if projection_predicate.projection_ty.self_ty() == param_ty.to_ty(cx.tcx) + && let ty::Term::Ty(term_ty) = projection_predicate.term + && let ty::Param(term_param_ty) = term_ty.kind() + { + let item_def_id = projection_predicate.projection_ty.item_def_id; + let assoc_item = cx.tcx.associated_item(item_def_id); + let projection = cx.tcx + .mk_projection(assoc_item.def_id, cx.tcx.mk_substs_trait(new_ty, &[])); + + if let Ok(projected_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, projection) + && substs[term_param_ty.index as usize] != ty::GenericArg::from(projected_ty) + { + deque.push_back((*term_param_ty, projected_ty)); + } + } + } + } + } + + true +} + struct TyPosition<'tcx> { position: Position, ty: Option>, @@ -1084,7 +1328,8 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data }, State::DerefedBorrow(state) => { let mut app = Applicability::MachineApplicable; - let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app); + let snip_expr = state.snip_expr.map_or(expr, |hir_id| cx.tcx.hir().expect_expr(hir_id)); + let (snip, snip_is_macro) = snippet_with_context(cx, snip_expr.span, data.span.ctxt(), "..", &mut app); span_lint_hir_and_then(cx, NEEDLESS_BORROW, data.hir_id, data.span, state.msg, |diag| { let calls_field = matches!(expr.kind, ExprKind::Field(..)) && matches!(data.position, Position::Callee); let sugg = if !snip_is_macro diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index e6a405f8170d..521739c28ff6 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -821,7 +821,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(verbose_file_reads::VerboseFileReads)); store.register_late_pass(|| Box::new(redundant_pub_crate::RedundantPubCrate::default())); store.register_late_pass(|| Box::new(unnamed_address::UnnamedAddress)); - store.register_late_pass(|| Box::new(dereference::Dereferencing::default())); + store.register_late_pass(move || Box::new(dereference::Dereferencing::new(msrv))); store.register_late_pass(|| Box::new(option_if_let_else::OptionIfLetElse)); store.register_late_pass(|| Box::new(future_not_send::FutureNotSend)); store.register_late_pass(|| Box::new(if_let_mutex::IfLetMutex)); diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 99b56da7a50c..e4624167ad0c 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -6,9 +6,8 @@ use clippy_utils::ty::{ contains_ty, get_associated_type, get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, peel_mid_ty_refs, }; -use clippy_utils::{meets_msrv, msrvs}; - use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item}; +use clippy_utils::{meets_msrv, msrvs}; use rustc_errors::Applicability; use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind}; use rustc_lint::LateContext; @@ -373,25 +372,15 @@ fn get_input_traits_and_projections<'tcx>( ) -> (Vec>, Vec>) { let mut trait_predicates = Vec::new(); let mut projection_predicates = Vec::new(); - for (predicate, _) in cx.tcx.predicates_of(callee_def_id).predicates.iter() { - // `substs` should have 1 + n elements. The first is the type on the left hand side of an - // `as`. The remaining n are trait parameters. - let is_input_substs = |substs: SubstsRef<'tcx>| { - if_chain! { - if let Some(arg) = substs.iter().next(); - if let GenericArgKind::Type(arg_ty) = arg.unpack(); - if arg_ty == input; - then { true } else { false } - } - }; + for predicate in cx.tcx.param_env(callee_def_id).caller_bounds() { match predicate.kind().skip_binder() { PredicateKind::Trait(trait_predicate) => { - if is_input_substs(trait_predicate.trait_ref.substs) { + if trait_predicate.trait_ref.self_ty() == input { trait_predicates.push(trait_predicate); } }, PredicateKind::Projection(projection_predicate) => { - if is_input_substs(projection_predicate.projection_ty.substs) { + if projection_predicate.projection_ty.self_ty() == input { projection_predicates.push(projection_predicate); } }, diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 9e238c6f1ac0..7fa0046a267b 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -13,7 +13,7 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { 1,62,0 { BOOL_THEN_SOME } - 1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN } + 1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR } 1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST } 1,51,0 { BORROW_AS_PTR, UNSIGNED_ABS } 1,50,0 { BOOL_THEN } diff --git a/tests/ui/needless_borrow.fixed b/tests/ui/needless_borrow.fixed index bfd2725ecaaa..8cf93bd24817 100644 --- a/tests/ui/needless_borrow.fixed +++ b/tests/ui/needless_borrow.fixed @@ -1,6 +1,6 @@ // run-rustfix -#![feature(lint_reasons)] +#![feature(custom_inner_attributes, lint_reasons)] #[warn(clippy::all, clippy::needless_borrow)] #[allow(unused_variables, clippy::unnecessary_mut_passed)] @@ -127,6 +127,20 @@ fn main() { 0 } } + + let _ = std::process::Command::new("ls").args(["-a", "-l"]).status().unwrap(); + let _ = std::path::Path::new(".").join("."); + deref_target_is_x(X); + multiple_constraints([[""]]); + multiple_constraints_normalizes_to_same(X, X); + let _ = Some("").unwrap_or(""); + + only_sized(&""); // Don't lint. `Sized` is only bound + let _ = std::any::Any::type_id(&""); // Don't lint. `Any` is only bound + let _ = Box::new(&""); // Don't lint. Type parameter appears in return type + ref_as_ref_path(&""); // Don't lint. Argument type is not a type parameter + refs_only(&()); // Don't lint. `&T` implements trait, but `T` doesn't + multiple_constraints_normalizes_to_different(&[[""]], &[""]); // Don't lint. Projected type appears in arguments } #[allow(clippy::needless_borrowed_reference)] @@ -183,3 +197,104 @@ mod issue9160 { } } } + +#[derive(Clone, Copy)] +struct X; + +impl std::ops::Deref for X { + type Target = X; + fn deref(&self) -> &Self::Target { + self + } +} + +fn deref_target_is_x(_: T) +where + T: std::ops::Deref, +{ +} + +fn multiple_constraints(_: T) +where + T: IntoIterator + IntoIterator, + U: IntoIterator, + V: AsRef, + X: IntoIterator, + Y: AsRef, +{ +} + +fn multiple_constraints_normalizes_to_same(_: T, _: V) +where + T: std::ops::Deref, + U: std::ops::Deref, +{ +} + +fn only_sized(_: T) {} + +fn ref_as_ref_path(_: &'static T) +where + &'static T: AsRef, +{ +} + +trait RefsOnly { + type Referent; +} + +impl RefsOnly for &T { + type Referent = T; +} + +fn refs_only(_: T) +where + T: RefsOnly, +{ +} + +fn multiple_constraints_normalizes_to_different(_: T, _: U) +where + T: IntoIterator, + U: IntoIterator, + V: AsRef, +{ +} + +// https://github.com/rust-lang/rust-clippy/pull/9136#pullrequestreview-1037379321 +#[allow(dead_code)] +mod copyable_iterator { + #[derive(Clone, Copy)] + struct Iter; + impl Iterator for Iter { + type Item = (); + fn next(&mut self) -> Option { + None + } + } + fn takes_iter(_: impl Iterator) {} + fn dont_warn(mut x: Iter) { + takes_iter(&mut x); + } + fn warn(mut x: &mut Iter) { + takes_iter(&mut x) + } +} + +mod under_msrv { + #![allow(dead_code)] + #![clippy::msrv = "1.52.0"] + + fn foo() { + let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap(); + } +} + +mod meets_msrv { + #![allow(dead_code)] + #![clippy::msrv = "1.53.0"] + + fn foo() { + let _ = std::process::Command::new("ls").args(["-a", "-l"]).status().unwrap(); + } +} diff --git a/tests/ui/needless_borrow.rs b/tests/ui/needless_borrow.rs index c457d8c54718..fd9b2a11df96 100644 --- a/tests/ui/needless_borrow.rs +++ b/tests/ui/needless_borrow.rs @@ -1,6 +1,6 @@ // run-rustfix -#![feature(lint_reasons)] +#![feature(custom_inner_attributes, lint_reasons)] #[warn(clippy::all, clippy::needless_borrow)] #[allow(unused_variables, clippy::unnecessary_mut_passed)] @@ -127,6 +127,20 @@ fn main() { 0 } } + + let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap(); + let _ = std::path::Path::new(".").join(&&"."); + deref_target_is_x(&X); + multiple_constraints(&[[""]]); + multiple_constraints_normalizes_to_same(&X, X); + let _ = Some("").unwrap_or(&""); + + only_sized(&""); // Don't lint. `Sized` is only bound + let _ = std::any::Any::type_id(&""); // Don't lint. `Any` is only bound + let _ = Box::new(&""); // Don't lint. Type parameter appears in return type + ref_as_ref_path(&""); // Don't lint. Argument type is not a type parameter + refs_only(&()); // Don't lint. `&T` implements trait, but `T` doesn't + multiple_constraints_normalizes_to_different(&[[""]], &[""]); // Don't lint. Projected type appears in arguments } #[allow(clippy::needless_borrowed_reference)] @@ -183,3 +197,104 @@ mod issue9160 { } } } + +#[derive(Clone, Copy)] +struct X; + +impl std::ops::Deref for X { + type Target = X; + fn deref(&self) -> &Self::Target { + self + } +} + +fn deref_target_is_x(_: T) +where + T: std::ops::Deref, +{ +} + +fn multiple_constraints(_: T) +where + T: IntoIterator + IntoIterator, + U: IntoIterator, + V: AsRef, + X: IntoIterator, + Y: AsRef, +{ +} + +fn multiple_constraints_normalizes_to_same(_: T, _: V) +where + T: std::ops::Deref, + U: std::ops::Deref, +{ +} + +fn only_sized(_: T) {} + +fn ref_as_ref_path(_: &'static T) +where + &'static T: AsRef, +{ +} + +trait RefsOnly { + type Referent; +} + +impl RefsOnly for &T { + type Referent = T; +} + +fn refs_only(_: T) +where + T: RefsOnly, +{ +} + +fn multiple_constraints_normalizes_to_different(_: T, _: U) +where + T: IntoIterator, + U: IntoIterator, + V: AsRef, +{ +} + +// https://github.com/rust-lang/rust-clippy/pull/9136#pullrequestreview-1037379321 +#[allow(dead_code)] +mod copyable_iterator { + #[derive(Clone, Copy)] + struct Iter; + impl Iterator for Iter { + type Item = (); + fn next(&mut self) -> Option { + None + } + } + fn takes_iter(_: impl Iterator) {} + fn dont_warn(mut x: Iter) { + takes_iter(&mut x); + } + fn warn(mut x: &mut Iter) { + takes_iter(&mut x) + } +} + +mod under_msrv { + #![allow(dead_code)] + #![clippy::msrv = "1.52.0"] + + fn foo() { + let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap(); + } +} + +mod meets_msrv { + #![allow(dead_code)] + #![clippy::msrv = "1.53.0"] + + fn foo() { + let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap(); + } +} diff --git a/tests/ui/needless_borrow.stderr b/tests/ui/needless_borrow.stderr index 66588689d818..5af68706d4ba 100644 --- a/tests/ui/needless_borrow.stderr +++ b/tests/ui/needless_borrow.stderr @@ -120,17 +120,59 @@ error: this expression creates a reference which is immediately dereferenced by LL | (&&5).foo(); | ^^^^^ help: change this to: `(&5)` +error: the borrowed expression implements the required traits + --> $DIR/needless_borrow.rs:131:51 + | +LL | let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap(); + | ^^^^^^^^^^^^^ help: change this to: `["-a", "-l"]` + +error: the borrowed expression implements the required traits + --> $DIR/needless_borrow.rs:132:44 + | +LL | let _ = std::path::Path::new(".").join(&&"."); + | ^^^^^ help: change this to: `"."` + +error: the borrowed expression implements the required traits + --> $DIR/needless_borrow.rs:133:23 + | +LL | deref_target_is_x(&X); + | ^^ help: change this to: `X` + +error: the borrowed expression implements the required traits + --> $DIR/needless_borrow.rs:134:26 + | +LL | multiple_constraints(&[[""]]); + | ^^^^^^^ help: change this to: `[[""]]` + +error: the borrowed expression implements the required traits + --> $DIR/needless_borrow.rs:135:45 + | +LL | multiple_constraints_normalizes_to_same(&X, X); + | ^^ help: change this to: `X` + +error: this expression creates a reference which is immediately dereferenced by the compiler + --> $DIR/needless_borrow.rs:136:32 + | +LL | let _ = Some("").unwrap_or(&""); + | ^^^ help: change this to: `""` + error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:173:13 + --> $DIR/needless_borrow.rs:187:13 | LL | (&self.f)() | ^^^^^^^^^ help: change this to: `(self.f)` error: this expression borrows a value the compiler would automatically borrow - --> $DIR/needless_borrow.rs:182:13 + --> $DIR/needless_borrow.rs:196:13 | LL | (&mut self.f)() | ^^^^^^^^^^^^^ help: change this to: `(self.f)` -error: aborting due to 22 previous errors +error: the borrowed expression implements the required traits + --> $DIR/needless_borrow.rs:298:55 + | +LL | let _ = std::process::Command::new("ls").args(&["-a", "-l"]).status().unwrap(); + | ^^^^^^^^^^^^^ help: change this to: `["-a", "-l"]` + +error: aborting due to 29 previous errors From 032f112745d2632fc37175fad7bab98215062586 Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius III" Date: Fri, 8 Jul 2022 05:30:17 -0400 Subject: [PATCH 3743/5092] Fix adjacent code --- clippy_dev/src/bless.rs | 2 +- clippy_dev/src/fmt.rs | 8 ++++---- clippy_dev/src/update_lints.rs | 4 ++-- rustc_tools_util/src/lib.rs | 4 ++-- tests/check-fmt.rs | 2 +- tests/dogfood.rs | 4 ++-- tests/integration.rs | 4 ++-- tests/lint_message_convention.rs | 4 ++-- tests/ui/regex.rs | 2 +- tests/ui/same_item_push.rs | 1 + tests/ui/verbose_file_reads.rs | 2 +- tests/workspace.rs | 14 +++++++------- 12 files changed, 26 insertions(+), 25 deletions(-) diff --git a/clippy_dev/src/bless.rs b/clippy_dev/src/bless.rs index f5c51b9474fc..92b2771f3fe7 100644 --- a/clippy_dev/src/bless.rs +++ b/clippy_dev/src/bless.rs @@ -37,7 +37,7 @@ fn update_reference_file(test_output_entry: &DirEntry, ignore_timestamp: bool) { return; } - let test_output_file = fs::read(&test_output_path).expect("Unable to read test output file"); + let test_output_file = fs::read(test_output_path).expect("Unable to read test output file"); let reference_file = fs::read(&reference_file_path).unwrap_or_default(); if test_output_file != reference_file { diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs index 3b27f061eb0b..357cf6fc43aa 100644 --- a/clippy_dev/src/fmt.rs +++ b/clippy_dev/src/fmt.rs @@ -46,7 +46,7 @@ pub fn run(check: bool, verbose: bool) { // dependency if fs::read_to_string(project_root.join("Cargo.toml")) .expect("Failed to read clippy Cargo.toml") - .contains(&"[target.'cfg(NOT_A_PLATFORM)'.dependencies]") + .contains("[target.'cfg(NOT_A_PLATFORM)'.dependencies]") { return Err(CliError::IntellijSetupActive); } @@ -193,10 +193,10 @@ fn rustfmt_test(context: &FmtContext) -> Result<(), CliError> { let args = &["--version"]; if context.verbose { - println!("{}", format_command(&program, &dir, args)); + println!("{}", format_command(program, &dir, args)); } - let output = Command::new(&program).current_dir(&dir).args(args.iter()).output()?; + let output = Command::new(program).current_dir(&dir).args(args.iter()).output()?; if output.status.success() { Ok(()) @@ -207,7 +207,7 @@ fn rustfmt_test(context: &FmtContext) -> Result<(), CliError> { Err(CliError::RustfmtNotInstalled) } else { Err(CliError::CommandFailed( - format_command(&program, &dir, args), + format_command(program, &dir, args), std::str::from_utf8(&output.stderr).unwrap_or("").to_string(), )) } diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 05e79a241884..c503142e5e45 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -418,7 +418,7 @@ fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec) -> io .expect("failed to find `impl_lint_pass` terminator"); impl_lint_pass_end += impl_lint_pass_start; - if let Some(lint_name_pos) = content[impl_lint_pass_start..impl_lint_pass_end].find(&lint_name_upper) { + if let Some(lint_name_pos) = content[impl_lint_pass_start..impl_lint_pass_end].find(lint_name_upper) { let mut lint_name_end = impl_lint_pass_start + (lint_name_pos + lint_name_upper.len()); for c in content[lint_name_end..impl_lint_pass_end].chars() { // Remove trailing whitespace @@ -451,7 +451,7 @@ fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec) -> io } let mut content = - fs::read_to_string(&path).unwrap_or_else(|_| panic!("failed to read `{}`", path.to_string_lossy())); + fs::read_to_string(path).unwrap_or_else(|_| panic!("failed to read `{}`", path.to_string_lossy())); eprintln!( "warn: you will have to manually remove any code related to `{}` from `{}`", diff --git a/rustc_tools_util/src/lib.rs b/rustc_tools_util/src/lib.rs index 5f289918a7c1..429dddc42ea9 100644 --- a/rustc_tools_util/src/lib.rs +++ b/rustc_tools_util/src/lib.rs @@ -84,7 +84,7 @@ impl std::fmt::Debug for VersionInfo { #[must_use] pub fn get_commit_hash() -> Option { std::process::Command::new("git") - .args(&["rev-parse", "--short", "HEAD"]) + .args(["rev-parse", "--short", "HEAD"]) .output() .ok() .and_then(|r| String::from_utf8(r.stdout).ok()) @@ -93,7 +93,7 @@ pub fn get_commit_hash() -> Option { #[must_use] pub fn get_commit_date() -> Option { std::process::Command::new("git") - .args(&["log", "-1", "--date=short", "--pretty=format:%cd"]) + .args(["log", "-1", "--date=short", "--pretty=format:%cd"]) .output() .ok() .and_then(|r| String::from_utf8(r.stdout).ok()) diff --git a/tests/check-fmt.rs b/tests/check-fmt.rs index 0defd45b68b0..e106583de4a2 100644 --- a/tests/check-fmt.rs +++ b/tests/check-fmt.rs @@ -13,7 +13,7 @@ fn fmt() { let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); let output = Command::new("cargo") .current_dir(root_dir) - .args(&["dev", "fmt", "--check"]) + .args(["dev", "fmt", "--check"]) .output() .unwrap(); diff --git a/tests/dogfood.rs b/tests/dogfood.rs index 5697e8680cd6..961525bbd910 100644 --- a/tests/dogfood.rs +++ b/tests/dogfood.rs @@ -87,11 +87,11 @@ fn run_clippy_for_package(project: &str, args: &[&str]) { if cfg!(feature = "internal") { // internal lints only exist if we build with the internal feature - command.args(&["-D", "clippy::internal"]); + command.args(["-D", "clippy::internal"]); } else { // running a clippy built without internal lints on the clippy source // that contains e.g. `allow(clippy::invalid_paths)` - command.args(&["-A", "unknown_lints"]); + command.args(["-A", "unknown_lints"]); } let output = command.output().unwrap(); diff --git a/tests/integration.rs b/tests/integration.rs index c64425fa01a4..23a9bef3ccce 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -19,7 +19,7 @@ fn integration_test() { repo_dir.push(crate_name); let st = Command::new("git") - .args(&[ + .args([ OsStr::new("clone"), OsStr::new("--depth=1"), OsStr::new(&repo_url), @@ -37,7 +37,7 @@ fn integration_test() { .current_dir(repo_dir) .env("RUST_BACKTRACE", "full") .env("CARGO_TARGET_DIR", target_dir) - .args(&[ + .args([ "clippy", "--all-targets", "--all-features", diff --git a/tests/lint_message_convention.rs b/tests/lint_message_convention.rs index c3aae1a9aa2d..2e0f4e76075b 100644 --- a/tests/lint_message_convention.rs +++ b/tests/lint_message_convention.rs @@ -19,7 +19,7 @@ impl Message { // we don't want the first letter after "error: ", "help: " ... to be capitalized // also no punctuation (except for "?" ?) at the end of a line static REGEX_SET: LazyLock = LazyLock::new(|| { - RegexSet::new(&[ + RegexSet::new([ r"error: [A-Z]", r"help: [A-Z]", r"warning: [A-Z]", @@ -37,7 +37,7 @@ impl Message { // sometimes the first character is capitalized and it is legal (like in "C-like enum variants") or // we want to ask a question ending in "?" static EXCEPTIONS_SET: LazyLock = LazyLock::new(|| { - RegexSet::new(&[ + RegexSet::new([ r"\.\.\.$", r".*C-like enum variant discriminant is not portable to 32-bit targets", r".*Intel x86 assembly syntax used", diff --git a/tests/ui/regex.rs b/tests/ui/regex.rs index f7f3b195ccc1..f0e1a8128d7c 100644 --- a/tests/ui/regex.rs +++ b/tests/ui/regex.rs @@ -1,4 +1,4 @@ -#![allow(unused)] +#![allow(unused, clippy::needless_borrow)] #![warn(clippy::invalid_regex, clippy::trivial_regex)] extern crate regex; diff --git a/tests/ui/same_item_push.rs b/tests/ui/same_item_push.rs index 99964f0de075..af01a8df71b0 100644 --- a/tests/ui/same_item_push.rs +++ b/tests/ui/same_item_push.rs @@ -151,6 +151,7 @@ fn main() { // Fix #6987 let mut vec = Vec::new(); + #[allow(clippy::needless_borrow)] for _ in 0..10 { vec.push(1); vec.extend(&[2]); diff --git a/tests/ui/verbose_file_reads.rs b/tests/ui/verbose_file_reads.rs index e0065e05ade6..df267e9872a0 100644 --- a/tests/ui/verbose_file_reads.rs +++ b/tests/ui/verbose_file_reads.rs @@ -18,7 +18,7 @@ fn main() -> std::io::Result<()> { s.read_to_end(); s.read_to_string(); // Should catch this - let mut f = File::open(&path)?; + let mut f = File::open(path)?; let mut buffer = Vec::new(); f.read_to_end(&mut buffer)?; // ...and this diff --git a/tests/workspace.rs b/tests/workspace.rs index e13efb3e0164..95325e060378 100644 --- a/tests/workspace.rs +++ b/tests/workspace.rs @@ -20,8 +20,8 @@ fn test_no_deps_ignores_path_deps_in_workspaces() { .current_dir(&cwd) .env("CARGO_TARGET_DIR", &target_dir) .arg("clean") - .args(&["-p", "subcrate"]) - .args(&["-p", "path_dep"]) + .args(["-p", "subcrate"]) + .args(["-p", "path_dep"]) .output() .unwrap(); @@ -32,11 +32,11 @@ fn test_no_deps_ignores_path_deps_in_workspaces() { .env("CARGO_INCREMENTAL", "0") .env("CARGO_TARGET_DIR", &target_dir) .arg("clippy") - .args(&["-p", "subcrate"]) + .args(["-p", "subcrate"]) .arg("--no-deps") .arg("--") .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir - .args(&["--cfg", r#"feature="primary_package_test""#]) + .args(["--cfg", r#"feature="primary_package_test""#]) .output() .unwrap(); println!("status: {}", output.status); @@ -52,10 +52,10 @@ fn test_no_deps_ignores_path_deps_in_workspaces() { .env("CARGO_INCREMENTAL", "0") .env("CARGO_TARGET_DIR", &target_dir) .arg("clippy") - .args(&["-p", "subcrate"]) + .args(["-p", "subcrate"]) .arg("--") .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir - .args(&["--cfg", r#"feature="primary_package_test""#]) + .args(["--cfg", r#"feature="primary_package_test""#]) .output() .unwrap(); println!("status: {}", output.status); @@ -79,7 +79,7 @@ fn test_no_deps_ignores_path_deps_in_workspaces() { .env("CARGO_INCREMENTAL", "0") .env("CARGO_TARGET_DIR", &target_dir) .arg("clippy") - .args(&["-p", "subcrate"]) + .args(["-p", "subcrate"]) .arg("--") .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir .output() From 48cb816530e020f568b0b578c22a791ee85f2868 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 16 Aug 2022 21:22:29 -0400 Subject: [PATCH 3744/5092] Handle `CARGO_TARGET_DIR` not being set in compile-test --- tests/compile-test.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/compile-test.rs b/tests/compile-test.rs index 6ef90c030b7e..9d0320bf065e 100644 --- a/tests/compile-test.rs +++ b/tests/compile-test.rs @@ -403,8 +403,12 @@ const RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS: &[&str] = &[ ]; fn check_rustfix_coverage() { - let target_dir = PathBuf::from(std::env::var("CARGO_TARGET_DIR").unwrap()); - let missing_coverage_path = target_dir.join("debug/test/ui/rustfix_missing_coverage.txt"); + let missing_coverage_path = Path::new("debug/test/ui/rustfix_missing_coverage.txt"); + let missing_coverage_path = if let Ok(target_dir) = std::env::var("CARGO_TARGET_DIR") { + PathBuf::from(target_dir).join(missing_coverage_path) + } else { + missing_coverage_path.to_path_buf() + }; if let Ok(missing_coverage_contents) = std::fs::read_to_string(missing_coverage_path) { assert!(RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS.iter().is_sorted_by_key(Path::new)); From aadd0148632645a3244c0ca119d47c5a736c042a Mon Sep 17 00:00:00 2001 From: cherryblossom <31467609+cherryblossom000@users.noreply.github.com> Date: Wed, 17 Aug 2022 18:56:06 +1000 Subject: [PATCH 3745/5092] Fix typo in as_undescore docs du -> due --- clippy_lints/src/as_underscore.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/as_underscore.rs b/clippy_lints/src/as_underscore.rs index 0bdef9d0a7e8..5b4b2c631c89 100644 --- a/clippy_lints/src/as_underscore.rs +++ b/clippy_lints/src/as_underscore.rs @@ -12,7 +12,7 @@ declare_clippy_lint! { /// /// ### Why is this bad? /// The conversion might include lossy conversion and dangerous cast that might go - /// undetected du to the type being inferred. + /// undetected due to the type being inferred. /// /// The lint is allowed by default as using `_` is less wordy than always specifying the type. /// From b4bdd5ca10d8887b32b0f2010f4c16e5f0285b26 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Aug 2022 07:44:12 -0400 Subject: [PATCH 3746/5092] fix vscode configuration --- CONTRIBUTING.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 42f77b5cbc0e..b2964e046ecb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -174,16 +174,14 @@ to `.vscode/settings.json` in your local Miri clone: "check", "--message-format=json" ], - "rust-analyzer.buildScripts.overrideCommand": [ + // Contrary to what the name suggests, this also affects proc macros. + "rust-analyzer.cargo.buildScripts.overrideCommand": [ "env", "MIRI_AUTO_OPS=no", "./miri", "check", "--message-format=json", ], - "rust-analyzer.rustfmt.extraArgs": [ - "+nightly" - ], } ``` From ab91d5a5408cdb888b49ed3d893c0e28afef5861 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Wed, 17 Aug 2022 18:58:17 +0200 Subject: [PATCH 3747/5092] unwrap_used: Fix error message for unwrap_err when expect_used is allowed --- clippy_lints/src/methods/unwrap_used.rs | 6 +++--- tests/ui/expect.rs | 3 ++- tests/ui/expect.stderr | 10 +++++++++- tests/ui/unwrap.rs | 3 ++- tests/ui/unwrap.stderr | 10 +++++++++- 5 files changed, 25 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/methods/unwrap_used.rs b/clippy_lints/src/methods/unwrap_used.rs index 05915c141090..ee17f2d7889e 100644 --- a/clippy_lints/src/methods/unwrap_used.rs +++ b/clippy_lints/src/methods/unwrap_used.rs @@ -25,7 +25,7 @@ pub(super) fn check( None }; - let method = if is_err { "unwrap_err" } else { "unwrap" }; + let method_suffix = if is_err { "_err" } else { "" }; if allow_unwrap_in_tests && is_in_test_function(cx.tcx, expr.hir_id) { return; @@ -35,7 +35,7 @@ pub(super) fn check( let help = if is_lint_allowed(cx, EXPECT_USED, expr.hir_id) { format!( "if you don't want to handle the `{none_value}` case gracefully, consider \ - using `expect()` to provide a better panic message" + using `expect{method_suffix}()` to provide a better panic message" ) } else { format!("if this value is {none_prefix}`{none_value}`, it will panic") @@ -45,7 +45,7 @@ pub(super) fn check( cx, lint, expr.span, - &format!("used `{method}()` on `{kind}` value"), + &format!("used `unwrap{method_suffix}()` on `{kind}` value"), None, &help, ); diff --git a/tests/ui/expect.rs b/tests/ui/expect.rs index 1073acf6f0cd..d742595e14d4 100644 --- a/tests/ui/expect.rs +++ b/tests/ui/expect.rs @@ -6,8 +6,9 @@ fn expect_option() { } fn expect_result() { - let res: Result = Ok(0); + let res: Result = Ok(0); let _ = res.expect(""); + let _ = res.expect_err(""); } fn main() { diff --git a/tests/ui/expect.stderr b/tests/ui/expect.stderr index ab28aac45563..904c09046452 100644 --- a/tests/ui/expect.stderr +++ b/tests/ui/expect.stderr @@ -15,5 +15,13 @@ LL | let _ = res.expect(""); | = help: if this value is an `Err`, it will panic -error: aborting due to 2 previous errors +error: used `expect_err()` on `a Result` value + --> $DIR/expect.rs:11:13 + | +LL | let _ = res.expect_err(""); + | ^^^^^^^^^^^^^^^^^^ + | + = help: if this value is an `Ok`, it will panic + +error: aborting due to 3 previous errors diff --git a/tests/ui/unwrap.rs b/tests/ui/unwrap.rs index a4a3cd1d3797..d9fd402e7cfb 100644 --- a/tests/ui/unwrap.rs +++ b/tests/ui/unwrap.rs @@ -6,8 +6,9 @@ fn unwrap_option() { } fn unwrap_result() { - let res: Result = Ok(0); + let res: Result = Ok(0); let _ = res.unwrap(); + let _ = res.unwrap_err(); } fn main() { diff --git a/tests/ui/unwrap.stderr b/tests/ui/unwrap.stderr index 4f0858005f6e..78422757819d 100644 --- a/tests/ui/unwrap.stderr +++ b/tests/ui/unwrap.stderr @@ -15,5 +15,13 @@ LL | let _ = res.unwrap(); | = help: if you don't want to handle the `Err` case gracefully, consider using `expect()` to provide a better panic message -error: aborting due to 2 previous errors +error: used `unwrap_err()` on `a Result` value + --> $DIR/unwrap.rs:11:13 + | +LL | let _ = res.unwrap_err(); + | ^^^^^^^^^^^^^^^^ + | + = help: if you don't want to handle the `Ok` case gracefully, consider using `expect_err()` to provide a better panic message + +error: aborting due to 3 previous errors From b2a17e9bd10b6a777485d9e37fa0289bf5ecf62f Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 3 Jul 2022 12:20:40 +0200 Subject: [PATCH 3748/5092] Keep ctxt in encoded span representation. --- compiler/rustc_span/src/lib.rs | 3 --- compiler/rustc_span/src/span_encoding.rs | 32 +++++++++++++++++------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index cf3069281514..c8dc1c1adcf2 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -533,9 +533,6 @@ impl Span { self.data().with_hi(hi) } #[inline] - pub fn ctxt(self) -> SyntaxContext { - self.data_untracked().ctxt - } pub fn eq_ctxt(self, other: Span) -> bool { self.data_untracked().ctxt == other.data_untracked().ctxt } diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index 3ee329e9736f..708ca43f4be9 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -28,12 +28,12 @@ use rustc_data_structures::fx::FxIndexSet; /// Inline (compressed) format: /// - `span.base_or_index == span_data.lo` /// - `span.len_or_tag == len == span_data.hi - span_data.lo` (must be `<= MAX_LEN`) -/// - `span.ctxt == span_data.ctxt` (must be `<= MAX_CTXT`) +/// - `span.ctxt == span_data.ctxt` (must be `< MAX_CTXT`) /// /// Interned format: /// - `span.base_or_index == index` (indexes into the interner table) /// - `span.len_or_tag == LEN_TAG` (high bit set, all other bits are zero) -/// - `span.ctxt == 0` +/// - `span.ctxt == span_data.ctxt` (must be < `MAX_CTXT`) or `MAX_CTXT` otherwise /// /// The inline form uses 0 for the tag value (rather than 1) so that we don't /// need to mask out the tag bit when getting the length, and so that the @@ -65,7 +65,7 @@ use rustc_data_structures::fx::FxIndexSet; pub struct Span { base_or_index: u32, len_or_tag: u16, - ctxt_or_zero: u16, + ctxt_or_max: u16, } const LEN_TAG: u16 = 0b1000_0000_0000_0000; @@ -73,7 +73,7 @@ const MAX_LEN: u32 = 0b0111_1111_1111_1111; const MAX_CTXT: u32 = 0b1111_1111_1111_1111; /// Dummy span, both position and length are zero, syntax context is zero as well. -pub const DUMMY_SP: Span = Span { base_or_index: 0, len_or_tag: 0, ctxt_or_zero: 0 }; +pub const DUMMY_SP: Span = Span { base_or_index: 0, len_or_tag: 0, ctxt_or_max: 0 }; impl Span { #[inline] @@ -89,14 +89,15 @@ impl Span { let (base, len, ctxt2) = (lo.0, hi.0 - lo.0, ctxt.as_u32()); - if len <= MAX_LEN && ctxt2 <= MAX_CTXT && parent.is_none() { + if len <= MAX_LEN && ctxt2 < MAX_CTXT && parent.is_none() { // Inline format. - Span { base_or_index: base, len_or_tag: len as u16, ctxt_or_zero: ctxt2 as u16 } + Span { base_or_index: base, len_or_tag: len as u16, ctxt_or_max: ctxt2 as u16 } } else { // Interned format. let index = with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt, parent })); - Span { base_or_index: index, len_or_tag: LEN_TAG, ctxt_or_zero: 0 } + let ctxt_or_max = if ctxt2 < MAX_CTXT { ctxt2 } else { MAX_CTXT } as u16; + Span { base_or_index: index, len_or_tag: LEN_TAG, ctxt_or_max } } } @@ -119,16 +120,29 @@ impl Span { SpanData { lo: BytePos(self.base_or_index), hi: BytePos(self.base_or_index + self.len_or_tag as u32), - ctxt: SyntaxContext::from_u32(self.ctxt_or_zero as u32), + ctxt: SyntaxContext::from_u32(self.ctxt_or_max as u32), parent: None, } } else { // Interned format. - debug_assert!(self.ctxt_or_zero == 0); let index = self.base_or_index; with_span_interner(|interner| interner.spans[index as usize]) } } + + /// This function is used as a fast path when decoding the full `SpanData` is not necessary. + #[inline] + pub fn ctxt(self) -> SyntaxContext { + let ctxt_or_max = self.ctxt_or_max as u32; + if ctxt_or_max < MAX_CTXT { + // Inline format or interned format with inline ctxt. + SyntaxContext::from_u32(ctxt_or_max) + } else { + // Interned format. + let index = self.base_or_index; + with_span_interner(|interner| interner.spans[index as usize].ctxt) + } + } } #[derive(Default)] From 3e67bded92b389dfdb56f7a9a40e85b8be4d4d4c Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 4 Jul 2022 09:40:30 +0200 Subject: [PATCH 3749/5092] Make names more explicit. --- compiler/rustc_span/src/span_encoding.rs | 36 ++++++++++++++---------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index 708ca43f4be9..b3de67415940 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -28,12 +28,17 @@ use rustc_data_structures::fx::FxIndexSet; /// Inline (compressed) format: /// - `span.base_or_index == span_data.lo` /// - `span.len_or_tag == len == span_data.hi - span_data.lo` (must be `<= MAX_LEN`) -/// - `span.ctxt == span_data.ctxt` (must be `< MAX_CTXT`) +/// - `span.ctxt_or_tag == span_data.ctxt` (must be `<= MAX_CTXT`) +/// +/// Interned format with inline `SyntaxContext`: +/// - `span.base_or_index == index` (indexes into the interner table) +/// - `span.len_or_tag == LEN_TAG` (high bit set, all other bits are zero) +/// - `span.ctxt_or_tag == span_data.ctxt` (must be `<= MAX_CTXT`) /// /// Interned format: /// - `span.base_or_index == index` (indexes into the interner table) /// - `span.len_or_tag == LEN_TAG` (high bit set, all other bits are zero) -/// - `span.ctxt == span_data.ctxt` (must be < `MAX_CTXT`) or `MAX_CTXT` otherwise +/// - `span.ctxt_or_tag == CTXT_TAG` /// /// The inline form uses 0 for the tag value (rather than 1) so that we don't /// need to mask out the tag bit when getting the length, and so that the @@ -50,10 +55,10 @@ use rustc_data_structures::fx::FxIndexSet; /// at 3 or 4, and then it drops off quickly from 8 onwards. 15 bits is enough /// for 99.99%+ of cases, but larger values (sometimes 20+ bits) might occur /// dozens of times in a typical crate. -/// - `ctxt` is 16 bits in `Span` and 32 bits in `SpanData`, which means that +/// - `ctxt_or_tag` is 16 bits in `Span` and 32 bits in `SpanData`, which means that /// large `ctxt` values will cause interning. The number of bits needed for /// `ctxt` values depend partly on the crate size and partly on the form of -/// the code. No crates in `rustc-perf` need more than 15 bits for `ctxt`, +/// the code. No crates in `rustc-perf` need more than 15 bits for `ctxt_or_tag`, /// but larger crates might need more than 16 bits. /// /// In order to reliably use parented spans in incremental compilation, @@ -65,15 +70,16 @@ use rustc_data_structures::fx::FxIndexSet; pub struct Span { base_or_index: u32, len_or_tag: u16, - ctxt_or_max: u16, + ctxt_or_tag: u16, } const LEN_TAG: u16 = 0b1000_0000_0000_0000; const MAX_LEN: u32 = 0b0111_1111_1111_1111; -const MAX_CTXT: u32 = 0b1111_1111_1111_1111; +const CTXT_TAG: u32 = 0b1111_1111_1111_1111; +const MAX_CTXT: u32 = CTXT_TAG - 1; /// Dummy span, both position and length are zero, syntax context is zero as well. -pub const DUMMY_SP: Span = Span { base_or_index: 0, len_or_tag: 0, ctxt_or_max: 0 }; +pub const DUMMY_SP: Span = Span { base_or_index: 0, len_or_tag: 0, ctxt_or_tag: 0 }; impl Span { #[inline] @@ -89,15 +95,15 @@ impl Span { let (base, len, ctxt2) = (lo.0, hi.0 - lo.0, ctxt.as_u32()); - if len <= MAX_LEN && ctxt2 < MAX_CTXT && parent.is_none() { + if len <= MAX_LEN && ctxt2 <= MAX_CTXT && parent.is_none() { // Inline format. - Span { base_or_index: base, len_or_tag: len as u16, ctxt_or_max: ctxt2 as u16 } + Span { base_or_index: base, len_or_tag: len as u16, ctxt_or_tag: ctxt2 as u16 } } else { // Interned format. let index = with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt, parent })); - let ctxt_or_max = if ctxt2 < MAX_CTXT { ctxt2 } else { MAX_CTXT } as u16; - Span { base_or_index: index, len_or_tag: LEN_TAG, ctxt_or_max } + let ctxt_or_tag = if ctxt2 <= MAX_CTXT { ctxt2 } else { CTXT_TAG } as u16; + Span { base_or_index: index, len_or_tag: LEN_TAG, ctxt_or_tag } } } @@ -120,7 +126,7 @@ impl Span { SpanData { lo: BytePos(self.base_or_index), hi: BytePos(self.base_or_index + self.len_or_tag as u32), - ctxt: SyntaxContext::from_u32(self.ctxt_or_max as u32), + ctxt: SyntaxContext::from_u32(self.ctxt_or_tag as u32), parent: None, } } else { @@ -133,10 +139,10 @@ impl Span { /// This function is used as a fast path when decoding the full `SpanData` is not necessary. #[inline] pub fn ctxt(self) -> SyntaxContext { - let ctxt_or_max = self.ctxt_or_max as u32; - if ctxt_or_max < MAX_CTXT { + let ctxt_or_tag = self.ctxt_or_tag as u32; + if ctxt_or_tag <= MAX_CTXT { // Inline format or interned format with inline ctxt. - SyntaxContext::from_u32(ctxt_or_max) + SyntaxContext::from_u32(ctxt_or_tag) } else { // Interned format. let index = self.base_or_index; From 38002b624aaacbb05f2640d60975e1470dfe5c1a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Aug 2022 21:50:23 -0400 Subject: [PATCH 3750/5092] organize shim tests into shims folder --- tests/fail/{ => shims}/backtrace/bad-backtrace-decl.rs | 0 tests/fail/{ => shims}/backtrace/bad-backtrace-decl.stderr | 0 tests/fail/{ => shims}/backtrace/bad-backtrace-flags.rs | 0 tests/fail/{ => shims}/backtrace/bad-backtrace-flags.stderr | 0 tests/fail/{ => shims}/backtrace/bad-backtrace-ptr.rs | 0 tests/fail/{ => shims}/backtrace/bad-backtrace-ptr.stderr | 0 tests/fail/{ => shims}/backtrace/bad-backtrace-resolve-flags.rs | 0 .../fail/{ => shims}/backtrace/bad-backtrace-resolve-flags.stderr | 0 .../{ => shims}/backtrace/bad-backtrace-resolve-names-flags.rs | 0 .../backtrace/bad-backtrace-resolve-names-flags.stderr | 0 tests/fail/{ => shims}/backtrace/bad-backtrace-size-flags.rs | 0 tests/fail/{ => shims}/backtrace/bad-backtrace-size-flags.stderr | 0 tests/fail/{ => shims}/fs/close_stdout.rs | 0 tests/fail/{ => shims}/fs/close_stdout.stderr | 0 tests/fail/{ => shims}/fs/isolated_file.rs | 0 tests/fail/{ => shims}/fs/isolated_file.stderr | 0 tests/fail/{ => shims}/fs/isolated_stdin.rs | 0 tests/fail/{ => shims}/fs/isolated_stdin.stderr | 0 tests/fail/{ => shims}/fs/mkstemp_immutable_arg.rs | 0 tests/fail/{ => shims}/fs/mkstemp_immutable_arg.stderr | 0 tests/fail/{ => shims}/fs/read_from_stdout.rs | 0 tests/fail/{ => shims}/fs/read_from_stdout.stderr | 0 tests/fail/{ => shims}/fs/unix_open_missing_required_mode.rs | 0 tests/fail/{ => shims}/fs/unix_open_missing_required_mode.stderr | 0 tests/fail/{ => shims}/fs/write_to_stdin.rs | 0 tests/fail/{ => shims}/fs/write_to_stdin.stderr | 0 tests/fail/{ => shims}/shim_arg_size.32bit.stderr | 0 tests/fail/{ => shims}/shim_arg_size.64bit.stderr | 0 tests/fail/{ => shims}/shim_arg_size.rs | 0 tests/fail/{ => shims}/sync/libc_pthread_cond_double_destroy.rs | 0 .../fail/{ => shims}/sync/libc_pthread_cond_double_destroy.stderr | 0 .../fail/{ => shims}/sync/libc_pthread_condattr_double_destroy.rs | 0 .../{ => shims}/sync/libc_pthread_condattr_double_destroy.stderr | 0 tests/fail/{ => shims}/sync/libc_pthread_mutex_NULL_deadlock.rs | 0 .../fail/{ => shims}/sync/libc_pthread_mutex_NULL_deadlock.stderr | 0 tests/fail/{ => shims}/sync/libc_pthread_mutex_deadlock.rs | 0 tests/fail/{ => shims}/sync/libc_pthread_mutex_deadlock.stderr | 0 .../fail/{ => shims}/sync/libc_pthread_mutex_default_deadlock.rs | 0 .../{ => shims}/sync/libc_pthread_mutex_default_deadlock.stderr | 0 tests/fail/{ => shims}/sync/libc_pthread_mutex_destroy_locked.rs | 0 .../{ => shims}/sync/libc_pthread_mutex_destroy_locked.stderr | 0 tests/fail/{ => shims}/sync/libc_pthread_mutex_double_destroy.rs | 0 .../{ => shims}/sync/libc_pthread_mutex_double_destroy.stderr | 0 tests/fail/{ => shims}/sync/libc_pthread_mutex_normal_deadlock.rs | 0 .../{ => shims}/sync/libc_pthread_mutex_normal_deadlock.stderr | 0 .../{ => shims}/sync/libc_pthread_mutex_normal_unlock_unlocked.rs | 0 .../sync/libc_pthread_mutex_normal_unlock_unlocked.stderr | 0 tests/fail/{ => shims}/sync/libc_pthread_mutex_wrong_owner.rs | 0 tests/fail/{ => shims}/sync/libc_pthread_mutex_wrong_owner.stderr | 0 .../{ => shims}/sync/libc_pthread_mutexattr_double_destroy.rs | 0 .../{ => shims}/sync/libc_pthread_mutexattr_double_destroy.stderr | 0 .../{ => shims}/sync/libc_pthread_rwlock_destroy_read_locked.rs | 0 .../sync/libc_pthread_rwlock_destroy_read_locked.stderr | 0 .../{ => shims}/sync/libc_pthread_rwlock_destroy_write_locked.rs | 0 .../sync/libc_pthread_rwlock_destroy_write_locked.stderr | 0 tests/fail/{ => shims}/sync/libc_pthread_rwlock_double_destroy.rs | 0 .../{ => shims}/sync/libc_pthread_rwlock_double_destroy.stderr | 0 .../sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs | 0 .../libc_pthread_rwlock_read_write_deadlock_single_thread.stderr | 0 .../fail/{ => shims}/sync/libc_pthread_rwlock_read_wrong_owner.rs | 0 .../{ => shims}/sync/libc_pthread_rwlock_read_wrong_owner.stderr | 0 .../fail/{ => shims}/sync/libc_pthread_rwlock_unlock_unlocked.rs | 0 .../{ => shims}/sync/libc_pthread_rwlock_unlock_unlocked.stderr | 0 .../{ => shims}/sync/libc_pthread_rwlock_write_read_deadlock.rs | 0 .../sync/libc_pthread_rwlock_write_read_deadlock.stderr | 0 .../sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs | 0 .../libc_pthread_rwlock_write_read_deadlock_single_thread.stderr | 0 .../{ => shims}/sync/libc_pthread_rwlock_write_write_deadlock.rs | 0 .../sync/libc_pthread_rwlock_write_write_deadlock.stderr | 0 .../libc_pthread_rwlock_write_write_deadlock_single_thread.rs | 0 .../libc_pthread_rwlock_write_write_deadlock_single_thread.stderr | 0 .../{ => shims}/sync/libc_pthread_rwlock_write_wrong_owner.rs | 0 .../{ => shims}/sync/libc_pthread_rwlock_write_wrong_owner.stderr | 0 tests/pass/{ => shims}/env/args.rs | 0 tests/pass/{ => shims}/env/args.stdout | 0 tests/pass/{ => shims}/env/current_dir.rs | 0 tests/pass/{ => shims}/env/current_dir_with_isolation.rs | 0 tests/pass/{ => shims}/env/current_dir_with_isolation.stderr | 0 tests/pass/{ => shims}/env/current_exe.rs | 0 tests/pass/{ => shims}/env/home.rs | 0 tests/pass/{ => shims}/env/var-exclude.rs | 0 tests/pass/{ => shims}/env/var-forward.rs | 0 tests/pass/{ => shims}/env/var-without-isolation.rs | 0 tests/pass/{ => shims}/env/var.rs | 0 tests/pass/{ => shims}/env/var.stdout | 0 tests/pass/{ => shims}/exit.rs | 0 tests/pass/{ => shims}/fs.rs | 0 tests/pass/{ => shims}/fs.stderr | 0 tests/pass/{ => shims}/fs.stdout | 0 tests/pass/{ => shims}/fs_with_isolation.rs | 0 tests/pass/{ => shims}/fs_with_isolation.stderr | 0 tests/pass/{ => shims}/libc.rs | 0 tests/pass/{ => shims}/linux-getrandom-without-isolation.rs | 0 tests/pass/{ => shims}/linux-getrandom.rs | 0 tests/pass/{ => shims}/posix_memalign.rs | 0 tests/pass/{ => shims}/sleep_long.rs | 0 tests/pass/{ => shims}/time.rs | 0 97 files changed, 0 insertions(+), 0 deletions(-) rename tests/fail/{ => shims}/backtrace/bad-backtrace-decl.rs (100%) rename tests/fail/{ => shims}/backtrace/bad-backtrace-decl.stderr (100%) rename tests/fail/{ => shims}/backtrace/bad-backtrace-flags.rs (100%) rename tests/fail/{ => shims}/backtrace/bad-backtrace-flags.stderr (100%) rename tests/fail/{ => shims}/backtrace/bad-backtrace-ptr.rs (100%) rename tests/fail/{ => shims}/backtrace/bad-backtrace-ptr.stderr (100%) rename tests/fail/{ => shims}/backtrace/bad-backtrace-resolve-flags.rs (100%) rename tests/fail/{ => shims}/backtrace/bad-backtrace-resolve-flags.stderr (100%) rename tests/fail/{ => shims}/backtrace/bad-backtrace-resolve-names-flags.rs (100%) rename tests/fail/{ => shims}/backtrace/bad-backtrace-resolve-names-flags.stderr (100%) rename tests/fail/{ => shims}/backtrace/bad-backtrace-size-flags.rs (100%) rename tests/fail/{ => shims}/backtrace/bad-backtrace-size-flags.stderr (100%) rename tests/fail/{ => shims}/fs/close_stdout.rs (100%) rename tests/fail/{ => shims}/fs/close_stdout.stderr (100%) rename tests/fail/{ => shims}/fs/isolated_file.rs (100%) rename tests/fail/{ => shims}/fs/isolated_file.stderr (100%) rename tests/fail/{ => shims}/fs/isolated_stdin.rs (100%) rename tests/fail/{ => shims}/fs/isolated_stdin.stderr (100%) rename tests/fail/{ => shims}/fs/mkstemp_immutable_arg.rs (100%) rename tests/fail/{ => shims}/fs/mkstemp_immutable_arg.stderr (100%) rename tests/fail/{ => shims}/fs/read_from_stdout.rs (100%) rename tests/fail/{ => shims}/fs/read_from_stdout.stderr (100%) rename tests/fail/{ => shims}/fs/unix_open_missing_required_mode.rs (100%) rename tests/fail/{ => shims}/fs/unix_open_missing_required_mode.stderr (100%) rename tests/fail/{ => shims}/fs/write_to_stdin.rs (100%) rename tests/fail/{ => shims}/fs/write_to_stdin.stderr (100%) rename tests/fail/{ => shims}/shim_arg_size.32bit.stderr (100%) rename tests/fail/{ => shims}/shim_arg_size.64bit.stderr (100%) rename tests/fail/{ => shims}/shim_arg_size.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_cond_double_destroy.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_cond_double_destroy.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_condattr_double_destroy.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_condattr_double_destroy.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_NULL_deadlock.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_NULL_deadlock.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_deadlock.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_deadlock.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_default_deadlock.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_default_deadlock.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_destroy_locked.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_destroy_locked.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_double_destroy.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_double_destroy.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_normal_deadlock.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_normal_deadlock.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_normal_unlock_unlocked.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_wrong_owner.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_wrong_owner.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutexattr_double_destroy.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutexattr_double_destroy.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_destroy_read_locked.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_destroy_read_locked.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_destroy_write_locked.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_destroy_write_locked.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_double_destroy.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_double_destroy.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_read_wrong_owner.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_read_wrong_owner.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_unlock_unlocked.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_unlock_unlocked.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_write_read_deadlock.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_write_read_deadlock.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_write_write_deadlock.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_write_write_deadlock.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_write_wrong_owner.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_write_wrong_owner.stderr (100%) rename tests/pass/{ => shims}/env/args.rs (100%) rename tests/pass/{ => shims}/env/args.stdout (100%) rename tests/pass/{ => shims}/env/current_dir.rs (100%) rename tests/pass/{ => shims}/env/current_dir_with_isolation.rs (100%) rename tests/pass/{ => shims}/env/current_dir_with_isolation.stderr (100%) rename tests/pass/{ => shims}/env/current_exe.rs (100%) rename tests/pass/{ => shims}/env/home.rs (100%) rename tests/pass/{ => shims}/env/var-exclude.rs (100%) rename tests/pass/{ => shims}/env/var-forward.rs (100%) rename tests/pass/{ => shims}/env/var-without-isolation.rs (100%) rename tests/pass/{ => shims}/env/var.rs (100%) rename tests/pass/{ => shims}/env/var.stdout (100%) rename tests/pass/{ => shims}/exit.rs (100%) rename tests/pass/{ => shims}/fs.rs (100%) rename tests/pass/{ => shims}/fs.stderr (100%) rename tests/pass/{ => shims}/fs.stdout (100%) rename tests/pass/{ => shims}/fs_with_isolation.rs (100%) rename tests/pass/{ => shims}/fs_with_isolation.stderr (100%) rename tests/pass/{ => shims}/libc.rs (100%) rename tests/pass/{ => shims}/linux-getrandom-without-isolation.rs (100%) rename tests/pass/{ => shims}/linux-getrandom.rs (100%) rename tests/pass/{ => shims}/posix_memalign.rs (100%) rename tests/pass/{ => shims}/sleep_long.rs (100%) rename tests/pass/{ => shims}/time.rs (100%) diff --git a/tests/fail/backtrace/bad-backtrace-decl.rs b/tests/fail/shims/backtrace/bad-backtrace-decl.rs similarity index 100% rename from tests/fail/backtrace/bad-backtrace-decl.rs rename to tests/fail/shims/backtrace/bad-backtrace-decl.rs diff --git a/tests/fail/backtrace/bad-backtrace-decl.stderr b/tests/fail/shims/backtrace/bad-backtrace-decl.stderr similarity index 100% rename from tests/fail/backtrace/bad-backtrace-decl.stderr rename to tests/fail/shims/backtrace/bad-backtrace-decl.stderr diff --git a/tests/fail/backtrace/bad-backtrace-flags.rs b/tests/fail/shims/backtrace/bad-backtrace-flags.rs similarity index 100% rename from tests/fail/backtrace/bad-backtrace-flags.rs rename to tests/fail/shims/backtrace/bad-backtrace-flags.rs diff --git a/tests/fail/backtrace/bad-backtrace-flags.stderr b/tests/fail/shims/backtrace/bad-backtrace-flags.stderr similarity index 100% rename from tests/fail/backtrace/bad-backtrace-flags.stderr rename to tests/fail/shims/backtrace/bad-backtrace-flags.stderr diff --git a/tests/fail/backtrace/bad-backtrace-ptr.rs b/tests/fail/shims/backtrace/bad-backtrace-ptr.rs similarity index 100% rename from tests/fail/backtrace/bad-backtrace-ptr.rs rename to tests/fail/shims/backtrace/bad-backtrace-ptr.rs diff --git a/tests/fail/backtrace/bad-backtrace-ptr.stderr b/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr similarity index 100% rename from tests/fail/backtrace/bad-backtrace-ptr.stderr rename to tests/fail/shims/backtrace/bad-backtrace-ptr.stderr diff --git a/tests/fail/backtrace/bad-backtrace-resolve-flags.rs b/tests/fail/shims/backtrace/bad-backtrace-resolve-flags.rs similarity index 100% rename from tests/fail/backtrace/bad-backtrace-resolve-flags.rs rename to tests/fail/shims/backtrace/bad-backtrace-resolve-flags.rs diff --git a/tests/fail/backtrace/bad-backtrace-resolve-flags.stderr b/tests/fail/shims/backtrace/bad-backtrace-resolve-flags.stderr similarity index 100% rename from tests/fail/backtrace/bad-backtrace-resolve-flags.stderr rename to tests/fail/shims/backtrace/bad-backtrace-resolve-flags.stderr diff --git a/tests/fail/backtrace/bad-backtrace-resolve-names-flags.rs b/tests/fail/shims/backtrace/bad-backtrace-resolve-names-flags.rs similarity index 100% rename from tests/fail/backtrace/bad-backtrace-resolve-names-flags.rs rename to tests/fail/shims/backtrace/bad-backtrace-resolve-names-flags.rs diff --git a/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr b/tests/fail/shims/backtrace/bad-backtrace-resolve-names-flags.stderr similarity index 100% rename from tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr rename to tests/fail/shims/backtrace/bad-backtrace-resolve-names-flags.stderr diff --git a/tests/fail/backtrace/bad-backtrace-size-flags.rs b/tests/fail/shims/backtrace/bad-backtrace-size-flags.rs similarity index 100% rename from tests/fail/backtrace/bad-backtrace-size-flags.rs rename to tests/fail/shims/backtrace/bad-backtrace-size-flags.rs diff --git a/tests/fail/backtrace/bad-backtrace-size-flags.stderr b/tests/fail/shims/backtrace/bad-backtrace-size-flags.stderr similarity index 100% rename from tests/fail/backtrace/bad-backtrace-size-flags.stderr rename to tests/fail/shims/backtrace/bad-backtrace-size-flags.stderr diff --git a/tests/fail/fs/close_stdout.rs b/tests/fail/shims/fs/close_stdout.rs similarity index 100% rename from tests/fail/fs/close_stdout.rs rename to tests/fail/shims/fs/close_stdout.rs diff --git a/tests/fail/fs/close_stdout.stderr b/tests/fail/shims/fs/close_stdout.stderr similarity index 100% rename from tests/fail/fs/close_stdout.stderr rename to tests/fail/shims/fs/close_stdout.stderr diff --git a/tests/fail/fs/isolated_file.rs b/tests/fail/shims/fs/isolated_file.rs similarity index 100% rename from tests/fail/fs/isolated_file.rs rename to tests/fail/shims/fs/isolated_file.rs diff --git a/tests/fail/fs/isolated_file.stderr b/tests/fail/shims/fs/isolated_file.stderr similarity index 100% rename from tests/fail/fs/isolated_file.stderr rename to tests/fail/shims/fs/isolated_file.stderr diff --git a/tests/fail/fs/isolated_stdin.rs b/tests/fail/shims/fs/isolated_stdin.rs similarity index 100% rename from tests/fail/fs/isolated_stdin.rs rename to tests/fail/shims/fs/isolated_stdin.rs diff --git a/tests/fail/fs/isolated_stdin.stderr b/tests/fail/shims/fs/isolated_stdin.stderr similarity index 100% rename from tests/fail/fs/isolated_stdin.stderr rename to tests/fail/shims/fs/isolated_stdin.stderr diff --git a/tests/fail/fs/mkstemp_immutable_arg.rs b/tests/fail/shims/fs/mkstemp_immutable_arg.rs similarity index 100% rename from tests/fail/fs/mkstemp_immutable_arg.rs rename to tests/fail/shims/fs/mkstemp_immutable_arg.rs diff --git a/tests/fail/fs/mkstemp_immutable_arg.stderr b/tests/fail/shims/fs/mkstemp_immutable_arg.stderr similarity index 100% rename from tests/fail/fs/mkstemp_immutable_arg.stderr rename to tests/fail/shims/fs/mkstemp_immutable_arg.stderr diff --git a/tests/fail/fs/read_from_stdout.rs b/tests/fail/shims/fs/read_from_stdout.rs similarity index 100% rename from tests/fail/fs/read_from_stdout.rs rename to tests/fail/shims/fs/read_from_stdout.rs diff --git a/tests/fail/fs/read_from_stdout.stderr b/tests/fail/shims/fs/read_from_stdout.stderr similarity index 100% rename from tests/fail/fs/read_from_stdout.stderr rename to tests/fail/shims/fs/read_from_stdout.stderr diff --git a/tests/fail/fs/unix_open_missing_required_mode.rs b/tests/fail/shims/fs/unix_open_missing_required_mode.rs similarity index 100% rename from tests/fail/fs/unix_open_missing_required_mode.rs rename to tests/fail/shims/fs/unix_open_missing_required_mode.rs diff --git a/tests/fail/fs/unix_open_missing_required_mode.stderr b/tests/fail/shims/fs/unix_open_missing_required_mode.stderr similarity index 100% rename from tests/fail/fs/unix_open_missing_required_mode.stderr rename to tests/fail/shims/fs/unix_open_missing_required_mode.stderr diff --git a/tests/fail/fs/write_to_stdin.rs b/tests/fail/shims/fs/write_to_stdin.rs similarity index 100% rename from tests/fail/fs/write_to_stdin.rs rename to tests/fail/shims/fs/write_to_stdin.rs diff --git a/tests/fail/fs/write_to_stdin.stderr b/tests/fail/shims/fs/write_to_stdin.stderr similarity index 100% rename from tests/fail/fs/write_to_stdin.stderr rename to tests/fail/shims/fs/write_to_stdin.stderr diff --git a/tests/fail/shim_arg_size.32bit.stderr b/tests/fail/shims/shim_arg_size.32bit.stderr similarity index 100% rename from tests/fail/shim_arg_size.32bit.stderr rename to tests/fail/shims/shim_arg_size.32bit.stderr diff --git a/tests/fail/shim_arg_size.64bit.stderr b/tests/fail/shims/shim_arg_size.64bit.stderr similarity index 100% rename from tests/fail/shim_arg_size.64bit.stderr rename to tests/fail/shims/shim_arg_size.64bit.stderr diff --git a/tests/fail/shim_arg_size.rs b/tests/fail/shims/shim_arg_size.rs similarity index 100% rename from tests/fail/shim_arg_size.rs rename to tests/fail/shims/shim_arg_size.rs diff --git a/tests/fail/sync/libc_pthread_cond_double_destroy.rs b/tests/fail/shims/sync/libc_pthread_cond_double_destroy.rs similarity index 100% rename from tests/fail/sync/libc_pthread_cond_double_destroy.rs rename to tests/fail/shims/sync/libc_pthread_cond_double_destroy.rs diff --git a/tests/fail/sync/libc_pthread_cond_double_destroy.stderr b/tests/fail/shims/sync/libc_pthread_cond_double_destroy.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_cond_double_destroy.stderr rename to tests/fail/shims/sync/libc_pthread_cond_double_destroy.stderr diff --git a/tests/fail/sync/libc_pthread_condattr_double_destroy.rs b/tests/fail/shims/sync/libc_pthread_condattr_double_destroy.rs similarity index 100% rename from tests/fail/sync/libc_pthread_condattr_double_destroy.rs rename to tests/fail/shims/sync/libc_pthread_condattr_double_destroy.rs diff --git a/tests/fail/sync/libc_pthread_condattr_double_destroy.stderr b/tests/fail/shims/sync/libc_pthread_condattr_double_destroy.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_condattr_double_destroy.stderr rename to tests/fail/shims/sync/libc_pthread_condattr_double_destroy.stderr diff --git a/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs b/tests/fail/shims/sync/libc_pthread_mutex_NULL_deadlock.rs similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs rename to tests/fail/shims/sync/libc_pthread_mutex_NULL_deadlock.rs diff --git a/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.stderr b/tests/fail/shims/sync/libc_pthread_mutex_NULL_deadlock.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_NULL_deadlock.stderr rename to tests/fail/shims/sync/libc_pthread_mutex_NULL_deadlock.stderr diff --git a/tests/fail/sync/libc_pthread_mutex_deadlock.rs b/tests/fail/shims/sync/libc_pthread_mutex_deadlock.rs similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_deadlock.rs rename to tests/fail/shims/sync/libc_pthread_mutex_deadlock.rs diff --git a/tests/fail/sync/libc_pthread_mutex_deadlock.stderr b/tests/fail/shims/sync/libc_pthread_mutex_deadlock.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_deadlock.stderr rename to tests/fail/shims/sync/libc_pthread_mutex_deadlock.stderr diff --git a/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs b/tests/fail/shims/sync/libc_pthread_mutex_default_deadlock.rs similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_default_deadlock.rs rename to tests/fail/shims/sync/libc_pthread_mutex_default_deadlock.rs diff --git a/tests/fail/sync/libc_pthread_mutex_default_deadlock.stderr b/tests/fail/shims/sync/libc_pthread_mutex_default_deadlock.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_default_deadlock.stderr rename to tests/fail/shims/sync/libc_pthread_mutex_default_deadlock.stderr diff --git a/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs b/tests/fail/shims/sync/libc_pthread_mutex_destroy_locked.rs similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_destroy_locked.rs rename to tests/fail/shims/sync/libc_pthread_mutex_destroy_locked.rs diff --git a/tests/fail/sync/libc_pthread_mutex_destroy_locked.stderr b/tests/fail/shims/sync/libc_pthread_mutex_destroy_locked.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_destroy_locked.stderr rename to tests/fail/shims/sync/libc_pthread_mutex_destroy_locked.stderr diff --git a/tests/fail/sync/libc_pthread_mutex_double_destroy.rs b/tests/fail/shims/sync/libc_pthread_mutex_double_destroy.rs similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_double_destroy.rs rename to tests/fail/shims/sync/libc_pthread_mutex_double_destroy.rs diff --git a/tests/fail/sync/libc_pthread_mutex_double_destroy.stderr b/tests/fail/shims/sync/libc_pthread_mutex_double_destroy.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_double_destroy.stderr rename to tests/fail/shims/sync/libc_pthread_mutex_double_destroy.stderr diff --git a/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs b/tests/fail/shims/sync/libc_pthread_mutex_normal_deadlock.rs similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs rename to tests/fail/shims/sync/libc_pthread_mutex_normal_deadlock.rs diff --git a/tests/fail/sync/libc_pthread_mutex_normal_deadlock.stderr b/tests/fail/shims/sync/libc_pthread_mutex_normal_deadlock.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_normal_deadlock.stderr rename to tests/fail/shims/sync/libc_pthread_mutex_normal_deadlock.stderr diff --git a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs b/tests/fail/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.rs similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs rename to tests/fail/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.rs diff --git a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr b/tests/fail/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr rename to tests/fail/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr diff --git a/tests/fail/sync/libc_pthread_mutex_wrong_owner.rs b/tests/fail/shims/sync/libc_pthread_mutex_wrong_owner.rs similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_wrong_owner.rs rename to tests/fail/shims/sync/libc_pthread_mutex_wrong_owner.rs diff --git a/tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr b/tests/fail/shims/sync/libc_pthread_mutex_wrong_owner.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr rename to tests/fail/shims/sync/libc_pthread_mutex_wrong_owner.stderr diff --git a/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs b/tests/fail/shims/sync/libc_pthread_mutexattr_double_destroy.rs similarity index 100% rename from tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs rename to tests/fail/shims/sync/libc_pthread_mutexattr_double_destroy.rs diff --git a/tests/fail/sync/libc_pthread_mutexattr_double_destroy.stderr b/tests/fail/shims/sync/libc_pthread_mutexattr_double_destroy.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_mutexattr_double_destroy.stderr rename to tests/fail/shims/sync/libc_pthread_mutexattr_double_destroy.stderr diff --git a/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs b/tests/fail/shims/sync/libc_pthread_rwlock_destroy_read_locked.rs similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs rename to tests/fail/shims/sync/libc_pthread_rwlock_destroy_read_locked.rs diff --git a/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_destroy_read_locked.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.stderr rename to tests/fail/shims/sync/libc_pthread_rwlock_destroy_read_locked.stderr diff --git a/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs b/tests/fail/shims/sync/libc_pthread_rwlock_destroy_write_locked.rs similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs rename to tests/fail/shims/sync/libc_pthread_rwlock_destroy_write_locked.rs diff --git a/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_destroy_write_locked.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.stderr rename to tests/fail/shims/sync/libc_pthread_rwlock_destroy_write_locked.stderr diff --git a/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs b/tests/fail/shims/sync/libc_pthread_rwlock_double_destroy.rs similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_double_destroy.rs rename to tests/fail/shims/sync/libc_pthread_rwlock_double_destroy.rs diff --git a/tests/fail/sync/libc_pthread_rwlock_double_destroy.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_double_destroy.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_double_destroy.stderr rename to tests/fail/shims/sync/libc_pthread_rwlock_double_destroy.stderr diff --git a/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs b/tests/fail/shims/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs rename to tests/fail/shims/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs diff --git a/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr rename to tests/fail/shims/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr diff --git a/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs b/tests/fail/shims/sync/libc_pthread_rwlock_read_wrong_owner.rs similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs rename to tests/fail/shims/sync/libc_pthread_rwlock_read_wrong_owner.rs diff --git a/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_read_wrong_owner.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr rename to tests/fail/shims/sync/libc_pthread_rwlock_read_wrong_owner.stderr diff --git a/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs b/tests/fail/shims/sync/libc_pthread_rwlock_unlock_unlocked.rs similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs rename to tests/fail/shims/sync/libc_pthread_rwlock_unlock_unlocked.rs diff --git a/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_unlock_unlocked.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.stderr rename to tests/fail/shims/sync/libc_pthread_rwlock_unlock_unlocked.stderr diff --git a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs b/tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock.rs similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs rename to tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock.rs diff --git a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr rename to tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock.stderr diff --git a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs b/tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs rename to tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs diff --git a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr rename to tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr diff --git a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs b/tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock.rs similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs rename to tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock.rs diff --git a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr rename to tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock.stderr diff --git a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs b/tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs rename to tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs diff --git a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr rename to tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr diff --git a/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs b/tests/fail/shims/sync/libc_pthread_rwlock_write_wrong_owner.rs similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs rename to tests/fail/shims/sync/libc_pthread_rwlock_write_wrong_owner.rs diff --git a/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_write_wrong_owner.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr rename to tests/fail/shims/sync/libc_pthread_rwlock_write_wrong_owner.stderr diff --git a/tests/pass/env/args.rs b/tests/pass/shims/env/args.rs similarity index 100% rename from tests/pass/env/args.rs rename to tests/pass/shims/env/args.rs diff --git a/tests/pass/env/args.stdout b/tests/pass/shims/env/args.stdout similarity index 100% rename from tests/pass/env/args.stdout rename to tests/pass/shims/env/args.stdout diff --git a/tests/pass/env/current_dir.rs b/tests/pass/shims/env/current_dir.rs similarity index 100% rename from tests/pass/env/current_dir.rs rename to tests/pass/shims/env/current_dir.rs diff --git a/tests/pass/env/current_dir_with_isolation.rs b/tests/pass/shims/env/current_dir_with_isolation.rs similarity index 100% rename from tests/pass/env/current_dir_with_isolation.rs rename to tests/pass/shims/env/current_dir_with_isolation.rs diff --git a/tests/pass/env/current_dir_with_isolation.stderr b/tests/pass/shims/env/current_dir_with_isolation.stderr similarity index 100% rename from tests/pass/env/current_dir_with_isolation.stderr rename to tests/pass/shims/env/current_dir_with_isolation.stderr diff --git a/tests/pass/env/current_exe.rs b/tests/pass/shims/env/current_exe.rs similarity index 100% rename from tests/pass/env/current_exe.rs rename to tests/pass/shims/env/current_exe.rs diff --git a/tests/pass/env/home.rs b/tests/pass/shims/env/home.rs similarity index 100% rename from tests/pass/env/home.rs rename to tests/pass/shims/env/home.rs diff --git a/tests/pass/env/var-exclude.rs b/tests/pass/shims/env/var-exclude.rs similarity index 100% rename from tests/pass/env/var-exclude.rs rename to tests/pass/shims/env/var-exclude.rs diff --git a/tests/pass/env/var-forward.rs b/tests/pass/shims/env/var-forward.rs similarity index 100% rename from tests/pass/env/var-forward.rs rename to tests/pass/shims/env/var-forward.rs diff --git a/tests/pass/env/var-without-isolation.rs b/tests/pass/shims/env/var-without-isolation.rs similarity index 100% rename from tests/pass/env/var-without-isolation.rs rename to tests/pass/shims/env/var-without-isolation.rs diff --git a/tests/pass/env/var.rs b/tests/pass/shims/env/var.rs similarity index 100% rename from tests/pass/env/var.rs rename to tests/pass/shims/env/var.rs diff --git a/tests/pass/env/var.stdout b/tests/pass/shims/env/var.stdout similarity index 100% rename from tests/pass/env/var.stdout rename to tests/pass/shims/env/var.stdout diff --git a/tests/pass/exit.rs b/tests/pass/shims/exit.rs similarity index 100% rename from tests/pass/exit.rs rename to tests/pass/shims/exit.rs diff --git a/tests/pass/fs.rs b/tests/pass/shims/fs.rs similarity index 100% rename from tests/pass/fs.rs rename to tests/pass/shims/fs.rs diff --git a/tests/pass/fs.stderr b/tests/pass/shims/fs.stderr similarity index 100% rename from tests/pass/fs.stderr rename to tests/pass/shims/fs.stderr diff --git a/tests/pass/fs.stdout b/tests/pass/shims/fs.stdout similarity index 100% rename from tests/pass/fs.stdout rename to tests/pass/shims/fs.stdout diff --git a/tests/pass/fs_with_isolation.rs b/tests/pass/shims/fs_with_isolation.rs similarity index 100% rename from tests/pass/fs_with_isolation.rs rename to tests/pass/shims/fs_with_isolation.rs diff --git a/tests/pass/fs_with_isolation.stderr b/tests/pass/shims/fs_with_isolation.stderr similarity index 100% rename from tests/pass/fs_with_isolation.stderr rename to tests/pass/shims/fs_with_isolation.stderr diff --git a/tests/pass/libc.rs b/tests/pass/shims/libc.rs similarity index 100% rename from tests/pass/libc.rs rename to tests/pass/shims/libc.rs diff --git a/tests/pass/linux-getrandom-without-isolation.rs b/tests/pass/shims/linux-getrandom-without-isolation.rs similarity index 100% rename from tests/pass/linux-getrandom-without-isolation.rs rename to tests/pass/shims/linux-getrandom-without-isolation.rs diff --git a/tests/pass/linux-getrandom.rs b/tests/pass/shims/linux-getrandom.rs similarity index 100% rename from tests/pass/linux-getrandom.rs rename to tests/pass/shims/linux-getrandom.rs diff --git a/tests/pass/posix_memalign.rs b/tests/pass/shims/posix_memalign.rs similarity index 100% rename from tests/pass/posix_memalign.rs rename to tests/pass/shims/posix_memalign.rs diff --git a/tests/pass/sleep_long.rs b/tests/pass/shims/sleep_long.rs similarity index 100% rename from tests/pass/sleep_long.rs rename to tests/pass/shims/sleep_long.rs diff --git a/tests/pass/time.rs b/tests/pass/shims/time.rs similarity index 100% rename from tests/pass/time.rs rename to tests/pass/shims/time.rs From 7c856f88639685faff194ea7d12748ae0936436c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Aug 2022 21:54:28 -0400 Subject: [PATCH 3751/5092] move libc pthread tests into separate file --- tests/pass/shims/{libc.rs => libc-misc.rs} | 125 -------------------- tests/pass/shims/pthreads.rs | 127 +++++++++++++++++++++ 2 files changed, 127 insertions(+), 125 deletions(-) rename tests/pass/shims/{libc.rs => libc-misc.rs} (61%) create mode 100644 tests/pass/shims/pthreads.rs diff --git a/tests/pass/shims/libc.rs b/tests/pass/shims/libc-misc.rs similarity index 61% rename from tests/pass/shims/libc.rs rename to tests/pass/shims/libc-misc.rs index f3aaccd57411..a883a3d967a3 100644 --- a/tests/pass/shims/libc.rs +++ b/tests/pass/shims/libc-misc.rs @@ -1,7 +1,6 @@ //@ignore-target-windows: No libc on Windows //@compile-flags: -Zmiri-disable-isolation #![feature(io_error_more)] -#![feature(rustc_private)] use std::fs::{remove_file, File}; use std::os::unix::io::AsRawFd; @@ -161,122 +160,6 @@ fn test_sync_file_range() { assert_eq!(result_2, 0); } -fn test_mutex_libc_init_recursive() { - unsafe { - let mut attr: libc::pthread_mutexattr_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutexattr_init(&mut attr as *mut _), 0); - assert_eq!( - libc::pthread_mutexattr_settype(&mut attr as *mut _, libc::PTHREAD_MUTEX_RECURSIVE), - 0, - ); - let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mut attr as *mut _), 0); - assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), libc::EPERM); - assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutexattr_destroy(&mut attr as *mut _), 0); - } -} - -fn test_mutex_libc_init_normal() { - unsafe { - let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); - assert_eq!( - libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, 0x12345678), - libc::EINVAL, - ); - assert_eq!( - libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), - 0, - ); - let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); - assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), libc::EBUSY); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); - } -} - -fn test_mutex_libc_init_errorcheck() { - unsafe { - let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); - assert_eq!( - libc::pthread_mutexattr_settype( - &mut mutexattr as *mut _, - libc::PTHREAD_MUTEX_ERRORCHECK, - ), - 0, - ); - let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); - assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), libc::EBUSY); - assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), libc::EDEADLK); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), libc::EPERM); - assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); - } -} - -// Only linux provides PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, -// libc for macOS just has the default PTHREAD_MUTEX_INITIALIZER. -#[cfg(target_os = "linux")] -fn test_mutex_libc_static_initializer_recursive() { - let mutex = std::cell::UnsafeCell::new(libc::PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP); - unsafe { - assert_eq!(libc::pthread_mutex_lock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_trylock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_trylock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_lock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_unlock(mutex.get()), libc::EPERM); - assert_eq!(libc::pthread_mutex_destroy(mutex.get()), 0); - } -} - -// Testing the behavior of std::sync::RwLock does not fully exercise the pthread rwlock shims, we -// need to go a layer deeper and test the behavior of the libc functions, because -// std::sys::unix::rwlock::RWLock itself keeps track of write_locked and num_readers. -fn test_rwlock_libc_static_initializer() { - let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); - unsafe { - assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); - assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); - - assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), libc::EBUSY); - assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); - assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); - - assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), libc::EBUSY); - assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); - assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); - - assert_eq!(libc::pthread_rwlock_destroy(rw.get()), 0); - } -} - /// Tests whether each thread has its own `__errno_location`. fn test_thread_local_errno() { #[cfg(target_os = "linux")] @@ -413,14 +296,6 @@ fn main() { #[cfg(any(target_os = "linux"))] test_sync_file_range(); - test_mutex_libc_init_recursive(); - test_mutex_libc_init_normal(); - test_mutex_libc_init_errorcheck(); - test_rwlock_libc_static_initializer(); - - #[cfg(any(target_os = "linux"))] - test_mutex_libc_static_initializer_recursive(); - test_thread_local_errno(); #[cfg(any(target_os = "linux"))] diff --git a/tests/pass/shims/pthreads.rs b/tests/pass/shims/pthreads.rs new file mode 100644 index 000000000000..d062eda7e90c --- /dev/null +++ b/tests/pass/shims/pthreads.rs @@ -0,0 +1,127 @@ +//@ignore-target-windows: No libc on Windows + +fn main() { + test_mutex_libc_init_recursive(); + test_mutex_libc_init_normal(); + test_mutex_libc_init_errorcheck(); + test_rwlock_libc_static_initializer(); + + #[cfg(any(target_os = "linux"))] + test_mutex_libc_static_initializer_recursive(); +} + +fn test_mutex_libc_init_recursive() { + unsafe { + let mut attr: libc::pthread_mutexattr_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutexattr_init(&mut attr as *mut _), 0); + assert_eq!( + libc::pthread_mutexattr_settype(&mut attr as *mut _, libc::PTHREAD_MUTEX_RECURSIVE), + 0, + ); + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mut attr as *mut _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), libc::EPERM); + assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutexattr_destroy(&mut attr as *mut _), 0); + } +} + +fn test_mutex_libc_init_normal() { + unsafe { + let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); + assert_eq!( + libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, 0x12345678), + libc::EINVAL, + ); + assert_eq!( + libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), + 0, + ); + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), libc::EBUSY); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); + } +} + +fn test_mutex_libc_init_errorcheck() { + unsafe { + let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); + assert_eq!( + libc::pthread_mutexattr_settype( + &mut mutexattr as *mut _, + libc::PTHREAD_MUTEX_ERRORCHECK, + ), + 0, + ); + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), libc::EBUSY); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), libc::EDEADLK); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), libc::EPERM); + assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); + } +} + +// Only linux provides PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, +// libc for macOS just has the default PTHREAD_MUTEX_INITIALIZER. +#[cfg(target_os = "linux")] +fn test_mutex_libc_static_initializer_recursive() { + let mutex = std::cell::UnsafeCell::new(libc::PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP); + unsafe { + assert_eq!(libc::pthread_mutex_lock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_trylock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_trylock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_lock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), libc::EPERM); + assert_eq!(libc::pthread_mutex_destroy(mutex.get()), 0); + } +} + +// Testing the behavior of std::sync::RwLock does not fully exercise the pthread rwlock shims, we +// need to go a layer deeper and test the behavior of the libc functions, because +// std::sys::unix::rwlock::RWLock itself keeps track of write_locked and num_readers. +fn test_rwlock_libc_static_initializer() { + let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); + unsafe { + assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + + assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + + assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + + assert_eq!(libc::pthread_rwlock_destroy(rw.get()), 0); + } +} From 83953f58e76b8edc236acf56f2526f4fd0957e83 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Aug 2022 21:58:10 -0400 Subject: [PATCH 3752/5092] remove unneeded rustc_private feature --- tests/fail/concurrency/libc_pthread_create_main_terminate.rs | 2 -- tests/fail/concurrency/libc_pthread_join_detached.rs | 2 -- tests/fail/concurrency/libc_pthread_join_joined.rs | 2 -- tests/fail/concurrency/libc_pthread_join_main.rs | 2 -- tests/fail/concurrency/libc_pthread_join_multiple.rs | 2 -- tests/fail/concurrency/libc_pthread_join_self.rs | 2 -- tests/fail/concurrency/too_few_args.rs | 2 -- tests/fail/concurrency/too_many_args.rs | 2 -- tests/fail/concurrency/unwind_top_of_stack.rs | 2 +- tests/fail/shims/fs/close_stdout.rs | 2 -- tests/fail/shims/fs/isolated_stdin.rs | 2 -- tests/fail/shims/fs/mkstemp_immutable_arg.rs | 2 -- tests/fail/shims/fs/read_from_stdout.rs | 2 -- tests/fail/shims/fs/unix_open_missing_required_mode.rs | 2 -- tests/fail/shims/fs/write_to_stdin.rs | 2 -- tests/fail/shims/sync/libc_pthread_cond_double_destroy.rs | 1 - tests/fail/shims/sync/libc_pthread_condattr_double_destroy.rs | 1 - tests/fail/shims/sync/libc_pthread_mutex_NULL_deadlock.rs | 2 -- tests/fail/shims/sync/libc_pthread_mutex_deadlock.rs | 2 -- tests/fail/shims/sync/libc_pthread_mutex_default_deadlock.rs | 2 -- tests/fail/shims/sync/libc_pthread_mutex_destroy_locked.rs | 2 -- tests/fail/shims/sync/libc_pthread_mutex_double_destroy.rs | 1 - tests/fail/shims/sync/libc_pthread_mutex_normal_deadlock.rs | 2 -- .../shims/sync/libc_pthread_mutex_normal_unlock_unlocked.rs | 2 -- tests/fail/shims/sync/libc_pthread_mutex_wrong_owner.rs | 2 -- tests/fail/shims/sync/libc_pthread_mutexattr_double_destroy.rs | 1 - .../fail/shims/sync/libc_pthread_rwlock_destroy_read_locked.rs | 2 -- .../fail/shims/sync/libc_pthread_rwlock_destroy_write_locked.rs | 2 -- tests/fail/shims/sync/libc_pthread_rwlock_double_destroy.rs | 1 - .../libc_pthread_rwlock_read_write_deadlock_single_thread.rs | 2 -- tests/fail/shims/sync/libc_pthread_rwlock_read_wrong_owner.rs | 2 -- tests/fail/shims/sync/libc_pthread_rwlock_unlock_unlocked.rs | 2 -- .../fail/shims/sync/libc_pthread_rwlock_write_read_deadlock.rs | 2 -- .../libc_pthread_rwlock_write_read_deadlock_single_thread.rs | 2 -- .../fail/shims/sync/libc_pthread_rwlock_write_write_deadlock.rs | 2 -- .../libc_pthread_rwlock_write_write_deadlock_single_thread.rs | 2 -- tests/fail/shims/sync/libc_pthread_rwlock_write_wrong_owner.rs | 2 -- tests/fail/unsupported_signal.rs | 1 - tests/panic/unsupported_syscall.rs | 1 - tests/pass/calloc.rs | 2 -- tests/pass/concurrency/libc_pthread_cond.rs | 2 -- tests/pass/concurrency/linux-futex.rs | 2 -- tests/pass/concurrency/tls_pthread_drop_order.rs | 2 -- tests/pass/foreign-fn-linkname.rs | 1 - tests/pass/malloc.rs | 2 -- tests/pass/regions-mock-trans.rs | 2 -- tests/pass/shims/fs.rs | 1 - tests/pass/shims/fs_with_isolation.rs | 2 -- tests/pass/shims/linux-getrandom-without-isolation.rs | 1 - tests/pass/shims/linux-getrandom.rs | 1 - tests/pass/shims/posix_memalign.rs | 1 - 51 files changed, 1 insertion(+), 89 deletions(-) diff --git a/tests/fail/concurrency/libc_pthread_create_main_terminate.rs b/tests/fail/concurrency/libc_pthread_create_main_terminate.rs index 9da9fbf2029d..065ad2d725f8 100644 --- a/tests/fail/concurrency/libc_pthread_create_main_terminate.rs +++ b/tests/fail/concurrency/libc_pthread_create_main_terminate.rs @@ -3,8 +3,6 @@ // Check that we terminate the program when the main thread terminates. -#![feature(rustc_private)] - use std::{mem, ptr}; extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { diff --git a/tests/fail/concurrency/libc_pthread_join_detached.rs b/tests/fail/concurrency/libc_pthread_join_detached.rs index e81978fc9953..488b14bbcfa8 100644 --- a/tests/fail/concurrency/libc_pthread_join_detached.rs +++ b/tests/fail/concurrency/libc_pthread_join_detached.rs @@ -2,8 +2,6 @@ // Joining a detached thread is undefined behavior. -#![feature(rustc_private)] - use std::{mem, ptr}; extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { diff --git a/tests/fail/concurrency/libc_pthread_join_joined.rs b/tests/fail/concurrency/libc_pthread_join_joined.rs index 11e00429c6ce..ebd1710bbf22 100644 --- a/tests/fail/concurrency/libc_pthread_join_joined.rs +++ b/tests/fail/concurrency/libc_pthread_join_joined.rs @@ -2,8 +2,6 @@ // Joining an already joined thread is undefined behavior. -#![feature(rustc_private)] - use std::{mem, ptr}; extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { diff --git a/tests/fail/concurrency/libc_pthread_join_main.rs b/tests/fail/concurrency/libc_pthread_join_main.rs index f029f08772f2..df6b520431b6 100644 --- a/tests/fail/concurrency/libc_pthread_join_main.rs +++ b/tests/fail/concurrency/libc_pthread_join_main.rs @@ -2,8 +2,6 @@ // Joining the main thread is undefined behavior. -#![feature(rustc_private)] - use std::{ptr, thread}; fn main() { diff --git a/tests/fail/concurrency/libc_pthread_join_multiple.rs b/tests/fail/concurrency/libc_pthread_join_multiple.rs index 017036ab01e1..e5187093befd 100644 --- a/tests/fail/concurrency/libc_pthread_join_multiple.rs +++ b/tests/fail/concurrency/libc_pthread_join_multiple.rs @@ -2,8 +2,6 @@ // Joining the same thread from multiple threads is undefined behavior. -#![feature(rustc_private)] - use std::thread; use std::{mem, ptr}; diff --git a/tests/fail/concurrency/libc_pthread_join_self.rs b/tests/fail/concurrency/libc_pthread_join_self.rs index ae6148893173..0c25c690f372 100644 --- a/tests/fail/concurrency/libc_pthread_join_self.rs +++ b/tests/fail/concurrency/libc_pthread_join_self.rs @@ -4,8 +4,6 @@ // Joining itself is undefined behavior. -#![feature(rustc_private)] - use std::{ptr, thread}; fn main() { diff --git a/tests/fail/concurrency/too_few_args.rs b/tests/fail/concurrency/too_few_args.rs index 4760fbb6b051..43c7c74d410f 100644 --- a/tests/fail/concurrency/too_few_args.rs +++ b/tests/fail/concurrency/too_few_args.rs @@ -2,8 +2,6 @@ //! The thread function must have exactly one argument. -#![feature(rustc_private)] - use std::{mem, ptr}; extern "C" fn thread_start() -> *mut libc::c_void { diff --git a/tests/fail/concurrency/too_many_args.rs b/tests/fail/concurrency/too_many_args.rs index 6abe767dc8a7..d660037ca669 100644 --- a/tests/fail/concurrency/too_many_args.rs +++ b/tests/fail/concurrency/too_many_args.rs @@ -2,8 +2,6 @@ //! The thread function must have exactly one argument. -#![feature(rustc_private)] - use std::{mem, ptr}; extern "C" fn thread_start(_null: *mut libc::c_void, _x: i32) -> *mut libc::c_void { diff --git a/tests/fail/concurrency/unwind_top_of_stack.rs b/tests/fail/concurrency/unwind_top_of_stack.rs index bd49401e61f5..c2b9d56e19c9 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.rs +++ b/tests/fail/concurrency/unwind_top_of_stack.rs @@ -3,7 +3,7 @@ //! Unwinding past the top frame of a stack is Undefined Behavior. -#![feature(rustc_private, c_unwind)] +#![feature(c_unwind)] use std::{mem, ptr}; diff --git a/tests/fail/shims/fs/close_stdout.rs b/tests/fail/shims/fs/close_stdout.rs index e4eab5fd6964..09da8509af41 100644 --- a/tests/fail/shims/fs/close_stdout.rs +++ b/tests/fail/shims/fs/close_stdout.rs @@ -3,8 +3,6 @@ // FIXME: standard handles cannot be closed (https://github.com/rust-lang/rust/issues/40032) -#![feature(rustc_private)] - fn main() { unsafe { libc::close(1); //~ ERROR: cannot close stdout diff --git a/tests/fail/shims/fs/isolated_stdin.rs b/tests/fail/shims/fs/isolated_stdin.rs index 86b04a038354..a45f805696d4 100644 --- a/tests/fail/shims/fs/isolated_stdin.rs +++ b/tests/fail/shims/fs/isolated_stdin.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - fn main() -> std::io::Result<()> { let mut bytes = [0u8; 512]; unsafe { diff --git a/tests/fail/shims/fs/mkstemp_immutable_arg.rs b/tests/fail/shims/fs/mkstemp_immutable_arg.rs index 5be1fb394b90..ba9f404d7c9a 100644 --- a/tests/fail/shims/fs/mkstemp_immutable_arg.rs +++ b/tests/fail/shims/fs/mkstemp_immutable_arg.rs @@ -1,8 +1,6 @@ //@ignore-target-windows: No libc on Windows //@compile-flags: -Zmiri-disable-isolation -#![feature(rustc_private)] - fn main() { test_mkstemp_immutable_arg(); } diff --git a/tests/fail/shims/fs/read_from_stdout.rs b/tests/fail/shims/fs/read_from_stdout.rs index 0fd8ba2fc419..073fca4712e9 100644 --- a/tests/fail/shims/fs/read_from_stdout.rs +++ b/tests/fail/shims/fs/read_from_stdout.rs @@ -1,8 +1,6 @@ //@compile-flags: -Zmiri-disable-isolation //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - fn main() -> std::io::Result<()> { let mut bytes = [0u8; 512]; unsafe { diff --git a/tests/fail/shims/fs/unix_open_missing_required_mode.rs b/tests/fail/shims/fs/unix_open_missing_required_mode.rs index 4740dcebe920..ae231d4be667 100644 --- a/tests/fail/shims/fs/unix_open_missing_required_mode.rs +++ b/tests/fail/shims/fs/unix_open_missing_required_mode.rs @@ -1,8 +1,6 @@ //@ignore-target-windows: No libc on Windows //@compile-flags: -Zmiri-disable-isolation -#![feature(rustc_private)] - fn main() { test_file_open_missing_needed_mode(); } diff --git a/tests/fail/shims/fs/write_to_stdin.rs b/tests/fail/shims/fs/write_to_stdin.rs index 0e9109fc6e23..d039ad718d33 100644 --- a/tests/fail/shims/fs/write_to_stdin.rs +++ b/tests/fail/shims/fs/write_to_stdin.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - fn main() -> std::io::Result<()> { let bytes = b"hello"; unsafe { diff --git a/tests/fail/shims/sync/libc_pthread_cond_double_destroy.rs b/tests/fail/shims/sync/libc_pthread_cond_double_destroy.rs index 90d5997f8712..94ca3496ed94 100644 --- a/tests/fail/shims/sync/libc_pthread_cond_double_destroy.rs +++ b/tests/fail/shims/sync/libc_pthread_cond_double_destroy.rs @@ -1,5 +1,4 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] /// Test that destroying a pthread_cond twice fails, even without a check for number validity diff --git a/tests/fail/shims/sync/libc_pthread_condattr_double_destroy.rs b/tests/fail/shims/sync/libc_pthread_condattr_double_destroy.rs index 028a924196f2..13e639a867dc 100644 --- a/tests/fail/shims/sync/libc_pthread_condattr_double_destroy.rs +++ b/tests/fail/shims/sync/libc_pthread_condattr_double_destroy.rs @@ -1,5 +1,4 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] /// Test that destroying a pthread_condattr twice fails, even without a check for number validity diff --git a/tests/fail/shims/sync/libc_pthread_mutex_NULL_deadlock.rs b/tests/fail/shims/sync/libc_pthread_mutex_NULL_deadlock.rs index d87455877abc..8b2510733831 100644 --- a/tests/fail/shims/sync/libc_pthread_mutex_NULL_deadlock.rs +++ b/tests/fail/shims/sync/libc_pthread_mutex_NULL_deadlock.rs @@ -2,8 +2,6 @@ // // Check that if we pass NULL attribute, then we get the default mutex type. -#![feature(rustc_private)] - fn main() { unsafe { let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); diff --git a/tests/fail/shims/sync/libc_pthread_mutex_deadlock.rs b/tests/fail/shims/sync/libc_pthread_mutex_deadlock.rs index f77f5c2e2022..6c3cb738e299 100644 --- a/tests/fail/shims/sync/libc_pthread_mutex_deadlock.rs +++ b/tests/fail/shims/sync/libc_pthread_mutex_deadlock.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - use std::cell::UnsafeCell; use std::sync::Arc; use std::thread; diff --git a/tests/fail/shims/sync/libc_pthread_mutex_default_deadlock.rs b/tests/fail/shims/sync/libc_pthread_mutex_default_deadlock.rs index b28101e20b24..f443768819f9 100644 --- a/tests/fail/shims/sync/libc_pthread_mutex_default_deadlock.rs +++ b/tests/fail/shims/sync/libc_pthread_mutex_default_deadlock.rs @@ -2,8 +2,6 @@ // // Check that if we do not set the mutex type, it is the default. -#![feature(rustc_private)] - fn main() { unsafe { let mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); diff --git a/tests/fail/shims/sync/libc_pthread_mutex_destroy_locked.rs b/tests/fail/shims/sync/libc_pthread_mutex_destroy_locked.rs index 0f74446fa27e..ec3965c7574e 100644 --- a/tests/fail/shims/sync/libc_pthread_mutex_destroy_locked.rs +++ b/tests/fail/shims/sync/libc_pthread_mutex_destroy_locked.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - fn main() { unsafe { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); diff --git a/tests/fail/shims/sync/libc_pthread_mutex_double_destroy.rs b/tests/fail/shims/sync/libc_pthread_mutex_double_destroy.rs index 89022f3b5625..622c3eaeae30 100644 --- a/tests/fail/shims/sync/libc_pthread_mutex_double_destroy.rs +++ b/tests/fail/shims/sync/libc_pthread_mutex_double_destroy.rs @@ -1,5 +1,4 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] /// Test that destroying a pthread_mutex twice fails, even without a check for number validity diff --git a/tests/fail/shims/sync/libc_pthread_mutex_normal_deadlock.rs b/tests/fail/shims/sync/libc_pthread_mutex_normal_deadlock.rs index ab6d9c7739d7..5ea09fa5aac3 100644 --- a/tests/fail/shims/sync/libc_pthread_mutex_normal_deadlock.rs +++ b/tests/fail/shims/sync/libc_pthread_mutex_normal_deadlock.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - fn main() { unsafe { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); diff --git a/tests/fail/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.rs b/tests/fail/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.rs index f259a4dee7d8..8ce7542edb87 100644 --- a/tests/fail/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.rs +++ b/tests/fail/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - fn main() { unsafe { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); diff --git a/tests/fail/shims/sync/libc_pthread_mutex_wrong_owner.rs b/tests/fail/shims/sync/libc_pthread_mutex_wrong_owner.rs index b8e57f8f74e9..b56775252e4b 100644 --- a/tests/fail/shims/sync/libc_pthread_mutex_wrong_owner.rs +++ b/tests/fail/shims/sync/libc_pthread_mutex_wrong_owner.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - use std::cell::UnsafeCell; use std::sync::Arc; use std::thread; diff --git a/tests/fail/shims/sync/libc_pthread_mutexattr_double_destroy.rs b/tests/fail/shims/sync/libc_pthread_mutexattr_double_destroy.rs index ac6292570e49..474a277516d9 100644 --- a/tests/fail/shims/sync/libc_pthread_mutexattr_double_destroy.rs +++ b/tests/fail/shims/sync/libc_pthread_mutexattr_double_destroy.rs @@ -1,5 +1,4 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] /// Test that destroying a pthread_mutexattr twice fails, even without a check for number validity diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_destroy_read_locked.rs b/tests/fail/shims/sync/libc_pthread_rwlock_destroy_read_locked.rs index ae7c1bbde72a..603580ff58ab 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_destroy_read_locked.rs +++ b/tests/fail/shims/sync/libc_pthread_rwlock_destroy_read_locked.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_destroy_write_locked.rs b/tests/fail/shims/sync/libc_pthread_rwlock_destroy_write_locked.rs index 9642595ca4e0..ae44f22d146c 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_destroy_write_locked.rs +++ b/tests/fail/shims/sync/libc_pthread_rwlock_destroy_write_locked.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_double_destroy.rs b/tests/fail/shims/sync/libc_pthread_rwlock_double_destroy.rs index 81b1661ce8d4..800986f7506c 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_double_destroy.rs +++ b/tests/fail/shims/sync/libc_pthread_rwlock_double_destroy.rs @@ -1,5 +1,4 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] /// Test that destroying a pthread_rwlock twice fails, even without a check for number validity diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs b/tests/fail/shims/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs index 158dd8c1cda3..782c95b6d2e3 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs +++ b/tests/fail/shims/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_read_wrong_owner.rs b/tests/fail/shims/sync/libc_pthread_rwlock_read_wrong_owner.rs index 23dda68c6a42..1b498ad8fcdb 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_read_wrong_owner.rs +++ b/tests/fail/shims/sync/libc_pthread_rwlock_read_wrong_owner.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - use std::cell::UnsafeCell; use std::sync::Arc; use std::thread; diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_unlock_unlocked.rs b/tests/fail/shims/sync/libc_pthread_rwlock_unlock_unlocked.rs index fdcf8e41d36f..05f7e7a06c57 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_unlock_unlocked.rs +++ b/tests/fail/shims/sync/libc_pthread_rwlock_unlock_unlocked.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock.rs b/tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock.rs index adbb95fc28e8..201844615e18 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock.rs +++ b/tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - use std::cell::UnsafeCell; use std::sync::Arc; use std::thread; diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs b/tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs index a7d16caa7a49..538f14ef89f2 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs +++ b/tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock.rs b/tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock.rs index 070373255d32..b1d7e0492e5a 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock.rs +++ b/tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - use std::cell::UnsafeCell; use std::sync::Arc; use std::thread; diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs b/tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs index 867c6272c463..2c963d36510e 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs +++ b/tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_write_wrong_owner.rs b/tests/fail/shims/sync/libc_pthread_rwlock_write_wrong_owner.rs index cff2a7a2e98c..dd099474d8fe 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_write_wrong_owner.rs +++ b/tests/fail/shims/sync/libc_pthread_rwlock_write_wrong_owner.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - use std::cell::UnsafeCell; use std::sync::Arc; use std::thread; diff --git a/tests/fail/unsupported_signal.rs b/tests/fail/unsupported_signal.rs index 20ebcc9bc473..d50041ffbd9d 100644 --- a/tests/fail/unsupported_signal.rs +++ b/tests/fail/unsupported_signal.rs @@ -1,7 +1,6 @@ //! `signal()` is special on Linux and macOS that it's only supported within libstd. //! The implementation is not complete enough to permit user code to call it. //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] fn main() { unsafe { diff --git a/tests/panic/unsupported_syscall.rs b/tests/panic/unsupported_syscall.rs index 27595bf1071f..31d666e1d9d8 100644 --- a/tests/panic/unsupported_syscall.rs +++ b/tests/panic/unsupported_syscall.rs @@ -1,7 +1,6 @@ //@ignore-target-windows: No libc on Windows //@ignore-target-apple: `syscall` is not supported on macOS //@compile-flags: -Zmiri-panic-on-unsupported -#![feature(rustc_private)] fn main() { unsafe { diff --git a/tests/pass/calloc.rs b/tests/pass/calloc.rs index e155d53ce812..62ab63c5fc78 100644 --- a/tests/pass/calloc.rs +++ b/tests/pass/calloc.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - use core::slice; fn main() { diff --git a/tests/pass/concurrency/libc_pthread_cond.rs b/tests/pass/concurrency/libc_pthread_cond.rs index c5b0e86666a0..b0325f7d78e5 100644 --- a/tests/pass/concurrency/libc_pthread_cond.rs +++ b/tests/pass/concurrency/libc_pthread_cond.rs @@ -2,8 +2,6 @@ //@ignore-target-apple: pthread_condattr_setclock is not supported on MacOS. //@compile-flags: -Zmiri-disable-isolation -#![feature(rustc_private)] - /// Test that conditional variable timeouts are working properly with both /// monotonic and system clocks. use std::mem::MaybeUninit; diff --git a/tests/pass/concurrency/linux-futex.rs b/tests/pass/concurrency/linux-futex.rs index 2c99bfa1000c..a456528ec207 100644 --- a/tests/pass/concurrency/linux-futex.rs +++ b/tests/pass/concurrency/linux-futex.rs @@ -1,8 +1,6 @@ //@only-target-linux //@compile-flags: -Zmiri-disable-isolation -#![feature(rustc_private)] - use std::mem::MaybeUninit; use std::ptr; use std::sync::atomic::AtomicI32; diff --git a/tests/pass/concurrency/tls_pthread_drop_order.rs b/tests/pass/concurrency/tls_pthread_drop_order.rs index 1ccc57da25fa..6200233c8119 100644 --- a/tests/pass/concurrency/tls_pthread_drop_order.rs +++ b/tests/pass/concurrency/tls_pthread_drop_order.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - use std::mem; use std::ptr; diff --git a/tests/pass/foreign-fn-linkname.rs b/tests/pass/foreign-fn-linkname.rs index 40aeb2ef6313..c1cb028f55da 100644 --- a/tests/pass/foreign-fn-linkname.rs +++ b/tests/pass/foreign-fn-linkname.rs @@ -1,5 +1,4 @@ //ignore-windows: Uses POSIX APIs -#![feature(rustc_private)] use std::ffi::CString; diff --git a/tests/pass/malloc.rs b/tests/pass/malloc.rs index 9066e2af25fa..f5e014c000d1 100644 --- a/tests/pass/malloc.rs +++ b/tests/pass/malloc.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - use core::{ptr, slice}; fn main() { diff --git a/tests/pass/regions-mock-trans.rs b/tests/pass/regions-mock-trans.rs index 7432ea958261..caaf48c2bec7 100644 --- a/tests/pass/regions-mock-trans.rs +++ b/tests/pass/regions-mock-trans.rs @@ -1,7 +1,5 @@ //ignore-windows: Uses POSIX APIs -#![feature(rustc_private)] - use std::mem; struct Arena(()); diff --git a/tests/pass/shims/fs.rs b/tests/pass/shims/fs.rs index af9f854ce527..9faced029161 100644 --- a/tests/pass/shims/fs.rs +++ b/tests/pass/shims/fs.rs @@ -1,7 +1,6 @@ //@ignore-target-windows: File handling is not implemented yet //@compile-flags: -Zmiri-disable-isolation -#![feature(rustc_private)] #![feature(io_error_more)] #![feature(io_error_uncategorized)] diff --git a/tests/pass/shims/fs_with_isolation.rs b/tests/pass/shims/fs_with_isolation.rs index f73e64ad17a2..f5420dbc5538 100644 --- a/tests/pass/shims/fs_with_isolation.rs +++ b/tests/pass/shims/fs_with_isolation.rs @@ -2,8 +2,6 @@ //@compile-flags: -Zmiri-isolation-error=warn-nobacktrace //@normalize-stderr-test: "(stat(x)?)" -> "$$STAT" -#![feature(rustc_private)] - use std::ffi::CString; use std::fs::{self, File}; use std::io::{Error, ErrorKind}; diff --git a/tests/pass/shims/linux-getrandom-without-isolation.rs b/tests/pass/shims/linux-getrandom-without-isolation.rs index 12b42552bd5d..349b447569a4 100644 --- a/tests/pass/shims/linux-getrandom-without-isolation.rs +++ b/tests/pass/shims/linux-getrandom-without-isolation.rs @@ -1,6 +1,5 @@ //@only-target-linux //@compile-flags: -Zmiri-disable-isolation -#![feature(rustc_private)] use std::ptr; diff --git a/tests/pass/shims/linux-getrandom.rs b/tests/pass/shims/linux-getrandom.rs index e3309f480d36..a1436c7319d3 100644 --- a/tests/pass/shims/linux-getrandom.rs +++ b/tests/pass/shims/linux-getrandom.rs @@ -1,5 +1,4 @@ //@only-target-linux -#![feature(rustc_private)] use std::ptr; diff --git a/tests/pass/shims/posix_memalign.rs b/tests/pass/shims/posix_memalign.rs index 5dadb62436d6..9bd8a00d68dc 100644 --- a/tests/pass/shims/posix_memalign.rs +++ b/tests/pass/shims/posix_memalign.rs @@ -1,6 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] #![feature(pointer_is_aligned)] #![feature(strict_provenance)] From ed41f1c96980ed26512e10e39406d8c91033a9e7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Aug 2022 22:00:54 -0400 Subject: [PATCH 3753/5092] remove some leftover //ignore that did not do anything --- tests/pass/foreign-fn-linkname.rs | 2 -- tests/pass/regions-mock-trans.rs | 2 -- 2 files changed, 4 deletions(-) diff --git a/tests/pass/foreign-fn-linkname.rs b/tests/pass/foreign-fn-linkname.rs index c1cb028f55da..9f090a4eff5d 100644 --- a/tests/pass/foreign-fn-linkname.rs +++ b/tests/pass/foreign-fn-linkname.rs @@ -1,5 +1,3 @@ -//ignore-windows: Uses POSIX APIs - use std::ffi::CString; mod mlibc { diff --git a/tests/pass/regions-mock-trans.rs b/tests/pass/regions-mock-trans.rs index caaf48c2bec7..57f1b75f4d52 100644 --- a/tests/pass/regions-mock-trans.rs +++ b/tests/pass/regions-mock-trans.rs @@ -1,5 +1,3 @@ -//ignore-windows: Uses POSIX APIs - use std::mem; struct Arena(()); From b6fc2fc82a90ee1deb4a65c811764c610155b6b9 Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Wed, 25 May 2022 16:28:37 -0700 Subject: [PATCH 3754/5092] basic theading --- src/lib.rs | 2 + src/shims/tls.rs | 16 +- src/shims/unix/thread.rs | 43 +---- src/shims/windows/dlsym.rs | 20 ++- src/shims/windows/foreign_items.rs | 106 +++++++----- src/shims/windows/handle.rs | 162 ++++++++++++++++++ src/shims/windows/mod.rs | 2 + src/shims/windows/thread.rs | 84 +++++++++ src/thread.rs | 113 +++++++++--- ...rs => libc_pthread_create_too_few_args.rs} | 2 +- ...> libc_pthread_create_too_few_args.stderr} | 2 +- ...s => libc_pthread_create_too_many_args.rs} | 2 +- ... libc_pthread_create_too_many_args.stderr} | 2 +- .../concurrency/libc_pthread_join_detached.rs | 2 +- .../libc_pthread_join_detached.stderr | 2 +- tests/fail/concurrency/thread-spawn.rs | 9 - tests/fail/concurrency/thread-spawn.stderr | 30 ---- .../thread_local_static_dealloc.rs | 2 - tests/fail/concurrency/unwind_top_of_stack.rs | 3 +- tests/fail/data_race/alloc_read_race.rs | 1 - tests/fail/data_race/alloc_write_race.rs | 1 - .../data_race/atomic_read_na_write_race1.rs | 1 - .../data_race/atomic_read_na_write_race2.rs | 1 - .../data_race/atomic_write_na_read_race1.rs | 1 - .../data_race/atomic_write_na_read_race2.rs | 1 - .../data_race/atomic_write_na_write_race1.rs | 1 - .../data_race/atomic_write_na_write_race2.rs | 1 - .../data_race/dangling_thread_async_race.rs | 1 - tests/fail/data_race/dangling_thread_race.rs | 1 - tests/fail/data_race/dealloc_read_race1.rs | 1 - tests/fail/data_race/dealloc_read_race2.rs | 1 - .../fail/data_race/dealloc_read_race_stack.rs | 1 - tests/fail/data_race/dealloc_write_race1.rs | 1 - tests/fail/data_race/dealloc_write_race2.rs | 1 - .../data_race/dealloc_write_race_stack.rs | 1 - .../data_race/enable_after_join_to_main.rs | 1 - tests/fail/data_race/fence_after_load.rs | 1 - tests/fail/data_race/read_write_race.rs | 1 - tests/fail/data_race/read_write_race_stack.rs | 1 - tests/fail/data_race/relax_acquire_race.rs | 1 - tests/fail/data_race/release_seq_race.rs | 1 - .../data_race/release_seq_race_same_thread.rs | 1 - tests/fail/data_race/rmw_race.rs | 1 - tests/fail/data_race/write_write_race.rs | 1 - .../fail/data_race/write_write_race_stack.rs | 1 - tests/fail/should-pass/cpp20_rwc_syncs.rs | 1 - tests/fail/weak_memory/racing_mixed_size.rs | 1 - .../weak_memory/racing_mixed_size_read.rs | 1 - tests/pass/0weak_memory_consistency.rs | 1 - tests/pass/concurrency/channels.rs | 2 +- .../concurrency/concurrent_caller_location.rs | 2 - tests/pass/concurrency/data_race.rs | 1 - .../concurrency/disable_data_race_detector.rs | 1 - tests/pass/concurrency/issue1643.rs | 2 - tests/pass/concurrency/simple.rs | 1 - tests/pass/concurrency/spin_loop.rs | 1 - .../pass/concurrency/spin_loops_nopreempt.rs | 2 +- tests/pass/concurrency/thread_locals.rs | 1 - tests/pass/concurrency/tls_lib_drop.rs | 2 - tests/pass/panic/concurrent-panic.rs | 2 +- tests/pass/shims/time.rs | 3 - tests/pass/threadleak_ignored.rs | 2 +- tests/pass/weak_memory/extra_cpp.rs | 1 - tests/pass/weak_memory/extra_cpp_unsafe.rs | 1 - tests/pass/weak_memory/weak.rs | 1 - 65 files changed, 450 insertions(+), 209 deletions(-) create mode 100644 src/shims/windows/handle.rs create mode 100644 src/shims/windows/thread.rs rename tests/fail/concurrency/{too_few_args.rs => libc_pthread_create_too_few_args.rs} (92%) rename tests/fail/concurrency/{too_few_args.stderr => libc_pthread_create_too_few_args.stderr} (92%) rename tests/fail/concurrency/{too_many_args.rs => libc_pthread_create_too_many_args.rs} (92%) rename tests/fail/concurrency/{too_many_args.stderr => libc_pthread_create_too_many_args.stderr} (92%) delete mode 100644 tests/fail/concurrency/thread-spawn.rs delete mode 100644 tests/fail/concurrency/thread-spawn.stderr diff --git a/src/lib.rs b/src/lib.rs index ba337f28311e..73c96b2e59ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,8 @@ #![feature(try_blocks)] #![feature(let_else)] #![feature(io_error_more)] +#![feature(int_log)] +#![feature(variant_count)] #![feature(yeet_expr)] #![feature(is_some_with)] #![feature(nonzero_ops)] diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 633e0322bb83..8627d9a04479 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -229,25 +229,25 @@ impl<'tcx> TlsData<'tcx> { impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// Schedule TLS destructors for the main thread on Windows. The - /// implementation assumes that we do not support concurrency on Windows - /// yet. + /// Schedule TLS destructors for Windows. + /// On windows, TLS destructors are managed by std. fn schedule_windows_tls_dtors(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let active_thread = this.get_active_thread(); - assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); + // Windows has a special magic linker section that is run on certain events. // Instead of searching for that section and supporting arbitrary hooks in there // (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. - let thread_callback = this - .eval_path_scalar(&["std", "sys", "windows", "thread_local_key", "p_thread_callback"])? - .to_pointer(this)?; + 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()?; + // Technically, the reason should be `DLL_PROCESS_DETACH` when the main thread exits but std ignores it. + let reason = this.eval_windows("c", "DLL_THREAD_DETACH")?; + // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. - let reason = this.eval_path_scalar(&["std", "sys", "windows", "c", "DLL_THREAD_DETACH"])?; this.call_function( thread_callback, Abi::System { unwind: false }, diff --git a/src/shims/unix/thread.rs b/src/shims/unix/thread.rs index 0df70543fac8..094183b3e781 100644 --- a/src/shims/unix/thread.rs +++ b/src/shims/unix/thread.rs @@ -13,47 +13,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Create the new thread - let new_thread_id = this.create_thread(); - - // Write the current thread-id, switch to the next thread later - // to treat this write operation as occuring on the current thread. - let thread_info_place = this.deref_operand(thread)?; - this.write_scalar( - Scalar::from_uint(new_thread_id.to_u32(), thread_info_place.layout.size), - &thread_info_place.into(), - )?; - - // Read the function argument that will be sent to the new thread - // before the thread starts executing since reading after the - // context switch will incorrectly report a data-race. - let fn_ptr = this.read_pointer(start_routine)?; - let func_arg = this.read_immediate(arg)?; - - // Finally switch to new thread so that we can push the first stackframe. - // After this all accesses will be treated as occuring in the new thread. - let old_thread_id = this.set_active_thread(new_thread_id); - - // Perform the function pointer load in the new thread frame. - let instance = this.get_ptr_fn(fn_ptr)?.as_instance()?; - - // Note: the returned value is currently ignored (see the FIXME in - // pthread_join below) because the Rust standard library does not use - // it. - let ret_place = - this.allocate(this.layout_of(this.tcx.types.usize)?, MiriMemoryKind::Machine.into())?; - - this.call_function( - instance, + this.start_thread( + Some(thread), + start_routine, Abi::C { unwind: false }, - &[*func_arg], - Some(&ret_place.into()), - StackPopCleanup::Root { cleanup: true }, + arg, + this.layout_of(this.tcx.types.usize)?, )?; - // Restore the old active thread frame. - this.set_active_thread(old_thread_id); - Ok(0) } diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index eab5f99c8785..f18e27d38c2b 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -5,11 +5,13 @@ use rustc_target::spec::abi::Abi; use log::trace; use crate::helpers::check_arg_count; +use crate::shims::windows::handle::Handle; use crate::*; #[derive(Debug, Copy, Clone)] pub enum Dlsym { NtWriteFile, + SetThreadDescription, } impl Dlsym { @@ -18,8 +20,8 @@ impl Dlsym { pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { Ok(match name { "GetSystemTimePreciseAsFileTime" => None, - "SetThreadDescription" => None, "NtWriteFile" => Some(Dlsym::NtWriteFile), + "SetThreadDescription" => Some(Dlsym::SetThreadDescription), _ => throw_unsup_format!("unsupported Windows dlsym: {}", name), }) } @@ -107,6 +109,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest, )?; } + Dlsym::SetThreadDescription => { + let [handle, name] = check_arg_count(args)?; + + let name = this.read_wide_str(this.read_pointer(name)?)?; + + let thread = + match Handle::from_scalar(this.read_scalar(handle)?.check_init()?, this)? { + Some(Handle::Thread(thread)) => thread, + Some(Handle::CurrentThread) => this.get_active_thread(), + _ => throw_ub_format!("invalid handle"), + }; + + this.set_thread_name_wide(thread, name); + + this.write_null(dest)?; + } } trace!("{:?}", this.dump_place(**dest)); diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 6520609b76f4..00a80f869751 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -1,12 +1,17 @@ use std::iter; +use std::time::{Duration, Instant}; use rustc_span::Symbol; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; +use crate::thread::Time; use crate::*; use shims::foreign_items::EmulateByNameResult; +use shims::windows::handle::{EvalContextExt as _, Handle}; use shims::windows::sync::EvalContextExt as _; +use shims::windows::thread::EvalContextExt as _; + use smallvec::SmallVec; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -219,6 +224,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.QueryPerformanceFrequency(lpFrequency)?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "Sleep" => { + let [timeout] = + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + + this.check_no_isolation("`Sleep`")?; + + let timeout_ms = this.read_scalar(timeout)?.to_u32()?; + + let duration = Duration::from_millis(timeout_ms as u64); + let timeout_time = Time::Monotonic(Instant::now().checked_add(duration).unwrap()); + + let active_thread = this.get_active_thread(); + this.block_thread(active_thread); + + this.register_timeout_callback( + active_thread, + timeout_time, + Box::new(move |ecx| { + ecx.unblock_thread(active_thread); + Ok(()) + }), + ); + } // Synchronization primitives "AcquireSRWLockExclusive" => { @@ -314,10 +342,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: we should set last_error, but to what? this.write_null(dest)?; } - "SwitchToThread" => { + // this is only callable from std because we know that std ignores the return value + "SwitchToThread" if this.frame_in_std() => { let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - // Note that once Miri supports concurrency, this will need to return a nonzero - // value if this call does result in switching to another thread. + + this.yield_active_thread(); + + // FIXME: this should return a nonzero value if this call does result in switching to another thread. this.write_null(dest)?; } "GetStdHandle" => { @@ -329,14 +360,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // std-only shim. this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?; } - - // Better error for attempts to create a thread - "CreateThread" => { - let [_, _, _, _, _, _] = + "CloseHandle" => { + let [handle] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - this.handle_unsupported("can't create threads on Windows")?; - return Ok(EmulateByNameResult::AlreadyJumped); + this.CloseHandle(handle)?; + + this.write_scalar(Scalar::from_u32(1), dest)?; + } + + // Threading + "CreateThread" => { + let [security, stacksize, start, arg, flags, thread] = + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + + let thread_id = + this.CreateThread(security, stacksize, start, arg, flags, thread)?; + + this.write_scalar(Handle::Thread(thread_id).to_scalar(this), dest)?; + } + "WaitForSingleObject" => { + let [handle, timeout] = + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + + this.WaitForSingleObject(handle, timeout)?; + + this.write_scalar(Scalar::from_u32(0), dest)?; + } + "GetCurrentThread" => { + let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + + this.write_scalar(Handle::CurrentThread.to_scalar(this), dest)?; } // Incomplete shims that we "stub out" just to get pre-main initialization code to work. @@ -374,40 +428,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_u32(1), dest)?; } - | "InitializeCriticalSection" - | "EnterCriticalSection" - | "LeaveCriticalSection" - | "DeleteCriticalSection" - if this.frame_in_std() => - { - #[allow(non_snake_case)] - let [_lpCriticalSection] = - this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - assert_eq!( - this.get_total_thread_count(), - 1, - "concurrency on Windows is not supported" - ); - // Nothing to do, not even a return value. - // (Windows locks are reentrant, and we have only 1 thread, - // so not doing any futher checks here is at least not incorrect.) - } - "TryEnterCriticalSection" if this.frame_in_std() => { - #[allow(non_snake_case)] - let [_lpCriticalSection] = - this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - assert_eq!( - this.get_total_thread_count(), - 1, - "concurrency on Windows is not supported" - ); - // There is only one thread, so this always succeeds and returns TRUE. - this.write_scalar(Scalar::from_i32(1), dest)?; - } - "GetCurrentThread" if this.frame_in_std() => { - let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; - } "GetCurrentProcessId" if this.frame_in_std() => { let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.GetCurrentProcessId()?; diff --git a/src/shims/windows/handle.rs b/src/shims/windows/handle.rs new file mode 100644 index 000000000000..ff64a958da3e --- /dev/null +++ b/src/shims/windows/handle.rs @@ -0,0 +1,162 @@ +use rustc_target::abi::HasDataLayout; +use std::mem::variant_count; + +use crate::*; + +/// A Windows `HANDLE` that represents a resource instead of being null or a pseudohandle. +/// +/// This is a seperate type from [`Handle`] to simplify the packing and unpacking code. +#[derive(Clone, Copy)] +enum RealHandle { + Thread(ThreadId), +} + +impl RealHandle { + const USABLE_BITS: u32 = 31; + + const THREAD_DISCRIMINANT: u32 = 1; + + fn discriminant(self) -> u32 { + match self { + // can't use zero here because all zero handle is invalid + Self::Thread(_) => Self::THREAD_DISCRIMINANT, + } + } + + fn data(self) -> u32 { + match self { + Self::Thread(thread) => thread.to_u32(), + } + } + + fn packed_disc_size() -> u32 { + // log2(x) + 1 is how many bits it takes to store x + // because the discriminants start at 1, the variant count is equal to the highest discriminant + variant_count::().ilog2() + 1 + } + + /// This function packs the discriminant and data values into a 31-bit space. + /// None of this layout is guaranteed to applications by Windows or Miri. + /// The sign bit is not used to avoid overlapping any pseudo-handles. + fn to_packed(self) -> i32 { + let disc_size = Self::packed_disc_size(); + let data_size = Self::USABLE_BITS - disc_size; + + let discriminant = self.discriminant(); + let data = self.data(); + + // make sure the discriminant fits into `disc_size` bits + assert!(discriminant < 2u32.pow(disc_size)); + + // make sure the data fits into `data_size` bits + assert!(data < 2u32.pow(data_size)); + + // packs the data into the lower `data_size` bits + // and packs the discriminant right above the data + (discriminant << data_size | data) as i32 + } + + fn new(discriminant: u32, data: u32) -> Option { + match discriminant { + Self::THREAD_DISCRIMINANT => Some(Self::Thread(data.into())), + _ => None, + } + } + + /// see docs for `to_packed` + fn from_packed(handle: i32) -> Option { + let handle_bits = handle as u32; + + let disc_size = Self::packed_disc_size(); + let data_size = Self::USABLE_BITS - disc_size; + + // the lower `data_size` bits of this mask are 1 + let data_mask = 2u32.pow(data_size) - 1; + + // the discriminant is stored right above the lower `data_size` bits + let discriminant = handle_bits >> data_size; + + // the data is stored in the lower `data_size` bits + let data = handle_bits & data_mask; + + Self::new(discriminant, data) + } +} + +/// Miri representation of a Windows `HANDLE` +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum Handle { + Null, // = 0 + + // pseudo-handles + // The lowest real windows pseudo-handle is -6, so miri pseduo-handles start at -7 to break code hardcoding these values + CurrentThread, // = -7 + + // real handles + Thread(ThreadId), +} + +impl Handle { + const CURRENT_THREAD_VALUE: i32 = -7; + + fn to_packed(self) -> i32 { + match self { + Self::Null => 0, + Self::CurrentThread => Self::CURRENT_THREAD_VALUE, + Self::Thread(thread) => RealHandle::Thread(thread).to_packed(), + } + } + + pub fn to_scalar(self, cx: &impl HasDataLayout) -> Scalar { + // 64-bit handles are sign extended 32-bit handles + // see https://docs.microsoft.com/en-us/windows/win32/winprog64/interprocess-communication + let handle = self.to_packed().into(); + + Scalar::from_machine_isize(handle, cx) + } + + fn from_packed(handle: i64) -> Option { + let current_thread_val = Self::CURRENT_THREAD_VALUE as i64; + + if handle == 0 { + Some(Self::Null) + } else if handle == current_thread_val { + Some(Self::CurrentThread) + } else if let Ok(handle) = handle.try_into() { + match RealHandle::from_packed(handle)? { + RealHandle::Thread(id) => Some(Self::Thread(id)), + } + } else { + // if a handle doesn't fit in an i32, it isn't valid. + None + } + } + + pub fn from_scalar<'tcx>( + handle: Scalar, + cx: &impl HasDataLayout, + ) -> InterpResult<'tcx, Option> { + let handle = handle.to_machine_isize(cx)?; + + Ok(Self::from_packed(handle)) + } +} + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} + +#[allow(non_snake_case)] +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn CloseHandle(&mut self, handle_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + match Handle::from_scalar(this.read_scalar(handle_op)?.check_init()?, this)? { + Some(Handle::Thread(thread)) => this.detach_thread(thread)?, + _ => + throw_machine_stop!(TerminationInfo::Abort( + "invalid handle passed to `CloseHandle`".into() + )), + }; + + Ok(()) + } +} diff --git a/src/shims/windows/mod.rs b/src/shims/windows/mod.rs index 668d69966bc4..40fe71b2dbd0 100644 --- a/src/shims/windows/mod.rs +++ b/src/shims/windows/mod.rs @@ -1,4 +1,6 @@ pub mod dlsym; pub mod foreign_items; +mod handle; mod sync; +mod thread; diff --git a/src/shims/windows/thread.rs b/src/shims/windows/thread.rs new file mode 100644 index 000000000000..66cd9dd0348f --- /dev/null +++ b/src/shims/windows/thread.rs @@ -0,0 +1,84 @@ +use std::time::{Duration, Instant}; + +use rustc_middle::ty::layout::LayoutOf; +use rustc_target::spec::abi::Abi; + +use crate::thread::Time; +use crate::*; +use shims::windows::handle::Handle; + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} + +#[allow(non_snake_case)] +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn CreateThread( + &mut self, + security_op: &OpTy<'tcx, Provenance>, + stacksize_op: &OpTy<'tcx, Provenance>, + start_op: &OpTy<'tcx, Provenance>, + arg_op: &OpTy<'tcx, Provenance>, + flags_op: &OpTy<'tcx, Provenance>, + thread_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, ThreadId> { + let this = self.eval_context_mut(); + + if !this.ptr_is_null(this.read_pointer(security_op)?)? { + throw_unsup_format!("non-null `lpThreadAttributes` in `CreateThread`") + } + + // stacksize is ignored, but still needs to be a valid usize + let _ = this.read_scalar(stacksize_op)?.to_machine_usize(this)?; + + let flags = this.read_scalar(flags_op)?.to_u32()?; + + let stack_size_param_is_a_reservation = + this.eval_windows("c", "STACK_SIZE_PARAM_IS_A_RESERVATION")?.to_u32()?; + + if flags != 0 && flags != stack_size_param_is_a_reservation { + throw_unsup_format!("unsupported `dwCreationFlags` {} in `CreateThread`", flags) + } + + let thread = + if this.ptr_is_null(this.read_pointer(thread_op)?)? { None } else { Some(thread_op) }; + + this.start_thread( + thread, + start_op, + Abi::System { unwind: false }, + arg_op, + this.layout_of(this.tcx.types.u32)?, + ) + } + + fn WaitForSingleObject( + &mut self, + handle: &OpTy<'tcx, Provenance>, + timeout: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let thread = match Handle::from_scalar(this.read_scalar(handle)?.check_init()?, this)? { + Some(Handle::Thread(thread)) => thread, + Some(Handle::CurrentThread) => throw_ub_format!("trying to wait on itself"), + _ => throw_ub_format!("invalid handle"), + }; + + if this.read_scalar(timeout)?.to_u32()? != this.eval_windows("c", "INFINITE")?.to_u32()? { + this.check_no_isolation("`WaitForSingleObject` with non-infinite timeout")?; + } + + let timeout_ms = this.read_scalar(timeout)?.to_u32()?; + + let timeout_time = if timeout_ms == this.eval_windows("c", "INFINITE")?.to_u32()? { + None + } else { + let duration = Duration::from_millis(timeout_ms as u64); + + Some(Time::Monotonic(Instant::now().checked_add(duration).unwrap())) + }; + + this.wait_on_thread(timeout_time, thread)?; + + Ok(()) + } +} diff --git a/src/thread.rs b/src/thread.rs index 6f394fa42fc9..fa70dcfa2a3d 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -11,6 +11,8 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::mir::Mutability; +use rustc_middle::ty::layout::TyAndLayout; +use rustc_target::spec::abi::Abi; use crate::concurrency::data_race; use crate::sync::SynchronizationState; @@ -179,7 +181,7 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> { } /// A specific moment in time. -#[derive(Debug)] +#[derive(Debug, Copy, Clone)] pub enum Time { Monotonic(Instant), RealTime(SystemTime), @@ -238,10 +240,7 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { fn default() -> Self { let mut threads = IndexVec::new(); // Create the main thread and add it to the list of threads. - let mut main_thread = Thread::new("main"); - // The main thread can *not* be joined on. - main_thread.join_status = ThreadJoinStatus::Detached; - threads.push(main_thread); + threads.push(Thread::new("main")); Self { active_thread: ThreadId::new(0), threads, @@ -254,6 +253,13 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { } impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { + pub(crate) fn init(ecx: &mut MiriEvalContext<'mir, 'tcx>) { + if ecx.tcx.sess.target.os.as_ref() != "windows" { + // The main thread can *not* be joined on except on windows. + ecx.machine.threads.threads[ThreadId::new(0)].join_status = ThreadJoinStatus::Detached; + } + } + /// Check if we have an allocation for the given thread local static for the /// active thread. fn get_thread_local_alloc_id(&self, def_id: DefId) -> Option> { @@ -348,10 +354,23 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Mark the thread as detached, which means that no other thread will try /// to join it and the thread is responsible for cleaning up. - fn detach_thread(&mut self, id: ThreadId) -> InterpResult<'tcx> { - if self.threads[id].join_status != ThreadJoinStatus::Joinable { + /// + /// `allow_terminated_joined` allows detaching joined threads that have already terminated. + /// This matches Windows's behavior for `CloseHandle`. + fn detach_thread(&mut self, id: ThreadId, allow_terminated_joined: bool) -> InterpResult<'tcx> { + trace!("detaching {:?}", id); + + let is_ub = if allow_terminated_joined && self.threads[id].state == ThreadState::Terminated + { + self.threads[id].join_status == ThreadJoinStatus::Detached + } else { + self.threads[id].join_status != ThreadJoinStatus::Joinable + }; + + if is_ub { throw_ub_format!("trying to detach thread that was already detached or joined"); } + self.threads[id].join_status = ThreadJoinStatus::Detached; Ok(()) } @@ -362,18 +381,10 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { joined_thread_id: ThreadId, data_race: Option<&mut data_race::GlobalState>, ) -> InterpResult<'tcx> { - if self.threads[joined_thread_id].join_status != ThreadJoinStatus::Joinable { - throw_ub_format!("trying to join a detached or already joined thread"); + if self.threads[joined_thread_id].join_status == ThreadJoinStatus::Detached { + throw_ub_format!("trying to join a detached thread"); } - if joined_thread_id == self.active_thread { - throw_ub_format!("trying to join itself"); - } - assert!( - self.threads - .iter() - .all(|thread| thread.state != ThreadState::BlockedOnJoin(joined_thread_id)), - "a joinable thread already has threads waiting for its termination" - ); + // Mark the joined thread as being joined so that we detect if other // threads try to join it. self.threads[joined_thread_id].join_status = ThreadJoinStatus::Joined; @@ -624,9 +635,62 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[inline] - fn detach_thread(&mut self, thread_id: ThreadId) -> InterpResult<'tcx> { + fn start_thread( + &mut self, + thread: Option>, + start_routine: Pointer>, + start_abi: Abi, + func_arg: ImmTy<'tcx, Provenance>, + ret_layout: TyAndLayout<'tcx>, + ) -> InterpResult<'tcx, ThreadId> { let this = self.eval_context_mut(); - this.machine.threads.detach_thread(thread_id) + + // Create the new thread + let new_thread_id = this.create_thread(); + + // Write the current thread-id, switch to the next thread later + // to treat this write operation as occuring on the current thread. + if let Some(thread_info_place) = thread { + this.write_scalar( + Scalar::from_uint(new_thread_id.to_u32(), thread_info_place.layout.size), + &thread_info_place.into(), + )?; + } + + // Finally switch to new thread so that we can push the first stackframe. + // After this all accesses will be treated as occuring in the new thread. + let old_thread_id = this.set_active_thread(new_thread_id); + + // Perform the function pointer load in the new thread frame. + let instance = this.get_ptr_fn(start_routine)?.as_instance()?; + + // Note: the returned value is currently ignored (see the FIXME in + // pthread_join in shims/unix/thread.rs) because the Rust standard library does not use + // it. + let ret_place = this.allocate(ret_layout, MiriMemoryKind::Machine.into())?; + + this.call_function( + instance, + start_abi, + &[*func_arg], + Some(&ret_place.into()), + StackPopCleanup::Root { cleanup: true }, + )?; + + // Restore the old active thread frame. + this.set_active_thread(old_thread_id); + + Ok(new_thread_id) + } + + #[inline] + fn detach_thread( + &mut self, + thread_id: ThreadId, + allow_terminated_joined: bool, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + this.machine.threads.detach_thread(thread_id, allow_terminated_joined) } #[inline] @@ -704,6 +768,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.threads.set_thread_name(thread, new_thread_name); } + #[inline] + fn set_thread_name_wide(&mut self, thread: ThreadId, new_thread_name: Vec) { + let this = self.eval_context_mut(); + this.machine.threads.set_thread_name( + thread, + new_thread_name.into_iter().flat_map(u16::to_ne_bytes).collect(), + ); + } + #[inline] fn get_thread_name<'c>(&'c self, thread: ThreadId) -> &'c [u8] where diff --git a/tests/fail/concurrency/too_few_args.rs b/tests/fail/concurrency/libc_pthread_create_too_few_args.rs similarity index 92% rename from tests/fail/concurrency/too_few_args.rs rename to tests/fail/concurrency/libc_pthread_create_too_few_args.rs index 43c7c74d410f..e1d3704af7c0 100644 --- a/tests/fail/concurrency/too_few_args.rs +++ b/tests/fail/concurrency/libc_pthread_create_too_few_args.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: No libc on Windows //! The thread function must have exactly one argument. diff --git a/tests/fail/concurrency/too_few_args.stderr b/tests/fail/concurrency/libc_pthread_create_too_few_args.stderr similarity index 92% rename from tests/fail/concurrency/too_few_args.stderr rename to tests/fail/concurrency/libc_pthread_create_too_few_args.stderr index c1eb4d8cb6b6..2304b42b2c78 100644 --- a/tests/fail/concurrency/too_few_args.stderr +++ b/tests/fail/concurrency/libc_pthread_create_too_few_args.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: callee has fewer arguments than expected - --> $DIR/too_few_args.rs:LL:CC + --> $DIR/libc_pthread_create_too_few_args.rs:LL:CC | LL | panic!() | ^^^^^^^^ callee has fewer arguments than expected diff --git a/tests/fail/concurrency/too_many_args.rs b/tests/fail/concurrency/libc_pthread_create_too_many_args.rs similarity index 92% rename from tests/fail/concurrency/too_many_args.rs rename to tests/fail/concurrency/libc_pthread_create_too_many_args.rs index d660037ca669..7408634db528 100644 --- a/tests/fail/concurrency/too_many_args.rs +++ b/tests/fail/concurrency/libc_pthread_create_too_many_args.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: No libc on Windows //! The thread function must have exactly one argument. diff --git a/tests/fail/concurrency/too_many_args.stderr b/tests/fail/concurrency/libc_pthread_create_too_many_args.stderr similarity index 92% rename from tests/fail/concurrency/too_many_args.stderr rename to tests/fail/concurrency/libc_pthread_create_too_many_args.stderr index 42a96ae62636..49c7f579970f 100644 --- a/tests/fail/concurrency/too_many_args.stderr +++ b/tests/fail/concurrency/libc_pthread_create_too_many_args.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: callee has more arguments than expected - --> $DIR/too_many_args.rs:LL:CC + --> $DIR/libc_pthread_create_too_many_args.rs:LL:CC | LL | panic!() | ^^^^^^^^ callee has more arguments than expected diff --git a/tests/fail/concurrency/libc_pthread_join_detached.rs b/tests/fail/concurrency/libc_pthread_join_detached.rs index 488b14bbcfa8..0b810dc8c721 100644 --- a/tests/fail/concurrency/libc_pthread_join_detached.rs +++ b/tests/fail/concurrency/libc_pthread_join_detached.rs @@ -15,6 +15,6 @@ fn main() { // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented. assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0); assert_eq!(libc::pthread_detach(native), 0); - assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join a detached or already joined thread + assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join a detached thread } } diff --git a/tests/fail/concurrency/libc_pthread_join_detached.stderr b/tests/fail/concurrency/libc_pthread_join_detached.stderr index be9781ff46ea..e381a71b2520 100644 --- a/tests/fail/concurrency/libc_pthread_join_detached.stderr +++ b/tests/fail/concurrency/libc_pthread_join_detached.stderr @@ -2,7 +2,7 @@ error: Undefined Behavior: trying to join a detached or already joined thread --> $DIR/libc_pthread_join_detached.rs:LL:CC | LL | ... assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached or already joined thread + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached thread | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/concurrency/thread-spawn.rs b/tests/fail/concurrency/thread-spawn.rs deleted file mode 100644 index 84848e35a0f3..000000000000 --- a/tests/fail/concurrency/thread-spawn.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@only-target-windows: Only Windows is not supported. - -use std::thread; - -//@error-pattern: can't create threads on Windows - -fn main() { - thread::spawn(|| {}); -} diff --git a/tests/fail/concurrency/thread-spawn.stderr b/tests/fail/concurrency/thread-spawn.stderr deleted file mode 100644 index 2e4b3a045e69..000000000000 --- a/tests/fail/concurrency/thread-spawn.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error: unsupported operation: can't create threads on Windows - --> RUSTLIB/std/src/sys/PLATFORM/thread.rs:LL:CC - | -LL | let ret = c::CreateThread( - | ___________________^ -LL | | ptr::null_mut(), -LL | | stack, -LL | | thread_start, -... | -LL | | ptr::null_mut(), -LL | | ); - | |_________^ can't create threads on Windows - | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: - = note: inside `std::sys::PLATFORM::thread::Thread::new` at RUSTLIB/std/src/sys/PLATFORM/thread.rs:LL:CC - = note: inside `std::thread::Builder::spawn_unchecked_::<[closure@$DIR/thread-spawn.rs:LL:CC], ()>` at RUSTLIB/std/src/thread/mod.rs:LL:CC - = note: inside `std::thread::Builder::spawn_unchecked::<[closure@$DIR/thread-spawn.rs:LL:CC], ()>` at RUSTLIB/std/src/thread/mod.rs:LL:CC - = note: inside `std::thread::Builder::spawn::<[closure@$DIR/thread-spawn.rs:LL:CC], ()>` at RUSTLIB/std/src/thread/mod.rs:LL:CC - = note: inside `std::thread::spawn::<[closure@$DIR/thread-spawn.rs:LL:CC], ()>` at RUSTLIB/std/src/thread/mod.rs:LL:CC -note: inside `main` at $DIR/thread-spawn.rs:LL:CC - --> $DIR/thread-spawn.rs:LL:CC - | -LL | thread::spawn(|| {}); - | ^^^^^^^^^^^^^^^^^^^^ - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/concurrency/thread_local_static_dealloc.rs b/tests/fail/concurrency/thread_local_static_dealloc.rs index 7c54e3bca7c1..d89c670b632e 100644 --- a/tests/fail/concurrency/thread_local_static_dealloc.rs +++ b/tests/fail/concurrency/thread_local_static_dealloc.rs @@ -1,5 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. - //! Ensure that thread-local statics get deallocated when the thread dies. #![feature(thread_local)] diff --git a/tests/fail/concurrency/unwind_top_of_stack.rs b/tests/fail/concurrency/unwind_top_of_stack.rs index c2b9d56e19c9..61d3b964e620 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.rs +++ b/tests/fail/concurrency/unwind_top_of_stack.rs @@ -1,4 +1,5 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: No libc on Windows + //@compile-flags: -Zmiri-disable-abi-check //! Unwinding past the top frame of a stack is Undefined Behavior. diff --git a/tests/fail/data_race/alloc_read_race.rs b/tests/fail/data_race/alloc_read_race.rs index f3f63aeb2b83..0bd3068af1ff 100644 --- a/tests/fail/data_race/alloc_read_race.rs +++ b/tests/fail/data_race/alloc_read_race.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 #![feature(new_uninit)] diff --git a/tests/fail/data_race/alloc_write_race.rs b/tests/fail/data_race/alloc_write_race.rs index a2738c3879b3..7991280721e2 100644 --- a/tests/fail/data_race/alloc_write_race.rs +++ b/tests/fail/data_race/alloc_write_race.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 #![feature(new_uninit)] diff --git a/tests/fail/data_race/atomic_read_na_write_race1.rs b/tests/fail/data_race/atomic_read_na_write_race1.rs index 30900a85d003..2b0446d724a0 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.rs +++ b/tests/fail/data_race/atomic_read_na_write_race1.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/tests/fail/data_race/atomic_read_na_write_race2.rs b/tests/fail/data_race/atomic_read_na_write_race2.rs index 493985f6cf17..ef5157515c64 100644 --- a/tests/fail/data_race/atomic_read_na_write_race2.rs +++ b/tests/fail/data_race/atomic_read_na_write_race2.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; diff --git a/tests/fail/data_race/atomic_write_na_read_race1.rs b/tests/fail/data_race/atomic_write_na_read_race1.rs index ca9c28abf1a9..8c17e7674843 100644 --- a/tests/fail/data_race/atomic_write_na_read_race1.rs +++ b/tests/fail/data_race/atomic_write_na_read_race1.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; diff --git a/tests/fail/data_race/atomic_write_na_read_race2.rs b/tests/fail/data_race/atomic_write_na_read_race2.rs index 1a79dde0b08a..f14d7c704dbb 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.rs +++ b/tests/fail/data_race/atomic_write_na_read_race2.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/tests/fail/data_race/atomic_write_na_write_race1.rs b/tests/fail/data_race/atomic_write_na_write_race1.rs index 04015c2d1420..0804b3340758 100644 --- a/tests/fail/data_race/atomic_write_na_write_race1.rs +++ b/tests/fail/data_race/atomic_write_na_write_race1.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/tests/fail/data_race/atomic_write_na_write_race2.rs b/tests/fail/data_race/atomic_write_na_write_race2.rs index 1d242ff3cdd6..658cddcc9c5b 100644 --- a/tests/fail/data_race/atomic_write_na_write_race2.rs +++ b/tests/fail/data_race/atomic_write_na_write_race2.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; diff --git a/tests/fail/data_race/dangling_thread_async_race.rs b/tests/fail/data_race/dangling_thread_async_race.rs index 6264255265f6..af2588e92324 100644 --- a/tests/fail/data_race/dangling_thread_async_race.rs +++ b/tests/fail/data_race/dangling_thread_async_race.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::mem; use std::thread::{sleep, spawn}; diff --git a/tests/fail/data_race/dangling_thread_race.rs b/tests/fail/data_race/dangling_thread_race.rs index 6f44fc69dbb7..1ee619c3f99d 100644 --- a/tests/fail/data_race/dangling_thread_race.rs +++ b/tests/fail/data_race/dangling_thread_race.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::mem; use std::thread::{sleep, spawn}; diff --git a/tests/fail/data_race/dealloc_read_race1.rs b/tests/fail/data_race/dealloc_read_race1.rs index 5349073ec3b7..cbc02549a254 100644 --- a/tests/fail/data_race/dealloc_read_race1.rs +++ b/tests/fail/data_race/dealloc_read_race1.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_read_race2.rs b/tests/fail/data_race/dealloc_read_race2.rs index bb9070ef7503..24cce5d6fac1 100644 --- a/tests/fail/data_race/dealloc_read_race2.rs +++ b/tests/fail/data_race/dealloc_read_race2.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_read_race_stack.rs b/tests/fail/data_race/dealloc_read_race_stack.rs index e114fbb8b4f1..5484370f35c1 100644 --- a/tests/fail/data_race/dealloc_read_race_stack.rs +++ b/tests/fail/data_race/dealloc_read_race_stack.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::ptr::null_mut; diff --git a/tests/fail/data_race/dealloc_write_race1.rs b/tests/fail/data_race/dealloc_write_race1.rs index 35949920e102..23bf73fe8c5a 100644 --- a/tests/fail/data_race/dealloc_write_race1.rs +++ b/tests/fail/data_race/dealloc_write_race1.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_write_race2.rs b/tests/fail/data_race/dealloc_write_race2.rs index b569086c8c34..7c8033e2335e 100644 --- a/tests/fail/data_race/dealloc_write_race2.rs +++ b/tests/fail/data_race/dealloc_write_race2.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_write_race_stack.rs b/tests/fail/data_race/dealloc_write_race_stack.rs index 0c74c7adf59c..1872abfe021b 100644 --- a/tests/fail/data_race/dealloc_write_race_stack.rs +++ b/tests/fail/data_race/dealloc_write_race_stack.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::ptr::null_mut; diff --git a/tests/fail/data_race/enable_after_join_to_main.rs b/tests/fail/data_race/enable_after_join_to_main.rs index f2235b95257b..c11239da7feb 100644 --- a/tests/fail/data_race/enable_after_join_to_main.rs +++ b/tests/fail/data_race/enable_after_join_to_main.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/fence_after_load.rs b/tests/fail/data_race/fence_after_load.rs index 8acbe12e82d6..ae443908598f 100644 --- a/tests/fail/data_race/fence_after_load.rs +++ b/tests/fail/data_race/fence_after_load.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::{fence, AtomicUsize, Ordering}; use std::sync::Arc; use std::thread; diff --git a/tests/fail/data_race/read_write_race.rs b/tests/fail/data_race/read_write_race.rs index cff868fb699f..482dd2df7df9 100644 --- a/tests/fail/data_race/read_write_race.rs +++ b/tests/fail/data_race/read_write_race.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/read_write_race_stack.rs b/tests/fail/data_race/read_write_race_stack.rs index b22173fa5a94..1b4932439b01 100644 --- a/tests/fail/data_race/read_write_race_stack.rs +++ b/tests/fail/data_race/read_write_race_stack.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 // Note: mir-opt-level set to 0 to prevent the read of stack_var in thread 1 diff --git a/tests/fail/data_race/relax_acquire_race.rs b/tests/fail/data_race/relax_acquire_race.rs index b99388b8923c..240b4c90eb22 100644 --- a/tests/fail/data_race/relax_acquire_race.rs +++ b/tests/fail/data_race/relax_acquire_race.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/release_seq_race.rs b/tests/fail/data_race/release_seq_race.rs index 31fc5d9a479f..5ae801278357 100644 --- a/tests/fail/data_race/release_seq_race.rs +++ b/tests/fail/data_race/release_seq_race.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/release_seq_race_same_thread.rs b/tests/fail/data_race/release_seq_race_same_thread.rs index c0ce437047a8..63e6dc2dd71b 100644 --- a/tests/fail/data_race/release_seq_race_same_thread.rs +++ b/tests/fail/data_race/release_seq_race_same_thread.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/rmw_race.rs b/tests/fail/data_race/rmw_race.rs index 540b01b0935d..122780d11aa1 100644 --- a/tests/fail/data_race/rmw_race.rs +++ b/tests/fail/data_race/rmw_race.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/write_write_race.rs b/tests/fail/data_race/write_write_race.rs index ac75c771e475..13c31c87cbba 100644 --- a/tests/fail/data_race/write_write_race.rs +++ b/tests/fail/data_race/write_write_race.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/write_write_race_stack.rs b/tests/fail/data_race/write_write_race_stack.rs index 5193b155512c..731ac8b26aa7 100644 --- a/tests/fail/data_race/write_write_race_stack.rs +++ b/tests/fail/data_race/write_write_race_stack.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::ptr::null_mut; diff --git a/tests/fail/should-pass/cpp20_rwc_syncs.rs b/tests/fail/should-pass/cpp20_rwc_syncs.rs index 6a7622671b59..545875a582a4 100644 --- a/tests/fail/should-pass/cpp20_rwc_syncs.rs +++ b/tests/fail/should-pass/cpp20_rwc_syncs.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-ignore-leaks // https://plv.mpi-sws.org/scfix/paper.pdf diff --git a/tests/fail/weak_memory/racing_mixed_size.rs b/tests/fail/weak_memory/racing_mixed_size.rs index 95a10510713c..7bbb7f9fe7c2 100644 --- a/tests/fail/weak_memory/racing_mixed_size.rs +++ b/tests/fail/weak_memory/racing_mixed_size.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] diff --git a/tests/fail/weak_memory/racing_mixed_size_read.rs b/tests/fail/weak_memory/racing_mixed_size_read.rs index 1c0b1c2be8fd..73178980b7e5 100644 --- a/tests/fail/weak_memory/racing_mixed_size_read.rs +++ b/tests/fail/weak_memory/racing_mixed_size_read.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::Ordering::*; use std::sync::atomic::{AtomicU16, AtomicU32}; diff --git a/tests/pass/0weak_memory_consistency.rs b/tests/pass/0weak_memory_consistency.rs index b5b6b83cce1b..8c650bca2f36 100644 --- a/tests/pass/0weak_memory_consistency.rs +++ b/tests/pass/0weak_memory_consistency.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows // The following tests check whether our weak memory emulation produces diff --git a/tests/pass/concurrency/channels.rs b/tests/pass/concurrency/channels.rs index 40d729f042d1..c75c5199bf11 100644 --- a/tests/pass/concurrency/channels.rs +++ b/tests/pass/concurrency/channels.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Channels on Windows are not supported yet. //@compile-flags: -Zmiri-strict-provenance use std::sync::mpsc::{channel, sync_channel}; diff --git a/tests/pass/concurrency/concurrent_caller_location.rs b/tests/pass/concurrency/concurrent_caller_location.rs index a07f6b13e6d7..0490330a15d8 100644 --- a/tests/pass/concurrency/concurrent_caller_location.rs +++ b/tests/pass/concurrency/concurrent_caller_location.rs @@ -1,5 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. - use std::panic::Location; use std::thread::spawn; diff --git a/tests/pass/concurrency/data_race.rs b/tests/pass/concurrency/data_race.rs index 9c7030db3db8..4e3c99058a0d 100644 --- a/tests/pass/concurrency/data_race.rs +++ b/tests/pass/concurrency/data_race.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::sync::atomic::{fence, AtomicUsize, Ordering}; diff --git a/tests/pass/concurrency/disable_data_race_detector.rs b/tests/pass/concurrency/disable_data_race_detector.rs index a4852b4674e8..d71e51b03842 100644 --- a/tests/pass/concurrency/disable_data_race_detector.rs +++ b/tests/pass/concurrency/disable_data_race_detector.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-data-race-detector use std::thread::spawn; diff --git a/tests/pass/concurrency/issue1643.rs b/tests/pass/concurrency/issue1643.rs index f4fe43d88cb1..c0956569ad8f 100644 --- a/tests/pass/concurrency/issue1643.rs +++ b/tests/pass/concurrency/issue1643.rs @@ -1,5 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. - use std::thread::spawn; fn initialize() { diff --git a/tests/pass/concurrency/simple.rs b/tests/pass/concurrency/simple.rs index 1d85c7fc9bd0..556e0a24769d 100644 --- a/tests/pass/concurrency/simple.rs +++ b/tests/pass/concurrency/simple.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-strict-provenance use std::thread; diff --git a/tests/pass/concurrency/spin_loop.rs b/tests/pass/concurrency/spin_loop.rs index 5f34168dbb1e..019bd44f1648 100644 --- a/tests/pass/concurrency/spin_loop.rs +++ b/tests/pass/concurrency/spin_loop.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread; diff --git a/tests/pass/concurrency/spin_loops_nopreempt.rs b/tests/pass/concurrency/spin_loops_nopreempt.rs index 34be0dd39481..5d8e2ef5f028 100644 --- a/tests/pass/concurrency/spin_loops_nopreempt.rs +++ b/tests/pass/concurrency/spin_loops_nopreempt.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Channels on Windows are not supported yet. // This specifically tests behavior *without* preemption. //@compile-flags: -Zmiri-preemption-rate=0 diff --git a/tests/pass/concurrency/thread_locals.rs b/tests/pass/concurrency/thread_locals.rs index 34431def33f8..b19e56312f30 100644 --- a/tests/pass/concurrency/thread_locals.rs +++ b/tests/pass/concurrency/thread_locals.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-strict-provenance //! The main purpose of this test is to check that if we take a pointer to diff --git a/tests/pass/concurrency/tls_lib_drop.rs b/tests/pass/concurrency/tls_lib_drop.rs index 6c66cd3a62fb..8ce011ede34e 100644 --- a/tests/pass/concurrency/tls_lib_drop.rs +++ b/tests/pass/concurrency/tls_lib_drop.rs @@ -1,5 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. - use std::cell::RefCell; use std::thread; diff --git a/tests/pass/panic/concurrent-panic.rs b/tests/pass/panic/concurrent-panic.rs index 1acae69b8d3b..342269c6acbe 100644 --- a/tests/pass/panic/concurrent-panic.rs +++ b/tests/pass/panic/concurrent-panic.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Condvars on Windows are not supported yet. // We are making scheduler assumptions here. //@compile-flags: -Zmiri-preemption-rate=0 diff --git a/tests/pass/shims/time.rs b/tests/pass/shims/time.rs index e1094006fb1f..23b5ab57efa0 100644 --- a/tests/pass/shims/time.rs +++ b/tests/pass/shims/time.rs @@ -8,8 +8,6 @@ fn duration_sanity(diff: Duration) { assert!(diff.as_millis() < 500); } -// Sleeping on Windows is not supported yet. -#[cfg(unix)] fn test_sleep() { let before = Instant::now(); std::thread::sleep(Duration::from_millis(100)); @@ -50,6 +48,5 @@ fn main() { assert_eq!(now2 - diff, now1); duration_sanity(diff); - #[cfg(unix)] test_sleep(); } diff --git a/tests/pass/threadleak_ignored.rs b/tests/pass/threadleak_ignored.rs index 077d8d083753..99bac7aa42a8 100644 --- a/tests/pass/threadleak_ignored.rs +++ b/tests/pass/threadleak_ignored.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Channels on Windows are not supported yet. // FIXME: disallow preemption to work around https://github.com/rust-lang/rust/issues/55005 //@compile-flags: -Zmiri-ignore-leaks -Zmiri-preemption-rate=0 diff --git a/tests/pass/weak_memory/extra_cpp.rs b/tests/pass/weak_memory/extra_cpp.rs index d98fba26ffa8..07cbb4a803f1 100644 --- a/tests/pass/weak_memory/extra_cpp.rs +++ b/tests/pass/weak_memory/extra_cpp.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-ignore-leaks // Tests operations not perfomable through C++'s atomic API diff --git a/tests/pass/weak_memory/extra_cpp_unsafe.rs b/tests/pass/weak_memory/extra_cpp_unsafe.rs index f5c6021a4a85..f7e2748408ff 100644 --- a/tests/pass/weak_memory/extra_cpp_unsafe.rs +++ b/tests/pass/weak_memory/extra_cpp_unsafe.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-ignore-leaks // Tests operations not perfomable through C++'s atomic API diff --git a/tests/pass/weak_memory/weak.rs b/tests/pass/weak_memory/weak.rs index dc7982991b69..4c3be6b3559a 100644 --- a/tests/pass/weak_memory/weak.rs +++ b/tests/pass/weak_memory/weak.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-ignore-leaks -Zmiri-preemption-rate=0 // Tests showing weak memory behaviours are exhibited. All tests From 08ffbb8d8ad5a65825a458982981222bccf951b7 Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Fri, 15 Jul 2022 01:40:06 -0700 Subject: [PATCH 3755/5092] fix windows join/detach and add tests --- src/machine.rs | 1 + src/shims/time.rs | 26 ++++++++++++ src/shims/unix/thread.rs | 4 +- src/shims/windows/dlsym.rs | 4 +- src/shims/windows/foreign_items.rs | 19 +-------- src/shims/windows/handle.rs | 15 ++++--- src/shims/windows/thread.rs | 25 ++++------- src/thread.rs | 34 +++++++++++++++ tests/fail/concurrency/unwind_top_of_stack.rs | 2 +- .../fail/concurrency/windows_join_detached.rs | 21 ++++++++++ .../concurrency/windows_join_detached.stderr | 22 ++++++++++ tests/fail/concurrency/windows_join_main.rs | 28 +++++++++++++ .../fail/concurrency/windows_join_main.stderr | 12 ++++++ tests/fail/concurrency/windows_join_self.rs | 25 +++++++++++ .../fail/concurrency/windows_join_self.stderr | 12 ++++++ .../concurrency/windows_detach_terminated.rs | 21 ++++++++++ .../pass/concurrency/windows_join_multiple.rs | 41 +++++++++++++++++++ 17 files changed, 265 insertions(+), 47 deletions(-) create mode 100644 tests/fail/concurrency/windows_join_detached.rs create mode 100644 tests/fail/concurrency/windows_join_detached.stderr create mode 100644 tests/fail/concurrency/windows_join_main.rs create mode 100644 tests/fail/concurrency/windows_join_main.stderr create mode 100644 tests/fail/concurrency/windows_join_self.rs create mode 100644 tests/fail/concurrency/windows_join_self.stderr create mode 100644 tests/pass/concurrency/windows_detach_terminated.rs create mode 100644 tests/pass/concurrency/windows_join_multiple.rs diff --git a/src/machine.rs b/src/machine.rs index 4ebf7dceab83..943d5570f7b7 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -418,6 +418,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { ) -> InterpResult<'tcx> { EnvVars::init(this, config)?; Evaluator::init_extern_statics(this)?; + ThreadManager::init(this); Ok(()) } diff --git a/src/shims/time.rs b/src/shims/time.rs index c3eb0161c210..e495f723668d 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -233,4 +233,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } + + #[allow(non_snake_case)] + fn Sleep(&mut self, timeout: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + this.check_no_isolation("`Sleep`")?; + + let timeout_ms = this.read_scalar(timeout)?.to_u32()?; + + let duration = Duration::from_millis(timeout_ms.into()); + let timeout_time = Time::Monotonic(Instant::now().checked_add(duration).unwrap()); + + let active_thread = this.get_active_thread(); + this.block_thread(active_thread); + + this.register_timeout_callback( + active_thread, + timeout_time, + Box::new(move |ecx| { + ecx.unblock_thread(active_thread); + Ok(()) + }), + ); + + Ok(()) + } } diff --git a/src/shims/unix/thread.rs b/src/shims/unix/thread.rs index 094183b3e781..d675df0f53f1 100644 --- a/src/shims/unix/thread.rs +++ b/src/shims/unix/thread.rs @@ -37,7 +37,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let thread_id = this.read_scalar(thread)?.to_machine_usize(this)?; - this.join_thread(thread_id.try_into().expect("thread ID should fit in u32"))?; + this.join_thread_exclusive(thread_id.try_into().expect("thread ID should fit in u32"))?; Ok(0) } @@ -46,7 +46,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let thread_id = this.read_scalar(thread)?.to_machine_usize(this)?; - this.detach_thread(thread_id.try_into().expect("thread ID should fit in u32"))?; + this.detach_thread(thread_id.try_into().expect("thread ID should fit in u32"), false)?; Ok(0) } diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index f18e27d38c2b..d64be9cc0527 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -5,7 +5,7 @@ use rustc_target::spec::abi::Abi; use log::trace; use crate::helpers::check_arg_count; -use crate::shims::windows::handle::Handle; +use crate::shims::windows::handle::{EvalContextExt as _, Handle}; use crate::*; #[derive(Debug, Copy, Clone)] @@ -118,7 +118,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match Handle::from_scalar(this.read_scalar(handle)?.check_init()?, this)? { Some(Handle::Thread(thread)) => thread, Some(Handle::CurrentThread) => this.get_active_thread(), - _ => throw_ub_format!("invalid handle"), + _ => this.invalid_handle("SetThreadDescription")?, }; this.set_thread_name_wide(thread, name); diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 00a80f869751..6014281100fc 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -228,24 +228,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [timeout] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - this.check_no_isolation("`Sleep`")?; - - let timeout_ms = this.read_scalar(timeout)?.to_u32()?; - - let duration = Duration::from_millis(timeout_ms as u64); - let timeout_time = Time::Monotonic(Instant::now().checked_add(duration).unwrap()); - - let active_thread = this.get_active_thread(); - this.block_thread(active_thread); - - this.register_timeout_callback( - active_thread, - timeout_time, - Box::new(move |ecx| { - ecx.unblock_thread(active_thread); - Ok(()) - }), - ); + this.Sleep(timeout)?; } // Synchronization primitives diff --git a/src/shims/windows/handle.rs b/src/shims/windows/handle.rs index ff64a958da3e..e1617ae6a8d9 100644 --- a/src/shims/windows/handle.rs +++ b/src/shims/windows/handle.rs @@ -146,16 +146,19 @@ impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tc #[allow(non_snake_case)] pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn invalid_handle(&mut self, function_name: &str) -> InterpResult<'tcx, !> { + throw_machine_stop!(TerminationInfo::Abort(format!( + "invalid handle passed to `{function_name}`" + ))) + } + fn CloseHandle(&mut self, handle_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); match Handle::from_scalar(this.read_scalar(handle_op)?.check_init()?, this)? { - Some(Handle::Thread(thread)) => this.detach_thread(thread)?, - _ => - throw_machine_stop!(TerminationInfo::Abort( - "invalid handle passed to `CloseHandle`".into() - )), - }; + Some(Handle::Thread(thread)) => this.detach_thread(thread, true)?, + _ => this.invalid_handle("CloseHandle")?, + } Ok(()) } diff --git a/src/shims/windows/thread.rs b/src/shims/windows/thread.rs index 66cd9dd0348f..6b6c4916dee2 100644 --- a/src/shims/windows/thread.rs +++ b/src/shims/windows/thread.rs @@ -1,11 +1,8 @@ -use std::time::{Duration, Instant}; - use rustc_middle::ty::layout::LayoutOf; use rustc_target::spec::abi::Abi; -use crate::thread::Time; use crate::*; -use shims::windows::handle::Handle; +use shims::windows::handle::{EvalContextExt as _, Handle}; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -59,25 +56,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let thread = match Handle::from_scalar(this.read_scalar(handle)?.check_init()?, this)? { Some(Handle::Thread(thread)) => thread, - Some(Handle::CurrentThread) => throw_ub_format!("trying to wait on itself"), - _ => throw_ub_format!("invalid handle"), + // Unlike on posix, joining the current thread is not UB on windows. + // It will just deadlock. + Some(Handle::CurrentThread) => this.get_active_thread(), + _ => this.invalid_handle("WaitForSingleObject")?, }; if this.read_scalar(timeout)?.to_u32()? != this.eval_windows("c", "INFINITE")?.to_u32()? { - this.check_no_isolation("`WaitForSingleObject` with non-infinite timeout")?; + throw_unsup_format!("`WaitForSingleObject` with non-infinite timeout"); } - let timeout_ms = this.read_scalar(timeout)?.to_u32()?; - - let timeout_time = if timeout_ms == this.eval_windows("c", "INFINITE")?.to_u32()? { - None - } else { - let duration = Duration::from_millis(timeout_ms as u64); - - Some(Time::Monotonic(Instant::now().checked_add(duration).unwrap())) - }; - - this.wait_on_thread(timeout_time, thread)?; + this.join_thread(thread)?; Ok(()) } diff --git a/src/thread.rs b/src/thread.rs index fa70dcfa2a3d..f7fcdd5822a2 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -405,6 +405,31 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { Ok(()) } + /// Mark that the active thread tries to exclusively join the thread with `joined_thread_id`. + /// If the thread is already joined by another thread + fn join_thread_exclusive( + &mut self, + joined_thread_id: ThreadId, + data_race: Option<&mut data_race::GlobalState>, + ) -> InterpResult<'tcx> { + if self.threads[joined_thread_id].join_status == ThreadJoinStatus::Joined { + throw_ub_format!("trying to join an already joined thread"); + } + + if joined_thread_id == self.active_thread { + throw_ub_format!("trying to join itself"); + } + + assert!( + self.threads + .iter() + .all(|thread| thread.state != ThreadState::BlockedOnJoin(joined_thread_id)), + "a joinable thread already has threads waiting for its termination" + ); + + self.join_thread(joined_thread_id, data_race) + } + /// Set the name of the given thread. pub fn set_thread_name(&mut self, thread: ThreadId, new_thread_name: Vec) { self.threads[thread].thread_name = Some(new_thread_name); @@ -700,6 +725,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } + #[inline] + fn join_thread_exclusive(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + this.machine + .threads + .join_thread_exclusive(joined_thread_id, this.machine.data_race.as_mut())?; + Ok(()) + } + #[inline] fn set_active_thread(&mut self, thread_id: ThreadId) -> ThreadId { let this = self.eval_context_mut(); diff --git a/tests/fail/concurrency/unwind_top_of_stack.rs b/tests/fail/concurrency/unwind_top_of_stack.rs index 61d3b964e620..4704cfed0393 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.rs +++ b/tests/fail/concurrency/unwind_top_of_stack.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows //@compile-flags: -Zmiri-disable-abi-check diff --git a/tests/fail/concurrency/windows_join_detached.rs b/tests/fail/concurrency/windows_join_detached.rs new file mode 100644 index 000000000000..548ed63534db --- /dev/null +++ b/tests/fail/concurrency/windows_join_detached.rs @@ -0,0 +1,21 @@ +//@only-target-windows: Uses win32 api functions +//@error-pattern: Undefined Behavior: trying to join a detached thread + +// Joining a detached thread is undefined behavior. + +use std::os::windows::io::{AsRawHandle, RawHandle}; +use std::thread; + +extern "system" { + fn CloseHandle(handle: RawHandle) -> u32; +} + +fn main() { + let thread = thread::spawn(|| ()); + + unsafe { + assert_ne!(CloseHandle(thread.as_raw_handle()), 0); + } + + thread.join().unwrap(); +} diff --git a/tests/fail/concurrency/windows_join_detached.stderr b/tests/fail/concurrency/windows_join_detached.stderr new file mode 100644 index 000000000000..a0e85f6ce5ab --- /dev/null +++ b/tests/fail/concurrency/windows_join_detached.stderr @@ -0,0 +1,22 @@ +error: Undefined Behavior: trying to join a detached thread + --> RUSTLIB/std/src/sys/PLATFORM/thread.rs:LL:CC + | +LL | let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached thread + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: backtrace: + = note: inside `std::sys::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/PLATFORM/thread.rs:LL:CC + = note: inside `std::thread::JoinInner::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC + = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC +note: inside `main` at $DIR/windows_join_detached.rs:LL:CC + --> $DIR/windows_join_detached.rs:LL:CC + | +LL | thread.join().unwrap(); + | ^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/concurrency/windows_join_main.rs b/tests/fail/concurrency/windows_join_main.rs new file mode 100644 index 000000000000..ea52220d4499 --- /dev/null +++ b/tests/fail/concurrency/windows_join_main.rs @@ -0,0 +1,28 @@ +//@only-target-windows: Uses win32 api functions +// We are making scheduler assumptions here. +//@compile-flags: -Zmiri-preemption-rate=0 + +// On windows, joining main is not UB, but it will block a thread forever. + +use std::thread; + +extern "system" { + fn WaitForSingleObject(handle: usize, timeout: u32) -> u32; +} + +const INFINITE: u32 = u32::MAX; + +// This is how miri represents the handle for thread 0. +// This value can be "legitimately" obtained by using `GetCurrentThread` with `DuplicateHandle` +// but miri does not implement `DuplicateHandle` yet. +const MAIN_THREAD: usize = 1 << 30; + +fn main() { + thread::spawn(|| { + unsafe { + assert_eq!(WaitForSingleObject(MAIN_THREAD, INFINITE), 0); //~ ERROR: deadlock: the evaluated program deadlocked + } + }) + .join() + .unwrap(); +} diff --git a/tests/fail/concurrency/windows_join_main.stderr b/tests/fail/concurrency/windows_join_main.stderr new file mode 100644 index 000000000000..72b854d354a3 --- /dev/null +++ b/tests/fail/concurrency/windows_join_main.stderr @@ -0,0 +1,12 @@ +error: deadlock: the evaluated program deadlocked + --> $DIR/windows_join_main.rs:LL:CC + | +LL | WaitForSingleObject(MAIN_THREAD, INFINITE); + | ^ the evaluated program deadlocked + | + = note: inside closure at $DIR/windows_join_main.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/concurrency/windows_join_self.rs b/tests/fail/concurrency/windows_join_self.rs new file mode 100644 index 000000000000..d9bbf66a7dca --- /dev/null +++ b/tests/fail/concurrency/windows_join_self.rs @@ -0,0 +1,25 @@ +//@only-target-windows: Uses win32 api functions +// We are making scheduler assumptions here. +//@compile-flags: -Zmiri-preemption-rate=0 + +// On windows, a thread joining itself is not UB, but it will deadlock. + +use std::thread; + +extern "system" { + fn GetCurrentThread() -> usize; + fn WaitForSingleObject(handle: usize, timeout: u32) -> u32; +} + +const INFINITE: u32 = u32::MAX; + +fn main() { + thread::spawn(|| { + unsafe { + let native = GetCurrentThread(); + assert_eq!(WaitForSingleObject(native, INFINITE), 0); //~ ERROR: deadlock: the evaluated program deadlocked + } + }) + .join() + .unwrap(); +} diff --git a/tests/fail/concurrency/windows_join_self.stderr b/tests/fail/concurrency/windows_join_self.stderr new file mode 100644 index 000000000000..bbec3f7257ec --- /dev/null +++ b/tests/fail/concurrency/windows_join_self.stderr @@ -0,0 +1,12 @@ +error: deadlock: the evaluated program deadlocked + --> $DIR/windows_join_self.rs:LL:CC + | +LL | assert_eq!(WaitForSingleObject(native, INFINITE), 0); + | ^ the evaluated program deadlocked + | + = note: inside closure at $DIR/windows_join_self.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/pass/concurrency/windows_detach_terminated.rs b/tests/pass/concurrency/windows_detach_terminated.rs new file mode 100644 index 000000000000..91088ce6aef9 --- /dev/null +++ b/tests/pass/concurrency/windows_detach_terminated.rs @@ -0,0 +1,21 @@ +//@only-target-windows: Uses win32 api functions +// We are making scheduler assumptions here. +//@compile-flags: -Zmiri-preemption-rate=0 + +use std::os::windows::io::IntoRawHandle; +use std::thread; + +extern "system" { + fn CloseHandle(handle: usize) -> i32; +} + +fn main() { + let thread = thread::spawn(|| {}).into_raw_handle() as usize; + + // this yield ensures that `thread` is terminated by this point + thread::yield_now(); + + unsafe { + assert_ne!(CloseHandle(thread), 0); + } +} diff --git a/tests/pass/concurrency/windows_join_multiple.rs b/tests/pass/concurrency/windows_join_multiple.rs new file mode 100644 index 000000000000..986e2b8cc10f --- /dev/null +++ b/tests/pass/concurrency/windows_join_multiple.rs @@ -0,0 +1,41 @@ +//@only-target-windows: Uses win32 api functions +// We are making scheduler assumptions here. +//@compile-flags: -Zmiri-preemption-rate=0 + +use std::os::windows::io::IntoRawHandle; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::thread; + +extern "system" { + fn WaitForSingleObject(handle: usize, timeout: u32) -> u32; +} + +const INFINITE: u32 = u32::MAX; + +fn main() { + static FLAG: AtomicBool = AtomicBool::new(false); + + let blocker = thread::spawn(|| { + while !FLAG.load(Ordering::Relaxed) { + thread::yield_now(); + } + }) + .into_raw_handle() as usize; + + let waiter = move || { + unsafe { + assert_eq!(WaitForSingleObject(blocker, INFINITE), 0); + } + }; + + let waiter1 = thread::spawn(waiter); + let waiter2 = thread::spawn(waiter); + + // this yield ensures `waiter1` & `waiter2` are blocked on `blocker` by this point + thread::yield_now(); + + FLAG.store(true, Ordering::Relaxed); + + waiter1.join().unwrap(); + waiter2.join().unwrap(); +} From 9f69c41c5fc0e876c75927cbc3ef7a5eff481ecc Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Sat, 16 Jul 2022 00:36:11 -0700 Subject: [PATCH 3756/5092] rewrite handle impl again --- src/shims/windows/dlsym.rs | 15 +- src/shims/windows/foreign_items.rs | 9 +- src/shims/windows/handle.rs | 139 +++++++++--------- src/shims/windows/thread.rs | 4 +- tests/fail/concurrency/windows_join_main.rs | 4 +- .../fail/concurrency/windows_join_main.stderr | 7 +- 6 files changed, 90 insertions(+), 88 deletions(-) diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index d64be9cc0527..fc36913638e0 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -5,7 +5,7 @@ use rustc_target::spec::abi::Abi; use log::trace; use crate::helpers::check_arg_count; -use crate::shims::windows::handle::{EvalContextExt as _, Handle}; +use crate::shims::windows::handle::{EvalContextExt as _, Handle, PseudoHandle}; use crate::*; #[derive(Debug, Copy, Clone)] @@ -112,14 +112,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Dlsym::SetThreadDescription => { let [handle, name] = check_arg_count(args)?; + let handle = this.read_scalar(handle)?.check_init()?; + let name = this.read_wide_str(this.read_pointer(name)?)?; - let thread = - match Handle::from_scalar(this.read_scalar(handle)?.check_init()?, this)? { - Some(Handle::Thread(thread)) => thread, - Some(Handle::CurrentThread) => this.get_active_thread(), - _ => this.invalid_handle("SetThreadDescription")?, - }; + let thread = match Handle::from_scalar(handle, this)? { + Some(Handle::Thread(thread)) => thread, + Some(Handle::Pseudo(PseudoHandle::CurrentThread)) => this.get_active_thread(), + _ => this.invalid_handle("SetThreadDescription")?, + }; this.set_thread_name_wide(thread, name); diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 6014281100fc..cc030ec3d0cf 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -1,14 +1,12 @@ use std::iter; -use std::time::{Duration, Instant}; use rustc_span::Symbol; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; -use crate::thread::Time; use crate::*; use shims::foreign_items::EmulateByNameResult; -use shims::windows::handle::{EvalContextExt as _, Handle}; +use shims::windows::handle::{EvalContextExt as _, Handle, PseudoHandle}; use shims::windows::sync::EvalContextExt as _; use shims::windows::thread::EvalContextExt as _; @@ -373,7 +371,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "GetCurrentThread" => { let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - this.write_scalar(Handle::CurrentThread.to_scalar(this), dest)?; + this.write_scalar( + Handle::Pseudo(PseudoHandle::CurrentThread).to_scalar(this), + dest, + )?; } // Incomplete shims that we "stub out" just to get pre-main initialization code to work. diff --git a/src/shims/windows/handle.rs b/src/shims/windows/handle.rs index e1617ae6a8d9..041033717e44 100644 --- a/src/shims/windows/handle.rs +++ b/src/shims/windows/handle.rs @@ -3,44 +3,79 @@ use std::mem::variant_count; use crate::*; -/// A Windows `HANDLE` that represents a resource instead of being null or a pseudohandle. -/// -/// This is a seperate type from [`Handle`] to simplify the packing and unpacking code. -#[derive(Clone, Copy)] -enum RealHandle { +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum PseudoHandle { + CurrentThread, +} + +impl PseudoHandle { + const CURRENT_THREAD_VALUE: u32 = 0; + + fn value(self) -> u32 { + match self { + Self::CurrentThread => Self::CURRENT_THREAD_VALUE, + } + } + + fn from_value(value: u32) -> Option { + match value { + Self::CURRENT_THREAD_VALUE => Some(Self::CurrentThread), + _ => None, + } + } +} + +/// Miri representation of a Windows `HANDLE` +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum Handle { + Null, + Pseudo(PseudoHandle), Thread(ThreadId), } -impl RealHandle { - const USABLE_BITS: u32 = 31; - - const THREAD_DISCRIMINANT: u32 = 1; +impl Handle { + const NULL_DISCRIMINANT: u32 = 0; + const PSEUDO_DISCRIMINANT: u32 = 1; + const THREAD_DISCRIMINANT: u32 = 2; fn discriminant(self) -> u32 { match self { - // can't use zero here because all zero handle is invalid + Self::Null => Self::NULL_DISCRIMINANT, + Self::Pseudo(_) => Self::PSEUDO_DISCRIMINANT, Self::Thread(_) => Self::THREAD_DISCRIMINANT, } } fn data(self) -> u32 { match self { + Self::Null => 0, + Self::Pseudo(pseudo_handle) => pseudo_handle.value(), Self::Thread(thread) => thread.to_u32(), } } fn packed_disc_size() -> u32 { - // log2(x) + 1 is how many bits it takes to store x - // because the discriminants start at 1, the variant count is equal to the highest discriminant - variant_count::().ilog2() + 1 + // ceil(log2(x)) is how many bits it takes to store x numbers + let variant_count = variant_count::(); + + // however, std's ilog2 is floor(log2(x)) + let floor_log2 = variant_count.ilog2(); + + // we need to add one for non powers of two to compensate for the difference + let ceil_log2 = if variant_count.is_power_of_two() { floor_log2 } else { floor_log2 + 1 }; + + ceil_log2 } - /// This function packs the discriminant and data values into a 31-bit space. + /// Converts a handle into its machine representation. + /// + /// The upper [`Self::packed_disc_size()`] bits are used to store a discriminant corresponding to the handle variant. + /// The remaining bits are used for the variant's field. + /// /// None of this layout is guaranteed to applications by Windows or Miri. - /// The sign bit is not used to avoid overlapping any pseudo-handles. - fn to_packed(self) -> i32 { + fn to_packed(self) -> u32 { let disc_size = Self::packed_disc_size(); - let data_size = Self::USABLE_BITS - disc_size; + let data_size = u32::BITS - disc_size; let discriminant = self.discriminant(); let data = self.data(); @@ -53,90 +88,54 @@ impl RealHandle { // packs the data into the lower `data_size` bits // and packs the discriminant right above the data - (discriminant << data_size | data) as i32 + discriminant << data_size | data } fn new(discriminant: u32, data: u32) -> Option { match discriminant { + Self::NULL_DISCRIMINANT if data == 0 => Some(Self::Null), + Self::PSEUDO_DISCRIMINANT => Some(Self::Pseudo(PseudoHandle::from_value(data)?)), Self::THREAD_DISCRIMINANT => Some(Self::Thread(data.into())), _ => None, } } /// see docs for `to_packed` - fn from_packed(handle: i32) -> Option { - let handle_bits = handle as u32; - + fn from_packed(handle: u32) -> Option { let disc_size = Self::packed_disc_size(); - let data_size = Self::USABLE_BITS - disc_size; + let data_size = u32::BITS - disc_size; // the lower `data_size` bits of this mask are 1 let data_mask = 2u32.pow(data_size) - 1; // the discriminant is stored right above the lower `data_size` bits - let discriminant = handle_bits >> data_size; + let discriminant = handle >> data_size; // the data is stored in the lower `data_size` bits - let data = handle_bits & data_mask; + let data = handle & data_mask; Self::new(discriminant, data) } -} - -/// Miri representation of a Windows `HANDLE` -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum Handle { - Null, // = 0 - - // pseudo-handles - // The lowest real windows pseudo-handle is -6, so miri pseduo-handles start at -7 to break code hardcoding these values - CurrentThread, // = -7 - - // real handles - Thread(ThreadId), -} - -impl Handle { - const CURRENT_THREAD_VALUE: i32 = -7; - - fn to_packed(self) -> i32 { - match self { - Self::Null => 0, - Self::CurrentThread => Self::CURRENT_THREAD_VALUE, - Self::Thread(thread) => RealHandle::Thread(thread).to_packed(), - } - } pub fn to_scalar(self, cx: &impl HasDataLayout) -> Scalar { // 64-bit handles are sign extended 32-bit handles // see https://docs.microsoft.com/en-us/windows/win32/winprog64/interprocess-communication - let handle = self.to_packed().into(); - - Scalar::from_machine_isize(handle, cx) - } - - fn from_packed(handle: i64) -> Option { - let current_thread_val = Self::CURRENT_THREAD_VALUE as i64; - - if handle == 0 { - Some(Self::Null) - } else if handle == current_thread_val { - Some(Self::CurrentThread) - } else if let Ok(handle) = handle.try_into() { - match RealHandle::from_packed(handle)? { - RealHandle::Thread(id) => Some(Self::Thread(id)), - } - } else { - // if a handle doesn't fit in an i32, it isn't valid. - None - } + let signed_handle = self.to_packed() as i32; + Scalar::from_machine_isize(signed_handle.into(), cx) } pub fn from_scalar<'tcx>( handle: Scalar, cx: &impl HasDataLayout, ) -> InterpResult<'tcx, Option> { - let handle = handle.to_machine_isize(cx)?; + let sign_extended_handle = handle.to_machine_isize(cx)?; + + let handle = if let Ok(signed_handle) = i32::try_from(sign_extended_handle) { + signed_handle as u32 + } else { + // if a handle doesn't fit in an i32, it isn't valid. + return Ok(None); + }; Ok(Self::from_packed(handle)) } diff --git a/src/shims/windows/thread.rs b/src/shims/windows/thread.rs index 6b6c4916dee2..08eb4ddba10c 100644 --- a/src/shims/windows/thread.rs +++ b/src/shims/windows/thread.rs @@ -2,7 +2,7 @@ use rustc_middle::ty::layout::LayoutOf; use rustc_target::spec::abi::Abi; use crate::*; -use shims::windows::handle::{EvalContextExt as _, Handle}; +use shims::windows::handle::{EvalContextExt as _, Handle, PseudoHandle}; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -58,7 +58,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(Handle::Thread(thread)) => thread, // Unlike on posix, joining the current thread is not UB on windows. // It will just deadlock. - Some(Handle::CurrentThread) => this.get_active_thread(), + Some(Handle::Pseudo(PseudoHandle::CurrentThread)) => this.get_active_thread(), _ => this.invalid_handle("WaitForSingleObject")?, }; diff --git a/tests/fail/concurrency/windows_join_main.rs b/tests/fail/concurrency/windows_join_main.rs index ea52220d4499..d3b54cdf156f 100644 --- a/tests/fail/concurrency/windows_join_main.rs +++ b/tests/fail/concurrency/windows_join_main.rs @@ -7,7 +7,7 @@ use std::thread; extern "system" { - fn WaitForSingleObject(handle: usize, timeout: u32) -> u32; + fn WaitForSingleObject(handle: isize, timeout: u32) -> u32; } const INFINITE: u32 = u32::MAX; @@ -15,7 +15,7 @@ const INFINITE: u32 = u32::MAX; // This is how miri represents the handle for thread 0. // This value can be "legitimately" obtained by using `GetCurrentThread` with `DuplicateHandle` // but miri does not implement `DuplicateHandle` yet. -const MAIN_THREAD: usize = 1 << 30; +const MAIN_THREAD: isize = (2i32 << 30) as isize; fn main() { thread::spawn(|| { diff --git a/tests/fail/concurrency/windows_join_main.stderr b/tests/fail/concurrency/windows_join_main.stderr index 72b854d354a3..ff0d074fa7d2 100644 --- a/tests/fail/concurrency/windows_join_main.stderr +++ b/tests/fail/concurrency/windows_join_main.stderr @@ -1,10 +1,11 @@ error: deadlock: the evaluated program deadlocked --> $DIR/windows_join_main.rs:LL:CC | -LL | WaitForSingleObject(MAIN_THREAD, INFINITE); - | ^ the evaluated program deadlocked +LL | assert_eq!(WaitForSingleObject(MAIN_THREAD, INFINITE), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program deadlocked | - = note: inside closure at $DIR/windows_join_main.rs:LL:CC + = note: inside closure at RUSTLIB/core/src/macros/mod.rs:LL:CC + = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace From d34242e8f1c538a8b4e01100a273ef1c5d456abd Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Sun, 31 Jul 2022 17:15:15 -0700 Subject: [PATCH 3757/5092] fix various issues --- src/shims/os_str.rs | 2 +- src/shims/tls.rs | 5 +- src/shims/unix/thread.rs | 15 +- src/shims/windows/dlsym.rs | 2 +- src/shims/windows/foreign_items.rs | 25 +-- src/shims/windows/handle.rs | 29 +-- src/shims/windows/thread.rs | 48 +++-- src/thread.rs | 23 ++- .../libc_pthread_join_detached.stderr | 6 +- .../concurrency/libc_pthread_join_joined.rs | 2 +- .../libc_pthread_join_joined.stderr | 6 +- .../concurrency/libc_pthread_join_main.rs | 2 +- .../concurrency/libc_pthread_join_main.stderr | 6 +- .../concurrency/libc_pthread_join_multiple.rs | 2 +- .../libc_pthread_join_multiple.stderr | 4 +- tests/fail/concurrency/windows_join_main.rs | 2 +- tests/pass/concurrency/tls_lib_drop.rs | 2 + .../pass/concurrency/tls_lib_drop_windows.rs | 191 ++++++++++++++++++ .../concurrency/tls_lib_drop_windows.stdout | 5 + 19 files changed, 306 insertions(+), 71 deletions(-) create mode 100644 tests/pass/concurrency/tls_lib_drop_windows.rs create mode 100644 tests/pass/concurrency/tls_lib_drop_windows.stdout diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index f99e2d174b53..fcf92dfc9f93 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -74,7 +74,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx 'mir: 'a, { #[cfg(windows)] - pub fn u16vec_to_osstring<'tcx, 'a>(u16_vec: Vec) -> InterpResult<'tcx, OsString> { + pub fn u16vec_to_osstring<'tcx>(u16_vec: Vec) -> InterpResult<'tcx, OsString> { Ok(OsString::from_wide(&u16_vec[..])) } #[cfg(not(windows))] diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 8627d9a04479..a52054879811 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -244,10 +244,13 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.eval_windows("thread_local_key", "p_thread_callback")?.to_pointer(this)?; let thread_callback = this.get_ptr_fn(thread_callback)?.as_instance()?; - // Technically, the reason should be `DLL_PROCESS_DETACH` when the main thread exits but std ignores it. + // FIXME: Technically, the reason should be `DLL_PROCESS_DETACH` when the main thread exits + // but std treats both the same. let reason = this.eval_windows("c", "DLL_THREAD_DETACH")?; // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. + // FIXME: `h` should be a handle to the current module and what `pv` should be is unknown + // but both are ignored by std this.call_function( thread_callback, Abi::System { unwind: false }, diff --git a/src/shims/unix/thread.rs b/src/shims/unix/thread.rs index d675df0f53f1..9365ec9a21f4 100644 --- a/src/shims/unix/thread.rs +++ b/src/shims/unix/thread.rs @@ -13,11 +13,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + let thread_info_place = this.deref_operand(thread)?; + + let start_routine = this.read_pointer(start_routine)?; + + let func_arg = this.read_immediate(arg)?; + this.start_thread( - Some(thread), + Some(thread_info_place), start_routine, Abi::C { unwind: false }, - arg, + func_arg, this.layout_of(this.tcx.types.usize)?, )?; @@ -46,7 +52,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let thread_id = this.read_scalar(thread)?.to_machine_usize(this)?; - this.detach_thread(thread_id.try_into().expect("thread ID should fit in u32"), false)?; + this.detach_thread( + thread_id.try_into().expect("thread ID should fit in u32"), + /*allow_terminated_joined*/ false, + )?; Ok(0) } diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index fc36913638e0..4c5e7a9b3138 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -122,7 +122,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => this.invalid_handle("SetThreadDescription")?, }; - this.set_thread_name_wide(thread, name); + this.set_thread_name_wide(thread, &name); this.write_null(dest)?; } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index cc030ec3d0cf..d853f3084d49 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -323,15 +323,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: we should set last_error, but to what? this.write_null(dest)?; } - // this is only callable from std because we know that std ignores the return value - "SwitchToThread" if this.frame_in_std() => { - let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - - this.yield_active_thread(); - - // FIXME: this should return a nonzero value if this call does result in switching to another thread. - this.write_null(dest)?; - } "GetStdHandle" => { let [which] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; @@ -339,6 +330,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We just make this the identity function, so we know later in `NtWriteFile` which // one it is. This is very fake, but libtest needs it so we cannot make it a // std-only shim. + // FIXME: this should return real HANDLEs when io support is added this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?; } "CloseHandle" => { @@ -364,9 +356,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [handle, timeout] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - this.WaitForSingleObject(handle, timeout)?; - - this.write_scalar(Scalar::from_u32(0), dest)?; + let ret = this.WaitForSingleObject(handle, timeout)?; + this.write_scalar(Scalar::from_u32(ret), dest)?; } "GetCurrentThread" => { let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; @@ -382,6 +373,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "GetProcessHeap" if this.frame_in_std() => { let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; // Just fake a HANDLE + // It's fine to not use the Handle type here because its a stub this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } "GetModuleHandleA" if this.frame_in_std() => { @@ -417,6 +409,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.GetCurrentProcessId()?; this.write_scalar(Scalar::from_u32(result), dest)?; } + // this is only callable from std because we know that std ignores the return value + "SwitchToThread" if this.frame_in_std() => { + let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + + this.yield_active_thread(); + + // FIXME: this should return a nonzero value if this call does result in switching to another thread. + this.write_null(dest)?; + } _ => return Ok(EmulateByNameResult::NotSupported), } diff --git a/src/shims/windows/handle.rs b/src/shims/windows/handle.rs index 041033717e44..443af1dfeaaa 100644 --- a/src/shims/windows/handle.rs +++ b/src/shims/windows/handle.rs @@ -8,6 +8,14 @@ pub enum PseudoHandle { CurrentThread, } +/// Miri representation of a Windows `HANDLE` +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum Handle { + Null, + Pseudo(PseudoHandle), + Thread(ThreadId), +} + impl PseudoHandle { const CURRENT_THREAD_VALUE: u32 = 0; @@ -25,14 +33,6 @@ impl PseudoHandle { } } -/// Miri representation of a Windows `HANDLE` -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum Handle { - Null, - Pseudo(PseudoHandle), - Thread(ThreadId), -} - impl Handle { const NULL_DISCRIMINANT: u32 = 0; const PSEUDO_DISCRIMINANT: u32 = 1; @@ -62,9 +62,7 @@ impl Handle { let floor_log2 = variant_count.ilog2(); // we need to add one for non powers of two to compensate for the difference - let ceil_log2 = if variant_count.is_power_of_two() { floor_log2 } else { floor_log2 + 1 }; - - ceil_log2 + if variant_count.is_power_of_two() { floor_log2 } else { floor_log2 + 1 } } /// Converts a handle into its machine representation. @@ -120,6 +118,7 @@ impl Handle { pub fn to_scalar(self, cx: &impl HasDataLayout) -> Scalar { // 64-bit handles are sign extended 32-bit handles // see https://docs.microsoft.com/en-us/windows/win32/winprog64/interprocess-communication + #[allow(clippy::cast_possible_wrap)] // we want it to wrap let signed_handle = self.to_packed() as i32; Scalar::from_machine_isize(signed_handle.into(), cx) } @@ -130,6 +129,7 @@ impl Handle { ) -> InterpResult<'tcx, Option> { let sign_extended_handle = handle.to_machine_isize(cx)?; + #[allow(clippy::cast_sign_loss)] // we want to lose the sign let handle = if let Ok(signed_handle) = i32::try_from(sign_extended_handle) { signed_handle as u32 } else { @@ -154,8 +154,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn CloseHandle(&mut self, handle_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - match Handle::from_scalar(this.read_scalar(handle_op)?.check_init()?, this)? { - Some(Handle::Thread(thread)) => this.detach_thread(thread, true)?, + let handle = this.read_scalar(handle_op)?.check_init()?; + + match Handle::from_scalar(handle, this)? { + Some(Handle::Thread(thread)) => + this.detach_thread(thread, /*allow_terminated_joined*/ true)?, _ => this.invalid_handle("CloseHandle")?, } diff --git a/src/shims/windows/thread.rs b/src/shims/windows/thread.rs index 08eb4ddba10c..06a5887d3e50 100644 --- a/src/shims/windows/thread.rs +++ b/src/shims/windows/thread.rs @@ -19,55 +19,71 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, ThreadId> { let this = self.eval_context_mut(); - if !this.ptr_is_null(this.read_pointer(security_op)?)? { - throw_unsup_format!("non-null `lpThreadAttributes` in `CreateThread`") - } + let security = this.read_pointer(security_op)?; // stacksize is ignored, but still needs to be a valid usize - let _ = this.read_scalar(stacksize_op)?.to_machine_usize(this)?; + this.read_scalar(stacksize_op)?.to_machine_usize(this)?; + + let start_routine = this.read_pointer(start_op)?; + + let func_arg = this.read_immediate(arg_op)?; let flags = this.read_scalar(flags_op)?.to_u32()?; + let thread = if this.ptr_is_null(this.read_pointer(thread_op)?)? { + None + } else { + let thread_info_place = this.deref_operand(thread_op)?; + Some(thread_info_place) + }; + let stack_size_param_is_a_reservation = this.eval_windows("c", "STACK_SIZE_PARAM_IS_A_RESERVATION")?.to_u32()?; + // We ignore the stack size, so we also ignore the + // `STACK_SIZE_PARAM_IS_A_RESERVATION` flag. if flags != 0 && flags != stack_size_param_is_a_reservation { throw_unsup_format!("unsupported `dwCreationFlags` {} in `CreateThread`", flags) } - let thread = - if this.ptr_is_null(this.read_pointer(thread_op)?)? { None } else { Some(thread_op) }; + if !this.ptr_is_null(security)? { + throw_unsup_format!("non-null `lpThreadAttributes` in `CreateThread`") + } this.start_thread( thread, - start_op, + start_routine, Abi::System { unwind: false }, - arg_op, + func_arg, this.layout_of(this.tcx.types.u32)?, ) } fn WaitForSingleObject( &mut self, - handle: &OpTy<'tcx, Provenance>, - timeout: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx> { + handle_op: &OpTy<'tcx, Provenance>, + timeout_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, u32> { let this = self.eval_context_mut(); - let thread = match Handle::from_scalar(this.read_scalar(handle)?.check_init()?, this)? { + let handle = this.read_scalar(handle_op)?.check_init()?; + + let timeout = this.read_scalar(timeout_op)?.to_u32()?; + + let thread = match Handle::from_scalar(handle, this)? { Some(Handle::Thread(thread)) => thread, - // Unlike on posix, joining the current thread is not UB on windows. - // It will just deadlock. + // Unlike on posix, the outcome of joining the current thread is not documented. + // On current Windows, it just deadlocks. Some(Handle::Pseudo(PseudoHandle::CurrentThread)) => this.get_active_thread(), _ => this.invalid_handle("WaitForSingleObject")?, }; - if this.read_scalar(timeout)?.to_u32()? != this.eval_windows("c", "INFINITE")?.to_u32()? { + if timeout != this.eval_windows("c", "INFINITE")?.to_u32()? { throw_unsup_format!("`WaitForSingleObject` with non-infinite timeout"); } this.join_thread(thread)?; - Ok(()) + Ok(0) } } diff --git a/src/thread.rs b/src/thread.rs index f7fcdd5822a2..b92728be2087 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -181,7 +181,7 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> { } /// A specific moment in time. -#[derive(Debug, Copy, Clone)] +#[derive(Debug)] pub enum Time { Monotonic(Instant), RealTime(SystemTime), @@ -357,16 +357,19 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// /// `allow_terminated_joined` allows detaching joined threads that have already terminated. /// This matches Windows's behavior for `CloseHandle`. + /// + /// See : + /// > The handle is valid until closed, even after the thread it represents has been terminated. fn detach_thread(&mut self, id: ThreadId, allow_terminated_joined: bool) -> InterpResult<'tcx> { trace!("detaching {:?}", id); let is_ub = if allow_terminated_joined && self.threads[id].state == ThreadState::Terminated { + // "Detached" in particular means "not yet joined". Redundant detaching is still UB. self.threads[id].join_status == ThreadJoinStatus::Detached } else { self.threads[id].join_status != ThreadJoinStatus::Joinable }; - if is_ub { throw_ub_format!("trying to detach thread that was already detached or joined"); } @@ -406,7 +409,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Mark that the active thread tries to exclusively join the thread with `joined_thread_id`. - /// If the thread is already joined by another thread + /// If the thread is already joined by another thread, it will throw UB fn join_thread_exclusive( &mut self, joined_thread_id: ThreadId, @@ -424,7 +427,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { self.threads .iter() .all(|thread| thread.state != ThreadState::BlockedOnJoin(joined_thread_id)), - "a joinable thread already has threads waiting for its termination" + "this thread already has threads waiting for its termination" ); self.join_thread(joined_thread_id, data_race) @@ -803,12 +806,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[inline] - fn set_thread_name_wide(&mut self, thread: ThreadId, new_thread_name: Vec) { + fn set_thread_name_wide(&mut self, thread: ThreadId, new_thread_name: &[u16]) { let this = self.eval_context_mut(); - this.machine.threads.set_thread_name( - thread, - new_thread_name.into_iter().flat_map(u16::to_ne_bytes).collect(), - ); + + // The Windows `GetThreadDescription` shim to get the thread name isn't implemented, so being lossy is okay. + // This is only read by diagnostics, which already use `from_utf8_lossy`. + this.machine + .threads + .set_thread_name(thread, String::from_utf16_lossy(new_thread_name).into_bytes()); } #[inline] diff --git a/tests/fail/concurrency/libc_pthread_join_detached.stderr b/tests/fail/concurrency/libc_pthread_join_detached.stderr index e381a71b2520..92b693c0fd6b 100644 --- a/tests/fail/concurrency/libc_pthread_join_detached.stderr +++ b/tests/fail/concurrency/libc_pthread_join_detached.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: trying to join a detached or already joined thread +error: Undefined Behavior: trying to join a detached thread --> $DIR/libc_pthread_join_detached.rs:LL:CC | -LL | ... assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached thread +LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached thread | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/concurrency/libc_pthread_join_joined.rs b/tests/fail/concurrency/libc_pthread_join_joined.rs index ebd1710bbf22..04ca4bbb3f61 100644 --- a/tests/fail/concurrency/libc_pthread_join_joined.rs +++ b/tests/fail/concurrency/libc_pthread_join_joined.rs @@ -15,6 +15,6 @@ fn main() { // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented. assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0); assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); - assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join a detached or already joined thread + assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join an already joined thread } } diff --git a/tests/fail/concurrency/libc_pthread_join_joined.stderr b/tests/fail/concurrency/libc_pthread_join_joined.stderr index 5ac35ffe512e..f11b94cde8ee 100644 --- a/tests/fail/concurrency/libc_pthread_join_joined.stderr +++ b/tests/fail/concurrency/libc_pthread_join_joined.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: trying to join a detached or already joined thread +error: Undefined Behavior: trying to join an already joined thread --> $DIR/libc_pthread_join_joined.rs:LL:CC | -LL | ... assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached or already joined thread +LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join an already joined thread | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/concurrency/libc_pthread_join_main.rs b/tests/fail/concurrency/libc_pthread_join_main.rs index df6b520431b6..757651821637 100644 --- a/tests/fail/concurrency/libc_pthread_join_main.rs +++ b/tests/fail/concurrency/libc_pthread_join_main.rs @@ -8,7 +8,7 @@ fn main() { let thread_id: libc::pthread_t = unsafe { libc::pthread_self() }; let handle = thread::spawn(move || { unsafe { - assert_eq!(libc::pthread_join(thread_id, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join a detached or already joined thread + assert_eq!(libc::pthread_join(thread_id, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join a detached thread } }); thread::yield_now(); diff --git a/tests/fail/concurrency/libc_pthread_join_main.stderr b/tests/fail/concurrency/libc_pthread_join_main.stderr index fe136549ce51..c162f37b309f 100644 --- a/tests/fail/concurrency/libc_pthread_join_main.stderr +++ b/tests/fail/concurrency/libc_pthread_join_main.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: trying to join a detached or already joined thread +error: Undefined Behavior: trying to join a detached thread --> $DIR/libc_pthread_join_main.rs:LL:CC | -LL | ... assert_eq!(libc::pthread_join(thread_id, ptr::null_mut()), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached or already joined thread +LL | assert_eq!(libc::pthread_join(thread_id, ptr::null_mut()), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached thread | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/concurrency/libc_pthread_join_multiple.rs b/tests/fail/concurrency/libc_pthread_join_multiple.rs index e5187093befd..966f416eeac7 100644 --- a/tests/fail/concurrency/libc_pthread_join_multiple.rs +++ b/tests/fail/concurrency/libc_pthread_join_multiple.rs @@ -21,7 +21,7 @@ fn main() { let mut native_copy: libc::pthread_t = mem::zeroed(); ptr::copy_nonoverlapping(&native, &mut native_copy, 1); let handle = thread::spawn(move || { - assert_eq!(libc::pthread_join(native_copy, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join a detached or already joined thread + assert_eq!(libc::pthread_join(native_copy, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join an already joined thread }); assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); handle.join().unwrap(); diff --git a/tests/fail/concurrency/libc_pthread_join_multiple.stderr b/tests/fail/concurrency/libc_pthread_join_multiple.stderr index 9b91e5a3d0ed..c0c73086f14d 100644 --- a/tests/fail/concurrency/libc_pthread_join_multiple.stderr +++ b/tests/fail/concurrency/libc_pthread_join_multiple.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: trying to join a detached or already joined thread +error: Undefined Behavior: trying to join an already joined thread --> $DIR/libc_pthread_join_multiple.rs:LL:CC | LL | ... assert_eq!(libc::pthread_join(native_copy, ptr::null_mut()), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached or already joined thread + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join an already joined thread | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/concurrency/windows_join_main.rs b/tests/fail/concurrency/windows_join_main.rs index d3b54cdf156f..cde6d19ef25b 100644 --- a/tests/fail/concurrency/windows_join_main.rs +++ b/tests/fail/concurrency/windows_join_main.rs @@ -12,7 +12,7 @@ extern "system" { const INFINITE: u32 = u32::MAX; -// This is how miri represents the handle for thread 0. +// XXX HACK: This is how miri represents the handle for thread 0. // This value can be "legitimately" obtained by using `GetCurrentThread` with `DuplicateHandle` // but miri does not implement `DuplicateHandle` yet. const MAIN_THREAD: isize = (2i32 << 30) as isize; diff --git a/tests/pass/concurrency/tls_lib_drop.rs b/tests/pass/concurrency/tls_lib_drop.rs index 8ce011ede34e..3fd6e2d6f242 100644 --- a/tests/pass/concurrency/tls_lib_drop.rs +++ b/tests/pass/concurrency/tls_lib_drop.rs @@ -1,3 +1,5 @@ +//@ignore-target-windows: TLS destructor order is different on Windows. + use std::cell::RefCell; use std::thread; diff --git a/tests/pass/concurrency/tls_lib_drop_windows.rs b/tests/pass/concurrency/tls_lib_drop_windows.rs new file mode 100644 index 000000000000..e8c6538e701d --- /dev/null +++ b/tests/pass/concurrency/tls_lib_drop_windows.rs @@ -0,0 +1,191 @@ +//@only-target-windows: TLS destructor order is different on Windows. + +use std::cell::RefCell; +use std::thread; + +struct TestCell { + value: RefCell, +} + +impl Drop for TestCell { + fn drop(&mut self) { + for _ in 0..10 { + thread::yield_now(); + } + println!("Dropping: {} (should be before 'Continue main 1').", *self.value.borrow()) + } +} + +thread_local! { + static A: TestCell = TestCell { value: RefCell::new(0) }; + static A_CONST: TestCell = const { TestCell { value: RefCell::new(10) } }; +} + +/// Check that destructors of the library thread locals are executed immediately +/// after a thread terminates. +fn check_destructors() { + thread::spawn(|| { + A.with(|f| { + assert_eq!(*f.value.borrow(), 0); + *f.value.borrow_mut() = 5; + }); + A_CONST.with(|f| { + assert_eq!(*f.value.borrow(), 10); + *f.value.borrow_mut() = 15; + }); + }) + .join() + .unwrap(); + println!("Continue main 1.") +} + +struct JoinCell { + value: RefCell>>, +} + +impl Drop for JoinCell { + fn drop(&mut self) { + for _ in 0..10 { + thread::yield_now(); + } + let join_handle = self.value.borrow_mut().take().unwrap(); + println!("Joining: {} (should be before 'Continue main 2').", join_handle.join().unwrap()); + } +} + +thread_local! { + static B: JoinCell = JoinCell { value: RefCell::new(None) }; +} + +/// Check that the destructor can be blocked joining another thread. +fn check_blocking() { + thread::spawn(|| { + B.with(|f| { + assert!(f.value.borrow().is_none()); + let handle = thread::spawn(|| 7); + *f.value.borrow_mut() = Some(handle); + }); + }) + .join() + .unwrap(); + println!("Continue main 2."); + // Preempt the main thread so that the destructor gets executed and can join + // the thread. + thread::yield_now(); + thread::yield_now(); +} + +// This test tests that TLS destructors have run before the thread joins. The +// test has no false positives (meaning: if the test fails, there's actually +// an ordering problem). It may have false negatives, where the test passes but +// join is not guaranteed to be after the TLS destructors. However, false +// negatives should be exceedingly rare due to judicious use of +// thread::yield_now and running the test several times. +fn join_orders_after_tls_destructors() { + use std::sync::atomic::{AtomicU8, Ordering}; + + // We emulate a synchronous MPSC rendezvous channel using only atomics and + // thread::yield_now. We can't use std::mpsc as the implementation itself + // may rely on thread locals. + // + // The basic state machine for an SPSC rendezvous channel is: + // FRESH -> THREAD1_WAITING -> MAIN_THREAD_RENDEZVOUS + // where the first transition is done by the “receiving” thread and the 2nd + // transition is done by the “sending” thread. + // + // We add an additional state `THREAD2_LAUNCHED` between `FRESH` and + // `THREAD1_WAITING` to block until all threads are actually running. + // + // A thread that joins on the “receiving” thread completion should never + // observe the channel in the `THREAD1_WAITING` state. If this does occur, + // we switch to the “poison” state `THREAD2_JOINED` and panic all around. + // (This is equivalent to “sending” from an alternate producer thread.) + const FRESH: u8 = 0; + const THREAD2_LAUNCHED: u8 = 1; + const THREAD1_WAITING: u8 = 2; + const MAIN_THREAD_RENDEZVOUS: u8 = 3; + const THREAD2_JOINED: u8 = 4; + static SYNC_STATE: AtomicU8 = AtomicU8::new(FRESH); + + for _ in 0..10 { + SYNC_STATE.store(FRESH, Ordering::SeqCst); + + let jh = thread::Builder::new() + .name("thread1".into()) + .spawn(move || { + struct TlDrop; + + impl Drop for TlDrop { + fn drop(&mut self) { + let mut sync_state = SYNC_STATE.swap(THREAD1_WAITING, Ordering::SeqCst); + loop { + match sync_state { + THREAD2_LAUNCHED | THREAD1_WAITING => thread::yield_now(), + MAIN_THREAD_RENDEZVOUS => break, + THREAD2_JOINED => + panic!( + "Thread 1 still running after thread 2 joined on thread 1" + ), + v => unreachable!("sync state: {}", v), + } + sync_state = SYNC_STATE.load(Ordering::SeqCst); + } + } + } + + thread_local! { + static TL_DROP: TlDrop = TlDrop; + } + + TL_DROP.with(|_| {}); + + loop { + match SYNC_STATE.load(Ordering::SeqCst) { + FRESH => thread::yield_now(), + THREAD2_LAUNCHED => break, + v => unreachable!("sync state: {}", v), + } + } + }) + .unwrap(); + + let jh2 = thread::Builder::new() + .name("thread2".into()) + .spawn(move || { + assert_eq!(SYNC_STATE.swap(THREAD2_LAUNCHED, Ordering::SeqCst), FRESH); + jh.join().unwrap(); + match SYNC_STATE.swap(THREAD2_JOINED, Ordering::SeqCst) { + MAIN_THREAD_RENDEZVOUS => return, + THREAD2_LAUNCHED | THREAD1_WAITING => { + panic!("Thread 2 running after thread 1 join before main thread rendezvous") + } + v => unreachable!("sync state: {:?}", v), + } + }) + .unwrap(); + + loop { + match SYNC_STATE.compare_exchange( + THREAD1_WAITING, + MAIN_THREAD_RENDEZVOUS, + Ordering::SeqCst, + Ordering::SeqCst, + ) { + Ok(_) => break, + Err(FRESH) => thread::yield_now(), + Err(THREAD2_LAUNCHED) => thread::yield_now(), + Err(THREAD2_JOINED) => { + panic!("Main thread rendezvous after thread 2 joined thread 1") + } + v => unreachable!("sync state: {:?}", v), + } + } + jh2.join().unwrap(); + } +} + +fn main() { + check_destructors(); + check_blocking(); + join_orders_after_tls_destructors(); +} diff --git a/tests/pass/concurrency/tls_lib_drop_windows.stdout b/tests/pass/concurrency/tls_lib_drop_windows.stdout new file mode 100644 index 000000000000..e5b8efcaf5fa --- /dev/null +++ b/tests/pass/concurrency/tls_lib_drop_windows.stdout @@ -0,0 +1,5 @@ +Dropping: 15 (should be before 'Continue main 1'). +Dropping: 5 (should be before 'Continue main 1'). +Continue main 1. +Joining: 7 (should be before 'Continue main 2'). +Continue main 2. From a05a8eb805166dcc5408175f16c46303b76c871d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Aug 2022 08:15:41 -0400 Subject: [PATCH 3758/5092] add very basic Android support --- ci.sh | 1 + rust-version | 2 +- src/helpers.rs | 2 +- src/machine.rs | 44 +++++++++++++++----- src/shims/unix/android/dlsym.rs | 53 +++++++++++++++++++++++++ src/shims/unix/android/foreign_items.rs | 23 +++++++++++ src/shims/unix/android/mod.rs | 2 + src/shims/unix/dlsym.rs | 15 ++++--- src/shims/unix/foreign_items.rs | 9 +++-- src/shims/unix/freebsd/dlsym.rs | 4 ++ src/shims/unix/linux/dlsym.rs | 4 ++ src/shims/unix/mod.rs | 1 + src/shims/windows/dlsym.rs | 4 +- 13 files changed, 143 insertions(+), 21 deletions(-) create mode 100644 src/shims/unix/android/dlsym.rs create mode 100644 src/shims/unix/android/foreign_items.rs create mode 100644 src/shims/unix/android/mod.rs diff --git a/ci.sh b/ci.sh index 51cec8fe1619..d1a8db183d14 100755 --- a/ci.sh +++ b/ci.sh @@ -84,6 +84,7 @@ case $HOST_TARGET in MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec data_race env/var + MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture ;; x86_64-apple-darwin) diff --git a/rust-version b/rust-version index 7317986eaea4..45dbb37c86ac 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8556e6620e4866526b3cea767ad8c20ae877a569 +9c20b2a8cc7588decb6de25ac6a7912dcef24d65 diff --git a/src/helpers.rs b/src/helpers.rs index 7c9f8740eb42..d63bf97ad51d 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -954,5 +954,5 @@ pub fn get_local_crates(tcx: TyCtxt<'_>) -> Vec { /// Helper function used inside the shims of foreign functions to check that /// `target_os` is a supported UNIX OS. pub fn target_os_is_unix(target_os: &str) -> bool { - matches!(target_os, "linux" | "macos" | "freebsd") + matches!(target_os, "linux" | "macos" | "freebsd" | "android") } diff --git a/src/machine.rs b/src/machine.rs index 4ebf7dceab83..d45f5de381f3 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -232,13 +232,15 @@ pub struct PrimitiveLayouts<'tcx> { pub u32: TyAndLayout<'tcx>, pub usize: TyAndLayout<'tcx>, pub bool: TyAndLayout<'tcx>, - pub mut_raw_ptr: TyAndLayout<'tcx>, + pub mut_raw_ptr: TyAndLayout<'tcx>, // *mut () + pub const_raw_ptr: TyAndLayout<'tcx>, // *const () } impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> { fn new(layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result> { let tcx = layout_cx.tcx; let mut_raw_ptr = tcx.mk_ptr(TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Mut }); + let const_raw_ptr = tcx.mk_ptr(TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Not }); Ok(Self { unit: layout_cx.layout_of(tcx.mk_unit())?, i8: layout_cx.layout_of(tcx.types.i8)?, @@ -251,6 +253,7 @@ impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> { usize: layout_cx.layout_of(tcx.types.usize)?, bool: layout_cx.layout_of(tcx.types.bool)?, mut_raw_ptr: layout_cx.layout_of(mut_raw_ptr)?, + const_raw_ptr: layout_cx.layout_of(const_raw_ptr)?, }) } } @@ -431,6 +434,17 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { this.machine.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap(); } + fn alloc_extern_static( + this: &mut MiriEvalContext<'mir, 'tcx>, + name: &str, + val: ImmTy<'tcx, Provenance>, + ) -> InterpResult<'tcx> { + let place = this.allocate(val.layout, MiriMemoryKind::ExternStatic.into())?; + this.write_immediate(*val, &place.into())?; + Self::add_extern_static(this, name, place.ptr); + Ok(()) + } + /// Sets up the "extern statics" for this machine. fn init_extern_statics(this: &mut MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx> { match this.tcx.sess.target.os.as_ref() { @@ -447,10 +461,8 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { // syscall that we do support). for name in &["__cxa_thread_atexit_impl", "getrandom", "statx", "__clock_gettime64"] { - let layout = this.machine.layouts.usize; - let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; - this.write_scalar(Scalar::from_machine_usize(0, this), &place.into())?; - Self::add_extern_static(this, name, place.ptr); + let val = ImmTy::from_int(0, this.machine.layouts.usize); + Self::alloc_extern_static(this, name, val)?; } } "freebsd" => { @@ -461,13 +473,27 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { this.machine.env_vars.environ.unwrap().ptr, ); } + "android" => { + // "signal" + let layout = this.machine.layouts.const_raw_ptr; + let dlsym = Dlsym::from_str("signal".as_bytes(), &this.tcx.sess.target.os)? + .expect("`signal` must be an actual dlsym on android"); + let ptr = this.create_fn_alloc_ptr(FnVal::Other(dlsym)); + let val = ImmTy::from_scalar(Scalar::from_pointer(ptr, this), layout); + Self::alloc_extern_static(this, "signal", val)?; + // A couple zero-initialized pointer-sized extern statics. + // Most of them are for weak symbols, which we all set to null (indicating that the + // symbol is not supported, and triggering fallback code.) + for name in &["bsd_signal"] { + let val = ImmTy::from_int(0, this.machine.layouts.usize); + Self::alloc_extern_static(this, name, val)?; + } + } "windows" => { // "_tls_used" // This is some obscure hack that is part of the Windows TLS story. It's a `u8`. - let layout = this.machine.layouts.u8; - let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; - this.write_scalar(Scalar::from_u8(0), &place.into())?; - Self::add_extern_static(this, "_tls_used", place.ptr); + let val = ImmTy::from_int(0, this.machine.layouts.u8); + Self::alloc_extern_static(this, "_tls_used", val)?; } _ => {} // No "extern statics" supported on this target } diff --git a/src/shims/unix/android/dlsym.rs b/src/shims/unix/android/dlsym.rs new file mode 100644 index 000000000000..a6b24d0fa507 --- /dev/null +++ b/src/shims/unix/android/dlsym.rs @@ -0,0 +1,53 @@ +use rustc_middle::mir; + +use crate::helpers::check_arg_count; +use crate::*; + +#[derive(Debug, Copy, Clone)] +#[allow(non_camel_case_types)] +pub enum Dlsym { + signal, +} + +impl Dlsym { + // Returns an error for unsupported symbols, and None if this symbol + // should become a NULL pointer (pretend it does not exist). + pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { + Ok(match &*name { + "signal" => Some(Dlsym::signal), + _ => throw_unsup_format!("unsupported Android dlsym: {}", name), + }) + } +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn call_dlsym( + &mut self, + dlsym: Dlsym, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, + ret: Option, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let ret = ret.expect("we don't support any diverging dlsym"); + assert!(this.tcx.sess.target.os == "android"); + + match dlsym { + Dlsym::signal => { + if !this.frame_in_std() { + throw_unsup_format!( + "`signal` support is crude and just enough for libstd to work" + ); + } + + let &[ref _sig, ref _func] = check_arg_count(args)?; + this.write_null(dest)?; + } + } + + log::trace!("{:?}", this.dump_place(**dest)); + this.go_to_block(ret); + Ok(()) + } +} diff --git a/src/shims/unix/android/foreign_items.rs b/src/shims/unix/android/foreign_items.rs new file mode 100644 index 000000000000..cde98b31e031 --- /dev/null +++ b/src/shims/unix/android/foreign_items.rs @@ -0,0 +1,23 @@ +use rustc_span::Symbol; +use rustc_target::spec::abi::Abi; + +use crate::*; +use shims::foreign_items::EmulateByNameResult; + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} + +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn emulate_foreign_item_by_name( + &mut self, + link_name: Symbol, + _abi: Abi, + _args: &[OpTy<'tcx, Provenance>], + _dest: &PlaceTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { + let _this = self.eval_context_mut(); + match link_name.as_str() { + _ => return Ok(EmulateByNameResult::NotSupported), + } + //Ok(EmulateByNameResult::NeedsJumping) + } +} diff --git a/src/shims/unix/android/mod.rs b/src/shims/unix/android/mod.rs new file mode 100644 index 000000000000..434f5f30b5a5 --- /dev/null +++ b/src/shims/unix/android/mod.rs @@ -0,0 +1,2 @@ +pub mod dlsym; +pub mod foreign_items; diff --git a/src/shims/unix/dlsym.rs b/src/shims/unix/dlsym.rs index a806c16e28bb..fee128229179 100644 --- a/src/shims/unix/dlsym.rs +++ b/src/shims/unix/dlsym.rs @@ -2,15 +2,17 @@ use rustc_middle::mir; use rustc_target::spec::abi::Abi; use crate::*; +use shims::unix::android::dlsym as android; use shims::unix::freebsd::dlsym as freebsd; use shims::unix::linux::dlsym as linux; use shims::unix::macos::dlsym as macos; #[derive(Debug, Copy, Clone)] pub enum Dlsym { + Android(android::Dlsym), + FreeBsd(freebsd::Dlsym), Linux(linux::Dlsym), MacOs(macos::Dlsym), - FreeBsd(freebsd::Dlsym), } impl Dlsym { @@ -18,10 +20,11 @@ impl Dlsym { // should become a NULL pointer (pretend it does not exist). pub fn from_str<'tcx>(name: &str, target_os: &str) -> InterpResult<'tcx, Option> { Ok(match target_os { + "android" => android::Dlsym::from_str(name)?.map(Dlsym::Android), + "freebsd" => freebsd::Dlsym::from_str(name)?.map(Dlsym::FreeBsd), "linux" => linux::Dlsym::from_str(name)?.map(Dlsym::Linux), "macos" => macos::Dlsym::from_str(name)?.map(Dlsym::MacOs), - "freebsd" => freebsd::Dlsym::from_str(name)?.map(Dlsym::FreeBsd), - _ => unreachable!(), + _ => panic!("unsupported Unix OS {target_os}"), }) } } @@ -41,10 +44,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_abi(abi, Abi::C { unwind: false })?; match dlsym { - Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), - Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), + Dlsym::Android(dlsym) => + android::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), Dlsym::FreeBsd(dlsym) => freebsd::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), + Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), + Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), } } } diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 877a144963a2..58b0997c6c01 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -24,6 +24,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); + #[rustfmt::skip] match link_name.as_str() { // Environment related shims "getenv" => { @@ -588,11 +589,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Platform-specific shims _ => { - match this.tcx.sess.target.os.as_ref() { + let target_os = &*this.tcx.sess.target.os; + match target_os { + "android" => return shims::unix::android::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest), + "freebsd" => return shims::unix::freebsd::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest), "linux" => return shims::unix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest), "macos" => return shims::unix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest), - "freebsd" => return shims::unix::freebsd::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest), - _ => unreachable!(), + _ => panic!("unsupported Unix OS {target_os}"), } } }; diff --git a/src/shims/unix/freebsd/dlsym.rs b/src/shims/unix/freebsd/dlsym.rs index 74c322c666d4..ebc1998f1b57 100644 --- a/src/shims/unix/freebsd/dlsym.rs +++ b/src/shims/unix/freebsd/dlsym.rs @@ -28,5 +28,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert!(this.tcx.sess.target.os == "freebsd"); match dlsym {} + + //trace!("{:?}", this.dump_place(**dest)); + //this.go_to_block(ret); + //Ok(()) } } diff --git a/src/shims/unix/linux/dlsym.rs b/src/shims/unix/linux/dlsym.rs index 44d51c4a0b3a..f5cf1e0071a9 100644 --- a/src/shims/unix/linux/dlsym.rs +++ b/src/shims/unix/linux/dlsym.rs @@ -32,5 +32,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert!(this.tcx.sess.target.os == "linux"); match dlsym {} + + //trace!("{:?}", this.dump_place(**dest)); + //this.go_to_block(ret); + //Ok(()) } } diff --git a/src/shims/unix/mod.rs b/src/shims/unix/mod.rs index 35380fc06d79..6fefb054f3c0 100644 --- a/src/shims/unix/mod.rs +++ b/src/shims/unix/mod.rs @@ -5,6 +5,7 @@ mod fs; mod sync; mod thread; +mod android; mod freebsd; mod linux; mod macos; diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index eab5f99c8785..e14c2a86b09c 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -45,7 +45,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Dlsym::NtWriteFile => { if !this.frame_in_std() { throw_unsup_format!( - "NtWriteFile support is crude and just enough for stdout to work" + "`NtWriteFile` support is crude and just enough for stdout to work" ); } @@ -68,7 +68,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if byte_offset != 0 { throw_unsup_format!( - "NtWriteFile ByteOffset paremeter is non-null, which is unsupported" + "`NtWriteFile` `ByteOffset` paremeter is non-null, which is unsupported" ); } From 3ec8dd87608b47ecc4f0eaa832a927f38f133eb1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Aug 2022 08:25:28 -0400 Subject: [PATCH 3759/5092] implement setting the thread name on freebsd --- ci.sh | 2 +- src/shims/unix/freebsd/foreign_items.rs | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/ci.sh b/ci.sh index d1a8db183d14..f93c9700c5a1 100755 --- a/ci.sh +++ b/ci.sh @@ -83,7 +83,7 @@ case $HOST_TARGET in MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests - MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec data_race env/var + MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple atomic data_race env/var MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture ;; diff --git a/src/shims/unix/freebsd/foreign_items.rs b/src/shims/unix/freebsd/foreign_items.rs index 658711526d00..92e76ff09dcb 100644 --- a/src/shims/unix/freebsd/foreign_items.rs +++ b/src/shims/unix/freebsd/foreign_items.rs @@ -3,6 +3,7 @@ use rustc_target::spec::abi::Abi; use crate::*; use shims::foreign_items::EmulateByNameResult; +use shims::unix::thread::EvalContextExt as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -16,12 +17,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); match link_name.as_str() { - // Linux's `pthread_getattr_np` equivalent + // Threading "pthread_attr_get_np" if this.frame_in_std() => { let [_thread, _attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_null(dest)?; } + "pthread_set_name_np" => { + let [thread, name] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let res = this.pthread_setname_np( + this.read_scalar(thread)?.check_init()?, + this.read_scalar(name)?.check_init()?, + )?; + this.write_scalar(res, dest)?; + } // errno "__error" => { From 4359f43e922a07d26dd9942f184289289d2aef84 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Aug 2022 08:39:53 -0400 Subject: [PATCH 3760/5092] make abort-on-panic work on Android --- ci.sh | 2 +- src/shims/unix/android/dlsym.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index f93c9700c5a1..d70feec66f26 100755 --- a/ci.sh +++ b/ci.sh @@ -84,7 +84,7 @@ case $HOST_TARGET in MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple atomic data_race env/var - MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec + MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec panic/panic MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture ;; x86_64-apple-darwin) diff --git a/src/shims/unix/android/dlsym.rs b/src/shims/unix/android/dlsym.rs index a6b24d0fa507..3e9b00fbe5f2 100644 --- a/src/shims/unix/android/dlsym.rs +++ b/src/shims/unix/android/dlsym.rs @@ -15,6 +15,7 @@ impl Dlsym { pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { Ok(match &*name { "signal" => Some(Dlsym::signal), + "android_set_abort_message" => None, _ => throw_unsup_format!("unsupported Android dlsym: {}", name), }) } From 5e10f14584f20f8b0b7716916a0d08e836696ef4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Aug 2022 09:13:07 -0400 Subject: [PATCH 3761/5092] clippy... --- src/lib.rs | 1 + src/shims/unix/android/dlsym.rs | 2 +- src/shims/unix/android/foreign_items.rs | 5 ++++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ba337f28311e..2c30ee06c057 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,6 +24,7 @@ clippy::derive_hash_xor_eq, clippy::too_many_arguments, clippy::type_complexity, + clippy::single_element_loop, // We are not implementing queries here so it's fine rustc::potential_query_instability )] diff --git a/src/shims/unix/android/dlsym.rs b/src/shims/unix/android/dlsym.rs index 3e9b00fbe5f2..28941a3de4ec 100644 --- a/src/shims/unix/android/dlsym.rs +++ b/src/shims/unix/android/dlsym.rs @@ -13,7 +13,7 @@ impl Dlsym { // Returns an error for unsupported symbols, and None if this symbol // should become a NULL pointer (pretend it does not exist). pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { - Ok(match &*name { + Ok(match name { "signal" => Some(Dlsym::signal), "android_set_abort_message" => None, _ => throw_unsup_format!("unsupported Android dlsym: {}", name), diff --git a/src/shims/unix/android/foreign_items.rs b/src/shims/unix/android/foreign_items.rs index cde98b31e031..9c12736887fa 100644 --- a/src/shims/unix/android/foreign_items.rs +++ b/src/shims/unix/android/foreign_items.rs @@ -15,9 +15,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let _this = self.eval_context_mut(); + #[allow(clippy::match_single_binding)] match link_name.as_str() { _ => return Ok(EmulateByNameResult::NotSupported), } - //Ok(EmulateByNameResult::NeedsJumping) + + #[allow(unreachable_code)] + Ok(EmulateByNameResult::NeedsJumping) } } From c466ac0b3ec200ac53b1ca8196c47261b692bda1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Aug 2022 11:25:20 -0400 Subject: [PATCH 3762/5092] add some missing assert_target_os --- src/shims/time.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index e495f723668d..67303c47db7e 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -197,12 +197,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn nanosleep( &mut self, req_op: &OpTy<'tcx, Provenance>, - _rem: &OpTy<'tcx, Provenance>, + _rem: &OpTy<'tcx, Provenance>, // Signal handlers are not supported, so rem will never be written to. ) -> InterpResult<'tcx, i32> { - // Signal handlers are not supported, so rem will never be written to. - let this = self.eval_context_mut(); + this.assert_target_os_is_unix("nanosleep"); this.check_no_isolation("`nanosleep`")?; let duration = match this.read_timespec(&this.deref_operand(req_op)?)? { @@ -238,6 +237,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn Sleep(&mut self, timeout: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + this.assert_target_os("windows", "Sleep"); this.check_no_isolation("`Sleep`")?; let timeout_ms = this.read_scalar(timeout)?.to_u32()?; From e87a5a1cc5e799b929abf27a03a6535a88698ce6 Mon Sep 17 00:00:00 2001 From: Lukas Lueg Date: Thu, 18 Aug 2022 19:30:56 +0200 Subject: [PATCH 3763/5092] Dont lint on match pattern-binding Fixes #9347 Technically it is possible to have a blank match-pattern that does nothing, and we fail to lint. But its easier to be safe than sorry here. --- clippy_lints/src/question_mark.rs | 2 +- tests/ui/question_mark.fixed | 15 +++++++++++++++ tests/ui/question_mark.rs | 15 +++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 964a057f00d3..b432ccb1ee32 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -123,7 +123,7 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else }) = higher::IfLet::hir(cx, expr); if !is_else_clause(cx.tcx, expr); if let PatKind::TupleStruct(ref path1, [field], None) = let_pat.kind; - if let PatKind::Binding(annot, bind_id, ident, _) = field.kind; + if let PatKind::Binding(annot, bind_id, ident, None) = field.kind; let caller_ty = cx.typeck_results().expr_ty(let_expr); let if_block = IfBlockType::IfLet(path1, caller_ty, ident.name, let_expr, if_then, if_else); if (is_early_return(sym::Option, cx, &if_block) && path_to_local_id(peel_blocks(if_then), bind_id)) diff --git a/tests/ui/question_mark.fixed b/tests/ui/question_mark.fixed index c4c9c8214333..57f23bd1916f 100644 --- a/tests/ui/question_mark.fixed +++ b/tests/ui/question_mark.fixed @@ -207,4 +207,19 @@ fn option_map() -> Option { } } +pub struct PatternedError { + flag: bool, +} + +// No warning +fn pattern() -> Result<(), PatternedError> { + let res = Ok(()); + + if let Err(err @ PatternedError { flag: true }) = res { + return Err(err); + } + + res +} + fn main() {} diff --git a/tests/ui/question_mark.rs b/tests/ui/question_mark.rs index cdbc7b1606f8..436f027c215d 100644 --- a/tests/ui/question_mark.rs +++ b/tests/ui/question_mark.rs @@ -243,4 +243,19 @@ fn option_map() -> Option { } } +pub struct PatternedError { + flag: bool, +} + +// No warning +fn pattern() -> Result<(), PatternedError> { + let res = Ok(()); + + if let Err(err @ PatternedError { flag: true }) = res { + return Err(err); + } + + res +} + fn main() {} From 581a01d0cc608d02090a5fd6d4fdc8a7b71b5c34 Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Thu, 18 Aug 2022 13:42:10 -0400 Subject: [PATCH 3764/5092] Migrate `syntax::make` to use format arg captures --- crates/syntax/src/ast/make.rs | 263 +++++++++++++++++----------------- 1 file changed, 132 insertions(+), 131 deletions(-) diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs index 037de876d45c..83f8bbac5880 100644 --- a/crates/syntax/src/ast/make.rs +++ b/crates/syntax/src/ast/make.rs @@ -25,7 +25,7 @@ pub mod ext { return from_text(&name.text()); fn from_text(text: &str) -> ast::IdentPat { - ast_from_text(&format!("fn f({}: ())", text)) + ast_from_text(&format!("fn f({text}: ())")) } } pub fn ident_path(ident: &str) -> ast::Path { @@ -60,10 +60,10 @@ pub mod ext { expr_from_text("todo!()") } pub fn expr_ty_default(ty: &ast::Type) -> ast::Expr { - expr_from_text(&format!("{}::default()", ty)) + expr_from_text(&format!("{ty}::default()")) } pub fn expr_ty_new(ty: &ast::Type) -> ast::Expr { - expr_from_text(&format!("{}::new()", ty)) + expr_from_text(&format!("{ty}::new()")) } pub fn zero_number() -> ast::Expr { @@ -92,18 +92,20 @@ pub mod ext { ty_path(ident_path("bool")) } pub fn ty_option(t: ast::Type) -> ast::Type { - ty_from_text(&format!("Option<{}>", t)) + ty_from_text(&format!("Option<{t}>")) } pub fn ty_result(t: ast::Type, e: ast::Type) -> ast::Type { - ty_from_text(&format!("Result<{}, {}>", t, e)) + ty_from_text(&format!("Result<{t}, {e}>")) } } -pub fn name(text: &str) -> ast::Name { - ast_from_text(&format!("mod {}{};", raw_ident_esc(text), text)) +pub fn name(name: &str) -> ast::Name { + let raw_escape = raw_ident_esc(name); + ast_from_text(&format!("mod {raw_escape}{name};")) } -pub fn name_ref(text: &str) -> ast::NameRef { - ast_from_text(&format!("fn f() {{ {}{}; }}", raw_ident_esc(text), text)) +pub fn name_ref(name_ref: &str) -> ast::NameRef { + let raw_escape = raw_ident_esc(name_ref); + ast_from_text(&format!("fn f() {{ {raw_escape}{name_ref}; }}")) } fn raw_ident_esc(ident: &str) -> &'static str { let is_keyword = parser::SyntaxKind::from_keyword(ident).is_some(); @@ -118,10 +120,10 @@ pub fn lifetime(text: &str) -> ast::Lifetime { let mut text = text; let tmp; if never!(!text.starts_with('\'')) { - tmp = format!("'{}", text); + tmp = format!("'{text}"); text = &tmp; } - ast_from_text(&format!("fn f<{}>() {{ }}", text)) + ast_from_text(&format!("fn f<{text}>() {{ }}")) } // FIXME: replace stringly-typed constructor with a family of typed ctors, a-la @@ -142,16 +144,16 @@ pub fn ty_tuple(types: impl IntoIterator) -> ast::Type { contents.push(','); } - ty_from_text(&format!("({})", contents)) + ty_from_text(&format!("({contents})")) } pub fn ty_ref(target: ast::Type, exclusive: bool) -> ast::Type { - ty_from_text(&if exclusive { format!("&mut {}", target) } else { format!("&{}", target) }) + ty_from_text(&if exclusive { format!("&mut {target}") } else { format!("&{target}") }) } pub fn ty_path(path: ast::Path) -> ast::Type { ty_from_text(&path.to_string()) } fn ty_from_text(text: &str) -> ast::Type { - ast_from_text(&format!("type _T = {};", text)) + ast_from_text(&format!("type _T = {text};")) } pub fn assoc_item_list() -> ast::AssocItemList { @@ -171,7 +173,7 @@ pub fn impl_( Some(params) => params.to_string(), None => String::new(), }; - ast_from_text(&format!("impl{} {}{} {{}}", params, ty, ty_params)) + ast_from_text(&format!("impl{params} {ty}{ty_params} {{}}")) } pub fn impl_trait( @@ -180,7 +182,7 @@ pub fn impl_trait( ty_params: Option, ) -> ast::Impl { let ty_params = ty_params.map_or_else(String::new, |params| params.to_string()); - ast_from_text(&format!("impl{2} {} for {}{2} {{}}", trait_, ty, ty_params)) + ast_from_text(&format!("impl{ty_params} {trait_} for {ty}{ty_params} {{}}")) } pub(crate) fn generic_arg_list() -> ast::GenericArgList { @@ -188,13 +190,13 @@ pub(crate) fn generic_arg_list() -> ast::GenericArgList { } pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment { - ast_from_text(&format!("type __ = {};", name_ref)) + ast_from_text(&format!("type __ = {name_ref};")) } pub fn path_segment_ty(type_ref: ast::Type, trait_ref: Option) -> ast::PathSegment { let text = match trait_ref { - Some(trait_ref) => format!("fn f(x: <{} as {}>) {{}}", type_ref, trait_ref), - None => format!("fn f(x: <{}>) {{}}", type_ref), + Some(trait_ref) => format!("fn f(x: <{type_ref} as {trait_ref}>) {{}}"), + None => format!("fn f(x: <{type_ref}>) {{}}"), }; ast_from_text(&text) } @@ -212,15 +214,15 @@ pub fn path_segment_crate() -> ast::PathSegment { } pub fn path_unqualified(segment: ast::PathSegment) -> ast::Path { - ast_from_text(&format!("type __ = {};", segment)) + ast_from_text(&format!("type __ = {segment};")) } pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path { - ast_from_text(&format!("{}::{}", qual, segment)) + ast_from_text(&format!("{qual}::{segment}")) } // FIXME: path concatenation operation doesn't make sense as AST op. pub fn path_concat(first: ast::Path, second: ast::Path) -> ast::Path { - ast_from_text(&format!("type __ = {}::{};", first, second)) + ast_from_text(&format!("type __ = {first}::{second};")) } pub fn path_from_segments( @@ -229,20 +231,20 @@ pub fn path_from_segments( ) -> ast::Path { let segments = segments.into_iter().map(|it| it.syntax().clone()).join("::"); ast_from_text(&if is_abs { - format!("fn f(x: ::{}) {{}}", segments) + format!("fn f(x: ::{segments}) {{}}") } else { - format!("fn f(x: {}) {{}}", segments) + format!("fn f(x: {segments}) {{}}") }) } pub fn join_paths(paths: impl IntoIterator) -> ast::Path { let paths = paths.into_iter().map(|it| it.syntax().clone()).join("::"); - ast_from_text(&format!("type __ = {};", paths)) + ast_from_text(&format!("type __ = {paths};")) } // FIXME: should not be pub pub fn path_from_text(text: &str) -> ast::Path { - ast_from_text(&format!("fn main() {{ let test = {}; }}", text)) + ast_from_text(&format!("fn main() {{ let test = {text}; }}")) } pub fn use_tree_glob() -> ast::UseTree { @@ -257,50 +259,50 @@ pub fn use_tree( let mut buf = "use ".to_string(); buf += &path.syntax().to_string(); if let Some(use_tree_list) = use_tree_list { - format_to!(buf, "::{}", use_tree_list); + format_to!(buf, "::{use_tree_list}"); } if add_star { buf += "::*"; } if let Some(alias) = alias { - format_to!(buf, " {}", alias); + format_to!(buf, " {alias}"); } ast_from_text(&buf) } pub fn use_tree_list(use_trees: impl IntoIterator) -> ast::UseTreeList { let use_trees = use_trees.into_iter().map(|it| it.syntax().clone()).join(", "); - ast_from_text(&format!("use {{{}}};", use_trees)) + ast_from_text(&format!("use {{{use_trees}}};")) } pub fn use_(visibility: Option, use_tree: ast::UseTree) -> ast::Use { let visibility = match visibility { None => String::new(), - Some(it) => format!("{} ", it), + Some(it) => format!("{it} "), }; - ast_from_text(&format!("{}use {};", visibility, use_tree)) + ast_from_text(&format!("{visibility}use {use_tree};")) } pub fn record_expr(path: ast::Path, fields: ast::RecordExprFieldList) -> ast::RecordExpr { - ast_from_text(&format!("fn f() {{ {} {} }}", path, fields)) + ast_from_text(&format!("fn f() {{ {path} {fields} }}")) } pub fn record_expr_field_list( fields: impl IntoIterator, ) -> ast::RecordExprFieldList { let fields = fields.into_iter().join(", "); - ast_from_text(&format!("fn f() {{ S {{ {} }} }}", fields)) + ast_from_text(&format!("fn f() {{ S {{ {fields} }} }}")) } pub fn record_expr_field(name: ast::NameRef, expr: Option) -> ast::RecordExprField { return match expr { - Some(expr) => from_text(&format!("{}: {}", name, expr)), + Some(expr) => from_text(&format!("{name}: {expr}")), None => from_text(&name.to_string()), }; fn from_text(text: &str) -> ast::RecordExprField { - ast_from_text(&format!("fn f() {{ S {{ {}, }} }}", text)) + ast_from_text(&format!("fn f() {{ S {{ {text}, }} }}")) } } @@ -311,9 +313,9 @@ pub fn record_field( ) -> ast::RecordField { let visibility = match visibility { None => String::new(), - Some(it) => format!("{} ", it), + Some(it) => format!("{it} "), }; - ast_from_text(&format!("struct S {{ {}{}: {}, }}", visibility, name, ty)) + ast_from_text(&format!("struct S {{ {visibility}{name}: {ty}, }}")) } // TODO @@ -323,13 +325,13 @@ pub fn block_expr( ) -> ast::BlockExpr { let mut buf = "{\n".to_string(); for stmt in stmts.into_iter() { - format_to!(buf, " {}\n", stmt); + format_to!(buf, " {stmt}\n"); } if let Some(tail_expr) = tail_expr { - format_to!(buf, " {}\n", tail_expr); + format_to!(buf, " {tail_expr}\n"); } buf += "}"; - ast_from_text(&format!("fn f() {}", buf)) + ast_from_text(&format!("fn f() {buf}")) } /// Ideally this function wouldn't exist since it involves manual indenting. @@ -343,18 +345,18 @@ pub fn hacky_block_expr_with_comments( let mut buf = "{\n".to_string(); for node_or_token in elements.into_iter() { match node_or_token { - rowan::NodeOrToken::Node(n) => format_to!(buf, " {}\n", n), + rowan::NodeOrToken::Node(n) => format_to!(buf, " {n}\n"), rowan::NodeOrToken::Token(t) if t.kind() == SyntaxKind::COMMENT => { - format_to!(buf, " {}\n", t) + format_to!(buf, " {t}\n") } _ => (), } } if let Some(tail_expr) = tail_expr { - format_to!(buf, " {}\n", tail_expr); + format_to!(buf, " {tail_expr}\n"); } buf += "}"; - ast_from_text(&format!("fn f() {}", buf)) + ast_from_text(&format!("fn f() {buf}")) } pub fn expr_unit() -> ast::Expr { @@ -362,7 +364,7 @@ pub fn expr_unit() -> ast::Expr { } pub fn expr_literal(text: &str) -> ast::Literal { assert_eq!(text.trim(), text); - ast_from_text(&format!("fn f() {{ let _ = {}; }}", text)) + ast_from_text(&format!("fn f() {{ let _ = {text}; }}")) } pub fn expr_empty_block() -> ast::Expr { @@ -373,41 +375,41 @@ pub fn expr_path(path: ast::Path) -> ast::Expr { } pub fn expr_continue(label: Option) -> ast::Expr { match label { - Some(label) => expr_from_text(&format!("continue {}", label)), + Some(label) => expr_from_text(&format!("continue {label}")), None => expr_from_text("continue"), } } // Consider `op: SyntaxKind` instead for nicer syntax at the call-site? pub fn expr_bin_op(lhs: ast::Expr, op: ast::BinaryOp, rhs: ast::Expr) -> ast::Expr { - expr_from_text(&format!("{} {} {}", lhs, op, rhs)) + expr_from_text(&format!("{lhs} {op} {rhs}")) } pub fn expr_break(label: Option, expr: Option) -> ast::Expr { let mut s = String::from("break"); if let Some(label) = label { - format_to!(s, " {}", label); + format_to!(s, " {label}"); } if let Some(expr) = expr { - format_to!(s, " {}", expr); + format_to!(s, " {expr}"); } expr_from_text(&s) } pub fn expr_return(expr: Option) -> ast::Expr { match expr { - Some(expr) => expr_from_text(&format!("return {}", expr)), + Some(expr) => expr_from_text(&format!("return {expr}")), None => expr_from_text("return"), } } pub fn expr_try(expr: ast::Expr) -> ast::Expr { - expr_from_text(&format!("{}?", expr)) + expr_from_text(&format!("{expr}?")) } pub fn expr_await(expr: ast::Expr) -> ast::Expr { - expr_from_text(&format!("{}.await", expr)) + expr_from_text(&format!("{expr}.await")) } pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::Expr { - expr_from_text(&format!("match {} {}", expr, match_arm_list)) + expr_from_text(&format!("match {expr} {match_arm_list}")) } pub fn expr_if( condition: ast::Expr, @@ -415,66 +417,67 @@ pub fn expr_if( else_branch: Option, ) -> ast::Expr { let else_branch = match else_branch { - Some(ast::ElseBranch::Block(block)) => format!("else {}", block), - Some(ast::ElseBranch::IfExpr(if_expr)) => format!("else {}", if_expr), + Some(ast::ElseBranch::Block(block)) => format!("else {block}"), + Some(ast::ElseBranch::IfExpr(if_expr)) => format!("else {if_expr}"), None => String::new(), }; - expr_from_text(&format!("if {} {} {}", condition, then_branch, else_branch)) + expr_from_text(&format!("if {condition} {then_branch} {else_branch}")) } pub fn expr_for_loop(pat: ast::Pat, expr: ast::Expr, block: ast::BlockExpr) -> ast::Expr { - expr_from_text(&format!("for {} in {} {}", pat, expr, block)) + expr_from_text(&format!("for {pat} in {expr} {block}")) } pub fn expr_loop(block: ast::BlockExpr) -> ast::Expr { - expr_from_text(&format!("loop {}", block)) + expr_from_text(&format!("loop {block}")) } pub fn expr_prefix(op: SyntaxKind, expr: ast::Expr) -> ast::Expr { let token = token(op); - expr_from_text(&format!("{}{}", token, expr)) + expr_from_text(&format!("{token}{expr}")) } pub fn expr_call(f: ast::Expr, arg_list: ast::ArgList) -> ast::Expr { - expr_from_text(&format!("{}{}", f, arg_list)) + expr_from_text(&format!("{f}{arg_list}")) } pub fn expr_method_call( receiver: ast::Expr, method: ast::NameRef, arg_list: ast::ArgList, ) -> ast::Expr { - expr_from_text(&format!("{}.{}{}", receiver, method, arg_list)) + expr_from_text(&format!("{receiver}.{method}{arg_list}")) } pub fn expr_macro_call(f: ast::Expr, arg_list: ast::ArgList) -> ast::Expr { - expr_from_text(&format!("{}!{}", f, arg_list)) + expr_from_text(&format!("{f}!{arg_list}")) } pub fn expr_ref(expr: ast::Expr, exclusive: bool) -> ast::Expr { - expr_from_text(&if exclusive { format!("&mut {}", expr) } else { format!("&{}", expr) }) + expr_from_text(&if exclusive { format!("&mut {expr}") } else { format!("&{expr}") }) } pub fn expr_closure(pats: impl IntoIterator, expr: ast::Expr) -> ast::Expr { let params = pats.into_iter().join(", "); - expr_from_text(&format!("|{}| {}", params, expr)) + expr_from_text(&format!("|{params}| {expr}")) } pub fn expr_field(receiver: ast::Expr, field: &str) -> ast::Expr { - expr_from_text(&format!("{}.{}", receiver, field)) + expr_from_text(&format!("{receiver}.{field}")) } pub fn expr_paren(expr: ast::Expr) -> ast::Expr { - expr_from_text(&format!("({})", expr)) + expr_from_text(&format!("({expr})")) } pub fn expr_tuple(elements: impl IntoIterator) -> ast::Expr { let expr = elements.into_iter().format(", "); - expr_from_text(&format!("({})", expr)) + expr_from_text(&format!("({expr})")) } pub fn expr_assignment(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr { - expr_from_text(&format!("{} = {}", lhs, rhs)) + expr_from_text(&format!("{lhs} = {rhs}")) } fn expr_from_text(text: &str) -> ast::Expr { - ast_from_text(&format!("const C: () = {};", text)) + ast_from_text(&format!("const C: () = {text};")) } pub fn expr_let(pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr { - ast_from_text(&format!("const _: () = while let {} = {} {{}};", pattern, expr)) + ast_from_text(&format!("const _: () = while let {pattern} = {expr} {{}};")) } pub fn arg_list(args: impl IntoIterator) -> ast::ArgList { - ast_from_text(&format!("fn main() {{ ()({}) }}", args.into_iter().format(", "))) + let args = args.into_iter().format(", "); + ast_from_text(&format!("fn main() {{ ()({args}) }}")) } pub fn ident_pat(ref_: bool, mut_: bool, name: ast::Name) -> ast::IdentPat { @@ -485,7 +488,7 @@ pub fn ident_pat(ref_: bool, mut_: bool, name: ast::Name) -> ast::IdentPat { if mut_ { s.push_str("mut "); } - format_to!(s, "{}", name); + format_to!(s, "{name}"); s.push_str(": ())"); ast_from_text(&s) } @@ -494,7 +497,7 @@ pub fn wildcard_pat() -> ast::WildcardPat { return from_text("_"); fn from_text(text: &str) -> ast::WildcardPat { - ast_from_text(&format!("fn f({}: ())", text)) + ast_from_text(&format!("fn f({text}: ())")) } } @@ -502,7 +505,7 @@ pub fn literal_pat(lit: &str) -> ast::LiteralPat { return from_text(lit); fn from_text(text: &str) -> ast::LiteralPat { - ast_from_text(&format!("fn f() {{ match x {{ {} => {{}} }} }}", text)) + ast_from_text(&format!("fn f() {{ match x {{ {text} => {{}} }} }}")) } } @@ -515,10 +518,10 @@ pub fn tuple_pat(pats: impl IntoIterator) -> ast::TuplePat { if count == 1 { pats_str.push(','); } - return from_text(&format!("({})", pats_str)); + return from_text(&format!("({pats_str})")); fn from_text(text: &str) -> ast::TuplePat { - ast_from_text(&format!("fn f({}: ())", text)) + ast_from_text(&format!("fn f({text}: ())")) } } @@ -527,46 +530,46 @@ pub fn tuple_struct_pat( pats: impl IntoIterator, ) -> ast::TupleStructPat { let pats_str = pats.into_iter().join(", "); - return from_text(&format!("{}({})", path, pats_str)); + return from_text(&format!("{path}({pats_str})")); fn from_text(text: &str) -> ast::TupleStructPat { - ast_from_text(&format!("fn f({}: ())", text)) + ast_from_text(&format!("fn f({text}: ())")) } } pub fn record_pat(path: ast::Path, pats: impl IntoIterator) -> ast::RecordPat { let pats_str = pats.into_iter().join(", "); - return from_text(&format!("{} {{ {} }}", path, pats_str)); + return from_text(&format!("{path} {{ {pats_str} }}")); fn from_text(text: &str) -> ast::RecordPat { - ast_from_text(&format!("fn f({}: ())", text)) + ast_from_text(&format!("fn f({text}: ())")) } } pub fn record_pat_with_fields(path: ast::Path, fields: ast::RecordPatFieldList) -> ast::RecordPat { - ast_from_text(&format!("fn f({} {}: ()))", path, fields)) + ast_from_text(&format!("fn f({path} {fields}: ()))")) } pub fn record_pat_field_list( fields: impl IntoIterator, ) -> ast::RecordPatFieldList { let fields = fields.into_iter().join(", "); - ast_from_text(&format!("fn f(S {{ {} }}: ()))", fields)) + ast_from_text(&format!("fn f(S {{ {fields} }}: ()))")) } pub fn record_pat_field(name_ref: ast::NameRef, pat: ast::Pat) -> ast::RecordPatField { - ast_from_text(&format!("fn f(S {{ {}: {} }}: ()))", name_ref, pat)) + ast_from_text(&format!("fn f(S {{ {name_ref}: {pat} }}: ()))")) } pub fn record_pat_field_shorthand(name_ref: ast::NameRef) -> ast::RecordPatField { - ast_from_text(&format!("fn f(S {{ {} }}: ()))", name_ref)) + ast_from_text(&format!("fn f(S {{ {name_ref} }}: ()))")) } /// Returns a `BindPat` if the path has just one segment, a `PathPat` otherwise. pub fn path_pat(path: ast::Path) -> ast::Pat { return from_text(&path.to_string()); fn from_text(text: &str) -> ast::Pat { - ast_from_text(&format!("fn f({}: ())", text)) + ast_from_text(&format!("fn f({text}: ())")) } } @@ -577,12 +580,12 @@ pub fn match_arm( ) -> ast::MatchArm { let pats_str = pats.into_iter().join(" | "); return match guard { - Some(guard) => from_text(&format!("{} if {} => {}", pats_str, guard, expr)), - None => from_text(&format!("{} => {}", pats_str, expr)), + Some(guard) => from_text(&format!("{pats_str} if {guard} => {expr}")), + None => from_text(&format!("{pats_str} => {expr}")), }; fn from_text(text: &str) -> ast::MatchArm { - ast_from_text(&format!("fn f() {{ match () {{{}}} }}", text)) + ast_from_text(&format!("fn f() {{ match () {{{text}}} }}")) } } @@ -592,10 +595,10 @@ pub fn match_arm_with_guard( expr: ast::Expr, ) -> ast::MatchArm { let pats_str = pats.into_iter().join(" | "); - return from_text(&format!("{} if {} => {}", pats_str, guard, expr)); + return from_text(&format!("{pats_str} if {guard} => {expr}")); fn from_text(text: &str) -> ast::MatchArm { - ast_from_text(&format!("fn f() {{ match () {{{}}} }}", text)) + ast_from_text(&format!("fn f() {{ match () {{{text}}} }}")) } } @@ -605,13 +608,14 @@ pub fn match_arm_list(arms: impl IntoIterator) -> ast::Mat .map(|arm| { let needs_comma = arm.expr().map_or(true, |it| !it.is_block_like()); let comma = if needs_comma { "," } else { "" }; - format!(" {}{}\n", arm.syntax(), comma) + let arm = arm.syntax(); + format!(" {arm}{comma}\n") }) .collect::(); return from_text(&arms_str); fn from_text(text: &str) -> ast::MatchArmList { - ast_from_text(&format!("fn f() {{ match () {{\n{}}} }}", text)) + ast_from_text(&format!("fn f() {{ match () {{\n{text}}} }}")) } } @@ -620,10 +624,10 @@ pub fn where_pred( bounds: impl IntoIterator, ) -> ast::WherePred { let bounds = bounds.into_iter().join(" + "); - return from_text(&format!("{}: {}", path, bounds)); + return from_text(&format!("{path}: {bounds}")); fn from_text(text: &str) -> ast::WherePred { - ast_from_text(&format!("fn f() where {} {{ }}", text)) + ast_from_text(&format!("fn f() where {text} {{ }}")) } } @@ -632,7 +636,7 @@ pub fn where_clause(preds: impl IntoIterator) -> ast::Whe return from_text(preds.as_str()); fn from_text(text: &str) -> ast::WhereClause { - ast_from_text(&format!("fn f() where {} {{ }}", text)) + ast_from_text(&format!("fn f() where {text} {{ }}")) } } @@ -642,19 +646,19 @@ pub fn let_stmt( initializer: Option, ) -> ast::LetStmt { let mut text = String::new(); - format_to!(text, "let {}", pattern); + format_to!(text, "let {pattern}"); if let Some(ty) = ty { - format_to!(text, ": {}", ty); + format_to!(text, ": {ty}"); } match initializer { - Some(it) => format_to!(text, " = {};", it), + Some(it) => format_to!(text, " = {it};"), None => format_to!(text, ";"), }; - ast_from_text(&format!("fn f() {{ {} }}", text)) + ast_from_text(&format!("fn f() {{ {text} }}")) } pub fn expr_stmt(expr: ast::Expr) -> ast::ExprStmt { let semi = if expr.is_block_like() { "" } else { ";" }; - ast_from_text(&format!("fn f() {{ {}{} (); }}", expr, semi)) + ast_from_text(&format!("fn f() {{ {expr}{semi} (); }}")) } pub fn item_const( @@ -665,13 +669,13 @@ pub fn item_const( ) -> ast::Const { let visibility = match visibility { None => String::new(), - Some(it) => format!("{} ", it), + Some(it) => format!("{it} "), }; - ast_from_text(&format!("{} const {}: {} = {};", visibility, name, ty, expr)) + ast_from_text(&format!("{visibility} const {name}: {ty} = {expr};")) } pub fn param(pat: ast::Pat, ty: ast::Type) -> ast::Param { - ast_from_text(&format!("fn f({}: {}) {{ }}", pat, ty)) + ast_from_text(&format!("fn f({pat}: {ty}) {{ }}")) } pub fn self_param() -> ast::SelfParam { @@ -679,7 +683,7 @@ pub fn self_param() -> ast::SelfParam { } pub fn ret_type(ty: ast::Type) -> ast::RetType { - ast_from_text(&format!("fn f() -> {} {{ }}", ty)) + ast_from_text(&format!("fn f() -> {ty} {{ }}")) } pub fn param_list( @@ -688,30 +692,30 @@ pub fn param_list( ) -> ast::ParamList { let args = pats.into_iter().join(", "); let list = match self_param { - Some(self_param) if args.is_empty() => format!("fn f({}) {{ }}", self_param), - Some(self_param) => format!("fn f({}, {}) {{ }}", self_param, args), - None => format!("fn f({}) {{ }}", args), + Some(self_param) if args.is_empty() => format!("fn f({self_param}) {{ }}"), + Some(self_param) => format!("fn f({self_param}, {args}) {{ }}"), + None => format!("fn f({args}) {{ }}"), }; ast_from_text(&list) } pub fn type_param(name: ast::Name, ty: Option) -> ast::TypeParam { let bound = match ty { - Some(it) => format!(": {}", it), + Some(it) => format!(": {it}"), None => String::new(), }; - ast_from_text(&format!("fn f<{}{}>() {{ }}", name, bound)) + ast_from_text(&format!("fn f<{name}{bound}>() {{ }}")) } pub fn lifetime_param(lifetime: ast::Lifetime) -> ast::LifetimeParam { - ast_from_text(&format!("fn f<{}>() {{ }}", lifetime)) + ast_from_text(&format!("fn f<{lifetime}>() {{ }}")) } pub fn generic_param_list( pats: impl IntoIterator, ) -> ast::GenericParamList { let args = pats.into_iter().join(", "); - ast_from_text(&format!("fn f<{}>() {{ }}", args)) + ast_from_text(&format!("fn f<{args}>() {{ }}")) } pub fn visibility_pub_crate() -> ast::Visibility { @@ -724,33 +728,33 @@ pub fn visibility_pub() -> ast::Visibility { pub fn tuple_field_list(fields: impl IntoIterator) -> ast::TupleFieldList { let fields = fields.into_iter().join(", "); - ast_from_text(&format!("struct f({});", fields)) + ast_from_text(&format!("struct f({fields});")) } pub fn record_field_list( fields: impl IntoIterator, ) -> ast::RecordFieldList { let fields = fields.into_iter().join(", "); - ast_from_text(&format!("struct f {{ {} }}", fields)) + ast_from_text(&format!("struct f {{ {fields} }}")) } pub fn tuple_field(visibility: Option, ty: ast::Type) -> ast::TupleField { let visibility = match visibility { None => String::new(), - Some(it) => format!("{} ", it), + Some(it) => format!("{it} "), }; - ast_from_text(&format!("struct f({}{});", visibility, ty)) + ast_from_text(&format!("struct f({visibility}{ty});")) } pub fn variant(name: ast::Name, field_list: Option) -> ast::Variant { let field_list = match field_list { None => String::new(), Some(it) => match it { - ast::FieldList::RecordFieldList(record) => format!(" {}", record), - ast::FieldList::TupleFieldList(tuple) => format!("{}", tuple), + ast::FieldList::RecordFieldList(record) => format!(" {record}"), + ast::FieldList::TupleFieldList(tuple) => format!("{tuple}"), }, }; - ast_from_text(&format!("enum f {{ {}{} }}", name, field_list)) + ast_from_text(&format!("enum f {{ {name}{field_list} }}")) } pub fn fn_( @@ -763,23 +767,22 @@ pub fn fn_( is_async: bool, ) -> ast::Fn { let type_params = match type_params { - Some(type_params) => format!("{}", type_params), + Some(type_params) => format!("{type_params}"), None => "".into(), }; let ret_type = match ret_type { - Some(ret_type) => format!("{} ", ret_type), + Some(ret_type) => format!("{ret_type} "), None => "".into(), }; let visibility = match visibility { None => String::new(), - Some(it) => format!("{} ", it), + Some(it) => format!("{it} "), }; let async_literal = if is_async { "async " } else { "" }; ast_from_text(&format!( - "{}{}fn {}{}{} {}{}", - visibility, async_literal, fn_name, type_params, params, ret_type, body + "{visibility}{async_literal}fn {fn_name}{type_params}{params} {ret_type}{body}", )) } @@ -793,13 +796,10 @@ pub fn struct_( let type_params = generic_param_list.map_or_else(String::new, |it| it.to_string()); let visibility = match visibility { None => String::new(), - Some(it) => format!("{} ", it), + Some(it) => format!("{it} "), }; - ast_from_text(&format!( - "{}struct {}{}{}{}", - visibility, strukt_name, type_params, field_list, semicolon - )) + ast_from_text(&format!("{visibility}struct {strukt_name}{type_params}{field_list}{semicolon}",)) } #[track_caller] @@ -808,7 +808,8 @@ fn ast_from_text(text: &str) -> N { let node = match parse.tree().syntax().descendants().find_map(N::cast) { Some(it) => it, None => { - panic!("Failed to make ast node `{}` from text {}", std::any::type_name::(), text) + let node = std::any::type_name::(); + panic!("Failed to make ast node `{node}` from text {text}") } }; let node = node.clone_subtree(); @@ -824,7 +825,7 @@ pub fn token(kind: SyntaxKind) -> SyntaxToken { .descendants_with_tokens() .filter_map(|it| it.into_token()) .find(|it| it.kind() == kind) - .unwrap_or_else(|| panic!("unhandled token: {:?}", kind)) + .unwrap_or_else(|| panic!("unhandled token: {kind:?}")) } pub mod tokens { @@ -863,7 +864,7 @@ pub mod tokens { pub fn literal(text: &str) -> SyntaxToken { assert_eq!(text.trim(), text); - let lit: ast::Literal = super::ast_from_text(&format!("fn f() {{ let _ = {}; }}", text)); + let lit: ast::Literal = super::ast_from_text(&format!("fn f() {{ let _ = {text}; }}")); lit.syntax().first_child_or_token().unwrap().into_token().unwrap() } From 14e72e7ffaef3880279e9f3d2fef7dcf8fc5cb5b Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 22 May 2022 19:39:09 -0400 Subject: [PATCH 3765/5092] Improve information sharing across SB diagnostics Previous Stacked Borrows diagnostics were missing a lot of information about the state of the interpreter, and it was difficult to add additional state because it was threaded through all the intervening function signatures. This change factors a lot of the arguments which used to be passed individually to many stacked borrows functions into a single `DiagnosticCx`, which is built in `Stacks::for_each`, and since it wraps a handle to `AllocHistory`, we can now handle more nuanced things like heterogeneous borrow of `!Freeze` types. --- src/diagnostics.rs | 21 +- src/helpers.rs | 52 +- src/machine.rs | 26 +- src/stacked_borrows/diagnostics.rs | 512 ++++++++++++++---- src/stacked_borrows/mod.rs | 351 ++++-------- tests/fail/box-cell-alias.stderr | 10 +- .../alias_through_mutation.stderr | 4 +- .../fail/stacked_borrows/aliasing_mut1.stderr | 2 +- .../fail/stacked_borrows/aliasing_mut2.stderr | 2 +- .../fail/stacked_borrows/aliasing_mut3.stderr | 14 +- .../fail/stacked_borrows/aliasing_mut4.stderr | 2 +- .../box_exclusive_violation1.stderr | 4 +- .../stacked_borrows/buggy_as_mut_slice.stderr | 4 +- .../stacked_borrows/buggy_split_at_mut.rs | 2 +- .../stacked_borrows/buggy_split_at_mut.stderr | 10 +- .../stacked_borrows/fnentry_invalidation.rs | 20 + .../fnentry_invalidation.stderr | 28 + .../fail/stacked_borrows/illegal_read1.stderr | 4 +- .../fail/stacked_borrows/illegal_read2.stderr | 4 +- .../fail/stacked_borrows/illegal_read3.stderr | 4 +- .../fail/stacked_borrows/illegal_read4.stderr | 4 +- .../fail/stacked_borrows/illegal_read5.stderr | 4 +- .../fail/stacked_borrows/illegal_read6.stderr | 4 +- tests/fail/stacked_borrows/illegal_read7.rs | 2 +- .../fail/stacked_borrows/illegal_read7.stderr | 10 +- .../fail/stacked_borrows/illegal_read8.stderr | 4 +- .../illegal_read_despite_exposed1.stderr | 10 + .../illegal_read_despite_exposed2.stderr | 10 + .../stacked_borrows/illegal_write1.stderr | 2 +- .../stacked_borrows/illegal_write2.stderr | 4 +- .../stacked_borrows/illegal_write3.stderr | 2 +- .../stacked_borrows/illegal_write4.stderr | 4 +- .../stacked_borrows/illegal_write5.stderr | 4 +- .../stacked_borrows/illegal_write6.stderr | 2 +- .../illegal_write_despite_exposed1.stderr | 10 + tests/fail/stacked_borrows/interior_mut1.rs | 2 +- .../fail/stacked_borrows/interior_mut1.stderr | 10 +- tests/fail/stacked_borrows/interior_mut2.rs | 2 +- .../fail/stacked_borrows/interior_mut2.stderr | 10 +- .../invalidate_against_barrier1.stderr | 2 +- .../invalidate_against_barrier2.stderr | 2 +- .../fail/stacked_borrows/load_invalid_mut.rs | 2 +- .../stacked_borrows/load_invalid_mut.stderr | 10 +- .../fail/stacked_borrows/load_invalid_shr.rs | 2 +- .../stacked_borrows/load_invalid_shr.stderr | 10 +- .../mut_exclusive_violation1.stderr | 4 +- .../mut_exclusive_violation2.stderr | 4 +- .../stacked_borrows/newtype_retagging.stderr | 2 +- .../stacked_borrows/outdated_local.stderr | 4 +- .../fail/stacked_borrows/pass_invalid_mut.rs | 2 +- .../stacked_borrows/pass_invalid_mut.stderr | 10 +- .../fail/stacked_borrows/pass_invalid_shr.rs | 2 +- .../stacked_borrows/pass_invalid_shr.stderr | 10 +- .../stacked_borrows/pointer_smuggling.stderr | 4 +- .../fail/stacked_borrows/raw_tracking.stderr | 4 +- .../stacked_borrows/return_invalid_mut.rs | 2 +- .../stacked_borrows/return_invalid_mut.stderr | 10 +- .../return_invalid_mut_option.rs | 2 +- .../return_invalid_mut_option.stderr | 10 +- .../return_invalid_mut_tuple.rs | 2 +- .../return_invalid_mut_tuple.stderr | 10 +- .../stacked_borrows/return_invalid_shr.rs | 2 +- .../stacked_borrows/return_invalid_shr.stderr | 10 +- .../return_invalid_shr_option.rs | 2 +- .../return_invalid_shr_option.stderr | 10 +- .../return_invalid_shr_tuple.rs | 2 +- .../return_invalid_shr_tuple.stderr | 10 +- .../shared_rw_borrows_are_weak1.rs | 2 +- .../shared_rw_borrows_are_weak1.stderr | 10 +- .../shared_rw_borrows_are_weak2.stderr | 4 +- .../shr_frozen_violation1.stderr | 2 +- tests/fail/stacked_borrows/track_caller.rs | 17 + .../fail/stacked_borrows/track_caller.stderr | 28 + .../transmute-is-no-escape.stderr | 2 +- .../stacked_borrows/unescaped_static.stderr | 2 +- tests/fail/stacked_borrows/zst_slice.rs | 2 +- tests/fail/stacked_borrows/zst_slice.stderr | 8 +- 77 files changed, 877 insertions(+), 522 deletions(-) create mode 100644 tests/fail/stacked_borrows/fnentry_invalidation.rs create mode 100644 tests/fail/stacked_borrows/fnentry_invalidation.stderr create mode 100644 tests/fail/stacked_borrows/track_caller.rs create mode 100644 tests/fail/stacked_borrows/track_caller.stderr diff --git a/src/diagnostics.rs b/src/diagnostics.rs index a378df0ad82b..eafe56955d1f 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -178,20 +178,15 @@ pub fn report_error<'tcx, 'mir>( (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental")), (None, format!("see {url} for further information")), ]; - match history { - Some(TagHistory::Tagged {tag, created: (created_range, created_span), invalidated, protected }) => { - let msg = format!("{tag:?} was created by a retag at offsets {created_range:?}"); - helps.push((Some(*created_span), msg)); - if let Some((invalidated_range, invalidated_span)) = invalidated { - let msg = format!("{tag:?} was later invalidated at offsets {invalidated_range:?}"); - helps.push((Some(*invalidated_span), msg)); - } - if let Some((protecting_tag, protecting_tag_span, protection_span)) = protected { - helps.push((Some(*protecting_tag_span), format!("{tag:?} was protected due to {protecting_tag:?} which was created here"))); - helps.push((Some(*protection_span), format!("this protector is live for this call"))); - } + if let Some(TagHistory {created, invalidated, protected}) = history.clone() { + helps.push((Some(created.1), created.0)); + if let Some((msg, span)) = invalidated { + helps.push((Some(span), msg)); + } + if let Some([(protector_msg, protector_span), (protection_msg, protection_span)]) = protected { + helps.push((Some(protector_span), protector_msg)); + helps.push((Some(protection_span), protection_msg)); } - None => {} } helps } diff --git a/src/helpers.rs b/src/helpers.rs index d63bf97ad51d..6f6cbcc38a77 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -876,8 +876,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { - pub fn current_span(&self) -> CurrentSpan<'_, 'mir, 'tcx> { - CurrentSpan { span: None, machine: self } + pub fn current_span(&self, tcx: TyCtxt<'tcx>) -> CurrentSpan<'_, 'mir, 'tcx> { + CurrentSpan { span: None, machine: self, tcx } } } @@ -888,27 +888,61 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { #[derive(Clone)] pub struct CurrentSpan<'a, 'mir, 'tcx> { span: Option, + tcx: TyCtxt<'tcx>, machine: &'a Evaluator<'mir, 'tcx>, } -impl<'a, 'mir, 'tcx> CurrentSpan<'a, 'mir, 'tcx> { +impl<'a, 'mir: 'a, 'tcx: 'a + 'mir> CurrentSpan<'a, 'mir, 'tcx> { + /// Get the current span, skipping non-local frames. + /// This function is backed by a cache, and can be assumed to be very fast. pub fn get(&mut self) -> Span { - *self.span.get_or_insert_with(|| Self::current_span(self.machine)) + *self.span.get_or_insert_with(|| Self::current_span(self.tcx, self.machine)) + } + + /// Similar to `CurrentSpan::get`, but retrieves the parent frame of the first non-local frame. + /// This is useful when we are processing something which occurs on function-entry and we want + /// to point at the call to the function, not the function definition generally. + #[inline(never)] + pub fn get_parent(&mut self) -> Span { + let idx = Self::current_span_index(self.tcx, self.machine); + Self::nth_span(self.machine, idx.wrapping_sub(1)) } #[inline(never)] - fn current_span(machine: &Evaluator<'_, '_>) -> Span { + fn current_span(tcx: TyCtxt<'_>, machine: &Evaluator<'_, '_>) -> Span { + let idx = Self::current_span_index(tcx, machine); + Self::nth_span(machine, idx) + } + + fn nth_span(machine: &Evaluator<'_, '_>, idx: usize) -> Span { + machine + .threads + .active_thread_stack() + .get(idx) + .map(Frame::current_span) + .unwrap_or(rustc_span::DUMMY_SP) + } + + // Find the position of the inner-most frame which is part of the crate being + // compiled/executed, part of the Cargo workspace, and is also not #[track_caller]. + fn current_span_index(tcx: TyCtxt<'_>, machine: &Evaluator<'_, '_>) -> usize { machine .threads .active_thread_stack() .iter() + .enumerate() .rev() - .find(|frame| { + .find_map(|(idx, frame)| { let def_id = frame.instance.def_id(); - def_id.is_local() || machine.local_crates.contains(&def_id.krate) + if (def_id.is_local() || machine.local_crates.contains(&def_id.krate)) + && !frame.instance.def.requires_caller_location(tcx) + { + Some(idx) + } else { + None + } }) - .map(|frame| frame.current_span()) - .unwrap_or(rustc_span::DUMMY_SP) + .unwrap_or(0) } } diff --git a/src/machine.rs b/src/machine.rs index 4dc091606739..7357731f3592 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -137,7 +137,7 @@ pub enum Provenance { } /// The "extra" information a pointer has over a regular AllocId. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, PartialEq)] pub enum ProvenanceExtra { Concrete(SbTag), Wildcard, @@ -706,15 +706,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } let alloc = alloc.into_owned(); - let stacks = ecx.machine.stacked_borrows.as_ref().map(|stacked_borrows| { - Stacks::new_allocation( - id, - alloc.size(), - stacked_borrows, - kind, - ecx.machine.current_span(), - ) - }); + let stacks = + ecx.machine.stacked_borrows.as_ref().map(|stacked_borrows| { + Stacks::new_allocation(id, alloc.size(), stacked_borrows, kind) + }); let race_alloc = ecx.machine.data_race.as_ref().map(|data_race| { data_race::AllocExtra::new_allocation( data_race, @@ -808,7 +803,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn before_memory_read( - _tcx: TyCtxt<'tcx>, + tcx: TyCtxt<'tcx>, machine: &Self, alloc_extra: &AllocExtra, (alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra), @@ -828,7 +823,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { prov_extra, range, machine.stacked_borrows.as_ref().unwrap(), - machine.current_span(), + machine.current_span(tcx), &machine.threads, )?; } @@ -840,7 +835,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn before_memory_write( - _tcx: TyCtxt<'tcx>, + tcx: TyCtxt<'tcx>, machine: &mut Self, alloc_extra: &mut AllocExtra, (alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra), @@ -860,7 +855,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { prov_extra, range, machine.stacked_borrows.as_ref().unwrap(), - machine.current_span(), + machine.current_span(tcx), &machine.threads, )?; } @@ -872,7 +867,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn before_memory_deallocation( - _tcx: TyCtxt<'tcx>, + tcx: TyCtxt<'tcx>, machine: &mut Self, alloc_extra: &mut AllocExtra, (alloc_id, prove_extra): (AllocId, Self::ProvenanceExtra), @@ -895,6 +890,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { prove_extra, range, machine.stacked_borrows.as_ref().unwrap(), + machine.current_span(tcx), &machine.threads, ) } else { diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index 6521f0772112..ac2783670cff 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -1,91 +1,294 @@ use smallvec::SmallVec; +use std::fmt; -use rustc_middle::mir::interpret::{AllocId, AllocRange}; +use rustc_middle::mir::interpret::{alloc_range, AllocId, AllocRange}; use rustc_span::{Span, SpanData}; use rustc_target::abi::Size; use crate::helpers::CurrentSpan; -use crate::stacked_borrows::{err_sb_ub, AccessKind}; +use crate::stacked_borrows::{err_sb_ub, AccessKind, GlobalStateInner, Permission}; use crate::*; use rustc_middle::mir::interpret::InterpError; #[derive(Clone, Debug)] pub struct AllocHistory { - // The time tags can be compressed down to one bit per event, by just storing a Vec - // where each bit is set to indicate if the event was a creation or a retag - current_time: usize, - creations: smallvec::SmallVec<[Event; 2]>, - invalidations: smallvec::SmallVec<[Event; 1]>, + id: AllocId, + creations: smallvec::SmallVec<[Creation; 1]>, + invalidations: smallvec::SmallVec<[Invalidation; 1]>, protectors: smallvec::SmallVec<[Protection; 1]>, } #[derive(Clone, Debug)] -struct Protection { - orig_tag: SbTag, - tag: SbTag, +struct Creation { + retag: RetagOp, span: Span, } +impl Creation { + fn generate_diagnostic(&self) -> (String, SpanData) { + let tag = self.retag.new_tag; + if let Some(perm) = self.retag.permission { + ( + format!( + "{tag:?} was created by a {:?} retag at offsets {:?}", + perm, self.retag.range, + ), + self.span.data(), + ) + } else { + assert!(self.retag.range.size == Size::ZERO); + ( + format!( + "{tag:?} would have been created here, but this is a zero-size retag ({:?}) so the tag in question does not exist anywhere", + self.retag.range, + ), + self.span.data(), + ) + } + } +} + #[derive(Clone, Debug)] -struct Event { - parent: Option, +struct Invalidation { tag: SbTag, range: AllocRange, span: Span, + cause: InvalidationCause, } -pub enum TagHistory { - Tagged { - tag: SbTag, - created: (AllocRange, SpanData), - invalidated: Option<(AllocRange, SpanData)>, - protected: Option<(SbTag, SpanData, SpanData)>, - }, +#[derive(Clone, Debug)] +enum InvalidationCause { + Access(AccessKind), + Retag(Permission, RetagCause), +} + +impl Invalidation { + fn generate_diagnostic(&self) -> (String, SpanData) { + ( + format!( + "{:?} was later invalidated at offsets {:?} by a {}", + self.tag, self.range, self.cause + ), + self.span.data(), + ) + } +} + +impl fmt::Display for InvalidationCause { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + InvalidationCause::Access(kind) => write!(f, "{}", kind), + InvalidationCause::Retag(perm, kind) => + if *kind == RetagCause::FnEntry { + write!(f, "{:?} FnEntry retag", perm) + } else { + write!(f, "{:?} retag", perm) + }, + } + } +} + +#[derive(Clone, Debug)] +struct Protection { + orig_tag: ProvenanceExtra, + tag: SbTag, + span: Span, +} + +#[derive(Clone)] +pub struct TagHistory { + pub created: (String, SpanData), + pub invalidated: Option<(String, SpanData)>, + pub protected: Option<([(String, SpanData); 2])>, +} + +pub struct DiagnosticCxBuilder<'ecx, 'mir, 'tcx> { + operation: Operation, + current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + threads: &'ecx ThreadManager<'mir, 'tcx>, +} + +pub struct DiagnosticCx<'ecx, 'mir, 'tcx, 'history> { + operation: Operation, + current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + threads: &'ecx ThreadManager<'mir, 'tcx>, + history: &'history mut AllocHistory, + offset: Size, +} + +impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCxBuilder<'ecx, 'mir, 'tcx> { + pub fn build( + self, + history: &'history mut AllocHistory, + offset: Size, + ) -> DiagnosticCx<'ecx, 'mir, 'tcx, 'history> { + DiagnosticCx { + operation: self.operation, + current_span: self.current_span, + threads: self.threads, + history, + offset, + } + } + + pub fn retag( + current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + threads: &'ecx ThreadManager<'mir, 'tcx>, + cause: RetagCause, + new_tag: SbTag, + orig_tag: ProvenanceExtra, + range: AllocRange, + ) -> Self { + let operation = + Operation::Retag(RetagOp { cause, new_tag, orig_tag, range, permission: None }); + + DiagnosticCxBuilder { current_span, threads, operation } + } + + pub fn read( + current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + threads: &'ecx ThreadManager<'mir, 'tcx>, + tag: ProvenanceExtra, + range: AllocRange, + ) -> Self { + let operation = Operation::Access(AccessOp { kind: AccessKind::Read, tag, range }); + DiagnosticCxBuilder { current_span, threads, operation } + } + + pub fn write( + current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + threads: &'ecx ThreadManager<'mir, 'tcx>, + tag: ProvenanceExtra, + range: AllocRange, + ) -> Self { + let operation = Operation::Access(AccessOp { kind: AccessKind::Write, tag, range }); + DiagnosticCxBuilder { current_span, threads, operation } + } + + pub fn dealloc( + current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + threads: &'ecx ThreadManager<'mir, 'tcx>, + tag: ProvenanceExtra, + ) -> Self { + let operation = Operation::Dealloc(DeallocOp { tag }); + DiagnosticCxBuilder { current_span, threads, operation } + } +} + +impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCx<'ecx, 'mir, 'tcx, 'history> { + pub fn unbuild(self) -> DiagnosticCxBuilder<'ecx, 'mir, 'tcx> { + DiagnosticCxBuilder { + operation: self.operation, + current_span: self.current_span, + threads: self.threads, + } + } +} + +#[derive(Debug, Clone)] +enum Operation { + Retag(RetagOp), + Access(AccessOp), + Dealloc(DeallocOp), +} + +#[derive(Debug, Clone)] +struct RetagOp { + cause: RetagCause, + new_tag: SbTag, + orig_tag: ProvenanceExtra, + range: AllocRange, + permission: Option, +} + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum RetagCause { + Normal, + FnReturn, + FnEntry, + TwoPhase, +} + +#[derive(Debug, Clone)] +struct AccessOp { + kind: AccessKind, + tag: ProvenanceExtra, + range: AllocRange, +} + +#[derive(Debug, Clone)] +struct DeallocOp { + tag: ProvenanceExtra, } impl AllocHistory { - pub fn new() -> Self { + pub fn new(id: AllocId) -> Self { Self { - current_time: 0, + id, creations: SmallVec::new(), invalidations: SmallVec::new(), protectors: SmallVec::new(), } } +} - pub fn log_creation( - &mut self, - parent: Option, - tag: SbTag, - range: AllocRange, - current_span: &mut CurrentSpan<'_, '_, '_>, - ) { - let span = current_span.get(); - self.creations.push(Event { parent, tag, range, span }); - self.current_time += 1; +impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCx<'ecx, 'mir, 'tcx, 'history> { + pub fn start_grant(&mut self, perm: Permission) { + let Operation::Retag(op) = &mut self.operation else { + unreachable!("start_grant must only be called during a retag, this is: {:?}", self.operation) + }; + op.permission = Some(perm); + + let last_creation = &mut self.history.creations.last_mut().unwrap(); + match last_creation.retag.permission { + None => { + last_creation.retag.permission = Some(perm); + } + Some(previous) => + if previous != perm { + let previous_range = last_creation.retag.range; + last_creation.retag.range = alloc_range(previous_range.start, self.offset); + let mut new_event = last_creation.clone(); + new_event.retag.range = alloc_range(self.offset, previous_range.end()); + new_event.retag.permission = Some(perm); + self.history.creations.push(new_event); + }, + } } - pub fn log_invalidation( - &mut self, - tag: SbTag, - range: AllocRange, - current_span: &mut CurrentSpan<'_, '_, '_>, - ) { - let span = current_span.get(); - self.invalidations.push(Event { parent: None, tag, range, span }); - self.current_time += 1; + pub fn log_creation(&mut self) { + let Operation::Retag(op) = &self.operation else { + unreachable!("log_creation must only be called during a retag") + }; + self.history.creations.push(Creation { retag: op.clone(), span: self.current_span.get() }); } - pub fn log_protector( - &mut self, - orig_tag: SbTag, - tag: SbTag, - current_span: &mut CurrentSpan<'_, '_, '_>, - ) { - let span = current_span.get(); - self.protectors.push(Protection { orig_tag, tag, span }); - self.current_time += 1; + pub fn log_invalidation(&mut self, tag: SbTag) { + let mut span = self.current_span.get(); + let (range, cause) = match &self.operation { + Operation::Retag(RetagOp { cause, range, permission, .. }) => { + if *cause == RetagCause::FnEntry { + span = self.current_span.get_parent(); + } + (*range, InvalidationCause::Retag(permission.unwrap(), *cause)) + } + Operation::Access(AccessOp { kind, range, .. }) => + (*range, InvalidationCause::Access(*kind)), + _ => unreachable!("Tags can only be invalidated during a retag or access"), + }; + self.history.invalidations.push(Invalidation { tag, range, span, cause }); + } + + pub fn log_protector(&mut self) { + let Operation::Retag(op) = &self.operation else { + unreachable!("Protectors can only be created during a retag") + }; + self.history.protectors.push(Protection { + orig_tag: op.orig_tag, + tag: op.new_tag, + span: self.current_span.get(), + }); } pub fn get_logs_relevant_to( @@ -93,9 +296,48 @@ impl AllocHistory { tag: SbTag, protector_tag: Option, ) -> Option { + let Some(created) = self.history + .creations + .iter() + .rev() + .find_map(|event| { + // First, look for a Creation event where the tag and the offset matches. This + // ensrues that we pick the right Creation event when a retag isn't uniform due to + // Freeze. + let range = event.retag.range; + if event.retag.new_tag == tag + && self.offset >= range.start + && self.offset < (range.start + range.size) + { + Some(event.generate_diagnostic()) + } else { + None + } + }) + .or_else(|| { + // If we didn't find anything with a matching offset, just return the event where + // the tag was created. This branch is hit when we use a tag at an offset that + // doesn't have the tag. + self.history.creations.iter().rev().find_map(|event| { + if event.retag.new_tag == tag { + Some(event.generate_diagnostic()) + } else { + None + } + }) + }) else { + // But if we don't have a creation event, this is related to a wildcard, and there + // is really nothing we can do to help. + return None; + }; + + let invalidated = self.history.invalidations.iter().rev().find_map(|event| { + if event.tag == tag { Some(event.generate_diagnostic()) } else { None } + }); + let protected = protector_tag .and_then(|protector| { - self.protectors.iter().find_map(|protection| { + self.history.protectors.iter().find_map(|protection| { if protection.tag == protector { Some((protection.orig_tag, protection.span.data())) } else { @@ -104,77 +346,141 @@ impl AllocHistory { }) }) .and_then(|(tag, call_span)| { - self.creations.iter().rev().find_map(|event| { - if event.tag == tag { - Some((event.parent?, event.span.data(), call_span)) + self.history.creations.iter().rev().find_map(|event| { + if ProvenanceExtra::Concrete(event.retag.new_tag) == tag { + Some((event.retag.orig_tag, event.span.data(), call_span)) } else { None } }) + }) + .map(|(protecting_tag, protecting_tag_span, protection_span)| { + [ + ( + format!( + "{tag:?} was protected due to {protecting_tag:?} which was created here" + ), + protecting_tag_span, + ), + (format!("this protector is live for this call"), protection_span), + ] }); - let get_matching = |events: &[Event]| { - events.iter().rev().find_map(|event| { - if event.tag == tag { Some((event.range, event.span.data())) } else { None } - }) - }; - Some(TagHistory::Tagged { - tag, - created: get_matching(&self.creations)?, - invalidated: get_matching(&self.invalidations), - protected, - }) + Some(TagHistory { created, invalidated, protected }) } /// Report a descriptive error when `new` could not be granted from `derived_from`. - pub fn grant_error<'tcx>( - &self, - derived_from: ProvenanceExtra, - new: Item, - alloc_id: AllocId, - alloc_range: AllocRange, - error_offset: Size, - stack: &Stack, - ) -> InterpError<'tcx> { + pub fn grant_error(&self, perm: Permission, stack: &Stack) -> InterpError<'tcx> { + let Operation::Retag(op) = &self.operation else { + unreachable!("grant_error should only be called during a retag") + }; let action = format!( - "trying to reborrow from {derived_from:?} for {new_perm:?} permission at {alloc_id:?}[{offset:#x}]", - new_perm = new.perm(), - offset = error_offset.bytes(), + "trying to retag from {:?} for {:?} permission at {:?}[{:#x}]", + op.orig_tag, + perm, + self.history.id, + self.offset.bytes(), ); err_sb_ub( - format!("{}{}", action, error_cause(stack, derived_from)), - Some(operation_summary("a reborrow", alloc_id, alloc_range)), - derived_from.and_then(|derived_from| self.get_logs_relevant_to(derived_from, None)), + format!("{}{}", action, error_cause(stack, op.orig_tag)), + Some(operation_summary(&op.cause.summary(), self.history.id, op.range)), + op.orig_tag.and_then(|orig_tag| self.get_logs_relevant_to(orig_tag, None)), ) } /// Report a descriptive error when `access` is not permitted based on `tag`. - pub fn access_error<'tcx>( - &self, - access: AccessKind, - tag: ProvenanceExtra, - alloc_id: AllocId, - alloc_range: AllocRange, - error_offset: Size, - stack: &Stack, - ) -> InterpError<'tcx> { + pub fn access_error(&self, stack: &Stack) -> InterpError<'tcx> { + let Operation::Access(op) = &self.operation else { + unreachable!("access_error should only be called during an access") + }; let action = format!( "attempting a {access} using {tag:?} at {alloc_id:?}[{offset:#x}]", - offset = error_offset.bytes(), + access = op.kind, + tag = op.tag, + alloc_id = self.history.id, + offset = self.offset.bytes(), ); err_sb_ub( - format!("{}{}", action, error_cause(stack, tag)), - Some(operation_summary("an access", alloc_id, alloc_range)), - tag.and_then(|tag| self.get_logs_relevant_to(tag, None)), + format!("{}{}", action, error_cause(stack, op.tag)), + Some(operation_summary("an access", self.history.id, op.range)), + op.tag.and_then(|tag| self.get_logs_relevant_to(tag, None)), ) } + + pub fn protector_error(&self, item: &Item) -> InterpError<'tcx> { + let call_id = self + .threads + .all_stacks() + .flatten() + .map(|frame| { + frame.extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data") + }) + .find(|frame| frame.protected_tags.contains(&item.tag())) + .map(|frame| frame.call_id) + .unwrap(); // FIXME: Surely we should find something, but a panic seems wrong here? + match self.operation { + Operation::Dealloc(_) => + err_sb_ub( + format!( + "deallocating while item {:?} is protected by call {:?}", + item, call_id + ), + None, + None, + ), + Operation::Retag(RetagOp { orig_tag: tag, .. }) + | Operation::Access(AccessOp { tag, .. }) => + err_sb_ub( + format!( + "not granting access to tag {:?} because incompatible item {:?} is protected by call {:?}", + tag, item, call_id + ), + None, + tag.and_then(|tag| self.get_logs_relevant_to(tag, Some(item.tag()))), + ), + } + } + + pub fn dealloc_error(&self) -> InterpError<'tcx> { + let Operation::Dealloc(op) = &self.operation else { + unreachable!("dealloc_error should only be called during a deallocation") + }; + err_sb_ub( + format!( + "no item granting write access for deallocation to tag {:?} at {:?} found in borrow stack", + op.tag, self.history.id, + ), + None, + op.tag.and_then(|tag| self.get_logs_relevant_to(tag, None)), + ) + } + + #[inline(never)] + pub fn check_tracked_tag_popped(&self, item: &Item, global: &GlobalStateInner) { + if !global.tracked_pointer_tags.contains(&item.tag()) { + return; + } + let summary = match self.operation { + Operation::Dealloc(_) => None, + Operation::Access(AccessOp { kind, tag, .. }) => Some((tag, kind)), + Operation::Retag(RetagOp { orig_tag, permission, .. }) => { + let kind = match permission + .expect("start_grant should set the current permission before popping a tag") + { + Permission::SharedReadOnly => AccessKind::Read, + Permission::Unique => AccessKind::Write, + Permission::SharedReadWrite | Permission::Disabled => { + panic!("Only SharedReadOnly and Unique retags can pop tags"); + } + }; + Some((orig_tag, kind)) + } + }; + register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag(*item, summary)); + } } -fn operation_summary( - operation: &'static str, - alloc_id: AllocId, - alloc_range: AllocRange, -) -> String { +fn operation_summary(operation: &str, alloc_id: AllocId, alloc_range: AllocRange) -> String { format!("this error occurs as part of {operation} at {alloc_id:?}{alloc_range:?}") } @@ -192,3 +498,15 @@ fn error_cause(stack: &Stack, prov_extra: ProvenanceExtra) -> &'static str { ", but no exposed tags have suitable permission in the borrow stack for this location" } } + +impl RetagCause { + fn summary(&self) -> String { + match self { + RetagCause::Normal => "retag", + RetagCause::FnEntry => "FnEntry retag", + RetagCause::FnReturn => "FnReturn retag", + RetagCause::TwoPhase => "two-phase retag", + } + .to_string() + } +} diff --git a/src/stacked_borrows/mod.rs b/src/stacked_borrows/mod.rs index b6b03f166999..6cb76e7b23aa 100644 --- a/src/stacked_borrows/mod.rs +++ b/src/stacked_borrows/mod.rs @@ -22,7 +22,7 @@ use smallvec::SmallVec; use crate::*; pub mod diagnostics; -use diagnostics::{AllocHistory, TagHistory}; +use diagnostics::{AllocHistory, DiagnosticCx, DiagnosticCxBuilder, RetagCause, TagHistory}; mod item; pub use item::{Item, Permission}; @@ -142,11 +142,11 @@ pub enum RefKind { impl fmt::Display for RefKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - RefKind::Unique { two_phase: false } => write!(f, "unique"), - RefKind::Unique { two_phase: true } => write!(f, "unique (two-phase)"), - RefKind::Shared => write!(f, "shared"), - RefKind::Raw { mutable: true } => write!(f, "raw (mutable)"), - RefKind::Raw { mutable: false } => write!(f, "raw (constant)"), + RefKind::Unique { two_phase: false } => write!(f, "unique reference"), + RefKind::Unique { two_phase: true } => write!(f, "unique reference (two-phase)"), + RefKind::Shared => write!(f, "shared reference"), + RefKind::Raw { mutable: true } => write!(f, "raw (mutable) pointer"), + RefKind::Raw { mutable: false } => write!(f, "raw (constant) pointer"), } } } @@ -285,94 +285,19 @@ impl<'tcx> Stack { /// currently checking. fn item_popped( item: &Item, - provoking_access: Option<(ProvenanceExtra, AllocRange, Size, AccessKind)>, // just for debug printing and error messages global: &GlobalStateInner, - alloc_history: &mut AllocHistory, - threads: &ThreadManager<'_, 'tcx>, + dcx: &mut DiagnosticCx<'_, '_, 'tcx, '_>, ) -> InterpResult<'tcx> { if !global.tracked_pointer_tags.is_empty() { - check_tracked(item, &provoking_access, global); - - #[inline(never)] // cold path - fn check_tracked( - item: &Item, - provoking_access: &Option<(ProvenanceExtra, AllocRange, Size, AccessKind)>, - global: &GlobalStateInner, - ) { - if global.tracked_pointer_tags.contains(&item.tag()) { - register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag( - *item, - provoking_access.map(|(tag, _alloc_range, _size, access)| (tag, access)), - )); - } - } + dcx.check_tracked_tag_popped(item, global); } if !item.protected() { return Ok(()); } - // We store tags twice, once in global.protected_tags and once in each call frame. - // We do this because consulting a single global set in this function is faster - // than attempting to search all call frames in the program for the `FrameExtra` - // (if any) which is protecting the popped tag. - // - // This duplication trades off making `end_call` slower to make this function faster. This - // trade-off is profitable in practice for a combination of two reasons. - // 1. A single protected tag can (and does in some programs) protect thousands of `Item`s. - // Therefore, adding overhead to in function call/return is profitable even if it only - // saves a little work in this function. - // 2. Most frames protect only one or two tags. So this duplicative global turns a search - // which ends up about linear in the number of protected tags in the program into a - // constant time check (and a slow linear, because the tags in the frames aren't contiguous). if global.protected_tags.contains(&item.tag()) { - return Err(protector_error(item, &provoking_access, alloc_history, threads)); - - #[inline(never)] // cold path - fn protector_error<'tcx>( - item: &Item, - provoking_access: &Option<(ProvenanceExtra, AllocRange, Size, AccessKind)>, - alloc_history: &mut AllocHistory, - threads: &ThreadManager<'_, 'tcx>, - ) -> InterpErrorInfo<'tcx> { - // This path is cold because it is fatal to the program. So here it is fine to do the - // more expensive search to figure out which call is responsible for protecting this - // tag. - let call_id = threads - .all_stacks() - .flatten() - .map(|frame| { - frame - .extra - .stacked_borrows - .as_ref() - .expect("we should have Stacked Borrows data") - }) - .find(|frame| frame.protected_tags.contains(&item.tag())) - .map(|frame| frame.call_id) - .unwrap(); // FIXME: Surely we should find something, but a panic seems wrong here? - if let Some((tag, _alloc_range, _offset, _access)) = provoking_access { - err_sb_ub( - format!( - "not granting access to tag {:?} because incompatible item {:?} is protected by call {:?}", - tag, item, call_id - ), - None, - tag.and_then(|tag| { - alloc_history.get_logs_relevant_to(tag, Some(item.tag())) - }), - ) - } else { - err_sb_ub( - format!( - "deallocating while item {:?} is protected by call {:?}", - item, call_id - ), - None, - None, - ) - }.into() - } + return Err(dcx.protector_error(item).into()); } Ok(()) } @@ -385,19 +310,15 @@ impl<'tcx> Stack { &mut self, access: AccessKind, tag: ProvenanceExtra, - (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &mut GlobalStateInner, - current_span: &mut CurrentSpan<'_, '_, 'tcx>, - alloc_history: &mut AllocHistory, + dcx: &mut DiagnosticCx<'_, '_, 'tcx, '_>, exposed_tags: &FxHashSet, - threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. - let granting_idx = self.find_granting(access, tag, exposed_tags).map_err(|_| { - alloc_history.access_error(access, tag, alloc_id, alloc_range, offset, self) - })?; + let granting_idx = + self.find_granting(access, tag, exposed_tags).map_err(|_| dcx.access_error(self))?; // Step 2: Remove incompatible items above them. Make sure we do not remove protected // items. Behavior differs for reads and writes. @@ -416,14 +337,8 @@ impl<'tcx> Stack { 0 }; self.pop_items_after(first_incompatible_idx, |item| { - Stack::item_popped( - &item, - Some((tag, alloc_range, offset, access)), - global, - alloc_history, - threads, - )?; - alloc_history.log_invalidation(item.tag(), alloc_range, current_span); + Stack::item_popped(&item, global, dcx)?; + dcx.log_invalidation(item.tag()); Ok(()) })?; } else { @@ -443,14 +358,8 @@ impl<'tcx> Stack { 0 }; self.disable_uniques_starting_at(first_incompatible_idx, |item| { - Stack::item_popped( - &item, - Some((tag, alloc_range, offset, access)), - global, - alloc_history, - threads, - )?; - alloc_history.log_invalidation(item.tag(), alloc_range, current_span); + Stack::item_popped(&item, global, dcx)?; + dcx.log_invalidation(item.tag()); Ok(()) })?; } @@ -487,27 +396,18 @@ impl<'tcx> Stack { fn dealloc( &mut self, tag: ProvenanceExtra, - (alloc_id, _alloc_range, _offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &GlobalStateInner, - alloc_history: &mut AllocHistory, + dcx: &mut DiagnosticCx<'_, '_, 'tcx, '_>, exposed_tags: &FxHashSet, - threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { // Step 1: Make sure there is a granting item. - self.find_granting(AccessKind::Write, tag, exposed_tags).map_err(|_| { - err_sb_ub(format!( - "no item granting write access for deallocation to tag {:?} at {:?} found in borrow stack", - tag, alloc_id, - ), - None, - tag.and_then(|tag| alloc_history.get_logs_relevant_to(tag, None)), - ) - })?; + self.find_granting(AccessKind::Write, tag, exposed_tags) + .map_err(|_| dcx.dealloc_error())?; // Step 2: Consider all items removed. This checks for protectors. for idx in (0..self.len()).rev() { let item = self.get(idx).unwrap(); - Stack::item_popped(&item, None, global, alloc_history, threads)?; + Stack::item_popped(&item, global, dcx)?; } Ok(()) } @@ -522,23 +422,21 @@ impl<'tcx> Stack { &mut self, derived_from: ProvenanceExtra, new: Item, - (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &mut GlobalStateInner, - current_span: &mut CurrentSpan<'_, '_, 'tcx>, - alloc_history: &mut AllocHistory, + dcx: &mut DiagnosticCx<'_, '_, 'tcx, '_>, exposed_tags: &FxHashSet, - threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { + dcx.start_grant(new.perm()); + // Figure out which access `perm` corresponds to. let access = if new.perm().grants(AccessKind::Write) { AccessKind::Write } else { AccessKind::Read }; // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. - let granting_idx = - self.find_granting(access, derived_from, exposed_tags).map_err(|_| { - alloc_history.grant_error(derived_from, new, alloc_id, alloc_range, offset, self) - })?; + let granting_idx = self + .find_granting(access, derived_from, exposed_tags) + .map_err(|_| dcx.grant_error(new.perm(), self))?; // Compute where to put the new item. // Either way, we ensure that we insert the new item in a way such that between @@ -568,16 +466,7 @@ impl<'tcx> Stack { // A "safe" reborrow for a pointer that actually expects some aliasing guarantees. // Here, creating a reference actually counts as an access. // This ensures F2b for `Unique`, by removing offending `SharedReadOnly`. - self.access( - access, - derived_from, - (alloc_id, alloc_range, offset), - global, - current_span, - alloc_history, - exposed_tags, - threads, - )?; + self.access(access, derived_from, global, dcx, exposed_tags)?; // We insert "as far up as possible": We know only compatible items are remaining // on top of `derived_from`, and we want the new item at the top so that we @@ -596,14 +485,15 @@ impl<'tcx> Stack { /// Map per-stack operations to higher-level per-location-range operations. impl<'tcx> Stacks { - /// Creates new stack with initial tag. - fn new(size: Size, perm: Permission, tag: SbTag) -> Self { + /// Creates a new stack with an initial tag. For diagnostic purposes, we also need to know + /// the [`AllocId`] of the allocation this is associated with. + fn new(size: Size, perm: Permission, tag: SbTag, id: AllocId) -> Self { let item = Item::new(tag, perm, false); let stack = Stack::new(item); Stacks { stacks: RangeMap::new(size, stack), - history: AllocHistory::new(), + history: AllocHistory::new(id), exposed_tags: FxHashSet::default(), } } @@ -612,15 +502,17 @@ impl<'tcx> Stacks { fn for_each( &mut self, range: AllocRange, + mut dcx_builder: DiagnosticCxBuilder<'_, '_, 'tcx>, mut f: impl FnMut( - Size, &mut Stack, - &mut AllocHistory, + &mut DiagnosticCx<'_, '_, 'tcx, '_>, &mut FxHashSet, ) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { for (offset, stack) in self.stacks.iter_mut(range.start, range.size) { - f(offset, stack, &mut self.history, &mut self.exposed_tags)?; + let mut dcx = dcx_builder.build(&mut self.history, offset); + f(stack, &mut dcx, &mut self.exposed_tags)?; + dcx_builder = dcx.unbuild(); } Ok(()) } @@ -633,7 +525,6 @@ impl Stacks { size: Size, state: &GlobalState, kind: MemoryKind, - mut current_span: CurrentSpan<'_, '_, '_>, ) -> Self { let mut extra = state.borrow_mut(); let (base_tag, perm) = match kind { @@ -646,25 +537,18 @@ impl Stacks { // Everything else is shared by default. _ => (extra.base_ptr_tag(id), Permission::SharedReadWrite), }; - let mut stacks = Stacks::new(size, perm, base_tag); - stacks.history.log_creation( - None, - base_tag, - alloc_range(Size::ZERO, size), - &mut current_span, - ); - stacks + Stacks::new(size, perm, base_tag, id) } #[inline(always)] - pub fn before_memory_read<'tcx>( + pub fn before_memory_read<'tcx, 'mir>( &mut self, alloc_id: AllocId, tag: ProvenanceExtra, range: AllocRange, state: &GlobalState, - mut current_span: CurrentSpan<'_, '_, 'tcx>, - threads: &ThreadManager<'_, 'tcx>, + current_span: CurrentSpan<'_, 'mir, 'tcx>, + threads: &ThreadManager<'mir, 'tcx>, ) -> InterpResult<'tcx> { trace!( "read access with tag {:?}: {:?}, size {}", @@ -672,30 +556,22 @@ impl Stacks { Pointer::new(alloc_id, range.start), range.size.bytes() ); + let dcx = DiagnosticCxBuilder::read(current_span, threads, tag, range); let mut state = state.borrow_mut(); - self.for_each(range, |offset, stack, history, exposed_tags| { - stack.access( - AccessKind::Read, - tag, - (alloc_id, range, offset), - &mut state, - &mut current_span, - history, - exposed_tags, - threads, - ) + self.for_each(range, dcx, |stack, dcx, exposed_tags| { + stack.access(AccessKind::Read, tag, &mut state, dcx, exposed_tags) }) } #[inline(always)] - pub fn before_memory_write<'tcx>( + pub fn before_memory_write<'tcx, 'mir>( &mut self, alloc_id: AllocId, tag: ProvenanceExtra, range: AllocRange, state: &GlobalState, - mut current_span: CurrentSpan<'_, '_, 'tcx>, - threads: &ThreadManager<'_, 'tcx>, + current_span: CurrentSpan<'_, 'mir, 'tcx>, + threads: &ThreadManager<'mir, 'tcx>, ) -> InterpResult<'tcx> { trace!( "write access with tag {:?}: {:?}, size {}", @@ -703,34 +579,28 @@ impl Stacks { Pointer::new(alloc_id, range.start), range.size.bytes() ); + let dcx = DiagnosticCxBuilder::write(current_span, threads, tag, range); let mut state = state.borrow_mut(); - self.for_each(range, |offset, stack, history, exposed_tags| { - stack.access( - AccessKind::Write, - tag, - (alloc_id, range, offset), - &mut state, - &mut current_span, - history, - exposed_tags, - threads, - ) + self.for_each(range, dcx, |stack, dcx, exposed_tags| { + stack.access(AccessKind::Write, tag, &mut state, dcx, exposed_tags) }) } #[inline(always)] - pub fn before_memory_deallocation<'tcx>( + pub fn before_memory_deallocation<'tcx, 'mir>( &mut self, alloc_id: AllocId, tag: ProvenanceExtra, range: AllocRange, state: &GlobalState, - threads: &ThreadManager<'_, 'tcx>, + current_span: CurrentSpan<'_, 'mir, 'tcx>, + threads: &ThreadManager<'mir, 'tcx>, ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", tag, alloc_id, range.size.bytes()); + let dcx = DiagnosticCxBuilder::dealloc(current_span, threads, tag); let state = state.borrow(); - self.for_each(range, |offset, stack, history, exposed_tags| { - stack.dealloc(tag, (alloc_id, range, offset), &state, history, exposed_tags, threads) + self.for_each(range, dcx, |stack, dcx, exposed_tags| { + stack.dealloc(tag, &state, dcx, exposed_tags) })?; Ok(()) } @@ -747,15 +617,15 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx place: &MPlaceTy<'tcx, Provenance>, size: Size, kind: RefKind, + retag_cause: RetagCause, // What caused this retag, for diagnostics only new_tag: SbTag, protect: bool, ) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); - let current_span = &mut this.machine.current_span(); // It is crucial that this gets called on all code paths, to ensure we track tag creation. let log_creation = |this: &MiriEvalContext<'mir, 'tcx>, - current_span: &mut CurrentSpan<'_, 'mir, 'tcx>, + current_span: CurrentSpan<'_, 'mir, 'tcx>, loc: Option<(AllocId, Size, ProvenanceExtra)>| // alloc_id, base_offset, orig_tag -> InterpResult<'tcx> { let global = this.machine.stacked_borrows.as_ref().unwrap().borrow(); @@ -771,14 +641,8 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(()) }; - // The SB history tracking needs a parent tag, so skip if we come from a wildcard. - let ProvenanceExtra::Concrete(orig_tag) = orig_tag else { - // FIXME: should we log this? - return Ok(()) - }; - - let (_size, _align, kind) = this.get_alloc_info(alloc_id); - match kind { + let (_size, _align, alloc_kind) = this.get_alloc_info(alloc_id); + match alloc_kind { AllocKind::LiveData => { // This should have alloc_extra data, but `get_alloc_extra` can still fail // if converting this alloc_id from a global to a local one @@ -789,14 +653,18 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .as_ref() .expect("we should have Stacked Borrows data") .borrow_mut(); - stacked_borrows.history.log_creation( - Some(orig_tag), - new_tag, - alloc_range(base_offset, size), + let dcx = DiagnosticCxBuilder::retag( current_span, + &this.machine.threads, + retag_cause, + new_tag, + orig_tag, + alloc_range(base_offset, size), ); + let mut dcx = dcx.build(&mut stacked_borrows.history, base_offset); + dcx.log_creation(); if protect { - stacked_borrows.history.log_protector(orig_tag, new_tag, current_span); + dcx.log_protector(); } } AllocKind::Function | AllocKind::VTable | AllocKind::Dead => { @@ -806,6 +674,8 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) }; + let current_span = this.machine.current_span(*this.tcx); + if size == Size::ZERO { trace!( "reborrow of size 0: {} reference {:?} derived from {:?} (pointee {})", @@ -829,6 +699,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx log_creation(this, current_span, None)?; return Ok(None); } + let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?; log_creation(this, current_span, Some((alloc_id, base_offset, orig_tag)))?; @@ -855,11 +726,22 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); if protect { + // We store tags twice, once in global.protected_tags and once in each call frame. + // We do this because consulting a single global set in this function is faster + // than attempting to search all call frames in the program for the `FrameExtra` + // (if any) which is protecting the popped tag. + // + // This duplication trades off making `end_call` slower to make this function faster. This + // trade-off is profitable in practice for a combination of two reasons. + // 1. A single protected tag can (and does in some programs) protect thousands of `Item`s. + // Therefore, adding overhead to in function call/return is profitable even if it only + // saves a little work in this function. + // 2. Most frames protect only one or two tags. So this duplicative global turns a search + // which ends up about linear in the number of protected tags in the program into a + // constant time check (and a slow linear, because the tags in the frames aren't contiguous). this.frame_mut().extra.stacked_borrows.as_mut().unwrap().protected_tags.push(new_tag); this.machine.stacked_borrows.as_mut().unwrap().get_mut().protected_tags.insert(new_tag); } - // FIXME: can't hold the current span handle across the borrows of self above - let current_span = &mut this.machine.current_span(); // Update the stacks. // Make sure that raw pointers and mutable shared references are reborrowed "weak": @@ -906,26 +788,26 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; let item = Item::new(new_tag, perm, protected); let mut global = this.machine.stacked_borrows.as_ref().unwrap().borrow_mut(); - let threads = &this.machine.threads; - stacked_borrows.for_each(range, |offset, stack, history, exposed_tags| { - stack.grant( - orig_tag, - item, - (alloc_id, range, offset), - &mut global, - current_span, - history, - exposed_tags, - threads, - ) + let dcx = DiagnosticCxBuilder::retag( + this.machine.current_span(*this.tcx), + &this.machine.threads, + retag_cause, + new_tag, + orig_tag, + alloc_range(base_offset, size), + ); + stacked_borrows.for_each(range, dcx, |stack, dcx, exposed_tags| { + stack.grant(orig_tag, item, &mut global, dcx, exposed_tags) }) })?; return Ok(Some(alloc_id)); } }; + // Here we can avoid `borrow()` calls because we have mutable references. // Note that this asserts that the allocation is mutable -- but since we are creating a // mutable pointer, that seems reasonable. + let tcx = *this.tcx; let (alloc_extra, machine) = this.get_alloc_extra_mut(alloc_id)?; let mut stacked_borrows = alloc_extra .stacked_borrows @@ -935,19 +817,16 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let item = Item::new(new_tag, perm, protect); let range = alloc_range(base_offset, size); let mut global = machine.stacked_borrows.as_ref().unwrap().borrow_mut(); - let threads = &machine.threads; - let current_span = &mut machine.current_span(); // `get_alloc_extra_mut` invalidated our old `current_span` - stacked_borrows.for_each(range, |offset, stack, history, exposed_tags| { - stack.grant( - orig_tag, - item, - (alloc_id, range, offset), - &mut global, - current_span, - history, - exposed_tags, - threads, - ) + let dcx = DiagnosticCxBuilder::retag( + machine.current_span(tcx), + &machine.threads, + retag_cause, + new_tag, + orig_tag, + alloc_range(base_offset, size), + ); + stacked_borrows.for_each(range, dcx, |stack, dcx, exposed_tags| { + stack.grant(orig_tag, item, &mut global, dcx, exposed_tags) })?; Ok(Some(alloc_id)) @@ -959,6 +838,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, val: &ImmTy<'tcx, Provenance>, kind: RefKind, + retag_cause: RetagCause, // What caused this retag, for diagnostics only protect: bool, ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { let this = self.eval_context_mut(); @@ -977,7 +857,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let new_tag = this.machine.stacked_borrows.as_mut().unwrap().get_mut().new_ptr(); // Reborrow. - let alloc_id = this.reborrow(&place, size, kind, new_tag, protect)?; + let alloc_id = this.reborrow(&place, size, kind, retag_cause, new_tag, protect)?; // Adjust pointer. let new_place = place.map_provenance(|p| { @@ -1007,7 +887,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn retag(&mut self, kind: RetagKind, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let retag_fields = this.machine.stacked_borrows.as_mut().unwrap().get_mut().retag_fields; - let mut visitor = RetagVisitor { ecx: this, kind, retag_fields }; + let retag_cause = match kind { + RetagKind::TwoPhase { .. } => RetagCause::TwoPhase, + RetagKind::FnEntry => RetagCause::FnEntry, + RetagKind::Raw | RetagKind::Default => RetagCause::Normal, + }; + let mut visitor = RetagVisitor { ecx: this, kind, retag_cause, retag_fields }; return visitor.visit_value(place); // Determine mutability and whether to add a protector. @@ -1036,6 +921,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx struct RetagVisitor<'ecx, 'mir, 'tcx> { ecx: &'ecx mut MiriEvalContext<'mir, 'tcx>, kind: RetagKind, + retag_cause: RetagCause, retag_fields: bool, } impl<'ecx, 'mir, 'tcx> RetagVisitor<'ecx, 'mir, 'tcx> { @@ -1044,10 +930,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, place: &PlaceTy<'tcx, Provenance>, ref_kind: RefKind, + retag_cause: RetagCause, protector: bool, ) -> InterpResult<'tcx> { let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?; - let val = self.ecx.retag_reference(&val, ref_kind, protector)?; + let val = self.ecx.retag_reference(&val, ref_kind, retag_cause, protector)?; self.ecx.write_immediate(*val, place)?; Ok(()) } @@ -1068,13 +955,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx self.retag_place( place, RefKind::Unique { two_phase: false }, + self.retag_cause, /*protector*/ false, ) } fn visit_value(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { if let Some((ref_kind, protector)) = qualify(place.layout.ty, self.kind) { - self.retag_place(place, ref_kind, protector)?; + self.retag_place(place, ref_kind, self.retag_cause, protector)?; } else if matches!(place.layout.ty.kind(), ty::RawPtr(..)) { // Wide raw pointers *do* have fields and their types are strange. // vtables have a type like `&[*const (); 3]` or so! @@ -1117,6 +1005,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val = this.retag_reference( &val, RefKind::Unique { two_phase: false }, + RetagCause::FnReturn, /*protector*/ true, )?; // And use reborrowed pointer for return place. diff --git a/tests/fail/box-cell-alias.stderr b/tests/fail/box-cell-alias.stderr index 705348ba0f06..1436afcd212b 100644 --- a/tests/fail/box-cell-alias.stderr +++ b/tests/fail/box-cell-alias.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/box-cell-alias.rs:LL:CC | LL | unsafe { (*ptr).set(20) }; | ^^^^^^^^^^^^^^ | | - | trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x1] + | trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of retag at ALLOC[0x0..0x1] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x1] +help: was created by a SharedReadWrite retag at offsets [0x0..0x1] --> $DIR/box-cell-alias.rs:LL:CC | LL | let ptr: *const Cell = &*val; | ^^^^^ -help: was later invalidated at offsets [0x0..0x1] +help: was later invalidated at offsets [0x0..0x1] by a Unique retag --> $DIR/box-cell-alias.rs:LL:CC | LL | let res = helper(val, ptr); diff --git a/tests/fail/stacked_borrows/alias_through_mutation.stderr b/tests/fail/stacked_borrows/alias_through_mutation.stderr index ec985cb26a99..74d1e4ebbcb8 100644 --- a/tests/fail/stacked_borrows/alias_through_mutation.stderr +++ b/tests/fail/stacked_borrows/alias_through_mutation.stderr @@ -9,12 +9,12 @@ LL | let _val = *target_alias; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadOnly retag at offsets [0x0..0x4] --> $DIR/alias_through_mutation.rs:LL:CC | LL | *x = &mut *(target as *mut _); | ^^^^^^^^^^^^^^^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a write access --> $DIR/alias_through_mutation.rs:LL:CC | LL | *target = 13; diff --git a/tests/fail/stacked_borrows/aliasing_mut1.stderr b/tests/fail/stacked_borrows/aliasing_mut1.stderr index b821d1e6edb4..e3f05f3350a5 100644 --- a/tests/fail/stacked_borrows/aliasing_mut1.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut1.stderr @@ -6,7 +6,7 @@ LL | pub fn safe(_x: &mut i32, _y: &mut i32) {} | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a Unique retag at offsets [0x0..0x4] --> $DIR/aliasing_mut1.rs:LL:CC | LL | let xraw: *mut i32 = unsafe { mem::transmute(&mut x) }; diff --git a/tests/fail/stacked_borrows/aliasing_mut2.stderr b/tests/fail/stacked_borrows/aliasing_mut2.stderr index 594b578fc09a..94c2ffa07f71 100644 --- a/tests/fail/stacked_borrows/aliasing_mut2.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut2.stderr @@ -6,7 +6,7 @@ LL | pub fn safe(_x: &i32, _y: &mut i32) {} | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a Unique retag at offsets [0x0..0x4] --> $DIR/aliasing_mut2.rs:LL:CC | LL | let xref = &mut x; diff --git a/tests/fail/stacked_borrows/aliasing_mut3.stderr b/tests/fail/stacked_borrows/aliasing_mut3.stderr index 0bb7b8d3a85c..0fa31260323f 100644 --- a/tests/fail/stacked_borrows/aliasing_mut3.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut3.stderr @@ -1,24 +1,24 @@ -error: Undefined Behavior: trying to reborrow from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/aliasing_mut3.rs:LL:CC | LL | pub fn safe(_x: &mut i32, _y: &i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | trying to reborrow from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | trying to retag from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of FnEntry retag at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadOnly retag at offsets [0x0..0x4] --> $DIR/aliasing_mut3.rs:LL:CC | LL | safe_raw(xraw, xshr); | ^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a Unique FnEntry retag --> $DIR/aliasing_mut3.rs:LL:CC | -LL | pub fn safe(_x: &mut i32, _y: &i32) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | safe_raw(xraw, xshr); + | ^^^^^^^^^^^^^^^^^^^^ = note: backtrace: = note: inside `safe` at $DIR/aliasing_mut3.rs:LL:CC note: inside `main` at $DIR/aliasing_mut3.rs:LL:CC diff --git a/tests/fail/stacked_borrows/aliasing_mut4.stderr b/tests/fail/stacked_borrows/aliasing_mut4.stderr index 0c7d85ae5756..f48d39b2e49f 100644 --- a/tests/fail/stacked_borrows/aliasing_mut4.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut4.stderr @@ -6,7 +6,7 @@ LL | pub fn safe(_x: &i32, _y: &mut Cell) {} | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a Unique retag at offsets [0x0..0x4] --> $DIR/aliasing_mut4.rs:LL:CC | LL | let xref = &mut x; diff --git a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr index 7214ef27be33..dfe49d7f0892 100644 --- a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr +++ b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr @@ -9,12 +9,12 @@ LL | *LEAK = 7; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadOnly retag at offsets [0x0..0x4] --> $DIR/box_exclusive_violation1.rs:LL:CC | LL | LEAK = x as *const _ as *mut _; | ^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a write access --> $DIR/box_exclusive_violation1.rs:LL:CC | LL | *our = 5; diff --git a/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr b/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr index 6e78ed6c7298..c0fc247cd4a2 100644 --- a/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr +++ b/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr @@ -9,12 +9,12 @@ LL | v1[1] = 5; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0xc] +help: was created by a Unique retag at offsets [0x0..0xc] --> $DIR/buggy_as_mut_slice.rs:LL:CC | LL | let v1 = safe::as_mut_slice(&v); | ^^^^^^^^^^^^^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0xc] +help: was later invalidated at offsets [0x0..0xc] by a Unique retag --> $DIR/buggy_as_mut_slice.rs:LL:CC | LL | unsafe { from_raw_parts_mut(self_.as_ptr() as *mut T, self_.len()) } diff --git a/tests/fail/stacked_borrows/buggy_split_at_mut.rs b/tests/fail/stacked_borrows/buggy_split_at_mut.rs index db64d559c517..8a1ea86d6338 100644 --- a/tests/fail/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/fail/stacked_borrows/buggy_split_at_mut.rs @@ -19,7 +19,7 @@ mod safe { fn main() { let mut array = [1, 2, 3, 4]; let (a, b) = safe::split_at_mut(&mut array, 0); - //~^ ERROR: /reborrow .* tag does not exist in the borrow stack/ + //~^ ERROR: /retag .* tag does not exist in the borrow stack/ a[1] = 5; b[1] = 6; } diff --git a/tests/fail/stacked_borrows/buggy_split_at_mut.stderr b/tests/fail/stacked_borrows/buggy_split_at_mut.stderr index 41ab9cfa92ae..b4c5140882f3 100644 --- a/tests/fail/stacked_borrows/buggy_split_at_mut.stderr +++ b/tests/fail/stacked_borrows/buggy_split_at_mut.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/buggy_split_at_mut.rs:LL:CC | LL | let (a, b) = safe::split_at_mut(&mut array, 0); | ^ | | - | trying to reborrow from for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x10] + | trying to retag from for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of retag at ALLOC[0x0..0x10] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x10] +help: was created by a Unique retag at offsets [0x0..0x10] --> $DIR/buggy_split_at_mut.rs:LL:CC | LL | from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x10] +help: was later invalidated at offsets [0x0..0x10] by a Unique retag --> $DIR/buggy_split_at_mut.rs:LL:CC | LL | from_raw_parts_mut(ptr.offset(mid as isize), len - mid), diff --git a/tests/fail/stacked_borrows/fnentry_invalidation.rs b/tests/fail/stacked_borrows/fnentry_invalidation.rs new file mode 100644 index 000000000000..37214bebb828 --- /dev/null +++ b/tests/fail/stacked_borrows/fnentry_invalidation.rs @@ -0,0 +1,20 @@ +// Test that spans displayed in diagnostics identify the function call, not the function +// definition, as the location of invalidation due to FnEntry retag. Technically the FnEntry retag +// occurs inside the function, but what the user wants to know is which call produced the +// invalidation. +fn main() { + let mut x = 0i32; + let z = &mut x as *mut i32; + x.do_bad(); + unsafe { + let _oof = *z; //~ ERROR: /read access .* tag does not exist in the borrow stack/ + } +} + +trait Bad { + fn do_bad(&mut self) { + // who knows + } +} + +impl Bad for i32 {} diff --git a/tests/fail/stacked_borrows/fnentry_invalidation.stderr b/tests/fail/stacked_borrows/fnentry_invalidation.stderr new file mode 100644 index 000000000000..a66fd3200347 --- /dev/null +++ b/tests/fail/stacked_borrows/fnentry_invalidation.stderr @@ -0,0 +1,28 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/fnentry_invalidation.rs:LL:CC + | +LL | let _oof = *z; + | ^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a SharedReadWrite retag at offsets [0x0..0x4] + --> $DIR/fnentry_invalidation.rs:LL:CC + | +LL | let z = &mut x as *mut i32; + | ^^^^^^ +help: was later invalidated at offsets [0x0..0x4] by a Unique FnEntry retag + --> $DIR/fnentry_invalidation.rs:LL:CC + | +LL | x.do_bad(); + | ^^^^^^^^^^ + = note: backtrace: + = note: inside `main` at $DIR/fnentry_invalidation.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/stacked_borrows/illegal_read1.stderr b/tests/fail/stacked_borrows/illegal_read1.stderr index 3f4ade9a712f..6e9d491137c8 100644 --- a/tests/fail/stacked_borrows/illegal_read1.stderr +++ b/tests/fail/stacked_borrows/illegal_read1.stderr @@ -9,12 +9,12 @@ LL | let _val = *xref; // ...but any use of raw will invalidate our ref. | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a Unique retag at offsets [0x0..0x4] --> $DIR/illegal_read1.rs:LL:CC | LL | let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok... | ^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a read access --> $DIR/illegal_read1.rs:LL:CC | LL | let _val = unsafe { *xraw }; diff --git a/tests/fail/stacked_borrows/illegal_read2.stderr b/tests/fail/stacked_borrows/illegal_read2.stderr index cb0ac5602782..fb1f9ec6a884 100644 --- a/tests/fail/stacked_borrows/illegal_read2.stderr +++ b/tests/fail/stacked_borrows/illegal_read2.stderr @@ -9,12 +9,12 @@ LL | let _val = *xref; // ...but any use of raw will invalidate our ref. | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a Unique retag at offsets [0x0..0x4] --> $DIR/illegal_read2.rs:LL:CC | LL | let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok... | ^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a SharedReadOnly retag --> $DIR/illegal_read2.rs:LL:CC | LL | let shr = unsafe { &*xraw }; diff --git a/tests/fail/stacked_borrows/illegal_read3.stderr b/tests/fail/stacked_borrows/illegal_read3.stderr index bdeca5f7ec86..55ab8877999c 100644 --- a/tests/fail/stacked_borrows/illegal_read3.stderr +++ b/tests/fail/stacked_borrows/illegal_read3.stderr @@ -9,12 +9,12 @@ LL | let _val = *xref2; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a Unique retag at offsets [0x0..0x4] --> $DIR/illegal_read3.rs:LL:CC | LL | let xref2 = &mut *xref1; | ^^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a read access --> $DIR/illegal_read3.rs:LL:CC | LL | let _val = unsafe { *xref1.r }; diff --git a/tests/fail/stacked_borrows/illegal_read4.stderr b/tests/fail/stacked_borrows/illegal_read4.stderr index 59c2088c0c85..3bb064e2f416 100644 --- a/tests/fail/stacked_borrows/illegal_read4.stderr +++ b/tests/fail/stacked_borrows/illegal_read4.stderr @@ -9,12 +9,12 @@ LL | let _illegal = *xref2; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a Unique retag at offsets [0x0..0x4] --> $DIR/illegal_read4.rs:LL:CC | LL | let xref2 = unsafe { &mut *xraw }; | ^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a read access --> $DIR/illegal_read4.rs:LL:CC | LL | let _val = unsafe { *xraw }; // use the raw again, this invalidates xref2 *even* with the special read except for uniq refs diff --git a/tests/fail/stacked_borrows/illegal_read5.stderr b/tests/fail/stacked_borrows/illegal_read5.stderr index d1506f199684..e060463cf1d3 100644 --- a/tests/fail/stacked_borrows/illegal_read5.stderr +++ b/tests/fail/stacked_borrows/illegal_read5.stderr @@ -9,12 +9,12 @@ LL | let _val = *xref; // the mutable one is dead and gone | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [$HEX..$HEX] +help: was created by a Unique retag at offsets [$HEX..$HEX] --> $DIR/illegal_read5.rs:LL:CC | LL | let xref: &mut i32 = &mut *refmut; | ^^^^^^^^^^^^ -help: was later invalidated at offsets [$HEX..$HEX] +help: was later invalidated at offsets [$HEX..$HEX] by a read access --> $DIR/illegal_read5.rs:LL:CC | LL | mem::forget(unsafe { ptr::read(xshr) }); // but after reading through the shared ref diff --git a/tests/fail/stacked_borrows/illegal_read6.stderr b/tests/fail/stacked_borrows/illegal_read6.stderr index 5abea6f611a4..8ef720925646 100644 --- a/tests/fail/stacked_borrows/illegal_read6.stderr +++ b/tests/fail/stacked_borrows/illegal_read6.stderr @@ -9,12 +9,12 @@ LL | let _val = *raw; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadWrite retag at offsets [0x0..0x4] --> $DIR/illegal_read6.rs:LL:CC | LL | let raw = x as *mut _; | ^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a Unique retag --> $DIR/illegal_read6.rs:LL:CC | LL | let x = &mut *x; // kill `raw` diff --git a/tests/fail/stacked_borrows/illegal_read7.rs b/tests/fail/stacked_borrows/illegal_read7.rs index c0d3816f4475..1901e8e4e348 100644 --- a/tests/fail/stacked_borrows/illegal_read7.rs +++ b/tests/fail/stacked_borrows/illegal_read7.rs @@ -17,6 +17,6 @@ fn main() { // without invalidating `x`. That would be bad! It would mean that creating `shr` // leaked `x` to `raw`. let _val = ptr::read(raw); - let _val = *x.get_mut(); //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ + let _val = *x.get_mut(); //~ ERROR: /retag .* tag does not exist in the borrow stack/ } } diff --git a/tests/fail/stacked_borrows/illegal_read7.stderr b/tests/fail/stacked_borrows/illegal_read7.stderr index 11335df4da0a..5c42b0a5863c 100644 --- a/tests/fail/stacked_borrows/illegal_read7.stderr +++ b/tests/fail/stacked_borrows/illegal_read7.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/illegal_read7.rs:LL:CC | LL | let _val = *x.get_mut(); | ^^^^^^^^^^^ | | - | trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of two-phase retag at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a Unique retag at offsets [0x0..0x4] --> $DIR/illegal_read7.rs:LL:CC | LL | let x = &mut *raw; | ^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a read access --> $DIR/illegal_read7.rs:LL:CC | LL | let _val = ptr::read(raw); diff --git a/tests/fail/stacked_borrows/illegal_read8.stderr b/tests/fail/stacked_borrows/illegal_read8.stderr index ef150e84f274..c962d1c3e403 100644 --- a/tests/fail/stacked_borrows/illegal_read8.stderr +++ b/tests/fail/stacked_borrows/illegal_read8.stderr @@ -9,12 +9,12 @@ LL | let _fail = *y1; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadOnly retag at offsets [0x0..0x4] --> $DIR/illegal_read8.rs:LL:CC | LL | let y1: &i32 = mem::transmute(&*x); // launder lifetimes | ^^^^^^^^^^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a write access --> $DIR/illegal_read8.rs:LL:CC | LL | *y2 += 1; diff --git a/tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr b/tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr index 7c77c62575d7..4607a9dbf675 100644 --- a/tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr +++ b/tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr @@ -9,6 +9,16 @@ LL | let _val = *root2; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a Unique retag at offsets [0x0..0x4] + --> $DIR/illegal_read_despite_exposed1.rs:LL:CC + | +LL | let root2 = &mut *exposed_ptr; + | ^^^^^^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] by a write access + --> $DIR/illegal_read_despite_exposed1.rs:LL:CC + | +LL | *exposed_ptr = 0; + | ^^^^^^^^^^^^^^^^ = note: backtrace: = note: inside `main` at $DIR/illegal_read_despite_exposed1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr b/tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr index 4fbbd4c6bede..4bf0df7d0625 100644 --- a/tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr +++ b/tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr @@ -9,6 +9,16 @@ LL | let _val = *root2; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a Unique retag at offsets [0x0..0x4] + --> $DIR/illegal_read_despite_exposed2.rs:LL:CC + | +LL | let root2 = &mut *exposed_ptr; + | ^^^^^^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] by a read access + --> $DIR/illegal_read_despite_exposed2.rs:LL:CC + | +LL | let _val = *exposed_ptr; + | ^^^^^^^^^^^^ = note: backtrace: = note: inside `main` at $DIR/illegal_read_despite_exposed2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_write1.stderr b/tests/fail/stacked_borrows/illegal_write1.stderr index f93972051692..55ba9aab9bf4 100644 --- a/tests/fail/stacked_borrows/illegal_write1.stderr +++ b/tests/fail/stacked_borrows/illegal_write1.stderr @@ -9,7 +9,7 @@ LL | unsafe { *x = 42 }; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadOnly retag at offsets [0x0..0x4] --> $DIR/illegal_write1.rs:LL:CC | LL | let x: *mut u32 = xref as *const _ as *mut _; diff --git a/tests/fail/stacked_borrows/illegal_write2.stderr b/tests/fail/stacked_borrows/illegal_write2.stderr index 92dacf214f8c..ceb4ce040b89 100644 --- a/tests/fail/stacked_borrows/illegal_write2.stderr +++ b/tests/fail/stacked_borrows/illegal_write2.stderr @@ -9,12 +9,12 @@ LL | unsafe { *target2 = 13 }; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadWrite retag at offsets [0x0..0x4] --> $DIR/illegal_write2.rs:LL:CC | LL | let target2 = target as *mut _; | ^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a Unique retag --> $DIR/illegal_write2.rs:LL:CC | LL | drop(&mut *target); // reborrow diff --git a/tests/fail/stacked_borrows/illegal_write3.stderr b/tests/fail/stacked_borrows/illegal_write3.stderr index bb6d189f8520..e091e25190bb 100644 --- a/tests/fail/stacked_borrows/illegal_write3.stderr +++ b/tests/fail/stacked_borrows/illegal_write3.stderr @@ -9,7 +9,7 @@ LL | unsafe { *ptr = 42 }; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadOnly retag at offsets [0x0..0x4] --> $DIR/illegal_write3.rs:LL:CC | LL | let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag diff --git a/tests/fail/stacked_borrows/illegal_write4.stderr b/tests/fail/stacked_borrows/illegal_write4.stderr index 97301d64deb3..d66585ff7f14 100644 --- a/tests/fail/stacked_borrows/illegal_write4.stderr +++ b/tests/fail/stacked_borrows/illegal_write4.stderr @@ -9,12 +9,12 @@ LL | let _val = *reference; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadOnly retag at offsets [0x0..0x4] --> $DIR/illegal_write4.rs:LL:CC | LL | let reference = unsafe { &*raw }; // freeze | ^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a Unique retag --> $DIR/illegal_write4.rs:LL:CC | LL | let _mut_ref: &mut i32 = unsafe { mem::transmute(raw) }; // &mut, with raw tag diff --git a/tests/fail/stacked_borrows/illegal_write5.stderr b/tests/fail/stacked_borrows/illegal_write5.stderr index 9cb32d7bdfd1..319c2d77062c 100644 --- a/tests/fail/stacked_borrows/illegal_write5.stderr +++ b/tests/fail/stacked_borrows/illegal_write5.stderr @@ -9,12 +9,12 @@ LL | let _val = *xref; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a Unique retag at offsets [0x0..0x4] --> $DIR/illegal_write5.rs:LL:CC | LL | let xref = unsafe { &mut *xraw }; | ^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a write access --> $DIR/illegal_write5.rs:LL:CC | LL | unsafe { *xraw = 15 }; diff --git a/tests/fail/stacked_borrows/illegal_write6.stderr b/tests/fail/stacked_borrows/illegal_write6.stderr index 42f7b3f8b54b..56576b1ff39b 100644 --- a/tests/fail/stacked_borrows/illegal_write6.stderr +++ b/tests/fail/stacked_borrows/illegal_write6.stderr @@ -6,7 +6,7 @@ LL | unsafe { *y = 2 }; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadWrite retag at offsets [0x0..0x4] --> $DIR/illegal_write6.rs:LL:CC | LL | let p = x as *mut u32; diff --git a/tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr b/tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr index 0f5834077b3d..aa436b544126 100644 --- a/tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr +++ b/tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr @@ -9,6 +9,16 @@ LL | let _val = *root2; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a SharedReadOnly retag at offsets [0x0..0x4] + --> $DIR/illegal_write_despite_exposed1.rs:LL:CC + | +LL | let root2 = &*exposed_ptr; + | ^^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] by a write access + --> $DIR/illegal_write_despite_exposed1.rs:LL:CC + | +LL | *exposed_ptr = 0; + | ^^^^^^^^^^^^^^^^ = note: backtrace: = note: inside `main` at $DIR/illegal_write_despite_exposed1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/interior_mut1.rs b/tests/fail/stacked_borrows/interior_mut1.rs index fda203910a44..6911238fc53e 100644 --- a/tests/fail/stacked_borrows/interior_mut1.rs +++ b/tests/fail/stacked_borrows/interior_mut1.rs @@ -12,6 +12,6 @@ fn main() { *c.get() = UnsafeCell::new(1); // invalidates inner_shr // stack: [c: SharedReadWrite] - let _val = *inner_shr.get(); //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ + let _val = *inner_shr.get(); //~ ERROR: /retag .* tag does not exist in the borrow stack/ } } diff --git a/tests/fail/stacked_borrows/interior_mut1.stderr b/tests/fail/stacked_borrows/interior_mut1.stderr index a2643841eac1..3aaca3892a54 100644 --- a/tests/fail/stacked_borrows/interior_mut1.stderr +++ b/tests/fail/stacked_borrows/interior_mut1.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/interior_mut1.rs:LL:CC | LL | let _val = *inner_shr.get(); | ^^^^^^^^^^^^^^^ | | - | trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of retag at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadWrite retag at offsets [0x0..0x4] --> $DIR/interior_mut1.rs:LL:CC | LL | let inner_shr = &*inner_uniq; // adds a SharedReadWrite | ^^^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a write access --> $DIR/interior_mut1.rs:LL:CC | LL | *c.get() = UnsafeCell::new(1); // invalidates inner_shr diff --git a/tests/fail/stacked_borrows/interior_mut2.rs b/tests/fail/stacked_borrows/interior_mut2.rs index 7f8c16c488e7..5e9d177cd038 100644 --- a/tests/fail/stacked_borrows/interior_mut2.rs +++ b/tests/fail/stacked_borrows/interior_mut2.rs @@ -25,6 +25,6 @@ fn main() { // stack: [c: SharedReadWrite] // now this does not work any more - let _val = *inner_shr.get(); //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ + let _val = *inner_shr.get(); //~ ERROR: /retag .* tag does not exist in the borrow stack/ } } diff --git a/tests/fail/stacked_borrows/interior_mut2.stderr b/tests/fail/stacked_borrows/interior_mut2.stderr index 0dbf6e2ea9f9..b0141cc34fb6 100644 --- a/tests/fail/stacked_borrows/interior_mut2.stderr +++ b/tests/fail/stacked_borrows/interior_mut2.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/interior_mut2.rs:LL:CC | LL | let _val = *inner_shr.get(); | ^^^^^^^^^^^^^^^ | | - | trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of retag at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadWrite retag at offsets [0x0..0x4] --> $DIR/interior_mut2.rs:LL:CC | LL | let inner_shr = &*inner_uniq; | ^^^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a write access --> $DIR/interior_mut2.rs:LL:CC | LL | *c.get() = UnsafeCell::new(0); // now inner_shr gets invalidated diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr index 4a1b14e46094..378f7b7d1ef5 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { *x }; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadWrite retag at offsets [0x0..0x4] --> $DIR/invalidate_against_barrier1.rs:LL:CC | LL | let xraw = &mut x as *mut _; diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr index c6f158316f51..0352b671823e 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr @@ -6,7 +6,7 @@ LL | unsafe { *x = 0 }; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadWrite retag at offsets [0x0..0x4] --> $DIR/invalidate_against_barrier2.rs:LL:CC | LL | let xraw = &mut x as *mut _; diff --git a/tests/fail/stacked_borrows/load_invalid_mut.rs b/tests/fail/stacked_borrows/load_invalid_mut.rs index 4e3a16b96d02..5c99c82da6d6 100644 --- a/tests/fail/stacked_borrows/load_invalid_mut.rs +++ b/tests/fail/stacked_borrows/load_invalid_mut.rs @@ -8,5 +8,5 @@ fn main() { let xref = unsafe { &mut *xraw }; let xref_in_mem = Box::new(xref); let _val = unsafe { *xraw }; // invalidate xref - let _val = *xref_in_mem; //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ + let _val = *xref_in_mem; //~ ERROR: /retag .* tag does not exist in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/load_invalid_mut.stderr b/tests/fail/stacked_borrows/load_invalid_mut.stderr index f8e03c631eee..43b6ce8d895e 100644 --- a/tests/fail/stacked_borrows/load_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/load_invalid_mut.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/load_invalid_mut.rs:LL:CC | LL | let _val = *xref_in_mem; | ^^^^^^^^^^^^ | | - | trying to reborrow from for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | trying to retag from for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of retag at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a Unique retag at offsets [0x0..0x4] --> $DIR/load_invalid_mut.rs:LL:CC | LL | let xref_in_mem = Box::new(xref); | ^^^^^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a read access --> $DIR/load_invalid_mut.rs:LL:CC | LL | let _val = unsafe { *xraw }; // invalidate xref diff --git a/tests/fail/stacked_borrows/load_invalid_shr.rs b/tests/fail/stacked_borrows/load_invalid_shr.rs index fb279e4710d1..8f94cc07a24f 100644 --- a/tests/fail/stacked_borrows/load_invalid_shr.rs +++ b/tests/fail/stacked_borrows/load_invalid_shr.rs @@ -8,5 +8,5 @@ fn main() { let xref = unsafe { &*xraw }; let xref_in_mem = Box::new(xref); unsafe { *xraw = 42 }; // unfreeze - let _val = *xref_in_mem; //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ + let _val = *xref_in_mem; //~ ERROR: /retag .* tag does not exist in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/load_invalid_shr.stderr b/tests/fail/stacked_borrows/load_invalid_shr.stderr index a9546c9a7680..2177ebdd7021 100644 --- a/tests/fail/stacked_borrows/load_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/load_invalid_shr.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/load_invalid_shr.rs:LL:CC | LL | let _val = *xref_in_mem; | ^^^^^^^^^^^^ | | - | trying to reborrow from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | trying to retag from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of retag at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadOnly retag at offsets [0x0..0x4] --> $DIR/load_invalid_shr.rs:LL:CC | LL | let xref_in_mem = Box::new(xref); | ^^^^^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a write access --> $DIR/load_invalid_shr.rs:LL:CC | LL | unsafe { *xraw = 42 }; // unfreeze diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr b/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr index acc904794fb5..42f872eac62f 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr +++ b/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr @@ -9,12 +9,12 @@ LL | *LEAK = 7; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadOnly retag at offsets [0x0..0x4] --> $DIR/mut_exclusive_violation1.rs:LL:CC | LL | LEAK = x as *const _ as *mut _; | ^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a write access --> $DIR/mut_exclusive_violation1.rs:LL:CC | LL | *our = 5; diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr b/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr index 5bbf9bc51847..1952172d927b 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr +++ b/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr @@ -9,12 +9,12 @@ LL | let _val = *raw1; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a Unique retag at offsets [0x0..0x4] --> $DIR/mut_exclusive_violation2.rs:LL:CC | LL | let raw1 = ptr1.as_mut(); | ^^^^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a Unique retag --> $DIR/mut_exclusive_violation2.rs:LL:CC | LL | let _raw2 = ptr2.as_mut(); diff --git a/tests/fail/stacked_borrows/newtype_retagging.stderr b/tests/fail/stacked_borrows/newtype_retagging.stderr index d9aebecfda73..2d26787231dc 100644 --- a/tests/fail/stacked_borrows/newtype_retagging.stderr +++ b/tests/fail/stacked_borrows/newtype_retagging.stderr @@ -6,7 +6,7 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadWrite retag at offsets [0x0..0x4] --> $DIR/newtype_retagging.rs:LL:CC | LL | let ptr = Box::into_raw(Box::new(0i32)); diff --git a/tests/fail/stacked_borrows/outdated_local.stderr b/tests/fail/stacked_borrows/outdated_local.stderr index d2ada6458631..e111a8227b2a 100644 --- a/tests/fail/stacked_borrows/outdated_local.stderr +++ b/tests/fail/stacked_borrows/outdated_local.stderr @@ -9,12 +9,12 @@ LL | assert_eq!(unsafe { *y }, 1); | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadOnly retag at offsets [0x0..0x4] --> $DIR/outdated_local.rs:LL:CC | LL | let y: *const i32 = &x; | ^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a write access --> $DIR/outdated_local.rs:LL:CC | LL | x = 1; // this invalidates y by reactivating the lowermost uniq borrow for this local diff --git a/tests/fail/stacked_borrows/pass_invalid_mut.rs b/tests/fail/stacked_borrows/pass_invalid_mut.rs index 55c93981e3cd..8db2c149b17e 100644 --- a/tests/fail/stacked_borrows/pass_invalid_mut.rs +++ b/tests/fail/stacked_borrows/pass_invalid_mut.rs @@ -6,5 +6,5 @@ fn main() { let xraw = x as *mut _; let xref = unsafe { &mut *xraw }; let _val = unsafe { *xraw }; // invalidate xref - foo(xref); //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ + foo(xref); //~ ERROR: /retag .* tag does not exist in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/pass_invalid_mut.stderr b/tests/fail/stacked_borrows/pass_invalid_mut.stderr index f254fd16dcbe..5fd977805445 100644 --- a/tests/fail/stacked_borrows/pass_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/pass_invalid_mut.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/pass_invalid_mut.rs:LL:CC | LL | foo(xref); | ^^^^ | | - | trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of two-phase retag at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a Unique retag at offsets [0x0..0x4] --> $DIR/pass_invalid_mut.rs:LL:CC | LL | let xref = unsafe { &mut *xraw }; | ^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a read access --> $DIR/pass_invalid_mut.rs:LL:CC | LL | let _val = unsafe { *xraw }; // invalidate xref diff --git a/tests/fail/stacked_borrows/pass_invalid_shr.rs b/tests/fail/stacked_borrows/pass_invalid_shr.rs index db8e6681e0de..903c2733107b 100644 --- a/tests/fail/stacked_borrows/pass_invalid_shr.rs +++ b/tests/fail/stacked_borrows/pass_invalid_shr.rs @@ -6,5 +6,5 @@ fn main() { let xraw = x as *mut _; let xref = unsafe { &*xraw }; unsafe { *xraw = 42 }; // unfreeze - foo(xref); //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ + foo(xref); //~ ERROR: /retag .* tag does not exist in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/pass_invalid_shr.stderr b/tests/fail/stacked_borrows/pass_invalid_shr.stderr index 28500836aa8d..0f0df02babb5 100644 --- a/tests/fail/stacked_borrows/pass_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/pass_invalid_shr.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/pass_invalid_shr.rs:LL:CC | LL | foo(xref); | ^^^^ | | - | trying to reborrow from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | trying to retag from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of retag at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadOnly retag at offsets [0x0..0x4] --> $DIR/pass_invalid_shr.rs:LL:CC | LL | let xref = unsafe { &*xraw }; | ^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a write access --> $DIR/pass_invalid_shr.rs:LL:CC | LL | unsafe { *xraw = 42 }; // unfreeze diff --git a/tests/fail/stacked_borrows/pointer_smuggling.stderr b/tests/fail/stacked_borrows/pointer_smuggling.stderr index 66427bdf64d6..43d689a0f4bb 100644 --- a/tests/fail/stacked_borrows/pointer_smuggling.stderr +++ b/tests/fail/stacked_borrows/pointer_smuggling.stderr @@ -9,12 +9,12 @@ LL | let _x = unsafe { *PTR }; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x1] +help: was created by a SharedReadWrite retag at offsets [0x0..0x1] --> $DIR/pointer_smuggling.rs:LL:CC | LL | PTR = x; | ^ -help: was later invalidated at offsets [0x0..0x1] +help: was later invalidated at offsets [0x0..0x1] by a write access --> $DIR/pointer_smuggling.rs:LL:CC | LL | *val = 2; // this invalidates any raw ptrs `fun1` might have created. diff --git a/tests/fail/stacked_borrows/raw_tracking.stderr b/tests/fail/stacked_borrows/raw_tracking.stderr index 2028a9114272..fc846f6d9f6a 100644 --- a/tests/fail/stacked_borrows/raw_tracking.stderr +++ b/tests/fail/stacked_borrows/raw_tracking.stderr @@ -9,12 +9,12 @@ LL | unsafe { *raw1 = 13 }; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadWrite retag at offsets [0x0..0x4] --> $DIR/raw_tracking.rs:LL:CC | LL | let raw1 = &mut l as *mut _; | ^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a Unique retag --> $DIR/raw_tracking.rs:LL:CC | LL | let raw2 = &mut l as *mut _; // invalidates raw1 diff --git a/tests/fail/stacked_borrows/return_invalid_mut.rs b/tests/fail/stacked_borrows/return_invalid_mut.rs index 1f379d4a77e7..7d9a6f11aff9 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut.rs +++ b/tests/fail/stacked_borrows/return_invalid_mut.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> &mut i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &mut (*xraw).1 }; let _val = unsafe { *xraw }; // invalidate xref - ret //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ + ret //~ ERROR: /retag .* tag does not exist in the borrow stack/ } fn main() { diff --git a/tests/fail/stacked_borrows/return_invalid_mut.stderr b/tests/fail/stacked_borrows/return_invalid_mut.stderr index 7c8007044370..c9194208e5dd 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> $DIR/return_invalid_mut.rs:LL:CC | LL | ret | ^^^ | | - | trying to reborrow from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x4..0x8] + | trying to retag from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of retag at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x4..0x8] +help: was created by a Unique retag at offsets [0x4..0x8] --> $DIR/return_invalid_mut.rs:LL:CC | LL | let ret = unsafe { &mut (*xraw).1 }; | ^^^^^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x8] +help: was later invalidated at offsets [0x0..0x8] by a read access --> $DIR/return_invalid_mut.rs:LL:CC | LL | let _val = unsafe { *xraw }; // invalidate xref diff --git a/tests/fail/stacked_borrows/return_invalid_mut_option.rs b/tests/fail/stacked_borrows/return_invalid_mut_option.rs index da3401260e1e..7fa9cf77d44b 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_option.rs +++ b/tests/fail/stacked_borrows/return_invalid_mut_option.rs @@ -10,7 +10,7 @@ fn foo(x: &mut (i32, i32)) -> Option<&mut i32> { fn main() { match foo(&mut (1, 2)) { - Some(_x) => {} //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ + Some(_x) => {} //~ ERROR: /retag .* tag does not exist in the borrow stack/ None => {} } } diff --git a/tests/fail/stacked_borrows/return_invalid_mut_option.stderr b/tests/fail/stacked_borrows/return_invalid_mut_option.stderr index cab997b47357..789d0a3aa829 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_option.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut_option.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> $DIR/return_invalid_mut_option.rs:LL:CC | LL | Some(_x) => {} | ^^ | | - | trying to reborrow from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x4..0x8] + | trying to retag from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of retag at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x4..0x8] +help: was created by a Unique retag at offsets [0x4..0x8] --> $DIR/return_invalid_mut_option.rs:LL:CC | LL | let ret = Some(ret); | ^^^ -help: was later invalidated at offsets [0x0..0x8] +help: was later invalidated at offsets [0x0..0x8] by a read access --> $DIR/return_invalid_mut_option.rs:LL:CC | LL | let _val = unsafe { *xraw }; // invalidate xref diff --git a/tests/fail/stacked_borrows/return_invalid_mut_tuple.rs b/tests/fail/stacked_borrows/return_invalid_mut_tuple.rs index 2184d20b1cfa..c94fef90542f 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_tuple.rs +++ b/tests/fail/stacked_borrows/return_invalid_mut_tuple.rs @@ -8,5 +8,5 @@ fn foo(x: &mut (i32, i32)) -> (&mut i32,) { } fn main() { - foo(&mut (1, 2)).0; //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ + foo(&mut (1, 2)).0; //~ ERROR: /retag .* tag does not exist in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr b/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr index 46ef6a737a63..f7fc75bfd098 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> $DIR/return_invalid_mut_tuple.rs:LL:CC | LL | foo(&mut (1, 2)).0; | ^^^^^^^^^^^^^^^^^^ | | - | trying to reborrow from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x4..0x8] + | trying to retag from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of retag at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x4..0x8] +help: was created by a Unique retag at offsets [0x4..0x8] --> $DIR/return_invalid_mut_tuple.rs:LL:CC | LL | let ret = (unsafe { &mut (*xraw).1 },); | ^^^^^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x8] +help: was later invalidated at offsets [0x0..0x8] by a read access --> $DIR/return_invalid_mut_tuple.rs:LL:CC | LL | let _val = unsafe { *xraw }; // invalidate xref diff --git a/tests/fail/stacked_borrows/return_invalid_shr.rs b/tests/fail/stacked_borrows/return_invalid_shr.rs index b1d16c025ebf..45526498dadf 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr.rs +++ b/tests/fail/stacked_borrows/return_invalid_shr.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> &i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &(*xraw).1 }; unsafe { *xraw = (42, 23) }; // unfreeze - ret //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ + ret //~ ERROR: /retag .* tag does not exist in the borrow stack/ } fn main() { diff --git a/tests/fail/stacked_borrows/return_invalid_shr.stderr b/tests/fail/stacked_borrows/return_invalid_shr.stderr index 6f745b69fc72..fef83c478fe9 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> $DIR/return_invalid_shr.rs:LL:CC | LL | ret | ^^^ | | - | trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x4..0x8] + | trying to retag from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of retag at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x4..0x8] +help: was created by a SharedReadOnly retag at offsets [0x4..0x8] --> $DIR/return_invalid_shr.rs:LL:CC | LL | let ret = unsafe { &(*xraw).1 }; | ^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x8] +help: was later invalidated at offsets [0x0..0x8] by a write access --> $DIR/return_invalid_shr.rs:LL:CC | LL | unsafe { *xraw = (42, 23) }; // unfreeze diff --git a/tests/fail/stacked_borrows/return_invalid_shr_option.rs b/tests/fail/stacked_borrows/return_invalid_shr_option.rs index e9faa945206e..3a028ceed86a 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_option.rs +++ b/tests/fail/stacked_borrows/return_invalid_shr_option.rs @@ -9,7 +9,7 @@ fn foo(x: &mut (i32, i32)) -> Option<&i32> { fn main() { match foo(&mut (1, 2)) { - Some(_x) => {} //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ + Some(_x) => {} //~ ERROR: /retag .* tag does not exist in the borrow stack/ None => {} } } diff --git a/tests/fail/stacked_borrows/return_invalid_shr_option.stderr b/tests/fail/stacked_borrows/return_invalid_shr_option.stderr index 2441c9aa1c51..cc316aaf44ec 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_option.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr_option.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> $DIR/return_invalid_shr_option.rs:LL:CC | LL | Some(_x) => {} | ^^ | | - | trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x4..0x8] + | trying to retag from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of retag at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x4..0x8] +help: was created by a SharedReadOnly retag at offsets [0x4..0x8] --> $DIR/return_invalid_shr_option.rs:LL:CC | LL | let ret = Some(unsafe { &(*xraw).1 }); | ^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x8] +help: was later invalidated at offsets [0x0..0x8] by a write access --> $DIR/return_invalid_shr_option.rs:LL:CC | LL | unsafe { *xraw = (42, 23) }; // unfreeze diff --git a/tests/fail/stacked_borrows/return_invalid_shr_tuple.rs b/tests/fail/stacked_borrows/return_invalid_shr_tuple.rs index 11eb4de56c9f..e4536626dbf2 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_tuple.rs +++ b/tests/fail/stacked_borrows/return_invalid_shr_tuple.rs @@ -8,5 +8,5 @@ fn foo(x: &mut (i32, i32)) -> (&i32,) { } fn main() { - foo(&mut (1, 2)).0; //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ + foo(&mut (1, 2)).0; //~ ERROR: /retag .* tag does not exist in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr b/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr index 5102f7cb53c4..f6be5d0e53a0 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> $DIR/return_invalid_shr_tuple.rs:LL:CC | LL | foo(&mut (1, 2)).0; | ^^^^^^^^^^^^^^^^^^ | | - | trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x4..0x8] + | trying to retag from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of retag at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x4..0x8] +help: was created by a SharedReadOnly retag at offsets [0x4..0x8] --> $DIR/return_invalid_shr_tuple.rs:LL:CC | LL | let ret = (unsafe { &(*xraw).1 },); | ^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x8] +help: was later invalidated at offsets [0x0..0x8] by a write access --> $DIR/return_invalid_shr_tuple.rs:LL:CC | LL | unsafe { *xraw = (42, 23) }; // unfreeze diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs index 01b2775d9d36..2450ec4b4a1d 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs @@ -11,6 +11,6 @@ fn main() { let y: &mut Cell = mem::transmute(&mut *x); // launder lifetime let shr_rw = &*x; // thanks to interior mutability this will be a SharedReadWrite shr_rw.set(1); - y.get_mut(); //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ + y.get_mut(); //~ ERROR: /retag .* tag does not exist in the borrow stack/ } } diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr index a412add67e02..3f5f2c66ae1f 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/shared_rw_borrows_are_weak1.rs:LL:CC | LL | y.get_mut(); | ^^^^^^^^^^^ | | - | trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of two-phase retag at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a Unique retag at offsets [0x0..0x4] --> $DIR/shared_rw_borrows_are_weak1.rs:LL:CC | LL | let y: &mut Cell = mem::transmute(&mut *x); // launder lifetime | ^^^^^^^^^^^^^^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a Unique retag --> $DIR/shared_rw_borrows_are_weak1.rs:LL:CC | LL | shr_rw.set(1); diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr index 2c0117577f2e..0a551fe824b5 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr @@ -9,12 +9,12 @@ LL | let _val = *y; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [$HEX..$HEX] +help: was created by a SharedReadOnly retag at offsets [$HEX..$HEX] --> $DIR/shared_rw_borrows_are_weak2.rs:LL:CC | LL | let y: &i32 = mem::transmute(&*x.borrow()); // launder lifetime | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: was later invalidated at offsets [$HEX..$HEX] +help: was later invalidated at offsets [$HEX..$HEX] by a Unique retag --> $DIR/shared_rw_borrows_are_weak2.rs:LL:CC | LL | shr_rw.replace(1); diff --git a/tests/fail/stacked_borrows/shr_frozen_violation1.stderr b/tests/fail/stacked_borrows/shr_frozen_violation1.stderr index 47799b18e1f9..9ae8461e13ea 100644 --- a/tests/fail/stacked_borrows/shr_frozen_violation1.stderr +++ b/tests/fail/stacked_borrows/shr_frozen_violation1.stderr @@ -9,7 +9,7 @@ LL | *(x as *const i32 as *mut i32) = 7; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadOnly retag at offsets [0x0..0x4] --> $DIR/shr_frozen_violation1.rs:LL:CC | LL | *(x as *const i32 as *mut i32) = 7; diff --git a/tests/fail/stacked_borrows/track_caller.rs b/tests/fail/stacked_borrows/track_caller.rs new file mode 100644 index 000000000000..3455eb4684ea --- /dev/null +++ b/tests/fail/stacked_borrows/track_caller.rs @@ -0,0 +1,17 @@ +// This is a copy of illegal_read1.rs, but with #[track_caller] on the test. +// This test only checks that our diagnostics do not display the contents of callee. + +#[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/5391 +fn main() { + let mut x = 15; + let xraw = &mut x as *mut _; + let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok... + callee(xraw); + let _val = *xref; // ...but any use of raw will invalidate our ref. + //~^ ERROR: /read access .* tag does not exist in the borrow stack/ +} + +#[track_caller] +fn callee(xraw: *mut i32) { + let _val = unsafe { *xraw }; +} diff --git a/tests/fail/stacked_borrows/track_caller.stderr b/tests/fail/stacked_borrows/track_caller.stderr new file mode 100644 index 000000000000..5ad22305910a --- /dev/null +++ b/tests/fail/stacked_borrows/track_caller.stderr @@ -0,0 +1,28 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/track_caller.rs:LL:CC + | +LL | let _val = *xref; // ...but any use of raw will invalidate our ref. + | ^^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a Unique retag at offsets [0x0..0x4] + --> $DIR/track_caller.rs:LL:CC + | +LL | let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok... + | ^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] by a read access + --> $DIR/track_caller.rs:LL:CC + | +LL | callee(xraw); + | ^^^^^^^^^^^^ + = note: backtrace: + = note: inside `main` at $DIR/track_caller.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr index b48abb3df709..eaac77034cce 100644 --- a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr +++ b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr @@ -9,7 +9,7 @@ LL | unsafe { *raw = 13 }; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x4..0x8] +help: was created by a SharedReadWrite retag at offsets [0x4..0x8] --> $DIR/transmute-is-no-escape.rs:LL:CC | LL | let raw = (&mut x[1] as *mut i32).wrapping_offset(-1); diff --git a/tests/fail/stacked_borrows/unescaped_static.stderr b/tests/fail/stacked_borrows/unescaped_static.stderr index 018ff77b2e93..7b210ed9314e 100644 --- a/tests/fail/stacked_borrows/unescaped_static.stderr +++ b/tests/fail/stacked_borrows/unescaped_static.stderr @@ -9,7 +9,7 @@ LL | let _val = unsafe { *ptr_to_first.add(1) }; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x1] +help: was created by a SharedReadOnly retag at offsets [0x0..0x1] --> $DIR/unescaped_static.rs:LL:CC | LL | let ptr_to_first = &ARRAY[0] as *const u8; diff --git a/tests/fail/stacked_borrows/zst_slice.rs b/tests/fail/stacked_borrows/zst_slice.rs index 11065186fc49..77daa9c9811a 100644 --- a/tests/fail/stacked_borrows/zst_slice.rs +++ b/tests/fail/stacked_borrows/zst_slice.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-strict-provenance -//@error-pattern: /reborrow .* tag does not exist in the borrow stack/ +//@error-pattern: /retag .* tag does not exist in the borrow stack/ fn main() { unsafe { diff --git a/tests/fail/stacked_borrows/zst_slice.stderr b/tests/fail/stacked_borrows/zst_slice.stderr index d47e967b543b..6d0e785cea76 100644 --- a/tests/fail/stacked_borrows/zst_slice.stderr +++ b/tests/fail/stacked_borrows/zst_slice.stderr @@ -1,15 +1,15 @@ -error: Undefined Behavior: trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> RUSTLIB/core/src/slice/mod.rs:LL:CC | LL | unsafe { &*index.get_unchecked(self) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x4..0x8] + | trying to retag from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of retag at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x0] +help: would have been created here, but this is a zero-size retag ([0x0..0x0]) so the tag in question does not exist anywhere --> $DIR/zst_slice.rs:LL:CC | LL | assert_eq!(*s.get_unchecked(1), 2); From 17fc52a06d07828fb7d2ef6f5202a9ae41b532c8 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Mon, 15 Aug 2022 22:19:00 -0400 Subject: [PATCH 3766/5092] Clean up diff churn a bit, adjust comments --- src/stacked_borrows/diagnostics.rs | 4 ++++ src/stacked_borrows/mod.rs | 32 +++++++++++++++--------------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index ac2783670cff..be363abad2a4 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -370,6 +370,7 @@ impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCx<'ecx, 'mir, 'tcx, 'history> { } /// Report a descriptive error when `new` could not be granted from `derived_from`. + #[inline(never)] // This is only called on fatal code paths pub fn grant_error(&self, perm: Permission, stack: &Stack) -> InterpError<'tcx> { let Operation::Retag(op) = &self.operation else { unreachable!("grant_error should only be called during a retag") @@ -389,6 +390,7 @@ impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCx<'ecx, 'mir, 'tcx, 'history> { } /// Report a descriptive error when `access` is not permitted based on `tag`. + #[inline(never)] // This is only called on fatal code paths pub fn access_error(&self, stack: &Stack) -> InterpError<'tcx> { let Operation::Access(op) = &self.operation else { unreachable!("access_error should only be called during an access") @@ -407,6 +409,7 @@ impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCx<'ecx, 'mir, 'tcx, 'history> { ) } + #[inline(never)] // This is only called on fatal code paths pub fn protector_error(&self, item: &Item) -> InterpError<'tcx> { let call_id = self .threads @@ -441,6 +444,7 @@ impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCx<'ecx, 'mir, 'tcx, 'history> { } } + #[inline(never)] // This is only called on fatal code paths pub fn dealloc_error(&self) -> InterpError<'tcx> { let Operation::Dealloc(op) = &self.operation else { unreachable!("dealloc_error should only be called during a deallocation") diff --git a/src/stacked_borrows/mod.rs b/src/stacked_borrows/mod.rs index 6cb76e7b23aa..9861e6fdb17b 100644 --- a/src/stacked_borrows/mod.rs +++ b/src/stacked_borrows/mod.rs @@ -296,6 +296,19 @@ impl<'tcx> Stack { return Ok(()); } + // We store tags twice, once in global.protected_tags and once in each call frame. + // We do this because consulting a single global set in this function is faster + // than attempting to search all call frames in the program for the `FrameExtra` + // (if any) which is protecting the popped tag. + // + // This duplication trades off making `end_call` slower to make this function faster. This + // trade-off is profitable in practice for a combination of two reasons. + // 1. A single protected tag can (and does in some programs) protect thousands of `Item`s. + // Therefore, adding overhead in function call/return is profitable even if it only + // saves a little work in this function. + // 2. Most frames protect only one or two tags. So this duplicative global turns a search + // which ends up about linear in the number of protected tags in the program into a + // constant time check (and a slow linear, because the tags in the frames aren't contiguous). if global.protected_tags.contains(&item.tag()) { return Err(dcx.protector_error(item).into()); } @@ -622,6 +635,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx protect: bool, ) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); + let current_span = this.machine.current_span(*this.tcx); // It is crucial that this gets called on all code paths, to ensure we track tag creation. let log_creation = |this: &MiriEvalContext<'mir, 'tcx>, @@ -674,8 +688,6 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) }; - let current_span = this.machine.current_span(*this.tcx); - if size == Size::ZERO { trace!( "reborrow of size 0: {} reference {:?} derived from {:?} (pointee {})", @@ -726,19 +738,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); if protect { - // We store tags twice, once in global.protected_tags and once in each call frame. - // We do this because consulting a single global set in this function is faster - // than attempting to search all call frames in the program for the `FrameExtra` - // (if any) which is protecting the popped tag. - // - // This duplication trades off making `end_call` slower to make this function faster. This - // trade-off is profitable in practice for a combination of two reasons. - // 1. A single protected tag can (and does in some programs) protect thousands of `Item`s. - // Therefore, adding overhead to in function call/return is profitable even if it only - // saves a little work in this function. - // 2. Most frames protect only one or two tags. So this duplicative global turns a search - // which ends up about linear in the number of protected tags in the program into a - // constant time check (and a slow linear, because the tags in the frames aren't contiguous). + // See comment in `Stack::item_popped` for why we store the tag twice. this.frame_mut().extra.stacked_borrows.as_mut().unwrap().protected_tags.push(new_tag); this.machine.stacked_borrows.as_mut().unwrap().get_mut().protected_tags.insert(new_tag); } @@ -818,7 +818,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let range = alloc_range(base_offset, size); let mut global = machine.stacked_borrows.as_ref().unwrap().borrow_mut(); let dcx = DiagnosticCxBuilder::retag( - machine.current_span(tcx), + machine.current_span(tcx), // `get_alloc_extra_mut` invalidated our old `current_span` &machine.threads, retag_cause, new_tag, From 15a4f0a9e094f09b658dbb3a176d62c8661dec3b Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 16 Aug 2022 20:32:58 -0400 Subject: [PATCH 3767/5092] some CurrentSpan cleanup --- src/helpers.rs | 29 ++++++------ src/stacked_borrows/diagnostics.rs | 33 ++++++++------ src/stacked_borrows/mod.rs | 72 +++++++++++++++++------------- 3 files changed, 76 insertions(+), 58 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 6f6cbcc38a77..f634c8d0c9ac 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -877,7 +877,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { pub fn current_span(&self, tcx: TyCtxt<'tcx>) -> CurrentSpan<'_, 'mir, 'tcx> { - CurrentSpan { span: None, machine: self, tcx } + CurrentSpan { current_frame_idx: None, machine: self, tcx } } } @@ -887,7 +887,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { /// The result of that search is cached so that later calls are approximately free. #[derive(Clone)] pub struct CurrentSpan<'a, 'mir, 'tcx> { - span: Option, + current_frame_idx: Option, tcx: TyCtxt<'tcx>, machine: &'a Evaluator<'mir, 'tcx>, } @@ -896,25 +896,19 @@ impl<'a, 'mir: 'a, 'tcx: 'a + 'mir> CurrentSpan<'a, 'mir, 'tcx> { /// Get the current span, skipping non-local frames. /// This function is backed by a cache, and can be assumed to be very fast. pub fn get(&mut self) -> Span { - *self.span.get_or_insert_with(|| Self::current_span(self.tcx, self.machine)) + let idx = self.current_frame_idx(); + Self::frame_span(self.machine, idx) } /// Similar to `CurrentSpan::get`, but retrieves the parent frame of the first non-local frame. /// This is useful when we are processing something which occurs on function-entry and we want /// to point at the call to the function, not the function definition generally. - #[inline(never)] pub fn get_parent(&mut self) -> Span { - let idx = Self::current_span_index(self.tcx, self.machine); - Self::nth_span(self.machine, idx.wrapping_sub(1)) + let idx = self.current_frame_idx(); + Self::frame_span(self.machine, idx.wrapping_sub(1)) } - #[inline(never)] - fn current_span(tcx: TyCtxt<'_>, machine: &Evaluator<'_, '_>) -> Span { - let idx = Self::current_span_index(tcx, machine); - Self::nth_span(machine, idx) - } - - fn nth_span(machine: &Evaluator<'_, '_>, idx: usize) -> Span { + fn frame_span(machine: &Evaluator<'_, '_>, idx: usize) -> Span { machine .threads .active_thread_stack() @@ -923,9 +917,16 @@ impl<'a, 'mir: 'a, 'tcx: 'a + 'mir> CurrentSpan<'a, 'mir, 'tcx> { .unwrap_or(rustc_span::DUMMY_SP) } + fn current_frame_idx(&mut self) -> usize { + *self + .current_frame_idx + .get_or_insert_with(|| Self::compute_current_frame_index(self.tcx, self.machine)) + } + // Find the position of the inner-most frame which is part of the crate being // compiled/executed, part of the Cargo workspace, and is also not #[track_caller]. - fn current_span_index(tcx: TyCtxt<'_>, machine: &Evaluator<'_, '_>) -> usize { + #[inline(never)] + fn compute_current_frame_index(tcx: TyCtxt<'_>, machine: &Evaluator<'_, '_>) -> usize { machine .threads .active_thread_stack() diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index be363abad2a4..741a3d363dd3 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -103,26 +103,30 @@ pub struct TagHistory { pub protected: Option<([(String, SpanData); 2])>, } -pub struct DiagnosticCxBuilder<'ecx, 'mir, 'tcx> { +pub struct DiagnosticCxBuilder<'span, 'ecx, 'mir, 'tcx> { operation: Operation, - current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + // 'span cannot be merged with any other lifetime since they appear invariantly, under the + // mutable ref. + current_span: &'span mut CurrentSpan<'ecx, 'mir, 'tcx>, threads: &'ecx ThreadManager<'mir, 'tcx>, } -pub struct DiagnosticCx<'ecx, 'mir, 'tcx, 'history> { +pub struct DiagnosticCx<'span, 'history, 'ecx, 'mir, 'tcx> { operation: Operation, - current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + // 'span and 'history cannot be merged, since when we call `unbuild` we need + // to return the exact 'span that was used when calling `build`. + current_span: &'span mut CurrentSpan<'ecx, 'mir, 'tcx>, threads: &'ecx ThreadManager<'mir, 'tcx>, history: &'history mut AllocHistory, offset: Size, } -impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCxBuilder<'ecx, 'mir, 'tcx> { - pub fn build( +impl<'span, 'ecx, 'mir, 'tcx> DiagnosticCxBuilder<'span, 'ecx, 'mir, 'tcx> { + pub fn build<'history>( self, history: &'history mut AllocHistory, offset: Size, - ) -> DiagnosticCx<'ecx, 'mir, 'tcx, 'history> { + ) -> DiagnosticCx<'span, 'history, 'ecx, 'mir, 'tcx> { DiagnosticCx { operation: self.operation, current_span: self.current_span, @@ -133,7 +137,7 @@ impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCxBuilder<'ecx, 'mir, 'tcx> { } pub fn retag( - current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + current_span: &'span mut CurrentSpan<'ecx, 'mir, 'tcx>, threads: &'ecx ThreadManager<'mir, 'tcx>, cause: RetagCause, new_tag: SbTag, @@ -147,7 +151,7 @@ impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCxBuilder<'ecx, 'mir, 'tcx> { } pub fn read( - current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + current_span: &'span mut CurrentSpan<'ecx, 'mir, 'tcx>, threads: &'ecx ThreadManager<'mir, 'tcx>, tag: ProvenanceExtra, range: AllocRange, @@ -157,7 +161,7 @@ impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCxBuilder<'ecx, 'mir, 'tcx> { } pub fn write( - current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + current_span: &'span mut CurrentSpan<'ecx, 'mir, 'tcx>, threads: &'ecx ThreadManager<'mir, 'tcx>, tag: ProvenanceExtra, range: AllocRange, @@ -167,7 +171,7 @@ impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCxBuilder<'ecx, 'mir, 'tcx> { } pub fn dealloc( - current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + current_span: &'span mut CurrentSpan<'ecx, 'mir, 'tcx>, threads: &'ecx ThreadManager<'mir, 'tcx>, tag: ProvenanceExtra, ) -> Self { @@ -176,8 +180,8 @@ impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCxBuilder<'ecx, 'mir, 'tcx> { } } -impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCx<'ecx, 'mir, 'tcx, 'history> { - pub fn unbuild(self) -> DiagnosticCxBuilder<'ecx, 'mir, 'tcx> { +impl<'span, 'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'span, 'history, 'ecx, 'mir, 'tcx> { + pub fn unbuild(self) -> DiagnosticCxBuilder<'span, 'ecx, 'mir, 'tcx> { DiagnosticCxBuilder { operation: self.operation, current_span: self.current_span, @@ -233,7 +237,7 @@ impl AllocHistory { } } -impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCx<'ecx, 'mir, 'tcx, 'history> { +impl<'span, 'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'span, 'history, 'ecx, 'mir, 'tcx> { pub fn start_grant(&mut self, perm: Permission) { let Operation::Retag(op) = &mut self.operation else { unreachable!("start_grant must only be called during a retag, this is: {:?}", self.operation) @@ -247,6 +251,7 @@ impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCx<'ecx, 'mir, 'tcx, 'history> { } Some(previous) => if previous != perm { + // 'Split up' the creation event. let previous_range = last_creation.retag.range; last_creation.retag.range = alloc_range(previous_range.start, self.offset); let mut new_event = last_creation.clone(); diff --git a/src/stacked_borrows/mod.rs b/src/stacked_borrows/mod.rs index 9861e6fdb17b..66fdd685def5 100644 --- a/src/stacked_borrows/mod.rs +++ b/src/stacked_borrows/mod.rs @@ -286,7 +286,7 @@ impl<'tcx> Stack { fn item_popped( item: &Item, global: &GlobalStateInner, - dcx: &mut DiagnosticCx<'_, '_, 'tcx, '_>, + dcx: &mut DiagnosticCx<'_, '_, '_, '_, 'tcx>, ) -> InterpResult<'tcx> { if !global.tracked_pointer_tags.is_empty() { dcx.check_tracked_tag_popped(item, global); @@ -324,7 +324,7 @@ impl<'tcx> Stack { access: AccessKind, tag: ProvenanceExtra, global: &mut GlobalStateInner, - dcx: &mut DiagnosticCx<'_, '_, 'tcx, '_>, + dcx: &mut DiagnosticCx<'_, '_, '_, '_, 'tcx>, exposed_tags: &FxHashSet, ) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. @@ -410,7 +410,7 @@ impl<'tcx> Stack { &mut self, tag: ProvenanceExtra, global: &GlobalStateInner, - dcx: &mut DiagnosticCx<'_, '_, 'tcx, '_>, + dcx: &mut DiagnosticCx<'_, '_, '_, '_, 'tcx>, exposed_tags: &FxHashSet, ) -> InterpResult<'tcx> { // Step 1: Make sure there is a granting item. @@ -436,7 +436,7 @@ impl<'tcx> Stack { derived_from: ProvenanceExtra, new: Item, global: &mut GlobalStateInner, - dcx: &mut DiagnosticCx<'_, '_, 'tcx, '_>, + dcx: &mut DiagnosticCx<'_, '_, '_, '_, 'tcx>, exposed_tags: &FxHashSet, ) -> InterpResult<'tcx> { dcx.start_grant(new.perm()); @@ -515,10 +515,10 @@ impl<'tcx> Stacks { fn for_each( &mut self, range: AllocRange, - mut dcx_builder: DiagnosticCxBuilder<'_, '_, 'tcx>, + mut dcx_builder: DiagnosticCxBuilder<'_, '_, '_, 'tcx>, mut f: impl FnMut( &mut Stack, - &mut DiagnosticCx<'_, '_, 'tcx, '_>, + &mut DiagnosticCx<'_, '_, '_, '_, 'tcx>, &mut FxHashSet, ) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { @@ -554,22 +554,25 @@ impl Stacks { } #[inline(always)] - pub fn before_memory_read<'tcx, 'mir>( + pub fn before_memory_read<'tcx, 'mir, 'ecx>( &mut self, alloc_id: AllocId, tag: ProvenanceExtra, range: AllocRange, state: &GlobalState, - current_span: CurrentSpan<'_, 'mir, 'tcx>, - threads: &ThreadManager<'mir, 'tcx>, - ) -> InterpResult<'tcx> { + mut current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + threads: &'ecx ThreadManager<'mir, 'tcx>, + ) -> InterpResult<'tcx> + where + 'tcx: 'ecx, + { trace!( "read access with tag {:?}: {:?}, size {}", tag, Pointer::new(alloc_id, range.start), range.size.bytes() ); - let dcx = DiagnosticCxBuilder::read(current_span, threads, tag, range); + let dcx = DiagnosticCxBuilder::read(&mut current_span, threads, tag, range); let mut state = state.borrow_mut(); self.for_each(range, dcx, |stack, dcx, exposed_tags| { stack.access(AccessKind::Read, tag, &mut state, dcx, exposed_tags) @@ -577,14 +580,14 @@ impl Stacks { } #[inline(always)] - pub fn before_memory_write<'tcx, 'mir>( + pub fn before_memory_write<'tcx, 'mir, 'ecx>( &mut self, alloc_id: AllocId, tag: ProvenanceExtra, range: AllocRange, state: &GlobalState, - current_span: CurrentSpan<'_, 'mir, 'tcx>, - threads: &ThreadManager<'mir, 'tcx>, + mut current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + threads: &'ecx ThreadManager<'mir, 'tcx>, ) -> InterpResult<'tcx> { trace!( "write access with tag {:?}: {:?}, size {}", @@ -592,7 +595,7 @@ impl Stacks { Pointer::new(alloc_id, range.start), range.size.bytes() ); - let dcx = DiagnosticCxBuilder::write(current_span, threads, tag, range); + let dcx = DiagnosticCxBuilder::write(&mut current_span, threads, tag, range); let mut state = state.borrow_mut(); self.for_each(range, dcx, |stack, dcx, exposed_tags| { stack.access(AccessKind::Write, tag, &mut state, dcx, exposed_tags) @@ -600,17 +603,17 @@ impl Stacks { } #[inline(always)] - pub fn before_memory_deallocation<'tcx, 'mir>( + pub fn before_memory_deallocation<'tcx, 'mir, 'ecx>( &mut self, alloc_id: AllocId, tag: ProvenanceExtra, range: AllocRange, state: &GlobalState, - current_span: CurrentSpan<'_, 'mir, 'tcx>, - threads: &ThreadManager<'mir, 'tcx>, + mut current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + threads: &'ecx ThreadManager<'mir, 'tcx>, ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", tag, alloc_id, range.size.bytes()); - let dcx = DiagnosticCxBuilder::dealloc(current_span, threads, tag); + let dcx = DiagnosticCxBuilder::dealloc(&mut current_span, threads, tag); let state = state.borrow(); self.for_each(range, dcx, |stack, dcx, exposed_tags| { stack.dealloc(tag, &state, dcx, exposed_tags) @@ -621,8 +624,11 @@ impl Stacks { /// Retagging/reborrowing. There is some policy in here, such as which permissions /// to grant for which references, and when to add protectors. -impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} -trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { +impl<'mir: 'ecx, 'tcx: 'mir, 'ecx> EvalContextPrivExt<'mir, 'tcx, 'ecx> + for crate::MiriEvalContext<'mir, 'tcx> +{ +} +trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Returns the `AllocId` the reborrow was done in, if some actual borrow stack manipulation /// happened. fn reborrow( @@ -635,11 +641,9 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx protect: bool, ) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); - let current_span = this.machine.current_span(*this.tcx); // It is crucial that this gets called on all code paths, to ensure we track tag creation. let log_creation = |this: &MiriEvalContext<'mir, 'tcx>, - current_span: CurrentSpan<'_, 'mir, 'tcx>, loc: Option<(AllocId, Size, ProvenanceExtra)>| // alloc_id, base_offset, orig_tag -> InterpResult<'tcx> { let global = this.machine.stacked_borrows.as_ref().unwrap().borrow(); @@ -658,6 +662,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (_size, _align, alloc_kind) = this.get_alloc_info(alloc_id); match alloc_kind { AllocKind::LiveData => { + let current_span = &mut this.machine.current_span(*this.tcx); // This should have alloc_extra data, but `get_alloc_extra` can still fail // if converting this alloc_id from a global to a local one // uncovers a non-supported `extern static`. @@ -667,9 +672,12 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .as_ref() .expect("we should have Stacked Borrows data") .borrow_mut(); - let dcx = DiagnosticCxBuilder::retag( + let threads = &this.machine.threads; + // Note that we create a *second* `DiagnosticCxBuilder` below for the actual retag. + // FIXME: can this be done cleaner? + let dcx = DiagnosticCxBuilder::retag( current_span, - &this.machine.threads, + threads, retag_cause, new_tag, orig_tag, @@ -704,16 +712,16 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dangling slices are a common case here; it's valid to get their length but with raw // pointer tagging for example all calls to get_unchecked on them are invalid. if let Ok((alloc_id, base_offset, orig_tag)) = this.ptr_try_get_alloc_id(place.ptr) { - log_creation(this, current_span, Some((alloc_id, base_offset, orig_tag)))?; + log_creation(this, Some((alloc_id, base_offset, orig_tag)))?; return Ok(Some(alloc_id)); } // This pointer doesn't come with an AllocId. :shrug: - log_creation(this, current_span, None)?; + log_creation(this, None)?; return Ok(None); } let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?; - log_creation(this, current_span, Some((alloc_id, base_offset, orig_tag)))?; + log_creation(this, Some((alloc_id, base_offset, orig_tag)))?; // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). let (alloc_size, _) = this.get_live_alloc_size_and_align(alloc_id)?; @@ -770,6 +778,8 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .as_ref() .expect("we should have Stacked Borrows data") .borrow_mut(); + // FIXME: can't share this with the current_span inside log_creation + let mut current_span = this.machine.current_span(*this.tcx); this.visit_freeze_sensitive(place, size, |mut range, frozen| { // Adjust range. range.start += base_offset; @@ -789,7 +799,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let item = Item::new(new_tag, perm, protected); let mut global = this.machine.stacked_borrows.as_ref().unwrap().borrow_mut(); let dcx = DiagnosticCxBuilder::retag( - this.machine.current_span(*this.tcx), + &mut current_span, // FIXME avoid this `clone` &this.machine.threads, retag_cause, new_tag, @@ -817,8 +827,10 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let item = Item::new(new_tag, perm, protect); let range = alloc_range(base_offset, size); let mut global = machine.stacked_borrows.as_ref().unwrap().borrow_mut(); + // FIXME: can't share this with the current_span inside log_creation + let current_span = &mut machine.current_span(tcx); let dcx = DiagnosticCxBuilder::retag( - machine.current_span(tcx), // `get_alloc_extra_mut` invalidated our old `current_span` + current_span, &machine.threads, retag_cause, new_tag, From 7397c8e9cf73ff338c0e00a64a4de66fd9553df3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Aug 2022 15:32:45 -0400 Subject: [PATCH 3768/5092] re-bless after rebase --- .../stacked_borrows/disable_mut_does_not_merge_srw.stderr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr b/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr index 9f5182ae98ff..a959bb90fbb7 100644 --- a/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr +++ b/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr @@ -9,12 +9,12 @@ LL | let _val = *raw; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadWrite retag at offsets [0x0..0x4] --> $DIR/disable_mut_does_not_merge_srw.rs:LL:CC | LL | mutref as *mut i32 | ^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a write access --> $DIR/disable_mut_does_not_merge_srw.rs:LL:CC | LL | *base = 1; From 8118a31e86ac0f468e47a3ba794b01c8e36db25d Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Thu, 18 Aug 2022 16:04:00 -0700 Subject: [PATCH 3769/5092] Inline `>::from` I noticed in the MIR for that it's inlined most stuff ``` scope 5 (inlined as Try>::branch) ``` ``` scope 8 (inlined as Try>::from_output) ``` But yet the do-nothing `from` call was still there: ``` _17 = >::from(move _18) -> bb9; ``` So let's give this a try and see what perf has to say. --- library/core/src/convert/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index b30c8a4aeabd..ff10a243d907 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -556,6 +556,7 @@ where #[rustc_const_unstable(feature = "const_convert", issue = "88674")] impl const From for T { /// Returns the argument unchanged. + #[inline(always)] fn from(t: T) -> T { t } From 2666c38acb8352b7fd5903f50ee5fd76e2441cff Mon Sep 17 00:00:00 2001 From: Serial <69764315+Serial-ATA@users.noreply.github.com> Date: Thu, 28 Jul 2022 20:50:43 -0400 Subject: [PATCH 3770/5092] Add [`unused_peekable`] lint --- CHANGELOG.md | 1 + clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_suspicious.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/unused_peekable.rs | 208 ++++++++++++++++++++ clippy_utils/src/paths.rs | 1 + clippy_utils/src/ty.rs | 2 +- tests/ui/unused_peekable.rs | 119 +++++++++++ tests/ui/unused_peekable.stderr | 51 +++++ 10 files changed, 386 insertions(+), 1 deletion(-) create mode 100644 clippy_lints/src/unused_peekable.rs create mode 100644 tests/ui/unused_peekable.rs create mode 100644 tests/ui/unused_peekable.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index edd7bc250a75..c42a03c04a00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4152,6 +4152,7 @@ Released 2018-09-13 [`unused_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_collect [`unused_io_amount`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount [`unused_label`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_label +[`unused_peekable`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_peekable [`unused_rounding`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_rounding [`unused_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_self [`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index a0a4b07a77e5..de0514c1b665 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -337,6 +337,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY), LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), LintId::of(unused_io_amount::UNUSED_IO_AMOUNT), + LintId::of(unused_peekable::UNUSED_PEEKABLE), LintId::of(unused_unit::UNUSED_UNIT), LintId::of(unwrap::PANICKING_UNWRAP), LintId::of(unwrap::UNNECESSARY_UNWRAP), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index b7dbd30aa0c8..eb23bb0c7dbe 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -573,6 +573,7 @@ store.register_lints(&[ unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, unused_async::UNUSED_ASYNC, unused_io_amount::UNUSED_IO_AMOUNT, + unused_peekable::UNUSED_PEEKABLE, unused_rounding::UNUSED_ROUNDING, unused_self::UNUSED_SELF, unused_unit::UNUSED_UNIT, diff --git a/clippy_lints/src/lib.register_suspicious.rs b/clippy_lints/src/lib.register_suspicious.rs index 6e185f8d31ee..5793d59bcad1 100644 --- a/clippy_lints/src/lib.register_suspicious.rs +++ b/clippy_lints/src/lib.register_suspicious.rs @@ -33,4 +33,5 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec! LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), LintId::of(swap_ptr_to_ref::SWAP_PTR_TO_REF), LintId::of(write::POSITIONAL_NAMED_FORMAT_PARAMETERS), + LintId::of(unused_peekable::UNUSED_PEEKABLE), ]) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index a041fbc7fd97..d4c6c4918cb3 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -398,6 +398,7 @@ mod unnested_or_patterns; mod unsafe_removed_from_name; mod unused_async; mod unused_io_amount; +mod unused_peekable; mod unused_rounding; mod unused_self; mod unused_unit; @@ -935,6 +936,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(manual_instant_elapsed::ManualInstantElapsed)); store.register_late_pass(|| Box::new(partialeq_to_none::PartialeqToNone)); store.register_late_pass(|| Box::new(manual_empty_string_creations::ManualEmptyStringCreations)); + store.register_late_pass(|| Box::new(unused_peekable::UnusedPeekable::default())); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/unused_peekable.rs b/clippy_lints/src/unused_peekable.rs new file mode 100644 index 000000000000..4988ec0eca12 --- /dev/null +++ b/clippy_lints/src/unused_peekable.rs @@ -0,0 +1,208 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::ty::{match_type, peel_mid_ty_refs_is_mutable}; +use clippy_utils::{fn_def_id, path_to_local_id, paths, peel_ref_operators}; +use rustc_ast::Mutability; +use rustc_hir::intravisit::{walk_expr, Visitor}; +use rustc_hir::lang_items::LangItem; +use rustc_hir::{Block, Expr, ExprKind, HirId, Local, Node, PatKind, PathSegment, StmtKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::Ty; +use rustc_session::{declare_tool_lint, impl_lint_pass}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for the creation of a `peekable` iterator that is never `.peek()`ed + /// + /// ### Why is this bad? + /// Creating a peekable iterator without using any of its methods is likely a mistake, + /// or just a leftover after a refactor. + /// + /// ### Example + /// ```rust + /// let collection = vec![1, 2, 3]; + /// let iter = collection.iter().peekable(); + /// + /// for item in iter { + /// // ... + /// } + /// ``` + /// + /// Use instead: + /// ```rust + /// let collection = vec![1, 2, 3]; + /// let iter = collection.iter(); + /// + /// for item in iter { + /// // ... + /// } + /// ``` + #[clippy::version = "1.64.0"] + pub UNUSED_PEEKABLE, + suspicious, + "creating a peekable iterator without using any of its methods" +} + +#[derive(Default)] +pub struct UnusedPeekable { + visited: Vec, +} + +impl_lint_pass!(UnusedPeekable => [UNUSED_PEEKABLE]); + +impl<'tcx> LateLintPass<'tcx> for UnusedPeekable { + fn check_block(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) { + // Don't lint `Peekable`s returned from a block + if let Some(expr) = block.expr + && let Some(ty) = cx.typeck_results().expr_ty_opt(peel_ref_operators(cx, expr)) + && match_type(cx, ty, &paths::PEEKABLE) + { + return; + } + + for (idx, stmt) in block.stmts.iter().enumerate() { + if !stmt.span.from_expansion() + && let StmtKind::Local(local) = stmt.kind + && !self.visited.contains(&local.pat.hir_id) + && let PatKind::Binding(_, _, ident, _) = local.pat.kind + && let Some(init) = local.init + && !init.span.from_expansion() + && let Some(ty) = cx.typeck_results().expr_ty_opt(init) + && let (ty, _, Mutability::Mut) = peel_mid_ty_refs_is_mutable(ty) + && match_type(cx, ty, &paths::PEEKABLE) + { + let mut vis = PeekableVisitor::new(cx, local.pat.hir_id); + + if idx + 1 == block.stmts.len() && block.expr.is_none() { + return; + } + + for stmt in &block.stmts[idx..] { + vis.visit_stmt(stmt); + } + + if let Some(expr) = block.expr { + vis.visit_expr(expr); + } + + if !vis.found_peek_call { + span_lint_and_help( + cx, + UNUSED_PEEKABLE, + ident.span, + "`peek` never called on `Peekable` iterator", + None, + "consider removing the call to `peekable`" + ); + } + } + } + } +} + +struct PeekableVisitor<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + expected_hir_id: HirId, + found_peek_call: bool, +} + +impl<'a, 'tcx> PeekableVisitor<'a, 'tcx> { + fn new(cx: &'a LateContext<'tcx>, expected_hir_id: HirId) -> Self { + Self { + cx, + expected_hir_id, + found_peek_call: false, + } + } +} + +impl<'tcx> Visitor<'_> for PeekableVisitor<'_, 'tcx> { + fn visit_expr(&mut self, ex: &'_ Expr<'_>) { + if path_to_local_id(ex, self.expected_hir_id) { + for (_, node) in self.cx.tcx.hir().parent_iter(ex.hir_id) { + match node { + Node::Expr(expr) => { + match expr.kind { + // some_function(peekable) + // + // If the Peekable is passed to a function, stop + ExprKind::Call(_, args) => { + if let Some(func_did) = fn_def_id(self.cx, expr) + && let Ok(into_iter_did) = self + .cx + .tcx + .lang_items() + .require(LangItem::IntoIterIntoIter) + && func_did == into_iter_did + { + // Probably a for loop desugar, stop searching + return; + } + + for arg in args.iter().map(|arg| peel_ref_operators(self.cx, arg)) { + if let ExprKind::Path(_) = arg.kind + && let Some(ty) = self + .cx + .typeck_results() + .expr_ty_opt(arg) + .map(Ty::peel_refs) + && match_type(self.cx, ty, &paths::PEEKABLE) + { + self.found_peek_call = true; + return; + } + } + }, + // Peekable::peek() + ExprKind::MethodCall(PathSegment { ident: method_name, .. }, [arg, ..], _) => { + let arg = peel_ref_operators(self.cx, arg); + let method_name = method_name.name.as_str(); + + if (method_name == "peek" + || method_name == "peek_mut" + || method_name == "next_if" + || method_name == "next_if_eq") + && let ExprKind::Path(_) = arg.kind + && let Some(ty) = self.cx.typeck_results().expr_ty_opt(arg).map(Ty::peel_refs) + && match_type(self.cx, ty, &paths::PEEKABLE) + { + self.found_peek_call = true; + return; + } + }, + // Don't bother if moved into a struct + ExprKind::Struct(..) => { + self.found_peek_call = true; + return; + }, + _ => {}, + } + }, + Node::Local(Local { init: Some(init), .. }) => { + if let Some(ty) = self.cx.typeck_results().expr_ty_opt(init) + && let (ty, _, Mutability::Mut) = peel_mid_ty_refs_is_mutable(ty) + && match_type(self.cx, ty, &paths::PEEKABLE) + { + self.found_peek_call = true; + return; + } + + break; + }, + Node::Stmt(stmt) => match stmt.kind { + StmtKind::Expr(_) | StmtKind::Semi(_) => {}, + _ => { + self.found_peek_call = true; + return; + }, + }, + Node::Block(_) => {}, + _ => { + break; + }, + } + } + } + + walk_expr(self, ex); + } +} diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 8d697a301c44..d3ae537a890d 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -96,6 +96,7 @@ pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwL pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 3] = ["lock_api", "rwlock", "RwLockWriteGuard"]; pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"]; pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"]; +pub const PEEKABLE: [&str; 5] = ["core", "iter", "adapters", "peekable", "Peekable"]; pub const PERMISSIONS: [&str; 3] = ["std", "fs", "Permissions"]; #[cfg_attr(not(unix), allow(clippy::invalid_paths))] pub const PERMISSIONS_FROM_MODE: [&str; 6] = ["std", "os", "unix", "fs", "PermissionsExt", "from_mode"]; diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index e7d670766a05..edbe9c5a8970 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -410,7 +410,7 @@ pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) { peel(ty, 0) } -/// Peels off all references on the type.Returns the underlying type, the number of references +/// Peels off all references on the type. Returns the underlying type, the number of references /// removed, and whether the pointer is ultimately mutable or not. pub fn peel_mid_ty_refs_is_mutable(ty: Ty<'_>) -> (Ty<'_>, usize, Mutability) { fn f(ty: Ty<'_>, count: usize, mutability: Mutability) -> (Ty<'_>, usize, Mutability) { diff --git a/tests/ui/unused_peekable.rs b/tests/ui/unused_peekable.rs new file mode 100644 index 000000000000..12cab9956219 --- /dev/null +++ b/tests/ui/unused_peekable.rs @@ -0,0 +1,119 @@ +#![warn(clippy::unused_peekable)] +#![allow(clippy::no_effect)] + +use std::iter::Empty; +use std::iter::Peekable; + +fn main() { + invalid(); + valid(); +} + +#[allow(clippy::unused_unit)] +fn invalid() { + let peekable = std::iter::empty::().peekable(); + + // Only lint `new_local` + let old_local = std::iter::empty::().peekable(); + let new_local = old_local; + + // Behind mut ref + let mut by_mut_ref_test = std::iter::empty::().peekable(); + let by_mut_ref = &mut by_mut_ref_test; + + // Explicitly returns `Peekable` + fn returns_peekable() -> Peekable> { + std::iter::empty().peekable() + } + + let peekable_from_fn = returns_peekable(); + + // Using a method not exclusive to `Peekable` + let mut peekable_using_iterator_method = std::iter::empty::().peekable(); + peekable_using_iterator_method.next(); + + let mut peekable_in_for_loop = std::iter::empty::().peekable(); + for x in peekable_in_for_loop {} +} + +fn valid() { + fn takes_peekable(_peek: Peekable>) {} + + // Passed to another function + let passed_along = std::iter::empty::().peekable(); + takes_peekable(passed_along); + + // `peek` called in another block + let mut peekable_in_block = std::iter::empty::().peekable(); + { + peekable_in_block.peek(); + } + + // Check the other `Peekable` methods :) + { + let mut peekable_with_peek_mut = std::iter::empty::().peekable(); + peekable_with_peek_mut.peek_mut(); + + let mut peekable_with_next_if = std::iter::empty::().peekable(); + peekable_with_next_if.next_if(|_| true); + + let mut peekable_with_next_if_eq = std::iter::empty::().peekable(); + peekable_with_next_if_eq.next_if_eq(&3); + } + + let mut peekable_in_closure = std::iter::empty::().peekable(); + let call_peek = |p: &mut Peekable>| { + p.peek(); + }; + call_peek(&mut peekable_in_closure); + + // From a macro + macro_rules! make_me_a_peekable_please { + () => { + std::iter::empty::().peekable() + }; + } + + let _unsuspecting_macro_user = make_me_a_peekable_please!(); + + // Generic Iterator returned + fn return_an_iter() -> impl Iterator { + std::iter::empty::().peekable() + } + + let _unsuspecting_user = return_an_iter(); + + // Call `peek` in a macro + macro_rules! peek_iter { + ($iter:ident) => { + $iter.peek(); + }; + } + + let mut peek_in_macro = std::iter::empty::().peekable(); + peek_iter!(peek_in_macro); + + // Behind mut ref + let mut by_mut_ref_test = std::iter::empty::().peekable(); + let by_mut_ref = &mut by_mut_ref_test; + by_mut_ref.peek(); + + // Behind ref + let mut by_ref_test = std::iter::empty::().peekable(); + let by_ref = &by_ref_test; + by_ref_test.peek(); + + // In struct + struct PeekableWrapper { + f: Peekable>, + } + + let struct_test = std::iter::empty::().peekable(); + PeekableWrapper { f: struct_test }; + + // `peek` called in another block as the last expression + let mut peekable_last_expr = std::iter::empty::().peekable(); + { + peekable_last_expr.peek(); + } +} diff --git a/tests/ui/unused_peekable.stderr b/tests/ui/unused_peekable.stderr new file mode 100644 index 000000000000..bd087f56e4ce --- /dev/null +++ b/tests/ui/unused_peekable.stderr @@ -0,0 +1,51 @@ +error: `peek` never called on `Peekable` iterator + --> $DIR/unused_peekable.rs:14:9 + | +LL | let peekable = std::iter::empty::().peekable(); + | ^^^^^^^^ + | + = note: `-D clippy::unused-peekable` implied by `-D warnings` + = help: consider removing the call to `peekable` + +error: `peek` never called on `Peekable` iterator + --> $DIR/unused_peekable.rs:18:9 + | +LL | let new_local = old_local; + | ^^^^^^^^^ + | + = help: consider removing the call to `peekable` + +error: `peek` never called on `Peekable` iterator + --> $DIR/unused_peekable.rs:22:9 + | +LL | let by_mut_ref = &mut by_mut_ref_test; + | ^^^^^^^^^^ + | + = help: consider removing the call to `peekable` + +error: `peek` never called on `Peekable` iterator + --> $DIR/unused_peekable.rs:29:9 + | +LL | let peekable_from_fn = returns_peekable(); + | ^^^^^^^^^^^^^^^^ + | + = help: consider removing the call to `peekable` + +error: `peek` never called on `Peekable` iterator + --> $DIR/unused_peekable.rs:32:13 + | +LL | let mut peekable_using_iterator_method = std::iter::empty::().peekable(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider removing the call to `peekable` + +error: `peek` never called on `Peekable` iterator + --> $DIR/unused_peekable.rs:35:13 + | +LL | let mut peekable_in_for_loop = std::iter::empty::().peekable(); + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider removing the call to `peekable` + +error: aborting due to 6 previous errors + From 0efafa4a6e2d96f55584fe77782c289199a560b1 Mon Sep 17 00:00:00 2001 From: Serial <69764315+Serial-ATA@users.noreply.github.com> Date: Fri, 5 Aug 2022 13:49:43 -0400 Subject: [PATCH 3771/5092] Better handle method/function calls --- clippy_lints/src/lib.register_suspicious.rs | 2 +- clippy_lints/src/lib.rs | 2 +- clippy_lints/src/unused_peekable.rs | 109 +++++++++++--------- tests/ui/unused_peekable.rs | 25 +++++ tests/ui/unused_peekable.stderr | 20 +++- 5 files changed, 108 insertions(+), 50 deletions(-) diff --git a/clippy_lints/src/lib.register_suspicious.rs b/clippy_lints/src/lib.register_suspicious.rs index 5793d59bcad1..369d4b4eed69 100644 --- a/clippy_lints/src/lib.register_suspicious.rs +++ b/clippy_lints/src/lib.register_suspicious.rs @@ -32,6 +32,6 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec! LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), LintId::of(swap_ptr_to_ref::SWAP_PTR_TO_REF), - LintId::of(write::POSITIONAL_NAMED_FORMAT_PARAMETERS), LintId::of(unused_peekable::UNUSED_PEEKABLE), + LintId::of(write::POSITIONAL_NAMED_FORMAT_PARAMETERS), ]) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index d4c6c4918cb3..2a0fb30131f7 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -936,7 +936,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(manual_instant_elapsed::ManualInstantElapsed)); store.register_late_pass(|| Box::new(partialeq_to_none::PartialeqToNone)); store.register_late_pass(|| Box::new(manual_empty_string_creations::ManualEmptyStringCreations)); - store.register_late_pass(|| Box::new(unused_peekable::UnusedPeekable::default())); + store.register_late_pass(|| Box::new(unused_peekable::UnusedPeekable)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/unused_peekable.rs b/clippy_lints/src/unused_peekable.rs index 4988ec0eca12..c060d767e234 100644 --- a/clippy_lints/src/unused_peekable.rs +++ b/clippy_lints/src/unused_peekable.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::{match_type, peel_mid_ty_refs_is_mutable}; -use clippy_utils::{fn_def_id, path_to_local_id, paths, peel_ref_operators}; +use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, paths, peel_ref_operators}; use rustc_ast::Mutability; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::lang_items::LangItem; use rustc_hir::{Block, Expr, ExprKind, HirId, Local, Node, PatKind, PathSegment, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::Ty; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -42,12 +42,7 @@ declare_clippy_lint! { "creating a peekable iterator without using any of its methods" } -#[derive(Default)] -pub struct UnusedPeekable { - visited: Vec, -} - -impl_lint_pass!(UnusedPeekable => [UNUSED_PEEKABLE]); +declare_lint_pass!(UnusedPeekable => [UNUSED_PEEKABLE]); impl<'tcx> LateLintPass<'tcx> for UnusedPeekable { fn check_block(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) { @@ -62,15 +57,14 @@ impl<'tcx> LateLintPass<'tcx> for UnusedPeekable { for (idx, stmt) in block.stmts.iter().enumerate() { if !stmt.span.from_expansion() && let StmtKind::Local(local) = stmt.kind - && !self.visited.contains(&local.pat.hir_id) - && let PatKind::Binding(_, _, ident, _) = local.pat.kind + && let PatKind::Binding(_, binding, ident, _) = local.pat.kind && let Some(init) = local.init && !init.span.from_expansion() && let Some(ty) = cx.typeck_results().expr_ty_opt(init) && let (ty, _, Mutability::Mut) = peel_mid_ty_refs_is_mutable(ty) && match_type(cx, ty, &paths::PEEKABLE) { - let mut vis = PeekableVisitor::new(cx, local.pat.hir_id); + let mut vis = PeekableVisitor::new(cx, binding); if idx + 1 == block.stmts.len() && block.expr.is_none() { return; @@ -117,6 +111,10 @@ impl<'a, 'tcx> PeekableVisitor<'a, 'tcx> { impl<'tcx> Visitor<'_> for PeekableVisitor<'_, 'tcx> { fn visit_expr(&mut self, ex: &'_ Expr<'_>) { + if self.found_peek_call { + return; + } + if path_to_local_id(ex, self.expected_hir_id) { for (_, node) in self.cx.tcx.hir().parent_iter(ex.hir_id) { match node { @@ -138,50 +136,58 @@ impl<'tcx> Visitor<'_> for PeekableVisitor<'_, 'tcx> { return; } - for arg in args.iter().map(|arg| peel_ref_operators(self.cx, arg)) { - if let ExprKind::Path(_) = arg.kind - && let Some(ty) = self - .cx - .typeck_results() - .expr_ty_opt(arg) - .map(Ty::peel_refs) - && match_type(self.cx, ty, &paths::PEEKABLE) - { - self.found_peek_call = true; - return; - } - } - }, - // Peekable::peek() - ExprKind::MethodCall(PathSegment { ident: method_name, .. }, [arg, ..], _) => { - let arg = peel_ref_operators(self.cx, arg); - let method_name = method_name.name.as_str(); - - if (method_name == "peek" - || method_name == "peek_mut" - || method_name == "next_if" - || method_name == "next_if_eq") - && let ExprKind::Path(_) = arg.kind - && let Some(ty) = self.cx.typeck_results().expr_ty_opt(arg).map(Ty::peel_refs) - && match_type(self.cx, ty, &paths::PEEKABLE) - { + if args.iter().any(|arg| { + matches!(arg.kind, ExprKind::Path(_)) && arg_is_mut_peekable(self.cx, arg) + }) { self.found_peek_call = true; return; } }, - // Don't bother if moved into a struct - ExprKind::Struct(..) => { + // Catch anything taking a Peekable mutably + ExprKind::MethodCall( + PathSegment { + ident: method_name_ident, + .. + }, + [self_arg, remaining_args @ ..], + _, + ) => { + let method_name = method_name_ident.name.as_str(); + + // `Peekable` methods + if matches!(method_name, "peek" | "peek_mut" | "next_if" | "next_if_eq") + && arg_is_mut_peekable(self.cx, self_arg) + { + self.found_peek_call = true; + return; + } + + // foo.some_method() excluding Iterator methods + if remaining_args.iter().any(|arg| arg_is_mut_peekable(self.cx, arg)) + && !is_trait_method(self.cx, expr, sym::Iterator) + { + self.found_peek_call = true; + return; + } + + // foo.by_ref(), keep checking for `peek` + if method_name == "by_ref" { + continue; + } + + return; + }, + ExprKind::AddrOf(_, Mutability::Mut, _) | ExprKind::Unary(..) | ExprKind::DropTemps(_) => { + }, + ExprKind::AddrOf(_, Mutability::Not, _) => return, + _ => { self.found_peek_call = true; return; }, - _ => {}, } }, Node::Local(Local { init: Some(init), .. }) => { - if let Some(ty) = self.cx.typeck_results().expr_ty_opt(init) - && let (ty, _, Mutability::Mut) = peel_mid_ty_refs_is_mutable(ty) - && match_type(self.cx, ty, &paths::PEEKABLE) - { + if arg_is_mut_peekable(self.cx, init) { self.found_peek_call = true; return; } @@ -206,3 +212,14 @@ impl<'tcx> Visitor<'_> for PeekableVisitor<'_, 'tcx> { walk_expr(self, ex); } } + +fn arg_is_mut_peekable(cx: &LateContext<'_>, arg: &Expr<'_>) -> bool { + if let Some(ty) = cx.typeck_results().expr_ty_opt(arg) + && let (ty, _, Mutability::Mut) = peel_mid_ty_refs_is_mutable(ty) + && match_type(cx, ty, &paths::PEEKABLE) + { + true + } else { + false + } +} diff --git a/tests/ui/unused_peekable.rs b/tests/ui/unused_peekable.rs index 12cab9956219..153457e36716 100644 --- a/tests/ui/unused_peekable.rs +++ b/tests/ui/unused_peekable.rs @@ -32,6 +32,15 @@ fn invalid() { let mut peekable_using_iterator_method = std::iter::empty::().peekable(); peekable_using_iterator_method.next(); + // Passed by ref to another function + fn takes_ref(_peek: &Peekable>) {} + let passed_along_ref = std::iter::empty::().peekable(); + takes_ref(&passed_along_ref); + + // `by_ref` without `peek` + let mut by_ref_test = std::iter::empty::().peekable(); + let _by_ref = by_ref_test.by_ref(); + let mut peekable_in_for_loop = std::iter::empty::().peekable(); for x in peekable_in_for_loop {} } @@ -43,6 +52,18 @@ fn valid() { let passed_along = std::iter::empty::().peekable(); takes_peekable(passed_along); + // Passed to another method + struct PeekableConsumer; + impl PeekableConsumer { + fn consume(&self, _: Peekable>) {} + fn consume_mut_ref(&self, _: &mut Peekable>) {} + } + + let peekable_consumer = PeekableConsumer; + let mut passed_along_to_method = std::iter::empty::().peekable(); + peekable_consumer.consume_mut_ref(&mut passed_along_to_method); + peekable_consumer.consume(passed_along_to_method); + // `peek` called in another block let mut peekable_in_block = std::iter::empty::().peekable(); { @@ -111,6 +132,10 @@ fn valid() { let struct_test = std::iter::empty::().peekable(); PeekableWrapper { f: struct_test }; + // `by_ref` before `peek` + let mut by_ref_test = std::iter::empty::().peekable(); + let peeked_val = by_ref_test.by_ref().peek(); + // `peek` called in another block as the last expression let mut peekable_last_expr = std::iter::empty::().peekable(); { diff --git a/tests/ui/unused_peekable.stderr b/tests/ui/unused_peekable.stderr index bd087f56e4ce..d557f54179db 100644 --- a/tests/ui/unused_peekable.stderr +++ b/tests/ui/unused_peekable.stderr @@ -40,12 +40,28 @@ LL | let mut peekable_using_iterator_method = std::iter::empty::().peek = help: consider removing the call to `peekable` error: `peek` never called on `Peekable` iterator - --> $DIR/unused_peekable.rs:35:13 + --> $DIR/unused_peekable.rs:37:9 + | +LL | let passed_along_ref = std::iter::empty::().peekable(); + | ^^^^^^^^^^^^^^^^ + | + = help: consider removing the call to `peekable` + +error: `peek` never called on `Peekable` iterator + --> $DIR/unused_peekable.rs:42:9 + | +LL | let _by_ref = by_ref_test.by_ref(); + | ^^^^^^^ + | + = help: consider removing the call to `peekable` + +error: `peek` never called on `Peekable` iterator + --> $DIR/unused_peekable.rs:44:13 | LL | let mut peekable_in_for_loop = std::iter::empty::().peekable(); | ^^^^^^^^^^^^^^^^^^^^ | = help: consider removing the call to `peekable` -error: aborting due to 6 previous errors +error: aborting due to 8 previous errors From 6669ea81c329b3c1451132e1139d0a8d0dc3cba0 Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Thu, 18 Aug 2022 03:02:42 -0400 Subject: [PATCH 3772/5092] Leave attrs on the variant, not the extracted struct --- .../extract_struct_from_enum_variant.rs | 82 +++++++------------ 1 file changed, 30 insertions(+), 52 deletions(-) diff --git a/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs index dfb565212646..3738718b3c6c 100644 --- a/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs @@ -101,21 +101,21 @@ pub(crate) fn extract_struct_from_enum_variant( }); } - let indent = enum_ast.indent_level(); let generic_params = enum_ast .generic_param_list() .and_then(|known_generics| extract_generic_params(&known_generics, &field_list)); let generics = generic_params.as_ref().map(|generics| generics.clone_for_update()); - let def = - create_struct_def(variant_name.clone(), &variant, &field_list, generics, &enum_ast); + let def = create_struct_def(variant_name.clone(), &field_list, generics, &enum_ast); + + let enum_ast = variant.parent_enum(); + let indent = enum_ast.indent_level(); def.reindent_to(indent); - let start_offset = &variant.parent_enum().syntax().clone(); - ted::insert_all_raw( - ted::Position::before(start_offset), + ted::insert_all( + ted::Position::before(enum_ast.syntax()), vec![ def.syntax().clone().into(), - make::tokens::whitespace(&format!("\n\n{}", indent)).into(), + make::tokens::whitespace(&format!("\n\n{indent}")).into(), ], ); @@ -227,8 +227,7 @@ fn tag_generics_in_variant(ty: &ast::Type, generics: &mut [(ast::GenericParam, b } fn create_struct_def( - variant_name: ast::Name, - variant: &ast::Variant, + name: ast::Name, field_list: &Either, generics: Option, enum_: &ast::Enum, @@ -269,37 +268,9 @@ fn create_struct_def( field_list.into() } }; - field_list.reindent_to(IndentLevel::single()); - let strukt = make::struct_(enum_vis, variant_name, generics, field_list).clone_for_update(); - - // FIXME: Consider making this an actual function somewhere (like in `AttrsOwnerEdit`) after some deliberation - let attrs_and_docs = |node: &SyntaxNode| { - let mut select_next_ws = false; - node.children_with_tokens().filter(move |child| { - let accept = match child.kind() { - ATTR | COMMENT => { - select_next_ws = true; - return true; - } - WHITESPACE if select_next_ws => true, - _ => false, - }; - select_next_ws = false; - - accept - }) - }; - - // copy attributes & comments from variant - let variant_attrs = attrs_and_docs(variant.syntax()) - .map(|tok| match tok.kind() { - WHITESPACE => make::tokens::single_newline().into(), - _ => tok, - }) - .collect(); - ted::insert_all(ted::Position::first_child_of(strukt.syntax()), variant_attrs); + let strukt = make::struct_(enum_vis, name, generics, field_list).clone_for_update(); // copy attributes from enum ted::insert_all( @@ -346,13 +317,20 @@ fn update_variant(variant: &ast::Variant, generics: Option Date: Thu, 18 Aug 2022 11:25:13 -0400 Subject: [PATCH 3773/5092] Insert newline after extracted struct's attributes --- .../handlers/extract_struct_from_enum_variant.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs index 3738718b3c6c..906be27ddbb8 100644 --- a/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs @@ -275,8 +275,14 @@ fn create_struct_def( // copy attributes from enum ted::insert_all( ted::Position::first_child_of(strukt.syntax()), - enum_.attrs().map(|it| it.syntax().clone_for_update().into()).collect(), + enum_ + .attrs() + .flat_map(|it| { + vec![it.syntax().clone_for_update().into(), make::tokens::single_newline().into()] + }) + .collect(), ); + strukt } @@ -458,10 +464,14 @@ enum En { Var(Var) }"#, fn test_extract_struct_carries_over_attributes() { check_assist( extract_struct_from_enum_variant, - r#"#[derive(Debug)] + r#" +#[derive(Debug)] #[derive(Clone)] enum Enum { Variant{ field: u32$0 } }"#, - r#"#[derive(Debug)]#[derive(Clone)] struct Variant{ field: u32 } + r#" +#[derive(Debug)] +#[derive(Clone)] +struct Variant{ field: u32 } #[derive(Debug)] #[derive(Clone)] From 8ab2f880d00bea8822f78289bbd3d1ae59990121 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 09:13:13 -0400 Subject: [PATCH 3774/5092] Move `AsUnderscore` into `Casts` lint pass --- clippy_lints/src/as_underscore.rs | 74 -------------------- clippy_lints/src/casts/as_underscore.rs | 25 +++++++ clippy_lints/src/casts/mod.rs | 38 +++++++++- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_restriction.rs | 2 +- clippy_lints/src/lib.rs | 2 - 6 files changed, 62 insertions(+), 81 deletions(-) delete mode 100644 clippy_lints/src/as_underscore.rs create mode 100644 clippy_lints/src/casts/as_underscore.rs diff --git a/clippy_lints/src/as_underscore.rs b/clippy_lints/src/as_underscore.rs deleted file mode 100644 index 5b4b2c631c89..000000000000 --- a/clippy_lints/src/as_underscore.rs +++ /dev/null @@ -1,74 +0,0 @@ -use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; -use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, TyKind}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; -use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -declare_clippy_lint! { - /// ### What it does - /// Check for the usage of `as _` conversion using inferred type. - /// - /// ### Why is this bad? - /// The conversion might include lossy conversion and dangerous cast that might go - /// undetected due to the type being inferred. - /// - /// The lint is allowed by default as using `_` is less wordy than always specifying the type. - /// - /// ### Example - /// ```rust - /// fn foo(n: usize) {} - /// let n: u16 = 256; - /// foo(n as _); - /// ``` - /// Use instead: - /// ```rust - /// fn foo(n: usize) {} - /// let n: u16 = 256; - /// foo(n as usize); - /// ``` - #[clippy::version = "1.63.0"] - pub AS_UNDERSCORE, - restriction, - "detects `as _` conversion" -} -declare_lint_pass!(AsUnderscore => [AS_UNDERSCORE]); - -impl<'tcx> LateLintPass<'tcx> for AsUnderscore { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { - if in_external_macro(cx.sess(), expr.span) { - return; - } - - if let ExprKind::Cast(_, ty) = expr.kind && let TyKind::Infer = ty.kind { - - let ty_resolved = cx.typeck_results().expr_ty(expr); - if let ty::Error(_) = ty_resolved.kind() { - span_lint_and_help( - cx, - AS_UNDERSCORE, - expr.span, - "using `as _` conversion", - None, - "consider giving the type explicitly", - ); - } else { - span_lint_and_then( - cx, - AS_UNDERSCORE, - expr.span, - "using `as _` conversion", - |diag| { - diag.span_suggestion( - ty.span, - "consider giving the type explicitly", - ty_resolved, - Applicability::MachineApplicable, - ); - } - ); - } - } - } -} diff --git a/clippy_lints/src/casts/as_underscore.rs b/clippy_lints/src/casts/as_underscore.rs new file mode 100644 index 000000000000..56e894c6261e --- /dev/null +++ b/clippy_lints/src/casts/as_underscore.rs @@ -0,0 +1,25 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use rustc_errors::Applicability; +use rustc_hir::{Expr, Ty, TyKind}; +use rustc_lint::LateContext; +use rustc_middle::ty; + +use super::AS_UNDERSCORE; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, ty: &'tcx Ty<'_>) { + if matches!(ty.kind, TyKind::Infer) { + span_lint_and_then(cx, AS_UNDERSCORE, expr.span, "using `as _` conversion", |diag| { + let ty_resolved = cx.typeck_results().expr_ty(expr); + if let ty::Error(_) = ty_resolved.kind() { + diag.help("consider giving the type explicitly"); + } else { + diag.span_suggestion( + ty.span, + "consider giving the type explicitly", + ty_resolved, + Applicability::MachineApplicable, + ); + } + }); + } +} diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index af3798a0cc8c..01057d9f67c8 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -1,3 +1,4 @@ +mod as_underscore; mod cast_abs_to_unsigned; mod cast_enum_constructor; mod cast_lossless; @@ -506,6 +507,34 @@ declare_clippy_lint! { "casting the result of `abs()` to an unsigned integer can panic" } +declare_clippy_lint! { + /// ### What it does + /// Check for the usage of `as _` conversion using inferred type. + /// + /// ### Why is this bad? + /// The conversion might include lossy conversion and dangerous cast that might go + /// undetected due to the type being inferred. + /// + /// The lint is allowed by default as using `_` is less wordy than always specifying the type. + /// + /// ### Example + /// ```rust + /// fn foo(n: usize) {} + /// let n: u16 = 256; + /// foo(n as _); + /// ``` + /// Use instead: + /// ```rust + /// fn foo(n: usize) {} + /// let n: u16 = 256; + /// foo(n as usize); + /// ``` + #[clippy::version = "1.63.0"] + pub AS_UNDERSCORE, + restriction, + "detects `as _` conversion" +} + pub struct Casts { msrv: Option, } @@ -534,7 +563,8 @@ impl_lint_pass!(Casts => [ PTR_AS_PTR, CAST_ENUM_TRUNCATION, CAST_ENUM_CONSTRUCTOR, - CAST_ABS_TO_UNSIGNED + CAST_ABS_TO_UNSIGNED, + AS_UNDERSCORE, ]); impl<'tcx> LateLintPass<'tcx> for Casts { @@ -547,8 +577,8 @@ impl<'tcx> LateLintPass<'tcx> for Casts { return; } - if let ExprKind::Cast(cast_expr, cast_to) = expr.kind { - if is_hir_ty_cfg_dependant(cx, cast_to) { + if let ExprKind::Cast(cast_expr, cast_to_hir) = expr.kind { + if is_hir_ty_cfg_dependant(cx, cast_to_hir) { return; } let (cast_from, cast_to) = ( @@ -575,6 +605,8 @@ impl<'tcx> LateLintPass<'tcx> for Casts { cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, self.msrv); cast_enum_constructor::check(cx, expr, cast_expr, cast_from); } + + as_underscore::check(cx, expr, cast_to_hir); } cast_ref_to_mut::check(cx, expr); diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index b7dbd30aa0c8..e7665c3fa1d5 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -38,7 +38,6 @@ store.register_lints(&[ almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE, approx_const::APPROX_CONSTANT, as_conversions::AS_CONVERSIONS, - as_underscore::AS_UNDERSCORE, asm_syntax::INLINE_ASM_X86_ATT_SYNTAX, asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX, assertions_on_constants::ASSERTIONS_ON_CONSTANTS, @@ -69,6 +68,7 @@ store.register_lints(&[ cargo::REDUNDANT_FEATURE_NAMES, cargo::WILDCARD_DEPENDENCIES, case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, + casts::AS_UNDERSCORE, casts::CAST_ABS_TO_UNSIGNED, casts::CAST_ENUM_CONSTRUCTOR, casts::CAST_ENUM_TRUNCATION, diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs index a7339ef27217..890ae2792abf 100644 --- a/clippy_lints/src/lib.register_restriction.rs +++ b/clippy_lints/src/lib.register_restriction.rs @@ -4,11 +4,11 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(as_conversions::AS_CONVERSIONS), - LintId::of(as_underscore::AS_UNDERSCORE), LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX), LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX), LintId::of(assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES), LintId::of(attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON), + LintId::of(casts::AS_UNDERSCORE), LintId::of(casts::FN_TO_NUMERIC_CAST_ANY), LintId::of(create_dir::CREATE_DIR), LintId::of(dbg_macro::DBG_MACRO), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index a041fbc7fd97..d32a2fad493a 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -170,7 +170,6 @@ mod renamed_lints; mod almost_complete_letter_range; mod approx_const; mod as_conversions; -mod as_underscore; mod asm_syntax; mod assertions_on_constants; mod assertions_on_result_states; @@ -923,7 +922,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(move || Box::new(almost_complete_letter_range::AlmostCompleteLetterRange::new(msrv))); store.register_late_pass(|| Box::new(swap_ptr_to_ref::SwapPtrToRef)); store.register_late_pass(|| Box::new(mismatching_type_param_order::TypeParamMismatch)); - store.register_late_pass(|| Box::new(as_underscore::AsUnderscore)); store.register_late_pass(|| Box::new(read_zero_byte_vec::ReadZeroByteVec)); store.register_late_pass(|| Box::new(default_instead_of_iter_empty::DefaultIterEmpty)); store.register_late_pass(move || Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv))); From 21f595433e449ff44de5e6cd6373b8a852512d49 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 09:33:15 -0400 Subject: [PATCH 3775/5092] Move `BorrowAsPtr` into `Casts` lint pass --- clippy_lints/src/borrow_as_ptr.rs | 99 ----------------------- clippy_lints/src/casts/borrow_as_ptr.rs | 37 +++++++++ clippy_lints/src/casts/mod.rs | 41 +++++++++- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_pedantic.rs | 2 +- clippy_lints/src/lib.rs | 2 - 6 files changed, 79 insertions(+), 104 deletions(-) delete mode 100644 clippy_lints/src/borrow_as_ptr.rs create mode 100644 clippy_lints/src/casts/borrow_as_ptr.rs diff --git a/clippy_lints/src/borrow_as_ptr.rs b/clippy_lints/src/borrow_as_ptr.rs deleted file mode 100644 index 0993adbae2e6..000000000000 --- a/clippy_lints/src/borrow_as_ptr.rs +++ /dev/null @@ -1,99 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_no_std_crate; -use clippy_utils::source::snippet_opt; -use clippy_utils::{meets_msrv, msrvs}; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, TyKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_semver::RustcVersion; -use rustc_session::{declare_tool_lint, impl_lint_pass}; - -declare_clippy_lint! { - /// ### What it does - /// Checks for the usage of `&expr as *const T` or - /// `&mut expr as *mut T`, and suggest using `ptr::addr_of` or - /// `ptr::addr_of_mut` instead. - /// - /// ### Why is this bad? - /// This would improve readability and avoid creating a reference - /// that points to an uninitialized value or unaligned place. - /// Read the `ptr::addr_of` docs for more information. - /// - /// ### Example - /// ```rust - /// let val = 1; - /// let p = &val as *const i32; - /// - /// let mut val_mut = 1; - /// let p_mut = &mut val_mut as *mut i32; - /// ``` - /// Use instead: - /// ```rust - /// let val = 1; - /// let p = std::ptr::addr_of!(val); - /// - /// let mut val_mut = 1; - /// let p_mut = std::ptr::addr_of_mut!(val_mut); - /// ``` - #[clippy::version = "1.60.0"] - pub BORROW_AS_PTR, - pedantic, - "borrowing just to cast to a raw pointer" -} - -impl_lint_pass!(BorrowAsPtr => [BORROW_AS_PTR]); - -pub struct BorrowAsPtr { - msrv: Option, -} - -impl BorrowAsPtr { - #[must_use] - pub fn new(msrv: Option) -> Self { - Self { msrv } - } -} - -impl<'tcx> LateLintPass<'tcx> for BorrowAsPtr { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if !meets_msrv(self.msrv, msrvs::BORROW_AS_PTR) { - return; - } - - if expr.span.from_expansion() { - return; - } - - if_chain! { - if let ExprKind::Cast(left_expr, ty) = &expr.kind; - if let TyKind::Ptr(_) = ty.kind; - if let ExprKind::AddrOf(BorrowKind::Ref, mutability, e) = &left_expr.kind; - - then { - let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" }; - let macro_name = match mutability { - Mutability::Not => "addr_of", - Mutability::Mut => "addr_of_mut", - }; - - span_lint_and_sugg( - cx, - BORROW_AS_PTR, - expr.span, - "borrow as raw pointer", - "try", - format!( - "{}::ptr::{}!({})", - core_or_std, - macro_name, - snippet_opt(cx, e.span).unwrap() - ), - Applicability::MachineApplicable, - ); - } - } - } - - extract_msrv_attr!(LateContext); -} diff --git a/clippy_lints/src/casts/borrow_as_ptr.rs b/clippy_lints/src/casts/borrow_as_ptr.rs new file mode 100644 index 000000000000..6e1f8cd64f07 --- /dev/null +++ b/clippy_lints/src/casts/borrow_as_ptr.rs @@ -0,0 +1,37 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_no_std_crate; +use clippy_utils::source::snippet_with_context; +use rustc_errors::Applicability; +use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Ty, TyKind}; +use rustc_lint::LateContext; + +use super::BORROW_AS_PTR; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + cast_expr: &'tcx Expr<'_>, + cast_to: &'tcx Ty<'_>, +) { + if matches!(cast_to.kind, TyKind::Ptr(_)) + && let ExprKind::AddrOf(BorrowKind::Ref, mutability, e) = cast_expr.kind + { + let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" }; + let macro_name = match mutability { + Mutability::Not => "addr_of", + Mutability::Mut => "addr_of_mut", + }; + let mut app = Applicability::MachineApplicable; + let snip = snippet_with_context(cx, e.span, cast_expr.span.ctxt(), "..", &mut app).0; + + span_lint_and_sugg( + cx, + BORROW_AS_PTR, + expr.span, + "borrow as raw pointer", + "try", + format!("{}::ptr::{}!({})", core_or_std, macro_name, snip), + Applicability::MachineApplicable, + ); + } +} diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 01057d9f67c8..644edefb8fe9 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -1,4 +1,5 @@ mod as_underscore; +mod borrow_as_ptr; mod cast_abs_to_unsigned; mod cast_enum_constructor; mod cast_lossless; @@ -17,7 +18,7 @@ mod ptr_as_ptr; mod unnecessary_cast; mod utils; -use clippy_utils::is_hir_ty_cfg_dependant; +use clippy_utils::{is_hir_ty_cfg_dependant, meets_msrv, msrvs}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; @@ -535,6 +536,39 @@ declare_clippy_lint! { "detects `as _` conversion" } +declare_clippy_lint! { + /// ### What it does + /// Checks for the usage of `&expr as *const T` or + /// `&mut expr as *mut T`, and suggest using `ptr::addr_of` or + /// `ptr::addr_of_mut` instead. + /// + /// ### Why is this bad? + /// This would improve readability and avoid creating a reference + /// that points to an uninitialized value or unaligned place. + /// Read the `ptr::addr_of` docs for more information. + /// + /// ### Example + /// ```rust + /// let val = 1; + /// let p = &val as *const i32; + /// + /// let mut val_mut = 1; + /// let p_mut = &mut val_mut as *mut i32; + /// ``` + /// Use instead: + /// ```rust + /// let val = 1; + /// let p = std::ptr::addr_of!(val); + /// + /// let mut val_mut = 1; + /// let p_mut = std::ptr::addr_of_mut!(val_mut); + /// ``` + #[clippy::version = "1.60.0"] + pub BORROW_AS_PTR, + pedantic, + "borrowing just to cast to a raw pointer" +} + pub struct Casts { msrv: Option, } @@ -565,6 +599,7 @@ impl_lint_pass!(Casts => [ CAST_ENUM_CONSTRUCTOR, CAST_ABS_TO_UNSIGNED, AS_UNDERSCORE, + BORROW_AS_PTR, ]); impl<'tcx> LateLintPass<'tcx> for Casts { @@ -607,6 +642,10 @@ impl<'tcx> LateLintPass<'tcx> for Casts { } as_underscore::check(cx, expr, cast_to_hir); + + if meets_msrv(self.msrv, msrvs::BORROW_AS_PTR) { + borrow_as_ptr::check(cx, expr, cast_expr, cast_to_hir); + } } cast_ref_to_mut::check(cx, expr); diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index e7665c3fa1d5..7883711e5a3e 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -58,7 +58,6 @@ store.register_lints(&[ bool_assert_comparison::BOOL_ASSERT_COMPARISON, booleans::NONMINIMAL_BOOL, booleans::OVERLY_COMPLEX_BOOL_EXPR, - borrow_as_ptr::BORROW_AS_PTR, borrow_deref_ref::BORROW_DEREF_REF, bytecount::NAIVE_BYTECOUNT, bytes_count_to_len::BYTES_COUNT_TO_LEN, @@ -69,6 +68,7 @@ store.register_lints(&[ cargo::WILDCARD_DEPENDENCIES, case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, casts::AS_UNDERSCORE, + casts::BORROW_AS_PTR, casts::CAST_ABS_TO_UNSIGNED, casts::CAST_ENUM_CONSTRUCTOR, casts::CAST_ENUM_TRUNCATION, diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index 4250ee055e6c..ae9f046f023f 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -4,9 +4,9 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(attrs::INLINE_ALWAYS), - LintId::of(borrow_as_ptr::BORROW_AS_PTR), LintId::of(bytecount::NAIVE_BYTECOUNT), LintId::of(case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS), + LintId::of(casts::BORROW_AS_PTR), LintId::of(casts::CAST_LOSSLESS), LintId::of(casts::CAST_POSSIBLE_TRUNCATION), LintId::of(casts::CAST_POSSIBLE_WRAP), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index d32a2fad493a..63e0fcf6b0fe 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -179,7 +179,6 @@ mod await_holding_invalid; mod blocks_in_if_conditions; mod bool_assert_comparison; mod booleans; -mod borrow_as_ptr; mod borrow_deref_ref; mod bytecount; mod bytes_count_to_len; @@ -893,7 +892,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(return_self_not_must_use::ReturnSelfNotMustUse)); store.register_late_pass(|| Box::new(init_numbered_fields::NumberedFields)); store.register_early_pass(|| Box::new(single_char_lifetime_names::SingleCharLifetimeNames)); - store.register_late_pass(move || Box::new(borrow_as_ptr::BorrowAsPtr::new(msrv))); store.register_late_pass(move || Box::new(manual_bits::ManualBits::new(msrv))); store.register_late_pass(|| Box::new(default_union_representation::DefaultUnionRepresentation)); store.register_early_pass(|| Box::new(doc_link_with_quotes::DocLinkWithQuotes)); From 25028986864fbb3231c54feb5e769c8778e037bf Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 11:39:36 -0400 Subject: [PATCH 3776/5092] Move `ByteCount` into `Methods` lint pass --- clippy_lints/src/bytecount.rs | 103 ---------------------- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_pedantic.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/bytecount.rs | 70 +++++++++++++++ clippy_lints/src/methods/mod.rs | 42 ++++++++- 6 files changed, 111 insertions(+), 110 deletions(-) delete mode 100644 clippy_lints/src/bytecount.rs create mode 100644 clippy_lints/src/methods/bytecount.rs diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs deleted file mode 100644 index 326ce34082af..000000000000 --- a/clippy_lints/src/bytecount.rs +++ /dev/null @@ -1,103 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::match_type; -use clippy_utils::visitors::is_local_used; -use clippy_utils::{path_to_local_id, paths, peel_blocks, peel_ref_operators, strip_pat_refs}; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Closure, Expr, ExprKind, PatKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{self, UintTy}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; - -declare_clippy_lint! { - /// ### What it does - /// Checks for naive byte counts - /// - /// ### Why is this bad? - /// The [`bytecount`](https://crates.io/crates/bytecount) - /// crate has methods to count your bytes faster, especially for large slices. - /// - /// ### Known problems - /// If you have predominantly small slices, the - /// `bytecount::count(..)` method may actually be slower. However, if you can - /// ensure that less than 2³²-1 matches arise, the `naive_count_32(..)` can be - /// faster in those cases. - /// - /// ### Example - /// ```rust - /// # let vec = vec![1_u8]; - /// let count = vec.iter().filter(|x| **x == 0u8).count(); - /// ``` - /// - /// Use instead: - /// ```rust,ignore - /// # let vec = vec![1_u8]; - /// let count = bytecount::count(&vec, 0u8); - /// ``` - #[clippy::version = "pre 1.29.0"] - pub NAIVE_BYTECOUNT, - pedantic, - "use of naive `.filter(|&x| x == y).count()` to count byte values" -} - -declare_lint_pass!(ByteCount => [NAIVE_BYTECOUNT]); - -impl<'tcx> LateLintPass<'tcx> for ByteCount { - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if_chain! { - if let ExprKind::MethodCall(count, [count_recv], _) = expr.kind; - if count.ident.name == sym::count; - if let ExprKind::MethodCall(filter, [filter_recv, filter_arg], _) = count_recv.kind; - if filter.ident.name == sym!(filter); - if let ExprKind::Closure(&Closure { body, .. }) = filter_arg.kind; - let body = cx.tcx.hir().body(body); - if let [param] = body.params; - if let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind; - if let ExprKind::Binary(ref op, l, r) = body.value.kind; - if op.node == BinOpKind::Eq; - if match_type(cx, - cx.typeck_results().expr_ty(filter_recv).peel_refs(), - &paths::SLICE_ITER); - let operand_is_arg = |expr| { - let expr = peel_ref_operators(cx, peel_blocks(expr)); - path_to_local_id(expr, arg_id) - }; - let needle = if operand_is_arg(l) { - r - } else if operand_is_arg(r) { - l - } else { - return; - }; - if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(needle).peel_refs().kind(); - if !is_local_used(cx, needle, arg_id); - then { - let haystack = if let ExprKind::MethodCall(path, args, _) = - filter_recv.kind { - let p = path.ident.name; - if (p == sym::iter || p == sym!(iter_mut)) && args.len() == 1 { - &args[0] - } else { - filter_recv - } - } else { - filter_recv - }; - let mut applicability = Applicability::MaybeIncorrect; - span_lint_and_sugg( - cx, - NAIVE_BYTECOUNT, - expr.span, - "you appear to be counting bytes the naive way", - "consider using the bytecount crate", - format!("bytecount::count({}, {})", - snippet_with_applicability(cx, haystack.span, "..", &mut applicability), - snippet_with_applicability(cx, needle.span, "..", &mut applicability)), - applicability, - ); - } - }; - } -} diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 7883711e5a3e..c3c24fb16680 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -59,7 +59,6 @@ store.register_lints(&[ booleans::NONMINIMAL_BOOL, booleans::OVERLY_COMPLEX_BOOL_EXPR, borrow_deref_ref::BORROW_DEREF_REF, - bytecount::NAIVE_BYTECOUNT, bytes_count_to_len::BYTES_COUNT_TO_LEN, cargo::CARGO_COMMON_METADATA, cargo::MULTIPLE_CRATE_VERSIONS, @@ -330,6 +329,7 @@ store.register_lints(&[ methods::MAP_FLATTEN, methods::MAP_IDENTITY, methods::MAP_UNWRAP_OR, + methods::NAIVE_BYTECOUNT, methods::NEEDLESS_OPTION_AS_DEREF, methods::NEEDLESS_OPTION_TAKE, methods::NEEDLESS_SPLITN, diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index ae9f046f023f..241d70d26287 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -4,7 +4,6 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(attrs::INLINE_ALWAYS), - LintId::of(bytecount::NAIVE_BYTECOUNT), LintId::of(case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS), LintId::of(casts::BORROW_AS_PTR), LintId::of(casts::CAST_LOSSLESS), @@ -64,6 +63,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(methods::IMPLICIT_CLONE), LintId::of(methods::INEFFICIENT_TO_STRING), LintId::of(methods::MAP_UNWRAP_OR), + LintId::of(methods::NAIVE_BYTECOUNT), LintId::of(methods::UNNECESSARY_JOIN), LintId::of(misc::USED_UNDERSCORE_BINDING), LintId::of(mismatching_type_param_order::MISMATCHING_TYPE_PARAM_ORDER), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 63e0fcf6b0fe..617f16223258 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -180,7 +180,6 @@ mod blocks_in_if_conditions; mod bool_assert_comparison; mod booleans; mod borrow_deref_ref; -mod bytecount; mod bytes_count_to_len; mod cargo; mod case_sensitive_file_extension_comparisons; @@ -718,7 +717,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: ); store.register_late_pass(move || Box::new(pass_by_ref_or_value)); store.register_late_pass(|| Box::new(ref_option_ref::RefOptionRef)); - store.register_late_pass(|| Box::new(bytecount::ByteCount)); store.register_late_pass(|| Box::new(infinite_iter::InfiniteIter)); store.register_late_pass(|| Box::new(inline_fn_without_body::InlineFnWithoutBody)); store.register_late_pass(|| Box::new(useless_conversion::UselessConversion::default())); diff --git a/clippy_lints/src/methods/bytecount.rs b/clippy_lints/src/methods/bytecount.rs new file mode 100644 index 000000000000..6a7c63d76f72 --- /dev/null +++ b/clippy_lints/src/methods/bytecount.rs @@ -0,0 +1,70 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::match_type; +use clippy_utils::visitors::is_local_used; +use clippy_utils::{path_to_local_id, paths, peel_blocks, peel_ref_operators, strip_pat_refs}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Closure, Expr, ExprKind, PatKind}; +use rustc_lint::LateContext; +use rustc_middle::ty::{self, UintTy}; +use rustc_span::sym; + +use super::NAIVE_BYTECOUNT; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + filter_recv: &'tcx Expr<'_>, + filter_arg: &'tcx Expr<'_>, +) { + if_chain! { + if let ExprKind::Closure(&Closure { body, .. }) = filter_arg.kind; + let body = cx.tcx.hir().body(body); + if let [param] = body.params; + if let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind; + if let ExprKind::Binary(ref op, l, r) = body.value.kind; + if op.node == BinOpKind::Eq; + if match_type(cx, + cx.typeck_results().expr_ty(filter_recv).peel_refs(), + &paths::SLICE_ITER); + let operand_is_arg = |expr| { + let expr = peel_ref_operators(cx, peel_blocks(expr)); + path_to_local_id(expr, arg_id) + }; + let needle = if operand_is_arg(l) { + r + } else if operand_is_arg(r) { + l + } else { + return; + }; + if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(needle).peel_refs().kind(); + if !is_local_used(cx, needle, arg_id); + then { + let haystack = if let ExprKind::MethodCall(path, args, _) = + filter_recv.kind { + let p = path.ident.name; + if (p == sym::iter || p == sym!(iter_mut)) && args.len() == 1 { + &args[0] + } else { + filter_recv + } + } else { + filter_recv + }; + let mut applicability = Applicability::MaybeIncorrect; + span_lint_and_sugg( + cx, + NAIVE_BYTECOUNT, + expr.span, + "you appear to be counting bytes the naive way", + "consider using the bytecount crate", + format!("bytecount::count({}, {})", + snippet_with_applicability(cx, haystack.span, "..", &mut applicability), + snippet_with_applicability(cx, needle.span, "..", &mut applicability)), + applicability, + ); + } + }; +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index b68a2651e1bd..f0d9dce5518c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1,4 +1,5 @@ mod bind_instead_of_map; +mod bytecount; mod bytes_nth; mod chars_cmp; mod chars_cmp_with_unwrap; @@ -82,7 +83,9 @@ use bind_instead_of_map::BindInsteadOfMap; use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::ty::{contains_adt_constructor, contains_ty, implements_trait, is_copy, is_type_diagnostic_item}; -use clippy_utils::{contains_return, get_trait_def_id, iter_input_pats, meets_msrv, msrvs, paths, return_ty}; +use clippy_utils::{ + contains_return, get_trait_def_id, is_trait_method, iter_input_pats, meets_msrv, msrvs, paths, return_ty, +}; use if_chain::if_chain; use rustc_hir as hir; use rustc_hir::def::Res; @@ -2368,6 +2371,37 @@ declare_clippy_lint! { "Iterator for empty array" } +declare_clippy_lint! { + /// ### What it does + /// Checks for naive byte counts + /// + /// ### Why is this bad? + /// The [`bytecount`](https://crates.io/crates/bytecount) + /// crate has methods to count your bytes faster, especially for large slices. + /// + /// ### Known problems + /// If you have predominantly small slices, the + /// `bytecount::count(..)` method may actually be slower. However, if you can + /// ensure that less than 2³²-1 matches arise, the `naive_count_32(..)` can be + /// faster in those cases. + /// + /// ### Example + /// ```rust + /// # let vec = vec![1_u8]; + /// let count = vec.iter().filter(|x| **x == 0u8).count(); + /// ``` + /// + /// Use instead: + /// ```rust,ignore + /// # let vec = vec![1_u8]; + /// let count = bytecount::count(&vec, 0u8); + /// ``` + #[clippy::version = "pre 1.29.0"] + pub NAIVE_BYTECOUNT, + pedantic, + "use of naive `.filter(|&x| x == y).count()` to count byte values" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2471,7 +2505,8 @@ impl_lint_pass!(Methods => [ NO_EFFECT_REPLACE, OBFUSCATED_IF_ELSE, ITER_ON_SINGLE_ITEMS, - ITER_ON_EMPTY_COLLECTIONS + ITER_ON_EMPTY_COLLECTIONS, + NAIVE_BYTECOUNT, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2726,12 +2761,13 @@ impl Methods { }, _ => {}, }, - ("count", []) => match method_call(recv) { + ("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) { Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false), Some((name2 @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => { iter_count::check(cx, expr, recv2, name2); }, Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg), + Some(("filter", [recv2, arg], _)) => bytecount::check(cx, expr, recv2, arg), _ => {}, }, ("drain", [arg]) => { From ba6a4595285e38f35970e66db903475989e0be6f Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 13:05:11 -0400 Subject: [PATCH 3777/5092] Move `BytesCountToLen` into `Methods` lint pass --- clippy_lints/src/bytes_count_to_len.rs | 70 ------------------- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_complexity.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.rs | 2 - .../src/methods/bytes_count_to_len.rs | 37 ++++++++++ clippy_lints/src/methods/mod.rs | 28 ++++++++ 7 files changed, 68 insertions(+), 75 deletions(-) delete mode 100644 clippy_lints/src/bytes_count_to_len.rs create mode 100644 clippy_lints/src/methods/bytes_count_to_len.rs diff --git a/clippy_lints/src/bytes_count_to_len.rs b/clippy_lints/src/bytes_count_to_len.rs deleted file mode 100644 index d70dbf5b2390..000000000000 --- a/clippy_lints/src/bytes_count_to_len.rs +++ /dev/null @@ -1,70 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{match_def_path, paths}; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir as hir; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; - -declare_clippy_lint! { - /// ### What it does - /// It checks for `str::bytes().count()` and suggests replacing it with - /// `str::len()`. - /// - /// ### Why is this bad? - /// `str::bytes().count()` is longer and may not be as performant as using - /// `str::len()`. - /// - /// ### Example - /// ```rust - /// "hello".bytes().count(); - /// String::from("hello").bytes().count(); - /// ``` - /// Use instead: - /// ```rust - /// "hello".len(); - /// String::from("hello").len(); - /// ``` - #[clippy::version = "1.62.0"] - pub BYTES_COUNT_TO_LEN, - complexity, - "Using `bytes().count()` when `len()` performs the same functionality" -} - -declare_lint_pass!(BytesCountToLen => [BYTES_COUNT_TO_LEN]); - -impl<'tcx> LateLintPass<'tcx> for BytesCountToLen { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if_chain! { - if let hir::ExprKind::MethodCall(_, expr_args, _) = &expr.kind; - if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if match_def_path(cx, expr_def_id, &paths::ITER_COUNT); - - if let [bytes_expr] = &**expr_args; - if let hir::ExprKind::MethodCall(_, bytes_args, _) = &bytes_expr.kind; - if let Some(bytes_def_id) = cx.typeck_results().type_dependent_def_id(bytes_expr.hir_id); - if match_def_path(cx, bytes_def_id, &paths::STR_BYTES); - - if let [str_expr] = &**bytes_args; - let ty = cx.typeck_results().expr_ty(str_expr).peel_refs(); - - if is_type_diagnostic_item(cx, ty, sym::String) || ty.kind() == &ty::Str; - then { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - BYTES_COUNT_TO_LEN, - expr.span, - "using long and hard to read `.bytes().count()`", - "consider calling `.len()` instead", - format!("{}.len()", snippet_with_applicability(cx, str_expr.span, "..", &mut applicability)), - applicability - ); - } - }; - } -} diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index a0a4b07a77e5..f48e542ee418 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -20,7 +20,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(booleans::NONMINIMAL_BOOL), LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR), LintId::of(borrow_deref_ref::BORROW_DEREF_REF), - LintId::of(bytes_count_to_len::BYTES_COUNT_TO_LEN), LintId::of(casts::CAST_ABS_TO_UNSIGNED), LintId::of(casts::CAST_ENUM_CONSTRUCTOR), LintId::of(casts::CAST_ENUM_TRUNCATION), @@ -151,6 +150,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT), LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT), LintId::of(methods::BIND_INSTEAD_OF_MAP), + LintId::of(methods::BYTES_COUNT_TO_LEN), LintId::of(methods::BYTES_NTH), LintId::of(methods::CHARS_LAST_CMP), LintId::of(methods::CHARS_NEXT_CMP), diff --git a/clippy_lints/src/lib.register_complexity.rs b/clippy_lints/src/lib.register_complexity.rs index 3784d3c68dce..324b380317f6 100644 --- a/clippy_lints/src/lib.register_complexity.rs +++ b/clippy_lints/src/lib.register_complexity.rs @@ -6,7 +6,6 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(attrs::DEPRECATED_CFG_ATTR), LintId::of(booleans::NONMINIMAL_BOOL), LintId::of(borrow_deref_ref::BORROW_DEREF_REF), - LintId::of(bytes_count_to_len::BYTES_COUNT_TO_LEN), LintId::of(casts::CHAR_LIT_AS_U8), LintId::of(casts::UNNECESSARY_CAST), LintId::of(dereference::EXPLICIT_AUTO_DEREF), @@ -33,6 +32,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(matches::NEEDLESS_MATCH), LintId::of(matches::WILDCARD_IN_OR_PATTERNS), LintId::of(methods::BIND_INSTEAD_OF_MAP), + LintId::of(methods::BYTES_COUNT_TO_LEN), LintId::of(methods::CLONE_ON_COPY), LintId::of(methods::FILTER_MAP_IDENTITY), LintId::of(methods::FILTER_NEXT), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index c3c24fb16680..bfd12b98944d 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -59,7 +59,6 @@ store.register_lints(&[ booleans::NONMINIMAL_BOOL, booleans::OVERLY_COMPLEX_BOOL_EXPR, borrow_deref_ref::BORROW_DEREF_REF, - bytes_count_to_len::BYTES_COUNT_TO_LEN, cargo::CARGO_COMMON_METADATA, cargo::MULTIPLE_CRATE_VERSIONS, cargo::NEGATIVE_FEATURE_NAMES, @@ -284,6 +283,7 @@ store.register_lints(&[ mem_replace::MEM_REPLACE_WITH_DEFAULT, mem_replace::MEM_REPLACE_WITH_UNINIT, methods::BIND_INSTEAD_OF_MAP, + methods::BYTES_COUNT_TO_LEN, methods::BYTES_NTH, methods::CHARS_LAST_CMP, methods::CHARS_NEXT_CMP, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 617f16223258..f4cb5e5bf16d 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -180,7 +180,6 @@ mod blocks_in_if_conditions; mod bool_assert_comparison; mod booleans; mod borrow_deref_ref; -mod bytes_count_to_len; mod cargo; mod case_sensitive_file_extension_comparisons; mod casts; @@ -907,7 +906,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings)); store.register_early_pass(|| Box::new(pub_use::PubUse)); store.register_late_pass(|| Box::new(format_push_string::FormatPushString)); - store.register_late_pass(|| Box::new(bytes_count_to_len::BytesCountToLen)); let max_include_file_size = conf.max_include_file_size; store.register_late_pass(move || Box::new(large_include_file::LargeIncludeFile::new(max_include_file_size))); store.register_late_pass(|| Box::new(strings::TrimSplitWhitespace)); diff --git a/clippy_lints/src/methods/bytes_count_to_len.rs b/clippy_lints/src/methods/bytes_count_to_len.rs new file mode 100644 index 000000000000..fcfc25b523da --- /dev/null +++ b/clippy_lints/src/methods/bytes_count_to_len.rs @@ -0,0 +1,37 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::is_type_diagnostic_item; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::BYTES_COUNT_TO_LEN; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + count_recv: &'tcx hir::Expr<'_>, + bytes_recv: &'tcx hir::Expr<'_>, +) { + if_chain! { + if let Some(bytes_id) = cx.typeck_results().type_dependent_def_id(count_recv.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(bytes_id); + if cx.tcx.type_of(impl_id).is_str(); + let ty = cx.typeck_results().expr_ty(bytes_recv).peel_refs(); + if ty.is_str() || is_type_diagnostic_item(cx, ty, sym::String); + then { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + BYTES_COUNT_TO_LEN, + expr.span, + "using long and hard to read `.bytes().count()`", + "consider calling `.len()` instead", + format!("{}.len()", snippet_with_applicability(cx, bytes_recv.span, "..", &mut applicability)), + applicability + ); + } + }; +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index f0d9dce5518c..eab3ca1842b0 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1,5 +1,6 @@ mod bind_instead_of_map; mod bytecount; +mod bytes_count_to_len; mod bytes_nth; mod chars_cmp; mod chars_cmp_with_unwrap; @@ -2402,6 +2403,31 @@ declare_clippy_lint! { "use of naive `.filter(|&x| x == y).count()` to count byte values" } +declare_clippy_lint! { + /// ### What it does + /// It checks for `str::bytes().count()` and suggests replacing it with + /// `str::len()`. + /// + /// ### Why is this bad? + /// `str::bytes().count()` is longer and may not be as performant as using + /// `str::len()`. + /// + /// ### Example + /// ```rust + /// "hello".bytes().count(); + /// String::from("hello").bytes().count(); + /// ``` + /// Use instead: + /// ```rust + /// "hello".len(); + /// String::from("hello").len(); + /// ``` + #[clippy::version = "1.62.0"] + pub BYTES_COUNT_TO_LEN, + complexity, + "Using `bytes().count()` when `len()` performs the same functionality" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2507,6 +2533,7 @@ impl_lint_pass!(Methods => [ ITER_ON_SINGLE_ITEMS, ITER_ON_EMPTY_COLLECTIONS, NAIVE_BYTECOUNT, + BYTES_COUNT_TO_LEN, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2768,6 +2795,7 @@ impl Methods { }, Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg), Some(("filter", [recv2, arg], _)) => bytecount::check(cx, expr, recv2, arg), + Some(("bytes", [recv2], _)) => bytes_count_to_len::check(cx, expr, recv, recv2), _ => {}, }, ("drain", [arg]) => { From e3b77974d0025b6900fde9799ad4b2cd324050fb Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 13:21:04 -0400 Subject: [PATCH 3778/5092] Move `CaseSensitiveFileExtensionComparisons` into `Methods` lint pass --- ...se_sensitive_file_extension_comparisons.rs | 85 ------------------- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_pedantic.rs | 2 +- clippy_lints/src/lib.rs | 4 - ...se_sensitive_file_extension_comparisons.rs | 41 +++++++++ clippy_lints/src/methods/mod.rs | 34 ++++++++ 6 files changed, 77 insertions(+), 91 deletions(-) delete mode 100644 clippy_lints/src/case_sensitive_file_extension_comparisons.rs create mode 100644 clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs diff --git a/clippy_lints/src/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/case_sensitive_file_extension_comparisons.rs deleted file mode 100644 index bef196565a2a..000000000000 --- a/clippy_lints/src/case_sensitive_file_extension_comparisons.rs +++ /dev/null @@ -1,85 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_help; -use if_chain::if_chain; -use rustc_ast::ast::LitKind; -use rustc_hir::{Expr, ExprKind, PathSegment}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::{source_map::Spanned, symbol::sym, Span}; - -declare_clippy_lint! { - /// ### What it does - /// Checks for calls to `ends_with` with possible file extensions - /// and suggests to use a case-insensitive approach instead. - /// - /// ### Why is this bad? - /// `ends_with` is case-sensitive and may not detect files with a valid extension. - /// - /// ### Example - /// ```rust - /// fn is_rust_file(filename: &str) -> bool { - /// filename.ends_with(".rs") - /// } - /// ``` - /// Use instead: - /// ```rust - /// fn is_rust_file(filename: &str) -> bool { - /// let filename = std::path::Path::new(filename); - /// filename.extension() - /// .map_or(false, |ext| ext.eq_ignore_ascii_case("rs")) - /// } - /// ``` - #[clippy::version = "1.51.0"] - pub CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, - pedantic, - "Checks for calls to ends_with with case-sensitive file extensions" -} - -declare_lint_pass!(CaseSensitiveFileExtensionComparisons => [CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS]); - -fn check_case_sensitive_file_extension_comparison(ctx: &LateContext<'_>, expr: &Expr<'_>) -> Option { - if_chain! { - if let ExprKind::MethodCall(PathSegment { ident, .. }, [obj, extension, ..], span) = expr.kind; - if ident.as_str() == "ends_with"; - if let ExprKind::Lit(Spanned { node: LitKind::Str(ext_literal, ..), ..}) = extension.kind; - if (2..=6).contains(&ext_literal.as_str().len()); - if ext_literal.as_str().starts_with('.'); - if ext_literal.as_str().chars().skip(1).all(|c| c.is_uppercase() || c.is_ascii_digit()) - || ext_literal.as_str().chars().skip(1).all(|c| c.is_lowercase() || c.is_ascii_digit()); - then { - let mut ty = ctx.typeck_results().expr_ty(obj); - ty = match ty.kind() { - ty::Ref(_, ty, ..) => *ty, - _ => ty - }; - - match ty.kind() { - ty::Str => { - return Some(span); - }, - ty::Adt(def, _) => { - if ctx.tcx.is_diagnostic_item(sym::String, def.did()) { - return Some(span); - } - }, - _ => { return None; } - } - } - } - None -} - -impl<'tcx> LateLintPass<'tcx> for CaseSensitiveFileExtensionComparisons { - fn check_expr(&mut self, ctx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if let Some(span) = check_case_sensitive_file_extension_comparison(ctx, expr) { - span_lint_and_help( - ctx, - CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, - span, - "case-sensitive file extension comparison", - None, - "consider using a case-insensitive comparison instead", - ); - } - } -} diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index bfd12b98944d..10ff1fa1f580 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -64,7 +64,6 @@ store.register_lints(&[ cargo::NEGATIVE_FEATURE_NAMES, cargo::REDUNDANT_FEATURE_NAMES, cargo::WILDCARD_DEPENDENCIES, - case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, casts::AS_UNDERSCORE, casts::BORROW_AS_PTR, casts::CAST_ABS_TO_UNSIGNED, @@ -285,6 +284,7 @@ store.register_lints(&[ methods::BIND_INSTEAD_OF_MAP, methods::BYTES_COUNT_TO_LEN, methods::BYTES_NTH, + methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, methods::CHARS_LAST_CMP, methods::CHARS_NEXT_CMP, methods::CLONED_INSTEAD_OF_COPIED, diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index 241d70d26287..c9cf7dbd0785 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -4,7 +4,6 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(attrs::INLINE_ALWAYS), - LintId::of(case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS), LintId::of(casts::BORROW_AS_PTR), LintId::of(casts::CAST_LOSSLESS), LintId::of(casts::CAST_POSSIBLE_TRUNCATION), @@ -56,6 +55,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS), LintId::of(matches::MATCH_WILD_ERR_ARM), LintId::of(matches::SINGLE_MATCH_ELSE), + LintId::of(methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS), LintId::of(methods::CLONED_INSTEAD_OF_COPIED), LintId::of(methods::FILTER_MAP_NEXT), LintId::of(methods::FLAT_MAP_OPTION), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index f4cb5e5bf16d..68f69dc64b86 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -181,7 +181,6 @@ mod bool_assert_comparison; mod booleans; mod borrow_deref_ref; mod cargo; -mod case_sensitive_file_extension_comparisons; mod casts; mod checked_conversions; mod cognitive_complexity; @@ -852,9 +851,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(strings::StringToString)); store.register_late_pass(|| Box::new(zero_sized_map_values::ZeroSizedMapValues)); store.register_late_pass(|| Box::new(vec_init_then_push::VecInitThenPush::default())); - store.register_late_pass(|| { - Box::new(case_sensitive_file_extension_comparisons::CaseSensitiveFileExtensionComparisons) - }); store.register_late_pass(|| Box::new(redundant_slicing::RedundantSlicing)); store.register_late_pass(|| Box::new(from_str_radix_10::FromStrRadix10)); store.register_late_pass(move || Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv))); diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs new file mode 100644 index 000000000000..b3c2c7c9a2dc --- /dev/null +++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -0,0 +1,41 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::ty::is_type_diagnostic_item; +use if_chain::if_chain; +use rustc_ast::ast::LitKind; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::{source_map::Spanned, symbol::sym, Span}; + +use super::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + call_span: Span, + recv: &'tcx Expr<'_>, + arg: &'tcx Expr<'_>, +) { + if_chain! { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(method_id); + if cx.tcx.type_of(impl_id).is_str(); + if let ExprKind::Lit(Spanned { node: LitKind::Str(ext_literal, ..), ..}) = arg.kind; + if (2..=6).contains(&ext_literal.as_str().len()); + let ext_str = ext_literal.as_str(); + if ext_str.starts_with('.'); + if ext_str.chars().skip(1).all(|c| c.is_uppercase() || c.is_ascii_digit()) + || ext_str.chars().skip(1).all(|c| c.is_lowercase() || c.is_ascii_digit()); + let recv_ty = cx.typeck_results().expr_ty(recv).peel_refs(); + if recv_ty.is_str() || is_type_diagnostic_item(cx, recv_ty, sym::String); + then { + span_lint_and_help( + cx, + CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, + call_span, + "case-sensitive file extension comparison", + None, + "consider using a case-insensitive comparison instead", + ); + } + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index eab3ca1842b0..0bb247c7e810 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2,6 +2,7 @@ mod bind_instead_of_map; mod bytecount; mod bytes_count_to_len; mod bytes_nth; +mod case_sensitive_file_extension_comparisons; mod chars_cmp; mod chars_cmp_with_unwrap; mod chars_last_cmp; @@ -2428,6 +2429,34 @@ declare_clippy_lint! { "Using `bytes().count()` when `len()` performs the same functionality" } +declare_clippy_lint! { + /// ### What it does + /// Checks for calls to `ends_with` with possible file extensions + /// and suggests to use a case-insensitive approach instead. + /// + /// ### Why is this bad? + /// `ends_with` is case-sensitive and may not detect files with a valid extension. + /// + /// ### Example + /// ```rust + /// fn is_rust_file(filename: &str) -> bool { + /// filename.ends_with(".rs") + /// } + /// ``` + /// Use instead: + /// ```rust + /// fn is_rust_file(filename: &str) -> bool { + /// let filename = std::path::Path::new(filename); + /// filename.extension() + /// .map_or(false, |ext| ext.eq_ignore_ascii_case("rs")) + /// } + /// ``` + #[clippy::version = "1.51.0"] + pub CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, + pedantic, + "Checks for calls to ends_with with case-sensitive file extensions" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2534,6 +2563,7 @@ impl_lint_pass!(Methods => [ ITER_ON_EMPTY_COLLECTIONS, NAIVE_BYTECOUNT, BYTES_COUNT_TO_LEN, + CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2801,6 +2831,10 @@ impl Methods { ("drain", [arg]) => { iter_with_drain::check(cx, expr, recv, span, arg); }, + ("ends_with", [arg]) => { + if let ExprKind::MethodCall(_, _, span) = expr.kind { + case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg); + }, ("expect", [_]) => match method_call(recv) { Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv), Some(("err", [recv], err_span)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span), From a8d80d531f1d358c26295eb3d81624594544dd4b Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 13:44:09 -0400 Subject: [PATCH 3779/5092] Move `GetFirst` into `Methods` lint pass --- clippy_lints/src/get_first.rs | 68 -------------------------- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_style.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/get_first.rs | 39 +++++++++++++++ clippy_lints/src/methods/mod.rs | 36 +++++++++++++- 7 files changed, 76 insertions(+), 75 deletions(-) delete mode 100644 clippy_lints/src/get_first.rs create mode 100644 clippy_lints/src/methods/get_first.rs diff --git a/clippy_lints/src/get_first.rs b/clippy_lints/src/get_first.rs deleted file mode 100644 index 529f7babaa5e..000000000000 --- a/clippy_lints/src/get_first.rs +++ /dev/null @@ -1,68 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{is_slice_of_primitives, match_def_path, paths}; -use if_chain::if_chain; -use rustc_ast::LitKind; -use rustc_errors::Applicability; -use rustc_hir as hir; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Spanned; - -declare_clippy_lint! { - /// ### What it does - /// Checks for using `x.get(0)` instead of - /// `x.first()`. - /// - /// ### Why is this bad? - /// Using `x.first()` is easier to read and has the same - /// result. - /// - /// ### Example - /// ```rust - /// let x = vec![2, 3, 5]; - /// let first_element = x.get(0); - /// ``` - /// - /// Use instead: - /// ```rust - /// let x = vec![2, 3, 5]; - /// let first_element = x.first(); - /// ``` - #[clippy::version = "1.63.0"] - pub GET_FIRST, - style, - "Using `x.get(0)` when `x.first()` is simpler" -} -declare_lint_pass!(GetFirst => [GET_FIRST]); - -impl<'tcx> LateLintPass<'tcx> for GetFirst { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if_chain! { - if let hir::ExprKind::MethodCall(_, [struct_calling_on, method_arg], _) = &expr.kind; - if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if match_def_path(cx, expr_def_id, &paths::SLICE_GET); - - if let Some(_) = is_slice_of_primitives(cx, struct_calling_on); - if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = method_arg.kind; - - then { - let mut applicability = Applicability::MachineApplicable; - let slice_name = snippet_with_applicability( - cx, - struct_calling_on.span, "..", - &mut applicability, - ); - span_lint_and_sugg( - cx, - GET_FIRST, - expr.span, - &format!("accessing first element with `{0}.get(0)`", slice_name), - "try", - format!("{}.first()", slice_name), - applicability, - ); - } - } - } -} diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index f48e542ee418..8ce0a26915f7 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -81,7 +81,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF), LintId::of(functions::RESULT_UNIT_ERR), LintId::of(functions::TOO_MANY_ARGUMENTS), - LintId::of(get_first::GET_FIRST), LintId::of(if_let_mutex::IF_LET_MUTEX), LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING), LintId::of(infinite_iter::INFINITE_ITER), @@ -162,6 +161,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::FILTER_MAP_IDENTITY), LintId::of(methods::FILTER_NEXT), LintId::of(methods::FLAT_MAP_IDENTITY), + LintId::of(methods::GET_FIRST), LintId::of(methods::GET_LAST_WITH_LEN), LintId::of(methods::INSPECT_FOR_EACH), LintId::of(methods::INTO_ITER_ON_REF), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 10ff1fa1f580..a6224035ec82 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -174,7 +174,6 @@ store.register_lints(&[ functions::TOO_MANY_ARGUMENTS, functions::TOO_MANY_LINES, future_not_send::FUTURE_NOT_SEND, - get_first::GET_FIRST, if_let_mutex::IF_LET_MUTEX, if_not_else::IF_NOT_ELSE, if_then_some_else_none::IF_THEN_SOME_ELSE_NONE, @@ -302,6 +301,7 @@ store.register_lints(&[ methods::FLAT_MAP_IDENTITY, methods::FLAT_MAP_OPTION, methods::FROM_ITER_INSTEAD_OF_COLLECT, + methods::GET_FIRST, methods::GET_LAST_WITH_LEN, methods::GET_UNWRAP, methods::IMPLICIT_CLONE, diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs index 6972c75597aa..5ddaba2396e7 100644 --- a/clippy_lints/src/lib.register_style.rs +++ b/clippy_lints/src/lib.register_style.rs @@ -29,7 +29,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(functions::DOUBLE_MUST_USE), LintId::of(functions::MUST_USE_UNIT), LintId::of(functions::RESULT_UNIT_ERR), - LintId::of(get_first::GET_FIRST), LintId::of(inherent_to_string::INHERENT_TO_STRING), LintId::of(init_numbered_fields::INIT_NUMBERED_FIELDS), LintId::of(len_zero::COMPARISON_TO_EMPTY), @@ -62,6 +61,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(methods::CHARS_LAST_CMP), LintId::of(methods::CHARS_NEXT_CMP), LintId::of(methods::ERR_EXPECT), + LintId::of(methods::GET_FIRST), LintId::of(methods::INTO_ITER_ON_REF), LintId::of(methods::IS_DIGIT_ASCII_RADIX), LintId::of(methods::ITER_CLONED_COLLECT), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 68f69dc64b86..3fcdc84113d1 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -233,7 +233,6 @@ mod from_over_into; mod from_str_radix_10; mod functions; mod future_not_send; -mod get_first; mod if_let_mutex; mod if_not_else; mod if_then_some_else_none; @@ -907,7 +906,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(strings::TrimSplitWhitespace)); store.register_late_pass(|| Box::new(rc_clone_in_vec_init::RcCloneInVecInit)); store.register_early_pass(|| Box::new(duplicate_mod::DuplicateMod::default())); - store.register_late_pass(|| Box::new(get_first::GetFirst)); store.register_early_pass(|| Box::new(unused_rounding::UnusedRounding)); store.register_early_pass(move || Box::new(almost_complete_letter_range::AlmostCompleteLetterRange::new(msrv))); store.register_late_pass(|| Box::new(swap_ptr_to_ref::SwapPtrToRef)); diff --git a/clippy_lints/src/methods/get_first.rs b/clippy_lints/src/methods/get_first.rs new file mode 100644 index 000000000000..4de77de74042 --- /dev/null +++ b/clippy_lints/src/methods/get_first.rs @@ -0,0 +1,39 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_slice_of_primitives; +use clippy_utils::source::snippet_with_applicability; +use if_chain::if_chain; +use rustc_ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_span::source_map::Spanned; + +use super::GET_FIRST; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + recv: &'tcx hir::Expr<'_>, + arg: &'tcx hir::Expr<'_>, +) { + if_chain! { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(method_id); + if cx.tcx.type_of(impl_id).is_slice(); + if let Some(_) = is_slice_of_primitives(cx, recv); + if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = arg.kind; + then { + let mut app = Applicability::MachineApplicable; + let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app); + span_lint_and_sugg( + cx, + GET_FIRST, + expr.span, + &format!("accessing first element with `{0}.get(0)`", slice_name), + "try", + format!("{}.first()", slice_name), + app, + ); + } + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 0bb247c7e810..c3438426985b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -24,6 +24,7 @@ mod filter_next; mod flat_map_identity; mod flat_map_option; mod from_iter_instead_of_collect; +mod get_first; mod get_last_with_len; mod get_unwrap; mod implicit_clone; @@ -2457,6 +2458,32 @@ declare_clippy_lint! { "Checks for calls to ends_with with case-sensitive file extensions" } +declare_clippy_lint! { + /// ### What it does + /// Checks for using `x.get(0)` instead of + /// `x.first()`. + /// + /// ### Why is this bad? + /// Using `x.first()` is easier to read and has the same + /// result. + /// + /// ### Example + /// ```rust + /// let x = vec![2, 3, 5]; + /// let first_element = x.get(0); + /// ``` + /// + /// Use instead: + /// ```rust + /// let x = vec![2, 3, 5]; + /// let first_element = x.first(); + /// ``` + #[clippy::version = "1.63.0"] + pub GET_FIRST, + style, + "Using `x.get(0)` when `x.first()` is simpler" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2564,6 +2591,7 @@ impl_lint_pass!(Methods => [ NAIVE_BYTECOUNT, BYTES_COUNT_TO_LEN, CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, + GET_FIRST, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2833,7 +2861,8 @@ impl Methods { }, ("ends_with", [arg]) => { if let ExprKind::MethodCall(_, _, span) = expr.kind { - case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg); + case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg); + } }, ("expect", [_]) => match method_call(recv) { Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv), @@ -2867,7 +2896,10 @@ impl Methods { inspect_for_each::check(cx, expr, span2); } }, - ("get", [arg]) => get_last_with_len::check(cx, expr, recv, arg), + ("get", [arg]) => { + get_first::check(cx, expr, recv, arg); + get_last_with_len::check(cx, expr, recv, arg); + }, ("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"), ("is_file", []) => filetype_is_file::check(cx, expr, recv), ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv), From 5bc8813cdd4f33f42c4dc17572d148c284d3e81b Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 15:20:47 -0400 Subject: [PATCH 3780/5092] Move `ManualOkOr` into `Methods` lint pass --- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_pedantic.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/manual_ok_or.rs | 95 ----------------------- clippy_lints/src/methods/manual_ok_or.rs | 64 +++++++++++++++ clippy_lints/src/methods/mod.rs | 33 +++++++- 6 files changed, 98 insertions(+), 100 deletions(-) delete mode 100644 clippy_lints/src/manual_ok_or.rs create mode 100644 clippy_lints/src/methods/manual_ok_or.rs diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index a6224035ec82..ac30c8b6eac2 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -243,7 +243,6 @@ store.register_lints(&[ manual_empty_string_creations::MANUAL_EMPTY_STRING_CREATIONS, manual_instant_elapsed::MANUAL_INSTANT_ELAPSED, manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE, - manual_ok_or::MANUAL_OK_OR, manual_rem_euclid::MANUAL_REM_EUCLID, manual_retain::MANUAL_RETAIN, manual_strip::MANUAL_STRIP, @@ -322,6 +321,7 @@ store.register_lints(&[ methods::ITER_WITH_DRAIN, methods::MANUAL_FILTER_MAP, methods::MANUAL_FIND_MAP, + methods::MANUAL_OK_OR, methods::MANUAL_SATURATING_ARITHMETIC, methods::MANUAL_SPLIT_ONCE, methods::MANUAL_STR_REPEAT, diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index c9cf7dbd0785..5c04a331d0a7 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -48,7 +48,6 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(macro_use::MACRO_USE_IMPORTS), LintId::of(manual_assert::MANUAL_ASSERT), LintId::of(manual_instant_elapsed::MANUAL_INSTANT_ELAPSED), - LintId::of(manual_ok_or::MANUAL_OK_OR), LintId::of(matches::MATCH_BOOL), LintId::of(matches::MATCH_ON_VEC_ITEMS), LintId::of(matches::MATCH_SAME_ARMS), @@ -62,6 +61,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(methods::FROM_ITER_INSTEAD_OF_COLLECT), LintId::of(methods::IMPLICIT_CLONE), LintId::of(methods::INEFFICIENT_TO_STRING), + LintId::of(methods::MANUAL_OK_OR), LintId::of(methods::MAP_UNWRAP_OR), LintId::of(methods::NAIVE_BYTECOUNT), LintId::of(methods::UNNECESSARY_JOIN), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 3fcdc84113d1..774ae01cc4f2 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -270,7 +270,6 @@ mod manual_bits; mod manual_empty_string_creations; mod manual_instant_elapsed; mod manual_non_exhaustive; -mod manual_ok_or; mod manual_rem_euclid; mod manual_retain; mod manual_strip; @@ -838,7 +837,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(stable_sort_primitive::StableSortPrimitive)); store.register_late_pass(|| Box::new(repeat_once::RepeatOnce)); store.register_late_pass(|| Box::new(unwrap_in_result::UnwrapInResult)); - store.register_late_pass(|| Box::new(manual_ok_or::ManualOkOr)); store.register_late_pass(|| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned)); store.register_late_pass(|| Box::new(async_yields_async::AsyncYieldsAsync)); let disallowed_methods = conf.disallowed_methods.clone(); diff --git a/clippy_lints/src/manual_ok_or.rs b/clippy_lints/src/manual_ok_or.rs deleted file mode 100644 index cf5004399b88..000000000000 --- a/clippy_lints/src/manual_ok_or.rs +++ /dev/null @@ -1,95 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; -use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_lang_ctor, path_to_local_id}; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::LangItem::{ResultErr, ResultOk}; -use rustc_hir::{Closure, Expr, ExprKind, PatKind}; -use rustc_lint::LintContext; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::symbol::sym; - -declare_clippy_lint! { - /// ### What it does - /// - /// Finds patterns that reimplement `Option::ok_or`. - /// - /// ### Why is this bad? - /// - /// Concise code helps focusing on behavior instead of boilerplate. - /// - /// ### Examples - /// ```rust - /// let foo: Option = None; - /// foo.map_or(Err("error"), |v| Ok(v)); - /// ``` - /// - /// Use instead: - /// ```rust - /// let foo: Option = None; - /// foo.ok_or("error"); - /// ``` - #[clippy::version = "1.49.0"] - pub MANUAL_OK_OR, - pedantic, - "finds patterns that can be encoded more concisely with `Option::ok_or`" -} - -declare_lint_pass!(ManualOkOr => [MANUAL_OK_OR]); - -impl<'tcx> LateLintPass<'tcx> for ManualOkOr { - fn check_expr(&mut self, cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'tcx>) { - if in_external_macro(cx.sess(), scrutinee.span) { - return; - } - - if_chain! { - if let ExprKind::MethodCall(method_segment, [receiver, or_expr, map_expr], _) = scrutinee.kind; - if method_segment.ident.name == sym!(map_or); - let ty = cx.typeck_results().expr_ty(receiver); - if is_type_diagnostic_item(cx, ty, sym::Option); - if is_ok_wrapping(cx, map_expr); - if let ExprKind::Call(Expr { kind: ExprKind::Path(err_path), .. }, &[ref err_arg]) = or_expr.kind; - if is_lang_ctor(cx, err_path, ResultErr); - if let Some(method_receiver_snippet) = snippet_opt(cx, receiver.span); - if let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span); - if let Some(indent) = indent_of(cx, scrutinee.span); - then { - let reindented_err_arg_snippet = - reindent_multiline(err_arg_snippet.into(), true, Some(indent + 4)); - span_lint_and_sugg( - cx, - MANUAL_OK_OR, - scrutinee.span, - "this pattern reimplements `Option::ok_or`", - "replace with", - format!( - "{}.ok_or({})", - method_receiver_snippet, - reindented_err_arg_snippet - ), - Applicability::MachineApplicable, - ); - } - } - } -} - -fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool { - if let ExprKind::Path(ref qpath) = map_expr.kind { - if is_lang_ctor(cx, qpath, ResultOk) { - return true; - } - } - if_chain! { - if let ExprKind::Closure(&Closure { body, .. }) = map_expr.kind; - let body = cx.tcx.hir().body(body); - if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind; - if let ExprKind::Call(Expr { kind: ExprKind::Path(ok_path), .. }, &[ref ok_arg]) = body.value.kind; - if is_lang_ctor(cx, ok_path, ResultOk); - then { path_to_local_id(ok_arg, param_id) } else { false } - } -} diff --git a/clippy_lints/src/methods/manual_ok_or.rs b/clippy_lints/src/methods/manual_ok_or.rs new file mode 100644 index 000000000000..ffd2f4a38b8a --- /dev/null +++ b/clippy_lints/src/methods/manual_ok_or.rs @@ -0,0 +1,64 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_lang_ctor, path_to_local_id}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::LangItem::{ResultErr, ResultOk}; +use rustc_hir::{Closure, Expr, ExprKind, PatKind}; +use rustc_lint::LateContext; +use rustc_span::symbol::sym; + +use super::MANUAL_OK_OR; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + recv: &'tcx Expr<'_>, + or_expr: &'tcx Expr<'_>, + map_expr: &'tcx Expr<'_>, +) { + if_chain! { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(method_id); + if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Option); + if let ExprKind::Call(Expr { kind: ExprKind::Path(err_path), .. }, [err_arg]) = or_expr.kind; + if is_lang_ctor(cx, err_path, ResultErr); + if is_ok_wrapping(cx, map_expr); + if let Some(recv_snippet) = snippet_opt(cx, recv.span); + if let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span); + if let Some(indent) = indent_of(cx, expr.span); + then { + let reindented_err_arg_snippet = reindent_multiline(err_arg_snippet.into(), true, Some(indent + 4)); + span_lint_and_sugg( + cx, + MANUAL_OK_OR, + expr.span, + "this pattern reimplements `Option::ok_or`", + "replace with", + format!( + "{}.ok_or({})", + recv_snippet, + reindented_err_arg_snippet + ), + Applicability::MachineApplicable, + ); + } + } +} + +fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool { + if let ExprKind::Path(ref qpath) = map_expr.kind { + if is_lang_ctor(cx, qpath, ResultOk) { + return true; + } + } + if_chain! { + if let ExprKind::Closure(&Closure { body, .. }) = map_expr.kind; + let body = cx.tcx.hir().body(body); + if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind; + if let ExprKind::Call(Expr { kind: ExprKind::Path(ok_path), .. }, &[ref ok_arg]) = body.value.kind; + if is_lang_ctor(cx, ok_path, ResultOk); + then { path_to_local_id(ok_arg, param_id) } else { false } + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index c3438426985b..132f6040a51d 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -42,6 +42,7 @@ mod iter_overeager_cloned; mod iter_skip_next; mod iter_with_drain; mod iterator_step_by_zero; +mod manual_ok_or; mod manual_saturating_arithmetic; mod manual_str_repeat; mod map_collect_result_unit; @@ -2484,6 +2485,32 @@ declare_clippy_lint! { "Using `x.get(0)` when `x.first()` is simpler" } +declare_clippy_lint! { + /// ### What it does + /// + /// Finds patterns that reimplement `Option::ok_or`. + /// + /// ### Why is this bad? + /// + /// Concise code helps focusing on behavior instead of boilerplate. + /// + /// ### Examples + /// ```rust + /// let foo: Option = None; + /// foo.map_or(Err("error"), |v| Ok(v)); + /// ``` + /// + /// Use instead: + /// ```rust + /// let foo: Option = None; + /// foo.ok_or("error"); + /// ``` + #[clippy::version = "1.49.0"] + pub MANUAL_OK_OR, + pedantic, + "finds patterns that can be encoded more concisely with `Option::ok_or`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2592,6 +2619,7 @@ impl_lint_pass!(Methods => [ BYTES_COUNT_TO_LEN, CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, GET_FIRST, + MANUAL_OK_OR, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2936,7 +2964,10 @@ impl Methods { } map_identity::check(cx, expr, recv, m_arg, name, span); }, - ("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map), + ("map_or", [def, map]) => { + option_map_or_none::check(cx, expr, recv, def, map); + manual_ok_or::check(cx, expr, recv, def, map); + }, ("next", []) => { if let Some((name2, [recv2, args2 @ ..], _)) = method_call(recv) { match (name2, args2) { From 452395485b113b06c1a47313eeab75d374d97e9f Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 15:45:04 -0400 Subject: [PATCH 3781/5092] Move `MapClone` into `Methods` lint pass --- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_style.rs | 2 +- clippy_lints/src/lib.rs | 3 - clippy_lints/src/map_clone.rs | 167 ------------------------- clippy_lints/src/methods/map_clone.rs | 122 ++++++++++++++++++ clippy_lints/src/methods/mod.rs | 34 +++++ 7 files changed, 159 insertions(+), 173 deletions(-) delete mode 100644 clippy_lints/src/map_clone.rs create mode 100644 clippy_lints/src/methods/map_clone.rs diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 8ce0a26915f7..c496fd289bb8 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -127,7 +127,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(manual_rem_euclid::MANUAL_REM_EUCLID), LintId::of(manual_retain::MANUAL_RETAIN), LintId::of(manual_strip::MANUAL_STRIP), - LintId::of(map_clone::MAP_CLONE), LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN), LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN), LintId::of(match_result_ok::MATCH_RESULT_OK), @@ -179,6 +178,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::MANUAL_SATURATING_ARITHMETIC), LintId::of(methods::MANUAL_SPLIT_ONCE), LintId::of(methods::MANUAL_STR_REPEAT), + LintId::of(methods::MAP_CLONE), LintId::of(methods::MAP_COLLECT_RESULT_UNIT), LintId::of(methods::MAP_FLATTEN), LintId::of(methods::MAP_IDENTITY), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index ac30c8b6eac2..c7ea7f703f2f 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -246,7 +246,6 @@ store.register_lints(&[ manual_rem_euclid::MANUAL_REM_EUCLID, manual_retain::MANUAL_RETAIN, manual_strip::MANUAL_STRIP, - map_clone::MAP_CLONE, map_err_ignore::MAP_ERR_IGNORE, map_unit_fn::OPTION_MAP_UNIT_FN, map_unit_fn::RESULT_MAP_UNIT_FN, @@ -325,6 +324,7 @@ store.register_lints(&[ methods::MANUAL_SATURATING_ARITHMETIC, methods::MANUAL_SPLIT_ONCE, methods::MANUAL_STR_REPEAT, + methods::MAP_CLONE, methods::MAP_COLLECT_RESULT_UNIT, methods::MAP_FLATTEN, methods::MAP_IDENTITY, diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs index 5ddaba2396e7..52bf019c82e9 100644 --- a/clippy_lints/src/lib.register_style.rs +++ b/clippy_lints/src/lib.register_style.rs @@ -45,7 +45,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(manual_bits::MANUAL_BITS), LintId::of(manual_empty_string_creations::MANUAL_EMPTY_STRING_CREATIONS), LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE), - LintId::of(map_clone::MAP_CLONE), LintId::of(match_result_ok::MATCH_RESULT_OK), LintId::of(matches::COLLAPSIBLE_MATCH), LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH), @@ -69,6 +68,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(methods::ITER_NTH_ZERO), LintId::of(methods::ITER_SKIP_NEXT), LintId::of(methods::MANUAL_SATURATING_ARITHMETIC), + LintId::of(methods::MAP_CLONE), LintId::of(methods::MAP_COLLECT_RESULT_UNIT), LintId::of(methods::NEW_RET_NO_SELF), LintId::of(methods::OBFUSCATED_IF_ELSE), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 774ae01cc4f2..8f31e4b938c7 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -273,7 +273,6 @@ mod manual_non_exhaustive; mod manual_rem_euclid; mod manual_retain; mod manual_strip; -mod map_clone; mod map_err_ignore; mod map_unit_fn; mod match_result_ok; @@ -628,8 +627,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || Box::new(needless_question_mark::NeedlessQuestionMark)); store.register_late_pass(move || Box::new(casts::Casts::new(msrv))); store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv))); - store.register_late_pass(move || Box::new(map_clone::MapClone::new(msrv))); - store.register_late_pass(|| Box::new(size_of_in_element_count::SizeOfInElementCount)); store.register_late_pass(|| Box::new(same_name_method::SameNameMethod)); let max_suggested_slice_pattern_length = conf.max_suggested_slice_pattern_length; diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs deleted file mode 100644 index 95c312f1fe26..000000000000 --- a/clippy_lints/src/map_clone.rs +++ /dev/null @@ -1,167 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::{is_copy, is_type_diagnostic_item}; -use clippy_utils::{is_trait_method, meets_msrv, msrvs, peel_blocks}; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir as hir; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::mir::Mutability; -use rustc_middle::ty; -use rustc_middle::ty::adjustment::Adjust; -use rustc_semver::RustcVersion; -use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::symbol::Ident; -use rustc_span::{sym, Span}; - -declare_clippy_lint! { - /// ### What it does - /// Checks for usage of `map(|x| x.clone())` or - /// dereferencing closures for `Copy` types, on `Iterator` or `Option`, - /// and suggests `cloned()` or `copied()` instead - /// - /// ### Why is this bad? - /// Readability, this can be written more concisely - /// - /// ### Example - /// ```rust - /// let x = vec![42, 43]; - /// let y = x.iter(); - /// let z = y.map(|i| *i); - /// ``` - /// - /// The correct use would be: - /// - /// ```rust - /// let x = vec![42, 43]; - /// let y = x.iter(); - /// let z = y.cloned(); - /// ``` - #[clippy::version = "pre 1.29.0"] - pub MAP_CLONE, - style, - "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types" -} - -pub struct MapClone { - msrv: Option, -} - -impl_lint_pass!(MapClone => [MAP_CLONE]); - -impl MapClone { - pub fn new(msrv: Option) -> Self { - Self { msrv } - } -} - -impl<'tcx> LateLintPass<'tcx> for MapClone { - fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) { - if e.span.from_expansion() { - return; - } - - if_chain! { - if let hir::ExprKind::MethodCall(method, args, _) = e.kind; - if args.len() == 2; - if method.ident.name == sym::map; - let ty = cx.typeck_results().expr_ty(&args[0]); - if is_type_diagnostic_item(cx, ty, sym::Option) || is_trait_method(cx, e, sym::Iterator); - if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = args[1].kind; - then { - let closure_body = cx.tcx.hir().body(body); - let closure_expr = peel_blocks(&closure_body.value); - match closure_body.params[0].pat.kind { - hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding( - hir::BindingAnnotation::Unannotated, .., name, None - ) = inner.kind { - if ident_eq(name, closure_expr) { - self.lint_explicit_closure(cx, e.span, args[0].span, true); - } - }, - hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, .., name, None) => { - match closure_expr.kind { - hir::ExprKind::Unary(hir::UnOp::Deref, inner) => { - if ident_eq(name, inner) { - if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() { - self.lint_explicit_closure(cx, e.span, args[0].span, true); - } - } - }, - hir::ExprKind::MethodCall(method, [obj], _) => if_chain! { - if ident_eq(name, obj) && method.ident.name == sym::clone; - if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id); - if let Some(trait_id) = cx.tcx.trait_of_item(fn_id); - if cx.tcx.lang_items().clone_trait().map_or(false, |id| id == trait_id); - // no autoderefs - if !cx.typeck_results().expr_adjustments(obj).iter() - .any(|a| matches!(a.kind, Adjust::Deref(Some(..)))); - then { - let obj_ty = cx.typeck_results().expr_ty(obj); - if let ty::Ref(_, ty, mutability) = obj_ty.kind() { - if matches!(mutability, Mutability::Not) { - let copy = is_copy(cx, *ty); - self.lint_explicit_closure(cx, e.span, args[0].span, copy); - } - } else { - lint_needless_cloning(cx, e.span, args[0].span); - } - } - }, - _ => {}, - } - }, - _ => {}, - } - } - } - } - - extract_msrv_attr!(LateContext); -} - -fn ident_eq(name: Ident, path: &hir::Expr<'_>) -> bool { - if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = path.kind { - path.segments.len() == 1 && path.segments[0].ident == name - } else { - false - } -} - -fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) { - span_lint_and_sugg( - cx, - MAP_CLONE, - root.trim_start(receiver).unwrap(), - "you are needlessly cloning iterator elements", - "remove the `map` call", - String::new(), - Applicability::MachineApplicable, - ); -} - -impl MapClone { - fn lint_explicit_closure(&self, cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool) { - let mut applicability = Applicability::MachineApplicable; - - let (message, sugg_method) = if is_copy && meets_msrv(self.msrv, msrvs::ITERATOR_COPIED) { - ("you are using an explicit closure for copying elements", "copied") - } else { - ("you are using an explicit closure for cloning elements", "cloned") - }; - - span_lint_and_sugg( - cx, - MAP_CLONE, - replace, - message, - &format!("consider calling the dedicated `{}` method", sugg_method), - format!( - "{}.{}()", - snippet_with_applicability(cx, root, "..", &mut applicability), - sugg_method, - ), - applicability, - ); - } -} diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs new file mode 100644 index 000000000000..ffedda95ff8e --- /dev/null +++ b/clippy_lints/src/methods/map_clone.rs @@ -0,0 +1,122 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::{is_copy, is_type_diagnostic_item}; +use clippy_utils::{is_diag_trait_item, meets_msrv, msrvs, peel_blocks}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_middle::mir::Mutability; +use rustc_middle::ty; +use rustc_middle::ty::adjustment::Adjust; +use rustc_semver::RustcVersion; +use rustc_span::symbol::Ident; +use rustc_span::{sym, Span}; + +use super::MAP_CLONE; + +pub(super) fn check<'tcx>( + cx: &LateContext<'_>, + e: &hir::Expr<'_>, + recv: &hir::Expr<'_>, + arg: &'tcx hir::Expr<'_>, + msrv: Option, +) { + if_chain! { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id); + if cx.tcx.impl_of_method(method_id) + .map_or(false, |id| is_type_diagnostic_item(cx, cx.tcx.type_of(id), sym::Option)) + || is_diag_trait_item(cx, method_id, sym::Iterator); + if let hir::ExprKind::Closure(&hir::Closure{ body, .. }) = arg.kind; + then { + let closure_body = cx.tcx.hir().body(body); + let closure_expr = peel_blocks(&closure_body.value); + match closure_body.params[0].pat.kind { + hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding( + hir::BindingAnnotation::Unannotated, .., name, None + ) = inner.kind { + if ident_eq(name, closure_expr) { + lint_explicit_closure(cx, e.span, recv.span, true, msrv); + } + }, + hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, .., name, None) => { + match closure_expr.kind { + hir::ExprKind::Unary(hir::UnOp::Deref, inner) => { + if ident_eq(name, inner) { + if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() { + lint_explicit_closure(cx, e.span, recv.span, true, msrv); + } + } + }, + hir::ExprKind::MethodCall(method, [obj], _) => if_chain! { + if ident_eq(name, obj) && method.ident.name == sym::clone; + if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id); + if let Some(trait_id) = cx.tcx.trait_of_item(fn_id); + if cx.tcx.lang_items().clone_trait().map_or(false, |id| id == trait_id); + // no autoderefs + if !cx.typeck_results().expr_adjustments(obj).iter() + .any(|a| matches!(a.kind, Adjust::Deref(Some(..)))); + then { + let obj_ty = cx.typeck_results().expr_ty(obj); + if let ty::Ref(_, ty, mutability) = obj_ty.kind() { + if matches!(mutability, Mutability::Not) { + let copy = is_copy(cx, *ty); + lint_explicit_closure(cx, e.span, recv.span, copy, msrv); + } + } else { + lint_needless_cloning(cx, e.span, recv.span); + } + } + }, + _ => {}, + } + }, + _ => {}, + } + } + } +} + +fn ident_eq(name: Ident, path: &hir::Expr<'_>) -> bool { + if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = path.kind { + path.segments.len() == 1 && path.segments[0].ident == name + } else { + false + } +} + +fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) { + span_lint_and_sugg( + cx, + MAP_CLONE, + root.trim_start(receiver).unwrap(), + "you are needlessly cloning iterator elements", + "remove the `map` call", + String::new(), + Applicability::MachineApplicable, + ); +} + +fn lint_explicit_closure(cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool, msrv: Option) { + let mut applicability = Applicability::MachineApplicable; + + let (message, sugg_method) = if is_copy && meets_msrv(msrv, msrvs::ITERATOR_COPIED) { + ("you are using an explicit closure for copying elements", "copied") + } else { + ("you are using an explicit closure for cloning elements", "cloned") + }; + + span_lint_and_sugg( + cx, + MAP_CLONE, + replace, + message, + &format!("consider calling the dedicated `{}` method", sugg_method), + format!( + "{}.{}()", + snippet_with_applicability(cx, root, "..", &mut applicability), + sugg_method, + ), + applicability, + ); +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 132f6040a51d..02592da1aae9 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -45,6 +45,7 @@ mod iterator_step_by_zero; mod manual_ok_or; mod manual_saturating_arithmetic; mod manual_str_repeat; +mod map_clone; mod map_collect_result_unit; mod map_flatten; mod map_identity; @@ -2511,6 +2512,35 @@ declare_clippy_lint! { "finds patterns that can be encoded more concisely with `Option::ok_or`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `map(|x| x.clone())` or + /// dereferencing closures for `Copy` types, on `Iterator` or `Option`, + /// and suggests `cloned()` or `copied()` instead + /// + /// ### Why is this bad? + /// Readability, this can be written more concisely + /// + /// ### Example + /// ```rust + /// let x = vec![42, 43]; + /// let y = x.iter(); + /// let z = y.map(|i| *i); + /// ``` + /// + /// The correct use would be: + /// + /// ```rust + /// let x = vec![42, 43]; + /// let y = x.iter(); + /// let z = y.cloned(); + /// ``` + #[clippy::version = "pre 1.29.0"] + pub MAP_CLONE, + style, + "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2620,6 +2650,7 @@ impl_lint_pass!(Methods => [ CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, GET_FIRST, MANUAL_OK_OR, + MAP_CLONE, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2949,6 +2980,9 @@ impl Methods { } }, (name @ ("map" | "map_err"), [m_arg]) => { + if name == "map" { + map_clone::check(cx, expr, recv, m_arg, self.msrv); + } if let Some((name, [recv2, args @ ..], span2)) = method_call(recv) { match (name, args) { ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv), From 2f0ed0a0b1fa7928464b95e0cfd0883699cb9c33 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 15:59:24 -0400 Subject: [PATCH 3782/5092] Move `MapErrIgnore` into `Methods` lint pass --- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_restriction.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/map_err_ignore.rs | 154 ------------------- clippy_lints/src/methods/map_err_ignore.rs | 34 ++++ clippy_lints/src/methods/mod.rs | 104 +++++++++++++ 6 files changed, 140 insertions(+), 158 deletions(-) delete mode 100644 clippy_lints/src/map_err_ignore.rs create mode 100644 clippy_lints/src/methods/map_err_ignore.rs diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index c7ea7f703f2f..67fb0d50931a 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -246,7 +246,6 @@ store.register_lints(&[ manual_rem_euclid::MANUAL_REM_EUCLID, manual_retain::MANUAL_RETAIN, manual_strip::MANUAL_STRIP, - map_err_ignore::MAP_ERR_IGNORE, map_unit_fn::OPTION_MAP_UNIT_FN, map_unit_fn::RESULT_MAP_UNIT_FN, match_result_ok::MATCH_RESULT_OK, @@ -326,6 +325,7 @@ store.register_lints(&[ methods::MANUAL_STR_REPEAT, methods::MAP_CLONE, methods::MAP_COLLECT_RESULT_UNIT, + methods::MAP_ERR_IGNORE, methods::MAP_FLATTEN, methods::MAP_IDENTITY, methods::MAP_UNWRAP_OR, diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs index 890ae2792abf..7fc5eef5f8a6 100644 --- a/clippy_lints/src/lib.register_restriction.rs +++ b/clippy_lints/src/lib.register_restriction.rs @@ -30,7 +30,6 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(large_include_file::LARGE_INCLUDE_FILE), LintId::of(let_underscore::LET_UNDERSCORE_MUST_USE), LintId::of(literal_representation::DECIMAL_LITERAL_REPRESENTATION), - LintId::of(map_err_ignore::MAP_ERR_IGNORE), LintId::of(matches::REST_PAT_IN_FULLY_BOUND_STRUCTS), LintId::of(matches::TRY_ERR), LintId::of(matches::WILDCARD_ENUM_MATCH_ARM), @@ -39,6 +38,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(methods::EXPECT_USED), LintId::of(methods::FILETYPE_IS_FILE), LintId::of(methods::GET_UNWRAP), + LintId::of(methods::MAP_ERR_IGNORE), LintId::of(methods::UNWRAP_USED), LintId::of(misc_early::SEPARATED_LITERAL_SUFFIX), LintId::of(misc_early::UNNEEDED_FIELD_PATTERN), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 8f31e4b938c7..179d630089fd 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -273,7 +273,6 @@ mod manual_non_exhaustive; mod manual_rem_euclid; mod manual_retain; mod manual_strip; -mod map_err_ignore; mod map_unit_fn; mod match_result_ok; mod matches; @@ -636,7 +635,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: msrv, )) }); - store.register_late_pass(|| Box::new(map_err_ignore::MapErrIgnore)); store.register_late_pass(|| Box::new(shadow::Shadow::default())); store.register_late_pass(|| Box::new(unit_types::UnitTypes)); store.register_late_pass(|| Box::new(loops::Loops)); diff --git a/clippy_lints/src/map_err_ignore.rs b/clippy_lints/src/map_err_ignore.rs deleted file mode 100644 index 1e542447c96e..000000000000 --- a/clippy_lints/src/map_err_ignore.rs +++ /dev/null @@ -1,154 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_help; -use rustc_hir::{CaptureBy, Closure, Expr, ExprKind, PatKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -declare_clippy_lint! { - /// ### What it does - /// Checks for instances of `map_err(|_| Some::Enum)` - /// - /// ### Why is this bad? - /// This `map_err` throws away the original error rather than allowing the enum to contain and report the cause of the error - /// - /// ### Example - /// Before: - /// ```rust - /// use std::fmt; - /// - /// #[derive(Debug)] - /// enum Error { - /// Indivisible, - /// Remainder(u8), - /// } - /// - /// impl fmt::Display for Error { - /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - /// match self { - /// Error::Indivisible => write!(f, "could not divide input by three"), - /// Error::Remainder(remainder) => write!( - /// f, - /// "input is not divisible by three, remainder = {}", - /// remainder - /// ), - /// } - /// } - /// } - /// - /// impl std::error::Error for Error {} - /// - /// fn divisible_by_3(input: &str) -> Result<(), Error> { - /// input - /// .parse::() - /// .map_err(|_| Error::Indivisible) - /// .map(|v| v % 3) - /// .and_then(|remainder| { - /// if remainder == 0 { - /// Ok(()) - /// } else { - /// Err(Error::Remainder(remainder as u8)) - /// } - /// }) - /// } - /// ``` - /// - /// After: - /// ```rust - /// use std::{fmt, num::ParseIntError}; - /// - /// #[derive(Debug)] - /// enum Error { - /// Indivisible(ParseIntError), - /// Remainder(u8), - /// } - /// - /// impl fmt::Display for Error { - /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - /// match self { - /// Error::Indivisible(_) => write!(f, "could not divide input by three"), - /// Error::Remainder(remainder) => write!( - /// f, - /// "input is not divisible by three, remainder = {}", - /// remainder - /// ), - /// } - /// } - /// } - /// - /// impl std::error::Error for Error { - /// fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - /// match self { - /// Error::Indivisible(source) => Some(source), - /// _ => None, - /// } - /// } - /// } - /// - /// fn divisible_by_3(input: &str) -> Result<(), Error> { - /// input - /// .parse::() - /// .map_err(Error::Indivisible) - /// .map(|v| v % 3) - /// .and_then(|remainder| { - /// if remainder == 0 { - /// Ok(()) - /// } else { - /// Err(Error::Remainder(remainder as u8)) - /// } - /// }) - /// } - /// ``` - #[clippy::version = "1.48.0"] - pub MAP_ERR_IGNORE, - restriction, - "`map_err` should not ignore the original error" -} - -declare_lint_pass!(MapErrIgnore => [MAP_ERR_IGNORE]); - -impl<'tcx> LateLintPass<'tcx> for MapErrIgnore { - // do not try to lint if this is from a macro or desugaring - fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) { - if e.span.from_expansion() { - return; - } - - // check if this is a method call (e.g. x.foo()) - if let ExprKind::MethodCall(method, [_, arg], _) = e.kind { - // only work if the method name is `map_err` and there are only 2 arguments (e.g. x.map_err(|_|[1] - // Enum::Variant[2])) - if method.ident.name == sym!(map_err) { - // make sure the first argument is a closure, and grab the CaptureRef, BodyId, and fn_decl_span - // fields - if let ExprKind::Closure(&Closure { - capture_clause, - body, - fn_decl_span, - .. - }) = arg.kind - { - // check if this is by Reference (meaning there's no move statement) - if capture_clause == CaptureBy::Ref { - // Get the closure body to check the parameters and values - let closure_body = cx.tcx.hir().body(body); - // make sure there's only one parameter (`|_|`) - if closure_body.params.len() == 1 { - // make sure that parameter is the wild token (`_`) - if let PatKind::Wild = closure_body.params[0].pat.kind { - // span the area of the closure capture and warn that the - // original error will be thrown away - span_lint_and_help( - cx, - MAP_ERR_IGNORE, - fn_decl_span, - "`map_err(|_|...` wildcard pattern discards the original error", - None, - "consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`)", - ); - } - } - } - } - } - } - } -} diff --git a/clippy_lints/src/methods/map_err_ignore.rs b/clippy_lints/src/methods/map_err_ignore.rs new file mode 100644 index 000000000000..1fb6617145e7 --- /dev/null +++ b/clippy_lints/src/methods/map_err_ignore.rs @@ -0,0 +1,34 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::ty::is_type_diagnostic_item; +use rustc_hir::{CaptureBy, Closure, Expr, ExprKind, PatKind}; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::MAP_ERR_IGNORE; + +pub(super) fn check<'tcx>(cx: &LateContext<'_>, e: &Expr<'_>, arg: &'tcx Expr<'_>) { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) + && let Some(impl_id) = cx.tcx.impl_of_method(method_id) + && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Result) + && let ExprKind::Closure(&Closure { + capture_clause: CaptureBy::Ref, + body, + fn_decl_span, + .. + }) = arg.kind + && let closure_body = cx.tcx.hir().body(body) + && let [param] = closure_body.params + && let PatKind::Wild = param.pat.kind + { + // span the area of the closure capture and warn that the + // original error will be thrown away + span_lint_and_help( + cx, + MAP_ERR_IGNORE, + fn_decl_span, + "`map_err(|_|...` wildcard pattern discards the original error", + None, + "consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`)", + ); + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 02592da1aae9..e327bdcf578a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -47,6 +47,7 @@ mod manual_saturating_arithmetic; mod manual_str_repeat; mod map_clone; mod map_collect_result_unit; +mod map_err_ignore; mod map_flatten; mod map_identity; mod map_unwrap_or; @@ -2541,6 +2542,106 @@ declare_clippy_lint! { "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types" } +declare_clippy_lint! { + /// ### What it does + /// Checks for instances of `map_err(|_| Some::Enum)` + /// + /// ### Why is this bad? + /// This `map_err` throws away the original error rather than allowing the enum to contain and report the cause of the error + /// + /// ### Example + /// Before: + /// ```rust + /// use std::fmt; + /// + /// #[derive(Debug)] + /// enum Error { + /// Indivisible, + /// Remainder(u8), + /// } + /// + /// impl fmt::Display for Error { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// match self { + /// Error::Indivisible => write!(f, "could not divide input by three"), + /// Error::Remainder(remainder) => write!( + /// f, + /// "input is not divisible by three, remainder = {}", + /// remainder + /// ), + /// } + /// } + /// } + /// + /// impl std::error::Error for Error {} + /// + /// fn divisible_by_3(input: &str) -> Result<(), Error> { + /// input + /// .parse::() + /// .map_err(|_| Error::Indivisible) + /// .map(|v| v % 3) + /// .and_then(|remainder| { + /// if remainder == 0 { + /// Ok(()) + /// } else { + /// Err(Error::Remainder(remainder as u8)) + /// } + /// }) + /// } + /// ``` + /// + /// After: + /// ```rust + /// use std::{fmt, num::ParseIntError}; + /// + /// #[derive(Debug)] + /// enum Error { + /// Indivisible(ParseIntError), + /// Remainder(u8), + /// } + /// + /// impl fmt::Display for Error { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// match self { + /// Error::Indivisible(_) => write!(f, "could not divide input by three"), + /// Error::Remainder(remainder) => write!( + /// f, + /// "input is not divisible by three, remainder = {}", + /// remainder + /// ), + /// } + /// } + /// } + /// + /// impl std::error::Error for Error { + /// fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + /// match self { + /// Error::Indivisible(source) => Some(source), + /// _ => None, + /// } + /// } + /// } + /// + /// fn divisible_by_3(input: &str) -> Result<(), Error> { + /// input + /// .parse::() + /// .map_err(Error::Indivisible) + /// .map(|v| v % 3) + /// .and_then(|remainder| { + /// if remainder == 0 { + /// Ok(()) + /// } else { + /// Err(Error::Remainder(remainder as u8)) + /// } + /// }) + /// } + /// ``` + #[clippy::version = "1.48.0"] + pub MAP_ERR_IGNORE, + restriction, + "`map_err` should not ignore the original error" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2651,6 +2752,7 @@ impl_lint_pass!(Methods => [ GET_FIRST, MANUAL_OK_OR, MAP_CLONE, + MAP_ERR_IGNORE, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2982,6 +3084,8 @@ impl Methods { (name @ ("map" | "map_err"), [m_arg]) => { if name == "map" { map_clone::check(cx, expr, recv, m_arg, self.msrv); + } else { + map_err_ignore::check(cx, expr, m_arg); } if let Some((name, [recv2, args @ ..], span2)) = method_call(recv) { match (name, args) { From 508cf6bdbc9d4d97503f2603f86ec4b3aa1db26a Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 19:57:58 -0400 Subject: [PATCH 3783/5092] Move `MutMutexLock` into `Methods` lint pass --- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_style.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/mod.rs | 41 +++++++++++++ clippy_lints/src/methods/mut_mutex_lock.rs | 30 ++++++++++ clippy_lints/src/mut_mutex_lock.rs | 70 ---------------------- 7 files changed, 74 insertions(+), 75 deletions(-) create mode 100644 clippy_lints/src/methods/mut_mutex_lock.rs delete mode 100644 clippy_lints/src/mut_mutex_lock.rs diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index c496fd289bb8..1151cd42e59f 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -182,6 +182,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::MAP_COLLECT_RESULT_UNIT), LintId::of(methods::MAP_FLATTEN), LintId::of(methods::MAP_IDENTITY), + LintId::of(methods::MUT_MUTEX_LOCK), LintId::of(methods::NEEDLESS_OPTION_AS_DEREF), LintId::of(methods::NEEDLESS_OPTION_TAKE), LintId::of(methods::NEEDLESS_SPLITN), @@ -226,7 +227,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(misc_early::ZERO_PREFIXED_LITERAL), LintId::of(mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION), LintId::of(mut_key::MUTABLE_KEY_TYPE), - LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK), LintId::of(mut_reference::UNNECESSARY_MUT_PASSED), LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE), LintId::of(needless_bool::BOOL_COMPARISON), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 67fb0d50931a..2ae93b497377 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -329,6 +329,7 @@ store.register_lints(&[ methods::MAP_FLATTEN, methods::MAP_IDENTITY, methods::MAP_UNWRAP_OR, + methods::MUT_MUTEX_LOCK, methods::NAIVE_BYTECOUNT, methods::NEEDLESS_OPTION_AS_DEREF, methods::NEEDLESS_OPTION_TAKE, @@ -389,7 +390,6 @@ store.register_lints(&[ module_style::SELF_NAMED_MODULE_FILES, mut_key::MUTABLE_KEY_TYPE, mut_mut::MUT_MUT, - mut_mutex_lock::MUT_MUTEX_LOCK, mut_reference::UNNECESSARY_MUT_PASSED, mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL, mutex_atomic::MUTEX_ATOMIC, diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs index 52bf019c82e9..d34aadd1d377 100644 --- a/clippy_lints/src/lib.register_style.rs +++ b/clippy_lints/src/lib.register_style.rs @@ -70,6 +70,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(methods::MANUAL_SATURATING_ARITHMETIC), LintId::of(methods::MAP_CLONE), LintId::of(methods::MAP_COLLECT_RESULT_UNIT), + LintId::of(methods::MUT_MUTEX_LOCK), LintId::of(methods::NEW_RET_NO_SELF), LintId::of(methods::OBFUSCATED_IF_ELSE), LintId::of(methods::OK_EXPECT), @@ -89,7 +90,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT), LintId::of(misc_early::MIXED_CASE_HEX_LITERALS), LintId::of(misc_early::REDUNDANT_PATTERN), - LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK), LintId::of(mut_reference::UNNECESSARY_MUT_PASSED), LintId::of(needless_late_init::NEEDLESS_LATE_INIT), LintId::of(needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 179d630089fd..9f6ea1266d51 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -291,7 +291,6 @@ mod mixed_read_write_in_expression; mod module_style; mod mut_key; mod mut_mut; -mod mut_mutex_lock; mod mut_reference; mod mutable_debug_assertion; mod mutex_atomic; @@ -815,7 +814,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(if_let_mutex::IfLetMutex)); store.register_late_pass(|| Box::new(if_not_else::IfNotElse)); store.register_late_pass(|| Box::new(equatable_if_let::PatternEquality)); - store.register_late_pass(|| Box::new(mut_mutex_lock::MutMutexLock)); store.register_late_pass(|| Box::new(manual_async_fn::ManualAsyncFn)); store.register_late_pass(|| Box::new(vec_resize_to_zero::VecResizeToZero)); store.register_late_pass(|| Box::new(panic_in_result_fn::PanicInResultFn)); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e327bdcf578a..6ad32ae09d7b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -51,6 +51,7 @@ mod map_err_ignore; mod map_flatten; mod map_identity; mod map_unwrap_or; +mod mut_mutex_lock; mod needless_option_as_deref; mod needless_option_take; mod no_effect_replace; @@ -2642,6 +2643,42 @@ declare_clippy_lint! { "`map_err` should not ignore the original error" } +declare_clippy_lint! { + /// ### What it does + /// Checks for `&mut Mutex::lock` calls + /// + /// ### Why is this bad? + /// `Mutex::lock` is less efficient than + /// calling `Mutex::get_mut`. In addition you also have a statically + /// guarantee that the mutex isn't locked, instead of just a runtime + /// guarantee. + /// + /// ### Example + /// ```rust + /// use std::sync::{Arc, Mutex}; + /// + /// let mut value_rc = Arc::new(Mutex::new(42_u8)); + /// let value_mutex = Arc::get_mut(&mut value_rc).unwrap(); + /// + /// let mut value = value_mutex.lock().unwrap(); + /// *value += 1; + /// ``` + /// Use instead: + /// ```rust + /// use std::sync::{Arc, Mutex}; + /// + /// let mut value_rc = Arc::new(Mutex::new(42_u8)); + /// let value_mutex = Arc::get_mut(&mut value_rc).unwrap(); + /// + /// let value = value_mutex.get_mut().unwrap(); + /// *value += 1; + /// ``` + #[clippy::version = "1.49.0"] + pub MUT_MUTEX_LOCK, + style, + "`&mut Mutex::lock` does unnecessary locking" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2753,6 +2790,7 @@ impl_lint_pass!(Methods => [ MANUAL_OK_OR, MAP_CLONE, MAP_ERR_IGNORE, + MUT_MUTEX_LOCK, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3081,6 +3119,9 @@ impl Methods { } } }, + ("lock", []) => { + mut_mutex_lock::check(cx, expr, recv, span); + }, (name @ ("map" | "map_err"), [m_arg]) => { if name == "map" { map_clone::check(cx, expr, recv, m_arg, self.msrv); diff --git a/clippy_lints/src/methods/mut_mutex_lock.rs b/clippy_lints/src/methods/mut_mutex_lock.rs new file mode 100644 index 000000000000..bd8458a222e2 --- /dev/null +++ b/clippy_lints/src/methods/mut_mutex_lock.rs @@ -0,0 +1,30 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::ty::is_type_diagnostic_item; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{Expr, Mutability}; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::{sym, Span}; + +use super::MUT_MUTEX_LOCK; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>, recv: &'tcx Expr<'tcx>, name_span: Span) { + if_chain! { + if let ty::Ref(_, _, Mutability::Mut) = cx.typeck_results().expr_ty(recv).kind(); + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(ex.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(method_id); + if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Mutex); + then { + span_lint_and_sugg( + cx, + MUT_MUTEX_LOCK, + name_span, + "calling `&mut Mutex::lock` unnecessarily locks an exclusive (mutable) reference", + "change this to", + "get_mut".to_owned(), + Applicability::MaybeIncorrect, + ); + } + } +} diff --git a/clippy_lints/src/mut_mutex_lock.rs b/clippy_lints/src/mut_mutex_lock.rs deleted file mode 100644 index b7f981faa2d4..000000000000 --- a/clippy_lints/src/mut_mutex_lock.rs +++ /dev/null @@ -1,70 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::ty::is_type_diagnostic_item; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, Mutability}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; - -declare_clippy_lint! { - /// ### What it does - /// Checks for `&mut Mutex::lock` calls - /// - /// ### Why is this bad? - /// `Mutex::lock` is less efficient than - /// calling `Mutex::get_mut`. In addition you also have a statically - /// guarantee that the mutex isn't locked, instead of just a runtime - /// guarantee. - /// - /// ### Example - /// ```rust - /// use std::sync::{Arc, Mutex}; - /// - /// let mut value_rc = Arc::new(Mutex::new(42_u8)); - /// let value_mutex = Arc::get_mut(&mut value_rc).unwrap(); - /// - /// let mut value = value_mutex.lock().unwrap(); - /// *value += 1; - /// ``` - /// Use instead: - /// ```rust - /// use std::sync::{Arc, Mutex}; - /// - /// let mut value_rc = Arc::new(Mutex::new(42_u8)); - /// let value_mutex = Arc::get_mut(&mut value_rc).unwrap(); - /// - /// let value = value_mutex.get_mut().unwrap(); - /// *value += 1; - /// ``` - #[clippy::version = "1.49.0"] - pub MUT_MUTEX_LOCK, - style, - "`&mut Mutex::lock` does unnecessary locking" -} - -declare_lint_pass!(MutMutexLock => [MUT_MUTEX_LOCK]); - -impl<'tcx> LateLintPass<'tcx> for MutMutexLock { - fn check_expr(&mut self, cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>) { - if_chain! { - if let ExprKind::MethodCall(path, [self_arg, ..], _) = &ex.kind; - if path.ident.name == sym!(lock); - let ty = cx.typeck_results().expr_ty(self_arg); - if let ty::Ref(_, inner_ty, Mutability::Mut) = ty.kind(); - if is_type_diagnostic_item(cx, *inner_ty, sym::Mutex); - then { - span_lint_and_sugg( - cx, - MUT_MUTEX_LOCK, - path.ident.span, - "calling `&mut Mutex::lock` unnecessarily locks an exclusive (mutable) reference", - "change this to", - "get_mut".to_owned(), - Applicability::MaybeIncorrect, - ); - } - } - } -} From 0cc01cef304838cf4911d2e0e8dee7842a4b645b Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 20:09:55 -0400 Subject: [PATCH 3784/5092] Move `OpenOptions` into `Methods` lint pass --- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_correctness.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/mod.rs | 26 +++++++++++ .../src/{ => methods}/open_options.rs | 44 +++++-------------- 6 files changed, 39 insertions(+), 39 deletions(-) rename clippy_lints/src/{ => methods}/open_options.rs (80%) diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 1151cd42e59f..9f4d5b728a40 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -187,6 +187,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::NEEDLESS_OPTION_TAKE), LintId::of(methods::NEEDLESS_SPLITN), LintId::of(methods::NEW_RET_NO_SELF), + LintId::of(methods::NONSENSICAL_OPEN_OPTIONS), LintId::of(methods::NO_EFFECT_REPLACE), LintId::of(methods::OBFUSCATED_IF_ELSE), LintId::of(methods::OK_EXPECT), @@ -246,7 +247,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), LintId::of(octal_escapes::OCTAL_ESCAPES), - LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS), LintId::of(operators::ABSURD_EXTREME_COMPARISONS), LintId::of(operators::ASSIGN_OP_PATTERN), LintId::of(operators::BAD_BIT_MASK), diff --git a/clippy_lints/src/lib.register_correctness.rs b/clippy_lints/src/lib.register_correctness.rs index 006275d1383f..8ba39cc973e4 100644 --- a/clippy_lints/src/lib.register_correctness.rs +++ b/clippy_lints/src/lib.register_correctness.rs @@ -39,12 +39,12 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT), LintId::of(methods::CLONE_DOUBLE_REF), LintId::of(methods::ITERATOR_STEP_BY_ZERO), + LintId::of(methods::NONSENSICAL_OPEN_OPTIONS), LintId::of(methods::SUSPICIOUS_SPLITN), LintId::of(methods::UNINIT_ASSUMED_INIT), LintId::of(methods::ZST_OFFSET), LintId::of(minmax::MIN_MAX), LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), - LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS), LintId::of(operators::ABSURD_EXTREME_COMPARISONS), LintId::of(operators::BAD_BIT_MASK), LintId::of(operators::CMP_NAN), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 2ae93b497377..cf58d1bc5180 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -335,6 +335,7 @@ store.register_lints(&[ methods::NEEDLESS_OPTION_TAKE, methods::NEEDLESS_SPLITN, methods::NEW_RET_NO_SELF, + methods::NONSENSICAL_OPEN_OPTIONS, methods::NO_EFFECT_REPLACE, methods::OBFUSCATED_IF_ELSE, methods::OK_EXPECT, @@ -421,7 +422,6 @@ store.register_lints(&[ nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES, octal_escapes::OCTAL_ESCAPES, only_used_in_recursion::ONLY_USED_IN_RECURSION, - open_options::NONSENSICAL_OPEN_OPTIONS, operators::ABSURD_EXTREME_COMPARISONS, operators::ARITHMETIC, operators::ASSIGN_OP_PATTERN, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 9f6ea1266d51..0d2cc07504a2 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -315,7 +315,6 @@ mod non_send_fields_in_send_ty; mod nonstandard_macro_braces; mod octal_escapes; mod only_used_in_recursion; -mod open_options; mod operators; mod option_env_unwrap; mod option_if_let_else; @@ -641,7 +640,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(lifetimes::Lifetimes)); store.register_late_pass(|| Box::new(entry::HashMapPass)); store.register_late_pass(|| Box::new(minmax::MinMaxPass)); - store.register_late_pass(|| Box::new(open_options::OpenOptions)); store.register_late_pass(|| Box::new(zero_div_zero::ZeroDiv)); store.register_late_pass(|| Box::new(mutex_atomic::Mutex)); store.register_late_pass(|| Box::new(needless_update::NeedlessUpdate)); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 6ad32ae09d7b..3532aa17afdd 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -57,6 +57,7 @@ mod needless_option_take; mod no_effect_replace; mod obfuscated_if_else; mod ok_expect; +mod open_options; mod option_as_ref_deref; mod option_map_or_none; mod option_map_unwrap_or; @@ -2679,6 +2680,27 @@ declare_clippy_lint! { "`&mut Mutex::lock` does unnecessary locking" } +declare_clippy_lint! { + /// ### What it does + /// Checks for duplicate open options as well as combinations + /// that make no sense. + /// + /// ### Why is this bad? + /// In the best case, the code will be harder to read than + /// necessary. I don't know the worst case. + /// + /// ### Example + /// ```rust + /// use std::fs::OpenOptions; + /// + /// OpenOptions::new().read(true).truncate(true); + /// ``` + #[clippy::version = "pre 1.29.0"] + pub NONSENSICAL_OPEN_OPTIONS, + correctness, + "nonsensical combination of options for opening a file" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2791,6 +2813,7 @@ impl_lint_pass!(Methods => [ MAP_CLONE, MAP_ERR_IGNORE, MUT_MUTEX_LOCK, + NONSENSICAL_OPEN_OPTIONS, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3168,6 +3191,9 @@ impl Methods { _ => iter_nth_zero::check(cx, expr, recv, n_arg), }, ("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"), + ("open", [_]) => { + open_options::check(cx, expr, recv); + }, ("or_else", [arg]) => { if !bind_instead_of_map::ResultOrElseErrInfo::check(cx, expr, recv, arg) { unnecessary_lazy_eval::check(cx, expr, recv, arg, "or"); diff --git a/clippy_lints/src/open_options.rs b/clippy_lints/src/methods/open_options.rs similarity index 80% rename from clippy_lints/src/open_options.rs rename to clippy_lints/src/methods/open_options.rs index 5a0b5042018b..c3112823e346 100644 --- a/clippy_lints/src/open_options.rs +++ b/clippy_lints/src/methods/open_options.rs @@ -3,43 +3,19 @@ use clippy_utils::paths; use clippy_utils::ty::match_type; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_lint::LateContext; use rustc_span::source_map::{Span, Spanned}; -declare_clippy_lint! { - /// ### What it does - /// Checks for duplicate open options as well as combinations - /// that make no sense. - /// - /// ### Why is this bad? - /// In the best case, the code will be harder to read than - /// necessary. I don't know the worst case. - /// - /// ### Example - /// ```rust - /// use std::fs::OpenOptions; - /// - /// OpenOptions::new().read(true).truncate(true); - /// ``` - #[clippy::version = "pre 1.29.0"] - pub NONSENSICAL_OPEN_OPTIONS, - correctness, - "nonsensical combination of options for opening a file" -} +use super::NONSENSICAL_OPEN_OPTIONS; -declare_lint_pass!(OpenOptions => [NONSENSICAL_OPEN_OPTIONS]); - -impl<'tcx> LateLintPass<'tcx> for OpenOptions { - fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if let ExprKind::MethodCall(path, [self_arg, ..], _) = &e.kind { - let obj_ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); - if path.ident.name == sym!(open) && match_type(cx, obj_ty, &paths::OPEN_OPTIONS) { - let mut options = Vec::new(); - get_open_options(cx, self_arg, &mut options); - check_open_options(cx, &options, e.span); - } - } +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) + && let Some(impl_id) = cx.tcx.impl_of_method(method_id) + && match_type(cx, cx.tcx.type_of(impl_id), &paths::OPEN_OPTIONS) + { + let mut options = Vec::new(); + get_open_options(cx, recv, &mut options); + check_open_options(cx, &options, e.span); } } From 226f135a033f48178ffaa629045664a54c23aa0e Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 20:27:36 -0400 Subject: [PATCH 3785/5092] Move `PathBufPushOverwrite` into `Methods` lint group --- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_nursery.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/mod.rs | 37 ++++++++++ .../src/methods/path_buf_push_overwrite.rs | 37 ++++++++++ clippy_lints/src/path_buf_push_overwrite.rs | 72 ------------------- 6 files changed, 76 insertions(+), 76 deletions(-) create mode 100644 clippy_lints/src/methods/path_buf_push_overwrite.rs delete mode 100644 clippy_lints/src/path_buf_push_overwrite.rs diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index cf58d1bc5180..5750f914ac54 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -344,6 +344,7 @@ store.register_lints(&[ methods::OPTION_MAP_OR_NONE, methods::OR_FUN_CALL, methods::OR_THEN_UNWRAP, + methods::PATH_BUF_PUSH_OVERWRITE, methods::RESULT_MAP_OR_INTO_OPTION, methods::SEARCH_IS_SOME, methods::SHOULD_IMPLEMENT_TRAIT, @@ -460,7 +461,6 @@ store.register_lints(&[ partialeq_to_none::PARTIALEQ_TO_NONE, pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE, pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF, - path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE, pattern_type_mismatch::PATTERN_TYPE_MISMATCH, precedence::PRECEDENCE, ptr::CMP_NULL, diff --git a/clippy_lints/src/lib.register_nursery.rs b/clippy_lints/src/lib.register_nursery.rs index d65901926553..dc50816452f3 100644 --- a/clippy_lints/src/lib.register_nursery.rs +++ b/clippy_lints/src/lib.register_nursery.rs @@ -17,6 +17,7 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(methods::ITER_ON_EMPTY_COLLECTIONS), LintId::of(methods::ITER_ON_SINGLE_ITEMS), LintId::of(methods::ITER_WITH_DRAIN), + LintId::of(methods::PATH_BUF_PUSH_OVERWRITE), LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN), LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), LintId::of(mutex_atomic::MUTEX_ATOMIC), @@ -25,7 +26,6 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES), LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION), LintId::of(option_if_let_else::OPTION_IF_LET_ELSE), - LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE), LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE), LintId::of(regex::TRIVIAL_REGEX), LintId::of(strings::STRING_LIT_AS_BYTES), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 0d2cc07504a2..44cfe0d00ec7 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -324,7 +324,6 @@ mod panic_unimplemented; mod partialeq_ne_impl; mod partialeq_to_none; mod pass_by_ref_or_value; -mod path_buf_push_overwrite; mod pattern_type_mismatch; mod precedence; mod ptr; @@ -727,7 +726,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(assertions_on_constants::AssertionsOnConstants)); store.register_late_pass(|| Box::new(assertions_on_result_states::AssertionsOnResultStates)); store.register_late_pass(|| Box::new(transmuting_null::TransmutingNull)); - store.register_late_pass(|| Box::new(path_buf_push_overwrite::PathBufPushOverwrite)); store.register_late_pass(|| Box::new(inherent_to_string::InherentToString)); let max_trait_bounds = conf.max_trait_bounds; store.register_late_pass(move || Box::new(trait_bounds::TraitBounds::new(max_trait_bounds))); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 3532aa17afdd..545cf7918af0 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -63,6 +63,7 @@ mod option_map_or_none; mod option_map_unwrap_or; mod or_fun_call; mod or_then_unwrap; +mod path_buf_push_overwrite; mod search_is_some; mod single_char_add_str; mod single_char_insert_string; @@ -2701,6 +2702,38 @@ declare_clippy_lint! { "nonsensical combination of options for opening a file" } +declare_clippy_lint! { + /// ### What it does + ///* Checks for [push](https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.push) + /// calls on `PathBuf` that can cause overwrites. + /// + /// ### Why is this bad? + /// Calling `push` with a root path at the start can overwrite the + /// previous defined path. + /// + /// ### Example + /// ```rust + /// use std::path::PathBuf; + /// + /// let mut x = PathBuf::from("/foo"); + /// x.push("/bar"); + /// assert_eq!(x, PathBuf::from("/bar")); + /// ``` + /// Could be written: + /// + /// ```rust + /// use std::path::PathBuf; + /// + /// let mut x = PathBuf::from("/foo"); + /// x.push("bar"); + /// assert_eq!(x, PathBuf::from("/foo/bar")); + /// ``` + #[clippy::version = "1.36.0"] + pub PATH_BUF_PUSH_OVERWRITE, + nursery, + "calling `push` with file system root on `PathBuf` can overwrite it" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2814,6 +2847,7 @@ impl_lint_pass!(Methods => [ MAP_ERR_IGNORE, MUT_MUTEX_LOCK, NONSENSICAL_OPEN_OPTIONS, + PATH_BUF_PUSH_OVERWRITE, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3199,6 +3233,9 @@ impl Methods { unnecessary_lazy_eval::check(cx, expr, recv, arg, "or"); } }, + ("push", [arg]) => { + path_buf_push_overwrite::check(cx, expr, arg); + }, ("splitn" | "rsplitn", [count_arg, pat_arg]) => { if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) { suspicious_splitn::check(cx, name, expr, recv, count); diff --git a/clippy_lints/src/methods/path_buf_push_overwrite.rs b/clippy_lints/src/methods/path_buf_push_overwrite.rs new file mode 100644 index 000000000000..0cc28c0dcb3d --- /dev/null +++ b/clippy_lints/src/methods/path_buf_push_overwrite.rs @@ -0,0 +1,37 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::ty::is_type_diagnostic_item; +use if_chain::if_chain; +use rustc_ast::ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::symbol::sym; +use std::path::{Component, Path}; + +use super::PATH_BUF_PUSH_OVERWRITE; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) { + if_chain! { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(method_id); + if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::PathBuf); + if let ExprKind::Lit(ref lit) = arg.kind; + if let LitKind::Str(ref path_lit, _) = lit.node; + if let pushed_path = Path::new(path_lit.as_str()); + if let Some(pushed_path_lit) = pushed_path.to_str(); + if pushed_path.has_root(); + if let Some(root) = pushed_path.components().next(); + if root == Component::RootDir; + then { + span_lint_and_sugg( + cx, + PATH_BUF_PUSH_OVERWRITE, + lit.span, + "calling `push` with '/' or '\\' (file system root) will overwrite the previous path definition", + "try", + format!("\"{}\"", pushed_path_lit.trim_start_matches(|c| c == '/' || c == '\\')), + Applicability::MachineApplicable, + ); + } + } +} diff --git a/clippy_lints/src/path_buf_push_overwrite.rs b/clippy_lints/src/path_buf_push_overwrite.rs deleted file mode 100644 index bc6a918f7035..000000000000 --- a/clippy_lints/src/path_buf_push_overwrite.rs +++ /dev/null @@ -1,72 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::ty::is_type_diagnostic_item; -use if_chain::if_chain; -use rustc_ast::ast::LitKind; -use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::symbol::sym; -use std::path::{Component, Path}; - -declare_clippy_lint! { - /// ### What it does - ///* Checks for [push](https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.push) - /// calls on `PathBuf` that can cause overwrites. - /// - /// ### Why is this bad? - /// Calling `push` with a root path at the start can overwrite the - /// previous defined path. - /// - /// ### Example - /// ```rust - /// use std::path::PathBuf; - /// - /// let mut x = PathBuf::from("/foo"); - /// x.push("/bar"); - /// assert_eq!(x, PathBuf::from("/bar")); - /// ``` - /// Could be written: - /// - /// ```rust - /// use std::path::PathBuf; - /// - /// let mut x = PathBuf::from("/foo"); - /// x.push("bar"); - /// assert_eq!(x, PathBuf::from("/foo/bar")); - /// ``` - #[clippy::version = "1.36.0"] - pub PATH_BUF_PUSH_OVERWRITE, - nursery, - "calling `push` with file system root on `PathBuf` can overwrite it" -} - -declare_lint_pass!(PathBufPushOverwrite => [PATH_BUF_PUSH_OVERWRITE]); - -impl<'tcx> LateLintPass<'tcx> for PathBufPushOverwrite { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if_chain! { - if let ExprKind::MethodCall(path, [recv, get_index_arg], _) = expr.kind; - if path.ident.name == sym!(push); - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv).peel_refs(), sym::PathBuf); - if let ExprKind::Lit(ref lit) = get_index_arg.kind; - if let LitKind::Str(ref path_lit, _) = lit.node; - if let pushed_path = Path::new(path_lit.as_str()); - if let Some(pushed_path_lit) = pushed_path.to_str(); - if pushed_path.has_root(); - if let Some(root) = pushed_path.components().next(); - if root == Component::RootDir; - then { - span_lint_and_sugg( - cx, - PATH_BUF_PUSH_OVERWRITE, - lit.span, - "calling `push` with '/' or '\\' (file system root) will overwrite the previous path definition", - "try", - format!("\"{}\"", pushed_path_lit.trim_start_matches(|c| c == '/' || c == '\\')), - Applicability::MachineApplicable, - ); - } - } - } -} From fd5376194a4b74021ef01b7f2c96898ea204b75d Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 20:39:57 -0400 Subject: [PATCH 3786/5092] Move `range_zip_with_len` into `Methods` lint pass --- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_complexity.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/methods/mod.rs | 34 +++++++++ .../src/methods/range_zip_with_len.rs | 34 +++++++++ clippy_lints/src/ranges.rs | 73 ++----------------- 6 files changed, 77 insertions(+), 70 deletions(-) create mode 100644 clippy_lints/src/methods/range_zip_with_len.rs diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 9f4d5b728a40..d2c8c44b14f4 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -196,6 +196,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::OPTION_MAP_OR_NONE), LintId::of(methods::OR_FUN_CALL), LintId::of(methods::OR_THEN_UNWRAP), + LintId::of(methods::RANGE_ZIP_WITH_LEN), LintId::of(methods::RESULT_MAP_OR_INTO_OPTION), LintId::of(methods::SEARCH_IS_SOME), LintId::of(methods::SHOULD_IMPLEMENT_TRAIT), @@ -276,7 +277,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST), LintId::of(question_mark::QUESTION_MARK), LintId::of(ranges::MANUAL_RANGE_CONTAINS), - LintId::of(ranges::RANGE_ZIP_WITH_LEN), LintId::of(ranges::REVERSED_EMPTY_RANGES), LintId::of(rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT), LintId::of(read_zero_byte_vec::READ_ZERO_BYTE_VEC), diff --git a/clippy_lints/src/lib.register_complexity.rs b/clippy_lints/src/lib.register_complexity.rs index 324b380317f6..f77483de4e4b 100644 --- a/clippy_lints/src/lib.register_complexity.rs +++ b/clippy_lints/src/lib.register_complexity.rs @@ -51,6 +51,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(methods::OPTION_AS_REF_DEREF), LintId::of(methods::OPTION_FILTER_MAP), LintId::of(methods::OR_THEN_UNWRAP), + LintId::of(methods::RANGE_ZIP_WITH_LEN), LintId::of(methods::SEARCH_IS_SOME), LintId::of(methods::SKIP_WHILE_NEXT), LintId::of(methods::UNNECESSARY_FILTER_MAP), @@ -76,7 +77,6 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL), LintId::of(precedence::PRECEDENCE), LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST), - LintId::of(ranges::RANGE_ZIP_WITH_LEN), LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL), LintId::of(redundant_slicing::REDUNDANT_SLICING), LintId::of(reference::DEREF_ADDROF), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 5750f914ac54..2e48e3449552 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -345,6 +345,7 @@ store.register_lints(&[ methods::OR_FUN_CALL, methods::OR_THEN_UNWRAP, methods::PATH_BUF_PUSH_OVERWRITE, + methods::RANGE_ZIP_WITH_LEN, methods::RESULT_MAP_OR_INTO_OPTION, methods::SEARCH_IS_SOME, methods::SHOULD_IMPLEMENT_TRAIT, @@ -473,7 +474,6 @@ store.register_lints(&[ ranges::MANUAL_RANGE_CONTAINS, ranges::RANGE_MINUS_ONE, ranges::RANGE_PLUS_ONE, - ranges::RANGE_ZIP_WITH_LEN, ranges::REVERSED_EMPTY_RANGES, rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT, read_zero_byte_vec::READ_ZERO_BYTE_VEC, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 545cf7918af0..4a7681172969 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -64,6 +64,7 @@ mod option_map_unwrap_or; mod or_fun_call; mod or_then_unwrap; mod path_buf_push_overwrite; +mod range_zip_with_len; mod search_is_some; mod single_char_add_str; mod single_char_insert_string; @@ -2734,6 +2735,31 @@ declare_clippy_lint! { "calling `push` with file system root on `PathBuf` can overwrite it" } +declare_clippy_lint! { + /// ### What it does + /// Checks for zipping a collection with the range of + /// `0.._.len()`. + /// + /// ### Why is this bad? + /// The code is better expressed with `.enumerate()`. + /// + /// ### Example + /// ```rust + /// # let x = vec![1]; + /// let _ = x.iter().zip(0..x.len()); + /// ``` + /// + /// Use instead: + /// ```rust + /// # let x = vec![1]; + /// let _ = x.iter().enumerate(); + /// ``` + #[clippy::version = "pre 1.29.0"] + pub RANGE_ZIP_WITH_LEN, + complexity, + "zipping iterator with a range when `enumerate()` would do" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2848,6 +2874,7 @@ impl_lint_pass!(Methods => [ MUT_MUTEX_LOCK, NONSENSICAL_OPEN_OPTIONS, PATH_BUF_PUSH_OVERWRITE, + RANGE_ZIP_WITH_LEN, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3304,6 +3331,13 @@ impl Methods { ("replace" | "replacen", [arg1, arg2] | [arg1, arg2, _]) => { no_effect_replace::check(cx, expr, arg1, arg2); }, + ("zip", [arg]) => { + if let ExprKind::MethodCall(name, [iter_recv], _) = recv.kind + && name.ident.name == sym::iter + { + range_zip_with_len::check(cx, expr, iter_recv, arg); + } + }, _ => {}, } } diff --git a/clippy_lints/src/methods/range_zip_with_len.rs b/clippy_lints/src/methods/range_zip_with_len.rs new file mode 100644 index 000000000000..00a2a0d14d11 --- /dev/null +++ b/clippy_lints/src/methods/range_zip_with_len.rs @@ -0,0 +1,34 @@ +use clippy_utils::diagnostics::span_lint; +use clippy_utils::source::snippet; +use clippy_utils::{higher, SpanlessEq}; +use clippy_utils::{is_integer_const, is_trait_method}; +use if_chain::if_chain; +use rustc_hir::{Expr, ExprKind, QPath}; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::RANGE_ZIP_WITH_LEN; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, zip_arg: &'tcx Expr<'_>) { + if_chain! { + if is_trait_method(cx, expr, sym::Iterator); + // range expression in `.zip()` call: `0..x.len()` + if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg); + if is_integer_const(cx, start, 0); + // `.len()` call + if let ExprKind::MethodCall(len_path, [len_recv], _) = end.kind; + if len_path.ident.name == sym::len; + // `.iter()` and `.len()` called on same `Path` + if let ExprKind::Path(QPath::Resolved(_, iter_path)) = recv.kind; + if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_recv.kind; + if SpanlessEq::new(cx).eq_path_segments(iter_path.segments, len_path.segments); + then { + span_lint(cx, + RANGE_ZIP_WITH_LEN, + expr.span, + &format!("it is more idiomatic to use `{}.iter().enumerate()`", + snippet(cx, recv.span, "_")) + ); + } + } +} diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index fbf842c339e4..490f345d2970 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -1,46 +1,20 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::higher; use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::{get_parent_expr, in_constant, is_integer_const, meets_msrv, msrvs, path_to_local}; -use clippy_utils::{higher, SpanlessEq}; use if_chain::if_chain; use rustc_ast::ast::RangeLimits; use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind, HirId, PathSegment, QPath}; +use rustc_hir::{BinOpKind, Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::{Span, Spanned}; -use rustc_span::sym; use std::cmp::Ordering; -declare_clippy_lint! { - /// ### What it does - /// Checks for zipping a collection with the range of - /// `0.._.len()`. - /// - /// ### Why is this bad? - /// The code is better expressed with `.enumerate()`. - /// - /// ### Example - /// ```rust - /// # let x = vec![1]; - /// let _ = x.iter().zip(0..x.len()); - /// ``` - /// - /// Use instead: - /// ```rust - /// # let x = vec![1]; - /// let _ = x.iter().enumerate(); - /// ``` - #[clippy::version = "pre 1.29.0"] - pub RANGE_ZIP_WITH_LEN, - complexity, - "zipping iterator with a range when `enumerate()` would do" -} - declare_clippy_lint! { /// ### What it does /// Checks for exclusive ranges where 1 is added to the @@ -198,7 +172,6 @@ impl Ranges { } impl_lint_pass!(Ranges => [ - RANGE_ZIP_WITH_LEN, RANGE_PLUS_ONE, RANGE_MINUS_ONE, REVERSED_EMPTY_RANGES, @@ -207,16 +180,10 @@ impl_lint_pass!(Ranges => [ impl<'tcx> LateLintPass<'tcx> for Ranges { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - match expr.kind { - ExprKind::MethodCall(path, args, _) => { - check_range_zip_with_len(cx, path, args, expr.span); - }, - ExprKind::Binary(ref op, l, r) => { - if meets_msrv(self.msrv, msrvs::RANGE_CONTAINS) { - check_possible_range_contains(cx, op.node, l, r, expr, expr.span); - } - }, - _ => {}, + if let ExprKind::Binary(ref op, l, r) = expr.kind { + if meets_msrv(self.msrv, msrvs::RANGE_CONTAINS) { + check_possible_range_contains(cx, op.node, l, r, expr, expr.span); + } } check_exclusive_range_plus_one(cx, expr); @@ -380,34 +347,6 @@ fn check_range_bounds<'a>(cx: &'a LateContext<'_>, ex: &'a Expr<'_>) -> Option, path: &PathSegment<'_>, args: &[Expr<'_>], span: Span) { - if_chain! { - if path.ident.as_str() == "zip"; - if let [iter, zip_arg] = args; - // `.iter()` call - if let ExprKind::MethodCall(iter_path, [iter_caller, ..], _) = iter.kind; - if iter_path.ident.name == sym::iter; - // range expression in `.zip()` call: `0..x.len()` - if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg); - if is_integer_const(cx, start, 0); - // `.len()` call - if let ExprKind::MethodCall(len_path, [len_caller], _) = end.kind; - if len_path.ident.name == sym::len; - // `.iter()` and `.len()` called on same `Path` - if let ExprKind::Path(QPath::Resolved(_, iter_path)) = iter_caller.kind; - if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_caller.kind; - if SpanlessEq::new(cx).eq_path_segments(iter_path.segments, len_path.segments); - then { - span_lint(cx, - RANGE_ZIP_WITH_LEN, - span, - &format!("it is more idiomatic to use `{}.iter().enumerate()`", - snippet(cx, iter_caller.span, "_")) - ); - } - } -} - // exclusive range plus one: `x..(y+1)` fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { From 06d752e28dcc4b343f9d437e59d7ebbedff3fde8 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 20:49:03 -0400 Subject: [PATCH 3787/5092] Move `RepeatOnce` into `Methods` lint pass --- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_complexity.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/mod.rs | 37 +++++++++ clippy_lints/src/methods/repeat_once.rs | 52 ++++++++++++ clippy_lints/src/repeat_once.rs | 89 --------------------- 7 files changed, 92 insertions(+), 94 deletions(-) create mode 100644 clippy_lints/src/methods/repeat_once.rs delete mode 100644 clippy_lints/src/repeat_once.rs diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index d2c8c44b14f4..812a89d33e53 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -197,6 +197,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::OR_FUN_CALL), LintId::of(methods::OR_THEN_UNWRAP), LintId::of(methods::RANGE_ZIP_WITH_LEN), + LintId::of(methods::REPEAT_ONCE), LintId::of(methods::RESULT_MAP_OR_INTO_OPTION), LintId::of(methods::SEARCH_IS_SOME), LintId::of(methods::SHOULD_IMPLEMENT_TRAIT), @@ -287,7 +288,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), LintId::of(reference::DEREF_ADDROF), LintId::of(regex::INVALID_REGEX), - LintId::of(repeat_once::REPEAT_ONCE), LintId::of(returns::LET_AND_RETURN), LintId::of(returns::NEEDLESS_RETURN), LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS), diff --git a/clippy_lints/src/lib.register_complexity.rs b/clippy_lints/src/lib.register_complexity.rs index f77483de4e4b..f79105f4960f 100644 --- a/clippy_lints/src/lib.register_complexity.rs +++ b/clippy_lints/src/lib.register_complexity.rs @@ -52,6 +52,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(methods::OPTION_FILTER_MAP), LintId::of(methods::OR_THEN_UNWRAP), LintId::of(methods::RANGE_ZIP_WITH_LEN), + LintId::of(methods::REPEAT_ONCE), LintId::of(methods::SEARCH_IS_SOME), LintId::of(methods::SKIP_WHILE_NEXT), LintId::of(methods::UNNECESSARY_FILTER_MAP), @@ -80,7 +81,6 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL), LintId::of(redundant_slicing::REDUNDANT_SLICING), LintId::of(reference::DEREF_ADDROF), - LintId::of(repeat_once::REPEAT_ONCE), LintId::of(strings::STRING_FROM_UTF8_AS_BYTES), LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS), LintId::of(swap::MANUAL_SWAP), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 2e48e3449552..659f0288d174 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -346,6 +346,7 @@ store.register_lints(&[ methods::OR_THEN_UNWRAP, methods::PATH_BUF_PUSH_OVERWRITE, methods::RANGE_ZIP_WITH_LEN, + methods::REPEAT_ONCE, methods::RESULT_MAP_OR_INTO_OPTION, methods::SEARCH_IS_SOME, methods::SHOULD_IMPLEMENT_TRAIT, @@ -489,7 +490,6 @@ store.register_lints(&[ reference::DEREF_ADDROF, regex::INVALID_REGEX, regex::TRIVIAL_REGEX, - repeat_once::REPEAT_ONCE, return_self_not_must_use::RETURN_SELF_NOT_MUST_USE, returns::LET_AND_RETURN, returns::NEEDLESS_RETURN, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 44cfe0d00ec7..40c77ede9ad3 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -343,7 +343,6 @@ mod redundant_static_lifetimes; mod ref_option_ref; mod reference; mod regex; -mod repeat_once; mod return_self_not_must_use; mod returns; mod same_name_method; @@ -824,7 +823,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(macro_use::MacroUseImports::default())); store.register_late_pass(|| Box::new(pattern_type_mismatch::PatternTypeMismatch)); store.register_late_pass(|| Box::new(stable_sort_primitive::StableSortPrimitive)); - store.register_late_pass(|| Box::new(repeat_once::RepeatOnce)); store.register_late_pass(|| Box::new(unwrap_in_result::UnwrapInResult)); store.register_late_pass(|| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned)); store.register_late_pass(|| Box::new(async_yields_async::AsyncYieldsAsync)); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 4a7681172969..bbd6f56c5eae 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -65,6 +65,7 @@ mod or_fun_call; mod or_then_unwrap; mod path_buf_push_overwrite; mod range_zip_with_len; +mod repeat_once; mod search_is_some; mod single_char_add_str; mod single_char_insert_string; @@ -2760,6 +2761,38 @@ declare_clippy_lint! { "zipping iterator with a range when `enumerate()` would do" } +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `.repeat(1)` and suggest the following method for each types. + /// - `.to_string()` for `str` + /// - `.clone()` for `String` + /// - `.to_vec()` for `slice` + /// + /// The lint will evaluate constant expressions and values as arguments of `.repeat(..)` and emit a message if + /// they are equivalent to `1`. (Related discussion in [rust-clippy#7306](https://github.com/rust-lang/rust-clippy/issues/7306)) + /// + /// ### Why is this bad? + /// For example, `String.repeat(1)` is equivalent to `.clone()`. If cloning + /// the string is the intention behind this, `clone()` should be used. + /// + /// ### Example + /// ```rust + /// fn main() { + /// let x = String::from("hello world").repeat(1); + /// } + /// ``` + /// Use instead: + /// ```rust + /// fn main() { + /// let x = String::from("hello world").clone(); + /// } + /// ``` + #[clippy::version = "1.47.0"] + pub REPEAT_ONCE, + complexity, + "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` " +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2875,6 +2908,7 @@ impl_lint_pass!(Methods => [ NONSENSICAL_OPEN_OPTIONS, PATH_BUF_PUSH_OVERWRITE, RANGE_ZIP_WITH_LEN, + REPEAT_ONCE, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3263,6 +3297,9 @@ impl Methods { ("push", [arg]) => { path_buf_push_overwrite::check(cx, expr, arg); }, + ("repeat", [arg]) => { + repeat_once::check(cx, expr, recv, arg); + }, ("splitn" | "rsplitn", [count_arg, pat_arg]) => { if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) { suspicious_splitn::check(cx, name, expr, recv, count); diff --git a/clippy_lints/src/methods/repeat_once.rs b/clippy_lints/src/methods/repeat_once.rs new file mode 100644 index 000000000000..0a14f9216ab3 --- /dev/null +++ b/clippy_lints/src/methods/repeat_once.rs @@ -0,0 +1,52 @@ +use clippy_utils::consts::{constant_context, Constant}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_diagnostic_item; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::REPEAT_ONCE; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + recv: &'tcx Expr<'_>, + repeat_arg: &'tcx Expr<'_>, +) { + if constant_context(cx, cx.typeck_results()).expr(repeat_arg) == Some(Constant::Int(1)) { + let ty = cx.typeck_results().expr_ty(recv).peel_refs(); + if ty.is_str() { + span_lint_and_sugg( + cx, + REPEAT_ONCE, + expr.span, + "calling `repeat(1)` on str", + "consider using `.to_string()` instead", + format!("{}.to_string()", snippet(cx, recv.span, r#""...""#)), + Applicability::MachineApplicable, + ); + } else if ty.builtin_index().is_some() { + span_lint_and_sugg( + cx, + REPEAT_ONCE, + expr.span, + "calling `repeat(1)` on slice", + "consider using `.to_vec()` instead", + format!("{}.to_vec()", snippet(cx, recv.span, r#""...""#)), + Applicability::MachineApplicable, + ); + } else if is_type_diagnostic_item(cx, ty, sym::String) { + span_lint_and_sugg( + cx, + REPEAT_ONCE, + expr.span, + "calling `repeat(1)` on a string literal", + "consider using `.clone()` instead", + format!("{}.clone()", snippet(cx, recv.span, r#""...""#)), + Applicability::MachineApplicable, + ); + } + } +} diff --git a/clippy_lints/src/repeat_once.rs b/clippy_lints/src/repeat_once.rs deleted file mode 100644 index 898c70ace66f..000000000000 --- a/clippy_lints/src/repeat_once.rs +++ /dev/null @@ -1,89 +0,0 @@ -use clippy_utils::consts::{constant_context, Constant}; -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet; -use clippy_utils::ty::is_type_diagnostic_item; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; - -declare_clippy_lint! { - /// ### What it does - /// Checks for usage of `.repeat(1)` and suggest the following method for each types. - /// - `.to_string()` for `str` - /// - `.clone()` for `String` - /// - `.to_vec()` for `slice` - /// - /// The lint will evaluate constant expressions and values as arguments of `.repeat(..)` and emit a message if - /// they are equivalent to `1`. (Related discussion in [rust-clippy#7306](https://github.com/rust-lang/rust-clippy/issues/7306)) - /// - /// ### Why is this bad? - /// For example, `String.repeat(1)` is equivalent to `.clone()`. If cloning - /// the string is the intention behind this, `clone()` should be used. - /// - /// ### Example - /// ```rust - /// fn main() { - /// let x = String::from("hello world").repeat(1); - /// } - /// ``` - /// Use instead: - /// ```rust - /// fn main() { - /// let x = String::from("hello world").clone(); - /// } - /// ``` - #[clippy::version = "1.47.0"] - pub REPEAT_ONCE, - complexity, - "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` " -} - -declare_lint_pass!(RepeatOnce => [REPEAT_ONCE]); - -impl<'tcx> LateLintPass<'tcx> for RepeatOnce { - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) { - if_chain! { - if let ExprKind::MethodCall(path, [receiver, count], _) = &expr.kind; - if path.ident.name == sym!(repeat); - if constant_context(cx, cx.typeck_results()).expr(count) == Some(Constant::Int(1)); - if !receiver.span.from_expansion(); - then { - let ty = cx.typeck_results().expr_ty(receiver).peel_refs(); - if ty.is_str() { - span_lint_and_sugg( - cx, - REPEAT_ONCE, - expr.span, - "calling `repeat(1)` on str", - "consider using `.to_string()` instead", - format!("{}.to_string()", snippet(cx, receiver.span, r#""...""#)), - Applicability::MachineApplicable, - ); - } else if ty.builtin_index().is_some() { - span_lint_and_sugg( - cx, - REPEAT_ONCE, - expr.span, - "calling `repeat(1)` on slice", - "consider using `.to_vec()` instead", - format!("{}.to_vec()", snippet(cx, receiver.span, r#""...""#)), - Applicability::MachineApplicable, - ); - } else if is_type_diagnostic_item(cx, ty, sym::String) { - span_lint_and_sugg( - cx, - REPEAT_ONCE, - expr.span, - "calling `repeat(1)` on a string literal", - "consider using `.clone()` instead", - format!("{}.clone()", snippet(cx, receiver.span, r#""...""#)), - Applicability::MachineApplicable, - ); - } - } - } - } -} From e834855950701dae9657e7c0dbde195f85a96bf3 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 21:07:29 -0400 Subject: [PATCH 3788/5092] Move `StableSortPrimitive` to `Methods` lint pass --- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_pedantic.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/mod.rs | 43 ++++++ .../src/methods/stable_sort_primitive.rs | 31 ++++ clippy_lints/src/stable_sort_primitive.rs | 144 ------------------ 6 files changed, 76 insertions(+), 148 deletions(-) create mode 100644 clippy_lints/src/methods/stable_sort_primitive.rs delete mode 100644 clippy_lints/src/stable_sort_primitive.rs diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 659f0288d174..e8c796b4e9b6 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -353,6 +353,7 @@ store.register_lints(&[ methods::SINGLE_CHAR_ADD_STR, methods::SINGLE_CHAR_PATTERN, methods::SKIP_WHILE_NEXT, + methods::STABLE_SORT_PRIMITIVE, methods::STRING_EXTEND_CHARS, methods::SUSPICIOUS_MAP, methods::SUSPICIOUS_SPLITN, @@ -504,7 +505,6 @@ store.register_lints(&[ single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS, size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT, slow_vector_initialization::SLOW_VECTOR_INITIALIZATION, - stable_sort_primitive::STABLE_SORT_PRIMITIVE, std_instead_of_core::ALLOC_INSTEAD_OF_CORE, std_instead_of_core::STD_INSTEAD_OF_ALLOC, std_instead_of_core::STD_INSTEAD_OF_CORE, diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index 5c04a331d0a7..13474127e8d7 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -64,6 +64,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(methods::MANUAL_OK_OR), LintId::of(methods::MAP_UNWRAP_OR), LintId::of(methods::NAIVE_BYTECOUNT), + LintId::of(methods::STABLE_SORT_PRIMITIVE), LintId::of(methods::UNNECESSARY_JOIN), LintId::of(misc::USED_UNDERSCORE_BINDING), LintId::of(mismatching_type_param_order::MISMATCHING_TYPE_PARAM_ORDER), @@ -85,7 +86,6 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(ref_option_ref::REF_OPTION_REF), LintId::of(return_self_not_must_use::RETURN_SELF_NOT_MUST_USE), LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED), - LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE), LintId::of(strings::STRING_ADD_ASSIGN), LintId::of(transmute::TRANSMUTE_PTR_TO_PTR), LintId::of(types::LINKEDLIST), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 40c77ede9ad3..c424c373d322 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -354,7 +354,6 @@ mod single_char_lifetime_names; mod single_component_path_imports; mod size_of_in_element_count; mod slow_vector_initialization; -mod stable_sort_primitive; mod std_instead_of_core; mod strings; mod strlen_on_c_strings; @@ -822,7 +821,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(move || Box::new(nonstandard_macro_braces::MacroBraces::new(¯o_matcher))); store.register_late_pass(|| Box::new(macro_use::MacroUseImports::default())); store.register_late_pass(|| Box::new(pattern_type_mismatch::PatternTypeMismatch)); - store.register_late_pass(|| Box::new(stable_sort_primitive::StableSortPrimitive)); store.register_late_pass(|| Box::new(unwrap_in_result::UnwrapInResult)); store.register_late_pass(|| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned)); store.register_late_pass(|| Box::new(async_yields_async::AsyncYieldsAsync)); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index bbd6f56c5eae..a47081d8752c 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -72,6 +72,7 @@ mod single_char_insert_string; mod single_char_pattern; mod single_char_push_string; mod skip_while_next; +mod stable_sort_primitive; mod str_splitn; mod string_extend_chars; mod suspicious_map; @@ -2793,6 +2794,44 @@ declare_clippy_lint! { "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` " } +declare_clippy_lint! { + /// ### What it does + /// When sorting primitive values (integers, bools, chars, as well + /// as arrays, slices, and tuples of such items), it is typically better to + /// use an unstable sort than a stable sort. + /// + /// ### Why is this bad? + /// Typically, using a stable sort consumes more memory and cpu cycles. + /// Because values which compare equal are identical, preserving their + /// relative order (the guarantee that a stable sort provides) means + /// nothing, while the extra costs still apply. + /// + /// ### Known problems + /// + /// As pointed out in + /// [issue #8241](https://github.com/rust-lang/rust-clippy/issues/8241), + /// a stable sort can instead be significantly faster for certain scenarios + /// (eg. when a sorted vector is extended with new data and resorted). + /// + /// For more information and benchmarking results, please refer to the + /// issue linked above. + /// + /// ### Example + /// ```rust + /// let mut vec = vec![2, 1, 3]; + /// vec.sort(); + /// ``` + /// Use instead: + /// ```rust + /// let mut vec = vec![2, 1, 3]; + /// vec.sort_unstable(); + /// ``` + #[clippy::version = "1.47.0"] + pub STABLE_SORT_PRIMITIVE, + pedantic, + "use of sort() when sort_unstable() is equivalent" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2909,6 +2948,7 @@ impl_lint_pass!(Methods => [ PATH_BUF_PUSH_OVERWRITE, RANGE_ZIP_WITH_LEN, REPEAT_ONCE, + STABLE_SORT_PRIMITIVE, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3300,6 +3340,9 @@ impl Methods { ("repeat", [arg]) => { repeat_once::check(cx, expr, recv, arg); }, + ("sort", []) => { + stable_sort_primitive::check(cx, expr, recv); + }, ("splitn" | "rsplitn", [count_arg, pat_arg]) => { if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) { suspicious_splitn::check(cx, name, expr, recv, count); diff --git a/clippy_lints/src/methods/stable_sort_primitive.rs b/clippy_lints/src/methods/stable_sort_primitive.rs new file mode 100644 index 000000000000..91951c65bb30 --- /dev/null +++ b/clippy_lints/src/methods/stable_sort_primitive.rs @@ -0,0 +1,31 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_slice_of_primitives; +use clippy_utils::source::snippet_with_context; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; + +use super::STABLE_SORT_PRIMITIVE; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) + && let Some(impl_id) = cx.tcx.impl_of_method(method_id) + && cx.tcx.type_of(impl_id).is_slice() + && let Some(slice_type) = is_slice_of_primitives(cx, recv) + { + span_lint_and_then( + cx, + STABLE_SORT_PRIMITIVE, + e.span, + &format!("used `sort` on primitive type `{}`", slice_type), + |diag| { + let mut app = Applicability::MachineApplicable; + let recv_snip = snippet_with_context(cx, recv.span, e.span.ctxt(), "..", &mut app).0; + diag.span_suggestion(e.span, "try", format!("{}.sort_unstable()", recv_snip), app); + diag.note( + "an unstable sort typically performs faster without any observable difference for this data type", + ); + }, + ); + } +} diff --git a/clippy_lints/src/stable_sort_primitive.rs b/clippy_lints/src/stable_sort_primitive.rs deleted file mode 100644 index 6d54935f81ab..000000000000 --- a/clippy_lints/src/stable_sort_primitive.rs +++ /dev/null @@ -1,144 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::{is_slice_of_primitives, sugg::Sugg}; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -declare_clippy_lint! { - /// ### What it does - /// When sorting primitive values (integers, bools, chars, as well - /// as arrays, slices, and tuples of such items), it is typically better to - /// use an unstable sort than a stable sort. - /// - /// ### Why is this bad? - /// Typically, using a stable sort consumes more memory and cpu cycles. - /// Because values which compare equal are identical, preserving their - /// relative order (the guarantee that a stable sort provides) means - /// nothing, while the extra costs still apply. - /// - /// ### Known problems - /// - /// As pointed out in - /// [issue #8241](https://github.com/rust-lang/rust-clippy/issues/8241), - /// a stable sort can instead be significantly faster for certain scenarios - /// (eg. when a sorted vector is extended with new data and resorted). - /// - /// For more information and benchmarking results, please refer to the - /// issue linked above. - /// - /// ### Example - /// ```rust - /// let mut vec = vec![2, 1, 3]; - /// vec.sort(); - /// ``` - /// Use instead: - /// ```rust - /// let mut vec = vec![2, 1, 3]; - /// vec.sort_unstable(); - /// ``` - #[clippy::version = "1.47.0"] - pub STABLE_SORT_PRIMITIVE, - pedantic, - "use of sort() when sort_unstable() is equivalent" -} - -declare_lint_pass!(StableSortPrimitive => [STABLE_SORT_PRIMITIVE]); - -/// The three "kinds" of sorts -enum SortingKind { - Vanilla, - /* The other kinds of lint are currently commented out because they - * can map distinct values to equal ones. If the key function is - * provably one-to-one, or if the Cmp function conserves equality, - * then they could be linted on, but I don't know if we can check - * for that. */ - - /* ByKey, - * ByCmp, */ -} -impl SortingKind { - /// The name of the stable version of this kind of sort - fn stable_name(&self) -> &str { - match self { - SortingKind::Vanilla => "sort", - /* SortingKind::ByKey => "sort_by_key", - * SortingKind::ByCmp => "sort_by", */ - } - } - /// The name of the unstable version of this kind of sort - fn unstable_name(&self) -> &str { - match self { - SortingKind::Vanilla => "sort_unstable", - /* SortingKind::ByKey => "sort_unstable_by_key", - * SortingKind::ByCmp => "sort_unstable_by", */ - } - } - /// Takes the name of a function call and returns the kind of sort - /// that corresponds to that function name (or None if it isn't) - fn from_stable_name(name: &str) -> Option { - match name { - "sort" => Some(SortingKind::Vanilla), - // "sort_by" => Some(SortingKind::ByCmp), - // "sort_by_key" => Some(SortingKind::ByKey), - _ => None, - } - } -} - -/// A detected instance of this lint -struct LintDetection { - slice_name: String, - method: SortingKind, - method_args: String, - slice_type: String, -} - -fn detect_stable_sort_primitive(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { - if_chain! { - if let ExprKind::MethodCall(method_name, [slice, args @ ..], _) = &expr.kind; - if let Some(method) = SortingKind::from_stable_name(method_name.ident.name.as_str()); - if let Some(slice_type) = is_slice_of_primitives(cx, slice); - then { - let args_str = args.iter().map(|arg| Sugg::hir(cx, arg, "..").to_string()).collect::>().join(", "); - Some(LintDetection { slice_name: Sugg::hir(cx, slice, "..").to_string(), method, method_args: args_str, slice_type }) - } else { - None - } - } -} - -impl LateLintPass<'_> for StableSortPrimitive { - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if let Some(detection) = detect_stable_sort_primitive(cx, expr) { - span_lint_and_then( - cx, - STABLE_SORT_PRIMITIVE, - expr.span, - format!( - "used `{}` on primitive type `{}`", - detection.method.stable_name(), - detection.slice_type, - ) - .as_str(), - |diag| { - diag.span_suggestion( - expr.span, - "try", - format!( - "{}.{}({})", - detection.slice_name, - detection.method.unstable_name(), - detection.method_args, - ), - Applicability::MachineApplicable, - ); - diag.note( - "an unstable sort typically performs faster without any observable difference for this data type", - ); - }, - ); - } - } -} From e213b6ee35faec133333e07f962958fbbfe12679 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 21:36:40 -0400 Subject: [PATCH 3789/5092] Move `TransmutingNull` into `Transmute` lint pass --- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_correctness.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/transmute/mod.rs | 25 ++++++ .../src/transmute/transmuting_null.rs | 61 +++++++++++++ clippy_lints/src/transmuting_null.rs | 89 ------------------- 7 files changed, 89 insertions(+), 94 deletions(-) create mode 100644 clippy_lints/src/transmute/transmuting_null.rs delete mode 100644 clippy_lints/src/transmuting_null.rs diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 812a89d33e53..aad6a1af200c 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -315,10 +315,10 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT), LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES), LintId::of(transmute::TRANSMUTE_PTR_TO_REF), + LintId::of(transmute::TRANSMUTING_NULL), LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE), LintId::of(transmute::USELESS_TRANSMUTE), LintId::of(transmute::WRONG_TRANSMUTE), - LintId::of(transmuting_null::TRANSMUTING_NULL), LintId::of(types::BORROWED_BOX), LintId::of(types::BOX_COLLECTION), LintId::of(types::REDUNDANT_ALLOCATION), diff --git a/clippy_lints/src/lib.register_correctness.rs b/clippy_lints/src/lib.register_correctness.rs index 8ba39cc973e4..9d69d4acc90a 100644 --- a/clippy_lints/src/lib.register_correctness.rs +++ b/clippy_lints/src/lib.register_correctness.rs @@ -62,9 +62,9 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve LintId::of(serde_api::SERDE_API_MISUSE), LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), LintId::of(swap::ALMOST_SWAPPED), + LintId::of(transmute::TRANSMUTING_NULL), LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE), LintId::of(transmute::WRONG_TRANSMUTE), - LintId::of(transmuting_null::TRANSMUTING_NULL), LintId::of(unicode::INVISIBLE_CHARACTERS), LintId::of(uninit_vec::UNINIT_VEC), LintId::of(unit_hash::UNIT_HASH), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index e8c796b4e9b6..a2a810520703 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -540,10 +540,10 @@ store.register_lints(&[ transmute::TRANSMUTE_PTR_TO_PTR, transmute::TRANSMUTE_PTR_TO_REF, transmute::TRANSMUTE_UNDEFINED_REPR, + transmute::TRANSMUTING_NULL, transmute::UNSOUND_COLLECTION_TRANSMUTE, transmute::USELESS_TRANSMUTE, transmute::WRONG_TRANSMUTE, - transmuting_null::TRANSMUTING_NULL, types::BORROWED_BOX, types::BOX_COLLECTION, types::LINKEDLIST, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index c424c373d322..e0b6ded0b584 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -367,7 +367,6 @@ mod to_digit_is_some; mod trailing_empty_array; mod trait_bounds; mod transmute; -mod transmuting_null; mod types; mod undocumented_unsafe_blocks; mod unicode; @@ -723,7 +722,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || Box::new(unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api))); store.register_late_pass(|| Box::new(assertions_on_constants::AssertionsOnConstants)); store.register_late_pass(|| Box::new(assertions_on_result_states::AssertionsOnResultStates)); - store.register_late_pass(|| Box::new(transmuting_null::TransmutingNull)); store.register_late_pass(|| Box::new(inherent_to_string::InherentToString)); let max_trait_bounds = conf.max_trait_bounds; store.register_late_pass(move || Box::new(trait_bounds::TraitBounds::new(max_trait_bounds))); diff --git a/clippy_lints/src/transmute/mod.rs b/clippy_lints/src/transmute/mod.rs index 5f3e98144f42..424a6e9264e4 100644 --- a/clippy_lints/src/transmute/mod.rs +++ b/clippy_lints/src/transmute/mod.rs @@ -9,6 +9,7 @@ mod transmute_ptr_to_ref; mod transmute_ref_to_ref; mod transmute_undefined_repr; mod transmutes_expressible_as_ptr_casts; +mod transmuting_null; mod unsound_collection_transmute; mod useless_transmute; mod utils; @@ -386,6 +387,28 @@ declare_clippy_lint! { "transmute to or from a type with an undefined representation" } +declare_clippy_lint! { + /// ### What it does + /// Checks for transmute calls which would receive a null pointer. + /// + /// ### Why is this bad? + /// Transmuting a null pointer is undefined behavior. + /// + /// ### Known problems + /// Not all cases can be detected at the moment of this writing. + /// For example, variables which hold a null pointer and are then fed to a `transmute` + /// call, aren't detectable yet. + /// + /// ### Example + /// ```rust + /// let null_ref: &u64 = unsafe { std::mem::transmute(0 as *const u64) }; + /// ``` + #[clippy::version = "1.35.0"] + pub TRANSMUTING_NULL, + correctness, + "transmutes from a null pointer to a reference, which is undefined behavior" +} + pub struct Transmute { msrv: Option, } @@ -404,6 +427,7 @@ impl_lint_pass!(Transmute => [ UNSOUND_COLLECTION_TRANSMUTE, TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS, TRANSMUTE_UNDEFINED_REPR, + TRANSMUTING_NULL, ]); impl Transmute { #[must_use] @@ -436,6 +460,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { let linted = wrong_transmute::check(cx, e, from_ty, to_ty) | crosspointer_transmute::check(cx, e, from_ty, to_ty) + | transmuting_null::check(cx, e, arg, to_ty) | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, self.msrv) | transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context) | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context) diff --git a/clippy_lints/src/transmute/transmuting_null.rs b/clippy_lints/src/transmute/transmuting_null.rs new file mode 100644 index 000000000000..c4981124f396 --- /dev/null +++ b/clippy_lints/src/transmute/transmuting_null.rs @@ -0,0 +1,61 @@ +use clippy_utils::consts::{constant_context, Constant}; +use clippy_utils::diagnostics::span_lint; +use clippy_utils::is_expr_diagnostic_item; +use if_chain::if_chain; +use rustc_ast::LitKind; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_middle::ty::Ty; +use rustc_span::symbol::sym; + +use super::TRANSMUTING_NULL; + +const LINT_MSG: &str = "transmuting a known null pointer into a reference"; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'tcx Expr<'_>, to_ty: Ty<'tcx>) -> bool { + if !to_ty.is_ref() { + return false; + } + + // Catching transmute over constants that resolve to `null`. + let mut const_eval_context = constant_context(cx, cx.typeck_results()); + if_chain! { + if let ExprKind::Path(ref _qpath) = arg.kind; + if let Some(Constant::RawPtr(x)) = const_eval_context.expr(arg); + if x == 0; + then { + span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); + return true; + } + } + + // Catching: + // `std::mem::transmute(0 as *const i32)` + if_chain! { + if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind; + if let ExprKind::Lit(ref lit) = inner_expr.kind; + if let LitKind::Int(0, _) = lit.node; + then { + span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); + return true; + } + } + + // Catching: + // `std::mem::transmute(std::ptr::null::())` + if_chain! { + if let ExprKind::Call(func1, []) = arg.kind; + if is_expr_diagnostic_item(cx, func1, sym::ptr_null); + then { + span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); + return true; + } + } + + // FIXME: + // Also catch transmutations of variables which are known nulls. + // To do this, MIR const propagation seems to be the better tool. + // Whenever MIR const prop routines are more developed, this will + // become available. As of this writing (25/03/19) it is not yet. + false +} diff --git a/clippy_lints/src/transmuting_null.rs b/clippy_lints/src/transmuting_null.rs deleted file mode 100644 index 7939dfedc3a2..000000000000 --- a/clippy_lints/src/transmuting_null.rs +++ /dev/null @@ -1,89 +0,0 @@ -use clippy_utils::consts::{constant_context, Constant}; -use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_expr_diagnostic_item; -use if_chain::if_chain; -use rustc_ast::LitKind; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::symbol::sym; - -declare_clippy_lint! { - /// ### What it does - /// Checks for transmute calls which would receive a null pointer. - /// - /// ### Why is this bad? - /// Transmuting a null pointer is undefined behavior. - /// - /// ### Known problems - /// Not all cases can be detected at the moment of this writing. - /// For example, variables which hold a null pointer and are then fed to a `transmute` - /// call, aren't detectable yet. - /// - /// ### Example - /// ```rust - /// let null_ref: &u64 = unsafe { std::mem::transmute(0 as *const u64) }; - /// ``` - #[clippy::version = "1.35.0"] - pub TRANSMUTING_NULL, - correctness, - "transmutes from a null pointer to a reference, which is undefined behavior" -} - -declare_lint_pass!(TransmutingNull => [TRANSMUTING_NULL]); - -const LINT_MSG: &str = "transmuting a known null pointer into a reference"; - -impl<'tcx> LateLintPass<'tcx> for TransmutingNull { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if in_external_macro(cx.sess(), expr.span) { - return; - } - - if_chain! { - if let ExprKind::Call(func, [arg]) = expr.kind; - if is_expr_diagnostic_item(cx, func, sym::transmute); - - then { - // Catching transmute over constants that resolve to `null`. - let mut const_eval_context = constant_context(cx, cx.typeck_results()); - if_chain! { - if let ExprKind::Path(ref _qpath) = arg.kind; - if let Some(Constant::RawPtr(x)) = const_eval_context.expr(arg); - if x == 0; - then { - span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG) - } - } - - // Catching: - // `std::mem::transmute(0 as *const i32)` - if_chain! { - if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind; - if let ExprKind::Lit(ref lit) = inner_expr.kind; - if let LitKind::Int(0, _) = lit.node; - then { - span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG) - } - } - - // Catching: - // `std::mem::transmute(std::ptr::null::())` - if_chain! { - if let ExprKind::Call(func1, []) = arg.kind; - if is_expr_diagnostic_item(cx, func1, sym::ptr_null); - then { - span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG) - } - } - - // FIXME: - // Also catch transmutations of variables which are known nulls. - // To do this, MIR const propagation seems to be the better tool. - // Whenever MIR const prop routines are more developed, this will - // become available. As of this writing (25/03/19) it is not yet. - } - } - } -} From bb0584dfb425f6c1a8bef9faad9ee36f0bbc19fb Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 21:41:33 -0400 Subject: [PATCH 3790/5092] Move `UnitHash` into `Methods` lint pass --- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_correctness.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/mod.rs | 44 +++++++++++ clippy_lints/src/methods/unit_hash.rs | 29 ++++++++ clippy_lints/src/unit_hash.rs | 78 -------------------- 7 files changed, 76 insertions(+), 83 deletions(-) create mode 100644 clippy_lints/src/methods/unit_hash.rs delete mode 100644 clippy_lints/src/unit_hash.rs diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index aad6a1af200c..e51ce0fa2546 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -208,6 +208,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::SUSPICIOUS_MAP), LintId::of(methods::SUSPICIOUS_SPLITN), LintId::of(methods::UNINIT_ASSUMED_INIT), + LintId::of(methods::UNIT_HASH), LintId::of(methods::UNNECESSARY_FILTER_MAP), LintId::of(methods::UNNECESSARY_FIND_MAP), LintId::of(methods::UNNECESSARY_FOLD), @@ -326,7 +327,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(types::VEC_BOX), LintId::of(unicode::INVISIBLE_CHARACTERS), LintId::of(uninit_vec::UNINIT_VEC), - LintId::of(unit_hash::UNIT_HASH), LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), LintId::of(unit_types::LET_UNIT_VALUE), LintId::of(unit_types::UNIT_ARG), diff --git a/clippy_lints/src/lib.register_correctness.rs b/clippy_lints/src/lib.register_correctness.rs index 9d69d4acc90a..d30e69b2240a 100644 --- a/clippy_lints/src/lib.register_correctness.rs +++ b/clippy_lints/src/lib.register_correctness.rs @@ -42,6 +42,7 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve LintId::of(methods::NONSENSICAL_OPEN_OPTIONS), LintId::of(methods::SUSPICIOUS_SPLITN), LintId::of(methods::UNINIT_ASSUMED_INIT), + LintId::of(methods::UNIT_HASH), LintId::of(methods::ZST_OFFSET), LintId::of(minmax::MIN_MAX), LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), @@ -67,7 +68,6 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve LintId::of(transmute::WRONG_TRANSMUTE), LintId::of(unicode::INVISIBLE_CHARACTERS), LintId::of(uninit_vec::UNINIT_VEC), - LintId::of(unit_hash::UNIT_HASH), LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), LintId::of(unit_types::UNIT_CMP), LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index a2a810520703..8aa1810fbd59 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -358,6 +358,7 @@ store.register_lints(&[ methods::SUSPICIOUS_MAP, methods::SUSPICIOUS_SPLITN, methods::UNINIT_ASSUMED_INIT, + methods::UNIT_HASH, methods::UNNECESSARY_FILTER_MAP, methods::UNNECESSARY_FIND_MAP, methods::UNNECESSARY_FOLD, @@ -558,7 +559,6 @@ store.register_lints(&[ unicode::NON_ASCII_LITERAL, unicode::UNICODE_NOT_NFC, uninit_vec::UNINIT_VEC, - unit_hash::UNIT_HASH, unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD, unit_types::LET_UNIT_VALUE, unit_types::UNIT_ARG, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index e0b6ded0b584..71ba3f18da87 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -371,7 +371,6 @@ mod types; mod undocumented_unsafe_blocks; mod unicode; mod uninit_vec; -mod unit_hash; mod unit_return_expecting_ord; mod unit_types; mod unnamed_address; @@ -582,7 +581,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(blocks_in_if_conditions::BlocksInIfConditions)); store.register_late_pass(|| Box::new(unicode::Unicode)); store.register_late_pass(|| Box::new(uninit_vec::UninitVec)); - store.register_late_pass(|| Box::new(unit_hash::UnitHash)); store.register_late_pass(|| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd)); store.register_late_pass(|| Box::new(strings::StringAdd)); store.register_late_pass(|| Box::new(implicit_return::ImplicitReturn)); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a47081d8752c..ce10b64c9486 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -78,6 +78,7 @@ mod string_extend_chars; mod suspicious_map; mod suspicious_splitn; mod uninit_assumed_init; +mod unit_hash; mod unnecessary_filter_map; mod unnecessary_fold; mod unnecessary_iter_cloned; @@ -2832,6 +2833,45 @@ declare_clippy_lint! { "use of sort() when sort_unstable() is equivalent" } +declare_clippy_lint! { + /// ### What it does + /// Detects `().hash(_)`. + /// + /// ### Why is this bad? + /// Hashing a unit value doesn't do anything as the implementation of `Hash` for `()` is a no-op. + /// + /// ### Example + /// ```rust + /// # use std::hash::Hash; + /// # use std::collections::hash_map::DefaultHasher; + /// # enum Foo { Empty, WithValue(u8) } + /// # use Foo::*; + /// # let mut state = DefaultHasher::new(); + /// # let my_enum = Foo::Empty; + /// match my_enum { + /// Empty => ().hash(&mut state), + /// WithValue(x) => x.hash(&mut state), + /// } + /// ``` + /// Use instead: + /// ```rust + /// # use std::hash::Hash; + /// # use std::collections::hash_map::DefaultHasher; + /// # enum Foo { Empty, WithValue(u8) } + /// # use Foo::*; + /// # let mut state = DefaultHasher::new(); + /// # let my_enum = Foo::Empty; + /// match my_enum { + /// Empty => 0_u8.hash(&mut state), + /// WithValue(x) => x.hash(&mut state), + /// } + /// ``` + #[clippy::version = "1.58.0"] + pub UNIT_HASH, + correctness, + "hashing a unit value, which does nothing" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2949,6 +2989,7 @@ impl_lint_pass!(Methods => [ RANGE_ZIP_WITH_LEN, REPEAT_ONCE, STABLE_SORT_PRIMITIVE, + UNIT_HASH, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3258,6 +3299,9 @@ impl Methods { get_last_with_len::check(cx, expr, recv, arg); }, ("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"), + ("hash", [arg]) => { + unit_hash::check(cx, expr, recv, arg); + }, ("is_file", []) => filetype_is_file::check(cx, expr, recv), ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv), ("is_none", []) => check_is_some_is_none(cx, expr, recv, false), diff --git a/clippy_lints/src/methods/unit_hash.rs b/clippy_lints/src/methods/unit_hash.rs new file mode 100644 index 000000000000..3c7955bc4698 --- /dev/null +++ b/clippy_lints/src/methods/unit_hash.rs @@ -0,0 +1,29 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_trait_method; +use clippy_utils::source::snippet; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::UNIT_HASH; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) { + if is_trait_method(cx, expr, sym::Hash) && cx.typeck_results().expr_ty(recv).is_unit() { + span_lint_and_then( + cx, + UNIT_HASH, + expr.span, + "this call to `hash` on the unit type will do nothing", + |diag| { + diag.span_suggestion( + expr.span, + "remove the call to `hash` or consider using", + format!("0_u8.hash({})", snippet(cx, arg.span, ".."),), + Applicability::MaybeIncorrect, + ); + diag.note("the implementation of `Hash` for `()` is a no-op"); + }, + ); + } +} diff --git a/clippy_lints/src/unit_hash.rs b/clippy_lints/src/unit_hash.rs deleted file mode 100644 index 88ca0cb20a12..000000000000 --- a/clippy_lints/src/unit_hash.rs +++ /dev/null @@ -1,78 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet; -use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; - -declare_clippy_lint! { - /// ### What it does - /// Detects `().hash(_)`. - /// - /// ### Why is this bad? - /// Hashing a unit value doesn't do anything as the implementation of `Hash` for `()` is a no-op. - /// - /// ### Example - /// ```rust - /// # use std::hash::Hash; - /// # use std::collections::hash_map::DefaultHasher; - /// # enum Foo { Empty, WithValue(u8) } - /// # use Foo::*; - /// # let mut state = DefaultHasher::new(); - /// # let my_enum = Foo::Empty; - /// match my_enum { - /// Empty => ().hash(&mut state), - /// WithValue(x) => x.hash(&mut state), - /// } - /// ``` - /// Use instead: - /// ```rust - /// # use std::hash::Hash; - /// # use std::collections::hash_map::DefaultHasher; - /// # enum Foo { Empty, WithValue(u8) } - /// # use Foo::*; - /// # let mut state = DefaultHasher::new(); - /// # let my_enum = Foo::Empty; - /// match my_enum { - /// Empty => 0_u8.hash(&mut state), - /// WithValue(x) => x.hash(&mut state), - /// } - /// ``` - #[clippy::version = "1.58.0"] - pub UNIT_HASH, - correctness, - "hashing a unit value, which does nothing" -} -declare_lint_pass!(UnitHash => [UNIT_HASH]); - -impl<'tcx> LateLintPass<'tcx> for UnitHash { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if_chain! { - if let ExprKind::MethodCall(name_ident, args, _) = &expr.kind; - if name_ident.ident.name == sym::hash; - if let [recv, state_param] = args; - if cx.typeck_results().expr_ty(recv).is_unit(); - then { - span_lint_and_then( - cx, - UNIT_HASH, - expr.span, - "this call to `hash` on the unit type will do nothing", - |diag| { - diag.span_suggestion( - expr.span, - "remove the call to `hash` or consider using", - format!( - "0_u8.hash({})", - snippet(cx, state_param.span, ".."), - ), - Applicability::MaybeIncorrect, - ); - diag.note("the implementation of `Hash` for `()` is a no-op"); - } - ); - } - } - } -} From d8d4a135ea2bc460033c75d4a56d21ae977b9ae2 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 5 Jun 2022 23:22:58 -0400 Subject: [PATCH 3791/5092] Move `UnnecessarySortBy` into `Methods` lint pass --- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_complexity.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/mod.rs | 42 +++++ .../src/{ => methods}/unnecessary_sort_by.rs | 156 +++++++----------- 6 files changed, 106 insertions(+), 100 deletions(-) rename clippy_lints/src/{ => methods}/unnecessary_sort_by.rs (63%) diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index e51ce0fa2546..bb5b28662685 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -213,6 +213,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::UNNECESSARY_FIND_MAP), LintId::of(methods::UNNECESSARY_FOLD), LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS), + LintId::of(methods::UNNECESSARY_SORT_BY), LintId::of(methods::UNNECESSARY_TO_OWNED), LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT), LintId::of(methods::USELESS_ASREF), @@ -334,7 +335,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS), LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS), LintId::of(unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS), - LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY), LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), LintId::of(unused_io_amount::UNUSED_IO_AMOUNT), LintId::of(unused_unit::UNUSED_UNIT), diff --git a/clippy_lints/src/lib.register_complexity.rs b/clippy_lints/src/lib.register_complexity.rs index f79105f4960f..0f7433a79be3 100644 --- a/clippy_lints/src/lib.register_complexity.rs +++ b/clippy_lints/src/lib.register_complexity.rs @@ -57,6 +57,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(methods::SKIP_WHILE_NEXT), LintId::of(methods::UNNECESSARY_FILTER_MAP), LintId::of(methods::UNNECESSARY_FIND_MAP), + LintId::of(methods::UNNECESSARY_SORT_BY), LintId::of(methods::USELESS_ASREF), LintId::of(misc::SHORT_CIRCUIT_STATEMENT), LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN), @@ -99,7 +100,6 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(types::TYPE_COMPLEXITY), LintId::of(types::VEC_BOX), LintId::of(unit_types::UNIT_ARG), - LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY), LintId::of(unwrap::UNNECESSARY_UNWRAP), LintId::of(useless_conversion::USELESS_CONVERSION), LintId::of(zero_div_zero::ZERO_DIVIDED_BY_ZERO), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 8aa1810fbd59..f5497c6bd6bc 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -364,6 +364,7 @@ store.register_lints(&[ methods::UNNECESSARY_FOLD, methods::UNNECESSARY_JOIN, methods::UNNECESSARY_LAZY_EVALUATIONS, + methods::UNNECESSARY_SORT_BY, methods::UNNECESSARY_TO_OWNED, methods::UNWRAP_OR_ELSE_DEFAULT, methods::UNWRAP_USED, @@ -567,7 +568,6 @@ store.register_lints(&[ unnamed_address::VTABLE_ADDRESS_COMPARISONS, unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS, unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS, - unnecessary_sort_by::UNNECESSARY_SORT_BY, unnecessary_wraps::UNNECESSARY_WRAPS, unnested_or_patterns::UNNESTED_OR_PATTERNS, unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 71ba3f18da87..cfcd4e3d1419 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -376,7 +376,6 @@ mod unit_types; mod unnamed_address; mod unnecessary_owned_empty_strings; mod unnecessary_self_imports; -mod unnecessary_sort_by; mod unnecessary_wraps; mod unnested_or_patterns; mod unsafe_removed_from_name; @@ -716,7 +715,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(ptr_offset_with_cast::PtrOffsetWithCast)); store.register_late_pass(|| Box::new(redundant_clone::RedundantClone)); store.register_late_pass(|| Box::new(slow_vector_initialization::SlowVectorInit)); - store.register_late_pass(|| Box::new(unnecessary_sort_by::UnnecessarySortBy)); store.register_late_pass(move || Box::new(unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api))); store.register_late_pass(|| Box::new(assertions_on_constants::AssertionsOnConstants)); store.register_late_pass(|| Box::new(assertions_on_result_states::AssertionsOnResultStates)); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index ce10b64c9486..54a0275da963 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -84,6 +84,7 @@ mod unnecessary_fold; mod unnecessary_iter_cloned; mod unnecessary_join; mod unnecessary_lazy_eval; +mod unnecessary_sort_by; mod unnecessary_to_owned; mod unwrap_or_else_default; mod unwrap_used; @@ -2872,6 +2873,40 @@ declare_clippy_lint! { "hashing a unit value, which does nothing" } +declare_clippy_lint! { + /// ### What it does + /// Detects uses of `Vec::sort_by` passing in a closure + /// which compares the two arguments, either directly or indirectly. + /// + /// ### Why is this bad? + /// It is more clear to use `Vec::sort_by_key` (or `Vec::sort` if + /// possible) than to use `Vec::sort_by` and a more complicated + /// closure. + /// + /// ### Known problems + /// If the suggested `Vec::sort_by_key` uses Reverse and it isn't already + /// imported by a use statement, then it will need to be added manually. + /// + /// ### Example + /// ```rust + /// # struct A; + /// # impl A { fn foo(&self) {} } + /// # let mut vec: Vec = Vec::new(); + /// vec.sort_by(|a, b| a.foo().cmp(&b.foo())); + /// ``` + /// Use instead: + /// ```rust + /// # struct A; + /// # impl A { fn foo(&self) {} } + /// # let mut vec: Vec = Vec::new(); + /// vec.sort_by_key(|a| a.foo()); + /// ``` + #[clippy::version = "1.46.0"] + pub UNNECESSARY_SORT_BY, + complexity, + "Use of `Vec::sort_by` when `Vec::sort_by_key` or `Vec::sort` would be clearer" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2990,6 +3025,7 @@ impl_lint_pass!(Methods => [ REPEAT_ONCE, STABLE_SORT_PRIMITIVE, UNIT_HASH, + UNNECESSARY_SORT_BY, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3387,6 +3423,12 @@ impl Methods { ("sort", []) => { stable_sort_primitive::check(cx, expr, recv); }, + ("sort_by", [arg]) => { + unnecessary_sort_by::check(cx, expr, recv, arg, false); + }, + ("sort_unstable_by", [arg]) => { + unnecessary_sort_by::check(cx, expr, recv, arg, true); + }, ("splitn" | "rsplitn", [count_arg, pat_arg]) => { if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) { suspicious_splitn::check(cx, name, expr, recv, count); diff --git a/clippy_lints/src/unnecessary_sort_by.rs b/clippy_lints/src/methods/unnecessary_sort_by.rs similarity index 63% rename from clippy_lints/src/unnecessary_sort_by.rs rename to clippy_lints/src/methods/unnecessary_sort_by.rs index ea5aadbbca1c..1966990bd774 100644 --- a/clippy_lints/src/unnecessary_sort_by.rs +++ b/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -1,51 +1,17 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_trait_method; use clippy_utils::sugg::Sugg; -use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; +use clippy_utils::ty::implements_trait; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::LateContext; use rustc_middle::ty::{self, subst::GenericArgKind}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; use rustc_span::symbol::Ident; use std::iter; -declare_clippy_lint! { - /// ### What it does - /// Detects uses of `Vec::sort_by` passing in a closure - /// which compares the two arguments, either directly or indirectly. - /// - /// ### Why is this bad? - /// It is more clear to use `Vec::sort_by_key` (or `Vec::sort` if - /// possible) than to use `Vec::sort_by` and a more complicated - /// closure. - /// - /// ### Known problems - /// If the suggested `Vec::sort_by_key` uses Reverse and it isn't already - /// imported by a use statement, then it will need to be added manually. - /// - /// ### Example - /// ```rust - /// # struct A; - /// # impl A { fn foo(&self) {} } - /// # let mut vec: Vec = Vec::new(); - /// vec.sort_by(|a, b| a.foo().cmp(&b.foo())); - /// ``` - /// Use instead: - /// ```rust - /// # struct A; - /// # impl A { fn foo(&self) {} } - /// # let mut vec: Vec = Vec::new(); - /// vec.sort_by_key(|a| a.foo()); - /// ``` - #[clippy::version = "1.46.0"] - pub UNNECESSARY_SORT_BY, - complexity, - "Use of `Vec::sort_by` when `Vec::sort_by_key` or `Vec::sort` would be clearer" -} - -declare_lint_pass!(UnnecessarySortBy => [UNNECESSARY_SORT_BY]); +use super::UNNECESSARY_SORT_BY; enum LintTrigger { Sort(SortDetection), @@ -54,7 +20,6 @@ enum LintTrigger { struct SortDetection { vec_name: String, - unstable: bool, } struct SortByKeyDetection { @@ -62,7 +27,6 @@ struct SortByKeyDetection { closure_arg: String, closure_body: String, reverse: bool, - unstable: bool, } /// Detect if the two expressions are mirrored (identical, except one @@ -150,20 +114,20 @@ fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident } } -fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { +fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) -> Option { if_chain! { - if let ExprKind::MethodCall(name_ident, args, _) = &expr.kind; - if let name = name_ident.ident.name.to_ident_string(); - if name == "sort_by" || name == "sort_unstable_by"; - if let [vec, Expr { kind: ExprKind::Closure(Closure { body: closure_body_id, .. }), .. }] = args; - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(vec), sym::Vec); - if let closure_body = cx.tcx.hir().body(*closure_body_id); + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(method_id); + if cx.tcx.type_of(impl_id).is_slice(); + if let ExprKind::Closure(&Closure { body, .. }) = arg.kind; + if let closure_body = cx.tcx.hir().body(body); if let &[ Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..}, Param { pat: Pat { kind: PatKind::Binding(_, _, right_ident, _), .. }, .. } ] = &closure_body.params; - if let ExprKind::MethodCall(method_path, [ref left_expr, ref right_expr], _) = &closure_body.value.kind; + if let ExprKind::MethodCall(method_path, [left_expr, right_expr], _) = closure_body.value.kind; if method_path.ident.name == sym::cmp; + if is_trait_method(cx, &closure_body.value, sym::Ord); then { let (closure_body, closure_arg, reverse) = if mirrored_exprs( left_expr, @@ -177,19 +141,18 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { } else { return None; }; - let vec_name = Sugg::hir(cx, &args[0], "..").to_string(); - let unstable = name == "sort_unstable_by"; + let vec_name = Sugg::hir(cx, recv, "..").to_string(); if_chain! { - if let ExprKind::Path(QPath::Resolved(_, Path { - segments: [PathSegment { ident: left_name, .. }], .. - })) = &left_expr.kind; - if left_name == left_ident; - if cx.tcx.get_diagnostic_item(sym::Ord).map_or(false, |id| { - implements_trait(cx, cx.typeck_results().expr_ty(left_expr), id, &[]) - }); + if let ExprKind::Path(QPath::Resolved(_, Path { + segments: [PathSegment { ident: left_name, .. }], .. + })) = &left_expr.kind; + if left_name == left_ident; + if cx.tcx.get_diagnostic_item(sym::Ord).map_or(false, |id| { + implements_trait(cx, cx.typeck_results().expr_ty(left_expr), id, &[]) + }); then { - return Some(LintTrigger::Sort(SortDetection { vec_name, unstable })); + return Some(LintTrigger::Sort(SortDetection { vec_name })); } } @@ -199,7 +162,6 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { closure_arg, closure_body, reverse, - unstable, })); } } @@ -213,46 +175,50 @@ fn expr_borrows(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { matches!(ty.kind(), ty::Ref(..)) || ty.walk().any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_))) } -impl LateLintPass<'_> for UnnecessarySortBy { - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - match detect_lint(cx, expr) { - Some(LintTrigger::SortByKey(trigger)) => span_lint_and_sugg( - cx, - UNNECESSARY_SORT_BY, - expr.span, - "use Vec::sort_by_key here instead", - "try", - format!( - "{}.sort{}_by_key(|{}| {})", - trigger.vec_name, - if trigger.unstable { "_unstable" } else { "" }, - trigger.closure_arg, - if trigger.reverse { - format!("std::cmp::Reverse({})", trigger.closure_body) - } else { - trigger.closure_body.to_string() - }, - ), +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + recv: &'tcx Expr<'_>, + arg: &'tcx Expr<'_>, + is_unstable: bool, +) { + match detect_lint(cx, expr, recv, arg) { + Some(LintTrigger::SortByKey(trigger)) => span_lint_and_sugg( + cx, + UNNECESSARY_SORT_BY, + expr.span, + "use Vec::sort_by_key here instead", + "try", + format!( + "{}.sort{}_by_key(|{}| {})", + trigger.vec_name, + if is_unstable { "_unstable" } else { "" }, + trigger.closure_arg, if trigger.reverse { - Applicability::MaybeIncorrect + format!("std::cmp::Reverse({})", trigger.closure_body) } else { - Applicability::MachineApplicable + trigger.closure_body.to_string() }, ), - Some(LintTrigger::Sort(trigger)) => span_lint_and_sugg( - cx, - UNNECESSARY_SORT_BY, - expr.span, - "use Vec::sort here instead", - "try", - format!( - "{}.sort{}()", - trigger.vec_name, - if trigger.unstable { "_unstable" } else { "" }, - ), - Applicability::MachineApplicable, + if trigger.reverse { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + }, + ), + Some(LintTrigger::Sort(trigger)) => span_lint_and_sugg( + cx, + UNNECESSARY_SORT_BY, + expr.span, + "use Vec::sort here instead", + "try", + format!( + "{}.sort{}()", + trigger.vec_name, + if is_unstable { "_unstable" } else { "" }, ), - None => {}, - } + Applicability::MachineApplicable, + ), + None => {}, } } From 8acc4d2f1e255e0e97e48b7a285a7d6db4a03bd6 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Mon, 6 Jun 2022 11:17:38 -0400 Subject: [PATCH 3792/5092] Move `VecResizeToZero` into `Methods` lint pass --- clippy_lints/src/lib.register_all.rs | 2 +- clippy_lints/src/lib.register_correctness.rs | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/mod.rs | 27 ++++++++ .../src/methods/vec_resize_to_zero.rs | 45 +++++++++++++ clippy_lints/src/vec_resize_to_zero.rs | 64 ------------------- tests/ui/vec_resize_to_zero.rs | 12 ++-- tests/ui/vec_resize_to_zero.stderr | 10 +-- 9 files changed, 88 insertions(+), 78 deletions(-) create mode 100644 clippy_lints/src/methods/vec_resize_to_zero.rs delete mode 100644 clippy_lints/src/vec_resize_to_zero.rs diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index bb5b28662685..4128096b43ae 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -217,6 +217,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::UNNECESSARY_TO_OWNED), LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT), LintId::of(methods::USELESS_ASREF), + LintId::of(methods::VEC_RESIZE_TO_ZERO), LintId::of(methods::WRONG_SELF_CONVENTION), LintId::of(methods::ZST_OFFSET), LintId::of(minmax::MIN_MAX), @@ -344,7 +345,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(useless_conversion::USELESS_CONVERSION), LintId::of(vec::USELESS_VEC), LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH), - LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO), LintId::of(write::POSITIONAL_NAMED_FORMAT_PARAMETERS), LintId::of(write::PRINTLN_EMPTY_STRING), LintId::of(write::PRINT_LITERAL), diff --git a/clippy_lints/src/lib.register_correctness.rs b/clippy_lints/src/lib.register_correctness.rs index d30e69b2240a..bb94037ec2e7 100644 --- a/clippy_lints/src/lib.register_correctness.rs +++ b/clippy_lints/src/lib.register_correctness.rs @@ -43,6 +43,7 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve LintId::of(methods::SUSPICIOUS_SPLITN), LintId::of(methods::UNINIT_ASSUMED_INIT), LintId::of(methods::UNIT_HASH), + LintId::of(methods::VEC_RESIZE_TO_ZERO), LintId::of(methods::ZST_OFFSET), LintId::of(minmax::MIN_MAX), LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), @@ -74,5 +75,4 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS), LintId::of(unused_io_amount::UNUSED_IO_AMOUNT), LintId::of(unwrap::PANICKING_UNWRAP), - LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO), ]) diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index f5497c6bd6bc..1b275516dfce 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -369,6 +369,7 @@ store.register_lints(&[ methods::UNWRAP_OR_ELSE_DEFAULT, methods::UNWRAP_USED, methods::USELESS_ASREF, + methods::VEC_RESIZE_TO_ZERO, methods::WRONG_SELF_CONVENTION, methods::ZST_OFFSET, minmax::MIN_MAX, @@ -584,7 +585,6 @@ store.register_lints(&[ useless_conversion::USELESS_CONVERSION, vec::USELESS_VEC, vec_init_then_push::VEC_INIT_THEN_PUSH, - vec_resize_to_zero::VEC_RESIZE_TO_ZERO, verbose_file_reads::VERBOSE_FILE_READS, wildcard_imports::ENUM_GLOB_USE, wildcard_imports::WILDCARD_IMPORTS, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index cfcd4e3d1419..ff68fbd19643 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -391,7 +391,6 @@ mod use_self; mod useless_conversion; mod vec; mod vec_init_then_push; -mod vec_resize_to_zero; mod verbose_file_reads; mod wildcard_imports; mod write; @@ -803,7 +802,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(if_not_else::IfNotElse)); store.register_late_pass(|| Box::new(equatable_if_let::PatternEquality)); store.register_late_pass(|| Box::new(manual_async_fn::ManualAsyncFn)); - store.register_late_pass(|| Box::new(vec_resize_to_zero::VecResizeToZero)); store.register_late_pass(|| Box::new(panic_in_result_fn::PanicInResultFn)); let single_char_binding_names_threshold = conf.single_char_binding_names_threshold; store.register_early_pass(move || { diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 54a0275da963..1a225c9bc951 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -90,6 +90,7 @@ mod unwrap_or_else_default; mod unwrap_used; mod useless_asref; mod utils; +mod vec_resize_to_zero; mod wrong_self_convention; mod zst_offset; @@ -2907,6 +2908,28 @@ declare_clippy_lint! { "Use of `Vec::sort_by` when `Vec::sort_by_key` or `Vec::sort` would be clearer" } +declare_clippy_lint! { + /// ### What it does + /// Finds occurrences of `Vec::resize(0, an_int)` + /// + /// ### Why is this bad? + /// This is probably an argument inversion mistake. + /// + /// ### Example + /// ```rust + /// vec!(1, 2, 3, 4, 5).resize(0, 5) + /// ``` + /// + /// Use instead: + /// ```rust + /// vec!(1, 2, 3, 4, 5).clear() + /// ``` + #[clippy::version = "1.46.0"] + pub VEC_RESIZE_TO_ZERO, + correctness, + "emptying a vector with `resize(0, an_int)` instead of `clear()` is probably an argument inversion mistake" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -3026,6 +3049,7 @@ impl_lint_pass!(Methods => [ STABLE_SORT_PRIMITIVE, UNIT_HASH, UNNECESSARY_SORT_BY, + VEC_RESIZE_TO_ZERO, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3420,6 +3444,9 @@ impl Methods { ("repeat", [arg]) => { repeat_once::check(cx, expr, recv, arg); }, + ("resize", [count_arg, default_arg]) => { + vec_resize_to_zero::check(cx, expr, count_arg, default_arg, span); + }, ("sort", []) => { stable_sort_primitive::check(cx, expr, recv); }, diff --git a/clippy_lints/src/methods/vec_resize_to_zero.rs b/clippy_lints/src/methods/vec_resize_to_zero.rs new file mode 100644 index 000000000000..02d8364cb295 --- /dev/null +++ b/clippy_lints/src/methods/vec_resize_to_zero.rs @@ -0,0 +1,45 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::ty::is_type_diagnostic_item; +use if_chain::if_chain; +use rustc_ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::source_map::Spanned; +use rustc_span::{sym, Span}; + +use super::VEC_RESIZE_TO_ZERO; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + count_arg: &'tcx Expr<'_>, + default_arg: &'tcx Expr<'_>, + name_span: Span, +) { + if_chain! { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(method_id); + if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Vec); + if let ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = count_arg.kind; + if let ExprKind::Lit(Spanned { node: LitKind::Int(..), .. }) = default_arg.kind; + then { + let method_call_span = expr.span.with_lo(name_span.lo()); + span_lint_and_then( + cx, + VEC_RESIZE_TO_ZERO, + expr.span, + "emptying a vector with `resize`", + |db| { + db.help("the arguments may be inverted..."); + db.span_suggestion( + method_call_span, + "...or you can empty the vector with", + "clear()".to_string(), + Applicability::MaybeIncorrect, + ); + }, + ); + } + } +} diff --git a/clippy_lints/src/vec_resize_to_zero.rs b/clippy_lints/src/vec_resize_to_zero.rs deleted file mode 100644 index 0fee3e812d28..000000000000 --- a/clippy_lints/src/vec_resize_to_zero.rs +++ /dev/null @@ -1,64 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::{match_def_path, paths}; -use if_chain::if_chain; -use rustc_ast::LitKind; -use rustc_errors::Applicability; -use rustc_hir as hir; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Spanned; - -declare_clippy_lint! { - /// ### What it does - /// Finds occurrences of `Vec::resize(0, an_int)` - /// - /// ### Why is this bad? - /// This is probably an argument inversion mistake. - /// - /// ### Example - /// ```rust - /// vec!(1, 2, 3, 4, 5).resize(0, 5) - /// ``` - /// - /// Use instead: - /// ```rust - /// vec!(1, 2, 3, 4, 5).clear() - /// ``` - #[clippy::version = "1.46.0"] - pub VEC_RESIZE_TO_ZERO, - correctness, - "emptying a vector with `resize(0, an_int)` instead of `clear()` is probably an argument inversion mistake" -} - -declare_lint_pass!(VecResizeToZero => [VEC_RESIZE_TO_ZERO]); - -impl<'tcx> LateLintPass<'tcx> for VecResizeToZero { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if_chain! { - if let hir::ExprKind::MethodCall(path_segment, args, _) = expr.kind; - if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if match_def_path(cx, method_def_id, &paths::VEC_RESIZE) && args.len() == 3; - if let ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = args[1].kind; - if let ExprKind::Lit(Spanned { node: LitKind::Int(..), .. }) = args[2].kind; - then { - let method_call_span = expr.span.with_lo(path_segment.ident.span.lo()); - span_lint_and_then( - cx, - VEC_RESIZE_TO_ZERO, - expr.span, - "emptying a vector with `resize`", - |db| { - db.help("the arguments may be inverted..."); - db.span_suggestion( - method_call_span, - "...or you can empty the vector with", - "clear()".to_string(), - Applicability::MaybeIncorrect, - ); - }, - ); - } - } - } -} diff --git a/tests/ui/vec_resize_to_zero.rs b/tests/ui/vec_resize_to_zero.rs index 7ed27439ec6e..a8307e741cf1 100644 --- a/tests/ui/vec_resize_to_zero.rs +++ b/tests/ui/vec_resize_to_zero.rs @@ -1,15 +1,19 @@ #![warn(clippy::vec_resize_to_zero)] fn main() { + let mut v = vec![1, 2, 3, 4, 5]; + // applicable here - vec![1, 2, 3, 4, 5].resize(0, 5); + v.resize(0, 5); // not applicable - vec![1, 2, 3, 4, 5].resize(2, 5); + v.resize(2, 5); + + let mut v = vec!["foo", "bar", "baz"]; // applicable here, but only implemented for integer literals for now - vec!["foo", "bar", "baz"].resize(0, "bar"); + v.resize(0, "bar"); // not applicable - vec!["foo", "bar", "baz"].resize(2, "bar") + v.resize(2, "bar") } diff --git a/tests/ui/vec_resize_to_zero.stderr b/tests/ui/vec_resize_to_zero.stderr index feb846298c65..7428cf62d6c4 100644 --- a/tests/ui/vec_resize_to_zero.stderr +++ b/tests/ui/vec_resize_to_zero.stderr @@ -1,10 +1,10 @@ error: emptying a vector with `resize` - --> $DIR/vec_resize_to_zero.rs:5:5 + --> $DIR/vec_resize_to_zero.rs:7:5 | -LL | vec![1, 2, 3, 4, 5].resize(0, 5); - | ^^^^^^^^^^^^^^^^^^^^------------ - | | - | help: ...or you can empty the vector with: `clear()` +LL | v.resize(0, 5); + | ^^------------ + | | + | help: ...or you can empty the vector with: `clear()` | = note: `-D clippy::vec-resize-to-zero` implied by `-D warnings` = help: the arguments may be inverted... From d8808db006cf4fde950076f1112ca465bcaf72ef Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Mon, 6 Jun 2022 11:58:30 -0400 Subject: [PATCH 3793/5092] Move `VerboseFileReads` into `Methods` lint pass --- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_restriction.rs | 2 +- clippy_lints/src/lib.rs | 2 - clippy_lints/src/methods/mod.rs | 35 ++++++++ .../src/methods/verbose_file_reads.rs | 28 ++++++ clippy_lints/src/verbose_file_reads.rs | 88 ------------------- 6 files changed, 65 insertions(+), 92 deletions(-) create mode 100644 clippy_lints/src/methods/verbose_file_reads.rs delete mode 100644 clippy_lints/src/verbose_file_reads.rs diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 1b275516dfce..db475950086d 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -370,6 +370,7 @@ store.register_lints(&[ methods::UNWRAP_USED, methods::USELESS_ASREF, methods::VEC_RESIZE_TO_ZERO, + methods::VERBOSE_FILE_READS, methods::WRONG_SELF_CONVENTION, methods::ZST_OFFSET, minmax::MIN_MAX, @@ -585,7 +586,6 @@ store.register_lints(&[ useless_conversion::USELESS_CONVERSION, vec::USELESS_VEC, vec_init_then_push::VEC_INIT_THEN_PUSH, - verbose_file_reads::VERBOSE_FILE_READS, wildcard_imports::ENUM_GLOB_USE, wildcard_imports::WILDCARD_IMPORTS, write::POSITIONAL_NAMED_FORMAT_PARAMETERS, diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs index 7fc5eef5f8a6..dd1e1e1a8e33 100644 --- a/clippy_lints/src/lib.register_restriction.rs +++ b/clippy_lints/src/lib.register_restriction.rs @@ -40,6 +40,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(methods::GET_UNWRAP), LintId::of(methods::MAP_ERR_IGNORE), LintId::of(methods::UNWRAP_USED), + LintId::of(methods::VERBOSE_FILE_READS), LintId::of(misc_early::SEPARATED_LITERAL_SUFFIX), LintId::of(misc_early::UNNEEDED_FIELD_PATTERN), LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX), @@ -81,7 +82,6 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(unicode::NON_ASCII_LITERAL), LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS), LintId::of(unwrap_in_result::UNWRAP_IN_RESULT), - LintId::of(verbose_file_reads::VERBOSE_FILE_READS), LintId::of(write::PRINT_STDERR), LintId::of(write::PRINT_STDOUT), LintId::of(write::USE_DEBUG), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index ff68fbd19643..dbea55a04d62 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -391,7 +391,6 @@ mod use_self; mod useless_conversion; mod vec; mod vec_init_then_push; -mod verbose_file_reads; mod wildcard_imports; mod write; mod zero_div_zero; @@ -792,7 +791,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| Box::new(option_env_unwrap::OptionEnvUnwrap)); let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports; store.register_late_pass(move || Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports))); - store.register_late_pass(|| Box::new(verbose_file_reads::VerboseFileReads)); store.register_late_pass(|| Box::new(redundant_pub_crate::RedundantPubCrate::default())); store.register_late_pass(|| Box::new(unnamed_address::UnnamedAddress)); store.register_late_pass(move || Box::new(dereference::Dereferencing::new(msrv))); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 1a225c9bc951..1cfe8c4191ef 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -91,6 +91,7 @@ mod unwrap_used; mod useless_asref; mod utils; mod vec_resize_to_zero; +mod verbose_file_reads; mod wrong_self_convention; mod zst_offset; @@ -2930,6 +2931,33 @@ declare_clippy_lint! { "emptying a vector with `resize(0, an_int)` instead of `clear()` is probably an argument inversion mistake" } +declare_clippy_lint! { + /// ### What it does + /// Checks for use of File::read_to_end and File::read_to_string. + /// + /// ### Why is this bad? + /// `fs::{read, read_to_string}` provide the same functionality when `buf` is empty with fewer imports and no intermediate values. + /// See also: [fs::read docs](https://doc.rust-lang.org/std/fs/fn.read.html), [fs::read_to_string docs](https://doc.rust-lang.org/std/fs/fn.read_to_string.html) + /// + /// ### Example + /// ```rust,no_run + /// # use std::io::Read; + /// # use std::fs::File; + /// let mut f = File::open("foo.txt").unwrap(); + /// let mut bytes = Vec::new(); + /// f.read_to_end(&mut bytes).unwrap(); + /// ``` + /// Can be written more concisely as + /// ```rust,no_run + /// # use std::fs; + /// let mut bytes = fs::read("foo.txt").unwrap(); + /// ``` + #[clippy::version = "1.44.0"] + pub VERBOSE_FILE_READS, + restriction, + "use of `File::read_to_end` or `File::read_to_string`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -3050,6 +3078,7 @@ impl_lint_pass!(Methods => [ UNIT_HASH, UNNECESSARY_SORT_BY, VEC_RESIZE_TO_ZERO, + VERBOSE_FILE_READS, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3441,6 +3470,12 @@ impl Methods { ("push", [arg]) => { path_buf_push_overwrite::check(cx, expr, arg); }, + ("read_to_end", [_]) => { + verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_END_MSG); + }, + ("read_to_string", [_]) => { + verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_STRING_MSG); + }, ("repeat", [arg]) => { repeat_once::check(cx, expr, recv, arg); }, diff --git a/clippy_lints/src/methods/verbose_file_reads.rs b/clippy_lints/src/methods/verbose_file_reads.rs new file mode 100644 index 000000000000..2fe5ae9a9ad8 --- /dev/null +++ b/clippy_lints/src/methods/verbose_file_reads.rs @@ -0,0 +1,28 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_trait_method; +use clippy_utils::ty::is_type_diagnostic_item; +use rustc_hir::{Expr, ExprKind, QPath}; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::VERBOSE_FILE_READS; + +pub(super) const READ_TO_END_MSG: (&str, &str) = ("use of `File::read_to_end`", "consider using `fs::read` instead"); +pub(super) const READ_TO_STRING_MSG: (&str, &str) = ( + "use of `File::read_to_string`", + "consider using `fs::read_to_string` instead", +); + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + recv: &'tcx Expr<'_>, + (msg, help): (&str, &str), +) { + if is_trait_method(cx, expr, sym::IoRead) + && matches!(recv.kind, ExprKind::Path(QPath::Resolved(None, _))) + && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(recv).peel_refs(), sym::File) + { + span_lint_and_help(cx, VERBOSE_FILE_READS, expr.span, msg, None, help); + } +} diff --git a/clippy_lints/src/verbose_file_reads.rs b/clippy_lints/src/verbose_file_reads.rs deleted file mode 100644 index afd0077a6580..000000000000 --- a/clippy_lints/src/verbose_file_reads.rs +++ /dev/null @@ -1,88 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::paths; -use clippy_utils::ty::match_type; -use if_chain::if_chain; -use rustc_hir::{Expr, ExprKind, QPath}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -declare_clippy_lint! { - /// ### What it does - /// Checks for use of File::read_to_end and File::read_to_string. - /// - /// ### Why is this bad? - /// `fs::{read, read_to_string}` provide the same functionality when `buf` is empty with fewer imports and no intermediate values. - /// See also: [fs::read docs](https://doc.rust-lang.org/std/fs/fn.read.html), [fs::read_to_string docs](https://doc.rust-lang.org/std/fs/fn.read_to_string.html) - /// - /// ### Example - /// ```rust,no_run - /// # use std::io::Read; - /// # use std::fs::File; - /// let mut f = File::open("foo.txt").unwrap(); - /// let mut bytes = Vec::new(); - /// f.read_to_end(&mut bytes).unwrap(); - /// ``` - /// Can be written more concisely as - /// ```rust,no_run - /// # use std::fs; - /// let mut bytes = fs::read("foo.txt").unwrap(); - /// ``` - #[clippy::version = "1.44.0"] - pub VERBOSE_FILE_READS, - restriction, - "use of `File::read_to_end` or `File::read_to_string`" -} - -declare_lint_pass!(VerboseFileReads => [VERBOSE_FILE_READS]); - -impl<'tcx> LateLintPass<'tcx> for VerboseFileReads { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if is_file_read_to_end(cx, expr) { - span_lint_and_help( - cx, - VERBOSE_FILE_READS, - expr.span, - "use of `File::read_to_end`", - None, - "consider using `fs::read` instead", - ); - } else if is_file_read_to_string(cx, expr) { - span_lint_and_help( - cx, - VERBOSE_FILE_READS, - expr.span, - "use of `File::read_to_string`", - None, - "consider using `fs::read_to_string` instead", - ); - } - } -} - -fn is_file_read_to_end<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { - if_chain! { - if let ExprKind::MethodCall(method_name, [recv, ..], _) = expr.kind; - if method_name.ident.as_str() == "read_to_end"; - if let ExprKind::Path(QPath::Resolved(None, _)) = &recv.kind; - let ty = cx.typeck_results().expr_ty(recv); - if match_type(cx, ty, &paths::FILE); - then { - return true - } - } - false -} - -fn is_file_read_to_string<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { - if_chain! { - if let ExprKind::MethodCall(method_name, exprs, _) = expr.kind; - if method_name.ident.as_str() == "read_to_string"; - if let ExprKind::Path(QPath::Resolved(None, _)) = &exprs[0].kind; - let ty = cx.typeck_results().expr_ty(&exprs[0]); - if match_type(cx, ty, &paths::FILE); - then { - return true - } - } - false -} From 4f049f5a695b003168125a3251f5c0295e64f261 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Thu, 18 Aug 2022 17:25:02 +0000 Subject: [PATCH 3794/5092] Refactor `FormatArgsExpn` --- clippy_lints/src/format.rs | 24 +- clippy_lints/src/format_args.rs | 31 +- clippy_lints/src/format_impl.rs | 11 +- .../src/methods/uninit_assumed_init.rs | 4 +- .../src/transmute/transmuting_null.rs | 4 +- clippy_utils/Cargo.toml | 1 + clippy_utils/src/lib.rs | 15 +- clippy_utils/src/macros.rs | 678 +++++++++++++----- clippy_utils/src/paths.rs | 1 - tests/ui/format_args.fixed | 13 +- tests/ui/format_args.rs | 13 +- tests/ui/format_args.stderr | 42 +- 12 files changed, 582 insertions(+), 255 deletions(-) diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 925a8cb8deed..0c5851cdbed2 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn}; -use clippy_utils::source::{snippet_opt, snippet_with_applicability}; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use if_chain::if_chain; use rustc_errors::Applicability; @@ -56,29 +56,27 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { }; let mut applicability = Applicability::MachineApplicable; - if format_args.value_args.is_empty() { - match *format_args.format_string_parts { + if format_args.args.is_empty() { + match *format_args.format_string.parts { [] => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability), [_] => { - if let Some(s_src) = snippet_opt(cx, format_args.format_string_span) { - // Simulate macro expansion, converting {{ and }} to { and }. - let s_expand = s_src.replace("{{", "{").replace("}}", "}"); - let sugg = format!("{}.to_string()", s_expand); - span_useless_format(cx, call_site, sugg, applicability); - } + // Simulate macro expansion, converting {{ and }} to { and }. + let s_expand = format_args.format_string.snippet.replace("{{", "{").replace("}}", "}"); + let sugg = format!("{}.to_string()", s_expand); + span_useless_format(cx, call_site, sugg, applicability); }, [..] => {}, } - } else if let [value] = *format_args.value_args { + } else if let [arg] = &*format_args.args { + let value = arg.param.value; if_chain! { - if format_args.format_string_parts == [kw::Empty]; + if format_args.format_string.parts == [kw::Empty]; if match cx.typeck_results().expr_ty(value).peel_refs().kind() { ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(sym::String, adt.did()), ty::Str => true, _ => false, }; - if let Some(args) = format_args.args(); - if args.iter().all(|arg| arg.format_trait == sym::Display && !arg.has_string_formatting()); + if !arg.format.has_string_formatting(); then { let is_new_string = match value.kind { ExprKind::Binary(..) => true, diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 1e6feaac26c3..5347ff880ce0 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -1,11 +1,12 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::is_diag_trait_item; -use clippy_utils::macros::{is_format_macro, FormatArgsArg, FormatArgsExpn}; +use clippy_utils::macros::{is_format_macro, FormatArgsExpn}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; use if_chain::if_chain; +use itertools::Itertools; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_middle::ty::Ty; @@ -74,20 +75,16 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs { if let Some(macro_def_id) = outermost_expn_data.macro_def_id; if is_format_macro(cx, macro_def_id); if let ExpnKind::Macro(_, name) = outermost_expn_data.kind; - if let Some(args) = format_args.args(); then { - for (i, arg) in args.iter().enumerate() { - if arg.format_trait != sym::Display { + for arg in &format_args.args { + if arg.format.has_string_formatting() { continue; } - if arg.has_string_formatting() { + if is_aliased(&format_args, arg.param.value.hir_id) { continue; } - if is_aliased(&args, i) { - continue; - } - check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg.value); - check_to_string_in_format_args(cx, name, arg.value); + check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg.param.value); + check_to_string_in_format_args(cx, name, arg.param.value); } } } @@ -167,12 +164,12 @@ fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Ex } } -// Returns true if `args[i]` "refers to" or "is referred to by" another argument. -fn is_aliased(args: &[FormatArgsArg<'_>], i: usize) -> bool { - let value = args[i].value; - args.iter() - .enumerate() - .any(|(j, arg)| i != j && std::ptr::eq(value, arg.value)) +// Returns true if `hir_id` is referred to by multiple format params +fn is_aliased(args: &FormatArgsExpn<'_>, hir_id: HirId) -> bool { + args.params() + .filter(|param| param.value.hir_id == hir_id) + .at_most_one() + .is_err() } fn count_needed_derefs<'tcx, I>(mut ty: Ty<'tcx>, mut iter: I) -> (usize, Ty<'tcx>) diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index 04b5be6c80ec..d8bc0bf08f2b 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; -use clippy_utils::macros::{is_format_macro, root_macro_call_first_node, FormatArgsArg, FormatArgsExpn}; +use clippy_utils::macros::{is_format_macro, root_macro_call_first_node, FormatArg, FormatArgsExpn}; use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators}; use if_chain::if_chain; use rustc_errors::Applicability; @@ -168,10 +168,9 @@ fn check_self_in_format_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, if let macro_def_id = outer_macro.def_id; if let Some(format_args) = FormatArgsExpn::find_nested(cx, expr, outer_macro.expn); if is_format_macro(cx, macro_def_id); - if let Some(args) = format_args.args(); then { - for arg in args { - if arg.format_trait != impl_trait.name { + for arg in format_args.args { + if arg.format.r#trait != impl_trait.name { continue; } check_format_arg_self(cx, expr, &arg, impl_trait); @@ -180,11 +179,11 @@ fn check_self_in_format_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, } } -fn check_format_arg_self(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &FormatArgsArg<'_>, impl_trait: FormatTrait) { +fn check_format_arg_self(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &FormatArg<'_>, impl_trait: FormatTrait) { // Handle multiple dereferencing of references e.g. &&self // Handle dereference of &self -> self that is equivalent (i.e. via *self in fmt() impl) // Since the argument to fmt is itself a reference: &self - let reference = peel_ref_operators(cx, arg.value); + let reference = peel_ref_operators(cx, arg.param.value); let map = cx.tcx.hir(); // Is the reference self? if path_to_local(reference).map(|x| map.name(x)) == Some(kw::SelfLower) { diff --git a/clippy_lints/src/methods/uninit_assumed_init.rs b/clippy_lints/src/methods/uninit_assumed_init.rs index 77d21f1d3730..a1c6294737cf 100644 --- a/clippy_lints/src/methods/uninit_assumed_init.rs +++ b/clippy_lints/src/methods/uninit_assumed_init.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::{is_expr_diagnostic_item, ty::is_uninit_value_valid_for_ty}; +use clippy_utils::{is_path_diagnostic_item, ty::is_uninit_value_valid_for_ty}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; @@ -12,7 +12,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr if_chain! { if let hir::ExprKind::Call(callee, args) = recv.kind; if args.is_empty(); - if is_expr_diagnostic_item(cx, callee, sym::maybe_uninit_uninit); + if is_path_diagnostic_item(cx, callee, sym::maybe_uninit_uninit); if !is_uninit_value_valid_for_ty(cx, cx.typeck_results().expr_ty_adjusted(expr)); then { span_lint( diff --git a/clippy_lints/src/transmute/transmuting_null.rs b/clippy_lints/src/transmute/transmuting_null.rs index c4981124f396..d8e349af7af8 100644 --- a/clippy_lints/src/transmute/transmuting_null.rs +++ b/clippy_lints/src/transmute/transmuting_null.rs @@ -1,6 +1,6 @@ use clippy_utils::consts::{constant_context, Constant}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_expr_diagnostic_item; +use clippy_utils::is_path_diagnostic_item; use if_chain::if_chain; use rustc_ast::LitKind; use rustc_hir::{Expr, ExprKind}; @@ -45,7 +45,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t // `std::mem::transmute(std::ptr::null::())` if_chain! { if let ExprKind::Call(func1, []) = arg.kind; - if is_expr_diagnostic_item(cx, func1, sym::ptr_null); + if is_path_diagnostic_item(cx, func1, sym::ptr_null); then { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); return true; diff --git a/clippy_utils/Cargo.toml b/clippy_utils/Cargo.toml index a688050f63a6..c36bca06507d 100644 --- a/clippy_utils/Cargo.toml +++ b/clippy_utils/Cargo.toml @@ -7,6 +7,7 @@ publish = false [dependencies] arrayvec = { version = "0.7", default-features = false } if_chain = "1.0" +itertools = "0.10.1" rustc-semver = "1.1" [features] diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index dc772e5efeef..9308f085214f 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -27,6 +27,7 @@ extern crate rustc_infer; extern crate rustc_lexer; extern crate rustc_lint; extern crate rustc_middle; +extern crate rustc_parse_format; extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; @@ -371,15 +372,19 @@ pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool { /// If the expression is a path, resolves it to a `DefId` and checks if it matches the given path. /// -/// Please use `is_expr_diagnostic_item` if the target is a diagnostic item. +/// Please use `is_path_diagnostic_item` if the target is a diagnostic item. pub fn is_expr_path_def_path(cx: &LateContext<'_>, expr: &Expr<'_>, segments: &[&str]) -> bool { path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, segments)) } -/// If the expression is a path, resolves it to a `DefId` and checks if it matches the given -/// diagnostic item. -pub fn is_expr_diagnostic_item(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool { - path_def_id(cx, expr).map_or(false, |id| cx.tcx.is_diagnostic_item(diag_item, id)) +/// If `maybe_path` is a path node which resolves to an item, resolves it to a `DefId` and checks if +/// it matches the given diagnostic item. +pub fn is_path_diagnostic_item<'tcx>( + cx: &LateContext<'_>, + maybe_path: &impl MaybePath<'tcx>, + diag_item: Symbol, +) -> bool { + path_def_id(cx, maybe_path).map_or(false, |id| cx.tcx.is_diagnostic_item(diag_item, id)) } /// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index a268e339bb13..37d8f1e458df 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -1,16 +1,21 @@ #![allow(clippy::similar_names)] // `expr` and `expn` +use crate::is_path_diagnostic_item; +use crate::source::snippet_opt; use crate::visitors::expr_visitor_no_bodies; use arrayvec::ArrayVec; -use if_chain::if_chain; +use itertools::{izip, Either, Itertools}; use rustc_ast::ast::LitKind; use rustc_hir::intravisit::Visitor; use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath}; +use rustc_lexer::unescape::unescape_literal; +use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind}; use rustc_lint::LateContext; +use rustc_parse_format::{self as rpf, Alignment}; use rustc_span::def_id::DefId; use rustc_span::hygiene::{self, MacroKind, SyntaxContext}; -use rustc_span::{sym, ExpnData, ExpnId, ExpnKind, Span, Symbol}; +use rustc_span::{sym, BytePos, ExpnData, ExpnId, ExpnKind, Pos, Span, SpanData, Symbol}; use std::ops::ControlFlow; const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[ @@ -332,121 +337,495 @@ fn is_assert_arg(cx: &LateContext<'_>, expr: &Expr<'_>, assert_expn: ExpnId) -> } } -/// A parsed `format_args!` expansion +/// The format string doesn't exist in the HIR, so we reassemble it from source code #[derive(Debug)] -pub struct FormatArgsExpn<'tcx> { - /// Span of the first argument, the format string - pub format_string_span: Span, - /// The format string split by formatted args like `{..}` - pub format_string_parts: Vec, - /// Values passed after the format string - pub value_args: Vec<&'tcx Expr<'tcx>>, - /// Each element is a `value_args` index and a formatting trait (e.g. `sym::Debug`) - pub formatters: Vec<(usize, Symbol)>, - /// List of `fmt::v1::Argument { .. }` expressions. If this is empty, - /// then `formatters` represents the format args (`{..}`). - /// If this is non-empty, it represents the format args, and the `position` - /// parameters within the struct expressions are indexes of `formatters`. - pub specs: Vec<&'tcx Expr<'tcx>>, +pub struct FormatString { + /// Span of the whole format string literal, including `[r#]"`. + pub span: Span, + /// Snippet of the whole format string literal, including `[r#]"`. + pub snippet: String, + /// If the string is raw `r"..."`/`r#""#`, how many `#`s does it have on each side. + pub style: Option, + /// The unescaped value of the format string, e.g. `"val – {}"` for the literal + /// `"val \u{2013} {}"`. + pub unescaped: String, + /// The format string split by format args like `{..}`. + pub parts: Vec, } -impl<'tcx> FormatArgsExpn<'tcx> { - /// Parses an expanded `format_args!` or `format_args_nl!` invocation - pub fn parse(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option { - macro_backtrace(expr.span).find(|macro_call| { - matches!( - cx.tcx.item_name(macro_call.def_id), - sym::const_format_args | sym::format_args | sym::format_args_nl - ) - })?; - let mut format_string_span: Option = None; - let mut format_string_parts: Vec = Vec::new(); - let mut value_args: Vec<&Expr<'_>> = Vec::new(); - let mut formatters: Vec<(usize, Symbol)> = Vec::new(); - let mut specs: Vec<&Expr<'_>> = Vec::new(); - expr_visitor_no_bodies(|e| { - // if we're still inside of the macro definition... - if e.span.ctxt() == expr.span.ctxt() { - // ArgumentV1::new_() - if_chain! { - if let ExprKind::Call(callee, [val]) = e.kind; - if let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind; - if let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind; - if path.segments.last().unwrap().ident.name == sym::ArgumentV1; - if seg.ident.name.as_str().starts_with("new_"); - then { - let val_idx = if_chain! { - if val.span.ctxt() == expr.span.ctxt(); - if let ExprKind::Field(_, field) = val.kind; - if let Ok(idx) = field.name.as_str().parse(); - then { - // tuple index - idx - } else { - // assume the value expression is passed directly - formatters.len() - } - }; - let fmt_trait = match seg.ident.name.as_str() { - "new_display" => "Display", - "new_debug" => "Debug", - "new_lower_exp" => "LowerExp", - "new_upper_exp" => "UpperExp", - "new_octal" => "Octal", - "new_pointer" => "Pointer", - "new_binary" => "Binary", - "new_lower_hex" => "LowerHex", - "new_upper_hex" => "UpperHex", - _ => unreachable!(), - }; - formatters.push((val_idx, Symbol::intern(fmt_trait))); - } +impl FormatString { + fn new(cx: &LateContext<'_>, pieces: &Expr<'_>) -> Option { + // format_args!(r"a {} b \", 1); + // + // expands to + // + // ::core::fmt::Arguments::new_v1(&["a ", " b \\"], + // &[::core::fmt::ArgumentV1::new_display(&1)]); + // + // where `pieces` is the expression `&["a ", " b \\"]`. It has the span of `r"a {} b \"` + let span = pieces.span; + let snippet = snippet_opt(cx, span)?; + + let (inner, style) = match tokenize(&snippet).next()?.kind { + TokenKind::Literal { kind, .. } => { + let style = match kind { + LiteralKind::Str { .. } => None, + LiteralKind::RawStr { n_hashes: Some(n), .. } => Some(n.into()), + _ => return None, + }; + + let start = style.map_or(1, |n| 2 + n); + let end = snippet.len() - style.map_or(1, |n| 1 + n); + + (&snippet[start..end], style) + }, + _ => return None, + }; + + let mode = if style.is_some() { + unescape::Mode::RawStr + } else { + unescape::Mode::Str + }; + + let mut unescaped = String::with_capacity(inner.len()); + unescape_literal(inner, mode, &mut |_, ch| { + unescaped.push(ch.unwrap()); + }); + + let mut parts = Vec::new(); + expr_visitor_no_bodies(|expr| { + if let ExprKind::Lit(lit) = &expr.kind { + if let LitKind::Str(symbol, _) = lit.node { + parts.push(symbol); } - if let ExprKind::Struct(QPath::Resolved(_, path), ..) = e.kind { - if path.segments.last().unwrap().ident.name == sym::Argument { - specs.push(e); - } - } - // walk through the macro expansion - return true; } - // assume that the first expr with a differing context represents - // (and has the span of) the format string - if format_string_span.is_none() { - format_string_span = Some(e.span); - let span = e.span; - // walk the expr and collect string literals which are format string parts - expr_visitor_no_bodies(|e| { - if e.span.ctxt() != span.ctxt() { - // defensive check, probably doesn't happen - return false; - } - if let ExprKind::Lit(lit) = &e.kind { - if let LitKind::Str(symbol, _s) = lit.node { - format_string_parts.push(symbol); - } - } - true - }) - .visit_expr(e); - } else { - // assume that any further exprs with a differing context are value args - value_args.push(e); - } - // don't walk anything not from the macro expansion (e.a. inputs) - false + + true }) - .visit_expr(expr); - Some(FormatArgsExpn { - format_string_span: format_string_span?, - format_string_parts, + .visit_expr(pieces); + + Some(Self { + span, + snippet, + style, + unescaped, + parts, + }) + } +} + +struct FormatArgsValues<'tcx> { + /// See `FormatArgsExpn::value_args` + value_args: Vec<&'tcx Expr<'tcx>>, + /// Maps an `rt::v1::Argument::position` or an `rt::v1::Count::Param` to its index in + /// `value_args` + pos_to_value_index: Vec, + /// Used to check if a value is declared inline & to resolve `InnerSpan`s. + format_string_span: SpanData, +} + +impl<'tcx> FormatArgsValues<'tcx> { + fn new(args: &'tcx Expr<'tcx>, format_string_span: SpanData) -> Self { + let mut pos_to_value_index = Vec::new(); + let mut value_args = Vec::new(); + expr_visitor_no_bodies(|expr| { + if expr.span.ctxt() == args.span.ctxt() { + // ArgumentV1::new_() + // ArgumentV1::from_usize() + if let ExprKind::Call(callee, [val]) = expr.kind + && let ExprKind::Path(QPath::TypeRelative(ty, _)) = callee.kind + && let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind + && path.segments.last().unwrap().ident.name == sym::ArgumentV1 + { + let val_idx = if val.span.ctxt() == expr.span.ctxt() + && let ExprKind::Field(_, field) = val.kind + && let Ok(idx) = field.name.as_str().parse() + { + // tuple index + idx + } else { + // assume the value expression is passed directly + pos_to_value_index.len() + }; + + pos_to_value_index.push(val_idx); + } + + true + } else { + // assume that any expr with a differing span is a value + value_args.push(expr); + + false + } + }) + .visit_expr(args); + + Self { value_args, - formatters, - specs, + pos_to_value_index, + format_string_span, + } + } +} + +/// The positions of a format argument's value, precision and width +/// +/// A position is an index into the second argument of `Arguments::new_v1[_formatted]` +#[derive(Debug, Default, Copy, Clone)] +struct ParamPosition { + /// The position stored in `rt::v1::Argument::position`. + value: usize, + /// The position stored in `rt::v1::FormatSpec::width` if it is a `Count::Param`. + width: Option, + /// The position stored in `rt::v1::FormatSpec::precision` if it is a `Count::Param`. + precision: Option, +} + +/// Parses the `fmt` arg of `Arguments::new_v1_formatted(pieces, args, fmt, _)` +fn parse_rt_fmt<'tcx>(fmt_arg: &'tcx Expr<'tcx>) -> Option + 'tcx> { + fn parse_count(expr: &Expr<'_>) -> Option { + // ::core::fmt::rt::v1::Count::Param(1usize), + if let ExprKind::Call(ctor, [val]) = expr.kind + && let ExprKind::Path(QPath::Resolved(_, path)) = ctor.kind + && path.segments.last()?.ident.name == sym::Param + && let ExprKind::Lit(lit) = &val.kind + && let LitKind::Int(pos, _) = lit.node + { + Some(pos as usize) + } else { + None + } + } + + if let ExprKind::AddrOf(.., array) = fmt_arg.kind + && let ExprKind::Array(specs) = array.kind + { + Some(specs.iter().map(|spec| { + let mut position = ParamPosition::default(); + + // ::core::fmt::rt::v1::Argument { + // position: 0usize, + // format: ::core::fmt::rt::v1::FormatSpec { + // .. + // precision: ::core::fmt::rt::v1::Count::Implied, + // width: ::core::fmt::rt::v1::Count::Implied, + // }, + // } + + // TODO: this can be made much nicer next sync with `Visitor::visit_expr_field` + if let ExprKind::Struct(_, fields, _) = spec.kind { + for field in fields { + match (field.ident.name, &field.expr.kind) { + (sym::position, ExprKind::Lit(lit)) => { + if let LitKind::Int(pos, _) = lit.node { + position.value = pos as usize; + } + }, + (sym::format, &ExprKind::Struct(_, spec_fields, _)) => { + for spec_field in spec_fields { + match spec_field.ident.name { + sym::precision => { + position.precision = parse_count(spec_field.expr); + }, + sym::width => { + position.width = parse_count(spec_field.expr); + }, + _ => {}, + } + } + }, + _ => {}, + } + } + } + + position + })) + } else { + None + } +} + +/// `Span::from_inner`, but for `rustc_parse_format`'s `InnerSpan` +fn span_from_inner(base: SpanData, inner: rpf::InnerSpan) -> Span { + Span::new( + base.lo + BytePos::from_usize(inner.start), + base.lo + BytePos::from_usize(inner.end), + base.ctxt, + base.parent, + ) +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum FormatParamKind { + /// An implicit parameter , such as `{}` or `{:?}`. + Implicit, + /// A parameter with an explicit number, or an asterisk precision. e.g. `{1}`, `{0:?}`, + /// `{:.0$}` or `{:.*}`. + Numbered, + /// A named parameter with a named `value_arg`, such as the `x` in `format!("{x}", x = 1)`. + Named(Symbol), + /// An implicit named paramter, such as the `y` in `format!("{y}")`. + NamedInline(Symbol), +} + +/// A `FormatParam` is any place in a `FormatArgument` that refers to a supplied value, e.g. +/// +/// ``` +/// let precision = 2; +/// format!("{:.precision$}", 0.1234); +/// ``` +/// +/// has two `FormatParam`s, a [`FormatParamKind::Implicit`] `.kind` with a `.value` of `0.1234` +/// and a [`FormatParamKind::NamedInline("precision")`] `.kind` with a `.value` of `2` +#[derive(Debug, Copy, Clone)] +pub struct FormatParam<'tcx> { + /// The expression this parameter refers to. + pub value: &'tcx Expr<'tcx>, + /// How this paramter refers to its `value`. + pub kind: FormatParamKind, + /// Span of the parameter, may be zero width. Includes the whitespace of implicit parameters. + /// + /// ```text + /// format!("{}, { }, {0}, {name}", ...); + /// ^ ~~ ~ ~~~~ + /// ``` + pub span: Span, +} + +impl<'tcx> FormatParam<'tcx> { + fn new( + mut kind: FormatParamKind, + position: usize, + inner: rpf::InnerSpan, + values: &FormatArgsValues<'tcx>, + ) -> Option { + let value_index = *values.pos_to_value_index.get(position)?; + let value = *values.value_args.get(value_index)?; + let span = span_from_inner(values.format_string_span, inner); + + // if a param is declared inline, e.g. `format!("{x}")`, the generated expr's span points + // into the format string + if let FormatParamKind::Named(name) = kind && values.format_string_span.contains(value.span.data()) { + kind = FormatParamKind::NamedInline(name); + } + + Some(Self { value, kind, span }) + } +} + +/// Used by [width](https://doc.rust-lang.org/std/fmt/#width) and +/// [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers. +#[derive(Debug, Copy, Clone)] +pub enum Count<'tcx> { + /// Specified with a literal number, stores the value. + Is(usize, Span), + /// Specified using `$` and `*` syntaxes. The `*` format is still considered to be + /// `FormatParamKind::Numbered`. + Param(FormatParam<'tcx>), + /// Not specified. + Implied, +} + +impl<'tcx> Count<'tcx> { + fn new( + count: rpf::Count<'_>, + position: Option, + inner: Option, + values: &FormatArgsValues<'tcx>, + ) -> Option { + Some(match count { + rpf::Count::CountIs(val) => Self::Is(val, span_from_inner(values.format_string_span, inner?)), + rpf::Count::CountIsName(name, span) => Self::Param(FormatParam::new( + FormatParamKind::Named(Symbol::intern(name)), + position?, + span, + values, + )?), + rpf::Count::CountIsParam(_) => { + Self::Param(FormatParam::new(FormatParamKind::Numbered, position?, inner?, values)?) + }, + rpf::Count::CountImplied => Self::Implied, }) } - /// Finds a nested call to `format_args!` within a `format!`-like macro call + pub fn is_implied(self) -> bool { + matches!(self, Count::Implied) + } + + pub fn param(self) -> Option> { + match self { + Count::Param(param) => Some(param), + _ => None, + } + } +} + +/// Specification for the formatting of an argument in the format string. See +/// for the precise meanings. +#[derive(Debug)] +pub struct FormatSpec<'tcx> { + /// Optionally specified character to fill alignment with. + pub fill: Option, + /// Optionally specified alignment. + pub align: Alignment, + /// Packed version of various flags provided, see [`rustc_parse_format::Flag`]. + pub flags: u32, + /// Represents either the maximum width or the integer precision. + pub precision: Count<'tcx>, + /// The minimum width, will be padded according to `width`/`align` + pub width: Count<'tcx>, + /// The formatting trait used by the argument, e.g. `sym::Display` for `{}`, `sym::Debug` for + /// `{:?}`. + pub r#trait: Symbol, + pub trait_span: Option, +} + +impl<'tcx> FormatSpec<'tcx> { + fn new(spec: rpf::FormatSpec<'_>, positions: ParamPosition, values: &FormatArgsValues<'tcx>) -> Option { + Some(Self { + fill: spec.fill, + align: spec.align, + flags: spec.flags, + precision: Count::new(spec.precision, positions.precision, spec.precision_span, values)?, + width: Count::new(spec.width, positions.width, spec.width_span, values)?, + r#trait: match spec.ty { + "" => sym::Display, + "?" => sym::Debug, + "o" => sym!(Octal), + "x" => sym!(LowerHex), + "X" => sym!(UpperHex), + "p" => sym::Pointer, + "b" => sym!(Binary), + "e" => sym!(LowerExp), + "E" => sym!(UpperExp), + _ => return None, + }, + trait_span: spec + .ty_span + .map(|span| span_from_inner(values.format_string_span, span)), + }) + } + + /// Returns true if this format spec would change the contents of a string when formatted + pub fn has_string_formatting(&self) -> bool { + self.r#trait != sym::Display || !self.width.is_implied() || !self.precision.is_implied() + } +} + +/// A format argument, such as `{}`, `{foo:?}`. +#[derive(Debug)] +pub struct FormatArg<'tcx> { + /// The parameter the argument refers to. + pub param: FormatParam<'tcx>, + /// How to format `param`. + pub format: FormatSpec<'tcx>, + /// span of the whole argument, `{..}`. + pub span: Span, +} + +/// A parsed `format_args!` expansion. +#[derive(Debug)] +pub struct FormatArgsExpn<'tcx> { + /// The format string literal. + pub format_string: FormatString, + // The format arguments, such as `{:?}`. + pub args: Vec>, + /// Has an added newline due to `println!()`/`writeln!()`/etc. The last format string part will + /// include this added newline. + pub newline: bool, + /// Values passed after the format string and implicit captures. `[1, z + 2, x]` for + /// `format!("{x} {} {y}", 1, z + 2)`. + value_args: Vec<&'tcx Expr<'tcx>>, +} + +impl<'tcx> FormatArgsExpn<'tcx> { + pub fn parse(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option { + let macro_name = macro_backtrace(expr.span) + .map(|macro_call| cx.tcx.item_name(macro_call.def_id)) + .find(|&name| matches!(name, sym::const_format_args | sym::format_args | sym::format_args_nl))?; + let newline = macro_name == sym::format_args_nl; + + // ::core::fmt::Arguments::new_v1(pieces, args) + // ::core::fmt::Arguments::new_v1_formatted(pieces, args, fmt, _unsafe_arg) + if let ExprKind::Call(callee, [pieces, args, rest @ ..]) = expr.kind + && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind + && is_path_diagnostic_item(cx, ty, sym::Arguments) + && matches!(seg.ident.as_str(), "new_v1" | "new_v1_formatted") + { + let format_string = FormatString::new(cx, pieces)?; + + let mut parser = rpf::Parser::new( + &format_string.unescaped, + format_string.style, + Some(format_string.snippet.clone()), + // `format_string.unescaped` does not contain the appended newline + false, + rpf::ParseMode::Format, + ); + + let parsed_args = parser + .by_ref() + .filter_map(|piece| match piece { + rpf::Piece::NextArgument(a) => Some(a), + rpf::Piece::String(_) => None, + }) + .collect_vec(); + if !parser.errors.is_empty() { + return None; + } + + let positions = if let Some(fmt_arg) = rest.first() { + // If the argument contains format specs, `new_v1_formatted(_, _, fmt, _)`, parse + // them. + + Either::Left(parse_rt_fmt(fmt_arg)?) + } else { + // If no format specs are given, the positions are in the given order and there are + // no `precision`/`width`s to consider. + + Either::Right((0..).map(|n| ParamPosition { + value: n, + width: None, + precision: None, + })) + }; + + let values = FormatArgsValues::new(args, format_string.span.data()); + + let args = izip!(positions, parsed_args, parser.arg_places) + .map(|(position, parsed_arg, arg_span)| { + Some(FormatArg { + param: FormatParam::new( + match parsed_arg.position { + rpf::Position::ArgumentImplicitlyIs(_) => FormatParamKind::Implicit, + rpf::Position::ArgumentIs(_) => FormatParamKind::Numbered, + // NamedInline is handled by `FormatParam::new()` + rpf::Position::ArgumentNamed(name) => FormatParamKind::Named(Symbol::intern(name)), + }, + position.value, + parsed_arg.position_span, + &values, + )?, + format: FormatSpec::new(parsed_arg.format, position, &values)?, + span: span_from_inner(values.format_string_span, arg_span), + }) + }) + .collect::>>()?; + + Some(Self { + format_string, + args, + value_args: values.value_args, + newline, + }) + } else { + None + } + } + pub fn find_nested(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expn_id: ExpnId) -> Option { let mut format_args = None; expr_visitor_no_bodies(|e| { @@ -466,88 +845,23 @@ impl<'tcx> FormatArgsExpn<'tcx> { format_args } - /// Returns a vector of `FormatArgsArg`. - pub fn args(&self) -> Option>> { - if self.specs.is_empty() { - let args = std::iter::zip(&self.value_args, &self.formatters) - .map(|(value, &(_, format_trait))| FormatArgsArg { - value, - format_trait, - spec: None, - }) - .collect(); - return Some(args); - } - self.specs - .iter() - .map(|spec| { - if_chain! { - // struct `core::fmt::rt::v1::Argument` - if let ExprKind::Struct(_, fields, _) = spec.kind; - if let Some(position_field) = fields.iter().find(|f| f.ident.name == sym::position); - if let ExprKind::Lit(lit) = &position_field.expr.kind; - if let LitKind::Int(position, _) = lit.node; - if let Ok(i) = usize::try_from(position); - if let Some(&(j, format_trait)) = self.formatters.get(i); - then { - Some(FormatArgsArg { - value: self.value_args[j], - format_trait, - spec: Some(spec), - }) - } else { - None - } - } - }) - .collect() - } - /// Source callsite span of all inputs pub fn inputs_span(&self) -> Span { match *self.value_args { - [] => self.format_string_span, + [] => self.format_string.span, [.., last] => self - .format_string_span - .to(hygiene::walk_chain(last.span, self.format_string_span.ctxt())), + .format_string + .span + .to(hygiene::walk_chain(last.span, self.format_string.span.ctxt())), } } -} -/// Type representing a `FormatArgsExpn`'s format arguments -pub struct FormatArgsArg<'tcx> { - /// An element of `value_args` according to `position` - pub value: &'tcx Expr<'tcx>, - /// An element of `args` according to `position` - pub format_trait: Symbol, - /// An element of `specs` - pub spec: Option<&'tcx Expr<'tcx>>, -} - -impl<'tcx> FormatArgsArg<'tcx> { - /// Returns true if any formatting parameters are used that would have an effect on strings, - /// like `{:+2}` instead of just `{}`. - pub fn has_string_formatting(&self) -> bool { - self.spec.map_or(false, |spec| { - // `!` because these conditions check that `self` is unformatted. - !if_chain! { - // struct `core::fmt::rt::v1::Argument` - if let ExprKind::Struct(_, fields, _) = spec.kind; - if let Some(format_field) = fields.iter().find(|f| f.ident.name == sym::format); - // struct `core::fmt::rt::v1::FormatSpec` - if let ExprKind::Struct(_, subfields, _) = format_field.expr.kind; - if subfields.iter().all(|field| match field.ident.name { - sym::precision | sym::width => match field.expr.kind { - ExprKind::Path(QPath::Resolved(_, path)) => { - path.segments.last().unwrap().ident.name == sym::Implied - } - _ => false, - } - _ => true, - }); - then { true } else { false } - } - }) + /// Iterator of all format params, both values and those referenced by `width`/`precision`s. + pub fn params(&'tcx self) -> impl Iterator> { + self.args + .iter() + .flat_map(|arg| [Some(arg.param), arg.format.precision.param(), arg.format.width.param()]) + .flatten() } } diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 8d697a301c44..199a3ab12ae0 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -71,7 +71,6 @@ pub const IPADDR_V6: [&str; 5] = ["std", "net", "ip", "IpAddr", "V6"]; pub const ITER_COUNT: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "count"]; pub const ITER_EMPTY: [&str; 5] = ["core", "iter", "sources", "empty", "Empty"]; pub const ITER_REPEAT: [&str; 5] = ["core", "iter", "sources", "repeat", "repeat"]; -#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"]; #[cfg(feature = "internal")] pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"]; diff --git a/tests/ui/format_args.fixed b/tests/ui/format_args.fixed index 69b5e1c722e0..4322891db762 100644 --- a/tests/ui/format_args.fixed +++ b/tests/ui/format_args.fixed @@ -1,8 +1,6 @@ // run-rustfix -#![allow(unreachable_code)] -#![allow(unused_macros)] -#![allow(unused_variables)] +#![allow(unused)] #![allow(clippy::assertions_on_constants)] #![allow(clippy::eq_op)] #![allow(clippy::print_literal)] @@ -115,3 +113,12 @@ fn main() { // https://github.com/rust-lang/rust-clippy/issues/7903 println!("{foo}{foo:?}", foo = "foo".to_string()); } + +fn issue8643(vendor_id: usize, product_id: usize, name: &str) { + println!( + "{:<9} {:<10} {}", + format!("0x{:x}", vendor_id), + format!("0x{:x}", product_id), + name + ); +} diff --git a/tests/ui/format_args.rs b/tests/ui/format_args.rs index 3a434c5bf002..61ad04612cdc 100644 --- a/tests/ui/format_args.rs +++ b/tests/ui/format_args.rs @@ -1,8 +1,6 @@ // run-rustfix -#![allow(unreachable_code)] -#![allow(unused_macros)] -#![allow(unused_variables)] +#![allow(unused)] #![allow(clippy::assertions_on_constants)] #![allow(clippy::eq_op)] #![allow(clippy::print_literal)] @@ -115,3 +113,12 @@ fn main() { // https://github.com/rust-lang/rust-clippy/issues/7903 println!("{foo}{foo:?}", foo = "foo".to_string()); } + +fn issue8643(vendor_id: usize, product_id: usize, name: &str) { + println!( + "{:<9} {:<10} {}", + format!("0x{:x}", vendor_id), + format!("0x{:x}", product_id), + name + ); +} diff --git a/tests/ui/format_args.stderr b/tests/ui/format_args.stderr index c0cbca507958..0aca1c1a0dfb 100644 --- a/tests/ui/format_args.stderr +++ b/tests/ui/format_args.stderr @@ -1,5 +1,5 @@ error: `to_string` applied to a type that implements `Display` in `format!` args - --> $DIR/format_args.rs:76:72 + --> $DIR/format_args.rs:74:72 | LL | let _ = format!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this @@ -7,121 +7,121 @@ LL | let _ = format!("error: something failed at {}", Location::caller().to_ = note: `-D clippy::to-string-in-format-args` implied by `-D warnings` error: `to_string` applied to a type that implements `Display` in `write!` args - --> $DIR/format_args.rs:80:27 + --> $DIR/format_args.rs:78:27 | LL | Location::caller().to_string() | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `writeln!` args - --> $DIR/format_args.rs:85:27 + --> $DIR/format_args.rs:83:27 | LL | Location::caller().to_string() | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `print!` args - --> $DIR/format_args.rs:87:63 + --> $DIR/format_args.rs:85:63 | LL | print!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:88:65 + --> $DIR/format_args.rs:86:65 | LL | println!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `eprint!` args - --> $DIR/format_args.rs:89:64 + --> $DIR/format_args.rs:87:64 | LL | eprint!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `eprintln!` args - --> $DIR/format_args.rs:90:66 + --> $DIR/format_args.rs:88:66 | LL | eprintln!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `format_args!` args - --> $DIR/format_args.rs:91:77 + --> $DIR/format_args.rs:89:77 | LL | let _ = format_args!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `assert!` args - --> $DIR/format_args.rs:92:70 + --> $DIR/format_args.rs:90:70 | LL | assert!(true, "error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `assert_eq!` args - --> $DIR/format_args.rs:93:73 + --> $DIR/format_args.rs:91:73 | LL | assert_eq!(0, 0, "error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `assert_ne!` args - --> $DIR/format_args.rs:94:73 + --> $DIR/format_args.rs:92:73 | LL | assert_ne!(0, 0, "error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `panic!` args - --> $DIR/format_args.rs:95:63 + --> $DIR/format_args.rs:93:63 | LL | panic!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:96:20 + --> $DIR/format_args.rs:94:20 | LL | println!("{}", X(1).to_string()); | ^^^^^^^^^^^^^^^^ help: use this: `*X(1)` error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:97:20 + --> $DIR/format_args.rs:95:20 | LL | println!("{}", Y(&X(1)).to_string()); | ^^^^^^^^^^^^^^^^^^^^ help: use this: `***Y(&X(1))` error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:98:24 + --> $DIR/format_args.rs:96:24 | LL | println!("{}", Z(1).to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:99:20 + --> $DIR/format_args.rs:97:20 | LL | println!("{}", x.to_string()); | ^^^^^^^^^^^^^ help: use this: `**x` error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:100:20 + --> $DIR/format_args.rs:98:20 | LL | println!("{}", x_ref.to_string()); | ^^^^^^^^^^^^^^^^^ help: use this: `***x_ref` error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:102:39 + --> $DIR/format_args.rs:100:39 | LL | println!("{foo}{bar}", foo = "foo".to_string(), bar = "bar"); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:103:52 + --> $DIR/format_args.rs:101:52 | LL | println!("{foo}{bar}", foo = "foo", bar = "bar".to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:104:39 + --> $DIR/format_args.rs:102:39 | LL | println!("{foo}{bar}", bar = "bar".to_string(), foo = "foo"); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> $DIR/format_args.rs:105:52 + --> $DIR/format_args.rs:103:52 | LL | println!("{foo}{bar}", bar = "bar", foo = "foo".to_string()); | ^^^^^^^^^^^^ help: remove this From d95b67560c4cce38e07aed560abf7832eb5aeaa7 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sun, 8 May 2022 13:11:53 -0400 Subject: [PATCH 3795/5092] Rework `only_used_in_recursion` --- clippy_lints/src/lib.rs | 2 +- clippy_lints/src/only_used_in_recursion.rs | 878 ++++++++------------- tests/ui/only_used_in_recursion.rs | 143 ++-- tests/ui/only_used_in_recursion.stderr | 193 ++++- tests/ui/only_used_in_recursion2.rs | 91 +++ tests/ui/only_used_in_recursion2.stderr | 63 ++ 6 files changed, 685 insertions(+), 685 deletions(-) create mode 100644 tests/ui/only_used_in_recursion2.rs create mode 100644 tests/ui/only_used_in_recursion2.stderr diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index dbea55a04d62..467051cfa688 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -860,7 +860,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || Box::new(manual_bits::ManualBits::new(msrv))); store.register_late_pass(|| Box::new(default_union_representation::DefaultUnionRepresentation)); store.register_early_pass(|| Box::new(doc_link_with_quotes::DocLinkWithQuotes)); - store.register_late_pass(|| Box::new(only_used_in_recursion::OnlyUsedInRecursion)); + store.register_late_pass(|| Box::new(only_used_in_recursion::OnlyUsedInRecursion::default())); let allow_dbg_in_tests = conf.allow_dbg_in_tests; store.register_late_pass(move || Box::new(dbg_macro::DbgMacro::new(allow_dbg_in_tests))); let cargo_ignore_publish = conf.cargo_ignore_publish; diff --git a/clippy_lints/src/only_used_in_recursion.rs b/clippy_lints/src/only_used_in_recursion.rs index 413a740be25a..a4f516df7357 100644 --- a/clippy_lints/src/only_used_in_recursion.rs +++ b/clippy_lints/src/only_used_in_recursion.rs @@ -1,25 +1,16 @@ -use std::collections::VecDeque; - -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_lint_allowed; -use itertools::{izip, Itertools}; -use rustc_ast::{walk_list, Label, Mutability}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::{get_expr_use_or_unification_node, get_parent_node, path_def_id, path_to_local, path_to_local_id}; +use core::cell::Cell; +use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; -use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; -use rustc_hir::intravisit::{walk_expr, walk_stmt, FnKind, Visitor}; -use rustc_hir::{ - Arm, Block, Body, Closure, Expr, ExprKind, Guard, HirId, ImplicitSelfKind, Let, Local, Pat, PatKind, Path, - PathSegment, QPath, Stmt, StmtKind, TyKind, UnOp, -}; +use rustc_hir::hir_id::HirIdMap; +use rustc_hir::{Body, Expr, ExprKind, HirId, ImplItem, ImplItemKind, Node, PatKind, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; -use rustc_middle::ty::{Ty, TyCtxt, TypeckResults}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::symbol::kw; -use rustc_span::symbol::Ident; +use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; +use rustc_middle::ty::{self, ConstKind}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::symbol::{kw, Ident}; use rustc_span::Span; declare_clippy_lint! { @@ -92,569 +83,320 @@ declare_clippy_lint! { nursery, "arguments that is only used in recursion can be removed" } -declare_lint_pass!(OnlyUsedInRecursion => [ONLY_USED_IN_RECURSION]); +impl_lint_pass!(OnlyUsedInRecursion => [ONLY_USED_IN_RECURSION]); + +#[derive(Clone, Copy)] +enum FnKind { + Fn, + TraitFn, + // This is a hack. Ideally we would store a `SubstsRef<'tcx>` type here, but a lint pass must be `'static`. + // Substitutions are, however, interned. This allows us to store the pointer as a `usize` when comparing for + // equality. + ImplTraitFn(usize), +} + +struct Param { + /// The function this is a parameter for. + fn_id: DefId, + fn_kind: FnKind, + /// The index of this parameter. + idx: usize, + ident: Ident, + /// Whether this parameter should be linted. Set by `Params::flag_for_linting`. + apply_lint: Cell, + /// All the uses of this parameter. + uses: Vec, +} +impl Param { + fn new(fn_id: DefId, fn_kind: FnKind, idx: usize, ident: Ident) -> Self { + Self { + fn_id, + fn_kind, + idx, + ident, + apply_lint: Cell::new(true), + uses: Vec::new(), + } + } +} + +#[derive(Debug)] +struct Usage { + span: Span, + idx: usize, +} +impl Usage { + fn new(span: Span, idx: usize) -> Self { + Self { span, idx } + } +} + +/// The parameters being checked by the lint, indexed by both the parameter's `HirId` and the +/// `DefId` of the function paired with the parameter's index. +#[derive(Default)] +struct Params { + params: Vec, + by_id: HirIdMap, + by_fn: FxHashMap<(DefId, usize), usize>, +} +impl Params { + fn insert(&mut self, param: Param, id: HirId) { + let idx = self.params.len(); + self.by_id.insert(id, idx); + self.by_fn.insert((param.fn_id, param.idx), idx); + self.params.push(param); + } + + fn remove_by_id(&mut self, id: HirId) { + if let Some(param) = self.get_by_id_mut(id) { + param.uses = Vec::new(); + let key = (param.fn_id, param.idx); + self.by_fn.remove(&key); + self.by_id.remove(&id); + } + } + + fn get_by_id_mut(&mut self, id: HirId) -> Option<&mut Param> { + self.params.get_mut(*self.by_id.get(&id)?) + } + + fn get_by_fn(&self, id: DefId, idx: usize) -> Option<&Param> { + self.params.get(*self.by_fn.get(&(id, idx))?) + } + + fn clear(&mut self) { + self.params.clear(); + self.by_id.clear(); + self.by_fn.clear(); + } + + /// Sets the `apply_lint` flag on each parameter. + fn flag_for_linting(&mut self) { + // Stores the list of parameters currently being resolved. Needed to avoid cycles. + let mut eval_stack = Vec::new(); + for param in &self.params { + self.try_disable_lint_for_param(param, &mut eval_stack); + } + } + + // Use by calling `flag_for_linting`. + fn try_disable_lint_for_param(&self, param: &Param, eval_stack: &mut Vec) -> bool { + if !param.apply_lint.get() { + true + } else if param.uses.is_empty() { + // Don't lint on unused parameters. + param.apply_lint.set(false); + true + } else if eval_stack.contains(¶m.idx) { + // Already on the evaluation stack. Returning false will continue to evaluate other dependencies. + false + } else { + eval_stack.push(param.idx); + // Check all cases when used at a different parameter index. + // Needed to catch cases like: `fn f(x: u32, y: u32) { f(y, x) }` + for usage in param.uses.iter().filter(|u| u.idx != param.idx) { + if self + .get_by_fn(param.fn_id, usage.idx) + // If the parameter can't be found, then it's used for more than just recursion. + .map_or(true, |p| self.try_disable_lint_for_param(p, eval_stack)) + { + param.apply_lint.set(false); + eval_stack.pop(); + return true; + } + } + eval_stack.pop(); + false + } + } +} + +#[derive(Default)] +pub struct OnlyUsedInRecursion { + /// Track the top-level body entered. Needed to delay reporting when entering nested bodies. + entered_body: Option, + params: Params, +} impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { - fn check_fn( - &mut self, - cx: &LateContext<'tcx>, - kind: FnKind<'tcx>, - decl: &'tcx rustc_hir::FnDecl<'tcx>, - body: &'tcx Body<'tcx>, - _: Span, - id: HirId, - ) { - if is_lint_allowed(cx, ONLY_USED_IN_RECURSION, id) { + fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'tcx>) { + if body.value.span.from_expansion() { return; } - if let FnKind::ItemFn(ident, ..) | FnKind::Method(ident, ..) = kind { - let def_id = id.owner.to_def_id(); - let data = cx.tcx.def_path(def_id).data; - - if data.len() > 1 { - match data.get(data.len() - 2) { - Some(DisambiguatedDefPathData { - data: DefPathData::Impl, - disambiguator, - }) if *disambiguator != 0 => return, - _ => {}, - } - } - - let has_self = !matches!(decl.implicit_self, ImplicitSelfKind::None); - - let ty_res = cx.typeck_results(); - let param_span = body - .params - .iter() - .flat_map(|param| { - let mut v = Vec::new(); - param.pat.each_binding(|_, hir_id, span, ident| { - v.push((hir_id, span, ident)); - }); - v - }) - .skip(if has_self { 1 } else { 0 }) - .filter(|(_, _, ident)| !ident.name.as_str().starts_with('_')) - .collect_vec(); - - let params = body.params.iter().map(|param| param.pat).collect(); - - let mut visitor = SideEffectVisit { - graph: FxHashMap::default(), - has_side_effect: FxHashSet::default(), - ret_vars: Vec::new(), - contains_side_effect: false, - break_vars: FxHashMap::default(), - params, - fn_ident: ident, - fn_def_id: def_id, - is_method: matches!(kind, FnKind::Method(..)), - has_self, - ty_res, - tcx: cx.tcx, - visited_exprs: FxHashSet::default(), - }; - - visitor.visit_expr(&body.value); - let vars = std::mem::take(&mut visitor.ret_vars); - // this would set the return variables to side effect - visitor.add_side_effect(vars); - - let mut queue = visitor.has_side_effect.iter().copied().collect::>(); - - // a simple BFS to check all the variables that have side effect - while let Some(id) = queue.pop_front() { - if let Some(next) = visitor.graph.get(&id) { - for i in next { - if !visitor.has_side_effect.contains(i) { - visitor.has_side_effect.insert(*i); - queue.push_back(*i); - } - } - } - } - - for (id, span, ident) in param_span { - // if the variable is not used in recursion, it would be marked as unused - if !visitor.has_side_effect.contains(&id) { - let mut queue = VecDeque::new(); - let mut visited = FxHashSet::default(); - - queue.push_back(id); - - // a simple BFS to check the graph can reach to itself - // if it can't, it means the variable is never used in recursion - while let Some(id) = queue.pop_front() { - if let Some(next) = visitor.graph.get(&id) { - for i in next { - if !visited.contains(i) { - visited.insert(id); - queue.push_back(*i); - } - } - } - } - - if visited.contains(&id) { - span_lint_and_sugg( - cx, - ONLY_USED_IN_RECURSION, - span, - "parameter is only used in recursion", - "if this is intentional, prefix with an underscore", - format!("_{}", ident.name.as_str()), - Applicability::MaybeIncorrect, - ); - } - } - } - } - } -} - -pub fn is_primitive(ty: Ty<'_>) -> bool { - let ty = ty.peel_refs(); - ty.is_primitive() || ty.is_str() -} - -pub fn is_array(ty: Ty<'_>) -> bool { - let ty = ty.peel_refs(); - ty.is_array() || ty.is_array_slice() -} - -/// This builds the graph of side effect. -/// The edge `a -> b` means if `a` has side effect, `b` will have side effect. -/// -/// There are some example in following code: -/// ```rust, ignore -/// let b = 1; -/// let a = b; // a -> b -/// let (c, d) = (a, b); // c -> b, d -> b -/// -/// let e = if a == 0 { // e -> a -/// c // e -> c -/// } else { -/// d // e -> d -/// }; -/// ``` -pub struct SideEffectVisit<'tcx> { - graph: FxHashMap>, - has_side_effect: FxHashSet, - // bool for if the variable was dereferenced from mutable reference - ret_vars: Vec<(HirId, bool)>, - contains_side_effect: bool, - // break label - break_vars: FxHashMap>, - params: Vec<&'tcx Pat<'tcx>>, - fn_ident: Ident, - fn_def_id: DefId, - is_method: bool, - has_self: bool, - ty_res: &'tcx TypeckResults<'tcx>, - tcx: TyCtxt<'tcx>, - visited_exprs: FxHashSet, -} - -impl<'tcx> Visitor<'tcx> for SideEffectVisit<'tcx> { - fn visit_stmt(&mut self, s: &'tcx Stmt<'tcx>) { - match s.kind { - StmtKind::Local(Local { - pat, init: Some(init), .. - }) => { - self.visit_pat_expr(pat, init, false); - }, - StmtKind::Item(_) | StmtKind::Expr(_) | StmtKind::Semi(_) => { - walk_stmt(self, s); - }, - StmtKind::Local(_) => {}, - } - self.ret_vars.clear(); - } - - fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { - if !self.visited_exprs.insert(ex.hir_id) { - return; - } - match ex.kind { - ExprKind::Array(exprs) | ExprKind::Tup(exprs) => { - self.ret_vars = exprs - .iter() - .flat_map(|expr| { - self.visit_expr(expr); - std::mem::take(&mut self.ret_vars) - }) - .collect(); - }, - ExprKind::Call(callee, args) => self.visit_fn(callee, args), - ExprKind::MethodCall(path, args, _) => self.visit_method_call(path, args), - ExprKind::Binary(_, lhs, rhs) => { - self.visit_bin_op(lhs, rhs); - }, - ExprKind::Unary(op, expr) => self.visit_un_op(op, expr), - ExprKind::Let(Let { pat, init, .. }) => self.visit_pat_expr(pat, init, false), - ExprKind::If(bind, then_expr, else_expr) => { - self.visit_if(bind, then_expr, else_expr); - }, - ExprKind::Match(expr, arms, _) => self.visit_match(expr, arms), - // since analysing the closure is not easy, just set all variables in it to side-effect - ExprKind::Closure(&Closure { body, .. }) => { - let body = self.tcx.hir().body(body); - self.visit_body(body); - let vars = std::mem::take(&mut self.ret_vars); - self.add_side_effect(vars); - }, - ExprKind::Loop(block, label, _, _) | ExprKind::Block(block, label) => { - self.visit_block_label(block, label); - }, - ExprKind::Assign(bind, expr, _) => { - self.visit_assign(bind, expr); - }, - ExprKind::AssignOp(_, bind, expr) => { - self.visit_assign(bind, expr); - self.visit_bin_op(bind, expr); - }, - ExprKind::Field(expr, _) => { - self.visit_expr(expr); - if matches!(self.ty_res.expr_ty(expr).kind(), ty::Ref(_, _, Mutability::Mut)) { - self.ret_vars.iter_mut().for_each(|(_, b)| *b = true); + // `skip_params` is either `0` or `1` to skip the `self` parameter in trait functions. + // It can't be renamed, and it can't be removed without removing it from multiple functions. + let (fn_id, fn_kind, skip_params) = match get_parent_node(cx.tcx, body.value.hir_id) { + Some(Node::Item(i)) => (i.def_id.to_def_id(), FnKind::Fn, 0), + Some(Node::TraitItem(&TraitItem { + kind: TraitItemKind::Fn(ref sig, _), + def_id, + .. + })) => ( + def_id.to_def_id(), + FnKind::TraitFn, + if sig.decl.implicit_self.has_implicit_self() { + 1 + } else { + 0 + }, + ), + Some(Node::ImplItem(&ImplItem { + kind: ImplItemKind::Fn(ref sig, _), + def_id, + .. + })) => { + #[allow(trivial_casts)] + if let Some(Node::Item(item)) = get_parent_node(cx.tcx, cx.tcx.hir().local_def_id_to_hir_id(def_id)) + && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.def_id) + && let Some(trait_item_id) = cx.tcx.associated_item(def_id).trait_item_def_id + { + ( + trait_item_id, + FnKind::ImplTraitFn(cx.tcx.erase_regions(trait_ref.substs) as *const _ as usize), + if sig.decl.implicit_self.has_implicit_self() { + 1 + } else { + 0 + }, + ) + } else { + (def_id.to_def_id(), FnKind::Fn, 0) } }, - ExprKind::Index(expr, index) => { - self.visit_expr(expr); - let mut vars = std::mem::take(&mut self.ret_vars); - self.visit_expr(index); - self.ret_vars.append(&mut vars); - - if !is_array(self.ty_res.expr_ty(expr)) { - self.add_side_effect(self.ret_vars.clone()); - } else if matches!(self.ty_res.expr_ty(expr).kind(), ty::Ref(_, _, Mutability::Mut)) { - self.ret_vars.iter_mut().for_each(|(_, b)| *b = true); - } - }, - ExprKind::Break(dest, Some(expr)) => { - self.visit_expr(expr); - if let Some(label) = dest.label { - self.break_vars - .entry(label.ident) - .or_insert(Vec::new()) - .append(&mut self.ret_vars); - } - self.contains_side_effect = true; - }, - ExprKind::Ret(Some(expr)) => { - self.visit_expr(expr); - let vars = std::mem::take(&mut self.ret_vars); - self.add_side_effect(vars); - self.contains_side_effect = true; - }, - ExprKind::Break(_, None) | ExprKind::Continue(_) | ExprKind::Ret(None) => { - self.contains_side_effect = true; - }, - ExprKind::Struct(_, exprs, expr) => { - let mut ret_vars = exprs - .iter() - .flat_map(|field| { - self.visit_expr(field.expr); - std::mem::take(&mut self.ret_vars) - }) - .collect(); - - walk_list!(self, visit_expr, expr); - self.ret_vars.append(&mut ret_vars); - }, - _ => walk_expr(self, ex), - } - } - - fn visit_path(&mut self, path: &'tcx Path<'tcx>, _id: HirId) { - if let Res::Local(id) = path.res { - self.ret_vars.push((id, false)); - } - } -} - -impl<'tcx> SideEffectVisit<'tcx> { - fn visit_assign(&mut self, lhs: &'tcx Expr<'tcx>, rhs: &'tcx Expr<'tcx>) { - // Just support array and tuple unwrapping for now. - // - // ex) `(a, b) = (c, d);` - // The graph would look like this: - // a -> c - // b -> d - // - // This would minimize the connection of the side-effect graph. - match (&lhs.kind, &rhs.kind) { - (ExprKind::Array(lhs), ExprKind::Array(rhs)) | (ExprKind::Tup(lhs), ExprKind::Tup(rhs)) => { - // if not, it is a compile error - debug_assert!(lhs.len() == rhs.len()); - izip!(*lhs, *rhs).for_each(|(lhs, rhs)| self.visit_assign(lhs, rhs)); - }, - // in other assigns, we have to connect all each other - // because they can be connected somehow - _ => { - self.visit_expr(lhs); - let lhs_vars = std::mem::take(&mut self.ret_vars); - self.visit_expr(rhs); - let rhs_vars = std::mem::take(&mut self.ret_vars); - self.connect_assign(&lhs_vars, &rhs_vars, false); - }, - } - } - - fn visit_block_label(&mut self, block: &'tcx Block<'tcx>, label: Option { fn encode(&self, s: &mut S) { @@ -23,6 +22,19 @@ impl>> Decodable for SmallVec { } } +impl> Encodable for ThinVec { + fn encode(&self, s: &mut S) { + self.as_slice().encode(s); + } +} + +impl> Decodable for ThinVec { + fn decode(d: &mut D) -> ThinVec { + let len = d.read_usize(); + (0..len).map(|_| Decodable::decode(d)).collect() + } +} + impl> Encodable for LinkedList { fn encode(&self, s: &mut S) { s.emit_usize(self.len()); diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index cbdfea89efb8..7bc35c7d5516 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -10,18 +10,19 @@ path = "lib.rs" arrayvec = { version = "0.7", default-features = false } askama = { version = "0.11", default-features = false, features = ["config"] } atty = "0.2" -pulldown-cmark = { version = "0.9.2", default-features = false } -minifier = "0.2.2" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -smallvec = "1.8.1" -tempfile = "3" itertools = "0.10.1" +minifier = "0.2.2" +once_cell = "1.10.0" +pulldown-cmark = { version = "0.9.2", default-features = false } regex = "1" rustdoc-json-types = { path = "../rustdoc-json-types" } +serde_json = "1.0" +serde = { version = "1.0", features = ["derive"] } +smallvec = "1.8.1" +tempfile = "3" +thin-vec = "0.2.8" tracing = "0.1" tracing-tree = "0.2.0" -once_cell = "1.10.0" [dependencies.tracing-subscriber] version = "0.3.3" diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 5441a7bd29ec..0239b8da57ee 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -123,7 +123,7 @@ where kind: Box::new(ImplItem(Box::new(Impl { unsafety: hir::Unsafety::Normal, generics: new_generics, - trait_: Some(clean_trait_ref_with_bindings(self.cx, trait_ref, &[])), + trait_: Some(clean_trait_ref_with_bindings(self.cx, trait_ref, ThinVec::new())), for_: clean_middle_ty(ty, self.cx, None), items: Vec::new(), polarity, diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index da15c3c2b1fa..cc734389e070 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -115,7 +115,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { ), // FIXME(eddyb) compute both `trait_` and `for_` from // the post-inference `trait_ref`, as it's more accurate. - trait_: Some(clean_trait_ref_with_bindings(cx, trait_ref.0, &[])), + trait_: Some(clean_trait_ref_with_bindings(cx, trait_ref.0, ThinVec::new())), for_: clean_middle_ty(ty.0, cx, None), items: cx.tcx .associated_items(impl_def_id) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index f367edcbf5a8..f000b79d3104 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -3,9 +3,10 @@ use std::iter::once; use std::sync::Arc; +use thin_vec::ThinVec; + use rustc_ast as ast; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::thin_vec::ThinVec; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; @@ -461,7 +462,7 @@ pub(crate) fn build_impl( ), }; let polarity = tcx.impl_polarity(did); - let trait_ = associated_trait.map(|t| clean_trait_ref_with_bindings(cx, t, &[])); + let trait_ = associated_trait.map(|t| clean_trait_ref_with_bindings(cx, t, ThinVec::new())); if trait_.as_ref().map(|t| t.def_id()) == tcx.lang_items().deref_trait() { super::build_deref_target_impls(cx, &trait_items, ret); } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 420159b5a675..a27d1a16e3bf 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -33,7 +33,8 @@ use std::collections::hash_map::Entry; use std::collections::BTreeMap; use std::default::Default; use std::hash::Hash; -use std::{mem, vec}; +use std::mem; +use thin_vec::ThinVec; use crate::core::{self, DocContext, ImplTraitParam}; use crate::formats::item_type::ItemType; @@ -125,7 +126,7 @@ fn clean_generic_bound<'tcx>( bug!("clean: parenthesized `GenericBound::LangItemTrait`"); }; - let trait_ = clean_trait_ref_with_bindings(cx, trait_ref, &bindings); + let trait_ = clean_trait_ref_with_bindings(cx, trait_ref, bindings); GenericBound::TraitBound( PolyTrait { trait_, generic_params: vec![] }, hir::TraitBoundModifier::None, @@ -147,14 +148,14 @@ fn clean_generic_bound<'tcx>( pub(crate) fn clean_trait_ref_with_bindings<'tcx>( cx: &mut DocContext<'tcx>, trait_ref: ty::TraitRef<'tcx>, - bindings: &[TypeBinding], + bindings: ThinVec, ) -> Path { let kind = cx.tcx.def_kind(trait_ref.def_id).into(); if !matches!(kind, ItemType::Trait | ItemType::TraitAlias) { span_bug!(cx.tcx.def_span(trait_ref.def_id), "`TraitRef` had unexpected kind {:?}", kind); } inline::record_extern_fqn(cx, trait_ref.def_id, kind); - let path = external_path(cx, trait_ref.def_id, true, bindings.to_vec(), trait_ref.substs); + let path = external_path(cx, trait_ref.def_id, true, bindings, trait_ref.substs); debug!("ty::TraitRef\n subst: {:?}\n", trait_ref.substs); @@ -164,7 +165,7 @@ pub(crate) fn clean_trait_ref_with_bindings<'tcx>( fn clean_poly_trait_ref_with_bindings<'tcx>( cx: &mut DocContext<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>, - bindings: &[TypeBinding], + bindings: ThinVec, ) -> GenericBound { let poly_trait_ref = poly_trait_ref.lift_to_tcx(cx.tcx).unwrap(); @@ -327,7 +328,7 @@ fn clean_poly_trait_predicate<'tcx>( let poly_trait_ref = pred.map_bound(|pred| pred.trait_ref); Some(WherePredicate::BoundPredicate { ty: clean_middle_ty(poly_trait_ref.skip_binder().self_ty(), cx, None), - bounds: vec![clean_poly_trait_ref_with_bindings(cx, poly_trait_ref, &[])], + bounds: vec![clean_poly_trait_ref_with_bindings(cx, poly_trait_ref, ThinVec::new())], bound_params: Vec::new(), }) } @@ -402,7 +403,7 @@ fn clean_projection<'tcx>( def_id: Option, ) -> Type { let lifted = ty.lift_to_tcx(cx.tcx).unwrap(); - let trait_ = clean_trait_ref_with_bindings(cx, lifted.trait_ref(cx.tcx), &[]); + let trait_ = clean_trait_ref_with_bindings(cx, lifted.trait_ref(cx.tcx), ThinVec::new()); let self_type = clean_middle_ty(ty.self_ty(), cx, None); let self_def_id = if let Some(def_id) = def_id { cx.tcx.opt_parent(def_id).or(Some(def_id)) @@ -1588,12 +1589,12 @@ pub(crate) fn clean_middle_ty<'tcx>( AdtKind::Enum => ItemType::Enum, }; inline::record_extern_fqn(cx, did, kind); - let path = external_path(cx, did, false, vec![], substs); + let path = external_path(cx, did, false, ThinVec::new(), substs); Type::Path { path } } ty::Foreign(did) => { inline::record_extern_fqn(cx, did, ItemType::ForeignType); - let path = external_path(cx, did, false, vec![], InternalSubsts::empty()); + let path = external_path(cx, did, false, ThinVec::new(), InternalSubsts::empty()); Type::Path { path } } ty::Dynamic(obj, ref reg) => { @@ -1617,7 +1618,7 @@ pub(crate) fn clean_middle_ty<'tcx>( let mut bounds = dids .map(|did| { let empty = cx.tcx.intern_substs(&[]); - let path = external_path(cx, did, false, vec![], empty); + let path = external_path(cx, did, false, ThinVec::new(), empty); inline::record_extern_fqn(cx, did, ItemType::Trait); PolyTrait { trait_: path, generic_params: Vec::new() } }) @@ -1693,7 +1694,7 @@ pub(crate) fn clean_middle_ty<'tcx>( } } - let bindings: Vec<_> = bounds + let bindings: ThinVec<_> = bounds .iter() .filter_map(|bound| { if let ty::PredicateKind::Projection(proj) = bound.kind().skip_binder() @@ -1714,7 +1715,7 @@ pub(crate) fn clean_middle_ty<'tcx>( }) .collect(); - Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, &bindings)) + Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, bindings)) }) .collect::>(); bounds.extend(regions); @@ -1845,12 +1846,8 @@ fn clean_generic_args<'tcx>( }) .collect::>() .into(); - let bindings = generic_args - .bindings - .iter() - .map(|x| clean_type_binding(x, cx)) - .collect::>() - .into(); + let bindings = + generic_args.bindings.iter().map(|x| clean_type_binding(x, cx)).collect::>(); GenericArgs::AngleBracketed { args, bindings } } } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 909a47d07b16..2808b400a0b5 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -8,6 +8,7 @@ use std::sync::OnceLock as OnceCell; use std::{cmp, fmt, iter}; use arrayvec::ArrayVec; +use thin_vec::ThinVec; use rustc_ast::attr; use rustc_ast::util::comments::beautify_doc_string; @@ -15,7 +16,6 @@ use rustc_ast::{self as ast, AttrStyle}; use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel}; use rustc_const_eval::const_eval::is_unstable_const_fn; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::thin_vec::ThinVec; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; @@ -1303,7 +1303,7 @@ impl GenericBound { pub(crate) fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound { let did = cx.tcx.require_lang_item(LangItem::Sized, None); let empty = cx.tcx.intern_substs(&[]); - let path = external_path(cx, did, false, vec![], empty); + let path = external_path(cx, did, false, ThinVec::new(), empty); inline::record_extern_fqn(cx, did, ItemType::Trait); GenericBound::TraitBound( PolyTrait { trait_: path, generic_params: Vec::new() }, diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 718cbbd2b837..ac9ab3396167 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -12,7 +12,6 @@ use crate::visit_lib::LibEmbargoVisitor; use rustc_ast as ast; use rustc_ast::tokenstream::TokenTree; -use rustc_data_structures::thin_vec::ThinVec; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; @@ -23,6 +22,7 @@ use rustc_middle::ty::{self, DefIdTree, TyCtxt}; use rustc_span::symbol::{kw, sym, Symbol}; use std::fmt::Write as _; use std::mem; +use thin_vec::ThinVec; #[cfg(test)] mod tests; @@ -102,7 +102,7 @@ fn external_generic_args<'tcx>( cx: &mut DocContext<'tcx>, did: DefId, has_self: bool, - bindings: Vec, + bindings: ThinVec, substs: SubstsRef<'tcx>, ) -> GenericArgs { let args = substs_to_args(cx, substs, has_self); @@ -112,7 +112,7 @@ fn external_generic_args<'tcx>( // The trait's first substitution is the one after self, if there is one. match substs.iter().nth(if has_self { 1 } else { 0 }).unwrap().expect_ty().kind() { ty::Tuple(tys) => tys.iter().map(|t| clean_middle_ty(t, cx, None)).collect::>().into(), - _ => return GenericArgs::AngleBracketed { args: args.into(), bindings: bindings.into() }, + _ => return GenericArgs::AngleBracketed { args: args.into(), bindings }, }; let output = None; // FIXME(#20299) return type comes from a projection now @@ -130,7 +130,7 @@ pub(super) fn external_path<'tcx>( cx: &mut DocContext<'tcx>, did: DefId, has_self: bool, - bindings: Vec, + bindings: ThinVec, substs: SubstsRef<'tcx>, ) -> Path { let def_kind = cx.tcx.def_kind(did); diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 5770bb7bc33c..b124490f747a 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -223,6 +223,7 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "time", "tinystr", "tinyvec", + "thin-vec", "tracing", "tracing-attributes", "tracing-core", From c768617f6fae82388df9ac1a5907c30fcba3ef44 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 23 Aug 2022 13:28:20 +1000 Subject: [PATCH 3913/5092] Improve `parse_dot_or_call_expr_with`. Avoid all the extra work in the very common case where `attrs` is empty. --- compiler/rustc_parse/src/parser/expr.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 18aa109d7a60..f28897aaeb0a 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -944,13 +944,18 @@ impl<'a> Parser<'a> { // Stitch the list of outer attributes onto the return value. // A little bit ugly, but the best way given the current code // structure - self.parse_dot_or_call_expr_with_(e0, lo).map(|expr| { - expr.map(|mut expr| { - attrs.extend(expr.attrs); - expr.attrs = attrs; - expr + let res = self.parse_dot_or_call_expr_with_(e0, lo); + if attrs.is_empty() { + res + } else { + res.map(|expr| { + expr.map(|mut expr| { + attrs.extend(expr.attrs); + expr.attrs = attrs; + expr + }) }) - }) + } } fn parse_dot_or_call_expr_with_(&mut self, mut e: P, lo: Span) -> PResult<'a, P> { From 925644ed09689018cd17b3bb6e469520d105e6b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 20 Aug 2022 13:40:18 +0200 Subject: [PATCH 3914/5092] Track PGO profiles in depinfo --- compiler/rustc_interface/src/passes.rs | 17 +++++++++--- src/test/run-make/track-pgo-dep-info/Makefile | 26 +++++++++++++++++++ src/test/run-make/track-pgo-dep-info/main.rs | 1 + 3 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 src/test/run-make/track-pgo-dep-info/Makefile create mode 100644 src/test/run-make/track-pgo-dep-info/main.rs diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index e00d0b7d0d82..149b3697d910 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -593,13 +593,24 @@ fn write_out_deps( // Account for explicitly marked-to-track files // (e.g. accessed in proc macros). let file_depinfo = sess.parse_sess.file_depinfo.borrow(); - let extra_tracked_files = file_depinfo.iter().map(|path_sym| { - let path = PathBuf::from(path_sym.as_str()); + + let normalize_path = |path: PathBuf| { let file = FileName::from(path); escape_dep_filename(&file.prefer_local().to_string()) - }); + }; + + let extra_tracked_files = + file_depinfo.iter().map(|path_sym| normalize_path(PathBuf::from(path_sym.as_str()))); files.extend(extra_tracked_files); + // We also need to track used PGO profile files + if let Some(ref profile_instr) = sess.opts.cg.profile_use { + files.push(normalize_path(profile_instr.as_path().to_path_buf())); + } + if let Some(ref profile_sample) = sess.opts.unstable_opts.profile_sample_use { + files.push(normalize_path(profile_sample.as_path().to_path_buf())); + } + if sess.binary_dep_depinfo() { if let Some(ref backend) = sess.opts.unstable_opts.codegen_backend { if backend.contains('.') { diff --git a/src/test/run-make/track-pgo-dep-info/Makefile b/src/test/run-make/track-pgo-dep-info/Makefile new file mode 100644 index 000000000000..60b59c04aa95 --- /dev/null +++ b/src/test/run-make/track-pgo-dep-info/Makefile @@ -0,0 +1,26 @@ +# needs-profiler-support +# ignore-windows-gnu + +-include ../../run-make-fulldeps/tools.mk + +# FIXME(eddyb) provide `HOST_RUSTC` and `TARGET_RUSTC` +# instead of hardcoding them everywhere they're needed. +ifeq ($(IS_MUSL_HOST),1) +ADDITIONAL_ARGS := $(RUSTFLAGS) +endif + +all: + # Generate PGO profiles + $(BARE_RUSTC) $(ADDITIONAL_ARGS) -Cprofile-generate=$(TMPDIR)/profiles --out-dir $(TMPDIR) main.rs + $(TMPDIR)/main + + # Merge profiles + "$(LLVM_BIN_DIR)/llvm-profdata" merge \ + -o "$(TMPDIR)/merged.profdata" \ + "$(TMPDIR)/profiles" || exit 1 + + # Use the profile + $(RUSTC) -Cprofile-use=$(TMPDIR)/merged.profdata --emit dep-info main.rs + + # Check that profile file is in depinfo + $(CGREP) "merged.profdata" < $(TMPDIR)/main.d diff --git a/src/test/run-make/track-pgo-dep-info/main.rs b/src/test/run-make/track-pgo-dep-info/main.rs new file mode 100644 index 000000000000..f328e4d9d04c --- /dev/null +++ b/src/test/run-make/track-pgo-dep-info/main.rs @@ -0,0 +1 @@ +fn main() {} From 78f83f0b460eb9c79369c5e5d6616ed6918a8024 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 29 Aug 2022 20:25:48 +1000 Subject: [PATCH 3915/5092] Inline `attrs`. --- compiler/rustc_ast/src/ast_traits.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index 0947a71b8243..79f5820230ed 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -279,6 +279,7 @@ macro_rules! impl_has_attrs { impl HasAttrs for $T { const SUPPORTS_CUSTOM_INNER_ATTRS: bool = $inner; + #[inline] fn attrs(&self) -> &[Attribute] { &self.attrs } From c9b36b4dedab0c1b44f0357ddbf4ebc3a702e259 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 29 Aug 2022 07:46:03 -0400 Subject: [PATCH 3916/5092] clarify test purpose --- tests/pass/stacked-borrows/zst-field-retagging-terminates.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/pass/stacked-borrows/zst-field-retagging-terminates.rs b/tests/pass/stacked-borrows/zst-field-retagging-terminates.rs index 2099c5ad1496..ce3c8b7d5f1a 100644 --- a/tests/pass/stacked-borrows/zst-field-retagging-terminates.rs +++ b/tests/pass/stacked-borrows/zst-field-retagging-terminates.rs @@ -1,4 +1,5 @@ //@compile-flags: -Zmiri-retag-fields +// Checks that the test does not run forever (which relies on a fast path). fn main() { let array = [(); usize::MAX]; drop(array); // Pass the array to a function, retagging its fields From 26a6891925f8e8bca95c6b71eea8e6becd38b73d Mon Sep 17 00:00:00 2001 From: Lukas Lueg Date: Mon, 29 Aug 2022 13:56:03 +0200 Subject: [PATCH 3917/5092] Fix missing parens in `suboptimal_flops` sugg Fixes #9391 --- clippy_lints/src/floating_point_arithmetic.rs | 4 +-- tests/ui/floating_point_rad.fixed | 5 +++ tests/ui/floating_point_rad.rs | 5 +++ tests/ui/floating_point_rad.stderr | 32 +++++++++++++------ 4 files changed, 34 insertions(+), 12 deletions(-) diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index df9b41d2c98b..a052ecb6e04f 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -651,7 +651,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue) && (F32(180_f32) == lvalue || F64(180_f64) == lvalue) { - let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..")); + let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..").maybe_par()); if_chain! { if let ExprKind::Lit(ref literal) = mul_lhs.kind; if let ast::LitKind::Float(ref value, float_type) = literal.node; @@ -677,7 +677,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { (F32(180_f32) == rvalue || F64(180_f64) == rvalue) && (F32(f32_consts::PI) == lvalue || F64(f64_consts::PI) == lvalue) { - let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..")); + let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..").maybe_par()); if_chain! { if let ExprKind::Lit(ref literal) = mul_lhs.kind; if let ast::LitKind::Float(ref value, float_type) = literal.node; diff --git a/tests/ui/floating_point_rad.fixed b/tests/ui/floating_point_rad.fixed index ce91fe176c6f..27674b8a455b 100644 --- a/tests/ui/floating_point_rad.fixed +++ b/tests/ui/floating_point_rad.fixed @@ -8,6 +8,11 @@ pub const fn const_context() { let _ = x * 180f32 / std::f32::consts::PI; } +pub fn issue9391(degrees: i64) { + let _ = (degrees as f64).to_radians(); + let _ = (degrees as f64).to_degrees(); +} + fn main() { let x = 3f32; let _ = x.to_degrees(); diff --git a/tests/ui/floating_point_rad.rs b/tests/ui/floating_point_rad.rs index 8f3234986148..f1ea73df3984 100644 --- a/tests/ui/floating_point_rad.rs +++ b/tests/ui/floating_point_rad.rs @@ -8,6 +8,11 @@ pub const fn const_context() { let _ = x * 180f32 / std::f32::consts::PI; } +pub fn issue9391(degrees: i64) { + let _ = degrees as f64 * std::f64::consts::PI / 180.0; + let _ = degrees as f64 * 180.0 / std::f64::consts::PI; +} + fn main() { let x = 3f32; let _ = x * 180f32 / std::f32::consts::PI; diff --git a/tests/ui/floating_point_rad.stderr b/tests/ui/floating_point_rad.stderr index f12d3d23f3ab..979442f2c24a 100644 --- a/tests/ui/floating_point_rad.stderr +++ b/tests/ui/floating_point_rad.stderr @@ -1,40 +1,52 @@ -error: conversion to degrees can be done more accurately - --> $DIR/floating_point_rad.rs:13:13 +error: conversion to radians can be done more accurately + --> $DIR/floating_point_rad.rs:12:13 | -LL | let _ = x * 180f32 / std::f32::consts::PI; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.to_degrees()` +LL | let _ = degrees as f64 * std::f64::consts::PI / 180.0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(degrees as f64).to_radians()` | = note: `-D clippy::suboptimal-flops` implied by `-D warnings` error: conversion to degrees can be done more accurately - --> $DIR/floating_point_rad.rs:14:13 + --> $DIR/floating_point_rad.rs:13:13 + | +LL | let _ = degrees as f64 * 180.0 / std::f64::consts::PI; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(degrees as f64).to_degrees()` + +error: conversion to degrees can be done more accurately + --> $DIR/floating_point_rad.rs:18:13 + | +LL | let _ = x * 180f32 / std::f32::consts::PI; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.to_degrees()` + +error: conversion to degrees can be done more accurately + --> $DIR/floating_point_rad.rs:19:13 | LL | let _ = 90. * 180f64 / std::f64::consts::PI; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.0_f64.to_degrees()` error: conversion to degrees can be done more accurately - --> $DIR/floating_point_rad.rs:15:13 + --> $DIR/floating_point_rad.rs:20:13 | LL | let _ = 90.5 * 180f64 / std::f64::consts::PI; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.5_f64.to_degrees()` error: conversion to radians can be done more accurately - --> $DIR/floating_point_rad.rs:16:13 + --> $DIR/floating_point_rad.rs:21:13 | LL | let _ = x * std::f32::consts::PI / 180f32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.to_radians()` error: conversion to radians can be done more accurately - --> $DIR/floating_point_rad.rs:17:13 + --> $DIR/floating_point_rad.rs:22:13 | LL | let _ = 90. * std::f32::consts::PI / 180f32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.0_f64.to_radians()` error: conversion to radians can be done more accurately - --> $DIR/floating_point_rad.rs:18:13 + --> $DIR/floating_point_rad.rs:23:13 | LL | let _ = 90.5 * std::f32::consts::PI / 180f32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.5_f64.to_radians()` -error: aborting due to 6 previous errors +error: aborting due to 8 previous errors From 8b53abd60208614f0ab8d85be022f59e55f2a3ce Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 29 Aug 2022 08:05:04 -0400 Subject: [PATCH 3918/5092] interpret: fix unnecessary allocation in validation visitor --- compiler/rustc_const_eval/src/interpret/validity.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 5f77c9b88927..2d096199e912 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -5,7 +5,7 @@ //! to be const-safe. use std::convert::TryFrom; -use std::fmt::Write; +use std::fmt::{Display, Write}; use std::num::NonZeroUsize; use rustc_ast::Mutability; @@ -308,7 +308,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' fn read_immediate( &self, op: &OpTy<'tcx, M::Provenance>, - expected: &str, + expected: impl Display, ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { Ok(try_validation!( self.ecx.read_immediate(op), @@ -321,7 +321,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' fn read_scalar( &self, op: &OpTy<'tcx, M::Provenance>, - expected: &str, + expected: impl Display, ) -> InterpResult<'tcx, Scalar> { Ok(self.read_immediate(op, expected)?.to_scalar()) } @@ -370,7 +370,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' value: &OpTy<'tcx, M::Provenance>, kind: &str, ) -> InterpResult<'tcx> { - let place = self.ecx.ref_to_mplace(&self.read_immediate(value, &format!("a {kind}"))?)?; + let place = + self.ecx.ref_to_mplace(&self.read_immediate(value, format_args!("a {kind}"))?)?; // Handle wide pointers. // Check metadata early, for better diagnostics if place.layout.is_unsized() { From c5a82304cf3ce4460df35a8cd0073c22bf0e5c64 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Mon, 29 Aug 2022 12:07:59 +0000 Subject: [PATCH 3919/5092] Fix `suspicious_to_owned` test when `c_char` is `u8` --- tests/ui/suspicious_to_owned.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ui/suspicious_to_owned.rs b/tests/ui/suspicious_to_owned.rs index a90e78a0ea03..cba21bf4a93a 100644 --- a/tests/ui/suspicious_to_owned.rs +++ b/tests/ui/suspicious_to_owned.rs @@ -2,12 +2,12 @@ #![warn(clippy::implicit_clone)] #![allow(clippy::redundant_clone)] use std::borrow::Cow; -use std::ffi::CStr; +use std::ffi::{c_char, CStr}; fn main() { let moo = "Moooo"; let c_moo = b"Moooo\0"; - let c_moo_ptr = c_moo.as_ptr() as *const i8; + let c_moo_ptr = c_moo.as_ptr() as *const c_char; let moos = ['M', 'o', 'o']; let moos_vec = moos.to_vec(); From 8abe7cbf359521de5395035fdcbf08c65fb28877 Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Mon, 29 Aug 2022 14:41:37 +0200 Subject: [PATCH 3920/5092] Ignore mailto links in linkchecker --- src/tools/linkchecker/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index a7c78d80ccd7..7842611bd4ff 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -215,6 +215,7 @@ impl Checker { || url.starts_with("ftp:") || url.starts_with("irc:") || url.starts_with("data:") + || url.starts_with("mailto:") { report.links_ignored_external += 1; return; From 30979bfe8314372051b3a62e88eb0695eedb512d Mon Sep 17 00:00:00 2001 From: clubby789 Date: Tue, 26 Jul 2022 19:17:21 +0100 Subject: [PATCH 3921/5092] Add lint `cast_slice_from_raw_parts` --- CHANGELOG.md | 1 + .../src/casts/cast_slice_from_raw_parts.rs | 63 +++++++++++++++++++ clippy_lints/src/casts/mod.rs | 29 ++++++++- clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_suspicious.rs | 1 + tests/ui/cast_raw_slice_pointer_cast.fixed | 24 +++++++ tests/ui/cast_raw_slice_pointer_cast.rs | 24 +++++++ tests/ui/cast_raw_slice_pointer_cast.stderr | 46 ++++++++++++++ 9 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 clippy_lints/src/casts/cast_slice_from_raw_parts.rs create mode 100644 tests/ui/cast_raw_slice_pointer_cast.fixed create mode 100644 tests/ui/cast_raw_slice_pointer_cast.rs create mode 100644 tests/ui/cast_raw_slice_pointer_cast.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index a076997eebdf..69ce0a201bfd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3627,6 +3627,7 @@ Released 2018-09-13 [`cast_ref_to_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_ref_to_mut [`cast_sign_loss`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_sign_loss [`cast_slice_different_sizes`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_slice_different_sizes +[`cast_slice_from_raw_parts`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_slice_from_raw_parts [`char_lit_as_u8`]: https://rust-lang.github.io/rust-clippy/master/index.html#char_lit_as_u8 [`chars_last_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_last_cmp [`chars_next_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_next_cmp diff --git a/clippy_lints/src/casts/cast_slice_from_raw_parts.rs b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs new file mode 100644 index 000000000000..284ef165998a --- /dev/null +++ b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs @@ -0,0 +1,63 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{match_def_path, meets_msrv, msrvs, paths}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{def_id::DefId, Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_middle::ty::{self, Ty}; +use rustc_semver::RustcVersion; + +use super::CAST_SLICE_FROM_RAW_PARTS; + +enum RawPartsKind { + Immutable, + Mutable, +} + +fn raw_parts_kind(cx: &LateContext<'_>, did: DefId) -> Option { + if match_def_path(cx, did, &paths::SLICE_FROM_RAW_PARTS) { + Some(RawPartsKind::Immutable) + } else if match_def_path(cx, did, &paths::SLICE_FROM_RAW_PARTS_MUT) { + Some(RawPartsKind::Mutable) + } else { + None + } +} + +pub(super) fn check( + cx: &LateContext<'_>, + expr: &Expr<'_>, + cast_expr: &Expr<'_>, + cast_to: Ty<'_>, + msrv: Option, +) { + if_chain! { + if meets_msrv(msrv, msrvs::PTR_SLICE_RAW_PARTS); + if let ty::RawPtr(ptrty) = cast_to.kind(); + if let ty::Slice(_) = ptrty.ty.kind(); + if let ExprKind::Call(fun, [ptr_arg, len_arg]) = cast_expr.peel_blocks().kind; + if let ExprKind::Path(ref qpath) = fun.kind; + if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id(); + if let Some(rpk) = raw_parts_kind(cx, fun_def_id); + then { + let func = match rpk { + RawPartsKind::Immutable => "from_raw_parts", + RawPartsKind::Mutable => "from_raw_parts_mut" + }; + let span = expr.span; + let mut applicability = Applicability::MachineApplicable; + let ptr = snippet_with_applicability(cx, ptr_arg.span, "ptr", &mut applicability); + let len = snippet_with_applicability(cx, len_arg.span, "len", &mut applicability); + span_lint_and_sugg( + cx, + CAST_SLICE_FROM_RAW_PARTS, + span, + &format!("casting the result of `{func}` to {cast_to}"), + "replace with", + format!("core::ptr::slice_{func}({ptr}, {len})"), + applicability + ); + } + } +} diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 644edefb8fe9..14659eb3d118 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -10,6 +10,7 @@ mod cast_ptr_alignment; mod cast_ref_to_mut; mod cast_sign_loss; mod cast_slice_different_sizes; +mod cast_slice_from_raw_parts; mod char_lit_as_u8; mod fn_to_numeric_cast; mod fn_to_numeric_cast_any; @@ -568,6 +569,31 @@ declare_clippy_lint! { pedantic, "borrowing just to cast to a raw pointer" } +declare_clippy_lint! { + /// **What it does:** Checks for a raw slice being cast to a slice pointer + /// + /// ### Why is this bad? + /// This can result in multiple `&mut` references to the same location when only a pointer is + /// required. + /// `ptr::slice_from_raw_parts` is a safe alternative that doesn't require + /// the same [safety requirements] to be upheld. + /// + /// ### Example + /// ```rust,ignore + /// let _: *const [u8] = std::slice::from_raw_parts(ptr, len) as *const _; + /// let _: *mut [u8] = std::slice::from_raw_parts_mut(ptr, len) as *mut _; + /// ``` + /// Use instead: + /// ```rust,ignore + /// let _: *const [u8] = std::ptr::slice_from_raw_parts(ptr, len); + /// let _: *mut [u8] = std::ptr::slice_from_raw_parts_mut(ptr, len); + /// ``` + /// [safety requirements]: https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html#safety + #[clippy::version = "1.64.0"] + pub CAST_SLICE_FROM_RAW_PARTS, + suspicious, + "casting a slice created from a pointer and length to a slice pointer" +} pub struct Casts { msrv: Option, @@ -600,6 +626,7 @@ impl_lint_pass!(Casts => [ CAST_ABS_TO_UNSIGNED, AS_UNDERSCORE, BORROW_AS_PTR, + CAST_SLICE_FROM_RAW_PARTS ]); impl<'tcx> LateLintPass<'tcx> for Casts { @@ -624,7 +651,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts { if unnecessary_cast::check(cx, expr, cast_expr, cast_from, cast_to) { return; } - + cast_slice_from_raw_parts::check(cx, expr, cast_expr, cast_to, self.msrv); fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, cast_to); fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to); fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to); diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 64982851b567..700762fa3efe 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -25,6 +25,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(casts::CAST_ENUM_TRUNCATION), LintId::of(casts::CAST_REF_TO_MUT), LintId::of(casts::CAST_SLICE_DIFFERENT_SIZES), + LintId::of(casts::CAST_SLICE_FROM_RAW_PARTS), LintId::of(casts::CHAR_LIT_AS_U8), LintId::of(casts::FN_TO_NUMERIC_CAST), LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index fbf77fb734fa..ee94165d2ed0 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -77,6 +77,7 @@ store.register_lints(&[ casts::CAST_REF_TO_MUT, casts::CAST_SIGN_LOSS, casts::CAST_SLICE_DIFFERENT_SIZES, + casts::CAST_SLICE_FROM_RAW_PARTS, casts::CHAR_LIT_AS_U8, casts::FN_TO_NUMERIC_CAST, casts::FN_TO_NUMERIC_CAST_ANY, diff --git a/clippy_lints/src/lib.register_suspicious.rs b/clippy_lints/src/lib.register_suspicious.rs index aa4e571dbe23..8f131bbf98be 100644 --- a/clippy_lints/src/lib.register_suspicious.rs +++ b/clippy_lints/src/lib.register_suspicious.rs @@ -11,6 +11,7 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec! LintId::of(casts::CAST_ABS_TO_UNSIGNED), LintId::of(casts::CAST_ENUM_CONSTRUCTOR), LintId::of(casts::CAST_ENUM_TRUNCATION), + LintId::of(casts::CAST_SLICE_FROM_RAW_PARTS), LintId::of(crate_in_macro_def::CRATE_IN_MACRO_DEF), LintId::of(drop_forget_ref::DROP_NON_DROP), LintId::of(drop_forget_ref::FORGET_NON_DROP), diff --git a/tests/ui/cast_raw_slice_pointer_cast.fixed b/tests/ui/cast_raw_slice_pointer_cast.fixed new file mode 100644 index 000000000000..b70c19129511 --- /dev/null +++ b/tests/ui/cast_raw_slice_pointer_cast.fixed @@ -0,0 +1,24 @@ +// run-rustfix +#![warn(clippy::cast_slice_from_raw_parts)] + +#[allow(unused_imports, unused_unsafe)] +fn main() { + let mut vec = vec![0u8; 1]; + let ptr: *const u8 = vec.as_ptr(); + let mptr = vec.as_mut_ptr(); + let _: *const [u8] = unsafe { core::ptr::slice_from_raw_parts(ptr, 1) }; + let _: *const [u8] = unsafe { core::ptr::slice_from_raw_parts_mut(mptr, 1) }; + let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1); + { + use core::slice; + let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1); + use slice as one; + let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1); + } + { + use std::slice; + let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1); + use slice as one; + let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1); + } +} diff --git a/tests/ui/cast_raw_slice_pointer_cast.rs b/tests/ui/cast_raw_slice_pointer_cast.rs new file mode 100644 index 000000000000..c1b316765c96 --- /dev/null +++ b/tests/ui/cast_raw_slice_pointer_cast.rs @@ -0,0 +1,24 @@ +// run-rustfix +#![warn(clippy::cast_slice_from_raw_parts)] + +#[allow(unused_imports, unused_unsafe)] +fn main() { + let mut vec = vec![0u8; 1]; + let ptr: *const u8 = vec.as_ptr(); + let mptr = vec.as_mut_ptr(); + let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) as *const [u8] }; + let _: *const [u8] = unsafe { std::slice::from_raw_parts_mut(mptr, 1) as *mut [u8] }; + let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) } as *const [u8]; + { + use core::slice; + let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8]; + use slice as one; + let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8]; + } + { + use std::slice; + let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8]; + use slice as one; + let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8]; + } +} diff --git a/tests/ui/cast_raw_slice_pointer_cast.stderr b/tests/ui/cast_raw_slice_pointer_cast.stderr new file mode 100644 index 000000000000..f07801c197cc --- /dev/null +++ b/tests/ui/cast_raw_slice_pointer_cast.stderr @@ -0,0 +1,46 @@ +error: casting the result of `from_raw_parts` to *const [u8] + --> $DIR/cast_raw_slice_pointer_cast.rs:9:35 + | +LL | let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) as *const [u8] }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` + | + = note: `-D clippy::cast-slice-from-raw-parts` implied by `-D warnings` + +error: casting the result of `from_raw_parts_mut` to *mut [u8] + --> $DIR/cast_raw_slice_pointer_cast.rs:10:35 + | +LL | let _: *const [u8] = unsafe { std::slice::from_raw_parts_mut(mptr, 1) as *mut [u8] }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts_mut(mptr, 1)` + +error: casting the result of `from_raw_parts` to *const [u8] + --> $DIR/cast_raw_slice_pointer_cast.rs:11:26 + | +LL | let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) } as *const [u8]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` + +error: casting the result of `from_raw_parts` to *const [u8] + --> $DIR/cast_raw_slice_pointer_cast.rs:14:30 + | +LL | let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` + +error: casting the result of `from_raw_parts` to *const [u8] + --> $DIR/cast_raw_slice_pointer_cast.rs:16:30 + | +LL | let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` + +error: casting the result of `from_raw_parts` to *const [u8] + --> $DIR/cast_raw_slice_pointer_cast.rs:20:30 + | +LL | let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` + +error: casting the result of `from_raw_parts` to *const [u8] + --> $DIR/cast_raw_slice_pointer_cast.rs:22:30 + | +LL | let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` + +error: aborting due to 7 previous errors + From 1383f0e9afa019bdf470e4c6cce4b819f8755aad Mon Sep 17 00:00:00 2001 From: Obei Sideg Date: Mon, 29 Aug 2022 16:53:36 +0300 Subject: [PATCH 3922/5092] Make the trait bound is not satisfied specify kind --- .../src/traits/error_reporting/mod.rs | 37 +++++++++++++++---- .../async-await/issues/issue-62009-1.stderr | 2 +- src/test/ui/binop/issue-77910-1.stderr | 2 +- .../closures/coerce-unsafe-to-closure.stderr | 2 +- .../ui/extern/extern-wrong-value-type.stderr | 2 +- .../intrinsics/const-eval-select-bad.stderr | 2 +- src/test/ui/issues/issue-59488.stderr | 4 +- ...70724-add_type_neq_err_label-unwrap.stderr | 2 +- src/test/ui/issues/issue-99875.rs | 16 ++++++++ src/test/ui/issues/issue-99875.stderr | 33 +++++++++++++++++ src/test/ui/namespace/namespace-mix.stderr | 8 ++-- src/test/ui/proc-macro/signature.stderr | 2 +- .../fn-traits.stderr | 12 +++--- ...rg-where-it-should-have-been-called.stderr | 4 +- ...rg-where-it-should-have-been-called.stderr | 4 +- .../unboxed-closures-unsafe-extern-fn.stderr | 6 +-- .../unboxed-closures-wrong-abi.stderr | 6 +-- ...d-closures-wrong-arg-type-extern-fn.stderr | 6 +-- 18 files changed, 111 insertions(+), 39 deletions(-) create mode 100644 src/test/ui/issues/issue-99875.rs create mode 100644 src/test/ui/issues/issue-99875.stderr diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index e4af7022239b..8910194f3ee1 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -450,12 +450,27 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { { "consider using `()`, or a `Result`".to_owned() } else { - format!( - "{}the trait `{}` is not implemented for `{}`", - pre_message, - trait_predicate.print_modifiers_and_trait_path(), - trait_ref.skip_binder().self_ty(), - ) + let ty_desc = match trait_ref.skip_binder().self_ty().kind() { + ty::FnDef(_, _) => Some("fn item"), + ty::Closure(_, _) => Some("closure"), + _ => None, + }; + + match ty_desc { + Some(desc) => format!( + "{}the trait `{}` is not implemented for {} `{}`", + pre_message, + trait_predicate.print_modifiers_and_trait_path(), + desc, + trait_ref.skip_binder().self_ty(), + ), + None => format!( + "{}the trait `{}` is not implemented for `{}`", + pre_message, + trait_predicate.print_modifiers_and_trait_path(), + trait_ref.skip_binder().self_ty(), + ), + } }; if self.suggest_add_reference_to_arg( @@ -1805,13 +1820,21 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { return false; } if candidates.len() == 1 { + let ty_desc = match candidates[0].self_ty().kind() { + ty::FnPtr(_) => Some("fn pointer"), + _ => None, + }; + let the_desc = match ty_desc { + Some(desc) => format!(" implemented for {} `", desc), + None => " implemented for `".to_string(), + }; err.highlighted_help(vec![ ( format!("the trait `{}` ", candidates[0].print_only_trait_path()), Style::NoStyle, ), ("is".to_string(), Style::Highlight), - (" implemented for `".to_string(), Style::NoStyle), + (the_desc, Style::NoStyle), (candidates[0].self_ty().to_string(), Style::Highlight), ("`".to_string(), Style::NoStyle), ]); diff --git a/src/test/ui/async-await/issues/issue-62009-1.stderr b/src/test/ui/async-await/issues/issue-62009-1.stderr index fb9dee11f2a0..0e323443ae8b 100644 --- a/src/test/ui/async-await/issues/issue-62009-1.stderr +++ b/src/test/ui/async-await/issues/issue-62009-1.stderr @@ -30,7 +30,7 @@ error[E0277]: `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]` is not a future LL | (|_| 2333).await; | ^^^^^^ `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]` is not a future | - = help: the trait `Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]` + = help: the trait `Future` is not implemented for closure `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]` = note: [closure@$DIR/issue-62009-1.rs:12:6: 12:9] must be a future or must implement `IntoFuture` to be awaited = note: required for `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]` to implement `IntoFuture` help: remove the `.await` diff --git a/src/test/ui/binop/issue-77910-1.stderr b/src/test/ui/binop/issue-77910-1.stderr index 68303b842088..097a14f26f86 100644 --- a/src/test/ui/binop/issue-77910-1.stderr +++ b/src/test/ui/binop/issue-77910-1.stderr @@ -18,7 +18,7 @@ LL | fn foo(s: &i32) -> &i32 { LL | assert_eq!(foo, y); | ^^^^^^^^^^^^^^^^^^ `for<'r> fn(&'r i32) -> &'r i32 {foo}` cannot be formatted using `{:?}` because it doesn't implement `Debug` | - = help: the trait `Debug` is not implemented for `for<'r> fn(&'r i32) -> &'r i32 {foo}` + = help: the trait `Debug` is not implemented for fn item `for<'r> fn(&'r i32) -> &'r i32 {foo}` = help: use parentheses to call the function: `foo(s)` = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/closures/coerce-unsafe-to-closure.stderr b/src/test/ui/closures/coerce-unsafe-to-closure.stderr index bd095c2d83d8..6ce63e829b31 100644 --- a/src/test/ui/closures/coerce-unsafe-to-closure.stderr +++ b/src/test/ui/closures/coerce-unsafe-to-closure.stderr @@ -6,7 +6,7 @@ LL | let x: Option<&[u8]> = Some("foo").map(std::mem::transmute); | | | required by a bound introduced by this call | - = help: the trait `FnOnce<(&str,)>` is not implemented for `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}` + = help: the trait `FnOnce<(&str,)>` is not implemented for fn item `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}` = note: unsafe function cannot be called generically without an unsafe block note: required by a bound in `Option::::map` --> $SRC_DIR/core/src/option.rs:LL:COL diff --git a/src/test/ui/extern/extern-wrong-value-type.stderr b/src/test/ui/extern/extern-wrong-value-type.stderr index c6f0d5df9b53..ff2934a2ba88 100644 --- a/src/test/ui/extern/extern-wrong-value-type.stderr +++ b/src/test/ui/extern/extern-wrong-value-type.stderr @@ -6,7 +6,7 @@ LL | is_fn(f); | | | required by a bound introduced by this call | - = help: the trait `Fn<()>` is not implemented for `extern "C" fn() {f}` + = help: the trait `Fn<()>` is not implemented for fn item `extern "C" fn() {f}` = note: wrap the `extern "C" fn() {f}` in a closure with no arguments: `|| { /* code */ }` note: required by a bound in `is_fn` --> $DIR/extern-wrong-value-type.rs:4:28 diff --git a/src/test/ui/intrinsics/const-eval-select-bad.stderr b/src/test/ui/intrinsics/const-eval-select-bad.stderr index 1a761ad5441c..904e83624b3f 100644 --- a/src/test/ui/intrinsics/const-eval-select-bad.stderr +++ b/src/test/ui/intrinsics/const-eval-select-bad.stderr @@ -6,7 +6,7 @@ LL | const_eval_select((), || {}, || {}); | | | required by a bound introduced by this call | - = help: the trait `~const FnOnce<()>` is not implemented for `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]` + = help: the trait `~const FnOnce<()>` is not implemented for closure `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]` note: the trait `FnOnce<()>` is implemented for `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]`, but that implementation is not `const` --> $DIR/const-eval-select-bad.rs:7:27 | diff --git a/src/test/ui/issues/issue-59488.stderr b/src/test/ui/issues/issue-59488.stderr index bb6843a19586..229dfcca47a2 100644 --- a/src/test/ui/issues/issue-59488.stderr +++ b/src/test/ui/issues/issue-59488.stderr @@ -93,7 +93,7 @@ error[E0277]: `fn(usize) -> Foo {Foo::Bar}` doesn't implement `Debug` LL | assert_eq!(Foo::Bar, i); | ^^^^^^^^^^^^^^^^^^^^^^^ `fn(usize) -> Foo {Foo::Bar}` cannot be formatted using `{:?}` because it doesn't implement `Debug` | - = help: the trait `Debug` is not implemented for `fn(usize) -> Foo {Foo::Bar}` + = help: the trait `Debug` is not implemented for fn item `fn(usize) -> Foo {Foo::Bar}` = help: the following other types implement trait `Debug`: extern "C" fn() -> Ret extern "C" fn(A, B) -> Ret @@ -112,7 +112,7 @@ error[E0277]: `fn(usize) -> Foo {Foo::Bar}` doesn't implement `Debug` LL | assert_eq!(Foo::Bar, i); | ^^^^^^^^^^^^^^^^^^^^^^^ `fn(usize) -> Foo {Foo::Bar}` cannot be formatted using `{:?}` because it doesn't implement `Debug` | - = help: the trait `Debug` is not implemented for `fn(usize) -> Foo {Foo::Bar}` + = help: the trait `Debug` is not implemented for fn item `fn(usize) -> Foo {Foo::Bar}` = help: the following other types implement trait `Debug`: extern "C" fn() -> Ret extern "C" fn(A, B) -> Ret diff --git a/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr b/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr index c6e6ea1e096a..b80abad2f67e 100644 --- a/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr +++ b/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr @@ -33,7 +33,7 @@ LL | fn a() -> i32 { LL | assert_eq!(a, 0); | ^^^^^^^^^^^^^^^^ `fn() -> i32 {a}` cannot be formatted using `{:?}` because it doesn't implement `Debug` | - = help: the trait `Debug` is not implemented for `fn() -> i32 {a}` + = help: the trait `Debug` is not implemented for fn item `fn() -> i32 {a}` = help: use parentheses to call the function: `a()` = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/issues/issue-99875.rs b/src/test/ui/issues/issue-99875.rs new file mode 100644 index 000000000000..cf73fd8d31fb --- /dev/null +++ b/src/test/ui/issues/issue-99875.rs @@ -0,0 +1,16 @@ +struct Argument; +struct Return; + +fn function(_: Argument) -> Return { todo!() } + +trait Trait {} +impl Trait for fn(Argument) -> Return {} + +fn takes(_: impl Trait) {} + +fn main() { + takes(function); + //~^ ERROR the trait bound + takes(|_: Argument| -> Return { todo!() }); + //~^ ERROR the trait bound +} diff --git a/src/test/ui/issues/issue-99875.stderr b/src/test/ui/issues/issue-99875.stderr new file mode 100644 index 000000000000..3ff8f12f1b8c --- /dev/null +++ b/src/test/ui/issues/issue-99875.stderr @@ -0,0 +1,33 @@ +error[E0277]: the trait bound `fn(Argument) -> Return {function}: Trait` is not satisfied + --> $DIR/issue-99875.rs:12:11 + | +LL | takes(function); + | ----- ^^^^^^^^ the trait `Trait` is not implemented for fn item `fn(Argument) -> Return {function}` + | | + | required by a bound introduced by this call + | + = help: the trait `Trait` is implemented for fn pointer `fn(Argument) -> Return` +note: required by a bound in `takes` + --> $DIR/issue-99875.rs:9:18 + | +LL | fn takes(_: impl Trait) {} + | ^^^^^ required by this bound in `takes` + +error[E0277]: the trait bound `[closure@$DIR/issue-99875.rs:14:11: 14:34]: Trait` is not satisfied + --> $DIR/issue-99875.rs:14:11 + | +LL | takes(|_: Argument| -> Return { todo!() }); + | ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for closure `[closure@$DIR/issue-99875.rs:14:11: 14:34]` + | | + | required by a bound introduced by this call + | + = help: the trait `Trait` is implemented for fn pointer `fn(Argument) -> Return` +note: required by a bound in `takes` + --> $DIR/issue-99875.rs:9:18 + | +LL | fn takes(_: impl Trait) {} + | ^^^^^ required by this bound in `takes` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/namespace/namespace-mix.stderr b/src/test/ui/namespace/namespace-mix.stderr index b04ea14d1a58..c07914df7273 100644 --- a/src/test/ui/namespace/namespace-mix.stderr +++ b/src/test/ui/namespace/namespace-mix.stderr @@ -218,7 +218,7 @@ error[E0277]: the trait bound `fn() -> c::TS {c::TS}: Impossible` is not satisfi --> $DIR/namespace-mix.rs:56:11 | LL | check(m3::TS); - | ----- ^^^^^^ the trait `Impossible` is not implemented for `fn() -> c::TS {c::TS}` + | ----- ^^^^^^ the trait `Impossible` is not implemented for fn item `fn() -> c::TS {c::TS}` | | | required by a bound introduced by this call | @@ -274,7 +274,7 @@ error[E0277]: the trait bound `fn() -> namespace_mix::c::TS {namespace_mix::c::T --> $DIR/namespace-mix.rs:62:11 | LL | check(xm3::TS); - | ----- ^^^^^^^ the trait `Impossible` is not implemented for `fn() -> namespace_mix::c::TS {namespace_mix::c::TS}` + | ----- ^^^^^^^ the trait `Impossible` is not implemented for fn item `fn() -> namespace_mix::c::TS {namespace_mix::c::TS}` | | | required by a bound introduced by this call | @@ -526,7 +526,7 @@ error[E0277]: the trait bound `fn() -> c::E {c::E::TV}: Impossible` is not satis --> $DIR/namespace-mix.rs:122:11 | LL | check(m9::TV); - | ----- ^^^^^^ the trait `Impossible` is not implemented for `fn() -> c::E {c::E::TV}` + | ----- ^^^^^^ the trait `Impossible` is not implemented for fn item `fn() -> c::E {c::E::TV}` | | | required by a bound introduced by this call | @@ -582,7 +582,7 @@ error[E0277]: the trait bound `fn() -> namespace_mix::c::E {namespace_mix::xm7:: --> $DIR/namespace-mix.rs:128:11 | LL | check(xm9::TV); - | ----- ^^^^^^^ the trait `Impossible` is not implemented for `fn() -> namespace_mix::c::E {namespace_mix::xm7::TV}` + | ----- ^^^^^^^ the trait `Impossible` is not implemented for fn item `fn() -> namespace_mix::c::E {namespace_mix::xm7::TV}` | | | required by a bound introduced by this call | diff --git a/src/test/ui/proc-macro/signature.stderr b/src/test/ui/proc-macro/signature.stderr index 78b0beff0da3..59b3e44c74a5 100644 --- a/src/test/ui/proc-macro/signature.stderr +++ b/src/test/ui/proc-macro/signature.stderr @@ -10,7 +10,7 @@ LL | | } | |_call the function in a closure: `|| unsafe { /* code */ }` | required by a bound introduced by this call | - = help: the trait `Fn<(proc_macro::TokenStream,)>` is not implemented for `unsafe extern "C" fn(i32, u32) -> u32 {foo}` + = help: the trait `Fn<(proc_macro::TokenStream,)>` is not implemented for fn item `unsafe extern "C" fn(i32, u32) -> u32 {foo}` = note: unsafe function cannot be called generically without an unsafe block note: required by a bound in `ProcMacro::custom_derive` --> $SRC_DIR/proc_macro/src/bridge/client.rs:LL:COL diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr index 94a90a568548..fc7bf22775dd 100644 --- a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr @@ -6,7 +6,7 @@ LL | call(foo); | | | required by a bound introduced by this call | - = help: the trait `Fn<()>` is not implemented for `fn() {foo}` + = help: the trait `Fn<()>` is not implemented for fn item `fn() {foo}` = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits note: required by a bound in `call` @@ -23,7 +23,7 @@ LL | call_mut(foo); | | | required by a bound introduced by this call | - = help: the trait `FnMut<()>` is not implemented for `fn() {foo}` + = help: the trait `FnMut<()>` is not implemented for fn item `fn() {foo}` = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits note: required by a bound in `call_mut` @@ -40,7 +40,7 @@ LL | call_once(foo); | | | required by a bound introduced by this call | - = help: the trait `FnOnce<()>` is not implemented for `fn() {foo}` + = help: the trait `FnOnce<()>` is not implemented for fn item `fn() {foo}` = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits note: required by a bound in `call_once` @@ -57,7 +57,7 @@ LL | call(foo_unsafe); | | | required by a bound introduced by this call | - = help: the trait `Fn<()>` is not implemented for `unsafe fn() {foo_unsafe}` + = help: the trait `Fn<()>` is not implemented for fn item `unsafe fn() {foo_unsafe}` = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits note: required by a bound in `call` @@ -74,7 +74,7 @@ LL | call_mut(foo_unsafe); | | | required by a bound introduced by this call | - = help: the trait `FnMut<()>` is not implemented for `unsafe fn() {foo_unsafe}` + = help: the trait `FnMut<()>` is not implemented for fn item `unsafe fn() {foo_unsafe}` = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits note: required by a bound in `call_mut` @@ -91,7 +91,7 @@ LL | call_once(foo_unsafe); | | | required by a bound introduced by this call | - = help: the trait `FnOnce<()>` is not implemented for `unsafe fn() {foo_unsafe}` + = help: the trait `FnOnce<()>` is not implemented for fn item `unsafe fn() {foo_unsafe}` = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits note: required by a bound in `call_once` diff --git a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr index c7d420e0aae8..bfd506c9f6e0 100644 --- a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr +++ b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr @@ -9,7 +9,7 @@ LL | bar(foo); | | | required by a bound introduced by this call | - = help: the trait `Future` is not implemented for `fn() -> impl Future {foo}` + = help: the trait `Future` is not implemented for fn item `fn() -> impl Future {foo}` = note: fn() -> impl Future {foo} must be a future or must implement `IntoFuture` to be awaited note: required by a bound in `bar` --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:7:16 @@ -31,7 +31,7 @@ LL | bar(async_closure); | | | required by a bound introduced by this call | - = help: the trait `Future` is not implemented for `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33]` + = help: the trait `Future` is not implemented for closure `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33]` = note: [closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33] must be a future or must implement `IntoFuture` to be awaited note: required by a bound in `bar` --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:7:16 diff --git a/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr index fb0a6f70bfb4..fe603b67575d 100644 --- a/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr +++ b/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr @@ -5,7 +5,7 @@ LL | fn foo() -> impl T { S } | --- consider calling this function ... LL | bar(foo); - | --- ^^^ the trait `T` is not implemented for `fn() -> impl T {foo}` + | --- ^^^ the trait `T` is not implemented for fn item `fn() -> impl T {foo}` | | | required by a bound introduced by this call | @@ -25,7 +25,7 @@ error[E0277]: the trait bound `[closure@$DIR/fn-ctor-passed-as-arg-where-it-shou LL | let closure = || S; | -- consider calling this closure LL | bar(closure); - | --- ^^^^^^^ the trait `T` is not implemented for `[closure@$DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:18:19: 18:21]` + | --- ^^^^^^^ the trait `T` is not implemented for closure `[closure@$DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:18:19: 18:21]` | | | required by a bound introduced by this call | diff --git a/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr index 18e133957ba3..9833304c636b 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr @@ -6,7 +6,7 @@ LL | let x = call_it(&square, 22); | | | required by a bound introduced by this call | - = help: the trait `for<'r> Fn<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` + = help: the trait `for<'r> Fn<(&'r isize,)>` is not implemented for fn item `for<'r> unsafe fn(&'r isize) -> isize {square}` = note: unsafe function cannot be called generically without an unsafe block note: required by a bound in `call_it` --> $DIR/unboxed-closures-unsafe-extern-fn.rs:9:15 @@ -22,7 +22,7 @@ LL | let y = call_it_mut(&mut square, 22); | | | required by a bound introduced by this call | - = help: the trait `for<'r> FnMut<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` + = help: the trait `for<'r> FnMut<(&'r isize,)>` is not implemented for fn item `for<'r> unsafe fn(&'r isize) -> isize {square}` = note: unsafe function cannot be called generically without an unsafe block note: required by a bound in `call_it_mut` --> $DIR/unboxed-closures-unsafe-extern-fn.rs:12:19 @@ -38,7 +38,7 @@ LL | let z = call_it_once(square, 22); | | | required by a bound introduced by this call | - = help: the trait `for<'r> FnOnce<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` + = help: the trait `for<'r> FnOnce<(&'r isize,)>` is not implemented for fn item `for<'r> unsafe fn(&'r isize) -> isize {square}` = note: unsafe function cannot be called generically without an unsafe block note: required by a bound in `call_it_once` --> $DIR/unboxed-closures-unsafe-extern-fn.rs:15:20 diff --git a/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr b/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr index 77c176de625c..54c92e0cd040 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr @@ -6,7 +6,7 @@ LL | let x = call_it(&square, 22); | | | required by a bound introduced by this call | - = help: the trait `for<'r> Fn<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}` + = help: the trait `for<'r> Fn<(&'r isize,)>` is not implemented for fn item `for<'r> extern "C" fn(&'r isize) -> isize {square}` note: required by a bound in `call_it` --> $DIR/unboxed-closures-wrong-abi.rs:9:15 | @@ -21,7 +21,7 @@ LL | let y = call_it_mut(&mut square, 22); | | | required by a bound introduced by this call | - = help: the trait `for<'r> FnMut<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}` + = help: the trait `for<'r> FnMut<(&'r isize,)>` is not implemented for fn item `for<'r> extern "C" fn(&'r isize) -> isize {square}` note: required by a bound in `call_it_mut` --> $DIR/unboxed-closures-wrong-abi.rs:12:19 | @@ -36,7 +36,7 @@ LL | let z = call_it_once(square, 22); | | | required by a bound introduced by this call | - = help: the trait `for<'r> FnOnce<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}` + = help: the trait `for<'r> FnOnce<(&'r isize,)>` is not implemented for fn item `for<'r> extern "C" fn(&'r isize) -> isize {square}` note: required by a bound in `call_it_once` --> $DIR/unboxed-closures-wrong-abi.rs:15:20 | diff --git a/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr index c826af3c4c38..2fedb5b92c28 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr @@ -6,7 +6,7 @@ LL | let x = call_it(&square, 22); | | | required by a bound introduced by this call | - = help: the trait `for<'r> Fn<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` + = help: the trait `for<'r> Fn<(&'r isize,)>` is not implemented for fn item `unsafe fn(isize) -> isize {square}` = note: unsafe function cannot be called generically without an unsafe block note: required by a bound in `call_it` --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:10:15 @@ -22,7 +22,7 @@ LL | let y = call_it_mut(&mut square, 22); | | | required by a bound introduced by this call | - = help: the trait `for<'r> FnMut<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` + = help: the trait `for<'r> FnMut<(&'r isize,)>` is not implemented for fn item `unsafe fn(isize) -> isize {square}` = note: unsafe function cannot be called generically without an unsafe block note: required by a bound in `call_it_mut` --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:13:19 @@ -38,7 +38,7 @@ LL | let z = call_it_once(square, 22); | | | required by a bound introduced by this call | - = help: the trait `for<'r> FnOnce<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` + = help: the trait `for<'r> FnOnce<(&'r isize,)>` is not implemented for fn item `unsafe fn(isize) -> isize {square}` = note: unsafe function cannot be called generically without an unsafe block note: required by a bound in `call_it_once` --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:16:20 From cc9f2035432135375ae73e3bdfb73e80114b55ea Mon Sep 17 00:00:00 2001 From: clubby789 Date: Mon, 29 Aug 2022 15:17:23 +0100 Subject: [PATCH 3923/5092] Update clippy_lints/src/casts/mod.rs Co-authored-by: Alex Macleod --- clippy_lints/src/casts/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 14659eb3d118..cc5d346b954e 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -570,7 +570,8 @@ declare_clippy_lint! { "borrowing just to cast to a raw pointer" } declare_clippy_lint! { - /// **What it does:** Checks for a raw slice being cast to a slice pointer + /// ### What it does + /// Checks for a raw slice being cast to a slice pointer /// /// ### Why is this bad? /// This can result in multiple `&mut` references to the same location when only a pointer is From 81a583c21e74d600ef8c4b45a3d5088382300e17 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Wed, 3 Aug 2022 22:24:47 +0200 Subject: [PATCH 3924/5092] Try normalizing types without RevealAll in ParamEnv in mir validation Before, the MIR validator used RevealAll in its ParamEnv for type checking. This could cause false negatives in some cases due to RevealAll ParamEnvs not always use all predicates as expected here. Since some MIR passes like inlining use RevealAll as well, keep using it in the MIR validator too, but when it fails usign RevealAll, also try the check without it, to stop false negatives. --- .../src/transform/validate.rs | 30 +++++++++++++------ src/test/ui/mir/issue-99866.rs | 25 ++++++++++++++++ 2 files changed, 46 insertions(+), 9 deletions(-) create mode 100644 src/test/ui/mir/issue-99866.rs diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 45a94972c113..ddde9ff4c028 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -181,16 +181,28 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if (src, dest).has_opaque_types() { return true; } - // Normalize projections and things like that. - let param_env = self.param_env.with_reveal_all_normalized(self.tcx); - let src = self.tcx.normalize_erasing_regions(param_env, src); - let dest = self.tcx.normalize_erasing_regions(param_env, dest); - // Type-changing assignments can happen when subtyping is used. While - // all normal lifetimes are erased, higher-ranked types with their - // late-bound lifetimes are still around and can lead to type - // differences. So we compare ignoring lifetimes. - equal_up_to_regions(self.tcx, param_env, src, dest) + let try_equal_with_param_env = |param_env| { + let src = self.tcx.normalize_erasing_regions(param_env, src); + let dest = self.tcx.normalize_erasing_regions(param_env, dest); + // Type-changing assignments can happen when subtyping is used. While + // all normal lifetimes are erased, higher-ranked types with their + // late-bound lifetimes are still around and can lead to type + // differences. So we compare ignoring lifetimes. + equal_up_to_regions(self.tcx, param_env, src, dest) + }; + + // Normalize projections and things like that. + // First, try with reveal_all. This might not work in some cases, as the predicates + // can be cleared in reveal_all mode. We try the reveal first anyways as it is used + // by some other passes like inlining as well. + let param_env = self.param_env.with_reveal_all_normalized(self.tcx); + if try_equal_with_param_env(param_env) { + true + } else { + // If this fails, we can try it without the reveal. + try_equal_with_param_env(self.param_env) + } } } diff --git a/src/test/ui/mir/issue-99866.rs b/src/test/ui/mir/issue-99866.rs new file mode 100644 index 000000000000..d39ae6ebf1da --- /dev/null +++ b/src/test/ui/mir/issue-99866.rs @@ -0,0 +1,25 @@ +// check-pass +pub trait Backend { + type DescriptorSetLayout; +} + +pub struct Back; + +impl Backend for Back { + type DescriptorSetLayout = u32; +} + +pub struct HalSetLayouts { + vertex_layout: ::DescriptorSetLayout, +} + +impl HalSetLayouts { + pub fn iter(self) -> DSL + where + Back: Backend, + { + self.vertex_layout + } +} + +fn main() {} From 96d4137deed6c52c6db2dd19568c37d1c160f1e7 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sat, 6 Aug 2022 14:22:57 +0200 Subject: [PATCH 3925/5092] Only normalize once in mir validator typechecker Before, it called `normalize_erasing_regions` twice since `equal_up_to_regions` called it as well for both types. --- .../src/transform/validate.rs | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index ddde9ff4c028..69113e57bdc5 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -182,27 +182,22 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { return true; } - let try_equal_with_param_env = |param_env| { - let src = self.tcx.normalize_erasing_regions(param_env, src); - let dest = self.tcx.normalize_erasing_regions(param_env, dest); - // Type-changing assignments can happen when subtyping is used. While - // all normal lifetimes are erased, higher-ranked types with their - // late-bound lifetimes are still around and can lead to type - // differences. So we compare ignoring lifetimes. - equal_up_to_regions(self.tcx, param_env, src, dest) - }; - // Normalize projections and things like that. + // Type-changing assignments can happen when subtyping is used. While + // all normal lifetimes are erased, higher-ranked types with their + // late-bound lifetimes are still around and can lead to type + // differences. So we compare ignoring lifetimes. + // First, try with reveal_all. This might not work in some cases, as the predicates // can be cleared in reveal_all mode. We try the reveal first anyways as it is used // by some other passes like inlining as well. let param_env = self.param_env.with_reveal_all_normalized(self.tcx); - if try_equal_with_param_env(param_env) { - true - } else { - // If this fails, we can try it without the reveal. - try_equal_with_param_env(self.param_env) + if equal_up_to_regions(self.tcx, param_env, src, dest) { + return true; } + + // If this fails, we can try it without the reveal. + equal_up_to_regions(self.tcx, self.param_env, src, dest) } } From 66ec636fec53da9ede460b94f61294a711689fd8 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sun, 28 Aug 2022 12:31:31 +0200 Subject: [PATCH 3926/5092] Highlight namerefs by syntax until proc-macros have been loaded --- crates/rust-analyzer/src/global_state.rs | 2 ++ crates/rust-analyzer/src/handlers.rs | 12 ++++++++++-- crates/rust-analyzer/src/reload.rs | 4 ++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 706e1742dffd..92df4d70fd90 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -116,6 +116,7 @@ pub(crate) struct GlobalStateSnapshot { pub(crate) semantic_tokens_cache: Arc>>, vfs: Arc)>>, pub(crate) workspaces: Arc>, + pub(crate) proc_macros_loaded: bool, } impl std::panic::UnwindSafe for GlobalStateSnapshot {} @@ -256,6 +257,7 @@ impl GlobalState { check_fixes: Arc::clone(&self.diagnostics.check_fixes), mem_docs: self.mem_docs.clone(), semantic_tokens_cache: Arc::clone(&self.semantic_tokens_cache), + proc_macros_loaded: !self.fetch_build_data_queue.last_op_result().0.is_empty(), } } diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index d89f0f5a3cf4..d9b669afbe81 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -1504,7 +1504,11 @@ pub(crate) fn handle_semantic_tokens_full( let text = snap.analysis.file_text(file_id)?; let line_index = snap.file_line_index(file_id)?; - let highlights = snap.analysis.highlight(snap.config.highlighting_config(), file_id)?; + let mut highlight_config = snap.config.highlighting_config(); + // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet. + highlight_config.syntactic_name_ref_highlighting = !snap.proc_macros_loaded; + + let highlights = snap.analysis.highlight(highlight_config, file_id)?; let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); // Unconditionally cache the tokens @@ -1523,7 +1527,11 @@ pub(crate) fn handle_semantic_tokens_full_delta( let text = snap.analysis.file_text(file_id)?; let line_index = snap.file_line_index(file_id)?; - let highlights = snap.analysis.highlight(snap.config.highlighting_config(), file_id)?; + let mut highlight_config = snap.config.highlighting_config(); + // Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet. + highlight_config.syntactic_name_ref_highlighting = !snap.proc_macros_loaded; + + let highlights = snap.analysis.highlight(highlight_config, file_id)?; let semantic_tokens = to_proto::semantic_tokens(&text, &line_index, highlights); let mut cache = snap.semantic_tokens_cache.lock(); diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index ceb2a6d703d9..f23bbca63876 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -347,8 +347,8 @@ impl GlobalState { error }) }) - .collect(); - } + .collect() + }; } let watch = match files_config.watcher { From ce847beb4794a5149a714b21b68347daf27a380c Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sat, 20 Aug 2022 20:40:08 +0200 Subject: [PATCH 3927/5092] Revert let_chains stabilization This reverts commit 326646074940222d602f3683d0559088690830f4. This is the revert against master, the beta revert was already done in #100538. --- clippy_dev/src/lib.rs | 1 + clippy_lints/src/lib.rs | 1 + clippy_utils/src/lib.rs | 1 + tests/ui/needless_late_init.fixed | 1 + tests/ui/needless_late_init.rs | 1 + tests/ui/needless_late_init.stderr | 32 +++++++++++++++--------------- 6 files changed, 21 insertions(+), 16 deletions(-) diff --git a/clippy_dev/src/lib.rs b/clippy_dev/src/lib.rs index 8a6bd1cbdf56..82574a8e64b0 100644 --- a/clippy_dev/src/lib.rs +++ b/clippy_dev/src/lib.rs @@ -1,3 +1,4 @@ +#![feature(let_chains)] #![feature(let_else)] #![feature(once_cell)] #![feature(rustc_private)] diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index e6a405f8170d..ec5c73c13576 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -4,6 +4,7 @@ #![feature(control_flow_enum)] #![feature(drain_filter)] #![feature(iter_intersperse)] +#![feature(let_chains)] #![feature(let_else)] #![feature(lint_reasons)] #![feature(never_type)] diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index f716f009ff3f..313f1f1d9a6f 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -2,6 +2,7 @@ #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(let_else)] +#![feature(let_chains)] #![feature(lint_reasons)] #![feature(once_cell)] #![feature(rustc_private)] diff --git a/tests/ui/needless_late_init.fixed b/tests/ui/needless_late_init.fixed index 4c98e1827bdb..fee8e3030b80 100644 --- a/tests/ui/needless_late_init.fixed +++ b/tests/ui/needless_late_init.fixed @@ -1,4 +1,5 @@ // run-rustfix +#![feature(let_chains)] #![allow( unused, clippy::assign_op_pattern, diff --git a/tests/ui/needless_late_init.rs b/tests/ui/needless_late_init.rs index 25e1e0214fb4..402d9f9ef7f8 100644 --- a/tests/ui/needless_late_init.rs +++ b/tests/ui/needless_late_init.rs @@ -1,4 +1,5 @@ // run-rustfix +#![feature(let_chains)] #![allow( unused, clippy::assign_op_pattern, diff --git a/tests/ui/needless_late_init.stderr b/tests/ui/needless_late_init.stderr index 97f0f7019a9d..313cdbbeba18 100644 --- a/tests/ui/needless_late_init.stderr +++ b/tests/ui/needless_late_init.stderr @@ -1,5 +1,5 @@ error: unneeded late initialization - --> $DIR/needless_late_init.rs:22:5 + --> $DIR/needless_late_init.rs:23:5 | LL | let a; | ^^^^^^ created here @@ -13,7 +13,7 @@ LL | let a = "zero"; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:25:5 + --> $DIR/needless_late_init.rs:26:5 | LL | let b; | ^^^^^^ created here @@ -27,7 +27,7 @@ LL | let b = 1; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:26:5 + --> $DIR/needless_late_init.rs:27:5 | LL | let c; | ^^^^^^ created here @@ -41,7 +41,7 @@ LL | let c = 2; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:30:5 + --> $DIR/needless_late_init.rs:31:5 | LL | let d: usize; | ^^^^^^^^^^^^^ created here @@ -54,7 +54,7 @@ LL | let d: usize = 1; | ~~~~~~~~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:33:5 + --> $DIR/needless_late_init.rs:34:5 | LL | let e; | ^^^^^^ created here @@ -67,7 +67,7 @@ LL | let e = format!("{}", d); | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:38:5 + --> $DIR/needless_late_init.rs:39:5 | LL | let a; | ^^^^^^ @@ -88,7 +88,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:47:5 + --> $DIR/needless_late_init.rs:48:5 | LL | let b; | ^^^^^^ @@ -109,7 +109,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:54:5 + --> $DIR/needless_late_init.rs:55:5 | LL | let d; | ^^^^^^ @@ -130,7 +130,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:62:5 + --> $DIR/needless_late_init.rs:63:5 | LL | let e; | ^^^^^^ @@ -151,7 +151,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:69:5 + --> $DIR/needless_late_init.rs:70:5 | LL | let f; | ^^^^^^ @@ -167,7 +167,7 @@ LL + 1 => "three", | error: unneeded late initialization - --> $DIR/needless_late_init.rs:75:5 + --> $DIR/needless_late_init.rs:76:5 | LL | let g: usize; | ^^^^^^^^^^^^^ @@ -187,7 +187,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:83:5 + --> $DIR/needless_late_init.rs:84:5 | LL | let x; | ^^^^^^ created here @@ -201,7 +201,7 @@ LL | let x = 1; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:87:5 + --> $DIR/needless_late_init.rs:88:5 | LL | let x; | ^^^^^^ created here @@ -215,7 +215,7 @@ LL | let x = SignificantDrop; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:91:5 + --> $DIR/needless_late_init.rs:92:5 | LL | let x; | ^^^^^^ created here @@ -229,7 +229,7 @@ LL | let x = SignificantDrop; | ~~~~~ error: unneeded late initialization - --> $DIR/needless_late_init.rs:110:5 + --> $DIR/needless_late_init.rs:111:5 | LL | let a; | ^^^^^^ @@ -250,7 +250,7 @@ LL | }; | + error: unneeded late initialization - --> $DIR/needless_late_init.rs:127:5 + --> $DIR/needless_late_init.rs:128:5 | LL | let a; | ^^^^^^ From 6eae169ca2206671779b5b405052417a182a47e9 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Mon, 29 Aug 2022 20:39:23 +0200 Subject: [PATCH 3928/5092] unix_sigpipe: Skip some tests on android; libc has no `signal` function If we don't skip these tests, they will fail in CI when `python3 ../x.py --stage 2 test --host= --target arm-linux-androideabi` runs. The failure is: auxiliary/libsigpipe_utils.so: error: undefined reference to 'signal' --- .../ui/attributes/unix_sigpipe/auxiliary/sigpipe-utils.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/test/ui/attributes/unix_sigpipe/auxiliary/sigpipe-utils.rs b/src/test/ui/attributes/unix_sigpipe/auxiliary/sigpipe-utils.rs index 07ff051f789b..e8b4fe7ae523 100644 --- a/src/test/ui/attributes/unix_sigpipe/auxiliary/sigpipe-utils.rs +++ b/src/test/ui/attributes/unix_sigpipe/auxiliary/sigpipe-utils.rs @@ -10,7 +10,12 @@ pub enum SignalHandler { /// Helper to assert that [`libc::SIGPIPE`] has the expected signal handler. pub fn assert_sigpipe_handler(expected_handler: SignalHandler) { #[cfg(unix)] - #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "horizon")))] + #[cfg(not(any( + target_os = "emscripten", + target_os = "fuchsia", + target_os = "horizon", + target_os = "android", + )))] { let prev = unsafe { libc::signal(libc::SIGPIPE, libc::SIG_IGN) }; From 98fe5f7c7d8c2b8b4559fadc7e58844bc4262728 Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Mon, 29 Aug 2022 21:28:35 +0100 Subject: [PATCH 3929/5092] Fix tests due to stricter invalid_value --- tests/ui/uninit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/uninit.rs b/tests/ui/uninit.rs index dac5ce272c02..211317317086 100644 --- a/tests/ui/uninit.rs +++ b/tests/ui/uninit.rs @@ -1,5 +1,5 @@ #![feature(stmt_expr_attributes)] -#![allow(clippy::let_unit_value)] +#![allow(clippy::let_unit_value, invalid_value)] use std::mem::{self, MaybeUninit}; From 9ffc5a5c8d55b536703d414e8772c5942aa8df45 Mon Sep 17 00:00:00 2001 From: Lukas Lueg Date: Mon, 29 Aug 2022 22:36:11 +0200 Subject: [PATCH 3930/5092] Fix more parens for `suboptimal_flops` suggs --- clippy_lints/src/floating_point_arithmetic.rs | 18 +++---- tests/ui/floating_point_exp.fixed | 1 + tests/ui/floating_point_exp.rs | 1 + tests/ui/floating_point_exp.stderr | 12 +++-- tests/ui/floating_point_log.fixed | 1 + tests/ui/floating_point_log.rs | 1 + tests/ui/floating_point_log.stderr | 54 ++++++++++--------- tests/ui/floating_point_logbase.fixed | 1 + tests/ui/floating_point_logbase.rs | 1 + tests/ui/floating_point_logbase.stderr | 12 +++-- tests/ui/floating_point_powf.fixed | 3 ++ tests/ui/floating_point_powf.rs | 3 ++ tests/ui/floating_point_powf.stderr | 52 ++++++++++++------ tests/ui/floating_point_powi.fixed | 1 + tests/ui/floating_point_powi.rs | 1 + tests/ui/floating_point_powi.stderr | 12 +++-- 16 files changed, 115 insertions(+), 59 deletions(-) diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index a052ecb6e04f..bb50e8fcabbb 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -172,7 +172,7 @@ fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { expr.span, "logarithm for bases 2, 10 and e can be computed more accurately", "consider using", - format!("{}.{}()", Sugg::hir(cx, &args[0], ".."), method), + format!("{}.{}()", Sugg::hir(cx, &args[0], "..").maybe_par(), method), Applicability::MachineApplicable, ); } @@ -263,13 +263,13 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { ( SUBOPTIMAL_FLOPS, "square-root of a number can be computed more efficiently and accurately", - format!("{}.sqrt()", Sugg::hir(cx, &args[0], "..")), + format!("{}.sqrt()", Sugg::hir(cx, &args[0], "..").maybe_par()), ) } else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value { ( IMPRECISE_FLOPS, "cube-root of a number can be computed more accurately", - format!("{}.cbrt()", Sugg::hir(cx, &args[0], "..")), + format!("{}.cbrt()", Sugg::hir(cx, &args[0], "..").maybe_par()), ) } else if let Some(exponent) = get_integer_from_float_constant(&value) { ( @@ -277,7 +277,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { "exponentiation with integer powers can be computed more efficiently", format!( "{}.powi({})", - Sugg::hir(cx, &args[0], ".."), + Sugg::hir(cx, &args[0], "..").maybe_par(), numeric_literal::format(&exponent.to_string(), None, false) ), ) @@ -327,7 +327,7 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { "consider using", format!( "{}.mul_add({}, {})", - Sugg::hir(cx, &args[0], ".."), + Sugg::hir(cx, &args[0], "..").maybe_par(), Sugg::hir(cx, &args[0], ".."), Sugg::hir(cx, other_addend, ".."), ), @@ -418,7 +418,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) { "consider using", format!( "{}.exp_m1()", - Sugg::hir(cx, self_arg, "..") + Sugg::hir(cx, self_arg, "..").maybe_par() ), Applicability::MachineApplicable, ); @@ -550,11 +550,11 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) { then { let positive_abs_sugg = ( "manual implementation of `abs` method", - format!("{}.abs()", Sugg::hir(cx, body, "..")), + format!("{}.abs()", Sugg::hir(cx, body, "..").maybe_par()), ); let negative_abs_sugg = ( "manual implementation of negation of `abs` method", - format!("-{}.abs()", Sugg::hir(cx, body, "..")), + format!("-{}.abs()", Sugg::hir(cx, body, "..").maybe_par()), ); let sugg = if is_testing_positive(cx, cond, body) { if if_expr_positive { @@ -621,7 +621,7 @@ fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) { expr.span, "log base can be expressed more clearly", "consider using", - format!("{}.log({})", Sugg::hir(cx, largs_self, ".."), Sugg::hir(cx, rargs_self, ".."),), + format!("{}.log({})", Sugg::hir(cx, largs_self, "..").maybe_par(), Sugg::hir(cx, rargs_self, ".."),), Applicability::MachineApplicable, ); } diff --git a/tests/ui/floating_point_exp.fixed b/tests/ui/floating_point_exp.fixed index ae7805fdf018..c86a502d15f0 100644 --- a/tests/ui/floating_point_exp.fixed +++ b/tests/ui/floating_point_exp.fixed @@ -5,6 +5,7 @@ fn main() { let x = 2f32; let _ = x.exp_m1(); let _ = x.exp_m1() + 2.0; + let _ = (x as f32).exp_m1() + 2.0; // Cases where the lint shouldn't be applied let _ = x.exp() - 2.0; let _ = x.exp() - 1.0 * 2.0; diff --git a/tests/ui/floating_point_exp.rs b/tests/ui/floating_point_exp.rs index 27e0b9bcbc93..e59589f912a2 100644 --- a/tests/ui/floating_point_exp.rs +++ b/tests/ui/floating_point_exp.rs @@ -5,6 +5,7 @@ fn main() { let x = 2f32; let _ = x.exp() - 1.0; let _ = x.exp() - 1.0 + 2.0; + let _ = (x as f32).exp() - 1.0 + 2.0; // Cases where the lint shouldn't be applied let _ = x.exp() - 2.0; let _ = x.exp() - 1.0 * 2.0; diff --git a/tests/ui/floating_point_exp.stderr b/tests/ui/floating_point_exp.stderr index 5cd999ad47cd..f84eede19872 100644 --- a/tests/ui/floating_point_exp.stderr +++ b/tests/ui/floating_point_exp.stderr @@ -13,16 +13,22 @@ LL | let _ = x.exp() - 1.0 + 2.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` error: (e.pow(x) - 1) can be computed more accurately - --> $DIR/floating_point_exp.rs:13:13 + --> $DIR/floating_point_exp.rs:8:13 + | +LL | let _ = (x as f32).exp() - 1.0 + 2.0; + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).exp_m1()` + +error: (e.pow(x) - 1) can be computed more accurately + --> $DIR/floating_point_exp.rs:14:13 | LL | let _ = x.exp() - 1.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` error: (e.pow(x) - 1) can be computed more accurately - --> $DIR/floating_point_exp.rs:14:13 + --> $DIR/floating_point_exp.rs:15:13 | LL | let _ = x.exp() - 1.0 + 2.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors diff --git a/tests/ui/floating_point_log.fixed b/tests/ui/floating_point_log.fixed index 5b487bb8fcf7..4def9300bb7d 100644 --- a/tests/ui/floating_point_log.fixed +++ b/tests/ui/floating_point_log.fixed @@ -12,6 +12,7 @@ fn check_log_base() { let _ = x.ln(); let _ = x.log2(); let _ = x.ln(); + let _ = (x as f32).log2(); let x = 1f64; let _ = x.log2(); diff --git a/tests/ui/floating_point_log.rs b/tests/ui/floating_point_log.rs index 01181484e7de..1e04caa7d2a8 100644 --- a/tests/ui/floating_point_log.rs +++ b/tests/ui/floating_point_log.rs @@ -12,6 +12,7 @@ fn check_log_base() { let _ = x.log(std::f32::consts::E); let _ = x.log(TWO); let _ = x.log(E); + let _ = (x as f32).log(2f32); let x = 1f64; let _ = x.log(2f64); diff --git a/tests/ui/floating_point_log.stderr b/tests/ui/floating_point_log.stderr index 96e5a1544417..89800a13a6ec 100644 --- a/tests/ui/floating_point_log.stderr +++ b/tests/ui/floating_point_log.stderr @@ -31,25 +31,31 @@ LL | let _ = x.log(E); | ^^^^^^^^ help: consider using: `x.ln()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_log.rs:17:13 + --> $DIR/floating_point_log.rs:15:13 + | +LL | let _ = (x as f32).log(2f32); + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).log2()` + +error: logarithm for bases 2, 10 and e can be computed more accurately + --> $DIR/floating_point_log.rs:18:13 | LL | let _ = x.log(2f64); | ^^^^^^^^^^^ help: consider using: `x.log2()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_log.rs:18:13 + --> $DIR/floating_point_log.rs:19:13 | LL | let _ = x.log(10f64); | ^^^^^^^^^^^^ help: consider using: `x.log10()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> $DIR/floating_point_log.rs:19:13 + --> $DIR/floating_point_log.rs:20:13 | LL | let _ = x.log(std::f64::consts::E); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.ln()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:24:13 + --> $DIR/floating_point_log.rs:25:13 | LL | let _ = (1f32 + 2.).ln(); | ^^^^^^^^^^^^^^^^ help: consider using: `2.0f32.ln_1p()` @@ -57,118 +63,118 @@ LL | let _ = (1f32 + 2.).ln(); = note: `-D clippy::imprecise-flops` implied by `-D warnings` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:25:13 + --> $DIR/floating_point_log.rs:26:13 | LL | let _ = (1f32 + 2.0).ln(); | ^^^^^^^^^^^^^^^^^ help: consider using: `2.0f32.ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:26:13 + --> $DIR/floating_point_log.rs:27:13 | LL | let _ = (1.0 + x).ln(); | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:27:13 + --> $DIR/floating_point_log.rs:28:13 | LL | let _ = (1.0 + x / 2.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:28:13 + --> $DIR/floating_point_log.rs:29:13 | LL | let _ = (1.0 + x.powi(3)).ln(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:29:13 + --> $DIR/floating_point_log.rs:30:13 | LL | let _ = (1.0 + x.powi(3) / 2.0).ln(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x.powi(3) / 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:30:13 + --> $DIR/floating_point_log.rs:31:13 | LL | let _ = (1.0 + (std::f32::consts::E - 1.0)).ln(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(std::f32::consts::E - 1.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:31:13 + --> $DIR/floating_point_log.rs:32:13 | LL | let _ = (x + 1.0).ln(); | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:32:13 + --> $DIR/floating_point_log.rs:33:13 | LL | let _ = (x.powi(3) + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:33:13 + --> $DIR/floating_point_log.rs:34:13 | LL | let _ = (x + 2.0 + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x + 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:34:13 + --> $DIR/floating_point_log.rs:35:13 | LL | let _ = (x / 2.0 + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:42:13 + --> $DIR/floating_point_log.rs:43:13 | LL | let _ = (1f64 + 2.).ln(); | ^^^^^^^^^^^^^^^^ help: consider using: `2.0f64.ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:43:13 + --> $DIR/floating_point_log.rs:44:13 | LL | let _ = (1f64 + 2.0).ln(); | ^^^^^^^^^^^^^^^^^ help: consider using: `2.0f64.ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:44:13 + --> $DIR/floating_point_log.rs:45:13 | LL | let _ = (1.0 + x).ln(); | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:45:13 + --> $DIR/floating_point_log.rs:46:13 | LL | let _ = (1.0 + x / 2.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:46:13 + --> $DIR/floating_point_log.rs:47:13 | LL | let _ = (1.0 + x.powi(3)).ln(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:47:13 + --> $DIR/floating_point_log.rs:48:13 | LL | let _ = (x + 1.0).ln(); | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:48:13 + --> $DIR/floating_point_log.rs:49:13 | LL | let _ = (x.powi(3) + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:49:13 + --> $DIR/floating_point_log.rs:50:13 | LL | let _ = (x + 2.0 + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x + 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> $DIR/floating_point_log.rs:50:13 + --> $DIR/floating_point_log.rs:51:13 | LL | let _ = (x / 2.0 + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()` -error: aborting due to 28 previous errors +error: aborting due to 29 previous errors diff --git a/tests/ui/floating_point_logbase.fixed b/tests/ui/floating_point_logbase.fixed index 13962a272d45..936462f94066 100644 --- a/tests/ui/floating_point_logbase.fixed +++ b/tests/ui/floating_point_logbase.fixed @@ -5,6 +5,7 @@ fn main() { let x = 3f32; let y = 5f32; let _ = x.log(y); + let _ = (x as f32).log(y); let _ = x.log(y); let _ = x.log(y); let _ = x.log(y); diff --git a/tests/ui/floating_point_logbase.rs b/tests/ui/floating_point_logbase.rs index 26bc20d5370b..0b56fa8fa41f 100644 --- a/tests/ui/floating_point_logbase.rs +++ b/tests/ui/floating_point_logbase.rs @@ -5,6 +5,7 @@ fn main() { let x = 3f32; let y = 5f32; let _ = x.ln() / y.ln(); + let _ = (x as f32).ln() / y.ln(); let _ = x.log2() / y.log2(); let _ = x.log10() / y.log10(); let _ = x.log(5f32) / y.log(5f32); diff --git a/tests/ui/floating_point_logbase.stderr b/tests/ui/floating_point_logbase.stderr index 78354c2f62d4..384e3554cbbe 100644 --- a/tests/ui/floating_point_logbase.stderr +++ b/tests/ui/floating_point_logbase.stderr @@ -9,20 +9,26 @@ LL | let _ = x.ln() / y.ln(); error: log base can be expressed more clearly --> $DIR/floating_point_logbase.rs:8:13 | +LL | let _ = (x as f32).ln() / y.ln(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).log(y)` + +error: log base can be expressed more clearly + --> $DIR/floating_point_logbase.rs:9:13 + | LL | let _ = x.log2() / y.log2(); | ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: log base can be expressed more clearly - --> $DIR/floating_point_logbase.rs:9:13 + --> $DIR/floating_point_logbase.rs:10:13 | LL | let _ = x.log10() / y.log10(); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: log base can be expressed more clearly - --> $DIR/floating_point_logbase.rs:10:13 + --> $DIR/floating_point_logbase.rs:11:13 | LL | let _ = x.log(5f32) / y.log(5f32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors diff --git a/tests/ui/floating_point_powf.fixed b/tests/ui/floating_point_powf.fixed index b0641a100cdc..7efe10a10f9e 100644 --- a/tests/ui/floating_point_powf.fixed +++ b/tests/ui/floating_point_powf.fixed @@ -11,10 +11,13 @@ fn main() { let _ = (-3.1f32).exp(); let _ = x.sqrt(); let _ = x.cbrt(); + let _ = (x as f32).cbrt(); let _ = x.powi(3); let _ = x.powi(-2); let _ = x.powi(16_777_215); let _ = x.powi(-16_777_215); + let _ = (x as f32).powi(-16_777_215); + let _ = (x as f32).powi(3); // Cases where the lint shouldn't be applied let _ = x.powf(2.1); let _ = x.powf(-2.1); diff --git a/tests/ui/floating_point_powf.rs b/tests/ui/floating_point_powf.rs index a0a2c973900f..445080417f2e 100644 --- a/tests/ui/floating_point_powf.rs +++ b/tests/ui/floating_point_powf.rs @@ -11,10 +11,13 @@ fn main() { let _ = std::f32::consts::E.powf(-3.1); let _ = x.powf(1.0 / 2.0); let _ = x.powf(1.0 / 3.0); + let _ = (x as f32).powf(1.0 / 3.0); let _ = x.powf(3.0); let _ = x.powf(-2.0); let _ = x.powf(16_777_215.0); let _ = x.powf(-16_777_215.0); + let _ = (x as f32).powf(-16_777_215.0); + let _ = (x as f32).powf(3.0); // Cases where the lint shouldn't be applied let _ = x.powf(2.1); let _ = x.powf(-2.1); diff --git a/tests/ui/floating_point_powf.stderr b/tests/ui/floating_point_powf.stderr index 2422eb911e90..6ee696e6ada5 100644 --- a/tests/ui/floating_point_powf.stderr +++ b/tests/ui/floating_point_powf.stderr @@ -50,101 +50,119 @@ LL | let _ = x.powf(1.0 / 3.0); | = note: `-D clippy::imprecise-flops` implied by `-D warnings` -error: exponentiation with integer powers can be computed more efficiently +error: cube-root of a number can be computed more accurately --> $DIR/floating_point_powf.rs:14:13 | +LL | let _ = (x as f32).powf(1.0 / 3.0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).cbrt()` + +error: exponentiation with integer powers can be computed more efficiently + --> $DIR/floating_point_powf.rs:15:13 + | LL | let _ = x.powf(3.0); | ^^^^^^^^^^^ help: consider using: `x.powi(3)` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:15:13 + --> $DIR/floating_point_powf.rs:16:13 | LL | let _ = x.powf(-2.0); | ^^^^^^^^^^^^ help: consider using: `x.powi(-2)` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:16:13 + --> $DIR/floating_point_powf.rs:17:13 | LL | let _ = x.powf(16_777_215.0); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(16_777_215)` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:17:13 + --> $DIR/floating_point_powf.rs:18:13 | LL | let _ = x.powf(-16_777_215.0); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(-16_777_215)` +error: exponentiation with integer powers can be computed more efficiently + --> $DIR/floating_point_powf.rs:19:13 + | +LL | let _ = (x as f32).powf(-16_777_215.0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).powi(-16_777_215)` + +error: exponentiation with integer powers can be computed more efficiently + --> $DIR/floating_point_powf.rs:20:13 + | +LL | let _ = (x as f32).powf(3.0); + | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).powi(3)` + error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:25:13 + --> $DIR/floating_point_powf.rs:28:13 | LL | let _ = 2f64.powf(x); | ^^^^^^^^^^^^ help: consider using: `x.exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:26:13 + --> $DIR/floating_point_powf.rs:29:13 | LL | let _ = 2f64.powf(3.1); | ^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:27:13 + --> $DIR/floating_point_powf.rs:30:13 | LL | let _ = 2f64.powf(-3.1); | ^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:28:13 + --> $DIR/floating_point_powf.rs:31:13 | LL | let _ = std::f64::consts::E.powf(x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:29:13 + --> $DIR/floating_point_powf.rs:32:13 | LL | let _ = std::f64::consts::E.powf(3.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:30:13 + --> $DIR/floating_point_powf.rs:33:13 | LL | let _ = std::f64::consts::E.powf(-3.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp()` error: square-root of a number can be computed more efficiently and accurately - --> $DIR/floating_point_powf.rs:31:13 + --> $DIR/floating_point_powf.rs:34:13 | LL | let _ = x.powf(1.0 / 2.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()` error: cube-root of a number can be computed more accurately - --> $DIR/floating_point_powf.rs:32:13 + --> $DIR/floating_point_powf.rs:35:13 | LL | let _ = x.powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:33:13 + --> $DIR/floating_point_powf.rs:36:13 | LL | let _ = x.powf(3.0); | ^^^^^^^^^^^ help: consider using: `x.powi(3)` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:34:13 + --> $DIR/floating_point_powf.rs:37:13 | LL | let _ = x.powf(-2.0); | ^^^^^^^^^^^^ help: consider using: `x.powi(-2)` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:35:13 + --> $DIR/floating_point_powf.rs:38:13 | LL | let _ = x.powf(-2_147_483_648.0); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(-2_147_483_648)` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:36:13 + --> $DIR/floating_point_powf.rs:39:13 | LL | let _ = x.powf(2_147_483_647.0); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2_147_483_647)` -error: aborting due to 24 previous errors +error: aborting due to 27 previous errors diff --git a/tests/ui/floating_point_powi.fixed b/tests/ui/floating_point_powi.fixed index 85f7c531e398..5758db7c6c82 100644 --- a/tests/ui/floating_point_powi.fixed +++ b/tests/ui/floating_point_powi.fixed @@ -8,6 +8,7 @@ fn main() { let y = 4f32; let _ = x.mul_add(x, y); let _ = y.mul_add(y, x); + let _ = (y as f32).mul_add(y as f32, x); let _ = x.mul_add(x, y).sqrt(); let _ = y.mul_add(y, x).sqrt(); // Cases where the lint shouldn't be applied diff --git a/tests/ui/floating_point_powi.rs b/tests/ui/floating_point_powi.rs index ece61d1bec42..5926bf1b0004 100644 --- a/tests/ui/floating_point_powi.rs +++ b/tests/ui/floating_point_powi.rs @@ -8,6 +8,7 @@ fn main() { let y = 4f32; let _ = x.powi(2) + y; let _ = x + y.powi(2); + let _ = x + (y as f32).powi(2); let _ = (x.powi(2) + y).sqrt(); let _ = (x + y.powi(2)).sqrt(); // Cases where the lint shouldn't be applied diff --git a/tests/ui/floating_point_powi.stderr b/tests/ui/floating_point_powi.stderr index 37d840988bb2..a3c74544212b 100644 --- a/tests/ui/floating_point_powi.stderr +++ b/tests/ui/floating_point_powi.stderr @@ -15,14 +15,20 @@ LL | let _ = x + y.powi(2); error: multiply and add expressions can be calculated more efficiently and accurately --> $DIR/floating_point_powi.rs:11:13 | -LL | let _ = (x.powi(2) + y).sqrt(); - | ^^^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, y)` +LL | let _ = x + (y as f32).powi(2); + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(y as f32).mul_add(y as f32, x)` error: multiply and add expressions can be calculated more efficiently and accurately --> $DIR/floating_point_powi.rs:12:13 | +LL | let _ = (x.powi(2) + y).sqrt(); + | ^^^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, y)` + +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_powi.rs:13:13 + | LL | let _ = (x + y.powi(2)).sqrt(); | ^^^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)` -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors From da0d4829bf7ca00fce64ce8563b84299699131b2 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Mon, 29 Aug 2022 17:14:45 -0400 Subject: [PATCH 3931/5092] Use the better FnEntry spans in protector errors --- rust-version | 2 +- src/diagnostics.rs | 3 +- src/machine.rs | 13 ++-- src/stacked_borrows/diagnostics.rs | 64 ++++++------------- src/stacked_borrows/mod.rs | 13 +++- .../fail/stacked_borrows/aliasing_mut1.stderr | 9 ++- .../fail/stacked_borrows/aliasing_mut2.stderr | 13 ++-- .../fail/stacked_borrows/aliasing_mut3.stderr | 8 +-- .../fail/stacked_borrows/aliasing_mut4.stderr | 13 ++-- tests/fail/stacked_borrows/illegal_write6.rs | 2 +- .../stacked_borrows/illegal_write6.stderr | 20 ++---- .../invalidate_against_protector1.stderr | 20 ++---- .../invalidate_against_protector2.stderr | 20 ++---- .../fail/stacked_borrows/newtype_retagging.rs | 2 +- .../stacked_borrows/newtype_retagging.stderr | 17 ++--- 15 files changed, 80 insertions(+), 139 deletions(-) diff --git a/rust-version b/rust-version index 9b8d986c6711..f7e2fa5a33d3 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4065b89b1e7287047d7d6c65e7abd7b8ee70bcf0 +94b2b15e63c5d2b2a6a0910e3dae554ce9415bf9 diff --git a/src/diagnostics.rs b/src/diagnostics.rs index eafe56955d1f..26442da6d655 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -183,9 +183,8 @@ pub fn report_error<'tcx, 'mir>( if let Some((msg, span)) = invalidated { helps.push((Some(span), msg)); } - if let Some([(protector_msg, protector_span), (protection_msg, protection_span)]) = protected { + if let Some((protector_msg, protector_span)) = protected { helps.push((Some(protector_span), protector_msg)); - helps.push((Some(protection_span), protection_msg)); } } helps diff --git a/src/machine.rs b/src/machine.rs index 0862b3b17c6d..4f7e3a6a71b1 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -743,10 +743,15 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } let alloc = alloc.into_owned(); - let stacks = - ecx.machine.stacked_borrows.as_ref().map(|stacked_borrows| { - Stacks::new_allocation(id, alloc.size(), stacked_borrows, kind) - }); + let stacks = ecx.machine.stacked_borrows.as_ref().map(|stacked_borrows| { + Stacks::new_allocation( + id, + alloc.size(), + stacked_borrows, + kind, + ecx.machine.current_span(*ecx.tcx), + ) + }); let race_alloc = ecx.machine.data_race.as_ref().map(|data_race| { data_race::AllocExtra::new_allocation( data_race, diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index 87f0ce741918..b8e777717e97 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -2,7 +2,7 @@ use smallvec::SmallVec; use std::fmt; use rustc_middle::mir::interpret::{alloc_range, AllocId, AllocRange}; -use rustc_span::{Span, SpanData, DUMMY_SP}; +use rustc_span::{Span, SpanData}; use rustc_target::abi::Size; use crate::helpers::CurrentSpan; @@ -14,6 +14,7 @@ use rustc_middle::mir::interpret::InterpError; #[derive(Clone, Debug)] pub struct AllocHistory { id: AllocId, + base: (Item, Span), creations: smallvec::SmallVec<[Creation; 1]>, invalidations: smallvec::SmallVec<[Invalidation; 1]>, protectors: smallvec::SmallVec<[Protection; 1]>, @@ -91,8 +92,6 @@ impl fmt::Display for InvalidationCause { #[derive(Clone, Debug)] struct Protection { - /// The parent tag from which this protected tag was derived. - orig_tag: ProvenanceExtra, tag: SbTag, span: Span, } @@ -101,7 +100,7 @@ struct Protection { pub struct TagHistory { pub created: (String, SpanData), pub invalidated: Option<(String, SpanData)>, - pub protected: Option<([(String, SpanData); 2])>, + pub protected: Option<(String, SpanData)>, } pub struct DiagnosticCxBuilder<'span, 'ecx, 'mir, 'tcx> { @@ -228,9 +227,10 @@ struct DeallocOp { } impl AllocHistory { - pub fn new(id: AllocId) -> Self { + pub fn new(id: AllocId, item: Item, current_span: &mut CurrentSpan<'_, '_, '_>) -> Self { Self { id, + base: (item, current_span.get()), creations: SmallVec::new(), invalidations: SmallVec::new(), protectors: SmallVec::new(), @@ -290,11 +290,7 @@ impl<'span, 'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'span, 'history, 'ecx, 'mir let Operation::Retag(op) = &self.operation else { unreachable!("Protectors can only be created during a retag") }; - self.history.protectors.push(Protection { - orig_tag: op.orig_tag, - tag: op.new_tag, - span: self.current_span.get(), - }); + self.history.protectors.push(Protection { tag: op.new_tag, span: self.current_span.get() }); } pub fn get_logs_relevant_to( @@ -331,6 +327,17 @@ impl<'span, 'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'span, 'history, 'ecx, 'mir None } }) + }).or_else(|| { + // If we didn't find a retag that created this tag, it might be the base tag of + // this allocation. + if self.history.base.0.tag() == tag { + Some(( + format!("{:?} was created here, as a base tag for {:?}", tag, self.history.id), + self.history.base.1.data() + )) + } else { + None + } }) else { // But if we don't have a creation event, this is related to a wildcard, and there // is really nothing we can do to help. @@ -343,40 +350,11 @@ impl<'span, 'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'span, 'history, 'ecx, 'mir let protected = protector_tag .and_then(|protector| { - self.history.protectors.iter().find(|protection| { - protection.tag == protector - }) + self.history.protectors.iter().find(|protection| protection.tag == protector) }) - .and_then(|protection| { - self.history.creations.iter().rev().find_map(|event| { - if ProvenanceExtra::Concrete(event.retag.new_tag) == protection.orig_tag { - Some((protection, event)) - } else { - None - } - }) - }) - .map(|(protection, protection_parent)| { + .map(|protection| { let protected_tag = protection.tag; - [ - ( - format!( - "{tag:?} cannot be used for memory access because that would remove protected tag {protected_tag:?}, protected by this function call", - ), - protection.span.data(), - ), - if protection_parent.retag.new_tag == tag { - (format!("{protected_tag:?} was derived from {tag:?}, the tag used for this memory access"), DUMMY_SP.data()) - } else { - ( - format!( - "{protected_tag:?} was derived from {protected_parent_tag:?}, which in turn was created here", - protected_parent_tag = protection_parent.retag.new_tag, - ), - protection_parent.span.data() - ) - } - ] + (format!("{protected_tag:?} is this argument"), protection.span.data()) }); Some(TagHistory { created, invalidated, protected }) @@ -448,7 +426,7 @@ impl<'span, 'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'span, 'history, 'ecx, 'mir | Operation::Access(AccessOp { tag, .. }) => err_sb_ub( format!( - "not granting access to tag {:?} because incompatible item {:?} is protected by call {:?}", + "not granting access to tag {:?} because that would remove {:?} which is protected because it is an argument of call {:?}", tag, item, call_id ), None, diff --git a/src/stacked_borrows/mod.rs b/src/stacked_borrows/mod.rs index 5cdcaecc17d2..4f7914c5fb0f 100644 --- a/src/stacked_borrows/mod.rs +++ b/src/stacked_borrows/mod.rs @@ -500,13 +500,19 @@ impl<'tcx> Stack { impl<'tcx> Stacks { /// Creates a new stack with an initial tag. For diagnostic purposes, we also need to know /// the [`AllocId`] of the allocation this is associated with. - fn new(size: Size, perm: Permission, tag: SbTag, id: AllocId) -> Self { + fn new( + size: Size, + perm: Permission, + tag: SbTag, + id: AllocId, + current_span: &mut CurrentSpan<'_, '_, '_>, + ) -> Self { let item = Item::new(tag, perm, false); let stack = Stack::new(item); Stacks { stacks: RangeMap::new(size, stack), - history: AllocHistory::new(id), + history: AllocHistory::new(id, item, current_span), exposed_tags: FxHashSet::default(), } } @@ -538,6 +544,7 @@ impl Stacks { size: Size, state: &GlobalState, kind: MemoryKind, + mut current_span: CurrentSpan<'_, '_, '_>, ) -> Self { let mut extra = state.borrow_mut(); let (base_tag, perm) = match kind { @@ -550,7 +557,7 @@ impl Stacks { // Everything else is shared by default. _ => (extra.base_ptr_tag(id), Permission::SharedReadWrite), }; - Stacks::new(size, perm, base_tag, id) + Stacks::new(size, perm, base_tag, id, &mut current_span) } #[inline(always)] diff --git a/tests/fail/stacked_borrows/aliasing_mut1.stderr b/tests/fail/stacked_borrows/aliasing_mut1.stderr index e5be3061b32c..514b1a9901e6 100644 --- a/tests/fail/stacked_borrows/aliasing_mut1.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item [Unique for ] is protected by call ID +error: Undefined Behavior: not granting access to tag because that would remove [Unique for ] which is protected because it is an argument of call ID --> $DIR/aliasing_mut1.rs:LL:CC | LL | pub fn safe(_x: &mut i32, _y: &mut i32) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item [Unique for ] is protected by call ID + | ^^ not granting access to tag because that would remove [Unique for ] which is protected because it is an argument of call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -11,12 +11,11 @@ help: was created by a Unique retag at offsets [0x0..0x4] | LL | let xraw: *mut i32 = unsafe { mem::transmute(&mut x) }; | ^^^^^^ -help: cannot be used for memory access because that would remove protected tag , protected by this function call +help: is this argument --> $DIR/aliasing_mut1.rs:LL:CC | LL | pub fn safe(_x: &mut i32, _y: &mut i32) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: was derived from , the tag used for this memory access + | ^^ = note: backtrace: = note: inside `safe` at $DIR/aliasing_mut1.rs:LL:CC note: inside `main` at $DIR/aliasing_mut1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/aliasing_mut2.stderr b/tests/fail/stacked_borrows/aliasing_mut2.stderr index c3dd3a893c07..5fc56a91f577 100644 --- a/tests/fail/stacked_borrows/aliasing_mut2.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item [SharedReadOnly for ] is protected by call ID +error: Undefined Behavior: not granting access to tag because that would remove [SharedReadOnly for ] which is protected because it is an argument of call ID --> $DIR/aliasing_mut2.rs:LL:CC | LL | pub fn safe(_x: &i32, _y: &mut i32) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item [SharedReadOnly for ] is protected by call ID + | ^^ not granting access to tag because that would remove [SharedReadOnly for ] which is protected because it is an argument of call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -11,16 +11,11 @@ help: was created by a Unique retag at offsets [0x0..0x4] | LL | let xref = &mut x; | ^^^^^^ -help: cannot be used for memory access because that would remove protected tag , protected by this function call +help: is this argument --> $DIR/aliasing_mut2.rs:LL:CC | LL | pub fn safe(_x: &i32, _y: &mut i32) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: was derived from , which in turn was created here - --> $DIR/aliasing_mut2.rs:LL:CC - | -LL | safe_raw(xshr, xraw); - | ^^^^ + | ^^ = note: backtrace: = note: inside `safe` at $DIR/aliasing_mut2.rs:LL:CC note: inside `main` at $DIR/aliasing_mut2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/aliasing_mut3.stderr b/tests/fail/stacked_borrows/aliasing_mut3.stderr index 0fa31260323f..ee38ea417003 100644 --- a/tests/fail/stacked_borrows/aliasing_mut3.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut3.stderr @@ -2,10 +2,10 @@ error: Undefined Behavior: trying to retag from for SharedReadOnly permiss --> $DIR/aliasing_mut3.rs:LL:CC | LL | pub fn safe(_x: &mut i32, _y: &i32) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | trying to retag from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of FnEntry retag at ALLOC[0x0..0x4] + | ^^ + | | + | trying to retag from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of FnEntry retag at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/aliasing_mut4.stderr b/tests/fail/stacked_borrows/aliasing_mut4.stderr index 601422ece302..d5c2e7366967 100644 --- a/tests/fail/stacked_borrows/aliasing_mut4.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut4.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item [SharedReadOnly for ] is protected by call ID +error: Undefined Behavior: not granting access to tag because that would remove [SharedReadOnly for ] which is protected because it is an argument of call ID --> $DIR/aliasing_mut4.rs:LL:CC | LL | pub fn safe(_x: &i32, _y: &mut Cell) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item [SharedReadOnly for ] is protected by call ID + | ^^ not granting access to tag because that would remove [SharedReadOnly for ] which is protected because it is an argument of call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -11,16 +11,11 @@ help: was created by a Unique retag at offsets [0x0..0x4] | LL | let xref = &mut x; | ^^^^^^ -help: cannot be used for memory access because that would remove protected tag , protected by this function call +help: is this argument --> $DIR/aliasing_mut4.rs:LL:CC | LL | pub fn safe(_x: &i32, _y: &mut Cell) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: was derived from , which in turn was created here - --> $DIR/aliasing_mut4.rs:LL:CC - | -LL | safe_raw(xshr, xraw as *mut _); - | ^^^^ + | ^^ = note: backtrace: = note: inside `safe` at $DIR/aliasing_mut4.rs:LL:CC note: inside `main` at $DIR/aliasing_mut4.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_write6.rs b/tests/fail/stacked_borrows/illegal_write6.rs index 1e032840917e..448f1493367a 100644 --- a/tests/fail/stacked_borrows/illegal_write6.rs +++ b/tests/fail/stacked_borrows/illegal_write6.rs @@ -7,6 +7,6 @@ fn main() { fn foo(a: &mut u32, y: *mut u32) -> u32 { *a = 1; let _b = &*a; - unsafe { *y = 2 }; //~ ERROR: /not granting access .* because incompatible item .* is protected/ + unsafe { *y = 2 }; //~ ERROR: /not granting access .* because that would remove .* which is protected/ return *a; } diff --git a/tests/fail/stacked_borrows/illegal_write6.stderr b/tests/fail/stacked_borrows/illegal_write6.stderr index fd3b19adcf5e..56e4bd79d477 100644 --- a/tests/fail/stacked_borrows/illegal_write6.stderr +++ b/tests/fail/stacked_borrows/illegal_write6.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item [Unique for ] is protected by call ID +error: Undefined Behavior: not granting access to tag because that would remove [Unique for ] which is protected because it is an argument of call ID --> $DIR/illegal_write6.rs:LL:CC | LL | unsafe { *y = 2 }; - | ^^^^^^ not granting access to tag because incompatible item [Unique for ] is protected by call ID + | ^^^^^^ not granting access to tag because that would remove [Unique for ] which is protected because it is an argument of call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -11,21 +11,11 @@ help: was created by a SharedReadWrite retag at offsets [0x0..0x4] | LL | let p = x as *mut u32; | ^ -help: cannot be used for memory access because that would remove protected tag , protected by this function call +help: is this argument --> $DIR/illegal_write6.rs:LL:CC | -LL | / fn foo(a: &mut u32, y: *mut u32) -> u32 { -LL | | *a = 1; -LL | | let _b = &*a; -LL | | unsafe { *y = 2 }; -LL | | return *a; -LL | | } - | |_^ -help: was derived from , which in turn was created here - --> $DIR/illegal_write6.rs:LL:CC - | -LL | foo(x, p); - | ^ +LL | fn foo(a: &mut u32, y: *mut u32) -> u32 { + | ^ = note: backtrace: = note: inside `foo` at $DIR/illegal_write6.rs:LL:CC note: inside `main` at $DIR/illegal_write6.rs:LL:CC diff --git a/tests/fail/stacked_borrows/invalidate_against_protector1.stderr b/tests/fail/stacked_borrows/invalidate_against_protector1.stderr index 18236adec882..5e6fd6e02757 100644 --- a/tests/fail/stacked_borrows/invalidate_against_protector1.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_protector1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item [Unique for ] is protected by call ID +error: Undefined Behavior: not granting access to tag because that would remove [Unique for ] which is protected because it is an argument of call ID --> $DIR/invalidate_against_protector1.rs:LL:CC | LL | let _val = unsafe { *x }; - | ^^ not granting access to tag because incompatible item [Unique for ] is protected by call ID + | ^^ not granting access to tag because that would remove [Unique for ] which is protected because it is an argument of call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -11,21 +11,11 @@ help: was created by a SharedReadWrite retag at offsets [0x0..0x4] | LL | let xraw = &mut x as *mut _; | ^^^^^^ -help: cannot be used for memory access because that would remove protected tag , protected by this function call +help: is this argument --> $DIR/invalidate_against_protector1.rs:LL:CC | -LL | / fn inner(x: *mut i32, _y: &mut i32) { -LL | | // If `x` and `y` alias, retagging is fine with this... but we really -LL | | // shouldn't be allowed to use `x` at all because `y` was assumed to be -LL | | // unique for the duration of this call. -LL | | let _val = unsafe { *x }; -LL | | } - | |_^ -help: was derived from , which in turn was created here - --> $DIR/invalidate_against_protector1.rs:LL:CC - | -LL | inner(xraw, xref); - | ^^^^ +LL | fn inner(x: *mut i32, _y: &mut i32) { + | ^^ = note: backtrace: = note: inside `inner` at $DIR/invalidate_against_protector1.rs:LL:CC note: inside `main` at $DIR/invalidate_against_protector1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/invalidate_against_protector2.stderr b/tests/fail/stacked_borrows/invalidate_against_protector2.stderr index 20b9d47bbef3..eab55d2568de 100644 --- a/tests/fail/stacked_borrows/invalidate_against_protector2.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_protector2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item [SharedReadOnly for ] is protected by call ID +error: Undefined Behavior: not granting access to tag because that would remove [SharedReadOnly for ] which is protected because it is an argument of call ID --> $DIR/invalidate_against_protector2.rs:LL:CC | LL | unsafe { *x = 0 }; - | ^^^^^^ not granting access to tag because incompatible item [SharedReadOnly for ] is protected by call ID + | ^^^^^^ not granting access to tag because that would remove [SharedReadOnly for ] which is protected because it is an argument of call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -11,21 +11,11 @@ help: was created by a SharedReadWrite retag at offsets [0x0..0x4] | LL | let xraw = &mut x as *mut _; | ^^^^^^ -help: cannot be used for memory access because that would remove protected tag , protected by this function call +help: is this argument --> $DIR/invalidate_against_protector2.rs:LL:CC | -LL | / fn inner(x: *mut i32, _y: &i32) { -LL | | // If `x` and `y` alias, retagging is fine with this... but we really -LL | | // shouldn't be allowed to write to `x` at all because `y` was assumed to be -LL | | // immutable for the duration of this call. -LL | | unsafe { *x = 0 }; -LL | | } - | |_^ -help: was derived from , which in turn was created here - --> $DIR/invalidate_against_protector2.rs:LL:CC - | -LL | inner(xraw, xref); - | ^^^^ +LL | fn inner(x: *mut i32, _y: &i32) { + | ^^ = note: backtrace: = note: inside `inner` at $DIR/invalidate_against_protector2.rs:LL:CC note: inside `main` at $DIR/invalidate_against_protector2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/newtype_retagging.rs b/tests/fail/stacked_borrows/newtype_retagging.rs index f9cceb761af3..6e7413cff5d4 100644 --- a/tests/fail/stacked_borrows/newtype_retagging.rs +++ b/tests/fail/stacked_borrows/newtype_retagging.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-retag-fields -//@error-pattern: is protected by call +//@error-pattern: which is protected struct Newtype<'a>(&'a mut i32); fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) { diff --git a/tests/fail/stacked_borrows/newtype_retagging.stderr b/tests/fail/stacked_borrows/newtype_retagging.stderr index e75502d36105..7073c8162d16 100644 --- a/tests/fail/stacked_borrows/newtype_retagging.stderr +++ b/tests/fail/stacked_borrows/newtype_retagging.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item [Unique for ] is protected by call ID +error: Undefined Behavior: not granting access to tag because that would remove [Unique for ] which is protected because it is an argument of call ID --> RUSTLIB/alloc/src/boxed.rs:LL:CC | LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item [Unique for ] is protected by call ID + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because that would remove [Unique for ] which is protected because it is an argument of call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -11,18 +11,11 @@ help: was created by a SharedReadWrite retag at offsets [0x0..0x4] | LL | let ptr = Box::into_raw(Box::new(0i32)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: cannot be used for memory access because that would remove protected tag , protected by this function call +help: is this argument --> $DIR/newtype_retagging.rs:LL:CC | -LL | / fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) { -LL | | dealloc(); -LL | | } - | |_^ -help: was derived from , which in turn was created here - --> $DIR/newtype_retagging.rs:LL:CC - | -LL | Newtype(&mut *ptr), - | ^^^^^^^^^^^^^^^^^^ +LL | fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) { + | ^^ = note: backtrace: = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC From e136e02fd97ac5207f1a0d1edd276ef22a1d24c1 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Fri, 26 Aug 2022 19:24:41 -0700 Subject: [PATCH 3932/5092] bootstrap: Add llvm-has-rust-patches target option This is so you can check out an upstream commit in src/llvm-project and have everything just work. --- config.toml.example | 4 ++++ src/bootstrap/config.rs | 3 +++ src/bootstrap/lib.rs | 12 +++++++----- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/config.toml.example b/config.toml.example index b3284050f053..28ccc2c8f14d 100644 --- a/config.toml.example +++ b/config.toml.example @@ -666,6 +666,10 @@ changelog-seen = 2 # target. #llvm-config = (path) +# Override detection of whether this is a Rust-patched LLVM. This would be used +# in conjunction with either an llvm-config or build.submodules = false. +#llvm-has-rust-patches = if llvm-config { false } else { true } + # Normally the build system can find LLVM's FileCheck utility, but if # not, you can specify an explicit file name for it. #llvm-filecheck = "/path/to/llvm-version/bin/FileCheck" diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index ea0f78e2a6be..f98f07b8eba2 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -388,6 +388,7 @@ impl PartialEq<&str> for TargetSelection { pub struct Target { /// Some(path to llvm-config) if using an external LLVM. pub llvm_config: Option, + pub llvm_has_rust_patches: Option, /// Some(path to FileCheck) if one was specified. pub llvm_filecheck: Option, pub llvm_libunwind: Option, @@ -729,6 +730,7 @@ define_config! { default_linker: Option = "default-linker", linker: Option = "linker", llvm_config: Option = "llvm-config", + llvm_has_rust_patches: Option = "llvm-has-rust-patches", llvm_filecheck: Option = "llvm-filecheck", llvm_libunwind: Option = "llvm-libunwind", android_ndk: Option = "android-ndk", @@ -1140,6 +1142,7 @@ impl Config { if let Some(ref s) = cfg.llvm_config { target.llvm_config = Some(config.src.join(s)); } + target.llvm_has_rust_patches = cfg.llvm_has_rust_patches; if let Some(ref s) = cfg.llvm_filecheck { target.llvm_filecheck = Some(config.src.join(s)); } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index cd421c249d8d..751692b46f39 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -112,6 +112,7 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::str; +use config::Target; use filetime::FileTime; use once_cell::sync::OnceCell; @@ -854,12 +855,13 @@ impl Build { /// /// If no custom `llvm-config` was specified then Rust's llvm will be used. fn is_rust_llvm(&self, target: TargetSelection) -> bool { - if self.config.llvm_from_ci && target == self.config.build { - return true; - } - match self.config.target_config.get(&target) { - Some(ref c) => c.llvm_config.is_none(), + Some(Target { llvm_has_rust_patches: Some(patched), .. }) => *patched, + Some(Target { llvm_config, .. }) => { + // If the user set llvm-config we assume Rust is not patched, + // but first check to see if it was configured by llvm-from-ci. + (self.config.llvm_from_ci && target == self.config.build) || llvm_config.is_none() + } None => true, } } From 73958fdf14d965eac2148991af99f0e0ad0c97ad Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Fri, 26 Aug 2022 19:29:39 -0700 Subject: [PATCH 3933/5092] Ignore cargo target folder in src/bootstrap Needed after changes in #97513. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a6625ac2ac4a..79405e377756 100644 --- a/.gitignore +++ b/.gitignore @@ -45,6 +45,7 @@ no_llvm_build /dist/ /unicode-downloads /target +/src/bootstrap/target /src/tools/x/target # Created by default with `src/ci/docker/run.sh` /obj/ From 77eb1aef52c3ec99220347dc56f87911fb3c0198 Mon Sep 17 00:00:00 2001 From: yukang Date: Tue, 30 Aug 2022 09:31:52 +0800 Subject: [PATCH 3934/5092] add UI test for unpretty --- compiler/rustc_driver/src/pretty.rs | 10 +++++----- compiler/rustc_driver/src/session_diagnostics.rs | 7 +++++++ compiler/rustc_error_messages/locales/en-US/driver.ftl | 2 ++ src/test/ui/unpretty/avoid-crash.rs | 4 ++++ src/test/ui/unpretty/avoid-crash.stderr | 4 ++++ 5 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/unpretty/avoid-crash.rs create mode 100644 src/test/ui/unpretty/avoid-crash.stderr diff --git a/compiler/rustc_driver/src/pretty.rs b/compiler/rustc_driver/src/pretty.rs index 21a3a077a10c..faeacd3e4104 100644 --- a/compiler/rustc_driver/src/pretty.rs +++ b/compiler/rustc_driver/src/pretty.rs @@ -1,5 +1,6 @@ //! The various pretty-printing routines. +use crate::session_diagnostics::UnprettyDumpFail; use rustc_ast as ast; use rustc_ast_pretty::pprust; use rustc_errors::ErrorGuaranteed; @@ -362,11 +363,10 @@ fn write_or_print(out: &str, ofile: Option<&Path>, sess: &Session) { None => print!("{}", out), Some(p) => { if let Err(e) = std::fs::write(p, out) { - let mut err = sess.struct_fatal(&format!( - "pretty-print failed to write {} due to error `{e}`", - p.display() - )); - err.emit(); + sess.emit_fatal(UnprettyDumpFail { + path: p.display().to_string(), + err: e.to_string(), + }); } } } diff --git a/compiler/rustc_driver/src/session_diagnostics.rs b/compiler/rustc_driver/src/session_diagnostics.rs index fe64d0fca9b2..e9696792d051 100644 --- a/compiler/rustc_driver/src/session_diagnostics.rs +++ b/compiler/rustc_driver/src/session_diagnostics.rs @@ -31,3 +31,10 @@ pub(crate) struct RLinkRustcVersionMismatch<'a> { #[derive(SessionDiagnostic)] #[diag(driver::rlink_no_a_file)] pub(crate) struct RlinkNotAFile; + +#[derive(SessionDiagnostic)] +#[diag(driver::unpretty_dump_fail)] +pub(crate) struct UnprettyDumpFail { + pub path: String, + pub err: String, +} diff --git a/compiler/rustc_error_messages/locales/en-US/driver.ftl b/compiler/rustc_error_messages/locales/en-US/driver.ftl index 73f084cf3290..8ad198c86c93 100644 --- a/compiler/rustc_error_messages/locales/en-US/driver.ftl +++ b/compiler/rustc_error_messages/locales/en-US/driver.ftl @@ -9,3 +9,5 @@ driver_rlink_encoding_version_mismatch = .rlink file was produced with encoding driver_rlink_rustc_version_mismatch = .rlink file was produced by rustc version `{$rustc_version}`, but the current version is `{$current_version}` driver_rlink_no_a_file = rlink must be a file + +driver_unpretty_dump_fail = pretty-print failed to write `{$path}` due to error `{$err}` diff --git a/src/test/ui/unpretty/avoid-crash.rs b/src/test/ui/unpretty/avoid-crash.rs new file mode 100644 index 000000000000..fd84b70d944c --- /dev/null +++ b/src/test/ui/unpretty/avoid-crash.rs @@ -0,0 +1,4 @@ +// normalize-stderr-test "error `.*`" -> "$$ERROR_MESSAGE" +// compile-flags: -o/tmp/ -Zunpretty=ast-tree + +fn main() {} diff --git a/src/test/ui/unpretty/avoid-crash.stderr b/src/test/ui/unpretty/avoid-crash.stderr new file mode 100644 index 000000000000..11cd3866fa86 --- /dev/null +++ b/src/test/ui/unpretty/avoid-crash.stderr @@ -0,0 +1,4 @@ +error: pretty-print failed to write `/tmp/` due to $ERROR_MESSAGE + +error: aborting due to previous error + From 97b1a6146c630374ddab15f424eb8141dbb88960 Mon Sep 17 00:00:00 2001 From: Donough Liu Date: Mon, 29 Aug 2022 19:06:36 +0100 Subject: [PATCH 3935/5092] Use more `into_iter` rather than `drain(..)` --- compiler/rustc_ast/src/tokenstream.rs | 2 +- .../rustc_data_structures/src/sorted_map.rs | 20 +++++++++---------- compiler/rustc_errors/src/diagnostic.rs | 4 ++-- compiler/rustc_errors/src/translation.rs | 2 +- .../src/diagnostics/diagnostic_builder.rs | 2 +- compiler/rustc_typeck/src/check/writeback.rs | 2 +- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 9e4a22e1fa3c..fd5aa9391976 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -555,7 +555,7 @@ impl TokenStreamBuilder { // Get the first stream, which will become the result stream. // If it's `None`, create an empty stream. - let mut iter = streams.drain(..); + let mut iter = streams.into_iter(); let mut res_stream_lrc = iter.next().unwrap().0; // Append the subsequent elements to the result stream, after diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs index 9efea1228ab2..937cb671573a 100644 --- a/compiler/rustc_data_structures/src/sorted_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map.rs @@ -164,7 +164,7 @@ impl SortedMap { /// It is up to the caller to make sure that the elements are sorted by key /// and that there are no duplicates. #[inline] - pub fn insert_presorted(&mut self, mut elements: Vec<(K, V)>) { + pub fn insert_presorted(&mut self, elements: Vec<(K, V)>) { if elements.is_empty() { return; } @@ -173,28 +173,28 @@ impl SortedMap { let start_index = self.lookup_index_for(&elements[0].0); - let drain = match start_index { + let elements = match start_index { Ok(index) => { - let mut drain = elements.drain(..); - self.data[index] = drain.next().unwrap(); - drain + let mut elements = elements.into_iter(); + self.data[index] = elements.next().unwrap(); + elements } Err(index) => { if index == self.data.len() || elements.last().unwrap().0 < self.data[index].0 { // We can copy the whole range without having to mix with // existing elements. - self.data.splice(index..index, elements.drain(..)); + self.data.splice(index..index, elements.into_iter()); return; } - let mut drain = elements.drain(..); - self.data.insert(index, drain.next().unwrap()); - drain + let mut elements = elements.into_iter(); + self.data.insert(index, elements.next().unwrap()); + elements } }; // Insert the rest - for (k, v) in drain { + for (k, v) in elements { self.insert(k, v); } } diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 506198df4d8e..935a9639231b 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -981,12 +981,12 @@ impl Diagnostic { fn sub_with_highlights>( &mut self, level: Level, - mut message: Vec<(M, Style)>, + message: Vec<(M, Style)>, span: MultiSpan, render_span: Option, ) { let message = message - .drain(..) + .into_iter() .map(|m| (self.subdiagnostic_message_to_diagnostic_message(m.0), m.1)) .collect(); let sub = SubDiagnostic { level, message, span, render_span }; diff --git a/compiler/rustc_errors/src/translation.rs b/compiler/rustc_errors/src/translation.rs index 65338f56d9cc..4f407badb3f9 100644 --- a/compiler/rustc_errors/src/translation.rs +++ b/compiler/rustc_errors/src/translation.rs @@ -21,7 +21,7 @@ pub trait Translate { /// Typically performed once for each diagnostic at the start of `emit_diagnostic` and then /// passed around as a reference thereafter. fn to_fluent_args<'arg>(&self, args: &[DiagnosticArg<'arg>]) -> FluentArgs<'arg> { - FromIterator::from_iter(args.to_vec().drain(..)) + FromIterator::from_iter(args.iter().cloned()) } /// Convert `DiagnosticMessage`s to a string, performing translation if necessary. diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index a4ccfcace192..2a4fe48a8aca 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -239,7 +239,7 @@ impl DiagnosticDeriveBuilder { } } - Ok(tokens.drain(..).collect()) + Ok(tokens.into_iter().collect()) } fn generate_field_attrs_code(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream { diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index ba687bc4da4c..9ecf34e9ad3e 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -501,7 +501,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { if !errors_buffer.is_empty() { errors_buffer.sort_by_key(|diag| diag.span.primary_span()); - for mut diag in errors_buffer.drain(..) { + for mut diag in errors_buffer { self.tcx().sess.diagnostic().emit_diagnostic(&mut diag); } } From 19ef04ff5df281f248ace29741b1054abf224752 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 30 Aug 2022 00:33:56 -0400 Subject: [PATCH 3936/5092] Fix the order of `trait_duplication_in_bounds` * Emit the lint in source order * Make suggestions with multiple traits be in source order rather than alphabetical --- clippy_lints/src/trait_bounds.rs | 34 ++++++++++++++----- tests/ui/trait_duplication_in_bounds.fixed | 4 +-- tests/ui/trait_duplication_in_bounds.stderr | 4 +-- ...ait_duplication_in_bounds_unfixable.stderr | 8 ++--- 4 files changed, 33 insertions(+), 17 deletions(-) diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 0434720f79b5..2ffa022b04f7 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -15,6 +15,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{BytePos, Span}; +use std::collections::hash_map::Entry; declare_clippy_lint! { /// ### What it does @@ -255,7 +256,7 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { then { return Some( rollup_traits(cx, bound_predicate.bounds, "these where clauses contain repeated elements") - .into_keys().map(|trait_ref| (path.res, trait_ref))) + .into_iter().map(|(trait_ref, _)| (path.res, trait_ref))) } } None @@ -295,8 +296,13 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { } } -#[derive(PartialEq, Eq, Hash, Debug)] +#[derive(Clone, PartialEq, Eq, Hash, Debug)] struct ComparableTraitRef(Res, Vec); +impl Default for ComparableTraitRef { + fn default() -> Self { + Self(Res::Err, Vec::new()) + } +} fn get_trait_info_from_bound<'a>(bound: &'a GenericBound<'_>) -> Option<(Res, &'a [PathSegment<'a>], Span)> { if let GenericBound::Trait(t, tbm) = bound { @@ -339,7 +345,7 @@ fn into_comparable_trait_ref(trait_ref: &TraitRef<'_>) -> ComparableTraitRef { ) } -fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) -> FxHashMap { +fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) -> Vec<(ComparableTraitRef, Span)> { let mut map = FxHashMap::default(); let mut repeated_res = false; @@ -351,23 +357,33 @@ fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) - } }; + let mut i = 0usize; for bound in bounds.iter().filter_map(only_comparable_trait_refs) { let (comparable_bound, span_direct) = bound; - if map.insert(comparable_bound, span_direct).is_some() { - repeated_res = true; + match map.entry(comparable_bound) { + Entry::Occupied(_) => repeated_res = true, + Entry::Vacant(e) => { + e.insert((span_direct, i)); + i += 1; + }, } } + // Put bounds in source order + let mut comparable_bounds = vec![Default::default(); map.len()]; + for (k, (v, i)) in map { + comparable_bounds[i] = (k, v); + } + if_chain! { if repeated_res; if let [first_trait, .., last_trait] = bounds; then { let all_trait_span = first_trait.span().to(last_trait.span()); - let mut traits = map.values() - .filter_map(|span| snippet_opt(cx, *span)) + let traits = comparable_bounds.iter() + .filter_map(|&(_, span)| snippet_opt(cx, span)) .collect::>(); - traits.sort_unstable(); let traits = traits.join(" + "); span_lint_and_sugg( @@ -382,5 +398,5 @@ fn rollup_traits(cx: &LateContext<'_>, bounds: &[GenericBound<'_>], msg: &str) - } } - map + comparable_bounds } diff --git a/tests/ui/trait_duplication_in_bounds.fixed b/tests/ui/trait_duplication_in_bounds.fixed index b4e6bf0ea1c2..4ce5d4217822 100644 --- a/tests/ui/trait_duplication_in_bounds.fixed +++ b/tests/ui/trait_duplication_in_bounds.fixed @@ -97,7 +97,7 @@ fn good_generic + GenericTrait>(arg0: T) { unimplemented!(); } -fn bad_generic + GenericTrait>(arg0: T) { +fn bad_generic + GenericTrait>(arg0: T) { unimplemented!(); } @@ -105,7 +105,7 @@ mod foo { pub trait Clone {} } -fn qualified_path(arg0: T) { +fn qualified_path(arg0: T) { unimplemented!(); } diff --git a/tests/ui/trait_duplication_in_bounds.stderr b/tests/ui/trait_duplication_in_bounds.stderr index 86c593811a74..af800ba78880 100644 --- a/tests/ui/trait_duplication_in_bounds.stderr +++ b/tests/ui/trait_duplication_in_bounds.stderr @@ -44,13 +44,13 @@ error: these bounds contain repeated elements --> $DIR/trait_duplication_in_bounds.rs:100:19 | LL | fn bad_generic + GenericTrait + GenericTrait>(arg0: T) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `GenericTrait + GenericTrait` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `GenericTrait + GenericTrait` error: these bounds contain repeated elements --> $DIR/trait_duplication_in_bounds.rs:108:22 | LL | fn qualified_path(arg0: T) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + foo::Clone` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::clone::Clone + foo::Clone` error: aborting due to 8 previous errors diff --git a/tests/ui/trait_duplication_in_bounds_unfixable.stderr b/tests/ui/trait_duplication_in_bounds_unfixable.stderr index aa44114eb6c5..fbd9abb005f1 100644 --- a/tests/ui/trait_duplication_in_bounds_unfixable.stderr +++ b/tests/ui/trait_duplication_in_bounds_unfixable.stderr @@ -1,8 +1,8 @@ error: this trait bound is already specified in the where clause - --> $DIR/trait_duplication_in_bounds_unfixable.rs:6:23 + --> $DIR/trait_duplication_in_bounds_unfixable.rs:6:15 | LL | fn bad_foo(arg0: T, arg1: Z) - | ^^^^^^^ + | ^^^^^ | note: the lint level is defined here --> $DIR/trait_duplication_in_bounds_unfixable.rs:1:9 @@ -12,10 +12,10 @@ LL | #![deny(clippy::trait_duplication_in_bounds)] = help: consider removing this trait bound error: this trait bound is already specified in the where clause - --> $DIR/trait_duplication_in_bounds_unfixable.rs:6:15 + --> $DIR/trait_duplication_in_bounds_unfixable.rs:6:23 | LL | fn bad_foo(arg0: T, arg1: Z) - | ^^^^^ + | ^^^^^^^ | = help: consider removing this trait bound From de6a3ec61a3d7af121bc4894f46516f6ee24932f Mon Sep 17 00:00:00 2001 From: yjhn <54238857+yjhn@users.noreply.github.com> Date: Tue, 30 Aug 2022 12:29:18 +0300 Subject: [PATCH 3937/5092] Make docs formulation more consistent for NonZero{int} Use third person, as it is used for other std documentation. --- library/core/src/num/nonzero.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 6196c4da4e32..1cf306f2103b 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -309,8 +309,8 @@ macro_rules! nonzero_unsigned_operations { ( $( $Ty: ident($Int: ident); )+ ) => { $( impl $Ty { - /// Add an unsigned integer to a non-zero value. - /// Check for overflow and return [`None`] on overflow + /// Adds an unsigned integer to a non-zero value. + /// Checks for overflow and returns [`None`] on overflow. /// As a consequence, the result cannot wrap to zero. /// /// @@ -346,7 +346,7 @@ macro_rules! nonzero_unsigned_operations { } } - /// Add an unsigned integer to a non-zero value. + /// Adds an unsigned integer to a non-zero value. #[doc = concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")] /// /// # Examples @@ -377,7 +377,7 @@ macro_rules! nonzero_unsigned_operations { unsafe { $Ty::new_unchecked(self.get().saturating_add(other)) } } - /// Add an unsigned integer to a non-zero value, + /// Adds an unsigned integer to a non-zero value, /// assuming overflow cannot occur. /// Overflow is unchecked, and it is undefined behaviour to overflow /// *even if the result would wrap to a non-zero value*. @@ -409,7 +409,7 @@ macro_rules! nonzero_unsigned_operations { } /// Returns the smallest power of two greater than or equal to n. - /// Check for overflow and return [`None`] + /// Checks for overflow and returns [`None`] /// if the next power of two is greater than the type’s maximum value. /// As a consequence, the result cannot wrap to zero. /// @@ -545,7 +545,7 @@ macro_rules! nonzero_signed_operations { } /// Checked absolute value. - /// Check for overflow and returns [`None`] if + /// Checks for overflow and returns [`None`] if #[doc = concat!("`self == ", stringify!($Int), "::MIN`.")] /// The result cannot be zero. /// @@ -740,8 +740,8 @@ macro_rules! nonzero_unsigned_signed_operations { ( $( $signedness:ident $Ty: ident($Int: ty); )+ ) => { $( impl $Ty { - /// Multiply two non-zero integers together. - /// Check for overflow and return [`None`] on overflow. + /// Multiplies two non-zero integers together. + /// Checks for overflow and returns [`None`] on overflow. /// As a consequence, the result cannot wrap to zero. /// /// # Examples @@ -777,7 +777,7 @@ macro_rules! nonzero_unsigned_signed_operations { } } - /// Multiply two non-zero integers together. + /// Multiplies two non-zero integers together. #[doc = concat!("Return [`", stringify!($Int), "::MAX`] on overflow.")] /// /// # Examples @@ -809,7 +809,7 @@ macro_rules! nonzero_unsigned_signed_operations { unsafe { $Ty::new_unchecked(self.get().saturating_mul(other.get())) } } - /// Multiply two non-zero integers together, + /// Multiplies two non-zero integers together, /// assuming overflow cannot occur. /// Overflow is unchecked, and it is undefined behaviour to overflow /// *even if the result would wrap to a non-zero value*. @@ -849,8 +849,8 @@ macro_rules! nonzero_unsigned_signed_operations { unsafe { $Ty::new_unchecked(self.get().unchecked_mul(other.get())) } } - /// Raise non-zero value to an integer power. - /// Check for overflow and return [`None`] on overflow. + /// Raises non-zero value to an integer power. + /// Checks for overflow and returns [`None`] on overflow. /// As a consequence, the result cannot wrap to zero. /// /// # Examples From 5f132e666db7290e3414d12a71e410afc7e13df3 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 30 Aug 2022 09:42:12 +0000 Subject: [PATCH 3938/5092] feat: Add a "Unmerge match arm" assist to split or-patterns inside match expressions --- .../src/handlers/unmerge_match_arm.rs | 293 ++++++++++++++++++ crates/ide-assists/src/lib.rs | 2 + crates/ide-assists/src/tests/generated.rs | 26 ++ 3 files changed, 321 insertions(+) create mode 100644 crates/ide-assists/src/handlers/unmerge_match_arm.rs diff --git a/crates/ide-assists/src/handlers/unmerge_match_arm.rs b/crates/ide-assists/src/handlers/unmerge_match_arm.rs new file mode 100644 index 000000000000..9565f0ee6f26 --- /dev/null +++ b/crates/ide-assists/src/handlers/unmerge_match_arm.rs @@ -0,0 +1,293 @@ +use syntax::{ + algo::neighbor, + ast::{self, edit::IndentLevel, make, AstNode}, + ted::{self, Position}, + Direction, SyntaxKind, T, +}; + +use crate::{AssistContext, AssistId, AssistKind, Assists}; + +// Assist: unmerge_match_arm +// +// Splits the current match with a `|` pattern into two arms with identical bodies. +// +// ``` +// enum Action { Move { distance: u32 }, Stop } +// +// fn handle(action: Action) { +// match action { +// Action::Move(..) $0| Action::Stop => foo(), +// } +// } +// ``` +// -> +// ``` +// enum Action { Move { distance: u32 }, Stop } +// +// fn handle(action: Action) { +// match action { +// Action::Move(..) => foo(), +// Action::Stop => foo(), +// } +// } +// ``` +pub(crate) fn unmerge_match_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let pipe_token = ctx.find_token_syntax_at_offset(T![|])?; + let or_pat = ast::OrPat::cast(pipe_token.parent()?)?.clone_for_update(); + let match_arm = ast::MatchArm::cast(or_pat.syntax().parent()?)?; + let match_arm_body = match_arm.expr()?; + + // We don't need to check for leading pipe because it is directly under `MatchArm` + // without `OrPat`. + + let new_parent = match_arm.syntax().parent()?; + let old_parent_range = new_parent.text_range(); + + acc.add( + AssistId("unmerge_match_arm", AssistKind::RefactorRewrite), + "Unmerge match arm", + pipe_token.text_range(), + |edit| { + let pats_after = pipe_token + .siblings_with_tokens(Direction::Next) + .filter_map(|it| ast::Pat::cast(it.into_node()?)); + // FIXME: We should add a leading pipe if the original arm has one. + let new_match_arm = make::match_arm( + pats_after, + match_arm.guard().and_then(|guard| guard.condition()), + match_arm_body, + ) + .clone_for_update(); + + let mut pipe_index = pipe_token.index(); + if pipe_token + .prev_sibling_or_token() + .map_or(false, |it| it.kind() == SyntaxKind::WHITESPACE) + { + pipe_index -= 1; + } + or_pat.syntax().splice_children( + pipe_index..or_pat.syntax().children_with_tokens().count(), + Vec::new(), + ); + + let mut insert_after_old_arm = Vec::new(); + + // A comma can be: + // - After the arm. In this case we always want to insert a comma after the newly + // inserted arm. + // - Missing after the arm, with no arms after. In this case we want to insert a + // comma before the newly inserted arm. It can not be necessary if there arm + // body is a block, but we don't bother to check that. + // - Missing after the arm with arms after, if the arm body is a block. In this case + // we don't want to insert a comma at all. + let has_comma_after = + std::iter::successors(match_arm.syntax().last_child_or_token(), |it| { + it.prev_sibling_or_token() + }) + .map(|it| it.kind()) + .skip_while(|it| it.is_trivia()) + .next() + == Some(T![,]); + let has_arms_after = neighbor(&match_arm, Direction::Next).is_some(); + if !has_comma_after && !has_arms_after { + insert_after_old_arm.push(make::token(T![,]).into()); + } + + let indent = IndentLevel::from_node(match_arm.syntax()); + insert_after_old_arm.push(make::tokens::whitespace(&format!("\n{indent}")).into()); + + insert_after_old_arm.push(new_match_arm.syntax().clone().into()); + + ted::insert_all_raw(Position::after(match_arm.syntax()), insert_after_old_arm); + + if has_comma_after { + ted::insert_raw( + Position::last_child_of(new_match_arm.syntax()), + make::token(T![,]), + ); + } + + edit.replace(old_parent_range, new_parent.to_string()); + }, + ) +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_assist, check_assist_not_applicable}; + + use super::*; + + #[test] + fn unmerge_match_arm_single_pipe() { + check_assist( + unmerge_match_arm, + r#" +#[derive(Debug)] +enum X { A, B, C } + +fn main() { + let x = X::A; + let y = match x { + X::A $0| X::B => { 1i32 } + X::C => { 2i32 } + }; +} +"#, + r#" +#[derive(Debug)] +enum X { A, B, C } + +fn main() { + let x = X::A; + let y = match x { + X::A => { 1i32 } + X::B => { 1i32 } + X::C => { 2i32 } + }; +} +"#, + ); + } + + #[test] + fn unmerge_match_arm_guard() { + check_assist( + unmerge_match_arm, + r#" +#[derive(Debug)] +enum X { A, B, C } + +fn main() { + let x = X::A; + let y = match x { + X::A $0| X::B if true => { 1i32 } + _ => { 2i32 } + }; +} +"#, + r#" +#[derive(Debug)] +enum X { A, B, C } + +fn main() { + let x = X::A; + let y = match x { + X::A if true => { 1i32 } + X::B if true => { 1i32 } + _ => { 2i32 } + }; +} +"#, + ); + } + + #[test] + fn unmerge_match_arm_leading_pipe() { + check_assist_not_applicable( + unmerge_match_arm, + r#" + +fn main() { + let y = match 0 { + |$0 0 => { 1i32 } + 1 => { 2i32 } + }; +} +"#, + ); + } + + #[test] + fn unmerge_match_arm_multiple_pipes() { + check_assist( + unmerge_match_arm, + r#" +#[derive(Debug)] +enum X { A, B, C, D, E } + +fn main() { + let x = X::A; + let y = match x { + X::A | X::B |$0 X::C | X::D => 1i32, + X::E => 2i32, + }; +} +"#, + r#" +#[derive(Debug)] +enum X { A, B, C, D, E } + +fn main() { + let x = X::A; + let y = match x { + X::A | X::B => 1i32, + X::C | X::D => 1i32, + X::E => 2i32, + }; +} +"#, + ); + } + + #[test] + fn unmerge_match_arm_inserts_comma_if_required() { + check_assist( + unmerge_match_arm, + r#" +#[derive(Debug)] +enum X { A, B } + +fn main() { + let x = X::A; + let y = match x { + X::A $0| X::B => 1i32 + }; +} +"#, + r#" +#[derive(Debug)] +enum X { A, B } + +fn main() { + let x = X::A; + let y = match x { + X::A => 1i32, + X::B => 1i32 + }; +} +"#, + ); + } + + #[test] + fn unmerge_match_arm_inserts_comma_if_had_after() { + check_assist( + unmerge_match_arm, + r#" +#[derive(Debug)] +enum X { A, B } + +fn main() { + let x = X::A; + match x { + X::A $0| X::B => {}, + } +} +"#, + r#" +#[derive(Debug)] +enum X { A, B } + +fn main() { + let x = X::A; + match x { + X::A => {}, + X::B => {}, + } +} +"#, + ); + } +} diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index 7fb35143fa2f..c558553b1cbe 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -185,6 +185,7 @@ mod handlers { mod replace_string_with_char; mod replace_turbofish_with_explicit_type; mod split_import; + mod unmerge_match_arm; mod sort_items; mod toggle_ignore; mod unmerge_use; @@ -278,6 +279,7 @@ mod handlers { sort_items::sort_items, split_import::split_import, toggle_ignore::toggle_ignore, + unmerge_match_arm::unmerge_match_arm, unmerge_use::unmerge_use, unnecessary_async::unnecessary_async, unwrap_block::unwrap_block, diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index 22319f36134f..7b2c16806b2b 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -2207,6 +2207,32 @@ fn arithmetics { ) } +#[test] +fn doctest_unmerge_match_arm() { + check_doc_test( + "unmerge_match_arm", + r#####" +enum Action { Move { distance: u32 }, Stop } + +fn handle(action: Action) { + match action { + Action::Move(..) $0| Action::Stop => foo(), + } +} +"#####, + r#####" +enum Action { Move { distance: u32 }, Stop } + +fn handle(action: Action) { + match action { + Action::Move(..) => foo(), + Action::Stop => foo(), + } +} +"#####, + ) +} + #[test] fn doctest_unmerge_use() { check_doc_test( From f9e2ac56e56cd011929b28d20edda8bed33e9a76 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Tue, 30 Aug 2022 20:10:59 +0900 Subject: [PATCH 3939/5092] fix: handle trait methods as inherent methods for trait object types --- crates/hir-ty/src/method_resolution.rs | 22 ++++++++++++++++---- crates/hir-ty/src/tests/method_resolution.rs | 17 +++++++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index 9a63d5013b46..c0ef4b2a9dc8 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -914,9 +914,6 @@ fn iterate_trait_method_candidates( let db = table.db; let env = table.trait_env.clone(); let self_is_array = matches!(self_ty.kind(Interner), chalk_ir::TyKind::Array(..)); - // if ty is `dyn Trait`, the trait doesn't need to be in scope - let inherent_trait = - self_ty.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t)); let env_traits = matches!(self_ty.kind(Interner), TyKind::Placeholder(_)) // if we have `T: Trait` in the param env, the trait doesn't need to be in scope .then(|| { @@ -925,7 +922,7 @@ fn iterate_trait_method_candidates( }) .into_iter() .flatten(); - let traits = inherent_trait.chain(env_traits).chain(traits_in_scope.iter().copied()); + let traits = env_traits.chain(traits_in_scope.iter().copied()); let canonical_self_ty = table.canonicalize(self_ty.clone()).value; @@ -990,6 +987,23 @@ fn iterate_inherent_methods( VisibleFromModule::None => (None, None), }; + // For trait object types, methods of the trait and its super traits are considered inherent + // methods. This matters because these trait methods have higher priority than the other + // traits' methods, which would be considered in `iterate_trait_method_candidates()` after this + // function. + let inherent_traits = + self_ty.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t)); + for t in inherent_traits { + let data = db.trait_data(t); + for &(_, item) in data.items.iter() { + // We don't pass `visible_from_module` as all trait items should be visible from the + // trait object. + if is_valid_candidate(table, name, receiver_ty, item, self_ty, None) { + callback(receiver_adjustments.clone().unwrap_or_default(), item)?; + } + } + } + if let Some(block_id) = block { if let Some(impls) = db.inherent_impls_in_block(block_id) { impls_for_self_ty( diff --git a/crates/hir-ty/src/tests/method_resolution.rs b/crates/hir-ty/src/tests/method_resolution.rs index 81588a7c4ffd..fb2fc9369a79 100644 --- a/crates/hir-ty/src/tests/method_resolution.rs +++ b/crates/hir-ty/src/tests/method_resolution.rs @@ -1218,6 +1218,23 @@ fn main() { ); } +#[test] +fn dyn_trait_method_priority() { + check_types( + r#" +//- minicore: from +trait Trait { + fn into(&self) -> usize { 0 } +} + +fn foo(a: &dyn Trait) { + let _ = a.into(); + //^usize +} + "#, + ); +} + #[test] fn autoderef_visibility_field() { check( From 7ecead23c82f783665aa0bdb2f9ff6d26de545e9 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Mon, 18 Jul 2022 19:49:14 +0900 Subject: [PATCH 3940/5092] fix: sort and deduplicate auto traits in trait object types --- crates/hir-ty/src/lower.rs | 47 +++++++++++++--- crates/hir-ty/src/tests/traits.rs | 92 +++++++++++++++++++++++++++++++ crates/ide/src/inlay_hints.rs | 2 +- 3 files changed, 132 insertions(+), 9 deletions(-) diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index ae115c8c0da8..64a07070f02a 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -1,8 +1,8 @@ //! Methods for lowering the HIR to types. There are two main cases here: //! //! - Lowering a type reference like `&usize` or `Option` to a -//! type: The entry point for this is `Ty::from_hir`. -//! - Building the type for an item: This happens through the `type_for_def` query. +//! type: The entry point for this is `TyLoweringContext::lower_ty`. +//! - Building the type for an item: This happens through the `ty` query. //! //! This usually involves resolving names, collecting generic arguments etc. use std::{ @@ -47,7 +47,7 @@ use crate::{ consteval::{intern_const_scalar, path_to_const, unknown_const, unknown_const_as_generic}, db::HirDatabase, make_binders, - mapping::ToChalk, + mapping::{from_chalk_trait_id, ToChalk}, static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx, utils::Generics, utils::{all_super_trait_refs, associated_type_by_name_including_super_traits, generics}, @@ -969,13 +969,44 @@ impl<'a> TyLoweringContext<'a> { fn lower_dyn_trait(&self, bounds: &[Interned]) -> Ty { let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner); let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { - QuantifiedWhereClauses::from_iter( + let bounds = + bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)); + + let mut auto_traits = SmallVec::<[_; 8]>::new(); + let mut regular_traits = SmallVec::<[_; 2]>::new(); + let mut other_bounds = SmallVec::<[_; 8]>::new(); + for bound in bounds { + if let Some(id) = bound.trait_id() { + if ctx.db.trait_data(from_chalk_trait_id(id)).is_auto { + auto_traits.push(bound); + } else { + regular_traits.push(bound); + } + } else { + other_bounds.push(bound); + } + } + + if regular_traits.len() > 1 { + return None; + } + + auto_traits.sort_unstable_by_key(|b| b.trait_id().unwrap()); + auto_traits.dedup(); + + Some(QuantifiedWhereClauses::from_iter( Interner, - bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)), - ) + regular_traits.into_iter().chain(other_bounds).chain(auto_traits), + )) }); - let bounds = crate::make_single_type_binders(bounds); - TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner) + + if let Some(bounds) = bounds { + let bounds = crate::make_single_type_binders(bounds); + TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner) + } else { + // FIXME: report error (additional non-auto traits) + TyKind::Error.intern(Interner) + } } fn lower_impl_trait( diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs index 0f37970e2b38..e67c27aa2db9 100644 --- a/crates/hir-ty/src/tests/traits.rs +++ b/crates/hir-ty/src/tests/traits.rs @@ -3833,3 +3833,95 @@ fn test() { "#, ) } + +#[test] +fn dyn_multiple_auto_traits_in_different_order() { + check_no_mismatches( + r#" +auto trait Send {} +auto trait Sync {} + +fn f(t: &(dyn Sync + Send)) {} +fn g(t: &(dyn Send + Sync)) { + f(t); +} + "#, + ); + + check_no_mismatches( + r#" +auto trait Send {} +auto trait Sync {} +trait T {} + +fn f(t: &(dyn T + Send + Sync)) {} +fn g(t: &(dyn Sync + T + Send)) { + f(t); +} + "#, + ); + + check_infer_with_mismatches( + r#" +auto trait Send {} +auto trait Sync {} +trait T1 {} +trait T2 {} + +fn f(t: &(dyn T1 + T2 + Send + Sync)) {} +fn g(t: &(dyn Sync + T2 + T1 + Send)) { + f(t); +} + "#, + expect![[r#" + 68..69 't': &{unknown} + 101..103 '{}': () + 109..110 't': &{unknown} + 142..155 '{ f(t); }': () + 148..149 'f': fn f(&{unknown}) + 148..152 'f(t)': () + 150..151 't': &{unknown} + "#]], + ); + + check_no_mismatches( + r#" +auto trait Send {} +auto trait Sync {} +trait T { + type Proj: Send + Sync; +} + +fn f(t: &(dyn T + Send + Sync)) {} +fn g(t: &(dyn Sync + T + Send)) { + f(t); +} + "#, + ); +} + +#[test] +fn dyn_duplicate_auto_trait() { + check_no_mismatches( + r#" +auto trait Send {} + +fn f(t: &(dyn Send + Send)) {} +fn g(t: &(dyn Send)) { + f(t); +} + "#, + ); + + check_no_mismatches( + r#" +auto trait Send {} +trait T {} + +fn f(t: &(dyn T + Send + Send)) {} +fn g(t: &(dyn T + Send)) { + f(t); +} + "#, + ); +} diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index ed19784d1fa4..e9034daefa8d 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -1910,7 +1910,7 @@ impl Vec { pub struct Box {} trait Display {} -trait Sync {} +auto trait Sync {} fn main() { // The block expression wrapping disables the constructor hint hiding logic From 66a97055b2721700b472e4460a560c8ded70b3c2 Mon Sep 17 00:00:00 2001 From: Lukas Lueg Date: Wed, 24 Aug 2022 23:11:19 +0200 Subject: [PATCH 3941/5092] Initial implementation of `result_large_err` --- CHANGELOG.md | 1 + clippy_lints/src/functions/mod.rs | 56 +++++++++- clippy_lints/src/functions/result.rs | 100 ++++++++++++++++++ clippy_lints/src/functions/result_unit_err.rs | 66 ------------ clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_perf.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/utils/conf.rs | 4 + clippy_utils/src/ty.rs | 50 +++++++++ .../toml_unknown_key/conf_unknown_key.stderr | 1 + tests/ui/result_large_err.rs | 98 +++++++++++++++++ tests/ui/result_large_err.stderr | 91 ++++++++++++++++ 13 files changed, 401 insertions(+), 71 deletions(-) create mode 100644 clippy_lints/src/functions/result.rs delete mode 100644 clippy_lints/src/functions/result_unit_err.rs create mode 100644 tests/ui/result_large_err.rs create mode 100644 tests/ui/result_large_err.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 69ce0a201bfd..c488c142e46f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4025,6 +4025,7 @@ Released 2018-09-13 [`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts [`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs [`result_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_expect_used +[`result_large_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err [`result_map_or_into_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_or_into_option [`result_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unit_fn [`result_map_unwrap_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unwrap_or_else diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index 73261fb8a44c..90911e0bf259 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -1,6 +1,6 @@ mod must_use; mod not_unsafe_ptr_arg_deref; -mod result_unit_err; +mod result; mod too_many_arguments; mod too_many_lines; @@ -217,17 +217,62 @@ declare_clippy_lint! { "public function returning `Result` with an `Err` type of `()`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for functions that return `Result` with an unusually large + /// `Err`-variant. + /// + /// ### Why is this bad? + /// A `Result` is at least as large as the `Err`-variant. While we + /// expect that variant to be seldomly used, the compiler needs to reserve + /// and move that much memory every single time. + /// + /// ### Known problems + /// The size determined by Clippy is platform-dependent. + /// + /// ### Examples + /// ```rust + /// pub enum ParseError { + /// UnparsedBytes([u8; 512]), + /// UnexpectedEof, + /// } + /// + /// // The `Result` has at least 512 bytes, even in the `Ok`-case + /// pub fn parse() -> Result<(), ParseError> { + /// Ok(()) + /// } + /// ``` + /// should be + /// ``` + /// pub enum ParseError { + /// UnparsedBytes(Box<[u8; 512]>), + /// UnexpectedEof, + /// } + /// + /// // The `Result` is slightly larger than a pointer + /// pub fn parse() -> Result<(), ParseError> { + /// Ok(()) + /// } + /// ``` + #[clippy::version = "1.64.0"] + pub RESULT_LARGE_ERR, + perf, + "function returning `Result` with large `Err` type" +} + #[derive(Copy, Clone)] pub struct Functions { too_many_arguments_threshold: u64, too_many_lines_threshold: u64, + large_error_threshold: u64, } impl Functions { - pub fn new(too_many_arguments_threshold: u64, too_many_lines_threshold: u64) -> Self { + pub fn new(too_many_arguments_threshold: u64, too_many_lines_threshold: u64, large_error_threshold: u64) -> Self { Self { too_many_arguments_threshold, too_many_lines_threshold, + large_error_threshold, } } } @@ -240,6 +285,7 @@ impl_lint_pass!(Functions => [ DOUBLE_MUST_USE, MUST_USE_CANDIDATE, RESULT_UNIT_ERR, + RESULT_LARGE_ERR, ]); impl<'tcx> LateLintPass<'tcx> for Functions { @@ -259,18 +305,18 @@ impl<'tcx> LateLintPass<'tcx> for Functions { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { must_use::check_item(cx, item); - result_unit_err::check_item(cx, item); + result::check_item(cx, item, self.large_error_threshold); } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) { must_use::check_impl_item(cx, item); - result_unit_err::check_impl_item(cx, item); + result::check_impl_item(cx, item, self.large_error_threshold); } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) { too_many_arguments::check_trait_item(cx, item, self.too_many_arguments_threshold); not_unsafe_ptr_arg_deref::check_trait_item(cx, item); must_use::check_trait_item(cx, item); - result_unit_err::check_trait_item(cx, item); + result::check_trait_item(cx, item, self.large_error_threshold); } } diff --git a/clippy_lints/src/functions/result.rs b/clippy_lints/src/functions/result.rs new file mode 100644 index 000000000000..af520a493eda --- /dev/null +++ b/clippy_lints/src/functions/result.rs @@ -0,0 +1,100 @@ +use rustc_errors::Diagnostic; +use rustc_hir as hir; +use rustc_lint::{LateContext, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::{self, Ty}; +use rustc_span::{sym, Span}; +use rustc_typeck::hir_ty_to_ty; + +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; +use clippy_utils::trait_ref_of_method; +use clippy_utils::ty::{approx_ty_size, is_type_diagnostic_item}; + +use super::{RESULT_LARGE_ERR, RESULT_UNIT_ERR}; + +/// The type of the `Err`-variant in a `std::result::Result` returned by the +/// given `FnDecl` +fn result_err_ty<'tcx>( + cx: &LateContext<'tcx>, + decl: &hir::FnDecl<'tcx>, + item_span: Span, +) -> Option<(&'tcx hir::Ty<'tcx>, Ty<'tcx>)> { + if !in_external_macro(cx.sess(), item_span) + && let hir::FnRetTy::Return(hir_ty) = decl.output + && let ty = hir_ty_to_ty(cx.tcx, hir_ty) + && is_type_diagnostic_item(cx, ty, sym::Result) + && let ty::Adt(_, substs) = ty.kind() + { + let err_ty = substs.type_at(1); + Some((hir_ty, err_ty)) + } else { + None + } +} + +pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, large_err_threshold: u64) { + if let hir::ItemKind::Fn(ref sig, _generics, _) = item.kind + && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.span) + { + if cx.access_levels.is_exported(item.def_id) { + let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); + check_result_unit_err(cx, err_ty, fn_header_span); + } + check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold); + } +} + +pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::ImplItem<'tcx>, large_err_threshold: u64) { + // Don't lint if method is a trait's implementation, we can't do anything about those + if let hir::ImplItemKind::Fn(ref sig, _) = item.kind + && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.span) + && trait_ref_of_method(cx, item.def_id).is_none() + { + if cx.access_levels.is_exported(item.def_id) { + let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); + check_result_unit_err(cx, err_ty, fn_header_span); + } + check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold); + } +} + +pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::TraitItem<'tcx>, large_err_threshold: u64) { + if let hir::TraitItemKind::Fn(ref sig, _) = item.kind { + let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); + if let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.span) { + if cx.access_levels.is_exported(item.def_id) { + check_result_unit_err(cx, err_ty, fn_header_span); + } + check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold); + } + } +} + +fn check_result_unit_err(cx: &LateContext<'_>, err_ty: Ty<'_>, fn_header_span: Span) { + if err_ty.is_unit() { + span_lint_and_help( + cx, + RESULT_UNIT_ERR, + fn_header_span, + "this returns a `Result<_, ()>`", + None, + "use a custom `Error` type instead", + ); + } +} + +fn check_result_large_err<'tcx>(cx: &LateContext<'tcx>, err_ty: Ty<'tcx>, hir_ty_span: Span, large_err_threshold: u64) { + let ty_size = approx_ty_size(cx, err_ty); + if ty_size >= large_err_threshold { + span_lint_and_then( + cx, + RESULT_LARGE_ERR, + hir_ty_span, + "the `Err`-variant returned from this function is very large", + |diag: &mut Diagnostic| { + diag.span_label(hir_ty_span, format!("the `Err`-variant is at least {ty_size} bytes")); + diag.help(format!("try reducing the size of `{err_ty}`, for example by boxing large elements or replacing it with `Box<{err_ty}>`")); + }, + ); + } +} diff --git a/clippy_lints/src/functions/result_unit_err.rs b/clippy_lints/src/functions/result_unit_err.rs deleted file mode 100644 index 2e63a1f920d6..000000000000 --- a/clippy_lints/src/functions/result_unit_err.rs +++ /dev/null @@ -1,66 +0,0 @@ -use rustc_hir as hir; -use rustc_lint::{LateContext, LintContext}; -use rustc_middle::lint::in_external_macro; -use rustc_middle::ty; -use rustc_span::{sym, Span}; -use rustc_typeck::hir_ty_to_ty; - -use if_chain::if_chain; - -use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::trait_ref_of_method; -use clippy_utils::ty::is_type_diagnostic_item; - -use super::RESULT_UNIT_ERR; - -pub(super) fn check_item(cx: &LateContext<'_>, item: &hir::Item<'_>) { - if let hir::ItemKind::Fn(ref sig, _generics, _) = item.kind { - let is_public = cx.access_levels.is_exported(item.def_id); - let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); - if is_public { - check_result_unit_err(cx, sig.decl, item.span, fn_header_span); - } - } -} - -pub(super) fn check_impl_item(cx: &LateContext<'_>, item: &hir::ImplItem<'_>) { - if let hir::ImplItemKind::Fn(ref sig, _) = item.kind { - let is_public = cx.access_levels.is_exported(item.def_id); - let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); - if is_public && trait_ref_of_method(cx, item.def_id).is_none() { - check_result_unit_err(cx, sig.decl, item.span, fn_header_span); - } - } -} - -pub(super) fn check_trait_item(cx: &LateContext<'_>, item: &hir::TraitItem<'_>) { - if let hir::TraitItemKind::Fn(ref sig, _) = item.kind { - let is_public = cx.access_levels.is_exported(item.def_id); - let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); - if is_public { - check_result_unit_err(cx, sig.decl, item.span, fn_header_span); - } - } -} - -fn check_result_unit_err(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, item_span: Span, fn_header_span: Span) { - if_chain! { - if !in_external_macro(cx.sess(), item_span); - if let hir::FnRetTy::Return(ty) = decl.output; - let ty = hir_ty_to_ty(cx.tcx, ty); - if is_type_diagnostic_item(cx, ty, sym::Result); - if let ty::Adt(_, substs) = ty.kind(); - let err_ty = substs.type_at(1); - if err_ty.is_unit(); - then { - span_lint_and_help( - cx, - RESULT_UNIT_ERR, - fn_header_span, - "this returns a `Result<_, ()>`", - None, - "use a custom `Error` type instead", - ); - } - } -} diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 700762fa3efe..134cbbf7b5c6 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -80,6 +80,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(functions::DOUBLE_MUST_USE), LintId::of(functions::MUST_USE_UNIT), LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF), + LintId::of(functions::RESULT_LARGE_ERR), LintId::of(functions::RESULT_UNIT_ERR), LintId::of(functions::TOO_MANY_ARGUMENTS), LintId::of(if_let_mutex::IF_LET_MUTEX), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index ee94165d2ed0..fd20e016578a 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -171,6 +171,7 @@ store.register_lints(&[ functions::MUST_USE_CANDIDATE, functions::MUST_USE_UNIT, functions::NOT_UNSAFE_PTR_ARG_DEREF, + functions::RESULT_LARGE_ERR, functions::RESULT_UNIT_ERR, functions::TOO_MANY_ARGUMENTS, functions::TOO_MANY_LINES, diff --git a/clippy_lints/src/lib.register_perf.rs b/clippy_lints/src/lib.register_perf.rs index 531fc47f8fac..195ce41e31e9 100644 --- a/clippy_lints/src/lib.register_perf.rs +++ b/clippy_lints/src/lib.register_perf.rs @@ -7,6 +7,7 @@ store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![ LintId::of(escape::BOXED_LOCAL), LintId::of(format_args::FORMAT_IN_FORMAT_ARGS), LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS), + LintId::of(functions::RESULT_LARGE_ERR), LintId::of(large_const_arrays::LARGE_CONST_ARRAYS), LintId::of(large_enum_variant::LARGE_ENUM_VARIANT), LintId::of(loops::MANUAL_MEMCPY), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 05d4dbd68599..178e57aaf61f 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -668,10 +668,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || Box::new(disallowed_names::DisallowedNames::new(disallowed_names.clone()))); let too_many_arguments_threshold = conf.too_many_arguments_threshold; let too_many_lines_threshold = conf.too_many_lines_threshold; + let large_error_threshold = conf.large_error_threshold; store.register_late_pass(move || { Box::new(functions::Functions::new( too_many_arguments_threshold, too_many_lines_threshold, + large_error_threshold, )) }); let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::>(); diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 47b72f4783e3..84e65d5fa0b7 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -379,6 +379,10 @@ define_Conf! { /// /// Whether `dbg!` should be allowed in test functions (allow_dbg_in_tests: bool = false), + /// Lint: RESULT_LARGE_ERR + /// + /// The maximum size of the `Err`-variant in a `Result` returned from a function + (large_error_threshold: u64 = 128), } /// Search for the configuration file. diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 00182e739b87..5a7f9568441c 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -831,3 +831,53 @@ pub fn ty_is_fn_once_param<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, predicates: &'tc }) .unwrap_or(false) } + +/// Comes up with an "at least" guesstimate for the type's size, not taking into +/// account the layout of type parameters. +pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 { + use rustc_middle::ty::layout::LayoutOf; + if !is_normalizable(cx, cx.param_env, ty) { + return 0; + } + match (cx.layout_of(ty).map(|layout| layout.size.bytes()), ty.kind()) { + (Ok(size), _) => size, + (Err(_), ty::Tuple(list)) => list.as_substs().types().map(|t| approx_ty_size(cx, t)).sum(), + (Err(_), ty::Array(t, n)) => { + n.try_eval_usize(cx.tcx, cx.param_env).unwrap_or_default() * approx_ty_size(cx, *t) + }, + (Err(_), ty::Adt(def, subst)) if def.is_struct() => def + .variants() + .iter() + .map(|v| { + v.fields + .iter() + .map(|field| approx_ty_size(cx, field.ty(cx.tcx, subst))) + .sum::() + }) + .sum(), + (Err(_), ty::Adt(def, subst)) if def.is_enum() => def + .variants() + .iter() + .map(|v| { + v.fields + .iter() + .map(|field| approx_ty_size(cx, field.ty(cx.tcx, subst))) + .sum::() + }) + .max() + .unwrap_or_default(), + (Err(_), ty::Adt(def, subst)) if def.is_union() => def + .variants() + .iter() + .map(|v| { + v.fields + .iter() + .map(|field| approx_ty_size(cx, field.ty(cx.tcx, subst))) + .max() + .unwrap_or_default() + }) + .max() + .unwrap_or_default(), + (Err(_), _) => 0, + } +} diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 9f8e778b3b9d..a52a0b5289fe 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -19,6 +19,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie enforced-import-renames enum-variant-name-threshold enum-variant-size-threshold + large-error-threshold literal-representation-threshold max-fn-params-bools max-include-file-size diff --git a/tests/ui/result_large_err.rs b/tests/ui/result_large_err.rs new file mode 100644 index 000000000000..78d8f76fe669 --- /dev/null +++ b/tests/ui/result_large_err.rs @@ -0,0 +1,98 @@ +#![warn(clippy::result_large_err)] + +pub fn small_err() -> Result<(), u128> { + Ok(()) +} + +pub fn large_err() -> Result<(), [u8; 512]> { + Ok(()) +} + +pub struct FullyDefinedLargeError { + _foo: u128, + _bar: [u8; 100], + _foobar: [u8; 120], +} + +impl FullyDefinedLargeError { + pub fn ret() -> Result<(), Self> { + Ok(()) + } +} + +pub fn struct_error() -> Result<(), FullyDefinedLargeError> { + Ok(()) +} + +type Fdlr = std::result::Result; +pub fn large_err_via_type_alias(x: T) -> Fdlr { + Ok(x) +} + +pub fn param_small_error() -> Result<(), (R, u128)> { + Ok(()) +} + +pub fn param_large_error() -> Result<(), (u128, R, FullyDefinedLargeError)> { + Ok(()) +} + +pub enum LargeErrorVariants { + _Small(u8), + _Omg([u8; 512]), + _Param(T), +} + +impl LargeErrorVariants<()> { + pub fn large_enum_error() -> Result<(), Self> { + Ok(()) + } +} + +trait TraitForcesLargeError { + fn large_error() -> Result<(), [u8; 512]> { + Ok(()) + } +} + +struct TraitImpl; + +impl TraitForcesLargeError for TraitImpl { + // Should not lint + fn large_error() -> Result<(), [u8; 512]> { + Ok(()) + } +} + +pub union FullyDefinedUnionError { + _maybe: u8, + _or_even: [[u8; 16]; 32], +} + +pub fn large_union_err() -> Result<(), FullyDefinedUnionError> { + Ok(()) +} + +pub union UnionError { + _maybe: T, + _or_perhaps_even: (T, [u8; 512]), +} + +pub fn param_large_union() -> Result<(), UnionError> { + Ok(()) +} + +pub struct ArrayError { + _large_array: [T; 32], + _other_stuff: U, +} + +pub fn array_error_subst() -> Result<(), ArrayError> { + Ok(()) +} + +pub fn array_error() -> Result<(), ArrayError<(i32, T), U>> { + Ok(()) +} + +fn main() {} diff --git a/tests/ui/result_large_err.stderr b/tests/ui/result_large_err.stderr new file mode 100644 index 000000000000..0f1f39d72cba --- /dev/null +++ b/tests/ui/result_large_err.stderr @@ -0,0 +1,91 @@ +error: the `Err`-variant returned from this function is very large + --> $DIR/result_large_err.rs:7:23 + | +LL | pub fn large_err() -> Result<(), [u8; 512]> { + | ^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes + | + = note: `-D clippy::result-large-err` implied by `-D warnings` + = help: try reducing the size of `[u8; 512]`, for example by boxing large elements or replacing it with `Box<[u8; 512]>` + +error: the `Err`-variant returned from this function is very large + --> $DIR/result_large_err.rs:18:21 + | +LL | pub fn ret() -> Result<(), Self> { + | ^^^^^^^^^^^^^^^^ the `Err`-variant is at least 240 bytes + | + = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box` + +error: the `Err`-variant returned from this function is very large + --> $DIR/result_large_err.rs:23:26 + | +LL | pub fn struct_error() -> Result<(), FullyDefinedLargeError> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 240 bytes + | + = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box` + +error: the `Err`-variant returned from this function is very large + --> $DIR/result_large_err.rs:28:45 + | +LL | pub fn large_err_via_type_alias(x: T) -> Fdlr { + | ^^^^^^^ the `Err`-variant is at least 240 bytes + | + = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box` + +error: the `Err`-variant returned from this function is very large + --> $DIR/result_large_err.rs:36:34 + | +LL | pub fn param_large_error() -> Result<(), (u128, R, FullyDefinedLargeError)> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 256 bytes + | + = help: try reducing the size of `(u128, R, FullyDefinedLargeError)`, for example by boxing large elements or replacing it with `Box<(u128, R, FullyDefinedLargeError)>` + +error: the `Err`-variant returned from this function is very large + --> $DIR/result_large_err.rs:47:34 + | +LL | pub fn large_enum_error() -> Result<(), Self> { + | ^^^^^^^^^^^^^^^^ the `Err`-variant is at least 513 bytes + | + = help: try reducing the size of `LargeErrorVariants<()>`, for example by boxing large elements or replacing it with `Box>` + +error: the `Err`-variant returned from this function is very large + --> $DIR/result_large_err.rs:53:25 + | +LL | fn large_error() -> Result<(), [u8; 512]> { + | ^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes + | + = help: try reducing the size of `[u8; 512]`, for example by boxing large elements or replacing it with `Box<[u8; 512]>` + +error: the `Err`-variant returned from this function is very large + --> $DIR/result_large_err.rs:72:29 + | +LL | pub fn large_union_err() -> Result<(), FullyDefinedUnionError> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes + | + = help: try reducing the size of `FullyDefinedUnionError`, for example by boxing large elements or replacing it with `Box` + +error: the `Err`-variant returned from this function is very large + --> $DIR/result_large_err.rs:81:40 + | +LL | pub fn param_large_union() -> Result<(), UnionError> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes + | + = help: try reducing the size of `UnionError`, for example by boxing large elements or replacing it with `Box>` + +error: the `Err`-variant returned from this function is very large + --> $DIR/result_large_err.rs:90:34 + | +LL | pub fn array_error_subst() -> Result<(), ArrayError> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 128 bytes + | + = help: try reducing the size of `ArrayError`, for example by boxing large elements or replacing it with `Box>` + +error: the `Err`-variant returned from this function is very large + --> $DIR/result_large_err.rs:94:31 + | +LL | pub fn array_error() -> Result<(), ArrayError<(i32, T), U>> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 128 bytes + | + = help: try reducing the size of `ArrayError<(i32, T), U>`, for example by boxing large elements or replacing it with `Box>` + +error: aborting due to 11 previous errors + From 484d5b6e70e30e3e2b1714c9dcf641bb47f01b7c Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Wed, 31 Aug 2022 01:00:53 +0900 Subject: [PATCH 3942/5092] fix: handle trait methods as inherent methods for placeholders --- crates/hir-ty/src/method_resolution.rs | 87 ++++++++++++++------ crates/hir-ty/src/tests/method_resolution.rs | 17 ++++ 2 files changed, 77 insertions(+), 27 deletions(-) diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index c0ef4b2a9dc8..dbf275003207 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -914,19 +914,10 @@ fn iterate_trait_method_candidates( let db = table.db; let env = table.trait_env.clone(); let self_is_array = matches!(self_ty.kind(Interner), chalk_ir::TyKind::Array(..)); - let env_traits = matches!(self_ty.kind(Interner), TyKind::Placeholder(_)) - // if we have `T: Trait` in the param env, the trait doesn't need to be in scope - .then(|| { - env.traits_in_scope_from_clauses(self_ty.clone()) - .flat_map(|t| all_super_traits(db.upcast(), t)) - }) - .into_iter() - .flatten(); - let traits = env_traits.chain(traits_in_scope.iter().copied()); let canonical_self_ty = table.canonicalize(self_ty.clone()).value; - 'traits: for t in traits { + 'traits: for &t in traits_in_scope { let data = db.trait_data(t); // Traits annotated with `#[rustc_skip_array_during_method_dispatch]` are skipped during @@ -976,6 +967,43 @@ fn iterate_inherent_methods( ) -> ControlFlow<()> { let db = table.db; let env = table.trait_env.clone(); + + // For trait object types and placeholder types with trait bounds, the methods of the trait and + // its super traits are considered inherent methods. This matters because these methods have + // higher priority than the other traits' methods, which would be considered in + // `iterate_trait_method_candidates()` only after this function. + match self_ty.kind(Interner) { + TyKind::Placeholder(_) => { + let env = table.trait_env.clone(); + let traits = env + .traits_in_scope_from_clauses(self_ty.clone()) + .flat_map(|t| all_super_traits(db.upcast(), t)); + iterate_inherent_trait_methods( + self_ty, + table, + name, + receiver_ty, + receiver_adjustments.clone(), + callback, + traits, + )?; + } + TyKind::Dyn(_) => { + let principal_trait = self_ty.dyn_trait().unwrap(); + let traits = all_super_traits(db.upcast(), principal_trait); + iterate_inherent_trait_methods( + self_ty, + table, + name, + receiver_ty, + receiver_adjustments.clone(), + callback, + traits.into_iter(), + )?; + } + _ => {} + } + let def_crates = match def_crates(db, self_ty, env.krate) { Some(k) => k, None => return ControlFlow::Continue(()), @@ -987,23 +1015,6 @@ fn iterate_inherent_methods( VisibleFromModule::None => (None, None), }; - // For trait object types, methods of the trait and its super traits are considered inherent - // methods. This matters because these trait methods have higher priority than the other - // traits' methods, which would be considered in `iterate_trait_method_candidates()` after this - // function. - let inherent_traits = - self_ty.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t)); - for t in inherent_traits { - let data = db.trait_data(t); - for &(_, item) in data.items.iter() { - // We don't pass `visible_from_module` as all trait items should be visible from the - // trait object. - if is_valid_candidate(table, name, receiver_ty, item, self_ty, None) { - callback(receiver_adjustments.clone().unwrap_or_default(), item)?; - } - } - } - if let Some(block_id) = block { if let Some(impls) = db.inherent_impls_in_block(block_id) { impls_for_self_ty( @@ -1034,6 +1045,28 @@ fn iterate_inherent_methods( } return ControlFlow::Continue(()); + fn iterate_inherent_trait_methods( + self_ty: &Ty, + table: &mut InferenceTable<'_>, + name: Option<&Name>, + receiver_ty: Option<&Ty>, + receiver_adjustments: Option, + callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>, + traits: impl Iterator, + ) -> ControlFlow<()> { + let db = table.db; + for t in traits { + let data = db.trait_data(t); + for &(_, item) in data.items.iter() { + // We don't pass `visible_from_module` as all trait items should be visible. + if is_valid_candidate(table, name, receiver_ty, item, self_ty, None) { + callback(receiver_adjustments.clone().unwrap_or_default(), item)?; + } + } + } + ControlFlow::Continue(()) + } + fn impls_for_self_ty( impls: &InherentImpls, self_ty: &Ty, diff --git a/crates/hir-ty/src/tests/method_resolution.rs b/crates/hir-ty/src/tests/method_resolution.rs index fb2fc9369a79..ac8edb841a58 100644 --- a/crates/hir-ty/src/tests/method_resolution.rs +++ b/crates/hir-ty/src/tests/method_resolution.rs @@ -1235,6 +1235,23 @@ fn foo(a: &dyn Trait) { ); } +#[test] +fn trait_method_priority_for_placeholder_type() { + check_types( + r#" +//- minicore: from +trait Trait { + fn into(&self) -> usize { 0 } +} + +fn foo(a: &T) { + let _ = a.into(); + //^usize +} + "#, + ); +} + #[test] fn autoderef_visibility_field() { check( From 45ad22be8f11dba54d1239d2cf25b71e71177b28 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 3 Apr 2022 14:50:56 +0200 Subject: [PATCH 3943/5092] Encode type in the main loop. --- compiler/rustc_metadata/src/rmeta/encoder.rs | 111 +++++++++---------- 1 file changed, 55 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 3482d9f04514..649bb6e94456 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1020,6 +1020,54 @@ fn should_encode_generics(def_kind: DefKind) -> bool { } } +fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> bool { + match def_kind { + DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::Variant + | DefKind::Ctor(..) + | DefKind::Field + | DefKind::Fn + | DefKind::Const + | DefKind::Static(..) + | DefKind::TyAlias + | DefKind::OpaqueTy + | DefKind::ForeignTy + | DefKind::Impl + | DefKind::AssocFn + | DefKind::AssocConst + | DefKind::Closure + | DefKind::Generator + | DefKind::ConstParam + | DefKind::AnonConst + | DefKind::InlineConst => true, + + DefKind::AssocTy => { + let assoc_item = tcx.associated_item(def_id); + match assoc_item.container { + ty::AssocItemContainer::ImplContainer => true, + ty::AssocItemContainer::TraitContainer => assoc_item.defaultness(tcx).has_value(), + } + } + DefKind::TyParam => { + let hir::Node::GenericParam(param) = tcx.hir().get_by_def_id(def_id) else { bug!() }; + let hir::GenericParamKind::Type { default, .. } = param.kind else { bug!() }; + default.is_some() + } + + DefKind::Trait + | DefKind::TraitAlias + | DefKind::Mod + | DefKind::ForeignMod + | DefKind::Macro(..) + | DefKind::Use + | DefKind::LifetimeParam + | DefKind::GlobalAsm + | DefKind::ExternCrate => false, + } +} + impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_attrs(&mut self, def_id: LocalDefId) { let mut attrs = self @@ -1076,6 +1124,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record_array!(self.tables.inferred_outlives_of[def_id] <- inferred_outlives); } } + if should_encode_type(tcx, local_id, def_kind) { + record!(self.tables.type_of[def_id] <- self.tcx.type_of(def_id)); + } if let DefKind::TyParam | DefKind::ConstParam = def_kind { if let Some(default) = self.tcx.object_lifetime_default(def_id) { record!(self.tables.object_lifetime_default[def_id] <- default); @@ -1097,11 +1148,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } - fn encode_item_type(&mut self, def_id: DefId) { - debug!("EncodeContext::encode_item_type({:?})", def_id); - record!(self.tables.type_of[def_id] <- self.tcx.type_of(def_id)); - } - fn encode_enum_variant_info(&mut self, def: ty::AdtDef<'tcx>, index: VariantIdx) { let tcx = self.tcx; let variant = &def.variant(index); @@ -1121,7 +1167,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { assert!(f.did.is_local()); f.did.index })); - self.encode_item_type(def_id); if variant.ctor_kind == CtorKind::Fn { // FIXME(eddyb) encode signature only in `encode_enum_variant_ctor`. if let Some(ctor_def_id) = variant.ctor_def_id { @@ -1146,7 +1191,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.kind[def_id] <- EntryKind::Variant(self.lazy(data))); self.tables.constness.set(def_id.index, hir::Constness::Const); - self.encode_item_type(def_id); if variant.ctor_kind == CtorKind::Fn { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); } @@ -1212,7 +1256,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { debug!("EncodeContext::encode_field({:?})", def_id); record!(self.tables.kind[def_id] <- EntryKind::Field); - self.encode_item_type(def_id); } fn encode_struct_ctor(&mut self, adt_def: ty::AdtDef<'tcx>, def_id: DefId) { @@ -1230,7 +1273,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.repr_options[def_id] <- adt_def.repr()); self.tables.constness.set(def_id.index, hir::Constness::Const); record!(self.tables.kind[def_id] <- EntryKind::Struct(self.lazy(data))); - self.encode_item_type(def_id); if variant.ctor_kind == CtorKind::Fn { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); } @@ -1285,16 +1327,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.kind[def_id] <- EntryKind::AssocType(ty::AssocItemContainer::TraitContainer)); } } - match trait_item.kind { - ty::AssocKind::Const | ty::AssocKind::Fn => { - self.encode_item_type(def_id); - } - ty::AssocKind::Type => { - if ast_item.defaultness.has_value() { - self.encode_item_type(def_id); - } - } - } if trait_item.kind == ty::AssocKind::Fn { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); } @@ -1341,7 +1373,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.kind[def_id] <- EntryKind::AssocType(ty::AssocItemContainer::ImplContainer)); } } - self.encode_item_type(def_id); if let Some(trait_item_def_id) = impl_item.trait_item_def_id { self.tables.trait_item_def_id.set(def_id.index, trait_item_def_id.into()); } @@ -1590,18 +1621,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } _ => {} } - match item.kind { - hir::ItemKind::Static(..) - | hir::ItemKind::Const(..) - | hir::ItemKind::Fn(..) - | hir::ItemKind::TyAlias(..) - | hir::ItemKind::OpaqueTy(..) - | hir::ItemKind::Enum(..) - | hir::ItemKind::Struct(..) - | hir::ItemKind::Union(..) - | hir::ItemKind::Impl { .. } => self.encode_item_type(def_id), - _ => {} - } if let hir::ItemKind::Fn(..) = item.kind { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); if tcx.is_intrinsic(def_id) { @@ -1615,13 +1634,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } - fn encode_info_for_generic_param(&mut self, def_id: DefId, kind: EntryKind, encode_type: bool) { - record!(self.tables.kind[def_id] <- kind); - if encode_type { - self.encode_item_type(def_id); - } - } - fn encode_info_for_closure(&mut self, hir_id: hir::HirId) { let def_id = self.tcx.hir().local_def_id(hir_id); debug!("EncodeContext::encode_info_for_closure({:?})", def_id); @@ -1638,16 +1650,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.generator_diagnostic_data[def_id.to_def_id()] <- generator_diagnostic_data); } - ty::Closure(..) => { + ty::Closure(_, substs) => { record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::Closure); + record!(self.tables.fn_sig[def_id.to_def_id()] <- substs.as_closure().sig()); } _ => bug!("closure that is neither generator nor closure"), } - self.encode_item_type(def_id.to_def_id()); - if let ty::Closure(def_id, substs) = *ty.kind() { - record!(self.tables.fn_sig[def_id] <- substs.as_closure().sig()); - } } fn encode_info_for_anon_const(&mut self, id: hir::HirId) { @@ -1660,7 +1669,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::AnonConst); record!(self.tables.mir_const_qualif[def_id.to_def_id()] <- qualifs); record!(self.tables.rendered_const[def_id.to_def_id()] <- const_data); - self.encode_item_type(def_id.to_def_id()); } fn encode_native_libraries(&mut self) -> LazyArray { @@ -1997,6 +2005,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }; self.tables.constness.set(def_id.index, constness); record!(self.tables.kind[def_id] <- EntryKind::ForeignFn); + record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); } hir::ForeignItemKind::Static(..) => { record!(self.tables.kind[def_id] <- EntryKind::ForeignStatic); @@ -2005,9 +2014,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.kind[def_id] <- EntryKind::ForeignType); } } - self.encode_item_type(def_id); if let hir::ForeignItemKind::Fn(..) = nitem.kind { - record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); if tcx.is_intrinsic(def_id) { self.tables.is_intrinsic.set(def_id.index, ()); } @@ -2061,17 +2068,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { for param in generics.params { let def_id = self.tcx.hir().local_def_id(param.hir_id); match param.kind { - GenericParamKind::Lifetime { .. } => continue, - GenericParamKind::Type { default, .. } => { - self.encode_info_for_generic_param( - def_id.to_def_id(), - EntryKind::TypeParam, - default.is_some(), - ); - } + GenericParamKind::Lifetime { .. } | GenericParamKind::Type { .. } => {} GenericParamKind::Const { ref default, .. } => { let def_id = def_id.to_def_id(); - self.encode_info_for_generic_param(def_id, EntryKind::ConstParam, true); if default.is_some() { record!(self.tables.const_param_default[def_id] <- self.tcx.const_param_default(def_id)) } From 73e9f37eaa05fbf2bb7657d6b80fe1afd0a6d445 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 8 Jun 2022 20:32:51 +0200 Subject: [PATCH 3944/5092] Encode consts in metadata main loop. --- compiler/rustc_metadata/src/rmeta/encoder.rs | 83 ++++++++++++-------- 1 file changed, 51 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 649bb6e94456..b4a30245b5ec 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1068,6 +1068,41 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> } } +fn should_encode_const(def_kind: DefKind) -> bool { + match def_kind { + DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => true, + + DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::Variant + | DefKind::Ctor(..) + | DefKind::Field + | DefKind::Fn + | DefKind::Static(..) + | DefKind::TyAlias + | DefKind::OpaqueTy + | DefKind::ForeignTy + | DefKind::Impl + | DefKind::AssocFn + | DefKind::Closure + | DefKind::Generator + | DefKind::ConstParam + | DefKind::InlineConst + | DefKind::AssocTy + | DefKind::TyParam + | DefKind::Trait + | DefKind::TraitAlias + | DefKind::Mod + | DefKind::ForeignMod + | DefKind::Macro(..) + | DefKind::Use + | DefKind::LifetimeParam + | DefKind::GlobalAsm + | DefKind::ExternCrate => false, + } +} + impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_attrs(&mut self, def_id: LocalDefId) { let mut attrs = self @@ -1093,7 +1128,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let def_kind = tcx.opt_def_kind(local_id); let Some(def_kind) = def_kind else { continue }; self.tables.opt_def_kind.set(def_id.index, def_kind); - record!(self.tables.def_span[def_id] <- tcx.def_span(def_id)); + let def_span = tcx.def_span(local_id); + record!(self.tables.def_span[def_id] <- def_span); self.encode_attrs(local_id); record!(self.tables.expn_that_defined[def_id] <- self.tcx.expn_that_defined(def_id)); if let Some(ident_span) = tcx.def_ident_span(def_id) { @@ -1127,6 +1163,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if should_encode_type(tcx, local_id, def_kind) { record!(self.tables.type_of[def_id] <- self.tcx.type_of(def_id)); } + if should_encode_const(def_kind) && tcx.is_mir_available(def_id) { + let qualifs = tcx.at(def_span).mir_const_qualif(def_id); + record!(self.tables.mir_const_qualif[def_id] <- qualifs); + let body_id = tcx.hir().maybe_body_owned_by(local_id); + if let Some(body_id) = body_id { + let const_data = self.encode_rendered_const_for_body(body_id); + record!(self.tables.rendered_const[def_id] <- const_data); + } + } if let DefKind::TyParam | DefKind::ConstParam = def_kind { if let Some(default) = self.tcx.object_lifetime_default(def_id) { record!(self.tables.object_lifetime_default[def_id] <- default); @@ -1296,14 +1341,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { match trait_item.kind { ty::AssocKind::Const => { - let rendered = rustc_hir_pretty::to_string( - &(&self.tcx.hir() as &dyn intravisit::Map<'_>), - |s| s.print_trait_item(ast_item), - ); - - record!(self.tables.kind[def_id] <- EntryKind::AssocConst(ty::AssocItemContainer::TraitContainer)); - record!(self.tables.mir_const_qualif[def_id] <- mir::ConstQualifs::default()); - record!(self.tables.rendered_const[def_id] <- rendered); + let container = trait_item.container; + record!(self.tables.kind[def_id] <- EntryKind::AssocConst(container)); } ty::AssocKind::Fn => { let hir::TraitItemKind::Fn(m_sig, m) = &ast_item.kind else { bug!() }; @@ -1342,16 +1381,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { match impl_item.kind { ty::AssocKind::Const => { - if let hir::ImplItemKind::Const(_, body_id) = ast_item.kind { - let qualifs = self.tcx.at(ast_item.span).mir_const_qualif(def_id); - let const_data = self.encode_rendered_const_for_body(body_id); - - record!(self.tables.kind[def_id] <- EntryKind::AssocConst(ty::AssocItemContainer::ImplContainer)); - record!(self.tables.mir_const_qualif[def_id] <- qualifs); - record!(self.tables.rendered_const[def_id] <- const_data); - } else { - bug!() - } + let container = impl_item.container; + record!(self.tables.kind[def_id] <- EntryKind::AssocConst(container)); } ty::AssocKind::Fn => { let hir::ImplItemKind::Fn(ref sig, body) = ast_item.kind else { bug!() }; @@ -1487,13 +1518,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let entry_kind = match item.kind { hir::ItemKind::Static(..) => EntryKind::Static, - hir::ItemKind::Const(_, body_id) => { - let qualifs = self.tcx.at(item.span).mir_const_qualif(def_id); - let const_data = self.encode_rendered_const_for_body(body_id); - record!(self.tables.mir_const_qualif[def_id] <- qualifs); - record!(self.tables.rendered_const[def_id] <- const_data); - EntryKind::Const - } + hir::ItemKind::Const(..) => EntryKind::Const, hir::ItemKind::Fn(ref sig, .., body) => { self.tables.asyncness.set(def_id.index, sig.header.asyncness); record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body)); @@ -1662,13 +1687,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_info_for_anon_const(&mut self, id: hir::HirId) { let def_id = self.tcx.hir().local_def_id(id); debug!("EncodeContext::encode_info_for_anon_const({:?})", def_id); - let body_id = self.tcx.hir().body_owned_by(def_id); - let const_data = self.encode_rendered_const_for_body(body_id); - let qualifs = self.tcx.mir_const_qualif(def_id); - record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::AnonConst); - record!(self.tables.mir_const_qualif[def_id.to_def_id()] <- qualifs); - record!(self.tables.rendered_const[def_id.to_def_id()] <- const_data); } fn encode_native_libraries(&mut self) -> LazyArray { From edd25c37c5246e082aadd3e110bc88282cd13ca5 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 3 Apr 2022 18:43:33 +0200 Subject: [PATCH 3945/5092] Simplify recursion scheme. --- compiler/rustc_metadata/src/rmeta/encoder.rs | 130 ++++++++----------- 1 file changed, 51 insertions(+), 79 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index b4a30245b5ec..45195138f274 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1288,21 +1288,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } - fn encode_field( - &mut self, - adt_def: ty::AdtDef<'tcx>, - variant_index: VariantIdx, - field_index: usize, - ) { - let variant = &adt_def.variant(variant_index); - let field = &variant.fields[field_index]; - - let def_id = field.did; - debug!("EncodeContext::encode_field({:?})", def_id); - - record!(self.tables.kind[def_id] <- EntryKind::Field); - } - fn encode_struct_ctor(&mut self, adt_def: ty::AdtDef<'tcx>, def_id: DefId) { debug!("EncodeContext::encode_struct_ctor({:?})", def_id); let tcx = self.tcx; @@ -1657,6 +1642,52 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.impl_trait_ref[def_id] <- trait_ref); } } + // In some cases, along with the item itself, we also + // encode some sub-items. Usually we want some info from the item + // so it's easier to do that here then to wait until we would encounter + // normally in the visitor walk. + match item.kind { + hir::ItemKind::Enum(..) => { + let def = self.tcx.adt_def(item.def_id.to_def_id()); + self.encode_fields(def); + + for (i, variant) in def.variants().iter_enumerated() { + self.encode_enum_variant_info(def, i); + + if let Some(_ctor_def_id) = variant.ctor_def_id { + self.encode_enum_variant_ctor(def, i); + } + } + } + hir::ItemKind::Struct(ref struct_def, _) => { + let def = self.tcx.adt_def(item.def_id.to_def_id()); + self.encode_fields(def); + + // If the struct has a constructor, encode it. + if let Some(ctor_hir_id) = struct_def.ctor_hir_id() { + let ctor_def_id = self.tcx.hir().local_def_id(ctor_hir_id); + self.encode_struct_ctor(def, ctor_def_id.to_def_id()); + } + } + hir::ItemKind::Union(..) => { + let def = self.tcx.adt_def(item.def_id.to_def_id()); + self.encode_fields(def); + } + hir::ItemKind::Impl { .. } => { + for &trait_item_def_id in + self.tcx.associated_item_def_ids(item.def_id.to_def_id()).iter() + { + self.encode_info_for_impl_item(trait_item_def_id); + } + } + hir::ItemKind::Trait(..) => { + for &item_def_id in self.tcx.associated_item_def_ids(item.def_id.to_def_id()).iter() + { + self.encode_info_for_trait_item(item_def_id); + } + } + _ => {} + } } fn encode_info_for_closure(&mut self, hir_id: hir::HirId) { @@ -2062,7 +2093,6 @@ impl<'a, 'tcx> Visitor<'tcx> for EncodeContext<'a, 'tcx> { hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) => {} // ignore these _ => self.encode_info_for_item(item.def_id.to_def_id(), item), } - self.encode_addl_info_for_item(item); } fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem<'tcx>) { intravisit::walk_foreign_item(self, ni); @@ -2078,7 +2108,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_fields(&mut self, adt_def: ty::AdtDef<'tcx>) { for (variant_index, variant) in adt_def.variants().iter_enumerated() { for (field_index, _field) in variant.fields.iter().enumerate() { - self.encode_field(adt_def, variant_index, field_index); + let variant = &adt_def.variant(variant_index); + let field = &variant.fields[field_index]; + let def_id = field.did; + debug!("EncodeContext::encode_field({:?})", def_id); + record!(self.tables.kind[def_id] <- EntryKind::Field); } } } @@ -2103,68 +2137,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.encode_info_for_closure(expr.hir_id); } } - - /// In some cases, along with the item itself, we also - /// encode some sub-items. Usually we want some info from the item - /// so it's easier to do that here then to wait until we would encounter - /// normally in the visitor walk. - fn encode_addl_info_for_item(&mut self, item: &hir::Item<'_>) { - match item.kind { - hir::ItemKind::Static(..) - | hir::ItemKind::Const(..) - | hir::ItemKind::Fn(..) - | hir::ItemKind::Macro(..) - | hir::ItemKind::Mod(..) - | hir::ItemKind::ForeignMod { .. } - | hir::ItemKind::GlobalAsm(..) - | hir::ItemKind::ExternCrate(..) - | hir::ItemKind::Use(..) - | hir::ItemKind::TyAlias(..) - | hir::ItemKind::OpaqueTy(..) - | hir::ItemKind::TraitAlias(..) => { - // no sub-item recording needed in these cases - } - hir::ItemKind::Enum(..) => { - let def = self.tcx.adt_def(item.def_id.to_def_id()); - self.encode_fields(def); - - for (i, variant) in def.variants().iter_enumerated() { - self.encode_enum_variant_info(def, i); - - if let Some(_ctor_def_id) = variant.ctor_def_id { - self.encode_enum_variant_ctor(def, i); - } - } - } - hir::ItemKind::Struct(ref struct_def, _) => { - let def = self.tcx.adt_def(item.def_id.to_def_id()); - self.encode_fields(def); - - // If the struct has a constructor, encode it. - if let Some(ctor_hir_id) = struct_def.ctor_hir_id() { - let ctor_def_id = self.tcx.hir().local_def_id(ctor_hir_id); - self.encode_struct_ctor(def, ctor_def_id.to_def_id()); - } - } - hir::ItemKind::Union(..) => { - let def = self.tcx.adt_def(item.def_id.to_def_id()); - self.encode_fields(def); - } - hir::ItemKind::Impl { .. } => { - for &trait_item_def_id in - self.tcx.associated_item_def_ids(item.def_id.to_def_id()).iter() - { - self.encode_info_for_impl_item(trait_item_def_id); - } - } - hir::ItemKind::Trait(..) => { - for &item_def_id in self.tcx.associated_item_def_ids(item.def_id.to_def_id()).iter() - { - self.encode_info_for_trait_item(item_def_id); - } - } - } - } } /// Used to prefetch queries which will be needed later by metadata encoding. From 927e58d633a569a404a6cb75df3a41d1af210d56 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 8 Jun 2022 20:59:59 +0200 Subject: [PATCH 3946/5092] Move VariantData to a metadata table. --- compiler/rustc_metadata/src/rmeta/decoder.rs | 23 ++++++++------------ compiler/rustc_metadata/src/rmeta/encoder.rs | 19 ++++++++++------ compiler/rustc_metadata/src/rmeta/mod.rs | 7 +++--- 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index d0e0aa91480c..d04bcbfc4b0e 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -858,19 +858,14 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_variant(self, kind: &EntryKind, index: DefIndex, parent_did: DefId) -> ty::VariantDef { - let data = match kind { - EntryKind::Variant(data) | EntryKind::Struct(data) | EntryKind::Union(data) => { - data.decode(self) - } + let adt_kind = match kind { + EntryKind::Variant => ty::AdtKind::Enum, + EntryKind::Struct => ty::AdtKind::Struct, + EntryKind::Union => ty::AdtKind::Union, _ => bug!(), }; - let adt_kind = match kind { - EntryKind::Variant(_) => ty::AdtKind::Enum, - EntryKind::Struct(..) => ty::AdtKind::Struct, - EntryKind::Union(..) => ty::AdtKind::Union, - _ => bug!(), - }; + let data = self.root.tables.variant_data.get(self, index).unwrap().decode(self); let variant_did = if adt_kind == ty::AdtKind::Enum { Some(self.local_def_id(index)) } else { None }; @@ -907,8 +902,8 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { let adt_kind = match kind { EntryKind::Enum => ty::AdtKind::Enum, - EntryKind::Struct(_) => ty::AdtKind::Struct, - EntryKind::Union(_) => ty::AdtKind::Union, + EntryKind::Struct => ty::AdtKind::Struct, + EntryKind::Union => ty::AdtKind::Union, _ => bug!("get_adt_def called on a non-ADT {:?}", did), }; let repr = self.root.tables.repr_options.get(self, item_id).unwrap().decode(self); @@ -1158,8 +1153,8 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn get_ctor_def_id_and_kind(self, node_id: DefIndex) -> Option<(DefId, CtorKind)> { match self.kind(node_id) { - EntryKind::Struct(data) | EntryKind::Variant(data) => { - let vdata = data.decode(self); + EntryKind::Struct | EntryKind::Variant => { + let vdata = self.root.tables.variant_data.get(self, node_id).unwrap().decode(self); vdata.ctor.map(|index| (self.local_def_id(index), vdata.ctor_kind)) } _ => None, diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 45195138f274..fa410821f315 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1206,7 +1206,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { is_non_exhaustive: variant.is_field_list_non_exhaustive(), }; - record!(self.tables.kind[def_id] <- EntryKind::Variant(self.lazy(data))); + record!(self.tables.variant_data[def_id] <- data); + record!(self.tables.kind[def_id] <- EntryKind::Variant); self.tables.constness.set(def_id.index, hir::Constness::Const); record_array!(self.tables.children[def_id] <- variant.fields.iter().map(|f| { assert!(f.did.is_local()); @@ -1234,7 +1235,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { is_non_exhaustive: variant.is_field_list_non_exhaustive(), }; - record!(self.tables.kind[def_id] <- EntryKind::Variant(self.lazy(data))); + record!(self.tables.variant_data[def_id] <- data); + record!(self.tables.kind[def_id] <- EntryKind::Variant); self.tables.constness.set(def_id.index, hir::Constness::Const); if variant.ctor_kind == CtorKind::Fn { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); @@ -1301,8 +1303,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }; record!(self.tables.repr_options[def_id] <- adt_def.repr()); + record!(self.tables.variant_data[def_id] <- data); + record!(self.tables.kind[def_id] <- EntryKind::Struct); self.tables.constness.set(def_id.index, hir::Constness::Const); - record!(self.tables.kind[def_id] <- EntryKind::Struct(self.lazy(data))); if variant.ctor_kind == CtorKind::Fn { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); } @@ -1541,24 +1544,26 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { .map(|ctor_hir_id| self.tcx.hir().local_def_id(ctor_hir_id).local_def_index); let variant = adt_def.non_enum_variant(); - EntryKind::Struct(self.lazy(VariantData { + record!(self.tables.variant_data[def_id] <- VariantData { ctor_kind: variant.ctor_kind, discr: variant.discr, ctor, is_non_exhaustive: variant.is_field_list_non_exhaustive(), - })) + }); + EntryKind::Struct } hir::ItemKind::Union(..) => { let adt_def = self.tcx.adt_def(def_id); record!(self.tables.repr_options[def_id] <- adt_def.repr()); let variant = adt_def.non_enum_variant(); - EntryKind::Union(self.lazy(VariantData { + record!(self.tables.variant_data[def_id] <- VariantData { ctor_kind: variant.ctor_kind, discr: variant.discr, ctor: None, is_non_exhaustive: variant.is_field_list_non_exhaustive(), - })) + }); + EntryKind::Union } hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => { self.tables.impl_defaultness.set(def_id.index, *defaultness); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index aeffc85b5075..6353e04316b1 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -393,6 +393,7 @@ define_tables! { proc_macro_quoted_spans: Table>, generator_diagnostic_data: Table>>, may_have_doc_links: Table, + variant_data: Table>, } #[derive(Copy, Clone, MetadataEncodable, MetadataDecodable)] @@ -410,9 +411,9 @@ enum EntryKind { OpaqueTy, Enum, Field, - Variant(LazyValue), - Struct(LazyValue), - Union(LazyValue), + Variant, + Struct, + Union, Fn, ForeignFn, Mod(LazyArray), From ca9f5645f3d4e363cad96bdacef8998cb30207d6 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 8 Jun 2022 21:11:08 +0200 Subject: [PATCH 3947/5092] Move AssocContainer to a metadata table. --- compiler/rustc_metadata/src/rmeta/decoder.rs | 13 +++++++------ compiler/rustc_metadata/src/rmeta/encoder.rs | 14 ++++++-------- compiler/rustc_metadata/src/rmeta/mod.rs | 7 ++++--- compiler/rustc_metadata/src/rmeta/table.rs | 7 +++++++ compiler/rustc_middle/src/ty/parameterized.rs | 1 + 5 files changed, 25 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index d04bcbfc4b0e..7e2ade03c73e 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1112,7 +1112,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn get_fn_has_self_parameter(self, id: DefIndex) -> bool { match self.kind(id) { - EntryKind::AssocFn { has_self, .. } => has_self, + EntryKind::AssocFn { has_self } => has_self, _ => false, } } @@ -1134,12 +1134,13 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn get_associated_item(self, id: DefIndex) -> ty::AssocItem { let name = self.item_name(id); - let (kind, container, has_self) = match self.kind(id) { - EntryKind::AssocConst(container) => (ty::AssocKind::Const, container, false), - EntryKind::AssocFn { container, has_self } => (ty::AssocKind::Fn, container, has_self), - EntryKind::AssocType(container) => (ty::AssocKind::Type, container, false), - _ => bug!("cannot get associated-item of `{:?}`", id), + let (kind, has_self) = match self.kind(id) { + EntryKind::AssocConst => (ty::AssocKind::Const, false), + EntryKind::AssocFn { has_self } => (ty::AssocKind::Fn, has_self), + EntryKind::AssocType => (ty::AssocKind::Type, false), + _ => bug!("cannot get associated-item of `{:?}`", self.def_key(id)), }; + let container = self.root.tables.assoc_container.get(self, id).unwrap(); ty::AssocItem { name, diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index fa410821f315..25590af84f64 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1326,11 +1326,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let ast_item = tcx.hir().expect_trait_item(def_id.expect_local()); self.tables.impl_defaultness.set(def_id.index, ast_item.defaultness); let trait_item = tcx.associated_item(def_id); + self.tables.assoc_container.set(def_id.index, trait_item.container); match trait_item.kind { ty::AssocKind::Const => { - let container = trait_item.container; - record!(self.tables.kind[def_id] <- EntryKind::AssocConst(container)); + record!(self.tables.kind[def_id] <- EntryKind::AssocConst); } ty::AssocKind::Fn => { let hir::TraitItemKind::Fn(m_sig, m) = &ast_item.kind else { bug!() }; @@ -1345,13 +1345,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.tables.asyncness.set(def_id.index, m_sig.header.asyncness); self.tables.constness.set(def_id.index, hir::Constness::NotConst); record!(self.tables.kind[def_id] <- EntryKind::AssocFn { - container: ty::AssocItemContainer::TraitContainer, has_self: trait_item.fn_has_self_parameter, }); } ty::AssocKind::Type => { self.encode_explicit_item_bounds(def_id); - record!(self.tables.kind[def_id] <- EntryKind::AssocType(ty::AssocItemContainer::TraitContainer)); + record!(self.tables.kind[def_id] <- EntryKind::AssocType); } } if trait_item.kind == ty::AssocKind::Fn { @@ -1366,11 +1365,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let ast_item = self.tcx.hir().expect_impl_item(def_id.expect_local()); self.tables.impl_defaultness.set(def_id.index, ast_item.defaultness); let impl_item = self.tcx.associated_item(def_id); + self.tables.assoc_container.set(def_id.index, impl_item.container); match impl_item.kind { ty::AssocKind::Const => { - let container = impl_item.container; - record!(self.tables.kind[def_id] <- EntryKind::AssocConst(container)); + record!(self.tables.kind[def_id] <- EntryKind::AssocConst); } ty::AssocKind::Fn => { let hir::ImplItemKind::Fn(ref sig, body) = ast_item.kind else { bug!() }; @@ -1384,12 +1383,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }; self.tables.constness.set(def_id.index, constness); record!(self.tables.kind[def_id] <- EntryKind::AssocFn { - container: ty::AssocItemContainer::ImplContainer, has_self: impl_item.fn_has_self_parameter, }); } ty::AssocKind::Type => { - record!(self.tables.kind[def_id] <- EntryKind::AssocType(ty::AssocItemContainer::ImplContainer)); + record!(self.tables.kind[def_id] <- EntryKind::AssocType); } } if let Some(trait_item_def_id) = impl_item.trait_item_def_id { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 6353e04316b1..7537f2c68e59 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -394,6 +394,7 @@ define_tables! { generator_diagnostic_data: Table>>, may_have_doc_links: Table, variant_data: Table>, + assoc_container: Table, } #[derive(Copy, Clone, MetadataEncodable, MetadataDecodable)] @@ -423,9 +424,9 @@ enum EntryKind { Generator, Trait, Impl, - AssocFn { container: ty::AssocItemContainer, has_self: bool }, - AssocType(ty::AssocItemContainer), - AssocConst(ty::AssocItemContainer), + AssocFn { has_self: bool }, + AssocType, + AssocConst, TraitAlias, } diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 21841ae2532a..6000df759348 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -141,6 +141,13 @@ fixed_size_enum! { } } +fixed_size_enum! { + ty::AssocItemContainer { + ( TraitContainer ) + ( ImplContainer ) + } +} + // We directly encode `DefPathHash` because a `LazyValue` would incur a 25% cost. impl FixedSizeEncoding for Option { type ByteArray = [u8; 16]; diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 19b8f27bc95c..ca24c0d1ce38 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -55,6 +55,7 @@ trivially_parameterized_over_tcx! { crate::middle::exported_symbols::SymbolExportInfo, crate::middle::resolve_lifetime::ObjectLifetimeDefault, crate::mir::ConstQualifs, + ty::AssocItemContainer, ty::Generics, ty::ImplPolarity, ty::ReprOptions, From 1ddb9443116dca2fc0caedc616b9b297a9b4bea4 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 8 Jun 2022 21:38:04 +0200 Subject: [PATCH 3948/5092] Use tables for macros. --- compiler/rustc_metadata/src/rmeta/decoder.rs | 18 +++++++++++------- compiler/rustc_metadata/src/rmeta/encoder.rs | 6 ++++-- compiler/rustc_metadata/src/rmeta/mod.rs | 6 ++++-- compiler/rustc_metadata/src/rmeta/table.rs | 8 ++++++++ compiler/rustc_middle/src/ty/parameterized.rs | 2 +- 5 files changed, 28 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 7e2ade03c73e..a29e1edc641d 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -4,7 +4,6 @@ use crate::creader::{CStore, CrateMetadataRef}; use crate::rmeta::*; use rustc_ast as ast; -use rustc_ast::ptr::P; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::svh::Svh; @@ -1025,10 +1024,15 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { let vis = self.get_visibility(child_index); let span = self.get_span(child_index, sess); let macro_rules = match kind { - DefKind::Macro(..) => match self.kind(child_index) { - EntryKind::MacroDef(_, macro_rules) => macro_rules, - _ => unreachable!(), - }, + DefKind::Macro(..) => { + self.root + .tables + .macro_definition + .get(self, child_index) + .unwrap() + .decode((self, sess)) + .macro_rules + } _ => false, }; @@ -1344,8 +1348,8 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn get_macro(self, id: DefIndex, sess: &Session) -> ast::MacroDef { match self.kind(id) { - EntryKind::MacroDef(mac_args, macro_rules) => { - ast::MacroDef { body: P(mac_args.decode((self, sess))), macro_rules } + EntryKind::MacroDef => { + self.root.tables.macro_definition.get(self, id).unwrap().decode((self, sess)) } _ => bug!(), } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 25590af84f64..fdc25270e971 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1512,7 +1512,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { EntryKind::Fn } hir::ItemKind::Macro(ref macro_def, _) => { - EntryKind::MacroDef(self.lazy(&*macro_def.body), macro_def.macro_rules) + record!(self.tables.macro_definition[def_id] <- macro_def); + EntryKind::MacroDef } hir::ItemKind::Mod(ref m) => { return self.encode_info_for_mod(item.def_id, m); @@ -1819,7 +1820,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let def_id = id.to_def_id(); self.tables.opt_def_kind.set(def_id.index, DefKind::Macro(macro_kind)); - record!(self.tables.kind[def_id] <- EntryKind::ProcMacro(macro_kind)); + self.tables.proc_macro.set(def_id.index, macro_kind); + record!(self.tables.kind[def_id] <- EntryKind::ProcMacro); self.encode_attrs(id); record!(self.tables.def_keys[def_id] <- def_key); record!(self.tables.def_ident_span[def_id] <- span); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 7537f2c68e59..0367f244c000 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -395,6 +395,8 @@ define_tables! { may_have_doc_links: Table, variant_data: Table>, assoc_container: Table, + macro_definition: Table>, + proc_macro: Table, } #[derive(Copy, Clone, MetadataEncodable, MetadataDecodable)] @@ -418,8 +420,8 @@ enum EntryKind { Fn, ForeignFn, Mod(LazyArray), - MacroDef(LazyValue, /*macro_rules*/ bool), - ProcMacro(MacroKind), + MacroDef, + ProcMacro, Closure, Generator, Trait, diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 6000df759348..9f88aeec9214 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -148,6 +148,14 @@ fixed_size_enum! { } } +fixed_size_enum! { + MacroKind { + ( Attr ) + ( Bang ) + ( Derive ) + } +} + // We directly encode `DefPathHash` because a `LazyValue` would incur a 25% cost. impl FixedSizeEncoding for Option { type ByteArray = [u8; 16]; diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index ca24c0d1ce38..504d02c1608c 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -64,7 +64,7 @@ trivially_parameterized_over_tcx! { ty::adjustment::CoerceUnsizedInfo, ty::fast_reject::SimplifiedTypeGen, rustc_ast::Attribute, - rustc_ast::MacArgs, + rustc_ast::MacroDef, rustc_attr::ConstStability, rustc_attr::DefaultBodyStability, rustc_attr::Deprecation, From 30ae64e51fae5bfbe93199dd1795207444d9931f Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 3 Jul 2022 17:49:06 +0200 Subject: [PATCH 3949/5092] Create a table for fn_has_self_parameter. --- compiler/rustc_metadata/src/rmeta/decoder.rs | 14 ++++++-------- compiler/rustc_metadata/src/rmeta/encoder.rs | 14 ++++++++------ compiler/rustc_metadata/src/rmeta/mod.rs | 4 +++- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index a29e1edc641d..b62aa95b254b 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1115,10 +1115,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_fn_has_self_parameter(self, id: DefIndex) -> bool { - match self.kind(id) { - EntryKind::AssocFn { has_self } => has_self, - _ => false, - } + self.root.tables.fn_has_self_parameter.get(self, id).is_some() } fn get_associated_item_def_ids( @@ -1138,12 +1135,13 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn get_associated_item(self, id: DefIndex) -> ty::AssocItem { let name = self.item_name(id); - let (kind, has_self) = match self.kind(id) { - EntryKind::AssocConst => (ty::AssocKind::Const, false), - EntryKind::AssocFn { has_self } => (ty::AssocKind::Fn, has_self), - EntryKind::AssocType => (ty::AssocKind::Type, false), + let kind = match self.kind(id) { + EntryKind::AssocConst => ty::AssocKind::Const, + EntryKind::AssocFn => ty::AssocKind::Fn, + EntryKind::AssocType => ty::AssocKind::Type, _ => bug!("cannot get associated-item of `{:?}`", self.def_key(id)), }; + let has_self = self.get_fn_has_self_parameter(id); let container = self.root.tables.assoc_container.get(self, id).unwrap(); ty::AssocItem { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index fdc25270e971..65f93ce1a25d 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1344,9 +1344,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }; self.tables.asyncness.set(def_id.index, m_sig.header.asyncness); self.tables.constness.set(def_id.index, hir::Constness::NotConst); - record!(self.tables.kind[def_id] <- EntryKind::AssocFn { - has_self: trait_item.fn_has_self_parameter, - }); + if trait_item.fn_has_self_parameter { + self.tables.fn_has_self_parameter.set(def_id.index, ()); + } + record!(self.tables.kind[def_id] <- EntryKind::AssocFn ); } ty::AssocKind::Type => { self.encode_explicit_item_bounds(def_id); @@ -1382,9 +1383,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::Constness::NotConst }; self.tables.constness.set(def_id.index, constness); - record!(self.tables.kind[def_id] <- EntryKind::AssocFn { - has_self: impl_item.fn_has_self_parameter, - }); + if impl_item.fn_has_self_parameter { + self.tables.fn_has_self_parameter.set(def_id.index, ()); + } + record!(self.tables.kind[def_id] <- EntryKind::AssocFn); } ty::AssocKind::Type => { record!(self.tables.kind[def_id] <- EntryKind::AssocType); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 0367f244c000..f32fed6ec476 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -397,6 +397,8 @@ define_tables! { assoc_container: Table, macro_definition: Table>, proc_macro: Table, + // Slot is full when there is a self parameter. + fn_has_self_parameter: Table, } #[derive(Copy, Clone, MetadataEncodable, MetadataDecodable)] @@ -426,7 +428,7 @@ enum EntryKind { Generator, Trait, Impl, - AssocFn { has_self: bool }, + AssocFn, AssocType, AssocConst, TraitAlias, From d330dc8c115f375eb99f33261cdcba581b5a89a9 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 3 Jul 2022 17:49:13 +0200 Subject: [PATCH 3950/5092] Fix the panic message. --- compiler/rustc_metadata/src/rmeta/table.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 9f88aeec9214..4e95561cfc0e 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -51,7 +51,7 @@ macro_rules! fixed_size_enum { } match b[0] - 1 { $(${index()} => Some($($pat)*),)* - _ => panic!("Unexpected ImplPolarity code: {:?}", b[0]), + _ => panic!("Unexpected {} code: {:?}", stringify!($ty), b[0]), } } From affb12210d4ab5fc914c6b3e7aa81c79a341d502 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 3 Jul 2022 17:54:15 +0200 Subject: [PATCH 3951/5092] Create a module-reexports table. --- compiler/rustc_metadata/src/rmeta/decoder.rs | 16 +++++----------- compiler/rustc_metadata/src/rmeta/encoder.rs | 10 ++++------ compiler/rustc_metadata/src/rmeta/mod.rs | 3 ++- 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index b62aa95b254b..fa82ac1d50bb 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1086,14 +1086,10 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - match self.kind(id) { - EntryKind::Mod(exports) => { - for exp in exports.decode((self, sess)) { - callback(exp); - } + if let Some(exports) = self.root.tables.module_reexports.get(self, id) { + for exp in exports.decode((self, sess)) { + callback(exp); } - EntryKind::Enum | EntryKind::Trait => {} - _ => bug!("`for_each_module_child` is called on a non-module: {:?}", self.def_kind(id)), } } @@ -1106,10 +1102,8 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn module_expansion(self, id: DefIndex, sess: &Session) -> ExpnId { - match self.kind(id) { - EntryKind::Mod(_) | EntryKind::Enum | EntryKind::Trait => { - self.get_expn_that_defined(id, sess) - } + match self.def_kind(id) { + DefKind::Mod | DefKind::Enum | DefKind::Trait => self.get_expn_that_defined(id, sess), _ => panic!("Expected module, found {:?}", self.local_def_id(id)), } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 65f93ce1a25d..e5eab16d8f17 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1254,15 +1254,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // code uses it). However, we skip encoding anything relating to child // items - we encode information about proc-macros later on. let reexports = if !self.is_proc_macro { - match tcx.module_reexports(local_def_id) { - Some(exports) => self.lazy_array(exports), - _ => LazyArray::empty(), - } + tcx.module_reexports(local_def_id).unwrap_or(&[]) } else { - LazyArray::empty() + &[] }; - record!(self.tables.kind[def_id] <- EntryKind::Mod(reexports)); + record_array!(self.tables.module_reexports[def_id] <- reexports); + record!(self.tables.kind[def_id] <- EntryKind::Mod); if self.is_proc_macro { // Encode this here because we don't do it in encode_def_ids. record!(self.tables.expn_that_defined[def_id] <- tcx.expn_that_defined(local_def_id)); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index f32fed6ec476..d69fb3471914 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -399,6 +399,7 @@ define_tables! { proc_macro: Table, // Slot is full when there is a self parameter. fn_has_self_parameter: Table, + module_reexports: Table>, } #[derive(Copy, Clone, MetadataEncodable, MetadataDecodable)] @@ -421,7 +422,7 @@ enum EntryKind { Union, Fn, ForeignFn, - Mod(LazyArray), + Mod, MacroDef, ProcMacro, Closure, From c485fccd8110bc3dc85187d1487d614c771e5362 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 3 Jul 2022 18:02:35 +0200 Subject: [PATCH 3952/5092] Remove EntryKind. --- compiler/rustc_metadata/src/rmeta/decoder.rs | 56 +++++------- compiler/rustc_metadata/src/rmeta/encoder.rs | 89 +++----------------- compiler/rustc_metadata/src/rmeta/mod.rs | 35 -------- 3 files changed, 32 insertions(+), 148 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index fa82ac1d50bb..8ebc0c4700e2 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -785,26 +785,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { self.opt_item_ident(item_index, sess).expect("no encoded ident for item") } - fn maybe_kind(self, item_id: DefIndex) -> Option { - self.root.tables.kind.get(self, item_id).map(|k| k.decode(self)) - } - #[inline] pub(super) fn map_encoded_cnum_to_current(self, cnum: CrateNum) -> CrateNum { if cnum == LOCAL_CRATE { self.cnum } else { self.cnum_map[cnum] } } - fn kind(self, item_id: DefIndex) -> EntryKind { - self.maybe_kind(item_id).unwrap_or_else(|| { - bug!( - "CrateMetadata::kind({:?}): id not found, in crate {:?} with number {}", - item_id, - self.root.name, - self.cnum, - ) - }) - } - fn def_kind(self, item_id: DefIndex) -> DefKind { self.root.tables.opt_def_kind.get(self, item_id).unwrap_or_else(|| { bug!( @@ -856,11 +841,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { ) } - fn get_variant(self, kind: &EntryKind, index: DefIndex, parent_did: DefId) -> ty::VariantDef { + fn get_variant(self, kind: &DefKind, index: DefIndex, parent_did: DefId) -> ty::VariantDef { let adt_kind = match kind { - EntryKind::Variant => ty::AdtKind::Enum, - EntryKind::Struct => ty::AdtKind::Struct, - EntryKind::Union => ty::AdtKind::Union, + DefKind::Variant => ty::AdtKind::Enum, + DefKind::Struct => ty::AdtKind::Struct, + DefKind::Union => ty::AdtKind::Union, _ => bug!(), }; @@ -896,13 +881,13 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_adt_def(self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::AdtDef<'tcx> { - let kind = self.kind(item_id); + let kind = self.def_kind(item_id); let did = self.local_def_id(item_id); let adt_kind = match kind { - EntryKind::Enum => ty::AdtKind::Enum, - EntryKind::Struct => ty::AdtKind::Struct, - EntryKind::Union => ty::AdtKind::Union, + DefKind::Enum => ty::AdtKind::Enum, + DefKind::Struct => ty::AdtKind::Struct, + DefKind::Union => ty::AdtKind::Union, _ => bug!("get_adt_def called on a non-ADT {:?}", did), }; let repr = self.root.tables.repr_options.get(self, item_id).unwrap().decode(self); @@ -914,7 +899,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .get(self, item_id) .unwrap_or_else(LazyArray::empty) .decode(self) - .map(|index| self.get_variant(&self.kind(index), index, did)) + .map(|index| self.get_variant(&self.def_kind(index), index, did)) .collect() } else { std::iter::once(self.get_variant(&kind, item_id, did)).collect() @@ -1129,10 +1114,10 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn get_associated_item(self, id: DefIndex) -> ty::AssocItem { let name = self.item_name(id); - let kind = match self.kind(id) { - EntryKind::AssocConst => ty::AssocKind::Const, - EntryKind::AssocFn => ty::AssocKind::Fn, - EntryKind::AssocType => ty::AssocKind::Type, + let kind = match self.def_kind(id) { + DefKind::AssocConst => ty::AssocKind::Const, + DefKind::AssocFn => ty::AssocKind::Fn, + DefKind::AssocTy => ty::AssocKind::Type, _ => bug!("cannot get associated-item of `{:?}`", self.def_key(id)), }; let has_self = self.get_fn_has_self_parameter(id); @@ -1149,8 +1134,8 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_ctor_def_id_and_kind(self, node_id: DefIndex) -> Option<(DefId, CtorKind)> { - match self.kind(node_id) { - EntryKind::Struct | EntryKind::Variant => { + match self.def_kind(node_id) { + DefKind::Struct | DefKind::Variant => { let vdata = self.root.tables.variant_data.get(self, node_id).unwrap().decode(self); vdata.ctor.map(|index| (self.local_def_id(index), vdata.ctor_kind)) } @@ -1339,8 +1324,8 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_macro(self, id: DefIndex, sess: &Session) -> ast::MacroDef { - match self.kind(id) { - EntryKind::MacroDef => { + match self.def_kind(id) { + DefKind::Macro(_) => { self.root.tables.macro_definition.get(self, id).unwrap().decode((self, sess)) } _ => bug!(), @@ -1348,9 +1333,10 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn is_foreign_item(self, id: DefIndex) -> bool { - match self.kind(id) { - EntryKind::ForeignStatic | EntryKind::ForeignFn => true, - _ => false, + if let Some(parent) = self.def_key(id).parent { + matches!(self.def_kind(parent), DefKind::ForeignMod) + } else { + false } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index e5eab16d8f17..927db8a6ab62 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -16,7 +16,6 @@ use rustc_hir::def_id::{ use rustc_hir::definitions::DefPathData; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::lang_items; -use rustc_hir::{AnonConst, GenericParamKind}; use rustc_middle::hir::nested_filter; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::{ @@ -1207,7 +1206,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }; record!(self.tables.variant_data[def_id] <- data); - record!(self.tables.kind[def_id] <- EntryKind::Variant); self.tables.constness.set(def_id.index, hir::Constness::Const); record_array!(self.tables.children[def_id] <- variant.fields.iter().map(|f| { assert!(f.did.is_local()); @@ -1236,7 +1234,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }; record!(self.tables.variant_data[def_id] <- data); - record!(self.tables.kind[def_id] <- EntryKind::Variant); self.tables.constness.set(def_id.index, hir::Constness::Const); if variant.ctor_kind == CtorKind::Fn { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); @@ -1260,7 +1257,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }; record_array!(self.tables.module_reexports[def_id] <- reexports); - record!(self.tables.kind[def_id] <- EntryKind::Mod); if self.is_proc_macro { // Encode this here because we don't do it in encode_def_ids. record!(self.tables.expn_that_defined[def_id] <- tcx.expn_that_defined(local_def_id)); @@ -1302,7 +1298,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.repr_options[def_id] <- adt_def.repr()); record!(self.tables.variant_data[def_id] <- data); - record!(self.tables.kind[def_id] <- EntryKind::Struct); self.tables.constness.set(def_id.index, hir::Constness::Const); if variant.ctor_kind == CtorKind::Fn { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); @@ -1327,9 +1322,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.tables.assoc_container.set(def_id.index, trait_item.container); match trait_item.kind { - ty::AssocKind::Const => { - record!(self.tables.kind[def_id] <- EntryKind::AssocConst); - } + ty::AssocKind::Const => {} ty::AssocKind::Fn => { let hir::TraitItemKind::Fn(m_sig, m) = &ast_item.kind else { bug!() }; match *m { @@ -1345,11 +1338,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if trait_item.fn_has_self_parameter { self.tables.fn_has_self_parameter.set(def_id.index, ()); } - record!(self.tables.kind[def_id] <- EntryKind::AssocFn ); } ty::AssocKind::Type => { self.encode_explicit_item_bounds(def_id); - record!(self.tables.kind[def_id] <- EntryKind::AssocType); } } if trait_item.kind == ty::AssocKind::Fn { @@ -1367,9 +1358,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.tables.assoc_container.set(def_id.index, impl_item.container); match impl_item.kind { - ty::AssocKind::Const => { - record!(self.tables.kind[def_id] <- EntryKind::AssocConst); - } ty::AssocKind::Fn => { let hir::ImplItemKind::Fn(ref sig, body) = ast_item.kind else { bug!() }; self.tables.asyncness.set(def_id.index, sig.header.asyncness); @@ -1384,11 +1372,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if impl_item.fn_has_self_parameter { self.tables.fn_has_self_parameter.set(def_id.index, ()); } - record!(self.tables.kind[def_id] <- EntryKind::AssocFn); - } - ty::AssocKind::Type => { - record!(self.tables.kind[def_id] <- EntryKind::AssocType); } + ty::AssocKind::Const | ty::AssocKind::Type => {} } if let Some(trait_item_def_id) = impl_item.trait_item_def_id { self.tables.trait_item_def_id.set(def_id.index, trait_item_def_id.into()); @@ -1502,33 +1487,24 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { debug!("EncodeContext::encode_info_for_item({:?})", def_id); - let entry_kind = match item.kind { - hir::ItemKind::Static(..) => EntryKind::Static, - hir::ItemKind::Const(..) => EntryKind::Const, + match item.kind { hir::ItemKind::Fn(ref sig, .., body) => { self.tables.asyncness.set(def_id.index, sig.header.asyncness); record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body)); self.tables.constness.set(def_id.index, sig.header.constness); - EntryKind::Fn } hir::ItemKind::Macro(ref macro_def, _) => { record!(self.tables.macro_definition[def_id] <- macro_def); - EntryKind::MacroDef } hir::ItemKind::Mod(ref m) => { return self.encode_info_for_mod(item.def_id, m); } - hir::ItemKind::ForeignMod { .. } => EntryKind::ForeignMod, - hir::ItemKind::GlobalAsm(..) => EntryKind::GlobalAsm, - hir::ItemKind::TyAlias(..) => EntryKind::Type, hir::ItemKind::OpaqueTy(..) => { self.encode_explicit_item_bounds(def_id); - EntryKind::OpaqueTy } hir::ItemKind::Enum(..) => { let adt_def = self.tcx.adt_def(def_id); record!(self.tables.repr_options[def_id] <- adt_def.repr()); - EntryKind::Enum } hir::ItemKind::Struct(ref struct_def, _) => { let adt_def = self.tcx.adt_def(def_id); @@ -1549,7 +1525,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { ctor, is_non_exhaustive: variant.is_field_list_non_exhaustive(), }); - EntryKind::Struct } hir::ItemKind::Union(..) => { let adt_def = self.tcx.adt_def(def_id); @@ -1562,7 +1537,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { ctor: None, is_non_exhaustive: variant.is_field_list_non_exhaustive(), }); - EntryKind::Union } hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => { self.tables.impl_defaultness.set(def_id.index, *defaultness); @@ -1588,26 +1562,24 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let polarity = self.tcx.impl_polarity(def_id); self.tables.impl_polarity.set(def_id.index, polarity); - - EntryKind::Impl } hir::ItemKind::Trait(..) => { let trait_def = self.tcx.trait_def(def_id); record!(self.tables.trait_def[def_id] <- trait_def); - - EntryKind::Trait } hir::ItemKind::TraitAlias(..) => { let trait_def = self.tcx.trait_def(def_id); record!(self.tables.trait_def[def_id] <- trait_def); - - EntryKind::TraitAlias } hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) => { bug!("cannot encode info for item {:?}", item) } + hir::ItemKind::Static(..) + | hir::ItemKind::Const(..) + | hir::ItemKind::ForeignMod { .. } + | hir::ItemKind::GlobalAsm(..) + | hir::ItemKind::TyAlias(..) => {} }; - record!(self.tables.kind[def_id] <- entry_kind); // FIXME(eddyb) there should be a nicer way to do this. match item.kind { hir::ItemKind::Enum(..) => record_array!(self.tables.children[def_id] <- @@ -1653,8 +1625,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { match item.kind { hir::ItemKind::Enum(..) => { let def = self.tcx.adt_def(item.def_id.to_def_id()); - self.encode_fields(def); - for (i, variant) in def.variants().iter_enumerated() { self.encode_enum_variant_info(def, i); @@ -1665,18 +1635,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } hir::ItemKind::Struct(ref struct_def, _) => { let def = self.tcx.adt_def(item.def_id.to_def_id()); - self.encode_fields(def); - // If the struct has a constructor, encode it. if let Some(ctor_hir_id) = struct_def.ctor_hir_id() { let ctor_def_id = self.tcx.hir().local_def_id(ctor_hir_id); self.encode_struct_ctor(def, ctor_def_id.to_def_id()); } } - hir::ItemKind::Union(..) => { - let def = self.tcx.adt_def(item.def_id.to_def_id()); - self.encode_fields(def); - } hir::ItemKind::Impl { .. } => { for &trait_item_def_id in self.tcx.associated_item_def_ids(item.def_id.to_def_id()).iter() @@ -1705,13 +1669,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { ty::Generator(..) => { let data = self.tcx.generator_kind(def_id).unwrap(); let generator_diagnostic_data = typeck_result.get_generator_diagnostic_data(); - record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::Generator); record!(self.tables.generator_kind[def_id.to_def_id()] <- data); record!(self.tables.generator_diagnostic_data[def_id.to_def_id()] <- generator_diagnostic_data); } ty::Closure(_, substs) => { - record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::Closure); record!(self.tables.fn_sig[def_id.to_def_id()] <- substs.as_closure().sig()); } @@ -1719,12 +1681,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } - fn encode_info_for_anon_const(&mut self, id: hir::HirId) { - let def_id = self.tcx.hir().local_def_id(id); - debug!("EncodeContext::encode_info_for_anon_const({:?})", def_id); - record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::AnonConst); - } - fn encode_native_libraries(&mut self) -> LazyArray { empty_proc_macro!(self); let used_libraries = self.tcx.native_libraries(LOCAL_CRATE); @@ -1821,7 +1777,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let def_id = id.to_def_id(); self.tables.opt_def_kind.set(def_id.index, DefKind::Macro(macro_kind)); self.tables.proc_macro.set(def_id.index, macro_kind); - record!(self.tables.kind[def_id] <- EntryKind::ProcMacro); self.encode_attrs(id); record!(self.tables.def_keys[def_id] <- def_key); record!(self.tables.def_ident_span[def_id] <- span); @@ -2059,15 +2014,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::Constness::NotConst }; self.tables.constness.set(def_id.index, constness); - record!(self.tables.kind[def_id] <- EntryKind::ForeignFn); record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); } - hir::ForeignItemKind::Static(..) => { - record!(self.tables.kind[def_id] <- EntryKind::ForeignStatic); - } - hir::ForeignItemKind::Type => { - record!(self.tables.kind[def_id] <- EntryKind::ForeignType); - } + hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => {} } if let hir::ForeignItemKind::Fn(..) = nitem.kind { if tcx.is_intrinsic(def_id) { @@ -2088,10 +2037,6 @@ impl<'a, 'tcx> Visitor<'tcx> for EncodeContext<'a, 'tcx> { intravisit::walk_expr(self, ex); self.encode_info_for_expr(ex); } - fn visit_anon_const(&mut self, c: &'tcx AnonConst) { - intravisit::walk_anon_const(self, c); - self.encode_info_for_anon_const(c.hir_id); - } fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { intravisit::walk_item(self, item); match item.kind { @@ -2110,24 +2055,12 @@ impl<'a, 'tcx> Visitor<'tcx> for EncodeContext<'a, 'tcx> { } impl<'a, 'tcx> EncodeContext<'a, 'tcx> { - fn encode_fields(&mut self, adt_def: ty::AdtDef<'tcx>) { - for (variant_index, variant) in adt_def.variants().iter_enumerated() { - for (field_index, _field) in variant.fields.iter().enumerate() { - let variant = &adt_def.variant(variant_index); - let field = &variant.fields[field_index]; - let def_id = field.did; - debug!("EncodeContext::encode_field({:?})", def_id); - record!(self.tables.kind[def_id] <- EntryKind::Field); - } - } - } - fn encode_info_for_generics(&mut self, generics: &hir::Generics<'tcx>) { for param in generics.params { let def_id = self.tcx.hir().local_def_id(param.hir_id); match param.kind { - GenericParamKind::Lifetime { .. } | GenericParamKind::Type { .. } => {} - GenericParamKind::Const { ref default, .. } => { + hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => {} + hir::GenericParamKind::Const { ref default, .. } => { let def_id = def_id.to_def_id(); if default.is_some() { record!(self.tables.const_param_default[def_id] <- self.tcx.const_param_default(def_id)) diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index d69fb3471914..04136b681342 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -334,7 +334,6 @@ macro_rules! define_tables { } define_tables! { - kind: Table>, attributes: Table>, children: Table>, @@ -402,39 +401,6 @@ define_tables! { module_reexports: Table>, } -#[derive(Copy, Clone, MetadataEncodable, MetadataDecodable)] -enum EntryKind { - AnonConst, - Const, - Static, - ForeignStatic, - ForeignMod, - ForeignType, - GlobalAsm, - Type, - TypeParam, - ConstParam, - OpaqueTy, - Enum, - Field, - Variant, - Struct, - Union, - Fn, - ForeignFn, - Mod, - MacroDef, - ProcMacro, - Closure, - Generator, - Trait, - Impl, - AssocFn, - AssocType, - AssocConst, - TraitAlias, -} - #[derive(TyEncodable, TyDecodable)] struct VariantData { ctor_kind: CtorKind, @@ -466,7 +432,6 @@ pub fn provide(providers: &mut Providers) { trivially_parameterized_over_tcx! { VariantData, - EntryKind, RawDefId, TraitImpls, IncoherentImpls, From b0b46c0a105a7b3144c28440c8ec5a7e182bf0e5 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 6 Jul 2022 11:11:11 +0200 Subject: [PATCH 3953/5092] Separate macro_rules and macro_definition. --- compiler/rustc_metadata/src/rmeta/decoder.rs | 13 +++++-------- compiler/rustc_metadata/src/rmeta/encoder.rs | 5 ++++- compiler/rustc_metadata/src/rmeta/mod.rs | 4 +++- compiler/rustc_middle/src/ty/parameterized.rs | 2 +- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 8ebc0c4700e2..a540c4606c93 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1010,13 +1010,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { let span = self.get_span(child_index, sess); let macro_rules = match kind { DefKind::Macro(..) => { - self.root - .tables - .macro_definition - .get(self, child_index) - .unwrap() - .decode((self, sess)) - .macro_rules + self.root.tables.macro_rules.get(self, child_index).is_some() } _ => false, }; @@ -1326,7 +1320,10 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn get_macro(self, id: DefIndex, sess: &Session) -> ast::MacroDef { match self.def_kind(id) { DefKind::Macro(_) => { - self.root.tables.macro_definition.get(self, id).unwrap().decode((self, sess)) + let macro_rules = self.root.tables.macro_rules.get(self, id).is_some(); + let body = + self.root.tables.macro_definition.get(self, id).unwrap().decode((self, sess)); + ast::MacroDef { macro_rules, body: ast::ptr::P(body) } } _ => bug!(), } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 927db8a6ab62..1288d19cb086 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1494,7 +1494,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.tables.constness.set(def_id.index, sig.header.constness); } hir::ItemKind::Macro(ref macro_def, _) => { - record!(self.tables.macro_definition[def_id] <- macro_def); + if macro_def.macro_rules { + self.tables.macro_rules.set(def_id.index, ()); + } + record!(self.tables.macro_definition[def_id] <- &*macro_def.body); } hir::ItemKind::Mod(ref m) => { return self.encode_info_for_mod(item.def_id, m); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 04136b681342..bb5b40bcc5b1 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -394,7 +394,9 @@ define_tables! { may_have_doc_links: Table, variant_data: Table>, assoc_container: Table, - macro_definition: Table>, + // Slot is full when macro is macro_rules. + macro_rules: Table, + macro_definition: Table>, proc_macro: Table, // Slot is full when there is a self parameter. fn_has_self_parameter: Table, diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 504d02c1608c..ca24c0d1ce38 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -64,7 +64,7 @@ trivially_parameterized_over_tcx! { ty::adjustment::CoerceUnsizedInfo, ty::fast_reject::SimplifiedTypeGen, rustc_ast::Attribute, - rustc_ast::MacroDef, + rustc_ast::MacArgs, rustc_attr::ConstStability, rustc_attr::DefaultBodyStability, rustc_attr::Deprecation, From b94d421d08da7cf27757abd9a7a6fdf8674a844f Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 4 Aug 2022 22:03:16 +0200 Subject: [PATCH 3954/5092] Remove fn_has_self_parameter table. --- compiler/rustc_metadata/src/rmeta/decoder.rs | 17 ++++++++++++----- .../src/rmeta/decoder/cstore_impl.rs | 6 +++--- compiler/rustc_metadata/src/rmeta/encoder.rs | 6 ------ compiler/rustc_metadata/src/rmeta/mod.rs | 2 -- .../rustc_resolve/src/build_reduced_graph.rs | 2 +- 5 files changed, 16 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index a540c4606c93..8e49ced56efe 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -32,7 +32,7 @@ use rustc_session::cstore::{ use rustc_session::Session; use rustc_span::hygiene::{ExpnIndex, MacroKind}; use rustc_span::source_map::{respan, Spanned}; -use rustc_span::symbol::{sym, Ident, Symbol}; +use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{self, BytePos, ExpnId, Pos, Span, SyntaxContext, DUMMY_SP}; use proc_macro::bridge::client::ProcMacro; @@ -1087,8 +1087,15 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn get_fn_has_self_parameter(self, id: DefIndex) -> bool { - self.root.tables.fn_has_self_parameter.get(self, id).is_some() + fn get_fn_has_self_parameter(self, id: DefIndex, sess: &'a Session) -> bool { + self.root + .tables + .fn_arg_names + .get(self, id) + .unwrap_or_else(LazyArray::empty) + .decode((self, sess)) + .nth(0) + .map_or(false, |ident| ident.name == kw::SelfLower) } fn get_associated_item_def_ids( @@ -1105,7 +1112,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .map(move |child_index| self.local_def_id(child_index)) } - fn get_associated_item(self, id: DefIndex) -> ty::AssocItem { + fn get_associated_item(self, id: DefIndex, sess: &'a Session) -> ty::AssocItem { let name = self.item_name(id); let kind = match self.def_kind(id) { @@ -1114,7 +1121,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { DefKind::AssocTy => ty::AssocKind::Type, _ => bug!("cannot get associated-item of `{:?}`", self.def_key(id)), }; - let has_self = self.get_fn_has_self_parameter(id); + let has_self = self.get_fn_has_self_parameter(id, sess); let container = self.root.tables.assoc_container.get(self, id).unwrap(); ty::AssocItem { diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 9d201a0c7999..6b447ebd9991 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -233,7 +233,7 @@ provide! { tcx, def_id, other, cdata, associated_item_def_ids => { tcx.arena.alloc_from_iter(cdata.get_associated_item_def_ids(def_id.index, tcx.sess)) } - associated_item => { cdata.get_associated_item(def_id.index) } + associated_item => { cdata.get_associated_item(def_id.index, tcx.sess) } inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) } is_foreign_item => { cdata.is_foreign_item(def_id.index) } item_attrs => { tcx.arena.alloc_from_iter(cdata.get_item_attrs(def_id.index, tcx.sess)) } @@ -535,8 +535,8 @@ impl CStore { ) } - pub fn fn_has_self_parameter_untracked(&self, def: DefId) -> bool { - self.get_crate_data(def.krate).get_fn_has_self_parameter(def.index) + pub fn fn_has_self_parameter_untracked(&self, def: DefId, sess: &Session) -> bool { + self.get_crate_data(def.krate).get_fn_has_self_parameter(def.index, sess) } pub fn crate_source_untracked(&self, cnum: CrateNum) -> Lrc { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 1288d19cb086..578a416ce6ba 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1335,9 +1335,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }; self.tables.asyncness.set(def_id.index, m_sig.header.asyncness); self.tables.constness.set(def_id.index, hir::Constness::NotConst); - if trait_item.fn_has_self_parameter { - self.tables.fn_has_self_parameter.set(def_id.index, ()); - } } ty::AssocKind::Type => { self.encode_explicit_item_bounds(def_id); @@ -1369,9 +1366,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { hir::Constness::NotConst }; self.tables.constness.set(def_id.index, constness); - if impl_item.fn_has_self_parameter { - self.tables.fn_has_self_parameter.set(def_id.index, ()); - } } ty::AssocKind::Const | ty::AssocKind::Type => {} } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index bb5b40bcc5b1..6f849a58580e 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -398,8 +398,6 @@ define_tables! { macro_rules: Table, macro_definition: Table>, proc_macro: Table, - // Slot is full when there is a self parameter. - fn_has_self_parameter: Table, module_reexports: Table>, } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 8f3b6009bd6e..052d05974cd8 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -1030,7 +1030,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { self.insert_field_names(def_id, field_names); } Res::Def(DefKind::AssocFn, def_id) => { - if cstore.fn_has_self_parameter_untracked(def_id) { + if cstore.fn_has_self_parameter_untracked(def_id, self.r.session) { self.r.has_self.insert(def_id); } } From 60a052f4d308b4b7e3b6132fd4bb2a48082b066c Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 3 Jul 2022 19:59:37 +0200 Subject: [PATCH 3955/5092] Handle MIR in a single place. --- compiler/rustc_metadata/src/rmeta/encoder.rs | 36 +++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 578a416ce6ba..ce5d51ebb58b 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1162,15 +1162,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if should_encode_type(tcx, local_id, def_kind) { record!(self.tables.type_of[def_id] <- self.tcx.type_of(def_id)); } - if should_encode_const(def_kind) && tcx.is_mir_available(def_id) { - let qualifs = tcx.at(def_span).mir_const_qualif(def_id); - record!(self.tables.mir_const_qualif[def_id] <- qualifs); - let body_id = tcx.hir().maybe_body_owned_by(local_id); - if let Some(body_id) = body_id { - let const_data = self.encode_rendered_const_for_body(body_id); - record!(self.tables.rendered_const[def_id] <- const_data); - } - } if let DefKind::TyParam | DefKind::ConstParam = def_kind { if let Some(default) = self.tcx.object_lifetime_default(def_id) { record!(self.tables.object_lifetime_default[def_id] <- default); @@ -1385,12 +1376,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { return; } - let keys_and_jobs = self - .tcx + let tcx = self.tcx; + + let keys_and_jobs = tcx .mir_keys(()) .iter() .filter_map(|&def_id| { - let (encode_const, encode_opt) = should_encode_mir(self.tcx, def_id); + let (encode_const, encode_opt) = should_encode_mir(tcx, def_id); if encode_const || encode_opt { Some((def_id, encode_const, encode_opt)) } else { @@ -1403,22 +1395,32 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { debug!("EntryBuilder::encode_mir({:?})", def_id); if encode_opt { - record!(self.tables.optimized_mir[def_id.to_def_id()] <- self.tcx.optimized_mir(def_id)); + record!(self.tables.optimized_mir[def_id.to_def_id()] <- tcx.optimized_mir(def_id)); } if encode_const { - record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- self.tcx.mir_for_ctfe(def_id)); + record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- tcx.mir_for_ctfe(def_id)); // FIXME(generic_const_exprs): this feels wrong to have in `encode_mir` - let abstract_const = self.tcx.thir_abstract_const(def_id); + let abstract_const = tcx.thir_abstract_const(def_id); if let Ok(Some(abstract_const)) = abstract_const { record!(self.tables.thir_abstract_const[def_id.to_def_id()] <- abstract_const); } + + if should_encode_const(tcx.def_kind(def_id)) { + let qualifs = tcx.mir_const_qualif(def_id); + record!(self.tables.mir_const_qualif[def_id.to_def_id()] <- qualifs); + let body_id = tcx.hir().maybe_body_owned_by(def_id); + if let Some(body_id) = body_id { + let const_data = self.encode_rendered_const_for_body(body_id); + record!(self.tables.rendered_const[def_id.to_def_id()] <- const_data); + } + } } - record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(def_id)); + record!(self.tables.promoted_mir[def_id.to_def_id()] <- tcx.promoted_mir(def_id)); let instance = ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id.to_def_id())); - let unused = self.tcx.unused_generic_params(instance); + let unused = tcx.unused_generic_params(instance); if !unused.is_empty() { record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused); } From 45dac9a3ef029f216cc0369ee0f1522c2a2aa03e Mon Sep 17 00:00:00 2001 From: DropDemBits Date: Tue, 30 Aug 2022 14:47:08 -0400 Subject: [PATCH 3956/5092] Move comments to the extracted struct --- .../extract_struct_from_enum_variant.rs | 51 +++++++++++++++---- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs index 906be27ddbb8..ddc2052e7aa2 100644 --- a/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs @@ -105,7 +105,8 @@ pub(crate) fn extract_struct_from_enum_variant( .generic_param_list() .and_then(|known_generics| extract_generic_params(&known_generics, &field_list)); let generics = generic_params.as_ref().map(|generics| generics.clone_for_update()); - let def = create_struct_def(variant_name.clone(), &field_list, generics, &enum_ast); + let def = + create_struct_def(variant_name.clone(), &variant, &field_list, generics, &enum_ast); let enum_ast = variant.parent_enum(); let indent = enum_ast.indent_level(); @@ -228,6 +229,7 @@ fn tag_generics_in_variant(ty: &ast::Type, generics: &mut [(ast::GenericParam, b fn create_struct_def( name: ast::Name, + variant: &ast::Variant, field_list: &Either, generics: Option, enum_: &ast::Enum, @@ -272,6 +274,12 @@ fn create_struct_def( let strukt = make::struct_(enum_vis, name, generics, field_list).clone_for_update(); + // take comments from variant + ted::insert_all( + ted::Position::first_child_of(strukt.syntax()), + take_all_comments(variant.syntax()), + ); + // copy attributes from enum ted::insert_all( ted::Position::first_child_of(strukt.syntax()), @@ -340,6 +348,31 @@ fn update_variant(variant: &ast::Variant, generics: Option Vec { + let mut remove_next_ws = false; + node.children_with_tokens() + .filter_map(move |child| match child.kind() { + COMMENT => { + remove_next_ws = true; + child.detach(); + Some(child) + } + WHITESPACE if remove_next_ws => { + remove_next_ws = false; + child.detach(); + Some(make::tokens::single_newline().into()) + } + _ => { + remove_next_ws = false; + None + } + }) + .collect() +} + fn apply_references( insert_use_cfg: InsertUseConfig, segment: ast::PathSegment, @@ -602,7 +635,7 @@ enum A { One(One) }"#, } #[test] - fn test_extract_struct_keep_comments_and_attrs_on_variant_struct() { + fn test_extract_struct_move_struct_variant_comments() { check_assist( extract_struct_from_enum_variant, r#" @@ -616,14 +649,14 @@ enum A { } }"#, r#" +/* comment */ +// other +/// comment struct One{ a: u32 } enum A { - /* comment */ - // other - /// comment #[attr] One(One) }"#, @@ -631,7 +664,7 @@ enum A { } #[test] - fn test_extract_struct_keep_comments_and_attrs_on_variant_tuple() { + fn test_extract_struct_move_tuple_variant_comments() { check_assist( extract_struct_from_enum_variant, r#" @@ -643,12 +676,12 @@ enum A { $0One(u32, u32) }"#, r#" +/* comment */ +// other +/// comment struct One(u32, u32); enum A { - /* comment */ - // other - /// comment #[attr] One(One) }"#, From 662ab0cd8eb6784e764903325da30418a2095307 Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Wed, 31 Aug 2022 03:43:28 +0900 Subject: [PATCH 3957/5092] fix: unescape all occurrences of module name in module resolution --- crates/hir-def/src/nameres/mod_resolution.rs | 3 +-- .../hir-def/src/nameres/tests/mod_resolution.rs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/crates/hir-def/src/nameres/mod_resolution.rs b/crates/hir-def/src/nameres/mod_resolution.rs index 99f7f1b549e2..ca7bcc814e8f 100644 --- a/crates/hir-def/src/nameres/mod_resolution.rs +++ b/crates/hir-def/src/nameres/mod_resolution.rs @@ -65,6 +65,7 @@ impl ModDir { name: &Name, attr_path: Option<&SmolStr>, ) -> Result<(FileId, bool, ModDir), Box<[String]>> { + let name = name.unescaped(); let orig_file_id = file_id.original_file(db.upcast()); let mut candidate_files = ArrayVec::<_, 2>::new(); @@ -73,12 +74,10 @@ impl ModDir { candidate_files.push(self.dir_path.join_attr(attr_path, self.root_non_dir_owner)) } None if file_id.is_include_macro(db.upcast()) => { - let name = name.unescaped(); candidate_files.push(format!("{}.rs", name)); candidate_files.push(format!("{}/mod.rs", name)); } None => { - let name = name.unescaped(); candidate_files.push(format!("{}{}.rs", self.dir_path.0, name)); candidate_files.push(format!("{}{}/mod.rs", self.dir_path.0, name)); } diff --git a/crates/hir-def/src/nameres/tests/mod_resolution.rs b/crates/hir-def/src/nameres/tests/mod_resolution.rs index 3fa585574dee..ba3bf8b5a5cf 100644 --- a/crates/hir-def/src/nameres/tests/mod_resolution.rs +++ b/crates/hir-def/src/nameres/tests/mod_resolution.rs @@ -127,7 +127,15 @@ mod r#async; use self::r#async::Bar; //- /async.rs +mod foo; +mod r#async; pub struct Bar; + +//- /async/foo.rs +pub struct Foo; + +//- /async/async.rs +pub struct Baz; "#, expect![[r#" crate @@ -136,6 +144,14 @@ pub struct Bar; crate::r#async Bar: t v + foo: t + r#async: t + + crate::r#async::foo + Foo: t v + + crate::r#async::r#async + Baz: t v "#]], ); } From b9d3f654128ce6ba29e1e9ff31fcc44f2f04b59f Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Tue, 30 Aug 2022 15:17:45 -0700 Subject: [PATCH 3958/5092] [drop tracking] Use parent expression for scope Previously we were just using the parent node as the scope for a temporary value, but it turns out this is too narrow. For example, in an expression like Foo { b: &42, a: async { 0 }.await, } the scope for the &42 was set to the ExprField node for `b: &42`, when we actually want to use the Foo struct expression. We fix this by recursively searching through parent nodes until we find a Node::Expr. It may be that we don't find one, and if so that's okay, we will just fall back on the enclosing temporary scope which is always sufficient. --- .../src/check/generator_interior.rs | 17 +++++++++++++++-- .../drop_ranges/record_consumed_borrow.rs | 4 ++-- src/test/ui/async-await/issue-73137.rs | 3 +++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs index 85a0d4e44990..f73d498aabc2 100644 --- a/compiler/rustc_typeck/src/check/generator_interior.rs +++ b/compiler/rustc_typeck/src/check/generator_interior.rs @@ -387,6 +387,18 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { ty.needs_drop(self.fcx.tcx, self.fcx.param_env) }; + let find_parent_expr = |mut hir_id| { + let hir = self.fcx.tcx.hir(); + hir_id = hir.find_parent_node(hir_id)?; + loop { + if let hir::Node::Expr(_) = self.fcx.tcx.hir().find(hir_id)? { + return Some(hir_id); + } else { + hir_id = hir.find_parent_node(hir_id)?; + } + } + }; + // Typically, the value produced by an expression is consumed by its parent in some way, // so we only have to check if the parent contains a yield (note that the parent may, for // example, store the value into a local variable, but then we already consider local @@ -409,8 +421,9 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { }) { self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id) } else { - debug!("parent_node: {:?}", self.fcx.tcx.hir().find_parent_node(expr.hir_id)); - match self.fcx.tcx.hir().find_parent_node(expr.hir_id) { + let parent_expr = find_parent_expr(expr.hir_id); + debug!("parent_expr: {:?}", parent_expr); + match parent_expr { Some(parent) => Some(Scope { id: parent.local_id, data: ScopeData::Node }), None => { self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id) diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs index ded0888c33e1..e22675e9d5f4 100644 --- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs +++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs @@ -159,8 +159,8 @@ impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> { bk: rustc_middle::ty::BorrowKind, ) { debug!( - "borrow: place_with_id = {place_with_id:?}, diag_expr_id={diag_expr_id:?}, \ - borrow_kind={bk:?}" + "borrow: place_with_id = {place_with_id:#?}, diag_expr_id={diag_expr_id:#?}, \ + borrow_kind={bk:#?}" ); self.borrow_place(place_with_id); diff --git a/src/test/ui/async-await/issue-73137.rs b/src/test/ui/async-await/issue-73137.rs index c43ce2cadba0..dcbe7765a9e1 100644 --- a/src/test/ui/async-await/issue-73137.rs +++ b/src/test/ui/async-await/issue-73137.rs @@ -2,6 +2,9 @@ // run-pass // edition:2018 +// revisions: normal drop-tracking +// [normal]compile-flags: -Zdrop-tracking=no +// [drop-tracking]compile-flags: -Zdrop-tracking #![allow(dead_code)] use std::future::Future; From e5e979906b86472ec63846b5ab03b59f122fedec Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 31 Aug 2022 01:07:41 +0000 Subject: [PATCH 3959/5092] Use type information to deduce the correct type for "Replace turbofish with explicit type", even when it is not exactly the same as the turbofish type I implemented that by checking the expressions' type. This could probably be implemented better by taking the function's return type and substituting the generic parameter with the provided turbofish, but this is more complicated. --- .../replace_turbofish_with_explicit_type.rs | 94 ++++++++++++++++++- 1 file changed, 91 insertions(+), 3 deletions(-) diff --git a/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs b/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs index 5242f3b5100c..a2df56d2f693 100644 --- a/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs +++ b/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs @@ -1,3 +1,4 @@ +use hir::HirDisplay; use syntax::{ ast::{Expr, GenericArg}, ast::{LetStmt, Type::InferType}, @@ -65,7 +66,16 @@ pub(crate) fn replace_turbofish_with_explicit_type( // An improvement would be to check that this is correctly part of the return value of the // function call, or sub in the actual return type. - let turbofish_type = &turbofish_args[0]; + let returned_type = match ctx.sema.type_of_expr(&initializer) { + Some(returned_type) if !returned_type.original.contains_unknown() => { + let module = ctx.sema.scope(let_stmt.syntax())?.module(); + returned_type.original.display_source_code(ctx.db(), module.into()).ok()? + } + _ => { + cov_mark::hit!(fallback_to_turbofish_type_if_type_info_not_available); + turbofish_args[0].to_string() + } + }; let initializer_start = initializer.syntax().text_range().start(); if ctx.offset() > turbofish_range.end() || ctx.offset() < initializer_start { @@ -83,7 +93,7 @@ pub(crate) fn replace_turbofish_with_explicit_type( "Replace turbofish with explicit type", TextRange::new(initializer_start, turbofish_range.end()), |builder| { - builder.insert(ident_range.end(), format!(": {}", turbofish_type)); + builder.insert(ident_range.end(), format!(": {}", returned_type)); builder.delete(turbofish_range); }, ); @@ -98,7 +108,7 @@ pub(crate) fn replace_turbofish_with_explicit_type( "Replace `_` with turbofish type", turbofish_range, |builder| { - builder.replace(underscore_range, turbofish_type.to_string()); + builder.replace(underscore_range, returned_type); builder.delete(turbofish_range); }, ); @@ -115,6 +125,7 @@ mod tests { #[test] fn replaces_turbofish_for_vec_string() { + cov_mark::check!(fallback_to_turbofish_type_if_type_info_not_available); check_assist( replace_turbofish_with_explicit_type, r#" @@ -135,6 +146,7 @@ fn main() { #[test] fn replaces_method_calls() { // foo.make() is a method call which uses a different expr in the let initializer + cov_mark::check!(fallback_to_turbofish_type_if_type_info_not_available); check_assist( replace_turbofish_with_explicit_type, r#" @@ -237,6 +249,82 @@ fn make() -> T {} fn main() { let a = make$0::, i32>(); } +"#, + ); + } + + #[test] + fn replaces_turbofish_for_known_type() { + check_assist( + replace_turbofish_with_explicit_type, + r#" +fn make() -> T {} +fn main() { + let a = make$0::(); +} +"#, + r#" +fn make() -> T {} +fn main() { + let a: i32 = make(); +} +"#, + ); + check_assist( + replace_turbofish_with_explicit_type, + r#" +//- minicore: option +fn make() -> T {} +fn main() { + let a = make$0::>(); +} +"#, + r#" +fn make() -> T {} +fn main() { + let a: Option = make(); +} +"#, + ); + } + + #[test] + fn replaces_turbofish_not_same_type() { + check_assist( + replace_turbofish_with_explicit_type, + r#" +//- minicore: option +fn make() -> Option {} +fn main() { + let a = make$0::(); +} +"#, + r#" +fn make() -> Option {} +fn main() { + let a: Option = make(); +} +"#, + ); + } + + #[test] + fn replaces_turbofish_for_type_with_defaulted_generic_param() { + check_assist( + replace_turbofish_with_explicit_type, + r#" +struct HasDefault(T, U); +fn make() -> HasDefault {} +fn main() { + let a = make$0::(); +} +"#, + r#" +struct HasDefault(T, U); +fn make() -> HasDefault {} +fn main() { + let a: HasDefault = make(); +} "#, ); } From bcdacfe50182089772f6e454ecb0904392dfcc21 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 31 Aug 2022 01:24:36 +0000 Subject: [PATCH 3960/5092] Support `?` and `.await` in "Replace turbofish with explicit type" Now that we use type information this is easy. --- .../replace_turbofish_with_explicit_type.rs | 66 ++++++++++++++----- 1 file changed, 50 insertions(+), 16 deletions(-) diff --git a/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs b/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs index a2df56d2f693..521447c26dfb 100644 --- a/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs +++ b/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs @@ -1,6 +1,6 @@ use hir::HirDisplay; use syntax::{ - ast::{Expr, GenericArg}, + ast::{Expr, GenericArg, GenericArgList}, ast::{LetStmt, Type::InferType}, AstNode, TextRange, }; @@ -35,21 +35,7 @@ pub(crate) fn replace_turbofish_with_explicit_type( let initializer = let_stmt.initializer()?; - let generic_args = match &initializer { - Expr::MethodCallExpr(ce) => ce.generic_arg_list()?, - Expr::CallExpr(ce) => { - if let Expr::PathExpr(pe) = ce.expr()? { - pe.path()?.segment()?.generic_arg_list()? - } else { - cov_mark::hit!(not_applicable_if_non_path_function_call); - return None; - } - } - _ => { - cov_mark::hit!(not_applicable_if_non_function_call_initializer); - return None; - } - }; + let generic_args = generic_arg_list(&initializer)?; // Find range of ::<_> let colon2 = generic_args.coloncolon_token()?; @@ -117,6 +103,26 @@ pub(crate) fn replace_turbofish_with_explicit_type( None } +fn generic_arg_list(expr: &Expr) -> Option { + match expr { + Expr::MethodCallExpr(expr) => expr.generic_arg_list(), + Expr::CallExpr(expr) => { + if let Expr::PathExpr(pe) = expr.expr()? { + pe.path()?.segment()?.generic_arg_list() + } else { + cov_mark::hit!(not_applicable_if_non_path_function_call); + return None; + } + } + Expr::AwaitExpr(expr) => generic_arg_list(&expr.expr()?), + Expr::TryExpr(expr) => generic_arg_list(&expr.expr()?), + _ => { + cov_mark::hit!(not_applicable_if_non_function_call_initializer); + None + } + } +} + #[cfg(test)] mod tests { use super::*; @@ -325,6 +331,34 @@ fn make() -> HasDefault {} fn main() { let a: HasDefault = make(); } +"#, + ); + } + + #[test] + fn replaces_turbofish_try_await() { + check_assist( + replace_turbofish_with_explicit_type, + r#" +//- minicore: option, future +struct Fut(T); +impl core::future::Future for Fut { + type Output = Option; +} +fn make() -> Fut {} +fn main() { + let a = make$0::().await?; +} +"#, + r#" +struct Fut(T); +impl core::future::Future for Fut { + type Output = Option; +} +fn make() -> Fut {} +fn main() { + let a: bool = make().await?; +} "#, ); } From 3cf0e98dc9a67086f4e738edb9d61b2fee1a38b0 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Wed, 4 May 2022 10:22:19 -0400 Subject: [PATCH 3961/5092] Stabilize GATs --- compiler/rustc_ast_passes/src/feature_gate.rs | 22 +----- compiler/rustc_feature/src/accepted.rs | 2 + compiler/rustc_feature/src/active.rs | 2 - compiler/rustc_lint_defs/src/builtin.rs | 2 - compiler/rustc_metadata/src/lib.rs | 2 +- compiler/rustc_middle/src/lib.rs | 2 +- .../src/traits/project.rs | 2 - src/librustdoc/lib.rs | 2 +- src/test/pretty/gat-bounds.rs | 2 - .../generic-associated-types/gats.rs | 2 +- .../rustdoc/generic-associated-types/gats.rs | 1 - .../generic-associated-types/issue-94683.rs | 1 - src/test/rustdoc/where.rs | 1 - .../associated-type-bounds/binder-on-bound.rs | 2 - .../binder-on-bound.stderr | 2 +- .../ui/associated-type-bounds/issue-79949.rs | 1 - src/test/ui/deriving/issue-89188-gat-hrtb.rs | 2 - .../feature-gate-generic_associated_types.rs | 31 -------- ...ature-gate-generic_associated_types.stderr | 78 ------------------- ...-gate-generic_associated_types_extended.rs | 2 - ...e-generic_associated_types_extended.stderr | 2 +- .../anonymize-bound-vars.rs | 1 - .../auxiliary/foo_defn.rs | 2 - .../bugs/issue-80626.rs | 2 - .../bugs/issue-80626.stderr | 4 +- .../bugs/issue-86218.rs | 1 - .../bugs/issue-86218.stderr | 6 +- .../bugs/issue-87735.rs | 2 - .../bugs/issue-87735.stderr | 2 +- .../bugs/issue-87755.rs | 2 - .../bugs/issue-87755.stderr | 2 +- .../bugs/issue-87803.rs | 2 - .../bugs/issue-87803.stderr | 2 +- .../bugs/issue-88382.rs | 2 - .../bugs/issue-88382.stderr | 4 +- .../bugs/issue-88460.rs | 2 - .../bugs/issue-88460.stderr | 4 +- .../bugs/issue-88526.rs | 2 - .../bugs/issue-88526.stderr | 2 +- .../bugs/issue-89008.rs | 1 - .../bugs/issue-89008.stderr | 4 +- .../{ => bugs}/issue-91762.rs | 5 +- .../{ => bugs}/issue-91762.stderr | 2 +- .../collections-project-default.rs | 1 - .../collections-project-default.stderr | 2 +- .../generic-associated-types/collections.rs | 1 - .../collectivity-regression.rs | 2 - .../collectivity-regression.stderr | 2 +- ...nst-generics-gat-in-trait-return-type-1.rs | 1 - ...nst-generics-gat-in-trait-return-type-2.rs | 1 - ...nst-generics-gat-in-trait-return-type-3.rs | 1 - .../const_params_have_right_type.rs | 2 - .../const_params_have_right_type.stderr | 2 +- .../constraint-assoc-type-suggestion.rs | 2 - .../constraint-assoc-type-suggestion.stderr | 2 +- .../construct_with_other_type.rs | 2 - .../cross-crate-bounds.stderr | 2 +- .../elided-in-expr-position.rs | 1 - .../elided-in-expr-position.stderr | 8 +- .../empty_generics.rs | 2 - .../empty_generics.stderr | 2 +- .../extended/lending_iterator.base.stderr | 2 +- .../extended/lending_iterator.rs | 1 - .../extended/lending_iterator_2.base.stderr | 2 +- .../extended/lending_iterator_2.rs | 1 - .../gat-dont-ice-on-absent-feature-2.rs | 16 ---- .../gat-dont-ice-on-absent-feature-2.stderr | 21 ----- .../gat-dont-ice-on-absent-feature.rs | 16 ---- .../gat-dont-ice-on-absent-feature.stderr | 19 ----- .../gat-in-trait-path-undeclared-lifetime.rs | 2 - ...t-in-trait-path-undeclared-lifetime.stderr | 4 +- .../gat-in-trait-path.base.stderr | 4 +- .../gat-in-trait-path.rs | 1 - .../gat-incomplete-warning.rs | 5 -- .../gat-trait-path-generic-type-arg.rs | 2 - .../gat-trait-path-generic-type-arg.stderr | 6 +- .../gat-trait-path-missing-lifetime.rs | 2 - .../gat-trait-path-missing-lifetime.stderr | 8 +- .../gat-trait-path-parenthesised-args.rs | 2 - .../gat-trait-path-parenthesised-args.stderr | 18 ++--- .../generic-associated-type-bounds.rs | 2 - .../generic-associated-types-where.rs | 2 - .../generic-associated-types-where.stderr | 4 +- ...ic_associated_type_undeclared_lifetimes.rs | 2 - ...ssociated_type_undeclared_lifetimes.stderr | 4 +- .../generic-associated-types/impl_bounds.rs | 1 - .../impl_bounds.stderr | 22 +++--- .../impl_bounds_ok.rs | 1 - .../generic-associated-types/issue-101020.rs | 2 - .../issue-101020.stderr | 6 +- .../issue-47206-where-clause.rs | 2 - .../issue-47206-where-clause.stderr | 2 +- .../issue-58694-parameter-out-of-range.rs | 2 - .../issue-62326-parameter-out-of-range.rs | 2 - .../generic-associated-types/issue-67424.rs | 2 +- .../issue-67424.stderr | 12 --- .../issue-67510-pass.base.stderr | 4 +- .../issue-67510-pass.rs | 1 - .../generic-associated-types/issue-67510.rs | 2 - .../issue-67510.stderr | 8 +- .../issue-68641-check-gat-bounds.rs | 2 - .../issue-68641-check-gat-bounds.stderr | 4 +- .../issue-68642-broken-llvm-ir.rs | 2 - .../issue-68642-broken-llvm-ir.stderr | 4 +- .../issue-68643-broken-mir.rs | 2 - .../issue-68643-broken-mir.stderr | 4 +- .../issue-68644-codegen-selection.rs | 2 - .../issue-68644-codegen-selection.stderr | 4 +- .../issue-68645-codegen-fulfillment.rs | 2 - .../issue-68645-codegen-fulfillment.stderr | 4 +- .../generic-associated-types/issue-68648-1.rs | 3 - .../generic-associated-types/issue-68648-2.rs | 2 - .../issue-68648-2.stderr | 4 +- .../issue-68649-pass.rs | 2 - .../generic-associated-types/issue-68653.rs | 2 - .../issue-68656-unsized-values.rs | 2 - .../issue-68656-unsized-values.stderr | 4 +- .../generic-associated-types/issue-70303.rs | 2 - .../generic-associated-types/issue-70304.rs | 2 - .../issue-70304.stderr | 6 +- .../generic-associated-types/issue-71176.rs | 2 - .../issue-71176.stderr | 4 +- .../generic-associated-types/issue-74684-1.rs | 2 - .../issue-74684-1.stderr | 2 +- .../generic-associated-types/issue-74684-2.rs | 2 - .../issue-74684-2.stderr | 6 +- .../generic-associated-types/issue-74816.rs | 1 - .../issue-74816.stderr | 8 +- .../generic-associated-types/issue-74824.rs | 1 - .../issue-74824.stderr | 8 +- .../generic-associated-types/issue-76407.rs | 2 - .../issue-76535.base.stderr | 12 +-- .../issue-76535.extended.stderr | 4 +- .../generic-associated-types/issue-76535.rs | 1 - .../generic-associated-types/issue-76826.rs | 2 - ...e-78113-lifetime-mismatch-dyn-trait-box.rs | 2 - ...113-lifetime-mismatch-dyn-trait-box.stderr | 26 +++---- .../issue-78671.base.stderr | 8 +- .../issue-78671.extended.stderr | 4 +- .../generic-associated-types/issue-78671.rs | 1 - .../issue-79422.base.stderr | 12 +-- .../issue-79422.extended.stderr | 8 +- .../generic-associated-types/issue-79422.rs | 1 - .../generic-associated-types/issue-79636-1.rs | 2 - .../issue-79636-1.stderr | 4 +- .../generic-associated-types/issue-79636-2.rs | 2 - .../issue-79636-2.stderr | 4 +- .../issue-80433-reduced.rs | 2 - .../generic-associated-types/issue-80433.rs | 2 - .../issue-80433.stderr | 4 +- .../generic-associated-types/issue-81487.rs | 2 - .../issue-81712-cyclic-traits.rs | 2 - .../issue-81712-cyclic-traits.stderr | 4 +- .../generic-associated-types/issue-81862.rs | 2 - .../issue-81862.stderr | 4 +- .../generic-associated-types/issue-84931.rs | 1 - .../issue-84931.stderr | 2 +- .../generic-associated-types/issue-85921.rs | 2 - .../generic-associated-types/issue-86483.rs | 2 - .../generic-associated-types/issue-86787.rs | 1 - .../issue-86787.stderr | 2 +- .../generic-associated-types/issue-87258_a.rs | 1 - .../issue-87258_a.stderr | 2 +- .../generic-associated-types/issue-87258_b.rs | 1 - .../issue-87258_b.stderr | 2 +- .../generic-associated-types/issue-87429-2.rs | 2 - .../issue-87429-associated-type-default.rs | 1 - ...issue-87429-associated-type-default.stderr | 4 +- .../issue-87429-specialization.rs | 1 - .../issue-87429-specialization.stderr | 4 +- .../generic-associated-types/issue-87429.rs | 2 - .../generic-associated-types/issue-87748.rs | 2 - .../generic-associated-types/issue-87750.rs | 2 - .../issue-87750.stderr | 2 +- .../generic-associated-types/issue-88287.rs | 1 - .../issue-88287.stderr | 4 +- .../generic-associated-types/issue-88360.rs | 2 - .../issue-88360.stderr | 2 +- .../generic-associated-types/issue-88405.rs | 2 - .../generic-associated-types/issue-88459.rs | 2 - .../generic-associated-types/issue-88595.rs | 1 - .../issue-88595.stderr | 4 +- .../generic-associated-types/issue-89352.rs | 2 - .../generic-associated-types/issue-90014.rs | 1 - .../issue-90014.stderr | 4 +- .../generic-associated-types/issue-90729.rs | 2 - .../issue-91139.migrate.stderr | 13 +--- .../generic-associated-types/issue-91139.rs | 2 - .../issue-91139.stderr | 18 ++--- .../generic-associated-types/issue-91883.rs | 2 - .../issue-91883.stderr | 6 +- .../generic-associated-types/issue-92033.rs | 2 - .../issue-92033.stderr | 4 +- .../issue-92096.migrate.stderr | 4 +- .../generic-associated-types/issue-92096.rs | 2 - .../issue-92096.stderr | 2 +- .../generic-associated-types/issue-92280.rs | 1 - .../generic-associated-types/issue-92954.rs | 2 - .../generic-associated-types/issue-93141.rs | 2 - .../generic-associated-types/issue-93262.rs | 2 - .../generic-associated-types/issue-93340.rs | 2 - .../generic-associated-types/issue-93341.rs | 1 - .../generic-associated-types/issue-93342.rs | 2 - .../generic-associated-types/issue-93874.rs | 2 - .../generic-associated-types/issue-95305.rs | 1 - .../issue-95305.stderr | 2 +- .../ui/generic-associated-types/iterable.rs | 2 - .../method-unsatified-assoc-type-predicate.rs | 2 - ...hod-unsatified-assoc-type-predicate.stderr | 4 +- .../missing-where-clause-on-trait.rs | 2 - .../missing-where-clause-on-trait.stderr | 2 +- .../missing_lifetime_args.rs | 2 - .../missing_lifetime_args.stderr | 12 +-- .../missing_lifetime_const.rs | 2 - .../missing_lifetime_const.stderr | 4 +- .../parameter_number_and_kind.rs | 1 - .../parameter_number_and_kind.stderr | 12 +-- .../parameter_number_and_kind_impl.rs | 1 - .../parameter_number_and_kind_impl.stderr | 12 +-- .../parse/in-trait-impl.rs | 2 - .../parse/in-trait.rs | 2 - .../parse/trait-path-expected-token.rs | 2 - .../parse/trait-path-expected-token.stderr | 2 +- .../parse/trait-path-expressions.rs | 2 - .../parse/trait-path-expressions.stderr | 4 +- .../parse/trait-path-missing-gen_arg.rs | 2 - .../parse/trait-path-missing-gen_arg.stderr | 10 +-- .../parse/trait-path-segments.rs | 2 - .../parse/trait-path-segments.stderr | 6 +- .../trait-path-type-error-once-implemented.rs | 2 - ...it-path-type-error-once-implemented.stderr | 8 +- .../parse/trait-path-types.rs | 2 - .../parse/trait-path-types.stderr | 6 +- .../pointer_family.rs | 2 - .../projection-bound-cycle-generic.rs | 2 - .../projection-bound-cycle-generic.stderr | 4 +- .../projection-bound-cycle.rs | 1 - .../projection-bound-cycle.stderr | 4 +- .../projection-type-lifetime-mismatch.rs | 2 - .../projection-type-lifetime-mismatch.stderr | 6 +- .../self-outlives-lint.rs | 2 - .../self-outlives-lint.stderr | 32 ++++---- .../ui/generic-associated-types/shadowing.rs | 2 - .../generic-associated-types/shadowing.stderr | 8 +- .../streaming_iterator.rs | 2 - .../trait-objects.base.stderr | 4 +- .../trait-objects.extended.stderr | 2 +- .../generic-associated-types/trait-objects.rs | 1 - .../unsatified-item-lifetime-bound.rs | 2 - .../unsatified-item-lifetime-bound.stderr | 14 ++-- .../unsatisfied-outlives-bound.rs | 2 - .../unsatisfied-outlives-bound.stderr | 8 +- .../variance_constraints.rs | 1 - .../normalize-under-binder/issue-90612.rs | 2 - .../normalize-under-binder/issue-90638.rs | 2 - .../expr-struct-type-relative-gat.rs | 2 - .../expr-struct-type-relative-gat.stderr | 2 +- .../ui/lifetimes/missing-lifetime-in-alias.rs | 2 - .../missing-lifetime-in-alias.stderr | 10 +-- .../impl-item-type-no-body-semantic-fail.rs | 2 - ...mpl-item-type-no-body-semantic-fail.stderr | 20 ++--- .../ui/parser/type-alias-where-fixable.fixed | 2 - .../ui/parser/type-alias-where-fixable.rs | 2 - .../ui/parser/type-alias-where-fixable.stderr | 6 +- src/test/ui/parser/type-alias-where.rs | 2 - src/test/ui/parser/type-alias-where.stderr | 4 +- .../default-generic-associated-type-bound.rs | 3 +- ...fault-generic-associated-type-bound.stderr | 4 +- src/test/ui/suggestions/issue-85347.rs | 2 - src/test/ui/suggestions/issue-85347.stderr | 4 +- .../ui/type-alias-impl-trait/issue-90400-1.rs | 1 - .../issue-90400-1.stderr | 4 +- .../ui/type-alias-impl-trait/issue-90400-2.rs | 1 - .../issue-90400-2.stderr | 4 +- src/tools/rustfmt/tests/source/issue_4257.rs | 3 - src/tools/rustfmt/tests/source/issue_4911.rs | 1 - src/tools/rustfmt/tests/source/issue_4943.rs | 2 - src/tools/rustfmt/tests/target/issue_4257.rs | 3 - src/tools/rustfmt/tests/target/issue_4911.rs | 1 - src/tools/rustfmt/tests/target/issue_4943.rs | 2 - 280 files changed, 313 insertions(+), 808 deletions(-) delete mode 100644 src/test/ui/feature-gates/feature-gate-generic_associated_types.rs delete mode 100644 src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr rename src/test/ui/generic-associated-types/{ => bugs}/issue-91762.rs (86%) rename src/test/ui/generic-associated-types/{ => bugs}/issue-91762.stderr (94%) delete mode 100644 src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.rs delete mode 100644 src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.stderr delete mode 100644 src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature.rs delete mode 100644 src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature.stderr delete mode 100644 src/test/ui/generic-associated-types/gat-incomplete-warning.rs delete mode 100644 src/test/ui/generic-associated-types/issue-67424.stderr diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 6f7e88eb86f1..ec3d03861a00 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -342,25 +342,6 @@ impl<'a> PostExpansionVisitor<'a> { } } - fn check_gat(&self, generics: &ast::Generics, span: Span) { - if !generics.params.is_empty() { - gate_feature_post!( - &self, - generic_associated_types, - span, - "generic associated types are unstable" - ); - } - if !generics.where_clause.predicates.is_empty() { - gate_feature_post!( - &self, - generic_associated_types, - span, - "where clauses on associated types are unstable" - ); - } - } - /// Feature gate `impl Trait` inside `type Alias = $type_expr;`. fn check_impl_trait(&self, ty: &ast::Ty) { struct ImplTraitVisitor<'a> { @@ -719,7 +700,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) { let is_fn = match i.kind { ast::AssocItemKind::Fn(_) => true, - ast::AssocItemKind::TyAlias(box ast::TyAlias { ref generics, ref ty, .. }) => { + ast::AssocItemKind::TyAlias(box ast::TyAlias { ref ty, .. }) => { if let (Some(_), AssocCtxt::Trait) = (ty, ctxt) { gate_feature_post!( &self, @@ -731,7 +712,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { if let Some(ty) = ty { self.check_impl_trait(ty); } - self.check_gat(generics, i.span); false } _ => false, diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index c22adf77a27f..100000f4cd62 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -161,6 +161,8 @@ declare_features! ( (accepted, fn_must_use, "1.27.0", Some(43302), None), /// Allows capturing variables in scope using format_args! (accepted, format_args_capture, "1.58.0", Some(67984), None), + /// Allows associated types to be generic, e.g., `type Foo;` (RFC 1598). + (accepted, generic_associated_types, "CURRENT_RUSTC_VERSION", Some(44265), None), /// Allows attributes on lifetime/type formal parameters in generics (RFC 1327). (accepted, generic_param_attrs, "1.27.0", Some(48848), None), /// Allows the `#[global_allocator]` attribute. diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index e09c3ccbc75a..4f628cee6303 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -398,8 +398,6 @@ declare_features! ( (active, generators, "1.21.0", Some(43122), None), /// Infer generic args for both consts and types. (active, generic_arg_infer, "1.55.0", Some(85077), None), - /// Allows associated types to be generic, e.g., `type Foo;` (RFC 1598). - (active, generic_associated_types, "1.23.0", Some(44265), None), /// An extension to the `generic_associated_types` feature, allowing incomplete features. (incomplete, generic_associated_types_extended, "1.61.0", Some(95451), None), /// Allows non-trivial generic constants which have to have wfness manually propagated to callers diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 2dca6acdd6d6..dec81c0d912e 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3989,8 +3989,6 @@ declare_lint! { /// ### Example /// /// ```rust - /// #![feature(generic_associated_types)] - /// /// trait Trait { /// type Assoc<'a> where Self: 'a; /// } diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 6440f3e390cf..062d25da2e5b 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -2,7 +2,7 @@ #![feature(decl_macro)] #![feature(drain_filter)] #![feature(generators)] -#![feature(generic_associated_types)] +#![cfg_attr(bootstrap, feature(generic_associated_types))] #![feature(iter_from_generator)] #![feature(let_chains)] #![feature(let_else)] diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index be9e5865e541..b8b3ff06fb28 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -31,7 +31,7 @@ #![feature(discriminant_kind)] #![feature(exhaustive_patterns)] #![feature(get_mut_unchecked)] -#![feature(generic_associated_types)] +#![cfg_attr(bootstrap, feature(generic_associated_types))] #![feature(if_let_guard)] #![feature(map_first_last)] #![feature(negative_impls)] diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 444ca6471e2e..99efe51b107b 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -2064,8 +2064,6 @@ fn confirm_impl_candidate<'cx, 'tcx>( // Get obligations corresponding to the predicates from the where-clause of the // associated type itself. -// Note: `feature(generic_associated_types)` is required to write such -// predicates, even for non-generic associated types. fn assoc_ty_own_obligations<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 92380d124292..f6c648140b85 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -16,7 +16,7 @@ #![feature(type_ascription)] #![feature(iter_intersperse)] #![feature(type_alias_impl_trait)] -#![feature(generic_associated_types)] +#![cfg_attr(bootstrap, feature(generic_associated_types))] #![recursion_limit = "256"] #![warn(rustc::internal)] #![allow(clippy::collapsible_if, clippy::collapsible_else_if)] diff --git a/src/test/pretty/gat-bounds.rs b/src/test/pretty/gat-bounds.rs index 8877c6cc9927..0a361a3835f7 100644 --- a/src/test/pretty/gat-bounds.rs +++ b/src/test/pretty/gat-bounds.rs @@ -3,8 +3,6 @@ // pretty-compare-only -#![feature(generic_associated_types)] - trait X { type Y: Trait where Self: Sized; } diff --git a/src/test/rustdoc-json/generic-associated-types/gats.rs b/src/test/rustdoc-json/generic-associated-types/gats.rs index cbaa0621dc2b..e5809783aeca 100644 --- a/src/test/rustdoc-json/generic-associated-types/gats.rs +++ b/src/test/rustdoc-json/generic-associated-types/gats.rs @@ -1,7 +1,7 @@ // ignore-tidy-linelength #![no_core] -#![feature(generic_associated_types, lang_items, no_core)] +#![feature(lang_items, no_core)] #[lang = "sized"] pub trait Sized {} diff --git a/src/test/rustdoc/generic-associated-types/gats.rs b/src/test/rustdoc/generic-associated-types/gats.rs index ae981b9499a6..7ab82bb58296 100644 --- a/src/test/rustdoc/generic-associated-types/gats.rs +++ b/src/test/rustdoc/generic-associated-types/gats.rs @@ -1,5 +1,4 @@ #![crate_name = "foo"] -#![feature(generic_associated_types)] // @has foo/trait.LendingIterator.html pub trait LendingIterator { diff --git a/src/test/rustdoc/generic-associated-types/issue-94683.rs b/src/test/rustdoc/generic-associated-types/issue-94683.rs index 91499100ec68..985c7e983aa0 100644 --- a/src/test/rustdoc/generic-associated-types/issue-94683.rs +++ b/src/test/rustdoc/generic-associated-types/issue-94683.rs @@ -1,5 +1,4 @@ #![crate_name = "foo"] -#![feature(generic_associated_types)] pub trait Trait { type Gat<'a>; diff --git a/src/test/rustdoc/where.rs b/src/test/rustdoc/where.rs index 50a5722fbaff..33440b17cf9d 100644 --- a/src/test/rustdoc/where.rs +++ b/src/test/rustdoc/where.rs @@ -1,4 +1,3 @@ -#![feature(generic_associated_types)] #![crate_name = "foo"] pub trait MyTrait { fn dummy(&self) { } } diff --git a/src/test/ui/associated-type-bounds/binder-on-bound.rs b/src/test/ui/associated-type-bounds/binder-on-bound.rs index 0b4b24b9820b..6cba45129e49 100644 --- a/src/test/ui/associated-type-bounds/binder-on-bound.rs +++ b/src/test/ui/associated-type-bounds/binder-on-bound.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - trait Trait { type Bound<'a>; } diff --git a/src/test/ui/associated-type-bounds/binder-on-bound.stderr b/src/test/ui/associated-type-bounds/binder-on-bound.stderr index 3432672e03c4..f71f72bfb94f 100644 --- a/src/test/ui/associated-type-bounds/binder-on-bound.stderr +++ b/src/test/ui/associated-type-bounds/binder-on-bound.stderr @@ -1,5 +1,5 @@ error: `for<...>` is not allowed on associated type bounds - --> $DIR/binder-on-bound.rs:7:22 + --> $DIR/binder-on-bound.rs:5:22 | LL | fn foo() where Trait Bound<'a> = &'a ()> { | ^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/associated-type-bounds/issue-79949.rs b/src/test/ui/associated-type-bounds/issue-79949.rs index 9f924f1fd81d..9dd37f98150b 100644 --- a/src/test/ui/associated-type-bounds/issue-79949.rs +++ b/src/test/ui/associated-type-bounds/issue-79949.rs @@ -2,7 +2,6 @@ #![allow(incomplete_features)] #![feature(associated_type_bounds)] -#![feature(generic_associated_types)] trait MP { type T<'a>; diff --git a/src/test/ui/deriving/issue-89188-gat-hrtb.rs b/src/test/ui/deriving/issue-89188-gat-hrtb.rs index abd85a616a4a..e8118f0c6e40 100644 --- a/src/test/ui/deriving/issue-89188-gat-hrtb.rs +++ b/src/test/ui/deriving/issue-89188-gat-hrtb.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(generic_associated_types)] - trait CallWithShim: Sized { type Shim<'s> where diff --git a/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs b/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs deleted file mode 100644 index c5c134514889..000000000000 --- a/src/test/ui/feature-gates/feature-gate-generic_associated_types.rs +++ /dev/null @@ -1,31 +0,0 @@ -use std::ops::Deref; - -trait PointerFamily { - type Pointer: Deref; - //~^ ERROR generic associated types are unstable - type Pointer2: Deref where T: Clone, U: Clone; - //~^ ERROR generic associated types are unstable - //~| ERROR where clauses on associated types are unstable -} - -struct Foo; - -impl PointerFamily for Foo { - type Pointer = Box; - //~^ ERROR generic associated types are unstable - type Pointer2 = Box; - //~^ ERROR generic associated types are unstable - //~| ERROR the trait bound `U32: Clone` is not satisfied -} - -trait Bar { - type Assoc where Self: Sized; - //~^ ERROR where clauses on associated types are unstable -} - -impl Bar for Foo { - type Assoc = Foo where Self: Sized; - //~^ ERROR where clauses on associated types are unstable -} - -fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr b/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr deleted file mode 100644 index 12a40ff0a12f..000000000000 --- a/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr +++ /dev/null @@ -1,78 +0,0 @@ -error[E0658]: generic associated types are unstable - --> $DIR/feature-gate-generic_associated_types.rs:4:5 - | -LL | type Pointer: Deref; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #44265 for more information - = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable - -error[E0658]: generic associated types are unstable - --> $DIR/feature-gate-generic_associated_types.rs:6:5 - | -LL | type Pointer2: Deref where T: Clone, U: Clone; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #44265 for more information - = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable - -error[E0658]: where clauses on associated types are unstable - --> $DIR/feature-gate-generic_associated_types.rs:6:5 - | -LL | type Pointer2: Deref where T: Clone, U: Clone; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #44265 for more information - = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable - -error[E0658]: generic associated types are unstable - --> $DIR/feature-gate-generic_associated_types.rs:14:5 - | -LL | type Pointer = Box; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #44265 for more information - = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable - -error[E0658]: generic associated types are unstable - --> $DIR/feature-gate-generic_associated_types.rs:16:5 - | -LL | type Pointer2 = Box; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #44265 for more information - = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable - -error[E0658]: where clauses on associated types are unstable - --> $DIR/feature-gate-generic_associated_types.rs:22:5 - | -LL | type Assoc where Self: Sized; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #44265 for more information - = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable - -error[E0658]: where clauses on associated types are unstable - --> $DIR/feature-gate-generic_associated_types.rs:27:5 - | -LL | type Assoc = Foo where Self: Sized; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #44265 for more information - = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable - -error[E0277]: the trait bound `U32: Clone` is not satisfied - --> $DIR/feature-gate-generic_associated_types.rs:16:26 - | -LL | type Pointer2 = Box; - | ^^^^^^^^ the trait `Clone` is not implemented for `U32` - | -help: consider restricting type parameter `U32` - | -LL | type Pointer2 = Box; - | +++++++++++++++++++ - -error: aborting due to 8 previous errors - -Some errors have detailed explanations: E0277, E0658. -For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/feature-gates/feature-gate-generic_associated_types_extended.rs b/src/test/ui/feature-gates/feature-gate-generic_associated_types_extended.rs index 258b8cd35c77..7842d44ac4f0 100644 --- a/src/test/ui/feature-gates/feature-gate-generic_associated_types_extended.rs +++ b/src/test/ui/feature-gates/feature-gate-generic_associated_types_extended.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - // This feature doesn't *currently* fire on any specific code; it's just a // behavior change. Future changes might. #[rustc_error] //~ the diff --git a/src/test/ui/feature-gates/feature-gate-generic_associated_types_extended.stderr b/src/test/ui/feature-gates/feature-gate-generic_associated_types_extended.stderr index 6a5eba38cacc..bb1622628dc1 100644 --- a/src/test/ui/feature-gates/feature-gate-generic_associated_types_extended.stderr +++ b/src/test/ui/feature-gates/feature-gate-generic_associated_types_extended.stderr @@ -1,5 +1,5 @@ error[E0658]: the `#[rustc_error]` attribute is just used for rustc unit tests and will never be stable - --> $DIR/feature-gate-generic_associated_types_extended.rs:5:1 + --> $DIR/feature-gate-generic_associated_types_extended.rs:3:1 | LL | #[rustc_error] | ^^^^^^^^^^^^^^ diff --git a/src/test/ui/generic-associated-types/anonymize-bound-vars.rs b/src/test/ui/generic-associated-types/anonymize-bound-vars.rs index 1ec9c69989a7..eb7a12412c6b 100644 --- a/src/test/ui/generic-associated-types/anonymize-bound-vars.rs +++ b/src/test/ui/generic-associated-types/anonymize-bound-vars.rs @@ -1,7 +1,6 @@ // check-pass // // regression test for #98702 -#![feature(generic_associated_types)] trait Foo { type Assoc; diff --git a/src/test/ui/generic-associated-types/auxiliary/foo_defn.rs b/src/test/ui/generic-associated-types/auxiliary/foo_defn.rs index 0e8e14852d9d..21a9b3b89a8d 100644 --- a/src/test/ui/generic-associated-types/auxiliary/foo_defn.rs +++ b/src/test/ui/generic-associated-types/auxiliary/foo_defn.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - use std::{future::Future, pin::Pin}; pub trait Foo { diff --git a/src/test/ui/generic-associated-types/bugs/issue-80626.rs b/src/test/ui/generic-associated-types/bugs/issue-80626.rs index 14f27aff1ccd..f6aa6b36e13d 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-80626.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-80626.rs @@ -3,8 +3,6 @@ // This should pass, but it requires `Sized` to be coinductive. -#![feature(generic_associated_types)] - trait Allocator { type Allocated; } diff --git a/src/test/ui/generic-associated-types/bugs/issue-80626.stderr b/src/test/ui/generic-associated-types/bugs/issue-80626.stderr index 487b83dfa3fc..9a0f332ed473 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-80626.stderr +++ b/src/test/ui/generic-associated-types/bugs/issue-80626.stderr @@ -1,11 +1,11 @@ error[E0275]: overflow evaluating the requirement `LinkedList: Sized` - --> $DIR/issue-80626.rs:14:10 + --> $DIR/issue-80626.rs:12:10 | LL | Next(A::Allocated) | ^^^^^^^^^^^^^^^^^^ | note: required by a bound in `Allocator::Allocated` - --> $DIR/issue-80626.rs:9:20 + --> $DIR/issue-80626.rs:7:20 | LL | type Allocated; | ^ required by this bound in `Allocator::Allocated` diff --git a/src/test/ui/generic-associated-types/bugs/issue-86218.rs b/src/test/ui/generic-associated-types/bugs/issue-86218.rs index fb62c10a9e38..3a2d758e7d6f 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-86218.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-86218.rs @@ -3,7 +3,6 @@ // This should pass, but seems to run into a TAIT issue. -#![feature(generic_associated_types)] #![feature(type_alias_impl_trait)] pub trait Stream { diff --git a/src/test/ui/generic-associated-types/bugs/issue-86218.stderr b/src/test/ui/generic-associated-types/bugs/issue-86218.stderr index fbf1c8f95fec..de1b464a41db 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-86218.stderr +++ b/src/test/ui/generic-associated-types/bugs/issue-86218.stderr @@ -1,17 +1,17 @@ error[E0477]: the type `<() as Yay<&'a ()>>::InnerStream<'s>` does not fulfill the required lifetime - --> $DIR/issue-86218.rs:23:28 + --> $DIR/issue-86218.rs:22:28 | LL | type InnerStream<'s> = impl Stream + 's; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: type must outlive the lifetime `'s` as defined here as required by this binding - --> $DIR/issue-86218.rs:23:22 + --> $DIR/issue-86218.rs:22:22 | LL | type InnerStream<'s> = impl Stream + 's; | ^^ error: unconstrained opaque type - --> $DIR/issue-86218.rs:23:28 + --> $DIR/issue-86218.rs:22:28 | LL | type InnerStream<'s> = impl Stream + 's; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/generic-associated-types/bugs/issue-87735.rs b/src/test/ui/generic-associated-types/bugs/issue-87735.rs index 0844d84c34fd..80737a79899b 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-87735.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-87735.rs @@ -3,8 +3,6 @@ // This should pass, but we need an extension of implied bounds (probably). -#![feature(generic_associated_types)] - pub trait AsRef2 { type Output<'a> where Self: 'a; diff --git a/src/test/ui/generic-associated-types/bugs/issue-87735.stderr b/src/test/ui/generic-associated-types/bugs/issue-87735.stderr index 0a18b5f0cbda..ebe2054ce5ef 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-87735.stderr +++ b/src/test/ui/generic-associated-types/bugs/issue-87735.stderr @@ -1,5 +1,5 @@ error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates - --> $DIR/issue-87735.rs:27:13 + --> $DIR/issue-87735.rs:25:13 | LL | impl<'b, T, U> AsRef2 for Foo | ^ unconstrained type parameter diff --git a/src/test/ui/generic-associated-types/bugs/issue-87755.rs b/src/test/ui/generic-associated-types/bugs/issue-87755.rs index efa487d624fd..cda722d2f0c7 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-87755.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-87755.rs @@ -3,8 +3,6 @@ // This should pass. -#![feature(generic_associated_types)] - use std::fmt::Debug; trait Foo { diff --git a/src/test/ui/generic-associated-types/bugs/issue-87755.stderr b/src/test/ui/generic-associated-types/bugs/issue-87755.stderr index 5d1aff0117c1..5e94db9b0c00 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-87755.stderr +++ b/src/test/ui/generic-associated-types/bugs/issue-87755.stderr @@ -1,5 +1,5 @@ error[E0275]: overflow evaluating the requirement `::Ass == _` - --> $DIR/issue-87755.rs:18:16 + --> $DIR/issue-87755.rs:16:16 | LL | type Ass = Bar; | ^^^ diff --git a/src/test/ui/generic-associated-types/bugs/issue-87803.rs b/src/test/ui/generic-associated-types/bugs/issue-87803.rs index a8a111c99ef7..56237e387ef3 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-87803.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-87803.rs @@ -4,8 +4,6 @@ // This should pass, but using a type alias vs a reference directly // changes late-bound -> early-bound. -#![feature(generic_associated_types)] - trait Scanner { type Input<'a>; type Token<'a>; diff --git a/src/test/ui/generic-associated-types/bugs/issue-87803.stderr b/src/test/ui/generic-associated-types/bugs/issue-87803.stderr index c81c051d32a8..fe2abdedbf37 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-87803.stderr +++ b/src/test/ui/generic-associated-types/bugs/issue-87803.stderr @@ -1,5 +1,5 @@ error[E0195]: lifetime parameters or bounds on method `scan` do not match the trait declaration - --> $DIR/issue-87803.rs:22:12 + --> $DIR/issue-87803.rs:20:12 | LL | fn scan<'a>(&mut self, i : Self::Input<'a>) -> Self::Token<'a>; | ---- lifetimes in impl do not match this method in trait diff --git a/src/test/ui/generic-associated-types/bugs/issue-88382.rs b/src/test/ui/generic-associated-types/bugs/issue-88382.rs index 5493b9b93913..8f8cc4523a20 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-88382.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-88382.rs @@ -3,8 +3,6 @@ // This should pass, but has a missed normalization due to HRTB. -#![feature(generic_associated_types)] - trait Iterable { type Iterator<'a> where Self: 'a; fn iter(&self) -> Self::Iterator<'_>; diff --git a/src/test/ui/generic-associated-types/bugs/issue-88382.stderr b/src/test/ui/generic-associated-types/bugs/issue-88382.stderr index 7210895b79bc..c5fd58096b7f 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-88382.stderr +++ b/src/test/ui/generic-associated-types/bugs/issue-88382.stderr @@ -1,5 +1,5 @@ error[E0631]: type mismatch in function arguments - --> $DIR/issue-88382.rs:28:40 + --> $DIR/issue-88382.rs:26:40 | LL | do_something(SomeImplementation(), test); | ------------ ^^^^ expected due to this @@ -12,7 +12,7 @@ LL | fn test<'a, I: Iterable>(_: &mut I::Iterator<'a>) {} = note: expected function signature `for<'r> fn(&'r mut std::iter::Empty) -> _` found function signature `for<'a, 'r> fn(&'r mut <_ as Iterable>::Iterator<'a>) -> _` note: required by a bound in `do_something` - --> $DIR/issue-88382.rs:22:48 + --> $DIR/issue-88382.rs:20:48 | LL | fn do_something(i: I, mut f: impl for<'a> Fn(&mut I::Iterator<'a>)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `do_something` diff --git a/src/test/ui/generic-associated-types/bugs/issue-88460.rs b/src/test/ui/generic-associated-types/bugs/issue-88460.rs index f1c3b2269158..224e696ad2c9 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-88460.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-88460.rs @@ -3,8 +3,6 @@ // This should pass, but has a missed normalization due to HRTB. -#![feature(generic_associated_types)] - pub trait Marker {} pub trait Trait { diff --git a/src/test/ui/generic-associated-types/bugs/issue-88460.stderr b/src/test/ui/generic-associated-types/bugs/issue-88460.stderr index 8193f491e69e..6612c4b49446 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-88460.stderr +++ b/src/test/ui/generic-associated-types/bugs/issue-88460.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `for<'a> <_ as Trait>::Assoc<'a>: Marker` is not satisfied - --> $DIR/issue-88460.rs:30:10 + --> $DIR/issue-88460.rs:28:10 | LL | test(Foo); | ---- ^^^ the trait `for<'a> Marker` is not implemented for `<_ as Trait>::Assoc<'a>` @@ -8,7 +8,7 @@ LL | test(Foo); | = help: the trait `Marker` is implemented for `()` note: required by a bound in `test` - --> $DIR/issue-88460.rs:17:27 + --> $DIR/issue-88460.rs:15:27 | LL | fn test(value: T) | ---- required by a bound in this diff --git a/src/test/ui/generic-associated-types/bugs/issue-88526.rs b/src/test/ui/generic-associated-types/bugs/issue-88526.rs index 15363ad04bfe..99397744fa65 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-88526.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-88526.rs @@ -3,8 +3,6 @@ // This should pass, but requires more logic. -#![feature(generic_associated_types)] - trait A { type I<'a>; } diff --git a/src/test/ui/generic-associated-types/bugs/issue-88526.stderr b/src/test/ui/generic-associated-types/bugs/issue-88526.stderr index 127c889bf715..56857c6550bd 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-88526.stderr +++ b/src/test/ui/generic-associated-types/bugs/issue-88526.stderr @@ -1,5 +1,5 @@ error[E0207]: the type parameter `I` is not constrained by the impl trait, self type, or predicates - --> $DIR/issue-88526.rs:27:13 + --> $DIR/issue-88526.rs:25:13 | LL | impl<'q, Q, I, F> A for TestB | ^ unconstrained type parameter diff --git a/src/test/ui/generic-associated-types/bugs/issue-89008.rs b/src/test/ui/generic-associated-types/bugs/issue-89008.rs index 79c28b0d2217..012aa8df2fc3 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-89008.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-89008.rs @@ -5,7 +5,6 @@ // This should pass, but seems to run into a TAIT bug. #![feature(type_alias_impl_trait)] -#![feature(generic_associated_types)] use std::future::Future; diff --git a/src/test/ui/generic-associated-types/bugs/issue-89008.stderr b/src/test/ui/generic-associated-types/bugs/issue-89008.stderr index 50844fdc14d9..3f72734efa1d 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-89008.stderr +++ b/src/test/ui/generic-associated-types/bugs/issue-89008.stderr @@ -1,5 +1,5 @@ error[E0271]: type mismatch resolving ` as Stream>::Item == Repr` - --> $DIR/issue-89008.rs:39:43 + --> $DIR/issue-89008.rs:38:43 | LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> { | ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving ` as Stream>::Item == Repr` @@ -7,7 +7,7 @@ LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> { | this type parameter | note: expected this to be `()` - --> $DIR/issue-89008.rs:18:17 + --> $DIR/issue-89008.rs:17:17 | LL | type Item = (); | ^^ diff --git a/src/test/ui/generic-associated-types/issue-91762.rs b/src/test/ui/generic-associated-types/bugs/issue-91762.rs similarity index 86% rename from src/test/ui/generic-associated-types/issue-91762.rs rename to src/test/ui/generic-associated-types/bugs/issue-91762.rs index b259a3c6e06b..796935cc06f5 100644 --- a/src/test/ui/generic-associated-types/issue-91762.rs +++ b/src/test/ui/generic-associated-types/bugs/issue-91762.rs @@ -1,13 +1,12 @@ // check-fail +// known-bug -// FIXME(generic_associated_types): We almost certaintly want this to pass, but +// We almost certaintly want this to pass, but // it's particularly difficult currently, because we need a way of specifying // that `::With = Self` without using that when we have // a `U`. See `https://github.com/rust-lang/rust/pull/92728` for a (hacky) // solution. This might be better to just wait for Chalk. -#![feature(generic_associated_types)] - pub trait Functor { type With; diff --git a/src/test/ui/generic-associated-types/issue-91762.stderr b/src/test/ui/generic-associated-types/bugs/issue-91762.stderr similarity index 94% rename from src/test/ui/generic-associated-types/issue-91762.stderr rename to src/test/ui/generic-associated-types/bugs/issue-91762.stderr index c2785fee387f..1272c8b8ae27 100644 --- a/src/test/ui/generic-associated-types/issue-91762.stderr +++ b/src/test/ui/generic-associated-types/bugs/issue-91762.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/issue-91762.rs:25:15 + --> $DIR/issue-91762.rs:24:15 | LL | ret = ::fmap(arg); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the associated function `fmap` diff --git a/src/test/ui/generic-associated-types/collections-project-default.rs b/src/test/ui/generic-associated-types/collections-project-default.rs index 157e1b1d2957..e08aa18cf0f1 100644 --- a/src/test/ui/generic-associated-types/collections-project-default.rs +++ b/src/test/ui/generic-associated-types/collections-project-default.rs @@ -1,4 +1,3 @@ -#![feature(generic_associated_types)] #![feature(associated_type_defaults)] // A Collection trait and collection families. Based on diff --git a/src/test/ui/generic-associated-types/collections-project-default.stderr b/src/test/ui/generic-associated-types/collections-project-default.stderr index 22fbc0271b48..5701017dc347 100644 --- a/src/test/ui/generic-associated-types/collections-project-default.stderr +++ b/src/test/ui/generic-associated-types/collections-project-default.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/collections-project-default.rs:59:5 + --> $DIR/collections-project-default.rs:58:5 | LL | fn floatify_sibling(ints: &C) -> >::Sibling | ------------------------------------ expected `>::Sibling` because of return type diff --git a/src/test/ui/generic-associated-types/collections.rs b/src/test/ui/generic-associated-types/collections.rs index 1c00aa73feb9..15f429afb027 100644 --- a/src/test/ui/generic-associated-types/collections.rs +++ b/src/test/ui/generic-associated-types/collections.rs @@ -1,4 +1,3 @@ -#![feature(generic_associated_types)] #![feature(associated_type_defaults)] // A Collection trait and collection families. Based on diff --git a/src/test/ui/generic-associated-types/collectivity-regression.rs b/src/test/ui/generic-associated-types/collectivity-regression.rs index fb7368439073..54154f9d1fc8 100644 --- a/src/test/ui/generic-associated-types/collectivity-regression.rs +++ b/src/test/ui/generic-associated-types/collectivity-regression.rs @@ -1,7 +1,5 @@ // Regression test from https://github.com/rust-lang/rust/pull/98109 -#![feature(generic_associated_types)] - pub trait Get { type Value<'a> where diff --git a/src/test/ui/generic-associated-types/collectivity-regression.stderr b/src/test/ui/generic-associated-types/collectivity-regression.stderr index a858dd7fddcd..1dbe1e2cb224 100644 --- a/src/test/ui/generic-associated-types/collectivity-regression.stderr +++ b/src/test/ui/generic-associated-types/collectivity-regression.stderr @@ -1,5 +1,5 @@ error: `T` does not live long enough - --> $DIR/collectivity-regression.rs:15:5 + --> $DIR/collectivity-regression.rs:13:5 | LL | / || { LL | | diff --git a/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-1.rs b/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-1.rs index afde5f37634b..c5f9a25a6ea9 100644 --- a/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-1.rs +++ b/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-1.rs @@ -1,5 +1,4 @@ // run-pass -#![feature(generic_associated_types)] // This test unsures that with_opt_const_param returns the // def_id of the N param in the Foo::Assoc GAT. diff --git a/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-2.rs b/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-2.rs index 51046be79b7e..cd7941ed9af7 100644 --- a/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-2.rs +++ b/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-2.rs @@ -1,5 +1,4 @@ // run-pass -#![feature(generic_associated_types)] // This test unsures that with_opt_const_param returns the // def_id of the N param in the Foo::Assoc GAT. diff --git a/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-3.rs b/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-3.rs index 457fe27b3ff3..db61fc08005b 100644 --- a/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-3.rs +++ b/src/test/ui/generic-associated-types/const-generics-gat-in-trait-return-type-3.rs @@ -1,5 +1,4 @@ // run-pass -#![feature(generic_associated_types)] // This test unsures that with_opt_const_param returns the // def_id of the N param in the Bar::Assoc GAT. diff --git a/src/test/ui/generic-associated-types/const_params_have_right_type.rs b/src/test/ui/generic-associated-types/const_params_have_right_type.rs index 6bed8e3aff97..d2cb12697e42 100644 --- a/src/test/ui/generic-associated-types/const_params_have_right_type.rs +++ b/src/test/ui/generic-associated-types/const_params_have_right_type.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - trait Trait { type Foo; } diff --git a/src/test/ui/generic-associated-types/const_params_have_right_type.stderr b/src/test/ui/generic-associated-types/const_params_have_right_type.stderr index 89c993dee5e6..fdedd3bf5fbf 100644 --- a/src/test/ui/generic-associated-types/const_params_have_right_type.stderr +++ b/src/test/ui/generic-associated-types/const_params_have_right_type.stderr @@ -1,5 +1,5 @@ error[E0053]: type `Foo` has an incompatible generic parameter for trait `Trait` - --> $DIR/const_params_have_right_type.rs:8:14 + --> $DIR/const_params_have_right_type.rs:6:14 | LL | trait Trait { | ----- diff --git a/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.rs b/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.rs index e315ee842180..c78a549970d8 100644 --- a/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.rs +++ b/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.rs @@ -1,7 +1,5 @@ // Test that correct syntax is used in suggestion to constrain associated type -#![feature(generic_associated_types)] - trait X { type Y; } diff --git a/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.stderr b/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.stderr index 957ae5d29324..96c4330fec02 100644 --- a/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.stderr +++ b/src/test/ui/generic-associated-types/constraint-assoc-type-suggestion.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/constraint-assoc-type-suggestion.rs:12:23 + --> $DIR/constraint-assoc-type-suggestion.rs:10:23 | LL | let b: Vec = a; | -------- ^ expected struct `Vec`, found associated type diff --git a/src/test/ui/generic-associated-types/construct_with_other_type.rs b/src/test/ui/generic-associated-types/construct_with_other_type.rs index 060804269aa7..5cb07f558834 100644 --- a/src/test/ui/generic-associated-types/construct_with_other_type.rs +++ b/src/test/ui/generic-associated-types/construct_with_other_type.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - // check-pass use std::ops::Deref; diff --git a/src/test/ui/generic-associated-types/cross-crate-bounds.stderr b/src/test/ui/generic-associated-types/cross-crate-bounds.stderr index c4009dd96251..c81cd7e7718c 100644 --- a/src/test/ui/generic-associated-types/cross-crate-bounds.stderr +++ b/src/test/ui/generic-associated-types/cross-crate-bounds.stderr @@ -5,7 +5,7 @@ LL | type Bar = (); | ^^ the trait `AsRef<()>` is not implemented for `()` | note: required by a bound in `foo_defn::Foo::Bar` - --> $DIR/auxiliary/foo_defn.rs:6:15 + --> $DIR/auxiliary/foo_defn.rs:4:15 | LL | type Bar: AsRef<()>; | ^^^^^^^^^ required by this bound in `foo_defn::Foo::Bar` diff --git a/src/test/ui/generic-associated-types/elided-in-expr-position.rs b/src/test/ui/generic-associated-types/elided-in-expr-position.rs index 482d0d5c00a6..e40093305c40 100644 --- a/src/test/ui/generic-associated-types/elided-in-expr-position.rs +++ b/src/test/ui/generic-associated-types/elided-in-expr-position.rs @@ -1,4 +1,3 @@ -#![feature(generic_associated_types)] #![allow(unused)] pub trait Trait { diff --git a/src/test/ui/generic-associated-types/elided-in-expr-position.stderr b/src/test/ui/generic-associated-types/elided-in-expr-position.stderr index b395a1cfd8a6..20f35c3c1370 100644 --- a/src/test/ui/generic-associated-types/elided-in-expr-position.stderr +++ b/src/test/ui/generic-associated-types/elided-in-expr-position.stderr @@ -1,11 +1,11 @@ error[E0107]: missing generics for associated type `Trait::Assoc` - --> $DIR/elided-in-expr-position.rs:10:26 + --> $DIR/elided-in-expr-position.rs:9:26 | LL | fn g(&self) -> Self::Assoc; | ^^^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/elided-in-expr-position.rs:5:10 + --> $DIR/elided-in-expr-position.rs:4:10 | LL | type Assoc<'a> where Self: 'a; | ^^^^^ -- @@ -15,13 +15,13 @@ LL | fn g(&self) -> Self::Assoc<'a>; | ~~~~~~~~~ error[E0107]: missing generics for associated type `Trait::Assoc` - --> $DIR/elided-in-expr-position.rs:32:26 + --> $DIR/elided-in-expr-position.rs:31:26 | LL | fn g(&self) -> Self::Assoc { | ^^^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/elided-in-expr-position.rs:5:10 + --> $DIR/elided-in-expr-position.rs:4:10 | LL | type Assoc<'a> where Self: 'a; | ^^^^^ -- diff --git a/src/test/ui/generic-associated-types/empty_generics.rs b/src/test/ui/generic-associated-types/empty_generics.rs index 772b7f2b4e30..964c2972d473 100644 --- a/src/test/ui/generic-associated-types/empty_generics.rs +++ b/src/test/ui/generic-associated-types/empty_generics.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - trait Foo { type Bar<,>; //~^ ERROR expected one of `#`, `>`, `const`, identifier, or lifetime, found `,` diff --git a/src/test/ui/generic-associated-types/empty_generics.stderr b/src/test/ui/generic-associated-types/empty_generics.stderr index ac22bfc0835b..b753181cf480 100644 --- a/src/test/ui/generic-associated-types/empty_generics.stderr +++ b/src/test/ui/generic-associated-types/empty_generics.stderr @@ -1,5 +1,5 @@ error: expected one of `#`, `>`, `const`, identifier, or lifetime, found `,` - --> $DIR/empty_generics.rs:4:14 + --> $DIR/empty_generics.rs:2:14 | LL | trait Foo { | - while parsing this item list starting here diff --git a/src/test/ui/generic-associated-types/extended/lending_iterator.base.stderr b/src/test/ui/generic-associated-types/extended/lending_iterator.base.stderr index 3da7794b3d2c..614c4a34c187 100644 --- a/src/test/ui/generic-associated-types/extended/lending_iterator.base.stderr +++ b/src/test/ui/generic-associated-types/extended/lending_iterator.base.stderr @@ -1,5 +1,5 @@ error[E0276]: impl has stricter requirements than trait - --> $DIR/lending_iterator.rs:14:45 + --> $DIR/lending_iterator.rs:13:45 | LL | fn from_iter LendingIterator = A>>(iter: T) -> Self; | ------------------------------------------------------------------------ definition of `from_iter` from trait diff --git a/src/test/ui/generic-associated-types/extended/lending_iterator.rs b/src/test/ui/generic-associated-types/extended/lending_iterator.rs index ede164766361..247761dd04bf 100644 --- a/src/test/ui/generic-associated-types/extended/lending_iterator.rs +++ b/src/test/ui/generic-associated-types/extended/lending_iterator.rs @@ -2,7 +2,6 @@ //[base] check-fail //[extended] check-pass -#![feature(generic_associated_types)] #![cfg_attr(extended, feature(generic_associated_types_extended))] #![cfg_attr(extended, allow(incomplete_features))] diff --git a/src/test/ui/generic-associated-types/extended/lending_iterator_2.base.stderr b/src/test/ui/generic-associated-types/extended/lending_iterator_2.base.stderr index 6c2a624ca11d..f6b0b644e406 100644 --- a/src/test/ui/generic-associated-types/extended/lending_iterator_2.base.stderr +++ b/src/test/ui/generic-associated-types/extended/lending_iterator_2.base.stderr @@ -1,5 +1,5 @@ error[E0276]: impl has stricter requirements than trait - --> $DIR/lending_iterator_2.rs:14:45 + --> $DIR/lending_iterator_2.rs:13:45 | LL | fn from_iter LendingIterator = A>>(iter: T) -> Self; | ------------------------------------------------------------------------ definition of `from_iter` from trait diff --git a/src/test/ui/generic-associated-types/extended/lending_iterator_2.rs b/src/test/ui/generic-associated-types/extended/lending_iterator_2.rs index 3c4a2184db90..eb9c0456a1ee 100644 --- a/src/test/ui/generic-associated-types/extended/lending_iterator_2.rs +++ b/src/test/ui/generic-associated-types/extended/lending_iterator_2.rs @@ -2,7 +2,6 @@ //[base] check-fail //[extended] check-pass -#![feature(generic_associated_types)] #![cfg_attr(extended, feature(generic_associated_types_extended))] #![cfg_attr(extended, allow(incomplete_features))] diff --git a/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.rs b/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.rs deleted file mode 100644 index c1d68812e935..000000000000 --- a/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.rs +++ /dev/null @@ -1,16 +0,0 @@ -// rust-lang/rust#60654: Do not ICE on an attempt to use GATs that is -// missing the feature gate. - -struct Foo; - -trait MyTrait { - type Item; - //~^ ERROR generic associated types are unstable [E0658] -} - -impl MyTrait for Foo { - type Item = T; - //~^ ERROR generic associated types are unstable [E0658] -} - -fn main() { } diff --git a/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.stderr b/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.stderr deleted file mode 100644 index 34f536dbe8f6..000000000000 --- a/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature-2.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0658]: generic associated types are unstable - --> $DIR/gat-dont-ice-on-absent-feature-2.rs:7:5 - | -LL | type Item; - | ^^^^^^^^^^^^^ - | - = note: see issue #44265 for more information - = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable - -error[E0658]: generic associated types are unstable - --> $DIR/gat-dont-ice-on-absent-feature-2.rs:12:5 - | -LL | type Item = T; - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #44265 for more information - = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature.rs b/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature.rs deleted file mode 100644 index e8fc47d2a59f..000000000000 --- a/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature.rs +++ /dev/null @@ -1,16 +0,0 @@ -// rust-lang/rust#60654: Do not ICE on an attempt to use GATs that is -// missing the feature gate. - -struct Foo; - -impl Iterator for Foo { - type Item<'b> = &'b Foo; - //~^ ERROR generic associated types are unstable [E0658] - //~| ERROR lifetime parameters or bounds on type `Item` do not match the trait declaration - - fn next(&mut self) -> Option { - None - } -} - -fn main() { } diff --git a/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature.stderr b/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature.stderr deleted file mode 100644 index ec36886f7b51..000000000000 --- a/src/test/ui/generic-associated-types/gat-dont-ice-on-absent-feature.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0658]: generic associated types are unstable - --> $DIR/gat-dont-ice-on-absent-feature.rs:7:5 - | -LL | type Item<'b> = &'b Foo; - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #44265 for more information - = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable - -error[E0195]: lifetime parameters or bounds on type `Item` do not match the trait declaration - --> $DIR/gat-dont-ice-on-absent-feature.rs:7:14 - | -LL | type Item<'b> = &'b Foo; - | ^^^^ lifetimes do not match type in trait - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0195, E0658. -For more information about an error, try `rustc --explain E0195`. diff --git a/src/test/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.rs b/src/test/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.rs index f542a7f545e0..86b164ba7d8a 100644 --- a/src/test/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.rs +++ b/src/test/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - trait X { type Y<'x>; } diff --git a/src/test/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr b/src/test/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr index 1792d8db292c..b77f10084c92 100644 --- a/src/test/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr +++ b/src/test/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr @@ -1,5 +1,5 @@ error[E0261]: use of undeclared lifetime name `'x` - --> $DIR/gat-in-trait-path-undeclared-lifetime.rs:8:35 + --> $DIR/gat-in-trait-path-undeclared-lifetime.rs:6:35 | LL | fn _f(arg : Box X = &'a [u32]>>) {} | ^^ undeclared lifetime @@ -15,7 +15,7 @@ LL | fn _f<'x>(arg : Box X = &'a [u32]>>) {} | ++++ error[E0582]: binding for associated type `Y` references lifetime `'a`, which does not appear in the trait input types - --> $DIR/gat-in-trait-path-undeclared-lifetime.rs:8:33 + --> $DIR/gat-in-trait-path-undeclared-lifetime.rs:6:33 | LL | fn _f(arg : Box X = &'a [u32]>>) {} | ^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/generic-associated-types/gat-in-trait-path.base.stderr b/src/test/ui/generic-associated-types/gat-in-trait-path.base.stderr index c2054f64e2d6..fd54faaf37cb 100644 --- a/src/test/ui/generic-associated-types/gat-in-trait-path.base.stderr +++ b/src/test/ui/generic-associated-types/gat-in-trait-path.base.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/gat-in-trait-path.rs:27:17 + --> $DIR/gat-in-trait-path.rs:26:17 | LL | fn f(_arg : Box Foo = &'a ()>>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit - --> $DIR/gat-in-trait-path.rs:11:10 + --> $DIR/gat-in-trait-path.rs:10:10 | LL | trait Foo { | --- this trait cannot be made into an object... diff --git a/src/test/ui/generic-associated-types/gat-in-trait-path.rs b/src/test/ui/generic-associated-types/gat-in-trait-path.rs index c82450ccff14..c55f5a726bdc 100644 --- a/src/test/ui/generic-associated-types/gat-in-trait-path.rs +++ b/src/test/ui/generic-associated-types/gat-in-trait-path.rs @@ -2,7 +2,6 @@ //[base] check-fail //[extended] check-pass -#![feature(generic_associated_types)] #![feature(associated_type_defaults)] #![cfg_attr(extended, feature(generic_associated_types_extended))] #![cfg_attr(extended, allow(incomplete_features))] diff --git a/src/test/ui/generic-associated-types/gat-incomplete-warning.rs b/src/test/ui/generic-associated-types/gat-incomplete-warning.rs deleted file mode 100644 index 607ea1759888..000000000000 --- a/src/test/ui/generic-associated-types/gat-incomplete-warning.rs +++ /dev/null @@ -1,5 +0,0 @@ -// run-pass - -#![feature(generic_associated_types)] - -fn main() {} diff --git a/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.rs b/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.rs index dbf7e02aeafc..d00c036fbd55 100644 --- a/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.rs +++ b/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - trait Foo { type F<'a>; diff --git a/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.stderr b/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.stderr index dad0dae6a44b..cb2b9f32bfe7 100644 --- a/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.stderr +++ b/src/test/ui/generic-associated-types/gat-trait-path-generic-type-arg.stderr @@ -1,5 +1,5 @@ error[E0403]: the name `T1` is already used for a generic parameter in this item's generic parameters - --> $DIR/gat-trait-path-generic-type-arg.rs:11:12 + --> $DIR/gat-trait-path-generic-type-arg.rs:9:12 | LL | impl Foo for T { | -- first use of `T1` @@ -8,13 +8,13 @@ LL | type F = &[u8]; | ^^ already used error[E0637]: `&` without an explicit lifetime name cannot be used here - --> $DIR/gat-trait-path-generic-type-arg.rs:11:18 + --> $DIR/gat-trait-path-generic-type-arg.rs:9:18 | LL | type F = &[u8]; | ^ explicit lifetime name needed here error[E0207]: the type parameter `T1` is not constrained by the impl trait, self type, or predicates - --> $DIR/gat-trait-path-generic-type-arg.rs:9:10 + --> $DIR/gat-trait-path-generic-type-arg.rs:7:10 | LL | impl Foo for T { | ^^ unconstrained type parameter diff --git a/src/test/ui/generic-associated-types/gat-trait-path-missing-lifetime.rs b/src/test/ui/generic-associated-types/gat-trait-path-missing-lifetime.rs index 9864787f0aa2..83b86f04a957 100644 --- a/src/test/ui/generic-associated-types/gat-trait-path-missing-lifetime.rs +++ b/src/test/ui/generic-associated-types/gat-trait-path-missing-lifetime.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - trait X { type Y<'a>; diff --git a/src/test/ui/generic-associated-types/gat-trait-path-missing-lifetime.stderr b/src/test/ui/generic-associated-types/gat-trait-path-missing-lifetime.stderr index aeb9238de81f..452dfefd1e3d 100644 --- a/src/test/ui/generic-associated-types/gat-trait-path-missing-lifetime.stderr +++ b/src/test/ui/generic-associated-types/gat-trait-path-missing-lifetime.stderr @@ -1,11 +1,11 @@ error[E0107]: missing generics for associated type `X::Y` - --> $DIR/gat-trait-path-missing-lifetime.rs:10:20 + --> $DIR/gat-trait-path-missing-lifetime.rs:8:20 | LL | fn foo<'a, T1: X>(t : T1) -> T1::Y<'a> { | ^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/gat-trait-path-missing-lifetime.rs:4:8 + --> $DIR/gat-trait-path-missing-lifetime.rs:2:8 | LL | type Y<'a>; | ^ -- @@ -15,13 +15,13 @@ LL | fn foo<'a, T1: X = T1>>(t : T1) -> T1::Y<'a> { | ~~~~~ error[E0107]: missing generics for associated type `X::Y` - --> $DIR/gat-trait-path-missing-lifetime.rs:10:20 + --> $DIR/gat-trait-path-missing-lifetime.rs:8:20 | LL | fn foo<'a, T1: X>(t : T1) -> T1::Y<'a> { | ^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/gat-trait-path-missing-lifetime.rs:4:8 + --> $DIR/gat-trait-path-missing-lifetime.rs:2:8 | LL | type Y<'a>; | ^ -- diff --git a/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs b/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs index c55b0530c9da..9eb069637c68 100644 --- a/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs +++ b/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - trait X { type Y<'a>; } diff --git a/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr b/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr index 162214063e7d..e55a21e19f04 100644 --- a/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr +++ b/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr @@ -1,11 +1,11 @@ error: lifetime in trait object type must be followed by `+` - --> $DIR/gat-trait-path-parenthesised-args.rs:7:29 + --> $DIR/gat-trait-path-parenthesised-args.rs:5:29 | LL | fn foo<'a>(arg: Box>) {} | ^^ error: parenthesized generic arguments cannot be used in associated type constraints - --> $DIR/gat-trait-path-parenthesised-args.rs:7:27 + --> $DIR/gat-trait-path-parenthesised-args.rs:5:27 | LL | fn foo<'a>(arg: Box>) {} | ^^^^^ @@ -16,7 +16,7 @@ LL | fn foo<'a>(arg: Box = &'a ()>>) {} | ~ ~ error: parenthesized generic arguments cannot be used in associated type constraints - --> $DIR/gat-trait-path-parenthesised-args.rs:14:27 + --> $DIR/gat-trait-path-parenthesised-args.rs:12:27 | LL | fn bar<'a>(arg: Box>) {} | ^-- @@ -24,13 +24,13 @@ LL | fn bar<'a>(arg: Box>) {} | help: remove these parentheses error[E0107]: this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied - --> $DIR/gat-trait-path-parenthesised-args.rs:7:27 + --> $DIR/gat-trait-path-parenthesised-args.rs:5:27 | LL | fn foo<'a>(arg: Box>) {} | ^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/gat-trait-path-parenthesised-args.rs:4:8 + --> $DIR/gat-trait-path-parenthesised-args.rs:2:8 | LL | type Y<'a>; | ^ -- @@ -40,7 +40,7 @@ LL | fn foo<'a>(arg: Box>) {} | +++ error[E0107]: this associated type takes 0 generic arguments but 1 generic argument was supplied - --> $DIR/gat-trait-path-parenthesised-args.rs:7:27 + --> $DIR/gat-trait-path-parenthesised-args.rs:5:27 | LL | fn foo<'a>(arg: Box>) {} | ^---- help: remove these generics @@ -48,19 +48,19 @@ LL | fn foo<'a>(arg: Box>) {} | expected 0 generic arguments | note: associated type defined here, with 0 generic parameters - --> $DIR/gat-trait-path-parenthesised-args.rs:4:8 + --> $DIR/gat-trait-path-parenthesised-args.rs:2:8 | LL | type Y<'a>; | ^ error[E0107]: this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied - --> $DIR/gat-trait-path-parenthesised-args.rs:14:27 + --> $DIR/gat-trait-path-parenthesised-args.rs:12:27 | LL | fn bar<'a>(arg: Box>) {} | ^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/gat-trait-path-parenthesised-args.rs:4:8 + --> $DIR/gat-trait-path-parenthesised-args.rs:2:8 | LL | type Y<'a>; | ^ -- diff --git a/src/test/ui/generic-associated-types/generic-associated-type-bounds.rs b/src/test/ui/generic-associated-types/generic-associated-type-bounds.rs index d7c4dbda2644..fdc5a72671ca 100644 --- a/src/test/ui/generic-associated-types/generic-associated-type-bounds.rs +++ b/src/test/ui/generic-associated-types/generic-associated-type-bounds.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(generic_associated_types)] - pub trait X { type Y<'a> where Self: 'a; fn m(&self) -> Self::Y<'_>; diff --git a/src/test/ui/generic-associated-types/generic-associated-types-where.rs b/src/test/ui/generic-associated-types/generic-associated-types-where.rs index 2ecbc8c59125..bbdfffafedb7 100644 --- a/src/test/ui/generic-associated-types/generic-associated-types-where.rs +++ b/src/test/ui/generic-associated-types/generic-associated-types-where.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - // Checking the interaction with this other feature #![feature(associated_type_defaults)] diff --git a/src/test/ui/generic-associated-types/generic-associated-types-where.stderr b/src/test/ui/generic-associated-types/generic-associated-types-where.stderr index e866b3bab797..9a745c099c0e 100644 --- a/src/test/ui/generic-associated-types/generic-associated-types-where.stderr +++ b/src/test/ui/generic-associated-types/generic-associated-types-where.stderr @@ -1,5 +1,5 @@ error[E0277]: `T` doesn't implement `std::fmt::Display` - --> $DIR/generic-associated-types-where.rs:20:22 + --> $DIR/generic-associated-types-where.rs:18:22 | LL | type Assoc2 = Vec; | ^^^^^^ `T` cannot be formatted with the default formatter @@ -11,7 +11,7 @@ LL | type Assoc2 = Vec; | +++++++++++++++++++ error[E0276]: impl has stricter requirements than trait - --> $DIR/generic-associated-types-where.rs:22:38 + --> $DIR/generic-associated-types-where.rs:20:38 | LL | type Assoc3; | -------------- definition of `Assoc3` from trait diff --git a/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.rs b/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.rs index 43058f7eb41b..2cb218bf8f25 100644 --- a/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.rs +++ b/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - use std::ops::Deref; trait Iterable { diff --git a/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr b/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr index a4bb361900fe..396ff15ab1a4 100644 --- a/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr +++ b/src/test/ui/generic-associated-types/generic_associated_type_undeclared_lifetimes.stderr @@ -1,5 +1,5 @@ error[E0261]: use of undeclared lifetime name `'b` - --> $DIR/generic_associated_type_undeclared_lifetimes.rs:8:37 + --> $DIR/generic_associated_type_undeclared_lifetimes.rs:6:37 | LL | + Deref>; | ^^ undeclared lifetime @@ -19,7 +19,7 @@ LL | trait Iterable<'b> { | ++++ error[E0261]: use of undeclared lifetime name `'undeclared` - --> $DIR/generic_associated_type_undeclared_lifetimes.rs:11:41 + --> $DIR/generic_associated_type_undeclared_lifetimes.rs:9:41 | LL | fn iter<'a>(&'a self) -> Self::Iter<'undeclared>; | ^^^^^^^^^^^ undeclared lifetime diff --git a/src/test/ui/generic-associated-types/impl_bounds.rs b/src/test/ui/generic-associated-types/impl_bounds.rs index ec1d171c0447..01165fcebaf7 100644 --- a/src/test/ui/generic-associated-types/impl_bounds.rs +++ b/src/test/ui/generic-associated-types/impl_bounds.rs @@ -1,4 +1,3 @@ -#![feature(generic_associated_types)] #![feature(associated_type_defaults)] trait Foo { diff --git a/src/test/ui/generic-associated-types/impl_bounds.stderr b/src/test/ui/generic-associated-types/impl_bounds.stderr index 4f8d673d1cf2..442d4f33690e 100644 --- a/src/test/ui/generic-associated-types/impl_bounds.stderr +++ b/src/test/ui/generic-associated-types/impl_bounds.stderr @@ -1,5 +1,5 @@ error[E0276]: impl has stricter requirements than trait - --> $DIR/impl_bounds.rs:15:39 + --> $DIR/impl_bounds.rs:14:39 | LL | type A<'a> where Self: 'a; | ---------- definition of `A` from trait @@ -8,7 +8,7 @@ LL | type A<'a> = (&'a ()) where Self: 'static; | ^^^^^^^ impl has extra requirement `T: 'static` error[E0276]: impl has stricter requirements than trait - --> $DIR/impl_bounds.rs:17:48 + --> $DIR/impl_bounds.rs:16:48 | LL | type B<'a, 'b> where 'a: 'b; | -------------- definition of `B` from trait @@ -17,7 +17,7 @@ LL | type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a; | ^^ impl has extra requirement `'b: 'a` error[E0478]: lifetime bound not satisfied - --> $DIR/impl_bounds.rs:17:22 + --> $DIR/impl_bounds.rs:16:22 | LL | type B<'a, 'b> where 'a: 'b; | -------------- definition of `B` from trait @@ -26,29 +26,29 @@ LL | type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a; | ^^^^^^^^^^^^^^^ - help: try copying this clause from the trait: `, 'a: 'b` | note: lifetime parameter instantiated with the lifetime `'a` as defined here - --> $DIR/impl_bounds.rs:17:12 + --> $DIR/impl_bounds.rs:16:12 | LL | type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a; | ^^ note: but lifetime parameter must outlive the lifetime `'b` as defined here - --> $DIR/impl_bounds.rs:17:16 + --> $DIR/impl_bounds.rs:16:16 | LL | type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a; | ^^ error[E0277]: the trait bound `T: Copy` is not satisfied - --> $DIR/impl_bounds.rs:20:33 + --> $DIR/impl_bounds.rs:19:33 | LL | type C = String where Self: Copy; | ^^^^ the trait `Copy` is not implemented for `T` | note: required for `Fooy` to implement `Copy` - --> $DIR/impl_bounds.rs:11:10 + --> $DIR/impl_bounds.rs:10:10 | LL | #[derive(Copy, Clone)] | ^^^^ note: the requirement `Fooy: Copy` appears on the `impl`'s associated type `C` but not on the corresponding trait's associated type - --> $DIR/impl_bounds.rs:7:10 + --> $DIR/impl_bounds.rs:6:10 | LL | trait Foo { | --- in this trait @@ -62,18 +62,18 @@ LL | impl Foo for Fooy { | +++++++++++++++++++ error[E0277]: the trait bound `T: Copy` is not satisfied - --> $DIR/impl_bounds.rs:22:24 + --> $DIR/impl_bounds.rs:21:24 | LL | fn d() where Self: Copy {} | ^^^^ the trait `Copy` is not implemented for `T` | note: required for `Fooy` to implement `Copy` - --> $DIR/impl_bounds.rs:11:10 + --> $DIR/impl_bounds.rs:10:10 | LL | #[derive(Copy, Clone)] | ^^^^ note: the requirement `Fooy: Copy` appears on the `impl`'s method `d` but not on the corresponding trait's method - --> $DIR/impl_bounds.rs:8:8 + --> $DIR/impl_bounds.rs:7:8 | LL | trait Foo { | --- in this trait diff --git a/src/test/ui/generic-associated-types/impl_bounds_ok.rs b/src/test/ui/generic-associated-types/impl_bounds_ok.rs index 4df8235d95f3..88f829ea25a5 100644 --- a/src/test/ui/generic-associated-types/impl_bounds_ok.rs +++ b/src/test/ui/generic-associated-types/impl_bounds_ok.rs @@ -1,6 +1,5 @@ // check-pass -#![feature(generic_associated_types)] #![feature(associated_type_defaults)] trait Foo { diff --git a/src/test/ui/generic-associated-types/issue-101020.rs b/src/test/ui/generic-associated-types/issue-101020.rs index 51cabe21e629..80d0fa5ad34b 100644 --- a/src/test/ui/generic-associated-types/issue-101020.rs +++ b/src/test/ui/generic-associated-types/issue-101020.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - pub trait LendingIterator { type Item<'a> where diff --git a/src/test/ui/generic-associated-types/issue-101020.stderr b/src/test/ui/generic-associated-types/issue-101020.stderr index 7fde89eb75e5..b4e94cb83f73 100644 --- a/src/test/ui/generic-associated-types/issue-101020.stderr +++ b/src/test/ui/generic-associated-types/issue-101020.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `for<'a> &'a mut (): Foo<&'a mut ()>` is not satisfied - --> $DIR/issue-101020.rs:33:5 + --> $DIR/issue-101020.rs:31:5 | LL | (&mut EmptyIter).consume(()); | ^^^^^^^^^^^^^^^^ ------- required by a bound introduced by this call @@ -7,12 +7,12 @@ LL | (&mut EmptyIter).consume(()); | the trait `for<'a> Foo<&'a mut ()>` is not implemented for `&'a mut ()` | note: required for `&'a mut ()` to implement `for<'a> FuncInput<'a, &'a mut ()>` - --> $DIR/issue-101020.rs:29:20 + --> $DIR/issue-101020.rs:27:20 | LL | impl<'a, T, F: 'a> FuncInput<'a, F> for T where F: Foo {} | ^^^^^^^^^^^^^^^^ ^ note: required by a bound in `LendingIterator::consume` - --> $DIR/issue-101020.rs:11:33 + --> $DIR/issue-101020.rs:9:33 | LL | fn consume(self, _f: F) | ------- required by a bound in this diff --git a/src/test/ui/generic-associated-types/issue-47206-where-clause.rs b/src/test/ui/generic-associated-types/issue-47206-where-clause.rs index d352c1948f23..3d1b88ddf299 100644 --- a/src/test/ui/generic-associated-types/issue-47206-where-clause.rs +++ b/src/test/ui/generic-associated-types/issue-47206-where-clause.rs @@ -1,7 +1,5 @@ // Check that this program doesn't cause the compiler to error without output. -#![feature(generic_associated_types)] - trait Foo { type Assoc3; } diff --git a/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr b/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr index 31948a878edf..7006744df498 100644 --- a/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr +++ b/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr @@ -1,5 +1,5 @@ error[E0276]: impl has stricter requirements than trait - --> $DIR/issue-47206-where-clause.rs:12:38 + --> $DIR/issue-47206-where-clause.rs:10:38 | LL | type Assoc3; | -------------- definition of `Assoc3` from trait diff --git a/src/test/ui/generic-associated-types/issue-58694-parameter-out-of-range.rs b/src/test/ui/generic-associated-types/issue-58694-parameter-out-of-range.rs index e87a76825c37..625ccfe89e09 100644 --- a/src/test/ui/generic-associated-types/issue-58694-parameter-out-of-range.rs +++ b/src/test/ui/generic-associated-types/issue-58694-parameter-out-of-range.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(generic_associated_types)] - trait Cert { type PublicKey<'a>: From<&'a [u8]>; } diff --git a/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.rs b/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.rs index d74d6d056d66..c1140bff82ba 100644 --- a/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.rs +++ b/src/test/ui/generic-associated-types/issue-62326-parameter-out-of-range.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - // check-pass trait Iterator { diff --git a/src/test/ui/generic-associated-types/issue-67424.rs b/src/test/ui/generic-associated-types/issue-67424.rs index fa35a3e8b04d..b6c7c70cd831 100644 --- a/src/test/ui/generic-associated-types/issue-67424.rs +++ b/src/test/ui/generic-associated-types/issue-67424.rs @@ -1,3 +1,4 @@ +// check-pass // Fixed by #67160 trait Trait1 { @@ -6,7 +7,6 @@ trait Trait1 { trait Trait2 { type Type1: Trait1; - //~^ ERROR: generic associated types are unstable } fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-67424.stderr b/src/test/ui/generic-associated-types/issue-67424.stderr deleted file mode 100644 index bbb7d56f5928..000000000000 --- a/src/test/ui/generic-associated-types/issue-67424.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0658]: generic associated types are unstable - --> $DIR/issue-67424.rs:8:5 - | -LL | type Type1: Trait1; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #44265 for more information - = help: add `#![feature(generic_associated_types)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/generic-associated-types/issue-67510-pass.base.stderr b/src/test/ui/generic-associated-types/issue-67510-pass.base.stderr index 74a616aaabe3..4cc68530ee1a 100644 --- a/src/test/ui/generic-associated-types/issue-67510-pass.base.stderr +++ b/src/test/ui/generic-associated-types/issue-67510-pass.base.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `X` cannot be made into an object - --> $DIR/issue-67510-pass.rs:13:23 + --> $DIR/issue-67510-pass.rs:12:23 | LL | fn _func1<'a>(_x: Box=&'a ()>>) {} | ^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit - --> $DIR/issue-67510-pass.rs:10:10 + --> $DIR/issue-67510-pass.rs:9:10 | LL | trait X { | - this trait cannot be made into an object... diff --git a/src/test/ui/generic-associated-types/issue-67510-pass.rs b/src/test/ui/generic-associated-types/issue-67510-pass.rs index c5b02ff9a640..66ce3e807a15 100644 --- a/src/test/ui/generic-associated-types/issue-67510-pass.rs +++ b/src/test/ui/generic-associated-types/issue-67510-pass.rs @@ -2,7 +2,6 @@ //[base] check-fail //[extended] check-pass -#![feature(generic_associated_types)] #![cfg_attr(extended, feature(generic_associated_types_extended))] #![cfg_attr(extended, allow(incomplete_features))] diff --git a/src/test/ui/generic-associated-types/issue-67510.rs b/src/test/ui/generic-associated-types/issue-67510.rs index 5725b660ab23..ab5c25d74da7 100644 --- a/src/test/ui/generic-associated-types/issue-67510.rs +++ b/src/test/ui/generic-associated-types/issue-67510.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - trait X { type Y<'a>; } diff --git a/src/test/ui/generic-associated-types/issue-67510.stderr b/src/test/ui/generic-associated-types/issue-67510.stderr index 8aeda22bad75..d25c5b0f387c 100644 --- a/src/test/ui/generic-associated-types/issue-67510.stderr +++ b/src/test/ui/generic-associated-types/issue-67510.stderr @@ -1,5 +1,5 @@ error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/issue-67510.rs:7:21 + --> $DIR/issue-67510.rs:5:21 | LL | fn f(x: Box = &'a ()>>) {} | ^^ undeclared lifetime @@ -15,7 +15,7 @@ LL | fn f<'a>(x: Box = &'a ()>>) {} | ++++ error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/issue-67510.rs:7:28 + --> $DIR/issue-67510.rs:5:28 | LL | fn f(x: Box = &'a ()>>) {} | ^^ undeclared lifetime @@ -30,13 +30,13 @@ LL | fn f<'a>(x: Box = &'a ()>>) {} | ++++ error[E0038]: the trait `X` cannot be made into an object - --> $DIR/issue-67510.rs:7:13 + --> $DIR/issue-67510.rs:5:13 | LL | fn f(x: Box = &'a ()>>) {} | ^^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit - --> $DIR/issue-67510.rs:4:10 + --> $DIR/issue-67510.rs:2:10 | LL | trait X { | - this trait cannot be made into an object... diff --git a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs index 617d985dce9f..f1e779fcb006 100644 --- a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs +++ b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs @@ -1,7 +1,5 @@ // Regression test for #68641 -#![feature(generic_associated_types)] - trait UnsafeCopy { type Item<'a>: Copy; diff --git a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr index 2e21b38cb0e9..6bb7492af811 100644 --- a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr +++ b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `T: Copy` is not satisfied - --> $DIR/issue-68641-check-gat-bounds.rs:14:21 + --> $DIR/issue-68641-check-gat-bounds.rs:12:21 | LL | type Item<'a> = T; | ^ the trait `Copy` is not implemented for `T` | note: required by a bound in `UnsafeCopy::Item` - --> $DIR/issue-68641-check-gat-bounds.rs:6:20 + --> $DIR/issue-68641-check-gat-bounds.rs:4:20 | LL | type Item<'a>: Copy; | ^^^^ required by this bound in `UnsafeCopy::Item` diff --git a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs index def0ad18f232..f5502adee426 100644 --- a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs +++ b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs @@ -1,7 +1,5 @@ // Regression test for #68642 -#![feature(generic_associated_types)] - trait Fun { type F<'a>: Fn() -> u32; diff --git a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr index 713cc744f5a2..07452137b5bd 100644 --- a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr +++ b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr @@ -1,12 +1,12 @@ error[E0277]: expected a `Fn<()>` closure, found `T` - --> $DIR/issue-68642-broken-llvm-ir.rs:14:18 + --> $DIR/issue-68642-broken-llvm-ir.rs:12:18 | LL | type F<'a> = Self; | ^^^^ expected an `Fn<()>` closure, found `T` | = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }` note: required by a bound in `Fun::F` - --> $DIR/issue-68642-broken-llvm-ir.rs:6:17 + --> $DIR/issue-68642-broken-llvm-ir.rs:4:17 | LL | type F<'a>: Fn() -> u32; | ^^^^^^^^^^^ required by this bound in `Fun::F` diff --git a/src/test/ui/generic-associated-types/issue-68643-broken-mir.rs b/src/test/ui/generic-associated-types/issue-68643-broken-mir.rs index 9af065b5d26d..6050a8bf5618 100644 --- a/src/test/ui/generic-associated-types/issue-68643-broken-mir.rs +++ b/src/test/ui/generic-associated-types/issue-68643-broken-mir.rs @@ -1,7 +1,5 @@ // Regression test for #68643 -#![feature(generic_associated_types)] - trait Fun { type F<'a>: Fn() -> u32; diff --git a/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr index a7b7f64cdb17..31ded5dab95b 100644 --- a/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr +++ b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr @@ -1,12 +1,12 @@ error[E0277]: expected a `Fn<()>` closure, found `T` - --> $DIR/issue-68643-broken-mir.rs:14:18 + --> $DIR/issue-68643-broken-mir.rs:12:18 | LL | type F<'a> = Self; | ^^^^ expected an `Fn<()>` closure, found `T` | = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }` note: required by a bound in `Fun::F` - --> $DIR/issue-68643-broken-mir.rs:6:17 + --> $DIR/issue-68643-broken-mir.rs:4:17 | LL | type F<'a>: Fn() -> u32; | ^^^^^^^^^^^ required by this bound in `Fun::F` diff --git a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs index 1d2636c260d8..898cfa1e744c 100644 --- a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs +++ b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs @@ -1,7 +1,5 @@ // Regression test for #68644 -#![feature(generic_associated_types)] - trait Fun { type F<'a>: Fn() -> u32; diff --git a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr index 5e921e053bb4..e2f9930cc67f 100644 --- a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr +++ b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr @@ -1,12 +1,12 @@ error[E0277]: expected a `Fn<()>` closure, found `T` - --> $DIR/issue-68644-codegen-selection.rs:14:18 + --> $DIR/issue-68644-codegen-selection.rs:12:18 | LL | type F<'a> = Self; | ^^^^ expected an `Fn<()>` closure, found `T` | = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }` note: required by a bound in `Fun::F` - --> $DIR/issue-68644-codegen-selection.rs:6:17 + --> $DIR/issue-68644-codegen-selection.rs:4:17 | LL | type F<'a>: Fn() -> u32; | ^^^^^^^^^^^ required by this bound in `Fun::F` diff --git a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs index aa505064f8c5..60b065bfc317 100644 --- a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs +++ b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs @@ -1,7 +1,5 @@ // Regression test for #68645 -#![feature(generic_associated_types)] - trait Fun { type F<'a>: Fn() -> u32; diff --git a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr index 7edcdce628e6..0065368ad31d 100644 --- a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr +++ b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr @@ -1,12 +1,12 @@ error[E0277]: expected a `Fn<()>` closure, found `T` - --> $DIR/issue-68645-codegen-fulfillment.rs:14:18 + --> $DIR/issue-68645-codegen-fulfillment.rs:12:18 | LL | type F<'a> = Self; | ^^^^ expected an `Fn<()>` closure, found `T` | = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }` note: required by a bound in `Fun::F` - --> $DIR/issue-68645-codegen-fulfillment.rs:6:17 + --> $DIR/issue-68645-codegen-fulfillment.rs:4:17 | LL | type F<'a>: Fn() -> u32; | ^^^^^^^^^^^ required by this bound in `Fun::F` diff --git a/src/test/ui/generic-associated-types/issue-68648-1.rs b/src/test/ui/generic-associated-types/issue-68648-1.rs index 17bc034b3958..0df41bab3272 100644 --- a/src/test/ui/generic-associated-types/issue-68648-1.rs +++ b/src/test/ui/generic-associated-types/issue-68648-1.rs @@ -1,8 +1,5 @@ // check-pass -#![feature(generic_associated_types)] - - trait Fun { type F<'a>; diff --git a/src/test/ui/generic-associated-types/issue-68648-2.rs b/src/test/ui/generic-associated-types/issue-68648-2.rs index 6c9a0d126a78..0f963d58f5e8 100644 --- a/src/test/ui/generic-associated-types/issue-68648-2.rs +++ b/src/test/ui/generic-associated-types/issue-68648-2.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - trait Fun { type F<'a>; diff --git a/src/test/ui/generic-associated-types/issue-68648-2.stderr b/src/test/ui/generic-associated-types/issue-68648-2.stderr index 06c1efcd80b0..b2bef19eb5e9 100644 --- a/src/test/ui/generic-associated-types/issue-68648-2.stderr +++ b/src/test/ui/generic-associated-types/issue-68648-2.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-68648-2.rs:14:17 + --> $DIR/issue-68648-2.rs:12:17 | LL | fn bug<'a, T: Fun = T>>(t: T) -> T::F<'a> { | - this type parameter @@ -11,7 +11,7 @@ LL | T::identity(()) = note: expected type parameter `T` found unit type `()` note: associated function defined here - --> $DIR/issue-68648-2.rs:6:8 + --> $DIR/issue-68648-2.rs:4:8 | LL | fn identity<'a>(t: Self::F<'a>) -> Self::F<'a> { t } | ^^^^^^^^ -------------- diff --git a/src/test/ui/generic-associated-types/issue-68649-pass.rs b/src/test/ui/generic-associated-types/issue-68649-pass.rs index 33f08faff56b..772743877954 100644 --- a/src/test/ui/generic-associated-types/issue-68649-pass.rs +++ b/src/test/ui/generic-associated-types/issue-68649-pass.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(generic_associated_types)] - trait Fun { type F<'a>; diff --git a/src/test/ui/generic-associated-types/issue-68653.rs b/src/test/ui/generic-associated-types/issue-68653.rs index 1e84717e9259..170b87cf2528 100644 --- a/src/test/ui/generic-associated-types/issue-68653.rs +++ b/src/test/ui/generic-associated-types/issue-68653.rs @@ -2,8 +2,6 @@ // check-pass -#![feature(generic_associated_types)] - trait Fun { type F<'a: 'a>; } diff --git a/src/test/ui/generic-associated-types/issue-68656-unsized-values.rs b/src/test/ui/generic-associated-types/issue-68656-unsized-values.rs index c0d933362567..607cfed0bc64 100644 --- a/src/test/ui/generic-associated-types/issue-68656-unsized-values.rs +++ b/src/test/ui/generic-associated-types/issue-68656-unsized-values.rs @@ -1,7 +1,5 @@ // Regression test for #68656 -#![feature(generic_associated_types)] - trait UnsafeCopy { type Item<'a>: std::ops::Deref; diff --git a/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr b/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr index 8e0f23716019..e8770aedfa1c 100644 --- a/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr +++ b/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr @@ -1,5 +1,5 @@ error[E0271]: type mismatch resolving `::Target == T` - --> $DIR/issue-68656-unsized-values.rs:15:21 + --> $DIR/issue-68656-unsized-values.rs:13:21 | LL | impl UnsafeCopy for T { | - this type parameter @@ -9,7 +9,7 @@ LL | type Item<'a> = T; = note: expected type parameter `T` found associated type `::Target` note: required by a bound in `UnsafeCopy::Item` - --> $DIR/issue-68656-unsized-values.rs:6:36 + --> $DIR/issue-68656-unsized-values.rs:4:36 | LL | type Item<'a>: std::ops::Deref; | ^^^^^^^^^^ required by this bound in `UnsafeCopy::Item` diff --git a/src/test/ui/generic-associated-types/issue-70303.rs b/src/test/ui/generic-associated-types/issue-70303.rs index 568996e1a17a..0edff5e4e339 100644 --- a/src/test/ui/generic-associated-types/issue-70303.rs +++ b/src/test/ui/generic-associated-types/issue-70303.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(generic_associated_types)] - trait Document { type Cursor<'a>: DocCursor<'a> where Self: 'a; diff --git a/src/test/ui/generic-associated-types/issue-70304.rs b/src/test/ui/generic-associated-types/issue-70304.rs index f778f985cf0d..8898d4c7d135 100644 --- a/src/test/ui/generic-associated-types/issue-70304.rs +++ b/src/test/ui/generic-associated-types/issue-70304.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - trait Document { type Cursor<'a>: DocCursor<'a>; //~^ ERROR: missing required bound on `Cursor` diff --git a/src/test/ui/generic-associated-types/issue-70304.stderr b/src/test/ui/generic-associated-types/issue-70304.stderr index bba7cab7093c..99339e968595 100644 --- a/src/test/ui/generic-associated-types/issue-70304.stderr +++ b/src/test/ui/generic-associated-types/issue-70304.stderr @@ -1,11 +1,11 @@ error[E0637]: `'_` cannot be used here - --> $DIR/issue-70304.rs:48:41 + --> $DIR/issue-70304.rs:46:41 | LL | fn create_doc() -> impl Document = DocCursorImpl<'_>> { | ^^ `'_` is a reserved lifetime name error[E0106]: missing lifetime specifier - --> $DIR/issue-70304.rs:48:61 + --> $DIR/issue-70304.rs:46:61 | LL | fn create_doc() -> impl Document = DocCursorImpl<'_>> { | ^^ expected named lifetime parameter @@ -17,7 +17,7 @@ LL | fn create_doc() -> impl Document = DocCursorImpl<'static>> { | ~~~~~~~ error: missing required bound on `Cursor` - --> $DIR/issue-70304.rs:4:5 + --> $DIR/issue-70304.rs:2:5 | LL | type Cursor<'a>: DocCursor<'a>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- diff --git a/src/test/ui/generic-associated-types/issue-71176.rs b/src/test/ui/generic-associated-types/issue-71176.rs index c2f0d59f4435..f0e162d825f9 100644 --- a/src/test/ui/generic-associated-types/issue-71176.rs +++ b/src/test/ui/generic-associated-types/issue-71176.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - trait Provider { type A<'a>; } diff --git a/src/test/ui/generic-associated-types/issue-71176.stderr b/src/test/ui/generic-associated-types/issue-71176.stderr index 08c8d41624e2..386c97161c8f 100644 --- a/src/test/ui/generic-associated-types/issue-71176.stderr +++ b/src/test/ui/generic-associated-types/issue-71176.stderr @@ -1,11 +1,11 @@ error[E0107]: missing generics for associated type `Provider::A` - --> $DIR/issue-71176.rs:12:27 + --> $DIR/issue-71176.rs:10:27 | LL | inner: Box>, | ^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/issue-71176.rs:4:10 + --> $DIR/issue-71176.rs:2:10 | LL | type A<'a>; | ^ -- diff --git a/src/test/ui/generic-associated-types/issue-74684-1.rs b/src/test/ui/generic-associated-types/issue-74684-1.rs index 0e3899a88cc9..e9ec80074f89 100644 --- a/src/test/ui/generic-associated-types/issue-74684-1.rs +++ b/src/test/ui/generic-associated-types/issue-74684-1.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - trait Fun { type F<'a>: ?Sized; diff --git a/src/test/ui/generic-associated-types/issue-74684-1.stderr b/src/test/ui/generic-associated-types/issue-74684-1.stderr index 2cd050ed8be6..cacc973077ce 100644 --- a/src/test/ui/generic-associated-types/issue-74684-1.stderr +++ b/src/test/ui/generic-associated-types/issue-74684-1.stderr @@ -1,5 +1,5 @@ error[E0597]: `a` does not live long enough - --> $DIR/issue-74684-1.rs:15:26 + --> $DIR/issue-74684-1.rs:13:26 | LL | fn bug<'a, T: ?Sized + Fun = [u8]>>(_ : Box) -> &'static T::F<'a> { | -- lifetime `'a` defined here diff --git a/src/test/ui/generic-associated-types/issue-74684-2.rs b/src/test/ui/generic-associated-types/issue-74684-2.rs index fca55070b5ba..ff243af2cb39 100644 --- a/src/test/ui/generic-associated-types/issue-74684-2.rs +++ b/src/test/ui/generic-associated-types/issue-74684-2.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - trait Fun { type F<'a>: ?Sized; diff --git a/src/test/ui/generic-associated-types/issue-74684-2.stderr b/src/test/ui/generic-associated-types/issue-74684-2.stderr index 7c2935d32bfd..59b85abf5c8c 100644 --- a/src/test/ui/generic-associated-types/issue-74684-2.stderr +++ b/src/test/ui/generic-associated-types/issue-74684-2.stderr @@ -1,5 +1,5 @@ error[E0271]: type mismatch resolving `<{integer} as Fun>::F<'_> == [u8]` - --> $DIR/issue-74684-2.rs:23:9 + --> $DIR/issue-74684-2.rs:21:9 | LL | bug(Box::new(x)); | --- ^^^^^^^^^^^ type mismatch resolving `<{integer} as Fun>::F<'_> == [u8]` @@ -7,12 +7,12 @@ LL | bug(Box::new(x)); | required by a bound introduced by this call | note: expected this to be `[u8]` - --> $DIR/issue-74684-2.rs:10:18 + --> $DIR/issue-74684-2.rs:8:18 | LL | type F<'a> = i32; | ^^^ note: required by a bound in `bug` - --> $DIR/issue-74684-2.rs:13:28 + --> $DIR/issue-74684-2.rs:11:28 | LL | fn bug<'a, T: ?Sized + Fun = [u8]>>(t: Box) -> &'static T::F<'a> { | ^^^^^^^^^^^^ required by this bound in `bug` diff --git a/src/test/ui/generic-associated-types/issue-74816.rs b/src/test/ui/generic-associated-types/issue-74816.rs index c932025d1178..344afb87f99c 100644 --- a/src/test/ui/generic-associated-types/issue-74816.rs +++ b/src/test/ui/generic-associated-types/issue-74816.rs @@ -1,5 +1,4 @@ #![feature(associated_type_defaults)] -#![feature(generic_associated_types)] trait Trait1 { fn foo(); diff --git a/src/test/ui/generic-associated-types/issue-74816.stderr b/src/test/ui/generic-associated-types/issue-74816.stderr index 9eaa74e343e4..45018e6976cf 100644 --- a/src/test/ui/generic-associated-types/issue-74816.stderr +++ b/src/test/ui/generic-associated-types/issue-74816.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `Self: Trait1` is not satisfied - --> $DIR/issue-74816.rs:9:31 + --> $DIR/issue-74816.rs:8:31 | LL | type Associated: Trait1 = Self; | ^^^^ the trait `Trait1` is not implemented for `Self` | note: required by a bound in `Trait2::Associated` - --> $DIR/issue-74816.rs:9:22 + --> $DIR/issue-74816.rs:8:22 | LL | type Associated: Trait1 = Self; | ^^^^^^ required by this bound in `Trait2::Associated` @@ -15,13 +15,13 @@ LL | trait Trait2: Trait1 { | ++++++++ error[E0277]: the size for values of type `Self` cannot be known at compilation time - --> $DIR/issue-74816.rs:9:31 + --> $DIR/issue-74816.rs:8:31 | LL | type Associated: Trait1 = Self; | ^^^^ doesn't have a size known at compile-time | note: required by a bound in `Trait2::Associated` - --> $DIR/issue-74816.rs:9:5 + --> $DIR/issue-74816.rs:8:5 | LL | type Associated: Trait1 = Self; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Trait2::Associated` diff --git a/src/test/ui/generic-associated-types/issue-74824.rs b/src/test/ui/generic-associated-types/issue-74824.rs index 1bbf7aac5cda..10c45d133642 100644 --- a/src/test/ui/generic-associated-types/issue-74824.rs +++ b/src/test/ui/generic-associated-types/issue-74824.rs @@ -1,4 +1,3 @@ -#![feature(generic_associated_types)] #![feature(associated_type_defaults)] use std::ops::Deref; diff --git a/src/test/ui/generic-associated-types/issue-74824.stderr b/src/test/ui/generic-associated-types/issue-74824.stderr index eabc806c2b7d..623adb1c2ad1 100644 --- a/src/test/ui/generic-associated-types/issue-74824.stderr +++ b/src/test/ui/generic-associated-types/issue-74824.stderr @@ -1,24 +1,24 @@ error[E0277]: the trait bound `Box: Copy` is not satisfied - --> $DIR/issue-74824.rs:7:26 + --> $DIR/issue-74824.rs:6:26 | LL | type Copy: Copy = Box; | ^^^^^^ the trait `Copy` is not implemented for `Box` | note: required by a bound in `UnsafeCopy::Copy` - --> $DIR/issue-74824.rs:7:19 + --> $DIR/issue-74824.rs:6:19 | LL | type Copy: Copy = Box; | ^^^^ required by this bound in `UnsafeCopy::Copy` error[E0277]: the trait bound `T: Clone` is not satisfied - --> $DIR/issue-74824.rs:7:26 + --> $DIR/issue-74824.rs:6:26 | LL | type Copy: Copy = Box; | ^^^^^^ the trait `Clone` is not implemented for `T` | = note: required for `Box` to implement `Clone` note: required by a bound in `UnsafeCopy::Copy` - --> $DIR/issue-74824.rs:7:19 + --> $DIR/issue-74824.rs:6:19 | LL | type Copy: Copy = Box; | ^^^^ required by this bound in `UnsafeCopy::Copy` diff --git a/src/test/ui/generic-associated-types/issue-76407.rs b/src/test/ui/generic-associated-types/issue-76407.rs index a8141829ba88..9556ec6da253 100644 --- a/src/test/ui/generic-associated-types/issue-76407.rs +++ b/src/test/ui/generic-associated-types/issue-76407.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(generic_associated_types)] - trait Marker {} impl Marker for u32 {} diff --git a/src/test/ui/generic-associated-types/issue-76535.base.stderr b/src/test/ui/generic-associated-types/issue-76535.base.stderr index fe5fe964e991..088f69b09f70 100644 --- a/src/test/ui/generic-associated-types/issue-76535.base.stderr +++ b/src/test/ui/generic-associated-types/issue-76535.base.stderr @@ -1,11 +1,11 @@ error[E0107]: missing generics for associated type `SuperTrait::SubType` - --> $DIR/issue-76535.rs:40:33 + --> $DIR/issue-76535.rs:39:33 | LL | let sub: Box> = Box::new(SuperStruct::new(0)); | ^^^^^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/issue-76535.rs:10:10 + --> $DIR/issue-76535.rs:9:10 | LL | type SubType<'a>: SubTrait where Self: 'a; | ^^^^^^^ -- @@ -15,13 +15,13 @@ LL | let sub: Box = SubStruct>> = Box::new(SuperS | ~~~~~~~~~~~ error[E0038]: the trait `SuperTrait` cannot be made into an object - --> $DIR/issue-76535.rs:40:14 + --> $DIR/issue-76535.rs:39:14 | LL | let sub: Box> = Box::new(SuperStruct::new(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit - --> $DIR/issue-76535.rs:10:10 + --> $DIR/issue-76535.rs:9:10 | LL | pub trait SuperTrait { | ---------- this trait cannot be made into an object... @@ -30,13 +30,13 @@ LL | type SubType<'a>: SubTrait where Self: 'a; = help: consider moving `SubType` to another trait error[E0038]: the trait `SuperTrait` cannot be made into an object - --> $DIR/issue-76535.rs:40:57 + --> $DIR/issue-76535.rs:39:57 | LL | let sub: Box> = Box::new(SuperStruct::new(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit - --> $DIR/issue-76535.rs:10:10 + --> $DIR/issue-76535.rs:9:10 | LL | pub trait SuperTrait { | ---------- this trait cannot be made into an object... diff --git a/src/test/ui/generic-associated-types/issue-76535.extended.stderr b/src/test/ui/generic-associated-types/issue-76535.extended.stderr index 067d0489b486..e79f0a73f5b5 100644 --- a/src/test/ui/generic-associated-types/issue-76535.extended.stderr +++ b/src/test/ui/generic-associated-types/issue-76535.extended.stderr @@ -1,11 +1,11 @@ error[E0107]: missing generics for associated type `SuperTrait::SubType` - --> $DIR/issue-76535.rs:40:33 + --> $DIR/issue-76535.rs:39:33 | LL | let sub: Box> = Box::new(SuperStruct::new(0)); | ^^^^^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/issue-76535.rs:10:10 + --> $DIR/issue-76535.rs:9:10 | LL | type SubType<'a>: SubTrait where Self: 'a; | ^^^^^^^ -- diff --git a/src/test/ui/generic-associated-types/issue-76535.rs b/src/test/ui/generic-associated-types/issue-76535.rs index 46f217ba06bc..2457a05a0672 100644 --- a/src/test/ui/generic-associated-types/issue-76535.rs +++ b/src/test/ui/generic-associated-types/issue-76535.rs @@ -1,6 +1,5 @@ // revisions: base extended -#![feature(generic_associated_types)] #![cfg_attr(extended, feature(generic_associated_types_extended))] #![cfg_attr(extended, allow(incomplete_features))] diff --git a/src/test/ui/generic-associated-types/issue-76826.rs b/src/test/ui/generic-associated-types/issue-76826.rs index 28eb3b0e750e..ead78453ecfe 100644 --- a/src/test/ui/generic-associated-types/issue-76826.rs +++ b/src/test/ui/generic-associated-types/issue-76826.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(generic_associated_types)] - pub trait Iter { type Item<'a> where Self: 'a; diff --git a/src/test/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.rs b/src/test/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.rs index 850d83be6845..ebf50bf4ace1 100644 --- a/src/test/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.rs +++ b/src/test/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.rs @@ -2,8 +2,6 @@ // check-fail -#![feature(generic_associated_types)] - pub trait A {} impl A for &dyn A {} impl A for Box {} diff --git a/src/test/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.stderr b/src/test/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.stderr index d487f19ba749..86e0f5745440 100644 --- a/src/test/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.stderr +++ b/src/test/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.stderr @@ -1,22 +1,22 @@ error: incompatible lifetime on type - --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:17:18 + --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:15:18 | LL | type T<'a> = Box; | ^^^^^^^^^^^^^^^ | note: because this has an unmet lifetime requirement - --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:12:17 + --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:10:17 | LL | type T<'a>: A; | ^ introduces a `'static` lifetime requirement note: the lifetime `'a` as defined here... - --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:17:12 + --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:15:12 | LL | type T<'a> = Box; | ^^ = note: ...does not necessarily outlive the static lifetime introduced by the compatible `impl` note: this has an implicit `'static` lifetime requirement - --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:9:20 + --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:7:20 | LL | impl A for Box {} | ^ @@ -26,51 +26,51 @@ LL | impl A for Box {} | ++++ error: incompatible lifetime on type - --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:27:18 + --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:25:18 | LL | type T<'a> = Box; | ^^^^^^^^^^^^^^^ | note: because this has an unmet lifetime requirement - --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:23:17 + --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:21:17 | LL | type T<'a>: C; | ^ introduces a `'static` lifetime requirement note: the lifetime `'a` as defined here... - --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:27:12 + --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:25:12 | LL | type T<'a> = Box; | ^^ note: ...does not necessarily outlive the static lifetime introduced by the compatible `impl` - --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:21:1 + --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:19:1 | LL | impl C for Box {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: incompatible lifetime on type - --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:37:18 + --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:35:18 | LL | type T<'a> = (Box, Box); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: because this has an unmet lifetime requirement - --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:33:17 + --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:31:17 | LL | type T<'a>: E; | ^ introduces a `'static` lifetime requirement note: the lifetime `'a` as defined here... - --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:37:12 + --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:35:12 | LL | type T<'a> = (Box, Box); | ^^ = note: ...does not necessarily outlive the static lifetime introduced by the compatible `impl` note: this has an implicit `'static` lifetime requirement - --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:31:21 + --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:29:21 | LL | impl E for (Box, Box) {} | ^ note: this has an implicit `'static` lifetime requirement - --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:31:33 + --> $DIR/issue-78113-lifetime-mismatch-dyn-trait-box.rs:29:33 | LL | impl E for (Box, Box) {} | ^ diff --git a/src/test/ui/generic-associated-types/issue-78671.base.stderr b/src/test/ui/generic-associated-types/issue-78671.base.stderr index 6bcd004b1a92..514f8d45a15f 100644 --- a/src/test/ui/generic-associated-types/issue-78671.base.stderr +++ b/src/test/ui/generic-associated-types/issue-78671.base.stderr @@ -1,11 +1,11 @@ error[E0107]: missing generics for associated type `CollectionFamily::Member` - --> $DIR/issue-78671.rs:11:47 + --> $DIR/issue-78671.rs:10:47 | LL | Box::new(Family) as &dyn CollectionFamily | ^^^^^^ expected 1 generic argument | note: associated type defined here, with 1 generic parameter: `T` - --> $DIR/issue-78671.rs:8:10 + --> $DIR/issue-78671.rs:7:10 | LL | type Member; | ^^^^^^ - @@ -15,13 +15,13 @@ LL | Box::new(Family) as &dyn CollectionFamily=usize> | ~~~~~~~~~ error[E0038]: the trait `CollectionFamily` cannot be made into an object - --> $DIR/issue-78671.rs:11:25 + --> $DIR/issue-78671.rs:10:25 | LL | Box::new(Family) as &dyn CollectionFamily | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `CollectionFamily` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit - --> $DIR/issue-78671.rs:8:10 + --> $DIR/issue-78671.rs:7:10 | LL | trait CollectionFamily { | ---------------- this trait cannot be made into an object... diff --git a/src/test/ui/generic-associated-types/issue-78671.extended.stderr b/src/test/ui/generic-associated-types/issue-78671.extended.stderr index f1b48933516f..6fa09a4c7e59 100644 --- a/src/test/ui/generic-associated-types/issue-78671.extended.stderr +++ b/src/test/ui/generic-associated-types/issue-78671.extended.stderr @@ -1,11 +1,11 @@ error[E0107]: missing generics for associated type `CollectionFamily::Member` - --> $DIR/issue-78671.rs:11:47 + --> $DIR/issue-78671.rs:10:47 | LL | Box::new(Family) as &dyn CollectionFamily | ^^^^^^ expected 1 generic argument | note: associated type defined here, with 1 generic parameter: `T` - --> $DIR/issue-78671.rs:8:10 + --> $DIR/issue-78671.rs:7:10 | LL | type Member; | ^^^^^^ - diff --git a/src/test/ui/generic-associated-types/issue-78671.rs b/src/test/ui/generic-associated-types/issue-78671.rs index c09dac28bda6..327b0c14ae86 100644 --- a/src/test/ui/generic-associated-types/issue-78671.rs +++ b/src/test/ui/generic-associated-types/issue-78671.rs @@ -1,6 +1,5 @@ // revisions: base extended -#![feature(generic_associated_types)] #![cfg_attr(extended, feature(generic_associated_types_extended))] #![cfg_attr(extended, allow(incomplete_features))] diff --git a/src/test/ui/generic-associated-types/issue-79422.base.stderr b/src/test/ui/generic-associated-types/issue-79422.base.stderr index 0ed75ba1efc2..3c1a29d48b2f 100644 --- a/src/test/ui/generic-associated-types/issue-79422.base.stderr +++ b/src/test/ui/generic-associated-types/issue-79422.base.stderr @@ -1,11 +1,11 @@ error[E0107]: missing generics for associated type `MapLike::VRefCont` - --> $DIR/issue-79422.rs:48:36 + --> $DIR/issue-79422.rs:47:36 | LL | as Box>>; | ^^^^^^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/issue-79422.rs:24:10 + --> $DIR/issue-79422.rs:23:10 | LL | type VRefCont<'a>: RefCont<'a, V> where Self: 'a; | ^^^^^^^^ -- @@ -15,13 +15,13 @@ LL | as Box = dyn RefCont<'_, u8>>>; | ~~~~~~~~~~~~ error[E0038]: the trait `MapLike` cannot be made into an object - --> $DIR/issue-79422.rs:48:12 + --> $DIR/issue-79422.rs:47:12 | LL | as Box>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit - --> $DIR/issue-79422.rs:24:10 + --> $DIR/issue-79422.rs:23:10 | LL | trait MapLike { | ------- this trait cannot be made into an object... @@ -30,13 +30,13 @@ LL | type VRefCont<'a>: RefCont<'a, V> where Self: 'a; = help: consider moving `VRefCont` to another trait error[E0038]: the trait `MapLike` cannot be made into an object - --> $DIR/issue-79422.rs:45:13 + --> $DIR/issue-79422.rs:44:13 | LL | let m = Box::new(std::collections::BTreeMap::::new()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit - --> $DIR/issue-79422.rs:24:10 + --> $DIR/issue-79422.rs:23:10 | LL | trait MapLike { | ------- this trait cannot be made into an object... diff --git a/src/test/ui/generic-associated-types/issue-79422.extended.stderr b/src/test/ui/generic-associated-types/issue-79422.extended.stderr index 9bcbd7471684..58c921bf09f6 100644 --- a/src/test/ui/generic-associated-types/issue-79422.extended.stderr +++ b/src/test/ui/generic-associated-types/issue-79422.extended.stderr @@ -1,11 +1,11 @@ error[E0107]: missing generics for associated type `MapLike::VRefCont` - --> $DIR/issue-79422.rs:48:36 + --> $DIR/issue-79422.rs:47:36 | LL | as Box>>; | ^^^^^^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/issue-79422.rs:24:10 + --> $DIR/issue-79422.rs:23:10 | LL | type VRefCont<'a>: RefCont<'a, V> where Self: 'a; | ^^^^^^^^ -- @@ -15,13 +15,13 @@ LL | as Box = dyn RefCont<'_, u8>>>; | ~~~~~~~~~~~~ error[E0271]: type mismatch resolving ` as MapLike>::VRefCont<'_> == (dyn RefCont<'_, u8> + 'static)` - --> $DIR/issue-79422.rs:45:13 + --> $DIR/issue-79422.rs:44:13 | LL | let m = Box::new(std::collections::BTreeMap::::new()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving ` as MapLike>::VRefCont<'_> == (dyn RefCont<'_, u8> + 'static)` | note: expected this to be `(dyn RefCont<'_, u8> + 'static)` - --> $DIR/issue-79422.rs:29:25 + --> $DIR/issue-79422.rs:28:25 | LL | type VRefCont<'a> = &'a V where Self: 'a; | ^^^^^ diff --git a/src/test/ui/generic-associated-types/issue-79422.rs b/src/test/ui/generic-associated-types/issue-79422.rs index 7749975e6872..a52dd792dda2 100644 --- a/src/test/ui/generic-associated-types/issue-79422.rs +++ b/src/test/ui/generic-associated-types/issue-79422.rs @@ -1,6 +1,5 @@ // revisions: base extended -#![feature(generic_associated_types)] #![cfg_attr(extended, feature(generic_associated_types_extended))] #![cfg_attr(extended, allow(incomplete_features))] diff --git a/src/test/ui/generic-associated-types/issue-79636-1.rs b/src/test/ui/generic-associated-types/issue-79636-1.rs index 6d73fd68dbed..a89039b5c720 100644 --- a/src/test/ui/generic-associated-types/issue-79636-1.rs +++ b/src/test/ui/generic-associated-types/issue-79636-1.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - trait Monad { type Unwrapped; type Wrapped; diff --git a/src/test/ui/generic-associated-types/issue-79636-1.stderr b/src/test/ui/generic-associated-types/issue-79636-1.stderr index 1ecb862827fd..155477048cad 100644 --- a/src/test/ui/generic-associated-types/issue-79636-1.stderr +++ b/src/test/ui/generic-associated-types/issue-79636-1.stderr @@ -1,11 +1,11 @@ error[E0107]: missing generics for associated type `Monad::Wrapped` - --> $DIR/issue-79636-1.rs:15:34 + --> $DIR/issue-79636-1.rs:13:34 | LL | MInner: Monad>, | ^^^^^^^ expected 1 generic argument | note: associated type defined here, with 1 generic parameter: `B` - --> $DIR/issue-79636-1.rs:5:10 + --> $DIR/issue-79636-1.rs:3:10 | LL | type Wrapped; | ^^^^^^^ - diff --git a/src/test/ui/generic-associated-types/issue-79636-2.rs b/src/test/ui/generic-associated-types/issue-79636-2.rs index cdaf2e483411..ff5ff38c968d 100644 --- a/src/test/ui/generic-associated-types/issue-79636-2.rs +++ b/src/test/ui/generic-associated-types/issue-79636-2.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - trait SomeTrait { type Wrapped: SomeTrait; diff --git a/src/test/ui/generic-associated-types/issue-79636-2.stderr b/src/test/ui/generic-associated-types/issue-79636-2.stderr index ae61b7b104e8..6a36bfc37f24 100644 --- a/src/test/ui/generic-associated-types/issue-79636-2.stderr +++ b/src/test/ui/generic-associated-types/issue-79636-2.stderr @@ -1,11 +1,11 @@ error[E0107]: missing generics for associated type `SomeTrait::Wrapped` - --> $DIR/issue-79636-2.rs:11:18 + --> $DIR/issue-79636-2.rs:9:18 | LL | W: SomeTrait, | ^^^^^^^ expected 1 generic argument | note: associated type defined here, with 1 generic parameter: `A` - --> $DIR/issue-79636-2.rs:4:10 + --> $DIR/issue-79636-2.rs:2:10 | LL | type Wrapped: SomeTrait; | ^^^^^^^ - diff --git a/src/test/ui/generic-associated-types/issue-80433-reduced.rs b/src/test/ui/generic-associated-types/issue-80433-reduced.rs index f15d4d8b1385..44831a995c66 100644 --- a/src/test/ui/generic-associated-types/issue-80433-reduced.rs +++ b/src/test/ui/generic-associated-types/issue-80433-reduced.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(generic_associated_types)] - struct E {} trait TestMut { diff --git a/src/test/ui/generic-associated-types/issue-80433.rs b/src/test/ui/generic-associated-types/issue-80433.rs index 6a1fe7519a84..05ff82fa7d5d 100644 --- a/src/test/ui/generic-associated-types/issue-80433.rs +++ b/src/test/ui/generic-associated-types/issue-80433.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - #[derive(Default)] struct E { data: T, diff --git a/src/test/ui/generic-associated-types/issue-80433.stderr b/src/test/ui/generic-associated-types/issue-80433.stderr index d8c210dcf7e9..20a407dd4125 100644 --- a/src/test/ui/generic-associated-types/issue-80433.stderr +++ b/src/test/ui/generic-associated-types/issue-80433.stderr @@ -1,11 +1,11 @@ error[E0107]: missing generics for associated type `TestMut::Output` - --> $DIR/issue-80433.rs:23:47 + --> $DIR/issue-80433.rs:21:47 | LL | fn test_simpler<'a>(dst: &'a mut impl TestMut) | ^^^^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/issue-80433.rs:9:10 + --> $DIR/issue-80433.rs:7:10 | LL | type Output<'a>; | ^^^^^^ -- diff --git a/src/test/ui/generic-associated-types/issue-81487.rs b/src/test/ui/generic-associated-types/issue-81487.rs index 7f399c4f9a2d..0d19a75bb7ff 100644 --- a/src/test/ui/generic-associated-types/issue-81487.rs +++ b/src/test/ui/generic-associated-types/issue-81487.rs @@ -1,7 +1,5 @@ // build-pass -#![feature(generic_associated_types)] - trait Trait { type Ref<'a>; } diff --git a/src/test/ui/generic-associated-types/issue-81712-cyclic-traits.rs b/src/test/ui/generic-associated-types/issue-81712-cyclic-traits.rs index fa2f86242257..a7cc9a6053e4 100644 --- a/src/test/ui/generic-associated-types/issue-81712-cyclic-traits.rs +++ b/src/test/ui/generic-associated-types/issue-81712-cyclic-traits.rs @@ -1,7 +1,5 @@ // Regression test for #81712. -#![feature(generic_associated_types)] - trait A { type BType: B; } diff --git a/src/test/ui/generic-associated-types/issue-81712-cyclic-traits.stderr b/src/test/ui/generic-associated-types/issue-81712-cyclic-traits.stderr index 86c99c32fc1a..c8961e28ede4 100644 --- a/src/test/ui/generic-associated-types/issue-81712-cyclic-traits.stderr +++ b/src/test/ui/generic-associated-types/issue-81712-cyclic-traits.stderr @@ -1,11 +1,11 @@ error[E0107]: missing generics for associated type `C::DType` - --> $DIR/issue-81712-cyclic-traits.rs:16:19 + --> $DIR/issue-81712-cyclic-traits.rs:14:19 | LL | type CType: C; | ^^^^^ expected 1 generic argument | note: associated type defined here, with 1 generic parameter: `T` - --> $DIR/issue-81712-cyclic-traits.rs:13:10 + --> $DIR/issue-81712-cyclic-traits.rs:11:10 | LL | type DType: D; | ^^^^^ - diff --git a/src/test/ui/generic-associated-types/issue-81862.rs b/src/test/ui/generic-associated-types/issue-81862.rs index e457bca0c096..bde828b775b5 100644 --- a/src/test/ui/generic-associated-types/issue-81862.rs +++ b/src/test/ui/generic-associated-types/issue-81862.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - trait StreamingIterator { type Item<'a>; fn next(&mut self) -> Option; diff --git a/src/test/ui/generic-associated-types/issue-81862.stderr b/src/test/ui/generic-associated-types/issue-81862.stderr index c664b3ee6683..ba798084673c 100644 --- a/src/test/ui/generic-associated-types/issue-81862.stderr +++ b/src/test/ui/generic-associated-types/issue-81862.stderr @@ -1,11 +1,11 @@ error[E0107]: missing generics for associated type `StreamingIterator::Item` - --> $DIR/issue-81862.rs:5:40 + --> $DIR/issue-81862.rs:3:40 | LL | fn next(&mut self) -> Option; | ^^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/issue-81862.rs:4:10 + --> $DIR/issue-81862.rs:2:10 | LL | type Item<'a>; | ^^^^ -- diff --git a/src/test/ui/generic-associated-types/issue-84931.rs b/src/test/ui/generic-associated-types/issue-84931.rs index 9e247de16320..4123ce9d4d94 100644 --- a/src/test/ui/generic-associated-types/issue-84931.rs +++ b/src/test/ui/generic-associated-types/issue-84931.rs @@ -1,4 +1,3 @@ -#![feature(generic_associated_types)] // check-fail trait StreamingIter { diff --git a/src/test/ui/generic-associated-types/issue-84931.stderr b/src/test/ui/generic-associated-types/issue-84931.stderr index 11c3dffde4b3..fffea98a449e 100644 --- a/src/test/ui/generic-associated-types/issue-84931.stderr +++ b/src/test/ui/generic-associated-types/issue-84931.stderr @@ -1,5 +1,5 @@ error[E0309]: the parameter type `T` may not live long enough - --> $DIR/issue-84931.rs:15:21 + --> $DIR/issue-84931.rs:14:21 | LL | type Item<'a> = &'a mut T; | ^^^^^^^^^- help: consider adding a where clause: `where T: 'a` diff --git a/src/test/ui/generic-associated-types/issue-85921.rs b/src/test/ui/generic-associated-types/issue-85921.rs index df59f497d784..d281ed9eedbc 100644 --- a/src/test/ui/generic-associated-types/issue-85921.rs +++ b/src/test/ui/generic-associated-types/issue-85921.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(generic_associated_types)] - trait Trait { type Assoc<'a>; diff --git a/src/test/ui/generic-associated-types/issue-86483.rs b/src/test/ui/generic-associated-types/issue-86483.rs index 07dd0bffd468..70267637ae9d 100644 --- a/src/test/ui/generic-associated-types/issue-86483.rs +++ b/src/test/ui/generic-associated-types/issue-86483.rs @@ -4,8 +4,6 @@ // // check-pass -#![feature(generic_associated_types)] - pub trait IceIce where for<'a> T: 'a, diff --git a/src/test/ui/generic-associated-types/issue-86787.rs b/src/test/ui/generic-associated-types/issue-86787.rs index 0f8096c8a7c1..96075ca503da 100644 --- a/src/test/ui/generic-associated-types/issue-86787.rs +++ b/src/test/ui/generic-associated-types/issue-86787.rs @@ -1,4 +1,3 @@ -#![feature(generic_associated_types)] // check-fail enum Either { diff --git a/src/test/ui/generic-associated-types/issue-86787.stderr b/src/test/ui/generic-associated-types/issue-86787.stderr index d4b2267d3ddc..f34c63cf72e1 100644 --- a/src/test/ui/generic-associated-types/issue-86787.stderr +++ b/src/test/ui/generic-associated-types/issue-86787.stderr @@ -1,5 +1,5 @@ error: missing required bound on `TRef` - --> $DIR/issue-86787.rs:11:5 + --> $DIR/issue-86787.rs:10:5 | LL | type TRef<'a>; | ^^^^^^^^^^^^^- diff --git a/src/test/ui/generic-associated-types/issue-87258_a.rs b/src/test/ui/generic-associated-types/issue-87258_a.rs index c65f3fb2aa0a..9ab683d3dc9e 100644 --- a/src/test/ui/generic-associated-types/issue-87258_a.rs +++ b/src/test/ui/generic-associated-types/issue-87258_a.rs @@ -1,5 +1,4 @@ #![feature(type_alias_impl_trait)] -#![feature(generic_associated_types)] // See https://github.com/rust-lang/rust/issues/87258#issuecomment-883293367 diff --git a/src/test/ui/generic-associated-types/issue-87258_a.stderr b/src/test/ui/generic-associated-types/issue-87258_a.stderr index db3a5c819cbf..fa0748a280b6 100644 --- a/src/test/ui/generic-associated-types/issue-87258_a.stderr +++ b/src/test/ui/generic-associated-types/issue-87258_a.stderr @@ -1,5 +1,5 @@ error: unconstrained opaque type - --> $DIR/issue-87258_a.rs:18:26 + --> $DIR/issue-87258_a.rs:17:26 | LL | type FooFuture<'a> = impl Trait1; | ^^^^^^^^^^^ diff --git a/src/test/ui/generic-associated-types/issue-87258_b.rs b/src/test/ui/generic-associated-types/issue-87258_b.rs index f59e0d766594..7b7610b21c7d 100644 --- a/src/test/ui/generic-associated-types/issue-87258_b.rs +++ b/src/test/ui/generic-associated-types/issue-87258_b.rs @@ -1,5 +1,4 @@ #![feature(type_alias_impl_trait)] -#![feature(generic_associated_types)] // See https://github.com/rust-lang/rust/issues/87258#issuecomment-883293367 diff --git a/src/test/ui/generic-associated-types/issue-87258_b.stderr b/src/test/ui/generic-associated-types/issue-87258_b.stderr index 9faccc96124b..0ee665f38ad0 100644 --- a/src/test/ui/generic-associated-types/issue-87258_b.stderr +++ b/src/test/ui/generic-associated-types/issue-87258_b.stderr @@ -1,5 +1,5 @@ error: unconstrained opaque type - --> $DIR/issue-87258_b.rs:17:49 + --> $DIR/issue-87258_b.rs:16:49 | LL | type Helper<'xenon, 'yttrium, KABOOM: Trait2> = impl Trait1; | ^^^^^^^^^^^ diff --git a/src/test/ui/generic-associated-types/issue-87429-2.rs b/src/test/ui/generic-associated-types/issue-87429-2.rs index d35bb098abdf..feb43ee5aa4a 100644 --- a/src/test/ui/generic-associated-types/issue-87429-2.rs +++ b/src/test/ui/generic-associated-types/issue-87429-2.rs @@ -4,8 +4,6 @@ // check-pass -#![feature(generic_associated_types)] - trait Family { type Member<'a, C: Eq>: for<'b> MyBound<'b, C>; } diff --git a/src/test/ui/generic-associated-types/issue-87429-associated-type-default.rs b/src/test/ui/generic-associated-types/issue-87429-associated-type-default.rs index 9ee07c2f1e1c..2006f9bc74df 100644 --- a/src/test/ui/generic-associated-types/issue-87429-associated-type-default.rs +++ b/src/test/ui/generic-associated-types/issue-87429-associated-type-default.rs @@ -1,7 +1,6 @@ // check-fail #![feature(associated_type_defaults)] -#![feature(generic_associated_types)] trait Family { // Fine, i32: PartialEq diff --git a/src/test/ui/generic-associated-types/issue-87429-associated-type-default.stderr b/src/test/ui/generic-associated-types/issue-87429-associated-type-default.stderr index c6fa02cb9a6b..b1abe012be23 100644 --- a/src/test/ui/generic-associated-types/issue-87429-associated-type-default.stderr +++ b/src/test/ui/generic-associated-types/issue-87429-associated-type-default.stderr @@ -1,12 +1,12 @@ error[E0277]: can't compare `Foo` with `Foo` - --> $DIR/issue-87429-associated-type-default.rs:14:60 + --> $DIR/issue-87429-associated-type-default.rs:13:60 | LL | type Member<'a>: for<'b> PartialEq> = Foo; | ^^^ no implementation for `Foo == Foo` | = help: the trait `PartialEq` is not implemented for `Foo` note: required by a bound in `Family2::Member` - --> $DIR/issue-87429-associated-type-default.rs:14:22 + --> $DIR/issue-87429-associated-type-default.rs:13:22 | LL | type Member<'a>: for<'b> PartialEq> = Foo; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Family2::Member` diff --git a/src/test/ui/generic-associated-types/issue-87429-specialization.rs b/src/test/ui/generic-associated-types/issue-87429-specialization.rs index b365e07feb28..6e31f1b21e5c 100644 --- a/src/test/ui/generic-associated-types/issue-87429-specialization.rs +++ b/src/test/ui/generic-associated-types/issue-87429-specialization.rs @@ -2,7 +2,6 @@ #![feature(specialization)] //~^ WARN incomplete -#![feature(generic_associated_types)] trait Family { type Member<'a>: for<'b> PartialEq>; diff --git a/src/test/ui/generic-associated-types/issue-87429-specialization.stderr b/src/test/ui/generic-associated-types/issue-87429-specialization.stderr index 015e0c7792fe..d8e889aecef7 100644 --- a/src/test/ui/generic-associated-types/issue-87429-specialization.stderr +++ b/src/test/ui/generic-associated-types/issue-87429-specialization.stderr @@ -9,14 +9,14 @@ LL | #![feature(specialization)] = help: consider using `min_specialization` instead, which is more stable and complete error[E0277]: can't compare `Foo` with `Foo` - --> $DIR/issue-87429-specialization.rs:21:31 + --> $DIR/issue-87429-specialization.rs:20:31 | LL | default type Member<'a> = Foo; | ^^^ no implementation for `Foo == Foo` | = help: the trait `PartialEq` is not implemented for `Foo` note: required by a bound in `Family::Member` - --> $DIR/issue-87429-specialization.rs:8:22 + --> $DIR/issue-87429-specialization.rs:7:22 | LL | type Member<'a>: for<'b> PartialEq>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Family::Member` diff --git a/src/test/ui/generic-associated-types/issue-87429.rs b/src/test/ui/generic-associated-types/issue-87429.rs index f905348ae32a..56394823cc51 100644 --- a/src/test/ui/generic-associated-types/issue-87429.rs +++ b/src/test/ui/generic-associated-types/issue-87429.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(generic_associated_types)] - trait Family { type Member<'a>: for<'b> PartialEq>; } diff --git a/src/test/ui/generic-associated-types/issue-87748.rs b/src/test/ui/generic-associated-types/issue-87748.rs index 1a1ab9bf8a4e..6cbe3d902233 100644 --- a/src/test/ui/generic-associated-types/issue-87748.rs +++ b/src/test/ui/generic-associated-types/issue-87748.rs @@ -3,8 +3,6 @@ // check-pass -#![feature(generic_associated_types)] - trait MyTrait { type Assoc<'a, 'b> where 'b: 'a; fn do_sth(arg: Self::Assoc<'_, '_>); diff --git a/src/test/ui/generic-associated-types/issue-87750.rs b/src/test/ui/generic-associated-types/issue-87750.rs index 89bd79ac2991..0a11a0f3ae0e 100644 --- a/src/test/ui/generic-associated-types/issue-87750.rs +++ b/src/test/ui/generic-associated-types/issue-87750.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - trait PointerFamily { type Pointer; } diff --git a/src/test/ui/generic-associated-types/issue-87750.stderr b/src/test/ui/generic-associated-types/issue-87750.stderr index 854541f3d8fd..b358ca273ca7 100644 --- a/src/test/ui/generic-associated-types/issue-87750.stderr +++ b/src/test/ui/generic-associated-types/issue-87750.stderr @@ -1,5 +1,5 @@ error[E0275]: overflow evaluating the requirement `Node: Sized` - --> $DIR/issue-87750.rs:20:16 + --> $DIR/issue-87750.rs:18:16 | LL | let _list: ::Pointer>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/generic-associated-types/issue-88287.rs b/src/test/ui/generic-associated-types/issue-88287.rs index 4952a082586d..82188493d52b 100644 --- a/src/test/ui/generic-associated-types/issue-88287.rs +++ b/src/test/ui/generic-associated-types/issue-88287.rs @@ -1,6 +1,5 @@ // edition:2018 -#![feature(generic_associated_types)] #![feature(type_alias_impl_trait)] use std::future::Future; diff --git a/src/test/ui/generic-associated-types/issue-88287.stderr b/src/test/ui/generic-associated-types/issue-88287.stderr index 5241d85a5f96..1b84cce62292 100644 --- a/src/test/ui/generic-associated-types/issue-88287.stderr +++ b/src/test/ui/generic-associated-types/issue-88287.stderr @@ -1,5 +1,5 @@ error[E0277]: the size for values of type `A` cannot be known at compilation time - --> $DIR/issue-88287.rs:35:9 + --> $DIR/issue-88287.rs:34:9 | LL | type SearchFutureTy<'f, A, B: 'f> | - this type parameter needs to be `std::marker::Sized` @@ -8,7 +8,7 @@ LL | async move { todo!() } | ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | note: required by a bound in `>` - --> $DIR/issue-88287.rs:25:6 + --> $DIR/issue-88287.rs:24:6 | LL | impl SearchableResourceExt for T | ^ required by this bound in `>` diff --git a/src/test/ui/generic-associated-types/issue-88360.rs b/src/test/ui/generic-associated-types/issue-88360.rs index 8ee98201aba7..c02690618d0e 100644 --- a/src/test/ui/generic-associated-types/issue-88360.rs +++ b/src/test/ui/generic-associated-types/issue-88360.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - trait GatTrait { type Gat<'a> where Self: 'a; diff --git a/src/test/ui/generic-associated-types/issue-88360.stderr b/src/test/ui/generic-associated-types/issue-88360.stderr index 5f769d799faa..cd3750344dda 100644 --- a/src/test/ui/generic-associated-types/issue-88360.stderr +++ b/src/test/ui/generic-associated-types/issue-88360.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-88360.rs:15:9 + --> $DIR/issue-88360.rs:13:9 | LL | trait SuperTrait | - this type parameter diff --git a/src/test/ui/generic-associated-types/issue-88405.rs b/src/test/ui/generic-associated-types/issue-88405.rs index 4a405bd3625c..8dad6a89fd05 100644 --- a/src/test/ui/generic-associated-types/issue-88405.rs +++ b/src/test/ui/generic-associated-types/issue-88405.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(generic_associated_types)] - trait SomeTrait {} trait OtherTrait { type Item; diff --git a/src/test/ui/generic-associated-types/issue-88459.rs b/src/test/ui/generic-associated-types/issue-88459.rs index 3b26a180152c..07d7bc06d08e 100644 --- a/src/test/ui/generic-associated-types/issue-88459.rs +++ b/src/test/ui/generic-associated-types/issue-88459.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(generic_associated_types)] - trait Trait { type Assoc<'a>; } diff --git a/src/test/ui/generic-associated-types/issue-88595.rs b/src/test/ui/generic-associated-types/issue-88595.rs index e0796dfecbbc..24641ee1f781 100644 --- a/src/test/ui/generic-associated-types/issue-88595.rs +++ b/src/test/ui/generic-associated-types/issue-88595.rs @@ -1,4 +1,3 @@ -#![feature(generic_associated_types)] #![feature(type_alias_impl_trait)] fn main() {} diff --git a/src/test/ui/generic-associated-types/issue-88595.stderr b/src/test/ui/generic-associated-types/issue-88595.stderr index 79d3479af8c8..bcefc8066851 100644 --- a/src/test/ui/generic-associated-types/issue-88595.stderr +++ b/src/test/ui/generic-associated-types/issue-88595.stderr @@ -1,11 +1,11 @@ error: non-defining opaque type use in defining scope - --> $DIR/issue-88595.rs:21:35 + --> $DIR/issue-88595.rs:20:35 | LL | fn a(&'a self) -> Self::B<'a> {} | ^^ | note: lifetime used multiple times - --> $DIR/issue-88595.rs:18:6 + --> $DIR/issue-88595.rs:17:6 | LL | impl<'a> A<'a> for C { | ^^ diff --git a/src/test/ui/generic-associated-types/issue-89352.rs b/src/test/ui/generic-associated-types/issue-89352.rs index d9c656d5f58a..1896d0c87f4c 100644 --- a/src/test/ui/generic-associated-types/issue-89352.rs +++ b/src/test/ui/generic-associated-types/issue-89352.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(generic_associated_types)] - use std::marker::PhantomData; pub trait GenAssoc { diff --git a/src/test/ui/generic-associated-types/issue-90014.rs b/src/test/ui/generic-associated-types/issue-90014.rs index f110b069383d..55db95a6d819 100644 --- a/src/test/ui/generic-associated-types/issue-90014.rs +++ b/src/test/ui/generic-associated-types/issue-90014.rs @@ -1,6 +1,5 @@ // edition:2018 -#![feature(generic_associated_types)] #![feature(type_alias_impl_trait)] use std::future::Future; diff --git a/src/test/ui/generic-associated-types/issue-90014.stderr b/src/test/ui/generic-associated-types/issue-90014.stderr index 457c582e8c8d..2d3f4a6af7e0 100644 --- a/src/test/ui/generic-associated-types/issue-90014.stderr +++ b/src/test/ui/generic-associated-types/issue-90014.stderr @@ -1,5 +1,5 @@ error[E0477]: the type `&mut ()` does not fulfill the required lifetime - --> $DIR/issue-90014.rs:14:20 + --> $DIR/issue-90014.rs:13:20 | LL | type Fut<'a> where Self: 'a; | ------------ definition of `Fut` from trait @@ -8,7 +8,7 @@ LL | type Fut<'a> = impl Future; | ^^^^^^^^^^^^^^^^^^^^^^^^- help: try copying this clause from the trait: `where Self: 'a` | note: type must outlive the lifetime `'a` as defined here - --> $DIR/issue-90014.rs:14:14 + --> $DIR/issue-90014.rs:13:14 | LL | type Fut<'a> = impl Future; | ^^ diff --git a/src/test/ui/generic-associated-types/issue-90729.rs b/src/test/ui/generic-associated-types/issue-90729.rs index 98295cce8d58..bcec2e32121d 100644 --- a/src/test/ui/generic-associated-types/issue-90729.rs +++ b/src/test/ui/generic-associated-types/issue-90729.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(generic_associated_types)] - use std::marker::PhantomData; pub trait Type { diff --git a/src/test/ui/generic-associated-types/issue-91139.migrate.stderr b/src/test/ui/generic-associated-types/issue-91139.migrate.stderr index b424d9a2fdb0..690160577cd9 100644 --- a/src/test/ui/generic-associated-types/issue-91139.migrate.stderr +++ b/src/test/ui/generic-associated-types/issue-91139.migrate.stderr @@ -1,13 +1,8 @@ -error[E0311]: the parameter type `T` may not live long enough - --> $DIR/issue-91139.rs:27:12 +error: expected identifier, found `<<` + --> $DIR/issue-91139.rs:1:1 | -LL | let _: for<'a> fn(<() as Foo>::Type<'a>, &'a T) = |_, _| (); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds - | -help: consider adding an explicit lifetime bound... - | -LL | fn foo() { - | ++++ +LL | <<<<<<< HEAD + | ^^ expected identifier error: aborting due to previous error diff --git a/src/test/ui/generic-associated-types/issue-91139.rs b/src/test/ui/generic-associated-types/issue-91139.rs index 40eef11f058e..5fc6071c9396 100644 --- a/src/test/ui/generic-associated-types/issue-91139.rs +++ b/src/test/ui/generic-associated-types/issue-91139.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - trait Foo { type Type<'a> where diff --git a/src/test/ui/generic-associated-types/issue-91139.stderr b/src/test/ui/generic-associated-types/issue-91139.stderr index b789b3a42f33..8bbe98fa1e50 100644 --- a/src/test/ui/generic-associated-types/issue-91139.stderr +++ b/src/test/ui/generic-associated-types/issue-91139.stderr @@ -1,41 +1,41 @@ error: `T` does not live long enough - --> $DIR/issue-91139.rs:16:12 + --> $DIR/issue-91139.rs:14:12 | LL | let _: for<'a> fn(<() as Foo>::Type<'a>, &'a T) = |_, _| (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `T` does not live long enough - --> $DIR/issue-91139.rs:16:12 + --> $DIR/issue-91139.rs:14:12 | LL | let _: for<'a> fn(<() as Foo>::Type<'a>, &'a T) = |_, _| (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `T` does not live long enough - --> $DIR/issue-91139.rs:16:12 + --> $DIR/issue-91139.rs:14:12 | LL | let _: for<'a> fn(<() as Foo>::Type<'a>, &'a T) = |_, _| (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `T` does not live long enough - --> $DIR/issue-91139.rs:16:12 + --> $DIR/issue-91139.rs:14:12 | LL | let _: for<'a> fn(<() as Foo>::Type<'a>, &'a T) = |_, _| (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `T` does not live long enough - --> $DIR/issue-91139.rs:16:58 + --> $DIR/issue-91139.rs:14:58 | LL | let _: for<'a> fn(<() as Foo>::Type<'a>, &'a T) = |_, _| (); | ^^^^^^^^^ error: `T` does not live long enough - --> $DIR/issue-91139.rs:16:58 + --> $DIR/issue-91139.rs:14:58 | LL | let _: for<'a> fn(<() as Foo>::Type<'a>, &'a T) = |_, _| (); | ^^^^^^^^^ error[E0310]: the parameter type `T` may not live long enough - --> $DIR/issue-91139.rs:16:58 + --> $DIR/issue-91139.rs:14:58 | LL | let _: for<'a> fn(<() as Foo>::Type<'a>, &'a T) = |_, _| (); | ^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds @@ -46,13 +46,13 @@ LL | fn foo() { | +++++++++ error: `T` does not live long enough - --> $DIR/issue-91139.rs:16:58 + --> $DIR/issue-91139.rs:14:58 | LL | let _: for<'a> fn(<() as Foo>::Type<'a>, &'a T) = |_, _| (); | ^^^^^^^^^ error: `T` does not live long enough - --> $DIR/issue-91139.rs:16:58 + --> $DIR/issue-91139.rs:14:58 | LL | let _: for<'a> fn(<() as Foo>::Type<'a>, &'a T) = |_, _| (); | ^^^^^^^^^ diff --git a/src/test/ui/generic-associated-types/issue-91883.rs b/src/test/ui/generic-associated-types/issue-91883.rs index 3d4585a44df8..e870e08a3a2b 100644 --- a/src/test/ui/generic-associated-types/issue-91883.rs +++ b/src/test/ui/generic-associated-types/issue-91883.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - use std::fmt::Debug; use std::marker::PhantomData; diff --git a/src/test/ui/generic-associated-types/issue-91883.stderr b/src/test/ui/generic-associated-types/issue-91883.stderr index baf4889cc1dd..1cfc2aaf1613 100644 --- a/src/test/ui/generic-associated-types/issue-91883.stderr +++ b/src/test/ui/generic-associated-types/issue-91883.stderr @@ -1,5 +1,5 @@ error[E0478]: lifetime bound not satisfied - --> $DIR/issue-91883.rs:32:24 + --> $DIR/issue-91883.rs:30:24 | LL | type Cursor<'tx>: Cursor<'tx> | ----------------------------- definition of `Cursor` from trait @@ -8,12 +8,12 @@ LL | type Cursor<'tx> = CursorImpl<'tx>; | ^^^^^^^^^^^^^^^- help: try copying these clauses from the trait: `where 'db: 'tx, Self: 'tx` | note: lifetime parameter instantiated with the lifetime `'db` as defined here - --> $DIR/issue-91883.rs:31:6 + --> $DIR/issue-91883.rs:29:6 | LL | impl<'db> Transaction<'db> for TransactionImpl<'db> { | ^^^ note: but lifetime parameter must outlive the lifetime `'tx` as defined here - --> $DIR/issue-91883.rs:32:17 + --> $DIR/issue-91883.rs:30:17 | LL | type Cursor<'tx> = CursorImpl<'tx>; | ^^^ diff --git a/src/test/ui/generic-associated-types/issue-92033.rs b/src/test/ui/generic-associated-types/issue-92033.rs index 1d5f7d5c0099..d111580b860a 100644 --- a/src/test/ui/generic-associated-types/issue-92033.rs +++ b/src/test/ui/generic-associated-types/issue-92033.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - struct Texture; trait Surface { diff --git a/src/test/ui/generic-associated-types/issue-92033.stderr b/src/test/ui/generic-associated-types/issue-92033.stderr index 6dd901027d7b..cd7eed25421e 100644 --- a/src/test/ui/generic-associated-types/issue-92033.stderr +++ b/src/test/ui/generic-associated-types/issue-92033.stderr @@ -1,5 +1,5 @@ error[E0477]: the type `&'s Texture` does not fulfill the required lifetime - --> $DIR/issue-92033.rs:22:28 + --> $DIR/issue-92033.rs:20:28 | LL | type TextureIter<'a>: Iterator | -------------------------------------------------- definition of `TextureIter` from trait @@ -8,7 +8,7 @@ LL | type TextureIter<'a> = std::option::IntoIter<&'a Texture>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try copying this clause from the trait: `where Self: 'a` | note: type must outlive the lifetime `'a` as defined here - --> $DIR/issue-92033.rs:22:22 + --> $DIR/issue-92033.rs:20:22 | LL | type TextureIter<'a> = std::option::IntoIter<&'a Texture>; | ^^ diff --git a/src/test/ui/generic-associated-types/issue-92096.migrate.stderr b/src/test/ui/generic-associated-types/issue-92096.migrate.stderr index c74161cd3e05..ce1fd6dd9831 100644 --- a/src/test/ui/generic-associated-types/issue-92096.migrate.stderr +++ b/src/test/ui/generic-associated-types/issue-92096.migrate.stderr @@ -1,5 +1,5 @@ error[E0311]: the parameter type `C` may not live long enough - --> $DIR/issue-92096.rs:20:33 + --> $DIR/issue-92096.rs:19:33 | LL | fn call_connect(c: &'_ C) -> impl '_ + Future + Send | ^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds @@ -10,7 +10,7 @@ LL | C: Client + Send + Sync + 'a, | ++++ error[E0311]: the parameter type `C` may not live long enough - --> $DIR/issue-92096.rs:20:33 + --> $DIR/issue-92096.rs:19:33 | LL | fn call_connect(c: &'_ C) -> impl '_ + Future + Send | ^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds diff --git a/src/test/ui/generic-associated-types/issue-92096.rs b/src/test/ui/generic-associated-types/issue-92096.rs index 377b8164ad50..e285af6660ec 100644 --- a/src/test/ui/generic-associated-types/issue-92096.rs +++ b/src/test/ui/generic-associated-types/issue-92096.rs @@ -1,7 +1,5 @@ // edition:2018 -#![feature(generic_associated_types)] - use std::future::Future; trait Client { diff --git a/src/test/ui/generic-associated-types/issue-92096.stderr b/src/test/ui/generic-associated-types/issue-92096.stderr index ca61a0f435e9..91a06d5acde1 100644 --- a/src/test/ui/generic-associated-types/issue-92096.stderr +++ b/src/test/ui/generic-associated-types/issue-92096.stderr @@ -1,5 +1,5 @@ error: `C` does not live long enough - --> $DIR/issue-92096.rs:19:5 + --> $DIR/issue-92096.rs:17:5 | LL | async move { c.connect().await } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/generic-associated-types/issue-92280.rs b/src/test/ui/generic-associated-types/issue-92280.rs index 81d000f1076c..9284beea33e5 100644 --- a/src/test/ui/generic-associated-types/issue-92280.rs +++ b/src/test/ui/generic-associated-types/issue-92280.rs @@ -1,6 +1,5 @@ // check-pass -#![feature(generic_associated_types)] #![allow(non_camel_case_types)] trait HasAssoc { diff --git a/src/test/ui/generic-associated-types/issue-92954.rs b/src/test/ui/generic-associated-types/issue-92954.rs index 95c090ff4e90..22ce8f9fe3b8 100644 --- a/src/test/ui/generic-associated-types/issue-92954.rs +++ b/src/test/ui/generic-associated-types/issue-92954.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(generic_associated_types)] - pub trait Foo { type Assoc<'c>; fn function() -> for<'x> fn(Self::Assoc<'x>); diff --git a/src/test/ui/generic-associated-types/issue-93141.rs b/src/test/ui/generic-associated-types/issue-93141.rs index 39ca77d13db9..48c78b9c0676 100644 --- a/src/test/ui/generic-associated-types/issue-93141.rs +++ b/src/test/ui/generic-associated-types/issue-93141.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(generic_associated_types)] - pub trait Fooey: Sized { type Context<'c> where Self: 'c; } diff --git a/src/test/ui/generic-associated-types/issue-93262.rs b/src/test/ui/generic-associated-types/issue-93262.rs index adc6aa8fa1af..a7bcd111dfff 100644 --- a/src/test/ui/generic-associated-types/issue-93262.rs +++ b/src/test/ui/generic-associated-types/issue-93262.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(generic_associated_types)] - pub trait Trait { type Assoc<'a> where Self: 'a; } diff --git a/src/test/ui/generic-associated-types/issue-93340.rs b/src/test/ui/generic-associated-types/issue-93340.rs index d065bde88c41..4662fda537b5 100644 --- a/src/test/ui/generic-associated-types/issue-93340.rs +++ b/src/test/ui/generic-associated-types/issue-93340.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(generic_associated_types)] - pub trait Scalar: 'static { type RefType<'a>: ScalarRef<'a>; } diff --git a/src/test/ui/generic-associated-types/issue-93341.rs b/src/test/ui/generic-associated-types/issue-93341.rs index e96a768ecda8..737b2bbdb245 100644 --- a/src/test/ui/generic-associated-types/issue-93341.rs +++ b/src/test/ui/generic-associated-types/issue-93341.rs @@ -1,6 +1,5 @@ // check-pass -#![feature(generic_associated_types)] use std::marker::PhantomData; pub struct Id<'id>(PhantomData &'id ()>); diff --git a/src/test/ui/generic-associated-types/issue-93342.rs b/src/test/ui/generic-associated-types/issue-93342.rs index d8d7adac9516..d4422d5d1d72 100644 --- a/src/test/ui/generic-associated-types/issue-93342.rs +++ b/src/test/ui/generic-associated-types/issue-93342.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(generic_associated_types)] - use std::marker::PhantomData; pub trait Scalar: 'static { diff --git a/src/test/ui/generic-associated-types/issue-93874.rs b/src/test/ui/generic-associated-types/issue-93874.rs index f403d75167d8..30956655ad40 100644 --- a/src/test/ui/generic-associated-types/issue-93874.rs +++ b/src/test/ui/generic-associated-types/issue-93874.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(generic_associated_types)] - pub trait Build { type Output; fn build(self, input: O) -> Self::Output; diff --git a/src/test/ui/generic-associated-types/issue-95305.rs b/src/test/ui/generic-associated-types/issue-95305.rs index e2f1710fa281..6c3ec20e7a05 100644 --- a/src/test/ui/generic-associated-types/issue-95305.rs +++ b/src/test/ui/generic-associated-types/issue-95305.rs @@ -2,7 +2,6 @@ // Forbid it for now but proper support might be added // at some point in the future. -#![feature(generic_associated_types)] #![feature(anonymous_lifetime_in_impl_trait)] trait Foo { type Item<'a>; diff --git a/src/test/ui/generic-associated-types/issue-95305.stderr b/src/test/ui/generic-associated-types/issue-95305.stderr index d8557525f54e..eb15cbc620ac 100644 --- a/src/test/ui/generic-associated-types/issue-95305.stderr +++ b/src/test/ui/generic-associated-types/issue-95305.stderr @@ -1,5 +1,5 @@ error[E0637]: `'_` cannot be used here - --> $DIR/issue-95305.rs:11:26 + --> $DIR/issue-95305.rs:10:26 | LL | fn foo(x: &impl Foo = u32>) { } | ^^ `'_` is a reserved lifetime name diff --git a/src/test/ui/generic-associated-types/iterable.rs b/src/test/ui/generic-associated-types/iterable.rs index af0049891b69..8ad351bd343c 100644 --- a/src/test/ui/generic-associated-types/iterable.rs +++ b/src/test/ui/generic-associated-types/iterable.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - // run-pass trait Iterable { diff --git a/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.rs b/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.rs index 655abd18da1c..36974b3df5e6 100644 --- a/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.rs +++ b/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.rs @@ -1,8 +1,6 @@ // Test that the predicate printed in an unresolved method error prints the // generics for a generic associated type. -#![feature(generic_associated_types)] - trait X { type Y; } diff --git a/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr b/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr index d9dc77ac8eb4..baef38f6b804 100644 --- a/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr +++ b/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr @@ -1,5 +1,5 @@ error[E0599]: the method `f` exists for struct `S`, but its trait bounds were not satisfied - --> $DIR/method-unsatified-assoc-type-predicate.rs:30:7 + --> $DIR/method-unsatified-assoc-type-predicate.rs:28:7 | LL | struct S; | -------- @@ -12,7 +12,7 @@ LL | a.f(); | ^ method cannot be called on `S` due to unsatisfied trait bounds | note: trait bound `::Y = i32` was not satisfied - --> $DIR/method-unsatified-assoc-type-predicate.rs:14:11 + --> $DIR/method-unsatified-assoc-type-predicate.rs:12:11 | LL | impl = i32>> M for T {} | ^^^^^^^^^^^^ - - diff --git a/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs index 8171dc0ae28d..de9cad308014 100644 --- a/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs +++ b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs @@ -1,7 +1,5 @@ // check-fail -#![feature(generic_associated_types)] - trait Foo { type Assoc<'a, 'b>; } diff --git a/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr index edd1f9367d12..ffdba6676bf8 100644 --- a/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr +++ b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr @@ -1,5 +1,5 @@ error[E0276]: impl has stricter requirements than trait - --> $DIR/missing-where-clause-on-trait.rs:9:39 + --> $DIR/missing-where-clause-on-trait.rs:7:39 | LL | type Assoc<'a, 'b>; | ------------------ definition of `Assoc` from trait diff --git a/src/test/ui/generic-associated-types/missing_lifetime_args.rs b/src/test/ui/generic-associated-types/missing_lifetime_args.rs index cd918157f7c8..78def80925ad 100644 --- a/src/test/ui/generic-associated-types/missing_lifetime_args.rs +++ b/src/test/ui/generic-associated-types/missing_lifetime_args.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - trait X { type Y<'a, 'b>; } diff --git a/src/test/ui/generic-associated-types/missing_lifetime_args.stderr b/src/test/ui/generic-associated-types/missing_lifetime_args.stderr index 7cf3f4b737e0..0ad1f1f8c4d3 100644 --- a/src/test/ui/generic-associated-types/missing_lifetime_args.stderr +++ b/src/test/ui/generic-associated-types/missing_lifetime_args.stderr @@ -1,11 +1,11 @@ error[E0107]: missing generics for associated type `X::Y` - --> $DIR/missing_lifetime_args.rs:13:32 + --> $DIR/missing_lifetime_args.rs:11:32 | LL | fn foo<'c, 'd>(_arg: Box>) {} | ^ expected 2 lifetime arguments | note: associated type defined here, with 2 lifetime parameters: `'a`, `'b` - --> $DIR/missing_lifetime_args.rs:4:10 + --> $DIR/missing_lifetime_args.rs:2:10 | LL | type Y<'a, 'b>; | ^ -- -- @@ -15,7 +15,7 @@ LL | fn foo<'c, 'd>(_arg: Box = (&'c u32, &'d u32)>>) {} | ~~~~~~~~~ error[E0107]: this struct takes 3 lifetime arguments but 2 lifetime arguments were supplied - --> $DIR/missing_lifetime_args.rs:16:26 + --> $DIR/missing_lifetime_args.rs:14:26 | LL | fn bar<'a, 'b, 'c>(_arg: Foo<'a, 'b>) {} | ^^^ -- -- supplied 2 lifetime arguments @@ -23,7 +23,7 @@ LL | fn bar<'a, 'b, 'c>(_arg: Foo<'a, 'b>) {} | expected 3 lifetime arguments | note: struct defined here, with 3 lifetime parameters: `'a`, `'b`, `'c` - --> $DIR/missing_lifetime_args.rs:7:8 + --> $DIR/missing_lifetime_args.rs:5:8 | LL | struct Foo<'a, 'b, 'c> { | ^^^ -- -- -- @@ -33,7 +33,7 @@ LL | fn bar<'a, 'b, 'c>(_arg: Foo<'a, 'b, 'a>) {} | ++++ error[E0107]: this struct takes 3 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing_lifetime_args.rs:19:16 + --> $DIR/missing_lifetime_args.rs:17:16 | LL | fn f<'a>(_arg: Foo<'a>) {} | ^^^ -- supplied 1 lifetime argument @@ -41,7 +41,7 @@ LL | fn f<'a>(_arg: Foo<'a>) {} | expected 3 lifetime arguments | note: struct defined here, with 3 lifetime parameters: `'a`, `'b`, `'c` - --> $DIR/missing_lifetime_args.rs:7:8 + --> $DIR/missing_lifetime_args.rs:5:8 | LL | struct Foo<'a, 'b, 'c> { | ^^^ -- -- -- diff --git a/src/test/ui/generic-associated-types/missing_lifetime_const.rs b/src/test/ui/generic-associated-types/missing_lifetime_const.rs index e3e78dd96f62..8b174b9e971e 100644 --- a/src/test/ui/generic-associated-types/missing_lifetime_const.rs +++ b/src/test/ui/generic-associated-types/missing_lifetime_const.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - trait Foo { type Assoc<'a, const N: usize>; } diff --git a/src/test/ui/generic-associated-types/missing_lifetime_const.stderr b/src/test/ui/generic-associated-types/missing_lifetime_const.stderr index 5d50637bd013..62d2e9f49dde 100644 --- a/src/test/ui/generic-associated-types/missing_lifetime_const.stderr +++ b/src/test/ui/generic-associated-types/missing_lifetime_const.stderr @@ -1,11 +1,11 @@ error[E0107]: this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied - --> $DIR/missing_lifetime_const.rs:8:24 + --> $DIR/missing_lifetime_const.rs:6:24 | LL | let _: ::Assoc<3>; | ^^^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/missing_lifetime_const.rs:4:10 + --> $DIR/missing_lifetime_const.rs:2:10 | LL | type Assoc<'a, const N: usize>; | ^^^^^ -- diff --git a/src/test/ui/generic-associated-types/parameter_number_and_kind.rs b/src/test/ui/generic-associated-types/parameter_number_and_kind.rs index 0508cc2daeae..8428e7763fb4 100644 --- a/src/test/ui/generic-associated-types/parameter_number_and_kind.rs +++ b/src/test/ui/generic-associated-types/parameter_number_and_kind.rs @@ -1,4 +1,3 @@ -#![feature(generic_associated_types)] #![feature(associated_type_defaults)] trait Foo { diff --git a/src/test/ui/generic-associated-types/parameter_number_and_kind.stderr b/src/test/ui/generic-associated-types/parameter_number_and_kind.stderr index 53d76fd22012..c20b9669e814 100644 --- a/src/test/ui/generic-associated-types/parameter_number_and_kind.stderr +++ b/src/test/ui/generic-associated-types/parameter_number_and_kind.stderr @@ -1,5 +1,5 @@ error[E0107]: this associated type takes 1 lifetime argument but 2 lifetime arguments were supplied - --> $DIR/parameter_number_and_kind.rs:12:24 + --> $DIR/parameter_number_and_kind.rs:11:24 | LL | type FErr1 = Self::E<'static, 'static>; | ^ ------- help: remove this lifetime argument @@ -7,19 +7,19 @@ LL | type FErr1 = Self::E<'static, 'static>; | expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/parameter_number_and_kind.rs:9:10 + --> $DIR/parameter_number_and_kind.rs:8:10 | LL | type E<'a, T>; | ^ -- error[E0107]: this associated type takes 1 generic argument but 0 generic arguments were supplied - --> $DIR/parameter_number_and_kind.rs:12:24 + --> $DIR/parameter_number_and_kind.rs:11:24 | LL | type FErr1 = Self::E<'static, 'static>; | ^ expected 1 generic argument | note: associated type defined here, with 1 generic parameter: `T` - --> $DIR/parameter_number_and_kind.rs:9:10 + --> $DIR/parameter_number_and_kind.rs:8:10 | LL | type E<'a, T>; | ^ - @@ -29,7 +29,7 @@ LL | type FErr1 = Self::E<'static, 'static, T>; | +++ error[E0107]: this associated type takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/parameter_number_and_kind.rs:15:27 + --> $DIR/parameter_number_and_kind.rs:14:27 | LL | type FErr2 = Self::E<'static, T, u32>; | ^ --- help: remove this generic argument @@ -37,7 +37,7 @@ LL | type FErr2 = Self::E<'static, T, u32>; | expected 1 generic argument | note: associated type defined here, with 1 generic parameter: `T` - --> $DIR/parameter_number_and_kind.rs:9:10 + --> $DIR/parameter_number_and_kind.rs:8:10 | LL | type E<'a, T>; | ^ - diff --git a/src/test/ui/generic-associated-types/parameter_number_and_kind_impl.rs b/src/test/ui/generic-associated-types/parameter_number_and_kind_impl.rs index 6ca0bc6ddbc9..c1381025ac2a 100644 --- a/src/test/ui/generic-associated-types/parameter_number_and_kind_impl.rs +++ b/src/test/ui/generic-associated-types/parameter_number_and_kind_impl.rs @@ -1,4 +1,3 @@ -#![feature(generic_associated_types)] #![feature(associated_type_defaults)] // FIXME(#44265) add tests for type-generic and const-genertic associated types. diff --git a/src/test/ui/generic-associated-types/parameter_number_and_kind_impl.stderr b/src/test/ui/generic-associated-types/parameter_number_and_kind_impl.stderr index 1458bf0c4a49..fdd6d305ab27 100644 --- a/src/test/ui/generic-associated-types/parameter_number_and_kind_impl.stderr +++ b/src/test/ui/generic-associated-types/parameter_number_and_kind_impl.stderr @@ -1,5 +1,5 @@ error[E0195]: lifetime parameters or bounds on type `A` do not match the trait declaration - --> $DIR/parameter_number_and_kind_impl.rs:15:11 + --> $DIR/parameter_number_and_kind_impl.rs:14:11 | LL | type A<'a>; | ---- lifetimes in impl do not match this type in trait @@ -8,7 +8,7 @@ LL | type A = u32; | ^ lifetimes do not match type in trait error[E0049]: type `B` has 1 type parameter but its trait declaration has 0 type parameters - --> $DIR/parameter_number_and_kind_impl.rs:17:12 + --> $DIR/parameter_number_and_kind_impl.rs:16:12 | LL | type B<'a, 'b>; | -- -- @@ -21,7 +21,7 @@ LL | type B<'a, T> = Vec; | found 1 type parameter error[E0195]: lifetime parameters or bounds on type `C` do not match the trait declaration - --> $DIR/parameter_number_and_kind_impl.rs:19:11 + --> $DIR/parameter_number_and_kind_impl.rs:18:11 | LL | type C; | - lifetimes in impl do not match this type in trait @@ -30,7 +30,7 @@ LL | type C<'a> = u32; | ^^^^ lifetimes do not match type in trait error[E0049]: type `A` has 1 type parameter but its trait declaration has 0 type parameters - --> $DIR/parameter_number_and_kind_impl.rs:26:12 + --> $DIR/parameter_number_and_kind_impl.rs:25:12 | LL | type A<'a>; | -- expected 0 type parameters @@ -39,7 +39,7 @@ LL | type A = u32; | ^ found 1 type parameter error[E0195]: lifetime parameters or bounds on type `B` do not match the trait declaration - --> $DIR/parameter_number_and_kind_impl.rs:28:11 + --> $DIR/parameter_number_and_kind_impl.rs:27:11 | LL | type B<'a, 'b>; | -------- lifetimes in impl do not match this type in trait @@ -48,7 +48,7 @@ LL | type B<'a> = u32; | ^^^^ lifetimes do not match type in trait error[E0049]: type `C` has 1 type parameter but its trait declaration has 0 type parameters - --> $DIR/parameter_number_and_kind_impl.rs:30:12 + --> $DIR/parameter_number_and_kind_impl.rs:29:12 | LL | type C; | - expected 0 type parameters diff --git a/src/test/ui/generic-associated-types/parse/in-trait-impl.rs b/src/test/ui/generic-associated-types/parse/in-trait-impl.rs index 7f4775ddbb07..767098835c48 100644 --- a/src/test/ui/generic-associated-types/parse/in-trait-impl.rs +++ b/src/test/ui/generic-associated-types/parse/in-trait-impl.rs @@ -1,8 +1,6 @@ // check-pass // compile-flags: -Z parse-only -#![feature(generic_associated_types)] - impl Baz for T where T: Foo { type Quux<'a> = ::Bar<'a, 'static>; } diff --git a/src/test/ui/generic-associated-types/parse/in-trait.rs b/src/test/ui/generic-associated-types/parse/in-trait.rs index d438795eb1d9..6628aac37430 100644 --- a/src/test/ui/generic-associated-types/parse/in-trait.rs +++ b/src/test/ui/generic-associated-types/parse/in-trait.rs @@ -1,8 +1,6 @@ // check-pass // compile-flags: -Z parse-only -#![feature(generic_associated_types)] - use std::ops::Deref; use std::fmt::Debug; diff --git a/src/test/ui/generic-associated-types/parse/trait-path-expected-token.rs b/src/test/ui/generic-associated-types/parse/trait-path-expected-token.rs index be85598b7bfa..cbb05189201d 100644 --- a/src/test/ui/generic-associated-types/parse/trait-path-expected-token.rs +++ b/src/test/ui/generic-associated-types/parse/trait-path-expected-token.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - trait X { type Y<'a>; } diff --git a/src/test/ui/generic-associated-types/parse/trait-path-expected-token.stderr b/src/test/ui/generic-associated-types/parse/trait-path-expected-token.stderr index 2b265e921616..53d5f9de6575 100644 --- a/src/test/ui/generic-associated-types/parse/trait-path-expected-token.stderr +++ b/src/test/ui/generic-associated-types/parse/trait-path-expected-token.stderr @@ -1,5 +1,5 @@ error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `=` - --> $DIR/trait-path-expected-token.rs:7:33 + --> $DIR/trait-path-expected-token.rs:5:33 | LL | fn f1<'a>(arg : Box>) {} | - ^ expected one of 7 possible tokens diff --git a/src/test/ui/generic-associated-types/parse/trait-path-expressions.rs b/src/test/ui/generic-associated-types/parse/trait-path-expressions.rs index d57c2813b38a..9183ec4976b0 100644 --- a/src/test/ui/generic-associated-types/parse/trait-path-expressions.rs +++ b/src/test/ui/generic-associated-types/parse/trait-path-expressions.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - mod error1 { trait X { type Y<'a>; diff --git a/src/test/ui/generic-associated-types/parse/trait-path-expressions.stderr b/src/test/ui/generic-associated-types/parse/trait-path-expressions.stderr index 272afc10b17b..cf2b1763fc9d 100644 --- a/src/test/ui/generic-associated-types/parse/trait-path-expressions.stderr +++ b/src/test/ui/generic-associated-types/parse/trait-path-expressions.stderr @@ -1,5 +1,5 @@ error: expected expression, found `)` - --> $DIR/trait-path-expressions.rs:8:39 + --> $DIR/trait-path-expressions.rs:6:39 | LL | fn f1<'a>(arg : Box>) {} | - ^ expected expression @@ -7,7 +7,7 @@ LL | fn f1<'a>(arg : Box>) {} | while parsing a const generic argument starting here error: expected one of `,`, `:`, or `>`, found `=` - --> $DIR/trait-path-expressions.rs:18:36 + --> $DIR/trait-path-expressions.rs:16:36 | LL | fn f2<'a>(arg : Box>) {} | - ^ expected one of `,`, `:`, or `>` diff --git a/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.rs b/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.rs index 7914864807ce..ecabf8943ea3 100644 --- a/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.rs +++ b/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - trait X { type Y<'a>; } diff --git a/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr b/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr index 3ace774a041c..10ceccedcac1 100644 --- a/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr +++ b/src/test/ui/generic-associated-types/parse/trait-path-missing-gen_arg.stderr @@ -1,5 +1,5 @@ error: expected one of `>`, a const expression, lifetime, or type, found `:` - --> $DIR/trait-path-missing-gen_arg.rs:8:30 + --> $DIR/trait-path-missing-gen_arg.rs:6:30 | LL | fn f1<'a>(arg : Box>) {} | ^ expected one of `>`, a const expression, lifetime, or type @@ -10,13 +10,13 @@ LL | fn f1<'a>(arg : Box<{ dyn X< : 32 } >>) {} | + + error: expected parameter name, found `>` - --> $DIR/trait-path-missing-gen_arg.rs:8:36 + --> $DIR/trait-path-missing-gen_arg.rs:6:36 | LL | fn f1<'a>(arg : Box>) {} | ^ expected parameter name error: expected one of `!`, `)`, `+`, `,`, or `::`, found `>` - --> $DIR/trait-path-missing-gen_arg.rs:8:36 + --> $DIR/trait-path-missing-gen_arg.rs:6:36 | LL | fn f1<'a>(arg : Box>) {} | ^ @@ -25,7 +25,7 @@ LL | fn f1<'a>(arg : Box>) {} | help: missing `,` error: expected one of `>`, a const expression, lifetime, or type, found `=` - --> $DIR/trait-path-missing-gen_arg.rs:16:30 + --> $DIR/trait-path-missing-gen_arg.rs:14:30 | LL | fn f1<'a>(arg : Box>) {} | - ^ expected one of `>`, a const expression, lifetime, or type @@ -33,7 +33,7 @@ LL | fn f1<'a>(arg : Box>) {} | maybe try to close unmatched angle bracket error[E0747]: constant provided when a type was expected - --> $DIR/trait-path-missing-gen_arg.rs:8:23 + --> $DIR/trait-path-missing-gen_arg.rs:6:23 | LL | fn f1<'a>(arg : Box>) {} | ^^^^^^^^^^^ diff --git a/src/test/ui/generic-associated-types/parse/trait-path-segments.rs b/src/test/ui/generic-associated-types/parse/trait-path-segments.rs index e943f075f534..458e203eb3ce 100644 --- a/src/test/ui/generic-associated-types/parse/trait-path-segments.rs +++ b/src/test/ui/generic-associated-types/parse/trait-path-segments.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - const _: () = { trait X { type Y<'a>; diff --git a/src/test/ui/generic-associated-types/parse/trait-path-segments.stderr b/src/test/ui/generic-associated-types/parse/trait-path-segments.stderr index 7394393c05e2..8bc737d67520 100644 --- a/src/test/ui/generic-associated-types/parse/trait-path-segments.stderr +++ b/src/test/ui/generic-associated-types/parse/trait-path-segments.stderr @@ -1,5 +1,5 @@ error: expected one of `!`, `(`, `+`, `,`, `::`, `:`, `<`, or `>`, found `=` - --> $DIR/trait-path-segments.rs:8:36 + --> $DIR/trait-path-segments.rs:6:36 | LL | fn f1<'a>(arg : Box>) {} | - ^ expected one of 8 possible tokens @@ -12,7 +12,7 @@ LL | fn f1<'a>(arg : Box = u32>>) {} | + error: expected one of `,`, `::`, `:`, or `>`, found `=` - --> $DIR/trait-path-segments.rs:19:35 + --> $DIR/trait-path-segments.rs:17:35 | LL | impl::Y<'a> = &'a u32>> Z for T {} | - ^ expected one of `,`, `::`, `:`, or `>` @@ -25,7 +25,7 @@ LL | impl::Y<'a>> = &'a u32>> Z for T {} | + error: expected one of `!`, `+`, `,`, `::`, `:`, or `>`, found `=` - --> $DIR/trait-path-segments.rs:30:25 + --> $DIR/trait-path-segments.rs:28:25 | LL | impl = &'a u32>> Z for T {} | - ^ expected one of `!`, `+`, `,`, `::`, `:`, or `>` diff --git a/src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs b/src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs index 4846af96d32a..1622b92aa0cc 100644 --- a/src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs +++ b/src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - trait X { type Y<'a>; } diff --git a/src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr b/src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr index 46ddcb635187..e00a414efb9b 100644 --- a/src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr +++ b/src/test/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr @@ -1,11 +1,11 @@ error[E0107]: this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied - --> $DIR/trait-path-type-error-once-implemented.rs:8:29 + --> $DIR/trait-path-type-error-once-implemented.rs:6:29 | LL | fn f2<'a>(arg : Box = &'a ()>>) {} | ^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/trait-path-type-error-once-implemented.rs:4:10 + --> $DIR/trait-path-type-error-once-implemented.rs:2:10 | LL | type Y<'a>; | ^ -- @@ -15,7 +15,7 @@ LL | fn f2<'a>(arg : Box = &'a ()>>) {} | +++ error[E0107]: this associated type takes 0 generic arguments but 1 generic argument was supplied - --> $DIR/trait-path-type-error-once-implemented.rs:8:29 + --> $DIR/trait-path-type-error-once-implemented.rs:6:29 | LL | fn f2<'a>(arg : Box = &'a ()>>) {} | ^--- help: remove these generics @@ -23,7 +23,7 @@ LL | fn f2<'a>(arg : Box = &'a ()>>) {} | expected 0 generic arguments | note: associated type defined here, with 0 generic parameters - --> $DIR/trait-path-type-error-once-implemented.rs:4:10 + --> $DIR/trait-path-type-error-once-implemented.rs:2:10 | LL | type Y<'a>; | ^ diff --git a/src/test/ui/generic-associated-types/parse/trait-path-types.rs b/src/test/ui/generic-associated-types/parse/trait-path-types.rs index 856253cc7fab..74a00342ff4b 100644 --- a/src/test/ui/generic-associated-types/parse/trait-path-types.rs +++ b/src/test/ui/generic-associated-types/parse/trait-path-types.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - trait X { type Y<'a>; } diff --git a/src/test/ui/generic-associated-types/parse/trait-path-types.stderr b/src/test/ui/generic-associated-types/parse/trait-path-types.stderr index fe9ed579e34a..8f7a73c95b65 100644 --- a/src/test/ui/generic-associated-types/parse/trait-path-types.stderr +++ b/src/test/ui/generic-associated-types/parse/trait-path-types.stderr @@ -1,5 +1,5 @@ error: expected one of `,`, `:`, or `>`, found `=` - --> $DIR/trait-path-types.rs:8:37 + --> $DIR/trait-path-types.rs:6:37 | LL | fn f<'a>(arg : Box>) {} | - ^ expected one of `,`, `:`, or `>` @@ -12,7 +12,7 @@ LL | fn f<'a>(arg : Box = u32>>) {} | + error: expected one of `,`, `:`, or `>`, found `=` - --> $DIR/trait-path-types.rs:13:37 + --> $DIR/trait-path-types.rs:11:37 | LL | fn f1<'a>(arg : Box) = &'a ()>>) {} | - ^ expected one of `,`, `:`, or `>` @@ -25,7 +25,7 @@ LL | fn f1<'a>(arg : Box)> = &'a ()>>) {} | + error: expected one of `,`, `:`, or `>`, found `=` - --> $DIR/trait-path-types.rs:18:33 + --> $DIR/trait-path-types.rs:16:33 | LL | fn f1<'a>(arg : Box>) {} | -- ^ expected one of `,`, `:`, or `>` diff --git a/src/test/ui/generic-associated-types/pointer_family.rs b/src/test/ui/generic-associated-types/pointer_family.rs index da86e7f27482..80827cd567b4 100644 --- a/src/test/ui/generic-associated-types/pointer_family.rs +++ b/src/test/ui/generic-associated-types/pointer_family.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - // check-pass use std::rc::Rc; diff --git a/src/test/ui/generic-associated-types/projection-bound-cycle-generic.rs b/src/test/ui/generic-associated-types/projection-bound-cycle-generic.rs index 794d677c8b65..58d57df63c1b 100644 --- a/src/test/ui/generic-associated-types/projection-bound-cycle-generic.rs +++ b/src/test/ui/generic-associated-types/projection-bound-cycle-generic.rs @@ -1,8 +1,6 @@ // Like `projection-bound-cycle.rs` but this avoids using // `feature(trivial_bounds)`. -#![feature(generic_associated_types)] - trait Print { fn print(); } diff --git a/src/test/ui/generic-associated-types/projection-bound-cycle-generic.stderr b/src/test/ui/generic-associated-types/projection-bound-cycle-generic.stderr index 2b57c439fe9a..27c1a82994a5 100644 --- a/src/test/ui/generic-associated-types/projection-bound-cycle-generic.stderr +++ b/src/test/ui/generic-associated-types/projection-bound-cycle-generic.stderr @@ -1,11 +1,11 @@ error[E0275]: overflow evaluating the requirement `::Item: Sized` - --> $DIR/projection-bound-cycle-generic.rs:44:18 + --> $DIR/projection-bound-cycle-generic.rs:42:18 | LL | type Assoc = OnlySized<::Item>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: required by a bound in `OnlySized` - --> $DIR/projection-bound-cycle-generic.rs:28:18 + --> $DIR/projection-bound-cycle-generic.rs:26:18 | LL | struct OnlySized where T: Sized { f: T } | ^ required by this bound in `OnlySized` diff --git a/src/test/ui/generic-associated-types/projection-bound-cycle.rs b/src/test/ui/generic-associated-types/projection-bound-cycle.rs index 6564a3608ec0..4cad1f61319e 100644 --- a/src/test/ui/generic-associated-types/projection-bound-cycle.rs +++ b/src/test/ui/generic-associated-types/projection-bound-cycle.rs @@ -2,7 +2,6 @@ // Make sure that we make sure that we don't allow arbitrary bounds to be // proven when a bound and a where clause of an associated type are the same. -#![feature(generic_associated_types)] #![feature(trivial_bounds)] trait Print { diff --git a/src/test/ui/generic-associated-types/projection-bound-cycle.stderr b/src/test/ui/generic-associated-types/projection-bound-cycle.stderr index d9d0bf4274bd..a46518c80da7 100644 --- a/src/test/ui/generic-associated-types/projection-bound-cycle.stderr +++ b/src/test/ui/generic-associated-types/projection-bound-cycle.stderr @@ -1,11 +1,11 @@ error[E0275]: overflow evaluating the requirement `::Item: Sized` - --> $DIR/projection-bound-cycle.rs:46:18 + --> $DIR/projection-bound-cycle.rs:45:18 | LL | type Assoc = OnlySized<::Item>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: required by a bound in `OnlySized` - --> $DIR/projection-bound-cycle.rs:30:18 + --> $DIR/projection-bound-cycle.rs:29:18 | LL | struct OnlySized where T: Sized { f: T } | ^ required by this bound in `OnlySized` diff --git a/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.rs b/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.rs index a40c0c2c4c74..8e4d5ca5e267 100644 --- a/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.rs +++ b/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - pub trait X { type Y<'a> where Self: 'a; fn m(&self) -> Self::Y<'_>; diff --git a/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr b/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr index 4620aa34e84d..753ead48bf54 100644 --- a/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr +++ b/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/projection-type-lifetime-mismatch.rs:17:5 + --> $DIR/projection-type-lifetime-mismatch.rs:15:5 | LL | fn f(x: &impl for<'a> X = &'a ()>) -> &'static () { | - let's call the lifetime of this reference `'1` @@ -7,7 +7,7 @@ LL | x.m() | ^^^^^ returning this value requires that `'1` must outlive `'static` error: lifetime may not live long enough - --> $DIR/projection-type-lifetime-mismatch.rs:22:5 + --> $DIR/projection-type-lifetime-mismatch.rs:20:5 | LL | fn g X = &'a ()>>(x: &T) -> &'static () { | - let's call the lifetime of this reference `'1` @@ -15,7 +15,7 @@ LL | x.m() | ^^^^^ returning this value requires that `'1` must outlive `'static` error: lifetime may not live long enough - --> $DIR/projection-type-lifetime-mismatch.rs:27:5 + --> $DIR/projection-type-lifetime-mismatch.rs:25:5 | LL | fn h(x: &()) -> &'static () { | - let's call the lifetime of this reference `'1` diff --git a/src/test/ui/generic-associated-types/self-outlives-lint.rs b/src/test/ui/generic-associated-types/self-outlives-lint.rs index 9bb42d4ff1c1..673891fc3d1b 100644 --- a/src/test/ui/generic-associated-types/self-outlives-lint.rs +++ b/src/test/ui/generic-associated-types/self-outlives-lint.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - // check-fail use std::fmt::Debug; diff --git a/src/test/ui/generic-associated-types/self-outlives-lint.stderr b/src/test/ui/generic-associated-types/self-outlives-lint.stderr index a43b35bd79c9..58172bf06b51 100644 --- a/src/test/ui/generic-associated-types/self-outlives-lint.stderr +++ b/src/test/ui/generic-associated-types/self-outlives-lint.stderr @@ -1,5 +1,5 @@ error: missing required bound on `Item` - --> $DIR/self-outlives-lint.rs:9:5 + --> $DIR/self-outlives-lint.rs:7:5 | LL | type Item<'x>; | ^^^^^^^^^^^^^- @@ -10,7 +10,7 @@ LL | type Item<'x>; = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Out` - --> $DIR/self-outlives-lint.rs:25:5 + --> $DIR/self-outlives-lint.rs:23:5 | LL | type Out<'x>; | ^^^^^^^^^^^^- @@ -21,7 +21,7 @@ LL | type Out<'x>; = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Out` - --> $DIR/self-outlives-lint.rs:39:5 + --> $DIR/self-outlives-lint.rs:37:5 | LL | type Out<'x>; | ^^^^^^^^^^^^- @@ -32,7 +32,7 @@ LL | type Out<'x>; = note: we are soliciting feedback, see issue #87479 for more information error: missing required bounds on `Out` - --> $DIR/self-outlives-lint.rs:46:5 + --> $DIR/self-outlives-lint.rs:44:5 | LL | type Out<'x, 'y>; | ^^^^^^^^^^^^^^^^- @@ -43,7 +43,7 @@ LL | type Out<'x, 'y>; = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Out` - --> $DIR/self-outlives-lint.rs:61:5 + --> $DIR/self-outlives-lint.rs:59:5 | LL | type Out<'x, D>; | ^^^^^^^^^^^^^^^- @@ -54,7 +54,7 @@ LL | type Out<'x, D>; = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Out` - --> $DIR/self-outlives-lint.rs:77:5 + --> $DIR/self-outlives-lint.rs:75:5 | LL | type Out<'x, D>; | ^^^^^^^^^^^^^^^- @@ -65,7 +65,7 @@ LL | type Out<'x, D>; = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Out` - --> $DIR/self-outlives-lint.rs:92:5 + --> $DIR/self-outlives-lint.rs:90:5 | LL | type Out<'x, D>; | ^^^^^^^^^^^^^^^- @@ -76,7 +76,7 @@ LL | type Out<'x, D>; = note: we are soliciting feedback, see issue #87479 for more information error: missing required bounds on `Bar` - --> $DIR/self-outlives-lint.rs:114:5 + --> $DIR/self-outlives-lint.rs:112:5 | LL | type Bar<'b>; | ^^^^^^^^^^^^- @@ -87,7 +87,7 @@ LL | type Bar<'b>; = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Bar` - --> $DIR/self-outlives-lint.rs:122:5 + --> $DIR/self-outlives-lint.rs:120:5 | LL | type Bar<'b>; | ^^^^^^^^^^^^- @@ -98,7 +98,7 @@ LL | type Bar<'b>; = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Bar` - --> $DIR/self-outlives-lint.rs:129:5 + --> $DIR/self-outlives-lint.rs:127:5 | LL | type Bar<'b>; | ^^^^^^^^^^^^- @@ -109,7 +109,7 @@ LL | type Bar<'b>; = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Item` - --> $DIR/self-outlives-lint.rs:142:5 + --> $DIR/self-outlives-lint.rs:140:5 | LL | type Item<'a>; | ^^^^^^^^^^^^^- @@ -120,7 +120,7 @@ LL | type Item<'a>; = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Iterator` - --> $DIR/self-outlives-lint.rs:144:5 + --> $DIR/self-outlives-lint.rs:142:5 | LL | type Iterator<'a>: Iterator>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -131,7 +131,7 @@ LL | type Iterator<'a>: Iterator>; = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Item` - --> $DIR/self-outlives-lint.rs:150:5 + --> $DIR/self-outlives-lint.rs:148:5 | LL | type Item<'a>; | ^^^^^^^^^^^^^- @@ -142,7 +142,7 @@ LL | type Item<'a>; = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Bar` - --> $DIR/self-outlives-lint.rs:159:5 + --> $DIR/self-outlives-lint.rs:157:5 | LL | type Bar<'a, 'b>; | ^^^^^^^^^^^^^^^^- @@ -153,7 +153,7 @@ LL | type Bar<'a, 'b>; = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Fut` - --> $DIR/self-outlives-lint.rs:175:5 + --> $DIR/self-outlives-lint.rs:173:5 | LL | type Fut<'out>; | ^^^^^^^^^^^^^^- @@ -164,7 +164,7 @@ LL | type Fut<'out>; = note: we are soliciting feedback, see issue #87479 for more information error: missing required bound on `Item` - --> $DIR/self-outlives-lint.rs:215:5 + --> $DIR/self-outlives-lint.rs:213:5 | LL | type Item<'a>; | ^^^^^^^^^^^^^- diff --git a/src/test/ui/generic-associated-types/shadowing.rs b/src/test/ui/generic-associated-types/shadowing.rs index 2a9763457df7..a05d6e14352b 100644 --- a/src/test/ui/generic-associated-types/shadowing.rs +++ b/src/test/ui/generic-associated-types/shadowing.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - trait Shadow<'a> { type Bar<'a>; //~^ ERROR lifetime name `'a` shadows a lifetime name that is already in scope diff --git a/src/test/ui/generic-associated-types/shadowing.stderr b/src/test/ui/generic-associated-types/shadowing.stderr index be765920975b..bb32684bc7b9 100644 --- a/src/test/ui/generic-associated-types/shadowing.stderr +++ b/src/test/ui/generic-associated-types/shadowing.stderr @@ -1,5 +1,5 @@ error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope - --> $DIR/shadowing.rs:4:14 + --> $DIR/shadowing.rs:2:14 | LL | trait Shadow<'a> { | -- first declared here @@ -7,7 +7,7 @@ LL | type Bar<'a>; | ^^ lifetime `'a` already in scope error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope - --> $DIR/shadowing.rs:13:14 + --> $DIR/shadowing.rs:11:14 | LL | impl<'a> NoShadow<'a> for &'a u32 { | -- first declared here @@ -15,7 +15,7 @@ LL | type Bar<'a> = i32; | ^^ lifetime `'a` already in scope error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters - --> $DIR/shadowing.rs:18:14 + --> $DIR/shadowing.rs:16:14 | LL | trait ShadowT { | - first use of `T` @@ -23,7 +23,7 @@ LL | type Bar; | ^ already used error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters - --> $DIR/shadowing.rs:27:14 + --> $DIR/shadowing.rs:25:14 | LL | impl NoShadowT for Option { | - first use of `T` diff --git a/src/test/ui/generic-associated-types/streaming_iterator.rs b/src/test/ui/generic-associated-types/streaming_iterator.rs index e71b6805ad41..408b8dc99eb4 100644 --- a/src/test/ui/generic-associated-types/streaming_iterator.rs +++ b/src/test/ui/generic-associated-types/streaming_iterator.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(generic_associated_types)] - use std::fmt::Display; trait StreamingIterator { diff --git a/src/test/ui/generic-associated-types/trait-objects.base.stderr b/src/test/ui/generic-associated-types/trait-objects.base.stderr index 1df76a21bf9b..556422c272cf 100644 --- a/src/test/ui/generic-associated-types/trait-objects.base.stderr +++ b/src/test/ui/generic-associated-types/trait-objects.base.stderr @@ -1,11 +1,11 @@ error[E0038]: the trait `StreamingIterator` cannot be made into an object - --> $DIR/trait-objects.rs:14:21 + --> $DIR/trait-objects.rs:13:21 | LL | fn min_size(x: &mut dyn for<'a> StreamingIterator = &'a i32>) -> usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `StreamingIterator` cannot be made into an object | note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit - --> $DIR/trait-objects.rs:8:10 + --> $DIR/trait-objects.rs:7:10 | LL | trait StreamingIterator { | ----------------- this trait cannot be made into an object... diff --git a/src/test/ui/generic-associated-types/trait-objects.extended.stderr b/src/test/ui/generic-associated-types/trait-objects.extended.stderr index 52d48d57859f..086177cc106d 100644 --- a/src/test/ui/generic-associated-types/trait-objects.extended.stderr +++ b/src/test/ui/generic-associated-types/trait-objects.extended.stderr @@ -1,5 +1,5 @@ error[E0521]: borrowed data escapes outside of function - --> $DIR/trait-objects.rs:16:5 + --> $DIR/trait-objects.rs:15:5 | LL | fn min_size(x: &mut dyn for<'a> StreamingIterator = &'a i32>) -> usize { | - - let's call the lifetime of this reference `'1` diff --git a/src/test/ui/generic-associated-types/trait-objects.rs b/src/test/ui/generic-associated-types/trait-objects.rs index c1da1e0a326d..17fed11bac36 100644 --- a/src/test/ui/generic-associated-types/trait-objects.rs +++ b/src/test/ui/generic-associated-types/trait-objects.rs @@ -1,6 +1,5 @@ // revisions: base extended -#![feature(generic_associated_types)] #![cfg_attr(extended, feature(generic_associated_types_extended))] #![cfg_attr(extended, allow(incomplete_features))] diff --git a/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.rs b/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.rs index 8b40dac574a4..1cc09aa6dd4c 100644 --- a/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.rs +++ b/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - pub trait X { type Y<'a: 'static>; //~^ WARNING unnecessary lifetime parameter diff --git a/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr b/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr index ae52010cc50a..fbd79879d0fb 100644 --- a/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr +++ b/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr @@ -1,5 +1,5 @@ warning: unnecessary lifetime parameter `'a` - --> $DIR/unsatified-item-lifetime-bound.rs:4:12 + --> $DIR/unsatified-item-lifetime-bound.rs:2:12 | LL | type Y<'a: 'static>; | ^^ @@ -7,39 +7,39 @@ LL | type Y<'a: 'static>; = help: you can use the `'static` lifetime directly, in place of `'a` error[E0478]: lifetime bound not satisfied - --> $DIR/unsatified-item-lifetime-bound.rs:13:8 + --> $DIR/unsatified-item-lifetime-bound.rs:11:8 | LL | f: ::Y<'a>, | ^^^^^^^^^^^^^^^ | note: lifetime parameter instantiated with the lifetime `'a` as defined here - --> $DIR/unsatified-item-lifetime-bound.rs:12:10 + --> $DIR/unsatified-item-lifetime-bound.rs:10:10 | LL | struct B<'a, T: for<'r> X = &'r ()>> { | ^^ = note: but lifetime parameter must outlive the static lifetime error[E0478]: lifetime bound not satisfied - --> $DIR/unsatified-item-lifetime-bound.rs:18:8 + --> $DIR/unsatified-item-lifetime-bound.rs:16:8 | LL | f: ::Y<'a>, | ^^^^^^^^^^^^^^^ | note: lifetime parameter instantiated with the lifetime `'a` as defined here - --> $DIR/unsatified-item-lifetime-bound.rs:17:10 + --> $DIR/unsatified-item-lifetime-bound.rs:15:10 | LL | struct C<'a, T: X> { | ^^ = note: but lifetime parameter must outlive the static lifetime error[E0478]: lifetime bound not satisfied - --> $DIR/unsatified-item-lifetime-bound.rs:23:8 + --> $DIR/unsatified-item-lifetime-bound.rs:21:8 | LL | f: <() as X>::Y<'a>, | ^^^^^^^^^^^^^^^^ | note: lifetime parameter instantiated with the lifetime `'a` as defined here - --> $DIR/unsatified-item-lifetime-bound.rs:22:10 + --> $DIR/unsatified-item-lifetime-bound.rs:20:10 | LL | struct D<'a> { | ^^ diff --git a/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.rs b/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.rs index 6466bf98dfc8..7137d92379ef 100644 --- a/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.rs +++ b/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - trait ATy { type Item<'a>: 'a; } diff --git a/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr b/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr index 7ec9386cabea..1c9ac01ec0f3 100644 --- a/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr +++ b/src/test/ui/generic-associated-types/unsatisfied-outlives-bound.stderr @@ -1,23 +1,23 @@ error[E0477]: the type `&'b ()` does not fulfill the required lifetime - --> $DIR/unsatisfied-outlives-bound.rs:8:21 + --> $DIR/unsatisfied-outlives-bound.rs:6:21 | LL | type Item<'a> = &'b (); | ^^^^^^ | note: type must outlive the lifetime `'a` as defined here as required by this binding - --> $DIR/unsatisfied-outlives-bound.rs:8:15 + --> $DIR/unsatisfied-outlives-bound.rs:6:15 | LL | type Item<'a> = &'b (); | ^^ error[E0477]: the type `&'a ()` does not fulfill the required lifetime - --> $DIR/unsatisfied-outlives-bound.rs:17:21 + --> $DIR/unsatisfied-outlives-bound.rs:15:21 | LL | type Item<'a> = &'a (); | ^^^^^^ | note: type must satisfy the static lifetime as required by this binding - --> $DIR/unsatisfied-outlives-bound.rs:13:20 + --> $DIR/unsatisfied-outlives-bound.rs:11:20 | LL | type Item<'a>: 'static; | ^^^^^^^ diff --git a/src/test/ui/generic-associated-types/variance_constraints.rs b/src/test/ui/generic-associated-types/variance_constraints.rs index 7d0f7638ac89..0e9dbb8b1bec 100644 --- a/src/test/ui/generic-associated-types/variance_constraints.rs +++ b/src/test/ui/generic-associated-types/variance_constraints.rs @@ -1,6 +1,5 @@ // check-pass // issue #69184 -#![feature(generic_associated_types)] trait A { type B<'a> where Self: 'a; diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90612.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90612.rs index e150ecfe9a0d..effc329456d4 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90612.rs +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90612.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(generic_associated_types)] - use std::marker::PhantomData; trait Family: Sized { diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90638.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90638.rs index 18b7f383482a..628b5cba1042 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90638.rs +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-90638.rs @@ -1,7 +1,5 @@ //check-pass -#![feature(generic_associated_types)] - trait Yokeable<'a>: 'static { type Output: 'a; } diff --git a/src/test/ui/inference/need_type_info/expr-struct-type-relative-gat.rs b/src/test/ui/inference/need_type_info/expr-struct-type-relative-gat.rs index bcd29bb4e349..b0c0d33975c3 100644 --- a/src/test/ui/inference/need_type_info/expr-struct-type-relative-gat.rs +++ b/src/test/ui/inference/need_type_info/expr-struct-type-relative-gat.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - trait Foo { type Output; diff --git a/src/test/ui/inference/need_type_info/expr-struct-type-relative-gat.stderr b/src/test/ui/inference/need_type_info/expr-struct-type-relative-gat.stderr index 65a75b68c1f0..cbc2477deb39 100644 --- a/src/test/ui/inference/need_type_info/expr-struct-type-relative-gat.stderr +++ b/src/test/ui/inference/need_type_info/expr-struct-type-relative-gat.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/expr-struct-type-relative-gat.rs:17:9 + --> $DIR/expr-struct-type-relative-gat.rs:15:9 | LL | Self::Output::Simple {}; | ^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the associated type `Output` diff --git a/src/test/ui/lifetimes/missing-lifetime-in-alias.rs b/src/test/ui/lifetimes/missing-lifetime-in-alias.rs index af7b6412780d..51c564c011a8 100644 --- a/src/test/ui/lifetimes/missing-lifetime-in-alias.rs +++ b/src/test/ui/lifetimes/missing-lifetime-in-alias.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - trait Trait<'a> { type Foo; diff --git a/src/test/ui/lifetimes/missing-lifetime-in-alias.stderr b/src/test/ui/lifetimes/missing-lifetime-in-alias.stderr index b8c68a4607da..428b8f14b6fc 100644 --- a/src/test/ui/lifetimes/missing-lifetime-in-alias.stderr +++ b/src/test/ui/lifetimes/missing-lifetime-in-alias.stderr @@ -1,5 +1,5 @@ error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-in-alias.rs:22:24 + --> $DIR/missing-lifetime-in-alias.rs:20:24 | LL | type B<'a> = as Trait>::Foo; | ^^^^^ expected named lifetime parameter @@ -10,13 +10,13 @@ LL | type B<'a> = as Trait<'a>>::Foo; | ++++ error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-in-alias.rs:26:28 + --> $DIR/missing-lifetime-in-alias.rs:24:28 | LL | type C<'a, 'b> = as Trait>::Bar; | ^^^^^ expected named lifetime parameter | note: these named lifetimes are available to use - --> $DIR/missing-lifetime-in-alias.rs:26:8 + --> $DIR/missing-lifetime-in-alias.rs:24:8 | LL | type C<'a, 'b> = as Trait>::Bar; | ^^ ^^ @@ -26,13 +26,13 @@ LL | type C<'a, 'b> = as Trait<'lifetime>>::Bar; | +++++++++++ error[E0107]: missing generics for associated type `Trait::Bar` - --> $DIR/missing-lifetime-in-alias.rs:26:36 + --> $DIR/missing-lifetime-in-alias.rs:24:36 | LL | type C<'a, 'b> = as Trait>::Bar; | ^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'b` - --> $DIR/missing-lifetime-in-alias.rs:6:10 + --> $DIR/missing-lifetime-in-alias.rs:4:10 | LL | type Bar<'b> | ^^^ -- diff --git a/src/test/ui/parser/impl-item-type-no-body-semantic-fail.rs b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.rs index 9871cb8fe3ee..1291a021bef5 100644 --- a/src/test/ui/parser/impl-item-type-no-body-semantic-fail.rs +++ b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - fn main() {} struct X; diff --git a/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr index 4b398d791c4d..3856754e080a 100644 --- a/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr +++ b/src/test/ui/parser/impl-item-type-no-body-semantic-fail.stderr @@ -1,5 +1,5 @@ error: associated type in `impl` without body - --> $DIR/impl-item-type-no-body-semantic-fail.rs:8:5 + --> $DIR/impl-item-type-no-body-semantic-fail.rs:6:5 | LL | type Y; | ^^^^^^- @@ -7,7 +7,7 @@ LL | type Y; | help: provide a definition for the type: `= ;` error: associated type in `impl` without body - --> $DIR/impl-item-type-no-body-semantic-fail.rs:11:5 + --> $DIR/impl-item-type-no-body-semantic-fail.rs:9:5 | LL | type Z: Ord; | ^^^^^^^^^^^- @@ -15,13 +15,13 @@ LL | type Z: Ord; | help: provide a definition for the type: `= ;` error: bounds on `type`s in `impl`s have no effect - --> $DIR/impl-item-type-no-body-semantic-fail.rs:11:13 + --> $DIR/impl-item-type-no-body-semantic-fail.rs:9:13 | LL | type Z: Ord; | ^^^ error: associated type in `impl` without body - --> $DIR/impl-item-type-no-body-semantic-fail.rs:15:5 + --> $DIR/impl-item-type-no-body-semantic-fail.rs:13:5 | LL | type W: Ord where Self: Eq; | ^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -29,13 +29,13 @@ LL | type W: Ord where Self: Eq; | help: provide a definition for the type: `= ;` error: bounds on `type`s in `impl`s have no effect - --> $DIR/impl-item-type-no-body-semantic-fail.rs:15:13 + --> $DIR/impl-item-type-no-body-semantic-fail.rs:13:13 | LL | type W: Ord where Self: Eq; | ^^^ error: associated type in `impl` without body - --> $DIR/impl-item-type-no-body-semantic-fail.rs:19:5 + --> $DIR/impl-item-type-no-body-semantic-fail.rs:17:5 | LL | type W where Self: Eq; | ^^^^^^^^^^^^^^^^^^^^^- @@ -43,7 +43,7 @@ LL | type W where Self: Eq; | help: provide a definition for the type: `= ;` error[E0658]: inherent associated types are unstable - --> $DIR/impl-item-type-no-body-semantic-fail.rs:8:5 + --> $DIR/impl-item-type-no-body-semantic-fail.rs:6:5 | LL | type Y; | ^^^^^^^ @@ -52,7 +52,7 @@ LL | type Y; = help: add `#![feature(inherent_associated_types)]` to the crate attributes to enable error[E0658]: inherent associated types are unstable - --> $DIR/impl-item-type-no-body-semantic-fail.rs:11:5 + --> $DIR/impl-item-type-no-body-semantic-fail.rs:9:5 | LL | type Z: Ord; | ^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL | type Z: Ord; = help: add `#![feature(inherent_associated_types)]` to the crate attributes to enable error[E0658]: inherent associated types are unstable - --> $DIR/impl-item-type-no-body-semantic-fail.rs:15:5 + --> $DIR/impl-item-type-no-body-semantic-fail.rs:13:5 | LL | type W: Ord where Self: Eq; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -70,7 +70,7 @@ LL | type W: Ord where Self: Eq; = help: add `#![feature(inherent_associated_types)]` to the crate attributes to enable error[E0658]: inherent associated types are unstable - --> $DIR/impl-item-type-no-body-semantic-fail.rs:19:5 + --> $DIR/impl-item-type-no-body-semantic-fail.rs:17:5 | LL | type W where Self: Eq; | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/parser/type-alias-where-fixable.fixed b/src/test/ui/parser/type-alias-where-fixable.fixed index 41dd10676d5f..2f47c0d91fa9 100644 --- a/src/test/ui/parser/type-alias-where-fixable.fixed +++ b/src/test/ui/parser/type-alias-where-fixable.fixed @@ -1,8 +1,6 @@ // check-pass // run-rustfix -#![feature(generic_associated_types)] - trait Trait { // Fine. type Assoc where u32: Copy; diff --git a/src/test/ui/parser/type-alias-where-fixable.rs b/src/test/ui/parser/type-alias-where-fixable.rs index 562a530a7f30..b20aa9398b58 100644 --- a/src/test/ui/parser/type-alias-where-fixable.rs +++ b/src/test/ui/parser/type-alias-where-fixable.rs @@ -1,8 +1,6 @@ // check-pass // run-rustfix -#![feature(generic_associated_types)] - trait Trait { // Fine. type Assoc where u32: Copy; diff --git a/src/test/ui/parser/type-alias-where-fixable.stderr b/src/test/ui/parser/type-alias-where-fixable.stderr index abfeb62fcbb4..2e516d5c4787 100644 --- a/src/test/ui/parser/type-alias-where-fixable.stderr +++ b/src/test/ui/parser/type-alias-where-fixable.stderr @@ -1,5 +1,5 @@ warning: where clause not allowed here - --> $DIR/type-alias-where-fixable.rs:15:16 + --> $DIR/type-alias-where-fixable.rs:13:16 | LL | type Assoc where u32: Copy = (); | ^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL + type Assoc = () where u32: Copy; | warning: where clause not allowed here - --> $DIR/type-alias-where-fixable.rs:18:17 + --> $DIR/type-alias-where-fixable.rs:16:17 | LL | type Assoc2 where u32: Copy = () where i32: Copy; | ^^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL + type Assoc2 = () where i32: Copy, u32: Copy; | warning: where clause not allowed here - --> $DIR/type-alias-where-fixable.rs:26:17 + --> $DIR/type-alias-where-fixable.rs:24:17 | LL | type Assoc2 where u32: Copy, i32: Copy = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/parser/type-alias-where.rs b/src/test/ui/parser/type-alias-where.rs index f6e7dfb7b7b2..62e301cb4086 100644 --- a/src/test/ui/parser/type-alias-where.rs +++ b/src/test/ui/parser/type-alias-where.rs @@ -1,7 +1,5 @@ // check-fail -#![feature(generic_associated_types)] - // Fine, but lints as unused type Foo where u32: Copy = (); // Not fine. diff --git a/src/test/ui/parser/type-alias-where.stderr b/src/test/ui/parser/type-alias-where.stderr index 8789d2665ad9..fb8381792669 100644 --- a/src/test/ui/parser/type-alias-where.stderr +++ b/src/test/ui/parser/type-alias-where.stderr @@ -1,5 +1,5 @@ error: where clauses are not allowed after the type for type aliases - --> $DIR/type-alias-where.rs:8:15 + --> $DIR/type-alias-where.rs:6:15 | LL | type Bar = () where u32: Copy; | ^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | type Bar = () where u32: Copy; = note: see issue #89122 for more information error: where clauses are not allowed after the type for type aliases - --> $DIR/type-alias-where.rs:10:15 + --> $DIR/type-alias-where.rs:8:15 | LL | type Baz = () where; | ^^^^^ diff --git a/src/test/ui/specialization/default-generic-associated-type-bound.rs b/src/test/ui/specialization/default-generic-associated-type-bound.rs index 0f5714e996a1..31a0685d004b 100644 --- a/src/test/ui/specialization/default-generic-associated-type-bound.rs +++ b/src/test/ui/specialization/default-generic-associated-type-bound.rs @@ -1,8 +1,7 @@ // Check that default generics associated types are validated. #![feature(specialization)] -#![feature(generic_associated_types)] -//~^^ WARNING `specialization` is incomplete +//~^ WARNING `specialization` is incomplete trait X { type U<'a>: PartialEq<&'a Self> where Self: 'a; diff --git a/src/test/ui/specialization/default-generic-associated-type-bound.stderr b/src/test/ui/specialization/default-generic-associated-type-bound.stderr index 6d98763a572f..44c24c1e578a 100644 --- a/src/test/ui/specialization/default-generic-associated-type-bound.stderr +++ b/src/test/ui/specialization/default-generic-associated-type-bound.stderr @@ -9,14 +9,14 @@ LL | #![feature(specialization)] = help: consider using `min_specialization` instead, which is more stable and complete error[E0277]: can't compare `T` with `T` - --> $DIR/default-generic-associated-type-bound.rs:18:26 + --> $DIR/default-generic-associated-type-bound.rs:17:26 | LL | default type U<'a> = &'a T; | ^^^^^ no implementation for `T == T` | = note: required for `&'a T` to implement `PartialEq` note: required by a bound in `X::U` - --> $DIR/default-generic-associated-type-bound.rs:8:17 + --> $DIR/default-generic-associated-type-bound.rs:7:17 | LL | type U<'a>: PartialEq<&'a Self> where Self: 'a; | ^^^^^^^^^^^^^^^^^^^ required by this bound in `X::U` diff --git a/src/test/ui/suggestions/issue-85347.rs b/src/test/ui/suggestions/issue-85347.rs index f08e38689d6a..dd52b3150551 100644 --- a/src/test/ui/suggestions/issue-85347.rs +++ b/src/test/ui/suggestions/issue-85347.rs @@ -1,5 +1,3 @@ -#![allow(incomplete_features)] -#![feature(generic_associated_types)] use std::ops::Deref; trait Foo { type Bar<'a>: Deref::Bar>; diff --git a/src/test/ui/suggestions/issue-85347.stderr b/src/test/ui/suggestions/issue-85347.stderr index fccd2ef8df77..de853de27e40 100644 --- a/src/test/ui/suggestions/issue-85347.stderr +++ b/src/test/ui/suggestions/issue-85347.stderr @@ -1,11 +1,11 @@ error[E0107]: this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied - --> $DIR/issue-85347.rs:5:42 + --> $DIR/issue-85347.rs:3:42 | LL | type Bar<'a>: Deref::Bar>; | ^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/issue-85347.rs:5:10 + --> $DIR/issue-85347.rs:3:10 | LL | type Bar<'a>: Deref::Bar>; | ^^^ -- diff --git a/src/test/ui/type-alias-impl-trait/issue-90400-1.rs b/src/test/ui/type-alias-impl-trait/issue-90400-1.rs index 8550a3e86379..15aead2f6411 100644 --- a/src/test/ui/type-alias-impl-trait/issue-90400-1.rs +++ b/src/test/ui/type-alias-impl-trait/issue-90400-1.rs @@ -1,7 +1,6 @@ // Regression test for #90400, // taken from https://github.com/rust-lang/rust/issues/90400#issuecomment-954927836 -#![feature(generic_associated_types)] #![feature(type_alias_impl_trait)] trait Bar { diff --git a/src/test/ui/type-alias-impl-trait/issue-90400-1.stderr b/src/test/ui/type-alias-impl-trait/issue-90400-1.stderr index 428a1074031e..ead28769f066 100644 --- a/src/test/ui/type-alias-impl-trait/issue-90400-1.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-90400-1.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `B: Bar` is not satisfied - --> $DIR/issue-90400-1.rs:23:9 + --> $DIR/issue-90400-1.rs:22:9 | LL | move || bar.bar() | ^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `B` | note: required by a bound in `::foo` - --> $DIR/issue-90400-1.rs:22:15 + --> $DIR/issue-90400-1.rs:21:15 | LL | fn foo(&self, bar: B) -> Self::FooFn { | ^^^ required by this bound in `::foo` diff --git a/src/test/ui/type-alias-impl-trait/issue-90400-2.rs b/src/test/ui/type-alias-impl-trait/issue-90400-2.rs index 2b369bb8a2b9..4c6e893c1729 100644 --- a/src/test/ui/type-alias-impl-trait/issue-90400-2.rs +++ b/src/test/ui/type-alias-impl-trait/issue-90400-2.rs @@ -1,7 +1,6 @@ // Regression test for #90400, // taken from https://github.com/rust-lang/rust/issues/90400#issuecomment-954927836 -#![feature(generic_associated_types)] #![feature(type_alias_impl_trait)] trait Bar { diff --git a/src/test/ui/type-alias-impl-trait/issue-90400-2.stderr b/src/test/ui/type-alias-impl-trait/issue-90400-2.stderr index f84ec0cdc273..50b2dc0495d7 100644 --- a/src/test/ui/type-alias-impl-trait/issue-90400-2.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-90400-2.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `B: Bar` is not satisfied - --> $DIR/issue-90400-2.rs:26:9 + --> $DIR/issue-90400-2.rs:25:9 | LL | MyBaz(bar) | ^^^^^^^^^^ the trait `Bar` is not implemented for `B` | note: required for `MyBaz` to implement `Baz` - --> $DIR/issue-90400-2.rs:31:14 + --> $DIR/issue-90400-2.rs:30:14 | LL | impl Baz for MyBaz { | ^^^ ^^^^^^^^ diff --git a/src/tools/rustfmt/tests/source/issue_4257.rs b/src/tools/rustfmt/tests/source/issue_4257.rs index 2b887fadb621..9482512efca0 100644 --- a/src/tools/rustfmt/tests/source/issue_4257.rs +++ b/src/tools/rustfmt/tests/source/issue_4257.rs @@ -1,6 +1,3 @@ -#![feature(generic_associated_types)] -#![allow(incomplete_features)] - trait Trait { type Type<'a> where T: 'a; fn foo(x: &T) -> Self::Type<'_>; diff --git a/src/tools/rustfmt/tests/source/issue_4911.rs b/src/tools/rustfmt/tests/source/issue_4911.rs index 21ef6c6c491a..c254db7b509c 100644 --- a/src/tools/rustfmt/tests/source/issue_4911.rs +++ b/src/tools/rustfmt/tests/source/issue_4911.rs @@ -1,4 +1,3 @@ -#![feature(generic_associated_types)] #![feature(min_type_alias_impl_trait)] impl SomeTrait for SomeType { diff --git a/src/tools/rustfmt/tests/source/issue_4943.rs b/src/tools/rustfmt/tests/source/issue_4943.rs index 0793b7b4fe1c..307d9a4a1aba 100644 --- a/src/tools/rustfmt/tests/source/issue_4943.rs +++ b/src/tools/rustfmt/tests/source/issue_4943.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - impl SomeStruct { fn process(v: T) -> ::R where Self: GAT = T> diff --git a/src/tools/rustfmt/tests/target/issue_4257.rs b/src/tools/rustfmt/tests/target/issue_4257.rs index 1ebaaf2b6001..309a66c8dc3c 100644 --- a/src/tools/rustfmt/tests/target/issue_4257.rs +++ b/src/tools/rustfmt/tests/target/issue_4257.rs @@ -1,6 +1,3 @@ -#![feature(generic_associated_types)] -#![allow(incomplete_features)] - trait Trait { type Type<'a> where diff --git a/src/tools/rustfmt/tests/target/issue_4911.rs b/src/tools/rustfmt/tests/target/issue_4911.rs index 890a62267ce6..0f64aa7f766f 100644 --- a/src/tools/rustfmt/tests/target/issue_4911.rs +++ b/src/tools/rustfmt/tests/target/issue_4911.rs @@ -1,4 +1,3 @@ -#![feature(generic_associated_types)] #![feature(min_type_alias_impl_trait)] impl SomeTrait for SomeType { diff --git a/src/tools/rustfmt/tests/target/issue_4943.rs b/src/tools/rustfmt/tests/target/issue_4943.rs index 318f7ebed6e0..bc8f1a366da2 100644 --- a/src/tools/rustfmt/tests/target/issue_4943.rs +++ b/src/tools/rustfmt/tests/target/issue_4943.rs @@ -1,5 +1,3 @@ -#![feature(generic_associated_types)] - impl SomeStruct { fn process(v: T) -> ::R where From 3f66efde759e396e02e4a1cdadb3b178884e3bbc Mon Sep 17 00:00:00 2001 From: Donough Liu Date: Mon, 29 Aug 2022 18:44:06 +0100 Subject: [PATCH 3962/5092] Fix uintended diagnostic caused by `drain(..)` --- .../rustc_resolve/src/late/diagnostics.rs | 25 ++++++----- src/test/ui/resolve/issue-73427.rs | 6 +++ src/test/ui/resolve/issue-73427.stderr | 44 ++++++++++++++----- src/test/ui/resolve/privacy-enum-ctor.stderr | 10 ++--- 4 files changed, 58 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index d41edea6a256..9fc637ddbbff 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1792,7 +1792,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { } }; - let mut suggestable_variants = variants + let suggestable_variants = variants .iter() .filter(|(_, def_id, kind)| !needs_placeholder(*def_id, *kind)) .map(|(variant, _, kind)| (path_names_to_string(variant), kind)) @@ -1802,8 +1802,9 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { CtorKind::Fictive => format!("({} {{}})", variant), }) .collect::>(); + let no_suggestable_variant = suggestable_variants.is_empty(); - if !suggestable_variants.is_empty() { + if !no_suggestable_variant { let msg = if suggestable_variants.len() == 1 { "you might have meant to use the following enum variant" } else { @@ -1813,7 +1814,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { err.span_suggestions( span, msg, - suggestable_variants.drain(..), + suggestable_variants.into_iter(), Applicability::MaybeIncorrect, ); } @@ -1830,15 +1831,15 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { .collect::>(); if !suggestable_variants_with_placeholders.is_empty() { - let msg = match ( - suggestable_variants.is_empty(), - suggestable_variants_with_placeholders.len(), - ) { - (true, 1) => "the following enum variant is available", - (true, _) => "the following enum variants are available", - (false, 1) => "alternatively, the following enum variant is available", - (false, _) => "alternatively, the following enum variants are also available", - }; + let msg = + match (no_suggestable_variant, suggestable_variants_with_placeholders.len()) { + (true, 1) => "the following enum variant is available", + (true, _) => "the following enum variants are available", + (false, 1) => "alternatively, the following enum variant is available", + (false, _) => { + "alternatively, the following enum variants are also available" + } + }; err.span_suggestions( span, diff --git a/src/test/ui/resolve/issue-73427.rs b/src/test/ui/resolve/issue-73427.rs index 3c62782a8979..5c2459a59036 100644 --- a/src/test/ui/resolve/issue-73427.rs +++ b/src/test/ui/resolve/issue-73427.rs @@ -22,6 +22,10 @@ enum D { Unit, } +enum E { + TupleWithFields(()), +} + fn main() { // Only variants without fields are suggested (and others mentioned in a note) where an enum // is used rather than a variant. @@ -34,6 +38,8 @@ fn main() { //~^ ERROR expected value, found enum `C` D.foo(); //~^ ERROR expected value, found enum `D` + E.foo(); + //~^ ERROR expected value, found enum `E` // Only tuple variants are suggested in calls or tuple struct pattern matching. diff --git a/src/test/ui/resolve/issue-73427.stderr b/src/test/ui/resolve/issue-73427.stderr index 59bb98a340a5..a2ca46f0ce96 100644 --- a/src/test/ui/resolve/issue-73427.stderr +++ b/src/test/ui/resolve/issue-73427.stderr @@ -1,5 +1,5 @@ error[E0423]: expected value, found enum `A` - --> $DIR/issue-73427.rs:29:5 + --> $DIR/issue-73427.rs:33:5 | LL | A.foo(); | ^ @@ -23,7 +23,7 @@ LL | (A::Tuple()).foo(); | ~~~~~~~~~~~~ LL | A::Unit.foo(); | ~~~~~~~ -help: the following enum variants are available +help: alternatively, the following enum variants are also available | LL | (A::StructWithFields { /* fields */ }).foo(); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -31,7 +31,7 @@ LL | (A::TupleWithFields(/* fields */)).foo(); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0423]: expected value, found enum `B` - --> $DIR/issue-73427.rs:31:5 + --> $DIR/issue-73427.rs:35:5 | LL | B.foo(); | ^ @@ -52,7 +52,7 @@ LL | (B::TupleWithFields(/* fields */)).foo(); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0423]: expected value, found enum `C` - --> $DIR/issue-73427.rs:33:5 + --> $DIR/issue-73427.rs:37:5 | LL | C.foo(); | ^ @@ -70,7 +70,7 @@ help: you might have meant to use the following enum variant | LL | C::Unit.foo(); | ~~~~~~~ -help: the following enum variants are available +help: alternatively, the following enum variants are also available | LL | (C::StructWithFields { /* fields */ }).foo(); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -78,7 +78,7 @@ LL | (C::TupleWithFields(/* fields */)).foo(); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0423]: expected value, found enum `D` - --> $DIR/issue-73427.rs:35:5 + --> $DIR/issue-73427.rs:39:5 | LL | D.foo(); | ^ @@ -95,13 +95,37 @@ help: you might have meant to use the following enum variant | LL | D::Unit.foo(); | ~~~~~~~ -help: the following enum variant is available +help: alternatively, the following enum variant is available | LL | (D::TupleWithFields(/* fields */)).foo(); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +error[E0423]: expected value, found enum `E` + --> $DIR/issue-73427.rs:41:5 + | +LL | E.foo(); + | ^ + | +note: the enum is defined here + --> $DIR/issue-73427.rs:25:1 + | +LL | / enum E { +LL | | TupleWithFields(()), +LL | | } + | |_^ +help: the following enum variant is available + | +LL | (E::TupleWithFields(/* fields */)).foo(); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +help: consider importing one of these items instead + | +LL | use std::f32::consts::E; + | +LL | use std::f64::consts::E; + | + error[E0423]: expected function, tuple struct or tuple variant, found enum `A` - --> $DIR/issue-73427.rs:40:13 + --> $DIR/issue-73427.rs:46:13 | LL | let x = A(3); | ^ @@ -126,7 +150,7 @@ LL | let x = A::TupleWithFields(3); | ~~~~~~~~~~~~~~~~~~ error[E0532]: expected tuple struct or tuple variant, found enum `A` - --> $DIR/issue-73427.rs:42:12 + --> $DIR/issue-73427.rs:48:12 | LL | if let A(3) = x { } | ^ @@ -150,7 +174,7 @@ LL | if let A::Tuple(3) = x { } LL | if let A::TupleWithFields(3) = x { } | ~~~~~~~~~~~~~~~~~~ -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors Some errors have detailed explanations: E0423, E0532. For more information about an error, try `rustc --explain E0423`. diff --git a/src/test/ui/resolve/privacy-enum-ctor.stderr b/src/test/ui/resolve/privacy-enum-ctor.stderr index f885ac2151d6..4c51d1252613 100644 --- a/src/test/ui/resolve/privacy-enum-ctor.stderr +++ b/src/test/ui/resolve/privacy-enum-ctor.stderr @@ -19,7 +19,7 @@ help: you might have meant to use the following enum variant | LL | m::Z::Unit; | ~~~~~~~~~~ -help: the following enum variants are available +help: alternatively, the following enum variants are also available | LL | (m::Z::Fn(/* fields */)); | ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -47,7 +47,7 @@ help: you might have meant to use the following enum variant | LL | m::Z::Unit; | ~~~~~~~~~~ -help: the following enum variants are available +help: alternatively, the following enum variants are also available | LL | (m::Z::Fn(/* fields */)); | ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -89,7 +89,7 @@ help: you might have meant to use the following enum variant | LL | let _: E = E::Unit; | ~~~~~~~ -help: the following enum variants are available +help: alternatively, the following enum variants are also available | LL | let _: E = (E::Fn(/* fields */)); | ~~~~~~~~~~~~~~~~~~~~~ @@ -143,7 +143,7 @@ help: you might have meant to use the following enum variant | LL | let _: E = E::Unit; | ~~~~~~~ -help: the following enum variants are available +help: alternatively, the following enum variants are also available | LL | let _: E = (E::Fn(/* fields */)); | ~~~~~~~~~~~~~~~~~~~~~ @@ -203,7 +203,7 @@ help: you might have meant to use the following enum variant | LL | let _: Z = m::Z::Unit; | ~~~~~~~~~~ -help: the following enum variants are available +help: alternatively, the following enum variants are also available | LL | let _: Z = (m::Z::Fn(/* fields */)); | ~~~~~~~~~~~~~~~~~~~~~~~~ From 5c0e25237c62675f7118a4a8a60985fca9afc4e4 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 31 Aug 2022 10:04:01 +0200 Subject: [PATCH 3963/5092] Drop the expander borrow in all control flow paths The change in https://github.com/rust-lang/rust-analyzer/pull/13123 actually re-uses the RefMut borrow instead of dropping it so we need to drop it manually where required. --- crates/hir-ty/src/lower.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 3f6d0844e9c1..708e63d7fd34 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -332,7 +332,10 @@ impl<'a> TyLoweringContext<'a> { TypeRef::Macro(macro_call) => { let (mut expander, recursion_start) = { match RefMut::filter_map(self.expander.borrow_mut(), Option::as_mut) { + // There already is an expander here, this means we are already recursing Ok(expander) => (expander, false), + // No expander was created yet, so we are at the start of the expansion recursion + // and therefore have to create an expander. Err(expander) => ( RefMut::map(expander, |it| { it.insert(Expander::new( @@ -362,9 +365,14 @@ impl<'a> TyLoweringContext<'a> { .exit(self.db.upcast(), mark); Some(ty) } - _ => None, + _ => { + drop(expander); + None + } } }; + + // drop the expander, resetting it to pre-recursion state if recursion_start { *self.expander.borrow_mut() = None; } From e10ab626904192186a9caf74207aba8370cb6458 Mon Sep 17 00:00:00 2001 From: Martin Geisler Date: Wed, 31 Aug 2022 10:35:36 +0200 Subject: [PATCH 3964/5092] =?UTF-8?q?Link=20=E2=80=9C=3F=20operator?= =?UTF-8?q?=E2=80=9D=20to=20relevant=20chapter=20in=20The=20Book?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before, the text simply asked people to use a symbol which is hard to search for. Now the text links back to the chapter on error propagation in The Book. That should help people find the relevant keywords for further searches. --- library/core/src/macros/mod.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 0bd9c8e9acfc..b37e9142d889 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -350,10 +350,12 @@ macro_rules! matches { /// Unwraps a result or propagates its error. /// -/// The `?` operator was added to replace `try!` and should be used instead. -/// Furthermore, `try` is a reserved word in Rust 2018, so if you must use -/// it, you will need to use the [raw-identifier syntax][ris]: `r#try`. +/// The [`?` operator][propagating-errors] was added to replace `try!` +/// and should be used instead. Furthermore, `try` is a reserved word +/// in Rust 2018, so if you must use it, you will need to use the +/// [raw-identifier syntax][ris]: `r#try`. /// +/// [propagating-errors]: https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator /// [ris]: https://doc.rust-lang.org/nightly/rust-by-example/compatibility/raw_identifiers.html /// /// `try!` matches the given [`Result`]. In case of the `Ok` variant, the From 43e8d9644f9e55b677e226dbfa0255d9a8af1303 Mon Sep 17 00:00:00 2001 From: austaras Date: Wed, 31 Aug 2022 17:31:23 +0800 Subject: [PATCH 3965/5092] change title --- crates/ide-assists/src/handlers/replace_or_with_or_else.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ide-assists/src/handlers/replace_or_with_or_else.rs b/crates/ide-assists/src/handlers/replace_or_with_or_else.rs index bee52a0d7fae..7d91be621013 100644 --- a/crates/ide-assists/src/handlers/replace_or_with_or_else.rs +++ b/crates/ide-assists/src/handlers/replace_or_with_or_else.rs @@ -62,7 +62,7 @@ pub(crate) fn replace_or_with_or_else(acc: &mut Assists, ctx: &AssistContext<'_> acc.add( AssistId("replace_or_with_or_else", AssistKind::RefactorRewrite), - "Replace unwrap_or or ok_or with lazy version", + format!("Replace {} with {}", name.text(), replace), call.syntax().text_range(), |builder| { builder.replace(name.syntax().text_range(), replace); @@ -138,7 +138,7 @@ pub(crate) fn replace_or_else_with_or(acc: &mut Assists, ctx: &AssistContext<'_> acc.add( AssistId("replace_or_else_with_or", AssistKind::RefactorRewrite), - "Replace unwrap_or_else or ok_or_else with eager version", + format!("Replace {} with {}", name.text(), replace), call.syntax().text_range(), |builder| { builder.replace(name.syntax().text_range(), replace); From 4661a60aa90e4fa7b4d1184ef64f8a6613e0075e Mon Sep 17 00:00:00 2001 From: Pocket7878 Date: Fri, 12 Aug 2022 16:11:04 +0900 Subject: [PATCH 3966/5092] Add convert_two_arm_bool_match_to_matches_macro ide-assists --- ...ert_two_arm_bool_match_to_matches_macro.rs | 293 ++++++++++++++++++ crates/ide-assists/src/lib.rs | 2 + crates/ide-assists/src/tests/generated.rs | 20 ++ 3 files changed, 315 insertions(+) create mode 100644 crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs diff --git a/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs b/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs new file mode 100644 index 000000000000..68c9f5baf2bb --- /dev/null +++ b/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs @@ -0,0 +1,293 @@ +use syntax::ast::{self, AstNode, Pat}; + +use crate::{AssistContext, AssistId, AssistKind, Assists}; + +// Assist: convert_two_arm_bool_match_to_matches_macro +// +// Convert 2-arm match that evaluates to a boolean into the equivalent matches! invocation. +// +// ``` +// fn main() { +// match scrutinee$0 { +// Some(val) if val.cond() => true, +// _ => false, +// } +// } +// ``` +// -> +// ``` +// fn main() { +// matches!(scrutinee, Some(val) if val.cond()) +// } +// ``` +pub(crate) fn convert_two_arm_bool_match_to_matches_macro( + acc: &mut Assists, + ctx: &AssistContext<'_>, +) -> Option<()> { + let match_expr = ctx.find_node_at_offset::()?; + let match_arm_list = match_expr.match_arm_list()?; + if match_arm_list.arms().count() != 2 { + cov_mark::hit!(non_two_arm_match); + return None; + } + + let mut normal_arm = None; + let mut normal_expr = None; + let mut wildcard_expr = None; + for arm in match_arm_list.arms() { + if matches!(arm.pat(), Some(Pat::WildcardPat(_))) && arm.guard().is_none() { + wildcard_expr = arm.expr(); + } else if !matches!(arm.pat(), Some(Pat::WildcardPat(_))) { + normal_arm = Some(arm.clone()); + normal_expr = arm.expr(); + } + } + + let invert_matches; + if is_bool_literal_expr(&normal_expr, true) && is_bool_literal_expr(&wildcard_expr, false) { + invert_matches = false; + } else if is_bool_literal_expr(&normal_expr, false) + && is_bool_literal_expr(&wildcard_expr, true) + { + invert_matches = true; + } else { + cov_mark::hit!(non_invert_bool_literal_arms); + return None; + } + + let target_range = ctx.sema.original_range(match_expr.syntax()).range; + let expr = match_expr.expr()?; + + acc.add( + AssistId("convert_two_arm_bool_match_to_matches_macro", AssistKind::RefactorRewrite), + "Convert to matches!", + target_range, + |builder| { + let mut arm_str = String::new(); + if let Some(ref pat) = normal_arm.as_ref().unwrap().pat() { + arm_str += &pat.to_string(); + } + if let Some(ref guard) = normal_arm.as_ref().unwrap().guard() { + arm_str += &format!(" {}", &guard.to_string()); + } + if invert_matches { + builder.replace(target_range, format!("!matches!({}, {})", expr, arm_str)); + } else { + builder.replace(target_range, format!("matches!({}, {})", expr, arm_str)); + } + }, + ) +} + +fn is_bool_literal_expr(expr: &Option, expect_bool: bool) -> bool { + if let Some(ast::Expr::Literal(lit)) = expr { + if let ast::LiteralKind::Bool(b) = lit.kind() { + return b == expect_bool; + } + } + + return false; +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; + + use super::convert_two_arm_bool_match_to_matches_macro; + + #[test] + fn not_applicable_outside_of_range_left() { + check_assist_not_applicable( + convert_two_arm_bool_match_to_matches_macro, + r#" +fn foo(a: Option) -> bool { + $0 match a { + Some(_val) => true, + _ => false + } +} + "#, + ); + } + + #[test] + fn not_applicable_non_two_arm_match() { + cov_mark::check!(non_two_arm_match); + check_assist_not_applicable( + convert_two_arm_bool_match_to_matches_macro, + r#" +fn foo(a: Option) -> bool { + match a$0 { + Some(3) => true, + Some(4) => true, + _ => false + } +} + "#, + ); + } + + #[test] + fn not_applicable_non_bool_literal_arms() { + cov_mark::check!(non_invert_bool_literal_arms); + check_assist_not_applicable( + convert_two_arm_bool_match_to_matches_macro, + r#" +fn foo(a: Option) -> bool { + match a$0 { + Some(val) => val == 3, + _ => false + } +} + "#, + ); + } + + #[test] + fn not_applicable_both_false_arms() { + cov_mark::check!(non_invert_bool_literal_arms); + check_assist_not_applicable( + convert_two_arm_bool_match_to_matches_macro, + r#" +fn foo(a: Option) -> bool { + match a$0 { + Some(val) => false, + _ => false + } +} + "#, + ); + } + + #[test] + fn not_applicable_both_true_arms() { + cov_mark::check!(non_invert_bool_literal_arms); + check_assist_not_applicable( + convert_two_arm_bool_match_to_matches_macro, + r#" +fn foo(a: Option) -> bool { + match a$0 { + Some(val) => true, + _ => true + } +} + "#, + ); + } + + #[test] + fn not_applicable_non_bool_match() { + cov_mark::check!(non_invert_bool_literal_arms); + check_assist_not_applicable( + convert_two_arm_bool_match_to_matches_macro, + r#" +fn foo(a: Option) -> u32 { + match a$0 { + Some(_val) => 1, + _ => 0 + } +} +"#, + ); + } + + #[test] + fn convert_simple_case() { + check_assist( + convert_two_arm_bool_match_to_matches_macro, + r#" +fn foo(a: Option) -> bool { + match a$0 { + Some(_val) => true, + _ => false + } +} +"#, + r#" +fn foo(a: Option) -> bool { + matches!(a, Some(_val)) +} +"#, + ); + } + + #[test] + fn convert_simple_invert_case() { + check_assist( + convert_two_arm_bool_match_to_matches_macro, + r#" +fn foo(a: Option) -> bool { + match a$0 { + Some(_val) => false, + _ => true + } +} +"#, + r#" +fn foo(a: Option) -> bool { + !matches!(a, Some(_val)) +} +"#, + ); + } + + #[test] + fn convert_with_guard_case() { + check_assist( + convert_two_arm_bool_match_to_matches_macro, + r#" +fn foo(a: Option) -> bool { + match a$0 { + Some(val) if val > 3 => true, + _ => false + } +} +"#, + r#" +fn foo(a: Option) -> bool { + matches!(a, Some(val) if val > 3) +} +"#, + ); + } + + #[test] + fn convert_target_simple() { + check_assist_target( + convert_two_arm_bool_match_to_matches_macro, + r#" +fn foo(a: Option) -> bool { + match a$0 { + Some(val) => true, + _ => false + } +} +"#, + r#"match a { + Some(val) => true, + _ => false + }"#, + ); + } + + #[test] + fn convert_target_complex() { + check_assist_target( + convert_two_arm_bool_match_to_matches_macro, + r#" +enum E { X, Y } + +fn main() { + match E::X$0 { + E::X => true, + _ => false, + } +} +"#, + "match E::X { + E::X => true, + _ => false, + }", + ); + } +} diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index c558553b1cbe..0a40c4038679 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -122,6 +122,7 @@ mod handlers { mod convert_let_else_to_match; mod convert_tuple_struct_to_named_struct; mod convert_to_guarded_return; + mod convert_two_arm_bool_match_to_matches_macro; mod convert_while_to_loop; mod destructure_tuple_binding; mod expand_glob_import; @@ -216,6 +217,7 @@ mod handlers { convert_let_else_to_match::convert_let_else_to_match, convert_to_guarded_return::convert_to_guarded_return, convert_tuple_struct_to_named_struct::convert_tuple_struct_to_named_struct, + convert_two_arm_bool_match_to_matches_macro::convert_two_arm_bool_match_to_matches_macro, convert_while_to_loop::convert_while_to_loop, destructure_tuple_binding::destructure_tuple_binding, expand_glob_import::expand_glob_import, diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index 7b2c16806b2b..c5895a843a2e 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -472,6 +472,26 @@ impl Point { ) } +#[test] +fn doctest_convert_two_arm_bool_match_to_matches_macro() { + check_doc_test( + "convert_two_arm_bool_match_to_matches_macro", + r#####" +fn main() { + match scrutinee$0 { + Some(val) if val.cond() => true, + _ => false, + } +} +"#####, + r#####" +fn main() { + matches!(scrutinee, Some(val) if val.cond()) +} +"#####, + ) +} + #[test] fn doctest_convert_while_to_loop() { check_doc_test( From a5d2463b1d0ee286218e428ca6f0ee53d72e3788 Mon Sep 17 00:00:00 2001 From: Pocket7878 Date: Sat, 13 Aug 2022 00:29:18 +0900 Subject: [PATCH 3967/5092] fix: Simplify logics to allow two-arm enum match. --- ...ert_two_arm_bool_match_to_matches_macro.rs | 101 ++++++------------ 1 file changed, 33 insertions(+), 68 deletions(-) diff --git a/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs b/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs index 68c9f5baf2bb..5278fe5303a5 100644 --- a/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs +++ b/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs @@ -1,4 +1,4 @@ -use syntax::ast::{self, AstNode, Pat}; +use syntax::ast::{self, AstNode}; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -31,27 +31,16 @@ pub(crate) fn convert_two_arm_bool_match_to_matches_macro( return None; } - let mut normal_arm = None; - let mut normal_expr = None; - let mut wildcard_expr = None; - for arm in match_arm_list.arms() { - if matches!(arm.pat(), Some(Pat::WildcardPat(_))) && arm.guard().is_none() { - wildcard_expr = arm.expr(); - } else if !matches!(arm.pat(), Some(Pat::WildcardPat(_))) { - normal_arm = Some(arm.clone()); - normal_expr = arm.expr(); - } - } + let first_arm = match_arm_list.arms().next()?; + let first_arm_expr = first_arm.expr(); let invert_matches; - if is_bool_literal_expr(&normal_expr, true) && is_bool_literal_expr(&wildcard_expr, false) { + if is_bool_literal_expr(&first_arm_expr, true) { invert_matches = false; - } else if is_bool_literal_expr(&normal_expr, false) - && is_bool_literal_expr(&wildcard_expr, true) - { + } else if is_bool_literal_expr(&first_arm_expr, false) { invert_matches = true; } else { - cov_mark::hit!(non_invert_bool_literal_arms); + cov_mark::hit!(non_bool_literal_match); return None; } @@ -64,10 +53,10 @@ pub(crate) fn convert_two_arm_bool_match_to_matches_macro( target_range, |builder| { let mut arm_str = String::new(); - if let Some(ref pat) = normal_arm.as_ref().unwrap().pat() { + if let Some(ref pat) = first_arm.pat() { arm_str += &pat.to_string(); } - if let Some(ref guard) = normal_arm.as_ref().unwrap().guard() { + if let Some(ref guard) = first_arm.guard() { arm_str += &format!(" {}", &guard.to_string()); } if invert_matches { @@ -129,7 +118,7 @@ fn foo(a: Option) -> bool { #[test] fn not_applicable_non_bool_literal_arms() { - cov_mark::check!(non_invert_bool_literal_arms); + cov_mark::check!(non_bool_literal_match); check_assist_not_applicable( convert_two_arm_bool_match_to_matches_macro, r#" @@ -143,54 +132,6 @@ fn foo(a: Option) -> bool { ); } - #[test] - fn not_applicable_both_false_arms() { - cov_mark::check!(non_invert_bool_literal_arms); - check_assist_not_applicable( - convert_two_arm_bool_match_to_matches_macro, - r#" -fn foo(a: Option) -> bool { - match a$0 { - Some(val) => false, - _ => false - } -} - "#, - ); - } - - #[test] - fn not_applicable_both_true_arms() { - cov_mark::check!(non_invert_bool_literal_arms); - check_assist_not_applicable( - convert_two_arm_bool_match_to_matches_macro, - r#" -fn foo(a: Option) -> bool { - match a$0 { - Some(val) => true, - _ => true - } -} - "#, - ); - } - - #[test] - fn not_applicable_non_bool_match() { - cov_mark::check!(non_invert_bool_literal_arms); - check_assist_not_applicable( - convert_two_arm_bool_match_to_matches_macro, - r#" -fn foo(a: Option) -> u32 { - match a$0 { - Some(_val) => 1, - _ => 0 - } -} -"#, - ); - } - #[test] fn convert_simple_case() { check_assist( @@ -251,6 +192,30 @@ fn foo(a: Option) -> bool { ); } + #[test] + fn convert_enum_match_cases() { + check_assist( + convert_two_arm_bool_match_to_matches_macro, + r#" +enum X { A, B } + +fn foo(a: X) -> bool { + match a$0 { + X::A => true, + _ => false + } +} +"#, + r#" +enum X { A, B } + +fn foo(a: X) -> bool { + matches!(a, X::A) +} +"#, + ); + } + #[test] fn convert_target_simple() { check_assist_target( From 5a1b45dcc157f41cbabf8f93fa1641bc4e29af60 Mon Sep 17 00:00:00 2001 From: Masato Sogame Date: Wed, 31 Aug 2022 18:29:58 +0900 Subject: [PATCH 3968/5092] feature: Simplfy branch check logics Co-authored-by: Lukas Wirth --- ...onvert_two_arm_bool_match_to_matches_macro.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs b/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs index 5278fe5303a5..68fe81f67b02 100644 --- a/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs +++ b/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs @@ -26,23 +26,23 @@ pub(crate) fn convert_two_arm_bool_match_to_matches_macro( ) -> Option<()> { let match_expr = ctx.find_node_at_offset::()?; let match_arm_list = match_expr.match_arm_list()?; - if match_arm_list.arms().count() != 2 { + let mut arms = match_arm_list.arms(); + let first_arm = arms.next()?; + let second_arm = arms.next()?; + if arms.next().is_some() { cov_mark::hit!(non_two_arm_match); return None; } - - let first_arm = match_arm_list.arms().next()?; let first_arm_expr = first_arm.expr(); - let invert_matches; - if is_bool_literal_expr(&first_arm_expr, true) { - invert_matches = false; + let invert_matches = if is_bool_literal_expr(&first_arm_expr, true) { + false } else if is_bool_literal_expr(&first_arm_expr, false) { - invert_matches = true; + true } else { cov_mark::hit!(non_bool_literal_match); return None; - } + }; let target_range = ctx.sema.original_range(match_expr.syntax()).range; let expr = match_expr.expr()?; From 7464b6dbc4b5342dc70105307c28ec26125b6380 Mon Sep 17 00:00:00 2001 From: Pocket7878 Date: Wed, 31 Aug 2022 18:38:20 +0900 Subject: [PATCH 3969/5092] feature: Check if first_arm bool and second_arm bool is inverted or not. --- ...ert_two_arm_bool_match_to_matches_macro.rs | 44 +++++++++++++++++-- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs b/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs index 68fe81f67b02..54a7f480a4e4 100644 --- a/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs +++ b/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs @@ -34,13 +34,18 @@ pub(crate) fn convert_two_arm_bool_match_to_matches_macro( return None; } let first_arm_expr = first_arm.expr(); + let second_arm_expr = second_arm.expr(); - let invert_matches = if is_bool_literal_expr(&first_arm_expr, true) { + let invert_matches = if is_bool_literal_expr(&first_arm_expr, true) + && is_bool_literal_expr(&second_arm_expr, false) + { false - } else if is_bool_literal_expr(&first_arm_expr, false) { + } else if is_bool_literal_expr(&first_arm_expr, false) + && is_bool_literal_expr(&second_arm_expr, true) + { true } else { - cov_mark::hit!(non_bool_literal_match); + cov_mark::hit!(non_invert_bool_literal_arms); return None; }; @@ -118,7 +123,7 @@ fn foo(a: Option) -> bool { #[test] fn not_applicable_non_bool_literal_arms() { - cov_mark::check!(non_bool_literal_match); + cov_mark::check!(non_invert_bool_literal_arms); check_assist_not_applicable( convert_two_arm_bool_match_to_matches_macro, r#" @@ -131,6 +136,37 @@ fn foo(a: Option) -> bool { "#, ); } + #[test] + fn not_applicable_both_false_arms() { + cov_mark::check!(non_invert_bool_literal_arms); + check_assist_not_applicable( + convert_two_arm_bool_match_to_matches_macro, + r#" +fn foo(a: Option) -> bool { + match a$0 { + Some(val) => false, + _ => false + } +} + "#, + ); + } + + #[test] + fn not_applicable_both_true_arms() { + cov_mark::check!(non_invert_bool_literal_arms); + check_assist_not_applicable( + convert_two_arm_bool_match_to_matches_macro, + r#" +fn foo(a: Option) -> bool { + match a$0 { + Some(val) => true, + _ => true + } +} + "#, + ); + } #[test] fn convert_simple_case() { From b1430fb7ca499d517d9f4b3b6c5a81442129c88b Mon Sep 17 00:00:00 2001 From: Dezhi Wu Date: Thu, 18 Aug 2022 10:13:37 +0800 Subject: [PATCH 3970/5092] Fix a bunch of typo This PR will fix some typos detected by [typos]. I only picked the ones I was sure were spelling errors to fix, mostly in the comments. [typos]: https://github.com/crate-ci/typos --- RELEASES.md | 4 ++-- compiler/rustc_ast_lowering/src/lib.rs | 2 +- compiler/rustc_ast_passes/src/ast_validation.rs | 2 +- compiler/rustc_codegen_cranelift/src/abi/mod.rs | 2 +- compiler/rustc_codegen_cranelift/src/constant.rs | 2 +- compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs | 2 +- compiler/rustc_codegen_ssa/src/back/symbol_export.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/mod.rs | 2 +- compiler/rustc_const_eval/src/interpret/intrinsics.rs | 2 +- compiler/rustc_const_eval/src/interpret/memory.rs | 4 ++-- compiler/rustc_const_eval/src/interpret/projection.rs | 2 +- compiler/rustc_const_eval/src/interpret/terminator.rs | 4 ++-- compiler/rustc_const_eval/src/interpret/traits.rs | 2 +- compiler/rustc_data_structures/src/fingerprint.rs | 4 ++-- compiler/rustc_expand/src/mbe/macro_parser.rs | 2 +- compiler/rustc_expand/src/mbe/macro_rules.rs | 2 +- compiler/rustc_expand/src/proc_macro.rs | 2 +- .../src/infer/error_reporting/need_type_info.rs | 2 +- compiler/rustc_infer/src/infer/mod.rs | 2 +- compiler/rustc_infer/src/infer/undo_log.rs | 2 +- compiler/rustc_interface/src/interface.rs | 4 ++-- compiler/rustc_lint/src/unused.rs | 6 +++--- compiler/rustc_lint_defs/src/builtin.rs | 2 +- compiler/rustc_middle/src/mir/basic_blocks.rs | 2 +- compiler/rustc_middle/src/mir/mod.rs | 2 +- compiler/rustc_middle/src/mir/syntax.rs | 4 ++-- compiler/rustc_middle/src/query/mod.rs | 2 +- .../rustc_middle/src/traits/specialization_graph.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 10 +++++----- compiler/rustc_middle/src/ty/generics.rs | 2 +- compiler/rustc_middle/src/ty/layout.rs | 2 +- compiler/rustc_mir_build/src/build/matches/mod.rs | 2 +- compiler/rustc_monomorphize/src/util.rs | 2 +- compiler/rustc_parse/src/parser/expr.rs | 4 ++-- compiler/rustc_parse/src/parser/mod.rs | 2 +- compiler/rustc_passes/src/hir_stats.rs | 2 +- compiler/rustc_resolve/src/late/lifetimes.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 2 +- compiler/rustc_resolve/src/macros.rs | 2 +- compiler/rustc_target/src/spec/mod.rs | 2 +- compiler/rustc_target/src/spec/windows_gnullvm_base.rs | 2 +- compiler/rustc_traits/src/chalk/lowering.rs | 2 +- compiler/rustc_transmute/src/layout/tree.rs | 2 +- compiler/rustc_typeck/src/check/check.rs | 6 +++--- compiler/rustc_typeck/src/check/fn_ctxt/checks.rs | 2 +- compiler/rustc_typeck/src/expr_use_visitor.rs | 2 +- library/alloc/src/collections/linked_list.rs | 2 +- library/alloc/src/vec/mod.rs | 4 ++-- library/core/src/hint.rs | 2 +- library/core/src/intrinsics.rs | 2 +- library/core/src/ptr/const_ptr.rs | 2 +- library/core/src/ptr/mod.rs | 6 +++--- library/core/src/ptr/mut_ptr.rs | 2 +- library/core/src/slice/iter.rs | 4 ++-- library/core/src/slice/mod.rs | 4 ++-- library/core/src/time.rs | 6 +++--- .../crates/core_simd/src/masks/to_bitmask.rs | 2 +- library/std/src/keyword_docs.rs | 6 +++--- library/std/src/sys/unix/locks/fuchsia_mutex.rs | 2 +- library/std/src/sys/unix/locks/futex_mutex.rs | 2 +- library/std/src/sys/unix/locks/futex_rwlock.rs | 2 +- library/std/src/sys/windows/cmath.rs | 2 +- library/std/src/sys/windows/path/tests.rs | 2 +- src/bootstrap/bootstrap.py | 2 +- src/bootstrap/builder.rs | 4 ++-- src/bootstrap/lib.rs | 2 +- src/bootstrap/native.rs | 2 +- .../src/platform-support/m68k-unknown-linux-gnu.md | 2 +- .../rustc/src/platform-support/pc-windows-gnullvm.md | 2 +- src/doc/rustc/src/platform-support/unknown-uefi.md | 2 +- .../src/platform-support/wasm64-unknown-unknown.md | 2 +- src/doc/unstable-book/src/compiler-flags/check-cfg.md | 2 +- .../src/compiler-flags/remap-cwd-prefix.md | 2 +- src/etc/cpu-usage-over-time-plot.sh | 2 +- src/etc/htmldocck.py | 2 +- src/librustdoc/html/highlight.rs | 4 ++-- src/librustdoc/passes/collect_intra_doc_links.rs | 4 ++-- src/test/codegen/issue-34634.rs | 2 +- src/test/codegen/unwind-abis/aapcs-unwind-abi.rs | 2 +- .../codegen/unwind-abis/c-unwind-abi-panic-abort.rs | 2 +- src/test/codegen/unwind-abis/c-unwind-abi.rs | 2 +- src/test/codegen/unwind-abis/cdecl-unwind-abi.rs | 2 +- src/test/codegen/unwind-abis/fastcall-unwind-abi.rs | 2 +- .../unwind-abis/nounwind-on-stable-panic-abort.rs | 2 +- .../unwind-abis/nounwind-on-stable-panic-unwind.rs | 2 +- src/test/codegen/unwind-abis/nounwind.rs | 2 +- src/test/codegen/unwind-abis/stdcall-unwind-abi.rs | 2 +- src/test/codegen/unwind-abis/system-unwind-abi.rs | 2 +- src/test/codegen/unwind-abis/sysv64-unwind-abi.rs | 2 +- src/test/codegen/unwind-abis/thiscall-unwind-abi.rs | 2 +- src/test/codegen/unwind-abis/vectorcall-unwind-abi.rs | 2 +- src/test/codegen/unwind-abis/win64-unwind-abi.rs | 2 +- src/test/codegen/unwind-extern-exports.rs | 2 +- src/test/incremental/hygiene/load_cached_hygiene.rs | 2 +- src/test/incremental/issue-49043.rs | 2 +- .../thinlto/cgu_invalidated_when_export_added.rs | 2 +- .../thinlto/cgu_invalidated_when_export_removed.rs | 2 +- src/test/mir-opt/dest-prop/union.rs | 2 +- src/test/run-make-fulldeps/issue-64153/Makefile | 2 +- src/test/run-make/coverage-reports/Makefile | 4 ++-- .../coverage-reports/expected_show_coverage.async.txt | 2 +- src/test/run-make/coverage/async.rs | 2 +- .../run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh | 2 +- src/test/rustdoc-ui/normalize-cycle.rs | 2 +- src/test/rustdoc/elided-lifetime.rs | 2 +- src/test/rustdoc/infinite-redirection.rs | 2 +- src/test/rustdoc/macro-document-private-duplicate.rs | 2 +- .../ui/allocator/no_std-alloc-error-handler-custom.rs | 2 +- .../ui/allocator/no_std-alloc-error-handler-default.rs | 2 +- src/test/ui/associated-type-bounds/elision.rs | 2 +- src/test/ui/borrowck/two-phase-nonrecv-autoref.rs | 4 ++-- .../two-phase-reservation-sharing-interference.rs | 2 +- .../2229_closure_analysis/diagnostics/arrays.rs | 2 +- .../ui/closures/2229_closure_analysis/repr_packed.rs | 2 +- .../2229_closure_analysis/run_pass/by_value.rs | 4 ++-- .../run_pass/disjoint-capture-in-same-closure.rs | 2 +- .../run_pass/multilevel-path-1.rs | 4 ++-- .../run_pass/multilevel-path-2.rs | 2 +- .../run_pass/mut_ref_struct_mem.rs | 2 +- src/test/ui/closures/issue-84128.rs | 2 +- src/test/ui/command/command-current-dir.rs | 2 +- src/test/ui/const-generics/issues/issue-83466.rs | 2 +- src/test/ui/consts/const-eval/ub-enum.rs | 2 +- .../issue-78113-lifetime-mismatch-dyn-trait-box.rs | 2 +- src/test/ui/issues/issue-23611-enum-swap-in-drop.rs | 2 +- .../ui/iterators/issue-58952-filter-type-length.rs | 2 +- .../issue-70819-dont-override-forbid-in-same-scope.rs | 2 +- src/test/ui/never_type/fallback-closure-wrap.rs | 2 +- src/test/ui/nll/issue-21232-partial-init-and-use.rs | 2 +- src/test/ui/nll/polonius/assignment-kills-loans.rs | 2 +- src/test/ui/pattern/rest-pat-semantic-disallowed.rs | 2 +- src/test/ui/proc-macro/crt-static.rs | 2 +- .../issue-56537-closure-uses-region-from-container.rs | 2 +- src/test/ui/specialization/issue-33017.rs | 2 +- .../ui/suggestions/suggest-blanket-impl-local-trait.rs | 2 +- .../explicitly-unimplemented-error-message.rs | 2 +- src/test/ui/type/type-alias-bounds.rs | 2 +- .../ui/variance/variance-use-contravariant-struct-1.rs | 2 +- .../ui/variance/variance-use-contravariant-struct-2.rs | 2 +- .../ui/variance/variance-use-invariant-struct-1.rs | 2 +- 140 files changed, 171 insertions(+), 171 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 147ff3561a30..5de300394178 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1442,7 +1442,7 @@ Compatibility Notes - [Mixing Option and Result via `?` is no longer permitted in closures for inferred types.][86831] - [Previously unsound code is no longer permitted where different constructors in branches could require different lifetimes.][85574] -- As previously mentioned the [`std::arch` instrinsics now uses stricter const checking][83278] +- As previously mentioned the [`std::arch` intrinsic now uses stricter const checking][83278] than before and may reject some previously accepted code. - [`i128` multiplication on Cortex M0+ platforms currently unconditionally causes overflow when compiled with `codegen-units = 1`.][86063] @@ -2520,7 +2520,7 @@ Compatibility Notes - [Fixed a regression parsing `{} && false` in tail expressions.][74650] - [Added changes to how proc-macros are expanded in `macro_rules!` that should help to preserve more span information.][73084] These changes may cause - compiliation errors if your macro was unhygenic or didn't correctly handle + compilation errors if your macro was unhygenic or didn't correctly handle `Delimiter::None`. - [Moved support for the CloudABI target to tier 3.][75568] - [`linux-gnu` targets now require minimum kernel 2.6.32 and glibc 2.11.][74163] diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 5e9e8aa553d9..3604a85367ab 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1177,7 +1177,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) -> hir::Ty<'hir> { // Check whether we should interpret this as a bare trait object. // This check mirrors the one in late resolution. We only introduce this special case in - // the rare occurence we need to lower `Fresh` anonymous lifetimes. + // the rare occurrence we need to lower `Fresh` anonymous lifetimes. // The other cases when a qpath should be opportunistically made a trait object are handled // by `ty_path`. if qself.is_none() diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index c36c4ad54da4..23464bf0a5a2 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1800,7 +1800,7 @@ pub(crate) enum ForbiddenLetReason { NotSupportedOr(Span), /// A let chain with invalid parentheses /// - /// For exemple, `let 1 = 1 && (expr && expr)` is allowed + /// For example, `let 1 = 1 && (expr && expr)` is allowed /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not NotSupportedParentheses(Span), } diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 815450f689e4..0497c2570e62 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -342,7 +342,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( let ret_place = codegen_place(fx, destination); - // Handle special calls like instrinsics and empty drop glue. + // Handle special calls like intrinsics and empty drop glue. let instance = if let ty::FnDef(def_id, substs) = *fn_ty.kind() { let instance = ty::Instance::resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, substs) .unwrap() diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index cb5d73a7e0ba..9224f499339c 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -59,7 +59,7 @@ pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, '_>) -> bool { ErrorHandled::TooGeneric => { span_bug!( constant.span, - "codgen encountered polymorphic constant: {:?}", + "codegen encountered polymorphic constant: {:?}", err ); } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 95239f415a99..4aeb1e3aab95 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -203,7 +203,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( sym::transmute => { crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", source_info); } - _ => unimplemented!("unsupported instrinsic {}", intrinsic), + _ => unimplemented!("unsupported intrinsics {}", intrinsic), } return; }; diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 32b340832ce2..8d7e2c5cf393 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -540,7 +540,7 @@ pub fn linking_symbol_name_for_instance_in_crate<'tcx>( .map(|fnabi| (fnabi.conv, &fnabi.args[..])) .unwrap_or((Conv::Rust, &[])); - // Decorate symbols with prefices, suffices and total number of bytes of arguments. + // Decorate symbols with prefixes, suffixes and total number of bytes of arguments. // Reference: https://docs.microsoft.com/en-us/cpp/build/reference/decorated-names?view=msvc-170 let (prefix, suffix) = match conv { Conv::X86Fastcall => ("@", "@"), diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index d6bbcd992345..2b931bfc91d6 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -191,7 +191,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // errored or at least linted ErrorHandled::Reported(_) | ErrorHandled::Linted => {} ErrorHandled::TooGeneric => { - span_bug!(const_.span, "codgen encountered polymorphic constant: {:?}", err) + span_bug!(const_.span, "codegen encountered polymorphic constant: {:?}", err) } } } diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index a8ec8447f64a..adda9639990d 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -320,7 +320,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let (a_offset, b_offset) = match (self.ptr_try_get_alloc_id(a), self.ptr_try_get_alloc_id(b)) { (Err(a), Err(b)) => { - // Neither poiner points to an allocation. + // Neither pointer points to an allocation. // If these are inequal or null, this *will* fail the deref check below. (a, b) } diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 69dbc9592fa8..ed155fbfef08 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -437,7 +437,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { msg, }) } - // Ensure we never consider the null pointer dereferencable. + // Ensure we never consider the null pointer dereferenceable. if M::Provenance::OFFSET_IS_ADDR { assert_ne!(ptr.addr(), Size::ZERO); } @@ -914,7 +914,7 @@ impl<'tcx, 'a, Prov: Provenance, Extra> AllocRefMut<'a, 'tcx, Prov, Extra> { self.write_scalar(alloc_range(offset, self.tcx.data_layout().pointer_size), val) } - /// Mark the entire referenced range as uninitalized + /// Mark the entire referenced range as uninitialized pub fn write_uninit(&mut self) -> InterpResult<'tcx> { Ok(self .alloc diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index 67dc9011ea20..77da8f1041ee 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -1,6 +1,6 @@ //! This file implements "place projections"; basically a symmetric API for 3 types: MPlaceTy, OpTy, PlaceTy. //! -//! OpTy and PlaceTy genrally work by "let's see if we are actually an MPlaceTy, and do something custom if not". +//! OpTy and PlaceTy generally work by "let's see if we are actually an MPlaceTy, and do something custom if not". //! For PlaceTy, the custom thing is basically always to call `force_allocation` and then use the MPlaceTy logic anyway. //! For OpTy, the custom thing on field pojections has to be pretty clever (since `Operand::Immediate` can have fields), //! but for array/slice operations it only has to worry about `Operand::Uninit`. That makes the value part trivial, diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index a71a5d4b833c..ea366eba7724 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -217,7 +217,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // When comparing the PassMode, we have to be smart about comparing the attributes. let arg_attr_compat = |a1: &ArgAttributes, a2: &ArgAttributes| { // There's only one regular attribute that matters for the call ABI: InReg. - // Everything else is things like noalias, dereferencable, nonnull, ... + // Everything else is things like noalias, dereferenceable, nonnull, ... // (This also applies to pointee_size, pointee_align.) if a1.regular.contains(ArgAttribute::InReg) != a2.regular.contains(ArgAttribute::InReg) { @@ -556,7 +556,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { .tcx .struct_tail_erasing_lifetimes(receiver_place.layout.ty, self.param_env); let ty::Dynamic(data, ..) = receiver_tail.kind() else { - span_bug!(self.cur_span(), "dyanmic call on non-`dyn` type {}", receiver_tail) + span_bug!(self.cur_span(), "dynamic call on non-`dyn` type {}", receiver_tail) }; // Get the required information from the vtable. diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs index b3a511d5a492..cab23b7241ff 100644 --- a/compiler/rustc_const_eval/src/interpret/traits.rs +++ b/compiler/rustc_const_eval/src/interpret/traits.rs @@ -32,7 +32,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(vtable_ptr.into()) } - /// Returns a high-level representation of the entires of the given vtable. + /// Returns a high-level representation of the entries of the given vtable. pub fn get_vtable_entries( &self, vtable: Pointer>, diff --git a/compiler/rustc_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs index 5ff2d18dd2be..a39178016ce2 100644 --- a/compiler/rustc_data_structures/src/fingerprint.rs +++ b/compiler/rustc_data_structures/src/fingerprint.rs @@ -29,7 +29,7 @@ impl Fingerprint { // quality hash values, let's still combine the two values because the // Fingerprints in DefPathHash have the StableCrateId portion which is // the same for all DefPathHashes from the same crate. Combining the - // two halfs makes sure we get a good quality hash in such cases too. + // two halves makes sure we get a good quality hash in such cases too. self.0.wrapping_mul(3).wrapping_add(self.1) } @@ -120,7 +120,7 @@ impl FingerprintHasher for crate::unhash::Unhasher { // quality hash values, let's still combine the two values because the // Fingerprints in DefPathHash have the StableCrateId portion which is // the same for all DefPathHashes from the same crate. Combining the - // two halfs makes sure we get a good quality hash in such cases too. + // two halves makes sure we get a good quality hash in such cases too. // // Since `Unhasher` is used only in the context of HashMaps, it is OK // to combine the two components in an order-independent way (which is diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 4fa91dfeaea2..c8bdc39311c6 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -430,7 +430,7 @@ impl TtParser { } } MatcherLoc::Delimited => { - // Entering the delimeter is trivial. + // Entering the delimiter is trivial. mp.idx += 1; self.cur_mps.push(mp); } diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index e009e4f7c68d..86dbd33a221f 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -976,7 +976,7 @@ impl<'tt> TokenSet<'tt> { self.maybe_empty = false; } - // Adds `tok` to the set for `self`, marking sequence as non-empy. + // Adds `tok` to the set for `self`, marking sequence as non-empty. fn add_one(&mut self, tt: TtHandle<'tt>) { if !self.tokens.contains(&tt) { self.tokens.push(tt); diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index 1a2ab9d190eb..b34ab15efe89 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -173,7 +173,7 @@ impl MultiItemModifier for DeriveProcMacro { // fail if there have been errors emitted if ecx.sess.parse_sess.span_diagnostic.err_count() > error_count_before { - ecx.struct_span_err(span, "proc-macro derive produced unparseable tokens").emit(); + ecx.struct_span_err(span, "proc-macro derive produced unparsable tokens").emit(); } ExpandResult::Ready(items) diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index e990fe7ecb50..91a05367eee0 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -199,7 +199,7 @@ fn ty_to_string<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String { } /// We don't want to directly use `ty_to_string` for closures as their type isn't really -/// something users are familar with. Directly printing the `fn_sig` of closures also +/// something users are familiar with. Directly printing the `fn_sig` of closures also /// doesn't work as they actually use the "rust-call" API. fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'_, 'tcx>, ty: Ty<'tcx>) -> String { let ty::Closure(_, substs) = ty.kind() else { unreachable!() }; diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 60ebf8b949d2..fe037a458a7f 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1333,7 +1333,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// `resolve_vars_if_possible` as well as `fully_resolve`. /// /// Make sure to call [`InferCtxt::process_registered_region_obligations`] - /// first, or preferrably use [`InferCtxt::check_region_obligations_and_report_errors`] + /// first, or preferably use [`InferCtxt::check_region_obligations_and_report_errors`] /// to do both of these operations together. pub fn resolve_regions_and_report_errors( &self, diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs index 74a26ebc39f8..611961ab1cc9 100644 --- a/compiler/rustc_infer/src/infer/undo_log.rs +++ b/compiler/rustc_infer/src/infer/undo_log.rs @@ -100,7 +100,7 @@ impl Default for InferCtxtUndoLogs<'_> { } /// The UndoLogs trait defines how we undo a particular kind of action (of type T). We can undo any -/// action that is convertable into an UndoLog (per the From impls above). +/// action that is convertible into an UndoLog (per the From impls above). impl<'tcx, T> UndoLogs for InferCtxtUndoLogs<'tcx> where UndoLog<'tcx>: From, diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index dc4799e4afce..1c6243c275c0 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -176,7 +176,7 @@ pub fn parse_check_cfg(specs: Vec) -> CheckCfg { let ident = arg.ident().expect("multi-segment cfg key"); names_valid.insert(ident.name.to_string()); } else { - error!("`names()` arguments must be simple identifers"); + error!("`names()` arguments must be simple identifiers"); } } continue 'specs; @@ -204,7 +204,7 @@ pub fn parse_check_cfg(specs: Vec) -> CheckCfg { continue 'specs; } else { error!( - "`values()` first argument must be a simple identifer" + "`values()` first argument must be a simple identifier" ); } } else if args.is_empty() { diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 58b2f0a44161..1f4e5b480917 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -268,7 +268,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { }, ty::Closure(..) => { cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| { - // FIXME(davidtwco): this isn't properly translatable becauses of the + // FIXME(davidtwco): this isn't properly translatable because of the // pre/post strings lint.build(fluent::lint::unused_closure) .set_arg("count", plural_len) @@ -281,7 +281,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { } ty::Generator(..) => { cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| { - // FIXME(davidtwco): this isn't properly translatable becauses of the + // FIXME(davidtwco): this isn't properly translatable because of the // pre/post strings lint.build(fluent::lint::unused_generator) .set_arg("count", plural_len) @@ -310,7 +310,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { ) -> bool { if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) { cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| { - // FIXME(davidtwco): this isn't properly translatable becauses of the pre/post + // FIXME(davidtwco): this isn't properly translatable because of the pre/post // strings let mut err = lint.build(fluent::lint::unused_def); err.set_arg("pre", descr_pre_path); diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 2dca6acdd6d6..845563338eaa 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3206,7 +3206,7 @@ declare_lint! { /// [future-incompatible]: ../index.md#future-incompatible-lints pub REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, Warn, - "tranparent type contains an external ZST that is marked #[non_exhaustive] or contains private fields", + "transparent type contains an external ZST that is marked #[non_exhaustive] or contains private fields", @future_incompatible = FutureIncompatibleInfo { reference: "issue #78586 ", }; diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index 78080fcd581f..752cbdeae6b2 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -86,7 +86,7 @@ impl<'tcx> BasicBlocks<'tcx> { /// /// You will only ever need this if you have also called [`BasicBlocks::as_mut_preserves_cfg`]. /// All other methods that allow you to mutate the basic blocks also call this method - /// themselves, thereby avoiding any risk of accidentaly cache invalidation. + /// themselves, thereby avoiding any risk of accidentally cache invalidation. pub fn invalidate_cfg_cache(&mut self) { self.predecessor_cache.invalidate(); self.switch_source_cache.invalidate(); diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 7784449d605e..560d9fde0492 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1457,7 +1457,7 @@ pub struct PlaceRef<'tcx> { // Once we stop implementing `Ord` for `DefId`, // this impl will be unnecessary. Until then, we'll // leave this impl in place to prevent re-adding a -// dependnecy on the `Ord` impl for `DefId` +// dependency on the `Ord` impl for `DefId` impl<'tcx> !PartialOrd for PlaceRef<'tcx> {} impl<'tcx> Place<'tcx> { diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 3426f5f43f0b..d7b9d59eced5 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -332,7 +332,7 @@ pub enum StatementKind<'tcx> { /// First, all three operands are evaluated. `src` and `dest` must each be a reference, pointer, /// or `Box` pointing to the same type `T`. `count` must evaluate to a `usize`. Then, `src` and /// `dest` are dereferenced, and `count * size_of::()` bytes beginning with the first byte of - /// the `src` place are copied to the continguous range of bytes beginning with the first byte + /// the `src` place are copied to the contiguous range of bytes beginning with the first byte /// of `dest`. /// /// **Needs clarification**: In what order are operands computed and dereferenced? It should @@ -378,7 +378,7 @@ pub enum FakeReadCause { /// Some(closure_def_id). /// Otherwise, the value of the optional LocalDefId will be None. // - // We can use LocaDefId here since fake read statements are removed + // We can use LocalDefId here since fake read statements are removed // before codegen in the `CleanupNonCodegenStatements` pass. ForMatchedPlace(Option), diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index ddca9820da1a..abaef0354ade 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1151,7 +1151,7 @@ rustc_queries! { /// Used by rustdoc. query rendered_const(def_id: DefId) -> String { storage(ArenaCacheSelector<'tcx>) - desc { |tcx| "rendering constant intializer of `{}`", tcx.def_path_str(def_id) } + desc { |tcx| "rendering constant initializer of `{}`", tcx.def_path_str(def_id) } cache_on_disk_if { def_id.is_local() } separate_provide_extern } diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs index 2465f8e2533e..0a2819feecf0 100644 --- a/compiler/rustc_middle/src/traits/specialization_graph.rs +++ b/compiler/rustc_middle/src/traits/specialization_graph.rs @@ -115,7 +115,7 @@ impl Node { matches!(self, Node::Trait(..)) } - /// Trys to find the associated item that implements `trait_item_def_id` + /// Tries to find the associated item that implements `trait_item_def_id` /// defined in this node. /// /// If this returns `None`, the item can potentially still be found in diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 0f34aa10a125..dc3f2ae20876 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1498,17 +1498,17 @@ impl<'tcx> TyCtxt<'tcx> { // Create a dependency to the crate to be sure we re-execute this when the amount of // definitions change. self.ensure().hir_crate(()); - // Leak a read lock once we start iterating on definitions, to prevent adding new onces + // Leak a read lock once we start iterating on definitions, to prevent adding new ones // while iterating. If some query needs to add definitions, it should be `ensure`d above. let definitions = self.definitions.leak(); definitions.iter_local_def_id() } pub fn def_path_table(self) -> &'tcx rustc_hir::definitions::DefPathTable { - // Create a dependency to the crate to be sure we reexcute this when the amount of + // Create a dependency to the crate to be sure we re-execute this when the amount of // definitions change. self.ensure().hir_crate(()); - // Leak a read lock once we start iterating on definitions, to prevent adding new onces + // Leak a read lock once we start iterating on definitions, to prevent adding new ones // while iterating. If some query needs to add definitions, it should be `ensure`d above. let definitions = self.definitions.leak(); definitions.def_path_table() @@ -1517,10 +1517,10 @@ impl<'tcx> TyCtxt<'tcx> { pub fn def_path_hash_to_def_index_map( self, ) -> &'tcx rustc_hir::def_path_hash_map::DefPathHashMap { - // Create a dependency to the crate to be sure we reexcute this when the amount of + // Create a dependency to the crate to be sure we re-execute this when the amount of // definitions change. self.ensure().hir_crate(()); - // Leak a read lock once we start iterating on definitions, to prevent adding new onces + // Leak a read lock once we start iterating on definitions, to prevent adding new ones // while iterating. If some query needs to add definitions, it should be `ensure`d above. let definitions = self.definitions.leak(); definitions.def_path_hash_to_def_index_map() diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 42b5d5a6efd7..a1d980af921a 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -266,7 +266,7 @@ impl<'tcx> Generics { // Filter the default arguments. // // This currently uses structural equality instead - // of semantic equivalance. While not ideal, that's + // of semantic equivalence. While not ideal, that's // good enough for now as this should only be used // for diagnostics anyways. own_params.end -= self diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 980bb8e86155..26b60e4f3398 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -756,7 +756,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // * the element type and length of the single array field, if // the first field is of array type, or // - // * the homogenous field type and the number of fields. + // * the homogeneous field type and the number of fields. let (e_ty, e_len, is_array) = if let ty::Array(e_ty, _) = f0_ty.kind() { // First ADT field is an array: diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 080dab030316..2ca6d7628466 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -702,7 +702,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let local_id = self.var_local_id(var, for_guard); let source_info = self.source_info(span); self.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(local_id) }); - // Altough there is almost always scope for given variable in corner cases + // Although there is almost always scope for given variable in corner cases // like #92893 we might get variable with no scope. if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) && schedule_drop{ self.schedule_drop(span, region_scope, local_id, DropKind::Storage); diff --git a/compiler/rustc_monomorphize/src/util.rs b/compiler/rustc_monomorphize/src/util.rs index 847e64dc2a2f..6a4d2df1ead1 100644 --- a/compiler/rustc_monomorphize/src/util.rs +++ b/compiler/rustc_monomorphize/src/util.rs @@ -13,7 +13,7 @@ pub(crate) fn dump_closure_profile<'tcx>(tcx: TyCtxt<'tcx>, closure_instance: In .append(true) .open(&format!("closure_profile_{}.csv", std::process::id())) else { - eprintln!("Cound't open file for writing closure profile"); + eprintln!("Couldn't open file for writing closure profile"); return; }; diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index c85416095144..be00e57b9322 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1578,7 +1578,7 @@ impl<'a> Parser<'a> { Applicability::MachineApplicable, ); - // Replace `'label: non_block_expr` with `'label: {non_block_expr}` in order to supress future errors about `break 'label`. + // Replace `'label: non_block_expr` with `'label: {non_block_expr}` in order to suppress future errors about `break 'label`. let stmt = self.mk_stmt(span, StmtKind::Expr(expr)); let blk = self.mk_block(vec![stmt], BlockCheckMode::Default, span); self.mk_expr(span, ExprKind::Block(blk, label)) @@ -2578,7 +2578,7 @@ impl<'a> Parser<'a> { } pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> { - // Used to check the `let_chains` and `if_let_guard` features mostly by scaning + // Used to check the `let_chains` and `if_let_guard` features mostly by scanning // `&&` tokens. fn check_let_expr(expr: &Expr) -> (bool, bool) { match expr.kind { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index f6516d3bd454..5e79308464f6 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -281,7 +281,7 @@ impl TokenCursor { if delim != Delimiter::Invisible { return (Token::new(token::OpenDelim(delim), sp.open), Spacing::Alone); } - // No open delimeter to return; continue on to the next iteration. + // No open delimiter to return; continue on to the next iteration. } }; } else if let Some(frame) = self.stack.pop() { diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 399d00b403a6..fb1d724d9d83 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -49,7 +49,7 @@ impl Node { /// /// For example, `ast::Visitor` has `visit_ident`, but `Ident`s are always /// stored inline within other AST nodes, so we don't implement `visit_ident` -/// here. In constrast, we do implement `visit_expr` because `ast::Expr` is +/// here. In contrast, we do implement `visit_expr` because `ast::Expr` is /// always stored as `P`, and every such expression should be /// measured separately. /// diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 6ea976a59006..661aadea9444 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -1368,7 +1368,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { return; } - // We may fail to resolve higher-ranked lifetimes that are mentionned by APIT. + // We may fail to resolve higher-ranked lifetimes that are mentioned by APIT. // AST-based resolution does not care for impl-trait desugaring, which are the // responibility of lowering. This may create a mismatch between the resolution // AST found (`region_def_id`) which points to HRTB, and what HIR allows. diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 66090c96d1ee..5c33cb694a76 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1991,7 +1991,7 @@ impl<'a> Resolver<'a> { _ => panic!("invalid arg index"), } } - // Cache the lookup to avoid parsing attributes for an iterm multiple times. + // Cache the lookup to avoid parsing attributes for an item multiple times. self.legacy_const_generic_args.insert(def_id, Some(ret.clone())); return Some(ret); } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 0c428aa6cc05..dafa10e9e002 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -441,7 +441,7 @@ impl<'a> ResolverExpand for Resolver<'a> { } PathResult::Indeterminate => indeterminate = true, // We can only be sure that a path doesn't exist after having tested all the - // posibilities, only at that time we can return false. + // possibilities, only at that time we can return false. PathResult::Failed { .. } => {} PathResult::Module(_) => panic!("unexpected path resolution"), } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 8d00129b1b1d..1c69596b2052 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2309,7 +2309,7 @@ impl Target { load_builtin(target_triple).expect("built-in target") } TargetTriple::TargetJson { .. } => { - panic!("built-in targets doens't support target-paths") + panic!("built-in targets doesn't support target-paths") } } } diff --git a/compiler/rustc_target/src/spec/windows_gnullvm_base.rs b/compiler/rustc_target/src/spec/windows_gnullvm_base.rs index bae007dc9f3b..f30be25497d8 100644 --- a/compiler/rustc_target/src/spec/windows_gnullvm_base.rs +++ b/compiler/rustc_target/src/spec/windows_gnullvm_base.rs @@ -3,7 +3,7 @@ use crate::spec::{cvs, LinkerFlavor, TargetOptions}; pub fn opts() -> TargetOptions { // We cannot use `-nodefaultlibs` because compiler-rt has to be passed // as a path since it's not added to linker search path by the default. - // There were attemts to make it behave like libgcc (so one can just use -l) + // There were attempts to make it behave like libgcc (so one can just use -l) // but LLVM maintainers rejected it: https://reviews.llvm.org/D51440 let pre_link_args = TargetOptions::link_args(LinkerFlavor::Gcc, &["-nolibc", "--unwindlib=none"]); diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index c7c604e14e3e..a166371fed1e 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -191,7 +191,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> for ty::Predi GenericArgKind::Const(..) => { chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner)) } - GenericArgKind::Lifetime(lt) => bug!("unexpect well formed predicate: {:?}", lt), + GenericArgKind::Lifetime(lt) => bug!("unexpected well formed predicate: {:?}", lt), }, ty::PredicateKind::ObjectSafe(t) => chalk_ir::GoalData::DomainGoal( diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index 93cab7ca5339..4ab6d3737c59 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -416,7 +416,7 @@ pub(crate) mod rustc { // begin with the field's visibility tree = tree.then(Self::def(Def::Field(field_def))); - // compute the field's layout charactaristics + // compute the field's layout characteristics let field_layout = layout_of(tcx, field_ty)?.clamp_align(min_align, max_align); // next comes the field's padding diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 5cdb2acd9f3c..29a128f27b84 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -101,7 +101,7 @@ pub(super) fn check_fn<'a, 'tcx>( decl.output.span(), param_env, )); - // If we replaced declared_ret_ty with infer vars, then we must be infering + // If we replaced declared_ret_ty with infer vars, then we must be inferring // an opaque type, so set a flag so we can improve diagnostics. fcx.return_type_has_opaque = ret_ty != declared_ret_ty; @@ -1543,7 +1543,7 @@ fn detect_discriminant_duplicate<'tcx>( None => { // At this point we know this discriminant is a duplicate, and was not explicitly // assigned by the user. Here we iterate backwards to fetch the HIR for the last - // explictly assigned discriminant, and letting the user know that this was the + // explicitly assigned discriminant, and letting the user know that this was the // increment startpoint, and how many steps from there leading to the duplicate if let Some((n, hir::Variant { span, ident, .. })) = vs[..idx].iter().rev().enumerate().find(|v| v.1.disr_expr.is_some()) @@ -1566,7 +1566,7 @@ fn detect_discriminant_duplicate<'tcx>( }; // Here we loop through the discriminants, comparing each discriminant to another. - // When a duplicate is detected, we instatiate an error and point to both + // When a duplicate is detected, we instantiate an error and point to both // initial and duplicate value. The duplicate discriminant is then discarded by swapping // it with the last element and decrementing the `vec.len` (which is why we have to evaluate // `discrs.len()` anew every iteration, and why this could be tricky to do in a functional diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 03bd485096a9..7ff4aef2d257 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -153,7 +153,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { let tcx = self.tcx; - // Conceptually, we've got some number of expected inputs, and some number of provided aguments + // Conceptually, we've got some number of expected inputs, and some number of provided arguments // and we can form a grid of whether each argument could satisfy a given input: // in1 | in2 | in3 | ... // arg1 ? | | | diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index 74a5b6e42c30..bfc4f061b70f 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -497,7 +497,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { let expr_place = return_if_err!(self.mc.cat_expr(expr)); f(self); if let Some(els) = els { - // borrowing because we need to test the descriminant + // borrowing because we need to test the discriminant self.maybe_read_scrutinee(expr, expr_place.clone(), from_ref(pat).iter()); self.walk_block(els) } diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index e21c8aa3bd53..6480fcaf93d4 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -1570,7 +1570,7 @@ impl<'a, T> CursorMut<'a, T> { /// that the cursor points to is unchanged, even if it is the "ghost" node. /// /// This operation should compute in *O*(1) time. - // `push_front` continues to point to "ghost" when it addes a node to mimic + // `push_front` continues to point to "ghost" when it adds a node to mimic // the behavior of `insert_before` on an empty list. #[unstable(feature = "linked_list_cursors", issue = "58533")] pub fn push_front(&mut self, elt: T) { diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 1f19b9e59454..60b36af5e67f 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -436,7 +436,7 @@ impl Vec { /// an explanation of the difference between length and capacity, see /// *[Capacity and reallocation]*. /// - /// If it is imporant to know the exact allocated capacity of a `Vec`, + /// If it is important to know the exact allocated capacity of a `Vec`, /// always use the [`capacity`] method after construction. /// /// For `Vec` where `T` is a zero-sized type, there will be no allocation @@ -591,7 +591,7 @@ impl Vec { /// an explanation of the difference between length and capacity, see /// *[Capacity and reallocation]*. /// - /// If it is imporant to know the exact allocated capacity of a `Vec`, + /// If it is important to know the exact allocated capacity of a `Vec`, /// always use the [`capacity`] method after construction. /// /// For `Vec` where `T` is a zero-sized type, there will be no allocation diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 81b6d5737ea7..20340d42962e 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -31,7 +31,7 @@ use crate::intrinsics; /// /// `unreachable_unchecked()` can be used in situations where the compiler /// can't prove invariants that were previously established. Such situations -/// have a higher chance of occuring if those invariants are upheld by +/// have a higher chance of occurring if those invariants are upheld by /// external code that the compiler can't analyze. /// ``` /// fn prepare_inputs(divisors: &mut Vec) { diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 5f8e6efa0cf5..d610f0a02f40 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1082,7 +1082,7 @@ extern "rust-intrinsic" { /// Note that using `transmute` to turn a pointer to a `usize` is (as noted above) [undefined /// behavior][ub] in `const` contexts. Also outside of consts, this operation might not behave /// as expected -- this is touching on many unspecified aspects of the Rust memory model. - /// Depending on what the code is doing, the following alternatives are preferrable to + /// Depending on what the code is doing, the following alternatives are preferable to /// pointer-to-integer transmutation: /// - If the code just wants to store data of arbitrary type in some buffer and needs to pick a /// type for that buffer, it can use [`MaybeUninit`][mem::MaybeUninit]. diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index ef7b3b1d1470..f5c72d797553 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -154,7 +154,7 @@ impl *const T { /// This is similar to `self as usize`, which semantically discards *provenance* and /// *address-space* information. However, unlike `self as usize`, casting the returned address /// back to a pointer yields [`invalid`][], which is undefined behavior to dereference. To - /// properly restore the lost information and obtain a dereferencable pointer, use + /// properly restore the lost information and obtain a dereferenceable pointer, use /// [`with_addr`][pointer::with_addr] or [`map_addr`][pointer::map_addr]. /// /// If using those APIs is not possible because there is no way to preserve a pointer with the diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 203531f66aa3..41a2685d361c 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -90,7 +90,7 @@ //! isn't *pointer*-sized but address-space/offset/allocation-sized (we'll probably continue //! to conflate these notions). This would potentially make it possible to more efficiently //! target platforms where pointers are larger than offsets, such as CHERI and maybe some -//! segmented architecures. +//! segmented architectures. //! //! ## Provenance //! @@ -172,7 +172,7 @@ //! a pointer to a usize is generally an operation which *only* extracts the address. It is //! therefore *impossible* to construct a valid pointer from a usize because there is no way //! to restore the address-space and provenance. In other words, pointer-integer-pointer -//! roundtrips are not possible (in the sense that the resulting pointer is not dereferencable). +//! roundtrips are not possible (in the sense that the resulting pointer is not dereferenceable). //! //! The key insight to making this model *at all* viable is the [`with_addr`][] method: //! @@ -272,7 +272,7 @@ //! //! * Create an invalid pointer from just an address (see [`ptr::invalid`][]). This can //! be used for sentinel values like `null` *or* to represent a tagged pointer that will -//! never be dereferencable. In general, it is always sound for an integer to pretend +//! never be dereferenceable. In general, it is always sound for an integer to pretend //! to be a pointer "for fun" as long as you don't use operations on it which require //! it to be valid (offset, read, write, etc). //! diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 6a3b9ee9a7da..3e4c3ae07567 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -160,7 +160,7 @@ impl *mut T { /// This is similar to `self as usize`, which semantically discards *provenance* and /// *address-space* information. However, unlike `self as usize`, casting the returned address /// back to a pointer yields [`invalid`][], which is undefined behavior to dereference. To - /// properly restore the lost information and obtain a dereferencable pointer, use + /// properly restore the lost information and obtain a dereferenceable pointer, use /// [`with_addr`][pointer::with_addr] or [`map_addr`][pointer::map_addr]. /// /// If using those APIs is not possible because there is no way to preserve a pointer with the diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index f43b780ec9a9..395c5678451c 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -2754,10 +2754,10 @@ impl<'a, T> Iterator for RChunksMut<'a, T> { None => 0, }; // SAFETY: This type ensures that self.v is a valid pointer with a correct len. - // Therefore the bounds check in split_at_mut guarantess the split point is inbounds. + // Therefore the bounds check in split_at_mut guarantees the split point is inbounds. let (head, tail) = unsafe { self.v.split_at_mut(start) }; // SAFETY: This type ensures that self.v is a valid pointer with a correct len. - // Therefore the bounds check in split_at_mut guarantess the split point is inbounds. + // Therefore the bounds check in split_at_mut guarantees the split point is inbounds. let (nth, _) = unsafe { tail.split_at_mut(end - start) }; self.v = head; // SAFETY: Nothing else points to or will point to the contents of this slice. diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index d5706c388f00..3bd296f37caf 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -2321,7 +2321,7 @@ impl [T] { } /// Binary searches this slice for a given element. - /// This behaves similary to [`contains`] if this slice is sorted. + /// This behaves similar to [`contains`] if this slice is sorted. /// /// If the value is found then [`Result::Ok`] is returned, containing the /// index of the matching element. If there are multiple matches, then any @@ -3530,7 +3530,7 @@ impl [T] { // alignment targeted for U. // `crate::ptr::align_offset` is called with a correctly aligned and // valid pointer `ptr` (it comes from a reference to `self`) and with - // a size that is a power of two (since it comes from the alignement for U), + // a size that is a power of two (since it comes from the alignment for U), // satisfying its safety constraints. let offset = unsafe { crate::ptr::align_offset(ptr, mem::align_of::()) }; if offset > self.len() { diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 153dc4dbb083..4f29ecc0fba8 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -1280,7 +1280,7 @@ macro_rules! try_from_secs { let rem_msb = nanos_tmp & rem_msb_mask == 0; let add_ns = !(rem_msb || (is_even && is_tie)); - // f32 does not have enough presicion to trigger the second branch + // f32 does not have enough precision to trigger the second branch // since it can not represent numbers between 0.999_999_940_395 and 1.0. let nanos = nanos + add_ns as u32; if ($mant_bits == 23) || (nanos != NANOS_PER_SEC) { (0, nanos) } else { (1, 0) } @@ -1299,9 +1299,9 @@ macro_rules! try_from_secs { let rem_msb = nanos_tmp & rem_msb_mask == 0; let add_ns = !(rem_msb || (is_even && is_tie)); - // f32 does not have enough presicion to trigger the second branch. + // f32 does not have enough precision to trigger the second branch. // For example, it can not represent numbers between 1.999_999_880... - // and 2.0. Bigger values result in even smaller presicion of the + // and 2.0. Bigger values result in even smaller precision of the // fractional part. let nanos = nanos + add_ns as u32; if ($mant_bits == 23) || (nanos != NANOS_PER_SEC) { diff --git a/library/portable-simd/crates/core_simd/src/masks/to_bitmask.rs b/library/portable-simd/crates/core_simd/src/masks/to_bitmask.rs index 65d3ce9be65e..2235f016c714 100644 --- a/library/portable-simd/crates/core_simd/src/masks/to_bitmask.rs +++ b/library/portable-simd/crates/core_simd/src/masks/to_bitmask.rs @@ -70,7 +70,7 @@ impl_integer_intrinsic! { impl ToBitMask for Mask<_, 64> } -/// Returns the minimum numnber of bytes in a bitmask with `lanes` lanes. +/// Returns the minimum number of bytes in a bitmask with `lanes` lanes. #[cfg(feature = "generic_const_exprs")] pub const fn bitmask_len(lanes: usize) -> usize { (lanes + 7) / 8 diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index 7157b5af00cf..a4b0522b0502 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -1921,7 +1921,7 @@ mod type_keyword {} /// and [proposal]s exist to use `unsafe {}` blocks inside such functions when /// making `unsafe` operations. /// -/// See the [Rustnomicon] and the [Reference] for more informations. +/// See the [Rustnomicon] and the [Reference] for more information. /// /// # Examples /// @@ -2113,7 +2113,7 @@ mod use_keyword {} /// Add constraints that must be upheld to use an item. /// /// `where` allows specifying constraints on lifetime and generic parameters. -/// The [RFC] introducing `where` contains detailed informations about the +/// The [RFC] introducing `where` contains detailed information about the /// keyword. /// /// # Examples @@ -2355,7 +2355,7 @@ mod dyn_keyword {} /// println!("f = {f} and i = {i}"); /// ``` /// -/// See the [Reference][union] for more informations on `union`s. +/// See the [Reference][union] for more information on `union`s. /// /// [`struct`]: keyword.struct.html /// [union]: ../reference/items/unions.html diff --git a/library/std/src/sys/unix/locks/fuchsia_mutex.rs b/library/std/src/sys/unix/locks/fuchsia_mutex.rs index ce427599c3bd..dbb9829bb666 100644 --- a/library/std/src/sys/unix/locks/fuchsia_mutex.rs +++ b/library/std/src/sys/unix/locks/fuchsia_mutex.rs @@ -138,7 +138,7 @@ impl Mutex { } } - // The state has changed or a wakeup occured, try to lock the mutex. + // The state has changed or a wakeup occurred, try to lock the mutex. match self.futex.compare_exchange(UNLOCKED, owned_state, Acquire, Relaxed) { Ok(_) => return, Err(updated) => state = updated, diff --git a/library/std/src/sys/unix/locks/futex_mutex.rs b/library/std/src/sys/unix/locks/futex_mutex.rs index 99ba86e5f996..1b5be46c6050 100644 --- a/library/std/src/sys/unix/locks/futex_mutex.rs +++ b/library/std/src/sys/unix/locks/futex_mutex.rs @@ -53,7 +53,7 @@ impl Mutex { // We avoid an unnecessary write if it as already set to 2, // to be friendlier for the caches. if state != 2 && self.futex.swap(2, Acquire) == 0 { - // We changed it from 0 to 2, so we just succesfully locked it. + // We changed it from 0 to 2, so we just successfully locked it. return; } diff --git a/library/std/src/sys/unix/locks/futex_rwlock.rs b/library/std/src/sys/unix/locks/futex_rwlock.rs index b3bbbf743f84..0cc92244ecad 100644 --- a/library/std/src/sys/unix/locks/futex_rwlock.rs +++ b/library/std/src/sys/unix/locks/futex_rwlock.rs @@ -54,7 +54,7 @@ fn is_read_lockable(state: u32) -> bool { // We don't allow read-locking if there's readers waiting, even if the lock is unlocked // and there's no writers waiting. The only situation when this happens is after unlocking, // at which point the unlocking thread might be waking up writers, which have priority over readers. - // The unlocking thread will clear the readers waiting bit and wake up readers, if necssary. + // The unlocking thread will clear the readers waiting bit and wake up readers, if necessary. state & MASK < MAX_READERS && !has_readers_waiting(state) && !has_writers_waiting(state) } diff --git a/library/std/src/sys/windows/cmath.rs b/library/std/src/sys/windows/cmath.rs index 1a5421facd0c..74bb552527f6 100644 --- a/library/std/src/sys/windows/cmath.rs +++ b/library/std/src/sys/windows/cmath.rs @@ -44,7 +44,7 @@ mod shims { } // On 32-bit x86 MSVC these functions aren't defined, so we just define shims -// which promote everything fo f64, perform the calculation, and then demote +// which promote everything for f64, perform the calculation, and then demote // back to f32. While not precisely correct should be "correct enough" for now. #[cfg(all(target_env = "msvc", target_arch = "x86"))] mod shims { diff --git a/library/std/src/sys/windows/path/tests.rs b/library/std/src/sys/windows/path/tests.rs index 2f7ec433bf26..a71175069052 100644 --- a/library/std/src/sys/windows/path/tests.rs +++ b/library/std/src/sys/windows/path/tests.rs @@ -115,7 +115,7 @@ fn test_parse_prefix_verbatim_device() { assert_eq!(prefix, parse_prefix(r"\\?/C:\windows\system32\notepad.exe")); } -// See #93586 for more infomation. +// See #93586 for more information. #[test] fn test_windows_prefix_components() { use crate::path::Path; diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 9301c5a2ff30..fe1b00a90fce 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -85,7 +85,7 @@ def _download(path, url, probably_big, verbose, exception): option = "-#" else: option = "-s" - # If curl is not present on Win32, we shoud not sys.exit + # If curl is not present on Win32, we should not sys.exit # but raise `CalledProcessError` or `OSError` instead require(["curl", "--version"], exception=platform_is_win32) run(["curl", option, diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 1e764811ea79..14e8ebd6876b 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -946,7 +946,7 @@ impl<'a> Builder<'a> { }; patchelf.args(&[OsString::from("--set-rpath"), rpath_entries]); if !fname.extension().map_or(false, |ext| ext == "so") { - // Finally, set the corret .interp for binaries + // Finally, set the correct .interp for binaries let dynamic_linker_path = nix_deps_dir.join("nix-support/dynamic-linker"); // FIXME: can we support utf8 here? `args` doesn't accept Vec, only OsString ... let dynamic_linker = t!(String::from_utf8(t!(fs::read(dynamic_linker_path)))); @@ -962,7 +962,7 @@ impl<'a> Builder<'a> { let tempfile = self.tempdir().join(dest_path.file_name().unwrap()); // While bootstrap itself only supports http and https downloads, downstream forks might // need to download components from other protocols. The match allows them adding more - // protocols without worrying about merge conficts if we change the HTTP implementation. + // protocols without worrying about merge conflicts if we change the HTTP implementation. match url.split_once("://").map(|(proto, _)| proto) { Some("http") | Some("https") => { self.download_http_with_retries(&tempfile, url, help_on_error) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 952943b78c6a..d111d945d6f2 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -1629,7 +1629,7 @@ fn chmod(_path: &Path, _perms: u32) {} /// If code is not 0 (successful exit status), exit status is 101 (rust's default error code.) /// If the test is running and code is an error code, it will cause a panic. fn detail_exit(code: i32) -> ! { - // if in test and code is an error code, panic with staus code provided + // if in test and code is an error code, panic with status code provided if cfg!(test) && code != 0 { panic!("status code: {}", code); } else { diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 7ecf74d3068d..f803ae071492 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -637,7 +637,7 @@ fn configure_cmake( if target.contains("darwin") { // Make sure that CMake does not build universal binaries on macOS. - // Explicitly specifiy the one single target architecture. + // Explicitly specify the one single target architecture. if target.starts_with("aarch64") { // macOS uses a different name for building arm64 cfg.define("CMAKE_OSX_ARCHITECTURES", "arm64"); diff --git a/src/doc/rustc/src/platform-support/m68k-unknown-linux-gnu.md b/src/doc/rustc/src/platform-support/m68k-unknown-linux-gnu.md index d325ba3346ab..b18a125f3b09 100644 --- a/src/doc/rustc/src/platform-support/m68k-unknown-linux-gnu.md +++ b/src/doc/rustc/src/platform-support/m68k-unknown-linux-gnu.md @@ -87,7 +87,7 @@ Rust programs can be built for that target: rustc --target m68k-unknown-linux-gnu your-code.rs ``` -Very simple progams can be run using the `qemu-m68k-static` program: +Very simple programs can be run using the `qemu-m68k-static` program: ```text $ qemu-m68k-static your-code diff --git a/src/doc/rustc/src/platform-support/pc-windows-gnullvm.md b/src/doc/rustc/src/platform-support/pc-windows-gnullvm.md index 721c234c6e60..fb0cea05d440 100644 --- a/src/doc/rustc/src/platform-support/pc-windows-gnullvm.md +++ b/src/doc/rustc/src/platform-support/pc-windows-gnullvm.md @@ -25,7 +25,7 @@ Like with any other Windows target created binaries are in PE format. ## Building the target -For cross-compilation I recommend using [llvm-mingw](https://github.com/mstorsjo/llvm-mingw) toolchain, one change that seems necessary beside configuring corss compilers is disabling experimental `m86k` target. Otherwise LLVM build fails with `multiple definition ...` errors. +For cross-compilation I recommend using [llvm-mingw](https://github.com/mstorsjo/llvm-mingw) toolchain, one change that seems necessary beside configuring cross compilers is disabling experimental `m86k` target. Otherwise LLVM build fails with `multiple definition ...` errors. Native bootstrapping builds require rather fragile hacks until host artifacts are available so I won't describe them here. ## Building Rust programs diff --git a/src/doc/rustc/src/platform-support/unknown-uefi.md b/src/doc/rustc/src/platform-support/unknown-uefi.md index 8f90d9c7453d..295dec0f0e48 100644 --- a/src/doc/rustc/src/platform-support/unknown-uefi.md +++ b/src/doc/rustc/src/platform-support/unknown-uefi.md @@ -133,7 +133,7 @@ There are 3 common ways to compile native C code for UEFI targets: - Use native Windows targets. This means compiling your C code for the Windows platform as if it was the UEFI platform. This works for static libraries, but needs adjustments when linking into an UEFI executable. You can, however, - link such static libraries seemlessly into rust code compiled for UEFI + link such static libraries seamlessly into rust code compiled for UEFI targets. Be wary of any includes that are not specifically suitable for UEFI targets (especially the C standard library includes are not always compatible). Freestanding compilations are recommended to avoid diff --git a/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md b/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md index 021b904debd8..6932e6a5764b 100644 --- a/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md +++ b/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md @@ -30,7 +30,7 @@ is 8-bytes large as well as pointers. The tradeoff, though, is that the maximum memory size is now the full 64-bit address space instead of the 4GB as limited by the 32-bit address space for `wasm32-unknown-unknown`. -This target is not a stable target. The [memory64] WebAssembly proposal is stil +This target is not a stable target. The [memory64] WebAssembly proposal is still in-progress and not standardized. This means that there are not many engines which implement the `memory64` feature and if they do they're likely behind a flag, for example: diff --git a/src/doc/unstable-book/src/compiler-flags/check-cfg.md b/src/doc/unstable-book/src/compiler-flags/check-cfg.md index bfa92e7d32a8..321992f7b0d7 100644 --- a/src/doc/unstable-book/src/compiler-flags/check-cfg.md +++ b/src/doc/unstable-book/src/compiler-flags/check-cfg.md @@ -143,7 +143,7 @@ fn do_features() {} #[cfg(has_feathers = "zapping")] // This is expected as "has_feathers" was provided in names() // and because no value checking was enable for "has_feathers" - // no warning is emited for the value "zapping" + // no warning is emitted for the value "zapping" fn do_zapping() {} #[cfg(has_mumble_frotz)] // This is UNEXPECTED because names checking is enable and diff --git a/src/doc/unstable-book/src/compiler-flags/remap-cwd-prefix.md b/src/doc/unstable-book/src/compiler-flags/remap-cwd-prefix.md index 977d258529f8..3890a12b7e68 100644 --- a/src/doc/unstable-book/src/compiler-flags/remap-cwd-prefix.md +++ b/src/doc/unstable-book/src/compiler-flags/remap-cwd-prefix.md @@ -8,7 +8,7 @@ This flag will rewrite absolute paths under the current working directory, replacing the current working directory prefix with a specified value. The given value may be absolute or relative, or empty. This switch takes -precidence over `--remap-path-prefix` in case they would both match a given +precedence over `--remap-path-prefix` in case they would both match a given path. This flag helps to produce deterministic output, by removing the current working diff --git a/src/etc/cpu-usage-over-time-plot.sh b/src/etc/cpu-usage-over-time-plot.sh index 1c3425591943..2617378ba5fd 100755 --- a/src/etc/cpu-usage-over-time-plot.sh +++ b/src/etc/cpu-usage-over-time-plot.sh @@ -15,7 +15,7 @@ # Improvements to this script are greatly appreciated! if [[ $# != 2 ]]; then - echo "expected 2 arguments, recieved $#" + echo "expected 2 arguments, received $#" echo "example usage: './src/etc/cpu-usage-over-time-plot.sh \ 7737e0b5c4103216d6fd8cf941b7ab9bdbaace7c \ x86_64-gnu'" diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py index baf95627c702..c97fb4b80547 100644 --- a/src/etc/htmldocck.py +++ b/src/etc/htmldocck.py @@ -386,7 +386,7 @@ def check_tree_attr(tree, path, attr, pat, regexp): return ret -# Returns the number of occurences matching the regex (`regexp`) and the text (`pat`). +# Returns the number of occurrences matching the regex (`regexp`) and the text (`pat`). def check_tree_text(tree, path, pat, regexp, stop_at_first): path = normalize_xpath(path) match_count = 0 diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 4a12d74ddef5..bb8e46af7628 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -450,7 +450,7 @@ impl<'a> PeekIter<'a> { fn new(iter: TokenIter<'a>) -> Self { Self { stored: VecDeque::new(), peek_pos: 0, iter } } - /// Returns the next item after the current one. It doesn't interfer with `peek_next` output. + /// Returns the next item after the current one. It doesn't interfere with `peek_next` output. fn peek(&mut self) -> Option<&(TokenKind, &'a str)> { if self.stored.is_empty() { if let Some(next) = self.iter.next() { @@ -459,7 +459,7 @@ impl<'a> PeekIter<'a> { } self.stored.front() } - /// Returns the next item after the last one peeked. It doesn't interfer with `peek` output. + /// Returns the next item after the last one peeked. It doesn't interfere with `peek` output. fn peek_next(&mut self) -> Option<&(TokenKind, &'a str)> { self.peek_pos += 1; if self.peek_pos - 1 < self.stored.len() { diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 7d7a63c53847..39d3b43cf32e 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -477,7 +477,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // If there's no `::`, it's not an associated item. // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved. .ok_or_else(|| { - debug!("found no `::`, assumming {} was correctly not in scope", item_name); + debug!("found no `::`, assuming {} was correctly not in scope", item_name); UnresolvedPath { item_id, module_id, @@ -1256,7 +1256,7 @@ impl LinkCollector<'_, '_> { &mut self, key: ResolutionInfo, diag: DiagnosticInfo<'_>, - // If errors are cached then they are only reported on first ocurrence + // If errors are cached then they are only reported on first occurrence // which we want in some cases but not in others. cache_errors: bool, ) -> Option<(Res, Option)> { diff --git a/src/test/codegen/issue-34634.rs b/src/test/codegen/issue-34634.rs index 6c18adbcb3c9..f53fa240cd1a 100644 --- a/src/test/codegen/issue-34634.rs +++ b/src/test/codegen/issue-34634.rs @@ -1,5 +1,5 @@ // Test that `wrapping_div` only checks divisor once. -// This test checks that there is only a single compare agains -1 and -1 is not present as a +// This test checks that there is only a single compare against -1 and -1 is not present as a // switch case (the second check present until rustc 1.12). // This test also verifies that a single panic call is generated (for the division by zero case). diff --git a/src/test/codegen/unwind-abis/aapcs-unwind-abi.rs b/src/test/codegen/unwind-abis/aapcs-unwind-abi.rs index 1fe048068601..c092e28a05ac 100644 --- a/src/test/codegen/unwind-abis/aapcs-unwind-abi.rs +++ b/src/test/codegen/unwind-abis/aapcs-unwind-abi.rs @@ -5,7 +5,7 @@ #[lang="sized"] trait Sized { } -// Test that `nounwind` atributes are correctly applied to exported `aapcs` and +// Test that `nounwind` attributes are correctly applied to exported `aapcs` and // `aapcs-unwind` extern functions. `aapcs-unwind` functions MUST NOT have this attribute. We // disable optimizations above to prevent LLVM from inferring the attribute. diff --git a/src/test/codegen/unwind-abis/c-unwind-abi-panic-abort.rs b/src/test/codegen/unwind-abis/c-unwind-abi-panic-abort.rs index e817d5715a18..8447bbeb1ed2 100644 --- a/src/test/codegen/unwind-abis/c-unwind-abi-panic-abort.rs +++ b/src/test/codegen/unwind-abis/c-unwind-abi-panic-abort.rs @@ -1,6 +1,6 @@ // compile-flags: -C panic=abort -// Test that `nounwind` atributes are also applied to extern `C-unwind` Rust functions +// Test that `nounwind` attributes are also applied to extern `C-unwind` Rust functions // when the code is compiled with `panic=abort`. #![crate_type = "lib"] diff --git a/src/test/codegen/unwind-abis/c-unwind-abi.rs b/src/test/codegen/unwind-abis/c-unwind-abi.rs index f15765367532..e258dbcacd22 100644 --- a/src/test/codegen/unwind-abis/c-unwind-abi.rs +++ b/src/test/codegen/unwind-abis/c-unwind-abi.rs @@ -1,6 +1,6 @@ // compile-flags: -C opt-level=0 -// Test that `nounwind` atributes are correctly applied to exported `C` and `C-unwind` extern +// Test that `nounwind` attributes are correctly applied to exported `C` and `C-unwind` extern // functions. `C-unwind` functions MUST NOT have this attribute. We disable optimizations above // to prevent LLVM from inferring the attribute. diff --git a/src/test/codegen/unwind-abis/cdecl-unwind-abi.rs b/src/test/codegen/unwind-abis/cdecl-unwind-abi.rs index 52e0d2d6e025..19a7228839ab 100644 --- a/src/test/codegen/unwind-abis/cdecl-unwind-abi.rs +++ b/src/test/codegen/unwind-abis/cdecl-unwind-abi.rs @@ -1,6 +1,6 @@ // compile-flags: -C opt-level=0 -// Test that `nounwind` atributes are correctly applied to exported `cdecl` and +// Test that `nounwind` attributes are correctly applied to exported `cdecl` and // `cdecl-unwind` extern functions. `cdecl-unwind` functions MUST NOT have this attribute. We // disable optimizations above to prevent LLVM from inferring the attribute. diff --git a/src/test/codegen/unwind-abis/fastcall-unwind-abi.rs b/src/test/codegen/unwind-abis/fastcall-unwind-abi.rs index ed23235ebfa8..b74099a5d965 100644 --- a/src/test/codegen/unwind-abis/fastcall-unwind-abi.rs +++ b/src/test/codegen/unwind-abis/fastcall-unwind-abi.rs @@ -5,7 +5,7 @@ #[lang="sized"] trait Sized { } -// Test that `nounwind` atributes are correctly applied to exported `fastcall` and +// Test that `nounwind` attributes are correctly applied to exported `fastcall` and // `fastcall-unwind` extern functions. `fastcall-unwind` functions MUST NOT have this attribute. We // disable optimizations above to prevent LLVM from inferring the attribute. diff --git a/src/test/codegen/unwind-abis/nounwind-on-stable-panic-abort.rs b/src/test/codegen/unwind-abis/nounwind-on-stable-panic-abort.rs index 9a4b3d3b4848..106d593b21de 100644 --- a/src/test/codegen/unwind-abis/nounwind-on-stable-panic-abort.rs +++ b/src/test/codegen/unwind-abis/nounwind-on-stable-panic-abort.rs @@ -3,7 +3,7 @@ #![crate_type = "lib"] -// We disable optimizations to prevent LLVM from infering the attribute. +// We disable optimizations to prevent LLVM from inferring the attribute. // CHECK: Function Attrs:{{.*}}nounwind // CHECK-NEXT: @foo diff --git a/src/test/codegen/unwind-abis/nounwind-on-stable-panic-unwind.rs b/src/test/codegen/unwind-abis/nounwind-on-stable-panic-unwind.rs index 2783c83d3efe..c1c5bbdda345 100644 --- a/src/test/codegen/unwind-abis/nounwind-on-stable-panic-unwind.rs +++ b/src/test/codegen/unwind-abis/nounwind-on-stable-panic-unwind.rs @@ -3,7 +3,7 @@ #![crate_type = "lib"] -// We disable optimizations to prevent LLVM from infering the attribute. +// We disable optimizations to prevent LLVM from inferring the attribute. extern "C" { fn bar(); diff --git a/src/test/codegen/unwind-abis/nounwind.rs b/src/test/codegen/unwind-abis/nounwind.rs index cfc140361f62..c46d717331b4 100644 --- a/src/test/codegen/unwind-abis/nounwind.rs +++ b/src/test/codegen/unwind-abis/nounwind.rs @@ -4,7 +4,7 @@ #![crate_type = "lib"] #![feature(c_unwind)] -// We disable optimizations to prevent LLVM from infering the attribute. +// We disable optimizations to prevent LLVM from inferring the attribute. // CHECK: Function Attrs:{{.*}}nounwind // CHECK-NEXT: @foo diff --git a/src/test/codegen/unwind-abis/stdcall-unwind-abi.rs b/src/test/codegen/unwind-abis/stdcall-unwind-abi.rs index f1dff27ad67b..8eff0719f8fa 100644 --- a/src/test/codegen/unwind-abis/stdcall-unwind-abi.rs +++ b/src/test/codegen/unwind-abis/stdcall-unwind-abi.rs @@ -5,7 +5,7 @@ #[lang="sized"] trait Sized { } -// Test that `nounwind` atributes are correctly applied to exported `stdcall` and `stdcall-unwind` +// Test that `nounwind` attributes are correctly applied to exported `stdcall` and `stdcall-unwind` // extern functions. `stdcall-unwind` functions MUST NOT have this attribute. We disable // optimizations above to prevent LLVM from inferring the attribute. diff --git a/src/test/codegen/unwind-abis/system-unwind-abi.rs b/src/test/codegen/unwind-abis/system-unwind-abi.rs index c4d51328352c..2591c1d48143 100644 --- a/src/test/codegen/unwind-abis/system-unwind-abi.rs +++ b/src/test/codegen/unwind-abis/system-unwind-abi.rs @@ -1,6 +1,6 @@ // compile-flags: -C opt-level=0 -// Test that `nounwind` atributes are correctly applied to exported `system` and `system-unwind` +// Test that `nounwind` attributes are correctly applied to exported `system` and `system-unwind` // extern functions. `system-unwind` functions MUST NOT have this attribute. We disable // optimizations above to prevent LLVM from inferring the attribute. diff --git a/src/test/codegen/unwind-abis/sysv64-unwind-abi.rs b/src/test/codegen/unwind-abis/sysv64-unwind-abi.rs index a38736f2a1f9..694fde17c3cb 100644 --- a/src/test/codegen/unwind-abis/sysv64-unwind-abi.rs +++ b/src/test/codegen/unwind-abis/sysv64-unwind-abi.rs @@ -5,7 +5,7 @@ #[lang="sized"] trait Sized { } -// Test that `nounwind` atributes are correctly applied to exported `sysv64` and +// Test that `nounwind` attributes are correctly applied to exported `sysv64` and // `sysv64-unwind` extern functions. `sysv64-unwind` functions MUST NOT have this attribute. We // disable optimizations above to prevent LLVM from inferring the attribute. diff --git a/src/test/codegen/unwind-abis/thiscall-unwind-abi.rs b/src/test/codegen/unwind-abis/thiscall-unwind-abi.rs index d2cf041b72d2..7e81367fc5b7 100644 --- a/src/test/codegen/unwind-abis/thiscall-unwind-abi.rs +++ b/src/test/codegen/unwind-abis/thiscall-unwind-abi.rs @@ -5,7 +5,7 @@ #[lang="sized"] trait Sized { } -// Test that `nounwind` atributes are correctly applied to exported `thiscall` and +// Test that `nounwind` attributes are correctly applied to exported `thiscall` and // `thiscall-unwind` extern functions. `thiscall-unwind` functions MUST NOT have this attribute. We // disable optimizations above to prevent LLVM from inferring the attribute. diff --git a/src/test/codegen/unwind-abis/vectorcall-unwind-abi.rs b/src/test/codegen/unwind-abis/vectorcall-unwind-abi.rs index 0fb9612a5e4e..d7eca2a97000 100644 --- a/src/test/codegen/unwind-abis/vectorcall-unwind-abi.rs +++ b/src/test/codegen/unwind-abis/vectorcall-unwind-abi.rs @@ -5,7 +5,7 @@ #[lang="sized"] trait Sized { } -// Test that `nounwind` atributes are correctly applied to exported `vectorcall` and +// Test that `nounwind` attributes are correctly applied to exported `vectorcall` and // `vectorcall-unwind` extern functions. `vectorcall-unwind` functions MUST NOT have this attribute. // We disable optimizations above to prevent LLVM from inferring the attribute. diff --git a/src/test/codegen/unwind-abis/win64-unwind-abi.rs b/src/test/codegen/unwind-abis/win64-unwind-abi.rs index 5d8482da6305..6591348c35d3 100644 --- a/src/test/codegen/unwind-abis/win64-unwind-abi.rs +++ b/src/test/codegen/unwind-abis/win64-unwind-abi.rs @@ -5,7 +5,7 @@ #[lang="sized"] trait Sized { } -// Test that `nounwind` atributes are correctly applied to exported `win64` and +// Test that `nounwind` attributes are correctly applied to exported `win64` and // `win64-unwind` extern functions. `win64-unwind` functions MUST NOT have this attribute. We // disable optimizations above to prevent LLVM from inferring the attribute. diff --git a/src/test/codegen/unwind-extern-exports.rs b/src/test/codegen/unwind-extern-exports.rs index c939235fb500..6ac3c079f81b 100644 --- a/src/test/codegen/unwind-extern-exports.rs +++ b/src/test/codegen/unwind-extern-exports.rs @@ -5,7 +5,7 @@ #![feature(c_unwind)] // Make sure these all do *not* get the attribute. -// We disable optimizations to prevent LLVM from infering the attribute. +// We disable optimizations to prevent LLVM from inferring the attribute. // CHECK-NOT: nounwind // "C" ABI diff --git a/src/test/incremental/hygiene/load_cached_hygiene.rs b/src/test/incremental/hygiene/load_cached_hygiene.rs index 8124141418bc..355d33458524 100644 --- a/src/test/incremental/hygiene/load_cached_hygiene.rs +++ b/src/test/incremental/hygiene/load_cached_hygiene.rs @@ -2,7 +2,7 @@ // compile-flags: -Z query-dep-graph // aux-build:cached_hygiene.rs -// This tests the folllowing scenario +// This tests the following scenario // 1. A foreign crate is compiled with incremental compilation. // This causes hygiene information to be saved to the incr cache. // 2. One function is the foreign crate is modified. This causes the diff --git a/src/test/incremental/issue-49043.rs b/src/test/incremental/issue-49043.rs index 50d8fb869307..8d13718b8d84 100644 --- a/src/test/incremental/issue-49043.rs +++ b/src/test/incremental/issue-49043.rs @@ -1,5 +1,5 @@ // Regression test for hashing involving canonical variables. In this -// test -- which has an intensional error -- the type of the value +// test -- which has an intentional error -- the type of the value // being dropped winds up including a type variable. Canonicalization // would then produce a `?0` which -- in turn -- triggered an ICE in // hashing. diff --git a/src/test/incremental/thinlto/cgu_invalidated_when_export_added.rs b/src/test/incremental/thinlto/cgu_invalidated_when_export_added.rs index 4d48a5f0ac52..95f3b8ae4d98 100644 --- a/src/test/incremental/thinlto/cgu_invalidated_when_export_added.rs +++ b/src/test/incremental/thinlto/cgu_invalidated_when_export_added.rs @@ -3,7 +3,7 @@ // rust-lang/rust#69798: // -// This is analgous to cgu_invalidated_when_import_added, but it covers a +// This is analogous to cgu_invalidated_when_import_added, but it covers a // problem uncovered where a change to the *export* set caused a link failure // when reusing post-LTO optimized object code. diff --git a/src/test/incremental/thinlto/cgu_invalidated_when_export_removed.rs b/src/test/incremental/thinlto/cgu_invalidated_when_export_removed.rs index e85b4856f3a9..e86ebd354b1a 100644 --- a/src/test/incremental/thinlto/cgu_invalidated_when_export_removed.rs +++ b/src/test/incremental/thinlto/cgu_invalidated_when_export_removed.rs @@ -3,7 +3,7 @@ // rust-lang/rust#69798: // -// This is analgous to cgu_invalidated_when_export_added, but it covers the +// This is analogous to cgu_invalidated_when_export_added, but it covers the // other direction. This is analogous to cgu_invalidated_when_import_added: we // include it, because it may uncover bugs in variant implementation strategies. diff --git a/src/test/mir-opt/dest-prop/union.rs b/src/test/mir-opt/dest-prop/union.rs index 68c834dfbbf2..eb6cb09fc455 100644 --- a/src/test/mir-opt/dest-prop/union.rs +++ b/src/test/mir-opt/dest-prop/union.rs @@ -1,4 +1,4 @@ -//! Tests that we can propogate into places that are projections into unions +//! Tests that we can propagate into places that are projections into unions // compile-flags: -Zunsound-mir-opts fn val() -> u32 { 1 diff --git a/src/test/run-make-fulldeps/issue-64153/Makefile b/src/test/run-make-fulldeps/issue-64153/Makefile index 51dc6b53a450..f42ea620fb9d 100644 --- a/src/test/run-make-fulldeps/issue-64153/Makefile +++ b/src/test/run-make-fulldeps/issue-64153/Makefile @@ -19,7 +19,7 @@ all: # Dump all the symbols from the staticlib into `syms` "$(LLVM_BIN_DIR)"/llvm-objdump -t $(TMPDIR)/libdownstream.a > $(TMPDIR)/syms # Count the global instances of `issue64153_test_function`. There'll be 2 - # if the `upstream` object file got erronously included twice. + # if the `upstream` object file got erroneously included twice. # The line we are testing for with the regex looks something like: # 0000000000000000 g F .text.issue64153_test_function 00000023 issue64153_test_function grep -c -e "[[:space:]]g[[:space:]]*F[[:space:]].*issue64153_test_function" $(TMPDIR)/syms > $(TMPDIR)/count diff --git a/src/test/run-make/coverage-reports/Makefile b/src/test/run-make/coverage-reports/Makefile index cac881ece129..6fc2a6bada9a 100644 --- a/src/test/run-make/coverage-reports/Makefile +++ b/src/test/run-make/coverage-reports/Makefile @@ -60,7 +60,7 @@ endif # for now, but it is effectively ignored for all tests that don't include this file anyway. # # (Note that it's also possible the `_counters..txt` and `.json` files (if generated) -# may order results from multiple files inconsistently, which might also have to be accomodated +# may order results from multiple files inconsistently, which might also have to be accommodated # if and when we allow `llvm-cov` to produce results for multiple files. Note, the path separators # appear to be normalized to `/` in those files, thankfully.) LLVM_COV_IGNORE_FILES=\ @@ -157,7 +157,7 @@ else # `// ignore-llvm-cov-show-diffs` anymore. This directive exists to work around a limitation # with `llvm-cov show`. When reporting coverage for multiple instantiations of a generic function, # with different type substitutions, `llvm-cov show` prints these in a non-deterministic order, - # breaking the `diff` comparision. + # breaking the `diff` comparison. # # A partial workaround is implemented below, with `diff --ignore-matching-lines=RE` # to ignore each line prefixing each generic instantiation coverage code region. diff --git a/src/test/run-make/coverage-reports/expected_show_coverage.async.txt b/src/test/run-make/coverage-reports/expected_show_coverage.async.txt index 2f69adbd81c5..87ccb6c43eab 100644 --- a/src/test/run-make/coverage-reports/expected_show_coverage.async.txt +++ b/src/test/run-make/coverage-reports/expected_show_coverage.async.txt @@ -55,7 +55,7 @@ 53| 1| 1 // This line appears covered, but the 1-character expression span covering the `1` ^0 54| 1| // is not executed. (`llvm-cov show` displays a `^0` below the `1` ). This is because - 55| 1| // `fn j()` executes the open brace for the funciton body, followed by the function's + 55| 1| // `fn j()` executes the open brace for the function body, followed by the function's 56| 1| // first executable statement, `match x`. Inner function declarations are not 57| 1| // "visible" to the MIR for `j()`, so the code region counts all lines between the 58| 1| // open brace and the first statement as executed, which is, in a sense, true. diff --git a/src/test/run-make/coverage/async.rs b/src/test/run-make/coverage/async.rs index a6e387747068..efd9e62d64e1 100644 --- a/src/test/run-make/coverage/async.rs +++ b/src/test/run-make/coverage/async.rs @@ -52,7 +52,7 @@ fn j(x: u8) { if x == 8 { 1 // This line appears covered, but the 1-character expression span covering the `1` // is not executed. (`llvm-cov show` displays a `^0` below the `1` ). This is because - // `fn j()` executes the open brace for the funciton body, followed by the function's + // `fn j()` executes the open brace for the function body, followed by the function's // first executable statement, `match x`. Inner function declarations are not // "visible" to the MIR for `j()`, so the code region counts all lines between the // open brace and the first statement as executed, which is, in a sense, true. diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh index 54645e9e257c..944343df6e58 100644 --- a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh @@ -45,7 +45,7 @@ check cc_plus_one_cxx cc_plus_one_cxx.checks check cc_plus_one_cxx_asm cc_plus_one_cxx_asm.checks check cc_plus_one_asm cc_plus_one_asm.checks \ || echo "warning: the cc crate forwards assembly files to the CC compiler." \ - "Clang uses its own intergrated assembler, which does not include the LVI passes." + "Clang uses its own integrated assembler, which does not include the LVI passes." check cmake_plus_one_c cmake_plus_one_c.checks check cmake_plus_one_c_asm cmake_plus_one_c_asm.checks diff --git a/src/test/rustdoc-ui/normalize-cycle.rs b/src/test/rustdoc-ui/normalize-cycle.rs index f48cad373cde..14ffac1e1dce 100644 --- a/src/test/rustdoc-ui/normalize-cycle.rs +++ b/src/test/rustdoc-ui/normalize-cycle.rs @@ -1,5 +1,5 @@ // check-pass -// Regresion test for . +// Regression test for . pub trait Query {} pub trait AsQuery { diff --git a/src/test/rustdoc/elided-lifetime.rs b/src/test/rustdoc/elided-lifetime.rs index 9b4ceb4f9cd8..006132ef8aa4 100644 --- a/src/test/rustdoc/elided-lifetime.rs +++ b/src/test/rustdoc/elided-lifetime.rs @@ -3,7 +3,7 @@ // rust-lang/rust#75225 // // Since Rust 2018 we encourage writing out <'_> explicitly to make it clear -// that borrowing is occuring. Make sure rustdoc is following the same idiom. +// that borrowing is occurring. Make sure rustdoc is following the same idiom. #![crate_name = "foo"] diff --git a/src/test/rustdoc/infinite-redirection.rs b/src/test/rustdoc/infinite-redirection.rs index 96a43323ce29..f037a8e1a83d 100644 --- a/src/test/rustdoc/infinite-redirection.rs +++ b/src/test/rustdoc/infinite-redirection.rs @@ -7,7 +7,7 @@ // @has 'foo/builders/struct.ActionRowBuilder.html' // @has - '//*[@id="synthetic-implementations"]' 'Auto Trait Implementations' -// And that the link in the module is targetting it. +// And that the link in the module is targeting it. // @has 'foo/builders/index.html' // @has - '//a[@href="struct.ActionRowBuilder.html"]' 'ActionRowBuilder' diff --git a/src/test/rustdoc/macro-document-private-duplicate.rs b/src/test/rustdoc/macro-document-private-duplicate.rs index ee3010514417..d3cf7e140650 100644 --- a/src/test/rustdoc/macro-document-private-duplicate.rs +++ b/src/test/rustdoc/macro-document-private-duplicate.rs @@ -4,7 +4,7 @@ // (yes, that's a thing), rustdoc lists both of them on the index page, // but only documents the first one on the page for the macro. // Fortunately, this can only happen in document private items mode, -// but it still isn't ideal beahvior. +// but it still isn't ideal behavior. // // See https://github.com/rust-lang/rust/pull/88019#discussion_r693920453 // diff --git a/src/test/ui/allocator/no_std-alloc-error-handler-custom.rs b/src/test/ui/allocator/no_std-alloc-error-handler-custom.rs index 54b7c8bb9c6f..851da231a734 100644 --- a/src/test/ui/allocator/no_std-alloc-error-handler-custom.rs +++ b/src/test/ui/allocator/no_std-alloc-error-handler-custom.rs @@ -86,7 +86,7 @@ fn panic(panic_info: &core::panic::PanicInfo) -> ! { // Because we are compiling this code with `-C panic=abort`, this wouldn't normally be needed. // However, `core` and `alloc` are both compiled with `-C panic=unwind`, which means that functions -// in these libaries will refer to `rust_eh_personality` if LLVM can not *prove* the contents won't +// in these libraries will refer to `rust_eh_personality` if LLVM can not *prove* the contents won't // unwind. So, for this test case we will define the symbol. #[lang = "eh_personality"] extern fn rust_eh_personality() {} diff --git a/src/test/ui/allocator/no_std-alloc-error-handler-default.rs b/src/test/ui/allocator/no_std-alloc-error-handler-default.rs index ffa331a992c8..30ce0f162c7a 100644 --- a/src/test/ui/allocator/no_std-alloc-error-handler-default.rs +++ b/src/test/ui/allocator/no_std-alloc-error-handler-default.rs @@ -73,7 +73,7 @@ fn panic(panic_info: &core::panic::PanicInfo) -> ! { // Because we are compiling this code with `-C panic=abort`, this wouldn't normally be needed. // However, `core` and `alloc` are both compiled with `-C panic=unwind`, which means that functions -// in these libaries will refer to `rust_eh_personality` if LLVM can not *prove* the contents won't +// in these libraries will refer to `rust_eh_personality` if LLVM can not *prove* the contents won't // unwind. So, for this test case we will define the symbol. #[lang = "eh_personality"] extern fn rust_eh_personality() {} diff --git a/src/test/ui/associated-type-bounds/elision.rs b/src/test/ui/associated-type-bounds/elision.rs index 4a533939931b..d00def571666 100644 --- a/src/test/ui/associated-type-bounds/elision.rs +++ b/src/test/ui/associated-type-bounds/elision.rs @@ -1,7 +1,7 @@ #![feature(associated_type_bounds)] #![feature(anonymous_lifetime_in_impl_trait)] -// The same thing should happen for constaints in dyn trait. +// The same thing should happen for constraints in dyn trait. fn f(x: &mut dyn Iterator>) -> Option<&'_ ()> { x.next() } //~^ ERROR missing lifetime specifier //~| ERROR mismatched types diff --git a/src/test/ui/borrowck/two-phase-nonrecv-autoref.rs b/src/test/ui/borrowck/two-phase-nonrecv-autoref.rs index 3d395d1f264a..da238205b402 100644 --- a/src/test/ui/borrowck/two-phase-nonrecv-autoref.rs +++ b/src/test/ui/borrowck/two-phase-nonrecv-autoref.rs @@ -131,13 +131,13 @@ fn coerce_index_op() { let mut i = I(10); i[i[3]] = 4; //~^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502] - // Shoud be accepted with g2p + // Should be accepted with g2p i[3] = i[4]; i[i[3]] = i[4]; //~^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502] - // Shoud be accepted with g2p + // Should be accepted with g2p } fn main() { diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference.rs b/src/test/ui/borrowck/two-phase-reservation-sharing-interference.rs index e0f4afa75276..0463e22b3c2d 100644 --- a/src/test/ui/borrowck/two-phase-reservation-sharing-interference.rs +++ b/src/test/ui/borrowck/two-phase-reservation-sharing-interference.rs @@ -40,6 +40,6 @@ fn main() { // // (At least in theory; part of the reason this test fails is that // the constructed MIR throws in extra &mut reborrows which - // flummoxes our attmpt to delay the activation point here.) + // flummoxes our attempt to delay the activation point here.) delay.push(2); } diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.rs index 93131b2ac4e4..f97e60daf43a 100644 --- a/src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.rs +++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/arrays.rs @@ -68,7 +68,7 @@ fn arrays_5() { arr[1] += 10; }; - // c will capture `arr` completely, therefore we cannot borrow other indecies + // c will capture `arr` completely, therefore we cannot borrow other indices // into the array. println!("{:#?}", &arr[3..2]); //~^ ERROR: cannot borrow `arr` as immutable because it is also borrowed as mutable diff --git a/src/test/ui/closures/2229_closure_analysis/repr_packed.rs b/src/test/ui/closures/2229_closure_analysis/repr_packed.rs index 3ed780f51c73..f23670f63acb 100644 --- a/src/test/ui/closures/2229_closure_analysis/repr_packed.rs +++ b/src/test/ui/closures/2229_closure_analysis/repr_packed.rs @@ -31,7 +31,7 @@ fn test_alignment_not_affected() { c(); } -// `String`, `u16` are not aligned at a one byte boundry and are thus affected by repr(packed). +// `String`, `u16` are not aligned at a one byte boundary and are thus affected by repr(packed). // // Here we test that the closure doesn't capture a reference point to `foo.x` but // rather capture `foo` entirely. diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/by_value.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/by_value.rs index 2c828aed528b..f8752fe1cec0 100644 --- a/src/test/ui/closures/2229_closure_analysis/run_pass/by_value.rs +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/by_value.rs @@ -1,8 +1,8 @@ // edition:2021 // run-pass -// Test that ByValue captures compile sucessefully especially when the captures are -// derefenced within the closure. +// Test that ByValue captures compile successfully especially when the captures are +// dereferenced within the closure. #[derive(Debug, Default)] struct SomeLargeType; diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.rs index 88a9816a0526..03400e0ee8d5 100644 --- a/src/test/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.rs +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/disjoint-capture-in-same-closure.rs @@ -1,7 +1,7 @@ // edition:2021 // run-pass -// Tests that if a closure uses indivual fields of the same object +// Tests that if a closure uses individual fields of the same object // then that case is handled properly. #![allow(unused)] diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.rs index b8e464031813..624e0ff22568 100644 --- a/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.rs +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-1.rs @@ -1,10 +1,10 @@ // edition:2021 // run-pass -// Test that closures can catpure paths that are more precise than just one level +// Test that closures can capture paths that are more precise than just one level // from the root variable. // -// If the closures can handle such precison we should be able to mutate one path in the closure +// If the closures can handle such precision we should be able to mutate one path in the closure // while being able to mutate another path outside the closure, where the two paths are disjoint // after applying two projections on the root variable. diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.rs index 11a324d8a34e..bd8addd37812 100644 --- a/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.rs +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/multilevel-path-2.rs @@ -3,7 +3,7 @@ #![allow(unused)] -// If the closures can handle such precison we should be able to read one path in the closure +// If the closures can handle such precision we should be able to read one path in the closure // while being able mutate another path outside the closure, where the two paths are disjoint // after applying two projections on the root variable. diff --git a/src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref_struct_mem.rs b/src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref_struct_mem.rs index bb784774b8cd..a85335438a9f 100644 --- a/src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref_struct_mem.rs +++ b/src/test/ui/closures/2229_closure_analysis/run_pass/mut_ref_struct_mem.rs @@ -5,7 +5,7 @@ // that is captured by the closure // More specifically we test that the if the mutable reference isn't root variable of a capture -// but rather accessed while acessing the precise capture. +// but rather accessed while accessing the precise capture. fn mut_tuple() { let mut t = (10, 10); diff --git a/src/test/ui/closures/issue-84128.rs b/src/test/ui/closures/issue-84128.rs index f81d7cfaa654..30733871b855 100644 --- a/src/test/ui/closures/issue-84128.rs +++ b/src/test/ui/closures/issue-84128.rs @@ -1,5 +1,5 @@ // test for issue 84128 -// missing suggestion for similar ADT type with diffetent generic paramenter +// missing suggestion for similar ADT type with diffetent generic parameter // on closure ReturnNoExpression struct Foo(T); diff --git a/src/test/ui/command/command-current-dir.rs b/src/test/ui/command/command-current-dir.rs index 91d8e4f381a3..69a0b486d689 100644 --- a/src/test/ui/command/command-current-dir.rs +++ b/src/test/ui/command/command-current-dir.rs @@ -18,7 +18,7 @@ fn main() { let exe = me.file_name().unwrap(); let cwd = me.parent().unwrap(); eprintln!("cwd={:?}", cwd); - // Change directory to where the exectuable is located, since this test + // Change directory to where the executable is located, since this test // fundamentally needs to use relative paths. In some cases (like // remote-test-server), the current_dir can be somewhere else, so make // sure it is something we can use. We assume we can write to this diff --git a/src/test/ui/const-generics/issues/issue-83466.rs b/src/test/ui/const-generics/issues/issue-83466.rs index c488a663fbb0..73c9301011d5 100644 --- a/src/test/ui/const-generics/issues/issue-83466.rs +++ b/src/test/ui/const-generics/issues/issue-83466.rs @@ -1,5 +1,5 @@ // regression test for #83466- tests that generic arg mismatch errors between -// consts and types are not supressed when there are explicit late bound lifetimes +// consts and types are not suppressed when there are explicit late bound lifetimes struct S; impl S { diff --git a/src/test/ui/consts/const-eval/ub-enum.rs b/src/test/ui/consts/const-eval/ub-enum.rs index 0e8744e790f6..d8dc6d057a73 100644 --- a/src/test/ui/consts/const-eval/ub-enum.rs +++ b/src/test/ui/consts/const-eval/ub-enum.rs @@ -93,7 +93,7 @@ const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute //~^ ERROR is undefined behavior // All variants are uninhabited but also have data. -// Use `0` as constant to make behavior endianess-independent. +// Use `0` as constant to make behavior endianness-independent. const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) }; //~^ ERROR evaluation of constant value failed const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) }; diff --git a/src/test/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.rs b/src/test/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.rs index 850d83be6845..f412ba84c6ba 100644 --- a/src/test/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.rs +++ b/src/test/ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.rs @@ -1,4 +1,4 @@ -// Test for diagnostics when we have mismatched lifetime due to implict 'static lifetime in GATs +// Test for diagnostics when we have mismatched lifetime due to implicit 'static lifetime in GATs // check-fail diff --git a/src/test/ui/issues/issue-23611-enum-swap-in-drop.rs b/src/test/ui/issues/issue-23611-enum-swap-in-drop.rs index 403cf970bcb0..cdb130d600c5 100644 --- a/src/test/ui/issues/issue-23611-enum-swap-in-drop.rs +++ b/src/test/ui/issues/issue-23611-enum-swap-in-drop.rs @@ -97,7 +97,7 @@ pub fn main() { // ever hands f_A off to instances of GaspA, and thus one should // be able to prove the invariant that f_A is *only* invoked from // from an instance of GaspA (either via the GaspA drop - // implementation or the E drop implementaton). Yet the old (bad) + // implementation or the E drop implementation). Yet the old (bad) // behavior allowed a call to f_A to leak in while we are tearing // down a value of type GaspB. } diff --git a/src/test/ui/iterators/issue-58952-filter-type-length.rs b/src/test/ui/iterators/issue-58952-filter-type-length.rs index ffbe89a14e3b..6d12db8d1373 100644 --- a/src/test/ui/iterators/issue-58952-filter-type-length.rs +++ b/src/test/ui/iterators/issue-58952-filter-type-length.rs @@ -1,6 +1,6 @@ // run-pass //! This snippet causes the type length to blowup exponentially, -//! so check that we don't accidentially exceed the type length limit. +//! so check that we don't accidentally exceed the type length limit. // FIXME: Once the size of iterator adaptors is further reduced, // increase the complexity of this test. use std::collections::VecDeque; diff --git a/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs b/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs index c66037e9a73a..b4fc3317487d 100644 --- a/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs +++ b/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs @@ -5,7 +5,7 @@ // If you turn off deduplicate diagnostics (which rustc turns on by default but // compiletest turns off when it runs ui tests), then the errors are // (unfortunately) repeated here because the checking is done as we read in the -// errors, and curretly that happens two or three different times, depending on +// errors, and currently that happens two or three different times, depending on // compiler flags. // // I decided avoiding the redundant output was not worth the time in engineering diff --git a/src/test/ui/never_type/fallback-closure-wrap.rs b/src/test/ui/never_type/fallback-closure-wrap.rs index 35052da6760b..f88355bb285f 100644 --- a/src/test/ui/never_type/fallback-closure-wrap.rs +++ b/src/test/ui/never_type/fallback-closure-wrap.rs @@ -3,7 +3,7 @@ // // This particular test case currently fails as the inference to `()` rather // than `!` happens as a result of an `as` cast, which is not currently tracked. -// Crater did not find many cases of this occuring, but it is included for +// Crater did not find many cases of this occurring, but it is included for // awareness. // // revisions: nofallback fallback diff --git a/src/test/ui/nll/issue-21232-partial-init-and-use.rs b/src/test/ui/nll/issue-21232-partial-init-and-use.rs index 4cd1e406f944..ad3eb248351d 100644 --- a/src/test/ui/nll/issue-21232-partial-init-and-use.rs +++ b/src/test/ui/nll/issue-21232-partial-init-and-use.rs @@ -53,7 +53,7 @@ impl R { fn new(f: F) -> Self { R { w: 0, f } } } // * local/field: Is the structure in a local or a field // * fully/partial/void: Are we fully initializing it before using any part? // Is whole type empty due to a void component? -// * init/reinit: First initialization, or did we previously inititalize and then move out? +// * init/reinit: First initialization, or did we previously initialize and then move out? // * struct/tuple: Is this a struct or a (X, Y). // // As a shorthand for the cases above, adding a numeric summary to diff --git a/src/test/ui/nll/polonius/assignment-kills-loans.rs b/src/test/ui/nll/polonius/assignment-kills-loans.rs index c4cf20389ac8..696bf61cefde 100644 --- a/src/test/ui/nll/polonius/assignment-kills-loans.rs +++ b/src/test/ui/nll/polonius/assignment-kills-loans.rs @@ -1,7 +1,7 @@ #![allow(dead_code)] // This tests the various kinds of assignments there are. Polonius used to generate `killed` -// facts only on simple assigments, but not projections, incorrectly causing errors to be emitted +// facts only on simple assignments, but not projections, incorrectly causing errors to be emitted // for code accepted by NLL. They are all variations from example code in the NLL RFC. // check-pass diff --git a/src/test/ui/pattern/rest-pat-semantic-disallowed.rs b/src/test/ui/pattern/rest-pat-semantic-disallowed.rs index 84552f2e7331..156285e0f9fc 100644 --- a/src/test/ui/pattern/rest-pat-semantic-disallowed.rs +++ b/src/test/ui/pattern/rest-pat-semantic-disallowed.rs @@ -1,5 +1,5 @@ // Here we test that rest patterns, i.e. `..`, are not allowed -// outside of slice (+ ident patterns witin those), tuple, +// outside of slice (+ ident patterns within those), tuple, // and tuple struct patterns and that duplicates are caught in these contexts. #![feature(box_patterns)] diff --git a/src/test/ui/proc-macro/crt-static.rs b/src/test/ui/proc-macro/crt-static.rs index 8c1a9dc80265..6103acb7b6bd 100644 --- a/src/test/ui/proc-macro/crt-static.rs +++ b/src/test/ui/proc-macro/crt-static.rs @@ -9,7 +9,7 @@ // FIXME: This don't work when crate-type is specified by attribute // `#![crate_type = "proc-macro"]`, not by `--crate-type=proc-macro` -// command line flag. This is beacuse the list of `cfg` symbols is generated +// command line flag. This is because the list of `cfg` symbols is generated // before attributes are parsed. See rustc_interface::util::add_configuration #[cfg(target_feature = "crt-static")] compile_error!("crt-static is enabled"); diff --git a/src/test/ui/regions/issue-56537-closure-uses-region-from-container.rs b/src/test/ui/regions/issue-56537-closure-uses-region-from-container.rs index bdd1ae91f7d7..a8f7a41c4428 100644 --- a/src/test/ui/regions/issue-56537-closure-uses-region-from-container.rs +++ b/src/test/ui/regions/issue-56537-closure-uses-region-from-container.rs @@ -5,7 +5,7 @@ // by the function. // // This works today, which precludes changing things so that closures -// follow the same lifetime-elision rules used elsehwere. See +// follow the same lifetime-elision rules used elsewhere. See // rust-lang/rust#56537 // check-pass diff --git a/src/test/ui/specialization/issue-33017.rs b/src/test/ui/specialization/issue-33017.rs index 4d19230df6ba..8dbadf58d5c8 100644 --- a/src/test/ui/specialization/issue-33017.rs +++ b/src/test/ui/specialization/issue-33017.rs @@ -1,4 +1,4 @@ -// Test to ensure that trait bounds are propertly +// Test to ensure that trait bounds are properly // checked on specializable associated types #![allow(incomplete_features)] diff --git a/src/test/ui/suggestions/suggest-blanket-impl-local-trait.rs b/src/test/ui/suggestions/suggest-blanket-impl-local-trait.rs index 7cf536f7966e..14fef1b52489 100644 --- a/src/test/ui/suggestions/suggest-blanket-impl-local-trait.rs +++ b/src/test/ui/suggestions/suggest-blanket-impl-local-trait.rs @@ -1,5 +1,5 @@ // Ensure that the compiler include the blanklet implementation suggestion -// when inside a `impl` statment are used two local traits. +// when inside a `impl` statement are used two local traits. // // edition:2021 use std::fmt; diff --git a/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.rs b/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.rs index 1314f9cb0932..17ddaa312f7c 100644 --- a/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.rs +++ b/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.rs @@ -1,5 +1,5 @@ // This tests issue #79683: note in the error message that the trait is -// explicitely unimplemented instead of suggesting to implement it. +// explicitly unimplemented instead of suggesting to implement it. #![feature(negative_impls)] diff --git a/src/test/ui/type/type-alias-bounds.rs b/src/test/ui/type/type-alias-bounds.rs index 65b79650d4d7..e49731725d51 100644 --- a/src/test/ui/type/type-alias-bounds.rs +++ b/src/test/ui/type/type-alias-bounds.rs @@ -52,7 +52,7 @@ type T2 where U: Bound = U::Assoc; //~ WARN not enforced in type aliases // Do this instead: type T4 = ::Assoc; -// Make sure the help about associatd types is not shown incorrectly +// Make sure the help about associated types is not shown incorrectly type T5 = ::Assoc; //~ WARN not enforced in type aliases type T6 = ::std::vec::Vec; //~ WARN not enforced in type aliases diff --git a/src/test/ui/variance/variance-use-contravariant-struct-1.rs b/src/test/ui/variance/variance-use-contravariant-struct-1.rs index 7f59067483b9..40781fbf082b 100644 --- a/src/test/ui/variance/variance-use-contravariant-struct-1.rs +++ b/src/test/ui/variance/variance-use-contravariant-struct-1.rs @@ -1,4 +1,4 @@ -// Test various uses of structs with distint variances to make sure +// Test various uses of structs with distinct variances to make sure // they permit lifetimes to be approximated as expected. struct SomeStruct(fn(T)); diff --git a/src/test/ui/variance/variance-use-contravariant-struct-2.rs b/src/test/ui/variance/variance-use-contravariant-struct-2.rs index 2113eb2addb9..d4b2d08342a9 100644 --- a/src/test/ui/variance/variance-use-contravariant-struct-2.rs +++ b/src/test/ui/variance/variance-use-contravariant-struct-2.rs @@ -1,4 +1,4 @@ -// Test various uses of structs with distint variances to make sure +// Test various uses of structs with distinct variances to make sure // they permit lifetimes to be approximated as expected. #![allow(dead_code)] diff --git a/src/test/ui/variance/variance-use-invariant-struct-1.rs b/src/test/ui/variance/variance-use-invariant-struct-1.rs index d40dbceb5f8c..72f50f3459d1 100644 --- a/src/test/ui/variance/variance-use-invariant-struct-1.rs +++ b/src/test/ui/variance/variance-use-invariant-struct-1.rs @@ -1,4 +1,4 @@ -// Test various uses of structs with distint variances to make sure +// Test various uses of structs with distinct variances to make sure // they permit lifetimes to be approximated as expected. struct SomeStruct(*mut T); From 85fc39c1e324f7c511fdcf07c956eaca2e92b494 Mon Sep 17 00:00:00 2001 From: Dezhi Wu Date: Thu, 18 Aug 2022 10:59:16 +0800 Subject: [PATCH 3971/5092] Fix ci checks --- compiler/rustc_expand/src/proc_macro.rs | 2 +- .../ui/check-cfg/invalid-arguments.names_simple_ident.stderr | 2 +- .../ui/check-cfg/invalid-arguments.values_simple_ident.stderr | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index b34ab15efe89..1a2ab9d190eb 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -173,7 +173,7 @@ impl MultiItemModifier for DeriveProcMacro { // fail if there have been errors emitted if ecx.sess.parse_sess.span_diagnostic.err_count() > error_count_before { - ecx.struct_span_err(span, "proc-macro derive produced unparsable tokens").emit(); + ecx.struct_span_err(span, "proc-macro derive produced unparseable tokens").emit(); } ExpandResult::Ready(items) diff --git a/src/test/ui/check-cfg/invalid-arguments.names_simple_ident.stderr b/src/test/ui/check-cfg/invalid-arguments.names_simple_ident.stderr index bdfbc3d54a2c..8fadcc1f9f06 100644 --- a/src/test/ui/check-cfg/invalid-arguments.names_simple_ident.stderr +++ b/src/test/ui/check-cfg/invalid-arguments.names_simple_ident.stderr @@ -1,2 +1,2 @@ -error: invalid `--check-cfg` argument: `names("NOT_IDENT")` (`names()` arguments must be simple identifers) +error: invalid `--check-cfg` argument: `names("NOT_IDENT")` (`names()` arguments must be simple identifiers) diff --git a/src/test/ui/check-cfg/invalid-arguments.values_simple_ident.stderr b/src/test/ui/check-cfg/invalid-arguments.values_simple_ident.stderr index b25882baaf3e..061d3f0e971c 100644 --- a/src/test/ui/check-cfg/invalid-arguments.values_simple_ident.stderr +++ b/src/test/ui/check-cfg/invalid-arguments.values_simple_ident.stderr @@ -1,2 +1,2 @@ -error: invalid `--check-cfg` argument: `values("NOT_IDENT")` (`values()` first argument must be a simple identifer) +error: invalid `--check-cfg` argument: `values("NOT_IDENT")` (`values()` first argument must be a simple identifier) From 17706937710756ccc9504caf121f09326446523b Mon Sep 17 00:00:00 2001 From: Dezhi Wu Date: Thu, 18 Aug 2022 16:36:49 +0800 Subject: [PATCH 3972/5092] Correct typo --- RELEASES.md | 2 +- compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs | 2 +- library/core/src/slice/mod.rs | 2 +- library/std/src/sys/windows/cmath.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 5de300394178..72b2c16a01f8 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1442,7 +1442,7 @@ Compatibility Notes - [Mixing Option and Result via `?` is no longer permitted in closures for inferred types.][86831] - [Previously unsound code is no longer permitted where different constructors in branches could require different lifetimes.][85574] -- As previously mentioned the [`std::arch` intrinsic now uses stricter const checking][83278] +- As previously mentioned the [`std::arch` intrinsics now uses stricter const checking][83278] than before and may reject some previously accepted code. - [`i128` multiplication on Cortex M0+ platforms currently unconditionally causes overflow when compiled with `codegen-units = 1`.][86063] diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 4aeb1e3aab95..39e9e784a478 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -203,7 +203,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( sym::transmute => { crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", source_info); } - _ => unimplemented!("unsupported intrinsics {}", intrinsic), + _ => unimplemented!("unsupported intrinsic {}", intrinsic), } return; }; diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 3bd296f37caf..1958745b5868 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -2321,7 +2321,7 @@ impl [T] { } /// Binary searches this slice for a given element. - /// This behaves similar to [`contains`] if this slice is sorted. + /// This behaves similarly to [`contains`] if this slice is sorted. /// /// If the value is found then [`Result::Ok`] is returned, containing the /// index of the matching element. If there are multiple matches, then any diff --git a/library/std/src/sys/windows/cmath.rs b/library/std/src/sys/windows/cmath.rs index 74bb552527f6..43ab8c7ee659 100644 --- a/library/std/src/sys/windows/cmath.rs +++ b/library/std/src/sys/windows/cmath.rs @@ -44,7 +44,7 @@ mod shims { } // On 32-bit x86 MSVC these functions aren't defined, so we just define shims -// which promote everything for f64, perform the calculation, and then demote +// which promote everything to f64, perform the calculation, and then demote // back to f32. While not precisely correct should be "correct enough" for now. #[cfg(all(target_env = "msvc", target_arch = "x86"))] mod shims { From b74654f25c15f69c2bf91e21db46aff32265741f Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 31 Aug 2022 10:27:05 +0000 Subject: [PATCH 3973/5092] Bump UI test dependency --- Cargo.lock | 50 +++-------------------------- Cargo.toml | 2 +- tests/compiletest.rs | 75 ++++++++++++++++++++++---------------------- 3 files changed, 43 insertions(+), 84 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 084b7b27a2fb..1ce41f0a85e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,15 +32,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - [[package]] name = "atty" version = "0.2.14" @@ -229,21 +220,11 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "ctor" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c" -dependencies = [ - "quote", - "syn", -] - [[package]] name = "diff" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" [[package]] name = "env_logger" @@ -464,15 +445,6 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" -[[package]] -name = "output_vt100" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" -dependencies = [ - "winapi", -] - [[package]] name = "owo-colors" version = "3.4.0" @@ -525,18 +497,6 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" -[[package]] -name = "pretty_assertions" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89f989ac94207d048d92db058e4f6ec7342b0971fc58d1271ca148b799b3563" -dependencies = [ - "ansi_term", - "ctor", - "diff", - "output_vt100", -] - [[package]] name = "proc-macro2" version = "1.0.39" @@ -794,16 +754,16 @@ dependencies = [ [[package]] name = "ui_test" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a7bfdb147f57c498ca629c7802b57899de0bb82ae36b6f01f1540da41832f1" +checksum = "ee6b579f4a09b0cf15b910e8edbaaae5bc66d0674a892ec4dbd5e8a5d094d979" dependencies = [ "cargo_metadata", "color-eyre", "colored", "crossbeam", + "diff", "lazy_static", - "pretty_assertions", "regex", "rustc_version", "serde", diff --git a/Cargo.toml b/Cargo.toml index d6d005ac3694..fee63359005e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,7 +40,7 @@ libc = "0.2" [dev-dependencies] colored = "2" -ui_test = "0.1" +ui_test = "0.2" # Features chosen to match those required by env_logger, to avoid rebuilds regex = { version = "1.5.5", default-features = false, features = ["perf", "std"] } lazy_static = "1.4.0" diff --git a/tests/compiletest.rs b/tests/compiletest.rs index fe0d9be28cf2..924d253b4cfc 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -1,7 +1,7 @@ use colored::*; use regex::Regex; use std::path::{Path, PathBuf}; -use std::{env, ffi::OsString, process::Command}; +use std::{env, process::Command}; use ui_test::{color_eyre::Result, Config, DependencyBuilder, Mode, OutputConflictHandling}; fn miri_path() -> PathBuf { @@ -43,30 +43,40 @@ fn run_tests( target: Option, with_dependencies: bool, ) -> Result<()> { + let mut config = Config { + target, + stderr_filters: STDERR.clone(), + stdout_filters: STDOUT.clone(), + root_dir: PathBuf::from(path), + mode, + program: miri_path(), + quiet: false, + ..Config::default() + }; + let in_rustc_test_suite = option_env!("RUSTC_STAGE").is_some(); // Add some flags we always want. - let mut flags: Vec = Vec::new(); - flags.push("--edition".into()); - flags.push("2018".into()); + config.args.push("--edition".into()); + config.args.push("2018".into()); if in_rustc_test_suite { // Less aggressive warnings to make the rustc toolstate management less painful. // (We often get warnings when e.g. a feature gets stabilized or some lint gets added/improved.) - flags.push("-Astable-features".into()); - flags.push("-Aunused".into()); + config.args.push("-Astable-features".into()); + config.args.push("-Aunused".into()); } else { - flags.push("-Dwarnings".into()); - flags.push("-Dunused".into()); + config.args.push("-Dwarnings".into()); + config.args.push("-Dunused".into()); } if let Ok(extra_flags) = env::var("MIRIFLAGS") { for flag in extra_flags.split_whitespace() { - flags.push(flag.into()); + config.args.push(flag.into()); } } - flags.push("-Zui-testing".into()); - if let Some(target) = &target { - flags.push("--target".into()); - flags.push(target.into()); + config.args.push("-Zui-testing".into()); + if let Some(target) = &config.target { + config.args.push("--target".into()); + config.args.push(target.into()); } // If we're on linux, and we're testing the extern-so functionality, @@ -76,45 +86,35 @@ fn run_tests( let so_file_path = build_so_for_c_ffi_tests(); let mut flag = std::ffi::OsString::from("-Zmiri-extern-so-file="); flag.push(so_file_path.into_os_string()); - flags.push(flag); + config.args.push(flag); } let skip_ui_checks = env::var_os("MIRI_SKIP_UI_CHECKS").is_some(); - let output_conflict_handling = match (env::var_os("MIRI_BLESS").is_some(), skip_ui_checks) { + config.output_conflict_handling = match (env::var_os("MIRI_BLESS").is_some(), skip_ui_checks) { (false, false) => OutputConflictHandling::Error, (true, false) => OutputConflictHandling::Bless, (false, true) => OutputConflictHandling::Ignore, (true, true) => panic!("cannot use MIRI_BLESS and MIRI_SKIP_UI_CHECKS at the same time"), }; - // Pass on all unknown arguments as filters. - let mut quiet = false; - let path_filter = std::env::args().skip(1).filter(|arg| { + // Handle command-line arguments. + config.path_filter.extend(std::env::args().skip(1).filter(|arg| { match &**arg { "--quiet" => { - quiet = true; + config.quiet = true; false } _ => true, } - }); + })); let use_std = env::var_os("MIRI_NO_STD").is_none(); - let config = Config { - args: flags, - target, - stderr_filters: STDERR.clone(), - stdout_filters: STDOUT.clone(), - root_dir: PathBuf::from(path), - mode, - path_filter: path_filter.collect(), - program: miri_path(), - output_conflict_handling, - dependencies_crate_manifest_path: (with_dependencies && use_std) - .then(|| Path::new("test_dependencies").join("Cargo.toml")), - dependency_builder: Some(DependencyBuilder { + if with_dependencies && use_std { + config.dependencies_crate_manifest_path = + Some(Path::new("test_dependencies").join("Cargo.toml")); + config.dependency_builder = Some(DependencyBuilder { program: std::env::var_os("CARGO").unwrap().into(), args: vec![ "run".into(), @@ -124,9 +124,8 @@ fn run_tests( "miri".into(), ], envs: vec![], - }), - quiet, - }; + }); + } ui_test::run_tests(config) } @@ -214,10 +213,10 @@ fn main() -> Result<()> { ui(Mode::Pass, "tests/pass", WithoutDependencies)?; ui(Mode::Pass, "tests/pass-dep", WithDependencies)?; ui(Mode::Panic, "tests/panic", WithDependencies)?; - ui(Mode::Fail, "tests/fail", WithDependencies)?; + ui(Mode::Fail { require_patterns: true }, "tests/fail", WithDependencies)?; if cfg!(target_os = "linux") { ui(Mode::Pass, "tests/extern-so/pass", WithoutDependencies)?; - ui(Mode::Fail, "tests/extern-so/fail", WithDependencies)?; + ui(Mode::Fail { require_patterns: true }, "tests/extern-so/fail", WithDependencies)?; } Ok(()) From eafc100b50684b629268acfb58b417ba1bbb3ceb Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 31 Aug 2022 11:06:35 +0000 Subject: [PATCH 3974/5092] Bump ui_test to 0.3.1 --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- tests/compiletest.rs | 21 +++++++++------------ 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1ce41f0a85e3..28be08c467cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -754,9 +754,9 @@ dependencies = [ [[package]] name = "ui_test" -version = "0.2.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee6b579f4a09b0cf15b910e8edbaaae5bc66d0674a892ec4dbd5e8a5d094d979" +checksum = "7d1f546a5883ae78da735bba529ec1116661e2f73582f23920d994dc97da3a22" dependencies = [ "cargo_metadata", "color-eyre", diff --git a/Cargo.toml b/Cargo.toml index fee63359005e..0a3dfc2a84e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,7 +40,7 @@ libc = "0.2" [dev-dependencies] colored = "2" -ui_test = "0.2" +ui_test = "0.3.1" # Features chosen to match those required by env_logger, to avoid rebuilds regex = { version = "1.5.5", default-features = false, features = ["perf", "std"] } lazy_static = "1.4.0" diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 924d253b4cfc..fc5b8c6fa99f 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -2,7 +2,7 @@ use colored::*; use regex::Regex; use std::path::{Path, PathBuf}; use std::{env, process::Command}; -use ui_test::{color_eyre::Result, Config, DependencyBuilder, Mode, OutputConflictHandling}; +use ui_test::{color_eyre::Result, Config, Mode, OutputConflictHandling}; fn miri_path() -> PathBuf { PathBuf::from(option_env!("MIRI").unwrap_or(env!("CARGO_BIN_EXE_miri"))) @@ -114,17 +114,14 @@ fn run_tests( if with_dependencies && use_std { config.dependencies_crate_manifest_path = Some(Path::new("test_dependencies").join("Cargo.toml")); - config.dependency_builder = Some(DependencyBuilder { - program: std::env::var_os("CARGO").unwrap().into(), - args: vec![ - "run".into(), - "--manifest-path".into(), - "cargo-miri/Cargo.toml".into(), - "--".into(), - "miri".into(), - ], - envs: vec![], - }); + config.dependency_builder.args = vec![ + "run".into(), + "--manifest-path".into(), + "cargo-miri/Cargo.toml".into(), + "--".into(), + "miri".into(), + "run".into(), + ]; } ui_test::run_tests(config) } From 10804672c221882cfd1c94809ad09846a35fe49d Mon Sep 17 00:00:00 2001 From: Bryanskiy Date: Sun, 14 Aug 2022 17:04:30 +0300 Subject: [PATCH 3975/5092] access_levels.rs refactor --- compiler/rustc_resolve/src/access_levels.rs | 158 +++++++------------- compiler/rustc_resolve/src/imports.rs | 27 ++-- compiler/rustc_resolve/src/lib.rs | 18 +++ 3 files changed, 80 insertions(+), 123 deletions(-) diff --git a/compiler/rustc_resolve/src/access_levels.rs b/compiler/rustc_resolve/src/access_levels.rs index 3fba923d9fdf..c98f7f0ccef4 100644 --- a/compiler/rustc_resolve/src/access_levels.rs +++ b/compiler/rustc_resolve/src/access_levels.rs @@ -1,25 +1,21 @@ +use crate::imports::ImportKind; +use crate::NameBinding; +use crate::NameBindingKind; +use crate::Resolver; use rustc_ast::ast; use rustc_ast::visit; use rustc_ast::visit::Visitor; use rustc_ast::Crate; use rustc_ast::EnumDef; -use rustc_ast::ForeignMod; use rustc_ast::NodeId; use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::CRATE_DEF_ID; use rustc_middle::middle::privacy::AccessLevel; -use rustc_middle::ty::Visibility; +use rustc_middle::ty::DefIdTree; use rustc_span::sym; -use crate::imports::ImportKind; -use crate::BindingKey; -use crate::NameBinding; -use crate::NameBindingKind; -use crate::Resolver; - pub struct AccessLevelsVisitor<'r, 'a> { r: &'r mut Resolver<'a>, - prev_level: Option, changed: bool, } @@ -28,11 +24,10 @@ impl<'r, 'a> AccessLevelsVisitor<'r, 'a> { /// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we /// need access to a TyCtxt for that. pub fn compute_access_levels<'c>(r: &'r mut Resolver<'a>, krate: &'c Crate) { - let mut visitor = - AccessLevelsVisitor { r, changed: false, prev_level: Some(AccessLevel::Public) }; + let mut visitor = AccessLevelsVisitor { r, changed: false }; visitor.set_access_level_def_id(CRATE_DEF_ID, Some(AccessLevel::Public)); - visitor.set_exports_access_level(CRATE_DEF_ID); + visitor.set_bindings_access_level(CRATE_DEF_ID); while visitor.changed { visitor.reset(); @@ -44,15 +39,17 @@ impl<'r, 'a> AccessLevelsVisitor<'r, 'a> { fn reset(&mut self) { self.changed = false; - self.prev_level = Some(AccessLevel::Public); } - /// Update the access level of the exports of the given module accordingly. The module access + /// Update the access level of the bindings in the given module accordingly. The module access /// level has to be Exported or Public. /// This will also follow `use` chains (see PrivacyVisitor::set_import_binding_access_level). - fn set_exports_access_level(&mut self, module_id: LocalDefId) { + fn set_bindings_access_level(&mut self, module_id: LocalDefId) { assert!(self.r.module_map.contains_key(&&module_id.to_def_id())); - + let module_level = self.r.access_levels.map.get(&module_id).copied(); + if !module_level.is_some() { + return; + } // Set the given binding access level to `AccessLevel::Public` and // sets the rest of the `use` chain to `AccessLevel::Exported` until // we hit the actual exported item. @@ -72,28 +69,20 @@ impl<'r, 'a> AccessLevelsVisitor<'r, 'a> { } }; - let module_level = self.r.access_levels.map.get(&module_id).copied(); - assert!(module_level >= Some(AccessLevel::Exported)); + let module = self.r.get_module(module_id.to_def_id()).unwrap(); + let resolutions = self.r.resolutions(module); - if let Some(exports) = self.r.reexport_map.get(&module_id) { - let pub_exports = exports - .iter() - .filter(|ex| ex.vis == Visibility::Public) - .cloned() - .collect::>(); - - let module = self.r.get_module(module_id.to_def_id()).unwrap(); - for export in pub_exports.into_iter() { - if let Some(export_def_id) = export.res.opt_def_id().and_then(|id| id.as_local()) { - self.set_access_level_def_id(export_def_id, Some(AccessLevel::Exported)); - } - - if let Some(ns) = export.res.ns() { - let key = BindingKey { ident: export.ident, ns, disambiguator: 0 }; - let name_res = self.r.resolution(module, key); - if let Some(binding) = name_res.borrow().binding() { - set_import_binding_access_level(self, binding, module_level) - } + for (.., name_resolution) in resolutions.borrow().iter() { + if let Some(binding) = name_resolution.borrow().binding() && binding.vis.is_public() && !binding.is_ambiguity() { + let access_level = match binding.is_import() { + true => { + set_import_binding_access_level(self, binding, module_level); + Some(AccessLevel::Exported) + }, + false => module_level, + }; + if let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) { + self.set_access_level_def_id(def_id, access_level); } } } @@ -127,97 +116,59 @@ impl<'r, 'a> AccessLevelsVisitor<'r, 'a> { impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> { fn visit_item(&mut self, item: &'ast ast::Item) { - let inherited_item_level = match item.kind { + let def_id = self.r.local_def_id(item.id); + // Set access level of nested items. + // If it's a mod, also make the visitor walk all of its items + match item.kind { // Resolved in rustc_privacy when types are available ast::ItemKind::Impl(..) => return, - // Only exported `macro_rules!` items are public, but they always are - ast::ItemKind::MacroDef(ref macro_def) if macro_def.macro_rules => { - let is_macro_export = - item.attrs.iter().any(|attr| attr.has_name(sym::macro_export)); - if is_macro_export { Some(AccessLevel::Public) } else { None } - } - - // Foreign modules inherit level from parents. - ast::ItemKind::ForeignMod(..) => self.prev_level, - - // Other `pub` items inherit levels from parents. - ast::ItemKind::ExternCrate(..) - | ast::ItemKind::Use(..) - | ast::ItemKind::Static(..) - | ast::ItemKind::Const(..) - | ast::ItemKind::Fn(..) - | ast::ItemKind::Mod(..) - | ast::ItemKind::GlobalAsm(..) - | ast::ItemKind::TyAlias(..) - | ast::ItemKind::Enum(..) - | ast::ItemKind::Struct(..) - | ast::ItemKind::Union(..) - | ast::ItemKind::Trait(..) - | ast::ItemKind::TraitAlias(..) - | ast::ItemKind::MacroDef(..) => { - if item.vis.kind.is_pub() { - self.prev_level - } else { - None - } - } - // Should be unreachable at this stage ast::ItemKind::MacCall(..) => panic!( "ast::ItemKind::MacCall encountered, this should not anymore appear at this stage" ), - }; - let access_level = self.set_access_level(item.id, inherited_item_level); + // Foreign modules inherit level from parents. + ast::ItemKind::ForeignMod(..) => { + let parent_level = + self.r.access_levels.map.get(&self.r.local_parent(def_id)).copied(); + self.set_access_level(item.id, parent_level); + } + + // Only exported `macro_rules!` items are public, but they always are + ast::ItemKind::MacroDef(ref macro_def) if macro_def.macro_rules => { + if item.attrs.iter().any(|attr| attr.has_name(sym::macro_export)) { + self.set_access_level(item.id, Some(AccessLevel::Public)); + } + } - // Set access level of nested items. - // If it's a mod, also make the visitor walk all of its items - match item.kind { ast::ItemKind::Mod(..) => { - if access_level.is_some() { - self.set_exports_access_level(self.r.local_def_id(item.id)); - } - - let orig_level = std::mem::replace(&mut self.prev_level, access_level); + self.set_bindings_access_level(def_id); visit::walk_item(self, item); - self.prev_level = orig_level; } - ast::ItemKind::ForeignMod(ForeignMod { ref items, .. }) => { - for nested in items { - if nested.vis.kind.is_pub() { - self.set_access_level(nested.id, access_level); - } - } - } ast::ItemKind::Enum(EnumDef { ref variants }, _) => { + self.set_bindings_access_level(def_id); for variant in variants { - let variant_level = self.set_access_level(variant.id, access_level); - if let Some(ctor_id) = variant.data.ctor_id() { - self.set_access_level(ctor_id, access_level); - } - + let variant_def_id = self.r.local_def_id(variant.id); + let variant_level = self.r.access_levels.map.get(&variant_def_id).copied(); for field in variant.data.fields() { self.set_access_level(field.id, variant_level); } } } - ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => { - if let Some(ctor_id) = def.ctor_id() { - self.set_access_level(ctor_id, access_level); - } + ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => { + let inherited_level = self.r.access_levels.map.get(&def_id).copied(); for field in def.fields() { if field.vis.kind.is_pub() { - self.set_access_level(field.id, access_level); + self.set_access_level(field.id, inherited_level); } } } - ast::ItemKind::Trait(ref trait_kind) => { - for nested in trait_kind.items.iter() { - self.set_access_level(nested.id, access_level); - } + + ast::ItemKind::Trait(..) => { + self.set_bindings_access_level(def_id); } ast::ItemKind::ExternCrate(..) @@ -229,9 +180,6 @@ impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> { | ast::ItemKind::TraitAlias(..) | ast::ItemKind::MacroDef(..) | ast::ItemKind::Fn(..) => return, - - // Unreachable kinds - ast::ItemKind::Impl(..) | ast::ItemKind::MacCall(..) => unreachable!(), } } } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index c2491c6ebdec..9a2c39fab72f 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1135,24 +1135,15 @@ impl<'a, 'b> ImportResolver<'a, 'b> { if let Some(def_id) = module.opt_def_id() { let mut reexports = Vec::new(); - module.for_each_child(self.r, |_, ident, _, binding| { - // FIXME: Consider changing the binding inserted by `#[macro_export] macro_rules` - // into the crate root to actual `NameBindingKind::Import`. - if binding.is_import() - || matches!(binding.kind, NameBindingKind::Res(_, _is_macro_export @ true)) - { - let res = binding.res().expect_non_local(); - // Ambiguous imports are treated as errors at this point and are - // not exposed to other crates (see #36837 for more details). - if res != def::Res::Err && !binding.is_ambiguity() { - reexports.push(ModChild { - ident, - res, - vis: binding.vis, - span: binding.span, - macro_rules: false, - }); - } + module.for_each_child(self.r, |this, ident, _, binding| { + if let Some(res) = this.is_reexport(binding) { + reexports.push(ModChild { + ident, + res, + vis: binding.vis, + span: binding.span, + macro_rules: false, + }); } }); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 66090c96d1ee..74f73bbd85cd 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -2021,6 +2021,24 @@ impl<'a> Resolver<'a> { } self.main_def = Some(MainDefinition { res, is_import, span }); } + + // Items that go to reexport table encoded to metadata and visible through it to other crates. + fn is_reexport(&self, binding: &NameBinding<'a>) -> Option> { + // FIXME: Consider changing the binding inserted by `#[macro_export] macro_rules` + // into the crate root to actual `NameBindingKind::Import`. + if binding.is_import() + || matches!(binding.kind, NameBindingKind::Res(_, _is_macro_export @ true)) + { + let res = binding.res().expect_non_local(); + // Ambiguous imports are treated as errors at this point and are + // not exposed to other crates (see #36837 for more details). + if res != def::Res::Err && !binding.is_ambiguity() { + return Some(res); + } + } + + return None; + } } fn names_to_string(names: &[Symbol]) -> String { From 0111fb00dac90d67f8d770ca2a25923cfd24e25d Mon Sep 17 00:00:00 2001 From: Bryanskiy Date: Sun, 14 Aug 2022 17:05:17 +0300 Subject: [PATCH 3976/5092] add TestReachabilityVisitor --- .../locales/en-US/privacy.ftl | 2 + compiler/rustc_feature/src/builtin_attrs.rs | 1 + compiler/rustc_privacy/src/errors.rs | 8 ++ compiler/rustc_privacy/src/lib.rs | 62 ++++++++- compiler/rustc_span/src/symbol.rs | 1 + src/test/ui/privacy/access_levels.rs | 49 +++++++ src/test/ui/privacy/access_levels.stderr | 125 ++++++++++++++++++ 7 files changed, 246 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/privacy/access_levels.rs create mode 100644 src/test/ui/privacy/access_levels.stderr diff --git a/compiler/rustc_error_messages/locales/en-US/privacy.ftl b/compiler/rustc_error_messages/locales/en-US/privacy.ftl index 223092a74bd9..da987152ff66 100644 --- a/compiler/rustc_error_messages/locales/en-US/privacy.ftl +++ b/compiler/rustc_error_messages/locales/en-US/privacy.ftl @@ -11,6 +11,8 @@ privacy_in_public_interface = {$vis_descr} {$kind} `{$descr}` in public interfac .label = can't leak {$vis_descr} {$kind} .visibility_label = `{$descr}` declared as {$vis_descr} +privacy_report_access_level = {$descr} + privacy_from_private_dep_in_public_interface = {$kind} `{$descr}` from private dependency '{$krate}' in public interface diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 0487270b52a9..0c88379d4989 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -758,6 +758,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // Internal attributes, Testing: // ========================================================================== + rustc_attr!(TEST, rustc_access_level, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_outlives, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word), WarnFollowing), diff --git a/compiler/rustc_privacy/src/errors.rs b/compiler/rustc_privacy/src/errors.rs index 1e423ddb7102..63f83f8965ec 100644 --- a/compiler/rustc_privacy/src/errors.rs +++ b/compiler/rustc_privacy/src/errors.rs @@ -75,6 +75,14 @@ pub struct InPublicInterface<'a> { pub vis_span: Span, } +#[derive(SessionDiagnostic)] +#[diag(privacy::report_access_level)] +pub struct ReportAccessLevel { + #[primary_span] + pub span: Span, + pub descr: String, +} + #[derive(LintDiagnostic)] #[diag(privacy::from_private_dep_in_public_interface)] pub struct FromPrivateDependencyInPublicInterface<'a> { diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 5d562f18a815..075a1411f02b 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -30,7 +30,7 @@ use rustc_middle::ty::{self, Const, DefIdTree, GenericParamDefKind}; use rustc_middle::ty::{TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; use rustc_session::lint; use rustc_span::hygiene::Transparency; -use rustc_span::symbol::{kw, Ident}; +use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; use std::marker::PhantomData; @@ -39,7 +39,8 @@ use std::{cmp, fmt, mem}; use errors::{ FieldIsPrivate, FieldIsPrivateLabel, FromPrivateDependencyInPublicInterface, InPublicInterface, - InPublicInterfaceTraits, ItemIsPrivate, PrivateInPublicLint, UnnamedItemIsPrivate, + InPublicInterfaceTraits, ItemIsPrivate, PrivateInPublicLint, ReportAccessLevel, + UnnamedItemIsPrivate, }; //////////////////////////////////////////////////////////////////////////////// @@ -904,6 +905,60 @@ impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> } } +//////////////////////////////////////////////////////////////////////////////// +/// Visitor, used for AccessLevels table checking +//////////////////////////////////////////////////////////////////////////////// +pub struct TestReachabilityVisitor<'tcx, 'a> { + tcx: TyCtxt<'tcx>, + access_levels: &'a AccessLevels, +} + +impl<'tcx, 'a> TestReachabilityVisitor<'tcx, 'a> { + fn access_level_diagnostic(&mut self, def_id: LocalDefId) { + if self.tcx.has_attr(def_id.to_def_id(), sym::rustc_access_level) { + let access_level = format!("{:?}", self.access_levels.map.get(&def_id)); + let span = self.tcx.def_span(def_id.to_def_id()); + self.tcx.sess.emit_err(ReportAccessLevel { span, descr: access_level }); + } + } +} + +impl<'tcx, 'a> Visitor<'tcx> for TestReachabilityVisitor<'tcx, 'a> { + fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { + self.access_level_diagnostic(item.def_id); + + match item.kind { + hir::ItemKind::Enum(ref def, _) => { + for variant in def.variants.iter() { + let variant_id = self.tcx.hir().local_def_id(variant.id); + self.access_level_diagnostic(variant_id); + for field in variant.data.fields() { + let def_id = self.tcx.hir().local_def_id(field.hir_id); + self.access_level_diagnostic(def_id); + } + } + } + hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => { + for field in def.fields() { + let def_id = self.tcx.hir().local_def_id(field.hir_id); + self.access_level_diagnostic(def_id); + } + } + _ => {} + } + } + + fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem<'tcx>) { + self.access_level_diagnostic(item.def_id); + } + fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem<'tcx>) { + self.access_level_diagnostic(item.def_id); + } + fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { + self.access_level_diagnostic(item.def_id); + } +} + ////////////////////////////////////////////////////////////////////////////////////// /// Name privacy visitor, checks privacy and reports violations. /// Most of name privacy checks are performed during the main resolution phase, @@ -2042,6 +2097,9 @@ fn privacy_access_levels(tcx: TyCtxt<'_>, (): ()) -> &AccessLevels { } } + let mut check_visitor = TestReachabilityVisitor { tcx, access_levels: &visitor.access_levels }; + tcx.hir().visit_all_item_likes_in_crate(&mut check_visitor); + tcx.arena.alloc(visitor.access_levels) } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 6eca7dc52b26..f854395ff814 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1206,6 +1206,7 @@ symbols! { rust_eh_unregister_frames, rust_oom, rustc, + rustc_access_level, rustc_allocator, rustc_allocator_nounwind, rustc_allocator_zeroed, diff --git a/src/test/ui/privacy/access_levels.rs b/src/test/ui/privacy/access_levels.rs new file mode 100644 index 000000000000..d51d2b57267b --- /dev/null +++ b/src/test/ui/privacy/access_levels.rs @@ -0,0 +1,49 @@ +#![feature(rustc_attrs)] + +#[rustc_access_level] mod outer { //~ ERROR None + #[rustc_access_level] pub mod inner { //~ ERROR Some(Exported) + #[rustc_access_level] + extern "C" { //~ ERROR Some(Exported) + #[rustc_access_level] static a: u8; //~ ERROR None + #[rustc_access_level] pub fn b(); //~ ERROR Some(Exported) + } + #[rustc_access_level] + pub trait Trait { //~ ERROR Some(Exported) + #[rustc_access_level] const A: i32; //~ ERROR Some(Exported) + #[rustc_access_level] type B; //~ ERROR Some(Exported) + } + + #[rustc_access_level] + pub struct Struct { //~ ERROR Some(Exported) + #[rustc_access_level] a: u8, //~ ERROR None + #[rustc_access_level] pub b: u8, //~ ERROR Some(Exported) + } + + #[rustc_access_level] + pub union Union { //~ ERROR Some(Exported) + #[rustc_access_level] a: u8, //~ ERROR None + #[rustc_access_level] pub b: u8, //~ ERROR Some(Exported) + } + + #[rustc_access_level] + pub enum Enum { //~ ERROR Some(Exported) + #[rustc_access_level] A( //~ ERROR Some(Exported) + #[rustc_access_level] Struct, //~ ERROR Some(Exported) + #[rustc_access_level] Union, //~ ERROR Some(Exported) + ), + } + } + + #[rustc_access_level] macro_rules! none_macro { //~ ERROR None + () => {}; + } + + #[macro_export] + #[rustc_access_level] macro_rules! public_macro { //~ ERROR Some(Public) + () => {}; + } +} + +pub use outer::inner; + +fn main() {} diff --git a/src/test/ui/privacy/access_levels.stderr b/src/test/ui/privacy/access_levels.stderr new file mode 100644 index 000000000000..f326293c384a --- /dev/null +++ b/src/test/ui/privacy/access_levels.stderr @@ -0,0 +1,125 @@ +error: None + --> $DIR/access_levels.rs:3:23 + | +LL | #[rustc_access_level] mod outer { + | ^^^^^^^^^ + +error: Some(Exported) + --> $DIR/access_levels.rs:4:27 + | +LL | #[rustc_access_level] pub mod inner { + | ^^^^^^^^^^^^^ + +error: Some(Exported) + --> $DIR/access_levels.rs:6:9 + | +LL | / extern "C" { +LL | | #[rustc_access_level] static a: u8; +LL | | #[rustc_access_level] pub fn b(); +LL | | } + | |_________^ + +error: Some(Exported) + --> $DIR/access_levels.rs:11:9 + | +LL | pub trait Trait { + | ^^^^^^^^^^^^^^^ + +error: Some(Exported) + --> $DIR/access_levels.rs:17:9 + | +LL | pub struct Struct { + | ^^^^^^^^^^^^^^^^^ + +error: None + --> $DIR/access_levels.rs:18:35 + | +LL | #[rustc_access_level] a: u8, + | ^^^^^ + +error: Some(Exported) + --> $DIR/access_levels.rs:19:35 + | +LL | #[rustc_access_level] pub b: u8, + | ^^^^^^^^^ + +error: Some(Exported) + --> $DIR/access_levels.rs:23:9 + | +LL | pub union Union { + | ^^^^^^^^^^^^^^^ + +error: None + --> $DIR/access_levels.rs:24:35 + | +LL | #[rustc_access_level] a: u8, + | ^^^^^ + +error: Some(Exported) + --> $DIR/access_levels.rs:25:35 + | +LL | #[rustc_access_level] pub b: u8, + | ^^^^^^^^^ + +error: Some(Exported) + --> $DIR/access_levels.rs:29:9 + | +LL | pub enum Enum { + | ^^^^^^^^^^^^^ + +error: Some(Exported) + --> $DIR/access_levels.rs:30:35 + | +LL | #[rustc_access_level] A( + | ^ + +error: Some(Exported) + --> $DIR/access_levels.rs:31:39 + | +LL | #[rustc_access_level] Struct, + | ^^^^^^ + +error: Some(Exported) + --> $DIR/access_levels.rs:32:39 + | +LL | #[rustc_access_level] Union, + | ^^^^^ + +error: None + --> $DIR/access_levels.rs:37:27 + | +LL | #[rustc_access_level] macro_rules! none_macro { + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: Some(Public) + --> $DIR/access_levels.rs:42:27 + | +LL | #[rustc_access_level] macro_rules! public_macro { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: Some(Exported) + --> $DIR/access_levels.rs:12:35 + | +LL | #[rustc_access_level] const A: i32; + | ^^^^^^^^^^^^ + +error: Some(Exported) + --> $DIR/access_levels.rs:13:35 + | +LL | #[rustc_access_level] type B; + | ^^^^^^ + +error: None + --> $DIR/access_levels.rs:7:35 + | +LL | #[rustc_access_level] static a: u8; + | ^^^^^^^^^^^^ + +error: Some(Exported) + --> $DIR/access_levels.rs:8:35 + | +LL | #[rustc_access_level] pub fn b(); + | ^^^^^^^^^^ + +error: aborting due to 20 previous errors + From b8075e4550a3ec9110930b41e09e77266482e54f Mon Sep 17 00:00:00 2001 From: Yuanheng Li <520dhh@gmail.com> Date: Sun, 21 Aug 2022 21:37:05 +0800 Subject: [PATCH 3977/5092] migrate rustc_query_system to use SessionDiagnostic with manual impl SessionDiagnostic --- .../locales/en-US/query_system.ftl | 21 +++++++ compiler/rustc_error_messages/src/lib.rs | 1 + compiler/rustc_query_system/src/error.rs | 60 +++++++++++++++++++ compiler/rustc_query_system/src/lib.rs | 3 + compiler/rustc_query_system/src/query/job.rs | 55 ++++++----------- .../rustc_query_system/src/query/plumbing.rs | 14 ++--- 6 files changed, 108 insertions(+), 46 deletions(-) create mode 100644 compiler/rustc_error_messages/locales/en-US/query_system.ftl create mode 100644 compiler/rustc_query_system/src/error.rs diff --git a/compiler/rustc_error_messages/locales/en-US/query_system.ftl b/compiler/rustc_error_messages/locales/en-US/query_system.ftl new file mode 100644 index 000000000000..2d8c7a651225 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/query_system.ftl @@ -0,0 +1,21 @@ +query_system_reentrant = internal compiler error: re-entrant incremental verify failure, suppressing message + +query_system_increment_compilation = internal compiler error: encountered incremental compilation error with {$dep_node} + .help = This is a known issue with the compiler. Run {$run_cmd} to allow your project to compile + +query_system_increment_compilation_note1 = Please follow the instructions below to create a bug report with the provided information +query_system_increment_compilation_note2 = See for more information + +query_system_cycle = cycle detected when {$stack_bottom} + +query_system_cycle_usage = cycle used when {$usage} + +query_system_cycle_stack_single = ...which immediately requires {$stack_bottom} again + +query_system_cycle_stack_multiple = ...which again requires {$stack_bottom}, completing the cycle + +query_system_cycle_recursive_ty_alias = type aliases cannot be recursive +query_system_cycle_recursive_ty_alias_help1 = consider using a struct, enum, or union instead to break the cycle +query_system_cycle_recursive_ty_alias_help2 = see for more information + +query_system_cycle_recursive_trait_alias = trait aliases cannot be recursive diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index d1ac326a72c6..601fa4c72f0b 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -52,6 +52,7 @@ fluent_messages! { ty_utils => "../locales/en-US/ty_utils.ftl", typeck => "../locales/en-US/typeck.ftl", mir_dataflow => "../locales/en-US/mir_dataflow.ftl", + query_system => "../locales/en-US/query_system.ftl", } pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES}; diff --git a/compiler/rustc_query_system/src/error.rs b/compiler/rustc_query_system/src/error.rs new file mode 100644 index 000000000000..2ae6d10b8283 --- /dev/null +++ b/compiler/rustc_query_system/src/error.rs @@ -0,0 +1,60 @@ +use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed}; +use rustc_session::SessionDiagnostic; +use rustc_span::Span; + +pub struct Cycle { + pub span: Span, + pub stack_bottom: String, + pub upper_stack_info: Vec<(Span, String)>, + pub recursive_ty_alias: bool, + pub recursive_trait_alias: bool, + pub cycle_usage: Option<(Span, String)>, +} + +impl SessionDiagnostic<'_> for Cycle { + fn into_diagnostic( + self, + sess: &'_ rustc_session::parse::ParseSess, + ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = sess.struct_err(rustc_errors::fluent::query_system::cycle); + diag.set_span(self.span); + diag.code(rustc_errors::DiagnosticId::Error("E0391".to_string())); + let upper_stack_len = self.upper_stack_info.len(); + for (span, desc) in self.upper_stack_info.into_iter() { + // FIXME: use fluent translation + diag.span_note(span, &format!("...which requires {}...", desc)); + } + diag.set_arg("stack_bottom", self.stack_bottom); + if upper_stack_len == 0 { + diag.note(rustc_errors::fluent::query_system::cycle_stack_single); + } else { + diag.note(rustc_errors::fluent::query_system::cycle_stack_multiple); + } + if self.recursive_trait_alias { + diag.note(rustc_errors::fluent::query_system::cycle_recursive_trait_alias); + } else if self.recursive_ty_alias { + diag.note(rustc_errors::fluent::query_system::cycle_recursive_ty_alias); + diag.help(rustc_errors::fluent::query_system::cycle_recursive_ty_alias_help1); + diag.help(rustc_errors::fluent::query_system::cycle_recursive_ty_alias_help2); + } + if let Some((span, desc)) = self.cycle_usage { + diag.set_arg("usage", desc); + diag.span_note(span, rustc_errors::fluent::query_system::cycle_usage); + } + diag + } +} + +#[derive(SessionDiagnostic)] +#[diag(query_system::reentrant)] +pub struct Reentrant; + +#[derive(SessionDiagnostic)] +#[diag(query_system::increment_compilation)] +#[help] +#[note(query_system::increment_compilation_note1)] +#[note(query_system::increment_compilation_note2)] +pub struct IncrementCompilation { + pub run_cmd: String, + pub dep_node: String, +} diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index 68284dcaa0be..da775893a2b0 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -5,6 +5,8 @@ #![feature(min_specialization)] #![feature(extern_types)] #![allow(rustc::potential_query_instability)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate tracing; @@ -15,5 +17,6 @@ extern crate rustc_macros; pub mod cache; pub mod dep_graph; +mod error; pub mod ich; pub mod query; diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 6d2aff38172f..718ec14db362 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -1,12 +1,10 @@ use crate::query::plumbing::CycleError; use crate::query::{QueryContext, QueryStackFrame}; -use rustc_hir::def::DefKind; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{ - struct_span_err, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, Handler, Level, -}; -use rustc_session::Session; +use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed, Handler, Level}; +use rustc_hir::def::DefKind; +use rustc_session::{Session, SessionDiagnostic}; use rustc_span::Span; use std::hash::Hash; @@ -536,46 +534,29 @@ pub(crate) fn report_cycle<'a>( assert!(!stack.is_empty()); let span = stack[0].query.default_span(stack[1 % stack.len()].span); - let mut err = - struct_span_err!(sess, span, E0391, "cycle detected when {}", stack[0].query.description); + + let mut cycle_diag = crate::error::Cycle { + span, + upper_stack_info: Vec::with_capacity(stack.len() - 1), + stack_bottom: stack[0].query.description.to_owned(), + recursive_ty_alias: false, + recursive_trait_alias: false, + cycle_usage: usage.map(|(span, query)| (query.default_span(span), query.description)), + }; for i in 1..stack.len() { let query = &stack[i].query; let span = query.default_span(stack[(i + 1) % stack.len()].span); - err.span_note(span, &format!("...which requires {}...", query.description)); + cycle_diag.upper_stack_info.push((span, query.description.to_owned())); } - if stack.len() == 1 { - err.note(&format!("...which immediately requires {} again", stack[0].query.description)); - } else { - err.note(&format!( - "...which again requires {}, completing the cycle", - stack[0].query.description - )); + if stack.iter().all(|entry| entry.query.def_kind == Some(DefKind::TyAlias)) { + cycle_diag.recursive_ty_alias = true; + } else if stack.iter().all(|entry| entry.query.def_kind == Some(DefKind::TraitAlias)) { + cycle_diag.recursive_trait_alias = true; } - if stack.iter().all(|entry| { - entry - .query - .def_kind - .map_or(false, |def_kind| matches!(def_kind, DefKind::TyAlias | DefKind::TraitAlias)) - }) { - if stack.iter().all(|entry| { - entry.query.def_kind.map_or(false, |def_kind| matches!(def_kind, DefKind::TyAlias)) - }) { - err.note("type aliases cannot be recursive"); - err.help("consider using a struct, enum, or union instead to break the cycle"); - err.help("see for more information"); - } else { - err.note("trait aliases cannot be recursive"); - } - } - - if let Some((span, query)) = usage { - err.span_note(query.default_span(span), &format!("cycle used when {}", query.description)); - } - - err + cycle_diag.into_diagnostic(&sess.parse_sess) } pub fn print_query_stack( diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 6ae9147ff774..e97411b777b4 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -618,16 +618,12 @@ fn incremental_verify_ich_cold(sess: &Session, dep_node: DebugArg<'_>, result: D let old_in_panic = INSIDE_VERIFY_PANIC.with(|in_panic| in_panic.replace(true)); if old_in_panic { - sess.struct_err( - "internal compiler error: re-entrant incremental verify failure, suppressing message", - ) - .emit(); + sess.emit_err(crate::error::Reentrant); } else { - sess.struct_err(&format!("internal compiler error: encountered incremental compilation error with {:?}", dep_node)) - .help(&format!("This is a known issue with the compiler. Run {} to allow your project to compile", run_cmd)) - .note("Please follow the instructions below to create a bug report with the provided information") - .note("See for more information") - .emit(); + sess.emit_err(crate::error::IncrementCompilation { + run_cmd, + dep_node: format!("{:?}", dep_node), + }); panic!("Found unstable fingerprints for {:?}: {:?}", dep_node, result); } From d7e07c0b6b08e898a0720bf9c2fd2a22404bdfec Mon Sep 17 00:00:00 2001 From: Li Yuanheng <520dhh@gmail.com> Date: Tue, 23 Aug 2022 07:23:36 +0800 Subject: [PATCH 3978/5092] link related issue to FIXME Co-authored-by: David Wood --- compiler/rustc_query_system/src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_query_system/src/error.rs b/compiler/rustc_query_system/src/error.rs index 2ae6d10b8283..515a022e9d9f 100644 --- a/compiler/rustc_query_system/src/error.rs +++ b/compiler/rustc_query_system/src/error.rs @@ -21,7 +21,7 @@ impl SessionDiagnostic<'_> for Cycle { diag.code(rustc_errors::DiagnosticId::Error("E0391".to_string())); let upper_stack_len = self.upper_stack_info.len(); for (span, desc) in self.upper_stack_info.into_iter() { - // FIXME: use fluent translation + // FIXME(#100717): use fluent translation diag.span_note(span, &format!("...which requires {}...", desc)); } diag.set_arg("stack_bottom", self.stack_bottom); From 240f92aae8344034f92edc809fcc2581f9bed333 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Aug 2022 13:36:25 +0200 Subject: [PATCH 3979/5092] add comment --- tests/compiletest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index fc5b8c6fa99f..6b5668e2d6c4 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -120,7 +120,7 @@ fn run_tests( "cargo-miri/Cargo.toml".into(), "--".into(), "miri".into(), - "run".into(), + "run".into(), // There is no `cargo miri build` so we just use `cargo miri run`. ]; } ui_test::run_tests(config) From ac638c1f5fca36484506415319ab254ad522a692 Mon Sep 17 00:00:00 2001 From: Yuanheng Li <520dhh@gmail.com> Date: Tue, 23 Aug 2022 11:19:38 +0800 Subject: [PATCH 3980/5092] use derive proc macro to impl SessionDiagnostic fixes `SessionSubdiagnostic` to accept multiple attributes emitting list of fluent message remains unresolved --- .../locales/en-US/query_system.ftl | 2 + .../src/diagnostics/subdiagnostic.rs | 708 +++++++----------- compiler/rustc_query_system/src/error.rs | 87 ++- compiler/rustc_query_system/src/lib.rs | 2 +- compiler/rustc_query_system/src/query/job.rs | 43 +- .../subdiagnostic-derive.rs | 164 +--- .../subdiagnostic-derive.stderr | 244 ++---- 7 files changed, 427 insertions(+), 823 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/query_system.ftl b/compiler/rustc_error_messages/locales/en-US/query_system.ftl index 2d8c7a651225..7fdecf4f3818 100644 --- a/compiler/rustc_error_messages/locales/en-US/query_system.ftl +++ b/compiler/rustc_error_messages/locales/en-US/query_system.ftl @@ -19,3 +19,5 @@ query_system_cycle_recursive_ty_alias_help1 = consider using a struct, enum, or query_system_cycle_recursive_ty_alias_help2 = see for more information query_system_cycle_recursive_trait_alias = trait aliases cannot be recursive + +query_system_cycle_which_requires = ...which requires {$desc}... diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index 8b40e295bd8a..c1b82abc1e06 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -12,7 +12,7 @@ use quote::{format_ident, quote}; use std::collections::HashMap; use std::fmt; use std::str::FromStr; -use syn::{spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, NestedMeta, Path}; +use syn::{spanned::Spanned, Meta, MetaList, MetaNameValue, NestedMeta, Path}; use synstructure::{BindingInfo, Structure, VariantInfo}; /// Which kind of suggestion is being created? @@ -28,41 +28,8 @@ enum SubdiagnosticSuggestionKind { Verbose, } -impl FromStr for SubdiagnosticSuggestionKind { - type Err = (); - - fn from_str(s: &str) -> Result { - match s { - "" => Ok(SubdiagnosticSuggestionKind::Normal), - "_short" => Ok(SubdiagnosticSuggestionKind::Short), - "_hidden" => Ok(SubdiagnosticSuggestionKind::Hidden), - "_verbose" => Ok(SubdiagnosticSuggestionKind::Verbose), - _ => Err(()), - } - } -} - -impl SubdiagnosticSuggestionKind { - pub fn to_suggestion_style(&self) -> TokenStream { - match self { - SubdiagnosticSuggestionKind::Normal => { - quote! { rustc_errors::SuggestionStyle::ShowCode } - } - SubdiagnosticSuggestionKind::Short => { - quote! { rustc_errors::SuggestionStyle::HideCodeInline } - } - SubdiagnosticSuggestionKind::Hidden => { - quote! { rustc_errors::SuggestionStyle::HideCodeAlways } - } - SubdiagnosticSuggestionKind::Verbose => { - quote! { rustc_errors::SuggestionStyle::ShowAlways } - } - } - } -} - /// Which kind of subdiagnostic is being created from a variant? -#[derive(Clone)] +#[derive(Clone, Copy)] enum SubdiagnosticKind { /// `#[label(...)]` Label, @@ -73,9 +40,31 @@ enum SubdiagnosticKind { /// `#[warning(...)]` Warn, /// `#[suggestion{,_short,_hidden,_verbose}]` - Suggestion { suggestion_kind: SubdiagnosticSuggestionKind, code: TokenStream }, - /// `#[multipart_suggestion{,_short,_hidden,_verbose}]` - MultipartSuggestion { suggestion_kind: SubdiagnosticSuggestionKind }, + Suggestion(SubdiagnosticSuggestionKind), +} + +impl FromStr for SubdiagnosticKind { + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "label" => Ok(SubdiagnosticKind::Label), + "note" => Ok(SubdiagnosticKind::Note), + "help" => Ok(SubdiagnosticKind::Help), + "warning" => Ok(SubdiagnosticKind::Warn), + "suggestion" => Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Normal)), + "suggestion_short" => { + Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Short)) + } + "suggestion_hidden" => { + Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Hidden)) + } + "suggestion_verbose" => { + Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Verbose)) + } + _ => Err(()), + } + } } impl quote::IdentFragment for SubdiagnosticKind { @@ -85,9 +74,17 @@ impl quote::IdentFragment for SubdiagnosticKind { SubdiagnosticKind::Note => write!(f, "note"), SubdiagnosticKind::Help => write!(f, "help"), SubdiagnosticKind::Warn => write!(f, "warn"), - SubdiagnosticKind::Suggestion { .. } => write!(f, "suggestion_with_style"), - SubdiagnosticKind::MultipartSuggestion { .. } => { - write!(f, "multipart_suggestion_with_style") + SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Normal) => { + write!(f, "suggestion") + } + SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Short) => { + write!(f, "suggestion_short") + } + SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Hidden) => { + write!(f, "suggestion_hidden") + } + SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Verbose) => { + write!(f, "suggestion_verbose") } } } @@ -151,9 +148,11 @@ impl<'a> SessionSubdiagnosticDerive<'a> { variant, span, fields: fields_map, + kinds: Vec::new(), + slugs: Vec::new(), + code: None, span_field: None, applicability: None, - has_suggestion_parts: false, }; builder.into_tokens().unwrap_or_else(|v| v.to_compile_error()) }); @@ -194,15 +193,21 @@ struct SessionSubdiagnosticDeriveBuilder<'a> { /// derive builder. fields: HashMap, + /// Subdiagnostic kind of the type/variant. + kinds: Vec<(SubdiagnosticKind, proc_macro::Span)>, + + /// Slugs of the subdiagnostic - corresponds to the Fluent identifier for the message - from the + /// `#[kind(slug)]` attribute on the type or variant. + slugs: Vec<(Path, proc_macro::Span)>, + /// If a suggestion, the code to suggest as a replacement - from the `#[kind(code = "...")]` + /// attribute on the type or variant. + code: Option<(TokenStream, proc_macro::Span)>, + /// Identifier for the binding to the `#[primary_span]` field. span_field: Option<(proc_macro2::Ident, proc_macro::Span)>, /// If a suggestion, the identifier for the binding to the `#[applicability]` field or a /// `rustc_errors::Applicability::*` variant directly. applicability: Option<(TokenStream, proc_macro::Span)>, - - /// Set to true when a `#[suggestion_part]` field is encountered, used to generate an error - /// during finalization if still `false`. - has_suggestion_parts: bool, } impl<'a> HasFieldMap for SessionSubdiagnosticDeriveBuilder<'a> { @@ -212,133 +217,124 @@ impl<'a> HasFieldMap for SessionSubdiagnosticDeriveBuilder<'a> { } impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { - fn identify_kind( - &mut self, - ) -> Result, DiagnosticDeriveError> { - let mut kind_slug = None; - - for attr in self.variant.ast().attrs { + fn identify_kind(&mut self) -> Result<(), DiagnosticDeriveError> { + for (i, attr) in self.variant.ast().attrs.iter().enumerate() { let span = attr.span().unwrap(); let name = attr.path.segments.last().unwrap().ident.to_string(); let name = name.as_str(); let meta = attr.parse_meta()?; - let Meta::List(MetaList { ref nested, .. }) = meta else { - throw_invalid_attr!(attr, &meta); - }; - - let mut kind = match name { - "label" => SubdiagnosticKind::Label, - "note" => SubdiagnosticKind::Note, - "help" => SubdiagnosticKind::Help, - "warning" => SubdiagnosticKind::Warn, - _ => { - if let Some(suggestion_kind) = - name.strip_prefix("suggestion").and_then(|s| s.parse().ok()) - { - SubdiagnosticKind::Suggestion { suggestion_kind, code: TokenStream::new() } - } else if let Some(suggestion_kind) = - name.strip_prefix("multipart_suggestion").and_then(|s| s.parse().ok()) - { - SubdiagnosticKind::MultipartSuggestion { suggestion_kind } - } else { - throw_invalid_attr!(attr, &meta); + let kind = match meta { + Meta::List(MetaList { ref nested, .. }) => { + let mut nested_iter = nested.into_iter(); + if let Some(nested_attr) = nested_iter.next() { + match nested_attr { + NestedMeta::Meta(Meta::Path(path)) => { + self.slugs.push((path.clone(), span)); + } + NestedMeta::Meta(meta @ Meta::NameValue(_)) + if matches!( + meta.path().segments.last().unwrap().ident.to_string().as_str(), + "code" | "applicability" + ) => + { + // don't error for valid follow-up attributes + } + nested_attr => { + throw_invalid_nested_attr!(attr, &nested_attr, |diag| { + diag.help( + "first argument of the attribute should be the diagnostic \ + slug", + ) + }) + } + }; } - } - }; - let mut slug = None; - let mut code = None; + for nested_attr in nested_iter { + let meta = match nested_attr { + NestedMeta::Meta(ref meta) => meta, + _ => throw_invalid_nested_attr!(attr, &nested_attr), + }; - let mut nested_iter = nested.into_iter(); - if let Some(nested_attr) = nested_iter.next() { - match nested_attr { - NestedMeta::Meta(Meta::Path(path)) => { - slug.set_once((path.clone(), span)); - } - NestedMeta::Meta(meta @ Meta::NameValue(_)) - if matches!( - meta.path().segments.last().unwrap().ident.to_string().as_str(), - "code" | "applicability" - ) => - { - // Don't error for valid follow-up attributes. - } - nested_attr => { - throw_invalid_nested_attr!(attr, &nested_attr, |diag| { - diag.help( - "first argument of the attribute should be the diagnostic \ - slug", - ) - }) - } - }; - } + let span = meta.span().unwrap(); + let nested_name = meta.path().segments.last().unwrap().ident.to_string(); + let nested_name = nested_name.as_str(); - for nested_attr in nested_iter { - let meta = match nested_attr { - NestedMeta::Meta(ref meta) => meta, - _ => throw_invalid_nested_attr!(attr, &nested_attr), - }; - - let span = meta.span().unwrap(); - let nested_name = meta.path().segments.last().unwrap().ident.to_string(); - let nested_name = nested_name.as_str(); - - let value = match meta { - Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) => value, - Meta::Path(_) => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { - diag.help("a diagnostic slug must be the first argument to the attribute") - }), - _ => throw_invalid_nested_attr!(attr, &nested_attr), - }; - - match nested_name { - "code" => { - if matches!(kind, SubdiagnosticKind::Suggestion { .. }) { - let formatted_str = self.build_format(&value.value(), value.span()); - code.set_once((formatted_str, span)); - } else { - span_err( - span, - &format!( - "`code` is not a valid nested attribute of a `{}` attribute", - name - ), - ) - .emit(); + match meta { + Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => { + match nested_name { + "code" => { + let formatted_str = self.build_format(&s.value(), s.span()); + self.code.set_once((formatted_str, span)); + } + "applicability" => { + let value = match Applicability::from_str(&s.value()) { + Ok(v) => v, + Err(()) => { + span_err(span, "invalid applicability").emit(); + Applicability::Unspecified + } + }; + self.applicability.set_once((quote! { #value }, span)); + } + _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { + diag.help( + "only `code` and `applicability` are valid nested \ + attributes", + ) + }), + } + } + _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { + if matches!(meta, Meta::Path(_)) { + diag.help( + "a diagnostic slug must be the first argument to the \ + attribute", + ) + } else { + diag + } + }), } } - "applicability" => { - if matches!( - kind, - SubdiagnosticKind::Suggestion { .. } - | SubdiagnosticKind::MultipartSuggestion { .. } - ) { - let value = - Applicability::from_str(&value.value()).unwrap_or_else(|()| { - span_err(span, "invalid applicability").emit(); - Applicability::Unspecified - }); - self.applicability.set_once((quote! { #value }, span)); - } else { - span_err( - span, - &format!( - "`applicability` is not a valid nested attribute of a `{}` attribute", - name - ) - ).emit(); - } - } - _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { - diag.help("only `code` and `applicability` are valid nested attributes") - }), + + let Ok(kind) = SubdiagnosticKind::from_str(name) else { + throw_invalid_attr!(attr, &meta) + }; + + kind } + _ => throw_invalid_attr!(attr, &meta), + }; + + if matches!( + kind, + SubdiagnosticKind::Label | SubdiagnosticKind::Help | SubdiagnosticKind::Note + ) && self.code.is_some() + { + throw_span_err!( + span, + &format!("`code` is not a valid nested attribute of a `{}` attribute", name) + ); } - let Some((slug, _)) = slug else { + if matches!( + kind, + SubdiagnosticKind::Label | SubdiagnosticKind::Help | SubdiagnosticKind::Note + ) && self.applicability.is_some() + { + throw_span_err!( + span, + &format!( + "`applicability` is not a valid nested attribute of a `{}` attribute", + name + ) + ); + } + + if self.slugs.len() != i + 1 { throw_span_err!( span, &format!( @@ -346,338 +342,146 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { name ) ); - }; - - match kind { - SubdiagnosticKind::Suggestion { code: ref mut code_field, .. } => { - let Some((code, _)) = code else { - throw_span_err!(span, "suggestion without `code = \"...\"`"); - }; - *code_field = code; - } - SubdiagnosticKind::Label - | SubdiagnosticKind::Note - | SubdiagnosticKind::Help - | SubdiagnosticKind::Warn - | SubdiagnosticKind::MultipartSuggestion { .. } => {} } - kind_slug.set_once(((kind, slug), span)) + self.kinds.push((kind, span)); } - Ok(kind_slug.map(|(kind_slug, _)| kind_slug)) + Ok(()) } - /// Generates the code for a field with no attributes. - fn generate_field_set_arg(&mut self, binding: &BindingInfo<'_>) -> TokenStream { + fn generate_field_code( + &mut self, + binding: &BindingInfo<'_>, + have_suggestion: bool, + ) -> Result { let ast = binding.ast(); - assert_eq!(ast.attrs.len(), 0, "field with attribute used as diagnostic arg"); + + let inner_ty = FieldInnerTy::from_type(&ast.ty); + let info = FieldInfo { + binding: binding, + ty: inner_ty.inner_type().unwrap_or(&ast.ty), + span: &ast.span(), + }; + + for attr in &ast.attrs { + let name = attr.path.segments.last().unwrap().ident.to_string(); + let name = name.as_str(); + let span = attr.span().unwrap(); + + let meta = attr.parse_meta()?; + match meta { + Meta::Path(_) => match name { + "primary_span" => { + report_error_if_not_applied_to_span(attr, &info)?; + self.span_field.set_once((binding.binding.clone(), span)); + return Ok(quote! {}); + } + "applicability" if have_suggestion => { + report_error_if_not_applied_to_applicability(attr, &info)?; + let binding = binding.binding.clone(); + self.applicability.set_once((quote! { #binding }, span)); + return Ok(quote! {}); + } + "applicability" => { + span_err(span, "`#[applicability]` is only valid on suggestions").emit(); + return Ok(quote! {}); + } + "skip_arg" => { + return Ok(quote! {}); + } + _ => throw_invalid_attr!(attr, &meta, |diag| { + diag.help( + "only `primary_span`, `applicability` and `skip_arg` are valid field \ + attributes", + ) + }), + }, + _ => throw_invalid_attr!(attr, &meta), + } + } + + let ident = ast.ident.as_ref().unwrap(); let diag = &self.diag; - let ident = ast.ident.as_ref().unwrap(); - quote! { + let generated = quote! { #diag.set_arg( stringify!(#ident), #binding ); - } + }; + + Ok(inner_ty.with(binding, generated)) } - /// Generates the necessary code for all attributes on a field. - fn generate_field_attr_code( - &mut self, - binding: &BindingInfo<'_>, - kind: &SubdiagnosticKind, - ) -> TokenStream { - let ast = binding.ast(); - assert!(ast.attrs.len() > 0, "field without attributes generating attr code"); - - // Abstract over `Vec` and `Option` fields using `FieldInnerTy`, which will - // apply the generated code on each element in the `Vec` or `Option`. - let inner_ty = FieldInnerTy::from_type(&ast.ty); - ast.attrs - .iter() - .map(|attr| { - let info = FieldInfo { - binding, - ty: inner_ty.inner_type().unwrap_or(&ast.ty), - span: &ast.span(), - }; - - let generated = self - .generate_field_code_inner(kind, attr, info) - .unwrap_or_else(|v| v.to_compile_error()); - - inner_ty.with(binding, generated) - }) - .collect() - } - - fn generate_field_code_inner( - &mut self, - kind: &SubdiagnosticKind, - attr: &Attribute, - info: FieldInfo<'_>, - ) -> Result { - let meta = attr.parse_meta()?; - match meta { - Meta::Path(path) => self.generate_field_code_inner_path(kind, attr, info, path), - Meta::List(list @ MetaList { .. }) => { - self.generate_field_code_inner_list(kind, attr, info, list) - } - _ => throw_invalid_attr!(attr, &meta), - } - } - - /// Generates the code for a `[Meta::Path]`-like attribute on a field (e.g. `#[primary_span]`). - fn generate_field_code_inner_path( - &mut self, - kind: &SubdiagnosticKind, - attr: &Attribute, - info: FieldInfo<'_>, - path: Path, - ) -> Result { - let span = attr.span().unwrap(); - let ident = &path.segments.last().unwrap().ident; - let name = ident.to_string(); - let name = name.as_str(); - - match name { - "skip_arg" => Ok(quote! {}), - "primary_span" => { - if matches!(kind, SubdiagnosticKind::MultipartSuggestion { .. }) { - throw_invalid_attr!(attr, &Meta::Path(path), |diag| { - diag.help( - "multipart suggestions use one or more `#[suggestion_part]`s rather \ - than one `#[primary_span]`", - ) - }) - } - - report_error_if_not_applied_to_span(attr, &info)?; - - let binding = info.binding.binding.clone(); - self.span_field.set_once((binding, span)); - - Ok(quote! {}) - } - "suggestion_part" => { - self.has_suggestion_parts = true; - - match kind { - SubdiagnosticKind::MultipartSuggestion { .. } => { - span_err( - span, - "`#[suggestion_part(...)]` attribute without `code = \"...\"`", - ) - .emit(); - Ok(quote! {}) - } - SubdiagnosticKind::Label - | SubdiagnosticKind::Note - | SubdiagnosticKind::Help - | SubdiagnosticKind::Warn - | SubdiagnosticKind::Suggestion { .. } => { - throw_invalid_attr!(attr, &Meta::Path(path), |diag| { - diag.help( - "`#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead", - ) - }); - } - } - } - "applicability" => { - if let SubdiagnosticKind::Suggestion { .. } - | SubdiagnosticKind::MultipartSuggestion { .. } = kind - { - report_error_if_not_applied_to_applicability(attr, &info)?; - - let binding = info.binding.binding.clone(); - self.applicability.set_once((quote! { #binding }, span)); - } else { - span_err(span, "`#[applicability]` is only valid on suggestions").emit(); - } - - Ok(quote! {}) - } - _ => throw_invalid_attr!(attr, &Meta::Path(path), |diag| { - let span_attr = if let SubdiagnosticKind::MultipartSuggestion { .. } = kind { - "suggestion_part" - } else { - "primary_span" - }; - diag.help(format!( - "only `{span_attr}`, `applicability` and `skip_arg` are valid field attributes", - )) - }), - } - } - - /// Generates the code for a `[Meta::List]`-like attribute on a field (e.g. - /// `#[suggestion_part(code = "...")]`). - fn generate_field_code_inner_list( - &mut self, - kind: &SubdiagnosticKind, - attr: &Attribute, - info: FieldInfo<'_>, - list: MetaList, - ) -> Result { - let span = attr.span().unwrap(); - let ident = &list.path.segments.last().unwrap().ident; - let name = ident.to_string(); - let name = name.as_str(); - - match name { - "suggestion_part" => { - if !matches!(kind, SubdiagnosticKind::MultipartSuggestion { .. }) { - throw_invalid_attr!(attr, &Meta::List(list), |diag| { - diag.help( - "`#[suggestion_part(...)]` is only valid in multipart suggestions", - ) - }) - } - - self.has_suggestion_parts = true; - - report_error_if_not_applied_to_span(attr, &info)?; - - let mut code = None; - for nested_attr in list.nested.iter() { - let NestedMeta::Meta(ref meta) = nested_attr else { - throw_invalid_nested_attr!(attr, &nested_attr); - }; - - let span = meta.span().unwrap(); - let nested_name = meta.path().segments.last().unwrap().ident.to_string(); - let nested_name = nested_name.as_str(); - - let Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) = meta else { - throw_invalid_nested_attr!(attr, &nested_attr); - }; - - match nested_name { - "code" => { - let formatted_str = self.build_format(&value.value(), value.span()); - code.set_once((formatted_str, span)); - } - _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { - diag.help("`code` is the only valid nested attribute") - }), - } - } - - let Some((code, _)) = code else { - span_err(span, "`#[suggestion_part(...)]` attribute without `code = \"...\"`") - .emit(); - return Ok(quote! {}); - }; - let binding = info.binding; - - Ok(quote! { suggestions.push((#binding, #code)); }) - } - _ => throw_invalid_attr!(attr, &Meta::List(list), |diag| { - let span_attr = if let SubdiagnosticKind::MultipartSuggestion { .. } = kind { - "suggestion_part" - } else { - "primary_span" - }; - diag.help(format!( - "only `{span_attr}`, `applicability` and `skip_arg` are valid field attributes", - )) - }), - } - } - - pub fn into_tokens(&mut self) -> Result { - let Some((kind, slug)) = self.identify_kind()? else { + fn into_tokens(&mut self) -> Result { + self.identify_kind()?; + if self.kinds.is_empty() { throw_span_err!( self.variant.ast().ident.span().unwrap(), "subdiagnostic kind not specified" ); }; + let have_suggestion = + self.kinds.iter().any(|(k, _)| matches!(k, SubdiagnosticKind::Suggestion(_))); + let mut args = TokenStream::new(); + for binding in self.variant.bindings() { + let arg = self + .generate_field_code(binding, have_suggestion) + .unwrap_or_else(|v| v.to_compile_error()); + args.extend(arg); + } + let mut tokens = TokenStream::new(); + for ((kind, _), (slug, _)) in self.kinds.iter().zip(&self.slugs) { + let code = match self.code.as_ref() { + Some((code, _)) => Some(quote! { #code }), + None if have_suggestion => { + span_err(self.span, "suggestion without `code = \"...\"`").emit(); + Some(quote! { /* macro error */ "..." }) + } + None => None, + }; - let init = match &kind { - SubdiagnosticKind::Label - | SubdiagnosticKind::Note - | SubdiagnosticKind::Help - | SubdiagnosticKind::Warn - | SubdiagnosticKind::Suggestion { .. } => quote! {}, - SubdiagnosticKind::MultipartSuggestion { .. } => { - quote! { let mut suggestions = Vec::new(); } - } - }; + let span_field = self.span_field.as_ref().map(|(span, _)| span); + let applicability = match self.applicability.clone() { + Some((applicability, _)) => Some(applicability), + None if have_suggestion => { + span_err(self.span, "suggestion without `applicability`").emit(); + Some(quote! { rustc_errors::Applicability::Unspecified }) + } + None => None, + }; - let attr_args: TokenStream = self - .variant - .bindings() - .iter() - .filter(|binding| !binding.ast().attrs.is_empty()) - .map(|binding| self.generate_field_attr_code(binding, &kind)) - .collect(); - - let span_field = self.span_field.as_ref().map(|(span, _)| span); - let applicability = self.applicability.take().map_or_else( - || quote! { rustc_errors::Applicability::Unspecified }, - |(applicability, _)| applicability, - ); - - let diag = &self.diag; - let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind); - let message = quote! { rustc_errors::fluent::#slug }; - let call = match kind { - SubdiagnosticKind::Suggestion { suggestion_kind, code } => { + let diag = &self.diag; + let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind); + let message = quote! { rustc_errors::fluent::#slug }; + let call = if matches!(kind, SubdiagnosticKind::Suggestion(..)) { if let Some(span) = span_field { - let style = suggestion_kind.to_suggestion_style(); - - quote! { #diag.#name(#span, #message, #code, #applicability, #style); } + quote! { #diag.#name(#span, #message, #code, #applicability); } } else { span_err(self.span, "suggestion without `#[primary_span]` field").emit(); quote! { unreachable!(); } } - } - SubdiagnosticKind::MultipartSuggestion { suggestion_kind } => { - if !self.has_suggestion_parts { - span_err( - self.span, - "multipart suggestion without any `#[suggestion_part(...)]` fields", - ) - .emit(); - } - - let style = suggestion_kind.to_suggestion_style(); - - quote! { #diag.#name(#message, suggestions, #applicability, #style); } - } - SubdiagnosticKind::Label => { + } else if matches!(kind, SubdiagnosticKind::Label) { if let Some(span) = span_field { quote! { #diag.#name(#span, #message); } } else { span_err(self.span, "label without `#[primary_span]` field").emit(); quote! { unreachable!(); } } - } - _ => { + } else { if let Some(span) = span_field { quote! { #diag.#name(#span, #message); } } else { quote! { #diag.#name(#message); } } - } - }; + }; + tokens.extend(quote! { + #call + #args + }); + } - let plain_args: TokenStream = self - .variant - .bindings() - .iter() - .filter(|binding| binding.ast().attrs.is_empty()) - .map(|binding| self.generate_field_set_arg(binding)) - .collect(); - - Ok(quote! { - #init - #attr_args - #call - #plain_args - }) + Ok(tokens) } } diff --git a/compiler/rustc_query_system/src/error.rs b/compiler/rustc_query_system/src/error.rs index 515a022e9d9f..9b808afeef62 100644 --- a/compiler/rustc_query_system/src/error.rs +++ b/compiler/rustc_query_system/src/error.rs @@ -1,50 +1,59 @@ -use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed}; -use rustc_session::SessionDiagnostic; +use rustc_errors::AddSubdiagnostic; use rustc_span::Span; -pub struct Cycle { +pub struct CycleStack { pub span: Span, - pub stack_bottom: String, - pub upper_stack_info: Vec<(Span, String)>, - pub recursive_ty_alias: bool, - pub recursive_trait_alias: bool, - pub cycle_usage: Option<(Span, String)>, + pub desc: String, } -impl SessionDiagnostic<'_> for Cycle { - fn into_diagnostic( - self, - sess: &'_ rustc_session::parse::ParseSess, - ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = sess.struct_err(rustc_errors::fluent::query_system::cycle); - diag.set_span(self.span); - diag.code(rustc_errors::DiagnosticId::Error("E0391".to_string())); - let upper_stack_len = self.upper_stack_info.len(); - for (span, desc) in self.upper_stack_info.into_iter() { - // FIXME(#100717): use fluent translation - diag.span_note(span, &format!("...which requires {}...", desc)); - } - diag.set_arg("stack_bottom", self.stack_bottom); - if upper_stack_len == 0 { - diag.note(rustc_errors::fluent::query_system::cycle_stack_single); - } else { - diag.note(rustc_errors::fluent::query_system::cycle_stack_multiple); - } - if self.recursive_trait_alias { - diag.note(rustc_errors::fluent::query_system::cycle_recursive_trait_alias); - } else if self.recursive_ty_alias { - diag.note(rustc_errors::fluent::query_system::cycle_recursive_ty_alias); - diag.help(rustc_errors::fluent::query_system::cycle_recursive_ty_alias_help1); - diag.help(rustc_errors::fluent::query_system::cycle_recursive_ty_alias_help2); - } - if let Some((span, desc)) = self.cycle_usage { - diag.set_arg("usage", desc); - diag.span_note(span, rustc_errors::fluent::query_system::cycle_usage); - } - diag +impl AddSubdiagnostic for CycleStack { + fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { + diag.span_note(self.span, &format!("...which requires {}...", self.desc)); } } +#[derive(SessionSubdiagnostic)] +pub enum StackCount { + #[note(query_system::cycle_stack_single)] + Single, + #[note(query_system::cycle_stack_multiple)] + Multiple, +} + +#[derive(SessionSubdiagnostic)] +pub enum Alias { + #[note(query_system::cycle_recursive_ty_alias)] + #[help(query_system::cycle_recursive_ty_alias_help1)] + #[help(query_system::cycle_recursive_ty_alias_help2)] + Ty, + #[note(query_system::cycle_recursive_trait_alias)] + Trait, +} + +#[derive(SessionSubdiagnostic)] +#[note(query_system::cycle_usage)] +pub struct CycleUsage { + #[primary_span] + pub span: Span, + pub usage: String, +} + +#[derive(SessionDiagnostic)] +#[diag(query_system::cycle, code = "E0391")] +pub struct Cycle { + #[primary_span] + pub span: Span, + pub stack_bottom: String, + #[subdiagnostic] + pub cycle_stack: Vec, + #[subdiagnostic] + pub stack_count: StackCount, + #[subdiagnostic] + pub alias: Option, + #[subdiagnostic] + pub cycle_usage: Option, +} + #[derive(SessionDiagnostic)] #[diag(query_system::reentrant)] pub struct Reentrant; diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index da775893a2b0..7067bc5f09cf 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -5,7 +5,7 @@ #![feature(min_specialization)] #![feature(extern_types)] #![allow(rustc::potential_query_instability)] -#![deny(rustc::untranslatable_diagnostic)] +// #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 718ec14db362..af1741bad6c3 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -1,3 +1,4 @@ +use crate::error::CycleStack; use crate::query::plumbing::CycleError; use crate::query::{QueryContext, QueryStackFrame}; @@ -535,26 +536,42 @@ pub(crate) fn report_cycle<'a>( let span = stack[0].query.default_span(stack[1 % stack.len()].span); - let mut cycle_diag = crate::error::Cycle { - span, - upper_stack_info: Vec::with_capacity(stack.len() - 1), - stack_bottom: stack[0].query.description.to_owned(), - recursive_ty_alias: false, - recursive_trait_alias: false, - cycle_usage: usage.map(|(span, query)| (query.default_span(span), query.description)), - }; + let mut cycle_stack = Vec::new(); + + use crate::error::StackCount; + let stack_count = if stack.len() == 1 { StackCount::Single } else { StackCount::Multiple }; for i in 1..stack.len() { let query = &stack[i].query; let span = query.default_span(stack[(i + 1) % stack.len()].span); - cycle_diag.upper_stack_info.push((span, query.description.to_owned())); + cycle_stack.push(CycleStack { span, desc: query.description.to_owned() }); } - if stack.iter().all(|entry| entry.query.def_kind == Some(DefKind::TyAlias)) { - cycle_diag.recursive_ty_alias = true; - } else if stack.iter().all(|entry| entry.query.def_kind == Some(DefKind::TraitAlias)) { - cycle_diag.recursive_trait_alias = true; + let mut cycle_usage = None; + if let Some((span, query)) = usage { + cycle_usage = Some(crate::error::CycleUsage { + span: query.default_span(span), + usage: query.description, + }); } + // let cycle_usage = usage.map(|(span, query)| query.default_span(span)) + + let alias = if stack.iter().all(|entry| entry.query.def_kind == Some(DefKind::TyAlias)) { + Some(crate::error::Alias::Ty) + } else if stack.iter().all(|entry| entry.query.def_kind == Some(DefKind::TraitAlias)) { + Some(crate::error::Alias::Trait) + } else { + None + }; + + let cycle_diag = crate::error::Cycle { + span, + cycle_stack, + stack_bottom: stack[0].query.description.to_owned(), + alias, + cycle_usage: cycle_usage, + stack_count, + }; cycle_diag.into_diagnostic(&sess.parse_sess) } diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs index 89eaec78c6f1..f0843c60543d 100644 --- a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs +++ b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs @@ -167,8 +167,8 @@ enum P { #[derive(SessionSubdiagnostic)] enum Q { #[bar] - //~^ ERROR `#[bar]` is not a valid attribute - //~^^ ERROR cannot find attribute `bar` in this scope +//~^ ERROR `#[bar]` is not a valid attribute +//~^^ ERROR cannot find attribute `bar` in this scope A { #[primary_span] span: Span, @@ -179,8 +179,8 @@ enum Q { #[derive(SessionSubdiagnostic)] enum R { #[bar = "..."] - //~^ ERROR `#[bar = ...]` is not a valid attribute - //~^^ ERROR cannot find attribute `bar` in this scope +//~^ ERROR `#[bar = ...]` is not a valid attribute +//~^^ ERROR cannot find attribute `bar` in this scope A { #[primary_span] span: Span, @@ -191,8 +191,8 @@ enum R { #[derive(SessionSubdiagnostic)] enum S { #[bar = 4] - //~^ ERROR `#[bar = ...]` is not a valid attribute - //~^^ ERROR cannot find attribute `bar` in this scope +//~^ ERROR `#[bar = ...]` is not a valid attribute +//~^^ ERROR cannot find attribute `bar` in this scope A { #[primary_span] span: Span, @@ -203,8 +203,8 @@ enum S { #[derive(SessionSubdiagnostic)] enum T { #[bar("...")] - //~^ ERROR `#[bar(...)]` is not a valid attribute - //~^^ ERROR cannot find attribute `bar` in this scope +//~^ ERROR `#[bar("...")]` is not a valid attribute +//~^^ ERROR cannot find attribute `bar` in this scope A { #[primary_span] span: Span, @@ -215,7 +215,7 @@ enum T { #[derive(SessionSubdiagnostic)] enum U { #[label(code = "...")] - //~^ ERROR diagnostic slug must be first argument of a `#[label(...)]` attribute +//~^ ERROR diagnostic slug must be first argument of a `#[label(...)]` attribute A { #[primary_span] span: Span, @@ -232,7 +232,7 @@ enum V { var: String, }, B { - //~^ ERROR subdiagnostic kind not specified +//~^ ERROR subdiagnostic kind not specified #[primary_span] span: Span, var: String, @@ -307,16 +307,6 @@ union AC { b: u64 } -#[derive(SessionSubdiagnostic)] -#[label(parser::add_paren)] -//~^ NOTE previously specified here -#[label(parser::add_paren)] -//~^ ERROR specified multiple times -struct AD { - #[primary_span] - span: Span, -} - #[derive(SessionSubdiagnostic)] #[label(parser::add_paren, parser::add_paren)] //~^ ERROR `#[label(parser::add_paren)]` is not a valid attribute @@ -329,16 +319,16 @@ struct AE { #[label(parser::add_paren)] struct AF { #[primary_span] - //~^ NOTE previously specified here +//~^ NOTE previously specified here span_a: Span, #[primary_span] - //~^ ERROR specified multiple times +//~^ ERROR specified multiple times span_b: Span, } #[derive(SessionSubdiagnostic)] struct AG { - //~^ ERROR subdiagnostic kind not specified +//~^ ERROR subdiagnostic kind not specified #[primary_span] span: Span, } @@ -390,25 +380,27 @@ struct AK { #[primary_span] span: Span, #[applicability] - //~^ NOTE previously specified here +//~^ NOTE previously specified here applicability_a: Applicability, #[applicability] - //~^ ERROR specified multiple times +//~^ ERROR specified multiple times applicability_b: Applicability, } #[derive(SessionSubdiagnostic)] #[suggestion(parser::add_paren, code = "...")] +//~^ ERROR suggestion without `applicability` struct AL { #[primary_span] span: Span, #[applicability] - //~^ ERROR the `#[applicability]` attribute can only be applied to fields of type `Applicability` +//~^ ERROR the `#[applicability]` attribute can only be applied to fields of type `Applicability` applicability: Span, } #[derive(SessionSubdiagnostic)] #[suggestion(parser::add_paren, code = "...")] +//~^ ERROR suggestion without `applicability` struct AM { #[primary_span] span: Span, @@ -444,7 +436,8 @@ struct AQ; #[derive(SessionSubdiagnostic)] #[suggestion(parser::add_paren, code = "...")] -//~^ ERROR suggestion without `#[primary_span]` field +//~^ ERROR suggestion without `applicability` +//~^^ ERROR suggestion without `#[primary_span]` field struct AR { var: String, } @@ -514,120 +507,3 @@ struct AZ { #[primary_span] span: Span, } - -#[derive(SessionSubdiagnostic)] -#[suggestion(parser::add_paren, code = "...")] -//~^ ERROR suggestion without `#[primary_span]` field -struct BA { - #[suggestion_part] - //~^ ERROR `#[suggestion_part]` is not a valid attribute - span: Span, - #[suggestion_part(code = "...")] - //~^ ERROR `#[suggestion_part(...)]` is not a valid attribute - span2: Span, - #[applicability] - applicability: Applicability, - var: String, -} - -#[derive(SessionSubdiagnostic)] -#[multipart_suggestion(parser::add_paren, code = "...", applicability = "machine-applicable")] -//~^ ERROR multipart suggestion without any `#[suggestion_part(...)]` fields -//~| ERROR `code` is not a valid nested attribute of a `multipart_suggestion` attribute -struct BBa { - var: String, -} - -#[derive(SessionSubdiagnostic)] -#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")] -struct BBb { - #[suggestion_part] - //~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."` - span1: Span, -} - -#[derive(SessionSubdiagnostic)] -#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")] -struct BBc { - #[suggestion_part()] - //~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."` - span1: Span, -} - -#[derive(SessionSubdiagnostic)] -#[multipart_suggestion(parser::add_paren)] -//~^ ERROR multipart suggestion without any `#[suggestion_part(...)]` fields -struct BC { - #[primary_span] - //~^ ERROR `#[primary_span]` is not a valid attribute - span: Span, -} - -#[derive(SessionSubdiagnostic)] -#[multipart_suggestion(parser::add_paren)] -struct BD { - #[suggestion_part] - //~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."` - span1: Span, - #[suggestion_part()] - //~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."` - span2: Span, - #[suggestion_part(foo = "bar")] - //~^ ERROR `#[suggestion_part(foo = ...)]` is not a valid attribute - span4: Span, - #[suggestion_part(code = "...")] - //~^ ERROR the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` - s1: String, - #[suggestion_part()] - //~^ ERROR the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` - s2: String, -} - -#[derive(SessionSubdiagnostic)] -#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")] -struct BE { - #[suggestion_part(code = "...", code = ",,,")] - //~^ ERROR specified multiple times - //~| NOTE previously specified here - span: Span, -} - -#[derive(SessionSubdiagnostic)] -#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")] -struct BF { - #[suggestion_part(code = "(")] - first: Span, - #[suggestion_part(code = ")")] - second: Span, -} - -#[derive(SessionSubdiagnostic)] -#[multipart_suggestion(parser::add_paren)] -struct BG { - #[applicability] - appl: Applicability, - #[suggestion_part(code = "(")] - first: Span, - #[suggestion_part(code = ")")] - second: Span, -} - -#[derive(SessionSubdiagnostic)] -#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")] -//~^ NOTE previously specified here -struct BH { - #[applicability] - //~^ ERROR specified multiple times - appl: Applicability, - #[suggestion_part(code = "(")] - first: Span, - #[suggestion_part(code = ")")] - second: Span, -} - -#[derive(SessionSubdiagnostic)] -#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")] -struct BI { - #[suggestion_part(code = "")] - spans: Vec, -} diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr index 75a34f44bbe7..6bd9144dbf6f 100644 --- a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr +++ b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr @@ -65,16 +65,16 @@ LL | #[label()] | ^^^^^^^^^^ error: `code` is not a valid nested attribute of a `label` attribute - --> $DIR/subdiagnostic-derive.rs:137:28 + --> $DIR/subdiagnostic-derive.rs:137:1 | LL | #[label(parser::add_paren, code = "...")] - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `applicability` is not a valid nested attribute of a `label` attribute - --> $DIR/subdiagnostic-derive.rs:146:28 + --> $DIR/subdiagnostic-derive.rs:146:1 | LL | #[label(parser::add_paren, applicability = "machine-applicable")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unsupported type attribute for subdiagnostic enum --> $DIR/subdiagnostic-derive.rs:155:1 @@ -100,11 +100,13 @@ error: `#[bar = ...]` is not a valid attribute LL | #[bar = 4] | ^^^^^^^^^^ -error: `#[bar(...)]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:205:5 +error: `#[bar("...")]` is not a valid attribute + --> $DIR/subdiagnostic-derive.rs:205:11 | LL | #[bar("...")] - | ^^^^^^^^^^^^^ + | ^^^^^ + | + = help: first argument of the attribute should be the diagnostic slug error: diagnostic slug must be first argument of a `#[label(...)]` attribute --> $DIR/subdiagnostic-derive.rs:217:5 @@ -161,8 +163,6 @@ error: `#[bar(...)]` is not a valid attribute | LL | #[bar("...")] | ^^^^^^^^^^^^^ - | - = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes error: unexpected unsupported untagged union --> $DIR/subdiagnostic-derive.rs:304:1 @@ -174,20 +174,8 @@ LL | | b: u64 LL | | } | |_^ -error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:313:1 - | -LL | #[label(parser::add_paren)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: previously specified here - --> $DIR/subdiagnostic-derive.rs:311:1 - | -LL | #[label(parser::add_paren)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: `#[label(parser::add_paren)]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:321:28 + --> $DIR/subdiagnostic-derive.rs:311:28 | LL | #[label(parser::add_paren, parser::add_paren)] | ^^^^^^^^^^^^^^^^^ @@ -195,226 +183,134 @@ LL | #[label(parser::add_paren, parser::add_paren)] = help: a diagnostic slug must be the first argument to the attribute error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:334:5 + --> $DIR/subdiagnostic-derive.rs:324:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:331:5 + --> $DIR/subdiagnostic-derive.rs:321:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ error: subdiagnostic kind not specified - --> $DIR/subdiagnostic-derive.rs:340:8 + --> $DIR/subdiagnostic-derive.rs:330:8 | LL | struct AG { | ^^ error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:377:47 + --> $DIR/subdiagnostic-derive.rs:367:47 | LL | #[suggestion(parser::add_paren, code = "...", code = "...")] | ^^^^^^^^^^^^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:377:33 + --> $DIR/subdiagnostic-derive.rs:367:33 | LL | #[suggestion(parser::add_paren, code = "...", code = "...")] | ^^^^^^^^^^^^ error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:395:5 + --> $DIR/subdiagnostic-derive.rs:385:5 | LL | #[applicability] | ^^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:392:5 + --> $DIR/subdiagnostic-derive.rs:382:5 | LL | #[applicability] | ^^^^^^^^^^^^^^^^ error: the `#[applicability]` attribute can only be applied to fields of type `Applicability` - --> $DIR/subdiagnostic-derive.rs:405:5 + --> $DIR/subdiagnostic-derive.rs:396:5 | LL | #[applicability] | ^^^^^^^^^^^^^^^^ -error: suggestion without `code = "..."` - --> $DIR/subdiagnostic-derive.rs:418:1 +error: suggestion without `applicability` + --> $DIR/subdiagnostic-derive.rs:391:1 | -LL | #[suggestion(parser::add_paren)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | / #[suggestion(parser::add_paren, code = "...")] +LL | | +LL | | struct AL { +LL | | #[primary_span] +... | +LL | | applicability: Span, +LL | | } + | |_^ + +error: suggestion without `applicability` + --> $DIR/subdiagnostic-derive.rs:402:1 + | +LL | / #[suggestion(parser::add_paren, code = "...")] +LL | | +LL | | struct AM { +LL | | #[primary_span] +LL | | span: Span, +LL | | } + | |_^ + +error: suggestion without `code = "..."` + --> $DIR/subdiagnostic-derive.rs:410:1 + | +LL | / #[suggestion(parser::add_paren)] +LL | | +LL | | struct AN { +LL | | #[primary_span] +... | +LL | | applicability: Applicability, +LL | | } + | |_^ error: invalid applicability - --> $DIR/subdiagnostic-derive.rs:428:46 + --> $DIR/subdiagnostic-derive.rs:420:46 | LL | #[suggestion(parser::add_paren, code ="...", applicability = "foo")] | ^^^^^^^^^^^^^^^^^^^^^ -error: suggestion without `#[primary_span]` field - --> $DIR/subdiagnostic-derive.rs:446:1 +error: suggestion without `applicability` + --> $DIR/subdiagnostic-derive.rs:438:1 | LL | / #[suggestion(parser::add_paren, code = "...")] LL | | +LL | | +LL | | struct AR { +LL | | var: String, +LL | | } + | |_^ + +error: suggestion without `#[primary_span]` field + --> $DIR/subdiagnostic-derive.rs:438:1 + | +LL | / #[suggestion(parser::add_paren, code = "...")] +LL | | +LL | | LL | | struct AR { LL | | var: String, LL | | } | |_^ error: unsupported type attribute for subdiagnostic enum - --> $DIR/subdiagnostic-derive.rs:460:1 + --> $DIR/subdiagnostic-derive.rs:453:1 | LL | #[label] | ^^^^^^^^ error: `var` doesn't refer to a field on this type - --> $DIR/subdiagnostic-derive.rs:480:39 + --> $DIR/subdiagnostic-derive.rs:473:39 | LL | #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")] | ^^^^^^^ error: `var` doesn't refer to a field on this type - --> $DIR/subdiagnostic-derive.rs:499:43 + --> $DIR/subdiagnostic-derive.rs:492:43 | LL | #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")] | ^^^^^^^ -error: `#[suggestion_part]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:522:5 - | -LL | #[suggestion_part] - | ^^^^^^^^^^^^^^^^^^ - | - = help: `#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead - -error: `#[suggestion_part(...)]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:525:5 - | -LL | #[suggestion_part(code = "...")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: `#[suggestion_part(...)]` is only valid in multipart suggestions - -error: suggestion without `#[primary_span]` field - --> $DIR/subdiagnostic-derive.rs:519:1 - | -LL | / #[suggestion(parser::add_paren, code = "...")] -LL | | -LL | | struct BA { -LL | | #[suggestion_part] -... | -LL | | var: String, -LL | | } - | |_^ - -error: `code` is not a valid nested attribute of a `multipart_suggestion` attribute - --> $DIR/subdiagnostic-derive.rs:534:43 - | -LL | #[multipart_suggestion(parser::add_paren, code = "...", applicability = "machine-applicable")] - | ^^^^^^^^^^^^ - -error: multipart suggestion without any `#[suggestion_part(...)]` fields - --> $DIR/subdiagnostic-derive.rs:534:1 - | -LL | / #[multipart_suggestion(parser::add_paren, code = "...", applicability = "machine-applicable")] -LL | | -LL | | -LL | | struct BBa { -LL | | var: String, -LL | | } - | |_^ - -error: `#[suggestion_part(...)]` attribute without `code = "..."` - --> $DIR/subdiagnostic-derive.rs:544:5 - | -LL | #[suggestion_part] - | ^^^^^^^^^^^^^^^^^^ - -error: `#[suggestion_part(...)]` attribute without `code = "..."` - --> $DIR/subdiagnostic-derive.rs:552:5 - | -LL | #[suggestion_part()] - | ^^^^^^^^^^^^^^^^^^^^ - -error: `#[primary_span]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:561:5 - | -LL | #[primary_span] - | ^^^^^^^^^^^^^^^ - | - = help: multipart suggestions use one or more `#[suggestion_part]`s rather than one `#[primary_span]` - -error: multipart suggestion without any `#[suggestion_part(...)]` fields - --> $DIR/subdiagnostic-derive.rs:558:1 - | -LL | / #[multipart_suggestion(parser::add_paren)] -LL | | -LL | | struct BC { -LL | | #[primary_span] -LL | | -LL | | span: Span, -LL | | } - | |_^ - -error: `#[suggestion_part(...)]` attribute without `code = "..."` - --> $DIR/subdiagnostic-derive.rs:569:5 - | -LL | #[suggestion_part] - | ^^^^^^^^^^^^^^^^^^ - -error: `#[suggestion_part(...)]` attribute without `code = "..."` - --> $DIR/subdiagnostic-derive.rs:572:5 - | -LL | #[suggestion_part()] - | ^^^^^^^^^^^^^^^^^^^^ - -error: `#[suggestion_part(foo = ...)]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:575:23 - | -LL | #[suggestion_part(foo = "bar")] - | ^^^^^^^^^^^ - | - = help: `code` is the only valid nested attribute - -error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` - --> $DIR/subdiagnostic-derive.rs:578:5 - | -LL | #[suggestion_part(code = "...")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` - --> $DIR/subdiagnostic-derive.rs:581:5 - | -LL | #[suggestion_part()] - | ^^^^^^^^^^^^^^^^^^^^ - -error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:589:37 - | -LL | #[suggestion_part(code = "...", code = ",,,")] - | ^^^^^^^^^^^^ - | -note: previously specified here - --> $DIR/subdiagnostic-derive.rs:589:23 - | -LL | #[suggestion_part(code = "...", code = ",,,")] - | ^^^^^^^^^^^^ - -error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:619:5 - | -LL | #[applicability] - | ^^^^^^^^^^^^^^^^ - | -note: previously specified here - --> $DIR/subdiagnostic-derive.rs:616:43 - | -LL | #[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: cannot find attribute `foo` in this scope --> $DIR/subdiagnostic-derive.rs:63:3 | @@ -475,6 +371,6 @@ error[E0425]: cannot find value `slug` in module `rustc_errors::fluent` LL | #[label(slug)] | ^^^^ not found in `rustc_errors::fluent` -error: aborting due to 64 previous errors +error: aborting due to 50 previous errors For more information about this error, try `rustc --explain E0425`. From 166aef90fb7936892af5f0f88335e732d207c731 Mon Sep 17 00:00:00 2001 From: Li Yuanheng <520dhh@gmail.com> Date: Thu, 25 Aug 2022 23:32:28 +0800 Subject: [PATCH 3981/5092] delete leftover comment --- compiler/rustc_query_system/src/query/job.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index af1741bad6c3..ddb5cd063440 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -554,7 +554,6 @@ pub(crate) fn report_cycle<'a>( usage: query.description, }); } - // let cycle_usage = usage.map(|(span, query)| query.default_span(span)) let alias = if stack.iter().all(|entry| entry.query.def_kind == Some(DefKind::TyAlias)) { Some(crate::error::Alias::Ty) From 7ce59ebf496590c8b2ba3693c13e981d369add4b Mon Sep 17 00:00:00 2001 From: Li Yuanheng <520dhh@gmail.com> Date: Sat, 27 Aug 2022 11:55:38 +0800 Subject: [PATCH 3982/5092] SessionDiagnostic for QueryOverflow error --- compiler/rustc_error_messages/locales/en-US/query_system.ftl | 2 ++ compiler/rustc_error_messages/src/lib.rs | 2 +- compiler/rustc_query_system/src/error.rs | 4 ++++ compiler/rustc_query_system/src/query/mod.rs | 2 +- 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/query_system.ftl b/compiler/rustc_error_messages/locales/en-US/query_system.ftl index 7fdecf4f3818..167704e46c07 100644 --- a/compiler/rustc_error_messages/locales/en-US/query_system.ftl +++ b/compiler/rustc_error_messages/locales/en-US/query_system.ftl @@ -21,3 +21,5 @@ query_system_cycle_recursive_ty_alias_help2 = see "../locales/en-US/passes.ftl", plugin_impl => "../locales/en-US/plugin_impl.ftl", privacy => "../locales/en-US/privacy.ftl", + query_system => "../locales/en-US/query_system.ftl", save_analysis => "../locales/en-US/save_analysis.ftl", ty_utils => "../locales/en-US/ty_utils.ftl", typeck => "../locales/en-US/typeck.ftl", mir_dataflow => "../locales/en-US/mir_dataflow.ftl", - query_system => "../locales/en-US/query_system.ftl", } pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES}; diff --git a/compiler/rustc_query_system/src/error.rs b/compiler/rustc_query_system/src/error.rs index 9b808afeef62..5f992ec9e21e 100644 --- a/compiler/rustc_query_system/src/error.rs +++ b/compiler/rustc_query_system/src/error.rs @@ -67,3 +67,7 @@ pub struct IncrementCompilation { pub run_cmd: String, pub dep_node: String, } + +#[derive(SessionDiagnostic)] +#[diag(query_system::query_overflow)] +pub struct QueryOverflow; diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index a1f2b081d434..c6197b9fedb2 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -125,6 +125,6 @@ pub trait QueryContext: HasDepContext { ) -> R; fn depth_limit_error(&self) { - self.dep_context().sess().fatal("queries overflow the depth limit!"); + self.dep_context().sess().emit_fatal(crate::error::QueryOverflow); } } From 14dd33b8c7b380459bd032d1bb4f907efca7dac7 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Tue, 30 Aug 2022 06:15:34 -0700 Subject: [PATCH 3983/5092] Avoid needless buffer zeroing in `std::sys::windows::fs` --- library/std/src/sys/windows/fs.rs | 38 +++++++++++++++++++------------ 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index 0aa7c50ded1c..98c8834d3840 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -3,7 +3,7 @@ use crate::os::windows::prelude::*; use crate::ffi::OsString; use crate::fmt; use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom}; -use crate::mem; +use crate::mem::{self, MaybeUninit}; use crate::os::windows::io::{AsHandle, BorrowedHandle}; use crate::path::{Path, PathBuf}; use crate::ptr; @@ -326,7 +326,8 @@ impl File { cvt(c::GetFileInformationByHandle(self.handle.as_raw_handle(), &mut info))?; let mut reparse_tag = 0; if info.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { - let mut b = Align8([0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]); + let mut b = + Align8([MaybeUninit::::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]); if let Ok((_, buf)) = self.reparse_point(&mut b) { reparse_tag = (*buf).ReparseTag; } @@ -389,7 +390,8 @@ impl File { attr.file_size = info.AllocationSize as u64; attr.number_of_links = Some(info.NumberOfLinks); if attr.file_type().is_reparse_point() { - let mut b = Align8([0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]); + let mut b = + Align8([MaybeUninit::::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]); if let Ok((_, buf)) = self.reparse_point(&mut b) { attr.reparse_tag = (*buf).ReparseTag; } @@ -463,7 +465,7 @@ impl File { // avoid narrowing provenance to the actual `REPARSE_DATA_BUFFER`. fn reparse_point( &self, - space: &mut Align8<[u8]>, + space: &mut Align8<[MaybeUninit]>, ) -> io::Result<(c::DWORD, *const c::REPARSE_DATA_BUFFER)> { unsafe { let mut bytes = 0; @@ -488,7 +490,7 @@ impl File { } fn readlink(&self) -> io::Result { - let mut space = Align8([0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]); + let mut space = Align8([MaybeUninit::::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]); let (_bytes, buf) = self.reparse_point(&mut space)?; unsafe { let (path_buffer, subst_off, subst_len, relative) = match (*buf).ReparseTag { @@ -658,12 +660,16 @@ impl File { /// A buffer for holding directory entries. struct DirBuff { - buffer: Box>, + buffer: Box; Self::BUFFER_SIZE]>>, } impl DirBuff { const BUFFER_SIZE: usize = 1024; fn new() -> Self { - Self { buffer: Box::new(Align8([0u8; Self::BUFFER_SIZE])) } + Self { + // Safety: `Align8<[MaybeUninit; N]>` does not need + // initialization. + buffer: unsafe { Box::new_uninit().assume_init() }, + } } fn capacity(&self) -> usize { self.buffer.0.len() @@ -676,8 +682,8 @@ impl DirBuff { DirBuffIter::new(self) } } -impl AsRef<[u8]> for DirBuff { - fn as_ref(&self) -> &[u8] { +impl AsRef<[MaybeUninit]> for DirBuff { + fn as_ref(&self) -> &[MaybeUninit] { &self.buffer.0 } } @@ -686,7 +692,7 @@ impl AsRef<[u8]> for DirBuff { /// /// Currently only returns file names (UTF-16 encoded). struct DirBuffIter<'a> { - buffer: Option<&'a [u8]>, + buffer: Option<&'a [MaybeUninit]>, cursor: usize, } impl<'a> DirBuffIter<'a> { @@ -701,9 +707,13 @@ impl<'a> Iterator for DirBuffIter<'a> { let buffer = &self.buffer?[self.cursor..]; // Get the name and next entry from the buffer. - // SAFETY: The buffer contains a `FILE_ID_BOTH_DIR_INFO` struct but the - // last field (the file name) is unsized. So an offset has to be - // used to get the file name slice. + // SAFETY: + // - The buffer contains a `FILE_ID_BOTH_DIR_INFO` struct but the last + // field (the file name) is unsized. So an offset has to be used to + // get the file name slice. + // - The OS has guaranteed initialization of the fields of + // `FILE_ID_BOTH_DIR_INFO` and the trailing filename (for at least + // `FileNameLength` bytes) let (name, is_directory, next_entry) = unsafe { let info = buffer.as_ptr().cast::(); // Guaranteed to be aligned in documentation for @@ -1349,7 +1359,7 @@ fn symlink_junction_inner(original: &Path, junction: &Path) -> io::Result<()> { let h = f.as_inner().as_raw_handle(); unsafe { - let mut data = Align8([0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]); + let mut data = Align8([MaybeUninit::::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]); let data_ptr = data.0.as_mut_ptr(); let db = data_ptr.cast::(); let buf = ptr::addr_of_mut!((*db).ReparseTarget).cast::(); From 0303a31c8aca33653f079b1df6adc8c83447a74d Mon Sep 17 00:00:00 2001 From: Jethro Beekman Date: Mon, 29 Aug 2022 11:59:54 +0200 Subject: [PATCH 3984/5092] Document x86_64-fortanix-unknown-sgx platform --- src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/platform-support.md | 2 +- .../x86_64-fortanix-unknown-sgx.md | 72 +++++++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 src/doc/rustc/src/platform-support/x86_64-fortanix-unknown-sgx.md diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 4e6bc41daa71..0941f9013eed 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -32,6 +32,7 @@ - [*-unknown-openbsd](platform-support/openbsd.md) - [\*-unknown-uefi](platform-support/unknown-uefi.md) - [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md) + - [x86_64-fortanix-unknown-sgx](platform-support/x86_64-fortanix-unknown-sgx.md) - [x86_64-unknown-none](platform-support/x86_64-unknown-none.md) - [Targets](targets/index.md) - [Built-in Targets](targets/built-in.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index f0f57f933867..dd856e5d78a3 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -174,7 +174,7 @@ target | std | notes `wasm32-unknown-unknown` | ✓ | WebAssembly `wasm32-wasi` | ✓ | WebAssembly with WASI `x86_64-apple-ios` | ✓ | 64-bit x86 iOS -`x86_64-fortanix-unknown-sgx` | ✓ | [Fortanix ABI] for 64-bit Intel SGX +[`x86_64-fortanix-unknown-sgx`](platform-support/x86_64-fortanix-unknown-sgx.md) | ✓ | [Fortanix ABI] for 64-bit Intel SGX `x86_64-fuchsia` | ✓ | 64-bit Fuchsia `x86_64-linux-android` | ✓ | 64-bit x86 Android `x86_64-pc-solaris` | ✓ | 64-bit Solaris 10/11, illumos diff --git a/src/doc/rustc/src/platform-support/x86_64-fortanix-unknown-sgx.md b/src/doc/rustc/src/platform-support/x86_64-fortanix-unknown-sgx.md new file mode 100644 index 000000000000..97b5827c1443 --- /dev/null +++ b/src/doc/rustc/src/platform-support/x86_64-fortanix-unknown-sgx.md @@ -0,0 +1,72 @@ +# `x86_64-fortanix-unknown-sgx` + +**Tier: 2** + +Secure enclaves using [Intel Software Guard Extensions +(SGX)](https://www.intel.com/content/www/us/en/developer/tools/software-guard-extensions/overview.html) +based on the ABI defined by Fortanix for the [Enclave Development Platform +(EDP)](https://edp.fortanix.com/). + +## Target maintainers + +The [EDP team](mailto:edp.maintainers@fortanix.com) at Fortanix. + +- Jethro Beekman [@jethrogb](https://github.com/jethrogb) +- Raoul Strackx [@raoulstrackx](https://github.com/raoulstrackx) +- Mohsen Zohrevandi [@mzohreva](https://github.com/mzohreva) + +## Requirements + +The target supports `std` with a default allocator. Only cross compilation is +supported. + +Binaries support all CPUs that include Intel SGX. Only 64-bit mode is supported. + +Not all `std` features are supported, see [Using Rust's +std](https://edp.fortanix.com/docs/concepts/rust-std/) for details. + +The `extern "C"` calling convention is the System V AMD64 ABI. + +The supported ABI is the +[fortanix-sgx-abi](https://edp.fortanix.com/docs/api/fortanix_sgx_abi/index.html). + +The compiler output is ELF, but the native format for the platform is the SGX +stream (SGXS) format. A converter like +[ftxsgx-elf2sgxs](https://crates.io/crates/fortanix-sgx-tools) is needed. + +Programs in SGXS format adhering to the Fortanix SGX ABI can be run with any +compatible runner, such as +[ftxsgx-runner](https://crates.io/crates/fortanix-sgx-tools). + +See the [EDP installation +guide](https://edp.fortanix.com/docs/installation/guide/) for recommendations +on how to setup a development and runtime environment. + +## Building the target + +As a tier 2 target, the target is built by the Rust project. + +You can configure rustbuild like so: + +```toml +[build] +build-stage = 1 +target = ["x86_64-fortanix-unknown-sgx"] +``` + +## Building Rust programs + +Standard build flows using `cargo` or `rustc` should work. + +## Testing + +The Rust test suite as well as custom unit and integration tests will run on +hardware that has Intel SGX enabled if a cargo runner is configured correctly, +see the requirements section. + +## Cross-compilation toolchains and C code + +C code is not generally supported, as there is no libc. C code compiled for +x86-64 in freestanding mode using the System V AMD64 ABI may work. The +[rs-libc](https://crates.io/crates/rs-libc) crate contains a subset of libc +that's known to work with this target. From 11fc7852fe7304b84a3bb642a0ab2d60611df1e0 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 31 Aug 2022 12:06:22 +0100 Subject: [PATCH 3985/5092] lint: avoid linting diag functions with diag lints Functions annotated with `#[rustc_lint_diagnostics]` are used by the diagnostic migration lints to know when to lint, but functions that are annotated with this attribute shouldn't themselves be linted. Signed-off-by: David Wood --- compiler/rustc_lint/src/internal.rs | 12 +++++++++--- src/test/ui-fulldeps/internal-lints/diagnostics.rs | 8 ++++++++ .../ui-fulldeps/internal-lints/diagnostics.stderr | 14 +++++++------- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index c26d7824758e..6d451f3090ac 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -393,8 +393,14 @@ impl LateLintPass<'_> for Diagnostics { return; } + let mut found_parent_with_attr = false; let mut found_impl = false; - for (_, parent) in cx.tcx.hir().parent_iter(expr.hir_id) { + for (hir_id, parent) in cx.tcx.hir().parent_iter(expr.hir_id) { + if let Some(owner_did) = hir_id.as_owner() { + found_parent_with_attr = found_parent_with_attr + || cx.tcx.has_attr(owner_did.to_def_id(), sym::rustc_lint_diagnostics); + } + debug!(?parent); if let Node::Item(Item { kind: ItemKind::Impl(impl_), .. }) = parent && let Impl { of_trait: Some(of_trait), .. } = impl_ && @@ -407,7 +413,7 @@ impl LateLintPass<'_> for Diagnostics { } } debug!(?found_impl); - if !found_impl { + if !found_parent_with_attr && !found_impl { cx.struct_span_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, |lint| { lint.build(fluent::lint::diag_out_of_impl).emit(); }) @@ -425,7 +431,7 @@ impl LateLintPass<'_> for Diagnostics { } } debug!(?found_diagnostic_message); - if !found_diagnostic_message { + if !found_parent_with_attr && !found_diagnostic_message { cx.struct_span_lint(UNTRANSLATABLE_DIAGNOSTIC, span, |lint| { lint.build(fluent::lint::untranslatable_diag).emit(); }) diff --git a/src/test/ui-fulldeps/internal-lints/diagnostics.rs b/src/test/ui-fulldeps/internal-lints/diagnostics.rs index 33192433bbf3..0e449256153a 100644 --- a/src/test/ui-fulldeps/internal-lints/diagnostics.rs +++ b/src/test/ui-fulldeps/internal-lints/diagnostics.rs @@ -1,6 +1,7 @@ // compile-flags: -Z unstable-options #![crate_type = "lib"] +#![feature(rustc_attrs)] #![feature(rustc_private)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] @@ -71,3 +72,10 @@ pub fn make_diagnostics<'a>(sess: &'a ParseSess) { //~^ ERROR diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls //~^^ ERROR diagnostics should be created using translatable messages } + +// Check that `rustc_lint_diagnostics`-annotated functions aren't themselves linted. + +#[rustc_lint_diagnostics] +pub fn skipped_because_of_annotation<'a>(sess: &'a ParseSess) { + let _diag = sess.struct_err("untranslatable diagnostic"); // okay! +} diff --git a/src/test/ui-fulldeps/internal-lints/diagnostics.stderr b/src/test/ui-fulldeps/internal-lints/diagnostics.stderr index bae78ffdc021..ed5105dabcd3 100644 --- a/src/test/ui-fulldeps/internal-lints/diagnostics.stderr +++ b/src/test/ui-fulldeps/internal-lints/diagnostics.stderr @@ -1,41 +1,41 @@ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:36:14 + --> $DIR/diagnostics.rs:37:14 | LL | sess.struct_err("untranslatable diagnostic") | ^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/diagnostics.rs:5:9 + --> $DIR/diagnostics.rs:6:9 | LL | #![deny(rustc::untranslatable_diagnostic)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:53:14 + --> $DIR/diagnostics.rs:54:14 | LL | diag.note("untranslatable diagnostic"); | ^^^^ error: diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls - --> $DIR/diagnostics.rs:67:22 + --> $DIR/diagnostics.rs:68:22 | LL | let _diag = sess.struct_err(fluent::parser::expect_path); | ^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/diagnostics.rs:6:9 + --> $DIR/diagnostics.rs:7:9 | LL | #![deny(rustc::diagnostic_outside_of_impl)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls - --> $DIR/diagnostics.rs:70:22 + --> $DIR/diagnostics.rs:71:22 | LL | let _diag = sess.struct_err("untranslatable diagnostic"); | ^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:70:22 + --> $DIR/diagnostics.rs:71:22 | LL | let _diag = sess.struct_err("untranslatable diagnostic"); | ^^^^^^^^^^ From 28a055dceacd61d1a0faad075d69f71dfd439678 Mon Sep 17 00:00:00 2001 From: Tim Siegel Date: Wed, 31 Aug 2022 09:09:11 -0400 Subject: [PATCH 3986/5092] match_wild_err_arm: Fix typo in note text --- clippy_lints/src/matches/match_wild_err_arm.rs | 2 +- tests/ui/match_wild_err_arm.edition2018.stderr | 8 ++++---- tests/ui/match_wild_err_arm.edition2021.stderr | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/matches/match_wild_err_arm.rs b/clippy_lints/src/matches/match_wild_err_arm.rs index bc16f17b6196..a3aa2e4b389a 100644 --- a/clippy_lints/src/matches/match_wild_err_arm.rs +++ b/clippy_lints/src/matches/match_wild_err_arm.rs @@ -40,7 +40,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<' arm.pat.span, &format!("`Err({})` matches all errors", ident_bind_name), None, - "match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable", + "match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable", ); } } diff --git a/tests/ui/match_wild_err_arm.edition2018.stderr b/tests/ui/match_wild_err_arm.edition2018.stderr index 2a4012039ba9..2d66daea8046 100644 --- a/tests/ui/match_wild_err_arm.edition2018.stderr +++ b/tests/ui/match_wild_err_arm.edition2018.stderr @@ -5,7 +5,7 @@ LL | Err(_) => panic!("err"), | ^^^^^^ | = note: `-D clippy::match-wild-err-arm` implied by `-D warnings` - = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable + = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable error: `Err(_)` matches all errors --> $DIR/match_wild_err_arm.rs:20:9 @@ -13,7 +13,7 @@ error: `Err(_)` matches all errors LL | Err(_) => panic!(), | ^^^^^^ | - = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable + = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable error: `Err(_)` matches all errors --> $DIR/match_wild_err_arm.rs:26:9 @@ -21,7 +21,7 @@ error: `Err(_)` matches all errors LL | Err(_) => { | ^^^^^^ | - = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable + = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable error: `Err(_e)` matches all errors --> $DIR/match_wild_err_arm.rs:34:9 @@ -29,7 +29,7 @@ error: `Err(_e)` matches all errors LL | Err(_e) => panic!(), | ^^^^^^^ | - = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable + = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable error: aborting due to 4 previous errors diff --git a/tests/ui/match_wild_err_arm.edition2021.stderr b/tests/ui/match_wild_err_arm.edition2021.stderr index 2a4012039ba9..2d66daea8046 100644 --- a/tests/ui/match_wild_err_arm.edition2021.stderr +++ b/tests/ui/match_wild_err_arm.edition2021.stderr @@ -5,7 +5,7 @@ LL | Err(_) => panic!("err"), | ^^^^^^ | = note: `-D clippy::match-wild-err-arm` implied by `-D warnings` - = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable + = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable error: `Err(_)` matches all errors --> $DIR/match_wild_err_arm.rs:20:9 @@ -13,7 +13,7 @@ error: `Err(_)` matches all errors LL | Err(_) => panic!(), | ^^^^^^ | - = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable + = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable error: `Err(_)` matches all errors --> $DIR/match_wild_err_arm.rs:26:9 @@ -21,7 +21,7 @@ error: `Err(_)` matches all errors LL | Err(_) => { | ^^^^^^ | - = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable + = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable error: `Err(_e)` matches all errors --> $DIR/match_wild_err_arm.rs:34:9 @@ -29,7 +29,7 @@ error: `Err(_e)` matches all errors LL | Err(_e) => panic!(), | ^^^^^^^ | - = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable + = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable error: aborting due to 4 previous errors From 7298de256850e2e7480844f6300c0ecc297276b6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Aug 2022 15:24:40 +0200 Subject: [PATCH 3987/5092] fix a clippy test --- tests/ui/indexing_slicing_index.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/indexing_slicing_index.rs b/tests/ui/indexing_slicing_index.rs index 45a430edcb58..7ebf6ee993cb 100644 --- a/tests/ui/indexing_slicing_index.rs +++ b/tests/ui/indexing_slicing_index.rs @@ -3,7 +3,7 @@ // We also check the out_of_bounds_indexing lint here, because it lints similar things and // we want to avoid false positives. #![warn(clippy::out_of_bounds_indexing)] -#![allow(const_err, clippy::no_effect, clippy::unnecessary_operation)] +#![allow(const_err, unconditional_panic, clippy::no_effect, clippy::unnecessary_operation)] const ARR: [i32; 2] = [1, 2]; const REF: &i32 = &ARR[idx()]; // Ok, should not produce stderr. From fb41bfa77405233da5ddd324091380e018e3d956 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 31 Aug 2022 09:24:45 -0400 Subject: [PATCH 3988/5092] Merge commit 'f51aade56f93175dde89177a92e3669ebd8e7592' into clippyup --- .github/workflows/clippy.yml | 1 + .github/workflows/clippy_bors.yml | 1 + CHANGELOG.md | 160 +++- clippy_dev/src/bless.rs | 2 +- clippy_dev/src/fmt.rs | 8 +- clippy_dev/src/new_lint.rs | 2 +- clippy_dev/src/update_lints.rs | 4 +- clippy_lints/src/as_underscore.rs | 74 -- clippy_lints/src/borrow_as_ptr.rs | 99 -- clippy_lints/src/borrow_deref_ref.rs | 7 +- clippy_lints/src/bytecount.rs | 103 -- clippy_lints/src/bytes_count_to_len.rs | 70 -- ...se_sensitive_file_extension_comparisons.rs | 86 -- clippy_lints/src/casts/as_underscore.rs | 25 + clippy_lints/src/casts/borrow_as_ptr.rs | 37 + .../src/casts/cast_slice_from_raw_parts.rs | 63 ++ clippy_lints/src/casts/mod.rs | 109 ++- clippy_lints/src/casts/unnecessary_cast.rs | 9 +- clippy_lints/src/dereference.rs | 312 ++++++- clippy_lints/src/derive.rs | 5 +- clippy_lints/src/doc_link_with_quotes.rs | 2 +- clippy_lints/src/duplicate_mod.rs | 2 +- clippy_lints/src/escape.rs | 13 +- clippy_lints/src/floating_point_arithmetic.rs | 22 +- clippy_lints/src/format.rs | 24 +- clippy_lints/src/format_args.rs | 94 +- clippy_lints/src/format_impl.rs | 11 +- clippy_lints/src/functions/mod.rs | 56 +- clippy_lints/src/functions/result.rs | 100 ++ clippy_lints/src/functions/result_unit_err.rs | 66 -- clippy_lints/src/get_first.rs | 68 -- clippy_lints/src/if_let_mutex.rs | 50 +- clippy_lints/src/if_then_some_else_none.rs | 90 +- clippy_lints/src/lib.register_all.rs | 30 +- clippy_lints/src/lib.register_complexity.rs | 9 +- clippy_lints/src/lib.register_correctness.rs | 8 +- clippy_lints/src/lib.register_lints.rs | 50 +- clippy_lints/src/lib.register_nursery.rs | 5 +- clippy_lints/src/lib.register_pedantic.rs | 11 +- clippy_lints/src/lib.register_perf.rs | 2 + clippy_lints/src/lib.register_restriction.rs | 6 +- clippy_lints/src/lib.register_style.rs | 6 +- clippy_lints/src/lib.register_suspicious.rs | 5 + clippy_lints/src/lib.rs | 53 +- clippy_lints/src/loops/needless_collect.rs | 34 +- clippy_lints/src/manual_async_fn.rs | 2 +- clippy_lints/src/manual_ok_or.rs | 95 -- clippy_lints/src/manual_string_new.rs | 140 +++ clippy_lints/src/map_clone.rs | 167 ---- clippy_lints/src/map_err_ignore.rs | 154 --- .../src/matches/match_like_matches.rs | 4 +- clippy_lints/src/matches/needless_match.rs | 22 +- clippy_lints/src/methods/bytecount.rs | 70 ++ .../src/methods/bytes_count_to_len.rs | 37 + ...se_sensitive_file_extension_comparisons.rs | 41 + .../src/methods/collapsible_str_replace.rs | 96 ++ clippy_lints/src/methods/expect_used.rs | 18 +- clippy_lints/src/methods/get_first.rs | 39 + .../iter_on_single_or_empty_collections.rs | 107 +++ clippy_lints/src/methods/manual_ok_or.rs | 64 ++ clippy_lints/src/methods/map_clone.rs | 122 +++ clippy_lints/src/methods/map_err_ignore.rs | 34 + clippy_lints/src/methods/mod.rs | 857 ++++++++++++++++- clippy_lints/src/methods/mut_mutex_lock.rs | 30 + .../src/{ => methods}/open_options.rs | 44 +- .../src/methods/option_map_unwrap_or.rs | 2 +- .../src/methods/path_buf_push_overwrite.rs | 37 + .../src/methods/range_zip_with_len.rs | 34 + clippy_lints/src/methods/repeat_once.rs | 52 ++ .../src/methods/stable_sort_primitive.rs | 31 + .../src/methods/suspicious_to_owned.rs | 36 + .../src/methods/uninit_assumed_init.rs | 4 +- clippy_lints/src/methods/unit_hash.rs | 29 + .../src/{ => methods}/unnecessary_sort_by.rs | 156 ++-- .../src/methods/unnecessary_to_owned.rs | 37 +- clippy_lints/src/methods/unwrap_used.rs | 20 +- .../src/methods/vec_resize_to_zero.rs | 45 + .../src/methods/verbose_file_reads.rs | 28 + .../misc_early/unneeded_wildcard_pattern.rs | 2 +- .../src/mismatching_type_param_order.rs | 2 +- clippy_lints/src/multi_assignments.rs | 65 ++ clippy_lints/src/mut_mutex_lock.rs | 70 -- clippy_lints/src/only_used_in_recursion.rs | 880 +++++++----------- clippy_lints/src/option_if_let_else.rs | 167 +++- clippy_lints/src/partialeq_to_none.rs | 3 +- clippy_lints/src/path_buf_push_overwrite.rs | 72 -- clippy_lints/src/question_mark.rs | 2 +- clippy_lints/src/ranges.rs | 73 +- clippy_lints/src/rc_clone_in_vec_init.rs | 2 +- clippy_lints/src/redundant_slicing.rs | 4 +- .../src/redundant_static_lifetimes.rs | 12 +- clippy_lints/src/repeat_once.rs | 89 -- clippy_lints/src/returns.rs | 10 +- clippy_lints/src/self_named_constructors.rs | 4 +- clippy_lints/src/stable_sort_primitive.rs | 144 --- clippy_lints/src/trait_bounds.rs | 106 ++- clippy_lints/src/transmute/mod.rs | 25 + .../src/transmute/transmute_undefined_repr.rs | 400 ++++---- .../src/transmute/transmuting_null.rs | 61 ++ clippy_lints/src/transmuting_null.rs | 89 -- clippy_lints/src/unicode.rs | 7 + clippy_lints/src/uninit_vec.rs | 2 +- clippy_lints/src/unit_hash.rs | 78 -- clippy_lints/src/unnecessary_wraps.rs | 2 +- clippy_lints/src/unused_peekable.rs | 225 +++++ clippy_lints/src/unused_rounding.rs | 2 +- clippy_lints/src/utils/conf.rs | 6 +- clippy_lints/src/utils/internal_lints.rs | 4 +- .../internal_lints/metadata_collector.rs | 2 +- clippy_lints/src/vec_resize_to_zero.rs | 64 -- clippy_lints/src/verbose_file_reads.rs | 88 -- clippy_lints/src/write.rs | 129 ++- clippy_utils/Cargo.toml | 1 + clippy_utils/src/lib.rs | 29 +- clippy_utils/src/macros.rs | 678 ++++++++++---- clippy_utils/src/msrvs.rs | 4 +- clippy_utils/src/paths.rs | 2 +- clippy_utils/src/ty.rs | 60 +- rust-toolchain | 2 +- rustc_tools_util/src/lib.rs | 4 +- tests/check-fmt.rs | 2 +- tests/compile-test.rs | 19 +- tests/dogfood.rs | 4 +- tests/integration.rs | 4 +- tests/lint_message_convention.rs | 4 +- .../toml_unknown_key/conf_unknown_key.stderr | 1 + ...se_sensitive_file_extension_comparisons.rs | 10 +- ...ensitive_file_extension_comparisons.stderr | 12 +- tests/ui/cast_raw_slice_pointer_cast.fixed | 24 + tests/ui/cast_raw_slice_pointer_cast.rs | 24 + tests/ui/cast_raw_slice_pointer_cast.stderr | 46 + tests/ui/collapsible_str_replace.fixed | 73 ++ tests/ui/collapsible_str_replace.rs | 76 ++ tests/ui/collapsible_str_replace.stderr | 86 ++ tests/ui/expect.rs | 3 +- tests/ui/expect.stderr | 10 +- tests/ui/floating_point_exp.fixed | 1 + tests/ui/floating_point_exp.rs | 1 + tests/ui/floating_point_exp.stderr | 12 +- tests/ui/floating_point_log.fixed | 1 + tests/ui/floating_point_log.rs | 1 + tests/ui/floating_point_log.stderr | 54 +- tests/ui/floating_point_logbase.fixed | 1 + tests/ui/floating_point_logbase.rs | 1 + tests/ui/floating_point_logbase.stderr | 12 +- tests/ui/floating_point_powf.fixed | 3 + tests/ui/floating_point_powf.rs | 3 + tests/ui/floating_point_powf.stderr | 52 +- tests/ui/floating_point_powi.fixed | 1 + tests/ui/floating_point_powi.rs | 1 + tests/ui/floating_point_powi.stderr | 12 +- tests/ui/floating_point_rad.fixed | 5 + tests/ui/floating_point_rad.rs | 5 + tests/ui/floating_point_rad.stderr | 32 +- tests/ui/format.fixed | 2 +- tests/ui/format.rs | 2 +- tests/ui/format_args.fixed | 51 +- tests/ui/format_args.rs | 51 +- tests/ui/format_args.stderr | 56 +- tests/ui/identity_op.fixed | 2 +- tests/ui/identity_op.rs | 2 +- tests/ui/if_let_mutex.rs | 8 + tests/ui/if_let_mutex.stderr | 30 +- tests/ui/if_then_some_else_none.stderr | 8 +- tests/ui/iter_on_empty_collections.fixed | 63 ++ tests/ui/iter_on_empty_collections.rs | 63 ++ tests/ui/iter_on_empty_collections.stderr | 40 + tests/ui/iter_on_single_items.fixed | 63 ++ tests/ui/iter_on_single_items.rs | 63 ++ tests/ui/iter_on_single_items.stderr | 40 + tests/ui/manual_string_new.fixed | 63 ++ tests/ui/manual_string_new.rs | 63 ++ tests/ui/manual_string_new.stderr | 58 ++ tests/ui/match_expr_like_matches_macro.fixed | 25 + tests/ui/match_expr_like_matches_macro.rs | 25 + tests/ui/multi_assignments.rs | 9 + tests/ui/multi_assignments.stderr | 40 + tests/ui/needless_borrow.fixed | 117 ++- tests/ui/needless_borrow.rs | 117 ++- tests/ui/needless_borrow.stderr | 48 +- tests/ui/needless_collect_indirect.rs | 189 ++++ tests/ui/needless_collect_indirect.stderr | 119 ++- tests/ui/needless_match.fixed | 39 + tests/ui/needless_match.rs | 46 + tests/ui/needless_match.stderr | 23 +- tests/ui/needless_return.fixed | 10 +- tests/ui/needless_return.rs | 10 +- tests/ui/only_used_in_recursion.rs | 143 ++- tests/ui/only_used_in_recursion.stderr | 193 +++- tests/ui/only_used_in_recursion2.rs | 91 ++ tests/ui/only_used_in_recursion2.stderr | 63 ++ tests/ui/option_if_let_else.fixed | 9 + tests/ui/option_if_let_else.rs | 21 + tests/ui/option_if_let_else.stderr | 48 +- tests/ui/or_fun_call.fixed | 4 +- tests/ui/or_fun_call.rs | 4 +- tests/ui/or_fun_call.stderr | 6 +- tests/ui/partialeq_to_none.fixed | 12 + tests/ui/partialeq_to_none.rs | 12 + tests/ui/partialeq_to_none.stderr | 28 +- .../positional_named_format_parameters.fixed | 56 ++ .../ui/positional_named_format_parameters.rs | 56 ++ .../positional_named_format_parameters.stderr | 418 +++++++++ tests/ui/question_mark.fixed | 15 + tests/ui/question_mark.rs | 15 + tests/ui/regex.rs | 2 +- tests/ui/result_large_err.rs | 98 ++ tests/ui/result_large_err.stderr | 91 ++ tests/ui/same_item_push.rs | 1 + tests/ui/string_add.rs | 4 +- tests/ui/string_add_assign.fixed | 4 +- tests/ui/string_add_assign.rs | 4 +- tests/ui/suspicious_to_owned.rs | 62 ++ tests/ui/suspicious_to_owned.stderr | 42 + tests/ui/trait_duplication_in_bounds.fixed | 112 +++ tests/ui/trait_duplication_in_bounds.rs | 230 ++--- tests/ui/trait_duplication_in_bounds.stderr | 185 +--- .../trait_duplication_in_bounds_unfixable.rs | 166 ++++ ...ait_duplication_in_bounds_unfixable.stderr | 71 ++ tests/ui/transmute_undefined_repr.rs | 12 + tests/ui/transmute_undefined_repr.stderr | 38 +- tests/ui/unicode.fixed | 48 +- tests/ui/unicode.rs | 48 +- tests/ui/unicode.stderr | 46 +- tests/ui/unnecessary_cast.fixed | 9 + tests/ui/unnecessary_cast.rs | 9 + tests/ui/unnecessary_cast.stderr | 14 +- .../ui/unnecessary_owned_empty_strings.fixed | 1 + tests/ui/unnecessary_owned_empty_strings.rs | 1 + .../ui/unnecessary_owned_empty_strings.stderr | 2 +- tests/ui/unnecessary_to_owned.fixed | 28 + tests/ui/unnecessary_to_owned.rs | 28 + tests/ui/unused_peekable.rs | 144 +++ tests/ui/unused_peekable.stderr | 67 ++ tests/ui/unwrap.rs | 3 +- tests/ui/unwrap.stderr | 10 +- tests/ui/unwrap_expect_used.rs | 25 + tests/ui/unwrap_expect_used.stderr | 26 +- tests/ui/useless_conversion_try.rs | 4 +- tests/ui/useless_conversion_try.stderr | 2 +- tests/ui/vec_resize_to_zero.rs | 12 +- tests/ui/vec_resize_to_zero.stderr | 10 +- tests/ui/verbose_file_reads.rs | 2 +- tests/workspace.rs | 14 +- 244 files changed, 9305 insertions(+), 4024 deletions(-) delete mode 100644 clippy_lints/src/as_underscore.rs delete mode 100644 clippy_lints/src/borrow_as_ptr.rs delete mode 100644 clippy_lints/src/bytecount.rs delete mode 100644 clippy_lints/src/bytes_count_to_len.rs delete mode 100644 clippy_lints/src/case_sensitive_file_extension_comparisons.rs create mode 100644 clippy_lints/src/casts/as_underscore.rs create mode 100644 clippy_lints/src/casts/borrow_as_ptr.rs create mode 100644 clippy_lints/src/casts/cast_slice_from_raw_parts.rs create mode 100644 clippy_lints/src/functions/result.rs delete mode 100644 clippy_lints/src/functions/result_unit_err.rs delete mode 100644 clippy_lints/src/get_first.rs delete mode 100644 clippy_lints/src/manual_ok_or.rs create mode 100644 clippy_lints/src/manual_string_new.rs delete mode 100644 clippy_lints/src/map_clone.rs delete mode 100644 clippy_lints/src/map_err_ignore.rs create mode 100644 clippy_lints/src/methods/bytecount.rs create mode 100644 clippy_lints/src/methods/bytes_count_to_len.rs create mode 100644 clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs create mode 100644 clippy_lints/src/methods/collapsible_str_replace.rs create mode 100644 clippy_lints/src/methods/get_first.rs create mode 100644 clippy_lints/src/methods/iter_on_single_or_empty_collections.rs create mode 100644 clippy_lints/src/methods/manual_ok_or.rs create mode 100644 clippy_lints/src/methods/map_clone.rs create mode 100644 clippy_lints/src/methods/map_err_ignore.rs create mode 100644 clippy_lints/src/methods/mut_mutex_lock.rs rename clippy_lints/src/{ => methods}/open_options.rs (80%) create mode 100644 clippy_lints/src/methods/path_buf_push_overwrite.rs create mode 100644 clippy_lints/src/methods/range_zip_with_len.rs create mode 100644 clippy_lints/src/methods/repeat_once.rs create mode 100644 clippy_lints/src/methods/stable_sort_primitive.rs create mode 100644 clippy_lints/src/methods/suspicious_to_owned.rs create mode 100644 clippy_lints/src/methods/unit_hash.rs rename clippy_lints/src/{ => methods}/unnecessary_sort_by.rs (63%) create mode 100644 clippy_lints/src/methods/vec_resize_to_zero.rs create mode 100644 clippy_lints/src/methods/verbose_file_reads.rs create mode 100644 clippy_lints/src/multi_assignments.rs delete mode 100644 clippy_lints/src/mut_mutex_lock.rs delete mode 100644 clippy_lints/src/path_buf_push_overwrite.rs delete mode 100644 clippy_lints/src/repeat_once.rs delete mode 100644 clippy_lints/src/stable_sort_primitive.rs create mode 100644 clippy_lints/src/transmute/transmuting_null.rs delete mode 100644 clippy_lints/src/transmuting_null.rs delete mode 100644 clippy_lints/src/unit_hash.rs create mode 100644 clippy_lints/src/unused_peekable.rs delete mode 100644 clippy_lints/src/vec_resize_to_zero.rs delete mode 100644 clippy_lints/src/verbose_file_reads.rs create mode 100644 tests/ui/cast_raw_slice_pointer_cast.fixed create mode 100644 tests/ui/cast_raw_slice_pointer_cast.rs create mode 100644 tests/ui/cast_raw_slice_pointer_cast.stderr create mode 100644 tests/ui/collapsible_str_replace.fixed create mode 100644 tests/ui/collapsible_str_replace.rs create mode 100644 tests/ui/collapsible_str_replace.stderr create mode 100644 tests/ui/iter_on_empty_collections.fixed create mode 100644 tests/ui/iter_on_empty_collections.rs create mode 100644 tests/ui/iter_on_empty_collections.stderr create mode 100644 tests/ui/iter_on_single_items.fixed create mode 100644 tests/ui/iter_on_single_items.rs create mode 100644 tests/ui/iter_on_single_items.stderr create mode 100644 tests/ui/manual_string_new.fixed create mode 100644 tests/ui/manual_string_new.rs create mode 100644 tests/ui/manual_string_new.stderr create mode 100644 tests/ui/multi_assignments.rs create mode 100644 tests/ui/multi_assignments.stderr create mode 100644 tests/ui/only_used_in_recursion2.rs create mode 100644 tests/ui/only_used_in_recursion2.stderr create mode 100644 tests/ui/positional_named_format_parameters.fixed create mode 100644 tests/ui/positional_named_format_parameters.rs create mode 100644 tests/ui/positional_named_format_parameters.stderr create mode 100644 tests/ui/result_large_err.rs create mode 100644 tests/ui/result_large_err.stderr create mode 100644 tests/ui/suspicious_to_owned.rs create mode 100644 tests/ui/suspicious_to_owned.stderr create mode 100644 tests/ui/trait_duplication_in_bounds.fixed create mode 100644 tests/ui/trait_duplication_in_bounds_unfixable.rs create mode 100644 tests/ui/trait_duplication_in_bounds_unfixable.stderr create mode 100644 tests/ui/unused_peekable.rs create mode 100644 tests/ui/unused_peekable.stderr diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml index 0e27cc927ace..fac2c99714d9 100644 --- a/.github/workflows/clippy.yml +++ b/.github/workflows/clippy.yml @@ -24,6 +24,7 @@ env: RUST_BACKTRACE: 1 CARGO_TARGET_DIR: '${{ github.workspace }}/target' NO_FMT_TEST: 1 + CARGO_INCREMENTAL: 0 jobs: base: diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml index 97453303cd6a..30607af49012 100644 --- a/.github/workflows/clippy_bors.yml +++ b/.github/workflows/clippy_bors.yml @@ -10,6 +10,7 @@ env: RUST_BACKTRACE: 1 CARGO_TARGET_DIR: '${{ github.workspace }}/target' NO_FMT_TEST: 1 + CARGO_INCREMENTAL: 0 defaults: run: diff --git a/CHANGELOG.md b/CHANGELOG.md index 380cd451987b..c488c142e46f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,157 @@ document. ## Unreleased / In Rust Nightly -[7c21f91b...master](https://github.com/rust-lang/rust-clippy/compare/7c21f91b...master) +[d7b5cbf0...master](https://github.com/rust-lang/rust-clippy/compare/d7b5cbf0...master) + +## Rust 1.63 + +Current stable, released 2022-08-11 + +[7c21f91b...d7b5cbf0](https://github.com/rust-lang/rust-clippy/compare/7c21f91b...d7b5cbf0) + +### New Lints + +* [`borrow_deref_ref`] + [#7930](https://github.com/rust-lang/rust-clippy/pull/7930) +* [`doc_link_with_quotes`] + [#8385](https://github.com/rust-lang/rust-clippy/pull/8385) +* [`no_effect_replace`] + [#8754](https://github.com/rust-lang/rust-clippy/pull/8754) +* [`rc_clone_in_vec_init`] + [#8769](https://github.com/rust-lang/rust-clippy/pull/8769) +* [`derive_partial_eq_without_eq`] + [#8796](https://github.com/rust-lang/rust-clippy/pull/8796) +* [`mismatching_type_param_order`] + [#8831](https://github.com/rust-lang/rust-clippy/pull/8831) +* [`duplicate_mod`] [#8832](https://github.com/rust-lang/rust-clippy/pull/8832) +* [`unused_rounding`] + [#8866](https://github.com/rust-lang/rust-clippy/pull/8866) +* [`get_first`] [#8882](https://github.com/rust-lang/rust-clippy/pull/8882) +* [`swap_ptr_to_ref`] + [#8916](https://github.com/rust-lang/rust-clippy/pull/8916) +* [`almost_complete_letter_range`] + [#8918](https://github.com/rust-lang/rust-clippy/pull/8918) +* [`needless_parens_on_range_literals`] + [#8933](https://github.com/rust-lang/rust-clippy/pull/8933) +* [`as_underscore`] [#8934](https://github.com/rust-lang/rust-clippy/pull/8934) + +### Moves and Deprecations + +* Rename `eval_order_dependence` to [`mixed_read_write_in_expression`], move to + `nursery` [#8621](https://github.com/rust-lang/rust-clippy/pull/8621) + +### Enhancements + +* [`undocumented_unsafe_blocks`]: Now also lints on unsafe trait implementations + [#8761](https://github.com/rust-lang/rust-clippy/pull/8761) +* [`empty_line_after_outer_attr`]: Now also lints on argumentless macros + [#8790](https://github.com/rust-lang/rust-clippy/pull/8790) +* [`expect_used`]: Now can be disabled in tests with the `allow-expect-in-tests` + option [#8802](https://github.com/rust-lang/rust-clippy/pull/8802) +* [`unwrap_used`]: Now can be disabled in tests with the `allow-unwrap-in-tests` + option [#8802](https://github.com/rust-lang/rust-clippy/pull/8802) +* [`disallowed_methods`]: Now also lints indirect usages + [#8852](https://github.com/rust-lang/rust-clippy/pull/8852) +* [`get_last_with_len`]: Now also lints `VecDeque` and any deref to slice + [#8862](https://github.com/rust-lang/rust-clippy/pull/8862) +* [`manual_range_contains`]: Now also lints on chains of `&&` and `||` + [#8884](https://github.com/rust-lang/rust-clippy/pull/8884) +* [`rc_clone_in_vec_init`]: Now also lints on `Weak` + [#8885](https://github.com/rust-lang/rust-clippy/pull/8885) +* [`dbg_macro`]: Introduce `allow-dbg-in-tests` config option + [#8897](https://github.com/rust-lang/rust-clippy/pull/8897) +* [`use_self`]: Now also lints on `TupleStruct` and `Struct` patterns + [#8899](https://github.com/rust-lang/rust-clippy/pull/8899) +* [`manual_find_map`] and [`manual_filter_map`]: Now also lints on more complex + method chains inside `map` + [#8930](https://github.com/rust-lang/rust-clippy/pull/8930) +* [`needless_return`]: Now also lints on macro expressions in return statements + [#8932](https://github.com/rust-lang/rust-clippy/pull/8932) +* [`doc_markdown`]: Users can now indicate, that the `doc-valid-idents` config + should extend the default and not replace it + [#8944](https://github.com/rust-lang/rust-clippy/pull/8944) +* [`disallowed_names`]: Users can now indicate, that the `disallowed-names` + config should extend the default and not replace it + [#8944](https://github.com/rust-lang/rust-clippy/pull/8944) +* [`never_loop`]: Now checks for `continue` in struct expression + [#9002](https://github.com/rust-lang/rust-clippy/pull/9002) + +### False Positive Fixes + +* [`useless_transmute`]: No longer lints on types with erased regions + [#8564](https://github.com/rust-lang/rust-clippy/pull/8564) +* [`vec_init_then_push`]: No longer lints when further extended + [#8699](https://github.com/rust-lang/rust-clippy/pull/8699) +* [`cmp_owned`]: No longer lints on `From::from` for `Copy` types + [#8807](https://github.com/rust-lang/rust-clippy/pull/8807) +* [`redundant_allocation`]: No longer lints on fat pointers that would become + thin pointers [#8813](https://github.com/rust-lang/rust-clippy/pull/8813) +* [`derive_partial_eq_without_eq`]: + * Handle differing predicates applied by `#[derive(PartialEq)]` and + `#[derive(Eq)]` + [#8869](https://github.com/rust-lang/rust-clippy/pull/8869) + * No longer lints on non-public types and better handles generics + [#8950](https://github.com/rust-lang/rust-clippy/pull/8950) +* [`empty_line_after_outer_attr`]: No longer lints empty lines in inner + string values [#8892](https://github.com/rust-lang/rust-clippy/pull/8892) +* [`branches_sharing_code`]: No longer lints when using different binding names + [#8901](https://github.com/rust-lang/rust-clippy/pull/8901) +* [`significant_drop_in_scrutinee`]: No longer lints on Try `?` and `await` + desugared expressions [#8902](https://github.com/rust-lang/rust-clippy/pull/8902) +* [`checked_conversions`]: No longer lints in `const` contexts + [#8907](https://github.com/rust-lang/rust-clippy/pull/8907) +* [`iter_overeager_cloned`]: No longer lints on `.cloned().flatten()` when + `T::Item` doesn't implement `IntoIterator` + [#8960](https://github.com/rust-lang/rust-clippy/pull/8960) + +### Suggestion Fixes/Improvements + +* [`vec_init_then_push`]: Suggest to remove `mut` binding when possible + [#8699](https://github.com/rust-lang/rust-clippy/pull/8699) +* [`manual_range_contains`]: Fix suggestion for integers with different signs + [#8763](https://github.com/rust-lang/rust-clippy/pull/8763) +* [`identity_op`]: Add parenthesis to suggestions where required + [#8786](https://github.com/rust-lang/rust-clippy/pull/8786) +* [`cast_lossless`]: No longer gives wrong suggestion on `usize`/`isize`->`f64` + [#8778](https://github.com/rust-lang/rust-clippy/pull/8778) +* [`rc_clone_in_vec_init`]: Add suggestion + [#8814](https://github.com/rust-lang/rust-clippy/pull/8814) +* The "unknown field" error messages for config files now wraps the field names + [#8823](https://github.com/rust-lang/rust-clippy/pull/8823) +* [`cast_abs_to_unsigned`]: Do not remove cast if it's required + [#8876](https://github.com/rust-lang/rust-clippy/pull/8876) +* [`significant_drop_in_scrutinee`]: Improve lint message for types that are not + references and not trivially clone-able + [#8902](https://github.com/rust-lang/rust-clippy/pull/8902) +* [`for_loops_over_fallibles`]: Now suggests the correct variant of `iter()`, + `iter_mut()` or `into_iter()` + [#8941](https://github.com/rust-lang/rust-clippy/pull/8941) + +### ICE Fixes + +* Fix ICE in [`let_unit_value`] when calling a `static`/`const` callable type + [#8835](https://github.com/rust-lang/rust-clippy/pull/8835) +* Fix ICEs on callable `static`/`const`s + [#8896](https://github.com/rust-lang/rust-clippy/pull/8896) +* [`needless_late_init`] + [#8912](https://github.com/rust-lang/rust-clippy/pull/8912) +* Fix ICE in shadow lints + [#8913](https://github.com/rust-lang/rust-clippy/pull/8913) + +### Documentation Improvements + +* Clippy has a [Book](https://doc.rust-lang.org/nightly/clippy/) now! + [#7359](https://github.com/rust-lang/rust-clippy/pull/7359) +* Add a *copy lint name*-button to Clippy's lint list + [#8839](https://github.com/rust-lang/rust-clippy/pull/8839) +* Display past names of renamed lints on Clippy's lint list + [#8843](https://github.com/rust-lang/rust-clippy/pull/8843) +* Add the ability to show the lint output in the lint list + [#8947](https://github.com/rust-lang/rust-clippy/pull/8947) ## Rust 1.62 -Current stable, released 2022-06-30 +Released 2022-06-30 [d0cf3481...7c21f91b](https://github.com/rust-lang/rust-clippy/compare/d0cf3481...7c21f91b) @@ -3481,6 +3627,7 @@ Released 2018-09-13 [`cast_ref_to_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_ref_to_mut [`cast_sign_loss`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_sign_loss [`cast_slice_different_sizes`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_slice_different_sizes +[`cast_slice_from_raw_parts`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_slice_from_raw_parts [`char_lit_as_u8`]: https://rust-lang.github.io/rust-clippy/master/index.html#char_lit_as_u8 [`chars_last_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_last_cmp [`chars_next_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_next_cmp @@ -3496,6 +3643,7 @@ Released 2018-09-13 [`collapsible_else_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_else_if [`collapsible_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if [`collapsible_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_match +[`collapsible_str_replace`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_str_replace [`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain [`comparison_to_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty [`const_static_lifetime`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_static_lifetime @@ -3656,6 +3804,8 @@ Released 2018-09-13 [`iter_not_returning_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_not_returning_iterator [`iter_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth [`iter_nth_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth_zero +[`iter_on_empty_collections`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_on_empty_collections +[`iter_on_single_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_on_single_items [`iter_overeager_cloned`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_overeager_cloned [`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next [`iter_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_with_drain @@ -3697,6 +3847,7 @@ Released 2018-09-13 [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic [`manual_split_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_split_once [`manual_str_repeat`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat +[`manual_string_new`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_string_new [`manual_strip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip [`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap [`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or @@ -3747,6 +3898,7 @@ Released 2018-09-13 [`module_name_repetitions`]: https://rust-lang.github.io/rust-clippy/master/index.html#module_name_repetitions [`modulo_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#modulo_arithmetic [`modulo_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#modulo_one +[`multi_assignments`]: https://rust-lang.github.io/rust-clippy/master/index.html#multi_assignments [`multiple_crate_versions`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_crate_versions [`multiple_inherent_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#multiple_inherent_impl [`must_use_candidate`]: https://rust-lang.github.io/rust-clippy/master/index.html#must_use_candidate @@ -3827,6 +3979,7 @@ Released 2018-09-13 [`partialeq_to_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_to_none [`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite [`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch +[`positional_named_format_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#positional_named_format_parameters [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma [`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence [`print_in_format_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_in_format_impl @@ -3872,6 +4025,7 @@ Released 2018-09-13 [`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts [`rest_pat_in_fully_bound_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#rest_pat_in_fully_bound_structs [`result_expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_expect_used +[`result_large_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err [`result_map_or_into_option`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_or_into_option [`result_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unit_fn [`result_map_unwrap_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unwrap_or_else @@ -3930,6 +4084,7 @@ Released 2018-09-13 [`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl [`suspicious_operation_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_operation_groupings [`suspicious_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_splitn +[`suspicious_to_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_to_owned [`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting [`swap_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#swap_ptr_to_ref [`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments @@ -4002,6 +4157,7 @@ Released 2018-09-13 [`unused_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_collect [`unused_io_amount`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount [`unused_label`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_label +[`unused_peekable`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_peekable [`unused_rounding`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_rounding [`unused_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_self [`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit diff --git a/clippy_dev/src/bless.rs b/clippy_dev/src/bless.rs index f5c51b9474fc..92b2771f3fe7 100644 --- a/clippy_dev/src/bless.rs +++ b/clippy_dev/src/bless.rs @@ -37,7 +37,7 @@ fn update_reference_file(test_output_entry: &DirEntry, ignore_timestamp: bool) { return; } - let test_output_file = fs::read(&test_output_path).expect("Unable to read test output file"); + let test_output_file = fs::read(test_output_path).expect("Unable to read test output file"); let reference_file = fs::read(&reference_file_path).unwrap_or_default(); if test_output_file != reference_file { diff --git a/clippy_dev/src/fmt.rs b/clippy_dev/src/fmt.rs index 3b27f061eb0b..357cf6fc43aa 100644 --- a/clippy_dev/src/fmt.rs +++ b/clippy_dev/src/fmt.rs @@ -46,7 +46,7 @@ pub fn run(check: bool, verbose: bool) { // dependency if fs::read_to_string(project_root.join("Cargo.toml")) .expect("Failed to read clippy Cargo.toml") - .contains(&"[target.'cfg(NOT_A_PLATFORM)'.dependencies]") + .contains("[target.'cfg(NOT_A_PLATFORM)'.dependencies]") { return Err(CliError::IntellijSetupActive); } @@ -193,10 +193,10 @@ fn rustfmt_test(context: &FmtContext) -> Result<(), CliError> { let args = &["--version"]; if context.verbose { - println!("{}", format_command(&program, &dir, args)); + println!("{}", format_command(program, &dir, args)); } - let output = Command::new(&program).current_dir(&dir).args(args.iter()).output()?; + let output = Command::new(program).current_dir(&dir).args(args.iter()).output()?; if output.status.success() { Ok(()) @@ -207,7 +207,7 @@ fn rustfmt_test(context: &FmtContext) -> Result<(), CliError> { Err(CliError::RustfmtNotInstalled) } else { Err(CliError::CommandFailed( - format_command(&program, &dir, args), + format_command(program, &dir, args), std::str::from_utf8(&output.stderr).unwrap_or("").to_string(), )) } diff --git a/clippy_dev/src/new_lint.rs b/clippy_dev/src/new_lint.rs index 10a8f31f4573..be05e67d724d 100644 --- a/clippy_dev/src/new_lint.rs +++ b/clippy_dev/src/new_lint.rs @@ -155,7 +155,7 @@ fn to_camel_case(name: &str) -> String { name.split('_') .map(|s| { if s.is_empty() { - String::from("") + String::new() } else { [&s[0..1].to_uppercase(), &s[1..]].concat() } diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 05e79a241884..c503142e5e45 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -418,7 +418,7 @@ fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec) -> io .expect("failed to find `impl_lint_pass` terminator"); impl_lint_pass_end += impl_lint_pass_start; - if let Some(lint_name_pos) = content[impl_lint_pass_start..impl_lint_pass_end].find(&lint_name_upper) { + if let Some(lint_name_pos) = content[impl_lint_pass_start..impl_lint_pass_end].find(lint_name_upper) { let mut lint_name_end = impl_lint_pass_start + (lint_name_pos + lint_name_upper.len()); for c in content[lint_name_end..impl_lint_pass_end].chars() { // Remove trailing whitespace @@ -451,7 +451,7 @@ fn remove_lint_declaration(name: &str, path: &Path, lints: &mut Vec) -> io } let mut content = - fs::read_to_string(&path).unwrap_or_else(|_| panic!("failed to read `{}`", path.to_string_lossy())); + fs::read_to_string(path).unwrap_or_else(|_| panic!("failed to read `{}`", path.to_string_lossy())); eprintln!( "warn: you will have to manually remove any code related to `{}` from `{}`", diff --git a/clippy_lints/src/as_underscore.rs b/clippy_lints/src/as_underscore.rs deleted file mode 100644 index 0bdef9d0a7e8..000000000000 --- a/clippy_lints/src/as_underscore.rs +++ /dev/null @@ -1,74 +0,0 @@ -use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; -use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, TyKind}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::lint::in_external_macro; -use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -declare_clippy_lint! { - /// ### What it does - /// Check for the usage of `as _` conversion using inferred type. - /// - /// ### Why is this bad? - /// The conversion might include lossy conversion and dangerous cast that might go - /// undetected du to the type being inferred. - /// - /// The lint is allowed by default as using `_` is less wordy than always specifying the type. - /// - /// ### Example - /// ```rust - /// fn foo(n: usize) {} - /// let n: u16 = 256; - /// foo(n as _); - /// ``` - /// Use instead: - /// ```rust - /// fn foo(n: usize) {} - /// let n: u16 = 256; - /// foo(n as usize); - /// ``` - #[clippy::version = "1.63.0"] - pub AS_UNDERSCORE, - restriction, - "detects `as _` conversion" -} -declare_lint_pass!(AsUnderscore => [AS_UNDERSCORE]); - -impl<'tcx> LateLintPass<'tcx> for AsUnderscore { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { - if in_external_macro(cx.sess(), expr.span) { - return; - } - - if let ExprKind::Cast(_, ty) = expr.kind && let TyKind::Infer = ty.kind { - - let ty_resolved = cx.typeck_results().expr_ty(expr); - if let ty::Error(_) = ty_resolved.kind() { - span_lint_and_help( - cx, - AS_UNDERSCORE, - expr.span, - "using `as _` conversion", - None, - "consider giving the type explicitly", - ); - } else { - span_lint_and_then( - cx, - AS_UNDERSCORE, - expr.span, - "using `as _` conversion", - |diag| { - diag.span_suggestion( - ty.span, - "consider giving the type explicitly", - ty_resolved, - Applicability::MachineApplicable, - ); - } - ); - } - } - } -} diff --git a/clippy_lints/src/borrow_as_ptr.rs b/clippy_lints/src/borrow_as_ptr.rs deleted file mode 100644 index 0993adbae2e6..000000000000 --- a/clippy_lints/src/borrow_as_ptr.rs +++ /dev/null @@ -1,99 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_no_std_crate; -use clippy_utils::source::snippet_opt; -use clippy_utils::{meets_msrv, msrvs}; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, TyKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_semver::RustcVersion; -use rustc_session::{declare_tool_lint, impl_lint_pass}; - -declare_clippy_lint! { - /// ### What it does - /// Checks for the usage of `&expr as *const T` or - /// `&mut expr as *mut T`, and suggest using `ptr::addr_of` or - /// `ptr::addr_of_mut` instead. - /// - /// ### Why is this bad? - /// This would improve readability and avoid creating a reference - /// that points to an uninitialized value or unaligned place. - /// Read the `ptr::addr_of` docs for more information. - /// - /// ### Example - /// ```rust - /// let val = 1; - /// let p = &val as *const i32; - /// - /// let mut val_mut = 1; - /// let p_mut = &mut val_mut as *mut i32; - /// ``` - /// Use instead: - /// ```rust - /// let val = 1; - /// let p = std::ptr::addr_of!(val); - /// - /// let mut val_mut = 1; - /// let p_mut = std::ptr::addr_of_mut!(val_mut); - /// ``` - #[clippy::version = "1.60.0"] - pub BORROW_AS_PTR, - pedantic, - "borrowing just to cast to a raw pointer" -} - -impl_lint_pass!(BorrowAsPtr => [BORROW_AS_PTR]); - -pub struct BorrowAsPtr { - msrv: Option, -} - -impl BorrowAsPtr { - #[must_use] - pub fn new(msrv: Option) -> Self { - Self { msrv } - } -} - -impl<'tcx> LateLintPass<'tcx> for BorrowAsPtr { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if !meets_msrv(self.msrv, msrvs::BORROW_AS_PTR) { - return; - } - - if expr.span.from_expansion() { - return; - } - - if_chain! { - if let ExprKind::Cast(left_expr, ty) = &expr.kind; - if let TyKind::Ptr(_) = ty.kind; - if let ExprKind::AddrOf(BorrowKind::Ref, mutability, e) = &left_expr.kind; - - then { - let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" }; - let macro_name = match mutability { - Mutability::Not => "addr_of", - Mutability::Mut => "addr_of_mut", - }; - - span_lint_and_sugg( - cx, - BORROW_AS_PTR, - expr.span, - "borrow as raw pointer", - "try", - format!( - "{}::ptr::{}!({})", - core_or_std, - macro_name, - snippet_opt(cx, e.span).unwrap() - ), - Applicability::MachineApplicable, - ); - } - } - } - - extract_msrv_attr!(LateContext); -} diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs index 937765b66147..c4520d003928 100644 --- a/clippy_lints/src/borrow_deref_ref.rs +++ b/clippy_lints/src/borrow_deref_ref.rs @@ -29,22 +29,17 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// fn foo(_x: &str) {} - /// /// let s = &String::new(); /// /// let a: &String = &* s; - /// foo(&*s); /// ``` /// /// Use instead: /// ```rust - /// # fn foo(_x: &str) {} /// # let s = &String::new(); /// let a: &String = s; - /// foo(&**s); /// ``` - #[clippy::version = "1.59.0"] + #[clippy::version = "1.63.0"] pub BORROW_DEREF_REF, complexity, "deref on an immutable reference returns the same type as itself" diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs deleted file mode 100644 index 326ce34082af..000000000000 --- a/clippy_lints/src/bytecount.rs +++ /dev/null @@ -1,103 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::match_type; -use clippy_utils::visitors::is_local_used; -use clippy_utils::{path_to_local_id, paths, peel_blocks, peel_ref_operators, strip_pat_refs}; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Closure, Expr, ExprKind, PatKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{self, UintTy}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; - -declare_clippy_lint! { - /// ### What it does - /// Checks for naive byte counts - /// - /// ### Why is this bad? - /// The [`bytecount`](https://crates.io/crates/bytecount) - /// crate has methods to count your bytes faster, especially for large slices. - /// - /// ### Known problems - /// If you have predominantly small slices, the - /// `bytecount::count(..)` method may actually be slower. However, if you can - /// ensure that less than 2³²-1 matches arise, the `naive_count_32(..)` can be - /// faster in those cases. - /// - /// ### Example - /// ```rust - /// # let vec = vec![1_u8]; - /// let count = vec.iter().filter(|x| **x == 0u8).count(); - /// ``` - /// - /// Use instead: - /// ```rust,ignore - /// # let vec = vec![1_u8]; - /// let count = bytecount::count(&vec, 0u8); - /// ``` - #[clippy::version = "pre 1.29.0"] - pub NAIVE_BYTECOUNT, - pedantic, - "use of naive `.filter(|&x| x == y).count()` to count byte values" -} - -declare_lint_pass!(ByteCount => [NAIVE_BYTECOUNT]); - -impl<'tcx> LateLintPass<'tcx> for ByteCount { - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if_chain! { - if let ExprKind::MethodCall(count, [count_recv], _) = expr.kind; - if count.ident.name == sym::count; - if let ExprKind::MethodCall(filter, [filter_recv, filter_arg], _) = count_recv.kind; - if filter.ident.name == sym!(filter); - if let ExprKind::Closure(&Closure { body, .. }) = filter_arg.kind; - let body = cx.tcx.hir().body(body); - if let [param] = body.params; - if let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind; - if let ExprKind::Binary(ref op, l, r) = body.value.kind; - if op.node == BinOpKind::Eq; - if match_type(cx, - cx.typeck_results().expr_ty(filter_recv).peel_refs(), - &paths::SLICE_ITER); - let operand_is_arg = |expr| { - let expr = peel_ref_operators(cx, peel_blocks(expr)); - path_to_local_id(expr, arg_id) - }; - let needle = if operand_is_arg(l) { - r - } else if operand_is_arg(r) { - l - } else { - return; - }; - if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(needle).peel_refs().kind(); - if !is_local_used(cx, needle, arg_id); - then { - let haystack = if let ExprKind::MethodCall(path, args, _) = - filter_recv.kind { - let p = path.ident.name; - if (p == sym::iter || p == sym!(iter_mut)) && args.len() == 1 { - &args[0] - } else { - filter_recv - } - } else { - filter_recv - }; - let mut applicability = Applicability::MaybeIncorrect; - span_lint_and_sugg( - cx, - NAIVE_BYTECOUNT, - expr.span, - "you appear to be counting bytes the naive way", - "consider using the bytecount crate", - format!("bytecount::count({}, {})", - snippet_with_applicability(cx, haystack.span, "..", &mut applicability), - snippet_with_applicability(cx, needle.span, "..", &mut applicability)), - applicability, - ); - } - }; - } -} diff --git a/clippy_lints/src/bytes_count_to_len.rs b/clippy_lints/src/bytes_count_to_len.rs deleted file mode 100644 index d70dbf5b2390..000000000000 --- a/clippy_lints/src/bytes_count_to_len.rs +++ /dev/null @@ -1,70 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{match_def_path, paths}; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir as hir; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; - -declare_clippy_lint! { - /// ### What it does - /// It checks for `str::bytes().count()` and suggests replacing it with - /// `str::len()`. - /// - /// ### Why is this bad? - /// `str::bytes().count()` is longer and may not be as performant as using - /// `str::len()`. - /// - /// ### Example - /// ```rust - /// "hello".bytes().count(); - /// String::from("hello").bytes().count(); - /// ``` - /// Use instead: - /// ```rust - /// "hello".len(); - /// String::from("hello").len(); - /// ``` - #[clippy::version = "1.62.0"] - pub BYTES_COUNT_TO_LEN, - complexity, - "Using `bytes().count()` when `len()` performs the same functionality" -} - -declare_lint_pass!(BytesCountToLen => [BYTES_COUNT_TO_LEN]); - -impl<'tcx> LateLintPass<'tcx> for BytesCountToLen { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if_chain! { - if let hir::ExprKind::MethodCall(_, expr_args, _) = &expr.kind; - if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if match_def_path(cx, expr_def_id, &paths::ITER_COUNT); - - if let [bytes_expr] = &**expr_args; - if let hir::ExprKind::MethodCall(_, bytes_args, _) = &bytes_expr.kind; - if let Some(bytes_def_id) = cx.typeck_results().type_dependent_def_id(bytes_expr.hir_id); - if match_def_path(cx, bytes_def_id, &paths::STR_BYTES); - - if let [str_expr] = &**bytes_args; - let ty = cx.typeck_results().expr_ty(str_expr).peel_refs(); - - if is_type_diagnostic_item(cx, ty, sym::String) || ty.kind() == &ty::Str; - then { - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - BYTES_COUNT_TO_LEN, - expr.span, - "using long and hard to read `.bytes().count()`", - "consider calling `.len()` instead", - format!("{}.len()", snippet_with_applicability(cx, str_expr.span, "..", &mut applicability)), - applicability - ); - } - }; - } -} diff --git a/clippy_lints/src/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/case_sensitive_file_extension_comparisons.rs deleted file mode 100644 index 7eff71d50074..000000000000 --- a/clippy_lints/src/case_sensitive_file_extension_comparisons.rs +++ /dev/null @@ -1,86 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_help; -use if_chain::if_chain; -use rustc_ast::ast::LitKind; -use rustc_hir::{Expr, ExprKind, PathSegment}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::{source_map::Spanned, symbol::sym, Span}; - -declare_clippy_lint! { - /// ### What it does - /// Checks for calls to `ends_with` with possible file extensions - /// and suggests to use a case-insensitive approach instead. - /// - /// ### Why is this bad? - /// `ends_with` is case-sensitive and may not detect files with a valid extension. - /// - /// ### Example - /// ```rust - /// fn is_rust_file(filename: &str) -> bool { - /// filename.ends_with(".rs") - /// } - /// ``` - /// Use instead: - /// ```rust - /// fn is_rust_file(filename: &str) -> bool { - /// let filename = std::path::Path::new(filename); - /// filename.extension() - /// .map(|ext| ext.eq_ignore_ascii_case("rs")) - /// .unwrap_or(false) - /// } - /// ``` - #[clippy::version = "1.51.0"] - pub CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, - pedantic, - "Checks for calls to ends_with with case-sensitive file extensions" -} - -declare_lint_pass!(CaseSensitiveFileExtensionComparisons => [CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS]); - -fn check_case_sensitive_file_extension_comparison(ctx: &LateContext<'_>, expr: &Expr<'_>) -> Option { - if_chain! { - if let ExprKind::MethodCall(PathSegment { ident, .. }, [obj, extension, ..], span) = expr.kind; - if ident.as_str() == "ends_with"; - if let ExprKind::Lit(Spanned { node: LitKind::Str(ext_literal, ..), ..}) = extension.kind; - if (2..=6).contains(&ext_literal.as_str().len()); - if ext_literal.as_str().starts_with('.'); - if ext_literal.as_str().chars().skip(1).all(|c| c.is_uppercase() || c.is_ascii_digit()) - || ext_literal.as_str().chars().skip(1).all(|c| c.is_lowercase() || c.is_ascii_digit()); - then { - let mut ty = ctx.typeck_results().expr_ty(obj); - ty = match ty.kind() { - ty::Ref(_, ty, ..) => *ty, - _ => ty - }; - - match ty.kind() { - ty::Str => { - return Some(span); - }, - ty::Adt(def, _) => { - if ctx.tcx.is_diagnostic_item(sym::String, def.did()) { - return Some(span); - } - }, - _ => { return None; } - } - } - } - None -} - -impl<'tcx> LateLintPass<'tcx> for CaseSensitiveFileExtensionComparisons { - fn check_expr(&mut self, ctx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if let Some(span) = check_case_sensitive_file_extension_comparison(ctx, expr) { - span_lint_and_help( - ctx, - CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, - span, - "case-sensitive file extension comparison", - None, - "consider using a case-insensitive comparison instead", - ); - } - } -} diff --git a/clippy_lints/src/casts/as_underscore.rs b/clippy_lints/src/casts/as_underscore.rs new file mode 100644 index 000000000000..56e894c6261e --- /dev/null +++ b/clippy_lints/src/casts/as_underscore.rs @@ -0,0 +1,25 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use rustc_errors::Applicability; +use rustc_hir::{Expr, Ty, TyKind}; +use rustc_lint::LateContext; +use rustc_middle::ty; + +use super::AS_UNDERSCORE; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, ty: &'tcx Ty<'_>) { + if matches!(ty.kind, TyKind::Infer) { + span_lint_and_then(cx, AS_UNDERSCORE, expr.span, "using `as _` conversion", |diag| { + let ty_resolved = cx.typeck_results().expr_ty(expr); + if let ty::Error(_) = ty_resolved.kind() { + diag.help("consider giving the type explicitly"); + } else { + diag.span_suggestion( + ty.span, + "consider giving the type explicitly", + ty_resolved, + Applicability::MachineApplicable, + ); + } + }); + } +} diff --git a/clippy_lints/src/casts/borrow_as_ptr.rs b/clippy_lints/src/casts/borrow_as_ptr.rs new file mode 100644 index 000000000000..6e1f8cd64f07 --- /dev/null +++ b/clippy_lints/src/casts/borrow_as_ptr.rs @@ -0,0 +1,37 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_no_std_crate; +use clippy_utils::source::snippet_with_context; +use rustc_errors::Applicability; +use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Ty, TyKind}; +use rustc_lint::LateContext; + +use super::BORROW_AS_PTR; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + cast_expr: &'tcx Expr<'_>, + cast_to: &'tcx Ty<'_>, +) { + if matches!(cast_to.kind, TyKind::Ptr(_)) + && let ExprKind::AddrOf(BorrowKind::Ref, mutability, e) = cast_expr.kind + { + let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" }; + let macro_name = match mutability { + Mutability::Not => "addr_of", + Mutability::Mut => "addr_of_mut", + }; + let mut app = Applicability::MachineApplicable; + let snip = snippet_with_context(cx, e.span, cast_expr.span.ctxt(), "..", &mut app).0; + + span_lint_and_sugg( + cx, + BORROW_AS_PTR, + expr.span, + "borrow as raw pointer", + "try", + format!("{}::ptr::{}!({})", core_or_std, macro_name, snip), + Applicability::MachineApplicable, + ); + } +} diff --git a/clippy_lints/src/casts/cast_slice_from_raw_parts.rs b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs new file mode 100644 index 000000000000..284ef165998a --- /dev/null +++ b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs @@ -0,0 +1,63 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{match_def_path, meets_msrv, msrvs, paths}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{def_id::DefId, Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_middle::ty::{self, Ty}; +use rustc_semver::RustcVersion; + +use super::CAST_SLICE_FROM_RAW_PARTS; + +enum RawPartsKind { + Immutable, + Mutable, +} + +fn raw_parts_kind(cx: &LateContext<'_>, did: DefId) -> Option { + if match_def_path(cx, did, &paths::SLICE_FROM_RAW_PARTS) { + Some(RawPartsKind::Immutable) + } else if match_def_path(cx, did, &paths::SLICE_FROM_RAW_PARTS_MUT) { + Some(RawPartsKind::Mutable) + } else { + None + } +} + +pub(super) fn check( + cx: &LateContext<'_>, + expr: &Expr<'_>, + cast_expr: &Expr<'_>, + cast_to: Ty<'_>, + msrv: Option, +) { + if_chain! { + if meets_msrv(msrv, msrvs::PTR_SLICE_RAW_PARTS); + if let ty::RawPtr(ptrty) = cast_to.kind(); + if let ty::Slice(_) = ptrty.ty.kind(); + if let ExprKind::Call(fun, [ptr_arg, len_arg]) = cast_expr.peel_blocks().kind; + if let ExprKind::Path(ref qpath) = fun.kind; + if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id(); + if let Some(rpk) = raw_parts_kind(cx, fun_def_id); + then { + let func = match rpk { + RawPartsKind::Immutable => "from_raw_parts", + RawPartsKind::Mutable => "from_raw_parts_mut" + }; + let span = expr.span; + let mut applicability = Applicability::MachineApplicable; + let ptr = snippet_with_applicability(cx, ptr_arg.span, "ptr", &mut applicability); + let len = snippet_with_applicability(cx, len_arg.span, "len", &mut applicability); + span_lint_and_sugg( + cx, + CAST_SLICE_FROM_RAW_PARTS, + span, + &format!("casting the result of `{func}` to {cast_to}"), + "replace with", + format!("core::ptr::slice_{func}({ptr}, {len})"), + applicability + ); + } + } +} diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index af3798a0cc8c..cc5d346b954e 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -1,3 +1,5 @@ +mod as_underscore; +mod borrow_as_ptr; mod cast_abs_to_unsigned; mod cast_enum_constructor; mod cast_lossless; @@ -8,6 +10,7 @@ mod cast_ptr_alignment; mod cast_ref_to_mut; mod cast_sign_loss; mod cast_slice_different_sizes; +mod cast_slice_from_raw_parts; mod char_lit_as_u8; mod fn_to_numeric_cast; mod fn_to_numeric_cast_any; @@ -16,7 +19,7 @@ mod ptr_as_ptr; mod unnecessary_cast; mod utils; -use clippy_utils::is_hir_ty_cfg_dependant; +use clippy_utils::{is_hir_ty_cfg_dependant, meets_msrv, msrvs}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; @@ -506,6 +509,93 @@ declare_clippy_lint! { "casting the result of `abs()` to an unsigned integer can panic" } +declare_clippy_lint! { + /// ### What it does + /// Check for the usage of `as _` conversion using inferred type. + /// + /// ### Why is this bad? + /// The conversion might include lossy conversion and dangerous cast that might go + /// undetected due to the type being inferred. + /// + /// The lint is allowed by default as using `_` is less wordy than always specifying the type. + /// + /// ### Example + /// ```rust + /// fn foo(n: usize) {} + /// let n: u16 = 256; + /// foo(n as _); + /// ``` + /// Use instead: + /// ```rust + /// fn foo(n: usize) {} + /// let n: u16 = 256; + /// foo(n as usize); + /// ``` + #[clippy::version = "1.63.0"] + pub AS_UNDERSCORE, + restriction, + "detects `as _` conversion" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for the usage of `&expr as *const T` or + /// `&mut expr as *mut T`, and suggest using `ptr::addr_of` or + /// `ptr::addr_of_mut` instead. + /// + /// ### Why is this bad? + /// This would improve readability and avoid creating a reference + /// that points to an uninitialized value or unaligned place. + /// Read the `ptr::addr_of` docs for more information. + /// + /// ### Example + /// ```rust + /// let val = 1; + /// let p = &val as *const i32; + /// + /// let mut val_mut = 1; + /// let p_mut = &mut val_mut as *mut i32; + /// ``` + /// Use instead: + /// ```rust + /// let val = 1; + /// let p = std::ptr::addr_of!(val); + /// + /// let mut val_mut = 1; + /// let p_mut = std::ptr::addr_of_mut!(val_mut); + /// ``` + #[clippy::version = "1.60.0"] + pub BORROW_AS_PTR, + pedantic, + "borrowing just to cast to a raw pointer" +} +declare_clippy_lint! { + /// ### What it does + /// Checks for a raw slice being cast to a slice pointer + /// + /// ### Why is this bad? + /// This can result in multiple `&mut` references to the same location when only a pointer is + /// required. + /// `ptr::slice_from_raw_parts` is a safe alternative that doesn't require + /// the same [safety requirements] to be upheld. + /// + /// ### Example + /// ```rust,ignore + /// let _: *const [u8] = std::slice::from_raw_parts(ptr, len) as *const _; + /// let _: *mut [u8] = std::slice::from_raw_parts_mut(ptr, len) as *mut _; + /// ``` + /// Use instead: + /// ```rust,ignore + /// let _: *const [u8] = std::ptr::slice_from_raw_parts(ptr, len); + /// let _: *mut [u8] = std::ptr::slice_from_raw_parts_mut(ptr, len); + /// ``` + /// [safety requirements]: https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html#safety + #[clippy::version = "1.64.0"] + pub CAST_SLICE_FROM_RAW_PARTS, + suspicious, + "casting a slice created from a pointer and length to a slice pointer" +} + pub struct Casts { msrv: Option, } @@ -534,7 +624,10 @@ impl_lint_pass!(Casts => [ PTR_AS_PTR, CAST_ENUM_TRUNCATION, CAST_ENUM_CONSTRUCTOR, - CAST_ABS_TO_UNSIGNED + CAST_ABS_TO_UNSIGNED, + AS_UNDERSCORE, + BORROW_AS_PTR, + CAST_SLICE_FROM_RAW_PARTS ]); impl<'tcx> LateLintPass<'tcx> for Casts { @@ -547,8 +640,8 @@ impl<'tcx> LateLintPass<'tcx> for Casts { return; } - if let ExprKind::Cast(cast_expr, cast_to) = expr.kind { - if is_hir_ty_cfg_dependant(cx, cast_to) { + if let ExprKind::Cast(cast_expr, cast_to_hir) = expr.kind { + if is_hir_ty_cfg_dependant(cx, cast_to_hir) { return; } let (cast_from, cast_to) = ( @@ -559,7 +652,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts { if unnecessary_cast::check(cx, expr, cast_expr, cast_from, cast_to) { return; } - + cast_slice_from_raw_parts::check(cx, expr, cast_expr, cast_to, self.msrv); fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, cast_to); fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to); fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to); @@ -575,6 +668,12 @@ impl<'tcx> LateLintPass<'tcx> for Casts { cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, self.msrv); cast_enum_constructor::check(cx, expr, cast_expr, cast_from); } + + as_underscore::check(cx, expr, cast_to_hir); + + if meets_msrv(self.msrv, msrvs::BORROW_AS_PTR) { + borrow_as_ptr::check(cx, expr, cast_expr, cast_to_hir); + } } cast_ref_to_mut::check(cx, expr); diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs index fff7da8e33f2..19d2e6e1d129 100644 --- a/clippy_lints/src/casts/unnecessary_cast.rs +++ b/clippy_lints/src/casts/unnecessary_cast.rs @@ -90,13 +90,20 @@ pub(super) fn check<'tcx>( fn lint_unnecessary_cast(cx: &LateContext<'_>, expr: &Expr<'_>, literal_str: &str, cast_from: Ty<'_>, cast_to: Ty<'_>) { let literal_kind_name = if cast_from.is_integral() { "integer" } else { "float" }; + let replaced_literal; + let matchless = if literal_str.contains(['(', ')']) { + replaced_literal = literal_str.replace(['(', ')'], ""); + &replaced_literal + } else { + literal_str + }; span_lint_and_sugg( cx, UNNECESSARY_CAST, expr.span, &format!("casting {} literal to `{}` is unnecessary", literal_kind_name, cast_to), "try", - format!("{}_{}", literal_str.trim_end_matches('.'), cast_to), + format!("{}_{}", matchless.trim_end_matches('.'), cast_to), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 59f10247a11d..1506ea604f0d 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1,24 +1,34 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; -use clippy_utils::ty::{expr_sig, peel_mid_ty_refs, ty_sig, variant_of_res}; -use clippy_utils::{get_parent_expr, get_parent_expr_for_hir, is_lint_allowed, path_to_local, walk_to_expr_usage}; +use clippy_utils::ty::{expr_sig, is_copy, peel_mid_ty_refs, ty_sig, variant_of_res}; +use clippy_utils::{ + fn_def_id, get_parent_expr, get_parent_expr_for_hir, is_lint_allowed, meets_msrv, msrvs, path_to_local, + walk_to_expr_usage, +}; use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX}; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_ty, Visitor}; use rustc_hir::{ - self as hir, BindingAnnotation, Body, BodyId, BorrowKind, Closure, Expr, ExprKind, FnRetTy, GenericArg, HirId, - ImplItem, ImplItemKind, Item, ItemKind, Local, MatchSource, Mutability, Node, Pat, PatKind, Path, QPath, TraitItem, - TraitItemKind, TyKind, UnOp, + self as hir, def_id::DefId, BindingAnnotation, Body, BodyId, BorrowKind, Closure, Expr, ExprKind, FnRetTy, + GenericArg, HirId, ImplItem, ImplItemKind, Item, ItemKind, Local, MatchSource, Mutability, Node, Pat, PatKind, + Path, QPath, TraitItem, TraitItemKind, TyKind, UnOp, }; +use rustc_index::bit_set::BitSet; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; -use rustc_middle::ty::{self, Binder, BoundVariableKind, List, Ty, TyCtxt, TypeVisitable, TypeckResults}; +use rustc_middle::ty::{ + self, subst::Subst, Binder, BoundVariableKind, EarlyBinder, FnSig, GenericArgKind, List, ParamTy, PredicateKind, + ProjectionPredicate, Ty, TyCtxt, TypeVisitable, TypeckResults, +}; +use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP}; -use rustc_trait_selection::infer::InferCtxtExt; +use rustc_trait_selection::infer::InferCtxtExt as _; +use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause}; +use std::collections::VecDeque; declare_clippy_lint! { /// ### What it does @@ -151,6 +161,7 @@ pub struct Dereferencing { /// been finished. Note we can't lint at the end of every body as they can be nested within each /// other. current_body: Option, + /// The list of locals currently being checked by the lint. /// If the value is `None`, then the binding has been seen as a ref pattern, but is not linted. /// This is needed for or patterns where one of the branches can be linted, but another can not @@ -158,6 +169,19 @@ pub struct Dereferencing { /// /// e.g. `m!(x) | Foo::Bar(ref x)` ref_locals: FxIndexMap>, + + // `IntoIterator` for arrays requires Rust 1.53. + msrv: Option, +} + +impl Dereferencing { + #[must_use] + pub fn new(msrv: Option) -> Self { + Self { + msrv, + ..Dereferencing::default() + } + } } struct StateData { @@ -170,6 +194,7 @@ struct StateData { struct DerefedBorrow { count: usize, msg: &'static str, + snip_expr: Option, } enum State { @@ -250,7 +275,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { match (self.state.take(), kind) { (None, kind) => { let expr_ty = typeck.expr_ty(expr); - let (position, adjustments) = walk_parents(cx, expr); + let (position, adjustments) = walk_parents(cx, expr, self.msrv); match kind { RefOp::Deref => { @@ -331,20 +356,23 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { let deref_msg = "this expression creates a reference which is immediately dereferenced by the compiler"; let borrow_msg = "this expression borrows a value the compiler would automatically borrow"; + let impl_msg = "the borrowed expression implements the required traits"; - let (required_refs, msg) = if position.can_auto_borrow() { - (1, if deref_count == 1 { borrow_msg } else { deref_msg }) + let (required_refs, msg, snip_expr) = if position.can_auto_borrow() { + (1, if deref_count == 1 { borrow_msg } else { deref_msg }, None) + } else if let Position::ImplArg(hir_id) = position { + (0, impl_msg, Some(hir_id)) } else if let Some(&Adjust::Borrow(AutoBorrow::Ref(_, mutability))) = next_adjust.map(|a| &a.kind) { if matches!(mutability, AutoBorrowMutability::Mut { .. }) && !position.is_reborrow_stable() { - (3, deref_msg) + (3, deref_msg, None) } else { - (2, deref_msg) + (2, deref_msg, None) } } else { - (2, deref_msg) + (2, deref_msg, None) }; if deref_count >= required_refs { @@ -354,6 +382,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { // can't be removed without breaking the code. See earlier comment. count: deref_count - required_refs, msg, + snip_expr, }), StateData { span: expr.span, hir_id: expr.hir_id, position }, )); @@ -510,7 +539,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { spans: vec![pat.span], app, replacements: vec![(pat.span, snip.into())], - hir_id: pat.hir_id + hir_id: pat.hir_id, }), ); } @@ -542,6 +571,8 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { self.current_body = None; } } + + extract_msrv_attr!(LateContext); } fn try_parse_ref_op<'tcx>( @@ -594,6 +625,7 @@ enum Position { /// The method is defined on a reference type. e.g. `impl Foo for &T` MethodReceiverRefImpl, Callee, + ImplArg(HirId), FieldAccess(Symbol), Postfix, Deref, @@ -630,7 +662,7 @@ impl Position { | Self::Callee | Self::FieldAccess(_) | Self::Postfix => PREC_POSTFIX, - Self::Deref => PREC_PREFIX, + Self::ImplArg(_) | Self::Deref => PREC_PREFIX, Self::DerefStable(p, _) | Self::ReborrowStable(p) | Self::Other(p) => p, } } @@ -639,8 +671,12 @@ impl Position { /// Walks up the parent expressions attempting to determine both how stable the auto-deref result /// is, and which adjustments will be applied to it. Note this will not consider auto-borrow /// locations as those follow different rules. -#[allow(clippy::too_many_lines)] -fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &'tcx [Adjustment<'tcx>]) { +#[expect(clippy::too_many_lines)] +fn walk_parents<'tcx>( + cx: &LateContext<'tcx>, + e: &'tcx Expr<'_>, + msrv: Option, +) -> (Position, &'tcx [Adjustment<'tcx>]) { let mut adjustments = [].as_slice(); let mut precedence = 0i8; let ctxt = e.span.ctxt(); @@ -745,13 +781,20 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & .iter() .position(|arg| arg.hir_id == child_id) .zip(expr_sig(cx, func)) - .and_then(|(i, sig)| sig.input_with_hir(i)) - .map(|(hir_ty, ty)| match hir_ty { - // Type inference for closures can depend on how they're called. Only go by the explicit - // types here. - Some(hir_ty) => binding_ty_auto_deref_stability(cx, hir_ty, precedence, ty.bound_vars()), - None => ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence) - .position_for_arg(), + .and_then(|(i, sig)| { + sig.input_with_hir(i).map(|(hir_ty, ty)| match hir_ty { + // Type inference for closures can depend on how they're called. Only go by the explicit + // types here. + Some(hir_ty) => binding_ty_auto_deref_stability(cx, hir_ty, precedence, ty.bound_vars()), + None => { + if let ty::Param(param_ty) = ty.skip_binder().kind() { + needless_borrow_impl_arg_position(cx, parent, i, *param_ty, e, precedence, msrv) + } else { + ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence) + .position_for_arg() + } + }, + }) }), ExprKind::MethodCall(_, args, _) => { let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap(); @@ -773,7 +816,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & .and_then(|subs| subs.get(1..)) { Some(subs) => cx.tcx.mk_substs(subs.iter().copied()), - None => cx.tcx.mk_substs([].iter()), + None => cx.tcx.mk_substs(std::iter::empty::>()), } && let impl_ty = if cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref() { // Trait methods taking `&self` sub_ty @@ -792,12 +835,17 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & Position::MethodReceiver } } else { - ty_auto_deref_stability( - cx, - cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)), - precedence, - ) - .position_for_arg() + let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i]; + if let ty::Param(param_ty) = ty.kind() { + needless_borrow_impl_arg_position(cx, parent, i, *param_ty, e, precedence, msrv) + } else { + ty_auto_deref_stability( + cx, + cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)), + precedence, + ) + .position_for_arg() + } } }) }, @@ -948,6 +996,205 @@ fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool { v.0 } +// Checks whether: +// * child is an expression of the form `&e` in an argument position requiring an `impl Trait` +// * `e`'s type implements `Trait` and is copyable +// If the conditions are met, returns `Some(Position::ImplArg(..))`; otherwise, returns `None`. +// The "is copyable" condition is to avoid the case where removing the `&` means `e` would have to +// be moved, but it cannot be. +fn needless_borrow_impl_arg_position<'tcx>( + cx: &LateContext<'tcx>, + parent: &Expr<'tcx>, + arg_index: usize, + param_ty: ParamTy, + mut expr: &Expr<'tcx>, + precedence: i8, + msrv: Option, +) -> Position { + let destruct_trait_def_id = cx.tcx.lang_items().destruct_trait(); + let sized_trait_def_id = cx.tcx.lang_items().sized_trait(); + + let Some(callee_def_id) = fn_def_id(cx, parent) else { return Position::Other(precedence) }; + let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder(); + let substs_with_expr_ty = cx + .typeck_results() + .node_substs(if let ExprKind::Call(callee, _) = parent.kind { + callee.hir_id + } else { + parent.hir_id + }); + + let predicates = cx.tcx.param_env(callee_def_id).caller_bounds(); + let projection_predicates = predicates + .iter() + .filter_map(|predicate| { + if let PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() { + Some(projection_predicate) + } else { + None + } + }) + .collect::>(); + + let mut trait_with_ref_mut_self_method = false; + + // If no traits were found, or only the `Destruct`, `Sized`, or `Any` traits were found, return. + if predicates + .iter() + .filter_map(|predicate| { + if let PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder() + && trait_predicate.trait_ref.self_ty() == param_ty.to_ty(cx.tcx) + { + Some(trait_predicate.trait_ref.def_id) + } else { + None + } + }) + .inspect(|trait_def_id| { + trait_with_ref_mut_self_method |= has_ref_mut_self_method(cx, *trait_def_id); + }) + .all(|trait_def_id| { + Some(trait_def_id) == destruct_trait_def_id + || Some(trait_def_id) == sized_trait_def_id + || cx.tcx.is_diagnostic_item(sym::Any, trait_def_id) + }) + { + return Position::Other(precedence); + } + + // `substs_with_referent_ty` can be constructed outside of `check_referent` because the same + // elements are modified each time `check_referent` is called. + let mut substs_with_referent_ty = substs_with_expr_ty.to_vec(); + + let mut check_referent = |referent| { + let referent_ty = cx.typeck_results().expr_ty(referent); + + if !is_copy(cx, referent_ty) { + return false; + } + + // https://github.com/rust-lang/rust-clippy/pull/9136#pullrequestreview-1037379321 + if trait_with_ref_mut_self_method && !matches!(referent_ty.kind(), ty::Ref(_, _, Mutability::Mut)) { + return false; + } + + if !replace_types( + cx, + param_ty, + referent_ty, + fn_sig, + arg_index, + &projection_predicates, + &mut substs_with_referent_ty, + ) { + return false; + } + + predicates.iter().all(|predicate| { + if let PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder() + && cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_predicate.trait_ref.def_id) + && let ty::Param(param_ty) = trait_predicate.self_ty().kind() + && let GenericArgKind::Type(ty) = substs_with_referent_ty[param_ty.index as usize].unpack() + && ty.is_array() + && !meets_msrv(msrv, msrvs::ARRAY_INTO_ITERATOR) + { + return false; + } + + let predicate = EarlyBinder(predicate).subst(cx.tcx, &substs_with_referent_ty); + let obligation = Obligation::new(ObligationCause::dummy(), cx.param_env, predicate); + cx.tcx + .infer_ctxt() + .enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation)) + }) + }; + + let mut needless_borrow = false; + while let ExprKind::AddrOf(_, _, referent) = expr.kind { + if !check_referent(referent) { + break; + } + expr = referent; + needless_borrow = true; + } + + if needless_borrow { + Position::ImplArg(expr.hir_id) + } else { + Position::Other(precedence) + } +} + +fn has_ref_mut_self_method(cx: &LateContext<'_>, trait_def_id: DefId) -> bool { + cx.tcx + .associated_items(trait_def_id) + .in_definition_order() + .any(|assoc_item| { + if assoc_item.fn_has_self_parameter { + let self_ty = cx.tcx.fn_sig(assoc_item.def_id).skip_binder().inputs()[0]; + matches!(self_ty.kind(), ty::Ref(_, _, Mutability::Mut)) + } else { + false + } + }) +} + +// Iteratively replaces `param_ty` with `new_ty` in `substs`, and similarly for each resulting +// projected type that is a type parameter. Returns `false` if replacing the types would have an +// effect on the function signature beyond substituting `new_ty` for `param_ty`. +// See: https://github.com/rust-lang/rust-clippy/pull/9136#discussion_r927212757 +fn replace_types<'tcx>( + cx: &LateContext<'tcx>, + param_ty: ParamTy, + new_ty: Ty<'tcx>, + fn_sig: FnSig<'tcx>, + arg_index: usize, + projection_predicates: &[ProjectionPredicate<'tcx>], + substs: &mut [ty::GenericArg<'tcx>], +) -> bool { + let mut replaced = BitSet::new_empty(substs.len()); + + let mut deque = VecDeque::with_capacity(substs.len()); + deque.push_back((param_ty, new_ty)); + + while let Some((param_ty, new_ty)) = deque.pop_front() { + // If `replaced.is_empty()`, then `param_ty` and `new_ty` are those initially passed in. + if !fn_sig + .inputs_and_output + .iter() + .enumerate() + .all(|(i, ty)| (replaced.is_empty() && i == arg_index) || !ty.contains(param_ty.to_ty(cx.tcx))) + { + return false; + } + + substs[param_ty.index as usize] = ty::GenericArg::from(new_ty); + + // The `replaced.insert(...)` check provides some protection against infinite loops. + if replaced.insert(param_ty.index) { + for projection_predicate in projection_predicates { + if projection_predicate.projection_ty.self_ty() == param_ty.to_ty(cx.tcx) + && let ty::Term::Ty(term_ty) = projection_predicate.term + && let ty::Param(term_param_ty) = term_ty.kind() + { + let item_def_id = projection_predicate.projection_ty.item_def_id; + let assoc_item = cx.tcx.associated_item(item_def_id); + let projection = cx.tcx + .mk_projection(assoc_item.def_id, cx.tcx.mk_substs_trait(new_ty, &[])); + + if let Ok(projected_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, projection) + && substs[term_param_ty.index as usize] != ty::GenericArg::from(projected_ty) + { + deque.push_back((*term_param_ty, projected_ty)); + } + } + } + } + } + + true +} + struct TyPosition<'tcx> { position: Position, ty: Option>, @@ -1086,7 +1333,8 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data }, State::DerefedBorrow(state) => { let mut app = Applicability::MachineApplicable; - let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app); + let snip_expr = state.snip_expr.map_or(expr, |hir_id| cx.tcx.hir().expect_expr(hir_id)); + let (snip, snip_is_macro) = snippet_with_context(cx, snip_expr.span, data.span.ctxt(), "..", &mut app); span_lint_hir_and_then(cx, NEEDLESS_BORROW, data.hir_id, data.span, state.msg, |diag| { let calls_field = matches!(expr.kind, ExprKind::Field(..)) && matches!(data.position, Position::Callee); let sugg = if !snip_is_macro diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs index a982990e4186..9ca443b7dff6 100644 --- a/clippy_lints/src/derive.rs +++ b/clippy_lints/src/derive.rs @@ -516,7 +516,10 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> tcx.mk_predicates(ty_predicates.iter().map(|&(p, _)| p).chain( params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| { tcx.mk_predicate(Binder::dummy(PredicateKind::Trait(TraitPredicate { - trait_ref: TraitRef::new(eq_trait_id, tcx.mk_substs([tcx.mk_param_from_def(param)].into_iter())), + trait_ref: TraitRef::new( + eq_trait_id, + tcx.mk_substs(std::iter::once(tcx.mk_param_from_def(param))), + ), constness: BoundConstness::NotConst, polarity: ImplPolarity::Positive, }))) diff --git a/clippy_lints/src/doc_link_with_quotes.rs b/clippy_lints/src/doc_link_with_quotes.rs index cb07f57e8700..0ff1d2755daf 100644 --- a/clippy_lints/src/doc_link_with_quotes.rs +++ b/clippy_lints/src/doc_link_with_quotes.rs @@ -21,7 +21,7 @@ declare_clippy_lint! { /// /// See also: [`foo`] /// fn bar() {} /// ``` - #[clippy::version = "1.60.0"] + #[clippy::version = "1.63.0"] pub DOC_LINK_WITH_QUOTES, pedantic, "possible typo for an intra-doc link" diff --git a/clippy_lints/src/duplicate_mod.rs b/clippy_lints/src/duplicate_mod.rs index e1eb3b6324c7..7ff7068f0b05 100644 --- a/clippy_lints/src/duplicate_mod.rs +++ b/clippy_lints/src/duplicate_mod.rs @@ -39,7 +39,7 @@ declare_clippy_lint! { /// // a.rs /// use crate::b; /// ``` - #[clippy::version = "1.62.0"] + #[clippy::version = "1.63.0"] pub DUPLICATE_MOD, suspicious, "file loaded as module multiple times" diff --git a/clippy_lints/src/escape.rs b/clippy_lints/src/escape.rs index 1ac7bfba06ba..327865e4c858 100644 --- a/clippy_lints/src/escape.rs +++ b/clippy_lints/src/escape.rs @@ -1,5 +1,4 @@ use clippy_utils::diagnostics::span_lint_hir; -use clippy_utils::ty::contains_ty; use rustc_hir::intravisit; use rustc_hir::{self, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node, Pat, PatKind}; use rustc_infer::infer::TyCtxtInferExt; @@ -30,18 +29,12 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// # fn foo(bar: usize) {} - /// let x = Box::new(1); - /// foo(*x); - /// println!("{}", *x); + /// fn foo(x: Box) {} /// ``` /// /// Use instead: /// ```rust - /// # fn foo(bar: usize) {} - /// let x = 1; - /// foo(x); - /// println!("{}", x); + /// fn foo(x: u32) {} /// ``` #[clippy::version = "pre 1.29.0"] pub BOXED_LOCAL, @@ -172,7 +165,7 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> { // skip if there is a `self` parameter binding to a type // that contains `Self` (i.e.: `self: Box`), see #4804 if let Some(trait_self_ty) = self.trait_self_ty { - if map.name(cmt.hir_id) == kw::SelfLower && contains_ty(cmt.place.ty(), trait_self_ty) { + if map.name(cmt.hir_id) == kw::SelfLower && cmt.place.ty().contains(trait_self_ty) { return; } } diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index df9b41d2c98b..bb50e8fcabbb 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -172,7 +172,7 @@ fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { expr.span, "logarithm for bases 2, 10 and e can be computed more accurately", "consider using", - format!("{}.{}()", Sugg::hir(cx, &args[0], ".."), method), + format!("{}.{}()", Sugg::hir(cx, &args[0], "..").maybe_par(), method), Applicability::MachineApplicable, ); } @@ -263,13 +263,13 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { ( SUBOPTIMAL_FLOPS, "square-root of a number can be computed more efficiently and accurately", - format!("{}.sqrt()", Sugg::hir(cx, &args[0], "..")), + format!("{}.sqrt()", Sugg::hir(cx, &args[0], "..").maybe_par()), ) } else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value { ( IMPRECISE_FLOPS, "cube-root of a number can be computed more accurately", - format!("{}.cbrt()", Sugg::hir(cx, &args[0], "..")), + format!("{}.cbrt()", Sugg::hir(cx, &args[0], "..").maybe_par()), ) } else if let Some(exponent) = get_integer_from_float_constant(&value) { ( @@ -277,7 +277,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { "exponentiation with integer powers can be computed more efficiently", format!( "{}.powi({})", - Sugg::hir(cx, &args[0], ".."), + Sugg::hir(cx, &args[0], "..").maybe_par(), numeric_literal::format(&exponent.to_string(), None, false) ), ) @@ -327,7 +327,7 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { "consider using", format!( "{}.mul_add({}, {})", - Sugg::hir(cx, &args[0], ".."), + Sugg::hir(cx, &args[0], "..").maybe_par(), Sugg::hir(cx, &args[0], ".."), Sugg::hir(cx, other_addend, ".."), ), @@ -418,7 +418,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) { "consider using", format!( "{}.exp_m1()", - Sugg::hir(cx, self_arg, "..") + Sugg::hir(cx, self_arg, "..").maybe_par() ), Applicability::MachineApplicable, ); @@ -550,11 +550,11 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) { then { let positive_abs_sugg = ( "manual implementation of `abs` method", - format!("{}.abs()", Sugg::hir(cx, body, "..")), + format!("{}.abs()", Sugg::hir(cx, body, "..").maybe_par()), ); let negative_abs_sugg = ( "manual implementation of negation of `abs` method", - format!("-{}.abs()", Sugg::hir(cx, body, "..")), + format!("-{}.abs()", Sugg::hir(cx, body, "..").maybe_par()), ); let sugg = if is_testing_positive(cx, cond, body) { if if_expr_positive { @@ -621,7 +621,7 @@ fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) { expr.span, "log base can be expressed more clearly", "consider using", - format!("{}.log({})", Sugg::hir(cx, largs_self, ".."), Sugg::hir(cx, rargs_self, ".."),), + format!("{}.log({})", Sugg::hir(cx, largs_self, "..").maybe_par(), Sugg::hir(cx, rargs_self, ".."),), Applicability::MachineApplicable, ); } @@ -651,7 +651,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue) && (F32(180_f32) == lvalue || F64(180_f64) == lvalue) { - let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..")); + let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..").maybe_par()); if_chain! { if let ExprKind::Lit(ref literal) = mul_lhs.kind; if let ast::LitKind::Float(ref value, float_type) = literal.node; @@ -677,7 +677,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { (F32(180_f32) == rvalue || F64(180_f64) == rvalue) && (F32(f32_consts::PI) == lvalue || F64(f64_consts::PI) == lvalue) { - let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..")); + let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..").maybe_par()); if_chain! { if let ExprKind::Lit(ref literal) = mul_lhs.kind; if let ast::LitKind::Float(ref value, float_type) = literal.node; diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 925a8cb8deed..0c5851cdbed2 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn}; -use clippy_utils::source::{snippet_opt, snippet_with_applicability}; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use if_chain::if_chain; use rustc_errors::Applicability; @@ -56,29 +56,27 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { }; let mut applicability = Applicability::MachineApplicable; - if format_args.value_args.is_empty() { - match *format_args.format_string_parts { + if format_args.args.is_empty() { + match *format_args.format_string.parts { [] => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability), [_] => { - if let Some(s_src) = snippet_opt(cx, format_args.format_string_span) { - // Simulate macro expansion, converting {{ and }} to { and }. - let s_expand = s_src.replace("{{", "{").replace("}}", "}"); - let sugg = format!("{}.to_string()", s_expand); - span_useless_format(cx, call_site, sugg, applicability); - } + // Simulate macro expansion, converting {{ and }} to { and }. + let s_expand = format_args.format_string.snippet.replace("{{", "{").replace("}}", "}"); + let sugg = format!("{}.to_string()", s_expand); + span_useless_format(cx, call_site, sugg, applicability); }, [..] => {}, } - } else if let [value] = *format_args.value_args { + } else if let [arg] = &*format_args.args { + let value = arg.param.value; if_chain! { - if format_args.format_string_parts == [kw::Empty]; + if format_args.format_string.parts == [kw::Empty]; if match cx.typeck_results().expr_ty(value).peel_refs().kind() { ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(sym::String, adt.did()), ty::Str => true, _ => false, }; - if let Some(args) = format_args.args(); - if args.iter().all(|arg| arg.format_trait == sym::Display && !arg.has_string_formatting()); + if !arg.format.has_string_formatting(); then { let is_new_string = match value.kind { ExprKind::Binary(..) => true, diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 1e6feaac26c3..9fb9fd99748b 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -1,11 +1,12 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::is_diag_trait_item; -use clippy_utils::macros::{is_format_macro, FormatArgsArg, FormatArgsExpn}; +use clippy_utils::macros::{is_format_macro, FormatArgsExpn}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; use if_chain::if_chain; +use itertools::Itertools; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, HirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_middle::ty::Ty; @@ -74,20 +75,16 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs { if let Some(macro_def_id) = outermost_expn_data.macro_def_id; if is_format_macro(cx, macro_def_id); if let ExpnKind::Macro(_, name) = outermost_expn_data.kind; - if let Some(args) = format_args.args(); then { - for (i, arg) in args.iter().enumerate() { - if arg.format_trait != sym::Display { + for arg in &format_args.args { + if arg.format.has_string_formatting() { continue; } - if arg.has_string_formatting() { + if is_aliased(&format_args, arg.param.value.hir_id) { continue; } - if is_aliased(&args, i) { - continue; - } - check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg.value); - check_to_string_in_format_args(cx, name, arg.value); + check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg.param.value); + check_to_string_in_format_args(cx, name, arg.param.value); } } } @@ -134,45 +131,56 @@ fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Ex if is_diag_trait_item(cx, method_def_id, sym::ToString); let receiver_ty = cx.typeck_results().expr_ty(receiver); if let Some(display_trait_id) = cx.tcx.get_diagnostic_item(sym::Display); + let (n_needed_derefs, target) = + count_needed_derefs(receiver_ty, cx.typeck_results().expr_adjustments(receiver).iter()); + if implements_trait(cx, target, display_trait_id, &[]); + if let Some(sized_trait_id) = cx.tcx.lang_items().sized_trait(); if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); then { - let (n_needed_derefs, target) = count_needed_derefs( - receiver_ty, - cx.typeck_results().expr_adjustments(receiver).iter(), - ); - if implements_trait(cx, target, display_trait_id, &[]) { - if n_needed_derefs == 0 { - span_lint_and_sugg( - cx, - TO_STRING_IN_FORMAT_ARGS, - value.span.with_lo(receiver.span.hi()), - &format!("`to_string` applied to a type that implements `Display` in `{}!` args", name), - "remove this", - String::new(), - Applicability::MachineApplicable, - ); - } else { - span_lint_and_sugg( - cx, - TO_STRING_IN_FORMAT_ARGS, - value.span, - &format!("`to_string` applied to a type that implements `Display` in `{}!` args", name), - "use this", - format!("{:*>width$}{}", "", receiver_snippet, width = n_needed_derefs), - Applicability::MachineApplicable, - ); - } + let needs_ref = !implements_trait(cx, receiver_ty, sized_trait_id, &[]); + if n_needed_derefs == 0 && !needs_ref { + span_lint_and_sugg( + cx, + TO_STRING_IN_FORMAT_ARGS, + value.span.with_lo(receiver.span.hi()), + &format!( + "`to_string` applied to a type that implements `Display` in `{}!` args", + name + ), + "remove this", + String::new(), + Applicability::MachineApplicable, + ); + } else { + span_lint_and_sugg( + cx, + TO_STRING_IN_FORMAT_ARGS, + value.span, + &format!( + "`to_string` applied to a type that implements `Display` in `{}!` args", + name + ), + "use this", + format!( + "{}{:*>width$}{}", + if needs_ref { "&" } else { "" }, + "", + receiver_snippet, + width = n_needed_derefs + ), + Applicability::MachineApplicable, + ); } } } } -// Returns true if `args[i]` "refers to" or "is referred to by" another argument. -fn is_aliased(args: &[FormatArgsArg<'_>], i: usize) -> bool { - let value = args[i].value; - args.iter() - .enumerate() - .any(|(j, arg)| i != j && std::ptr::eq(value, arg.value)) +// Returns true if `hir_id` is referred to by multiple format params +fn is_aliased(args: &FormatArgsExpn<'_>, hir_id: HirId) -> bool { + args.params() + .filter(|param| param.value.hir_id == hir_id) + .at_most_one() + .is_err() } fn count_needed_derefs<'tcx, I>(mut ty: Ty<'tcx>, mut iter: I) -> (usize, Ty<'tcx>) diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index 04b5be6c80ec..d8bc0bf08f2b 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; -use clippy_utils::macros::{is_format_macro, root_macro_call_first_node, FormatArgsArg, FormatArgsExpn}; +use clippy_utils::macros::{is_format_macro, root_macro_call_first_node, FormatArg, FormatArgsExpn}; use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators}; use if_chain::if_chain; use rustc_errors::Applicability; @@ -168,10 +168,9 @@ fn check_self_in_format_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, if let macro_def_id = outer_macro.def_id; if let Some(format_args) = FormatArgsExpn::find_nested(cx, expr, outer_macro.expn); if is_format_macro(cx, macro_def_id); - if let Some(args) = format_args.args(); then { - for arg in args { - if arg.format_trait != impl_trait.name { + for arg in format_args.args { + if arg.format.r#trait != impl_trait.name { continue; } check_format_arg_self(cx, expr, &arg, impl_trait); @@ -180,11 +179,11 @@ fn check_self_in_format_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, } } -fn check_format_arg_self(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &FormatArgsArg<'_>, impl_trait: FormatTrait) { +fn check_format_arg_self(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &FormatArg<'_>, impl_trait: FormatTrait) { // Handle multiple dereferencing of references e.g. &&self // Handle dereference of &self -> self that is equivalent (i.e. via *self in fmt() impl) // Since the argument to fmt is itself a reference: &self - let reference = peel_ref_operators(cx, arg.value); + let reference = peel_ref_operators(cx, arg.param.value); let map = cx.tcx.hir(); // Is the reference self? if path_to_local(reference).map(|x| map.name(x)) == Some(kw::SelfLower) { diff --git a/clippy_lints/src/functions/mod.rs b/clippy_lints/src/functions/mod.rs index 73261fb8a44c..90911e0bf259 100644 --- a/clippy_lints/src/functions/mod.rs +++ b/clippy_lints/src/functions/mod.rs @@ -1,6 +1,6 @@ mod must_use; mod not_unsafe_ptr_arg_deref; -mod result_unit_err; +mod result; mod too_many_arguments; mod too_many_lines; @@ -217,17 +217,62 @@ declare_clippy_lint! { "public function returning `Result` with an `Err` type of `()`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for functions that return `Result` with an unusually large + /// `Err`-variant. + /// + /// ### Why is this bad? + /// A `Result` is at least as large as the `Err`-variant. While we + /// expect that variant to be seldomly used, the compiler needs to reserve + /// and move that much memory every single time. + /// + /// ### Known problems + /// The size determined by Clippy is platform-dependent. + /// + /// ### Examples + /// ```rust + /// pub enum ParseError { + /// UnparsedBytes([u8; 512]), + /// UnexpectedEof, + /// } + /// + /// // The `Result` has at least 512 bytes, even in the `Ok`-case + /// pub fn parse() -> Result<(), ParseError> { + /// Ok(()) + /// } + /// ``` + /// should be + /// ``` + /// pub enum ParseError { + /// UnparsedBytes(Box<[u8; 512]>), + /// UnexpectedEof, + /// } + /// + /// // The `Result` is slightly larger than a pointer + /// pub fn parse() -> Result<(), ParseError> { + /// Ok(()) + /// } + /// ``` + #[clippy::version = "1.64.0"] + pub RESULT_LARGE_ERR, + perf, + "function returning `Result` with large `Err` type" +} + #[derive(Copy, Clone)] pub struct Functions { too_many_arguments_threshold: u64, too_many_lines_threshold: u64, + large_error_threshold: u64, } impl Functions { - pub fn new(too_many_arguments_threshold: u64, too_many_lines_threshold: u64) -> Self { + pub fn new(too_many_arguments_threshold: u64, too_many_lines_threshold: u64, large_error_threshold: u64) -> Self { Self { too_many_arguments_threshold, too_many_lines_threshold, + large_error_threshold, } } } @@ -240,6 +285,7 @@ impl_lint_pass!(Functions => [ DOUBLE_MUST_USE, MUST_USE_CANDIDATE, RESULT_UNIT_ERR, + RESULT_LARGE_ERR, ]); impl<'tcx> LateLintPass<'tcx> for Functions { @@ -259,18 +305,18 @@ impl<'tcx> LateLintPass<'tcx> for Functions { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { must_use::check_item(cx, item); - result_unit_err::check_item(cx, item); + result::check_item(cx, item, self.large_error_threshold); } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) { must_use::check_impl_item(cx, item); - result_unit_err::check_impl_item(cx, item); + result::check_impl_item(cx, item, self.large_error_threshold); } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) { too_many_arguments::check_trait_item(cx, item, self.too_many_arguments_threshold); not_unsafe_ptr_arg_deref::check_trait_item(cx, item); must_use::check_trait_item(cx, item); - result_unit_err::check_trait_item(cx, item); + result::check_trait_item(cx, item, self.large_error_threshold); } } diff --git a/clippy_lints/src/functions/result.rs b/clippy_lints/src/functions/result.rs new file mode 100644 index 000000000000..af520a493eda --- /dev/null +++ b/clippy_lints/src/functions/result.rs @@ -0,0 +1,100 @@ +use rustc_errors::Diagnostic; +use rustc_hir as hir; +use rustc_lint::{LateContext, LintContext}; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::{self, Ty}; +use rustc_span::{sym, Span}; +use rustc_typeck::hir_ty_to_ty; + +use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; +use clippy_utils::trait_ref_of_method; +use clippy_utils::ty::{approx_ty_size, is_type_diagnostic_item}; + +use super::{RESULT_LARGE_ERR, RESULT_UNIT_ERR}; + +/// The type of the `Err`-variant in a `std::result::Result` returned by the +/// given `FnDecl` +fn result_err_ty<'tcx>( + cx: &LateContext<'tcx>, + decl: &hir::FnDecl<'tcx>, + item_span: Span, +) -> Option<(&'tcx hir::Ty<'tcx>, Ty<'tcx>)> { + if !in_external_macro(cx.sess(), item_span) + && let hir::FnRetTy::Return(hir_ty) = decl.output + && let ty = hir_ty_to_ty(cx.tcx, hir_ty) + && is_type_diagnostic_item(cx, ty, sym::Result) + && let ty::Adt(_, substs) = ty.kind() + { + let err_ty = substs.type_at(1); + Some((hir_ty, err_ty)) + } else { + None + } +} + +pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, large_err_threshold: u64) { + if let hir::ItemKind::Fn(ref sig, _generics, _) = item.kind + && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.span) + { + if cx.access_levels.is_exported(item.def_id) { + let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); + check_result_unit_err(cx, err_ty, fn_header_span); + } + check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold); + } +} + +pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::ImplItem<'tcx>, large_err_threshold: u64) { + // Don't lint if method is a trait's implementation, we can't do anything about those + if let hir::ImplItemKind::Fn(ref sig, _) = item.kind + && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.span) + && trait_ref_of_method(cx, item.def_id).is_none() + { + if cx.access_levels.is_exported(item.def_id) { + let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); + check_result_unit_err(cx, err_ty, fn_header_span); + } + check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold); + } +} + +pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::TraitItem<'tcx>, large_err_threshold: u64) { + if let hir::TraitItemKind::Fn(ref sig, _) = item.kind { + let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); + if let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.span) { + if cx.access_levels.is_exported(item.def_id) { + check_result_unit_err(cx, err_ty, fn_header_span); + } + check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold); + } + } +} + +fn check_result_unit_err(cx: &LateContext<'_>, err_ty: Ty<'_>, fn_header_span: Span) { + if err_ty.is_unit() { + span_lint_and_help( + cx, + RESULT_UNIT_ERR, + fn_header_span, + "this returns a `Result<_, ()>`", + None, + "use a custom `Error` type instead", + ); + } +} + +fn check_result_large_err<'tcx>(cx: &LateContext<'tcx>, err_ty: Ty<'tcx>, hir_ty_span: Span, large_err_threshold: u64) { + let ty_size = approx_ty_size(cx, err_ty); + if ty_size >= large_err_threshold { + span_lint_and_then( + cx, + RESULT_LARGE_ERR, + hir_ty_span, + "the `Err`-variant returned from this function is very large", + |diag: &mut Diagnostic| { + diag.span_label(hir_ty_span, format!("the `Err`-variant is at least {ty_size} bytes")); + diag.help(format!("try reducing the size of `{err_ty}`, for example by boxing large elements or replacing it with `Box<{err_ty}>`")); + }, + ); + } +} diff --git a/clippy_lints/src/functions/result_unit_err.rs b/clippy_lints/src/functions/result_unit_err.rs deleted file mode 100644 index 2e63a1f920d6..000000000000 --- a/clippy_lints/src/functions/result_unit_err.rs +++ /dev/null @@ -1,66 +0,0 @@ -use rustc_hir as hir; -use rustc_lint::{LateContext, LintContext}; -use rustc_middle::lint::in_external_macro; -use rustc_middle::ty; -use rustc_span::{sym, Span}; -use rustc_typeck::hir_ty_to_ty; - -use if_chain::if_chain; - -use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::trait_ref_of_method; -use clippy_utils::ty::is_type_diagnostic_item; - -use super::RESULT_UNIT_ERR; - -pub(super) fn check_item(cx: &LateContext<'_>, item: &hir::Item<'_>) { - if let hir::ItemKind::Fn(ref sig, _generics, _) = item.kind { - let is_public = cx.access_levels.is_exported(item.def_id); - let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); - if is_public { - check_result_unit_err(cx, sig.decl, item.span, fn_header_span); - } - } -} - -pub(super) fn check_impl_item(cx: &LateContext<'_>, item: &hir::ImplItem<'_>) { - if let hir::ImplItemKind::Fn(ref sig, _) = item.kind { - let is_public = cx.access_levels.is_exported(item.def_id); - let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); - if is_public && trait_ref_of_method(cx, item.def_id).is_none() { - check_result_unit_err(cx, sig.decl, item.span, fn_header_span); - } - } -} - -pub(super) fn check_trait_item(cx: &LateContext<'_>, item: &hir::TraitItem<'_>) { - if let hir::TraitItemKind::Fn(ref sig, _) = item.kind { - let is_public = cx.access_levels.is_exported(item.def_id); - let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); - if is_public { - check_result_unit_err(cx, sig.decl, item.span, fn_header_span); - } - } -} - -fn check_result_unit_err(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, item_span: Span, fn_header_span: Span) { - if_chain! { - if !in_external_macro(cx.sess(), item_span); - if let hir::FnRetTy::Return(ty) = decl.output; - let ty = hir_ty_to_ty(cx.tcx, ty); - if is_type_diagnostic_item(cx, ty, sym::Result); - if let ty::Adt(_, substs) = ty.kind(); - let err_ty = substs.type_at(1); - if err_ty.is_unit(); - then { - span_lint_and_help( - cx, - RESULT_UNIT_ERR, - fn_header_span, - "this returns a `Result<_, ()>`", - None, - "use a custom `Error` type instead", - ); - } - } -} diff --git a/clippy_lints/src/get_first.rs b/clippy_lints/src/get_first.rs deleted file mode 100644 index 529f7babaa5e..000000000000 --- a/clippy_lints/src/get_first.rs +++ /dev/null @@ -1,68 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{is_slice_of_primitives, match_def_path, paths}; -use if_chain::if_chain; -use rustc_ast::LitKind; -use rustc_errors::Applicability; -use rustc_hir as hir; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::source_map::Spanned; - -declare_clippy_lint! { - /// ### What it does - /// Checks for using `x.get(0)` instead of - /// `x.first()`. - /// - /// ### Why is this bad? - /// Using `x.first()` is easier to read and has the same - /// result. - /// - /// ### Example - /// ```rust - /// let x = vec![2, 3, 5]; - /// let first_element = x.get(0); - /// ``` - /// - /// Use instead: - /// ```rust - /// let x = vec![2, 3, 5]; - /// let first_element = x.first(); - /// ``` - #[clippy::version = "1.63.0"] - pub GET_FIRST, - style, - "Using `x.get(0)` when `x.first()` is simpler" -} -declare_lint_pass!(GetFirst => [GET_FIRST]); - -impl<'tcx> LateLintPass<'tcx> for GetFirst { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if_chain! { - if let hir::ExprKind::MethodCall(_, [struct_calling_on, method_arg], _) = &expr.kind; - if let Some(expr_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if match_def_path(cx, expr_def_id, &paths::SLICE_GET); - - if let Some(_) = is_slice_of_primitives(cx, struct_calling_on); - if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = method_arg.kind; - - then { - let mut applicability = Applicability::MachineApplicable; - let slice_name = snippet_with_applicability( - cx, - struct_calling_on.span, "..", - &mut applicability, - ); - span_lint_and_sugg( - cx, - GET_FIRST, - expr.span, - &format!("accessing first element with `{0}.get(0)`", slice_name), - "try", - format!("{}.first()", slice_name), - applicability, - ); - } - } - } -} diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs index e95017007849..4d703d691acc 100644 --- a/clippy_lints/src/if_let_mutex.rs +++ b/clippy_lints/src/if_let_mutex.rs @@ -1,8 +1,9 @@ -use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::SpanlessEq; use if_chain::if_chain; +use rustc_errors::Diagnostic; use rustc_hir::intravisit::{self as visit, Visitor}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -45,16 +46,8 @@ declare_lint_pass!(IfLetMutex => [IF_LET_MUTEX]); impl<'tcx> LateLintPass<'tcx> for IfLetMutex { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - let mut arm_visit = ArmVisitor { - mutex_lock_called: false, - found_mutex: None, - cx, - }; - let mut op_visit = OppVisitor { - mutex_lock_called: false, - found_mutex: None, - cx, - }; + let mut arm_visit = ArmVisitor { found_mutex: None, cx }; + let mut op_visit = OppVisitor { found_mutex: None, cx }; if let Some(higher::IfLet { let_expr, if_then, @@ -63,18 +56,28 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex { }) = higher::IfLet::hir(cx, expr) { op_visit.visit_expr(let_expr); - if op_visit.mutex_lock_called { + if let Some(op_mutex) = op_visit.found_mutex { arm_visit.visit_expr(if_then); arm_visit.visit_expr(if_else); - if arm_visit.mutex_lock_called && arm_visit.same_mutex(cx, op_visit.found_mutex.unwrap()) { - span_lint_and_help( + if let Some(arm_mutex) = arm_visit.found_mutex_if_same_as(op_mutex) { + let diag = |diag: &mut Diagnostic| { + diag.span_label( + op_mutex.span, + "this Mutex will remain locked for the entire `if let`-block...", + ); + diag.span_label( + arm_mutex.span, + "... and is tried to lock again here, which will always deadlock.", + ); + diag.help("move the lock call outside of the `if let ...` expression"); + }; + span_lint_and_then( cx, IF_LET_MUTEX, expr.span, "calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock", - None, - "move the lock call outside of the `if let ...` expression", + diag, ); } } @@ -84,7 +87,6 @@ impl<'tcx> LateLintPass<'tcx> for IfLetMutex { /// Checks if `Mutex::lock` is called in the `if let` expr. pub struct OppVisitor<'a, 'tcx> { - mutex_lock_called: bool, found_mutex: Option<&'tcx Expr<'tcx>>, cx: &'a LateContext<'tcx>, } @@ -93,7 +95,6 @@ impl<'tcx> Visitor<'tcx> for OppVisitor<'_, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { if let Some(mutex) = is_mutex_lock_call(self.cx, expr) { self.found_mutex = Some(mutex); - self.mutex_lock_called = true; return; } visit::walk_expr(self, expr); @@ -102,7 +103,6 @@ impl<'tcx> Visitor<'tcx> for OppVisitor<'_, 'tcx> { /// Checks if `Mutex::lock` is called in any of the branches. pub struct ArmVisitor<'a, 'tcx> { - mutex_lock_called: bool, found_mutex: Option<&'tcx Expr<'tcx>>, cx: &'a LateContext<'tcx>, } @@ -111,7 +111,6 @@ impl<'tcx> Visitor<'tcx> for ArmVisitor<'_, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { if let Some(mutex) = is_mutex_lock_call(self.cx, expr) { self.found_mutex = Some(mutex); - self.mutex_lock_called = true; return; } visit::walk_expr(self, expr); @@ -119,9 +118,12 @@ impl<'tcx> Visitor<'tcx> for ArmVisitor<'_, 'tcx> { } impl<'tcx, 'l> ArmVisitor<'tcx, 'l> { - fn same_mutex(&self, cx: &LateContext<'_>, op_mutex: &Expr<'_>) -> bool { - self.found_mutex - .map_or(false, |arm_mutex| SpanlessEq::new(cx).eq_expr(op_mutex, arm_mutex)) + fn found_mutex_if_same_as(&self, op_mutex: &Expr<'_>) -> Option<&Expr<'_>> { + self.found_mutex.and_then(|arm_mutex| { + SpanlessEq::new(self.cx) + .eq_expr(op_mutex, arm_mutex) + .then_some(arm_mutex) + }) } } @@ -129,7 +131,7 @@ fn is_mutex_lock_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Opt if_chain! { if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind; if path.ident.as_str() == "lock"; - let ty = cx.typeck_results().expr_ty(self_arg); + let ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); if is_type_diagnostic_item(cx, ty, sym::Mutex); then { Some(self_arg) diff --git a/clippy_lints/src/if_then_some_else_none.rs b/clippy_lints/src/if_then_some_else_none.rs index b8d227855d97..11c43247868c 100644 --- a/clippy_lints/src/if_then_some_else_none.rs +++ b/clippy_lints/src/if_then_some_else_none.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::source::snippet_with_macro_callsite; use clippy_utils::{contains_return, higher, is_else_clause, is_lang_ctor, meets_msrv, msrvs, peel_blocks}; -use if_chain::if_chain; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -11,10 +11,12 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { /// ### What it does - /// Checks for if-else that could be written to `bool::then`. + /// Checks for if-else that could be written using either `bool::then` or `bool::then_some`. /// /// ### Why is this bad? - /// Looks a little redundant. Using `bool::then` helps it have less lines of code. + /// Looks a little redundant. Using `bool::then` is more concise and incurs no loss of clarity. + /// For simple calculations and known values, use `bool::then_some`, which is eagerly evaluated + /// in comparison to `bool::then`. /// /// ### Example /// ```rust @@ -39,7 +41,7 @@ declare_clippy_lint! { #[clippy::version = "1.53.0"] pub IF_THEN_SOME_ELSE_NONE, restriction, - "Finds if-else that could be written using `bool::then`" + "Finds if-else that could be written using either `bool::then` or `bool::then_some`" } pub struct IfThenSomeElseNone { @@ -56,7 +58,7 @@ impl IfThenSomeElseNone { impl_lint_pass!(IfThenSomeElseNone => [IF_THEN_SOME_ELSE_NONE]); impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if !meets_msrv(self.msrv, msrvs::BOOL_THEN) { return; } @@ -70,43 +72,47 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { return; } - if_chain! { - if let Some(higher::If { cond, then, r#else: Some(els) }) = higher::If::hir(expr); - if let ExprKind::Block(then_block, _) = then.kind; - if let Some(then_expr) = then_block.expr; - if let ExprKind::Call(then_call, [then_arg]) = then_expr.kind; - if let ExprKind::Path(ref then_call_qpath) = then_call.kind; - if is_lang_ctor(cx, then_call_qpath, OptionSome); - if let ExprKind::Path(ref qpath) = peel_blocks(els).kind; - if is_lang_ctor(cx, qpath, OptionNone); - if !stmts_contains_early_return(then_block.stmts); - then { - let cond_snip = snippet_with_macro_callsite(cx, cond.span, "[condition]"); - let cond_snip = if matches!(cond.kind, ExprKind::Unary(_, _) | ExprKind::Binary(_, _, _)) { - format!("({})", cond_snip) - } else { - cond_snip.into_owned() - }; - let arg_snip = snippet_with_macro_callsite(cx, then_arg.span, ""); - let closure_body = if then_block.stmts.is_empty() { - arg_snip.into_owned() - } else { - format!("{{ /* snippet */ {} }}", arg_snip) - }; - let help = format!( - "consider using `bool::then` like: `{}.then(|| {})`", - cond_snip, - closure_body, - ); - span_lint_and_help( - cx, - IF_THEN_SOME_ELSE_NONE, - expr.span, - "this could be simplified with `bool::then`", - None, - &help, - ); - } + if let Some(higher::If { cond, then, r#else: Some(els) }) = higher::If::hir(expr) + && let ExprKind::Block(then_block, _) = then.kind + && let Some(then_expr) = then_block.expr + && let ExprKind::Call(then_call, [then_arg]) = then_expr.kind + && let ExprKind::Path(ref then_call_qpath) = then_call.kind + && is_lang_ctor(cx, then_call_qpath, OptionSome) + && let ExprKind::Path(ref qpath) = peel_blocks(els).kind + && is_lang_ctor(cx, qpath, OptionNone) + && !stmts_contains_early_return(then_block.stmts) + { + let cond_snip = snippet_with_macro_callsite(cx, cond.span, "[condition]"); + let cond_snip = if matches!(cond.kind, ExprKind::Unary(_, _) | ExprKind::Binary(_, _, _)) { + format!("({})", cond_snip) + } else { + cond_snip.into_owned() + }; + let arg_snip = snippet_with_macro_callsite(cx, then_arg.span, ""); + let mut method_body = if then_block.stmts.is_empty() { + arg_snip.into_owned() + } else { + format!("{{ /* snippet */ {} }}", arg_snip) + }; + let method_name = if switch_to_eager_eval(cx, expr) && meets_msrv(self.msrv, msrvs::BOOL_THEN_SOME) { + "then_some" + } else { + method_body.insert_str(0, "|| "); + "then" + }; + + let help = format!( + "consider using `bool::{}` like: `{}.{}({})`", + method_name, cond_snip, method_name, method_body, + ); + span_lint_and_help( + cx, + IF_THEN_SOME_ELSE_NONE, + expr.span, + &format!("this could be simplified with `bool::{}`", method_name), + None, + &help, + ); } } diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 01082cc8eeb6..134cbbf7b5c6 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -20,12 +20,12 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(booleans::NONMINIMAL_BOOL), LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR), LintId::of(borrow_deref_ref::BORROW_DEREF_REF), - LintId::of(bytes_count_to_len::BYTES_COUNT_TO_LEN), LintId::of(casts::CAST_ABS_TO_UNSIGNED), LintId::of(casts::CAST_ENUM_CONSTRUCTOR), LintId::of(casts::CAST_ENUM_TRUNCATION), LintId::of(casts::CAST_REF_TO_MUT), LintId::of(casts::CAST_SLICE_DIFFERENT_SIZES), + LintId::of(casts::CAST_SLICE_FROM_RAW_PARTS), LintId::of(casts::CHAR_LIT_AS_U8), LintId::of(casts::FN_TO_NUMERIC_CAST), LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION), @@ -80,9 +80,9 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(functions::DOUBLE_MUST_USE), LintId::of(functions::MUST_USE_UNIT), LintId::of(functions::NOT_UNSAFE_PTR_ARG_DEREF), + LintId::of(functions::RESULT_LARGE_ERR), LintId::of(functions::RESULT_UNIT_ERR), LintId::of(functions::TOO_MANY_ARGUMENTS), - LintId::of(get_first::GET_FIRST), LintId::of(if_let_mutex::IF_LET_MUTEX), LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING), LintId::of(infinite_iter::INFINITE_ITER), @@ -128,7 +128,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(manual_rem_euclid::MANUAL_REM_EUCLID), LintId::of(manual_retain::MANUAL_RETAIN), LintId::of(manual_strip::MANUAL_STRIP), - LintId::of(map_clone::MAP_CLONE), LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN), LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN), LintId::of(match_result_ok::MATCH_RESULT_OK), @@ -150,17 +149,20 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT), LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT), LintId::of(methods::BIND_INSTEAD_OF_MAP), + LintId::of(methods::BYTES_COUNT_TO_LEN), LintId::of(methods::BYTES_NTH), LintId::of(methods::CHARS_LAST_CMP), LintId::of(methods::CHARS_NEXT_CMP), LintId::of(methods::CLONE_DOUBLE_REF), LintId::of(methods::CLONE_ON_COPY), + LintId::of(methods::COLLAPSIBLE_STR_REPLACE), LintId::of(methods::ERR_EXPECT), LintId::of(methods::EXPECT_FUN_CALL), LintId::of(methods::EXTEND_WITH_DRAIN), LintId::of(methods::FILTER_MAP_IDENTITY), LintId::of(methods::FILTER_NEXT), LintId::of(methods::FLAT_MAP_IDENTITY), + LintId::of(methods::GET_FIRST), LintId::of(methods::GET_LAST_WITH_LEN), LintId::of(methods::INSPECT_FOR_EACH), LintId::of(methods::INTO_ITER_ON_REF), @@ -178,13 +180,16 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::MANUAL_SATURATING_ARITHMETIC), LintId::of(methods::MANUAL_SPLIT_ONCE), LintId::of(methods::MANUAL_STR_REPEAT), + LintId::of(methods::MAP_CLONE), LintId::of(methods::MAP_COLLECT_RESULT_UNIT), LintId::of(methods::MAP_FLATTEN), LintId::of(methods::MAP_IDENTITY), + LintId::of(methods::MUT_MUTEX_LOCK), LintId::of(methods::NEEDLESS_OPTION_AS_DEREF), LintId::of(methods::NEEDLESS_OPTION_TAKE), LintId::of(methods::NEEDLESS_SPLITN), LintId::of(methods::NEW_RET_NO_SELF), + LintId::of(methods::NONSENSICAL_OPEN_OPTIONS), LintId::of(methods::NO_EFFECT_REPLACE), LintId::of(methods::OBFUSCATED_IF_ELSE), LintId::of(methods::OK_EXPECT), @@ -193,6 +198,8 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::OPTION_MAP_OR_NONE), LintId::of(methods::OR_FUN_CALL), LintId::of(methods::OR_THEN_UNWRAP), + LintId::of(methods::RANGE_ZIP_WITH_LEN), + LintId::of(methods::REPEAT_ONCE), LintId::of(methods::RESULT_MAP_OR_INTO_OPTION), LintId::of(methods::SEARCH_IS_SOME), LintId::of(methods::SHOULD_IMPLEMENT_TRAIT), @@ -202,14 +209,18 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(methods::STRING_EXTEND_CHARS), LintId::of(methods::SUSPICIOUS_MAP), LintId::of(methods::SUSPICIOUS_SPLITN), + LintId::of(methods::SUSPICIOUS_TO_OWNED), LintId::of(methods::UNINIT_ASSUMED_INIT), + LintId::of(methods::UNIT_HASH), LintId::of(methods::UNNECESSARY_FILTER_MAP), LintId::of(methods::UNNECESSARY_FIND_MAP), LintId::of(methods::UNNECESSARY_FOLD), LintId::of(methods::UNNECESSARY_LAZY_EVALUATIONS), + LintId::of(methods::UNNECESSARY_SORT_BY), LintId::of(methods::UNNECESSARY_TO_OWNED), LintId::of(methods::UNWRAP_OR_ELSE_DEFAULT), LintId::of(methods::USELESS_ASREF), + LintId::of(methods::VEC_RESIZE_TO_ZERO), LintId::of(methods::WRONG_SELF_CONVENTION), LintId::of(methods::ZST_OFFSET), LintId::of(minmax::MIN_MAX), @@ -224,8 +235,8 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN), LintId::of(misc_early::ZERO_PREFIXED_LITERAL), LintId::of(mixed_read_write_in_expression::DIVERGING_SUB_EXPRESSION), + LintId::of(multi_assignments::MULTI_ASSIGNMENTS), LintId::of(mut_key::MUTABLE_KEY_TYPE), - LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK), LintId::of(mut_reference::UNNECESSARY_MUT_PASSED), LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE), LintId::of(needless_bool::BOOL_COMPARISON), @@ -245,7 +256,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), LintId::of(octal_escapes::OCTAL_ESCAPES), - LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS), + LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION), LintId::of(operators::ABSURD_EXTREME_COMPARISONS), LintId::of(operators::ASSIGN_OP_PATTERN), LintId::of(operators::BAD_BIT_MASK), @@ -275,7 +286,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST), LintId::of(question_mark::QUESTION_MARK), LintId::of(ranges::MANUAL_RANGE_CONTAINS), - LintId::of(ranges::RANGE_ZIP_WITH_LEN), LintId::of(ranges::REVERSED_EMPTY_RANGES), LintId::of(rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT), LintId::of(read_zero_byte_vec::READ_ZERO_BYTE_VEC), @@ -286,7 +296,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), LintId::of(reference::DEREF_ADDROF), LintId::of(regex::INVALID_REGEX), - LintId::of(repeat_once::REPEAT_ONCE), LintId::of(returns::LET_AND_RETURN), LintId::of(returns::NEEDLESS_RETURN), LintId::of(self_named_constructors::SELF_NAMED_CONSTRUCTORS), @@ -314,10 +323,10 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT), LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES), LintId::of(transmute::TRANSMUTE_PTR_TO_REF), + LintId::of(transmute::TRANSMUTING_NULL), LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE), LintId::of(transmute::USELESS_TRANSMUTE), LintId::of(transmute::WRONG_TRANSMUTE), - LintId::of(transmuting_null::TRANSMUTING_NULL), LintId::of(types::BORROWED_BOX), LintId::of(types::BOX_COLLECTION), LintId::of(types::REDUNDANT_ALLOCATION), @@ -325,7 +334,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(types::VEC_BOX), LintId::of(unicode::INVISIBLE_CHARACTERS), LintId::of(uninit_vec::UNINIT_VEC), - LintId::of(unit_hash::UNIT_HASH), LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), LintId::of(unit_types::LET_UNIT_VALUE), LintId::of(unit_types::UNIT_ARG), @@ -333,9 +341,9 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS), LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS), LintId::of(unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS), - LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY), LintId::of(unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), LintId::of(unused_io_amount::UNUSED_IO_AMOUNT), + LintId::of(unused_peekable::UNUSED_PEEKABLE), LintId::of(unused_unit::UNUSED_UNIT), LintId::of(unwrap::PANICKING_UNWRAP), LintId::of(unwrap::UNNECESSARY_UNWRAP), @@ -343,7 +351,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(useless_conversion::USELESS_CONVERSION), LintId::of(vec::USELESS_VEC), LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH), - LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO), + LintId::of(write::POSITIONAL_NAMED_FORMAT_PARAMETERS), LintId::of(write::PRINTLN_EMPTY_STRING), LintId::of(write::PRINT_LITERAL), LintId::of(write::PRINT_WITH_NEWLINE), diff --git a/clippy_lints/src/lib.register_complexity.rs b/clippy_lints/src/lib.register_complexity.rs index 3784d3c68dce..aa247352f88f 100644 --- a/clippy_lints/src/lib.register_complexity.rs +++ b/clippy_lints/src/lib.register_complexity.rs @@ -6,7 +6,6 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(attrs::DEPRECATED_CFG_ATTR), LintId::of(booleans::NONMINIMAL_BOOL), LintId::of(borrow_deref_ref::BORROW_DEREF_REF), - LintId::of(bytes_count_to_len::BYTES_COUNT_TO_LEN), LintId::of(casts::CHAR_LIT_AS_U8), LintId::of(casts::UNNECESSARY_CAST), LintId::of(dereference::EXPLICIT_AUTO_DEREF), @@ -33,6 +32,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(matches::NEEDLESS_MATCH), LintId::of(matches::WILDCARD_IN_OR_PATTERNS), LintId::of(methods::BIND_INSTEAD_OF_MAP), + LintId::of(methods::BYTES_COUNT_TO_LEN), LintId::of(methods::CLONE_ON_COPY), LintId::of(methods::FILTER_MAP_IDENTITY), LintId::of(methods::FILTER_NEXT), @@ -51,10 +51,13 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(methods::OPTION_AS_REF_DEREF), LintId::of(methods::OPTION_FILTER_MAP), LintId::of(methods::OR_THEN_UNWRAP), + LintId::of(methods::RANGE_ZIP_WITH_LEN), + LintId::of(methods::REPEAT_ONCE), LintId::of(methods::SEARCH_IS_SOME), LintId::of(methods::SKIP_WHILE_NEXT), LintId::of(methods::UNNECESSARY_FILTER_MAP), LintId::of(methods::UNNECESSARY_FIND_MAP), + LintId::of(methods::UNNECESSARY_SORT_BY), LintId::of(methods::USELESS_ASREF), LintId::of(misc::SHORT_CIRCUIT_STATEMENT), LintId::of(misc_early::UNNEEDED_WILDCARD_PATTERN), @@ -69,6 +72,7 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD), LintId::of(no_effect::NO_EFFECT), LintId::of(no_effect::UNNECESSARY_OPERATION), + LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION), LintId::of(operators::DOUBLE_COMPARISONS), LintId::of(operators::DURATION_SUBSEC), LintId::of(operators::IDENTITY_OP), @@ -76,11 +80,9 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL), LintId::of(precedence::PRECEDENCE), LintId::of(ptr_offset_with_cast::PTR_OFFSET_WITH_CAST), - LintId::of(ranges::RANGE_ZIP_WITH_LEN), LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL), LintId::of(redundant_slicing::REDUNDANT_SLICING), LintId::of(reference::DEREF_ADDROF), - LintId::of(repeat_once::REPEAT_ONCE), LintId::of(strings::STRING_FROM_UTF8_AS_BYTES), LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS), LintId::of(swap::MANUAL_SWAP), @@ -99,7 +101,6 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec! LintId::of(types::TYPE_COMPLEXITY), LintId::of(types::VEC_BOX), LintId::of(unit_types::UNIT_ARG), - LintId::of(unnecessary_sort_by::UNNECESSARY_SORT_BY), LintId::of(unwrap::UNNECESSARY_UNWRAP), LintId::of(useless_conversion::USELESS_CONVERSION), LintId::of(zero_div_zero::ZERO_DIVIDED_BY_ZERO), diff --git a/clippy_lints/src/lib.register_correctness.rs b/clippy_lints/src/lib.register_correctness.rs index 006275d1383f..bb94037ec2e7 100644 --- a/clippy_lints/src/lib.register_correctness.rs +++ b/clippy_lints/src/lib.register_correctness.rs @@ -39,12 +39,14 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT), LintId::of(methods::CLONE_DOUBLE_REF), LintId::of(methods::ITERATOR_STEP_BY_ZERO), + LintId::of(methods::NONSENSICAL_OPEN_OPTIONS), LintId::of(methods::SUSPICIOUS_SPLITN), LintId::of(methods::UNINIT_ASSUMED_INIT), + LintId::of(methods::UNIT_HASH), + LintId::of(methods::VEC_RESIZE_TO_ZERO), LintId::of(methods::ZST_OFFSET), LintId::of(minmax::MIN_MAX), LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS), - LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS), LintId::of(operators::ABSURD_EXTREME_COMPARISONS), LintId::of(operators::BAD_BIT_MASK), LintId::of(operators::CMP_NAN), @@ -62,17 +64,15 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve LintId::of(serde_api::SERDE_API_MISUSE), LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), LintId::of(swap::ALMOST_SWAPPED), + LintId::of(transmute::TRANSMUTING_NULL), LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE), LintId::of(transmute::WRONG_TRANSMUTE), - LintId::of(transmuting_null::TRANSMUTING_NULL), LintId::of(unicode::INVISIBLE_CHARACTERS), LintId::of(uninit_vec::UNINIT_VEC), - LintId::of(unit_hash::UNIT_HASH), LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), LintId::of(unit_types::UNIT_CMP), LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS), LintId::of(unnamed_address::VTABLE_ADDRESS_COMPARISONS), LintId::of(unused_io_amount::UNUSED_IO_AMOUNT), LintId::of(unwrap::PANICKING_UNWRAP), - LintId::of(vec_resize_to_zero::VEC_RESIZE_TO_ZERO), ]) diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index c540573b8022..fd20e016578a 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -38,7 +38,6 @@ store.register_lints(&[ almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE, approx_const::APPROX_CONSTANT, as_conversions::AS_CONVERSIONS, - as_underscore::AS_UNDERSCORE, asm_syntax::INLINE_ASM_X86_ATT_SYNTAX, asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX, assertions_on_constants::ASSERTIONS_ON_CONSTANTS, @@ -59,16 +58,14 @@ store.register_lints(&[ bool_assert_comparison::BOOL_ASSERT_COMPARISON, booleans::NONMINIMAL_BOOL, booleans::OVERLY_COMPLEX_BOOL_EXPR, - borrow_as_ptr::BORROW_AS_PTR, borrow_deref_ref::BORROW_DEREF_REF, - bytecount::NAIVE_BYTECOUNT, - bytes_count_to_len::BYTES_COUNT_TO_LEN, cargo::CARGO_COMMON_METADATA, cargo::MULTIPLE_CRATE_VERSIONS, cargo::NEGATIVE_FEATURE_NAMES, cargo::REDUNDANT_FEATURE_NAMES, cargo::WILDCARD_DEPENDENCIES, - case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, + casts::AS_UNDERSCORE, + casts::BORROW_AS_PTR, casts::CAST_ABS_TO_UNSIGNED, casts::CAST_ENUM_CONSTRUCTOR, casts::CAST_ENUM_TRUNCATION, @@ -80,6 +77,7 @@ store.register_lints(&[ casts::CAST_REF_TO_MUT, casts::CAST_SIGN_LOSS, casts::CAST_SLICE_DIFFERENT_SIZES, + casts::CAST_SLICE_FROM_RAW_PARTS, casts::CHAR_LIT_AS_U8, casts::FN_TO_NUMERIC_CAST, casts::FN_TO_NUMERIC_CAST_ANY, @@ -173,11 +171,11 @@ store.register_lints(&[ functions::MUST_USE_CANDIDATE, functions::MUST_USE_UNIT, functions::NOT_UNSAFE_PTR_ARG_DEREF, + functions::RESULT_LARGE_ERR, functions::RESULT_UNIT_ERR, functions::TOO_MANY_ARGUMENTS, functions::TOO_MANY_LINES, future_not_send::FUTURE_NOT_SEND, - get_first::GET_FIRST, if_let_mutex::IF_LET_MUTEX, if_not_else::IF_NOT_ELSE, if_then_some_else_none::IF_THEN_SOME_ELSE_NONE, @@ -246,12 +244,10 @@ store.register_lints(&[ manual_bits::MANUAL_BITS, manual_instant_elapsed::MANUAL_INSTANT_ELAPSED, manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE, - manual_ok_or::MANUAL_OK_OR, manual_rem_euclid::MANUAL_REM_EUCLID, manual_retain::MANUAL_RETAIN, + manual_string_new::MANUAL_STRING_NEW, manual_strip::MANUAL_STRIP, - map_clone::MAP_CLONE, - map_err_ignore::MAP_ERR_IGNORE, map_unit_fn::OPTION_MAP_UNIT_FN, map_unit_fn::RESULT_MAP_UNIT_FN, match_result_ok::MATCH_RESULT_OK, @@ -284,13 +280,16 @@ store.register_lints(&[ mem_replace::MEM_REPLACE_WITH_DEFAULT, mem_replace::MEM_REPLACE_WITH_UNINIT, methods::BIND_INSTEAD_OF_MAP, + methods::BYTES_COUNT_TO_LEN, methods::BYTES_NTH, + methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, methods::CHARS_LAST_CMP, methods::CHARS_NEXT_CMP, methods::CLONED_INSTEAD_OF_COPIED, methods::CLONE_DOUBLE_REF, methods::CLONE_ON_COPY, methods::CLONE_ON_REF_PTR, + methods::COLLAPSIBLE_STR_REPLACE, methods::ERR_EXPECT, methods::EXPECT_FUN_CALL, methods::EXPECT_USED, @@ -302,6 +301,7 @@ store.register_lints(&[ methods::FLAT_MAP_IDENTITY, methods::FLAT_MAP_OPTION, methods::FROM_ITER_INSTEAD_OF_COLLECT, + methods::GET_FIRST, methods::GET_LAST_WITH_LEN, methods::GET_UNWRAP, methods::IMPLICIT_CLONE, @@ -315,22 +315,30 @@ store.register_lints(&[ methods::ITER_NEXT_SLICE, methods::ITER_NTH, methods::ITER_NTH_ZERO, + methods::ITER_ON_EMPTY_COLLECTIONS, + methods::ITER_ON_SINGLE_ITEMS, methods::ITER_OVEREAGER_CLONED, methods::ITER_SKIP_NEXT, methods::ITER_WITH_DRAIN, methods::MANUAL_FILTER_MAP, methods::MANUAL_FIND_MAP, + methods::MANUAL_OK_OR, methods::MANUAL_SATURATING_ARITHMETIC, methods::MANUAL_SPLIT_ONCE, methods::MANUAL_STR_REPEAT, + methods::MAP_CLONE, methods::MAP_COLLECT_RESULT_UNIT, + methods::MAP_ERR_IGNORE, methods::MAP_FLATTEN, methods::MAP_IDENTITY, methods::MAP_UNWRAP_OR, + methods::MUT_MUTEX_LOCK, + methods::NAIVE_BYTECOUNT, methods::NEEDLESS_OPTION_AS_DEREF, methods::NEEDLESS_OPTION_TAKE, methods::NEEDLESS_SPLITN, methods::NEW_RET_NO_SELF, + methods::NONSENSICAL_OPEN_OPTIONS, methods::NO_EFFECT_REPLACE, methods::OBFUSCATED_IF_ELSE, methods::OK_EXPECT, @@ -339,25 +347,34 @@ store.register_lints(&[ methods::OPTION_MAP_OR_NONE, methods::OR_FUN_CALL, methods::OR_THEN_UNWRAP, + methods::PATH_BUF_PUSH_OVERWRITE, + methods::RANGE_ZIP_WITH_LEN, + methods::REPEAT_ONCE, methods::RESULT_MAP_OR_INTO_OPTION, methods::SEARCH_IS_SOME, methods::SHOULD_IMPLEMENT_TRAIT, methods::SINGLE_CHAR_ADD_STR, methods::SINGLE_CHAR_PATTERN, methods::SKIP_WHILE_NEXT, + methods::STABLE_SORT_PRIMITIVE, methods::STRING_EXTEND_CHARS, methods::SUSPICIOUS_MAP, methods::SUSPICIOUS_SPLITN, + methods::SUSPICIOUS_TO_OWNED, methods::UNINIT_ASSUMED_INIT, + methods::UNIT_HASH, methods::UNNECESSARY_FILTER_MAP, methods::UNNECESSARY_FIND_MAP, methods::UNNECESSARY_FOLD, methods::UNNECESSARY_JOIN, methods::UNNECESSARY_LAZY_EVALUATIONS, + methods::UNNECESSARY_SORT_BY, methods::UNNECESSARY_TO_OWNED, methods::UNWRAP_OR_ELSE_DEFAULT, methods::UNWRAP_USED, methods::USELESS_ASREF, + methods::VEC_RESIZE_TO_ZERO, + methods::VERBOSE_FILE_READS, methods::WRONG_SELF_CONVENTION, methods::ZST_OFFSET, minmax::MIN_MAX, @@ -384,9 +401,9 @@ store.register_lints(&[ mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION, module_style::MOD_MODULE_FILES, module_style::SELF_NAMED_MODULE_FILES, + multi_assignments::MULTI_ASSIGNMENTS, mut_key::MUTABLE_KEY_TYPE, mut_mut::MUT_MUT, - mut_mutex_lock::MUT_MUTEX_LOCK, mut_reference::UNNECESSARY_MUT_PASSED, mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL, mutex_atomic::MUTEX_ATOMIC, @@ -418,7 +435,6 @@ store.register_lints(&[ nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES, octal_escapes::OCTAL_ESCAPES, only_used_in_recursion::ONLY_USED_IN_RECURSION, - open_options::NONSENSICAL_OPEN_OPTIONS, operators::ABSURD_EXTREME_COMPARISONS, operators::ARITHMETIC, operators::ASSIGN_OP_PATTERN, @@ -457,7 +473,6 @@ store.register_lints(&[ partialeq_to_none::PARTIALEQ_TO_NONE, pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE, pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF, - path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE, pattern_type_mismatch::PATTERN_TYPE_MISMATCH, precedence::PRECEDENCE, ptr::CMP_NULL, @@ -470,7 +485,6 @@ store.register_lints(&[ ranges::MANUAL_RANGE_CONTAINS, ranges::RANGE_MINUS_ONE, ranges::RANGE_PLUS_ONE, - ranges::RANGE_ZIP_WITH_LEN, ranges::REVERSED_EMPTY_RANGES, rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT, read_zero_byte_vec::READ_ZERO_BYTE_VEC, @@ -486,7 +500,6 @@ store.register_lints(&[ reference::DEREF_ADDROF, regex::INVALID_REGEX, regex::TRIVIAL_REGEX, - repeat_once::REPEAT_ONCE, return_self_not_must_use::RETURN_SELF_NOT_MUST_USE, returns::LET_AND_RETURN, returns::NEEDLESS_RETURN, @@ -501,7 +514,6 @@ store.register_lints(&[ single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS, size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT, slow_vector_initialization::SLOW_VECTOR_INITIALIZATION, - stable_sort_primitive::STABLE_SORT_PRIMITIVE, std_instead_of_core::ALLOC_INSTEAD_OF_CORE, std_instead_of_core::STD_INSTEAD_OF_ALLOC, std_instead_of_core::STD_INSTEAD_OF_CORE, @@ -537,10 +549,10 @@ store.register_lints(&[ transmute::TRANSMUTE_PTR_TO_PTR, transmute::TRANSMUTE_PTR_TO_REF, transmute::TRANSMUTE_UNDEFINED_REPR, + transmute::TRANSMUTING_NULL, transmute::UNSOUND_COLLECTION_TRANSMUTE, transmute::USELESS_TRANSMUTE, transmute::WRONG_TRANSMUTE, - transmuting_null::TRANSMUTING_NULL, types::BORROWED_BOX, types::BOX_COLLECTION, types::LINKEDLIST, @@ -555,7 +567,6 @@ store.register_lints(&[ unicode::NON_ASCII_LITERAL, unicode::UNICODE_NOT_NFC, uninit_vec::UNINIT_VEC, - unit_hash::UNIT_HASH, unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD, unit_types::LET_UNIT_VALUE, unit_types::UNIT_ARG, @@ -564,12 +575,12 @@ store.register_lints(&[ unnamed_address::VTABLE_ADDRESS_COMPARISONS, unnecessary_owned_empty_strings::UNNECESSARY_OWNED_EMPTY_STRINGS, unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS, - unnecessary_sort_by::UNNECESSARY_SORT_BY, unnecessary_wraps::UNNECESSARY_WRAPS, unnested_or_patterns::UNNESTED_OR_PATTERNS, unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, unused_async::UNUSED_ASYNC, unused_io_amount::UNUSED_IO_AMOUNT, + unused_peekable::UNUSED_PEEKABLE, unused_rounding::UNUSED_ROUNDING, unused_self::UNUSED_SELF, unused_unit::UNUSED_UNIT, @@ -581,10 +592,9 @@ store.register_lints(&[ useless_conversion::USELESS_CONVERSION, vec::USELESS_VEC, vec_init_then_push::VEC_INIT_THEN_PUSH, - vec_resize_to_zero::VEC_RESIZE_TO_ZERO, - verbose_file_reads::VERBOSE_FILE_READS, wildcard_imports::ENUM_GLOB_USE, wildcard_imports::WILDCARD_IMPORTS, + write::POSITIONAL_NAMED_FORMAT_PARAMETERS, write::PRINTLN_EMPTY_STRING, write::PRINT_LITERAL, write::PRINT_STDERR, diff --git a/clippy_lints/src/lib.register_nursery.rs b/clippy_lints/src/lib.register_nursery.rs index 91210b23afe3..e319e7ee72c5 100644 --- a/clippy_lints/src/lib.register_nursery.rs +++ b/clippy_lints/src/lib.register_nursery.rs @@ -14,16 +14,17 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(index_refutable_slice::INDEX_REFUTABLE_SLICE), LintId::of(let_if_seq::USELESS_LET_IF_SEQ), LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE), + LintId::of(methods::ITER_ON_EMPTY_COLLECTIONS), + LintId::of(methods::ITER_ON_SINGLE_ITEMS), LintId::of(methods::ITER_WITH_DRAIN), + LintId::of(methods::PATH_BUF_PUSH_OVERWRITE), LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN), LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), LintId::of(mutex_atomic::MUTEX_ATOMIC), LintId::of(mutex_atomic::MUTEX_INTEGER), LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY), LintId::of(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES), - LintId::of(only_used_in_recursion::ONLY_USED_IN_RECURSION), LintId::of(option_if_let_else::OPTION_IF_LET_ELSE), - LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE), LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE), LintId::of(regex::TRIVIAL_REGEX), LintId::of(strings::STRING_LIT_AS_BYTES), diff --git a/clippy_lints/src/lib.register_pedantic.rs b/clippy_lints/src/lib.register_pedantic.rs index bd7d1a15ab4e..584ccf55e511 100644 --- a/clippy_lints/src/lib.register_pedantic.rs +++ b/clippy_lints/src/lib.register_pedantic.rs @@ -4,9 +4,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(attrs::INLINE_ALWAYS), - LintId::of(borrow_as_ptr::BORROW_AS_PTR), - LintId::of(bytecount::NAIVE_BYTECOUNT), - LintId::of(case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS), + LintId::of(casts::BORROW_AS_PTR), LintId::of(casts::CAST_LOSSLESS), LintId::of(casts::CAST_POSSIBLE_TRUNCATION), LintId::of(casts::CAST_POSSIBLE_WRAP), @@ -50,20 +48,24 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(macro_use::MACRO_USE_IMPORTS), LintId::of(manual_assert::MANUAL_ASSERT), LintId::of(manual_instant_elapsed::MANUAL_INSTANT_ELAPSED), - LintId::of(manual_ok_or::MANUAL_OK_OR), + LintId::of(manual_string_new::MANUAL_STRING_NEW), LintId::of(matches::MATCH_BOOL), LintId::of(matches::MATCH_ON_VEC_ITEMS), LintId::of(matches::MATCH_SAME_ARMS), LintId::of(matches::MATCH_WILDCARD_FOR_SINGLE_VARIANTS), LintId::of(matches::MATCH_WILD_ERR_ARM), LintId::of(matches::SINGLE_MATCH_ELSE), + LintId::of(methods::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS), LintId::of(methods::CLONED_INSTEAD_OF_COPIED), LintId::of(methods::FILTER_MAP_NEXT), LintId::of(methods::FLAT_MAP_OPTION), LintId::of(methods::FROM_ITER_INSTEAD_OF_COLLECT), LintId::of(methods::IMPLICIT_CLONE), LintId::of(methods::INEFFICIENT_TO_STRING), + LintId::of(methods::MANUAL_OK_OR), LintId::of(methods::MAP_UNWRAP_OR), + LintId::of(methods::NAIVE_BYTECOUNT), + LintId::of(methods::STABLE_SORT_PRIMITIVE), LintId::of(methods::UNNECESSARY_JOIN), LintId::of(misc::USED_UNDERSCORE_BINDING), LintId::of(mismatching_type_param_order::MISMATCHING_TYPE_PARAM_ORDER), @@ -85,7 +87,6 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(ref_option_ref::REF_OPTION_REF), LintId::of(return_self_not_must_use::RETURN_SELF_NOT_MUST_USE), LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED), - LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE), LintId::of(strings::STRING_ADD_ASSIGN), LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS), LintId::of(trait_bounds::TYPE_REPETITION_IN_BOUNDS), diff --git a/clippy_lints/src/lib.register_perf.rs b/clippy_lints/src/lib.register_perf.rs index e1b90acb93c2..195ce41e31e9 100644 --- a/clippy_lints/src/lib.register_perf.rs +++ b/clippy_lints/src/lib.register_perf.rs @@ -7,12 +7,14 @@ store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![ LintId::of(escape::BOXED_LOCAL), LintId::of(format_args::FORMAT_IN_FORMAT_ARGS), LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS), + LintId::of(functions::RESULT_LARGE_ERR), LintId::of(large_const_arrays::LARGE_CONST_ARRAYS), LintId::of(large_enum_variant::LARGE_ENUM_VARIANT), LintId::of(loops::MANUAL_MEMCPY), LintId::of(loops::MISSING_SPIN_LOOP), LintId::of(loops::NEEDLESS_COLLECT), LintId::of(manual_retain::MANUAL_RETAIN), + LintId::of(methods::COLLAPSIBLE_STR_REPLACE), LintId::of(methods::EXPECT_FUN_CALL), LintId::of(methods::EXTEND_WITH_DRAIN), LintId::of(methods::ITER_NTH), diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs index a7339ef27217..dd1e1e1a8e33 100644 --- a/clippy_lints/src/lib.register_restriction.rs +++ b/clippy_lints/src/lib.register_restriction.rs @@ -4,11 +4,11 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(as_conversions::AS_CONVERSIONS), - LintId::of(as_underscore::AS_UNDERSCORE), LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX), LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX), LintId::of(assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES), LintId::of(attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON), + LintId::of(casts::AS_UNDERSCORE), LintId::of(casts::FN_TO_NUMERIC_CAST_ANY), LintId::of(create_dir::CREATE_DIR), LintId::of(dbg_macro::DBG_MACRO), @@ -30,7 +30,6 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(large_include_file::LARGE_INCLUDE_FILE), LintId::of(let_underscore::LET_UNDERSCORE_MUST_USE), LintId::of(literal_representation::DECIMAL_LITERAL_REPRESENTATION), - LintId::of(map_err_ignore::MAP_ERR_IGNORE), LintId::of(matches::REST_PAT_IN_FULLY_BOUND_STRUCTS), LintId::of(matches::TRY_ERR), LintId::of(matches::WILDCARD_ENUM_MATCH_ARM), @@ -39,7 +38,9 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(methods::EXPECT_USED), LintId::of(methods::FILETYPE_IS_FILE), LintId::of(methods::GET_UNWRAP), + LintId::of(methods::MAP_ERR_IGNORE), LintId::of(methods::UNWRAP_USED), + LintId::of(methods::VERBOSE_FILE_READS), LintId::of(misc_early::SEPARATED_LITERAL_SUFFIX), LintId::of(misc_early::UNNEEDED_FIELD_PATTERN), LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX), @@ -81,7 +82,6 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(unicode::NON_ASCII_LITERAL), LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS), LintId::of(unwrap_in_result::UNWRAP_IN_RESULT), - LintId::of(verbose_file_reads::VERBOSE_FILE_READS), LintId::of(write::PRINT_STDERR), LintId::of(write::PRINT_STDOUT), LintId::of(write::USE_DEBUG), diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs index bfa654238f13..b5cb078e7a3c 100644 --- a/clippy_lints/src/lib.register_style.rs +++ b/clippy_lints/src/lib.register_style.rs @@ -29,7 +29,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(functions::DOUBLE_MUST_USE), LintId::of(functions::MUST_USE_UNIT), LintId::of(functions::RESULT_UNIT_ERR), - LintId::of(get_first::GET_FIRST), LintId::of(inherent_to_string::INHERENT_TO_STRING), LintId::of(init_numbered_fields::INIT_NUMBERED_FIELDS), LintId::of(len_zero::COMPARISON_TO_EMPTY), @@ -45,7 +44,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(manual_async_fn::MANUAL_ASYNC_FN), LintId::of(manual_bits::MANUAL_BITS), LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE), - LintId::of(map_clone::MAP_CLONE), LintId::of(match_result_ok::MATCH_RESULT_OK), LintId::of(matches::COLLAPSIBLE_MATCH), LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH), @@ -61,6 +59,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(methods::CHARS_LAST_CMP), LintId::of(methods::CHARS_NEXT_CMP), LintId::of(methods::ERR_EXPECT), + LintId::of(methods::GET_FIRST), LintId::of(methods::INTO_ITER_ON_REF), LintId::of(methods::IS_DIGIT_ASCII_RADIX), LintId::of(methods::ITER_CLONED_COLLECT), @@ -68,7 +67,9 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(methods::ITER_NTH_ZERO), LintId::of(methods::ITER_SKIP_NEXT), LintId::of(methods::MANUAL_SATURATING_ARITHMETIC), + LintId::of(methods::MAP_CLONE), LintId::of(methods::MAP_COLLECT_RESULT_UNIT), + LintId::of(methods::MUT_MUTEX_LOCK), LintId::of(methods::NEW_RET_NO_SELF), LintId::of(methods::OBFUSCATED_IF_ELSE), LintId::of(methods::OK_EXPECT), @@ -88,7 +89,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(misc_early::DUPLICATE_UNDERSCORE_ARGUMENT), LintId::of(misc_early::MIXED_CASE_HEX_LITERALS), LintId::of(misc_early::REDUNDANT_PATTERN), - LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK), LintId::of(mut_reference::UNNECESSARY_MUT_PASSED), LintId::of(needless_late_init::NEEDLESS_LATE_INIT), LintId::of(needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS), diff --git a/clippy_lints/src/lib.register_suspicious.rs b/clippy_lints/src/lib.register_suspicious.rs index 964992bd94fe..8f131bbf98be 100644 --- a/clippy_lints/src/lib.register_suspicious.rs +++ b/clippy_lints/src/lib.register_suspicious.rs @@ -11,6 +11,7 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec! LintId::of(casts::CAST_ABS_TO_UNSIGNED), LintId::of(casts::CAST_ENUM_CONSTRUCTOR), LintId::of(casts::CAST_ENUM_TRUNCATION), + LintId::of(casts::CAST_SLICE_FROM_RAW_PARTS), LintId::of(crate_in_macro_def::CRATE_IN_MACRO_DEF), LintId::of(drop_forget_ref::DROP_NON_DROP), LintId::of(drop_forget_ref::FORGET_NON_DROP), @@ -24,6 +25,8 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec! LintId::of(loops::MUT_RANGE_BOUND), LintId::of(methods::NO_EFFECT_REPLACE), LintId::of(methods::SUSPICIOUS_MAP), + LintId::of(methods::SUSPICIOUS_TO_OWNED), + LintId::of(multi_assignments::MULTI_ASSIGNMENTS), LintId::of(mut_key::MUTABLE_KEY_TYPE), LintId::of(octal_escapes::OCTAL_ESCAPES), LintId::of(operators::FLOAT_EQUALITY_WITHOUT_ABS), @@ -32,4 +35,6 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec! LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), LintId::of(swap_ptr_to_ref::SWAP_PTR_TO_REF), + LintId::of(unused_peekable::UNUSED_PEEKABLE), + LintId::of(write::POSITIONAL_NAMED_FORMAT_PARAMETERS), ]) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index ec5c73c13576..dfdaf90f09f4 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -171,7 +171,6 @@ mod renamed_lints; mod almost_complete_letter_range; mod approx_const; mod as_conversions; -mod as_underscore; mod asm_syntax; mod assertions_on_constants; mod assertions_on_result_states; @@ -181,12 +180,8 @@ mod await_holding_invalid; mod blocks_in_if_conditions; mod bool_assert_comparison; mod booleans; -mod borrow_as_ptr; mod borrow_deref_ref; -mod bytecount; -mod bytes_count_to_len; mod cargo; -mod case_sensitive_file_extension_comparisons; mod casts; mod checked_conversions; mod cognitive_complexity; @@ -239,7 +234,6 @@ mod from_over_into; mod from_str_radix_10; mod functions; mod future_not_send; -mod get_first; mod if_let_mutex; mod if_not_else; mod if_then_some_else_none; @@ -276,12 +270,10 @@ mod manual_async_fn; mod manual_bits; mod manual_instant_elapsed; mod manual_non_exhaustive; -mod manual_ok_or; mod manual_rem_euclid; mod manual_retain; +mod manual_string_new; mod manual_strip; -mod map_clone; -mod map_err_ignore; mod map_unit_fn; mod match_result_ok; mod matches; @@ -298,9 +290,9 @@ mod missing_enforced_import_rename; mod missing_inline; mod mixed_read_write_in_expression; mod module_style; +mod multi_assignments; mod mut_key; mod mut_mut; -mod mut_mutex_lock; mod mut_reference; mod mutable_debug_assertion; mod mutex_atomic; @@ -325,7 +317,6 @@ mod non_send_fields_in_send_ty; mod nonstandard_macro_braces; mod octal_escapes; mod only_used_in_recursion; -mod open_options; mod operators; mod option_env_unwrap; mod option_if_let_else; @@ -335,7 +326,6 @@ mod panic_unimplemented; mod partialeq_ne_impl; mod partialeq_to_none; mod pass_by_ref_or_value; -mod path_buf_push_overwrite; mod pattern_type_mismatch; mod precedence; mod ptr; @@ -355,7 +345,6 @@ mod redundant_static_lifetimes; mod ref_option_ref; mod reference; mod regex; -mod repeat_once; mod return_self_not_must_use; mod returns; mod same_name_method; @@ -367,7 +356,6 @@ mod single_char_lifetime_names; mod single_component_path_imports; mod size_of_in_element_count; mod slow_vector_initialization; -mod stable_sort_primitive; mod std_instead_of_core; mod strings; mod strlen_on_c_strings; @@ -381,23 +369,21 @@ mod to_digit_is_some; mod trailing_empty_array; mod trait_bounds; mod transmute; -mod transmuting_null; mod types; mod undocumented_unsafe_blocks; mod unicode; mod uninit_vec; -mod unit_hash; mod unit_return_expecting_ord; mod unit_types; mod unnamed_address; mod unnecessary_owned_empty_strings; mod unnecessary_self_imports; -mod unnecessary_sort_by; mod unnecessary_wraps; mod unnested_or_patterns; mod unsafe_removed_from_name; mod unused_async; mod unused_io_amount; +mod unused_peekable; mod unused_rounding; mod unused_self; mod unused_unit; @@ -408,8 +394,6 @@ mod use_self; mod useless_conversion; mod vec; mod vec_init_then_push; -mod vec_resize_to_zero; -mod verbose_file_reads; mod wildcard_imports; mod write; mod zero_div_zero; @@ -597,7 +581,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(blocks_in_if_conditions::BlocksInIfConditions)); store.register_late_pass(|| Box::new(unicode::Unicode)); store.register_late_pass(|| Box::new(uninit_vec::UninitVec)); - store.register_late_pass(|| Box::new(unit_hash::UnitHash)); store.register_late_pass(|| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd)); store.register_late_pass(|| Box::new(strings::StringAdd)); store.register_late_pass(|| Box::new(implicit_return::ImplicitReturn)); @@ -635,8 +618,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || Box::new(needless_question_mark::NeedlessQuestionMark)); store.register_late_pass(move || Box::new(casts::Casts::new(msrv))); store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv))); - store.register_late_pass(move || Box::new(map_clone::MapClone::new(msrv))); - store.register_late_pass(|| Box::new(size_of_in_element_count::SizeOfInElementCount)); store.register_late_pass(|| Box::new(same_name_method::SameNameMethod)); let max_suggested_slice_pattern_length = conf.max_suggested_slice_pattern_length; @@ -646,7 +627,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: msrv, )) }); - store.register_late_pass(|| Box::new(map_err_ignore::MapErrIgnore)); store.register_late_pass(|| Box::new(shadow::Shadow::default())); store.register_late_pass(|| Box::new(unit_types::UnitTypes)); store.register_late_pass(|| Box::new(loops::Loops)); @@ -654,7 +634,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(lifetimes::Lifetimes)); store.register_late_pass(|| Box::new(entry::HashMapPass)); store.register_late_pass(|| Box::new(minmax::MinMaxPass)); - store.register_late_pass(|| Box::new(open_options::OpenOptions)); store.register_late_pass(|| Box::new(zero_div_zero::ZeroDiv)); store.register_late_pass(|| Box::new(mutex_atomic::Mutex)); store.register_late_pass(|| Box::new(needless_update::NeedlessUpdate)); @@ -690,10 +669,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || Box::new(disallowed_names::DisallowedNames::new(disallowed_names.clone()))); let too_many_arguments_threshold = conf.too_many_arguments_threshold; let too_many_lines_threshold = conf.too_many_lines_threshold; + let large_error_threshold = conf.large_error_threshold; store.register_late_pass(move || { Box::new(functions::Functions::new( too_many_arguments_threshold, too_many_lines_threshold, + large_error_threshold, )) }); let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::>(); @@ -720,7 +701,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: ); store.register_late_pass(move || Box::new(pass_by_ref_or_value)); store.register_late_pass(|| Box::new(ref_option_ref::RefOptionRef)); - store.register_late_pass(|| Box::new(bytecount::ByteCount)); store.register_late_pass(|| Box::new(infinite_iter::InfiniteIter)); store.register_late_pass(|| Box::new(inline_fn_without_body::InlineFnWithoutBody)); store.register_late_pass(|| Box::new(useless_conversion::UselessConversion::default())); @@ -738,12 +718,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(ptr_offset_with_cast::PtrOffsetWithCast)); store.register_late_pass(|| Box::new(redundant_clone::RedundantClone)); store.register_late_pass(|| Box::new(slow_vector_initialization::SlowVectorInit)); - store.register_late_pass(|| Box::new(unnecessary_sort_by::UnnecessarySortBy)); store.register_late_pass(move || Box::new(unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api))); store.register_late_pass(|| Box::new(assertions_on_constants::AssertionsOnConstants)); store.register_late_pass(|| Box::new(assertions_on_result_states::AssertionsOnResultStates)); - store.register_late_pass(|| Box::new(transmuting_null::TransmutingNull)); - store.register_late_pass(|| Box::new(path_buf_push_overwrite::PathBufPushOverwrite)); store.register_late_pass(|| Box::new(inherent_to_string::InherentToString)); let max_trait_bounds = conf.max_trait_bounds; store.register_late_pass(move || Box::new(trait_bounds::TraitBounds::new(max_trait_bounds))); @@ -819,18 +796,15 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| Box::new(option_env_unwrap::OptionEnvUnwrap)); let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports; store.register_late_pass(move || Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports))); - store.register_late_pass(|| Box::new(verbose_file_reads::VerboseFileReads)); store.register_late_pass(|| Box::new(redundant_pub_crate::RedundantPubCrate::default())); store.register_late_pass(|| Box::new(unnamed_address::UnnamedAddress)); - store.register_late_pass(|| Box::new(dereference::Dereferencing::default())); + store.register_late_pass(move || Box::new(dereference::Dereferencing::new(msrv))); store.register_late_pass(|| Box::new(option_if_let_else::OptionIfLetElse)); store.register_late_pass(|| Box::new(future_not_send::FutureNotSend)); store.register_late_pass(|| Box::new(if_let_mutex::IfLetMutex)); store.register_late_pass(|| Box::new(if_not_else::IfNotElse)); store.register_late_pass(|| Box::new(equatable_if_let::PatternEquality)); - store.register_late_pass(|| Box::new(mut_mutex_lock::MutMutexLock)); store.register_late_pass(|| Box::new(manual_async_fn::ManualAsyncFn)); - store.register_late_pass(|| Box::new(vec_resize_to_zero::VecResizeToZero)); store.register_late_pass(|| Box::new(panic_in_result_fn::PanicInResultFn)); let single_char_binding_names_threshold = conf.single_char_binding_names_threshold; store.register_early_pass(move || { @@ -842,10 +816,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(move || Box::new(nonstandard_macro_braces::MacroBraces::new(¯o_matcher))); store.register_late_pass(|| Box::new(macro_use::MacroUseImports::default())); store.register_late_pass(|| Box::new(pattern_type_mismatch::PatternTypeMismatch)); - store.register_late_pass(|| Box::new(stable_sort_primitive::StableSortPrimitive)); - store.register_late_pass(|| Box::new(repeat_once::RepeatOnce)); store.register_late_pass(|| Box::new(unwrap_in_result::UnwrapInResult)); - store.register_late_pass(|| Box::new(manual_ok_or::ManualOkOr)); store.register_late_pass(|| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned)); store.register_late_pass(|| Box::new(async_yields_async::AsyncYieldsAsync)); let disallowed_methods = conf.disallowed_methods.clone(); @@ -857,9 +828,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(strings::StringToString)); store.register_late_pass(|| Box::new(zero_sized_map_values::ZeroSizedMapValues)); store.register_late_pass(|| Box::new(vec_init_then_push::VecInitThenPush::default())); - store.register_late_pass(|| { - Box::new(case_sensitive_file_extension_comparisons::CaseSensitiveFileExtensionComparisons) - }); store.register_late_pass(|| Box::new(redundant_slicing::RedundantSlicing)); store.register_late_pass(|| Box::new(from_str_radix_10::FromStrRadix10)); store.register_late_pass(move || Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv))); @@ -894,11 +862,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(return_self_not_must_use::ReturnSelfNotMustUse)); store.register_late_pass(|| Box::new(init_numbered_fields::NumberedFields)); store.register_early_pass(|| Box::new(single_char_lifetime_names::SingleCharLifetimeNames)); - store.register_late_pass(move || Box::new(borrow_as_ptr::BorrowAsPtr::new(msrv))); store.register_late_pass(move || Box::new(manual_bits::ManualBits::new(msrv))); store.register_late_pass(|| Box::new(default_union_representation::DefaultUnionRepresentation)); store.register_early_pass(|| Box::new(doc_link_with_quotes::DocLinkWithQuotes)); - store.register_late_pass(|| Box::new(only_used_in_recursion::OnlyUsedInRecursion)); + store.register_late_pass(|| Box::new(only_used_in_recursion::OnlyUsedInRecursion::default())); let allow_dbg_in_tests = conf.allow_dbg_in_tests; store.register_late_pass(move || Box::new(dbg_macro::DbgMacro::new(allow_dbg_in_tests))); let cargo_ignore_publish = conf.cargo_ignore_publish; @@ -912,18 +879,15 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings)); store.register_early_pass(|| Box::new(pub_use::PubUse)); store.register_late_pass(|| Box::new(format_push_string::FormatPushString)); - store.register_late_pass(|| Box::new(bytes_count_to_len::BytesCountToLen)); let max_include_file_size = conf.max_include_file_size; store.register_late_pass(move || Box::new(large_include_file::LargeIncludeFile::new(max_include_file_size))); store.register_late_pass(|| Box::new(strings::TrimSplitWhitespace)); store.register_late_pass(|| Box::new(rc_clone_in_vec_init::RcCloneInVecInit)); store.register_early_pass(|| Box::new(duplicate_mod::DuplicateMod::default())); - store.register_late_pass(|| Box::new(get_first::GetFirst)); store.register_early_pass(|| Box::new(unused_rounding::UnusedRounding)); store.register_early_pass(move || Box::new(almost_complete_letter_range::AlmostCompleteLetterRange::new(msrv))); store.register_late_pass(|| Box::new(swap_ptr_to_ref::SwapPtrToRef)); store.register_late_pass(|| Box::new(mismatching_type_param_order::TypeParamMismatch)); - store.register_late_pass(|| Box::new(as_underscore::AsUnderscore)); store.register_late_pass(|| Box::new(read_zero_byte_vec::ReadZeroByteVec)); store.register_late_pass(|| Box::new(default_instead_of_iter_empty::DefaultIterEmpty)); store.register_late_pass(move || Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv))); @@ -934,6 +898,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(std_instead_of_core::StdReexports::default())); store.register_late_pass(|| Box::new(manual_instant_elapsed::ManualInstantElapsed)); store.register_late_pass(|| Box::new(partialeq_to_none::PartialeqToNone)); + store.register_late_pass(|| Box::new(manual_string_new::ManualStringNew)); + store.register_late_pass(|| Box::new(unused_peekable::UnusedPeekable)); + store.register_early_pass(|| Box::new(multi_assignments::MultiAssignments)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/loops/needless_collect.rs b/clippy_lints/src/loops/needless_collect.rs index ddaffc751880..6d987f393fa5 100644 --- a/clippy_lints/src/loops/needless_collect.rs +++ b/clippy_lints/src/loops/needless_collect.rs @@ -1,5 +1,6 @@ use super::NEEDLESS_COLLECT; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; +use clippy_utils::higher; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; @@ -184,10 +185,19 @@ struct IterFunctionVisitor<'a, 'tcx> { impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> { fn visit_block(&mut self, block: &'tcx Block<'tcx>) { for (expr, hir_id) in block.stmts.iter().filter_map(get_expr_and_hir_id_from_stmt) { + if check_loop_kind(expr).is_some() { + continue; + } self.visit_block_expr(expr, hir_id); } if let Some(expr) = block.expr { - self.visit_block_expr(expr, None); + if let Some(loop_kind) = check_loop_kind(expr) { + if let LoopKind::Conditional(block_expr) = loop_kind { + self.visit_block_expr(block_expr, None); + } + } else { + self.visit_block_expr(expr, None); + } } } @@ -264,6 +274,28 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> { } } +enum LoopKind<'tcx> { + Conditional(&'tcx Expr<'tcx>), + Loop, +} + +fn check_loop_kind<'tcx>(expr: &Expr<'tcx>) -> Option> { + if let Some(higher::WhileLet { let_expr, .. }) = higher::WhileLet::hir(expr) { + return Some(LoopKind::Conditional(let_expr)); + } + if let Some(higher::While { condition, .. }) = higher::While::hir(expr) { + return Some(LoopKind::Conditional(condition)); + } + if let Some(higher::ForLoop { arg, .. }) = higher::ForLoop::hir(expr) { + return Some(LoopKind::Conditional(arg)); + } + if let ExprKind::Loop { .. } = expr.kind { + return Some(LoopKind::Loop); + } + + None +} + impl<'tcx> IterFunctionVisitor<'_, 'tcx> { fn visit_block_expr(&mut self, expr: &'tcx Expr<'tcx>, hir_id: Option) { self.current_statement_hir_id = hir_id; diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index a0ca7e6ff1e2..2502c8f880dd 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -192,7 +192,7 @@ fn suggested_ret(cx: &LateContext<'_>, output: &Ty<'_>) -> Option<(&'static str, match output.kind { TyKind::Tup(tys) if tys.is_empty() => { let sugg = "remove the return type"; - Some((sugg, "".into())) + Some((sugg, String::new())) }, _ => { let sugg = "return the output of the future directly"; diff --git a/clippy_lints/src/manual_ok_or.rs b/clippy_lints/src/manual_ok_or.rs deleted file mode 100644 index cf5004399b88..000000000000 --- a/clippy_lints/src/manual_ok_or.rs +++ /dev/null @@ -1,95 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; -use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_lang_ctor, path_to_local_id}; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::LangItem::{ResultErr, ResultOk}; -use rustc_hir::{Closure, Expr, ExprKind, PatKind}; -use rustc_lint::LintContext; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::lint::in_external_macro; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::symbol::sym; - -declare_clippy_lint! { - /// ### What it does - /// - /// Finds patterns that reimplement `Option::ok_or`. - /// - /// ### Why is this bad? - /// - /// Concise code helps focusing on behavior instead of boilerplate. - /// - /// ### Examples - /// ```rust - /// let foo: Option = None; - /// foo.map_or(Err("error"), |v| Ok(v)); - /// ``` - /// - /// Use instead: - /// ```rust - /// let foo: Option = None; - /// foo.ok_or("error"); - /// ``` - #[clippy::version = "1.49.0"] - pub MANUAL_OK_OR, - pedantic, - "finds patterns that can be encoded more concisely with `Option::ok_or`" -} - -declare_lint_pass!(ManualOkOr => [MANUAL_OK_OR]); - -impl<'tcx> LateLintPass<'tcx> for ManualOkOr { - fn check_expr(&mut self, cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'tcx>) { - if in_external_macro(cx.sess(), scrutinee.span) { - return; - } - - if_chain! { - if let ExprKind::MethodCall(method_segment, [receiver, or_expr, map_expr], _) = scrutinee.kind; - if method_segment.ident.name == sym!(map_or); - let ty = cx.typeck_results().expr_ty(receiver); - if is_type_diagnostic_item(cx, ty, sym::Option); - if is_ok_wrapping(cx, map_expr); - if let ExprKind::Call(Expr { kind: ExprKind::Path(err_path), .. }, &[ref err_arg]) = or_expr.kind; - if is_lang_ctor(cx, err_path, ResultErr); - if let Some(method_receiver_snippet) = snippet_opt(cx, receiver.span); - if let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span); - if let Some(indent) = indent_of(cx, scrutinee.span); - then { - let reindented_err_arg_snippet = - reindent_multiline(err_arg_snippet.into(), true, Some(indent + 4)); - span_lint_and_sugg( - cx, - MANUAL_OK_OR, - scrutinee.span, - "this pattern reimplements `Option::ok_or`", - "replace with", - format!( - "{}.ok_or({})", - method_receiver_snippet, - reindented_err_arg_snippet - ), - Applicability::MachineApplicable, - ); - } - } - } -} - -fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool { - if let ExprKind::Path(ref qpath) = map_expr.kind { - if is_lang_ctor(cx, qpath, ResultOk) { - return true; - } - } - if_chain! { - if let ExprKind::Closure(&Closure { body, .. }) = map_expr.kind; - let body = cx.tcx.hir().body(body); - if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind; - if let ExprKind::Call(Expr { kind: ExprKind::Path(ok_path), .. }, &[ref ok_arg]) = body.value.kind; - if is_lang_ctor(cx, ok_path, ResultOk); - then { path_to_local_id(ok_arg, param_id) } else { false } - } -} diff --git a/clippy_lints/src/manual_string_new.rs b/clippy_lints/src/manual_string_new.rs new file mode 100644 index 000000000000..a90eaa8fdcbe --- /dev/null +++ b/clippy_lints/src/manual_string_new.rs @@ -0,0 +1,140 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use rustc_ast::LitKind; +use rustc_errors::Applicability::MachineApplicable; +use rustc_hir::{Expr, ExprKind, PathSegment, QPath, TyKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::{sym, symbol, Span}; + +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for usage of `""` to create a `String`, such as `"".to_string()`, `"".to_owned()`, + /// `String::from("")` and others. + /// + /// ### Why is this bad? + /// + /// Different ways of creating an empty string makes your code less standardized, which can + /// be confusing. + /// + /// ### Example + /// ```rust + /// let a = "".to_string(); + /// let b: String = "".into(); + /// ``` + /// Use instead: + /// ```rust + /// let a = String::new(); + /// let b = String::new(); + /// ``` + #[clippy::version = "1.65.0"] + pub MANUAL_STRING_NEW, + pedantic, + "empty String is being created manually" +} +declare_lint_pass!(ManualStringNew => [MANUAL_STRING_NEW]); + +impl LateLintPass<'_> for ManualStringNew { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + if expr.span.from_expansion() { + return; + } + + let ty = cx.typeck_results().expr_ty(expr); + match ty.kind() { + ty::Adt(adt_def, _) if adt_def.is_struct() => { + if !cx.tcx.is_diagnostic_item(sym::String, adt_def.did()) { + return; + } + }, + _ => return, + } + + match expr.kind { + ExprKind::Call(func, args) => { + parse_call(cx, expr.span, func, args); + }, + ExprKind::MethodCall(path_segment, args, _) => { + parse_method_call(cx, expr.span, path_segment, args); + }, + _ => (), + } + } +} + +/// Checks if an expression's kind corresponds to an empty &str. +fn is_expr_kind_empty_str(expr_kind: &ExprKind<'_>) -> bool { + if let ExprKind::Lit(lit) = expr_kind && + let LitKind::Str(value, _) = lit.node && + value == symbol::kw::Empty + { + return true; + } + + false +} + +fn warn_then_suggest(cx: &LateContext<'_>, span: Span) { + span_lint_and_sugg( + cx, + MANUAL_STRING_NEW, + span, + "empty String is being created manually", + "consider using", + "String::new()".into(), + MachineApplicable, + ); +} + +/// Tries to parse an expression as a method call, emitting the warning if necessary. +fn parse_method_call(cx: &LateContext<'_>, span: Span, path_segment: &PathSegment<'_>, args: &[Expr<'_>]) { + if args.is_empty() { + // When parsing TryFrom::try_from(...).expect(...), we will have more than 1 arg. + return; + } + + let ident = path_segment.ident.as_str(); + let method_arg_kind = &args[0].kind; + if ["to_string", "to_owned", "into"].contains(&ident) && is_expr_kind_empty_str(method_arg_kind) { + warn_then_suggest(cx, span); + } else if let ExprKind::Call(func, args) = method_arg_kind { + // If our first argument is a function call itself, it could be an `unwrap`-like function. + // E.g. String::try_from("hello").unwrap(), TryFrom::try_from("").expect("hello"), etc. + parse_call(cx, span, func, args); + } +} + +/// Tries to parse an expression as a function call, emitting the warning if necessary. +fn parse_call(cx: &LateContext<'_>, span: Span, func: &Expr<'_>, args: &[Expr<'_>]) { + if args.len() != 1 { + return; + } + + let arg_kind = &args[0].kind; + if let ExprKind::Path(qpath) = &func.kind { + if let QPath::TypeRelative(_, _) = qpath { + // String::from(...) or String::try_from(...) + if let QPath::TypeRelative(ty, path_seg) = qpath && + [sym::from, sym::try_from].contains(&path_seg.ident.name) && + let TyKind::Path(qpath) = &ty.kind && + let QPath::Resolved(_, path) = qpath && + let [path_seg] = path.segments && + path_seg.ident.name == sym::String && + is_expr_kind_empty_str(arg_kind) + { + warn_then_suggest(cx, span); + } + } else if let QPath::Resolved(_, path) = qpath { + // From::from(...) or TryFrom::try_from(...) + if let [path_seg1, path_seg2] = path.segments && + is_expr_kind_empty_str(arg_kind) && ( + (path_seg1.ident.name == sym::From && path_seg2.ident.name == sym::from) || + (path_seg1.ident.name == sym::TryFrom && path_seg2.ident.name == sym::try_from) + ) + { + warn_then_suggest(cx, span); + } + } + } +} diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs deleted file mode 100644 index 95c312f1fe26..000000000000 --- a/clippy_lints/src/map_clone.rs +++ /dev/null @@ -1,167 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::{is_copy, is_type_diagnostic_item}; -use clippy_utils::{is_trait_method, meets_msrv, msrvs, peel_blocks}; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir as hir; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::mir::Mutability; -use rustc_middle::ty; -use rustc_middle::ty::adjustment::Adjust; -use rustc_semver::RustcVersion; -use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::symbol::Ident; -use rustc_span::{sym, Span}; - -declare_clippy_lint! { - /// ### What it does - /// Checks for usage of `map(|x| x.clone())` or - /// dereferencing closures for `Copy` types, on `Iterator` or `Option`, - /// and suggests `cloned()` or `copied()` instead - /// - /// ### Why is this bad? - /// Readability, this can be written more concisely - /// - /// ### Example - /// ```rust - /// let x = vec![42, 43]; - /// let y = x.iter(); - /// let z = y.map(|i| *i); - /// ``` - /// - /// The correct use would be: - /// - /// ```rust - /// let x = vec![42, 43]; - /// let y = x.iter(); - /// let z = y.cloned(); - /// ``` - #[clippy::version = "pre 1.29.0"] - pub MAP_CLONE, - style, - "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types" -} - -pub struct MapClone { - msrv: Option, -} - -impl_lint_pass!(MapClone => [MAP_CLONE]); - -impl MapClone { - pub fn new(msrv: Option) -> Self { - Self { msrv } - } -} - -impl<'tcx> LateLintPass<'tcx> for MapClone { - fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) { - if e.span.from_expansion() { - return; - } - - if_chain! { - if let hir::ExprKind::MethodCall(method, args, _) = e.kind; - if args.len() == 2; - if method.ident.name == sym::map; - let ty = cx.typeck_results().expr_ty(&args[0]); - if is_type_diagnostic_item(cx, ty, sym::Option) || is_trait_method(cx, e, sym::Iterator); - if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = args[1].kind; - then { - let closure_body = cx.tcx.hir().body(body); - let closure_expr = peel_blocks(&closure_body.value); - match closure_body.params[0].pat.kind { - hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding( - hir::BindingAnnotation::Unannotated, .., name, None - ) = inner.kind { - if ident_eq(name, closure_expr) { - self.lint_explicit_closure(cx, e.span, args[0].span, true); - } - }, - hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, .., name, None) => { - match closure_expr.kind { - hir::ExprKind::Unary(hir::UnOp::Deref, inner) => { - if ident_eq(name, inner) { - if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() { - self.lint_explicit_closure(cx, e.span, args[0].span, true); - } - } - }, - hir::ExprKind::MethodCall(method, [obj], _) => if_chain! { - if ident_eq(name, obj) && method.ident.name == sym::clone; - if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id); - if let Some(trait_id) = cx.tcx.trait_of_item(fn_id); - if cx.tcx.lang_items().clone_trait().map_or(false, |id| id == trait_id); - // no autoderefs - if !cx.typeck_results().expr_adjustments(obj).iter() - .any(|a| matches!(a.kind, Adjust::Deref(Some(..)))); - then { - let obj_ty = cx.typeck_results().expr_ty(obj); - if let ty::Ref(_, ty, mutability) = obj_ty.kind() { - if matches!(mutability, Mutability::Not) { - let copy = is_copy(cx, *ty); - self.lint_explicit_closure(cx, e.span, args[0].span, copy); - } - } else { - lint_needless_cloning(cx, e.span, args[0].span); - } - } - }, - _ => {}, - } - }, - _ => {}, - } - } - } - } - - extract_msrv_attr!(LateContext); -} - -fn ident_eq(name: Ident, path: &hir::Expr<'_>) -> bool { - if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = path.kind { - path.segments.len() == 1 && path.segments[0].ident == name - } else { - false - } -} - -fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) { - span_lint_and_sugg( - cx, - MAP_CLONE, - root.trim_start(receiver).unwrap(), - "you are needlessly cloning iterator elements", - "remove the `map` call", - String::new(), - Applicability::MachineApplicable, - ); -} - -impl MapClone { - fn lint_explicit_closure(&self, cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool) { - let mut applicability = Applicability::MachineApplicable; - - let (message, sugg_method) = if is_copy && meets_msrv(self.msrv, msrvs::ITERATOR_COPIED) { - ("you are using an explicit closure for copying elements", "copied") - } else { - ("you are using an explicit closure for cloning elements", "cloned") - }; - - span_lint_and_sugg( - cx, - MAP_CLONE, - replace, - message, - &format!("consider calling the dedicated `{}` method", sugg_method), - format!( - "{}.{}()", - snippet_with_applicability(cx, root, "..", &mut applicability), - sugg_method, - ), - applicability, - ); - } -} diff --git a/clippy_lints/src/map_err_ignore.rs b/clippy_lints/src/map_err_ignore.rs deleted file mode 100644 index 1e542447c96e..000000000000 --- a/clippy_lints/src/map_err_ignore.rs +++ /dev/null @@ -1,154 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_help; -use rustc_hir::{CaptureBy, Closure, Expr, ExprKind, PatKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -declare_clippy_lint! { - /// ### What it does - /// Checks for instances of `map_err(|_| Some::Enum)` - /// - /// ### Why is this bad? - /// This `map_err` throws away the original error rather than allowing the enum to contain and report the cause of the error - /// - /// ### Example - /// Before: - /// ```rust - /// use std::fmt; - /// - /// #[derive(Debug)] - /// enum Error { - /// Indivisible, - /// Remainder(u8), - /// } - /// - /// impl fmt::Display for Error { - /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - /// match self { - /// Error::Indivisible => write!(f, "could not divide input by three"), - /// Error::Remainder(remainder) => write!( - /// f, - /// "input is not divisible by three, remainder = {}", - /// remainder - /// ), - /// } - /// } - /// } - /// - /// impl std::error::Error for Error {} - /// - /// fn divisible_by_3(input: &str) -> Result<(), Error> { - /// input - /// .parse::() - /// .map_err(|_| Error::Indivisible) - /// .map(|v| v % 3) - /// .and_then(|remainder| { - /// if remainder == 0 { - /// Ok(()) - /// } else { - /// Err(Error::Remainder(remainder as u8)) - /// } - /// }) - /// } - /// ``` - /// - /// After: - /// ```rust - /// use std::{fmt, num::ParseIntError}; - /// - /// #[derive(Debug)] - /// enum Error { - /// Indivisible(ParseIntError), - /// Remainder(u8), - /// } - /// - /// impl fmt::Display for Error { - /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - /// match self { - /// Error::Indivisible(_) => write!(f, "could not divide input by three"), - /// Error::Remainder(remainder) => write!( - /// f, - /// "input is not divisible by three, remainder = {}", - /// remainder - /// ), - /// } - /// } - /// } - /// - /// impl std::error::Error for Error { - /// fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - /// match self { - /// Error::Indivisible(source) => Some(source), - /// _ => None, - /// } - /// } - /// } - /// - /// fn divisible_by_3(input: &str) -> Result<(), Error> { - /// input - /// .parse::() - /// .map_err(Error::Indivisible) - /// .map(|v| v % 3) - /// .and_then(|remainder| { - /// if remainder == 0 { - /// Ok(()) - /// } else { - /// Err(Error::Remainder(remainder as u8)) - /// } - /// }) - /// } - /// ``` - #[clippy::version = "1.48.0"] - pub MAP_ERR_IGNORE, - restriction, - "`map_err` should not ignore the original error" -} - -declare_lint_pass!(MapErrIgnore => [MAP_ERR_IGNORE]); - -impl<'tcx> LateLintPass<'tcx> for MapErrIgnore { - // do not try to lint if this is from a macro or desugaring - fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) { - if e.span.from_expansion() { - return; - } - - // check if this is a method call (e.g. x.foo()) - if let ExprKind::MethodCall(method, [_, arg], _) = e.kind { - // only work if the method name is `map_err` and there are only 2 arguments (e.g. x.map_err(|_|[1] - // Enum::Variant[2])) - if method.ident.name == sym!(map_err) { - // make sure the first argument is a closure, and grab the CaptureRef, BodyId, and fn_decl_span - // fields - if let ExprKind::Closure(&Closure { - capture_clause, - body, - fn_decl_span, - .. - }) = arg.kind - { - // check if this is by Reference (meaning there's no move statement) - if capture_clause == CaptureBy::Ref { - // Get the closure body to check the parameters and values - let closure_body = cx.tcx.hir().body(body); - // make sure there's only one parameter (`|_|`) - if closure_body.params.len() == 1 { - // make sure that parameter is the wild token (`_`) - if let PatKind::Wild = closure_body.params[0].pat.kind { - // span the area of the closure capture and warn that the - // original error will be thrown away - span_lint_and_help( - cx, - MAP_ERR_IGNORE, - fn_decl_span, - "`map_err(|_|...` wildcard pattern discards the original error", - None, - "consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`)", - ); - } - } - } - } - } - } - } -} diff --git a/clippy_lints/src/matches/match_like_matches.rs b/clippy_lints/src/matches/match_like_matches.rs index 0da4833f1dfe..34cc082687ec 100644 --- a/clippy_lints/src/matches/match_like_matches.rs +++ b/clippy_lints/src/matches/match_like_matches.rs @@ -1,10 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_wild; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::span_contains_comment; use rustc_ast::{Attribute, LitKind}; use rustc_errors::Applicability; use rustc_hir::{Arm, BorrowKind, Expr, ExprKind, Guard, Pat}; -use rustc_lint::LateContext; +use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty; use rustc_span::source_map::Spanned; @@ -76,6 +77,7 @@ where >, { if_chain! { + if !span_contains_comment(cx.sess().source_map(), expr.span); if iter.len() >= 2; if cx.typeck_results().expr_ty(expr).is_bool(); if let Some((_, last_pat_opt, last_expr, _)) = iter.next_back(); diff --git a/clippy_lints/src/matches/needless_match.rs b/clippy_lints/src/matches/needless_match.rs index fa19cddd35ec..6f037339ec75 100644 --- a/clippy_lints/src/matches/needless_match.rs +++ b/clippy_lints/src/matches/needless_match.rs @@ -8,7 +8,7 @@ use clippy_utils::{ }; use rustc_errors::Applicability; use rustc_hir::LangItem::OptionNone; -use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, FnRetTy, Node, Pat, PatKind, Path, QPath}; +use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, FnRetTy, Guard, Node, Pat, PatKind, Path, QPath}; use rustc_lint::LateContext; use rustc_span::sym; use rustc_typeck::hir_ty_to_ty; @@ -65,8 +65,26 @@ pub(crate) fn check_if_let<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'_>, if_let: fn check_all_arms(cx: &LateContext<'_>, match_expr: &Expr<'_>, arms: &[Arm<'_>]) -> bool { for arm in arms { let arm_expr = peel_blocks_with_stmt(arm.body); + + if let Some(guard_expr) = &arm.guard { + match guard_expr { + // gives up if `pat if expr` can have side effects + Guard::If(if_cond) => { + if if_cond.can_have_side_effects() { + return false; + } + }, + // gives up `pat if let ...` arm + Guard::IfLet(_) => { + return false; + }, + }; + } + if let PatKind::Wild = arm.pat.kind { - return eq_expr_value(cx, match_expr, strip_return(arm_expr)); + if !eq_expr_value(cx, match_expr, strip_return(arm_expr)) { + return false; + } } else if !pat_same_as_expr(arm.pat, arm_expr) { return false; } diff --git a/clippy_lints/src/methods/bytecount.rs b/clippy_lints/src/methods/bytecount.rs new file mode 100644 index 000000000000..6a7c63d76f72 --- /dev/null +++ b/clippy_lints/src/methods/bytecount.rs @@ -0,0 +1,70 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::match_type; +use clippy_utils::visitors::is_local_used; +use clippy_utils::{path_to_local_id, paths, peel_blocks, peel_ref_operators, strip_pat_refs}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Closure, Expr, ExprKind, PatKind}; +use rustc_lint::LateContext; +use rustc_middle::ty::{self, UintTy}; +use rustc_span::sym; + +use super::NAIVE_BYTECOUNT; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + filter_recv: &'tcx Expr<'_>, + filter_arg: &'tcx Expr<'_>, +) { + if_chain! { + if let ExprKind::Closure(&Closure { body, .. }) = filter_arg.kind; + let body = cx.tcx.hir().body(body); + if let [param] = body.params; + if let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind; + if let ExprKind::Binary(ref op, l, r) = body.value.kind; + if op.node == BinOpKind::Eq; + if match_type(cx, + cx.typeck_results().expr_ty(filter_recv).peel_refs(), + &paths::SLICE_ITER); + let operand_is_arg = |expr| { + let expr = peel_ref_operators(cx, peel_blocks(expr)); + path_to_local_id(expr, arg_id) + }; + let needle = if operand_is_arg(l) { + r + } else if operand_is_arg(r) { + l + } else { + return; + }; + if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(needle).peel_refs().kind(); + if !is_local_used(cx, needle, arg_id); + then { + let haystack = if let ExprKind::MethodCall(path, args, _) = + filter_recv.kind { + let p = path.ident.name; + if (p == sym::iter || p == sym!(iter_mut)) && args.len() == 1 { + &args[0] + } else { + filter_recv + } + } else { + filter_recv + }; + let mut applicability = Applicability::MaybeIncorrect; + span_lint_and_sugg( + cx, + NAIVE_BYTECOUNT, + expr.span, + "you appear to be counting bytes the naive way", + "consider using the bytecount crate", + format!("bytecount::count({}, {})", + snippet_with_applicability(cx, haystack.span, "..", &mut applicability), + snippet_with_applicability(cx, needle.span, "..", &mut applicability)), + applicability, + ); + } + }; +} diff --git a/clippy_lints/src/methods/bytes_count_to_len.rs b/clippy_lints/src/methods/bytes_count_to_len.rs new file mode 100644 index 000000000000..fcfc25b523da --- /dev/null +++ b/clippy_lints/src/methods/bytes_count_to_len.rs @@ -0,0 +1,37 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::is_type_diagnostic_item; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::BYTES_COUNT_TO_LEN; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + count_recv: &'tcx hir::Expr<'_>, + bytes_recv: &'tcx hir::Expr<'_>, +) { + if_chain! { + if let Some(bytes_id) = cx.typeck_results().type_dependent_def_id(count_recv.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(bytes_id); + if cx.tcx.type_of(impl_id).is_str(); + let ty = cx.typeck_results().expr_ty(bytes_recv).peel_refs(); + if ty.is_str() || is_type_diagnostic_item(cx, ty, sym::String); + then { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + BYTES_COUNT_TO_LEN, + expr.span, + "using long and hard to read `.bytes().count()`", + "consider calling `.len()` instead", + format!("{}.len()", snippet_with_applicability(cx, bytes_recv.span, "..", &mut applicability)), + applicability + ); + } + }; +} diff --git a/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs new file mode 100644 index 000000000000..b3c2c7c9a2dc --- /dev/null +++ b/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -0,0 +1,41 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::ty::is_type_diagnostic_item; +use if_chain::if_chain; +use rustc_ast::ast::LitKind; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::{source_map::Spanned, symbol::sym, Span}; + +use super::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + call_span: Span, + recv: &'tcx Expr<'_>, + arg: &'tcx Expr<'_>, +) { + if_chain! { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(method_id); + if cx.tcx.type_of(impl_id).is_str(); + if let ExprKind::Lit(Spanned { node: LitKind::Str(ext_literal, ..), ..}) = arg.kind; + if (2..=6).contains(&ext_literal.as_str().len()); + let ext_str = ext_literal.as_str(); + if ext_str.starts_with('.'); + if ext_str.chars().skip(1).all(|c| c.is_uppercase() || c.is_ascii_digit()) + || ext_str.chars().skip(1).all(|c| c.is_lowercase() || c.is_ascii_digit()); + let recv_ty = cx.typeck_results().expr_ty(recv).peel_refs(); + if recv_ty.is_str() || is_type_diagnostic_item(cx, recv_ty, sym::String); + then { + span_lint_and_help( + cx, + CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, + call_span, + "case-sensitive file extension comparison", + None, + "consider using a case-insensitive comparison instead", + ); + } + } +} diff --git a/clippy_lints/src/methods/collapsible_str_replace.rs b/clippy_lints/src/methods/collapsible_str_replace.rs new file mode 100644 index 000000000000..561033be5b6a --- /dev/null +++ b/clippy_lints/src/methods/collapsible_str_replace.rs @@ -0,0 +1,96 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::visitors::for_each_expr; +use clippy_utils::{eq_expr_value, get_parent_expr}; +use core::ops::ControlFlow; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use std::collections::VecDeque; + +use super::method_call; +use super::COLLAPSIBLE_STR_REPLACE; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'tcx>, + from: &'tcx hir::Expr<'tcx>, + to: &'tcx hir::Expr<'tcx>, +) { + let replace_methods = collect_replace_calls(cx, expr, to); + if replace_methods.methods.len() > 1 { + let from_kind = cx.typeck_results().expr_ty(from).peel_refs().kind(); + // If the parent node's `to` argument is the same as the `to` argument + // of the last replace call in the current chain, don't lint as it was already linted + if let Some(parent) = get_parent_expr(cx, expr) + && let Some(("replace", [_, current_from, current_to], _)) = method_call(parent) + && eq_expr_value(cx, to, current_to) + && from_kind == cx.typeck_results().expr_ty(current_from).peel_refs().kind() + { + return; + } + + check_consecutive_replace_calls(cx, expr, &replace_methods, to); + } +} + +struct ReplaceMethods<'tcx> { + methods: VecDeque<&'tcx hir::Expr<'tcx>>, + from_args: VecDeque<&'tcx hir::Expr<'tcx>>, +} + +fn collect_replace_calls<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'tcx>, + to_arg: &'tcx hir::Expr<'tcx>, +) -> ReplaceMethods<'tcx> { + let mut methods = VecDeque::new(); + let mut from_args = VecDeque::new(); + + let _: Option<()> = for_each_expr(expr, |e| { + if let Some(("replace", [_, from, to], _)) = method_call(e) { + if eq_expr_value(cx, to_arg, to) && cx.typeck_results().expr_ty(from).peel_refs().is_char() { + methods.push_front(e); + from_args.push_front(from); + ControlFlow::Continue(()) + } else { + ControlFlow::BREAK + } + } else { + ControlFlow::Continue(()) + } + }); + + ReplaceMethods { methods, from_args } +} + +/// Check a chain of `str::replace` calls for `collapsible_str_replace` lint. +fn check_consecutive_replace_calls<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'tcx>, + replace_methods: &ReplaceMethods<'tcx>, + to_arg: &'tcx hir::Expr<'tcx>, +) { + let from_args = &replace_methods.from_args; + let from_arg_reprs: Vec = from_args + .iter() + .map(|from_arg| snippet(cx, from_arg.span, "..").to_string()) + .collect(); + let app = Applicability::MachineApplicable; + let earliest_replace_call = replace_methods.methods.front().unwrap(); + if let Some((_, [..], span_lo)) = method_call(earliest_replace_call) { + span_lint_and_sugg( + cx, + COLLAPSIBLE_STR_REPLACE, + expr.span.with_lo(span_lo.lo()), + "used consecutive `str::replace` call", + "replace with", + format!( + "replace([{}], {})", + from_arg_reprs.join(", "), + snippet(cx, to_arg.span, ".."), + ), + app, + ); + } +} diff --git a/clippy_lints/src/methods/expect_used.rs b/clippy_lints/src/methods/expect_used.rs index 5ef08ca6290b..d59fefa1ddc0 100644 --- a/clippy_lints/src/methods/expect_used.rs +++ b/clippy_lints/src/methods/expect_used.rs @@ -7,18 +7,26 @@ use rustc_span::sym; use super::EXPECT_USED; -/// lint use of `expect()` for `Option`s and `Result`s -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, allow_expect_in_tests: bool) { +/// lint use of `expect()` or `expect_err` for `Result` and `expect()` for `Option`. +pub(super) fn check( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + recv: &hir::Expr<'_>, + is_err: bool, + allow_expect_in_tests: bool, +) { let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); - let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) { + let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err { Some((EXPECT_USED, "an Option", "None", "")) } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) { - Some((EXPECT_USED, "a Result", "Err", "an ")) + Some((EXPECT_USED, "a Result", if is_err { "Ok" } else { "Err" }, "an ")) } else { None }; + let method = if is_err { "expect_err" } else { "expect" }; + if allow_expect_in_tests && is_in_test_function(cx.tcx, expr.hir_id) { return; } @@ -28,7 +36,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr cx, lint, expr.span, - &format!("used `expect()` on `{kind}` value"), + &format!("used `{method}()` on `{kind}` value"), None, &format!("if this value is {none_prefix}`{none_value}`, it will panic"), ); diff --git a/clippy_lints/src/methods/get_first.rs b/clippy_lints/src/methods/get_first.rs new file mode 100644 index 000000000000..4de77de74042 --- /dev/null +++ b/clippy_lints/src/methods/get_first.rs @@ -0,0 +1,39 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_slice_of_primitives; +use clippy_utils::source::snippet_with_applicability; +use if_chain::if_chain; +use rustc_ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_span::source_map::Spanned; + +use super::GET_FIRST; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx hir::Expr<'_>, + recv: &'tcx hir::Expr<'_>, + arg: &'tcx hir::Expr<'_>, +) { + if_chain! { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(method_id); + if cx.tcx.type_of(impl_id).is_slice(); + if let Some(_) = is_slice_of_primitives(cx, recv); + if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = arg.kind; + then { + let mut app = Applicability::MachineApplicable; + let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app); + span_lint_and_sugg( + cx, + GET_FIRST, + expr.span, + &format!("accessing first element with `{0}.get(0)`", slice_name), + "try", + format!("{}.first()", slice_name), + app, + ); + } + } +} diff --git a/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs new file mode 100644 index 000000000000..cea7b0d82ff3 --- /dev/null +++ b/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs @@ -0,0 +1,107 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::{get_expr_use_or_unification_node, is_lang_ctor, is_no_std_crate}; + +use rustc_errors::Applicability; +use rustc_hir::LangItem::{OptionNone, OptionSome}; +use rustc_hir::{Expr, ExprKind, Node}; +use rustc_lint::LateContext; + +use super::{ITER_ON_EMPTY_COLLECTIONS, ITER_ON_SINGLE_ITEMS}; + +enum IterType { + Iter, + IterMut, + IntoIter, +} + +impl IterType { + fn ref_prefix(&self) -> &'static str { + match self { + Self::Iter => "&", + Self::IterMut => "&mut ", + Self::IntoIter => "", + } + } +} + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, method_name: &str, recv: &Expr<'_>) { + let item = match &recv.kind { + ExprKind::Array(v) if v.len() <= 1 => v.first(), + ExprKind::Path(p) => { + if is_lang_ctor(cx, p, OptionNone) { + None + } else { + return; + } + }, + ExprKind::Call(f, some_args) if some_args.len() == 1 => { + if let ExprKind::Path(p) = &f.kind { + if is_lang_ctor(cx, p, OptionSome) { + Some(&some_args[0]) + } else { + return; + } + } else { + return; + } + }, + _ => return, + }; + let iter_type = match method_name { + "iter" => IterType::Iter, + "iter_mut" => IterType::IterMut, + "into_iter" => IterType::IntoIter, + _ => return, + }; + + let is_unified = match get_expr_use_or_unification_node(cx.tcx, expr) { + Some((Node::Expr(parent), child_id)) => match parent.kind { + ExprKind::If(e, _, _) | ExprKind::Match(e, _, _) if e.hir_id == child_id => false, + ExprKind::If(_, _, _) + | ExprKind::Match(_, _, _) + | ExprKind::Closure(_) + | ExprKind::Ret(_) + | ExprKind::Break(_, _) => true, + _ => false, + }, + Some((Node::Stmt(_) | Node::Local(_), _)) => false, + _ => true, + }; + + if is_unified { + return; + } + + if let Some(i) = item { + let sugg = format!( + "{}::iter::once({}{})", + if is_no_std_crate(cx) { "core" } else { "std" }, + iter_type.ref_prefix(), + snippet(cx, i.span, "...") + ); + span_lint_and_sugg( + cx, + ITER_ON_SINGLE_ITEMS, + expr.span, + &format!("`{method_name}` call on a collection with only one item"), + "try", + sugg, + Applicability::MaybeIncorrect, + ); + } else { + span_lint_and_sugg( + cx, + ITER_ON_EMPTY_COLLECTIONS, + expr.span, + &format!("`{method_name}` call on an empty collection"), + "try", + if is_no_std_crate(cx) { + "core::iter::empty()".to_string() + } else { + "std::iter::empty()".to_string() + }, + Applicability::MaybeIncorrect, + ); + } +} diff --git a/clippy_lints/src/methods/manual_ok_or.rs b/clippy_lints/src/methods/manual_ok_or.rs new file mode 100644 index 000000000000..ffd2f4a38b8a --- /dev/null +++ b/clippy_lints/src/methods/manual_ok_or.rs @@ -0,0 +1,64 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_lang_ctor, path_to_local_id}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::LangItem::{ResultErr, ResultOk}; +use rustc_hir::{Closure, Expr, ExprKind, PatKind}; +use rustc_lint::LateContext; +use rustc_span::symbol::sym; + +use super::MANUAL_OK_OR; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + recv: &'tcx Expr<'_>, + or_expr: &'tcx Expr<'_>, + map_expr: &'tcx Expr<'_>, +) { + if_chain! { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(method_id); + if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Option); + if let ExprKind::Call(Expr { kind: ExprKind::Path(err_path), .. }, [err_arg]) = or_expr.kind; + if is_lang_ctor(cx, err_path, ResultErr); + if is_ok_wrapping(cx, map_expr); + if let Some(recv_snippet) = snippet_opt(cx, recv.span); + if let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span); + if let Some(indent) = indent_of(cx, expr.span); + then { + let reindented_err_arg_snippet = reindent_multiline(err_arg_snippet.into(), true, Some(indent + 4)); + span_lint_and_sugg( + cx, + MANUAL_OK_OR, + expr.span, + "this pattern reimplements `Option::ok_or`", + "replace with", + format!( + "{}.ok_or({})", + recv_snippet, + reindented_err_arg_snippet + ), + Applicability::MachineApplicable, + ); + } + } +} + +fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool { + if let ExprKind::Path(ref qpath) = map_expr.kind { + if is_lang_ctor(cx, qpath, ResultOk) { + return true; + } + } + if_chain! { + if let ExprKind::Closure(&Closure { body, .. }) = map_expr.kind; + let body = cx.tcx.hir().body(body); + if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind; + if let ExprKind::Call(Expr { kind: ExprKind::Path(ok_path), .. }, &[ref ok_arg]) = body.value.kind; + if is_lang_ctor(cx, ok_path, ResultOk); + then { path_to_local_id(ok_arg, param_id) } else { false } + } +} diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs new file mode 100644 index 000000000000..ffedda95ff8e --- /dev/null +++ b/clippy_lints/src/methods/map_clone.rs @@ -0,0 +1,122 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::ty::{is_copy, is_type_diagnostic_item}; +use clippy_utils::{is_diag_trait_item, meets_msrv, msrvs, peel_blocks}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_middle::mir::Mutability; +use rustc_middle::ty; +use rustc_middle::ty::adjustment::Adjust; +use rustc_semver::RustcVersion; +use rustc_span::symbol::Ident; +use rustc_span::{sym, Span}; + +use super::MAP_CLONE; + +pub(super) fn check<'tcx>( + cx: &LateContext<'_>, + e: &hir::Expr<'_>, + recv: &hir::Expr<'_>, + arg: &'tcx hir::Expr<'_>, + msrv: Option, +) { + if_chain! { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id); + if cx.tcx.impl_of_method(method_id) + .map_or(false, |id| is_type_diagnostic_item(cx, cx.tcx.type_of(id), sym::Option)) + || is_diag_trait_item(cx, method_id, sym::Iterator); + if let hir::ExprKind::Closure(&hir::Closure{ body, .. }) = arg.kind; + then { + let closure_body = cx.tcx.hir().body(body); + let closure_expr = peel_blocks(&closure_body.value); + match closure_body.params[0].pat.kind { + hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding( + hir::BindingAnnotation::Unannotated, .., name, None + ) = inner.kind { + if ident_eq(name, closure_expr) { + lint_explicit_closure(cx, e.span, recv.span, true, msrv); + } + }, + hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, .., name, None) => { + match closure_expr.kind { + hir::ExprKind::Unary(hir::UnOp::Deref, inner) => { + if ident_eq(name, inner) { + if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() { + lint_explicit_closure(cx, e.span, recv.span, true, msrv); + } + } + }, + hir::ExprKind::MethodCall(method, [obj], _) => if_chain! { + if ident_eq(name, obj) && method.ident.name == sym::clone; + if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id); + if let Some(trait_id) = cx.tcx.trait_of_item(fn_id); + if cx.tcx.lang_items().clone_trait().map_or(false, |id| id == trait_id); + // no autoderefs + if !cx.typeck_results().expr_adjustments(obj).iter() + .any(|a| matches!(a.kind, Adjust::Deref(Some(..)))); + then { + let obj_ty = cx.typeck_results().expr_ty(obj); + if let ty::Ref(_, ty, mutability) = obj_ty.kind() { + if matches!(mutability, Mutability::Not) { + let copy = is_copy(cx, *ty); + lint_explicit_closure(cx, e.span, recv.span, copy, msrv); + } + } else { + lint_needless_cloning(cx, e.span, recv.span); + } + } + }, + _ => {}, + } + }, + _ => {}, + } + } + } +} + +fn ident_eq(name: Ident, path: &hir::Expr<'_>) -> bool { + if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = path.kind { + path.segments.len() == 1 && path.segments[0].ident == name + } else { + false + } +} + +fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) { + span_lint_and_sugg( + cx, + MAP_CLONE, + root.trim_start(receiver).unwrap(), + "you are needlessly cloning iterator elements", + "remove the `map` call", + String::new(), + Applicability::MachineApplicable, + ); +} + +fn lint_explicit_closure(cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool, msrv: Option) { + let mut applicability = Applicability::MachineApplicable; + + let (message, sugg_method) = if is_copy && meets_msrv(msrv, msrvs::ITERATOR_COPIED) { + ("you are using an explicit closure for copying elements", "copied") + } else { + ("you are using an explicit closure for cloning elements", "cloned") + }; + + span_lint_and_sugg( + cx, + MAP_CLONE, + replace, + message, + &format!("consider calling the dedicated `{}` method", sugg_method), + format!( + "{}.{}()", + snippet_with_applicability(cx, root, "..", &mut applicability), + sugg_method, + ), + applicability, + ); +} diff --git a/clippy_lints/src/methods/map_err_ignore.rs b/clippy_lints/src/methods/map_err_ignore.rs new file mode 100644 index 000000000000..1fb6617145e7 --- /dev/null +++ b/clippy_lints/src/methods/map_err_ignore.rs @@ -0,0 +1,34 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::ty::is_type_diagnostic_item; +use rustc_hir::{CaptureBy, Closure, Expr, ExprKind, PatKind}; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::MAP_ERR_IGNORE; + +pub(super) fn check<'tcx>(cx: &LateContext<'_>, e: &Expr<'_>, arg: &'tcx Expr<'_>) { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) + && let Some(impl_id) = cx.tcx.impl_of_method(method_id) + && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Result) + && let ExprKind::Closure(&Closure { + capture_clause: CaptureBy::Ref, + body, + fn_decl_span, + .. + }) = arg.kind + && let closure_body = cx.tcx.hir().body(body) + && let [param] = closure_body.params + && let PatKind::Wild = param.pat.kind + { + // span the area of the closure capture and warn that the + // original error will be thrown away + span_lint_and_help( + cx, + MAP_ERR_IGNORE, + fn_decl_span, + "`map_err(|_|...` wildcard pattern discards the original error", + None, + "consider storing the original error as a source in the new error, or silence this warning using an ignored identifier (`.map_err(|_foo| ...`)", + ); + } +} diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5ac6b09f0aa2..a0d190a58aff 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1,5 +1,8 @@ mod bind_instead_of_map; +mod bytecount; +mod bytes_count_to_len; mod bytes_nth; +mod case_sensitive_file_extension_comparisons; mod chars_cmp; mod chars_cmp_with_unwrap; mod chars_last_cmp; @@ -9,6 +12,7 @@ mod chars_next_cmp_with_unwrap; mod clone_on_copy; mod clone_on_ref_ptr; mod cloned_instead_of_copied; +mod collapsible_str_replace; mod err_expect; mod expect_fun_call; mod expect_used; @@ -21,6 +25,7 @@ mod filter_next; mod flat_map_identity; mod flat_map_option; mod from_iter_instead_of_collect; +mod get_first; mod get_last_with_len; mod get_unwrap; mod implicit_clone; @@ -33,55 +38,72 @@ mod iter_count; mod iter_next_slice; mod iter_nth; mod iter_nth_zero; +mod iter_on_single_or_empty_collections; mod iter_overeager_cloned; mod iter_skip_next; mod iter_with_drain; mod iterator_step_by_zero; +mod manual_ok_or; mod manual_saturating_arithmetic; mod manual_str_repeat; +mod map_clone; mod map_collect_result_unit; +mod map_err_ignore; mod map_flatten; mod map_identity; mod map_unwrap_or; +mod mut_mutex_lock; mod needless_option_as_deref; mod needless_option_take; mod no_effect_replace; mod obfuscated_if_else; mod ok_expect; +mod open_options; mod option_as_ref_deref; mod option_map_or_none; mod option_map_unwrap_or; mod or_fun_call; mod or_then_unwrap; +mod path_buf_push_overwrite; +mod range_zip_with_len; +mod repeat_once; mod search_is_some; mod single_char_add_str; mod single_char_insert_string; mod single_char_pattern; mod single_char_push_string; mod skip_while_next; +mod stable_sort_primitive; mod str_splitn; mod string_extend_chars; mod suspicious_map; mod suspicious_splitn; +mod suspicious_to_owned; mod uninit_assumed_init; +mod unit_hash; mod unnecessary_filter_map; mod unnecessary_fold; mod unnecessary_iter_cloned; mod unnecessary_join; mod unnecessary_lazy_eval; +mod unnecessary_sort_by; mod unnecessary_to_owned; mod unwrap_or_else_default; mod unwrap_used; mod useless_asref; mod utils; +mod vec_resize_to_zero; +mod verbose_file_reads; mod wrong_self_convention; mod zst_offset; use bind_instead_of_map::BindInsteadOfMap; use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; -use clippy_utils::ty::{contains_adt_constructor, contains_ty, implements_trait, is_copy, is_type_diagnostic_item}; -use clippy_utils::{contains_return, get_trait_def_id, iter_input_pats, meets_msrv, msrvs, paths, return_ty}; +use clippy_utils::ty::{contains_adt_constructor, implements_trait, is_copy, is_type_diagnostic_item}; +use clippy_utils::{ + contains_return, get_trait_def_id, is_trait_method, iter_input_pats, meets_msrv, msrvs, paths, return_ty, +}; use if_chain::if_chain; use rustc_hir as hir; use rustc_hir::def::Res; @@ -117,6 +139,32 @@ declare_clippy_lint! { "used `cloned` where `copied` could be used instead" } +declare_clippy_lint! { + /// ### What it does + /// Checks for consecutive calls to `str::replace` (2 or more) + /// that can be collapsed into a single call. + /// + /// ### Why is this bad? + /// Consecutive `str::replace` calls scan the string multiple times + /// with repetitive code. + /// + /// ### Example + /// ```rust + /// let hello = "hesuo worpd" + /// .replace('s', "l") + /// .replace("u", "l") + /// .replace('p', "l"); + /// ``` + /// Use instead: + /// ```rust + /// let hello = "hesuo worpd".replace(&['s', 'u', 'p'], "l"); + /// ``` + #[clippy::version = "1.64.0"] + pub COLLAPSIBLE_STR_REPLACE, + perf, + "collapse consecutive calls to str::replace (2 or more) into a single call" +} + declare_clippy_lint! { /// ### What it does /// Checks for usage of `_.cloned().()` where call to `.cloned()` can be postponed. @@ -173,7 +221,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for `.unwrap()` calls on `Option`s and on `Result`s. + /// Checks for `.unwrap()` or `.unwrap_err()` calls on `Result`s and `.unwrap()` call on `Option`s. /// /// ### Why is this bad? /// It is better to handle the `None` or `Err` case, @@ -223,7 +271,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for `.expect()` calls on `Option`s and `Result`s. + /// Checks for `.expect()` or `.expect_err()` calls on `Result`s and `.expect()` call on `Option`s. /// /// ### Why is this bad? /// Usually it is better to handle the `None` or `Err` case. @@ -2006,6 +2054,55 @@ declare_clippy_lint! { "replace `.iter().count()` with `.len()`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for the usage of `_.to_owned()`, on a `Cow<'_, _>`. + /// + /// ### Why is this bad? + /// Calling `to_owned()` on a `Cow` creates a clone of the `Cow` + /// itself, without taking ownership of the `Cow` contents (i.e. + /// it's equivalent to calling `Cow::clone`). + /// The similarly named `into_owned` method, on the other hand, + /// clones the `Cow` contents, effectively turning any `Cow::Borrowed` + /// into a `Cow::Owned`. + /// + /// Given the potential ambiguity, consider replacing `to_owned` + /// with `clone` for better readability or, if getting a `Cow::Owned` + /// was the original intent, using `into_owned` instead. + /// + /// ### Example + /// ```rust + /// # use std::borrow::Cow; + /// let s = "Hello world!"; + /// let cow = Cow::Borrowed(s); + /// + /// let data = cow.to_owned(); + /// assert!(matches!(data, Cow::Borrowed(_))) + /// ``` + /// Use instead: + /// ```rust + /// # use std::borrow::Cow; + /// let s = "Hello world!"; + /// let cow = Cow::Borrowed(s); + /// + /// let data = cow.clone(); + /// assert!(matches!(data, Cow::Borrowed(_))) + /// ``` + /// or + /// ```rust + /// # use std::borrow::Cow; + /// let s = "Hello world!"; + /// let cow = Cow::Borrowed(s); + /// + /// let data = cow.into_owned(); + /// assert!(matches!(data, String)) + /// ``` + #[clippy::version = "1.65.0"] + pub SUSPICIOUS_TO_OWNED, + suspicious, + "calls to `to_owned` on a `Cow<'_, _>` might not do what they are expected" +} + declare_clippy_lint! { /// ### What it does /// Checks for calls to [`splitn`] @@ -2269,7 +2366,7 @@ declare_clippy_lint! { /// "1234".replace("12", "12"); /// "1234".replacen("12", "12", 1); /// ``` - #[clippy::version = "1.62.0"] + #[clippy::version = "1.63.0"] pub NO_EFFECT_REPLACE, suspicious, "replace with no effect" @@ -2304,6 +2401,640 @@ declare_clippy_lint! { more clearly with `if .. else ..`" } +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for calls to `iter`, `iter_mut` or `into_iter` on collections containing a single item + /// + /// ### Why is this bad? + /// + /// It is simpler to use the once function from the standard library: + /// + /// ### Example + /// + /// ```rust + /// let a = [123].iter(); + /// let b = Some(123).into_iter(); + /// ``` + /// Use instead: + /// ```rust + /// use std::iter; + /// let a = iter::once(&123); + /// let b = iter::once(123); + /// ``` + /// + /// ### Known problems + /// + /// The type of the resulting iterator might become incompatible with its usage + #[clippy::version = "1.64.0"] + pub ITER_ON_SINGLE_ITEMS, + nursery, + "Iterator for array of length 1" +} + +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for calls to `iter`, `iter_mut` or `into_iter` on empty collections + /// + /// ### Why is this bad? + /// + /// It is simpler to use the empty function from the standard library: + /// + /// ### Example + /// + /// ```rust + /// use std::{slice, option}; + /// let a: slice::Iter = [].iter(); + /// let f: option::IntoIter = None.into_iter(); + /// ``` + /// Use instead: + /// ```rust + /// use std::iter; + /// let a: iter::Empty = iter::empty(); + /// let b: iter::Empty = iter::empty(); + /// ``` + /// + /// ### Known problems + /// + /// The type of the resulting iterator might become incompatible with its usage + #[clippy::version = "1.64.0"] + pub ITER_ON_EMPTY_COLLECTIONS, + nursery, + "Iterator for empty array" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for naive byte counts + /// + /// ### Why is this bad? + /// The [`bytecount`](https://crates.io/crates/bytecount) + /// crate has methods to count your bytes faster, especially for large slices. + /// + /// ### Known problems + /// If you have predominantly small slices, the + /// `bytecount::count(..)` method may actually be slower. However, if you can + /// ensure that less than 2³²-1 matches arise, the `naive_count_32(..)` can be + /// faster in those cases. + /// + /// ### Example + /// ```rust + /// # let vec = vec![1_u8]; + /// let count = vec.iter().filter(|x| **x == 0u8).count(); + /// ``` + /// + /// Use instead: + /// ```rust,ignore + /// # let vec = vec![1_u8]; + /// let count = bytecount::count(&vec, 0u8); + /// ``` + #[clippy::version = "pre 1.29.0"] + pub NAIVE_BYTECOUNT, + pedantic, + "use of naive `.filter(|&x| x == y).count()` to count byte values" +} + +declare_clippy_lint! { + /// ### What it does + /// It checks for `str::bytes().count()` and suggests replacing it with + /// `str::len()`. + /// + /// ### Why is this bad? + /// `str::bytes().count()` is longer and may not be as performant as using + /// `str::len()`. + /// + /// ### Example + /// ```rust + /// "hello".bytes().count(); + /// String::from("hello").bytes().count(); + /// ``` + /// Use instead: + /// ```rust + /// "hello".len(); + /// String::from("hello").len(); + /// ``` + #[clippy::version = "1.62.0"] + pub BYTES_COUNT_TO_LEN, + complexity, + "Using `bytes().count()` when `len()` performs the same functionality" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for calls to `ends_with` with possible file extensions + /// and suggests to use a case-insensitive approach instead. + /// + /// ### Why is this bad? + /// `ends_with` is case-sensitive and may not detect files with a valid extension. + /// + /// ### Example + /// ```rust + /// fn is_rust_file(filename: &str) -> bool { + /// filename.ends_with(".rs") + /// } + /// ``` + /// Use instead: + /// ```rust + /// fn is_rust_file(filename: &str) -> bool { + /// let filename = std::path::Path::new(filename); + /// filename.extension() + /// .map_or(false, |ext| ext.eq_ignore_ascii_case("rs")) + /// } + /// ``` + #[clippy::version = "1.51.0"] + pub CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, + pedantic, + "Checks for calls to ends_with with case-sensitive file extensions" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for using `x.get(0)` instead of + /// `x.first()`. + /// + /// ### Why is this bad? + /// Using `x.first()` is easier to read and has the same + /// result. + /// + /// ### Example + /// ```rust + /// let x = vec![2, 3, 5]; + /// let first_element = x.get(0); + /// ``` + /// + /// Use instead: + /// ```rust + /// let x = vec![2, 3, 5]; + /// let first_element = x.first(); + /// ``` + #[clippy::version = "1.63.0"] + pub GET_FIRST, + style, + "Using `x.get(0)` when `x.first()` is simpler" +} + +declare_clippy_lint! { + /// ### What it does + /// + /// Finds patterns that reimplement `Option::ok_or`. + /// + /// ### Why is this bad? + /// + /// Concise code helps focusing on behavior instead of boilerplate. + /// + /// ### Examples + /// ```rust + /// let foo: Option = None; + /// foo.map_or(Err("error"), |v| Ok(v)); + /// ``` + /// + /// Use instead: + /// ```rust + /// let foo: Option = None; + /// foo.ok_or("error"); + /// ``` + #[clippy::version = "1.49.0"] + pub MANUAL_OK_OR, + pedantic, + "finds patterns that can be encoded more concisely with `Option::ok_or`" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `map(|x| x.clone())` or + /// dereferencing closures for `Copy` types, on `Iterator` or `Option`, + /// and suggests `cloned()` or `copied()` instead + /// + /// ### Why is this bad? + /// Readability, this can be written more concisely + /// + /// ### Example + /// ```rust + /// let x = vec![42, 43]; + /// let y = x.iter(); + /// let z = y.map(|i| *i); + /// ``` + /// + /// The correct use would be: + /// + /// ```rust + /// let x = vec![42, 43]; + /// let y = x.iter(); + /// let z = y.cloned(); + /// ``` + #[clippy::version = "pre 1.29.0"] + pub MAP_CLONE, + style, + "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for instances of `map_err(|_| Some::Enum)` + /// + /// ### Why is this bad? + /// This `map_err` throws away the original error rather than allowing the enum to contain and report the cause of the error + /// + /// ### Example + /// Before: + /// ```rust + /// use std::fmt; + /// + /// #[derive(Debug)] + /// enum Error { + /// Indivisible, + /// Remainder(u8), + /// } + /// + /// impl fmt::Display for Error { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// match self { + /// Error::Indivisible => write!(f, "could not divide input by three"), + /// Error::Remainder(remainder) => write!( + /// f, + /// "input is not divisible by three, remainder = {}", + /// remainder + /// ), + /// } + /// } + /// } + /// + /// impl std::error::Error for Error {} + /// + /// fn divisible_by_3(input: &str) -> Result<(), Error> { + /// input + /// .parse::() + /// .map_err(|_| Error::Indivisible) + /// .map(|v| v % 3) + /// .and_then(|remainder| { + /// if remainder == 0 { + /// Ok(()) + /// } else { + /// Err(Error::Remainder(remainder as u8)) + /// } + /// }) + /// } + /// ``` + /// + /// After: + /// ```rust + /// use std::{fmt, num::ParseIntError}; + /// + /// #[derive(Debug)] + /// enum Error { + /// Indivisible(ParseIntError), + /// Remainder(u8), + /// } + /// + /// impl fmt::Display for Error { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// match self { + /// Error::Indivisible(_) => write!(f, "could not divide input by three"), + /// Error::Remainder(remainder) => write!( + /// f, + /// "input is not divisible by three, remainder = {}", + /// remainder + /// ), + /// } + /// } + /// } + /// + /// impl std::error::Error for Error { + /// fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + /// match self { + /// Error::Indivisible(source) => Some(source), + /// _ => None, + /// } + /// } + /// } + /// + /// fn divisible_by_3(input: &str) -> Result<(), Error> { + /// input + /// .parse::() + /// .map_err(Error::Indivisible) + /// .map(|v| v % 3) + /// .and_then(|remainder| { + /// if remainder == 0 { + /// Ok(()) + /// } else { + /// Err(Error::Remainder(remainder as u8)) + /// } + /// }) + /// } + /// ``` + #[clippy::version = "1.48.0"] + pub MAP_ERR_IGNORE, + restriction, + "`map_err` should not ignore the original error" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for `&mut Mutex::lock` calls + /// + /// ### Why is this bad? + /// `Mutex::lock` is less efficient than + /// calling `Mutex::get_mut`. In addition you also have a statically + /// guarantee that the mutex isn't locked, instead of just a runtime + /// guarantee. + /// + /// ### Example + /// ```rust + /// use std::sync::{Arc, Mutex}; + /// + /// let mut value_rc = Arc::new(Mutex::new(42_u8)); + /// let value_mutex = Arc::get_mut(&mut value_rc).unwrap(); + /// + /// let mut value = value_mutex.lock().unwrap(); + /// *value += 1; + /// ``` + /// Use instead: + /// ```rust + /// use std::sync::{Arc, Mutex}; + /// + /// let mut value_rc = Arc::new(Mutex::new(42_u8)); + /// let value_mutex = Arc::get_mut(&mut value_rc).unwrap(); + /// + /// let value = value_mutex.get_mut().unwrap(); + /// *value += 1; + /// ``` + #[clippy::version = "1.49.0"] + pub MUT_MUTEX_LOCK, + style, + "`&mut Mutex::lock` does unnecessary locking" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for duplicate open options as well as combinations + /// that make no sense. + /// + /// ### Why is this bad? + /// In the best case, the code will be harder to read than + /// necessary. I don't know the worst case. + /// + /// ### Example + /// ```rust + /// use std::fs::OpenOptions; + /// + /// OpenOptions::new().read(true).truncate(true); + /// ``` + #[clippy::version = "pre 1.29.0"] + pub NONSENSICAL_OPEN_OPTIONS, + correctness, + "nonsensical combination of options for opening a file" +} + +declare_clippy_lint! { + /// ### What it does + ///* Checks for [push](https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.push) + /// calls on `PathBuf` that can cause overwrites. + /// + /// ### Why is this bad? + /// Calling `push` with a root path at the start can overwrite the + /// previous defined path. + /// + /// ### Example + /// ```rust + /// use std::path::PathBuf; + /// + /// let mut x = PathBuf::from("/foo"); + /// x.push("/bar"); + /// assert_eq!(x, PathBuf::from("/bar")); + /// ``` + /// Could be written: + /// + /// ```rust + /// use std::path::PathBuf; + /// + /// let mut x = PathBuf::from("/foo"); + /// x.push("bar"); + /// assert_eq!(x, PathBuf::from("/foo/bar")); + /// ``` + #[clippy::version = "1.36.0"] + pub PATH_BUF_PUSH_OVERWRITE, + nursery, + "calling `push` with file system root on `PathBuf` can overwrite it" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for zipping a collection with the range of + /// `0.._.len()`. + /// + /// ### Why is this bad? + /// The code is better expressed with `.enumerate()`. + /// + /// ### Example + /// ```rust + /// # let x = vec![1]; + /// let _ = x.iter().zip(0..x.len()); + /// ``` + /// + /// Use instead: + /// ```rust + /// # let x = vec![1]; + /// let _ = x.iter().enumerate(); + /// ``` + #[clippy::version = "pre 1.29.0"] + pub RANGE_ZIP_WITH_LEN, + complexity, + "zipping iterator with a range when `enumerate()` would do" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `.repeat(1)` and suggest the following method for each types. + /// - `.to_string()` for `str` + /// - `.clone()` for `String` + /// - `.to_vec()` for `slice` + /// + /// The lint will evaluate constant expressions and values as arguments of `.repeat(..)` and emit a message if + /// they are equivalent to `1`. (Related discussion in [rust-clippy#7306](https://github.com/rust-lang/rust-clippy/issues/7306)) + /// + /// ### Why is this bad? + /// For example, `String.repeat(1)` is equivalent to `.clone()`. If cloning + /// the string is the intention behind this, `clone()` should be used. + /// + /// ### Example + /// ```rust + /// fn main() { + /// let x = String::from("hello world").repeat(1); + /// } + /// ``` + /// Use instead: + /// ```rust + /// fn main() { + /// let x = String::from("hello world").clone(); + /// } + /// ``` + #[clippy::version = "1.47.0"] + pub REPEAT_ONCE, + complexity, + "using `.repeat(1)` instead of `String.clone()`, `str.to_string()` or `slice.to_vec()` " +} + +declare_clippy_lint! { + /// ### What it does + /// When sorting primitive values (integers, bools, chars, as well + /// as arrays, slices, and tuples of such items), it is typically better to + /// use an unstable sort than a stable sort. + /// + /// ### Why is this bad? + /// Typically, using a stable sort consumes more memory and cpu cycles. + /// Because values which compare equal are identical, preserving their + /// relative order (the guarantee that a stable sort provides) means + /// nothing, while the extra costs still apply. + /// + /// ### Known problems + /// + /// As pointed out in + /// [issue #8241](https://github.com/rust-lang/rust-clippy/issues/8241), + /// a stable sort can instead be significantly faster for certain scenarios + /// (eg. when a sorted vector is extended with new data and resorted). + /// + /// For more information and benchmarking results, please refer to the + /// issue linked above. + /// + /// ### Example + /// ```rust + /// let mut vec = vec![2, 1, 3]; + /// vec.sort(); + /// ``` + /// Use instead: + /// ```rust + /// let mut vec = vec![2, 1, 3]; + /// vec.sort_unstable(); + /// ``` + #[clippy::version = "1.47.0"] + pub STABLE_SORT_PRIMITIVE, + pedantic, + "use of sort() when sort_unstable() is equivalent" +} + +declare_clippy_lint! { + /// ### What it does + /// Detects `().hash(_)`. + /// + /// ### Why is this bad? + /// Hashing a unit value doesn't do anything as the implementation of `Hash` for `()` is a no-op. + /// + /// ### Example + /// ```rust + /// # use std::hash::Hash; + /// # use std::collections::hash_map::DefaultHasher; + /// # enum Foo { Empty, WithValue(u8) } + /// # use Foo::*; + /// # let mut state = DefaultHasher::new(); + /// # let my_enum = Foo::Empty; + /// match my_enum { + /// Empty => ().hash(&mut state), + /// WithValue(x) => x.hash(&mut state), + /// } + /// ``` + /// Use instead: + /// ```rust + /// # use std::hash::Hash; + /// # use std::collections::hash_map::DefaultHasher; + /// # enum Foo { Empty, WithValue(u8) } + /// # use Foo::*; + /// # let mut state = DefaultHasher::new(); + /// # let my_enum = Foo::Empty; + /// match my_enum { + /// Empty => 0_u8.hash(&mut state), + /// WithValue(x) => x.hash(&mut state), + /// } + /// ``` + #[clippy::version = "1.58.0"] + pub UNIT_HASH, + correctness, + "hashing a unit value, which does nothing" +} + +declare_clippy_lint! { + /// ### What it does + /// Detects uses of `Vec::sort_by` passing in a closure + /// which compares the two arguments, either directly or indirectly. + /// + /// ### Why is this bad? + /// It is more clear to use `Vec::sort_by_key` (or `Vec::sort` if + /// possible) than to use `Vec::sort_by` and a more complicated + /// closure. + /// + /// ### Known problems + /// If the suggested `Vec::sort_by_key` uses Reverse and it isn't already + /// imported by a use statement, then it will need to be added manually. + /// + /// ### Example + /// ```rust + /// # struct A; + /// # impl A { fn foo(&self) {} } + /// # let mut vec: Vec = Vec::new(); + /// vec.sort_by(|a, b| a.foo().cmp(&b.foo())); + /// ``` + /// Use instead: + /// ```rust + /// # struct A; + /// # impl A { fn foo(&self) {} } + /// # let mut vec: Vec = Vec::new(); + /// vec.sort_by_key(|a| a.foo()); + /// ``` + #[clippy::version = "1.46.0"] + pub UNNECESSARY_SORT_BY, + complexity, + "Use of `Vec::sort_by` when `Vec::sort_by_key` or `Vec::sort` would be clearer" +} + +declare_clippy_lint! { + /// ### What it does + /// Finds occurrences of `Vec::resize(0, an_int)` + /// + /// ### Why is this bad? + /// This is probably an argument inversion mistake. + /// + /// ### Example + /// ```rust + /// vec!(1, 2, 3, 4, 5).resize(0, 5) + /// ``` + /// + /// Use instead: + /// ```rust + /// vec!(1, 2, 3, 4, 5).clear() + /// ``` + #[clippy::version = "1.46.0"] + pub VEC_RESIZE_TO_ZERO, + correctness, + "emptying a vector with `resize(0, an_int)` instead of `clear()` is probably an argument inversion mistake" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for use of File::read_to_end and File::read_to_string. + /// + /// ### Why is this bad? + /// `fs::{read, read_to_string}` provide the same functionality when `buf` is empty with fewer imports and no intermediate values. + /// See also: [fs::read docs](https://doc.rust-lang.org/std/fs/fn.read.html), [fs::read_to_string docs](https://doc.rust-lang.org/std/fs/fn.read_to_string.html) + /// + /// ### Example + /// ```rust,no_run + /// # use std::io::Read; + /// # use std::fs::File; + /// let mut f = File::open("foo.txt").unwrap(); + /// let mut bytes = Vec::new(); + /// f.read_to_end(&mut bytes).unwrap(); + /// ``` + /// Can be written more concisely as + /// ```rust,no_run + /// # use std::fs; + /// let mut bytes = fs::read("foo.txt").unwrap(); + /// ``` + #[clippy::version = "1.44.0"] + pub VERBOSE_FILE_READS, + restriction, + "use of `File::read_to_end` or `File::read_to_string`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Option, @@ -2347,6 +3078,7 @@ impl_lint_pass!(Methods => [ CLONE_ON_COPY, CLONE_ON_REF_PTR, CLONE_DOUBLE_REF, + COLLAPSIBLE_STR_REPLACE, ITER_OVEREAGER_CLONED, CLONED_INSTEAD_OF_COPIED, FLAT_MAP_OPTION, @@ -2393,6 +3125,7 @@ impl_lint_pass!(Methods => [ FROM_ITER_INSTEAD_OF_COLLECT, INSPECT_FOR_EACH, IMPLICIT_CLONE, + SUSPICIOUS_TO_OWNED, SUSPICIOUS_SPLITN, MANUAL_STR_REPEAT, EXTEND_WITH_DRAIN, @@ -2406,6 +3139,25 @@ impl_lint_pass!(Methods => [ NEEDLESS_OPTION_TAKE, NO_EFFECT_REPLACE, OBFUSCATED_IF_ELSE, + ITER_ON_SINGLE_ITEMS, + ITER_ON_EMPTY_COLLECTIONS, + NAIVE_BYTECOUNT, + BYTES_COUNT_TO_LEN, + CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, + GET_FIRST, + MANUAL_OK_OR, + MAP_CLONE, + MAP_ERR_IGNORE, + MUT_MUTEX_LOCK, + NONSENSICAL_OPEN_OPTIONS, + PATH_BUF_PUSH_OVERWRITE, + RANGE_ZIP_WITH_LEN, + REPEAT_ONCE, + STABLE_SORT_PRIMITIVE, + UNIT_HASH, + UNNECESSARY_SORT_BY, + VEC_RESIZE_TO_ZERO, + VERBOSE_FILE_READS, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -2541,7 +3293,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if contains_adt_constructor(ret_ty, self_adt) { return; } - } else if contains_ty(ret_ty, self_ty) { + } else if ret_ty.contains(self_ty) { return; } @@ -2559,7 +3311,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if contains_adt_constructor(assoc_ty, self_adt) { return; } - } else if contains_ty(assoc_ty, self_ty) { + } else if assoc_ty.contains(self_ty) { return; } } @@ -2608,7 +3360,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if let TraitItemKind::Fn(_, _) = item.kind; let ret_ty = return_ty(cx, item.hir_id()); let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty().skip_binder(); - if !contains_ty(ret_ty, self_ty); + if !ret_ty.contains(self_ty); then { span_lint( @@ -2660,22 +3412,30 @@ impl Methods { }, _ => {}, }, - ("count", []) => match method_call(recv) { + ("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) { Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false), Some((name2 @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => { iter_count::check(cx, expr, recv2, name2); }, Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg), + Some(("filter", [recv2, arg], _)) => bytecount::check(cx, expr, recv2, arg), + Some(("bytes", [recv2], _)) => bytes_count_to_len::check(cx, expr, recv, recv2), _ => {}, }, ("drain", [arg]) => { iter_with_drain::check(cx, expr, recv, span, arg); }, + ("ends_with", [arg]) => { + if let ExprKind::MethodCall(_, _, span) = expr.kind { + case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg); + } + }, ("expect", [_]) => match method_call(recv) { Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv), Some(("err", [recv], err_span)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span), - _ => expect_used::check(cx, expr, recv, self.allow_expect_in_tests), + _ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests), }, + ("expect_err", [_]) => expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests), ("extend", [arg]) => { string_extend_chars::check(cx, expr, recv, arg); extend_with_drain::check(cx, expr, recv, arg); @@ -2702,12 +3462,21 @@ impl Methods { inspect_for_each::check(cx, expr, span2); } }, - ("get", [arg]) => get_last_with_len::check(cx, expr, recv, arg), + ("get", [arg]) => { + get_first::check(cx, expr, recv, arg); + get_last_with_len::check(cx, expr, recv, arg); + }, ("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"), + ("hash", [arg]) => { + unit_hash::check(cx, expr, recv, arg); + }, ("is_file", []) => filetype_is_file::check(cx, expr, recv), ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv), ("is_none", []) => check_is_some_is_none(cx, expr, recv, false), ("is_some", []) => check_is_some_is_none(cx, expr, recv, true), + ("iter" | "iter_mut" | "into_iter", []) => { + iter_on_single_or_empty_collections::check(cx, expr, name, recv); + }, ("join", [join_arg]) => { if let Some(("collect", _, span)) = method_call(recv) { unnecessary_join::check(cx, expr, recv, join_arg, span); @@ -2720,7 +3489,15 @@ impl Methods { } } }, + ("lock", []) => { + mut_mutex_lock::check(cx, expr, recv, span); + }, (name @ ("map" | "map_err"), [m_arg]) => { + if name == "map" { + map_clone::check(cx, expr, recv, m_arg, self.msrv); + } else { + map_err_ignore::check(cx, expr, m_arg); + } if let Some((name, [recv2, args @ ..], span2)) = method_call(recv) { match (name, args) { ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv), @@ -2736,7 +3513,10 @@ impl Methods { } map_identity::check(cx, expr, recv, m_arg, name, span); }, - ("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map), + ("map_or", [def, map]) => { + option_map_or_none::check(cx, expr, recv, def, map); + manual_ok_or::check(cx, expr, recv, def, map); + }, ("next", []) => { if let Some((name2, [recv2, args2 @ ..], _)) = method_call(recv) { match (name2, args2) { @@ -2758,11 +3538,46 @@ impl Methods { _ => iter_nth_zero::check(cx, expr, recv, n_arg), }, ("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"), + ("open", [_]) => { + open_options::check(cx, expr, recv); + }, ("or_else", [arg]) => { if !bind_instead_of_map::ResultOrElseErrInfo::check(cx, expr, recv, arg) { unnecessary_lazy_eval::check(cx, expr, recv, arg, "or"); } }, + ("push", [arg]) => { + path_buf_push_overwrite::check(cx, expr, arg); + }, + ("read_to_end", [_]) => { + verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_END_MSG); + }, + ("read_to_string", [_]) => { + verbose_file_reads::check(cx, expr, recv, verbose_file_reads::READ_TO_STRING_MSG); + }, + ("repeat", [arg]) => { + repeat_once::check(cx, expr, recv, arg); + }, + (name @ ("replace" | "replacen"), [arg1, arg2] | [arg1, arg2, _]) => { + no_effect_replace::check(cx, expr, arg1, arg2); + + // Check for repeated `str::replace` calls to perform `collapsible_str_replace` lint + if name == "replace" && let Some(("replace", ..)) = method_call(recv) { + collapsible_str_replace::check(cx, expr, arg1, arg2); + } + }, + ("resize", [count_arg, default_arg]) => { + vec_resize_to_zero::check(cx, expr, count_arg, default_arg, span); + }, + ("sort", []) => { + stable_sort_primitive::check(cx, expr, recv); + }, + ("sort_by", [arg]) => { + unnecessary_sort_by::check(cx, expr, recv, arg, false); + }, + ("sort_unstable_by", [arg]) => { + unnecessary_sort_by::check(cx, expr, recv, arg, true); + }, ("splitn" | "rsplitn", [count_arg, pat_arg]) => { if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) { suspicious_splitn::check(cx, name, expr, recv, count); @@ -2789,7 +3604,12 @@ impl Methods { } unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some"); }, - ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => { + ("to_owned", []) => { + if !suspicious_to_owned::check(cx, expr, recv) { + implicit_clone::check(cx, name, expr, recv); + } + }, + ("to_os_string" | "to_path_buf" | "to_vec", []) => { implicit_clone::check(cx, name, expr, recv); }, ("unwrap", []) => { @@ -2805,8 +3625,9 @@ impl Methods { }, _ => {}, } - unwrap_used::check(cx, expr, recv, self.allow_unwrap_in_tests); + unwrap_used::check(cx, expr, recv, false, self.allow_unwrap_in_tests); }, + ("unwrap_err", []) => unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests), ("unwrap_or", [u_arg]) => match method_call(recv) { Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => { manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]); @@ -2827,8 +3648,12 @@ impl Methods { unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or"); }, }, - ("replace" | "replacen", [arg1, arg2] | [arg1, arg2, _]) => { - no_effect_replace::check(cx, expr, arg1, arg2); + ("zip", [arg]) => { + if let ExprKind::MethodCall(name, [iter_recv], _) = recv.kind + && name.ident.name == sym::iter + { + range_zip_with_len::check(cx, expr, iter_recv, arg); + } }, _ => {}, } diff --git a/clippy_lints/src/methods/mut_mutex_lock.rs b/clippy_lints/src/methods/mut_mutex_lock.rs new file mode 100644 index 000000000000..bd8458a222e2 --- /dev/null +++ b/clippy_lints/src/methods/mut_mutex_lock.rs @@ -0,0 +1,30 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::ty::is_type_diagnostic_item; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{Expr, Mutability}; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::{sym, Span}; + +use super::MUT_MUTEX_LOCK; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>, recv: &'tcx Expr<'tcx>, name_span: Span) { + if_chain! { + if let ty::Ref(_, _, Mutability::Mut) = cx.typeck_results().expr_ty(recv).kind(); + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(ex.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(method_id); + if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Mutex); + then { + span_lint_and_sugg( + cx, + MUT_MUTEX_LOCK, + name_span, + "calling `&mut Mutex::lock` unnecessarily locks an exclusive (mutable) reference", + "change this to", + "get_mut".to_owned(), + Applicability::MaybeIncorrect, + ); + } + } +} diff --git a/clippy_lints/src/open_options.rs b/clippy_lints/src/methods/open_options.rs similarity index 80% rename from clippy_lints/src/open_options.rs rename to clippy_lints/src/methods/open_options.rs index 5a0b5042018b..c3112823e346 100644 --- a/clippy_lints/src/open_options.rs +++ b/clippy_lints/src/methods/open_options.rs @@ -3,43 +3,19 @@ use clippy_utils::paths; use clippy_utils::ty::match_type; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_lint::LateContext; use rustc_span::source_map::{Span, Spanned}; -declare_clippy_lint! { - /// ### What it does - /// Checks for duplicate open options as well as combinations - /// that make no sense. - /// - /// ### Why is this bad? - /// In the best case, the code will be harder to read than - /// necessary. I don't know the worst case. - /// - /// ### Example - /// ```rust - /// use std::fs::OpenOptions; - /// - /// OpenOptions::new().read(true).truncate(true); - /// ``` - #[clippy::version = "pre 1.29.0"] - pub NONSENSICAL_OPEN_OPTIONS, - correctness, - "nonsensical combination of options for opening a file" -} +use super::NONSENSICAL_OPEN_OPTIONS; -declare_lint_pass!(OpenOptions => [NONSENSICAL_OPEN_OPTIONS]); - -impl<'tcx> LateLintPass<'tcx> for OpenOptions { - fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if let ExprKind::MethodCall(path, [self_arg, ..], _) = &e.kind { - let obj_ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); - if path.ident.name == sym!(open) && match_type(cx, obj_ty, &paths::OPEN_OPTIONS) { - let mut options = Vec::new(); - get_open_options(cx, self_arg, &mut options); - check_open_options(cx, &options, e.span); - } - } +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) + && let Some(impl_id) = cx.tcx.impl_of_method(method_id) + && match_type(cx, cx.tcx.type_of(impl_id), &paths::OPEN_OPTIONS) + { + let mut options = Vec::new(); + get_open_options(cx, recv, &mut options); + check_open_options(cx, &options, e.span); } } diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index 6c641af59f92..3c4002a3aef9 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -78,7 +78,7 @@ pub(super) fn check<'tcx>( map_span, String::from(if unwrap_snippet_none { "and_then" } else { "map_or" }), ), - (expr.span.with_lo(unwrap_recv.span.hi()), String::from("")), + (expr.span.with_lo(unwrap_recv.span.hi()), String::new()), ]; if !unwrap_snippet_none { diff --git a/clippy_lints/src/methods/path_buf_push_overwrite.rs b/clippy_lints/src/methods/path_buf_push_overwrite.rs new file mode 100644 index 000000000000..0cc28c0dcb3d --- /dev/null +++ b/clippy_lints/src/methods/path_buf_push_overwrite.rs @@ -0,0 +1,37 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::ty::is_type_diagnostic_item; +use if_chain::if_chain; +use rustc_ast::ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::symbol::sym; +use std::path::{Component, Path}; + +use super::PATH_BUF_PUSH_OVERWRITE; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) { + if_chain! { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(method_id); + if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::PathBuf); + if let ExprKind::Lit(ref lit) = arg.kind; + if let LitKind::Str(ref path_lit, _) = lit.node; + if let pushed_path = Path::new(path_lit.as_str()); + if let Some(pushed_path_lit) = pushed_path.to_str(); + if pushed_path.has_root(); + if let Some(root) = pushed_path.components().next(); + if root == Component::RootDir; + then { + span_lint_and_sugg( + cx, + PATH_BUF_PUSH_OVERWRITE, + lit.span, + "calling `push` with '/' or '\\' (file system root) will overwrite the previous path definition", + "try", + format!("\"{}\"", pushed_path_lit.trim_start_matches(|c| c == '/' || c == '\\')), + Applicability::MachineApplicable, + ); + } + } +} diff --git a/clippy_lints/src/methods/range_zip_with_len.rs b/clippy_lints/src/methods/range_zip_with_len.rs new file mode 100644 index 000000000000..00a2a0d14d11 --- /dev/null +++ b/clippy_lints/src/methods/range_zip_with_len.rs @@ -0,0 +1,34 @@ +use clippy_utils::diagnostics::span_lint; +use clippy_utils::source::snippet; +use clippy_utils::{higher, SpanlessEq}; +use clippy_utils::{is_integer_const, is_trait_method}; +use if_chain::if_chain; +use rustc_hir::{Expr, ExprKind, QPath}; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::RANGE_ZIP_WITH_LEN; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, zip_arg: &'tcx Expr<'_>) { + if_chain! { + if is_trait_method(cx, expr, sym::Iterator); + // range expression in `.zip()` call: `0..x.len()` + if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg); + if is_integer_const(cx, start, 0); + // `.len()` call + if let ExprKind::MethodCall(len_path, [len_recv], _) = end.kind; + if len_path.ident.name == sym::len; + // `.iter()` and `.len()` called on same `Path` + if let ExprKind::Path(QPath::Resolved(_, iter_path)) = recv.kind; + if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_recv.kind; + if SpanlessEq::new(cx).eq_path_segments(iter_path.segments, len_path.segments); + then { + span_lint(cx, + RANGE_ZIP_WITH_LEN, + expr.span, + &format!("it is more idiomatic to use `{}.iter().enumerate()`", + snippet(cx, recv.span, "_")) + ); + } + } +} diff --git a/clippy_lints/src/methods/repeat_once.rs b/clippy_lints/src/methods/repeat_once.rs new file mode 100644 index 000000000000..0a14f9216ab3 --- /dev/null +++ b/clippy_lints/src/methods/repeat_once.rs @@ -0,0 +1,52 @@ +use clippy_utils::consts::{constant_context, Constant}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::ty::is_type_diagnostic_item; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::REPEAT_ONCE; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + recv: &'tcx Expr<'_>, + repeat_arg: &'tcx Expr<'_>, +) { + if constant_context(cx, cx.typeck_results()).expr(repeat_arg) == Some(Constant::Int(1)) { + let ty = cx.typeck_results().expr_ty(recv).peel_refs(); + if ty.is_str() { + span_lint_and_sugg( + cx, + REPEAT_ONCE, + expr.span, + "calling `repeat(1)` on str", + "consider using `.to_string()` instead", + format!("{}.to_string()", snippet(cx, recv.span, r#""...""#)), + Applicability::MachineApplicable, + ); + } else if ty.builtin_index().is_some() { + span_lint_and_sugg( + cx, + REPEAT_ONCE, + expr.span, + "calling `repeat(1)` on slice", + "consider using `.to_vec()` instead", + format!("{}.to_vec()", snippet(cx, recv.span, r#""...""#)), + Applicability::MachineApplicable, + ); + } else if is_type_diagnostic_item(cx, ty, sym::String) { + span_lint_and_sugg( + cx, + REPEAT_ONCE, + expr.span, + "calling `repeat(1)` on a string literal", + "consider using `.clone()` instead", + format!("{}.clone()", snippet(cx, recv.span, r#""...""#)), + Applicability::MachineApplicable, + ); + } + } +} diff --git a/clippy_lints/src/methods/stable_sort_primitive.rs b/clippy_lints/src/methods/stable_sort_primitive.rs new file mode 100644 index 000000000000..91951c65bb30 --- /dev/null +++ b/clippy_lints/src/methods/stable_sort_primitive.rs @@ -0,0 +1,31 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_slice_of_primitives; +use clippy_utils::source::snippet_with_context; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; + +use super::STABLE_SORT_PRIMITIVE; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) + && let Some(impl_id) = cx.tcx.impl_of_method(method_id) + && cx.tcx.type_of(impl_id).is_slice() + && let Some(slice_type) = is_slice_of_primitives(cx, recv) + { + span_lint_and_then( + cx, + STABLE_SORT_PRIMITIVE, + e.span, + &format!("used `sort` on primitive type `{}`", slice_type), + |diag| { + let mut app = Applicability::MachineApplicable; + let recv_snip = snippet_with_context(cx, recv.span, e.span.ctxt(), "..", &mut app).0; + diag.span_suggestion(e.span, "try", format!("{}.sort_unstable()", recv_snip), app); + diag.note( + "an unstable sort typically performs faster without any observable difference for this data type", + ); + }, + ); + } +} diff --git a/clippy_lints/src/methods/suspicious_to_owned.rs b/clippy_lints/src/methods/suspicious_to_owned.rs new file mode 100644 index 000000000000..6b306fbf0085 --- /dev/null +++ b/clippy_lints/src/methods/suspicious_to_owned.rs @@ -0,0 +1,36 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_diag_trait_item; +use clippy_utils::source::snippet_with_context; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_middle::ty; +use rustc_span::sym; + +use super::SUSPICIOUS_TO_OWNED; + +pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) -> bool { + if_chain! { + if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if is_diag_trait_item(cx, method_def_id, sym::ToOwned); + let input_type = cx.typeck_results().expr_ty(expr); + if let ty::Adt(adt, _) = cx.typeck_results().expr_ty(expr).kind(); + if cx.tcx.is_diagnostic_item(sym::Cow, adt.did()); + then { + let mut app = Applicability::MaybeIncorrect; + let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0; + span_lint_and_sugg( + cx, + SUSPICIOUS_TO_OWNED, + expr.span, + &format!("this `to_owned` call clones the {0} itself and does not cause the {0} contents to become owned", input_type), + "consider using, depending on intent", + format!("{0}.clone()` or `{0}.into_owned()", recv_snip), + app, + ); + return true; + } + } + false +} diff --git a/clippy_lints/src/methods/uninit_assumed_init.rs b/clippy_lints/src/methods/uninit_assumed_init.rs index 77d21f1d3730..a1c6294737cf 100644 --- a/clippy_lints/src/methods/uninit_assumed_init.rs +++ b/clippy_lints/src/methods/uninit_assumed_init.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::{is_expr_diagnostic_item, ty::is_uninit_value_valid_for_ty}; +use clippy_utils::{is_path_diagnostic_item, ty::is_uninit_value_valid_for_ty}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::LateContext; @@ -12,7 +12,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr if_chain! { if let hir::ExprKind::Call(callee, args) = recv.kind; if args.is_empty(); - if is_expr_diagnostic_item(cx, callee, sym::maybe_uninit_uninit); + if is_path_diagnostic_item(cx, callee, sym::maybe_uninit_uninit); if !is_uninit_value_valid_for_ty(cx, cx.typeck_results().expr_ty_adjusted(expr)); then { span_lint( diff --git a/clippy_lints/src/methods/unit_hash.rs b/clippy_lints/src/methods/unit_hash.rs new file mode 100644 index 000000000000..3c7955bc4698 --- /dev/null +++ b/clippy_lints/src/methods/unit_hash.rs @@ -0,0 +1,29 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_trait_method; +use clippy_utils::source::snippet; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::UNIT_HASH; + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) { + if is_trait_method(cx, expr, sym::Hash) && cx.typeck_results().expr_ty(recv).is_unit() { + span_lint_and_then( + cx, + UNIT_HASH, + expr.span, + "this call to `hash` on the unit type will do nothing", + |diag| { + diag.span_suggestion( + expr.span, + "remove the call to `hash` or consider using", + format!("0_u8.hash({})", snippet(cx, arg.span, ".."),), + Applicability::MaybeIncorrect, + ); + diag.note("the implementation of `Hash` for `()` is a no-op"); + }, + ); + } +} diff --git a/clippy_lints/src/unnecessary_sort_by.rs b/clippy_lints/src/methods/unnecessary_sort_by.rs similarity index 63% rename from clippy_lints/src/unnecessary_sort_by.rs rename to clippy_lints/src/methods/unnecessary_sort_by.rs index ea5aadbbca1c..1966990bd774 100644 --- a/clippy_lints/src/unnecessary_sort_by.rs +++ b/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -1,51 +1,17 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_trait_method; use clippy_utils::sugg::Sugg; -use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; +use clippy_utils::ty::implements_trait; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::LateContext; use rustc_middle::ty::{self, subst::GenericArgKind}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; use rustc_span::symbol::Ident; use std::iter; -declare_clippy_lint! { - /// ### What it does - /// Detects uses of `Vec::sort_by` passing in a closure - /// which compares the two arguments, either directly or indirectly. - /// - /// ### Why is this bad? - /// It is more clear to use `Vec::sort_by_key` (or `Vec::sort` if - /// possible) than to use `Vec::sort_by` and a more complicated - /// closure. - /// - /// ### Known problems - /// If the suggested `Vec::sort_by_key` uses Reverse and it isn't already - /// imported by a use statement, then it will need to be added manually. - /// - /// ### Example - /// ```rust - /// # struct A; - /// # impl A { fn foo(&self) {} } - /// # let mut vec: Vec = Vec::new(); - /// vec.sort_by(|a, b| a.foo().cmp(&b.foo())); - /// ``` - /// Use instead: - /// ```rust - /// # struct A; - /// # impl A { fn foo(&self) {} } - /// # let mut vec: Vec = Vec::new(); - /// vec.sort_by_key(|a| a.foo()); - /// ``` - #[clippy::version = "1.46.0"] - pub UNNECESSARY_SORT_BY, - complexity, - "Use of `Vec::sort_by` when `Vec::sort_by_key` or `Vec::sort` would be clearer" -} - -declare_lint_pass!(UnnecessarySortBy => [UNNECESSARY_SORT_BY]); +use super::UNNECESSARY_SORT_BY; enum LintTrigger { Sort(SortDetection), @@ -54,7 +20,6 @@ enum LintTrigger { struct SortDetection { vec_name: String, - unstable: bool, } struct SortByKeyDetection { @@ -62,7 +27,6 @@ struct SortByKeyDetection { closure_arg: String, closure_body: String, reverse: bool, - unstable: bool, } /// Detect if the two expressions are mirrored (identical, except one @@ -150,20 +114,20 @@ fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident } } -fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { +fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) -> Option { if_chain! { - if let ExprKind::MethodCall(name_ident, args, _) = &expr.kind; - if let name = name_ident.ident.name.to_ident_string(); - if name == "sort_by" || name == "sort_unstable_by"; - if let [vec, Expr { kind: ExprKind::Closure(Closure { body: closure_body_id, .. }), .. }] = args; - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(vec), sym::Vec); - if let closure_body = cx.tcx.hir().body(*closure_body_id); + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(method_id); + if cx.tcx.type_of(impl_id).is_slice(); + if let ExprKind::Closure(&Closure { body, .. }) = arg.kind; + if let closure_body = cx.tcx.hir().body(body); if let &[ Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..}, Param { pat: Pat { kind: PatKind::Binding(_, _, right_ident, _), .. }, .. } ] = &closure_body.params; - if let ExprKind::MethodCall(method_path, [ref left_expr, ref right_expr], _) = &closure_body.value.kind; + if let ExprKind::MethodCall(method_path, [left_expr, right_expr], _) = closure_body.value.kind; if method_path.ident.name == sym::cmp; + if is_trait_method(cx, &closure_body.value, sym::Ord); then { let (closure_body, closure_arg, reverse) = if mirrored_exprs( left_expr, @@ -177,19 +141,18 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { } else { return None; }; - let vec_name = Sugg::hir(cx, &args[0], "..").to_string(); - let unstable = name == "sort_unstable_by"; + let vec_name = Sugg::hir(cx, recv, "..").to_string(); if_chain! { - if let ExprKind::Path(QPath::Resolved(_, Path { - segments: [PathSegment { ident: left_name, .. }], .. - })) = &left_expr.kind; - if left_name == left_ident; - if cx.tcx.get_diagnostic_item(sym::Ord).map_or(false, |id| { - implements_trait(cx, cx.typeck_results().expr_ty(left_expr), id, &[]) - }); + if let ExprKind::Path(QPath::Resolved(_, Path { + segments: [PathSegment { ident: left_name, .. }], .. + })) = &left_expr.kind; + if left_name == left_ident; + if cx.tcx.get_diagnostic_item(sym::Ord).map_or(false, |id| { + implements_trait(cx, cx.typeck_results().expr_ty(left_expr), id, &[]) + }); then { - return Some(LintTrigger::Sort(SortDetection { vec_name, unstable })); + return Some(LintTrigger::Sort(SortDetection { vec_name })); } } @@ -199,7 +162,6 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { closure_arg, closure_body, reverse, - unstable, })); } } @@ -213,46 +175,50 @@ fn expr_borrows(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { matches!(ty.kind(), ty::Ref(..)) || ty.walk().any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_))) } -impl LateLintPass<'_> for UnnecessarySortBy { - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - match detect_lint(cx, expr) { - Some(LintTrigger::SortByKey(trigger)) => span_lint_and_sugg( - cx, - UNNECESSARY_SORT_BY, - expr.span, - "use Vec::sort_by_key here instead", - "try", - format!( - "{}.sort{}_by_key(|{}| {})", - trigger.vec_name, - if trigger.unstable { "_unstable" } else { "" }, - trigger.closure_arg, - if trigger.reverse { - format!("std::cmp::Reverse({})", trigger.closure_body) - } else { - trigger.closure_body.to_string() - }, - ), +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + recv: &'tcx Expr<'_>, + arg: &'tcx Expr<'_>, + is_unstable: bool, +) { + match detect_lint(cx, expr, recv, arg) { + Some(LintTrigger::SortByKey(trigger)) => span_lint_and_sugg( + cx, + UNNECESSARY_SORT_BY, + expr.span, + "use Vec::sort_by_key here instead", + "try", + format!( + "{}.sort{}_by_key(|{}| {})", + trigger.vec_name, + if is_unstable { "_unstable" } else { "" }, + trigger.closure_arg, if trigger.reverse { - Applicability::MaybeIncorrect + format!("std::cmp::Reverse({})", trigger.closure_body) } else { - Applicability::MachineApplicable + trigger.closure_body.to_string() }, ), - Some(LintTrigger::Sort(trigger)) => span_lint_and_sugg( - cx, - UNNECESSARY_SORT_BY, - expr.span, - "use Vec::sort here instead", - "try", - format!( - "{}.sort{}()", - trigger.vec_name, - if trigger.unstable { "_unstable" } else { "" }, - ), - Applicability::MachineApplicable, + if trigger.reverse { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + }, + ), + Some(LintTrigger::Sort(trigger)) => span_lint_and_sugg( + cx, + UNNECESSARY_SORT_BY, + expr.span, + "use Vec::sort here instead", + "try", + format!( + "{}.sort{}()", + trigger.vec_name, + if is_unstable { "_unstable" } else { "" }, ), - None => {}, - } + Applicability::MachineApplicable, + ), + None => {}, } } diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index b3276f1394ed..44bf84352943 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -3,11 +3,10 @@ use super::unnecessary_iter_cloned::{self, is_into_iter}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; use clippy_utils::ty::{ - contains_ty, get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs, + get_associated_type, get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, peel_mid_ty_refs, }; -use clippy_utils::{meets_msrv, msrvs}; - use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item}; +use clippy_utils::{meets_msrv, msrvs}; use rustc_errors::Applicability; use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind}; use rustc_lint::LateContext; @@ -279,7 +278,19 @@ fn check_other_call_arg<'tcx>( &trait_predicate.trait_ref.substs.iter().skip(1).collect::>()[..], call_substs, ); - implements_trait(cx, receiver_ty, as_ref_trait_id, &composed_substs) + // if `expr` is a `String` and generic target is [u8], skip + // (https://github.com/rust-lang/rust-clippy/issues/9317). + if let [subst] = composed_substs[..] + && let GenericArgKind::Type(arg_ty) = subst.unpack() + && arg_ty.is_slice() + && let inner_ty = arg_ty.builtin_index().unwrap() + && let ty::Uint(ty::UintTy::U8) = inner_ty.kind() + && let self_ty = cx.typeck_results().expr_ty(expr).peel_refs() + && is_type_diagnostic_item(cx, self_ty, sym::String) { + false + } else { + implements_trait(cx, receiver_ty, as_ref_trait_id, &composed_substs) + } } else { false }; @@ -292,7 +303,7 @@ fn check_other_call_arg<'tcx>( // (https://github.com/rust-lang/rust-clippy/issues/8507). if (n_refs == 0 && !receiver_ty.is_ref()) || trait_predicate.def_id() != as_ref_trait_id - || !contains_ty(fn_sig.output(), input); + || !fn_sig.output().contains(input); if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); then { span_lint_and_sugg( @@ -360,25 +371,15 @@ fn get_input_traits_and_projections<'tcx>( ) -> (Vec>, Vec>) { let mut trait_predicates = Vec::new(); let mut projection_predicates = Vec::new(); - for (predicate, _) in cx.tcx.predicates_of(callee_def_id).predicates.iter() { - // `substs` should have 1 + n elements. The first is the type on the left hand side of an - // `as`. The remaining n are trait parameters. - let is_input_substs = |substs: SubstsRef<'tcx>| { - if_chain! { - if let Some(arg) = substs.iter().next(); - if let GenericArgKind::Type(arg_ty) = arg.unpack(); - if arg_ty == input; - then { true } else { false } - } - }; + for predicate in cx.tcx.param_env(callee_def_id).caller_bounds() { match predicate.kind().skip_binder() { PredicateKind::Trait(trait_predicate) => { - if is_input_substs(trait_predicate.trait_ref.substs) { + if trait_predicate.trait_ref.self_ty() == input { trait_predicates.push(trait_predicate); } }, PredicateKind::Projection(projection_predicate) => { - if is_input_substs(projection_predicate.projection_ty.substs) { + if projection_predicate.projection_ty.self_ty() == input { projection_predicates.push(projection_predicate); } }, diff --git a/clippy_lints/src/methods/unwrap_used.rs b/clippy_lints/src/methods/unwrap_used.rs index ce1a52e5480a..ee17f2d7889e 100644 --- a/clippy_lints/src/methods/unwrap_used.rs +++ b/clippy_lints/src/methods/unwrap_used.rs @@ -7,18 +7,26 @@ use rustc_span::sym; use super::{EXPECT_USED, UNWRAP_USED}; -/// lint use of `unwrap()` for `Option`s and `Result`s -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, allow_unwrap_in_tests: bool) { +/// lint use of `unwrap()` or `unwrap_err` for `Result` and `unwrap()` for `Option`. +pub(super) fn check( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + recv: &hir::Expr<'_>, + is_err: bool, + allow_unwrap_in_tests: bool, +) { let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); - let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) { + let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err { Some((UNWRAP_USED, "an Option", "None", "")) } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) { - Some((UNWRAP_USED, "a Result", "Err", "an ")) + Some((UNWRAP_USED, "a Result", if is_err { "Ok" } else { "Err" }, "an ")) } else { None }; + let method_suffix = if is_err { "_err" } else { "" }; + if allow_unwrap_in_tests && is_in_test_function(cx.tcx, expr.hir_id) { return; } @@ -27,7 +35,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr let help = if is_lint_allowed(cx, EXPECT_USED, expr.hir_id) { format!( "if you don't want to handle the `{none_value}` case gracefully, consider \ - using `expect()` to provide a better panic message" + using `expect{method_suffix}()` to provide a better panic message" ) } else { format!("if this value is {none_prefix}`{none_value}`, it will panic") @@ -37,7 +45,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr cx, lint, expr.span, - &format!("used `unwrap()` on `{kind}` value"), + &format!("used `unwrap{method_suffix}()` on `{kind}` value"), None, &help, ); diff --git a/clippy_lints/src/methods/vec_resize_to_zero.rs b/clippy_lints/src/methods/vec_resize_to_zero.rs new file mode 100644 index 000000000000..02d8364cb295 --- /dev/null +++ b/clippy_lints/src/methods/vec_resize_to_zero.rs @@ -0,0 +1,45 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::ty::is_type_diagnostic_item; +use if_chain::if_chain; +use rustc_ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::source_map::Spanned; +use rustc_span::{sym, Span}; + +use super::VEC_RESIZE_TO_ZERO; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + count_arg: &'tcx Expr<'_>, + default_arg: &'tcx Expr<'_>, + name_span: Span, +) { + if_chain! { + if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(method_id); + if is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id), sym::Vec); + if let ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = count_arg.kind; + if let ExprKind::Lit(Spanned { node: LitKind::Int(..), .. }) = default_arg.kind; + then { + let method_call_span = expr.span.with_lo(name_span.lo()); + span_lint_and_then( + cx, + VEC_RESIZE_TO_ZERO, + expr.span, + "emptying a vector with `resize`", + |db| { + db.help("the arguments may be inverted..."); + db.span_suggestion( + method_call_span, + "...or you can empty the vector with", + "clear()".to_string(), + Applicability::MaybeIncorrect, + ); + }, + ); + } + } +} diff --git a/clippy_lints/src/methods/verbose_file_reads.rs b/clippy_lints/src/methods/verbose_file_reads.rs new file mode 100644 index 000000000000..2fe5ae9a9ad8 --- /dev/null +++ b/clippy_lints/src/methods/verbose_file_reads.rs @@ -0,0 +1,28 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_trait_method; +use clippy_utils::ty::is_type_diagnostic_item; +use rustc_hir::{Expr, ExprKind, QPath}; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::VERBOSE_FILE_READS; + +pub(super) const READ_TO_END_MSG: (&str, &str) = ("use of `File::read_to_end`", "consider using `fs::read` instead"); +pub(super) const READ_TO_STRING_MSG: (&str, &str) = ( + "use of `File::read_to_string`", + "consider using `fs::read_to_string` instead", +); + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + recv: &'tcx Expr<'_>, + (msg, help): (&str, &str), +) { + if is_trait_method(cx, expr, sym::IoRead) + && matches!(recv.kind, ExprKind::Path(QPath::Resolved(None, _))) + && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(recv).peel_refs(), sym::File) + { + span_lint_and_help(cx, VERBOSE_FILE_READS, expr.span, msg, None, help); + } +} diff --git a/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs b/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs index df044538fe19..7c4ae746e90e 100644 --- a/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs +++ b/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs @@ -46,7 +46,7 @@ fn span_lint(cx: &EarlyContext<'_>, span: Span, only_one: bool) { "these patterns are unneeded as the `..` pattern can match those elements" }, if only_one { "remove it" } else { "remove them" }, - "".to_string(), + String::new(), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/mismatching_type_param_order.rs b/clippy_lints/src/mismatching_type_param_order.rs index f763e0d24c94..020efeaebf02 100644 --- a/clippy_lints/src/mismatching_type_param_order.rs +++ b/clippy_lints/src/mismatching_type_param_order.rs @@ -40,7 +40,7 @@ declare_clippy_lint! { /// } /// impl Foo {} /// ``` - #[clippy::version = "1.62.0"] + #[clippy::version = "1.63.0"] pub MISMATCHING_TYPE_PARAM_ORDER, pedantic, "type parameter positioned inconsistently between type def and impl block" diff --git a/clippy_lints/src/multi_assignments.rs b/clippy_lints/src/multi_assignments.rs new file mode 100644 index 000000000000..81eb1a085aea --- /dev/null +++ b/clippy_lints/src/multi_assignments.rs @@ -0,0 +1,65 @@ +use clippy_utils::diagnostics::span_lint; +use rustc_ast::ast::{Expr, ExprKind, Stmt, StmtKind}; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for nested assignments. + /// + /// ### Why is this bad? + /// While this is in most cases already a type mismatch, + /// the result of an assignment being `()` can throw off people coming from languages like python or C, + /// where such assignments return a copy of the assigned value. + /// + /// ### Example + /// ```rust + ///# let (a, b); + /// a = b = 42; + /// ``` + /// Use instead: + /// ```rust + ///# let (a, b); + /// b = 42; + /// a = b; + /// ``` + #[clippy::version = "1.65.0"] + pub MULTI_ASSIGNMENTS, + suspicious, + "instead of using `a = b = c;` use `a = c; b = c;`" +} + +declare_lint_pass!(MultiAssignments => [MULTI_ASSIGNMENTS]); + +fn strip_paren_blocks(expr: &Expr) -> &Expr { + match &expr.kind { + ExprKind::Paren(e) => strip_paren_blocks(e), + ExprKind::Block(b, _) => { + if let [ + Stmt { + kind: StmtKind::Expr(e), + .. + }, + ] = &b.stmts[..] + { + strip_paren_blocks(e) + } else { + expr + } + }, + _ => expr, + } +} + +impl EarlyLintPass for MultiAssignments { + fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { + if let ExprKind::Assign(target, source, _) = &expr.kind { + if let ExprKind::Assign(_target, _source, _) = &strip_paren_blocks(target).kind { + span_lint(cx, MULTI_ASSIGNMENTS, expr.span, "assignments don't nest intuitively"); + }; + if let ExprKind::Assign(_target, _source, _) = &strip_paren_blocks(source).kind { + span_lint(cx, MULTI_ASSIGNMENTS, expr.span, "assignments don't nest intuitively"); + } + }; + } +} diff --git a/clippy_lints/src/mut_mutex_lock.rs b/clippy_lints/src/mut_mutex_lock.rs deleted file mode 100644 index b7f981faa2d4..000000000000 --- a/clippy_lints/src/mut_mutex_lock.rs +++ /dev/null @@ -1,70 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::ty::is_type_diagnostic_item; -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, Mutability}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; - -declare_clippy_lint! { - /// ### What it does - /// Checks for `&mut Mutex::lock` calls - /// - /// ### Why is this bad? - /// `Mutex::lock` is less efficient than - /// calling `Mutex::get_mut`. In addition you also have a statically - /// guarantee that the mutex isn't locked, instead of just a runtime - /// guarantee. - /// - /// ### Example - /// ```rust - /// use std::sync::{Arc, Mutex}; - /// - /// let mut value_rc = Arc::new(Mutex::new(42_u8)); - /// let value_mutex = Arc::get_mut(&mut value_rc).unwrap(); - /// - /// let mut value = value_mutex.lock().unwrap(); - /// *value += 1; - /// ``` - /// Use instead: - /// ```rust - /// use std::sync::{Arc, Mutex}; - /// - /// let mut value_rc = Arc::new(Mutex::new(42_u8)); - /// let value_mutex = Arc::get_mut(&mut value_rc).unwrap(); - /// - /// let value = value_mutex.get_mut().unwrap(); - /// *value += 1; - /// ``` - #[clippy::version = "1.49.0"] - pub MUT_MUTEX_LOCK, - style, - "`&mut Mutex::lock` does unnecessary locking" -} - -declare_lint_pass!(MutMutexLock => [MUT_MUTEX_LOCK]); - -impl<'tcx> LateLintPass<'tcx> for MutMutexLock { - fn check_expr(&mut self, cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>) { - if_chain! { - if let ExprKind::MethodCall(path, [self_arg, ..], _) = &ex.kind; - if path.ident.name == sym!(lock); - let ty = cx.typeck_results().expr_ty(self_arg); - if let ty::Ref(_, inner_ty, Mutability::Mut) = ty.kind(); - if is_type_diagnostic_item(cx, *inner_ty, sym::Mutex); - then { - span_lint_and_sugg( - cx, - MUT_MUTEX_LOCK, - path.ident.span, - "calling `&mut Mutex::lock` unnecessarily locks an exclusive (mutable) reference", - "change this to", - "get_mut".to_owned(), - Applicability::MaybeIncorrect, - ); - } - } - } -} diff --git a/clippy_lints/src/only_used_in_recursion.rs b/clippy_lints/src/only_used_in_recursion.rs index 413a740be25a..774a3540d1e0 100644 --- a/clippy_lints/src/only_used_in_recursion.rs +++ b/clippy_lints/src/only_used_in_recursion.rs @@ -1,25 +1,16 @@ -use std::collections::VecDeque; - -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_lint_allowed; -use itertools::{izip, Itertools}; -use rustc_ast::{walk_list, Label, Mutability}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::{get_expr_use_or_unification_node, get_parent_node, path_def_id, path_to_local, path_to_local_id}; +use core::cell::Cell; +use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; -use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; -use rustc_hir::intravisit::{walk_expr, walk_stmt, FnKind, Visitor}; -use rustc_hir::{ - Arm, Block, Body, Closure, Expr, ExprKind, Guard, HirId, ImplicitSelfKind, Let, Local, Pat, PatKind, Path, - PathSegment, QPath, Stmt, StmtKind, TyKind, UnOp, -}; +use rustc_hir::hir_id::HirIdMap; +use rustc_hir::{Body, Expr, ExprKind, HirId, ImplItem, ImplItemKind, Node, PatKind, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; -use rustc_middle::ty::{Ty, TyCtxt, TypeckResults}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::symbol::kw; -use rustc_span::symbol::Ident; +use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; +use rustc_middle::ty::{self, ConstKind}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::symbol::{kw, Ident}; use rustc_span::Span; declare_clippy_lint! { @@ -89,572 +80,323 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.61.0"] pub ONLY_USED_IN_RECURSION, - nursery, + complexity, "arguments that is only used in recursion can be removed" } -declare_lint_pass!(OnlyUsedInRecursion => [ONLY_USED_IN_RECURSION]); +impl_lint_pass!(OnlyUsedInRecursion => [ONLY_USED_IN_RECURSION]); + +#[derive(Clone, Copy)] +enum FnKind { + Fn, + TraitFn, + // This is a hack. Ideally we would store a `SubstsRef<'tcx>` type here, but a lint pass must be `'static`. + // Substitutions are, however, interned. This allows us to store the pointer as a `usize` when comparing for + // equality. + ImplTraitFn(usize), +} + +struct Param { + /// The function this is a parameter for. + fn_id: DefId, + fn_kind: FnKind, + /// The index of this parameter. + idx: usize, + ident: Ident, + /// Whether this parameter should be linted. Set by `Params::flag_for_linting`. + apply_lint: Cell, + /// All the uses of this parameter. + uses: Vec, +} +impl Param { + fn new(fn_id: DefId, fn_kind: FnKind, idx: usize, ident: Ident) -> Self { + Self { + fn_id, + fn_kind, + idx, + ident, + apply_lint: Cell::new(true), + uses: Vec::new(), + } + } +} + +#[derive(Debug)] +struct Usage { + span: Span, + idx: usize, +} +impl Usage { + fn new(span: Span, idx: usize) -> Self { + Self { span, idx } + } +} + +/// The parameters being checked by the lint, indexed by both the parameter's `HirId` and the +/// `DefId` of the function paired with the parameter's index. +#[derive(Default)] +struct Params { + params: Vec, + by_id: HirIdMap, + by_fn: FxHashMap<(DefId, usize), usize>, +} +impl Params { + fn insert(&mut self, param: Param, id: HirId) { + let idx = self.params.len(); + self.by_id.insert(id, idx); + self.by_fn.insert((param.fn_id, param.idx), idx); + self.params.push(param); + } + + fn remove_by_id(&mut self, id: HirId) { + if let Some(param) = self.get_by_id_mut(id) { + param.uses = Vec::new(); + let key = (param.fn_id, param.idx); + self.by_fn.remove(&key); + self.by_id.remove(&id); + } + } + + fn get_by_id_mut(&mut self, id: HirId) -> Option<&mut Param> { + self.params.get_mut(*self.by_id.get(&id)?) + } + + fn get_by_fn(&self, id: DefId, idx: usize) -> Option<&Param> { + self.params.get(*self.by_fn.get(&(id, idx))?) + } + + fn clear(&mut self) { + self.params.clear(); + self.by_id.clear(); + self.by_fn.clear(); + } + + /// Sets the `apply_lint` flag on each parameter. + fn flag_for_linting(&mut self) { + // Stores the list of parameters currently being resolved. Needed to avoid cycles. + let mut eval_stack = Vec::new(); + for param in &self.params { + self.try_disable_lint_for_param(param, &mut eval_stack); + } + } + + // Use by calling `flag_for_linting`. + fn try_disable_lint_for_param(&self, param: &Param, eval_stack: &mut Vec) -> bool { + if !param.apply_lint.get() { + true + } else if param.uses.is_empty() { + // Don't lint on unused parameters. + param.apply_lint.set(false); + true + } else if eval_stack.contains(¶m.idx) { + // Already on the evaluation stack. Returning false will continue to evaluate other dependencies. + false + } else { + eval_stack.push(param.idx); + // Check all cases when used at a different parameter index. + // Needed to catch cases like: `fn f(x: u32, y: u32) { f(y, x) }` + for usage in param.uses.iter().filter(|u| u.idx != param.idx) { + if self + .get_by_fn(param.fn_id, usage.idx) + // If the parameter can't be found, then it's used for more than just recursion. + .map_or(true, |p| self.try_disable_lint_for_param(p, eval_stack)) + { + param.apply_lint.set(false); + eval_stack.pop(); + return true; + } + } + eval_stack.pop(); + false + } + } +} + +#[derive(Default)] +pub struct OnlyUsedInRecursion { + /// Track the top-level body entered. Needed to delay reporting when entering nested bodies. + entered_body: Option, + params: Params, +} impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { - fn check_fn( - &mut self, - cx: &LateContext<'tcx>, - kind: FnKind<'tcx>, - decl: &'tcx rustc_hir::FnDecl<'tcx>, - body: &'tcx Body<'tcx>, - _: Span, - id: HirId, - ) { - if is_lint_allowed(cx, ONLY_USED_IN_RECURSION, id) { + fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'tcx>) { + if body.value.span.from_expansion() { return; } - if let FnKind::ItemFn(ident, ..) | FnKind::Method(ident, ..) = kind { - let def_id = id.owner.to_def_id(); - let data = cx.tcx.def_path(def_id).data; - - if data.len() > 1 { - match data.get(data.len() - 2) { - Some(DisambiguatedDefPathData { - data: DefPathData::Impl, - disambiguator, - }) if *disambiguator != 0 => return, - _ => {}, - } - } - - let has_self = !matches!(decl.implicit_self, ImplicitSelfKind::None); - - let ty_res = cx.typeck_results(); - let param_span = body - .params - .iter() - .flat_map(|param| { - let mut v = Vec::new(); - param.pat.each_binding(|_, hir_id, span, ident| { - v.push((hir_id, span, ident)); - }); - v - }) - .skip(if has_self { 1 } else { 0 }) - .filter(|(_, _, ident)| !ident.name.as_str().starts_with('_')) - .collect_vec(); - - let params = body.params.iter().map(|param| param.pat).collect(); - - let mut visitor = SideEffectVisit { - graph: FxHashMap::default(), - has_side_effect: FxHashSet::default(), - ret_vars: Vec::new(), - contains_side_effect: false, - break_vars: FxHashMap::default(), - params, - fn_ident: ident, - fn_def_id: def_id, - is_method: matches!(kind, FnKind::Method(..)), - has_self, - ty_res, - tcx: cx.tcx, - visited_exprs: FxHashSet::default(), - }; - - visitor.visit_expr(&body.value); - let vars = std::mem::take(&mut visitor.ret_vars); - // this would set the return variables to side effect - visitor.add_side_effect(vars); - - let mut queue = visitor.has_side_effect.iter().copied().collect::>(); - - // a simple BFS to check all the variables that have side effect - while let Some(id) = queue.pop_front() { - if let Some(next) = visitor.graph.get(&id) { - for i in next { - if !visitor.has_side_effect.contains(i) { - visitor.has_side_effect.insert(*i); - queue.push_back(*i); - } - } - } - } - - for (id, span, ident) in param_span { - // if the variable is not used in recursion, it would be marked as unused - if !visitor.has_side_effect.contains(&id) { - let mut queue = VecDeque::new(); - let mut visited = FxHashSet::default(); - - queue.push_back(id); - - // a simple BFS to check the graph can reach to itself - // if it can't, it means the variable is never used in recursion - while let Some(id) = queue.pop_front() { - if let Some(next) = visitor.graph.get(&id) { - for i in next { - if !visited.contains(i) { - visited.insert(id); - queue.push_back(*i); - } - } - } - } - - if visited.contains(&id) { - span_lint_and_sugg( - cx, - ONLY_USED_IN_RECURSION, - span, - "parameter is only used in recursion", - "if this is intentional, prefix with an underscore", - format!("_{}", ident.name.as_str()), - Applicability::MaybeIncorrect, - ); - } - } - } - } - } -} - -pub fn is_primitive(ty: Ty<'_>) -> bool { - let ty = ty.peel_refs(); - ty.is_primitive() || ty.is_str() -} - -pub fn is_array(ty: Ty<'_>) -> bool { - let ty = ty.peel_refs(); - ty.is_array() || ty.is_array_slice() -} - -/// This builds the graph of side effect. -/// The edge `a -> b` means if `a` has side effect, `b` will have side effect. -/// -/// There are some example in following code: -/// ```rust, ignore -/// let b = 1; -/// let a = b; // a -> b -/// let (c, d) = (a, b); // c -> b, d -> b -/// -/// let e = if a == 0 { // e -> a -/// c // e -> c -/// } else { -/// d // e -> d -/// }; -/// ``` -pub struct SideEffectVisit<'tcx> { - graph: FxHashMap>, - has_side_effect: FxHashSet, - // bool for if the variable was dereferenced from mutable reference - ret_vars: Vec<(HirId, bool)>, - contains_side_effect: bool, - // break label - break_vars: FxHashMap>, - params: Vec<&'tcx Pat<'tcx>>, - fn_ident: Ident, - fn_def_id: DefId, - is_method: bool, - has_self: bool, - ty_res: &'tcx TypeckResults<'tcx>, - tcx: TyCtxt<'tcx>, - visited_exprs: FxHashSet, -} - -impl<'tcx> Visitor<'tcx> for SideEffectVisit<'tcx> { - fn visit_stmt(&mut self, s: &'tcx Stmt<'tcx>) { - match s.kind { - StmtKind::Local(Local { - pat, init: Some(init), .. - }) => { - self.visit_pat_expr(pat, init, false); - }, - StmtKind::Item(_) | StmtKind::Expr(_) | StmtKind::Semi(_) => { - walk_stmt(self, s); - }, - StmtKind::Local(_) => {}, - } - self.ret_vars.clear(); - } - - fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { - if !self.visited_exprs.insert(ex.hir_id) { - return; - } - match ex.kind { - ExprKind::Array(exprs) | ExprKind::Tup(exprs) => { - self.ret_vars = exprs - .iter() - .flat_map(|expr| { - self.visit_expr(expr); - std::mem::take(&mut self.ret_vars) - }) - .collect(); - }, - ExprKind::Call(callee, args) => self.visit_fn(callee, args), - ExprKind::MethodCall(path, args, _) => self.visit_method_call(path, args), - ExprKind::Binary(_, lhs, rhs) => { - self.visit_bin_op(lhs, rhs); - }, - ExprKind::Unary(op, expr) => self.visit_un_op(op, expr), - ExprKind::Let(Let { pat, init, .. }) => self.visit_pat_expr(pat, init, false), - ExprKind::If(bind, then_expr, else_expr) => { - self.visit_if(bind, then_expr, else_expr); - }, - ExprKind::Match(expr, arms, _) => self.visit_match(expr, arms), - // since analysing the closure is not easy, just set all variables in it to side-effect - ExprKind::Closure(&Closure { body, .. }) => { - let body = self.tcx.hir().body(body); - self.visit_body(body); - let vars = std::mem::take(&mut self.ret_vars); - self.add_side_effect(vars); - }, - ExprKind::Loop(block, label, _, _) | ExprKind::Block(block, label) => { - self.visit_block_label(block, label); - }, - ExprKind::Assign(bind, expr, _) => { - self.visit_assign(bind, expr); - }, - ExprKind::AssignOp(_, bind, expr) => { - self.visit_assign(bind, expr); - self.visit_bin_op(bind, expr); - }, - ExprKind::Field(expr, _) => { - self.visit_expr(expr); - if matches!(self.ty_res.expr_ty(expr).kind(), ty::Ref(_, _, Mutability::Mut)) { - self.ret_vars.iter_mut().for_each(|(_, b)| *b = true); + // `skip_params` is either `0` or `1` to skip the `self` parameter in trait functions. + // It can't be renamed, and it can't be removed without removing it from multiple functions. + let (fn_id, fn_kind, skip_params) = match get_parent_node(cx.tcx, body.value.hir_id) { + Some(Node::Item(i)) => (i.def_id.to_def_id(), FnKind::Fn, 0), + Some(Node::TraitItem(&TraitItem { + kind: TraitItemKind::Fn(ref sig, _), + def_id, + .. + })) => ( + def_id.to_def_id(), + FnKind::TraitFn, + if sig.decl.implicit_self.has_implicit_self() { + 1 + } else { + 0 + }, + ), + Some(Node::ImplItem(&ImplItem { + kind: ImplItemKind::Fn(ref sig, _), + def_id, + .. + })) => { + #[allow(trivial_casts)] + if let Some(Node::Item(item)) = get_parent_node(cx.tcx, cx.tcx.hir().local_def_id_to_hir_id(def_id)) + && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.def_id) + && let Some(trait_item_id) = cx.tcx.associated_item(def_id).trait_item_def_id + { + ( + trait_item_id, + FnKind::ImplTraitFn(cx.tcx.erase_regions(trait_ref.substs) as *const _ as usize), + if sig.decl.implicit_self.has_implicit_self() { + 1 + } else { + 0 + }, + ) + } else { + (def_id.to_def_id(), FnKind::Fn, 0) } }, - ExprKind::Index(expr, index) => { - self.visit_expr(expr); - let mut vars = std::mem::take(&mut self.ret_vars); - self.visit_expr(index); - self.ret_vars.append(&mut vars); - - if !is_array(self.ty_res.expr_ty(expr)) { - self.add_side_effect(self.ret_vars.clone()); - } else if matches!(self.ty_res.expr_ty(expr).kind(), ty::Ref(_, _, Mutability::Mut)) { - self.ret_vars.iter_mut().for_each(|(_, b)| *b = true); - } - }, - ExprKind::Break(dest, Some(expr)) => { - self.visit_expr(expr); - if let Some(label) = dest.label { - self.break_vars - .entry(label.ident) - .or_insert(Vec::new()) - .append(&mut self.ret_vars); - } - self.contains_side_effect = true; - }, - ExprKind::Ret(Some(expr)) => { - self.visit_expr(expr); - let vars = std::mem::take(&mut self.ret_vars); - self.add_side_effect(vars); - self.contains_side_effect = true; - }, - ExprKind::Break(_, None) | ExprKind::Continue(_) | ExprKind::Ret(None) => { - self.contains_side_effect = true; - }, - ExprKind::Struct(_, exprs, expr) => { - let mut ret_vars = exprs - .iter() - .flat_map(|field| { - self.visit_expr(field.expr); - std::mem::take(&mut self.ret_vars) - }) - .collect(); - - walk_list!(self, visit_expr, expr); - self.ret_vars.append(&mut ret_vars); - }, - _ => walk_expr(self, ex), - } - } - - fn visit_path(&mut self, path: &'tcx Path<'tcx>, _id: HirId) { - if let Res::Local(id) = path.res { - self.ret_vars.push((id, false)); - } - } -} - -impl<'tcx> SideEffectVisit<'tcx> { - fn visit_assign(&mut self, lhs: &'tcx Expr<'tcx>, rhs: &'tcx Expr<'tcx>) { - // Just support array and tuple unwrapping for now. - // - // ex) `(a, b) = (c, d);` - // The graph would look like this: - // a -> c - // b -> d - // - // This would minimize the connection of the side-effect graph. - match (&lhs.kind, &rhs.kind) { - (ExprKind::Array(lhs), ExprKind::Array(rhs)) | (ExprKind::Tup(lhs), ExprKind::Tup(rhs)) => { - // if not, it is a compile error - debug_assert!(lhs.len() == rhs.len()); - izip!(*lhs, *rhs).for_each(|(lhs, rhs)| self.visit_assign(lhs, rhs)); - }, - // in other assigns, we have to connect all each other - // because they can be connected somehow - _ => { - self.visit_expr(lhs); - let lhs_vars = std::mem::take(&mut self.ret_vars); - self.visit_expr(rhs); - let rhs_vars = std::mem::take(&mut self.ret_vars); - self.connect_assign(&lhs_vars, &rhs_vars, false); - }, - } - } - - fn visit_block_label(&mut self, block: &'tcx Block<'tcx>, label: Option + ImplTrait {} + +fn main() {} diff --git a/tests/ui/trait_duplication_in_bounds_unfixable.stderr b/tests/ui/trait_duplication_in_bounds_unfixable.stderr new file mode 100644 index 000000000000..fbd9abb005f1 --- /dev/null +++ b/tests/ui/trait_duplication_in_bounds_unfixable.stderr @@ -0,0 +1,71 @@ +error: this trait bound is already specified in the where clause + --> $DIR/trait_duplication_in_bounds_unfixable.rs:6:15 + | +LL | fn bad_foo(arg0: T, arg1: Z) + | ^^^^^ + | +note: the lint level is defined here + --> $DIR/trait_duplication_in_bounds_unfixable.rs:1:9 + | +LL | #![deny(clippy::trait_duplication_in_bounds)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: consider removing this trait bound + +error: this trait bound is already specified in the where clause + --> $DIR/trait_duplication_in_bounds_unfixable.rs:6:23 + | +LL | fn bad_foo(arg0: T, arg1: Z) + | ^^^^^^^ + | + = help: consider removing this trait bound + +error: this trait bound is already specified in trait declaration + --> $DIR/trait_duplication_in_bounds_unfixable.rs:35:15 + | +LL | Self: Default; + | ^^^^^^^ + | + = help: consider removing this trait bound + +error: this trait bound is already specified in trait declaration + --> $DIR/trait_duplication_in_bounds_unfixable.rs:49:15 + | +LL | Self: Default + Clone; + | ^^^^^^^ + | + = help: consider removing this trait bound + +error: this trait bound is already specified in trait declaration + --> $DIR/trait_duplication_in_bounds_unfixable.rs:55:15 + | +LL | Self: Default + Clone; + | ^^^^^^^ + | + = help: consider removing this trait bound + +error: this trait bound is already specified in trait declaration + --> $DIR/trait_duplication_in_bounds_unfixable.rs:55:25 + | +LL | Self: Default + Clone; + | ^^^^^ + | + = help: consider removing this trait bound + +error: this trait bound is already specified in trait declaration + --> $DIR/trait_duplication_in_bounds_unfixable.rs:58:15 + | +LL | Self: Default; + | ^^^^^^^ + | + = help: consider removing this trait bound + +error: this trait bound is already specified in trait declaration + --> $DIR/trait_duplication_in_bounds_unfixable.rs:93:15 + | +LL | Self: Iterator, + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider removing this trait bound + +error: aborting due to 8 previous errors + diff --git a/tests/ui/transmute_undefined_repr.rs b/tests/ui/transmute_undefined_repr.rs index ebcaa7a84cfb..5aad0b44270a 100644 --- a/tests/ui/transmute_undefined_repr.rs +++ b/tests/ui/transmute_undefined_repr.rs @@ -4,6 +4,7 @@ use core::any::TypeId; use core::ffi::c_void; use core::mem::{size_of, transmute, MaybeUninit}; +use core::ptr::NonNull; fn value() -> T { unimplemented!() @@ -109,6 +110,17 @@ fn main() { let _: Ty2 = transmute(value::>>()); // Ok let _: Ty<&[u32]> = transmute::<&[u32], _>(value::<&Vec>()); // Ok + + let _: *const Ty2 = transmute(value::<*const Ty2C, u32>>()); // Ok + let _: *const Ty2C, u32> = transmute(value::<*const Ty2>()); // Ok + let _: *const Ty2 = transmute(value::<*const Ty2C<(), Ty2>>()); // Ok + let _: *const Ty2C<(), Ty2> = transmute(value::<*const Ty2>()); // Ok + + let _: *const Ty2 = transmute(value::<*const Ty2C>>()); // Err + let _: *const Ty2C> = transmute(value::<*const Ty2>()); // Err + + let _: NonNull = transmute(value::>()); // Ok + let _: NonNull<(String, String)> = transmute(value::>()); // Ok } } diff --git a/tests/ui/transmute_undefined_repr.stderr b/tests/ui/transmute_undefined_repr.stderr index 28bfba6c7571..e50a773290e1 100644 --- a/tests/ui/transmute_undefined_repr.stderr +++ b/tests/ui/transmute_undefined_repr.stderr @@ -1,5 +1,5 @@ error: transmute from `Ty2` which has an undefined layout - --> $DIR/transmute_undefined_repr.rs:27:33 + --> $DIR/transmute_undefined_repr.rs:28:33 | LL | let _: Ty2C = transmute(value::>()); // Lint, Ty2 is unordered | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,13 +7,13 @@ LL | let _: Ty2C = transmute(value::>()); // Lin = note: `-D clippy::transmute-undefined-repr` implied by `-D warnings` error: transmute into `Ty2` which has an undefined layout - --> $DIR/transmute_undefined_repr.rs:28:32 + --> $DIR/transmute_undefined_repr.rs:29:32 | LL | let _: Ty2 = transmute(value::>()); // Lint, Ty2 is unordered | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from `Ty>` to `Ty2`, both of which have an undefined layout - --> $DIR/transmute_undefined_repr.rs:33:32 + --> $DIR/transmute_undefined_repr.rs:34:32 | LL | let _: Ty2 = transmute(value::>>()); // Lint, different Ty2 instances | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -21,7 +21,7 @@ LL | let _: Ty2 = transmute(value::>>()); // = note: two instances of the same generic type (`Ty2`) may have different layouts error: transmute from `Ty2` to `Ty>`, both of which have an undefined layout - --> $DIR/transmute_undefined_repr.rs:34:36 + --> $DIR/transmute_undefined_repr.rs:35:36 | LL | let _: Ty> = transmute(value::>()); // Lint, different Ty2 instances | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -29,7 +29,7 @@ LL | let _: Ty> = transmute(value::>()); // = note: two instances of the same generic type (`Ty2`) may have different layouts error: transmute from `Ty<&Ty2>` to `&Ty2`, both of which have an undefined layout - --> $DIR/transmute_undefined_repr.rs:39:33 + --> $DIR/transmute_undefined_repr.rs:40:33 | LL | let _: &Ty2 = transmute(value::>>()); // Lint, different Ty2 instances | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL | let _: &Ty2 = transmute(value::>>()); / = note: two instances of the same generic type (`Ty2`) may have different layouts error: transmute from `&Ty2` to `Ty<&Ty2>`, both of which have an undefined layout - --> $DIR/transmute_undefined_repr.rs:40:37 + --> $DIR/transmute_undefined_repr.rs:41:37 | LL | let _: Ty<&Ty2> = transmute(value::<&Ty2>()); // Lint, different Ty2 instances | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -45,7 +45,7 @@ LL | let _: Ty<&Ty2> = transmute(value::<&Ty2>()); / = note: two instances of the same generic type (`Ty2`) may have different layouts error: transmute from `std::boxed::Box>` to `&mut Ty2`, both of which have an undefined layout - --> $DIR/transmute_undefined_repr.rs:57:45 + --> $DIR/transmute_undefined_repr.rs:58:45 | LL | let _: &'static mut Ty2 = transmute(value::>>()); // Lint, different Ty2 instances | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -53,15 +53,31 @@ LL | let _: &'static mut Ty2 = transmute(value::` to `std::boxed::Box>`, both of which have an undefined layout - --> $DIR/transmute_undefined_repr.rs:58:37 + --> $DIR/transmute_undefined_repr.rs:59:37 | LL | let _: Box> = transmute(value::<&'static mut Ty2>()); // Lint, different Ty2 instances | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: two instances of the same generic type (`Ty2`) may have different layouts +error: transmute into `*const Ty2` which has an undefined layout + --> $DIR/transmute_undefined_repr.rs:119:39 + | +LL | let _: *const Ty2 = transmute(value::<*const Ty2C>>()); // Err + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the contained type `Ty2` has an undefined layout + +error: transmute from `*const Ty2` which has an undefined layout + --> $DIR/transmute_undefined_repr.rs:120:50 + | +LL | let _: *const Ty2C> = transmute(value::<*const Ty2>()); // Err + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the contained type `Ty2` has an undefined layout + error: transmute from `std::vec::Vec>` to `std::vec::Vec>`, both of which have an undefined layout - --> $DIR/transmute_undefined_repr.rs:138:35 + --> $DIR/transmute_undefined_repr.rs:150:35 | LL | let _: Vec> = transmute(value::>>()); // Err | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -69,12 +85,12 @@ LL | let _: Vec> = transmute(value::>>()); / = note: two instances of the same generic type (`Vec`) may have different layouts error: transmute from `std::vec::Vec>` to `std::vec::Vec>`, both of which have an undefined layout - --> $DIR/transmute_undefined_repr.rs:139:35 + --> $DIR/transmute_undefined_repr.rs:151:35 | LL | let _: Vec> = transmute(value::>>()); // Err | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: two instances of the same generic type (`Vec`) may have different layouts -error: aborting due to 10 previous errors +error: aborting due to 12 previous errors diff --git a/tests/ui/unicode.fixed b/tests/ui/unicode.fixed index 328cda369e11..94b4723452fa 100644 --- a/tests/ui/unicode.fixed +++ b/tests/ui/unicode.fixed @@ -1,4 +1,7 @@ // run-rustfix +// compile-flags: --test +#![allow(dead_code)] + #[warn(clippy::invisible_characters)] fn zero() { print!("Here >\u{200B}< is a ZWS, and \u{200B}another"); @@ -15,22 +18,43 @@ fn canon() { print!("a\u{0300}h?"); // also ok } -#[warn(clippy::non_ascii_literal)] -fn uni() { - print!("\u{dc}ben!"); - print!("\u{DC}ben!"); // this is ok -} +mod non_ascii_literal { + #![deny(clippy::non_ascii_literal)] -// issue 8013 -#[warn(clippy::non_ascii_literal)] -fn single_quote() { - const _EMPTY_BLOCK: char = '\u{25b1}'; - const _FULL_BLOCK: char = '\u{25b0}'; + fn uni() { + print!("\u{dc}ben!"); + print!("\u{DC}ben!"); // this is ok + } + + // issue 8013 + fn single_quote() { + const _EMPTY_BLOCK: char = '\u{25b1}'; + const _FULL_BLOCK: char = '\u{25b0}'; + } + + #[test] + pub fn issue_7739() { + // Ryū crate: https://github.com/dtolnay/ryu + } + + mod issue_8263 { + #![deny(clippy::non_ascii_literal)] + + // Re-allow for a single test + #[test] + #[allow(clippy::non_ascii_literal)] + fn allowed() { + let _ = "悲しいかな、ここに日本語を書くことはできない。"; + } + + #[test] + fn denied() { + let _ = "\u{60b2}\u{3057}\u{3044}\u{304b}\u{306a}\u{3001}\u{3053}\u{3053}\u{306b}\u{65e5}\u{672c}\u{8a9e}\u{3092}\u{66f8}\u{304f}\u{3053}\u{3068}\u{306f}\u{3067}\u{304d}\u{306a}\u{3044}\u{3002}"; + } + } } fn main() { zero(); - uni(); canon(); - single_quote(); } diff --git a/tests/ui/unicode.rs b/tests/ui/unicode.rs index 7828d6bcbea7..6ad0b255b948 100644 --- a/tests/ui/unicode.rs +++ b/tests/ui/unicode.rs @@ -1,4 +1,7 @@ // run-rustfix +// compile-flags: --test +#![allow(dead_code)] + #[warn(clippy::invisible_characters)] fn zero() { print!("Here >​< is a ZWS, and ​another"); @@ -15,22 +18,43 @@ fn canon() { print!("a\u{0300}h?"); // also ok } -#[warn(clippy::non_ascii_literal)] -fn uni() { - print!("Üben!"); - print!("\u{DC}ben!"); // this is ok -} +mod non_ascii_literal { + #![deny(clippy::non_ascii_literal)] -// issue 8013 -#[warn(clippy::non_ascii_literal)] -fn single_quote() { - const _EMPTY_BLOCK: char = '▱'; - const _FULL_BLOCK: char = '▰'; + fn uni() { + print!("Üben!"); + print!("\u{DC}ben!"); // this is ok + } + + // issue 8013 + fn single_quote() { + const _EMPTY_BLOCK: char = '▱'; + const _FULL_BLOCK: char = '▰'; + } + + #[test] + pub fn issue_7739() { + // Ryū crate: https://github.com/dtolnay/ryu + } + + mod issue_8263 { + #![deny(clippy::non_ascii_literal)] + + // Re-allow for a single test + #[test] + #[allow(clippy::non_ascii_literal)] + fn allowed() { + let _ = "悲しいかな、ここに日本語を書くことはできない。"; + } + + #[test] + fn denied() { + let _ = "悲しいかな、ここに日本語を書くことはできない。"; + } + } } fn main() { zero(); - uni(); canon(); - single_quote(); } diff --git a/tests/ui/unicode.stderr b/tests/ui/unicode.stderr index 01d3f3c02967..ea74a81451e3 100644 --- a/tests/ui/unicode.stderr +++ b/tests/ui/unicode.stderr @@ -1,5 +1,5 @@ error: invisible character detected - --> $DIR/unicode.rs:4:12 + --> $DIR/unicode.rs:7:12 | LL | print!("Here >​< is a ZWS, and ​another"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{200B}< is a ZWS, and /u{200B}another"` @@ -7,19 +7,19 @@ LL | print!("Here >​< is a ZWS, and ​another"); = note: `-D clippy::invisible-characters` implied by `-D warnings` error: invisible character detected - --> $DIR/unicode.rs:6:12 + --> $DIR/unicode.rs:9:12 | LL | print!("Here >­< is a SHY, and ­another"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{AD}< is a SHY, and /u{AD}another"` error: invisible character detected - --> $DIR/unicode.rs:8:12 + --> $DIR/unicode.rs:11:12 | LL | print!("Here >⁠< is a WJ, and ⁠another"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{2060}< is a WJ, and /u{2060}another"` error: non-NFC Unicode sequence detected - --> $DIR/unicode.rs:14:12 + --> $DIR/unicode.rs:17:12 | LL | print!("̀àh?"); | ^^^^^ help: consider replacing the string with: `"̀àh?"` @@ -27,24 +27,40 @@ LL | print!("̀àh?"); = note: `-D clippy::unicode-not-nfc` implied by `-D warnings` error: literal non-ASCII character detected - --> $DIR/unicode.rs:20:12 + --> $DIR/unicode.rs:25:16 | -LL | print!("Üben!"); - | ^^^^^^^ help: consider replacing the string with: `"/u{dc}ben!"` +LL | print!("Üben!"); + | ^^^^^^^ help: consider replacing the string with: `"/u{dc}ben!"` | - = note: `-D clippy::non-ascii-literal` implied by `-D warnings` +note: the lint level is defined here + --> $DIR/unicode.rs:22:13 + | +LL | #![deny(clippy::non_ascii_literal)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: literal non-ASCII character detected - --> $DIR/unicode.rs:27:32 + --> $DIR/unicode.rs:31:36 | -LL | const _EMPTY_BLOCK: char = '▱'; - | ^^^ help: consider replacing the string with: `'/u{25b1}'` +LL | const _EMPTY_BLOCK: char = '▱'; + | ^^^ help: consider replacing the string with: `'/u{25b1}'` error: literal non-ASCII character detected - --> $DIR/unicode.rs:28:31 + --> $DIR/unicode.rs:32:35 | -LL | const _FULL_BLOCK: char = '▰'; - | ^^^ help: consider replacing the string with: `'/u{25b0}'` +LL | const _FULL_BLOCK: char = '▰'; + | ^^^ help: consider replacing the string with: `'/u{25b0}'` -error: aborting due to 7 previous errors +error: literal non-ASCII character detected + --> $DIR/unicode.rs:52:21 + | +LL | let _ = "悲しいかな、ここに日本語を書くことはできない。"; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"/u{60b2}/u{3057}/u{3044}/u{304b}/u{306a}/u{3001}/u{3053}/u{3053}/u{306b}/u{65e5}/u{672c}/u{8a9e}/u{3092}/u{66f8}/u{304f}/u{3053}/u{3068}/u{306f}/u{3067}/u{304d}/u{306a}/u{3044}/u{3002}"` + | +note: the lint level is defined here + --> $DIR/unicode.rs:41:17 + | +LL | #![deny(clippy::non_ascii_literal)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 8 previous errors diff --git a/tests/ui/unnecessary_cast.fixed b/tests/ui/unnecessary_cast.fixed index b352b285c862..ee9f157342d4 100644 --- a/tests/ui/unnecessary_cast.fixed +++ b/tests/ui/unnecessary_cast.fixed @@ -88,4 +88,13 @@ mod fixable { } type I32Alias = i32; + + fn issue_9380() { + let _: i32 = -1_i32; + let _: f32 = -(1) as f32; + let _: i64 = -1_i64; + let _: i64 = -(1.0) as i64; + + let _ = -(1 + 1) as i64; + } } diff --git a/tests/ui/unnecessary_cast.rs b/tests/ui/unnecessary_cast.rs index 6c8cc3effe8f..5b70412424c0 100644 --- a/tests/ui/unnecessary_cast.rs +++ b/tests/ui/unnecessary_cast.rs @@ -88,4 +88,13 @@ mod fixable { } type I32Alias = i32; + + fn issue_9380() { + let _: i32 = -(1) as i32; + let _: f32 = -(1) as f32; + let _: i64 = -(1) as i64; + let _: i64 = -(1.0) as i64; + + let _ = -(1 + 1) as i64; + } } diff --git a/tests/ui/unnecessary_cast.stderr b/tests/ui/unnecessary_cast.stderr index bad45f0025b2..f7829ff3b0ef 100644 --- a/tests/ui/unnecessary_cast.stderr +++ b/tests/ui/unnecessary_cast.stderr @@ -150,5 +150,17 @@ error: casting float literal to `f32` is unnecessary LL | let _ = -1.0 as f32; | ^^^^^^^^^^^ help: try: `-1.0_f32` -error: aborting due to 25 previous errors +error: casting integer literal to `i32` is unnecessary + --> $DIR/unnecessary_cast.rs:93:22 + | +LL | let _: i32 = -(1) as i32; + | ^^^^^^^^^^^ help: try: `-1_i32` + +error: casting integer literal to `i64` is unnecessary + --> $DIR/unnecessary_cast.rs:95:22 + | +LL | let _: i64 = -(1) as i64; + | ^^^^^^^^^^^ help: try: `-1_i64` + +error: aborting due to 27 previous errors diff --git a/tests/ui/unnecessary_owned_empty_strings.fixed b/tests/ui/unnecessary_owned_empty_strings.fixed index f95f91329a2f..40052c41039e 100644 --- a/tests/ui/unnecessary_owned_empty_strings.fixed +++ b/tests/ui/unnecessary_owned_empty_strings.fixed @@ -12,6 +12,7 @@ fn main() { ref_str_argument(""); // should be linted + #[allow(clippy::manual_string_new)] ref_str_argument(""); // should not be linted diff --git a/tests/ui/unnecessary_owned_empty_strings.rs b/tests/ui/unnecessary_owned_empty_strings.rs index 0cbdc151ed9b..2304dff5192b 100644 --- a/tests/ui/unnecessary_owned_empty_strings.rs +++ b/tests/ui/unnecessary_owned_empty_strings.rs @@ -12,6 +12,7 @@ fn main() { ref_str_argument(&String::new()); // should be linted + #[allow(clippy::manual_string_new)] ref_str_argument(&String::from("")); // should not be linted diff --git a/tests/ui/unnecessary_owned_empty_strings.stderr b/tests/ui/unnecessary_owned_empty_strings.stderr index 46bc4597b335..1eb198a8675e 100644 --- a/tests/ui/unnecessary_owned_empty_strings.stderr +++ b/tests/ui/unnecessary_owned_empty_strings.stderr @@ -7,7 +7,7 @@ LL | ref_str_argument(&String::new()); = note: `-D clippy::unnecessary-owned-empty-strings` implied by `-D warnings` error: usage of `&String::from("")` for a function expecting a `&str` argument - --> $DIR/unnecessary_owned_empty_strings.rs:15:22 + --> $DIR/unnecessary_owned_empty_strings.rs:16:22 | LL | ref_str_argument(&String::from("")); | ^^^^^^^^^^^^^^^^^ help: try: `""` diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed index f4f76cd3dd49..9cd5bc73b1ec 100644 --- a/tests/ui/unnecessary_to_owned.fixed +++ b/tests/ui/unnecessary_to_owned.fixed @@ -329,3 +329,31 @@ mod issue_8759_variant { rw.set_view(&rw.default_view().to_owned()); } } + +mod issue_9317 { + #![allow(dead_code)] + + struct Bytes {} + + impl ToString for Bytes { + fn to_string(&self) -> String { + "123".to_string() + } + } + + impl AsRef<[u8]> for Bytes { + fn as_ref(&self) -> &[u8] { + &[1, 2, 3] + } + } + + fn consume>(c: C) { + let _ = c; + } + + pub fn main() { + let b = Bytes {}; + // Should not lint. + consume(b.to_string()); + } +} diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index fe09a489ab0a..7f62ba3ab5d5 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -329,3 +329,31 @@ mod issue_8759_variant { rw.set_view(&rw.default_view().to_owned()); } } + +mod issue_9317 { + #![allow(dead_code)] + + struct Bytes {} + + impl ToString for Bytes { + fn to_string(&self) -> String { + "123".to_string() + } + } + + impl AsRef<[u8]> for Bytes { + fn as_ref(&self) -> &[u8] { + &[1, 2, 3] + } + } + + fn consume>(c: C) { + let _ = c; + } + + pub fn main() { + let b = Bytes {}; + // Should not lint. + consume(b.to_string()); + } +} diff --git a/tests/ui/unused_peekable.rs b/tests/ui/unused_peekable.rs new file mode 100644 index 000000000000..153457e36716 --- /dev/null +++ b/tests/ui/unused_peekable.rs @@ -0,0 +1,144 @@ +#![warn(clippy::unused_peekable)] +#![allow(clippy::no_effect)] + +use std::iter::Empty; +use std::iter::Peekable; + +fn main() { + invalid(); + valid(); +} + +#[allow(clippy::unused_unit)] +fn invalid() { + let peekable = std::iter::empty::().peekable(); + + // Only lint `new_local` + let old_local = std::iter::empty::().peekable(); + let new_local = old_local; + + // Behind mut ref + let mut by_mut_ref_test = std::iter::empty::().peekable(); + let by_mut_ref = &mut by_mut_ref_test; + + // Explicitly returns `Peekable` + fn returns_peekable() -> Peekable> { + std::iter::empty().peekable() + } + + let peekable_from_fn = returns_peekable(); + + // Using a method not exclusive to `Peekable` + let mut peekable_using_iterator_method = std::iter::empty::().peekable(); + peekable_using_iterator_method.next(); + + // Passed by ref to another function + fn takes_ref(_peek: &Peekable>) {} + let passed_along_ref = std::iter::empty::().peekable(); + takes_ref(&passed_along_ref); + + // `by_ref` without `peek` + let mut by_ref_test = std::iter::empty::().peekable(); + let _by_ref = by_ref_test.by_ref(); + + let mut peekable_in_for_loop = std::iter::empty::().peekable(); + for x in peekable_in_for_loop {} +} + +fn valid() { + fn takes_peekable(_peek: Peekable>) {} + + // Passed to another function + let passed_along = std::iter::empty::().peekable(); + takes_peekable(passed_along); + + // Passed to another method + struct PeekableConsumer; + impl PeekableConsumer { + fn consume(&self, _: Peekable>) {} + fn consume_mut_ref(&self, _: &mut Peekable>) {} + } + + let peekable_consumer = PeekableConsumer; + let mut passed_along_to_method = std::iter::empty::().peekable(); + peekable_consumer.consume_mut_ref(&mut passed_along_to_method); + peekable_consumer.consume(passed_along_to_method); + + // `peek` called in another block + let mut peekable_in_block = std::iter::empty::().peekable(); + { + peekable_in_block.peek(); + } + + // Check the other `Peekable` methods :) + { + let mut peekable_with_peek_mut = std::iter::empty::().peekable(); + peekable_with_peek_mut.peek_mut(); + + let mut peekable_with_next_if = std::iter::empty::().peekable(); + peekable_with_next_if.next_if(|_| true); + + let mut peekable_with_next_if_eq = std::iter::empty::().peekable(); + peekable_with_next_if_eq.next_if_eq(&3); + } + + let mut peekable_in_closure = std::iter::empty::().peekable(); + let call_peek = |p: &mut Peekable>| { + p.peek(); + }; + call_peek(&mut peekable_in_closure); + + // From a macro + macro_rules! make_me_a_peekable_please { + () => { + std::iter::empty::().peekable() + }; + } + + let _unsuspecting_macro_user = make_me_a_peekable_please!(); + + // Generic Iterator returned + fn return_an_iter() -> impl Iterator { + std::iter::empty::().peekable() + } + + let _unsuspecting_user = return_an_iter(); + + // Call `peek` in a macro + macro_rules! peek_iter { + ($iter:ident) => { + $iter.peek(); + }; + } + + let mut peek_in_macro = std::iter::empty::().peekable(); + peek_iter!(peek_in_macro); + + // Behind mut ref + let mut by_mut_ref_test = std::iter::empty::().peekable(); + let by_mut_ref = &mut by_mut_ref_test; + by_mut_ref.peek(); + + // Behind ref + let mut by_ref_test = std::iter::empty::().peekable(); + let by_ref = &by_ref_test; + by_ref_test.peek(); + + // In struct + struct PeekableWrapper { + f: Peekable>, + } + + let struct_test = std::iter::empty::().peekable(); + PeekableWrapper { f: struct_test }; + + // `by_ref` before `peek` + let mut by_ref_test = std::iter::empty::().peekable(); + let peeked_val = by_ref_test.by_ref().peek(); + + // `peek` called in another block as the last expression + let mut peekable_last_expr = std::iter::empty::().peekable(); + { + peekable_last_expr.peek(); + } +} diff --git a/tests/ui/unused_peekable.stderr b/tests/ui/unused_peekable.stderr new file mode 100644 index 000000000000..d557f54179db --- /dev/null +++ b/tests/ui/unused_peekable.stderr @@ -0,0 +1,67 @@ +error: `peek` never called on `Peekable` iterator + --> $DIR/unused_peekable.rs:14:9 + | +LL | let peekable = std::iter::empty::().peekable(); + | ^^^^^^^^ + | + = note: `-D clippy::unused-peekable` implied by `-D warnings` + = help: consider removing the call to `peekable` + +error: `peek` never called on `Peekable` iterator + --> $DIR/unused_peekable.rs:18:9 + | +LL | let new_local = old_local; + | ^^^^^^^^^ + | + = help: consider removing the call to `peekable` + +error: `peek` never called on `Peekable` iterator + --> $DIR/unused_peekable.rs:22:9 + | +LL | let by_mut_ref = &mut by_mut_ref_test; + | ^^^^^^^^^^ + | + = help: consider removing the call to `peekable` + +error: `peek` never called on `Peekable` iterator + --> $DIR/unused_peekable.rs:29:9 + | +LL | let peekable_from_fn = returns_peekable(); + | ^^^^^^^^^^^^^^^^ + | + = help: consider removing the call to `peekable` + +error: `peek` never called on `Peekable` iterator + --> $DIR/unused_peekable.rs:32:13 + | +LL | let mut peekable_using_iterator_method = std::iter::empty::().peekable(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider removing the call to `peekable` + +error: `peek` never called on `Peekable` iterator + --> $DIR/unused_peekable.rs:37:9 + | +LL | let passed_along_ref = std::iter::empty::().peekable(); + | ^^^^^^^^^^^^^^^^ + | + = help: consider removing the call to `peekable` + +error: `peek` never called on `Peekable` iterator + --> $DIR/unused_peekable.rs:42:9 + | +LL | let _by_ref = by_ref_test.by_ref(); + | ^^^^^^^ + | + = help: consider removing the call to `peekable` + +error: `peek` never called on `Peekable` iterator + --> $DIR/unused_peekable.rs:44:13 + | +LL | let mut peekable_in_for_loop = std::iter::empty::().peekable(); + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: consider removing the call to `peekable` + +error: aborting due to 8 previous errors + diff --git a/tests/ui/unwrap.rs b/tests/ui/unwrap.rs index a4a3cd1d3797..d9fd402e7cfb 100644 --- a/tests/ui/unwrap.rs +++ b/tests/ui/unwrap.rs @@ -6,8 +6,9 @@ fn unwrap_option() { } fn unwrap_result() { - let res: Result = Ok(0); + let res: Result = Ok(0); let _ = res.unwrap(); + let _ = res.unwrap_err(); } fn main() { diff --git a/tests/ui/unwrap.stderr b/tests/ui/unwrap.stderr index 4f0858005f6e..78422757819d 100644 --- a/tests/ui/unwrap.stderr +++ b/tests/ui/unwrap.stderr @@ -15,5 +15,13 @@ LL | let _ = res.unwrap(); | = help: if you don't want to handle the `Err` case gracefully, consider using `expect()` to provide a better panic message -error: aborting due to 2 previous errors +error: used `unwrap_err()` on `a Result` value + --> $DIR/unwrap.rs:11:13 + | +LL | let _ = res.unwrap_err(); + | ^^^^^^^^^^^^^^^^ + | + = help: if you don't want to handle the `Ok` case gracefully, consider using `expect_err()` to provide a better panic message + +error: aborting due to 3 previous errors diff --git a/tests/ui/unwrap_expect_used.rs b/tests/ui/unwrap_expect_used.rs index 0d4a0504a6e0..9f27fef82494 100644 --- a/tests/ui/unwrap_expect_used.rs +++ b/tests/ui/unwrap_expect_used.rs @@ -1,10 +1,35 @@ #![warn(clippy::unwrap_used, clippy::expect_used)] +trait OptionExt { + type Item; + + fn unwrap_err(self) -> Self::Item; + + fn expect_err(self, msg: &str) -> Self::Item; +} + +impl OptionExt for Option { + type Item = T; + fn unwrap_err(self) -> T { + panic!(); + } + + fn expect_err(self, msg: &str) -> T { + panic!(); + } +} + fn main() { Some(3).unwrap(); Some(3).expect("Hello world!"); + // Don't trigger on unwrap_err on an option + Some(3).unwrap_err(); + Some(3).expect_err("Hellow none!"); + let a: Result = Ok(3); a.unwrap(); a.expect("Hello world!"); + a.unwrap_err(); + a.expect_err("Hello error!"); } diff --git a/tests/ui/unwrap_expect_used.stderr b/tests/ui/unwrap_expect_used.stderr index f54bfd617c4e..1a19459b2c17 100644 --- a/tests/ui/unwrap_expect_used.stderr +++ b/tests/ui/unwrap_expect_used.stderr @@ -1,5 +1,5 @@ error: used `unwrap()` on `an Option` value - --> $DIR/unwrap_expect_used.rs:4:5 + --> $DIR/unwrap_expect_used.rs:23:5 | LL | Some(3).unwrap(); | ^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | Some(3).unwrap(); = help: if this value is `None`, it will panic error: used `expect()` on `an Option` value - --> $DIR/unwrap_expect_used.rs:5:5 + --> $DIR/unwrap_expect_used.rs:24:5 | LL | Some(3).expect("Hello world!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | Some(3).expect("Hello world!"); = help: if this value is `None`, it will panic error: used `unwrap()` on `a Result` value - --> $DIR/unwrap_expect_used.rs:8:5 + --> $DIR/unwrap_expect_used.rs:31:5 | LL | a.unwrap(); | ^^^^^^^^^^ @@ -25,12 +25,28 @@ LL | a.unwrap(); = help: if this value is an `Err`, it will panic error: used `expect()` on `a Result` value - --> $DIR/unwrap_expect_used.rs:9:5 + --> $DIR/unwrap_expect_used.rs:32:5 | LL | a.expect("Hello world!"); | ^^^^^^^^^^^^^^^^^^^^^^^^ | = help: if this value is an `Err`, it will panic -error: aborting due to 4 previous errors +error: used `unwrap_err()` on `a Result` value + --> $DIR/unwrap_expect_used.rs:33:5 + | +LL | a.unwrap_err(); + | ^^^^^^^^^^^^^^ + | + = help: if this value is an `Ok`, it will panic + +error: used `expect_err()` on `a Result` value + --> $DIR/unwrap_expect_used.rs:34:5 + | +LL | a.expect_err("Hello error!"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: if this value is an `Ok`, it will panic + +error: aborting due to 6 previous errors diff --git a/tests/ui/useless_conversion_try.rs b/tests/ui/useless_conversion_try.rs index 39f54c27bee1..4acf5b5fa2d1 100644 --- a/tests/ui/useless_conversion_try.rs +++ b/tests/ui/useless_conversion_try.rs @@ -29,10 +29,10 @@ fn main() { let _ = String::try_from("foo".to_string()).unwrap(); let _ = String::try_from(format!("A: {:04}", 123)).unwrap(); let _: String = format!("Hello {}", "world").try_into().unwrap(); - let _: String = "".to_owned().try_into().unwrap(); + let _: String = String::new().try_into().unwrap(); let _: String = match String::from("_").try_into() { Ok(a) => a, - Err(_) => "".into(), + Err(_) => String::new(), }; // FIXME this is a false negative #[allow(clippy::cmp_owned)] diff --git a/tests/ui/useless_conversion_try.stderr b/tests/ui/useless_conversion_try.stderr index b691c13f7dbb..12e74d614717 100644 --- a/tests/ui/useless_conversion_try.stderr +++ b/tests/ui/useless_conversion_try.stderr @@ -62,7 +62,7 @@ LL | let _: String = format!("Hello {}", "world").try_into().unwrap(); error: useless conversion to the same type: `std::string::String` --> $DIR/useless_conversion_try.rs:32:21 | -LL | let _: String = "".to_owned().try_into().unwrap(); +LL | let _: String = String::new().try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider removing `.try_into()` diff --git a/tests/ui/vec_resize_to_zero.rs b/tests/ui/vec_resize_to_zero.rs index 7ed27439ec6e..a8307e741cf1 100644 --- a/tests/ui/vec_resize_to_zero.rs +++ b/tests/ui/vec_resize_to_zero.rs @@ -1,15 +1,19 @@ #![warn(clippy::vec_resize_to_zero)] fn main() { + let mut v = vec![1, 2, 3, 4, 5]; + // applicable here - vec![1, 2, 3, 4, 5].resize(0, 5); + v.resize(0, 5); // not applicable - vec![1, 2, 3, 4, 5].resize(2, 5); + v.resize(2, 5); + + let mut v = vec!["foo", "bar", "baz"]; // applicable here, but only implemented for integer literals for now - vec!["foo", "bar", "baz"].resize(0, "bar"); + v.resize(0, "bar"); // not applicable - vec!["foo", "bar", "baz"].resize(2, "bar") + v.resize(2, "bar") } diff --git a/tests/ui/vec_resize_to_zero.stderr b/tests/ui/vec_resize_to_zero.stderr index feb846298c65..7428cf62d6c4 100644 --- a/tests/ui/vec_resize_to_zero.stderr +++ b/tests/ui/vec_resize_to_zero.stderr @@ -1,10 +1,10 @@ error: emptying a vector with `resize` - --> $DIR/vec_resize_to_zero.rs:5:5 + --> $DIR/vec_resize_to_zero.rs:7:5 | -LL | vec![1, 2, 3, 4, 5].resize(0, 5); - | ^^^^^^^^^^^^^^^^^^^^------------ - | | - | help: ...or you can empty the vector with: `clear()` +LL | v.resize(0, 5); + | ^^------------ + | | + | help: ...or you can empty the vector with: `clear()` | = note: `-D clippy::vec-resize-to-zero` implied by `-D warnings` = help: the arguments may be inverted... diff --git a/tests/ui/verbose_file_reads.rs b/tests/ui/verbose_file_reads.rs index e0065e05ade6..df267e9872a0 100644 --- a/tests/ui/verbose_file_reads.rs +++ b/tests/ui/verbose_file_reads.rs @@ -18,7 +18,7 @@ fn main() -> std::io::Result<()> { s.read_to_end(); s.read_to_string(); // Should catch this - let mut f = File::open(&path)?; + let mut f = File::open(path)?; let mut buffer = Vec::new(); f.read_to_end(&mut buffer)?; // ...and this diff --git a/tests/workspace.rs b/tests/workspace.rs index e13efb3e0164..95325e060378 100644 --- a/tests/workspace.rs +++ b/tests/workspace.rs @@ -20,8 +20,8 @@ fn test_no_deps_ignores_path_deps_in_workspaces() { .current_dir(&cwd) .env("CARGO_TARGET_DIR", &target_dir) .arg("clean") - .args(&["-p", "subcrate"]) - .args(&["-p", "path_dep"]) + .args(["-p", "subcrate"]) + .args(["-p", "path_dep"]) .output() .unwrap(); @@ -32,11 +32,11 @@ fn test_no_deps_ignores_path_deps_in_workspaces() { .env("CARGO_INCREMENTAL", "0") .env("CARGO_TARGET_DIR", &target_dir) .arg("clippy") - .args(&["-p", "subcrate"]) + .args(["-p", "subcrate"]) .arg("--no-deps") .arg("--") .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir - .args(&["--cfg", r#"feature="primary_package_test""#]) + .args(["--cfg", r#"feature="primary_package_test""#]) .output() .unwrap(); println!("status: {}", output.status); @@ -52,10 +52,10 @@ fn test_no_deps_ignores_path_deps_in_workspaces() { .env("CARGO_INCREMENTAL", "0") .env("CARGO_TARGET_DIR", &target_dir) .arg("clippy") - .args(&["-p", "subcrate"]) + .args(["-p", "subcrate"]) .arg("--") .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir - .args(&["--cfg", r#"feature="primary_package_test""#]) + .args(["--cfg", r#"feature="primary_package_test""#]) .output() .unwrap(); println!("status: {}", output.status); @@ -79,7 +79,7 @@ fn test_no_deps_ignores_path_deps_in_workspaces() { .env("CARGO_INCREMENTAL", "0") .env("CARGO_TARGET_DIR", &target_dir) .arg("clippy") - .args(&["-p", "subcrate"]) + .args(["-p", "subcrate"]) .arg("--") .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir .output() From cacc7bf5f0cc4b18f81809b2d61862f0224259d4 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Wed, 31 Aug 2022 22:27:37 +0900 Subject: [PATCH 3989/5092] Fix a typo on `wasm64-unknown-unknown` doc --- src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md b/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md index 021b904debd8..6932e6a5764b 100644 --- a/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md +++ b/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md @@ -30,7 +30,7 @@ is 8-bytes large as well as pointers. The tradeoff, though, is that the maximum memory size is now the full 64-bit address space instead of the 4GB as limited by the 32-bit address space for `wasm32-unknown-unknown`. -This target is not a stable target. The [memory64] WebAssembly proposal is stil +This target is not a stable target. The [memory64] WebAssembly proposal is still in-progress and not standardized. This means that there are not many engines which implement the `memory64` feature and if they do they're likely behind a flag, for example: From 7ed133324ad029ca5a0ecdb636f63fdf315c4381 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 31 Aug 2022 09:33:32 -0400 Subject: [PATCH 3990/5092] Use `CountIsStart` in clippy --- src/tools/clippy/clippy_lints/src/write.rs | 4 ++-- src/tools/clippy/clippy_utils/src/macros.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs index 5533840b166f..347165d9704a 100644 --- a/src/tools/clippy/clippy_lints/src/write.rs +++ b/src/tools/clippy/clippy_lints/src/write.rs @@ -526,7 +526,7 @@ impl SimpleFormatArgs { str_lit_span: Span, fmt_span: Span, ) { - use rustc_parse_format::{ArgumentImplicitlyIs, ArgumentIs, CountIsParam}; + use rustc_parse_format::{ArgumentImplicitlyIs, ArgumentIs, CountIsParam, CountIsStar}; let snippet = snippet_opt(cx, fmt_span); @@ -540,7 +540,7 @@ impl SimpleFormatArgs { self.push_to_complex(span, n); }; - if let (CountIsParam(n), Some(span)) = (arg.format.precision, arg.format.precision_span) { + if let (CountIsParam(n) | CountIsStar(n), Some(span)) = (arg.format.precision, arg.format.precision_span) { // We need to do this hack as precision spans should be converted from .* to .foo$ let hack = if snippet.as_ref().and_then(|s| s.find('*')).is_some() { 0 diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs index e5ca35455404..43e53f3feebd 100644 --- a/src/tools/clippy/clippy_utils/src/macros.rs +++ b/src/tools/clippy/clippy_utils/src/macros.rs @@ -644,7 +644,7 @@ impl<'tcx> Count<'tcx> { span, values, )?), - rpf::Count::CountIsParam(_) => { + rpf::Count::CountIsParam(_) | rpf::Count::CountIsStar(_) => { Self::Param(FormatParam::new(FormatParamKind::Numbered, position?, inner?, values)?) }, rpf::Count::CountImplied => Self::Implied, From 7bd5b012c701da221b308a147a6547854f680f1a Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 31 Aug 2022 09:33:32 -0400 Subject: [PATCH 3991/5092] Use `CountIsStart` in clippy --- clippy_lints/src/write.rs | 4 ++-- clippy_utils/src/macros.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 5533840b166f..347165d9704a 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -526,7 +526,7 @@ impl SimpleFormatArgs { str_lit_span: Span, fmt_span: Span, ) { - use rustc_parse_format::{ArgumentImplicitlyIs, ArgumentIs, CountIsParam}; + use rustc_parse_format::{ArgumentImplicitlyIs, ArgumentIs, CountIsParam, CountIsStar}; let snippet = snippet_opt(cx, fmt_span); @@ -540,7 +540,7 @@ impl SimpleFormatArgs { self.push_to_complex(span, n); }; - if let (CountIsParam(n), Some(span)) = (arg.format.precision, arg.format.precision_span) { + if let (CountIsParam(n) | CountIsStar(n), Some(span)) = (arg.format.precision, arg.format.precision_span) { // We need to do this hack as precision spans should be converted from .* to .foo$ let hack = if snippet.as_ref().and_then(|s| s.find('*')).is_some() { 0 diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index e5ca35455404..43e53f3feebd 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -644,7 +644,7 @@ impl<'tcx> Count<'tcx> { span, values, )?), - rpf::Count::CountIsParam(_) => { + rpf::Count::CountIsParam(_) | rpf::Count::CountIsStar(_) => { Self::Param(FormatParam::new(FormatParamKind::Numbered, position?, inner?, values)?) }, rpf::Count::CountImplied => Self::Implied, From 4cb26afc0c25f77d52b6f2c83eba89466d85b214 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Aug 2022 14:44:36 +0200 Subject: [PATCH 3992/5092] fix progress report being deduplicated --- src/diagnostics.rs | 70 +++++++++++++++++++++++++++++++--------------- src/machine.rs | 16 +++++------ 2 files changed, 55 insertions(+), 31 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 26442da6d655..3a0d17b22a76 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -70,7 +70,9 @@ pub enum NonHaltingDiagnostic { CreatedAlloc(AllocId, Size, Align, MemoryKind), FreedAlloc(AllocId), RejectedIsolatedOp(String), - ProgressReport, + ProgressReport { + block_count: u64, // how many basic blocks have been run so far + }, Int2Ptr { details: bool, }, @@ -261,6 +263,7 @@ pub fn report_error<'tcx, 'mir>( DiagLevel::Error, &if let Some(title) = title { format!("{}: {}", title, msg[0]) } else { msg[0].clone() }, msg, + vec![], helps, &stacktrace, ); @@ -307,6 +310,7 @@ fn report_msg<'mir, 'tcx>( diag_level: DiagLevel, title: &str, span_msg: Vec, + notes: Vec<(Option, String)>, helps: Vec<(Option, String)>, stacktrace: &[FrameInfo<'tcx>], ) { @@ -331,15 +335,22 @@ fn report_msg<'mir, 'tcx>( err.note("(no span available)"); } - // Show help messages. - if !helps.is_empty() { - for (span_data, help) in helps { - if let Some(span_data) = span_data { - err.span_help(span_data.span(), &help); - } else { - err.help(&help); - } + // Show note and help messages. + for (span_data, note) in ¬es { + if let Some(span_data) = span_data { + err.span_note(span_data.span(), note); + } else { + err.note(note); } + } + for (span_data, help) in &helps { + if let Some(span_data) = span_data { + err.span_help(span_data.span(), help); + } else { + err.help(help); + } + } + if notes.len() + helps.len() > 0 { // Add visual separator before backtrace. err.note("backtrace:"); } @@ -436,6 +447,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Show diagnostics. for e in diagnostics.drain(..) { use NonHaltingDiagnostic::*; + + let (title, diag_level) = match e { + RejectedIsolatedOp(_) => + ("operation rejected by isolation", DiagLevel::Warning), + Int2Ptr { .. } => ("integer-to-pointer cast", DiagLevel::Warning), + CreatedPointerTag(..) + | PoppedPointerTag(..) + | CreatedCallId(..) + | CreatedAlloc(..) + | FreedAlloc(..) + | ProgressReport { .. } + | WeakMemoryOutdatedLoad => + ("tracking was triggered", DiagLevel::Note), + }; + let msg = match e { CreatedPointerTag(tag, None) => format!("created tag {tag:?}"), @@ -465,7 +491,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx format!("freed allocation with id {id}"), RejectedIsolatedOp(ref op) => format!("{op} was made to return an error due to isolation"), - ProgressReport => + ProgressReport { .. } => format!("progress report: current operation being executed is here"), Int2Ptr { .. } => format!("integer-to-pointer cast"), @@ -473,18 +499,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx format!("weak memory emulation: outdated value returned from load"), }; - let (title, diag_level) = match e { - RejectedIsolatedOp(_) => - ("operation rejected by isolation", DiagLevel::Warning), - Int2Ptr { .. } => ("integer-to-pointer cast", DiagLevel::Warning), - CreatedPointerTag(..) - | PoppedPointerTag(..) - | CreatedCallId(..) - | CreatedAlloc(..) - | FreedAlloc(..) - | ProgressReport - | WeakMemoryOutdatedLoad => - ("tracking was triggered", DiagLevel::Note), + let notes = match e { + ProgressReport { block_count } => { + // It is important that each progress report is slightly different, since + // identical diagnostics are being deduplicated. + vec![ + (None, format!("so far, {block_count} basic blocks have been executed")), + ] + } + _ => vec![], }; let helps = match e { @@ -500,7 +523,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => vec![], }; - report_msg(this, diag_level, title, vec![msg], helps, &stacktrace); + report_msg(this, diag_level, title, vec![msg], notes, helps, &stacktrace); } }); } @@ -519,6 +542,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "the place in the program where the ICE was triggered", vec![], vec![], + vec![], &stacktrace, ); } diff --git a/src/machine.rs b/src/machine.rs index 4f7e3a6a71b1..3be4d1d1b5bc 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -374,8 +374,8 @@ pub struct Evaluator<'mir, 'tcx> { /// If `Some`, we will report the current stack every N basic blocks. pub(crate) report_progress: Option, - /// The number of blocks that passed since the last progress report. - pub(crate) since_progress_report: u32, + // The total number of blocks that have been executed. + pub(crate) basic_block_count: u64, /// Handle of the optional shared object file for external functions. pub external_so_lib: Option<(libloading::Library, std::path::PathBuf)>, @@ -433,7 +433,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { weak_memory: config.weak_memory_emulation, preemption_rate: config.preemption_rate, report_progress: config.report_progress, - since_progress_report: 0, + basic_block_count: 0, external_so_lib: config.external_so_file.as_ref().map(|lib_file_path| { // Check if host target == the session target. if env!("TARGET") != target_triple { @@ -992,14 +992,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { + ecx.machine.basic_block_count += 1u64; // a u64 that is only incremented by 1 will "never" overflow // Possibly report our progress. if let Some(report_progress) = ecx.machine.report_progress { - if ecx.machine.since_progress_report >= report_progress { - register_diagnostic(NonHaltingDiagnostic::ProgressReport); - ecx.machine.since_progress_report = 0; + if ecx.machine.basic_block_count % u64::from(report_progress) == 0 { + register_diagnostic(NonHaltingDiagnostic::ProgressReport { + block_count: ecx.machine.basic_block_count, + }); } - // Cannot overflow, since it is strictly less than `report_progress`. - ecx.machine.since_progress_report += 1; } // These are our preemption points. ecx.maybe_preempt_active_thread(); From 192a79c23551b5e1d3d5ef8115ebec67437daaff Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 31 Aug 2022 16:58:11 +0200 Subject: [PATCH 3993/5092] Remove hir::Expr::MacroStmts This hir expression isn't needed and only existed as it was simpler to deal with at first as it gave us a direct mapping for the ast version of the same construct. This PR removes it, properly handling the statements that are introduced by macro call expressions. --- crates/hir-def/src/body/lower.rs | 126 ++++++++++--------- crates/hir-def/src/body/pretty.rs | 13 -- crates/hir-def/src/body/scope.rs | 3 - crates/hir-def/src/expr.rs | 6 +- crates/hir-expand/src/lib.rs | 2 +- crates/hir-ty/src/infer/expr.rs | 3 - crates/hir-ty/src/tests/macros.rs | 17 +-- crates/hir-ty/src/tests/regression.rs | 3 +- crates/hir/src/source_analyzer.rs | 16 ++- crates/ide-db/src/syntax_helpers/node_ext.rs | 1 - crates/syntax/rust.ungram | 1 - crates/syntax/src/ast/generated/nodes.rs | 7 -- 12 files changed, 88 insertions(+), 110 deletions(-) diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index f6ec8bf7e9e0..cb6fdbfc562e 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -550,20 +550,6 @@ impl ExprCollector<'_> { None => self.alloc_expr(Expr::Missing, syntax_ptr), } } - ast::Expr::MacroStmts(e) => { - let statements: Box<[_]> = - e.statements().filter_map(|s| self.collect_stmt(s)).collect(); - let tail = e.expr().map(|e| self.collect_expr(e)); - - if e.syntax().children().next().is_none() { - // HACK: make sure that macros that expand to nothing aren't treated as a `()` - // expression when used in block tail position. - cov_mark::hit!(empty_macro_in_trailing_position_is_removed); - return None; - } - - self.alloc_expr(Expr::MacroStmts { tail, statements }, syntax_ptr) - } ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr), }) } @@ -640,7 +626,58 @@ impl ExprCollector<'_> { } } - fn collect_stmt(&mut self, s: ast::Stmt) -> Option { + fn collect_macro_as_stmt( + &mut self, + mac: ast::MacroExpr, + ) -> Option<(Vec, Option)> { + let mac_call = mac.macro_call()?; + let syntax_ptr = AstPtr::new(&ast::Expr::from(mac)); + let macro_ptr = AstPtr::new(&mac_call); + let expansion = self.collect_macro_call( + mac_call, + macro_ptr, + false, + |this, expansion: Option| match expansion { + Some(expansion) => { + let mut statements: Vec<_> = expansion + .statements() + .filter_map(|stmt| this.collect_stmt(stmt)) + .flatten() + .collect(); + let tail = expansion.expr().and_then(|expr| match expr { + ast::Expr::MacroExpr(mac) => { + let (stmts, tail) = this.collect_macro_as_stmt(mac)?; + statements.extend(stmts); + tail + } + expr => Some(this.collect_expr(expr)), + }); + Some((statements, tail)) + } + None => None, + }, + ); + let mut stmts = Vec::new(); + let expr = match expansion { + Some((statements, tail)) => { + stmts.extend(statements); + // Make the macro-call point to its expanded expression so we can query + // semantics on syntax pointers to the macro + let src = self.expander.to_source(syntax_ptr); + match tail { + Some(tail) => { + self.source_map.expr_map.insert(src, tail); + tail + } + None => self.make_expr(Expr::Missing, Ok(src.clone())), + } + } + None => self.alloc_expr(Expr::Missing, syntax_ptr), + }; + Some((stmts, Some(expr))) + } + + fn collect_stmt(&mut self, s: ast::Stmt) -> Option> { match s { ast::Stmt::LetStmt(stmt) => { if self.check_cfg(&stmt).is_none() { @@ -654,7 +691,7 @@ impl ExprCollector<'_> { .let_else() .and_then(|let_else| let_else.block_expr()) .map(|block| self.collect_block(block)); - Some(Statement::Let { pat, type_ref, initializer, else_branch }) + Some(vec![Statement::Let { pat, type_ref, initializer, else_branch }]) } ast::Stmt::ExprStmt(stmt) => { let expr = stmt.expr(); @@ -665,47 +702,15 @@ impl ExprCollector<'_> { } let has_semi = stmt.semicolon_token().is_some(); // Note that macro could be expanded to multiple statements - if let Some(expr @ ast::Expr::MacroExpr(mac)) = &expr { - let mac_call = mac.macro_call()?; - let syntax_ptr = AstPtr::new(expr); - let macro_ptr = AstPtr::new(&mac_call); - let stmt = self.collect_macro_call( - mac_call, - macro_ptr, - false, - |this, expansion: Option| match expansion { - Some(expansion) => { - let statements = expansion - .statements() - .filter_map(|stmt| this.collect_stmt(stmt)) - .collect(); - let tail = expansion.expr().map(|expr| this.collect_expr(expr)); - - let mac_stmts = this.alloc_expr( - Expr::MacroStmts { tail, statements }, - AstPtr::new(&ast::Expr::MacroStmts(expansion)), - ); - - Some(mac_stmts) - } - None => None, - }, - ); - - let expr = match stmt { - Some(expr) => { - // Make the macro-call point to its expanded expression so we can query - // semantics on syntax pointers to the macro - let src = self.expander.to_source(syntax_ptr); - self.source_map.expr_map.insert(src, expr); - expr - } - None => self.alloc_expr(Expr::Missing, syntax_ptr), - }; - Some(Statement::Expr { expr, has_semi }) + if let Some(ast::Expr::MacroExpr(mac)) = expr { + let (mut statements, tail) = self.collect_macro_as_stmt(mac)?; + if let Some(expr) = tail { + statements.push(Statement::Expr { expr, has_semi }); + } + Some(statements) } else { let expr = self.collect_expr_opt(expr); - Some(Statement::Expr { expr, has_semi }) + Some(vec![Statement::Expr { expr, has_semi }]) } } ast::Stmt::Item(_item) => None, @@ -730,8 +735,15 @@ impl ExprCollector<'_> { let prev_local_module = mem::replace(&mut self.expander.module, module); let mut statements: Vec<_> = - block.statements().filter_map(|s| self.collect_stmt(s)).collect(); - let tail = block.tail_expr().and_then(|e| self.maybe_collect_expr(e)); + block.statements().filter_map(|s| self.collect_stmt(s)).flatten().collect(); + let tail = block.tail_expr().and_then(|e| match e { + ast::Expr::MacroExpr(mac) => { + let (stmts, tail) = self.collect_macro_as_stmt(mac)?; + statements.extend(stmts); + tail + } + expr => self.maybe_collect_expr(expr), + }); let tail = tail.or_else(|| { let stmt = statements.pop()?; if let Statement::Expr { expr, has_semi: false } = stmt { diff --git a/crates/hir-def/src/body/pretty.rs b/crates/hir-def/src/body/pretty.rs index ddd476efe5c4..f2fed954444e 100644 --- a/crates/hir-def/src/body/pretty.rs +++ b/crates/hir-def/src/body/pretty.rs @@ -422,19 +422,6 @@ impl<'a> Printer<'a> { } w!(self, "}}"); } - Expr::MacroStmts { statements, tail } => { - w!(self, "{{ // macro statements"); - self.indented(|p| { - for stmt in statements.iter() { - p.print_stmt(stmt); - } - if let Some(tail) = tail { - p.print_expr(*tail); - } - }); - self.newline(); - w!(self, "}}"); - } } } diff --git a/crates/hir-def/src/body/scope.rs b/crates/hir-def/src/body/scope.rs index f4c390dce26e..9b28e38029e0 100644 --- a/crates/hir-def/src/body/scope.rs +++ b/crates/hir-def/src/body/scope.rs @@ -176,9 +176,6 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope scopes.set_scope(expr, *scope); match &body[expr] { - Expr::MacroStmts { statements, tail } => { - compute_block_scopes(statements, *tail, body, scopes, scope); - } Expr::Block { statements, tail, id, label } => { let mut scope = scopes.new_block_scope(*scope, *id, make_label(label)); // Overwrite the old scope for the block expr, so that every block scope can be found diff --git a/crates/hir-def/src/expr.rs b/crates/hir-def/src/expr.rs index 4381b43c258b..419d3feec3b6 100644 --- a/crates/hir-def/src/expr.rs +++ b/crates/hir-def/src/expr.rs @@ -206,10 +206,6 @@ pub enum Expr { Unsafe { body: ExprId, }, - MacroStmts { - statements: Box<[Statement]>, - tail: Option, - }, Array(Array), Literal(Literal), Underscore, @@ -263,7 +259,7 @@ impl Expr { Expr::Let { expr, .. } => { f(*expr); } - Expr::MacroStmts { tail, statements } | Expr::Block { statements, tail, .. } => { + Expr::Block { statements, tail, .. } => { for stmt in statements.iter() { match stmt { Statement::Let { initializer, .. } => { diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs index d753d88470c4..fc128102f225 100644 --- a/crates/hir-expand/src/lib.rs +++ b/crates/hir-expand/src/lib.rs @@ -969,7 +969,7 @@ impl ExpandTo { if parent.kind() == MACRO_EXPR && parent .parent() - .map_or(true, |p| matches!(p.kind(), EXPR_STMT | STMT_LIST | MACRO_STMTS)) + .map_or(false, |p| matches!(p.kind(), EXPR_STMT | STMT_LIST | MACRO_STMTS)) { return ExpandTo::Statements; } diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index 2a13106390d9..a42a00ea598e 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -794,9 +794,6 @@ impl<'a> InferenceContext<'a> { None => self.table.new_float_var(), }, }, - Expr::MacroStmts { tail, statements } => { - self.infer_block(tgt_expr, statements, *tail, expected) - } Expr::Underscore => { // Underscore expressions may only appear in assignee expressions, // which are handled by `infer_assignee_expr()`, so any underscore diff --git a/crates/hir-ty/src/tests/macros.rs b/crates/hir-ty/src/tests/macros.rs index a1ab6060e790..a1a2fdd1fb28 100644 --- a/crates/hir-ty/src/tests/macros.rs +++ b/crates/hir-ty/src/tests/macros.rs @@ -193,8 +193,6 @@ fn expr_macro_def_expanded_in_various_places() { !0..6 '1isize': isize !0..6 '1isize': isize !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize 39..442 '{ ...!(); }': () 73..94 'spam!(...am!())': {unknown} 100..119 'for _ ...!() {}': () @@ -276,8 +274,6 @@ fn expr_macro_rules_expanded_in_various_places() { !0..6 '1isize': isize !0..6 '1isize': isize !0..6 '1isize': isize - !0..6 '1isize': isize - !0..6 '1isize': isize 53..456 '{ ...!(); }': () 87..108 'spam!(...am!())': {unknown} 114..133 'for _ ...!() {}': () @@ -312,16 +308,16 @@ fn expr_macro_expanded_in_stmts() { } "#, expect![[r#" - !0..8 'leta=();': () !3..4 'a': () !5..7 '()': () 57..84 '{ ...); } }': () + 63..82 'id! { ... (); }': () "#]], ); } #[test] -fn recurisve_macro_expanded_in_stmts() { +fn recursive_macro_expanded_in_stmts() { check_infer( r#" macro_rules! ng { @@ -340,11 +336,7 @@ fn recurisve_macro_expanded_in_stmts() { } "#, expect![[r#" - !0..7 'leta=3;': () - !0..13 'ng!{[leta=3]}': () - !0..13 'ng!{[leta=]3}': () - !0..13 'ng!{[leta]=3}': () - !0..13 'ng!{[let]a=3}': () + !0..13 'ng!{[leta=3]}': {unknown} !3..4 'a': i32 !5..6 '3': i32 196..237 '{ ...= a; }': () @@ -369,8 +361,7 @@ fn recursive_inner_item_macro_rules() { "#, expect![[r#" !0..1 '1': i32 - !0..7 'mac!($)': () - !0..26 'macro_...>{1};}': () + !0..7 'mac!($)': {unknown} 107..143 '{ ...!(); }': () 129..130 'a': i32 "#]], diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs index c7895db1afbf..cc49c3d45fcd 100644 --- a/crates/hir-ty/src/tests/regression.rs +++ b/crates/hir-ty/src/tests/regression.rs @@ -573,12 +573,12 @@ fn issue_6811() { } "#, expect![[r#" - !0..16 'let_a=...t_b=1;': () !3..5 '_a': i32 !6..7 '1': i32 !11..13 '_b': i32 !14..15 '1': i32 103..131 '{ ...!(); }': () + 109..128 'profil...ion!()': {unknown} "#]], ); } @@ -1679,7 +1679,6 @@ fn main() { #[test] fn trailing_empty_macro() { - cov_mark::check!(empty_macro_in_trailing_position_is_removed); check_no_mismatches( r#" macro_rules! m2 { diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index bd35af06e23e..342912b678a1 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -140,11 +140,19 @@ impl SourceAnalyzer { ) -> Option> { let macro_file = self.body_source_map()?.node_macro_file(expr.as_ref())?; let expanded = db.parse_or_expand(macro_file)?; - - let res = match ast::MacroCall::cast(expanded.clone()) { - Some(call) => self.expand_expr(db, InFile::new(macro_file, call))?, - _ => InFile::new(macro_file, ast::Expr::cast(expanded)?), + let res = if let Some(stmts) = ast::MacroStmts::cast(expanded.clone()) { + match stmts.expr()? { + ast::Expr::MacroExpr(mac) => { + self.expand_expr(db, InFile::new(macro_file, mac.macro_call()?))? + } + expr => InFile::new(macro_file, expr), + } + } else if let Some(call) = ast::MacroCall::cast(expanded.clone()) { + self.expand_expr(db, InFile::new(macro_file, call))? + } else { + InFile::new(macro_file, ast::Expr::cast(expanded)?) }; + Some(res) } diff --git a/crates/ide-db/src/syntax_helpers/node_ext.rs b/crates/ide-db/src/syntax_helpers/node_ext.rs index 84bde4d44dbb..b890e2b58df8 100644 --- a/crates/ide-db/src/syntax_helpers/node_ext.rs +++ b/crates/ide-db/src/syntax_helpers/node_ext.rs @@ -315,7 +315,6 @@ pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) { | ast::Expr::IndexExpr(_) | ast::Expr::Literal(_) | ast::Expr::MacroExpr(_) - | ast::Expr::MacroStmts(_) | ast::Expr::MethodCallExpr(_) | ast::Expr::ParenExpr(_) | ast::Expr::PathExpr(_) diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram index 62aa47839942..894795435451 100644 --- a/crates/syntax/rust.ungram +++ b/crates/syntax/rust.ungram @@ -343,7 +343,6 @@ Expr = | Literal | LoopExpr | MacroExpr -| MacroStmts | MatchExpr | MethodCallExpr | ParenExpr diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index 8c4825ad69eb..449402e5f5b3 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs @@ -1526,7 +1526,6 @@ pub enum Expr { Literal(Literal), LoopExpr(LoopExpr), MacroExpr(MacroExpr), - MacroStmts(MacroStmts), MatchExpr(MatchExpr), MethodCallExpr(MethodCallExpr), ParenExpr(ParenExpr), @@ -3342,9 +3341,6 @@ impl From for Expr { impl From for Expr { fn from(node: MacroExpr) -> Expr { Expr::MacroExpr(node) } } -impl From for Expr { - fn from(node: MacroStmts) -> Expr { Expr::MacroStmts(node) } -} impl From for Expr { fn from(node: MatchExpr) -> Expr { Expr::MatchExpr(node) } } @@ -3411,7 +3407,6 @@ impl AstNode for Expr { | LITERAL | LOOP_EXPR | MACRO_EXPR - | MACRO_STMTS | MATCH_EXPR | METHOD_CALL_EXPR | PAREN_EXPR @@ -3448,7 +3443,6 @@ impl AstNode for Expr { LITERAL => Expr::Literal(Literal { syntax }), LOOP_EXPR => Expr::LoopExpr(LoopExpr { syntax }), MACRO_EXPR => Expr::MacroExpr(MacroExpr { syntax }), - MACRO_STMTS => Expr::MacroStmts(MacroStmts { syntax }), MATCH_EXPR => Expr::MatchExpr(MatchExpr { syntax }), METHOD_CALL_EXPR => Expr::MethodCallExpr(MethodCallExpr { syntax }), PAREN_EXPR => Expr::ParenExpr(ParenExpr { syntax }), @@ -3487,7 +3481,6 @@ impl AstNode for Expr { Expr::Literal(it) => &it.syntax, Expr::LoopExpr(it) => &it.syntax, Expr::MacroExpr(it) => &it.syntax, - Expr::MacroStmts(it) => &it.syntax, Expr::MatchExpr(it) => &it.syntax, Expr::MethodCallExpr(it) => &it.syntax, Expr::ParenExpr(it) => &it.syntax, From 1a580a3396ea11c3cf186af8ec5c563d906b7127 Mon Sep 17 00:00:00 2001 From: iDawer Date: Wed, 31 Aug 2022 20:17:54 +0500 Subject: [PATCH 3994/5092] Implement unstable RFC 1872 `exhaustive_patterns` --- crates/hir-ty/src/diagnostics/expr.rs | 7 +- .../match_check/deconstruct_pat.rs | 16 +- .../src/diagnostics/match_check/usefulness.rs | 41 +++- crates/hir-ty/src/inhabitedness.rs | 176 ++++++++++++++++++ crates/hir-ty/src/lib.rs | 1 + .../src/handlers/missing_match_arms.rs | 44 +++++ 6 files changed, 265 insertions(+), 20 deletions(-) create mode 100644 crates/hir-ty/src/inhabitedness.rs diff --git a/crates/hir-ty/src/diagnostics/expr.rs b/crates/hir-ty/src/diagnostics/expr.rs index 642e03edd230..c8df4c796efc 100644 --- a/crates/hir-ty/src/diagnostics/expr.rs +++ b/crates/hir-ty/src/diagnostics/expr.rs @@ -159,12 +159,7 @@ impl ExprValidator { } let pattern_arena = Arena::new(); - let cx = MatchCheckCtx { - module: self.owner.module(db.upcast()), - body: self.owner, - db, - pattern_arena: &pattern_arena, - }; + let cx = MatchCheckCtx::new(self.owner.module(db.upcast()), self.owner, db, &pattern_arena); let mut m_arms = Vec::with_capacity(arms.len()); let mut has_lowering_errors = false; diff --git a/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs b/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs index bbbe539c13fb..47d60fc41e70 100644 --- a/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs +++ b/crates/hir-ty/src/diagnostics/match_check/deconstruct_pat.rs @@ -52,7 +52,10 @@ use hir_def::{EnumVariantId, HasModule, LocalFieldId, VariantId}; use smallvec::{smallvec, SmallVec}; use stdx::never; -use crate::{infer::normalize, AdtId, Interner, Scalar, Ty, TyExt, TyKind}; +use crate::{ + infer::normalize, inhabitedness::is_enum_variant_uninhabited_from, AdtId, Interner, Scalar, Ty, + TyExt, TyKind, +}; use super::{ is_box, @@ -557,8 +560,8 @@ impl SplitWildcard { TyKind::Scalar(Scalar::Bool) => smallvec![make_range(0, 1, Scalar::Bool)], // TyKind::Array(..) if ... => unhandled(), TyKind::Array(..) | TyKind::Slice(..) => unhandled(), - &TyKind::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), ..) => { - let enum_data = cx.db.enum_data(enum_id); + TyKind::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), subst) => { + let enum_data = cx.db.enum_data(*enum_id); // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an // additional "unknown" constructor. @@ -591,14 +594,15 @@ impl SplitWildcard { let mut ctors: SmallVec<[_; 1]> = enum_data .variants .iter() - .filter(|&(_, _v)| { + .map(|(local_id, _)| EnumVariantId { parent: *enum_id, local_id }) + .filter(|&variant| { // If `exhaustive_patterns` is enabled, we exclude variants known to be // uninhabited. let is_uninhabited = is_exhaustive_pat_feature - && unimplemented!("after MatchCheckCtx.feature_exhaustive_patterns()"); + && is_enum_variant_uninhabited_from(variant, subst, cx.module, cx.db); !is_uninhabited }) - .map(|(local_id, _)| Variant(EnumVariantId { parent: enum_id, local_id })) + .map(Variant) .collect(); if is_secretly_empty || is_declared_nonexhaustive { diff --git a/crates/hir-ty/src/diagnostics/match_check/usefulness.rs b/crates/hir-ty/src/diagnostics/match_check/usefulness.rs index 1221327b9510..4bb4ff8f10a6 100644 --- a/crates/hir-ty/src/diagnostics/match_check/usefulness.rs +++ b/crates/hir-ty/src/diagnostics/match_check/usefulness.rs @@ -274,10 +274,11 @@ use std::iter::once; use hir_def::{AdtId, DefWithBodyId, HasModule, ModuleId}; +use once_cell::unsync::OnceCell; use smallvec::{smallvec, SmallVec}; use typed_arena::Arena; -use crate::{db::HirDatabase, Ty, TyExt}; +use crate::{db::HirDatabase, inhabitedness::is_ty_uninhabited_from, Ty, TyExt}; use super::deconstruct_pat::{Constructor, DeconstructedPat, Fields, SplitWildcard}; @@ -289,13 +290,25 @@ pub(crate) struct MatchCheckCtx<'a, 'p> { pub(crate) db: &'a dyn HirDatabase, /// Lowered patterns from arms plus generated by the check. pub(crate) pattern_arena: &'p Arena>, + feature_exhaustive_patterns: OnceCell, } impl<'a, 'p> MatchCheckCtx<'a, 'p> { - pub(super) fn is_uninhabited(&self, _ty: &Ty) -> bool { - // FIXME(iDawer) implement exhaustive_patterns feature. More info in: - // Tracking issue for RFC 1872: exhaustive_patterns feature https://github.com/rust-lang/rust/issues/51085 - false + pub(crate) fn new( + module: ModuleId, + body: DefWithBodyId, + db: &'a dyn HirDatabase, + pattern_arena: &'p Arena>, + ) -> Self { + Self { module, body, db, pattern_arena, feature_exhaustive_patterns: Default::default() } + } + + pub(super) fn is_uninhabited(&self, ty: &Ty) -> bool { + if self.feature_exhaustive_patterns() { + is_ty_uninhabited_from(ty, self.module, self.db) + } else { + false + } } /// Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`. @@ -311,10 +324,22 @@ impl<'a, 'p> MatchCheckCtx<'a, 'p> { } } - // Rust feature described as "Allows exhaustive pattern matching on types that contain uninhabited types." + // Rust's unstable feature described as "Allows exhaustive pattern matching on types that contain uninhabited types." pub(super) fn feature_exhaustive_patterns(&self) -> bool { - // FIXME see MatchCheckCtx::is_uninhabited - false + *self.feature_exhaustive_patterns.get_or_init(|| { + let def_map = self.db.crate_def_map(self.module.krate()); + let root_mod = def_map.module_id(def_map.root()); + let rood_attrs = self.db.attrs(root_mod.into()); + let mut nightly_features = rood_attrs + .by_key("feature") + .attrs() + .map(|attr| attr.parse_path_comma_token_tree()) + .flatten() + .flatten(); + nightly_features.any( + |feat| matches!(feat.segments(), [name] if name.to_smol_str() == "exhaustive_patterns"), + ) + }) } } diff --git a/crates/hir-ty/src/inhabitedness.rs b/crates/hir-ty/src/inhabitedness.rs new file mode 100644 index 000000000000..f4d822b9c709 --- /dev/null +++ b/crates/hir-ty/src/inhabitedness.rs @@ -0,0 +1,176 @@ +use std::ops::ControlFlow::{self, Break, Continue}; + +use chalk_ir::{ + visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}, + DebruijnIndex, +}; +use hir_def::{ + adt::VariantData, attr::Attrs, type_ref::ConstScalar, visibility::Visibility, AdtId, + EnumVariantId, HasModule, Lookup, ModuleId, VariantId, +}; + +use crate::{ + db::HirDatabase, Binders, ConcreteConst, Const, ConstValue, Interner, Substitution, Ty, TyKind, +}; + +pub(crate) fn is_ty_uninhabited_from(ty: &Ty, target_mod: ModuleId, db: &dyn HirDatabase) -> bool { + let mut uninhabited_from = UninhabitedFrom { target_mod, db }; + let inhabitedness = ty.visit_with(&mut uninhabited_from, DebruijnIndex::INNERMOST); + inhabitedness == BREAK_VISIBLY_UNINHABITED +} + +pub(crate) fn is_enum_variant_uninhabited_from( + variant: EnumVariantId, + subst: &Substitution, + target_mod: ModuleId, + db: &dyn HirDatabase, +) -> bool { + let enum_data = db.enum_data(variant.parent); + let vars_attrs = db.variants_attrs(variant.parent); + let is_local = variant.parent.lookup(db.upcast()).container.krate() == target_mod.krate(); + + let mut uninhabited_from = UninhabitedFrom { target_mod, db }; + let inhabitedness = uninhabited_from.visit_variant( + variant.into(), + &enum_data.variants[variant.local_id].variant_data, + subst, + &vars_attrs[variant.local_id], + is_local, + ); + inhabitedness == BREAK_VISIBLY_UNINHABITED +} + +struct UninhabitedFrom<'a> { + target_mod: ModuleId, + db: &'a dyn HirDatabase, +} + +const CONTINUE_OPAQUELY_INHABITED: ControlFlow = Continue(()); +const BREAK_VISIBLY_UNINHABITED: ControlFlow = Break(VisiblyUninhabited); +#[derive(PartialEq, Eq)] +struct VisiblyUninhabited; + +impl TypeVisitor for UninhabitedFrom<'_> { + type BreakTy = VisiblyUninhabited; + + fn as_dyn(&mut self) -> &mut dyn TypeVisitor { + self + } + + fn visit_ty( + &mut self, + ty: &Ty, + outer_binder: DebruijnIndex, + ) -> ControlFlow { + match ty.kind(Interner) { + TyKind::Adt(adt, subst) => self.visit_adt(adt.0, subst), + TyKind::Never => BREAK_VISIBLY_UNINHABITED, + TyKind::Tuple(..) => ty.super_visit_with(self, outer_binder), + TyKind::Array(item_ty, len) => match try_usize_const(len) { + Some(0) | None => CONTINUE_OPAQUELY_INHABITED, + Some(1..) => item_ty.super_visit_with(self, outer_binder), + }, + + TyKind::Ref(..) | _ => CONTINUE_OPAQUELY_INHABITED, + } + } + + fn interner(&self) -> Interner { + Interner + } +} + +impl UninhabitedFrom<'_> { + fn visit_adt(&mut self, adt: AdtId, subst: &Substitution) -> ControlFlow { + let attrs = self.db.attrs(adt.into()); + let adt_non_exhaustive = attrs.by_key("non_exhaustive").exists(); + let is_local = adt.module(self.db.upcast()).krate() == self.target_mod.krate(); + if adt_non_exhaustive && !is_local { + return CONTINUE_OPAQUELY_INHABITED; + } + + // An ADT is uninhabited iff all its variants uninhabited. + match adt { + // rustc: For now, `union`s are never considered uninhabited. + AdtId::UnionId(_) => CONTINUE_OPAQUELY_INHABITED, + AdtId::StructId(s) => { + let struct_data = self.db.struct_data(s); + self.visit_variant(s.into(), &struct_data.variant_data, subst, &attrs, is_local) + } + AdtId::EnumId(e) => { + let vars_attrs = self.db.variants_attrs(e); + let enum_data = self.db.enum_data(e); + + for (local_id, enum_var) in enum_data.variants.iter() { + let variant_inhabitedness = self.visit_variant( + EnumVariantId { parent: e, local_id }.into(), + &enum_var.variant_data, + subst, + &vars_attrs[local_id], + is_local, + ); + match variant_inhabitedness { + Break(VisiblyUninhabited) => continue, + Continue(()) => return CONTINUE_OPAQUELY_INHABITED, + } + } + BREAK_VISIBLY_UNINHABITED + } + } + } + + fn visit_variant( + &mut self, + variant: VariantId, + variant_data: &VariantData, + subst: &Substitution, + attrs: &Attrs, + is_local: bool, + ) -> ControlFlow { + let non_exhaustive_field_list = attrs.by_key("non_exhaustive").exists(); + if non_exhaustive_field_list && !is_local { + return CONTINUE_OPAQUELY_INHABITED; + } + + let is_enum = matches!(variant, VariantId::EnumVariantId(..)); + let field_tys = self.db.field_types(variant); + let field_vis = self.db.field_visibilities(variant); + + for (fid, _) in variant_data.fields().iter() { + self.visit_field(field_vis[fid], &field_tys[fid], subst, is_enum)?; + } + CONTINUE_OPAQUELY_INHABITED + } + + fn visit_field( + &mut self, + vis: Visibility, + ty: &Binders, + subst: &Substitution, + is_enum: bool, + ) -> ControlFlow { + let target_mod = self.target_mod; + let mut data_uninhabitedness = + || ty.clone().substitute(Interner, subst).visit_with(self, DebruijnIndex::INNERMOST); + if is_enum { + data_uninhabitedness() + } else { + match vis { + Visibility::Module(mod_id) if mod_id == target_mod => data_uninhabitedness(), + Visibility::Module(_) => CONTINUE_OPAQUELY_INHABITED, + Visibility::Public => data_uninhabitedness(), + } + } + } +} + +fn try_usize_const(c: &Const) -> Option { + let data = &c.data(Interner); + if data.ty.kind(Interner) != &TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)) { + return None; + } + match data.value { + ConstValue::Concrete(ConcreteConst { interned: ConstScalar::UInt(value) }) => Some(value), + _ => None, + } +} diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs index 5a5d610e360f..a82a331d4b87 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -14,6 +14,7 @@ mod chalk_db; mod chalk_ext; pub mod consteval; mod infer; +mod inhabitedness; mod interner; mod lower; mod mapping; diff --git a/crates/ide-diagnostics/src/handlers/missing_match_arms.rs b/crates/ide-diagnostics/src/handlers/missing_match_arms.rs index 5fcaf405b14b..c24430ce6046 100644 --- a/crates/ide-diagnostics/src/handlers/missing_match_arms.rs +++ b/crates/ide-diagnostics/src/handlers/missing_match_arms.rs @@ -947,6 +947,50 @@ fn f() { ); } + mod rust_unstable { + use super::*; + + #[test] + fn rfc_1872_exhaustive_patterns() { + check_diagnostics_no_bails( + r" +//- minicore: option, result +#![feature(exhaustive_patterns)] +enum Void {} +fn test() { + match None:: { None => () } + match Result::::Ok(2) { Ok(_) => () } + match Result::::Ok(2) { Ok(_) => () } + match (2, loop {}) {} + match Result::::Ok(loop {}) {} + match (&loop {}) {} // https://github.com/rust-lang/rust/issues/50642#issuecomment-388234919 + // ^^^^^^^^^^ error: missing match arm: type `&!` is non-empty +}", + ); + } + + #[test] + fn rfc_1872_private_uninhabitedness() { + check_diagnostics_no_bails( + r" +//- minicore: option +//- /lib.rs crate:lib +#![feature(exhaustive_patterns)] +pub struct PrivatelyUninhabited { private_field: Void } +enum Void {} +fn test_local(x: Option) { + match x {} +} // ^ error: missing match arm: `None` not covered +//- /main.rs crate:main deps:lib +#![feature(exhaustive_patterns)] +fn test(x: Option) { + match x {} + // ^ error: missing match arm: `None` and `Some(_)` not covered +}", + ); + } + } + mod false_negatives { //! The implementation of match checking here is a work in progress. As we roll this out, we //! prefer false negatives to false positives (ideally there would be no false positives). This From 671a4b8b0ff3d4e32f2e55eaf8389e69433535df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Aug 2022 14:51:05 +0200 Subject: [PATCH 3995/5092] make backtrace header a bit more visible --- src/diagnostics.rs | 2 +- tests/extern-so/fail/function_not_in_so.stderr | 2 +- tests/fail/alloc/deallocate-bad-alignment.stderr | 2 +- tests/fail/alloc/deallocate-bad-size.stderr | 2 +- tests/fail/alloc/deallocate-twice.stderr | 2 +- tests/fail/alloc/global_system_mixup.stderr | 2 +- tests/fail/alloc/no_global_allocator.stderr | 2 +- tests/fail/alloc/reallocate-bad-size.stderr | 2 +- tests/fail/alloc/reallocate-change-alloc.stderr | 2 +- tests/fail/alloc/reallocate-dangling.stderr | 2 +- tests/fail/alloc/stack_free.stderr | 2 +- tests/fail/box-cell-alias.stderr | 2 +- tests/fail/branchless-select-i128-pointer.stderr | 2 +- tests/fail/concurrency/libc_pthread_create_too_few_args.stderr | 2 +- tests/fail/concurrency/libc_pthread_create_too_many_args.stderr | 2 +- tests/fail/concurrency/libc_pthread_join_detached.stderr | 2 +- tests/fail/concurrency/libc_pthread_join_joined.stderr | 2 +- tests/fail/concurrency/libc_pthread_join_main.stderr | 2 +- tests/fail/concurrency/libc_pthread_join_multiple.stderr | 2 +- tests/fail/concurrency/libc_pthread_join_self.stderr | 2 +- tests/fail/concurrency/read_only_atomic_cmpxchg.stderr | 2 +- tests/fail/concurrency/read_only_atomic_load.stderr | 2 +- tests/fail/concurrency/thread_local_static_dealloc.stderr | 2 +- tests/fail/concurrency/unwind_top_of_stack.stderr | 2 +- tests/fail/concurrency/windows_join_detached.stderr | 2 +- tests/fail/crates/tokio_mvp.stderr | 2 +- tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr | 2 +- tests/fail/dangling_pointers/dangling_pointer_deref.stderr | 2 +- tests/fail/dangling_pointers/dangling_zst_deref.stderr | 2 +- tests/fail/dangling_pointers/deref-invalid-ptr.stderr | 2 +- tests/fail/dangling_pointers/deref-partially-dangling.stderr | 2 +- tests/fail/dangling_pointers/dyn_size.stderr | 2 +- .../fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr | 2 +- .../fail/dangling_pointers/maybe_null_pointer_write_zst.stderr | 2 +- tests/fail/dangling_pointers/null_pointer_deref.stderr | 2 +- tests/fail/dangling_pointers/null_pointer_deref_zst.stderr | 2 +- tests/fail/dangling_pointers/null_pointer_write.stderr | 2 +- tests/fail/dangling_pointers/null_pointer_write_zst.stderr | 2 +- tests/fail/dangling_pointers/out_of_bounds_read1.stderr | 2 +- tests/fail/dangling_pointers/out_of_bounds_read2.stderr | 2 +- tests/fail/dangling_pointers/stack_temporary.stderr | 2 +- tests/fail/dangling_pointers/storage_dead_dangling.stderr | 2 +- tests/fail/dangling_pointers/wild_pointer_deref.stderr | 2 +- tests/fail/data_race/alloc_read_race.stderr | 2 +- tests/fail/data_race/alloc_write_race.stderr | 2 +- tests/fail/data_race/atomic_read_na_write_race1.stderr | 2 +- tests/fail/data_race/atomic_read_na_write_race2.stderr | 2 +- tests/fail/data_race/atomic_write_na_read_race1.stderr | 2 +- tests/fail/data_race/atomic_write_na_read_race2.stderr | 2 +- tests/fail/data_race/atomic_write_na_write_race1.stderr | 2 +- tests/fail/data_race/atomic_write_na_write_race2.stderr | 2 +- tests/fail/data_race/dangling_thread_async_race.stderr | 2 +- tests/fail/data_race/dangling_thread_race.stderr | 2 +- tests/fail/data_race/dealloc_read_race1.stderr | 2 +- tests/fail/data_race/dealloc_read_race2.stderr | 2 +- tests/fail/data_race/dealloc_read_race_stack.stderr | 2 +- tests/fail/data_race/dealloc_write_race1.stderr | 2 +- tests/fail/data_race/dealloc_write_race2.stderr | 2 +- tests/fail/data_race/dealloc_write_race_stack.stderr | 2 +- tests/fail/data_race/enable_after_join_to_main.stderr | 2 +- tests/fail/data_race/fence_after_load.stderr | 2 +- tests/fail/data_race/read_write_race.stderr | 2 +- tests/fail/data_race/read_write_race_stack.stderr | 2 +- tests/fail/data_race/relax_acquire_race.stderr | 2 +- tests/fail/data_race/release_seq_race.stderr | 2 +- tests/fail/data_race/release_seq_race_same_thread.stderr | 2 +- tests/fail/data_race/rmw_race.stderr | 2 +- tests/fail/data_race/stack_pop_race.stderr | 2 +- tests/fail/data_race/write_write_race.stderr | 2 +- tests/fail/data_race/write_write_race_stack.stderr | 2 +- tests/fail/dyn-call-trait-mismatch.stderr | 2 +- tests/fail/dyn-upcast-trait-mismatch.stderr | 2 +- tests/fail/environ-gets-deallocated.stderr | 2 +- tests/fail/extern_static.stderr | 2 +- tests/fail/extern_static_in_const.stderr | 2 +- tests/fail/extern_static_wrong_size.stderr | 2 +- tests/fail/fast_math_both.stderr | 2 +- tests/fail/fast_math_first.stderr | 2 +- tests/fail/fast_math_second.stderr | 2 +- tests/fail/function_calls/check_arg_abi.stderr | 2 +- tests/fail/function_calls/check_arg_count_abort.stderr | 2 +- tests/fail/function_calls/check_arg_count_too_few_args.stderr | 2 +- tests/fail/function_calls/check_arg_count_too_many_args.stderr | 2 +- tests/fail/function_calls/check_callback_abi.stderr | 2 +- .../function_calls/exported_symbol_abi_mismatch.cache.stderr | 2 +- .../function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr | 2 +- .../function_calls/exported_symbol_abi_mismatch.no_cache.stderr | 2 +- tests/fail/function_calls/exported_symbol_bad_unwind1.stderr | 2 +- .../exported_symbol_bad_unwind2.extern_block.stderr | 2 +- tests/fail/function_calls/exported_symbol_clashing.stderr | 2 +- tests/fail/function_calls/exported_symbol_shim_clashing.stderr | 2 +- .../fail/function_calls/exported_symbol_wrong_arguments.stderr | 2 +- tests/fail/function_calls/exported_symbol_wrong_type.stderr | 2 +- tests/fail/function_pointers/cast_box_int_to_fn_ptr.stderr | 2 +- tests/fail/function_pointers/cast_fn_ptr1.stderr | 2 +- tests/fail/function_pointers/cast_fn_ptr2.stderr | 2 +- tests/fail/function_pointers/cast_fn_ptr3.stderr | 2 +- tests/fail/function_pointers/cast_fn_ptr4.stderr | 2 +- tests/fail/function_pointers/cast_fn_ptr5.stderr | 2 +- tests/fail/function_pointers/cast_int_to_fn_ptr.stderr | 2 +- tests/fail/function_pointers/deref_fn_ptr.stderr | 2 +- tests/fail/function_pointers/execute_memory.stderr | 2 +- tests/fail/function_pointers/fn_ptr_offset.stderr | 2 +- tests/fail/generator-pinned-moved.stderr | 2 +- tests/fail/intrinsics/assume.stderr | 2 +- tests/fail/intrinsics/copy_null.stderr | 2 +- tests/fail/intrinsics/copy_overflow.stderr | 2 +- tests/fail/intrinsics/copy_overlapping.stderr | 2 +- tests/fail/intrinsics/copy_unaligned.stderr | 2 +- tests/fail/intrinsics/ctlz_nonzero.stderr | 2 +- tests/fail/intrinsics/cttz_nonzero.stderr | 2 +- tests/fail/intrinsics/div-by-zero.stderr | 2 +- tests/fail/intrinsics/exact_div1.stderr | 2 +- tests/fail/intrinsics/exact_div2.stderr | 2 +- tests/fail/intrinsics/exact_div3.stderr | 2 +- tests/fail/intrinsics/exact_div4.stderr | 2 +- tests/fail/intrinsics/float_to_int_32_inf1.stderr | 2 +- tests/fail/intrinsics/float_to_int_32_infneg1.stderr | 2 +- tests/fail/intrinsics/float_to_int_32_nan.stderr | 2 +- tests/fail/intrinsics/float_to_int_32_nanneg.stderr | 2 +- tests/fail/intrinsics/float_to_int_32_neg.stderr | 2 +- tests/fail/intrinsics/float_to_int_32_too_big1.stderr | 2 +- tests/fail/intrinsics/float_to_int_32_too_big2.stderr | 2 +- tests/fail/intrinsics/float_to_int_32_too_small1.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_inf1.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_infneg1.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_infneg2.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_nan.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_neg.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_too_big1.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_too_big2.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_too_big3.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_too_big4.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_too_big5.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_too_big6.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_too_big7.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_too_small1.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_too_small2.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_too_small3.stderr | 2 +- tests/fail/intrinsics/out_of_bounds_ptr_1.stderr | 2 +- tests/fail/intrinsics/out_of_bounds_ptr_2.stderr | 2 +- tests/fail/intrinsics/out_of_bounds_ptr_3.stderr | 2 +- tests/fail/intrinsics/overflowing-unchecked-rsh.stderr | 2 +- tests/fail/intrinsics/ptr_offset_0_plus_0.stderr | 2 +- tests/fail/intrinsics/ptr_offset_from_oob.stderr | 2 +- tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr | 2 +- tests/fail/intrinsics/ptr_offset_int_plus_int.stderr | 2 +- tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr | 2 +- tests/fail/intrinsics/ptr_offset_overflow.stderr | 2 +- tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr | 2 +- tests/fail/intrinsics/raw_eq_on_ptr.stderr | 2 +- tests/fail/intrinsics/rem-by-zero.stderr | 2 +- tests/fail/intrinsics/simd-div-by-zero.stderr | 2 +- tests/fail/intrinsics/simd-div-overflow.stderr | 2 +- tests/fail/intrinsics/simd-float-to-int.stderr | 2 +- tests/fail/intrinsics/simd-gather.stderr | 2 +- tests/fail/intrinsics/simd-reduce-invalid-bool.stderr | 2 +- tests/fail/intrinsics/simd-rem-by-zero.stderr | 2 +- tests/fail/intrinsics/simd-scatter.stderr | 2 +- tests/fail/intrinsics/simd-select-bitmask-invalid.stderr | 2 +- tests/fail/intrinsics/simd-select-invalid-bool.stderr | 2 +- tests/fail/intrinsics/simd-shl-too-far.stderr | 2 +- tests/fail/intrinsics/simd-shr-too-far.stderr | 2 +- tests/fail/intrinsics/unchecked_add1.stderr | 2 +- tests/fail/intrinsics/unchecked_add2.stderr | 2 +- tests/fail/intrinsics/unchecked_div1.stderr | 2 +- tests/fail/intrinsics/unchecked_mul1.stderr | 2 +- tests/fail/intrinsics/unchecked_mul2.stderr | 2 +- tests/fail/intrinsics/unchecked_sub1.stderr | 2 +- tests/fail/intrinsics/unchecked_sub2.stderr | 2 +- tests/fail/intrinsics/write_bytes_null.stderr | 2 +- tests/fail/intrinsics/write_bytes_overflow.stderr | 2 +- tests/fail/invalid_bool.stderr | 2 +- tests/fail/invalid_char.stderr | 2 +- tests/fail/invalid_enum_tag.stderr | 2 +- tests/fail/invalid_int.stderr | 2 +- tests/fail/issue-miri-1112.stderr | 2 +- tests/fail/issue-miri-2432.stderr | 2 +- tests/fail/modifying_constants.stderr | 2 +- tests/fail/never_say_never.stderr | 2 +- tests/fail/never_transmute_humans.stderr | 2 +- tests/fail/never_transmute_void.stderr | 2 +- tests/fail/panic/bad_miri_start_panic.stderr | 2 +- tests/fail/panic/bad_unwind.stderr | 2 +- tests/fail/panic/unwind_panic_abort.stderr | 2 +- tests/fail/pointer_partial_overwrite.stderr | 2 +- tests/fail/provenance/provenance_transmute.stderr | 2 +- tests/fail/provenance/ptr_int_unexposed.stderr | 2 +- tests/fail/provenance/ptr_invalid.stderr | 2 +- tests/fail/provenance/ptr_invalid_offset.stderr | 2 +- tests/fail/provenance/strict_provenance_cast.stderr | 2 +- tests/fail/rc_as_ptr.stderr | 2 +- tests/fail/reading_half_a_pointer.stderr | 2 +- tests/fail/shims/backtrace/bad-backtrace-decl.stderr | 2 +- tests/fail/shims/backtrace/bad-backtrace-flags.stderr | 2 +- tests/fail/shims/backtrace/bad-backtrace-ptr.stderr | 2 +- tests/fail/shims/backtrace/bad-backtrace-resolve-flags.stderr | 2 +- .../shims/backtrace/bad-backtrace-resolve-names-flags.stderr | 2 +- tests/fail/shims/backtrace/bad-backtrace-size-flags.stderr | 2 +- tests/fail/shims/fs/close_stdout.stderr | 2 +- tests/fail/shims/fs/isolated_file.stderr | 2 +- tests/fail/shims/fs/isolated_stdin.stderr | 2 +- tests/fail/shims/fs/mkstemp_immutable_arg.stderr | 2 +- tests/fail/shims/fs/read_from_stdout.stderr | 2 +- tests/fail/shims/fs/unix_open_missing_required_mode.stderr | 2 +- tests/fail/shims/fs/write_to_stdin.stderr | 2 +- tests/fail/shims/shim_arg_size.64bit.stderr | 2 +- tests/fail/shims/sync/libc_pthread_cond_double_destroy.stderr | 2 +- .../fail/shims/sync/libc_pthread_condattr_double_destroy.stderr | 2 +- tests/fail/shims/sync/libc_pthread_mutex_NULL_deadlock.stderr | 2 +- .../fail/shims/sync/libc_pthread_mutex_default_deadlock.stderr | 2 +- tests/fail/shims/sync/libc_pthread_mutex_destroy_locked.stderr | 2 +- tests/fail/shims/sync/libc_pthread_mutex_double_destroy.stderr | 2 +- .../shims/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr | 2 +- tests/fail/shims/sync/libc_pthread_mutex_wrong_owner.stderr | 2 +- .../shims/sync/libc_pthread_mutexattr_double_destroy.stderr | 2 +- .../shims/sync/libc_pthread_rwlock_destroy_read_locked.stderr | 2 +- .../shims/sync/libc_pthread_rwlock_destroy_write_locked.stderr | 2 +- tests/fail/shims/sync/libc_pthread_rwlock_double_destroy.stderr | 2 +- .../fail/shims/sync/libc_pthread_rwlock_read_wrong_owner.stderr | 2 +- .../fail/shims/sync/libc_pthread_rwlock_unlock_unlocked.stderr | 2 +- .../shims/sync/libc_pthread_rwlock_write_wrong_owner.stderr | 2 +- tests/fail/should-pass/cpp20_rwc_syncs.stderr | 2 +- tests/fail/stacked_borrows/alias_through_mutation.stderr | 2 +- tests/fail/stacked_borrows/aliasing_mut1.stderr | 2 +- tests/fail/stacked_borrows/aliasing_mut2.stderr | 2 +- tests/fail/stacked_borrows/aliasing_mut3.stderr | 2 +- tests/fail/stacked_borrows/aliasing_mut4.stderr | 2 +- tests/fail/stacked_borrows/box_exclusive_violation1.stderr | 2 +- tests/fail/stacked_borrows/buggy_as_mut_slice.stderr | 2 +- tests/fail/stacked_borrows/buggy_split_at_mut.stderr | 2 +- tests/fail/stacked_borrows/deallocate_against_protector1.stderr | 2 +- tests/fail/stacked_borrows/deallocate_against_protector2.stderr | 2 +- .../fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr | 2 +- tests/fail/stacked_borrows/exposed_only_ro.stderr | 2 +- tests/fail/stacked_borrows/fnentry_invalidation.stderr | 2 +- tests/fail/stacked_borrows/illegal_read1.stderr | 2 +- tests/fail/stacked_borrows/illegal_read2.stderr | 2 +- tests/fail/stacked_borrows/illegal_read3.stderr | 2 +- tests/fail/stacked_borrows/illegal_read4.stderr | 2 +- tests/fail/stacked_borrows/illegal_read5.stderr | 2 +- tests/fail/stacked_borrows/illegal_read6.stderr | 2 +- tests/fail/stacked_borrows/illegal_read7.stderr | 2 +- tests/fail/stacked_borrows/illegal_read8.stderr | 2 +- tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr | 2 +- tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr | 2 +- tests/fail/stacked_borrows/illegal_write1.stderr | 2 +- tests/fail/stacked_borrows/illegal_write2.stderr | 2 +- tests/fail/stacked_borrows/illegal_write3.stderr | 2 +- tests/fail/stacked_borrows/illegal_write4.stderr | 2 +- tests/fail/stacked_borrows/illegal_write5.stderr | 2 +- tests/fail/stacked_borrows/illegal_write6.stderr | 2 +- .../fail/stacked_borrows/illegal_write_despite_exposed1.stderr | 2 +- tests/fail/stacked_borrows/interior_mut1.stderr | 2 +- tests/fail/stacked_borrows/interior_mut2.stderr | 2 +- tests/fail/stacked_borrows/invalidate_against_protector1.stderr | 2 +- tests/fail/stacked_borrows/invalidate_against_protector2.stderr | 2 +- tests/fail/stacked_borrows/issue-miri-1050-1.stderr | 2 +- tests/fail/stacked_borrows/issue-miri-1050-2.stderr | 2 +- tests/fail/stacked_borrows/load_invalid_mut.stderr | 2 +- tests/fail/stacked_borrows/load_invalid_shr.stderr | 2 +- tests/fail/stacked_borrows/mut_exclusive_violation1.stderr | 2 +- tests/fail/stacked_borrows/mut_exclusive_violation2.stderr | 2 +- tests/fail/stacked_borrows/newtype_retagging.stderr | 2 +- tests/fail/stacked_borrows/outdated_local.stderr | 2 +- tests/fail/stacked_borrows/pass_invalid_mut.stderr | 2 +- tests/fail/stacked_borrows/pass_invalid_shr.stderr | 2 +- tests/fail/stacked_borrows/pointer_smuggling.stderr | 2 +- tests/fail/stacked_borrows/raw_tracking.stderr | 2 +- tests/fail/stacked_borrows/return_invalid_mut.stderr | 2 +- tests/fail/stacked_borrows/return_invalid_mut_option.stderr | 2 +- tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr | 2 +- tests/fail/stacked_borrows/return_invalid_shr.stderr | 2 +- tests/fail/stacked_borrows/return_invalid_shr_option.stderr | 2 +- tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr | 2 +- tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr | 2 +- tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr | 2 +- tests/fail/stacked_borrows/shr_frozen_violation1.stderr | 2 +- tests/fail/stacked_borrows/static_memory_modification.stderr | 2 +- tests/fail/stacked_borrows/track_caller.stderr | 2 +- tests/fail/stacked_borrows/transmute-is-no-escape.stderr | 2 +- tests/fail/stacked_borrows/unescaped_local.stderr | 2 +- tests/fail/stacked_borrows/unescaped_static.stderr | 2 +- tests/fail/stacked_borrows/zst_slice.stderr | 2 +- tests/fail/static_memory_modification1.stderr | 2 +- tests/fail/static_memory_modification2.stderr | 2 +- tests/fail/static_memory_modification3.stderr | 2 +- tests/fail/transmute-pair-uninit.stderr | 2 +- tests/fail/transmute_fat1.stderr | 2 +- tests/fail/unaligned_pointers/alignment.stderr | 2 +- tests/fail/unaligned_pointers/atomic_unaligned.stderr | 2 +- tests/fail/unaligned_pointers/dyn_alignment.stderr | 2 +- tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr | 2 +- tests/fail/unaligned_pointers/reference_to_packed.stderr | 2 +- tests/fail/unaligned_pointers/unaligned_ptr1.stderr | 2 +- tests/fail/unaligned_pointers/unaligned_ptr2.stderr | 2 +- tests/fail/unaligned_pointers/unaligned_ptr3.stderr | 2 +- tests/fail/unaligned_pointers/unaligned_ptr4.stderr | 2 +- tests/fail/unaligned_pointers/unaligned_ptr_addr_of.stderr | 2 +- tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr | 2 +- tests/fail/uninit_buffer.stderr | 2 +- tests/fail/uninit_byte_read.stderr | 2 +- tests/fail/unreachable.stderr | 2 +- tests/fail/unsized-local.stderr | 2 +- tests/fail/unsupported_foreign_function.stderr | 2 +- tests/fail/unsupported_signal.stderr | 2 +- tests/fail/validity/cast_fn_ptr1.stderr | 2 +- tests/fail/validity/cast_fn_ptr2.stderr | 2 +- tests/fail/validity/dangling_ref1.stderr | 2 +- tests/fail/validity/dangling_ref2.stderr | 2 +- tests/fail/validity/dangling_ref3.stderr | 2 +- tests/fail/validity/invalid_bool.stderr | 2 +- tests/fail/validity/invalid_bool_uninit.stderr | 2 +- tests/fail/validity/invalid_char.stderr | 2 +- tests/fail/validity/invalid_char_uninit.stderr | 2 +- tests/fail/validity/invalid_enum_tag.stderr | 2 +- tests/fail/validity/invalid_fnptr_null.stderr | 2 +- tests/fail/validity/invalid_fnptr_uninit.stderr | 2 +- tests/fail/validity/invalid_wide_raw.stderr | 2 +- tests/fail/validity/nonzero.stderr | 2 +- tests/fail/validity/ptr_integer_array_transmute.stderr | 2 +- tests/fail/validity/ref_to_uninhabited1.stderr | 2 +- tests/fail/validity/ref_to_uninhabited2.stderr | 2 +- tests/fail/validity/too-big-slice.stderr | 2 +- tests/fail/validity/too-big-unsized.stderr | 2 +- tests/fail/validity/transmute_through_ptr.stderr | 2 +- tests/fail/validity/uninit_float.stderr | 2 +- tests/fail/validity/uninit_integer.stderr | 2 +- tests/fail/validity/uninit_raw_ptr.stderr | 2 +- tests/fail/weak_memory/racing_mixed_size.stderr | 2 +- tests/fail/weak_memory/racing_mixed_size_read.stderr | 2 +- tests/fail/zst1.stderr | 2 +- tests/fail/zst2.stderr | 2 +- tests/fail/zst3.stderr | 2 +- tests/pass/box.stderr | 2 +- tests/pass/extern_types.stderr | 2 +- tests/pass/stacked-borrows/issue-miri-2389.stderr | 2 +- 337 files changed, 337 insertions(+), 337 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 3a0d17b22a76..74d2fe2680a4 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -352,7 +352,7 @@ fn report_msg<'mir, 'tcx>( } if notes.len() + helps.len() > 0 { // Add visual separator before backtrace. - err.note("backtrace:"); + err.note("BACKTRACE:"); } // Add backtrace for (idx, frame_info) in stacktrace.iter().enumerate() { diff --git a/tests/extern-so/fail/function_not_in_so.stderr b/tests/extern-so/fail/function_not_in_so.stderr index 8ff9ca74bc58..f649f0ae43e3 100644 --- a/tests/extern-so/fail/function_not_in_so.stderr +++ b/tests/extern-so/fail/function_not_in_so.stderr @@ -5,7 +5,7 @@ LL | foo(); | ^^^^^ can't call foreign function: foo | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/function_not_in_so.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/alloc/deallocate-bad-alignment.stderr b/tests/fail/alloc/deallocate-bad-alignment.stderr index e46533ad70d3..28439b54b290 100644 --- a/tests/fail/alloc/deallocate-bad-alignment.stderr +++ b/tests/fail/alloc/deallocate-bad-alignment.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/deallocate-bad-alignment.rs:LL:CC --> $DIR/deallocate-bad-alignment.rs:LL:CC diff --git a/tests/fail/alloc/deallocate-bad-size.stderr b/tests/fail/alloc/deallocate-bad-size.stderr index d3ca2a4544bf..a6ceab1f56f5 100644 --- a/tests/fail/alloc/deallocate-bad-size.stderr +++ b/tests/fail/alloc/deallocate-bad-size.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/deallocate-bad-size.rs:LL:CC --> $DIR/deallocate-bad-size.rs:LL:CC diff --git a/tests/fail/alloc/deallocate-twice.stderr b/tests/fail/alloc/deallocate-twice.stderr index 1fadb277a0e4..b6c5b6f97ee7 100644 --- a/tests/fail/alloc/deallocate-twice.stderr +++ b/tests/fail/alloc/deallocate-twice.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/deallocate-twice.rs:LL:CC --> $DIR/deallocate-twice.rs:LL:CC diff --git a/tests/fail/alloc/global_system_mixup.stderr b/tests/fail/alloc/global_system_mixup.stderr index 60b91155f5e5..4ee85add6c22 100644 --- a/tests/fail/alloc/global_system_mixup.stderr +++ b/tests/fail/alloc/global_system_mixup.stderr @@ -6,7 +6,7 @@ LL | FREE(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::sys::PLATFORM::alloc::::dealloc` at RUSTLIB/std/src/sys/PLATFORM/alloc.rs:LL:CC = note: inside `::deallocate` at RUSTLIB/std/src/alloc.rs:LL:CC note: inside `main` at $DIR/global_system_mixup.rs:LL:CC diff --git a/tests/fail/alloc/no_global_allocator.stderr b/tests/fail/alloc/no_global_allocator.stderr index 5c11df9539c1..ea70970ae0fe 100644 --- a/tests/fail/alloc/no_global_allocator.stderr +++ b/tests/fail/alloc/no_global_allocator.stderr @@ -5,7 +5,7 @@ LL | __rust_alloc(1, 1); | ^^^^^^^^^^^^^^^^^^ can't call foreign function: __rust_alloc | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `start` at $DIR/no_global_allocator.rs:LL:CC error: aborting due to previous error diff --git a/tests/fail/alloc/reallocate-bad-size.stderr b/tests/fail/alloc/reallocate-bad-size.stderr index abe47e29ed32..c11b5a851048 100644 --- a/tests/fail/alloc/reallocate-bad-size.stderr +++ b/tests/fail/alloc/reallocate-bad-size.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::alloc::realloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/reallocate-bad-size.rs:LL:CC --> $DIR/reallocate-bad-size.rs:LL:CC diff --git a/tests/fail/alloc/reallocate-change-alloc.stderr b/tests/fail/alloc/reallocate-change-alloc.stderr index c22e44b754c9..5631dcb4cc08 100644 --- a/tests/fail/alloc/reallocate-change-alloc.stderr +++ b/tests/fail/alloc/reallocate-change-alloc.stderr @@ -6,7 +6,7 @@ LL | let _z = *x; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/reallocate-change-alloc.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/alloc/reallocate-dangling.stderr b/tests/fail/alloc/reallocate-dangling.stderr index 5eeaab8700c8..c7db5a729048 100644 --- a/tests/fail/alloc/reallocate-dangling.stderr +++ b/tests/fail/alloc/reallocate-dangling.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::alloc::realloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/reallocate-dangling.rs:LL:CC --> $DIR/reallocate-dangling.rs:LL:CC diff --git a/tests/fail/alloc/stack_free.stderr b/tests/fail/alloc/stack_free.stderr index 6ce522df58d6..44991542b135 100644 --- a/tests/fail/alloc/stack_free.stderr +++ b/tests/fail/alloc/stack_free.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `alloc::alloc::box_free::` at RUSTLIB/alloc/src/alloc.rs:LL:CC diff --git a/tests/fail/box-cell-alias.stderr b/tests/fail/box-cell-alias.stderr index 1436afcd212b..837016399768 100644 --- a/tests/fail/box-cell-alias.stderr +++ b/tests/fail/box-cell-alias.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x1] by a Unique retag | LL | let res = helper(val, ptr); | ^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `helper` at $DIR/box-cell-alias.rs:LL:CC note: inside `main` at $DIR/box-cell-alias.rs:LL:CC --> $DIR/box-cell-alias.rs:LL:CC diff --git a/tests/fail/branchless-select-i128-pointer.stderr b/tests/fail/branchless-select-i128-pointer.stderr index 15befcd12655..96f2ff3282c8 100644 --- a/tests/fail/branchless-select-i128-pointer.stderr +++ b/tests/fail/branchless-select-i128-pointer.stderr @@ -10,7 +10,7 @@ LL | | ) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/branchless-select-i128-pointer.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/libc_pthread_create_too_few_args.stderr b/tests/fail/concurrency/libc_pthread_create_too_few_args.stderr index 2304b42b2c78..94463bef8f0f 100644 --- a/tests/fail/concurrency/libc_pthread_create_too_few_args.stderr +++ b/tests/fail/concurrency/libc_pthread_create_too_few_args.stderr @@ -6,7 +6,7 @@ LL | panic!() | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `thread_start` at RUSTLIB/std/src/panic.rs:LL:CC = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/fail/concurrency/libc_pthread_create_too_many_args.stderr b/tests/fail/concurrency/libc_pthread_create_too_many_args.stderr index 49c7f579970f..fdbe91cc8a80 100644 --- a/tests/fail/concurrency/libc_pthread_create_too_many_args.stderr +++ b/tests/fail/concurrency/libc_pthread_create_too_many_args.stderr @@ -6,7 +6,7 @@ LL | panic!() | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `thread_start` at RUSTLIB/std/src/panic.rs:LL:CC = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/fail/concurrency/libc_pthread_join_detached.stderr b/tests/fail/concurrency/libc_pthread_join_detached.stderr index 92b693c0fd6b..763e0d3665d8 100644 --- a/tests/fail/concurrency/libc_pthread_join_detached.stderr +++ b/tests/fail/concurrency/libc_pthread_join_detached.stderr @@ -6,7 +6,7 @@ LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/libc_pthread_join_detached.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/libc_pthread_join_joined.stderr b/tests/fail/concurrency/libc_pthread_join_joined.stderr index f11b94cde8ee..a3253e2ef933 100644 --- a/tests/fail/concurrency/libc_pthread_join_joined.stderr +++ b/tests/fail/concurrency/libc_pthread_join_joined.stderr @@ -6,7 +6,7 @@ LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/libc_pthread_join_joined.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/libc_pthread_join_main.stderr b/tests/fail/concurrency/libc_pthread_join_main.stderr index c162f37b309f..09e14d46a967 100644 --- a/tests/fail/concurrency/libc_pthread_join_main.stderr +++ b/tests/fail/concurrency/libc_pthread_join_main.stderr @@ -6,7 +6,7 @@ LL | assert_eq!(libc::pthread_join(thread_id, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/libc_pthread_join_main.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/libc_pthread_join_multiple.stderr b/tests/fail/concurrency/libc_pthread_join_multiple.stderr index c0c73086f14d..db5d7bfd5dae 100644 --- a/tests/fail/concurrency/libc_pthread_join_multiple.stderr +++ b/tests/fail/concurrency/libc_pthread_join_multiple.stderr @@ -6,7 +6,7 @@ LL | ... assert_eq!(libc::pthread_join(native_copy, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/libc_pthread_join_multiple.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/libc_pthread_join_self.stderr b/tests/fail/concurrency/libc_pthread_join_self.stderr index 38e758e46c12..8db4a83f9ceb 100644 --- a/tests/fail/concurrency/libc_pthread_join_self.stderr +++ b/tests/fail/concurrency/libc_pthread_join_self.stderr @@ -6,7 +6,7 @@ LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/libc_pthread_join_self.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr b/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr index b90dc5c9d6cd..d51fdee0b256 100644 --- a/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr +++ b/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr @@ -12,7 +12,7 @@ please report an issue at if this is | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/read_only_atomic_cmpxchg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/read_only_atomic_load.stderr b/tests/fail/concurrency/read_only_atomic_load.stderr index b19d3755fbb0..17851d6b470b 100644 --- a/tests/fail/concurrency/read_only_atomic_load.stderr +++ b/tests/fail/concurrency/read_only_atomic_load.stderr @@ -12,7 +12,7 @@ please report an issue at if this is | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/read_only_atomic_load.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/thread_local_static_dealloc.stderr b/tests/fail/concurrency/thread_local_static_dealloc.stderr index 58e7cf07348f..cc3e56398781 100644 --- a/tests/fail/concurrency/thread_local_static_dealloc.stderr +++ b/tests/fail/concurrency/thread_local_static_dealloc.stderr @@ -6,7 +6,7 @@ LL | let _val = *dangling_ptr.0; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/thread_local_static_dealloc.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/unwind_top_of_stack.stderr b/tests/fail/concurrency/unwind_top_of_stack.stderr index efd19ef4c51a..98db33e3206b 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.stderr +++ b/tests/fail/concurrency/unwind_top_of_stack.stderr @@ -11,7 +11,7 @@ LL | | } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `thread_start` at $DIR/unwind_top_of_stack.rs:LL:CC error: aborting due to previous error diff --git a/tests/fail/concurrency/windows_join_detached.stderr b/tests/fail/concurrency/windows_join_detached.stderr index a0e85f6ce5ab..78c75611d333 100644 --- a/tests/fail/concurrency/windows_join_detached.stderr +++ b/tests/fail/concurrency/windows_join_detached.stderr @@ -6,7 +6,7 @@ LL | let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle( | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::sys::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/PLATFORM/thread.rs:LL:CC = note: inside `std::thread::JoinInner::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC diff --git a/tests/fail/crates/tokio_mvp.stderr b/tests/fail/crates/tokio_mvp.stderr index 8df83662aa02..016081d90adf 100644 --- a/tests/fail/crates/tokio_mvp.stderr +++ b/tests/fail/crates/tokio_mvp.stderr @@ -5,7 +5,7 @@ LL | syscall!(epoll_create1(flag)).map(|ep| Selector { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't call foreign function: epoll_create1 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: note: inside `main` at $DIR/tokio_mvp.rs:LL:CC --> $DIR/tokio_mvp.rs:LL:CC | diff --git a/tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr b/tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr index a6a2ca1507b5..5f081afe68af 100644 --- a/tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr +++ b/tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr @@ -6,7 +6,7 @@ LL | let x = unsafe { ptr::addr_of!(*p) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at RUSTLIB/core/src/ptr/mod.rs:LL:CC = note: this error originates in the macro `ptr::addr_of` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/fail/dangling_pointers/dangling_pointer_deref.stderr b/tests/fail/dangling_pointers/dangling_pointer_deref.stderr index cca3d0278aec..cb323818845d 100644 --- a/tests/fail/dangling_pointers/dangling_pointer_deref.stderr +++ b/tests/fail/dangling_pointers/dangling_pointer_deref.stderr @@ -6,7 +6,7 @@ LL | let x = unsafe { *p }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/dangling_pointer_deref.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/dangling_zst_deref.stderr b/tests/fail/dangling_pointers/dangling_zst_deref.stderr index 66626a925cc6..02db6302a0a1 100644 --- a/tests/fail/dangling_pointers/dangling_zst_deref.stderr +++ b/tests/fail/dangling_pointers/dangling_zst_deref.stderr @@ -6,7 +6,7 @@ LL | let _x = unsafe { *p }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/dangling_zst_deref.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/deref-invalid-ptr.stderr b/tests/fail/dangling_pointers/deref-invalid-ptr.stderr index 68003284994e..3e2c3903b7e4 100644 --- a/tests/fail/dangling_pointers/deref-invalid-ptr.stderr +++ b/tests/fail/dangling_pointers/deref-invalid-ptr.stderr @@ -6,7 +6,7 @@ LL | let _y = unsafe { &*x as *const u32 }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/deref-invalid-ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/deref-partially-dangling.stderr b/tests/fail/dangling_pointers/deref-partially-dangling.stderr index e37b6885922b..fe039ef3adaf 100644 --- a/tests/fail/dangling_pointers/deref-partially-dangling.stderr +++ b/tests/fail/dangling_pointers/deref-partially-dangling.stderr @@ -6,7 +6,7 @@ LL | let val = unsafe { (*xptr).1 }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/deref-partially-dangling.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/dyn_size.stderr b/tests/fail/dangling_pointers/dyn_size.stderr index 0abcee595e15..33aa6c844101 100644 --- a/tests/fail/dangling_pointers/dyn_size.stderr +++ b/tests/fail/dangling_pointers/dyn_size.stderr @@ -6,7 +6,7 @@ LL | let _ptr = unsafe { &*ptr }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/dyn_size.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr b/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr index 222f2a628196..3e492a170c8b 100644 --- a/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr +++ b/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr @@ -6,7 +6,7 @@ LL | let _x: () = unsafe { *ptr }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/maybe_null_pointer_deref_zst.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr index 12228bc1d717..c41c20aaf4a7 100644 --- a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr +++ b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr @@ -6,7 +6,7 @@ LL | unsafe { *ptr = zst_val }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/maybe_null_pointer_write_zst.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/null_pointer_deref.stderr b/tests/fail/dangling_pointers/null_pointer_deref.stderr index fbb922c4c113..64dcaa454847 100644 --- a/tests/fail/dangling_pointers/null_pointer_deref.stderr +++ b/tests/fail/dangling_pointers/null_pointer_deref.stderr @@ -6,7 +6,7 @@ LL | let x: i32 = unsafe { *std::ptr::null() }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/null_pointer_deref.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr b/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr index 40b8d0899b13..301578a4f5fb 100644 --- a/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr +++ b/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr @@ -6,7 +6,7 @@ LL | let x: () = unsafe { *std::ptr::null() }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/null_pointer_deref_zst.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/null_pointer_write.stderr b/tests/fail/dangling_pointers/null_pointer_write.stderr index a5bf59e26d25..0e5858a96f9d 100644 --- a/tests/fail/dangling_pointers/null_pointer_write.stderr +++ b/tests/fail/dangling_pointers/null_pointer_write.stderr @@ -6,7 +6,7 @@ LL | unsafe { *std::ptr::null_mut() = 0i32 }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/null_pointer_write.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/null_pointer_write_zst.stderr b/tests/fail/dangling_pointers/null_pointer_write_zst.stderr index 17ac04a706ff..2953d85c25f3 100644 --- a/tests/fail/dangling_pointers/null_pointer_write_zst.stderr +++ b/tests/fail/dangling_pointers/null_pointer_write_zst.stderr @@ -6,7 +6,7 @@ LL | unsafe { std::ptr::null_mut::<[u8; 0]>().write(zst_val) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/null_pointer_write_zst.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/out_of_bounds_read1.stderr b/tests/fail/dangling_pointers/out_of_bounds_read1.stderr index 2abc7a457b9a..b2461ce4230a 100644 --- a/tests/fail/dangling_pointers/out_of_bounds_read1.stderr +++ b/tests/fail/dangling_pointers/out_of_bounds_read1.stderr @@ -6,7 +6,7 @@ LL | let x = unsafe { *v.as_ptr().wrapping_offset(5) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/out_of_bounds_read1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/out_of_bounds_read2.stderr b/tests/fail/dangling_pointers/out_of_bounds_read2.stderr index e0735dd1f926..b17058b40629 100644 --- a/tests/fail/dangling_pointers/out_of_bounds_read2.stderr +++ b/tests/fail/dangling_pointers/out_of_bounds_read2.stderr @@ -6,7 +6,7 @@ LL | let x = unsafe { *v.as_ptr().wrapping_offset(5) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/out_of_bounds_read2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/stack_temporary.stderr b/tests/fail/dangling_pointers/stack_temporary.stderr index dd24e6dd675c..679e4809ca66 100644 --- a/tests/fail/dangling_pointers/stack_temporary.stderr +++ b/tests/fail/dangling_pointers/stack_temporary.stderr @@ -6,7 +6,7 @@ LL | let val = *x; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/stack_temporary.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/storage_dead_dangling.stderr b/tests/fail/dangling_pointers/storage_dead_dangling.stderr index 25c12feaa82d..72e5f20f924a 100644 --- a/tests/fail/dangling_pointers/storage_dead_dangling.stderr +++ b/tests/fail/dangling_pointers/storage_dead_dangling.stderr @@ -6,7 +6,7 @@ LL | unsafe { &mut *(LEAK as *mut i32) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `evil` at $DIR/storage_dead_dangling.rs:LL:CC note: inside `main` at $DIR/storage_dead_dangling.rs:LL:CC --> $DIR/storage_dead_dangling.rs:LL:CC diff --git a/tests/fail/dangling_pointers/wild_pointer_deref.stderr b/tests/fail/dangling_pointers/wild_pointer_deref.stderr index 571bbcef6595..658fb228174e 100644 --- a/tests/fail/dangling_pointers/wild_pointer_deref.stderr +++ b/tests/fail/dangling_pointers/wild_pointer_deref.stderr @@ -6,7 +6,7 @@ LL | let x = unsafe { *p }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/wild_pointer_deref.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/alloc_read_race.stderr b/tests/fail/data_race/alloc_read_race.stderr index b180c30bdf34..c6bfd12b2411 100644 --- a/tests/fail/data_race/alloc_read_race.stderr +++ b/tests/fail/data_race/alloc_read_race.stderr @@ -6,7 +6,7 @@ LL | *pointer.load(Ordering::Relaxed) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/alloc_read_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/alloc_write_race.stderr b/tests/fail/data_race/alloc_write_race.stderr index bae65b6262f4..c4efc175c207 100644 --- a/tests/fail/data_race/alloc_write_race.stderr +++ b/tests/fail/data_race/alloc_write_race.stderr @@ -6,7 +6,7 @@ LL | *pointer.load(Ordering::Relaxed) = 2; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/alloc_write_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/atomic_read_na_write_race1.stderr b/tests/fail/data_race/atomic_read_na_write_race1.stderr index e7a219e12352..04adf0a98b6c 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.stderr +++ b/tests/fail/data_race/atomic_read_na_write_race1.stderr @@ -6,7 +6,7 @@ LL | (&*c.0).load(Ordering::SeqCst) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/atomic_read_na_write_race1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/atomic_read_na_write_race2.stderr b/tests/fail/data_race/atomic_read_na_write_race2.stderr index 48a9c8546908..b48f927b8fca 100644 --- a/tests/fail/data_race/atomic_read_na_write_race2.stderr +++ b/tests/fail/data_race/atomic_read_na_write_race2.stderr @@ -6,7 +6,7 @@ LL | *atomic_ref.get_mut() = 32; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/atomic_read_na_write_race2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/atomic_write_na_read_race1.stderr b/tests/fail/data_race/atomic_write_na_read_race1.stderr index b3e12168255a..fdb9b353a67b 100644 --- a/tests/fail/data_race/atomic_write_na_read_race1.stderr +++ b/tests/fail/data_race/atomic_write_na_read_race1.stderr @@ -6,7 +6,7 @@ LL | *atomic_ref.get_mut() | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/atomic_write_na_read_race1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/atomic_write_na_read_race2.stderr b/tests/fail/data_race/atomic_write_na_read_race2.stderr index e9c6005f27e6..ec581e322b7d 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.stderr +++ b/tests/fail/data_race/atomic_write_na_read_race2.stderr @@ -6,7 +6,7 @@ LL | (&*c.0).store(32, Ordering::SeqCst); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/atomic_write_na_read_race2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/atomic_write_na_write_race1.stderr b/tests/fail/data_race/atomic_write_na_write_race1.stderr index 5ecc4ca04026..4c75f94d71cf 100644 --- a/tests/fail/data_race/atomic_write_na_write_race1.stderr +++ b/tests/fail/data_race/atomic_write_na_write_race1.stderr @@ -6,7 +6,7 @@ LL | (&*c.0).store(64, Ordering::SeqCst); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/atomic_write_na_write_race1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/atomic_write_na_write_race2.stderr b/tests/fail/data_race/atomic_write_na_write_race2.stderr index 2de1c6858888..8c7f14081c87 100644 --- a/tests/fail/data_race/atomic_write_na_write_race2.stderr +++ b/tests/fail/data_race/atomic_write_na_write_race2.stderr @@ -6,7 +6,7 @@ LL | *atomic_ref.get_mut() = 32; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/atomic_write_na_write_race2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dangling_thread_async_race.stderr b/tests/fail/data_race/dangling_thread_async_race.stderr index 66bb8b0be404..663bb8d4af51 100644 --- a/tests/fail/data_race/dangling_thread_async_race.stderr +++ b/tests/fail/data_race/dangling_thread_async_race.stderr @@ -6,7 +6,7 @@ LL | *c.0 = 64; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/dangling_thread_async_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dangling_thread_race.stderr b/tests/fail/data_race/dangling_thread_race.stderr index 1fd9afe17633..ad3e1735378f 100644 --- a/tests/fail/data_race/dangling_thread_race.stderr +++ b/tests/fail/data_race/dangling_thread_race.stderr @@ -6,7 +6,7 @@ LL | *c.0 = 64; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/dangling_thread_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dealloc_read_race1.stderr b/tests/fail/data_race/dealloc_read_race1.stderr index eec74e8b542a..194c2260baaa 100644 --- a/tests/fail/data_race/dealloc_read_race1.stderr +++ b/tests/fail/data_race/dealloc_read_race1.stderr @@ -11,7 +11,7 @@ LL | | ); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/dealloc_read_race1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dealloc_read_race2.stderr b/tests/fail/data_race/dealloc_read_race2.stderr index 41a1224101fc..f303d57c8bd9 100644 --- a/tests/fail/data_race/dealloc_read_race2.stderr +++ b/tests/fail/data_race/dealloc_read_race2.stderr @@ -6,7 +6,7 @@ LL | *ptr.0 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/dealloc_read_race2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dealloc_read_race_stack.stderr b/tests/fail/data_race/dealloc_read_race_stack.stderr index 3c125e03a680..c986e912f03b 100644 --- a/tests/fail/data_race/dealloc_read_race_stack.stderr +++ b/tests/fail/data_race/dealloc_read_race_stack.stderr @@ -6,7 +6,7 @@ LL | } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/dealloc_read_race_stack.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dealloc_write_race1.stderr b/tests/fail/data_race/dealloc_write_race1.stderr index f16c0040bb8a..56eb0b519c48 100644 --- a/tests/fail/data_race/dealloc_write_race1.stderr +++ b/tests/fail/data_race/dealloc_write_race1.stderr @@ -11,7 +11,7 @@ LL | | ); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/dealloc_write_race1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dealloc_write_race2.stderr b/tests/fail/data_race/dealloc_write_race2.stderr index 6f2e829b4297..23b8e9ade0e0 100644 --- a/tests/fail/data_race/dealloc_write_race2.stderr +++ b/tests/fail/data_race/dealloc_write_race2.stderr @@ -6,7 +6,7 @@ LL | *ptr.0 = 2; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/dealloc_write_race2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dealloc_write_race_stack.stderr b/tests/fail/data_race/dealloc_write_race_stack.stderr index ed069bb6fcd6..7b77e2470a1a 100644 --- a/tests/fail/data_race/dealloc_write_race_stack.stderr +++ b/tests/fail/data_race/dealloc_write_race_stack.stderr @@ -6,7 +6,7 @@ LL | } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/dealloc_write_race_stack.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/enable_after_join_to_main.stderr b/tests/fail/data_race/enable_after_join_to_main.stderr index cd707bdcfa9c..26c07ae6962b 100644 --- a/tests/fail/data_race/enable_after_join_to_main.stderr +++ b/tests/fail/data_race/enable_after_join_to_main.stderr @@ -6,7 +6,7 @@ LL | *c.0 = 64; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/enable_after_join_to_main.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/fence_after_load.stderr b/tests/fail/data_race/fence_after_load.stderr index 878342c1bd9f..0abfe213db17 100644 --- a/tests/fail/data_race/fence_after_load.stderr +++ b/tests/fail/data_race/fence_after_load.stderr @@ -6,7 +6,7 @@ LL | unsafe { V = 2 } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/fence_after_load.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/read_write_race.stderr b/tests/fail/data_race/read_write_race.stderr index b87a7a10974e..08a19537312c 100644 --- a/tests/fail/data_race/read_write_race.stderr +++ b/tests/fail/data_race/read_write_race.stderr @@ -6,7 +6,7 @@ LL | *c.0 = 64; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/read_write_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/read_write_race_stack.stderr b/tests/fail/data_race/read_write_race_stack.stderr index 29739d5083c4..20f137afe732 100644 --- a/tests/fail/data_race/read_write_race_stack.stderr +++ b/tests/fail/data_race/read_write_race_stack.stderr @@ -6,7 +6,7 @@ LL | stack_var | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/read_write_race_stack.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/relax_acquire_race.stderr b/tests/fail/data_race/relax_acquire_race.stderr index 21f9e6f96035..6121c25db22d 100644 --- a/tests/fail/data_race/relax_acquire_race.stderr +++ b/tests/fail/data_race/relax_acquire_race.stderr @@ -6,7 +6,7 @@ LL | *c.0 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/relax_acquire_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/release_seq_race.stderr b/tests/fail/data_race/release_seq_race.stderr index a7bca03547e5..777bc4adadc6 100644 --- a/tests/fail/data_race/release_seq_race.stderr +++ b/tests/fail/data_race/release_seq_race.stderr @@ -6,7 +6,7 @@ LL | *c.0 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/release_seq_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/release_seq_race_same_thread.stderr b/tests/fail/data_race/release_seq_race_same_thread.stderr index 515ce17e16cd..0fcb192d920f 100644 --- a/tests/fail/data_race/release_seq_race_same_thread.stderr +++ b/tests/fail/data_race/release_seq_race_same_thread.stderr @@ -6,7 +6,7 @@ LL | *c.0 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/release_seq_race_same_thread.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/rmw_race.stderr b/tests/fail/data_race/rmw_race.stderr index 905592fc2224..3ae6f3b84fe1 100644 --- a/tests/fail/data_race/rmw_race.stderr +++ b/tests/fail/data_race/rmw_race.stderr @@ -6,7 +6,7 @@ LL | *c.0 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/rmw_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/stack_pop_race.stderr b/tests/fail/data_race/stack_pop_race.stderr index ba830753f6ee..5de27108ab63 100644 --- a/tests/fail/data_race/stack_pop_race.stderr +++ b/tests/fail/data_race/stack_pop_race.stderr @@ -6,7 +6,7 @@ LL | } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `race` at $DIR/stack_pop_race.rs:LL:CC note: inside `main` at $DIR/stack_pop_race.rs:LL:CC --> $DIR/stack_pop_race.rs:LL:CC diff --git a/tests/fail/data_race/write_write_race.stderr b/tests/fail/data_race/write_write_race.stderr index afb9f4c1edb7..ee7072ccf5d1 100644 --- a/tests/fail/data_race/write_write_race.stderr +++ b/tests/fail/data_race/write_write_race.stderr @@ -6,7 +6,7 @@ LL | *c.0 = 64; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/write_write_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/write_write_race_stack.stderr b/tests/fail/data_race/write_write_race_stack.stderr index 97977bc297c1..ceb473c2a4a4 100644 --- a/tests/fail/data_race/write_write_race_stack.stderr +++ b/tests/fail/data_race/write_write_race_stack.stderr @@ -6,7 +6,7 @@ LL | stack_var = 1usize; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/write_write_race_stack.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dyn-call-trait-mismatch.stderr b/tests/fail/dyn-call-trait-mismatch.stderr index 2673a22a3df2..03272105c414 100644 --- a/tests/fail/dyn-call-trait-mismatch.stderr +++ b/tests/fail/dyn-call-trait-mismatch.stderr @@ -6,7 +6,7 @@ LL | r2.method2(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/dyn-call-trait-mismatch.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dyn-upcast-trait-mismatch.stderr b/tests/fail/dyn-upcast-trait-mismatch.stderr index cdd1421a660c..21870ef3733e 100644 --- a/tests/fail/dyn-upcast-trait-mismatch.stderr +++ b/tests/fail/dyn-upcast-trait-mismatch.stderr @@ -6,7 +6,7 @@ LL | let _err = baz_fake as &dyn Foo; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/dyn-upcast-trait-mismatch.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/environ-gets-deallocated.stderr b/tests/fail/environ-gets-deallocated.stderr index bb6525fa8061..a2d343bf8651 100644 --- a/tests/fail/environ-gets-deallocated.stderr +++ b/tests/fail/environ-gets-deallocated.stderr @@ -6,7 +6,7 @@ LL | let _y = unsafe { *pointer }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/environ-gets-deallocated.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/extern_static.stderr b/tests/fail/extern_static.stderr index 0adb996decdb..fa0d55e5f678 100644 --- a/tests/fail/extern_static.stderr +++ b/tests/fail/extern_static.stderr @@ -5,7 +5,7 @@ LL | let _val = unsafe { std::ptr::addr_of!(FOO) }; | ^^^ `extern` static `FOO` from crate `extern_static` is not supported by Miri | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/extern_static.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/extern_static_in_const.stderr b/tests/fail/extern_static_in_const.stderr index ebd5dd7fee15..e4ee8f1acba2 100644 --- a/tests/fail/extern_static_in_const.stderr +++ b/tests/fail/extern_static_in_const.stderr @@ -5,7 +5,7 @@ LL | let _val = X; | ^ `extern` static `E` from crate `extern_static_in_const` is not supported by Miri | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/extern_static_in_const.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/extern_static_wrong_size.stderr b/tests/fail/extern_static_wrong_size.stderr index fdeb7bb5f688..a56eba09df98 100644 --- a/tests/fail/extern_static_wrong_size.stderr +++ b/tests/fail/extern_static_wrong_size.stderr @@ -5,7 +5,7 @@ LL | let _val = unsafe { environ }; | ^^^^^^^ `extern` static `environ` from crate `extern_static_wrong_size` has been declared with a size of 1 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of N bytes and alignment of N bytes | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/extern_static_wrong_size.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/fast_math_both.stderr b/tests/fail/fast_math_both.stderr index 902c9a1f8bb5..2a0759f8a3ba 100644 --- a/tests/fail/fast_math_both.stderr +++ b/tests/fail/fast_math_both.stderr @@ -6,7 +6,7 @@ LL | ...: f32 = core::intrinsics::fsub_fast(f32::NAN, f32::NAN); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/fast_math_both.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/fast_math_first.stderr b/tests/fail/fast_math_first.stderr index 986b487991f9..766662ca14ba 100644 --- a/tests/fail/fast_math_first.stderr +++ b/tests/fail/fast_math_first.stderr @@ -6,7 +6,7 @@ LL | ... let _x: f32 = core::intrinsics::frem_fast(f32::NAN, 3.2); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/fast_math_first.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/fast_math_second.stderr b/tests/fail/fast_math_second.stderr index c5abb17f8fac..ce93f9398f2c 100644 --- a/tests/fail/fast_math_second.stderr +++ b/tests/fail/fast_math_second.stderr @@ -6,7 +6,7 @@ LL | ...f32 = core::intrinsics::fmul_fast(3.4f32, f32::INFINITY); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/fast_math_second.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/check_arg_abi.stderr b/tests/fail/function_calls/check_arg_abi.stderr index 952acde9ea53..406ccb070bab 100644 --- a/tests/fail/function_calls/check_arg_abi.stderr +++ b/tests/fail/function_calls/check_arg_abi.stderr @@ -6,7 +6,7 @@ LL | let _ = malloc(0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/check_arg_abi.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/check_arg_count_abort.stderr b/tests/fail/function_calls/check_arg_count_abort.stderr index bf24c5c91794..d90a7e31d6ee 100644 --- a/tests/fail/function_calls/check_arg_count_abort.stderr +++ b/tests/fail/function_calls/check_arg_count_abort.stderr @@ -6,7 +6,7 @@ LL | abort(1); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/check_arg_count_abort.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/check_arg_count_too_few_args.stderr b/tests/fail/function_calls/check_arg_count_too_few_args.stderr index ac0ec606dac8..9e2751a216bc 100644 --- a/tests/fail/function_calls/check_arg_count_too_few_args.stderr +++ b/tests/fail/function_calls/check_arg_count_too_few_args.stderr @@ -6,7 +6,7 @@ LL | let _ = malloc(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/check_arg_count_too_few_args.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/check_arg_count_too_many_args.stderr b/tests/fail/function_calls/check_arg_count_too_many_args.stderr index b465b02b6e42..e9a38b5ae421 100644 --- a/tests/fail/function_calls/check_arg_count_too_many_args.stderr +++ b/tests/fail/function_calls/check_arg_count_too_many_args.stderr @@ -6,7 +6,7 @@ LL | let _ = malloc(1, 2); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/check_arg_count_too_many_args.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/check_callback_abi.stderr b/tests/fail/function_calls/check_callback_abi.stderr index 5d5c30a203ac..50afc1097974 100644 --- a/tests/fail/function_calls/check_callback_abi.stderr +++ b/tests/fail/function_calls/check_callback_abi.stderr @@ -11,7 +11,7 @@ LL | | ); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/check_callback_abi.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr b/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr index ba2b4de889b7..ae5c6cb72b3c 100644 --- a/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr +++ b/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr @@ -6,7 +6,7 @@ LL | foo(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/exported_symbol_abi_mismatch.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr b/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr index 358f86c0403b..17d56793ac5c 100644 --- a/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr +++ b/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr @@ -6,7 +6,7 @@ LL | std::mem::transmute::(foo)(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/exported_symbol_abi_mismatch.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr b/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr index ba2b4de889b7..ae5c6cb72b3c 100644 --- a/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr +++ b/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr @@ -6,7 +6,7 @@ LL | foo(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/exported_symbol_abi_mismatch.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr b/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr index 0b943432c207..7f87ec6f3bb6 100644 --- a/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr +++ b/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr @@ -8,7 +8,7 @@ LL | unsafe { unwind() } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/exported_symbol_bad_unwind1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr b/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr index f974eb87037a..b23c05a53035 100644 --- a/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr +++ b/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr @@ -8,7 +8,7 @@ LL | unsafe { nounwind() } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/exported_symbol_bad_unwind2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_clashing.stderr b/tests/fail/function_calls/exported_symbol_clashing.stderr index 998b7c415930..8eb9fa4ff5c2 100644 --- a/tests/fail/function_calls/exported_symbol_clashing.stderr +++ b/tests/fail/function_calls/exported_symbol_clashing.stderr @@ -14,7 +14,7 @@ help: then it's defined here again, in crate `exported_symbol_clashing` | LL | fn bar() {} | ^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/exported_symbol_clashing.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_shim_clashing.stderr b/tests/fail/function_calls/exported_symbol_shim_clashing.stderr index 69b99b374733..58a996e64530 100644 --- a/tests/fail/function_calls/exported_symbol_shim_clashing.stderr +++ b/tests/fail/function_calls/exported_symbol_shim_clashing.stderr @@ -12,7 +12,7 @@ LL | | LL | | unreachable!() LL | | } | |_^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/exported_symbol_shim_clashing.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr b/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr index 2e80e833710e..1aa13ce43895 100644 --- a/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr +++ b/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr @@ -6,7 +6,7 @@ LL | unsafe { foo(1) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/exported_symbol_wrong_arguments.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_wrong_type.stderr b/tests/fail/function_calls/exported_symbol_wrong_type.stderr index 900e23d1212e..abfd7a9a6c4d 100644 --- a/tests/fail/function_calls/exported_symbol_wrong_type.stderr +++ b/tests/fail/function_calls/exported_symbol_wrong_type.stderr @@ -6,7 +6,7 @@ LL | unsafe { FOO() } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/exported_symbol_wrong_type.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_box_int_to_fn_ptr.stderr b/tests/fail/function_pointers/cast_box_int_to_fn_ptr.stderr index 436cced9f02e..ad43c2c9d3fe 100644 --- a/tests/fail/function_pointers/cast_box_int_to_fn_ptr.stderr +++ b/tests/fail/function_pointers/cast_box_int_to_fn_ptr.stderr @@ -6,7 +6,7 @@ LL | (*g)(42) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/cast_box_int_to_fn_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_fn_ptr1.stderr b/tests/fail/function_pointers/cast_fn_ptr1.stderr index 972fd9afc8ea..bb2a26379598 100644 --- a/tests/fail/function_pointers/cast_fn_ptr1.stderr +++ b/tests/fail/function_pointers/cast_fn_ptr1.stderr @@ -6,7 +6,7 @@ LL | g(42) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/cast_fn_ptr1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_fn_ptr2.stderr b/tests/fail/function_pointers/cast_fn_ptr2.stderr index 638c4ca6781e..086712e0d13b 100644 --- a/tests/fail/function_pointers/cast_fn_ptr2.stderr +++ b/tests/fail/function_pointers/cast_fn_ptr2.stderr @@ -6,7 +6,7 @@ LL | g(42) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/cast_fn_ptr2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_fn_ptr3.stderr b/tests/fail/function_pointers/cast_fn_ptr3.stderr index e21d1c6b6f73..55fd7d607208 100644 --- a/tests/fail/function_pointers/cast_fn_ptr3.stderr +++ b/tests/fail/function_pointers/cast_fn_ptr3.stderr @@ -6,7 +6,7 @@ LL | g() | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/cast_fn_ptr3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_fn_ptr4.stderr b/tests/fail/function_pointers/cast_fn_ptr4.stderr index b1acafcebe7e..610425658fe1 100644 --- a/tests/fail/function_pointers/cast_fn_ptr4.stderr +++ b/tests/fail/function_pointers/cast_fn_ptr4.stderr @@ -6,7 +6,7 @@ LL | g(&42 as *const i32) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/cast_fn_ptr4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_fn_ptr5.stderr b/tests/fail/function_pointers/cast_fn_ptr5.stderr index c4915f905bf3..c4e08b58430a 100644 --- a/tests/fail/function_pointers/cast_fn_ptr5.stderr +++ b/tests/fail/function_pointers/cast_fn_ptr5.stderr @@ -6,7 +6,7 @@ LL | g() | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/cast_fn_ptr5.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr b/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr index 3d4acbe6f09a..81fc9716a415 100644 --- a/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr +++ b/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr @@ -6,7 +6,7 @@ LL | g(42) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/cast_int_to_fn_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/deref_fn_ptr.stderr b/tests/fail/function_pointers/deref_fn_ptr.stderr index ecd001964a1b..7ce0b08695eb 100644 --- a/tests/fail/function_pointers/deref_fn_ptr.stderr +++ b/tests/fail/function_pointers/deref_fn_ptr.stderr @@ -6,7 +6,7 @@ LL | *std::mem::transmute::(f) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/deref_fn_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/execute_memory.stderr b/tests/fail/function_pointers/execute_memory.stderr index b6438934b2b3..10c53ca2beae 100644 --- a/tests/fail/function_pointers/execute_memory.stderr +++ b/tests/fail/function_pointers/execute_memory.stderr @@ -6,7 +6,7 @@ LL | f() | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/execute_memory.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/fn_ptr_offset.stderr b/tests/fail/function_pointers/fn_ptr_offset.stderr index b5164d02ace1..f8c519c1b54b 100644 --- a/tests/fail/function_pointers/fn_ptr_offset.stderr +++ b/tests/fail/function_pointers/fn_ptr_offset.stderr @@ -6,7 +6,7 @@ LL | x(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/fn_ptr_offset.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/generator-pinned-moved.stderr b/tests/fail/generator-pinned-moved.stderr index f1fb366d0652..4f73671a7894 100644 --- a/tests/fail/generator-pinned-moved.stderr +++ b/tests/fail/generator-pinned-moved.stderr @@ -6,7 +6,7 @@ LL | *num += 1; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/generator-pinned-moved.rs:LL:CC note: inside ` as std::iter::Iterator>::next` at $DIR/generator-pinned-moved.rs:LL:CC --> $DIR/generator-pinned-moved.rs:LL:CC diff --git a/tests/fail/intrinsics/assume.stderr b/tests/fail/intrinsics/assume.stderr index 1664e7ad743f..17e4cc6698d4 100644 --- a/tests/fail/intrinsics/assume.stderr +++ b/tests/fail/intrinsics/assume.stderr @@ -6,7 +6,7 @@ LL | std::intrinsics::assume(x > 42); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/assume.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/copy_null.stderr b/tests/fail/intrinsics/copy_null.stderr index d7725064832e..6e3215d9f1c9 100644 --- a/tests/fail/intrinsics/copy_null.stderr +++ b/tests/fail/intrinsics/copy_null.stderr @@ -6,7 +6,7 @@ LL | copy_nonoverlapping(std::ptr::null(), ptr, 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/copy_null.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/copy_overflow.stderr b/tests/fail/intrinsics/copy_overflow.stderr index 3534f4d1fb85..23a4adbd0ed6 100644 --- a/tests/fail/intrinsics/copy_overflow.stderr +++ b/tests/fail/intrinsics/copy_overflow.stderr @@ -6,7 +6,7 @@ LL | (&mut y as *mut i32).copy_from(&x, 1usize << (mem::size_of:: | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/copy_overflow.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/copy_overlapping.stderr b/tests/fail/intrinsics/copy_overlapping.stderr index 9298a87712bb..cdb3da74ca95 100644 --- a/tests/fail/intrinsics/copy_overlapping.stderr +++ b/tests/fail/intrinsics/copy_overlapping.stderr @@ -6,7 +6,7 @@ LL | copy_nonoverlapping(a, b, 2); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/copy_overlapping.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/copy_unaligned.stderr b/tests/fail/intrinsics/copy_unaligned.stderr index 890c7b12e03d..a275979e6be1 100644 --- a/tests/fail/intrinsics/copy_unaligned.stderr +++ b/tests/fail/intrinsics/copy_unaligned.stderr @@ -6,7 +6,7 @@ LL | copy_nonoverlapping(&data[5], ptr, 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/copy_unaligned.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ctlz_nonzero.stderr b/tests/fail/intrinsics/ctlz_nonzero.stderr index 7d4d3dd8e1b8..5ae14472a8a6 100644 --- a/tests/fail/intrinsics/ctlz_nonzero.stderr +++ b/tests/fail/intrinsics/ctlz_nonzero.stderr @@ -6,7 +6,7 @@ LL | ctlz_nonzero(0u8); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/ctlz_nonzero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/cttz_nonzero.stderr b/tests/fail/intrinsics/cttz_nonzero.stderr index 284bfc1c4c99..ae013fb3d979 100644 --- a/tests/fail/intrinsics/cttz_nonzero.stderr +++ b/tests/fail/intrinsics/cttz_nonzero.stderr @@ -6,7 +6,7 @@ LL | cttz_nonzero(0u8); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/cttz_nonzero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/div-by-zero.stderr b/tests/fail/intrinsics/div-by-zero.stderr index 061123ddc1de..8c2910de3eef 100644 --- a/tests/fail/intrinsics/div-by-zero.stderr +++ b/tests/fail/intrinsics/div-by-zero.stderr @@ -6,7 +6,7 @@ LL | let _n = unchecked_div(1i64, 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/div-by-zero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/exact_div1.stderr b/tests/fail/intrinsics/exact_div1.stderr index 6564fad475de..2c7bbc00e1b1 100644 --- a/tests/fail/intrinsics/exact_div1.stderr +++ b/tests/fail/intrinsics/exact_div1.stderr @@ -6,7 +6,7 @@ LL | unsafe { std::intrinsics::exact_div(2, 0) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/exact_div1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/exact_div2.stderr b/tests/fail/intrinsics/exact_div2.stderr index 7e8e2ee18121..6a264b8b4476 100644 --- a/tests/fail/intrinsics/exact_div2.stderr +++ b/tests/fail/intrinsics/exact_div2.stderr @@ -6,7 +6,7 @@ LL | unsafe { std::intrinsics::exact_div(2u16, 3) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/exact_div2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/exact_div3.stderr b/tests/fail/intrinsics/exact_div3.stderr index 8b1f15794b7c..1a73822c300f 100644 --- a/tests/fail/intrinsics/exact_div3.stderr +++ b/tests/fail/intrinsics/exact_div3.stderr @@ -6,7 +6,7 @@ LL | unsafe { std::intrinsics::exact_div(-19i8, 2) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/exact_div3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/exact_div4.stderr b/tests/fail/intrinsics/exact_div4.stderr index 4da670bc846c..27201d9c7cf6 100644 --- a/tests/fail/intrinsics/exact_div4.stderr +++ b/tests/fail/intrinsics/exact_div4.stderr @@ -6,7 +6,7 @@ LL | unsafe { std::intrinsics::exact_div(i64::MIN, -1) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/exact_div4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_inf1.stderr b/tests/fail/intrinsics/float_to_int_32_inf1.stderr index 88cd4a7c184b..c82d6b30224f 100644 --- a/tests/fail/intrinsics/float_to_int_32_inf1.stderr +++ b/tests/fail/intrinsics/float_to_int_32_inf1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f32::INFINITY); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_32_inf1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_infneg1.stderr b/tests/fail/intrinsics/float_to_int_32_infneg1.stderr index a83300184048..4ca41b676e9c 100644 --- a/tests/fail/intrinsics/float_to_int_32_infneg1.stderr +++ b/tests/fail/intrinsics/float_to_int_32_infneg1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f32::NEG_INFINITY); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_32_infneg1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_nan.stderr b/tests/fail/intrinsics/float_to_int_32_nan.stderr index 9bf312a9ccbd..88b8948b0c29 100644 --- a/tests/fail/intrinsics/float_to_int_32_nan.stderr +++ b/tests/fail/intrinsics/float_to_int_32_nan.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f32::NAN); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_32_nan.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_nanneg.stderr b/tests/fail/intrinsics/float_to_int_32_nanneg.stderr index be105ccdaa71..ca798dd391aa 100644 --- a/tests/fail/intrinsics/float_to_int_32_nanneg.stderr +++ b/tests/fail/intrinsics/float_to_int_32_nanneg.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(-f32::NAN); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_32_nanneg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_neg.stderr b/tests/fail/intrinsics/float_to_int_32_neg.stderr index 6f926d442bb4..4ff6eb809854 100644 --- a/tests/fail/intrinsics/float_to_int_32_neg.stderr +++ b/tests/fail/intrinsics/float_to_int_32_neg.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(-1.000000001f32); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_32_neg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_too_big1.stderr b/tests/fail/intrinsics/float_to_int_32_too_big1.stderr index 880eb6f48a9b..fd17709d164b 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_big1.stderr +++ b/tests/fail/intrinsics/float_to_int_32_too_big1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(2147483648.0f32); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_32_too_big1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_too_big2.stderr b/tests/fail/intrinsics/float_to_int_32_too_big2.stderr index 9ee3e2feed2f..fdc1f65dc148 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_big2.stderr +++ b/tests/fail/intrinsics/float_to_int_32_too_big2.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::((u32::MAX - 127) as f32); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_32_too_big2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_too_small1.stderr b/tests/fail/intrinsics/float_to_int_32_too_small1.stderr index 0f23fc05fd72..9e743a321444 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_small1.stderr +++ b/tests/fail/intrinsics/float_to_int_32_too_small1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(-2147483904.0f32); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_32_too_small1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_inf1.stderr b/tests/fail/intrinsics/float_to_int_64_inf1.stderr index eb493f141cbd..ee01143dc8df 100644 --- a/tests/fail/intrinsics/float_to_int_64_inf1.stderr +++ b/tests/fail/intrinsics/float_to_int_64_inf1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f64::INFINITY); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_inf1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_infneg1.stderr b/tests/fail/intrinsics/float_to_int_64_infneg1.stderr index 5e499e271202..f37b8ae55064 100644 --- a/tests/fail/intrinsics/float_to_int_64_infneg1.stderr +++ b/tests/fail/intrinsics/float_to_int_64_infneg1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f64::NEG_INFINITY); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_infneg1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_infneg2.stderr b/tests/fail/intrinsics/float_to_int_64_infneg2.stderr index da22fa481727..05dcd5ebcf69 100644 --- a/tests/fail/intrinsics/float_to_int_64_infneg2.stderr +++ b/tests/fail/intrinsics/float_to_int_64_infneg2.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f64::NEG_INFINITY); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_infneg2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_nan.stderr b/tests/fail/intrinsics/float_to_int_64_nan.stderr index eff110ad724c..0a914abb2ce7 100644 --- a/tests/fail/intrinsics/float_to_int_64_nan.stderr +++ b/tests/fail/intrinsics/float_to_int_64_nan.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f64::NAN); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_nan.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_neg.stderr b/tests/fail/intrinsics/float_to_int_64_neg.stderr index 8d8851a9d7bf..7e24f45f653d 100644 --- a/tests/fail/intrinsics/float_to_int_64_neg.stderr +++ b/tests/fail/intrinsics/float_to_int_64_neg.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(-1.0000000000001f64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_neg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_big1.stderr b/tests/fail/intrinsics/float_to_int_64_too_big1.stderr index 53c999ccba92..42da33321f37 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big1.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(2147483648.0f64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_too_big1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_big2.stderr b/tests/fail/intrinsics/float_to_int_64_too_big2.stderr index 4f5927eed59a..af4c4ceb3f73 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big2.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big2.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(9223372036854775808.0f64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_too_big2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_big3.stderr b/tests/fail/intrinsics/float_to_int_64_too_big3.stderr index d439b8695efb..6e384a6fbc7c 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big3.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big3.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(18446744073709551616.0f64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_too_big3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_big4.stderr b/tests/fail/intrinsics/float_to_int_64_too_big4.stderr index 56677cd31554..77f05ff91e3b 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big4.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big4.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(u128::MAX as f64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_too_big4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_big5.stderr b/tests/fail/intrinsics/float_to_int_64_too_big5.stderr index ab5b2c954aec..cb5eba490b44 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big5.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big5.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(2402823669209384634633746074317 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_too_big5.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_big6.stderr b/tests/fail/intrinsics/float_to_int_64_too_big6.stderr index e64ab2262715..d899d2f808a5 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big6.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big6.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f64::MAX); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_too_big6.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_big7.stderr b/tests/fail/intrinsics/float_to_int_64_too_big7.stderr index e9809e3ba589..443b2759c260 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big7.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big7.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f64::MIN); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_too_big7.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_small1.stderr b/tests/fail/intrinsics/float_to_int_64_too_small1.stderr index 714205ca1beb..f8d88c44aa80 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small1.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_small1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(-2147483649.0f64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_too_small1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_small2.stderr b/tests/fail/intrinsics/float_to_int_64_too_small2.stderr index b2302bf905ac..d94e57b1e67c 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small2.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_small2.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(-9223372036854777856.0f64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_too_small2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_small3.stderr b/tests/fail/intrinsics/float_to_int_64_too_small3.stderr index bcff0fb63042..59b74f5f51f3 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small3.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_small3.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(-240282366920938463463374607431 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_too_small3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr b/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr index afa2c8306466..4422310870a6 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr +++ b/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr @@ -6,7 +6,7 @@ LL | let x = unsafe { x.offset(5) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/out_of_bounds_ptr_1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr b/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr index a32b50a18e6a..6a11ebae108f 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr +++ b/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr @@ -6,7 +6,7 @@ LL | let x = unsafe { x.offset(isize::MIN) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/out_of_bounds_ptr_2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr b/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr index d06c33beb48a..1364e0f9009d 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr +++ b/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr @@ -6,7 +6,7 @@ LL | let x = unsafe { x.offset(-1) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/out_of_bounds_ptr_3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/overflowing-unchecked-rsh.stderr b/tests/fail/intrinsics/overflowing-unchecked-rsh.stderr index bba92602285a..9c5d0d13108c 100644 --- a/tests/fail/intrinsics/overflowing-unchecked-rsh.stderr +++ b/tests/fail/intrinsics/overflowing-unchecked-rsh.stderr @@ -6,7 +6,7 @@ LL | let _n = 1i64.unchecked_shr(64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/overflowing-unchecked-rsh.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr b/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr index 40a5022351dd..9c1c387d5499 100644 --- a/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr +++ b/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr @@ -6,7 +6,7 @@ LL | let _x = unsafe { x.offset(0) }; // UB despite offset 0, NULL is never | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/ptr_offset_0_plus_0.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ptr_offset_from_oob.stderr b/tests/fail/intrinsics/ptr_offset_from_oob.stderr index 546245a499e1..a31b929d7a7a 100644 --- a/tests/fail/intrinsics/ptr_offset_from_oob.stderr +++ b/tests/fail/intrinsics/ptr_offset_from_oob.stderr @@ -6,7 +6,7 @@ LL | unsafe { end_ptr.offset_from(end_ptr) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/ptr_offset_from_oob.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr b/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr index 419b7497a2f9..803aaaa55c21 100644 --- a/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr +++ b/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { ptr1.sub_ptr(ptr2) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/ptr_offset_from_unsigned_neg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr b/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr index a96717a06707..f76881011d07 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr +++ b/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr @@ -6,7 +6,7 @@ LL | let _val = (1 as *mut u8).offset(1); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/ptr_offset_int_plus_int.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr index c1abe01dcea5..6e0744b7d5c3 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr +++ b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr @@ -6,7 +6,7 @@ LL | let _val = (1 as *mut u8).offset(ptr as isize); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/ptr_offset_int_plus_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ptr_offset_overflow.stderr b/tests/fail/intrinsics/ptr_offset_overflow.stderr index d5935006e43b..6fb94cf5f812 100644 --- a/tests/fail/intrinsics/ptr_offset_overflow.stderr +++ b/tests/fail/intrinsics/ptr_offset_overflow.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { x.offset(isize::MIN) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/ptr_offset_overflow.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr b/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr index 5c516d5a490f..b18147ce379d 100644 --- a/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr +++ b/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr @@ -6,7 +6,7 @@ LL | let _x = unsafe { x.offset(0) }; // UB despite offset 0, the pointer is | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/ptr_offset_ptr_plus_0.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/raw_eq_on_ptr.stderr b/tests/fail/intrinsics/raw_eq_on_ptr.stderr index 6c5e618315c8..c6ed1750c04e 100644 --- a/tests/fail/intrinsics/raw_eq_on_ptr.stderr +++ b/tests/fail/intrinsics/raw_eq_on_ptr.stderr @@ -5,7 +5,7 @@ LL | unsafe { raw_eq(&x, &x) }; | ^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/raw_eq_on_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/rem-by-zero.stderr b/tests/fail/intrinsics/rem-by-zero.stderr index 1da33d8eaf59..1fc39188e5a9 100644 --- a/tests/fail/intrinsics/rem-by-zero.stderr +++ b/tests/fail/intrinsics/rem-by-zero.stderr @@ -6,7 +6,7 @@ LL | let _n = unchecked_rem(3u32, 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/rem-by-zero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-div-by-zero.stderr b/tests/fail/intrinsics/simd-div-by-zero.stderr index 552749c48ea7..ddab24d0c163 100644 --- a/tests/fail/intrinsics/simd-div-by-zero.stderr +++ b/tests/fail/intrinsics/simd-div-by-zero.stderr @@ -6,7 +6,7 @@ LL | simd_div(x, y); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/simd-div-by-zero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-div-overflow.stderr b/tests/fail/intrinsics/simd-div-overflow.stderr index 98a3c1516270..27d4dd9e3e73 100644 --- a/tests/fail/intrinsics/simd-div-overflow.stderr +++ b/tests/fail/intrinsics/simd-div-overflow.stderr @@ -6,7 +6,7 @@ LL | simd_div(x, y); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/simd-div-overflow.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-float-to-int.stderr b/tests/fail/intrinsics/simd-float-to-int.stderr index d29b356d268d..36bb9643b48d 100644 --- a/tests/fail/intrinsics/simd-float-to-int.stderr +++ b/tests/fail/intrinsics/simd-float-to-int.stderr @@ -6,7 +6,7 @@ LL | unsafe { intrinsics::simd_cast(self) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::simd::Simd::::to_int_unchecked::` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC note: inside `main` at $DIR/simd-float-to-int.rs:LL:CC --> $DIR/simd-float-to-int.rs:LL:CC diff --git a/tests/fail/intrinsics/simd-gather.stderr b/tests/fail/intrinsics/simd-gather.stderr index a23307c05ffb..29a4ef65705a 100644 --- a/tests/fail/intrinsics/simd-gather.stderr +++ b/tests/fail/intrinsics/simd-gather.stderr @@ -6,7 +6,7 @@ LL | unsafe { intrinsics::simd_gather(or, ptrs, enable.to_int()) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::simd::Simd::::gather_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC note: inside `main` at $DIR/simd-gather.rs:LL:CC --> $DIR/simd-gather.rs:LL:CC diff --git a/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr b/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr index 5a44861feee1..1e5ac5277e6d 100644 --- a/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr +++ b/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr @@ -6,7 +6,7 @@ LL | simd_reduce_any(x); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/simd-reduce-invalid-bool.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-rem-by-zero.stderr b/tests/fail/intrinsics/simd-rem-by-zero.stderr index dd68d3aa1840..96248e7e599c 100644 --- a/tests/fail/intrinsics/simd-rem-by-zero.stderr +++ b/tests/fail/intrinsics/simd-rem-by-zero.stderr @@ -6,7 +6,7 @@ LL | simd_rem(x, y); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/simd-rem-by-zero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-scatter.stderr b/tests/fail/intrinsics/simd-scatter.stderr index ba8c8f347060..fde85a63503b 100644 --- a/tests/fail/intrinsics/simd-scatter.stderr +++ b/tests/fail/intrinsics/simd-scatter.stderr @@ -6,7 +6,7 @@ LL | intrinsics::simd_scatter(self, ptrs, enable.to_int()) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::simd::Simd::::scatter_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC note: inside `main` at $DIR/simd-scatter.rs:LL:CC --> $DIR/simd-scatter.rs:LL:CC diff --git a/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr b/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr index 7b3b3292ef78..e72cce998d0e 100644 --- a/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr +++ b/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr @@ -6,7 +6,7 @@ LL | simd_select_bitmask(0b11111111u8, x, x); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/simd-select-bitmask-invalid.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-select-invalid-bool.stderr b/tests/fail/intrinsics/simd-select-invalid-bool.stderr index ad5a89310681..277ceb54ec71 100644 --- a/tests/fail/intrinsics/simd-select-invalid-bool.stderr +++ b/tests/fail/intrinsics/simd-select-invalid-bool.stderr @@ -6,7 +6,7 @@ LL | simd_select(x, x, x); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/simd-select-invalid-bool.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-shl-too-far.stderr b/tests/fail/intrinsics/simd-shl-too-far.stderr index cea99f681932..c8445bb3cdc7 100644 --- a/tests/fail/intrinsics/simd-shl-too-far.stderr +++ b/tests/fail/intrinsics/simd-shl-too-far.stderr @@ -6,7 +6,7 @@ LL | simd_shl(x, y); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/simd-shl-too-far.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-shr-too-far.stderr b/tests/fail/intrinsics/simd-shr-too-far.stderr index df3288a805c8..8eec30c5a52f 100644 --- a/tests/fail/intrinsics/simd-shr-too-far.stderr +++ b/tests/fail/intrinsics/simd-shr-too-far.stderr @@ -6,7 +6,7 @@ LL | simd_shr(x, y); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/simd-shr-too-far.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_add1.stderr b/tests/fail/intrinsics/unchecked_add1.stderr index 062acbb8de8c..f5e96198ee4c 100644 --- a/tests/fail/intrinsics/unchecked_add1.stderr +++ b/tests/fail/intrinsics/unchecked_add1.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { 40000u16.unchecked_add(30000) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unchecked_add1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_add2.stderr b/tests/fail/intrinsics/unchecked_add2.stderr index 09b622d6e296..5a5c7070ae0b 100644 --- a/tests/fail/intrinsics/unchecked_add2.stderr +++ b/tests/fail/intrinsics/unchecked_add2.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { (-30000i16).unchecked_add(-8000) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unchecked_add2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_div1.stderr b/tests/fail/intrinsics/unchecked_div1.stderr index 867c8e0a9d39..9267e0c49473 100644 --- a/tests/fail/intrinsics/unchecked_div1.stderr +++ b/tests/fail/intrinsics/unchecked_div1.stderr @@ -6,7 +6,7 @@ LL | std::intrinsics::unchecked_div(i16::MIN, -1); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unchecked_div1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_mul1.stderr b/tests/fail/intrinsics/unchecked_mul1.stderr index e260c343c4e6..9a5a585e1cce 100644 --- a/tests/fail/intrinsics/unchecked_mul1.stderr +++ b/tests/fail/intrinsics/unchecked_mul1.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { 300u16.unchecked_mul(250u16) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unchecked_mul1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_mul2.stderr b/tests/fail/intrinsics/unchecked_mul2.stderr index 88b3a49b98ec..46b9f6182172 100644 --- a/tests/fail/intrinsics/unchecked_mul2.stderr +++ b/tests/fail/intrinsics/unchecked_mul2.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { 1_000_000_000i32.unchecked_mul(-4) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unchecked_mul2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_sub1.stderr b/tests/fail/intrinsics/unchecked_sub1.stderr index ebd7bc10eb41..01e569767bac 100644 --- a/tests/fail/intrinsics/unchecked_sub1.stderr +++ b/tests/fail/intrinsics/unchecked_sub1.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { 14u32.unchecked_sub(22) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unchecked_sub1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_sub2.stderr b/tests/fail/intrinsics/unchecked_sub2.stderr index 73d7c4d86bc0..38c1647b4f49 100644 --- a/tests/fail/intrinsics/unchecked_sub2.stderr +++ b/tests/fail/intrinsics/unchecked_sub2.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { 30000i16.unchecked_sub(-7000) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unchecked_sub2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/write_bytes_null.stderr b/tests/fail/intrinsics/write_bytes_null.stderr index 8fd866aa8b32..b2969ca3b592 100644 --- a/tests/fail/intrinsics/write_bytes_null.stderr +++ b/tests/fail/intrinsics/write_bytes_null.stderr @@ -6,7 +6,7 @@ LL | unsafe { write_bytes::(std::ptr::null_mut(), 0, 0) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/write_bytes_null.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/write_bytes_overflow.stderr b/tests/fail/intrinsics/write_bytes_overflow.stderr index 47610b062301..f88afde879ac 100644 --- a/tests/fail/intrinsics/write_bytes_overflow.stderr +++ b/tests/fail/intrinsics/write_bytes_overflow.stderr @@ -6,7 +6,7 @@ LL | (&mut y as *mut i32).write_bytes(0u8, 1usize << (mem::size_of::::uninit().assume_init() } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/invalid_int.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/issue-miri-1112.stderr b/tests/fail/issue-miri-1112.stderr index 4a2bdb0f414d..e6644a72849f 100644 --- a/tests/fail/issue-miri-1112.stderr +++ b/tests/fail/issue-miri-1112.stderr @@ -6,7 +6,7 @@ LL | let obj = std::mem::transmute::(obj) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `FunnyPointer::from_data_ptr` at $DIR/issue-miri-1112.rs:LL:CC note: inside `main` at $DIR/issue-miri-1112.rs:LL:CC --> $DIR/issue-miri-1112.rs:LL:CC diff --git a/tests/fail/issue-miri-2432.stderr b/tests/fail/issue-miri-2432.stderr index a5c9300fb07c..b8e13b61ceb6 100644 --- a/tests/fail/issue-miri-2432.stderr +++ b/tests/fail/issue-miri-2432.stderr @@ -6,7 +6,7 @@ LL | ::foo(&()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/issue-miri-2432.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/modifying_constants.stderr b/tests/fail/modifying_constants.stderr index 853e3a9015e7..6425a5d7a0ad 100644 --- a/tests/fail/modifying_constants.stderr +++ b/tests/fail/modifying_constants.stderr @@ -6,7 +6,7 @@ LL | *y = 42; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/modifying_constants.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/never_say_never.stderr b/tests/fail/never_say_never.stderr index 4072a0376f5c..a2a63b8baf59 100644 --- a/tests/fail/never_say_never.stderr +++ b/tests/fail/never_say_never.stderr @@ -6,7 +6,7 @@ LL | *(y as *const _ as *const !) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/never_say_never.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/never_transmute_humans.stderr b/tests/fail/never_transmute_humans.stderr index 2a8ee0a3e9bd..e8df4739f9bc 100644 --- a/tests/fail/never_transmute_humans.stderr +++ b/tests/fail/never_transmute_humans.stderr @@ -6,7 +6,7 @@ LL | std::mem::transmute::(Human) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/never_transmute_humans.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/never_transmute_void.stderr b/tests/fail/never_transmute_void.stderr index 31614ef3edf8..4c3a3d075f02 100644 --- a/tests/fail/never_transmute_void.stderr +++ b/tests/fail/never_transmute_void.stderr @@ -6,7 +6,7 @@ LL | match v.0 {} | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `m::f` at $DIR/never_transmute_void.rs:LL:CC note: inside `main` at $DIR/never_transmute_void.rs:LL:CC --> $DIR/never_transmute_void.rs:LL:CC diff --git a/tests/fail/panic/bad_miri_start_panic.stderr b/tests/fail/panic/bad_miri_start_panic.stderr index a664590e36ae..3bd2be03ea1f 100644 --- a/tests/fail/panic/bad_miri_start_panic.stderr +++ b/tests/fail/panic/bad_miri_start_panic.stderr @@ -6,7 +6,7 @@ LL | unsafe { miri_start_panic(&mut 0) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/bad_miri_start_panic.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/panic/bad_unwind.stderr b/tests/fail/panic/bad_unwind.stderr index be8a3668ac52..23c33f5e7f3f 100644 --- a/tests/fail/panic/bad_unwind.stderr +++ b/tests/fail/panic/bad_unwind.stderr @@ -8,7 +8,7 @@ LL | std::panic::catch_unwind(|| unwind()).unwrap_err(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/bad_unwind.rs:LL:CC = note: inside `std::panicking::r#try::do_call::<[closure@$DIR/bad_unwind.rs:LL:CC], ()>` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::panicking::r#try::<(), [closure@$DIR/bad_unwind.rs:LL:CC]>` at RUSTLIB/std/src/panicking.rs:LL:CC diff --git a/tests/fail/panic/unwind_panic_abort.stderr b/tests/fail/panic/unwind_panic_abort.stderr index df4b9522f467..363e69ba41db 100644 --- a/tests/fail/panic/unwind_panic_abort.stderr +++ b/tests/fail/panic/unwind_panic_abort.stderr @@ -6,7 +6,7 @@ LL | miri_start_panic(&mut 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unwind_panic_abort.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/pointer_partial_overwrite.stderr b/tests/fail/pointer_partial_overwrite.stderr index cd3c4ddd6ca4..7d10b75e8805 100644 --- a/tests/fail/pointer_partial_overwrite.stderr +++ b/tests/fail/pointer_partial_overwrite.stderr @@ -6,7 +6,7 @@ LL | let x = *p; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/pointer_partial_overwrite.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/provenance/provenance_transmute.stderr b/tests/fail/provenance/provenance_transmute.stderr index 5b7e9442d7c0..f7c5f6046e19 100644 --- a/tests/fail/provenance/provenance_transmute.stderr +++ b/tests/fail/provenance/provenance_transmute.stderr @@ -6,7 +6,7 @@ LL | let _val = *left_ptr; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `deref` at $DIR/provenance_transmute.rs:LL:CC note: inside `main` at $DIR/provenance_transmute.rs:LL:CC --> $DIR/provenance_transmute.rs:LL:CC diff --git a/tests/fail/provenance/ptr_int_unexposed.stderr b/tests/fail/provenance/ptr_int_unexposed.stderr index f5ea7718c78a..4ad885ddabdc 100644 --- a/tests/fail/provenance/ptr_int_unexposed.stderr +++ b/tests/fail/provenance/ptr_int_unexposed.stderr @@ -6,7 +6,7 @@ LL | assert_eq!(unsafe { *ptr }, 3); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/ptr_int_unexposed.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/provenance/ptr_invalid.stderr b/tests/fail/provenance/ptr_invalid.stderr index 02bfef3ae73f..ef9dcad97cbd 100644 --- a/tests/fail/provenance/ptr_invalid.stderr +++ b/tests/fail/provenance/ptr_invalid.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { *xptr_invalid }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/ptr_invalid.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/provenance/ptr_invalid_offset.stderr b/tests/fail/provenance/ptr_invalid_offset.stderr index 813a6515b771..3607635c8fbe 100644 --- a/tests/fail/provenance/ptr_invalid_offset.stderr +++ b/tests/fail/provenance/ptr_invalid_offset.stderr @@ -6,7 +6,7 @@ LL | let _ = unsafe { roundtrip.offset(1) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/ptr_invalid_offset.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/provenance/strict_provenance_cast.stderr b/tests/fail/provenance/strict_provenance_cast.stderr index 5796a3196dc6..998ccc8bb49c 100644 --- a/tests/fail/provenance/strict_provenance_cast.stderr +++ b/tests/fail/provenance/strict_provenance_cast.stderr @@ -5,7 +5,7 @@ LL | let _ptr = std::ptr::from_exposed_addr::(addr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance` | = help: use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/strict_provenance_cast.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/rc_as_ptr.stderr b/tests/fail/rc_as_ptr.stderr index f2dd245be345..70bdd157bdc3 100644 --- a/tests/fail/rc_as_ptr.stderr +++ b/tests/fail/rc_as_ptr.stderr @@ -6,7 +6,7 @@ LL | assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at RUSTLIB/core/src/macros/mod.rs:LL:CC = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/fail/reading_half_a_pointer.stderr b/tests/fail/reading_half_a_pointer.stderr index d6690f0c7a01..28cd7cef2433 100644 --- a/tests/fail/reading_half_a_pointer.stderr +++ b/tests/fail/reading_half_a_pointer.stderr @@ -5,7 +5,7 @@ LL | let _x = *d_alias; | ^^^^^^^^ unable to turn pointer into raw bytes | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/reading_half_a_pointer.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/backtrace/bad-backtrace-decl.stderr b/tests/fail/shims/backtrace/bad-backtrace-decl.stderr index 3cb4a8e8a458..200f5f56213d 100644 --- a/tests/fail/shims/backtrace/bad-backtrace-decl.stderr +++ b/tests/fail/shims/backtrace/bad-backtrace-decl.stderr @@ -6,7 +6,7 @@ LL | ... miri_resolve_frame(*frame, 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/bad-backtrace-decl.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/backtrace/bad-backtrace-flags.stderr b/tests/fail/shims/backtrace/bad-backtrace-flags.stderr index f186fb1e5717..5d51790f8a5c 100644 --- a/tests/fail/shims/backtrace/bad-backtrace-flags.stderr +++ b/tests/fail/shims/backtrace/bad-backtrace-flags.stderr @@ -5,7 +5,7 @@ LL | miri_get_backtrace(2, std::ptr::null_mut()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_get_backtrace` flags 2 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/bad-backtrace-flags.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr b/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr index 72755afb34a7..f23f834000aa 100644 --- a/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr +++ b/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr @@ -6,7 +6,7 @@ LL | miri_resolve_frame(std::ptr::null_mut(), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/bad-backtrace-ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/backtrace/bad-backtrace-resolve-flags.stderr b/tests/fail/shims/backtrace/bad-backtrace-resolve-flags.stderr index cf80488de22d..fe123c2352f0 100644 --- a/tests/fail/shims/backtrace/bad-backtrace-resolve-flags.stderr +++ b/tests/fail/shims/backtrace/bad-backtrace-resolve-flags.stderr @@ -5,7 +5,7 @@ LL | miri_resolve_frame(buf[0], 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_resolve_frame` flags 2 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/bad-backtrace-resolve-flags.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/backtrace/bad-backtrace-resolve-names-flags.stderr b/tests/fail/shims/backtrace/bad-backtrace-resolve-names-flags.stderr index c7e0d41009ad..a3003c9093f7 100644 --- a/tests/fail/shims/backtrace/bad-backtrace-resolve-names-flags.stderr +++ b/tests/fail/shims/backtrace/bad-backtrace-resolve-names-flags.stderr @@ -5,7 +5,7 @@ LL | ... miri_resolve_frame_names(buf[0], 2, std::ptr::null_mut(), std::ptr::n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_resolve_frame_names` flags 2 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/bad-backtrace-resolve-names-flags.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/backtrace/bad-backtrace-size-flags.stderr b/tests/fail/shims/backtrace/bad-backtrace-size-flags.stderr index 0cfe5d7173ce..b4a02c0e363e 100644 --- a/tests/fail/shims/backtrace/bad-backtrace-size-flags.stderr +++ b/tests/fail/shims/backtrace/bad-backtrace-size-flags.stderr @@ -5,7 +5,7 @@ LL | miri_backtrace_size(2); | ^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_backtrace_size` flags 2 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/bad-backtrace-size-flags.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/fs/close_stdout.stderr b/tests/fail/shims/fs/close_stdout.stderr index eb2c54e05f1f..02f1eee97fc0 100644 --- a/tests/fail/shims/fs/close_stdout.stderr +++ b/tests/fail/shims/fs/close_stdout.stderr @@ -5,7 +5,7 @@ LL | libc::close(1); | ^^^^^^^^^^^^^^ cannot close stdout | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/close_stdout.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/fs/isolated_file.stderr b/tests/fail/shims/fs/isolated_file.stderr index e75d7b7c3d93..4e3fdc7a4580 100644 --- a/tests/fail/shims/fs/isolated_file.stderr +++ b/tests/fail/shims/fs/isolated_file.stderr @@ -6,7 +6,7 @@ LL | let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode a | = help: pass the flag `-Zmiri-disable-isolation` to disable isolation; = help: or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning - = note: backtrace: + = note: BACKTRACE: = note: inside closure at RUSTLIB/std/src/sys/PLATFORM/fs.rs:LL:CC = note: inside `std::sys::PLATFORM::cvt_r::` at RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC = note: inside `std::sys::PLATFORM::fs::File::open_c` at RUSTLIB/std/src/sys/PLATFORM/fs.rs:LL:CC diff --git a/tests/fail/shims/fs/isolated_stdin.stderr b/tests/fail/shims/fs/isolated_stdin.stderr index fe9700f07b39..ed826147e3bd 100644 --- a/tests/fail/shims/fs/isolated_stdin.stderr +++ b/tests/fail/shims/fs/isolated_stdin.stderr @@ -6,7 +6,7 @@ LL | libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512); | = help: pass the flag `-Zmiri-disable-isolation` to disable isolation; = help: or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/isolated_stdin.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/fs/mkstemp_immutable_arg.stderr b/tests/fail/shims/fs/mkstemp_immutable_arg.stderr index 0bd91f90a10f..414ac1cb1b70 100644 --- a/tests/fail/shims/fs/mkstemp_immutable_arg.stderr +++ b/tests/fail/shims/fs/mkstemp_immutable_arg.stderr @@ -6,7 +6,7 @@ LL | let _fd = unsafe { libc::mkstemp(s) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `test_mkstemp_immutable_arg` at $DIR/mkstemp_immutable_arg.rs:LL:CC note: inside `main` at $DIR/mkstemp_immutable_arg.rs:LL:CC --> $DIR/mkstemp_immutable_arg.rs:LL:CC diff --git a/tests/fail/shims/fs/read_from_stdout.stderr b/tests/fail/shims/fs/read_from_stdout.stderr index 5c16999cbf79..bcece7ad4e55 100644 --- a/tests/fail/shims/fs/read_from_stdout.stderr +++ b/tests/fail/shims/fs/read_from_stdout.stderr @@ -5,7 +5,7 @@ LL | libc::read(1, bytes.as_mut_ptr() as *mut libc::c_void, 512); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot read from stdout | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/read_from_stdout.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/fs/unix_open_missing_required_mode.stderr b/tests/fail/shims/fs/unix_open_missing_required_mode.stderr index a7297efaff96..38d033b49455 100644 --- a/tests/fail/shims/fs/unix_open_missing_required_mode.stderr +++ b/tests/fail/shims/fs/unix_open_missing_required_mode.stderr @@ -6,7 +6,7 @@ LL | ...safe { libc::open(name_ptr, libc::O_CREAT) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `test_file_open_missing_needed_mode` at $DIR/unix_open_missing_required_mode.rs:LL:CC note: inside `main` at $DIR/unix_open_missing_required_mode.rs:LL:CC --> $DIR/unix_open_missing_required_mode.rs:LL:CC diff --git a/tests/fail/shims/fs/write_to_stdin.stderr b/tests/fail/shims/fs/write_to_stdin.stderr index 518d36b5551b..d4a38e1ca961 100644 --- a/tests/fail/shims/fs/write_to_stdin.stderr +++ b/tests/fail/shims/fs/write_to_stdin.stderr @@ -5,7 +5,7 @@ LL | libc::write(0, bytes.as_ptr() as *const libc::c_void, 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot write to stdin | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/write_to_stdin.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/shim_arg_size.64bit.stderr b/tests/fail/shims/shim_arg_size.64bit.stderr index 98ed99d6d729..0e8b402ac714 100644 --- a/tests/fail/shims/shim_arg_size.64bit.stderr +++ b/tests/fail/shims/shim_arg_size.64bit.stderr @@ -6,7 +6,7 @@ LL | let _p1 = malloc(42); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/shim_arg_size.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_cond_double_destroy.stderr b/tests/fail/shims/sync/libc_pthread_cond_double_destroy.stderr index 0e1c776f5965..ecfedf753703 100644 --- a/tests/fail/shims/sync/libc_pthread_cond_double_destroy.stderr +++ b/tests/fail/shims/sync/libc_pthread_cond_double_destroy.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_cond_destroy(cond.as_mut_ptr()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/libc_pthread_cond_double_destroy.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_condattr_double_destroy.stderr b/tests/fail/shims/sync/libc_pthread_condattr_double_destroy.stderr index dee50249b6b6..f39d909adbd6 100644 --- a/tests/fail/shims/sync/libc_pthread_condattr_double_destroy.stderr +++ b/tests/fail/shims/sync/libc_pthread_condattr_double_destroy.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_condattr_destroy(attr.as_mut_ptr()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/libc_pthread_condattr_double_destroy.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_mutex_NULL_deadlock.stderr b/tests/fail/shims/sync/libc_pthread_mutex_NULL_deadlock.stderr index 1b40f39d04bc..4a138e6f8a25 100644 --- a/tests/fail/shims/sync/libc_pthread_mutex_NULL_deadlock.stderr +++ b/tests/fail/shims/sync/libc_pthread_mutex_NULL_deadlock.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_mutex_lock(&mut mutex as *mut _); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/libc_pthread_mutex_NULL_deadlock.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_mutex_default_deadlock.stderr b/tests/fail/shims/sync/libc_pthread_mutex_default_deadlock.stderr index 7606472beb97..8aea3f5c6932 100644 --- a/tests/fail/shims/sync/libc_pthread_mutex_default_deadlock.stderr +++ b/tests/fail/shims/sync/libc_pthread_mutex_default_deadlock.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_mutex_lock(&mut mutex as *mut _); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/libc_pthread_mutex_default_deadlock.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_mutex_destroy_locked.stderr b/tests/fail/shims/sync/libc_pthread_mutex_destroy_locked.stderr index 40a7b3de09d5..a8ab948116e1 100644 --- a/tests/fail/shims/sync/libc_pthread_mutex_destroy_locked.stderr +++ b/tests/fail/shims/sync/libc_pthread_mutex_destroy_locked.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_mutex_destroy(&mut mutex as *mut _); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/libc_pthread_mutex_destroy_locked.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_mutex_double_destroy.stderr b/tests/fail/shims/sync/libc_pthread_mutex_double_destroy.stderr index 274d4496266b..9620fdbd18b2 100644 --- a/tests/fail/shims/sync/libc_pthread_mutex_double_destroy.stderr +++ b/tests/fail/shims/sync/libc_pthread_mutex_double_destroy.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_mutex_destroy(mutex.as_mut_ptr()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/libc_pthread_mutex_double_destroy.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr b/tests/fail/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr index daa9a7c51448..754137b85b9a 100644 --- a/tests/fail/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr +++ b/tests/fail/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_mutex_unlock(&mut mutex as *mut _); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/libc_pthread_mutex_normal_unlock_unlocked.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_mutex_wrong_owner.stderr b/tests/fail/shims/sync/libc_pthread_mutex_wrong_owner.stderr index 83c22b2673d6..aa81b06fc80a 100644 --- a/tests/fail/shims/sync/libc_pthread_mutex_wrong_owner.stderr +++ b/tests/fail/shims/sync/libc_pthread_mutex_wrong_owner.stderr @@ -6,7 +6,7 @@ LL | ...t_eq!(libc::pthread_mutex_unlock(lock_copy.0.get() as *mut _), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/libc_pthread_mutex_wrong_owner.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_mutexattr_double_destroy.stderr b/tests/fail/shims/sync/libc_pthread_mutexattr_double_destroy.stderr index 44a201fe0583..82949047d2aa 100644 --- a/tests/fail/shims/sync/libc_pthread_mutexattr_double_destroy.stderr +++ b/tests/fail/shims/sync/libc_pthread_mutexattr_double_destroy.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/libc_pthread_mutexattr_double_destroy.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_destroy_read_locked.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_destroy_read_locked.stderr index 43f8b2dcca6f..be73e7f1e2ad 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_destroy_read_locked.stderr +++ b/tests/fail/shims/sync/libc_pthread_rwlock_destroy_read_locked.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_rwlock_destroy(rw.get()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/libc_pthread_rwlock_destroy_read_locked.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_destroy_write_locked.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_destroy_write_locked.stderr index cbaa2b3fcce9..bc2713a5ffbf 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_destroy_write_locked.stderr +++ b/tests/fail/shims/sync/libc_pthread_rwlock_destroy_write_locked.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_rwlock_destroy(rw.get()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/libc_pthread_rwlock_destroy_write_locked.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_double_destroy.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_double_destroy.stderr index 159e1b9881a9..5004f84358da 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_double_destroy.stderr +++ b/tests/fail/shims/sync/libc_pthread_rwlock_double_destroy.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_rwlock_destroy(&mut lock); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/libc_pthread_rwlock_double_destroy.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_read_wrong_owner.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_read_wrong_owner.stderr index 0921f3d4b506..7dfa27b43d07 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_read_wrong_owner.stderr +++ b/tests/fail/shims/sync/libc_pthread_rwlock_read_wrong_owner.stderr @@ -6,7 +6,7 @@ LL | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/libc_pthread_rwlock_read_wrong_owner.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_unlock_unlocked.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_unlock_unlocked.stderr index 67bfde22edcf..1c25ac2c048f 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_unlock_unlocked.stderr +++ b/tests/fail/shims/sync/libc_pthread_rwlock_unlock_unlocked.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_rwlock_unlock(rw.get()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/libc_pthread_rwlock_unlock_unlocked.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_write_wrong_owner.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_write_wrong_owner.stderr index d066cb687a1a..5bf402c775ae 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_write_wrong_owner.stderr +++ b/tests/fail/shims/sync/libc_pthread_rwlock_write_wrong_owner.stderr @@ -6,7 +6,7 @@ LL | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/libc_pthread_rwlock_write_wrong_owner.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/should-pass/cpp20_rwc_syncs.stderr b/tests/fail/should-pass/cpp20_rwc_syncs.stderr index 17573a33b3d7..8a24b085a99f 100644 --- a/tests/fail/should-pass/cpp20_rwc_syncs.stderr +++ b/tests/fail/should-pass/cpp20_rwc_syncs.stderr @@ -6,7 +6,7 @@ LL | std::hint::unreachable_unchecked(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `test_cpp20_rwc_syncs` at $DIR/cpp20_rwc_syncs.rs:LL:CC note: inside `main` at $DIR/cpp20_rwc_syncs.rs:LL:CC --> $DIR/cpp20_rwc_syncs.rs:LL:CC diff --git a/tests/fail/stacked_borrows/alias_through_mutation.stderr b/tests/fail/stacked_borrows/alias_through_mutation.stderr index 74d1e4ebbcb8..461275c3fa34 100644 --- a/tests/fail/stacked_borrows/alias_through_mutation.stderr +++ b/tests/fail/stacked_borrows/alias_through_mutation.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | *target = 13; | ^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/alias_through_mutation.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/aliasing_mut1.stderr b/tests/fail/stacked_borrows/aliasing_mut1.stderr index 514b1a9901e6..5d4679b13ad1 100644 --- a/tests/fail/stacked_borrows/aliasing_mut1.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut1.stderr @@ -16,7 +16,7 @@ help: is this argument | LL | pub fn safe(_x: &mut i32, _y: &mut i32) {} | ^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `safe` at $DIR/aliasing_mut1.rs:LL:CC note: inside `main` at $DIR/aliasing_mut1.rs:LL:CC --> $DIR/aliasing_mut1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/aliasing_mut2.stderr b/tests/fail/stacked_borrows/aliasing_mut2.stderr index 5fc56a91f577..c8408c150e77 100644 --- a/tests/fail/stacked_borrows/aliasing_mut2.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut2.stderr @@ -16,7 +16,7 @@ help: is this argument | LL | pub fn safe(_x: &i32, _y: &mut i32) {} | ^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `safe` at $DIR/aliasing_mut2.rs:LL:CC note: inside `main` at $DIR/aliasing_mut2.rs:LL:CC --> $DIR/aliasing_mut2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/aliasing_mut3.stderr b/tests/fail/stacked_borrows/aliasing_mut3.stderr index ee38ea417003..c2ea90f242a2 100644 --- a/tests/fail/stacked_borrows/aliasing_mut3.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut3.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a Unique FnEntry reta | LL | safe_raw(xraw, xshr); | ^^^^^^^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `safe` at $DIR/aliasing_mut3.rs:LL:CC note: inside `main` at $DIR/aliasing_mut3.rs:LL:CC --> $DIR/aliasing_mut3.rs:LL:CC diff --git a/tests/fail/stacked_borrows/aliasing_mut4.stderr b/tests/fail/stacked_borrows/aliasing_mut4.stderr index d5c2e7366967..c53fe70f6dd3 100644 --- a/tests/fail/stacked_borrows/aliasing_mut4.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut4.stderr @@ -16,7 +16,7 @@ help: is this argument | LL | pub fn safe(_x: &i32, _y: &mut Cell) {} | ^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `safe` at $DIR/aliasing_mut4.rs:LL:CC note: inside `main` at $DIR/aliasing_mut4.rs:LL:CC --> $DIR/aliasing_mut4.rs:LL:CC diff --git a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr index dfe49d7f0892..d82b8342f123 100644 --- a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr +++ b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | *our = 5; | ^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `unknown_code_2` at $DIR/box_exclusive_violation1.rs:LL:CC note: inside `demo_box_advanced_unique` at $DIR/box_exclusive_violation1.rs:LL:CC --> $DIR/box_exclusive_violation1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr b/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr index c0fc247cd4a2..6aa14361287e 100644 --- a/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr +++ b/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0xc] by a Unique retag | LL | unsafe { from_raw_parts_mut(self_.as_ptr() as *mut T, self_.len()) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/buggy_as_mut_slice.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/buggy_split_at_mut.stderr b/tests/fail/stacked_borrows/buggy_split_at_mut.stderr index b4c5140882f3..cdeccc0855a9 100644 --- a/tests/fail/stacked_borrows/buggy_split_at_mut.stderr +++ b/tests/fail/stacked_borrows/buggy_split_at_mut.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x10] by a Unique retag | LL | from_raw_parts_mut(ptr.offset(mid as isize), len - mid), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/buggy_split_at_mut.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/deallocate_against_protector1.stderr b/tests/fail/stacked_borrows/deallocate_against_protector1.stderr index 2ead0c6a9dda..a5db4a00c69e 100644 --- a/tests/fail/stacked_borrows/deallocate_against_protector1.stderr +++ b/tests/fail/stacked_borrows/deallocate_against_protector1.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `alloc::alloc::box_free::` at RUSTLIB/alloc/src/alloc.rs:LL:CC diff --git a/tests/fail/stacked_borrows/deallocate_against_protector2.stderr b/tests/fail/stacked_borrows/deallocate_against_protector2.stderr index 60be936bd7e4..99c6ee6eb074 100644 --- a/tests/fail/stacked_borrows/deallocate_against_protector2.stderr +++ b/tests/fail/stacked_borrows/deallocate_against_protector2.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `alloc::alloc::box_free::` at RUSTLIB/alloc/src/alloc.rs:LL:CC diff --git a/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr b/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr index a959bb90fbb7..e05f44fac9d2 100644 --- a/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr +++ b/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | *base = 1; | ^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/disable_mut_does_not_merge_srw.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/exposed_only_ro.stderr b/tests/fail/stacked_borrows/exposed_only_ro.stderr index af76183fb25d..cb5e7bffde48 100644 --- a/tests/fail/stacked_borrows/exposed_only_ro.stderr +++ b/tests/fail/stacked_borrows/exposed_only_ro.stderr @@ -9,7 +9,7 @@ LL | unsafe { *ptr = 0 }; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/exposed_only_ro.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/fnentry_invalidation.stderr b/tests/fail/stacked_borrows/fnentry_invalidation.stderr index a66fd3200347..653ceca85885 100644 --- a/tests/fail/stacked_borrows/fnentry_invalidation.stderr +++ b/tests/fail/stacked_borrows/fnentry_invalidation.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a Unique FnEntry reta | LL | x.do_bad(); | ^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/fnentry_invalidation.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read1.stderr b/tests/fail/stacked_borrows/illegal_read1.stderr index 6e9d491137c8..95ff05d70c30 100644 --- a/tests/fail/stacked_borrows/illegal_read1.stderr +++ b/tests/fail/stacked_borrows/illegal_read1.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a read access | LL | let _val = unsafe { *xraw }; | ^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_read1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read2.stderr b/tests/fail/stacked_borrows/illegal_read2.stderr index fb1f9ec6a884..5cfdf77dee40 100644 --- a/tests/fail/stacked_borrows/illegal_read2.stderr +++ b/tests/fail/stacked_borrows/illegal_read2.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a SharedReadOnly reta | LL | let shr = unsafe { &*xraw }; | ^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_read2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read3.stderr b/tests/fail/stacked_borrows/illegal_read3.stderr index 55ab8877999c..dacf71fa3ee3 100644 --- a/tests/fail/stacked_borrows/illegal_read3.stderr +++ b/tests/fail/stacked_borrows/illegal_read3.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a read access | LL | let _val = unsafe { *xref1.r }; | ^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_read3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read4.stderr b/tests/fail/stacked_borrows/illegal_read4.stderr index 3bb064e2f416..5ce0cba61791 100644 --- a/tests/fail/stacked_borrows/illegal_read4.stderr +++ b/tests/fail/stacked_borrows/illegal_read4.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a read access | LL | let _val = unsafe { *xraw }; // use the raw again, this invalidates xref2 *even* with the special read except for uniq refs | ^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_read4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read5.stderr b/tests/fail/stacked_borrows/illegal_read5.stderr index e060463cf1d3..63532f87944e 100644 --- a/tests/fail/stacked_borrows/illegal_read5.stderr +++ b/tests/fail/stacked_borrows/illegal_read5.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [$HEX..$HEX] by a read access | LL | mem::forget(unsafe { ptr::read(xshr) }); // but after reading through the shared ref | ^^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_read5.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read6.stderr b/tests/fail/stacked_borrows/illegal_read6.stderr index 8ef720925646..93a96ab601ea 100644 --- a/tests/fail/stacked_borrows/illegal_read6.stderr +++ b/tests/fail/stacked_borrows/illegal_read6.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a Unique retag | LL | let x = &mut *x; // kill `raw` | ^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_read6.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read7.stderr b/tests/fail/stacked_borrows/illegal_read7.stderr index 5c42b0a5863c..2e8ac207beaf 100644 --- a/tests/fail/stacked_borrows/illegal_read7.stderr +++ b/tests/fail/stacked_borrows/illegal_read7.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a read access | LL | let _val = ptr::read(raw); | ^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_read7.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read8.stderr b/tests/fail/stacked_borrows/illegal_read8.stderr index c962d1c3e403..c34fa2d8955d 100644 --- a/tests/fail/stacked_borrows/illegal_read8.stderr +++ b/tests/fail/stacked_borrows/illegal_read8.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | *y2 += 1; | ^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_read8.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr b/tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr index 4607a9dbf675..43b4ec2ba652 100644 --- a/tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr +++ b/tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | *exposed_ptr = 0; | ^^^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_read_despite_exposed1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr b/tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr index 4bf0df7d0625..832320fc202e 100644 --- a/tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr +++ b/tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a read access | LL | let _val = *exposed_ptr; | ^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_read_despite_exposed2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write1.stderr b/tests/fail/stacked_borrows/illegal_write1.stderr index 55ba9aab9bf4..3bf27f4815e9 100644 --- a/tests/fail/stacked_borrows/illegal_write1.stderr +++ b/tests/fail/stacked_borrows/illegal_write1.stderr @@ -14,7 +14,7 @@ help: was created by a SharedReadOnly retag at offsets [0x0..0x4] | LL | let x: *mut u32 = xref as *const _ as *mut _; | ^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_write1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write2.stderr b/tests/fail/stacked_borrows/illegal_write2.stderr index ceb4ce040b89..a9fe8cb6ccc0 100644 --- a/tests/fail/stacked_borrows/illegal_write2.stderr +++ b/tests/fail/stacked_borrows/illegal_write2.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a Unique retag | LL | drop(&mut *target); // reborrow | ^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_write2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write3.stderr b/tests/fail/stacked_borrows/illegal_write3.stderr index e091e25190bb..d64f2ddd8767 100644 --- a/tests/fail/stacked_borrows/illegal_write3.stderr +++ b/tests/fail/stacked_borrows/illegal_write3.stderr @@ -14,7 +14,7 @@ help: was created by a SharedReadOnly retag at offsets [0x0..0x4] | LL | let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag | ^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_write3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write4.stderr b/tests/fail/stacked_borrows/illegal_write4.stderr index d66585ff7f14..e3b8621eb74f 100644 --- a/tests/fail/stacked_borrows/illegal_write4.stderr +++ b/tests/fail/stacked_borrows/illegal_write4.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a Unique retag | LL | let _mut_ref: &mut i32 = unsafe { mem::transmute(raw) }; // &mut, with raw tag | ^^^^^^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_write4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write5.stderr b/tests/fail/stacked_borrows/illegal_write5.stderr index 319c2d77062c..bbeb81258bde 100644 --- a/tests/fail/stacked_borrows/illegal_write5.stderr +++ b/tests/fail/stacked_borrows/illegal_write5.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | unsafe { *xraw = 15 }; | ^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_write5.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write6.stderr b/tests/fail/stacked_borrows/illegal_write6.stderr index 56e4bd79d477..331faa89f860 100644 --- a/tests/fail/stacked_borrows/illegal_write6.stderr +++ b/tests/fail/stacked_borrows/illegal_write6.stderr @@ -16,7 +16,7 @@ help: is this argument | LL | fn foo(a: &mut u32, y: *mut u32) -> u32 { | ^ - = note: backtrace: + = note: BACKTRACE: = note: inside `foo` at $DIR/illegal_write6.rs:LL:CC note: inside `main` at $DIR/illegal_write6.rs:LL:CC --> $DIR/illegal_write6.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr b/tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr index aa436b544126..87ddf61d7586 100644 --- a/tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr +++ b/tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | *exposed_ptr = 0; | ^^^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_write_despite_exposed1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/interior_mut1.stderr b/tests/fail/stacked_borrows/interior_mut1.stderr index 3aaca3892a54..1d68727c82af 100644 --- a/tests/fail/stacked_borrows/interior_mut1.stderr +++ b/tests/fail/stacked_borrows/interior_mut1.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | *c.get() = UnsafeCell::new(1); // invalidates inner_shr | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/interior_mut1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/interior_mut2.stderr b/tests/fail/stacked_borrows/interior_mut2.stderr index b0141cc34fb6..8a3357142261 100644 --- a/tests/fail/stacked_borrows/interior_mut2.stderr +++ b/tests/fail/stacked_borrows/interior_mut2.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | *c.get() = UnsafeCell::new(0); // now inner_shr gets invalidated | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/interior_mut2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/invalidate_against_protector1.stderr b/tests/fail/stacked_borrows/invalidate_against_protector1.stderr index 5e6fd6e02757..f87bd2319abd 100644 --- a/tests/fail/stacked_borrows/invalidate_against_protector1.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_protector1.stderr @@ -16,7 +16,7 @@ help: is this argument | LL | fn inner(x: *mut i32, _y: &mut i32) { | ^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `inner` at $DIR/invalidate_against_protector1.rs:LL:CC note: inside `main` at $DIR/invalidate_against_protector1.rs:LL:CC --> $DIR/invalidate_against_protector1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/invalidate_against_protector2.stderr b/tests/fail/stacked_borrows/invalidate_against_protector2.stderr index eab55d2568de..07c51a39b825 100644 --- a/tests/fail/stacked_borrows/invalidate_against_protector2.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_protector2.stderr @@ -16,7 +16,7 @@ help: is this argument | LL | fn inner(x: *mut i32, _y: &i32) { | ^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `inner` at $DIR/invalidate_against_protector2.rs:LL:CC note: inside `main` at $DIR/invalidate_against_protector2.rs:LL:CC --> $DIR/invalidate_against_protector2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/issue-miri-1050-1.stderr b/tests/fail/stacked_borrows/issue-miri-1050-1.stderr index 4d8488fa7684..16c8810a8e6d 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-1.stderr +++ b/tests/fail/stacked_borrows/issue-miri-1050-1.stderr @@ -6,7 +6,7 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC note: inside `main` at $DIR/issue-miri-1050-1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/issue-miri-1050-2.stderr b/tests/fail/stacked_borrows/issue-miri-1050-2.stderr index 562a82fb610b..d57e7662e504 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-2.stderr +++ b/tests/fail/stacked_borrows/issue-miri-1050-2.stderr @@ -6,7 +6,7 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC note: inside `main` at $DIR/issue-miri-1050-2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/load_invalid_mut.stderr b/tests/fail/stacked_borrows/load_invalid_mut.stderr index 43b6ce8d895e..08dc171c9eef 100644 --- a/tests/fail/stacked_borrows/load_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/load_invalid_mut.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a read access | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/load_invalid_mut.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/load_invalid_shr.stderr b/tests/fail/stacked_borrows/load_invalid_shr.stderr index 2177ebdd7021..50bbed2b295c 100644 --- a/tests/fail/stacked_borrows/load_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/load_invalid_shr.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | unsafe { *xraw = 42 }; // unfreeze | ^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/load_invalid_shr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr b/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr index 42f872eac62f..1c7f8e12d3d7 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr +++ b/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | *our = 5; | ^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `unknown_code_2` at $DIR/mut_exclusive_violation1.rs:LL:CC note: inside `demo_mut_advanced_unique` at $DIR/mut_exclusive_violation1.rs:LL:CC --> $DIR/mut_exclusive_violation1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr b/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr index 1952172d927b..43b5325fc541 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr +++ b/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a Unique retag | LL | let _raw2 = ptr2.as_mut(); | ^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/mut_exclusive_violation2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/newtype_retagging.stderr b/tests/fail/stacked_borrows/newtype_retagging.stderr index 7073c8162d16..06a9b86c6f45 100644 --- a/tests/fail/stacked_borrows/newtype_retagging.stderr +++ b/tests/fail/stacked_borrows/newtype_retagging.stderr @@ -16,7 +16,7 @@ help: is this argument | LL | fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) { | ^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC note: inside closure at $DIR/newtype_retagging.rs:LL:CC diff --git a/tests/fail/stacked_borrows/outdated_local.stderr b/tests/fail/stacked_borrows/outdated_local.stderr index e111a8227b2a..8c2bba539188 100644 --- a/tests/fail/stacked_borrows/outdated_local.stderr +++ b/tests/fail/stacked_borrows/outdated_local.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | x = 1; // this invalidates y by reactivating the lowermost uniq borrow for this local | ^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/outdated_local.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/pass_invalid_mut.stderr b/tests/fail/stacked_borrows/pass_invalid_mut.stderr index 5fd977805445..d7ab930aa378 100644 --- a/tests/fail/stacked_borrows/pass_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/pass_invalid_mut.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a read access | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/pass_invalid_mut.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/pass_invalid_shr.stderr b/tests/fail/stacked_borrows/pass_invalid_shr.stderr index 0f0df02babb5..c14b35c75c83 100644 --- a/tests/fail/stacked_borrows/pass_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/pass_invalid_shr.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | unsafe { *xraw = 42 }; // unfreeze | ^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/pass_invalid_shr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/pointer_smuggling.stderr b/tests/fail/stacked_borrows/pointer_smuggling.stderr index 43d689a0f4bb..6415af1e18bb 100644 --- a/tests/fail/stacked_borrows/pointer_smuggling.stderr +++ b/tests/fail/stacked_borrows/pointer_smuggling.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x1] by a write access | LL | *val = 2; // this invalidates any raw ptrs `fun1` might have created. | ^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `fun2` at $DIR/pointer_smuggling.rs:LL:CC note: inside `main` at $DIR/pointer_smuggling.rs:LL:CC --> $DIR/pointer_smuggling.rs:LL:CC diff --git a/tests/fail/stacked_borrows/raw_tracking.stderr b/tests/fail/stacked_borrows/raw_tracking.stderr index fc846f6d9f6a..d75934445e6d 100644 --- a/tests/fail/stacked_borrows/raw_tracking.stderr +++ b/tests/fail/stacked_borrows/raw_tracking.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a Unique retag | LL | let raw2 = &mut l as *mut _; // invalidates raw1 | ^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/raw_tracking.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/return_invalid_mut.stderr b/tests/fail/stacked_borrows/return_invalid_mut.stderr index c9194208e5dd..9deb0c41742f 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x8] by a read access | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `foo` at $DIR/return_invalid_mut.rs:LL:CC note: inside `main` at $DIR/return_invalid_mut.rs:LL:CC --> $DIR/return_invalid_mut.rs:LL:CC diff --git a/tests/fail/stacked_borrows/return_invalid_mut_option.stderr b/tests/fail/stacked_borrows/return_invalid_mut_option.stderr index 789d0a3aa829..1068c286c62f 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_option.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut_option.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x8] by a read access | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/return_invalid_mut_option.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr b/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr index f7fc75bfd098..79de9b668cf2 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x8] by a read access | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/return_invalid_mut_tuple.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/return_invalid_shr.stderr b/tests/fail/stacked_borrows/return_invalid_shr.stderr index fef83c478fe9..dd651517c2fb 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x8] by a write access | LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `foo` at $DIR/return_invalid_shr.rs:LL:CC note: inside `main` at $DIR/return_invalid_shr.rs:LL:CC --> $DIR/return_invalid_shr.rs:LL:CC diff --git a/tests/fail/stacked_borrows/return_invalid_shr_option.stderr b/tests/fail/stacked_borrows/return_invalid_shr_option.stderr index cc316aaf44ec..f45456305db2 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_option.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr_option.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x8] by a write access | LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/return_invalid_shr_option.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr b/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr index f6be5d0e53a0..2e41f505bb9d 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x8] by a write access | LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/return_invalid_shr_tuple.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr index 3f5f2c66ae1f..3a139c3ab212 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a Unique retag | LL | shr_rw.set(1); | ^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/shared_rw_borrows_are_weak1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr index 0a551fe824b5..0609a73e7931 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [$HEX..$HEX] by a Unique retag | LL | shr_rw.replace(1); | ^^^^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/shared_rw_borrows_are_weak2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/shr_frozen_violation1.stderr b/tests/fail/stacked_borrows/shr_frozen_violation1.stderr index 9ae8461e13ea..0818d07da48e 100644 --- a/tests/fail/stacked_borrows/shr_frozen_violation1.stderr +++ b/tests/fail/stacked_borrows/shr_frozen_violation1.stderr @@ -14,7 +14,7 @@ help: was created by a SharedReadOnly retag at offsets [0x0..0x4] | LL | *(x as *const i32 as *mut i32) = 7; | ^ - = note: backtrace: + = note: BACKTRACE: = note: inside `unknown_code` at $DIR/shr_frozen_violation1.rs:LL:CC note: inside `foo` at $DIR/shr_frozen_violation1.rs:LL:CC --> $DIR/shr_frozen_violation1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/static_memory_modification.stderr b/tests/fail/stacked_borrows/static_memory_modification.stderr index c8a0dc8dca2d..ca99a8262b8b 100644 --- a/tests/fail/stacked_borrows/static_memory_modification.stderr +++ b/tests/fail/stacked_borrows/static_memory_modification.stderr @@ -6,7 +6,7 @@ LL | std::mem::transmute::<&usize, &mut usize>(&X) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/static_memory_modification.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/track_caller.stderr b/tests/fail/stacked_borrows/track_caller.stderr index 5ad22305910a..6f1d0ccd348e 100644 --- a/tests/fail/stacked_borrows/track_caller.stderr +++ b/tests/fail/stacked_borrows/track_caller.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a read access | LL | callee(xraw); | ^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/track_caller.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr index eaac77034cce..a2ecb07fd311 100644 --- a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr +++ b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr @@ -14,7 +14,7 @@ help: was created by a SharedReadWrite retag at offsets [0x4..0x8] | LL | let raw = (&mut x[1] as *mut i32).wrapping_offset(-1); | ^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/transmute-is-no-escape.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/unescaped_local.stderr b/tests/fail/stacked_borrows/unescaped_local.stderr index 6302ccde9837..4deafa890005 100644 --- a/tests/fail/stacked_borrows/unescaped_local.stderr +++ b/tests/fail/stacked_borrows/unescaped_local.stderr @@ -9,7 +9,7 @@ LL | *raw = 13; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unescaped_local.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/unescaped_static.stderr b/tests/fail/stacked_borrows/unescaped_static.stderr index 7b210ed9314e..01a4bf4340c7 100644 --- a/tests/fail/stacked_borrows/unescaped_static.stderr +++ b/tests/fail/stacked_borrows/unescaped_static.stderr @@ -14,7 +14,7 @@ help: was created by a SharedReadOnly retag at offsets [0x0..0x1] | LL | let ptr_to_first = &ARRAY[0] as *const u8; | ^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unescaped_static.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/zst_slice.stderr b/tests/fail/stacked_borrows/zst_slice.stderr index 6d0e785cea76..86f1da1f70a3 100644 --- a/tests/fail/stacked_borrows/zst_slice.stderr +++ b/tests/fail/stacked_borrows/zst_slice.stderr @@ -14,7 +14,7 @@ help: would have been created here, but this is a zero-size retag ([0x0..0 | LL | assert_eq!(*s.get_unchecked(1), 2); | ^^^^^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `core::slice::::get_unchecked::` at RUSTLIB/core/src/slice/mod.rs:LL:CC note: inside `main` at $DIR/zst_slice.rs:LL:CC --> $DIR/zst_slice.rs:LL:CC diff --git a/tests/fail/static_memory_modification1.stderr b/tests/fail/static_memory_modification1.stderr index 47590afc1d1a..5e7213ee6088 100644 --- a/tests/fail/static_memory_modification1.stderr +++ b/tests/fail/static_memory_modification1.stderr @@ -6,7 +6,7 @@ LL | *std::mem::transmute::<&usize, &mut usize>(&X) = 6; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/static_memory_modification1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/static_memory_modification2.stderr b/tests/fail/static_memory_modification2.stderr index c8fce81ede55..4c160cd32068 100644 --- a/tests/fail/static_memory_modification2.stderr +++ b/tests/fail/static_memory_modification2.stderr @@ -6,7 +6,7 @@ LL | transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/static_memory_modification2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/static_memory_modification3.stderr b/tests/fail/static_memory_modification3.stderr index 16b06bb3f796..1986059c50a8 100644 --- a/tests/fail/static_memory_modification3.stderr +++ b/tests/fail/static_memory_modification3.stderr @@ -6,7 +6,7 @@ LL | transmute::<&[u8], &mut [u8]>(bs)[4] = 42; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/static_memory_modification3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/transmute-pair-uninit.stderr b/tests/fail/transmute-pair-uninit.stderr index a8e0bdd05b6d..642bf0a71343 100644 --- a/tests/fail/transmute-pair-uninit.stderr +++ b/tests/fail/transmute-pair-uninit.stderr @@ -6,7 +6,7 @@ LL | let v = unsafe { *z.offset(first_undef) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/transmute-pair-uninit.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/transmute_fat1.stderr b/tests/fail/transmute_fat1.stderr index a2dcffb255fe..e1907e080194 100644 --- a/tests/fail/transmute_fat1.stderr +++ b/tests/fail/transmute_fat1.stderr @@ -6,7 +6,7 @@ LL | std::mem::transmute::<&[u8], [u8; N]>(&[1u8]) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/transmute_fat1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/alignment.stderr b/tests/fail/unaligned_pointers/alignment.stderr index f3bd7ca27571..bbebe3b89fd7 100644 --- a/tests/fail/unaligned_pointers/alignment.stderr +++ b/tests/fail/unaligned_pointers/alignment.stderr @@ -6,7 +6,7 @@ LL | *(x_ptr as *mut u32) = 42; *(x_ptr.add(1) as *mut u32) = 42; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/alignment.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/atomic_unaligned.stderr b/tests/fail/unaligned_pointers/atomic_unaligned.stderr index bde4ff615c29..8c3aa3429af5 100644 --- a/tests/fail/unaligned_pointers/atomic_unaligned.stderr +++ b/tests/fail/unaligned_pointers/atomic_unaligned.stderr @@ -6,7 +6,7 @@ LL | ::std::intrinsics::atomic_load_seqcst(zptr); | = help: this usually indicates that your program performed an invalid operation and caused Undefined Behavior = help: but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/atomic_unaligned.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/dyn_alignment.stderr b/tests/fail/unaligned_pointers/dyn_alignment.stderr index 930ec994d002..a900b46612b8 100644 --- a/tests/fail/unaligned_pointers/dyn_alignment.stderr +++ b/tests/fail/unaligned_pointers/dyn_alignment.stderr @@ -6,7 +6,7 @@ LL | let _ptr = &*ptr; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/dyn_alignment.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr b/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr index 963fa81b655c..392495a386de 100644 --- a/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr +++ b/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr @@ -6,7 +6,7 @@ LL | unsafe { *u16_ptr = 2 }; | = help: this usually indicates that your program performed an invalid operation and caused Undefined Behavior = help: but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/intptrcast_alignment_check.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/reference_to_packed.stderr b/tests/fail/unaligned_pointers/reference_to_packed.stderr index ce667c1e8dec..6c2a3dca2dee 100644 --- a/tests/fail/unaligned_pointers/reference_to_packed.stderr +++ b/tests/fail/unaligned_pointers/reference_to_packed.stderr @@ -6,7 +6,7 @@ LL | let i = *p; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/reference_to_packed.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/unaligned_ptr1.stderr b/tests/fail/unaligned_pointers/unaligned_ptr1.stderr index c557ebb11f67..49292be9cd15 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr1.stderr +++ b/tests/fail/unaligned_pointers/unaligned_ptr1.stderr @@ -6,7 +6,7 @@ LL | let _x = unsafe { *x }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unaligned_ptr1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/unaligned_ptr2.stderr b/tests/fail/unaligned_pointers/unaligned_ptr2.stderr index 5bff91621317..e75482f723b6 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr2.stderr +++ b/tests/fail/unaligned_pointers/unaligned_ptr2.stderr @@ -6,7 +6,7 @@ LL | let _x = unsafe { *x }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unaligned_ptr2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/unaligned_ptr3.stderr b/tests/fail/unaligned_pointers/unaligned_ptr3.stderr index f887f38bec53..50dd4fdfc89f 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr3.stderr +++ b/tests/fail/unaligned_pointers/unaligned_ptr3.stderr @@ -6,7 +6,7 @@ LL | let _x = unsafe { *x }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unaligned_ptr3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/unaligned_ptr4.stderr b/tests/fail/unaligned_pointers/unaligned_ptr4.stderr index f2fe961eb6a1..182f3e0f876f 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr4.stderr +++ b/tests/fail/unaligned_pointers/unaligned_ptr4.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { *ptr }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unaligned_ptr4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.stderr b/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.stderr index 157eb68b50d8..2d8b1bf74508 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.stderr +++ b/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.stderr @@ -6,7 +6,7 @@ LL | let _x = unsafe { ptr::addr_of!(*x) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at RUSTLIB/core/src/ptr/mod.rs:LL:CC = note: this error originates in the macro `ptr::addr_of` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr b/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr index da53e922b7a9..aa0cbe1623b6 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr +++ b/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr @@ -6,7 +6,7 @@ LL | let _x = unsafe { *x }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unaligned_ptr_zst.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/uninit_buffer.stderr b/tests/fail/uninit_buffer.stderr index 879c827eb884..a543d59addb1 100644 --- a/tests/fail/uninit_buffer.stderr +++ b/tests/fail/uninit_buffer.stderr @@ -6,7 +6,7 @@ LL | let mut order = unsafe { memcmp(left.as_ptr(), right.as_ptr(), len) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `::compare` at RUSTLIB/core/src/slice/cmp.rs:LL:CC = note: inside `core::slice::cmp::::cmp` at RUSTLIB/core/src/slice/cmp.rs:LL:CC note: inside `main` at $DIR/uninit_buffer.rs:LL:CC diff --git a/tests/fail/uninit_byte_read.stderr b/tests/fail/uninit_byte_read.stderr index 432710b04f86..9f7638888d64 100644 --- a/tests/fail/uninit_byte_read.stderr +++ b/tests/fail/uninit_byte_read.stderr @@ -6,7 +6,7 @@ LL | let undef = unsafe { *v.get_unchecked(5) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/uninit_byte_read.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unreachable.stderr b/tests/fail/unreachable.stderr index b487b4374756..a57d731f1f71 100644 --- a/tests/fail/unreachable.stderr +++ b/tests/fail/unreachable.stderr @@ -6,7 +6,7 @@ LL | unsafe { std::hint::unreachable_unchecked() } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unreachable.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unsized-local.stderr b/tests/fail/unsized-local.stderr index 8277bc4546cb..66d93c6f503c 100644 --- a/tests/fail/unsized-local.stderr +++ b/tests/fail/unsized-local.stderr @@ -5,7 +5,7 @@ LL | let x = *(Box::new(A) as Box); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsized locals are not supported | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unsized-local.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unsupported_foreign_function.stderr b/tests/fail/unsupported_foreign_function.stderr index 3298f57dd51e..fde5fb78ac08 100644 --- a/tests/fail/unsupported_foreign_function.stderr +++ b/tests/fail/unsupported_foreign_function.stderr @@ -5,7 +5,7 @@ LL | foo(); | ^^^^^ can't call foreign function: foo | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unsupported_foreign_function.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unsupported_signal.stderr b/tests/fail/unsupported_signal.stderr index 622b1876e0f8..d22ecbc11ff6 100644 --- a/tests/fail/unsupported_signal.stderr +++ b/tests/fail/unsupported_signal.stderr @@ -5,7 +5,7 @@ LL | libc::signal(libc::SIGPIPE, libc::SIG_IGN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't call foreign function: signal | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unsupported_signal.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/cast_fn_ptr1.stderr b/tests/fail/validity/cast_fn_ptr1.stderr index 6ac10b10a003..133e4b2c16a1 100644 --- a/tests/fail/validity/cast_fn_ptr1.stderr +++ b/tests/fail/validity/cast_fn_ptr1.stderr @@ -6,7 +6,7 @@ LL | g(0usize as *const i32) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/cast_fn_ptr1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/cast_fn_ptr2.stderr b/tests/fail/validity/cast_fn_ptr2.stderr index cd73237c867f..21001f2b4609 100644 --- a/tests/fail/validity/cast_fn_ptr2.stderr +++ b/tests/fail/validity/cast_fn_ptr2.stderr @@ -6,7 +6,7 @@ LL | let _x = g(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/cast_fn_ptr2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/dangling_ref1.stderr b/tests/fail/validity/dangling_ref1.stderr index 52e1ae2acb85..01ef071e8693 100644 --- a/tests/fail/validity/dangling_ref1.stderr +++ b/tests/fail/validity/dangling_ref1.stderr @@ -6,7 +6,7 @@ LL | let _x: &i32 = unsafe { mem::transmute(16usize) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/dangling_ref1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/dangling_ref2.stderr b/tests/fail/validity/dangling_ref2.stderr index f9d0ad5515c8..4be4e8075a72 100644 --- a/tests/fail/validity/dangling_ref2.stderr +++ b/tests/fail/validity/dangling_ref2.stderr @@ -6,7 +6,7 @@ LL | let _x: &i32 = unsafe { mem::transmute(ptr) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/dangling_ref2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/dangling_ref3.stderr b/tests/fail/validity/dangling_ref3.stderr index 37b8d6bce6e8..4b7bdf782368 100644 --- a/tests/fail/validity/dangling_ref3.stderr +++ b/tests/fail/validity/dangling_ref3.stderr @@ -6,7 +6,7 @@ LL | let _x: &i32 = unsafe { mem::transmute(dangling()) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/dangling_ref3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_bool.stderr b/tests/fail/validity/invalid_bool.stderr index 31575a439b5b..3972787a4d2f 100644 --- a/tests/fail/validity/invalid_bool.stderr +++ b/tests/fail/validity/invalid_bool.stderr @@ -6,7 +6,7 @@ LL | let _b = unsafe { std::mem::transmute::(2) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/invalid_bool.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_bool_uninit.stderr b/tests/fail/validity/invalid_bool_uninit.stderr index 3d90a45d831c..2dbd102d9833 100644 --- a/tests/fail/validity/invalid_bool_uninit.stderr +++ b/tests/fail/validity/invalid_bool_uninit.stderr @@ -6,7 +6,7 @@ LL | let _b = unsafe { MyUninit { init: () }.uninit }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/invalid_bool_uninit.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_char.stderr b/tests/fail/validity/invalid_char.stderr index a64452041f6f..eeff289dfa4e 100644 --- a/tests/fail/validity/invalid_char.stderr +++ b/tests/fail/validity/invalid_char.stderr @@ -6,7 +6,7 @@ LL | let _val = match unsafe { std::mem::transmute::(-1) } { | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/invalid_char.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_char_uninit.stderr b/tests/fail/validity/invalid_char_uninit.stderr index 0512f90a90a4..c59bbedd0ab8 100644 --- a/tests/fail/validity/invalid_char_uninit.stderr +++ b/tests/fail/validity/invalid_char_uninit.stderr @@ -6,7 +6,7 @@ LL | let _b = unsafe { MyUninit { init: () }.uninit }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/invalid_char_uninit.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_enum_tag.stderr b/tests/fail/validity/invalid_enum_tag.stderr index e6a484d7bde3..9234b4d705a9 100644 --- a/tests/fail/validity/invalid_enum_tag.stderr +++ b/tests/fail/validity/invalid_enum_tag.stderr @@ -6,7 +6,7 @@ LL | let _f = unsafe { std::mem::transmute::(42) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/invalid_enum_tag.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_fnptr_null.stderr b/tests/fail/validity/invalid_fnptr_null.stderr index 6c744f204445..63fad1d56e38 100644 --- a/tests/fail/validity/invalid_fnptr_null.stderr +++ b/tests/fail/validity/invalid_fnptr_null.stderr @@ -6,7 +6,7 @@ LL | let _b: fn() = unsafe { std::mem::transmute(0usize) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/invalid_fnptr_null.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_fnptr_uninit.stderr b/tests/fail/validity/invalid_fnptr_uninit.stderr index f5de8101709d..15ae78e35db2 100644 --- a/tests/fail/validity/invalid_fnptr_uninit.stderr +++ b/tests/fail/validity/invalid_fnptr_uninit.stderr @@ -6,7 +6,7 @@ LL | let _b = unsafe { MyUninit { init: () }.uninit }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/invalid_fnptr_uninit.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_wide_raw.stderr b/tests/fail/validity/invalid_wide_raw.stderr index 304008f65163..cf12ab8dbd55 100644 --- a/tests/fail/validity/invalid_wide_raw.stderr +++ b/tests/fail/validity/invalid_wide_raw.stderr @@ -6,7 +6,7 @@ LL | dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/invalid_wide_raw.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/nonzero.stderr b/tests/fail/validity/nonzero.stderr index 05b08d99d36d..a9a68177ed97 100644 --- a/tests/fail/validity/nonzero.stderr +++ b/tests/fail/validity/nonzero.stderr @@ -6,7 +6,7 @@ LL | let _x = Some(unsafe { NonZero(0) }); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/nonzero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/ptr_integer_array_transmute.stderr b/tests/fail/validity/ptr_integer_array_transmute.stderr index 43eedb70fe65..118c6a4327cd 100644 --- a/tests/fail/validity/ptr_integer_array_transmute.stderr +++ b/tests/fail/validity/ptr_integer_array_transmute.stderr @@ -6,7 +6,7 @@ LL | let _i: [usize; 1] = unsafe { std::mem::transmute(r) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/ptr_integer_array_transmute.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/ref_to_uninhabited1.stderr b/tests/fail/validity/ref_to_uninhabited1.stderr index ae606d0a8013..4facd2159c8d 100644 --- a/tests/fail/validity/ref_to_uninhabited1.stderr +++ b/tests/fail/validity/ref_to_uninhabited1.stderr @@ -6,7 +6,7 @@ LL | let x: Box = transmute(&mut 42); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/ref_to_uninhabited1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/ref_to_uninhabited2.stderr b/tests/fail/validity/ref_to_uninhabited2.stderr index 3db040eeda10..264465f93919 100644 --- a/tests/fail/validity/ref_to_uninhabited2.stderr +++ b/tests/fail/validity/ref_to_uninhabited2.stderr @@ -6,7 +6,7 @@ LL | let _x: &(i32, Void) = transmute(&42); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/ref_to_uninhabited2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/too-big-slice.stderr b/tests/fail/validity/too-big-slice.stderr index 591dc6d7b5c2..6df00aefe756 100644 --- a/tests/fail/validity/too-big-slice.stderr +++ b/tests/fail/validity/too-big-slice.stderr @@ -6,7 +6,7 @@ LL | let _x: &[u8] = mem::transmute((ptr, usize::MAX)); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/too-big-slice.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/too-big-unsized.stderr b/tests/fail/validity/too-big-unsized.stderr index 3b8b9f50cf87..cbcb31b29fc3 100644 --- a/tests/fail/validity/too-big-unsized.stderr +++ b/tests/fail/validity/too-big-unsized.stderr @@ -6,7 +6,7 @@ LL | let _x: &MySlice = mem::transmute((ptr, isize::MAX as usize)); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/too-big-unsized.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/transmute_through_ptr.stderr b/tests/fail/validity/transmute_through_ptr.stderr index bf79e8649d01..ea155405cd61 100644 --- a/tests/fail/validity/transmute_through_ptr.stderr +++ b/tests/fail/validity/transmute_through_ptr.stderr @@ -6,7 +6,7 @@ LL | let y = x; // reading this ought to be enough to trigger validation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/transmute_through_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/uninit_float.stderr b/tests/fail/validity/uninit_float.stderr index 8a677202c8eb..c64f56e25516 100644 --- a/tests/fail/validity/uninit_float.stderr +++ b/tests/fail/validity/uninit_float.stderr @@ -6,7 +6,7 @@ LL | let _val: f32 = unsafe { std::mem::uninitialized() }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/uninit_float.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/uninit_integer.stderr b/tests/fail/validity/uninit_integer.stderr index 60bf2c736677..5828eba7939c 100644 --- a/tests/fail/validity/uninit_integer.stderr +++ b/tests/fail/validity/uninit_integer.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_ini | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/uninit_integer.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/uninit_raw_ptr.stderr b/tests/fail/validity/uninit_raw_ptr.stderr index efa444229270..68f7d2af6a5d 100644 --- a/tests/fail/validity/uninit_raw_ptr.stderr +++ b/tests/fail/validity/uninit_raw_ptr.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { std::mem::MaybeUninit::<*const u8>::uninit().assume | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/uninit_raw_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/weak_memory/racing_mixed_size.stderr b/tests/fail/weak_memory/racing_mixed_size.stderr index 4c53828a6ce6..dda22ac9ce24 100644 --- a/tests/fail/weak_memory/racing_mixed_size.stderr +++ b/tests/fail/weak_memory/racing_mixed_size.stderr @@ -5,7 +5,7 @@ LL | std::intrinsics::atomic_load_relaxed(hi); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/racing_mixed_size.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/weak_memory/racing_mixed_size_read.stderr b/tests/fail/weak_memory/racing_mixed_size_read.stderr index 8dbf9e6948bd..59fa5c741023 100644 --- a/tests/fail/weak_memory/racing_mixed_size_read.stderr +++ b/tests/fail/weak_memory/racing_mixed_size_read.stderr @@ -5,7 +5,7 @@ LL | (*hi).load(Relaxed); | ^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/racing_mixed_size_read.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/zst1.stderr b/tests/fail/zst1.stderr index eeb2429d4c6f..b89f06af9589 100644 --- a/tests/fail/zst1.stderr +++ b/tests/fail/zst1.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { *x }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/zst1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/zst2.stderr b/tests/fail/zst2.stderr index 8687e8636bfe..6c49656e4c67 100644 --- a/tests/fail/zst2.stderr +++ b/tests/fail/zst2.stderr @@ -6,7 +6,7 @@ LL | unsafe { *x = zst_val }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/zst2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/zst3.stderr b/tests/fail/zst3.stderr index 43233d4d2afd..c9accf2c8fbe 100644 --- a/tests/fail/zst3.stderr +++ b/tests/fail/zst3.stderr @@ -6,7 +6,7 @@ LL | unsafe { *(x as *mut [u8; 0]) = zst_val }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/zst3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/pass/box.stderr b/tests/pass/box.stderr index 2c2534fa2b05..0001a8dd6eb3 100644 --- a/tests/pass/box.stderr +++ b/tests/pass/box.stderr @@ -10,7 +10,7 @@ LL | let r2 = ((r as usize) + 0) as *mut i32; = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead. = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics. = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning. - = note: backtrace: + = note: BACKTRACE: = note: inside `into_raw` at $DIR/box.rs:LL:CC note: inside `main` at $DIR/box.rs:LL:CC --> $DIR/box.rs:LL:CC diff --git a/tests/pass/extern_types.stderr b/tests/pass/extern_types.stderr index fcb04d951d16..2e18f6930589 100644 --- a/tests/pass/extern_types.stderr +++ b/tests/pass/extern_types.stderr @@ -10,6 +10,6 @@ LL | let x: &Foo = unsafe { &*(16 as *const Foo) }; = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead. = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics. = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning. - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/extern_types.rs:LL:CC diff --git a/tests/pass/stacked-borrows/issue-miri-2389.stderr b/tests/pass/stacked-borrows/issue-miri-2389.stderr index 2ff931f23157..f3ba052ae513 100644 --- a/tests/pass/stacked-borrows/issue-miri-2389.stderr +++ b/tests/pass/stacked-borrows/issue-miri-2389.stderr @@ -10,6 +10,6 @@ LL | let wildcard = &root0 as *const Cell as usize as *const Cell Date: Wed, 31 Aug 2022 16:05:40 +0200 Subject: [PATCH 3996/5092] make shim_arg_size ptr-width-independent --- tests/fail/shims/shim_arg_size.64bit.stderr | 15 --------------- tests/fail/shims/shim_arg_size.rs | 13 +++---------- ...arg_size.32bit.stderr => shim_arg_size.stderr} | 8 ++++---- 3 files changed, 7 insertions(+), 29 deletions(-) delete mode 100644 tests/fail/shims/shim_arg_size.64bit.stderr rename tests/fail/shims/{shim_arg_size.32bit.stderr => shim_arg_size.stderr} (72%) diff --git a/tests/fail/shims/shim_arg_size.64bit.stderr b/tests/fail/shims/shim_arg_size.64bit.stderr deleted file mode 100644 index 0e8b402ac714..000000000000 --- a/tests/fail/shims/shim_arg_size.64bit.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: scalar size mismatch: expected 8 bytes but got 4 bytes instead - --> $DIR/shim_arg_size.rs:LL:CC - | -LL | let _p1 = malloc(42); - | ^^^^^^^^^^ scalar size mismatch: expected 8 bytes but got 4 bytes instead - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `main` at $DIR/shim_arg_size.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/shims/shim_arg_size.rs b/tests/fail/shims/shim_arg_size.rs index 383df286d4c8..3d7bc25bf5d3 100644 --- a/tests/fail/shims/shim_arg_size.rs +++ b/tests/fail/shims/shim_arg_size.rs @@ -1,17 +1,10 @@ -//@stderr-per-bitwidth - fn main() { extern "C" { - // Use the wrong type(ie. not the pointer width) for the `size` - // argument. - #[cfg(target_pointer_width = "64")] - fn malloc(size: u32) -> *mut std::ffi::c_void; - - #[cfg(target_pointer_width = "32")] - fn malloc(size: u16) -> *mut std::ffi::c_void; + // Use the wrong type (ie. not `i32`) for the `c` argument. + fn memchr(s: *const std::ffi::c_void, c: u8, n: usize) -> *mut std::ffi::c_void; } unsafe { - let _p1 = malloc(42); //~ ERROR: Undefined Behavior: scalar size mismatch + memchr(std::ptr::null(), 0, 0); //~ ERROR: Undefined Behavior: scalar size mismatch }; } diff --git a/tests/fail/shims/shim_arg_size.32bit.stderr b/tests/fail/shims/shim_arg_size.stderr similarity index 72% rename from tests/fail/shims/shim_arg_size.32bit.stderr rename to tests/fail/shims/shim_arg_size.stderr index 84b09acbac3d..d951f81810ef 100644 --- a/tests/fail/shims/shim_arg_size.32bit.stderr +++ b/tests/fail/shims/shim_arg_size.stderr @@ -1,12 +1,12 @@ -error: Undefined Behavior: scalar size mismatch: expected 4 bytes but got 2 bytes instead +error: Undefined Behavior: scalar size mismatch: expected 4 bytes but got 1 bytes instead --> $DIR/shim_arg_size.rs:LL:CC | -LL | let _p1 = malloc(42); - | ^^^^^^^^^^ scalar size mismatch: expected 4 bytes but got 2 bytes instead +LL | memchr(std::ptr::null(), 0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ scalar size mismatch: expected 4 bytes but got 1 bytes instead | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/shim_arg_size.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace From ee02a4721b5bb20a67a105291cc3f59d8e57da7b Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 31 Aug 2022 18:05:52 +0200 Subject: [PATCH 3997/5092] Remove unnecessary allocations --- crates/hir-def/src/body/lower.rs | 73 +++++++++------------------ crates/hir-ty/src/tests/macros.rs | 3 -- crates/hir-ty/src/tests/regression.rs | 1 - crates/hir-ty/src/tests/simple.rs | 1 - 4 files changed, 25 insertions(+), 53 deletions(-) diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index cb6fdbfc562e..8ebac5cb1c6c 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -628,8 +628,9 @@ impl ExprCollector<'_> { fn collect_macro_as_stmt( &mut self, + statements: &mut Vec, mac: ast::MacroExpr, - ) -> Option<(Vec, Option)> { + ) -> Option { let mac_call = mac.macro_call()?; let syntax_ptr = AstPtr::new(&ast::Expr::from(mac)); let macro_ptr = AstPtr::new(&mac_call); @@ -639,49 +640,32 @@ impl ExprCollector<'_> { false, |this, expansion: Option| match expansion { Some(expansion) => { - let mut statements: Vec<_> = expansion - .statements() - .filter_map(|stmt| this.collect_stmt(stmt)) - .flatten() - .collect(); - let tail = expansion.expr().and_then(|expr| match expr { - ast::Expr::MacroExpr(mac) => { - let (stmts, tail) = this.collect_macro_as_stmt(mac)?; - statements.extend(stmts); - tail - } + expansion.statements().for_each(|stmt| this.collect_stmt(statements, stmt)); + expansion.expr().and_then(|expr| match expr { + ast::Expr::MacroExpr(mac) => this.collect_macro_as_stmt(statements, mac), expr => Some(this.collect_expr(expr)), - }); - Some((statements, tail)) + }) } None => None, }, ); - let mut stmts = Vec::new(); - let expr = match expansion { - Some((statements, tail)) => { - stmts.extend(statements); + match expansion { + Some(tail) => { // Make the macro-call point to its expanded expression so we can query // semantics on syntax pointers to the macro let src = self.expander.to_source(syntax_ptr); - match tail { - Some(tail) => { - self.source_map.expr_map.insert(src, tail); - tail - } - None => self.make_expr(Expr::Missing, Ok(src.clone())), - } + self.source_map.expr_map.insert(src, tail); + Some(tail) } - None => self.alloc_expr(Expr::Missing, syntax_ptr), - }; - Some((stmts, Some(expr))) + None => None, + } } - fn collect_stmt(&mut self, s: ast::Stmt) -> Option> { + fn collect_stmt(&mut self, statements: &mut Vec, s: ast::Stmt) { match s { ast::Stmt::LetStmt(stmt) => { if self.check_cfg(&stmt).is_none() { - return None; + return; } let pat = self.collect_pat_opt(stmt.pat()); let type_ref = @@ -691,29 +675,26 @@ impl ExprCollector<'_> { .let_else() .and_then(|let_else| let_else.block_expr()) .map(|block| self.collect_block(block)); - Some(vec![Statement::Let { pat, type_ref, initializer, else_branch }]) + statements.push(Statement::Let { pat, type_ref, initializer, else_branch }); } ast::Stmt::ExprStmt(stmt) => { let expr = stmt.expr(); - if let Some(expr) = &expr { - if self.check_cfg(expr).is_none() { - return None; - } + match &expr { + Some(expr) if self.check_cfg(expr).is_none() => return, + _ => (), } let has_semi = stmt.semicolon_token().is_some(); // Note that macro could be expanded to multiple statements if let Some(ast::Expr::MacroExpr(mac)) = expr { - let (mut statements, tail) = self.collect_macro_as_stmt(mac)?; - if let Some(expr) = tail { - statements.push(Statement::Expr { expr, has_semi }); + if let Some(expr) = self.collect_macro_as_stmt(statements, mac) { + statements.push(Statement::Expr { expr, has_semi }) } - Some(statements) } else { let expr = self.collect_expr_opt(expr); - Some(vec![Statement::Expr { expr, has_semi }]) + statements.push(Statement::Expr { expr, has_semi }); } } - ast::Stmt::Item(_item) => None, + ast::Stmt::Item(_item) => (), } } @@ -734,14 +715,10 @@ impl ExprCollector<'_> { let prev_def_map = mem::replace(&mut self.expander.def_map, def_map); let prev_local_module = mem::replace(&mut self.expander.module, module); - let mut statements: Vec<_> = - block.statements().filter_map(|s| self.collect_stmt(s)).flatten().collect(); + let mut statements = Vec::new(); + block.statements().for_each(|s| self.collect_stmt(&mut statements, s)); let tail = block.tail_expr().and_then(|e| match e { - ast::Expr::MacroExpr(mac) => { - let (stmts, tail) = self.collect_macro_as_stmt(mac)?; - statements.extend(stmts); - tail - } + ast::Expr::MacroExpr(mac) => self.collect_macro_as_stmt(&mut statements, mac), expr => self.maybe_collect_expr(expr), }); let tail = tail.or_else(|| { diff --git a/crates/hir-ty/src/tests/macros.rs b/crates/hir-ty/src/tests/macros.rs index a1a2fdd1fb28..b3adafaafd38 100644 --- a/crates/hir-ty/src/tests/macros.rs +++ b/crates/hir-ty/src/tests/macros.rs @@ -311,7 +311,6 @@ fn expr_macro_expanded_in_stmts() { !3..4 'a': () !5..7 '()': () 57..84 '{ ...); } }': () - 63..82 'id! { ... (); }': () "#]], ); } @@ -336,7 +335,6 @@ fn recursive_macro_expanded_in_stmts() { } "#, expect![[r#" - !0..13 'ng!{[leta=3]}': {unknown} !3..4 'a': i32 !5..6 '3': i32 196..237 '{ ...= a; }': () @@ -361,7 +359,6 @@ fn recursive_inner_item_macro_rules() { "#, expect![[r#" !0..1 '1': i32 - !0..7 'mac!($)': {unknown} 107..143 '{ ...!(); }': () 129..130 'a': i32 "#]], diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs index cc49c3d45fcd..23e51a9c16a5 100644 --- a/crates/hir-ty/src/tests/regression.rs +++ b/crates/hir-ty/src/tests/regression.rs @@ -578,7 +578,6 @@ fn issue_6811() { !11..13 '_b': i32 !14..15 '1': i32 103..131 '{ ...!(); }': () - 109..128 'profil...ion!()': {unknown} "#]], ); } diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs index 5b08f552109e..707e9e84506a 100644 --- a/crates/hir-ty/src/tests/simple.rs +++ b/crates/hir-ty/src/tests/simple.rs @@ -2549,7 +2549,6 @@ impl B for Astruct {} expect![[r#" 569..573 'self': Box<[T], A> 602..634 '{ ... }': Vec - 612..628 'unimpl...ted!()': Vec 648..761 '{ ...t]); }': () 658..661 'vec': Vec 664..679 '<[_]>::into_vec': fn into_vec(Box<[i32], Global>) -> Vec From 803e35abf7c2949fe04d1c403d69605f570d5637 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 31 Aug 2022 17:05:38 +0200 Subject: [PATCH 3998/5092] Remove unneeded extra whitespace before where clause --- src/librustdoc/html/format.rs | 13 ++++--------- src/librustdoc/html/render/mod.rs | 12 ++++++------ 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index b023792e95a5..05d10f8137fe 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -349,8 +349,7 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>( let where_preds = comma_sep(where_predicates, false); let clause = if f.alternate() { if ending == Ending::Newline { - // add a space so stripping
tags and breaking spaces still renders properly - format!(" where{where_preds}, ") + format!(" where{where_preds},") } else { format!(" where{where_preds}") } @@ -364,20 +363,16 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>( if ending == Ending::Newline { let mut clause = " ".repeat(indent.saturating_sub(1)); - // add a space so stripping
tags and breaking spaces still renders properly - write!( - clause, - " where{where_preds}, " - )?; + write!(clause, "where{where_preds},")?; clause } else { // insert a
tag after a single space but before multiple spaces at the start if indent == 0 { - format!("
where{where_preds}") + format!("
where{where_preds}") } else { let mut clause = br_with_padding; clause.truncate(clause.len() - 5 * " ".len()); - write!(clause, " where{where_preds}")?; + write!(clause, "where{where_preds}")?; clause } } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 6272f47f460c..bff12e6fee9b 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1739,8 +1739,8 @@ pub(crate) fn render_impl_summary( // in documentation pages for trait with automatic implementations like "Send" and "Sync". aliases: &[String], ) { - let id = - cx.derive_id(get_id_for_impl(&i.inner_impl().for_, i.inner_impl().trait_.as_ref(), cx)); + let inner_impl = i.inner_impl(); + let id = cx.derive_id(get_id_for_impl(&inner_impl.for_, inner_impl.trait_.as_ref(), cx)); let aliases = if aliases.is_empty() { String::new() } else { @@ -1752,9 +1752,9 @@ pub(crate) fn render_impl_summary( write!(w, "

"); if let Some(use_absolute) = use_absolute { - write!(w, "{}", i.inner_impl().print(use_absolute, cx)); + write!(w, "{}", inner_impl.print(use_absolute, cx)); if show_def_docs { - for it in &i.inner_impl().items { + for it in &inner_impl.items { if let clean::AssocTypeItem(ref tydef, ref _bounds) = *it.kind { w.write_str(" "); assoc_type( @@ -1772,11 +1772,11 @@ pub(crate) fn render_impl_summary( } } } else { - write!(w, "{}", i.inner_impl().print(false, cx)); + write!(w, "{}", inner_impl.print(false, cx)); } write!(w, "

"); - let is_trait = i.inner_impl().trait_.is_some(); + let is_trait = inner_impl.trait_.is_some(); if is_trait { if let Some(portability) = portability(&i.impl_item, Some(parent)) { write!(w, "{}", portability); From 4304d1d1e6ea31ca45b722047f516322af4305c4 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 31 Aug 2022 17:05:46 +0200 Subject: [PATCH 3999/5092] Update rustdoc tests --- src/test/rustdoc-gui/src/lib2/lib.rs | 27 +++++++++++++++++++ .../const-generics/const-generics-docs.rs | 8 +++--- .../rustdoc/generic-associated-types/gats.rs | 4 +-- .../rustdoc/higher-ranked-trait-bounds.rs | 8 +++--- src/test/rustdoc/impl-parts.rs | 4 +-- src/test/rustdoc/issue-20727-4.rs | 4 +-- src/test/rustdoc/issue-21801.rs | 2 +- src/test/rustdoc/issue-29503.rs | 2 +- src/test/rustdoc/issue-34928.rs | 2 +- src/test/rustdoc/issue-50159.rs | 4 +-- src/test/rustdoc/issue-51236.rs | 2 +- src/test/rustdoc/issue-54705.rs | 6 ++--- src/test/rustdoc/issue-98697.rs | 2 +- .../rustdoc/primitive-slice-auto-trait.rs | 4 +-- src/test/rustdoc/synthetic_auto/basic.rs | 4 +-- src/test/rustdoc/synthetic_auto/complex.rs | 2 +- src/test/rustdoc/synthetic_auto/lifetimes.rs | 4 +-- src/test/rustdoc/synthetic_auto/manual.rs | 2 +- src/test/rustdoc/synthetic_auto/nested.rs | 4 +-- .../rustdoc/synthetic_auto/no-redundancy.rs | 2 +- src/test/rustdoc/synthetic_auto/project.rs | 4 +-- .../synthetic_auto/self-referential.rs | 2 +- .../rustdoc/synthetic_auto/static-region.rs | 2 +- src/test/rustdoc/where-clause-order.rs | 2 +- src/test/rustdoc/where.rs | 22 +++++++-------- 25 files changed, 77 insertions(+), 52 deletions(-) diff --git a/src/test/rustdoc-gui/src/lib2/lib.rs b/src/test/rustdoc-gui/src/lib2/lib.rs index 87f91be3ac82..7f3172878bfb 100644 --- a/src/test/rustdoc-gui/src/lib2/lib.rs +++ b/src/test/rustdoc-gui/src/lib2/lib.rs @@ -143,3 +143,30 @@ pub struct LongItemInfo2; /// Some docs. #[doc(cfg(any(target_os = "android", target_os = "linux", target_os = "emscripten", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd")))] impl SimpleTrait for LongItemInfo2 {} + +pub struct WhereWhitespace; + +impl WhereWhitespace { + pub fn new(f: F) -> Self + where + F: FnMut() -> i32, + {} +} + +impl Whitespace<&K> for WhereWhitespace +where + K: std::fmt::Debug, +{ + type Output = WhereWhitespace; + fn index(&self, _key: &K) -> &Self::Output { + self + } +} + +pub trait Whitespace +where + Idx: ?Sized, +{ + type Output; + fn index(&self, index: Idx) -> &Self::Output; +} diff --git a/src/test/rustdoc/const-generics/const-generics-docs.rs b/src/test/rustdoc/const-generics/const-generics-docs.rs index 352a8e646bb4..87d2f29e2605 100644 --- a/src/test/rustdoc/const-generics/const-generics-docs.rs +++ b/src/test/rustdoc/const-generics/const-generics-docs.rs @@ -31,12 +31,12 @@ impl Trait<{1 + 2}> for u8 {} impl Trait for [u8; N] {} // @has foo/struct.Foo.html '//pre[@class="rust struct"]' \ -// 'pub struct Foo where u8: Trait' +// 'pub struct Foowhere u8: Trait' pub struct Foo where u8: Trait; // @has foo/struct.Bar.html '//pre[@class="rust struct"]' 'pub struct Bar(_)' pub struct Bar([T; N]); -// @has foo/struct.Foo.html '//*[@id="impl-Foo%3CM%3E"]/h3[@class="code-header in-band"]' 'impl Foo where u8: Trait' +// @has foo/struct.Foo.html '//*[@id="impl-Foo%3CM%3E"]/h3[@class="code-header in-band"]' 'impl Foowhere u8: Trait' impl Foo where u8: Trait { // @has - '//*[@id="associatedconstant.FOO_ASSOC"]' 'pub const FOO_ASSOC: usize' pub const FOO_ASSOC: usize = M + 13; @@ -50,14 +50,14 @@ impl Foo where u8: Trait { // @has foo/struct.Bar.html '//*[@id="impl-Bar%3Cu8%2C%20M%3E"]/h3[@class="code-header in-band"]' 'impl Bar' impl Bar { // @has - '//*[@id="method.hey"]' \ - // 'pub fn hey(&self) -> Foo where u8: Trait' + // 'pub fn hey(&self) -> Foowhere u8: Trait' pub fn hey(&self) -> Foo where u8: Trait { Foo } } // @has foo/fn.test.html '//pre[@class="rust fn"]' \ -// 'pub fn test() -> impl Trait where u8: Trait' +// 'pub fn test() -> impl Traitwhere u8: Trait' pub fn test() -> impl Trait where u8: Trait { 2u8 } diff --git a/src/test/rustdoc/generic-associated-types/gats.rs b/src/test/rustdoc/generic-associated-types/gats.rs index ae981b9499a6..2b9d4952d04e 100644 --- a/src/test/rustdoc/generic-associated-types/gats.rs +++ b/src/test/rustdoc/generic-associated-types/gats.rs @@ -3,7 +3,7 @@ // @has foo/trait.LendingIterator.html pub trait LendingIterator { - // @has - '//*[@id="associatedtype.Item"]//h4[@class="code-header"]' "type Item<'a> where Self: 'a" + // @has - '//*[@id="associatedtype.Item"]//h4[@class="code-header"]' "type Item<'a>where Self: 'a" type Item<'a> where Self: 'a; // @has - '//*[@id="tymethod.next"]//h4[@class="code-header"]' \ @@ -24,7 +24,7 @@ impl LendingIterator for () { pub struct Infinite(T); // @has foo/trait.LendingIterator.html -// @has - '//*[@id="associatedtype.Item-2"]//h4[@class="code-header"]' "type Item<'a> where Self: 'a = &'a T" +// @has - '//*[@id="associatedtype.Item-2"]//h4[@class="code-header"]' "type Item<'a>where Self: 'a = &'a T" impl LendingIterator for Infinite { type Item<'a> where Self: 'a = &'a T; diff --git a/src/test/rustdoc/higher-ranked-trait-bounds.rs b/src/test/rustdoc/higher-ranked-trait-bounds.rs index b75b8de52f9c..59b5b6e5797c 100644 --- a/src/test/rustdoc/higher-ranked-trait-bounds.rs +++ b/src/test/rustdoc/higher-ranked-trait-bounds.rs @@ -4,7 +4,7 @@ pub trait Trait<'x> {} // @has foo/fn.test1.html -// @has - '//pre' "pub fn test1() where for<'a> &'a T: Iterator," +// @has - '//pre' "pub fn test1()where for<'a> &'a T: Iterator," pub fn test1() where for<'a> &'a T: Iterator, @@ -12,7 +12,7 @@ where } // @has foo/fn.test2.html -// @has - '//pre' "pub fn test2() where for<'a, 'b> &'a T: Trait<'b>," +// @has - '//pre' "pub fn test2()where for<'a, 'b> &'a T: Trait<'b>," pub fn test2() where for<'a, 'b> &'a T: Trait<'b>, @@ -20,7 +20,7 @@ where } // @has foo/fn.test3.html -// @has - '//pre' "pub fn test3() where F: for<'a, 'b> Fn(&'a u8, &'b u8)," +// @has - '//pre' "pub fn test3()where F: for<'a, 'b> Fn(&'a u8, &'b u8)," pub fn test3() where F: for<'a, 'b> Fn(&'a u8, &'b u8), @@ -38,7 +38,7 @@ pub struct Foo<'a> { // @has - '//span[@id="structfield.some_trait"]' "some_trait: &'a dyn for<'b> Trait<'b>" impl<'a> Foo<'a> { - // @has - '//h4[@class="code-header"]' "pub fn bar() where T: Trait<'a>," + // @has - '//h4[@class="code-header"]' "pub fn bar()where T: Trait<'a>," pub fn bar() where T: Trait<'a>, diff --git a/src/test/rustdoc/impl-parts.rs b/src/test/rustdoc/impl-parts.rs index 249158c1a1f8..b1481e1f2797 100644 --- a/src/test/rustdoc/impl-parts.rs +++ b/src/test/rustdoc/impl-parts.rs @@ -6,7 +6,7 @@ pub auto trait AnAutoTrait {} pub struct Foo { field: T } // @has impl_parts/struct.Foo.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ -// "impl !AnAutoTrait for Foo where T: Sync," +// "impl !AnAutoTrait for Foowhere T: Sync," // @has impl_parts/trait.AnAutoTrait.html '//*[@class="item-list"]//h3[@class="code-header in-band"]' \ -// "impl !AnAutoTrait for Foo where T: Sync," +// "impl !AnAutoTrait for Foowhere T: Sync," impl !AnAutoTrait for Foo where T: Sync {} diff --git a/src/test/rustdoc/issue-20727-4.rs b/src/test/rustdoc/issue-20727-4.rs index 84fc6f94a265..643f93875909 100644 --- a/src/test/rustdoc/issue-20727-4.rs +++ b/src/test/rustdoc/issue-20727-4.rs @@ -25,7 +25,7 @@ pub trait IndexMut: Index { pub mod reexport { // @has issue_20727_4/reexport/trait.Index.html - // @has - '//*[@class="rust trait"]' 'trait Index where Idx: ?Sized, {' + // @has - '//*[@class="rust trait"]' 'trait Indexwhere Idx: ?Sized,{' // @has - '//*[@class="rust trait"]' 'type Output: ?Sized' // @has - '//*[@class="rust trait"]' \ // 'fn index(&self, index: Idx) -> &Self::Output' @@ -33,7 +33,7 @@ pub mod reexport { // @has issue_20727_4/reexport/trait.IndexMut.html // @has - '//*[@class="rust trait"]' \ - // 'trait IndexMut: Index where Idx: ?Sized, {' + // 'trait IndexMut: Indexwhere Idx: ?Sized,{' // @has - '//*[@class="rust trait"]' \ // 'fn index_mut(&mut self, index: Idx) -> &mut Self::Output;' pub use issue_20727::IndexMut; diff --git a/src/test/rustdoc/issue-21801.rs b/src/test/rustdoc/issue-21801.rs index 2a586b6ff6cd..29d2ec64c206 100644 --- a/src/test/rustdoc/issue-21801.rs +++ b/src/test/rustdoc/issue-21801.rs @@ -5,5 +5,5 @@ extern crate issue_21801; // @has issue_21801/struct.Foo.html // @has - '//*[@id="method.new"]' \ -// 'fn new(f: F) -> Foo where F: FnMut() -> i32' +// 'fn new(f: F) -> Foowhere F: FnMut() -> i32' pub use issue_21801::Foo; diff --git a/src/test/rustdoc/issue-29503.rs b/src/test/rustdoc/issue-29503.rs index 635c3175f813..134821e1ef3e 100644 --- a/src/test/rustdoc/issue-29503.rs +++ b/src/test/rustdoc/issue-29503.rs @@ -5,7 +5,7 @@ pub trait MyTrait { fn my_string(&self) -> String; } -// @has - "//div[@id='implementors-list']//*[@id='impl-MyTrait-for-T']//h3[@class='code-header in-band']" "impl MyTrait for T where T: Debug" +// @has - "//div[@id='implementors-list']//*[@id='impl-MyTrait-for-T']//h3[@class='code-header in-band']" "impl MyTrait for Twhere T: Debug" impl MyTrait for T where T: fmt::Debug, diff --git a/src/test/rustdoc/issue-34928.rs b/src/test/rustdoc/issue-34928.rs index 4184086f622a..91b67757453d 100644 --- a/src/test/rustdoc/issue-34928.rs +++ b/src/test/rustdoc/issue-34928.rs @@ -2,5 +2,5 @@ pub trait Bar {} -// @has foo/struct.Foo.html '//pre' 'pub struct Foo(pub T) where T: Bar;' +// @has foo/struct.Foo.html '//pre' 'pub struct Foo(pub T)where T: Bar;' pub struct Foo(pub T) where T: Bar; diff --git a/src/test/rustdoc/issue-50159.rs b/src/test/rustdoc/issue-50159.rs index d88c29217023..43fb705f5899 100644 --- a/src/test/rustdoc/issue-50159.rs +++ b/src/test/rustdoc/issue-50159.rs @@ -11,8 +11,8 @@ impl Signal2 for B where B: Signal { } // @has issue_50159/struct.Switch.html -// @has - '//h3[@class="code-header in-band"]' 'impl Send for Switch where ::Item: Send' -// @has - '//h3[@class="code-header in-band"]' 'impl Sync for Switch where ::Item: Sync' +// @has - '//h3[@class="code-header in-band"]' 'impl Send for Switchwhere ::Item: Send' +// @has - '//h3[@class="code-header in-band"]' 'impl Sync for Switchwhere ::Item: Sync' // @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0 // @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5 pub struct Switch { diff --git a/src/test/rustdoc/issue-51236.rs b/src/test/rustdoc/issue-51236.rs index ee11ccc68116..aa5890a84514 100644 --- a/src/test/rustdoc/issue-51236.rs +++ b/src/test/rustdoc/issue-51236.rs @@ -8,7 +8,7 @@ pub mod traits { // @has issue_51236/struct.Owned.html // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ -// "impl Send for Owned where >::Reader: Send" +// "impl Send for Ownedwhere >::Reader: Send" pub struct Owned where T: for<'a> ::traits::Owned<'a> { marker: PhantomData<>::Reader>, } diff --git a/src/test/rustdoc/issue-54705.rs b/src/test/rustdoc/issue-54705.rs index bedaf5c4ddc3..ce0f85d25da5 100644 --- a/src/test/rustdoc/issue-54705.rs +++ b/src/test/rustdoc/issue-54705.rs @@ -1,13 +1,11 @@ pub trait ScopeHandle<'scope> {} - - // @has issue_54705/struct.ScopeFutureContents.html // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ -// "impl<'scope, S> Send for ScopeFutureContents<'scope, S> where S: Sync" +// "impl<'scope, S> Send for ScopeFutureContents<'scope, S>where S: Sync" // // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ -// "impl<'scope, S> Sync for ScopeFutureContents<'scope, S> where S: Sync" +// "impl<'scope, S> Sync for ScopeFutureContents<'scope, S>where S: Sync" pub struct ScopeFutureContents<'scope, S> where S: ScopeHandle<'scope>, { diff --git a/src/test/rustdoc/issue-98697.rs b/src/test/rustdoc/issue-98697.rs index 83e08094c095..a8841f137fec 100644 --- a/src/test/rustdoc/issue-98697.rs +++ b/src/test/rustdoc/issue-98697.rs @@ -8,7 +8,7 @@ extern crate issue_98697_reexport_with_anonymous_lifetime; -// @has issue_98697/fn.repro.html '//pre[@class="rust fn"]/code' 'fn repro() where F: Fn(&str)' +// @has issue_98697/fn.repro.html '//pre[@class="rust fn"]/code' 'fn repro()where F: Fn(&str)' // @!has issue_98697/fn.repro.html '//pre[@class="rust fn"]/code' 'for<' pub use issue_98697_reexport_with_anonymous_lifetime::repro; diff --git a/src/test/rustdoc/primitive-slice-auto-trait.rs b/src/test/rustdoc/primitive-slice-auto-trait.rs index b3f511bc1f15..7f8f74ff457a 100644 --- a/src/test/rustdoc/primitive-slice-auto-trait.rs +++ b/src/test/rustdoc/primitive-slice-auto-trait.rs @@ -7,8 +7,8 @@ // @has - '//span[@class="in-band"]' 'Primitive Type slice' // @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!' // @has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations' -// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl Send for [T] where T: Send' -// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl Sync for [T] where T: Sync' +// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl Send for [T]where T: Send' +// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl Sync for [T]where T: Sync' #[doc(primitive = "slice")] /// this is a test! mod slice_prim {} diff --git a/src/test/rustdoc/synthetic_auto/basic.rs b/src/test/rustdoc/synthetic_auto/basic.rs index 54c54fdbf68a..19138fd1aceb 100644 --- a/src/test/rustdoc/synthetic_auto/basic.rs +++ b/src/test/rustdoc/synthetic_auto/basic.rs @@ -1,6 +1,6 @@ // @has basic/struct.Foo.html -// @has - '//h3[@class="code-header in-band"]' 'impl Send for Foo where T: Send' -// @has - '//h3[@class="code-header in-band"]' 'impl Sync for Foo where T: Sync' +// @has - '//h3[@class="code-header in-band"]' 'impl Send for Foowhere T: Send' +// @has - '//h3[@class="code-header in-band"]' 'impl Sync for Foowhere T: Sync' // @count - '//*[@id="implementations-list"]//*[@class="impl has-srclink"]' 0 // @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5 pub struct Foo { diff --git a/src/test/rustdoc/synthetic_auto/complex.rs b/src/test/rustdoc/synthetic_auto/complex.rs index f9017b90caee..39f78983da2b 100644 --- a/src/test/rustdoc/synthetic_auto/complex.rs +++ b/src/test/rustdoc/synthetic_auto/complex.rs @@ -21,7 +21,7 @@ mod foo { // @has complex/struct.NotOuter.html // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ -// "impl<'a, T, K: ?Sized> Send for Outer<'a, T, K> where K: for<'b> Fn((&'b bool, &'a u8)) \ +// "impl<'a, T, K: ?Sized> Send for Outer<'a, T, K>where K: for<'b> Fn((&'b bool, &'a u8)) \ // -> &'b i8, T: MyTrait<'a>, >::MyItem: Copy, 'a: 'static" pub use foo::{Foo, Inner as NotInner, MyTrait as NotMyTrait, Outer as NotOuter}; diff --git a/src/test/rustdoc/synthetic_auto/lifetimes.rs b/src/test/rustdoc/synthetic_auto/lifetimes.rs index ee1393f9729c..0c94850e7860 100644 --- a/src/test/rustdoc/synthetic_auto/lifetimes.rs +++ b/src/test/rustdoc/synthetic_auto/lifetimes.rs @@ -10,10 +10,10 @@ where // @has lifetimes/struct.Foo.html // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ -// "impl<'c, K> Send for Foo<'c, K> where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static" +// "impl<'c, K> Send for Foo<'c, K>where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static" // // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ -// "impl<'c, K> Sync for Foo<'c, K> where K: Sync" +// "impl<'c, K> Sync for Foo<'c, K>where K: Sync" pub struct Foo<'c, K: 'c> { inner_field: Inner<'c, K>, } diff --git a/src/test/rustdoc/synthetic_auto/manual.rs b/src/test/rustdoc/synthetic_auto/manual.rs index 49bad162211b..35047e3e8c07 100644 --- a/src/test/rustdoc/synthetic_auto/manual.rs +++ b/src/test/rustdoc/synthetic_auto/manual.rs @@ -1,6 +1,6 @@ // @has manual/struct.Foo.html // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ -// 'impl Sync for Foo where T: Sync' +// 'impl Sync for Foowhere T: Sync' // // @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ // 'impl Send for Foo' diff --git a/src/test/rustdoc/synthetic_auto/nested.rs b/src/test/rustdoc/synthetic_auto/nested.rs index 69edbee619e3..09587bcc30f1 100644 --- a/src/test/rustdoc/synthetic_auto/nested.rs +++ b/src/test/rustdoc/synthetic_auto/nested.rs @@ -10,10 +10,10 @@ where // @has nested/struct.Foo.html // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ -// 'impl Send for Foo where T: Copy' +// 'impl Send for Foowhere T: Copy' // // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ -// 'impl Sync for Foo where T: Sync' +// 'impl Sync for Foowhere T: Sync' pub struct Foo { inner_field: Inner, } diff --git a/src/test/rustdoc/synthetic_auto/no-redundancy.rs b/src/test/rustdoc/synthetic_auto/no-redundancy.rs index 16ab876e829e..41375decc8a4 100644 --- a/src/test/rustdoc/synthetic_auto/no-redundancy.rs +++ b/src/test/rustdoc/synthetic_auto/no-redundancy.rs @@ -10,7 +10,7 @@ where // @has no_redundancy/struct.Outer.html // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ -// "impl Send for Outer where T: Send + Copy" +// "impl Send for Outerwhere T: Send + Copy" pub struct Outer { inner_field: Inner, } diff --git a/src/test/rustdoc/synthetic_auto/project.rs b/src/test/rustdoc/synthetic_auto/project.rs index 8b020582563f..e80b1b1dc9bc 100644 --- a/src/test/rustdoc/synthetic_auto/project.rs +++ b/src/test/rustdoc/synthetic_auto/project.rs @@ -24,10 +24,10 @@ where // @has project/struct.Foo.html // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ -// "impl<'c, K> Send for Foo<'c, K> where K: MyTrait, 'c: 'static" +// "impl<'c, K> Send for Foo<'c, K>where K: MyTrait, 'c: 'static" // // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ -// "impl<'c, K> Sync for Foo<'c, K> where K: MyTrait, ::MyItem: OtherTrait, \ +// "impl<'c, K> Sync for Foo<'c, K>where K: MyTrait, ::MyItem: OtherTrait, \ // 'c: 'static," pub struct Foo<'c, K: 'c> { inner_field: Inner<'c, K>, diff --git a/src/test/rustdoc/synthetic_auto/self-referential.rs b/src/test/rustdoc/synthetic_auto/self-referential.rs index ccef901b18da..d15a8de7d2fe 100644 --- a/src/test/rustdoc/synthetic_auto/self-referential.rs +++ b/src/test/rustdoc/synthetic_auto/self-referential.rs @@ -24,6 +24,6 @@ impl Pattern for Wrapper { // @has self_referential/struct.WriteAndThen.html // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ -// "impl Send for WriteAndThen where ::Value: Send" +// "impl Send for WriteAndThenwhere ::Value: Send" pub struct WriteAndThen(pub P1::Value,pub > as Pattern>::Value) where P1: Pattern; diff --git a/src/test/rustdoc/synthetic_auto/static-region.rs b/src/test/rustdoc/synthetic_auto/static-region.rs index 36e985144b0e..08e9567313e2 100644 --- a/src/test/rustdoc/synthetic_auto/static-region.rs +++ b/src/test/rustdoc/synthetic_auto/static-region.rs @@ -4,7 +4,7 @@ pub trait OwnedTrait<'a> { // @has static_region/struct.Owned.html // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ -// "impl Send for Owned where >::Reader: Send" +// "impl Send for Ownedwhere >::Reader: Send" pub struct Owned where T: OwnedTrait<'static> { marker: >::Reader, } diff --git a/src/test/rustdoc/where-clause-order.rs b/src/test/rustdoc/where-clause-order.rs index 3150a8ea05f4..b8502e10a48c 100644 --- a/src/test/rustdoc/where-clause-order.rs +++ b/src/test/rustdoc/where-clause-order.rs @@ -7,7 +7,7 @@ where } // @has 'foo/trait.SomeTrait.html' -// @has - "//*[@id='impl-SomeTrait%3C(A%2C%20B%2C%20C%2C%20D%2C%20E)%3E-for-(A%2C%20B%2C%20C%2C%20D%2C%20E)']/h3" "impl SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E) where A: PartialOrd + PartialEq, B: PartialOrd + PartialEq, C: PartialOrd + PartialEq, D: PartialOrd + PartialEq, E: PartialOrd + PartialEq + ?Sized, " +// @has - "//*[@id='impl-SomeTrait%3C(A%2C%20B%2C%20C%2C%20D%2C%20E)%3E-for-(A%2C%20B%2C%20C%2C%20D%2C%20E)']/h3" "impl SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E)where A: PartialOrd + PartialEq, B: PartialOrd + PartialEq, C: PartialOrd + PartialEq, D: PartialOrd + PartialEq, E: PartialOrd + PartialEq + ?Sized, " impl SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E) where A: PartialOrd + PartialEq, diff --git a/src/test/rustdoc/where.rs b/src/test/rustdoc/where.rs index 50a5722fbaff..c1a630e25ba0 100644 --- a/src/test/rustdoc/where.rs +++ b/src/test/rustdoc/where.rs @@ -3,17 +3,17 @@ pub trait MyTrait { fn dummy(&self) { } } -// @has foo/struct.Alpha.html '//pre' "pub struct Alpha(_) where A: MyTrait" +// @has foo/struct.Alpha.html '//pre' "pub struct Alpha(_)where A: MyTrait" pub struct Alpha(A) where A: MyTrait; -// @has foo/trait.Bravo.html '//pre' "pub trait Bravo where B: MyTrait" +// @has foo/trait.Bravo.html '//pre' "pub trait Bravowhere B: MyTrait" pub trait Bravo where B: MyTrait { fn get(&self, B: B); } -// @has foo/fn.charlie.html '//pre' "pub fn charlie() where C: MyTrait" +// @has foo/fn.charlie.html '//pre' "pub fn charlie()where C: MyTrait" pub fn charlie() where C: MyTrait {} pub struct Delta(D); // @has foo/struct.Delta.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ -// "impl Delta where D: MyTrait" +// "impl Deltawhere D: MyTrait" impl Delta where D: MyTrait { pub fn delta() {} } @@ -33,19 +33,19 @@ pub trait TraitWhere { } // @has foo/struct.Echo.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ -// "impl MyTrait for Echo where E: MyTrait" +// "impl MyTrait for Echowhere E: MyTrait" // @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header in-band"]' \ -// "impl MyTrait for Echo where E: MyTrait" -impl MyTrait for Echo where E: MyTrait {} +// "impl MyTrait for Echowhere E: MyTrait" +impl MyTrait for Echowhere E: MyTrait {} pub enum Foxtrot { Foxtrot1(F) } // @has foo/enum.Foxtrot.html '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \ -// "impl MyTrait for Foxtrot where F: MyTrait" +// "impl MyTrait for Foxtrotwhere F: MyTrait" // @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//h3[@class="code-header in-band"]' \ -// "impl MyTrait for Foxtrot where F: MyTrait" -impl MyTrait for Foxtrot where F: MyTrait {} +// "impl MyTrait for Foxtrotwhere F: MyTrait" +impl MyTrait for Foxtrotwhere F: MyTrait {} // @has foo/type.Golf.html '//pre[@class="rust typedef"]' \ -// "type Golf where T: Clone, = (T, T)" +// "type Golfwhere T: Clone, = (T, T)" pub type Golf where T: Clone = (T, T); From b112bfeda9dba77c6d7e8eef92125e7002c43e68 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 31 Aug 2022 18:13:59 +0200 Subject: [PATCH 4000/5092] Add rustdoc GUI test --- src/test/rustdoc-gui/where-whitespace.goml | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/test/rustdoc-gui/where-whitespace.goml diff --git a/src/test/rustdoc-gui/where-whitespace.goml b/src/test/rustdoc-gui/where-whitespace.goml new file mode 100644 index 000000000000..1a3ff1f491cb --- /dev/null +++ b/src/test/rustdoc-gui/where-whitespace.goml @@ -0,0 +1,27 @@ +// This test ensures that the where conditions are correctly displayed. +goto: file://|DOC_PATH|/lib2/trait.Whitespace.html +show-text: true +// First, we check in the trait definition if the where clause is "on its own" (not on the same +// line than "pub trait Whitespace"). +compare-elements-position-false: (".item-decl code", ".where.fmt-newline", ("y")) +// And that the code following it isn't on the same line either. +compare-elements-position-false: (".item-decl .fnname", ".where.fmt-newline", ("y")) + +goto: file://|DOC_PATH|/lib2/struct.WhereWhitespace.html +// We make the screen a bit wider to ensure that the trait impl is on one line. +size: (915, 915) + +compare-elements-position-false: ("#method\.new .fnname", "#method\.new .where.fmt-newline", ("y")) +// We ensure that both the trait name and the struct name are on the same line in +// "impl Whitespace<&K> for WhereWhitespace". +compare-elements-position: ( + "#trait-implementations-list .impl h3 .trait", + "#trait-implementations-list .impl h3 .struct", + ("y"), +) +// And we now check that the where condition isn't on the same line. +compare-elements-position-false: ( + "#trait-implementations-list .impl h3 .trait", + "#trait-implementations-list .impl h3 .where.fmt-newline", + ("y"), +) From d21b601b6e89746378e020a1e4a6f3d7e98bc5c4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Aug 2022 15:59:27 -0400 Subject: [PATCH 4001/5092] make Miri build again with rustc provenance changes --- src/diagnostics.rs | 7 +-- src/helpers.rs | 2 +- src/machine.rs | 15 ++++++ src/shims/foreign_items.rs | 8 +-- src/shims/unix/fs.rs | 2 +- src/shims/windows/dlsym.rs | 3 +- tests/fail/copy_half_a_pointer.rs | 21 ++++++++ tests/fail/copy_half_a_pointer.stderr | 14 +++++ tests/fail/intrinsics/raw_eq_on_ptr.rs | 3 +- tests/fail/intrinsics/raw_eq_on_ptr.stderr | 7 +-- tests/fail/invalid_int.rs | 1 + tests/fail/reading_half_a_pointer.rs | 3 +- tests/fail/reading_half_a_pointer.stderr | 9 ++-- tests/fail/transmute_fat1.rs | 13 ----- tests/fail/transmute_fat1.stderr | 15 ------ tests/fail/validity/invalid_bool_uninit.rs | 4 +- .../fail/validity/invalid_bool_uninit.stderr | 4 +- tests/fail/validity/invalid_char_uninit.rs | 4 +- .../fail/validity/invalid_char_uninit.stderr | 4 +- tests/fail/validity/invalid_fnptr_uninit.rs | 4 +- .../fail/validity/invalid_fnptr_uninit.stderr | 4 +- .../validity/ptr_integer_array_transmute.rs | 4 -- .../ptr_integer_array_transmute.stderr | 15 ------ tests/fail/validity/uninit_float.rs | 5 +- tests/fail/validity/uninit_float.stderr | 6 +-- tests/fail/validity/uninit_integer.rs | 4 +- tests/fail/validity/uninit_integer.stderr | 6 +-- tests/fail/validity/uninit_raw_ptr.rs | 5 +- tests/fail/validity/uninit_raw_ptr.stderr | 6 +-- tests/pass/transmute_fat.rs | 10 ---- tests/pass/transmute_ptr.rs | 52 +++++++++++++++++++ 31 files changed, 158 insertions(+), 102 deletions(-) create mode 100644 tests/fail/copy_half_a_pointer.rs create mode 100644 tests/fail/copy_half_a_pointer.stderr delete mode 100644 tests/fail/transmute_fat1.rs delete mode 100644 tests/fail/transmute_fat1.stderr delete mode 100644 tests/fail/validity/ptr_integer_array_transmute.rs delete mode 100644 tests/fail/validity/ptr_integer_array_transmute.stderr delete mode 100644 tests/pass/transmute_fat.rs create mode 100644 tests/pass/transmute_ptr.rs diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 74d2fe2680a4..8ba2995662ba 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -226,13 +226,14 @@ pub fn report_error<'tcx, 'mir>( let helps = match e.kind() { Unsupported( UnsupportedOpInfo::ThreadLocalStatic(_) | - UnsupportedOpInfo::ReadExternStatic(_) + UnsupportedOpInfo::ReadExternStatic(_) | + UnsupportedOpInfo::PartialPointerOverwrite(_) | // we make memory uninit instead + UnsupportedOpInfo::ReadPointerAsBytes ) => panic!("Error should never be raised by Miri: {kind:?}", kind = e.kind()), Unsupported( UnsupportedOpInfo::Unsupported(_) | - UnsupportedOpInfo::PartialPointerOverwrite(_) | - UnsupportedOpInfo::ReadPointerAsBytes + UnsupportedOpInfo::PartialPointerCopy(_) ) => vec![(None, format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"))], UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. }) diff --git a/src/helpers.rs b/src/helpers.rs index 92139d9aa2a9..57c9fd3389ce 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -757,7 +757,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Step 2: get the bytes. - this.read_bytes_ptr(ptr, len) + this.read_bytes_ptr_strip_provenance(ptr, len) } fn read_wide_str(&self, mut ptr: Pointer>) -> InterpResult<'tcx, Vec> { diff --git a/src/machine.rs b/src/machine.rs index 3be4d1d1b5bc..b7624ac5922d 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -205,6 +205,21 @@ impl interpret::Provenance for Provenance { Provenance::Wildcard => None, } } + + fn join(left: Option, right: Option) -> Option { + match (left, right) { + // If both are the *same* concrete tag, that is the result. + ( + Some(Provenance::Concrete { alloc_id: left_alloc, sb: left_sb }), + Some(Provenance::Concrete { alloc_id: right_alloc, sb: right_sb }), + ) if left_alloc == right_alloc && left_sb == right_sb => left, + // If one side is a wildcard, the best possible outcome is that it is equal to the other + // one, and we use that. + (Some(Provenance::Wildcard), o) | (o, Some(Provenance::Wildcard)) => o, + // Otherwise, fall back to `None`. + _ => None, + } + } } impl fmt::Debug for ProvenanceExtra { diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 117e0933ddcf..b94b6bbb2b8b 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -560,8 +560,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let n = Size::from_bytes(this.read_scalar(n)?.to_machine_usize(this)?); let result = { - let left_bytes = this.read_bytes_ptr(left, n)?; - let right_bytes = this.read_bytes_ptr(right, n)?; + let left_bytes = this.read_bytes_ptr_strip_provenance(left, n)?; + let right_bytes = this.read_bytes_ptr_strip_provenance(right, n)?; use std::cmp::Ordering::*; match left_bytes.cmp(right_bytes) { @@ -583,7 +583,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val = val as u8; if let Some(idx) = this - .read_bytes_ptr(ptr, Size::from_bytes(num))? + .read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(num))? .iter() .rev() .position(|&c| c == val) @@ -606,7 +606,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val = val as u8; let idx = this - .read_bytes_ptr(ptr, Size::from_bytes(num))? + .read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(num))? .iter() .position(|&c| c == val); if let Some(idx) = idx { diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index d3f4f5ef5451..06cd533626a5 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -761,7 +761,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let communicate = this.machine.communicate(); if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { - let bytes = this.read_bytes_ptr(buf, Size::from_bytes(count))?; + let bytes = this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(count))?; let result = file_descriptor.write(communicate, bytes)?.map(|c| i64::try_from(c).unwrap()); this.try_unwrap_io_result(result) diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 5cbfecb889a2..8749ed91bb4b 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -78,7 +78,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // stdout/stderr use std::io::{self, Write}; - let buf_cont = this.read_bytes_ptr(buf, Size::from_bytes(u64::from(n)))?; + let buf_cont = + this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(u64::from(n)))?; let res = if this.machine.mute_stdout_stderr { Ok(buf_cont.len()) } else if handle == -11 { diff --git a/tests/fail/copy_half_a_pointer.rs b/tests/fail/copy_half_a_pointer.rs new file mode 100644 index 000000000000..e1dcdda7fdfe --- /dev/null +++ b/tests/fail/copy_half_a_pointer.rs @@ -0,0 +1,21 @@ +//@normalize-stderr-test: "\+0x[48]" -> "+HALF_PTR" +#![allow(dead_code)] + +// We use packed structs to get around alignment restrictions +#[repr(packed)] +struct Data { + pad: u8, + ptr: &'static i32, +} + +static G: i32 = 0; + +fn main() { + let mut d = Data { pad: 0, ptr: &G }; + + // Get a pointer to the beginning of the Data struct (one u8 byte, then the pointer bytes). + let d_alias = &mut d as *mut _ as *mut *const u8; + unsafe { + let _x = d_alias.read_unaligned(); //~ERROR: unable to copy parts of a pointer + } +} diff --git a/tests/fail/copy_half_a_pointer.stderr b/tests/fail/copy_half_a_pointer.stderr new file mode 100644 index 000000000000..21797757084e --- /dev/null +++ b/tests/fail/copy_half_a_pointer.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: unable to copy parts of a pointer from memory at ALLOC+HALF_PTR + --> $DIR/copy_half_a_pointer.rs:LL:CC + | +LL | let _x = d_alias.read_unaligned(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ unable to copy parts of a pointer from memory at ALLOC+HALF_PTR + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = note: BACKTRACE: + = note: inside `main` at $DIR/copy_half_a_pointer.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/intrinsics/raw_eq_on_ptr.rs b/tests/fail/intrinsics/raw_eq_on_ptr.rs index 675b7cf9224b..c14f86147dbb 100644 --- a/tests/fail/intrinsics/raw_eq_on_ptr.rs +++ b/tests/fail/intrinsics/raw_eq_on_ptr.rs @@ -6,6 +6,5 @@ extern "rust-intrinsic" { fn main() { let x = &0; - // FIXME: the error message is not great (should be UB rather than 'unsupported') - unsafe { raw_eq(&x, &x) }; //~ERROR: unsupported operation + unsafe { raw_eq(&x, &x) }; //~ERROR: `raw_eq` on bytes with provenance } diff --git a/tests/fail/intrinsics/raw_eq_on_ptr.stderr b/tests/fail/intrinsics/raw_eq_on_ptr.stderr index c6ed1750c04e..2236ad9839c5 100644 --- a/tests/fail/intrinsics/raw_eq_on_ptr.stderr +++ b/tests/fail/intrinsics/raw_eq_on_ptr.stderr @@ -1,10 +1,11 @@ -error: unsupported operation: unable to turn pointer into raw bytes +error: Undefined Behavior: `raw_eq` on bytes with provenance --> $DIR/raw_eq_on_ptr.rs:LL:CC | LL | unsafe { raw_eq(&x, &x) }; - | ^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^ `raw_eq` on bytes with provenance | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: = note: inside `main` at $DIR/raw_eq_on_ptr.rs:LL:CC diff --git a/tests/fail/invalid_int.rs b/tests/fail/invalid_int.rs index b51af24c134b..2435a87a6f28 100644 --- a/tests/fail/invalid_int.rs +++ b/tests/fail/invalid_int.rs @@ -1,3 +1,4 @@ +#![allow(invalid_value)] // Validation makes this fail in the wrong place // Make sure we find these even with many checks disabled. //@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation diff --git a/tests/fail/reading_half_a_pointer.rs b/tests/fail/reading_half_a_pointer.rs index a8cdb11f40ba..2d6691326247 100644 --- a/tests/fail/reading_half_a_pointer.rs +++ b/tests/fail/reading_half_a_pointer.rs @@ -24,6 +24,7 @@ fn main() { // starts 1 byte to the right, so using it would actually be wrong! let d_alias = &mut w.data as *mut _ as *mut *const u8; unsafe { - let _x = *d_alias; //~ ERROR: unable to turn pointer into raw bytes + let x = *d_alias; + let _val = *x; //~ERROR: is a dangling pointer (it has no provenance) } } diff --git a/tests/fail/reading_half_a_pointer.stderr b/tests/fail/reading_half_a_pointer.stderr index 28cd7cef2433..61a7161a98bb 100644 --- a/tests/fail/reading_half_a_pointer.stderr +++ b/tests/fail/reading_half_a_pointer.stderr @@ -1,10 +1,11 @@ -error: unsupported operation: unable to turn pointer into raw bytes +error: Undefined Behavior: dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) --> $DIR/reading_half_a_pointer.rs:LL:CC | -LL | let _x = *d_alias; - | ^^^^^^^^ unable to turn pointer into raw bytes +LL | let _val = *x; + | ^^ dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: = note: inside `main` at $DIR/reading_half_a_pointer.rs:LL:CC diff --git a/tests/fail/transmute_fat1.rs b/tests/fail/transmute_fat1.rs deleted file mode 100644 index a60efb98f9d8..000000000000 --- a/tests/fail/transmute_fat1.rs +++ /dev/null @@ -1,13 +0,0 @@ -#[cfg(target_pointer_width = "64")] -const N: usize = 16; - -#[cfg(target_pointer_width = "32")] -const N: usize = 8; - -fn main() { - let bad = unsafe { - std::mem::transmute::<&[u8], [u8; N]>(&[1u8]) - //~^ ERROR: constructing invalid value: encountered a pointer - }; - let _val = bad[0] + bad[bad.len() - 1]; -} diff --git a/tests/fail/transmute_fat1.stderr b/tests/fail/transmute_fat1.stderr deleted file mode 100644 index e1907e080194..000000000000 --- a/tests/fail/transmute_fat1.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: constructing invalid value: encountered a pointer, but expected plain (non-pointer) bytes - --> $DIR/transmute_fat1.rs:LL:CC - | -LL | std::mem::transmute::<&[u8], [u8; N]>(&[1u8]) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a pointer, but expected plain (non-pointer) bytes - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `main` at $DIR/transmute_fat1.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/validity/invalid_bool_uninit.rs b/tests/fail/validity/invalid_bool_uninit.rs index 84a221a469a7..ce4fdcabd047 100644 --- a/tests/fail/validity/invalid_bool_uninit.rs +++ b/tests/fail/validity/invalid_bool_uninit.rs @@ -2,9 +2,9 @@ union MyUninit { init: (), - uninit: bool, + uninit: [bool; 1], } fn main() { - let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: uninitialized + let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: constructing invalid value } diff --git a/tests/fail/validity/invalid_bool_uninit.stderr b/tests/fail/validity/invalid_bool_uninit.stderr index 2dbd102d9833..5a7bd80e40c1 100644 --- a/tests/fail/validity/invalid_bool_uninit.stderr +++ b/tests/fail/validity/invalid_bool_uninit.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: constructing invalid value at [0]: encountered uninitialized memory, but expected a boolean --> $DIR/invalid_bool_uninit.rs:LL:CC | LL | let _b = unsafe { MyUninit { init: () }.uninit }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered uninitialized memory, but expected a boolean | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/invalid_char_uninit.rs b/tests/fail/validity/invalid_char_uninit.rs index c16e26649076..0e3c3ccac6f2 100644 --- a/tests/fail/validity/invalid_char_uninit.rs +++ b/tests/fail/validity/invalid_char_uninit.rs @@ -2,9 +2,9 @@ union MyUninit { init: (), - uninit: char, + uninit: [char; 1], } fn main() { - let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: uninitialized + let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: constructing invalid value } diff --git a/tests/fail/validity/invalid_char_uninit.stderr b/tests/fail/validity/invalid_char_uninit.stderr index c59bbedd0ab8..fb5d3ee1f1f9 100644 --- a/tests/fail/validity/invalid_char_uninit.stderr +++ b/tests/fail/validity/invalid_char_uninit.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: constructing invalid value at [0]: encountered uninitialized memory, but expected a unicode scalar value --> $DIR/invalid_char_uninit.rs:LL:CC | LL | let _b = unsafe { MyUninit { init: () }.uninit }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered uninitialized memory, but expected a unicode scalar value | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/invalid_fnptr_uninit.rs b/tests/fail/validity/invalid_fnptr_uninit.rs index c857d83bde0d..014a8ae847a7 100644 --- a/tests/fail/validity/invalid_fnptr_uninit.rs +++ b/tests/fail/validity/invalid_fnptr_uninit.rs @@ -2,9 +2,9 @@ union MyUninit { init: (), - uninit: fn(), + uninit: [fn(); 1], } fn main() { - let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: uninitialized + let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: constructing invalid value } diff --git a/tests/fail/validity/invalid_fnptr_uninit.stderr b/tests/fail/validity/invalid_fnptr_uninit.stderr index 15ae78e35db2..35309e90136c 100644 --- a/tests/fail/validity/invalid_fnptr_uninit.stderr +++ b/tests/fail/validity/invalid_fnptr_uninit.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: constructing invalid value at [0]: encountered uninitialized memory, but expected a function pointer --> $DIR/invalid_fnptr_uninit.rs:LL:CC | LL | let _b = unsafe { MyUninit { init: () }.uninit }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered uninitialized memory, but expected a function pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/ptr_integer_array_transmute.rs b/tests/fail/validity/ptr_integer_array_transmute.rs deleted file mode 100644 index c8613d274c81..000000000000 --- a/tests/fail/validity/ptr_integer_array_transmute.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn main() { - let r = &mut 42; - let _i: [usize; 1] = unsafe { std::mem::transmute(r) }; //~ ERROR: encountered a pointer, but expected plain (non-pointer) bytes -} diff --git a/tests/fail/validity/ptr_integer_array_transmute.stderr b/tests/fail/validity/ptr_integer_array_transmute.stderr deleted file mode 100644 index 118c6a4327cd..000000000000 --- a/tests/fail/validity/ptr_integer_array_transmute.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: constructing invalid value: encountered a pointer, but expected plain (non-pointer) bytes - --> $DIR/ptr_integer_array_transmute.rs:LL:CC - | -LL | let _i: [usize; 1] = unsafe { std::mem::transmute(r) }; - | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a pointer, but expected plain (non-pointer) bytes - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `main` at $DIR/ptr_integer_array_transmute.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/validity/uninit_float.rs b/tests/fail/validity/uninit_float.rs index fecc02d7a505..045bb46464fa 100644 --- a/tests/fail/validity/uninit_float.rs +++ b/tests/fail/validity/uninit_float.rs @@ -1,8 +1,9 @@ -#![allow(deprecated)] +#![allow(deprecated, invalid_value)] // This test is adapted from https://github.com/rust-lang/miri/issues/1340#issue-600900312. fn main() { // Deliberately using `mem::uninitialized` to make sure that despite all the mitigations, we consider this UB. - let _val: f32 = unsafe { std::mem::uninitialized() }; + // The array avoids a `Scalar` layout which detects uninit without even doing validation. + let _val: [f32; 1] = unsafe { std::mem::uninitialized() }; //~^ ERROR: uninitialized } diff --git a/tests/fail/validity/uninit_float.stderr b/tests/fail/validity/uninit_float.stderr index c64f56e25516..677a0fc5570d 100644 --- a/tests/fail/validity/uninit_float.stderr +++ b/tests/fail/validity/uninit_float.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: constructing invalid value at .value[0]: encountered uninitialized bytes --> $DIR/uninit_float.rs:LL:CC | -LL | let _val: f32 = unsafe { std::mem::uninitialized() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory +LL | let _val: [f32; 1] = unsafe { std::mem::uninitialized() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value[0]: encountered uninitialized bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/uninit_integer.rs b/tests/fail/validity/uninit_integer.rs index a9b200732653..a94302603a21 100644 --- a/tests/fail/validity/uninit_integer.rs +++ b/tests/fail/validity/uninit_integer.rs @@ -1,6 +1,8 @@ +#![allow(invalid_value)] // This test is from https://github.com/rust-lang/miri/issues/1340#issue-600900312. fn main() { - let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + // The array avoids a `Scalar` layout which detects uninit without even doing validation. + let _val = unsafe { std::mem::MaybeUninit::<[usize; 1]>::uninit().assume_init() }; //~^ ERROR: uninitialized } diff --git a/tests/fail/validity/uninit_integer.stderr b/tests/fail/validity/uninit_integer.stderr index 5828eba7939c..a9ac2a6dc67e 100644 --- a/tests/fail/validity/uninit_integer.stderr +++ b/tests/fail/validity/uninit_integer.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: constructing invalid value at .value[0]: encountered uninitialized bytes --> $DIR/uninit_integer.rs:LL:CC | -LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory +LL | let _val = unsafe { std::mem::MaybeUninit::<[usize; 1]>::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value[0]: encountered uninitialized bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/uninit_raw_ptr.rs b/tests/fail/validity/uninit_raw_ptr.rs index 9f99dc1a0e11..18703152ea10 100644 --- a/tests/fail/validity/uninit_raw_ptr.rs +++ b/tests/fail/validity/uninit_raw_ptr.rs @@ -1,4 +1,7 @@ +#![allow(invalid_value)] + fn main() { - let _val = unsafe { std::mem::MaybeUninit::<*const u8>::uninit().assume_init() }; + // The array avoids a `Scalar` layout which detects uninit without even doing validation. + let _val = unsafe { std::mem::MaybeUninit::<[*const u8; 1]>::uninit().assume_init() }; //~^ ERROR: uninitialized } diff --git a/tests/fail/validity/uninit_raw_ptr.stderr b/tests/fail/validity/uninit_raw_ptr.stderr index 68f7d2af6a5d..bbae9cf69ffe 100644 --- a/tests/fail/validity/uninit_raw_ptr.stderr +++ b/tests/fail/validity/uninit_raw_ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: constructing invalid value at .value[0]: encountered uninitialized memory, but expected a raw pointer --> $DIR/uninit_raw_ptr.rs:LL:CC | -LL | let _val = unsafe { std::mem::MaybeUninit::<*const u8>::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory +LL | let _val = unsafe { std::mem::MaybeUninit::<[*const u8; 1]>::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value[0]: encountered uninitialized memory, but expected a raw pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/pass/transmute_fat.rs b/tests/pass/transmute_fat.rs deleted file mode 100644 index dfd78ace520c..000000000000 --- a/tests/pass/transmute_fat.rs +++ /dev/null @@ -1,10 +0,0 @@ -// Stacked Borrows disallows this becuase the reference is never cast to a raw pointer. -//@compile-flags: -Zmiri-disable-stacked-borrows - -fn main() { - // If we are careful, we can exploit data layout... - // This is a tricky case since we are transmuting a ScalarPair type to a non-ScalarPair type. - let raw = unsafe { std::mem::transmute::<&[u8], [*const u8; 2]>(&[42]) }; - let ptr: *const u8 = unsafe { std::mem::transmute_copy(&raw) }; - assert_eq!(unsafe { *ptr }, 42); -} diff --git a/tests/pass/transmute_ptr.rs b/tests/pass/transmute_ptr.rs new file mode 100644 index 000000000000..fd9d457e440e --- /dev/null +++ b/tests/pass/transmute_ptr.rs @@ -0,0 +1,52 @@ +#![feature(strict_provenance)] +use std::{mem, ptr}; + +fn t1() { + // If we are careful, we can exploit data layout... + // This is a tricky case since we are transmuting a ScalarPair type to a non-ScalarPair type. + let raw = unsafe { mem::transmute::<&[u8], [*const u8; 2]>(&[42]) }; + let ptr: *const u8 = unsafe { mem::transmute_copy(&raw) }; + assert_eq!(unsafe { *ptr }, 42); +} + +#[cfg(target_pointer_width = "64")] +const PTR_SIZE: usize = 8; +#[cfg(target_pointer_width = "32")] +const PTR_SIZE: usize = 4; + +fn t2() { + let bad = unsafe { mem::transmute::<&[u8], [u8; 2 * PTR_SIZE]>(&[1u8]) }; + let _val = bad[0] + bad[bad.len() - 1]; +} + +fn ptr_integer_array() { + let r = &mut 42; + let _i: [usize; 1] = unsafe { mem::transmute(r) }; + + let _x: [u8; PTR_SIZE] = unsafe { mem::transmute(&0) }; +} + +fn ptr_in_two_halves() { + unsafe { + let ptr = &0 as *const i32; + let arr = [ptr; 2]; + // We want to do a scalar read of a pointer at offset PTR_SIZE/2 into this array. But we + // cannot use a packed struct or `read_unaligned`, as those use the memcpy code path in + // Miri. So instead we shift the entire array by a bit and then the actual read we want to + // do is perfectly aligned. + let mut target_arr = [ptr::null::(); 3]; + let target = target_arr.as_mut_ptr().cast::(); + target.add(PTR_SIZE / 2).cast::<[*const i32; 2]>().write_unaligned(arr); + // Now target_arr[1] is a mix of the two `ptr` we had stored in `arr`. + let strange_ptr = target_arr[1]; + // Check that the provenance works out. + assert_eq!(*strange_ptr.with_addr(ptr.addr()), 0); + } +} + +fn main() { + t1(); + t2(); + ptr_integer_array(); + ptr_in_two_halves(); +} From 0113f9e727665b6fa54ef4b92766b0e40201a296 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Aug 2022 18:19:14 +0200 Subject: [PATCH 4002/5092] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index f7e2fa5a33d3..0909f24752ac 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -94b2b15e63c5d2b2a6a0910e3dae554ce9415bf9 +4fd4de7ea358ad6fc28c5780533ea8ccc09e1006 From 236903f7e9045717d7795ab12bdf349ccf276c3b Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Wed, 31 Aug 2022 18:04:15 +0200 Subject: [PATCH 4003/5092] unix_sigpipe: Inline compiler sigpipe constants in std --- compiler/rustc_session/src/config/sigpipe.rs | 2 ++ library/std/src/sys/unix/mod.rs | 12 +++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_session/src/config/sigpipe.rs b/compiler/rustc_session/src/config/sigpipe.rs index 31a3d9de05be..a5c94118a47e 100644 --- a/compiler/rustc_session/src/config/sigpipe.rs +++ b/compiler/rustc_session/src/config/sigpipe.rs @@ -1,3 +1,5 @@ +//! NOTE: Keep these constants in sync with `library/std/src/sys/unix/mod.rs`! + /// Do not touch `SIGPIPE`. Use whatever the parent process uses. #[allow(dead_code)] pub const INHERIT: u8 = 1; diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index e11201f60ff7..d701f950e863 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -155,10 +155,16 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { unsafe fn reset_sigpipe(#[allow(unused_variables)] sigpipe: u8) { #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia", target_os = "horizon")))] { - // We don't want to add this as a public type to libstd, nor do we want to - // duplicate the code, so we choose to include this compiler file like this. + // We don't want to add this as a public type to libstd, nor do we + // want to `include!` a file from the compiler (which would break + // Miri and xargo for example), so we choose to duplicate these + // constants from `compiler/rustc_session/src/config/sigpipe.rs`. + // See the other file for docs. NOTE: Make sure to keep them in + // sync! mod sigpipe { - include!("../../../../../compiler/rustc_session/src/config/sigpipe.rs"); + pub const INHERIT: u8 = 1; + pub const SIG_IGN: u8 = 2; + pub const SIG_DFL: u8 = 3; } let handler = match sigpipe { From 3d1a4e4f2792948d78b3fed030e93c9c156fe35a Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Wed, 31 Aug 2022 18:11:48 +0200 Subject: [PATCH 4004/5092] unix_sigpipe: Add docs for `init()` `sigpipe` param --- library/std/src/rt.rs | 2 ++ library/std/src/sys/unix/mod.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index 7cf3d7d41634..b3f6f82952b7 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -72,6 +72,8 @@ macro_rules! rtunwrap { // Runs before `main`. // SAFETY: must be called only once during runtime initialization. // NOTE: this is not guaranteed to run, for example when Rust code is called externally. +// The extra parameter `sigpipe` allows rustc to generate code that instructs std whether +// or not to ignore `SIGPIPE`. #[cfg_attr(test, allow(dead_code))] unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { unsafe { diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index d701f950e863..2856dfcb3707 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -49,6 +49,8 @@ pub fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {} #[cfg(not(target_os = "espidf"))] // SAFETY: must be called only once during runtime initialization. // NOTE: this is not guaranteed to run, for example when Rust code is called externally. +// The extra parameter `sigpipe` allows rustc to generate code that instructs std whether +// or not to ignore `SIGPIPE`. pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { // The standard streams might be closed on application startup. To prevent // std::io::{stdin, stdout,stderr} objects from using other unrelated file From 241807dbf9785748a76cb61358a68214fc24e013 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 31 Aug 2022 18:34:10 +0200 Subject: [PATCH 4005/5092] Allow multi-part inlay hint labels with location links --- crates/ide/src/inlay_hints.rs | 162 ++++++++++++++++++++++----- crates/ide/src/lib.rs | 4 +- crates/rust-analyzer/src/handlers.rs | 2 +- crates/rust-analyzer/src/to_proto.rs | 57 +++++++--- 4 files changed, 179 insertions(+), 46 deletions(-) diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index e9034daefa8d..4ad6aa0e0497 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -1,3 +1,5 @@ +use std::fmt; + use either::Either; use hir::{known, Callable, HasVisibility, HirDisplay, Mutability, Semantics, TypeInfo}; use ide_db::{ @@ -69,7 +71,7 @@ pub enum InlayKind { pub struct InlayHint { pub range: TextRange, pub kind: InlayKind, - pub label: String, + pub label: InlayHintLabel, pub tooltip: Option, } @@ -80,6 +82,78 @@ pub enum InlayTooltip { HoverOffset(FileId, TextSize), } +pub struct InlayHintLabel { + pub parts: Vec, +} + +impl InlayHintLabel { + pub fn as_simple_str(&self) -> Option<&str> { + match &*self.parts { + [part] => part.as_simple_str(), + _ => None, + } + } + + pub fn prepend_str(&mut self, s: &str) { + match &mut *self.parts { + [part, ..] if part.as_simple_str().is_some() => part.text = format!("{s}{}", part.text), + _ => self.parts.insert(0, InlayHintLabelPart { text: s.into(), linked_location: None }), + } + } + + pub fn append_str(&mut self, s: &str) { + match &mut *self.parts { + [.., part] if part.as_simple_str().is_some() => part.text.push_str(s), + _ => self.parts.push(InlayHintLabelPart { text: s.into(), linked_location: None }), + } + } +} + +impl From for InlayHintLabel { + fn from(s: String) -> Self { + Self { parts: vec![InlayHintLabelPart { text: s, linked_location: None }] } + } +} + +impl fmt::Display for InlayHintLabel { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.parts.iter().map(|part| &part.text).format("")) + } +} + +impl fmt::Debug for InlayHintLabel { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(&self.parts).finish() + } +} + +pub struct InlayHintLabelPart { + pub text: String, + pub linked_location: Option, +} + +impl InlayHintLabelPart { + pub fn as_simple_str(&self) -> Option<&str> { + match self { + Self { text, linked_location: None } => Some(text), + _ => None, + } + } +} + +impl fmt::Debug for InlayHintLabelPart { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.as_simple_str() { + Some(string) => string.fmt(f), + None => f + .debug_struct("InlayHintLabelPart") + .field("text", &self.text) + .field("linked_location", &self.linked_location) + .finish(), + } + } +} + // Feature: Inlay Hints // // rust-analyzer shows additional information inline with the source code. @@ -281,7 +355,7 @@ fn closing_brace_hints( acc.push(InlayHint { range: closing_token.text_range(), kind: InlayKind::ClosingBraceHint, - label, + label: label.into(), tooltip: name_offset.map(|it| InlayTooltip::HoverOffset(file_id, it)), }); @@ -311,7 +385,7 @@ fn implicit_static_hints( acc.push(InlayHint { range: t.text_range(), kind: InlayKind::LifetimeHint, - label: "'static".to_owned(), + label: "'static".to_owned().into(), tooltip: Some(InlayTooltip::String("Elided static lifetime".into())), }); } @@ -329,10 +403,10 @@ fn fn_lifetime_fn_hints( return None; } - let mk_lt_hint = |t: SyntaxToken, label| InlayHint { + let mk_lt_hint = |t: SyntaxToken, label: String| InlayHint { range: t.text_range(), kind: InlayKind::LifetimeHint, - label, + label: label.into(), tooltip: Some(InlayTooltip::String("Elided lifetime".into())), }; @@ -486,7 +560,8 @@ fn fn_lifetime_fn_hints( "{}{}", allocated_lifetimes.iter().format(", "), if is_empty { "" } else { ", " } - ), + ) + .into(), tooltip: Some(InlayTooltip::String("Elided lifetimes".into())), }); } @@ -535,7 +610,8 @@ fn closure_ret_hints( range: param_list.syntax().text_range(), kind: InlayKind::ClosureReturnTypeHint, label: hint_iterator(sema, &famous_defs, config, &ty) - .unwrap_or_else(|| ty.display_truncated(sema.db, config.max_length).to_string()), + .unwrap_or_else(|| ty.display_truncated(sema.db, config.max_length).to_string()) + .into(), tooltip: Some(InlayTooltip::HoverRanged(file_id, param_list.syntax().text_range())), }); Some(()) @@ -562,7 +638,7 @@ fn reborrow_hints( acc.push(InlayHint { range: expr.syntax().text_range(), kind: InlayKind::ImplicitReborrowHint, - label: label.to_string(), + label: label.to_string().into(), tooltip: Some(InlayTooltip::String("Compiler inserted reborrow".into())), }); Some(()) @@ -620,9 +696,9 @@ fn chaining_hints( acc.push(InlayHint { range: expr.syntax().text_range(), kind: InlayKind::ChainingHint, - label: hint_iterator(sema, &famous_defs, config, &ty).unwrap_or_else(|| { - ty.display_truncated(sema.db, config.max_length).to_string() - }), + label: hint_iterator(sema, &famous_defs, config, &ty) + .unwrap_or_else(|| ty.display_truncated(sema.db, config.max_length).to_string()) + .into(), tooltip: Some(InlayTooltip::HoverRanged(file_id, expr.syntax().text_range())), }); } @@ -674,7 +750,7 @@ fn param_name_hints( InlayHint { range, kind: InlayKind::ParameterHint, - label: param_name, + label: param_name.into(), tooltip: tooltip.map(|it| InlayTooltip::HoverOffset(it.file_id, it.range.start())), } }); @@ -705,7 +781,7 @@ fn binding_mode_hints( acc.push(InlayHint { range, kind: InlayKind::BindingModeHint, - label: r.to_string(), + label: r.to_string().into(), tooltip: Some(InlayTooltip::String("Inferred binding mode".into())), }); }); @@ -720,7 +796,7 @@ fn binding_mode_hints( acc.push(InlayHint { range, kind: InlayKind::BindingModeHint, - label: bm.to_string(), + label: bm.to_string().into(), tooltip: Some(InlayTooltip::String("Inferred binding mode".into())), }); } @@ -772,7 +848,7 @@ fn bind_pat_hints( None => pat.syntax().text_range(), }, kind: InlayKind::TypeHint, - label, + label: label.into(), tooltip: pat .name() .map(|it| it.syntax().text_range()) @@ -2223,7 +2299,9 @@ fn main() { InlayHint { range: 147..172, kind: ChainingHint, - label: "B", + label: [ + "B", + ], tooltip: Some( HoverRanged( FileId( @@ -2236,7 +2314,9 @@ fn main() { InlayHint { range: 147..154, kind: ChainingHint, - label: "A", + label: [ + "A", + ], tooltip: Some( HoverRanged( FileId( @@ -2294,7 +2374,9 @@ fn main() { InlayHint { range: 143..190, kind: ChainingHint, - label: "C", + label: [ + "C", + ], tooltip: Some( HoverRanged( FileId( @@ -2307,7 +2389,9 @@ fn main() { InlayHint { range: 143..179, kind: ChainingHint, - label: "B", + label: [ + "B", + ], tooltip: Some( HoverRanged( FileId( @@ -2350,7 +2434,9 @@ fn main() { InlayHint { range: 246..283, kind: ChainingHint, - label: "B>", + label: [ + "B>", + ], tooltip: Some( HoverRanged( FileId( @@ -2363,7 +2449,9 @@ fn main() { InlayHint { range: 246..265, kind: ChainingHint, - label: "A>", + label: [ + "A>", + ], tooltip: Some( HoverRanged( FileId( @@ -2408,7 +2496,9 @@ fn main() { InlayHint { range: 174..241, kind: ChainingHint, - label: "impl Iterator", + label: [ + "impl Iterator", + ], tooltip: Some( HoverRanged( FileId( @@ -2421,7 +2511,9 @@ fn main() { InlayHint { range: 174..224, kind: ChainingHint, - label: "impl Iterator", + label: [ + "impl Iterator", + ], tooltip: Some( HoverRanged( FileId( @@ -2434,7 +2526,9 @@ fn main() { InlayHint { range: 174..206, kind: ChainingHint, - label: "impl Iterator", + label: [ + "impl Iterator", + ], tooltip: Some( HoverRanged( FileId( @@ -2447,7 +2541,9 @@ fn main() { InlayHint { range: 174..189, kind: ChainingHint, - label: "&mut MyIter", + label: [ + "&mut MyIter", + ], tooltip: Some( HoverRanged( FileId( @@ -2489,7 +2585,9 @@ fn main() { InlayHint { range: 124..130, kind: TypeHint, - label: "Struct", + label: [ + "Struct", + ], tooltip: Some( HoverRanged( FileId( @@ -2502,7 +2600,9 @@ fn main() { InlayHint { range: 145..185, kind: ChainingHint, - label: "Struct", + label: [ + "Struct", + ], tooltip: Some( HoverRanged( FileId( @@ -2515,7 +2615,9 @@ fn main() { InlayHint { range: 145..168, kind: ChainingHint, - label: "Struct", + label: [ + "Struct", + ], tooltip: Some( HoverRanged( FileId( @@ -2528,7 +2630,9 @@ fn main() { InlayHint { range: 222..228, kind: ParameterHint, - label: "self", + label: [ + "self", + ], tooltip: Some( HoverOffset( FileId( diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index d61d69a090b3..0552330814aa 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -82,8 +82,8 @@ pub use crate::{ highlight_related::{HighlightRelatedConfig, HighlightedRange}, hover::{HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult}, inlay_hints::{ - ClosureReturnTypeHints, InlayHint, InlayHintsConfig, InlayKind, InlayTooltip, - LifetimeElisionHints, ReborrowHints, + ClosureReturnTypeHints, InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind, + InlayTooltip, LifetimeElisionHints, ReborrowHints, }, join_lines::JoinLinesConfig, markup::Markup, diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index d89f0f5a3cf4..3a661ddf063c 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -1362,7 +1362,7 @@ pub(crate) fn handle_inlay_hints( .map(|it| { to_proto::inlay_hint(&snap, &line_index, inlay_hints_config.render_colons, it) }) - .collect(), + .collect::>>()?, )) } diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 102cd6029504..de151f0d92c1 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -9,8 +9,9 @@ use ide::{ Annotation, AnnotationKind, Assist, AssistKind, Cancellable, CompletionItem, CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange, FileSystemEdit, Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel, InlayHint, - InlayKind, Markup, NavigationTarget, ReferenceCategory, RenameError, Runnable, Severity, - SignatureHelp, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize, + InlayHintLabel, InlayKind, Markup, NavigationTarget, ReferenceCategory, RenameError, Runnable, + Severity, SignatureHelp, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, + TextSize, }; use itertools::Itertools; use serde_json::to_value; @@ -426,9 +427,16 @@ pub(crate) fn inlay_hint( snap: &GlobalStateSnapshot, line_index: &LineIndex, render_colons: bool, - inlay_hint: InlayHint, -) -> lsp_types::InlayHint { - lsp_types::InlayHint { + mut inlay_hint: InlayHint, +) -> Result { + match inlay_hint.kind { + InlayKind::ParameterHint if render_colons => inlay_hint.label.append_str(":"), + InlayKind::TypeHint if render_colons => inlay_hint.label.prepend_str(": "), + InlayKind::ClosureReturnTypeHint => inlay_hint.label.prepend_str(" -> "), + _ => {} + } + + Ok(lsp_types::InlayHint { position: match inlay_hint.kind { // before annotated thing InlayKind::ParameterHint @@ -459,15 +467,9 @@ pub(crate) fn inlay_hint( | InlayKind::ImplicitReborrowHint | InlayKind::TypeHint | InlayKind::ClosingBraceHint => false, - InlayKind::BindingModeHint => inlay_hint.label != "&", + InlayKind::BindingModeHint => inlay_hint.label.to_string() != "&", InlayKind::ParameterHint | InlayKind::LifetimeHint => true, }), - label: lsp_types::InlayHintLabel::String(match inlay_hint.kind { - InlayKind::ParameterHint if render_colons => format!("{}:", inlay_hint.label), - InlayKind::TypeHint if render_colons => format!(": {}", inlay_hint.label), - InlayKind::ClosureReturnTypeHint => format!(" -> {}", inlay_hint.label), - _ => inlay_hint.label.clone(), - }), kind: match inlay_hint.kind { InlayKind::ParameterHint => Some(lsp_types::InlayHintKind::PARAMETER), InlayKind::ClosureReturnTypeHint | InlayKind::TypeHint | InlayKind::ChainingHint => { @@ -506,9 +508,36 @@ pub(crate) fn inlay_hint( })(), tooltip: Some(match inlay_hint.tooltip { Some(ide::InlayTooltip::String(s)) => lsp_types::InlayHintTooltip::String(s), - _ => lsp_types::InlayHintTooltip::String(inlay_hint.label), + _ => lsp_types::InlayHintTooltip::String(inlay_hint.label.to_string()), }), - } + label: inlay_hint_label(snap, inlay_hint.label)?, + }) +} + +fn inlay_hint_label( + snap: &GlobalStateSnapshot, + label: InlayHintLabel, +) -> Result { + Ok(match label.as_simple_str() { + Some(s) => lsp_types::InlayHintLabel::String(s.into()), + None => lsp_types::InlayHintLabel::LabelParts( + label + .parts + .into_iter() + .map(|part| { + Ok(lsp_types::InlayHintLabelPart { + value: part.text, + tooltip: None, + location: part + .linked_location + .map(|range| location(snap, range)) + .transpose()?, + command: None, + }) + }) + .collect::>>()?, + ), + }) } static TOKEN_RESULT_COUNTER: AtomicU32 = AtomicU32::new(1); From 1fa9d5e07b1b2035be2eca70d0e2bb81f10edd8a Mon Sep 17 00:00:00 2001 From: iDawer Date: Wed, 31 Aug 2022 21:41:24 +0500 Subject: [PATCH 4006/5092] Correct visibility check --- crates/hir-ty/src/inhabitedness.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/crates/hir-ty/src/inhabitedness.rs b/crates/hir-ty/src/inhabitedness.rs index f4d822b9c709..f3fe10c85754 100644 --- a/crates/hir-ty/src/inhabitedness.rs +++ b/crates/hir-ty/src/inhabitedness.rs @@ -149,17 +149,11 @@ impl UninhabitedFrom<'_> { subst: &Substitution, is_enum: bool, ) -> ControlFlow { - let target_mod = self.target_mod; - let mut data_uninhabitedness = - || ty.clone().substitute(Interner, subst).visit_with(self, DebruijnIndex::INNERMOST); - if is_enum { - data_uninhabitedness() + if is_enum || vis.is_visible_from(self.db.upcast(), self.target_mod) { + let ty = ty.clone().substitute(Interner, subst); + ty.visit_with(self, DebruijnIndex::INNERMOST) } else { - match vis { - Visibility::Module(mod_id) if mod_id == target_mod => data_uninhabitedness(), - Visibility::Module(_) => CONTINUE_OPAQUELY_INHABITED, - Visibility::Public => data_uninhabitedness(), - } + CONTINUE_OPAQUELY_INHABITED } } } From 54645e880ff88b8c2d242423733e3e0d26e0c1ea Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Tue, 23 Aug 2022 13:25:03 -0600 Subject: [PATCH 4007/5092] set up rustc_metadata for SessionDiagnostics, port dependency_format.rs --- .../locales/en-US/metadata.ftl | 21 +++++ compiler/rustc_error_messages/src/lib.rs | 1 + .../rustc_metadata/src/dependency_format.rs | 79 ++++++------------- compiler/rustc_metadata/src/errors.rs | 52 ++++++++++++ compiler/rustc_metadata/src/lib.rs | 3 + 5 files changed, 103 insertions(+), 53 deletions(-) create mode 100644 compiler/rustc_error_messages/locales/en-US/metadata.ftl create mode 100644 compiler/rustc_metadata/src/errors.rs diff --git a/compiler/rustc_error_messages/locales/en-US/metadata.ftl b/compiler/rustc_error_messages/locales/en-US/metadata.ftl new file mode 100644 index 000000000000..a27e76544642 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/metadata.ftl @@ -0,0 +1,21 @@ +metadata_rlib_required = + crate `{$crate_name}` required to be available in rlib format, but was not found in this form + +metadata_lib_required = + crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form + +metadata_crate_dep_multiple = + cannot satisfy dependencies so `{$crate_name}` only shows up once + .help = having upstream crates all available in one format will likely make this go away + +metadata_two_panic_runtimes = + cannot link together two panic runtimes: {$prev_name} and {$cur_name} + +metadata_bad_panic_strategy = + the linked panic runtime `{$runtime}` is not compiled with this crate's panic strategy `{$strategy}` + +metadata_required_panic_strategy = + the crate `{$crate_name}` requires panic strategy `{$found_strategy}` which is incompatible with this crate's strategy of `{$desired_strategy}` + +metadata_incompatible_panic_in_drop_strategy = + the crate `{$crate_name}` is compiled with the panic-in-drop strategy `{$found_strategy}` which is incompatible with this crate's strategy of `{$desired_strategy}` diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 42fb2d538b04..72174d1f75d1 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -46,6 +46,7 @@ fluent_messages! { infer => "../locales/en-US/infer.ftl", lint => "../locales/en-US/lint.ftl", monomorphize => "../locales/en-US/monomorphize.ftl", + metadata => "../locales/en-US/metadata.ftl", parser => "../locales/en-US/parser.ftl", passes => "../locales/en-US/passes.ftl", plugin_impl => "../locales/en-US/plugin_impl.ftl", diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index b765c34f8e36..5d1082acc0be 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -52,6 +52,10 @@ //! than finding a number of solutions (there are normally quite a few). use crate::creader::CStore; +use crate::errors::{ + BadPanicStrategy, CrateDepMultiple, IncompatiblePanicInDropStrategy, LibRequired, + RequiredPanicStrategy, RlibRequired, TwoPanicRuntimes, +}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::CrateNum; @@ -136,11 +140,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { if src.rlib.is_some() { continue; } - sess.err(&format!( - "crate `{}` required to be available in rlib format, \ - but was not found in this form", - tcx.crate_name(cnum) - )); + sess.emit_err(RlibRequired { crate_name: tcx.crate_name(cnum).to_string() }); } return Vec::new(); } @@ -224,12 +224,10 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { Linkage::Static => "rlib", _ => "dylib", }; - sess.err(&format!( - "crate `{}` required to be available in {} format, \ - but was not found in this form", - tcx.crate_name(cnum), - kind - )); + sess.emit_err(LibRequired { + crate_name: tcx.crate_name(cnum).to_string(), + kind: kind.to_string(), + }); } } } @@ -254,16 +252,7 @@ fn add_library( // can be refined over time. if link2 != link || link == RequireStatic { tcx.sess - .struct_err(&format!( - "cannot satisfy dependencies so `{}` only \ - shows up once", - tcx.crate_name(cnum) - )) - .help( - "having upstream crates all available in one format \ - will likely make this go away", - ) - .emit(); + .emit_err(CrateDepMultiple { crate_name: tcx.crate_name(cnum).to_string() }); } } None => { @@ -358,13 +347,9 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) { if tcx.is_panic_runtime(cnum) { if let Some((prev, _)) = panic_runtime { - let prev_name = tcx.crate_name(prev); - let cur_name = tcx.crate_name(cnum); - sess.err(&format!( - "cannot link together two \ - panic runtimes: {} and {}", - prev_name, cur_name - )); + let prev_name = tcx.crate_name(prev).to_string(); + let cur_name = tcx.crate_name(cnum).to_string(); + sess.emit_err(TwoPanicRuntimes { prev_name, cur_name }); } panic_runtime = Some(( cnum, @@ -384,13 +369,10 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) { // First up, validate that our selected panic runtime is indeed exactly // our same strategy. if found_strategy != desired_strategy { - sess.err(&format!( - "the linked panic runtime `{}` is \ - not compiled with this crate's \ - panic strategy `{}`", - tcx.crate_name(runtime_cnum), - desired_strategy.desc() - )); + sess.emit_err(BadPanicStrategy { + runtime: tcx.crate_name(runtime_cnum).to_string(), + strategy: desired_strategy.desc().to_string(), + }); } // Next up, verify that all other crates are compatible with this panic @@ -407,28 +389,19 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) { } if let Some(found_strategy) = tcx.required_panic_strategy(cnum) && desired_strategy != found_strategy { - sess.err(&format!( - "the crate `{}` requires \ - panic strategy `{}` which is \ - incompatible with this crate's \ - strategy of `{}`", - tcx.crate_name(cnum), - found_strategy.desc(), - desired_strategy.desc() - )); + sess.emit_err(RequiredPanicStrategy { + crate_name: tcx.crate_name(cnum).to_string(), + found_strategy: found_strategy.desc().to_string(), + desired_strategy: desired_strategy.desc().to_string() }); } let found_drop_strategy = tcx.panic_in_drop_strategy(cnum); if tcx.sess.opts.unstable_opts.panic_in_drop != found_drop_strategy { - sess.err(&format!( - "the crate `{}` is compiled with the \ - panic-in-drop strategy `{}` which is \ - incompatible with this crate's \ - strategy of `{}`", - tcx.crate_name(cnum), - found_drop_strategy.desc(), - tcx.sess.opts.unstable_opts.panic_in_drop.desc() - )); + sess.emit_err(IncompatiblePanicInDropStrategy { + crate_name: tcx.crate_name(cnum).to_string(), + found_strategy: found_drop_strategy.desc().to_string(), + desired_strategy: tcx.sess.opts.unstable_opts.panic_in_drop.desc().to_string(), + }); } } } diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs new file mode 100644 index 000000000000..702863c376b9 --- /dev/null +++ b/compiler/rustc_metadata/src/errors.rs @@ -0,0 +1,52 @@ +// use rustc_errors::ErrorGuaranteed; +use rustc_macros::SessionDiagnostic; + +#[derive(SessionDiagnostic)] +#[diag(metadata::rlib_required)] +pub struct RlibRequired { + pub crate_name: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::lib_required)] +pub struct LibRequired { + pub crate_name: String, + pub kind: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::crate_dep_multiple)] +#[help] +pub struct CrateDepMultiple { + pub crate_name: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::two_panic_runtimes)] +pub struct TwoPanicRuntimes { + pub prev_name: String, + pub cur_name: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::bad_panic_strategy)] +pub struct BadPanicStrategy { + pub runtime: String, + pub strategy: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::required_panic_strategy)] +pub struct RequiredPanicStrategy { + pub crate_name: String, + pub found_strategy: String, + pub desired_strategy: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::incompatible_panic_in_drop_strategy)] +pub struct IncompatiblePanicInDropStrategy { + pub crate_name: String, + pub found_strategy: String, + pub desired_strategy: String, +} diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 6440f3e390cf..fae5b664f4e4 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -16,6 +16,8 @@ #![feature(never_type)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] extern crate proc_macro; @@ -34,6 +36,7 @@ mod native_libs; mod rmeta; pub mod creader; +pub mod errors; pub mod fs; pub mod locator; From 3ed93107ff0f92a64391e3c0936fb17195d525aa Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Tue, 23 Aug 2022 16:33:28 -0600 Subject: [PATCH 4008/5092] port native_libs.rs to SessionDiagnostics --- .../locales/en-US/metadata.ftl | 102 ++++++++ compiler/rustc_metadata/src/errors.rs | 232 ++++++++++++++++++ compiler/rustc_metadata/src/native_libs.rs | 182 ++++---------- 3 files changed, 388 insertions(+), 128 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/metadata.ftl b/compiler/rustc_error_messages/locales/en-US/metadata.ftl index a27e76544642..0685981f9bb4 100644 --- a/compiler/rustc_error_messages/locales/en-US/metadata.ftl +++ b/compiler/rustc_error_messages/locales/en-US/metadata.ftl @@ -19,3 +19,105 @@ metadata_required_panic_strategy = metadata_incompatible_panic_in_drop_strategy = the crate `{$crate_name}` is compiled with the panic-in-drop strategy `{$found_strategy}` which is incompatible with this crate's strategy of `{$desired_strategy}` + +metadata_multiple_names_in_link = + multiple `name` arguments in a single `#[link]` attribute + +metadata_multiple_kinds_in_link = + multiple `kind` arguments in a single `#[link]` attribute + +metadata_link_name_form = + link name must be of the form `name = "string"` + +metadata_link_kind_form = + link kind must be of the form `kind = "string"` + +metadata_link_modifiers_form = + link modifiers must be of the form `modifiers = "string"` + +metadata_link_cfg_form = + link cfg must be of the form `cfg(/* predicate */)` + +metadata_wasm_import_form = + wasm import module must be of the form `wasm_import_module = "string"` + +metadata_empty_link_name = + link name must not be empty + .label = empty link name + +metadata_link_framework_apple = + link kind `framework` is only supported on Apple targets + +metadata_framework_only_windows = + link kind `raw-dylib` is only supported on Windows targets + +metadata_unknown_link_kind = + unknown link kind `{$kind}`, expected one of: static, dylib, framework, raw-dylib + .label = unknown link kind + +metadata_multiple_link_modifiers = + multiple `modifiers` arguments in a single `#[link]` attribute + +metadata_multiple_cfgs = + multiple `cfg` arguments in a single `#[link]` attribute + +metadata_link_cfg_single_predicate = + link cfg must have a single predicate argument + +metadata_multiple_wasm_import = + multiple `wasm_import_module` arguments in a single `#[link]` attribute + +metadata_unexpected_link_arg = + unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module, import_name_type + +metadata_invalid_link_modifier = + invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed + +metadata_multiple_modifiers = + multiple `{$modifier}` modifiers in a single `modifiers` argument + +metadata_bundle_needs_static = + linking modifier `bundle` is only compatible with `static` linking kind + +metadata_whole_archive_needs_static = + linking modifier `whole-archive` is only compatible with `static` linking kind + +metadata_as_needed_compatibility = + linking modifier `as-needed` is only compatible with `dylib` and `framework` linking kinds + +metadata_unknown_link_modifier = + unknown linking modifier `{$modifier}`, expected one of: bundle, verbatim, whole-archive, as-needed + +metadata_incompatible_wasm_link = + `wasm_import_module` is incompatible with other arguments in `#[link]` attributes + +metadata_link_requires_name = + `#[link]` attribute requires a `name = "string"` argument + .label = missing `name` argument + +metadata_raw_dylib_no_nul = + link name must not contain NUL characters if link kind is `raw-dylib` + +metadata_link_ordinal_raw_dylib = + `#[link_ordinal]` is only supported if link kind is `raw-dylib` + +metadata_lib_framework_apple = + library kind `framework` is only supported on Apple targets + +metadata_empty_renaming_target = + an empty renaming target was specified for library `{$lib_name}` + +metadata_renaming_no_link = + renaming of the library `{$lib_name}` was specified, however this crate contains no `#[link(...)]` attributes referencing this library + +metadata_multiple_renamings = + multiple renamings were specified for library `{$lib_name}` + +metadata_no_link_mod_override = + overriding linking modifiers from command line is not supported + +metadata_unsupported_abi_i686 = + ABI not supported by `#[link(kind = "raw-dylib")]` on i686 + +metadata_unsupported_abi = + ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index 702863c376b9..7e3c9b66fbdf 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -1,5 +1,6 @@ // use rustc_errors::ErrorGuaranteed; use rustc_macros::SessionDiagnostic; +use rustc_span::Span; #[derive(SessionDiagnostic)] #[diag(metadata::rlib_required)] @@ -50,3 +51,234 @@ pub struct IncompatiblePanicInDropStrategy { pub found_strategy: String, pub desired_strategy: String, } + +#[derive(SessionDiagnostic)] +#[diag(metadata::multiple_names_in_link)] +pub struct MultipleNamesInLink { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::multiple_kinds_in_link)] +pub struct MultipleKindsInLink { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::link_name_form)] +pub struct LinkNameForm { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::link_kind_form)] +pub struct LinkKindForm { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::link_modifiers_form)] +pub struct LinkModifiersForm { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::link_cfg_form)] +pub struct LinkCfgForm { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::wasm_import_form)] +pub struct WasmImportForm { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::empty_link_name, code = "E0454")] +pub struct EmptyLinkName { + #[label] + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::link_framework_apple, code = "E0455")] +pub struct LinkFrameworkApple { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::framework_only_windows, code = "E0455")] +pub struct FrameworkOnlyWindows { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::unknown_link_kind, code = "E0458")] +pub struct UnknownLinkKind { + #[label] + #[primary_span] + pub span: Span, + pub kind: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::multiple_link_modifiers)] +pub struct MultipleLinkModifiers { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::multiple_cfgs)] +pub struct MultipleCfgs { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::link_cfg_single_predicate)] +pub struct LinkCfgSinglePredicate { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::multiple_wasm_import)] +pub struct MultipleWasmImport { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::unexpected_link_arg)] +pub struct UnexpectedLinkArg { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::invalid_link_modifier)] +pub struct InvalidLinkModifier { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::multiple_modifiers)] +pub struct MultipleModifiers { + #[primary_span] + pub span: Span, + pub modifier: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::bundle_needs_static)] +pub struct BundleNeedsStatic { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::whole_archive_needs_static)] +pub struct WholeArchiveNeedsStatic { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::as_needed_compatibility)] +pub struct AsNeededCompatibility { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::unknown_link_modifier)] +pub struct UnknownLinkModifier { + #[primary_span] + pub span: Span, + pub modifier: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::incompatible_wasm_link)] +pub struct IncompatibleWasmLink { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::link_requires_name, code = "E0459")] +pub struct LinkRequiresName { + #[label] + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::raw_dylib_no_nul)] +pub struct RawDylibNoNul { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::link_ordinal_raw_dylib)] +pub struct LinkOrdinalRawDylib { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::lib_framework_apple)] +pub struct LibFrameworkApple; + +#[derive(SessionDiagnostic)] +#[diag(metadata::empty_renaming_target)] +pub struct EmptyRenamingTarget { + pub lib_name: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::renaming_no_link)] +pub struct RenamingNoLink { + pub lib_name: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::multiple_renamings)] +pub struct MultipleRenamings { + pub lib_name: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::no_link_mod_override)] +pub struct NoLinkModOverride { + #[primary_span] + pub span: Option, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::unsupported_abi_i686)] +pub struct UnsupportedAbiI686 { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::unsupported_abi)] +pub struct UnsupportedAbi { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 8bafe203748f..e8489232fbda 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -12,6 +12,17 @@ use rustc_session::Session; use rustc_span::symbol::{sym, Symbol}; use rustc_target::spec::abi::Abi; +use crate::errors::{ + AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, EmptyRenamingTarget, + FrameworkOnlyWindows, IncompatibleWasmLink, InvalidLinkModifier, LibFrameworkApple, + LinkCfgForm, LinkCfgSinglePredicate, LinkFrameworkApple, LinkKindForm, LinkModifiersForm, + LinkNameForm, LinkOrdinalRawDylib, LinkRequiresName, MultipleCfgs, MultipleKindsInLink, + MultipleLinkModifiers, MultipleModifiers, MultipleNamesInLink, MultipleRenamings, + MultipleWasmImport, NoLinkModOverride, RawDylibNoNul, RenamingNoLink, UnexpectedLinkArg, + UnknownLinkKind, UnknownLinkModifier, UnsupportedAbi, UnsupportedAbiI686, WasmImportForm, + WholeArchiveNeedsStatic, +}; + pub(crate) fn collect(tcx: TyCtxt<'_>) -> Vec { let mut collector = Collector { tcx, libs: Vec::new() }; for id in tcx.hir().items() { @@ -66,32 +77,26 @@ impl<'tcx> Collector<'tcx> { match item.name_or_empty() { sym::name => { if name.is_some() { - let msg = "multiple `name` arguments in a single `#[link]` attribute"; - sess.span_err(item.span(), msg); + sess.emit_err(MultipleNamesInLink { span: item.span() }); continue; } let Some(link_name) = item.value_str() else { - let msg = "link name must be of the form `name = \"string\"`"; - sess.span_err(item.span(), msg); + sess.emit_err(LinkNameForm { span: item.span() }); continue; }; let span = item.name_value_literal_span().unwrap(); if link_name.is_empty() { - struct_span_err!(sess, span, E0454, "link name must not be empty") - .span_label(span, "empty link name") - .emit(); + sess.emit_err(EmptyLinkName { span }); } name = Some((link_name, span)); } sym::kind => { if kind.is_some() { - let msg = "multiple `kind` arguments in a single `#[link]` attribute"; - sess.span_err(item.span(), msg); + sess.emit_err(MultipleKindsInLink { span: item.span() }); continue; } let Some(link_kind) = item.value_str() else { - let msg = "link kind must be of the form `kind = \"string\"`"; - sess.span_err(item.span(), msg); + sess.emit_err(LinkKindForm { span: item.span() }); continue; }; @@ -101,25 +106,13 @@ impl<'tcx> Collector<'tcx> { "dylib" => NativeLibKind::Dylib { as_needed: None }, "framework" => { if !sess.target.is_like_osx { - struct_span_err!( - sess, - span, - E0455, - "link kind `framework` is only supported on Apple targets" - ) - .emit(); + sess.emit_err(LinkFrameworkApple { span }); } NativeLibKind::Framework { as_needed: None } } "raw-dylib" => { if !sess.target.is_like_windows { - struct_span_err!( - sess, - span, - E0455, - "link kind `raw-dylib` is only supported on Windows targets" - ) - .emit(); + sess.emit_err(FrameworkOnlyWindows { span }); } else if !features.raw_dylib { feature_err( &sess.parse_sess, @@ -132,13 +125,7 @@ impl<'tcx> Collector<'tcx> { NativeLibKind::RawDylib } kind => { - let msg = format!( - "unknown link kind `{kind}`, expected one of: \ - static, dylib, framework, raw-dylib" - ); - struct_span_err!(sess, span, E0458, "{}", msg) - .span_label(span, "unknown link kind") - .emit(); + sess.emit_err(UnknownLinkKind { span, kind: kind.to_string() }); continue; } }; @@ -146,32 +133,26 @@ impl<'tcx> Collector<'tcx> { } sym::modifiers => { if modifiers.is_some() { - let msg = - "multiple `modifiers` arguments in a single `#[link]` attribute"; - sess.span_err(item.span(), msg); + sess.emit_err(MultipleLinkModifiers { span: item.span() }); continue; } let Some(link_modifiers) = item.value_str() else { - let msg = "link modifiers must be of the form `modifiers = \"string\"`"; - sess.span_err(item.span(), msg); + sess.emit_err(LinkModifiersForm { span: item.span() }); continue; }; modifiers = Some((link_modifiers, item.name_value_literal_span().unwrap())); } sym::cfg => { if cfg.is_some() { - let msg = "multiple `cfg` arguments in a single `#[link]` attribute"; - sess.span_err(item.span(), msg); + sess.emit_err(MultipleCfgs { span: item.span() }); continue; } let Some(link_cfg) = item.meta_item_list() else { - let msg = "link cfg must be of the form `cfg(/* predicate */)`"; - sess.span_err(item.span(), msg); + sess.emit_err(LinkCfgForm { span: item.span() }); continue; }; let [NestedMetaItem::MetaItem(link_cfg)] = link_cfg else { - let msg = "link cfg must have a single predicate argument"; - sess.span_err(item.span(), msg); + sess.emit_err(LinkCfgSinglePredicate { span: item.span() }); continue; }; if !features.link_cfg { @@ -187,15 +168,11 @@ impl<'tcx> Collector<'tcx> { } sym::wasm_import_module => { if wasm_import_module.is_some() { - let msg = "multiple `wasm_import_module` arguments \ - in a single `#[link]` attribute"; - sess.span_err(item.span(), msg); + sess.emit_err(MultipleWasmImport { span: item.span() }); continue; } let Some(link_wasm_import_module) = item.value_str() else { - let msg = "wasm import module must be of the form \ - `wasm_import_module = \"string\"`"; - sess.span_err(item.span(), msg); + sess.emit_err(WasmImportForm { span: item.span() }); continue; }; wasm_import_module = Some((link_wasm_import_module, item.span())); @@ -243,9 +220,7 @@ impl<'tcx> Collector<'tcx> { import_name_type = Some((link_import_name_type, item.span())); } _ => { - let msg = "unexpected `#[link]` argument, expected one of: \ - name, kind, modifiers, cfg, wasm_import_module, import_name_type"; - sess.span_err(item.span(), msg); + sess.emit_err(UnexpectedLinkArg { span: item.span() }); } } } @@ -257,11 +232,7 @@ impl<'tcx> Collector<'tcx> { let (modifier, value) = match modifier.strip_prefix(&['+', '-']) { Some(m) => (m, modifier.starts_with('+')), None => { - sess.span_err( - span, - "invalid linking modifier syntax, expected '+' or '-' prefix \ - before one of: bundle, verbatim, whole-archive, as-needed", - ); + sess.emit_err(InvalidLinkModifier { span }); continue; } }; @@ -279,10 +250,10 @@ impl<'tcx> Collector<'tcx> { } let assign_modifier = |dst: &mut Option| { if dst.is_some() { - let msg = format!( - "multiple `{modifier}` modifiers in a single `modifiers` argument" - ); - sess.span_err(span, &msg); + sess.emit_err(MultipleModifiers { + span, + modifier: modifier.to_string(), + }); } else { *dst = Some(value); } @@ -292,11 +263,7 @@ impl<'tcx> Collector<'tcx> { assign_modifier(bundle) } ("bundle", _) => { - sess.span_err( - span, - "linking modifier `bundle` is only compatible with \ - `static` linking kind", - ); + sess.emit_err(BundleNeedsStatic { span }); } ("verbatim", _) => { @@ -308,11 +275,7 @@ impl<'tcx> Collector<'tcx> { assign_modifier(whole_archive) } ("whole-archive", _) => { - sess.span_err( - span, - "linking modifier `whole-archive` is only compatible with \ - `static` linking kind", - ); + sess.emit_err(WholeArchiveNeedsStatic { span }); } ("as-needed", Some(NativeLibKind::Dylib { as_needed })) @@ -321,21 +284,14 @@ impl<'tcx> Collector<'tcx> { assign_modifier(as_needed) } ("as-needed", _) => { - sess.span_err( - span, - "linking modifier `as-needed` is only compatible with \ - `dylib` and `framework` linking kinds", - ); + sess.emit_err(AsNeededCompatibility { span }); } _ => { - sess.span_err( + sess.emit_err(UnknownLinkModifier { span, - format!( - "unknown linking modifier `{modifier}`, expected one of: \ - bundle, verbatim, whole-archive, as-needed" - ), - ); + modifier: modifier.to_string(), + }); } } } @@ -343,19 +299,10 @@ impl<'tcx> Collector<'tcx> { if let Some((_, span)) = wasm_import_module { if name.is_some() || kind.is_some() || modifiers.is_some() || cfg.is_some() { - let msg = "`wasm_import_module` is incompatible with \ - other arguments in `#[link]` attributes"; - sess.span_err(span, msg); + sess.emit_err(IncompatibleWasmLink { span }); } } else if name.is_none() { - struct_span_err!( - sess, - m.span, - E0459, - "`#[link]` attribute requires a `name = \"string\"` argument" - ) - .span_label(m.span, "missing `name` argument") - .emit(); + sess.emit_err(LinkRequiresName { span: m.span }); } // Do this outside of the loop so that `import_name_type` can be specified before `kind`. @@ -369,10 +316,7 @@ impl<'tcx> Collector<'tcx> { let dll_imports = match kind { Some(NativeLibKind::RawDylib) => { if let Some((name, span)) = name && name.as_str().contains('\0') { - sess.span_err( - span, - "link name must not contain NUL characters if link kind is `raw-dylib`", - ); + sess.emit_err(RawDylibNoNul { span }); } foreign_mod_items .iter() @@ -401,10 +345,7 @@ impl<'tcx> Collector<'tcx> { .iter() .find(|a| a.has_name(sym::link_ordinal)) .unwrap(); - sess.span_err( - link_ordinal_attr.span, - "`#[link_ordinal]` is only supported if link kind is `raw-dylib`", - ); + sess.emit_err(LinkOrdinalRawDylib { span: link_ordinal_attr.span }); } } @@ -430,7 +371,7 @@ impl<'tcx> Collector<'tcx> { for lib in &self.tcx.sess.opts.libs { if let NativeLibKind::Framework { .. } = lib.kind && !self.tcx.sess.target.is_like_osx { // Cannot check this when parsing options because the target is not yet available. - self.tcx.sess.err("library kind `framework` is only supported on Apple targets"); + self.tcx.sess.emit_err(LibFrameworkApple); } if let Some(ref new_name) = lib.new_name { let any_duplicate = self @@ -439,23 +380,11 @@ impl<'tcx> Collector<'tcx> { .filter_map(|lib| lib.name.as_ref()) .any(|n| n.as_str() == lib.name); if new_name.is_empty() { - self.tcx.sess.err(format!( - "an empty renaming target was specified for library `{}`", - lib.name - )); + self.tcx.sess.emit_err(EmptyRenamingTarget { lib_name: lib.name.clone() }); } else if !any_duplicate { - self.tcx.sess.err(format!( - "renaming of the library `{}` was specified, \ - however this crate contains no `#[link(...)]` \ - attributes referencing this library", - lib.name - )); + self.tcx.sess.emit_err(RenamingNoLink { lib_name: lib.name.clone() }); } else if !renames.insert(&lib.name) { - self.tcx.sess.err(format!( - "multiple renamings were \ - specified for library `{}`", - lib.name - )); + self.tcx.sess.emit_err(MultipleRenamings { lib_name: lib.name.clone() }); } } } @@ -480,10 +409,13 @@ impl<'tcx> Collector<'tcx> { // involved or not, library reordering and kind overriding without // explicit `:rename` in particular. if lib.has_modifiers() || passed_lib.has_modifiers() { - let msg = "overriding linking modifiers from command line is not supported"; match lib.foreign_module { - Some(def_id) => self.tcx.sess.span_err(self.tcx.def_span(def_id), msg), - None => self.tcx.sess.err(msg), + Some(def_id) => self.tcx.sess.emit_err(NoLinkModOverride { + span: Some(self.tcx.def_span(def_id)), + }), + None => { + self.tcx.sess.emit_err(NoLinkModOverride { span: None }) + } }; } if passed_lib.kind != NativeLibKind::Unspecified { @@ -562,20 +494,14 @@ impl<'tcx> Collector<'tcx> { DllCallingConvention::Vectorcall(self.i686_arg_list_size(item)) } _ => { - self.tcx.sess.span_fatal( - item.span, - r#"ABI not supported by `#[link(kind = "raw-dylib")]` on i686"#, - ); + self.tcx.sess.emit_fatal(UnsupportedAbiI686 { span: item.span }); } } } else { match abi { Abi::C { .. } | Abi::Win64 { .. } | Abi::System { .. } => DllCallingConvention::C, _ => { - self.tcx.sess.span_fatal( - item.span, - r#"ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture"#, - ); + self.tcx.sess.emit_fatal(UnsupportedAbi { span: item.span }); } } }; From f7e462a6c7faaea4bfce236fb94b4622ea8260ef Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Tue, 23 Aug 2022 16:40:43 -0600 Subject: [PATCH 4009/5092] port encoder.rs to SessionDiagnostics --- .../locales/en-US/metadata.ftl | 9 +++++++++ compiler/rustc_metadata/src/errors.rs | 18 ++++++++++++++++++ compiler/rustc_metadata/src/rmeta/encoder.rs | 7 ++++--- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/metadata.ftl b/compiler/rustc_error_messages/locales/en-US/metadata.ftl index 0685981f9bb4..8cce1f007e22 100644 --- a/compiler/rustc_error_messages/locales/en-US/metadata.ftl +++ b/compiler/rustc_error_messages/locales/en-US/metadata.ftl @@ -121,3 +121,12 @@ metadata_unsupported_abi_i686 = metadata_unsupported_abi = ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture + +metadata_fail_create_file_encoder = + failed to create file encoder: {$err} + +metadata_fail_seek_file = + failed to seek the file: {$err} + +metadata_fail_write_file = + failed to write to the file: {$err} diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index 7e3c9b66fbdf..5edc59bf9e92 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -282,3 +282,21 @@ pub struct UnsupportedAbi { #[primary_span] pub span: Span, } + +#[derive(SessionDiagnostic)] +#[diag(metadata::fail_create_file_encoder)] +pub struct FailCreateFileEncoder { + pub err: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::fail_seek_file)] +pub struct FailSeekFile { + pub err: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::fail_write_file)] +pub struct FailWriteFile { + pub err: String, +} diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 3482d9f04514..2b1f9f17a3c8 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1,3 +1,4 @@ +use crate::errors::{FailCreateFileEncoder, FailSeekFile, FailWriteFile}; use crate::rmeta::def_path_hash_map::DefPathHashMapRef; use crate::rmeta::table::TableBuilder; use crate::rmeta::*; @@ -2269,7 +2270,7 @@ pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path) { fn encode_metadata_impl(tcx: TyCtxt<'_>, path: &Path) { let mut encoder = opaque::FileEncoder::new(path) - .unwrap_or_else(|err| tcx.sess.fatal(&format!("failed to create file encoder: {}", err))); + .unwrap_or_else(|err| tcx.sess.emit_fatal(FailCreateFileEncoder { err: err.to_string() })); encoder.emit_raw_bytes(METADATA_HEADER); // Will be filled with the root position after encoding everything. @@ -2314,10 +2315,10 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>, path: &Path) { // Encode the root position. let header = METADATA_HEADER.len(); file.seek(std::io::SeekFrom::Start(header as u64)) - .unwrap_or_else(|err| tcx.sess.fatal(&format!("failed to seek the file: {}", err))); + .unwrap_or_else(|err| tcx.sess.emit_fatal(FailSeekFile { err: err.to_string() })); let pos = root.position.get(); file.write_all(&[(pos >> 24) as u8, (pos >> 16) as u8, (pos >> 8) as u8, (pos >> 0) as u8]) - .unwrap_or_else(|err| tcx.sess.fatal(&format!("failed to write to the file: {}", err))); + .unwrap_or_else(|err| tcx.sess.emit_fatal(FailWriteFile { err: err.to_string() })); // Return to the position where we are before writing the root position. file.seek(std::io::SeekFrom::Start(pos_before_seek)).unwrap(); From 32e1823b2275cf55a598e65c5093a28122b4039f Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Tue, 23 Aug 2022 17:03:49 -0600 Subject: [PATCH 4010/5092] port creader.rs to SessionDiagnostics --- .../locales/en-US/metadata.ftl | 28 ++++++++++ compiler/rustc_metadata/src/creader.rs | 56 ++++++++----------- compiler/rustc_metadata/src/errors.rs | 52 +++++++++++++++++ 3 files changed, 102 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/metadata.ftl b/compiler/rustc_error_messages/locales/en-US/metadata.ftl index 8cce1f007e22..3ce1275a8991 100644 --- a/compiler/rustc_error_messages/locales/en-US/metadata.ftl +++ b/compiler/rustc_error_messages/locales/en-US/metadata.ftl @@ -130,3 +130,31 @@ metadata_fail_seek_file = metadata_fail_write_file = failed to write to the file: {$err} + +metadata_crate_not_panic_runtime = + the crate `{$crate_name}` is not a panic runtime + +metadata_no_panic_strategy = + the crate `{$crate_name}` does not have the panic strategy `{$strategy}` + +metadata_profiler_builtins_needs_core = + `profiler_builtins` crate (required by compiler options) is not compatible with crate attribute `#![no_core]` + +metadata_not_profiler_runtime = + the crate `{$crate_name}` is not a profiler runtime + +metadata_no_multiple_global_alloc = + cannot define multiple global allocators + .label = cannot define a new global allocator + +metadata_prev_global_alloc = + previous global allocator defined here + +metadata_conflicting_global_alloc = + the `#[global_allocator]` in {$other_crate_name} conflicts with global allocator in: {$crate_name} + +metadata_global_alloc_required = + no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait + +metadata_no_transitive_needs_dep = + the crate `{$crate_name}` cannot depend on a crate that needs {$needs_crate_name}, but it depends on `{$deps_crate_name}` diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 708d0b1fd8a3..f9aa3733f6a3 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -1,5 +1,9 @@ //! Validates all used crates and extern libraries and loads their metadata +use crate::errors::{ + ConflictingGlobalAlloc, CrateNotPanicRuntime, GlobalAllocRequired, NoMultipleGlobalAlloc, + NoPanicStrategy, NoTransitiveNeedsDep, NotProfilerRuntime, ProfilerBuiltinsNeedsCore, +}; use crate::locator::{CrateError, CrateLocator, CratePaths}; use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob}; @@ -746,15 +750,13 @@ impl<'a> CrateLoader<'a> { // Sanity check the loaded crate to ensure it is indeed a panic runtime // and the panic strategy is indeed what we thought it was. if !data.is_panic_runtime() { - self.sess.err(&format!("the crate `{}` is not a panic runtime", name)); + self.sess.emit_err(CrateNotPanicRuntime { crate_name: name.to_string() }); } if data.required_panic_strategy() != Some(desired_strategy) { - self.sess.err(&format!( - "the crate `{}` does not have the panic \ - strategy `{}`", - name, - desired_strategy.desc() - )); + self.sess.emit_err(NoPanicStrategy { + crate_name: name.to_string(), + strategy: desired_strategy.desc().to_string(), + }); } self.cstore.injected_panic_runtime = Some(cnum); @@ -774,10 +776,7 @@ impl<'a> CrateLoader<'a> { let name = Symbol::intern(&self.sess.opts.unstable_opts.profiler_runtime); if name == sym::profiler_builtins && self.sess.contains_name(&krate.attrs, sym::no_core) { - self.sess.err( - "`profiler_builtins` crate (required by compiler options) \ - is not compatible with crate attribute `#![no_core]`", - ); + self.sess.emit_err(ProfilerBuiltinsNeedsCore); } let Some(cnum) = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit) else { return; }; @@ -785,18 +784,14 @@ impl<'a> CrateLoader<'a> { // Sanity check the loaded crate to ensure it is indeed a profiler runtime if !data.is_profiler_runtime() { - self.sess.err(&format!("the crate `{}` is not a profiler runtime", name)); + self.sess.emit_err(NotProfilerRuntime { crate_name: name.to_string() }); } } fn inject_allocator_crate(&mut self, krate: &ast::Crate) { self.cstore.has_global_allocator = match &*global_allocator_spans(&self.sess, krate) { [span1, span2, ..] => { - self.sess - .struct_span_err(*span2, "cannot define multiple global allocators") - .span_label(*span2, "cannot define a new global allocator") - .span_label(*span1, "previous global allocator defined here") - .emit(); + self.sess.emit_err(NoMultipleGlobalAlloc { span2: *span2, span1: *span1 }); true } spans => !spans.is_empty(), @@ -832,11 +827,10 @@ impl<'a> CrateLoader<'a> { if data.has_global_allocator() { match global_allocator { Some(other_crate) => { - self.sess.err(&format!( - "the `#[global_allocator]` in {} conflicts with global allocator in: {}", - other_crate, - data.name() - )); + self.sess.emit_err(ConflictingGlobalAlloc { + crate_name: data.name().to_string(), + other_crate_name: other_crate.to_string(), + }); } None => global_allocator = Some(data.name()), } @@ -855,10 +849,7 @@ impl<'a> CrateLoader<'a> { if !self.sess.contains_name(&krate.attrs, sym::default_lib_allocator) && !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator()) { - self.sess.err( - "no global memory allocator found but one is required; link to std or add \ - `#[global_allocator]` to a static item that implements the GlobalAlloc trait", - ); + self.sess.emit_err(GlobalAllocRequired); } self.cstore.allocator_kind = Some(AllocatorKind::Default); } @@ -882,14 +873,11 @@ impl<'a> CrateLoader<'a> { for dep in self.cstore.crate_dependencies_in_reverse_postorder(krate) { let data = self.cstore.get_crate_data(dep); if needs_dep(&data) { - self.sess.err(&format!( - "the crate `{}` cannot depend \ - on a crate that needs {}, but \ - it depends on `{}`", - self.cstore.get_crate_data(krate).name(), - what, - data.name() - )); + self.sess.emit_err(NoTransitiveNeedsDep { + crate_name: self.cstore.get_crate_data(krate).name().to_string(), + needs_crate_name: what.to_string(), + deps_crate_name: data.name().to_string(), + }); } } diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index 5edc59bf9e92..3d025e89857c 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -300,3 +300,55 @@ pub struct FailSeekFile { pub struct FailWriteFile { pub err: String, } + +#[derive(SessionDiagnostic)] +#[diag(metadata::crate_not_panic_runtime)] +pub struct CrateNotPanicRuntime { + pub crate_name: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::no_panic_strategy)] +pub struct NoPanicStrategy { + pub crate_name: String, + pub strategy: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::profiler_builtins_needs_core)] +pub struct ProfilerBuiltinsNeedsCore; + +#[derive(SessionDiagnostic)] +#[diag(metadata::not_profiler_runtime)] +pub struct NotProfilerRuntime { + pub crate_name: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::no_multiple_global_alloc)] +pub struct NoMultipleGlobalAlloc { + #[primary_span] + #[label] + pub span2: Span, + #[label(metadata::prev_global_alloc)] + pub span1: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::conflicting_global_alloc)] +pub struct ConflictingGlobalAlloc { + pub crate_name: String, + pub other_crate_name: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::global_alloc_required)] +pub struct GlobalAllocRequired; + +#[derive(SessionDiagnostic)] +#[diag(metadata::no_transitive_needs_dep)] +pub struct NoTransitiveNeedsDep { + pub crate_name: String, + pub needs_crate_name: String, + pub deps_crate_name: String, +} From bd8e312d73f07517e24a58a201e8524ebe4da8da Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Tue, 23 Aug 2022 17:16:04 -0600 Subject: [PATCH 4011/5092] port fs.rs to SessionDiagnostics --- .../locales/en-US/metadata.ftl | 12 +++++++++ compiler/rustc_metadata/src/errors.rs | 26 +++++++++++++++++++ compiler/rustc_metadata/src/fs.rs | 26 ++++++++++++------- 3 files changed, 55 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/metadata.ftl b/compiler/rustc_error_messages/locales/en-US/metadata.ftl index 3ce1275a8991..a4881dbc7645 100644 --- a/compiler/rustc_error_messages/locales/en-US/metadata.ftl +++ b/compiler/rustc_error_messages/locales/en-US/metadata.ftl @@ -158,3 +158,15 @@ metadata_global_alloc_required = metadata_no_transitive_needs_dep = the crate `{$crate_name}` cannot depend on a crate that needs {$needs_crate_name}, but it depends on `{$deps_crate_name}` + +metadata_failed_write_error = + failed to write {$filename}: {$err} + +metadata_failed_create_tempdir = + couldn't create a temp dir: {$err} + +metadata_failed_create_file = + failed to create the file {$filename}: {$err} + +metadata_failed_create_encoded_metadata = + failed to create encoded metadata from file: {$err} diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index 3d025e89857c..c373e49ba495 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -352,3 +352,29 @@ pub struct NoTransitiveNeedsDep { pub needs_crate_name: String, pub deps_crate_name: String, } + +#[derive(SessionDiagnostic)] +#[diag(metadata::failed_write_error)] +pub struct FailedWriteError { + pub filename: String, + pub err: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::failed_create_tempdir)] +pub struct FailedCreateTempdir { + pub err: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::failed_create_file)] +pub struct FailedCreateFile { + pub filename: String, + pub err: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::failed_create_encoded_metadata)] +pub struct FailedCreateEncodedMetadata { + pub err: String, +} diff --git a/compiler/rustc_metadata/src/fs.rs b/compiler/rustc_metadata/src/fs.rs index e6072901aaa4..67c18766c595 100644 --- a/compiler/rustc_metadata/src/fs.rs +++ b/compiler/rustc_metadata/src/fs.rs @@ -1,3 +1,6 @@ +use crate::errors::{ + FailedCreateEncodedMetadata, FailedCreateFile, FailedCreateTempdir, FailedWriteError, +}; use crate::{encode_metadata, EncodedMetadata}; use rustc_data_structures::temp_dir::MaybeTempDir; @@ -24,7 +27,10 @@ pub fn emit_metadata(sess: &Session, metadata: &[u8], tmpdir: &MaybeTempDir) -> let result = fs::write(&out_filename, metadata); if let Err(e) = result { - sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); + sess.emit_fatal(FailedWriteError { + filename: out_filename.display().to_string(), + err: e.to_string(), + }); } out_filename @@ -65,7 +71,7 @@ pub fn encode_and_write_metadata( let metadata_tmpdir = TempFileBuilder::new() .prefix("rmeta") .tempdir_in(out_filename.parent().unwrap_or_else(|| Path::new(""))) - .unwrap_or_else(|err| tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err))); + .unwrap_or_else(|err| tcx.sess.emit_fatal(FailedCreateTempdir { err: err.to_string() })); let metadata_tmpdir = MaybeTempDir::new(metadata_tmpdir, tcx.sess.opts.cg.save_temps); let metadata_filename = metadata_tmpdir.as_ref().join(METADATA_FILENAME); @@ -74,11 +80,10 @@ pub fn encode_and_write_metadata( match metadata_kind { MetadataKind::None => { std::fs::File::create(&metadata_filename).unwrap_or_else(|e| { - tcx.sess.fatal(&format!( - "failed to create the file {}: {}", - metadata_filename.display(), - e - )) + tcx.sess.emit_fatal(FailedCreateFile { + filename: metadata_filename.display().to_string(), + err: e.to_string(), + }); }); } MetadataKind::Uncompressed | MetadataKind::Compressed => { @@ -94,7 +99,10 @@ pub fn encode_and_write_metadata( let need_metadata_file = tcx.sess.opts.output_types.contains_key(&OutputType::Metadata); let (metadata_filename, metadata_tmpdir) = if need_metadata_file { if let Err(e) = non_durable_rename(&metadata_filename, &out_filename) { - tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); + tcx.sess.emit_fatal(FailedWriteError { + filename: out_filename.display().to_string(), + err: e.to_string(), + }); } if tcx.sess.opts.json_artifact_notifications { tcx.sess @@ -110,7 +118,7 @@ pub fn encode_and_write_metadata( // Load metadata back to memory: codegen may need to include it in object files. let metadata = EncodedMetadata::from_path(metadata_filename, metadata_tmpdir).unwrap_or_else(|e| { - tcx.sess.fatal(&format!("failed to create encoded metadata from file: {}", e)) + tcx.sess.emit_fatal(FailedCreateEncodedMetadata { err: e.to_string() }); }); let need_metadata_module = metadata_kind == MetadataKind::Compressed; From d0ba1fbaa4f73b6edf27346817b1f74fb352945e Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Wed, 24 Aug 2022 12:14:41 -0600 Subject: [PATCH 4012/5092] port of locator.rs to SessionDiagnostics, fix some of the errors revealed by tests, manually add a panic to test for dead code --- .../locales/en-US/metadata.ftl | 55 +++ compiler/rustc_metadata/src/errors.rs | 257 ++++++++++++- compiler/rustc_metadata/src/locator.rs | 352 +++++++----------- compiler/rustc_metadata/src/native_libs.rs | 1 - 4 files changed, 450 insertions(+), 215 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/metadata.ftl b/compiler/rustc_error_messages/locales/en-US/metadata.ftl index a4881dbc7645..e3e58cf8bed7 100644 --- a/compiler/rustc_error_messages/locales/en-US/metadata.ftl +++ b/compiler/rustc_error_messages/locales/en-US/metadata.ftl @@ -170,3 +170,58 @@ metadata_failed_create_file = metadata_failed_create_encoded_metadata = failed to create encoded metadata from file: {$err} + +metadata_non_ascii_name = + cannot load a crate with a non-ascii name `{$crate_name}` + +metadata_extern_location_not_exist = + extern location for {$crate_name} does not exist: {$location} + +metadata_extern_location_not_file = + extern location for {$crate_name} is not a file: {$location} + +metadata_multiple_candidates = + multiple {$flavor} candidates for `{$crate_name}` found + +metadata_multiple_matching_crates = + multiple matching crates for `{$crate_name}` + .note = candidates:{$candidates} + +metadata_symbol_conflicts_current = + the current crate is indistinguishable from one of its dependencies: it has the same crate-name `{$crate_name}` and was compiled with the same `-C metadata` arguments. This will result in symbol conflicts between the two. + +metadata_symbol_conflicts_others = + found two different crates with name `{$crate_name}` that are not distinguished by differing `-C metadata`. This will result in symbol conflicts between the two. + +metadata_stable_crate_id_collision = + found crates (`{$crate_name0}` and `{$crate_name1}`) with colliding StableCrateId values. + +metadata_dl_error = + {$err} + +metadata_newer_crate_version = + found possibly newer version of crate `{$crate_name}`{$add_info} + .note = perhaps that crate needs to be recompiled? + +metadata_found_crate_versions = + the following crate versions were found:{$found_crates} + +metadata_no_crate_with_triple = + couldn't find crate `{$crate_name}` with expected target triple {$locator_triple}{$add_info} + +metadata_found_staticlib = + found staticlib `{$crate_name}` instead of rlib or dylib{$add_info} + .help = please recompile that crate using --crate-type lib + +metadata_incompatible_rustc = + found crate `{$crate_name}` compiled by an incompatible version of rustc{$add_info} + .help = please recompile that crate using this compiler ({$rustc_version}) (consider running `cargo clean` first) + +metadata_invalid_meta_files = + found invalid metadata files for crate `{$crate_name}`{$add_info} + +metadata_cannot_find_crate = + can't find crate for `{$crate_name}`{$add_info} + +metadata_no_dylib_plugin = + plugin `{$crate_name}` only found in rlib format, but must be available in dylib format diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index c373e49ba495..d3f35ca8d164 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -1,6 +1,10 @@ -// use rustc_errors::ErrorGuaranteed; +use std::path::PathBuf; + +use rustc_errors::{DiagnosticId, ErrorGuaranteed}; use rustc_macros::SessionDiagnostic; -use rustc_span::Span; +use rustc_session::{config, SessionDiagnostic}; +use rustc_span::{sym, Span, Symbol}; +use rustc_target::spec::TargetTriple; #[derive(SessionDiagnostic)] #[diag(metadata::rlib_required)] @@ -104,8 +108,8 @@ pub struct WasmImportForm { #[derive(SessionDiagnostic)] #[diag(metadata::empty_link_name, code = "E0454")] pub struct EmptyLinkName { - #[label] #[primary_span] + #[label] pub span: Span, } @@ -126,8 +130,8 @@ pub struct FrameworkOnlyWindows { #[derive(SessionDiagnostic)] #[diag(metadata::unknown_link_kind, code = "E0458")] pub struct UnknownLinkKind { - #[label] #[primary_span] + #[label] pub span: Span, pub kind: String, } @@ -221,8 +225,8 @@ pub struct IncompatibleWasmLink { #[derive(SessionDiagnostic)] #[diag(metadata::link_requires_name, code = "E0459")] pub struct LinkRequiresName { - #[label] #[primary_span] + #[label] pub span: Span, } @@ -378,3 +382,246 @@ pub struct FailedCreateFile { pub struct FailedCreateEncodedMetadata { pub err: String, } + +#[derive(SessionDiagnostic)] +#[diag(metadata::non_ascii_name)] +pub struct NonAsciiName { + #[primary_span] + pub span: Span, + pub crate_name: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::extern_location_not_exist)] +pub struct ExternLocationNotExist { + #[primary_span] + pub span: Span, + pub crate_name: String, + pub location: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::extern_location_not_file)] +pub struct ExternLocationNotFile { + #[primary_span] + pub span: Span, + pub crate_name: String, + pub location: String, +} + +pub struct MultipleCandidates { + pub span: Span, + pub flavor: String, + pub crate_name: String, + pub candidates: Vec, +} + +impl SessionDiagnostic<'_> for MultipleCandidates { + fn into_diagnostic( + self, + sess: &'_ rustc_session::parse::ParseSess, + ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = sess.struct_err(rustc_errors::fluent::metadata::multiple_candidates); + diag.set_arg("crate_name", self.crate_name); + diag.set_arg("flavor", self.flavor); + diag.code(DiagnosticId::Error("E0465".into())); + diag.set_span(self.span); + for (i, candidate) in self.candidates.iter().enumerate() { + diag.span_note(self.span, &format!("candidate #{}: {}", i + 1, candidate.display())); + } + diag + } +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::multiple_matching_crates, code = "E0464")] +#[note] +pub struct MultipleMatchingCrates { + #[primary_span] + pub span: Span, + pub crate_name: String, + pub candidates: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::symbol_conflicts_current, code = "E0519")] +pub struct SymbolConflictsCurrent { + #[primary_span] + pub span: Span, + pub crate_name: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::symbol_conflicts_others, code = "E0523")] +pub struct SymbolConflictsOthers { + #[primary_span] + pub span: Span, + pub crate_name: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::stable_crate_id_collision)] +pub struct StableCrateIdCollision { + #[primary_span] + pub span: Span, + pub crate_name0: String, + pub crate_name1: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::dl_error)] +pub struct DlError { + #[primary_span] + pub span: Span, + pub err: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::newer_crate_version, code = "E0460")] +#[note] +#[note(metadata::found_crate_versions)] +pub struct NewerCrateVersion { + #[primary_span] + pub span: Span, + pub crate_name: String, + pub add_info: String, + pub found_crates: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::no_crate_with_triple, code = "E0461")] +#[note(metadata::found_crate_versions)] +pub struct NoCrateWithTriple { + #[primary_span] + pub span: Span, + pub crate_name: String, + pub locator_triple: String, + pub add_info: String, + pub found_crates: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::found_staticlib, code = "E0462")] +#[note(metadata::found_crate_versions)] +#[help] +pub struct FoundStaticlib { + #[primary_span] + pub span: Span, + pub crate_name: String, + pub add_info: String, + pub found_crates: String, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::incompatible_rustc, code = "E0514")] +#[note(metadata::found_crate_versions)] +#[help] +pub struct IncompatibleRustc { + #[primary_span] + pub span: Span, + pub crate_name: String, + pub add_info: String, + pub found_crates: String, + pub rustc_version: String, +} + +pub struct InvalidMetadataFiles { + pub span: Span, + pub crate_name: String, + pub add_info: String, + pub crate_rejections: Vec, +} + +impl SessionDiagnostic<'_> for InvalidMetadataFiles { + fn into_diagnostic( + self, + sess: &'_ rustc_session::parse::ParseSess, + ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = sess.struct_err(rustc_errors::fluent::metadata::invalid_meta_files); + diag.set_arg("crate_name", self.crate_name); + diag.set_arg("add_info", self.add_info); + diag.code(DiagnosticId::Error("E0786".into())); + diag.set_span(self.span); + for crate_rejection in self.crate_rejections { + diag.note(crate_rejection); + } + diag + } +} + +pub struct CannotFindCrate { + pub span: Span, + pub crate_name: String, + pub crate_name_symbol: Symbol, + pub add_info: String, + pub missing_core: bool, + pub current_crate: String, + pub is_nightly_build: bool, + pub profiler_runtime: Symbol, + pub locator_triple: TargetTriple, +} + +impl SessionDiagnostic<'_> for CannotFindCrate { + fn into_diagnostic( + self, + sess: &'_ rustc_session::parse::ParseSess, + ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = sess.struct_err(rustc_errors::fluent::metadata::cannot_find_crate); + diag.set_arg("crate_name", self.crate_name.clone()); + diag.set_arg("add_info", self.add_info); + diag.code(DiagnosticId::Error("E0463".into())); + diag.set_span(self.span); + // FIXME: Find a way to distill this logic down into the derived SessionDiagnostic form + if (self.crate_name_symbol == sym::std || self.crate_name_symbol == sym::core) + && self.locator_triple != TargetTriple::from_triple(config::host_triple()) + { + if self.missing_core { + diag.note(&format!("the `{}` target may not be installed", self.locator_triple)); + } else { + diag.note(&format!( + "the `{}` target may not support the standard library", + self.locator_triple + )); + } + // NOTE: this suggests using rustup, even though the user may not have it installed. + // That's because they could choose to install it; or this may give them a hint which + // target they need to install from their distro. + if self.missing_core { + diag.help(&format!( + "consider downloading the target with `rustup target add {}`", + self.locator_triple + )); + } + // Suggest using #![no_std]. #[no_core] is unstable and not really supported anyway. + // NOTE: this is a dummy span if `extern crate std` was injected by the compiler. + // If it's not a dummy, that means someone added `extern crate std` explicitly and + // `#![no_std]` won't help. + if !self.missing_core && self.span.is_dummy() { + diag.note(&format!( + "`std` is required by `{}` because it does not declare `#![no_std]`", + self.current_crate + )); + } + if self.is_nightly_build { + diag.help("consider building the standard library from source with `cargo build -Zbuild-std`"); + } + } else if self.crate_name_symbol == self.profiler_runtime { + diag.note("the compiler may have been built without the profiler runtime"); + } else if self.crate_name.starts_with("rustc_") { + diag.help( + "maybe you need to install the missing components with: \ + `rustup component add rust-src rustc-dev llvm-tools-preview`", + ); + } + diag.span_label(self.span, "can't find crate"); + diag + } +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::no_dylib_plugin, code = "E0457")] +pub struct NoDylibPlugin { + #[primary_span] + pub span: Span, + pub crate_name: String, +} diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 2c1c84b0be26..83c8756078ec 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -213,6 +213,12 @@ //! metadata::locator or metadata::creader for all the juicy details! use crate::creader::Library; +use crate::errors::{ + CannotFindCrate, DlError, ExternLocationNotExist, ExternLocationNotFile, FoundStaticlib, + IncompatibleRustc, InvalidMetadataFiles, MultipleCandidates, MultipleMatchingCrates, + NewerCrateVersion, NoCrateWithTriple, NoDylibPlugin, NonAsciiName, StableCrateIdCollision, + SymbolConflictsCurrent, SymbolConflictsOthers, +}; use crate::rmeta::{rustc_version, MetadataBlob, METADATA_HEADER}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -220,14 +226,14 @@ use rustc_data_structures::memmap::Mmap; use rustc_data_structures::owning_ref::OwningRef; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::MetadataRef; -use rustc_errors::{struct_span_err, FatalError}; +use rustc_errors::FatalError; use rustc_session::config::{self, CrateType}; use rustc_session::cstore::{CrateSource, MetadataLoader}; use rustc_session::filesearch::FileSearch; use rustc_session::search_paths::PathKind; use rustc_session::utils::CanonicalizedPath; use rustc_session::Session; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::Symbol; use rustc_span::Span; use rustc_target::spec::{Target, TargetTriple}; @@ -938,41 +944,33 @@ impl fmt::Display for MetadataError<'_> { impl CrateError { pub(crate) fn report(self, sess: &Session, span: Span, missing_core: bool) { - let mut diag = match self { - CrateError::NonAsciiName(crate_name) => sess.struct_span_err( - span, - &format!("cannot load a crate with a non-ascii name `{}`", crate_name), - ), - CrateError::ExternLocationNotExist(crate_name, loc) => sess.struct_span_err( - span, - &format!("extern location for {} does not exist: {}", crate_name, loc.display()), - ), - CrateError::ExternLocationNotFile(crate_name, loc) => sess.struct_span_err( - span, - &format!("extern location for {} is not a file: {}", crate_name, loc.display()), - ), - CrateError::MultipleCandidates(crate_name, flavor, candidates) => { - let mut err = struct_span_err!( - sess, + match self { + CrateError::NonAsciiName(crate_name) => { + sess.emit_err(NonAsciiName { span, crate_name: crate_name.to_string() }); + } + CrateError::ExternLocationNotExist(crate_name, loc) => { + sess.emit_err(ExternLocationNotExist { span, - E0465, - "multiple {} candidates for `{}` found", - flavor, - crate_name, - ); - for (i, candidate) in candidates.iter().enumerate() { - err.span_note(span, &format!("candidate #{}: {}", i + 1, candidate.display())); - } - err + crate_name: crate_name.to_string(), + location: loc.display().to_string(), + }); + } + CrateError::ExternLocationNotFile(crate_name, loc) => { + sess.emit_err(ExternLocationNotFile { + span, + crate_name: crate_name.to_string(), + location: loc.display().to_string(), + }); + } + CrateError::MultipleCandidates(crate_name, flavor, candidates) => { + sess.emit_err(MultipleCandidates { + span, + flavor: flavor.to_string(), + crate_name: crate_name.to_string(), + candidates, + }); } CrateError::MultipleMatchingCrates(crate_name, libraries) => { - let mut err = struct_span_err!( - sess, - span, - E0464, - "multiple matching crates for `{}`", - crate_name - ); let mut libraries: Vec<_> = libraries.into_values().collect(); // Make ordering of candidates deterministic. // This has to `clone()` to work around lifetime restrictions with `sort_by_key()`. @@ -1000,223 +998,159 @@ impl CrateError { s }) .collect::(); - err.note(&format!("candidates:{}", candidates)); - err + sess.emit_err(MultipleMatchingCrates { + span, + crate_name: crate_name.to_string(), + candidates, + }); + } + CrateError::SymbolConflictsCurrent(root_name) => { + sess.emit_err(SymbolConflictsCurrent { span, crate_name: root_name.to_string() }); + } + CrateError::SymbolConflictsOthers(root_name) => { + sess.emit_err(SymbolConflictsOthers { span, crate_name: root_name.to_string() }); } - CrateError::SymbolConflictsCurrent(root_name) => struct_span_err!( - sess, - span, - E0519, - "the current crate is indistinguishable from one of its dependencies: it has the \ - same crate-name `{}` and was compiled with the same `-C metadata` arguments. \ - This will result in symbol conflicts between the two.", - root_name, - ), - CrateError::SymbolConflictsOthers(root_name) => struct_span_err!( - sess, - span, - E0523, - "found two different crates with name `{}` that are not distinguished by differing \ - `-C metadata`. This will result in symbol conflicts between the two.", - root_name, - ), CrateError::StableCrateIdCollision(crate_name0, crate_name1) => { - let msg = format!( - "found crates (`{}` and `{}`) with colliding StableCrateId values.", - crate_name0, crate_name1 - ); - sess.struct_span_err(span, &msg) + sess.emit_err(StableCrateIdCollision { + span, + crate_name0: crate_name0.to_string(), + crate_name1: crate_name1.to_string(), + }); + } + CrateError::DlOpen(s) | CrateError::DlSym(s) => { + sess.emit_err(DlError { span, err: s.to_string() }); } - CrateError::DlOpen(s) | CrateError::DlSym(s) => sess.struct_span_err(span, &s), CrateError::LocatorCombined(locator) => { let crate_name = locator.crate_name; - let add = match &locator.root { + let add_info = match &locator.root { None => String::new(), Some(r) => format!(" which `{}` depends on", r.name), }; - let mut msg = "the following crate versions were found:".to_string(); - let mut err = if !locator.crate_rejections.via_hash.is_empty() { - let mut err = struct_span_err!( - sess, - span, - E0460, - "found possibly newer version of crate `{}`{}", - crate_name, - add, - ); - err.note("perhaps that crate needs to be recompiled?"); + // FIXME: Is there any way to get these notes and helps onto every diagnostic in this + // huge branch arm without changing them all to manual implementations? + let mut global_loc_notes = Vec::new(); + let mut global_loc_helps = Vec::new(); + if !locator.crate_rejections.via_filename.is_empty() { + let mismatches = locator.crate_rejections.via_filename.iter(); + for CrateMismatch { path, .. } in mismatches { + global_loc_notes.push(format!( + "extern location for {} is of an unknown type: {}", + crate_name, + path.display(), + )); + global_loc_helps.push(format!( + "file name should be lib*.rlib or {}*.{}", + locator.dll_prefix, locator.dll_suffix + )); + } + panic!("!!!!! REVERT THIS COMMIT !!!!!"); + } + let mut found_crates = String::new(); + if !locator.crate_rejections.via_hash.is_empty() { let mismatches = locator.crate_rejections.via_hash.iter(); for CrateMismatch { path, .. } in mismatches { - msg.push_str(&format!("\ncrate `{}`: {}", crate_name, path.display())); + found_crates.push_str(&format!( + "\ncrate `{}`: {}", + crate_name, + path.display() + )); } if let Some(r) = locator.root { for path in r.source.paths() { - msg.push_str(&format!("\ncrate `{}`: {}", r.name, path.display())); + found_crates.push_str(&format!( + "\ncrate `{}`: {}", + r.name, + path.display() + )); } } - err.note(&msg); - err - } else if !locator.crate_rejections.via_triple.is_empty() { - let mut err = struct_span_err!( - sess, + sess.emit_err(NewerCrateVersion { span, - E0461, - "couldn't find crate `{}` with expected target triple {}{}", - crate_name, - locator.triple, - add, - ); + crate_name: crate_name.to_string(), + add_info, + found_crates, + }); + } else if !locator.crate_rejections.via_triple.is_empty() { let mismatches = locator.crate_rejections.via_triple.iter(); for CrateMismatch { path, got } in mismatches { - msg.push_str(&format!( + found_crates.push_str(&format!( "\ncrate `{}`, target triple {}: {}", crate_name, got, path.display(), )); } - err.note(&msg); - err - } else if !locator.crate_rejections.via_kind.is_empty() { - let mut err = struct_span_err!( - sess, + sess.emit_err(NoCrateWithTriple { span, - E0462, - "found staticlib `{}` instead of rlib or dylib{}", - crate_name, - add, - ); - err.help("please recompile that crate using --crate-type lib"); + crate_name: crate_name.to_string(), + locator_triple: locator.triple.to_string(), + add_info, + found_crates, + }); + } else if !locator.crate_rejections.via_kind.is_empty() { let mismatches = locator.crate_rejections.via_kind.iter(); for CrateMismatch { path, .. } in mismatches { - msg.push_str(&format!("\ncrate `{}`: {}", crate_name, path.display())); + found_crates.push_str(&format!( + "\ncrate `{}`: {}", + crate_name, + path.display() + )); } - err.note(&msg); - err - } else if !locator.crate_rejections.via_version.is_empty() { - let mut err = struct_span_err!( - sess, + sess.emit_err(FoundStaticlib { span, - E0514, - "found crate `{}` compiled by an incompatible version of rustc{}", - crate_name, - add, - ); - err.help(&format!( - "please recompile that crate using this compiler ({}) \ - (consider running `cargo clean` first)", - rustc_version(), - )); + crate_name: crate_name.to_string(), + add_info, + found_crates, + }); + } else if !locator.crate_rejections.via_version.is_empty() { let mismatches = locator.crate_rejections.via_version.iter(); for CrateMismatch { path, got } in mismatches { - msg.push_str(&format!( + found_crates.push_str(&format!( "\ncrate `{}` compiled by {}: {}", crate_name, got, path.display(), )); } - err.note(&msg); - err + sess.emit_err(IncompatibleRustc { + span, + crate_name: crate_name.to_string(), + add_info, + found_crates, + rustc_version: rustc_version(), + }); } else if !locator.crate_rejections.via_invalid.is_empty() { - let mut err = struct_span_err!( - sess, - span, - E0786, - "found invalid metadata files for crate `{}`{}", - crate_name, - add, - ); + let mut crate_rejections = Vec::new(); for CrateMismatch { path: _, got } in locator.crate_rejections.via_invalid { - err.note(&got); + crate_rejections.push(got); } - err - } else { - let mut err = struct_span_err!( - sess, + sess.emit_err(InvalidMetadataFiles { span, - E0463, - "can't find crate for `{}`{}", - crate_name, - add, - ); - - if (crate_name == sym::std || crate_name == sym::core) - && locator.triple != TargetTriple::from_triple(config::host_triple()) - { - if missing_core { - err.note(&format!( - "the `{}` target may not be installed", - locator.triple - )); - } else { - err.note(&format!( - "the `{}` target may not support the standard library", - locator.triple - )); - } - // NOTE: this suggests using rustup, even though the user may not have it installed. - // That's because they could choose to install it; or this may give them a hint which - // target they need to install from their distro. - if missing_core { - err.help(&format!( - "consider downloading the target with `rustup target add {}`", - locator.triple - )); - } - // Suggest using #![no_std]. #[no_core] is unstable and not really supported anyway. - // NOTE: this is a dummy span if `extern crate std` was injected by the compiler. - // If it's not a dummy, that means someone added `extern crate std` explicitly and `#![no_std]` won't help. - if !missing_core && span.is_dummy() { - let current_crate = - sess.opts.crate_name.as_deref().unwrap_or(""); - err.note(&format!( - "`std` is required by `{}` because it does not declare `#![no_std]`", - current_crate - )); - } - if sess.is_nightly_build() { - err.help("consider building the standard library from source with `cargo build -Zbuild-std`"); - } - } else if crate_name - == Symbol::intern(&sess.opts.unstable_opts.profiler_runtime) - { - err.note("the compiler may have been built without the profiler runtime"); - } else if crate_name.as_str().starts_with("rustc_") { - err.help( - "maybe you need to install the missing components with: \ - `rustup component add rust-src rustc-dev llvm-tools-preview`", - ); - } - err.span_label(span, "can't find crate"); - err - }; - - if !locator.crate_rejections.via_filename.is_empty() { - let mismatches = locator.crate_rejections.via_filename.iter(); - for CrateMismatch { path, .. } in mismatches { - err.note(&format!( - "extern location for {} is of an unknown type: {}", - crate_name, - path.display(), - )) - .help(&format!( - "file name should be lib*.rlib or {}*.{}", - locator.dll_prefix, locator.dll_suffix - )); - } + crate_name: crate_name.to_string(), + add_info, + crate_rejections, + }); + } else { + sess.emit_err(CannotFindCrate { + span, + crate_name: crate_name.to_string(), + crate_name_symbol: crate_name, + add_info, + missing_core, + current_crate: sess + .opts + .crate_name + .clone() + .unwrap_or("".to_string()), + is_nightly_build: sess.is_nightly_build(), + profiler_runtime: Symbol::intern(&sess.opts.unstable_opts.profiler_runtime), + locator_triple: locator.triple, + }); } - err } - CrateError::NonDylibPlugin(crate_name) => struct_span_err!( - sess, - span, - E0457, - "plugin `{}` only found in rlib format, but must be available in dylib format", - crate_name, - ), - }; - - diag.emit(); + CrateError::NonDylibPlugin(crate_name) => { + sess.emit_err(NoDylibPlugin { span, crate_name: crate_name.to_string() }); + } + } } } diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index e8489232fbda..dbaa2e9defa1 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -1,7 +1,6 @@ use rustc_ast::{NestedMetaItem, CRATE_NODE_ID}; use rustc_attr as attr; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_middle::ty::{List, ParamEnv, ParamEnvAnd, Ty, TyCtxt}; From 0d65819d529f222e47164f6c8132d8134909f2a4 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Fri, 26 Aug 2022 14:39:59 -0600 Subject: [PATCH 4013/5092] respond to review feedback: mainly eliminate as many conversions as possible... - ... when creating diagnostics in rustc_metadata - use the error_code! macro - pass macro output to diag.code() - use fluent from within manual implementation of SessionDiagnostic - emit the untested errors in case they occur in the wild - stop panicking in the probably-not-dead code, add fixme to write test --- Cargo.lock | 1 + .../locales/en-US/metadata.ftl | 30 +++ compiler/rustc_errors/Cargo.toml | 5 +- compiler/rustc_errors/src/diagnostic.rs | 7 + compiler/rustc_metadata/src/creader.rs | 19 +- .../rustc_metadata/src/dependency_format.rs | 30 ++- compiler/rustc_metadata/src/errors.rs | 215 +++++++++--------- compiler/rustc_metadata/src/fs.rs | 27 +-- compiler/rustc_metadata/src/locator.rs | 102 ++++----- compiler/rustc_metadata/src/native_libs.rs | 18 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 6 +- 11 files changed, 234 insertions(+), 226 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 002d73be7d1d..0ce329ff0708 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3514,6 +3514,7 @@ dependencies = [ "rustc_macros", "rustc_serialize", "rustc_span", + "rustc_target", "serde", "serde_json", "termcolor", diff --git a/compiler/rustc_error_messages/locales/en-US/metadata.ftl b/compiler/rustc_error_messages/locales/en-US/metadata.ftl index e3e58cf8bed7..dee01bcad4bb 100644 --- a/compiler/rustc_error_messages/locales/en-US/metadata.ftl +++ b/compiler/rustc_error_messages/locales/en-US/metadata.ftl @@ -225,3 +225,33 @@ metadata_cannot_find_crate = metadata_no_dylib_plugin = plugin `{$crate_name}` only found in rlib format, but must be available in dylib format + +metadata_target_not_installed = + the `{$locator_triple}` target may not be installed + +metadata_target_no_std_support = + the `{$locator_triple}` target may not support the standard library + +metadata_consider_downloading_target = + consider downloading the target with `rustup target add {$locator_triple}` + +metadata_std_required = + `std` is required by `{$current_crate}` because it does not declare `#![no_std]` + +metadata_consider_building_std = + consider building the standard library from source with `cargo build -Zbuild-std` + +metadata_compiler_missing_profiler = + the compiler may have been built without the profiler runtime + +metadata_install_missing_components = + maybe you need to install the missing components with: `rustup component add rust-src rustc-dev llvm-tools-preview` + +metadata_cant_find_crate = + can't find crate + +metadata_crate_location_unknown_type = + extern location for {$crate_name} is of an unknown type: {$path} + +metadata_lib_filename_form = + file name should be lib*.rlib or {dll_prefix}*.{dll_suffix} diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index 36805aa874fe..4d207fd17fb2 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -15,13 +15,14 @@ rustc_macros = { path = "../rustc_macros" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_hir = { path = "../rustc_hir" } rustc_lint_defs = { path = "../rustc_lint_defs" } +rustc_target = { path = "../rustc_target" } unicode-width = "0.1.4" atty = "0.2" termcolor = "1.0" annotate-snippets = "0.9" termize = "0.1.1" -serde = { version = "1.0.125", features = ["derive"] } +serde = { version = "1.0.125", features = [ "derive" ] } serde_json = "1.0.59" [target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = ["handleapi", "synchapi", "winbase"] } +winapi = { version = "0.3", features = [ "handleapi", "synchapi", "winbase" ] } diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index f75e2596f361..b569ef4fc2c9 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -10,6 +10,7 @@ use rustc_lint_defs::{Applicability, LintExpectationId}; use rustc_span::edition::LATEST_STABLE_EDITION; use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol}; use rustc_span::{edition::Edition, Span, DUMMY_SP}; +use rustc_target::spec::PanicStrategy; use std::borrow::Cow; use std::fmt; use std::hash::{Hash, Hasher}; @@ -144,6 +145,12 @@ impl IntoDiagnosticArg for usize { } } +impl IntoDiagnosticArg for PanicStrategy { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(self.desc().to_string())) + } +} + impl<'source> Into> for DiagnosticArgValue<'source> { fn into(self) -> FluentValue<'source> { match self { diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index f9aa3733f6a3..edffec8ab55c 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -750,13 +750,10 @@ impl<'a> CrateLoader<'a> { // Sanity check the loaded crate to ensure it is indeed a panic runtime // and the panic strategy is indeed what we thought it was. if !data.is_panic_runtime() { - self.sess.emit_err(CrateNotPanicRuntime { crate_name: name.to_string() }); + self.sess.emit_err(CrateNotPanicRuntime { crate_name: name }); } if data.required_panic_strategy() != Some(desired_strategy) { - self.sess.emit_err(NoPanicStrategy { - crate_name: name.to_string(), - strategy: desired_strategy.desc().to_string(), - }); + self.sess.emit_err(NoPanicStrategy { crate_name: name, strategy: desired_strategy }); } self.cstore.injected_panic_runtime = Some(cnum); @@ -784,7 +781,7 @@ impl<'a> CrateLoader<'a> { // Sanity check the loaded crate to ensure it is indeed a profiler runtime if !data.is_profiler_runtime() { - self.sess.emit_err(NotProfilerRuntime { crate_name: name.to_string() }); + self.sess.emit_err(NotProfilerRuntime { crate_name: name }); } } @@ -828,8 +825,8 @@ impl<'a> CrateLoader<'a> { match global_allocator { Some(other_crate) => { self.sess.emit_err(ConflictingGlobalAlloc { - crate_name: data.name().to_string(), - other_crate_name: other_crate.to_string(), + crate_name: data.name(), + other_crate_name: other_crate, }); } None => global_allocator = Some(data.name()), @@ -874,9 +871,9 @@ impl<'a> CrateLoader<'a> { let data = self.cstore.get_crate_data(dep); if needs_dep(&data) { self.sess.emit_err(NoTransitiveNeedsDep { - crate_name: self.cstore.get_crate_data(krate).name().to_string(), - needs_crate_name: what.to_string(), - deps_crate_name: data.name().to_string(), + crate_name: self.cstore.get_crate_data(krate).name(), + needs_crate_name: what, + deps_crate_name: data.name(), }); } } diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index 5d1082acc0be..9ad0099ad251 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -140,7 +140,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { if src.rlib.is_some() { continue; } - sess.emit_err(RlibRequired { crate_name: tcx.crate_name(cnum).to_string() }); + sess.emit_err(RlibRequired { crate_name: tcx.crate_name(cnum) }); } return Vec::new(); } @@ -224,10 +224,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { Linkage::Static => "rlib", _ => "dylib", }; - sess.emit_err(LibRequired { - crate_name: tcx.crate_name(cnum).to_string(), - kind: kind.to_string(), - }); + sess.emit_err(LibRequired { crate_name: tcx.crate_name(cnum), kind: kind }); } } } @@ -251,8 +248,7 @@ fn add_library( // This error is probably a little obscure, but I imagine that it // can be refined over time. if link2 != link || link == RequireStatic { - tcx.sess - .emit_err(CrateDepMultiple { crate_name: tcx.crate_name(cnum).to_string() }); + tcx.sess.emit_err(CrateDepMultiple { crate_name: tcx.crate_name(cnum) }); } } None => { @@ -347,8 +343,8 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) { if tcx.is_panic_runtime(cnum) { if let Some((prev, _)) = panic_runtime { - let prev_name = tcx.crate_name(prev).to_string(); - let cur_name = tcx.crate_name(cnum).to_string(); + let prev_name = tcx.crate_name(prev); + let cur_name = tcx.crate_name(cnum); sess.emit_err(TwoPanicRuntimes { prev_name, cur_name }); } panic_runtime = Some(( @@ -370,8 +366,8 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) { // our same strategy. if found_strategy != desired_strategy { sess.emit_err(BadPanicStrategy { - runtime: tcx.crate_name(runtime_cnum).to_string(), - strategy: desired_strategy.desc().to_string(), + runtime: tcx.crate_name(runtime_cnum), + strategy: desired_strategy, }); } @@ -390,17 +386,17 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) { if let Some(found_strategy) = tcx.required_panic_strategy(cnum) && desired_strategy != found_strategy { sess.emit_err(RequiredPanicStrategy { - crate_name: tcx.crate_name(cnum).to_string(), - found_strategy: found_strategy.desc().to_string(), - desired_strategy: desired_strategy.desc().to_string() }); + crate_name: tcx.crate_name(cnum), + found_strategy, + desired_strategy}); } let found_drop_strategy = tcx.panic_in_drop_strategy(cnum); if tcx.sess.opts.unstable_opts.panic_in_drop != found_drop_strategy { sess.emit_err(IncompatiblePanicInDropStrategy { - crate_name: tcx.crate_name(cnum).to_string(), - found_strategy: found_drop_strategy.desc().to_string(), - desired_strategy: tcx.sess.opts.unstable_opts.panic_in_drop.desc().to_string(), + crate_name: tcx.crate_name(cnum), + found_strategy: found_drop_strategy, + desired_strategy: tcx.sess.opts.unstable_opts.panic_in_drop, }); } } diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index d3f35ca8d164..565c96917e2f 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -1,59 +1,64 @@ -use std::path::PathBuf; +use std::{ + io::Error, + path::{Path, PathBuf}, +}; -use rustc_errors::{DiagnosticId, ErrorGuaranteed}; +use rustc_errors::{error_code, ErrorGuaranteed}; use rustc_macros::SessionDiagnostic; use rustc_session::{config, SessionDiagnostic}; use rustc_span::{sym, Span, Symbol}; -use rustc_target::spec::TargetTriple; +use rustc_target::spec::{PanicStrategy, TargetTriple}; + +use crate::locator::CrateFlavor; #[derive(SessionDiagnostic)] #[diag(metadata::rlib_required)] pub struct RlibRequired { - pub crate_name: String, + pub crate_name: Symbol, } #[derive(SessionDiagnostic)] #[diag(metadata::lib_required)] -pub struct LibRequired { - pub crate_name: String, - pub kind: String, +pub struct LibRequired<'a> { + pub crate_name: Symbol, + pub kind: &'a str, } #[derive(SessionDiagnostic)] #[diag(metadata::crate_dep_multiple)] #[help] pub struct CrateDepMultiple { - pub crate_name: String, + pub crate_name: Symbol, } #[derive(SessionDiagnostic)] #[diag(metadata::two_panic_runtimes)] pub struct TwoPanicRuntimes { - pub prev_name: String, - pub cur_name: String, + pub prev_name: Symbol, + pub cur_name: Symbol, } #[derive(SessionDiagnostic)] #[diag(metadata::bad_panic_strategy)] pub struct BadPanicStrategy { - pub runtime: String, - pub strategy: String, + pub runtime: Symbol, + pub strategy: PanicStrategy, } #[derive(SessionDiagnostic)] #[diag(metadata::required_panic_strategy)] pub struct RequiredPanicStrategy { - pub crate_name: String, - pub found_strategy: String, - pub desired_strategy: String, + pub crate_name: Symbol, + pub found_strategy: PanicStrategy, + pub desired_strategy: PanicStrategy, } #[derive(SessionDiagnostic)] #[diag(metadata::incompatible_panic_in_drop_strategy)] pub struct IncompatiblePanicInDropStrategy { - pub crate_name: String, - pub found_strategy: String, - pub desired_strategy: String, + pub crate_name: Symbol, + pub found_strategy: PanicStrategy, + pub desired_strategy: PanicStrategy, } #[derive(SessionDiagnostic)] @@ -129,11 +134,11 @@ pub struct FrameworkOnlyWindows { #[derive(SessionDiagnostic)] #[diag(metadata::unknown_link_kind, code = "E0458")] -pub struct UnknownLinkKind { +pub struct UnknownLinkKind<'a> { #[primary_span] #[label] pub span: Span, - pub kind: String, + pub kind: &'a str, } #[derive(SessionDiagnostic)] @@ -180,10 +185,10 @@ pub struct InvalidLinkModifier { #[derive(SessionDiagnostic)] #[diag(metadata::multiple_modifiers)] -pub struct MultipleModifiers { +pub struct MultipleModifiers<'a> { #[primary_span] pub span: Span, - pub modifier: String, + pub modifier: &'a str, } #[derive(SessionDiagnostic)] @@ -209,10 +214,10 @@ pub struct AsNeededCompatibility { #[derive(SessionDiagnostic)] #[diag(metadata::unknown_link_modifier)] -pub struct UnknownLinkModifier { +pub struct UnknownLinkModifier<'a> { #[primary_span] pub span: Span, - pub modifier: String, + pub modifier: &'a str, } #[derive(SessionDiagnostic)] @@ -250,20 +255,20 @@ pub struct LibFrameworkApple; #[derive(SessionDiagnostic)] #[diag(metadata::empty_renaming_target)] -pub struct EmptyRenamingTarget { - pub lib_name: String, +pub struct EmptyRenamingTarget<'a> { + pub lib_name: &'a str, } #[derive(SessionDiagnostic)] #[diag(metadata::renaming_no_link)] -pub struct RenamingNoLink { - pub lib_name: String, +pub struct RenamingNoLink<'a> { + pub lib_name: &'a str, } #[derive(SessionDiagnostic)] #[diag(metadata::multiple_renamings)] -pub struct MultipleRenamings { - pub lib_name: String, +pub struct MultipleRenamings<'a> { + pub lib_name: &'a str, } #[derive(SessionDiagnostic)] @@ -290,32 +295,32 @@ pub struct UnsupportedAbi { #[derive(SessionDiagnostic)] #[diag(metadata::fail_create_file_encoder)] pub struct FailCreateFileEncoder { - pub err: String, + pub err: Error, } #[derive(SessionDiagnostic)] #[diag(metadata::fail_seek_file)] pub struct FailSeekFile { - pub err: String, + pub err: Error, } #[derive(SessionDiagnostic)] #[diag(metadata::fail_write_file)] pub struct FailWriteFile { - pub err: String, + pub err: Error, } #[derive(SessionDiagnostic)] #[diag(metadata::crate_not_panic_runtime)] pub struct CrateNotPanicRuntime { - pub crate_name: String, + pub crate_name: Symbol, } #[derive(SessionDiagnostic)] #[diag(metadata::no_panic_strategy)] pub struct NoPanicStrategy { - pub crate_name: String, - pub strategy: String, + pub crate_name: Symbol, + pub strategy: PanicStrategy, } #[derive(SessionDiagnostic)] @@ -325,7 +330,7 @@ pub struct ProfilerBuiltinsNeedsCore; #[derive(SessionDiagnostic)] #[diag(metadata::not_profiler_runtime)] pub struct NotProfilerRuntime { - pub crate_name: String, + pub crate_name: Symbol, } #[derive(SessionDiagnostic)] @@ -341,8 +346,8 @@ pub struct NoMultipleGlobalAlloc { #[derive(SessionDiagnostic)] #[diag(metadata::conflicting_global_alloc)] pub struct ConflictingGlobalAlloc { - pub crate_name: String, - pub other_crate_name: String, + pub crate_name: Symbol, + pub other_crate_name: Symbol, } #[derive(SessionDiagnostic)] @@ -351,36 +356,36 @@ pub struct GlobalAllocRequired; #[derive(SessionDiagnostic)] #[diag(metadata::no_transitive_needs_dep)] -pub struct NoTransitiveNeedsDep { - pub crate_name: String, - pub needs_crate_name: String, - pub deps_crate_name: String, +pub struct NoTransitiveNeedsDep<'a> { + pub crate_name: Symbol, + pub needs_crate_name: &'a str, + pub deps_crate_name: Symbol, } #[derive(SessionDiagnostic)] #[diag(metadata::failed_write_error)] pub struct FailedWriteError { - pub filename: String, - pub err: String, + pub filename: PathBuf, + pub err: Error, } #[derive(SessionDiagnostic)] #[diag(metadata::failed_create_tempdir)] pub struct FailedCreateTempdir { - pub err: String, + pub err: Error, } #[derive(SessionDiagnostic)] #[diag(metadata::failed_create_file)] -pub struct FailedCreateFile { - pub filename: String, - pub err: String, +pub struct FailedCreateFile<'a> { + pub filename: &'a Path, + pub err: Error, } #[derive(SessionDiagnostic)] #[diag(metadata::failed_create_encoded_metadata)] pub struct FailedCreateEncodedMetadata { - pub err: String, + pub err: Error, } #[derive(SessionDiagnostic)] @@ -388,31 +393,31 @@ pub struct FailedCreateEncodedMetadata { pub struct NonAsciiName { #[primary_span] pub span: Span, - pub crate_name: String, + pub crate_name: Symbol, } #[derive(SessionDiagnostic)] #[diag(metadata::extern_location_not_exist)] -pub struct ExternLocationNotExist { +pub struct ExternLocationNotExist<'a> { #[primary_span] pub span: Span, - pub crate_name: String, - pub location: String, + pub crate_name: Symbol, + pub location: &'a Path, } #[derive(SessionDiagnostic)] #[diag(metadata::extern_location_not_file)] -pub struct ExternLocationNotFile { +pub struct ExternLocationNotFile<'a> { #[primary_span] pub span: Span, - pub crate_name: String, - pub location: String, + pub crate_name: Symbol, + pub location: &'a Path, } -pub struct MultipleCandidates { +pub(crate) struct MultipleCandidates { pub span: Span, - pub flavor: String, - pub crate_name: String, + pub flavor: CrateFlavor, + pub crate_name: Symbol, pub candidates: Vec, } @@ -424,7 +429,7 @@ impl SessionDiagnostic<'_> for MultipleCandidates { let mut diag = sess.struct_err(rustc_errors::fluent::metadata::multiple_candidates); diag.set_arg("crate_name", self.crate_name); diag.set_arg("flavor", self.flavor); - diag.code(DiagnosticId::Error("E0465".into())); + diag.code(error_code!(E0465)); diag.set_span(self.span); for (i, candidate) in self.candidates.iter().enumerate() { diag.span_note(self.span, &format!("candidate #{}: {}", i + 1, candidate.display())); @@ -439,7 +444,7 @@ impl SessionDiagnostic<'_> for MultipleCandidates { pub struct MultipleMatchingCrates { #[primary_span] pub span: Span, - pub crate_name: String, + pub crate_name: Symbol, pub candidates: String, } @@ -448,7 +453,7 @@ pub struct MultipleMatchingCrates { pub struct SymbolConflictsCurrent { #[primary_span] pub span: Span, - pub crate_name: String, + pub crate_name: Symbol, } #[derive(SessionDiagnostic)] @@ -456,7 +461,7 @@ pub struct SymbolConflictsCurrent { pub struct SymbolConflictsOthers { #[primary_span] pub span: Span, - pub crate_name: String, + pub crate_name: Symbol, } #[derive(SessionDiagnostic)] @@ -464,8 +469,8 @@ pub struct SymbolConflictsOthers { pub struct StableCrateIdCollision { #[primary_span] pub span: Span, - pub crate_name0: String, - pub crate_name1: String, + pub crate_name0: Symbol, + pub crate_name1: Symbol, } #[derive(SessionDiagnostic)] @@ -483,7 +488,7 @@ pub struct DlError { pub struct NewerCrateVersion { #[primary_span] pub span: Span, - pub crate_name: String, + pub crate_name: Symbol, pub add_info: String, pub found_crates: String, } @@ -491,11 +496,11 @@ pub struct NewerCrateVersion { #[derive(SessionDiagnostic)] #[diag(metadata::no_crate_with_triple, code = "E0461")] #[note(metadata::found_crate_versions)] -pub struct NoCrateWithTriple { +pub struct NoCrateWithTriple<'a> { #[primary_span] pub span: Span, - pub crate_name: String, - pub locator_triple: String, + pub crate_name: Symbol, + pub locator_triple: &'a str, pub add_info: String, pub found_crates: String, } @@ -507,7 +512,7 @@ pub struct NoCrateWithTriple { pub struct FoundStaticlib { #[primary_span] pub span: Span, - pub crate_name: String, + pub crate_name: Symbol, pub add_info: String, pub found_crates: String, } @@ -519,7 +524,7 @@ pub struct FoundStaticlib { pub struct IncompatibleRustc { #[primary_span] pub span: Span, - pub crate_name: String, + pub crate_name: Symbol, pub add_info: String, pub found_crates: String, pub rustc_version: String, @@ -527,7 +532,7 @@ pub struct IncompatibleRustc { pub struct InvalidMetadataFiles { pub span: Span, - pub crate_name: String, + pub crate_name: Symbol, pub add_info: String, pub crate_rejections: Vec, } @@ -540,7 +545,7 @@ impl SessionDiagnostic<'_> for InvalidMetadataFiles { let mut diag = sess.struct_err(rustc_errors::fluent::metadata::invalid_meta_files); diag.set_arg("crate_name", self.crate_name); diag.set_arg("add_info", self.add_info); - diag.code(DiagnosticId::Error("E0786".into())); + diag.code(error_code!(E0786)); diag.set_span(self.span); for crate_rejection in self.crate_rejections { diag.note(crate_rejection); @@ -551,8 +556,7 @@ impl SessionDiagnostic<'_> for InvalidMetadataFiles { pub struct CannotFindCrate { pub span: Span, - pub crate_name: String, - pub crate_name_symbol: Symbol, + pub crate_name: Symbol, pub add_info: String, pub missing_core: bool, pub current_crate: String, @@ -567,53 +571,41 @@ impl SessionDiagnostic<'_> for CannotFindCrate { sess: &'_ rustc_session::parse::ParseSess, ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { let mut diag = sess.struct_err(rustc_errors::fluent::metadata::cannot_find_crate); - diag.set_arg("crate_name", self.crate_name.clone()); + diag.set_arg("crate_name", self.crate_name); diag.set_arg("add_info", self.add_info); - diag.code(DiagnosticId::Error("E0463".into())); + diag.set_arg("locator_triple", self.locator_triple.triple()); + diag.code(error_code!(E0463)); diag.set_span(self.span); - // FIXME: Find a way to distill this logic down into the derived SessionDiagnostic form - if (self.crate_name_symbol == sym::std || self.crate_name_symbol == sym::core) + if (self.crate_name == sym::std || self.crate_name == sym::core) && self.locator_triple != TargetTriple::from_triple(config::host_triple()) { if self.missing_core { - diag.note(&format!("the `{}` target may not be installed", self.locator_triple)); + diag.note(rustc_errors::fluent::metadata::target_not_installed); } else { - diag.note(&format!( - "the `{}` target may not support the standard library", - self.locator_triple - )); + diag.note(rustc_errors::fluent::metadata::target_no_std_support); } // NOTE: this suggests using rustup, even though the user may not have it installed. // That's because they could choose to install it; or this may give them a hint which // target they need to install from their distro. if self.missing_core { - diag.help(&format!( - "consider downloading the target with `rustup target add {}`", - self.locator_triple - )); + diag.help(rustc_errors::fluent::metadata::consider_downloading_target); } // Suggest using #![no_std]. #[no_core] is unstable and not really supported anyway. // NOTE: this is a dummy span if `extern crate std` was injected by the compiler. // If it's not a dummy, that means someone added `extern crate std` explicitly and // `#![no_std]` won't help. if !self.missing_core && self.span.is_dummy() { - diag.note(&format!( - "`std` is required by `{}` because it does not declare `#![no_std]`", - self.current_crate - )); + diag.note(rustc_errors::fluent::metadata::std_required); } if self.is_nightly_build { - diag.help("consider building the standard library from source with `cargo build -Zbuild-std`"); + diag.help(rustc_errors::fluent::metadata::consider_building_std); } - } else if self.crate_name_symbol == self.profiler_runtime { - diag.note("the compiler may have been built without the profiler runtime"); - } else if self.crate_name.starts_with("rustc_") { - diag.help( - "maybe you need to install the missing components with: \ - `rustup component add rust-src rustc-dev llvm-tools-preview`", - ); + } else if self.crate_name == self.profiler_runtime { + diag.note(rustc_errors::fluent::metadata::compiler_missing_profiler); + } else if self.crate_name.as_str().starts_with("rustc_") { + diag.help(rustc_errors::fluent::metadata::install_missing_components); } - diag.span_label(self.span, "can't find crate"); + diag.span_label(self.span, rustc_errors::fluent::metadata::cant_find_crate); diag } } @@ -623,5 +615,22 @@ impl SessionDiagnostic<'_> for CannotFindCrate { pub struct NoDylibPlugin { #[primary_span] pub span: Span, - pub crate_name: String, + pub crate_name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::crate_location_unknown_type)] +pub struct CrateLocationUnknownType<'a> { + #[primary_span] + pub span: Span, + pub path: &'a Path, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::lib_filename_form)] +pub struct LibFilenameForm<'a> { + #[primary_span] + pub span: Span, + pub dll_prefix: &'a str, + pub dll_suffix: &'a str, } diff --git a/compiler/rustc_metadata/src/fs.rs b/compiler/rustc_metadata/src/fs.rs index 67c18766c595..f360a586476e 100644 --- a/compiler/rustc_metadata/src/fs.rs +++ b/compiler/rustc_metadata/src/fs.rs @@ -26,11 +26,8 @@ pub fn emit_metadata(sess: &Session, metadata: &[u8], tmpdir: &MaybeTempDir) -> let out_filename = tmpdir.as_ref().join(METADATA_FILENAME); let result = fs::write(&out_filename, metadata); - if let Err(e) = result { - sess.emit_fatal(FailedWriteError { - filename: out_filename.display().to_string(), - err: e.to_string(), - }); + if let Err(err) = result { + sess.emit_fatal(FailedWriteError { filename: out_filename, err }); } out_filename @@ -71,7 +68,7 @@ pub fn encode_and_write_metadata( let metadata_tmpdir = TempFileBuilder::new() .prefix("rmeta") .tempdir_in(out_filename.parent().unwrap_or_else(|| Path::new(""))) - .unwrap_or_else(|err| tcx.sess.emit_fatal(FailedCreateTempdir { err: err.to_string() })); + .unwrap_or_else(|err| tcx.sess.emit_fatal(FailedCreateTempdir { err })); let metadata_tmpdir = MaybeTempDir::new(metadata_tmpdir, tcx.sess.opts.cg.save_temps); let metadata_filename = metadata_tmpdir.as_ref().join(METADATA_FILENAME); @@ -79,11 +76,8 @@ pub fn encode_and_write_metadata( // This simplifies the creation of the output `out_filename` when requested. match metadata_kind { MetadataKind::None => { - std::fs::File::create(&metadata_filename).unwrap_or_else(|e| { - tcx.sess.emit_fatal(FailedCreateFile { - filename: metadata_filename.display().to_string(), - err: e.to_string(), - }); + std::fs::File::create(&metadata_filename).unwrap_or_else(|err| { + tcx.sess.emit_fatal(FailedCreateFile { filename: &metadata_filename, err }); }); } MetadataKind::Uncompressed | MetadataKind::Compressed => { @@ -98,11 +92,8 @@ pub fn encode_and_write_metadata( // this file always exists. let need_metadata_file = tcx.sess.opts.output_types.contains_key(&OutputType::Metadata); let (metadata_filename, metadata_tmpdir) = if need_metadata_file { - if let Err(e) = non_durable_rename(&metadata_filename, &out_filename) { - tcx.sess.emit_fatal(FailedWriteError { - filename: out_filename.display().to_string(), - err: e.to_string(), - }); + if let Err(err) = non_durable_rename(&metadata_filename, &out_filename) { + tcx.sess.emit_fatal(FailedWriteError { filename: out_filename, err }); } if tcx.sess.opts.json_artifact_notifications { tcx.sess @@ -117,8 +108,8 @@ pub fn encode_and_write_metadata( // Load metadata back to memory: codegen may need to include it in object files. let metadata = - EncodedMetadata::from_path(metadata_filename, metadata_tmpdir).unwrap_or_else(|e| { - tcx.sess.emit_fatal(FailedCreateEncodedMetadata { err: e.to_string() }); + EncodedMetadata::from_path(metadata_filename, metadata_tmpdir).unwrap_or_else(|err| { + tcx.sess.emit_fatal(FailedCreateEncodedMetadata { err }); }); let need_metadata_module = metadata_kind == MetadataKind::Compressed; diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 83c8756078ec..5edad819e7e3 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -214,10 +214,11 @@ use crate::creader::Library; use crate::errors::{ - CannotFindCrate, DlError, ExternLocationNotExist, ExternLocationNotFile, FoundStaticlib, - IncompatibleRustc, InvalidMetadataFiles, MultipleCandidates, MultipleMatchingCrates, - NewerCrateVersion, NoCrateWithTriple, NoDylibPlugin, NonAsciiName, StableCrateIdCollision, - SymbolConflictsCurrent, SymbolConflictsOthers, + CannotFindCrate, CrateLocationUnknownType, DlError, ExternLocationNotExist, + ExternLocationNotFile, FoundStaticlib, IncompatibleRustc, InvalidMetadataFiles, + LibFilenameForm, MultipleCandidates, MultipleMatchingCrates, NewerCrateVersion, + NoCrateWithTriple, NoDylibPlugin, NonAsciiName, StableCrateIdCollision, SymbolConflictsCurrent, + SymbolConflictsOthers, }; use crate::rmeta::{rustc_version, MetadataBlob, METADATA_HEADER}; @@ -226,7 +227,7 @@ use rustc_data_structures::memmap::Mmap; use rustc_data_structures::owning_ref::OwningRef; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::MetadataRef; -use rustc_errors::FatalError; +use rustc_errors::{DiagnosticArgValue, FatalError, IntoDiagnosticArg}; use rustc_session::config::{self, CrateType}; use rustc_session::cstore::{CrateSource, MetadataLoader}; use rustc_session::filesearch::FileSearch; @@ -238,6 +239,7 @@ use rustc_span::Span; use rustc_target::spec::{Target, TargetTriple}; use snap::read::FrameDecoder; +use std::borrow::Cow; use std::fmt::Write as _; use std::io::{Read, Result as IoResult, Write}; use std::path::{Path, PathBuf}; @@ -294,6 +296,16 @@ impl fmt::Display for CrateFlavor { } } +impl IntoDiagnosticArg for CrateFlavor { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + match self { + CrateFlavor::Rlib => DiagnosticArgValue::Str(Cow::Borrowed("rlib")), + CrateFlavor::Rmeta => DiagnosticArgValue::Str(Cow::Borrowed("rmeta")), + CrateFlavor::Dylib => DiagnosticArgValue::Str(Cow::Borrowed("dylib")), + } + } +} + impl<'a> CrateLocator<'a> { pub(crate) fn new( sess: &'a Session, @@ -946,29 +958,16 @@ impl CrateError { pub(crate) fn report(self, sess: &Session, span: Span, missing_core: bool) { match self { CrateError::NonAsciiName(crate_name) => { - sess.emit_err(NonAsciiName { span, crate_name: crate_name.to_string() }); + sess.emit_err(NonAsciiName { span, crate_name }); } CrateError::ExternLocationNotExist(crate_name, loc) => { - sess.emit_err(ExternLocationNotExist { - span, - crate_name: crate_name.to_string(), - location: loc.display().to_string(), - }); + sess.emit_err(ExternLocationNotExist { span, crate_name, location: &loc }); } CrateError::ExternLocationNotFile(crate_name, loc) => { - sess.emit_err(ExternLocationNotFile { - span, - crate_name: crate_name.to_string(), - location: loc.display().to_string(), - }); + sess.emit_err(ExternLocationNotFile { span, crate_name, location: &loc }); } CrateError::MultipleCandidates(crate_name, flavor, candidates) => { - sess.emit_err(MultipleCandidates { - span, - flavor: flavor.to_string(), - crate_name: crate_name.to_string(), - candidates, - }); + sess.emit_err(MultipleCandidates { span, flavor: flavor, crate_name, candidates }); } CrateError::MultipleMatchingCrates(crate_name, libraries) => { let mut libraries: Vec<_> = libraries.into_values().collect(); @@ -998,27 +997,23 @@ impl CrateError { s }) .collect::(); - sess.emit_err(MultipleMatchingCrates { - span, - crate_name: crate_name.to_string(), - candidates, - }); + sess.emit_err(MultipleMatchingCrates { span, crate_name, candidates }); } CrateError::SymbolConflictsCurrent(root_name) => { - sess.emit_err(SymbolConflictsCurrent { span, crate_name: root_name.to_string() }); + sess.emit_err(SymbolConflictsCurrent { span, crate_name: root_name }); } CrateError::SymbolConflictsOthers(root_name) => { - sess.emit_err(SymbolConflictsOthers { span, crate_name: root_name.to_string() }); + sess.emit_err(SymbolConflictsOthers { span, crate_name: root_name }); } CrateError::StableCrateIdCollision(crate_name0, crate_name1) => { sess.emit_err(StableCrateIdCollision { span, - crate_name0: crate_name0.to_string(), - crate_name1: crate_name1.to_string(), + crate_name0: crate_name0, + crate_name1: crate_name1, }); } CrateError::DlOpen(s) | CrateError::DlSym(s) => { - sess.emit_err(DlError { span, err: s.to_string() }); + sess.emit_err(DlError { span, err: s }); } CrateError::LocatorCombined(locator) => { let crate_name = locator.crate_name; @@ -1026,24 +1021,17 @@ impl CrateError { None => String::new(), Some(r) => format!(" which `{}` depends on", r.name), }; - // FIXME: Is there any way to get these notes and helps onto every diagnostic in this - // huge branch arm without changing them all to manual implementations? - let mut global_loc_notes = Vec::new(); - let mut global_loc_helps = Vec::new(); + // FIXME: There are no tests for CrateLocationUnknownType or LibFilenameForm if !locator.crate_rejections.via_filename.is_empty() { let mismatches = locator.crate_rejections.via_filename.iter(); for CrateMismatch { path, .. } in mismatches { - global_loc_notes.push(format!( - "extern location for {} is of an unknown type: {}", - crate_name, - path.display(), - )); - global_loc_helps.push(format!( - "file name should be lib*.rlib or {}*.{}", - locator.dll_prefix, locator.dll_suffix - )); + sess.emit_err(CrateLocationUnknownType { span, path: &path }); + sess.emit_err(LibFilenameForm { + span, + dll_prefix: &locator.dll_prefix, + dll_suffix: &locator.dll_suffix, + }); } - panic!("!!!!! REVERT THIS COMMIT !!!!!"); } let mut found_crates = String::new(); if !locator.crate_rejections.via_hash.is_empty() { @@ -1066,7 +1054,7 @@ impl CrateError { } sess.emit_err(NewerCrateVersion { span, - crate_name: crate_name.to_string(), + crate_name: crate_name, add_info, found_crates, }); @@ -1082,8 +1070,8 @@ impl CrateError { } sess.emit_err(NoCrateWithTriple { span, - crate_name: crate_name.to_string(), - locator_triple: locator.triple.to_string(), + crate_name: crate_name, + locator_triple: locator.triple.triple(), add_info, found_crates, }); @@ -1096,12 +1084,7 @@ impl CrateError { path.display() )); } - sess.emit_err(FoundStaticlib { - span, - crate_name: crate_name.to_string(), - add_info, - found_crates, - }); + sess.emit_err(FoundStaticlib { span, crate_name, add_info, found_crates }); } else if !locator.crate_rejections.via_version.is_empty() { let mismatches = locator.crate_rejections.via_version.iter(); for CrateMismatch { path, got } in mismatches { @@ -1114,7 +1097,7 @@ impl CrateError { } sess.emit_err(IncompatibleRustc { span, - crate_name: crate_name.to_string(), + crate_name, add_info, found_crates, rustc_version: rustc_version(), @@ -1126,15 +1109,14 @@ impl CrateError { } sess.emit_err(InvalidMetadataFiles { span, - crate_name: crate_name.to_string(), + crate_name, add_info, crate_rejections, }); } else { sess.emit_err(CannotFindCrate { span, - crate_name: crate_name.to_string(), - crate_name_symbol: crate_name, + crate_name, add_info, missing_core, current_crate: sess @@ -1149,7 +1131,7 @@ impl CrateError { } } CrateError::NonDylibPlugin(crate_name) => { - sess.emit_err(NoDylibPlugin { span, crate_name: crate_name.to_string() }); + sess.emit_err(NoDylibPlugin { span, crate_name }); } } } diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index dbaa2e9defa1..19f64ef70c9c 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -124,7 +124,7 @@ impl<'tcx> Collector<'tcx> { NativeLibKind::RawDylib } kind => { - sess.emit_err(UnknownLinkKind { span, kind: kind.to_string() }); + sess.emit_err(UnknownLinkKind { span, kind }); continue; } }; @@ -249,10 +249,7 @@ impl<'tcx> Collector<'tcx> { } let assign_modifier = |dst: &mut Option| { if dst.is_some() { - sess.emit_err(MultipleModifiers { - span, - modifier: modifier.to_string(), - }); + sess.emit_err(MultipleModifiers { span, modifier }); } else { *dst = Some(value); } @@ -287,10 +284,7 @@ impl<'tcx> Collector<'tcx> { } _ => { - sess.emit_err(UnknownLinkModifier { - span, - modifier: modifier.to_string(), - }); + sess.emit_err(UnknownLinkModifier { span, modifier }); } } } @@ -379,11 +373,11 @@ impl<'tcx> Collector<'tcx> { .filter_map(|lib| lib.name.as_ref()) .any(|n| n.as_str() == lib.name); if new_name.is_empty() { - self.tcx.sess.emit_err(EmptyRenamingTarget { lib_name: lib.name.clone() }); + self.tcx.sess.emit_err(EmptyRenamingTarget { lib_name: &lib.name }); } else if !any_duplicate { - self.tcx.sess.emit_err(RenamingNoLink { lib_name: lib.name.clone() }); + self.tcx.sess.emit_err(RenamingNoLink { lib_name: &lib.name }); } else if !renames.insert(&lib.name) { - self.tcx.sess.emit_err(MultipleRenamings { lib_name: lib.name.clone() }); + self.tcx.sess.emit_err(MultipleRenamings { lib_name: &lib.name }); } } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 2b1f9f17a3c8..8f55fb59f0bf 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -2270,7 +2270,7 @@ pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path) { fn encode_metadata_impl(tcx: TyCtxt<'_>, path: &Path) { let mut encoder = opaque::FileEncoder::new(path) - .unwrap_or_else(|err| tcx.sess.emit_fatal(FailCreateFileEncoder { err: err.to_string() })); + .unwrap_or_else(|err| tcx.sess.emit_fatal(FailCreateFileEncoder { err })); encoder.emit_raw_bytes(METADATA_HEADER); // Will be filled with the root position after encoding everything. @@ -2315,10 +2315,10 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>, path: &Path) { // Encode the root position. let header = METADATA_HEADER.len(); file.seek(std::io::SeekFrom::Start(header as u64)) - .unwrap_or_else(|err| tcx.sess.emit_fatal(FailSeekFile { err: err.to_string() })); + .unwrap_or_else(|err| tcx.sess.emit_fatal(FailSeekFile { err })); let pos = root.position.get(); file.write_all(&[(pos >> 24) as u8, (pos >> 16) as u8, (pos >> 8) as u8, (pos >> 0) as u8]) - .unwrap_or_else(|err| tcx.sess.emit_fatal(FailWriteFile { err: err.to_string() })); + .unwrap_or_else(|err| tcx.sess.emit_fatal(FailWriteFile { err })); // Return to the position where we are before writing the root position. file.seek(std::io::SeekFrom::Start(pos_before_seek)).unwrap(); From 30adfd6a17bd0d7c4d1302cc4a0f92962577de4a Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Sat, 27 Aug 2022 17:50:11 -0600 Subject: [PATCH 4014/5092] port 5 new diagnostics that appeared in master --- .../locales/en-US/metadata.ftl | 15 ++++++++ compiler/rustc_metadata/src/errors.rs | 36 +++++++++++++++++++ compiler/rustc_metadata/src/native_libs.rs | 36 +++++++++---------- 3 files changed, 67 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/metadata.ftl b/compiler/rustc_error_messages/locales/en-US/metadata.ftl index dee01bcad4bb..00067a1bf6ad 100644 --- a/compiler/rustc_error_messages/locales/en-US/metadata.ftl +++ b/compiler/rustc_error_messages/locales/en-US/metadata.ftl @@ -255,3 +255,18 @@ metadata_crate_location_unknown_type = metadata_lib_filename_form = file name should be lib*.rlib or {dll_prefix}*.{dll_suffix} + +metadata_multiple_import_name_type = + multiple `import_name_type` arguments in a single `#[link]` attribute + +metadata_import_name_type_form = + import name type must be of the form `import_name_type = "string"` + +metadata_import_name_type_x86 = + import name type is only supported on x86 + +metadata_unknown_import_name_type = + unknown import name type `{$import_name_type}`, expected one of: decorated, noprefix, undecorated + +metadata_import_name_type_raw = + import name type can only be used with link kind `raw-dylib` diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index 565c96917e2f..18d0248333a5 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -634,3 +634,39 @@ pub struct LibFilenameForm<'a> { pub dll_prefix: &'a str, pub dll_suffix: &'a str, } + +#[derive(SessionDiagnostic)] +#[diag(metadata::multiple_import_name_type)] +pub struct MultipleImportNameType { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::import_name_type_form)] +pub struct ImportNameTypeForm { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::import_name_type_x86)] +pub struct ImportNameTypeX86 { + #[primary_span] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::unknown_import_name_type)] +pub struct UnknownImportNameType<'a> { + #[primary_span] + pub span: Span, + pub import_name_type: &'a str, +} + +#[derive(SessionDiagnostic)] +#[diag(metadata::import_name_type_raw)] +pub struct ImportNameTypeRaw { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 19f64ef70c9c..87b5e750f1cb 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -13,13 +13,14 @@ use rustc_target::spec::abi::Abi; use crate::errors::{ AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, EmptyRenamingTarget, - FrameworkOnlyWindows, IncompatibleWasmLink, InvalidLinkModifier, LibFrameworkApple, - LinkCfgForm, LinkCfgSinglePredicate, LinkFrameworkApple, LinkKindForm, LinkModifiersForm, - LinkNameForm, LinkOrdinalRawDylib, LinkRequiresName, MultipleCfgs, MultipleKindsInLink, - MultipleLinkModifiers, MultipleModifiers, MultipleNamesInLink, MultipleRenamings, - MultipleWasmImport, NoLinkModOverride, RawDylibNoNul, RenamingNoLink, UnexpectedLinkArg, - UnknownLinkKind, UnknownLinkModifier, UnsupportedAbi, UnsupportedAbiI686, WasmImportForm, - WholeArchiveNeedsStatic, + FrameworkOnlyWindows, ImportNameTypeForm, ImportNameTypeRaw, ImportNameTypeX86, + IncompatibleWasmLink, InvalidLinkModifier, LibFrameworkApple, LinkCfgForm, + LinkCfgSinglePredicate, LinkFrameworkApple, LinkKindForm, LinkModifiersForm, LinkNameForm, + LinkOrdinalRawDylib, LinkRequiresName, MultipleCfgs, MultipleImportNameType, + MultipleKindsInLink, MultipleLinkModifiers, MultipleModifiers, MultipleNamesInLink, + MultipleRenamings, MultipleWasmImport, NoLinkModOverride, RawDylibNoNul, RenamingNoLink, + UnexpectedLinkArg, UnknownImportNameType, UnknownLinkKind, UnknownLinkModifier, UnsupportedAbi, + UnsupportedAbiI686, WasmImportForm, WholeArchiveNeedsStatic, }; pub(crate) fn collect(tcx: TyCtxt<'_>) -> Vec { @@ -178,18 +179,15 @@ impl<'tcx> Collector<'tcx> { } sym::import_name_type => { if import_name_type.is_some() { - let msg = "multiple `import_name_type` arguments in a single `#[link]` attribute"; - sess.span_err(item.span(), msg); + sess.emit_err(MultipleImportNameType { span: item.span() }); continue; } let Some(link_import_name_type) = item.value_str() else { - let msg = "import name type must be of the form `import_name_type = \"string\"`"; - sess.span_err(item.span(), msg); + sess.emit_err(ImportNameTypeForm { span: item.span() }); continue; }; if self.tcx.sess.target.arch != "x86" { - let msg = "import name type is only supported on x86"; - sess.span_err(item.span(), msg); + sess.emit_err(ImportNameTypeX86 { span: item.span() }); continue; } @@ -198,11 +196,10 @@ impl<'tcx> Collector<'tcx> { "noprefix" => PeImportNameType::NoPrefix, "undecorated" => PeImportNameType::Undecorated, import_name_type => { - let msg = format!( - "unknown import name type `{import_name_type}`, expected one of: \ - decorated, noprefix, undecorated" - ); - sess.span_err(item.span(), msg); + sess.emit_err(UnknownImportNameType { + span: item.span(), + import_name_type, + }); continue; } }; @@ -301,8 +298,7 @@ impl<'tcx> Collector<'tcx> { // Do this outside of the loop so that `import_name_type` can be specified before `kind`. if let Some((_, span)) = import_name_type { if kind != Some(NativeLibKind::RawDylib) { - let msg = "import name type can only be used with link kind `raw-dylib`"; - sess.span_err(span, msg); + sess.emit_err(ImportNameTypeRaw { span }); } } From f921f5626d1dcc08f2707ed2c22e22fd1ad678b7 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Wed, 31 Aug 2022 11:10:19 -0700 Subject: [PATCH 4015/5092] Use parent_iter instead of a find_parent_node loop --- compiler/rustc_middle/src/hir/map/mod.rs | 3 +++ .../src/check/generator_interior.rs | 20 +++++++------------ 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 8f7877392483..6217bffb8f76 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -291,6 +291,9 @@ impl<'hir> Map<'hir> { Some(def_kind) } + /// Finds the id of the parent node to this one. + /// + /// If calling repeatedly and iterating over parents, prefer [`Map::parent_iter`]. pub fn find_parent_node(self, id: HirId) -> Option { if id.local_id == ItemLocalId::from_u32(0) { Some(self.tcx.hir_owner_parent(id.owner)) diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs index f73d498aabc2..2710606f9143 100644 --- a/compiler/rustc_typeck/src/check/generator_interior.rs +++ b/compiler/rustc_typeck/src/check/generator_interior.rs @@ -387,18 +387,6 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { ty.needs_drop(self.fcx.tcx, self.fcx.param_env) }; - let find_parent_expr = |mut hir_id| { - let hir = self.fcx.tcx.hir(); - hir_id = hir.find_parent_node(hir_id)?; - loop { - if let hir::Node::Expr(_) = self.fcx.tcx.hir().find(hir_id)? { - return Some(hir_id); - } else { - hir_id = hir.find_parent_node(hir_id)?; - } - } - }; - // Typically, the value produced by an expression is consumed by its parent in some way, // so we only have to check if the parent contains a yield (note that the parent may, for // example, store the value into a local variable, but then we already consider local @@ -421,7 +409,13 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { }) { self.rvalue_scopes.temporary_scope(self.region_scope_tree, expr.hir_id.local_id) } else { - let parent_expr = find_parent_expr(expr.hir_id); + let parent_expr = self + .fcx + .tcx + .hir() + .parent_iter(expr.hir_id) + .find(|(_, node)| matches!(node, hir::Node::Expr(_))) + .map(|(id, _)| id); debug!("parent_expr: {:?}", parent_expr); match parent_expr { Some(parent) => Some(Scope { id: parent.local_id, data: ScopeData::Node }), From fbcc038a224e58f7d3aca25c7f2321f11ce5513d Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Wed, 31 Aug 2022 18:17:32 +0000 Subject: [PATCH 4016/5092] safe transmute: use `to_valtree` to destructure const `Assume` ref: https://github.com/rust-lang/rust/pull/100726#discussion_r954813220 --- compiler/rustc_transmute/src/lib.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index 68270a603a14..2a1a81315657 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -123,7 +123,7 @@ mod rustc { param_env: ParamEnv<'tcx>, c: Const<'tcx>, ) -> Self { - use rustc_middle::ty::DestructuredConst; + use rustc_middle::ty::ScalarInt; use rustc_middle::ty::TypeVisitable; use rustc_span::symbol::sym; @@ -142,9 +142,8 @@ mod rustc { LangItem::TransmuteOpts.name(), ); - let DestructuredConst { variant, fields } = tcx.destructure_const(c); - let variant_idx = variant.expect("The given `Const` must be an ADT."); - let variant = adt_def.variant(variant_idx); + let variant = adt_def.non_enum_variant(); + let fields = c.to_valtree().unwrap_branch(); let get_field = |name| { let (field_idx, _) = variant @@ -153,9 +152,7 @@ mod rustc { .enumerate() .find(|(_, field_def)| name == field_def.name) .expect(&format!("There were no fields named `{name}`.")); - fields[field_idx].try_eval_bool(tcx, param_env).expect(&format!( - "The field named `{name}` lang item could not be evaluated to a bool." - )) + fields[field_idx].unwrap_leaf() == ScalarInt::TRUE }; Self { From 117169799ffb6df9a86f4d3e933968274022bdd3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 29 Aug 2022 18:05:21 +0200 Subject: [PATCH 4017/5092] Generate error index with mdbook instead of raw HTML pages --- Cargo.lock | 2 +- src/bootstrap/doc.rs | 2 +- src/tools/error_index_generator/Cargo.toml | 2 +- .../error_index_generator/book_config.toml | 19 ++ .../error_index_generator/error-index.css | 38 +++ .../error_index_generator/error-index.js | 9 + src/tools/error_index_generator/main.rs | 285 +++++++++--------- src/tools/error_index_generator/redirect.js | 10 + 8 files changed, 220 insertions(+), 147 deletions(-) create mode 100644 src/tools/error_index_generator/book_config.toml create mode 100644 src/tools/error_index_generator/error-index.css create mode 100644 src/tools/error_index_generator/error-index.js create mode 100644 src/tools/error_index_generator/redirect.js diff --git a/Cargo.lock b/Cargo.lock index 7c3879fdd98d..8dff674a630e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1268,7 +1268,7 @@ dependencies = [ name = "error_index_generator" version = "0.0.0" dependencies = [ - "rustdoc", + "mdbook", ] [[package]] diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 2852442d0be6..f909ecc0ab85 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -793,7 +793,7 @@ impl Step for ErrorIndex { t!(fs::create_dir_all(&out)); let mut index = tool::ErrorIndex::command(builder); index.arg("html"); - index.arg(out.join("error-index.html")); + index.arg(out); index.arg(&builder.version); builder.run(&mut index); diff --git a/src/tools/error_index_generator/Cargo.toml b/src/tools/error_index_generator/Cargo.toml index b9fd852f742c..f4dac6e947e3 100644 --- a/src/tools/error_index_generator/Cargo.toml +++ b/src/tools/error_index_generator/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" edition = "2021" [dependencies] -rustdoc = { path = "../../librustdoc" } +mdbook = { version = "0.4", default-features = false, features = ["search"] } [[bin]] name = "error_index_generator" diff --git a/src/tools/error_index_generator/book_config.toml b/src/tools/error_index_generator/book_config.toml new file mode 100644 index 000000000000..885100ae3a44 --- /dev/null +++ b/src/tools/error_index_generator/book_config.toml @@ -0,0 +1,19 @@ +[book] +title = "Error codes index" +description = "Book listing all Rust error codes" +src = "" + +[output.html] +git-repository-url = "https://github.com/rust-lang/rust/" +additional-css = ["error-index.css"] +additional-js = ["error-index.js"] + +[output.html.search] +enable = true +limit-results = 20 +use-boolean-and = true +boost-title = 2 +boost-hierarchy = 2 +boost-paragraph = 1 +expand = true +heading-split-level = 0 diff --git a/src/tools/error_index_generator/error-index.css b/src/tools/error_index_generator/error-index.css new file mode 100644 index 000000000000..8975af82de03 --- /dev/null +++ b/src/tools/error_index_generator/error-index.css @@ -0,0 +1,38 @@ +code.compile_fail { + border-left: 2px solid red; +} + +pre .tooltip { + position: absolute; + left: -25px; + top: 0; + z-index: 1; + color: red; + cursor: pointer; +} +pre .tooltip::after { + display: none; + content: "This example deliberately fails to compile"; + background-color: #000; + color: #fff; + border-color: #000; + text-align: center; + padding: 5px 3px 3px 3px; + border-radius: 6px; + margin-left: 5px; +} +pre .tooltip::before { + display: none; + border-color: transparent black transparent transparent; + content: " "; + position: absolute; + top: 50%; + left: 16px; + margin-top: -5px; + border-width: 5px; + border-style: solid; +} + +pre .tooltip:hover::before, pre .tooltip:hover::after { + display: inline; +} diff --git a/src/tools/error_index_generator/error-index.js b/src/tools/error_index_generator/error-index.js new file mode 100644 index 000000000000..39b371be04b9 --- /dev/null +++ b/src/tools/error_index_generator/error-index.js @@ -0,0 +1,9 @@ +for (const elem of document.querySelectorAll("pre.playground")) { + if (elem.querySelector(".compile_fail") === null) { + continue; + } + const child = document.createElement("div"); + child.className = "tooltip"; + child.textContent = "ⓘ"; + elem.appendChild(child); +} diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index 68c46700361a..5451e45b28be 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -1,20 +1,21 @@ #![feature(rustc_private)] extern crate rustc_driver; -extern crate rustc_span; +// We use the function we generate from `register_diagnostics!`. use crate::error_codes::error_codes; use std::env; use std::error::Error; -use std::fs::{create_dir_all, File}; +use std::fs::{self, create_dir_all, File}; use std::io::Write; use std::path::Path; use std::path::PathBuf; -use rustc_span::edition::DEFAULT_EDITION; +use std::str::FromStr; -use rustdoc::html::markdown::{ErrorCodes, HeadingOffset, IdMap, Markdown, Playground}; +use mdbook::book::{parse_summary, BookItem, Chapter}; +use mdbook::{Config, MDBook}; macro_rules! register_diagnostics { ($($error_code:ident: $message:expr,)+ ; $($undocumented:ident,)* ) => { @@ -33,104 +34,21 @@ macro_rules! register_diagnostics { mod error_codes; enum OutputFormat { - HTML(HTMLFormatter), + HTML, Markdown, Unknown(String), } impl OutputFormat { - fn from(format: &str, resource_suffix: &str) -> OutputFormat { + fn from(format: &str) -> OutputFormat { match &*format.to_lowercase() { - "html" => OutputFormat::HTML(HTMLFormatter(resource_suffix.to_owned())), + "html" => OutputFormat::HTML, "markdown" => OutputFormat::Markdown, s => OutputFormat::Unknown(s.to_owned()), } } } -struct HTMLFormatter(String); - -impl HTMLFormatter { - fn create_error_code_file( - &self, - err_code: &str, - explanation: &str, - parent_dir: &Path, - ) -> Result<(), Box> { - let mut output_file = File::create(parent_dir.join(err_code).with_extension("html"))?; - - self.header(&mut output_file, "../", "")?; - self.title(&mut output_file, &format!("Error code {}", err_code))?; - - let mut id_map = IdMap::new(); - let playground = - Playground { crate_name: None, url: String::from("https://play.rust-lang.org/") }; - write!( - output_file, - "{}", - Markdown { - content: explanation, - links: &[], - ids: &mut id_map, - error_codes: ErrorCodes::Yes, - edition: DEFAULT_EDITION, - playground: &Some(playground), - heading_offset: HeadingOffset::H1, - } - .into_string() - )?; - write!( - output_file, - "", - )?; - - self.footer(&mut output_file) - } - - fn header( - &self, - output: &mut dyn Write, - extra_path: &str, - extra: &str, - ) -> Result<(), Box> { - write!( - output, - r##" - - -Rust Compiler Error Index - - - - - -{extra} - - -"##, - suffix = self.0, - )?; - Ok(()) - } - - fn title(&self, output: &mut dyn Write, title: &str) -> Result<(), Box> { - write!(output, "

{}

\n", title)?; - Ok(()) - } - - fn footer(&self, output: &mut dyn Write) -> Result<(), Box> { - write!(output, "")?; - Ok(()) - } -} - /// Output an HTML page for the errors in `err_map` to `output_path`. fn render_markdown(output_path: &Path) -> Result<(), Box> { let mut output_file = File::create(output_path)?; @@ -147,61 +65,144 @@ fn render_markdown(output_path: &Path) -> Result<(), Box> { Ok(()) } -fn render_html(output_path: &Path, formatter: HTMLFormatter) -> Result<(), Box> { - let mut output_file = File::create(output_path)?; +fn move_folder(source: &Path, target: &Path) -> Result<(), Box> { + let entries = + fs::read_dir(source)?.map(|res| res.map(|e| e.path())).collect::, _>>()?; - let error_codes_dir = "error_codes"; - - let parent = output_path.parent().expect("There should have a parent").join(error_codes_dir); - - if !parent.exists() { - create_dir_all(&parent)?; - } - - formatter.header( - &mut output_file, - "", - &format!( - r#""# - ), - )?; - formatter.title(&mut output_file, "Rust Compiler Error Index")?; - - write!( - output_file, - "

This page lists all the error codes emitted by the Rust compiler. If you want a full \ - explanation on an error code, click on it.

\ -
    ", - )?; - for (err_code, explanation) in error_codes().iter() { - if let Some(explanation) = explanation { - write!( - output_file, - "
  • {1}
  • ", - error_codes_dir, err_code - )?; - formatter.create_error_code_file(err_code, explanation, &parent)?; + for entry in entries { + let file_name = entry.file_name().expect("file_name() failed").to_os_string(); + let output = target.join(file_name); + if entry.is_file() { + fs::rename(entry, output)?; } else { - write!(output_file, "
  • {}
  • ", err_code)?; + if !output.exists() { + create_dir_all(&output)?; + } + move_folder(&entry, &output)?; } } - write!(output_file, "
")?; - formatter.footer(&mut output_file) + + fs::remove_dir(&source)?; + + Ok(()) +} + +fn render_html(output_path: &Path) -> Result<(), Box> { + // We need to render into a temporary folder to prevent `mdbook` from removing everything + // in the output folder (including other completely unrelated things). + let tmp_output = output_path.join("tmp"); + + if !tmp_output.exists() { + create_dir_all(&tmp_output)?; + } + + render_html_inner(&tmp_output)?; + + move_folder(&tmp_output, output_path)?; + + Ok(()) +} + +// By default, mdbook doesn't consider code blocks as Rust ones contrary to rustdoc so we have +// to manually add `rust` attribute whenever needed. +fn add_rust_attribute_on_codeblock(explanation: &str) -> String { + // Very hacky way to add the rust attribute on all code blocks. + let mut skip = true; + explanation.split("\n```").fold(String::new(), |mut acc, part| { + if !acc.is_empty() { + acc.push_str("\n```"); + } + if !skip { + if let Some(attrs) = part.split('\n').next() { + if !attrs.contains("rust") + && (attrs.is_empty() + || attrs.contains("compile_fail") + || attrs.contains("ignore") + || attrs.contains("edition")) + { + if !attrs.is_empty() { + acc.push_str("rust,"); + } else { + acc.push_str("rust"); + } + } + } + } + skip = !skip; + acc.push_str(part); + acc + }) +} + +fn render_html_inner(output_path: &Path) -> Result<(), Box> { + // We need to have a little difference between `summary` and `introduction` because the "draft" + // chapters (the ones looking like `[a]()`) are not handled correctly when being put into a + // `Chapter` directly: they generate a link whereas they shouldn't. + let mut introduction = format!( + " +# Rust error codes index + +This page lists all the error codes emitted by the Rust compiler. + +", + include_str!("redirect.js") + ); + + let err_codes = error_codes(); + let mut chapters = Vec::with_capacity(err_codes.len()); + + for (err_code, explanation) in err_codes.iter() { + if let Some(explanation) = explanation { + introduction.push_str(&format!(" * [{0}](./error_codes/{0}.html)\n", err_code)); + + let content = add_rust_attribute_on_codeblock(explanation); + chapters.push(BookItem::Chapter(Chapter { + name: err_code.to_string(), + content: format!("# Error code {}\n\n{}\n", err_code, content), + number: None, + sub_items: Vec::new(), + // We generate it into the `error_codes` folder. + path: Some(PathBuf::from(&format!("error_codes/{}.html", err_code))), + source_path: None, + parent_names: Vec::new(), + })); + } else { + introduction.push_str(&format!(" * {}\n", err_code)); + } + } + + let mut config = Config::from_str(include_str!("book_config.toml"))?; + config.build.build_dir = output_path.to_path_buf(); + let mut book = MDBook::load_with_config_and_summary( + env!("CARGO_MANIFEST_DIR"), + config, + parse_summary("")?, + )?; + let chapter = Chapter { + name: "Rust error codes index".to_owned(), + content: introduction, + number: None, + sub_items: chapters, + // Very important: this file is named as `error-index.html` and not `index.html`! + path: Some(PathBuf::from("error-index.html")), + source_path: None, + parent_names: Vec::new(), + }; + book.book.sections.push(BookItem::Chapter(chapter)); + book.build()?; + + // We don't need this file since it's handled by doc.rust-lang.org directly. + let _ = fs::remove_file(output_path.join("404.html")); + // We don't want this file either because it would overwrite the already existing `index.html`. + let _ = fs::remove_file(output_path.join("index.html")); + + Ok(()) } fn main_with_result(format: OutputFormat, dst: &Path) -> Result<(), Box> { match format { OutputFormat::Unknown(s) => panic!("Unknown output format: {}", s), - OutputFormat::HTML(h) => render_html(dst, h), + OutputFormat::HTML => render_html(dst), OutputFormat::Markdown => render_markdown(dst), } } @@ -210,12 +211,9 @@ fn parse_args() -> (OutputFormat, PathBuf) { let mut args = env::args().skip(1); let format = args.next(); let dst = args.next(); - let resource_suffix = args.next().unwrap_or_else(String::new); - let format = format - .map(|a| OutputFormat::from(&a, &resource_suffix)) - .unwrap_or(OutputFormat::from("html", &resource_suffix)); + let format = format.map(|a| OutputFormat::from(&a)).unwrap_or(OutputFormat::from("html")); let dst = dst.map(PathBuf::from).unwrap_or_else(|| match format { - OutputFormat::HTML(..) => PathBuf::from("doc/error-index.html"), + OutputFormat::HTML => PathBuf::from("doc"), OutputFormat::Markdown => PathBuf::from("doc/error-index.md"), OutputFormat::Unknown(..) => PathBuf::from(""), }); @@ -225,9 +223,8 @@ fn parse_args() -> (OutputFormat, PathBuf) { fn main() { rustc_driver::init_env_logger("RUST_LOG"); let (format, dst) = parse_args(); - let result = - rustc_span::create_default_session_globals_then(move || main_with_result(format, &dst)); + let result = main_with_result(format, &dst); if let Err(e) = result { - panic!("{}", e.to_string()); + panic!("{:?}", e); } } diff --git a/src/tools/error_index_generator/redirect.js b/src/tools/error_index_generator/redirect.js new file mode 100644 index 000000000000..e6e910658e48 --- /dev/null +++ b/src/tools/error_index_generator/redirect.js @@ -0,0 +1,10 @@ +(function() {{ + if (window.location.hash) {{ + let code = window.location.hash.replace(/^#/, ''); + // We have to make sure this pattern matches to avoid inadvertently creating an + // open redirect. + if (/^E[0-9]+$/.test(code)) {{ + window.location = './error_codes/' + code + '.html'; + }} + }} +}})() From a928255ab1c6a594faa15f93d912c1179ae354ea Mon Sep 17 00:00:00 2001 From: Matt Hamrick Date: Wed, 31 Aug 2022 13:21:47 -0700 Subject: [PATCH 4018/5092] Fix bad target name in Walkthrough Walkthrough currently say: ``` rustup target add aarch_64-fuchsia ``` but should say ``` rustup target add aarch64-fuchsia ``` --- src/doc/rustc/src/platform-support/fuchsia.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md index c2a1613f288c..94373b01cc46 100644 --- a/src/doc/rustc/src/platform-support/fuchsia.md +++ b/src/doc/rustc/src/platform-support/fuchsia.md @@ -79,7 +79,7 @@ the following commands: ```sh rustup target add x86_64-fuchsia -rustup target add aarch_64-fuchsia +rustup target add aarch64-fuchsia ``` After installing our Fuchsia targets, we can now compile a Rust binary that targets From 45fac3472b58682c5d2853ce674b15579e940f55 Mon Sep 17 00:00:00 2001 From: klensy Date: Wed, 31 Aug 2022 23:04:12 +0300 Subject: [PATCH 4019/5092] update few crates to drop old deps --- Cargo.lock | 156 +++++----------------- src/tools/rustc-workspace-hack/Cargo.toml | 3 - src/tools/tidy/src/deps.rs | 5 - 3 files changed, 33 insertions(+), 131 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 002d73be7d1d..2c88d7ab7aa5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -209,34 +209,13 @@ dependencies = [ "typenum", ] -[[package]] -name = "block-buffer" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -dependencies = [ - "block-padding", - "byte-tools", - "byteorder", - "generic-array 0.12.4", -] - [[package]] name = "block-buffer" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" dependencies = [ - "generic-array 0.14.4", -] - -[[package]] -name = "block-padding" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" -dependencies = [ - "byte-tools", + "generic-array", ] [[package]] @@ -277,12 +256,6 @@ dependencies = [ "toml", ] -[[package]] -name = "byte-tools" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" - [[package]] name = "bytecount" version = "0.6.2" @@ -292,12 +265,6 @@ dependencies = [ "packed_simd_2", ] -[[package]] -name = "byteorder" -version = "1.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" - [[package]] name = "bytes" version = "1.0.1" @@ -770,9 +737,9 @@ dependencies = [ [[package]] name = "combine" -version = "4.6.3" +version = "4.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50b727aacc797f9fc28e355d21f34709ac4fc9adecfe470ad07b8f4464f53062" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" dependencies = [ "bytes", "memchr", @@ -1010,7 +977,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4600d695eb3f6ce1cd44e6e291adceb2cc3ab12f20a33777ecd0bf6eba34e06" dependencies = [ - "generic-array 0.14.4", + "generic-array", ] [[package]] @@ -1105,22 +1072,13 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" -[[package]] -name = "digest" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -dependencies = [ - "generic-array 0.12.4", -] - [[package]] name = "digest" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cb780dce4f9a8f5c087362b3a4595936b2019e7c8b30f2c3e9a7e94e6ae9837" dependencies = [ - "block-buffer 0.10.2", + "block-buffer", "crypto-common", ] @@ -1299,12 +1257,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" - [[package]] name = "fallible-iterator" version = "0.2.0" @@ -1538,15 +1490,6 @@ dependencies = [ "termcolor", ] -[[package]] -name = "generic-array" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" -dependencies = [ - "typenum", -] - [[package]] name = "generic-array" version = "0.14.4" @@ -1681,16 +1624,16 @@ dependencies = [ [[package]] name = "handlebars" -version = "4.1.0" +version = "4.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72a0ffab8c36d0436114310c7e10b59b3307e650ddfabf6d006028e29a70c6e6" +checksum = "360d9740069b2f6cbb63ce2dbaa71a20d3185350cbb990d7bebeb9318415eb17" dependencies = [ "log", "pest", "pest_derive", - "quick-error 2.0.0", "serde", "serde_json", + "thiserror", ] [[package]] @@ -1780,7 +1723,7 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" dependencies = [ - "quick-error 1.2.3", + "quick-error", ] [[package]] @@ -1826,13 +1769,13 @@ dependencies = [ [[package]] name = "im-rc" -version = "15.0.0" +version = "15.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ca8957e71f04a205cb162508f9326aea04676c8dfd0711220190d6b83664f3f" +checksum = "af1955a75fa080c677d3972822ec4bad316169ab1cfc6c257a942c2265dbe5fe" dependencies = [ "bitmaps", - "rand_core 0.5.1", - "rand_xoshiro 0.4.0", + "rand_core 0.6.2", + "rand_xoshiro", "sized-chunks", "typenum", "version_check", @@ -2169,7 +2112,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6a38fc55c8bbc10058782919516f88826e70320db6d206aebc49611d24216ae" dependencies = [ - "digest 0.10.2", + "digest", ] [[package]] @@ -2395,12 +2338,6 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" -[[package]] -name = "opaque-debug" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" - [[package]] name = "opener" version = "0.5.0" @@ -2590,18 +2527,19 @@ dependencies = [ [[package]] name = "pest" -version = "2.1.3" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +checksum = "4b0560d531d1febc25a3c9398a62a71256c0178f2e3443baedd9ad4bb8c9deb4" dependencies = [ + "thiserror", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" +checksum = "905708f7f674518498c1f8d644481440f476d39ca6ecae83319bba7c6c12da91" dependencies = [ "pest", "pest_generator", @@ -2609,9 +2547,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.1.3" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" +checksum = "5803d8284a629cc999094ecd630f55e91b561a1d1ba75e233b00ae13b91a69ad" dependencies = [ "pest", "pest_meta", @@ -2622,13 +2560,13 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.1.3" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" +checksum = "1538eb784f07615c6d9a8ab061089c6c54a344c5b4301db51990ca1c241e8c04" dependencies = [ - "maplit", + "once_cell", "pest", - "sha-1 0.8.2", + "sha-1", ] [[package]] @@ -2830,12 +2768,6 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" -[[package]] -name = "quick-error" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ac73b1112776fc109b2e61909bc46c7e1bf0d7f690ffb1676553acce16d5cda" - [[package]] name = "quine-mc_cluskey" version = "0.2.4" @@ -2931,15 +2863,6 @@ dependencies = [ "rand_core 0.5.1", ] -[[package]] -name = "rand_xoshiro" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9fcdd2e881d02f1d9390ae47ad8e5696a9e4be7b547a1da2afbc61973217004" -dependencies = [ - "rand_core 0.5.1", -] - [[package]] name = "rand_xoshiro" version = "0.6.0" @@ -3172,7 +3095,6 @@ dependencies = [ "bstr", "clap", "libz-sys", - "memchr", "regex", "serde_json", "syn", @@ -3807,7 +3729,7 @@ dependencies = [ "gsgdt", "polonius-engine", "rand 0.8.5", - "rand_xoshiro 0.6.0", + "rand_xoshiro", "rustc-rayon", "rustc-rayon-core", "rustc_apfloat", @@ -4142,7 +4064,7 @@ dependencies = [ "rustc_macros", "rustc_serialize", "scoped-tls", - "sha-1 0.10.0", + "sha-1", "sha2", "tracing", "unicode-width", @@ -4529,18 +4451,6 @@ dependencies = [ "serde", ] -[[package]] -name = "sha-1" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" -dependencies = [ - "block-buffer 0.7.3", - "digest 0.8.1", - "fake-simd", - "opaque-debug", -] - [[package]] name = "sha-1" version = "0.10.0" @@ -4549,7 +4459,7 @@ checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.2", + "digest", ] [[package]] @@ -4560,7 +4470,7 @@ checksum = "99c3bd8169c58782adad9290a9af5939994036b76187f7b4f0e6de91dbbfc0ec" dependencies = [ "cfg-if 1.0.0", "cpufeatures", - "digest 0.10.2", + "digest", ] [[package]] @@ -4885,18 +4795,18 @@ checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" [[package]] name = "thiserror" -version = "1.0.30" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "3d0a539a918745651435ac7db7a18761589a94cd7e94cd56999f828bf73c8a57" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.30" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "c251e90f708e16c49a16f4917dc2131e75222b72edfa9cb7f7c58ae56aae0c09" dependencies = [ "proc-macro2", "quote", diff --git a/src/tools/rustc-workspace-hack/Cargo.toml b/src/tools/rustc-workspace-hack/Cargo.toml index 3c982b261271..80bb3b5d6a8d 100644 --- a/src/tools/rustc-workspace-hack/Cargo.toml +++ b/src/tools/rustc-workspace-hack/Cargo.toml @@ -77,9 +77,6 @@ clap = { version = "3.1.1", features = ["derive", "clap_derive"]} curl-sys = { version = "0.4.13", features = ["http2", "libnghttp2-sys"], optional = true } # Ensure default features of libz-sys, which are disabled in some scenarios. libz-sys = { version = "1.1.2" } -# The only user of memchr's deprecated `use_std` feature is `combine`, so this can be -# removed if/when https://github.com/Marwes/combine/pull/348 is merged and released. -memchr = { version = "2.5", features = ["std", "use_std"] } # Ensure default features of regex, which are disabled in some scenarios. regex = { version = "1.5.6" } serde_json = { version = "1.0.31", features = ["raw_value", "unbounded_depth"] } diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 2fe17e979c87..6fa73ca9ec6c 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -91,9 +91,6 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "autocfg", "bitflags", "block-buffer", - "block-padding", - "byte-tools", - "byteorder", "cc", "cfg-if", "chalk-derive", @@ -118,7 +115,6 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "ena", "env_logger", "expect-test", - "fake-simd", "fallible-iterator", // dependency of `thorin` "filetime", "fixedbitset", @@ -162,7 +158,6 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "object", "odht", "once_cell", - "opaque-debug", "parking_lot", "parking_lot_core", "pathdiff", From 037a911bd8f223a15a500c172e1b8d030c9a05f3 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 31 Aug 2022 10:06:48 -0700 Subject: [PATCH 4020/5092] rustdoc: remove unused `.docblock .impl-items` CSS The impl-items list stopped being nested inside a docblock since c1b1d6804bfce1aee3a95b3cbff3eaeb15bad9a4 --- src/librustdoc/html/static/css/rustdoc.css | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index c117e3ac40da..00d230087728 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -759,14 +759,6 @@ pre, .rustdoc.source .example-wrap { margin-bottom: 15px; } -.content .docblock > .impl-items { - margin-left: 20px; - margin-top: -34px; -} -.content .docblock >.impl-items table td { - padding: 0; -} - .item-info { display: block; } From d786a40e73f2b2f7ab4f77e9fb880b5d06ca1cdb Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Wed, 31 Aug 2022 23:19:09 +0000 Subject: [PATCH 4021/5092] Parse TypePathFn with preceding `::` e.g. `impl Fn::() -> ()`. --- crates/parser/src/grammar/paths.rs | 5 +++ .../ok/0202_typepathfn_with_coloncolon.rast | 43 +++++++++++++++++++ .../ok/0202_typepathfn_with_coloncolon.rs | 1 + 3 files changed, 49 insertions(+) create mode 100644 crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rast create mode 100644 crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs diff --git a/crates/parser/src/grammar/paths.rs b/crates/parser/src/grammar/paths.rs index 8de5d33a1936..5dc9c6c82a14 100644 --- a/crates/parser/src/grammar/paths.rs +++ b/crates/parser/src/grammar/paths.rs @@ -118,6 +118,11 @@ fn opt_path_type_args(p: &mut Parser<'_>, mode: Mode) { match mode { Mode::Use => {} Mode::Type => { + // test typepathfn_with_coloncolon + // type F = Start::(Middle) -> (Middle)::End; + if p.at(T![::]) && p.nth_at(2, T!['(']) { + p.bump(T![::]); + } // test path_fn_trait_args // type F = Box ()>; if p.at(T!['(']) { diff --git a/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rast b/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rast new file mode 100644 index 000000000000..b47a5a5c1470 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rast @@ -0,0 +1,43 @@ +SOURCE_FILE + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "F" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "Start" + COLON2 "::" + PARAM_LIST + L_PAREN "(" + PARAM + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Middle" + R_PAREN ")" + WHITESPACE " " + RET_TYPE + THIN_ARROW "->" + WHITESPACE " " + PAREN_TYPE + L_PAREN "(" + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Middle" + R_PAREN ")" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "End" + SEMICOLON ";" + WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs b/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs new file mode 100644 index 000000000000..8efd93a7ff68 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs @@ -0,0 +1 @@ +type F = Start::(Middle) -> (Middle)::End; From 2eec4ed69d46ec74a9ee29033e9431edd342e048 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Thu, 1 Sep 2022 00:11:32 +0000 Subject: [PATCH 4022/5092] Lower float literals with underscores --- crates/syntax/src/ast/token_ext.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/crates/syntax/src/ast/token_ext.rs b/crates/syntax/src/ast/token_ext.rs index 28976d837b88..ba72e64425b2 100644 --- a/crates/syntax/src/ast/token_ext.rs +++ b/crates/syntax/src/ast/token_ext.rs @@ -322,7 +322,7 @@ impl ast::IntNumber { pub fn float_value(&self) -> Option { let (_, text, _) = self.split_into_parts(); - text.parse::().ok() + text.replace('_', "").parse::().ok() } } @@ -361,7 +361,7 @@ impl ast::FloatNumber { pub fn value(&self) -> Option { let (text, _) = self.split_into_parts(); - text.parse::().ok() + text.replace('_', "").parse::().ok() } } @@ -397,6 +397,15 @@ mod tests { assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.suffix(), expected.into()); } + fn check_float_value(lit: &str, expected: impl Into> + Copy) { + assert_eq!(FloatNumber { syntax: make::tokens::literal(lit) }.value(), expected.into()); + assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.float_value(), expected.into()); + } + + fn check_int_value(lit: &str, expected: impl Into>) { + assert_eq!(IntNumber { syntax: make::tokens::literal(lit) }.value(), expected.into()); + } + #[test] fn test_float_number_suffix() { check_float_suffix("123.0", None); @@ -437,6 +446,14 @@ mod tests { check_string_value(r"\nfoobar", "\nfoobar"); check_string_value(r"C:\\Windows\\System32\\", "C:\\Windows\\System32\\"); } + + #[test] + fn test_value_underscores() { + check_float_value("3.141592653589793_f64", 3.141592653589793_f64); + check_float_value("1__0.__0__f32", 10.0); + check_int_value("0b__1_0_", 2); + check_int_value("1_1_1_1_1_1", 111111); + } } impl ast::Char { From d8b572b820e2c1b59a26d28fc2c6234e34aedc6d Mon Sep 17 00:00:00 2001 From: Andrew Pollack Date: Wed, 31 Aug 2022 23:49:48 +0000 Subject: [PATCH 4023/5092] Tweaks to fuchsia doc walkthrough --- src/doc/rustc/src/platform-support/fuchsia.md | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md index c2a1613f288c..10d12f88454d 100644 --- a/src/doc/rustc/src/platform-support/fuchsia.md +++ b/src/doc/rustc/src/platform-support/fuchsia.md @@ -125,13 +125,20 @@ during compilation: [target.x86_64-fuchsia] rustflags = [ - "-Lnative", "/arch/x64/sysroot/lib", - "-Lnative", "/arch/x64/lib" + "-Lnative=/arch/x64/lib", + "-Lnative=/arch/x64/sysroot/lib" ] ``` *Note: Make sure to fill out `` with the path to the downloaded [Fuchsia SDK].* +These options configure the following: + +* `-Lnative=${SDK_PATH}/arch/${ARCH}/lib`: Link against Fuchsia libraries from + the SDK +* `-Lnative=${SDK_PATH}/arch/${ARCH}/sysroot/lib`: Link against Fuchsia kernel + libraries from the SDK + In total, our new project will look like: **Current directory structure** @@ -368,6 +375,7 @@ language called CML. The Fuchsia devsite contains an [overview of CML] and a } ``` +**Current directory structure** ```txt hello_fuchsia/ ┗━ pkg/ @@ -386,6 +394,9 @@ ${SDK_PATH}/tools/${ARCH}/cmc compile \ -o pkg/meta/hello_fuchsia.cm ``` +*Note: `--includepath` tells the compiler where to look for `include`s from our CML. +In our case, we're only using `syslog/client.shard.cml`.* + **Current directory structure** ```txt hello_fuchsia/ @@ -397,19 +408,16 @@ hello_fuchsia/ ┗━ hello_fuchsia.cml ``` -*Note: `--includepath` tells the compiler where to look for `include`s from our CML. -In our case, we're only using `syslog/client.shard.cml`.* - ### Building a Fuchsia package Next, we'll build a package manifest as defined by our manifest: ```sh ${SDK_PATH}/tools/${ARCH}/pm \ - -o hello_fuchsia_manifest \ + -o pkg/hello_fuchsia_manifest \ -m pkg/hello_fuchsia.manifest \ build \ - -output-package-manifest hello_fuchsia_package_manifest + -output-package-manifest pkg/hello_fuchsia_package_manifest ``` This will produce `pkg/hello_fuchsia_manifest/` which is a package manifest we can @@ -469,15 +477,15 @@ We can publish our new package to that repository with: ```sh ${SDK_PATH}/tools/${ARCH}/pm publish \ - -repo repo \ - -lp -f <(echo "hello_fuchsia_package_manifest") + -repo pkg/repo \ + -lp -f <(echo "pkg/hello_fuchsia_package_manifest") ``` Then we can add the repository to `ffx`'s package server as `hello-fuchsia` using: ```sh ${SDK_PATH}/tools/${ARCH}/ffx repository add-from-pm \ - repo \ + pkg/repo \ -r hello-fuchsia ``` From 3cfb9915fcf97ac3f312d2277193d2c2cf934057 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Wed, 31 Aug 2022 08:45:26 -0400 Subject: [PATCH 4024/5092] Add a protector test that demonstrates the base tag diagnostic --- src/stacked_borrows/diagnostics.rs | 2 +- .../invalidate_against_protector3.rs | 15 ++++++++++ .../invalidate_against_protector3.stderr | 30 +++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 tests/fail/stacked_borrows/invalidate_against_protector3.rs create mode 100644 tests/fail/stacked_borrows/invalidate_against_protector3.stderr diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index b8e777717e97..461715cedd8f 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -332,7 +332,7 @@ impl<'span, 'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'span, 'history, 'ecx, 'mir // this allocation. if self.history.base.0.tag() == tag { Some(( - format!("{:?} was created here, as a base tag for {:?}", tag, self.history.id), + format!("{:?} was created here, as the base tag for {:?}", tag, self.history.id), self.history.base.1.data() )) } else { diff --git a/tests/fail/stacked_borrows/invalidate_against_protector3.rs b/tests/fail/stacked_borrows/invalidate_against_protector3.rs new file mode 100644 index 000000000000..634eb97217c6 --- /dev/null +++ b/tests/fail/stacked_borrows/invalidate_against_protector3.rs @@ -0,0 +1,15 @@ +use std::alloc::{alloc, Layout}; + +fn inner(x: *mut i32, _y: &i32) { + // If `x` and `y` alias, retagging is fine with this... but we really + // shouldn't be allowed to write to `x` at all because `y` was assumed to be + // immutable for the duration of this call. + unsafe { *x = 0 }; //~ ERROR: protect +} + +fn main() { + unsafe { + let ptr = alloc(Layout::for_value(&0i32)) as *mut i32; + inner(ptr, &*ptr); + }; +} diff --git a/tests/fail/stacked_borrows/invalidate_against_protector3.stderr b/tests/fail/stacked_borrows/invalidate_against_protector3.stderr new file mode 100644 index 000000000000..afda15ea160e --- /dev/null +++ b/tests/fail/stacked_borrows/invalidate_against_protector3.stderr @@ -0,0 +1,30 @@ +error: Undefined Behavior: not granting access to tag because that would remove [SharedReadOnly for ] which is protected because it is an argument of call ID + --> $DIR/invalidate_against_protector3.rs:LL:CC + | +LL | unsafe { *x = 0 }; + | ^^^^^^ not granting access to tag because that would remove [SharedReadOnly for ] which is protected because it is an argument of call ID + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created here, as the base tag for ALLOC + --> $DIR/invalidate_against_protector3.rs:LL:CC + | +LL | let ptr = alloc(Layout::for_value(&0i32)) as *mut i32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: is this argument + --> $DIR/invalidate_against_protector3.rs:LL:CC + | +LL | fn inner(x: *mut i32, _y: &i32) { + | ^^ + = note: BACKTRACE: + = note: inside `inner` at $DIR/invalidate_against_protector3.rs:LL:CC +note: inside `main` at $DIR/invalidate_against_protector3.rs:LL:CC + --> $DIR/invalidate_against_protector3.rs:LL:CC + | +LL | inner(ptr, &*ptr); + | ^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + From 630f831cd06d24732c9a422b8d3d3e2ce9e1a879 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Thu, 1 Sep 2022 04:17:36 +0100 Subject: [PATCH 4025/5092] Use `FILE_ATTRIBUTE_TAG_INFO` to get reparse tag This avoid unnecessarily getting the full reparse data when all we need is the tag. --- library/std/src/sys/windows/c.rs | 6 ++++++ library/std/src/sys/windows/fs.rs | 26 ++++++++++++++++++-------- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index c99c8efe4367..b4db77700aab 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -454,6 +454,12 @@ pub enum FILE_INFO_BY_HANDLE_CLASS { MaximumFileInfoByHandlesClass, } +#[repr(C)] +pub struct FILE_ATTRIBUTE_TAG_INFO { + pub FileAttributes: DWORD, + pub ReparseTag: DWORD, +} + #[repr(C)] pub struct FILE_DISPOSITION_INFO { pub DeleteFile: BOOLEAN, diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index 98c8834d3840..c2ad592dfea7 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -326,10 +326,15 @@ impl File { cvt(c::GetFileInformationByHandle(self.handle.as_raw_handle(), &mut info))?; let mut reparse_tag = 0; if info.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { - let mut b = - Align8([MaybeUninit::::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]); - if let Ok((_, buf)) = self.reparse_point(&mut b) { - reparse_tag = (*buf).ReparseTag; + let mut attr_tag: c::FILE_ATTRIBUTE_TAG_INFO = mem::zeroed(); + cvt(c::GetFileInformationByHandleEx( + self.handle.as_raw_handle(), + c::FileAttributeTagInfo, + ptr::addr_of_mut!(attr_tag).cast(), + mem::size_of::().try_into().unwrap(), + ))?; + if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { + reparse_tag = attr_tag.ReparseTag; } } Ok(FileAttr { @@ -390,10 +395,15 @@ impl File { attr.file_size = info.AllocationSize as u64; attr.number_of_links = Some(info.NumberOfLinks); if attr.file_type().is_reparse_point() { - let mut b = - Align8([MaybeUninit::::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]); - if let Ok((_, buf)) = self.reparse_point(&mut b) { - attr.reparse_tag = (*buf).ReparseTag; + let mut attr_tag: c::FILE_ATTRIBUTE_TAG_INFO = mem::zeroed(); + cvt(c::GetFileInformationByHandleEx( + self.handle.as_raw_handle(), + c::FileAttributeTagInfo, + ptr::addr_of_mut!(attr_tag).cast(), + mem::size_of::().try_into().unwrap(), + ))?; + if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { + reparse_tag = attr_tag.ReparseTag; } } Ok(attr) From d4a0785464f567c8781f15819f8be74a95b0a3f0 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 31 Aug 2022 23:24:29 -0400 Subject: [PATCH 4026/5092] Correctly handle unescape warnings --- clippy_dev/src/update_lints.rs | 6 +++++- clippy_lints/src/write.rs | 6 +++++- clippy_utils/src/macros.rs | 6 ++++-- tests/ui/crashes/ice-9405.rs | 11 +++++++++++ tests/ui/crashes/ice-9405.stderr | 11 +++++++++++ 5 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 tests/ui/crashes/ice-9405.rs create mode 100644 tests/ui/crashes/ice-9405.stderr diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index c503142e5e45..28bec872c08a 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -977,7 +977,11 @@ fn remove_line_splices(s: &str) -> String { .and_then(|s| s.strip_suffix('"')) .unwrap_or_else(|| panic!("expected quoted string, found `{}`", s)); let mut res = String::with_capacity(s.len()); - unescape::unescape_literal(s, unescape::Mode::Str, &mut |range, _| res.push_str(&s[range])); + unescape::unescape_literal(s, unescape::Mode::Str, &mut |range, ch| { + if ch.is_ok() { + res.push_str(&s[range]); + } + }); res } diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 5533840b166f..abd681c53076 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -805,7 +805,11 @@ fn check_newlines(fmtstr: &StrLit) -> bool { let contents = fmtstr.symbol.as_str(); let mut cb = |r: Range, c: Result| { - let c = c.unwrap(); + let c = match c { + Ok(c) => c, + Err(e) if !e.is_fatal() => return, + Err(e) => panic!("{:?}", e), + }; if r.end == contents.len() && c == '\n' && !last_was_cr && !has_internal_newline { should_lint = true; diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index e5ca35455404..6b7d5e9aea80 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -389,8 +389,10 @@ impl FormatString { }; let mut unescaped = String::with_capacity(inner.len()); - unescape_literal(inner, mode, &mut |_, ch| { - unescaped.push(ch.unwrap()); + unescape_literal(inner, mode, &mut |_, ch| match ch { + Ok(ch) => unescaped.push(ch), + Err(e) if !e.is_fatal() => (), + Err(e) => panic!("{:?}", e), }); let mut parts = Vec::new(); diff --git a/tests/ui/crashes/ice-9405.rs b/tests/ui/crashes/ice-9405.rs new file mode 100644 index 000000000000..e2d274aeb044 --- /dev/null +++ b/tests/ui/crashes/ice-9405.rs @@ -0,0 +1,11 @@ +#![warn(clippy::useless_format)] +#![allow(clippy::print_literal)] + +fn main() { + println!( + "\ + + {}", + "multiple skipped lines" + ); +} diff --git a/tests/ui/crashes/ice-9405.stderr b/tests/ui/crashes/ice-9405.stderr new file mode 100644 index 000000000000..9a6e410f21ea --- /dev/null +++ b/tests/ui/crashes/ice-9405.stderr @@ -0,0 +1,11 @@ +warning: multiple lines skipped by escaped newline + --> $DIR/ice-9405.rs:6:10 + | +LL | "/ + | __________^ +LL | | +LL | | {}", + | |____________^ skipping everything up to and including this point + +warning: 1 warning emitted + From 3810d4a3680d825448f5034262cc6ad63586b02e Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Thu, 1 Sep 2022 06:43:03 +0200 Subject: [PATCH 4027/5092] unix_sigpipe: Make `sigpipe` param docs long-form --- library/std/src/rt.rs | 21 +++++++++++++++++++-- library/std/src/sys/unix/mod.rs | 3 +-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index b3f6f82952b7..98f6cc7aa3ea 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -72,8 +72,25 @@ macro_rules! rtunwrap { // Runs before `main`. // SAFETY: must be called only once during runtime initialization. // NOTE: this is not guaranteed to run, for example when Rust code is called externally. -// The extra parameter `sigpipe` allows rustc to generate code that instructs std whether -// or not to ignore `SIGPIPE`. +// +// # The `sigpipe` parameter +// +// Since 2014, the Rust runtime on Unix has set the `SIGPIPE` handler to +// `SIG_IGN`. Applications have good reasons to want a different behavior +// though, so there is a `#[unix_sigpipe = "..."]` attribute on `fn main()` that +// can be used to select how `SIGPIPE` shall be setup (if changed at all) before +// `fn main()` is called. See +// for more info. +// +// The `sigpipe` parameter to this function gets its value via the code that +// rustc generates to invoke `fn lang_start()`. The reason we have `sigpipe` for +// all platforms and not only Unix, is because std is not allowed to have `cfg` +// directives as this high level. See the module docs in +// `src/tools/tidy/src/pal.rs` for more info. On all other platforms, `sigpipe` +// has a value, but its value is ignored. +// +// Even though it is an `u8`, it only ever has 3 values. These are documented in +// `compiler/rustc_session/src/config/sigpipe.rs`. #[cfg_attr(test, allow(dead_code))] unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { unsafe { diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index 2856dfcb3707..c84e292eac15 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -49,8 +49,7 @@ pub fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {} #[cfg(not(target_os = "espidf"))] // SAFETY: must be called only once during runtime initialization. // NOTE: this is not guaranteed to run, for example when Rust code is called externally. -// The extra parameter `sigpipe` allows rustc to generate code that instructs std whether -// or not to ignore `SIGPIPE`. +// See `fn init()` in `library/std/src/rt.rs` for docs on `sigpipe`. pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { // The standard streams might be closed on application startup. To prevent // std::io::{stdin, stdout,stderr} objects from using other unrelated file From a20318d94ba68151a97d585b870915d3e2f9da58 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 1 Sep 2022 11:20:08 +0200 Subject: [PATCH 4028/5092] Update outdated comment about output capturing in print_to. --- library/std/src/io/stdio.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 4d3736f79146..07239746258d 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -986,10 +986,10 @@ pub fn set_output_capture(sink: Option) -> Option { /// otherwise. `label` identifies the stream in a panic message. /// /// This function is used to print error messages, so it takes extra -/// care to avoid causing a panic when `local_s` is unusable. -/// For instance, if the TLS key for the local stream is -/// already destroyed, or if the local stream is locked by another -/// thread, it will just fall back to the global stream. +/// care to avoid causing a panic when `OUTPUT_CAPTURE` is unusable. +/// For instance, if the TLS key for output capturing is already destroyed, or +/// if the local stream is in use by another thread, it will just fall back to +/// the global stream. /// /// However, if the actual I/O causes an error, this function does panic. fn print_to(args: fmt::Arguments<'_>, global_s: fn() -> T, label: &str) From 098725c2e2b943b5b84c4a3a0a9f49e900a51954 Mon Sep 17 00:00:00 2001 From: Quinn Painter Date: Thu, 1 Sep 2022 10:23:15 +0100 Subject: [PATCH 4029/5092] Fix filename of armv4t-none-eabi.md The filename differed from the link in SUMMARY.md, causing it to 404. --- .../platform-support/{armv4t_none_eabi.md => armv4t-none-eabi.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/doc/rustc/src/platform-support/{armv4t_none_eabi.md => armv4t-none-eabi.md} (100%) diff --git a/src/doc/rustc/src/platform-support/armv4t_none_eabi.md b/src/doc/rustc/src/platform-support/armv4t-none-eabi.md similarity index 100% rename from src/doc/rustc/src/platform-support/armv4t_none_eabi.md rename to src/doc/rustc/src/platform-support/armv4t-none-eabi.md From f0d642ea38877a9b68c05c48ed3cd14192ae1bb9 Mon Sep 17 00:00:00 2001 From: dswij Date: Thu, 1 Sep 2022 00:47:56 +0800 Subject: [PATCH 4030/5092] Use macro source when creating `Sugg` helper --- clippy_utils/src/sugg.rs | 46 ++++++++++++++++++---------------- tests/ui/collapsible_if.fixed | 3 +++ tests/ui/collapsible_if.rs | 5 ++++ tests/ui/collapsible_if.stderr | 10 +++++++- 4 files changed, 42 insertions(+), 22 deletions(-) diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index 081c98e2f3ce..b4619860a6d9 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -22,7 +22,7 @@ use std::fmt::{Display, Write as _}; use std::ops::{Add, Neg, Not, Sub}; /// A helper type to build suggestion correctly handling parentheses. -#[derive(Clone, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub enum Sugg<'a> { /// An expression that never needs parentheses such as `1337` or `[0; 42]`. NonParen(Cow<'a, str>), @@ -177,11 +177,11 @@ impl<'a> Sugg<'a> { pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self { use rustc_ast::ast::RangeLimits; - let get_whole_snippet = || { - if expr.span.from_expansion() { - snippet_with_macro_callsite(cx, expr.span, default) + let snippet_without_expansion = |cx, span: Span, default| { + if span.from_expansion() { + snippet_with_macro_callsite(cx, span, default) } else { - snippet(cx, expr.span, default) + snippet(cx, span, default) } }; @@ -192,7 +192,7 @@ impl<'a> Sugg<'a> { | ast::ExprKind::If(..) | ast::ExprKind::Let(..) | ast::ExprKind::Unary(..) - | ast::ExprKind::Match(..) => Sugg::MaybeParen(get_whole_snippet()), + | ast::ExprKind::Match(..) => Sugg::MaybeParen(snippet_without_expansion(cx, expr.span, default)), ast::ExprKind::Async(..) | ast::ExprKind::Block(..) | ast::ExprKind::Break(..) @@ -221,41 +221,45 @@ impl<'a> Sugg<'a> { | ast::ExprKind::Array(..) | ast::ExprKind::While(..) | ast::ExprKind::Await(..) - | ast::ExprKind::Err => Sugg::NonParen(get_whole_snippet()), + | ast::ExprKind::Err => Sugg::NonParen(snippet_without_expansion(cx, expr.span, default)), ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::HalfOpen) => Sugg::BinOp( AssocOp::DotDot, - lhs.as_ref().map_or("".into(), |lhs| snippet(cx, lhs.span, default)), - rhs.as_ref().map_or("".into(), |rhs| snippet(cx, rhs.span, default)), + lhs.as_ref() + .map_or("".into(), |lhs| snippet_without_expansion(cx, lhs.span, default)), + rhs.as_ref() + .map_or("".into(), |rhs| snippet_without_expansion(cx, rhs.span, default)), ), ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::Closed) => Sugg::BinOp( AssocOp::DotDotEq, - lhs.as_ref().map_or("".into(), |lhs| snippet(cx, lhs.span, default)), - rhs.as_ref().map_or("".into(), |rhs| snippet(cx, rhs.span, default)), + lhs.as_ref() + .map_or("".into(), |lhs| snippet_without_expansion(cx, lhs.span, default)), + rhs.as_ref() + .map_or("".into(), |rhs| snippet_without_expansion(cx, rhs.span, default)), ), ast::ExprKind::Assign(ref lhs, ref rhs, _) => Sugg::BinOp( AssocOp::Assign, - snippet(cx, lhs.span, default), - snippet(cx, rhs.span, default), + snippet_without_expansion(cx, lhs.span, default), + snippet_without_expansion(cx, rhs.span, default), ), ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => Sugg::BinOp( astbinop2assignop(op), - snippet(cx, lhs.span, default), - snippet(cx, rhs.span, default), + snippet_without_expansion(cx, lhs.span, default), + snippet_without_expansion(cx, rhs.span, default), ), ast::ExprKind::Binary(op, ref lhs, ref rhs) => Sugg::BinOp( AssocOp::from_ast_binop(op.node), - snippet(cx, lhs.span, default), - snippet(cx, rhs.span, default), + snippet_without_expansion(cx, lhs.span, default), + snippet_without_expansion(cx, rhs.span, default), ), ast::ExprKind::Cast(ref lhs, ref ty) => Sugg::BinOp( AssocOp::As, - snippet(cx, lhs.span, default), - snippet(cx, ty.span, default), + snippet_without_expansion(cx, lhs.span, default), + snippet_without_expansion(cx, ty.span, default), ), ast::ExprKind::Type(ref lhs, ref ty) => Sugg::BinOp( AssocOp::Colon, - snippet(cx, lhs.span, default), - snippet(cx, ty.span, default), + snippet_without_expansion(cx, lhs.span, default), + snippet_without_expansion(cx, ty.span, default), ), } } diff --git a/tests/ui/collapsible_if.fixed b/tests/ui/collapsible_if.fixed index 5b0e4a473c4a..6bb7682bae95 100644 --- a/tests/ui/collapsible_if.fixed +++ b/tests/ui/collapsible_if.fixed @@ -139,6 +139,9 @@ fn main() { // Fix #5962 if matches!(true, true) && matches!(true, true) {} + // Issue #9375 + if matches!(true, true) && truth() && matches!(true, true) {} + if true { #[cfg(not(teehee))] if true { diff --git a/tests/ui/collapsible_if.rs b/tests/ui/collapsible_if.rs index cd231a5d7abb..e216a9ee54c9 100644 --- a/tests/ui/collapsible_if.rs +++ b/tests/ui/collapsible_if.rs @@ -155,6 +155,11 @@ fn main() { if matches!(true, true) {} } + // Issue #9375 + if matches!(true, true) && truth() { + if matches!(true, true) {} + } + if true { #[cfg(not(teehee))] if true { diff --git a/tests/ui/collapsible_if.stderr b/tests/ui/collapsible_if.stderr index 6749612388fe..6327444df21d 100644 --- a/tests/ui/collapsible_if.stderr +++ b/tests/ui/collapsible_if.stderr @@ -126,5 +126,13 @@ LL | | if matches!(true, true) {} LL | | } | |_____^ help: collapse nested if block: `if matches!(true, true) && matches!(true, true) {}` -error: aborting due to 8 previous errors +error: this `if` statement can be collapsed + --> $DIR/collapsible_if.rs:159:5 + | +LL | / if matches!(true, true) && truth() { +LL | | if matches!(true, true) {} +LL | | } + | |_____^ help: collapse nested if block: `if matches!(true, true) && truth() && matches!(true, true) {}` + +error: aborting due to 9 previous errors From 6e14e60af45ebc79f06eeeb75004e77de4658a80 Mon Sep 17 00:00:00 2001 From: Lukas Lueg Date: Wed, 31 Aug 2022 21:08:33 +0200 Subject: [PATCH 4031/5092] Fix {subopt,imprec}_float not lint const.*(const) Fixes #9402 Fixes #9201 --- clippy_lints/src/floating_point_arithmetic.rs | 30 +++++------ tests/ui/floating_point_powf.fixed | 5 ++ tests/ui/floating_point_powf.rs | 5 ++ tests/ui/floating_point_powf.stderr | 50 ++++++++++++++----- 4 files changed, 62 insertions(+), 28 deletions(-) diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index bb50e8fcabbb..9120507f48c8 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -238,23 +238,23 @@ fn get_integer_from_float_constant(value: &Constant) -> Option { fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { // Check receiver if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) { - let method = if F32(f32_consts::E) == value || F64(f64_consts::E) == value { - "exp" + if let Some(method) = if F32(f32_consts::E) == value || F64(f64_consts::E) == value { + Some("exp") } else if F32(2.0) == value || F64(2.0) == value { - "exp2" + Some("exp2") } else { - return; - }; - - span_lint_and_sugg( - cx, - SUBOPTIMAL_FLOPS, - expr.span, - "exponent for bases 2 and e can be computed more accurately", - "consider using", - format!("{}.{}()", prepare_receiver_sugg(cx, &args[1]), method), - Applicability::MachineApplicable, - ); + None + } { + span_lint_and_sugg( + cx, + SUBOPTIMAL_FLOPS, + expr.span, + "exponent for bases 2 and e can be computed more accurately", + "consider using", + format!("{}.{}()", prepare_receiver_sugg(cx, &args[1]), method), + Applicability::MachineApplicable, + ); + } } // Check argument diff --git a/tests/ui/floating_point_powf.fixed b/tests/ui/floating_point_powf.fixed index 7efe10a10f9e..e7ef45634dff 100644 --- a/tests/ui/floating_point_powf.fixed +++ b/tests/ui/floating_point_powf.fixed @@ -18,6 +18,11 @@ fn main() { let _ = x.powi(-16_777_215); let _ = (x as f32).powi(-16_777_215); let _ = (x as f32).powi(3); + let _ = (1.5_f32 + 1.0).cbrt(); + let _ = 1.5_f64.cbrt(); + let _ = 1.5_f64.sqrt(); + let _ = 1.5_f64.powi(3); + // Cases where the lint shouldn't be applied let _ = x.powf(2.1); let _ = x.powf(-2.1); diff --git a/tests/ui/floating_point_powf.rs b/tests/ui/floating_point_powf.rs index 445080417f2e..d749aa2d48a4 100644 --- a/tests/ui/floating_point_powf.rs +++ b/tests/ui/floating_point_powf.rs @@ -18,6 +18,11 @@ fn main() { let _ = x.powf(-16_777_215.0); let _ = (x as f32).powf(-16_777_215.0); let _ = (x as f32).powf(3.0); + let _ = (1.5_f32 + 1.0).powf(1.0 / 3.0); + let _ = 1.5_f64.powf(1.0 / 3.0); + let _ = 1.5_f64.powf(1.0 / 2.0); + let _ = 1.5_f64.powf(3.0); + // Cases where the lint shouldn't be applied let _ = x.powf(2.1); let _ = x.powf(-2.1); diff --git a/tests/ui/floating_point_powf.stderr b/tests/ui/floating_point_powf.stderr index 6ee696e6ada5..e9693de8fc90 100644 --- a/tests/ui/floating_point_powf.stderr +++ b/tests/ui/floating_point_powf.stderr @@ -92,77 +92,101 @@ error: exponentiation with integer powers can be computed more efficiently LL | let _ = (x as f32).powf(3.0); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).powi(3)` +error: cube-root of a number can be computed more accurately + --> $DIR/floating_point_powf.rs:21:13 + | +LL | let _ = (1.5_f32 + 1.0).powf(1.0 / 3.0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(1.5_f32 + 1.0).cbrt()` + +error: cube-root of a number can be computed more accurately + --> $DIR/floating_point_powf.rs:22:13 + | +LL | let _ = 1.5_f64.powf(1.0 / 3.0); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1.5_f64.cbrt()` + +error: square-root of a number can be computed more efficiently and accurately + --> $DIR/floating_point_powf.rs:23:13 + | +LL | let _ = 1.5_f64.powf(1.0 / 2.0); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1.5_f64.sqrt()` + +error: exponentiation with integer powers can be computed more efficiently + --> $DIR/floating_point_powf.rs:24:13 + | +LL | let _ = 1.5_f64.powf(3.0); + | ^^^^^^^^^^^^^^^^^ help: consider using: `1.5_f64.powi(3)` + error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:28:13 + --> $DIR/floating_point_powf.rs:33:13 | LL | let _ = 2f64.powf(x); | ^^^^^^^^^^^^ help: consider using: `x.exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:29:13 + --> $DIR/floating_point_powf.rs:34:13 | LL | let _ = 2f64.powf(3.1); | ^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:30:13 + --> $DIR/floating_point_powf.rs:35:13 | LL | let _ = 2f64.powf(-3.1); | ^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp2()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:31:13 + --> $DIR/floating_point_powf.rs:36:13 | LL | let _ = std::f64::consts::E.powf(x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:32:13 + --> $DIR/floating_point_powf.rs:37:13 | LL | let _ = std::f64::consts::E.powf(3.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp()` error: exponent for bases 2 and e can be computed more accurately - --> $DIR/floating_point_powf.rs:33:13 + --> $DIR/floating_point_powf.rs:38:13 | LL | let _ = std::f64::consts::E.powf(-3.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp()` error: square-root of a number can be computed more efficiently and accurately - --> $DIR/floating_point_powf.rs:34:13 + --> $DIR/floating_point_powf.rs:39:13 | LL | let _ = x.powf(1.0 / 2.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()` error: cube-root of a number can be computed more accurately - --> $DIR/floating_point_powf.rs:35:13 + --> $DIR/floating_point_powf.rs:40:13 | LL | let _ = x.powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:36:13 + --> $DIR/floating_point_powf.rs:41:13 | LL | let _ = x.powf(3.0); | ^^^^^^^^^^^ help: consider using: `x.powi(3)` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:37:13 + --> $DIR/floating_point_powf.rs:42:13 | LL | let _ = x.powf(-2.0); | ^^^^^^^^^^^^ help: consider using: `x.powi(-2)` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:38:13 + --> $DIR/floating_point_powf.rs:43:13 | LL | let _ = x.powf(-2_147_483_648.0); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(-2_147_483_648)` error: exponentiation with integer powers can be computed more efficiently - --> $DIR/floating_point_powf.rs:39:13 + --> $DIR/floating_point_powf.rs:44:13 | LL | let _ = x.powf(2_147_483_647.0); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2_147_483_647)` -error: aborting due to 27 previous errors +error: aborting due to 31 previous errors From c9f4af6e11ce44a3ab5de838279295be3df3aa95 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Thu, 1 Sep 2022 12:09:42 +0100 Subject: [PATCH 4032/5092] Fix typo in comment --- src/librustdoc/passes/stripper.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs index 83ed3752a824..a9d768f0149d 100644 --- a/src/librustdoc/passes/stripper.rs +++ b/src/librustdoc/passes/stripper.rs @@ -91,7 +91,7 @@ impl<'a> DocFolder for Stripper<'a> { clean::ExternCrateItem { .. } => {} clean::ImportItem(ref imp) => { // Because json doesn't inline imports from private modules, we need to mark - // the imported item as retained so it's impls won't be stripped.i + // the imported item as retained so it's impls won't be stripped. // // FIXME: Is it necessary to check for json output here: See // https://github.com/rust-lang/rust/pull/100325#discussion_r941495215 From f5857d5c5e1d2fde302f330d11c5cdea8005eb2a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 31 Aug 2022 21:00:05 +0200 Subject: [PATCH 4033/5092] Move error code book into a sub folder --- src/tools/error_index_generator/main.rs | 81 +++++++-------------- src/tools/error_index_generator/redirect.js | 18 +++-- 2 files changed, 40 insertions(+), 59 deletions(-) diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index 5451e45b28be..1bde8e007826 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -7,7 +7,7 @@ use crate::error_codes::error_codes; use std::env; use std::error::Error; -use std::fs::{self, create_dir_all, File}; +use std::fs::{self, File}; use std::io::Write; use std::path::Path; use std::path::PathBuf; @@ -65,44 +65,6 @@ fn render_markdown(output_path: &Path) -> Result<(), Box> { Ok(()) } -fn move_folder(source: &Path, target: &Path) -> Result<(), Box> { - let entries = - fs::read_dir(source)?.map(|res| res.map(|e| e.path())).collect::, _>>()?; - - for entry in entries { - let file_name = entry.file_name().expect("file_name() failed").to_os_string(); - let output = target.join(file_name); - if entry.is_file() { - fs::rename(entry, output)?; - } else { - if !output.exists() { - create_dir_all(&output)?; - } - move_folder(&entry, &output)?; - } - } - - fs::remove_dir(&source)?; - - Ok(()) -} - -fn render_html(output_path: &Path) -> Result<(), Box> { - // We need to render into a temporary folder to prevent `mdbook` from removing everything - // in the output folder (including other completely unrelated things). - let tmp_output = output_path.join("tmp"); - - if !tmp_output.exists() { - create_dir_all(&tmp_output)?; - } - - render_html_inner(&tmp_output)?; - - move_folder(&tmp_output, output_path)?; - - Ok(()) -} - // By default, mdbook doesn't consider code blocks as Rust ones contrary to rustdoc so we have // to manually add `rust` attribute whenever needed. fn add_rust_attribute_on_codeblock(explanation: &str) -> String { @@ -134,18 +96,14 @@ fn add_rust_attribute_on_codeblock(explanation: &str) -> String { }) } -fn render_html_inner(output_path: &Path) -> Result<(), Box> { - // We need to have a little difference between `summary` and `introduction` because the "draft" - // chapters (the ones looking like `[a]()`) are not handled correctly when being put into a - // `Chapter` directly: they generate a link whereas they shouldn't. +fn render_html(output_path: &Path) -> Result<(), Box> { let mut introduction = format!( - " + " # Rust error codes index This page lists all the error codes emitted by the Rust compiler. -", - include_str!("redirect.js") +" ); let err_codes = error_codes(); @@ -153,7 +111,7 @@ This page lists all the error codes emitted by the Rust compiler. for (err_code, explanation) in err_codes.iter() { if let Some(explanation) = explanation { - introduction.push_str(&format!(" * [{0}](./error_codes/{0}.html)\n", err_code)); + introduction.push_str(&format!(" * [{0}](./{0}.html)\n", err_code)); let content = add_rust_attribute_on_codeblock(explanation); chapters.push(BookItem::Chapter(Chapter { @@ -162,7 +120,7 @@ This page lists all the error codes emitted by the Rust compiler. number: None, sub_items: Vec::new(), // We generate it into the `error_codes` folder. - path: Some(PathBuf::from(&format!("error_codes/{}.html", err_code))), + path: Some(PathBuf::from(&format!("{}.html", err_code))), source_path: None, parent_names: Vec::new(), })); @@ -172,7 +130,7 @@ This page lists all the error codes emitted by the Rust compiler. } let mut config = Config::from_str(include_str!("book_config.toml"))?; - config.build.build_dir = output_path.to_path_buf(); + config.build.build_dir = output_path.join("error_codes").to_path_buf(); let mut book = MDBook::load_with_config_and_summary( env!("CARGO_MANIFEST_DIR"), config, @@ -191,10 +149,27 @@ This page lists all the error codes emitted by the Rust compiler. book.book.sections.push(BookItem::Chapter(chapter)); book.build()?; - // We don't need this file since it's handled by doc.rust-lang.org directly. - let _ = fs::remove_file(output_path.join("404.html")); - // We don't want this file either because it would overwrite the already existing `index.html`. - let _ = fs::remove_file(output_path.join("index.html")); + // We can't put this content into another file, otherwise `mbdbook` will also put it into the + // output directory, making a duplicate. + fs::write( + output_path.join("error-index.html"), + r#" + + + Rust error codes index - Error codes index + + + + + +
If you are not automatically redirected to the error code index, please here. + + +"#, + )?; + + // No need for a 404 file, it's already handled by the server. + fs::remove_file(output_path.join("error_codes/404.html"))?; Ok(()) } diff --git a/src/tools/error_index_generator/redirect.js b/src/tools/error_index_generator/redirect.js index e6e910658e48..8c907f5795d3 100644 --- a/src/tools/error_index_generator/redirect.js +++ b/src/tools/error_index_generator/redirect.js @@ -1,10 +1,16 @@ -(function() {{ - if (window.location.hash) {{ +(function() { + if (window.location.hash) { let code = window.location.hash.replace(/^#/, ''); // We have to make sure this pattern matches to avoid inadvertently creating an // open redirect. - if (/^E[0-9]+$/.test(code)) {{ + if (!/^E[0-9]+$/.test(code)) { + return; + } + if (window.location.pathname.indexOf("/error_codes/") !== -1) { + // We're not at the top level, so we don't prepend with "./error_codes/". + window.location = './' + code + '.html'; + } else { window.location = './error_codes/' + code + '.html'; - }} - }} -}})() + } + } +})() From fb14ad06fab41a4e5c1436749dea21b67105c069 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 1 Sep 2022 14:31:27 +0200 Subject: [PATCH 4034/5092] Correctly merge impl block cfg attributes with its parents --- src/librustdoc/passes/propagate_doc_cfg.rs | 60 ++++++++++++++-------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index 2b12d118bca0..765f7c61bd39 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use crate::clean::cfg::Cfg; use crate::clean::inline::{load_attrs, merge_attrs}; -use crate::clean::{Crate, Item}; +use crate::clean::{Crate, Item, ItemKind}; use crate::core::DocContext; use crate::fold::DocFolder; use crate::passes::Pass; @@ -26,30 +26,50 @@ struct CfgPropagator<'a, 'tcx> { cx: &'a mut DocContext<'tcx>, } +impl<'a, 'tcx> CfgPropagator<'a, 'tcx> { + // Some items need to merge their attributes with their parents' otherwise a few of them + // (mostly `cfg` ones) will be missing. + fn merge_with_parent_attributes(&mut self, item: &mut Item) { + let check_parent = match &*item.kind { + // impl blocks can be in different modules with different cfg and we need to get them + // as well. + ItemKind::ImplItem(_) => false, + kind if kind.is_non_assoc() => true, + _ => return, + }; + + let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local()) + else { return }; + + let hir = self.cx.tcx.hir(); + let hir_id = hir.local_def_id_to_hir_id(def_id); + + if check_parent { + let expected_parent = hir.get_parent_item(hir_id); + // If parents are different, it means that `item` is a reexport and we need + // to compute the actual `cfg` by iterating through its "real" parents. + if self.parent == Some(expected_parent) { + return; + } + } + + let mut attrs = Vec::new(); + for (parent_hir_id, _) in hir.parent_iter(hir_id) { + if let Some(def_id) = hir.opt_local_def_id(parent_hir_id) { + attrs.extend_from_slice(load_attrs(self.cx, def_id.to_def_id())); + } + } + let (_, cfg) = merge_attrs(self.cx, None, item.attrs.other_attrs.as_slice(), Some(&attrs)); + item.cfg = cfg; + } +} + impl<'a, 'tcx> DocFolder for CfgPropagator<'a, 'tcx> { fn fold_item(&mut self, mut item: Item) -> Option { let old_parent_cfg = self.parent_cfg.clone(); - if item.kind.is_non_assoc() && - let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local()) { - let hir = self.cx.tcx.hir(); - let hir_id = hir.local_def_id_to_hir_id(def_id); - let expected_parent = hir.get_parent_item(hir_id); + self.merge_with_parent_attributes(&mut item); - // If parents are different, it means that `item` is a reexport and we need to compute - // the actual `cfg` by iterating through its "real" parents. - if self.parent != Some(expected_parent) { - let mut attrs = Vec::new(); - for (parent_hir_id, _) in hir.parent_iter(hir_id) { - if let Some(def_id) = hir.opt_local_def_id(parent_hir_id) { - attrs.extend_from_slice(load_attrs(self.cx, def_id.to_def_id())); - } - } - let (_, cfg) = - merge_attrs(self.cx, None, item.attrs.other_attrs.as_slice(), Some(&attrs)); - item.cfg = cfg; - } - } let new_cfg = match (self.parent_cfg.take(), item.cfg.take()) { (None, None) => None, (Some(rc), None) | (None, Some(rc)) => Some(rc), From 68d0094305b4bebb96ef9d4c111fca256c1b0b4f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 1 Sep 2022 14:31:41 +0200 Subject: [PATCH 4035/5092] Add regression test for #101129 --- src/test/rustdoc/doc_auto_cfg_nested_impl.rs | 24 ++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/test/rustdoc/doc_auto_cfg_nested_impl.rs diff --git a/src/test/rustdoc/doc_auto_cfg_nested_impl.rs b/src/test/rustdoc/doc_auto_cfg_nested_impl.rs new file mode 100644 index 000000000000..4d73e0d829ad --- /dev/null +++ b/src/test/rustdoc/doc_auto_cfg_nested_impl.rs @@ -0,0 +1,24 @@ +// Regression test for . + +#![feature(doc_auto_cfg)] +#![crate_type = "lib"] +#![crate_name = "foo"] + +pub struct S; +pub trait MyTrait1 {} +pub trait MyTrait2 {} + +// @has foo/struct.S.html +// @has - '//*[@id="impl-MyTrait1-for-S"]//*[@class="stab portability"]' \ +// 'Available on non-crate feature coolstuff only.' +#[cfg(not(feature = "coolstuff"))] +impl MyTrait1 for S {} + +#[cfg(not(feature = "coolstuff"))] +mod submod { + use crate::{S, MyTrait2}; + // This impl should also have the `not(feature = "coolstuff")`. + // @has - '//*[@id="impl-MyTrait2-for-S"]//*[@class="stab portability"]' \ + // 'Available on non-crate feature coolstuff only.' + impl MyTrait2 for S {} +} From d6fc4a9ea6dc062b7ee37a25f20a1309e493e8a1 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 1 Sep 2022 14:13:08 +0200 Subject: [PATCH 4036/5092] Simplify breakables handling --- crates/hir-ty/src/infer.rs | 3 ++ crates/hir-ty/src/infer/expr.rs | 91 ++++++++++++++++----------------- 2 files changed, 48 insertions(+), 46 deletions(-) diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 5df48e5fdcba..ba18d0c5ea6b 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -418,8 +418,11 @@ pub(crate) struct InferenceContext<'a> { #[derive(Clone, Debug)] struct BreakableContext { + /// Whether this context contains at least one break expression. may_break: bool, + /// The coercion target of the context. coerce: CoerceMany, + /// The optional label of the context. label: Option, } diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index a42a00ea598e..a29e15ec5cba 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -10,7 +10,7 @@ use chalk_ir::{ cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind, }; use hir_def::{ - expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, Literal, Statement, UnaryOp}, + expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, LabelId, Literal, Statement, UnaryOp}, generics::TypeOrConstParamData, path::{GenericArg, GenericArgs}, resolver::resolver_for_expr, @@ -120,20 +120,16 @@ impl<'a> InferenceContext<'a> { let ty = match label { Some(_) => { let break_ty = self.table.new_type_var(); - self.breakables.push(BreakableContext { - may_break: false, - coerce: CoerceMany::new(break_ty.clone()), - label: label.map(|label| self.body[label].name.clone()), + let (ctx, ty) = self.with_breakable_ctx(break_ty.clone(), *label, |this| { + this.infer_block( + tgt_expr, + statements, + *tail, + &Expectation::has_type(break_ty), + ) }); - let ty = self.infer_block( - tgt_expr, - statements, - *tail, - &Expectation::has_type(break_ty), - ); - let ctxt = self.breakables.pop().expect("breakable stack broken"); - if ctxt.may_break { - ctxt.coerce.complete() + if ctx.may_break { + ctx.coerce.complete() } else { ty } @@ -166,54 +162,42 @@ impl<'a> InferenceContext<'a> { TyKind::OpaqueType(opaque_ty_id, Substitution::from1(Interner, inner_ty)) .intern(Interner) } - Expr::Loop { body, label } => { - self.breakables.push(BreakableContext { - may_break: false, - coerce: CoerceMany::new(self.table.new_type_var()), - label: label.map(|label| self.body[label].name.clone()), + &Expr::Loop { body, label } => { + let ty = self.table.new_type_var(); + let (ctx, ()) = self.with_breakable_ctx(ty, label, |this| { + this.infer_expr(body, &Expectation::has_type(TyBuilder::unit())); }); - self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit())); - let ctxt = self.breakables.pop().expect("breakable stack broken"); - - if ctxt.may_break { + if ctx.may_break { self.diverges = Diverges::Maybe; - ctxt.coerce.complete() + ctx.coerce.complete() } else { TyKind::Never.intern(Interner) } } - Expr::While { condition, body, label } => { - self.breakables.push(BreakableContext { - may_break: false, - coerce: CoerceMany::new(self.err_ty()), - label: label.map(|label| self.body[label].name.clone()), + &Expr::While { condition, body, label } => { + self.with_breakable_ctx(self.err_ty(), label, |this| { + this.infer_expr( + condition, + &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)), + ); + this.infer_expr(body, &Expectation::has_type(TyBuilder::unit())); }); - self.infer_expr( - *condition, - &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)), - ); - self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit())); - let _ctxt = self.breakables.pop().expect("breakable stack broken"); + // the body may not run, so it diverging doesn't mean we diverge self.diverges = Diverges::Maybe; TyBuilder::unit() } - Expr::For { iterable, body, pat, label } => { - let iterable_ty = self.infer_expr(*iterable, &Expectation::none()); - - self.breakables.push(BreakableContext { - may_break: false, - coerce: CoerceMany::new(self.err_ty()), - label: label.map(|label| self.body[label].name.clone()), - }); + &Expr::For { iterable, body, pat, label } => { + let iterable_ty = self.infer_expr(iterable, &Expectation::none()); let pat_ty = self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item()); - self.infer_pat(*pat, &pat_ty, BindingMode::default()); + self.infer_pat(pat, &pat_ty, BindingMode::default()); + let (_ctx, ()) = self.with_breakable_ctx(self.err_ty(), label, |this| { + this.infer_expr(body, &Expectation::has_type(TyBuilder::unit())); + }); - self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit())); - let _ctxt = self.breakables.pop().expect("breakable stack broken"); // the body may not run, so it diverging doesn't mean we diverge self.diverges = Diverges::Maybe; TyBuilder::unit() @@ -1472,4 +1456,19 @@ impl<'a> InferenceContext<'a> { }, }) } + + fn with_breakable_ctx( + &mut self, + ty: Ty, + label: Option, + cb: impl FnOnce(&mut Self) -> T, + ) -> (BreakableContext, T) { + self.breakables.push({ + let label = label.map(|label| self.body[label].name.clone()); + BreakableContext { may_break: false, coerce: CoerceMany::new(ty), label } + }); + let res = cb(self); + let ctx = self.breakables.pop().expect("breakable stack broken"); + (ctx, res) + } } From 1e66a5a8ce38c0ec96479f234e87d10850264e09 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 1 Sep 2022 14:30:57 +0200 Subject: [PATCH 4037/5092] Diagnose incorrect continue expressions --- crates/hir-ty/src/infer.rs | 2 +- crates/hir-ty/src/infer/expr.rs | 53 +++++++++++-------- crates/hir/src/diagnostics.rs | 1 + crates/hir/src/lib.rs | 6 +-- .../src/handlers/break_outside_of_loop.rs | 17 ++++-- 5 files changed, 48 insertions(+), 31 deletions(-) diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index ba18d0c5ea6b..f41c4afaf565 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -182,7 +182,7 @@ pub(crate) type InferResult = Result, TypeError>; #[derive(Debug, PartialEq, Eq, Clone)] pub enum InferenceDiagnostic { NoSuchField { expr: ExprId }, - BreakOutsideOfLoop { expr: ExprId }, + BreakOutsideOfLoop { expr: ExprId, is_break: bool }, MismatchedArgCount { call_expr: ExprId, expected: usize, found: usize }, } diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index a29e15ec5cba..09d83202522d 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -120,19 +120,16 @@ impl<'a> InferenceContext<'a> { let ty = match label { Some(_) => { let break_ty = self.table.new_type_var(); - let (ctx, ty) = self.with_breakable_ctx(break_ty.clone(), *label, |this| { - this.infer_block( - tgt_expr, - statements, - *tail, - &Expectation::has_type(break_ty), - ) - }); - if ctx.may_break { - ctx.coerce.complete() - } else { - ty - } + let (breaks, ty) = + self.with_breakable_ctx(break_ty.clone(), *label, |this| { + this.infer_block( + tgt_expr, + statements, + *tail, + &Expectation::has_type(break_ty), + ) + }); + breaks.unwrap_or(ty) } None => self.infer_block(tgt_expr, statements, *tail, expected), }; @@ -164,15 +161,16 @@ impl<'a> InferenceContext<'a> { } &Expr::Loop { body, label } => { let ty = self.table.new_type_var(); - let (ctx, ()) = self.with_breakable_ctx(ty, label, |this| { + let (breaks, ()) = self.with_breakable_ctx(ty, label, |this| { this.infer_expr(body, &Expectation::has_type(TyBuilder::unit())); }); - if ctx.may_break { - self.diverges = Diverges::Maybe; - ctx.coerce.complete() - } else { - TyKind::Never.intern(Interner) + match breaks { + Some(breaks) => { + self.diverges = Diverges::Maybe; + breaks + } + None => TyKind::Never.intern(Interner), } } &Expr::While { condition, body, label } => { @@ -194,7 +192,7 @@ impl<'a> InferenceContext<'a> { self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item()); self.infer_pat(pat, &pat_ty, BindingMode::default()); - let (_ctx, ()) = self.with_breakable_ctx(self.err_ty(), label, |this| { + self.with_breakable_ctx(self.err_ty(), label, |this| { this.infer_expr(body, &Expectation::has_type(TyBuilder::unit())); }); @@ -356,7 +354,15 @@ impl<'a> InferenceContext<'a> { let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr); self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or_else(|| self.err_ty()) } - Expr::Continue { .. } => TyKind::Never.intern(Interner), + Expr::Continue { label } => { + if let None = find_breakable(&mut self.breakables, label.as_ref()) { + self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop { + expr: tgt_expr, + is_break: false, + }); + }; + TyKind::Never.intern(Interner) + } Expr::Break { expr, label } => { let mut coerce = match find_breakable(&mut self.breakables, label.as_ref()) { Some(ctxt) => { @@ -384,6 +390,7 @@ impl<'a> InferenceContext<'a> { } else { self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop { expr: tgt_expr, + is_break: true, }); }; @@ -1462,13 +1469,13 @@ impl<'a> InferenceContext<'a> { ty: Ty, label: Option, cb: impl FnOnce(&mut Self) -> T, - ) -> (BreakableContext, T) { + ) -> (Option, T) { self.breakables.push({ let label = label.map(|label| self.body[label].name.clone()); BreakableContext { may_break: false, coerce: CoerceMany::new(ty), label } }); let res = cb(self); let ctx = self.breakables.pop().expect("breakable stack broken"); - (ctx, res) + (ctx.may_break.then(|| ctx.coerce.complete()), res) } } diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index 50374f4b3fe4..5edc16d8bce9 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -124,6 +124,7 @@ pub struct NoSuchField { #[derive(Debug)] pub struct BreakOutsideOfLoop { pub expr: InFile>, + pub is_break: bool, } #[derive(Debug)] diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 6dccf2ed20b8..e4bb63a86471 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -1216,11 +1216,11 @@ impl DefWithBody { let field = source_map.field_syntax(*expr); acc.push(NoSuchField { field }.into()) } - hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr } => { + &hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break } => { let expr = source_map - .expr_syntax(*expr) + .expr_syntax(expr) .expect("break outside of loop in synthetic syntax"); - acc.push(BreakOutsideOfLoop { expr }.into()) + acc.push(BreakOutsideOfLoop { expr, is_break }.into()) } hir_ty::InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => { match source_map.expr_syntax(*call_expr) { diff --git a/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs b/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs index d12594a4ce5c..59203106efa5 100644 --- a/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs +++ b/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs @@ -7,9 +7,10 @@ pub(crate) fn break_outside_of_loop( ctx: &DiagnosticsContext<'_>, d: &hir::BreakOutsideOfLoop, ) -> Diagnostic { + let construct = if d.is_break { "break" } else { "continue" }; Diagnostic::new( "break-outside-of-loop", - "break outside of loop", + format!("{construct} outside of loop"), ctx.sema.diagnostics_display_range(d.expr.clone().map(|it| it.into())).range, ) } @@ -19,11 +20,19 @@ mod tests { use crate::tests::check_diagnostics; #[test] - fn break_outside_of_loop() { + fn outside_of_loop() { check_diagnostics( r#" -fn foo() { break; } - //^^^^^ error: break outside of loop +fn foo() { + break; + //^^^^^ error: break outside of loop + break 'a; + //^^^^^^^^ error: break outside of loop + continue; + //^^^^^^^^ error: continue outside of loop + continue 'a; + //^^^^^^^^^^^ error: continue outside of loop +} "#, ); } From 8110119fef9dbbd5b68e27245e84900b5faf0a3e Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 1 Sep 2022 14:54:47 +0200 Subject: [PATCH 4038/5092] Properly handle break resolution inside non-breakable expressions --- crates/hir-ty/src/infer.rs | 28 ++++- crates/hir-ty/src/infer/expr.rs | 49 ++++++--- .../src/handlers/break_outside_of_loop.rs | 103 ++++++++++++++++++ 3 files changed, 163 insertions(+), 17 deletions(-) diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index f41c4afaf565..10ffde87eef1 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -424,15 +424,39 @@ struct BreakableContext { coerce: CoerceMany, /// The optional label of the context. label: Option, + kind: BreakableKind, +} + +#[derive(Clone, Debug)] +enum BreakableKind { + Block, + Loop, + /// A border is something like an async block, closure etc. Anything that prevents + /// breaking/continuing through + Border, } fn find_breakable<'c>( ctxs: &'c mut [BreakableContext], label: Option<&name::Name>, ) -> Option<&'c mut BreakableContext> { + let mut ctxs = ctxs + .iter_mut() + .rev() + .take_while(|it| matches!(it.kind, BreakableKind::Block | BreakableKind::Loop)); match label { - Some(_) => ctxs.iter_mut().rev().find(|ctx| ctx.label.as_ref() == label), - None => ctxs.last_mut(), + Some(_) => ctxs.find(|ctx| ctx.label.as_ref() == label), + None => ctxs.find(|ctx| matches!(ctx.kind, BreakableKind::Loop)), + } +} + +fn find_continuable<'c>( + ctxs: &'c mut [BreakableContext], + label: Option<&name::Name>, +) -> Option<&'c mut BreakableContext> { + match label { + Some(_) => find_breakable(ctxs, label).filter(|it| matches!(it.kind, BreakableKind::Loop)), + None => find_breakable(ctxs, label), } } diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index 09d83202522d..f3f4ee65bb2e 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -23,7 +23,7 @@ use syntax::ast::RangeOp; use crate::{ autoderef::{self, Autoderef}, consteval, - infer::coerce::CoerceMany, + infer::{coerce::CoerceMany, find_continuable, BreakableKind}, lower::{ const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode, }, @@ -120,15 +120,19 @@ impl<'a> InferenceContext<'a> { let ty = match label { Some(_) => { let break_ty = self.table.new_type_var(); - let (breaks, ty) = - self.with_breakable_ctx(break_ty.clone(), *label, |this| { + let (breaks, ty) = self.with_breakable_ctx( + BreakableKind::Block, + break_ty.clone(), + *label, + |this| { this.infer_block( tgt_expr, statements, *tail, &Expectation::has_type(break_ty), ) - }); + }, + ); breaks.unwrap_or(ty) } None => self.infer_block(tgt_expr, statements, *tail, expected), @@ -136,9 +140,17 @@ impl<'a> InferenceContext<'a> { self.resolver = old_resolver; ty } - Expr::Unsafe { body } | Expr::Const { body } => self.infer_expr(*body, expected), + Expr::Unsafe { body } => self.infer_expr(*body, expected), + Expr::Const { body } => { + self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| { + this.infer_expr(*body, expected) + }) + .1 + } Expr::TryBlock { body } => { - let _inner = self.infer_expr(*body, expected); + self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| { + let _inner = this.infer_expr(*body, expected); + }); // FIXME should be std::result::Result<{inner}, _> self.err_ty() } @@ -147,7 +159,10 @@ impl<'a> InferenceContext<'a> { let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone()); - let inner_ty = self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty)); + let (_, inner_ty) = + self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| { + this.infer_expr_coerce(*body, &Expectation::has_type(ret_ty)) + }); self.diverges = prev_diverges; self.return_ty = prev_ret_ty; @@ -161,9 +176,10 @@ impl<'a> InferenceContext<'a> { } &Expr::Loop { body, label } => { let ty = self.table.new_type_var(); - let (breaks, ()) = self.with_breakable_ctx(ty, label, |this| { - this.infer_expr(body, &Expectation::has_type(TyBuilder::unit())); - }); + let (breaks, ()) = + self.with_breakable_ctx(BreakableKind::Loop, ty, label, |this| { + this.infer_expr(body, &Expectation::has_type(TyBuilder::unit())); + }); match breaks { Some(breaks) => { @@ -174,7 +190,7 @@ impl<'a> InferenceContext<'a> { } } &Expr::While { condition, body, label } => { - self.with_breakable_ctx(self.err_ty(), label, |this| { + self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| { this.infer_expr( condition, &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(Interner)), @@ -192,7 +208,7 @@ impl<'a> InferenceContext<'a> { self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item()); self.infer_pat(pat, &pat_ty, BindingMode::default()); - self.with_breakable_ctx(self.err_ty(), label, |this| { + self.with_breakable_ctx(BreakableKind::Loop, self.err_ty(), label, |this| { this.infer_expr(body, &Expectation::has_type(TyBuilder::unit())); }); @@ -251,7 +267,9 @@ impl<'a> InferenceContext<'a> { let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone()); - self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty)); + self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| { + this.infer_expr_coerce(*body, &Expectation::has_type(ret_ty)); + }); self.diverges = prev_diverges; self.return_ty = prev_ret_ty; @@ -355,7 +373,7 @@ impl<'a> InferenceContext<'a> { self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or_else(|| self.err_ty()) } Expr::Continue { label } => { - if let None = find_breakable(&mut self.breakables, label.as_ref()) { + if let None = find_continuable(&mut self.breakables, label.as_ref()) { self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop { expr: tgt_expr, is_break: false, @@ -1466,13 +1484,14 @@ impl<'a> InferenceContext<'a> { fn with_breakable_ctx( &mut self, + kind: BreakableKind, ty: Ty, label: Option, cb: impl FnOnce(&mut Self) -> T, ) -> (Option, T) { self.breakables.push({ let label = label.map(|label| self.body[label].name.clone()); - BreakableContext { may_break: false, coerce: CoerceMany::new(ty), label } + BreakableContext { kind, may_break: false, coerce: CoerceMany::new(ty), label } }); let res = cb(self); let ctx = self.breakables.pop().expect("breakable stack broken"); diff --git a/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs b/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs index 59203106efa5..0c92e706b391 100644 --- a/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs +++ b/crates/ide-diagnostics/src/handlers/break_outside_of_loop.rs @@ -33,6 +33,109 @@ fn foo() { continue 'a; //^^^^^^^^^^^ error: continue outside of loop } +"#, + ); + } + + #[test] + fn try_blocks_are_borders() { + check_diagnostics( + r#" +fn foo() { + 'a: loop { + try { + break; + //^^^^^ error: break outside of loop + break 'a; + //^^^^^^^^ error: break outside of loop + continue; + //^^^^^^^^ error: continue outside of loop + continue 'a; + //^^^^^^^^^^^ error: continue outside of loop + }; + } +} +"#, + ); + } + + #[test] + fn async_blocks_are_borders() { + check_diagnostics( + r#" +fn foo() { + 'a: loop { + try { + break; + //^^^^^ error: break outside of loop + break 'a; + //^^^^^^^^ error: break outside of loop + continue; + //^^^^^^^^ error: continue outside of loop + continue 'a; + //^^^^^^^^^^^ error: continue outside of loop + }; + } +} +"#, + ); + } + + #[test] + fn closures_are_borders() { + check_diagnostics( + r#" +fn foo() { + 'a: loop { + try { + break; + //^^^^^ error: break outside of loop + break 'a; + //^^^^^^^^ error: break outside of loop + continue; + //^^^^^^^^ error: continue outside of loop + continue 'a; + //^^^^^^^^^^^ error: continue outside of loop + }; + } +} +"#, + ); + } + + #[test] + fn blocks_pass_through() { + check_diagnostics( + r#" +fn foo() { + 'a: loop { + { + break; + break 'a; + continue; + continue 'a; + } + } +} +"#, + ); + } + + #[test] + fn label_blocks() { + check_diagnostics( + r#" +fn foo() { + 'a: { + break; + //^^^^^ error: break outside of loop + break 'a; + continue; + //^^^^^^^^ error: continue outside of loop + continue 'a; + //^^^^^^^^^^^ error: continue outside of loop + } +} "#, ); } From c6b7f453088df08294372474085765e7c6361b9f Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 1 Sep 2022 15:04:55 +0200 Subject: [PATCH 4039/5092] Don't run `rust-2021-compatibility` lints, our crates are already on 2021 --- .github/workflows/ci.yaml | 132 +++++++++++++++++++------------------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index a70252fa65a5..1563ee0b1438 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -6,15 +6,15 @@ on: pull_request: push: branches: - - auto - - try + - auto + - try env: CARGO_INCREMENTAL: 0 CARGO_NET_RETRY: 10 CI: 1 RUST_BACKTRACE: short - RUSTFLAGS: "-D warnings -W unreachable-pub -W rust-2021-compatibility" + RUSTFLAGS: "-D warnings -W unreachable-pub -W bare-trait-objects" RUSTUP_MAX_RETRIES: 10 jobs: @@ -31,25 +31,25 @@ jobs: os: [ubuntu-latest, windows-latest, macos-latest] steps: - - name: Checkout repository - uses: actions/checkout@v3 - with: - ref: ${{ github.event.pull_request.head.sha }} - fetch-depth: 20 + - name: Checkout repository + uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 20 - - name: Install Rust toolchain - run: | - rustup update --no-self-update stable - rustup component add rustfmt rust-src + - name: Install Rust toolchain + run: | + rustup update --no-self-update stable + rustup component add rustfmt rust-src - - name: Cache Dependencies - uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72 + - name: Cache Dependencies + uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72 - - name: Compile - run: cargo test --no-run --locked + - name: Compile + run: cargo test --no-run --locked - - name: Test - run: cargo test -- --nocapture --quiet + - name: Test + run: cargo test -- --nocapture --quiet # Weird targets to catch non-portable code rust-cross: @@ -64,25 +64,25 @@ jobs: targets_ide: "wasm32-unknown-unknown" steps: - - name: Checkout repository - uses: actions/checkout@v3 + - name: Checkout repository + uses: actions/checkout@v3 - - name: Install Rust toolchain - run: | - rustup update --no-self-update stable - rustup target add ${{ env.targets }} ${{ env.targets_ide }} + - name: Install Rust toolchain + run: | + rustup update --no-self-update stable + rustup target add ${{ env.targets }} ${{ env.targets_ide }} - - name: Cache Dependencies - uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72 + - name: Cache Dependencies + uses: Swatinem/rust-cache@ce325b60658c1b38465c06cc965b79baf32c1e72 - - name: Check - run: | - for target in ${{ env.targets }}; do - cargo check --target=$target --all-targets - done - for target in ${{ env.targets_ide }}; do - cargo check -p ide --target=$target --all-targets - done + - name: Check + run: | + for target in ${{ env.targets }}; do + cargo check --target=$target --all-targets + done + for target in ${{ env.targets_ide }}; do + cargo check -p ide --target=$target --all-targets + done typescript: if: github.repository == 'rust-lang/rust-analyzer' @@ -95,47 +95,47 @@ jobs: runs-on: ${{ matrix.os }} steps: - - name: Checkout repository - uses: actions/checkout@v3 + - name: Checkout repository + uses: actions/checkout@v3 - - name: Install Nodejs - uses: actions/setup-node@v1 - with: - node-version: 16.x + - name: Install Nodejs + uses: actions/setup-node@v1 + with: + node-version: 16.x - - name: Install xvfb - if: matrix.os == 'ubuntu-latest' - run: sudo apt-get install -y xvfb + - name: Install xvfb + if: matrix.os == 'ubuntu-latest' + run: sudo apt-get install -y xvfb - - run: npm ci - working-directory: ./editors/code + - run: npm ci + working-directory: ./editors/code -# - run: npm audit || { sleep 10 && npm audit; } || { sleep 30 && npm audit; } -# if: runner.os == 'Linux' -# working-directory: ./editors/code + # - run: npm audit || { sleep 10 && npm audit; } || { sleep 30 && npm audit; } + # if: runner.os == 'Linux' + # working-directory: ./editors/code - - run: npm run lint - working-directory: ./editors/code + - run: npm run lint + working-directory: ./editors/code - - name: Run VS Code tests (Linux) - if: matrix.os == 'ubuntu-latest' - env: - VSCODE_CLI: 1 - run: xvfb-run npm test - working-directory: ./editors/code + - name: Run VS Code tests (Linux) + if: matrix.os == 'ubuntu-latest' + env: + VSCODE_CLI: 1 + run: xvfb-run npm test + working-directory: ./editors/code - - name: Run VS Code tests (Windows) - if: matrix.os == 'windows-latest' - env: - VSCODE_CLI: 1 - run: npm test - working-directory: ./editors/code + - name: Run VS Code tests (Windows) + if: matrix.os == 'windows-latest' + env: + VSCODE_CLI: 1 + run: npm test + working-directory: ./editors/code - - run: npm run pretest - working-directory: ./editors/code + - run: npm run pretest + working-directory: ./editors/code - - run: npm run package --scripts-prepend-node-path - working-directory: ./editors/code + - run: npm run package --scripts-prepend-node-path + working-directory: ./editors/code end-success: name: bors build finished From e12962b4aa1c019982fa83cbfc05939e398e8c25 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 1 Sep 2022 15:20:05 +0200 Subject: [PATCH 4040/5092] Zulip notifications: ping the Miri team --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 95303a592c8a..8193411f8799 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -142,7 +142,7 @@ jobs: ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }} run: | ~/.local/bin/zulip-send --stream miri --subject "Cron Job Failure (miri, $(date -u +%Y-%m))" \ - --message 'Dear @**RalfJ** and @**oli** + --message 'Dear @*T-miri*, It would appear that the Miri cron job build failed. Would you mind investigating this issue? From 7dc186ff7efd4526316fe48845dad581706ea529 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 14 Aug 2022 20:28:34 +0300 Subject: [PATCH 4041/5092] rustc_target: Add a compatibility layer to separate internal and user-facing linker flavors --- compiler/rustc_codegen_ssa/src/back/link.rs | 3 +- compiler/rustc_session/src/config.rs | 4 +- compiler/rustc_session/src/options.rs | 10 +- compiler/rustc_target/src/spec/mod.rs | 190 +++++++++++++----- .../rustc_target/src/spec/tests/tests_impl.rs | 6 +- 5 files changed, 152 insertions(+), 61 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index d2f2c7bf7988..efad767edef2 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1236,7 +1236,8 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { // linker and linker flavor specified via command line have precedence over what the target // specification specifies - if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), sess.opts.cg.linker_flavor) { + let linker_flavor = sess.opts.cg.linker_flavor.map(LinkerFlavor::from_cli); + if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), linker_flavor) { return ret; } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 162fc9aa0a6e..c894b20e1a7d 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -12,7 +12,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::ToStableHashKey; use rustc_target::abi::{Align, TargetDataLayout}; -use rustc_target::spec::{LinkerFlavor, SplitDebuginfo, Target, TargetTriple, TargetWarnings}; +use rustc_target::spec::{LinkerFlavorCli, SplitDebuginfo, Target, TargetTriple, TargetWarnings}; use rustc_target::spec::{PanicStrategy, SanitizerSet, TARGETS}; use crate::parse::{CrateCheckConfig, CrateConfig}; @@ -2379,7 +2379,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { } } - if cg.linker_flavor == Some(LinkerFlavor::L4Bender) + if cg.linker_flavor == Some(LinkerFlavorCli::L4Bender) && !nightly_options::is_unstable_enabled(matches) { early_error( diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 46bba02537dc..9f07394b61ab 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -5,7 +5,7 @@ use crate::lint; use crate::search_paths::SearchPath; use crate::utils::NativeLib; use rustc_errors::LanguageIdentifier; -use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy, SanitizerSet}; +use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, SanitizerSet}; use rustc_target::spec::{ RelocModel, RelroLevel, SplitDebuginfo, StackProtector, TargetTriple, TlsModel, }; @@ -382,7 +382,7 @@ mod desc { "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`"; pub const parse_cfprotection: &str = "`none`|`no`|`n` (default), `branch`, `return`, or `full`|`yes`|`y` (equivalent to `branch` and `return`)"; pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`"; - pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavor::one_of(); + pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of(); pub const parse_optimization_fuel: &str = "crate=integer"; pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`"; pub const parse_instrument_coverage: &str = @@ -763,8 +763,8 @@ mod parse { true } - pub(crate) fn parse_linker_flavor(slot: &mut Option, v: Option<&str>) -> bool { - match v.and_then(LinkerFlavor::from_str) { + pub(crate) fn parse_linker_flavor(slot: &mut Option, v: Option<&str>) -> bool { + match v.and_then(LinkerFlavorCli::from_str) { Some(lf) => *slot = Some(lf), _ => return false, } @@ -1139,7 +1139,7 @@ options! { on C toolchain installed in the system"), linker: Option = (None, parse_opt_pathbuf, [UNTRACKED], "system linker to link outputs with"), - linker_flavor: Option = (None, parse_linker_flavor, [UNTRACKED], + linker_flavor: Option = (None, parse_linker_flavor, [UNTRACKED], "linker flavor"), linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled, parse_linker_plugin_lto, [TRACKED], diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 2459b0280cd6..168fd154cf00 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -102,6 +102,18 @@ pub enum LinkerFlavor { BpfLinker, } +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +pub enum LinkerFlavorCli { + Em, + Gcc, + L4Bender, + Ld, + Msvc, + Lld(LldFlavor), + PtxLinker, + BpfLinker, +} + #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] pub enum LldFlavor { Wasm, @@ -137,14 +149,37 @@ impl ToJson for LldFlavor { } } -impl ToJson for LinkerFlavor { - fn to_json(&self) -> Json { - self.desc().to_json() +impl LinkerFlavor { + pub fn from_cli(cli: LinkerFlavorCli) -> LinkerFlavor { + match cli { + LinkerFlavorCli::Em => LinkerFlavor::Em, + LinkerFlavorCli::Gcc => LinkerFlavor::Gcc, + LinkerFlavorCli::L4Bender => LinkerFlavor::L4Bender, + LinkerFlavorCli::Ld => LinkerFlavor::Ld, + LinkerFlavorCli::Msvc => LinkerFlavor::Msvc, + LinkerFlavorCli::Lld(lld_flavor) => LinkerFlavor::Lld(lld_flavor), + LinkerFlavorCli::PtxLinker => LinkerFlavor::PtxLinker, + LinkerFlavorCli::BpfLinker => LinkerFlavor::BpfLinker, + } + } + + fn to_cli(self) -> LinkerFlavorCli { + match self { + LinkerFlavor::Em => LinkerFlavorCli::Em, + LinkerFlavor::Gcc => LinkerFlavorCli::Gcc, + LinkerFlavor::L4Bender => LinkerFlavorCli::L4Bender, + LinkerFlavor::Ld => LinkerFlavorCli::Ld, + LinkerFlavor::Msvc => LinkerFlavorCli::Msvc, + LinkerFlavor::Lld(lld_flavor) => LinkerFlavorCli::Lld(lld_flavor), + LinkerFlavor::PtxLinker => LinkerFlavorCli::PtxLinker, + LinkerFlavor::BpfLinker => LinkerFlavorCli::BpfLinker, + } } } + macro_rules! flavor_mappings { ($((($($flavor:tt)*), $string:expr),)*) => ( - impl LinkerFlavor { + impl LinkerFlavorCli { pub const fn one_of() -> &'static str { concat!("one of: ", $($string, " ",)*) } @@ -166,17 +201,23 @@ macro_rules! flavor_mappings { } flavor_mappings! { - ((LinkerFlavor::Em), "em"), - ((LinkerFlavor::Gcc), "gcc"), - ((LinkerFlavor::L4Bender), "l4-bender"), - ((LinkerFlavor::Ld), "ld"), - ((LinkerFlavor::Msvc), "msvc"), - ((LinkerFlavor::PtxLinker), "ptx-linker"), - ((LinkerFlavor::BpfLinker), "bpf-linker"), - ((LinkerFlavor::Lld(LldFlavor::Wasm)), "wasm-ld"), - ((LinkerFlavor::Lld(LldFlavor::Ld64)), "ld64.lld"), - ((LinkerFlavor::Lld(LldFlavor::Ld)), "ld.lld"), - ((LinkerFlavor::Lld(LldFlavor::Link)), "lld-link"), + ((LinkerFlavorCli::Em), "em"), + ((LinkerFlavorCli::Gcc), "gcc"), + ((LinkerFlavorCli::L4Bender), "l4-bender"), + ((LinkerFlavorCli::Ld), "ld"), + ((LinkerFlavorCli::Msvc), "msvc"), + ((LinkerFlavorCli::PtxLinker), "ptx-linker"), + ((LinkerFlavorCli::BpfLinker), "bpf-linker"), + ((LinkerFlavorCli::Lld(LldFlavor::Wasm)), "wasm-ld"), + ((LinkerFlavorCli::Lld(LldFlavor::Ld64)), "ld64.lld"), + ((LinkerFlavorCli::Lld(LldFlavor::Ld)), "ld.lld"), + ((LinkerFlavorCli::Lld(LldFlavor::Link)), "lld-link"), +} + +impl ToJson for LinkerFlavorCli { + fn to_json(&self) -> Json { + self.desc().to_json() + } } #[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable, HashStable_Generic)] @@ -467,6 +508,7 @@ impl fmt::Display for LinkOutputKind { } pub type LinkArgs = BTreeMap>>; +pub type LinkArgsCli = BTreeMap>>; /// Which kind of debuginfo does the target use? /// @@ -1213,6 +1255,7 @@ pub struct TargetOptions { /// Default linker flavor used if `-C linker-flavor` or `-C linker` are not passed /// on the command line. Defaults to `LinkerFlavor::Gcc`. pub linker_flavor: LinkerFlavor, + linker_flavor_json: LinkerFlavorCli, /// Linker to invoke pub linker: Option>, @@ -1223,6 +1266,7 @@ pub struct TargetOptions { /// Linker arguments that are passed *before* any user-defined libraries. pub pre_link_args: LinkArgs, + pre_link_args_json: LinkArgsCli, /// Objects to link before and after all other object code. pub pre_link_objects: CrtObjects, pub post_link_objects: CrtObjects, @@ -1235,15 +1279,19 @@ pub struct TargetOptions { /// user-defined but before post-link objects. Standard platform /// libraries that should be always be linked to, usually go here. pub late_link_args: LinkArgs, + late_link_args_json: LinkArgsCli, /// Linker arguments used in addition to `late_link_args` if at least one /// Rust dependency is dynamically linked. pub late_link_args_dynamic: LinkArgs, + late_link_args_dynamic_json: LinkArgsCli, /// Linker arguments used in addition to `late_link_args` if all Rust /// dependencies are statically linked. pub late_link_args_static: LinkArgs, + late_link_args_static_json: LinkArgsCli, /// Linker arguments that are unconditionally passed *after* any /// user-defined libraries. pub post_link_args: LinkArgs, + post_link_args_json: LinkArgsCli, /// Optional link script applied to `dylib` and `executable` crate types. /// This is a string containing the script, not a path. Can only be applied /// to linkers where `linker_is_gnu` is true. @@ -1554,6 +1602,36 @@ impl TargetOptions { fn add_post_link_args(&mut self, flavor: LinkerFlavor, args: &[&'static str]) { add_link_args(&mut self.post_link_args, flavor, args); } + + fn update_from_cli(&mut self) { + self.linker_flavor = LinkerFlavor::from_cli(self.linker_flavor_json); + for (args, args_json) in [ + (&mut self.pre_link_args, &self.pre_link_args_json), + (&mut self.late_link_args, &self.late_link_args_json), + (&mut self.late_link_args_dynamic, &self.late_link_args_dynamic_json), + (&mut self.late_link_args_static, &self.late_link_args_static_json), + (&mut self.post_link_args, &self.post_link_args_json), + ] { + *args = args_json + .iter() + .map(|(flavor, args)| (LinkerFlavor::from_cli(*flavor), args.clone())) + .collect(); + } + } + + fn update_to_cli(&mut self) { + self.linker_flavor_json = self.linker_flavor.to_cli(); + for (args, args_json) in [ + (&self.pre_link_args, &mut self.pre_link_args_json), + (&self.late_link_args, &mut self.late_link_args_json), + (&self.late_link_args_dynamic, &mut self.late_link_args_dynamic_json), + (&self.late_link_args_static, &mut self.late_link_args_static_json), + (&self.post_link_args, &mut self.post_link_args_json), + ] { + *args_json = + args.iter().map(|(flavor, args)| (flavor.to_cli(), args.clone())).collect(); + } + } } impl Default for TargetOptions { @@ -1569,10 +1647,13 @@ impl Default for TargetOptions { abi: "".into(), vendor: "unknown".into(), linker_flavor: LinkerFlavor::Gcc, + linker_flavor_json: LinkerFlavorCli::Gcc, linker: option_env!("CFG_DEFAULT_LINKER").map(|s| s.into()), lld_flavor: LldFlavor::Ld, pre_link_args: LinkArgs::new(), + pre_link_args_json: LinkArgsCli::new(), post_link_args: LinkArgs::new(), + post_link_args_json: LinkArgsCli::new(), link_script: None, asm_args: cvs![], cpu: "generic".into(), @@ -1613,8 +1694,11 @@ impl Default for TargetOptions { post_link_objects_self_contained: Default::default(), link_self_contained: LinkSelfContainedDefault::False, late_link_args: LinkArgs::new(), + late_link_args_json: LinkArgsCli::new(), late_link_args_dynamic: LinkArgs::new(), + late_link_args_dynamic_json: LinkArgsCli::new(), late_link_args_static: LinkArgs::new(), + late_link_args_static_json: LinkArgsCli::new(), link_env: cvs![], link_env_remove: cvs![], archive_format: "gnu".into(), @@ -2019,13 +2103,13 @@ impl Target { Some(Ok(())) })).unwrap_or(Ok(())) } ); - ($key_name:ident, LinkerFlavor) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { - match LinkerFlavor::from_str(s) { + ($key_name:ident = $json_name:expr, LinkerFlavor) => ( { + let name = $json_name; + obj.remove(name).and_then(|o| o.as_str().and_then(|s| { + match LinkerFlavorCli::from_str(s) { Some(linker_flavor) => base.$key_name = linker_flavor, _ => return Some(Err(format!("'{}' is not a valid value for linker-flavor. \ - Use {}", s, LinkerFlavor::one_of()))), + Use {}", s, LinkerFlavorCli::one_of()))), } Some(Ok(())) })).unwrap_or(Ok(())) @@ -2106,14 +2190,14 @@ impl Target { base.$key_name = args; } } ); - ($key_name:ident, link_args) => ( { - let name = (stringify!($key_name)).replace("_", "-"); - if let Some(val) = obj.remove(&name) { + ($key_name:ident = $json_name:expr, link_args) => ( { + let name = $json_name; + if let Some(val) = obj.remove(name) { let obj = val.as_object().ok_or_else(|| format!("{}: expected a \ JSON object with fields per linker-flavor.", name))?; - let mut args = LinkArgs::new(); + let mut args = LinkArgsCli::new(); for (k, v) in obj { - let flavor = LinkerFlavor::from_str(&k).ok_or_else(|| { + let flavor = LinkerFlavorCli::from_str(&k).ok_or_else(|| { format!("{}: '{}' is not a valid value for linker-flavor. \ Use 'em', 'gcc', 'ld' or 'msvc'", name, k) })?; @@ -2199,7 +2283,7 @@ impl Target { key!(env); key!(abi); key!(vendor); - key!(linker_flavor, LinkerFlavor)?; + key!(linker_flavor_json = "linker-flavor", LinkerFlavor)?; key!(linker, optional); key!(lld_flavor, LldFlavor)?; key!(pre_link_objects = "pre-link-objects", link_objects); @@ -2207,11 +2291,11 @@ impl Target { key!(pre_link_objects_self_contained = "pre-link-objects-fallback", link_objects); key!(post_link_objects_self_contained = "post-link-objects-fallback", link_objects); key!(link_self_contained = "crt-objects-fallback", link_self_contained)?; - key!(pre_link_args, link_args); - key!(late_link_args, link_args); - key!(late_link_args_dynamic, link_args); - key!(late_link_args_static, link_args); - key!(post_link_args, link_args); + key!(pre_link_args_json = "pre-link-args", link_args); + key!(late_link_args_json = "late-link-args", link_args); + key!(late_link_args_dynamic_json = "late-link-args-dynamic", link_args); + key!(late_link_args_static_json = "late-link-args-static", link_args); + key!(post_link_args_json = "post-link-args", link_args); key!(link_script, optional); key!(link_env, env); key!(link_env_remove, list); @@ -2296,6 +2380,8 @@ impl Target { // This can cause unfortunate ICEs later down the line. return Err("may not set is_builtin for targets not built-in".into()); } + base.update_from_cli(); + // Each field should have been read using `Json::remove` so any keys remaining are unused. let remaining_keys = obj.keys(); Ok(( @@ -2387,42 +2473,44 @@ impl ToJson for Target { fn to_json(&self) -> Json { let mut d = serde_json::Map::new(); let default: TargetOptions = Default::default(); + let mut target = self.clone(); + target.update_to_cli(); macro_rules! target_val { ($attr:ident) => {{ let name = (stringify!($attr)).replace("_", "-"); - d.insert(name, self.$attr.to_json()); + d.insert(name, target.$attr.to_json()); }}; } macro_rules! target_option_val { ($attr:ident) => {{ let name = (stringify!($attr)).replace("_", "-"); - if default.$attr != self.$attr { - d.insert(name, self.$attr.to_json()); + if default.$attr != target.$attr { + d.insert(name, target.$attr.to_json()); } }}; - ($attr:ident, $key_name:expr) => {{ - let name = $key_name; - if default.$attr != self.$attr { - d.insert(name.into(), self.$attr.to_json()); + ($attr:ident, $json_name:expr) => {{ + let name = $json_name; + if default.$attr != target.$attr { + d.insert(name.into(), target.$attr.to_json()); } }}; - (link_args - $attr:ident) => {{ - let name = (stringify!($attr)).replace("_", "-"); - if default.$attr != self.$attr { - let obj = self + (link_args - $attr:ident, $json_name:expr) => {{ + let name = $json_name; + if default.$attr != target.$attr { + let obj = target .$attr .iter() .map(|(k, v)| (k.desc().to_string(), v.clone())) .collect::>(); - d.insert(name, obj.to_json()); + d.insert(name.to_string(), obj.to_json()); } }}; (env - $attr:ident) => {{ let name = (stringify!($attr)).replace("_", "-"); - if default.$attr != self.$attr { - let obj = self + if default.$attr != target.$attr { + let obj = target .$attr .iter() .map(|&(ref k, ref v)| format!("{k}={v}")) @@ -2444,7 +2532,7 @@ impl ToJson for Target { target_option_val!(env); target_option_val!(abi); target_option_val!(vendor); - target_option_val!(linker_flavor); + target_option_val!(linker_flavor_json, "linker-flavor"); target_option_val!(linker); target_option_val!(lld_flavor); target_option_val!(pre_link_objects); @@ -2452,11 +2540,11 @@ impl ToJson for Target { target_option_val!(pre_link_objects_self_contained, "pre-link-objects-fallback"); target_option_val!(post_link_objects_self_contained, "post-link-objects-fallback"); target_option_val!(link_self_contained, "crt-objects-fallback"); - target_option_val!(link_args - pre_link_args); - target_option_val!(link_args - late_link_args); - target_option_val!(link_args - late_link_args_dynamic); - target_option_val!(link_args - late_link_args_static); - target_option_val!(link_args - post_link_args); + target_option_val!(link_args - pre_link_args_json, "pre-link-args"); + target_option_val!(link_args - late_link_args_json, "late-link-args"); + target_option_val!(link_args - late_link_args_dynamic_json, "late-link-args-dynamic"); + target_option_val!(link_args - late_link_args_static_json, "late-link-args-static"); + target_option_val!(link_args - post_link_args_json, "post-link-args"); target_option_val!(link_script); target_option_val!(env - link_env); target_option_val!(link_env_remove); diff --git a/compiler/rustc_target/src/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs index 4a53b9c173d1..244f82624285 100644 --- a/compiler/rustc_target/src/spec/tests/tests_impl.rs +++ b/compiler/rustc_target/src/spec/tests/tests_impl.rs @@ -2,9 +2,11 @@ use super::super::*; use std::assert_matches::assert_matches; // Test target self-consistency and JSON encoding/decoding roundtrip. -pub(super) fn test_target(target: Target, triple: &str) { +pub(super) fn test_target(mut target: Target, triple: &str) { + let recycled_target = Target::from_json(target.to_json()).map(|(j, _)| j); + target.update_to_cli(); target.check_consistency(triple); - assert_eq!(Target::from_json(target.to_json()).map(|(j, _)| j), Ok(target)); + assert_eq!(recycled_target, Ok(target)); } impl Target { From a0e21ff10506dc83deb5ef90c8bf3b308ae5b2b8 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 15 Aug 2022 00:31:31 +0300 Subject: [PATCH 4042/5092] rustc_target: Refactor internal linker flavors slightly Remove one unstable user-facing linker flavor (l4-bender) --- compiler/rustc_codegen_ssa/src/back/link.rs | 27 +++-- compiler/rustc_codegen_ssa/src/back/linker.rs | 21 ++-- compiler/rustc_interface/src/tests.rs | 8 +- compiler/rustc_session/src/config.rs | 14 +-- .../src/spec/asmjs_unknown_emscripten.rs | 2 +- compiler/rustc_target/src/spec/bpf_base.rs | 2 +- compiler/rustc_target/src/spec/l4re_base.rs | 2 +- compiler/rustc_target/src/spec/mod.rs | 110 ++++++++---------- .../src/spec/nvptx64_nvidia_cuda.rs | 2 +- .../rustc_target/src/spec/tests/tests_impl.rs | 22 ++-- .../src/spec/wasm32_unknown_emscripten.rs | 4 +- 11 files changed, 93 insertions(+), 121 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index efad767edef2..1ebe5bac203d 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1173,13 +1173,6 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { // only the linker flavor is known; use the default linker for the selected flavor (None, Some(flavor)) => Some(( PathBuf::from(match flavor { - LinkerFlavor::Em => { - if cfg!(windows) { - "emcc.bat" - } else { - "emcc" - } - } LinkerFlavor::Gcc => { if cfg!(any(target_os = "solaris", target_os = "illumos")) { // On historical Solaris systems, "cc" may have @@ -1194,11 +1187,17 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { } } LinkerFlavor::Ld => "ld", - LinkerFlavor::Msvc => "link.exe", LinkerFlavor::Lld(_) => "lld", - LinkerFlavor::PtxLinker => "rust-ptx-linker", - LinkerFlavor::BpfLinker => "bpf-linker", - LinkerFlavor::L4Bender => "l4-bender", + LinkerFlavor::Msvc => "link.exe", + LinkerFlavor::EmCc => { + if cfg!(windows) { + "emcc.bat" + } else { + "emcc" + } + } + LinkerFlavor::Bpf => "bpf-linker", + LinkerFlavor::Ptx => "rust-ptx-linker", }), flavor, )), @@ -1208,7 +1207,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { }); let flavor = if stem == "emcc" { - LinkerFlavor::Em + LinkerFlavor::EmCc } else if stem == "gcc" || stem.ends_with("-gcc") || stem == "clang" @@ -2114,11 +2113,11 @@ fn add_order_independent_options( }); } - if flavor == LinkerFlavor::PtxLinker { + if flavor == LinkerFlavor::Ptx { // Provide the linker with fallback to internal `target-cpu`. cmd.arg("--fallback-arch"); cmd.arg(&codegen_results.crate_info.target_cpu); - } else if flavor == LinkerFlavor::BpfLinker { + } else if flavor == LinkerFlavor::Bpf { cmd.arg("--cpu"); cmd.arg(&codegen_results.crate_info.target_cpu); cmd.arg("--cpu-features"); diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index ce51b2e9531f..8c6f526b054b 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -126,29 +126,26 @@ pub fn get_linker<'a>( // to the linker args construction. assert!(cmd.get_args().is_empty() || sess.target.vendor == "uwp"); match flavor { - LinkerFlavor::Lld(LldFlavor::Link) | LinkerFlavor::Msvc => { - Box::new(MsvcLinker { cmd, sess }) as Box - } - LinkerFlavor::Em => Box::new(EmLinker { cmd, sess }) as Box, LinkerFlavor::Gcc => { Box::new(GccLinker { cmd, sess, target_cpu, hinted_static: false, is_ld: false }) as Box } - + LinkerFlavor::Ld if sess.target.os == "l4re" => { + Box::new(L4Bender::new(cmd, sess)) as Box + } LinkerFlavor::Lld(LldFlavor::Ld) | LinkerFlavor::Lld(LldFlavor::Ld64) | LinkerFlavor::Ld => { Box::new(GccLinker { cmd, sess, target_cpu, hinted_static: false, is_ld: true }) as Box } - + LinkerFlavor::Lld(LldFlavor::Link) | LinkerFlavor::Msvc => { + Box::new(MsvcLinker { cmd, sess }) as Box + } LinkerFlavor::Lld(LldFlavor::Wasm) => Box::new(WasmLd::new(cmd, sess)) as Box, - - LinkerFlavor::PtxLinker => Box::new(PtxLinker { cmd, sess }) as Box, - - LinkerFlavor::BpfLinker => Box::new(BpfLinker { cmd, sess }) as Box, - - LinkerFlavor::L4Bender => Box::new(L4Bender::new(cmd, sess)) as Box, + LinkerFlavor::EmCc => Box::new(EmLinker { cmd, sess }) as Box, + LinkerFlavor::Bpf => Box::new(BpfLinker { cmd, sess }) as Box, + LinkerFlavor::Ptx => Box::new(PtxLinker { cmd, sess }) as Box, } } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 9207a0488623..5df5ab3ddc03 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -21,10 +21,8 @@ use rustc_session::{build_session, getopts, DiagnosticOutput, Session}; use rustc_span::edition::{Edition, DEFAULT_EDITION}; use rustc_span::symbol::sym; use rustc_span::SourceFileHashAlgorithm; -use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy}; -use rustc_target::spec::{ - RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel, -}; +use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, RelocModel}; +use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TlsModel}; use std::collections::{BTreeMap, BTreeSet}; use std::iter::FromIterator; @@ -552,7 +550,7 @@ fn test_codegen_options_tracking_hash() { untracked!(link_args, vec![String::from("abc"), String::from("def")]); untracked!(link_self_contained, Some(true)); untracked!(linker, Some(PathBuf::from("linker"))); - untracked!(linker_flavor, Some(LinkerFlavor::Gcc)); + untracked!(linker_flavor, Some(LinkerFlavorCli::Gcc)); untracked!(no_stack_check, true); untracked!(remark, Passes::Some(vec![String::from("pass1"), String::from("pass2")])); untracked!(rpath, true); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index c894b20e1a7d..c1c064352d06 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -12,8 +12,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::ToStableHashKey; use rustc_target::abi::{Align, TargetDataLayout}; -use rustc_target::spec::{LinkerFlavorCli, SplitDebuginfo, Target, TargetTriple, TargetWarnings}; -use rustc_target::spec::{PanicStrategy, SanitizerSet, TARGETS}; +use rustc_target::spec::{PanicStrategy, SanitizerSet, SplitDebuginfo}; +use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS}; use crate::parse::{CrateCheckConfig, CrateConfig}; use rustc_feature::UnstableFeatures; @@ -2379,16 +2379,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { } } - if cg.linker_flavor == Some(LinkerFlavorCli::L4Bender) - && !nightly_options::is_unstable_enabled(matches) - { - early_error( - error_format, - "`l4-bender` linker flavor is unstable, `-Z unstable-options` \ - flag must also be passed to explicitly use it", - ); - } - let prints = collect_print_requests(&mut cg, &mut unstable_opts, matches, error_format); let cg = cg; diff --git a/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs b/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs index b4cf2c5ee229..f492c3451a41 100644 --- a/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs +++ b/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs @@ -2,6 +2,6 @@ use super::{wasm32_unknown_emscripten, LinkerFlavor, Target}; pub fn target() -> Target { let mut target = wasm32_unknown_emscripten::target(); - target.add_post_link_args(LinkerFlavor::Em, &["-sWASM=0", "--memory-init-file", "0"]); + target.add_post_link_args(LinkerFlavor::EmCc, &["-sWASM=0", "--memory-init-file", "0"]); target } diff --git a/compiler/rustc_target/src/spec/bpf_base.rs b/compiler/rustc_target/src/spec/bpf_base.rs index 3c4da6f883d9..baf36587147a 100644 --- a/compiler/rustc_target/src/spec/bpf_base.rs +++ b/compiler/rustc_target/src/spec/bpf_base.rs @@ -5,7 +5,7 @@ pub fn opts(endian: Endian) -> TargetOptions { TargetOptions { allow_asm: true, endian, - linker_flavor: LinkerFlavor::BpfLinker, + linker_flavor: LinkerFlavor::Bpf, atomic_cas: false, dynamic_linking: true, no_builtins: true, diff --git a/compiler/rustc_target/src/spec/l4re_base.rs b/compiler/rustc_target/src/spec/l4re_base.rs index cab4dd333d43..b7bc1072bf32 100644 --- a/compiler/rustc_target/src/spec/l4re_base.rs +++ b/compiler/rustc_target/src/spec/l4re_base.rs @@ -4,7 +4,7 @@ pub fn opts() -> TargetOptions { TargetOptions { os: "l4re".into(), env: "uclibc".into(), - linker_flavor: LinkerFlavor::L4Bender, + linker_flavor: LinkerFlavor::Ld, panic_strategy: PanicStrategy::Abort, linker: Some("l4-bender".into()), linker_is_gnu: false, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 168fd154cf00..47eb5fc6a1dc 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -92,26 +92,24 @@ mod windows_uwp_msvc_base; #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] pub enum LinkerFlavor { - Em, Gcc, - L4Bender, Ld, - Msvc, Lld(LldFlavor), - PtxLinker, - BpfLinker, + Msvc, + EmCc, + Bpf, + Ptx, } #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] pub enum LinkerFlavorCli { - Em, Gcc, - L4Bender, Ld, - Msvc, Lld(LldFlavor), - PtxLinker, + Msvc, + Em, BpfLinker, + PtxLinker, } #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] @@ -152,39 +150,37 @@ impl ToJson for LldFlavor { impl LinkerFlavor { pub fn from_cli(cli: LinkerFlavorCli) -> LinkerFlavor { match cli { - LinkerFlavorCli::Em => LinkerFlavor::Em, LinkerFlavorCli::Gcc => LinkerFlavor::Gcc, - LinkerFlavorCli::L4Bender => LinkerFlavor::L4Bender, LinkerFlavorCli::Ld => LinkerFlavor::Ld, - LinkerFlavorCli::Msvc => LinkerFlavor::Msvc, LinkerFlavorCli::Lld(lld_flavor) => LinkerFlavor::Lld(lld_flavor), - LinkerFlavorCli::PtxLinker => LinkerFlavor::PtxLinker, - LinkerFlavorCli::BpfLinker => LinkerFlavor::BpfLinker, + LinkerFlavorCli::Msvc => LinkerFlavor::Msvc, + LinkerFlavorCli::Em => LinkerFlavor::EmCc, + LinkerFlavorCli::BpfLinker => LinkerFlavor::Bpf, + LinkerFlavorCli::PtxLinker => LinkerFlavor::Ptx, } } fn to_cli(self) -> LinkerFlavorCli { match self { - LinkerFlavor::Em => LinkerFlavorCli::Em, LinkerFlavor::Gcc => LinkerFlavorCli::Gcc, - LinkerFlavor::L4Bender => LinkerFlavorCli::L4Bender, LinkerFlavor::Ld => LinkerFlavorCli::Ld, - LinkerFlavor::Msvc => LinkerFlavorCli::Msvc, LinkerFlavor::Lld(lld_flavor) => LinkerFlavorCli::Lld(lld_flavor), - LinkerFlavor::PtxLinker => LinkerFlavorCli::PtxLinker, - LinkerFlavor::BpfLinker => LinkerFlavorCli::BpfLinker, + LinkerFlavor::Msvc => LinkerFlavorCli::Msvc, + LinkerFlavor::EmCc => LinkerFlavorCli::Em, + LinkerFlavor::Bpf => LinkerFlavorCli::BpfLinker, + LinkerFlavor::Ptx => LinkerFlavorCli::PtxLinker, } } } -macro_rules! flavor_mappings { - ($((($($flavor:tt)*), $string:expr),)*) => ( +macro_rules! linker_flavor_cli_impls { + ($(($($flavor:tt)*) $string:literal)*) => ( impl LinkerFlavorCli { pub const fn one_of() -> &'static str { concat!("one of: ", $($string, " ",)*) } - pub fn from_str(s: &str) -> Option { + pub fn from_str(s: &str) -> Option { Some(match s { $($string => $($flavor)*,)* _ => return None, @@ -200,18 +196,17 @@ macro_rules! flavor_mappings { ) } -flavor_mappings! { - ((LinkerFlavorCli::Em), "em"), - ((LinkerFlavorCli::Gcc), "gcc"), - ((LinkerFlavorCli::L4Bender), "l4-bender"), - ((LinkerFlavorCli::Ld), "ld"), - ((LinkerFlavorCli::Msvc), "msvc"), - ((LinkerFlavorCli::PtxLinker), "ptx-linker"), - ((LinkerFlavorCli::BpfLinker), "bpf-linker"), - ((LinkerFlavorCli::Lld(LldFlavor::Wasm)), "wasm-ld"), - ((LinkerFlavorCli::Lld(LldFlavor::Ld64)), "ld64.lld"), - ((LinkerFlavorCli::Lld(LldFlavor::Ld)), "ld.lld"), - ((LinkerFlavorCli::Lld(LldFlavor::Link)), "lld-link"), +linker_flavor_cli_impls! { + (LinkerFlavorCli::Gcc) "gcc" + (LinkerFlavorCli::Ld) "ld" + (LinkerFlavorCli::Lld(LldFlavor::Ld)) "ld.lld" + (LinkerFlavorCli::Lld(LldFlavor::Ld64)) "ld64.lld" + (LinkerFlavorCli::Lld(LldFlavor::Link)) "lld-link" + (LinkerFlavorCli::Lld(LldFlavor::Wasm)) "wasm-ld" + (LinkerFlavorCli::Msvc) "msvc" + (LinkerFlavorCli::Em) "em" + (LinkerFlavorCli::BpfLinker) "bpf-linker" + (LinkerFlavorCli::PtxLinker) "ptx-linker" } impl ToJson for LinkerFlavorCli { @@ -1252,21 +1247,21 @@ pub struct TargetOptions { pub abi: StaticCow, /// Vendor name to use for conditional compilation (`target_vendor`). Defaults to "unknown". pub vendor: StaticCow, + + /// Linker to invoke + pub linker: Option>, /// Default linker flavor used if `-C linker-flavor` or `-C linker` are not passed /// on the command line. Defaults to `LinkerFlavor::Gcc`. pub linker_flavor: LinkerFlavor, linker_flavor_json: LinkerFlavorCli, - - /// Linker to invoke - pub linker: Option>, - /// LLD flavor used if `lld` (or `rust-lld`) is specified as a linker /// without clarifying its flavor in any way. + /// FIXME: Merge this into `LinkerFlavor`. pub lld_flavor: LldFlavor, + /// Whether the linker support GNU-like arguments such as -O. Defaults to true. + /// FIXME: Merge this into `LinkerFlavor`. + pub linker_is_gnu: bool, - /// Linker arguments that are passed *before* any user-defined libraries. - pub pre_link_args: LinkArgs, - pre_link_args_json: LinkArgsCli, /// Objects to link before and after all other object code. pub pre_link_objects: CrtObjects, pub post_link_objects: CrtObjects, @@ -1275,6 +1270,9 @@ pub struct TargetOptions { pub post_link_objects_self_contained: CrtObjects, pub link_self_contained: LinkSelfContainedDefault, + /// Linker arguments that are passed *before* any user-defined libraries. + pub pre_link_args: LinkArgs, + pre_link_args_json: LinkArgsCli, /// Linker arguments that are unconditionally passed after any /// user-defined but before post-link objects. Standard platform /// libraries that should be always be linked to, usually go here. @@ -1292,11 +1290,11 @@ pub struct TargetOptions { /// user-defined libraries. pub post_link_args: LinkArgs, post_link_args_json: LinkArgsCli, + /// Optional link script applied to `dylib` and `executable` crate types. /// This is a string containing the script, not a path. Can only be applied /// to linkers where `linker_is_gnu` is true. pub link_script: Option>, - /// Environment variables to be set for the linker invocation. pub link_env: StaticCow<[(StaticCow, StaticCow)]>, /// Environment variables to be removed for the linker invocation. @@ -1381,8 +1379,6 @@ pub struct TargetOptions { /// Default supported version of DWARF on this platform. /// Useful because some platforms (osx, bsd) only want up to DWARF2. pub default_dwarf_version: u32, - /// Whether the linker support GNU-like arguments such as -O. Defaults to true. - pub linker_is_gnu: bool, /// The MinGW toolchain has a known issue that prevents it from correctly /// handling COFF object files with more than 215 sections. Since each weak /// symbol needs its own COMDAT section, weak linkage implies a large @@ -1580,11 +1576,7 @@ fn add_link_args(link_args: &mut LinkArgs, flavor: LinkerFlavor, args: &[&'stati LinkerFlavor::Lld(lld_flavor) => { panic!("add_link_args: use non-LLD flavor for {:?}", lld_flavor) } - LinkerFlavor::Gcc - | LinkerFlavor::Em - | LinkerFlavor::L4Bender - | LinkerFlavor::BpfLinker - | LinkerFlavor::PtxLinker => {} + LinkerFlavor::Gcc | LinkerFlavor::EmCc | LinkerFlavor::Bpf | LinkerFlavor::Ptx => {} } } @@ -1646,14 +1638,11 @@ impl Default for TargetOptions { env: "".into(), abi: "".into(), vendor: "unknown".into(), + linker: option_env!("CFG_DEFAULT_LINKER").map(|s| s.into()), linker_flavor: LinkerFlavor::Gcc, linker_flavor_json: LinkerFlavorCli::Gcc, - linker: option_env!("CFG_DEFAULT_LINKER").map(|s| s.into()), lld_flavor: LldFlavor::Ld, - pre_link_args: LinkArgs::new(), - pre_link_args_json: LinkArgsCli::new(), - post_link_args: LinkArgs::new(), - post_link_args_json: LinkArgsCli::new(), + linker_is_gnu: true, link_script: None, asm_args: cvs![], cpu: "generic".into(), @@ -1680,7 +1669,6 @@ impl Default for TargetOptions { is_like_msvc: false, is_like_wasm: false, default_dwarf_version: 4, - linker_is_gnu: true, allows_weak_linkage: true, has_rpath: false, no_default_libraries: true, @@ -1693,12 +1681,16 @@ impl Default for TargetOptions { pre_link_objects_self_contained: Default::default(), post_link_objects_self_contained: Default::default(), link_self_contained: LinkSelfContainedDefault::False, + pre_link_args: LinkArgs::new(), + pre_link_args_json: LinkArgsCli::new(), late_link_args: LinkArgs::new(), late_link_args_json: LinkArgsCli::new(), late_link_args_dynamic: LinkArgs::new(), late_link_args_dynamic_json: LinkArgsCli::new(), late_link_args_static: LinkArgs::new(), late_link_args_static_json: LinkArgsCli::new(), + post_link_args: LinkArgs::new(), + post_link_args_json: LinkArgsCli::new(), link_env: cvs![], link_env_remove: cvs![], archive_format: "gnu".into(), @@ -2283,9 +2275,10 @@ impl Target { key!(env); key!(abi); key!(vendor); - key!(linker_flavor_json = "linker-flavor", LinkerFlavor)?; key!(linker, optional); + key!(linker_flavor_json = "linker-flavor", LinkerFlavor)?; key!(lld_flavor, LldFlavor)?; + key!(linker_is_gnu, bool); key!(pre_link_objects = "pre-link-objects", link_objects); key!(post_link_objects = "post-link-objects", link_objects); key!(pre_link_objects_self_contained = "pre-link-objects-fallback", link_objects); @@ -2323,7 +2316,6 @@ impl Target { key!(is_like_msvc, bool); key!(is_like_wasm, bool); key!(default_dwarf_version, u32); - key!(linker_is_gnu, bool); key!(allows_weak_linkage, bool); key!(has_rpath, bool); key!(no_default_libraries, bool); @@ -2532,9 +2524,10 @@ impl ToJson for Target { target_option_val!(env); target_option_val!(abi); target_option_val!(vendor); - target_option_val!(linker_flavor_json, "linker-flavor"); target_option_val!(linker); + target_option_val!(linker_flavor_json, "linker-flavor"); target_option_val!(lld_flavor); + target_option_val!(linker_is_gnu); target_option_val!(pre_link_objects); target_option_val!(post_link_objects); target_option_val!(pre_link_objects_self_contained, "pre-link-objects-fallback"); @@ -2573,7 +2566,6 @@ impl ToJson for Target { target_option_val!(is_like_msvc); target_option_val!(is_like_wasm); target_option_val!(default_dwarf_version); - target_option_val!(linker_is_gnu); target_option_val!(allows_weak_linkage); target_option_val!(has_rpath); target_option_val!(no_default_libraries); diff --git a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs index 1c5b68001b95..6ab3a8b7eb5a 100644 --- a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs +++ b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { options: TargetOptions { os: "cuda".into(), vendor: "nvidia".into(), - linker_flavor: LinkerFlavor::PtxLinker, + linker_flavor: LinkerFlavor::Ptx, // The linker can be installed from `crates.io`. linker: Some("rust-ptx-linker".into()), linker_is_gnu: false, diff --git a/compiler/rustc_target/src/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs index 244f82624285..d03f959076de 100644 --- a/compiler/rustc_target/src/spec/tests/tests_impl.rs +++ b/compiler/rustc_target/src/spec/tests/tests_impl.rs @@ -24,10 +24,9 @@ impl Target { assert_eq!(self.is_like_osx, matches!(self.lld_flavor, LldFlavor::Ld64)); assert_eq!(self.is_like_msvc, matches!(self.lld_flavor, LldFlavor::Link)); assert_eq!(self.is_like_wasm, matches!(self.lld_flavor, LldFlavor::Wasm)); - assert_eq!(self.os == "l4re", matches!(self.linker_flavor, LinkerFlavor::L4Bender)); - assert_eq!(self.os == "emscripten", matches!(self.linker_flavor, LinkerFlavor::Em)); - assert_eq!(self.arch == "bpf", matches!(self.linker_flavor, LinkerFlavor::BpfLinker)); - assert_eq!(self.arch == "nvptx64", matches!(self.linker_flavor, LinkerFlavor::PtxLinker)); + assert_eq!(self.os == "emscripten", matches!(self.linker_flavor, LinkerFlavor::EmCc)); + assert_eq!(self.arch == "bpf", matches!(self.linker_flavor, LinkerFlavor::Bpf)); + assert_eq!(self.arch == "nvptx64", matches!(self.linker_flavor, LinkerFlavor::Ptx)); for args in [ &self.pre_link_args, @@ -67,17 +66,14 @@ impl Target { LinkerFlavor::Lld(LldFlavor::Wasm) | LinkerFlavor::Gcc ) } - (LinkerFlavor::L4Bender, LldFlavor::Ld) => { - assert_matches!(flavor, LinkerFlavor::L4Bender) + (LinkerFlavor::EmCc, LldFlavor::Wasm) => { + assert_matches!(flavor, LinkerFlavor::EmCc) } - (LinkerFlavor::Em, LldFlavor::Wasm) => { - assert_matches!(flavor, LinkerFlavor::Em) + (LinkerFlavor::Bpf, LldFlavor::Ld) => { + assert_matches!(flavor, LinkerFlavor::Bpf) } - (LinkerFlavor::BpfLinker, LldFlavor::Ld) => { - assert_matches!(flavor, LinkerFlavor::BpfLinker) - } - (LinkerFlavor::PtxLinker, LldFlavor::Ld) => { - assert_matches!(flavor, LinkerFlavor::PtxLinker) + (LinkerFlavor::Ptx, LldFlavor::Ld) => { + assert_matches!(flavor, LinkerFlavor::Ptx) } flavors => unreachable!("unexpected flavor combination: {:?}", flavors), } diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs index c7e7d2210865..6f77ef98c015 100644 --- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs +++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs @@ -5,13 +5,13 @@ pub fn target() -> Target { // Reset flags for non-Em flavors back to empty to satisfy sanity checking tests. let pre_link_args = LinkArgs::new(); let post_link_args = TargetOptions::link_args( - LinkerFlavor::Em, + LinkerFlavor::EmCc, &["-sABORTING_MALLOC=0", "-Wl,--fatal-warnings"], ); let opts = TargetOptions { os: "emscripten".into(), - linker_flavor: LinkerFlavor::Em, + linker_flavor: LinkerFlavor::EmCc, // emcc emits two files - a .js file to instantiate the wasm and supply platform // functionality, and a .wasm file. exe_suffix: ".js".into(), From 78e9bea598a1e9a87236e9bf437baa8f9ecb8294 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Thu, 1 Sep 2022 23:50:51 +0900 Subject: [PATCH 4043/5092] do not suggest adding `move` to closure when `move` is already used --- .../src/diagnostics/region_errors.rs | 14 +++++++++++--- ...e-when-closure-is-already-marked-as-move.rs | 8 ++++++++ ...en-closure-is-already-marked-as-move.stderr | 18 ++++++++++++++++++ 3 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.rs create mode 100644 src/test/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 00fdf331ca60..082dd8690235 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -902,7 +902,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { hir::ExprKind::MethodCall(.., args, _) => { // only the first closre parameter of the method. args[0] is MethodCall PathSegment for i in 1..args.len() { - if let hir::ExprKind::Closure(..) = args[i].kind { + if let hir::ExprKind::Closure(hir::Closure { + capture_clause: hir::CaptureBy::Ref, + .. + }) = args[i].kind + { closure_span = Some(args[i].span.shrink_to_lo()); break; } @@ -911,7 +915,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { hir::ExprKind::Block(blk, _) => { if let Some(ref expr) = blk.expr { // only when the block is a closure - if let hir::ExprKind::Closure(..) = expr.kind { + if let hir::ExprKind::Closure(hir::Closure { + capture_clause: hir::CaptureBy::Ref, + .. + }) = expr.kind + { closure_span = Some(expr.span.shrink_to_lo()); } } @@ -921,7 +929,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if let Some(closure_span) = closure_span { diag.span_suggestion_verbose( closure_span, - format!("consider adding 'move' keyword before the nested closure"), + "consider adding 'move' keyword before the nested closure", "move ", Applicability::MaybeIncorrect, ); diff --git a/src/test/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.rs b/src/test/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.rs new file mode 100644 index 000000000000..524459291f85 --- /dev/null +++ b/src/test/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.rs @@ -0,0 +1,8 @@ +fn main() { + let mut vec: Vec = Vec::new(); + let closure = move || { + vec.clear(); + let mut iter = vec.iter(); + move || { iter.next() } //~ ERROR captured variable cannot escape `FnMut` closure bod + }; +} diff --git a/src/test/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.stderr b/src/test/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.stderr new file mode 100644 index 000000000000..78ca090feb72 --- /dev/null +++ b/src/test/ui/borrowck/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.stderr @@ -0,0 +1,18 @@ +error: captured variable cannot escape `FnMut` closure body + --> $DIR/do-not-suggest-adding-move-when-closure-is-already-marked-as-move.rs:6:9 + | +LL | let mut vec: Vec = Vec::new(); + | ------- variable defined here +LL | let closure = move || { + | - inferred to be a `FnMut` closure +LL | vec.clear(); + | --- variable captured here +LL | let mut iter = vec.iter(); +LL | move || { iter.next() } + | ^^^^^^^^^^^^^^^^^^^^^^^ returns a closure that contains a reference to a captured variable, which then escapes the closure body + | + = note: `FnMut` closures only have access to their captured variables while they are executing... + = note: ...therefore, they cannot allow references to captured variables to escape + +error: aborting due to previous error + From d3b22c726721639c1ab104a8ff8b3a17fd5e99d7 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 31 Aug 2022 13:01:10 +0000 Subject: [PATCH 4044/5092] Directly use the `instrument` macro instead of its full path --- compiler/rustc_ast_lowering/src/index.rs | 12 +++++------ compiler/rustc_ast_lowering/src/lib.rs | 18 ++++++++--------- .../src/diagnostics/region_name.rs | 10 +++++----- .../src/debuginfo/metadata.rs | 2 -- compiler/rustc_codegen_llvm/src/lib.rs | 2 ++ .../rustc_const_eval/src/interpret/intern.rs | 2 +- compiler/rustc_infer/src/infer/combine.rs | 4 ++-- .../src/infer/error_reporting/mod.rs | 2 +- .../src/infer/outlives/obligations.rs | 2 +- .../src/infer/outlives/test_type_match.rs | 6 +++--- .../rustc_mir_build/src/build/matches/mod.rs | 2 +- compiler/rustc_mir_build/src/thir/cx/mod.rs | 2 +- compiler/rustc_passes/src/liveness.rs | 2 +- compiler/rustc_resolve/src/ident.rs | 20 +++++++++---------- compiler/rustc_resolve/src/late.rs | 18 ++++++++--------- compiler/rustc_resolve/src/late/lifetimes.rs | 16 +++++++-------- .../src/traits/fulfill.rs | 2 +- .../src/traits/project.rs | 8 ++++---- .../src/traits/select/candidate_assembly.rs | 10 +++++----- .../src/traits/select/mod.rs | 4 ++-- compiler/rustc_typeck/src/astconv/mod.rs | 17 +++++++--------- .../rustc_typeck/src/check/compare_method.rs | 2 +- compiler/rustc_typeck/src/check/demand.rs | 2 +- .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 2 +- compiler/rustc_typeck/src/check/wfcheck.rs | 8 ++++---- 25 files changed, 86 insertions(+), 89 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 2b7431f09905..a0547497b192 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -31,7 +31,7 @@ pub(super) struct NodeCollector<'a, 'hir> { definitions: &'a definitions::Definitions, } -#[tracing::instrument(level = "debug", skip(sess, definitions, bodies))] +#[instrument(level = "debug", skip(sess, definitions, bodies))] pub(super) fn index_hir<'hir>( sess: &Session, definitions: &definitions::Definitions, @@ -67,7 +67,7 @@ pub(super) fn index_hir<'hir>( } impl<'a, 'hir> NodeCollector<'a, 'hir> { - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) { debug_assert_eq!(self.owner, hir_id.owner); debug_assert_ne!(hir_id.local_id.as_u32(), 0); @@ -142,7 +142,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn visit_item(&mut self, i: &'hir Item<'hir>) { debug_assert_eq!(i.def_id, self.owner); self.with_parent(i.hir_id(), |this| { @@ -156,7 +156,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) { debug_assert_eq!(fi.def_id, self.owner); self.with_parent(fi.hir_id(), |this| { @@ -175,7 +175,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }) } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) { debug_assert_eq!(ti.def_id, self.owner); self.with_parent(ti.hir_id(), |this| { @@ -183,7 +183,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) { debug_assert_eq!(ii.def_id, self.owner); self.with_parent(ii.hir_id(), |this| { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index a5957e2df2e5..9a960356a85f 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -220,7 +220,7 @@ impl ResolverAstLoweringExt for ResolverAstLowering { /// Panics if no map has been pushed. /// Remapping is used when creating lowering `-> impl Trait` return /// types to create the resulting opaque type. - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn record_def_id_remap(&mut self, from: LocalDefId, to: LocalDefId) { self.generics_def_id_map.last_mut().expect("no map pushed").insert(from, to); } @@ -771,7 +771,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } /// Converts a lifetime into a new generic parameter. - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn lifetime_res_to_generic_param( &mut self, ident: Ident, @@ -815,7 +815,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// name resolver owing to lifetime elision; this also populates the resolver's node-id->def-id /// map, so that later calls to `opt_node_id_to_def_id` that refer to these extra lifetime /// parameters will be successful. - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] #[inline] fn lower_lifetime_binder( &mut self, @@ -1385,7 +1385,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// added explicitly in the HIR). But this includes all the lifetimes, and we only want to /// capture the lifetimes that are referenced in the bounds. Therefore, we add *extra* lifetime parameters /// for the lifetimes that get captured (`'x`, in our example above) and reference those. - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn lower_opaque_impl_trait( &mut self, span: Span, @@ -1621,7 +1621,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // `make_ret_async`: if `Some`, converts `-> T` into `-> impl Future` in the // return type. This is used for `async fn` declarations. The `NodeId` is the ID of the // return type `impl Trait` item. - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn lower_fn_decl( &mut self, decl: &FnDecl, @@ -1730,7 +1730,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // `output`: unlowered output type (`T` in `-> T`) // `fn_def_id`: `DefId` of the parent function (used to create child impl trait definition) // `opaque_ty_node_id`: `NodeId` of the opaque `impl Trait` type that should be created - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn lower_async_fn_ret_ty( &mut self, output: &FnRetTy, @@ -2013,7 +2013,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.new_named_lifetime(l.id, l.id, span, ident) } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn new_named_lifetime_with_res( &mut self, id: NodeId, @@ -2044,7 +2044,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::Lifetime { hir_id: self.lower_node_id(id), span: self.lower_span(span), name } } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn new_named_lifetime( &mut self, id: NodeId, @@ -2132,7 +2132,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::TraitRef { path, hir_ref_id: self.lower_node_id(p.ref_id) } } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn lower_poly_trait_ref( &mut self, p: &PolyTraitRef, diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index a87e8bd5ba16..75fde53b6cde 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -265,7 +265,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { /// *user* has a name for. In that case, we'll be able to map /// `fr` to a `Region<'tcx>`, and that region will be one of /// named variants. - #[tracing::instrument(level = "trace", skip(self))] + #[instrument(level = "trace", skip(self))] fn give_name_from_error_region(&self, fr: RegionVid) -> Option { let error_region = self.to_error_region(fr)?; @@ -373,7 +373,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { /// | fn foo(x: &u32) { .. } /// ------- fully elaborated type of `x` is `&'1 u32` /// ``` - #[tracing::instrument(level = "trace", skip(self))] + #[instrument(level = "trace", skip(self))] fn give_name_if_anonymous_region_appears_in_arguments( &self, fr: RegionVid, @@ -662,7 +662,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { /// | let x = Some(&22); /// - fully elaborated type of `x` is `Option<&'1 u32>` /// ``` - #[tracing::instrument(level = "trace", skip(self))] + #[instrument(level = "trace", skip(self))] fn give_name_if_anonymous_region_appears_in_upvars(&self, fr: RegionVid) -> Option { let upvar_index = self.regioncx.get_upvar_index_for_region(self.infcx.tcx, fr)?; let (upvar_name, upvar_span) = self.regioncx.get_upvar_name_and_span_for_region( @@ -682,7 +682,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { /// must be a closure since, in a free fn, such an argument would /// have to either also appear in an argument (if using elision) /// or be early bound (named, not in argument). - #[tracing::instrument(level = "trace", skip(self))] + #[instrument(level = "trace", skip(self))] fn give_name_if_anonymous_region_appears_in_output(&self, fr: RegionVid) -> Option { let tcx = self.infcx.tcx; let hir = tcx.hir(); @@ -814,7 +814,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { } } - #[tracing::instrument(level = "trace", skip(self))] + #[instrument(level = "trace", skip(self))] fn give_name_if_anonymous_region_appears_in_yield_ty( &self, fr: RegionVid, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index d0a6f216858b..163ccd9460c5 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -42,7 +42,6 @@ use rustc_span::{self, FileNameDisplayPreference, SourceFile}; use rustc_symbol_mangling::typeid_for_trait_ref; use rustc_target::abi::{Align, Size}; use smallvec::smallvec; -use tracing::debug; use libc::{c_char, c_longlong, c_uint}; use std::borrow::Cow; @@ -51,7 +50,6 @@ use std::hash::{Hash, Hasher}; use std::iter; use std::path::{Path, PathBuf}; use std::ptr; -use tracing::instrument; impl PartialEq for llvm::Metadata { fn eq(&self, other: &Self) -> bool { diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 636d689a34b5..334425ae55b4 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -16,6 +16,8 @@ #[macro_use] extern crate rustc_macros; +#[macro_use] +extern crate tracing; use back::write::{create_informational_target_machine, create_target_machine}; diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 66ab3f15716f..24dbc769529c 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -334,7 +334,7 @@ pub enum InternKind { /// tracks where in the value we are and thus can show much better error messages. /// Any errors here would anyway be turned into `const_err` lints, whereas validation failures /// are hard errors. -#[tracing::instrument(level = "debug", skip(ecx))] +#[instrument(level = "debug", skip(ecx))] pub fn intern_const_alloc_recursive< 'mir, 'tcx: 'mir, diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 8bf1de34a9b5..99d8f57505c2 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -856,7 +856,7 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?)) } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn tys(&mut self, t: Ty<'tcx>, _t: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { debug_assert_eq!(t, _t); debug!("ConstInferUnifier: t={:?}", t); @@ -932,7 +932,7 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { } } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn consts( &mut self, c: ty::Const<'tcx>, diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 3a6119a62736..6dad9873d613 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1434,7 +1434,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// the message in `secondary_span` as the primary label, and apply the message that would /// otherwise be used for the primary label on the `secondary_span` `Span`. This applies on /// E0271, like `src/test/ui/issues/issue-39970.stderr`. - #[tracing::instrument( + #[instrument( level = "debug", skip(self, diag, secondary_span, swap_secondary_and_primary, prefer_label) )] diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index fe78890ff6ed..74c8bd88d275 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -313,7 +313,7 @@ where self.delegate.push_verify(origin, generic, region, verify_bound); } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn projection_must_outlive( &mut self, origin: infer::SubregionOrigin<'tcx>, diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs index be03c8b5bae9..a5c21f0fb9b5 100644 --- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs +++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs @@ -34,7 +34,7 @@ use crate::infer::region_constraints::VerifyIfEq; /// like are used. This is a particular challenge since this function is invoked /// very late in inference and hence cannot make use of the normal inference /// machinery. -#[tracing::instrument(level = "debug", skip(tcx, param_env))] +#[instrument(level = "debug", skip(tcx, param_env))] pub fn extract_verify_if_eq<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -71,7 +71,7 @@ pub fn extract_verify_if_eq<'tcx>( } /// True if a (potentially higher-ranked) outlives -#[tracing::instrument(level = "debug", skip(tcx, param_env))] +#[instrument(level = "debug", skip(tcx, param_env))] pub(super) fn can_match_erased_ty<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -110,7 +110,7 @@ impl<'tcx> Match<'tcx> { /// Binds the pattern variable `br` to `value`; returns an `Err` if the pattern /// is already bound to a different value. - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn bind( &mut self, br: ty::BoundRegion, diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 2ca6d7628466..0e5cd6199ac9 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -155,7 +155,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// /// * From each pre-binding block to the next pre-binding block. /// * From each otherwise block to the next pre-binding block. - #[tracing::instrument(level = "debug", skip(self, arms))] + #[instrument(level = "debug", skip(self, arms))] pub(crate) fn match_expr( &mut self, destination: Place<'tcx>, diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index f7351a4caa95..b84a84976c7d 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -77,7 +77,7 @@ impl<'tcx> Cx<'tcx> { } } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] pub(crate) fn pattern_from_hir(&mut self, p: &hir::Pat<'_>) -> Pat<'tcx> { let p = match self.tcx.hir().get(p.hir_id) { Node::Pat(p) => p, diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 5b79dd3d3ef2..2a6889af7c2c 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1573,7 +1573,7 @@ impl<'tcx> Liveness<'_, 'tcx> { } } - #[tracing::instrument(skip(self), level = "INFO")] + #[instrument(skip(self), level = "INFO")] fn report_unused( &self, hir_ids_and_spans: Vec<(HirId, Span, Span)>, diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 2afba94d793a..b84a610833dd 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -273,7 +273,7 @@ impl<'a> Resolver<'a> { /// /// Invariant: This must only be called during main resolution, not during /// import resolution. - #[tracing::instrument(level = "debug", skip(self, ribs))] + #[instrument(level = "debug", skip(self, ribs))] pub(crate) fn resolve_ident_in_lexical_scope( &mut self, mut ident: Ident, @@ -367,7 +367,7 @@ impl<'a> Resolver<'a> { /// expansion and import resolution (perhaps they can be merged in the future). /// The function is used for resolving initial segments of macro paths (e.g., `foo` in /// `foo::bar!(); or `foo!();`) and also for import paths on 2018 edition. - #[tracing::instrument(level = "debug", skip(self, scope_set))] + #[instrument(level = "debug", skip(self, scope_set))] pub(crate) fn early_resolve_ident_in_lexical_scope( &mut self, orig_ident: Ident, @@ -708,7 +708,7 @@ impl<'a> Resolver<'a> { Err(Determinacy::determined(determinacy == Determinacy::Determined || force)) } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] pub(crate) fn maybe_resolve_ident_in_module( &mut self, module: ModuleOrUniformRoot<'a>, @@ -720,7 +720,7 @@ impl<'a> Resolver<'a> { .map_err(|(determinacy, _)| determinacy) } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] pub(crate) fn resolve_ident_in_module( &mut self, module: ModuleOrUniformRoot<'a>, @@ -734,7 +734,7 @@ impl<'a> Resolver<'a> { .map_err(|(determinacy, _)| determinacy) } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn resolve_ident_in_module_ext( &mut self, module: ModuleOrUniformRoot<'a>, @@ -772,7 +772,7 @@ impl<'a> Resolver<'a> { ) } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn resolve_ident_in_module_unadjusted( &mut self, module: ModuleOrUniformRoot<'a>, @@ -796,7 +796,7 @@ impl<'a> Resolver<'a> { /// Attempts to resolve `ident` in namespaces `ns` of `module`. /// Invariant: if `finalize` is `Some`, expansion and import resolution must be complete. - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn resolve_ident_in_module_unadjusted_ext( &mut self, module: ModuleOrUniformRoot<'a>, @@ -1059,7 +1059,7 @@ impl<'a> Resolver<'a> { } /// Validate a local resolution (from ribs). - #[tracing::instrument(level = "debug", skip(self, all_ribs))] + #[instrument(level = "debug", skip(self, all_ribs))] fn validate_res_from_ribs( &mut self, rib_index: usize, @@ -1294,7 +1294,7 @@ impl<'a> Resolver<'a> { res } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] pub(crate) fn maybe_resolve_path( &mut self, path: &[Segment], @@ -1304,7 +1304,7 @@ impl<'a> Resolver<'a> { self.resolve_path_with_ribs(path, opt_ns, parent_scope, None, None, None) } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] pub(crate) fn resolve_path( &mut self, path: &[Segment], diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 693ec86616ee..4cdfc6e7a4d7 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1390,7 +1390,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { }) } - #[tracing::instrument(level = "debug", skip(self, work))] + #[instrument(level = "debug", skip(self, work))] fn with_lifetime_rib( &mut self, kind: LifetimeRibKind, @@ -1404,7 +1404,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ret } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn resolve_lifetime(&mut self, lifetime: &'ast Lifetime, use_ctxt: visit::LifetimeCtxt) { let ident = lifetime.ident; @@ -1508,7 +1508,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.record_lifetime_res(lifetime.id, LifetimeRes::Error, LifetimeElisionCandidate::Named); } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn resolve_anonymous_lifetime(&mut self, lifetime: &Lifetime, elided: bool) { debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime); @@ -1573,7 +1573,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.report_missing_lifetime_specifiers(vec![missing_lifetime], None); } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn resolve_elided_lifetime(&mut self, anchor_id: NodeId, span: Span) { let id = self.r.next_node_id(); let lt = Lifetime { id, ident: Ident::new(kw::UnderscoreLifetime, span) }; @@ -1586,7 +1586,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.resolve_anonymous_lifetime(<, true); } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn create_fresh_lifetime(&mut self, id: NodeId, ident: Ident, binder: NodeId) -> LifetimeRes { debug_assert_eq!(ident.name, kw::UnderscoreLifetime); debug!(?ident.span); @@ -1604,7 +1604,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { res } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn resolve_elided_lifetimes_in_path( &mut self, path_id: NodeId, @@ -1804,7 +1804,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn record_lifetime_res( &mut self, id: NodeId, @@ -1827,7 +1827,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn record_lifetime_param(&mut self, id: NodeId, res: LifetimeRes) { if let Some(prev_res) = self.r.lifetimes_res_map.insert(id, res) { panic!( @@ -1838,7 +1838,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } /// Perform resolution of a function signature, accounting for lifetime elision. - #[tracing::instrument(level = "debug", skip(self, inputs))] + #[instrument(level = "debug", skip(self, inputs))] fn resolve_fn_signature( &mut self, fn_id: NodeId, diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 661aadea9444..242dad17ec92 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -278,7 +278,7 @@ pub fn provide(providers: &mut ty::query::Providers) { /// lifetimes into a single binder.) This requires us to resolve the /// *trait definition* of `Sub`; basically just enough lifetime information /// to look at the supertraits. -#[tracing::instrument(level = "debug", skip(tcx))] +#[instrument(level = "debug", skip(tcx))] fn resolve_lifetimes_trait_definition( tcx: TyCtxt<'_>, local_def_id: LocalDefId, @@ -289,7 +289,7 @@ fn resolve_lifetimes_trait_definition( /// Computes the `ResolveLifetimes` map that contains data for an entire `Item`. /// You should not read the result of this query directly, but rather use /// `named_region_map`, `is_late_bound_map`, etc. -#[tracing::instrument(level = "debug", skip(tcx))] +#[instrument(level = "debug", skip(tcx))] fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> ResolveLifetimes { convert_named_region_map(do_resolve(tcx, local_def_id, false)) } @@ -647,7 +647,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { match ty.kind { hir::TyKind::BareFn(ref c) => { @@ -930,7 +930,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { match lifetime_ref.name { hir::LifetimeName::Static => self.insert_lifetime(lifetime_ref, Region::Static), @@ -1287,7 +1287,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { self.with(scope, walk); } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn resolve_lifetime_ref( &mut self, region_def_id: LocalDefId, @@ -1409,7 +1409,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { ); } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn visit_segment_args( &mut self, res: Res, @@ -1659,7 +1659,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn visit_fn_like_elision( &mut self, inputs: &'tcx [hir::Ty<'tcx>], @@ -1707,7 +1707,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth)); } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) { debug!( node = ?self.tcx.hir().node_to_string(lifetime_ref.hir_id), diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index d840677f1ca8..3763a98c488b 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -135,7 +135,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { /// `SomeTrait` or a where-clause that lets us unify `$0` with /// something concrete. If this fails, we'll unify `$0` with /// `projection_ty` again. - #[tracing::instrument(level = "debug", skip(self, infcx, param_env, cause))] + #[instrument(level = "debug", skip(self, infcx, param_env, cause))] fn normalize_projection_type( &mut self, infcx: &InferCtxt<'_, 'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 444ca6471e2e..398635674abc 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -231,7 +231,7 @@ pub(super) fn poly_project_and_unify_type<'cx, 'tcx>( /// If successful, this may result in additional obligations. /// /// See [poly_project_and_unify_type] for an explanation of the return value. -#[tracing::instrument(level = "debug", skip(selcx))] +#[instrument(level = "debug", skip(selcx))] fn project_and_unify_type<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionObligation<'tcx>, @@ -1206,7 +1206,7 @@ impl<'tcx> Progress<'tcx> { /// /// IMPORTANT: /// - `obligation` must be fully normalized -#[tracing::instrument(level = "info", skip(selcx))] +#[instrument(level = "info", skip(selcx))] fn project<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, @@ -1368,7 +1368,7 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>( ); } -#[tracing::instrument( +#[instrument( level = "debug", skip(selcx, candidate_set, ctor, env_predicates, potentially_unnormalized_candidates) )] @@ -1419,7 +1419,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( } } -#[tracing::instrument(level = "debug", skip(selcx, obligation, candidate_set))] +#[instrument(level = "debug", skip(selcx, obligation, candidate_set))] fn assemble_candidates_from_impls<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index d67bd6292b43..cfd9d711894e 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -337,7 +337,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(candidates) } - #[tracing::instrument(level = "debug", skip(self, candidates))] + #[instrument(level = "debug", skip(self, candidates))] fn assemble_candidates_from_projected_tys( &mut self, obligation: &TraitObligation<'tcx>, @@ -367,7 +367,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// supplied to find out whether it is listed among them. /// /// Never affects the inference environment. - #[tracing::instrument(level = "debug", skip(self, stack, candidates))] + #[instrument(level = "debug", skip(self, stack, candidates))] fn assemble_candidates_from_caller_bounds<'o>( &mut self, stack: &TraitObligationStack<'o, 'tcx>, @@ -880,7 +880,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; } - #[tracing::instrument(level = "debug", skip(self, obligation, candidates))] + #[instrument(level = "debug", skip(self, obligation, candidates))] fn assemble_candidates_for_transmutability( &mut self, obligation: &TraitObligation<'tcx>, @@ -898,7 +898,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates.vec.push(TransmutabilityCandidate); } - #[tracing::instrument(level = "debug", skip(self, obligation, candidates))] + #[instrument(level = "debug", skip(self, obligation, candidates))] fn assemble_candidates_for_trait_alias( &mut self, obligation: &TraitObligation<'tcx>, @@ -917,7 +917,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Assembles the trait which are built-in to the language itself: /// `Copy`, `Clone` and `Sized`. - #[tracing::instrument(level = "debug", skip(self, candidates))] + #[instrument(level = "debug", skip(self, candidates))] fn assemble_builtin_bound_candidates( &mut self, conditions: BuiltinImplConditions<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 46b50dd92f1e..83838b70fb25 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2153,7 +2153,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn match_impl( &mut self, impl_def_id: DefId, @@ -2335,7 +2335,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// impl or trait. The obligations are substituted and fully /// normalized. This is used when confirming an impl or default /// impl. - #[tracing::instrument(level = "debug", skip(self, cause, param_env))] + #[instrument(level = "debug", skip(self, cause, param_env))] fn impl_or_trait_obligations( &mut self, cause: &ObligationCause<'tcx>, diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 5c96f1c4623a..72778c8b76a8 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -201,7 +201,7 @@ pub trait CreateSubstsForGenericArgsCtxt<'a, 'tcx> { } impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] pub fn ast_region_to_region( &self, lifetime: &hir::Lifetime, @@ -317,7 +317,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// `[Vec, u8]` and `generic_args` are the arguments for the associated /// type itself: `['a]`. The returned `SubstsRef` concatenates these two /// lists: `[Vec, u8, 'a]`. - #[tracing::instrument(level = "debug", skip(self, span))] + #[instrument(level = "debug", skip(self, span))] fn create_substs_for_ast_path<'a>( &self, span: Span, @@ -716,7 +716,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// where `'a` is a bound region at depth 0. Similarly, the `poly_trait_ref` would be /// `Bar<'a>`. The returned poly-trait-ref will have this binder instantiated explicitly, /// however. - #[tracing::instrument(level = "debug", skip(self, span, constness, bounds, speculative))] + #[instrument(level = "debug", skip(self, span, constness, bounds, speculative))] pub(crate) fn instantiate_poly_trait_ref( &self, trait_ref: &hir::TraitRef<'_>, @@ -808,7 +808,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ty::TraitRef::new(trait_def_id, substs) } - #[tracing::instrument(level = "debug", skip(self, span))] + #[instrument(level = "debug", skip(self, span))] fn create_substs_for_ast_trait_ref<'a>( &self, span: Span, @@ -922,7 +922,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// **A note on binders:** there is an implied binder around /// `param_ty` and `ast_bounds`. See `instantiate_poly_trait_ref` /// for more details. - #[tracing::instrument(level = "debug", skip(self, ast_bounds, bounds))] + #[instrument(level = "debug", skip(self, ast_bounds, bounds))] pub(crate) fn add_bounds<'hir, I: Iterator>>( &self, param_ty: Ty<'tcx>, @@ -1028,10 +1028,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// **A note on binders:** given something like `T: for<'a> Iterator`, the /// `trait_ref` here will be `for<'a> T: Iterator`. The `binding` data however is from *inside* /// the binder (e.g., `&'a u32`) and hence may reference bound regions. - #[tracing::instrument( - level = "debug", - skip(self, bounds, speculative, dup_bindings, path_span) - )] + #[instrument(level = "debug", skip(self, bounds, speculative, dup_bindings, path_span))] fn add_predicates_for_ast_type_binding( &self, hir_ref_id: hir::HirId, @@ -2599,7 +2596,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// Turns a `hir::Ty` into a `Ty`. For diagnostics' purposes we keep track of whether trait /// objects are borrowed like `&dyn Trait` to avoid emitting redundant errors. - #[tracing::instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self))] fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool) -> Ty<'tcx> { let tcx = self.tcx(); diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index 804306814a24..b6bc244d2b14 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -1308,7 +1308,7 @@ fn compare_type_predicate_entailment<'tcx>( /// For default associated types the normalization is not possible (the value /// from the impl could be overridden). We also can't normalize generic /// associated types (yet) because they contain bound parameters. -#[tracing::instrument(level = "debug", skip(tcx))] +#[instrument(level = "debug", skip(tcx))] pub fn check_type_bounds<'tcx>( tcx: TyCtxt<'tcx>, trait_ty: &ty::AssocItem, diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index 07046f3f0326..b9054898a2e5 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -130,7 +130,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// N.B., this code relies on `self.diverges` to be accurate. In particular, assignments to `!` /// will be permitted if the diverges flag is currently "always". - #[tracing::instrument(level = "debug", skip(self, expr, expected_ty_expr, allow_two_phase))] + #[instrument(level = "debug", skip(self, expr, expected_ty_expr, allow_two_phase))] pub fn demand_coerce_diag( &self, expr: &hir::Expr<'tcx>, diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 20d25d508d22..63cdf2cc1f0c 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -1405,7 +1405,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) } - #[tracing::instrument(level = "debug", skip(self, code, span, def_id, substs))] + #[instrument(level = "debug", skip(self, code, span, def_id, substs))] fn add_required_obligations_with_code( &self, span: Span, diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index ba42453bd60e..86cf12d22404 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -972,7 +972,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { } } -#[tracing::instrument(level = "debug", skip(tcx, span, sig_if_method))] +#[instrument(level = "debug", skip(tcx, span, sig_if_method))] fn check_associated_item( tcx: TyCtxt<'_>, item_id: LocalDefId, @@ -1225,7 +1225,7 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: LocalDefId, ty_span: Span, allow_fo }); } -#[tracing::instrument(level = "debug", skip(tcx, ast_self_ty, ast_trait_ref))] +#[instrument(level = "debug", skip(tcx, ast_self_ty, ast_trait_ref))] fn check_impl<'tcx>( tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>, @@ -1472,7 +1472,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id wfcx.register_obligations(obligations); } -#[tracing::instrument(level = "debug", skip(wfcx, span, hir_decl))] +#[instrument(level = "debug", skip(wfcx, span, hir_decl))] fn check_fn_or_method<'tcx>( wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, @@ -1536,7 +1536,7 @@ const HELP_FOR_SELF_TYPE: &str = "consider changing to `self`, `&self`, `&mut se `self: Rc`, `self: Arc`, or `self: Pin

` (where P is one \ of the previous types except `Self`)"; -#[tracing::instrument(level = "debug", skip(wfcx))] +#[instrument(level = "debug", skip(wfcx))] fn check_method_receiver<'tcx>( wfcx: &WfCheckingCtxt<'_, 'tcx>, fn_sig: &hir::FnSig<'_>, From ee3c8350189de045ec71997874eaa6cebf99fbf3 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 31 Aug 2022 13:09:26 +0000 Subject: [PATCH 4045/5092] Always import all tracing macros for the entire crate instead of piecemeal by module --- compiler/rustc_ast/src/lib.rs | 3 +++ compiler/rustc_ast/src/util/literal.rs | 1 - compiler/rustc_ast_lowering/src/index.rs | 2 -- compiler/rustc_ast_lowering/src/path.rs | 1 - compiler/rustc_ast_passes/src/feature_gate.rs | 2 -- compiler/rustc_ast_passes/src/lib.rs | 3 +++ .../src/diagnostics/outlives_suggestion.rs | 1 - compiler/rustc_builtin_macros/src/lib.rs | 3 +++ compiler/rustc_builtin_macros/src/test.rs | 2 +- .../rustc_builtin_macros/src/test_harness.rs | 1 - compiler/rustc_codegen_llvm/src/asm.rs | 1 - compiler/rustc_codegen_llvm/src/back/archive.rs | 8 ++++---- compiler/rustc_codegen_llvm/src/back/lto.rs | 1 - compiler/rustc_codegen_llvm/src/back/write.rs | 1 - compiler/rustc_codegen_llvm/src/builder.rs | 1 - compiler/rustc_codegen_llvm/src/callee.rs | 1 - compiler/rustc_codegen_llvm/src/common.rs | 1 - compiler/rustc_codegen_llvm/src/consts.rs | 1 - .../src/coverageinfo/mapgen.rs | 2 -- .../rustc_codegen_llvm/src/coverageinfo/mod.rs | 1 - compiler/rustc_codegen_llvm/src/debuginfo/mod.rs | 1 - .../rustc_codegen_llvm/src/debuginfo/utils.rs | 2 +- compiler/rustc_codegen_llvm/src/declare.rs | 1 - compiler/rustc_codegen_llvm/src/llvm_util.rs | 1 - compiler/rustc_codegen_llvm/src/mono_item.rs | 1 - compiler/rustc_codegen_llvm/src/type_of.rs | 1 - compiler/rustc_error_messages/src/lib.rs | 4 +++- compiler/rustc_errors/src/diagnostic_builder.rs | 1 - compiler/rustc_errors/src/emitter.rs | 1 - compiler/rustc_expand/src/lib.rs | 3 +++ compiler/rustc_expand/src/mbe/macro_rules.rs | 1 - compiler/rustc_hir/src/definitions.rs | 1 - compiler/rustc_hir/src/lib.rs | 3 +++ compiler/rustc_interface/src/interface.rs | 2 +- compiler/rustc_interface/src/lib.rs | 3 +++ compiler/rustc_interface/src/passes.rs | 5 ++--- compiler/rustc_interface/src/queries.rs | 2 +- compiler/rustc_interface/src/util.rs | 2 +- compiler/rustc_lint/src/builtin.rs | 1 - compiler/rustc_lint/src/context.rs | 5 ++--- compiler/rustc_lint/src/early.rs | 1 - compiler/rustc_lint/src/internal.rs | 1 - compiler/rustc_lint/src/late.rs | 1 - compiler/rustc_lint/src/levels.rs | 1 - compiler/rustc_lint/src/lib.rs | 2 ++ compiler/rustc_lint/src/types.rs | 1 - compiler/rustc_metadata/src/creader.rs | 3 +-- compiler/rustc_metadata/src/dependency_format.rs | 6 +++--- compiler/rustc_metadata/src/lib.rs | 3 +++ compiler/rustc_metadata/src/locator.rs | 1 - compiler/rustc_metadata/src/rmeta/decoder.rs | 1 - compiler/rustc_metadata/src/rmeta/encoder.rs | 1 - compiler/rustc_metadata/src/rmeta/table.rs | 1 - compiler/rustc_mir_build/src/thir/cx/expr.rs | 2 +- compiler/rustc_parse/src/lexer/mod.rs | 2 -- .../src/lexer/unescape_error_reporting.rs | 8 ++------ compiler/rustc_parse/src/parser/attr.rs | 2 -- compiler/rustc_parse/src/parser/diagnostics.rs | 1 - compiler/rustc_parse/src/parser/item.rs | 1 - compiler/rustc_parse/src/parser/mod.rs | 1 - compiler/rustc_parse/src/parser/path.rs | 1 - compiler/rustc_privacy/src/lib.rs | 5 ++++- compiler/rustc_resolve/src/access_levels.rs | 2 +- .../rustc_resolve/src/build_reduced_graph.rs | 1 - compiler/rustc_resolve/src/def_collector.rs | 1 - compiler/rustc_resolve/src/diagnostics.rs | 1 - compiler/rustc_resolve/src/imports.rs | 2 -- compiler/rustc_resolve/src/late.rs | 7 ++----- compiler/rustc_resolve/src/late/diagnostics.rs | 2 -- compiler/rustc_resolve/src/late/lifetimes.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 1 - compiler/rustc_save_analysis/src/dump_visitor.rs | 2 -- compiler/rustc_save_analysis/src/lib.rs | 5 +++-- compiler/rustc_session/src/cgu_reuse_tracker.rs | 1 - compiler/rustc_session/src/config.rs | 2 +- compiler/rustc_session/src/filesearch.rs | 1 - compiler/rustc_session/src/lib.rs | 3 +++ compiler/rustc_span/src/hygiene.rs | 1 - compiler/rustc_span/src/lib.rs | 2 -- compiler/rustc_span/src/source_map.rs | 1 - compiler/rustc_symbol_mangling/src/legacy.rs | 2 -- compiler/rustc_symbol_mangling/src/lib.rs | 5 +++-- .../src/traits/error_reporting/mod.rs | 2 +- compiler/rustc_transmute/src/layout/tree.rs | 16 ++++++++-------- .../src/maybe_transmutable/mod.rs | 4 ++-- .../src/maybe_transmutable/query_context.rs | 2 +- compiler/rustc_ty_utils/src/instance.rs | 2 -- .../rustc_typeck/src/check/generator_interior.rs | 1 - 88 files changed, 76 insertions(+), 119 deletions(-) diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 27061f300a2b..e5435e3a3d4f 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -26,6 +26,9 @@ #[macro_use] extern crate rustc_macros; +#[macro_use] +extern crate tracing; + pub mod util { pub mod classify; pub mod comments; diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index 69a78d165ef5..6a1578498e68 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -9,7 +9,6 @@ use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; use std::ascii; -use tracing::debug; pub enum LitError { NotLiteral, diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index a0547497b192..219e1b81d1ea 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -11,8 +11,6 @@ use rustc_session::Session; use rustc_span::source_map::SourceMap; use rustc_span::{Span, DUMMY_SP}; -use tracing::debug; - /// A visitor that walks over the HIR and collects `Node`s into a HIR map. pub(super) struct NodeCollector<'a, 'hir> { /// Source map diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 5874d08a94fe..897c7215805e 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -13,7 +13,6 @@ use rustc_span::symbol::{kw, Ident}; use rustc_span::{BytePos, Span, DUMMY_SP}; use smallvec::smallvec; -use tracing::debug; impl<'a, 'hir> LoweringContext<'a, 'hir> { #[instrument(level = "trace", skip(self))] diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 6f7e88eb86f1..ca5b7a641551 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -11,8 +11,6 @@ use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; use rustc_span::Span; -use tracing::debug; - macro_rules! gate_feature_fn { ($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $help: expr) => {{ let (visitor, has_feature, span, name, explain, help) = diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs index f282ff251bda..af25982e2887 100644 --- a/compiler/rustc_ast_passes/src/lib.rs +++ b/compiler/rustc_ast_passes/src/lib.rs @@ -12,6 +12,9 @@ #![feature(let_else)] #![recursion_limit = "256"] +#[macro_use] +extern crate tracing; + pub mod ast_validation; mod errors; pub mod feature_gate; diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs index d359d7efb626..35c3df768995 100644 --- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs +++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs @@ -6,7 +6,6 @@ use rustc_errors::Diagnostic; use rustc_middle::ty::RegionVid; use smallvec::SmallVec; use std::collections::BTreeMap; -use tracing::debug; use crate::MirBorrowckCtxt; diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 11565ba72d75..280fa7045114 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -16,6 +16,9 @@ extern crate proc_macro; +#[macro_use] +extern crate tracing; + use crate::deriving::*; use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind}; diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 7eee80733666..7efb6cc61eec 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -335,7 +335,7 @@ pub fn expand_test_or_bench( // extern crate test let test_extern = cx.item(sp, test_id, ast::AttrVec::new(), ast::ItemKind::ExternCrate(None)); - tracing::debug!("synthetic test item:\n{}\n", pprust::item_to_string(&test_const)); + debug!("synthetic test item:\n{}\n", pprust::item_to_string(&test_const)); if is_stmt { vec![ diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 89b0d2cc9be2..079c6ff37cfb 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -15,7 +15,6 @@ use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::PanicStrategy; use smallvec::{smallvec, SmallVec}; use thin_vec::thin_vec; -use tracing::debug; use std::{iter, mem}; diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 2a6612eb86f1..5202ac697e94 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -19,7 +19,6 @@ use rustc_target::asm::*; use libc::{c_char, c_uint}; use smallvec::SmallVec; -use tracing::debug; impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { fn codegen_inline_asm( diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 2e614e5dd88e..38a366095b41 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -190,10 +190,10 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { let output_path_z = rustc_fs_util::path_to_c_string(&output_path); - tracing::trace!("invoking LLVMRustWriteImportLibrary"); - tracing::trace!(" dll_name {:#?}", dll_name_z); - tracing::trace!(" output_path {}", output_path.display()); - tracing::trace!( + trace!("invoking LLVMRustWriteImportLibrary"); + trace!(" dll_name {:#?}", dll_name_z); + trace!(" output_path {}", output_path.display()); + trace!( " import names: {}", dll_imports .iter() diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index e4af6269abc5..a89df00e248e 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -18,7 +18,6 @@ use rustc_middle::dep_graph::WorkProduct; use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel}; use rustc_session::cgu_reuse_tracker::CguReuse; use rustc_session::config::{self, CrateType, Lto}; -use tracing::{debug, info}; use std::ffi::{CStr, CString}; use std::fs::File; diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 740a68d0772c..a695df8409bb 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -28,7 +28,6 @@ use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::InnerSpan; use rustc_target::spec::{CodeModel, RelocModel, SanitizerSet, SplitDebuginfo}; -use tracing::debug; use libc::{c_char, c_int, c_uint, c_void, size_t}; use std::ffi::CString; diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index e7e373bf45d1..63b63c6a1fab 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -27,7 +27,6 @@ use std::ffi::CStr; use std::iter; use std::ops::Deref; use std::ptr; -use tracing::{debug, instrument}; // All Builders must have an llfn associated with them #[must_use] diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs index d55f995b933a..b83c1e8f08f3 100644 --- a/compiler/rustc_codegen_llvm/src/callee.rs +++ b/compiler/rustc_codegen_llvm/src/callee.rs @@ -11,7 +11,6 @@ use crate::context::CodegenCx; use crate::llvm; use crate::value::Value; use rustc_codegen_ssa::traits::*; -use tracing::debug; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt}; use rustc_middle::ty::{self, Instance, TypeVisitable}; diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 63d3bb40a3fe..13e437cfbf7f 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -21,7 +21,6 @@ use rustc_target::spec::Target; use libc::{c_char, c_uint}; use std::fmt::Write; -use tracing::debug; /* * A note on nomenclature of linking: "extern", "foreign", and "upcall". diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index d3e33da27993..a559f7f3d570 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -23,7 +23,6 @@ use rustc_target::abi::{ AddressSpace, Align, HasDataLayout, Primitive, Scalar, Size, WrappingRange, }; use std::ops::Range; -use tracing::debug; pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation<'_>) -> &'ll Value { let alloc = alloc.inner(); diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 58f391692c49..0d1df6fb1acd 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -16,8 +16,6 @@ use rustc_middle::ty::TyCtxt; use std::ffi::CString; -use tracing::debug; - /// Generates and exports the Coverage Map. /// /// Rust Coverage Map generation supports LLVM Coverage Mapping Format versions diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index 98ba38356a4c..964a632b6eed 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -28,7 +28,6 @@ use std::cell::RefCell; use std::ffi::CString; use std::iter; -use tracing::debug; pub mod mapgen; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index cf591295b846..b23fe3fc9d55 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -39,7 +39,6 @@ use smallvec::SmallVec; use std::cell::OnceCell; use std::cell::RefCell; use std::iter; -use tracing::debug; mod create_scope_map; pub mod gdb; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs index 8f2436739077..a40cfc8b23fb 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs @@ -6,7 +6,7 @@ use super::CodegenUnitDebugContext; use rustc_hir::def_id::DefId; use rustc_middle::ty::layout::{HasParamEnv, LayoutOf}; use rustc_middle::ty::{self, DefIdTree, Ty}; -use tracing::trace; +use trace; use crate::common::CodegenCx; use crate::llvm; diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index fa0ecd18fc89..0f663a26732b 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -22,7 +22,6 @@ use rustc_codegen_ssa::traits::TypeMembershipMethods; use rustc_middle::ty::Ty; use rustc_symbol_mangling::typeid::typeid_for_fnabi; use smallvec::SmallVec; -use tracing::debug; /// Declare a function. /// diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index f5d676c44e34..1b049dfe9790 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -15,7 +15,6 @@ use rustc_span::symbol::Symbol; use rustc_target::spec::{MergeFunctions, PanicStrategy}; use smallvec::{smallvec, SmallVec}; use std::ffi::{CStr, CString}; -use tracing::debug; use std::mem; use std::path::Path; diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index 6e94284852f3..1eceb7f5c87b 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -11,7 +11,6 @@ use rustc_middle::ty::layout::{FnAbiOf, LayoutOf}; use rustc_middle::ty::{self, Instance, TypeVisitable}; use rustc_session::config::CrateType; use rustc_target::spec::RelocModel; -use tracing::debug; impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'_, 'tcx> { fn predefine_static( diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 9f0e6c80b19a..dc1165835e7c 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -11,7 +11,6 @@ use rustc_target::abi::{Abi, AddressSpace, Align, FieldsShape}; use rustc_target::abi::{Int, Pointer, F32, F64}; use rustc_target::abi::{PointeeInfo, Scalar, Size, TyAbiInterface, Variants}; use smallvec::{smallvec, SmallVec}; -use tracing::debug; use std::fmt::Write; diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 8f47be25db91..ed5e092814f1 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -5,6 +5,9 @@ #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +#[macro_use] +extern crate tracing; + use fluent_bundle::FluentResource; use fluent_syntax::parser::ParserError; use rustc_data_structures::sync::Lrc; @@ -16,7 +19,6 @@ use std::fmt; use std::fs; use std::io; use std::path::{Path, PathBuf}; -use tracing::{instrument, trace}; #[cfg(not(parallel_compiler))] use std::cell::LazyCell as Lazy; diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 61d767a1cc6b..7e29dc207acc 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -12,7 +12,6 @@ use std::fmt::{self, Debug}; use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; use std::thread::panicking; -use tracing::debug; /// Used for emitting structured error messages and other diagnostic information. /// diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 6c1bfcb9919e..e79ce11a6fc0 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -34,7 +34,6 @@ use std::iter; use std::path::Path; use termcolor::{Ansi, BufferWriter, ColorChoice, ColorSpec, StandardStream}; use termcolor::{Buffer, Color, WriteColor}; -use tracing::*; /// Default column width, used in tests and when terminal dimensions cannot be determined. const DEFAULT_COLUMN_WIDTH: usize = 140; diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index 75dcbd69674d..ac0e200b1b73 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -15,6 +15,9 @@ #[macro_use] extern crate rustc_macros; +#[macro_use] +extern crate tracing; + extern crate proc_macro as pm; mod placeholders; diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 86dbd33a221f..7764ffd246e3 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -32,7 +32,6 @@ use rustc_span::Span; use std::borrow::Cow; use std::collections::hash_map::Entry; use std::{mem, slice}; -use tracing::debug; pub(crate) struct ParserAnyMacro<'a> { parser: Parser<'a>, diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index c2c551e78a41..d85ac960f9b2 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -15,7 +15,6 @@ use rustc_span::symbol::{kw, sym, Symbol}; use std::fmt::{self, Write}; use std::hash::Hash; -use tracing::debug; /// The `DefPathTable` maps `DefIndex`es to `DefKey`s and vice versa. /// Internally the `DefPathTable` holds a tree of `DefKey`s, where each `DefKey` diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index 092029ef09ec..1b33cb9c2da9 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -17,6 +17,9 @@ #[macro_use] extern crate rustc_macros; +#[macro_use] +extern crate tracing; + #[macro_use] extern crate rustc_data_structures; diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 1c6243c275c0..949bd02ad683 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -332,7 +332,7 @@ pub fn create_compiler_and_run(config: Config, f: impl FnOnce(&Compiler) -> R // JUSTIFICATION: before session exists, only config #[allow(rustc::bad_opt_access)] pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R { - tracing::trace!("run_compiler"); + trace!("run_compiler"); util::run_in_thread_pool_with_globals( config.opts.edition, config.opts.unstable_opts.threads, diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index 258e38c3bdb9..1a8d619fafb6 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -8,6 +8,9 @@ #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +#[macro_use] +extern crate tracing; + mod callbacks; mod errors; pub mod interface; diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 66c6a229b89e..f8b40949e2ed 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -38,7 +38,6 @@ use rustc_span::symbol::{sym, Symbol}; use rustc_span::FileName; use rustc_trait_selection::traits; use rustc_typeck as typeck; -use tracing::{info, warn}; use std::any::Any; use std::cell::RefCell; @@ -165,7 +164,7 @@ pub fn create_resolver( krate: &ast::Crate, crate_name: &str, ) -> BoxedResolver { - tracing::trace!("create_resolver"); + trace!("create_resolver"); BoxedResolver::new(sess, move |sess, resolver_arenas| { Resolver::new(sess, krate, crate_name, metadata_loader, resolver_arenas) }) @@ -279,7 +278,7 @@ pub fn configure_and_expand( crate_name: &str, resolver: &mut Resolver<'_>, ) -> Result { - tracing::trace!("configure_and_expand"); + trace!("configure_and_expand"); pre_expansion_lint(sess, lint_store, resolver.registered_tools(), &krate, crate_name); rustc_builtin_macros::register_builtin_macros(resolver); diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 65fa8d7495a4..6c725a01b531 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -166,7 +166,7 @@ impl<'tcx> Queries<'tcx> { pub fn expansion( &self, ) -> Result<&Query<(Lrc, Rc>, Lrc)>> { - tracing::trace!("expansion"); + trace!("expansion"); self.expansion.compute(|| { let crate_name = self.crate_name()?.peek().clone(); let (krate, lint_store) = self.register_plugins()?.take(); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index e74978485a21..f7e70d355cf8 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -1,3 +1,4 @@ +use info; use libloading::Library; use rustc_ast as ast; use rustc_codegen_ssa::traits::CodegenBackend; @@ -31,7 +32,6 @@ use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::OnceLock; use std::thread; -use tracing::info; /// Function pointer type that constructs a new CodegenBackend. pub type MakeBackendFn = fn() -> Box; diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 868555a72b0d..4a744748b2bc 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -59,7 +59,6 @@ use rustc_trait_selection::traits::{self, misc::can_type_implement_copy}; use crate::nonstandard_style::{method_context, MethodLateContext}; use std::fmt::Write; -use tracing::{debug, trace}; // hardwired lints from librustc_middle pub use rustc_session::lint::builtin::*; diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 002bba4759be..e3b6c0159870 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -45,7 +45,6 @@ use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{BytePos, Span}; use rustc_target::abi; -use tracing::debug; use std::cell::Cell; use std::iter; @@ -417,7 +416,7 @@ impl LintStore { None => { // 1. The tool is currently running, so this lint really doesn't exist. // FIXME: should this handle tools that never register a lint, like rustfmt? - tracing::debug!("lints={:?}", self.by_name.keys().collect::>()); + debug!("lints={:?}", self.by_name.keys().collect::>()); let tool_prefix = format!("{}::", tool_name); return if self.by_name.keys().any(|lint| lint.starts_with(&tool_prefix)) { self.no_lint_suggestion(&complete_name) @@ -510,7 +509,7 @@ impl LintStore { CheckLintNameResult::Tool(Err((Some(slice::from_ref(id)), complete_name))) } Some(other) => { - tracing::debug!("got renamed lint {:?}", other); + debug!("got renamed lint {:?}", other); CheckLintNameResult::NoLint(None) } } diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index cdb5b3c4284a..27d173ebde82 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -26,7 +26,6 @@ use rustc_span::symbol::Ident; use rustc_span::Span; use std::slice; -use tracing::debug; macro_rules! run_early_pass { ($cx:expr, $f:ident, $($args:expr),*) => ({ $cx.pass.$f(&$cx.context, $($args),*); diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 6d451f3090ac..16b7d2cbbaea 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -12,7 +12,6 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; -use tracing::debug; declare_tool_lint! { pub rustc::DEFAULT_HASH_TYPES, diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index 5188ac633d39..8a336844dc2f 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -29,7 +29,6 @@ use rustc_span::Span; use std::any::Any; use std::cell::Cell; use std::slice; -use tracing::debug; /// Extract the `LintStore` from the query context. /// This function exists because we've erased `LintStore` as `dyn Any` in the context. diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 89409b58f88b..f1d8ef2e47d3 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -21,7 +21,6 @@ use rustc_session::parse::{add_feature_diagnostics, feature_err}; use rustc_session::Session; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; -use tracing::debug; use crate::errors::{ MalformedAttribute, MalformedAttributeSub, OverruledAttribute, OverruledAttributeSub, diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index c3065e4a2d93..801249badcc8 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -42,6 +42,8 @@ extern crate rustc_middle; #[macro_use] extern crate rustc_session; +#[macro_use] +extern crate tracing; mod array_into_iter; pub mod builtin; diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 484e541afc58..031665199812 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -19,7 +19,6 @@ use rustc_target::spec::abi::Abi as SpecAbi; use std::cmp; use std::iter; use std::ops::ControlFlow; -use tracing::debug; declare_lint! { /// The `unused_comparisons` lint detects comparisons made useless by diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 708d0b1fd8a3..6a5716600b3b 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -29,7 +29,6 @@ use proc_macro::bridge::client::ProcMacro; use std::ops::Fn; use std::path::Path; use std::{cmp, env}; -use tracing::{debug, info}; #[derive(Clone)] pub struct CStore { @@ -263,7 +262,7 @@ impl<'a> CrateLoader<'a> { fn existing_match(&self, name: Symbol, hash: Option, kind: PathKind) -> Option { for (cnum, data) in self.cstore.iter_crate_data() { if data.name() != name { - tracing::trace!("{} did not match {}", data.name(), name); + trace!("{} did not match {}", data.name(), name); continue; } diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index b765c34f8e36..1a25e987d3a6 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -158,11 +158,11 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { let name = tcx.crate_name(cnum); let src = tcx.used_crate_source(cnum); if src.dylib.is_some() { - tracing::info!("adding dylib: {}", name); + info!("adding dylib: {}", name); add_library(tcx, cnum, RequireDynamic, &mut formats); let deps = tcx.dylib_dependency_formats(cnum); for &(depnum, style) in deps.iter() { - tracing::info!("adding {:?}: {}", style, tcx.crate_name(depnum)); + info!("adding {:?}: {}", style, tcx.crate_name(depnum)); add_library(tcx, depnum, style, &mut formats); } } @@ -190,7 +190,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { && tcx.dep_kind(cnum) == CrateDepKind::Explicit { assert!(src.rlib.is_some() || src.rmeta.is_some()); - tracing::info!("adding staticlib: {}", tcx.crate_name(cnum)); + info!("adding staticlib: {}", tcx.crate_name(cnum)); add_library(tcx, cnum, RequireStatic, &mut formats); ret[cnum.as_usize() - 1] = Linkage::Static; } diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 6440f3e390cf..337d3cca2aed 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -26,6 +26,9 @@ extern crate rustc_middle; #[macro_use] extern crate rustc_data_structures; +#[macro_use] +extern crate tracing; + pub use rmeta::{provide, provide_extern}; mod dependency_format; diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 2c1c84b0be26..5b7d0c8581ab 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -236,7 +236,6 @@ use std::fmt::Write as _; use std::io::{Read, Result as IoResult, Write}; use std::path::{Path, PathBuf}; use std::{cmp, fmt, fs}; -use tracing::{debug, info}; #[derive(Clone)] pub(crate) struct CrateLocator<'a> { diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index d0e0aa91480c..b28f54fac1a6 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -42,7 +42,6 @@ use std::iter::TrustedLen; use std::mem; use std::num::NonZeroUsize; use std::path::Path; -use tracing::debug; pub(super) use cstore_impl::provide; pub use cstore_impl::provide_extern; diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 3482d9f04514..34d8edc30cdd 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -44,7 +44,6 @@ use std::io::{Read, Seek, Write}; use std::iter; use std::num::NonZeroUsize; use std::path::{Path, PathBuf}; -use tracing::{debug, trace}; pub(super) struct EncodeContext<'a, 'tcx> { opaque: opaque::FileEncoder, diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 21841ae2532a..8085675d75cc 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -10,7 +10,6 @@ use rustc_span::hygiene::MacroKind; use std::convert::TryInto; use std::marker::PhantomData; use std::num::NonZeroUsize; -use tracing::debug; /// Helper trait, for encoding to, and decoding from, a fixed number of bytes. /// Used mainly for Lazy positions and lengths. diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 0c2b117453fe..9ed1c064d2b7 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -268,7 +268,7 @@ impl<'tcx> Cx<'tcx> { // the overall method call for better diagnostics. args[0] // is guaranteed to exist, since a method call always has a receiver. let old_adjustment_span = self.adjustment_span.replace((args[0].hir_id, expr_span)); - tracing::info!("Using method span: {:?}", expr.span); + info!("Using method span: {:?}", expr.span); let args = self.mirror_exprs(args); self.adjustment_span = old_adjustment_span; ExprKind::Call { diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 848e142e59ce..63819a2f98df 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -14,8 +14,6 @@ use rustc_session::parse::ParseSess; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{edition::Edition, BytePos, Pos, Span}; -use tracing::debug; - mod tokentrees; mod unescape_error_reporting; mod unicode_chars; diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index 273827864f1a..77c4fadab45e 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -20,13 +20,9 @@ pub(crate) fn emit_unescape_error( range: Range, error: EscapeError, ) { - tracing::debug!( + debug!( "emit_unescape_error: {:?}, {:?}, {:?}, {:?}, {:?}", - lit, - span_with_quotes, - mode, - range, - error + lit, span_with_quotes, mode, range, error ); let last_char = || { let c = lit[range.clone()].chars().rev().next().unwrap(); diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 72ab96b5ca67..77a6bde1c164 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -7,8 +7,6 @@ use rustc_errors::{error_code, Diagnostic, PResult}; use rustc_span::{sym, BytePos, Span}; use std::convert::TryInto; -use tracing::debug; - // Public for rustfmt usage #[derive(Debug)] pub enum InnerAttrPolicy<'a> { diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index f0ea1dfe297f..dd806e2130e9 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -29,7 +29,6 @@ use std::ops::{Deref, DerefMut}; use std::mem::take; use crate::parser; -use tracing::{debug, trace}; const TURBOFISH_SUGGESTION_STR: &str = "use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments"; diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index b743162a7e4d..5b75d1d5f221 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -22,7 +22,6 @@ use rustc_span::DUMMY_SP; use std::convert::TryFrom; use std::mem; -use tracing::debug; impl<'a> Parser<'a> { /// Parses a source module as a crate. This is the main entry point for the parser. diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 5e79308464f6..5c8f374255c7 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -37,7 +37,6 @@ use rustc_errors::{ use rustc_session::parse::ParseSess; use rustc_span::source_map::{Span, DUMMY_SP}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use tracing::debug; use std::ops::Range; use std::{cmp, mem, slice}; diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index fc7fb866f110..fdc1af27f82e 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -13,7 +13,6 @@ use rustc_span::source_map::{BytePos, Span}; use rustc_span::symbol::{kw, sym, Ident}; use std::mem; -use tracing::debug; /// Specifies how to parse a path. #[derive(Copy, Clone, PartialEq)] diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 5d562f18a815..a9271761358c 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -8,6 +8,9 @@ #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +#[macro_use] +extern crate tracing; + mod errors; use rustc_ast::MacroDef; @@ -1784,7 +1787,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { fn leaks_private_dep(&self, item_id: DefId) -> bool { let ret = self.required_visibility.is_public() && self.tcx.is_private_dep(item_id.krate); - tracing::debug!("leaks_private_dep(item_id={:?})={}", item_id, ret); + debug!("leaks_private_dep(item_id={:?})={}", item_id, ret); ret } } diff --git a/compiler/rustc_resolve/src/access_levels.rs b/compiler/rustc_resolve/src/access_levels.rs index 3fba923d9fdf..882a92c0ebb6 100644 --- a/compiler/rustc_resolve/src/access_levels.rs +++ b/compiler/rustc_resolve/src/access_levels.rs @@ -39,7 +39,7 @@ impl<'r, 'a> AccessLevelsVisitor<'r, 'a> { visit::walk_crate(&mut visitor, krate); } - tracing::info!("resolve::access_levels: {:#?}", r.access_levels); + info!("resolve::access_levels: {:#?}", r.access_levels); } fn reset(&mut self) { diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 8f3b6009bd6e..cd0b2443da58 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -36,7 +36,6 @@ use rustc_span::Span; use std::cell::Cell; use std::ptr; -use tracing::debug; type Res = def::Res; diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 66641fb2cb24..5955d8df16ee 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -8,7 +8,6 @@ use rustc_hir::definitions::*; use rustc_span::hygiene::LocalExpnId; use rustc_span::symbol::sym; use rustc_span::Span; -use tracing::debug; pub(crate) fn collect_definitions( resolver: &mut Resolver<'_>, diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 2d15b1b0a1b9..4fd6fe4e36c6 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -25,7 +25,6 @@ use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, Span}; -use tracing::debug; use crate::imports::{Import, ImportKind, ImportResolver}; use crate::late::{PatternSource, Rib}; diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index c2491c6ebdec..619ce0462203 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -23,8 +23,6 @@ use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::Span; -use tracing::*; - use std::cell::Cell; use std::{mem, ptr}; diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 4cdfc6e7a4d7..dbe4d691f04c 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -32,7 +32,6 @@ use smallvec::{smallvec, SmallVec}; use rustc_span::source_map::{respan, Spanned}; use std::collections::{hash_map::Entry, BTreeSet}; use std::mem::{replace, take}; -use tracing::debug; mod diagnostics; pub(crate) mod lifetimes; @@ -3268,11 +3267,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { source: PathSource<'ast>, finalize: Finalize, ) -> PartialRes { - tracing::debug!( + debug!( "smart_resolve_path_fragment(qself={:?}, path={:?}, finalize={:?})", - qself, - path, - finalize, + qself, path, finalize, ); let ns = source.namespace(); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 9fc637ddbbff..99d13acbae1b 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -33,8 +33,6 @@ use rustc_span::{BytePos, Span}; use std::iter; use std::ops::Deref; -use tracing::debug; - type Res = def::Res; /// A field or associated item from self type suggested in case of resolution failure. diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 242dad17ec92..c16eab222f62 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -1212,7 +1212,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { scope: &wrap_scope, trait_definition_only: self.trait_definition_only, }; - let span = tracing::debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope)); + let span = debug_span!("scope", scope = ?TruncatedScopeDebug(&this.scope)); { let _enter = span.enter(); f(&mut this); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 5c33cb694a76..4e8f3a2cae87 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -58,7 +58,6 @@ use smallvec::{smallvec, SmallVec}; use std::cell::{Cell, RefCell}; use std::collections::BTreeSet; use std::{cmp, fmt, ptr}; -use tracing::debug; use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion}; use imports::{Import, ImportKind, ImportResolver, NameResolution}; diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs index e2e0e1f5b300..ac6c3663b637 100644 --- a/compiler/rustc_save_analysis/src/dump_visitor.rs +++ b/compiler/rustc_save_analysis/src/dump_visitor.rs @@ -44,8 +44,6 @@ use rls_data::{ RefKind, Relation, RelationKind, SpanData, }; -use tracing::{debug, error}; - #[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5213 macro_rules! down_cast_data { ($id:ident, $kind:ident, $sp:expr) => { diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index 619e083d89ad..16af53385104 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -7,6 +7,9 @@ #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] +#[macro_use] +extern crate tracing; + mod dump_visitor; mod dumper; #[macro_use] @@ -49,8 +52,6 @@ use rls_data::{ RefKind, Relation, RelationKind, SpanData, }; -use tracing::{debug, error, info}; - pub struct SaveContext<'tcx> { tcx: TyCtxt<'tcx>, maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>, diff --git a/compiler/rustc_session/src/cgu_reuse_tracker.rs b/compiler/rustc_session/src/cgu_reuse_tracker.rs index 2a4a772f6108..2336d99363fd 100644 --- a/compiler/rustc_session/src/cgu_reuse_tracker.rs +++ b/compiler/rustc_session/src/cgu_reuse_tracker.rs @@ -10,7 +10,6 @@ use rustc_span::{Span, Symbol}; use std::borrow::Cow; use std::fmt::{self}; use std::sync::{Arc, Mutex}; -use tracing::debug; #[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] pub enum CguReuse { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 162fc9aa0a6e..7c50fe2d823b 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2530,7 +2530,7 @@ fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Optio ), ), }; - tracing::debug!("got unpretty option: {first:?}"); + debug!("got unpretty option: {first:?}"); Some(first) } diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index c973e3140cef..e8edb38f5038 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -7,7 +7,6 @@ use std::path::{Path, PathBuf}; use crate::search_paths::{PathKind, SearchPath}; use rustc_fs_util::fix_windows_verbatim_for_gcc; -use tracing::debug; #[derive(Copy, Clone)] pub enum FileMatch { diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index 429475c573c8..02d5d33c8d5b 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -14,6 +14,9 @@ extern crate rustc_macros; pub mod errors; +#[macro_use] +extern crate tracing; + pub mod cgu_reuse_tracker; pub mod utils; pub use lint::{declare_lint, declare_lint_pass, declare_tool_lint, impl_lint_pass}; diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index e169d3c7cfb7..e8ddb4ed17a3 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -41,7 +41,6 @@ use rustc_macros::HashStable_Generic; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use std::fmt; use std::hash::Hash; -use tracing::*; /// A `SyntaxContext` represents a chain of pairs `(ExpnId, Transparency)` named "marks". #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 860af7fe93a0..34e2e92bdfce 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -76,8 +76,6 @@ use md5::Md5; use sha1::Sha1; use sha2::Sha256; -use tracing::debug; - #[cfg(test)] mod tests; diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index a32cabab4c40..8ffbbff7a7dc 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -23,7 +23,6 @@ use std::{convert::TryFrom, unreachable}; use std::fs; use std::io; -use tracing::debug; #[cfg(test)] mod tests; diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 9241fd82c745..46c5fe78ffbf 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -6,8 +6,6 @@ use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeVisitable}; use rustc_middle::util::common::record_time; -use tracing::debug; - use std::fmt::{self, Write}; use std::mem::{self, discriminant}; diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 0c6489acb348..62f44a48032e 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -97,6 +97,9 @@ #[macro_use] extern crate rustc_middle; +#[macro_use] +extern crate tracing; + use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; @@ -107,8 +110,6 @@ use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, Instance, TyCtxt}; use rustc_session::config::SymbolManglingVersion; -use tracing::debug; - mod legacy; mod v0; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index e4af7022239b..99046bd126f9 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -2014,7 +2014,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { let predicate = self.resolve_vars_if_possible(obligation.predicate); let span = obligation.cause.span; - debug!(?predicate, obligation.cause.code = tracing::field::debug(&obligation.cause.code())); + debug!(?predicate, obligation.cause.code = ?obligation.cause.code()); // Ambiguity errors are often caused as fallout from earlier errors. // We ignore them if this `infcx` is tainted in some cases below. diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index 4ab6d3737c59..211c813b8001 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -317,7 +317,7 @@ pub(crate) mod rustc { tcx, )?, AdtKind::Enum => { - tracing::trace!(?adt_def, "treeifying enum"); + trace!(?adt_def, "treeifying enum"); let mut tree = Tree::uninhabited(); for (idx, discr) in adt_def.discriminants(tcx) { @@ -381,7 +381,7 @@ pub(crate) mod rustc { let clamp = |align: Align| align.clamp(min_align, max_align).bytes().try_into().unwrap(); - let variant_span = tracing::trace_span!( + let variant_span = trace_span!( "treeifying variant", min_align = ?min_align, max_align = ?max_align, @@ -396,22 +396,22 @@ pub(crate) mod rustc { // The layout of the variant is prefixed by the discriminant, if any. if let Some(discr) = discr { - tracing::trace!(?discr, "treeifying discriminant"); + trace!(?discr, "treeifying discriminant"); let discr_layout = alloc::Layout::from_size_align( layout_summary.discriminant_size, clamp(layout_summary.discriminant_align), ) .unwrap(); - tracing::trace!(?discr_layout, "computed discriminant layout"); + trace!(?discr_layout, "computed discriminant layout"); variant_layout = variant_layout.extend(discr_layout).unwrap().0; tree = tree.then(Self::from_disr(discr, tcx, layout_summary.discriminant_size)); } // Next come fields. - let fields_span = tracing::trace_span!("treeifying fields").entered(); + let fields_span = trace_span!("treeifying fields").entered(); for field_def in variant_def.fields.iter() { let field_ty = field_def.ty(tcx, substs_ref); - let _span = tracing::trace_span!("treeifying field", field = ?field_ty).entered(); + let _span = trace_span!("treeifying field", field = ?field_ty).entered(); // begin with the field's visibility tree = tree.then(Self::def(Def::Field(field_def))); @@ -434,7 +434,7 @@ pub(crate) mod rustc { drop(fields_span); // finally: padding - let padding_span = tracing::trace_span!("adding trailing padding").entered(); + let padding_span = trace_span!("adding trailing padding").entered(); let padding_needed = layout_summary.total_size - variant_layout.size(); if padding_needed > 0 { tree = tree.then(Self::padding(padding_needed)); @@ -467,7 +467,7 @@ pub(crate) mod rustc { layout.align().abi.bytes().try_into().unwrap(), ) .unwrap(); - tracing::trace!(?ty, ?layout, "computed layout for type"); + trace!(?ty, ?layout, "computed layout for type"); Ok(layout) } } diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs index 076d922d1b72..248ff1ec2416 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs @@ -110,7 +110,7 @@ where // Remove all `Def` nodes from `src`, without checking their visibility. let src = src.prune(&|def| true); - tracing::trace!(?src, "pruned src"); + trace!(?src, "pruned src"); // Remove all `Def` nodes from `dst`, additionally... let dst = if assume_visibility { @@ -121,7 +121,7 @@ where dst.prune(&|def| context.is_accessible_from(def, scope)) }; - tracing::trace!(?dst, "pruned dst"); + trace!(?dst, "pruned dst"); // Convert `src` from a tree-based representation to an NFA-based representation. // If the conversion fails because `src` is uninhabited, conclude that the transmutation diff --git a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs index 9c2cf4c9a923..adab343ac98a 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs @@ -82,7 +82,7 @@ mod rustc { false }; - tracing::trace!(?ret, "ret"); + trace!(?ret, "ret"); ret } diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index bd1d568cd9a0..661e413fc5b8 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -15,8 +15,6 @@ use std::collections::btree_map::Entry; use std::collections::BTreeMap; use std::ops::ControlFlow; -use tracing::debug; - // FIXME(#86795): `BoundVarsCollector` here should **NOT** be used // outside of `resolve_associated_item`. It's just to address #64494, // #83765, and #85848 which are creating bound types/regions that lose diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs index 85a0d4e44990..2a8c460bb118 100644 --- a/compiler/rustc_typeck/src/check/generator_interior.rs +++ b/compiler/rustc_typeck/src/check/generator_interior.rs @@ -17,7 +17,6 @@ use rustc_middle::middle::region::{self, Scope, ScopeData, YieldData}; use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt, TypeVisitable}; use rustc_span::symbol::sym; use rustc_span::Span; -use tracing::debug; mod drop_ranges; From 1fc9ef1edd30ae5a924c3673d76f275f7d12c3fb Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 28 Jun 2022 15:18:07 +0000 Subject: [PATCH 4046/5092] tracing::instrument cleanup --- .../rustc_borrowck/src/region_infer/mod.rs | 28 +++++------ .../src/region_infer/opaque_types.rs | 2 +- .../rustc_borrowck/src/universal_regions.rs | 3 +- .../src/const_eval/eval_queries.rs | 7 +-- .../src/const_eval/valtrees.rs | 18 +++----- compiler/rustc_driver/Cargo.toml | 2 +- compiler/rustc_infer/src/infer/combine.rs | 23 ++-------- .../src/infer/higher_ranked/mod.rs | 7 ++- .../src/infer/lexical_region_resolve/mod.rs | 10 ++-- .../rustc_infer/src/infer/nll_relate/mod.rs | 4 +- .../rustc_infer/src/infer/opaque_types.rs | 10 ++-- .../src/infer/opaque_types/table.rs | 2 +- .../rustc_infer/src/infer/outlives/mod.rs | 2 +- compiler/rustc_middle/src/mir/mod.rs | 22 ++++----- compiler/rustc_middle/src/ty/consts.rs | 2 - compiler/rustc_middle/src/ty/fold.rs | 2 +- .../src/ty/normalize_erasing_regions.rs | 2 - compiler/rustc_middle/src/ty/trait_def.rs | 1 - compiler/rustc_middle/src/ty/util.rs | 3 +- compiler/rustc_middle/src/ty/visit.rs | 12 ++--- .../src/thir/pattern/const_to_pat.rs | 9 ++-- .../src/thir/pattern/usefulness.rs | 3 +- compiler/rustc_monomorphize/src/collector.rs | 14 ++---- .../rustc_monomorphize/src/polymorphize.rs | 1 - compiler/rustc_query_impl/src/plumbing.rs | 2 +- compiler/rustc_span/src/source_map.rs | 10 ++-- .../src/traits/codegen.rs | 2 - .../src/traits/select/candidate_assembly.rs | 6 +-- .../src/traits/select/mod.rs | 46 ++++++++----------- .../rustc_trait_selection/src/traits/wf.rs | 2 +- compiler/rustc_ty_utils/src/ty.rs | 2 - compiler/rustc_typeck/src/astconv/mod.rs | 25 ++++------ compiler/rustc_typeck/src/check/_match.rs | 6 +-- compiler/rustc_typeck/src/check/closure.rs | 18 ++------ .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 7 +-- compiler/rustc_typeck/src/check/method/mod.rs | 29 ++---------- .../rustc_typeck/src/check/method/probe.rs | 12 +---- compiler/rustc_typeck/src/check/mod.rs | 1 - compiler/rustc_typeck/src/collect/type_of.rs | 1 - .../passes/collect_intra_doc_links.rs | 6 +-- 40 files changed, 117 insertions(+), 247 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index f5bd5cd3beae..8dc9368a0b99 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1139,7 +1139,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// include the CFG anyhow. /// - For each `end('x)` element in `'r`, compute the mutual LUB, yielding /// a result `'y`. - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "debug", ret)] pub(crate) fn universal_upper_bound(&self, r: RegionVid) -> RegionVid { debug!(r = %self.region_value_str(r)); @@ -1151,8 +1151,6 @@ impl<'tcx> RegionInferenceContext<'tcx> { lub = self.universal_region_relations.postdom_upper_bound(lub, ur); } - debug!(?lub); - lub } @@ -1333,15 +1331,15 @@ impl<'tcx> RegionInferenceContext<'tcx> { } // Evaluate whether `sup_region: sub_region`. - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "debug", ret)] fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool { debug!( - "eval_outlives: sup_region's value = {:?} universal={:?}", + "sup_region's value = {:?} universal={:?}", self.region_value_str(sup_region), self.universal_regions.is_universal_region(sup_region), ); debug!( - "eval_outlives: sub_region's value = {:?} universal={:?}", + "sub_region's value = {:?} universal={:?}", self.region_value_str(sub_region), self.universal_regions.is_universal_region(sub_region), ); @@ -1354,7 +1352,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // true if `'sup` outlives static. if !self.universe_compatible(sub_region_scc, sup_region_scc) { debug!( - "eval_outlives: sub universe `{sub_region_scc:?}` is not nameable \ + "sub universe `{sub_region_scc:?}` is not nameable \ by super `{sup_region_scc:?}`, promoting to static", ); @@ -1375,9 +1373,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { }); if !universal_outlives { - debug!( - "eval_outlives: returning false because sub region contains a universal region not present in super" - ); + debug!("sub region contains a universal region not present in super"); return false; } @@ -1386,15 +1382,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { if self.universal_regions.is_universal_region(sup_region) { // Micro-opt: universal regions contain all points. - debug!( - "eval_outlives: returning true because super is universal and hence contains all points" - ); + debug!("super is universal and hence contains all points"); return true; } - let result = self.scc_values.contains_points(sup_region_scc, sub_region_scc); - debug!("returning {} because of comparison between points in sup/sub", result); - result + debug!("comparison between points in sup/sub"); + + self.scc_values.contains_points(sup_region_scc, sub_region_scc) } /// Once regions have been propagated, this method is used to see @@ -1971,7 +1965,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } /// Finds some region R such that `fr1: R` and `R` is live at `elem`. - #[instrument(skip(self), level = "trace")] + #[instrument(skip(self), level = "trace", ret)] pub(crate) fn find_sub_region_live_at(&self, fr1: RegionVid, elem: Location) -> RegionVid { trace!(scc = ?self.constraint_sccs.scc(fr1)); trace!(universe = ?self.scc_universes[self.constraint_sccs.scc(fr1)]); diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 127cb4e40837..0392367288c4 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -60,7 +60,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// Calling `universal_upper_bound` for such a region gives `fr_fn_body`, /// which has no `external_name` in which case we use `'empty` as the /// region to pass to `infer_opaque_definition_from_instantiation`. - #[instrument(level = "debug", skip(self, infcx))] + #[instrument(level = "debug", skip(self, infcx), ret)] pub(crate) fn infer_opaque_types( &self, infcx: &InferCtxt<'_, 'tcx>, diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 2a7713bc4df3..b9b181681ec4 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -768,10 +768,9 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { mir_def_id: LocalDefId, indices: &mut UniversalRegionIndices<'tcx>, ) { - debug!("replace_late_bound_regions_with_nll_infer_vars(mir_def_id={:?})", mir_def_id); let typeck_root_def_id = self.tcx.typeck_root_def_id(mir_def_id.to_def_id()); for_each_late_bound_region_defined_on(self.tcx, typeck_root_def_id, |r| { - debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r); + debug!(?r); if !indices.indices.contains_key(&r) { let region_vid = self.next_nll_region_var(FR); debug!(?region_vid); diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index b46f71fc78a3..a2f14e753aeb 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -197,7 +197,7 @@ pub(super) fn op_to_const<'tcx>( } } -#[instrument(skip(tcx), level = "debug")] +#[instrument(skip(tcx), level = "debug", ret)] pub(crate) fn turn_into_const_value<'tcx>( tcx: TyCtxt<'tcx>, constant: ConstAlloc<'tcx>, @@ -224,10 +224,7 @@ pub(crate) fn turn_into_const_value<'tcx>( ); // Turn this into a proper constant. - let const_val = op_to_const(&ecx, &mplace.into()); - debug!(?const_val); - - const_val + op_to_const(&ecx, &mplace.into()) } #[instrument(skip(tcx), level = "debug")] diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 373b139c86e4..8b7c3cf3377c 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -204,7 +204,7 @@ fn get_info_on_unsized_field<'tcx>( (unsized_inner_ty, num_elems) } -#[instrument(skip(ecx), level = "debug")] +#[instrument(skip(ecx), level = "debug", ret)] fn create_pointee_place<'tcx>( ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>, ty: Ty<'tcx>, @@ -237,14 +237,11 @@ fn create_pointee_place<'tcx>( let ptr = ecx.allocate_ptr(size, align, MemoryKind::Stack).unwrap(); debug!(?ptr); - let place = MPlaceTy::from_aligned_ptr_with_meta( + MPlaceTy::from_aligned_ptr_with_meta( ptr.into(), layout, MemPlaceMeta::Meta(Scalar::from_machine_usize(num_elems as u64, &tcx)), - ); - debug!(?place); - - place + ) } else { create_mplace_from_layout(ecx, ty) } @@ -253,7 +250,7 @@ fn create_pointee_place<'tcx>( /// Converts a `ValTree` to a `ConstValue`, which is needed after mir /// construction has finished. // FIXME Merge `valtree_to_const_value` and `valtree_into_mplace` into one function -#[instrument(skip(tcx), level = "debug")] +#[instrument(skip(tcx), level = "debug", ret)] pub fn valtree_to_const_value<'tcx>( tcx: TyCtxt<'tcx>, param_env_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, @@ -294,7 +291,7 @@ pub fn valtree_to_const_value<'tcx>( dump_place(&ecx, place.into()); intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &place).unwrap(); - let const_val = match ty.kind() { + match ty.kind() { ty::Ref(_, _, _) => { let ref_place = place.to_ref(&tcx); let imm = @@ -303,10 +300,7 @@ pub fn valtree_to_const_value<'tcx>( op_to_const(&ecx, &imm.into()) } _ => op_to_const(&ecx, &place.into()), - }; - debug!(?const_val); - - const_val + } } ty::Never | ty::Error(_) diff --git a/compiler/rustc_driver/Cargo.toml b/compiler/rustc_driver/Cargo.toml index 4570c1448337..d1d02ed73f95 100644 --- a/compiler/rustc_driver/Cargo.toml +++ b/compiler/rustc_driver/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" crate-type = ["dylib"] [dependencies] -tracing = { version = "0.1.28" } +tracing = { version = "0.1.35" } serde_json = "1.0.59" rustc_log = { path = "../rustc_log" } rustc_middle = { path = "../rustc_middle" } diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 99d8f57505c2..d4350aa5734d 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -391,7 +391,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { /// Preconditions: /// /// - `for_vid` is a "root vid" - #[instrument(skip(self), level = "trace")] + #[instrument(skip(self), level = "trace", ret)] fn generalize( &self, ty: Ty<'tcx>, @@ -435,15 +435,8 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { cache: SsoHashMap::new(), }; - let ty = match generalize.relate(ty, ty) { - Ok(ty) => ty, - Err(e) => { - debug!(?e, "failure"); - return Err(e); - } - }; + let ty = generalize.relate(ty, ty)?; let needs_wf = generalize.needs_wf; - trace!(?ty, ?needs_wf, "success"); Ok(Generalization { ty, needs_wf }) } @@ -499,6 +492,7 @@ struct Generalizer<'cx, 'tcx> { /// Result from a generalization operation. This includes /// not only the generalized type, but also a bool flag /// indicating whether further WF checks are needed. +#[derive(Debug)] struct Generalization<'tcx> { ty: Ty<'tcx>, @@ -856,10 +850,9 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?)) } - #[instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self), ret)] fn tys(&mut self, t: Ty<'tcx>, _t: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { debug_assert_eq!(t, _t); - debug!("ConstInferUnifier: t={:?}", t); match t.kind() { &ty::Infer(ty::TyVar(vid)) => { @@ -883,12 +876,7 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { .borrow_mut() .type_variables() .new_var(self.for_universe, origin); - let u = self.tcx().mk_ty_var(new_var_id); - debug!( - "ConstInferUnifier: replacing original vid={:?} with new={:?}", - vid, u - ); - Ok(u) + Ok(self.tcx().mk_ty_var(new_var_id)) } } } @@ -939,7 +927,6 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { _c: ty::Const<'tcx>, ) -> RelateResult<'tcx, ty::Const<'tcx>> { debug_assert_eq!(c, _c); - debug!("ConstInferUnifier: c={:?}", c); match c.kind() { ty::ConstKind::Infer(InferConst::Var(vid)) => { diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs index d0d9efe152cc..67426fcf0fed 100644 --- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs +++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs @@ -69,7 +69,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// For more details visit the relevant sections of the [rustc dev guide]. /// /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html - #[instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self), ret)] pub fn replace_bound_vars_with_placeholders(&self, binder: ty::Binder<'tcx, T>) -> T where T: TypeFoldable<'tcx> + Copy, @@ -104,9 +104,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }, }; - let result = self.tcx.replace_bound_vars_uncached(binder, delegate); - debug!(?next_universe, ?result); - result + debug!(?next_universe); + self.tcx.replace_bound_vars_uncached(binder, delegate) } /// See [RegionConstraintCollector::leak_check][1]. diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index 3783cfb4cc5c..13b7e8eb9643 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -333,9 +333,9 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { /// /// Neither `a` nor `b` may be an inference variable (hence the /// term "concrete regions"). - #[instrument(level = "trace", skip(self))] + #[instrument(level = "trace", skip(self), ret)] fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> { - let r = match (*a, *b) { + match (*a, *b) { (ReLateBound(..), _) | (_, ReLateBound(..)) | (ReErased, _) | (_, ReErased) => { bug!("cannot relate region: LUB({:?}, {:?})", a, b); } @@ -399,11 +399,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { self.tcx().lifetimes.re_static } } - }; - - debug!("lub_concrete_regions({:?}, {:?}) = {:?}", a, b, r); - - r + } } /// After expansion is complete, go and check upper bounds (i.e., diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index e7e93116a66d..bb6f6ae60e26 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -542,7 +542,7 @@ where true } - #[instrument(skip(self, info), level = "trace")] + #[instrument(skip(self, info), level = "trace", ret)] fn relate_with_variance>( &mut self, variance: ty::Variance, @@ -560,8 +560,6 @@ where self.ambient_variance = old_ambient_variance; - debug!(?r); - Ok(r) } diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 233a5004a393..d45adf43abfc 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -390,7 +390,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }); } - #[instrument(skip(self), level = "trace")] + #[instrument(skip(self), level = "trace", ret)] pub fn opaque_type_origin(&self, def_id: LocalDefId, span: Span) -> Option { let opaque_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); let parent_def_id = match self.defining_use_anchor { @@ -421,16 +421,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { in_definition_scope.then_some(*origin) } - #[instrument(skip(self), level = "trace")] + #[instrument(skip(self), level = "trace", ret)] fn opaque_ty_origin_unchecked(&self, def_id: LocalDefId, span: Span) -> OpaqueTyOrigin { - let origin = match self.tcx.hir().expect_item(def_id).kind { + match self.tcx.hir().expect_item(def_id).kind { hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => origin, ref itemkind => { span_bug!(span, "weird opaque type: {:?}, {:#?}", def_id, itemkind) } - }; - trace!(?origin); - origin + } } } diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs index fb12da0cc13f..4d124554afb9 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/table.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs @@ -29,7 +29,7 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { } } - #[instrument(level = "debug")] + #[instrument(level = "debug", ret)] pub fn take_opaque_types(&mut self) -> OpaqueTypeMap<'tcx> { std::mem::take(&mut self.opaque_types) } diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index 2a085288fb7c..2d19d1823fdf 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -9,7 +9,7 @@ pub mod verify; use rustc_middle::traits::query::OutlivesBound; use rustc_middle::ty; -#[instrument(level = "debug", skip(param_env))] +#[instrument(level = "debug", skip(param_env), ret)] pub fn explicit_outlives_bounds<'tcx>( param_env: ty::ParamEnv<'tcx>, ) -> impl Iterator> + 'tcx { diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 560d9fde0492..f3676604bb0e 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2267,7 +2267,7 @@ impl<'tcx> ConstantKind<'tcx> { Self::from_opt_const_arg_anon_const(tcx, ty::WithOptConstParam::unknown(def_id), param_env) } - #[instrument(skip(tcx), level = "debug")] + #[instrument(skip(tcx), level = "debug", ret)] pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let body_id = match tcx.hir().get(hir_id) { @@ -2305,21 +2305,18 @@ impl<'tcx> ConstantKind<'tcx> { let substs = ty::InlineConstSubsts::new(tcx, ty::InlineConstSubstsParts { parent_substs, ty }) .substs; - let uneval_const = tcx.mk_const(ty::ConstS { + debug_assert!(!substs.has_free_regions()); + Self::Ty(tcx.mk_const(ty::ConstS { kind: ty::ConstKind::Unevaluated(ty::Unevaluated { def: ty::WithOptConstParam::unknown(def_id).to_global(), substs, promoted: None, }), ty, - }); - debug!(?uneval_const); - debug_assert!(!uneval_const.has_free_regions()); - - Self::Ty(uneval_const) + })) } - #[instrument(skip(tcx), level = "debug")] + #[instrument(skip(tcx), level = "debug", ret)] fn from_opt_const_arg_anon_const( tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam, @@ -2402,24 +2399,21 @@ impl<'tcx> ConstantKind<'tcx> { match tcx.const_eval_resolve(param_env, uneval, Some(span)) { Ok(val) => { - debug!("evaluated const value: {:?}", val); + debug!("evaluated const value"); Self::Val(val, ty) } Err(_) => { debug!("error encountered during evaluation"); // Error was handled in `const_eval_resolve`. Here we just create a // new unevaluated const and error hard later in codegen - let ty_const = tcx.mk_const(ty::ConstS { + Self::Ty(tcx.mk_const(ty::ConstS { kind: ty::ConstKind::Unevaluated(ty::Unevaluated { def: def.to_global(), substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()), promoted: None, }), ty, - }); - debug!(?ty_const); - - Self::Ty(ty_const) + })) } } } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index f8792edc017b..2eb5cffa6bc4 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -65,8 +65,6 @@ impl<'tcx> Const<'tcx> { tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam, ) -> Self { - debug!("Const::from_anon_const(def={:?})", def); - let body_id = match tcx.hir().get_by_def_id(def.did) { hir::Node::AnonConst(ac) => ac.body, _ => span_bug!( diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 5e96e278b9ca..cb46a9dba579 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -353,7 +353,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> { t } - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "debug", ret)] fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match *r { ty::ReLateBound(debruijn, _) if debruijn < self.current_index => { diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index 9d8a81165943..cac8560ce1c3 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -188,13 +188,11 @@ struct NormalizeAfterErasingRegionsFolder<'tcx> { } impl<'tcx> NormalizeAfterErasingRegionsFolder<'tcx> { - #[instrument(skip(self), level = "debug")] fn normalize_generic_arg_after_erasing_regions( &self, arg: ty::GenericArg<'tcx>, ) -> ty::GenericArg<'tcx> { let arg = self.param_env.and(arg); - debug!(?arg); self.tcx.try_normalize_generic_arg_after_erasing_regions(arg).unwrap_or_else(|_| bug!( "Failed to normalize {:?}, maybe try to call `try_normalize_erasing_regions` instead", diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index 541dace5cc2b..ac79949fca5c 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -256,7 +256,6 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait } // Query provider for `incoherent_impls`. -#[instrument(level = "debug", skip(tcx))] pub(super) fn incoherent_impls_provider(tcx: TyCtxt<'_>, simp: SimplifiedType) -> &[DefId] { let mut impls = Vec::new(); diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 591bb7831b5b..a3837512bce2 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -627,7 +627,7 @@ impl<'tcx> TyCtxt<'tcx> { } /// Expands the given impl trait type, stopping if the type is recursive. - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "debug", ret)] pub fn try_expand_impl_trait_type( self, def_id: DefId, @@ -644,7 +644,6 @@ impl<'tcx> TyCtxt<'tcx> { }; let expanded_type = visitor.expand_opaque_ty(def_id, substs).unwrap(); - trace!(?expanded_type); if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) } } diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index 5365067209af..5e042c3acfce 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -84,7 +84,7 @@ pub trait TypeVisitable<'tcx>: fmt::Debug + Clone { self.has_vars_bound_at_or_above(ty::INNERMOST) } - #[instrument(level = "trace")] + #[instrument(level = "trace", ret)] fn has_type_flags(&self, flags: TypeFlags) -> bool { self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags) } @@ -560,7 +560,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { type BreakTy = FoundFlags; #[inline] - #[instrument(skip(self), level = "trace")] + #[instrument(skip(self), level = "trace", ret)] fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { let flags = t.flags(); trace!(t.flags=?t.flags()); @@ -572,7 +572,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { } #[inline] - #[instrument(skip(self), level = "trace")] + #[instrument(skip(self), level = "trace", ret)] fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow { let flags = r.type_flags(); trace!(r.flags=?flags); @@ -584,7 +584,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { } #[inline] - #[instrument(level = "trace")] + #[instrument(level = "trace", ret)] fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow { let flags = FlagComputation::for_const(c); trace!(r.flags=?flags); @@ -596,7 +596,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { } #[inline] - #[instrument(level = "trace")] + #[instrument(level = "trace", ret)] fn visit_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow { let flags = FlagComputation::for_unevaluated_const(uv); trace!(r.flags=?flags); @@ -608,7 +608,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { } #[inline] - #[instrument(level = "trace")] + #[instrument(level = "trace", ret)] fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow { debug!( "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}", diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index f2045ac19cac..210d77c66e70 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -19,7 +19,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { /// Converts an evaluated constant to a pattern (if possible). /// This means aggregate values (like structs and enums) are converted /// to a pattern that matches the value (as if you'd compared via structural equality). - #[instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self), ret)] pub(super) fn const_to_pat( &self, cv: mir::ConstantKind<'tcx>, @@ -27,13 +27,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { span: Span, mir_structural_match_violation: bool, ) -> Pat<'tcx> { - let pat = self.tcx.infer_ctxt().enter(|infcx| { + self.tcx.infer_ctxt().enter(|infcx| { let mut convert = ConstToPat::new(self, id, span, infcx); convert.to_pat(cv, mir_structural_match_violation) - }); - - debug!(?pat); - pat + }) } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 443626d14b9f..319183eb9b33 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -791,7 +791,7 @@ fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>( /// `is_under_guard` is used to inform if the pattern has a guard. If it /// has one it must not be inserted into the matrix. This shouldn't be /// relied on for soundness. -#[instrument(level = "debug", skip(cx, matrix, hir_id))] +#[instrument(level = "debug", skip(cx, matrix, hir_id), ret)] fn is_useful<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, matrix: &Matrix<'p, 'tcx>, @@ -917,7 +917,6 @@ fn is_useful<'p, 'tcx>( v.head().set_reachable(); } - debug!(?ret); ret } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 170616d4b42c..6ec5e9e113d1 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -419,7 +419,6 @@ fn collect_items_rec<'tcx>( // We've been here already, no need to search again. return; } - debug!("BEGIN collect_items_rec({})", starting_point.node); let mut neighbors = MonoItems { compute_inlining: true, tcx, items: Vec::new() }; let recursion_depth_reset; @@ -545,8 +544,6 @@ fn collect_items_rec<'tcx>( if let Some((def_id, depth)) = recursion_depth_reset { recursion_depths.insert(def_id, depth); } - - debug!("END collect_items_rec({})", starting_point.node); } /// Format instance name that is already known to be too long for rustc. @@ -1148,23 +1145,18 @@ fn find_vtable_types_for_unsizing<'tcx>( } } -#[instrument(skip(tcx), level = "debug")] +#[instrument(skip(tcx), level = "debug", ret)] fn create_fn_mono_item<'tcx>( tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, source: Span, ) -> Spanned> { - debug!("create_fn_mono_item(instance={})", instance); - let def_id = instance.def_id(); if tcx.sess.opts.unstable_opts.profile_closures && def_id.is_local() && tcx.is_closure(def_id) { crate::util::dump_closure_profile(tcx, instance); } - let respanned = respan(source, MonoItem::Fn(instance.polymorphize(tcx))); - debug!(?respanned); - - respanned + respan(source, MonoItem::Fn(instance.polymorphize(tcx))) } /// Creates a `MonoItem` for each method that is referenced by the vtable for @@ -1309,7 +1301,7 @@ impl<'v> RootCollector<'_, 'v> { #[instrument(skip(self), level = "debug")] fn push_if_root(&mut self, def_id: LocalDefId) { if self.is_root(def_id) { - debug!("RootCollector::push_if_root: found root def_id={:?}", def_id); + debug!("found root"); let instance = Instance::mono(self.tcx, def_id.to_def_id()); self.output.push(create_fn_mono_item(self.tcx, instance, DUMMY_SP)); diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index 6e4ab2a35c33..af4b35db3bac 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -33,7 +33,6 @@ pub fn provide(providers: &mut Providers) { /// /// Returns a bitset where bits representing unused parameters are set (`is_empty` indicates all /// parameters are used). -#[instrument(level = "debug", skip(tcx))] fn unused_generic_params<'tcx>( tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>, diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index f38f29e14afd..eabb31661474 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -555,7 +555,7 @@ macro_rules! define_queries_struct { $($(#[$attr])* #[inline(always)] - #[tracing::instrument(level = "trace", skip(self, tcx))] + #[tracing::instrument(level = "trace", skip(self, tcx), ret)] fn $name( &'tcx self, tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 8ffbbff7a7dc..4d94c92d3f2b 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -1059,13 +1059,13 @@ impl FilePathMapping { return remap_path_prefix(&self.mapping, path); - #[instrument(level = "debug", skip(mapping))] + #[instrument(level = "debug", skip(mapping), ret)] fn remap_path_prefix(mapping: &[(PathBuf, PathBuf)], path: PathBuf) -> (PathBuf, bool) { // NOTE: We are iterating over the mapping entries from last to first // because entries specified later on the command line should // take precedence. for &(ref from, ref to) in mapping.iter().rev() { - debug!("Trying to apply {:?} => {:?}", from, to); + debug!("Trying to apply {from:?} => {to:?}"); if let Ok(rest) = path.strip_prefix(from) { let remapped = if rest.as_os_str().is_empty() { @@ -1079,15 +1079,15 @@ impl FilePathMapping { } else { to.join(rest) }; - debug!("Match - remapped {:?} => {:?}", path, remapped); + debug!("Match - remapped"); return (remapped, true); } else { - debug!("No match - prefix {:?} does not match {:?}", from, path); + debug!("No match - prefix {from:?} does not match"); } } - debug!("Path {:?} was not remapped", path); + debug!("not remapped"); (path, false) } } diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs index c0700748c79f..26f8e7d34c6e 100644 --- a/compiler/rustc_trait_selection/src/traits/codegen.rs +++ b/compiler/rustc_trait_selection/src/traits/codegen.rs @@ -18,7 +18,6 @@ use rustc_middle::ty::{self, TyCtxt}; /// obligations *could be* resolved if we wanted to. /// /// This also expects that `trait_ref` is fully normalized. -#[instrument(level = "debug", skip(tcx))] pub fn codegen_fulfill_obligation<'tcx>( tcx: TyCtxt<'tcx>, (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>), @@ -74,7 +73,6 @@ pub fn codegen_fulfill_obligation<'tcx>( // (ouz-a) This is required for `type-alias-impl-trait/assoc-projection-ice.rs` to pass let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); - debug!("Cache miss: {trait_ref:?} => {impl_source:?}"); Ok(&*tcx.arena.alloc(impl_source)) }) } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index cfd9d711894e..e84c462ca816 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -28,7 +28,7 @@ use super::SelectionCandidate::{self, *}; use super::{EvaluatedCandidate, SelectionCandidateSet, SelectionContext, TraitObligationStack}; impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { - #[instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self), ret)] pub(super) fn candidate_from_obligation<'o>( &mut self, stack: &TraitObligationStack<'o, 'tcx>, @@ -48,7 +48,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if let Some(c) = self.check_candidate_cache(stack.obligation.param_env, cache_fresh_trait_pred) { - debug!(candidate = ?c, "CACHE HIT"); + debug!("CACHE HIT"); return c; } @@ -61,7 +61,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let (candidate, dep_node) = self.in_task(|this| this.candidate_from_obligation_no_cache(stack)); - debug!(?candidate, "CACHE MISS"); + debug!("CACHE MISS"); self.insert_candidate_cache( stack.obligation.param_env, cache_fresh_trait_pred, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 83838b70fb25..5da8cfab0b13 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -295,7 +295,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Attempts to satisfy the obligation. If successful, this will affect the surrounding /// type environment by performing unification. - #[instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self), ret)] pub fn select( &mut self, obligation: &TraitObligation<'tcx>, @@ -325,10 +325,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Err(SelectionError::Overflow(OverflowError::Canonical)) } Err(e) => Err(e), - Ok(candidate) => { - debug!(?candidate, "confirmed"); - Ok(Some(candidate)) - } + Ok(candidate) => Ok(Some(candidate)), } } @@ -435,6 +432,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { level = "debug", skip(self, previous_stack), fields(previous_stack = ?previous_stack.head()) + ret, )] fn evaluate_predicate_recursively<'o>( &mut self, @@ -450,7 +448,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { None => self.check_recursion_limit(&obligation, &obligation)?, } - let result = ensure_sufficient_stack(|| { + ensure_sufficient_stack(|| { let bound_predicate = obligation.predicate.kind(); match bound_predicate.skip_binder() { ty::PredicateKind::Trait(t) => { @@ -760,14 +758,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { bug!("TypeWellFormedFromEnv is only used for chalk") } } - }); - - debug!("finished: {:?} from {:?}", result, obligation); - - result + }) } - #[instrument(skip(self, previous_stack), level = "debug")] + #[instrument(skip(self, previous_stack), level = "debug", ret)] fn evaluate_trait_predicate_recursively<'o>( &mut self, previous_stack: TraitObligationStackList<'o, 'tcx>, @@ -798,12 +792,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // If a trait predicate is in the (local or global) evaluation cache, // then we know it holds without cycles. if let Some(result) = self.check_evaluation_cache(param_env, fresh_trait_pred) { - debug!(?result, "CACHE HIT"); + debug!("CACHE HIT"); return Ok(result); } if let Some(result) = stack.cache().get_provisional(fresh_trait_pred) { - debug!(?result, "PROVISIONAL CACHE HIT"); + debug!("PROVISIONAL CACHE HIT"); stack.update_reached_depth(result.reached_depth); return Ok(result.result); } @@ -826,11 +820,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let reached_depth = stack.reached_depth.get(); if reached_depth >= stack.depth { - debug!(?result, "CACHE MISS"); + debug!("CACHE MISS"); self.insert_evaluation_cache(param_env, fresh_trait_pred, dep_node, result); stack.cache().on_completion(stack.dfn); } else { - debug!(?result, "PROVISIONAL"); + debug!("PROVISIONAL"); debug!( "caching provisionally because {:?} \ is a cycle participant (at depth {}, reached depth {})", @@ -1023,7 +1017,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { #[instrument( level = "debug", skip(self, stack), - fields(depth = stack.obligation.recursion_depth) + fields(depth = stack.obligation.recursion_depth), + ret )] fn evaluate_candidate<'o>( &mut self, @@ -1056,7 +1051,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { result = result.max(EvaluatedToOkModuloRegions); } - debug!(?result); Ok(result) } @@ -1405,7 +1399,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// a projection, look at the bounds of `T::Bar`, see if we can find a /// `Baz` bound. We return indexes into the list returned by /// `tcx.item_bounds` for any applicable bounds. - #[instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self), ret)] fn match_projection_obligation_against_definition_bounds( &mut self, obligation: &TraitObligation<'tcx>, @@ -1435,7 +1429,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // unnecessary ambiguity. let mut distinct_normalized_bounds = FxHashSet::default(); - let matching_bounds = bounds + bounds .iter() .enumerate() .filter_map(|(idx, bound)| { @@ -1462,10 +1456,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } None }) - .collect(); - - debug!(?matching_bounds); - matching_bounds + .collect() } /// Equates the trait in `obligation` with trait bound. If the two traits @@ -2153,7 +2144,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - #[instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self), ret)] fn match_impl( &mut self, impl_def_id: DefId, @@ -2194,17 +2185,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .at(&cause, obligation.param_env) .define_opaque_types(false) .eq(placeholder_obligation_trait_ref, impl_trait_ref) - .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{}`", e))?; + .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{e}`"))?; nested_obligations.extend(obligations); if !self.intercrate && self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation { - debug!("match_impl: reservation impls only apply in intercrate mode"); + debug!("reservation impls only apply in intercrate mode"); return Err(()); } - debug!(?impl_substs, ?nested_obligations, "match_impl: success"); Ok(Normalized { value: impl_substs, obligations: nested_obligations }) } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 4bd179d23913..bb6009cb22a3 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -841,7 +841,7 @@ pub fn object_region_bounds<'tcx>( /// /// Requires that trait definitions have been processed so that we can /// elaborate predicates and walk supertraits. -#[instrument(skip(tcx, predicates), level = "debug")] +#[instrument(skip(tcx, predicates), level = "debug", ret)] pub(crate) fn required_region_bounds<'tcx>( tcx: TyCtxt<'tcx>, erased_self_ty: Ty<'tcx>, diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index acfeefb4d12d..9d640672cf92 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -104,7 +104,6 @@ fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtSizedConstrain } /// See `ParamEnv` struct definition for details. -#[instrument(level = "debug", skip(tcx))] fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { // The param_env of an impl Trait type is its defining function's param_env if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) { @@ -410,7 +409,6 @@ fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync { } /// Don't call this directly: use ``tcx.conservative_is_privately_uninhabited`` instead. -#[instrument(level = "debug", skip(tcx))] pub fn conservative_is_privately_uninhabited_raw<'tcx>( tcx: TyCtxt<'tcx>, param_env_and: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 72778c8b76a8..ef927058df4e 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -144,7 +144,7 @@ enum ConvertedBindingKind<'a, 'tcx> { /// instantiated with some generic arguments providing `'a` explicitly, /// we taint those arguments with `ExplicitLateBound::Yes` so that we /// can provide an appropriate diagnostic later. -#[derive(Copy, Clone, PartialEq)] +#[derive(Copy, Clone, PartialEq, Debug)] pub enum ExplicitLateBound { Yes, No, @@ -167,7 +167,7 @@ pub(crate) enum GenericArgPosition { /// A marker denoting that the generic arguments that were /// provided did not match the respective generic parameters. -#[derive(Clone, Default)] +#[derive(Clone, Default, Debug)] pub struct GenericArgCountMismatch { /// Indicates whether a fatal error was reported (`Some`), or just a lint (`None`). pub reported: Option, @@ -177,7 +177,7 @@ pub struct GenericArgCountMismatch { /// Decorates the result of a generic argument count mismatch /// check with whether explicit late bounds were provided. -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct GenericArgCountResult { pub explicit_late_bound: ExplicitLateBound, pub correct: Result<(), GenericArgCountMismatch>, @@ -201,7 +201,7 @@ pub trait CreateSubstsForGenericArgsCtxt<'a, 'tcx> { } impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { - #[instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self), ret)] pub fn ast_region_to_region( &self, lifetime: &hir::Lifetime, @@ -210,7 +210,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let tcx = self.tcx(); let lifetime_name = |def_id| tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id)); - let r = match tcx.named_region(lifetime.hir_id) { + match tcx.named_region(lifetime.hir_id) { Some(rl::Region::Static) => tcx.lifetimes.re_static, Some(rl::Region::LateBound(debruijn, index, def_id)) => { @@ -255,9 +255,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx.lifetimes.re_static }) } - }; - debug!("ast_region_to_region(lifetime={:?}) yields {:?}", lifetime, r); - r + } } /// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`, @@ -317,7 +315,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// `[Vec, u8]` and `generic_args` are the arguments for the associated /// type itself: `['a]`. The returned `SubstsRef` concatenates these two /// lists: `[Vec, u8, 'a]`. - #[instrument(level = "debug", skip(self, span))] + #[instrument(level = "debug", skip(self, span), ret)] fn create_substs_for_ast_path<'a>( &self, span: Span, @@ -537,11 +535,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &mut substs_ctx, ); - debug!( - "create_substs_for_ast_path(generic_params={:?}, self_ty={:?}) -> {:?}", - generics, self_ty, substs - ); - (substs, arg_count) } @@ -2596,7 +2589,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// Turns a `hir::Ty` into a `Ty`. For diagnostics' purposes we keep track of whether trait /// objects are borrowed like `&dyn Trait` to avoid emitting redundant errors. - #[instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self), ret)] fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool) -> Ty<'tcx> { let tcx = self.tcx(); @@ -2700,8 +2693,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { hir::TyKind::Err => tcx.ty_error(), }; - debug!(?result_ty); - self.record_ty(ast_ty.hir_id, result_ty, ast_ty.span); result_ty } diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs index 2d50412007d9..25bafdfe859b 100644 --- a/compiler/rustc_typeck/src/check/_match.rs +++ b/compiler/rustc_typeck/src/check/_match.rs @@ -12,7 +12,7 @@ use rustc_trait_selection::traits::{ }; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "debug", ret)] pub fn check_match( &self, expr: &'tcx hir::Expr<'tcx>, @@ -212,9 +212,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We won't diverge unless the scrutinee or all arms diverge. self.diverges.set(scrut_diverges | all_arms_diverge); - let match_ty = coercion.complete(self); - debug!(?match_ty); - match_ty + coercion.complete(self) } /// When the previously checked expression (the scrutinee) diverges, diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs index fee872155f5b..bc3fec6e7d66 100644 --- a/compiler/rustc_typeck/src/check/closure.rs +++ b/compiler/rustc_typeck/src/check/closure.rs @@ -58,7 +58,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_closure(expr, expected_kind, decl, body, gen, expected_sig) } - #[instrument(skip(self, expr, body, decl), level = "debug")] + #[instrument(skip(self, expr, body, decl), level = "debug", ret)] fn check_closure( &self, expr: &hir::Expr<'_>, @@ -158,11 +158,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, ); - let closure_type = self.tcx.mk_closure(expr_def_id.to_def_id(), closure_substs.substs); - - debug!(?expr.hir_id, ?closure_type); - - closure_type + self.tcx.mk_closure(expr_def_id.to_def_id(), closure_substs.substs) } /// Given the expected type, figures out what it can about this closure we @@ -262,7 +258,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// The `cause_span` should be the span that caused us to /// have this expected signature, or `None` if we can't readily /// know that. - #[instrument(level = "debug", skip(self, cause_span))] + #[instrument(level = "debug", skip(self, cause_span), ret)] fn deduce_sig_from_projection( &self, cause_span: Option, @@ -317,7 +313,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::Unsafety::Normal, Abi::Rust, )); - debug!(?sig); Some(ExpectedSig { cause_span, sig }) } @@ -576,7 +571,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// types that the user gave into a signature. /// /// Also, record this closure signature for later. - #[instrument(skip(self, decl, body), level = "debug")] + #[instrument(skip(self, decl, body), level = "debug", ret)] fn supplied_sig_of_closure( &self, hir_id: hir::HirId, @@ -629,8 +624,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { bound_vars, ); - debug!(?result); - let c_result = self.inh.infcx.canonicalize_response(result); self.typeck_results.borrow_mut().user_provided_sigs.insert(expr_def_id, c_result); @@ -643,7 +636,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// user specified. The "desugared" return type is an `impl /// Future`, so we do this by searching through the /// obligations to extract the `T`. - #[instrument(skip(self), level = "debug")] + #[instrument(skip(self), level = "debug", ret)] fn deduce_future_output_from_obligations( &self, expr_def_id: DefId, @@ -704,7 +697,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); self.register_predicates(obligations); - debug!("deduce_future_output_from_obligations: output_ty={:?}", output_ty); Some(output_ty) } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 63cdf2cc1f0c..66b737a49305 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -83,7 +83,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.resolve_vars_with_obligations_and_mutate_fulfillment(ty, |_| {}) } - #[instrument(skip(self, mutate_fulfillment_errors), level = "debug")] + #[instrument(skip(self, mutate_fulfillment_errors), level = "debug", ret)] pub(in super::super) fn resolve_vars_with_obligations_and_mutate_fulfillment( &self, mut ty: Ty<'tcx>, @@ -107,10 +107,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // indirect dependencies that don't seem worth tracking // precisely. self.select_obligations_where_possible(false, mutate_fulfillment_errors); - ty = self.resolve_vars_if_possible(ty); - - debug!(?ty); - ty + self.resolve_vars_if_possible(ty) } pub(in super::super) fn record_deferred_call_resolution( diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs index de26a9e56e2d..a9071cd1fd94 100644 --- a/compiler/rustc_typeck/src/check/method/mod.rs +++ b/compiler/rustc_typeck/src/check/method/mod.rs @@ -168,7 +168,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// * `call_expr`: the complete method call: (`foo.bar::(...)`) /// * `self_expr`: the self expression (`foo`) /// * `args`: the expressions of the arguments (`a, b + 1, ...`) - #[instrument(level = "debug", skip(self, call_expr, self_expr))] + #[instrument(level = "debug", skip(self))] pub fn lookup_method( &self, self_ty: Ty<'tcx>, @@ -178,11 +178,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self_expr: &'tcx hir::Expr<'tcx>, args: &'tcx [hir::Expr<'tcx>], ) -> Result, MethodError<'tcx>> { - debug!( - "lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})", - segment.ident, self_ty, call_expr, self_expr - ); - let pick = self.lookup_probe(span, segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?; @@ -383,7 +378,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// In particular, it doesn't really do any probing: it simply constructs /// an obligation for a particular trait with the given self type and checks /// whether that trait is implemented. - #[instrument(level = "debug", skip(self, span, opt_input_types))] + #[instrument(level = "debug", skip(self, span))] pub(super) fn lookup_method_in_trait( &self, span: Span, @@ -392,11 +387,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self_ty: Ty<'tcx>, opt_input_types: Option<&[Ty<'tcx>]>, ) -> Option>> { - debug!( - "lookup_in_trait_adjusted(self_ty={:?}, m_name={}, trait_def_id={:?}, opt_input_types={:?})", - self_ty, m_name, trait_def_id, opt_input_types - ); - let (obligation, substs) = self.obligation_for_method(span, trait_def_id, self_ty, opt_input_types); self.construct_obligation_for_trait( @@ -576,7 +566,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// * `self_ty`: the type to search within (`Foo`) /// * `self_ty_span` the span for the type being searched within (span of `Foo`) /// * `expr_id`: the [`hir::HirId`] of the expression composing the entire call - #[instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self), ret)] pub fn resolve_fully_qualified_call( &self, span: Span, @@ -585,11 +575,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self_ty_span: Span, expr_id: hir::HirId, ) -> Result<(DefKind, DefId), MethodError<'tcx>> { - debug!( - "resolve_fully_qualified_call: method_name={:?} self_ty={:?} expr_id={:?}", - method_name, self_ty, expr_id, - ); - let tcx = self.tcx; // Check if we have an enum variant. @@ -633,21 +618,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &pick, ); - debug!("resolve_fully_qualified_call: pick={:?}", pick); + debug!(?pick); { let mut typeck_results = self.typeck_results.borrow_mut(); let used_trait_imports = Lrc::get_mut(&mut typeck_results.used_trait_imports).unwrap(); for import_id in pick.import_ids { - debug!("resolve_fully_qualified_call: used_trait_import: {:?}", import_id); + debug!(used_trait_import=?import_id); used_trait_imports.insert(import_id); } } let def_kind = pick.item.kind.as_def_kind(); - debug!( - "resolve_fully_qualified_call: def_kind={:?}, def_id={:?}", - def_kind, pick.item.def_id - ); tcx.check_stability(pick.item.def_id, Some(expr_id), span, Some(method_name.span)); Ok((def_kind, pick.item.def_id)) } diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index d9870060a40b..e9f55ab3406f 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -253,7 +253,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// would result in an error (basically, the same criteria we /// would use to decide if a method is a plausible fit for /// ambiguity purposes). - #[instrument(level = "debug", skip(self, scope_expr_id))] + #[instrument(level = "debug", skip(self))] pub fn probe_for_return_type( &self, span: Span, @@ -262,10 +262,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self_ty: Ty<'tcx>, scope_expr_id: hir::HirId, ) -> Vec { - debug!( - "probe(self_ty={:?}, return_type={}, scope_expr_id={})", - self_ty, return_type, scope_expr_id - ); let method_names = self .probe_op( span, @@ -299,7 +295,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .collect() } - #[instrument(level = "debug", skip(self, scope_expr_id))] + #[instrument(level = "debug", skip(self))] pub fn probe_for_name( &self, span: Span, @@ -310,10 +306,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { scope_expr_id: hir::HirId, scope: ProbeScope, ) -> PickResult<'tcx> { - debug!( - "probe(self_ty={:?}, item_name={}, scope_expr_id={})", - self_ty, item_name, scope_expr_id - ); self.probe_op( span, mode, diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 3281dd8298bc..66281448d40e 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -341,7 +341,6 @@ fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::T typeck_with_fallback(tcx, def_id, fallback) } -#[instrument(skip(tcx, fallback))] fn typeck_with_fallback<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index f1dbe64f13ab..9f931de6fded 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -19,7 +19,6 @@ use crate::errors::UnconstrainedOpaqueType; /// Computes the relevant generic parameter for a potential generic const argument. /// /// This should be called using the query `tcx.opt_const_param_of`. -#[instrument(level = "debug", skip(tcx))] pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { use hir::*; let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 39d3b43cf32e..c27f0ce18c14 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -750,7 +750,7 @@ fn resolve_associated_trait_item<'a>( /// /// This is just a wrapper around [`TyCtxt::impl_item_implementor_ids()`] and /// [`TyCtxt::associated_item()`] (with some helpful logging added). -#[instrument(level = "debug", skip(tcx))] +#[instrument(level = "debug", skip(tcx), ret)] fn trait_assoc_to_impl_assoc_item<'tcx>( tcx: TyCtxt<'tcx>, impl_id: DefId, @@ -760,9 +760,7 @@ fn trait_assoc_to_impl_assoc_item<'tcx>( debug!(?trait_to_impl_assoc_map); let impl_assoc_id = *trait_to_impl_assoc_map.get(&trait_assoc_id)?; debug!(?impl_assoc_id); - let impl_assoc = tcx.associated_item(impl_assoc_id); - debug!(?impl_assoc); - Some(impl_assoc) + Some(tcx.associated_item(impl_assoc_id)) } /// Given a type, return all trait impls in scope in `module` for that type. From 3f1f694ca5845131782d69f0598b0f6e5b3ae3d5 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 31 Aug 2022 14:46:51 +0000 Subject: [PATCH 4047/5092] Adjust stderr file --- src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs | 2 +- .../ui-fulldeps/session-diagnostic/diagnostic-derive.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs index b1f557cb94de..c1c109ac1ead 100644 --- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs +++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs @@ -2,7 +2,7 @@ // Tests error conditions for specifying diagnostics using #[derive(SessionDiagnostic)] // normalize-stderr-test "the following other types implement trait `IntoDiagnosticArg`:(?:.*\n){0,9}\s+and \d+ others" -> "normalized in stderr" - +// normalize-stderr-test "diagnostic_builder\.rs:[0-9]+:[0-9]+" -> "diagnostic_builder.rs:LL:CC" // The proc_macro2 crate handles spans differently when on beta/stable release rather than nightly, // changing the output of this test. Since SessionDiagnostic is strictly internal to the compiler // the test is just ignored on stable and beta: diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index 621c59f44895..ab5c28fe4733 100644 --- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -453,7 +453,7 @@ LL | #[derive(SessionDiagnostic)] | = help: normalized in stderr note: required by a bound in `DiagnosticBuilder::<'a, G>::set_arg` - --> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:569:19 + --> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:LL:CC | LL | arg: impl IntoDiagnosticArg, | ^^^^^^^^^^^^^^^^^ required by this bound in `DiagnosticBuilder::<'a, G>::set_arg` From 9d0542b76d801b09097a56a2bacce0acf60c849d Mon Sep 17 00:00:00 2001 From: Adam-Gleave Date: Thu, 1 Sep 2022 16:09:25 +0100 Subject: [PATCH 4048/5092] Document eager evaluation of `bool::then_some` argument --- library/core/src/bool.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/core/src/bool.rs b/library/core/src/bool.rs index f7a8aa0d9215..267d787483d5 100644 --- a/library/core/src/bool.rs +++ b/library/core/src/bool.rs @@ -6,6 +6,12 @@ impl bool { /// Returns `Some(t)` if the `bool` is [`true`](../std/keyword.true.html), /// or `None` otherwise. /// + /// Arguments passed to `then_some` are eagerly evaluated; if you are + /// passing the result of a function call, it is recommended to use + /// [`then`], which is lazily evaluated. + /// + /// [`then`]: bool::then + /// /// # Examples /// /// ``` From 3e834a7a6295127fe2a5dd8605c7903ad7e5918d Mon Sep 17 00:00:00 2001 From: 111 Date: Fri, 26 Aug 2022 11:24:09 +0800 Subject: [PATCH 4049/5092] Migrate DropCheckOverflow --- .../rustc_error_messages/locales/en-US/middle.ftl | 3 +++ compiler/rustc_error_messages/src/lib.rs | 1 + compiler/rustc_middle/src/error.rs | 14 ++++++++++++++ compiler/rustc_middle/src/lib.rs | 1 + compiler/rustc_middle/src/traits/query.rs | 13 +++---------- 5 files changed, 22 insertions(+), 10 deletions(-) create mode 100644 compiler/rustc_error_messages/locales/en-US/middle.ftl create mode 100644 compiler/rustc_middle/src/error.rs diff --git a/compiler/rustc_error_messages/locales/en-US/middle.ftl b/compiler/rustc_error_messages/locales/en-US/middle.ftl new file mode 100644 index 000000000000..f2864ec4922e --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/middle.ftl @@ -0,0 +1,3 @@ +middle_drop_check_overflow = + overflow while adding drop-check rules for {$ty} + .note = {$note} diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 8f47be25db91..ebd56b4e084d 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -45,6 +45,7 @@ fluent_messages! { interface => "../locales/en-US/interface.ftl", infer => "../locales/en-US/infer.ftl", lint => "../locales/en-US/lint.ftl", + middle => "../locales/en-US/middle.ftl", monomorphize => "../locales/en-US/monomorphize.ftl", parser => "../locales/en-US/parser.ftl", passes => "../locales/en-US/passes.ftl", diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs new file mode 100644 index 000000000000..d81eb5241697 --- /dev/null +++ b/compiler/rustc_middle/src/error.rs @@ -0,0 +1,14 @@ +use rustc_macros::SessionDiagnostic; +use rustc_span::Span; + +use crate::ty::Ty; + +#[derive(SessionDiagnostic)] +#[diag(middle::drop_check_overflow, code = "E0320")] +#[note] +pub struct DropCheckOverflow<'tcx> { + #[primary_span] + pub span: Span, + pub ty: Ty<'tcx>, + pub note: String, +} diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index be9e5865e541..1e3a6bcfc7d3 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -86,6 +86,7 @@ pub mod query; pub mod arena; #[macro_use] pub mod dep_graph; +pub(crate) mod error; pub mod hir; pub mod infer; pub mod lint; diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 1f9b474ade12..8002f9286130 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -5,11 +5,11 @@ //! The providers for the queries defined here can be found in //! `rustc_traits`. +use crate::error::DropCheckOverflow; use crate::infer::canonical::{Canonical, QueryResponse}; use crate::ty::error::TypeError; use crate::ty::subst::GenericArg; use crate::ty::{self, Ty, TyCtxt}; -use rustc_errors::struct_span_err; use rustc_span::source_map::Span; use std::iter::FromIterator; @@ -117,15 +117,8 @@ pub struct DropckOutlivesResult<'tcx> { impl<'tcx> DropckOutlivesResult<'tcx> { pub fn report_overflows(&self, tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) { if let Some(overflow_ty) = self.overflows.get(0) { - let mut err = struct_span_err!( - tcx.sess, - span, - E0320, - "overflow while adding drop-check rules for {}", - ty, - ); - err.note(&format!("overflowed on {}", overflow_ty)); - err.emit(); + let note = format!("overflowed on {}", overflow_ty); + tcx.sess.emit_err(DropCheckOverflow { span, ty, note }); } } From 00cd965046f6f3e9fcf937bf1f6fec4d7f8d50ca Mon Sep 17 00:00:00 2001 From: 111 Date: Wed, 31 Aug 2022 20:16:02 +0800 Subject: [PATCH 4050/5092] Migrate OpaqueHiddenType mismatch --- .../locales/en-US/middle.ftl | 10 +++++++ compiler/rustc_middle/src/error.rs | 26 +++++++++++++++++++ compiler/rustc_middle/src/ty/mod.rs | 24 ++++++++--------- 3 files changed, 47 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/middle.ftl b/compiler/rustc_error_messages/locales/en-US/middle.ftl index f2864ec4922e..bc1aebd9dbe2 100644 --- a/compiler/rustc_error_messages/locales/en-US/middle.ftl +++ b/compiler/rustc_error_messages/locales/en-US/middle.ftl @@ -1,3 +1,13 @@ middle_drop_check_overflow = overflow while adding drop-check rules for {$ty} .note = {$note} + +middle_opaque_hidden_type_mismatch = + concrete type differs from previous defining opaque type use + .label = expected `{$self_ty}`, got `{$other_ty}` + +middle_conflict_types = + this expression supplies two conflicting concrete types for the same opaque type + +middle_previous_use_here = + previous use here diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index d81eb5241697..27588440aace 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -12,3 +12,29 @@ pub struct DropCheckOverflow<'tcx> { pub ty: Ty<'tcx>, pub note: String, } + +#[derive(SessionDiagnostic)] +#[diag(middle::opaque_hidden_type_mismatch)] +pub struct OpaqueHiddenTypeMismatch<'tcx> { + pub self_ty: Ty<'tcx>, + pub other_ty: Ty<'tcx>, + #[primary_span] + #[label] + pub other_span: Span, + #[subdiagnostic] + pub sub: TypeMismatchReason, +} + +#[derive(SessionSubdiagnostic)] +pub enum TypeMismatchReason { + #[label(middle::conflict_types)] + ConflictType { + #[primary_span] + span: Span, + }, + #[note(middle::previous_use_here)] + PreviousUse { + #[primary_span] + span: Span, + }, +} diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index ed04e7660339..5c38d7614119 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -15,6 +15,7 @@ pub use self::AssocItemContainer::*; pub use self::BorrowKind::*; pub use self::IntVarValue::*; pub use self::Variance::*; +use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason}; use crate::metadata::ModChild; use crate::middle::privacy::AccessLevels; use crate::mir::{Body, GeneratorLayout}; @@ -1184,20 +1185,17 @@ pub struct OpaqueHiddenType<'tcx> { impl<'tcx> OpaqueHiddenType<'tcx> { pub fn report_mismatch(&self, other: &Self, tcx: TyCtxt<'tcx>) { // Found different concrete types for the opaque type. - let mut err = tcx.sess.struct_span_err( - other.span, - "concrete type differs from previous defining opaque type use", - ); - err.span_label(other.span, format!("expected `{}`, got `{}`", self.ty, other.ty)); - if self.span == other.span { - err.span_label( - self.span, - "this expression supplies two conflicting concrete types for the same opaque type", - ); + let sub_diag = if self.span == other.span { + TypeMismatchReason::ConflictType { span: self.span } } else { - err.span_note(self.span, "previous use here"); - } - err.emit(); + TypeMismatchReason::PreviousUse { span: self.span } + }; + tcx.sess.emit_err(OpaqueHiddenTypeMismatch { + self_ty: self.ty, + other_ty: other.ty, + other_span: other.span, + sub: sub_diag, + }); } } From b37e645d801a84f8eb32daba3d4d61a926aef33d Mon Sep 17 00:00:00 2001 From: 111 Date: Thu, 1 Sep 2022 22:09:45 +0800 Subject: [PATCH 4051/5092] Migrate limit error --- compiler/rustc_error_messages/locales/en-US/middle.ftl | 4 ++++ compiler/rustc_middle/src/error.rs | 10 ++++++++++ compiler/rustc_middle/src/middle/limits.rs | 8 ++------ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/middle.ftl b/compiler/rustc_error_messages/locales/en-US/middle.ftl index bc1aebd9dbe2..3a55064c7077 100644 --- a/compiler/rustc_error_messages/locales/en-US/middle.ftl +++ b/compiler/rustc_error_messages/locales/en-US/middle.ftl @@ -11,3 +11,7 @@ middle_conflict_types = middle_previous_use_here = previous use here + +middle_limit_invalid = + `limit` must be a non-negative integer + .label = {$error_str} diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index 27588440aace..0dfe6374cf30 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -38,3 +38,13 @@ pub enum TypeMismatchReason { span: Span, }, } + +#[derive(SessionDiagnostic)] +#[diag(middle::limit_invalid)] +pub struct LimitInvalid<'a> { + #[primary_span] + pub span: Span, + #[label] + pub value_span: Span, + pub error_str: &'a str, +} diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs index acced0492efe..53c4d9267849 100644 --- a/compiler/rustc_middle/src/middle/limits.rs +++ b/compiler/rustc_middle/src/middle/limits.rs @@ -10,6 +10,7 @@ //! just peeks and looks for that attribute. use crate::bug; +use crate::error::LimitInvalid; use crate::ty; use rustc_ast::Attribute; use rustc_session::Session; @@ -56,9 +57,6 @@ fn get_limit(krate_attrs: &[Attribute], sess: &Session, name: Symbol, default: u match s.as_str().parse() { Ok(n) => return Limit::new(n), Err(e) => { - let mut err = - sess.struct_span_err(attr.span, "`limit` must be a non-negative integer"); - let value_span = attr .meta() .and_then(|meta| meta.name_value_literal_span()) @@ -74,9 +72,7 @@ fn get_limit(krate_attrs: &[Attribute], sess: &Session, name: Symbol, default: u IntErrorKind::Zero => bug!("zero is a valid `limit`"), kind => bug!("unimplemented IntErrorKind variant: {:?}", kind), }; - - err.span_label(value_span, error_str); - err.emit(); + sess.emit_err(LimitInvalid { span: attr.span, value_span, error_str }); } } } From 33afe9724aff279cd6a9fc1cbbdca5aa8a721e30 Mon Sep 17 00:00:00 2001 From: Adam-Gleave Date: Thu, 1 Sep 2022 17:32:00 +0100 Subject: [PATCH 4052/5092] Remove trailing whitespace --- library/core/src/bool.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/bool.rs b/library/core/src/bool.rs index 267d787483d5..7667a6508376 100644 --- a/library/core/src/bool.rs +++ b/library/core/src/bool.rs @@ -6,12 +6,12 @@ impl bool { /// Returns `Some(t)` if the `bool` is [`true`](../std/keyword.true.html), /// or `None` otherwise. /// - /// Arguments passed to `then_some` are eagerly evaluated; if you are - /// passing the result of a function call, it is recommended to use + /// Arguments passed to `then_some` are eagerly evaluated; if you are + /// passing the result of a function call, it is recommended to use /// [`then`], which is lazily evaluated. - /// + /// /// [`then`]: bool::then - /// + /// /// # Examples /// /// ``` From 9df75ee254a2999fe0b7e4c3bddebef34b539891 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Thu, 1 Sep 2022 19:42:49 +0200 Subject: [PATCH 4053/5092] Revert parts of "use derive proc macro to impl SessionDiagnostic" This reverts parts of commit ac638c1f5fca36484506415319ab254ad522a692. During rebase, this commit accidentally reverted unrelated changes to the subdiagnostic derive (those allowing multipart_suggestions to be derived). This commit reverts all changes to the subdiagnostic code made in ac638c1f5fc, the next commit will reintroduce the actually intended changes. --- .../src/diagnostics/subdiagnostic.rs | 714 +++++++++++------- .../subdiagnostic-derive.rs | 164 +++- .../subdiagnostic-derive.stderr | 240 ++++-- 3 files changed, 771 insertions(+), 347 deletions(-) diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index c1b82abc1e06..8b40e295bd8a 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -12,7 +12,7 @@ use quote::{format_ident, quote}; use std::collections::HashMap; use std::fmt; use std::str::FromStr; -use syn::{spanned::Spanned, Meta, MetaList, MetaNameValue, NestedMeta, Path}; +use syn::{spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, NestedMeta, Path}; use synstructure::{BindingInfo, Structure, VariantInfo}; /// Which kind of suggestion is being created? @@ -28,8 +28,41 @@ enum SubdiagnosticSuggestionKind { Verbose, } +impl FromStr for SubdiagnosticSuggestionKind { + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "" => Ok(SubdiagnosticSuggestionKind::Normal), + "_short" => Ok(SubdiagnosticSuggestionKind::Short), + "_hidden" => Ok(SubdiagnosticSuggestionKind::Hidden), + "_verbose" => Ok(SubdiagnosticSuggestionKind::Verbose), + _ => Err(()), + } + } +} + +impl SubdiagnosticSuggestionKind { + pub fn to_suggestion_style(&self) -> TokenStream { + match self { + SubdiagnosticSuggestionKind::Normal => { + quote! { rustc_errors::SuggestionStyle::ShowCode } + } + SubdiagnosticSuggestionKind::Short => { + quote! { rustc_errors::SuggestionStyle::HideCodeInline } + } + SubdiagnosticSuggestionKind::Hidden => { + quote! { rustc_errors::SuggestionStyle::HideCodeAlways } + } + SubdiagnosticSuggestionKind::Verbose => { + quote! { rustc_errors::SuggestionStyle::ShowAlways } + } + } + } +} + /// Which kind of subdiagnostic is being created from a variant? -#[derive(Clone, Copy)] +#[derive(Clone)] enum SubdiagnosticKind { /// `#[label(...)]` Label, @@ -40,31 +73,9 @@ enum SubdiagnosticKind { /// `#[warning(...)]` Warn, /// `#[suggestion{,_short,_hidden,_verbose}]` - Suggestion(SubdiagnosticSuggestionKind), -} - -impl FromStr for SubdiagnosticKind { - type Err = (); - - fn from_str(s: &str) -> Result { - match s { - "label" => Ok(SubdiagnosticKind::Label), - "note" => Ok(SubdiagnosticKind::Note), - "help" => Ok(SubdiagnosticKind::Help), - "warning" => Ok(SubdiagnosticKind::Warn), - "suggestion" => Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Normal)), - "suggestion_short" => { - Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Short)) - } - "suggestion_hidden" => { - Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Hidden)) - } - "suggestion_verbose" => { - Ok(SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Verbose)) - } - _ => Err(()), - } - } + Suggestion { suggestion_kind: SubdiagnosticSuggestionKind, code: TokenStream }, + /// `#[multipart_suggestion{,_short,_hidden,_verbose}]` + MultipartSuggestion { suggestion_kind: SubdiagnosticSuggestionKind }, } impl quote::IdentFragment for SubdiagnosticKind { @@ -74,17 +85,9 @@ impl quote::IdentFragment for SubdiagnosticKind { SubdiagnosticKind::Note => write!(f, "note"), SubdiagnosticKind::Help => write!(f, "help"), SubdiagnosticKind::Warn => write!(f, "warn"), - SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Normal) => { - write!(f, "suggestion") - } - SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Short) => { - write!(f, "suggestion_short") - } - SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Hidden) => { - write!(f, "suggestion_hidden") - } - SubdiagnosticKind::Suggestion(SubdiagnosticSuggestionKind::Verbose) => { - write!(f, "suggestion_verbose") + SubdiagnosticKind::Suggestion { .. } => write!(f, "suggestion_with_style"), + SubdiagnosticKind::MultipartSuggestion { .. } => { + write!(f, "multipart_suggestion_with_style") } } } @@ -148,11 +151,9 @@ impl<'a> SessionSubdiagnosticDerive<'a> { variant, span, fields: fields_map, - kinds: Vec::new(), - slugs: Vec::new(), - code: None, span_field: None, applicability: None, + has_suggestion_parts: false, }; builder.into_tokens().unwrap_or_else(|v| v.to_compile_error()) }); @@ -193,21 +194,15 @@ struct SessionSubdiagnosticDeriveBuilder<'a> { /// derive builder. fields: HashMap, - /// Subdiagnostic kind of the type/variant. - kinds: Vec<(SubdiagnosticKind, proc_macro::Span)>, - - /// Slugs of the subdiagnostic - corresponds to the Fluent identifier for the message - from the - /// `#[kind(slug)]` attribute on the type or variant. - slugs: Vec<(Path, proc_macro::Span)>, - /// If a suggestion, the code to suggest as a replacement - from the `#[kind(code = "...")]` - /// attribute on the type or variant. - code: Option<(TokenStream, proc_macro::Span)>, - /// Identifier for the binding to the `#[primary_span]` field. span_field: Option<(proc_macro2::Ident, proc_macro::Span)>, /// If a suggestion, the identifier for the binding to the `#[applicability]` field or a /// `rustc_errors::Applicability::*` variant directly. applicability: Option<(TokenStream, proc_macro::Span)>, + + /// Set to true when a `#[suggestion_part]` field is encountered, used to generate an error + /// during finalization if still `false`. + has_suggestion_parts: bool, } impl<'a> HasFieldMap for SessionSubdiagnosticDeriveBuilder<'a> { @@ -217,124 +212,133 @@ impl<'a> HasFieldMap for SessionSubdiagnosticDeriveBuilder<'a> { } impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { - fn identify_kind(&mut self) -> Result<(), DiagnosticDeriveError> { - for (i, attr) in self.variant.ast().attrs.iter().enumerate() { + fn identify_kind( + &mut self, + ) -> Result, DiagnosticDeriveError> { + let mut kind_slug = None; + + for attr in self.variant.ast().attrs { let span = attr.span().unwrap(); let name = attr.path.segments.last().unwrap().ident.to_string(); let name = name.as_str(); let meta = attr.parse_meta()?; - let kind = match meta { - Meta::List(MetaList { ref nested, .. }) => { - let mut nested_iter = nested.into_iter(); - if let Some(nested_attr) = nested_iter.next() { - match nested_attr { - NestedMeta::Meta(Meta::Path(path)) => { - self.slugs.push((path.clone(), span)); - } - NestedMeta::Meta(meta @ Meta::NameValue(_)) - if matches!( - meta.path().segments.last().unwrap().ident.to_string().as_str(), - "code" | "applicability" - ) => - { - // don't error for valid follow-up attributes - } - nested_attr => { - throw_invalid_nested_attr!(attr, &nested_attr, |diag| { - diag.help( - "first argument of the attribute should be the diagnostic \ - slug", - ) - }) - } - }; - } - - for nested_attr in nested_iter { - let meta = match nested_attr { - NestedMeta::Meta(ref meta) => meta, - _ => throw_invalid_nested_attr!(attr, &nested_attr), - }; - - let span = meta.span().unwrap(); - let nested_name = meta.path().segments.last().unwrap().ident.to_string(); - let nested_name = nested_name.as_str(); - - match meta { - Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => { - match nested_name { - "code" => { - let formatted_str = self.build_format(&s.value(), s.span()); - self.code.set_once((formatted_str, span)); - } - "applicability" => { - let value = match Applicability::from_str(&s.value()) { - Ok(v) => v, - Err(()) => { - span_err(span, "invalid applicability").emit(); - Applicability::Unspecified - } - }; - self.applicability.set_once((quote! { #value }, span)); - } - _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { - diag.help( - "only `code` and `applicability` are valid nested \ - attributes", - ) - }), - } - } - _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { - if matches!(meta, Meta::Path(_)) { - diag.help( - "a diagnostic slug must be the first argument to the \ - attribute", - ) - } else { - diag - } - }), - } - } - - let Ok(kind) = SubdiagnosticKind::from_str(name) else { - throw_invalid_attr!(attr, &meta) - }; - - kind - } - _ => throw_invalid_attr!(attr, &meta), + let Meta::List(MetaList { ref nested, .. }) = meta else { + throw_invalid_attr!(attr, &meta); }; - if matches!( - kind, - SubdiagnosticKind::Label | SubdiagnosticKind::Help | SubdiagnosticKind::Note - ) && self.code.is_some() - { - throw_span_err!( - span, - &format!("`code` is not a valid nested attribute of a `{}` attribute", name) - ); + let mut kind = match name { + "label" => SubdiagnosticKind::Label, + "note" => SubdiagnosticKind::Note, + "help" => SubdiagnosticKind::Help, + "warning" => SubdiagnosticKind::Warn, + _ => { + if let Some(suggestion_kind) = + name.strip_prefix("suggestion").and_then(|s| s.parse().ok()) + { + SubdiagnosticKind::Suggestion { suggestion_kind, code: TokenStream::new() } + } else if let Some(suggestion_kind) = + name.strip_prefix("multipart_suggestion").and_then(|s| s.parse().ok()) + { + SubdiagnosticKind::MultipartSuggestion { suggestion_kind } + } else { + throw_invalid_attr!(attr, &meta); + } + } + }; + + let mut slug = None; + let mut code = None; + + let mut nested_iter = nested.into_iter(); + if let Some(nested_attr) = nested_iter.next() { + match nested_attr { + NestedMeta::Meta(Meta::Path(path)) => { + slug.set_once((path.clone(), span)); + } + NestedMeta::Meta(meta @ Meta::NameValue(_)) + if matches!( + meta.path().segments.last().unwrap().ident.to_string().as_str(), + "code" | "applicability" + ) => + { + // Don't error for valid follow-up attributes. + } + nested_attr => { + throw_invalid_nested_attr!(attr, &nested_attr, |diag| { + diag.help( + "first argument of the attribute should be the diagnostic \ + slug", + ) + }) + } + }; } - if matches!( - kind, - SubdiagnosticKind::Label | SubdiagnosticKind::Help | SubdiagnosticKind::Note - ) && self.applicability.is_some() - { - throw_span_err!( - span, - &format!( - "`applicability` is not a valid nested attribute of a `{}` attribute", - name - ) - ); + for nested_attr in nested_iter { + let meta = match nested_attr { + NestedMeta::Meta(ref meta) => meta, + _ => throw_invalid_nested_attr!(attr, &nested_attr), + }; + + let span = meta.span().unwrap(); + let nested_name = meta.path().segments.last().unwrap().ident.to_string(); + let nested_name = nested_name.as_str(); + + let value = match meta { + Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) => value, + Meta::Path(_) => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { + diag.help("a diagnostic slug must be the first argument to the attribute") + }), + _ => throw_invalid_nested_attr!(attr, &nested_attr), + }; + + match nested_name { + "code" => { + if matches!(kind, SubdiagnosticKind::Suggestion { .. }) { + let formatted_str = self.build_format(&value.value(), value.span()); + code.set_once((formatted_str, span)); + } else { + span_err( + span, + &format!( + "`code` is not a valid nested attribute of a `{}` attribute", + name + ), + ) + .emit(); + } + } + "applicability" => { + if matches!( + kind, + SubdiagnosticKind::Suggestion { .. } + | SubdiagnosticKind::MultipartSuggestion { .. } + ) { + let value = + Applicability::from_str(&value.value()).unwrap_or_else(|()| { + span_err(span, "invalid applicability").emit(); + Applicability::Unspecified + }); + self.applicability.set_once((quote! { #value }, span)); + } else { + span_err( + span, + &format!( + "`applicability` is not a valid nested attribute of a `{}` attribute", + name + ) + ).emit(); + } + } + _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { + diag.help("only `code` and `applicability` are valid nested attributes") + }), + } } - if self.slugs.len() != i + 1 { + let Some((slug, _)) = slug else { throw_span_err!( span, &format!( @@ -342,146 +346,338 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { name ) ); + }; + + match kind { + SubdiagnosticKind::Suggestion { code: ref mut code_field, .. } => { + let Some((code, _)) = code else { + throw_span_err!(span, "suggestion without `code = \"...\"`"); + }; + *code_field = code; + } + SubdiagnosticKind::Label + | SubdiagnosticKind::Note + | SubdiagnosticKind::Help + | SubdiagnosticKind::Warn + | SubdiagnosticKind::MultipartSuggestion { .. } => {} } - self.kinds.push((kind, span)); + kind_slug.set_once(((kind, slug), span)) } - Ok(()) + Ok(kind_slug.map(|(kind_slug, _)| kind_slug)) } - fn generate_field_code( - &mut self, - binding: &BindingInfo<'_>, - have_suggestion: bool, - ) -> Result { + /// Generates the code for a field with no attributes. + fn generate_field_set_arg(&mut self, binding: &BindingInfo<'_>) -> TokenStream { let ast = binding.ast(); - - let inner_ty = FieldInnerTy::from_type(&ast.ty); - let info = FieldInfo { - binding: binding, - ty: inner_ty.inner_type().unwrap_or(&ast.ty), - span: &ast.span(), - }; - - for attr in &ast.attrs { - let name = attr.path.segments.last().unwrap().ident.to_string(); - let name = name.as_str(); - let span = attr.span().unwrap(); - - let meta = attr.parse_meta()?; - match meta { - Meta::Path(_) => match name { - "primary_span" => { - report_error_if_not_applied_to_span(attr, &info)?; - self.span_field.set_once((binding.binding.clone(), span)); - return Ok(quote! {}); - } - "applicability" if have_suggestion => { - report_error_if_not_applied_to_applicability(attr, &info)?; - let binding = binding.binding.clone(); - self.applicability.set_once((quote! { #binding }, span)); - return Ok(quote! {}); - } - "applicability" => { - span_err(span, "`#[applicability]` is only valid on suggestions").emit(); - return Ok(quote! {}); - } - "skip_arg" => { - return Ok(quote! {}); - } - _ => throw_invalid_attr!(attr, &meta, |diag| { - diag.help( - "only `primary_span`, `applicability` and `skip_arg` are valid field \ - attributes", - ) - }), - }, - _ => throw_invalid_attr!(attr, &meta), - } - } - - let ident = ast.ident.as_ref().unwrap(); + assert_eq!(ast.attrs.len(), 0, "field with attribute used as diagnostic arg"); let diag = &self.diag; - let generated = quote! { + let ident = ast.ident.as_ref().unwrap(); + quote! { #diag.set_arg( stringify!(#ident), #binding ); - }; - - Ok(inner_ty.with(binding, generated)) + } } - fn into_tokens(&mut self) -> Result { - self.identify_kind()?; - if self.kinds.is_empty() { + /// Generates the necessary code for all attributes on a field. + fn generate_field_attr_code( + &mut self, + binding: &BindingInfo<'_>, + kind: &SubdiagnosticKind, + ) -> TokenStream { + let ast = binding.ast(); + assert!(ast.attrs.len() > 0, "field without attributes generating attr code"); + + // Abstract over `Vec` and `Option` fields using `FieldInnerTy`, which will + // apply the generated code on each element in the `Vec` or `Option`. + let inner_ty = FieldInnerTy::from_type(&ast.ty); + ast.attrs + .iter() + .map(|attr| { + let info = FieldInfo { + binding, + ty: inner_ty.inner_type().unwrap_or(&ast.ty), + span: &ast.span(), + }; + + let generated = self + .generate_field_code_inner(kind, attr, info) + .unwrap_or_else(|v| v.to_compile_error()); + + inner_ty.with(binding, generated) + }) + .collect() + } + + fn generate_field_code_inner( + &mut self, + kind: &SubdiagnosticKind, + attr: &Attribute, + info: FieldInfo<'_>, + ) -> Result { + let meta = attr.parse_meta()?; + match meta { + Meta::Path(path) => self.generate_field_code_inner_path(kind, attr, info, path), + Meta::List(list @ MetaList { .. }) => { + self.generate_field_code_inner_list(kind, attr, info, list) + } + _ => throw_invalid_attr!(attr, &meta), + } + } + + /// Generates the code for a `[Meta::Path]`-like attribute on a field (e.g. `#[primary_span]`). + fn generate_field_code_inner_path( + &mut self, + kind: &SubdiagnosticKind, + attr: &Attribute, + info: FieldInfo<'_>, + path: Path, + ) -> Result { + let span = attr.span().unwrap(); + let ident = &path.segments.last().unwrap().ident; + let name = ident.to_string(); + let name = name.as_str(); + + match name { + "skip_arg" => Ok(quote! {}), + "primary_span" => { + if matches!(kind, SubdiagnosticKind::MultipartSuggestion { .. }) { + throw_invalid_attr!(attr, &Meta::Path(path), |diag| { + diag.help( + "multipart suggestions use one or more `#[suggestion_part]`s rather \ + than one `#[primary_span]`", + ) + }) + } + + report_error_if_not_applied_to_span(attr, &info)?; + + let binding = info.binding.binding.clone(); + self.span_field.set_once((binding, span)); + + Ok(quote! {}) + } + "suggestion_part" => { + self.has_suggestion_parts = true; + + match kind { + SubdiagnosticKind::MultipartSuggestion { .. } => { + span_err( + span, + "`#[suggestion_part(...)]` attribute without `code = \"...\"`", + ) + .emit(); + Ok(quote! {}) + } + SubdiagnosticKind::Label + | SubdiagnosticKind::Note + | SubdiagnosticKind::Help + | SubdiagnosticKind::Warn + | SubdiagnosticKind::Suggestion { .. } => { + throw_invalid_attr!(attr, &Meta::Path(path), |diag| { + diag.help( + "`#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead", + ) + }); + } + } + } + "applicability" => { + if let SubdiagnosticKind::Suggestion { .. } + | SubdiagnosticKind::MultipartSuggestion { .. } = kind + { + report_error_if_not_applied_to_applicability(attr, &info)?; + + let binding = info.binding.binding.clone(); + self.applicability.set_once((quote! { #binding }, span)); + } else { + span_err(span, "`#[applicability]` is only valid on suggestions").emit(); + } + + Ok(quote! {}) + } + _ => throw_invalid_attr!(attr, &Meta::Path(path), |diag| { + let span_attr = if let SubdiagnosticKind::MultipartSuggestion { .. } = kind { + "suggestion_part" + } else { + "primary_span" + }; + diag.help(format!( + "only `{span_attr}`, `applicability` and `skip_arg` are valid field attributes", + )) + }), + } + } + + /// Generates the code for a `[Meta::List]`-like attribute on a field (e.g. + /// `#[suggestion_part(code = "...")]`). + fn generate_field_code_inner_list( + &mut self, + kind: &SubdiagnosticKind, + attr: &Attribute, + info: FieldInfo<'_>, + list: MetaList, + ) -> Result { + let span = attr.span().unwrap(); + let ident = &list.path.segments.last().unwrap().ident; + let name = ident.to_string(); + let name = name.as_str(); + + match name { + "suggestion_part" => { + if !matches!(kind, SubdiagnosticKind::MultipartSuggestion { .. }) { + throw_invalid_attr!(attr, &Meta::List(list), |diag| { + diag.help( + "`#[suggestion_part(...)]` is only valid in multipart suggestions", + ) + }) + } + + self.has_suggestion_parts = true; + + report_error_if_not_applied_to_span(attr, &info)?; + + let mut code = None; + for nested_attr in list.nested.iter() { + let NestedMeta::Meta(ref meta) = nested_attr else { + throw_invalid_nested_attr!(attr, &nested_attr); + }; + + let span = meta.span().unwrap(); + let nested_name = meta.path().segments.last().unwrap().ident.to_string(); + let nested_name = nested_name.as_str(); + + let Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(value), .. }) = meta else { + throw_invalid_nested_attr!(attr, &nested_attr); + }; + + match nested_name { + "code" => { + let formatted_str = self.build_format(&value.value(), value.span()); + code.set_once((formatted_str, span)); + } + _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| { + diag.help("`code` is the only valid nested attribute") + }), + } + } + + let Some((code, _)) = code else { + span_err(span, "`#[suggestion_part(...)]` attribute without `code = \"...\"`") + .emit(); + return Ok(quote! {}); + }; + let binding = info.binding; + + Ok(quote! { suggestions.push((#binding, #code)); }) + } + _ => throw_invalid_attr!(attr, &Meta::List(list), |diag| { + let span_attr = if let SubdiagnosticKind::MultipartSuggestion { .. } = kind { + "suggestion_part" + } else { + "primary_span" + }; + diag.help(format!( + "only `{span_attr}`, `applicability` and `skip_arg` are valid field attributes", + )) + }), + } + } + + pub fn into_tokens(&mut self) -> Result { + let Some((kind, slug)) = self.identify_kind()? else { throw_span_err!( self.variant.ast().ident.span().unwrap(), "subdiagnostic kind not specified" ); }; - let have_suggestion = - self.kinds.iter().any(|(k, _)| matches!(k, SubdiagnosticKind::Suggestion(_))); - let mut args = TokenStream::new(); - for binding in self.variant.bindings() { - let arg = self - .generate_field_code(binding, have_suggestion) - .unwrap_or_else(|v| v.to_compile_error()); - args.extend(arg); - } - let mut tokens = TokenStream::new(); - for ((kind, _), (slug, _)) in self.kinds.iter().zip(&self.slugs) { - let code = match self.code.as_ref() { - Some((code, _)) => Some(quote! { #code }), - None if have_suggestion => { - span_err(self.span, "suggestion without `code = \"...\"`").emit(); - Some(quote! { /* macro error */ "..." }) - } - None => None, - }; - let span_field = self.span_field.as_ref().map(|(span, _)| span); - let applicability = match self.applicability.clone() { - Some((applicability, _)) => Some(applicability), - None if have_suggestion => { - span_err(self.span, "suggestion without `applicability`").emit(); - Some(quote! { rustc_errors::Applicability::Unspecified }) - } - None => None, - }; + let init = match &kind { + SubdiagnosticKind::Label + | SubdiagnosticKind::Note + | SubdiagnosticKind::Help + | SubdiagnosticKind::Warn + | SubdiagnosticKind::Suggestion { .. } => quote! {}, + SubdiagnosticKind::MultipartSuggestion { .. } => { + quote! { let mut suggestions = Vec::new(); } + } + }; - let diag = &self.diag; - let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind); - let message = quote! { rustc_errors::fluent::#slug }; - let call = if matches!(kind, SubdiagnosticKind::Suggestion(..)) { + let attr_args: TokenStream = self + .variant + .bindings() + .iter() + .filter(|binding| !binding.ast().attrs.is_empty()) + .map(|binding| self.generate_field_attr_code(binding, &kind)) + .collect(); + + let span_field = self.span_field.as_ref().map(|(span, _)| span); + let applicability = self.applicability.take().map_or_else( + || quote! { rustc_errors::Applicability::Unspecified }, + |(applicability, _)| applicability, + ); + + let diag = &self.diag; + let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind); + let message = quote! { rustc_errors::fluent::#slug }; + let call = match kind { + SubdiagnosticKind::Suggestion { suggestion_kind, code } => { if let Some(span) = span_field { - quote! { #diag.#name(#span, #message, #code, #applicability); } + let style = suggestion_kind.to_suggestion_style(); + + quote! { #diag.#name(#span, #message, #code, #applicability, #style); } } else { span_err(self.span, "suggestion without `#[primary_span]` field").emit(); quote! { unreachable!(); } } - } else if matches!(kind, SubdiagnosticKind::Label) { + } + SubdiagnosticKind::MultipartSuggestion { suggestion_kind } => { + if !self.has_suggestion_parts { + span_err( + self.span, + "multipart suggestion without any `#[suggestion_part(...)]` fields", + ) + .emit(); + } + + let style = suggestion_kind.to_suggestion_style(); + + quote! { #diag.#name(#message, suggestions, #applicability, #style); } + } + SubdiagnosticKind::Label => { if let Some(span) = span_field { quote! { #diag.#name(#span, #message); } } else { span_err(self.span, "label without `#[primary_span]` field").emit(); quote! { unreachable!(); } } - } else { + } + _ => { if let Some(span) = span_field { quote! { #diag.#name(#span, #message); } } else { quote! { #diag.#name(#message); } } - }; - tokens.extend(quote! { - #call - #args - }); - } + } + }; - Ok(tokens) + let plain_args: TokenStream = self + .variant + .bindings() + .iter() + .filter(|binding| binding.ast().attrs.is_empty()) + .map(|binding| self.generate_field_set_arg(binding)) + .collect(); + + Ok(quote! { + #init + #attr_args + #call + #plain_args + }) } } diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs index f0843c60543d..89eaec78c6f1 100644 --- a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs +++ b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs @@ -167,8 +167,8 @@ enum P { #[derive(SessionSubdiagnostic)] enum Q { #[bar] -//~^ ERROR `#[bar]` is not a valid attribute -//~^^ ERROR cannot find attribute `bar` in this scope + //~^ ERROR `#[bar]` is not a valid attribute + //~^^ ERROR cannot find attribute `bar` in this scope A { #[primary_span] span: Span, @@ -179,8 +179,8 @@ enum Q { #[derive(SessionSubdiagnostic)] enum R { #[bar = "..."] -//~^ ERROR `#[bar = ...]` is not a valid attribute -//~^^ ERROR cannot find attribute `bar` in this scope + //~^ ERROR `#[bar = ...]` is not a valid attribute + //~^^ ERROR cannot find attribute `bar` in this scope A { #[primary_span] span: Span, @@ -191,8 +191,8 @@ enum R { #[derive(SessionSubdiagnostic)] enum S { #[bar = 4] -//~^ ERROR `#[bar = ...]` is not a valid attribute -//~^^ ERROR cannot find attribute `bar` in this scope + //~^ ERROR `#[bar = ...]` is not a valid attribute + //~^^ ERROR cannot find attribute `bar` in this scope A { #[primary_span] span: Span, @@ -203,8 +203,8 @@ enum S { #[derive(SessionSubdiagnostic)] enum T { #[bar("...")] -//~^ ERROR `#[bar("...")]` is not a valid attribute -//~^^ ERROR cannot find attribute `bar` in this scope + //~^ ERROR `#[bar(...)]` is not a valid attribute + //~^^ ERROR cannot find attribute `bar` in this scope A { #[primary_span] span: Span, @@ -215,7 +215,7 @@ enum T { #[derive(SessionSubdiagnostic)] enum U { #[label(code = "...")] -//~^ ERROR diagnostic slug must be first argument of a `#[label(...)]` attribute + //~^ ERROR diagnostic slug must be first argument of a `#[label(...)]` attribute A { #[primary_span] span: Span, @@ -232,7 +232,7 @@ enum V { var: String, }, B { -//~^ ERROR subdiagnostic kind not specified + //~^ ERROR subdiagnostic kind not specified #[primary_span] span: Span, var: String, @@ -307,6 +307,16 @@ union AC { b: u64 } +#[derive(SessionSubdiagnostic)] +#[label(parser::add_paren)] +//~^ NOTE previously specified here +#[label(parser::add_paren)] +//~^ ERROR specified multiple times +struct AD { + #[primary_span] + span: Span, +} + #[derive(SessionSubdiagnostic)] #[label(parser::add_paren, parser::add_paren)] //~^ ERROR `#[label(parser::add_paren)]` is not a valid attribute @@ -319,16 +329,16 @@ struct AE { #[label(parser::add_paren)] struct AF { #[primary_span] -//~^ NOTE previously specified here + //~^ NOTE previously specified here span_a: Span, #[primary_span] -//~^ ERROR specified multiple times + //~^ ERROR specified multiple times span_b: Span, } #[derive(SessionSubdiagnostic)] struct AG { -//~^ ERROR subdiagnostic kind not specified + //~^ ERROR subdiagnostic kind not specified #[primary_span] span: Span, } @@ -380,27 +390,25 @@ struct AK { #[primary_span] span: Span, #[applicability] -//~^ NOTE previously specified here + //~^ NOTE previously specified here applicability_a: Applicability, #[applicability] -//~^ ERROR specified multiple times + //~^ ERROR specified multiple times applicability_b: Applicability, } #[derive(SessionSubdiagnostic)] #[suggestion(parser::add_paren, code = "...")] -//~^ ERROR suggestion without `applicability` struct AL { #[primary_span] span: Span, #[applicability] -//~^ ERROR the `#[applicability]` attribute can only be applied to fields of type `Applicability` + //~^ ERROR the `#[applicability]` attribute can only be applied to fields of type `Applicability` applicability: Span, } #[derive(SessionSubdiagnostic)] #[suggestion(parser::add_paren, code = "...")] -//~^ ERROR suggestion without `applicability` struct AM { #[primary_span] span: Span, @@ -436,8 +444,7 @@ struct AQ; #[derive(SessionSubdiagnostic)] #[suggestion(parser::add_paren, code = "...")] -//~^ ERROR suggestion without `applicability` -//~^^ ERROR suggestion without `#[primary_span]` field +//~^ ERROR suggestion without `#[primary_span]` field struct AR { var: String, } @@ -507,3 +514,120 @@ struct AZ { #[primary_span] span: Span, } + +#[derive(SessionSubdiagnostic)] +#[suggestion(parser::add_paren, code = "...")] +//~^ ERROR suggestion without `#[primary_span]` field +struct BA { + #[suggestion_part] + //~^ ERROR `#[suggestion_part]` is not a valid attribute + span: Span, + #[suggestion_part(code = "...")] + //~^ ERROR `#[suggestion_part(...)]` is not a valid attribute + span2: Span, + #[applicability] + applicability: Applicability, + var: String, +} + +#[derive(SessionSubdiagnostic)] +#[multipart_suggestion(parser::add_paren, code = "...", applicability = "machine-applicable")] +//~^ ERROR multipart suggestion without any `#[suggestion_part(...)]` fields +//~| ERROR `code` is not a valid nested attribute of a `multipart_suggestion` attribute +struct BBa { + var: String, +} + +#[derive(SessionSubdiagnostic)] +#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")] +struct BBb { + #[suggestion_part] + //~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."` + span1: Span, +} + +#[derive(SessionSubdiagnostic)] +#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")] +struct BBc { + #[suggestion_part()] + //~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."` + span1: Span, +} + +#[derive(SessionSubdiagnostic)] +#[multipart_suggestion(parser::add_paren)] +//~^ ERROR multipart suggestion without any `#[suggestion_part(...)]` fields +struct BC { + #[primary_span] + //~^ ERROR `#[primary_span]` is not a valid attribute + span: Span, +} + +#[derive(SessionSubdiagnostic)] +#[multipart_suggestion(parser::add_paren)] +struct BD { + #[suggestion_part] + //~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."` + span1: Span, + #[suggestion_part()] + //~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."` + span2: Span, + #[suggestion_part(foo = "bar")] + //~^ ERROR `#[suggestion_part(foo = ...)]` is not a valid attribute + span4: Span, + #[suggestion_part(code = "...")] + //~^ ERROR the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` + s1: String, + #[suggestion_part()] + //~^ ERROR the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` + s2: String, +} + +#[derive(SessionSubdiagnostic)] +#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")] +struct BE { + #[suggestion_part(code = "...", code = ",,,")] + //~^ ERROR specified multiple times + //~| NOTE previously specified here + span: Span, +} + +#[derive(SessionSubdiagnostic)] +#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")] +struct BF { + #[suggestion_part(code = "(")] + first: Span, + #[suggestion_part(code = ")")] + second: Span, +} + +#[derive(SessionSubdiagnostic)] +#[multipart_suggestion(parser::add_paren)] +struct BG { + #[applicability] + appl: Applicability, + #[suggestion_part(code = "(")] + first: Span, + #[suggestion_part(code = ")")] + second: Span, +} + +#[derive(SessionSubdiagnostic)] +#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")] +//~^ NOTE previously specified here +struct BH { + #[applicability] + //~^ ERROR specified multiple times + appl: Applicability, + #[suggestion_part(code = "(")] + first: Span, + #[suggestion_part(code = ")")] + second: Span, +} + +#[derive(SessionSubdiagnostic)] +#[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")] +struct BI { + #[suggestion_part(code = "")] + spans: Vec, +} diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr index 6bd9144dbf6f..75a34f44bbe7 100644 --- a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr +++ b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr @@ -65,16 +65,16 @@ LL | #[label()] | ^^^^^^^^^^ error: `code` is not a valid nested attribute of a `label` attribute - --> $DIR/subdiagnostic-derive.rs:137:1 + --> $DIR/subdiagnostic-derive.rs:137:28 | LL | #[label(parser::add_paren, code = "...")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ error: `applicability` is not a valid nested attribute of a `label` attribute - --> $DIR/subdiagnostic-derive.rs:146:1 + --> $DIR/subdiagnostic-derive.rs:146:28 | LL | #[label(parser::add_paren, applicability = "machine-applicable")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unsupported type attribute for subdiagnostic enum --> $DIR/subdiagnostic-derive.rs:155:1 @@ -100,13 +100,11 @@ error: `#[bar = ...]` is not a valid attribute LL | #[bar = 4] | ^^^^^^^^^^ -error: `#[bar("...")]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:205:11 +error: `#[bar(...)]` is not a valid attribute + --> $DIR/subdiagnostic-derive.rs:205:5 | LL | #[bar("...")] - | ^^^^^ - | - = help: first argument of the attribute should be the diagnostic slug + | ^^^^^^^^^^^^^ error: diagnostic slug must be first argument of a `#[label(...)]` attribute --> $DIR/subdiagnostic-derive.rs:217:5 @@ -163,6 +161,8 @@ error: `#[bar(...)]` is not a valid attribute | LL | #[bar("...")] | ^^^^^^^^^^^^^ + | + = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes error: unexpected unsupported untagged union --> $DIR/subdiagnostic-derive.rs:304:1 @@ -174,8 +174,20 @@ LL | | b: u64 LL | | } | |_^ +error: specified multiple times + --> $DIR/subdiagnostic-derive.rs:313:1 + | +LL | #[label(parser::add_paren)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: previously specified here + --> $DIR/subdiagnostic-derive.rs:311:1 + | +LL | #[label(parser::add_paren)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: `#[label(parser::add_paren)]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:311:28 + --> $DIR/subdiagnostic-derive.rs:321:28 | LL | #[label(parser::add_paren, parser::add_paren)] | ^^^^^^^^^^^^^^^^^ @@ -183,134 +195,226 @@ LL | #[label(parser::add_paren, parser::add_paren)] = help: a diagnostic slug must be the first argument to the attribute error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:324:5 + --> $DIR/subdiagnostic-derive.rs:334:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:321:5 + --> $DIR/subdiagnostic-derive.rs:331:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ error: subdiagnostic kind not specified - --> $DIR/subdiagnostic-derive.rs:330:8 + --> $DIR/subdiagnostic-derive.rs:340:8 | LL | struct AG { | ^^ error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:367:47 + --> $DIR/subdiagnostic-derive.rs:377:47 | LL | #[suggestion(parser::add_paren, code = "...", code = "...")] | ^^^^^^^^^^^^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:367:33 + --> $DIR/subdiagnostic-derive.rs:377:33 | LL | #[suggestion(parser::add_paren, code = "...", code = "...")] | ^^^^^^^^^^^^ error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:385:5 + --> $DIR/subdiagnostic-derive.rs:395:5 | LL | #[applicability] | ^^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:382:5 + --> $DIR/subdiagnostic-derive.rs:392:5 | LL | #[applicability] | ^^^^^^^^^^^^^^^^ error: the `#[applicability]` attribute can only be applied to fields of type `Applicability` - --> $DIR/subdiagnostic-derive.rs:396:5 + --> $DIR/subdiagnostic-derive.rs:405:5 | LL | #[applicability] | ^^^^^^^^^^^^^^^^ -error: suggestion without `applicability` - --> $DIR/subdiagnostic-derive.rs:391:1 - | -LL | / #[suggestion(parser::add_paren, code = "...")] -LL | | -LL | | struct AL { -LL | | #[primary_span] -... | -LL | | applicability: Span, -LL | | } - | |_^ - -error: suggestion without `applicability` - --> $DIR/subdiagnostic-derive.rs:402:1 - | -LL | / #[suggestion(parser::add_paren, code = "...")] -LL | | -LL | | struct AM { -LL | | #[primary_span] -LL | | span: Span, -LL | | } - | |_^ - error: suggestion without `code = "..."` - --> $DIR/subdiagnostic-derive.rs:410:1 + --> $DIR/subdiagnostic-derive.rs:418:1 | -LL | / #[suggestion(parser::add_paren)] -LL | | -LL | | struct AN { -LL | | #[primary_span] -... | -LL | | applicability: Applicability, -LL | | } - | |_^ +LL | #[suggestion(parser::add_paren)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: invalid applicability - --> $DIR/subdiagnostic-derive.rs:420:46 + --> $DIR/subdiagnostic-derive.rs:428:46 | LL | #[suggestion(parser::add_paren, code ="...", applicability = "foo")] | ^^^^^^^^^^^^^^^^^^^^^ -error: suggestion without `applicability` - --> $DIR/subdiagnostic-derive.rs:438:1 - | -LL | / #[suggestion(parser::add_paren, code = "...")] -LL | | -LL | | -LL | | struct AR { -LL | | var: String, -LL | | } - | |_^ - error: suggestion without `#[primary_span]` field - --> $DIR/subdiagnostic-derive.rs:438:1 + --> $DIR/subdiagnostic-derive.rs:446:1 | LL | / #[suggestion(parser::add_paren, code = "...")] LL | | -LL | | LL | | struct AR { LL | | var: String, LL | | } | |_^ error: unsupported type attribute for subdiagnostic enum - --> $DIR/subdiagnostic-derive.rs:453:1 + --> $DIR/subdiagnostic-derive.rs:460:1 | LL | #[label] | ^^^^^^^^ error: `var` doesn't refer to a field on this type - --> $DIR/subdiagnostic-derive.rs:473:39 + --> $DIR/subdiagnostic-derive.rs:480:39 | LL | #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")] | ^^^^^^^ error: `var` doesn't refer to a field on this type - --> $DIR/subdiagnostic-derive.rs:492:43 + --> $DIR/subdiagnostic-derive.rs:499:43 | LL | #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")] | ^^^^^^^ +error: `#[suggestion_part]` is not a valid attribute + --> $DIR/subdiagnostic-derive.rs:522:5 + | +LL | #[suggestion_part] + | ^^^^^^^^^^^^^^^^^^ + | + = help: `#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead + +error: `#[suggestion_part(...)]` is not a valid attribute + --> $DIR/subdiagnostic-derive.rs:525:5 + | +LL | #[suggestion_part(code = "...")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[suggestion_part(...)]` is only valid in multipart suggestions + +error: suggestion without `#[primary_span]` field + --> $DIR/subdiagnostic-derive.rs:519:1 + | +LL | / #[suggestion(parser::add_paren, code = "...")] +LL | | +LL | | struct BA { +LL | | #[suggestion_part] +... | +LL | | var: String, +LL | | } + | |_^ + +error: `code` is not a valid nested attribute of a `multipart_suggestion` attribute + --> $DIR/subdiagnostic-derive.rs:534:43 + | +LL | #[multipart_suggestion(parser::add_paren, code = "...", applicability = "machine-applicable")] + | ^^^^^^^^^^^^ + +error: multipart suggestion without any `#[suggestion_part(...)]` fields + --> $DIR/subdiagnostic-derive.rs:534:1 + | +LL | / #[multipart_suggestion(parser::add_paren, code = "...", applicability = "machine-applicable")] +LL | | +LL | | +LL | | struct BBa { +LL | | var: String, +LL | | } + | |_^ + +error: `#[suggestion_part(...)]` attribute without `code = "..."` + --> $DIR/subdiagnostic-derive.rs:544:5 + | +LL | #[suggestion_part] + | ^^^^^^^^^^^^^^^^^^ + +error: `#[suggestion_part(...)]` attribute without `code = "..."` + --> $DIR/subdiagnostic-derive.rs:552:5 + | +LL | #[suggestion_part()] + | ^^^^^^^^^^^^^^^^^^^^ + +error: `#[primary_span]` is not a valid attribute + --> $DIR/subdiagnostic-derive.rs:561:5 + | +LL | #[primary_span] + | ^^^^^^^^^^^^^^^ + | + = help: multipart suggestions use one or more `#[suggestion_part]`s rather than one `#[primary_span]` + +error: multipart suggestion without any `#[suggestion_part(...)]` fields + --> $DIR/subdiagnostic-derive.rs:558:1 + | +LL | / #[multipart_suggestion(parser::add_paren)] +LL | | +LL | | struct BC { +LL | | #[primary_span] +LL | | +LL | | span: Span, +LL | | } + | |_^ + +error: `#[suggestion_part(...)]` attribute without `code = "..."` + --> $DIR/subdiagnostic-derive.rs:569:5 + | +LL | #[suggestion_part] + | ^^^^^^^^^^^^^^^^^^ + +error: `#[suggestion_part(...)]` attribute without `code = "..."` + --> $DIR/subdiagnostic-derive.rs:572:5 + | +LL | #[suggestion_part()] + | ^^^^^^^^^^^^^^^^^^^^ + +error: `#[suggestion_part(foo = ...)]` is not a valid attribute + --> $DIR/subdiagnostic-derive.rs:575:23 + | +LL | #[suggestion_part(foo = "bar")] + | ^^^^^^^^^^^ + | + = help: `code` is the only valid nested attribute + +error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` + --> $DIR/subdiagnostic-derive.rs:578:5 + | +LL | #[suggestion_part(code = "...")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` + --> $DIR/subdiagnostic-derive.rs:581:5 + | +LL | #[suggestion_part()] + | ^^^^^^^^^^^^^^^^^^^^ + +error: specified multiple times + --> $DIR/subdiagnostic-derive.rs:589:37 + | +LL | #[suggestion_part(code = "...", code = ",,,")] + | ^^^^^^^^^^^^ + | +note: previously specified here + --> $DIR/subdiagnostic-derive.rs:589:23 + | +LL | #[suggestion_part(code = "...", code = ",,,")] + | ^^^^^^^^^^^^ + +error: specified multiple times + --> $DIR/subdiagnostic-derive.rs:619:5 + | +LL | #[applicability] + | ^^^^^^^^^^^^^^^^ + | +note: previously specified here + --> $DIR/subdiagnostic-derive.rs:616:43 + | +LL | #[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: cannot find attribute `foo` in this scope --> $DIR/subdiagnostic-derive.rs:63:3 | @@ -371,6 +475,6 @@ error[E0425]: cannot find value `slug` in module `rustc_errors::fluent` LL | #[label(slug)] | ^^^^ not found in `rustc_errors::fluent` -error: aborting due to 50 previous errors +error: aborting due to 64 previous errors For more information about this error, try `rustc --explain E0425`. From 8e8220027711874f8bf176b14cb8e87b01342081 Mon Sep 17 00:00:00 2001 From: Gabriel Bustamante Date: Fri, 26 Aug 2022 13:08:58 -0500 Subject: [PATCH 4054/5092] Porting 'compiler/rustc_trait_selection' to translatable diagnostics - Part 1 --- .../locales/en-US/trait_selection.ftl | 26 +++++ compiler/rustc_error_messages/src/lib.rs | 1 + compiler/rustc_middle/src/ty/consts/kind.rs | 6 ++ compiler/rustc_middle/src/ty/sty.rs | 6 ++ compiler/rustc_session/src/session.rs | 6 ++ .../rustc_trait_selection/src/autoderef.rs | 19 +--- compiler/rustc_trait_selection/src/errors.rs | 102 ++++++++++++++++++ compiler/rustc_trait_selection/src/lib.rs | 1 + .../src/traits/auto_trait.rs | 8 +- .../rustc_trait_selection/src/traits/mod.rs | 8 +- .../src/traits/on_unimplemented.rs | 47 ++------ .../src/traits/specialize/mod.rs | 37 ++----- 12 files changed, 180 insertions(+), 87 deletions(-) create mode 100644 compiler/rustc_error_messages/locales/en-US/trait_selection.ftl create mode 100644 compiler/rustc_trait_selection/src/errors.rs diff --git a/compiler/rustc_error_messages/locales/en-US/trait_selection.ftl b/compiler/rustc_error_messages/locales/en-US/trait_selection.ftl new file mode 100644 index 000000000000..004e0ab18969 --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/trait_selection.ftl @@ -0,0 +1,26 @@ +trait_selection_dump_vtable_entries = vtable entries for `{$trait_ref}`: {$entries} + +trait_selection_unable_to_construct_constant_value = unable to construct a constant value for the unevaluated constant {$unevaluated} + +trait_selection_auto_deref_reached_recursion_limit = reached the recursion limit while auto-dereferencing `{$ty}` + .label = deref recursion limit reached + .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`) + +trait_selection_empty_on_clause_in_rustc_on_unimplemented = empty `on`-clause in `#[rustc_on_unimplemented]` + .label = empty on-clause here + +trait_selection_invalid_on_clause_in_rustc_on_unimplemented = invalid `on`-clause in `#[rustc_on_unimplemented]` + .label = invalid on-clause here + +trait_selection_no_value_in_rustc_on_unimplemented = this attribute must have a valid value + .label = expected value here + .note = eg `#[rustc_on_unimplemented(message="foo")]` + +trait_selection_negative_positive_conflict = found both positive and negative implementation of trait `{$trait_desc}`{$self_desc -> + [none] {""} + *[default] {" "}for type `{$self_desc}` + }: + .negative_implementation_here = negative implementation here + .negative_implementation_in_crate = negative implementation in crate `{$negative_impl_cname}` + .positive_implementation_here = positive implementation here + .positive_implementation_in_crate = positive implementation in crate `{$positive_impl_cname}` diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 8f47be25db91..5fe107fbc530 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -51,6 +51,7 @@ fluent_messages! { plugin_impl => "../locales/en-US/plugin_impl.ftl", privacy => "../locales/en-US/privacy.ftl", query_system => "../locales/en-US/query_system.ftl", + trait_selection => "../locales/en-US/trait_selection.ftl", save_analysis => "../locales/en-US/save_analysis.ftl", ty_utils => "../locales/en-US/ty_utils.ftl", typeck => "../locales/en-US/typeck.ftl", diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index cb0137d2e5e0..3840e79cebd8 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -20,6 +20,12 @@ pub struct Unevaluated<'tcx, P = Option> { pub promoted: P, } +impl rustc_errors::IntoDiagnosticArg for Unevaluated<'_> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + format!("{:?}", self).into_diagnostic_arg() + } +} + impl<'tcx> Unevaluated<'tcx> { #[inline] pub fn shrink(self) -> Unevaluated<'tcx, ()> { diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 80354a3f8a22..9fb91b5fe870 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -849,6 +849,12 @@ impl<'tcx> PolyTraitRef<'tcx> { } } +impl rustc_errors::IntoDiagnosticArg for PolyTraitRef<'_> { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + self.to_string().into_diagnostic_arg() + } +} + /// An existential reference to a trait, where `Self` is erased. /// For example, the trait object `Trait<'a, 'b, X, Y>` is: /// ```ignore (illustrative) diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index ec5e5170d359..a49af23be231 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -110,6 +110,12 @@ impl Mul for Limit { } } +impl rustc_errors::IntoDiagnosticArg for Limit { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + self.to_string().into_diagnostic_arg() + } +} + #[derive(Clone, Copy, Debug, HashStable_Generic)] pub struct Limits { /// The maximum recursion limit for potentially infinitely recursive diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs index 8b7e8984a8ad..36ab8f3bd884 100644 --- a/compiler/rustc_trait_selection/src/autoderef.rs +++ b/compiler/rustc_trait_selection/src/autoderef.rs @@ -1,6 +1,6 @@ +use crate::errors::AutoDerefReachedRecursionLimit; use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::{self, TraitEngine}; -use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_infer::infer::InferCtxt; use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt}; @@ -222,19 +222,10 @@ pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Spa Limit(0) => Limit(2), limit => limit * 2, }; - struct_span_err!( - tcx.sess, + tcx.sess.emit_err(AutoDerefReachedRecursionLimit { span, - E0055, - "reached the recursion limit while auto-dereferencing `{:?}`", - ty - ) - .span_label(span, "deref recursion limit reached") - .help(&format!( - "consider increasing the recursion limit by adding a \ - `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)", + ty, suggested_limit, - tcx.crate_name(LOCAL_CRATE), - )) - .emit(); + crate_name: tcx.crate_name(LOCAL_CRATE), + }); } diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs new file mode 100644 index 000000000000..81977f25ca21 --- /dev/null +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -0,0 +1,102 @@ +use rustc_errors::{fluent, ErrorGuaranteed}; +use rustc_macros::SessionDiagnostic; +use rustc_middle::ty::{PolyTraitRef, Ty, Unevaluated}; +use rustc_session::{parse::ParseSess, Limit, SessionDiagnostic}; +use rustc_span::{Span, Symbol}; + +#[derive(SessionDiagnostic)] +#[diag(trait_selection::dump_vtable_entries)] +pub struct DumpVTableEntries<'a> { + #[primary_span] + pub span: Span, + pub trait_ref: PolyTraitRef<'a>, + pub entries: String, +} + +#[derive(SessionDiagnostic)] +#[diag(trait_selection::unable_to_construct_constant_value)] +pub struct UnableToConstructConstantValue<'a> { + #[primary_span] + pub span: Span, + pub unevaluated: Unevaluated<'a>, +} + +#[derive(SessionDiagnostic)] +#[help] +#[diag(trait_selection::auto_deref_reached_recursion_limit, code = "E0055")] +pub struct AutoDerefReachedRecursionLimit<'a> { + #[primary_span] + #[label] + pub span: Span, + pub ty: Ty<'a>, + pub suggested_limit: Limit, + pub crate_name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[diag(trait_selection::empty_on_clause_in_rustc_on_unimplemented, code = "E0232")] +pub struct EmptyOnClauseInOnUnimplemented { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(trait_selection::invalid_on_clause_in_rustc_on_unimplemented, code = "E0232")] +pub struct InvalidOnClauseInOnUnimplemented { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[diag(trait_selection::no_value_in_rustc_on_unimplemented, code = "E0232")] +#[note] +pub struct NoValueInOnUnimplemented { + #[primary_span] + #[label] + pub span: Span, +} + +pub struct NegativePositiveConflict<'a> { + pub impl_span: Span, + pub trait_desc: &'a str, + pub self_desc: &'a Option, + pub negative_impl_span: Result, + pub positive_impl_span: Result, +} + +impl SessionDiagnostic<'_> for NegativePositiveConflict<'_> { + fn into_diagnostic( + self, + sess: &ParseSess, + ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = sess.struct_err(fluent::trait_selection::negative_positive_conflict); + diag.set_arg("trait_desc", self.trait_desc); + diag.set_arg( + "self_desc", + self.self_desc.clone().map_or_else(|| String::from("none"), |ty| ty), + ); + diag.set_span(self.impl_span); + diag.code(rustc_errors::error_code!(E0751)); + match self.negative_impl_span { + Ok(span) => { + diag.span_label(span, fluent::trait_selection::negative_implementation_here); + } + Err(cname) => { + diag.note(fluent::trait_selection::negative_implementation_in_crate); + diag.set_arg("negative_impl_cname", cname.to_string()); + } + } + match self.positive_impl_span { + Ok(span) => { + diag.span_label(span, fluent::trait_selection::positive_implementation_here); + } + Err(cname) => { + diag.note(fluent::trait_selection::positive_implementation_in_crate); + diag.set_arg("positive_impl_cname", cname.to_string()); + } + } + diag + } +} diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index 77cc2c164c34..f039b1fca181 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -37,5 +37,6 @@ extern crate rustc_middle; extern crate smallvec; pub mod autoderef; +pub mod errors; pub mod infer; pub mod traits; diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 4bab99355012..1223c7ced7ab 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -3,6 +3,7 @@ use super::*; +use crate::errors::UnableToConstructConstantValue; use crate::infer::region_constraints::{Constraint, RegionConstraintData}; use crate::infer::InferCtxt; use crate::traits::project::ProjectAndUnifyResult; @@ -830,8 +831,11 @@ impl<'tcx> AutoTraitFinder<'tcx> { Ok(None) => { let tcx = self.tcx; let def_id = unevaluated.def.did; - let reported = tcx.sess.struct_span_err(tcx.def_span(def_id), &format!("unable to construct a constant value for the unevaluated constant {:?}", unevaluated)).emit(); - + let reported = + tcx.sess.emit_err(UnableToConstructConstantValue { + span: tcx.def_span(def_id), + unevaluated, + }); Err(ErrorHandled::Reported(reported)) } Err(err) => Err(err), diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index e11ea7751aa7..14e078096783 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -23,6 +23,7 @@ mod structural_match; mod util; pub mod wf; +use crate::errors::DumpVTableEntries; use crate::infer::outlives::env::OutlivesEnvironment; use crate::infer::{InferCtxt, TyCtxtInferExt}; use crate::traits::error_reporting::InferCtxtExt as _; @@ -763,8 +764,11 @@ fn dump_vtable_entries<'tcx>( trait_ref: ty::PolyTraitRef<'tcx>, entries: &[VtblEntry<'tcx>], ) { - let msg = format!("vtable entries for `{}`: {:#?}", trait_ref, entries); - tcx.sess.struct_span_err(sp, &msg).emit(); + tcx.sess.emit_err(DumpVTableEntries { + span: sp, + trait_ref, + entries: format!("{:#?}", entries), + }); } fn own_existential_vtable_entries<'tcx>( diff --git a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs index 9227bbf011db..3d8840e9e742 100644 --- a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs @@ -8,6 +8,10 @@ use rustc_parse_format::{ParseMode, Parser, Piece, Position}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; +use crate::errors::{ + EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented, +}; + #[derive(Clone, Debug)] pub struct OnUnimplementedFormatString(Symbol); @@ -35,21 +39,6 @@ pub struct OnUnimplementedNote { pub append_const_msg: Option>, } -fn parse_error( - tcx: TyCtxt<'_>, - span: Span, - message: &str, - label: &str, - note: Option<&str>, -) -> ErrorGuaranteed { - let mut diag = struct_span_err!(tcx.sess, span, E0232, "{}", message); - diag.span_label(span, label); - if let Some(note) = note { - diag.note(note); - } - diag.emit() -} - impl<'tcx> OnUnimplementedDirective { fn parse( tcx: TyCtxt<'tcx>, @@ -70,25 +59,9 @@ impl<'tcx> OnUnimplementedDirective { } else { let cond = item_iter .next() - .ok_or_else(|| { - parse_error( - tcx, - span, - "empty `on`-clause in `#[rustc_on_unimplemented]`", - "empty on-clause here", - None, - ) - })? + .ok_or_else(|| tcx.sess.emit_err(EmptyOnClauseInOnUnimplemented { span }))? .meta_item() - .ok_or_else(|| { - parse_error( - tcx, - span, - "invalid `on`-clause in `#[rustc_on_unimplemented]`", - "invalid on-clause here", - None, - ) - })?; + .ok_or_else(|| tcx.sess.emit_err(InvalidOnClauseInOnUnimplemented { span }))?; attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |cfg| { if let Some(value) = cfg.value && let Err(guar) = parse_value(value) { errored = Some(guar); @@ -150,13 +123,7 @@ impl<'tcx> OnUnimplementedDirective { } // nothing found - parse_error( - tcx, - item.span(), - "this attribute must have a valid value", - "expected value here", - Some(r#"eg `#[rustc_on_unimplemented(message="foo")]`"#), - ); + tcx.sess.emit_err(NoValueInOnUnimplemented { span: item.span() }); } if let Some(reported) = errored { diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 0f76fef0eee2..7d299e30ae04 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -12,6 +12,7 @@ pub mod specialization_graph; use specialization_graph::GraphExt; +use crate::errors::NegativePositiveConflict; use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt}; use crate::traits::select::IntercrateAmbiguityCause; use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause}; @@ -327,35 +328,13 @@ fn report_negative_positive_conflict( positive_impl_def_id: DefId, sg: &mut specialization_graph::Graph, ) { - let impl_span = tcx.def_span(local_impl_def_id); - - let mut err = struct_span_err!( - tcx.sess, - impl_span, - E0751, - "found both positive and negative implementation of trait `{}`{}:", - overlap.trait_desc, - overlap.self_desc.clone().map_or_else(String::new, |ty| format!(" for type `{}`", ty)) - ); - - match tcx.span_of_impl(negative_impl_def_id) { - Ok(span) => { - err.span_label(span, "negative implementation here"); - } - Err(cname) => { - err.note(&format!("negative implementation in crate `{}`", cname)); - } - } - - match tcx.span_of_impl(positive_impl_def_id) { - Ok(span) => { - err.span_label(span, "positive implementation here"); - } - Err(cname) => { - err.note(&format!("positive implementation in crate `{}`", cname)); - } - } - + let mut err = tcx.sess.create_err(NegativePositiveConflict { + impl_span: tcx.def_span(local_impl_def_id), + trait_desc: &overlap.trait_desc, + self_desc: &overlap.self_desc, + negative_impl_span: tcx.span_of_impl(negative_impl_def_id), + positive_impl_span: tcx.span_of_impl(positive_impl_def_id), + }); sg.has_errored = Some(err.emit()); } From 31071336f516197760461dec4254f2d2de80b6a1 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 1 Sep 2022 10:25:23 -0700 Subject: [PATCH 4055/5092] rustdoc: remove unneeded CSS `.content table td:first-child > a` This rule was added in c1c6175e62189f8f0e6479bff7bac0e59a95a406 to benefit the module items table. However, the module items table stopped using table tags when 6020c79ddeafe8d9760b27c14c39da81bac9b4a6 switched us over to grid layout. --- src/librustdoc/html/static/css/rustdoc.css | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index deed6eaf0cb6..c53cfa623644 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -207,7 +207,6 @@ h1, h2, h3, h4, h5, h6, a.source, .search-input, .search-results .result-name, -.content table td:first-child > a, .item-left > a, .out-of-band, span.since, From d9b874c083936fa14d139fec243f9df0897fdf09 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Thu, 1 Sep 2022 20:53:59 +0200 Subject: [PATCH 4056/5092] Allow deriving multiple subdiagnostics using one SessionSubdiagnostic This reimplements ac638c1, which had to be reverted in the previous commit because it contains a rebase accident that itself reverted significant unrelated changes to SessionSubdiagnostic. --- .../src/diagnostics/subdiagnostic.rs | 216 ++++++++++-------- .../subdiagnostic-derive.rs | 2 - .../subdiagnostic-derive.stderr | 80 +++---- 3 files changed, 154 insertions(+), 144 deletions(-) diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index 8b40e295bd8a..dce5d3cfb84f 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -211,11 +211,39 @@ impl<'a> HasFieldMap for SessionSubdiagnosticDeriveBuilder<'a> { } } +/// Provides frequently-needed information about the diagnostic kinds being derived for this type. +#[derive(Clone, Copy, Debug)] +struct KindsStatistics { + has_multipart_suggestion: bool, + all_multipart_suggestions: bool, + has_normal_suggestion: bool, +} + +impl<'a> FromIterator<&'a SubdiagnosticKind> for KindsStatistics { + fn from_iter>(kinds: T) -> Self { + let mut ret = Self { + has_multipart_suggestion: false, + all_multipart_suggestions: true, + has_normal_suggestion: false, + }; + for kind in kinds { + if let SubdiagnosticKind::MultipartSuggestion { .. } = kind { + ret.has_multipart_suggestion = true; + } else { + ret.all_multipart_suggestions = false; + } + + if let SubdiagnosticKind::Suggestion { .. } = kind { + ret.has_normal_suggestion = true; + } + } + ret + } +} + impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { - fn identify_kind( - &mut self, - ) -> Result, DiagnosticDeriveError> { - let mut kind_slug = None; + fn identify_kind(&mut self) -> Result, DiagnosticDeriveError> { + let mut kind_slugs = vec![]; for attr in self.variant.ast().attrs { let span = attr.span().unwrap(); @@ -362,10 +390,10 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { | SubdiagnosticKind::MultipartSuggestion { .. } => {} } - kind_slug.set_once(((kind, slug), span)) + kind_slugs.push((kind, slug)) } - Ok(kind_slug.map(|(kind_slug, _)| kind_slug)) + Ok(kind_slugs) } /// Generates the code for a field with no attributes. @@ -387,7 +415,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { fn generate_field_attr_code( &mut self, binding: &BindingInfo<'_>, - kind: &SubdiagnosticKind, + kind_stats: KindsStatistics, ) -> TokenStream { let ast = binding.ast(); assert!(ast.attrs.len() > 0, "field without attributes generating attr code"); @@ -405,7 +433,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { }; let generated = self - .generate_field_code_inner(kind, attr, info) + .generate_field_code_inner(kind_stats, attr, info) .unwrap_or_else(|v| v.to_compile_error()); inner_ty.with(binding, generated) @@ -415,15 +443,15 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { fn generate_field_code_inner( &mut self, - kind: &SubdiagnosticKind, + kind_stats: KindsStatistics, attr: &Attribute, info: FieldInfo<'_>, ) -> Result { let meta = attr.parse_meta()?; match meta { - Meta::Path(path) => self.generate_field_code_inner_path(kind, attr, info, path), + Meta::Path(path) => self.generate_field_code_inner_path(kind_stats, attr, info, path), Meta::List(list @ MetaList { .. }) => { - self.generate_field_code_inner_list(kind, attr, info, list) + self.generate_field_code_inner_list(kind_stats, attr, info, list) } _ => throw_invalid_attr!(attr, &meta), } @@ -432,7 +460,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { /// Generates the code for a `[Meta::Path]`-like attribute on a field (e.g. `#[primary_span]`). fn generate_field_code_inner_path( &mut self, - kind: &SubdiagnosticKind, + kind_stats: KindsStatistics, attr: &Attribute, info: FieldInfo<'_>, path: Path, @@ -445,7 +473,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { match name { "skip_arg" => Ok(quote! {}), "primary_span" => { - if matches!(kind, SubdiagnosticKind::MultipartSuggestion { .. }) { + if kind_stats.has_multipart_suggestion { throw_invalid_attr!(attr, &Meta::Path(path), |diag| { diag.help( "multipart suggestions use one or more `#[suggestion_part]`s rather \ @@ -464,32 +492,20 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { "suggestion_part" => { self.has_suggestion_parts = true; - match kind { - SubdiagnosticKind::MultipartSuggestion { .. } => { - span_err( - span, - "`#[suggestion_part(...)]` attribute without `code = \"...\"`", - ) + if kind_stats.has_multipart_suggestion { + span_err(span, "`#[suggestion_part(...)]` attribute without `code = \"...\"`") .emit(); - Ok(quote! {}) - } - SubdiagnosticKind::Label - | SubdiagnosticKind::Note - | SubdiagnosticKind::Help - | SubdiagnosticKind::Warn - | SubdiagnosticKind::Suggestion { .. } => { - throw_invalid_attr!(attr, &Meta::Path(path), |diag| { - diag.help( + Ok(quote! {}) + } else { + throw_invalid_attr!(attr, &Meta::Path(path), |diag| { + diag.help( "`#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead", ) - }); - } + }); } } "applicability" => { - if let SubdiagnosticKind::Suggestion { .. } - | SubdiagnosticKind::MultipartSuggestion { .. } = kind - { + if kind_stats.has_multipart_suggestion || kind_stats.has_normal_suggestion { report_error_if_not_applied_to_applicability(attr, &info)?; let binding = info.binding.binding.clone(); @@ -501,13 +517,16 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { Ok(quote! {}) } _ => throw_invalid_attr!(attr, &Meta::Path(path), |diag| { - let span_attr = if let SubdiagnosticKind::MultipartSuggestion { .. } = kind { - "suggestion_part" - } else { - "primary_span" - }; + let mut span_attrs = vec![]; + if kind_stats.has_multipart_suggestion { + span_attrs.push("suggestion_part"); + } + if !kind_stats.all_multipart_suggestions { + span_attrs.push("primary_span") + } diag.help(format!( - "only `{span_attr}`, `applicability` and `skip_arg` are valid field attributes", + "only `{}`, `applicability` and `skip_arg` are valid field attributes", + span_attrs.join(", ") )) }), } @@ -517,7 +536,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { /// `#[suggestion_part(code = "...")]`). fn generate_field_code_inner_list( &mut self, - kind: &SubdiagnosticKind, + kind_stats: KindsStatistics, attr: &Attribute, info: FieldInfo<'_>, list: MetaList, @@ -529,7 +548,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { match name { "suggestion_part" => { - if !matches!(kind, SubdiagnosticKind::MultipartSuggestion { .. }) { + if !kind_stats.has_multipart_suggestion { throw_invalid_attr!(attr, &Meta::List(list), |diag| { diag.help( "`#[suggestion_part(...)]` is only valid in multipart suggestions", @@ -576,35 +595,36 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { Ok(quote! { suggestions.push((#binding, #code)); }) } _ => throw_invalid_attr!(attr, &Meta::List(list), |diag| { - let span_attr = if let SubdiagnosticKind::MultipartSuggestion { .. } = kind { - "suggestion_part" - } else { - "primary_span" - }; + let mut span_attrs = vec![]; + if kind_stats.has_multipart_suggestion { + span_attrs.push("suggestion_part"); + } + if !kind_stats.all_multipart_suggestions { + span_attrs.push("primary_span") + } diag.help(format!( - "only `{span_attr}`, `applicability` and `skip_arg` are valid field attributes", + "only `{}`, `applicability` and `skip_arg` are valid field attributes", + span_attrs.join(", ") )) }), } } pub fn into_tokens(&mut self) -> Result { - let Some((kind, slug)) = self.identify_kind()? else { + let kind_slugs = self.identify_kind()?; + if kind_slugs.is_empty() { throw_span_err!( self.variant.ast().ident.span().unwrap(), "subdiagnostic kind not specified" ); }; - let init = match &kind { - SubdiagnosticKind::Label - | SubdiagnosticKind::Note - | SubdiagnosticKind::Help - | SubdiagnosticKind::Warn - | SubdiagnosticKind::Suggestion { .. } => quote! {}, - SubdiagnosticKind::MultipartSuggestion { .. } => { - quote! { let mut suggestions = Vec::new(); } - } + let kind_stats: KindsStatistics = kind_slugs.iter().map(|(kind, _slug)| kind).collect(); + + let init = if kind_stats.has_multipart_suggestion { + quote! { let mut suggestions = Vec::new(); } + } else { + quote! {} }; let attr_args: TokenStream = self @@ -612,7 +632,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { .bindings() .iter() .filter(|binding| !binding.ast().attrs.is_empty()) - .map(|binding| self.generate_field_attr_code(binding, &kind)) + .map(|binding| self.generate_field_attr_code(binding, kind_stats)) .collect(); let span_field = self.span_field.as_ref().map(|(span, _)| span); @@ -622,48 +642,52 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { ); let diag = &self.diag; - let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind); - let message = quote! { rustc_errors::fluent::#slug }; - let call = match kind { - SubdiagnosticKind::Suggestion { suggestion_kind, code } => { - if let Some(span) = span_field { + let mut calls = TokenStream::new(); + for (kind, slug) in kind_slugs { + let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind); + let message = quote! { rustc_errors::fluent::#slug }; + let call = match kind { + SubdiagnosticKind::Suggestion { suggestion_kind, code } => { + if let Some(span) = span_field { + let style = suggestion_kind.to_suggestion_style(); + + quote! { #diag.#name(#span, #message, #code, #applicability, #style); } + } else { + span_err(self.span, "suggestion without `#[primary_span]` field").emit(); + quote! { unreachable!(); } + } + } + SubdiagnosticKind::MultipartSuggestion { suggestion_kind } => { + if !self.has_suggestion_parts { + span_err( + self.span, + "multipart suggestion without any `#[suggestion_part(...)]` fields", + ) + .emit(); + } + let style = suggestion_kind.to_suggestion_style(); - quote! { #diag.#name(#span, #message, #code, #applicability, #style); } - } else { - span_err(self.span, "suggestion without `#[primary_span]` field").emit(); - quote! { unreachable!(); } + quote! { #diag.#name(#message, suggestions, #applicability, #style); } } - } - SubdiagnosticKind::MultipartSuggestion { suggestion_kind } => { - if !self.has_suggestion_parts { - span_err( - self.span, - "multipart suggestion without any `#[suggestion_part(...)]` fields", - ) - .emit(); + SubdiagnosticKind::Label => { + if let Some(span) = span_field { + quote! { #diag.#name(#span, #message); } + } else { + span_err(self.span, "label without `#[primary_span]` field").emit(); + quote! { unreachable!(); } + } } - - let style = suggestion_kind.to_suggestion_style(); - - quote! { #diag.#name(#message, suggestions, #applicability, #style); } - } - SubdiagnosticKind::Label => { - if let Some(span) = span_field { - quote! { #diag.#name(#span, #message); } - } else { - span_err(self.span, "label without `#[primary_span]` field").emit(); - quote! { unreachable!(); } + _ => { + if let Some(span) = span_field { + quote! { #diag.#name(#span, #message); } + } else { + quote! { #diag.#name(#message); } + } } - } - _ => { - if let Some(span) = span_field { - quote! { #diag.#name(#span, #message); } - } else { - quote! { #diag.#name(#message); } - } - } - }; + }; + calls.extend(call); + } let plain_args: TokenStream = self .variant @@ -676,7 +700,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> { Ok(quote! { #init #attr_args - #call + #calls #plain_args }) } diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs index 89eaec78c6f1..812ca0c72bd0 100644 --- a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs +++ b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs @@ -309,9 +309,7 @@ union AC { #[derive(SessionSubdiagnostic)] #[label(parser::add_paren)] -//~^ NOTE previously specified here #[label(parser::add_paren)] -//~^ ERROR specified multiple times struct AD { #[primary_span] span: Span, diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr index 75a34f44bbe7..0a0247e89808 100644 --- a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr +++ b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr @@ -174,20 +174,8 @@ LL | | b: u64 LL | | } | |_^ -error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:313:1 - | -LL | #[label(parser::add_paren)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: previously specified here - --> $DIR/subdiagnostic-derive.rs:311:1 - | -LL | #[label(parser::add_paren)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: `#[label(parser::add_paren)]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:321:28 + --> $DIR/subdiagnostic-derive.rs:319:28 | LL | #[label(parser::add_paren, parser::add_paren)] | ^^^^^^^^^^^^^^^^^ @@ -195,67 +183,67 @@ LL | #[label(parser::add_paren, parser::add_paren)] = help: a diagnostic slug must be the first argument to the attribute error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:334:5 + --> $DIR/subdiagnostic-derive.rs:332:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:331:5 + --> $DIR/subdiagnostic-derive.rs:329:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ error: subdiagnostic kind not specified - --> $DIR/subdiagnostic-derive.rs:340:8 + --> $DIR/subdiagnostic-derive.rs:338:8 | LL | struct AG { | ^^ error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:377:47 + --> $DIR/subdiagnostic-derive.rs:375:47 | LL | #[suggestion(parser::add_paren, code = "...", code = "...")] | ^^^^^^^^^^^^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:377:33 + --> $DIR/subdiagnostic-derive.rs:375:33 | LL | #[suggestion(parser::add_paren, code = "...", code = "...")] | ^^^^^^^^^^^^ error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:395:5 + --> $DIR/subdiagnostic-derive.rs:393:5 | LL | #[applicability] | ^^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:392:5 + --> $DIR/subdiagnostic-derive.rs:390:5 | LL | #[applicability] | ^^^^^^^^^^^^^^^^ error: the `#[applicability]` attribute can only be applied to fields of type `Applicability` - --> $DIR/subdiagnostic-derive.rs:405:5 + --> $DIR/subdiagnostic-derive.rs:403:5 | LL | #[applicability] | ^^^^^^^^^^^^^^^^ error: suggestion without `code = "..."` - --> $DIR/subdiagnostic-derive.rs:418:1 + --> $DIR/subdiagnostic-derive.rs:416:1 | LL | #[suggestion(parser::add_paren)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: invalid applicability - --> $DIR/subdiagnostic-derive.rs:428:46 + --> $DIR/subdiagnostic-derive.rs:426:46 | LL | #[suggestion(parser::add_paren, code ="...", applicability = "foo")] | ^^^^^^^^^^^^^^^^^^^^^ error: suggestion without `#[primary_span]` field - --> $DIR/subdiagnostic-derive.rs:446:1 + --> $DIR/subdiagnostic-derive.rs:444:1 | LL | / #[suggestion(parser::add_paren, code = "...")] LL | | @@ -265,25 +253,25 @@ LL | | } | |_^ error: unsupported type attribute for subdiagnostic enum - --> $DIR/subdiagnostic-derive.rs:460:1 + --> $DIR/subdiagnostic-derive.rs:458:1 | LL | #[label] | ^^^^^^^^ error: `var` doesn't refer to a field on this type - --> $DIR/subdiagnostic-derive.rs:480:39 + --> $DIR/subdiagnostic-derive.rs:478:39 | LL | #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")] | ^^^^^^^ error: `var` doesn't refer to a field on this type - --> $DIR/subdiagnostic-derive.rs:499:43 + --> $DIR/subdiagnostic-derive.rs:497:43 | LL | #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")] | ^^^^^^^ error: `#[suggestion_part]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:522:5 + --> $DIR/subdiagnostic-derive.rs:520:5 | LL | #[suggestion_part] | ^^^^^^^^^^^^^^^^^^ @@ -291,7 +279,7 @@ LL | #[suggestion_part] = help: `#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead error: `#[suggestion_part(...)]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:525:5 + --> $DIR/subdiagnostic-derive.rs:523:5 | LL | #[suggestion_part(code = "...")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -299,7 +287,7 @@ LL | #[suggestion_part(code = "...")] = help: `#[suggestion_part(...)]` is only valid in multipart suggestions error: suggestion without `#[primary_span]` field - --> $DIR/subdiagnostic-derive.rs:519:1 + --> $DIR/subdiagnostic-derive.rs:517:1 | LL | / #[suggestion(parser::add_paren, code = "...")] LL | | @@ -311,13 +299,13 @@ LL | | } | |_^ error: `code` is not a valid nested attribute of a `multipart_suggestion` attribute - --> $DIR/subdiagnostic-derive.rs:534:43 + --> $DIR/subdiagnostic-derive.rs:532:43 | LL | #[multipart_suggestion(parser::add_paren, code = "...", applicability = "machine-applicable")] | ^^^^^^^^^^^^ error: multipart suggestion without any `#[suggestion_part(...)]` fields - --> $DIR/subdiagnostic-derive.rs:534:1 + --> $DIR/subdiagnostic-derive.rs:532:1 | LL | / #[multipart_suggestion(parser::add_paren, code = "...", applicability = "machine-applicable")] LL | | @@ -328,19 +316,19 @@ LL | | } | |_^ error: `#[suggestion_part(...)]` attribute without `code = "..."` - --> $DIR/subdiagnostic-derive.rs:544:5 + --> $DIR/subdiagnostic-derive.rs:542:5 | LL | #[suggestion_part] | ^^^^^^^^^^^^^^^^^^ error: `#[suggestion_part(...)]` attribute without `code = "..."` - --> $DIR/subdiagnostic-derive.rs:552:5 + --> $DIR/subdiagnostic-derive.rs:550:5 | LL | #[suggestion_part()] | ^^^^^^^^^^^^^^^^^^^^ error: `#[primary_span]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:561:5 + --> $DIR/subdiagnostic-derive.rs:559:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ @@ -348,7 +336,7 @@ LL | #[primary_span] = help: multipart suggestions use one or more `#[suggestion_part]`s rather than one `#[primary_span]` error: multipart suggestion without any `#[suggestion_part(...)]` fields - --> $DIR/subdiagnostic-derive.rs:558:1 + --> $DIR/subdiagnostic-derive.rs:556:1 | LL | / #[multipart_suggestion(parser::add_paren)] LL | | @@ -360,19 +348,19 @@ LL | | } | |_^ error: `#[suggestion_part(...)]` attribute without `code = "..."` - --> $DIR/subdiagnostic-derive.rs:569:5 + --> $DIR/subdiagnostic-derive.rs:567:5 | LL | #[suggestion_part] | ^^^^^^^^^^^^^^^^^^ error: `#[suggestion_part(...)]` attribute without `code = "..."` - --> $DIR/subdiagnostic-derive.rs:572:5 + --> $DIR/subdiagnostic-derive.rs:570:5 | LL | #[suggestion_part()] | ^^^^^^^^^^^^^^^^^^^^ error: `#[suggestion_part(foo = ...)]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:575:23 + --> $DIR/subdiagnostic-derive.rs:573:23 | LL | #[suggestion_part(foo = "bar")] | ^^^^^^^^^^^ @@ -380,37 +368,37 @@ LL | #[suggestion_part(foo = "bar")] = help: `code` is the only valid nested attribute error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` - --> $DIR/subdiagnostic-derive.rs:578:5 + --> $DIR/subdiagnostic-derive.rs:576:5 | LL | #[suggestion_part(code = "...")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` - --> $DIR/subdiagnostic-derive.rs:581:5 + --> $DIR/subdiagnostic-derive.rs:579:5 | LL | #[suggestion_part()] | ^^^^^^^^^^^^^^^^^^^^ error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:589:37 + --> $DIR/subdiagnostic-derive.rs:587:37 | LL | #[suggestion_part(code = "...", code = ",,,")] | ^^^^^^^^^^^^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:589:23 + --> $DIR/subdiagnostic-derive.rs:587:23 | LL | #[suggestion_part(code = "...", code = ",,,")] | ^^^^^^^^^^^^ error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:619:5 + --> $DIR/subdiagnostic-derive.rs:617:5 | LL | #[applicability] | ^^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:616:43 + --> $DIR/subdiagnostic-derive.rs:614:43 | LL | #[multipart_suggestion(parser::add_paren, applicability = "machine-applicable")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -475,6 +463,6 @@ error[E0425]: cannot find value `slug` in module `rustc_errors::fluent` LL | #[label(slug)] | ^^^^ not found in `rustc_errors::fluent` -error: aborting due to 64 previous errors +error: aborting due to 63 previous errors For more information about this error, try `rustc --explain E0425`. From 5f3545e773f930c3345e7166b98bf9d2a76adff6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 1 Sep 2022 22:25:14 +0200 Subject: [PATCH 4057/5092] disable extern-so ffi support for now due to licensing situation --- Cargo.lock | 27 --------------------------- Cargo.toml | 2 +- README.md | 11 ----------- src/shims/foreign_items.rs | 6 +++--- src/shims/mod.rs | 2 +- tests/compiletest.rs | 4 ++-- 6 files changed, 7 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 28be08c467cd..a7303421808f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "abort_on_panic" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955f37ac58af2416bac687c8ab66a4ccba282229bd7422a28d2281a5e66a6116" - [[package]] name = "addr2line" version = "0.17.0" @@ -314,26 +308,6 @@ version = "0.2.112" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" -[[package]] -name = "libffi" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e08093a2ddeee94bd0c830a53d895ff91f1f3bb0f9b3c8c6b00739cdf76bc1d" -dependencies = [ - "abort_on_panic", - "libc", - "libffi-sys", -] - -[[package]] -name = "libffi-sys" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab4106b7f09d7b87d021334d5618fac1dfcfb824d4c5fe111ff0074dfd242e15" -dependencies = [ - "cc", -] - [[package]] name = "libloading" version = "0.7.3" @@ -418,7 +392,6 @@ dependencies = [ "getrandom", "lazy_static", "libc", - "libffi", "libloading", "log", "measureme", diff --git a/Cargo.toml b/Cargo.toml index 0a3dfc2a84e3..c0a217b64116 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ doctest = false # and no doc tests [dependencies] getrandom = { version = "0.2", features = ["std"] } env_logger = "0.9" -libffi = "3.0.0" +#FIXME(miri#2526): libffi = "3.0.0" libloading = "0.7" log = "0.4" shell-escape = "0.1.4" diff --git a/README.md b/README.md index 8e96338a865f..c7a3200dbd90 100644 --- a/README.md +++ b/README.md @@ -346,17 +346,6 @@ to Miri failing to detect cases of undefined behavior in a program. this flag is **unsound**. * `-Zmiri-disable-weak-memory-emulation` disables the emulation of some C++11 weak memory effects. -* `-Zmiri-extern-so-file=` is an experimental flag for providing support - for FFI calls. Functions not provided by that file are still executed via the usual Miri shims. - **WARNING**: If an invalid/incorrect `.so` file is specified, this can cause undefined behaviour in Miri itself! - And of course, Miri cannot do any checks on the actions taken by the external code. - Note that Miri has its own handling of file descriptors, so if you want to replace *some* functions - working on file descriptors, you will have to replace *all* of them, or the two kinds of - file descriptors will be mixed up. - This is **work in progress**; currently, only integer arguments and return values are - supported (and no, pointer/integer casts to work around this limitation will not work; - they will fail horribly). - Follow [the discussion on supporting other types](https://github.com/rust-lang/miri/issues/2365). * `-Zmiri-measureme=` enables `measureme` profiling for the interpreted program. This can be used to find which parts of your program are executing slowly under Miri. The profile is written out to a file with the prefix ``, and can be processed diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index b94b6bbb2b8b..bd46e4ae80e2 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -23,7 +23,7 @@ use rustc_target::{ use super::backtrace::EvalContextExt as _; use crate::helpers::{convert::Truncate, target_os_is_unix}; -use crate::shims::ffi_support::EvalContextExt as _; +//FIXME(miri#2526): use crate::shims::ffi_support::EvalContextExt as _; use crate::*; /// Returned by `emulate_foreign_item_by_name`. @@ -375,9 +375,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // An Ok(false) here means that the function being called was not exported // by the specified `.so` file; we should continue and check if it corresponds to // a provided shim. - if this.call_external_c_fct(link_name, dest, args)? { + /*FIXME(miri#2526): if this.call_external_c_fct(link_name, dest, args)? { return Ok(EmulateByNameResult::NeedsJumping); - } + }*/ } // When adding a new shim, you should follow the following pattern: diff --git a/src/shims/mod.rs b/src/shims/mod.rs index ee2145db7e1b..8179d09defe3 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -1,7 +1,7 @@ #![warn(clippy::integer_arithmetic)] mod backtrace; -pub mod ffi_support; +//FIXME(miri#2526): pub mod ffi_support; pub mod foreign_items; pub mod intrinsics; pub mod unix; diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 6b5668e2d6c4..0e492c3eecdf 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -212,8 +212,8 @@ fn main() -> Result<()> { ui(Mode::Panic, "tests/panic", WithDependencies)?; ui(Mode::Fail { require_patterns: true }, "tests/fail", WithDependencies)?; if cfg!(target_os = "linux") { - ui(Mode::Pass, "tests/extern-so/pass", WithoutDependencies)?; - ui(Mode::Fail { require_patterns: true }, "tests/extern-so/fail", WithDependencies)?; + //FIXME(miri#2526): ui(Mode::Pass, "tests/extern-so/pass", WithoutDependencies)?; + //FIXME(miri#2526): ui(Mode::Fail { require_patterns: true }, "tests/extern-so/fail", WithDependencies)?; } Ok(()) From f76eac48665feaac77fd5cfe6528b403e842af8f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 1 Sep 2022 22:59:05 +0200 Subject: [PATCH 4058/5092] update Miri --- Cargo.lock | 38 +++++--------------------------------- src/tools/miri | 2 +- 2 files changed, 6 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 002d73be7d1d..9c9848a8563c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1035,16 +1035,6 @@ dependencies = [ "quote", ] -[[package]] -name = "ctor" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c" -dependencies = [ - "quote", - "syn", -] - [[package]] name = "curl" version = "0.4.43" @@ -2293,6 +2283,7 @@ dependencies = [ "getrandom 0.2.0", "lazy_static", "libc", + "libloading", "log", "measureme", "rand 0.8.5", @@ -2471,15 +2462,6 @@ version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" -[[package]] -name = "output_vt100" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" -dependencies = [ - "winapi", -] - [[package]] name = "owo-colors" version = "3.4.0" @@ -2720,18 +2702,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" -[[package]] -name = "pretty_assertions" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89f989ac94207d048d92db058e4f6ec7342b0971fc58d1271ca148b799b3563" -dependencies = [ - "ansi_term", - "ctor", - "diff", - "output_vt100", -] - [[package]] name = "pretty_env_logger" version = "0.4.0" @@ -5119,14 +5089,16 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" [[package]] name = "ui_test" -version = "0.1.0" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d1f546a5883ae78da735bba529ec1116661e2f73582f23920d994dc97da3a22" dependencies = [ "cargo_metadata 0.15.0", "color-eyre", "colored", "crossbeam", + "diff", "lazy_static", - "pretty_assertions", "regex", "rustc_version", "serde", diff --git a/src/tools/miri b/src/tools/miri index ab88e64b152d..8c8b479be723 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit ab88e64b152d3704c35db96dbbc6efaaed67773f +Subproject commit 8c8b479be723fb103b0b1203faf9246a3f587250 From b1f86a49ea0119e66ee7dced613c91824d56c6d0 Mon Sep 17 00:00:00 2001 From: Dmitrii Lavrov Date: Thu, 30 Jun 2022 16:57:15 +0300 Subject: [PATCH 4059/5092] New lint `bool_to_int_with_if` --- CHANGELOG.md | 1 + clippy_lints/src/bool_to_int_with_if.rs | 125 +++++++++++++++++++++ clippy_lints/src/lib.register_all.rs | 1 + clippy_lints/src/lib.register_lints.rs | 1 + clippy_lints/src/lib.register_style.rs | 1 + clippy_lints/src/lib.rs | 2 + clippy_lints/src/matches/single_match.rs | 8 +- clippy_lints/src/only_used_in_recursion.rs | 12 +- tests/ui/author/struct.rs | 7 +- tests/ui/bool_to_int_with_if.fixed | 85 ++++++++++++++ tests/ui/bool_to_int_with_if.rs | 109 ++++++++++++++++++ tests/ui/bool_to_int_with_if.stderr | 84 ++++++++++++++ 12 files changed, 419 insertions(+), 17 deletions(-) create mode 100644 clippy_lints/src/bool_to_int_with_if.rs create mode 100644 tests/ui/bool_to_int_with_if.fixed create mode 100644 tests/ui/bool_to_int_with_if.rs create mode 100644 tests/ui/bool_to_int_with_if.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index c488c142e46f..257add86b6e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3603,6 +3603,7 @@ Released 2018-09-13 [`blocks_in_if_conditions`]: https://rust-lang.github.io/rust-clippy/master/index.html#blocks_in_if_conditions [`bool_assert_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison [`bool_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison +[`bool_to_int_with_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_to_int_with_if [`borrow_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_as_ptr [`borrow_deref_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_deref_ref [`borrow_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const diff --git a/clippy_lints/src/bool_to_int_with_if.rs b/clippy_lints/src/bool_to_int_with_if.rs new file mode 100644 index 000000000000..a4b8cbb0d82a --- /dev/null +++ b/clippy_lints/src/bool_to_int_with_if.rs @@ -0,0 +1,125 @@ +use rustc_ast::{ExprPrecedence, LitKind}; +use rustc_hir::{Block, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +use clippy_utils::{diagnostics::span_lint_and_then, is_else_clause, source::snippet_block_with_applicability}; +use rustc_errors::Applicability; + +declare_clippy_lint! { + /// ### What it does + /// Instead of using an if statement to convert a bool to an int, + /// this lint suggests using a `from()` function or an `as` coercion. + /// + /// ### Why is this bad? + /// Coercion or `from()` is idiomatic way to convert bool to a number. + /// Both methods are guaranteed to return 1 for true, and 0 for false. + /// + /// See https://doc.rust-lang.org/std/primitive.bool.html#impl-From%3Cbool%3E + /// + /// ### Example + /// ```rust + /// # let condition = false; + /// if condition { + /// 1_i64 + /// } else { + /// 0 + /// }; + /// ``` + /// Use instead: + /// ```rust + /// # let condition = false; + /// i64::from(condition); + /// ``` + /// or + /// ```rust + /// # let condition = false; + /// condition as i64; + /// ``` + #[clippy::version = "1.65.0"] + pub BOOL_TO_INT_WITH_IF, + style, + "using if to convert bool to int" +} +declare_lint_pass!(BoolToIntWithIf => [BOOL_TO_INT_WITH_IF]); + +impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf { + fn check_expr(&mut self, ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) { + if !expr.span.from_expansion() { + check_if_else(ctx, expr); + } + } +} + +fn check_if_else<'tcx>(ctx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) { + if let ExprKind::If(check, then, Some(else_)) = expr.kind + && let Some(then_lit) = int_literal(then) + && let Some(else_lit) = int_literal(else_) + && check_int_literal_equals_val(then_lit, 1) + && check_int_literal_equals_val(else_lit, 0) + { + let mut applicability = Applicability::MachineApplicable; + let snippet = snippet_block_with_applicability(ctx, check.span, "..", None, &mut applicability); + let snippet_with_braces = { + let need_parens = should_have_parentheses(check); + let (left_paren, right_paren) = if need_parens {("(", ")")} else {("", "")}; + format!("{left_paren}{snippet}{right_paren}") + }; + + let ty = ctx.typeck_results().expr_ty(then_lit); // then and else must be of same type + + let suggestion = { + let wrap_in_curly = is_else_clause(ctx.tcx, expr); + let (left_curly, right_curly) = if wrap_in_curly {("{", "}")} else {("", "")}; + format!( + "{left_curly}{ty}::from({snippet}){right_curly}" + ) + }; // when used in else clause if statement should be wrapped in curly braces + + span_lint_and_then(ctx, + BOOL_TO_INT_WITH_IF, + expr.span, + "boolean to int conversion using if", + |diag| { + diag.span_suggestion( + expr.span, + "replace with from", + suggestion, + applicability, + ); + diag.note(format!("`{snippet_with_braces} as {ty}` or `{snippet_with_braces}.into()` can also be valid options")); + }); + }; +} + +// If block contains only a int literal expression, return literal expression +fn int_literal<'tcx>(expr: &'tcx rustc_hir::Expr<'tcx>) -> Option<&'tcx rustc_hir::Expr<'tcx>> { + if let ExprKind::Block(block, _) = expr.kind + && let Block { + stmts: [], // Shouldn't lint if statements with side effects + expr: Some(expr), + .. + } = block + && let ExprKind::Lit(lit) = &expr.kind + && let LitKind::Int(_, _) = lit.node + { + Some(expr) + } else { + None + } +} + +fn check_int_literal_equals_val<'tcx>(expr: &'tcx rustc_hir::Expr<'tcx>, expected_value: u128) -> bool { + if let ExprKind::Lit(lit) = &expr.kind + && let LitKind::Int(val, _) = lit.node + && val == expected_value + { + true + } else { + false + } +} + +fn should_have_parentheses<'tcx>(check: &'tcx rustc_hir::Expr<'tcx>) -> bool { + check.precedence().order() < ExprPrecedence::Cast.order() +} diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 134cbbf7b5c6..1f85382347aa 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -17,6 +17,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF), LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON), + LintId::of(bool_to_int_with_if::BOOL_TO_INT_WITH_IF), LintId::of(booleans::NONMINIMAL_BOOL), LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR), LintId::of(borrow_deref_ref::BORROW_DEREF_REF), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index fd20e016578a..13b573beea1b 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -56,6 +56,7 @@ store.register_lints(&[ await_holding_invalid::AWAIT_HOLDING_REFCELL_REF, blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS, bool_assert_comparison::BOOL_ASSERT_COMPARISON, + bool_to_int_with_if::BOOL_TO_INT_WITH_IF, booleans::NONMINIMAL_BOOL, booleans::OVERLY_COMPLEX_BOOL_EXPR, borrow_deref_ref::BORROW_DEREF_REF, diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs index b5cb078e7a3c..05d2ec2e9e1e 100644 --- a/clippy_lints/src/lib.register_style.rs +++ b/clippy_lints/src/lib.register_style.rs @@ -6,6 +6,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS), LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON), + LintId::of(bool_to_int_with_if::BOOL_TO_INT_WITH_IF), LintId::of(casts::FN_TO_NUMERIC_CAST), LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION), LintId::of(collapsible_if::COLLAPSIBLE_ELSE_IF), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 178e57aaf61f..a26e129f094e 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -178,6 +178,7 @@ mod attrs; mod await_holding_invalid; mod blocks_in_if_conditions; mod bool_assert_comparison; +mod bool_to_int_with_if; mod booleans; mod borrow_deref_ref; mod cargo; @@ -900,6 +901,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(manual_string_new::ManualStringNew)); store.register_late_pass(|| Box::new(unused_peekable::UnusedPeekable)); store.register_early_pass(|| Box::new(multi_assignments::MultiAssignments)); + store.register_late_pass(|| Box::new(bool_to_int_with_if::BoolToIntWithIf)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index 92091a0c3395..52632e88b1bd 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -201,12 +201,8 @@ fn form_exhaustive_matches<'a>(cx: &LateContext<'a>, ty: Ty<'a>, left: &Pat<'_>, // in the arms, so we need to evaluate the correct offsets here in order to iterate in // both arms at the same time. let len = max( - left_in.len() + { - if left_pos.is_some() { 1 } else { 0 } - }, - right_in.len() + { - if right_pos.is_some() { 1 } else { 0 } - }, + left_in.len() + usize::from(left_pos.is_some()), + right_in.len() + usize::from(right_pos.is_some()), ); let mut left_pos = left_pos.unwrap_or(usize::MAX); let mut right_pos = right_pos.unwrap_or(usize::MAX); diff --git a/clippy_lints/src/only_used_in_recursion.rs b/clippy_lints/src/only_used_in_recursion.rs index 774a3540d1e0..c55478b3441f 100644 --- a/clippy_lints/src/only_used_in_recursion.rs +++ b/clippy_lints/src/only_used_in_recursion.rs @@ -234,11 +234,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { })) => ( def_id.to_def_id(), FnKind::TraitFn, - if sig.decl.implicit_self.has_implicit_self() { - 1 - } else { - 0 - }, + usize::from(sig.decl.implicit_self.has_implicit_self()), ), Some(Node::ImplItem(&ImplItem { kind: ImplItemKind::Fn(ref sig, _), @@ -253,11 +249,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { ( trait_item_id, FnKind::ImplTraitFn(cx.tcx.erase_regions(trait_ref.substs) as *const _ as usize), - if sig.decl.implicit_self.has_implicit_self() { - 1 - } else { - 0 - }, + usize::from(sig.decl.implicit_self.has_implicit_self()), ) } else { (def_id.to_def_id(), FnKind::Fn, 0) diff --git a/tests/ui/author/struct.rs b/tests/ui/author/struct.rs index 5fdf3433a370..a99bdfc13137 100644 --- a/tests/ui/author/struct.rs +++ b/tests/ui/author/struct.rs @@ -1,4 +1,9 @@ -#[allow(clippy::unnecessary_operation, clippy::single_match)] +#![allow( + clippy::unnecessary_operation, + clippy::single_match, + clippy::no_effect, + clippy::bool_to_int_with_if +)] fn main() { struct Test { field: u32, diff --git a/tests/ui/bool_to_int_with_if.fixed b/tests/ui/bool_to_int_with_if.fixed new file mode 100644 index 000000000000..9c1098dc4c17 --- /dev/null +++ b/tests/ui/bool_to_int_with_if.fixed @@ -0,0 +1,85 @@ +// run-rustfix + +#![warn(clippy::bool_to_int_with_if)] +#![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)] + +fn main() { + let a = true; + let b = false; + + let x = 1; + let y = 2; + + // Should lint + // precedence + i32::from(a); + i32::from(!a); + i32::from(a || b); + i32::from(cond(a, b)); + i32::from(x + y < 4); + + // if else if + if a { + 123 + } else {i32::from(b)}; + + // Shouldn't lint + + if a { + 1 + } else if b { + 0 + } else { + 3 + }; + + if a { + 3 + } else if b { + 1 + } else { + -2 + }; + + if a { + 3 + } else { + 0 + }; + if a { + side_effect(); + 1 + } else { + 0 + }; + if a { + 1 + } else { + side_effect(); + 0 + }; + + // multiple else ifs + if a { + 123 + } else if b { + 1 + } else if a | b { + 0 + } else { + 123 + }; + + some_fn(a); +} + +// Lint returns and type inference +fn some_fn(a: bool) -> u8 { + u8::from(a) +} + +fn side_effect() {} + +fn cond(a: bool, b: bool) -> bool { + a || b +} diff --git a/tests/ui/bool_to_int_with_if.rs b/tests/ui/bool_to_int_with_if.rs new file mode 100644 index 000000000000..0c967dac6e2d --- /dev/null +++ b/tests/ui/bool_to_int_with_if.rs @@ -0,0 +1,109 @@ +// run-rustfix + +#![warn(clippy::bool_to_int_with_if)] +#![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)] + +fn main() { + let a = true; + let b = false; + + let x = 1; + let y = 2; + + // Should lint + // precedence + if a { + 1 + } else { + 0 + }; + if !a { + 1 + } else { + 0 + }; + if a || b { + 1 + } else { + 0 + }; + if cond(a, b) { + 1 + } else { + 0 + }; + if x + y < 4 { + 1 + } else { + 0 + }; + + // if else if + if a { + 123 + } else if b { + 1 + } else { + 0 + }; + + // Shouldn't lint + + if a { + 1 + } else if b { + 0 + } else { + 3 + }; + + if a { + 3 + } else if b { + 1 + } else { + -2 + }; + + if a { + 3 + } else { + 0 + }; + if a { + side_effect(); + 1 + } else { + 0 + }; + if a { + 1 + } else { + side_effect(); + 0 + }; + + // multiple else ifs + if a { + 123 + } else if b { + 1 + } else if a | b { + 0 + } else { + 123 + }; + + some_fn(a); +} + +// Lint returns and type inference +fn some_fn(a: bool) -> u8 { + if a { 1 } else { 0 } +} + +fn side_effect() {} + +fn cond(a: bool, b: bool) -> bool { + a || b +} diff --git a/tests/ui/bool_to_int_with_if.stderr b/tests/ui/bool_to_int_with_if.stderr new file mode 100644 index 000000000000..8647a9cffbed --- /dev/null +++ b/tests/ui/bool_to_int_with_if.stderr @@ -0,0 +1,84 @@ +error: boolean to int conversion using if + --> $DIR/bool_to_int_with_if.rs:15:5 + | +LL | / if a { +LL | | 1 +LL | | } else { +LL | | 0 +LL | | }; + | |_____^ help: replace with from: `i32::from(a)` + | + = note: `-D clippy::bool-to-int-with-if` implied by `-D warnings` + = note: `a as i32` or `a.into()` can also be valid options + +error: boolean to int conversion using if + --> $DIR/bool_to_int_with_if.rs:20:5 + | +LL | / if !a { +LL | | 1 +LL | | } else { +LL | | 0 +LL | | }; + | |_____^ help: replace with from: `i32::from(!a)` + | + = note: `!a as i32` or `!a.into()` can also be valid options + +error: boolean to int conversion using if + --> $DIR/bool_to_int_with_if.rs:25:5 + | +LL | / if a || b { +LL | | 1 +LL | | } else { +LL | | 0 +LL | | }; + | |_____^ help: replace with from: `i32::from(a || b)` + | + = note: `(a || b) as i32` or `(a || b).into()` can also be valid options + +error: boolean to int conversion using if + --> $DIR/bool_to_int_with_if.rs:30:5 + | +LL | / if cond(a, b) { +LL | | 1 +LL | | } else { +LL | | 0 +LL | | }; + | |_____^ help: replace with from: `i32::from(cond(a, b))` + | + = note: `cond(a, b) as i32` or `cond(a, b).into()` can also be valid options + +error: boolean to int conversion using if + --> $DIR/bool_to_int_with_if.rs:35:5 + | +LL | / if x + y < 4 { +LL | | 1 +LL | | } else { +LL | | 0 +LL | | }; + | |_____^ help: replace with from: `i32::from(x + y < 4)` + | + = note: `(x + y < 4) as i32` or `(x + y < 4).into()` can also be valid options + +error: boolean to int conversion using if + --> $DIR/bool_to_int_with_if.rs:44:12 + | +LL | } else if b { + | ____________^ +LL | | 1 +LL | | } else { +LL | | 0 +LL | | }; + | |_____^ help: replace with from: `{i32::from(b)}` + | + = note: `b as i32` or `b.into()` can also be valid options + +error: boolean to int conversion using if + --> $DIR/bool_to_int_with_if.rs:102:5 + | +LL | if a { 1 } else { 0 } + | ^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `u8::from(a)` + | + = note: `a as u8` or `a.into()` can also be valid options + +error: aborting due to 7 previous errors + From 053874eecc9806f36195c35a7fad9c8878b0788e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 25 Aug 2022 12:25:44 +1000 Subject: [PATCH 4060/5092] Clean up THIR patterns. `thir::Pat::kind` is a `Box`, which doesn't follow the usual pattern in AST/HIR/THIR which is that the "kind" enum for a node is stored inline within the parent struct. This commit makes the `PatKind` directly inline within the `Pat`. This requires using `Box` in all the types that hold a `Pat. Ideally, `Pat` would be stored in `Thir` like `Expr` and `Stmt` and referred to with a `PatId` rather than `Box`. But this is hard to do because lots of `Pat`s get created after the destruction of the `Cx` that does normal THIR building. But this does get us a step closer to `PatId`, because all the `Box` occurrences would be replaced with `PatId` if `PatId` ever happened. At 128 bytes, `Pat` is large. Subsequent commits will shrink it. --- compiler/rustc_middle/src/thir.rs | 48 +++++++++---------- compiler/rustc_middle/src/thir/visit.rs | 4 +- compiler/rustc_mir_build/src/build/block.rs | 4 +- .../rustc_mir_build/src/build/matches/mod.rs | 21 ++++---- .../src/build/matches/simplify.rs | 14 +++--- .../rustc_mir_build/src/build/matches/test.rs | 20 ++++---- .../rustc_mir_build/src/build/matches/util.rs | 6 +-- compiler/rustc_mir_build/src/build/mod.rs | 4 +- .../rustc_mir_build/src/check_unsafety.rs | 4 +- compiler/rustc_mir_build/src/thir/cx/block.rs | 8 ++-- compiler/rustc_mir_build/src/thir/cx/mod.rs | 2 +- .../src/thir/pattern/const_to_pat.rs | 34 ++++++------- .../src/thir/pattern/deconstruct_pat.rs | 26 +++++----- .../rustc_mir_build/src/thir/pattern/mod.rs | 47 +++++++++--------- compiler/rustc_ty_utils/src/consts.rs | 2 +- 15 files changed, 123 insertions(+), 121 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 0f2504e3d9af..99d72f70ba68 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -180,7 +180,7 @@ pub enum StmtKind<'tcx> { /// `let = ...` /// /// If a type annotation is included, it is added as an ascription pattern. - pattern: Pat<'tcx>, + pattern: Box>, /// `let pat: ty = ` initializer: Option, @@ -301,7 +301,7 @@ pub enum ExprKind<'tcx> { }, Let { expr: ExprId, - pat: Pat<'tcx>, + pat: Box>, }, /// A `match` expression. Match { @@ -467,7 +467,7 @@ pub struct FruInfo<'tcx> { /// A `match` arm. #[derive(Clone, Debug, HashStable)] pub struct Arm<'tcx> { - pub pattern: Pat<'tcx>, + pub pattern: Box>, pub guard: Option>, pub body: ExprId, pub lint_level: LintLevel, @@ -479,7 +479,7 @@ pub struct Arm<'tcx> { #[derive(Clone, Debug, HashStable)] pub enum Guard<'tcx> { If(ExprId), - IfLet(Pat<'tcx>, ExprId), + IfLet(Box>, ExprId), } #[derive(Copy, Clone, Debug, HashStable)] @@ -534,19 +534,19 @@ pub enum BindingMode { #[derive(Clone, Debug, HashStable)] pub struct FieldPat<'tcx> { pub field: Field, - pub pattern: Pat<'tcx>, + pub pattern: Box>, } #[derive(Clone, Debug, HashStable)] pub struct Pat<'tcx> { pub ty: Ty<'tcx>, pub span: Span, - pub kind: Box>, + pub kind: PatKind<'tcx>, } impl<'tcx> Pat<'tcx> { pub fn wildcard_from_ty(ty: Ty<'tcx>) -> Self { - Pat { ty, span: DUMMY_SP, kind: Box::new(PatKind::Wild) } + Pat { ty, span: DUMMY_SP, kind: PatKind::Wild } } } @@ -581,7 +581,7 @@ pub enum PatKind<'tcx> { AscribeUserType { ascription: Ascription<'tcx>, - subpattern: Pat<'tcx>, + subpattern: Box>, }, /// `x`, `ref x`, `x @ P`, etc. @@ -591,7 +591,7 @@ pub enum PatKind<'tcx> { mode: BindingMode, var: LocalVarId, ty: Ty<'tcx>, - subpattern: Option>, + subpattern: Option>>, /// Is this the leftmost occurrence of the binding, i.e., is `var` the /// `HirId` of this pattern? is_primary: bool, @@ -614,7 +614,7 @@ pub enum PatKind<'tcx> { /// `box P`, `&P`, `&mut P`, etc. Deref { - subpattern: Pat<'tcx>, + subpattern: Box>, }, /// One of the following: @@ -634,22 +634,22 @@ pub enum PatKind<'tcx> { /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty. /// e.g., `&[ref xs @ ..]`. Slice { - prefix: Vec>, - slice: Option>, - suffix: Vec>, + prefix: Vec>>, + slice: Option>>, + suffix: Vec>>, }, /// Fixed match against an array; irrefutable. Array { - prefix: Vec>, - slice: Option>, - suffix: Vec>, + prefix: Vec>>, + slice: Option>>, + suffix: Vec>>, }, /// An or-pattern, e.g. `p | q`. /// Invariant: `pats.len() >= 2`. Or { - pats: Vec>, + pats: Vec>>, }, } @@ -674,7 +674,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> { }; let mut start_or_comma = || start_or_continue(", "); - match *self.kind { + match self.kind { PatKind::Wild => write!(f, "_"), PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{}: _", subpattern), PatKind::Binding { mutability, name, mode, ref subpattern, .. } => { @@ -695,7 +695,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> { Ok(()) } PatKind::Variant { ref subpatterns, .. } | PatKind::Leaf { ref subpatterns } => { - let variant = match *self.kind { + let variant = match self.kind { PatKind::Variant { adt_def, variant_index, .. } => { Some(adt_def.variant(variant_index)) } @@ -714,7 +714,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> { let mut printed = 0; for p in subpatterns { - if let PatKind::Wild = *p.pattern.kind { + if let PatKind::Wild = p.pattern.kind { continue; } let name = variant.fields[p.field.index()].name; @@ -780,7 +780,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> { } if let Some(ref slice) = *slice { write!(f, "{}", start_or_comma())?; - match *slice.kind { + match slice.kind { PatKind::Wild => {} _ => write!(f, "{}", slice)?, } @@ -809,8 +809,8 @@ mod size_asserts { static_assert_size!(Block, 56); static_assert_size!(Expr<'_>, 64); static_assert_size!(ExprKind<'_>, 40); - static_assert_size!(Pat<'_>, 24); + static_assert_size!(Pat<'_>, 128); static_assert_size!(PatKind<'_>, 112); - static_assert_size!(Stmt<'_>, 72); - static_assert_size!(StmtKind<'_>, 64); + static_assert_size!(Stmt<'_>, 56); + static_assert_size!(StmtKind<'_>, 48); } diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index c5c48a636092..5168c2120f43 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -211,7 +211,7 @@ pub fn walk_arm<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, arm: &Arm<' pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'tcx>) { use PatKind::*; - match pat.kind.as_ref() { + match &pat.kind { AscribeUserType { subpattern, ascription: _ } | Deref { subpattern } | Binding { @@ -236,7 +236,7 @@ pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<' visitor.visit_pat(&subpattern); } if let Some(pat) = slice { - visitor.visit_pat(pat); + visitor.visit_pat(&pat); } for subpattern in suffix { visitor.visit_pat(&subpattern); diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index d5213dc0e046..ef976d6308b5 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -117,7 +117,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { lint_level, else_block, } => { - let ignores_expr_result = matches!(*pattern.kind, PatKind::Wild); + let ignores_expr_result = matches!(pattern.kind, PatKind::Wild); this.block_context.push(BlockFrame::Statement { ignores_expr_result }); // Enter the remainder scope, i.e., the bindings' destruction scope. @@ -160,7 +160,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ArmHasGuard(false), Some((None, initializer_span)), ); - this.expr_into_pattern(block, pattern.clone(), init) // irrefutable pattern + this.expr_into_pattern(block, (**pattern).clone(), init) // irrefutable pattern } }) }, diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 0e5cd6199ac9..72f8034bbc17 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -493,7 +493,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { irrefutable_pat: Pat<'tcx>, initializer: &Expr<'tcx>, ) -> BlockAnd<()> { - match *irrefutable_pat.kind { + match irrefutable_pat.kind { // Optimize the case of `let x = ...` to write directly into `x` PatKind::Binding { mode: BindingMode::ByValue, var, subpattern: None, .. } => { let place = @@ -518,13 +518,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // broken. PatKind::AscribeUserType { subpattern: - Pat { + box Pat { kind: - box PatKind::Binding { - mode: BindingMode::ByValue, - var, - subpattern: None, - .. + PatKind::Binding { + mode: BindingMode::ByValue, var, subpattern: None, .. }, .. }, @@ -744,7 +741,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { "visit_primary_bindings: pattern={:?} pattern_user_ty={:?}", pattern, pattern_user_ty ); - match *pattern.kind { + match pattern.kind { PatKind::Binding { mutability, name, @@ -1330,7 +1327,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // All of the or-patterns have been sorted to the end, so if the first // pattern is an or-pattern we only have or-patterns. - match *first_candidate.match_pairs[0].pattern.kind { + match first_candidate.match_pairs[0].pattern.kind { PatKind::Or { .. } => (), _ => { self.test_candidates( @@ -1350,7 +1347,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut otherwise = None; for match_pair in match_pairs { - let PatKind::Or { ref pats } = &*match_pair.pattern.kind else { + let PatKind::Or { ref pats } = &match_pair.pattern.kind else { bug!("Or-patterns should have been sorted to the end"); }; let or_span = match_pair.pattern.span; @@ -1384,7 +1381,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, candidate: &mut Candidate<'pat, 'tcx>, otherwise: &mut Option, - pats: &'pat [Pat<'tcx>], + pats: &'pat [Box>], or_span: Span, place: PlaceBuilder<'tcx>, fake_borrows: &mut Option>>, @@ -2289,7 +2286,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let else_block_span = self.thir[else_block].span; let (matching, failure) = self.in_if_then_scope(remainder_scope, |this| { let scrutinee = unpack!(block = this.lower_scrutinee(block, init, initializer_span)); - let pat = Pat { ty: init.ty, span: else_block_span, kind: Box::new(PatKind::Wild) }; + let pat = Pat { ty: init.ty, span: else_block_span, kind: PatKind::Wild }; let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false); this.declare_bindings( visibility_scope, diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index c6298904140c..b9954be377b3 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -67,7 +67,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { loop { let match_pairs = mem::take(&mut candidate.match_pairs); - if let [MatchPair { pattern: Pat { kind: box PatKind::Or { pats }, .. }, place }] = + if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place }] = &*match_pairs { existing_bindings.extend_from_slice(&new_bindings); @@ -113,7 +113,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // late as possible. candidate .match_pairs - .sort_by_key(|pair| matches!(*pair.pattern.kind, PatKind::Or { .. })); + .sort_by_key(|pair| matches!(pair.pattern.kind, PatKind::Or { .. })); debug!(simplified = ?candidate, "simplify_candidate"); return false; // if we were not able to simplify any, done. } @@ -127,10 +127,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, candidate: &Candidate<'pat, 'tcx>, place: PlaceBuilder<'tcx>, - pats: &'pat [Pat<'tcx>], + pats: &'pat [Box>], ) -> Vec> { pats.iter() - .map(|pat| { + .map(|box pat| { let mut candidate = Candidate::new(place.clone(), pat, candidate.has_guard); self.simplify_candidate(&mut candidate); candidate @@ -149,7 +149,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidate: &mut Candidate<'pat, 'tcx>, ) -> Result<(), MatchPair<'pat, 'tcx>> { let tcx = self.tcx; - match *match_pair.pattern.kind { + match match_pair.pattern.kind { PatKind::AscribeUserType { ref subpattern, ascription: thir::Ascription { ref annotation, variance }, @@ -254,7 +254,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut candidate.match_pairs, &match_pair.place, prefix, - slice.as_ref(), + slice, suffix, ); Ok(()) @@ -294,7 +294,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut candidate.match_pairs, &match_pair.place, prefix, - slice.as_ref(), + slice, suffix, ); Ok(()) diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 598da80c574a..ce85f240603a 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -29,7 +29,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// /// It is a bug to call this with a not-fully-simplified pattern. pub(super) fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> { - match *match_pair.pattern.kind { + match match_pair.pattern.kind { PatKind::Variant { adt_def, substs: _, variant_index: _, subpatterns: _ } => Test { span: match_pair.pattern.span, kind: TestKind::Switch { @@ -92,7 +92,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { return false; }; - match *match_pair.pattern.kind { + match match_pair.pattern.kind { PatKind::Constant { value } => { options .entry(value) @@ -130,7 +130,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { return false; }; - match *match_pair.pattern.kind { + match match_pair.pattern.kind { PatKind::Variant { adt_def: _, variant_index, .. } => { // We have a pattern testing for variant `variant_index` // set the corresponding index to true @@ -506,7 +506,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let (match_pair_index, match_pair) = candidate.match_pairs.iter().enumerate().find(|&(_, mp)| mp.place == *test_place)?; - match (&test.kind, &*match_pair.pattern.kind) { + match (&test.kind, &match_pair.pattern.kind) { // If we are performing a variant switch, then this // informs variant patterns, but nothing else. ( @@ -569,7 +569,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match_pair_index, candidate, prefix, - slice.as_ref(), + slice, suffix, ); Some(0) @@ -607,7 +607,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match_pair_index, candidate, prefix, - slice.as_ref(), + slice, suffix, ); Some(0) @@ -678,7 +678,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // However, at this point we can still encounter or-patterns that were extracted // from previous calls to `sort_candidate`, so we need to manually address that // case to avoid panicking in `self.test()`. - if let PatKind::Or { .. } = &*match_pair.pattern.kind { + if let PatKind::Or { .. } = &match_pair.pattern.kind { return None; } @@ -708,9 +708,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, match_pair_index: usize, candidate: &mut Candidate<'pat, 'tcx>, - prefix: &'pat [Pat<'tcx>], - opt_slice: Option<&'pat Pat<'tcx>>, - suffix: &'pat [Pat<'tcx>], + prefix: &'pat [Box>], + opt_slice: &'pat Option>>, + suffix: &'pat [Box>], ) { let removed_place = candidate.match_pairs.remove(match_pair_index).place; self.prefix_slice_suffix( diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 9a1e98d3bb18..06f24040f7be 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -26,9 +26,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, match_pairs: &mut SmallVec<[MatchPair<'pat, 'tcx>; 1]>, place: &PlaceBuilder<'tcx>, - prefix: &'pat [Pat<'tcx>], - opt_slice: Option<&'pat Pat<'tcx>>, - suffix: &'pat [Pat<'tcx>], + prefix: &'pat [Box>], + opt_slice: &'pat Option>>, + suffix: &'pat [Box>], ) { let tcx = self.tcx; let (min_length, exact_size) = if let Ok(place_resolved) = diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 684b228e87fa..17767f4218c0 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -1015,7 +1015,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let original_source_scope = self.source_scope; let span = pattern.span; self.set_correct_source_scope_for_arg(arg.hir_id, original_source_scope, span); - match *pattern.kind { + match pattern.kind { // Don't introduce extra copies for simple bindings PatKind::Binding { mutability, @@ -1052,7 +1052,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Some((Some(&place), span)), ); let place_builder = PlaceBuilder::from(local); - unpack!(block = self.place_into_pattern(block, pattern, place_builder, false)); + unpack!(block = self.place_into_pattern(block, *pattern, place_builder, false)); } } self.source_scope = original_source_scope; diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index bf5a2e7c73fa..495738ebe1c7 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -214,7 +214,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { fn visit_pat(&mut self, pat: &Pat<'tcx>) { if self.in_union_destructure { - match *pat.kind { + match pat.kind { // binding to a variable allows getting stuff out of variable PatKind::Binding { .. } // match is conditional on having this value @@ -236,7 +236,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { } }; - match &*pat.kind { + match &pat.kind { PatKind::Leaf { .. } => { if let ty::Adt(adt_def, ..) = pat.ty.kind() { if adt_def.is_union() { diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs index 54c4b9eda70d..c4e238c7821e 100644 --- a/compiler/rustc_mir_build/src/thir/cx/block.rs +++ b/compiler/rustc_mir_build/src/thir/cx/block.rs @@ -91,17 +91,17 @@ impl<'tcx> Cx<'tcx> { span: ty.span, inferred_ty: self.typeck_results.node_type(ty.hir_id), }; - pattern = Pat { + pattern = Box::new(Pat { ty: pattern.ty, span: pattern.span, - kind: Box::new(PatKind::AscribeUserType { + kind: PatKind::AscribeUserType { ascription: Ascription { annotation, variance: ty::Variance::Covariant, }, subpattern: pattern, - }), - }; + }, + }); } } diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index b84a84976c7d..ae53df1f9b9a 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -78,7 +78,7 @@ impl<'tcx> Cx<'tcx> { } #[instrument(level = "debug", skip(self))] - pub(crate) fn pattern_from_hir(&mut self, p: &hir::Pat<'_>) -> Pat<'tcx> { + pub(crate) fn pattern_from_hir(&mut self, p: &hir::Pat<'_>) -> Box> { let p = match self.tcx.hir().get(p.hir_id) { Node::Pat(p) => p, node => bug!("pattern became {:?}", node), diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 210d77c66e70..5af5ce407c6b 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -26,7 +26,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { id: hir::HirId, span: Span, mir_structural_match_violation: bool, - ) -> Pat<'tcx> { + ) -> Box> { self.tcx.infer_ctxt().enter(|infcx| { let mut convert = ConstToPat::new(self, id, span, infcx); convert.to_pat(cv, mir_structural_match_violation) @@ -156,7 +156,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { &mut self, cv: mir::ConstantKind<'tcx>, mir_structural_match_violation: bool, - ) -> Pat<'tcx> { + ) -> Box> { trace!(self.treat_byte_string_as_slice); // This method is just a wrapper handling a validity check; the heavy lifting is // performed by the recursive `recur` method, which is not meant to be @@ -166,10 +166,12 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // level of indirection can be eliminated let inlined_const_as_pat = - self.recur(cv, mir_structural_match_violation).unwrap_or_else(|_| Pat { - span: self.span, - ty: cv.ty(), - kind: Box::new(PatKind::Constant { value: cv }), + self.recur(cv, mir_structural_match_violation).unwrap_or_else(|_| { + Box::new(Pat { + span: self.span, + ty: cv.ty(), + kind: PatKind::Constant { value: cv }, + }) }); if self.include_lint_checks && !self.saw_const_match_error.get() { @@ -271,7 +273,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { &self, cv: mir::ConstantKind<'tcx>, mir_structural_match_violation: bool, - ) -> Result, FallbackToConstRef> { + ) -> Result>, FallbackToConstRef> { let id = self.id; let span = self.span; let tcx = self.tcx(); @@ -425,8 +427,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { let old = self.behind_reference.replace(true); let array = tcx.deref_mir_constant(self.param_env.and(cv)); let val = PatKind::Deref { - subpattern: Pat { - kind: Box::new(PatKind::Array { + subpattern: Box::new(Pat { + kind: PatKind::Array { prefix: tcx .destructure_mir_constant(param_env, array) .fields @@ -435,10 +437,10 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { .collect::>()?, slice: None, suffix: vec![], - }), + }, span, ty: *pointee_ty, - }, + }), }; self.behind_reference.set(old); val @@ -451,8 +453,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { let old = self.behind_reference.replace(true); let array = tcx.deref_mir_constant(self.param_env.and(cv)); let val = PatKind::Deref { - subpattern: Pat { - kind: Box::new(PatKind::Slice { + subpattern: Box::new(Pat { + kind: PatKind::Slice { prefix: tcx .destructure_mir_constant(param_env, array) .fields @@ -461,10 +463,10 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { .collect::>()?, slice: None, suffix: vec![], - }), + }, span, ty: tcx.mk_slice(elem_ty), - }, + }), }; self.behind_reference.set(old); val @@ -598,6 +600,6 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { ); } - Ok(Pat { span, ty: cv.ty(), kind: Box::new(kind) }) + Ok(Box::new(Pat { span, ty: cv.ty(), kind })) } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 8d6f8efb6003..fdd74d5221dd 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -71,9 +71,9 @@ use std::ops::RangeInclusive; /// Recursively expand this pattern into its subpatterns. Only useful for or-patterns. fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> { fn expand<'p, 'tcx>(pat: &'p Pat<'tcx>, vec: &mut Vec<&'p Pat<'tcx>>) { - if let PatKind::Or { pats } = pat.kind.as_ref() { + if let PatKind::Or { pats } = &pat.kind { for pat in pats { - expand(pat, vec); + expand(&pat, vec); } } else { vec.push(pat) @@ -255,7 +255,7 @@ impl IntRange { PatKind::Range(PatRange { lo: lo_const, hi: hi_const, end: RangeEnd::Included }) }; - Pat { ty, span: DUMMY_SP, kind: Box::new(kind) } + Pat { ty, span: DUMMY_SP, kind } } /// Lint on likely incorrect range patterns (#63987) @@ -1297,7 +1297,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { let mkpat = |pat| DeconstructedPat::from_pat(cx, pat); let ctor; let fields; - match pat.kind.as_ref() { + match &pat.kind { PatKind::AscribeUserType { subpattern, .. } => return mkpat(subpattern), PatKind::Binding { subpattern: Some(subpat), .. } => return mkpat(subpat), PatKind::Binding { subpattern: None, .. } | PatKind::Wild => { @@ -1342,9 +1342,9 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { fields = Fields::singleton(cx, pat); } ty::Adt(adt, _) => { - ctor = match pat.kind.as_ref() { + ctor = match pat.kind { PatKind::Leaf { .. } => Single, - PatKind::Variant { variant_index, .. } => Variant(*variant_index), + PatKind::Variant { variant_index, .. } => Variant(variant_index), _ => bug!(), }; let variant = &adt.variant(ctor.variant_index_for_adt(*adt)); @@ -1429,7 +1429,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { FixedLen(prefix.len() + suffix.len()) }; ctor = Slice(Slice::new(array_len, kind)); - fields = Fields::from_iter(cx, prefix.iter().chain(suffix).map(mkpat)); + fields = Fields::from_iter(cx, prefix.iter().chain(suffix).map(|p| mkpat(&*p))); } PatKind::Or { .. } => { ctor = Or; @@ -1442,15 +1442,15 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { pub(crate) fn to_pat(&self, cx: &MatchCheckCtxt<'p, 'tcx>) -> Pat<'tcx> { let is_wildcard = |pat: &Pat<'_>| { - matches!(*pat.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild) + matches!(pat.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild) }; - let mut subpatterns = self.iter_fields().map(|p| p.to_pat(cx)); - let pat = match &self.ctor { + let mut subpatterns = self.iter_fields().map(|p| Box::new(p.to_pat(cx))); + let kind = match &self.ctor { Single | Variant(_) => match self.ty.kind() { ty::Tuple(..) => PatKind::Leaf { subpatterns: subpatterns .enumerate() - .map(|(i, p)| FieldPat { field: Field::new(i), pattern: p }) + .map(|(i, pattern)| FieldPat { field: Field::new(i), pattern }) .collect(), }, ty::Adt(adt_def, _) if adt_def.is_box() => { @@ -1506,7 +1506,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { } let suffix: Vec<_> = subpatterns.collect(); let wild = Pat::wildcard_from_ty(self.ty); - PatKind::Slice { prefix, slice: Some(wild), suffix } + PatKind::Slice { prefix, slice: Some(Box::new(wild)), suffix } } } } @@ -1523,7 +1523,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { } }; - Pat { ty: self.ty, span: DUMMY_SP, kind: Box::new(pat) } + Pat { ty: self.ty, span: DUMMY_SP, kind } } pub(super) fn is_or_pat(&self) -> bool { diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index a13748a2d474..c10fc607d107 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -49,7 +49,7 @@ pub(crate) fn pat_from_hir<'a, 'tcx>( param_env: ty::ParamEnv<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>, pat: &'tcx hir::Pat<'tcx>, -) -> Pat<'tcx> { +) -> Box> { let mut pcx = PatCtxt::new(tcx, param_env, typeck_results); let result = pcx.lower_pattern(pat); if !pcx.errors.is_empty() { @@ -74,7 +74,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { self } - pub(crate) fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> { + pub(crate) fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box> { // When implicit dereferences have been inserted in this pattern, the unadjusted lowered // pattern has the type that results *after* dereferencing. For example, in this code: // @@ -97,13 +97,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let unadjusted_pat = self.lower_pattern_unadjusted(pat); self.typeck_results.pat_adjustments().get(pat.hir_id).unwrap_or(&vec![]).iter().rev().fold( unadjusted_pat, - |pat, ref_ty| { + |pat: Box<_>, ref_ty| { debug!("{:?}: wrapping pattern with type {:?}", pat, ref_ty); - Pat { + Box::new(Pat { span: pat.span, ty: *ref_ty, - kind: Box::new(PatKind::Deref { subpattern: pat }), - } + kind: PatKind::Deref { subpattern: pat }, + }) }, ) } @@ -113,7 +113,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { expr: &'tcx hir::Expr<'tcx>, ) -> (PatKind<'tcx>, Option>) { match self.lower_lit(expr) { - PatKind::AscribeUserType { ascription, subpattern: Pat { kind: box kind, .. } } => { + PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => { (kind, Some(ascription)) } kind => (kind, None), @@ -196,7 +196,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } } - fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> { + fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box> { let mut ty = self.typeck_results.node_type(pat.hir_id); let kind = match pat.kind { @@ -228,7 +228,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // constants somewhere. Have them on the range pattern. for end in &[lo, hi] { if let Some((_, Some(ascription))) = end { - let subpattern = Pat { span: pat.span, ty, kind: Box::new(kind) }; + let subpattern = Box::new(Pat { span: pat.span, ty, kind }); kind = PatKind::AscribeUserType { ascription: ascription.clone(), subpattern }; } @@ -322,7 +322,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { hir::PatKind::Or(ref pats) => PatKind::Or { pats: self.lower_patterns(pats) }, }; - Pat { span: pat.span, ty, kind: Box::new(kind) } + Box::new(Pat { span: pat.span, ty, kind }) } fn lower_tuple_subpats( @@ -340,11 +340,14 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { .collect() } - fn lower_patterns(&mut self, pats: &'tcx [hir::Pat<'tcx>]) -> Vec> { + fn lower_patterns(&mut self, pats: &'tcx [hir::Pat<'tcx>]) -> Vec>> { pats.iter().map(|p| self.lower_pattern(p)).collect() } - fn lower_opt_pattern(&mut self, pat: &'tcx Option<&'tcx hir::Pat<'tcx>>) -> Option> { + fn lower_opt_pattern( + &mut self, + pat: &'tcx Option<&'tcx hir::Pat<'tcx>>, + ) -> Option>> { pat.as_ref().map(|p| self.lower_pattern(p)) } @@ -441,7 +444,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { inferred_ty: self.typeck_results.node_type(hir_id), }; kind = PatKind::AscribeUserType { - subpattern: Pat { span, ty, kind: Box::new(kind) }, + subpattern: Box::new(Pat { span, ty, kind }), ascription: Ascription { annotation, variance: ty::Variance::Covariant }, }; } @@ -453,11 +456,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { /// it to `const_to_pat`. Any other path (like enum variants without fields) /// is converted to the corresponding pattern via `lower_variant_or_leaf`. #[instrument(skip(self), level = "debug")] - fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) -> Pat<'tcx> { + fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) -> Box> { let ty = self.typeck_results.node_type(id); let res = self.typeck_results.qpath_res(qpath, id); - let pat_from_kind = |kind| Pat { span, ty, kind: Box::new(kind) }; + let pat_from_kind = |kind| Box::new(Pat { span, ty, kind }); let (def_id, is_associated_const) = match res { Res::Def(DefKind::Const, def_id) => (def_id, false), @@ -509,9 +512,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { span, inferred_ty: self.typeck_results().node_type(id), }; - Pat { + Box::new(Pat { span, - kind: Box::new(PatKind::AscribeUserType { + kind: PatKind::AscribeUserType { subpattern: pattern, ascription: Ascription { annotation, @@ -519,9 +522,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { /// `variance` field documentation for details. variance: ty::Variance::Contravariant, }, - }), + }, ty: const_.ty(), - } + }) } else { pattern } @@ -569,7 +572,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { _ => bug!("Expected either ConstKind::Param or ConstKind::Unevaluated"), } } - mir::ConstantKind::Val(_, _) => *self.const_to_pat(value, id, span, false).kind, + mir::ConstantKind::Val(_, _) => self.const_to_pat(value, id, span, false).kind, } } @@ -580,7 +583,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { fn lower_lit(&mut self, expr: &'tcx hir::Expr<'tcx>) -> PatKind<'tcx> { let (lit, neg) = match expr.kind { hir::ExprKind::Path(ref qpath) => { - return *self.lower_path(qpath, expr.hir_id, expr.span).kind; + return self.lower_path(qpath, expr.hir_id, expr.span).kind; } hir::ExprKind::ConstBlock(ref anon_const) => { return self.lower_inline_const(anon_const, expr.hir_id, expr.span); @@ -598,7 +601,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let lit_input = LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg }; match self.tcx.at(expr.span).lit_to_mir_constant(lit_input) { - Ok(constant) => *self.const_to_pat(constant, expr.hir_id, lit.span, false).kind, + Ok(constant) => self.const_to_pat(constant, expr.hir_id, lit.span, false).kind, Err(LitToConstError::Reported) => PatKind::Wild, Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"), } diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 16c4d429129a..6cbccb4bf291 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -155,7 +155,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { return true; } - match pat.kind.as_ref() { + match pat.kind { thir::PatKind::Constant { value } => value.has_param_types_or_consts(), thir::PatKind::Range(thir::PatRange { lo, hi, .. }) => { lo.has_param_types_or_consts() || hi.has_param_types_or_consts() From bd1e6836a07fa7b96b41effc3ec90e60aaa494df Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 25 Aug 2022 14:05:01 +1000 Subject: [PATCH 4061/5092] Avoid some clones. `Builder::expr_into_pattern` has a single call site. Currently the `pattern` argument at the call site is always cloned. This commit changes things so that we instead do a clone within `expr_into_pattern`, but only if the pattern has the `PatKind::AscribeUserType` kind, and we only clone the annotation within the pattern instead of the entire pattern. --- compiler/rustc_mir_build/src/build/block.rs | 2 +- compiler/rustc_mir_build/src/build/matches/mod.rs | 8 ++++---- compiler/rustc_mir_build/src/build/mod.rs | 5 ++++- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index ef976d6308b5..c8d4a1bf2c9e 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -160,7 +160,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ArmHasGuard(false), Some((None, initializer_span)), ); - this.expr_into_pattern(block, (**pattern).clone(), init) // irrefutable pattern + this.expr_into_pattern(block, pattern, init) // irrefutable pattern } }) }, diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 72f8034bbc17..b4440f2dda80 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -490,7 +490,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(super) fn expr_into_pattern( &mut self, mut block: BasicBlock, - irrefutable_pat: Pat<'tcx>, + irrefutable_pat: &Pat<'tcx>, initializer: &Expr<'tcx>, ) -> BlockAnd<()> { match irrefutable_pat.kind { @@ -525,7 +525,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }, .. }, - ascription: thir::Ascription { annotation, variance: _ }, + ascription: thir::Ascription { ref annotation, variance: _ }, } => { let place = self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true); @@ -538,7 +538,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let ty_source_info = self.source_info(annotation.span); - let base = self.canonical_user_type_annotations.push(annotation); + let base = self.canonical_user_type_annotations.push(annotation.clone()); self.cfg.push( block, Statement { @@ -578,7 +578,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pub(crate) fn place_into_pattern( &mut self, block: BasicBlock, - irrefutable_pat: Pat<'tcx>, + irrefutable_pat: &Pat<'tcx>, initializer: PlaceBuilder<'tcx>, set_match_place: bool, ) -> BlockAnd<()> { diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 17767f4218c0..763038c52d7f 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -1052,7 +1052,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Some((Some(&place), span)), ); let place_builder = PlaceBuilder::from(local); - unpack!(block = self.place_into_pattern(block, *pattern, place_builder, false)); + unpack!( + block = + self.place_into_pattern(block, pattern.as_ref(), place_builder, false) + ); } } self.source_scope = original_source_scope; From 2c4c8eb1a3add142c2380aecdd46ec32e42a9900 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 26 Aug 2022 11:36:24 +1000 Subject: [PATCH 4062/5092] Box `PatKind::Range`. Because it's the biggest variant. Also, make `PatRange` non-`Copy`, because it's 104 bytes, which is pretty big. --- compiler/rustc_middle/src/thir.rs | 10 ++++---- .../rustc_mir_build/src/build/matches/mod.rs | 2 +- .../src/build/matches/simplify.rs | 2 +- .../rustc_mir_build/src/build/matches/test.rs | 24 +++++++++---------- .../src/thir/pattern/deconstruct_pat.rs | 10 +++++--- .../rustc_mir_build/src/thir/pattern/mod.rs | 10 +++++--- compiler/rustc_ty_utils/src/consts.rs | 2 +- 7 files changed, 34 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 99d72f70ba68..7eaf9c0099cd 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -628,7 +628,7 @@ pub enum PatKind<'tcx> { value: mir::ConstantKind<'tcx>, }, - Range(PatRange<'tcx>), + Range(Box>), /// Matches against a slice, checking the length and extracting elements. /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty. @@ -653,7 +653,7 @@ pub enum PatKind<'tcx> { }, } -#[derive(Copy, Clone, Debug, PartialEq, HashStable)] +#[derive(Clone, Debug, PartialEq, HashStable)] pub struct PatRange<'tcx> { pub lo: mir::ConstantKind<'tcx>, pub hi: mir::ConstantKind<'tcx>, @@ -767,7 +767,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> { write!(f, "{}", subpattern) } PatKind::Constant { value } => write!(f, "{}", value), - PatKind::Range(PatRange { lo, hi, end }) => { + PatKind::Range(box PatRange { lo, hi, end }) => { write!(f, "{}", lo)?; write!(f, "{}", end)?; write!(f, "{}", hi) @@ -809,8 +809,8 @@ mod size_asserts { static_assert_size!(Block, 56); static_assert_size!(Expr<'_>, 64); static_assert_size!(ExprKind<'_>, 40); - static_assert_size!(Pat<'_>, 128); - static_assert_size!(PatKind<'_>, 112); + static_assert_size!(Pat<'_>, 112); + static_assert_size!(PatKind<'_>, 96); static_assert_size!(Stmt<'_>, 56); static_assert_size!(StmtKind<'_>, 48); } diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index b4440f2dda80..bf56c26074cd 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -979,7 +979,7 @@ enum TestKind<'tcx> { }, /// Test whether the value falls within an inclusive or exclusive range - Range(PatRange<'tcx>), + Range(Box>), /// Test that the length of the slice is equal to `len`. Len { len: u64, op: BinOp }, diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index b9954be377b3..55ed09da64fb 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -208,7 +208,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Err(match_pair) } - PatKind::Range(PatRange { lo, hi, end }) => { + PatKind::Range(box PatRange { lo, hi, end }) => { let (range, bias) = match *lo.ty().kind() { ty::Char => { (Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32))), 0) diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index ce85f240603a..19c303e0bab7 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -58,10 +58,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { kind: TestKind::Eq { value, ty: match_pair.pattern.ty }, }, - PatKind::Range(range) => { + PatKind::Range(ref range) => { assert_eq!(range.lo.ty(), match_pair.pattern.ty); assert_eq!(range.hi.ty(), match_pair.pattern.ty); - Test { span: match_pair.pattern.span, kind: TestKind::Range(range) } + Test { span: match_pair.pattern.span, kind: TestKind::Range(range.clone()) } } PatKind::Slice { ref prefix, ref slice, ref suffix } => { @@ -102,9 +102,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { PatKind::Variant { .. } => { panic!("you should have called add_variants_to_switch instead!"); } - PatKind::Range(range) => { + PatKind::Range(ref range) => { // Check that none of the switch values are in the range. - self.values_not_contained_in_range(range, options).unwrap_or(false) + self.values_not_contained_in_range(&*range, options).unwrap_or(false) } PatKind::Slice { .. } | PatKind::Array { .. } @@ -272,7 +272,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - TestKind::Range(PatRange { lo, hi, ref end }) => { + TestKind::Range(box PatRange { lo, hi, ref end }) => { let lower_bound_success = self.cfg.start_new_block(); let target_blocks = make_target_blocks(self); @@ -540,9 +540,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Some(index) } - (&TestKind::SwitchInt { switch_ty: _, ref options }, &PatKind::Range(range)) => { + (&TestKind::SwitchInt { switch_ty: _, ref options }, &PatKind::Range(ref range)) => { let not_contained = - self.values_not_contained_in_range(range, options).unwrap_or(false); + self.values_not_contained_in_range(&*range, options).unwrap_or(false); if not_contained { // No switch values are contained in the pattern range, @@ -631,7 +631,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - (&TestKind::Range(test), &PatKind::Range(pat)) => { + (&TestKind::Range(ref test), &PatKind::Range(ref pat)) => { use std::cmp::Ordering::*; if test == pat { @@ -658,8 +658,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { no_overlap } - (&TestKind::Range(range), &PatKind::Constant { value }) => { - if let Some(false) = self.const_range_contains(range, value) { + (&TestKind::Range(ref range), &PatKind::Constant { value }) => { + if let Some(false) = self.const_range_contains(&*range, value) { // `value` is not contained in the testing range, // so `value` can be matched only if this test fails. Some(1) @@ -754,7 +754,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn const_range_contains( &self, - range: PatRange<'tcx>, + range: &PatRange<'tcx>, value: ConstantKind<'tcx>, ) -> Option { use std::cmp::Ordering::*; @@ -772,7 +772,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn values_not_contained_in_range( &self, - range: PatRange<'tcx>, + range: &PatRange<'tcx>, options: &FxIndexMap, u128>, ) -> Option { for &val in options.keys() { diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index fdd74d5221dd..7f975d217bd3 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -252,7 +252,11 @@ impl IntRange { let kind = if lo == hi { PatKind::Constant { value: lo_const } } else { - PatKind::Range(PatRange { lo: lo_const, hi: hi_const, end: RangeEnd::Included }) + PatKind::Range(Box::new(PatRange { + lo: lo_const, + hi: hi_const, + end: RangeEnd::Included, + })) }; Pat { ty, span: DUMMY_SP, kind } @@ -1402,7 +1406,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { } } } - &PatKind::Range(PatRange { lo, hi, end }) => { + &PatKind::Range(box PatRange { lo, hi, end }) => { let ty = lo.ty(); ctor = if let Some(int_range) = IntRange::from_range( cx.tcx, @@ -1511,7 +1515,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { } } &Str(value) => PatKind::Constant { value }, - &FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }), + &FloatRange(lo, hi, end) => PatKind::Range(Box::new(PatRange { lo, hi, end })), IntRange(range) => return range.to_pat(cx.tcx, self.ty), Wildcard | NonExhaustive => PatKind::Wild, Missing { .. } => bug!( diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index c10fc607d107..b02b6b6f5ca6 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -134,7 +134,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { match (end, cmp) { // `x..y` where `x < y`. // Non-empty because the range includes at least `x`. - (RangeEnd::Excluded, Some(Ordering::Less)) => PatKind::Range(PatRange { lo, hi, end }), + (RangeEnd::Excluded, Some(Ordering::Less)) => { + PatKind::Range(Box::new(PatRange { lo, hi, end })) + } // `x..y` where `x >= y`. The range is empty => error. (RangeEnd::Excluded, _) => { struct_span_err!( @@ -149,7 +151,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // `x..=y` where `x == y`. (RangeEnd::Included, Some(Ordering::Equal)) => PatKind::Constant { value: lo }, // `x..=y` where `x < y`. - (RangeEnd::Included, Some(Ordering::Less)) => PatKind::Range(PatRange { lo, hi, end }), + (RangeEnd::Included, Some(Ordering::Less)) => { + PatKind::Range(Box::new(PatRange { lo, hi, end })) + } // `x..=y` where `x > y` hence the range is empty => error. (RangeEnd::Included, _) => { let mut err = struct_span_err!( @@ -735,7 +739,7 @@ impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> { PatKind::Deref { subpattern: subpattern.fold_with(folder) } } PatKind::Constant { value } => PatKind::Constant { value }, - PatKind::Range(range) => PatKind::Range(range), + PatKind::Range(ref range) => PatKind::Range(range.clone()), PatKind::Slice { ref prefix, ref slice, ref suffix } => PatKind::Slice { prefix: prefix.fold_with(folder), slice: slice.fold_with(folder), diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 6cbccb4bf291..bb6b3e1ff5d7 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -157,7 +157,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { match pat.kind { thir::PatKind::Constant { value } => value.has_param_types_or_consts(), - thir::PatKind::Range(thir::PatRange { lo, hi, .. }) => { + thir::PatKind::Range(box thir::PatRange { lo, hi, .. }) => { lo.has_param_types_or_consts() || hi.has_param_types_or_consts() } _ => false, From a40124e01c4b10629c78b417a1fe524d929bcbe9 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 26 Aug 2022 11:53:54 +1000 Subject: [PATCH 4063/5092] Box `CanonicalUserTypeAnnotation::CanonicalUserType`. This shrinks `Ascription`, which shrinks `PatKind::AscribeUserType`, which shrinks `Pat`. --- compiler/rustc_middle/src/thir.rs | 4 ++-- compiler/rustc_middle/src/ty/context.rs | 2 +- .../rustc_mir_build/src/build/expr/as_constant.rs | 12 ++++++------ compiler/rustc_mir_build/src/build/expr/as_place.rs | 8 ++++---- compiler/rustc_mir_build/src/build/expr/into.rs | 4 ++-- compiler/rustc_mir_build/src/thir/cx/block.rs | 2 +- compiler/rustc_mir_build/src/thir/pattern/mod.rs | 4 ++-- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 7eaf9c0099cd..120fa787009d 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -809,8 +809,8 @@ mod size_asserts { static_assert_size!(Block, 56); static_assert_size!(Expr<'_>, 64); static_assert_size!(ExprKind<'_>, 40); - static_assert_size!(Pat<'_>, 112); - static_assert_size!(PatKind<'_>, 96); + static_assert_size!(Pat<'_>, 80); + static_assert_size!(PatKind<'_>, 64); static_assert_size!(Stmt<'_>, 56); static_assert_size!(StmtKind<'_>, 48); } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 052bb1263c98..cd3201e77ce9 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -874,7 +874,7 @@ pub type CanonicalUserTypeAnnotations<'tcx> = #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct CanonicalUserTypeAnnotation<'tcx> { - pub user_ty: CanonicalUserType<'tcx>, + pub user_ty: Box>, pub span: Span, pub inferred_ty: Ty<'tcx>, } diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index b316a6eeac1c..3549b47478cb 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -42,10 +42,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Constant { span, user_ty: None, literal } } ExprKind::NonHirLiteral { lit, ref user_ty } => { - let user_ty = user_ty.as_ref().map(|box user_ty| { + let user_ty = user_ty.as_ref().map(|user_ty| { this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { span, - user_ty: *user_ty, + user_ty: user_ty.clone(), inferred_ty: ty, }) }); @@ -54,10 +54,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Constant { span, user_ty: user_ty, literal } } ExprKind::ZstLiteral { ref user_ty } => { - let user_ty = user_ty.as_ref().map(|box user_ty| { + let user_ty = user_ty.as_ref().map(|user_ty| { this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { span, - user_ty: *user_ty, + user_ty: user_ty.clone(), inferred_ty: ty, }) }); @@ -66,10 +66,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Constant { span, user_ty: user_ty, literal } } ExprKind::NamedConst { def_id, substs, ref user_ty } => { - let user_ty = user_ty.as_ref().map(|box user_ty| { + let user_ty = user_ty.as_ref().map(|user_ty| { this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { span, - user_ty: *user_ty, + user_ty: user_ty.clone(), inferred_ty: ty, }) }); diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index b8277f28cdc4..46dbd8a136b5 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -522,11 +522,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fake_borrow_temps, ) ); - if let Some(box user_ty) = user_ty { + if let Some(user_ty) = user_ty { let annotation_index = this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { span: source_info.span, - user_ty: *user_ty, + user_ty: user_ty.clone(), inferred_ty: expr.ty, }); @@ -551,11 +551,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let source = &this.thir[source]; let temp = unpack!(block = this.as_temp(block, source.temp_lifetime, source, mutability)); - if let Some(box user_ty) = user_ty { + if let Some(user_ty) = user_ty { let annotation_index = this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { span: source_info.span, - user_ty: *user_ty, + user_ty: user_ty.clone(), inferred_ty: expr.ty, }); this.cfg.push( diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 48ec7a06724a..74509646c17c 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -378,10 +378,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; let inferred_ty = expr.ty; - let user_ty = user_ty.as_ref().map(|box user_ty| { + let user_ty = user_ty.as_ref().map(|user_ty| { this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { span: source_info.span, - user_ty: *user_ty, + user_ty: user_ty.clone(), inferred_ty, }) }); diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs index c4e238c7821e..321353ca20ba 100644 --- a/compiler/rustc_mir_build/src/thir/cx/block.rs +++ b/compiler/rustc_mir_build/src/thir/cx/block.rs @@ -87,7 +87,7 @@ impl<'tcx> Cx<'tcx> { { debug!("mirror_stmts: user_ty={:?}", user_ty); let annotation = CanonicalUserTypeAnnotation { - user_ty, + user_ty: Box::new(user_ty), span: ty.span, inferred_ty: self.typeck_results.node_type(ty.hir_id), }; diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index b02b6b6f5ca6..21a2cb32aa76 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -443,7 +443,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { if let Some(user_ty) = self.user_substs_applied_to_ty_of_hir_id(hir_id) { debug!("lower_variant_or_leaf: kind={:?} user_ty={:?} span={:?}", kind, user_ty, span); let annotation = CanonicalUserTypeAnnotation { - user_ty, + user_ty: Box::new(user_ty), span, inferred_ty: self.typeck_results.node_type(hir_id), }; @@ -512,7 +512,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let user_provided_types = self.typeck_results().user_provided_types(); if let Some(&user_ty) = user_provided_types.get(id) { let annotation = CanonicalUserTypeAnnotation { - user_ty, + user_ty: Box::new(user_ty), span, inferred_ty: self.typeck_results().node_type(id), }; From 43a0268f3a28fa53ad8290720002984cff785224 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 26 Aug 2022 12:06:13 +1000 Subject: [PATCH 4064/5092] Use boxed slices in `PatKind`. To shrink it a little more. --- compiler/rustc_middle/src/thir.rs | 20 +++++++++---------- compiler/rustc_middle/src/thir/visit.rs | 6 +++--- .../rustc_mir_build/src/build/matches/mod.rs | 6 +++--- .../src/thir/pattern/const_to_pat.rs | 6 +++--- .../src/thir/pattern/deconstruct_pat.rs | 15 +++++++++----- .../rustc_mir_build/src/thir/pattern/mod.rs | 8 +++++++- 6 files changed, 36 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 120fa787009d..59e14337f4ed 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -634,22 +634,22 @@ pub enum PatKind<'tcx> { /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty. /// e.g., `&[ref xs @ ..]`. Slice { - prefix: Vec>>, + prefix: Box<[Box>]>, slice: Option>>, - suffix: Vec>>, + suffix: Box<[Box>]>, }, /// Fixed match against an array; irrefutable. Array { - prefix: Vec>>, + prefix: Box<[Box>]>, slice: Option>>, - suffix: Vec>>, + suffix: Box<[Box>]>, }, /// An or-pattern, e.g. `p | q`. /// Invariant: `pats.len() >= 2`. Or { - pats: Vec>>, + pats: Box<[Box>]>, }, } @@ -775,7 +775,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> { PatKind::Slice { ref prefix, ref slice, ref suffix } | PatKind::Array { ref prefix, ref slice, ref suffix } => { write!(f, "[")?; - for p in prefix { + for p in prefix.iter() { write!(f, "{}{}", start_or_comma(), p)?; } if let Some(ref slice) = *slice { @@ -786,13 +786,13 @@ impl<'tcx> fmt::Display for Pat<'tcx> { } write!(f, "..")?; } - for p in suffix { + for p in suffix.iter() { write!(f, "{}{}", start_or_comma(), p)?; } write!(f, "]") } PatKind::Or { ref pats } => { - for pat in pats { + for pat in pats.iter() { write!(f, "{}{}", start_or_continue(" | "), pat)?; } Ok(()) @@ -809,8 +809,8 @@ mod size_asserts { static_assert_size!(Block, 56); static_assert_size!(Expr<'_>, 64); static_assert_size!(ExprKind<'_>, 40); - static_assert_size!(Pat<'_>, 80); - static_assert_size!(PatKind<'_>, 64); + static_assert_size!(Pat<'_>, 72); + static_assert_size!(PatKind<'_>, 56); static_assert_size!(Stmt<'_>, 56); static_assert_size!(StmtKind<'_>, 48); } diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 5168c2120f43..79a0e75aa7c7 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -232,18 +232,18 @@ pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<' Constant { value: _ } => {} Range(_) => {} Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => { - for subpattern in prefix { + for subpattern in prefix.iter() { visitor.visit_pat(&subpattern); } if let Some(pat) = slice { visitor.visit_pat(&pat); } - for subpattern in suffix { + for subpattern in suffix.iter() { visitor.visit_pat(&subpattern); } } Or { pats } => { - for pat in pats { + for pat in pats.iter() { visitor.visit_pat(&pat); } } diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index bf56c26074cd..a316c2e7d6e1 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -764,7 +764,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | PatKind::Slice { ref prefix, ref slice, ref suffix } => { let from = u64::try_from(prefix.len()).unwrap(); let to = u64::try_from(suffix.len()).unwrap(); - for subpattern in prefix { + for subpattern in prefix.iter() { self.visit_primary_bindings(subpattern, pattern_user_ty.clone().index(), f); } for subpattern in slice { @@ -774,7 +774,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { f, ); } - for subpattern in suffix { + for subpattern in suffix.iter() { self.visit_primary_bindings(subpattern, pattern_user_ty.clone().index(), f); } } @@ -827,7 +827,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // may not all be in the leftmost subpattern. For example in // `let (x | y) = ...`, the primary binding of `y` occurs in // the right subpattern - for subpattern in pats { + for subpattern in pats.iter() { self.visit_primary_bindings(subpattern, pattern_user_ty.clone(), f); } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 5af5ce407c6b..b58685e89580 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -400,7 +400,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { .map(|val| self.recur(*val, false)) .collect::>()?, slice: None, - suffix: Vec::new(), + suffix: Box::new([]), }, ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() { // These are not allowed and will error elsewhere anyway. @@ -436,7 +436,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { .map(|val| self.recur(*val, false)) .collect::>()?, slice: None, - suffix: vec![], + suffix: Box::new([]), }, span, ty: *pointee_ty, @@ -462,7 +462,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { .map(|val| self.recur(*val, false)) .collect::>()?, slice: None, - suffix: vec![], + suffix: Box::new([]), }, span, ty: tcx.mk_slice(elem_ty), diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 7f975d217bd3..5105f059f9b6 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -72,7 +72,7 @@ use std::ops::RangeInclusive; fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> { fn expand<'p, 'tcx>(pat: &'p Pat<'tcx>, vec: &mut Vec<&'p Pat<'tcx>>) { if let PatKind::Or { pats } = &pat.kind { - for pat in pats { + for pat in pats.iter() { expand(&pat, vec); } } else { @@ -1433,7 +1433,8 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { FixedLen(prefix.len() + suffix.len()) }; ctor = Slice(Slice::new(array_len, kind)); - fields = Fields::from_iter(cx, prefix.iter().chain(suffix).map(|p| mkpat(&*p))); + fields = + Fields::from_iter(cx, prefix.iter().chain(suffix.iter()).map(|p| mkpat(&*p))); } PatKind::Or { .. } => { ctor = Or; @@ -1489,7 +1490,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { FixedLen(_) => PatKind::Slice { prefix: subpatterns.collect(), slice: None, - suffix: vec![], + suffix: Box::new([]), }, VarLen(prefix, _) => { let mut subpatterns = subpatterns.peekable(); @@ -1508,9 +1509,13 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { subpatterns.next(); } } - let suffix: Vec<_> = subpatterns.collect(); + let suffix: Box<[_]> = subpatterns.collect(); let wild = Pat::wildcard_from_ty(self.ty); - PatKind::Slice { prefix, slice: Some(Box::new(wild)), suffix } + PatKind::Slice { + prefix: prefix.into_boxed_slice(), + slice: Some(Box::new(wild)), + suffix, + } } } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 21a2cb32aa76..d2f93b679acc 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -344,7 +344,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { .collect() } - fn lower_patterns(&mut self, pats: &'tcx [hir::Pat<'tcx>]) -> Vec>> { + fn lower_patterns(&mut self, pats: &'tcx [hir::Pat<'tcx>]) -> Box<[Box>]> { pats.iter().map(|p| self.lower_pattern(p)).collect() } @@ -653,6 +653,12 @@ impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Vec { } } +impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Box<[T]> { + fn super_fold_with>(&self, folder: &mut F) -> Self { + self.iter().map(|t| t.fold_with(folder)).collect() + } +} + impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Option { fn super_fold_with>(&self, folder: &mut F) -> Self { self.as_ref().map(|t| t.fold_with(folder)) From 096efc29f1be25daca6675f5f7684780ff294613 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 1 Sep 2022 13:06:24 -0700 Subject: [PATCH 4065/5092] rustdoc: remove unused CSS `#main-content > .since` This rule was added (actually, it was called `#main > .since` back then) with cdca0843779eed0b9046e9fee48c91458ad51605 and you can see an example of the bug it's intended to fix in by looking at the `1.0.0` version marker. However, a5a2f2b951ea982a666eaf52b1874d8f1b17290b changed it so that `` is always placed in an out-of-band wrapper, so it's never nested directly below `#main` / `#main-content` any more. --- src/librustdoc/html/static/css/rustdoc.css | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index deed6eaf0cb6..3198347ce7fa 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -216,7 +216,6 @@ details.rustdoc-toggle > summary::before, div.impl-items > div:not(.docblock):not(.item-info), .content ul.crate a.crate, a.srclink, -#main-content > .since, #help-button > button, details.rustdoc-toggle.top-doc > summary, details.rustdoc-toggle.top-doc > summary::before, From 1cf7bcc388b5aee7ef940d730d1ede212f8e5a31 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 23 Aug 2022 21:47:59 -0500 Subject: [PATCH 4066/5092] Get rid of `make_query` module --- compiler/rustc_query_impl/src/plumbing.rs | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index eabb31661474..b115381eb1c1 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -308,18 +308,6 @@ macro_rules! define_queries { input: ($(([$($modifiers)*] [$($attr)*] [$name]))*) } - mod make_query { - use super::*; - - // Create an eponymous constructor for each query. - $(#[allow(nonstandard_style)] $(#[$attr])* - pub fn $name<'tcx>(tcx: QueryCtxt<'tcx>, key: as QueryConfig>::Key) -> QueryStackFrame { - let kind = dep_graph::DepKind::$name; - let name = stringify!($name); - $crate::plumbing::create_query_frame(tcx, queries::$name::describe, key, kind, name) - })* - } - #[allow(nonstandard_style)] mod queries { use std::marker::PhantomData; @@ -531,9 +519,14 @@ macro_rules! define_queries_struct { let mut jobs = QueryMap::default(); $( + let make_query = |tcx, key| { + let kind = dep_graph::DepKind::$name; + let name = stringify!($name); + $crate::plumbing::create_query_frame(tcx, queries::$name::describe, key, kind, name) + }; self.$name.try_collect_active_jobs( tcx, - make_query::$name, + make_query, &mut jobs, )?; )* From 375d78012f2e7bdeba942eeb2a85115d1b1a98cb Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 23 Aug 2022 22:10:47 -0500 Subject: [PATCH 4067/5092] Move `try_on_disk_cache` out of the giant macro --- compiler/rustc_query_impl/src/plumbing.rs | 30 ++++++++++++++--------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index b115381eb1c1..e0707eee8ba6 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -7,7 +7,7 @@ use crate::{on_disk_cache, Queries}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lock; use rustc_errors::{Diagnostic, Handler}; -use rustc_middle::dep_graph::{self, DepKind, DepNodeIndex, SerializedDepNodeIndex}; +use rustc_middle::dep_graph::{self, DepKind, DepNode, DepNodeIndex, SerializedDepNodeIndex}; use rustc_middle::ty::tls::{self, ImplicitCtxt}; use rustc_middle::ty::{self, TyCtxt}; use rustc_query_system::dep_graph::HasDepContext; @@ -298,6 +298,23 @@ pub(crate) fn create_query_frame< QueryStackFrame::new(name, description, span, def_kind, hash) } +pub(crate) fn try_load_from_on_disk_cache<'tcx, K, V>( + tcx: TyCtxt<'tcx>, + dep_node: DepNode, + recover: fn(TyCtxt<'tcx>, DepNode) -> Option, + cache_on_disk: fn(TyCtxt<'tcx>, &K) -> bool, + do_query: fn(TyCtxt<'tcx>, K) -> V, +) { + debug_assert!(tcx.dep_graph.is_green(&dep_node)); + + let key = recover(tcx, dep_node).unwrap_or_else(|| { + panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash) + }); + if cache_on_disk(tcx, &key) { + let _ = do_query(tcx, key); + } +} + // NOTE: `$V` isn't used here, but we still need to match on it so it can be passed to other macros // invoked by `rustc_query_append`. macro_rules! define_queries { @@ -457,21 +474,12 @@ macro_rules! define_queries { } } - fn try_load_from_on_disk_cache(tcx: TyCtxt<'_>, dep_node: DepNode) { - debug_assert!(tcx.dep_graph.is_green(&dep_node)); - - let key = recover(tcx, dep_node).unwrap_or_else(|| panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash)); - if queries::$name::cache_on_disk(tcx, &key) { - let _ = tcx.$name(key); - } - } - DepKindStruct { is_anon, is_eval_always, fingerprint_style, force_from_dep_node: Some(force_from_dep_node), - try_load_from_on_disk_cache: Some(try_load_from_on_disk_cache), + try_load_from_on_disk_cache: Some(|tcx, key| $crate::plumbing::try_load_from_on_disk_cache(tcx, key, recover, queries::$name::cache_on_disk, TyCtxt::$name)), } })* } From 70f20ac40ea95f4bba330858750e81f4ab2b8b3a Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 23 Aug 2022 22:24:39 -0500 Subject: [PATCH 4068/5092] Move `force_with_dep_node` outside the giant macro --- compiler/rustc_query_impl/src/plumbing.rs | 42 ++++++++++++++--------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index e0707eee8ba6..7c6b898751a9 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -10,10 +10,11 @@ use rustc_errors::{Diagnostic, Handler}; use rustc_middle::dep_graph::{self, DepKind, DepNode, DepNodeIndex, SerializedDepNodeIndex}; use rustc_middle::ty::tls::{self, ImplicitCtxt}; use rustc_middle::ty::{self, TyCtxt}; -use rustc_query_system::dep_graph::HasDepContext; +use rustc_query_system::dep_graph::{DepNodeParams, HasDepContext}; use rustc_query_system::ich::StableHashingContext; use rustc_query_system::query::{ - QueryContext, QueryJobId, QueryMap, QuerySideEffects, QueryStackFrame, + force_query, QueryContext, QueryDescription, QueryJobId, QueryMap, QuerySideEffects, + QueryStackFrame, }; use std::any::Any; use std::num::NonZeroU64; @@ -315,6 +316,27 @@ pub(crate) fn try_load_from_on_disk_cache<'tcx, K, V>( } } +pub(crate) fn force_from_dep_node<'tcx, Q>( + tcx: TyCtxt<'tcx>, + // dep_node: rustc_query_system::dep_graph::DepNode, + dep_node: DepNode, + recover: fn(TyCtxt<'tcx>, DepNode) -> Option, +) -> bool +where + Q: QueryDescription>, + Q::Key: DepNodeParams>, +{ + if let Some(key) = recover(tcx, dep_node) { + #[cfg(debug_assertions)] + let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered(); + let tcx = QueryCtxt::from_tcx(tcx); + force_query::(tcx, key, dep_node); + true + } else { + false + } +} + // NOTE: `$V` isn't used here, but we still need to match on it so it can be passed to other macros // invoked by `rustc_query_append`. macro_rules! define_queries { @@ -385,7 +407,7 @@ macro_rules! define_queries { use super::*; use rustc_middle::dep_graph::DepNode; use rustc_query_system::dep_graph::DepNodeParams; - use rustc_query_system::query::{force_query, QueryDescription}; + use rustc_query_system::query::QueryDescription; use rustc_query_system::dep_graph::FingerprintStyle; // We use this for most things when incr. comp. is turned off. @@ -462,23 +484,11 @@ macro_rules! define_queries { < as QueryConfig>::Key as DepNodeParams>>::recover(tcx, &dep_node) } - fn force_from_dep_node(tcx: TyCtxt<'_>, dep_node: DepNode) -> bool { - if let Some(key) = recover(tcx, dep_node) { - #[cfg(debug_assertions)] - let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered(); - let tcx = QueryCtxt::from_tcx(tcx); - force_query::, _>(tcx, key, dep_node); - true - } else { - false - } - } - DepKindStruct { is_anon, is_eval_always, fingerprint_style, - force_from_dep_node: Some(force_from_dep_node), + force_from_dep_node: Some(|tcx, dep_node| $crate::plumbing::force_from_dep_node::>(tcx, dep_node, recover)), try_load_from_on_disk_cache: Some(|tcx, key| $crate::plumbing::try_load_from_on_disk_cache(tcx, key, recover, queries::$name::cache_on_disk, TyCtxt::$name)), } })* From 8f442e8ded9cd246e19ec9886eb50c2131a6e7ba Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 23 Aug 2022 22:49:20 -0500 Subject: [PATCH 4069/5092] Get rid of `fn recover` --- compiler/rustc_query_impl/src/plumbing.rs | 26 +++++++---------------- 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 7c6b898751a9..3483c40396b5 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -299,16 +299,15 @@ pub(crate) fn create_query_frame< QueryStackFrame::new(name, description, span, def_kind, hash) } -pub(crate) fn try_load_from_on_disk_cache<'tcx, K, V>( +pub(crate) fn try_load_from_on_disk_cache<'tcx, K: DepNodeParams>, V>( tcx: TyCtxt<'tcx>, dep_node: DepNode, - recover: fn(TyCtxt<'tcx>, DepNode) -> Option, cache_on_disk: fn(TyCtxt<'tcx>, &K) -> bool, do_query: fn(TyCtxt<'tcx>, K) -> V, ) { debug_assert!(tcx.dep_graph.is_green(&dep_node)); - let key = recover(tcx, dep_node).unwrap_or_else(|| { + let key = K::recover(tcx, &dep_node).unwrap_or_else(|| { panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash) }); if cache_on_disk(tcx, &key) { @@ -316,17 +315,12 @@ pub(crate) fn try_load_from_on_disk_cache<'tcx, K, V>( } } -pub(crate) fn force_from_dep_node<'tcx, Q>( - tcx: TyCtxt<'tcx>, - // dep_node: rustc_query_system::dep_graph::DepNode, - dep_node: DepNode, - recover: fn(TyCtxt<'tcx>, DepNode) -> Option, -) -> bool +fn force_from_dep_node<'tcx, Q>(tcx: TyCtxt<'tcx>, dep_node: DepNode) -> bool where Q: QueryDescription>, Q::Key: DepNodeParams>, { - if let Some(key) = recover(tcx, dep_node) { + if let Some(key) = Q::Key::recover(tcx, &dep_node) { #[cfg(debug_assertions)] let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered(); let tcx = QueryCtxt::from_tcx(tcx); @@ -405,7 +399,6 @@ macro_rules! define_queries { #[allow(nonstandard_style)] mod query_callbacks { use super::*; - use rustc_middle::dep_graph::DepNode; use rustc_query_system::dep_graph::DepNodeParams; use rustc_query_system::query::QueryDescription; use rustc_query_system::dep_graph::FingerprintStyle; @@ -479,17 +472,14 @@ macro_rules! define_queries { } } - #[inline(always)] - fn recover<'tcx>(tcx: TyCtxt<'tcx>, dep_node: DepNode) -> Option< as QueryConfig>::Key> { - < as QueryConfig>::Key as DepNodeParams>>::recover(tcx, &dep_node) - } - DepKindStruct { is_anon, is_eval_always, fingerprint_style, - force_from_dep_node: Some(|tcx, dep_node| $crate::plumbing::force_from_dep_node::>(tcx, dep_node, recover)), - try_load_from_on_disk_cache: Some(|tcx, key| $crate::plumbing::try_load_from_on_disk_cache(tcx, key, recover, queries::$name::cache_on_disk, TyCtxt::$name)), + force_from_dep_node: Some(|tcx, dep_node| $crate::plumbing::force_from_dep_node::>(tcx, dep_node)), + try_load_from_on_disk_cache: Some(|tcx, key| $crate::plumbing::try_load_from_on_disk_cache::< + as QueryConfig>::Key, _ + >(tcx, key, queries::$name::cache_on_disk, TyCtxt::$name)), } })* } From 0c4ec5df58201a9215248d6cf68865431b4d3e35 Mon Sep 17 00:00:00 2001 From: est31 Date: Tue, 30 Aug 2022 23:05:51 +0200 Subject: [PATCH 4070/5092] Also replace the version placeholder in rustc_attr This fixes rustdoc not showing the current version as stabilization version for recently stabilized lang features. --- compiler/rustc_attr/src/builtin.rs | 12 ++++++++++++ compiler/rustc_passes/src/lib_features.rs | 2 +- src/tools/replace-version-placeholder/src/main.rs | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 65edab78ce74..a8ed510866d8 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -15,6 +15,12 @@ use std::num::NonZeroU32; use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause}; +/// The version placeholder that recently stabilized features contain inside the +/// `since` field of the `#[stable]` attribute. +/// +/// For more, see [this pull request](https://github.com/rust-lang/rust/pull/100591). +pub const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION"; + pub fn is_builtin_attr(attr: &Attribute) -> bool { attr.is_doc_comment() || attr.ident().filter(|ident| is_builtin_attr_name(ident.name)).is_some() } @@ -483,6 +489,12 @@ where } } + if let Some(s) = since && s.as_str() == VERSION_PLACEHOLDER { + let version = option_env!("CFG_VERSION").unwrap_or(""); + let version = version.split(' ').next().unwrap(); + since = Some(Symbol::intern(&version)); + } + match (feature, since) { (Some(feature), Some(since)) => { let level = Stable { since, allowed_through_unstable_modules: false }; diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index 70b6bfd1e582..5aac6943eef1 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -5,6 +5,7 @@ //! collect them instead. use rustc_ast::{Attribute, MetaItemKind}; +use rustc_attr::VERSION_PLACEHOLDER; use rustc_errors::struct_span_err; use rustc_hir::intravisit::Visitor; use rustc_middle::hir::nested_filter; @@ -54,7 +55,6 @@ impl<'tcx> LibFeatureCollector<'tcx> { } } } - const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION"; if let Some(s) = since && s.as_str() == VERSION_PLACEHOLDER { let version = option_env!("CFG_VERSION").unwrap_or(""); diff --git a/src/tools/replace-version-placeholder/src/main.rs b/src/tools/replace-version-placeholder/src/main.rs index 146e53f2e9a0..33b35d054157 100644 --- a/src/tools/replace-version-placeholder/src/main.rs +++ b/src/tools/replace-version-placeholder/src/main.rs @@ -14,7 +14,7 @@ fn main() { walk::filter_dirs(path) // We exempt these as they require the placeholder // for their operation - || path.ends_with("compiler/rustc_passes/src/lib_features.rs") + || path.ends_with("compiler/rustc_attr/src/builtin.rs") || path.ends_with("src/tools/tidy/src/features/version.rs") || path.ends_with("src/tools/replace-version-placeholder") }, From 83b6dc9588b6f970fd2a1c2da6373bebe406946f Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 23 Aug 2022 23:31:12 -0500 Subject: [PATCH 4071/5092] Move almost all of the function in `query_callbacks` to a generic function --- compiler/rustc_query_impl/src/plumbing.rs | 75 ++++++++++++++--------- 1 file changed, 47 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 3483c40396b5..49afa3b36343 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -7,14 +7,16 @@ use crate::{on_disk_cache, Queries}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lock; use rustc_errors::{Diagnostic, Handler}; -use rustc_middle::dep_graph::{self, DepKind, DepNode, DepNodeIndex, SerializedDepNodeIndex}; +use rustc_middle::dep_graph::{ + self, DepKind, DepKindStruct, DepNode, DepNodeIndex, SerializedDepNodeIndex, +}; use rustc_middle::ty::tls::{self, ImplicitCtxt}; use rustc_middle::ty::{self, TyCtxt}; use rustc_query_system::dep_graph::{DepNodeParams, HasDepContext}; use rustc_query_system::ich::StableHashingContext; use rustc_query_system::query::{ - force_query, QueryContext, QueryDescription, QueryJobId, QueryMap, QuerySideEffects, - QueryStackFrame, + force_query, QueryConfig, QueryContext, QueryDescription, QueryJobId, QueryMap, + QuerySideEffects, QueryStackFrame, }; use std::any::Any; use std::num::NonZeroU64; @@ -303,7 +305,7 @@ pub(crate) fn try_load_from_on_disk_cache<'tcx, K: DepNodeParams>, tcx: TyCtxt<'tcx>, dep_node: DepNode, cache_on_disk: fn(TyCtxt<'tcx>, &K) -> bool, - do_query: fn(TyCtxt<'tcx>, K) -> V, + cache_query_deps: fn(TyCtxt<'tcx>, K) -> V, ) { debug_assert!(tcx.dep_graph.is_green(&dep_node)); @@ -311,11 +313,11 @@ pub(crate) fn try_load_from_on_disk_cache<'tcx, K: DepNodeParams>, panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash) }); if cache_on_disk(tcx, &key) { - let _ = do_query(tcx, key); + let _ = cache_query_deps(tcx, key); } } -fn force_from_dep_node<'tcx, Q>(tcx: TyCtxt<'tcx>, dep_node: DepNode) -> bool +pub(crate) fn force_from_dep_node<'tcx, Q>(tcx: TyCtxt<'tcx>, dep_node: DepNode) -> bool where Q: QueryDescription>, Q::Key: DepNodeParams>, @@ -331,6 +333,39 @@ where } } +pub(crate) fn query_callback<'tcx, Q: QueryConfig>( + // NOTE: we can't remove these function pointers, because `recover` is invariant -> `try_load_from_on_disk_cache` takes a concrete lifetime, not a universal lifetime. + // Instead, we infer the correct lifetime at the callsite, so we can pass in a HRTB function pointer to the DepKindStruct. + try_load_from_on_disk_cache: fn(TyCtxt<'_>, DepNode), + force_from_dep_node: fn(TyCtxt<'_>, DepNode) -> bool, + is_anon: bool, + is_eval_always: bool, +) -> DepKindStruct +where + Q: QueryDescription>, + Q::Key: DepNodeParams>, +{ + let fingerprint_style = Q::Key::fingerprint_style(); + + if is_anon || !fingerprint_style.reconstructible() { + return DepKindStruct { + is_anon, + is_eval_always, + fingerprint_style, + force_from_dep_node: None, + try_load_from_on_disk_cache: None, + }; + } + + DepKindStruct { + is_anon, + is_eval_always, + fingerprint_style, + force_from_dep_node: Some(force_from_dep_node), + try_load_from_on_disk_cache: Some(try_load_from_on_disk_cache), + } +} + // NOTE: `$V` isn't used here, but we still need to match on it so it can be passed to other macros // invoked by `rustc_query_append`. macro_rules! define_queries { @@ -399,7 +434,6 @@ macro_rules! define_queries { #[allow(nonstandard_style)] mod query_callbacks { use super::*; - use rustc_query_system::dep_graph::DepNodeParams; use rustc_query_system::query::QueryDescription; use rustc_query_system::dep_graph::FingerprintStyle; @@ -458,29 +492,14 @@ macro_rules! define_queries { $(pub(crate) fn $name()-> DepKindStruct { let is_anon = is_anon!([$($modifiers)*]); let is_eval_always = is_eval_always!([$($modifiers)*]); + type Q<'tcx> = queries::$name<'tcx>; - let fingerprint_style = - < as QueryConfig>::Key as DepNodeParams>>::fingerprint_style(); - - if is_anon || !fingerprint_style.reconstructible() { - return DepKindStruct { - is_anon, - is_eval_always, - fingerprint_style, - force_from_dep_node: None, - try_load_from_on_disk_cache: None, - } - } - - DepKindStruct { + $crate::plumbing::query_callback::>( + |tcx, key| $crate::plumbing::try_load_from_on_disk_cache::< as QueryConfig>::Key, _>(tcx, key, >::cache_on_disk, TyCtxt::$name), + |tcx, key| $crate::plumbing::force_from_dep_node::>(tcx, key), is_anon, - is_eval_always, - fingerprint_style, - force_from_dep_node: Some(|tcx, dep_node| $crate::plumbing::force_from_dep_node::>(tcx, dep_node)), - try_load_from_on_disk_cache: Some(|tcx, key| $crate::plumbing::try_load_from_on_disk_cache::< - as QueryConfig>::Key, _ - >(tcx, key, queries::$name::cache_on_disk, TyCtxt::$name)), - } + is_eval_always + ) })* } From 4fcc7452666a82c677ae6563bad31c852c258215 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 23 Aug 2022 23:34:23 -0500 Subject: [PATCH 4072/5092] Simplify `try_load_from_on_disk_cache` --- compiler/rustc_query_impl/src/plumbing.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 49afa3b36343..cc7e07651710 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -301,18 +301,20 @@ pub(crate) fn create_query_frame< QueryStackFrame::new(name, description, span, def_kind, hash) } -pub(crate) fn try_load_from_on_disk_cache<'tcx, K: DepNodeParams>, V>( +pub(crate) fn try_load_from_on_disk_cache<'tcx, Q, V>( tcx: TyCtxt<'tcx>, dep_node: DepNode, - cache_on_disk: fn(TyCtxt<'tcx>, &K) -> bool, - cache_query_deps: fn(TyCtxt<'tcx>, K) -> V, -) { + cache_query_deps: fn(TyCtxt<'tcx>, Q::Key) -> V, +) where + Q: QueryDescription>, + Q::Key: DepNodeParams>, +{ debug_assert!(tcx.dep_graph.is_green(&dep_node)); - let key = K::recover(tcx, &dep_node).unwrap_or_else(|| { + let key = Q::Key::recover(tcx, &dep_node).unwrap_or_else(|| { panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash) }); - if cache_on_disk(tcx, &key) { + if Q::cache_on_disk(tcx, &key) { let _ = cache_query_deps(tcx, key); } } @@ -434,7 +436,6 @@ macro_rules! define_queries { #[allow(nonstandard_style)] mod query_callbacks { use super::*; - use rustc_query_system::query::QueryDescription; use rustc_query_system::dep_graph::FingerprintStyle; // We use this for most things when incr. comp. is turned off. @@ -495,7 +496,7 @@ macro_rules! define_queries { type Q<'tcx> = queries::$name<'tcx>; $crate::plumbing::query_callback::>( - |tcx, key| $crate::plumbing::try_load_from_on_disk_cache::< as QueryConfig>::Key, _>(tcx, key, >::cache_on_disk, TyCtxt::$name), + |tcx, key| $crate::plumbing::try_load_from_on_disk_cache::, _>(tcx, key, TyCtxt::$name), |tcx, key| $crate::plumbing::force_from_dep_node::>(tcx, key), is_anon, is_eval_always From 4e09a13bb848a64acf6bb20359f582e813e74764 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 29 Aug 2022 10:20:14 -0500 Subject: [PATCH 4073/5092] Don't create two new closures for each query - Parameterize DepKindStruct over `'tcx` This allows passing in an invariant function pointer in `query_callback`, rather than having to try and make it work for any lifetime. - Add a new `execute_query` function to `QueryDescription` so we can call `tcx.$name` without needing to be in a macro context --- compiler/rustc_middle/src/arena.rs | 2 +- .../rustc_middle/src/dep_graph/dep_node.rs | 6 +-- compiler/rustc_middle/src/ty/context.rs | 6 +-- compiler/rustc_query_impl/src/plumbing.rs | 51 ++++++++----------- .../rustc_query_system/src/query/config.rs | 3 ++ 5 files changed, 31 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index b94de537dc81..65d5f755f724 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -100,7 +100,7 @@ macro_rules! arena_types { [decode] is_late_bound_map: rustc_data_structures::fx::FxIndexSet, [decode] impl_source: rustc_middle::traits::ImplSource<'tcx, ()>, - [] dep_kind: rustc_middle::dep_graph::DepKindStruct, + [] dep_kind: rustc_middle::dep_graph::DepKindStruct<'tcx>, ]); ) } diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index 65fc8a2e9cf5..7718906ac4ee 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -74,7 +74,7 @@ pub use rustc_query_system::dep_graph::{DepContext, DepNodeParams}; /// Information is retrieved by indexing the `DEP_KINDS` array using the integer value /// of the `DepKind`. Overall, this allows to implement `DepContext` using this manual /// jump table instead of large matches. -pub struct DepKindStruct { +pub struct DepKindStruct<'tcx> { /// Anonymous queries cannot be replayed from one compiler invocation to the next. /// When their result is needed, it is recomputed. They are useful for fine-grained /// dependency tracking, and caching within one compiler invocation. @@ -124,10 +124,10 @@ pub struct DepKindStruct { /// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode` /// is actually a `DefPathHash`, and can therefore just look up the corresponding /// `DefId` in `tcx.def_path_hash_to_def_id`. - pub force_from_dep_node: Option, dep_node: DepNode) -> bool>, + pub force_from_dep_node: Option, dep_node: DepNode) -> bool>, /// Invoke a query to put the on-disk cached value in memory. - pub try_load_from_on_disk_cache: Option, DepNode)>, + pub try_load_from_on_disk_cache: Option, DepNode)>, } impl DepKind { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 052bb1263c98..7a990773ab87 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1089,7 +1089,7 @@ pub struct GlobalCtxt<'tcx> { pub queries: &'tcx dyn query::QueryEngine<'tcx>, pub query_caches: query::QueryCaches<'tcx>, - query_kinds: &'tcx [DepKindStruct], + query_kinds: &'tcx [DepKindStruct<'tcx>], // Internal caches for metadata decoding. No need to track deps on this. pub ty_rcache: Lock>>, @@ -1246,7 +1246,7 @@ impl<'tcx> TyCtxt<'tcx> { dep_graph: DepGraph, on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>, queries: &'tcx dyn query::QueryEngine<'tcx>, - query_kinds: &'tcx [DepKindStruct], + query_kinds: &'tcx [DepKindStruct<'tcx>], crate_name: &str, output_filenames: OutputFilenames, ) -> GlobalCtxt<'tcx> { @@ -1296,7 +1296,7 @@ impl<'tcx> TyCtxt<'tcx> { } } - pub(crate) fn query_kind(self, k: DepKind) -> &'tcx DepKindStruct { + pub(crate) fn query_kind(self, k: DepKind) -> &'tcx DepKindStruct<'tcx> { &self.query_kinds[k as usize] } diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index cc7e07651710..274df5b5e5e9 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -301,11 +301,8 @@ pub(crate) fn create_query_frame< QueryStackFrame::new(name, description, span, def_kind, hash) } -pub(crate) fn try_load_from_on_disk_cache<'tcx, Q, V>( - tcx: TyCtxt<'tcx>, - dep_node: DepNode, - cache_query_deps: fn(TyCtxt<'tcx>, Q::Key) -> V, -) where +fn try_load_from_on_disk_cache<'tcx, Q>(tcx: TyCtxt<'tcx>, dep_node: DepNode) +where Q: QueryDescription>, Q::Key: DepNodeParams>, { @@ -315,11 +312,11 @@ pub(crate) fn try_load_from_on_disk_cache<'tcx, Q, V>( panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash) }); if Q::cache_on_disk(tcx, &key) { - let _ = cache_query_deps(tcx, key); + let _ = Q::execute_query(tcx, key); } } -pub(crate) fn force_from_dep_node<'tcx, Q>(tcx: TyCtxt<'tcx>, dep_node: DepNode) -> bool +fn force_from_dep_node<'tcx, Q>(tcx: TyCtxt<'tcx>, dep_node: DepNode) -> bool where Q: QueryDescription>, Q::Key: DepNodeParams>, @@ -336,13 +333,9 @@ where } pub(crate) fn query_callback<'tcx, Q: QueryConfig>( - // NOTE: we can't remove these function pointers, because `recover` is invariant -> `try_load_from_on_disk_cache` takes a concrete lifetime, not a universal lifetime. - // Instead, we infer the correct lifetime at the callsite, so we can pass in a HRTB function pointer to the DepKindStruct. - try_load_from_on_disk_cache: fn(TyCtxt<'_>, DepNode), - force_from_dep_node: fn(TyCtxt<'_>, DepNode) -> bool, is_anon: bool, is_eval_always: bool, -) -> DepKindStruct +) -> DepKindStruct<'tcx> where Q: QueryDescription>, Q::Key: DepNodeParams>, @@ -363,8 +356,8 @@ where is_anon, is_eval_always, fingerprint_style, - force_from_dep_node: Some(force_from_dep_node), - try_load_from_on_disk_cache: Some(try_load_from_on_disk_cache), + force_from_dep_node: Some(force_from_dep_node::), + try_load_from_on_disk_cache: Some(try_load_from_on_disk_cache::), } } @@ -431,6 +424,10 @@ macro_rules! define_queries { try_load_from_disk: Self::TRY_LOAD_FROM_DISK, } } + + fn execute_query(tcx: TyCtxt<'tcx>, k: Self::Key) -> Self::Stored { + tcx.$name(k) + } })* #[allow(nonstandard_style)] @@ -439,7 +436,7 @@ macro_rules! define_queries { use rustc_query_system::dep_graph::FingerprintStyle; // We use this for most things when incr. comp. is turned off. - pub fn Null() -> DepKindStruct { + pub fn Null<'tcx>() -> DepKindStruct<'tcx> { DepKindStruct { is_anon: false, is_eval_always: false, @@ -450,7 +447,7 @@ macro_rules! define_queries { } // We use this for the forever-red node. - pub fn Red() -> DepKindStruct { + pub fn Red<'tcx>() -> DepKindStruct<'tcx> { DepKindStruct { is_anon: false, is_eval_always: false, @@ -460,7 +457,7 @@ macro_rules! define_queries { } } - pub fn TraitSelect() -> DepKindStruct { + pub fn TraitSelect<'tcx>() -> DepKindStruct<'tcx> { DepKindStruct { is_anon: true, is_eval_always: false, @@ -470,7 +467,7 @@ macro_rules! define_queries { } } - pub fn CompileCodegenUnit() -> DepKindStruct { + pub fn CompileCodegenUnit<'tcx>() -> DepKindStruct<'tcx> { DepKindStruct { is_anon: false, is_eval_always: false, @@ -480,7 +477,7 @@ macro_rules! define_queries { } } - pub fn CompileMonoItem() -> DepKindStruct { + pub fn CompileMonoItem<'tcx>() -> DepKindStruct<'tcx> { DepKindStruct { is_anon: false, is_eval_always: false, @@ -490,21 +487,15 @@ macro_rules! define_queries { } } - $(pub(crate) fn $name()-> DepKindStruct { - let is_anon = is_anon!([$($modifiers)*]); - let is_eval_always = is_eval_always!([$($modifiers)*]); - type Q<'tcx> = queries::$name<'tcx>; - - $crate::plumbing::query_callback::>( - |tcx, key| $crate::plumbing::try_load_from_on_disk_cache::, _>(tcx, key, TyCtxt::$name), - |tcx, key| $crate::plumbing::force_from_dep_node::>(tcx, key), - is_anon, - is_eval_always + $(pub(crate) fn $name<'tcx>()-> DepKindStruct<'tcx> { + $crate::plumbing::query_callback::>( + is_anon!([$($modifiers)*]), + is_eval_always!([$($modifiers)*]), ) })* } - pub fn query_callbacks<'tcx>(arena: &'tcx Arena<'tcx>) -> &'tcx [DepKindStruct] { + pub fn query_callbacks<'tcx>(arena: &'tcx Arena<'tcx>) -> &'tcx [DepKindStruct<'tcx>] { arena.alloc_from_iter(make_dep_kind_array!(query_callbacks)) } } diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs index bd0fd7ac3503..ea38df836cbf 100644 --- a/compiler/rustc_query_system/src/query/config.rs +++ b/compiler/rustc_query_system/src/query/config.rs @@ -73,4 +73,7 @@ pub trait QueryDescription: QueryConfig { fn make_vtable(tcx: CTX, key: &Self::Key) -> QueryVTable; fn cache_on_disk(tcx: CTX::DepContext, key: &Self::Key) -> bool; + + // Don't use this method to compute query results, instead use the methods on TyCtxt + fn execute_query(tcx: CTX::DepContext, k: Self::Key) -> Self::Stored; } From 1cd28639c9773474bf447375a74b5c2491014c56 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Thu, 1 Sep 2022 20:49:12 -0500 Subject: [PATCH 4074/5092] Add autolabels for `A-query-system` --- triagebot.toml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index 8a90bc0e3c14..89d1574726f0 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -195,6 +195,13 @@ trigger_files = [ "compiler/rustc_macros/src/diagnostics" ] +[autolabel."A-query-system"] +trigger_files = [ + "compiler/rustc_query_system", + "compiler/rustc_query_impl", + "compiler/rustc_macros/src/query.rs" +] + [notify-zulip."I-prioritize"] zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts topic = "#{number} {title}" From e5d60af3c6f44be48371e32ef553416d277c92ec Mon Sep 17 00:00:00 2001 From: Jakob Degen Date: Sat, 20 Aug 2022 21:47:53 -0700 Subject: [PATCH 4075/5092] Simplify MIR opt tests This commit removes many cases of MIR opt tests emitting `.diff`s for more than one pass. These tests cannot be `unit-test`s, and so they are easy to break, and they also provide little value due to having excessively strong opinions over *how* a piece of code should be optimized. Where reasonable, we instead add separate test files that only emit the `PreCodegen.after` MIR for code where we want to track what the result of the net result of the optimization pipeline's output is. --- .../mir-opt/early_otherwise_branch_68867.rs | 5 +- ...re-SimplifyConstCondition-final.after.diff | 322 ------------------ ...ch_68867.try_sum.EarlyOtherwiseBranch.diff | 12 +- src/test/mir-opt/issue-73223.rs | 1 - .../issue_73223.main.PreCodegen.32bit.diff | 117 ------- .../issue_73223.main.PreCodegen.64bit.diff | 117 ------- ...wer_array_len.array_bound.InstCombine.diff | 66 ---- ..._array_len.array_bound.SimplifyLocals.diff | 70 ---- ...array_len.array_bound_mut.InstCombine.diff | 79 ----- ...ay_len.array_bound_mut.SimplifyLocals.diff | 93 ----- ...lower_array_len.array_len.InstCombine.diff | 27 -- ...er_array_len.array_len.SimplifyLocals.diff | 22 -- ...ay_len.array_len_by_value.InstCombine.diff | 26 -- ...len.array_len_by_value.SimplifyLocals.diff | 22 -- src/test/mir-opt/lower_array_len.rs | 11 +- ...y_len_e2e.array_bound.PreCodegen.after.mir | 49 +++ ...n_e2e.array_bound_mut.PreCodegen.after.mir | 62 ++++ ...ray_len_e2e.array_len.PreCodegen.after.mir | 11 + ...2e.array_len_by_value.PreCodegen.after.mir | 11 + src/test/mir-opt/lower_array_len_e2e.rs | 39 +++ ...r_intrinsics.align_of.LowerIntrinsics.diff | 2 +- ...trinsics.discriminant.LowerIntrinsics.diff | 20 +- ...wer_intrinsics.forget.LowerIntrinsics.diff | 2 +- ..._intrinsics.non_const.LowerIntrinsics.diff | 2 +- src/test/mir-opt/lower_intrinsics.rs | 31 +- ...er_intrinsics.size_of.LowerIntrinsics.diff | 2 +- ...ntrinsics.unreachable.LowerIntrinsics.diff | 2 +- ...r_intrinsics.wrapping.LowerIntrinsics.diff | 6 +- ...intrinsics_e2e.f_u64.PreCodegen.after.mir} | 38 +-- ...ntrinsics_e2e.f_unit.PreCodegen.after.mir} | 34 +- src/test/mir-opt/lower_intrinsics_e2e.rs | 32 ++ ...s.bar.MatchBranchSimplification.32bit.diff | 4 +- ...s.bar.MatchBranchSimplification.64bit.diff | 4 +- ...s.foo.MatchBranchSimplification.32bit.diff | 45 ++- ...s.foo.MatchBranchSimplification.64bit.diff | 45 ++- ...e_branches.foo.PreCodegen.before.32bit.mir | 10 - ...e_branches.foo.PreCodegen.before.64bit.mir | 10 - ...ed_if.MatchBranchSimplification.32bit.diff | 101 +++++- ...ed_if.MatchBranchSimplification.64bit.diff | 101 +++++- src/test/mir-opt/matches_reduce_branches.rs | 3 +- src/test/mir-opt/matches_u8.rs | 2 + ...t_switch.identity.SeparateConstSwitch.diff | 4 +- src/test/mir-opt/separate_const_switch.rs | 4 - src/test/mir-opt/simplify-arm-identity.rs | 3 + src/test/mir-opt/simplify-arm.rs | 3 + ...ocals-removes-unused-discriminant-reads.rs | 2 +- .../simplify_arm.id.SimplifyArmIdentity.diff | 46 --- .../simplify_arm.id.SimplifyBranchSame.diff | 46 --- ...ify_arm.id_result.SimplifyArmIdentity.diff | 58 ---- ...lify_arm.id_result.SimplifyBranchSame.diff | 58 ---- ...entity.main.SimplifyArmIdentity.32bit.diff | 61 ---- ...entity.main.SimplifyArmIdentity.64bit.diff | 61 ---- ...minant_reads.map.SimplifyLocals.32bit.diff | 17 +- ...minant_reads.map.SimplifyLocals.64bit.diff | 17 +- src/test/mir-opt/simplify_try.rs | 30 -- .../try_identity_e2e.new.PreCodegen.after.mir | 96 ++++++ .../try_identity_e2e.old.PreCodegen.after.mir | 53 +++ src/test/mir-opt/try_identity_e2e.rs | 34 ++ 58 files changed, 742 insertions(+), 1509 deletions(-) delete mode 100644 src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff delete mode 100644 src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff delete mode 100644 src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff delete mode 100644 src/test/mir-opt/lower_array_len.array_bound.InstCombine.diff delete mode 100644 src/test/mir-opt/lower_array_len.array_bound.SimplifyLocals.diff delete mode 100644 src/test/mir-opt/lower_array_len.array_bound_mut.InstCombine.diff delete mode 100644 src/test/mir-opt/lower_array_len.array_bound_mut.SimplifyLocals.diff delete mode 100644 src/test/mir-opt/lower_array_len.array_len.InstCombine.diff delete mode 100644 src/test/mir-opt/lower_array_len.array_len.SimplifyLocals.diff delete mode 100644 src/test/mir-opt/lower_array_len.array_len_by_value.InstCombine.diff delete mode 100644 src/test/mir-opt/lower_array_len.array_len_by_value.SimplifyLocals.diff create mode 100644 src/test/mir-opt/lower_array_len_e2e.array_bound.PreCodegen.after.mir create mode 100644 src/test/mir-opt/lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir create mode 100644 src/test/mir-opt/lower_array_len_e2e.array_len.PreCodegen.after.mir create mode 100644 src/test/mir-opt/lower_array_len_e2e.array_len_by_value.PreCodegen.after.mir create mode 100644 src/test/mir-opt/lower_array_len_e2e.rs rename src/test/mir-opt/{lower_intrinsics.f_u64.PreCodegen.before.mir => lower_intrinsics_e2e.f_u64.PreCodegen.after.mir} (68%) rename src/test/mir-opt/{lower_intrinsics.f_unit.PreCodegen.before.mir => lower_intrinsics_e2e.f_unit.PreCodegen.after.mir} (68%) create mode 100644 src/test/mir-opt/lower_intrinsics_e2e.rs delete mode 100644 src/test/mir-opt/matches_reduce_branches.foo.PreCodegen.before.32bit.mir delete mode 100644 src/test/mir-opt/matches_reduce_branches.foo.PreCodegen.before.64bit.mir delete mode 100644 src/test/mir-opt/simplify_arm.id.SimplifyArmIdentity.diff delete mode 100644 src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff delete mode 100644 src/test/mir-opt/simplify_arm.id_result.SimplifyArmIdentity.diff delete mode 100644 src/test/mir-opt/simplify_arm.id_result.SimplifyBranchSame.diff delete mode 100644 src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.32bit.diff delete mode 100644 src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.64bit.diff delete mode 100644 src/test/mir-opt/simplify_try.rs create mode 100644 src/test/mir-opt/try_identity_e2e.new.PreCodegen.after.mir create mode 100644 src/test/mir-opt/try_identity_e2e.old.PreCodegen.after.mir create mode 100644 src/test/mir-opt/try_identity_e2e.rs diff --git a/src/test/mir-opt/early_otherwise_branch_68867.rs b/src/test/mir-opt/early_otherwise_branch_68867.rs index ca298e9211d4..a6a56f3a95d1 100644 --- a/src/test/mir-opt/early_otherwise_branch_68867.rs +++ b/src/test/mir-opt/early_otherwise_branch_68867.rs @@ -1,4 +1,6 @@ -// compile-flags: -Z mir-opt-level=4 -Zunsound-mir-opts +// unit-test: EarlyOtherwiseBranch + +// FIXME: This test was broken by the derefer change. // example from #68867 type CSSFloat = f32; @@ -11,7 +13,6 @@ pub enum ViewportPercentageLength { } // EMIT_MIR early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff -// EMIT_MIR early_otherwise_branch_68867.try_sum EarlyOtherwiseBranch.before SimplifyConstCondition-final.after #[no_mangle] pub extern "C" fn try_sum( x: &ViewportPercentageLength, diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff deleted file mode 100644 index 8b37fb79f411..000000000000 --- a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff +++ /dev/null @@ -1,322 +0,0 @@ -- // MIR for `try_sum` before EarlyOtherwiseBranch -+ // MIR for `try_sum` after SimplifyConstCondition-final - - fn try_sum(_1: &ViewportPercentageLength, _2: &ViewportPercentageLength) -> Result { - debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+1:5: +1:6 - debug other => _2; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+2:5: +2:10 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/early_otherwise_branch_68867.rs:+3:6: +3:42 - let mut _3: ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +11:6 - let mut _4: (&ViewportPercentageLength, &ViewportPercentageLength); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _5: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:15: +5:16 - let mut _6: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:18: +5:23 - let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:21: +6:30 - let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:21: +7:30 - let mut _9: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:23: +8:34 - let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:23: +9:34 - let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:11: +6:18 - let _12: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17 - let _13: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29 - let mut _14: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:49 - let mut _15: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:41 - let mut _16: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:44: +6:49 - let _17: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17 - let _18: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29 - let mut _19: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:49 - let mut _20: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:41 - let mut _21: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:44: +7:49 - let _22: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19 - let _23: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33 - let mut _24: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:55 - let mut _25: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:47 - let mut _26: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:50: +8:55 - let _27: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19 - let _28: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33 - let mut _29: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:55 - let mut _30: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:47 - let mut _31: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:50: +9:55 - let mut _32: !; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:14: +10:28 - let mut _33: (); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:25: +10:27 - let mut _34: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _35: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _36: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _37: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _38: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _39: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _40: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _41: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _42: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _43: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _44: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _45: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - let mut _46: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - scope 1 { -- debug one => _12; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17 -- debug other => _13; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29 -+ debug one => _15; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17 -+ debug other => _16; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29 - } - scope 2 { -- debug one => _17; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17 -- debug other => _18; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29 -+ debug one => _20; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17 -+ debug other => _21; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29 - } - scope 3 { -- debug one => _22; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19 -- debug other => _23; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33 -+ debug one => _25; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19 -+ debug other => _26; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33 - } - scope 4 { -- debug one => _27; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19 -- debug other => _28; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33 -+ debug one => _30; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19 -+ debug other => _31; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33 - } - - bb0: { -- StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +11:6 -- StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 -- StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:15: +5:16 -- _5 = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:15: +5:16 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +11:6 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:15: +5:16 -+ (_4.0: &ViewportPercentageLength) = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:15: +5:16 - StorageLive(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:18: +5:23 - _6 = _2; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:18: +5:23 - Deinit(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 -- (_4.0: &ViewportPercentageLength) = move _5; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - (_4.1: &ViewportPercentageLength) = move _6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:23: +5:24 -- StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:23: +5:24 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:23: +5:24 - _34 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - _11 = discriminant((*_34)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb11]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24 - } - - bb1: { - _35 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - _7 = discriminant((*_35)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24 - } - - bb2: { - StorageLive(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:25: +10:27 - nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:25: +10:27 - Deinit(_0); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28 - nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28 - discriminant(_0) = 1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28 - StorageDead(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:27: +10:28 -- StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+11:6: +11:7 -- StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:1: +12:2 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+11:6: +11:7 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:1: +12:2 - return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2 - } - - bb3: { - _36 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - _8 = discriminant((*_36)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24 - } - - bb4: { - _37 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - _9 = discriminant((*_37)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24 - } - - bb5: { - _38 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - _10 = discriminant((*_38)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24 - } - - bb6: { -- StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17 - _39 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17 -- _12 = (((*_39) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17 -- StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29 -+ _15 = (((*_39) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:14: +6:17 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29 - _40 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29 -- _13 = (((*_40) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29 -- StorageLive(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:49 -- StorageLive(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:41 -- _15 = _12; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:41 -- StorageLive(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:44: +6:49 -- _16 = _13; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:44: +6:49 -- _14 = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:49 -- StorageDead(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:48: +6:49 -- StorageDead(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:48: +6:49 -- Deinit(_3); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50 -- ((_3 as Vw).0: f32) = move _14; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50 -- discriminant(_3) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50 -- StorageDead(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50 -- StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50 -- StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50 -+ _16 = (((*_40) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:24: +6:29 -+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:49 -+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:41 -+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:41 -+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:44: +6:49 -+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:44: +6:49 -+ ((((_0 as Ok).0: ViewportPercentageLength) as Vw).0: f32) = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:38: +6:49 -+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:48: +6:49 -+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:48: +6:49 -+ Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50 -+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50 -+ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:35: +6:50 -+ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50 - goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+6:49: +6:50 - } - - bb7: { -- StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17 - _41 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17 -- _17 = (((*_41) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17 -- StorageLive(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29 -+ _20 = (((*_41) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:14: +7:17 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29 - _42 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29 -- _18 = (((*_42) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29 -- StorageLive(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:49 -- StorageLive(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:41 -- _20 = _17; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:41 -- StorageLive(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:44: +7:49 -- _21 = _18; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:44: +7:49 -- _19 = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:49 -- StorageDead(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:48: +7:49 -- StorageDead(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:48: +7:49 -- Deinit(_3); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50 -- ((_3 as Vh).0: f32) = move _19; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50 -- discriminant(_3) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50 -- StorageDead(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50 -- StorageDead(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50 -- StorageDead(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50 -+ _21 = (((*_42) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:24: +7:29 -+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:49 -+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:41 -+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:41 -+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:44: +7:49 -+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:44: +7:49 -+ ((((_0 as Ok).0: ViewportPercentageLength) as Vh).0: f32) = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:38: +7:49 -+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:48: +7:49 -+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:48: +7:49 -+ Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50 -+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50 -+ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:35: +7:50 -+ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50 - goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+7:49: +7:50 - } - - bb8: { -- StorageLive(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19 - _43 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19 -- _22 = (((*_43) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19 -- StorageLive(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33 -+ _25 = (((*_43) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:16: +8:19 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33 - _44 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33 -- _23 = (((*_44) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33 -- StorageLive(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:55 -- StorageLive(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:47 -- _25 = _22; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:47 -- StorageLive(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:50: +8:55 -- _26 = _23; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:50: +8:55 -- _24 = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:55 -- StorageDead(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:54: +8:55 -- StorageDead(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:54: +8:55 -- Deinit(_3); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56 -- ((_3 as Vmin).0: f32) = move _24; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56 -- discriminant(_3) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56 -- StorageDead(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56 -- StorageDead(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56 -- StorageDead(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56 -+ _26 = (((*_44) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:28: +8:33 -+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:55 -+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:47 -+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:47 -+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:50: +8:55 -+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:50: +8:55 -+ ((((_0 as Ok).0: ViewportPercentageLength) as Vmin).0: f32) = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:44: +8:55 -+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:54: +8:55 -+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:54: +8:55 -+ Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56 -+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56 -+ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:39: +8:56 -+ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56 - goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+8:55: +8:56 - } - - bb9: { -- StorageLive(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19 - _45 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19 -- _27 = (((*_45) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19 -- StorageLive(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33 -+ _30 = (((*_45) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:16: +9:19 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33 - _46 = deref_copy (_4.1: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33 -- _28 = (((*_46) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33 -- StorageLive(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:55 -- StorageLive(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:47 -- _30 = _27; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:47 -- StorageLive(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:50: +9:55 -- _31 = _28; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:50: +9:55 -- _29 = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:55 -- StorageDead(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:54: +9:55 -- StorageDead(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:54: +9:55 -- Deinit(_3); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56 -- ((_3 as Vmax).0: f32) = move _29; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56 -- discriminant(_3) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56 -- StorageDead(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56 -- StorageDead(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56 -- StorageDead(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56 -+ _31 = (((*_46) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:28: +9:33 -+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:55 -+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:47 -+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:47 -+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:50: +9:55 -+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:50: +9:55 -+ ((((_0 as Ok).0: ViewportPercentageLength) as Vmax).0: f32) = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:44: +9:55 -+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:54: +9:55 -+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:54: +9:55 -+ Deinit(((_0 as Ok).0: ViewportPercentageLength)); // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56 -+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56 -+ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:39: +9:56 -+ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56 - goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+9:55: +9:56 - } - - bb10: { - Deinit(_0); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:5: +11:7 -- ((_0 as Ok).0: ViewportPercentageLength) = move _3; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:5: +11:7 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:5: +11:7 - discriminant(_0) = 0; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:5: +11:7 -- StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+11:6: +11:7 -- StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:1: +12:2 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+11:6: +11:7 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:1: +12:2 - return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2 - } - - bb11: { - unreachable; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2 - } - } - diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff index 50a58d4792a8..6bc025bb5b20 100644 --- a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff +++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff @@ -80,7 +80,7 @@ StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:23: +5:24 _34 = deref_copy (_4.0: &ViewportPercentageLength); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 _11 = discriminant((*_34)); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:14: +5:24 - switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb11]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24 + switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:8: +5:24 } bb1: { @@ -91,14 +91,14 @@ bb2: { StorageLive(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:25: +10:27 - nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:25: +10:27 + Deinit(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:25: +10:27 Deinit(_0); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28 - nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28 + ((_0 as Err).0: ()) = move _33; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28 discriminant(_0) = 1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:21: +10:28 StorageDead(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+10:27: +10:28 StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+11:6: +11:7 StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:1: +12:2 - return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2 + goto -> bb11; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2 } bb3: { @@ -221,11 +221,11 @@ discriminant(_0) = 0; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+5:5: +11:7 StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+11:6: +11:7 StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:1: +12:2 - return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2 + goto -> bb11; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2 } bb11: { - unreachable; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2 + return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:+12:2: +12:2 } } diff --git a/src/test/mir-opt/issue-73223.rs b/src/test/mir-opt/issue-73223.rs index 703b87612313..9e731c409087 100644 --- a/src/test/mir-opt/issue-73223.rs +++ b/src/test/mir-opt/issue-73223.rs @@ -10,4 +10,3 @@ fn main() { // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR issue_73223.main.SimplifyArmIdentity.diff -// EMIT_MIR issue_73223.main.PreCodegen.diff diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff deleted file mode 100644 index be8e86a832cb..000000000000 --- a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff +++ /dev/null @@ -1,117 +0,0 @@ -- // MIR for `main` before PreCodegen -+ // MIR for `main` after PreCodegen - - fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/issue-73223.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/issue-73223.rs:+1:9: +1:14 - let mut _2: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - let _3: i32; // in scope 0 at $DIR/issue-73223.rs:+2:14: +2:15 - let mut _5: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _6: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _7: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _10: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _11: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _12: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _14: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _15: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _16: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _17: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _18: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _19: std::option::Option; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - scope 1 { - debug split => _1; // in scope 1 at $DIR/issue-73223.rs:+1:9: +1:14 - let _4: std::option::Option; // in scope 1 at $DIR/issue-73223.rs:+6:9: +6:14 - scope 3 { - debug _prev => _4; // in scope 3 at $DIR/issue-73223.rs:+6:9: +6:14 - let _8: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _9: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _20: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - scope 4 { - debug left_val => _8; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - debug right_val => _9; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _13: core::panicking::AssertKind; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - scope 5 { - debug kind => _13; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - } - } - } - scope 2 { - debug v => _3; // in scope 2 at $DIR/issue-73223.rs:+2:14: +2:15 - } - - bb0: { - StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:+1:9: +1:14 - StorageLive(_2); // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - Deinit(_2); // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - StorageLive(_3); // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15 - _3 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15 - _1 = _3; // scope 2 at $DIR/issue-73223.rs:+2:20: +2:21 - StorageDead(_3); // scope 0 at $DIR/issue-73223.rs:+2:20: +2:21 - StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:+4:6: +4:7 - StorageLive(_4); // scope 1 at $DIR/issue-73223.rs:+6:9: +6:14 - StorageLive(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_6); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _6 = &_1; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _20 = const main::promoted[0]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - // mir::Constant - // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) } - _7 = _20; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - Deinit(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_5.0: &i32) = move _6; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_5.1: &i32) = move _7; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_6); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _8 = (_5.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _9 = (_5.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_11); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_12); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _12 = (*_8); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _11 = Eq(move _12, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_12); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _10 = Not(move _11); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_11); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - switchInt(move _10) -> [false: bb2, otherwise: bb1]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - - bb1: { - StorageLive(_13); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_14); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_15); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_16); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _16 = _8; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _15 = _16; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_17); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_18); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _18 = _9; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _17 = _18; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_19); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - Deinit(_19); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - discriminant(_19) = 0; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _14 = core::panicking::assert_failed::(const core::panicking::AssertKind::Eq, move _15, move _17, move _19); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - // mir::Constant - // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option>) -> ! {core::panicking::assert_failed::}, val: Value() } - // mir::Constant - // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) } - } - - bb2: { - StorageDead(_10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_4); // scope 1 at $DIR/issue-73223.rs:+8:1: +8:2 - StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:+8:1: +8:2 - return; // scope 0 at $DIR/issue-73223.rs:+8:2: +8:2 - } - } - diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff deleted file mode 100644 index be8e86a832cb..000000000000 --- a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff +++ /dev/null @@ -1,117 +0,0 @@ -- // MIR for `main` before PreCodegen -+ // MIR for `main` after PreCodegen - - fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/issue-73223.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/issue-73223.rs:+1:9: +1:14 - let mut _2: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - let _3: i32; // in scope 0 at $DIR/issue-73223.rs:+2:14: +2:15 - let mut _5: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _6: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _7: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _10: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _11: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _12: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _14: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _15: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _16: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _17: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _18: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _19: std::option::Option; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - scope 1 { - debug split => _1; // in scope 1 at $DIR/issue-73223.rs:+1:9: +1:14 - let _4: std::option::Option; // in scope 1 at $DIR/issue-73223.rs:+6:9: +6:14 - scope 3 { - debug _prev => _4; // in scope 3 at $DIR/issue-73223.rs:+6:9: +6:14 - let _8: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _9: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _20: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - scope 4 { - debug left_val => _8; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - debug right_val => _9; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _13: core::panicking::AssertKind; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - scope 5 { - debug kind => _13; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - } - } - } - scope 2 { - debug v => _3; // in scope 2 at $DIR/issue-73223.rs:+2:14: +2:15 - } - - bb0: { - StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:+1:9: +1:14 - StorageLive(_2); // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - Deinit(_2); // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - StorageLive(_3); // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15 - _3 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15 - _1 = _3; // scope 2 at $DIR/issue-73223.rs:+2:20: +2:21 - StorageDead(_3); // scope 0 at $DIR/issue-73223.rs:+2:20: +2:21 - StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:+4:6: +4:7 - StorageLive(_4); // scope 1 at $DIR/issue-73223.rs:+6:9: +6:14 - StorageLive(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_6); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _6 = &_1; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _20 = const main::promoted[0]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - // mir::Constant - // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) } - _7 = _20; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - Deinit(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_5.0: &i32) = move _6; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_5.1: &i32) = move _7; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_6); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _8 = (_5.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _9 = (_5.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_11); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_12); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _12 = (*_8); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _11 = Eq(move _12, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_12); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _10 = Not(move _11); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_11); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - switchInt(move _10) -> [false: bb2, otherwise: bb1]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - - bb1: { - StorageLive(_13); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_14); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_15); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_16); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _16 = _8; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _15 = _16; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_17); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_18); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _18 = _9; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _17 = _18; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_19); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - Deinit(_19); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - discriminant(_19) = 0; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _14 = core::panicking::assert_failed::(const core::panicking::AssertKind::Eq, move _15, move _17, move _19); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - // mir::Constant - // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option>) -> ! {core::panicking::assert_failed::}, val: Value() } - // mir::Constant - // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) } - } - - bb2: { - StorageDead(_10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_4); // scope 1 at $DIR/issue-73223.rs:+8:1: +8:2 - StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:+8:1: +8:2 - return; // scope 0 at $DIR/issue-73223.rs:+8:2: +8:2 - } - } - diff --git a/src/test/mir-opt/lower_array_len.array_bound.InstCombine.diff b/src/test/mir-opt/lower_array_len.array_bound.InstCombine.diff deleted file mode 100644 index 2589c9f282f3..000000000000 --- a/src/test/mir-opt/lower_array_len.array_bound.InstCombine.diff +++ /dev/null @@ -1,66 +0,0 @@ -- // MIR for `array_bound` before InstCombine -+ // MIR for `array_bound` after InstCombine - - fn array_bound(_1: usize, _2: &[u8; N]) -> u8 { - debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:36: +0:41 - debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:+0:50: +0:55 - let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:+0:70: +0:72 - let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 - let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - let mut _11: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - - bb0: { - StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - _4 = _1; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- _7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ _7 = _2; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - _11 = _7; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:+1:20: +1:21 -- _5 = Len((*_11)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ _5 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - } - - bb1: { - StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 - _8 = _1; // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 -- _9 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ _9 = const N; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb2; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - } - - bb2: { - _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:+3:5: +3:6 - goto -> bb4; // scope 0 at $DIR/lower_array_len.rs:+1:5: +5:6 - } - - bb3: { - _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:11 - goto -> bb4; // scope 0 at $DIR/lower_array_len.rs:+1:5: +5:6 - } - - bb4: { - StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+5:5: +5:6 - return; // scope 0 at $DIR/lower_array_len.rs:+6:2: +6:2 - } - } - diff --git a/src/test/mir-opt/lower_array_len.array_bound.SimplifyLocals.diff b/src/test/mir-opt/lower_array_len.array_bound.SimplifyLocals.diff deleted file mode 100644 index 8312db6b37b3..000000000000 --- a/src/test/mir-opt/lower_array_len.array_bound.SimplifyLocals.diff +++ /dev/null @@ -1,70 +0,0 @@ -- // MIR for `array_bound` before SimplifyLocals -+ // MIR for `array_bound` after SimplifyLocals - - fn array_bound(_1: usize, _2: &[u8; N]) -> u8 { - debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:36: +0:41 - debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:+0:50: +0:55 - let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:+0:70: +0:72 - let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 -- let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -- let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -- let mut _11: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ let _6: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 -+ let mut _7: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ let mut _8: bool; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - - bb0: { - StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - _4 = _1; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:+1:20: +1:21 - _5 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - } - - bb1: { -- StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 -- _8 = _1; // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 -- _9 = const N; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -- _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb2; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 -+ _6 = _1; // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 -+ _7 = const N; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ _8 = Lt(_6, _7); // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb2; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - } - - bb2: { -- _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -- StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:+3:5: +3:6 -+ _0 = (*_2)[_6]; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:+3:5: +3:6 - goto -> bb4; // scope 0 at $DIR/lower_array_len.rs:+1:5: +5:6 - } - - bb3: { - _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:11 - goto -> bb4; // scope 0 at $DIR/lower_array_len.rs:+1:5: +5:6 - } - - bb4: { - StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+5:5: +5:6 - return; // scope 0 at $DIR/lower_array_len.rs:+6:2: +6:2 - } - } - diff --git a/src/test/mir-opt/lower_array_len.array_bound_mut.InstCombine.diff b/src/test/mir-opt/lower_array_len.array_bound_mut.InstCombine.diff deleted file mode 100644 index 401d4bac61e0..000000000000 --- a/src/test/mir-opt/lower_array_len.array_bound_mut.InstCombine.diff +++ /dev/null @@ -1,79 +0,0 @@ -- // MIR for `array_bound_mut` before InstCombine -+ // MIR for `array_bound_mut` after InstCombine - - fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 { - debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:40: +0:45 - debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:+0:54: +0:59 - let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:+0:78: +0:80 - let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 - let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - let _11: usize; // in scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16 - let mut _12: usize; // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 - let mut _13: bool; // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 - let mut _14: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - - bb0: { - StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - _4 = _1; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - _7 = &(*_2); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageLive(_14); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - _14 = _7; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - _6 = move _7 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:+1:20: +1:21 -- _5 = Len((*_14)); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ _5 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageDead(_14); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 - StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - } - - bb1: { - StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 - _8 = _1; // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 -- _9 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ _9 = const N; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb2; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - } - - bb2: { - _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:+3:5: +3:6 - goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:+1:5: +7:6 - } - - bb3: { - StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16 - _11 = const 0_usize; // scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16 -- _12 = Len((*_2)); // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 -+ _12 = const N; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 - _13 = Lt(_11, _12); // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 - assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, _11) -> bb4; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 - } - - bb4: { - (*_2)[_11] = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:22 - StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:+4:22: +4:23 - _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:+6:9: +6:11 - goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:+1:5: +7:6 - } - - bb5: { - StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+7:5: +7:6 - return; // scope 0 at $DIR/lower_array_len.rs:+8:2: +8:2 - } - } - diff --git a/src/test/mir-opt/lower_array_len.array_bound_mut.SimplifyLocals.diff b/src/test/mir-opt/lower_array_len.array_bound_mut.SimplifyLocals.diff deleted file mode 100644 index 4f241d7c9064..000000000000 --- a/src/test/mir-opt/lower_array_len.array_bound_mut.SimplifyLocals.diff +++ /dev/null @@ -1,93 +0,0 @@ -- // MIR for `array_bound_mut` before SimplifyLocals -+ // MIR for `array_bound_mut` after SimplifyLocals - - fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 { - debug index => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:40: +0:45 - debug slice => _2; // in scope 0 at $DIR/lower_array_len.rs:+0:54: +0:59 - let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len.rs:+0:78: +0:80 - let mut _3: bool; // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - let mut _4: usize; // in scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - let mut _5: usize; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- let mut _6: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- let mut _7: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- let _8: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 -- let mut _9: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -- let mut _10: bool; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -- let _11: usize; // in scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16 -- let mut _12: usize; // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 -- let mut _13: bool; // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 -- let mut _14: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -+ let _6: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 -+ let mut _7: usize; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ let mut _8: bool; // in scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ let _9: usize; // in scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16 -+ let mut _10: usize; // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 -+ let mut _11: bool; // in scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 - - bb0: { - StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - _4 = _1; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:13 - StorageLive(_5); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- StorageLive(_7); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- StorageLive(_14); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- StorageDead(_7); // scope 0 at $DIR/lower_array_len.rs:+1:20: +1:21 - _5 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- StorageDead(_14); // scope 0 at $DIR/lower_array_len.rs:+1:16: +1:27 -- StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - StorageDead(_5); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:26: +1:27 - switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len.rs:+1:8: +1:27 - } - - bb1: { -- StorageLive(_8); // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 -- _8 = _1; // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 -- _9 = const N; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -- _10 = Lt(_8, _9); // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, _8) -> bb2; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ StorageLive(_6); // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 -+ _6 = _1; // scope 0 at $DIR/lower_array_len.rs:+2:15: +2:20 -+ _7 = const N; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ _8 = Lt(_6, _7); // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb2; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 - } - - bb2: { -- _0 = (*_2)[_8]; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -- StorageDead(_8); // scope 0 at $DIR/lower_array_len.rs:+3:5: +3:6 -+ _0 = (*_2)[_6]; // scope 0 at $DIR/lower_array_len.rs:+2:9: +2:21 -+ StorageDead(_6); // scope 0 at $DIR/lower_array_len.rs:+3:5: +3:6 - goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:+1:5: +7:6 - } - - bb3: { -- StorageLive(_11); // scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16 -- _11 = const 0_usize; // scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16 -- _12 = const N; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 -- _13 = Lt(const 0_usize, _12); // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 -- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, const 0_usize) -> bb4; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 -+ StorageLive(_9); // scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16 -+ _9 = const 0_usize; // scope 0 at $DIR/lower_array_len.rs:+4:15: +4:16 -+ _10 = const N; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 -+ _11 = Lt(const 0_usize, _10); // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 -+ assert(move _11, "index out of bounds: the length is {} but the index is {}", move _10, const 0_usize) -> bb4; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:17 - } - - bb4: { -- (*_2)[_11] = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:22 -- StorageDead(_11); // scope 0 at $DIR/lower_array_len.rs:+4:22: +4:23 -+ (*_2)[_9] = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:+4:9: +4:22 -+ StorageDead(_9); // scope 0 at $DIR/lower_array_len.rs:+4:22: +4:23 - _0 = const 42_u8; // scope 0 at $DIR/lower_array_len.rs:+6:9: +6:11 - goto -> bb5; // scope 0 at $DIR/lower_array_len.rs:+1:5: +7:6 - } - - bb5: { - StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+7:5: +7:6 - return; // scope 0 at $DIR/lower_array_len.rs:+8:2: +8:2 - } - } - diff --git a/src/test/mir-opt/lower_array_len.array_len.InstCombine.diff b/src/test/mir-opt/lower_array_len.array_len.InstCombine.diff deleted file mode 100644 index 26f45be17be6..000000000000 --- a/src/test/mir-opt/lower_array_len.array_len.InstCombine.diff +++ /dev/null @@ -1,27 +0,0 @@ -- // MIR for `array_len` before InstCombine -+ // MIR for `array_len` after InstCombine - - fn array_len(_1: &[u8; N]) -> usize { - debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:34: +0:37 - let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:52: +0:57 - let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - - bb0: { - StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- _3 = &(*_1); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ _3 = _1; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - _4 = _3; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:7: +1:8 -- _0 = Len((*_4)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ _0 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:+1:13: +1:14 - return; // scope 0 at $DIR/lower_array_len.rs:+2:2: +2:2 - } - } - diff --git a/src/test/mir-opt/lower_array_len.array_len.SimplifyLocals.diff b/src/test/mir-opt/lower_array_len.array_len.SimplifyLocals.diff deleted file mode 100644 index 09d571d20a36..000000000000 --- a/src/test/mir-opt/lower_array_len.array_len.SimplifyLocals.diff +++ /dev/null @@ -1,22 +0,0 @@ -- // MIR for `array_len` before SimplifyLocals -+ // MIR for `array_len` after SimplifyLocals - - fn array_len(_1: &[u8; N]) -> usize { - debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:34: +0:37 - let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:52: +0:57 -- let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - - bb0: { -- StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:7: +1:8 - _0 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:+1:13: +1:14 - return; // scope 0 at $DIR/lower_array_len.rs:+2:2: +2:2 - } - } - diff --git a/src/test/mir-opt/lower_array_len.array_len_by_value.InstCombine.diff b/src/test/mir-opt/lower_array_len.array_len_by_value.InstCombine.diff deleted file mode 100644 index 843da758deb1..000000000000 --- a/src/test/mir-opt/lower_array_len.array_len_by_value.InstCombine.diff +++ /dev/null @@ -1,26 +0,0 @@ -- // MIR for `array_len_by_value` before InstCombine -+ // MIR for `array_len_by_value` after InstCombine - - fn array_len_by_value(_1: [u8; N]) -> usize { - debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:43: +0:46 - let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:60: +0:65 - let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - - bb0: { - StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - _3 = &_1; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - _4 = _3; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:7: +1:8 -- _0 = Len((*_4)); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -+ _0 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:+1:13: +1:14 - return; // scope 0 at $DIR/lower_array_len.rs:+2:2: +2:2 - } - } - diff --git a/src/test/mir-opt/lower_array_len.array_len_by_value.SimplifyLocals.diff b/src/test/mir-opt/lower_array_len.array_len_by_value.SimplifyLocals.diff deleted file mode 100644 index dc1c00b69c13..000000000000 --- a/src/test/mir-opt/lower_array_len.array_len_by_value.SimplifyLocals.diff +++ /dev/null @@ -1,22 +0,0 @@ -- // MIR for `array_len_by_value` before SimplifyLocals -+ // MIR for `array_len_by_value` after SimplifyLocals - - fn array_len_by_value(_1: [u8; N]) -> usize { - debug arr => _1; // in scope 0 at $DIR/lower_array_len.rs:+0:43: +0:46 - let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len.rs:+0:60: +0:65 -- let mut _2: &[u8]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- let mut _3: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- let mut _4: &[u8; N]; // in scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 - - bb0: { -- StorageLive(_2); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- StorageLive(_3); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- StorageLive(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- StorageDead(_3); // scope 0 at $DIR/lower_array_len.rs:+1:7: +1:8 - _0 = const N; // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- StorageDead(_4); // scope 0 at $DIR/lower_array_len.rs:+1:5: +1:14 -- StorageDead(_2); // scope 0 at $DIR/lower_array_len.rs:+1:13: +1:14 - return; // scope 0 at $DIR/lower_array_len.rs:+2:2: +2:2 - } - } - diff --git a/src/test/mir-opt/lower_array_len.rs b/src/test/mir-opt/lower_array_len.rs index fc12ee75fcfc..ea0224b21d72 100644 --- a/src/test/mir-opt/lower_array_len.rs +++ b/src/test/mir-opt/lower_array_len.rs @@ -1,8 +1,7 @@ -// compile-flags: -Z mir-opt-level=4 +// unit-test: NormalizeArrayLen +// compile-flags: -Zmir-enable-passes=+LowerSliceLenCalls // EMIT_MIR lower_array_len.array_bound.NormalizeArrayLen.diff -// EMIT_MIR lower_array_len.array_bound.SimplifyLocals.diff -// EMIT_MIR lower_array_len.array_bound.InstCombine.diff pub fn array_bound(index: usize, slice: &[u8; N]) -> u8 { if index < slice.len() { slice[index] @@ -12,8 +11,6 @@ pub fn array_bound(index: usize, slice: &[u8; N]) -> u8 { } // EMIT_MIR lower_array_len.array_bound_mut.NormalizeArrayLen.diff -// EMIT_MIR lower_array_len.array_bound_mut.SimplifyLocals.diff -// EMIT_MIR lower_array_len.array_bound_mut.InstCombine.diff pub fn array_bound_mut(index: usize, slice: &mut [u8; N]) -> u8 { if index < slice.len() { slice[index] @@ -25,15 +22,11 @@ pub fn array_bound_mut(index: usize, slice: &mut [u8; N]) -> u8 } // EMIT_MIR lower_array_len.array_len.NormalizeArrayLen.diff -// EMIT_MIR lower_array_len.array_len.SimplifyLocals.diff -// EMIT_MIR lower_array_len.array_len.InstCombine.diff pub fn array_len(arr: &[u8; N]) -> usize { arr.len() } // EMIT_MIR lower_array_len.array_len_by_value.NormalizeArrayLen.diff -// EMIT_MIR lower_array_len.array_len_by_value.SimplifyLocals.diff -// EMIT_MIR lower_array_len.array_len_by_value.InstCombine.diff pub fn array_len_by_value(arr: [u8; N]) -> usize { arr.len() } diff --git a/src/test/mir-opt/lower_array_len_e2e.array_bound.PreCodegen.after.mir b/src/test/mir-opt/lower_array_len_e2e.array_bound.PreCodegen.after.mir new file mode 100644 index 000000000000..2c6c93cb1d83 --- /dev/null +++ b/src/test/mir-opt/lower_array_len_e2e.array_bound.PreCodegen.after.mir @@ -0,0 +1,49 @@ +// MIR for `array_bound` after PreCodegen + +fn array_bound(_1: usize, _2: &[u8; N]) -> u8 { + debug index => _1; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:36: +0:41 + debug slice => _2; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:50: +0:55 + let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:70: +0:72 + let mut _3: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 + let mut _4: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13 + let mut _5: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 + let _6: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:15: +2:20 + let mut _7: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 + let mut _8: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 + + bb0: { + StorageLive(_3); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 + StorageLive(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13 + _4 = _1; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13 + StorageLive(_5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 + _5 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 + _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 + StorageDead(_5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27 + StorageDead(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27 + switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 + } + + bb1: { + StorageLive(_6); // scope 0 at $DIR/lower_array_len_e2e.rs:+2:15: +2:20 + _6 = _1; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:15: +2:20 + _7 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 + _8 = Lt(_6, _7); // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 + assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb2; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 + } + + bb2: { + _0 = (*_2)[_6]; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 + StorageDead(_6); // scope 0 at $DIR/lower_array_len_e2e.rs:+3:5: +3:6 + goto -> bb4; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +5:6 + } + + bb3: { + _0 = const 42_u8; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:11 + goto -> bb4; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +5:6 + } + + bb4: { + StorageDead(_3); // scope 0 at $DIR/lower_array_len_e2e.rs:+5:5: +5:6 + return; // scope 0 at $DIR/lower_array_len_e2e.rs:+6:2: +6:2 + } +} diff --git a/src/test/mir-opt/lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir b/src/test/mir-opt/lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir new file mode 100644 index 000000000000..aee3a8242cdd --- /dev/null +++ b/src/test/mir-opt/lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir @@ -0,0 +1,62 @@ +// MIR for `array_bound_mut` after PreCodegen + +fn array_bound_mut(_1: usize, _2: &mut [u8; N]) -> u8 { + debug index => _1; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:40: +0:45 + debug slice => _2; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:54: +0:59 + let mut _0: u8; // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:78: +0:80 + let mut _3: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 + let mut _4: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13 + let mut _5: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 + let _6: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:15: +2:20 + let mut _7: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 + let mut _8: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 + let _9: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16 + let mut _10: usize; // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17 + let mut _11: bool; // in scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17 + + bb0: { + StorageLive(_3); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 + StorageLive(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13 + _4 = _1; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:13 + StorageLive(_5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 + _5 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:16: +1:27 + _3 = Lt(move _4, move _5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 + StorageDead(_5); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27 + StorageDead(_4); // scope 0 at $DIR/lower_array_len_e2e.rs:+1:26: +1:27 + switchInt(move _3) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:8: +1:27 + } + + bb1: { + StorageLive(_6); // scope 0 at $DIR/lower_array_len_e2e.rs:+2:15: +2:20 + _6 = _1; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:15: +2:20 + _7 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 + _8 = Lt(_6, _7); // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 + assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb2; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 + } + + bb2: { + _0 = (*_2)[_6]; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:9: +2:21 + StorageDead(_6); // scope 0 at $DIR/lower_array_len_e2e.rs:+3:5: +3:6 + goto -> bb5; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +7:6 + } + + bb3: { + StorageLive(_9); // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16 + _9 = const 0_usize; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:15: +4:16 + _10 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17 + _11 = Lt(const 0_usize, _10); // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17 + assert(move _11, "index out of bounds: the length is {} but the index is {}", move _10, const 0_usize) -> bb4; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:17 + } + + bb4: { + (*_2)[_9] = const 42_u8; // scope 0 at $DIR/lower_array_len_e2e.rs:+4:9: +4:22 + StorageDead(_9); // scope 0 at $DIR/lower_array_len_e2e.rs:+4:22: +4:23 + _0 = const 42_u8; // scope 0 at $DIR/lower_array_len_e2e.rs:+6:9: +6:11 + goto -> bb5; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +7:6 + } + + bb5: { + StorageDead(_3); // scope 0 at $DIR/lower_array_len_e2e.rs:+7:5: +7:6 + return; // scope 0 at $DIR/lower_array_len_e2e.rs:+8:2: +8:2 + } +} diff --git a/src/test/mir-opt/lower_array_len_e2e.array_len.PreCodegen.after.mir b/src/test/mir-opt/lower_array_len_e2e.array_len.PreCodegen.after.mir new file mode 100644 index 000000000000..4b19f6795588 --- /dev/null +++ b/src/test/mir-opt/lower_array_len_e2e.array_len.PreCodegen.after.mir @@ -0,0 +1,11 @@ +// MIR for `array_len` after PreCodegen + +fn array_len(_1: &[u8; N]) -> usize { + debug arr => _1; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:34: +0:37 + let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:52: +0:57 + + bb0: { + _0 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +1:14 + return; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:2: +2:2 + } +} diff --git a/src/test/mir-opt/lower_array_len_e2e.array_len_by_value.PreCodegen.after.mir b/src/test/mir-opt/lower_array_len_e2e.array_len_by_value.PreCodegen.after.mir new file mode 100644 index 000000000000..4dc0ba9a268e --- /dev/null +++ b/src/test/mir-opt/lower_array_len_e2e.array_len_by_value.PreCodegen.after.mir @@ -0,0 +1,11 @@ +// MIR for `array_len_by_value` after PreCodegen + +fn array_len_by_value(_1: [u8; N]) -> usize { + debug arr => _1; // in scope 0 at $DIR/lower_array_len_e2e.rs:+0:43: +0:46 + let mut _0: usize; // return place in scope 0 at $DIR/lower_array_len_e2e.rs:+0:60: +0:65 + + bb0: { + _0 = const N; // scope 0 at $DIR/lower_array_len_e2e.rs:+1:5: +1:14 + return; // scope 0 at $DIR/lower_array_len_e2e.rs:+2:2: +2:2 + } +} diff --git a/src/test/mir-opt/lower_array_len_e2e.rs b/src/test/mir-opt/lower_array_len_e2e.rs new file mode 100644 index 000000000000..49b35d509f02 --- /dev/null +++ b/src/test/mir-opt/lower_array_len_e2e.rs @@ -0,0 +1,39 @@ +// compile-flags: -Z mir-opt-level=4 + +// EMIT_MIR lower_array_len_e2e.array_bound.PreCodegen.after.mir +pub fn array_bound(index: usize, slice: &[u8; N]) -> u8 { + if index < slice.len() { + slice[index] + } else { + 42 + } +} + +// EMIT_MIR lower_array_len_e2e.array_bound_mut.PreCodegen.after.mir +pub fn array_bound_mut(index: usize, slice: &mut [u8; N]) -> u8 { + if index < slice.len() { + slice[index] + } else { + slice[0] = 42; + + 42 + } +} + +// EMIT_MIR lower_array_len_e2e.array_len.PreCodegen.after.mir +pub fn array_len(arr: &[u8; N]) -> usize { + arr.len() +} + +// EMIT_MIR lower_array_len_e2e.array_len_by_value.PreCodegen.after.mir +pub fn array_len_by_value(arr: [u8; N]) -> usize { + arr.len() +} + +fn main() { + let _ = array_bound(3, &[0, 1, 2, 3]); + let mut tmp = [0, 1, 2, 3, 4]; + let _ = array_bound_mut(3, &mut [0, 1, 2, 3]); + let _ = array_len(&[0]); + let _ = array_len_by_value([0, 2]); +} diff --git a/src/test/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff index 5c635e2220ed..3389db733b99 100644 --- a/src/test/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff @@ -7,7 +7,7 @@ bb0: { - _0 = std::intrinsics::min_align_of::() -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:42 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:19:5: 19:40 +- // + span: $DIR/lower_intrinsics.rs:21:5: 21:40 - // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::min_align_of::}, val: Value() } + _0 = AlignOf(T); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:42 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:42 diff --git a/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff index 8a80de32f3ae..f92ff9faf979 100644 --- a/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff @@ -31,7 +31,7 @@ _3 = &(*_4); // scope 0 at $DIR/lower_intrinsics.rs:+1:42: +1:44 - _2 = discriminant_value::(move _3) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:74:5: 74:41 +- // + span: $DIR/lower_intrinsics.rs:49:5: 49:41 - // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r T) -> ::Discriminant {discriminant_value::}, val: Value() } + _2 = discriminant((*_3)); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45 @@ -46,13 +46,13 @@ StorageLive(_7); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44 _19 = const discriminant::::promoted[2]; // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44 // mir::Constant - // + span: $DIR/lower_intrinsics.rs:75:42: 75:44 + // + span: $DIR/lower_intrinsics.rs:50:42: 50:44 // + literal: Const { ty: &i32, val: Unevaluated(discriminant, [T], Some(promoted[2])) } _7 = &(*_19); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44 _6 = &(*_7); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44 - _5 = discriminant_value::(move _6) -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:75:5: 75:41 +- // + span: $DIR/lower_intrinsics.rs:50:5: 50:41 - // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r i32) -> ::Discriminant {discriminant_value::}, val: Value() } + _5 = discriminant((*_6)); // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45 + goto -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45 @@ -67,13 +67,13 @@ StorageLive(_11); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45 _18 = const discriminant::::promoted[1]; // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45 // mir::Constant - // + span: $DIR/lower_intrinsics.rs:76:42: 76:45 + // + span: $DIR/lower_intrinsics.rs:51:42: 51:45 // + literal: Const { ty: &(), val: Unevaluated(discriminant, [T], Some(promoted[1])) } _11 = &(*_18); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45 _10 = &(*_11); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45 - _9 = discriminant_value::<()>(move _10) -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:76:5: 76:41 +- // + span: $DIR/lower_intrinsics.rs:51:5: 51:41 - // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r ()) -> <() as DiscriminantKind>::Discriminant {discriminant_value::<()>}, val: Value() } + _9 = discriminant((*_10)); // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46 + goto -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46 @@ -88,13 +88,13 @@ StorageLive(_15); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47 _17 = const discriminant::::promoted[0]; // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47 // mir::Constant - // + span: $DIR/lower_intrinsics.rs:77:42: 77:47 + // + span: $DIR/lower_intrinsics.rs:52:42: 52:47 // + literal: Const { ty: &E, val: Unevaluated(discriminant, [T], Some(promoted[0])) } _15 = &(*_17); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47 _14 = &(*_15); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47 - _13 = discriminant_value::(move _14) -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:77:5: 77:41 +- // + span: $DIR/lower_intrinsics.rs:52:5: 52:41 - // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r E) -> ::Discriminant {discriminant_value::}, val: Value() } + _13 = discriminant((*_14)); // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48 + goto -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48 @@ -105,11 +105,15 @@ StorageDead(_15); // scope 0 at $DIR/lower_intrinsics.rs:+4:48: +4:49 StorageDead(_13); // scope 0 at $DIR/lower_intrinsics.rs:+4:48: +4:49 _0 = const (); // scope 0 at $DIR/lower_intrinsics.rs:+0:30: +5:2 - drop(_1) -> bb5; // scope 0 at $DIR/lower_intrinsics.rs:+5:1: +5:2 + drop(_1) -> [return: bb5, unwind: bb6]; // scope 0 at $DIR/lower_intrinsics.rs:+5:1: +5:2 } bb5: { return; // scope 0 at $DIR/lower_intrinsics.rs:+5:2: +5:2 } + + bb6 (cleanup): { + resume; // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +5:2 + } } diff --git a/src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff index e6a2f6512f55..4cbbc02c9433 100644 --- a/src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff @@ -11,7 +11,7 @@ _2 = move _1; // scope 0 at $DIR/lower_intrinsics.rs:+1:30: +1:31 - _0 = std::intrinsics::forget::(move _2) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:32 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:24:5: 24:29 +- // + span: $DIR/lower_intrinsics.rs:26:5: 26:29 - // + literal: Const { ty: extern "rust-intrinsic" fn(T) {std::intrinsics::forget::}, val: Value() } + _0 = const (); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:32 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:32 diff --git a/src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff index 1ab2f2a0a046..d8cd5f59a353 100644 --- a/src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff @@ -13,7 +13,7 @@ StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+2:9: +2:18 _1 = std::intrinsics::size_of::; // scope 0 at $DIR/lower_intrinsics.rs:+2:21: +2:51 // mir::Constant - // + span: $DIR/lower_intrinsics.rs:62:21: 62:51 + // + span: $DIR/lower_intrinsics.rs:37:21: 37:51 // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::}, val: Value() } StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:+3:5: +3:14 _2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:+3:5: +3:14 diff --git a/src/test/mir-opt/lower_intrinsics.rs b/src/test/mir-opt/lower_intrinsics.rs index eab51b65f1a1..195543d42bb5 100644 --- a/src/test/mir-opt/lower_intrinsics.rs +++ b/src/test/mir-opt/lower_intrinsics.rs @@ -1,4 +1,6 @@ -// compile-flags: -Cpanic=abort +// unit-test: LowerIntrinsics +// ignore-wasm32 compiled with panic=abort by default + #![feature(core_intrinsics)] #![crate_type = "lib"] @@ -29,33 +31,6 @@ pub fn unreachable() -> ! { unsafe { core::intrinsics::unreachable() }; } -// EMIT_MIR lower_intrinsics.f_unit.PreCodegen.before.mir -pub fn f_unit() { - f_dispatch(()); -} - - -// EMIT_MIR lower_intrinsics.f_u64.PreCodegen.before.mir -pub fn f_u64() { - f_dispatch(0u64); -} - -#[inline(always)] -pub fn f_dispatch(t: T) { - if std::mem::size_of::() == 0 { - f_zst(t); - } else { - f_non_zst(t); - } -} - -#[inline(never)] -pub fn f_zst(_t: T) { -} - -#[inline(never)] -pub fn f_non_zst(_t: T) {} - // EMIT_MIR lower_intrinsics.non_const.LowerIntrinsics.diff pub fn non_const() -> usize { // Check that lowering works with non-const operand as a func. diff --git a/src/test/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff index 11b27976b551..cf0ab73a5d4b 100644 --- a/src/test/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff @@ -7,7 +7,7 @@ bb0: { - _0 = std::intrinsics::size_of::() -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:37 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:14:5: 14:35 +- // + span: $DIR/lower_intrinsics.rs:16:5: 16:35 - // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::}, val: Value() } + _0 = SizeOf(T); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:37 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:37 diff --git a/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff index ac077e85b04f..6f17d44516de 100644 --- a/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff @@ -14,7 +14,7 @@ StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45 - _3 = std::intrinsics::unreachable(); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:29:14: 29:43 +- // + span: $DIR/lower_intrinsics.rs:31:14: 31:43 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn() -> ! {std::intrinsics::unreachable}, val: Value() } + unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45 } diff --git a/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff index e0a5416b22b5..22ef75fd8046 100644 --- a/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff @@ -32,7 +32,7 @@ _5 = _2; // scope 0 at $DIR/lower_intrinsics.rs:+1:48: +1:49 - _3 = wrapping_add::(move _4, move _5) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:50 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:7:14: 7:44 +- // + span: $DIR/lower_intrinsics.rs:9:14: 9:44 - // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_add::}, val: Value() } + _3 = Add(move _4, move _5); // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:50 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:50 @@ -48,7 +48,7 @@ _8 = _2; // scope 1 at $DIR/lower_intrinsics.rs:+2:48: +2:49 - _6 = wrapping_sub::(move _7, move _8) -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:50 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:8:14: 8:44 +- // + span: $DIR/lower_intrinsics.rs:10:14: 10:44 - // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_sub::}, val: Value() } + _6 = Sub(move _7, move _8); // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:50 + goto -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:50 @@ -64,7 +64,7 @@ _11 = _2; // scope 2 at $DIR/lower_intrinsics.rs:+3:48: +3:49 - _9 = wrapping_mul::(move _10, move _11) -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:50 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:9:14: 9:44 +- // + span: $DIR/lower_intrinsics.rs:11:14: 11:44 - // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_mul::}, val: Value() } + _9 = Mul(move _10, move _11); // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:50 + goto -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:50 diff --git a/src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir b/src/test/mir-opt/lower_intrinsics_e2e.f_u64.PreCodegen.after.mir similarity index 68% rename from src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir rename to src/test/mir-opt/lower_intrinsics_e2e.f_u64.PreCodegen.after.mir index 2a9a099a38d9..8e185323e1a8 100644 --- a/src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir +++ b/src/test/mir-opt/lower_intrinsics_e2e.f_u64.PreCodegen.after.mir @@ -1,32 +1,32 @@ -// MIR for `f_u64` before PreCodegen +// MIR for `f_u64` after PreCodegen fn f_u64() -> () { - let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:16: +0:16 - let mut _1: u64; // in scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:21 - scope 1 (inlined f_dispatch::) { // at $DIR/lower_intrinsics.rs:40:5: 40:21 - debug t => _1; // in scope 1 at $DIR/lower_intrinsics.rs:44:22: 44:23 - let _2: (); // in scope 1 at $DIR/lower_intrinsics.rs:48:9: 48:21 - let mut _3: u64; // in scope 1 at $DIR/lower_intrinsics.rs:48:19: 48:20 - scope 2 (inlined std::mem::size_of::) { // at $DIR/lower_intrinsics.rs:45:8: 45:32 + let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics_e2e.rs:+0:16: +0:16 + let mut _1: u64; // in scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:5: +1:21 + scope 1 (inlined f_dispatch::) { // at $DIR/lower_intrinsics_e2e.rs:15:5: 15:21 + debug t => _1; // in scope 1 at $DIR/lower_intrinsics_e2e.rs:19:22: 19:23 + let _2: (); // in scope 1 at $DIR/lower_intrinsics_e2e.rs:23:9: 23:21 + let mut _3: u64; // in scope 1 at $DIR/lower_intrinsics_e2e.rs:23:19: 23:20 + scope 2 (inlined std::mem::size_of::) { // at $DIR/lower_intrinsics_e2e.rs:20:8: 20:32 } } bb0: { - StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:21 - _1 = const 0_u64; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:21 - StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:48:9: 48:21 - StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:48:19: 48:20 - _3 = move _1; // scope 1 at $DIR/lower_intrinsics.rs:48:19: 48:20 - _2 = f_non_zst::(move _3) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:48:9: 48:21 + StorageLive(_1); // scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:5: +1:21 + _1 = const 0_u64; // scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:5: +1:21 + StorageLive(_2); // scope 1 at $DIR/lower_intrinsics_e2e.rs:23:9: 23:21 + StorageLive(_3); // scope 1 at $DIR/lower_intrinsics_e2e.rs:23:19: 23:20 + _3 = move _1; // scope 1 at $DIR/lower_intrinsics_e2e.rs:23:19: 23:20 + _2 = f_non_zst::(move _3) -> bb1; // scope 1 at $DIR/lower_intrinsics_e2e.rs:23:9: 23:21 // mir::Constant - // + span: $DIR/lower_intrinsics.rs:48:9: 48:18 + // + span: $DIR/lower_intrinsics_e2e.rs:23:9: 23:18 // + literal: Const { ty: fn(u64) {f_non_zst::}, val: Value() } } bb1: { - StorageDead(_3); // scope 1 at $DIR/lower_intrinsics.rs:48:20: 48:21 - StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:48:21: 48:22 - StorageDead(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:21 - return; // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2 + StorageDead(_3); // scope 1 at $DIR/lower_intrinsics_e2e.rs:23:20: 23:21 + StorageDead(_2); // scope 1 at $DIR/lower_intrinsics_e2e.rs:23:21: 23:22 + StorageDead(_1); // scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:5: +1:21 + return; // scope 0 at $DIR/lower_intrinsics_e2e.rs:+2:2: +2:2 } } diff --git a/src/test/mir-opt/lower_intrinsics.f_unit.PreCodegen.before.mir b/src/test/mir-opt/lower_intrinsics_e2e.f_unit.PreCodegen.after.mir similarity index 68% rename from src/test/mir-opt/lower_intrinsics.f_unit.PreCodegen.before.mir rename to src/test/mir-opt/lower_intrinsics_e2e.f_unit.PreCodegen.after.mir index 5783822f6b54..a5b396ca0bc7 100644 --- a/src/test/mir-opt/lower_intrinsics.f_unit.PreCodegen.before.mir +++ b/src/test/mir-opt/lower_intrinsics_e2e.f_unit.PreCodegen.after.mir @@ -1,30 +1,30 @@ -// MIR for `f_unit` before PreCodegen +// MIR for `f_unit` after PreCodegen fn f_unit() -> () { - let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:17: +0:17 - let mut _1: (); // in scope 0 at $DIR/lower_intrinsics.rs:+1:16: +1:18 - scope 1 (inlined f_dispatch::<()>) { // at $DIR/lower_intrinsics.rs:34:5: 34:19 - debug t => _1; // in scope 1 at $DIR/lower_intrinsics.rs:44:22: 44:23 - let _2: (); // in scope 1 at $DIR/lower_intrinsics.rs:46:9: 46:17 - let mut _3: (); // in scope 1 at $DIR/lower_intrinsics.rs:46:15: 46:16 - scope 2 (inlined std::mem::size_of::<()>) { // at $DIR/lower_intrinsics.rs:45:8: 45:32 + let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics_e2e.rs:+0:17: +0:17 + let mut _1: (); // in scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:16: +1:18 + scope 1 (inlined f_dispatch::<()>) { // at $DIR/lower_intrinsics_e2e.rs:9:5: 9:19 + debug t => _1; // in scope 1 at $DIR/lower_intrinsics_e2e.rs:19:22: 19:23 + let _2: (); // in scope 1 at $DIR/lower_intrinsics_e2e.rs:21:9: 21:17 + let mut _3: (); // in scope 1 at $DIR/lower_intrinsics_e2e.rs:21:15: 21:16 + scope 2 (inlined std::mem::size_of::<()>) { // at $DIR/lower_intrinsics_e2e.rs:20:8: 20:32 } } bb0: { - StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:16: +1:18 - StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:46:9: 46:17 - StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:46:15: 46:16 - _2 = f_zst::<()>(move _3) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:46:9: 46:17 + StorageLive(_1); // scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:16: +1:18 + StorageLive(_2); // scope 1 at $DIR/lower_intrinsics_e2e.rs:21:9: 21:17 + StorageLive(_3); // scope 1 at $DIR/lower_intrinsics_e2e.rs:21:15: 21:16 + _2 = f_zst::<()>(move _3) -> bb1; // scope 1 at $DIR/lower_intrinsics_e2e.rs:21:9: 21:17 // mir::Constant - // + span: $DIR/lower_intrinsics.rs:46:9: 46:14 + // + span: $DIR/lower_intrinsics_e2e.rs:21:9: 21:14 // + literal: Const { ty: fn(()) {f_zst::<()>}, val: Value() } } bb1: { - StorageDead(_3); // scope 1 at $DIR/lower_intrinsics.rs:46:16: 46:17 - StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:46:17: 46:18 - StorageDead(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:18: +1:19 - return; // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2 + StorageDead(_3); // scope 1 at $DIR/lower_intrinsics_e2e.rs:21:16: 21:17 + StorageDead(_2); // scope 1 at $DIR/lower_intrinsics_e2e.rs:21:17: 21:18 + StorageDead(_1); // scope 0 at $DIR/lower_intrinsics_e2e.rs:+1:18: +1:19 + return; // scope 0 at $DIR/lower_intrinsics_e2e.rs:+2:2: +2:2 } } diff --git a/src/test/mir-opt/lower_intrinsics_e2e.rs b/src/test/mir-opt/lower_intrinsics_e2e.rs new file mode 100644 index 000000000000..872ef59b0818 --- /dev/null +++ b/src/test/mir-opt/lower_intrinsics_e2e.rs @@ -0,0 +1,32 @@ +// Checks that we do not have any branches in the MIR for the two tested functions. + +// compile-flags: -Cpanic=abort +#![feature(core_intrinsics)] +#![crate_type = "lib"] + +// EMIT_MIR lower_intrinsics_e2e.f_unit.PreCodegen.after.mir +pub fn f_unit() { + f_dispatch(()); +} + + +// EMIT_MIR lower_intrinsics_e2e.f_u64.PreCodegen.after.mir +pub fn f_u64() { + f_dispatch(0u64); +} + +#[inline(always)] +pub fn f_dispatch(t: T) { + if std::mem::size_of::() == 0 { + f_zst(t); + } else { + f_non_zst(t); + } +} + +#[inline(never)] +pub fn f_zst(_t: T) { +} + +#[inline(never)] +pub fn f_non_zst(_t: T) {} diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff index 2005c10efa93..f9eeb1ea5b96 100644 --- a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff +++ b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff @@ -41,7 +41,7 @@ - _3 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+16:13: +16:22 - _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+17:13: +17:22 - _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+18:13: +18:21 -- nop; // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15 +- Deinit(_6); // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15 - goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15 - } - @@ -54,7 +54,7 @@ + _3 = Eq(_11, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:+9:13: +9:21 _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+10:13: +10:22 _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+11:13: +11:21 -- nop; // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15 + Deinit(_6); // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15 - goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15 - } - diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff index 2005c10efa93..f9eeb1ea5b96 100644 --- a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff +++ b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff @@ -41,7 +41,7 @@ - _3 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+16:13: +16:22 - _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+17:13: +17:22 - _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+18:13: +18:21 -- nop; // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15 +- Deinit(_6); // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15 - goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15 - } - @@ -54,7 +54,7 @@ + _3 = Eq(_11, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:+9:13: +9:21 _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+10:13: +10:22 _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+11:13: +11:21 -- nop; // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15 + Deinit(_6); // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15 - goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15 - } - diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff index b7862e5678f2..0b40b3be8bdd 100644 --- a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff +++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff @@ -4,26 +4,51 @@ fn foo(_1: Option<()>) -> () { debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:11 let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:25 - let mut _2: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:22: +1:26 -+ let mut _3: isize; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _3: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:22: +1:26 ++ let mut _4: isize; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL bb0: { - _2 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+1:17: +1:20 -- switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -- } -- -- bb1: { + StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _3 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+1:17: +1:20 +- switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL ++ StorageLive(_4); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL ++ _4 = move _3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL ++ _2 = Eq(_4, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL ++ StorageDead(_4); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL ++ switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + } + + bb1: { +- _2 = const false; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - goto -> bb3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - - bb2: { +- _2 = const true; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - goto -> bb3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - - bb3: { -+ StorageLive(_3); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -+ _3 = move _2; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -+ StorageDead(_3); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL +- switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL +- } +- +- bb4: { + Deinit(_0); // scope 0 at $DIR/matches_reduce_branches.rs:+2:9: +2:11 +- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6 ++ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6 + } + +- bb5: { ++ bb2: { + _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:+3:6: +3:6 +- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6 ++ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6 + } + +- bb6: { ++ bb3: { + StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+3:5: +3:6 return; // scope 0 at $DIR/matches_reduce_branches.rs:+4:2: +4:2 } } diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff index b7862e5678f2..0b40b3be8bdd 100644 --- a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff +++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff @@ -4,26 +4,51 @@ fn foo(_1: Option<()>) -> () { debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:11 let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:25 - let mut _2: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:22: +1:26 -+ let mut _3: isize; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _3: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:22: +1:26 ++ let mut _4: isize; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL bb0: { - _2 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+1:17: +1:20 -- switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -- } -- -- bb1: { + StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _3 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+1:17: +1:20 +- switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL ++ StorageLive(_4); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL ++ _4 = move _3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL ++ _2 = Eq(_4, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL ++ StorageDead(_4); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL ++ switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + } + + bb1: { +- _2 = const false; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - goto -> bb3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - - bb2: { +- _2 = const true; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - goto -> bb3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - - bb3: { -+ StorageLive(_3); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -+ _3 = move _2; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -+ StorageDead(_3); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL +- switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL +- } +- +- bb4: { + Deinit(_0); // scope 0 at $DIR/matches_reduce_branches.rs:+2:9: +2:11 +- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6 ++ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6 + } + +- bb5: { ++ bb2: { + _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:+3:6: +3:6 +- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6 ++ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6 + } + +- bb6: { ++ bb3: { + StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+3:5: +3:6 return; // scope 0 at $DIR/matches_reduce_branches.rs:+4:2: +4:2 } } diff --git a/src/test/mir-opt/matches_reduce_branches.foo.PreCodegen.before.32bit.mir b/src/test/mir-opt/matches_reduce_branches.foo.PreCodegen.before.32bit.mir deleted file mode 100644 index a36ec8de4a39..000000000000 --- a/src/test/mir-opt/matches_reduce_branches.foo.PreCodegen.before.32bit.mir +++ /dev/null @@ -1,10 +0,0 @@ -// MIR for `foo` before PreCodegen - -fn foo(_1: Option<()>) -> () { - debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:11 - let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:25 - - bb0: { - return; // scope 0 at $DIR/matches_reduce_branches.rs:+4:2: +4:2 - } -} diff --git a/src/test/mir-opt/matches_reduce_branches.foo.PreCodegen.before.64bit.mir b/src/test/mir-opt/matches_reduce_branches.foo.PreCodegen.before.64bit.mir deleted file mode 100644 index a36ec8de4a39..000000000000 --- a/src/test/mir-opt/matches_reduce_branches.foo.PreCodegen.before.64bit.mir +++ /dev/null @@ -1,10 +0,0 @@ -// MIR for `foo` before PreCodegen - -fn foo(_1: Option<()>) -> () { - debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:11 - let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:25 - - bb0: { - return; // scope 0 at $DIR/matches_reduce_branches.rs:+4:2: +4:2 - } -} diff --git a/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff index 672c6b34e94b..b8c7722cd371 100644 --- a/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff +++ b/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff @@ -4,36 +4,107 @@ fn match_nested_if() -> bool { let mut _0: bool; // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:29 let _1: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:12 - let mut _2: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 -+ let mut _3: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 + let mut _2: (); // in scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23 + let mut _3: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10 + let mut _4: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76 + let mut _5: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52 + let mut _6: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 ++ let mut _7: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 ++ let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52 ++ let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76 ++ let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10 scope 1 { debug val => _1; // in scope 1 at $DIR/matches_reduce_branches.rs:+1:9: +1:12 } bb0: { StorageLive(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:12 - StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 - _2 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 -- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 + StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23 + Deinit(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23 + StorageLive(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10 + StorageLive(_4); // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76 + StorageLive(_5); // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52 + StorageLive(_6); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 + _6 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 +- switchInt(move _6) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 - } - - bb1: { -+ StorageLive(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 -+ _3 = move _2; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 - StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+2:51: +2:52 -- _1 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17 -- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17 +- _5 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:31: +2:35 +- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52 - } - - bb2: { -- StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+2:51: +2:52 -- _1 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19 -- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19 +- _5 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+2:45: +2:50 +- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52 - } - - bb3: { -+ _1 = Ne(_3, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19 -+ StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 ++ StorageLive(_7); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 ++ _7 = move _6; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 ++ _5 = Ne(_7, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+2:45: +2:50 ++ StorageDead(_7); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 + StorageDead(_6); // scope 0 at $DIR/matches_reduce_branches.rs:+2:51: +2:52 +- switchInt(move _5) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52 +- } +- +- bb4: { +- _4 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:55: +2:59 +- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76 +- } +- +- bb5: { +- _4 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+2:69: +2:74 +- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76 +- } +- +- bb6: { ++ StorageLive(_8); // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52 ++ _8 = move _5; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52 ++ _4 = Ne(_8, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+2:69: +2:74 ++ StorageDead(_8); // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52 + StorageDead(_5); // scope 0 at $DIR/matches_reduce_branches.rs:+2:75: +2:76 +- switchInt(move _4) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76 +- } +- +- bb7: { +- _3 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+3:13: +3:17 +- goto -> bb9; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10 +- } +- +- bb8: { +- _3 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+5:13: +5:18 +- goto -> bb9; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10 +- } +- +- bb9: { +- switchInt(move _3) -> [false: bb11, otherwise: bb10]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10 +- } +- +- bb10: { ++ StorageLive(_9); // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76 ++ _9 = move _4; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76 ++ _3 = Ne(_9, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+5:13: +5:18 ++ StorageDead(_9); // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76 ++ StorageLive(_10); // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10 ++ _10 = move _3; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10 + StorageDead(_4); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10 + StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10 +- _1 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17 +- goto -> bb12; // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17 +- } +- +- bb11: { +- StorageDead(_4); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10 +- StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10 +- _1 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19 +- goto -> bb12; // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19 +- } +- +- bb12: { ++ _1 = Ne(_10, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19 ++ StorageDead(_10); // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10 + StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+11:6: +11:7 _0 = _1; // scope 1 at $DIR/matches_reduce_branches.rs:+12:5: +12:8 StorageDead(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+13:1: +13:2 return; // scope 0 at $DIR/matches_reduce_branches.rs:+13:2: +13:2 diff --git a/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff index 672c6b34e94b..b8c7722cd371 100644 --- a/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff +++ b/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff @@ -4,36 +4,107 @@ fn match_nested_if() -> bool { let mut _0: bool; // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:29 let _1: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:12 - let mut _2: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 -+ let mut _3: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 + let mut _2: (); // in scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23 + let mut _3: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10 + let mut _4: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76 + let mut _5: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52 + let mut _6: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 ++ let mut _7: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 ++ let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52 ++ let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76 ++ let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10 scope 1 { debug val => _1; // in scope 1 at $DIR/matches_reduce_branches.rs:+1:9: +1:12 } bb0: { StorageLive(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:12 - StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 - _2 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 -- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 + StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23 + Deinit(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23 + StorageLive(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10 + StorageLive(_4); // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76 + StorageLive(_5); // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52 + StorageLive(_6); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 + _6 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 +- switchInt(move _6) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 - } - - bb1: { -+ StorageLive(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 -+ _3 = move _2; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 - StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+2:51: +2:52 -- _1 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17 -- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17 +- _5 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:31: +2:35 +- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52 - } - - bb2: { -- StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+2:51: +2:52 -- _1 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19 -- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19 +- _5 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+2:45: +2:50 +- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52 - } - - bb3: { -+ _1 = Ne(_3, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19 -+ StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 ++ StorageLive(_7); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 ++ _7 = move _6; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 ++ _5 = Ne(_7, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+2:45: +2:50 ++ StorageDead(_7); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 + StorageDead(_6); // scope 0 at $DIR/matches_reduce_branches.rs:+2:51: +2:52 +- switchInt(move _5) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52 +- } +- +- bb4: { +- _4 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:55: +2:59 +- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76 +- } +- +- bb5: { +- _4 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+2:69: +2:74 +- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76 +- } +- +- bb6: { ++ StorageLive(_8); // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52 ++ _8 = move _5; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52 ++ _4 = Ne(_8, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+2:69: +2:74 ++ StorageDead(_8); // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52 + StorageDead(_5); // scope 0 at $DIR/matches_reduce_branches.rs:+2:75: +2:76 +- switchInt(move _4) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76 +- } +- +- bb7: { +- _3 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+3:13: +3:17 +- goto -> bb9; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10 +- } +- +- bb8: { +- _3 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+5:13: +5:18 +- goto -> bb9; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10 +- } +- +- bb9: { +- switchInt(move _3) -> [false: bb11, otherwise: bb10]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10 +- } +- +- bb10: { ++ StorageLive(_9); // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76 ++ _9 = move _4; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76 ++ _3 = Ne(_9, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+5:13: +5:18 ++ StorageDead(_9); // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76 ++ StorageLive(_10); // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10 ++ _10 = move _3; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10 + StorageDead(_4); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10 + StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10 +- _1 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17 +- goto -> bb12; // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17 +- } +- +- bb11: { +- StorageDead(_4); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10 +- StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10 +- _1 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19 +- goto -> bb12; // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19 +- } +- +- bb12: { ++ _1 = Ne(_10, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19 ++ StorageDead(_10); // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10 + StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+11:6: +11:7 _0 = _1; // scope 1 at $DIR/matches_reduce_branches.rs:+12:5: +12:8 StorageDead(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+13:1: +13:2 return; // scope 0 at $DIR/matches_reduce_branches.rs:+13:2: +13:2 diff --git a/src/test/mir-opt/matches_reduce_branches.rs b/src/test/mir-opt/matches_reduce_branches.rs index 51be3884d48d..c122b4c69d15 100644 --- a/src/test/mir-opt/matches_reduce_branches.rs +++ b/src/test/mir-opt/matches_reduce_branches.rs @@ -1,6 +1,7 @@ +// unit-test: MatchBranchSimplification + // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR matches_reduce_branches.foo.MatchBranchSimplification.diff -// EMIT_MIR matches_reduce_branches.foo.PreCodegen.before.mir // EMIT_MIR matches_reduce_branches.bar.MatchBranchSimplification.diff // EMIT_MIR matches_reduce_branches.match_nested_if.MatchBranchSimplification.diff diff --git a/src/test/mir-opt/matches_u8.rs b/src/test/mir-opt/matches_u8.rs index 78373be48b68..2c748b02a8b7 100644 --- a/src/test/mir-opt/matches_u8.rs +++ b/src/test/mir-opt/matches_u8.rs @@ -1,3 +1,5 @@ +// unit-test: MatchBranchSimplification + // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR matches_u8.exhaustive_match.MatchBranchSimplification.diff // EMIT_MIR matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff diff --git a/src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff b/src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff index b8c554d3ea6b..f25b3ce724be 100644 --- a/src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff +++ b/src/test/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff @@ -15,7 +15,7 @@ scope 1 { debug residual => _6; // in scope 1 at $DIR/separate_const_switch.rs:+1:9: +1:10 scope 2 { - scope 8 (inlined #[track_caller] as FromResidual>>::from_residual) { // at $DIR/separate_const_switch.rs:29:8: 29:10 + scope 8 (inlined #[track_caller] as FromResidual>>::from_residual) { // at $DIR/separate_const_switch.rs:25:8: 25:10 debug residual => _8; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL let _16: i32; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL let mut _17: i32; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL @@ -34,7 +34,7 @@ scope 4 { } } - scope 5 (inlined as Try>::branch) { // at $DIR/separate_const_switch.rs:29:8: 29:10 + scope 5 (inlined as Try>::branch) { // at $DIR/separate_const_switch.rs:25:8: 25:10 debug self => _4; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL let mut _10: isize; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL let _11: i32; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL diff --git a/src/test/mir-opt/separate_const_switch.rs b/src/test/mir-opt/separate_const_switch.rs index 5d82acf4d609..c809e5629cc1 100644 --- a/src/test/mir-opt/separate_const_switch.rs +++ b/src/test/mir-opt/separate_const_switch.rs @@ -4,8 +4,6 @@ use std::ops::ControlFlow; // EMIT_MIR separate_const_switch.too_complex.SeparateConstSwitch.diff -// EMIT_MIR separate_const_switch.too_complex.ConstProp.diff -// EMIT_MIR separate_const_switch.too_complex.PreCodegen.after.mir fn too_complex(x: Result) -> Option { // The pass should break the outer match into // two blocks that only have one parent each. @@ -23,8 +21,6 @@ fn too_complex(x: Result) -> Option { } // EMIT_MIR separate_const_switch.identity.SeparateConstSwitch.diff -// EMIT_MIR separate_const_switch.identity.ConstProp.diff -// EMIT_MIR separate_const_switch.identity.PreCodegen.after.mir fn identity(x: Result) -> Result { Ok(x?) } diff --git a/src/test/mir-opt/simplify-arm-identity.rs b/src/test/mir-opt/simplify-arm-identity.rs index bedc86bbacb8..cf6ff57aa96d 100644 --- a/src/test/mir-opt/simplify-arm-identity.rs +++ b/src/test/mir-opt/simplify-arm-identity.rs @@ -4,6 +4,9 @@ // compile-flags: -Zmir-opt-level=3 // EMIT_MIR_FOR_EACH_BIT_WIDTH +// This pass is broken since deaggregation changed +// ignore-test + enum Src { Foo(u8), Bar, diff --git a/src/test/mir-opt/simplify-arm.rs b/src/test/mir-opt/simplify-arm.rs index f7dcaa13449e..c247872e2af4 100644 --- a/src/test/mir-opt/simplify-arm.rs +++ b/src/test/mir-opt/simplify-arm.rs @@ -6,6 +6,9 @@ // EMIT_MIR simplify_arm.id_try.SimplifyArmIdentity.diff // EMIT_MIR simplify_arm.id_try.SimplifyBranchSame.diff +// This pass is broken since deaggregation changed +// ignore-test + fn id(o: Option) -> Option { match o { Some(v) => Some(v), diff --git a/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs b/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs index 84f57deccf7e..62a15df04b14 100644 --- a/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs +++ b/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zunsound-mir-opts +// unit-test: SimplifyLocals fn map(x: Option>) -> Option> { match x { diff --git a/src/test/mir-opt/simplify_arm.id.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_arm.id.SimplifyArmIdentity.diff deleted file mode 100644 index 9c3ad4b4df91..000000000000 --- a/src/test/mir-opt/simplify_arm.id.SimplifyArmIdentity.diff +++ /dev/null @@ -1,46 +0,0 @@ -- // MIR for `id` before SimplifyArmIdentity -+ // MIR for `id` after SimplifyArmIdentity - - fn id(_1: Option) -> Option { - debug o => _1; // in scope 0 at $DIR/simplify-arm.rs:+0:7: +0:8 - let mut _0: std::option::Option; // return place in scope 0 at $DIR/simplify-arm.rs:+0:25: +0:35 - let mut _2: isize; // in scope 0 at $DIR/simplify-arm.rs:+2:9: +2:16 - let _3: u8; // in scope 0 at $DIR/simplify-arm.rs:+2:14: +2:15 - let mut _4: u8; // in scope 0 at $DIR/simplify-arm.rs:+2:25: +2:26 - scope 1 { - debug v => _3; // in scope 1 at $DIR/simplify-arm.rs:+2:14: +2:15 - } - - bb0: { - _2 = discriminant(_1); // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12 - switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:+1:5: +1:12 - } - - bb1: { - Deinit(_0); // scope 0 at $DIR/simplify-arm.rs:+3:17: +3:21 - discriminant(_0) = 0; // scope 0 at $DIR/simplify-arm.rs:+3:17: +3:21 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:+3:17: +3:21 - } - - bb2: { - unreachable; // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12 - } - - bb3: { - StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:+2:14: +2:15 - _3 = ((_1 as Some).0: u8); // scope 0 at $DIR/simplify-arm.rs:+2:14: +2:15 - StorageLive(_4); // scope 1 at $DIR/simplify-arm.rs:+2:25: +2:26 - _4 = _3; // scope 1 at $DIR/simplify-arm.rs:+2:25: +2:26 - Deinit(_0); // scope 1 at $DIR/simplify-arm.rs:+2:20: +2:27 - ((_0 as Some).0: u8) = move _4; // scope 1 at $DIR/simplify-arm.rs:+2:20: +2:27 - discriminant(_0) = 1; // scope 1 at $DIR/simplify-arm.rs:+2:20: +2:27 - StorageDead(_4); // scope 1 at $DIR/simplify-arm.rs:+2:26: +2:27 - StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:+2:26: +2:27 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:+2:26: +2:27 - } - - bb4: { - return; // scope 0 at $DIR/simplify-arm.rs:+5:2: +5:2 - } - } - diff --git a/src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff b/src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff deleted file mode 100644 index 7b3a69936577..000000000000 --- a/src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff +++ /dev/null @@ -1,46 +0,0 @@ -- // MIR for `id` before SimplifyBranchSame -+ // MIR for `id` after SimplifyBranchSame - - fn id(_1: Option) -> Option { - debug o => _1; // in scope 0 at $DIR/simplify-arm.rs:+0:7: +0:8 - let mut _0: std::option::Option; // return place in scope 0 at $DIR/simplify-arm.rs:+0:25: +0:35 - let mut _2: isize; // in scope 0 at $DIR/simplify-arm.rs:+2:9: +2:16 - let _3: u8; // in scope 0 at $DIR/simplify-arm.rs:+2:14: +2:15 - let mut _4: u8; // in scope 0 at $DIR/simplify-arm.rs:+2:25: +2:26 - scope 1 { - debug v => _3; // in scope 1 at $DIR/simplify-arm.rs:+2:14: +2:15 - } - - bb0: { - _2 = discriminant(_1); // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12 - switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:+1:5: +1:12 - } - - bb1: { - Deinit(_0); // scope 0 at $DIR/simplify-arm.rs:+3:17: +3:21 - discriminant(_0) = 0; // scope 0 at $DIR/simplify-arm.rs:+3:17: +3:21 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:+3:17: +3:21 - } - - bb2: { - unreachable; // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12 - } - - bb3: { - StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:+2:14: +2:15 - _3 = ((_1 as Some).0: u8); // scope 0 at $DIR/simplify-arm.rs:+2:14: +2:15 - StorageLive(_4); // scope 1 at $DIR/simplify-arm.rs:+2:25: +2:26 - _4 = _3; // scope 1 at $DIR/simplify-arm.rs:+2:25: +2:26 - Deinit(_0); // scope 1 at $DIR/simplify-arm.rs:+2:20: +2:27 - ((_0 as Some).0: u8) = move _4; // scope 1 at $DIR/simplify-arm.rs:+2:20: +2:27 - discriminant(_0) = 1; // scope 1 at $DIR/simplify-arm.rs:+2:20: +2:27 - StorageDead(_4); // scope 1 at $DIR/simplify-arm.rs:+2:26: +2:27 - StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:+2:26: +2:27 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:+2:26: +2:27 - } - - bb4: { - return; // scope 0 at $DIR/simplify-arm.rs:+5:2: +5:2 - } - } - diff --git a/src/test/mir-opt/simplify_arm.id_result.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_arm.id_result.SimplifyArmIdentity.diff deleted file mode 100644 index 31d8453cec01..000000000000 --- a/src/test/mir-opt/simplify_arm.id_result.SimplifyArmIdentity.diff +++ /dev/null @@ -1,58 +0,0 @@ -- // MIR for `id_result` before SimplifyArmIdentity -+ // MIR for `id_result` after SimplifyArmIdentity - - fn id_result(_1: Result) -> Result { - debug r => _1; // in scope 0 at $DIR/simplify-arm.rs:+0:14: +0:15 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify-arm.rs:+0:37: +0:52 - let mut _2: isize; // in scope 0 at $DIR/simplify-arm.rs:+2:9: +2:14 - let _3: u8; // in scope 0 at $DIR/simplify-arm.rs:+2:12: +2:13 - let mut _4: u8; // in scope 0 at $DIR/simplify-arm.rs:+2:21: +2:22 - let _5: i32; // in scope 0 at $DIR/simplify-arm.rs:+3:13: +3:14 - let mut _6: i32; // in scope 0 at $DIR/simplify-arm.rs:+3:23: +3:24 - scope 1 { - debug x => _3; // in scope 1 at $DIR/simplify-arm.rs:+2:12: +2:13 - } - scope 2 { - debug y => _5; // in scope 2 at $DIR/simplify-arm.rs:+3:13: +3:14 - } - - bb0: { - _2 = discriminant(_1); // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12 - switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:+1:5: +1:12 - } - - bb1: { - StorageLive(_5); // scope 0 at $DIR/simplify-arm.rs:+3:13: +3:14 - _5 = ((_1 as Err).0: i32); // scope 0 at $DIR/simplify-arm.rs:+3:13: +3:14 - StorageLive(_6); // scope 2 at $DIR/simplify-arm.rs:+3:23: +3:24 - _6 = _5; // scope 2 at $DIR/simplify-arm.rs:+3:23: +3:24 - Deinit(_0); // scope 2 at $DIR/simplify-arm.rs:+3:19: +3:25 - ((_0 as Err).0: i32) = move _6; // scope 2 at $DIR/simplify-arm.rs:+3:19: +3:25 - discriminant(_0) = 1; // scope 2 at $DIR/simplify-arm.rs:+3:19: +3:25 - StorageDead(_6); // scope 2 at $DIR/simplify-arm.rs:+3:24: +3:25 - StorageDead(_5); // scope 0 at $DIR/simplify-arm.rs:+3:24: +3:25 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:+3:24: +3:25 - } - - bb2: { - unreachable; // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12 - } - - bb3: { - StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:+2:12: +2:13 - _3 = ((_1 as Ok).0: u8); // scope 0 at $DIR/simplify-arm.rs:+2:12: +2:13 - StorageLive(_4); // scope 1 at $DIR/simplify-arm.rs:+2:21: +2:22 - _4 = _3; // scope 1 at $DIR/simplify-arm.rs:+2:21: +2:22 - Deinit(_0); // scope 1 at $DIR/simplify-arm.rs:+2:18: +2:23 - ((_0 as Ok).0: u8) = move _4; // scope 1 at $DIR/simplify-arm.rs:+2:18: +2:23 - discriminant(_0) = 0; // scope 1 at $DIR/simplify-arm.rs:+2:18: +2:23 - StorageDead(_4); // scope 1 at $DIR/simplify-arm.rs:+2:22: +2:23 - StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:+2:22: +2:23 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:+2:22: +2:23 - } - - bb4: { - return; // scope 0 at $DIR/simplify-arm.rs:+5:2: +5:2 - } - } - diff --git a/src/test/mir-opt/simplify_arm.id_result.SimplifyBranchSame.diff b/src/test/mir-opt/simplify_arm.id_result.SimplifyBranchSame.diff deleted file mode 100644 index 3692ebf747bd..000000000000 --- a/src/test/mir-opt/simplify_arm.id_result.SimplifyBranchSame.diff +++ /dev/null @@ -1,58 +0,0 @@ -- // MIR for `id_result` before SimplifyBranchSame -+ // MIR for `id_result` after SimplifyBranchSame - - fn id_result(_1: Result) -> Result { - debug r => _1; // in scope 0 at $DIR/simplify-arm.rs:+0:14: +0:15 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify-arm.rs:+0:37: +0:52 - let mut _2: isize; // in scope 0 at $DIR/simplify-arm.rs:+2:9: +2:14 - let _3: u8; // in scope 0 at $DIR/simplify-arm.rs:+2:12: +2:13 - let mut _4: u8; // in scope 0 at $DIR/simplify-arm.rs:+2:21: +2:22 - let _5: i32; // in scope 0 at $DIR/simplify-arm.rs:+3:13: +3:14 - let mut _6: i32; // in scope 0 at $DIR/simplify-arm.rs:+3:23: +3:24 - scope 1 { - debug x => _3; // in scope 1 at $DIR/simplify-arm.rs:+2:12: +2:13 - } - scope 2 { - debug y => _5; // in scope 2 at $DIR/simplify-arm.rs:+3:13: +3:14 - } - - bb0: { - _2 = discriminant(_1); // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12 - switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:+1:5: +1:12 - } - - bb1: { - StorageLive(_5); // scope 0 at $DIR/simplify-arm.rs:+3:13: +3:14 - _5 = ((_1 as Err).0: i32); // scope 0 at $DIR/simplify-arm.rs:+3:13: +3:14 - StorageLive(_6); // scope 2 at $DIR/simplify-arm.rs:+3:23: +3:24 - _6 = _5; // scope 2 at $DIR/simplify-arm.rs:+3:23: +3:24 - Deinit(_0); // scope 2 at $DIR/simplify-arm.rs:+3:19: +3:25 - ((_0 as Err).0: i32) = move _6; // scope 2 at $DIR/simplify-arm.rs:+3:19: +3:25 - discriminant(_0) = 1; // scope 2 at $DIR/simplify-arm.rs:+3:19: +3:25 - StorageDead(_6); // scope 2 at $DIR/simplify-arm.rs:+3:24: +3:25 - StorageDead(_5); // scope 0 at $DIR/simplify-arm.rs:+3:24: +3:25 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:+3:24: +3:25 - } - - bb2: { - unreachable; // scope 0 at $DIR/simplify-arm.rs:+1:11: +1:12 - } - - bb3: { - StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:+2:12: +2:13 - _3 = ((_1 as Ok).0: u8); // scope 0 at $DIR/simplify-arm.rs:+2:12: +2:13 - StorageLive(_4); // scope 1 at $DIR/simplify-arm.rs:+2:21: +2:22 - _4 = _3; // scope 1 at $DIR/simplify-arm.rs:+2:21: +2:22 - Deinit(_0); // scope 1 at $DIR/simplify-arm.rs:+2:18: +2:23 - ((_0 as Ok).0: u8) = move _4; // scope 1 at $DIR/simplify-arm.rs:+2:18: +2:23 - discriminant(_0) = 0; // scope 1 at $DIR/simplify-arm.rs:+2:18: +2:23 - StorageDead(_4); // scope 1 at $DIR/simplify-arm.rs:+2:22: +2:23 - StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:+2:22: +2:23 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:+2:22: +2:23 - } - - bb4: { - return; // scope 0 at $DIR/simplify-arm.rs:+5:2: +5:2 - } - } - diff --git a/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.32bit.diff b/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.32bit.diff deleted file mode 100644 index 118f5dd0abb4..000000000000 --- a/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.32bit.diff +++ /dev/null @@ -1,61 +0,0 @@ -- // MIR for `main` before SimplifyArmIdentity -+ // MIR for `main` after SimplifyArmIdentity - - fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/simplify-arm-identity.rs:+0:11: +0:11 - let _1: Src; // in scope 0 at $DIR/simplify-arm-identity.rs:+1:9: +1:10 - let mut _2: Dst; // in scope 0 at $DIR/simplify-arm-identity.rs:+2:18: +5:6 - let mut _3: isize; // in scope 0 at $DIR/simplify-arm-identity.rs:+3:9: +3:20 - let mut _5: u8; // in scope 0 at $DIR/simplify-arm-identity.rs:+3:33: +3:34 - scope 1 { - debug e => _1; // in scope 1 at $DIR/simplify-arm-identity.rs:+1:9: +1:10 - let _4: u8; // in scope 1 at $DIR/simplify-arm-identity.rs:+3:18: +3:19 - scope 2 { - } - scope 3 { - debug x => _4; // in scope 3 at $DIR/simplify-arm-identity.rs:+3:18: +3:19 - } - } - - bb0: { - StorageLive(_1); // scope 0 at $DIR/simplify-arm-identity.rs:+1:9: +1:10 - Deinit(_1); // scope 0 at $DIR/simplify-arm-identity.rs:+1:18: +1:29 - ((_1 as Foo).0: u8) = const 0_u8; // scope 0 at $DIR/simplify-arm-identity.rs:+1:18: +1:29 - discriminant(_1) = 0; // scope 0 at $DIR/simplify-arm-identity.rs:+1:18: +1:29 - StorageLive(_2); // scope 1 at $DIR/simplify-arm-identity.rs:+2:18: +5:6 - _3 = const 0_isize; // scope 1 at $DIR/simplify-arm-identity.rs:+2:24: +2:25 - goto -> bb3; // scope 1 at $DIR/simplify-arm-identity.rs:+2:18: +2:25 - } - - bb1: { - Deinit(_2); // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32 - ((_2 as Foo).0: u8) = const 0_u8; // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32 - discriminant(_2) = 0; // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32 - goto -> bb4; // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32 - } - - bb2: { - unreachable; // scope 1 at $DIR/simplify-arm-identity.rs:+2:24: +2:25 - } - - bb3: { - StorageLive(_4); // scope 1 at $DIR/simplify-arm-identity.rs:+3:18: +3:19 - _4 = ((_1 as Foo).0: u8); // scope 1 at $DIR/simplify-arm-identity.rs:+3:18: +3:19 - StorageLive(_5); // scope 3 at $DIR/simplify-arm-identity.rs:+3:33: +3:34 - _5 = _4; // scope 3 at $DIR/simplify-arm-identity.rs:+3:33: +3:34 - Deinit(_2); // scope 3 at $DIR/simplify-arm-identity.rs:+3:24: +3:35 - ((_2 as Foo).0: u8) = move _5; // scope 3 at $DIR/simplify-arm-identity.rs:+3:24: +3:35 - discriminant(_2) = 0; // scope 3 at $DIR/simplify-arm-identity.rs:+3:24: +3:35 - StorageDead(_5); // scope 3 at $DIR/simplify-arm-identity.rs:+3:34: +3:35 - StorageDead(_4); // scope 1 at $DIR/simplify-arm-identity.rs:+3:34: +3:35 - goto -> bb4; // scope 1 at $DIR/simplify-arm-identity.rs:+3:34: +3:35 - } - - bb4: { - StorageDead(_2); // scope 1 at $DIR/simplify-arm-identity.rs:+5:6: +5:7 - nop; // scope 0 at $DIR/simplify-arm-identity.rs:+0:11: +6:2 - StorageDead(_1); // scope 0 at $DIR/simplify-arm-identity.rs:+6:1: +6:2 - return; // scope 0 at $DIR/simplify-arm-identity.rs:+6:2: +6:2 - } - } - diff --git a/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.64bit.diff b/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.64bit.diff deleted file mode 100644 index 118f5dd0abb4..000000000000 --- a/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.64bit.diff +++ /dev/null @@ -1,61 +0,0 @@ -- // MIR for `main` before SimplifyArmIdentity -+ // MIR for `main` after SimplifyArmIdentity - - fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/simplify-arm-identity.rs:+0:11: +0:11 - let _1: Src; // in scope 0 at $DIR/simplify-arm-identity.rs:+1:9: +1:10 - let mut _2: Dst; // in scope 0 at $DIR/simplify-arm-identity.rs:+2:18: +5:6 - let mut _3: isize; // in scope 0 at $DIR/simplify-arm-identity.rs:+3:9: +3:20 - let mut _5: u8; // in scope 0 at $DIR/simplify-arm-identity.rs:+3:33: +3:34 - scope 1 { - debug e => _1; // in scope 1 at $DIR/simplify-arm-identity.rs:+1:9: +1:10 - let _4: u8; // in scope 1 at $DIR/simplify-arm-identity.rs:+3:18: +3:19 - scope 2 { - } - scope 3 { - debug x => _4; // in scope 3 at $DIR/simplify-arm-identity.rs:+3:18: +3:19 - } - } - - bb0: { - StorageLive(_1); // scope 0 at $DIR/simplify-arm-identity.rs:+1:9: +1:10 - Deinit(_1); // scope 0 at $DIR/simplify-arm-identity.rs:+1:18: +1:29 - ((_1 as Foo).0: u8) = const 0_u8; // scope 0 at $DIR/simplify-arm-identity.rs:+1:18: +1:29 - discriminant(_1) = 0; // scope 0 at $DIR/simplify-arm-identity.rs:+1:18: +1:29 - StorageLive(_2); // scope 1 at $DIR/simplify-arm-identity.rs:+2:18: +5:6 - _3 = const 0_isize; // scope 1 at $DIR/simplify-arm-identity.rs:+2:24: +2:25 - goto -> bb3; // scope 1 at $DIR/simplify-arm-identity.rs:+2:18: +2:25 - } - - bb1: { - Deinit(_2); // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32 - ((_2 as Foo).0: u8) = const 0_u8; // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32 - discriminant(_2) = 0; // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32 - goto -> bb4; // scope 1 at $DIR/simplify-arm-identity.rs:+4:21: +4:32 - } - - bb2: { - unreachable; // scope 1 at $DIR/simplify-arm-identity.rs:+2:24: +2:25 - } - - bb3: { - StorageLive(_4); // scope 1 at $DIR/simplify-arm-identity.rs:+3:18: +3:19 - _4 = ((_1 as Foo).0: u8); // scope 1 at $DIR/simplify-arm-identity.rs:+3:18: +3:19 - StorageLive(_5); // scope 3 at $DIR/simplify-arm-identity.rs:+3:33: +3:34 - _5 = _4; // scope 3 at $DIR/simplify-arm-identity.rs:+3:33: +3:34 - Deinit(_2); // scope 3 at $DIR/simplify-arm-identity.rs:+3:24: +3:35 - ((_2 as Foo).0: u8) = move _5; // scope 3 at $DIR/simplify-arm-identity.rs:+3:24: +3:35 - discriminant(_2) = 0; // scope 3 at $DIR/simplify-arm-identity.rs:+3:24: +3:35 - StorageDead(_5); // scope 3 at $DIR/simplify-arm-identity.rs:+3:34: +3:35 - StorageDead(_4); // scope 1 at $DIR/simplify-arm-identity.rs:+3:34: +3:35 - goto -> bb4; // scope 1 at $DIR/simplify-arm-identity.rs:+3:34: +3:35 - } - - bb4: { - StorageDead(_2); // scope 1 at $DIR/simplify-arm-identity.rs:+5:6: +5:7 - nop; // scope 0 at $DIR/simplify-arm-identity.rs:+0:11: +6:2 - StorageDead(_1); // scope 0 at $DIR/simplify-arm-identity.rs:+6:1: +6:2 - return; // scope 0 at $DIR/simplify-arm-identity.rs:+6:2: +6:2 - } - } - diff --git a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff index d8e0657c6ebc..51d26b08b2a1 100644 --- a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff +++ b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff @@ -5,24 +5,32 @@ debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:8: +0:9 let mut _0: std::option::Option>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:31: +0:46 let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:9: +2:13 -- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15 -- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26 + let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15 + let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26 - let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2 - let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2 - let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2 scope 1 { - debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15 + debug x => _3; // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15 } bb0: { +- _5 = const false; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12 +- _5 = const true; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12 _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12 switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:5: +1:12 } bb1: { - ((_0 as Some).0: std::boxed::Box<()>) = move ((_1 as Some).0: std::boxed::Box<()>); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15 + StorageLive(_3); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15 + _3 = move ((_1 as Some).0: std::boxed::Box<()>); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15 + StorageLive(_4); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26 + _4 = move _3; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26 Deinit(_0); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27 + ((_0 as Some).0: std::boxed::Box<()>) = move _4; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27 discriminant(_0) = 1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27 + StorageDead(_4); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27 + StorageDead(_3); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27 goto -> bb4; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27 } @@ -37,6 +45,7 @@ } bb4: { +- _6 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2 return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:2: +5:2 } } diff --git a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff index d8e0657c6ebc..51d26b08b2a1 100644 --- a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff +++ b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff @@ -5,24 +5,32 @@ debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:8: +0:9 let mut _0: std::option::Option>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:31: +0:46 let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:9: +2:13 -- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15 -- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26 + let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15 + let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26 - let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2 - let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2 - let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2 scope 1 { - debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15 + debug x => _3; // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15 } bb0: { +- _5 = const false; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12 +- _5 = const true; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12 _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12 switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:5: +1:12 } bb1: { - ((_0 as Some).0: std::boxed::Box<()>) = move ((_1 as Some).0: std::boxed::Box<()>); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15 + StorageLive(_3); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15 + _3 = move ((_1 as Some).0: std::boxed::Box<()>); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15 + StorageLive(_4); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26 + _4 = move _3; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26 Deinit(_0); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27 + ((_0 as Some).0: std::boxed::Box<()>) = move _4; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27 discriminant(_0) = 1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27 + StorageDead(_4); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27 + StorageDead(_3); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27 goto -> bb4; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27 } @@ -37,6 +45,7 @@ } bb4: { +- _6 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2 return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:2: +5:2 } } diff --git a/src/test/mir-opt/simplify_try.rs b/src/test/mir-opt/simplify_try.rs deleted file mode 100644 index 15e351e7d501..000000000000 --- a/src/test/mir-opt/simplify_try.rs +++ /dev/null @@ -1,30 +0,0 @@ -// compile-flags: -Zunsound-mir-opts -// EMIT_MIR simplify_try.try_identity.SimplifyArmIdentity.diff -// EMIT_MIR simplify_try.try_identity.SimplifyBranchSame.after.mir -// EMIT_MIR simplify_try.try_identity.SimplifyLocals.after.mir -// EMIT_MIR simplify_try.try_identity.DestinationPropagation.diff - - -fn into_result(r: Result) -> Result { - r -} - -fn from_error(e: E) -> Result { - Err(e) -} - -// This was written to the `?` from `try_trait`, but `try_trait_v2` uses a different structure, -// so the relevant desugar is copied inline in order to keep the test testing the same thing. -// FIXME(#85133): while this might be useful for `r#try!`, it would be nice to have a MIR -// optimization that picks up the `?` desugaring, as `SimplifyArmIdentity` does not. -fn try_identity(x: Result) -> Result { - let y = match into_result(x) { - Err(e) => return from_error(From::from(e)), - Ok(v) => v, - }; - Ok(y) -} - -fn main() { - let _ = try_identity(Ok(0)); -} diff --git a/src/test/mir-opt/try_identity_e2e.new.PreCodegen.after.mir b/src/test/mir-opt/try_identity_e2e.new.PreCodegen.after.mir new file mode 100644 index 000000000000..330929c58c91 --- /dev/null +++ b/src/test/mir-opt/try_identity_e2e.new.PreCodegen.after.mir @@ -0,0 +1,96 @@ +// MIR for `new` after PreCodegen + +fn new(_1: Result) -> Result { + debug x => _1; // in scope 0 at $DIR/try_identity_e2e.rs:+0:14: +0:15 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/try_identity_e2e.rs:+0:34: +0:46 + let mut _2: T; // in scope 0 at $DIR/try_identity_e2e.rs:+2:9: +10:10 + let mut _3: std::ops::ControlFlow; // in scope 0 at $DIR/try_identity_e2e.rs:+2:15: +7:10 + let mut _4: isize; // in scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:22 + let _5: T; // in scope 0 at $DIR/try_identity_e2e.rs:+4:20: +4:21 + let mut _6: T; // in scope 0 at $DIR/try_identity_e2e.rs:+4:48: +4:49 + let _7: E; // in scope 0 at $DIR/try_identity_e2e.rs:+5:21: +5:22 + let mut _8: E; // in scope 0 at $DIR/try_identity_e2e.rs:+5:46: +5:47 + let mut _9: isize; // in scope 0 at $DIR/try_identity_e2e.rs:+8:13: +8:37 + let _10: T; // in scope 0 at $DIR/try_identity_e2e.rs:+8:35: +8:36 + let _11: E; // in scope 0 at $DIR/try_identity_e2e.rs:+9:32: +9:33 + let mut _12: E; // in scope 0 at $DIR/try_identity_e2e.rs:+9:49: +9:50 + scope 1 { + debug v => _5; // in scope 1 at $DIR/try_identity_e2e.rs:+4:20: +4:21 + } + scope 2 { + debug e => _7; // in scope 2 at $DIR/try_identity_e2e.rs:+5:21: +5:22 + } + scope 3 { + debug v => _10; // in scope 3 at $DIR/try_identity_e2e.rs:+8:35: +8:36 + } + scope 4 { + debug e => _11; // in scope 4 at $DIR/try_identity_e2e.rs:+9:32: +9:33 + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/try_identity_e2e.rs:+2:9: +10:10 + StorageLive(_3); // scope 0 at $DIR/try_identity_e2e.rs:+2:15: +7:10 + _4 = discriminant(_1); // scope 0 at $DIR/try_identity_e2e.rs:+3:19: +3:20 + switchInt(move _4) -> [0_isize: bb2, 1_isize: bb1, otherwise: bb4]; // scope 0 at $DIR/try_identity_e2e.rs:+3:13: +3:20 + } + + bb1: { + StorageLive(_7); // scope 0 at $DIR/try_identity_e2e.rs:+5:21: +5:22 + _7 = move ((_1 as Err).0: E); // scope 0 at $DIR/try_identity_e2e.rs:+5:21: +5:22 + StorageLive(_8); // scope 2 at $DIR/try_identity_e2e.rs:+5:46: +5:47 + _8 = move _7; // scope 2 at $DIR/try_identity_e2e.rs:+5:46: +5:47 + Deinit(_3); // scope 2 at $DIR/try_identity_e2e.rs:+5:27: +5:48 + ((_3 as Break).0: E) = move _8; // scope 2 at $DIR/try_identity_e2e.rs:+5:27: +5:48 + discriminant(_3) = 1; // scope 2 at $DIR/try_identity_e2e.rs:+5:27: +5:48 + StorageDead(_8); // scope 2 at $DIR/try_identity_e2e.rs:+5:47: +5:48 + StorageDead(_7); // scope 0 at $DIR/try_identity_e2e.rs:+5:47: +5:48 + _9 = discriminant(_3); // scope 0 at $DIR/try_identity_e2e.rs:+2:15: +7:10 + switchInt(move _9) -> [0_isize: bb5, 1_isize: bb3, otherwise: bb4]; // scope 0 at $DIR/try_identity_e2e.rs:+2:9: +7:10 + } + + bb2: { + StorageLive(_5); // scope 0 at $DIR/try_identity_e2e.rs:+4:20: +4:21 + _5 = move ((_1 as Ok).0: T); // scope 0 at $DIR/try_identity_e2e.rs:+4:20: +4:21 + StorageLive(_6); // scope 1 at $DIR/try_identity_e2e.rs:+4:48: +4:49 + _6 = move _5; // scope 1 at $DIR/try_identity_e2e.rs:+4:48: +4:49 + Deinit(_3); // scope 1 at $DIR/try_identity_e2e.rs:+4:26: +4:50 + ((_3 as Continue).0: T) = move _6; // scope 1 at $DIR/try_identity_e2e.rs:+4:26: +4:50 + discriminant(_3) = 0; // scope 1 at $DIR/try_identity_e2e.rs:+4:26: +4:50 + StorageDead(_6); // scope 1 at $DIR/try_identity_e2e.rs:+4:49: +4:50 + StorageDead(_5); // scope 0 at $DIR/try_identity_e2e.rs:+4:49: +4:50 + _9 = discriminant(_3); // scope 0 at $DIR/try_identity_e2e.rs:+2:15: +7:10 + switchInt(move _9) -> [0_isize: bb5, 1_isize: bb3, otherwise: bb4]; // scope 0 at $DIR/try_identity_e2e.rs:+2:9: +7:10 + } + + bb3: { + StorageLive(_11); // scope 0 at $DIR/try_identity_e2e.rs:+9:32: +9:33 + _11 = move ((_3 as Break).0: E); // scope 0 at $DIR/try_identity_e2e.rs:+9:32: +9:33 + StorageLive(_12); // scope 4 at $DIR/try_identity_e2e.rs:+9:49: +9:50 + _12 = move _11; // scope 4 at $DIR/try_identity_e2e.rs:+9:49: +9:50 + Deinit(_0); // scope 4 at $DIR/try_identity_e2e.rs:+9:45: +9:51 + ((_0 as Err).0: E) = move _12; // scope 4 at $DIR/try_identity_e2e.rs:+9:45: +9:51 + discriminant(_0) = 1; // scope 4 at $DIR/try_identity_e2e.rs:+9:45: +9:51 + StorageDead(_12); // scope 4 at $DIR/try_identity_e2e.rs:+9:50: +9:51 + StorageDead(_11); // scope 0 at $DIR/try_identity_e2e.rs:+9:50: +9:51 + StorageDead(_2); // scope 0 at $DIR/try_identity_e2e.rs:+11:5: +11:6 + StorageDead(_3); // scope 0 at $DIR/try_identity_e2e.rs:+12:1: +12:2 + return; // scope 0 at $DIR/try_identity_e2e.rs:+12:1: +12:2 + } + + bb4: { + unreachable; // scope 0 at $DIR/try_identity_e2e.rs:+2:15: +7:10 + } + + bb5: { + StorageLive(_10); // scope 0 at $DIR/try_identity_e2e.rs:+8:35: +8:36 + _10 = move ((_3 as Continue).0: T); // scope 0 at $DIR/try_identity_e2e.rs:+8:35: +8:36 + _2 = move _10; // scope 3 at $DIR/try_identity_e2e.rs:+8:41: +8:42 + StorageDead(_10); // scope 0 at $DIR/try_identity_e2e.rs:+8:41: +8:42 + Deinit(_0); // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +11:6 + ((_0 as Ok).0: T) = move _2; // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +11:6 + discriminant(_0) = 0; // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +11:6 + StorageDead(_2); // scope 0 at $DIR/try_identity_e2e.rs:+11:5: +11:6 + StorageDead(_3); // scope 0 at $DIR/try_identity_e2e.rs:+12:1: +12:2 + return; // scope 0 at $DIR/try_identity_e2e.rs:+12:1: +12:2 + } +} diff --git a/src/test/mir-opt/try_identity_e2e.old.PreCodegen.after.mir b/src/test/mir-opt/try_identity_e2e.old.PreCodegen.after.mir new file mode 100644 index 000000000000..18d3e0fb2639 --- /dev/null +++ b/src/test/mir-opt/try_identity_e2e.old.PreCodegen.after.mir @@ -0,0 +1,53 @@ +// MIR for `old` after PreCodegen + +fn old(_1: Result) -> Result { + debug x => _1; // in scope 0 at $DIR/try_identity_e2e.rs:+0:14: +0:15 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/try_identity_e2e.rs:+0:34: +0:46 + let mut _2: T; // in scope 0 at $DIR/try_identity_e2e.rs:+2:9: +5:10 + let mut _3: isize; // in scope 0 at $DIR/try_identity_e2e.rs:+3:13: +3:18 + let _4: T; // in scope 0 at $DIR/try_identity_e2e.rs:+3:16: +3:17 + let _5: E; // in scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:18 + let mut _6: E; // in scope 0 at $DIR/try_identity_e2e.rs:+4:34: +4:35 + scope 1 { + debug v => _4; // in scope 1 at $DIR/try_identity_e2e.rs:+3:16: +3:17 + } + scope 2 { + debug e => _5; // in scope 2 at $DIR/try_identity_e2e.rs:+4:17: +4:18 + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/try_identity_e2e.rs:+2:9: +5:10 + _3 = discriminant(_1); // scope 0 at $DIR/try_identity_e2e.rs:+2:15: +2:16 + switchInt(move _3) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/try_identity_e2e.rs:+2:9: +2:16 + } + + bb1: { + StorageLive(_5); // scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:18 + _5 = move ((_1 as Err).0: E); // scope 0 at $DIR/try_identity_e2e.rs:+4:17: +4:18 + StorageLive(_6); // scope 2 at $DIR/try_identity_e2e.rs:+4:34: +4:35 + _6 = move _5; // scope 2 at $DIR/try_identity_e2e.rs:+4:34: +4:35 + Deinit(_0); // scope 2 at $DIR/try_identity_e2e.rs:+4:30: +4:36 + ((_0 as Err).0: E) = move _6; // scope 2 at $DIR/try_identity_e2e.rs:+4:30: +4:36 + discriminant(_0) = 1; // scope 2 at $DIR/try_identity_e2e.rs:+4:30: +4:36 + StorageDead(_6); // scope 2 at $DIR/try_identity_e2e.rs:+4:35: +4:36 + StorageDead(_5); // scope 0 at $DIR/try_identity_e2e.rs:+4:35: +4:36 + StorageDead(_2); // scope 0 at $DIR/try_identity_e2e.rs:+6:5: +6:6 + return; // scope 0 at $DIR/try_identity_e2e.rs:+7:1: +7:2 + } + + bb2: { + unreachable; // scope 0 at $DIR/try_identity_e2e.rs:+2:15: +2:16 + } + + bb3: { + StorageLive(_4); // scope 0 at $DIR/try_identity_e2e.rs:+3:16: +3:17 + _4 = move ((_1 as Ok).0: T); // scope 0 at $DIR/try_identity_e2e.rs:+3:16: +3:17 + _2 = move _4; // scope 1 at $DIR/try_identity_e2e.rs:+3:22: +3:23 + StorageDead(_4); // scope 0 at $DIR/try_identity_e2e.rs:+3:22: +3:23 + Deinit(_0); // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +6:6 + ((_0 as Ok).0: T) = move _2; // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +6:6 + discriminant(_0) = 0; // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +6:6 + StorageDead(_2); // scope 0 at $DIR/try_identity_e2e.rs:+6:5: +6:6 + return; // scope 0 at $DIR/try_identity_e2e.rs:+7:1: +7:2 + } +} diff --git a/src/test/mir-opt/try_identity_e2e.rs b/src/test/mir-opt/try_identity_e2e.rs new file mode 100644 index 000000000000..00cb80f5035b --- /dev/null +++ b/src/test/mir-opt/try_identity_e2e.rs @@ -0,0 +1,34 @@ +// Track the status of MIR optimizations simplifying `Ok(res?)` for both the old and new desugarings +// of that syntax. + +use std::ops::ControlFlow; + +// EMIT_MIR try_identity_e2e.new.PreCodegen.after.mir +fn new(x: Result) -> Result { + Ok( + match { + match x { + Ok(v) => ControlFlow::Continue(v), + Err(e) => ControlFlow::Break(e), + } + } { + ControlFlow::Continue(v) => v, + ControlFlow::Break(e) => return Err(e), + } + ) +} + +// EMIT_MIR try_identity_e2e.old.PreCodegen.after.mir +fn old(x: Result) -> Result { + Ok( + match x { + Ok(v) => v, + Err(e) => return Err(e), + } + ) +} + +fn main() { + let _ = new::<(), ()>(Ok(())); + let _ = old::<(), ()>(Ok(())); +} From 8bed0f25ef59c01d8c7d3dc5e41b699f3b26532f Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 2 Sep 2022 10:18:12 +0200 Subject: [PATCH 4076/5092] Update LLVM submodule Fixes #100834. Fixes #101121. --- src/llvm-project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm-project b/src/llvm-project index e3be3f64ecac..670e5f673acb 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit e3be3f64ecac101d14ceda759ba078ad0aaf3747 +Subproject commit 670e5f673acb736acbfce65e0ffe2c8cd115b93f From 61ad33da422f77b3e7833f6a43aa717f5a37481e Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 2 Sep 2022 11:48:58 +0100 Subject: [PATCH 4077/5092] internal: ignore failures when publishing to ovsx This has been failing for a while https://github.com/rust-lang/rust-analyzer/runs/8147683225?check_suite_focus=true#step:24:19 --- .github/workflows/release.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index b2e5db6f689b..303a10615bb7 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -248,7 +248,7 @@ jobs: if: github.ref == 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer') working-directory: ./editors/code # token from https://dev.azure.com/rust-analyzer/ - run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix + run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix || true - name: Publish Extension (Code Marketplace, nightly) if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer') @@ -258,4 +258,4 @@ jobs: - name: Publish Extension (OpenVSX, nightly) if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer') working-directory: ./editors/code - run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix + run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix || true From 137eea86db9abc255ceb5de167c5f4d7ee53846e Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 1 Sep 2022 16:22:30 +0200 Subject: [PATCH 4078/5092] Make CrateConfig make order depended for linting purpose --- compiler/rustc_session/src/config.rs | 2 +- compiler/rustc_session/src/parse.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 7c50fe2d823b..7528c27ce482 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -891,7 +891,7 @@ fn default_configuration(sess: &Session) -> CrateConfig { sess.fatal(&err); }); - let mut ret = FxHashSet::default(); + let mut ret = CrateConfig::default(); ret.reserve(7); // the minimum number of insertions // Target bindings. ret.insert((sym::target_os, Some(Symbol::intern(os)))); diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index ebec754dcffb..5b95d73bd4d3 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -8,7 +8,7 @@ use crate::lint::{ }; use crate::SessionDiagnostic; use rustc_ast::node_id::NodeId; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_data_structures::sync::{Lock, Lrc}; use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler}; use rustc_errors::{ @@ -25,7 +25,7 @@ use std::str; /// The set of keys (and, optionally, values) that define the compilation /// environment of the crate, used to drive conditional compilation. -pub type CrateConfig = FxHashSet<(Symbol, Option)>; +pub type CrateConfig = FxIndexSet<(Symbol, Option)>; pub type CrateCheckConfig = CheckCfg; /// Collected spans during parsing for places where a certain feature was @@ -241,7 +241,7 @@ impl ParseSess { Self { span_diagnostic: handler, unstable_features: UnstableFeatures::from_environment(None), - config: FxHashSet::default(), + config: FxIndexSet::default(), check_config: CrateCheckConfig::default(), edition: ExpnId::root().expn_data().edition, raw_identifier_spans: Lock::new(Vec::new()), From eccdccf4ebd1b1389e409cccb3427b85bbe6166b Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 11 Aug 2022 19:50:48 +0200 Subject: [PATCH 4079/5092] Add warning against unexpected --cfg with --check-cfg --- .../locales/en-US/lint.ftl | 6 ++++ compiler/rustc_lint/src/builtin.rs | 36 +++++++++++++++++++ compiler/rustc_lint/src/lib.rs | 1 + compiler/rustc_lint_defs/src/builtin.rs | 1 - src/test/ui/check-cfg/allow-at-crate-level.rs | 8 +++++ .../ui/check-cfg/invalid-cfg-value.stderr | 6 +++- src/test/ui/check-cfg/mix.rs | 2 +- src/test/ui/check-cfg/mix.stderr | 10 +++++- 8 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/check-cfg/allow-at-crate-level.rs diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 27ad3e453660..7f9918e4f128 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -354,6 +354,12 @@ lint_builtin_unreachable_pub = unreachable `pub` {$what} .suggestion = consider restricting its visibility .help = or consider exporting it for use by other crates +lint_builtin_unexpected_cli_config_name = unexpected `{$name}` as condition name + .help = was set with `--cfg` but isn't in the `--check-cfg` expected names + +lint_builtin_unexpected_cli_config_value = unexpected condition value `{$value}` for condition name `{$name}` + .help = was set with `--cfg` but isn't in the `--check-cfg` expected values + lint_builtin_type_alias_bounds_help = use fully disambiguated paths (i.e., `::Assoc`) to refer to associated types in type aliases lint_builtin_type_alias_where_clause = where clauses are not enforced in type aliases diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 4e9c209a5840..48942211eba2 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -3250,3 +3250,39 @@ impl EarlyLintPass for SpecialModuleName { } } } + +pub use rustc_session::lint::builtin::UNEXPECTED_CFGS; + +declare_lint_pass!(UnexpectedCfgs => [UNEXPECTED_CFGS]); + +impl EarlyLintPass for UnexpectedCfgs { + fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) { + let cfg = &cx.sess().parse_sess.config; + let check_cfg = &cx.sess().parse_sess.check_config; + for &(name, value) in cfg { + if let Some(names_valid) = &check_cfg.names_valid { + if !names_valid.contains(&name) { + cx.lookup(UNEXPECTED_CFGS, None::, |diag| { + diag.build(fluent::lint::builtin_unexpected_cli_config_name) + .help(fluent::lint::help) + .set_arg("name", name) + .emit(); + }); + } + } + if let Some(value) = value { + if let Some(values) = &check_cfg.values_valid.get(&name) { + if !values.contains(&value) { + cx.lookup(UNEXPECTED_CFGS, None::, |diag| { + diag.build(fluent::lint::builtin_unexpected_cli_config_value) + .help(fluent::lint::help) + .set_arg("name", name) + .set_arg("value", value) + .emit(); + }); + } + } + } + } + } +} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 3478be1ed5d9..e6cb90cdccaf 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -144,6 +144,7 @@ macro_rules! early_lint_passes { IncompleteFeatures: IncompleteFeatures, RedundantSemicolons: RedundantSemicolons, UnusedDocComment: UnusedDocComment, + UnexpectedCfgs: UnexpectedCfgs, ] ); }; diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 845563338eaa..ca01599acc8b 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3365,7 +3365,6 @@ declare_lint_pass! { DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, DUPLICATE_MACRO_ATTRIBUTES, SUSPICIOUS_AUTO_TRAIT_IMPLS, - UNEXPECTED_CFGS, DEPRECATED_WHERE_CLAUSE_LOCATION, TEST_UNSTABLE_LINT, FFI_UNWIND_CALLS, diff --git a/src/test/ui/check-cfg/allow-at-crate-level.rs b/src/test/ui/check-cfg/allow-at-crate-level.rs new file mode 100644 index 000000000000..ce3383a2961a --- /dev/null +++ b/src/test/ui/check-cfg/allow-at-crate-level.rs @@ -0,0 +1,8 @@ +// This test check that #![allow(unexpected_cfgs)] works with --cfg +// +// check-pass +// compile-flags: --cfg=unexpected --check-cfg=names() -Z unstable-options + +#![allow(unexpected_cfgs)] + +fn main() {} diff --git a/src/test/ui/check-cfg/invalid-cfg-value.stderr b/src/test/ui/check-cfg/invalid-cfg-value.stderr index 6cce31d33928..7db2aadec177 100644 --- a/src/test/ui/check-cfg/invalid-cfg-value.stderr +++ b/src/test/ui/check-cfg/invalid-cfg-value.stderr @@ -15,5 +15,9 @@ LL | #[cfg(feature = "rand")] | = note: expected values for `feature` are: full, serde -warning: 2 warnings emitted +warning: unexpected condition value `rand` for condition name `feature` + | + = help: was set with `--cfg` but isn't in the `--check-cfg` expected values + +warning: 3 warnings emitted diff --git a/src/test/ui/check-cfg/mix.rs b/src/test/ui/check-cfg/mix.rs index 8e3d20d50458..4e488fc03ec4 100644 --- a/src/test/ui/check-cfg/mix.rs +++ b/src/test/ui/check-cfg/mix.rs @@ -3,7 +3,7 @@ // we correctly lint on the `cfg!` macro and `cfg_attr` attribute. // // check-pass -// compile-flags: --check-cfg=names() --check-cfg=values(feature,"foo") --cfg feature="bar" -Z unstable-options +// compile-flags: --check-cfg=names() --check-cfg=values(feature,"foo") --cfg feature="bar" --cfg unknown_name -Z unstable-options #[cfg(windows)] fn do_windows_stuff() {} diff --git a/src/test/ui/check-cfg/mix.stderr b/src/test/ui/check-cfg/mix.stderr index e51b75b3d435..9cf887ec7885 100644 --- a/src/test/ui/check-cfg/mix.stderr +++ b/src/test/ui/check-cfg/mix.stderr @@ -28,6 +28,14 @@ warning: unexpected `cfg` condition name LL | #[cfg_attr(uu, test)] | ^^ +warning: unexpected condition value `bar` for condition name `feature` + | + = help: was set with `--cfg` but isn't in the `--check-cfg` expected values + +warning: unexpected `unknown_name` as condition name + | + = help: was set with `--cfg` but isn't in the `--check-cfg` expected names + warning: unexpected `cfg` condition name --> $DIR/mix.rs:35:10 | @@ -170,5 +178,5 @@ LL | cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra")); | = note: expected values for `feature` are: foo -warning: 25 warnings emitted +warning: 27 warnings emitted From 8ae58b9fe45aac9534475e2042729327c4485d5f Mon Sep 17 00:00:00 2001 From: iDawer Date: Fri, 2 Sep 2022 12:52:58 +0500 Subject: [PATCH 4080/5092] Record enabled unstable features into DefMap --- crates/hir-def/src/nameres.rs | 11 +++++++++- crates/hir-def/src/nameres/collector.rs | 11 ++++++++++ crates/hir-expand/src/name.rs | 1 + .../src/diagnostics/match_check/usefulness.rs | 22 +++++-------------- 4 files changed, 27 insertions(+), 18 deletions(-) diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs index 45f631936d2a..fc8444394cf5 100644 --- a/crates/hir-def/src/nameres.rs +++ b/crates/hir-def/src/nameres.rs @@ -64,7 +64,7 @@ use hir_expand::{name::Name, InFile, MacroCallId, MacroDefId}; use itertools::Itertools; use la_arena::Arena; use profile::Count; -use rustc_hash::FxHashMap; +use rustc_hash::{FxHashMap, FxHashSet}; use stdx::format_to; use syntax::{ast, SmolStr}; @@ -114,6 +114,8 @@ pub struct DefMap { registered_attrs: Vec, /// Custom tool modules registered with `#![register_tool]`. registered_tools: Vec, + /// Unstable features of Rust enabled with `#![feature(A, B)]`. + unstable_features: FxHashSet, edition: Edition, recursion_limit: Option, @@ -284,6 +286,7 @@ impl DefMap { modules, registered_attrs: Vec::new(), registered_tools: Vec::new(), + unstable_features: FxHashSet::default(), diagnostics: Vec::new(), } } @@ -314,6 +317,10 @@ impl DefMap { &self.registered_attrs } + pub fn is_unstable_feature_enabled(&self, feature: &str) -> bool { + self.unstable_features.contains(feature) + } + pub fn root(&self) -> LocalModuleId { self.root } @@ -483,6 +490,7 @@ impl DefMap { registered_tools, fn_proc_macro_mapping, derive_helpers_in_scope, + unstable_features, proc_macro_loading_error: _, block: _, edition: _, @@ -500,6 +508,7 @@ impl DefMap { registered_tools.shrink_to_fit(); fn_proc_macro_mapping.shrink_to_fit(); derive_helpers_in_scope.shrink_to_fit(); + unstable_features.shrink_to_fit(); for (_, module) in modules.iter_mut() { module.children.shrink_to_fit(); module.scope.shrink_to_fit(); diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 8a6bb929c3df..ee27aa2554a3 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -294,6 +294,17 @@ impl DefCollector<'_> { continue; } + if *attr_name == hir_expand::name![feature] { + let features = + attr.parse_path_comma_token_tree().into_iter().flatten().filter_map( + |feat| match feat.segments() { + [name] => Some(name.to_smol_str()), + _ => None, + }, + ); + self.def_map.unstable_features.extend(features); + } + let attr_is_register_like = *attr_name == hir_expand::name![register_attr] || *attr_name == hir_expand::name![register_tool]; if !attr_is_register_like { diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs index 2b859f775095..4ce21a57967c 100644 --- a/crates/hir-expand/src/name.rs +++ b/crates/hir-expand/src/name.rs @@ -336,6 +336,7 @@ pub mod known { test, test_case, recursion_limit, + feature, // Safe intrinsics abort, add_with_overflow, diff --git a/crates/hir-ty/src/diagnostics/match_check/usefulness.rs b/crates/hir-ty/src/diagnostics/match_check/usefulness.rs index 4bb4ff8f10a6..c4d709a975b0 100644 --- a/crates/hir-ty/src/diagnostics/match_check/usefulness.rs +++ b/crates/hir-ty/src/diagnostics/match_check/usefulness.rs @@ -274,7 +274,6 @@ use std::iter::once; use hir_def::{AdtId, DefWithBodyId, HasModule, ModuleId}; -use once_cell::unsync::OnceCell; use smallvec::{smallvec, SmallVec}; use typed_arena::Arena; @@ -290,7 +289,7 @@ pub(crate) struct MatchCheckCtx<'a, 'p> { pub(crate) db: &'a dyn HirDatabase, /// Lowered patterns from arms plus generated by the check. pub(crate) pattern_arena: &'p Arena>, - feature_exhaustive_patterns: OnceCell, + exhaustive_patterns: bool, } impl<'a, 'p> MatchCheckCtx<'a, 'p> { @@ -300,7 +299,9 @@ impl<'a, 'p> MatchCheckCtx<'a, 'p> { db: &'a dyn HirDatabase, pattern_arena: &'p Arena>, ) -> Self { - Self { module, body, db, pattern_arena, feature_exhaustive_patterns: Default::default() } + let def_map = db.crate_def_map(module.krate()); + let exhaustive_patterns = def_map.is_unstable_feature_enabled("exhaustive_patterns"); + Self { module, body, db, pattern_arena, exhaustive_patterns } } pub(super) fn is_uninhabited(&self, ty: &Ty) -> bool { @@ -326,20 +327,7 @@ impl<'a, 'p> MatchCheckCtx<'a, 'p> { // Rust's unstable feature described as "Allows exhaustive pattern matching on types that contain uninhabited types." pub(super) fn feature_exhaustive_patterns(&self) -> bool { - *self.feature_exhaustive_patterns.get_or_init(|| { - let def_map = self.db.crate_def_map(self.module.krate()); - let root_mod = def_map.module_id(def_map.root()); - let rood_attrs = self.db.attrs(root_mod.into()); - let mut nightly_features = rood_attrs - .by_key("feature") - .attrs() - .map(|attr| attr.parse_path_comma_token_tree()) - .flatten() - .flatten(); - nightly_features.any( - |feat| matches!(feat.segments(), [name] if name.to_smol_str() == "exhaustive_patterns"), - ) - }) + self.exhaustive_patterns } } From ffd79c28879d102baf8adcee8f2603ab98c5852d Mon Sep 17 00:00:00 2001 From: iDawer Date: Fri, 2 Sep 2022 17:01:51 +0500 Subject: [PATCH 4081/5092] Add docs --- crates/hir-ty/src/inhabitedness.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/hir-ty/src/inhabitedness.rs b/crates/hir-ty/src/inhabitedness.rs index f3fe10c85754..0c547192ac0d 100644 --- a/crates/hir-ty/src/inhabitedness.rs +++ b/crates/hir-ty/src/inhabitedness.rs @@ -1,3 +1,4 @@ +//! Type inhabitedness logic. use std::ops::ControlFlow::{self, Break, Continue}; use chalk_ir::{ @@ -13,12 +14,14 @@ use crate::{ db::HirDatabase, Binders, ConcreteConst, Const, ConstValue, Interner, Substitution, Ty, TyKind, }; +/// Checks whether a type is visibly uninhabited from a particular module. pub(crate) fn is_ty_uninhabited_from(ty: &Ty, target_mod: ModuleId, db: &dyn HirDatabase) -> bool { let mut uninhabited_from = UninhabitedFrom { target_mod, db }; let inhabitedness = ty.visit_with(&mut uninhabited_from, DebruijnIndex::INNERMOST); inhabitedness == BREAK_VISIBLY_UNINHABITED } +/// Checks whether a variant is visibly uninhabited from a particular module. pub(crate) fn is_enum_variant_uninhabited_from( variant: EnumVariantId, subst: &Substitution, From 3fee843ebbe180b8be5ff403aefebb53e931d835 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 2 Sep 2022 13:32:16 +0100 Subject: [PATCH 4082/5092] Fix internal doc link The doc link from `DedupSortedIter` to `BTreeMap::bulk_build_from_sorted_iter` was broken when building internal documentation, --- library/alloc/src/collections/btree/dedup_sorted_iter.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/alloc/src/collections/btree/dedup_sorted_iter.rs b/library/alloc/src/collections/btree/dedup_sorted_iter.rs index 60bf83b8387c..17ee78045a9b 100644 --- a/library/alloc/src/collections/btree/dedup_sorted_iter.rs +++ b/library/alloc/src/collections/btree/dedup_sorted_iter.rs @@ -3,7 +3,9 @@ use core::iter::Peekable; /// A iterator for deduping the key of a sorted iterator. /// When encountering the duplicated key, only the last key-value pair is yielded. /// -/// Used by [`BTreeMap::bulk_build_from_sorted_iter`]. +/// Used by [`BTreeMap::bulk_build_from_sorted_iter`][1]. +/// +/// [1]: crate::collections::BTreeMap::bulk_build_from_sorted_iter pub struct DedupSortedIter where I: Iterator, From 2f348abafc697b65919073c6a36510a5b4fe0add Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 2 Sep 2022 14:38:52 +0200 Subject: [PATCH 4083/5092] Revert "disable extern-so ffi support for now due to licensing situation" This reverts commit 5f3545e773f930c3345e7166b98bf9d2a76adff6. With https://github.com/tov/libffi-rs/pull/58 landed, we no longer depend on abort_on_panic. --- Cargo.lock | 20 ++++++++++++++++++++ Cargo.toml | 2 +- README.md | 11 +++++++++++ src/shims/foreign_items.rs | 6 +++--- src/shims/mod.rs | 2 +- tests/compiletest.rs | 4 ++-- 6 files changed, 38 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a7303421808f..9df35ec0deb2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -308,6 +308,25 @@ version = "0.2.112" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" +[[package]] +name = "libffi" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e454b3efb16fba3b17810ae5e41df02b649e564ab3c5a34b3b93ed07ad287e6" +dependencies = [ + "libc", + "libffi-sys", +] + +[[package]] +name = "libffi-sys" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab4106b7f09d7b87d021334d5618fac1dfcfb824d4c5fe111ff0074dfd242e15" +dependencies = [ + "cc", +] + [[package]] name = "libloading" version = "0.7.3" @@ -392,6 +411,7 @@ dependencies = [ "getrandom", "lazy_static", "libc", + "libffi", "libloading", "log", "measureme", diff --git a/Cargo.toml b/Cargo.toml index c0a217b64116..0a3dfc2a84e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ doctest = false # and no doc tests [dependencies] getrandom = { version = "0.2", features = ["std"] } env_logger = "0.9" -#FIXME(miri#2526): libffi = "3.0.0" +libffi = "3.0.0" libloading = "0.7" log = "0.4" shell-escape = "0.1.4" diff --git a/README.md b/README.md index c7a3200dbd90..8e96338a865f 100644 --- a/README.md +++ b/README.md @@ -346,6 +346,17 @@ to Miri failing to detect cases of undefined behavior in a program. this flag is **unsound**. * `-Zmiri-disable-weak-memory-emulation` disables the emulation of some C++11 weak memory effects. +* `-Zmiri-extern-so-file=` is an experimental flag for providing support + for FFI calls. Functions not provided by that file are still executed via the usual Miri shims. + **WARNING**: If an invalid/incorrect `.so` file is specified, this can cause undefined behaviour in Miri itself! + And of course, Miri cannot do any checks on the actions taken by the external code. + Note that Miri has its own handling of file descriptors, so if you want to replace *some* functions + working on file descriptors, you will have to replace *all* of them, or the two kinds of + file descriptors will be mixed up. + This is **work in progress**; currently, only integer arguments and return values are + supported (and no, pointer/integer casts to work around this limitation will not work; + they will fail horribly). + Follow [the discussion on supporting other types](https://github.com/rust-lang/miri/issues/2365). * `-Zmiri-measureme=` enables `measureme` profiling for the interpreted program. This can be used to find which parts of your program are executing slowly under Miri. The profile is written out to a file with the prefix ``, and can be processed diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index bd46e4ae80e2..b94b6bbb2b8b 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -23,7 +23,7 @@ use rustc_target::{ use super::backtrace::EvalContextExt as _; use crate::helpers::{convert::Truncate, target_os_is_unix}; -//FIXME(miri#2526): use crate::shims::ffi_support::EvalContextExt as _; +use crate::shims::ffi_support::EvalContextExt as _; use crate::*; /// Returned by `emulate_foreign_item_by_name`. @@ -375,9 +375,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // An Ok(false) here means that the function being called was not exported // by the specified `.so` file; we should continue and check if it corresponds to // a provided shim. - /*FIXME(miri#2526): if this.call_external_c_fct(link_name, dest, args)? { + if this.call_external_c_fct(link_name, dest, args)? { return Ok(EmulateByNameResult::NeedsJumping); - }*/ + } } // When adding a new shim, you should follow the following pattern: diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 8179d09defe3..ee2145db7e1b 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -1,7 +1,7 @@ #![warn(clippy::integer_arithmetic)] mod backtrace; -//FIXME(miri#2526): pub mod ffi_support; +pub mod ffi_support; pub mod foreign_items; pub mod intrinsics; pub mod unix; diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 0e492c3eecdf..6b5668e2d6c4 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -212,8 +212,8 @@ fn main() -> Result<()> { ui(Mode::Panic, "tests/panic", WithDependencies)?; ui(Mode::Fail { require_patterns: true }, "tests/fail", WithDependencies)?; if cfg!(target_os = "linux") { - //FIXME(miri#2526): ui(Mode::Pass, "tests/extern-so/pass", WithoutDependencies)?; - //FIXME(miri#2526): ui(Mode::Fail { require_patterns: true }, "tests/extern-so/fail", WithDependencies)?; + ui(Mode::Pass, "tests/extern-so/pass", WithoutDependencies)?; + ui(Mode::Fail { require_patterns: true }, "tests/extern-so/fail", WithDependencies)?; } Ok(()) From fe0a10625633f5896bfe220e5ad75ec661a82007 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 2 Sep 2022 15:08:48 +0200 Subject: [PATCH 4084/5092] Don't store SyntheticSyntax in the reverse maps in BodySourceMap They are ZSTs which we can just create on missing access instead. --- crates/hir-def/src/body.rs | 8 ++++---- crates/hir-def/src/body/lower.rs | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs index 1d818d96267c..d572d46e8b01 100644 --- a/crates/hir-def/src/body.rs +++ b/crates/hir-def/src/body.rs @@ -264,10 +264,10 @@ pub type LabelSource = InFile; #[derive(Default, Debug, Eq, PartialEq)] pub struct BodySourceMap { expr_map: FxHashMap, - expr_map_back: ArenaMap>, + expr_map_back: ArenaMap, pat_map: FxHashMap, - pat_map_back: ArenaMap>, + pat_map_back: ArenaMap, label_map: FxHashMap, label_map_back: ArenaMap, @@ -420,7 +420,7 @@ impl Index for Body { // Perhaps `expr_syntax` and `expr_id`? impl BodySourceMap { pub fn expr_syntax(&self, expr: ExprId) -> Result { - self.expr_map_back[expr].clone() + self.expr_map_back.get(expr).cloned().ok_or(SyntheticSyntax) } pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option { @@ -434,7 +434,7 @@ impl BodySourceMap { } pub fn pat_syntax(&self, pat: PatId) -> Result { - self.pat_map_back[pat].clone() + self.pat_map_back.get(pat).cloned().ok_or(SyntheticSyntax) } pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option { diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index 8ebac5cb1c6c..df536e09fde3 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -24,7 +24,7 @@ use syntax::{ use crate::{ adt::StructKind, - body::{Body, BodySourceMap, Expander, LabelSource, PatPtr, SyntheticSyntax}, + body::{Body, BodySourceMap, Expander, LabelSource, PatPtr}, body::{BodyDiagnostic, ExprSource, PatSource}, builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint}, db::DefDatabase, @@ -152,19 +152,19 @@ impl ExprCollector<'_> { fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr) -> ExprId { let src = self.expander.to_source(ptr); - let id = self.make_expr(expr, Ok(src.clone())); + let id = self.make_expr(expr, src.clone()); self.source_map.expr_map.insert(src, id); id } // desugared exprs don't have ptr, that's wrong and should be fixed // somehow. fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId { - self.make_expr(expr, Err(SyntheticSyntax)) + self.body.exprs.alloc(expr) } fn missing_expr(&mut self) -> ExprId { self.alloc_expr_desugared(Expr::Missing) } - fn make_expr(&mut self, expr: Expr, src: Result) -> ExprId { + fn make_expr(&mut self, expr: Expr, src: ExprSource) -> ExprId { let id = self.body.exprs.alloc(expr); self.source_map.expr_map_back.insert(id, src); id @@ -172,14 +172,14 @@ impl ExprCollector<'_> { fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { let src = self.expander.to_source(ptr); - let id = self.make_pat(pat, Ok(src.clone())); + let id = self.make_pat(pat, src.clone()); self.source_map.pat_map.insert(src, id); id } fn missing_pat(&mut self) -> PatId { - self.make_pat(Pat::Missing, Err(SyntheticSyntax)) + self.body.pats.alloc(Pat::Missing) } - fn make_pat(&mut self, pat: Pat, src: Result) -> PatId { + fn make_pat(&mut self, pat: Pat, src: PatSource) -> PatId { let id = self.body.pats.alloc(pat); self.source_map.pat_map_back.insert(id, src); id From 017cfebcac9b04e34a782a2926af723026da3c03 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 2 Sep 2022 15:09:59 +0200 Subject: [PATCH 4085/5092] Remove unused .toggle-label CSS rule --- src/librustdoc/html/static/css/rustdoc.css | 6 ------ src/librustdoc/html/static/css/themes/ayu.css | 1 - src/librustdoc/html/static/css/themes/dark.css | 1 - src/librustdoc/html/static/css/themes/light.css | 1 - 4 files changed, 9 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index abbfecd84978..7409be2dbb9b 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1242,12 +1242,6 @@ h3.variant { margin-left: 24px; } -.toggle-label { - display: inline-block; - margin-left: 4px; - margin-top: 3px; -} - :target > code, :target > .code-header { opacity: 1; } diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css index e301a793282e..4f6dd645c272 100644 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -242,7 +242,6 @@ a.test-arrow:hover { color: #c5c5c5; } -.toggle-label, .code-attribute { color: #999; } diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css index d5cd47c3e19d..a37bbac5306a 100644 --- a/src/librustdoc/html/static/css/themes/dark.css +++ b/src/librustdoc/html/static/css/themes/dark.css @@ -197,7 +197,6 @@ a.test-arrow:hover{ background-color: #4e8bca; } -.toggle-label, .code-attribute { color: #999; } diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css index cff70268144f..3d8e866fdc61 100644 --- a/src/librustdoc/html/static/css/themes/light.css +++ b/src/librustdoc/html/static/css/themes/light.css @@ -182,7 +182,6 @@ a.test-arrow:hover{ background-color: #4e8bca; } -.toggle-label, .code-attribute { color: #999; } From e7b62be96b07534bd45decb18ec125a8d85542bb Mon Sep 17 00:00:00 2001 From: Quinn Painter Date: Fri, 2 Sep 2022 14:16:02 +0100 Subject: [PATCH 4086/5092] Add {thumb,arm}v5te-none-eabi targets --- .../src/spec/armv5te_none_eabi.rs | 50 +++++++++++++ compiler/rustc_target/src/spec/mod.rs | 2 + .../src/spec/thumbv5te_none_eabi.rs | 41 ++++++++++ src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/platform-support.md | 2 + .../src/platform-support/armv5te-none-eabi.md | 75 +++++++++++++++++++ 6 files changed, 171 insertions(+) create mode 100644 compiler/rustc_target/src/spec/armv5te_none_eabi.rs create mode 100644 compiler/rustc_target/src/spec/thumbv5te_none_eabi.rs create mode 100644 src/doc/rustc/src/platform-support/armv5te-none-eabi.md diff --git a/compiler/rustc_target/src/spec/armv5te_none_eabi.rs b/compiler/rustc_target/src/spec/armv5te_none_eabi.rs new file mode 100644 index 000000000000..c78928be0d29 --- /dev/null +++ b/compiler/rustc_target/src/spec/armv5te_none_eabi.rs @@ -0,0 +1,50 @@ +//! Targets the ARMv5TE, with code as `a32` code by default. + +use crate::spec::{ + cvs, LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOptions +}; + +pub fn target() -> Target { + Target { + llvm_target: "armv5te-none-eabi".into(), + pointer_width: 32, + arch: "arm".into(), + /* Data layout args are '-' separated: + * little endian + * stack is 64-bit aligned (EABI) + * pointers are 32-bit + * i64 must be 64-bit aligned (EABI) + * mangle names with ELF style + * native integers are 32-bit + * All other elements are default + */ + data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), + + options: TargetOptions { + abi: "eabi".into(), + linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), + linker: Some("rust-lld".into()), + // extra args passed to the external assembler (assuming `arm-none-eabi-as`): + // * activate t32/a32 interworking + // * use arch ARMv5TE + // * use little-endian + asm_args: cvs!["-mthumb-interwork", "-march=armv5te", "-mlittle-endian",], + // minimum extra features, these cannot be disabled via -C + // Also force-enable 32-bit atomics, which allows the use of atomic load/store only. + // The resulting atomics are ABI incompatible with atomics backed by libatomic. + features: "+soft-float,+strict-align,+atomics-32".into(), + main_needs_argc_argv: false, + // don't have atomic compare-and-swap + atomic_cas: false, + has_thumb_interworking: true, + relocation_model: RelocModel::Static, + panic_strategy: PanicStrategy::Abort, + // from thumb_base, rust-lang/rust#44993. + emit_debug_gdb_scripts: false, + // from thumb_base, apparently gcc/clang give enums a minimum of 8 bits on no-os targets + c_enum_min_bits: 8, + + ..Default::default() + }, + } +} diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 2459b0280cd6..6ddb50989b47 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1082,6 +1082,8 @@ supported_targets! { ("mipsel-unknown-none", mipsel_unknown_none), ("thumbv4t-none-eabi", thumbv4t_none_eabi), ("armv4t-none-eabi", armv4t_none_eabi), + ("thumbv5te-none-eabi", thumbv5te_none_eabi), + ("armv5te-none-eabi", armv5te_none_eabi), ("aarch64_be-unknown-linux-gnu", aarch64_be_unknown_linux_gnu), ("aarch64-unknown-linux-gnu_ilp32", aarch64_unknown_linux_gnu_ilp32), diff --git a/compiler/rustc_target/src/spec/thumbv5te_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv5te_none_eabi.rs new file mode 100644 index 000000000000..021b0e0eb622 --- /dev/null +++ b/compiler/rustc_target/src/spec/thumbv5te_none_eabi.rs @@ -0,0 +1,41 @@ +//! Targets the ARMv5TE, with code as `t32` code by default. + +use crate::spec::{cvs, FramePointer, Target, TargetOptions}; + +pub fn target() -> Target { + Target { + llvm_target: "thumbv5te-none-eabi".into(), + pointer_width: 32, + arch: "arm".into(), + /* Data layout args are '-' separated: + * little endian + * stack is 64-bit aligned (EABI) + * pointers are 32-bit + * i64 must be 64-bit aligned (EABI) + * mangle names with ELF style + * native integers are 32-bit + * All other elements are default + */ + data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(), + + options: TargetOptions { + abi: "eabi".into(), + // extra args passed to the external assembler (assuming `arm-none-eabi-as`): + // * activate t32/a32 interworking + // * use arch ARMv5TE + // * use little-endian + asm_args: cvs!["-mthumb-interwork", "-march=armv5te", "-mlittle-endian",], + // minimum extra features, these cannot be disabled via -C + // Also force-enable 32-bit atomics, which allows the use of atomic load/store only. + // The resulting atomics are ABI incompatible with atomics backed by libatomic. + features: "+soft-float,+strict-align,+atomics-32".into(), + frame_pointer: FramePointer::MayOmit, + main_needs_argc_argv: false, + // don't have atomic compare-and-swap + atomic_cas: false, + has_thumb_interworking: true, + + ..super::thumb_base::opts() + }, + } +} diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 4e6bc41daa71..1dcd2aaf79a3 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -19,6 +19,7 @@ - [\*-apple-watchos\*](platform-support/apple-watchos.md) - [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md) - [armv4t-none-eabi](platform-support/armv4t-none-eabi.md) + - [armv5te-none-eabi](platform-support/armv5te-none-eabi.md) - [armv6k-nintendo-3ds](platform-support/armv6k-nintendo-3ds.md) - [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md) - [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 742fbe11d9c6..b84e5f6c708e 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -225,6 +225,7 @@ target | std | host | notes [`arm64_32-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | ARM Apple WatchOS 64-bit with 32-bit pointers `armv4t-none-eabi` | * | | ARMv4T A32 `armv4t-unknown-linux-gnueabi` | ? | | +[`armv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | ARMv5TE A32 `armv5te-unknown-linux-uclibceabi` | ? | | ARMv5TE Linux with uClibc `armv6-unknown-freebsd` | ✓ | ✓ | ARMv6 FreeBSD `armv6-unknown-netbsd-eabihf` | ? | | @@ -291,6 +292,7 @@ target | std | host | notes `sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64 [`sparc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/sparc64 `thumbv4t-none-eabi` | * | | ARMv4T T32 +[`thumbv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | ARMv5TE T32 `thumbv7a-pc-windows-msvc` | ? | | `thumbv7a-uwp-windows-msvc` | ✓ | | `thumbv7neon-unknown-linux-musleabihf` | ? | | Thumb2-mode ARMv7a Linux with NEON, MUSL diff --git a/src/doc/rustc/src/platform-support/armv5te-none-eabi.md b/src/doc/rustc/src/platform-support/armv5te-none-eabi.md new file mode 100644 index 000000000000..e7e9aaba54bf --- /dev/null +++ b/src/doc/rustc/src/platform-support/armv5te-none-eabi.md @@ -0,0 +1,75 @@ +# `armv5te-none-eabi` + +**Tier: 3** + +Bare-metal target for any cpu in the ARMv5TE architecture family, supporting +ARM/Thumb code interworking (aka `a32`/`t32`), with ARM code as the default code +generation. + +The `thumbv5te-none-eabi` target is the same as this one, but with THUMB code as the default. + +In particular this supports the main CPU of the Nintendo DS, but there's nothing DS +specific with this target, so any ARMv5TE device should work fine. + +## Target Maintainers + +* [@QuinnPainter](https://github.com/QuinnPainter) + +## Requirements + +The target is cross-compiled, and uses static linking. + +By default, the `lld` linker included with Rust will be used. + +However, you may want to use the `arm-none-eabi-ld` linker instead. This can be obtained for Windows/Mac/Linux from the [ARM +Developer Website][arm-dev], or possibly from your OS's package manager. To use it, add the following to your `.cargo/config.toml`: + +```toml +[target.armv5te-none-eabi] +linker = "arm-none-eabi-ld" +``` + +[arm-dev]: https://developer.arm.com/Tools%20and%20Software/GNU%20Toolchain + +This target doesn't provide a linker script, you'll need to bring your own +according to the specific device you want to target. Pass +`-Clink-arg=-Tyour_script.ld` as a rustc argument to make the linker use +`your_script.ld` during linking. + +## Building Rust Programs + +Because it is Tier 3, rust does not yet ship pre-compiled artifacts for this target. + +Just use the `build-std` nightly cargo feature to build the `core` library. You +can pass this as a command line argument to cargo, or your `.cargo/config.toml` +file might include the following lines: + +```toml +[unstable] +build-std = ["core"] +``` + +Most of `core` should work as expected, with the following notes: +* the target is "soft float", so `f32` and `f64` operations are emulated in + software. +* integer division is also emulated in software. +* the target is old enough that it doesn't have atomic instructions. + +`alloc` is also supported, as long as you provide your own global allocator. + +Rust programs are output as ELF files. + +For running on DS hardware, you'll need to use an external tool to bundle this ELF file into an NDS binary. The `ndstool` utility included with devkitARM is one such tool that can do this for you: + +```shell +ndstool -c [out_nds] -9 [in_elf] +``` + +## Testing + +This is a cross-compiled target that you will need to emulate during testing. + +Because this is a device-agnostic target, and the exact emulator that you'll +need depends on the specific device you want to run your code on. + +For example, when programming for the DS, you can use one of the several available DS emulators, such as [melonDS](https://melonds.kuribo64.net/). From 7b0377c7164caf86a839bd701813c8ef7adab793 Mon Sep 17 00:00:00 2001 From: Quinn Painter Date: Fri, 2 Sep 2022 14:17:01 +0100 Subject: [PATCH 4087/5092] fix tidy --- compiler/rustc_target/src/spec/armv5te_none_eabi.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/rustc_target/src/spec/armv5te_none_eabi.rs b/compiler/rustc_target/src/spec/armv5te_none_eabi.rs index c78928be0d29..ad26f9ee356d 100644 --- a/compiler/rustc_target/src/spec/armv5te_none_eabi.rs +++ b/compiler/rustc_target/src/spec/armv5te_none_eabi.rs @@ -1,8 +1,6 @@ //! Targets the ARMv5TE, with code as `a32` code by default. -use crate::spec::{ - cvs, LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOptions -}; +use crate::spec::{cvs, LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOptions}; pub fn target() -> Target { Target { From bc793c9fb2ae45b1e93cdd6ad1cd4ffe30587674 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 2 Sep 2022 13:23:52 +0100 Subject: [PATCH 4088/5092] Use `BCRYPT_RNG_ALG_HANDLE` by default Also briefly document the history of `sys/windows/rand.rs` as they may be relevant to any future changes. --- library/std/src/sys/windows/c.rs | 2 +- library/std/src/sys/windows/rand.rs | 41 ++++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index c99c8efe4367..270294d13df3 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -285,7 +285,7 @@ pub fn nt_success(status: NTSTATUS) -> bool { status >= 0 } -pub const BCRYPT_USE_SYSTEM_PREFERRED_RNG: DWORD = 0x00000002; +pub const BCRYPT_RNG_ALG_HANDLE: usize = 0x81; #[repr(C)] pub struct UNICODE_STRING { diff --git a/library/std/src/sys/windows/rand.rs b/library/std/src/sys/windows/rand.rs index f8fd93a7398e..8b9697884364 100644 --- a/library/std/src/sys/windows/rand.rs +++ b/library/std/src/sys/windows/rand.rs @@ -1,16 +1,49 @@ +//! # Random key generation +//! +//! This module wraps the RNG provided by the OS. There are a few different +//! ways to interface with the OS RNG so it's worth exploring each of the options. +//! Note that at the time of writing these all go through the (undocumented) +//! `bcryptPrimitives.dll` but they use different route to get there. +//! +//! Originally we were using [`RtlGenRandom`], however that function is +//! deprecated and warns it "may be altered or unavailable in subsequent versions". +//! +//! So we switched to [`BCryptGenRandom`] with the `BCRYPT_USE_SYSTEM_PREFERRED_RNG` +//! flag to query and find the system configured RNG. However, this change caused a small +//! but significant number of users to experience panics caused by a failure of +//! this function. See [#94098]. +//! +//! The current version changes this to use the `BCRYPT_RNG_ALG_HANDLE` +//! [Pseudo-handle], which gets the default RNG algorithm without querying the +//! system preference thus hopefully avoiding the previous issue. +//! This is only supported on Windows 10+ so a fallback is used for older versions. +//! +//! [#94098]: https://github.com/rust-lang/rust/issues/94098 +//! [`RtlGenRandom`]: https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom +//! [`BCryptGenRandom`]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom +//! [Pseudo-handle]: https://docs.microsoft.com/en-us/windows/win32/seccng/cng-algorithm-pseudo-handles use crate::io; use crate::mem; use crate::ptr; use crate::sys::c; +/// Generates high quality secure random keys for use by [`HashMap`]. +/// +/// This is used to seed the default [`RandomState`]. +/// +/// [`HashMap`]: crate::collections::HashMap +/// [`RandomState`]: crate::collections::hash_map::RandomState pub fn hashmap_random_keys() -> (u64, u64) { let mut v = (0, 0); let ret = unsafe { + let size = mem::size_of_val(&v).try_into().unwrap(); c::BCryptGenRandom( - ptr::null_mut(), - &mut v as *mut _ as *mut u8, - mem::size_of_val(&v) as c::ULONG, - c::BCRYPT_USE_SYSTEM_PREFERRED_RNG, + // BCRYPT_RNG_ALG_HANDLE is only supported in Windows 10+. + // So for Windows 8.1 and Windows 7 we'll need a fallback when this fails. + ptr::invalid_mut(c::BCRYPT_RNG_ALG_HANDLE), + ptr::addr_of_mut!(v).cast(), + size, + 0, ) }; if ret != 0 { fallback_rng() } else { v } From 7155a2190ee515fb7c73b533e559f46c774a055b Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 2 Sep 2022 13:55:18 +0000 Subject: [PATCH 4089/5092] Rustup --- rust-version | 2 +- tests/pass/concurrency/sync_nopreempt.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 0909f24752ac..0b9f9bba0ad4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4fd4de7ea358ad6fc28c5780533ea8ccc09e1006 +9353538c7bea6edb245457712cec720305c4576e diff --git a/tests/pass/concurrency/sync_nopreempt.rs b/tests/pass/concurrency/sync_nopreempt.rs index a53f143fef67..83ecd72ce8da 100644 --- a/tests/pass/concurrency/sync_nopreempt.rs +++ b/tests/pass/concurrency/sync_nopreempt.rs @@ -16,7 +16,7 @@ fn check_conditional_variables_notify_all() { let (lock, cvar) = &*pair2; let guard = lock.lock().unwrap(); // Block waiting on the conditional variable. - let _ = cvar.wait(guard).unwrap(); + let _x = cvar.wait(guard).unwrap(); }) }) .inspect(|_| { From 6a29a6842ad6b650cb7cdbf823e3b732e8b9997a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 2 Sep 2022 13:55:26 +0000 Subject: [PATCH 4090/5092] Clippy after rustup --- cargo-miri/src/setup.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cargo-miri/src/setup.rs b/cargo-miri/src/setup.rs index 62d6e25a53e0..c27bb1863175 100644 --- a/cargo-miri/src/setup.rs +++ b/cargo-miri/src/setup.rs @@ -76,7 +76,7 @@ pub fn setup(subcommand: &MiriCommand, host: &str, target: &str) { show_error!("xargo is too old; please upgrade to the latest version") } let mut cmd = cargo(); - cmd.args(&["install", "xargo"]); + cmd.args(["install", "xargo"]); ask_to_run(cmd, ask_user, "install a recent enough xargo"); } @@ -93,7 +93,7 @@ pub fn setup(subcommand: &MiriCommand, host: &str, target: &str) { None => { // Check for `rust-src` rustup component. let output = miri_for_host() - .args(&["--print", "sysroot"]) + .args(["--print", "sysroot"]) .output() .expect("failed to determine sysroot"); if !output.status.success() { @@ -110,7 +110,7 @@ pub fn setup(subcommand: &MiriCommand, host: &str, target: &str) { if !rustup_src.join("std").join("Cargo.toml").exists() { // Ask the user to install the `rust-src` component, and use that. let mut cmd = Command::new("rustup"); - cmd.args(&["component", "add", "rust-src"]); + cmd.args(["component", "add", "rust-src"]); ask_to_run( cmd, ask_user, @@ -136,7 +136,7 @@ pub fn setup(subcommand: &MiriCommand, host: &str, target: &str) { let dirs = directories::ProjectDirs::from("org", "rust-lang", "miri").unwrap(); let dir = dirs.cache_dir(); if !dir.exists() { - fs::create_dir_all(&dir).unwrap(); + fs::create_dir_all(dir).unwrap(); } // The interesting bit: Xargo.toml (only needs content if we actually need std) let xargo_toml = if std::env::var_os("MIRI_NO_STD").is_some() { @@ -178,8 +178,8 @@ path = "lib.rs" // Now invoke xargo. let mut command = xargo_check(); command.arg("check").arg("-q"); - command.current_dir(&dir); - command.env("XARGO_HOME", &dir); + command.current_dir(dir); + command.env("XARGO_HOME", dir); command.env("XARGO_RUST_SRC", &rust_src); // We always need to set a target so rustc bootstrap can tell apart host from target crates. command.arg("--target").arg(target); From 169569cccb0882d3e94c82fc89ab34a34dda0604 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 2 Sep 2022 16:10:24 +0200 Subject: [PATCH 4091/5092] tweak variable name --- tests/pass/concurrency/sync_nopreempt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/pass/concurrency/sync_nopreempt.rs b/tests/pass/concurrency/sync_nopreempt.rs index 83ecd72ce8da..3da33fee4c0e 100644 --- a/tests/pass/concurrency/sync_nopreempt.rs +++ b/tests/pass/concurrency/sync_nopreempt.rs @@ -16,7 +16,7 @@ fn check_conditional_variables_notify_all() { let (lock, cvar) = &*pair2; let guard = lock.lock().unwrap(); // Block waiting on the conditional variable. - let _x = cvar.wait(guard).unwrap(); + let _guard = cvar.wait(guard).unwrap(); }) }) .inspect(|_| { From 532d5f2320758e37bb6e9f851c5bc507933733c9 Mon Sep 17 00:00:00 2001 From: Wojciech Kordalski Date: Fri, 2 Sep 2022 16:35:40 +0200 Subject: [PATCH 4092/5092] Fix `std::collections::HashSet::drain` documentation --- library/std/src/collections/hash/set.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index abff82788a38..5b6a415fadc1 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -239,7 +239,7 @@ impl HashSet { /// /// If the returned iterator is dropped before being fully consumed, it /// drops the remaining elements. The returned iterator keeps a mutable - /// borrow on the vector to optimize its implementation. + /// borrow on the set to optimize its implementation. /// /// # Examples /// From fe7e207e282d17cf1ab7a0bfad58600704f3f477 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 2 Sep 2022 16:49:38 +0200 Subject: [PATCH 4093/5092] update Miri --- Cargo.lock | 20 ++++++++++++++++++++ src/tools/miri | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 97a64feca1b7..08b377d82140 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1990,6 +1990,25 @@ dependencies = [ "rustc-std-workspace-core", ] +[[package]] +name = "libffi" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e454b3efb16fba3b17810ae5e41df02b649e564ab3c5a34b3b93ed07ad287e6" +dependencies = [ + "libc", + "libffi-sys", +] + +[[package]] +name = "libffi-sys" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab4106b7f09d7b87d021334d5618fac1dfcfb824d4c5fe111ff0074dfd242e15" +dependencies = [ + "cc", +] + [[package]] name = "libgit2-sys" version = "0.14.0+1.5.0" @@ -2284,6 +2303,7 @@ dependencies = [ "getrandom 0.2.0", "lazy_static", "libc", + "libffi", "libloading", "log", "measureme", diff --git a/src/tools/miri b/src/tools/miri index 8c8b479be723..dba35d2be72f 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit 8c8b479be723fb103b0b1203faf9246a3f587250 +Subproject commit dba35d2be72f4b78343d1a0f0b4737306f310672 From 8828049b2398b0df3bfc76d06bcf5154cdbe536a Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 2 Sep 2022 16:57:31 +0200 Subject: [PATCH 4094/5092] Lift out the module scope into a field in the Resolver A Resolver *always* has a module scope at the end of its scope stack, instead of encoding this as an invariant we can just lift this scope out into a field, allowing us to skip going through the scope vec indirection entirely. --- crates/hir-def/src/body.rs | 11 +- crates/hir-def/src/body/lower.rs | 6 +- crates/hir-def/src/body/scope.rs | 31 ++-- crates/hir-def/src/resolver.rs | 282 +++++++++++++++---------------- crates/hir-ty/src/autoderef.rs | 3 +- lib/la-arena/src/lib.rs | 37 ++++ 6 files changed, 211 insertions(+), 159 deletions(-) diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs index d572d46e8b01..22f5fb992663 100644 --- a/crates/hir-def/src/body.rs +++ b/crates/hir-def/src/body.rs @@ -250,6 +250,10 @@ pub type PatSource = InFile; pub type LabelPtr = AstPtr; pub type LabelSource = InFile; + +pub type FieldPtr = AstPtr; +pub type FieldSource = InFile; + /// An item body together with the mapping from syntax nodes to HIR expression /// IDs. This is needed to go from e.g. a position in a file to the HIR /// expression containing it; but for type inference etc., we want to operate on @@ -274,8 +278,8 @@ pub struct BodySourceMap { /// We don't create explicit nodes for record fields (`S { record_field: 92 }`). /// Instead, we use id of expression (`92`) to identify the field. - field_map: FxHashMap>, ExprId>, - field_map_back: FxHashMap>>, + field_map: FxHashMap, + field_map_back: FxHashMap, expansions: FxHashMap>, HirFileId>, @@ -456,9 +460,10 @@ impl BodySourceMap { self.label_map.get(&src).cloned() } - pub fn field_syntax(&self, expr: ExprId) -> InFile> { + pub fn field_syntax(&self, expr: ExprId) -> FieldSource { self.field_map_back[&expr].clone() } + pub fn node_field(&self, node: InFile<&ast::RecordExprField>) -> Option { let src = node.map(AstPtr::new); self.field_map.get(&src).cloned() diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index df536e09fde3..3b3297f7811c 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -24,7 +24,7 @@ use syntax::{ use crate::{ adt::StructKind, - body::{Body, BodySourceMap, Expander, LabelSource, PatPtr}, + body::{Body, BodySourceMap, Expander, ExprPtr, LabelPtr, LabelSource, PatPtr}, body::{BodyDiagnostic, ExprSource, PatSource}, builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint}, db::DefDatabase, @@ -150,7 +150,7 @@ impl ExprCollector<'_> { LowerCtx::new(self.db, self.expander.current_file_id) } - fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr) -> ExprId { + fn alloc_expr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId { let src = self.expander.to_source(ptr); let id = self.make_expr(expr, src.clone()); self.source_map.expr_map.insert(src, id); @@ -185,7 +185,7 @@ impl ExprCollector<'_> { id } - fn alloc_label(&mut self, label: Label, ptr: AstPtr) -> LabelId { + fn alloc_label(&mut self, label: Label, ptr: LabelPtr) -> LabelId { let src = self.expander.to_source(ptr); let id = self.make_label(label, src.clone()); self.source_map.label_map.insert(src, id); diff --git a/crates/hir-def/src/body/scope.rs b/crates/hir-def/src/body/scope.rs index 9b28e38029e0..45f64ebb0600 100644 --- a/crates/hir-def/src/body/scope.rs +++ b/crates/hir-def/src/body/scope.rs @@ -47,16 +47,9 @@ pub struct ScopeData { impl ExprScopes { pub(crate) fn expr_scopes_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc { let body = db.body(def); - Arc::new(ExprScopes::new(&*body)) - } - - fn new(body: &Body) -> ExprScopes { - let mut scopes = - ExprScopes { scopes: Arena::default(), scope_by_expr: FxHashMap::default() }; - let mut root = scopes.root_scope(); - scopes.add_params_bindings(body, root, &body.params); - compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root); - scopes + let mut scopes = ExprScopes::new(&*body); + scopes.shrink_to_fit(); + Arc::new(scopes) } pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { @@ -89,6 +82,17 @@ impl ExprScopes { pub fn scope_by_expr(&self) -> &FxHashMap { &self.scope_by_expr } +} + +impl ExprScopes { + fn new(body: &Body) -> ExprScopes { + let mut scopes = + ExprScopes { scopes: Arena::default(), scope_by_expr: FxHashMap::default() }; + let mut root = scopes.root_scope(); + scopes.add_params_bindings(body, root, &body.params); + compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root); + scopes + } fn root_scope(&mut self) -> ScopeId { self.scopes.alloc(ScopeData { parent: None, block: None, label: None, entries: vec![] }) @@ -138,6 +142,13 @@ impl ExprScopes { fn set_scope(&mut self, node: ExprId, scope: ScopeId) { self.scope_by_expr.insert(node, scope); } + + fn shrink_to_fit(&mut self) { + let ExprScopes { scopes, scope_by_expr } = self; + scopes.shrink_to_fit(); + scopes.values_mut().for_each(|it| it.entries.shrink_to_fit()); + scope_by_expr.shrink_to_fit(); + } } fn compute_block_scopes( diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index 3163fa0f93fa..769aa9dcb0ca 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -31,12 +31,10 @@ pub struct Resolver { /// /// When using, you generally want to process the scopes in reverse order, /// there's `scopes` *method* for that. - /// - /// Invariant: There exists at least one Scope::ModuleScope at the start of the vec. scopes: Vec, + module_scope: ModuleItemMap, } -// FIXME how to store these best #[derive(Debug, Clone)] struct ModuleItemMap { def_map: Arc, @@ -53,7 +51,7 @@ struct ExprScope { #[derive(Debug, Clone)] enum Scope { /// All the items and imported names of a module - ModuleScope(ModuleItemMap), + BlockScope(ModuleItemMap), /// Brings the generic parameters of an item into scope GenericParams { def: GenericDefId, params: Interned }, /// Brings `Self` in `impl` block into scope @@ -127,24 +125,6 @@ impl Resolver { } } - fn scopes(&self) -> impl Iterator { - self.scopes.iter().rev() - } - - fn resolve_module_path( - &self, - db: &dyn DefDatabase, - path: &ModPath, - shadow: BuiltinShadowMode, - ) -> PerNs { - let (item_map, module) = self.module_scope(); - let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow); - if segment_index.is_some() { - return PerNs::none(); - } - module_res - } - pub fn resolve_module_path_in_items(&self, db: &dyn DefDatabase, path: &ModPath) -> PerNs { self.resolve_module_path(db, path, BuiltinShadowMode::Module) } @@ -155,7 +135,7 @@ impl Resolver { db: &dyn DefDatabase, path: &ModPath, ) -> Option { - let (item_map, module) = self.module_scope(); + let (item_map, module) = self.item_scope(); let (module_res, idx) = item_map.resolve_path(db, module, path, BuiltinShadowMode::Module); match module_res.take_types()? { ModuleDefId::TraitId(it) => { @@ -183,37 +163,38 @@ impl Resolver { ) -> Option<(TypeNs, Option)> { let first_name = path.segments().first()?; let skip_to_mod = path.kind != PathKind::Plain; + if skip_to_mod { + return self.module_scope.resolve_path_in_type_ns(db, path); + } + + let remaining_idx = || if path.segments().len() == 1 { None } else { Some(1) }; + for scope in self.scopes() { match scope { Scope::ExprScope(_) => continue, - Scope::GenericParams { .. } | Scope::ImplDefScope(_) if skip_to_mod => continue, - Scope::GenericParams { params, def } => { if let Some(id) = params.find_type_by_name(first_name, *def) { - let idx = if path.segments().len() == 1 { None } else { Some(1) }; - return Some((TypeNs::GenericParam(id), idx)); + return Some((TypeNs::GenericParam(id), remaining_idx())); } } - Scope::ImplDefScope(impl_) => { + &Scope::ImplDefScope(impl_) => { if first_name == &name![Self] { - let idx = if path.segments().len() == 1 { None } else { Some(1) }; - return Some((TypeNs::SelfType(*impl_), idx)); + return Some((TypeNs::SelfType(impl_), remaining_idx())); } } - Scope::AdtScope(adt) => { + &Scope::AdtScope(adt) => { if first_name == &name![Self] { - let idx = if path.segments().len() == 1 { None } else { Some(1) }; - return Some((TypeNs::AdtSelfType(*adt), idx)); + return Some((TypeNs::AdtSelfType(adt), remaining_idx())); } } - Scope::ModuleScope(m) => { + Scope::BlockScope(m) => { if let Some(res) = m.resolve_path_in_type_ns(db, path) { return Some(res); } } } } - None + self.module_scope.resolve_path_in_type_ns(db, path) } pub fn resolve_path_in_type_ns_fully( @@ -235,7 +216,7 @@ impl Resolver { ) -> Option { match visibility { RawVisibility::Module(_) => { - let (item_map, module) = self.module_scope(); + let (item_map, module) = self.item_scope(); item_map.resolve_visibility(db, module, visibility) } RawVisibility::Public => Some(Visibility::Public), @@ -251,18 +232,14 @@ impl Resolver { let tmp = name![self]; let first_name = if path.is_self() { &tmp } else { path.segments().first()? }; let skip_to_mod = path.kind != PathKind::Plain && !path.is_self(); + if skip_to_mod { + return self.module_scope.resolve_path_in_value_ns(db, path); + } + for scope in self.scopes() { match scope { - Scope::AdtScope(_) - | Scope::ExprScope(_) - | Scope::GenericParams { .. } - | Scope::ImplDefScope(_) - if skip_to_mod => - { - continue - } - - Scope::ExprScope(scope) if n_segments <= 1 => { + Scope::ExprScope(_) if n_segments > 1 => continue, + Scope::ExprScope(scope) => { let entry = scope .expr_scopes .entries(scope.scope_id) @@ -273,44 +250,39 @@ impl Resolver { return Some(ResolveValueResult::ValueNs(ValueNs::LocalBinding(e.pat()))); } } - Scope::ExprScope(_) => continue, - Scope::GenericParams { params, def } if n_segments > 1 => { if let Some(id) = params.find_type_by_name(first_name, *def) { let ty = TypeNs::GenericParam(id); return Some(ResolveValueResult::Partial(ty, 1)); } } - Scope::GenericParams { params, def } if n_segments == 1 => { + Scope::GenericParams { .. } if n_segments != 1 => continue, + Scope::GenericParams { params, def } => { if let Some(id) = params.find_const_by_name(first_name, *def) { let val = ValueNs::GenericParam(id); return Some(ResolveValueResult::ValueNs(val)); } } - Scope::GenericParams { .. } => continue, - Scope::ImplDefScope(impl_) => { + &Scope::ImplDefScope(impl_) => { if first_name == &name![Self] { - if n_segments > 1 { - let ty = TypeNs::SelfType(*impl_); - return Some(ResolveValueResult::Partial(ty, 1)); + return Some(if n_segments > 1 { + ResolveValueResult::Partial(TypeNs::SelfType(impl_), 1) } else { - return Some(ResolveValueResult::ValueNs(ValueNs::ImplSelf(*impl_))); - } + ResolveValueResult::ValueNs(ValueNs::ImplSelf(impl_)) + }); } } + // bare `Self` doesn't work in the value namespace in a struct/enum definition + Scope::AdtScope(_) if n_segments == 1 => continue, Scope::AdtScope(adt) => { - if n_segments == 1 { - // bare `Self` doesn't work in the value namespace in a struct/enum definition - continue; - } if first_name == &name![Self] { let ty = TypeNs::AdtSelfType(*adt); return Some(ResolveValueResult::Partial(ty, 1)); } } - Scope::ModuleScope(m) => { + Scope::BlockScope(m) => { if let Some(def) = m.resolve_path_in_value_ns(db, path) { return Some(def); } @@ -318,15 +290,16 @@ impl Resolver { } } + if let res @ Some(_) = self.module_scope.resolve_path_in_value_ns(db, path) { + return res; + } + // If a path of the shape `u16::from_le_bytes` failed to resolve at all, then we fall back // to resolving to the primitive type, to allow this to still work in the presence of // `use core::u16;`. if path.kind == PathKind::Plain && path.segments().len() > 1 { - match BuiltinType::by_name(&path.segments()[0]) { - Some(builtin) => { - return Some(ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1)); - } - None => {} + if let Some(builtin) = BuiltinType::by_name(&path.segments()[0]) { + return Some(ResolveValueResult::Partial(TypeNs::BuiltinType(builtin), 1)); } } @@ -345,7 +318,7 @@ impl Resolver { } pub fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option { - let (item_map, module) = self.module_scope(); + let (item_map, module) = self.item_scope(); item_map.resolve_path(db, module, path, BuiltinShadowMode::Other).0.take_macros() } @@ -395,30 +368,34 @@ impl Resolver { for scope in self.scopes() { scope.process_names(&mut res, db); } + process_module_scope_names(&mut res, db, &self.module_scope); res.map } pub fn traits_in_scope(&self, db: &dyn DefDatabase) -> FxHashSet { let mut traits = FxHashSet::default(); + + let collect_module_traits = |traits: &mut FxHashSet<_>, m: &ModuleItemMap| { + if let Some(prelude) = m.def_map.prelude() { + let prelude_def_map = prelude.def_map(db); + traits.extend(prelude_def_map[prelude.local_id].scope.traits()); + } + traits.extend(m.def_map[m.module_id].scope.traits()); + + // Add all traits that are in scope because of the containing DefMaps + m.def_map.with_ancestor_maps(db, m.module_id, &mut |def_map, module| { + if let Some(prelude) = def_map.prelude() { + let prelude_def_map = prelude.def_map(db); + traits.extend(prelude_def_map[prelude.local_id].scope.traits()); + } + traits.extend(def_map[module].scope.traits()); + None::<()> + }); + }; + for scope in self.scopes() { match scope { - Scope::ModuleScope(m) => { - if let Some(prelude) = m.def_map.prelude() { - let prelude_def_map = prelude.def_map(db); - traits.extend(prelude_def_map[prelude.local_id].scope.traits()); - } - traits.extend(m.def_map[m.module_id].scope.traits()); - - // Add all traits that are in scope because of the containing DefMaps - m.def_map.with_ancestor_maps(db, m.module_id, &mut |def_map, module| { - if let Some(prelude) = def_map.prelude() { - let prelude_def_map = prelude.def_map(db); - traits.extend(prelude_def_map[prelude.local_id].scope.traits()); - } - traits.extend(def_map[module].scope.traits()); - None::<()> - }); - } + Scope::BlockScope(m) => collect_module_traits(&mut traits, m), &Scope::ImplDefScope(impl_) => { if let Some(target_trait) = &db.impl_data(impl_).target_trait { if let Some(TypeNs::TraitId(trait_)) = @@ -431,35 +408,22 @@ impl Resolver { _ => (), } } + + collect_module_traits(&mut traits, &self.module_scope); traits } - fn module_scope(&self) -> (&DefMap, LocalModuleId) { - self.scopes() - .find_map(|scope| match scope { - Scope::ModuleScope(m) => Some((&*m.def_map, m.module_id)), - _ => None, - }) - .expect("module scope invariant violated") - } - pub fn module(&self) -> ModuleId { - let (def_map, local_id) = self.module_scope(); + let (def_map, local_id) = self.item_scope(); def_map.module_id(local_id) } pub fn krate(&self) -> CrateId { - self.def_map().krate() + self.module_scope.def_map.krate() } pub fn def_map(&self) -> &DefMap { - self.scopes - .get(0) - .and_then(|scope| match scope { - Scope::ModuleScope(m) => Some(&m.def_map), - _ => None, - }) - .expect("module scope invariant violated") + self.item_scope().0 } pub fn where_predicates_in_scope( @@ -488,6 +452,36 @@ impl Resolver { } } +impl Resolver { + fn scopes(&self) -> impl Iterator { + self.scopes.iter().rev() + } + + fn resolve_module_path( + &self, + db: &dyn DefDatabase, + path: &ModPath, + shadow: BuiltinShadowMode, + ) -> PerNs { + let (item_map, module) = self.item_scope(); + let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow); + if segment_index.is_some() { + return PerNs::none(); + } + module_res + } + + /// The innermost block scope that contains items or the module scope that contains this resolver. + fn item_scope(&self) -> (&DefMap, LocalModuleId) { + self.scopes() + .find_map(|scope| match scope { + Scope::BlockScope(m) => Some((&*m.def_map, m.module_id)), + _ => None, + }) + .unwrap_or((&self.module_scope.def_map, self.module_scope.module_id)) + } +} + #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum ScopeDef { ModuleDef(ModuleDefId), @@ -499,41 +493,42 @@ pub enum ScopeDef { Label(LabelId), } +fn process_module_scope_names(acc: &mut ScopeNames, db: &dyn DefDatabase, m: &ModuleItemMap) { + // FIXME: should we provide `self` here? + // f( + // Name::self_param(), + // PerNs::types(Resolution::Def { + // def: m.module.into(), + // }), + // ); + m.def_map[m.module_id].scope.entries().for_each(|(name, def)| { + acc.add_per_ns(name, def); + }); + m.def_map[m.module_id].scope.legacy_macros().for_each(|(name, macs)| { + macs.iter().for_each(|&mac| { + acc.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(MacroId::from(mac)))); + }) + }); + m.def_map.extern_prelude().for_each(|(name, &def)| { + acc.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def))); + }); + if m.def_map.block_id().is_none() { + BUILTIN_SCOPE.iter().for_each(|(name, &def)| { + acc.add_per_ns(name, def); + }); + } + if let Some(prelude) = m.def_map.prelude() { + let prelude_def_map = prelude.def_map(db); + for (name, def) in prelude_def_map[prelude.local_id].scope.entries() { + acc.add_per_ns(name, def) + } + } +} + impl Scope { fn process_names(&self, acc: &mut ScopeNames, db: &dyn DefDatabase) { match self { - Scope::ModuleScope(m) => { - // FIXME: should we provide `self` here? - // f( - // Name::self_param(), - // PerNs::types(Resolution::Def { - // def: m.module.into(), - // }), - // ); - m.def_map[m.module_id].scope.entries().for_each(|(name, def)| { - acc.add_per_ns(name, def); - }); - m.def_map[m.module_id].scope.legacy_macros().for_each(|(name, macs)| { - macs.iter().for_each(|&mac| { - acc.add( - name, - ScopeDef::ModuleDef(ModuleDefId::MacroId(MacroId::from(mac))), - ); - }) - }); - m.def_map.extern_prelude().for_each(|(name, &def)| { - acc.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def))); - }); - BUILTIN_SCOPE.iter().for_each(|(name, &def)| { - acc.add_per_ns(name, def); - }); - if let Some(prelude) = m.def_map.prelude() { - let prelude_def_map = prelude.def_map(db); - for (name, def) in prelude_def_map[prelude.local_id].scope.entries() { - acc.add_per_ns(name, def) - } - } - } + Scope::BlockScope(m) => process_module_scope_names(acc, db, m), Scope::GenericParams { params, def: parent } => { let parent = *parent; for (local_id, param) in params.type_or_consts.iter() { @@ -596,7 +591,7 @@ pub fn resolver_for_scope( if let Some(block) = scopes.block(scope) { if let Some(def_map) = db.block_def_map(block) { let root = def_map.root(); - r = r.push_module_scope(def_map, root); + r = r.push_block_scope(def_map, root); // FIXME: This adds as many module scopes as there are blocks, but resolving in each // already traverses all parents, so this is O(n²). I think we could only store the // innermost module scope instead? @@ -623,8 +618,8 @@ impl Resolver { self.push_scope(Scope::ImplDefScope(impl_def)) } - fn push_module_scope(self, def_map: Arc, module_id: LocalModuleId) -> Resolver { - self.push_scope(Scope::ModuleScope(ModuleItemMap { def_map, module_id })) + fn push_block_scope(self, def_map: Arc, module_id: LocalModuleId) -> Resolver { + self.push_scope(Scope::BlockScope(ModuleItemMap { def_map, module_id })) } fn push_expr_scope( @@ -768,14 +763,19 @@ pub trait HasResolver: Copy { impl HasResolver for ModuleId { fn resolver(self, db: &dyn DefDatabase) -> Resolver { let mut def_map = self.def_map(db); - let mut modules: SmallVec<[_; 2]> = smallvec![(def_map.clone(), self.local_id)]; + let mut modules: SmallVec<[_; 1]> = smallvec![]; + let mut module_id = self.local_id; while let Some(parent) = def_map.parent() { + modules.push((def_map, module_id)); def_map = parent.def_map(db); - modules.push((def_map.clone(), parent.local_id)); + module_id = parent.local_id; } - let mut resolver = Resolver { scopes: Vec::with_capacity(modules.len()) }; + let mut resolver = Resolver { + scopes: Vec::with_capacity(modules.len()), + module_scope: ModuleItemMap { def_map, module_id }, + }; for (def_map, module) in modules.into_iter().rev() { - resolver = resolver.push_module_scope(def_map, module); + resolver = resolver.push_block_scope(def_map, module); } resolver } diff --git a/crates/hir-ty/src/autoderef.rs b/crates/hir-ty/src/autoderef.rs index b6f226dbfd20..344036dd8139 100644 --- a/crates/hir-ty/src/autoderef.rs +++ b/crates/hir-ty/src/autoderef.rs @@ -104,8 +104,7 @@ pub(crate) fn deref(table: &mut InferenceTable<'_>, ty: Ty) -> Option { fn builtin_deref(ty: &Ty) -> Option<&Ty> { match ty.kind(Interner) { - TyKind::Ref(.., ty) => Some(ty), - TyKind::Raw(.., ty) => Some(ty), + TyKind::Ref(.., ty) | TyKind::Raw(.., ty) => Some(ty), _ => None, } } diff --git a/lib/la-arena/src/lib.rs b/lib/la-arena/src/lib.rs index 50e8d06b6604..ccaaf3991769 100644 --- a/lib/la-arena/src/lib.rs +++ b/lib/la-arena/src/lib.rs @@ -322,6 +322,43 @@ impl Arena { .map(|(idx, value)| (Idx::from_raw(RawIdx(idx as u32)), value)) } + /// Returns an iterator over the arena’s values. + /// + /// ``` + /// let mut arena = la_arena::Arena::new(); + /// let idx1 = arena.alloc(20); + /// let idx2 = arena.alloc(40); + /// let idx3 = arena.alloc(60); + /// + /// let mut iterator = arena.values(); + /// assert_eq!(iterator.next(), Some(&20)); + /// assert_eq!(iterator.next(), Some(&40)); + /// assert_eq!(iterator.next(), Some(&60)); + /// ``` + pub fn values(&mut self) -> impl Iterator + ExactSizeIterator + DoubleEndedIterator { + self.data.iter() + } + + /// Returns an iterator over the arena’s mutable values. + /// + /// ``` + /// let mut arena = la_arena::Arena::new(); + /// let idx1 = arena.alloc(20); + /// + /// assert_eq!(arena[idx1], 20); + /// + /// let mut iterator = arena.values_mut(); + /// *iterator.next().unwrap() = 10; + /// drop(iterator); + /// + /// assert_eq!(arena[idx1], 10); + /// ``` + pub fn values_mut( + &mut self, + ) -> impl Iterator + ExactSizeIterator + DoubleEndedIterator { + self.data.iter_mut() + } + /// Reallocates the arena to make it take up as little space as possible. pub fn shrink_to_fit(&mut self) { self.data.shrink_to_fit(); From 1f2ece2096f9b4ffd8a26489e9a13f9aec70829d Mon Sep 17 00:00:00 2001 From: Alex <93376818+sashashura@users.noreply.github.com> Date: Fri, 2 Sep 2022 16:08:39 +0100 Subject: [PATCH 4095/5092] Update ci.yml Signed-off-by: sashashura <93376818+sashashura@users.noreply.github.com> --- src/ci/github-actions/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 6e4b0b0c2c3f..42ce0576d49e 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -264,6 +264,9 @@ on: branches: - "**" +permissions: + contents: read + defaults: run: # On Linux, macOS, and Windows, use the system-provided bash as the default From 894aa0ed0d181668ca33e4c5d2e08b4a49ae20d7 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 2 Sep 2022 17:43:20 +0200 Subject: [PATCH 4096/5092] Clarify the state of (extern) preludes for block def maps --- crates/hir-def/src/nameres.rs | 4 + crates/hir-def/src/nameres/collector.rs | 13 +-- crates/hir-def/src/resolver.rs | 103 +++++++++++------------- 3 files changed, 60 insertions(+), 60 deletions(-) diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs index fc8444394cf5..2e392f741bf2 100644 --- a/crates/hir-def/src/nameres.rs +++ b/crates/hir-def/src/nameres.rs @@ -98,7 +98,11 @@ pub struct DefMap { /// The prelude module for this crate. This either comes from an import /// marked with the `prelude_import` attribute, or (in the normal case) from /// a dependency (`std` or `core`). + /// The prelude is empty for non-block DefMaps (unless `#[prelude_import]` was used, + /// but that attribute is nightly and when used in a block, it affects resolution globally + /// so we aren't handling this correctly anyways). prelude: Option, + /// The extern prelude is only populated for non-block DefMaps extern_prelude: FxHashMap, /// Side table for resolving derive helpers. diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index ee27aa2554a3..495bbe4579f0 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -512,10 +512,9 @@ impl DefCollector<'_> { Edition::Edition2021 => name![rust_2021], }; - let path_kind = if self.def_map.edition == Edition::Edition2015 { - PathKind::Plain - } else { - PathKind::Abs + let path_kind = match self.def_map.edition { + Edition::Edition2015 => PathKind::Plain, + _ => PathKind::Abs, }; let path = ModPath::from_segments(path_kind, [krate.clone(), name![prelude], edition].into_iter()); @@ -535,7 +534,6 @@ impl DefCollector<'_> { match per_ns.types { Some((ModuleDefId::ModuleId(m), _)) => { self.def_map.prelude = Some(m); - return; } types => { tracing::debug!( @@ -850,7 +848,10 @@ impl DefCollector<'_> { tracing::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 - if import.is_extern_crate && module_id == self.def_map.root { + if import.is_extern_crate + && self.def_map.block.is_none() + && module_id == self.def_map.root + { if let (Some(ModuleDefId::ModuleId(def)), Some(name)) = (def.take_types(), name) { self.def_map.extern_prelude.insert(name.clone(), def); diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs index 769aa9dcb0ca..8aa5973cac57 100644 --- a/crates/hir-def/src/resolver.rs +++ b/crates/hir-def/src/resolver.rs @@ -368,34 +368,43 @@ impl Resolver { for scope in self.scopes() { scope.process_names(&mut res, db); } - process_module_scope_names(&mut res, db, &self.module_scope); + let ModuleItemMap { ref def_map, module_id } = self.module_scope; + // FIXME: should we provide `self` here? + // f( + // Name::self_param(), + // PerNs::types(Resolution::Def { + // def: m.module.into(), + // }), + // ); + def_map[module_id].scope.entries().for_each(|(name, def)| { + res.add_per_ns(name, def); + }); + def_map[module_id].scope.legacy_macros().for_each(|(name, macs)| { + macs.iter().for_each(|&mac| { + res.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(MacroId::from(mac)))); + }) + }); + def_map.extern_prelude().for_each(|(name, &def)| { + res.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def))); + }); + BUILTIN_SCOPE.iter().for_each(|(name, &def)| { + res.add_per_ns(name, def); + }); + if let Some(prelude) = def_map.prelude() { + let prelude_def_map = prelude.def_map(db); + for (name, def) in prelude_def_map[prelude.local_id].scope.entries() { + res.add_per_ns(name, def) + } + } res.map } pub fn traits_in_scope(&self, db: &dyn DefDatabase) -> FxHashSet { let mut traits = FxHashSet::default(); - let collect_module_traits = |traits: &mut FxHashSet<_>, m: &ModuleItemMap| { - if let Some(prelude) = m.def_map.prelude() { - let prelude_def_map = prelude.def_map(db); - traits.extend(prelude_def_map[prelude.local_id].scope.traits()); - } - traits.extend(m.def_map[m.module_id].scope.traits()); - - // Add all traits that are in scope because of the containing DefMaps - m.def_map.with_ancestor_maps(db, m.module_id, &mut |def_map, module| { - if let Some(prelude) = def_map.prelude() { - let prelude_def_map = prelude.def_map(db); - traits.extend(prelude_def_map[prelude.local_id].scope.traits()); - } - traits.extend(def_map[module].scope.traits()); - None::<()> - }); - }; - for scope in self.scopes() { match scope { - Scope::BlockScope(m) => collect_module_traits(&mut traits, m), + Scope::BlockScope(m) => traits.extend(m.def_map[m.module_id].scope.traits()), &Scope::ImplDefScope(impl_) => { if let Some(target_trait) = &db.impl_data(impl_).target_trait { if let Some(TypeNs::TraitId(trait_)) = @@ -409,7 +418,13 @@ impl Resolver { } } - collect_module_traits(&mut traits, &self.module_scope); + // Fill in the prelude traits + if let Some(prelude) = self.module_scope.def_map.prelude() { + let prelude_def_map = prelude.def_map(db); + traits.extend(prelude_def_map[prelude.local_id].scope.traits()); + } + // Fill in module visible traits + traits.extend(self.module_scope.def_map[self.module_scope.module_id].scope.traits()); traits } @@ -493,42 +508,22 @@ pub enum ScopeDef { Label(LabelId), } -fn process_module_scope_names(acc: &mut ScopeNames, db: &dyn DefDatabase, m: &ModuleItemMap) { - // FIXME: should we provide `self` here? - // f( - // Name::self_param(), - // PerNs::types(Resolution::Def { - // def: m.module.into(), - // }), - // ); - m.def_map[m.module_id].scope.entries().for_each(|(name, def)| { - acc.add_per_ns(name, def); - }); - m.def_map[m.module_id].scope.legacy_macros().for_each(|(name, macs)| { - macs.iter().for_each(|&mac| { - acc.add(name, ScopeDef::ModuleDef(ModuleDefId::MacroId(MacroId::from(mac)))); - }) - }); - m.def_map.extern_prelude().for_each(|(name, &def)| { - acc.add(name, ScopeDef::ModuleDef(ModuleDefId::ModuleId(def))); - }); - if m.def_map.block_id().is_none() { - BUILTIN_SCOPE.iter().for_each(|(name, &def)| { - acc.add_per_ns(name, def); - }); - } - if let Some(prelude) = m.def_map.prelude() { - let prelude_def_map = prelude.def_map(db); - for (name, def) in prelude_def_map[prelude.local_id].scope.entries() { - acc.add_per_ns(name, def) - } - } -} - impl Scope { fn process_names(&self, acc: &mut ScopeNames, db: &dyn DefDatabase) { match self { - Scope::BlockScope(m) => process_module_scope_names(acc, db, m), + Scope::BlockScope(m) => { + m.def_map[m.module_id].scope.entries().for_each(|(name, def)| { + acc.add_per_ns(name, def); + }); + m.def_map[m.module_id].scope.legacy_macros().for_each(|(name, macs)| { + macs.iter().for_each(|&mac| { + acc.add( + name, + ScopeDef::ModuleDef(ModuleDefId::MacroId(MacroId::from(mac))), + ); + }) + }); + } Scope::GenericParams { params, def: parent } => { let parent = *parent; for (local_id, param) in params.type_or_consts.iter() { From 301cc87abe1c732c0a7e9e9efe266fd0e10130fc Mon Sep 17 00:00:00 2001 From: Alex <93376818+sashashura@users.noreply.github.com> Date: Fri, 2 Sep 2022 17:37:17 +0100 Subject: [PATCH 4097/5092] Update ci.yml Signed-off-by: sashashura <93376818+sashashura@users.noreply.github.com> --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ec1ef041b206..9ebbc9c1c4bb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,6 +25,8 @@ name: CI pull_request: branches: - "**" +permissions: + contents: read defaults: run: shell: bash From bd70ccf915482503b193d8d53e00dcdc6197676a Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Fri, 2 Sep 2022 13:40:35 -0400 Subject: [PATCH 4098/5092] Don't use `hir_ty_to_ty` in `result_large_err` as it sometimes leaves late-bound lifetimes. --- clippy_lints/src/functions/result.rs | 10 +++++----- tests/ui/crashes/ice-9414.rs | 8 ++++++++ 2 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 tests/ui/crashes/ice-9414.rs diff --git a/clippy_lints/src/functions/result.rs b/clippy_lints/src/functions/result.rs index af520a493eda..9591405cb06f 100644 --- a/clippy_lints/src/functions/result.rs +++ b/clippy_lints/src/functions/result.rs @@ -4,7 +4,6 @@ use rustc_lint::{LateContext, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; use rustc_span::{sym, Span}; -use rustc_typeck::hir_ty_to_ty; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; use clippy_utils::trait_ref_of_method; @@ -17,11 +16,12 @@ use super::{RESULT_LARGE_ERR, RESULT_UNIT_ERR}; fn result_err_ty<'tcx>( cx: &LateContext<'tcx>, decl: &hir::FnDecl<'tcx>, + id: hir::def_id::LocalDefId, item_span: Span, ) -> Option<(&'tcx hir::Ty<'tcx>, Ty<'tcx>)> { if !in_external_macro(cx.sess(), item_span) && let hir::FnRetTy::Return(hir_ty) = decl.output - && let ty = hir_ty_to_ty(cx.tcx, hir_ty) + && let ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).output()) && is_type_diagnostic_item(cx, ty, sym::Result) && let ty::Adt(_, substs) = ty.kind() { @@ -34,7 +34,7 @@ fn result_err_ty<'tcx>( pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, large_err_threshold: u64) { if let hir::ItemKind::Fn(ref sig, _generics, _) = item.kind - && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.span) + && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id, item.span) { if cx.access_levels.is_exported(item.def_id) { let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); @@ -47,7 +47,7 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, l pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::ImplItem<'tcx>, large_err_threshold: u64) { // Don't lint if method is a trait's implementation, we can't do anything about those if let hir::ImplItemKind::Fn(ref sig, _) = item.kind - && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.span) + && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id, item.span) && trait_ref_of_method(cx, item.def_id).is_none() { if cx.access_levels.is_exported(item.def_id) { @@ -61,7 +61,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::ImplItem pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::TraitItem<'tcx>, large_err_threshold: u64) { if let hir::TraitItemKind::Fn(ref sig, _) = item.kind { let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); - if let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.span) { + if let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id, item.span) { if cx.access_levels.is_exported(item.def_id) { check_result_unit_err(cx, err_ty, fn_header_span); } diff --git a/tests/ui/crashes/ice-9414.rs b/tests/ui/crashes/ice-9414.rs new file mode 100644 index 000000000000..02cf5d5c240f --- /dev/null +++ b/tests/ui/crashes/ice-9414.rs @@ -0,0 +1,8 @@ +#![warn(clippy::result_large_err)] + +trait T {} +fn f(_: &u32) -> Result<(), *const (dyn '_ + T)> { + Ok(()) +} + +fn main() {} From 02ba216e3cb6edd4a51e0738953a4276aa84fa20 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 30 Aug 2022 17:34:35 -0500 Subject: [PATCH 4099/5092] Refactor and re-use BindingAnnotation --- compiler/rustc_ast/src/ast.rs | 81 +++++++++++++------ compiler/rustc_ast_lowering/src/expr.rs | 6 +- compiler/rustc_ast_lowering/src/item.rs | 11 +-- compiler/rustc_ast_lowering/src/lib.rs | 7 +- compiler/rustc_ast_lowering/src/pat.rs | 27 +++---- .../rustc_ast_passes/src/ast_validation.rs | 4 +- compiler/rustc_ast_pretty/src/pprust/state.rs | 26 +++--- .../src/diagnostics/mutability_errors.rs | 2 +- .../src/deriving/generic/mod.rs | 28 ++++--- compiler/rustc_expand/src/build.rs | 10 +-- compiler/rustc_hir/src/hir.rs | 26 +----- compiler/rustc_hir/src/pat_util.rs | 13 +-- compiler/rustc_hir_pretty/src/lib.rs | 24 +++--- compiler/rustc_lint/src/builtin.rs | 13 +-- compiler/rustc_lint/src/unused.rs | 6 +- compiler/rustc_middle/src/ty/binding.rs | 14 ++-- .../rustc_parse/src/parser/diagnostics.rs | 10 +-- compiler/rustc_parse/src/parser/item.rs | 4 +- compiler/rustc_parse/src/parser/pat.rs | 42 +++++----- compiler/rustc_passes/src/naked_functions.rs | 2 +- compiler/rustc_resolve/src/late.rs | 14 ++-- compiler/rustc_save_analysis/src/lib.rs | 15 +--- .../src/traits/error_reporting/suggestions.rs | 2 +- compiler/rustc_typeck/src/check/pat.rs | 6 +- compiler/rustc_typeck/src/check/region.rs | 8 +- 25 files changed, 176 insertions(+), 225 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 3af6dee9e43f..f05f58d63a38 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -594,7 +594,7 @@ impl Pat { // In a type expression `_` is an inference variable. PatKind::Wild => TyKind::Infer, // An IDENT pattern with no binding mode would be valid as path to a type. E.g. `u32`. - PatKind::Ident(BindingMode::ByValue(Mutability::Not), ident, None) => { + PatKind::Ident(BindingAnnotation::NONE, ident, None) => { TyKind::Path(None, Path::from_ident(*ident)) } PatKind::Path(qself, path) => TyKind::Path(qself.clone(), path.clone()), @@ -681,10 +681,43 @@ pub struct PatField { pub is_placeholder: bool, } -#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy)] -pub enum BindingMode { - ByRef(Mutability), - ByValue(Mutability), +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Encodable, Decodable, HashStable_Generic)] +pub enum ByRef { + Yes, + No, +} + +impl From for ByRef { + fn from(b: bool) -> ByRef { + match b { + false => ByRef::No, + true => ByRef::Yes, + } + } +} + +/// Explicit binding annotations given in the HIR for a binding. Note +/// that this is not the final binding *mode* that we infer after type +/// inference. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Encodable, Decodable, HashStable_Generic)] +pub struct BindingAnnotation(pub ByRef, pub Mutability); + +impl BindingAnnotation { + pub const NONE: Self = Self(ByRef::No, Mutability::Not); + pub const REF: Self = Self(ByRef::Yes, Mutability::Not); + pub const MUT: Self = Self(ByRef::No, Mutability::Mut); + pub const REF_MUT: Self = Self(ByRef::Yes, Mutability::Mut); + + pub fn prefix_str(self) -> &'static str { + match self { + Self::NONE => "", + Self::REF => "ref ", + Self::MUT => "mut ", + Self::REF_MUT => "ref mut ", + } + } } #[derive(Clone, Encodable, Decodable, Debug)] @@ -713,7 +746,7 @@ pub enum PatKind { /// or a unit struct/variant pattern, or a const pattern (in the last two cases the third /// field must be `None`). Disambiguation cannot be done with parser alone, so it happens /// during name resolution. - Ident(BindingMode, Ident, Option>), + Ident(BindingAnnotation, Ident, Option>), /// A struct or struct variant pattern (e.g., `Variant {x, y, ..}`). /// The `bool` is `true` in the presence of a `..`. @@ -2228,7 +2261,7 @@ pub type ExplicitSelf = Spanned; impl Param { /// Attempts to cast parameter to `ExplicitSelf`. pub fn to_self(&self) -> Option { - if let PatKind::Ident(BindingMode::ByValue(mutbl), ident, _) = self.pat.kind { + if let PatKind::Ident(BindingAnnotation(ByRef::No, mutbl), ident, _) = self.pat.kind { if ident.name == kw::SelfLower { return match self.ty.kind { TyKind::ImplicitSelf => Some(respan(self.pat.span, SelfKind::Value(mutbl))), @@ -2258,23 +2291,10 @@ impl Param { pub fn from_self(attrs: AttrVec, eself: ExplicitSelf, eself_ident: Ident) -> Param { let span = eself.span.to(eself_ident.span); let infer_ty = P(Ty { id: DUMMY_NODE_ID, kind: TyKind::ImplicitSelf, span, tokens: None }); - let param = |mutbl, ty| Param { - attrs, - pat: P(Pat { - id: DUMMY_NODE_ID, - kind: PatKind::Ident(BindingMode::ByValue(mutbl), eself_ident, None), - span, - tokens: None, - }), - span, - ty, - id: DUMMY_NODE_ID, - is_placeholder: false, - }; - match eself.node { - SelfKind::Explicit(ty, mutbl) => param(mutbl, ty), - SelfKind::Value(mutbl) => param(mutbl, infer_ty), - SelfKind::Region(lt, mutbl) => param( + let (mutbl, ty) = match eself.node { + SelfKind::Explicit(ty, mutbl) => (mutbl, ty), + SelfKind::Value(mutbl) => (mutbl, infer_ty), + SelfKind::Region(lt, mutbl) => ( Mutability::Not, P(Ty { id: DUMMY_NODE_ID, @@ -2283,6 +2303,19 @@ impl Param { tokens: None, }), ), + }; + Param { + attrs, + pat: P(Pat { + id: DUMMY_NODE_ID, + kind: PatKind::Ident(BindingAnnotation(ByRef::No, mutbl), eself_ident, None), + span, + tokens: None, + }), + span, + ty, + id: DUMMY_NODE_ID, + is_placeholder: false, } } } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 7df3520422c1..7d3f839c922e 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -577,7 +577,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (pat, task_context_hid) = self.pat_ident_binding_mode( span, Ident::with_dummy_span(sym::_task_context), - hir::BindingAnnotation::Mutable, + hir::BindingAnnotation::MUT, ); let param = hir::Param { hir_id: self.next_id(), @@ -671,7 +671,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // this name to identify what is being awaited by a suspended async functions. let awaitee_ident = Ident::with_dummy_span(sym::__awaitee); let (awaitee_pat, awaitee_pat_hid) = - self.pat_ident_binding_mode(span, awaitee_ident, hir::BindingAnnotation::Mutable); + self.pat_ident_binding_mode(span, awaitee_ident, hir::BindingAnnotation::MUT); let task_context_ident = Ident::with_dummy_span(sym::_task_context); @@ -1433,7 +1433,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // `mut iter` let iter = Ident::with_dummy_span(sym::iter); let (iter_pat, iter_pat_nid) = - self.pat_ident_binding_mode(head_span, iter, hir::BindingAnnotation::Mutable); + self.pat_ident_binding_mode(head_span, iter, hir::BindingAnnotation::MUT); // `match Iterator::next(&mut iter) { ... }` let match_expr = { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index fd338ffc0c5e..810ee6eb76db 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1074,12 +1074,9 @@ impl<'hir> LoweringContext<'_, 'hir> { // Check if this is a binding pattern, if so, we can optimize and avoid adding a // `let = __argN;` statement. In this case, we do not rename the parameter. let (ident, is_simple_parameter) = match parameter.pat.kind { - hir::PatKind::Binding( - hir::BindingAnnotation::Unannotated | hir::BindingAnnotation::Mutable, - _, - ident, - _, - ) => (ident, true), + hir::PatKind::Binding(hir::BindingAnnotation(ByRef::No, _), _, ident, _) => { + (ident, true) + } // For `ref mut` or wildcard arguments, we can't reuse the binding, but // we can keep the same name for the parameter. // This lets rustdoc render it correctly in documentation. @@ -1144,7 +1141,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (move_pat, move_id) = this.pat_ident_binding_mode( desugared_span, ident, - hir::BindingAnnotation::Mutable, + hir::BindingAnnotation::MUT, ); let move_expr = this.expr_ident(desugared_span, ident, new_parameter_id); let move_stmt = this.stmt_let_pat( diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 9a960356a85f..62ea49e8df9d 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1696,10 +1696,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { output, c_variadic, implicit_self: decl.inputs.get(0).map_or(hir::ImplicitSelfKind::None, |arg| { - use BindingMode::{ByRef, ByValue}; let is_mutable_pat = matches!( arg.pat.kind, - PatKind::Ident(ByValue(Mutability::Mut) | ByRef(Mutability::Mut), ..) + PatKind::Ident(hir::BindingAnnotation(_, Mutability::Mut), ..) ); match arg.ty.kind { @@ -2361,11 +2360,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn pat_ident(&mut self, span: Span, ident: Ident) -> (&'hir hir::Pat<'hir>, hir::HirId) { - self.pat_ident_binding_mode(span, ident, hir::BindingAnnotation::Unannotated) + self.pat_ident_binding_mode(span, ident, hir::BindingAnnotation::NONE) } fn pat_ident_mut(&mut self, span: Span, ident: Ident) -> (hir::Pat<'hir>, hir::HirId) { - self.pat_ident_binding_mode_mut(span, ident, hir::BindingAnnotation::Unannotated) + self.pat_ident_binding_mode_mut(span, ident, hir::BindingAnnotation::NONE) } fn pat_ident_binding_mode( diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 1efa19a3a828..c185a0d31bd4 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -24,7 +24,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let node = loop { match pattern.kind { PatKind::Wild => break hir::PatKind::Wild, - PatKind::Ident(ref binding_mode, ident, ref sub) => { + PatKind::Ident(binding_mode, ident, ref sub) => { let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(&*s)); break self.lower_pat_ident(pattern, binding_mode, ident, lower_sub); } @@ -176,9 +176,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let mut prev_rest_span = None; // Lowers `$bm $ident @ ..` to `$bm $ident @ _`. - let lower_rest_sub = |this: &mut Self, pat, bm, ident, sub| { + let lower_rest_sub = |this: &mut Self, pat, ann, ident, sub| { let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub)); - let node = this.lower_pat_ident(pat, bm, ident, lower_sub); + let node = this.lower_pat_ident(pat, ann, ident, lower_sub); this.pat_with_node_id_of(pat, node) }; @@ -194,9 +194,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } // Found a sub-slice pattern `$binding_mode $ident @ ..`. // Record, lower it to `$binding_mode $ident @ _`, and stop here. - PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => { + PatKind::Ident(ann, ident, Some(ref sub)) if sub.is_rest() => { prev_rest_span = Some(sub.span); - slice = Some(self.arena.alloc(lower_rest_sub(self, pat, bm, ident, sub))); + slice = Some(self.arena.alloc(lower_rest_sub(self, pat, ann, ident, sub))); break; } // It was not a subslice pattern so lower it normally. @@ -209,9 +209,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // There was a previous subslice pattern; make sure we don't allow more. let rest_span = match pat.kind { PatKind::Rest => Some(pat.span), - PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => { + PatKind::Ident(ann, ident, Some(ref sub)) if sub.is_rest() => { // #69103: Lower into `binding @ _` as above to avoid ICEs. - after.push(lower_rest_sub(self, pat, bm, ident, sub)); + after.push(lower_rest_sub(self, pat, ann, ident, sub)); Some(sub.span) } _ => None, @@ -235,7 +235,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_pat_ident( &mut self, p: &Pat, - binding_mode: &BindingMode, + annotation: BindingAnnotation, ident: Ident, lower_sub: impl FnOnce(&mut Self) -> Option<&'hir hir::Pat<'hir>>, ) -> hir::PatKind<'hir> { @@ -248,7 +248,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; hir::PatKind::Binding( - self.lower_binding_mode(binding_mode), + annotation, self.lower_node_id(canonical_id), self.lower_ident(ident), lower_sub(self), @@ -265,15 +265,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - fn lower_binding_mode(&mut self, b: &BindingMode) -> hir::BindingAnnotation { - match *b { - BindingMode::ByValue(Mutability::Not) => hir::BindingAnnotation::Unannotated, - BindingMode::ByRef(Mutability::Not) => hir::BindingAnnotation::Ref, - BindingMode::ByValue(Mutability::Mut) => hir::BindingAnnotation::Mutable, - BindingMode::ByRef(Mutability::Mut) => hir::BindingAnnotation::RefMut, - } - } - fn pat_wild_with_node_id_of(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> { self.arena.alloc(self.pat_with_node_id_of(p, hir::PatKind::Wild)) } diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 23464bf0a5a2..d6d8881a53a1 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -281,8 +281,8 @@ impl<'a> AstValidator<'a> { fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option, bool)) { for Param { pat, .. } in &decl.inputs { match pat.kind { - PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None) | PatKind::Wild => {} - PatKind::Ident(BindingMode::ByValue(Mutability::Mut), ident, None) => { + PatKind::Ident(BindingAnnotation::NONE, _, None) | PatKind::Wild => {} + PatKind::Ident(BindingAnnotation::MUT, ident, None) => { report_err(pat.span, Some(ident), true) } _ => report_err(pat.span, None, false), diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 8749a13c5dde..ed5e7dace4bc 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -11,8 +11,8 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::util::classify; use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle}; use rustc_ast::util::parser; -use rustc_ast::{self as ast, BlockCheckMode, PatKind, RangeEnd, RangeSyntax}; -use rustc_ast::{attr, Term}; +use rustc_ast::{self as ast, BlockCheckMode, Mutability, PatKind, RangeEnd, RangeSyntax}; +use rustc_ast::{attr, BindingAnnotation, ByRef, Term}; use rustc_ast::{GenericArg, MacArgs, MacArgsEq}; use rustc_ast::{GenericBound, SelfKind, TraitBoundModifier}; use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass}; @@ -1399,16 +1399,12 @@ impl<'a> State<'a> { is that it doesn't matter */ match pat.kind { PatKind::Wild => self.word("_"), - PatKind::Ident(binding_mode, ident, ref sub) => { - match binding_mode { - ast::BindingMode::ByRef(mutbl) => { - self.word_nbsp("ref"); - self.print_mutability(mutbl, false); - } - ast::BindingMode::ByValue(ast::Mutability::Not) => {} - ast::BindingMode::ByValue(ast::Mutability::Mut) => { - self.word_nbsp("mut"); - } + PatKind::Ident(BindingAnnotation(by_ref, mutbl), ident, ref sub) => { + if by_ref == ByRef::Yes { + self.word_nbsp("ref"); + } + if mutbl == Mutability::Mut { + self.word_nbsp("mut"); } self.print_ident(ident); if let Some(ref p) = *sub { @@ -1487,12 +1483,10 @@ impl<'a> State<'a> { } PatKind::Ref(ref inner, mutbl) => { self.word("&"); - if mutbl == ast::Mutability::Mut { + if mutbl == Mutability::Mut { self.word("mut "); } - if let PatKind::Ident(ast::BindingMode::ByValue(ast::Mutability::Mut), ..) = - inner.kind - { + if let PatKind::Ident(ast::BindingAnnotation::MUT, ..) = inner.kind { self.popen(); self.print_pat(inner); self.pclose(); diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index dd9590016b99..e2db7f3ead1a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -367,7 +367,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if let Some(Node::Pat(pat)) = self.infcx.tcx.hir().find(upvar_hir_id) && let hir::PatKind::Binding( - hir::BindingAnnotation::Unannotated, + hir::BindingAnnotation::NONE, _, upvar_ident, _, diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index adffebd3fd28..3cc160adb539 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -164,7 +164,9 @@ pub use SubstructureFields::*; use crate::deriving; use rustc_ast::ptr::P; -use rustc_ast::{self as ast, EnumDef, Expr, Generics, PatKind}; +use rustc_ast::{ + self as ast, BindingAnnotation, ByRef, EnumDef, Expr, Generics, Mutability, PatKind, +}; use rustc_ast::{GenericArg, GenericParamKind, VariantData}; use rustc_attr as attr; use rustc_expand::base::{Annotatable, ExtCtxt}; @@ -1063,9 +1065,9 @@ impl<'a> MethodDef<'a> { let mut body = mk_body(cx, selflike_fields); let struct_path = cx.path(span, vec![Ident::new(kw::SelfUpper, type_ident.span)]); - let use_ref_pat = is_packed && !always_copy; + let by_ref = ByRef::from(is_packed && !always_copy); let patterns = - trait_.create_struct_patterns(cx, struct_path, struct_def, &prefixes, use_ref_pat); + trait_.create_struct_patterns(cx, struct_path, struct_def, &prefixes, by_ref); // Do the let-destructuring. let mut stmts: Vec<_> = iter::zip(selflike_args, patterns) @@ -1247,13 +1249,13 @@ impl<'a> MethodDef<'a> { let sp = variant.span.with_ctxt(trait_.span.ctxt()); let variant_path = cx.path(sp, vec![type_ident, variant.ident]); - let use_ref_pat = false; // because enums can't be repr(packed) + let by_ref = ByRef::No; // because enums can't be repr(packed) let mut subpats: Vec<_> = trait_.create_struct_patterns( cx, variant_path, &variant.data, &prefixes, - use_ref_pat, + by_ref, ); // `(VariantK, VariantK, ...)` or just `VariantK`. @@ -1414,7 +1416,7 @@ impl<'a> TraitDef<'a> { struct_path: ast::Path, struct_def: &'a VariantData, prefixes: &[String], - use_ref_pat: bool, + by_ref: ByRef, ) -> Vec> { prefixes .iter() @@ -1422,17 +1424,19 @@ impl<'a> TraitDef<'a> { let pieces_iter = struct_def.fields().iter().enumerate().map(|(i, struct_field)| { let sp = struct_field.span.with_ctxt(self.span.ctxt()); - let binding_mode = if use_ref_pat { - ast::BindingMode::ByRef(ast::Mutability::Not) - } else { - ast::BindingMode::ByValue(ast::Mutability::Not) - }; let ident = self.mk_pattern_ident(prefix, i); let path = ident.with_span_pos(sp); ( sp, struct_field.ident, - cx.pat(path.span, PatKind::Ident(binding_mode, path, None)), + cx.pat( + path.span, + PatKind::Ident( + BindingAnnotation(by_ref, Mutability::Not), + path, + None, + ), + ), ) }); diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index c4890b4a9c41..cf2c023c2f89 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -178,8 +178,7 @@ impl<'a> ExtCtxt<'a> { ex: P, ) -> ast::Stmt { let pat = if mutbl { - let binding_mode = ast::BindingMode::ByValue(ast::Mutability::Mut); - self.pat_ident_binding_mode(sp, ident, binding_mode) + self.pat_ident_binding_mode(sp, ident, ast::BindingAnnotation::MUT) } else { self.pat_ident(sp, ident) }; @@ -445,17 +444,16 @@ impl<'a> ExtCtxt<'a> { self.pat(span, PatKind::Lit(expr)) } pub fn pat_ident(&self, span: Span, ident: Ident) -> P { - let binding_mode = ast::BindingMode::ByValue(ast::Mutability::Not); - self.pat_ident_binding_mode(span, ident, binding_mode) + self.pat_ident_binding_mode(span, ident, ast::BindingAnnotation::NONE) } pub fn pat_ident_binding_mode( &self, span: Span, ident: Ident, - bm: ast::BindingMode, + ann: ast::BindingAnnotation, ) -> P { - let pat = PatKind::Ident(bm, ident.with_span_pos(span), None); + let pat = PatKind::Ident(ann, ident.with_span_pos(span), None); self.pat(span, pat) } pub fn pat_path(&self, span: Span, path: ast::Path) -> P { diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index a069c49b0cc1..34c4f0bc273f 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -7,7 +7,7 @@ use crate::LangItem; use rustc_ast as ast; use rustc_ast::util::parser::ExprPrecedence; use rustc_ast::{Attribute, FloatTy, IntTy, Label, LitKind, TraitObjectSyntax, UintTy}; -pub use rustc_ast::{BorrowKind, ImplPolarity, IsAuto}; +pub use rustc_ast::{BindingAnnotation, BorrowKind, ByRef, ImplPolarity, IsAuto}; pub use rustc_ast::{CaptureBy, Movability, Mutability}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_data_structures::fingerprint::Fingerprint; @@ -1049,30 +1049,6 @@ pub struct PatField<'hir> { pub span: Span, } -/// Explicit binding annotations given in the HIR for a binding. Note -/// that this is not the final binding *mode* that we infer after type -/// inference. -#[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)] -pub enum BindingAnnotation { - /// No binding annotation given: this means that the final binding mode - /// will depend on whether we have skipped through a `&` reference - /// when matching. For example, the `x` in `Some(x)` will have binding - /// mode `None`; if you do `let Some(x) = &Some(22)`, it will - /// ultimately be inferred to be by-reference. - /// - /// Note that implicit reference skipping is not implemented yet (#42640). - Unannotated, - - /// Annotated with `mut x` -- could be either ref or not, similar to `None`. - Mutable, - - /// Annotated as `ref`, like `ref x` - Ref, - - /// Annotated as `ref mut x`. - RefMut, -} - #[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)] pub enum RangeEnd { Included, diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs index 93112199b603..9baaf9390f2c 100644 --- a/compiler/rustc_hir/src/pat_util.rs +++ b/compiler/rustc_hir/src/pat_util.rs @@ -1,6 +1,6 @@ use crate::def::{CtorOf, DefKind, Res}; use crate::def_id::DefId; -use crate::hir::{self, HirId, PatKind}; +use crate::hir::{self, BindingAnnotation, ByRef, HirId, PatKind}; use rustc_data_structures::fx::FxHashSet; use rustc_span::hygiene::DesugaringKind; use rustc_span::symbol::Ident; @@ -93,12 +93,7 @@ impl hir::Pat<'_> { pub fn simple_ident(&self) -> Option { match self.kind { - PatKind::Binding( - hir::BindingAnnotation::Unannotated | hir::BindingAnnotation::Mutable, - _, - ident, - None, - ) => Some(ident), + PatKind::Binding(BindingAnnotation(ByRef::No, _), _, ident, None) => Some(ident), _ => None, } } @@ -135,11 +130,11 @@ impl hir::Pat<'_> { pub fn contains_explicit_ref_binding(&self) -> Option { let mut result = None; self.each_binding(|annotation, _, _, _| match annotation { - hir::BindingAnnotation::Ref => match result { + hir::BindingAnnotation::REF => match result { None | Some(hir::Mutability::Not) => result = Some(hir::Mutability::Not), _ => {} }, - hir::BindingAnnotation::RefMut => result = Some(hir::Mutability::Mut), + hir::BindingAnnotation::REF_MUT => result = Some(hir::Mutability::Mut), _ => {} }); result diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 42663da8a3f9..bb83b371ae89 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -9,7 +9,9 @@ use rustc_ast_pretty::pp::{self, Breaks}; use rustc_ast_pretty::pprust::{Comments, PrintState}; use rustc_hir as hir; use rustc_hir::LifetimeParamKind; -use rustc_hir::{GenericArg, GenericParam, GenericParamKind, Node, Term}; +use rustc_hir::{ + BindingAnnotation, ByRef, GenericArg, GenericParam, GenericParamKind, Mutability, Node, Term, +}; use rustc_hir::{GenericBound, PatKind, RangeEnd, TraitBoundModifier}; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, Ident, IdentPrinter, Symbol}; @@ -1758,20 +1760,12 @@ impl<'a> State<'a> { // is that it doesn't matter match pat.kind { PatKind::Wild => self.word("_"), - PatKind::Binding(binding_mode, _, ident, sub) => { - match binding_mode { - hir::BindingAnnotation::Ref => { - self.word_nbsp("ref"); - self.print_mutability(hir::Mutability::Not, false); - } - hir::BindingAnnotation::RefMut => { - self.word_nbsp("ref"); - self.print_mutability(hir::Mutability::Mut, false); - } - hir::BindingAnnotation::Unannotated => {} - hir::BindingAnnotation::Mutable => { - self.word_nbsp("mut"); - } + PatKind::Binding(BindingAnnotation(by_ref, mutbl), _, ident, sub) => { + if by_ref == ByRef::Yes { + self.word_nbsp("ref"); + } + if mutbl == Mutability::Mut { + self.word_nbsp("mut"); } self.print_ident(ident); if let Some(p) = sub { diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 4e9c209a5840..6bd5ca7b6066 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -259,17 +259,8 @@ impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns { == Some(cx.tcx.field_index(fieldpat.hir_id, cx.typeck_results())) { cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, |lint| { - let binding = match binding_annot { - hir::BindingAnnotation::Unannotated => None, - hir::BindingAnnotation::Mutable => Some("mut"), - hir::BindingAnnotation::Ref => Some("ref"), - hir::BindingAnnotation::RefMut => Some("ref mut"), - }; - let suggested_ident = if let Some(binding) = binding { - format!("{} {}", binding, ident) - } else { - ident.to_string() - }; + let suggested_ident = + format!("{}{}", binding_annot.prefix_str(), ident); lint.build(fluent::lint::builtin_non_shorthand_field_patterns) .set_arg("ident", ident.clone()) .span_suggestion( diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 1f4e5b480917..9a7d722c05a9 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -751,7 +751,7 @@ impl UnusedParens { avoid_or: bool, avoid_mut: bool, ) { - use ast::{BindingMode, Mutability, PatKind}; + use ast::{BindingAnnotation, PatKind}; if let PatKind::Paren(inner) = &value.kind { match inner.kind { @@ -763,7 +763,9 @@ impl UnusedParens { // Avoid `p0 | .. | pn` if we should. PatKind::Or(..) if avoid_or => return, // Avoid `mut x` and `mut x @ p` if we should: - PatKind::Ident(BindingMode::ByValue(Mutability::Mut), ..) if avoid_mut => return, + PatKind::Ident(BindingAnnotation::MUT, ..) if avoid_mut => { + return; + } // Otherwise proceed with linting. _ => {} } diff --git a/compiler/rustc_middle/src/ty/binding.rs b/compiler/rustc_middle/src/ty/binding.rs index 3d65429f2e53..a5b05a4f9b52 100644 --- a/compiler/rustc_middle/src/ty/binding.rs +++ b/compiler/rustc_middle/src/ty/binding.rs @@ -1,6 +1,4 @@ -use rustc_hir::BindingAnnotation; -use rustc_hir::BindingAnnotation::*; -use rustc_hir::Mutability; +use rustc_hir::{BindingAnnotation, ByRef, Mutability}; #[derive(Clone, PartialEq, TyEncodable, TyDecodable, Debug, Copy, HashStable)] pub enum BindingMode { @@ -11,12 +9,10 @@ pub enum BindingMode { TrivialTypeTraversalAndLiftImpls! { BindingMode, } impl BindingMode { - pub fn convert(ba: BindingAnnotation) -> BindingMode { - match ba { - Unannotated => BindingMode::BindByValue(Mutability::Not), - Mutable => BindingMode::BindByValue(Mutability::Mut), - Ref => BindingMode::BindByReference(Mutability::Not), - RefMut => BindingMode::BindByReference(Mutability::Mut), + pub fn convert(BindingAnnotation(by_ref, mutbl): BindingAnnotation) -> BindingMode { + match by_ref { + ByRef::No => BindingMode::BindByValue(mutbl), + ByRef::Yes => BindingMode::BindByReference(mutbl), } } } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index dd806e2130e9..9b5dd09372cc 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -10,9 +10,9 @@ use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Lit, LitKind, TokenKind}; use rustc_ast::util::parser::AssocOp; use rustc_ast::{ - AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, Block, - BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Mutability, Param, Pat, - PatKind, Path, PathSegment, QSelf, Ty, TyKind, + AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingAnnotation, Block, + BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Param, Pat, PatKind, + Path, PathSegment, QSelf, Ty, TyKind, }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; @@ -37,7 +37,7 @@ const TURBOFISH_SUGGESTION_STR: &str = pub(super) fn dummy_arg(ident: Ident) -> Param { let pat = P(Pat { id: ast::DUMMY_NODE_ID, - kind: PatKind::Ident(BindingMode::ByValue(Mutability::Not), ident, None), + kind: PatKind::Ident(BindingAnnotation::NONE, ident, None), span: ident.span, tokens: None, }); @@ -2961,7 +2961,7 @@ impl<'a> Parser<'a> { } _ => {} }, - PatKind::Ident(BindingMode::ByValue(Mutability::Not), ident, None) => { + PatKind::Ident(BindingAnnotation::NONE, ident, None) => { match &first_pat.kind { PatKind::Ident(_, old_ident, _) => { let path = PatKind::Path( diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 5b75d1d5f221..dbdd85ea8e87 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -8,7 +8,7 @@ use rustc_ast::token::{self, Delimiter, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; use rustc_ast::{self as ast, AttrVec, Attribute, DUMMY_NODE_ID}; use rustc_ast::{Async, Const, Defaultness, IsAuto, Mutability, Unsafe, UseTree, UseTreeKind}; -use rustc_ast::{BindingMode, Block, FnDecl, FnSig, Param, SelfKind}; +use rustc_ast::{BindingAnnotation, Block, FnDecl, FnSig, Param, SelfKind}; use rustc_ast::{EnumDef, FieldDef, Generics, TraitRef, Ty, TyKind, Variant, VariantData}; use rustc_ast::{FnHeader, ForeignItem, Path, PathSegment, Visibility, VisibilityKind}; use rustc_ast::{MacArgs, MacCall, MacDelimiter}; @@ -2322,7 +2322,7 @@ impl<'a> Parser<'a> { match ty { Ok(ty) => { let ident = Ident::new(kw::Empty, this.prev_token.span); - let bm = BindingMode::ByValue(Mutability::Not); + let bm = BindingAnnotation::NONE; let pat = this.mk_pat_ident(ty.span, bm, ident); (pat, ty) } diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 8b3200d45fcc..88bd57d37cb6 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -4,8 +4,8 @@ use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor}; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter}; use rustc_ast::{ - self as ast, AttrVec, BindingMode, Expr, ExprKind, MacCall, Mutability, Pat, PatField, PatKind, - Path, QSelf, RangeEnd, RangeSyntax, + self as ast, AttrVec, BindingAnnotation, ByRef, Expr, ExprKind, MacCall, Mutability, Pat, + PatField, PatKind, Path, QSelf, RangeEnd, RangeSyntax, }; use rustc_ast_pretty::pprust; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult}; @@ -353,7 +353,7 @@ impl<'a> Parser<'a> { } else if self.eat_keyword(kw::Ref) { // Parse ref ident @ pat / ref mut ident @ pat let mutbl = self.parse_mutability(); - self.parse_pat_ident(BindingMode::ByRef(mutbl))? + self.parse_pat_ident(BindingAnnotation(ByRef::Yes, mutbl))? } else if self.eat_keyword(kw::Box) { self.parse_pat_box()? } else if self.check_inline_const(0) { @@ -369,7 +369,7 @@ impl<'a> Parser<'a> { // Parse `ident @ pat` // This can give false positives and parse nullary enums, // they are dealt with later in resolve. - self.parse_pat_ident(BindingMode::ByValue(Mutability::Not))? + self.parse_pat_ident(BindingAnnotation::NONE)? } else if self.is_start_of_pat_with_path() { // Parse pattern starting with a path let (qself, path) = if self.eat_lt() { @@ -578,7 +578,8 @@ impl<'a> Parser<'a> { let mut pat = self.parse_pat_no_top_alt(Some("identifier"))?; // If we don't have `mut $ident (@ pat)?`, error. - if let PatKind::Ident(BindingMode::ByValue(m @ Mutability::Not), ..) = &mut pat.kind { + if let PatKind::Ident(BindingAnnotation(ByRef::No, m @ Mutability::Not), ..) = &mut pat.kind + { // Don't recurse into the subpattern. // `mut` on the outer binding doesn't affect the inner bindings. *m = Mutability::Mut; @@ -604,7 +605,7 @@ impl<'a> Parser<'a> { ) .emit(); - self.parse_pat_ident(BindingMode::ByRef(Mutability::Mut)) + self.parse_pat_ident(BindingAnnotation::REF_MUT) } /// Turn all by-value immutable bindings in a pattern into mutable bindings. @@ -613,7 +614,8 @@ impl<'a> Parser<'a> { struct AddMut(bool); impl MutVisitor for AddMut { fn visit_pat(&mut self, pat: &mut P) { - if let PatKind::Ident(BindingMode::ByValue(m @ Mutability::Not), ..) = &mut pat.kind + if let PatKind::Ident(BindingAnnotation(ByRef::No, m @ Mutability::Not), ..) = + &mut pat.kind { self.0 = true; *m = Mutability::Mut; @@ -838,7 +840,7 @@ impl<'a> Parser<'a> { /// Parses `ident` or `ident @ pat`. /// Used by the copy foo and ref foo patterns to give a good /// error message when parsing mistakes like `ref foo(a, b)`. - fn parse_pat_ident(&mut self, binding_mode: BindingMode) -> PResult<'a, PatKind> { + fn parse_pat_ident(&mut self, binding_annotation: BindingAnnotation) -> PResult<'a, PatKind> { let ident = self.parse_ident()?; let sub = if self.eat(&token::At) { Some(self.parse_pat_no_top_alt(Some("binding pattern"))?) @@ -856,7 +858,7 @@ impl<'a> Parser<'a> { .struct_span_err(self.prev_token.span, "expected identifier, found enum pattern")); } - Ok(PatKind::Ident(binding_mode, ident, sub)) + Ok(PatKind::Ident(binding_annotation, ident, sub)) } /// Parse a struct ("record") pattern (e.g. `Foo { ... }` or `Foo::Bar { ... }`). @@ -936,11 +938,7 @@ impl<'a> Parser<'a> { None }; - Ok(PatKind::Ident( - BindingMode::ByValue(Mutability::Not), - Ident::new(kw::Box, box_span), - sub, - )) + Ok(PatKind::Ident(BindingAnnotation::NONE, Ident::new(kw::Box, box_span), sub)) } else { let pat = self.parse_pat_with_range_pat(false, None)?; self.sess.gated_spans.gate(sym::box_patterns, box_span.to(self.prev_token.span)); @@ -1117,14 +1115,12 @@ impl<'a> Parser<'a> { let fieldname = self.parse_field_name()?; hi = self.prev_token.span; - let bind_type = match (is_ref, is_mut) { - (true, true) => BindingMode::ByRef(Mutability::Mut), - (true, false) => BindingMode::ByRef(Mutability::Not), - (false, true) => BindingMode::ByValue(Mutability::Mut), - (false, false) => BindingMode::ByValue(Mutability::Not), + let mutability = match is_mut { + false => Mutability::Not, + true => Mutability::Mut, }; - - let fieldpat = self.mk_pat_ident(boxed_span.to(hi), bind_type, fieldname); + let ann = BindingAnnotation(ByRef::from(is_ref), mutability); + let fieldpat = self.mk_pat_ident(boxed_span.to(hi), ann, fieldname); let subpat = if is_box { self.mk_pat(lo.to(hi), PatKind::Box(fieldpat)) } else { fieldpat }; (subpat, fieldname, true) @@ -1141,8 +1137,8 @@ impl<'a> Parser<'a> { }) } - pub(super) fn mk_pat_ident(&self, span: Span, bm: BindingMode, ident: Ident) -> P { - self.mk_pat(span, PatKind::Ident(bm, ident, None)) + pub(super) fn mk_pat_ident(&self, span: Span, ann: BindingAnnotation, ident: Ident) -> P { + self.mk_pat(span, PatKind::Ident(ann, ident, None)) } pub(super) fn mk_pat(&self, span: Span, kind: PatKind) -> P { diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index 296b6ed5d99a..607973446fc1 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -76,7 +76,7 @@ fn check_no_patterns(tcx: TyCtxt<'_>, params: &[hir::Param<'_>]) { for param in params { match param.pat.kind { hir::PatKind::Wild - | hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, _, None) => {} + | hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, _, None) => {} _ => { tcx.sess .struct_span_err( diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index dbe4d691f04c..b37feb15890b 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -20,7 +20,7 @@ use rustc_errors::DiagnosticId; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, PartialRes, PerNS}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; -use rustc_hir::{PrimTy, TraitCandidate}; +use rustc_hir::{BindingAnnotation, PrimTy, TraitCandidate}; use rustc_middle::middle::resolve_lifetime::Set1; use rustc_middle::ty::DefIdTree; use rustc_middle::{bug, span_bug}; @@ -50,7 +50,7 @@ use diagnostics::{ #[derive(Copy, Clone, Debug)] struct BindingInfo { span: Span, - binding_mode: BindingMode, + annotation: BindingAnnotation, } #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -2865,10 +2865,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { pat.walk(&mut |pat| { match pat.kind { - PatKind::Ident(binding_mode, ident, ref sub_pat) + PatKind::Ident(annotation, ident, ref sub_pat) if sub_pat.is_some() || self.is_base_res_local(pat.id) => { - binding_map.insert(ident, BindingInfo { span: ident.span, binding_mode }); + binding_map.insert(ident, BindingInfo { span: ident.span, annotation }); } PatKind::Or(ref ps) => { // Check the consistency of this or-pattern and @@ -2925,7 +2925,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { binding_error.target.insert(pat_outer.span); } Some(binding_outer) => { - if binding_outer.binding_mode != binding_inner.binding_mode { + if binding_outer.annotation != binding_inner.annotation { // The binding modes in the outer and inner bindings differ. inconsistent_vars .entry(name) @@ -3146,14 +3146,14 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { fn try_resolve_as_non_binding( &mut self, pat_src: PatternSource, - bm: BindingMode, + ann: BindingAnnotation, ident: Ident, has_sub: bool, ) -> Option { // An immutable (no `mut`) by-value (no `ref`) binding pattern without // a sub pattern (no `@ $pat`) is syntactically ambiguous as it could // also be interpreted as a path to e.g. a constant, variant, etc. - let is_syntactic_ambiguity = !has_sub && bm == BindingMode::ByValue(Mutability::Not); + let is_syntactic_ambiguity = !has_sub && ann == BindingAnnotation::NONE; let ls_binding = self.maybe_resolve_ident_in_lexical_scope(ident, ValueNS)?; let (res, binding) = match ls_binding { diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index 16af53385104..eae1f0831077 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -865,23 +865,12 @@ impl<'l> Visitor<'l> for PathCollector<'l> { hir::PatKind::TupleStruct(ref path, ..) | hir::PatKind::Path(ref path) => { self.collected_paths.push((p.hir_id, path)); } - hir::PatKind::Binding(bm, _, ident, _) => { + hir::PatKind::Binding(hir::BindingAnnotation(_, mutbl), _, ident, _) => { debug!( "PathCollector, visit ident in pat {}: {:?} {:?}", ident, p.span, ident.span ); - let immut = match bm { - // Even if the ref is mut, you can't change the ref, only - // the data pointed at, so showing the initialising expression - // is still worthwhile. - hir::BindingAnnotation::Unannotated | hir::BindingAnnotation::Ref => { - hir::Mutability::Not - } - hir::BindingAnnotation::Mutable | hir::BindingAnnotation::RefMut => { - hir::Mutability::Mut - } - }; - self.collected_idents.push((p.hir_id, ident, immut)); + self.collected_idents.push((p.hir_id, ident, mutbl)); } _ => {} } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 02adae5bde15..b012073f7719 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -774,7 +774,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // Get the local name of this closure. This can be inaccurate because // of the possibility of reassignment, but this should be good enough. match &kind { - hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, ident, None) => { + hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, ident, None) => { Some(ident.name) } _ => { diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 6dcc364bb50f..9096fc442d49 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -569,7 +569,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Ty<'tcx> { // Determine the binding mode... let bm = match ba { - hir::BindingAnnotation::Unannotated => def_bm, + hir::BindingAnnotation::NONE => def_bm, _ => BindingMode::convert(ba), }; // ...and store it in a side table: @@ -655,7 +655,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ba: hir::BindingAnnotation, ) { match (expected.kind(), actual.kind(), ba) { - (ty::Ref(_, inner_ty, _), _, hir::BindingAnnotation::Unannotated) + (ty::Ref(_, inner_ty, _), _, hir::BindingAnnotation::NONE) if self.can_eq(self.param_env, *inner_ty, actual).is_ok() => { err.span_suggestion_verbose( @@ -665,7 +665,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MaybeIncorrect, ); } - (_, ty::Ref(_, inner_ty, _), hir::BindingAnnotation::Ref) + (_, ty::Ref(_, inner_ty, _), hir::BindingAnnotation::REF) if self.can_eq(self.param_env, expected, *inner_ty).is_ok() => { err.span_suggestion_verbose( diff --git a/compiler/rustc_typeck/src/check/region.rs b/compiler/rustc_typeck/src/check/region.rs index 0081e9049eec..b779713482e1 100644 --- a/compiler/rustc_typeck/src/check/region.rs +++ b/compiler/rustc_typeck/src/check/region.rs @@ -587,8 +587,7 @@ fn resolve_local<'tcx>( // & expression, and its lifetime would be extended to the end of the block (due // to a different rule, not the below code). match pat.kind { - PatKind::Binding(hir::BindingAnnotation::Ref, ..) - | PatKind::Binding(hir::BindingAnnotation::RefMut, ..) => true, + PatKind::Binding(hir::BindingAnnotation(hir::ByRef::Yes, _), ..) => true, PatKind::Struct(_, ref field_pats, _) => { field_pats.iter().any(|fp| is_binding_pat(&fp.pat)) @@ -607,10 +606,7 @@ fn resolve_local<'tcx>( PatKind::Box(ref subpat) => is_binding_pat(&subpat), PatKind::Ref(_, _) - | PatKind::Binding( - hir::BindingAnnotation::Unannotated | hir::BindingAnnotation::Mutable, - .., - ) + | PatKind::Binding(hir::BindingAnnotation(hir::ByRef::No, _), ..) | PatKind::Wild | PatKind::Path(_) | PatKind::Lit(_) From ac4bb0085b22f2e4d65b7ece7ad04df12dc625ad Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 30 Aug 2022 17:39:36 -0500 Subject: [PATCH 4100/5092] rustfmt: BindingAnnotation change --- src/tools/rustfmt/src/patterns.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs index 9b74b35f3141..e2fe92b28f23 100644 --- a/src/tools/rustfmt/src/patterns.rs +++ b/src/tools/rustfmt/src/patterns.rs @@ -1,4 +1,6 @@ -use rustc_ast::ast::{self, BindingMode, Pat, PatField, PatKind, RangeEnd, RangeSyntax}; +use rustc_ast::ast::{ + self, BindingAnnotation, ByRef, Pat, PatField, PatKind, RangeEnd, RangeSyntax, +}; use rustc_ast::ptr; use rustc_span::{BytePos, Span}; @@ -99,10 +101,10 @@ impl Rewrite for Pat { write_list(&items, &fmt) } PatKind::Box(ref pat) => rewrite_unary_prefix(context, "box ", &**pat, shape), - PatKind::Ident(binding_mode, ident, ref sub_pat) => { - let (prefix, mutability) = match binding_mode { - BindingMode::ByRef(mutability) => ("ref", mutability), - BindingMode::ByValue(mutability) => ("", mutability), + PatKind::Ident(BindingAnnotation(by_ref, mutability), ident, ref sub_pat) => { + let prefix = match by_ref { + ByRef::Yes => "ref", + ByRef::No => "", }; let mut_infix = format_mutability(mutability).trim(); let id_str = rewrite_ident(context, ident); From 9ea82d57e296efd6dfc0cb0a6c4c09f4111c123d Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 30 Aug 2022 17:36:53 -0500 Subject: [PATCH 4101/5092] clippy: BindingAnnotation change --- .../clippy/clippy_lints/src/dereference.rs | 2 +- .../clippy/clippy_lints/src/explicit_write.rs | 2 +- .../clippy_lints/src/index_refutable_slice.rs | 16 ++++++++------- .../clippy/clippy_lints/src/let_if_seq.rs | 4 ++-- .../clippy_lints/src/loops/manual_find.rs | 2 +- .../clippy_lints/src/loops/mut_range_bound.rs | 2 +- .../clippy_lints/src/loops/same_item_push.rs | 4 ++-- .../clippy_lints/src/matches/manual_map.rs | 2 +- .../clippy_lints/src/matches/match_as_ref.rs | 20 +++++++++---------- .../src/matches/needless_match.rs | 5 ++--- .../clippy_lints/src/matches/single_match.rs | 2 +- .../clippy_lints/src/methods/clone_on_copy.rs | 9 ++------- .../src/methods/iter_skip_next.rs | 2 +- .../clippy_lints/src/methods/map_clone.rs | 4 ++-- .../clippy_lints/src/methods/str_splitn.rs | 11 +++++----- src/tools/clippy/clippy_lints/src/misc.rs | 11 +++++----- .../src/misc_early/redundant_pattern.rs | 12 +++-------- .../src/needless_arbitrary_self_type.rs | 6 +++--- .../clippy_lints/src/needless_borrowed_ref.rs | 2 +- .../clippy_lints/src/needless_late_init.rs | 2 +- .../src/needless_pass_by_value.rs | 10 ++++------ .../clippy_lints/src/option_if_let_else.rs | 4 ++-- .../clippy_lints/src/pass_by_ref_or_value.rs | 2 +- src/tools/clippy/clippy_lints/src/ptr.rs | 4 ++-- .../clippy/clippy_lints/src/question_mark.rs | 7 +++---- .../src/slow_vector_initialization.rs | 2 +- .../clippy_lints/src/unnested_or_patterns.rs | 4 ++-- .../clippy/clippy_lints/src/utils/author.rs | 14 ++++++++++--- .../clippy_lints/src/vec_init_then_push.rs | 2 +- .../clippy/clippy_utils/src/hir_utils.rs | 11 +++++----- src/tools/clippy/clippy_utils/src/lib.rs | 2 +- src/tools/clippy/tests/ui/author.stdout | 2 +- .../clippy/tests/ui/author/blocks.stdout | 6 +++--- src/tools/clippy/tests/ui/author/loop.stdout | 4 ++-- .../clippy/tests/ui/author/matches.stdout | 4 ++-- 35 files changed, 95 insertions(+), 103 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 1506ea604f0d..3de188d96ce8 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -503,7 +503,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { } fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { - if let PatKind::Binding(BindingAnnotation::Ref, id, name, _) = pat.kind { + if let PatKind::Binding(BindingAnnotation::REF, id, name, _) = pat.kind { if let Some(opt_prev_pat) = self.ref_locals.get_mut(&id) { // This binding id has been seen before. Add this pattern to the list of changes. if let Some(prev_pat) = opt_prev_pat { diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs index 5bf4313b41a4..502f0b583c41 100644 --- a/src/tools/clippy/clippy_lints/src/explicit_write.rs +++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs @@ -128,7 +128,7 @@ fn look_in_block<'tcx, 'hir>(cx: &LateContext<'tcx>, kind: &'tcx ExprKind<'hir>) if let Some(Node::Pat(res_pat)) = cx.tcx.hir().find(expr_res); // Find id of the local we found in the block - if let PatKind::Binding(BindingAnnotation::Unannotated, local_hir_id, _ident, None) = local.pat.kind; + if let PatKind::Binding(BindingAnnotation::NONE, local_hir_id, _ident, None) = local.pat.kind; // If those two are the same hir id if res_pat.hir_id == local_hir_id; diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs index d0c6495e35a7..0dd7f5bf000d 100644 --- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs +++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs @@ -95,12 +95,14 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap = FxHashSet::default(); let mut slices: FxIndexMap = FxIndexMap::default(); pat.walk_always(|pat| { - if let hir::PatKind::Binding(binding, value_hir_id, ident, sub_pat) = pat.kind { - // We'll just ignore mut and ref mut for simplicity sake right now - if let hir::BindingAnnotation::Mutable | hir::BindingAnnotation::RefMut = binding { - return; - } - + // We'll just ignore mut and ref mut for simplicity sake right now + if let hir::PatKind::Binding( + hir::BindingAnnotation(by_ref, hir::Mutability::Not), + value_hir_id, + ident, + sub_pat, + ) = pat.kind + { // This block catches bindings with sub patterns. It would be hard to build a correct suggestion // for them and it's likely that the user knows what they are doing in such a case. if removed_pat.contains(&value_hir_id) { @@ -116,7 +118,7 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap LateLintPass<'tcx> for LetIfSeq { }; let mutability = match mode { - BindingAnnotation::RefMut | BindingAnnotation::Mutable => " ", + BindingAnnotation(_, Mutability::Mut) => " ", _ => "", }; diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs index 215c83a7edf6..09b2376d5c04 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs @@ -106,7 +106,7 @@ fn get_binding(pat: &Pat<'_>) -> Option { hir_id = None; return; } - if let BindingAnnotation::Unannotated = annotation { + if let BindingAnnotation::NONE = annotation { hir_id = Some(id); } }); diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs index aedf3810b23e..fce2d54639cb 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs @@ -44,7 +44,7 @@ fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option if_chain! { if let Some(hir_id) = path_to_local(bound); if let Node::Pat(pat) = cx.tcx.hir().get(hir_id); - if let PatKind::Binding(BindingAnnotation::Mutable, ..) = pat.kind; + if let PatKind::Binding(BindingAnnotation::MUT, ..) = pat.kind; then { return Some(hir_id); } diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs index 1439f1f4c75d..98f73c428ebf 100644 --- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs +++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs @@ -7,7 +7,7 @@ use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Node, Pat, PatKind, Stmt, StmtKind}; +use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Mutability, Node, Pat, PatKind, Stmt, StmtKind}; use rustc_lint::LateContext; use rustc_span::symbol::sym; use std::iter::Iterator; @@ -65,7 +65,7 @@ pub(super) fn check<'tcx>( if_chain! { if let Node::Pat(pat) = node; if let PatKind::Binding(bind_ann, ..) = pat.kind; - if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable); + if !matches!(bind_ann, BindingAnnotation(_, Mutability::Mut)); let parent_node = cx.tcx.hir().get_parent_node(hir_id); if let Some(Node::Local(parent_let_expr)) = cx.tcx.hir().find(parent_node); if let Some(init) = parent_let_expr.init; diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_map.rs b/src/tools/clippy/clippy_lints/src/matches/manual_map.rs index 8f98b43b9e5c..b0198e856d5b 100644 --- a/src/tools/clippy/clippy_lints/src/matches/manual_map.rs +++ b/src/tools/clippy/clippy_lints/src/matches/manual_map.rs @@ -165,7 +165,7 @@ fn check<'tcx>( } // `ref` and `ref mut` annotations were handled earlier. - let annotation = if matches!(annotation, BindingAnnotation::Mutable) { + let annotation = if matches!(annotation, BindingAnnotation::MUT) { "mut " } else { "" diff --git a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs index a0efdecec67f..91d17f481e2d 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{is_lang_ctor, peel_blocks}; use rustc_errors::Applicability; -use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, LangItem, PatKind, QPath}; +use rustc_hir::{Arm, BindingAnnotation, ByRef, Expr, ExprKind, LangItem, Mutability, PatKind, QPath}; use rustc_lint::LateContext; use rustc_middle::ty; @@ -10,18 +10,17 @@ use super::MATCH_AS_REF; pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) { if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() { - let arm_ref: Option = if is_none_arm(cx, &arms[0]) { + let arm_ref_mut = if is_none_arm(cx, &arms[0]) { is_ref_some_arm(cx, &arms[1]) } else if is_none_arm(cx, &arms[1]) { is_ref_some_arm(cx, &arms[0]) } else { None }; - if let Some(rb) = arm_ref { - let suggestion = if rb == BindingAnnotation::Ref { - "as_ref" - } else { - "as_mut" + if let Some(rb) = arm_ref_mut { + let suggestion = match rb { + Mutability::Not => "as_ref", + Mutability::Mut => "as_mut", }; let output_ty = cx.typeck_results().expr_ty(expr); @@ -66,19 +65,18 @@ fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { } // Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`) -fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option { +fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option { if_chain! { if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind; if is_lang_ctor(cx, qpath, LangItem::OptionSome); - if let PatKind::Binding(rb, .., ident, _) = first_pat.kind; - if rb == BindingAnnotation::Ref || rb == BindingAnnotation::RefMut; + if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., ident, _) = first_pat.kind; if let ExprKind::Call(e, [arg]) = peel_blocks(arm.body).kind; if let ExprKind::Path(ref some_path) = e.kind; if is_lang_ctor(cx, some_path, LangItem::OptionSome); if let ExprKind::Path(QPath::Resolved(_, path2)) = arg.kind; if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name; then { - return Some(rb) + return Some(mutabl) } } None diff --git a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs index 6f037339ec75..634eef82e532 100644 --- a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs @@ -8,7 +8,7 @@ use clippy_utils::{ }; use rustc_errors::Applicability; use rustc_hir::LangItem::OptionNone; -use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, FnRetTy, Guard, Node, Pat, PatKind, Path, QPath}; +use rustc_hir::{Arm, BindingAnnotation, ByRef, Expr, ExprKind, FnRetTy, Guard, Node, Pat, PatKind, Path, QPath}; use rustc_lint::LateContext; use rustc_span::sym; use rustc_typeck::hir_ty_to_ty; @@ -189,8 +189,7 @@ fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool { }, )), ) => { - return !matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut) - && pat_ident.name == first_seg.ident.name; + return !matches!(annot, BindingAnnotation(ByRef::Yes, _)) && pat_ident.name == first_seg.ident.name; }, // Example: `Custom::TypeA => Custom::TypeB`, or `None => None` (PatKind::Path(QPath::Resolved(_, p_path)), ExprKind::Path(QPath::Resolved(_, e_path))) => { diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs index 92091a0c3395..95478af45b4b 100644 --- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs @@ -175,7 +175,7 @@ fn collect_pat_paths<'a>(acc: &mut Vec>, cx: &LateContext<'a>, pat: &Pat< let p_ty = cx.typeck_results().pat_ty(p); collect_pat_paths(acc, cx, p, p_ty); }), - PatKind::TupleStruct(..) | PatKind::Binding(BindingAnnotation::Unannotated, .., None) | PatKind::Path(_) => { + PatKind::TupleStruct(..) | PatKind::Binding(BindingAnnotation::NONE, .., None) | PatKind::Path(_) => { acc.push(ty); }, _ => {}, diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs index 60e1355f9b92..2c3683a09e32 100644 --- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs +++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet_with_context; use clippy_utils::sugg; use clippy_utils::ty::is_copy; use rustc_errors::Applicability; -use rustc_hir::{BindingAnnotation, Expr, ExprKind, MatchSource, Node, PatKind, QPath}; +use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, MatchSource, Node, PatKind, QPath}; use rustc_lint::LateContext; use rustc_middle::ty::{self, adjustment::Adjust}; use rustc_span::symbol::{sym, Symbol}; @@ -98,12 +98,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, _ => false, }, // local binding capturing a reference - Some(Node::Local(l)) - if matches!( - l.pat.kind, - PatKind::Binding(BindingAnnotation::Ref | BindingAnnotation::RefMut, ..) - ) => - { + Some(Node::Local(l)) if matches!(l.pat.kind, PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..)) => { return; }, _ => false, diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs b/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs index 43e9451f7d37..beb772100aff 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs @@ -24,7 +24,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr if let Some(id) = path_to_local(recv); if let Node::Pat(pat) = cx.tcx.hir().get(id); if let PatKind::Binding(ann, _, _, _) = pat.kind; - if ann != BindingAnnotation::Mutable; + if ann != BindingAnnotation::MUT; then { application = Applicability::Unspecified; diag.span_help( diff --git a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs index ffedda95ff8e..a13541ad48d8 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs @@ -33,13 +33,13 @@ pub(super) fn check<'tcx>( let closure_expr = peel_blocks(&closure_body.value); match closure_body.params[0].pat.kind { hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding( - hir::BindingAnnotation::Unannotated, .., name, None + hir::BindingAnnotation::NONE, .., name, None ) = inner.kind { if ident_eq(name, closure_expr) { lint_explicit_closure(cx, e.span, recv.span, true, msrv); } }, - hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, .., name, None) => { + hir::PatKind::Binding(hir::BindingAnnotation::NONE, .., name, None) => { match closure_expr.kind { hir::ExprKind::Unary(hir::UnOp::Deref, inner) => { if ident_eq(name, inner) { diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs index 4ac738272d08..c5da8c8b0fec 100644 --- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs +++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs @@ -130,7 +130,7 @@ fn check_manual_split_once_indirect( let ctxt = expr.span.ctxt(); let mut parents = cx.tcx.hir().parent_iter(expr.hir_id); if let (_, Node::Local(local)) = parents.next()? - && let PatKind::Binding(BindingAnnotation::Mutable, iter_binding_id, iter_ident, None) = local.pat.kind + && let PatKind::Binding(BindingAnnotation::MUT, iter_binding_id, iter_ident, None) = local.pat.kind && let (iter_stmt_id, Node::Stmt(_)) = parents.next()? && let (_, Node::Block(enclosing_block)) = parents.next()? @@ -212,11 +212,10 @@ fn indirect_usage<'tcx>( ctxt: SyntaxContext, ) -> Option> { if let StmtKind::Local(Local { - pat: - Pat { - kind: PatKind::Binding(BindingAnnotation::Unannotated, _, ident, None), - .. - }, + pat: Pat { + kind: PatKind::Binding(BindingAnnotation::NONE, _, ident, None), + .. + }, init: Some(init_expr), hir_id: local_hir_id, .. diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index 8224e80c9ccb..ea245edd7704 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -5,8 +5,8 @@ use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - self as hir, def, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind, Stmt, - StmtKind, TyKind, + self as hir, def, BinOpKind, BindingAnnotation, Body, ByRef, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind, + Stmt, StmtKind, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; @@ -146,7 +146,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { return; } for arg in iter_input_pats(decl, body) { - if let PatKind::Binding(BindingAnnotation::Ref | BindingAnnotation::RefMut, ..) = arg.pat.kind { + if let PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..) = arg.pat.kind { span_lint( cx, TOPLEVEL_REF_ARG, @@ -162,9 +162,8 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { if_chain! { if !in_external_macro(cx.tcx.sess, stmt.span); if let StmtKind::Local(local) = stmt.kind; - if let PatKind::Binding(an, .., name, None) = local.pat.kind; + if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., name, None) = local.pat.kind; if let Some(init) = local.init; - if an == BindingAnnotation::Ref || an == BindingAnnotation::RefMut; then { // use the macro callsite when the init span (but not the whole local span) // comes from an expansion like `vec![1, 2, 3]` in `let ref _ = vec![1, 2, 3];` @@ -173,7 +172,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { } else { Sugg::hir(cx, init, "..") }; - let (mutopt, initref) = if an == BindingAnnotation::RefMut { + let (mutopt, initref) = if mutabl == Mutability::Mut { ("mut ", sugg_init.mut_addr()) } else { ("", sugg_init.addr()) diff --git a/src/tools/clippy/clippy_lints/src/misc_early/redundant_pattern.rs b/src/tools/clippy/clippy_lints/src/misc_early/redundant_pattern.rs index 525dbf7757c1..d7bb0616acb0 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early/redundant_pattern.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early/redundant_pattern.rs @@ -1,18 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use rustc_ast::ast::{BindingMode, Mutability, Pat, PatKind}; +use rustc_ast::ast::{Pat, PatKind}; use rustc_errors::Applicability; use rustc_lint::EarlyContext; use super::REDUNDANT_PATTERN; pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { - if let PatKind::Ident(left, ident, Some(ref right)) = pat.kind { - let left_binding = match left { - BindingMode::ByRef(Mutability::Mut) => "ref mut ", - BindingMode::ByRef(Mutability::Not) => "ref ", - BindingMode::ByValue(..) => "", - }; - + if let PatKind::Ident(ann, ident, Some(ref right)) = pat.kind { if let PatKind::Wild = right.kind { span_lint_and_sugg( cx, @@ -23,7 +17,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { ident.name, ident.name, ), "try", - format!("{}{}", left_binding, ident.name), + format!("{}{}", ann.prefix_str(), ident.name), Applicability::MachineApplicable, ); } diff --git a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs index 9838d3cad9f0..f2ffac85bf40 100644 --- a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use if_chain::if_chain; -use rustc_ast::ast::{BindingMode, Lifetime, Mutability, Param, PatKind, Path, TyKind}; +use rustc_ast::ast::{BindingAnnotation, ByRef, Lifetime, Mutability, Param, PatKind, Path, TyKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -120,14 +120,14 @@ impl EarlyLintPass for NeedlessArbitrarySelfType { match &p.ty.kind { TyKind::Path(None, path) => { - if let PatKind::Ident(BindingMode::ByValue(mutbl), _, _) = p.pat.kind { + if let PatKind::Ident(BindingAnnotation(ByRef::No, mutbl), _, _) = p.pat.kind { check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl); } }, TyKind::Rptr(lifetime, mut_ty) => { if_chain! { if let TyKind::Path(None, path) = &mut_ty.ty.kind; - if let PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, _) = p.pat.kind; + if let PatKind::Ident(BindingAnnotation::NONE, _, _) = p.pat.kind; then { check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl); } diff --git a/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs b/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs index 05c012b92e87..b8855e5adbff 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs @@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowedRef { if let PatKind::Ref(sub_pat, Mutability::Not) = pat.kind; // Check sub_pat got a `ref` keyword (excluding `ref mut`). - if let PatKind::Binding(BindingAnnotation::Ref, .., spanned_name, _) = sub_pat.kind; + if let PatKind::Binding(BindingAnnotation::REF, .., spanned_name, _) = sub_pat.kind; let parent_id = cx.tcx.hir().get_parent_node(pat.hir_id); if let Some(parent_node) = cx.tcx.hir().find(parent_id); then { diff --git a/src/tools/clippy/clippy_lints/src/needless_late_init.rs b/src/tools/clippy/clippy_lints/src/needless_late_init.rs index ff2999b1f4a5..de99f1d7078e 100644 --- a/src/tools/clippy/clippy_lints/src/needless_late_init.rs +++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs @@ -373,7 +373,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit { if let Local { init: None, pat: &Pat { - kind: PatKind::Binding(BindingAnnotation::Unannotated, binding_id, _, None), + kind: PatKind::Binding(BindingAnnotation::NONE, binding_id, _, None), .. }, source: LocalSource::Normal, diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 0cbef1c95fe9..6d17c7a7346f 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -8,7 +8,9 @@ use rustc_ast::ast::Attribute; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, Diagnostic}; use rustc_hir::intravisit::FnKind; -use rustc_hir::{BindingAnnotation, Body, FnDecl, GenericArg, HirId, Impl, ItemKind, Node, PatKind, QPath, TyKind}; +use rustc_hir::{ + BindingAnnotation, Body, FnDecl, GenericArg, HirId, Impl, ItemKind, Mutability, Node, PatKind, QPath, TyKind, +}; use rustc_hir::{HirIdMap, HirIdSet}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; @@ -188,13 +190,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { if !implements_borrow_trait; if !all_borrowable_trait; - if let PatKind::Binding(mode, canonical_id, ..) = arg.pat.kind; + if let PatKind::Binding(BindingAnnotation(_, Mutability::Not), canonical_id, ..) = arg.pat.kind; if !moved_vars.contains(&canonical_id); then { - if mode == BindingAnnotation::Mutable || mode == BindingAnnotation::RefMut { - continue; - } - // Dereference suggestion let sugg = |diag: &mut Diagnostic| { if let ty::Adt(def, ..) = ty.kind() { diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs index 9602d0d1d2ea..0315678bf97a 100644 --- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs @@ -130,7 +130,7 @@ fn try_get_option_occurence<'tcx>( .filter_map(|(id, &c)| none_captures.get(id).map(|&c2| (c, c2))) .all(|(x, y)| x.is_imm_ref() && y.is_imm_ref()); then { - let capture_mut = if bind_annotation == BindingAnnotation::Mutable { "mut " } else { "" }; + let capture_mut = if bind_annotation == BindingAnnotation::MUT { "mut " } else { "" }; let some_body = peel_blocks(if_then); let none_body = peel_blocks(if_else); let method_sugg = if eager_or_lazy::switch_to_eager_eval(cx, none_body) { "map_or" } else { "map_or_else" }; @@ -138,7 +138,7 @@ fn try_get_option_occurence<'tcx>( let (as_ref, as_mut) = match &expr.kind { ExprKind::AddrOf(_, Mutability::Not, _) => (true, false), ExprKind::AddrOf(_, Mutability::Mut, _) => (false, true), - _ => (bind_annotation == BindingAnnotation::Ref, bind_annotation == BindingAnnotation::RefMut), + _ => (bind_annotation == BindingAnnotation::REF, bind_annotation == BindingAnnotation::REF_MUT), }; // Check if captures the closure will need conflict with borrows made in the scrutinee. diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index 5fa4fd74853f..0960b050c240 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -221,7 +221,7 @@ impl<'tcx> PassByRefOrValue { // if function has a body and parameter is annotated with mut, ignore if let Some(param) = fn_body.and_then(|body| body.params.get(index)) { match param.pat.kind { - PatKind::Binding(BindingAnnotation::Unannotated, _, _, _) => {}, + PatKind::Binding(BindingAnnotation::NONE, _, _, _) => {}, _ => continue, } } diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index 3c5ea2d94144..47b5ff7e0f04 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -571,7 +571,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: Some((Node::Stmt(_), _)) => (), Some((Node::Local(l), _)) => { // Only trace simple bindings. e.g `let x = y;` - if let PatKind::Binding(BindingAnnotation::Unannotated, id, _, None) = l.pat.kind { + if let PatKind::Binding(BindingAnnotation::NONE, id, _, None) = l.pat.kind { self.bindings.insert(id, args_idx); } else { set_skip_flag(); @@ -644,7 +644,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: .filter_map(|(i, arg)| { let param = &body.params[arg.idx]; match param.pat.kind { - PatKind::Binding(BindingAnnotation::Unannotated, id, _, None) + PatKind::Binding(BindingAnnotation::NONE, id, _, None) if !is_lint_allowed(cx, PTR_ARG, param.hir_id) => { Some((id, i)) diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index b432ccb1ee32..98a62e1b8670 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -9,7 +9,7 @@ use clippy_utils::{ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; -use rustc_hir::{BindingAnnotation, Expr, ExprKind, Node, PatKind, PathSegment, QPath}; +use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, Node, PatKind, PathSegment, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -123,7 +123,7 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else }) = higher::IfLet::hir(cx, expr); if !is_else_clause(cx.tcx, expr); if let PatKind::TupleStruct(ref path1, [field], None) = let_pat.kind; - if let PatKind::Binding(annot, bind_id, ident, None) = field.kind; + if let PatKind::Binding(BindingAnnotation(by_ref, _), bind_id, ident, None) = field.kind; let caller_ty = cx.typeck_results().expr_ty(let_expr); let if_block = IfBlockType::IfLet(path1, caller_ty, ident.name, let_expr, if_then, if_else); if (is_early_return(sym::Option, cx, &if_block) && path_to_local_id(peel_blocks(if_then), bind_id)) @@ -132,12 +132,11 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: then { let mut applicability = Applicability::MachineApplicable; let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability); - let by_ref = matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut); let requires_semi = matches!(get_parent_node(cx.tcx, expr.hir_id), Some(Node::Stmt(_))); let sugg = format!( "{}{}?{}", receiver_str, - if by_ref { ".as_ref()" } else { "" }, + if by_ref == ByRef::Yes { ".as_ref()" } else { "" }, if requires_semi { ";" } else { "" } ); span_lint_and_sugg( diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs index b59a25e3a400..3437d196b5d5 100644 --- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs @@ -99,7 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit { // Matches statements which initializes vectors. For example: `let mut vec = Vec::with_capacity(10)` if_chain! { if let StmtKind::Local(local) = stmt.kind; - if let PatKind::Binding(BindingAnnotation::Mutable, local_id, _, None) = local.pat.kind; + if let PatKind::Binding(BindingAnnotation::MUT, local_id, _, None) = local.pat.kind; if let Some(init) = local.init; if let Some(len_arg) = Self::is_vec_with_capacity(cx, init); diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs index 04e2f301bfd8..fb73c386640b 100644 --- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs @@ -137,12 +137,12 @@ fn insert_necessary_parens(pat: &mut P) { struct Visitor; impl MutVisitor for Visitor { fn visit_pat(&mut self, pat: &mut P) { - use ast::{BindingMode::*, Mutability::*}; + use ast::BindingAnnotation; noop_visit_pat(pat, self); let target = match &mut pat.kind { // `i @ a | b`, `box a | b`, and `& mut? a | b`. Ident(.., Some(p)) | Box(p) | Ref(p, _) if matches!(&p.kind, Or(ps) if ps.len() > 1) => p, - Ref(p, Not) if matches!(p.kind, Ident(ByValue(Mut), ..)) => p, // `&(mut x)` + Ref(p, Mutability::Not) if matches!(p.kind, Ident(BindingAnnotation::MUT, ..)) => p, // `&(mut x)` _ => return, }; target.kind = Paren(P(take_pat(target))); diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 429c64ac1564..a298c00caed0 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -6,7 +6,9 @@ use rustc_ast::ast::{LitFloatType, LitKind}; use rustc_ast::LitIntType; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; -use rustc_hir::{ArrayLen, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind}; +use rustc_hir::{ + ArrayLen, BindingAnnotation, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind, +}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::{Ident, Symbol}; @@ -609,10 +611,16 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { match pat.value.kind { PatKind::Wild => kind!("Wild"), - PatKind::Binding(anno, .., name, sub) => { + PatKind::Binding(ann, _, name, sub) => { bind!(self, name); opt_bind!(self, sub); - kind!("Binding(BindingAnnotation::{anno:?}, _, {name}, {sub})"); + let ann = match ann { + BindingAnnotation::NONE => "NONE", + BindingAnnotation::REF => "REF", + BindingAnnotation::MUT => "MUT", + BindingAnnotation::REF_MUT => "REF_MUT", + }; + kind!("Binding(BindingAnnotation::{ann}, _, {name}, {sub})"); self.ident(name); sub.if_some(|p| self.pat(p)); }, diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs index 35db45e2b0c9..627f65107002 100644 --- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs +++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs @@ -157,7 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) { if let Some(init_expr) = local.init - && let PatKind::Binding(BindingAnnotation::Mutable, id, name, None) = local.pat.kind + && let PatKind::Binding(BindingAnnotation::MUT, id, name, None) = local.pat.kind && !in_external_macro(cx.sess(), local.span) && let Some(init) = get_vec_init_kind(cx, init_expr) && !matches!(init, VecInitKind::WithExprCapacity(_)) diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 1834e2a2de87..e531dc29dccf 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -6,9 +6,9 @@ use rustc_data_structures::fx::FxHasher; use rustc_hir::def::Res; use rustc_hir::HirIdMap; use rustc_hir::{ - ArrayLen, BinOpKind, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard, - HirId, InlineAsmOperand, Let, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath, - Stmt, StmtKind, Ty, TyKind, TypeBinding, + ArrayLen, BinOpKind, BindingAnnotation, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, GenericArg, + GenericArgs, Guard, HirId, InlineAsmOperand, Let, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, + PathSegment, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding, }; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::LateContext; @@ -815,8 +815,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { pub fn hash_pat(&mut self, pat: &Pat<'_>) { std::mem::discriminant(&pat.kind).hash(&mut self.s); match pat.kind { - PatKind::Binding(ann, _, _, pat) => { - std::mem::discriminant(&ann).hash(&mut self.s); + PatKind::Binding(BindingAnnotation(by_ref, mutability), _, _, pat) => { + std::mem::discriminant(&by_ref).hash(&mut self.s); + std::mem::discriminant(&mutability).hash(&mut self.s); if let Some(pat) = pat { self.hash_pat(pat); } diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 997e773b5da4..839e6292f381 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -192,7 +192,7 @@ pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option< let hir = cx.tcx.hir(); if_chain! { if let Some(Node::Pat(pat)) = hir.find(hir_id); - if matches!(pat.kind, PatKind::Binding(BindingAnnotation::Unannotated, ..)); + if matches!(pat.kind, PatKind::Binding(BindingAnnotation::NONE, ..)); let parent = hir.get_parent_node(hir_id); if let Some(Node::Local(local)) = hir.find(parent); then { diff --git a/src/tools/clippy/tests/ui/author.stdout b/src/tools/clippy/tests/ui/author.stdout index 3125863036bb..597318a556b8 100644 --- a/src/tools/clippy/tests/ui/author.stdout +++ b/src/tools/clippy/tests/ui/author.stdout @@ -6,7 +6,7 @@ if_chain! { if match_qpath(qpath, &["char"]); if let ExprKind::Lit(ref lit) = expr.kind; if let LitKind::Int(69, LitIntType::Unsuffixed) = lit.node; - if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local.pat.kind; + if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind; if name.as_str() == "x"; then { // report your lint here diff --git a/src/tools/clippy/tests/ui/author/blocks.stdout b/src/tools/clippy/tests/ui/author/blocks.stdout index 2fc4a7d1f7fe..a529981e2e68 100644 --- a/src/tools/clippy/tests/ui/author/blocks.stdout +++ b/src/tools/clippy/tests/ui/author/blocks.stdout @@ -5,13 +5,13 @@ if_chain! { if let Some(init) = local.init; if let ExprKind::Lit(ref lit) = init.kind; if let LitKind::Int(42, LitIntType::Signed(IntTy::I32)) = lit.node; - if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local.pat.kind; + if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind; if name.as_str() == "x"; if let StmtKind::Local(local1) = block.stmts[1].kind; if let Some(init1) = local1.init; if let ExprKind::Lit(ref lit1) = init1.kind; if let LitKind::Float(_, LitFloatType::Suffixed(FloatTy::F32)) = lit1.node; - if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local1.pat.kind; + if let PatKind::Binding(BindingAnnotation::NONE, _, name1, None) = local1.pat.kind; if name1.as_str() == "_t"; if let StmtKind::Semi(e) = block.stmts[2].kind; if let ExprKind::Unary(UnOp::Neg, inner) = e.kind; @@ -31,7 +31,7 @@ if_chain! { if let ExprKind::Path(ref qpath) = func.kind; if match_qpath(qpath, &["String", "new"]); if args.is_empty(); - if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local.pat.kind; + if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind; if name.as_str() == "expr"; if let Some(trailing_expr) = block.expr; if let ExprKind::Call(func1, args1) = trailing_expr.kind; diff --git a/src/tools/clippy/tests/ui/author/loop.stdout b/src/tools/clippy/tests/ui/author/loop.stdout index 3d9560f697a7..ceb53fcd4963 100644 --- a/src/tools/clippy/tests/ui/author/loop.stdout +++ b/src/tools/clippy/tests/ui/author/loop.stdout @@ -1,6 +1,6 @@ if_chain! { if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::ForLoop::hir(expr); - if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = pat.kind; + if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = pat.kind; if name.as_str() == "y"; if let ExprKind::Struct(qpath, fields, None) = arg.kind; if matches!(qpath, QPath::LangItem(LangItem::Range, _)); @@ -17,7 +17,7 @@ if_chain! { if let Some(init) = local.init; if let ExprKind::Path(ref qpath1) = init.kind; if match_qpath(qpath1, &["y"]); - if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local.pat.kind; + if let PatKind::Binding(BindingAnnotation::NONE, _, name1, None) = local.pat.kind; if name1.as_str() == "z"; if block.expr.is_none(); then { diff --git a/src/tools/clippy/tests/ui/author/matches.stdout b/src/tools/clippy/tests/ui/author/matches.stdout index 38444a0094ca..2cf69a035b4c 100644 --- a/src/tools/clippy/tests/ui/author/matches.stdout +++ b/src/tools/clippy/tests/ui/author/matches.stdout @@ -21,7 +21,7 @@ if_chain! { if let Some(init1) = local1.init; if let ExprKind::Lit(ref lit4) = init1.kind; if let LitKind::Int(3, LitIntType::Unsuffixed) = lit4.node; - if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local1.pat.kind; + if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local1.pat.kind; if name.as_str() == "x"; if let Some(trailing_expr) = block.expr; if let ExprKind::Path(ref qpath) = trailing_expr.kind; @@ -30,7 +30,7 @@ if_chain! { if arms[2].guard.is_none(); if let ExprKind::Lit(ref lit5) = arms[2].body.kind; if let LitKind::Int(1, LitIntType::Unsuffixed) = lit5.node; - if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local.pat.kind; + if let PatKind::Binding(BindingAnnotation::NONE, _, name1, None) = local.pat.kind; if name1.as_str() == "a"; then { // report your lint here From e5f30f4dfa3b9311273b2546897b23ddafd17133 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 30 Aug 2022 17:36:53 -0500 Subject: [PATCH 4102/5092] clippy: BindingAnnotation change --- clippy_lints/src/dereference.rs | 2 +- clippy_lints/src/explicit_write.rs | 2 +- clippy_lints/src/index_refutable_slice.rs | 16 ++++++++------- clippy_lints/src/let_if_seq.rs | 4 ++-- clippy_lints/src/loops/manual_find.rs | 2 +- clippy_lints/src/loops/mut_range_bound.rs | 2 +- clippy_lints/src/loops/same_item_push.rs | 4 ++-- clippy_lints/src/matches/manual_map.rs | 2 +- clippy_lints/src/matches/match_as_ref.rs | 20 +++++++++---------- clippy_lints/src/matches/needless_match.rs | 5 ++--- clippy_lints/src/matches/single_match.rs | 2 +- clippy_lints/src/methods/clone_on_copy.rs | 9 ++------- clippy_lints/src/methods/iter_skip_next.rs | 2 +- clippy_lints/src/methods/map_clone.rs | 4 ++-- clippy_lints/src/methods/str_splitn.rs | 11 +++++----- clippy_lints/src/misc.rs | 11 +++++----- .../src/misc_early/redundant_pattern.rs | 12 +++-------- .../src/needless_arbitrary_self_type.rs | 6 +++--- clippy_lints/src/needless_borrowed_ref.rs | 2 +- clippy_lints/src/needless_late_init.rs | 2 +- clippy_lints/src/needless_pass_by_value.rs | 10 ++++------ clippy_lints/src/option_if_let_else.rs | 4 ++-- clippy_lints/src/pass_by_ref_or_value.rs | 2 +- clippy_lints/src/ptr.rs | 4 ++-- clippy_lints/src/question_mark.rs | 7 +++---- .../src/slow_vector_initialization.rs | 2 +- clippy_lints/src/unnested_or_patterns.rs | 4 ++-- clippy_lints/src/utils/author.rs | 14 ++++++++++--- clippy_lints/src/vec_init_then_push.rs | 2 +- clippy_utils/src/hir_utils.rs | 11 +++++----- clippy_utils/src/lib.rs | 2 +- tests/ui/author.stdout | 2 +- tests/ui/author/blocks.stdout | 6 +++--- tests/ui/author/loop.stdout | 4 ++-- tests/ui/author/matches.stdout | 4 ++-- 35 files changed, 95 insertions(+), 103 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 1506ea604f0d..3de188d96ce8 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -503,7 +503,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { } fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { - if let PatKind::Binding(BindingAnnotation::Ref, id, name, _) = pat.kind { + if let PatKind::Binding(BindingAnnotation::REF, id, name, _) = pat.kind { if let Some(opt_prev_pat) = self.ref_locals.get_mut(&id) { // This binding id has been seen before. Add this pattern to the list of changes. if let Some(prev_pat) = opt_prev_pat { diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index 5bf4313b41a4..502f0b583c41 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -128,7 +128,7 @@ fn look_in_block<'tcx, 'hir>(cx: &LateContext<'tcx>, kind: &'tcx ExprKind<'hir>) if let Some(Node::Pat(res_pat)) = cx.tcx.hir().find(expr_res); // Find id of the local we found in the block - if let PatKind::Binding(BindingAnnotation::Unannotated, local_hir_id, _ident, None) = local.pat.kind; + if let PatKind::Binding(BindingAnnotation::NONE, local_hir_id, _ident, None) = local.pat.kind; // If those two are the same hir id if res_pat.hir_id == local_hir_id; diff --git a/clippy_lints/src/index_refutable_slice.rs b/clippy_lints/src/index_refutable_slice.rs index d0c6495e35a7..0dd7f5bf000d 100644 --- a/clippy_lints/src/index_refutable_slice.rs +++ b/clippy_lints/src/index_refutable_slice.rs @@ -95,12 +95,14 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap = FxHashSet::default(); let mut slices: FxIndexMap = FxIndexMap::default(); pat.walk_always(|pat| { - if let hir::PatKind::Binding(binding, value_hir_id, ident, sub_pat) = pat.kind { - // We'll just ignore mut and ref mut for simplicity sake right now - if let hir::BindingAnnotation::Mutable | hir::BindingAnnotation::RefMut = binding { - return; - } - + // We'll just ignore mut and ref mut for simplicity sake right now + if let hir::PatKind::Binding( + hir::BindingAnnotation(by_ref, hir::Mutability::Not), + value_hir_id, + ident, + sub_pat, + ) = pat.kind + { // This block catches bindings with sub patterns. It would be hard to build a correct suggestion // for them and it's likely that the user knows what they are doing in such a case. if removed_pat.contains(&value_hir_id) { @@ -116,7 +118,7 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap LateLintPass<'tcx> for LetIfSeq { }; let mutability = match mode { - BindingAnnotation::RefMut | BindingAnnotation::Mutable => " ", + BindingAnnotation(_, Mutability::Mut) => " ", _ => "", }; diff --git a/clippy_lints/src/loops/manual_find.rs b/clippy_lints/src/loops/manual_find.rs index 215c83a7edf6..09b2376d5c04 100644 --- a/clippy_lints/src/loops/manual_find.rs +++ b/clippy_lints/src/loops/manual_find.rs @@ -106,7 +106,7 @@ fn get_binding(pat: &Pat<'_>) -> Option { hir_id = None; return; } - if let BindingAnnotation::Unannotated = annotation { + if let BindingAnnotation::NONE = annotation { hir_id = Some(id); } }); diff --git a/clippy_lints/src/loops/mut_range_bound.rs b/clippy_lints/src/loops/mut_range_bound.rs index aedf3810b23e..fce2d54639cb 100644 --- a/clippy_lints/src/loops/mut_range_bound.rs +++ b/clippy_lints/src/loops/mut_range_bound.rs @@ -44,7 +44,7 @@ fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option if_chain! { if let Some(hir_id) = path_to_local(bound); if let Node::Pat(pat) = cx.tcx.hir().get(hir_id); - if let PatKind::Binding(BindingAnnotation::Mutable, ..) = pat.kind; + if let PatKind::Binding(BindingAnnotation::MUT, ..) = pat.kind; then { return Some(hir_id); } diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs index 1439f1f4c75d..98f73c428ebf 100644 --- a/clippy_lints/src/loops/same_item_push.rs +++ b/clippy_lints/src/loops/same_item_push.rs @@ -7,7 +7,7 @@ use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::{walk_expr, Visitor}; -use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Node, Pat, PatKind, Stmt, StmtKind}; +use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Mutability, Node, Pat, PatKind, Stmt, StmtKind}; use rustc_lint::LateContext; use rustc_span::symbol::sym; use std::iter::Iterator; @@ -65,7 +65,7 @@ pub(super) fn check<'tcx>( if_chain! { if let Node::Pat(pat) = node; if let PatKind::Binding(bind_ann, ..) = pat.kind; - if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable); + if !matches!(bind_ann, BindingAnnotation(_, Mutability::Mut)); let parent_node = cx.tcx.hir().get_parent_node(hir_id); if let Some(Node::Local(parent_let_expr)) = cx.tcx.hir().find(parent_node); if let Some(init) = parent_let_expr.init; diff --git a/clippy_lints/src/matches/manual_map.rs b/clippy_lints/src/matches/manual_map.rs index 8f98b43b9e5c..b0198e856d5b 100644 --- a/clippy_lints/src/matches/manual_map.rs +++ b/clippy_lints/src/matches/manual_map.rs @@ -165,7 +165,7 @@ fn check<'tcx>( } // `ref` and `ref mut` annotations were handled earlier. - let annotation = if matches!(annotation, BindingAnnotation::Mutable) { + let annotation = if matches!(annotation, BindingAnnotation::MUT) { "mut " } else { "" diff --git a/clippy_lints/src/matches/match_as_ref.rs b/clippy_lints/src/matches/match_as_ref.rs index a0efdecec67f..91d17f481e2d 100644 --- a/clippy_lints/src/matches/match_as_ref.rs +++ b/clippy_lints/src/matches/match_as_ref.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{is_lang_ctor, peel_blocks}; use rustc_errors::Applicability; -use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, LangItem, PatKind, QPath}; +use rustc_hir::{Arm, BindingAnnotation, ByRef, Expr, ExprKind, LangItem, Mutability, PatKind, QPath}; use rustc_lint::LateContext; use rustc_middle::ty; @@ -10,18 +10,17 @@ use super::MATCH_AS_REF; pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) { if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() { - let arm_ref: Option = if is_none_arm(cx, &arms[0]) { + let arm_ref_mut = if is_none_arm(cx, &arms[0]) { is_ref_some_arm(cx, &arms[1]) } else if is_none_arm(cx, &arms[1]) { is_ref_some_arm(cx, &arms[0]) } else { None }; - if let Some(rb) = arm_ref { - let suggestion = if rb == BindingAnnotation::Ref { - "as_ref" - } else { - "as_mut" + if let Some(rb) = arm_ref_mut { + let suggestion = match rb { + Mutability::Not => "as_ref", + Mutability::Mut => "as_mut", }; let output_ty = cx.typeck_results().expr_ty(expr); @@ -66,19 +65,18 @@ fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { } // Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`) -fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option { +fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option { if_chain! { if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind; if is_lang_ctor(cx, qpath, LangItem::OptionSome); - if let PatKind::Binding(rb, .., ident, _) = first_pat.kind; - if rb == BindingAnnotation::Ref || rb == BindingAnnotation::RefMut; + if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., ident, _) = first_pat.kind; if let ExprKind::Call(e, [arg]) = peel_blocks(arm.body).kind; if let ExprKind::Path(ref some_path) = e.kind; if is_lang_ctor(cx, some_path, LangItem::OptionSome); if let ExprKind::Path(QPath::Resolved(_, path2)) = arg.kind; if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name; then { - return Some(rb) + return Some(mutabl) } } None diff --git a/clippy_lints/src/matches/needless_match.rs b/clippy_lints/src/matches/needless_match.rs index 6f037339ec75..634eef82e532 100644 --- a/clippy_lints/src/matches/needless_match.rs +++ b/clippy_lints/src/matches/needless_match.rs @@ -8,7 +8,7 @@ use clippy_utils::{ }; use rustc_errors::Applicability; use rustc_hir::LangItem::OptionNone; -use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, FnRetTy, Guard, Node, Pat, PatKind, Path, QPath}; +use rustc_hir::{Arm, BindingAnnotation, ByRef, Expr, ExprKind, FnRetTy, Guard, Node, Pat, PatKind, Path, QPath}; use rustc_lint::LateContext; use rustc_span::sym; use rustc_typeck::hir_ty_to_ty; @@ -189,8 +189,7 @@ fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool { }, )), ) => { - return !matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut) - && pat_ident.name == first_seg.ident.name; + return !matches!(annot, BindingAnnotation(ByRef::Yes, _)) && pat_ident.name == first_seg.ident.name; }, // Example: `Custom::TypeA => Custom::TypeB`, or `None => None` (PatKind::Path(QPath::Resolved(_, p_path)), ExprKind::Path(QPath::Resolved(_, e_path))) => { diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs index 92091a0c3395..95478af45b4b 100644 --- a/clippy_lints/src/matches/single_match.rs +++ b/clippy_lints/src/matches/single_match.rs @@ -175,7 +175,7 @@ fn collect_pat_paths<'a>(acc: &mut Vec>, cx: &LateContext<'a>, pat: &Pat< let p_ty = cx.typeck_results().pat_ty(p); collect_pat_paths(acc, cx, p, p_ty); }), - PatKind::TupleStruct(..) | PatKind::Binding(BindingAnnotation::Unannotated, .., None) | PatKind::Path(_) => { + PatKind::TupleStruct(..) | PatKind::Binding(BindingAnnotation::NONE, .., None) | PatKind::Path(_) => { acc.push(ty); }, _ => {}, diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index 60e1355f9b92..2c3683a09e32 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet_with_context; use clippy_utils::sugg; use clippy_utils::ty::is_copy; use rustc_errors::Applicability; -use rustc_hir::{BindingAnnotation, Expr, ExprKind, MatchSource, Node, PatKind, QPath}; +use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, MatchSource, Node, PatKind, QPath}; use rustc_lint::LateContext; use rustc_middle::ty::{self, adjustment::Adjust}; use rustc_span::symbol::{sym, Symbol}; @@ -98,12 +98,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, _ => false, }, // local binding capturing a reference - Some(Node::Local(l)) - if matches!( - l.pat.kind, - PatKind::Binding(BindingAnnotation::Ref | BindingAnnotation::RefMut, ..) - ) => - { + Some(Node::Local(l)) if matches!(l.pat.kind, PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..)) => { return; }, _ => false, diff --git a/clippy_lints/src/methods/iter_skip_next.rs b/clippy_lints/src/methods/iter_skip_next.rs index 43e9451f7d37..beb772100aff 100644 --- a/clippy_lints/src/methods/iter_skip_next.rs +++ b/clippy_lints/src/methods/iter_skip_next.rs @@ -24,7 +24,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr if let Some(id) = path_to_local(recv); if let Node::Pat(pat) = cx.tcx.hir().get(id); if let PatKind::Binding(ann, _, _, _) = pat.kind; - if ann != BindingAnnotation::Mutable; + if ann != BindingAnnotation::MUT; then { application = Applicability::Unspecified; diag.span_help( diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs index ffedda95ff8e..a13541ad48d8 100644 --- a/clippy_lints/src/methods/map_clone.rs +++ b/clippy_lints/src/methods/map_clone.rs @@ -33,13 +33,13 @@ pub(super) fn check<'tcx>( let closure_expr = peel_blocks(&closure_body.value); match closure_body.params[0].pat.kind { hir::PatKind::Ref(inner, hir::Mutability::Not) => if let hir::PatKind::Binding( - hir::BindingAnnotation::Unannotated, .., name, None + hir::BindingAnnotation::NONE, .., name, None ) = inner.kind { if ident_eq(name, closure_expr) { lint_explicit_closure(cx, e.span, recv.span, true, msrv); } }, - hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, .., name, None) => { + hir::PatKind::Binding(hir::BindingAnnotation::NONE, .., name, None) => { match closure_expr.kind { hir::ExprKind::Unary(hir::UnOp::Deref, inner) => { if ident_eq(name, inner) { diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 4ac738272d08..c5da8c8b0fec 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -130,7 +130,7 @@ fn check_manual_split_once_indirect( let ctxt = expr.span.ctxt(); let mut parents = cx.tcx.hir().parent_iter(expr.hir_id); if let (_, Node::Local(local)) = parents.next()? - && let PatKind::Binding(BindingAnnotation::Mutable, iter_binding_id, iter_ident, None) = local.pat.kind + && let PatKind::Binding(BindingAnnotation::MUT, iter_binding_id, iter_ident, None) = local.pat.kind && let (iter_stmt_id, Node::Stmt(_)) = parents.next()? && let (_, Node::Block(enclosing_block)) = parents.next()? @@ -212,11 +212,10 @@ fn indirect_usage<'tcx>( ctxt: SyntaxContext, ) -> Option> { if let StmtKind::Local(Local { - pat: - Pat { - kind: PatKind::Binding(BindingAnnotation::Unannotated, _, ident, None), - .. - }, + pat: Pat { + kind: PatKind::Binding(BindingAnnotation::NONE, _, ident, None), + .. + }, init: Some(init_expr), hir_id: local_hir_id, .. diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 8224e80c9ccb..ea245edd7704 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -5,8 +5,8 @@ use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - self as hir, def, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind, Stmt, - StmtKind, TyKind, + self as hir, def, BinOpKind, BindingAnnotation, Body, ByRef, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind, + Stmt, StmtKind, TyKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; @@ -146,7 +146,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { return; } for arg in iter_input_pats(decl, body) { - if let PatKind::Binding(BindingAnnotation::Ref | BindingAnnotation::RefMut, ..) = arg.pat.kind { + if let PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..) = arg.pat.kind { span_lint( cx, TOPLEVEL_REF_ARG, @@ -162,9 +162,8 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { if_chain! { if !in_external_macro(cx.tcx.sess, stmt.span); if let StmtKind::Local(local) = stmt.kind; - if let PatKind::Binding(an, .., name, None) = local.pat.kind; + if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., name, None) = local.pat.kind; if let Some(init) = local.init; - if an == BindingAnnotation::Ref || an == BindingAnnotation::RefMut; then { // use the macro callsite when the init span (but not the whole local span) // comes from an expansion like `vec![1, 2, 3]` in `let ref _ = vec![1, 2, 3];` @@ -173,7 +172,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { } else { Sugg::hir(cx, init, "..") }; - let (mutopt, initref) = if an == BindingAnnotation::RefMut { + let (mutopt, initref) = if mutabl == Mutability::Mut { ("mut ", sugg_init.mut_addr()) } else { ("", sugg_init.addr()) diff --git a/clippy_lints/src/misc_early/redundant_pattern.rs b/clippy_lints/src/misc_early/redundant_pattern.rs index 525dbf7757c1..d7bb0616acb0 100644 --- a/clippy_lints/src/misc_early/redundant_pattern.rs +++ b/clippy_lints/src/misc_early/redundant_pattern.rs @@ -1,18 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use rustc_ast::ast::{BindingMode, Mutability, Pat, PatKind}; +use rustc_ast::ast::{Pat, PatKind}; use rustc_errors::Applicability; use rustc_lint::EarlyContext; use super::REDUNDANT_PATTERN; pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { - if let PatKind::Ident(left, ident, Some(ref right)) = pat.kind { - let left_binding = match left { - BindingMode::ByRef(Mutability::Mut) => "ref mut ", - BindingMode::ByRef(Mutability::Not) => "ref ", - BindingMode::ByValue(..) => "", - }; - + if let PatKind::Ident(ann, ident, Some(ref right)) = pat.kind { if let PatKind::Wild = right.kind { span_lint_and_sugg( cx, @@ -23,7 +17,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) { ident.name, ident.name, ), "try", - format!("{}{}", left_binding, ident.name), + format!("{}{}", ann.prefix_str(), ident.name), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/needless_arbitrary_self_type.rs b/clippy_lints/src/needless_arbitrary_self_type.rs index 9838d3cad9f0..f2ffac85bf40 100644 --- a/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/clippy_lints/src/needless_arbitrary_self_type.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use if_chain::if_chain; -use rustc_ast::ast::{BindingMode, Lifetime, Mutability, Param, PatKind, Path, TyKind}; +use rustc_ast::ast::{BindingAnnotation, ByRef, Lifetime, Mutability, Param, PatKind, Path, TyKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -120,14 +120,14 @@ impl EarlyLintPass for NeedlessArbitrarySelfType { match &p.ty.kind { TyKind::Path(None, path) => { - if let PatKind::Ident(BindingMode::ByValue(mutbl), _, _) = p.pat.kind { + if let PatKind::Ident(BindingAnnotation(ByRef::No, mutbl), _, _) = p.pat.kind { check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl); } }, TyKind::Rptr(lifetime, mut_ty) => { if_chain! { if let TyKind::Path(None, path) = &mut_ty.ty.kind; - if let PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, _) = p.pat.kind; + if let PatKind::Ident(BindingAnnotation::NONE, _, _) = p.pat.kind; then { check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl); } diff --git a/clippy_lints/src/needless_borrowed_ref.rs b/clippy_lints/src/needless_borrowed_ref.rs index 05c012b92e87..b8855e5adbff 100644 --- a/clippy_lints/src/needless_borrowed_ref.rs +++ b/clippy_lints/src/needless_borrowed_ref.rs @@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowedRef { if let PatKind::Ref(sub_pat, Mutability::Not) = pat.kind; // Check sub_pat got a `ref` keyword (excluding `ref mut`). - if let PatKind::Binding(BindingAnnotation::Ref, .., spanned_name, _) = sub_pat.kind; + if let PatKind::Binding(BindingAnnotation::REF, .., spanned_name, _) = sub_pat.kind; let parent_id = cx.tcx.hir().get_parent_node(pat.hir_id); if let Some(parent_node) = cx.tcx.hir().find(parent_id); then { diff --git a/clippy_lints/src/needless_late_init.rs b/clippy_lints/src/needless_late_init.rs index ff2999b1f4a5..de99f1d7078e 100644 --- a/clippy_lints/src/needless_late_init.rs +++ b/clippy_lints/src/needless_late_init.rs @@ -373,7 +373,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit { if let Local { init: None, pat: &Pat { - kind: PatKind::Binding(BindingAnnotation::Unannotated, binding_id, _, None), + kind: PatKind::Binding(BindingAnnotation::NONE, binding_id, _, None), .. }, source: LocalSource::Normal, diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 0cbef1c95fe9..6d17c7a7346f 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -8,7 +8,9 @@ use rustc_ast::ast::Attribute; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, Diagnostic}; use rustc_hir::intravisit::FnKind; -use rustc_hir::{BindingAnnotation, Body, FnDecl, GenericArg, HirId, Impl, ItemKind, Node, PatKind, QPath, TyKind}; +use rustc_hir::{ + BindingAnnotation, Body, FnDecl, GenericArg, HirId, Impl, ItemKind, Mutability, Node, PatKind, QPath, TyKind, +}; use rustc_hir::{HirIdMap, HirIdSet}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; @@ -188,13 +190,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { if !implements_borrow_trait; if !all_borrowable_trait; - if let PatKind::Binding(mode, canonical_id, ..) = arg.pat.kind; + if let PatKind::Binding(BindingAnnotation(_, Mutability::Not), canonical_id, ..) = arg.pat.kind; if !moved_vars.contains(&canonical_id); then { - if mode == BindingAnnotation::Mutable || mode == BindingAnnotation::RefMut { - continue; - } - // Dereference suggestion let sugg = |diag: &mut Diagnostic| { if let ty::Adt(def, ..) = ty.kind() { diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 9602d0d1d2ea..0315678bf97a 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -130,7 +130,7 @@ fn try_get_option_occurence<'tcx>( .filter_map(|(id, &c)| none_captures.get(id).map(|&c2| (c, c2))) .all(|(x, y)| x.is_imm_ref() && y.is_imm_ref()); then { - let capture_mut = if bind_annotation == BindingAnnotation::Mutable { "mut " } else { "" }; + let capture_mut = if bind_annotation == BindingAnnotation::MUT { "mut " } else { "" }; let some_body = peel_blocks(if_then); let none_body = peel_blocks(if_else); let method_sugg = if eager_or_lazy::switch_to_eager_eval(cx, none_body) { "map_or" } else { "map_or_else" }; @@ -138,7 +138,7 @@ fn try_get_option_occurence<'tcx>( let (as_ref, as_mut) = match &expr.kind { ExprKind::AddrOf(_, Mutability::Not, _) => (true, false), ExprKind::AddrOf(_, Mutability::Mut, _) => (false, true), - _ => (bind_annotation == BindingAnnotation::Ref, bind_annotation == BindingAnnotation::RefMut), + _ => (bind_annotation == BindingAnnotation::REF, bind_annotation == BindingAnnotation::REF_MUT), }; // Check if captures the closure will need conflict with borrows made in the scrutinee. diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 5fa4fd74853f..0960b050c240 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -221,7 +221,7 @@ impl<'tcx> PassByRefOrValue { // if function has a body and parameter is annotated with mut, ignore if let Some(param) = fn_body.and_then(|body| body.params.get(index)) { match param.pat.kind { - PatKind::Binding(BindingAnnotation::Unannotated, _, _, _) => {}, + PatKind::Binding(BindingAnnotation::NONE, _, _, _) => {}, _ => continue, } } diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 3c5ea2d94144..47b5ff7e0f04 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -571,7 +571,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: Some((Node::Stmt(_), _)) => (), Some((Node::Local(l), _)) => { // Only trace simple bindings. e.g `let x = y;` - if let PatKind::Binding(BindingAnnotation::Unannotated, id, _, None) = l.pat.kind { + if let PatKind::Binding(BindingAnnotation::NONE, id, _, None) = l.pat.kind { self.bindings.insert(id, args_idx); } else { set_skip_flag(); @@ -644,7 +644,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: .filter_map(|(i, arg)| { let param = &body.params[arg.idx]; match param.pat.kind { - PatKind::Binding(BindingAnnotation::Unannotated, id, _, None) + PatKind::Binding(BindingAnnotation::NONE, id, _, None) if !is_lint_allowed(cx, PTR_ARG, param.hir_id) => { Some((id, i)) diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index b432ccb1ee32..98a62e1b8670 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -9,7 +9,7 @@ use clippy_utils::{ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk}; -use rustc_hir::{BindingAnnotation, Expr, ExprKind, Node, PatKind, PathSegment, QPath}; +use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, Node, PatKind, PathSegment, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -123,7 +123,7 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else }) = higher::IfLet::hir(cx, expr); if !is_else_clause(cx.tcx, expr); if let PatKind::TupleStruct(ref path1, [field], None) = let_pat.kind; - if let PatKind::Binding(annot, bind_id, ident, None) = field.kind; + if let PatKind::Binding(BindingAnnotation(by_ref, _), bind_id, ident, None) = field.kind; let caller_ty = cx.typeck_results().expr_ty(let_expr); let if_block = IfBlockType::IfLet(path1, caller_ty, ident.name, let_expr, if_then, if_else); if (is_early_return(sym::Option, cx, &if_block) && path_to_local_id(peel_blocks(if_then), bind_id)) @@ -132,12 +132,11 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: then { let mut applicability = Applicability::MachineApplicable; let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability); - let by_ref = matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut); let requires_semi = matches!(get_parent_node(cx.tcx, expr.hir_id), Some(Node::Stmt(_))); let sugg = format!( "{}{}?{}", receiver_str, - if by_ref { ".as_ref()" } else { "" }, + if by_ref == ByRef::Yes { ".as_ref()" } else { "" }, if requires_semi { ";" } else { "" } ); span_lint_and_sugg( diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index b59a25e3a400..3437d196b5d5 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -99,7 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for SlowVectorInit { // Matches statements which initializes vectors. For example: `let mut vec = Vec::with_capacity(10)` if_chain! { if let StmtKind::Local(local) = stmt.kind; - if let PatKind::Binding(BindingAnnotation::Mutable, local_id, _, None) = local.pat.kind; + if let PatKind::Binding(BindingAnnotation::MUT, local_id, _, None) = local.pat.kind; if let Some(init) = local.init; if let Some(len_arg) = Self::is_vec_with_capacity(cx, init); diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs index 04e2f301bfd8..fb73c386640b 100644 --- a/clippy_lints/src/unnested_or_patterns.rs +++ b/clippy_lints/src/unnested_or_patterns.rs @@ -137,12 +137,12 @@ fn insert_necessary_parens(pat: &mut P) { struct Visitor; impl MutVisitor for Visitor { fn visit_pat(&mut self, pat: &mut P) { - use ast::{BindingMode::*, Mutability::*}; + use ast::BindingAnnotation; noop_visit_pat(pat, self); let target = match &mut pat.kind { // `i @ a | b`, `box a | b`, and `& mut? a | b`. Ident(.., Some(p)) | Box(p) | Ref(p, _) if matches!(&p.kind, Or(ps) if ps.len() > 1) => p, - Ref(p, Not) if matches!(p.kind, Ident(ByValue(Mut), ..)) => p, // `&(mut x)` + Ref(p, Mutability::Not) if matches!(p.kind, Ident(BindingAnnotation::MUT, ..)) => p, // `&(mut x)` _ => return, }; target.kind = Paren(P(take_pat(target))); diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 429c64ac1564..a298c00caed0 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -6,7 +6,9 @@ use rustc_ast::ast::{LitFloatType, LitKind}; use rustc_ast::LitIntType; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; -use rustc_hir::{ArrayLen, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind}; +use rustc_hir::{ + ArrayLen, BindingAnnotation, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind, +}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::{Ident, Symbol}; @@ -609,10 +611,16 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { match pat.value.kind { PatKind::Wild => kind!("Wild"), - PatKind::Binding(anno, .., name, sub) => { + PatKind::Binding(ann, _, name, sub) => { bind!(self, name); opt_bind!(self, sub); - kind!("Binding(BindingAnnotation::{anno:?}, _, {name}, {sub})"); + let ann = match ann { + BindingAnnotation::NONE => "NONE", + BindingAnnotation::REF => "REF", + BindingAnnotation::MUT => "MUT", + BindingAnnotation::REF_MUT => "REF_MUT", + }; + kind!("Binding(BindingAnnotation::{ann}, _, {name}, {sub})"); self.ident(name); sub.if_some(|p| self.pat(p)); }, diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs index 35db45e2b0c9..627f65107002 100644 --- a/clippy_lints/src/vec_init_then_push.rs +++ b/clippy_lints/src/vec_init_then_push.rs @@ -157,7 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush { fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) { if let Some(init_expr) = local.init - && let PatKind::Binding(BindingAnnotation::Mutable, id, name, None) = local.pat.kind + && let PatKind::Binding(BindingAnnotation::MUT, id, name, None) = local.pat.kind && !in_external_macro(cx.sess(), local.span) && let Some(init) = get_vec_init_kind(cx, init_expr) && !matches!(init, VecInitKind::WithExprCapacity(_)) diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 1834e2a2de87..e531dc29dccf 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -6,9 +6,9 @@ use rustc_data_structures::fx::FxHasher; use rustc_hir::def::Res; use rustc_hir::HirIdMap; use rustc_hir::{ - ArrayLen, BinOpKind, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard, - HirId, InlineAsmOperand, Let, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath, - Stmt, StmtKind, Ty, TyKind, TypeBinding, + ArrayLen, BinOpKind, BindingAnnotation, Block, BodyId, Closure, Expr, ExprField, ExprKind, FnRetTy, GenericArg, + GenericArgs, Guard, HirId, InlineAsmOperand, Let, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, + PathSegment, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding, }; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::LateContext; @@ -815,8 +815,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { pub fn hash_pat(&mut self, pat: &Pat<'_>) { std::mem::discriminant(&pat.kind).hash(&mut self.s); match pat.kind { - PatKind::Binding(ann, _, _, pat) => { - std::mem::discriminant(&ann).hash(&mut self.s); + PatKind::Binding(BindingAnnotation(by_ref, mutability), _, _, pat) => { + std::mem::discriminant(&by_ref).hash(&mut self.s); + std::mem::discriminant(&mutability).hash(&mut self.s); if let Some(pat) = pat { self.hash_pat(pat); } diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 997e773b5da4..839e6292f381 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -192,7 +192,7 @@ pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option< let hir = cx.tcx.hir(); if_chain! { if let Some(Node::Pat(pat)) = hir.find(hir_id); - if matches!(pat.kind, PatKind::Binding(BindingAnnotation::Unannotated, ..)); + if matches!(pat.kind, PatKind::Binding(BindingAnnotation::NONE, ..)); let parent = hir.get_parent_node(hir_id); if let Some(Node::Local(local)) = hir.find(parent); then { diff --git a/tests/ui/author.stdout b/tests/ui/author.stdout index 3125863036bb..597318a556b8 100644 --- a/tests/ui/author.stdout +++ b/tests/ui/author.stdout @@ -6,7 +6,7 @@ if_chain! { if match_qpath(qpath, &["char"]); if let ExprKind::Lit(ref lit) = expr.kind; if let LitKind::Int(69, LitIntType::Unsuffixed) = lit.node; - if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local.pat.kind; + if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind; if name.as_str() == "x"; then { // report your lint here diff --git a/tests/ui/author/blocks.stdout b/tests/ui/author/blocks.stdout index 2fc4a7d1f7fe..a529981e2e68 100644 --- a/tests/ui/author/blocks.stdout +++ b/tests/ui/author/blocks.stdout @@ -5,13 +5,13 @@ if_chain! { if let Some(init) = local.init; if let ExprKind::Lit(ref lit) = init.kind; if let LitKind::Int(42, LitIntType::Signed(IntTy::I32)) = lit.node; - if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local.pat.kind; + if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind; if name.as_str() == "x"; if let StmtKind::Local(local1) = block.stmts[1].kind; if let Some(init1) = local1.init; if let ExprKind::Lit(ref lit1) = init1.kind; if let LitKind::Float(_, LitFloatType::Suffixed(FloatTy::F32)) = lit1.node; - if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local1.pat.kind; + if let PatKind::Binding(BindingAnnotation::NONE, _, name1, None) = local1.pat.kind; if name1.as_str() == "_t"; if let StmtKind::Semi(e) = block.stmts[2].kind; if let ExprKind::Unary(UnOp::Neg, inner) = e.kind; @@ -31,7 +31,7 @@ if_chain! { if let ExprKind::Path(ref qpath) = func.kind; if match_qpath(qpath, &["String", "new"]); if args.is_empty(); - if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local.pat.kind; + if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind; if name.as_str() == "expr"; if let Some(trailing_expr) = block.expr; if let ExprKind::Call(func1, args1) = trailing_expr.kind; diff --git a/tests/ui/author/loop.stdout b/tests/ui/author/loop.stdout index 3d9560f697a7..ceb53fcd4963 100644 --- a/tests/ui/author/loop.stdout +++ b/tests/ui/author/loop.stdout @@ -1,6 +1,6 @@ if_chain! { if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::ForLoop::hir(expr); - if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = pat.kind; + if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = pat.kind; if name.as_str() == "y"; if let ExprKind::Struct(qpath, fields, None) = arg.kind; if matches!(qpath, QPath::LangItem(LangItem::Range, _)); @@ -17,7 +17,7 @@ if_chain! { if let Some(init) = local.init; if let ExprKind::Path(ref qpath1) = init.kind; if match_qpath(qpath1, &["y"]); - if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local.pat.kind; + if let PatKind::Binding(BindingAnnotation::NONE, _, name1, None) = local.pat.kind; if name1.as_str() == "z"; if block.expr.is_none(); then { diff --git a/tests/ui/author/matches.stdout b/tests/ui/author/matches.stdout index 38444a0094ca..2cf69a035b4c 100644 --- a/tests/ui/author/matches.stdout +++ b/tests/ui/author/matches.stdout @@ -21,7 +21,7 @@ if_chain! { if let Some(init1) = local1.init; if let ExprKind::Lit(ref lit4) = init1.kind; if let LitKind::Int(3, LitIntType::Unsuffixed) = lit4.node; - if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local1.pat.kind; + if let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local1.pat.kind; if name.as_str() == "x"; if let Some(trailing_expr) = block.expr; if let ExprKind::Path(ref qpath) = trailing_expr.kind; @@ -30,7 +30,7 @@ if_chain! { if arms[2].guard.is_none(); if let ExprKind::Lit(ref lit5) = arms[2].body.kind; if let LitKind::Int(1, LitIntType::Unsuffixed) = lit5.node; - if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local.pat.kind; + if let PatKind::Binding(BindingAnnotation::NONE, _, name1, None) = local.pat.kind; if name1.as_str() == "a"; then { // report your lint here From 6fbc4d91653c4b59ec40816166a7b908b43c57ce Mon Sep 17 00:00:00 2001 From: Matt Hamrick Date: Fri, 2 Sep 2022 11:14:22 -0700 Subject: [PATCH 4103/5092] Fix unsupported syntax in .manifest file Fuchsia .manifest files do not support a `#` comment syntax. Because of this, if you copy and paste the current example code for this file, and then remove the line you don't need, you still see an error. To make this a bit easier to follow, split this into two code blocks, one for rustc, and one for cargo. --- src/doc/rustc/src/platform-support/fuchsia.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md index 53a510f080ec..5a815635f4be 100644 --- a/src/doc/rustc/src/platform-support/fuchsia.md +++ b/src/doc/rustc/src/platform-support/fuchsia.md @@ -330,10 +330,18 @@ Now, create the following files inside: The `package` file describes our package's name and version number. Every package must contain one. -**`pkg/hello_fuchsia.manifest`** +**`pkg/hello_fuchsia.manifest` if using cargo** ```txt -bin/hello_fuchsia=target/x86_64-fuchsia/debug/hello_fuchsia # If using cargo... -bin/hello_fuchsia=bin/hello_fuchsia # If using rustc... +bin/hello_fuchsia=target/x86_64-fuchsia/debug/hello_fuchsia +lib/ld.so.1=/arch/x64/sysroot/dist/lib/ld.so.1 +lib/libfdio.so=/arch/x64/dist/libfdio.so +meta/package=pkg/meta/package +meta/hello_fuchsia.cm=pkg/meta/hello_fuchsia.cm +``` + +**`pkg/hello_fuchsia.manifest` if using rustc** +```txt +bin/hello_fuchsia=bin/hello_fuchsia lib/ld.so.1=/arch/x64/sysroot/dist/lib/ld.so.1 lib/libfdio.so=/arch/x64/dist/libfdio.so meta/package=pkg/meta/package From ffc75af4cd01740e9daac43ff24d777525e506c1 Mon Sep 17 00:00:00 2001 From: Lukas Lueg Date: Fri, 2 Sep 2022 20:28:00 +0200 Subject: [PATCH 4104/5092] Fix `mut_mutex_lock` for Mutex behind imm deref Fixes #9415 --- clippy_lints/src/methods/mut_mutex_lock.rs | 3 ++- tests/ui/mut_mutex_lock.fixed | 7 +++++++ tests/ui/mut_mutex_lock.rs | 7 +++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/mut_mutex_lock.rs b/clippy_lints/src/methods/mut_mutex_lock.rs index bd8458a222e2..b9593b3687d9 100644 --- a/clippy_lints/src/methods/mut_mutex_lock.rs +++ b/clippy_lints/src/methods/mut_mutex_lock.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{expr_custom_deref_adjustment, ty::is_type_diagnostic_item}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, Mutability}; @@ -11,6 +11,7 @@ use super::MUT_MUTEX_LOCK; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>, recv: &'tcx Expr<'tcx>, name_span: Span) { if_chain! { + if matches!(expr_custom_deref_adjustment(cx, recv), None | Some(Mutability::Mut)); if let ty::Ref(_, _, Mutability::Mut) = cx.typeck_results().expr_ty(recv).kind(); if let Some(method_id) = cx.typeck_results().type_dependent_def_id(ex.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(method_id); diff --git a/tests/ui/mut_mutex_lock.fixed b/tests/ui/mut_mutex_lock.fixed index 36bc52e3374e..ecad10a82903 100644 --- a/tests/ui/mut_mutex_lock.fixed +++ b/tests/ui/mut_mutex_lock.fixed @@ -18,4 +18,11 @@ fn no_owned_mutex_lock() { *value += 1; } +fn issue9415() { + let mut arc_mutex = Arc::new(Mutex::new(42_u8)); + let arc_mutex: &mut Arc> = &mut arc_mutex; + let mut guard = arc_mutex.lock().unwrap(); + *guard += 1; +} + fn main() {} diff --git a/tests/ui/mut_mutex_lock.rs b/tests/ui/mut_mutex_lock.rs index ea60df5ae1bb..f2b1d6fbfbc3 100644 --- a/tests/ui/mut_mutex_lock.rs +++ b/tests/ui/mut_mutex_lock.rs @@ -18,4 +18,11 @@ fn no_owned_mutex_lock() { *value += 1; } +fn issue9415() { + let mut arc_mutex = Arc::new(Mutex::new(42_u8)); + let arc_mutex: &mut Arc> = &mut arc_mutex; + let mut guard = arc_mutex.lock().unwrap(); + *guard += 1; +} + fn main() {} From df0904750dc7ef332930f77610e12ab03b28e9fd Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 2 Sep 2022 10:54:40 -0700 Subject: [PATCH 4105/5092] rustdoc: remove unused CSS selector `.methods > .item-info` It was added with e08a84a0c18739417a50c3e46917ced5037244eb (actually, it was called `.methods > .stability` at the time) and was directly nested that way. But with the switch to `

`, the code has changed drastically out from under it, to the point where you have to go out of your way to actually get it to render this way, and the result looks overly-tight and weird alongside the normal version where this code is not reachable. --- src/librustdoc/html/static/css/rustdoc.css | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index c7a9f247e208..c4a1728151d1 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -782,10 +782,6 @@ pre, .rustdoc.source .example-wrap { margin-left: 40px; } -.methods > .item-info, .content .impl-items > .item-info { - margin-top: -8px; -} - .impl-items { flex-basis: 100%; } From 6f95c89c4d65a5579295e6490c4fa70e08424fcb Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 2 Sep 2022 11:50:19 -0700 Subject: [PATCH 4106/5092] rustdoc: remove incorrect CSS rule causing misaligned item-info --- src/librustdoc/html/static/css/rustdoc.css | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index c4a1728151d1..90c86750425f 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -778,10 +778,6 @@ pre, .rustdoc.source .example-wrap { margin-bottom: .6em; } -.content .impl-items > .item-info { - margin-left: 40px; -} - .impl-items { flex-basis: 100%; } From a7b4f189d871702b93fea0f53ae8b70a9b8fbce1 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Fri, 2 Sep 2022 16:09:58 -0400 Subject: [PATCH 4107/5092] Update backtrace --- library/backtrace | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/backtrace b/library/backtrace index 4e5a3f72929f..07872f28cd8a 160000 --- a/library/backtrace +++ b/library/backtrace @@ -1 +1 @@ -Subproject commit 4e5a3f72929f152752d5659e95bb15c8f6b41eff +Subproject commit 07872f28cd8a65c3c7428811548dc85f1f2fb05b From 0f29824760eefd74aba742fc2c287c2d3901bd63 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 2 Sep 2022 12:15:06 -0700 Subject: [PATCH 4108/5092] rustdoc: put in rule to get alignment in desktop and mobile layouts --- src/librustdoc/html/static/css/rustdoc.css | 5 +++++ src/test/rustdoc-gui/item-info-alignment.goml | 10 ++++++++++ src/test/rustdoc-gui/src/lib2/lib.rs | 10 ++++++++++ 3 files changed, 25 insertions(+) create mode 100644 src/test/rustdoc-gui/item-info-alignment.goml diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 90c86750425f..147d2260964f 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -2007,6 +2007,11 @@ in storage.js plus the media query with (min-width: 701px) #main-content > div > details.rustdoc-toggle > summary::before { left: -11px; } + + /* Align summary-nested and unnested item-info gizmos. */ + .content .impl-items > .item-info { + margin-left: 34px; + } } @media print { diff --git a/src/test/rustdoc-gui/item-info-alignment.goml b/src/test/rustdoc-gui/item-info-alignment.goml new file mode 100644 index 000000000000..4d7b5045f7c1 --- /dev/null +++ b/src/test/rustdoc-gui/item-info-alignment.goml @@ -0,0 +1,10 @@ +// This test ensures that the "item-info" looks about the same +// whether or not it's inside a toggle. +goto: file://|DOC_PATH|/lib2/struct.ItemInfoAlignmentTest.html + +// First, we try it in "desktop" mode. +size: (1200, 870) +compare-elements-position: (".impl-items > .item-info", "summary > .item-info", ("x")) +// Next, we try it in "mobile" mode (max-width: 700px). +size: (650, 650) +compare-elements-position: (".impl-items > .item-info", "summary > .item-info", ("x")) diff --git a/src/test/rustdoc-gui/src/lib2/lib.rs b/src/test/rustdoc-gui/src/lib2/lib.rs index 7f3172878bfb..5a151ed7b687 100644 --- a/src/test/rustdoc-gui/src/lib2/lib.rs +++ b/src/test/rustdoc-gui/src/lib2/lib.rs @@ -170,3 +170,13 @@ where type Output; fn index(&self, index: Idx) -> &Self::Output; } + +pub struct ItemInfoAlignmentTest; + +impl ItemInfoAlignmentTest { + /// This method has docs + #[deprecated] + pub fn foo() {} + #[deprecated] + pub fn bar() {} +} From ad72aee93c80cf2e207e1f728ff0c87336ead695 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Sun, 5 Jun 2022 10:44:14 +0200 Subject: [PATCH 4109/5092] add `--explain` subcommand --- clippy_dev/src/update_lints.rs | 188 +++++- src/docs.rs | 596 ++++++++++++++++++ src/docs/absurd_extreme_comparisons.txt | 25 + src/docs/alloc_instead_of_core.txt | 18 + src/docs/allow_attributes_without_reason.txt | 22 + src/docs/almost_complete_letter_range.txt | 15 + src/docs/almost_swapped.txt | 15 + src/docs/approx_constant.txt | 24 + src/docs/arithmetic.txt | 28 + src/docs/as_conversions.txt | 32 + src/docs/as_underscore.txt | 21 + src/docs/assertions_on_constants.txt | 14 + src/docs/assertions_on_result_states.txt | 14 + src/docs/assign_op_pattern.txt | 28 + src/docs/async_yields_async.txt | 28 + src/docs/await_holding_invalid_type.txt | 29 + src/docs/await_holding_lock.txt | 51 ++ src/docs/await_holding_refcell_ref.txt | 47 ++ src/docs/bad_bit_mask.txt | 30 + src/docs/bind_instead_of_map.txt | 22 + src/docs/blanket_clippy_restriction_lints.txt | 16 + src/docs/blocks_in_if_conditions.txt | 21 + src/docs/bool_assert_comparison.txt | 16 + src/docs/bool_comparison.txt | 18 + src/docs/bool_to_int_with_if.txt | 26 + src/docs/borrow_as_ptr.txt | 26 + src/docs/borrow_deref_ref.txt | 27 + src/docs/borrow_interior_mutable_const.txt | 40 ++ src/docs/borrowed_box.txt | 19 + src/docs/box_collection.txt | 23 + src/docs/boxed_local.txt | 18 + src/docs/branches_sharing_code.txt | 32 + src/docs/builtin_type_shadow.txt | 15 + src/docs/bytes_count_to_len.txt | 18 + src/docs/bytes_nth.txt | 16 + src/docs/cargo_common_metadata.txt | 33 + ...e_sensitive_file_extension_comparisons.txt | 21 + src/docs/cast_abs_to_unsigned.txt | 16 + src/docs/cast_enum_constructor.txt | 11 + src/docs/cast_enum_truncation.txt | 12 + src/docs/cast_lossless.txt | 26 + src/docs/cast_possible_truncation.txt | 16 + src/docs/cast_possible_wrap.txt | 17 + src/docs/cast_precision_loss.txt | 19 + src/docs/cast_ptr_alignment.txt | 21 + src/docs/cast_ref_to_mut.txt | 28 + src/docs/cast_sign_loss.txt | 15 + src/docs/cast_slice_different_sizes.txt | 38 ++ src/docs/cast_slice_from_raw_parts.txt | 20 + src/docs/char_lit_as_u8.txt | 21 + src/docs/chars_last_cmp.txt | 17 + src/docs/chars_next_cmp.txt | 19 + src/docs/checked_conversions.txt | 15 + src/docs/clone_double_ref.txt | 16 + src/docs/clone_on_copy.txt | 11 + src/docs/clone_on_ref_ptr.txt | 21 + src/docs/cloned_instead_of_copied.txt | 16 + src/docs/cmp_nan.txt | 16 + src/docs/cmp_null.txt | 23 + src/docs/cmp_owned.txt | 18 + src/docs/cognitive_complexity.txt | 13 + src/docs/collapsible_else_if.txt | 29 + src/docs/collapsible_if.txt | 23 + src/docs/collapsible_match.txt | 31 + src/docs/collapsible_str_replace.txt | 19 + src/docs/comparison_chain.txt | 36 ++ src/docs/comparison_to_empty.txt | 31 + src/docs/copy_iterator.txt | 20 + src/docs/crate_in_macro_def.txt | 35 + src/docs/create_dir.txt | 15 + src/docs/crosspointer_transmute.txt | 12 + src/docs/dbg_macro.txt | 16 + src/docs/debug_assert_with_mut_call.txt | 18 + src/docs/decimal_literal_representation.txt | 13 + src/docs/declare_interior_mutable_const.txt | 46 ++ src/docs/default_instead_of_iter_empty.txt | 15 + src/docs/default_numeric_fallback.txt | 28 + src/docs/default_trait_access.txt | 16 + src/docs/default_union_representation.txt | 36 ++ src/docs/deprecated_cfg_attr.txt | 24 + src/docs/deprecated_semver.txt | 13 + src/docs/deref_addrof.txt | 22 + src/docs/deref_by_slicing.txt | 17 + src/docs/derivable_impls.txt | 35 + src/docs/derive_hash_xor_eq.txt | 23 + src/docs/derive_ord_xor_partial_ord.txt | 44 ++ src/docs/derive_partial_eq_without_eq.txt | 25 + src/docs/disallowed_methods.txt | 41 ++ src/docs/disallowed_names.txt | 12 + src/docs/disallowed_script_idents.txt | 32 + src/docs/disallowed_types.txt | 33 + src/docs/diverging_sub_expression.txt | 19 + src/docs/doc_link_with_quotes.txt | 16 + src/docs/doc_markdown.txt | 35 + src/docs/double_comparisons.txt | 17 + src/docs/double_must_use.txt | 17 + src/docs/double_neg.txt | 12 + src/docs/double_parens.txt | 24 + src/docs/drop_copy.txt | 15 + src/docs/drop_non_drop.txt | 13 + src/docs/drop_ref.txt | 17 + src/docs/duplicate_mod.txt | 31 + src/docs/duplicate_underscore_argument.txt | 16 + src/docs/duration_subsec.txt | 19 + src/docs/else_if_without_else.txt | 27 + src/docs/empty_drop.txt | 20 + src/docs/empty_enum.txt | 27 + src/docs/empty_line_after_outer_attr.txt | 35 + src/docs/empty_loop.txt | 27 + src/docs/empty_structs_with_brackets.txt | 14 + src/docs/enum_clike_unportable_variant.txt | 16 + src/docs/enum_glob_use.txt | 24 + src/docs/enum_variant_names.txt | 30 + src/docs/eq_op.txt | 22 + src/docs/equatable_if_let.txt | 23 + src/docs/erasing_op.txt | 15 + src/docs/err_expect.txt | 16 + src/docs/excessive_precision.txt | 18 + src/docs/exhaustive_enums.txt | 23 + src/docs/exhaustive_structs.txt | 23 + src/docs/exit.txt | 12 + src/docs/expect_fun_call.txt | 24 + src/docs/expect_used.txt | 26 + src/docs/expl_impl_clone_on_copy.txt | 20 + src/docs/explicit_auto_deref.txt | 16 + src/docs/explicit_counter_loop.txt | 21 + src/docs/explicit_deref_methods.txt | 24 + src/docs/explicit_into_iter_loop.txt | 20 + src/docs/explicit_iter_loop.txt | 25 + src/docs/explicit_write.txt | 18 + src/docs/extend_with_drain.txt | 21 + src/docs/extra_unused_lifetimes.txt | 23 + src/docs/fallible_impl_from.txt | 32 + src/docs/field_reassign_with_default.txt | 23 + src/docs/filetype_is_file.txt | 29 + src/docs/filter_map_identity.txt | 14 + src/docs/filter_map_next.txt | 16 + src/docs/filter_next.txt | 16 + src/docs/flat_map_identity.txt | 14 + src/docs/flat_map_option.txt | 16 + src/docs/float_arithmetic.txt | 11 + src/docs/float_cmp.txt | 28 + src/docs/float_cmp_const.txt | 26 + src/docs/float_equality_without_abs.txt | 26 + src/docs/fn_address_comparisons.txt | 17 + src/docs/fn_params_excessive_bools.txt | 31 + src/docs/fn_to_numeric_cast.txt | 21 + src/docs/fn_to_numeric_cast_any.txt | 35 + .../fn_to_numeric_cast_with_truncation.txt | 26 + src/docs/for_kv_map.txt | 22 + src/docs/for_loops_over_fallibles.txt | 32 + src/docs/forget_copy.txt | 21 + src/docs/forget_non_drop.txt | 13 + src/docs/forget_ref.txt | 15 + src/docs/format_in_format_args.txt | 16 + src/docs/format_push_string.txt | 26 + src/docs/from_iter_instead_of_collect.txt | 24 + src/docs/from_over_into.txt | 26 + src/docs/from_str_radix_10.txt | 25 + src/docs/future_not_send.txt | 29 + src/docs/get_first.txt | 19 + src/docs/get_last_with_len.txt | 26 + src/docs/get_unwrap.txt | 30 + src/docs/identity_op.txt | 11 + src/docs/if_let_mutex.txt | 25 + src/docs/if_not_else.txt | 25 + src/docs/if_same_then_else.txt | 15 + src/docs/if_then_some_else_none.txt | 26 + src/docs/ifs_same_cond.txt | 25 + src/docs/implicit_clone.txt | 19 + src/docs/implicit_hasher.txt | 26 + src/docs/implicit_return.txt | 22 + src/docs/implicit_saturating_sub.txt | 21 + src/docs/imprecise_flops.txt | 23 + src/docs/inconsistent_digit_grouping.txt | 17 + src/docs/inconsistent_struct_constructor.txt | 40 ++ src/docs/index_refutable_slice.txt | 29 + src/docs/indexing_slicing.txt | 33 + src/docs/ineffective_bit_mask.txt | 25 + src/docs/inefficient_to_string.txt | 17 + src/docs/infallible_destructuring_match.txt | 29 + src/docs/infinite_iter.txt | 13 + src/docs/inherent_to_string.txt | 29 + .../inherent_to_string_shadow_display.txt | 37 ++ src/docs/init_numbered_fields.txt | 24 + src/docs/inline_always.txt | 23 + src/docs/inline_asm_x86_att_syntax.txt | 16 + src/docs/inline_asm_x86_intel_syntax.txt | 16 + src/docs/inline_fn_without_body.txt | 14 + src/docs/inspect_for_each.txt | 23 + src/docs/int_plus_one.txt | 15 + src/docs/integer_arithmetic.txt | 18 + src/docs/integer_division.txt | 19 + src/docs/into_iter_on_ref.txt | 18 + src/docs/invalid_null_ptr_usage.txt | 16 + src/docs/invalid_regex.txt | 12 + src/docs/invalid_upcast_comparisons.txt | 18 + src/docs/invalid_utf8_in_unchecked.txt | 12 + src/docs/invisible_characters.txt | 10 + src/docs/is_digit_ascii_radix.txt | 20 + src/docs/items_after_statements.txt | 37 ++ src/docs/iter_cloned_collect.txt | 17 + src/docs/iter_count.txt | 22 + src/docs/iter_next_loop.txt | 17 + src/docs/iter_next_slice.txt | 16 + src/docs/iter_not_returning_iterator.txt | 26 + src/docs/iter_nth.txt | 20 + src/docs/iter_nth_zero.txt | 17 + src/docs/iter_on_empty_collections.txt | 25 + src/docs/iter_on_single_items.txt | 24 + src/docs/iter_overeager_cloned.txt | 22 + src/docs/iter_skip_next.txt | 18 + src/docs/iter_with_drain.txt | 16 + src/docs/iterator_step_by_zero.txt | 13 + src/docs/just_underscores_and_digits.txt | 14 + src/docs/large_const_arrays.txt | 17 + src/docs/large_digit_groups.txt | 12 + src/docs/large_enum_variant.txt | 40 ++ src/docs/large_include_file.txt | 21 + src/docs/large_stack_arrays.txt | 10 + src/docs/large_types_passed_by_value.txt | 24 + src/docs/len_without_is_empty.txt | 19 + src/docs/len_zero.txt | 28 + src/docs/let_and_return.txt | 21 + src/docs/let_underscore_drop.txt | 29 + src/docs/let_underscore_lock.txt | 20 + src/docs/let_underscore_must_use.txt | 17 + src/docs/let_unit_value.txt | 13 + src/docs/linkedlist.txt | 32 + src/docs/lossy_float_literal.txt | 18 + src/docs/macro_use_imports.txt | 12 + src/docs/main_recursion.txt | 13 + src/docs/manual_assert.txt | 18 + src/docs/manual_async_fn.txt | 16 + src/docs/manual_bits.txt | 15 + src/docs/manual_filter_map.txt | 19 + src/docs/manual_find.txt | 24 + src/docs/manual_find_map.txt | 19 + src/docs/manual_flatten.txt | 25 + src/docs/manual_instant_elapsed.txt | 21 + src/docs/manual_map.txt | 17 + src/docs/manual_memcpy.txt | 18 + src/docs/manual_non_exhaustive.txt | 41 ++ src/docs/manual_ok_or.txt | 19 + src/docs/manual_range_contains.txt | 19 + src/docs/manual_rem_euclid.txt | 17 + src/docs/manual_retain.txt | 15 + src/docs/manual_saturating_arithmetic.txt | 18 + src/docs/manual_split_once.txt | 29 + src/docs/manual_str_repeat.txt | 15 + src/docs/manual_string_new.txt | 20 + src/docs/manual_strip.txt | 24 + src/docs/manual_swap.txt | 22 + src/docs/manual_unwrap_or.txt | 20 + src/docs/many_single_char_names.txt | 12 + src/docs/map_clone.txt | 22 + src/docs/map_collect_result_unit.txt | 14 + src/docs/map_entry.txt | 28 + src/docs/map_err_ignore.txt | 93 +++ src/docs/map_flatten.txt | 21 + src/docs/map_identity.txt | 16 + src/docs/map_unwrap_or.txt | 22 + src/docs/match_as_ref.txt | 23 + src/docs/match_bool.txt | 24 + src/docs/match_like_matches_macro.txt | 32 + src/docs/match_on_vec_items.txt | 29 + src/docs/match_overlapping_arm.txt | 16 + src/docs/match_ref_pats.txt | 26 + src/docs/match_result_ok.txt | 27 + src/docs/match_same_arms.txt | 38 ++ src/docs/match_single_binding.txt | 23 + src/docs/match_str_case_mismatch.txt | 22 + src/docs/match_wild_err_arm.txt | 16 + .../match_wildcard_for_single_variants.txt | 27 + src/docs/maybe_infinite_iter.txt | 16 + src/docs/mem_forget.txt | 12 + src/docs/mem_replace_option_with_none.txt | 21 + src/docs/mem_replace_with_default.txt | 18 + src/docs/mem_replace_with_uninit.txt | 24 + src/docs/min_max.txt | 18 + src/docs/mismatched_target_os.txt | 24 + src/docs/mismatching_type_param_order.txt | 33 + src/docs/misrefactored_assign_op.txt | 20 + src/docs/missing_const_for_fn.txt | 40 ++ src/docs/missing_docs_in_private_items.txt | 9 + src/docs/missing_enforced_import_renames.txt | 22 + src/docs/missing_errors_doc.txt | 21 + src/docs/missing_inline_in_public_items.txt | 45 ++ src/docs/missing_panics_doc.txt | 24 + src/docs/missing_safety_doc.txt | 26 + src/docs/missing_spin_loop.txt | 27 + src/docs/mistyped_literal_suffixes.txt | 15 + src/docs/mixed_case_hex_literals.txt | 16 + src/docs/mixed_read_write_in_expression.txt | 32 + src/docs/mod_module_files.txt | 22 + src/docs/module_inception.txt | 24 + src/docs/module_name_repetitions.txt | 20 + src/docs/modulo_arithmetic.txt | 15 + src/docs/modulo_one.txt | 16 + src/docs/multi_assignments.txt | 17 + src/docs/multiple_crate_versions.txt | 19 + src/docs/multiple_inherent_impl.txt | 26 + src/docs/must_use_candidate.txt | 23 + src/docs/must_use_unit.txt | 13 + src/docs/mut_from_ref.txt | 26 + src/docs/mut_mut.txt | 12 + src/docs/mut_mutex_lock.txt | 29 + src/docs/mut_range_bound.txt | 29 + src/docs/mutable_key_type.txt | 61 ++ src/docs/mutex_atomic.txt | 22 + src/docs/mutex_integer.txt | 22 + src/docs/naive_bytecount.txt | 22 + src/docs/needless_arbitrary_self_type.txt | 44 ++ src/docs/needless_bitwise_bool.txt | 22 + src/docs/needless_bool.txt | 26 + src/docs/needless_borrow.txt | 21 + src/docs/needless_borrowed_reference.txt | 30 + src/docs/needless_collect.txt | 14 + src/docs/needless_continue.txt | 61 ++ src/docs/needless_doctest_main.txt | 22 + src/docs/needless_for_each.txt | 24 + src/docs/needless_late_init.txt | 42 ++ src/docs/needless_lifetimes.txt | 29 + src/docs/needless_match.txt | 36 ++ src/docs/needless_option_as_deref.txt | 18 + src/docs/needless_option_take.txt | 17 + .../needless_parens_on_range_literals.txt | 23 + src/docs/needless_pass_by_value.txt | 27 + src/docs/needless_question_mark.txt | 43 ++ src/docs/needless_range_loop.txt | 23 + src/docs/needless_return.txt | 19 + src/docs/needless_splitn.txt | 16 + src/docs/needless_update.txt | 30 + src/docs/neg_cmp_op_on_partial_ord.txt | 26 + src/docs/neg_multiply.txt | 18 + src/docs/negative_feature_names.txt | 22 + src/docs/never_loop.txt | 15 + src/docs/new_ret_no_self.txt | 47 ++ src/docs/new_without_default.txt | 32 + src/docs/no_effect.txt | 12 + src/docs/no_effect_replace.txt | 11 + src/docs/no_effect_underscore_binding.txt | 16 + src/docs/non_ascii_literal.txt | 19 + src/docs/non_octal_unix_permissions.txt | 23 + src/docs/non_send_fields_in_send_ty.txt | 36 ++ src/docs/nonminimal_bool.txt | 23 + src/docs/nonsensical_open_options.txt | 14 + src/docs/nonstandard_macro_braces.txt | 15 + src/docs/not_unsafe_ptr_arg_deref.txt | 30 + src/docs/obfuscated_if_else.txt | 21 + src/docs/octal_escapes.txt | 33 + src/docs/ok_expect.txt | 19 + src/docs/only_used_in_recursion.txt | 58 ++ src/docs/op_ref.txt | 17 + src/docs/option_as_ref_deref.txt | 15 + src/docs/option_env_unwrap.txt | 19 + src/docs/option_filter_map.txt | 15 + src/docs/option_if_let_else.txt | 46 ++ src/docs/option_map_or_none.txt | 19 + src/docs/option_map_unit_fn.txt | 27 + src/docs/option_option.txt | 32 + src/docs/or_fun_call.txt | 26 + src/docs/or_then_unwrap.txt | 22 + src/docs/out_of_bounds_indexing.txt | 22 + src/docs/overflow_check_conditional.txt | 11 + src/docs/overly_complex_bool_expr.txt | 20 + src/docs/panic.txt | 10 + src/docs/panic_in_result_fn.txt | 22 + src/docs/panicking_unwrap.txt | 18 + src/docs/partialeq_ne_impl.txt | 18 + src/docs/partialeq_to_none.txt | 24 + src/docs/path_buf_push_overwrite.txt | 25 + src/docs/pattern_type_mismatch.txt | 64 ++ .../positional_named_format_parameters.txt | 15 + src/docs/possible_missing_comma.txt | 14 + src/docs/precedence.txt | 17 + src/docs/print_in_format_impl.txt | 34 + src/docs/print_literal.txt | 20 + src/docs/print_stderr.txt | 21 + src/docs/print_stdout.txt | 21 + src/docs/print_with_newline.txt | 16 + src/docs/println_empty_string.txt | 16 + src/docs/ptr_arg.txt | 29 + src/docs/ptr_as_ptr.txt | 22 + src/docs/ptr_eq.txt | 22 + src/docs/ptr_offset_with_cast.txt | 30 + src/docs/pub_use.txt | 28 + src/docs/question_mark.txt | 18 + src/docs/range_minus_one.txt | 27 + src/docs/range_plus_one.txt | 36 ++ src/docs/range_zip_with_len.txt | 16 + src/docs/rc_buffer.txt | 27 + src/docs/rc_clone_in_vec_init.txt | 29 + src/docs/rc_mutex.txt | 26 + src/docs/read_zero_byte_vec.txt | 30 + src/docs/recursive_format_impl.txt | 32 + src/docs/redundant_allocation.txt | 17 + src/docs/redundant_clone.txt | 23 + src/docs/redundant_closure.txt | 25 + src/docs/redundant_closure_call.txt | 17 + .../redundant_closure_for_method_calls.txt | 15 + src/docs/redundant_else.txt | 30 + src/docs/redundant_feature_names.txt | 23 + src/docs/redundant_field_names.txt | 22 + src/docs/redundant_pattern.txt | 22 + src/docs/redundant_pattern_matching.txt | 45 ++ src/docs/redundant_pub_crate.txt | 21 + src/docs/redundant_slicing.txt | 24 + src/docs/redundant_static_lifetimes.txt | 19 + src/docs/ref_binding_to_reference.txt | 21 + src/docs/ref_option_ref.txt | 19 + src/docs/repeat_once.txt | 25 + src/docs/rest_pat_in_fully_bound_structs.txt | 24 + src/docs/result_large_err.txt | 36 ++ src/docs/result_map_or_into_option.txt | 16 + src/docs/result_map_unit_fn.txt | 26 + src/docs/result_unit_err.txt | 40 ++ src/docs/return_self_not_must_use.txt | 46 ++ src/docs/reversed_empty_ranges.txt | 26 + src/docs/same_functions_in_if_condition.txt | 41 ++ src/docs/same_item_push.txt | 29 + src/docs/same_name_method.txt | 23 + src/docs/search_is_some.txt | 24 + src/docs/self_assignment.txt | 32 + src/docs/self_named_constructors.txt | 26 + src/docs/self_named_module_files.txt | 22 + src/docs/semicolon_if_nothing_returned.txt | 20 + src/docs/separated_literal_suffix.txt | 17 + src/docs/serde_api_misuse.txt | 10 + src/docs/shadow_reuse.txt | 20 + src/docs/shadow_same.txt | 18 + src/docs/shadow_unrelated.txt | 22 + src/docs/short_circuit_statement.txt | 14 + src/docs/should_implement_trait.txt | 22 + src/docs/significant_drop_in_scrutinee.txt | 43 ++ src/docs/similar_names.txt | 12 + src/docs/single_char_add_str.txt | 18 + src/docs/single_char_lifetime_names.txt | 28 + src/docs/single_char_pattern.txt | 20 + src/docs/single_component_path_imports.txt | 21 + src/docs/single_element_loop.txt | 21 + src/docs/single_match.txt | 21 + src/docs/single_match_else.txt | 29 + src/docs/size_of_in_element_count.txt | 16 + src/docs/skip_while_next.txt | 16 + src/docs/slow_vector_initialization.txt | 24 + src/docs/stable_sort_primitive.txt | 31 + src/docs/std_instead_of_alloc.txt | 18 + src/docs/std_instead_of_core.txt | 18 + src/docs/str_to_string.txt | 18 + src/docs/string_add.txt | 27 + src/docs/string_add_assign.txt | 17 + src/docs/string_extend_chars.txt | 23 + src/docs/string_from_utf8_as_bytes.txt | 15 + src/docs/string_lit_as_bytes.txt | 39 ++ src/docs/string_slice.txt | 17 + src/docs/string_to_string.txt | 19 + src/docs/strlen_on_c_strings.txt | 20 + src/docs/struct_excessive_bools.txt | 29 + src/docs/suboptimal_flops.txt | 50 ++ src/docs/suspicious_arithmetic_impl.txt | 17 + src/docs/suspicious_assignment_formatting.txt | 12 + src/docs/suspicious_else_formatting.txt | 30 + src/docs/suspicious_map.txt | 13 + src/docs/suspicious_op_assign_impl.txt | 15 + src/docs/suspicious_operation_groupings.txt | 41 ++ src/docs/suspicious_splitn.txt | 22 + src/docs/suspicious_to_owned.txt | 39 ++ src/docs/suspicious_unary_op_formatting.txt | 18 + src/docs/swap_ptr_to_ref.txt | 23 + src/docs/tabs_in_doc_comments.txt | 44 ++ src/docs/temporary_assignment.txt | 12 + src/docs/to_digit_is_some.txt | 15 + src/docs/to_string_in_format_args.txt | 17 + src/docs/todo.txt | 10 + src/docs/too_many_arguments.txt | 14 + src/docs/too_many_lines.txt | 17 + src/docs/toplevel_ref_arg.txt | 28 + src/docs/trailing_empty_array.txt | 22 + src/docs/trait_duplication_in_bounds.txt | 37 ++ src/docs/transmute_bytes_to_str.txt | 27 + src/docs/transmute_float_to_int.txt | 16 + src/docs/transmute_int_to_bool.txt | 16 + src/docs/transmute_int_to_char.txt | 27 + src/docs/transmute_int_to_float.txt | 16 + src/docs/transmute_num_to_bytes.txt | 16 + src/docs/transmute_ptr_to_ptr.txt | 21 + src/docs/transmute_ptr_to_ref.txt | 21 + src/docs/transmute_undefined_repr.txt | 22 + .../transmutes_expressible_as_ptr_casts.txt | 16 + src/docs/transmuting_null.txt | 15 + src/docs/trim_split_whitespace.txt | 14 + src/docs/trivial_regex.txt | 18 + src/docs/trivially_copy_pass_by_ref.txt | 43 ++ src/docs/try_err.txt | 28 + src/docs/type_complexity.txt | 14 + src/docs/type_repetition_in_bounds.txt | 16 + src/docs/undocumented_unsafe_blocks.txt | 43 ++ src/docs/undropped_manually_drops.txt | 22 + src/docs/unicode_not_nfc.txt | 12 + src/docs/unimplemented.txt | 10 + src/docs/uninit_assumed_init.txt | 28 + src/docs/uninit_vec.txt | 41 ++ src/docs/unit_arg.txt | 14 + src/docs/unit_cmp.txt | 33 + src/docs/unit_hash.txt | 20 + src/docs/unit_return_expecting_ord.txt | 20 + src/docs/unnecessary_cast.txt | 19 + src/docs/unnecessary_filter_map.txt | 23 + src/docs/unnecessary_find_map.txt | 23 + src/docs/unnecessary_fold.txt | 17 + src/docs/unnecessary_join.txt | 25 + src/docs/unnecessary_lazy_evaluations.txt | 32 + src/docs/unnecessary_mut_passed.txt | 17 + src/docs/unnecessary_operation.txt | 12 + src/docs/unnecessary_owned_empty_strings.txt | 16 + src/docs/unnecessary_self_imports.txt | 19 + src/docs/unnecessary_sort_by.txt | 21 + src/docs/unnecessary_to_owned.txt | 24 + src/docs/unnecessary_unwrap.txt | 20 + src/docs/unnecessary_wraps.txt | 36 ++ src/docs/unneeded_field_pattern.txt | 26 + src/docs/unneeded_wildcard_pattern.txt | 28 + src/docs/unnested_or_patterns.txt | 22 + src/docs/unreachable.txt | 10 + src/docs/unreadable_literal.txt | 16 + src/docs/unsafe_derive_deserialize.txt | 27 + src/docs/unsafe_removed_from_name.txt | 15 + src/docs/unseparated_literal_suffix.txt | 18 + src/docs/unsound_collection_transmute.txt | 25 + src/docs/unused_async.txt | 23 + src/docs/unused_io_amount.txt | 31 + src/docs/unused_peekable.txt | 26 + src/docs/unused_rounding.txt | 17 + src/docs/unused_self.txt | 23 + src/docs/unused_unit.txt | 18 + src/docs/unusual_byte_groupings.txt | 12 + src/docs/unwrap_in_result.txt | 39 ++ src/docs/unwrap_or_else_default.txt | 18 + src/docs/unwrap_used.txt | 37 ++ src/docs/upper_case_acronyms.txt | 25 + src/docs/use_debug.txt | 12 + src/docs/use_self.txt | 31 + src/docs/used_underscore_binding.txt | 19 + src/docs/useless_asref.txt | 17 + src/docs/useless_attribute.txt | 36 ++ src/docs/useless_conversion.txt | 17 + src/docs/useless_format.txt | 22 + src/docs/useless_let_if_seq.txt | 39 ++ src/docs/useless_transmute.txt | 12 + src/docs/useless_vec.txt | 18 + src/docs/vec_box.txt | 26 + src/docs/vec_init_then_push.txt | 23 + src/docs/vec_resize_to_zero.txt | 15 + src/docs/verbose_bit_mask.txt | 15 + src/docs/verbose_file_reads.txt | 17 + src/docs/vtable_address_comparisons.txt | 17 + src/docs/while_immutable_condition.txt | 20 + src/docs/while_let_loop.txt | 25 + src/docs/while_let_on_iterator.txt | 20 + src/docs/wildcard_dependencies.txt | 13 + src/docs/wildcard_enum_match_arm.txt | 25 + src/docs/wildcard_imports.txt | 45 ++ src/docs/wildcard_in_or_patterns.txt | 22 + src/docs/write_literal.txt | 21 + src/docs/write_with_newline.txt | 18 + src/docs/writeln_empty_string.txt | 16 + src/docs/wrong_self_convention.txt | 39 ++ src/docs/wrong_transmute.txt | 15 + src/docs/zero_divided_by_zero.txt | 15 + src/docs/zero_prefixed_literal.txt | 32 + src/docs/zero_ptr.txt | 16 + src/docs/zero_sized_map_values.txt | 24 + src/docs/zst_offset.txt | 11 + src/main.rs | 13 + 575 files changed, 13817 insertions(+), 28 deletions(-) create mode 100644 src/docs.rs create mode 100644 src/docs/absurd_extreme_comparisons.txt create mode 100644 src/docs/alloc_instead_of_core.txt create mode 100644 src/docs/allow_attributes_without_reason.txt create mode 100644 src/docs/almost_complete_letter_range.txt create mode 100644 src/docs/almost_swapped.txt create mode 100644 src/docs/approx_constant.txt create mode 100644 src/docs/arithmetic.txt create mode 100644 src/docs/as_conversions.txt create mode 100644 src/docs/as_underscore.txt create mode 100644 src/docs/assertions_on_constants.txt create mode 100644 src/docs/assertions_on_result_states.txt create mode 100644 src/docs/assign_op_pattern.txt create mode 100644 src/docs/async_yields_async.txt create mode 100644 src/docs/await_holding_invalid_type.txt create mode 100644 src/docs/await_holding_lock.txt create mode 100644 src/docs/await_holding_refcell_ref.txt create mode 100644 src/docs/bad_bit_mask.txt create mode 100644 src/docs/bind_instead_of_map.txt create mode 100644 src/docs/blanket_clippy_restriction_lints.txt create mode 100644 src/docs/blocks_in_if_conditions.txt create mode 100644 src/docs/bool_assert_comparison.txt create mode 100644 src/docs/bool_comparison.txt create mode 100644 src/docs/bool_to_int_with_if.txt create mode 100644 src/docs/borrow_as_ptr.txt create mode 100644 src/docs/borrow_deref_ref.txt create mode 100644 src/docs/borrow_interior_mutable_const.txt create mode 100644 src/docs/borrowed_box.txt create mode 100644 src/docs/box_collection.txt create mode 100644 src/docs/boxed_local.txt create mode 100644 src/docs/branches_sharing_code.txt create mode 100644 src/docs/builtin_type_shadow.txt create mode 100644 src/docs/bytes_count_to_len.txt create mode 100644 src/docs/bytes_nth.txt create mode 100644 src/docs/cargo_common_metadata.txt create mode 100644 src/docs/case_sensitive_file_extension_comparisons.txt create mode 100644 src/docs/cast_abs_to_unsigned.txt create mode 100644 src/docs/cast_enum_constructor.txt create mode 100644 src/docs/cast_enum_truncation.txt create mode 100644 src/docs/cast_lossless.txt create mode 100644 src/docs/cast_possible_truncation.txt create mode 100644 src/docs/cast_possible_wrap.txt create mode 100644 src/docs/cast_precision_loss.txt create mode 100644 src/docs/cast_ptr_alignment.txt create mode 100644 src/docs/cast_ref_to_mut.txt create mode 100644 src/docs/cast_sign_loss.txt create mode 100644 src/docs/cast_slice_different_sizes.txt create mode 100644 src/docs/cast_slice_from_raw_parts.txt create mode 100644 src/docs/char_lit_as_u8.txt create mode 100644 src/docs/chars_last_cmp.txt create mode 100644 src/docs/chars_next_cmp.txt create mode 100644 src/docs/checked_conversions.txt create mode 100644 src/docs/clone_double_ref.txt create mode 100644 src/docs/clone_on_copy.txt create mode 100644 src/docs/clone_on_ref_ptr.txt create mode 100644 src/docs/cloned_instead_of_copied.txt create mode 100644 src/docs/cmp_nan.txt create mode 100644 src/docs/cmp_null.txt create mode 100644 src/docs/cmp_owned.txt create mode 100644 src/docs/cognitive_complexity.txt create mode 100644 src/docs/collapsible_else_if.txt create mode 100644 src/docs/collapsible_if.txt create mode 100644 src/docs/collapsible_match.txt create mode 100644 src/docs/collapsible_str_replace.txt create mode 100644 src/docs/comparison_chain.txt create mode 100644 src/docs/comparison_to_empty.txt create mode 100644 src/docs/copy_iterator.txt create mode 100644 src/docs/crate_in_macro_def.txt create mode 100644 src/docs/create_dir.txt create mode 100644 src/docs/crosspointer_transmute.txt create mode 100644 src/docs/dbg_macro.txt create mode 100644 src/docs/debug_assert_with_mut_call.txt create mode 100644 src/docs/decimal_literal_representation.txt create mode 100644 src/docs/declare_interior_mutable_const.txt create mode 100644 src/docs/default_instead_of_iter_empty.txt create mode 100644 src/docs/default_numeric_fallback.txt create mode 100644 src/docs/default_trait_access.txt create mode 100644 src/docs/default_union_representation.txt create mode 100644 src/docs/deprecated_cfg_attr.txt create mode 100644 src/docs/deprecated_semver.txt create mode 100644 src/docs/deref_addrof.txt create mode 100644 src/docs/deref_by_slicing.txt create mode 100644 src/docs/derivable_impls.txt create mode 100644 src/docs/derive_hash_xor_eq.txt create mode 100644 src/docs/derive_ord_xor_partial_ord.txt create mode 100644 src/docs/derive_partial_eq_without_eq.txt create mode 100644 src/docs/disallowed_methods.txt create mode 100644 src/docs/disallowed_names.txt create mode 100644 src/docs/disallowed_script_idents.txt create mode 100644 src/docs/disallowed_types.txt create mode 100644 src/docs/diverging_sub_expression.txt create mode 100644 src/docs/doc_link_with_quotes.txt create mode 100644 src/docs/doc_markdown.txt create mode 100644 src/docs/double_comparisons.txt create mode 100644 src/docs/double_must_use.txt create mode 100644 src/docs/double_neg.txt create mode 100644 src/docs/double_parens.txt create mode 100644 src/docs/drop_copy.txt create mode 100644 src/docs/drop_non_drop.txt create mode 100644 src/docs/drop_ref.txt create mode 100644 src/docs/duplicate_mod.txt create mode 100644 src/docs/duplicate_underscore_argument.txt create mode 100644 src/docs/duration_subsec.txt create mode 100644 src/docs/else_if_without_else.txt create mode 100644 src/docs/empty_drop.txt create mode 100644 src/docs/empty_enum.txt create mode 100644 src/docs/empty_line_after_outer_attr.txt create mode 100644 src/docs/empty_loop.txt create mode 100644 src/docs/empty_structs_with_brackets.txt create mode 100644 src/docs/enum_clike_unportable_variant.txt create mode 100644 src/docs/enum_glob_use.txt create mode 100644 src/docs/enum_variant_names.txt create mode 100644 src/docs/eq_op.txt create mode 100644 src/docs/equatable_if_let.txt create mode 100644 src/docs/erasing_op.txt create mode 100644 src/docs/err_expect.txt create mode 100644 src/docs/excessive_precision.txt create mode 100644 src/docs/exhaustive_enums.txt create mode 100644 src/docs/exhaustive_structs.txt create mode 100644 src/docs/exit.txt create mode 100644 src/docs/expect_fun_call.txt create mode 100644 src/docs/expect_used.txt create mode 100644 src/docs/expl_impl_clone_on_copy.txt create mode 100644 src/docs/explicit_auto_deref.txt create mode 100644 src/docs/explicit_counter_loop.txt create mode 100644 src/docs/explicit_deref_methods.txt create mode 100644 src/docs/explicit_into_iter_loop.txt create mode 100644 src/docs/explicit_iter_loop.txt create mode 100644 src/docs/explicit_write.txt create mode 100644 src/docs/extend_with_drain.txt create mode 100644 src/docs/extra_unused_lifetimes.txt create mode 100644 src/docs/fallible_impl_from.txt create mode 100644 src/docs/field_reassign_with_default.txt create mode 100644 src/docs/filetype_is_file.txt create mode 100644 src/docs/filter_map_identity.txt create mode 100644 src/docs/filter_map_next.txt create mode 100644 src/docs/filter_next.txt create mode 100644 src/docs/flat_map_identity.txt create mode 100644 src/docs/flat_map_option.txt create mode 100644 src/docs/float_arithmetic.txt create mode 100644 src/docs/float_cmp.txt create mode 100644 src/docs/float_cmp_const.txt create mode 100644 src/docs/float_equality_without_abs.txt create mode 100644 src/docs/fn_address_comparisons.txt create mode 100644 src/docs/fn_params_excessive_bools.txt create mode 100644 src/docs/fn_to_numeric_cast.txt create mode 100644 src/docs/fn_to_numeric_cast_any.txt create mode 100644 src/docs/fn_to_numeric_cast_with_truncation.txt create mode 100644 src/docs/for_kv_map.txt create mode 100644 src/docs/for_loops_over_fallibles.txt create mode 100644 src/docs/forget_copy.txt create mode 100644 src/docs/forget_non_drop.txt create mode 100644 src/docs/forget_ref.txt create mode 100644 src/docs/format_in_format_args.txt create mode 100644 src/docs/format_push_string.txt create mode 100644 src/docs/from_iter_instead_of_collect.txt create mode 100644 src/docs/from_over_into.txt create mode 100644 src/docs/from_str_radix_10.txt create mode 100644 src/docs/future_not_send.txt create mode 100644 src/docs/get_first.txt create mode 100644 src/docs/get_last_with_len.txt create mode 100644 src/docs/get_unwrap.txt create mode 100644 src/docs/identity_op.txt create mode 100644 src/docs/if_let_mutex.txt create mode 100644 src/docs/if_not_else.txt create mode 100644 src/docs/if_same_then_else.txt create mode 100644 src/docs/if_then_some_else_none.txt create mode 100644 src/docs/ifs_same_cond.txt create mode 100644 src/docs/implicit_clone.txt create mode 100644 src/docs/implicit_hasher.txt create mode 100644 src/docs/implicit_return.txt create mode 100644 src/docs/implicit_saturating_sub.txt create mode 100644 src/docs/imprecise_flops.txt create mode 100644 src/docs/inconsistent_digit_grouping.txt create mode 100644 src/docs/inconsistent_struct_constructor.txt create mode 100644 src/docs/index_refutable_slice.txt create mode 100644 src/docs/indexing_slicing.txt create mode 100644 src/docs/ineffective_bit_mask.txt create mode 100644 src/docs/inefficient_to_string.txt create mode 100644 src/docs/infallible_destructuring_match.txt create mode 100644 src/docs/infinite_iter.txt create mode 100644 src/docs/inherent_to_string.txt create mode 100644 src/docs/inherent_to_string_shadow_display.txt create mode 100644 src/docs/init_numbered_fields.txt create mode 100644 src/docs/inline_always.txt create mode 100644 src/docs/inline_asm_x86_att_syntax.txt create mode 100644 src/docs/inline_asm_x86_intel_syntax.txt create mode 100644 src/docs/inline_fn_without_body.txt create mode 100644 src/docs/inspect_for_each.txt create mode 100644 src/docs/int_plus_one.txt create mode 100644 src/docs/integer_arithmetic.txt create mode 100644 src/docs/integer_division.txt create mode 100644 src/docs/into_iter_on_ref.txt create mode 100644 src/docs/invalid_null_ptr_usage.txt create mode 100644 src/docs/invalid_regex.txt create mode 100644 src/docs/invalid_upcast_comparisons.txt create mode 100644 src/docs/invalid_utf8_in_unchecked.txt create mode 100644 src/docs/invisible_characters.txt create mode 100644 src/docs/is_digit_ascii_radix.txt create mode 100644 src/docs/items_after_statements.txt create mode 100644 src/docs/iter_cloned_collect.txt create mode 100644 src/docs/iter_count.txt create mode 100644 src/docs/iter_next_loop.txt create mode 100644 src/docs/iter_next_slice.txt create mode 100644 src/docs/iter_not_returning_iterator.txt create mode 100644 src/docs/iter_nth.txt create mode 100644 src/docs/iter_nth_zero.txt create mode 100644 src/docs/iter_on_empty_collections.txt create mode 100644 src/docs/iter_on_single_items.txt create mode 100644 src/docs/iter_overeager_cloned.txt create mode 100644 src/docs/iter_skip_next.txt create mode 100644 src/docs/iter_with_drain.txt create mode 100644 src/docs/iterator_step_by_zero.txt create mode 100644 src/docs/just_underscores_and_digits.txt create mode 100644 src/docs/large_const_arrays.txt create mode 100644 src/docs/large_digit_groups.txt create mode 100644 src/docs/large_enum_variant.txt create mode 100644 src/docs/large_include_file.txt create mode 100644 src/docs/large_stack_arrays.txt create mode 100644 src/docs/large_types_passed_by_value.txt create mode 100644 src/docs/len_without_is_empty.txt create mode 100644 src/docs/len_zero.txt create mode 100644 src/docs/let_and_return.txt create mode 100644 src/docs/let_underscore_drop.txt create mode 100644 src/docs/let_underscore_lock.txt create mode 100644 src/docs/let_underscore_must_use.txt create mode 100644 src/docs/let_unit_value.txt create mode 100644 src/docs/linkedlist.txt create mode 100644 src/docs/lossy_float_literal.txt create mode 100644 src/docs/macro_use_imports.txt create mode 100644 src/docs/main_recursion.txt create mode 100644 src/docs/manual_assert.txt create mode 100644 src/docs/manual_async_fn.txt create mode 100644 src/docs/manual_bits.txt create mode 100644 src/docs/manual_filter_map.txt create mode 100644 src/docs/manual_find.txt create mode 100644 src/docs/manual_find_map.txt create mode 100644 src/docs/manual_flatten.txt create mode 100644 src/docs/manual_instant_elapsed.txt create mode 100644 src/docs/manual_map.txt create mode 100644 src/docs/manual_memcpy.txt create mode 100644 src/docs/manual_non_exhaustive.txt create mode 100644 src/docs/manual_ok_or.txt create mode 100644 src/docs/manual_range_contains.txt create mode 100644 src/docs/manual_rem_euclid.txt create mode 100644 src/docs/manual_retain.txt create mode 100644 src/docs/manual_saturating_arithmetic.txt create mode 100644 src/docs/manual_split_once.txt create mode 100644 src/docs/manual_str_repeat.txt create mode 100644 src/docs/manual_string_new.txt create mode 100644 src/docs/manual_strip.txt create mode 100644 src/docs/manual_swap.txt create mode 100644 src/docs/manual_unwrap_or.txt create mode 100644 src/docs/many_single_char_names.txt create mode 100644 src/docs/map_clone.txt create mode 100644 src/docs/map_collect_result_unit.txt create mode 100644 src/docs/map_entry.txt create mode 100644 src/docs/map_err_ignore.txt create mode 100644 src/docs/map_flatten.txt create mode 100644 src/docs/map_identity.txt create mode 100644 src/docs/map_unwrap_or.txt create mode 100644 src/docs/match_as_ref.txt create mode 100644 src/docs/match_bool.txt create mode 100644 src/docs/match_like_matches_macro.txt create mode 100644 src/docs/match_on_vec_items.txt create mode 100644 src/docs/match_overlapping_arm.txt create mode 100644 src/docs/match_ref_pats.txt create mode 100644 src/docs/match_result_ok.txt create mode 100644 src/docs/match_same_arms.txt create mode 100644 src/docs/match_single_binding.txt create mode 100644 src/docs/match_str_case_mismatch.txt create mode 100644 src/docs/match_wild_err_arm.txt create mode 100644 src/docs/match_wildcard_for_single_variants.txt create mode 100644 src/docs/maybe_infinite_iter.txt create mode 100644 src/docs/mem_forget.txt create mode 100644 src/docs/mem_replace_option_with_none.txt create mode 100644 src/docs/mem_replace_with_default.txt create mode 100644 src/docs/mem_replace_with_uninit.txt create mode 100644 src/docs/min_max.txt create mode 100644 src/docs/mismatched_target_os.txt create mode 100644 src/docs/mismatching_type_param_order.txt create mode 100644 src/docs/misrefactored_assign_op.txt create mode 100644 src/docs/missing_const_for_fn.txt create mode 100644 src/docs/missing_docs_in_private_items.txt create mode 100644 src/docs/missing_enforced_import_renames.txt create mode 100644 src/docs/missing_errors_doc.txt create mode 100644 src/docs/missing_inline_in_public_items.txt create mode 100644 src/docs/missing_panics_doc.txt create mode 100644 src/docs/missing_safety_doc.txt create mode 100644 src/docs/missing_spin_loop.txt create mode 100644 src/docs/mistyped_literal_suffixes.txt create mode 100644 src/docs/mixed_case_hex_literals.txt create mode 100644 src/docs/mixed_read_write_in_expression.txt create mode 100644 src/docs/mod_module_files.txt create mode 100644 src/docs/module_inception.txt create mode 100644 src/docs/module_name_repetitions.txt create mode 100644 src/docs/modulo_arithmetic.txt create mode 100644 src/docs/modulo_one.txt create mode 100644 src/docs/multi_assignments.txt create mode 100644 src/docs/multiple_crate_versions.txt create mode 100644 src/docs/multiple_inherent_impl.txt create mode 100644 src/docs/must_use_candidate.txt create mode 100644 src/docs/must_use_unit.txt create mode 100644 src/docs/mut_from_ref.txt create mode 100644 src/docs/mut_mut.txt create mode 100644 src/docs/mut_mutex_lock.txt create mode 100644 src/docs/mut_range_bound.txt create mode 100644 src/docs/mutable_key_type.txt create mode 100644 src/docs/mutex_atomic.txt create mode 100644 src/docs/mutex_integer.txt create mode 100644 src/docs/naive_bytecount.txt create mode 100644 src/docs/needless_arbitrary_self_type.txt create mode 100644 src/docs/needless_bitwise_bool.txt create mode 100644 src/docs/needless_bool.txt create mode 100644 src/docs/needless_borrow.txt create mode 100644 src/docs/needless_borrowed_reference.txt create mode 100644 src/docs/needless_collect.txt create mode 100644 src/docs/needless_continue.txt create mode 100644 src/docs/needless_doctest_main.txt create mode 100644 src/docs/needless_for_each.txt create mode 100644 src/docs/needless_late_init.txt create mode 100644 src/docs/needless_lifetimes.txt create mode 100644 src/docs/needless_match.txt create mode 100644 src/docs/needless_option_as_deref.txt create mode 100644 src/docs/needless_option_take.txt create mode 100644 src/docs/needless_parens_on_range_literals.txt create mode 100644 src/docs/needless_pass_by_value.txt create mode 100644 src/docs/needless_question_mark.txt create mode 100644 src/docs/needless_range_loop.txt create mode 100644 src/docs/needless_return.txt create mode 100644 src/docs/needless_splitn.txt create mode 100644 src/docs/needless_update.txt create mode 100644 src/docs/neg_cmp_op_on_partial_ord.txt create mode 100644 src/docs/neg_multiply.txt create mode 100644 src/docs/negative_feature_names.txt create mode 100644 src/docs/never_loop.txt create mode 100644 src/docs/new_ret_no_self.txt create mode 100644 src/docs/new_without_default.txt create mode 100644 src/docs/no_effect.txt create mode 100644 src/docs/no_effect_replace.txt create mode 100644 src/docs/no_effect_underscore_binding.txt create mode 100644 src/docs/non_ascii_literal.txt create mode 100644 src/docs/non_octal_unix_permissions.txt create mode 100644 src/docs/non_send_fields_in_send_ty.txt create mode 100644 src/docs/nonminimal_bool.txt create mode 100644 src/docs/nonsensical_open_options.txt create mode 100644 src/docs/nonstandard_macro_braces.txt create mode 100644 src/docs/not_unsafe_ptr_arg_deref.txt create mode 100644 src/docs/obfuscated_if_else.txt create mode 100644 src/docs/octal_escapes.txt create mode 100644 src/docs/ok_expect.txt create mode 100644 src/docs/only_used_in_recursion.txt create mode 100644 src/docs/op_ref.txt create mode 100644 src/docs/option_as_ref_deref.txt create mode 100644 src/docs/option_env_unwrap.txt create mode 100644 src/docs/option_filter_map.txt create mode 100644 src/docs/option_if_let_else.txt create mode 100644 src/docs/option_map_or_none.txt create mode 100644 src/docs/option_map_unit_fn.txt create mode 100644 src/docs/option_option.txt create mode 100644 src/docs/or_fun_call.txt create mode 100644 src/docs/or_then_unwrap.txt create mode 100644 src/docs/out_of_bounds_indexing.txt create mode 100644 src/docs/overflow_check_conditional.txt create mode 100644 src/docs/overly_complex_bool_expr.txt create mode 100644 src/docs/panic.txt create mode 100644 src/docs/panic_in_result_fn.txt create mode 100644 src/docs/panicking_unwrap.txt create mode 100644 src/docs/partialeq_ne_impl.txt create mode 100644 src/docs/partialeq_to_none.txt create mode 100644 src/docs/path_buf_push_overwrite.txt create mode 100644 src/docs/pattern_type_mismatch.txt create mode 100644 src/docs/positional_named_format_parameters.txt create mode 100644 src/docs/possible_missing_comma.txt create mode 100644 src/docs/precedence.txt create mode 100644 src/docs/print_in_format_impl.txt create mode 100644 src/docs/print_literal.txt create mode 100644 src/docs/print_stderr.txt create mode 100644 src/docs/print_stdout.txt create mode 100644 src/docs/print_with_newline.txt create mode 100644 src/docs/println_empty_string.txt create mode 100644 src/docs/ptr_arg.txt create mode 100644 src/docs/ptr_as_ptr.txt create mode 100644 src/docs/ptr_eq.txt create mode 100644 src/docs/ptr_offset_with_cast.txt create mode 100644 src/docs/pub_use.txt create mode 100644 src/docs/question_mark.txt create mode 100644 src/docs/range_minus_one.txt create mode 100644 src/docs/range_plus_one.txt create mode 100644 src/docs/range_zip_with_len.txt create mode 100644 src/docs/rc_buffer.txt create mode 100644 src/docs/rc_clone_in_vec_init.txt create mode 100644 src/docs/rc_mutex.txt create mode 100644 src/docs/read_zero_byte_vec.txt create mode 100644 src/docs/recursive_format_impl.txt create mode 100644 src/docs/redundant_allocation.txt create mode 100644 src/docs/redundant_clone.txt create mode 100644 src/docs/redundant_closure.txt create mode 100644 src/docs/redundant_closure_call.txt create mode 100644 src/docs/redundant_closure_for_method_calls.txt create mode 100644 src/docs/redundant_else.txt create mode 100644 src/docs/redundant_feature_names.txt create mode 100644 src/docs/redundant_field_names.txt create mode 100644 src/docs/redundant_pattern.txt create mode 100644 src/docs/redundant_pattern_matching.txt create mode 100644 src/docs/redundant_pub_crate.txt create mode 100644 src/docs/redundant_slicing.txt create mode 100644 src/docs/redundant_static_lifetimes.txt create mode 100644 src/docs/ref_binding_to_reference.txt create mode 100644 src/docs/ref_option_ref.txt create mode 100644 src/docs/repeat_once.txt create mode 100644 src/docs/rest_pat_in_fully_bound_structs.txt create mode 100644 src/docs/result_large_err.txt create mode 100644 src/docs/result_map_or_into_option.txt create mode 100644 src/docs/result_map_unit_fn.txt create mode 100644 src/docs/result_unit_err.txt create mode 100644 src/docs/return_self_not_must_use.txt create mode 100644 src/docs/reversed_empty_ranges.txt create mode 100644 src/docs/same_functions_in_if_condition.txt create mode 100644 src/docs/same_item_push.txt create mode 100644 src/docs/same_name_method.txt create mode 100644 src/docs/search_is_some.txt create mode 100644 src/docs/self_assignment.txt create mode 100644 src/docs/self_named_constructors.txt create mode 100644 src/docs/self_named_module_files.txt create mode 100644 src/docs/semicolon_if_nothing_returned.txt create mode 100644 src/docs/separated_literal_suffix.txt create mode 100644 src/docs/serde_api_misuse.txt create mode 100644 src/docs/shadow_reuse.txt create mode 100644 src/docs/shadow_same.txt create mode 100644 src/docs/shadow_unrelated.txt create mode 100644 src/docs/short_circuit_statement.txt create mode 100644 src/docs/should_implement_trait.txt create mode 100644 src/docs/significant_drop_in_scrutinee.txt create mode 100644 src/docs/similar_names.txt create mode 100644 src/docs/single_char_add_str.txt create mode 100644 src/docs/single_char_lifetime_names.txt create mode 100644 src/docs/single_char_pattern.txt create mode 100644 src/docs/single_component_path_imports.txt create mode 100644 src/docs/single_element_loop.txt create mode 100644 src/docs/single_match.txt create mode 100644 src/docs/single_match_else.txt create mode 100644 src/docs/size_of_in_element_count.txt create mode 100644 src/docs/skip_while_next.txt create mode 100644 src/docs/slow_vector_initialization.txt create mode 100644 src/docs/stable_sort_primitive.txt create mode 100644 src/docs/std_instead_of_alloc.txt create mode 100644 src/docs/std_instead_of_core.txt create mode 100644 src/docs/str_to_string.txt create mode 100644 src/docs/string_add.txt create mode 100644 src/docs/string_add_assign.txt create mode 100644 src/docs/string_extend_chars.txt create mode 100644 src/docs/string_from_utf8_as_bytes.txt create mode 100644 src/docs/string_lit_as_bytes.txt create mode 100644 src/docs/string_slice.txt create mode 100644 src/docs/string_to_string.txt create mode 100644 src/docs/strlen_on_c_strings.txt create mode 100644 src/docs/struct_excessive_bools.txt create mode 100644 src/docs/suboptimal_flops.txt create mode 100644 src/docs/suspicious_arithmetic_impl.txt create mode 100644 src/docs/suspicious_assignment_formatting.txt create mode 100644 src/docs/suspicious_else_formatting.txt create mode 100644 src/docs/suspicious_map.txt create mode 100644 src/docs/suspicious_op_assign_impl.txt create mode 100644 src/docs/suspicious_operation_groupings.txt create mode 100644 src/docs/suspicious_splitn.txt create mode 100644 src/docs/suspicious_to_owned.txt create mode 100644 src/docs/suspicious_unary_op_formatting.txt create mode 100644 src/docs/swap_ptr_to_ref.txt create mode 100644 src/docs/tabs_in_doc_comments.txt create mode 100644 src/docs/temporary_assignment.txt create mode 100644 src/docs/to_digit_is_some.txt create mode 100644 src/docs/to_string_in_format_args.txt create mode 100644 src/docs/todo.txt create mode 100644 src/docs/too_many_arguments.txt create mode 100644 src/docs/too_many_lines.txt create mode 100644 src/docs/toplevel_ref_arg.txt create mode 100644 src/docs/trailing_empty_array.txt create mode 100644 src/docs/trait_duplication_in_bounds.txt create mode 100644 src/docs/transmute_bytes_to_str.txt create mode 100644 src/docs/transmute_float_to_int.txt create mode 100644 src/docs/transmute_int_to_bool.txt create mode 100644 src/docs/transmute_int_to_char.txt create mode 100644 src/docs/transmute_int_to_float.txt create mode 100644 src/docs/transmute_num_to_bytes.txt create mode 100644 src/docs/transmute_ptr_to_ptr.txt create mode 100644 src/docs/transmute_ptr_to_ref.txt create mode 100644 src/docs/transmute_undefined_repr.txt create mode 100644 src/docs/transmutes_expressible_as_ptr_casts.txt create mode 100644 src/docs/transmuting_null.txt create mode 100644 src/docs/trim_split_whitespace.txt create mode 100644 src/docs/trivial_regex.txt create mode 100644 src/docs/trivially_copy_pass_by_ref.txt create mode 100644 src/docs/try_err.txt create mode 100644 src/docs/type_complexity.txt create mode 100644 src/docs/type_repetition_in_bounds.txt create mode 100644 src/docs/undocumented_unsafe_blocks.txt create mode 100644 src/docs/undropped_manually_drops.txt create mode 100644 src/docs/unicode_not_nfc.txt create mode 100644 src/docs/unimplemented.txt create mode 100644 src/docs/uninit_assumed_init.txt create mode 100644 src/docs/uninit_vec.txt create mode 100644 src/docs/unit_arg.txt create mode 100644 src/docs/unit_cmp.txt create mode 100644 src/docs/unit_hash.txt create mode 100644 src/docs/unit_return_expecting_ord.txt create mode 100644 src/docs/unnecessary_cast.txt create mode 100644 src/docs/unnecessary_filter_map.txt create mode 100644 src/docs/unnecessary_find_map.txt create mode 100644 src/docs/unnecessary_fold.txt create mode 100644 src/docs/unnecessary_join.txt create mode 100644 src/docs/unnecessary_lazy_evaluations.txt create mode 100644 src/docs/unnecessary_mut_passed.txt create mode 100644 src/docs/unnecessary_operation.txt create mode 100644 src/docs/unnecessary_owned_empty_strings.txt create mode 100644 src/docs/unnecessary_self_imports.txt create mode 100644 src/docs/unnecessary_sort_by.txt create mode 100644 src/docs/unnecessary_to_owned.txt create mode 100644 src/docs/unnecessary_unwrap.txt create mode 100644 src/docs/unnecessary_wraps.txt create mode 100644 src/docs/unneeded_field_pattern.txt create mode 100644 src/docs/unneeded_wildcard_pattern.txt create mode 100644 src/docs/unnested_or_patterns.txt create mode 100644 src/docs/unreachable.txt create mode 100644 src/docs/unreadable_literal.txt create mode 100644 src/docs/unsafe_derive_deserialize.txt create mode 100644 src/docs/unsafe_removed_from_name.txt create mode 100644 src/docs/unseparated_literal_suffix.txt create mode 100644 src/docs/unsound_collection_transmute.txt create mode 100644 src/docs/unused_async.txt create mode 100644 src/docs/unused_io_amount.txt create mode 100644 src/docs/unused_peekable.txt create mode 100644 src/docs/unused_rounding.txt create mode 100644 src/docs/unused_self.txt create mode 100644 src/docs/unused_unit.txt create mode 100644 src/docs/unusual_byte_groupings.txt create mode 100644 src/docs/unwrap_in_result.txt create mode 100644 src/docs/unwrap_or_else_default.txt create mode 100644 src/docs/unwrap_used.txt create mode 100644 src/docs/upper_case_acronyms.txt create mode 100644 src/docs/use_debug.txt create mode 100644 src/docs/use_self.txt create mode 100644 src/docs/used_underscore_binding.txt create mode 100644 src/docs/useless_asref.txt create mode 100644 src/docs/useless_attribute.txt create mode 100644 src/docs/useless_conversion.txt create mode 100644 src/docs/useless_format.txt create mode 100644 src/docs/useless_let_if_seq.txt create mode 100644 src/docs/useless_transmute.txt create mode 100644 src/docs/useless_vec.txt create mode 100644 src/docs/vec_box.txt create mode 100644 src/docs/vec_init_then_push.txt create mode 100644 src/docs/vec_resize_to_zero.txt create mode 100644 src/docs/verbose_bit_mask.txt create mode 100644 src/docs/verbose_file_reads.txt create mode 100644 src/docs/vtable_address_comparisons.txt create mode 100644 src/docs/while_immutable_condition.txt create mode 100644 src/docs/while_let_loop.txt create mode 100644 src/docs/while_let_on_iterator.txt create mode 100644 src/docs/wildcard_dependencies.txt create mode 100644 src/docs/wildcard_enum_match_arm.txt create mode 100644 src/docs/wildcard_imports.txt create mode 100644 src/docs/wildcard_in_or_patterns.txt create mode 100644 src/docs/write_literal.txt create mode 100644 src/docs/write_with_newline.txt create mode 100644 src/docs/writeln_empty_string.txt create mode 100644 src/docs/wrong_self_convention.txt create mode 100644 src/docs/wrong_transmute.txt create mode 100644 src/docs/zero_divided_by_zero.txt create mode 100644 src/docs/zero_prefixed_literal.txt create mode 100644 src/docs/zero_ptr.txt create mode 100644 src/docs/zero_sized_map_values.txt create mode 100644 src/docs/zst_offset.txt diff --git a/clippy_dev/src/update_lints.rs b/clippy_dev/src/update_lints.rs index 28bec872c08a..b95061bf81a2 100644 --- a/clippy_dev/src/update_lints.rs +++ b/clippy_dev/src/update_lints.rs @@ -3,7 +3,7 @@ use aho_corasick::AhoCorasickBuilder; use indoc::writedoc; use itertools::Itertools; use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind}; -use std::collections::{HashMap, HashSet}; +use std::collections::{BTreeSet, HashMap, HashSet}; use std::ffi::OsStr; use std::fmt::Write; use std::fs::{self, OpenOptions}; @@ -124,6 +124,8 @@ fn generate_lint_files( let content = gen_lint_group_list("all", all_group_lints); process_file("clippy_lints/src/lib.register_all.rs", update_mode, &content); + update_docs(update_mode, &usable_lints); + for (lint_group, lints) in Lint::by_lint_group(usable_lints.into_iter().chain(internal_lints)) { let content = gen_lint_group_list(&lint_group, lints.iter()); process_file( @@ -140,6 +142,62 @@ fn generate_lint_files( process_file("tests/ui/rename.rs", update_mode, &content); } +fn update_docs(update_mode: UpdateMode, usable_lints: &[Lint]) { + replace_region_in_file(update_mode, Path::new("src/docs.rs"), "docs! {\n", "\n}\n", |res| { + for name in usable_lints.iter().map(|lint| lint.name.clone()).sorted() { + writeln!(res, r#" "{name}","#).unwrap(); + } + }); + + if update_mode == UpdateMode::Check { + let mut extra = BTreeSet::new(); + let mut lint_names = usable_lints + .iter() + .map(|lint| lint.name.clone()) + .collect::>(); + for file in std::fs::read_dir("src/docs").unwrap() { + let filename = file.unwrap().file_name().into_string().unwrap(); + if let Some(name) = filename.strip_suffix(".txt") { + if !lint_names.remove(name) { + extra.insert(name.to_string()); + } + } + } + + let failed = print_lint_names("extra lint docs:", &extra) | print_lint_names("missing lint docs:", &lint_names); + + if failed { + exit_with_failure(); + } + } else { + if std::fs::remove_dir_all("src/docs").is_err() { + eprintln!("could not remove src/docs directory"); + } + if std::fs::create_dir("src/docs").is_err() { + eprintln!("could not recreate src/docs directory"); + } + } + for lint in usable_lints { + process_file( + Path::new("src/docs").join(lint.name.clone() + ".txt"), + update_mode, + &lint.documentation, + ); + } +} + +fn print_lint_names(header: &str, lints: &BTreeSet) -> bool { + if lints.is_empty() { + return false; + } + println!("{}", header); + for lint in lints.iter().sorted() { + println!(" {}", lint); + } + println!(); + true +} + pub fn print_lints() { let (lint_list, _, _) = gather_all(); let usable_lints = Lint::usable_lints(&lint_list); @@ -589,17 +647,26 @@ struct Lint { desc: String, module: String, declaration_range: Range, + documentation: String, } impl Lint { #[must_use] - fn new(name: &str, group: &str, desc: &str, module: &str, declaration_range: Range) -> Self { + fn new( + name: &str, + group: &str, + desc: &str, + module: &str, + declaration_range: Range, + documentation: String, + ) -> Self { Self { name: name.to_lowercase(), group: group.into(), desc: remove_line_splices(desc), module: module.into(), declaration_range, + documentation, } } @@ -852,27 +919,35 @@ fn parse_contents(contents: &str, module: &str, lints: &mut Vec) { }| token_kind == &TokenKind::Ident && *content == "declare_clippy_lint", ) { let start = range.start; - - let mut iter = iter - .by_ref() - .filter(|t| !matches!(t.token_kind, TokenKind::Whitespace | TokenKind::LineComment { .. })); + let mut docs = String::with_capacity(128); + let mut iter = iter.by_ref().filter(|t| !matches!(t.token_kind, TokenKind::Whitespace)); // matches `!{` match_tokens!(iter, Bang OpenBrace); - match iter.next() { - // #[clippy::version = "version"] pub - Some(LintDeclSearchResult { - token_kind: TokenKind::Pound, - .. - }) => { - match_tokens!(iter, OpenBracket Ident Colon Colon Ident Eq Literal{..} CloseBracket Ident); - }, - // pub - Some(LintDeclSearchResult { - token_kind: TokenKind::Ident, - .. - }) => (), - _ => continue, + let mut in_code = false; + while let Some(t) = iter.next() { + match t.token_kind { + TokenKind::LineComment { .. } => { + if let Some(line) = t.content.strip_prefix("/// ").or_else(|| t.content.strip_prefix("///")) { + if line.starts_with("```") { + docs += "```\n"; + in_code = !in_code; + } else if !(in_code && line.starts_with("# ")) { + docs += line; + docs.push('\n'); + } + } + }, + TokenKind::Pound => { + match_tokens!(iter, OpenBracket Ident Colon Colon Ident Eq Literal{..} CloseBracket Ident); + break; + }, + TokenKind::Ident => { + break; + }, + _ => {}, + } } + docs.pop(); // remove final newline let (name, group, desc) = match_tokens!( iter, @@ -890,7 +965,7 @@ fn parse_contents(contents: &str, module: &str, lints: &mut Vec) { .. }) = iter.next() { - lints.push(Lint::new(name, group, desc, module, start..range.end)); + lints.push(Lint::new(name, group, desc, module, start..range.end, docs)); } } } @@ -1120,6 +1195,7 @@ mod tests { "\"really long text\"", "module_name", Range::default(), + String::new(), ), Lint::new( "doc_markdown", @@ -1127,6 +1203,7 @@ mod tests { "\"single line\"", "module_name", Range::default(), + String::new(), ), ]; assert_eq!(expected, result); @@ -1166,6 +1243,7 @@ mod tests { "\"abc\"", "module_name", Range::default(), + String::new(), ), Lint::new( "should_assert_eq2", @@ -1173,6 +1251,7 @@ mod tests { "\"abc\"", "module_name", Range::default(), + String::new(), ), Lint::new( "should_assert_eq2", @@ -1180,6 +1259,7 @@ mod tests { "\"abc\"", "module_name", Range::default(), + String::new(), ), ]; let expected = vec![Lint::new( @@ -1188,6 +1268,7 @@ mod tests { "\"abc\"", "module_name", Range::default(), + String::new(), )]; assert_eq!(expected, Lint::usable_lints(&lints)); } @@ -1195,22 +1276,51 @@ mod tests { #[test] fn test_by_lint_group() { let lints = vec![ - Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()), + Lint::new( + "should_assert_eq", + "group1", + "\"abc\"", + "module_name", + Range::default(), + String::new(), + ), Lint::new( "should_assert_eq2", "group2", "\"abc\"", "module_name", Range::default(), + String::new(), + ), + Lint::new( + "incorrect_match", + "group1", + "\"abc\"", + "module_name", + Range::default(), + String::new(), ), - Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()), ]; let mut expected: HashMap> = HashMap::new(); expected.insert( "group1".to_string(), vec![ - Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()), - Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()), + Lint::new( + "should_assert_eq", + "group1", + "\"abc\"", + "module_name", + Range::default(), + String::new(), + ), + Lint::new( + "incorrect_match", + "group1", + "\"abc\"", + "module_name", + Range::default(), + String::new(), + ), ], ); expected.insert( @@ -1221,6 +1331,7 @@ mod tests { "\"abc\"", "module_name", Range::default(), + String::new(), )], ); assert_eq!(expected, Lint::by_lint_group(lints.into_iter())); @@ -1259,9 +1370,30 @@ mod tests { #[test] fn test_gen_lint_group_list() { let lints = vec![ - Lint::new("abc", "group1", "\"abc\"", "module_name", Range::default()), - Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()), - Lint::new("internal", "internal_style", "\"abc\"", "module_name", Range::default()), + Lint::new( + "abc", + "group1", + "\"abc\"", + "module_name", + Range::default(), + String::new(), + ), + Lint::new( + "should_assert_eq", + "group1", + "\"abc\"", + "module_name", + Range::default(), + String::new(), + ), + Lint::new( + "internal", + "internal_style", + "\"abc\"", + "module_name", + Range::default(), + String::new(), + ), ]; let expected = GENERATED_FILE_COMMENT.to_string() + &[ diff --git a/src/docs.rs b/src/docs.rs new file mode 100644 index 000000000000..69243bf4d9c9 --- /dev/null +++ b/src/docs.rs @@ -0,0 +1,596 @@ +// autogenerated. Please look at /clippy_dev/src/update_lints.rs + +macro_rules! include_lint { + ($file_name: expr) => { + include_str!($file_name) + }; +} + +macro_rules! docs { + ($($lint_name: expr,)*) => { + pub fn explain(lint: &str) { + println!("{}", match lint { + $( + $lint_name => include_lint!(concat!("docs/", concat!($lint_name, ".txt"))), + )* + _ => "unknown lint", + }) + } + } +} + +docs! { + "absurd_extreme_comparisons", + "alloc_instead_of_core", + "allow_attributes_without_reason", + "almost_complete_letter_range", + "almost_swapped", + "approx_constant", + "arithmetic", + "as_conversions", + "as_underscore", + "assertions_on_constants", + "assertions_on_result_states", + "assign_op_pattern", + "async_yields_async", + "await_holding_invalid_type", + "await_holding_lock", + "await_holding_refcell_ref", + "bad_bit_mask", + "bind_instead_of_map", + "blanket_clippy_restriction_lints", + "blocks_in_if_conditions", + "bool_assert_comparison", + "bool_comparison", + "bool_to_int_with_if", + "borrow_as_ptr", + "borrow_deref_ref", + "borrow_interior_mutable_const", + "borrowed_box", + "box_collection", + "boxed_local", + "branches_sharing_code", + "builtin_type_shadow", + "bytes_count_to_len", + "bytes_nth", + "cargo_common_metadata", + "case_sensitive_file_extension_comparisons", + "cast_abs_to_unsigned", + "cast_enum_constructor", + "cast_enum_truncation", + "cast_lossless", + "cast_possible_truncation", + "cast_possible_wrap", + "cast_precision_loss", + "cast_ptr_alignment", + "cast_ref_to_mut", + "cast_sign_loss", + "cast_slice_different_sizes", + "cast_slice_from_raw_parts", + "char_lit_as_u8", + "chars_last_cmp", + "chars_next_cmp", + "checked_conversions", + "clone_double_ref", + "clone_on_copy", + "clone_on_ref_ptr", + "cloned_instead_of_copied", + "cmp_nan", + "cmp_null", + "cmp_owned", + "cognitive_complexity", + "collapsible_else_if", + "collapsible_if", + "collapsible_match", + "collapsible_str_replace", + "comparison_chain", + "comparison_to_empty", + "copy_iterator", + "crate_in_macro_def", + "create_dir", + "crosspointer_transmute", + "dbg_macro", + "debug_assert_with_mut_call", + "decimal_literal_representation", + "declare_interior_mutable_const", + "default_instead_of_iter_empty", + "default_numeric_fallback", + "default_trait_access", + "default_union_representation", + "deprecated_cfg_attr", + "deprecated_semver", + "deref_addrof", + "deref_by_slicing", + "derivable_impls", + "derive_hash_xor_eq", + "derive_ord_xor_partial_ord", + "derive_partial_eq_without_eq", + "disallowed_methods", + "disallowed_names", + "disallowed_script_idents", + "disallowed_types", + "diverging_sub_expression", + "doc_link_with_quotes", + "doc_markdown", + "double_comparisons", + "double_must_use", + "double_neg", + "double_parens", + "drop_copy", + "drop_non_drop", + "drop_ref", + "duplicate_mod", + "duplicate_underscore_argument", + "duration_subsec", + "else_if_without_else", + "empty_drop", + "empty_enum", + "empty_line_after_outer_attr", + "empty_loop", + "empty_structs_with_brackets", + "enum_clike_unportable_variant", + "enum_glob_use", + "enum_variant_names", + "eq_op", + "equatable_if_let", + "erasing_op", + "err_expect", + "excessive_precision", + "exhaustive_enums", + "exhaustive_structs", + "exit", + "expect_fun_call", + "expect_used", + "expl_impl_clone_on_copy", + "explicit_auto_deref", + "explicit_counter_loop", + "explicit_deref_methods", + "explicit_into_iter_loop", + "explicit_iter_loop", + "explicit_write", + "extend_with_drain", + "extra_unused_lifetimes", + "fallible_impl_from", + "field_reassign_with_default", + "filetype_is_file", + "filter_map_identity", + "filter_map_next", + "filter_next", + "flat_map_identity", + "flat_map_option", + "float_arithmetic", + "float_cmp", + "float_cmp_const", + "float_equality_without_abs", + "fn_address_comparisons", + "fn_params_excessive_bools", + "fn_to_numeric_cast", + "fn_to_numeric_cast_any", + "fn_to_numeric_cast_with_truncation", + "for_kv_map", + "for_loops_over_fallibles", + "forget_copy", + "forget_non_drop", + "forget_ref", + "format_in_format_args", + "format_push_string", + "from_iter_instead_of_collect", + "from_over_into", + "from_str_radix_10", + "future_not_send", + "get_first", + "get_last_with_len", + "get_unwrap", + "identity_op", + "if_let_mutex", + "if_not_else", + "if_same_then_else", + "if_then_some_else_none", + "ifs_same_cond", + "implicit_clone", + "implicit_hasher", + "implicit_return", + "implicit_saturating_sub", + "imprecise_flops", + "inconsistent_digit_grouping", + "inconsistent_struct_constructor", + "index_refutable_slice", + "indexing_slicing", + "ineffective_bit_mask", + "inefficient_to_string", + "infallible_destructuring_match", + "infinite_iter", + "inherent_to_string", + "inherent_to_string_shadow_display", + "init_numbered_fields", + "inline_always", + "inline_asm_x86_att_syntax", + "inline_asm_x86_intel_syntax", + "inline_fn_without_body", + "inspect_for_each", + "int_plus_one", + "integer_arithmetic", + "integer_division", + "into_iter_on_ref", + "invalid_null_ptr_usage", + "invalid_regex", + "invalid_upcast_comparisons", + "invalid_utf8_in_unchecked", + "invisible_characters", + "is_digit_ascii_radix", + "items_after_statements", + "iter_cloned_collect", + "iter_count", + "iter_next_loop", + "iter_next_slice", + "iter_not_returning_iterator", + "iter_nth", + "iter_nth_zero", + "iter_on_empty_collections", + "iter_on_single_items", + "iter_overeager_cloned", + "iter_skip_next", + "iter_with_drain", + "iterator_step_by_zero", + "just_underscores_and_digits", + "large_const_arrays", + "large_digit_groups", + "large_enum_variant", + "large_include_file", + "large_stack_arrays", + "large_types_passed_by_value", + "len_without_is_empty", + "len_zero", + "let_and_return", + "let_underscore_drop", + "let_underscore_lock", + "let_underscore_must_use", + "let_unit_value", + "linkedlist", + "lossy_float_literal", + "macro_use_imports", + "main_recursion", + "manual_assert", + "manual_async_fn", + "manual_bits", + "manual_filter_map", + "manual_find", + "manual_find_map", + "manual_flatten", + "manual_instant_elapsed", + "manual_map", + "manual_memcpy", + "manual_non_exhaustive", + "manual_ok_or", + "manual_range_contains", + "manual_rem_euclid", + "manual_retain", + "manual_saturating_arithmetic", + "manual_split_once", + "manual_str_repeat", + "manual_string_new", + "manual_strip", + "manual_swap", + "manual_unwrap_or", + "many_single_char_names", + "map_clone", + "map_collect_result_unit", + "map_entry", + "map_err_ignore", + "map_flatten", + "map_identity", + "map_unwrap_or", + "match_as_ref", + "match_bool", + "match_like_matches_macro", + "match_on_vec_items", + "match_overlapping_arm", + "match_ref_pats", + "match_result_ok", + "match_same_arms", + "match_single_binding", + "match_str_case_mismatch", + "match_wild_err_arm", + "match_wildcard_for_single_variants", + "maybe_infinite_iter", + "mem_forget", + "mem_replace_option_with_none", + "mem_replace_with_default", + "mem_replace_with_uninit", + "min_max", + "mismatched_target_os", + "mismatching_type_param_order", + "misrefactored_assign_op", + "missing_const_for_fn", + "missing_docs_in_private_items", + "missing_enforced_import_renames", + "missing_errors_doc", + "missing_inline_in_public_items", + "missing_panics_doc", + "missing_safety_doc", + "missing_spin_loop", + "mistyped_literal_suffixes", + "mixed_case_hex_literals", + "mixed_read_write_in_expression", + "mod_module_files", + "module_inception", + "module_name_repetitions", + "modulo_arithmetic", + "modulo_one", + "multi_assignments", + "multiple_crate_versions", + "multiple_inherent_impl", + "must_use_candidate", + "must_use_unit", + "mut_from_ref", + "mut_mut", + "mut_mutex_lock", + "mut_range_bound", + "mutable_key_type", + "mutex_atomic", + "mutex_integer", + "naive_bytecount", + "needless_arbitrary_self_type", + "needless_bitwise_bool", + "needless_bool", + "needless_borrow", + "needless_borrowed_reference", + "needless_collect", + "needless_continue", + "needless_doctest_main", + "needless_for_each", + "needless_late_init", + "needless_lifetimes", + "needless_match", + "needless_option_as_deref", + "needless_option_take", + "needless_parens_on_range_literals", + "needless_pass_by_value", + "needless_question_mark", + "needless_range_loop", + "needless_return", + "needless_splitn", + "needless_update", + "neg_cmp_op_on_partial_ord", + "neg_multiply", + "negative_feature_names", + "never_loop", + "new_ret_no_self", + "new_without_default", + "no_effect", + "no_effect_replace", + "no_effect_underscore_binding", + "non_ascii_literal", + "non_octal_unix_permissions", + "non_send_fields_in_send_ty", + "nonminimal_bool", + "nonsensical_open_options", + "nonstandard_macro_braces", + "not_unsafe_ptr_arg_deref", + "obfuscated_if_else", + "octal_escapes", + "ok_expect", + "only_used_in_recursion", + "op_ref", + "option_as_ref_deref", + "option_env_unwrap", + "option_filter_map", + "option_if_let_else", + "option_map_or_none", + "option_map_unit_fn", + "option_option", + "or_fun_call", + "or_then_unwrap", + "out_of_bounds_indexing", + "overflow_check_conditional", + "overly_complex_bool_expr", + "panic", + "panic_in_result_fn", + "panicking_unwrap", + "partialeq_ne_impl", + "partialeq_to_none", + "path_buf_push_overwrite", + "pattern_type_mismatch", + "positional_named_format_parameters", + "possible_missing_comma", + "precedence", + "print_in_format_impl", + "print_literal", + "print_stderr", + "print_stdout", + "print_with_newline", + "println_empty_string", + "ptr_arg", + "ptr_as_ptr", + "ptr_eq", + "ptr_offset_with_cast", + "pub_use", + "question_mark", + "range_minus_one", + "range_plus_one", + "range_zip_with_len", + "rc_buffer", + "rc_clone_in_vec_init", + "rc_mutex", + "read_zero_byte_vec", + "recursive_format_impl", + "redundant_allocation", + "redundant_clone", + "redundant_closure", + "redundant_closure_call", + "redundant_closure_for_method_calls", + "redundant_else", + "redundant_feature_names", + "redundant_field_names", + "redundant_pattern", + "redundant_pattern_matching", + "redundant_pub_crate", + "redundant_slicing", + "redundant_static_lifetimes", + "ref_binding_to_reference", + "ref_option_ref", + "repeat_once", + "rest_pat_in_fully_bound_structs", + "result_large_err", + "result_map_or_into_option", + "result_map_unit_fn", + "result_unit_err", + "return_self_not_must_use", + "reversed_empty_ranges", + "same_functions_in_if_condition", + "same_item_push", + "same_name_method", + "search_is_some", + "self_assignment", + "self_named_constructors", + "self_named_module_files", + "semicolon_if_nothing_returned", + "separated_literal_suffix", + "serde_api_misuse", + "shadow_reuse", + "shadow_same", + "shadow_unrelated", + "short_circuit_statement", + "should_implement_trait", + "significant_drop_in_scrutinee", + "similar_names", + "single_char_add_str", + "single_char_lifetime_names", + "single_char_pattern", + "single_component_path_imports", + "single_element_loop", + "single_match", + "single_match_else", + "size_of_in_element_count", + "skip_while_next", + "slow_vector_initialization", + "stable_sort_primitive", + "std_instead_of_alloc", + "std_instead_of_core", + "str_to_string", + "string_add", + "string_add_assign", + "string_extend_chars", + "string_from_utf8_as_bytes", + "string_lit_as_bytes", + "string_slice", + "string_to_string", + "strlen_on_c_strings", + "struct_excessive_bools", + "suboptimal_flops", + "suspicious_arithmetic_impl", + "suspicious_assignment_formatting", + "suspicious_else_formatting", + "suspicious_map", + "suspicious_op_assign_impl", + "suspicious_operation_groupings", + "suspicious_splitn", + "suspicious_to_owned", + "suspicious_unary_op_formatting", + "swap_ptr_to_ref", + "tabs_in_doc_comments", + "temporary_assignment", + "to_digit_is_some", + "to_string_in_format_args", + "todo", + "too_many_arguments", + "too_many_lines", + "toplevel_ref_arg", + "trailing_empty_array", + "trait_duplication_in_bounds", + "transmute_bytes_to_str", + "transmute_float_to_int", + "transmute_int_to_bool", + "transmute_int_to_char", + "transmute_int_to_float", + "transmute_num_to_bytes", + "transmute_ptr_to_ptr", + "transmute_ptr_to_ref", + "transmute_undefined_repr", + "transmutes_expressible_as_ptr_casts", + "transmuting_null", + "trim_split_whitespace", + "trivial_regex", + "trivially_copy_pass_by_ref", + "try_err", + "type_complexity", + "type_repetition_in_bounds", + "undocumented_unsafe_blocks", + "undropped_manually_drops", + "unicode_not_nfc", + "unimplemented", + "uninit_assumed_init", + "uninit_vec", + "unit_arg", + "unit_cmp", + "unit_hash", + "unit_return_expecting_ord", + "unnecessary_cast", + "unnecessary_filter_map", + "unnecessary_find_map", + "unnecessary_fold", + "unnecessary_join", + "unnecessary_lazy_evaluations", + "unnecessary_mut_passed", + "unnecessary_operation", + "unnecessary_owned_empty_strings", + "unnecessary_self_imports", + "unnecessary_sort_by", + "unnecessary_to_owned", + "unnecessary_unwrap", + "unnecessary_wraps", + "unneeded_field_pattern", + "unneeded_wildcard_pattern", + "unnested_or_patterns", + "unreachable", + "unreadable_literal", + "unsafe_derive_deserialize", + "unsafe_removed_from_name", + "unseparated_literal_suffix", + "unsound_collection_transmute", + "unused_async", + "unused_io_amount", + "unused_peekable", + "unused_rounding", + "unused_self", + "unused_unit", + "unusual_byte_groupings", + "unwrap_in_result", + "unwrap_or_else_default", + "unwrap_used", + "upper_case_acronyms", + "use_debug", + "use_self", + "used_underscore_binding", + "useless_asref", + "useless_attribute", + "useless_conversion", + "useless_format", + "useless_let_if_seq", + "useless_transmute", + "useless_vec", + "vec_box", + "vec_init_then_push", + "vec_resize_to_zero", + "verbose_bit_mask", + "verbose_file_reads", + "vtable_address_comparisons", + "while_immutable_condition", + "while_let_loop", + "while_let_on_iterator", + "wildcard_dependencies", + "wildcard_enum_match_arm", + "wildcard_imports", + "wildcard_in_or_patterns", + "write_literal", + "write_with_newline", + "writeln_empty_string", + "wrong_self_convention", + "wrong_transmute", + "zero_divided_by_zero", + "zero_prefixed_literal", + "zero_ptr", + "zero_sized_map_values", + "zst_offset", + +} diff --git a/src/docs/absurd_extreme_comparisons.txt b/src/docs/absurd_extreme_comparisons.txt new file mode 100644 index 000000000000..590bee28aa23 --- /dev/null +++ b/src/docs/absurd_extreme_comparisons.txt @@ -0,0 +1,25 @@ +### What it does +Checks for comparisons where one side of the relation is +either the minimum or maximum value for its type and warns if it involves a +case that is always true or always false. Only integer and boolean types are +checked. + +### Why is this bad? +An expression like `min <= x` may misleadingly imply +that it is possible for `x` to be less than the minimum. Expressions like +`max < x` are probably mistakes. + +### Known problems +For `usize` the size of the current compile target will +be assumed (e.g., 64 bits on 64 bit systems). This means code that uses such +a comparison to detect target pointer width will trigger this lint. One can +use `mem::sizeof` and compare its value or conditional compilation +attributes +like `#[cfg(target_pointer_width = "64")] ..` instead. + +### Example +``` +let vec: Vec = Vec::new(); +if vec.len() <= 0 {} +if 100 > i32::MAX {} +``` \ No newline at end of file diff --git a/src/docs/alloc_instead_of_core.txt b/src/docs/alloc_instead_of_core.txt new file mode 100644 index 000000000000..488a36e9276c --- /dev/null +++ b/src/docs/alloc_instead_of_core.txt @@ -0,0 +1,18 @@ +### What it does + +Finds items imported through `alloc` when available through `core`. + +### Why is this bad? + +Crates which have `no_std` compatibility and may optionally require alloc may wish to ensure types are +imported from core to ensure disabling `alloc` does not cause the crate to fail to compile. This lint +is also useful for crates migrating to become `no_std` compatible. + +### Example +``` +use alloc::slice::from_ref; +``` +Use instead: +``` +use core::slice::from_ref; +``` \ No newline at end of file diff --git a/src/docs/allow_attributes_without_reason.txt b/src/docs/allow_attributes_without_reason.txt new file mode 100644 index 000000000000..fcc4f49b08b3 --- /dev/null +++ b/src/docs/allow_attributes_without_reason.txt @@ -0,0 +1,22 @@ +### What it does +Checks for attributes that allow lints without a reason. + +(This requires the `lint_reasons` feature) + +### Why is this bad? +Allowing a lint should always have a reason. This reason should be documented to +ensure that others understand the reasoning + +### Example +``` +#![feature(lint_reasons)] + +#![allow(clippy::some_lint)] +``` + +Use instead: +``` +#![feature(lint_reasons)] + +#![allow(clippy::some_lint, reason = "False positive rust-lang/rust-clippy#1002020")] +``` \ No newline at end of file diff --git a/src/docs/almost_complete_letter_range.txt b/src/docs/almost_complete_letter_range.txt new file mode 100644 index 000000000000..01cbaf9eae25 --- /dev/null +++ b/src/docs/almost_complete_letter_range.txt @@ -0,0 +1,15 @@ +### What it does +Checks for ranges which almost include the entire range of letters from 'a' to 'z', but +don't because they're a half open range. + +### Why is this bad? +This (`'a'..'z'`) is almost certainly a typo meant to include all letters. + +### Example +``` +let _ = 'a'..'z'; +``` +Use instead: +``` +let _ = 'a'..='z'; +``` \ No newline at end of file diff --git a/src/docs/almost_swapped.txt b/src/docs/almost_swapped.txt new file mode 100644 index 000000000000..cd10a8d5409b --- /dev/null +++ b/src/docs/almost_swapped.txt @@ -0,0 +1,15 @@ +### What it does +Checks for `foo = bar; bar = foo` sequences. + +### Why is this bad? +This looks like a failed attempt to swap. + +### Example +``` +a = b; +b = a; +``` +If swapping is intended, use `swap()` instead: +``` +std::mem::swap(&mut a, &mut b); +``` \ No newline at end of file diff --git a/src/docs/approx_constant.txt b/src/docs/approx_constant.txt new file mode 100644 index 000000000000..393fa4b5ef7e --- /dev/null +++ b/src/docs/approx_constant.txt @@ -0,0 +1,24 @@ +### What it does +Checks for floating point literals that approximate +constants which are defined in +[`std::f32::consts`](https://doc.rust-lang.org/stable/std/f32/consts/#constants) +or +[`std::f64::consts`](https://doc.rust-lang.org/stable/std/f64/consts/#constants), +respectively, suggesting to use the predefined constant. + +### Why is this bad? +Usually, the definition in the standard library is more +precise than what people come up with. If you find that your definition is +actually more precise, please [file a Rust +issue](https://github.com/rust-lang/rust/issues). + +### Example +``` +let x = 3.14; +let y = 1_f64 / x; +``` +Use instead: +``` +let x = std::f32::consts::PI; +let y = std::f64::consts::FRAC_1_PI; +``` \ No newline at end of file diff --git a/src/docs/arithmetic.txt b/src/docs/arithmetic.txt new file mode 100644 index 000000000000..0b3f07d95056 --- /dev/null +++ b/src/docs/arithmetic.txt @@ -0,0 +1,28 @@ +### What it does +Checks for any kind of arithmetic operation of any type. + +Operators like `+`, `-`, `*` or `<<` are usually capable of overflowing according to the [Rust +Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow), +or can panic (`/`, `%`). Known safe built-in types like `Wrapping` or `Saturing` are filtered +away. + +### Why is this bad? +Integer overflow will trigger a panic in debug builds or will wrap in +release mode. Division by zero will cause a panic in either mode. In some applications one +wants explicitly checked, wrapping or saturating arithmetic. + +#### Example +``` +a + 1; +``` + +Third-party types also tend to overflow. + +#### Example +``` +use rust_decimal::Decimal; +let _n = Decimal::MAX + Decimal::MAX; +``` + +### Allowed types +Custom allowed types can be specified through the "arithmetic-allowed" filter. \ No newline at end of file diff --git a/src/docs/as_conversions.txt b/src/docs/as_conversions.txt new file mode 100644 index 000000000000..4af479bd8111 --- /dev/null +++ b/src/docs/as_conversions.txt @@ -0,0 +1,32 @@ +### What it does +Checks for usage of `as` conversions. + +Note that this lint is specialized in linting *every single* use of `as` +regardless of whether good alternatives exist or not. +If you want more precise lints for `as`, please consider using these separate lints: +`unnecessary_cast`, `cast_lossless/cast_possible_truncation/cast_possible_wrap/cast_precision_loss/cast_sign_loss`, +`fn_to_numeric_cast(_with_truncation)`, `char_lit_as_u8`, `ref_to_mut` and `ptr_as_ptr`. +There is a good explanation the reason why this lint should work in this way and how it is useful +[in this issue](https://github.com/rust-lang/rust-clippy/issues/5122). + +### Why is this bad? +`as` conversions will perform many kinds of +conversions, including silently lossy conversions and dangerous coercions. +There are cases when it makes sense to use `as`, so the lint is +Allow by default. + +### Example +``` +let a: u32; +... +f(a as u16); +``` + +Use instead: +``` +f(a.try_into()?); + +// or + +f(a.try_into().expect("Unexpected u16 overflow in f")); +``` \ No newline at end of file diff --git a/src/docs/as_underscore.txt b/src/docs/as_underscore.txt new file mode 100644 index 000000000000..2d9b0c358936 --- /dev/null +++ b/src/docs/as_underscore.txt @@ -0,0 +1,21 @@ +### What it does +Check for the usage of `as _` conversion using inferred type. + +### Why is this bad? +The conversion might include lossy conversion and dangerous cast that might go +undetected due to the type being inferred. + +The lint is allowed by default as using `_` is less wordy than always specifying the type. + +### Example +``` +fn foo(n: usize) {} +let n: u16 = 256; +foo(n as _); +``` +Use instead: +``` +fn foo(n: usize) {} +let n: u16 = 256; +foo(n as usize); +``` \ No newline at end of file diff --git a/src/docs/assertions_on_constants.txt b/src/docs/assertions_on_constants.txt new file mode 100644 index 000000000000..270c1e3b639d --- /dev/null +++ b/src/docs/assertions_on_constants.txt @@ -0,0 +1,14 @@ +### What it does +Checks for `assert!(true)` and `assert!(false)` calls. + +### Why is this bad? +Will be optimized out by the compiler or should probably be replaced by a +`panic!()` or `unreachable!()` + +### Example +``` +assert!(false) +assert!(true) +const B: bool = false; +assert!(B) +``` \ No newline at end of file diff --git a/src/docs/assertions_on_result_states.txt b/src/docs/assertions_on_result_states.txt new file mode 100644 index 000000000000..0889084fd3ad --- /dev/null +++ b/src/docs/assertions_on_result_states.txt @@ -0,0 +1,14 @@ +### What it does +Checks for `assert!(r.is_ok())` or `assert!(r.is_err())` calls. + +### Why is this bad? +An assertion failure cannot output an useful message of the error. + +### Known problems +The suggested replacement decreases the readability of code and log output. + +### Example +``` +assert!(r.is_ok()); +assert!(r.is_err()); +``` \ No newline at end of file diff --git a/src/docs/assign_op_pattern.txt b/src/docs/assign_op_pattern.txt new file mode 100644 index 000000000000..f355c0cc18d3 --- /dev/null +++ b/src/docs/assign_op_pattern.txt @@ -0,0 +1,28 @@ +### What it does +Checks for `a = a op b` or `a = b commutative_op a` +patterns. + +### Why is this bad? +These can be written as the shorter `a op= b`. + +### Known problems +While forbidden by the spec, `OpAssign` traits may have +implementations that differ from the regular `Op` impl. + +### Example +``` +let mut a = 5; +let b = 0; +// ... + +a = a + b; +``` + +Use instead: +``` +let mut a = 5; +let b = 0; +// ... + +a += b; +``` \ No newline at end of file diff --git a/src/docs/async_yields_async.txt b/src/docs/async_yields_async.txt new file mode 100644 index 000000000000..a40de6d2e473 --- /dev/null +++ b/src/docs/async_yields_async.txt @@ -0,0 +1,28 @@ +### What it does +Checks for async blocks that yield values of types +that can themselves be awaited. + +### Why is this bad? +An await is likely missing. + +### Example +``` +async fn foo() {} + +fn bar() { + let x = async { + foo() + }; +} +``` + +Use instead: +``` +async fn foo() {} + +fn bar() { + let x = async { + foo().await + }; +} +``` \ No newline at end of file diff --git a/src/docs/await_holding_invalid_type.txt b/src/docs/await_holding_invalid_type.txt new file mode 100644 index 000000000000..e9c768772ff6 --- /dev/null +++ b/src/docs/await_holding_invalid_type.txt @@ -0,0 +1,29 @@ +### What it does +Allows users to configure types which should not be held across `await` +suspension points. + +### Why is this bad? +There are some types which are perfectly "safe" to be used concurrently +from a memory access perspective but will cause bugs at runtime if they +are held in such a way. + +### Example + +``` +await-holding-invalid-types = [ + # You can specify a type name + "CustomLockType", + # You can (optionally) specify a reason + { path = "OtherCustomLockType", reason = "Relies on a thread local" } +] +``` + +``` +struct CustomLockType; +struct OtherCustomLockType; +async fn foo() { + let _x = CustomLockType; + let _y = OtherCustomLockType; + baz().await; // Lint violation +} +``` \ No newline at end of file diff --git a/src/docs/await_holding_lock.txt b/src/docs/await_holding_lock.txt new file mode 100644 index 000000000000..0f450a11160c --- /dev/null +++ b/src/docs/await_holding_lock.txt @@ -0,0 +1,51 @@ +### What it does +Checks for calls to await while holding a non-async-aware MutexGuard. + +### Why is this bad? +The Mutex types found in std::sync and parking_lot +are not designed to operate in an async context across await points. + +There are two potential solutions. One is to use an async-aware Mutex +type. Many asynchronous foundation crates provide such a Mutex type. The +other solution is to ensure the mutex is unlocked before calling await, +either by introducing a scope or an explicit call to Drop::drop. + +### Known problems +Will report false positive for explicitly dropped guards +([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)). A workaround for this is +to wrap the `.lock()` call in a block instead of explicitly dropping the guard. + +### Example +``` +async fn foo(x: &Mutex) { + let mut guard = x.lock().unwrap(); + *guard += 1; + baz().await; +} + +async fn bar(x: &Mutex) { + let mut guard = x.lock().unwrap(); + *guard += 1; + drop(guard); // explicit drop + baz().await; +} +``` + +Use instead: +``` +async fn foo(x: &Mutex) { + { + let mut guard = x.lock().unwrap(); + *guard += 1; + } + baz().await; +} + +async fn bar(x: &Mutex) { + { + let mut guard = x.lock().unwrap(); + *guard += 1; + } // guard dropped here at end of scope + baz().await; +} +``` \ No newline at end of file diff --git a/src/docs/await_holding_refcell_ref.txt b/src/docs/await_holding_refcell_ref.txt new file mode 100644 index 000000000000..226a261b9cc5 --- /dev/null +++ b/src/docs/await_holding_refcell_ref.txt @@ -0,0 +1,47 @@ +### What it does +Checks for calls to await while holding a `RefCell` `Ref` or `RefMut`. + +### Why is this bad? +`RefCell` refs only check for exclusive mutable access +at runtime. Holding onto a `RefCell` ref across an `await` suspension point +risks panics from a mutable ref shared while other refs are outstanding. + +### Known problems +Will report false positive for explicitly dropped refs +([#6353](https://github.com/rust-lang/rust-clippy/issues/6353)). A workaround for this is +to wrap the `.borrow[_mut]()` call in a block instead of explicitly dropping the ref. + +### Example +``` +async fn foo(x: &RefCell) { + let mut y = x.borrow_mut(); + *y += 1; + baz().await; +} + +async fn bar(x: &RefCell) { + let mut y = x.borrow_mut(); + *y += 1; + drop(y); // explicit drop + baz().await; +} +``` + +Use instead: +``` +async fn foo(x: &RefCell) { + { + let mut y = x.borrow_mut(); + *y += 1; + } + baz().await; +} + +async fn bar(x: &RefCell) { + { + let mut y = x.borrow_mut(); + *y += 1; + } // y dropped here at end of scope + baz().await; +} +``` \ No newline at end of file diff --git a/src/docs/bad_bit_mask.txt b/src/docs/bad_bit_mask.txt new file mode 100644 index 000000000000..d40024ee5620 --- /dev/null +++ b/src/docs/bad_bit_mask.txt @@ -0,0 +1,30 @@ +### What it does +Checks for incompatible bit masks in comparisons. + +The formula for detecting if an expression of the type `_ m + c` (where `` is one of {`&`, `|`} and `` is one of +{`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following +table: + +|Comparison |Bit Op|Example |is always|Formula | +|------------|------|-------------|---------|----------------------| +|`==` or `!=`| `&` |`x & 2 == 3` |`false` |`c & m != c` | +|`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` | +|`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` | +|`==` or `!=`| `\|` |`x \| 1 == 0`|`false` |`c \| m != c` | +|`<` or `>=`| `\|` |`x \| 1 < 1` |`false` |`m >= c` | +|`<=` or `>` | `\|` |`x \| 1 > 0` |`true` |`m > c` | + +### Why is this bad? +If the bits that the comparison cares about are always +set to zero or one by the bit mask, the comparison is constant `true` or +`false` (depending on mask, compared value, and operators). + +So the code is actively misleading, and the only reason someone would write +this intentionally is to win an underhanded Rust contest or create a +test-case for this lint. + +### Example +``` +if (x & 1 == 2) { } +``` \ No newline at end of file diff --git a/src/docs/bind_instead_of_map.txt b/src/docs/bind_instead_of_map.txt new file mode 100644 index 000000000000..148575803d38 --- /dev/null +++ b/src/docs/bind_instead_of_map.txt @@ -0,0 +1,22 @@ +### What it does +Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))` or +`_.or_else(|x| Err(y))`. + +### Why is this bad? +Readability, this can be written more concisely as +`_.map(|x| y)` or `_.map_err(|x| y)`. + +### Example +``` +let _ = opt().and_then(|s| Some(s.len())); +let _ = res().and_then(|s| if s.len() == 42 { Ok(10) } else { Ok(20) }); +let _ = res().or_else(|s| if s.len() == 42 { Err(10) } else { Err(20) }); +``` + +The correct use would be: + +``` +let _ = opt().map(|s| s.len()); +let _ = res().map(|s| if s.len() == 42 { 10 } else { 20 }); +let _ = res().map_err(|s| if s.len() == 42 { 10 } else { 20 }); +``` \ No newline at end of file diff --git a/src/docs/blanket_clippy_restriction_lints.txt b/src/docs/blanket_clippy_restriction_lints.txt new file mode 100644 index 000000000000..28a4ebf7169b --- /dev/null +++ b/src/docs/blanket_clippy_restriction_lints.txt @@ -0,0 +1,16 @@ +### What it does +Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category. + +### Why is this bad? +Restriction lints sometimes are in contrast with other lints or even go against idiomatic rust. +These lints should only be enabled on a lint-by-lint basis and with careful consideration. + +### Example +``` +#![deny(clippy::restriction)] +``` + +Use instead: +``` +#![deny(clippy::as_conversions)] +``` \ No newline at end of file diff --git a/src/docs/blocks_in_if_conditions.txt b/src/docs/blocks_in_if_conditions.txt new file mode 100644 index 000000000000..3afa14853fd2 --- /dev/null +++ b/src/docs/blocks_in_if_conditions.txt @@ -0,0 +1,21 @@ +### What it does +Checks for `if` conditions that use blocks containing an +expression, statements or conditions that use closures with blocks. + +### Why is this bad? +Style, using blocks in the condition makes it hard to read. + +### Examples +``` +if { true } { /* ... */ } + +if { let x = somefunc(); x } { /* ... */ } +``` + +Use instead: +``` +if true { /* ... */ } + +let res = { let x = somefunc(); x }; +if res { /* ... */ } +``` \ No newline at end of file diff --git a/src/docs/bool_assert_comparison.txt b/src/docs/bool_assert_comparison.txt new file mode 100644 index 000000000000..df7ca00cc2ba --- /dev/null +++ b/src/docs/bool_assert_comparison.txt @@ -0,0 +1,16 @@ +### What it does +This lint warns about boolean comparisons in assert-like macros. + +### Why is this bad? +It is shorter to use the equivalent. + +### Example +``` +assert_eq!("a".is_empty(), false); +assert_ne!("a".is_empty(), true); +``` + +Use instead: +``` +assert!(!"a".is_empty()); +``` \ No newline at end of file diff --git a/src/docs/bool_comparison.txt b/src/docs/bool_comparison.txt new file mode 100644 index 000000000000..0996f60cec44 --- /dev/null +++ b/src/docs/bool_comparison.txt @@ -0,0 +1,18 @@ +### What it does +Checks for expressions of the form `x == true`, +`x != true` and order comparisons such as `x < true` (or vice versa) and +suggest using the variable directly. + +### Why is this bad? +Unnecessary code. + +### Example +``` +if x == true {} +if y == false {} +``` +use `x` directly: +``` +if x {} +if !y {} +``` \ No newline at end of file diff --git a/src/docs/bool_to_int_with_if.txt b/src/docs/bool_to_int_with_if.txt new file mode 100644 index 000000000000..63535b454c9f --- /dev/null +++ b/src/docs/bool_to_int_with_if.txt @@ -0,0 +1,26 @@ +### What it does +Instead of using an if statement to convert a bool to an int, +this lint suggests using a `from()` function or an `as` coercion. + +### Why is this bad? +Coercion or `from()` is idiomatic way to convert bool to a number. +Both methods are guaranteed to return 1 for true, and 0 for false. + +See https://doc.rust-lang.org/std/primitive.bool.html#impl-From%3Cbool%3E + +### Example +``` +if condition { + 1_i64 +} else { + 0 +}; +``` +Use instead: +``` +i64::from(condition); +``` +or +``` +condition as i64; +``` \ No newline at end of file diff --git a/src/docs/borrow_as_ptr.txt b/src/docs/borrow_as_ptr.txt new file mode 100644 index 000000000000..0be865abd578 --- /dev/null +++ b/src/docs/borrow_as_ptr.txt @@ -0,0 +1,26 @@ +### What it does +Checks for the usage of `&expr as *const T` or +`&mut expr as *mut T`, and suggest using `ptr::addr_of` or +`ptr::addr_of_mut` instead. + +### Why is this bad? +This would improve readability and avoid creating a reference +that points to an uninitialized value or unaligned place. +Read the `ptr::addr_of` docs for more information. + +### Example +``` +let val = 1; +let p = &val as *const i32; + +let mut val_mut = 1; +let p_mut = &mut val_mut as *mut i32; +``` +Use instead: +``` +let val = 1; +let p = std::ptr::addr_of!(val); + +let mut val_mut = 1; +let p_mut = std::ptr::addr_of_mut!(val_mut); +``` \ No newline at end of file diff --git a/src/docs/borrow_deref_ref.txt b/src/docs/borrow_deref_ref.txt new file mode 100644 index 000000000000..352480d3f26a --- /dev/null +++ b/src/docs/borrow_deref_ref.txt @@ -0,0 +1,27 @@ +### What it does +Checks for `&*(&T)`. + +### Why is this bad? +Dereferencing and then borrowing a reference value has no effect in most cases. + +### Known problems +False negative on such code: +``` +let x = &12; +let addr_x = &x as *const _ as usize; +let addr_y = &&*x as *const _ as usize; // assert ok now, and lint triggered. + // But if we fix it, assert will fail. +assert_ne!(addr_x, addr_y); +``` + +### Example +``` +let s = &String::new(); + +let a: &String = &* s; +``` + +Use instead: +``` +let a: &String = s; +``` \ No newline at end of file diff --git a/src/docs/borrow_interior_mutable_const.txt b/src/docs/borrow_interior_mutable_const.txt new file mode 100644 index 000000000000..e55b6a77e666 --- /dev/null +++ b/src/docs/borrow_interior_mutable_const.txt @@ -0,0 +1,40 @@ +### What it does +Checks if `const` items which is interior mutable (e.g., +contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.) has been borrowed directly. + +### Why is this bad? +Consts are copied everywhere they are referenced, i.e., +every time you refer to the const a fresh instance of the `Cell` or `Mutex` +or `AtomicXxxx` will be created, which defeats the whole purpose of using +these types in the first place. + +The `const` value should be stored inside a `static` item. + +### Known problems +When an enum has variants with interior mutability, use of its non +interior mutable variants can generate false positives. See issue +[#3962](https://github.com/rust-lang/rust-clippy/issues/3962) + +Types that have underlying or potential interior mutability trigger the lint whether +the interior mutable field is used or not. See issues +[#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and +[#3825](https://github.com/rust-lang/rust-clippy/issues/3825) + +### Example +``` +use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; +const CONST_ATOM: AtomicUsize = AtomicUsize::new(12); + +CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged +assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct +``` + +Use instead: +``` +use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; +const CONST_ATOM: AtomicUsize = AtomicUsize::new(12); + +static STATIC_ATOM: AtomicUsize = CONST_ATOM; +STATIC_ATOM.store(9, SeqCst); +assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance +``` \ No newline at end of file diff --git a/src/docs/borrowed_box.txt b/src/docs/borrowed_box.txt new file mode 100644 index 000000000000..d7089be662a5 --- /dev/null +++ b/src/docs/borrowed_box.txt @@ -0,0 +1,19 @@ +### What it does +Checks for use of `&Box` anywhere in the code. +Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information. + +### Why is this bad? +A `&Box` parameter requires the function caller to box `T` first before passing it to a function. +Using `&T` defines a concrete type for the parameter and generalizes the function, this would also +auto-deref to `&T` at the function call site if passed a `&Box`. + +### Example +``` +fn foo(bar: &Box) { ... } +``` + +Better: + +``` +fn foo(bar: &T) { ... } +``` \ No newline at end of file diff --git a/src/docs/box_collection.txt b/src/docs/box_collection.txt new file mode 100644 index 000000000000..053f24c46281 --- /dev/null +++ b/src/docs/box_collection.txt @@ -0,0 +1,23 @@ +### What it does +Checks for use of `Box` where T is a collection such as Vec anywhere in the code. +Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information. + +### Why is this bad? +Collections already keeps their contents in a separate area on +the heap. So if you `Box` them, you just add another level of indirection +without any benefit whatsoever. + +### Example +``` +struct X { + values: Box>, +} +``` + +Better: + +``` +struct X { + values: Vec, +} +``` \ No newline at end of file diff --git a/src/docs/boxed_local.txt b/src/docs/boxed_local.txt new file mode 100644 index 000000000000..8b1febf1455f --- /dev/null +++ b/src/docs/boxed_local.txt @@ -0,0 +1,18 @@ +### What it does +Checks for usage of `Box` where an unboxed `T` would +work fine. + +### Why is this bad? +This is an unnecessary allocation, and bad for +performance. It is only necessary to allocate if you wish to move the box +into something. + +### Example +``` +fn foo(x: Box) {} +``` + +Use instead: +``` +fn foo(x: u32) {} +``` \ No newline at end of file diff --git a/src/docs/branches_sharing_code.txt b/src/docs/branches_sharing_code.txt new file mode 100644 index 000000000000..79be6124798a --- /dev/null +++ b/src/docs/branches_sharing_code.txt @@ -0,0 +1,32 @@ +### What it does +Checks if the `if` and `else` block contain shared code that can be +moved out of the blocks. + +### Why is this bad? +Duplicate code is less maintainable. + +### Known problems +* The lint doesn't check if the moved expressions modify values that are being used in + the if condition. The suggestion can in that case modify the behavior of the program. + See [rust-clippy#7452](https://github.com/rust-lang/rust-clippy/issues/7452) + +### Example +``` +let foo = if … { + println!("Hello World"); + 13 +} else { + println!("Hello World"); + 42 +}; +``` + +Use instead: +``` +println!("Hello World"); +let foo = if … { + 13 +} else { + 42 +}; +``` \ No newline at end of file diff --git a/src/docs/builtin_type_shadow.txt b/src/docs/builtin_type_shadow.txt new file mode 100644 index 000000000000..15b1c9df7baa --- /dev/null +++ b/src/docs/builtin_type_shadow.txt @@ -0,0 +1,15 @@ +### What it does +Warns if a generic shadows a built-in type. + +### Why is this bad? +This gives surprising type errors. + +### Example + +``` +impl Foo { + fn impl_func(&self) -> u32 { + 42 + } +} +``` \ No newline at end of file diff --git a/src/docs/bytes_count_to_len.txt b/src/docs/bytes_count_to_len.txt new file mode 100644 index 000000000000..ca7bf9a38da8 --- /dev/null +++ b/src/docs/bytes_count_to_len.txt @@ -0,0 +1,18 @@ +### What it does +It checks for `str::bytes().count()` and suggests replacing it with +`str::len()`. + +### Why is this bad? +`str::bytes().count()` is longer and may not be as performant as using +`str::len()`. + +### Example +``` +"hello".bytes().count(); +String::from("hello").bytes().count(); +``` +Use instead: +``` +"hello".len(); +String::from("hello").len(); +``` \ No newline at end of file diff --git a/src/docs/bytes_nth.txt b/src/docs/bytes_nth.txt new file mode 100644 index 000000000000..260de343353d --- /dev/null +++ b/src/docs/bytes_nth.txt @@ -0,0 +1,16 @@ +### What it does +Checks for the use of `.bytes().nth()`. + +### Why is this bad? +`.as_bytes().get()` is more efficient and more +readable. + +### Example +``` +"Hello".bytes().nth(3); +``` + +Use instead: +``` +"Hello".as_bytes().get(3); +``` \ No newline at end of file diff --git a/src/docs/cargo_common_metadata.txt b/src/docs/cargo_common_metadata.txt new file mode 100644 index 000000000000..1998647a9274 --- /dev/null +++ b/src/docs/cargo_common_metadata.txt @@ -0,0 +1,33 @@ +### What it does +Checks to see if all common metadata is defined in +`Cargo.toml`. See: https://rust-lang-nursery.github.io/api-guidelines/documentation.html#cargotoml-includes-all-common-metadata-c-metadata + +### Why is this bad? +It will be more difficult for users to discover the +purpose of the crate, and key information related to it. + +### Example +``` +[package] +name = "clippy" +version = "0.0.212" +repository = "https://github.com/rust-lang/rust-clippy" +readme = "README.md" +license = "MIT OR Apache-2.0" +keywords = ["clippy", "lint", "plugin"] +categories = ["development-tools", "development-tools::cargo-plugins"] +``` + +Should include a description field like: + +``` +[package] +name = "clippy" +version = "0.0.212" +description = "A bunch of helpful lints to avoid common pitfalls in Rust" +repository = "https://github.com/rust-lang/rust-clippy" +readme = "README.md" +license = "MIT OR Apache-2.0" +keywords = ["clippy", "lint", "plugin"] +categories = ["development-tools", "development-tools::cargo-plugins"] +``` \ No newline at end of file diff --git a/src/docs/case_sensitive_file_extension_comparisons.txt b/src/docs/case_sensitive_file_extension_comparisons.txt new file mode 100644 index 000000000000..8e6e18ed4e23 --- /dev/null +++ b/src/docs/case_sensitive_file_extension_comparisons.txt @@ -0,0 +1,21 @@ +### What it does +Checks for calls to `ends_with` with possible file extensions +and suggests to use a case-insensitive approach instead. + +### Why is this bad? +`ends_with` is case-sensitive and may not detect files with a valid extension. + +### Example +``` +fn is_rust_file(filename: &str) -> bool { + filename.ends_with(".rs") +} +``` +Use instead: +``` +fn is_rust_file(filename: &str) -> bool { + let filename = std::path::Path::new(filename); + filename.extension() + .map_or(false, |ext| ext.eq_ignore_ascii_case("rs")) +} +``` \ No newline at end of file diff --git a/src/docs/cast_abs_to_unsigned.txt b/src/docs/cast_abs_to_unsigned.txt new file mode 100644 index 000000000000..c5d8ee034ce5 --- /dev/null +++ b/src/docs/cast_abs_to_unsigned.txt @@ -0,0 +1,16 @@ +### What it does +Checks for uses of the `abs()` method that cast the result to unsigned. + +### Why is this bad? +The `unsigned_abs()` method avoids panic when called on the MIN value. + +### Example +``` +let x: i32 = -42; +let y: u32 = x.abs() as u32; +``` +Use instead: +``` +let x: i32 = -42; +let y: u32 = x.unsigned_abs(); +``` \ No newline at end of file diff --git a/src/docs/cast_enum_constructor.txt b/src/docs/cast_enum_constructor.txt new file mode 100644 index 000000000000..675c03a42bc2 --- /dev/null +++ b/src/docs/cast_enum_constructor.txt @@ -0,0 +1,11 @@ +### What it does +Checks for casts from an enum tuple constructor to an integer. + +### Why is this bad? +The cast is easily confused with casting a c-like enum value to an integer. + +### Example +``` +enum E { X(i32) }; +let _ = E::X as usize; +``` \ No newline at end of file diff --git a/src/docs/cast_enum_truncation.txt b/src/docs/cast_enum_truncation.txt new file mode 100644 index 000000000000..abe32a8296da --- /dev/null +++ b/src/docs/cast_enum_truncation.txt @@ -0,0 +1,12 @@ +### What it does +Checks for casts from an enum type to an integral type which will definitely truncate the +value. + +### Why is this bad? +The resulting integral value will not match the value of the variant it came from. + +### Example +``` +enum E { X = 256 }; +let _ = E::X as u8; +``` \ No newline at end of file diff --git a/src/docs/cast_lossless.txt b/src/docs/cast_lossless.txt new file mode 100644 index 000000000000..c3a61dd470fc --- /dev/null +++ b/src/docs/cast_lossless.txt @@ -0,0 +1,26 @@ +### What it does +Checks for casts between numerical types that may +be replaced by safe conversion functions. + +### Why is this bad? +Rust's `as` keyword will perform many kinds of +conversions, including silently lossy conversions. Conversion functions such +as `i32::from` will only perform lossless conversions. Using the conversion +functions prevents conversions from turning into silent lossy conversions if +the types of the input expressions ever change, and make it easier for +people reading the code to know that the conversion is lossless. + +### Example +``` +fn as_u64(x: u8) -> u64 { + x as u64 +} +``` + +Using `::from` would look like this: + +``` +fn as_u64(x: u8) -> u64 { + u64::from(x) +} +``` \ No newline at end of file diff --git a/src/docs/cast_possible_truncation.txt b/src/docs/cast_possible_truncation.txt new file mode 100644 index 000000000000..0b164848cc7c --- /dev/null +++ b/src/docs/cast_possible_truncation.txt @@ -0,0 +1,16 @@ +### What it does +Checks for casts between numerical types that may +truncate large values. This is expected behavior, so the cast is `Allow` by +default. + +### Why is this bad? +In some problem domains, it is good practice to avoid +truncation. This lint can be activated to help assess where additional +checks could be beneficial. + +### Example +``` +fn as_u8(x: u64) -> u8 { + x as u8 +} +``` \ No newline at end of file diff --git a/src/docs/cast_possible_wrap.txt b/src/docs/cast_possible_wrap.txt new file mode 100644 index 000000000000..f883fc9cfb99 --- /dev/null +++ b/src/docs/cast_possible_wrap.txt @@ -0,0 +1,17 @@ +### What it does +Checks for casts from an unsigned type to a signed type of +the same size. Performing such a cast is a 'no-op' for the compiler, +i.e., nothing is changed at the bit level, and the binary representation of +the value is reinterpreted. This can cause wrapping if the value is too big +for the target signed type. However, the cast works as defined, so this lint +is `Allow` by default. + +### Why is this bad? +While such a cast is not bad in itself, the results can +be surprising when this is not the intended behavior, as demonstrated by the +example below. + +### Example +``` +u32::MAX as i32; // will yield a value of `-1` +``` \ No newline at end of file diff --git a/src/docs/cast_precision_loss.txt b/src/docs/cast_precision_loss.txt new file mode 100644 index 000000000000..f915d9f8a6d0 --- /dev/null +++ b/src/docs/cast_precision_loss.txt @@ -0,0 +1,19 @@ +### What it does +Checks for casts from any numerical to a float type where +the receiving type cannot store all values from the original type without +rounding errors. This possible rounding is to be expected, so this lint is +`Allow` by default. + +Basically, this warns on casting any integer with 32 or more bits to `f32` +or any 64-bit integer to `f64`. + +### Why is this bad? +It's not bad at all. But in some applications it can be +helpful to know where precision loss can take place. This lint can help find +those places in the code. + +### Example +``` +let x = u64::MAX; +x as f64; +``` \ No newline at end of file diff --git a/src/docs/cast_ptr_alignment.txt b/src/docs/cast_ptr_alignment.txt new file mode 100644 index 000000000000..6a6d4dcaa2ae --- /dev/null +++ b/src/docs/cast_ptr_alignment.txt @@ -0,0 +1,21 @@ +### What it does +Checks for casts, using `as` or `pointer::cast`, +from a less-strictly-aligned pointer to a more-strictly-aligned pointer + +### Why is this bad? +Dereferencing the resulting pointer may be undefined +behavior. + +### Known problems +Using `std::ptr::read_unaligned` and `std::ptr::write_unaligned` or similar +on the resulting pointer is fine. Is over-zealous: Casts with manual alignment checks or casts like +u64-> u8 -> u16 can be fine. Miri is able to do a more in-depth analysis. + +### Example +``` +let _ = (&1u8 as *const u8) as *const u16; +let _ = (&mut 1u8 as *mut u8) as *mut u16; + +(&1u8 as *const u8).cast::(); +(&mut 1u8 as *mut u8).cast::(); +``` \ No newline at end of file diff --git a/src/docs/cast_ref_to_mut.txt b/src/docs/cast_ref_to_mut.txt new file mode 100644 index 000000000000..fb5b4dbb62d8 --- /dev/null +++ b/src/docs/cast_ref_to_mut.txt @@ -0,0 +1,28 @@ +### What it does +Checks for casts of `&T` to `&mut T` anywhere in the code. + +### Why is this bad? +It’s basically guaranteed to be undefined behavior. +`UnsafeCell` is the only way to obtain aliasable data that is considered +mutable. + +### Example +``` +fn x(r: &i32) { + unsafe { + *(r as *const _ as *mut _) += 1; + } +} +``` + +Instead consider using interior mutability types. + +``` +use std::cell::UnsafeCell; + +fn x(r: &UnsafeCell) { + unsafe { + *r.get() += 1; + } +} +``` \ No newline at end of file diff --git a/src/docs/cast_sign_loss.txt b/src/docs/cast_sign_loss.txt new file mode 100644 index 000000000000..d64fe1b07f46 --- /dev/null +++ b/src/docs/cast_sign_loss.txt @@ -0,0 +1,15 @@ +### What it does +Checks for casts from a signed to an unsigned numerical +type. In this case, negative values wrap around to large positive values, +which can be quite surprising in practice. However, as the cast works as +defined, this lint is `Allow` by default. + +### Why is this bad? +Possibly surprising results. You can activate this lint +as a one-time check to see where numerical wrapping can arise. + +### Example +``` +let y: i8 = -1; +y as u128; // will return 18446744073709551615 +``` \ No newline at end of file diff --git a/src/docs/cast_slice_different_sizes.txt b/src/docs/cast_slice_different_sizes.txt new file mode 100644 index 000000000000..c01ef0ba92c0 --- /dev/null +++ b/src/docs/cast_slice_different_sizes.txt @@ -0,0 +1,38 @@ +### What it does +Checks for `as` casts between raw pointers to slices with differently sized elements. + +### Why is this bad? +The produced raw pointer to a slice does not update its length metadata. The produced +pointer will point to a different number of bytes than the original pointer because the +length metadata of a raw slice pointer is in elements rather than bytes. +Producing a slice reference from the raw pointer will either create a slice with +less data (which can be surprising) or create a slice with more data and cause Undefined Behavior. + +### Example +// Missing data +``` +let a = [1_i32, 2, 3, 4]; +let p = &a as *const [i32] as *const [u8]; +unsafe { + println!("{:?}", &*p); +} +``` +// Undefined Behavior (note: also potential alignment issues) +``` +let a = [1_u8, 2, 3, 4]; +let p = &a as *const [u8] as *const [u32]; +unsafe { + println!("{:?}", &*p); +} +``` +Instead use `ptr::slice_from_raw_parts` to construct a slice from a data pointer and the correct length +``` +let a = [1_i32, 2, 3, 4]; +let old_ptr = &a as *const [i32]; +// The data pointer is cast to a pointer to the target `u8` not `[u8]` +// The length comes from the known length of 4 i32s times the 4 bytes per i32 +let new_ptr = core::ptr::slice_from_raw_parts(old_ptr as *const u8, 16); +unsafe { + println!("{:?}", &*new_ptr); +} +``` \ No newline at end of file diff --git a/src/docs/cast_slice_from_raw_parts.txt b/src/docs/cast_slice_from_raw_parts.txt new file mode 100644 index 000000000000..b58c739766aa --- /dev/null +++ b/src/docs/cast_slice_from_raw_parts.txt @@ -0,0 +1,20 @@ +### What it does +Checks for a raw slice being cast to a slice pointer + +### Why is this bad? +This can result in multiple `&mut` references to the same location when only a pointer is +required. +`ptr::slice_from_raw_parts` is a safe alternative that doesn't require +the same [safety requirements] to be upheld. + +### Example +``` +let _: *const [u8] = std::slice::from_raw_parts(ptr, len) as *const _; +let _: *mut [u8] = std::slice::from_raw_parts_mut(ptr, len) as *mut _; +``` +Use instead: +``` +let _: *const [u8] = std::ptr::slice_from_raw_parts(ptr, len); +let _: *mut [u8] = std::ptr::slice_from_raw_parts_mut(ptr, len); +``` +[safety requirements]: https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html#safety \ No newline at end of file diff --git a/src/docs/char_lit_as_u8.txt b/src/docs/char_lit_as_u8.txt new file mode 100644 index 000000000000..00d60b9a451b --- /dev/null +++ b/src/docs/char_lit_as_u8.txt @@ -0,0 +1,21 @@ +### What it does +Checks for expressions where a character literal is cast +to `u8` and suggests using a byte literal instead. + +### Why is this bad? +In general, casting values to smaller types is +error-prone and should be avoided where possible. In the particular case of +converting a character literal to u8, it is easy to avoid by just using a +byte literal instead. As an added bonus, `b'a'` is even slightly shorter +than `'a' as u8`. + +### Example +``` +'x' as u8 +``` + +A better version, using the byte literal: + +``` +b'x' +``` \ No newline at end of file diff --git a/src/docs/chars_last_cmp.txt b/src/docs/chars_last_cmp.txt new file mode 100644 index 000000000000..4c1d8838973a --- /dev/null +++ b/src/docs/chars_last_cmp.txt @@ -0,0 +1,17 @@ +### What it does +Checks for usage of `_.chars().last()` or +`_.chars().next_back()` on a `str` to check if it ends with a given char. + +### Why is this bad? +Readability, this can be written more concisely as +`_.ends_with(_)`. + +### Example +``` +name.chars().last() == Some('_') || name.chars().next_back() == Some('-'); +``` + +Use instead: +``` +name.ends_with('_') || name.ends_with('-'); +``` \ No newline at end of file diff --git a/src/docs/chars_next_cmp.txt b/src/docs/chars_next_cmp.txt new file mode 100644 index 000000000000..77cbce2de00f --- /dev/null +++ b/src/docs/chars_next_cmp.txt @@ -0,0 +1,19 @@ +### What it does +Checks for usage of `.chars().next()` on a `str` to check +if it starts with a given char. + +### Why is this bad? +Readability, this can be written more concisely as +`_.starts_with(_)`. + +### Example +``` +let name = "foo"; +if name.chars().next() == Some('_') {}; +``` + +Use instead: +``` +let name = "foo"; +if name.starts_with('_') {}; +``` \ No newline at end of file diff --git a/src/docs/checked_conversions.txt b/src/docs/checked_conversions.txt new file mode 100644 index 000000000000..536b01294ee1 --- /dev/null +++ b/src/docs/checked_conversions.txt @@ -0,0 +1,15 @@ +### What it does +Checks for explicit bounds checking when casting. + +### Why is this bad? +Reduces the readability of statements & is error prone. + +### Example +``` +foo <= i32::MAX as u32; +``` + +Use instead: +``` +i32::try_from(foo).is_ok(); +``` \ No newline at end of file diff --git a/src/docs/clone_double_ref.txt b/src/docs/clone_double_ref.txt new file mode 100644 index 000000000000..2729635bd246 --- /dev/null +++ b/src/docs/clone_double_ref.txt @@ -0,0 +1,16 @@ +### What it does +Checks for usage of `.clone()` on an `&&T`. + +### Why is this bad? +Cloning an `&&T` copies the inner `&T`, instead of +cloning the underlying `T`. + +### Example +``` +fn main() { + let x = vec![1]; + let y = &&x; + let z = y.clone(); + println!("{:p} {:p}", *y, z); // prints out the same pointer +} +``` \ No newline at end of file diff --git a/src/docs/clone_on_copy.txt b/src/docs/clone_on_copy.txt new file mode 100644 index 000000000000..99a0bdb4c4ac --- /dev/null +++ b/src/docs/clone_on_copy.txt @@ -0,0 +1,11 @@ +### What it does +Checks for usage of `.clone()` on a `Copy` type. + +### Why is this bad? +The only reason `Copy` types implement `Clone` is for +generics, not for using the `clone` method on a concrete type. + +### Example +``` +42u64.clone(); +``` \ No newline at end of file diff --git a/src/docs/clone_on_ref_ptr.txt b/src/docs/clone_on_ref_ptr.txt new file mode 100644 index 000000000000..2d83f8fefc12 --- /dev/null +++ b/src/docs/clone_on_ref_ptr.txt @@ -0,0 +1,21 @@ +### What it does +Checks for usage of `.clone()` on a ref-counted pointer, +(`Rc`, `Arc`, `rc::Weak`, or `sync::Weak`), and suggests calling Clone via unified +function syntax instead (e.g., `Rc::clone(foo)`). + +### Why is this bad? +Calling '.clone()' on an Rc, Arc, or Weak +can obscure the fact that only the pointer is being cloned, not the underlying +data. + +### Example +``` +let x = Rc::new(1); + +x.clone(); +``` + +Use instead: +``` +Rc::clone(&x); +``` \ No newline at end of file diff --git a/src/docs/cloned_instead_of_copied.txt b/src/docs/cloned_instead_of_copied.txt new file mode 100644 index 000000000000..2f2014d5fd29 --- /dev/null +++ b/src/docs/cloned_instead_of_copied.txt @@ -0,0 +1,16 @@ +### What it does +Checks for usages of `cloned()` on an `Iterator` or `Option` where +`copied()` could be used instead. + +### Why is this bad? +`copied()` is better because it guarantees that the type being cloned +implements `Copy`. + +### Example +``` +[1, 2, 3].iter().cloned(); +``` +Use instead: +``` +[1, 2, 3].iter().copied(); +``` \ No newline at end of file diff --git a/src/docs/cmp_nan.txt b/src/docs/cmp_nan.txt new file mode 100644 index 000000000000..e2ad04d93235 --- /dev/null +++ b/src/docs/cmp_nan.txt @@ -0,0 +1,16 @@ +### What it does +Checks for comparisons to NaN. + +### Why is this bad? +NaN does not compare meaningfully to anything – not +even itself – so those comparisons are simply wrong. + +### Example +``` +if x == f32::NAN { } +``` + +Use instead: +``` +if x.is_nan() { } +``` \ No newline at end of file diff --git a/src/docs/cmp_null.txt b/src/docs/cmp_null.txt new file mode 100644 index 000000000000..02fd15124f03 --- /dev/null +++ b/src/docs/cmp_null.txt @@ -0,0 +1,23 @@ +### What it does +This lint checks for equality comparisons with `ptr::null` + +### Why is this bad? +It's easier and more readable to use the inherent +`.is_null()` +method instead + +### Example +``` +use std::ptr; + +if x == ptr::null { + // .. +} +``` + +Use instead: +``` +if x.is_null() { + // .. +} +``` \ No newline at end of file diff --git a/src/docs/cmp_owned.txt b/src/docs/cmp_owned.txt new file mode 100644 index 000000000000..f8d4956ff1d4 --- /dev/null +++ b/src/docs/cmp_owned.txt @@ -0,0 +1,18 @@ +### What it does +Checks for conversions to owned values just for the sake +of a comparison. + +### Why is this bad? +The comparison can operate on a reference, so creating +an owned value effectively throws it away directly afterwards, which is +needlessly consuming code and heap space. + +### Example +``` +if x.to_owned() == y {} +``` + +Use instead: +``` +if x == y {} +``` \ No newline at end of file diff --git a/src/docs/cognitive_complexity.txt b/src/docs/cognitive_complexity.txt new file mode 100644 index 000000000000..fdd75f6479cd --- /dev/null +++ b/src/docs/cognitive_complexity.txt @@ -0,0 +1,13 @@ +### What it does +Checks for methods with high cognitive complexity. + +### Why is this bad? +Methods of high cognitive complexity tend to be hard to +both read and maintain. Also LLVM will tend to optimize small methods better. + +### Known problems +Sometimes it's hard to find a way to reduce the +complexity. + +### Example +You'll see it when you get the warning. \ No newline at end of file diff --git a/src/docs/collapsible_else_if.txt b/src/docs/collapsible_else_if.txt new file mode 100644 index 000000000000..4ddfca17731f --- /dev/null +++ b/src/docs/collapsible_else_if.txt @@ -0,0 +1,29 @@ +### What it does +Checks for collapsible `else { if ... }` expressions +that can be collapsed to `else if ...`. + +### Why is this bad? +Each `if`-statement adds one level of nesting, which +makes code look more complex than it really is. + +### Example +``` + +if x { + … +} else { + if y { + … + } +} +``` + +Should be written: + +``` +if x { + … +} else if y { + … +} +``` \ No newline at end of file diff --git a/src/docs/collapsible_if.txt b/src/docs/collapsible_if.txt new file mode 100644 index 000000000000..e1264ee062e9 --- /dev/null +++ b/src/docs/collapsible_if.txt @@ -0,0 +1,23 @@ +### What it does +Checks for nested `if` statements which can be collapsed +by `&&`-combining their conditions. + +### Why is this bad? +Each `if`-statement adds one level of nesting, which +makes code look more complex than it really is. + +### Example +``` +if x { + if y { + // … + } +} +``` + +Use instead: +``` +if x && y { + // … +} +``` \ No newline at end of file diff --git a/src/docs/collapsible_match.txt b/src/docs/collapsible_match.txt new file mode 100644 index 000000000000..0d59594a03a2 --- /dev/null +++ b/src/docs/collapsible_match.txt @@ -0,0 +1,31 @@ +### What it does +Finds nested `match` or `if let` expressions where the patterns may be "collapsed" together +without adding any branches. + +Note that this lint is not intended to find _all_ cases where nested match patterns can be merged, but only +cases where merging would most likely make the code more readable. + +### Why is this bad? +It is unnecessarily verbose and complex. + +### Example +``` +fn func(opt: Option>) { + let n = match opt { + Some(n) => match n { + Ok(n) => n, + _ => return, + } + None => return, + }; +} +``` +Use instead: +``` +fn func(opt: Option>) { + let n = match opt { + Some(Ok(n)) => n, + _ => return, + }; +} +``` \ No newline at end of file diff --git a/src/docs/collapsible_str_replace.txt b/src/docs/collapsible_str_replace.txt new file mode 100644 index 000000000000..c24c25a3028a --- /dev/null +++ b/src/docs/collapsible_str_replace.txt @@ -0,0 +1,19 @@ +### What it does +Checks for consecutive calls to `str::replace` (2 or more) +that can be collapsed into a single call. + +### Why is this bad? +Consecutive `str::replace` calls scan the string multiple times +with repetitive code. + +### Example +``` +let hello = "hesuo worpd" + .replace('s', "l") + .replace("u", "l") + .replace('p', "l"); +``` +Use instead: +``` +let hello = "hesuo worpd".replace(&['s', 'u', 'p'], "l"); +``` \ No newline at end of file diff --git a/src/docs/comparison_chain.txt b/src/docs/comparison_chain.txt new file mode 100644 index 000000000000..43b09f31ff4a --- /dev/null +++ b/src/docs/comparison_chain.txt @@ -0,0 +1,36 @@ +### What it does +Checks comparison chains written with `if` that can be +rewritten with `match` and `cmp`. + +### Why is this bad? +`if` is not guaranteed to be exhaustive and conditionals can get +repetitive + +### Known problems +The match statement may be slower due to the compiler +not inlining the call to cmp. See issue [#5354](https://github.com/rust-lang/rust-clippy/issues/5354) + +### Example +``` +fn f(x: u8, y: u8) { + if x > y { + a() + } else if x < y { + b() + } else { + c() + } +} +``` + +Use instead: +``` +use std::cmp::Ordering; +fn f(x: u8, y: u8) { + match x.cmp(&y) { + Ordering::Greater => a(), + Ordering::Less => b(), + Ordering::Equal => c() + } +} +``` \ No newline at end of file diff --git a/src/docs/comparison_to_empty.txt b/src/docs/comparison_to_empty.txt new file mode 100644 index 000000000000..db6f74fe2706 --- /dev/null +++ b/src/docs/comparison_to_empty.txt @@ -0,0 +1,31 @@ +### What it does +Checks for comparing to an empty slice such as `""` or `[]`, +and suggests using `.is_empty()` where applicable. + +### Why is this bad? +Some structures can answer `.is_empty()` much faster +than checking for equality. So it is good to get into the habit of using +`.is_empty()`, and having it is cheap. +Besides, it makes the intent clearer than a manual comparison in some contexts. + +### Example + +``` +if s == "" { + .. +} + +if arr == [] { + .. +} +``` +Use instead: +``` +if s.is_empty() { + .. +} + +if arr.is_empty() { + .. +} +``` \ No newline at end of file diff --git a/src/docs/copy_iterator.txt b/src/docs/copy_iterator.txt new file mode 100644 index 000000000000..5f9a2a015b86 --- /dev/null +++ b/src/docs/copy_iterator.txt @@ -0,0 +1,20 @@ +### What it does +Checks for types that implement `Copy` as well as +`Iterator`. + +### Why is this bad? +Implicit copies can be confusing when working with +iterator combinators. + +### Example +``` +#[derive(Copy, Clone)] +struct Countdown(u8); + +impl Iterator for Countdown { + // ... +} + +let a: Vec<_> = my_iterator.take(1).collect(); +let b: Vec<_> = my_iterator.collect(); +``` \ No newline at end of file diff --git a/src/docs/crate_in_macro_def.txt b/src/docs/crate_in_macro_def.txt new file mode 100644 index 000000000000..047e986dee71 --- /dev/null +++ b/src/docs/crate_in_macro_def.txt @@ -0,0 +1,35 @@ +### What it does +Checks for use of `crate` as opposed to `$crate` in a macro definition. + +### Why is this bad? +`crate` refers to the macro call's crate, whereas `$crate` refers to the macro definition's +crate. Rarely is the former intended. See: +https://doc.rust-lang.org/reference/macros-by-example.html#hygiene + +### Example +``` +#[macro_export] +macro_rules! print_message { + () => { + println!("{}", crate::MESSAGE); + }; +} +pub const MESSAGE: &str = "Hello!"; +``` +Use instead: +``` +#[macro_export] +macro_rules! print_message { + () => { + println!("{}", $crate::MESSAGE); + }; +} +pub const MESSAGE: &str = "Hello!"; +``` + +Note that if the use of `crate` is intentional, an `allow` attribute can be applied to the +macro definition, e.g.: +``` +#[allow(clippy::crate_in_macro_def)] +macro_rules! ok { ... crate::foo ... } +``` \ No newline at end of file diff --git a/src/docs/create_dir.txt b/src/docs/create_dir.txt new file mode 100644 index 000000000000..e4e7937684e6 --- /dev/null +++ b/src/docs/create_dir.txt @@ -0,0 +1,15 @@ +### What it does +Checks usage of `std::fs::create_dir` and suggest using `std::fs::create_dir_all` instead. + +### Why is this bad? +Sometimes `std::fs::create_dir` is mistakenly chosen over `std::fs::create_dir_all`. + +### Example +``` +std::fs::create_dir("foo"); +``` + +Use instead: +``` +std::fs::create_dir_all("foo"); +``` \ No newline at end of file diff --git a/src/docs/crosspointer_transmute.txt b/src/docs/crosspointer_transmute.txt new file mode 100644 index 000000000000..49dea154970e --- /dev/null +++ b/src/docs/crosspointer_transmute.txt @@ -0,0 +1,12 @@ +### What it does +Checks for transmutes between a type `T` and `*T`. + +### Why is this bad? +It's easy to mistakenly transmute between a type and a +pointer to that type. + +### Example +``` +core::intrinsics::transmute(t) // where the result type is the same as + // `*t` or `&t`'s +``` \ No newline at end of file diff --git a/src/docs/dbg_macro.txt b/src/docs/dbg_macro.txt new file mode 100644 index 000000000000..3e1a9a043f9f --- /dev/null +++ b/src/docs/dbg_macro.txt @@ -0,0 +1,16 @@ +### What it does +Checks for usage of dbg!() macro. + +### Why is this bad? +`dbg!` macro is intended as a debugging tool. It +should not be in version control. + +### Example +``` +dbg!(true) +``` + +Use instead: +``` +true +``` \ No newline at end of file diff --git a/src/docs/debug_assert_with_mut_call.txt b/src/docs/debug_assert_with_mut_call.txt new file mode 100644 index 000000000000..2c44abe1f05c --- /dev/null +++ b/src/docs/debug_assert_with_mut_call.txt @@ -0,0 +1,18 @@ +### What it does +Checks for function/method calls with a mutable +parameter in `debug_assert!`, `debug_assert_eq!` and `debug_assert_ne!` macros. + +### Why is this bad? +In release builds `debug_assert!` macros are optimized out by the +compiler. +Therefore mutating something in a `debug_assert!` macro results in different behavior +between a release and debug build. + +### Example +``` +debug_assert_eq!(vec![3].pop(), Some(3)); + +// or + +debug_assert!(takes_a_mut_parameter(&mut x)); +``` \ No newline at end of file diff --git a/src/docs/decimal_literal_representation.txt b/src/docs/decimal_literal_representation.txt new file mode 100644 index 000000000000..daca9bbb3a84 --- /dev/null +++ b/src/docs/decimal_literal_representation.txt @@ -0,0 +1,13 @@ +### What it does +Warns if there is a better representation for a numeric literal. + +### Why is this bad? +Especially for big powers of 2 a hexadecimal representation is more +readable than a decimal representation. + +### Example +``` +`255` => `0xFF` +`65_535` => `0xFFFF` +`4_042_322_160` => `0xF0F0_F0F0` +``` \ No newline at end of file diff --git a/src/docs/declare_interior_mutable_const.txt b/src/docs/declare_interior_mutable_const.txt new file mode 100644 index 000000000000..2801b5ccff80 --- /dev/null +++ b/src/docs/declare_interior_mutable_const.txt @@ -0,0 +1,46 @@ +### What it does +Checks for declaration of `const` items which is interior +mutable (e.g., contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.). + +### Why is this bad? +Consts are copied everywhere they are referenced, i.e., +every time you refer to the const a fresh instance of the `Cell` or `Mutex` +or `AtomicXxxx` will be created, which defeats the whole purpose of using +these types in the first place. + +The `const` should better be replaced by a `static` item if a global +variable is wanted, or replaced by a `const fn` if a constructor is wanted. + +### Known problems +A "non-constant" const item is a legacy way to supply an +initialized value to downstream `static` items (e.g., the +`std::sync::ONCE_INIT` constant). In this case the use of `const` is legit, +and this lint should be suppressed. + +Even though the lint avoids triggering on a constant whose type has enums that have variants +with interior mutability, and its value uses non interior mutable variants (see +[#3962](https://github.com/rust-lang/rust-clippy/issues/3962) and +[#3825](https://github.com/rust-lang/rust-clippy/issues/3825) for examples); +it complains about associated constants without default values only based on its types; +which might not be preferable. +There're other enums plus associated constants cases that the lint cannot handle. + +Types that have underlying or potential interior mutability trigger the lint whether +the interior mutable field is used or not. See issues +[#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and + +### Example +``` +use std::sync::atomic::{AtomicUsize, Ordering::SeqCst}; + +const CONST_ATOM: AtomicUsize = AtomicUsize::new(12); +CONST_ATOM.store(6, SeqCst); // the content of the atomic is unchanged +assert_eq!(CONST_ATOM.load(SeqCst), 12); // because the CONST_ATOM in these lines are distinct +``` + +Use instead: +``` +static STATIC_ATOM: AtomicUsize = AtomicUsize::new(15); +STATIC_ATOM.store(9, SeqCst); +assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance +``` \ No newline at end of file diff --git a/src/docs/default_instead_of_iter_empty.txt b/src/docs/default_instead_of_iter_empty.txt new file mode 100644 index 000000000000..b63ef3d18fc4 --- /dev/null +++ b/src/docs/default_instead_of_iter_empty.txt @@ -0,0 +1,15 @@ +### What it does +It checks for `std::iter::Empty::default()` and suggests replacing it with +`std::iter::empty()`. +### Why is this bad? +`std::iter::empty()` is the more idiomatic way. +### Example +``` +let _ = std::iter::Empty::::default(); +let iter: std::iter::Empty = std::iter::Empty::default(); +``` +Use instead: +``` +let _ = std::iter::empty::(); +let iter: std::iter::Empty = std::iter::empty(); +``` \ No newline at end of file diff --git a/src/docs/default_numeric_fallback.txt b/src/docs/default_numeric_fallback.txt new file mode 100644 index 000000000000..15076a0a68bf --- /dev/null +++ b/src/docs/default_numeric_fallback.txt @@ -0,0 +1,28 @@ +### What it does +Checks for usage of unconstrained numeric literals which may cause default numeric fallback in type +inference. + +Default numeric fallback means that if numeric types have not yet been bound to concrete +types at the end of type inference, then integer type is bound to `i32`, and similarly +floating type is bound to `f64`. + +See [RFC0212](https://github.com/rust-lang/rfcs/blob/master/text/0212-restore-int-fallback.md) for more information about the fallback. + +### Why is this bad? +For those who are very careful about types, default numeric fallback +can be a pitfall that cause unexpected runtime behavior. + +### Known problems +This lint can only be allowed at the function level or above. + +### Example +``` +let i = 10; +let f = 1.23; +``` + +Use instead: +``` +let i = 10i32; +let f = 1.23f64; +``` \ No newline at end of file diff --git a/src/docs/default_trait_access.txt b/src/docs/default_trait_access.txt new file mode 100644 index 000000000000..e69298969c8e --- /dev/null +++ b/src/docs/default_trait_access.txt @@ -0,0 +1,16 @@ +### What it does +Checks for literal calls to `Default::default()`. + +### Why is this bad? +It's easier for the reader if the name of the type is used, rather than the +generic `Default`. + +### Example +``` +let s: String = Default::default(); +``` + +Use instead: +``` +let s = String::default(); +``` \ No newline at end of file diff --git a/src/docs/default_union_representation.txt b/src/docs/default_union_representation.txt new file mode 100644 index 000000000000..f79ff9760e57 --- /dev/null +++ b/src/docs/default_union_representation.txt @@ -0,0 +1,36 @@ +### What it does +Displays a warning when a union is declared with the default representation (without a `#[repr(C)]` attribute). + +### Why is this bad? +Unions in Rust have unspecified layout by default, despite many people thinking that they +lay out each field at the start of the union (like C does). That is, there are no guarantees +about the offset of the fields for unions with multiple non-ZST fields without an explicitly +specified layout. These cases may lead to undefined behavior in unsafe blocks. + +### Example +``` +union Foo { + a: i32, + b: u32, +} + +fn main() { + let _x: u32 = unsafe { + Foo { a: 0_i32 }.b // Undefined behavior: `b` is allowed to be padding + }; +} +``` +Use instead: +``` +#[repr(C)] +union Foo { + a: i32, + b: u32, +} + +fn main() { + let _x: u32 = unsafe { + Foo { a: 0_i32 }.b // Now defined behavior, this is just an i32 -> u32 transmute + }; +} +``` \ No newline at end of file diff --git a/src/docs/deprecated_cfg_attr.txt b/src/docs/deprecated_cfg_attr.txt new file mode 100644 index 000000000000..9f264887a057 --- /dev/null +++ b/src/docs/deprecated_cfg_attr.txt @@ -0,0 +1,24 @@ +### What it does +Checks for `#[cfg_attr(rustfmt, rustfmt_skip)]` and suggests to replace it +with `#[rustfmt::skip]`. + +### Why is this bad? +Since tool_attributes ([rust-lang/rust#44690](https://github.com/rust-lang/rust/issues/44690)) +are stable now, they should be used instead of the old `cfg_attr(rustfmt)` attributes. + +### Known problems +This lint doesn't detect crate level inner attributes, because they get +processed before the PreExpansionPass lints get executed. See +[#3123](https://github.com/rust-lang/rust-clippy/pull/3123#issuecomment-422321765) + +### Example +``` +#[cfg_attr(rustfmt, rustfmt_skip)] +fn main() { } +``` + +Use instead: +``` +#[rustfmt::skip] +fn main() { } +``` \ No newline at end of file diff --git a/src/docs/deprecated_semver.txt b/src/docs/deprecated_semver.txt new file mode 100644 index 000000000000..c9574a99b2be --- /dev/null +++ b/src/docs/deprecated_semver.txt @@ -0,0 +1,13 @@ +### What it does +Checks for `#[deprecated]` annotations with a `since` +field that is not a valid semantic version. + +### Why is this bad? +For checking the version of the deprecation, it must be +a valid semver. Failing that, the contained information is useless. + +### Example +``` +#[deprecated(since = "forever")] +fn something_else() { /* ... */ } +``` \ No newline at end of file diff --git a/src/docs/deref_addrof.txt b/src/docs/deref_addrof.txt new file mode 100644 index 000000000000..fa711b924d48 --- /dev/null +++ b/src/docs/deref_addrof.txt @@ -0,0 +1,22 @@ +### What it does +Checks for usage of `*&` and `*&mut` in expressions. + +### Why is this bad? +Immediately dereferencing a reference is no-op and +makes the code less clear. + +### Known problems +Multiple dereference/addrof pairs are not handled so +the suggested fix for `x = **&&y` is `x = *&y`, which is still incorrect. + +### Example +``` +let a = f(*&mut b); +let c = *&d; +``` + +Use instead: +``` +let a = f(b); +let c = d; +``` \ No newline at end of file diff --git a/src/docs/deref_by_slicing.txt b/src/docs/deref_by_slicing.txt new file mode 100644 index 000000000000..4dad24ac00ca --- /dev/null +++ b/src/docs/deref_by_slicing.txt @@ -0,0 +1,17 @@ +### What it does +Checks for slicing expressions which are equivalent to dereferencing the +value. + +### Why is this bad? +Some people may prefer to dereference rather than slice. + +### Example +``` +let vec = vec![1, 2, 3]; +let slice = &vec[..]; +``` +Use instead: +``` +let vec = vec![1, 2, 3]; +let slice = &*vec; +``` \ No newline at end of file diff --git a/src/docs/derivable_impls.txt b/src/docs/derivable_impls.txt new file mode 100644 index 000000000000..8e4a80a672cc --- /dev/null +++ b/src/docs/derivable_impls.txt @@ -0,0 +1,35 @@ +### What it does +Detects manual `std::default::Default` implementations that are identical to a derived implementation. + +### Why is this bad? +It is less concise. + +### Example +``` +struct Foo { + bar: bool +} + +impl Default for Foo { + fn default() -> Self { + Self { + bar: false + } + } +} +``` + +Use instead: +``` +#[derive(Default)] +struct Foo { + bar: bool +} +``` + +### Known problems +Derive macros [sometimes use incorrect bounds](https://github.com/rust-lang/rust/issues/26925) +in generic types and the user defined `impl` maybe is more generalized or +specialized than what derive will produce. This lint can't detect the manual `impl` +has exactly equal bounds, and therefore this lint is disabled for types with +generic parameters. \ No newline at end of file diff --git a/src/docs/derive_hash_xor_eq.txt b/src/docs/derive_hash_xor_eq.txt new file mode 100644 index 000000000000..fbf623d5adbc --- /dev/null +++ b/src/docs/derive_hash_xor_eq.txt @@ -0,0 +1,23 @@ +### What it does +Checks for deriving `Hash` but implementing `PartialEq` +explicitly or vice versa. + +### Why is this bad? +The implementation of these traits must agree (for +example for use with `HashMap`) so it’s probably a bad idea to use a +default-generated `Hash` implementation with an explicitly defined +`PartialEq`. In particular, the following must hold for any type: + +``` +k1 == k2 ⇒ hash(k1) == hash(k2) +``` + +### Example +``` +#[derive(Hash)] +struct Foo; + +impl PartialEq for Foo { + ... +} +``` \ No newline at end of file diff --git a/src/docs/derive_ord_xor_partial_ord.txt b/src/docs/derive_ord_xor_partial_ord.txt new file mode 100644 index 000000000000..f2107a5f69ee --- /dev/null +++ b/src/docs/derive_ord_xor_partial_ord.txt @@ -0,0 +1,44 @@ +### What it does +Checks for deriving `Ord` but implementing `PartialOrd` +explicitly or vice versa. + +### Why is this bad? +The implementation of these traits must agree (for +example for use with `sort`) so it’s probably a bad idea to use a +default-generated `Ord` implementation with an explicitly defined +`PartialOrd`. In particular, the following must hold for any type +implementing `Ord`: + +``` +k1.cmp(&k2) == k1.partial_cmp(&k2).unwrap() +``` + +### Example +``` +#[derive(Ord, PartialEq, Eq)] +struct Foo; + +impl PartialOrd for Foo { + ... +} +``` +Use instead: +``` +#[derive(PartialEq, Eq)] +struct Foo; + +impl PartialOrd for Foo { + fn partial_cmp(&self, other: &Foo) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Foo { + ... +} +``` +or, if you don't need a custom ordering: +``` +#[derive(Ord, PartialOrd, PartialEq, Eq)] +struct Foo; +``` \ No newline at end of file diff --git a/src/docs/derive_partial_eq_without_eq.txt b/src/docs/derive_partial_eq_without_eq.txt new file mode 100644 index 000000000000..932fabad666c --- /dev/null +++ b/src/docs/derive_partial_eq_without_eq.txt @@ -0,0 +1,25 @@ +### What it does +Checks for types that derive `PartialEq` and could implement `Eq`. + +### Why is this bad? +If a type `T` derives `PartialEq` and all of its members implement `Eq`, +then `T` can always implement `Eq`. Implementing `Eq` allows `T` to be used +in APIs that require `Eq` types. It also allows structs containing `T` to derive +`Eq` themselves. + +### Example +``` +#[derive(PartialEq)] +struct Foo { + i_am_eq: i32, + i_am_eq_too: Vec, +} +``` +Use instead: +``` +#[derive(PartialEq, Eq)] +struct Foo { + i_am_eq: i32, + i_am_eq_too: Vec, +} +``` \ No newline at end of file diff --git a/src/docs/disallowed_methods.txt b/src/docs/disallowed_methods.txt new file mode 100644 index 000000000000..d8ad5b6a6674 --- /dev/null +++ b/src/docs/disallowed_methods.txt @@ -0,0 +1,41 @@ +### What it does +Denies the configured methods and functions in clippy.toml + +Note: Even though this lint is warn-by-default, it will only trigger if +methods are defined in the clippy.toml file. + +### Why is this bad? +Some methods are undesirable in certain contexts, and it's beneficial to +lint for them as needed. + +### Example +An example clippy.toml configuration: +``` +disallowed-methods = [ + # Can use a string as the path of the disallowed method. + "std::boxed::Box::new", + # Can also use an inline table with a `path` key. + { path = "std::time::Instant::now" }, + # When using an inline table, can add a `reason` for why the method + # is disallowed. + { path = "std::vec::Vec::leak", reason = "no leaking memory" }, +] +``` + +``` +// Example code where clippy issues a warning +let xs = vec![1, 2, 3, 4]; +xs.leak(); // Vec::leak is disallowed in the config. +// The diagnostic contains the message "no leaking memory". + +let _now = Instant::now(); // Instant::now is disallowed in the config. + +let _box = Box::new(3); // Box::new is disallowed in the config. +``` + +Use instead: +``` +// Example code which does not raise clippy warning +let mut xs = Vec::new(); // Vec::new is _not_ disallowed in the config. +xs.push(123); // Vec::push is _not_ disallowed in the config. +``` \ No newline at end of file diff --git a/src/docs/disallowed_names.txt b/src/docs/disallowed_names.txt new file mode 100644 index 000000000000..f4aaee9c77b7 --- /dev/null +++ b/src/docs/disallowed_names.txt @@ -0,0 +1,12 @@ +### What it does +Checks for usage of disallowed names for variables, such +as `foo`. + +### Why is this bad? +These names are usually placeholder names and should be +avoided. + +### Example +``` +let foo = 3.14; +``` \ No newline at end of file diff --git a/src/docs/disallowed_script_idents.txt b/src/docs/disallowed_script_idents.txt new file mode 100644 index 000000000000..2151b7a20ded --- /dev/null +++ b/src/docs/disallowed_script_idents.txt @@ -0,0 +1,32 @@ +### What it does +Checks for usage of unicode scripts other than those explicitly allowed +by the lint config. + +This lint doesn't take into account non-text scripts such as `Unknown` and `Linear_A`. +It also ignores the `Common` script type. +While configuring, be sure to use official script name [aliases] from +[the list of supported scripts][supported_scripts]. + +See also: [`non_ascii_idents`]. + +[aliases]: http://www.unicode.org/reports/tr24/tr24-31.html#Script_Value_Aliases +[supported_scripts]: https://www.unicode.org/iso15924/iso15924-codes.html + +### Why is this bad? +It may be not desired to have many different scripts for +identifiers in the codebase. + +Note that if you only want to allow plain English, you might want to use +built-in [`non_ascii_idents`] lint instead. + +[`non_ascii_idents`]: https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html#non-ascii-idents + +### Example +``` +// Assuming that `clippy.toml` contains the following line: +// allowed-locales = ["Latin", "Cyrillic"] +let counter = 10; // OK, latin is allowed. +let счётчик = 10; // OK, cyrillic is allowed. +let zähler = 10; // OK, it's still latin. +let カウンタ = 10; // Will spawn the lint. +``` \ No newline at end of file diff --git a/src/docs/disallowed_types.txt b/src/docs/disallowed_types.txt new file mode 100644 index 000000000000..2bcbcddee566 --- /dev/null +++ b/src/docs/disallowed_types.txt @@ -0,0 +1,33 @@ +### What it does +Denies the configured types in clippy.toml. + +Note: Even though this lint is warn-by-default, it will only trigger if +types are defined in the clippy.toml file. + +### Why is this bad? +Some types are undesirable in certain contexts. + +### Example: +An example clippy.toml configuration: +``` +disallowed-types = [ + # Can use a string as the path of the disallowed type. + "std::collections::BTreeMap", + # Can also use an inline table with a `path` key. + { path = "std::net::TcpListener" }, + # When using an inline table, can add a `reason` for why the type + # is disallowed. + { path = "std::net::Ipv4Addr", reason = "no IPv4 allowed" }, +] +``` + +``` +use std::collections::BTreeMap; +// or its use +let x = std::collections::BTreeMap::new(); +``` +Use instead: +``` +// A similar type that is allowed by the config +use std::collections::HashMap; +``` \ No newline at end of file diff --git a/src/docs/diverging_sub_expression.txt b/src/docs/diverging_sub_expression.txt new file mode 100644 index 000000000000..194362218025 --- /dev/null +++ b/src/docs/diverging_sub_expression.txt @@ -0,0 +1,19 @@ +### What it does +Checks for diverging calls that are not match arms or +statements. + +### Why is this bad? +It is often confusing to read. In addition, the +sub-expression evaluation order for Rust is not well documented. + +### Known problems +Someone might want to use `some_bool || panic!()` as a +shorthand. + +### Example +``` +let a = b() || panic!() || c(); +// `c()` is dead, `panic!()` is only called if `b()` returns `false` +let x = (a, b, c, panic!()); +// can simply be replaced by `panic!()` +``` \ No newline at end of file diff --git a/src/docs/doc_link_with_quotes.txt b/src/docs/doc_link_with_quotes.txt new file mode 100644 index 000000000000..107c8ac116d9 --- /dev/null +++ b/src/docs/doc_link_with_quotes.txt @@ -0,0 +1,16 @@ +### What it does +Detects the syntax `['foo']` in documentation comments (notice quotes instead of backticks) +outside of code blocks +### Why is this bad? +It is likely a typo when defining an intra-doc link + +### Example +``` +/// See also: ['foo'] +fn bar() {} +``` +Use instead: +``` +/// See also: [`foo`] +fn bar() {} +``` \ No newline at end of file diff --git a/src/docs/doc_markdown.txt b/src/docs/doc_markdown.txt new file mode 100644 index 000000000000..94f54c587e30 --- /dev/null +++ b/src/docs/doc_markdown.txt @@ -0,0 +1,35 @@ +### What it does +Checks for the presence of `_`, `::` or camel-case words +outside ticks in documentation. + +### Why is this bad? +*Rustdoc* supports markdown formatting, `_`, `::` and +camel-case probably indicates some code which should be included between +ticks. `_` can also be used for emphasis in markdown, this lint tries to +consider that. + +### Known problems +Lots of bad docs won’t be fixed, what the lint checks +for is limited, and there are still false positives. HTML elements and their +content are not linted. + +In addition, when writing documentation comments, including `[]` brackets +inside a link text would trip the parser. Therefore, documenting link with +`[`SmallVec<[T; INLINE_CAPACITY]>`]` and then [`SmallVec<[T; INLINE_CAPACITY]>`]: SmallVec +would fail. + +### Examples +``` +/// Do something with the foo_bar parameter. See also +/// that::other::module::foo. +// ^ `foo_bar` and `that::other::module::foo` should be ticked. +fn doit(foo_bar: usize) {} +``` + +``` +// Link text with `[]` brackets should be written as following: +/// Consume the array and return the inner +/// [`SmallVec<[T; INLINE_CAPACITY]>`][SmallVec]. +/// [SmallVec]: SmallVec +fn main() {} +``` \ No newline at end of file diff --git a/src/docs/double_comparisons.txt b/src/docs/double_comparisons.txt new file mode 100644 index 000000000000..7dc6818779f4 --- /dev/null +++ b/src/docs/double_comparisons.txt @@ -0,0 +1,17 @@ +### What it does +Checks for double comparisons that could be simplified to a single expression. + + +### Why is this bad? +Readability. + +### Example +``` +if x == y || x < y {} +``` + +Use instead: + +``` +if x <= y {} +``` \ No newline at end of file diff --git a/src/docs/double_must_use.txt b/src/docs/double_must_use.txt new file mode 100644 index 000000000000..0017d10d40d3 --- /dev/null +++ b/src/docs/double_must_use.txt @@ -0,0 +1,17 @@ +### What it does +Checks for a `#[must_use]` attribute without +further information on functions and methods that return a type already +marked as `#[must_use]`. + +### Why is this bad? +The attribute isn't needed. Not using the result +will already be reported. Alternatively, one can add some text to the +attribute to improve the lint message. + +### Examples +``` +#[must_use] +fn double_must_use() -> Result<(), ()> { + unimplemented!(); +} +``` \ No newline at end of file diff --git a/src/docs/double_neg.txt b/src/docs/double_neg.txt new file mode 100644 index 000000000000..a07f67496d7c --- /dev/null +++ b/src/docs/double_neg.txt @@ -0,0 +1,12 @@ +### What it does +Detects expressions of the form `--x`. + +### Why is this bad? +It can mislead C/C++ programmers to think `x` was +decremented. + +### Example +``` +let mut x = 3; +--x; +``` \ No newline at end of file diff --git a/src/docs/double_parens.txt b/src/docs/double_parens.txt new file mode 100644 index 000000000000..260d7dd575e5 --- /dev/null +++ b/src/docs/double_parens.txt @@ -0,0 +1,24 @@ +### What it does +Checks for unnecessary double parentheses. + +### Why is this bad? +This makes code harder to read and might indicate a +mistake. + +### Example +``` +fn simple_double_parens() -> i32 { + ((0)) +} + +foo((0)); +``` + +Use instead: +``` +fn simple_no_parens() -> i32 { + 0 +} + +foo(0); +``` \ No newline at end of file diff --git a/src/docs/drop_copy.txt b/src/docs/drop_copy.txt new file mode 100644 index 000000000000..f917ca8ed21a --- /dev/null +++ b/src/docs/drop_copy.txt @@ -0,0 +1,15 @@ +### What it does +Checks for calls to `std::mem::drop` with a value +that derives the Copy trait + +### Why is this bad? +Calling `std::mem::drop` [does nothing for types that +implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html), since the +value will be copied and moved into the function on invocation. + +### Example +``` +let x: i32 = 42; // i32 implements Copy +std::mem::drop(x) // A copy of x is passed to the function, leaving the + // original unaffected +``` \ No newline at end of file diff --git a/src/docs/drop_non_drop.txt b/src/docs/drop_non_drop.txt new file mode 100644 index 000000000000..ee1e3a6c216e --- /dev/null +++ b/src/docs/drop_non_drop.txt @@ -0,0 +1,13 @@ +### What it does +Checks for calls to `std::mem::drop` with a value that does not implement `Drop`. + +### Why is this bad? +Calling `std::mem::drop` is no different than dropping such a type. A different value may +have been intended. + +### Example +``` +struct Foo; +let x = Foo; +std::mem::drop(x); +``` \ No newline at end of file diff --git a/src/docs/drop_ref.txt b/src/docs/drop_ref.txt new file mode 100644 index 000000000000..c4f7adf0cfa3 --- /dev/null +++ b/src/docs/drop_ref.txt @@ -0,0 +1,17 @@ +### What it does +Checks for calls to `std::mem::drop` with a reference +instead of an owned value. + +### Why is this bad? +Calling `drop` on a reference will only drop the +reference itself, which is a no-op. It will not call the `drop` method (from +the `Drop` trait implementation) on the underlying referenced value, which +is likely what was intended. + +### Example +``` +let mut lock_guard = mutex.lock(); +std::mem::drop(&lock_guard) // Should have been drop(lock_guard), mutex +// still locked +operation_that_requires_mutex_to_be_unlocked(); +``` \ No newline at end of file diff --git a/src/docs/duplicate_mod.txt b/src/docs/duplicate_mod.txt new file mode 100644 index 000000000000..709a9aba03ad --- /dev/null +++ b/src/docs/duplicate_mod.txt @@ -0,0 +1,31 @@ +### What it does +Checks for files that are included as modules multiple times. + +### Why is this bad? +Loading a file as a module more than once causes it to be compiled +multiple times, taking longer and putting duplicate content into the +module tree. + +### Example +``` +// lib.rs +mod a; +mod b; +``` +``` +// a.rs +#[path = "./b.rs"] +mod b; +``` + +Use instead: + +``` +// lib.rs +mod a; +mod b; +``` +``` +// a.rs +use crate::b; +``` \ No newline at end of file diff --git a/src/docs/duplicate_underscore_argument.txt b/src/docs/duplicate_underscore_argument.txt new file mode 100644 index 000000000000..a8fcd6a9fbe6 --- /dev/null +++ b/src/docs/duplicate_underscore_argument.txt @@ -0,0 +1,16 @@ +### What it does +Checks for function arguments having the similar names +differing by an underscore. + +### Why is this bad? +It affects code readability. + +### Example +``` +fn foo(a: i32, _a: i32) {} +``` + +Use instead: +``` +fn bar(a: i32, _b: i32) {} +``` \ No newline at end of file diff --git a/src/docs/duration_subsec.txt b/src/docs/duration_subsec.txt new file mode 100644 index 000000000000..e7e0ca88745e --- /dev/null +++ b/src/docs/duration_subsec.txt @@ -0,0 +1,19 @@ +### What it does +Checks for calculation of subsecond microseconds or milliseconds +from other `Duration` methods. + +### Why is this bad? +It's more concise to call `Duration::subsec_micros()` or +`Duration::subsec_millis()` than to calculate them. + +### Example +``` +let micros = duration.subsec_nanos() / 1_000; +let millis = duration.subsec_nanos() / 1_000_000; +``` + +Use instead: +``` +let micros = duration.subsec_micros(); +let millis = duration.subsec_millis(); +``` \ No newline at end of file diff --git a/src/docs/else_if_without_else.txt b/src/docs/else_if_without_else.txt new file mode 100644 index 000000000000..33f5d0f91859 --- /dev/null +++ b/src/docs/else_if_without_else.txt @@ -0,0 +1,27 @@ +### What it does +Checks for usage of if expressions with an `else if` branch, +but without a final `else` branch. + +### Why is this bad? +Some coding guidelines require this (e.g., MISRA-C:2004 Rule 14.10). + +### Example +``` +if x.is_positive() { + a(); +} else if x.is_negative() { + b(); +} +``` + +Use instead: + +``` +if x.is_positive() { + a(); +} else if x.is_negative() { + b(); +} else { + // We don't care about zero. +} +``` \ No newline at end of file diff --git a/src/docs/empty_drop.txt b/src/docs/empty_drop.txt new file mode 100644 index 000000000000..d0c0c24a9c88 --- /dev/null +++ b/src/docs/empty_drop.txt @@ -0,0 +1,20 @@ +### What it does +Checks for empty `Drop` implementations. + +### Why is this bad? +Empty `Drop` implementations have no effect when dropping an instance of the type. They are +most likely useless. However, an empty `Drop` implementation prevents a type from being +destructured, which might be the intention behind adding the implementation as a marker. + +### Example +``` +struct S; + +impl Drop for S { + fn drop(&mut self) {} +} +``` +Use instead: +``` +struct S; +``` \ No newline at end of file diff --git a/src/docs/empty_enum.txt b/src/docs/empty_enum.txt new file mode 100644 index 000000000000..f7b41c41ee5a --- /dev/null +++ b/src/docs/empty_enum.txt @@ -0,0 +1,27 @@ +### What it does +Checks for `enum`s with no variants. + +As of this writing, the `never_type` is still a +nightly-only experimental API. Therefore, this lint is only triggered +if the `never_type` is enabled. + +### Why is this bad? +If you want to introduce a type which +can't be instantiated, you should use `!` (the primitive type "never"), +or a wrapper around it, because `!` has more extensive +compiler support (type inference, etc...) and wrappers +around it are the conventional way to define an uninhabited type. +For further information visit [never type documentation](https://doc.rust-lang.org/std/primitive.never.html) + + +### Example +``` +enum Test {} +``` + +Use instead: +``` +#![feature(never_type)] + +struct Test(!); +``` \ No newline at end of file diff --git a/src/docs/empty_line_after_outer_attr.txt b/src/docs/empty_line_after_outer_attr.txt new file mode 100644 index 000000000000..c85242bbee0e --- /dev/null +++ b/src/docs/empty_line_after_outer_attr.txt @@ -0,0 +1,35 @@ +### What it does +Checks for empty lines after outer attributes + +### Why is this bad? +Most likely the attribute was meant to be an inner attribute using a '!'. +If it was meant to be an outer attribute, then the following item +should not be separated by empty lines. + +### Known problems +Can cause false positives. + +From the clippy side it's difficult to detect empty lines between an attributes and the +following item because empty lines and comments are not part of the AST. The parsing +currently works for basic cases but is not perfect. + +### Example +``` +#[allow(dead_code)] + +fn not_quite_good_code() { } +``` + +Use instead: +``` +// Good (as inner attribute) +#![allow(dead_code)] + +fn this_is_fine() { } + +// or + +// Good (as outer attribute) +#[allow(dead_code)] +fn this_is_fine_too() { } +``` \ No newline at end of file diff --git a/src/docs/empty_loop.txt b/src/docs/empty_loop.txt new file mode 100644 index 000000000000..fea49a74d04e --- /dev/null +++ b/src/docs/empty_loop.txt @@ -0,0 +1,27 @@ +### What it does +Checks for empty `loop` expressions. + +### Why is this bad? +These busy loops burn CPU cycles without doing +anything. It is _almost always_ a better idea to `panic!` than to have +a busy loop. + +If panicking isn't possible, think of the environment and either: + - block on something + - sleep the thread for some microseconds + - yield or pause the thread + +For `std` targets, this can be done with +[`std::thread::sleep`](https://doc.rust-lang.org/std/thread/fn.sleep.html) +or [`std::thread::yield_now`](https://doc.rust-lang.org/std/thread/fn.yield_now.html). + +For `no_std` targets, doing this is more complicated, especially because +`#[panic_handler]`s can't panic. To stop/pause the thread, you will +probably need to invoke some target-specific intrinsic. Examples include: + - [`x86_64::instructions::hlt`](https://docs.rs/x86_64/0.12.2/x86_64/instructions/fn.hlt.html) + - [`cortex_m::asm::wfi`](https://docs.rs/cortex-m/0.6.3/cortex_m/asm/fn.wfi.html) + +### Example +``` +loop {} +``` \ No newline at end of file diff --git a/src/docs/empty_structs_with_brackets.txt b/src/docs/empty_structs_with_brackets.txt new file mode 100644 index 000000000000..ab5e35ae2ada --- /dev/null +++ b/src/docs/empty_structs_with_brackets.txt @@ -0,0 +1,14 @@ +### What it does +Finds structs without fields (a so-called "empty struct") that are declared with brackets. + +### Why is this bad? +Empty brackets after a struct declaration can be omitted. + +### Example +``` +struct Cookie {} +``` +Use instead: +``` +struct Cookie; +``` \ No newline at end of file diff --git a/src/docs/enum_clike_unportable_variant.txt b/src/docs/enum_clike_unportable_variant.txt new file mode 100644 index 000000000000..d30a973a5a13 --- /dev/null +++ b/src/docs/enum_clike_unportable_variant.txt @@ -0,0 +1,16 @@ +### What it does +Checks for C-like enumerations that are +`repr(isize/usize)` and have values that don't fit into an `i32`. + +### Why is this bad? +This will truncate the variant value on 32 bit +architectures, but works fine on 64 bit. + +### Example +``` +#[repr(usize)] +enum NonPortable { + X = 0x1_0000_0000, + Y = 0, +} +``` \ No newline at end of file diff --git a/src/docs/enum_glob_use.txt b/src/docs/enum_glob_use.txt new file mode 100644 index 000000000000..3776822c35b0 --- /dev/null +++ b/src/docs/enum_glob_use.txt @@ -0,0 +1,24 @@ +### What it does +Checks for `use Enum::*`. + +### Why is this bad? +It is usually better style to use the prefixed name of +an enumeration variant, rather than importing variants. + +### Known problems +Old-style enumerations that prefix the variants are +still around. + +### Example +``` +use std::cmp::Ordering::*; + +foo(Less); +``` + +Use instead: +``` +use std::cmp::Ordering; + +foo(Ordering::Less) +``` \ No newline at end of file diff --git a/src/docs/enum_variant_names.txt b/src/docs/enum_variant_names.txt new file mode 100644 index 000000000000..e726925edda8 --- /dev/null +++ b/src/docs/enum_variant_names.txt @@ -0,0 +1,30 @@ +### What it does +Detects enumeration variants that are prefixed or suffixed +by the same characters. + +### Why is this bad? +Enumeration variant names should specify their variant, +not repeat the enumeration name. + +### Limitations +Characters with no casing will be considered when comparing prefixes/suffixes +This applies to numbers and non-ascii characters without casing +e.g. `Foo1` and `Foo2` is considered to have different prefixes +(the prefixes are `Foo1` and `Foo2` respectively), as also `Bar螃`, `Bar蟹` + +### Example +``` +enum Cake { + BlackForestCake, + HummingbirdCake, + BattenbergCake, +} +``` +Use instead: +``` +enum Cake { + BlackForest, + Hummingbird, + Battenberg, +} +``` \ No newline at end of file diff --git a/src/docs/eq_op.txt b/src/docs/eq_op.txt new file mode 100644 index 000000000000..2d75a0ec546e --- /dev/null +++ b/src/docs/eq_op.txt @@ -0,0 +1,22 @@ +### What it does +Checks for equal operands to comparison, logical and +bitwise, difference and division binary operators (`==`, `>`, etc., `&&`, +`||`, `&`, `|`, `^`, `-` and `/`). + +### Why is this bad? +This is usually just a typo or a copy and paste error. + +### Known problems +False negatives: We had some false positives regarding +calls (notably [racer](https://github.com/phildawes/racer) had one instance +of `x.pop() && x.pop()`), so we removed matching any function or method +calls. We may introduce a list of known pure functions in the future. + +### Example +``` +if x + 1 == x + 1 {} + +// or + +assert_eq!(a, a); +``` \ No newline at end of file diff --git a/src/docs/equatable_if_let.txt b/src/docs/equatable_if_let.txt new file mode 100644 index 000000000000..9997046954c2 --- /dev/null +++ b/src/docs/equatable_if_let.txt @@ -0,0 +1,23 @@ +### What it does +Checks for pattern matchings that can be expressed using equality. + +### Why is this bad? + +* It reads better and has less cognitive load because equality won't cause binding. +* It is a [Yoda condition](https://en.wikipedia.org/wiki/Yoda_conditions). Yoda conditions are widely +criticized for increasing the cognitive load of reading the code. +* Equality is a simple bool expression and can be merged with `&&` and `||` and +reuse if blocks + +### Example +``` +if let Some(2) = x { + do_thing(); +} +``` +Use instead: +``` +if x == Some(2) { + do_thing(); +} +``` \ No newline at end of file diff --git a/src/docs/erasing_op.txt b/src/docs/erasing_op.txt new file mode 100644 index 000000000000..3d285a6d86e4 --- /dev/null +++ b/src/docs/erasing_op.txt @@ -0,0 +1,15 @@ +### What it does +Checks for erasing operations, e.g., `x * 0`. + +### Why is this bad? +The whole expression can be replaced by zero. +This is most likely not the intended outcome and should probably be +corrected + +### Example +``` +let x = 1; +0 / x; +0 * x; +x & 0; +``` \ No newline at end of file diff --git a/src/docs/err_expect.txt b/src/docs/err_expect.txt new file mode 100644 index 000000000000..1dc83c5ce0ee --- /dev/null +++ b/src/docs/err_expect.txt @@ -0,0 +1,16 @@ +### What it does +Checks for `.err().expect()` calls on the `Result` type. + +### Why is this bad? +`.expect_err()` can be called directly to avoid the extra type conversion from `err()`. + +### Example +``` +let x: Result = Ok(10); +x.err().expect("Testing err().expect()"); +``` +Use instead: +``` +let x: Result = Ok(10); +x.expect_err("Testing expect_err"); +``` \ No newline at end of file diff --git a/src/docs/excessive_precision.txt b/src/docs/excessive_precision.txt new file mode 100644 index 000000000000..517879c47152 --- /dev/null +++ b/src/docs/excessive_precision.txt @@ -0,0 +1,18 @@ +### What it does +Checks for float literals with a precision greater +than that supported by the underlying type. + +### Why is this bad? +Rust will truncate the literal silently. + +### Example +``` +let v: f32 = 0.123_456_789_9; +println!("{}", v); // 0.123_456_789 +``` + +Use instead: +``` +let v: f64 = 0.123_456_789_9; +println!("{}", v); // 0.123_456_789_9 +``` \ No newline at end of file diff --git a/src/docs/exhaustive_enums.txt b/src/docs/exhaustive_enums.txt new file mode 100644 index 000000000000..d1032a7a29aa --- /dev/null +++ b/src/docs/exhaustive_enums.txt @@ -0,0 +1,23 @@ +### What it does +Warns on any exported `enum`s that are not tagged `#[non_exhaustive]` + +### Why is this bad? +Exhaustive enums are typically fine, but a project which does +not wish to make a stability commitment around exported enums may wish to +disable them by default. + +### Example +``` +enum Foo { + Bar, + Baz +} +``` +Use instead: +``` +#[non_exhaustive] +enum Foo { + Bar, + Baz +} +``` \ No newline at end of file diff --git a/src/docs/exhaustive_structs.txt b/src/docs/exhaustive_structs.txt new file mode 100644 index 000000000000..fd6e4f5caf1f --- /dev/null +++ b/src/docs/exhaustive_structs.txt @@ -0,0 +1,23 @@ +### What it does +Warns on any exported `structs`s that are not tagged `#[non_exhaustive]` + +### Why is this bad? +Exhaustive structs are typically fine, but a project which does +not wish to make a stability commitment around exported structs may wish to +disable them by default. + +### Example +``` +struct Foo { + bar: u8, + baz: String, +} +``` +Use instead: +``` +#[non_exhaustive] +struct Foo { + bar: u8, + baz: String, +} +``` \ No newline at end of file diff --git a/src/docs/exit.txt b/src/docs/exit.txt new file mode 100644 index 000000000000..1e6154d43e05 --- /dev/null +++ b/src/docs/exit.txt @@ -0,0 +1,12 @@ +### What it does +`exit()` terminates the program and doesn't provide a +stack trace. + +### Why is this bad? +Ideally a program is terminated by finishing +the main function. + +### Example +``` +std::process::exit(0) +``` \ No newline at end of file diff --git a/src/docs/expect_fun_call.txt b/src/docs/expect_fun_call.txt new file mode 100644 index 000000000000..d82d9aa9baff --- /dev/null +++ b/src/docs/expect_fun_call.txt @@ -0,0 +1,24 @@ +### What it does +Checks for calls to `.expect(&format!(...))`, `.expect(foo(..))`, +etc., and suggests to use `unwrap_or_else` instead + +### Why is this bad? +The function will always be called. + +### Known problems +If the function has side-effects, not calling it will +change the semantics of the program, but you shouldn't rely on that anyway. + +### Example +``` +foo.expect(&format!("Err {}: {}", err_code, err_msg)); + +// or + +foo.expect(format!("Err {}: {}", err_code, err_msg).as_str()); +``` + +Use instead: +``` +foo.unwrap_or_else(|| panic!("Err {}: {}", err_code, err_msg)); +``` \ No newline at end of file diff --git a/src/docs/expect_used.txt b/src/docs/expect_used.txt new file mode 100644 index 000000000000..4a6981e334fd --- /dev/null +++ b/src/docs/expect_used.txt @@ -0,0 +1,26 @@ +### What it does +Checks for `.expect()` or `.expect_err()` calls on `Result`s and `.expect()` call on `Option`s. + +### Why is this bad? +Usually it is better to handle the `None` or `Err` case. +Still, for a lot of quick-and-dirty code, `expect` is a good choice, which is why +this lint is `Allow` by default. + +`result.expect()` will let the thread panic on `Err` +values. Normally, you want to implement more sophisticated error handling, +and propagate errors upwards with `?` operator. + +### Examples +``` +option.expect("one"); +result.expect("one"); +``` + +Use instead: +``` +option?; + +// or + +result?; +``` \ No newline at end of file diff --git a/src/docs/expl_impl_clone_on_copy.txt b/src/docs/expl_impl_clone_on_copy.txt new file mode 100644 index 000000000000..391d93b6713c --- /dev/null +++ b/src/docs/expl_impl_clone_on_copy.txt @@ -0,0 +1,20 @@ +### What it does +Checks for explicit `Clone` implementations for `Copy` +types. + +### Why is this bad? +To avoid surprising behavior, these traits should +agree and the behavior of `Copy` cannot be overridden. In almost all +situations a `Copy` type should have a `Clone` implementation that does +nothing more than copy the object, which is what `#[derive(Copy, Clone)]` +gets you. + +### Example +``` +#[derive(Copy)] +struct Foo; + +impl Clone for Foo { + // .. +} +``` \ No newline at end of file diff --git a/src/docs/explicit_auto_deref.txt b/src/docs/explicit_auto_deref.txt new file mode 100644 index 000000000000..65b256317725 --- /dev/null +++ b/src/docs/explicit_auto_deref.txt @@ -0,0 +1,16 @@ +### What it does +Checks for dereferencing expressions which would be covered by auto-deref. + +### Why is this bad? +This unnecessarily complicates the code. + +### Example +``` +let x = String::new(); +let y: &str = &*x; +``` +Use instead: +``` +let x = String::new(); +let y: &str = &x; +``` \ No newline at end of file diff --git a/src/docs/explicit_counter_loop.txt b/src/docs/explicit_counter_loop.txt new file mode 100644 index 000000000000..2661a43e1034 --- /dev/null +++ b/src/docs/explicit_counter_loop.txt @@ -0,0 +1,21 @@ +### What it does +Checks `for` loops over slices with an explicit counter +and suggests the use of `.enumerate()`. + +### Why is this bad? +Using `.enumerate()` makes the intent more clear, +declutters the code and may be faster in some instances. + +### Example +``` +let mut i = 0; +for item in &v { + bar(i, *item); + i += 1; +} +``` + +Use instead: +``` +for (i, item) in v.iter().enumerate() { bar(i, *item); } +``` \ No newline at end of file diff --git a/src/docs/explicit_deref_methods.txt b/src/docs/explicit_deref_methods.txt new file mode 100644 index 000000000000..e14e981c7073 --- /dev/null +++ b/src/docs/explicit_deref_methods.txt @@ -0,0 +1,24 @@ +### What it does +Checks for explicit `deref()` or `deref_mut()` method calls. + +### Why is this bad? +Dereferencing by `&*x` or `&mut *x` is clearer and more concise, +when not part of a method chain. + +### Example +``` +use std::ops::Deref; +let a: &mut String = &mut String::from("foo"); +let b: &str = a.deref(); +``` + +Use instead: +``` +let a: &mut String = &mut String::from("foo"); +let b = &*a; +``` + +This lint excludes: +``` +let _ = d.unwrap().deref(); +``` \ No newline at end of file diff --git a/src/docs/explicit_into_iter_loop.txt b/src/docs/explicit_into_iter_loop.txt new file mode 100644 index 000000000000..3931dfd69a31 --- /dev/null +++ b/src/docs/explicit_into_iter_loop.txt @@ -0,0 +1,20 @@ +### What it does +Checks for loops on `y.into_iter()` where `y` will do, and +suggests the latter. + +### Why is this bad? +Readability. + +### Example +``` +// with `y` a `Vec` or slice: +for x in y.into_iter() { + // .. +} +``` +can be rewritten to +``` +for x in y { + // .. +} +``` \ No newline at end of file diff --git a/src/docs/explicit_iter_loop.txt b/src/docs/explicit_iter_loop.txt new file mode 100644 index 000000000000..cabe72e91d04 --- /dev/null +++ b/src/docs/explicit_iter_loop.txt @@ -0,0 +1,25 @@ +### What it does +Checks for loops on `x.iter()` where `&x` will do, and +suggests the latter. + +### Why is this bad? +Readability. + +### Known problems +False negatives. We currently only warn on some known +types. + +### Example +``` +// with `y` a `Vec` or slice: +for x in y.iter() { + // .. +} +``` + +Use instead: +``` +for x in &y { + // .. +} +``` \ No newline at end of file diff --git a/src/docs/explicit_write.txt b/src/docs/explicit_write.txt new file mode 100644 index 000000000000..eafed5d39e5c --- /dev/null +++ b/src/docs/explicit_write.txt @@ -0,0 +1,18 @@ +### What it does +Checks for usage of `write!()` / `writeln()!` which can be +replaced with `(e)print!()` / `(e)println!()` + +### Why is this bad? +Using `(e)println! is clearer and more concise + +### Example +``` +writeln!(&mut std::io::stderr(), "foo: {:?}", bar).unwrap(); +writeln!(&mut std::io::stdout(), "foo: {:?}", bar).unwrap(); +``` + +Use instead: +``` +eprintln!("foo: {:?}", bar); +println!("foo: {:?}", bar); +``` \ No newline at end of file diff --git a/src/docs/extend_with_drain.txt b/src/docs/extend_with_drain.txt new file mode 100644 index 000000000000..2f31dcf5f740 --- /dev/null +++ b/src/docs/extend_with_drain.txt @@ -0,0 +1,21 @@ +### What it does +Checks for occurrences where one vector gets extended instead of append + +### Why is this bad? +Using `append` instead of `extend` is more concise and faster + +### Example +``` +let mut a = vec![1, 2, 3]; +let mut b = vec![4, 5, 6]; + +a.extend(b.drain(..)); +``` + +Use instead: +``` +let mut a = vec![1, 2, 3]; +let mut b = vec![4, 5, 6]; + +a.append(&mut b); +``` \ No newline at end of file diff --git a/src/docs/extra_unused_lifetimes.txt b/src/docs/extra_unused_lifetimes.txt new file mode 100644 index 000000000000..bc1814aa4752 --- /dev/null +++ b/src/docs/extra_unused_lifetimes.txt @@ -0,0 +1,23 @@ +### What it does +Checks for lifetimes in generics that are never used +anywhere else. + +### Why is this bad? +The additional lifetimes make the code look more +complicated, while there is nothing out of the ordinary going on. Removing +them leads to more readable code. + +### Example +``` +// unnecessary lifetimes +fn unused_lifetime<'a>(x: u8) { + // .. +} +``` + +Use instead: +``` +fn no_lifetime(x: u8) { + // ... +} +``` \ No newline at end of file diff --git a/src/docs/fallible_impl_from.txt b/src/docs/fallible_impl_from.txt new file mode 100644 index 000000000000..588a5bb103d4 --- /dev/null +++ b/src/docs/fallible_impl_from.txt @@ -0,0 +1,32 @@ +### What it does +Checks for impls of `From<..>` that contain `panic!()` or `unwrap()` + +### Why is this bad? +`TryFrom` should be used if there's a possibility of failure. + +### Example +``` +struct Foo(i32); + +impl From for Foo { + fn from(s: String) -> Self { + Foo(s.parse().unwrap()) + } +} +``` + +Use instead: +``` +struct Foo(i32); + +impl TryFrom for Foo { + type Error = (); + fn try_from(s: String) -> Result { + if let Ok(parsed) = s.parse() { + Ok(Foo(parsed)) + } else { + Err(()) + } + } +} +``` \ No newline at end of file diff --git a/src/docs/field_reassign_with_default.txt b/src/docs/field_reassign_with_default.txt new file mode 100644 index 000000000000..e58b7239fde9 --- /dev/null +++ b/src/docs/field_reassign_with_default.txt @@ -0,0 +1,23 @@ +### What it does +Checks for immediate reassignment of fields initialized +with Default::default(). + +### Why is this bad? +It's more idiomatic to use the [functional update syntax](https://doc.rust-lang.org/reference/expressions/struct-expr.html#functional-update-syntax). + +### Known problems +Assignments to patterns that are of tuple type are not linted. + +### Example +``` +let mut a: A = Default::default(); +a.i = 42; +``` + +Use instead: +``` +let a = A { + i: 42, + .. Default::default() +}; +``` \ No newline at end of file diff --git a/src/docs/filetype_is_file.txt b/src/docs/filetype_is_file.txt new file mode 100644 index 000000000000..ad14bd62c4de --- /dev/null +++ b/src/docs/filetype_is_file.txt @@ -0,0 +1,29 @@ +### What it does +Checks for `FileType::is_file()`. + +### Why is this bad? +When people testing a file type with `FileType::is_file` +they are testing whether a path is something they can get bytes from. But +`is_file` doesn't cover special file types in unix-like systems, and doesn't cover +symlink in windows. Using `!FileType::is_dir()` is a better way to that intention. + +### Example +``` +let metadata = std::fs::metadata("foo.txt")?; +let filetype = metadata.file_type(); + +if filetype.is_file() { + // read file +} +``` + +should be written as: + +``` +let metadata = std::fs::metadata("foo.txt")?; +let filetype = metadata.file_type(); + +if !filetype.is_dir() { + // read file +} +``` \ No newline at end of file diff --git a/src/docs/filter_map_identity.txt b/src/docs/filter_map_identity.txt new file mode 100644 index 000000000000..83b666f2e278 --- /dev/null +++ b/src/docs/filter_map_identity.txt @@ -0,0 +1,14 @@ +### What it does +Checks for usage of `filter_map(|x| x)`. + +### Why is this bad? +Readability, this can be written more concisely by using `flatten`. + +### Example +``` +iter.filter_map(|x| x); +``` +Use instead: +``` +iter.flatten(); +``` \ No newline at end of file diff --git a/src/docs/filter_map_next.txt b/src/docs/filter_map_next.txt new file mode 100644 index 000000000000..b38620b56a50 --- /dev/null +++ b/src/docs/filter_map_next.txt @@ -0,0 +1,16 @@ +### What it does +Checks for usage of `_.filter_map(_).next()`. + +### Why is this bad? +Readability, this can be written more concisely as +`_.find_map(_)`. + +### Example +``` + (0..3).filter_map(|x| if x == 2 { Some(x) } else { None }).next(); +``` +Can be written as + +``` + (0..3).find_map(|x| if x == 2 { Some(x) } else { None }); +``` \ No newline at end of file diff --git a/src/docs/filter_next.txt b/src/docs/filter_next.txt new file mode 100644 index 000000000000..898a74166dc1 --- /dev/null +++ b/src/docs/filter_next.txt @@ -0,0 +1,16 @@ +### What it does +Checks for usage of `_.filter(_).next()`. + +### Why is this bad? +Readability, this can be written more concisely as +`_.find(_)`. + +### Example +``` +vec.iter().filter(|x| **x == 0).next(); +``` + +Use instead: +``` +vec.iter().find(|x| **x == 0); +``` \ No newline at end of file diff --git a/src/docs/flat_map_identity.txt b/src/docs/flat_map_identity.txt new file mode 100644 index 000000000000..a5ee79b4982f --- /dev/null +++ b/src/docs/flat_map_identity.txt @@ -0,0 +1,14 @@ +### What it does +Checks for usage of `flat_map(|x| x)`. + +### Why is this bad? +Readability, this can be written more concisely by using `flatten`. + +### Example +``` +iter.flat_map(|x| x); +``` +Can be written as +``` +iter.flatten(); +``` \ No newline at end of file diff --git a/src/docs/flat_map_option.txt b/src/docs/flat_map_option.txt new file mode 100644 index 000000000000..d50b9156d365 --- /dev/null +++ b/src/docs/flat_map_option.txt @@ -0,0 +1,16 @@ +### What it does +Checks for usages of `Iterator::flat_map()` where `filter_map()` could be +used instead. + +### Why is this bad? +When applicable, `filter_map()` is more clear since it shows that +`Option` is used to produce 0 or 1 items. + +### Example +``` +let nums: Vec = ["1", "2", "whee!"].iter().flat_map(|x| x.parse().ok()).collect(); +``` +Use instead: +``` +let nums: Vec = ["1", "2", "whee!"].iter().filter_map(|x| x.parse().ok()).collect(); +``` \ No newline at end of file diff --git a/src/docs/float_arithmetic.txt b/src/docs/float_arithmetic.txt new file mode 100644 index 000000000000..1f9bce5abd59 --- /dev/null +++ b/src/docs/float_arithmetic.txt @@ -0,0 +1,11 @@ +### What it does +Checks for float arithmetic. + +### Why is this bad? +For some embedded systems or kernel development, it +can be useful to rule out floating-point numbers. + +### Example +``` +a + 1.0; +``` \ No newline at end of file diff --git a/src/docs/float_cmp.txt b/src/docs/float_cmp.txt new file mode 100644 index 000000000000..c19907c903e9 --- /dev/null +++ b/src/docs/float_cmp.txt @@ -0,0 +1,28 @@ +### What it does +Checks for (in-)equality comparisons on floating-point +values (apart from zero), except in functions called `*eq*` (which probably +implement equality for a type involving floats). + +### Why is this bad? +Floating point calculations are usually imprecise, so +asking if two values are *exactly* equal is asking for trouble. For a good +guide on what to do, see [the floating point +guide](http://www.floating-point-gui.de/errors/comparison). + +### Example +``` +let x = 1.2331f64; +let y = 1.2332f64; + +if y == 1.23f64 { } +if y != x {} // where both are floats +``` + +Use instead: +``` +let error_margin = f64::EPSILON; // Use an epsilon for comparison +// Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead. +// let error_margin = std::f64::EPSILON; +if (y - 1.23f64).abs() < error_margin { } +if (y - x).abs() > error_margin { } +``` \ No newline at end of file diff --git a/src/docs/float_cmp_const.txt b/src/docs/float_cmp_const.txt new file mode 100644 index 000000000000..9208feaacd81 --- /dev/null +++ b/src/docs/float_cmp_const.txt @@ -0,0 +1,26 @@ +### What it does +Checks for (in-)equality comparisons on floating-point +value and constant, except in functions called `*eq*` (which probably +implement equality for a type involving floats). + +### Why is this bad? +Floating point calculations are usually imprecise, so +asking if two values are *exactly* equal is asking for trouble. For a good +guide on what to do, see [the floating point +guide](http://www.floating-point-gui.de/errors/comparison). + +### Example +``` +let x: f64 = 1.0; +const ONE: f64 = 1.00; + +if x == ONE { } // where both are floats +``` + +Use instead: +``` +let error_margin = f64::EPSILON; // Use an epsilon for comparison +// Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead. +// let error_margin = std::f64::EPSILON; +if (x - ONE).abs() < error_margin { } +``` \ No newline at end of file diff --git a/src/docs/float_equality_without_abs.txt b/src/docs/float_equality_without_abs.txt new file mode 100644 index 000000000000..556b574e15d3 --- /dev/null +++ b/src/docs/float_equality_without_abs.txt @@ -0,0 +1,26 @@ +### What it does +Checks for statements of the form `(a - b) < f32::EPSILON` or +`(a - b) < f64::EPSILON`. Notes the missing `.abs()`. + +### Why is this bad? +The code without `.abs()` is more likely to have a bug. + +### Known problems +If the user can ensure that b is larger than a, the `.abs()` is +technically unnecessary. However, it will make the code more robust and doesn't have any +large performance implications. If the abs call was deliberately left out for performance +reasons, it is probably better to state this explicitly in the code, which then can be done +with an allow. + +### Example +``` +pub fn is_roughly_equal(a: f32, b: f32) -> bool { + (a - b) < f32::EPSILON +} +``` +Use instead: +``` +pub fn is_roughly_equal(a: f32, b: f32) -> bool { + (a - b).abs() < f32::EPSILON +} +``` \ No newline at end of file diff --git a/src/docs/fn_address_comparisons.txt b/src/docs/fn_address_comparisons.txt new file mode 100644 index 000000000000..7d2b7b681deb --- /dev/null +++ b/src/docs/fn_address_comparisons.txt @@ -0,0 +1,17 @@ +### What it does +Checks for comparisons with an address of a function item. + +### Why is this bad? +Function item address is not guaranteed to be unique and could vary +between different code generation units. Furthermore different function items could have +the same address after being merged together. + +### Example +``` +type F = fn(); +fn a() {} +let f: F = a; +if f == a { + // ... +} +``` \ No newline at end of file diff --git a/src/docs/fn_params_excessive_bools.txt b/src/docs/fn_params_excessive_bools.txt new file mode 100644 index 000000000000..2eae0563368c --- /dev/null +++ b/src/docs/fn_params_excessive_bools.txt @@ -0,0 +1,31 @@ +### What it does +Checks for excessive use of +bools in function definitions. + +### Why is this bad? +Calls to such functions +are confusing and error prone, because it's +hard to remember argument order and you have +no type system support to back you up. Using +two-variant enums instead of bools often makes +API easier to use. + +### Example +``` +fn f(is_round: bool, is_hot: bool) { ... } +``` + +Use instead: +``` +enum Shape { + Round, + Spiky, +} + +enum Temperature { + Hot, + IceCold, +} + +fn f(shape: Shape, temperature: Temperature) { ... } +``` \ No newline at end of file diff --git a/src/docs/fn_to_numeric_cast.txt b/src/docs/fn_to_numeric_cast.txt new file mode 100644 index 000000000000..1f587f6d7176 --- /dev/null +++ b/src/docs/fn_to_numeric_cast.txt @@ -0,0 +1,21 @@ +### What it does +Checks for casts of function pointers to something other than usize + +### Why is this bad? +Casting a function pointer to anything other than usize/isize is not portable across +architectures, because you end up losing bits if the target type is too small or end up with a +bunch of extra bits that waste space and add more instructions to the final binary than +strictly necessary for the problem + +Casting to isize also doesn't make sense since there are no signed addresses. + +### Example +``` +fn fun() -> i32 { 1 } +let _ = fun as i64; +``` + +Use instead: +``` +let _ = fun as usize; +``` \ No newline at end of file diff --git a/src/docs/fn_to_numeric_cast_any.txt b/src/docs/fn_to_numeric_cast_any.txt new file mode 100644 index 000000000000..ee3c33d23725 --- /dev/null +++ b/src/docs/fn_to_numeric_cast_any.txt @@ -0,0 +1,35 @@ +### What it does +Checks for casts of a function pointer to any integer type. + +### Why is this bad? +Casting a function pointer to an integer can have surprising results and can occur +accidentally if parentheses are omitted from a function call. If you aren't doing anything +low-level with function pointers then you can opt-out of casting functions to integers in +order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function +pointer casts in your code. + +### Example +``` +// fn1 is cast as `usize` +fn fn1() -> u16 { + 1 +}; +let _ = fn1 as usize; +``` + +Use instead: +``` +// maybe you intended to call the function? +fn fn2() -> u16 { + 1 +}; +let _ = fn2() as usize; + +// or + +// maybe you intended to cast it to a function type? +fn fn3() -> u16 { + 1 +} +let _ = fn3 as fn() -> u16; +``` \ No newline at end of file diff --git a/src/docs/fn_to_numeric_cast_with_truncation.txt b/src/docs/fn_to_numeric_cast_with_truncation.txt new file mode 100644 index 000000000000..69f12fa319f1 --- /dev/null +++ b/src/docs/fn_to_numeric_cast_with_truncation.txt @@ -0,0 +1,26 @@ +### What it does +Checks for casts of a function pointer to a numeric type not wide enough to +store address. + +### Why is this bad? +Such a cast discards some bits of the function's address. If this is intended, it would be more +clearly expressed by casting to usize first, then casting the usize to the intended type (with +a comment) to perform the truncation. + +### Example +``` +fn fn1() -> i16 { + 1 +}; +let _ = fn1 as i32; +``` + +Use instead: +``` +// Cast to usize first, then comment with the reason for the truncation +fn fn1() -> i16 { + 1 +}; +let fn_ptr = fn1 as usize; +let fn_ptr_truncated = fn_ptr as i32; +``` \ No newline at end of file diff --git a/src/docs/for_kv_map.txt b/src/docs/for_kv_map.txt new file mode 100644 index 000000000000..a9a2ffee9c74 --- /dev/null +++ b/src/docs/for_kv_map.txt @@ -0,0 +1,22 @@ +### What it does +Checks for iterating a map (`HashMap` or `BTreeMap`) and +ignoring either the keys or values. + +### Why is this bad? +Readability. There are `keys` and `values` methods that +can be used to express that don't need the values or keys. + +### Example +``` +for (k, _) in &map { + .. +} +``` + +could be replaced by + +``` +for k in map.keys() { + .. +} +``` \ No newline at end of file diff --git a/src/docs/for_loops_over_fallibles.txt b/src/docs/for_loops_over_fallibles.txt new file mode 100644 index 000000000000..c5a7508e45d4 --- /dev/null +++ b/src/docs/for_loops_over_fallibles.txt @@ -0,0 +1,32 @@ +### What it does +Checks for `for` loops over `Option` or `Result` values. + +### Why is this bad? +Readability. This is more clearly expressed as an `if +let`. + +### Example +``` +for x in opt { + // .. +} + +for x in &res { + // .. +} + +for x in res.iter() { + // .. +} +``` + +Use instead: +``` +if let Some(x) = opt { + // .. +} + +if let Ok(x) = res { + // .. +} +``` \ No newline at end of file diff --git a/src/docs/forget_copy.txt b/src/docs/forget_copy.txt new file mode 100644 index 000000000000..1d100912e9a4 --- /dev/null +++ b/src/docs/forget_copy.txt @@ -0,0 +1,21 @@ +### What it does +Checks for calls to `std::mem::forget` with a value that +derives the Copy trait + +### Why is this bad? +Calling `std::mem::forget` [does nothing for types that +implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html) since the +value will be copied and moved into the function on invocation. + +An alternative, but also valid, explanation is that Copy types do not +implement +the Drop trait, which means they have no destructors. Without a destructor, +there +is nothing for `std::mem::forget` to ignore. + +### Example +``` +let x: i32 = 42; // i32 implements Copy +std::mem::forget(x) // A copy of x is passed to the function, leaving the + // original unaffected +``` \ No newline at end of file diff --git a/src/docs/forget_non_drop.txt b/src/docs/forget_non_drop.txt new file mode 100644 index 000000000000..3307d654c17f --- /dev/null +++ b/src/docs/forget_non_drop.txt @@ -0,0 +1,13 @@ +### What it does +Checks for calls to `std::mem::forget` with a value that does not implement `Drop`. + +### Why is this bad? +Calling `std::mem::forget` is no different than dropping such a type. A different value may +have been intended. + +### Example +``` +struct Foo; +let x = Foo; +std::mem::forget(x); +``` \ No newline at end of file diff --git a/src/docs/forget_ref.txt b/src/docs/forget_ref.txt new file mode 100644 index 000000000000..874fb8786068 --- /dev/null +++ b/src/docs/forget_ref.txt @@ -0,0 +1,15 @@ +### What it does +Checks for calls to `std::mem::forget` with a reference +instead of an owned value. + +### Why is this bad? +Calling `forget` on a reference will only forget the +reference itself, which is a no-op. It will not forget the underlying +referenced +value, which is likely what was intended. + +### Example +``` +let x = Box::new(1); +std::mem::forget(&x) // Should have been forget(x), x will still be dropped +``` \ No newline at end of file diff --git a/src/docs/format_in_format_args.txt b/src/docs/format_in_format_args.txt new file mode 100644 index 000000000000..ac498472f017 --- /dev/null +++ b/src/docs/format_in_format_args.txt @@ -0,0 +1,16 @@ +### What it does +Detects `format!` within the arguments of another macro that does +formatting such as `format!` itself, `write!` or `println!`. Suggests +inlining the `format!` call. + +### Why is this bad? +The recommended code is both shorter and avoids a temporary allocation. + +### Example +``` +println!("error: {}", format!("something failed at {}", Location::caller())); +``` +Use instead: +``` +println!("error: something failed at {}", Location::caller()); +``` \ No newline at end of file diff --git a/src/docs/format_push_string.txt b/src/docs/format_push_string.txt new file mode 100644 index 000000000000..ca409ebc7ec2 --- /dev/null +++ b/src/docs/format_push_string.txt @@ -0,0 +1,26 @@ +### What it does +Detects cases where the result of a `format!` call is +appended to an existing `String`. + +### Why is this bad? +Introduces an extra, avoidable heap allocation. + +### Known problems +`format!` returns a `String` but `write!` returns a `Result`. +Thus you are forced to ignore the `Err` variant to achieve the same API. + +While using `write!` in the suggested way should never fail, this isn't necessarily clear to the programmer. + +### Example +``` +let mut s = String::new(); +s += &format!("0x{:X}", 1024); +s.push_str(&format!("0x{:X}", 1024)); +``` +Use instead: +``` +use std::fmt::Write as _; // import without risk of name clashing + +let mut s = String::new(); +let _ = write!(s, "0x{:X}", 1024); +``` \ No newline at end of file diff --git a/src/docs/from_iter_instead_of_collect.txt b/src/docs/from_iter_instead_of_collect.txt new file mode 100644 index 000000000000..f3fd27597264 --- /dev/null +++ b/src/docs/from_iter_instead_of_collect.txt @@ -0,0 +1,24 @@ +### What it does +Checks for `from_iter()` function calls on types that implement the `FromIterator` +trait. + +### Why is this bad? +It is recommended style to use collect. See +[FromIterator documentation](https://doc.rust-lang.org/std/iter/trait.FromIterator.html) + +### Example +``` +let five_fives = std::iter::repeat(5).take(5); + +let v = Vec::from_iter(five_fives); + +assert_eq!(v, vec![5, 5, 5, 5, 5]); +``` +Use instead: +``` +let five_fives = std::iter::repeat(5).take(5); + +let v: Vec = five_fives.collect(); + +assert_eq!(v, vec![5, 5, 5, 5, 5]); +``` \ No newline at end of file diff --git a/src/docs/from_over_into.txt b/src/docs/from_over_into.txt new file mode 100644 index 000000000000..0770bcc42c27 --- /dev/null +++ b/src/docs/from_over_into.txt @@ -0,0 +1,26 @@ +### What it does +Searches for implementations of the `Into<..>` trait and suggests to implement `From<..>` instead. + +### Why is this bad? +According the std docs implementing `From<..>` is preferred since it gives you `Into<..>` for free where the reverse isn't true. + +### Example +``` +struct StringWrapper(String); + +impl Into for String { + fn into(self) -> StringWrapper { + StringWrapper(self) + } +} +``` +Use instead: +``` +struct StringWrapper(String); + +impl From for StringWrapper { + fn from(s: String) -> StringWrapper { + StringWrapper(s) + } +} +``` \ No newline at end of file diff --git a/src/docs/from_str_radix_10.txt b/src/docs/from_str_radix_10.txt new file mode 100644 index 000000000000..f6f319d3eaa1 --- /dev/null +++ b/src/docs/from_str_radix_10.txt @@ -0,0 +1,25 @@ +### What it does + +Checks for function invocations of the form `primitive::from_str_radix(s, 10)` + +### Why is this bad? + +This specific common use case can be rewritten as `s.parse::()` +(and in most cases, the turbofish can be removed), which reduces code length +and complexity. + +### Known problems + +This lint may suggest using (&).parse() instead of .parse() directly +in some cases, which is correct but adds unnecessary complexity to the code. + +### Example +``` +let input: &str = get_input(); +let num = u16::from_str_radix(input, 10)?; +``` +Use instead: +``` +let input: &str = get_input(); +let num: u16 = input.parse()?; +``` \ No newline at end of file diff --git a/src/docs/future_not_send.txt b/src/docs/future_not_send.txt new file mode 100644 index 000000000000..0aa048d27355 --- /dev/null +++ b/src/docs/future_not_send.txt @@ -0,0 +1,29 @@ +### What it does +This lint requires Future implementations returned from +functions and methods to implement the `Send` marker trait. It is mostly +used by library authors (public and internal) that target an audience where +multithreaded executors are likely to be used for running these Futures. + +### Why is this bad? +A Future implementation captures some state that it +needs to eventually produce its final value. When targeting a multithreaded +executor (which is the norm on non-embedded devices) this means that this +state may need to be transported to other threads, in other words the +whole Future needs to implement the `Send` marker trait. If it does not, +then the resulting Future cannot be submitted to a thread pool in the +end user’s code. + +Especially for generic functions it can be confusing to leave the +discovery of this problem to the end user: the reported error location +will be far from its cause and can in many cases not even be fixed without +modifying the library where the offending Future implementation is +produced. + +### Example +``` +async fn not_send(bytes: std::rc::Rc<[u8]>) {} +``` +Use instead: +``` +async fn is_send(bytes: std::sync::Arc<[u8]>) {} +``` \ No newline at end of file diff --git a/src/docs/get_first.txt b/src/docs/get_first.txt new file mode 100644 index 000000000000..c905a737ddf3 --- /dev/null +++ b/src/docs/get_first.txt @@ -0,0 +1,19 @@ +### What it does +Checks for using `x.get(0)` instead of +`x.first()`. + +### Why is this bad? +Using `x.first()` is easier to read and has the same +result. + +### Example +``` +let x = vec![2, 3, 5]; +let first_element = x.get(0); +``` + +Use instead: +``` +let x = vec![2, 3, 5]; +let first_element = x.first(); +``` \ No newline at end of file diff --git a/src/docs/get_last_with_len.txt b/src/docs/get_last_with_len.txt new file mode 100644 index 000000000000..31c7f269586a --- /dev/null +++ b/src/docs/get_last_with_len.txt @@ -0,0 +1,26 @@ +### What it does +Checks for using `x.get(x.len() - 1)` instead of +`x.last()`. + +### Why is this bad? +Using `x.last()` is easier to read and has the same +result. + +Note that using `x[x.len() - 1]` is semantically different from +`x.last()`. Indexing into the array will panic on out-of-bounds +accesses, while `x.get()` and `x.last()` will return `None`. + +There is another lint (get_unwrap) that covers the case of using +`x.get(index).unwrap()` instead of `x[index]`. + +### Example +``` +let x = vec![2, 3, 5]; +let last_element = x.get(x.len() - 1); +``` + +Use instead: +``` +let x = vec![2, 3, 5]; +let last_element = x.last(); +``` \ No newline at end of file diff --git a/src/docs/get_unwrap.txt b/src/docs/get_unwrap.txt new file mode 100644 index 000000000000..8defc2224416 --- /dev/null +++ b/src/docs/get_unwrap.txt @@ -0,0 +1,30 @@ +### What it does +Checks for use of `.get().unwrap()` (or +`.get_mut().unwrap`) on a standard library type which implements `Index` + +### Why is this bad? +Using the Index trait (`[]`) is more clear and more +concise. + +### Known problems +Not a replacement for error handling: Using either +`.unwrap()` or the Index trait (`[]`) carries the risk of causing a `panic` +if the value being accessed is `None`. If the use of `.get().unwrap()` is a +temporary placeholder for dealing with the `Option` type, then this does +not mitigate the need for error handling. If there is a chance that `.get()` +will be `None` in your program, then it is advisable that the `None` case +is handled in a future refactor instead of using `.unwrap()` or the Index +trait. + +### Example +``` +let mut some_vec = vec![0, 1, 2, 3]; +let last = some_vec.get(3).unwrap(); +*some_vec.get_mut(0).unwrap() = 1; +``` +The correct use would be: +``` +let mut some_vec = vec![0, 1, 2, 3]; +let last = some_vec[3]; +some_vec[0] = 1; +``` \ No newline at end of file diff --git a/src/docs/identity_op.txt b/src/docs/identity_op.txt new file mode 100644 index 000000000000..a8e40bb43e9d --- /dev/null +++ b/src/docs/identity_op.txt @@ -0,0 +1,11 @@ +### What it does +Checks for identity operations, e.g., `x + 0`. + +### Why is this bad? +This code can be removed without changing the +meaning. So it just obscures what's going on. Delete it mercilessly. + +### Example +``` +x / 1 + 0 * 1 - 0 | 0; +``` \ No newline at end of file diff --git a/src/docs/if_let_mutex.txt b/src/docs/if_let_mutex.txt new file mode 100644 index 000000000000..4d873ade9ace --- /dev/null +++ b/src/docs/if_let_mutex.txt @@ -0,0 +1,25 @@ +### What it does +Checks for `Mutex::lock` calls in `if let` expression +with lock calls in any of the else blocks. + +### Why is this bad? +The Mutex lock remains held for the whole +`if let ... else` block and deadlocks. + +### Example +``` +if let Ok(thing) = mutex.lock() { + do_thing(); +} else { + mutex.lock(); +} +``` +Should be written +``` +let locked = mutex.lock(); +if let Ok(thing) = locked { + do_thing(thing); +} else { + use_locked(locked); +} +``` \ No newline at end of file diff --git a/src/docs/if_not_else.txt b/src/docs/if_not_else.txt new file mode 100644 index 000000000000..0e5ac4ce6bb8 --- /dev/null +++ b/src/docs/if_not_else.txt @@ -0,0 +1,25 @@ +### What it does +Checks for usage of `!` or `!=` in an if condition with an +else branch. + +### Why is this bad? +Negations reduce the readability of statements. + +### Example +``` +if !v.is_empty() { + a() +} else { + b() +} +``` + +Could be written: + +``` +if v.is_empty() { + b() +} else { + a() +} +``` \ No newline at end of file diff --git a/src/docs/if_same_then_else.txt b/src/docs/if_same_then_else.txt new file mode 100644 index 000000000000..75127016bb8c --- /dev/null +++ b/src/docs/if_same_then_else.txt @@ -0,0 +1,15 @@ +### What it does +Checks for `if/else` with the same body as the *then* part +and the *else* part. + +### Why is this bad? +This is probably a copy & paste error. + +### Example +``` +let foo = if … { + 42 +} else { + 42 +}; +``` \ No newline at end of file diff --git a/src/docs/if_then_some_else_none.txt b/src/docs/if_then_some_else_none.txt new file mode 100644 index 000000000000..13744f920e36 --- /dev/null +++ b/src/docs/if_then_some_else_none.txt @@ -0,0 +1,26 @@ +### What it does +Checks for if-else that could be written using either `bool::then` or `bool::then_some`. + +### Why is this bad? +Looks a little redundant. Using `bool::then` is more concise and incurs no loss of clarity. +For simple calculations and known values, use `bool::then_some`, which is eagerly evaluated +in comparison to `bool::then`. + +### Example +``` +let a = if v.is_empty() { + println!("true!"); + Some(42) +} else { + None +}; +``` + +Could be written: + +``` +let a = v.is_empty().then(|| { + println!("true!"); + 42 +}); +``` \ No newline at end of file diff --git a/src/docs/ifs_same_cond.txt b/src/docs/ifs_same_cond.txt new file mode 100644 index 000000000000..024ba5df93a6 --- /dev/null +++ b/src/docs/ifs_same_cond.txt @@ -0,0 +1,25 @@ +### What it does +Checks for consecutive `if`s with the same condition. + +### Why is this bad? +This is probably a copy & paste error. + +### Example +``` +if a == b { + … +} else if a == b { + … +} +``` + +Note that this lint ignores all conditions with a function call as it could +have side effects: + +``` +if foo() { + … +} else if foo() { // not linted + … +} +``` \ No newline at end of file diff --git a/src/docs/implicit_clone.txt b/src/docs/implicit_clone.txt new file mode 100644 index 000000000000..f5aa112c52c3 --- /dev/null +++ b/src/docs/implicit_clone.txt @@ -0,0 +1,19 @@ +### What it does +Checks for the usage of `_.to_owned()`, `vec.to_vec()`, or similar when calling `_.clone()` would be clearer. + +### Why is this bad? +These methods do the same thing as `_.clone()` but may be confusing as +to why we are calling `to_vec` on something that is already a `Vec` or calling `to_owned` on something that is already owned. + +### Example +``` +let a = vec![1, 2, 3]; +let b = a.to_vec(); +let c = a.to_owned(); +``` +Use instead: +``` +let a = vec![1, 2, 3]; +let b = a.clone(); +let c = a.clone(); +``` \ No newline at end of file diff --git a/src/docs/implicit_hasher.txt b/src/docs/implicit_hasher.txt new file mode 100644 index 000000000000..0c1f76620f51 --- /dev/null +++ b/src/docs/implicit_hasher.txt @@ -0,0 +1,26 @@ +### What it does +Checks for public `impl` or `fn` missing generalization +over different hashers and implicitly defaulting to the default hashing +algorithm (`SipHash`). + +### Why is this bad? +`HashMap` or `HashSet` with custom hashers cannot be +used with them. + +### Known problems +Suggestions for replacing constructors can contain +false-positives. Also applying suggestions can require modification of other +pieces of code, possibly including external crates. + +### Example +``` +impl Serialize for HashMap { } + +pub fn foo(map: &mut HashMap) { } +``` +could be rewritten as +``` +impl Serialize for HashMap { } + +pub fn foo(map: &mut HashMap) { } +``` \ No newline at end of file diff --git a/src/docs/implicit_return.txt b/src/docs/implicit_return.txt new file mode 100644 index 000000000000..ee65a636b38c --- /dev/null +++ b/src/docs/implicit_return.txt @@ -0,0 +1,22 @@ +### What it does +Checks for missing return statements at the end of a block. + +### Why is this bad? +Actually omitting the return keyword is idiomatic Rust code. Programmers +coming from other languages might prefer the expressiveness of `return`. It's possible to miss +the last returning statement because the only difference is a missing `;`. Especially in bigger +code with multiple return paths having a `return` keyword makes it easier to find the +corresponding statements. + +### Example +``` +fn foo(x: usize) -> usize { + x +} +``` +add return +``` +fn foo(x: usize) -> usize { + return x; +} +``` \ No newline at end of file diff --git a/src/docs/implicit_saturating_sub.txt b/src/docs/implicit_saturating_sub.txt new file mode 100644 index 000000000000..03b47905a211 --- /dev/null +++ b/src/docs/implicit_saturating_sub.txt @@ -0,0 +1,21 @@ +### What it does +Checks for implicit saturating subtraction. + +### Why is this bad? +Simplicity and readability. Instead we can easily use an builtin function. + +### Example +``` +let mut i: u32 = end - start; + +if i != 0 { + i -= 1; +} +``` + +Use instead: +``` +let mut i: u32 = end - start; + +i = i.saturating_sub(1); +``` \ No newline at end of file diff --git a/src/docs/imprecise_flops.txt b/src/docs/imprecise_flops.txt new file mode 100644 index 000000000000..e84d81cea98e --- /dev/null +++ b/src/docs/imprecise_flops.txt @@ -0,0 +1,23 @@ +### What it does +Looks for floating-point expressions that +can be expressed using built-in methods to improve accuracy +at the cost of performance. + +### Why is this bad? +Negatively impacts accuracy. + +### Example +``` +let a = 3f32; +let _ = a.powf(1.0 / 3.0); +let _ = (1.0 + a).ln(); +let _ = a.exp() - 1.0; +``` + +Use instead: +``` +let a = 3f32; +let _ = a.cbrt(); +let _ = a.ln_1p(); +let _ = a.exp_m1(); +``` \ No newline at end of file diff --git a/src/docs/inconsistent_digit_grouping.txt b/src/docs/inconsistent_digit_grouping.txt new file mode 100644 index 000000000000..aa0b072de1c4 --- /dev/null +++ b/src/docs/inconsistent_digit_grouping.txt @@ -0,0 +1,17 @@ +### What it does +Warns if an integral or floating-point constant is +grouped inconsistently with underscores. + +### Why is this bad? +Readers may incorrectly interpret inconsistently +grouped digits. + +### Example +``` +618_64_9189_73_511 +``` + +Use instead: +``` +61_864_918_973_511 +``` \ No newline at end of file diff --git a/src/docs/inconsistent_struct_constructor.txt b/src/docs/inconsistent_struct_constructor.txt new file mode 100644 index 000000000000..eb682109a54e --- /dev/null +++ b/src/docs/inconsistent_struct_constructor.txt @@ -0,0 +1,40 @@ +### What it does +Checks for struct constructors where all fields are shorthand and +the order of the field init shorthand in the constructor is inconsistent +with the order in the struct definition. + +### Why is this bad? +Since the order of fields in a constructor doesn't affect the +resulted instance as the below example indicates, + +``` +#[derive(Debug, PartialEq, Eq)] +struct Foo { + x: i32, + y: i32, +} +let x = 1; +let y = 2; + +// This assertion never fails: +assert_eq!(Foo { x, y }, Foo { y, x }); +``` + +inconsistent order can be confusing and decreases readability and consistency. + +### Example +``` +struct Foo { + x: i32, + y: i32, +} +let x = 1; +let y = 2; + +Foo { y, x }; +``` + +Use instead: +``` +Foo { x, y }; +``` \ No newline at end of file diff --git a/src/docs/index_refutable_slice.txt b/src/docs/index_refutable_slice.txt new file mode 100644 index 000000000000..8a7d52761af8 --- /dev/null +++ b/src/docs/index_refutable_slice.txt @@ -0,0 +1,29 @@ +### What it does +The lint checks for slice bindings in patterns that are only used to +access individual slice values. + +### Why is this bad? +Accessing slice values using indices can lead to panics. Using refutable +patterns can avoid these. Binding to individual values also improves the +readability as they can be named. + +### Limitations +This lint currently only checks for immutable access inside `if let` +patterns. + +### Example +``` +let slice: Option<&[u32]> = Some(&[1, 2, 3]); + +if let Some(slice) = slice { + println!("{}", slice[0]); +} +``` +Use instead: +``` +let slice: Option<&[u32]> = Some(&[1, 2, 3]); + +if let Some(&[first, ..]) = slice { + println!("{}", first); +} +``` \ No newline at end of file diff --git a/src/docs/indexing_slicing.txt b/src/docs/indexing_slicing.txt new file mode 100644 index 000000000000..76ca6ed318b3 --- /dev/null +++ b/src/docs/indexing_slicing.txt @@ -0,0 +1,33 @@ +### What it does +Checks for usage of indexing or slicing. Arrays are special cases, this lint +does report on arrays if we can tell that slicing operations are in bounds and does not +lint on constant `usize` indexing on arrays because that is handled by rustc's `const_err` lint. + +### Why is this bad? +Indexing and slicing can panic at runtime and there are +safe alternatives. + +### Example +``` +// Vector +let x = vec![0; 5]; + +x[2]; +&x[2..100]; + +// Array +let y = [0, 1, 2, 3]; + +&y[10..100]; +&y[10..]; +``` + +Use instead: +``` + +x.get(2); +x.get(2..100); + +y.get(10); +y.get(10..100); +``` \ No newline at end of file diff --git a/src/docs/ineffective_bit_mask.txt b/src/docs/ineffective_bit_mask.txt new file mode 100644 index 000000000000..f6e7ef556215 --- /dev/null +++ b/src/docs/ineffective_bit_mask.txt @@ -0,0 +1,25 @@ +### What it does +Checks for bit masks in comparisons which can be removed +without changing the outcome. The basic structure can be seen in the +following table: + +|Comparison| Bit Op |Example |equals | +|----------|----------|------------|-------| +|`>` / `<=`|`\|` / `^`|`x \| 2 > 3`|`x > 3`| +|`<` / `>=`|`\|` / `^`|`x ^ 1 < 4` |`x < 4`| + +### Why is this bad? +Not equally evil as [`bad_bit_mask`](#bad_bit_mask), +but still a bit misleading, because the bit mask is ineffective. + +### Known problems +False negatives: This lint will only match instances +where we have figured out the math (which is for a power-of-two compared +value). This means things like `x | 1 >= 7` (which would be better written +as `x >= 6`) will not be reported (but bit masks like this are fairly +uncommon). + +### Example +``` +if (x | 1 > 3) { } +``` \ No newline at end of file diff --git a/src/docs/inefficient_to_string.txt b/src/docs/inefficient_to_string.txt new file mode 100644 index 000000000000..f7061d1ce7b0 --- /dev/null +++ b/src/docs/inefficient_to_string.txt @@ -0,0 +1,17 @@ +### What it does +Checks for usage of `.to_string()` on an `&&T` where +`T` implements `ToString` directly (like `&&str` or `&&String`). + +### Why is this bad? +This bypasses the specialized implementation of +`ToString` and instead goes through the more expensive string formatting +facilities. + +### Example +``` +// Generic implementation for `T: Display` is used (slow) +["foo", "bar"].iter().map(|s| s.to_string()); + +// OK, the specialized impl is used +["foo", "bar"].iter().map(|&s| s.to_string()); +``` \ No newline at end of file diff --git a/src/docs/infallible_destructuring_match.txt b/src/docs/infallible_destructuring_match.txt new file mode 100644 index 000000000000..4b5d3c4ba6c4 --- /dev/null +++ b/src/docs/infallible_destructuring_match.txt @@ -0,0 +1,29 @@ +### What it does +Checks for matches being used to destructure a single-variant enum +or tuple struct where a `let` will suffice. + +### Why is this bad? +Just readability – `let` doesn't nest, whereas a `match` does. + +### Example +``` +enum Wrapper { + Data(i32), +} + +let wrapper = Wrapper::Data(42); + +let data = match wrapper { + Wrapper::Data(i) => i, +}; +``` + +The correct use would be: +``` +enum Wrapper { + Data(i32), +} + +let wrapper = Wrapper::Data(42); +let Wrapper::Data(data) = wrapper; +``` \ No newline at end of file diff --git a/src/docs/infinite_iter.txt b/src/docs/infinite_iter.txt new file mode 100644 index 000000000000..8a22fabc5492 --- /dev/null +++ b/src/docs/infinite_iter.txt @@ -0,0 +1,13 @@ +### What it does +Checks for iteration that is guaranteed to be infinite. + +### Why is this bad? +While there may be places where this is acceptable +(e.g., in event streams), in most cases this is simply an error. + +### Example +``` +use std::iter; + +iter::repeat(1_u8).collect::>(); +``` \ No newline at end of file diff --git a/src/docs/inherent_to_string.txt b/src/docs/inherent_to_string.txt new file mode 100644 index 000000000000..b18e600e9e67 --- /dev/null +++ b/src/docs/inherent_to_string.txt @@ -0,0 +1,29 @@ +### What it does +Checks for the definition of inherent methods with a signature of `to_string(&self) -> String`. + +### Why is this bad? +This method is also implicitly defined if a type implements the `Display` trait. As the functionality of `Display` is much more versatile, it should be preferred. + +### Example +``` +pub struct A; + +impl A { + pub fn to_string(&self) -> String { + "I am A".to_string() + } +} +``` + +Use instead: +``` +use std::fmt; + +pub struct A; + +impl fmt::Display for A { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "I am A") + } +} +``` \ No newline at end of file diff --git a/src/docs/inherent_to_string_shadow_display.txt b/src/docs/inherent_to_string_shadow_display.txt new file mode 100644 index 000000000000..a4bd0b622c4f --- /dev/null +++ b/src/docs/inherent_to_string_shadow_display.txt @@ -0,0 +1,37 @@ +### What it does +Checks for the definition of inherent methods with a signature of `to_string(&self) -> String` and if the type implementing this method also implements the `Display` trait. + +### Why is this bad? +This method is also implicitly defined if a type implements the `Display` trait. The less versatile inherent method will then shadow the implementation introduced by `Display`. + +### Example +``` +use std::fmt; + +pub struct A; + +impl A { + pub fn to_string(&self) -> String { + "I am A".to_string() + } +} + +impl fmt::Display for A { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "I am A, too") + } +} +``` + +Use instead: +``` +use std::fmt; + +pub struct A; + +impl fmt::Display for A { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "I am A") + } +} +``` \ No newline at end of file diff --git a/src/docs/init_numbered_fields.txt b/src/docs/init_numbered_fields.txt new file mode 100644 index 000000000000..ba40af6a5fa5 --- /dev/null +++ b/src/docs/init_numbered_fields.txt @@ -0,0 +1,24 @@ +### What it does +Checks for tuple structs initialized with field syntax. +It will however not lint if a base initializer is present. +The lint will also ignore code in macros. + +### Why is this bad? +This may be confusing to the uninitiated and adds no +benefit as opposed to tuple initializers + +### Example +``` +struct TupleStruct(u8, u16); + +let _ = TupleStruct { + 0: 1, + 1: 23, +}; + +// should be written as +let base = TupleStruct(1, 23); + +// This is OK however +let _ = TupleStruct { 0: 42, ..base }; +``` \ No newline at end of file diff --git a/src/docs/inline_always.txt b/src/docs/inline_always.txt new file mode 100644 index 000000000000..7721da4c4cc7 --- /dev/null +++ b/src/docs/inline_always.txt @@ -0,0 +1,23 @@ +### What it does +Checks for items annotated with `#[inline(always)]`, +unless the annotated function is empty or simply panics. + +### Why is this bad? +While there are valid uses of this annotation (and once +you know when to use it, by all means `allow` this lint), it's a common +newbie-mistake to pepper one's code with it. + +As a rule of thumb, before slapping `#[inline(always)]` on a function, +measure if that additional function call really affects your runtime profile +sufficiently to make up for the increase in compile time. + +### Known problems +False positives, big time. This lint is meant to be +deactivated by everyone doing serious performance work. This means having +done the measurement. + +### Example +``` +#[inline(always)] +fn not_quite_hot_code(..) { ... } +``` \ No newline at end of file diff --git a/src/docs/inline_asm_x86_att_syntax.txt b/src/docs/inline_asm_x86_att_syntax.txt new file mode 100644 index 000000000000..8eb49d122d89 --- /dev/null +++ b/src/docs/inline_asm_x86_att_syntax.txt @@ -0,0 +1,16 @@ +### What it does +Checks for usage of AT&T x86 assembly syntax. + +### Why is this bad? +The lint has been enabled to indicate a preference +for Intel x86 assembly syntax. + +### Example + +``` +asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax)); +``` +Use instead: +``` +asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr); +``` \ No newline at end of file diff --git a/src/docs/inline_asm_x86_intel_syntax.txt b/src/docs/inline_asm_x86_intel_syntax.txt new file mode 100644 index 000000000000..5aa22c8ed235 --- /dev/null +++ b/src/docs/inline_asm_x86_intel_syntax.txt @@ -0,0 +1,16 @@ +### What it does +Checks for usage of Intel x86 assembly syntax. + +### Why is this bad? +The lint has been enabled to indicate a preference +for AT&T x86 assembly syntax. + +### Example + +``` +asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr); +``` +Use instead: +``` +asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax)); +``` \ No newline at end of file diff --git a/src/docs/inline_fn_without_body.txt b/src/docs/inline_fn_without_body.txt new file mode 100644 index 000000000000..127c161aaa25 --- /dev/null +++ b/src/docs/inline_fn_without_body.txt @@ -0,0 +1,14 @@ +### What it does +Checks for `#[inline]` on trait methods without bodies + +### Why is this bad? +Only implementations of trait methods may be inlined. +The inline attribute is ignored for trait methods without bodies. + +### Example +``` +trait Animal { + #[inline] + fn name(&self) -> &'static str; +} +``` \ No newline at end of file diff --git a/src/docs/inspect_for_each.txt b/src/docs/inspect_for_each.txt new file mode 100644 index 000000000000..01a46d6c451f --- /dev/null +++ b/src/docs/inspect_for_each.txt @@ -0,0 +1,23 @@ +### What it does +Checks for usage of `inspect().for_each()`. + +### Why is this bad? +It is the same as performing the computation +inside `inspect` at the beginning of the closure in `for_each`. + +### Example +``` +[1,2,3,4,5].iter() +.inspect(|&x| println!("inspect the number: {}", x)) +.for_each(|&x| { + assert!(x >= 0); +}); +``` +Can be written as +``` +[1,2,3,4,5].iter() +.for_each(|&x| { + println!("inspect the number: {}", x); + assert!(x >= 0); +}); +``` \ No newline at end of file diff --git a/src/docs/int_plus_one.txt b/src/docs/int_plus_one.txt new file mode 100644 index 000000000000..1b68f3eeb64b --- /dev/null +++ b/src/docs/int_plus_one.txt @@ -0,0 +1,15 @@ +### What it does +Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block + +### Why is this bad? +Readability -- better to use `> y` instead of `>= y + 1`. + +### Example +``` +if x >= y + 1 {} +``` + +Use instead: +``` +if x > y {} +``` \ No newline at end of file diff --git a/src/docs/integer_arithmetic.txt b/src/docs/integer_arithmetic.txt new file mode 100644 index 000000000000..ea57a2ef97bf --- /dev/null +++ b/src/docs/integer_arithmetic.txt @@ -0,0 +1,18 @@ +### What it does +Checks for integer arithmetic operations which could overflow or panic. + +Specifically, checks for any operators (`+`, `-`, `*`, `<<`, etc) which are capable +of overflowing according to the [Rust +Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow), +or which can panic (`/`, `%`). No bounds analysis or sophisticated reasoning is +attempted. + +### Why is this bad? +Integer overflow will trigger a panic in debug builds or will wrap in +release mode. Division by zero will cause a panic in either mode. In some applications one +wants explicitly checked, wrapping or saturating arithmetic. + +### Example +``` +a + 1; +``` \ No newline at end of file diff --git a/src/docs/integer_division.txt b/src/docs/integer_division.txt new file mode 100644 index 000000000000..f6d3349810ed --- /dev/null +++ b/src/docs/integer_division.txt @@ -0,0 +1,19 @@ +### What it does +Checks for division of integers + +### Why is this bad? +When outside of some very specific algorithms, +integer division is very often a mistake because it discards the +remainder. + +### Example +``` +let x = 3 / 2; +println!("{}", x); +``` + +Use instead: +``` +let x = 3f32 / 2f32; +println!("{}", x); +``` \ No newline at end of file diff --git a/src/docs/into_iter_on_ref.txt b/src/docs/into_iter_on_ref.txt new file mode 100644 index 000000000000..acb6bd474ebf --- /dev/null +++ b/src/docs/into_iter_on_ref.txt @@ -0,0 +1,18 @@ +### What it does +Checks for `into_iter` calls on references which should be replaced by `iter` +or `iter_mut`. + +### Why is this bad? +Readability. Calling `into_iter` on a reference will not move out its +content into the resulting iterator, which is confusing. It is better just call `iter` or +`iter_mut` directly. + +### Example +``` +(&vec).into_iter(); +``` + +Use instead: +``` +(&vec).iter(); +``` \ No newline at end of file diff --git a/src/docs/invalid_null_ptr_usage.txt b/src/docs/invalid_null_ptr_usage.txt new file mode 100644 index 000000000000..6fb3fa3f83d6 --- /dev/null +++ b/src/docs/invalid_null_ptr_usage.txt @@ -0,0 +1,16 @@ +### What it does +This lint checks for invalid usages of `ptr::null`. + +### Why is this bad? +This causes undefined behavior. + +### Example +``` +// Undefined behavior +unsafe { std::slice::from_raw_parts(ptr::null(), 0); } +``` + +Use instead: +``` +unsafe { std::slice::from_raw_parts(NonNull::dangling().as_ptr(), 0); } +``` \ No newline at end of file diff --git a/src/docs/invalid_regex.txt b/src/docs/invalid_regex.txt new file mode 100644 index 000000000000..6c9969b6e1a3 --- /dev/null +++ b/src/docs/invalid_regex.txt @@ -0,0 +1,12 @@ +### What it does +Checks [regex](https://crates.io/crates/regex) creation +(with `Regex::new`, `RegexBuilder::new`, or `RegexSet::new`) for correct +regex syntax. + +### Why is this bad? +This will lead to a runtime panic. + +### Example +``` +Regex::new("(") +``` \ No newline at end of file diff --git a/src/docs/invalid_upcast_comparisons.txt b/src/docs/invalid_upcast_comparisons.txt new file mode 100644 index 000000000000..77cb03308037 --- /dev/null +++ b/src/docs/invalid_upcast_comparisons.txt @@ -0,0 +1,18 @@ +### What it does +Checks for comparisons where the relation is always either +true or false, but where one side has been upcast so that the comparison is +necessary. Only integer types are checked. + +### Why is this bad? +An expression like `let x : u8 = ...; (x as u32) > 300` +will mistakenly imply that it is possible for `x` to be outside the range of +`u8`. + +### Known problems +https://github.com/rust-lang/rust-clippy/issues/886 + +### Example +``` +let x: u8 = 1; +(x as u32) > 300; +``` \ No newline at end of file diff --git a/src/docs/invalid_utf8_in_unchecked.txt b/src/docs/invalid_utf8_in_unchecked.txt new file mode 100644 index 000000000000..afb5acbe9c51 --- /dev/null +++ b/src/docs/invalid_utf8_in_unchecked.txt @@ -0,0 +1,12 @@ +### What it does +Checks for `std::str::from_utf8_unchecked` with an invalid UTF-8 literal + +### Why is this bad? +Creating such a `str` would result in undefined behavior + +### Example +``` +unsafe { + std::str::from_utf8_unchecked(b"cl\x82ippy"); +} +``` \ No newline at end of file diff --git a/src/docs/invisible_characters.txt b/src/docs/invisible_characters.txt new file mode 100644 index 000000000000..3dda380911f9 --- /dev/null +++ b/src/docs/invisible_characters.txt @@ -0,0 +1,10 @@ +### What it does +Checks for invisible Unicode characters in the code. + +### Why is this bad? +Having an invisible character in the code makes for all +sorts of April fools, but otherwise is very much frowned upon. + +### Example +You don't see it, but there may be a zero-width space or soft hyphen +some­where in this text. \ No newline at end of file diff --git a/src/docs/is_digit_ascii_radix.txt b/src/docs/is_digit_ascii_radix.txt new file mode 100644 index 000000000000..9f11cf43054f --- /dev/null +++ b/src/docs/is_digit_ascii_radix.txt @@ -0,0 +1,20 @@ +### What it does +Finds usages of [`char::is_digit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_digit) that +can be replaced with [`is_ascii_digit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_ascii_digit) or +[`is_ascii_hexdigit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_ascii_hexdigit). + +### Why is this bad? +`is_digit(..)` is slower and requires specifying the radix. + +### Example +``` +let c: char = '6'; +c.is_digit(10); +c.is_digit(16); +``` +Use instead: +``` +let c: char = '6'; +c.is_ascii_digit(); +c.is_ascii_hexdigit(); +``` \ No newline at end of file diff --git a/src/docs/items_after_statements.txt b/src/docs/items_after_statements.txt new file mode 100644 index 000000000000..6fdfff50d20e --- /dev/null +++ b/src/docs/items_after_statements.txt @@ -0,0 +1,37 @@ +### What it does +Checks for items declared after some statement in a block. + +### Why is this bad? +Items live for the entire scope they are declared +in. But statements are processed in order. This might cause confusion as +it's hard to figure out which item is meant in a statement. + +### Example +``` +fn foo() { + println!("cake"); +} + +fn main() { + foo(); // prints "foo" + fn foo() { + println!("foo"); + } + foo(); // prints "foo" +} +``` + +Use instead: +``` +fn foo() { + println!("cake"); +} + +fn main() { + fn foo() { + println!("foo"); + } + foo(); // prints "foo" + foo(); // prints "foo" +} +``` \ No newline at end of file diff --git a/src/docs/iter_cloned_collect.txt b/src/docs/iter_cloned_collect.txt new file mode 100644 index 000000000000..90dc9ebb40f0 --- /dev/null +++ b/src/docs/iter_cloned_collect.txt @@ -0,0 +1,17 @@ +### What it does +Checks for the use of `.cloned().collect()` on slice to +create a `Vec`. + +### Why is this bad? +`.to_vec()` is clearer + +### Example +``` +let s = [1, 2, 3, 4, 5]; +let s2: Vec = s[..].iter().cloned().collect(); +``` +The better use would be: +``` +let s = [1, 2, 3, 4, 5]; +let s2: Vec = s.to_vec(); +``` \ No newline at end of file diff --git a/src/docs/iter_count.txt b/src/docs/iter_count.txt new file mode 100644 index 000000000000..f3db4a26c299 --- /dev/null +++ b/src/docs/iter_count.txt @@ -0,0 +1,22 @@ +### What it does +Checks for the use of `.iter().count()`. + +### Why is this bad? +`.len()` is more efficient and more +readable. + +### Example +``` +let some_vec = vec![0, 1, 2, 3]; + +some_vec.iter().count(); +&some_vec[..].iter().count(); +``` + +Use instead: +``` +let some_vec = vec![0, 1, 2, 3]; + +some_vec.len(); +&some_vec[..].len(); +``` \ No newline at end of file diff --git a/src/docs/iter_next_loop.txt b/src/docs/iter_next_loop.txt new file mode 100644 index 000000000000..b33eb39d6e1d --- /dev/null +++ b/src/docs/iter_next_loop.txt @@ -0,0 +1,17 @@ +### What it does +Checks for loops on `x.next()`. + +### Why is this bad? +`next()` returns either `Some(value)` if there was a +value, or `None` otherwise. The insidious thing is that `Option<_>` +implements `IntoIterator`, so that possibly one value will be iterated, +leading to some hard to find bugs. No one will want to write such code +[except to win an Underhanded Rust +Contest](https://www.reddit.com/r/rust/comments/3hb0wm/underhanded_rust_contest/cu5yuhr). + +### Example +``` +for x in y.next() { + .. +} +``` \ No newline at end of file diff --git a/src/docs/iter_next_slice.txt b/src/docs/iter_next_slice.txt new file mode 100644 index 000000000000..1cea25eaf301 --- /dev/null +++ b/src/docs/iter_next_slice.txt @@ -0,0 +1,16 @@ +### What it does +Checks for usage of `iter().next()` on a Slice or an Array + +### Why is this bad? +These can be shortened into `.get()` + +### Example +``` +a[2..].iter().next(); +b.iter().next(); +``` +should be written as: +``` +a.get(2); +b.get(0); +``` \ No newline at end of file diff --git a/src/docs/iter_not_returning_iterator.txt b/src/docs/iter_not_returning_iterator.txt new file mode 100644 index 000000000000..0ca862910a6f --- /dev/null +++ b/src/docs/iter_not_returning_iterator.txt @@ -0,0 +1,26 @@ +### What it does +Detects methods named `iter` or `iter_mut` that do not have a return type that implements `Iterator`. + +### Why is this bad? +Methods named `iter` or `iter_mut` conventionally return an `Iterator`. + +### Example +``` +// `String` does not implement `Iterator` +struct Data {} +impl Data { + fn iter(&self) -> String { + todo!() + } +} +``` +Use instead: +``` +use std::str::Chars; +struct Data {} +impl Data { + fn iter(&self) -> Chars<'static> { + todo!() + } +} +``` \ No newline at end of file diff --git a/src/docs/iter_nth.txt b/src/docs/iter_nth.txt new file mode 100644 index 000000000000..3d67d583ffde --- /dev/null +++ b/src/docs/iter_nth.txt @@ -0,0 +1,20 @@ +### What it does +Checks for use of `.iter().nth()` (and the related +`.iter_mut().nth()`) on standard library types with *O*(1) element access. + +### Why is this bad? +`.get()` and `.get_mut()` are more efficient and more +readable. + +### Example +``` +let some_vec = vec![0, 1, 2, 3]; +let bad_vec = some_vec.iter().nth(3); +let bad_slice = &some_vec[..].iter().nth(3); +``` +The correct use would be: +``` +let some_vec = vec![0, 1, 2, 3]; +let bad_vec = some_vec.get(3); +let bad_slice = &some_vec[..].get(3); +``` \ No newline at end of file diff --git a/src/docs/iter_nth_zero.txt b/src/docs/iter_nth_zero.txt new file mode 100644 index 000000000000..8efe47a16a10 --- /dev/null +++ b/src/docs/iter_nth_zero.txt @@ -0,0 +1,17 @@ +### What it does +Checks for the use of `iter.nth(0)`. + +### Why is this bad? +`iter.next()` is equivalent to +`iter.nth(0)`, as they both consume the next element, + but is more readable. + +### Example +``` +let x = s.iter().nth(0); +``` + +Use instead: +``` +let x = s.iter().next(); +``` \ No newline at end of file diff --git a/src/docs/iter_on_empty_collections.txt b/src/docs/iter_on_empty_collections.txt new file mode 100644 index 000000000000..87c4ec12afae --- /dev/null +++ b/src/docs/iter_on_empty_collections.txt @@ -0,0 +1,25 @@ +### What it does + +Checks for calls to `iter`, `iter_mut` or `into_iter` on empty collections + +### Why is this bad? + +It is simpler to use the empty function from the standard library: + +### Example + +``` +use std::{slice, option}; +let a: slice::Iter = [].iter(); +let f: option::IntoIter = None.into_iter(); +``` +Use instead: +``` +use std::iter; +let a: iter::Empty = iter::empty(); +let b: iter::Empty = iter::empty(); +``` + +### Known problems + +The type of the resulting iterator might become incompatible with its usage \ No newline at end of file diff --git a/src/docs/iter_on_single_items.txt b/src/docs/iter_on_single_items.txt new file mode 100644 index 000000000000..d0388f25d045 --- /dev/null +++ b/src/docs/iter_on_single_items.txt @@ -0,0 +1,24 @@ +### What it does + +Checks for calls to `iter`, `iter_mut` or `into_iter` on collections containing a single item + +### Why is this bad? + +It is simpler to use the once function from the standard library: + +### Example + +``` +let a = [123].iter(); +let b = Some(123).into_iter(); +``` +Use instead: +``` +use std::iter; +let a = iter::once(&123); +let b = iter::once(123); +``` + +### Known problems + +The type of the resulting iterator might become incompatible with its usage \ No newline at end of file diff --git a/src/docs/iter_overeager_cloned.txt b/src/docs/iter_overeager_cloned.txt new file mode 100644 index 000000000000..2f902a0c2db4 --- /dev/null +++ b/src/docs/iter_overeager_cloned.txt @@ -0,0 +1,22 @@ +### What it does +Checks for usage of `_.cloned().()` where call to `.cloned()` can be postponed. + +### Why is this bad? +It's often inefficient to clone all elements of an iterator, when eventually, only some +of them will be consumed. + +### Known Problems +This `lint` removes the side of effect of cloning items in the iterator. +A code that relies on that side-effect could fail. + +### Examples +``` +vec.iter().cloned().take(10); +vec.iter().cloned().last(); +``` + +Use instead: +``` +vec.iter().take(10).cloned(); +vec.iter().last().cloned(); +``` \ No newline at end of file diff --git a/src/docs/iter_skip_next.txt b/src/docs/iter_skip_next.txt new file mode 100644 index 000000000000..da226b041cf2 --- /dev/null +++ b/src/docs/iter_skip_next.txt @@ -0,0 +1,18 @@ +### What it does +Checks for use of `.skip(x).next()` on iterators. + +### Why is this bad? +`.nth(x)` is cleaner + +### Example +``` +let some_vec = vec![0, 1, 2, 3]; +let bad_vec = some_vec.iter().skip(3).next(); +let bad_slice = &some_vec[..].iter().skip(3).next(); +``` +The correct use would be: +``` +let some_vec = vec![0, 1, 2, 3]; +let bad_vec = some_vec.iter().nth(3); +let bad_slice = &some_vec[..].iter().nth(3); +``` \ No newline at end of file diff --git a/src/docs/iter_with_drain.txt b/src/docs/iter_with_drain.txt new file mode 100644 index 000000000000..2c52b99f7a5c --- /dev/null +++ b/src/docs/iter_with_drain.txt @@ -0,0 +1,16 @@ +### What it does +Checks for use of `.drain(..)` on `Vec` and `VecDeque` for iteration. + +### Why is this bad? +`.into_iter()` is simpler with better performance. + +### Example +``` +let mut foo = vec![0, 1, 2, 3]; +let bar: HashSet = foo.drain(..).collect(); +``` +Use instead: +``` +let foo = vec![0, 1, 2, 3]; +let bar: HashSet = foo.into_iter().collect(); +``` \ No newline at end of file diff --git a/src/docs/iterator_step_by_zero.txt b/src/docs/iterator_step_by_zero.txt new file mode 100644 index 000000000000..73ecc99acfcb --- /dev/null +++ b/src/docs/iterator_step_by_zero.txt @@ -0,0 +1,13 @@ +### What it does +Checks for calling `.step_by(0)` on iterators which panics. + +### Why is this bad? +This very much looks like an oversight. Use `panic!()` instead if you +actually intend to panic. + +### Example +``` +for x in (0..100).step_by(0) { + //.. +} +``` \ No newline at end of file diff --git a/src/docs/just_underscores_and_digits.txt b/src/docs/just_underscores_and_digits.txt new file mode 100644 index 000000000000..a8790bcf25be --- /dev/null +++ b/src/docs/just_underscores_and_digits.txt @@ -0,0 +1,14 @@ +### What it does +Checks if you have variables whose name consists of just +underscores and digits. + +### Why is this bad? +It's hard to memorize what a variable means without a +descriptive name. + +### Example +``` +let _1 = 1; +let ___1 = 1; +let __1___2 = 11; +``` \ No newline at end of file diff --git a/src/docs/large_const_arrays.txt b/src/docs/large_const_arrays.txt new file mode 100644 index 000000000000..71f67854f2a1 --- /dev/null +++ b/src/docs/large_const_arrays.txt @@ -0,0 +1,17 @@ +### What it does +Checks for large `const` arrays that should +be defined as `static` instead. + +### Why is this bad? +Performance: const variables are inlined upon use. +Static items result in only one instance and has a fixed location in memory. + +### Example +``` +pub const a = [0u32; 1_000_000]; +``` + +Use instead: +``` +pub static a = [0u32; 1_000_000]; +``` \ No newline at end of file diff --git a/src/docs/large_digit_groups.txt b/src/docs/large_digit_groups.txt new file mode 100644 index 000000000000..f60b19345af4 --- /dev/null +++ b/src/docs/large_digit_groups.txt @@ -0,0 +1,12 @@ +### What it does +Warns if the digits of an integral or floating-point +constant are grouped into groups that +are too large. + +### Why is this bad? +Negatively impacts readability. + +### Example +``` +let x: u64 = 6186491_8973511; +``` \ No newline at end of file diff --git a/src/docs/large_enum_variant.txt b/src/docs/large_enum_variant.txt new file mode 100644 index 000000000000..787e8e027e12 --- /dev/null +++ b/src/docs/large_enum_variant.txt @@ -0,0 +1,40 @@ +### What it does +Checks for large size differences between variants on +`enum`s. + +### Why is this bad? +Enum size is bounded by the largest variant. Having a +large variant can penalize the memory layout of that enum. + +### Known problems +This lint obviously cannot take the distribution of +variants in your running program into account. It is possible that the +smaller variants make up less than 1% of all instances, in which case +the overhead is negligible and the boxing is counter-productive. Always +measure the change this lint suggests. + +For types that implement `Copy`, the suggestion to `Box` a variant's +data would require removing the trait impl. The types can of course +still be `Clone`, but that is worse ergonomically. Depending on the +use case it may be possible to store the large data in an auxiliary +structure (e.g. Arena or ECS). + +The lint will ignore generic types if the layout depends on the +generics, even if the size difference will be large anyway. + +### Example +``` +enum Test { + A(i32), + B([i32; 8000]), +} +``` + +Use instead: +``` +// Possibly better +enum Test2 { + A(i32), + B(Box<[i32; 8000]>), +} +``` \ No newline at end of file diff --git a/src/docs/large_include_file.txt b/src/docs/large_include_file.txt new file mode 100644 index 000000000000..b2a54bd2eb5c --- /dev/null +++ b/src/docs/large_include_file.txt @@ -0,0 +1,21 @@ +### What it does +Checks for the inclusion of large files via `include_bytes!()` +and `include_str!()` + +### Why is this bad? +Including large files can increase the size of the binary + +### Example +``` +let included_str = include_str!("very_large_file.txt"); +let included_bytes = include_bytes!("very_large_file.txt"); +``` + +Use instead: +``` +use std::fs; + +// You can load the file at runtime +let string = fs::read_to_string("very_large_file.txt")?; +let bytes = fs::read("very_large_file.txt")?; +``` \ No newline at end of file diff --git a/src/docs/large_stack_arrays.txt b/src/docs/large_stack_arrays.txt new file mode 100644 index 000000000000..4a6f34785b0e --- /dev/null +++ b/src/docs/large_stack_arrays.txt @@ -0,0 +1,10 @@ +### What it does +Checks for local arrays that may be too large. + +### Why is this bad? +Large local arrays may cause stack overflow. + +### Example +``` +let a = [0u32; 1_000_000]; +``` \ No newline at end of file diff --git a/src/docs/large_types_passed_by_value.txt b/src/docs/large_types_passed_by_value.txt new file mode 100644 index 000000000000..bca07f3ac61b --- /dev/null +++ b/src/docs/large_types_passed_by_value.txt @@ -0,0 +1,24 @@ +### What it does +Checks for functions taking arguments by value, where +the argument type is `Copy` and large enough to be worth considering +passing by reference. Does not trigger if the function is being exported, +because that might induce API breakage, if the parameter is declared as mutable, +or if the argument is a `self`. + +### Why is this bad? +Arguments passed by value might result in an unnecessary +shallow copy, taking up more space in the stack and requiring a call to +`memcpy`, which can be expensive. + +### Example +``` +#[derive(Clone, Copy)] +struct TooLarge([u8; 2048]); + +fn foo(v: TooLarge) {} +``` + +Use instead: +``` +fn foo(v: &TooLarge) {} +``` \ No newline at end of file diff --git a/src/docs/len_without_is_empty.txt b/src/docs/len_without_is_empty.txt new file mode 100644 index 000000000000..47a2e8575228 --- /dev/null +++ b/src/docs/len_without_is_empty.txt @@ -0,0 +1,19 @@ +### What it does +Checks for items that implement `.len()` but not +`.is_empty()`. + +### Why is this bad? +It is good custom to have both methods, because for +some data structures, asking about the length will be a costly operation, +whereas `.is_empty()` can usually answer in constant time. Also it used to +lead to false positives on the [`len_zero`](#len_zero) lint – currently that +lint will ignore such entities. + +### Example +``` +impl X { + pub fn len(&self) -> usize { + .. + } +} +``` \ No newline at end of file diff --git a/src/docs/len_zero.txt b/src/docs/len_zero.txt new file mode 100644 index 000000000000..664124bd391d --- /dev/null +++ b/src/docs/len_zero.txt @@ -0,0 +1,28 @@ +### What it does +Checks for getting the length of something via `.len()` +just to compare to zero, and suggests using `.is_empty()` where applicable. + +### Why is this bad? +Some structures can answer `.is_empty()` much faster +than calculating their length. So it is good to get into the habit of using +`.is_empty()`, and having it is cheap. +Besides, it makes the intent clearer than a manual comparison in some contexts. + +### Example +``` +if x.len() == 0 { + .. +} +if y.len() != 0 { + .. +} +``` +instead use +``` +if x.is_empty() { + .. +} +if !y.is_empty() { + .. +} +``` \ No newline at end of file diff --git a/src/docs/let_and_return.txt b/src/docs/let_and_return.txt new file mode 100644 index 000000000000..eba5a90ddd66 --- /dev/null +++ b/src/docs/let_and_return.txt @@ -0,0 +1,21 @@ +### What it does +Checks for `let`-bindings, which are subsequently +returned. + +### Why is this bad? +It is just extraneous code. Remove it to make your code +more rusty. + +### Example +``` +fn foo() -> String { + let x = String::new(); + x +} +``` +instead, use +``` +fn foo() -> String { + String::new() +} +``` \ No newline at end of file diff --git a/src/docs/let_underscore_drop.txt b/src/docs/let_underscore_drop.txt new file mode 100644 index 000000000000..29ce9bf50ce6 --- /dev/null +++ b/src/docs/let_underscore_drop.txt @@ -0,0 +1,29 @@ +### What it does +Checks for `let _ = ` +where expr has a type that implements `Drop` + +### Why is this bad? +This statement immediately drops the initializer +expression instead of extending its lifetime to the end of the scope, which +is often not intended. To extend the expression's lifetime to the end of the +scope, use an underscore-prefixed name instead (i.e. _var). If you want to +explicitly drop the expression, `std::mem::drop` conveys your intention +better and is less error-prone. + +### Example +``` +{ + let _ = DroppableItem; + // ^ dropped here + /* more code */ +} +``` + +Use instead: +``` +{ + let _droppable = DroppableItem; + /* more code */ + // dropped at end of scope +} +``` \ No newline at end of file diff --git a/src/docs/let_underscore_lock.txt b/src/docs/let_underscore_lock.txt new file mode 100644 index 000000000000..bd8217fb58b3 --- /dev/null +++ b/src/docs/let_underscore_lock.txt @@ -0,0 +1,20 @@ +### What it does +Checks for `let _ = sync_lock`. +This supports `mutex` and `rwlock` in `std::sync` and `parking_lot`. + +### Why is this bad? +This statement immediately drops the lock instead of +extending its lifetime to the end of the scope, which is often not intended. +To extend lock lifetime to the end of the scope, use an underscore-prefixed +name instead (i.e. _lock). If you want to explicitly drop the lock, +`std::mem::drop` conveys your intention better and is less error-prone. + +### Example +``` +let _ = mutex.lock(); +``` + +Use instead: +``` +let _lock = mutex.lock(); +``` \ No newline at end of file diff --git a/src/docs/let_underscore_must_use.txt b/src/docs/let_underscore_must_use.txt new file mode 100644 index 000000000000..270b81d9a4c4 --- /dev/null +++ b/src/docs/let_underscore_must_use.txt @@ -0,0 +1,17 @@ +### What it does +Checks for `let _ = ` where expr is `#[must_use]` + +### Why is this bad? +It's better to explicitly handle the value of a `#[must_use]` +expr + +### Example +``` +fn f() -> Result { + Ok(0) +} + +let _ = f(); +// is_ok() is marked #[must_use] +let _ = f().is_ok(); +``` \ No newline at end of file diff --git a/src/docs/let_unit_value.txt b/src/docs/let_unit_value.txt new file mode 100644 index 000000000000..bc16d5b3d81b --- /dev/null +++ b/src/docs/let_unit_value.txt @@ -0,0 +1,13 @@ +### What it does +Checks for binding a unit value. + +### Why is this bad? +A unit value cannot usefully be used anywhere. So +binding one is kind of pointless. + +### Example +``` +let x = { + 1; +}; +``` \ No newline at end of file diff --git a/src/docs/linkedlist.txt b/src/docs/linkedlist.txt new file mode 100644 index 000000000000..986ff1369e3c --- /dev/null +++ b/src/docs/linkedlist.txt @@ -0,0 +1,32 @@ +### What it does +Checks for usage of any `LinkedList`, suggesting to use a +`Vec` or a `VecDeque` (formerly called `RingBuf`). + +### Why is this bad? +Gankro says: + +> The TL;DR of `LinkedList` is that it's built on a massive amount of +pointers and indirection. +> It wastes memory, it has terrible cache locality, and is all-around slow. +`RingBuf`, while +> "only" amortized for push/pop, should be faster in the general case for +almost every possible +> workload, and isn't even amortized at all if you can predict the capacity +you need. +> +> `LinkedList`s are only really good if you're doing a lot of merging or +splitting of lists. +> This is because they can just mangle some pointers instead of actually +copying the data. Even +> if you're doing a lot of insertion in the middle of the list, `RingBuf` +can still be better +> because of how expensive it is to seek to the middle of a `LinkedList`. + +### Known problems +False positives – the instances where using a +`LinkedList` makes sense are few and far between, but they can still happen. + +### Example +``` +let x: LinkedList = LinkedList::new(); +``` \ No newline at end of file diff --git a/src/docs/lossy_float_literal.txt b/src/docs/lossy_float_literal.txt new file mode 100644 index 000000000000..bbcb9115ea62 --- /dev/null +++ b/src/docs/lossy_float_literal.txt @@ -0,0 +1,18 @@ +### What it does +Checks for whole number float literals that +cannot be represented as the underlying type without loss. + +### Why is this bad? +Rust will silently lose precision during +conversion to a float. + +### Example +``` +let _: f32 = 16_777_217.0; // 16_777_216.0 +``` + +Use instead: +``` +let _: f32 = 16_777_216.0; +let _: f64 = 16_777_217.0; +``` \ No newline at end of file diff --git a/src/docs/macro_use_imports.txt b/src/docs/macro_use_imports.txt new file mode 100644 index 000000000000..6a8180a60bc6 --- /dev/null +++ b/src/docs/macro_use_imports.txt @@ -0,0 +1,12 @@ +### What it does +Checks for `#[macro_use] use...`. + +### Why is this bad? +Since the Rust 2018 edition you can import +macro's directly, this is considered idiomatic. + +### Example +``` +#[macro_use] +use some_macro; +``` \ No newline at end of file diff --git a/src/docs/main_recursion.txt b/src/docs/main_recursion.txt new file mode 100644 index 000000000000..e49becd15bbd --- /dev/null +++ b/src/docs/main_recursion.txt @@ -0,0 +1,13 @@ +### What it does +Checks for recursion using the entrypoint. + +### Why is this bad? +Apart from special setups (which we could detect following attributes like #![no_std]), +recursing into main() seems like an unintuitive anti-pattern we should be able to detect. + +### Example +``` +fn main() { + main(); +} +``` \ No newline at end of file diff --git a/src/docs/manual_assert.txt b/src/docs/manual_assert.txt new file mode 100644 index 000000000000..93653081a2ce --- /dev/null +++ b/src/docs/manual_assert.txt @@ -0,0 +1,18 @@ +### What it does +Detects `if`-then-`panic!` that can be replaced with `assert!`. + +### Why is this bad? +`assert!` is simpler than `if`-then-`panic!`. + +### Example +``` +let sad_people: Vec<&str> = vec![]; +if !sad_people.is_empty() { + panic!("there are sad people: {:?}", sad_people); +} +``` +Use instead: +``` +let sad_people: Vec<&str> = vec![]; +assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people); +``` \ No newline at end of file diff --git a/src/docs/manual_async_fn.txt b/src/docs/manual_async_fn.txt new file mode 100644 index 000000000000..d01ac402e0d2 --- /dev/null +++ b/src/docs/manual_async_fn.txt @@ -0,0 +1,16 @@ +### What it does +It checks for manual implementations of `async` functions. + +### Why is this bad? +It's more idiomatic to use the dedicated syntax. + +### Example +``` +use std::future::Future; + +fn foo() -> impl Future { async { 42 } } +``` +Use instead: +``` +async fn foo() -> i32 { 42 } +``` \ No newline at end of file diff --git a/src/docs/manual_bits.txt b/src/docs/manual_bits.txt new file mode 100644 index 000000000000..b96c2eb151d4 --- /dev/null +++ b/src/docs/manual_bits.txt @@ -0,0 +1,15 @@ +### What it does +Checks for uses of `std::mem::size_of::() * 8` when +`T::BITS` is available. + +### Why is this bad? +Can be written as the shorter `T::BITS`. + +### Example +``` +std::mem::size_of::() * 8; +``` +Use instead: +``` +usize::BITS as usize; +``` \ No newline at end of file diff --git a/src/docs/manual_filter_map.txt b/src/docs/manual_filter_map.txt new file mode 100644 index 000000000000..3b6860798ff5 --- /dev/null +++ b/src/docs/manual_filter_map.txt @@ -0,0 +1,19 @@ +### What it does +Checks for usage of `_.filter(_).map(_)` that can be written more simply +as `filter_map(_)`. + +### Why is this bad? +Redundant code in the `filter` and `map` operations is poor style and +less performant. + +### Example +``` +(0_i32..10) + .filter(|n| n.checked_add(1).is_some()) + .map(|n| n.checked_add(1).unwrap()); +``` + +Use instead: +``` +(0_i32..10).filter_map(|n| n.checked_add(1)); +``` \ No newline at end of file diff --git a/src/docs/manual_find.txt b/src/docs/manual_find.txt new file mode 100644 index 000000000000..e3e07a2771f9 --- /dev/null +++ b/src/docs/manual_find.txt @@ -0,0 +1,24 @@ +### What it does +Check for manual implementations of Iterator::find + +### Why is this bad? +It doesn't affect performance, but using `find` is shorter and easier to read. + +### Example + +``` +fn example(arr: Vec) -> Option { + for el in arr { + if el == 1 { + return Some(el); + } + } + None +} +``` +Use instead: +``` +fn example(arr: Vec) -> Option { + arr.into_iter().find(|&el| el == 1) +} +``` \ No newline at end of file diff --git a/src/docs/manual_find_map.txt b/src/docs/manual_find_map.txt new file mode 100644 index 000000000000..83b22060c0e1 --- /dev/null +++ b/src/docs/manual_find_map.txt @@ -0,0 +1,19 @@ +### What it does +Checks for usage of `_.find(_).map(_)` that can be written more simply +as `find_map(_)`. + +### Why is this bad? +Redundant code in the `find` and `map` operations is poor style and +less performant. + +### Example +``` +(0_i32..10) + .find(|n| n.checked_add(1).is_some()) + .map(|n| n.checked_add(1).unwrap()); +``` + +Use instead: +``` +(0_i32..10).find_map(|n| n.checked_add(1)); +``` \ No newline at end of file diff --git a/src/docs/manual_flatten.txt b/src/docs/manual_flatten.txt new file mode 100644 index 000000000000..62d5f3ec9357 --- /dev/null +++ b/src/docs/manual_flatten.txt @@ -0,0 +1,25 @@ +### What it does +Check for unnecessary `if let` usage in a for loop +where only the `Some` or `Ok` variant of the iterator element is used. + +### Why is this bad? +It is verbose and can be simplified +by first calling the `flatten` method on the `Iterator`. + +### Example + +``` +let x = vec![Some(1), Some(2), Some(3)]; +for n in x { + if let Some(n) = n { + println!("{}", n); + } +} +``` +Use instead: +``` +let x = vec![Some(1), Some(2), Some(3)]; +for n in x.into_iter().flatten() { + println!("{}", n); +} +``` \ No newline at end of file diff --git a/src/docs/manual_instant_elapsed.txt b/src/docs/manual_instant_elapsed.txt new file mode 100644 index 000000000000..dde3d493c70d --- /dev/null +++ b/src/docs/manual_instant_elapsed.txt @@ -0,0 +1,21 @@ +### What it does +Lints subtraction between `Instant::now()` and another `Instant`. + +### Why is this bad? +It is easy to accidentally write `prev_instant - Instant::now()`, which will always be 0ns +as `Instant` subtraction saturates. + +`prev_instant.elapsed()` also more clearly signals intention. + +### Example +``` +use std::time::Instant; +let prev_instant = Instant::now(); +let duration = Instant::now() - prev_instant; +``` +Use instead: +``` +use std::time::Instant; +let prev_instant = Instant::now(); +let duration = prev_instant.elapsed(); +``` \ No newline at end of file diff --git a/src/docs/manual_map.txt b/src/docs/manual_map.txt new file mode 100644 index 000000000000..7f68ccd1037e --- /dev/null +++ b/src/docs/manual_map.txt @@ -0,0 +1,17 @@ +### What it does +Checks for usages of `match` which could be implemented using `map` + +### Why is this bad? +Using the `map` method is clearer and more concise. + +### Example +``` +match Some(0) { + Some(x) => Some(x + 1), + None => None, +}; +``` +Use instead: +``` +Some(0).map(|x| x + 1); +``` \ No newline at end of file diff --git a/src/docs/manual_memcpy.txt b/src/docs/manual_memcpy.txt new file mode 100644 index 000000000000..d7690bf25866 --- /dev/null +++ b/src/docs/manual_memcpy.txt @@ -0,0 +1,18 @@ +### What it does +Checks for for-loops that manually copy items between +slices that could be optimized by having a memcpy. + +### Why is this bad? +It is not as fast as a memcpy. + +### Example +``` +for i in 0..src.len() { + dst[i + 64] = src[i]; +} +``` + +Use instead: +``` +dst[64..(src.len() + 64)].clone_from_slice(&src[..]); +``` \ No newline at end of file diff --git a/src/docs/manual_non_exhaustive.txt b/src/docs/manual_non_exhaustive.txt new file mode 100644 index 000000000000..fb021393bd7c --- /dev/null +++ b/src/docs/manual_non_exhaustive.txt @@ -0,0 +1,41 @@ +### What it does +Checks for manual implementations of the non-exhaustive pattern. + +### Why is this bad? +Using the #[non_exhaustive] attribute expresses better the intent +and allows possible optimizations when applied to enums. + +### Example +``` +struct S { + pub a: i32, + pub b: i32, + _c: (), +} + +enum E { + A, + B, + #[doc(hidden)] + _C, +} + +struct T(pub i32, pub i32, ()); +``` +Use instead: +``` +#[non_exhaustive] +struct S { + pub a: i32, + pub b: i32, +} + +#[non_exhaustive] +enum E { + A, + B, +} + +#[non_exhaustive] +struct T(pub i32, pub i32); +``` \ No newline at end of file diff --git a/src/docs/manual_ok_or.txt b/src/docs/manual_ok_or.txt new file mode 100644 index 000000000000..5accdf25965a --- /dev/null +++ b/src/docs/manual_ok_or.txt @@ -0,0 +1,19 @@ +### What it does + +Finds patterns that reimplement `Option::ok_or`. + +### Why is this bad? + +Concise code helps focusing on behavior instead of boilerplate. + +### Examples +``` +let foo: Option = None; +foo.map_or(Err("error"), |v| Ok(v)); +``` + +Use instead: +``` +let foo: Option = None; +foo.ok_or("error"); +``` \ No newline at end of file diff --git a/src/docs/manual_range_contains.txt b/src/docs/manual_range_contains.txt new file mode 100644 index 000000000000..0ade26951d38 --- /dev/null +++ b/src/docs/manual_range_contains.txt @@ -0,0 +1,19 @@ +### What it does +Checks for expressions like `x >= 3 && x < 8` that could +be more readably expressed as `(3..8).contains(x)`. + +### Why is this bad? +`contains` expresses the intent better and has less +failure modes (such as fencepost errors or using `||` instead of `&&`). + +### Example +``` +// given +let x = 6; + +assert!(x >= 3 && x < 8); +``` +Use instead: +``` +assert!((3..8).contains(&x)); +``` \ No newline at end of file diff --git a/src/docs/manual_rem_euclid.txt b/src/docs/manual_rem_euclid.txt new file mode 100644 index 000000000000..d3bb8c61304e --- /dev/null +++ b/src/docs/manual_rem_euclid.txt @@ -0,0 +1,17 @@ +### What it does +Checks for an expression like `((x % 4) + 4) % 4` which is a common manual reimplementation +of `x.rem_euclid(4)`. + +### Why is this bad? +It's simpler and more readable. + +### Example +``` +let x: i32 = 24; +let rem = ((x % 4) + 4) % 4; +``` +Use instead: +``` +let x: i32 = 24; +let rem = x.rem_euclid(4); +``` \ No newline at end of file diff --git a/src/docs/manual_retain.txt b/src/docs/manual_retain.txt new file mode 100644 index 000000000000..cd4f65a93fc3 --- /dev/null +++ b/src/docs/manual_retain.txt @@ -0,0 +1,15 @@ +### What it does +Checks for code to be replaced by `.retain()`. +### Why is this bad? +`.retain()` is simpler and avoids needless allocation. +### Example +``` +let mut vec = vec![0, 1, 2]; +vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect(); +vec = vec.into_iter().filter(|x| x % 2 == 0).collect(); +``` +Use instead: +``` +let mut vec = vec![0, 1, 2]; +vec.retain(|x| x % 2 == 0); +``` \ No newline at end of file diff --git a/src/docs/manual_saturating_arithmetic.txt b/src/docs/manual_saturating_arithmetic.txt new file mode 100644 index 000000000000..d9f5d3d11871 --- /dev/null +++ b/src/docs/manual_saturating_arithmetic.txt @@ -0,0 +1,18 @@ +### What it does +Checks for `.checked_add/sub(x).unwrap_or(MAX/MIN)`. + +### Why is this bad? +These can be written simply with `saturating_add/sub` methods. + +### Example +``` +let add = x.checked_add(y).unwrap_or(u32::MAX); +let sub = x.checked_sub(y).unwrap_or(u32::MIN); +``` + +can be written using dedicated methods for saturating addition/subtraction as: + +``` +let add = x.saturating_add(y); +let sub = x.saturating_sub(y); +``` \ No newline at end of file diff --git a/src/docs/manual_split_once.txt b/src/docs/manual_split_once.txt new file mode 100644 index 000000000000..291ae447de08 --- /dev/null +++ b/src/docs/manual_split_once.txt @@ -0,0 +1,29 @@ +### What it does +Checks for usages of `str::splitn(2, _)` + +### Why is this bad? +`split_once` is both clearer in intent and slightly more efficient. + +### Example +``` +let s = "key=value=add"; +let (key, value) = s.splitn(2, '=').next_tuple()?; +let value = s.splitn(2, '=').nth(1)?; + +let mut parts = s.splitn(2, '='); +let key = parts.next()?; +let value = parts.next()?; +``` + +Use instead: +``` +let s = "key=value=add"; +let (key, value) = s.split_once('=')?; +let value = s.split_once('=')?.1; + +let (key, value) = s.split_once('=')?; +``` + +### Limitations +The multiple statement variant currently only detects `iter.next()?`/`iter.next().unwrap()` +in two separate `let` statements that immediately follow the `splitn()` \ No newline at end of file diff --git a/src/docs/manual_str_repeat.txt b/src/docs/manual_str_repeat.txt new file mode 100644 index 000000000000..1d4a7a48e203 --- /dev/null +++ b/src/docs/manual_str_repeat.txt @@ -0,0 +1,15 @@ +### What it does +Checks for manual implementations of `str::repeat` + +### Why is this bad? +These are both harder to read, as well as less performant. + +### Example +``` +let x: String = std::iter::repeat('x').take(10).collect(); +``` + +Use instead: +``` +let x: String = "x".repeat(10); +``` \ No newline at end of file diff --git a/src/docs/manual_string_new.txt b/src/docs/manual_string_new.txt new file mode 100644 index 000000000000..4cbc43f8f843 --- /dev/null +++ b/src/docs/manual_string_new.txt @@ -0,0 +1,20 @@ +### What it does + +Checks for usage of `""` to create a `String`, such as `"".to_string()`, `"".to_owned()`, +`String::from("")` and others. + +### Why is this bad? + +Different ways of creating an empty string makes your code less standardized, which can +be confusing. + +### Example +``` +let a = "".to_string(); +let b: String = "".into(); +``` +Use instead: +``` +let a = String::new(); +let b = String::new(); +``` \ No newline at end of file diff --git a/src/docs/manual_strip.txt b/src/docs/manual_strip.txt new file mode 100644 index 000000000000..f32d8e7a09bb --- /dev/null +++ b/src/docs/manual_strip.txt @@ -0,0 +1,24 @@ +### What it does +Suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing using +the pattern's length. + +### Why is this bad? +Using `str:strip_{prefix,suffix}` is safer and may have better performance as there is no +slicing which may panic and the compiler does not need to insert this panic code. It is +also sometimes more readable as it removes the need for duplicating or storing the pattern +used by `str::{starts,ends}_with` and in the slicing. + +### Example +``` +let s = "hello, world!"; +if s.starts_with("hello, ") { + assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!"); +} +``` +Use instead: +``` +let s = "hello, world!"; +if let Some(end) = s.strip_prefix("hello, ") { + assert_eq!(end.to_uppercase(), "WORLD!"); +} +``` \ No newline at end of file diff --git a/src/docs/manual_swap.txt b/src/docs/manual_swap.txt new file mode 100644 index 000000000000..bd9526288e35 --- /dev/null +++ b/src/docs/manual_swap.txt @@ -0,0 +1,22 @@ +### What it does +Checks for manual swapping. + +### Why is this bad? +The `std::mem::swap` function exposes the intent better +without deinitializing or copying either variable. + +### Example +``` +let mut a = 42; +let mut b = 1337; + +let t = b; +b = a; +a = t; +``` +Use std::mem::swap(): +``` +let mut a = 1; +let mut b = 2; +std::mem::swap(&mut a, &mut b); +``` \ No newline at end of file diff --git a/src/docs/manual_unwrap_or.txt b/src/docs/manual_unwrap_or.txt new file mode 100644 index 000000000000..1fd7d831bfca --- /dev/null +++ b/src/docs/manual_unwrap_or.txt @@ -0,0 +1,20 @@ +### What it does +Finds patterns that reimplement `Option::unwrap_or` or `Result::unwrap_or`. + +### Why is this bad? +Concise code helps focusing on behavior instead of boilerplate. + +### Example +``` +let foo: Option = None; +match foo { + Some(v) => v, + None => 1, +}; +``` + +Use instead: +``` +let foo: Option = None; +foo.unwrap_or(1); +``` \ No newline at end of file diff --git a/src/docs/many_single_char_names.txt b/src/docs/many_single_char_names.txt new file mode 100644 index 000000000000..55ee5da55574 --- /dev/null +++ b/src/docs/many_single_char_names.txt @@ -0,0 +1,12 @@ +### What it does +Checks for too many variables whose name consists of a +single character. + +### Why is this bad? +It's hard to memorize what a variable means without a +descriptive name. + +### Example +``` +let (a, b, c, d, e, f, g) = (...); +``` \ No newline at end of file diff --git a/src/docs/map_clone.txt b/src/docs/map_clone.txt new file mode 100644 index 000000000000..3ee27f072ef3 --- /dev/null +++ b/src/docs/map_clone.txt @@ -0,0 +1,22 @@ +### What it does +Checks for usage of `map(|x| x.clone())` or +dereferencing closures for `Copy` types, on `Iterator` or `Option`, +and suggests `cloned()` or `copied()` instead + +### Why is this bad? +Readability, this can be written more concisely + +### Example +``` +let x = vec![42, 43]; +let y = x.iter(); +let z = y.map(|i| *i); +``` + +The correct use would be: + +``` +let x = vec![42, 43]; +let y = x.iter(); +let z = y.cloned(); +``` \ No newline at end of file diff --git a/src/docs/map_collect_result_unit.txt b/src/docs/map_collect_result_unit.txt new file mode 100644 index 000000000000..9b720612495c --- /dev/null +++ b/src/docs/map_collect_result_unit.txt @@ -0,0 +1,14 @@ +### What it does +Checks for usage of `_.map(_).collect::()`. + +### Why is this bad? +Using `try_for_each` instead is more readable and idiomatic. + +### Example +``` +(0..3).map(|t| Err(t)).collect::>(); +``` +Use instead: +``` +(0..3).try_for_each(|t| Err(t)); +``` \ No newline at end of file diff --git a/src/docs/map_entry.txt b/src/docs/map_entry.txt new file mode 100644 index 000000000000..20dba1798d0d --- /dev/null +++ b/src/docs/map_entry.txt @@ -0,0 +1,28 @@ +### What it does +Checks for uses of `contains_key` + `insert` on `HashMap` +or `BTreeMap`. + +### Why is this bad? +Using `entry` is more efficient. + +### Known problems +The suggestion may have type inference errors in some cases. e.g. +``` +let mut map = std::collections::HashMap::new(); +let _ = if !map.contains_key(&0) { + map.insert(0, 0) +} else { + None +}; +``` + +### Example +``` +if !map.contains_key(&k) { + map.insert(k, v); +} +``` +Use instead: +``` +map.entry(k).or_insert(v); +``` \ No newline at end of file diff --git a/src/docs/map_err_ignore.txt b/src/docs/map_err_ignore.txt new file mode 100644 index 000000000000..2606c13a7afd --- /dev/null +++ b/src/docs/map_err_ignore.txt @@ -0,0 +1,93 @@ +### What it does +Checks for instances of `map_err(|_| Some::Enum)` + +### Why is this bad? +This `map_err` throws away the original error rather than allowing the enum to contain and report the cause of the error + +### Example +Before: +``` +use std::fmt; + +#[derive(Debug)] +enum Error { + Indivisible, + Remainder(u8), +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::Indivisible => write!(f, "could not divide input by three"), + Error::Remainder(remainder) => write!( + f, + "input is not divisible by three, remainder = {}", + remainder + ), + } + } +} + +impl std::error::Error for Error {} + +fn divisible_by_3(input: &str) -> Result<(), Error> { + input + .parse::() + .map_err(|_| Error::Indivisible) + .map(|v| v % 3) + .and_then(|remainder| { + if remainder == 0 { + Ok(()) + } else { + Err(Error::Remainder(remainder as u8)) + } + }) +} + ``` + + After: + ```rust +use std::{fmt, num::ParseIntError}; + +#[derive(Debug)] +enum Error { + Indivisible(ParseIntError), + Remainder(u8), +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::Indivisible(_) => write!(f, "could not divide input by three"), + Error::Remainder(remainder) => write!( + f, + "input is not divisible by three, remainder = {}", + remainder + ), + } + } +} + +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Error::Indivisible(source) => Some(source), + _ => None, + } + } +} + +fn divisible_by_3(input: &str) -> Result<(), Error> { + input + .parse::() + .map_err(Error::Indivisible) + .map(|v| v % 3) + .and_then(|remainder| { + if remainder == 0 { + Ok(()) + } else { + Err(Error::Remainder(remainder as u8)) + } + }) +} +``` \ No newline at end of file diff --git a/src/docs/map_flatten.txt b/src/docs/map_flatten.txt new file mode 100644 index 000000000000..73c0e51407f2 --- /dev/null +++ b/src/docs/map_flatten.txt @@ -0,0 +1,21 @@ +### What it does +Checks for usage of `_.map(_).flatten(_)` on `Iterator` and `Option` + +### Why is this bad? +Readability, this can be written more concisely as +`_.flat_map(_)` for `Iterator` or `_.and_then(_)` for `Option` + +### Example +``` +let vec = vec![vec![1]]; +let opt = Some(5); + +vec.iter().map(|x| x.iter()).flatten(); +opt.map(|x| Some(x * 2)).flatten(); +``` + +Use instead: +``` +vec.iter().flat_map(|x| x.iter()); +opt.and_then(|x| Some(x * 2)); +``` \ No newline at end of file diff --git a/src/docs/map_identity.txt b/src/docs/map_identity.txt new file mode 100644 index 000000000000..e2e7af0bed9b --- /dev/null +++ b/src/docs/map_identity.txt @@ -0,0 +1,16 @@ +### What it does +Checks for instances of `map(f)` where `f` is the identity function. + +### Why is this bad? +It can be written more concisely without the call to `map`. + +### Example +``` +let x = [1, 2, 3]; +let y: Vec<_> = x.iter().map(|x| x).map(|x| 2*x).collect(); +``` +Use instead: +``` +let x = [1, 2, 3]; +let y: Vec<_> = x.iter().map(|x| 2*x).collect(); +``` \ No newline at end of file diff --git a/src/docs/map_unwrap_or.txt b/src/docs/map_unwrap_or.txt new file mode 100644 index 000000000000..485b29f01b10 --- /dev/null +++ b/src/docs/map_unwrap_or.txt @@ -0,0 +1,22 @@ +### What it does +Checks for usage of `option.map(_).unwrap_or(_)` or `option.map(_).unwrap_or_else(_)` or +`result.map(_).unwrap_or_else(_)`. + +### Why is this bad? +Readability, these can be written more concisely (resp.) as +`option.map_or(_, _)`, `option.map_or_else(_, _)` and `result.map_or_else(_, _)`. + +### Known problems +The order of the arguments is not in execution order + +### Examples +``` +option.map(|a| a + 1).unwrap_or(0); +result.map(|a| a + 1).unwrap_or_else(some_function); +``` + +Use instead: +``` +option.map_or(0, |a| a + 1); +result.map_or_else(some_function, |a| a + 1); +``` \ No newline at end of file diff --git a/src/docs/match_as_ref.txt b/src/docs/match_as_ref.txt new file mode 100644 index 000000000000..5e5f3d645a4e --- /dev/null +++ b/src/docs/match_as_ref.txt @@ -0,0 +1,23 @@ +### What it does +Checks for match which is used to add a reference to an +`Option` value. + +### Why is this bad? +Using `as_ref()` or `as_mut()` instead is shorter. + +### Example +``` +let x: Option<()> = None; + +let r: Option<&()> = match x { + None => None, + Some(ref v) => Some(v), +}; +``` + +Use instead: +``` +let x: Option<()> = None; + +let r: Option<&()> = x.as_ref(); +``` \ No newline at end of file diff --git a/src/docs/match_bool.txt b/src/docs/match_bool.txt new file mode 100644 index 000000000000..96f9e1f8b7d1 --- /dev/null +++ b/src/docs/match_bool.txt @@ -0,0 +1,24 @@ +### What it does +Checks for matches where match expression is a `bool`. It +suggests to replace the expression with an `if...else` block. + +### Why is this bad? +It makes the code less readable. + +### Example +``` +let condition: bool = true; +match condition { + true => foo(), + false => bar(), +} +``` +Use if/else instead: +``` +let condition: bool = true; +if condition { + foo(); +} else { + bar(); +} +``` \ No newline at end of file diff --git a/src/docs/match_like_matches_macro.txt b/src/docs/match_like_matches_macro.txt new file mode 100644 index 000000000000..643e2ddc97ba --- /dev/null +++ b/src/docs/match_like_matches_macro.txt @@ -0,0 +1,32 @@ +### What it does +Checks for `match` or `if let` expressions producing a +`bool` that could be written using `matches!` + +### Why is this bad? +Readability and needless complexity. + +### Known problems +This lint falsely triggers, if there are arms with +`cfg` attributes that remove an arm evaluating to `false`. + +### Example +``` +let x = Some(5); + +let a = match x { + Some(0) => true, + _ => false, +}; + +let a = if let Some(0) = x { + true +} else { + false +}; +``` + +Use instead: +``` +let x = Some(5); +let a = matches!(x, Some(0)); +``` \ No newline at end of file diff --git a/src/docs/match_on_vec_items.txt b/src/docs/match_on_vec_items.txt new file mode 100644 index 000000000000..981d18d0f9ed --- /dev/null +++ b/src/docs/match_on_vec_items.txt @@ -0,0 +1,29 @@ +### What it does +Checks for `match vec[idx]` or `match vec[n..m]`. + +### Why is this bad? +This can panic at runtime. + +### Example +``` +let arr = vec![0, 1, 2, 3]; +let idx = 1; + +match arr[idx] { + 0 => println!("{}", 0), + 1 => println!("{}", 3), + _ => {}, +} +``` + +Use instead: +``` +let arr = vec![0, 1, 2, 3]; +let idx = 1; + +match arr.get(idx) { + Some(0) => println!("{}", 0), + Some(1) => println!("{}", 3), + _ => {}, +} +``` \ No newline at end of file diff --git a/src/docs/match_overlapping_arm.txt b/src/docs/match_overlapping_arm.txt new file mode 100644 index 000000000000..841c091bd5ca --- /dev/null +++ b/src/docs/match_overlapping_arm.txt @@ -0,0 +1,16 @@ +### What it does +Checks for overlapping match arms. + +### Why is this bad? +It is likely to be an error and if not, makes the code +less obvious. + +### Example +``` +let x = 5; +match x { + 1..=10 => println!("1 ... 10"), + 5..=15 => println!("5 ... 15"), + _ => (), +} +``` \ No newline at end of file diff --git a/src/docs/match_ref_pats.txt b/src/docs/match_ref_pats.txt new file mode 100644 index 000000000000..b1d902995097 --- /dev/null +++ b/src/docs/match_ref_pats.txt @@ -0,0 +1,26 @@ +### What it does +Checks for matches where all arms match a reference, +suggesting to remove the reference and deref the matched expression +instead. It also checks for `if let &foo = bar` blocks. + +### Why is this bad? +It just makes the code less readable. That reference +destructuring adds nothing to the code. + +### Example +``` +match x { + &A(ref y) => foo(y), + &B => bar(), + _ => frob(&x), +} +``` + +Use instead: +``` +match *x { + A(ref y) => foo(y), + B => bar(), + _ => frob(x), +} +``` \ No newline at end of file diff --git a/src/docs/match_result_ok.txt b/src/docs/match_result_ok.txt new file mode 100644 index 000000000000..eea7c8e00f1b --- /dev/null +++ b/src/docs/match_result_ok.txt @@ -0,0 +1,27 @@ +### What it does +Checks for unnecessary `ok()` in `while let`. + +### Why is this bad? +Calling `ok()` in `while let` is unnecessary, instead match +on `Ok(pat)` + +### Example +``` +while let Some(value) = iter.next().ok() { + vec.push(value) +} + +if let Some(value) = iter.next().ok() { + vec.push(value) +} +``` +Use instead: +``` +while let Ok(value) = iter.next() { + vec.push(value) +} + +if let Ok(value) = iter.next() { + vec.push(value) +} +``` \ No newline at end of file diff --git a/src/docs/match_same_arms.txt b/src/docs/match_same_arms.txt new file mode 100644 index 000000000000..14edf12032e0 --- /dev/null +++ b/src/docs/match_same_arms.txt @@ -0,0 +1,38 @@ +### What it does +Checks for `match` with identical arm bodies. + +### Why is this bad? +This is probably a copy & paste error. If arm bodies +are the same on purpose, you can factor them +[using `|`](https://doc.rust-lang.org/book/patterns.html#multiple-patterns). + +### Known problems +False positive possible with order dependent `match` +(see issue +[#860](https://github.com/rust-lang/rust-clippy/issues/860)). + +### Example +``` +match foo { + Bar => bar(), + Quz => quz(), + Baz => bar(), // <= oops +} +``` + +This should probably be +``` +match foo { + Bar => bar(), + Quz => quz(), + Baz => baz(), // <= fixed +} +``` + +or if the original code was not a typo: +``` +match foo { + Bar | Baz => bar(), // <= shows the intent better + Quz => quz(), +} +``` \ No newline at end of file diff --git a/src/docs/match_single_binding.txt b/src/docs/match_single_binding.txt new file mode 100644 index 000000000000..67ded0bbd553 --- /dev/null +++ b/src/docs/match_single_binding.txt @@ -0,0 +1,23 @@ +### What it does +Checks for useless match that binds to only one value. + +### Why is this bad? +Readability and needless complexity. + +### Known problems + Suggested replacements may be incorrect when `match` +is actually binding temporary value, bringing a 'dropped while borrowed' error. + +### Example +``` +match (a, b) { + (c, d) => { + // useless match + } +} +``` + +Use instead: +``` +let (c, d) = (a, b); +``` \ No newline at end of file diff --git a/src/docs/match_str_case_mismatch.txt b/src/docs/match_str_case_mismatch.txt new file mode 100644 index 000000000000..19e74c2084ea --- /dev/null +++ b/src/docs/match_str_case_mismatch.txt @@ -0,0 +1,22 @@ +### What it does +Checks for `match` expressions modifying the case of a string with non-compliant arms + +### Why is this bad? +The arm is unreachable, which is likely a mistake + +### Example +``` +match &*text.to_ascii_lowercase() { + "foo" => {}, + "Bar" => {}, + _ => {}, +} +``` +Use instead: +``` +match &*text.to_ascii_lowercase() { + "foo" => {}, + "bar" => {}, + _ => {}, +} +``` \ No newline at end of file diff --git a/src/docs/match_wild_err_arm.txt b/src/docs/match_wild_err_arm.txt new file mode 100644 index 000000000000..f89b3a23a1ca --- /dev/null +++ b/src/docs/match_wild_err_arm.txt @@ -0,0 +1,16 @@ +### What it does +Checks for arm which matches all errors with `Err(_)` +and take drastic actions like `panic!`. + +### Why is this bad? +It is generally a bad practice, similar to +catching all exceptions in java with `catch(Exception)` + +### Example +``` +let x: Result = Ok(3); +match x { + Ok(_) => println!("ok"), + Err(_) => panic!("err"), +} +``` \ No newline at end of file diff --git a/src/docs/match_wildcard_for_single_variants.txt b/src/docs/match_wildcard_for_single_variants.txt new file mode 100644 index 000000000000..25559b9ecdcf --- /dev/null +++ b/src/docs/match_wildcard_for_single_variants.txt @@ -0,0 +1,27 @@ +### What it does +Checks for wildcard enum matches for a single variant. + +### Why is this bad? +New enum variants added by library updates can be missed. + +### Known problems +Suggested replacements may not use correct path to enum +if it's not present in the current scope. + +### Example +``` +match x { + Foo::A => {}, + Foo::B => {}, + _ => {}, +} +``` + +Use instead: +``` +match x { + Foo::A => {}, + Foo::B => {}, + Foo::C => {}, +} +``` \ No newline at end of file diff --git a/src/docs/maybe_infinite_iter.txt b/src/docs/maybe_infinite_iter.txt new file mode 100644 index 000000000000..1204a49b4668 --- /dev/null +++ b/src/docs/maybe_infinite_iter.txt @@ -0,0 +1,16 @@ +### What it does +Checks for iteration that may be infinite. + +### Why is this bad? +While there may be places where this is acceptable +(e.g., in event streams), in most cases this is simply an error. + +### Known problems +The code may have a condition to stop iteration, but +this lint is not clever enough to analyze it. + +### Example +``` +let infinite_iter = 0..; +[0..].iter().zip(infinite_iter.take_while(|x| *x > 5)); +``` \ No newline at end of file diff --git a/src/docs/mem_forget.txt b/src/docs/mem_forget.txt new file mode 100644 index 000000000000..a6888c48fc33 --- /dev/null +++ b/src/docs/mem_forget.txt @@ -0,0 +1,12 @@ +### What it does +Checks for usage of `std::mem::forget(t)` where `t` is +`Drop`. + +### Why is this bad? +`std::mem::forget(t)` prevents `t` from running its +destructor, possibly causing leaks. + +### Example +``` +mem::forget(Rc::new(55)) +``` \ No newline at end of file diff --git a/src/docs/mem_replace_option_with_none.txt b/src/docs/mem_replace_option_with_none.txt new file mode 100644 index 000000000000..7f243d1c1656 --- /dev/null +++ b/src/docs/mem_replace_option_with_none.txt @@ -0,0 +1,21 @@ +### What it does +Checks for `mem::replace()` on an `Option` with +`None`. + +### Why is this bad? +`Option` already has the method `take()` for +taking its current value (Some(..) or None) and replacing it with +`None`. + +### Example +``` +use std::mem; + +let mut an_option = Some(0); +let replaced = mem::replace(&mut an_option, None); +``` +Is better expressed with: +``` +let mut an_option = Some(0); +let taken = an_option.take(); +``` \ No newline at end of file diff --git a/src/docs/mem_replace_with_default.txt b/src/docs/mem_replace_with_default.txt new file mode 100644 index 000000000000..24e0913a30c9 --- /dev/null +++ b/src/docs/mem_replace_with_default.txt @@ -0,0 +1,18 @@ +### What it does +Checks for `std::mem::replace` on a value of type +`T` with `T::default()`. + +### Why is this bad? +`std::mem` module already has the method `take` to +take the current value and replace it with the default value of that type. + +### Example +``` +let mut text = String::from("foo"); +let replaced = std::mem::replace(&mut text, String::default()); +``` +Is better expressed with: +``` +let mut text = String::from("foo"); +let taken = std::mem::take(&mut text); +``` \ No newline at end of file diff --git a/src/docs/mem_replace_with_uninit.txt b/src/docs/mem_replace_with_uninit.txt new file mode 100644 index 000000000000..0bb483668abc --- /dev/null +++ b/src/docs/mem_replace_with_uninit.txt @@ -0,0 +1,24 @@ +### What it does +Checks for `mem::replace(&mut _, mem::uninitialized())` +and `mem::replace(&mut _, mem::zeroed())`. + +### Why is this bad? +This will lead to undefined behavior even if the +value is overwritten later, because the uninitialized value may be +observed in the case of a panic. + +### Example +``` +use std::mem; + +#[allow(deprecated, invalid_value)] +fn myfunc (v: &mut Vec) { + let taken_v = unsafe { mem::replace(v, mem::uninitialized()) }; + let new_v = may_panic(taken_v); // undefined behavior on panic + mem::forget(mem::replace(v, new_v)); +} +``` + +The [take_mut](https://docs.rs/take_mut) crate offers a sound solution, +at the cost of either lazily creating a replacement value or aborting +on panic, to ensure that the uninitialized value cannot be observed. \ No newline at end of file diff --git a/src/docs/min_max.txt b/src/docs/min_max.txt new file mode 100644 index 000000000000..6acf0f932e98 --- /dev/null +++ b/src/docs/min_max.txt @@ -0,0 +1,18 @@ +### What it does +Checks for expressions where `std::cmp::min` and `max` are +used to clamp values, but switched so that the result is constant. + +### Why is this bad? +This is in all probability not the intended outcome. At +the least it hurts readability of the code. + +### Example +``` +min(0, max(100, x)) + +// or + +x.max(100).min(0) +``` +It will always be equal to `0`. Probably the author meant to clamp the value +between 0 and 100, but has erroneously swapped `min` and `max`. \ No newline at end of file diff --git a/src/docs/mismatched_target_os.txt b/src/docs/mismatched_target_os.txt new file mode 100644 index 000000000000..51e5ec6e7c5c --- /dev/null +++ b/src/docs/mismatched_target_os.txt @@ -0,0 +1,24 @@ +### What it does +Checks for cfg attributes having operating systems used in target family position. + +### Why is this bad? +The configuration option will not be recognised and the related item will not be included +by the conditional compilation engine. + +### Example +``` +#[cfg(linux)] +fn conditional() { } +``` + +Use instead: +``` +#[cfg(target_os = "linux")] +fn conditional() { } + +// or + +#[cfg(unix)] +fn conditional() { } +``` +Check the [Rust Reference](https://doc.rust-lang.org/reference/conditional-compilation.html#target_os) for more details. \ No newline at end of file diff --git a/src/docs/mismatching_type_param_order.txt b/src/docs/mismatching_type_param_order.txt new file mode 100644 index 000000000000..ffc7f32d0aad --- /dev/null +++ b/src/docs/mismatching_type_param_order.txt @@ -0,0 +1,33 @@ +### What it does +Checks for type parameters which are positioned inconsistently between +a type definition and impl block. Specifically, a parameter in an impl +block which has the same name as a parameter in the type def, but is in +a different place. + +### Why is this bad? +Type parameters are determined by their position rather than name. +Naming type parameters inconsistently may cause you to refer to the +wrong type parameter. + +### Limitations +This lint only applies to impl blocks with simple generic params, e.g. +`A`. If there is anything more complicated, such as a tuple, it will be +ignored. + +### Example +``` +struct Foo { + x: A, + y: B, +} +// inside the impl, B refers to Foo::A +impl Foo {} +``` +Use instead: +``` +struct Foo { + x: A, + y: B, +} +impl Foo {} +``` \ No newline at end of file diff --git a/src/docs/misrefactored_assign_op.txt b/src/docs/misrefactored_assign_op.txt new file mode 100644 index 000000000000..3d691fe4178b --- /dev/null +++ b/src/docs/misrefactored_assign_op.txt @@ -0,0 +1,20 @@ +### What it does +Checks for `a op= a op b` or `a op= b op a` patterns. + +### Why is this bad? +Most likely these are bugs where one meant to write `a +op= b`. + +### Known problems +Clippy cannot know for sure if `a op= a op b` should have +been `a = a op a op b` or `a = a op b`/`a op= b`. Therefore, it suggests both. +If `a op= a op b` is really the correct behavior it should be +written as `a = a op a op b` as it's less confusing. + +### Example +``` +let mut a = 5; +let b = 2; +// ... +a += a + b; +``` \ No newline at end of file diff --git a/src/docs/missing_const_for_fn.txt b/src/docs/missing_const_for_fn.txt new file mode 100644 index 000000000000..067614d4c46b --- /dev/null +++ b/src/docs/missing_const_for_fn.txt @@ -0,0 +1,40 @@ +### What it does +Suggests the use of `const` in functions and methods where possible. + +### Why is this bad? +Not having the function const prevents callers of the function from being const as well. + +### Known problems +Const functions are currently still being worked on, with some features only being available +on nightly. This lint does not consider all edge cases currently and the suggestions may be +incorrect if you are using this lint on stable. + +Also, the lint only runs one pass over the code. Consider these two non-const functions: + +``` +fn a() -> i32 { + 0 +} +fn b() -> i32 { + a() +} +``` + +When running Clippy, the lint will only suggest to make `a` const, because `b` at this time +can't be const as it calls a non-const function. Making `a` const and running Clippy again, +will suggest to make `b` const, too. + +### Example +``` +fn new() -> Self { + Self { random_number: 42 } +} +``` + +Could be a const fn: + +``` +const fn new() -> Self { + Self { random_number: 42 } +} +``` \ No newline at end of file diff --git a/src/docs/missing_docs_in_private_items.txt b/src/docs/missing_docs_in_private_items.txt new file mode 100644 index 000000000000..5d37505bb171 --- /dev/null +++ b/src/docs/missing_docs_in_private_items.txt @@ -0,0 +1,9 @@ +### What it does +Warns if there is missing doc for any documentable item +(public or private). + +### Why is this bad? +Doc is good. *rustc* has a `MISSING_DOCS` +allowed-by-default lint for +public members, but has no way to enforce documentation of private items. +This lint fixes that. \ No newline at end of file diff --git a/src/docs/missing_enforced_import_renames.txt b/src/docs/missing_enforced_import_renames.txt new file mode 100644 index 000000000000..8f4649bd5923 --- /dev/null +++ b/src/docs/missing_enforced_import_renames.txt @@ -0,0 +1,22 @@ +### What it does +Checks for imports that do not rename the item as specified +in the `enforce-import-renames` config option. + +### Why is this bad? +Consistency is important, if a project has defined import +renames they should be followed. More practically, some item names are too +vague outside of their defining scope this can enforce a more meaningful naming. + +### Example +An example clippy.toml configuration: +``` +enforced-import-renames = [ { path = "serde_json::Value", rename = "JsonValue" }] +``` + +``` +use serde_json::Value; +``` +Use instead: +``` +use serde_json::Value as JsonValue; +``` \ No newline at end of file diff --git a/src/docs/missing_errors_doc.txt b/src/docs/missing_errors_doc.txt new file mode 100644 index 000000000000..028778d85aeb --- /dev/null +++ b/src/docs/missing_errors_doc.txt @@ -0,0 +1,21 @@ +### What it does +Checks the doc comments of publicly visible functions that +return a `Result` type and warns if there is no `# Errors` section. + +### Why is this bad? +Documenting the type of errors that can be returned from a +function can help callers write code to handle the errors appropriately. + +### Examples +Since the following function returns a `Result` it has an `# Errors` section in +its doc comment: + +``` +/// # Errors +/// +/// Will return `Err` if `filename` does not exist or the user does not have +/// permission to read it. +pub fn read(filename: String) -> io::Result { + unimplemented!(); +} +``` \ No newline at end of file diff --git a/src/docs/missing_inline_in_public_items.txt b/src/docs/missing_inline_in_public_items.txt new file mode 100644 index 000000000000..d90c50fe7f9e --- /dev/null +++ b/src/docs/missing_inline_in_public_items.txt @@ -0,0 +1,45 @@ +### What it does +It lints if an exported function, method, trait method with default impl, +or trait method impl is not `#[inline]`. + +### Why is this bad? +In general, it is not. Functions can be inlined across +crates when that's profitable as long as any form of LTO is used. When LTO is disabled, +functions that are not `#[inline]` cannot be inlined across crates. Certain types of crates +might intend for most of the methods in their public API to be able to be inlined across +crates even when LTO is disabled. For these types of crates, enabling this lint might make +sense. It allows the crate to require all exported methods to be `#[inline]` by default, and +then opt out for specific methods where this might not make sense. + +### Example +``` +pub fn foo() {} // missing #[inline] +fn ok() {} // ok +#[inline] pub fn bar() {} // ok +#[inline(always)] pub fn baz() {} // ok + +pub trait Bar { + fn bar(); // ok + fn def_bar() {} // missing #[inline] +} + +struct Baz; +impl Baz { + fn private() {} // ok +} + +impl Bar for Baz { + fn bar() {} // ok - Baz is not exported +} + +pub struct PubBaz; +impl PubBaz { + fn private() {} // ok + pub fn not_private() {} // missing #[inline] +} + +impl Bar for PubBaz { + fn bar() {} // missing #[inline] + fn def_bar() {} // missing #[inline] +} +``` \ No newline at end of file diff --git a/src/docs/missing_panics_doc.txt b/src/docs/missing_panics_doc.txt new file mode 100644 index 000000000000..e5e39a824519 --- /dev/null +++ b/src/docs/missing_panics_doc.txt @@ -0,0 +1,24 @@ +### What it does +Checks the doc comments of publicly visible functions that +may panic and warns if there is no `# Panics` section. + +### Why is this bad? +Documenting the scenarios in which panicking occurs +can help callers who do not want to panic to avoid those situations. + +### Examples +Since the following function may panic it has a `# Panics` section in +its doc comment: + +``` +/// # Panics +/// +/// Will panic if y is 0 +pub fn divide_by(x: i32, y: i32) -> i32 { + if y == 0 { + panic!("Cannot divide by 0") + } else { + x / y + } +} +``` \ No newline at end of file diff --git a/src/docs/missing_safety_doc.txt b/src/docs/missing_safety_doc.txt new file mode 100644 index 000000000000..6492eb84f63b --- /dev/null +++ b/src/docs/missing_safety_doc.txt @@ -0,0 +1,26 @@ +### What it does +Checks for the doc comments of publicly visible +unsafe functions and warns if there is no `# Safety` section. + +### Why is this bad? +Unsafe functions should document their safety +preconditions, so that users can be sure they are using them safely. + +### Examples +``` +/// This function should really be documented +pub unsafe fn start_apocalypse(u: &mut Universe) { + unimplemented!(); +} +``` + +At least write a line about safety: + +``` +/// # Safety +/// +/// This function should not be called before the horsemen are ready. +pub unsafe fn start_apocalypse(u: &mut Universe) { + unimplemented!(); +} +``` \ No newline at end of file diff --git a/src/docs/missing_spin_loop.txt b/src/docs/missing_spin_loop.txt new file mode 100644 index 000000000000..3a06a91d7183 --- /dev/null +++ b/src/docs/missing_spin_loop.txt @@ -0,0 +1,27 @@ +### What it does +Check for empty spin loops + +### Why is this bad? +The loop body should have something like `thread::park()` or at least +`std::hint::spin_loop()` to avoid needlessly burning cycles and conserve +energy. Perhaps even better use an actual lock, if possible. + +### Known problems +This lint doesn't currently trigger on `while let` or +`loop { match .. { .. } }` loops, which would be considered idiomatic in +combination with e.g. `AtomicBool::compare_exchange_weak`. + +### Example + +``` +use core::sync::atomic::{AtomicBool, Ordering}; +let b = AtomicBool::new(true); +// give a ref to `b` to another thread,wait for it to become false +while b.load(Ordering::Acquire) {}; +``` +Use instead: +``` +while b.load(Ordering::Acquire) { + std::hint::spin_loop() +} +``` \ No newline at end of file diff --git a/src/docs/mistyped_literal_suffixes.txt b/src/docs/mistyped_literal_suffixes.txt new file mode 100644 index 000000000000..1760fcbfeacc --- /dev/null +++ b/src/docs/mistyped_literal_suffixes.txt @@ -0,0 +1,15 @@ +### What it does +Warns for mistyped suffix in literals + +### Why is this bad? +This is most probably a typo + +### Known problems +- Does not match on integers too large to fit in the corresponding unsigned type +- Does not match on `_127` since that is a valid grouping for decimal and octal numbers + +### Example +``` +`2_32` => `2_i32` +`250_8 => `250_u8` +``` \ No newline at end of file diff --git a/src/docs/mixed_case_hex_literals.txt b/src/docs/mixed_case_hex_literals.txt new file mode 100644 index 000000000000..d2d01e0c98eb --- /dev/null +++ b/src/docs/mixed_case_hex_literals.txt @@ -0,0 +1,16 @@ +### What it does +Warns on hexadecimal literals with mixed-case letter +digits. + +### Why is this bad? +It looks confusing. + +### Example +``` +0x1a9BAcD +``` + +Use instead: +``` +0x1A9BACD +``` \ No newline at end of file diff --git a/src/docs/mixed_read_write_in_expression.txt b/src/docs/mixed_read_write_in_expression.txt new file mode 100644 index 000000000000..02d1c5d05252 --- /dev/null +++ b/src/docs/mixed_read_write_in_expression.txt @@ -0,0 +1,32 @@ +### What it does +Checks for a read and a write to the same variable where +whether the read occurs before or after the write depends on the evaluation +order of sub-expressions. + +### Why is this bad? +It is often confusing to read. As described [here](https://doc.rust-lang.org/reference/expressions.html?highlight=subexpression#evaluation-order-of-operands), +the operands of these expressions are evaluated before applying the effects of the expression. + +### Known problems +Code which intentionally depends on the evaluation +order, or which is correct for any evaluation order. + +### Example +``` +let mut x = 0; + +let a = { + x = 1; + 1 +} + x; +// Unclear whether a is 1 or 2. +``` + +Use instead: +``` +let tmp = { + x = 1; + 1 +}; +let a = tmp + x; +``` \ No newline at end of file diff --git a/src/docs/mod_module_files.txt b/src/docs/mod_module_files.txt new file mode 100644 index 000000000000..95bca583afd3 --- /dev/null +++ b/src/docs/mod_module_files.txt @@ -0,0 +1,22 @@ +### What it does +Checks that module layout uses only self named module files, bans `mod.rs` files. + +### Why is this bad? +Having multiple module layout styles in a project can be confusing. + +### Example +``` +src/ + stuff/ + stuff_files.rs + mod.rs + lib.rs +``` +Use instead: +``` +src/ + stuff/ + stuff_files.rs + stuff.rs + lib.rs +``` \ No newline at end of file diff --git a/src/docs/module_inception.txt b/src/docs/module_inception.txt new file mode 100644 index 000000000000..d80a1b8d8fe5 --- /dev/null +++ b/src/docs/module_inception.txt @@ -0,0 +1,24 @@ +### What it does +Checks for modules that have the same name as their +parent module + +### Why is this bad? +A typical beginner mistake is to have `mod foo;` and +again `mod foo { .. +}` in `foo.rs`. +The expectation is that items inside the inner `mod foo { .. }` are then +available +through `foo::x`, but they are only available through +`foo::foo::x`. +If this is done on purpose, it would be better to choose a more +representative module name. + +### Example +``` +// lib.rs +mod foo; +// foo.rs +mod foo { + ... +} +``` \ No newline at end of file diff --git a/src/docs/module_name_repetitions.txt b/src/docs/module_name_repetitions.txt new file mode 100644 index 000000000000..3bc05d02780c --- /dev/null +++ b/src/docs/module_name_repetitions.txt @@ -0,0 +1,20 @@ +### What it does +Detects type names that are prefixed or suffixed by the +containing module's name. + +### Why is this bad? +It requires the user to type the module name twice. + +### Example +``` +mod cake { + struct BlackForestCake; +} +``` + +Use instead: +``` +mod cake { + struct BlackForest; +} +``` \ No newline at end of file diff --git a/src/docs/modulo_arithmetic.txt b/src/docs/modulo_arithmetic.txt new file mode 100644 index 000000000000..ff7296f3c5b8 --- /dev/null +++ b/src/docs/modulo_arithmetic.txt @@ -0,0 +1,15 @@ +### What it does +Checks for modulo arithmetic. + +### Why is this bad? +The results of modulo (%) operation might differ +depending on the language, when negative numbers are involved. +If you interop with different languages it might be beneficial +to double check all places that use modulo arithmetic. + +For example, in Rust `17 % -3 = 2`, but in Python `17 % -3 = -1`. + +### Example +``` +let x = -17 % 3; +``` \ No newline at end of file diff --git a/src/docs/modulo_one.txt b/src/docs/modulo_one.txt new file mode 100644 index 000000000000..bc8f95b0be69 --- /dev/null +++ b/src/docs/modulo_one.txt @@ -0,0 +1,16 @@ +### What it does +Checks for getting the remainder of a division by one or minus +one. + +### Why is this bad? +The result for a divisor of one can only ever be zero; for +minus one it can cause panic/overflow (if the left operand is the minimal value of +the respective integer type) or results in zero. No one will write such code +deliberately, unless trying to win an Underhanded Rust Contest. Even for that +contest, it's probably a bad idea. Use something more underhanded. + +### Example +``` +let a = x % 1; +let a = x % -1; +``` \ No newline at end of file diff --git a/src/docs/multi_assignments.txt b/src/docs/multi_assignments.txt new file mode 100644 index 000000000000..ed1f1b420cbd --- /dev/null +++ b/src/docs/multi_assignments.txt @@ -0,0 +1,17 @@ +### What it does +Checks for nested assignments. + +### Why is this bad? +While this is in most cases already a type mismatch, +the result of an assignment being `()` can throw off people coming from languages like python or C, +where such assignments return a copy of the assigned value. + +### Example +``` +a = b = 42; +``` +Use instead: +``` +b = 42; +a = b; +``` \ No newline at end of file diff --git a/src/docs/multiple_crate_versions.txt b/src/docs/multiple_crate_versions.txt new file mode 100644 index 000000000000..cf2d2c6abee3 --- /dev/null +++ b/src/docs/multiple_crate_versions.txt @@ -0,0 +1,19 @@ +### What it does +Checks to see if multiple versions of a crate are being +used. + +### Why is this bad? +This bloats the size of targets, and can lead to +confusing error messages when structs or traits are used interchangeably +between different versions of a crate. + +### Known problems +Because this can be caused purely by the dependencies +themselves, it's not always possible to fix this issue. + +### Example +``` +[dependencies] +ctrlc = "=3.1.0" +ansi_term = "=0.11.0" +``` \ No newline at end of file diff --git a/src/docs/multiple_inherent_impl.txt b/src/docs/multiple_inherent_impl.txt new file mode 100644 index 000000000000..9d42286560ce --- /dev/null +++ b/src/docs/multiple_inherent_impl.txt @@ -0,0 +1,26 @@ +### What it does +Checks for multiple inherent implementations of a struct + +### Why is this bad? +Splitting the implementation of a type makes the code harder to navigate. + +### Example +``` +struct X; +impl X { + fn one() {} +} +impl X { + fn other() {} +} +``` + +Could be written: + +``` +struct X; +impl X { + fn one() {} + fn other() {} +} +``` \ No newline at end of file diff --git a/src/docs/must_use_candidate.txt b/src/docs/must_use_candidate.txt new file mode 100644 index 000000000000..70890346fe6b --- /dev/null +++ b/src/docs/must_use_candidate.txt @@ -0,0 +1,23 @@ +### What it does +Checks for public functions that have no +`#[must_use]` attribute, but return something not already marked +must-use, have no mutable arg and mutate no statics. + +### Why is this bad? +Not bad at all, this lint just shows places where +you could add the attribute. + +### Known problems +The lint only checks the arguments for mutable +types without looking if they are actually changed. On the other hand, +it also ignores a broad range of potentially interesting side effects, +because we cannot decide whether the programmer intends the function to +be called for the side effect or the result. Expect many false +positives. At least we don't lint if the result type is unit or already +`#[must_use]`. + +### Examples +``` +// this could be annotated with `#[must_use]`. +fn id(t: T) -> T { t } +``` \ No newline at end of file diff --git a/src/docs/must_use_unit.txt b/src/docs/must_use_unit.txt new file mode 100644 index 000000000000..cabbb23f8651 --- /dev/null +++ b/src/docs/must_use_unit.txt @@ -0,0 +1,13 @@ +### What it does +Checks for a `#[must_use]` attribute on +unit-returning functions and methods. + +### Why is this bad? +Unit values are useless. The attribute is likely +a remnant of a refactoring that removed the return type. + +### Examples +``` +#[must_use] +fn useless() { } +``` \ No newline at end of file diff --git a/src/docs/mut_from_ref.txt b/src/docs/mut_from_ref.txt new file mode 100644 index 000000000000..cc1da12549a5 --- /dev/null +++ b/src/docs/mut_from_ref.txt @@ -0,0 +1,26 @@ +### What it does +This lint checks for functions that take immutable references and return +mutable ones. This will not trigger if no unsafe code exists as there +are multiple safe functions which will do this transformation + +To be on the conservative side, if there's at least one mutable +reference with the output lifetime, this lint will not trigger. + +### Why is this bad? +Creating a mutable reference which can be repeatably derived from an +immutable reference is unsound as it allows creating multiple live +mutable references to the same object. + +This [error](https://github.com/rust-lang/rust/issues/39465) actually +lead to an interim Rust release 1.15.1. + +### Known problems +This pattern is used by memory allocators to allow allocating multiple +objects while returning mutable references to each one. So long as +different mutable references are returned each time such a function may +be safe. + +### Example +``` +fn foo(&Foo) -> &mut Bar { .. } +``` \ No newline at end of file diff --git a/src/docs/mut_mut.txt b/src/docs/mut_mut.txt new file mode 100644 index 000000000000..0bd34dd24b26 --- /dev/null +++ b/src/docs/mut_mut.txt @@ -0,0 +1,12 @@ +### What it does +Checks for instances of `mut mut` references. + +### Why is this bad? +Multiple `mut`s don't add anything meaningful to the +source. This is either a copy'n'paste error, or it shows a fundamental +misunderstanding of references. + +### Example +``` +let x = &mut &mut y; +``` \ No newline at end of file diff --git a/src/docs/mut_mutex_lock.txt b/src/docs/mut_mutex_lock.txt new file mode 100644 index 000000000000..5e9ad8a3f176 --- /dev/null +++ b/src/docs/mut_mutex_lock.txt @@ -0,0 +1,29 @@ +### What it does +Checks for `&mut Mutex::lock` calls + +### Why is this bad? +`Mutex::lock` is less efficient than +calling `Mutex::get_mut`. In addition you also have a statically +guarantee that the mutex isn't locked, instead of just a runtime +guarantee. + +### Example +``` +use std::sync::{Arc, Mutex}; + +let mut value_rc = Arc::new(Mutex::new(42_u8)); +let value_mutex = Arc::get_mut(&mut value_rc).unwrap(); + +let mut value = value_mutex.lock().unwrap(); +*value += 1; +``` +Use instead: +``` +use std::sync::{Arc, Mutex}; + +let mut value_rc = Arc::new(Mutex::new(42_u8)); +let value_mutex = Arc::get_mut(&mut value_rc).unwrap(); + +let value = value_mutex.get_mut().unwrap(); +*value += 1; +``` \ No newline at end of file diff --git a/src/docs/mut_range_bound.txt b/src/docs/mut_range_bound.txt new file mode 100644 index 000000000000..e9c38a543b14 --- /dev/null +++ b/src/docs/mut_range_bound.txt @@ -0,0 +1,29 @@ +### What it does +Checks for loops which have a range bound that is a mutable variable + +### Why is this bad? +One might think that modifying the mutable variable changes the loop bounds + +### Known problems +False positive when mutation is followed by a `break`, but the `break` is not immediately +after the mutation: + +``` +let mut x = 5; +for _ in 0..x { + x += 1; // x is a range bound that is mutated + ..; // some other expression + break; // leaves the loop, so mutation is not an issue +} +``` + +False positive on nested loops ([#6072](https://github.com/rust-lang/rust-clippy/issues/6072)) + +### Example +``` +let mut foo = 42; +for i in 0..foo { + foo -= 1; + println!("{}", i); // prints numbers from 0 to 42, not 0 to 21 +} +``` \ No newline at end of file diff --git a/src/docs/mutable_key_type.txt b/src/docs/mutable_key_type.txt new file mode 100644 index 000000000000..15fe34f2bb5e --- /dev/null +++ b/src/docs/mutable_key_type.txt @@ -0,0 +1,61 @@ +### What it does +Checks for sets/maps with mutable key types. + +### Why is this bad? +All of `HashMap`, `HashSet`, `BTreeMap` and +`BtreeSet` rely on either the hash or the order of keys be unchanging, +so having types with interior mutability is a bad idea. + +### Known problems + +#### False Positives +It's correct to use a struct that contains interior mutability as a key, when its +implementation of `Hash` or `Ord` doesn't access any of the interior mutable types. +However, this lint is unable to recognize this, so it will often cause false positives in +theses cases. The `bytes` crate is a great example of this. + +#### False Negatives +For custom `struct`s/`enum`s, this lint is unable to check for interior mutability behind +indirection. For example, `struct BadKey<'a>(&'a Cell)` will be seen as immutable +and cause a false negative if its implementation of `Hash`/`Ord` accesses the `Cell`. + +This lint does check a few cases for indirection. Firstly, using some standard library +types (`Option`, `Result`, `Box`, `Rc`, `Arc`, `Vec`, `VecDeque`, `BTreeMap` and +`BTreeSet`) directly as keys (e.g. in `HashMap>, ()>`) **will** trigger the +lint, because the impls of `Hash`/`Ord` for these types directly call `Hash`/`Ord` on their +contained type. + +Secondly, the implementations of `Hash` and `Ord` for raw pointers (`*const T` or `*mut T`) +apply only to the **address** of the contained value. Therefore, interior mutability +behind raw pointers (e.g. in `HashSet<*mut Cell>`) can't impact the value of `Hash` +or `Ord`, and therefore will not trigger this link. For more info, see issue +[#6745](https://github.com/rust-lang/rust-clippy/issues/6745). + +### Example +``` +use std::cmp::{PartialEq, Eq}; +use std::collections::HashSet; +use std::hash::{Hash, Hasher}; +use std::sync::atomic::AtomicUsize; + +struct Bad(AtomicUsize); +impl PartialEq for Bad { + fn eq(&self, rhs: &Self) -> bool { + .. +; unimplemented!(); + } +} + +impl Eq for Bad {} + +impl Hash for Bad { + fn hash(&self, h: &mut H) { + .. +; unimplemented!(); + } +} + +fn main() { + let _: HashSet = HashSet::new(); +} +``` \ No newline at end of file diff --git a/src/docs/mutex_atomic.txt b/src/docs/mutex_atomic.txt new file mode 100644 index 000000000000..062ac8b323b7 --- /dev/null +++ b/src/docs/mutex_atomic.txt @@ -0,0 +1,22 @@ +### What it does +Checks for usages of `Mutex` where an atomic will do. + +### Why is this bad? +Using a mutex just to make access to a plain bool or +reference sequential is shooting flies with cannons. +`std::sync::atomic::AtomicBool` and `std::sync::atomic::AtomicPtr` are leaner and +faster. + +### Known problems +This lint cannot detect if the mutex is actually used +for waiting before a critical section. + +### Example +``` +let x = Mutex::new(&y); +``` + +Use instead: +``` +let x = AtomicBool::new(y); +``` \ No newline at end of file diff --git a/src/docs/mutex_integer.txt b/src/docs/mutex_integer.txt new file mode 100644 index 000000000000..f9dbdfb904c9 --- /dev/null +++ b/src/docs/mutex_integer.txt @@ -0,0 +1,22 @@ +### What it does +Checks for usages of `Mutex` where `X` is an integral +type. + +### Why is this bad? +Using a mutex just to make access to a plain integer +sequential is +shooting flies with cannons. `std::sync::atomic::AtomicUsize` is leaner and faster. + +### Known problems +This lint cannot detect if the mutex is actually used +for waiting before a critical section. + +### Example +``` +let x = Mutex::new(0usize); +``` + +Use instead: +``` +let x = AtomicUsize::new(0usize); +``` \ No newline at end of file diff --git a/src/docs/naive_bytecount.txt b/src/docs/naive_bytecount.txt new file mode 100644 index 000000000000..24659dc79ae7 --- /dev/null +++ b/src/docs/naive_bytecount.txt @@ -0,0 +1,22 @@ +### What it does +Checks for naive byte counts + +### Why is this bad? +The [`bytecount`](https://crates.io/crates/bytecount) +crate has methods to count your bytes faster, especially for large slices. + +### Known problems +If you have predominantly small slices, the +`bytecount::count(..)` method may actually be slower. However, if you can +ensure that less than 2³²-1 matches arise, the `naive_count_32(..)` can be +faster in those cases. + +### Example +``` +let count = vec.iter().filter(|x| **x == 0u8).count(); +``` + +Use instead: +``` +let count = bytecount::count(&vec, 0u8); +``` \ No newline at end of file diff --git a/src/docs/needless_arbitrary_self_type.txt b/src/docs/needless_arbitrary_self_type.txt new file mode 100644 index 000000000000..8216a3a3fb6e --- /dev/null +++ b/src/docs/needless_arbitrary_self_type.txt @@ -0,0 +1,44 @@ +### What it does +The lint checks for `self` in fn parameters that +specify the `Self`-type explicitly +### Why is this bad? +Increases the amount and decreases the readability of code + +### Example +``` +enum ValType { + I32, + I64, + F32, + F64, +} + +impl ValType { + pub fn bytes(self: Self) -> usize { + match self { + Self::I32 | Self::F32 => 4, + Self::I64 | Self::F64 => 8, + } + } +} +``` + +Could be rewritten as + +``` +enum ValType { + I32, + I64, + F32, + F64, +} + +impl ValType { + pub fn bytes(self) -> usize { + match self { + Self::I32 | Self::F32 => 4, + Self::I64 | Self::F64 => 8, + } + } +} +``` \ No newline at end of file diff --git a/src/docs/needless_bitwise_bool.txt b/src/docs/needless_bitwise_bool.txt new file mode 100644 index 000000000000..fcd7b730aaae --- /dev/null +++ b/src/docs/needless_bitwise_bool.txt @@ -0,0 +1,22 @@ +### What it does +Checks for uses of bitwise and/or operators between booleans, where performance may be improved by using +a lazy and. + +### Why is this bad? +The bitwise operators do not support short-circuiting, so it may hinder code performance. +Additionally, boolean logic "masked" as bitwise logic is not caught by lints like `unnecessary_fold` + +### Known problems +This lint evaluates only when the right side is determined to have no side effects. At this time, that +determination is quite conservative. + +### Example +``` +let (x,y) = (true, false); +if x & !y {} // where both x and y are booleans +``` +Use instead: +``` +let (x,y) = (true, false); +if x && !y {} +``` \ No newline at end of file diff --git a/src/docs/needless_bool.txt b/src/docs/needless_bool.txt new file mode 100644 index 000000000000..b5c78871f14f --- /dev/null +++ b/src/docs/needless_bool.txt @@ -0,0 +1,26 @@ +### What it does +Checks for expressions of the form `if c { true } else { +false }` (or vice versa) and suggests using the condition directly. + +### Why is this bad? +Redundant code. + +### Known problems +Maybe false positives: Sometimes, the two branches are +painstakingly documented (which we, of course, do not detect), so they *may* +have some value. Even then, the documentation can be rewritten to match the +shorter code. + +### Example +``` +if x { + false +} else { + true +} +``` + +Use instead: +``` +!x +``` \ No newline at end of file diff --git a/src/docs/needless_borrow.txt b/src/docs/needless_borrow.txt new file mode 100644 index 000000000000..4debcf473723 --- /dev/null +++ b/src/docs/needless_borrow.txt @@ -0,0 +1,21 @@ +### What it does +Checks for address of operations (`&`) that are going to +be dereferenced immediately by the compiler. + +### Why is this bad? +Suggests that the receiver of the expression borrows +the expression. + +### Example +``` +fn fun(_a: &i32) {} + +let x: &i32 = &&&&&&5; +fun(&x); +``` + +Use instead: +``` +let x: &i32 = &5; +fun(x); +``` \ No newline at end of file diff --git a/src/docs/needless_borrowed_reference.txt b/src/docs/needless_borrowed_reference.txt new file mode 100644 index 000000000000..55faa0cf5719 --- /dev/null +++ b/src/docs/needless_borrowed_reference.txt @@ -0,0 +1,30 @@ +### What it does +Checks for bindings that destructure a reference and borrow the inner +value with `&ref`. + +### Why is this bad? +This pattern has no effect in almost all cases. + +### Known problems +In some cases, `&ref` is needed to avoid a lifetime mismatch error. +Example: +``` +fn foo(a: &Option, b: &Option) { + match (a, b) { + (None, &ref c) | (&ref c, None) => (), + (&Some(ref c), _) => (), + }; +} +``` + +### Example +``` +let mut v = Vec::::new(); +v.iter_mut().filter(|&ref a| a.is_empty()); +``` + +Use instead: +``` +let mut v = Vec::::new(); +v.iter_mut().filter(|a| a.is_empty()); +``` \ No newline at end of file diff --git a/src/docs/needless_collect.txt b/src/docs/needless_collect.txt new file mode 100644 index 000000000000..275c39afc9df --- /dev/null +++ b/src/docs/needless_collect.txt @@ -0,0 +1,14 @@ +### What it does +Checks for functions collecting an iterator when collect +is not needed. + +### Why is this bad? +`collect` causes the allocation of a new data structure, +when this allocation may not be needed. + +### Example +``` +let len = iterator.clone().collect::>().len(); +// should be +let len = iterator.count(); +``` \ No newline at end of file diff --git a/src/docs/needless_continue.txt b/src/docs/needless_continue.txt new file mode 100644 index 000000000000..2cee621c1af0 --- /dev/null +++ b/src/docs/needless_continue.txt @@ -0,0 +1,61 @@ +### What it does +The lint checks for `if`-statements appearing in loops +that contain a `continue` statement in either their main blocks or their +`else`-blocks, when omitting the `else`-block possibly with some +rearrangement of code can make the code easier to understand. + +### Why is this bad? +Having explicit `else` blocks for `if` statements +containing `continue` in their THEN branch adds unnecessary branching and +nesting to the code. Having an else block containing just `continue` can +also be better written by grouping the statements following the whole `if` +statement within the THEN block and omitting the else block completely. + +### Example +``` +while condition() { + update_condition(); + if x { + // ... + } else { + continue; + } + println!("Hello, world"); +} +``` + +Could be rewritten as + +``` +while condition() { + update_condition(); + if x { + // ... + println!("Hello, world"); + } +} +``` + +As another example, the following code + +``` +loop { + if waiting() { + continue; + } else { + // Do something useful + } + # break; +} +``` +Could be rewritten as + +``` +loop { + if waiting() { + continue; + } + // Do something useful + # break; +} +``` \ No newline at end of file diff --git a/src/docs/needless_doctest_main.txt b/src/docs/needless_doctest_main.txt new file mode 100644 index 000000000000..8f91a7baa715 --- /dev/null +++ b/src/docs/needless_doctest_main.txt @@ -0,0 +1,22 @@ +### What it does +Checks for `fn main() { .. }` in doctests + +### Why is this bad? +The test can be shorter (and likely more readable) +if the `fn main()` is left implicit. + +### Examples +``` +/// An example of a doctest with a `main()` function +/// +/// # Examples +/// +/// ``` +/// fn main() { +/// // this needs not be in an `fn` +/// } +/// ``` +fn needless_main() { + unimplemented!(); +} +``` \ No newline at end of file diff --git a/src/docs/needless_for_each.txt b/src/docs/needless_for_each.txt new file mode 100644 index 000000000000..9ae6dd360c8f --- /dev/null +++ b/src/docs/needless_for_each.txt @@ -0,0 +1,24 @@ +### What it does +Checks for usage of `for_each` that would be more simply written as a +`for` loop. + +### Why is this bad? +`for_each` may be used after applying iterator transformers like +`filter` for better readability and performance. It may also be used to fit a simple +operation on one line. +But when none of these apply, a simple `for` loop is more idiomatic. + +### Example +``` +let v = vec![0, 1, 2]; +v.iter().for_each(|elem| { + println!("{}", elem); +}) +``` +Use instead: +``` +let v = vec![0, 1, 2]; +for elem in v.iter() { + println!("{}", elem); +} +``` \ No newline at end of file diff --git a/src/docs/needless_late_init.txt b/src/docs/needless_late_init.txt new file mode 100644 index 000000000000..9e7bbcea9982 --- /dev/null +++ b/src/docs/needless_late_init.txt @@ -0,0 +1,42 @@ +### What it does +Checks for late initializations that can be replaced by a `let` statement +with an initializer. + +### Why is this bad? +Assigning in the `let` statement is less repetitive. + +### Example +``` +let a; +a = 1; + +let b; +match 3 { + 0 => b = "zero", + 1 => b = "one", + _ => b = "many", +} + +let c; +if true { + c = 1; +} else { + c = -1; +} +``` +Use instead: +``` +let a = 1; + +let b = match 3 { + 0 => "zero", + 1 => "one", + _ => "many", +}; + +let c = if true { + 1 +} else { + -1 +}; +``` \ No newline at end of file diff --git a/src/docs/needless_lifetimes.txt b/src/docs/needless_lifetimes.txt new file mode 100644 index 000000000000..b280caa66b58 --- /dev/null +++ b/src/docs/needless_lifetimes.txt @@ -0,0 +1,29 @@ +### What it does +Checks for lifetime annotations which can be removed by +relying on lifetime elision. + +### Why is this bad? +The additional lifetimes make the code look more +complicated, while there is nothing out of the ordinary going on. Removing +them leads to more readable code. + +### Known problems +- We bail out if the function has a `where` clause where lifetimes +are mentioned due to potential false positives. +- Lifetime bounds such as `impl Foo + 'a` and `T: 'a` must be elided with the +placeholder notation `'_` because the fully elided notation leaves the type bound to `'static`. + +### Example +``` +// Unnecessary lifetime annotations +fn in_and_out<'a>(x: &'a u8, y: u8) -> &'a u8 { + x +} +``` + +Use instead: +``` +fn elided(x: &u8, y: u8) -> &u8 { + x +} +``` \ No newline at end of file diff --git a/src/docs/needless_match.txt b/src/docs/needless_match.txt new file mode 100644 index 000000000000..92b40a5df648 --- /dev/null +++ b/src/docs/needless_match.txt @@ -0,0 +1,36 @@ +### What it does +Checks for unnecessary `match` or match-like `if let` returns for `Option` and `Result` +when function signatures are the same. + +### Why is this bad? +This `match` block does nothing and might not be what the coder intended. + +### Example +``` +fn foo() -> Result<(), i32> { + match result { + Ok(val) => Ok(val), + Err(err) => Err(err), + } +} + +fn bar() -> Option { + if let Some(val) = option { + Some(val) + } else { + None + } +} +``` + +Could be replaced as + +``` +fn foo() -> Result<(), i32> { + result +} + +fn bar() -> Option { + option +} +``` \ No newline at end of file diff --git a/src/docs/needless_option_as_deref.txt b/src/docs/needless_option_as_deref.txt new file mode 100644 index 000000000000..226396c97ac4 --- /dev/null +++ b/src/docs/needless_option_as_deref.txt @@ -0,0 +1,18 @@ +### What it does +Checks for no-op uses of `Option::{as_deref, as_deref_mut}`, +for example, `Option<&T>::as_deref()` returns the same type. + +### Why is this bad? +Redundant code and improving readability. + +### Example +``` +let a = Some(&1); +let b = a.as_deref(); // goes from Option<&i32> to Option<&i32> +``` + +Use instead: +``` +let a = Some(&1); +let b = a; +``` \ No newline at end of file diff --git a/src/docs/needless_option_take.txt b/src/docs/needless_option_take.txt new file mode 100644 index 000000000000..6bac65a13b5b --- /dev/null +++ b/src/docs/needless_option_take.txt @@ -0,0 +1,17 @@ +### What it does +Checks for calling `take` function after `as_ref`. + +### Why is this bad? +Redundant code. `take` writes `None` to its argument. +In this case the modification is useless as it's a temporary that cannot be read from afterwards. + +### Example +``` +let x = Some(3); +x.as_ref().take(); +``` +Use instead: +``` +let x = Some(3); +x.as_ref(); +``` \ No newline at end of file diff --git a/src/docs/needless_parens_on_range_literals.txt b/src/docs/needless_parens_on_range_literals.txt new file mode 100644 index 000000000000..85fab10cb5f6 --- /dev/null +++ b/src/docs/needless_parens_on_range_literals.txt @@ -0,0 +1,23 @@ +### What it does +The lint checks for parenthesis on literals in range statements that are +superfluous. + +### Why is this bad? +Having superfluous parenthesis makes the code less readable +overhead when reading. + +### Example + +``` +for i in (0)..10 { + println!("{i}"); +} +``` + +Use instead: + +``` +for i in 0..10 { + println!("{i}"); +} +``` \ No newline at end of file diff --git a/src/docs/needless_pass_by_value.txt b/src/docs/needless_pass_by_value.txt new file mode 100644 index 000000000000..58c420b19f62 --- /dev/null +++ b/src/docs/needless_pass_by_value.txt @@ -0,0 +1,27 @@ +### What it does +Checks for functions taking arguments by value, but not +consuming them in its +body. + +### Why is this bad? +Taking arguments by reference is more flexible and can +sometimes avoid +unnecessary allocations. + +### Known problems +* This lint suggests taking an argument by reference, +however sometimes it is better to let users decide the argument type +(by using `Borrow` trait, for example), depending on how the function is used. + +### Example +``` +fn foo(v: Vec) { + assert_eq!(v.len(), 42); +} +``` +should be +``` +fn foo(v: &[i32]) { + assert_eq!(v.len(), 42); +} +``` \ No newline at end of file diff --git a/src/docs/needless_question_mark.txt b/src/docs/needless_question_mark.txt new file mode 100644 index 000000000000..540739fd45fa --- /dev/null +++ b/src/docs/needless_question_mark.txt @@ -0,0 +1,43 @@ +### What it does +Suggests alternatives for useless applications of `?` in terminating expressions + +### Why is this bad? +There's no reason to use `?` to short-circuit when execution of the body will end there anyway. + +### Example +``` +struct TO { + magic: Option, +} + +fn f(to: TO) -> Option { + Some(to.magic?) +} + +struct TR { + magic: Result, +} + +fn g(tr: Result) -> Result { + tr.and_then(|t| Ok(t.magic?)) +} + +``` +Use instead: +``` +struct TO { + magic: Option, +} + +fn f(to: TO) -> Option { + to.magic +} + +struct TR { + magic: Result, +} + +fn g(tr: Result) -> Result { + tr.and_then(|t| t.magic) +} +``` \ No newline at end of file diff --git a/src/docs/needless_range_loop.txt b/src/docs/needless_range_loop.txt new file mode 100644 index 000000000000..583c09b28497 --- /dev/null +++ b/src/docs/needless_range_loop.txt @@ -0,0 +1,23 @@ +### What it does +Checks for looping over the range of `0..len` of some +collection just to get the values by index. + +### Why is this bad? +Just iterating the collection itself makes the intent +more clear and is probably faster. + +### Example +``` +let vec = vec!['a', 'b', 'c']; +for i in 0..vec.len() { + println!("{}", vec[i]); +} +``` + +Use instead: +``` +let vec = vec!['a', 'b', 'c']; +for i in vec { + println!("{}", i); +} +``` \ No newline at end of file diff --git a/src/docs/needless_return.txt b/src/docs/needless_return.txt new file mode 100644 index 000000000000..48782cb0ca84 --- /dev/null +++ b/src/docs/needless_return.txt @@ -0,0 +1,19 @@ +### What it does +Checks for return statements at the end of a block. + +### Why is this bad? +Removing the `return` and semicolon will make the code +more rusty. + +### Example +``` +fn foo(x: usize) -> usize { + return x; +} +``` +simplify to +``` +fn foo(x: usize) -> usize { + x +} +``` \ No newline at end of file diff --git a/src/docs/needless_splitn.txt b/src/docs/needless_splitn.txt new file mode 100644 index 000000000000..b10a84fbc42d --- /dev/null +++ b/src/docs/needless_splitn.txt @@ -0,0 +1,16 @@ +### What it does +Checks for usages of `str::splitn` (or `str::rsplitn`) where using `str::split` would be the same. +### Why is this bad? +The function `split` is simpler and there is no performance difference in these cases, considering +that both functions return a lazy iterator. +### Example +``` +let str = "key=value=add"; +let _ = str.splitn(3, '=').next().unwrap(); +``` + +Use instead: +``` +let str = "key=value=add"; +let _ = str.split('=').next().unwrap(); +``` \ No newline at end of file diff --git a/src/docs/needless_update.txt b/src/docs/needless_update.txt new file mode 100644 index 000000000000..82adabf6482c --- /dev/null +++ b/src/docs/needless_update.txt @@ -0,0 +1,30 @@ +### What it does +Checks for needlessly including a base struct on update +when all fields are changed anyway. + +This lint is not applied to structs marked with +[non_exhaustive](https://doc.rust-lang.org/reference/attributes/type_system.html). + +### Why is this bad? +This will cost resources (because the base has to be +somewhere), and make the code less readable. + +### Example +``` +Point { + x: 1, + y: 1, + z: 1, + ..zero_point +}; +``` + +Use instead: +``` +// Missing field `z` +Point { + x: 1, + y: 1, + ..zero_point +}; +``` \ No newline at end of file diff --git a/src/docs/neg_cmp_op_on_partial_ord.txt b/src/docs/neg_cmp_op_on_partial_ord.txt new file mode 100644 index 000000000000..fa55c6cfd74b --- /dev/null +++ b/src/docs/neg_cmp_op_on_partial_ord.txt @@ -0,0 +1,26 @@ +### What it does +Checks for the usage of negated comparison operators on types which only implement +`PartialOrd` (e.g., `f64`). + +### Why is this bad? +These operators make it easy to forget that the underlying types actually allow not only three +potential Orderings (Less, Equal, Greater) but also a fourth one (Uncomparable). This is +especially easy to miss if the operator based comparison result is negated. + +### Example +``` +let a = 1.0; +let b = f64::NAN; + +let not_less_or_equal = !(a <= b); +``` + +Use instead: +``` +use std::cmp::Ordering; + +let _not_less_or_equal = match a.partial_cmp(&b) { + None | Some(Ordering::Greater) => true, + _ => false, +}; +``` \ No newline at end of file diff --git a/src/docs/neg_multiply.txt b/src/docs/neg_multiply.txt new file mode 100644 index 000000000000..4e8b096eb9cc --- /dev/null +++ b/src/docs/neg_multiply.txt @@ -0,0 +1,18 @@ +### What it does +Checks for multiplication by -1 as a form of negation. + +### Why is this bad? +It's more readable to just negate. + +### Known problems +This only catches integers (for now). + +### Example +``` +let a = x * -1; +``` + +Use instead: +``` +let a = -x; +``` \ No newline at end of file diff --git a/src/docs/negative_feature_names.txt b/src/docs/negative_feature_names.txt new file mode 100644 index 000000000000..01ee9efb318b --- /dev/null +++ b/src/docs/negative_feature_names.txt @@ -0,0 +1,22 @@ +### What it does +Checks for negative feature names with prefix `no-` or `not-` + +### Why is this bad? +Features are supposed to be additive, and negatively-named features violate it. + +### Example +``` +[features] +default = [] +no-abc = [] +not-def = [] + +``` +Use instead: +``` +[features] +default = ["abc", "def"] +abc = [] +def = [] + +``` \ No newline at end of file diff --git a/src/docs/never_loop.txt b/src/docs/never_loop.txt new file mode 100644 index 000000000000..737ccf415cb9 --- /dev/null +++ b/src/docs/never_loop.txt @@ -0,0 +1,15 @@ +### What it does +Checks for loops that will always `break`, `return` or +`continue` an outer loop. + +### Why is this bad? +This loop never loops, all it does is obfuscating the +code. + +### Example +``` +loop { + ..; + break; +} +``` \ No newline at end of file diff --git a/src/docs/new_ret_no_self.txt b/src/docs/new_ret_no_self.txt new file mode 100644 index 000000000000..291bad24a643 --- /dev/null +++ b/src/docs/new_ret_no_self.txt @@ -0,0 +1,47 @@ +### What it does +Checks for `new` not returning a type that contains `Self`. + +### Why is this bad? +As a convention, `new` methods are used to make a new +instance of a type. + +### Example +In an impl block: +``` +impl Foo { + fn new() -> NotAFoo { + } +} +``` + +``` +struct Bar(Foo); +impl Foo { + // Bad. The type name must contain `Self` + fn new() -> Bar { + } +} +``` + +``` +impl Foo { + // Good. Return type contains `Self` + fn new() -> Result { + } +} +``` + +Or in a trait definition: +``` +pub trait Trait { + // Bad. The type name must contain `Self` + fn new(); +} +``` + +``` +pub trait Trait { + // Good. Return type contains `Self` + fn new() -> Self; +} +``` \ No newline at end of file diff --git a/src/docs/new_without_default.txt b/src/docs/new_without_default.txt new file mode 100644 index 000000000000..662d39c8efdd --- /dev/null +++ b/src/docs/new_without_default.txt @@ -0,0 +1,32 @@ +### What it does +Checks for public types with a `pub fn new() -> Self` method and no +implementation of +[`Default`](https://doc.rust-lang.org/std/default/trait.Default.html). + +### Why is this bad? +The user might expect to be able to use +[`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) as the +type can be constructed without arguments. + +### Example +``` +pub struct Foo(Bar); + +impl Foo { + pub fn new() -> Self { + Foo(Bar::new()) + } +} +``` + +To fix the lint, add a `Default` implementation that delegates to `new`: + +``` +pub struct Foo(Bar); + +impl Default for Foo { + fn default() -> Self { + Foo::new() + } +} +``` \ No newline at end of file diff --git a/src/docs/no_effect.txt b/src/docs/no_effect.txt new file mode 100644 index 000000000000..d4cc08fa8a7d --- /dev/null +++ b/src/docs/no_effect.txt @@ -0,0 +1,12 @@ +### What it does +Checks for statements which have no effect. + +### Why is this bad? +Unlike dead code, these statements are actually +executed. However, as they have no effect, all they do is make the code less +readable. + +### Example +``` +0; +``` \ No newline at end of file diff --git a/src/docs/no_effect_replace.txt b/src/docs/no_effect_replace.txt new file mode 100644 index 000000000000..646d45287ef5 --- /dev/null +++ b/src/docs/no_effect_replace.txt @@ -0,0 +1,11 @@ +### What it does +Checks for `replace` statements which have no effect. + +### Why is this bad? +It's either a mistake or confusing. + +### Example +``` +"1234".replace("12", "12"); +"1234".replacen("12", "12", 1); +``` \ No newline at end of file diff --git a/src/docs/no_effect_underscore_binding.txt b/src/docs/no_effect_underscore_binding.txt new file mode 100644 index 000000000000..972f60dd01e9 --- /dev/null +++ b/src/docs/no_effect_underscore_binding.txt @@ -0,0 +1,16 @@ +### What it does +Checks for binding to underscore prefixed variable without side-effects. + +### Why is this bad? +Unlike dead code, these bindings are actually +executed. However, as they have no effect and shouldn't be used further on, all they +do is make the code less readable. + +### Known problems +Further usage of this variable is not checked, which can lead to false positives if it is +used later in the code. + +### Example +``` +let _i_serve_no_purpose = 1; +``` \ No newline at end of file diff --git a/src/docs/non_ascii_literal.txt b/src/docs/non_ascii_literal.txt new file mode 100644 index 000000000000..164902b4726e --- /dev/null +++ b/src/docs/non_ascii_literal.txt @@ -0,0 +1,19 @@ +### What it does +Checks for non-ASCII characters in string and char literals. + +### Why is this bad? +Yeah, we know, the 90's called and wanted their charset +back. Even so, there still are editors and other programs out there that +don't work well with Unicode. So if the code is meant to be used +internationally, on multiple operating systems, or has other portability +requirements, activating this lint could be useful. + +### Example +``` +let x = String::from("€"); +``` + +Use instead: +``` +let x = String::from("\u{20ac}"); +``` \ No newline at end of file diff --git a/src/docs/non_octal_unix_permissions.txt b/src/docs/non_octal_unix_permissions.txt new file mode 100644 index 000000000000..4a468e94db16 --- /dev/null +++ b/src/docs/non_octal_unix_permissions.txt @@ -0,0 +1,23 @@ +### What it does +Checks for non-octal values used to set Unix file permissions. + +### Why is this bad? +They will be converted into octal, creating potentially +unintended file permissions. + +### Example +``` +use std::fs::OpenOptions; +use std::os::unix::fs::OpenOptionsExt; + +let mut options = OpenOptions::new(); +options.mode(644); +``` +Use instead: +``` +use std::fs::OpenOptions; +use std::os::unix::fs::OpenOptionsExt; + +let mut options = OpenOptions::new(); +options.mode(0o644); +``` \ No newline at end of file diff --git a/src/docs/non_send_fields_in_send_ty.txt b/src/docs/non_send_fields_in_send_ty.txt new file mode 100644 index 000000000000..11e6f6e162cf --- /dev/null +++ b/src/docs/non_send_fields_in_send_ty.txt @@ -0,0 +1,36 @@ +### What it does +This lint warns about a `Send` implementation for a type that +contains fields that are not safe to be sent across threads. +It tries to detect fields that can cause a soundness issue +when sent to another thread (e.g., `Rc`) while allowing `!Send` fields +that are expected to exist in a `Send` type, such as raw pointers. + +### Why is this bad? +Sending the struct to another thread effectively sends all of its fields, +and the fields that do not implement `Send` can lead to soundness bugs +such as data races when accessed in a thread +that is different from the thread that created it. + +See: +* [*The Rustonomicon* about *Send and Sync*](https://doc.rust-lang.org/nomicon/send-and-sync.html) +* [The documentation of `Send`](https://doc.rust-lang.org/std/marker/trait.Send.html) + +### Known Problems +This lint relies on heuristics to distinguish types that are actually +unsafe to be sent across threads and `!Send` types that are expected to +exist in `Send` type. Its rule can filter out basic cases such as +`Vec<*const T>`, but it's not perfect. Feel free to create an issue if +you have a suggestion on how this heuristic can be improved. + +### Example +``` +struct ExampleStruct { + rc_is_not_send: Rc, + unbounded_generic_field: T, +} + +// This impl is unsound because it allows sending `!Send` types through `ExampleStruct` +unsafe impl Send for ExampleStruct {} +``` +Use thread-safe types like [`std::sync::Arc`](https://doc.rust-lang.org/std/sync/struct.Arc.html) +or specify correct bounds on generic type parameters (`T: Send`). \ No newline at end of file diff --git a/src/docs/nonminimal_bool.txt b/src/docs/nonminimal_bool.txt new file mode 100644 index 000000000000..488980ddf023 --- /dev/null +++ b/src/docs/nonminimal_bool.txt @@ -0,0 +1,23 @@ +### What it does +Checks for boolean expressions that can be written more +concisely. + +### Why is this bad? +Readability of boolean expressions suffers from +unnecessary duplication. + +### Known problems +Ignores short circuiting behavior of `||` and +`&&`. Ignores `|`, `&` and `^`. + +### Example +``` +if a && true {} +if !(a == b) {} +``` + +Use instead: +``` +if a {} +if a != b {} +``` \ No newline at end of file diff --git a/src/docs/nonsensical_open_options.txt b/src/docs/nonsensical_open_options.txt new file mode 100644 index 000000000000..7a95443b51a5 --- /dev/null +++ b/src/docs/nonsensical_open_options.txt @@ -0,0 +1,14 @@ +### What it does +Checks for duplicate open options as well as combinations +that make no sense. + +### Why is this bad? +In the best case, the code will be harder to read than +necessary. I don't know the worst case. + +### Example +``` +use std::fs::OpenOptions; + +OpenOptions::new().read(true).truncate(true); +``` \ No newline at end of file diff --git a/src/docs/nonstandard_macro_braces.txt b/src/docs/nonstandard_macro_braces.txt new file mode 100644 index 000000000000..7e8d0d2d33bf --- /dev/null +++ b/src/docs/nonstandard_macro_braces.txt @@ -0,0 +1,15 @@ +### What it does +Checks that common macros are used with consistent bracing. + +### Why is this bad? +This is mostly a consistency lint although using () or [] +doesn't give you a semicolon in item position, which can be unexpected. + +### Example +``` +vec!{1, 2, 3}; +``` +Use instead: +``` +vec![1, 2, 3]; +``` \ No newline at end of file diff --git a/src/docs/not_unsafe_ptr_arg_deref.txt b/src/docs/not_unsafe_ptr_arg_deref.txt new file mode 100644 index 000000000000..31355fbb7b66 --- /dev/null +++ b/src/docs/not_unsafe_ptr_arg_deref.txt @@ -0,0 +1,30 @@ +### What it does +Checks for public functions that dereference raw pointer +arguments but are not marked `unsafe`. + +### Why is this bad? +The function should probably be marked `unsafe`, since +for an arbitrary raw pointer, there is no way of telling for sure if it is +valid. + +### Known problems +* It does not check functions recursively so if the pointer is passed to a +private non-`unsafe` function which does the dereferencing, the lint won't +trigger. +* It only checks for arguments whose type are raw pointers, not raw pointers +got from an argument in some other way (`fn foo(bar: &[*const u8])` or +`some_argument.get_raw_ptr()`). + +### Example +``` +pub fn foo(x: *const u8) { + println!("{}", unsafe { *x }); +} +``` + +Use instead: +``` +pub unsafe fn foo(x: *const u8) { + println!("{}", unsafe { *x }); +} +``` \ No newline at end of file diff --git a/src/docs/obfuscated_if_else.txt b/src/docs/obfuscated_if_else.txt new file mode 100644 index 000000000000..638f63b0db5e --- /dev/null +++ b/src/docs/obfuscated_if_else.txt @@ -0,0 +1,21 @@ +### What it does +Checks for usages of `.then_some(..).unwrap_or(..)` + +### Why is this bad? +This can be written more clearly with `if .. else ..` + +### Limitations +This lint currently only looks for usages of +`.then_some(..).unwrap_or(..)`, but will be expanded +to account for similar patterns. + +### Example +``` +let x = true; +x.then_some("a").unwrap_or("b"); +``` +Use instead: +``` +let x = true; +if x { "a" } else { "b" }; +``` \ No newline at end of file diff --git a/src/docs/octal_escapes.txt b/src/docs/octal_escapes.txt new file mode 100644 index 000000000000..eee820587158 --- /dev/null +++ b/src/docs/octal_escapes.txt @@ -0,0 +1,33 @@ +### What it does +Checks for `\0` escapes in string and byte literals that look like octal +character escapes in C. + +### Why is this bad? + +C and other languages support octal character escapes in strings, where +a backslash is followed by up to three octal digits. For example, `\033` +stands for the ASCII character 27 (ESC). Rust does not support this +notation, but has the escape code `\0` which stands for a null +byte/character, and any following digits do not form part of the escape +sequence. Therefore, `\033` is not a compiler error but the result may +be surprising. + +### Known problems +The actual meaning can be the intended one. `\x00` can be used in these +cases to be unambiguous. + +The lint does not trigger for format strings in `print!()`, `write!()` +and friends since the string is already preprocessed when Clippy lints +can see it. + +### Example +``` +let one = "\033[1m Bold? \033[0m"; // \033 intended as escape +let two = "\033\0"; // \033 intended as null-3-3 +``` + +Use instead: +``` +let one = "\x1b[1mWill this be bold?\x1b[0m"; +let two = "\x0033\x00"; +``` \ No newline at end of file diff --git a/src/docs/ok_expect.txt b/src/docs/ok_expect.txt new file mode 100644 index 000000000000..fd5205d49dc0 --- /dev/null +++ b/src/docs/ok_expect.txt @@ -0,0 +1,19 @@ +### What it does +Checks for usage of `ok().expect(..)`. + +### Why is this bad? +Because you usually call `expect()` on the `Result` +directly to get a better error message. + +### Known problems +The error type needs to implement `Debug` + +### Example +``` +x.ok().expect("why did I do this again?"); +``` + +Use instead: +``` +x.expect("why did I do this again?"); +``` \ No newline at end of file diff --git a/src/docs/only_used_in_recursion.txt b/src/docs/only_used_in_recursion.txt new file mode 100644 index 000000000000..f19f47ff9eb5 --- /dev/null +++ b/src/docs/only_used_in_recursion.txt @@ -0,0 +1,58 @@ +### What it does +Checks for arguments that are only used in recursion with no side-effects. + +### Why is this bad? +It could contain a useless calculation and can make function simpler. + +The arguments can be involved in calculations and assignments but as long as +the calculations have no side-effects (function calls or mutating dereference) +and the assigned variables are also only in recursion, it is useless. + +### Known problems +Too many code paths in the linting code are currently untested and prone to produce false +positives or are prone to have performance implications. + +In some cases, this would not catch all useless arguments. + +``` +fn foo(a: usize, b: usize) -> usize { + let f = |x| x + 1; + + if a == 0 { + 1 + } else { + foo(a - 1, f(b)) + } +} +``` + +For example, the argument `b` is only used in recursion, but the lint would not catch it. + +List of some examples that can not be caught: +- binary operation of non-primitive types +- closure usage +- some `break` relative operations +- struct pattern binding + +Also, when you recurse the function name with path segments, it is not possible to detect. + +### Example +``` +fn f(a: usize, b: usize) -> usize { + if a == 0 { + 1 + } else { + f(a - 1, b + 1) + } +} +``` +Use instead: +``` +fn f(a: usize) -> usize { + if a == 0 { + 1 + } else { + f(a - 1) + } +} +``` \ No newline at end of file diff --git a/src/docs/op_ref.txt b/src/docs/op_ref.txt new file mode 100644 index 000000000000..7a7ed1bc9bad --- /dev/null +++ b/src/docs/op_ref.txt @@ -0,0 +1,17 @@ +### What it does +Checks for arguments to `==` which have their address +taken to satisfy a bound +and suggests to dereference the other argument instead + +### Why is this bad? +It is more idiomatic to dereference the other argument. + +### Example +``` +&x == y +``` + +Use instead: +``` +x == *y +``` \ No newline at end of file diff --git a/src/docs/option_as_ref_deref.txt b/src/docs/option_as_ref_deref.txt new file mode 100644 index 000000000000..ad7411d3d4bd --- /dev/null +++ b/src/docs/option_as_ref_deref.txt @@ -0,0 +1,15 @@ +### What it does +Checks for usage of `_.as_ref().map(Deref::deref)` or it's aliases (such as String::as_str). + +### Why is this bad? +Readability, this can be written more concisely as +`_.as_deref()`. + +### Example +``` +opt.as_ref().map(String::as_str) +``` +Can be written as +``` +opt.as_deref() +``` \ No newline at end of file diff --git a/src/docs/option_env_unwrap.txt b/src/docs/option_env_unwrap.txt new file mode 100644 index 000000000000..c952cba8e261 --- /dev/null +++ b/src/docs/option_env_unwrap.txt @@ -0,0 +1,19 @@ +### What it does +Checks for usage of `option_env!(...).unwrap()` and +suggests usage of the `env!` macro. + +### Why is this bad? +Unwrapping the result of `option_env!` will panic +at run-time if the environment variable doesn't exist, whereas `env!` +catches it at compile-time. + +### Example +``` +let _ = option_env!("HOME").unwrap(); +``` + +Is better expressed as: + +``` +let _ = env!("HOME"); +``` \ No newline at end of file diff --git a/src/docs/option_filter_map.txt b/src/docs/option_filter_map.txt new file mode 100644 index 000000000000..25f7bde7b4d0 --- /dev/null +++ b/src/docs/option_filter_map.txt @@ -0,0 +1,15 @@ +### What it does +Checks for indirect collection of populated `Option` + +### Why is this bad? +`Option` is like a collection of 0-1 things, so `flatten` +automatically does this without suspicious-looking `unwrap` calls. + +### Example +``` +let _ = std::iter::empty::>().filter(Option::is_some).map(Option::unwrap); +``` +Use instead: +``` +let _ = std::iter::empty::>().flatten(); +``` \ No newline at end of file diff --git a/src/docs/option_if_let_else.txt b/src/docs/option_if_let_else.txt new file mode 100644 index 000000000000..43652db513b4 --- /dev/null +++ b/src/docs/option_if_let_else.txt @@ -0,0 +1,46 @@ +### What it does +Lints usage of `if let Some(v) = ... { y } else { x }` and +`match .. { Some(v) => y, None/_ => x }` which are more +idiomatically done with `Option::map_or` (if the else bit is a pure +expression) or `Option::map_or_else` (if the else bit is an impure +expression). + +### Why is this bad? +Using the dedicated functions of the `Option` type is clearer and +more concise than an `if let` expression. + +### Known problems +This lint uses a deliberately conservative metric for checking +if the inside of either body contains breaks or continues which will +cause it to not suggest a fix if either block contains a loop with +continues or breaks contained within the loop. + +### Example +``` +let _ = if let Some(foo) = optional { + foo +} else { + 5 +}; +let _ = match optional { + Some(val) => val + 1, + None => 5 +}; +let _ = if let Some(foo) = optional { + foo +} else { + let y = do_complicated_function(); + y*y +}; +``` + +should be + +``` +let _ = optional.map_or(5, |foo| foo); +let _ = optional.map_or(5, |val| val + 1); +let _ = optional.map_or_else(||{ + let y = do_complicated_function(); + y*y +}, |foo| foo); +``` \ No newline at end of file diff --git a/src/docs/option_map_or_none.txt b/src/docs/option_map_or_none.txt new file mode 100644 index 000000000000..c86c65215f01 --- /dev/null +++ b/src/docs/option_map_or_none.txt @@ -0,0 +1,19 @@ +### What it does +Checks for usage of `_.map_or(None, _)`. + +### Why is this bad? +Readability, this can be written more concisely as +`_.and_then(_)`. + +### Known problems +The order of the arguments is not in execution order. + +### Example +``` +opt.map_or(None, |a| Some(a + 1)); +``` + +Use instead: +``` +opt.and_then(|a| Some(a + 1)); +``` \ No newline at end of file diff --git a/src/docs/option_map_unit_fn.txt b/src/docs/option_map_unit_fn.txt new file mode 100644 index 000000000000..fc4b528f0923 --- /dev/null +++ b/src/docs/option_map_unit_fn.txt @@ -0,0 +1,27 @@ +### What it does +Checks for usage of `option.map(f)` where f is a function +or closure that returns the unit type `()`. + +### Why is this bad? +Readability, this can be written more clearly with +an if let statement + +### Example +``` +let x: Option = do_stuff(); +x.map(log_err_msg); +x.map(|msg| log_err_msg(format_msg(msg))); +``` + +The correct use would be: + +``` +let x: Option = do_stuff(); +if let Some(msg) = x { + log_err_msg(msg); +} + +if let Some(msg) = x { + log_err_msg(format_msg(msg)); +} +``` \ No newline at end of file diff --git a/src/docs/option_option.txt b/src/docs/option_option.txt new file mode 100644 index 000000000000..b4324bd83990 --- /dev/null +++ b/src/docs/option_option.txt @@ -0,0 +1,32 @@ +### What it does +Checks for use of `Option>` in function signatures and type +definitions + +### Why is this bad? +`Option<_>` represents an optional value. `Option>` +represents an optional optional value which is logically the same thing as an optional +value but has an unneeded extra level of wrapping. + +If you have a case where `Some(Some(_))`, `Some(None)` and `None` are distinct cases, +consider a custom `enum` instead, with clear names for each case. + +### Example +``` +fn get_data() -> Option> { + None +} +``` + +Better: + +``` +pub enum Contents { + Data(Vec), // Was Some(Some(Vec)) + NotYetFetched, // Was Some(None) + None, // Was None +} + +fn get_data() -> Contents { + Contents::None +} +``` \ No newline at end of file diff --git a/src/docs/or_fun_call.txt b/src/docs/or_fun_call.txt new file mode 100644 index 000000000000..5605e96c98ee --- /dev/null +++ b/src/docs/or_fun_call.txt @@ -0,0 +1,26 @@ +### What it does +Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`, +etc., and suggests to use `or_else`, `unwrap_or_else`, etc., or +`unwrap_or_default` instead. + +### Why is this bad? +The function will always be called and potentially +allocate an object acting as the default. + +### Known problems +If the function has side-effects, not calling it will +change the semantic of the program, but you shouldn't rely on that anyway. + +### Example +``` +foo.unwrap_or(String::new()); +``` + +Use instead: +``` +foo.unwrap_or_else(String::new); + +// or + +foo.unwrap_or_default(); +``` \ No newline at end of file diff --git a/src/docs/or_then_unwrap.txt b/src/docs/or_then_unwrap.txt new file mode 100644 index 000000000000..64ac53749e8a --- /dev/null +++ b/src/docs/or_then_unwrap.txt @@ -0,0 +1,22 @@ +### What it does +Checks for `.or(…).unwrap()` calls to Options and Results. + +### Why is this bad? +You should use `.unwrap_or(…)` instead for clarity. + +### Example +``` +// Result +let value = result.or::(Ok(fallback)).unwrap(); + +// Option +let value = option.or(Some(fallback)).unwrap(); +``` +Use instead: +``` +// Result +let value = result.unwrap_or(fallback); + +// Option +let value = option.unwrap_or(fallback); +``` \ No newline at end of file diff --git a/src/docs/out_of_bounds_indexing.txt b/src/docs/out_of_bounds_indexing.txt new file mode 100644 index 000000000000..5802eea29966 --- /dev/null +++ b/src/docs/out_of_bounds_indexing.txt @@ -0,0 +1,22 @@ +### What it does +Checks for out of bounds array indexing with a constant +index. + +### Why is this bad? +This will always panic at runtime. + +### Example +``` +let x = [1, 2, 3, 4]; + +x[9]; +&x[2..9]; +``` + +Use instead: +``` +// Index within bounds + +x[0]; +x[3]; +``` \ No newline at end of file diff --git a/src/docs/overflow_check_conditional.txt b/src/docs/overflow_check_conditional.txt new file mode 100644 index 000000000000..a09cc18a0bcc --- /dev/null +++ b/src/docs/overflow_check_conditional.txt @@ -0,0 +1,11 @@ +### What it does +Detects classic underflow/overflow checks. + +### Why is this bad? +Most classic C underflow/overflow checks will fail in +Rust. Users can use functions like `overflowing_*` and `wrapping_*` instead. + +### Example +``` +a + b < a; +``` \ No newline at end of file diff --git a/src/docs/overly_complex_bool_expr.txt b/src/docs/overly_complex_bool_expr.txt new file mode 100644 index 000000000000..65ca18392e75 --- /dev/null +++ b/src/docs/overly_complex_bool_expr.txt @@ -0,0 +1,20 @@ +### What it does +Checks for boolean expressions that contain terminals that +can be eliminated. + +### Why is this bad? +This is most likely a logic bug. + +### Known problems +Ignores short circuiting behavior. + +### Example +``` +// The `b` is unnecessary, the expression is equivalent to `if a`. +if a && b || a { ... } +``` + +Use instead: +``` +if a {} +``` \ No newline at end of file diff --git a/src/docs/panic.txt b/src/docs/panic.txt new file mode 100644 index 000000000000..f9bdc6e87ccf --- /dev/null +++ b/src/docs/panic.txt @@ -0,0 +1,10 @@ +### What it does +Checks for usage of `panic!`. + +### Why is this bad? +`panic!` will stop the execution of the executable + +### Example +``` +panic!("even with a good reason"); +``` \ No newline at end of file diff --git a/src/docs/panic_in_result_fn.txt b/src/docs/panic_in_result_fn.txt new file mode 100644 index 000000000000..51c2f8ae5a30 --- /dev/null +++ b/src/docs/panic_in_result_fn.txt @@ -0,0 +1,22 @@ +### What it does +Checks for usage of `panic!`, `unimplemented!`, `todo!`, `unreachable!` or assertions in a function of type result. + +### Why is this bad? +For some codebases, it is desirable for functions of type result to return an error instead of crashing. Hence panicking macros should be avoided. + +### Known problems +Functions called from a function returning a `Result` may invoke a panicking macro. This is not checked. + +### Example +``` +fn result_with_panic() -> Result +{ + panic!("error"); +} +``` +Use instead: +``` +fn result_without_panic() -> Result { + Err(String::from("error")) +} +``` \ No newline at end of file diff --git a/src/docs/panicking_unwrap.txt b/src/docs/panicking_unwrap.txt new file mode 100644 index 000000000000..1fbc245c8ec3 --- /dev/null +++ b/src/docs/panicking_unwrap.txt @@ -0,0 +1,18 @@ +### What it does +Checks for calls of `unwrap[_err]()` that will always fail. + +### Why is this bad? +If panicking is desired, an explicit `panic!()` should be used. + +### Known problems +This lint only checks `if` conditions not assignments. +So something like `let x: Option<()> = None; x.unwrap();` will not be recognized. + +### Example +``` +if option.is_none() { + do_something_with(option.unwrap()) +} +``` + +This code will always panic. The if condition should probably be inverted. \ No newline at end of file diff --git a/src/docs/partialeq_ne_impl.txt b/src/docs/partialeq_ne_impl.txt new file mode 100644 index 000000000000..78f55188bab8 --- /dev/null +++ b/src/docs/partialeq_ne_impl.txt @@ -0,0 +1,18 @@ +### What it does +Checks for manual re-implementations of `PartialEq::ne`. + +### Why is this bad? +`PartialEq::ne` is required to always return the +negated result of `PartialEq::eq`, which is exactly what the default +implementation does. Therefore, there should never be any need to +re-implement it. + +### Example +``` +struct Foo; + +impl PartialEq for Foo { + fn eq(&self, other: &Foo) -> bool { true } + fn ne(&self, other: &Foo) -> bool { !(self == other) } +} +``` \ No newline at end of file diff --git a/src/docs/partialeq_to_none.txt b/src/docs/partialeq_to_none.txt new file mode 100644 index 000000000000..5cc07bf88435 --- /dev/null +++ b/src/docs/partialeq_to_none.txt @@ -0,0 +1,24 @@ +### What it does + +Checks for binary comparisons to a literal `Option::None`. + +### Why is this bad? + +A programmer checking if some `foo` is `None` via a comparison `foo == None` +is usually inspired from other programming languages (e.g. `foo is None` +in Python). +Checking if a value of type `Option` is (not) equal to `None` in that +way relies on `T: PartialEq` to do the comparison, which is unneeded. + +### Example +``` +fn foo(f: Option) -> &'static str { + if f != None { "yay" } else { "nay" } +} +``` +Use instead: +``` +fn foo(f: Option) -> &'static str { + if f.is_some() { "yay" } else { "nay" } +} +``` \ No newline at end of file diff --git a/src/docs/path_buf_push_overwrite.txt b/src/docs/path_buf_push_overwrite.txt new file mode 100644 index 000000000000..34f8901da239 --- /dev/null +++ b/src/docs/path_buf_push_overwrite.txt @@ -0,0 +1,25 @@ +### What it does +* Checks for [push](https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.push) +calls on `PathBuf` that can cause overwrites. + +### Why is this bad? +Calling `push` with a root path at the start can overwrite the +previous defined path. + +### Example +``` +use std::path::PathBuf; + +let mut x = PathBuf::from("/foo"); +x.push("/bar"); +assert_eq!(x, PathBuf::from("/bar")); +``` +Could be written: + +``` +use std::path::PathBuf; + +let mut x = PathBuf::from("/foo"); +x.push("bar"); +assert_eq!(x, PathBuf::from("/foo/bar")); +``` \ No newline at end of file diff --git a/src/docs/pattern_type_mismatch.txt b/src/docs/pattern_type_mismatch.txt new file mode 100644 index 000000000000..64da881d592a --- /dev/null +++ b/src/docs/pattern_type_mismatch.txt @@ -0,0 +1,64 @@ +### What it does +Checks for patterns that aren't exact representations of the types +they are applied to. + +To satisfy this lint, you will have to adjust either the expression that is matched +against or the pattern itself, as well as the bindings that are introduced by the +adjusted patterns. For matching you will have to either dereference the expression +with the `*` operator, or amend the patterns to explicitly match against `&` +or `&mut ` depending on the reference mutability. For the bindings you need +to use the inverse. You can leave them as plain bindings if you wish for the value +to be copied, but you must use `ref mut ` or `ref ` to construct +a reference into the matched structure. + +If you are looking for a way to learn about ownership semantics in more detail, it +is recommended to look at IDE options available to you to highlight types, lifetimes +and reference semantics in your code. The available tooling would expose these things +in a general way even outside of the various pattern matching mechanics. Of course +this lint can still be used to highlight areas of interest and ensure a good understanding +of ownership semantics. + +### Why is this bad? +It isn't bad in general. But in some contexts it can be desirable +because it increases ownership hints in the code, and will guard against some changes +in ownership. + +### Example +This example shows the basic adjustments necessary to satisfy the lint. Note how +the matched expression is explicitly dereferenced with `*` and the `inner` variable +is bound to a shared borrow via `ref inner`. + +``` +// Bad +let value = &Some(Box::new(23)); +match value { + Some(inner) => println!("{}", inner), + None => println!("none"), +} + +// Good +let value = &Some(Box::new(23)); +match *value { + Some(ref inner) => println!("{}", inner), + None => println!("none"), +} +``` + +The following example demonstrates one of the advantages of the more verbose style. +Note how the second version uses `ref mut a` to explicitly declare `a` a shared mutable +borrow, while `b` is simply taken by value. This ensures that the loop body cannot +accidentally modify the wrong part of the structure. + +``` +// Bad +let mut values = vec![(2, 3), (3, 4)]; +for (a, b) in &mut values { + *a += *b; +} + +// Good +let mut values = vec![(2, 3), (3, 4)]; +for &mut (ref mut a, b) in &mut values { + *a += b; +} +``` \ No newline at end of file diff --git a/src/docs/positional_named_format_parameters.txt b/src/docs/positional_named_format_parameters.txt new file mode 100644 index 000000000000..e391d2406677 --- /dev/null +++ b/src/docs/positional_named_format_parameters.txt @@ -0,0 +1,15 @@ +### What it does +This lint warns when a named parameter in a format string is used as a positional one. + +### Why is this bad? +It may be confused for an assignment and obfuscates which parameter is being used. + +### Example +``` +println!("{}", x = 10); +``` + +Use instead: +``` +println!("{x}", x = 10); +``` \ No newline at end of file diff --git a/src/docs/possible_missing_comma.txt b/src/docs/possible_missing_comma.txt new file mode 100644 index 000000000000..5d92f4cae91e --- /dev/null +++ b/src/docs/possible_missing_comma.txt @@ -0,0 +1,14 @@ +### What it does +Checks for possible missing comma in an array. It lints if +an array element is a binary operator expression and it lies on two lines. + +### Why is this bad? +This could lead to unexpected results. + +### Example +``` +let a = &[ + -1, -2, -3 // <= no comma here + -4, -5, -6 +]; +``` \ No newline at end of file diff --git a/src/docs/precedence.txt b/src/docs/precedence.txt new file mode 100644 index 000000000000..fda0b831f335 --- /dev/null +++ b/src/docs/precedence.txt @@ -0,0 +1,17 @@ +### What it does +Checks for operations where precedence may be unclear +and suggests to add parentheses. Currently it catches the following: +* mixed usage of arithmetic and bit shifting/combining operators without +parentheses +* a "negative" numeric literal (which is really a unary `-` followed by a +numeric literal) + followed by a method call + +### Why is this bad? +Not everyone knows the precedence of those operators by +heart, so expressions like these may trip others trying to reason about the +code. + +### Example +* `1 << 2 + 3` equals 32, while `(1 << 2) + 3` equals 7 +* `-1i32.abs()` equals -1, while `(-1i32).abs()` equals 1 \ No newline at end of file diff --git a/src/docs/print_in_format_impl.txt b/src/docs/print_in_format_impl.txt new file mode 100644 index 000000000000..140d23d6faab --- /dev/null +++ b/src/docs/print_in_format_impl.txt @@ -0,0 +1,34 @@ +### What it does +Checks for use of `println`, `print`, `eprintln` or `eprint` in an +implementation of a formatting trait. + +### Why is this bad? +Using a print macro is likely unintentional since formatting traits +should write to the `Formatter`, not stdout/stderr. + +### Example +``` +use std::fmt::{Display, Error, Formatter}; + +struct S; +impl Display for S { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + println!("S"); + + Ok(()) + } +} +``` +Use instead: +``` +use std::fmt::{Display, Error, Formatter}; + +struct S; +impl Display for S { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + writeln!(f, "S"); + + Ok(()) + } +} +``` \ No newline at end of file diff --git a/src/docs/print_literal.txt b/src/docs/print_literal.txt new file mode 100644 index 000000000000..160073414f9a --- /dev/null +++ b/src/docs/print_literal.txt @@ -0,0 +1,20 @@ +### What it does +This lint warns about the use of literals as `print!`/`println!` args. + +### Why is this bad? +Using literals as `println!` args is inefficient +(c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary +(i.e., just put the literal in the format string) + +### Known problems +Will also warn with macro calls as arguments that expand to literals +-- e.g., `println!("{}", env!("FOO"))`. + +### Example +``` +println!("{}", "foo"); +``` +use the literal without formatting: +``` +println!("foo"); +``` \ No newline at end of file diff --git a/src/docs/print_stderr.txt b/src/docs/print_stderr.txt new file mode 100644 index 000000000000..fc14511cd6a6 --- /dev/null +++ b/src/docs/print_stderr.txt @@ -0,0 +1,21 @@ +### What it does +Checks for printing on *stderr*. The purpose of this lint +is to catch debugging remnants. + +### Why is this bad? +People often print on *stderr* while debugging an +application and might forget to remove those prints afterward. + +### Known problems +* Only catches `eprint!` and `eprintln!` calls. +* The lint level is unaffected by crate attributes. The level can still + be set for functions, modules and other items. To change the level for + the entire crate, please use command line flags. More information and a + configuration example can be found in [clippy#6610]. + +[clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558 + +### Example +``` +eprintln!("Hello world!"); +``` \ No newline at end of file diff --git a/src/docs/print_stdout.txt b/src/docs/print_stdout.txt new file mode 100644 index 000000000000..6c9a4b98e1e6 --- /dev/null +++ b/src/docs/print_stdout.txt @@ -0,0 +1,21 @@ +### What it does +Checks for printing on *stdout*. The purpose of this lint +is to catch debugging remnants. + +### Why is this bad? +People often print on *stdout* while debugging an +application and might forget to remove those prints afterward. + +### Known problems +* Only catches `print!` and `println!` calls. +* The lint level is unaffected by crate attributes. The level can still + be set for functions, modules and other items. To change the level for + the entire crate, please use command line flags. More information and a + configuration example can be found in [clippy#6610]. + +[clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558 + +### Example +``` +println!("Hello world!"); +``` \ No newline at end of file diff --git a/src/docs/print_with_newline.txt b/src/docs/print_with_newline.txt new file mode 100644 index 000000000000..640323e822db --- /dev/null +++ b/src/docs/print_with_newline.txt @@ -0,0 +1,16 @@ +### What it does +This lint warns when you use `print!()` with a format +string that ends in a newline. + +### Why is this bad? +You should use `println!()` instead, which appends the +newline. + +### Example +``` +print!("Hello {}!\n", name); +``` +use println!() instead +``` +println!("Hello {}!", name); +``` \ No newline at end of file diff --git a/src/docs/println_empty_string.txt b/src/docs/println_empty_string.txt new file mode 100644 index 000000000000..b980413022ca --- /dev/null +++ b/src/docs/println_empty_string.txt @@ -0,0 +1,16 @@ +### What it does +This lint warns when you use `println!("")` to +print a newline. + +### Why is this bad? +You should use `println!()`, which is simpler. + +### Example +``` +println!(""); +``` + +Use instead: +``` +println!(); +``` \ No newline at end of file diff --git a/src/docs/ptr_arg.txt b/src/docs/ptr_arg.txt new file mode 100644 index 000000000000..796b0a65b717 --- /dev/null +++ b/src/docs/ptr_arg.txt @@ -0,0 +1,29 @@ +### What it does +This lint checks for function arguments of type `&String`, `&Vec`, +`&PathBuf`, and `Cow<_>`. It will also suggest you replace `.clone()` calls +with the appropriate `.to_owned()`/`to_string()` calls. + +### Why is this bad? +Requiring the argument to be of the specific size +makes the function less useful for no benefit; slices in the form of `&[T]` +or `&str` usually suffice and can be obtained from other types, too. + +### Known problems +There may be `fn(&Vec)`-typed references pointing to your function. +If you have them, you will get a compiler error after applying this lint's +suggestions. You then have the choice to undo your changes or change the +type of the reference. + +Note that if the function is part of your public interface, there may be +other crates referencing it, of which you may not be aware. Carefully +deprecate the function before applying the lint suggestions in this case. + +### Example +``` +fn foo(&Vec) { .. } +``` + +Use instead: +``` +fn foo(&[u32]) { .. } +``` \ No newline at end of file diff --git a/src/docs/ptr_as_ptr.txt b/src/docs/ptr_as_ptr.txt new file mode 100644 index 000000000000..8fb35c4aae8f --- /dev/null +++ b/src/docs/ptr_as_ptr.txt @@ -0,0 +1,22 @@ +### What it does +Checks for `as` casts between raw pointers without changing its mutability, +namely `*const T` to `*const U` and `*mut T` to `*mut U`. + +### Why is this bad? +Though `as` casts between raw pointers is not terrible, `pointer::cast` is safer because +it cannot accidentally change the pointer's mutability nor cast the pointer to other types like `usize`. + +### Example +``` +let ptr: *const u32 = &42_u32; +let mut_ptr: *mut u32 = &mut 42_u32; +let _ = ptr as *const i32; +let _ = mut_ptr as *mut i32; +``` +Use instead: +``` +let ptr: *const u32 = &42_u32; +let mut_ptr: *mut u32 = &mut 42_u32; +let _ = ptr.cast::(); +let _ = mut_ptr.cast::(); +``` \ No newline at end of file diff --git a/src/docs/ptr_eq.txt b/src/docs/ptr_eq.txt new file mode 100644 index 000000000000..06b36ca55e69 --- /dev/null +++ b/src/docs/ptr_eq.txt @@ -0,0 +1,22 @@ +### What it does +Use `std::ptr::eq` when applicable + +### Why is this bad? +`ptr::eq` can be used to compare `&T` references +(which coerce to `*const T` implicitly) by their address rather than +comparing the values they point to. + +### Example +``` +let a = &[1, 2, 3]; +let b = &[1, 2, 3]; + +assert!(a as *const _ as usize == b as *const _ as usize); +``` +Use instead: +``` +let a = &[1, 2, 3]; +let b = &[1, 2, 3]; + +assert!(std::ptr::eq(a, b)); +``` \ No newline at end of file diff --git a/src/docs/ptr_offset_with_cast.txt b/src/docs/ptr_offset_with_cast.txt new file mode 100644 index 000000000000..f204e769bf4b --- /dev/null +++ b/src/docs/ptr_offset_with_cast.txt @@ -0,0 +1,30 @@ +### What it does +Checks for usage of the `offset` pointer method with a `usize` casted to an +`isize`. + +### Why is this bad? +If we’re always increasing the pointer address, we can avoid the numeric +cast by using the `add` method instead. + +### Example +``` +let vec = vec![b'a', b'b', b'c']; +let ptr = vec.as_ptr(); +let offset = 1_usize; + +unsafe { + ptr.offset(offset as isize); +} +``` + +Could be written: + +``` +let vec = vec![b'a', b'b', b'c']; +let ptr = vec.as_ptr(); +let offset = 1_usize; + +unsafe { + ptr.add(offset); +} +``` \ No newline at end of file diff --git a/src/docs/pub_use.txt b/src/docs/pub_use.txt new file mode 100644 index 000000000000..407cafa01903 --- /dev/null +++ b/src/docs/pub_use.txt @@ -0,0 +1,28 @@ +### What it does + +Restricts the usage of `pub use ...` + +### Why is this bad? + +`pub use` is usually fine, but a project may wish to limit `pub use` instances to prevent +unintentional exports or to encourage placing exported items directly in public modules + +### Example +``` +pub mod outer { + mod inner { + pub struct Test {} + } + pub use inner::Test; +} + +use outer::Test; +``` +Use instead: +``` +pub mod outer { + pub struct Test {} +} + +use outer::Test; +``` \ No newline at end of file diff --git a/src/docs/question_mark.txt b/src/docs/question_mark.txt new file mode 100644 index 000000000000..4dc987be8813 --- /dev/null +++ b/src/docs/question_mark.txt @@ -0,0 +1,18 @@ +### What it does +Checks for expressions that could be replaced by the question mark operator. + +### Why is this bad? +Question mark usage is more idiomatic. + +### Example +``` +if option.is_none() { + return None; +} +``` + +Could be written: + +``` +option?; +``` \ No newline at end of file diff --git a/src/docs/range_minus_one.txt b/src/docs/range_minus_one.txt new file mode 100644 index 000000000000..fcb96dcc34ed --- /dev/null +++ b/src/docs/range_minus_one.txt @@ -0,0 +1,27 @@ +### What it does +Checks for inclusive ranges where 1 is subtracted from +the upper bound, e.g., `x..=(y-1)`. + +### Why is this bad? +The code is more readable with an exclusive range +like `x..y`. + +### Known problems +This will cause a warning that cannot be fixed if +the consumer of the range only accepts a specific range type, instead of +the generic `RangeBounds` trait +([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)). + +### Example +``` +for i in x..=(y-1) { + // .. +} +``` + +Use instead: +``` +for i in x..y { + // .. +} +``` \ No newline at end of file diff --git a/src/docs/range_plus_one.txt b/src/docs/range_plus_one.txt new file mode 100644 index 000000000000..193c85f9cbc7 --- /dev/null +++ b/src/docs/range_plus_one.txt @@ -0,0 +1,36 @@ +### What it does +Checks for exclusive ranges where 1 is added to the +upper bound, e.g., `x..(y+1)`. + +### Why is this bad? +The code is more readable with an inclusive range +like `x..=y`. + +### Known problems +Will add unnecessary pair of parentheses when the +expression is not wrapped in a pair but starts with an opening parenthesis +and ends with a closing one. +I.e., `let _ = (f()+1)..(f()+1)` results in `let _ = ((f()+1)..=f())`. + +Also in many cases, inclusive ranges are still slower to run than +exclusive ranges, because they essentially add an extra branch that +LLVM may fail to hoist out of the loop. + +This will cause a warning that cannot be fixed if the consumer of the +range only accepts a specific range type, instead of the generic +`RangeBounds` trait +([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)). + +### Example +``` +for i in x..(y+1) { + // .. +} +``` + +Use instead: +``` +for i in x..=y { + // .. +} +``` \ No newline at end of file diff --git a/src/docs/range_zip_with_len.txt b/src/docs/range_zip_with_len.txt new file mode 100644 index 000000000000..24c1efec789a --- /dev/null +++ b/src/docs/range_zip_with_len.txt @@ -0,0 +1,16 @@ +### What it does +Checks for zipping a collection with the range of +`0.._.len()`. + +### Why is this bad? +The code is better expressed with `.enumerate()`. + +### Example +``` +let _ = x.iter().zip(0..x.len()); +``` + +Use instead: +``` +let _ = x.iter().enumerate(); +``` \ No newline at end of file diff --git a/src/docs/rc_buffer.txt b/src/docs/rc_buffer.txt new file mode 100644 index 000000000000..82ac58eeb308 --- /dev/null +++ b/src/docs/rc_buffer.txt @@ -0,0 +1,27 @@ +### What it does +Checks for `Rc` and `Arc` when `T` is a mutable buffer type such as `String` or `Vec`. + +### Why is this bad? +Expressions such as `Rc` usually have no advantage over `Rc`, since +it is larger and involves an extra level of indirection, and doesn't implement `Borrow`. + +While mutating a buffer type would still be possible with `Rc::get_mut()`, it only +works if there are no additional references yet, which usually defeats the purpose of +enclosing it in a shared ownership type. Instead, additionally wrapping the inner +type with an interior mutable container (such as `RefCell` or `Mutex`) would normally +be used. + +### Known problems +This pattern can be desirable to avoid the overhead of a `RefCell` or `Mutex` for +cases where mutation only happens before there are any additional references. + +### Example +``` +fn foo(interned: Rc) { ... } +``` + +Better: + +``` +fn foo(interned: Rc) { ... } +``` \ No newline at end of file diff --git a/src/docs/rc_clone_in_vec_init.txt b/src/docs/rc_clone_in_vec_init.txt new file mode 100644 index 000000000000..6fc08aaf9ab5 --- /dev/null +++ b/src/docs/rc_clone_in_vec_init.txt @@ -0,0 +1,29 @@ +### What it does +Checks for reference-counted pointers (`Arc`, `Rc`, `rc::Weak`, and `sync::Weak`) +in `vec![elem; len]` + +### Why is this bad? +This will create `elem` once and clone it `len` times - doing so with `Arc`/`Rc`/`Weak` +is a bit misleading, as it will create references to the same pointer, rather +than different instances. + +### Example +``` +let v = vec![std::sync::Arc::new("some data".to_string()); 100]; +// or +let v = vec![std::rc::Rc::new("some data".to_string()); 100]; +``` +Use instead: +``` +// Initialize each value separately: +let mut data = Vec::with_capacity(100); +for _ in 0..100 { + data.push(std::rc::Rc::new("some data".to_string())); +} + +// Or if you want clones of the same reference, +// Create the reference beforehand to clarify that +// it should be cloned for each value +let data = std::rc::Rc::new("some data".to_string()); +let v = vec![data; 100]; +``` \ No newline at end of file diff --git a/src/docs/rc_mutex.txt b/src/docs/rc_mutex.txt new file mode 100644 index 000000000000..ed7a1e344d08 --- /dev/null +++ b/src/docs/rc_mutex.txt @@ -0,0 +1,26 @@ +### What it does +Checks for `Rc>`. + +### Why is this bad? +`Rc` is used in single thread and `Mutex` is used in multi thread. +Consider using `Rc>` in single thread or `Arc>` in multi thread. + +### Known problems +Sometimes combining generic types can lead to the requirement that a +type use Rc in conjunction with Mutex. We must consider those cases false positives, but +alas they are quite hard to rule out. Luckily they are also rare. + +### Example +``` +use std::rc::Rc; +use std::sync::Mutex; +fn foo(interned: Rc>) { ... } +``` + +Better: + +``` +use std::rc::Rc; +use std::cell::RefCell +fn foo(interned: Rc>) { ... } +``` \ No newline at end of file diff --git a/src/docs/read_zero_byte_vec.txt b/src/docs/read_zero_byte_vec.txt new file mode 100644 index 000000000000..cef5604e01c0 --- /dev/null +++ b/src/docs/read_zero_byte_vec.txt @@ -0,0 +1,30 @@ +### What it does +This lint catches reads into a zero-length `Vec`. +Especially in the case of a call to `with_capacity`, this lint warns that read +gets the number of bytes from the `Vec`'s length, not its capacity. + +### Why is this bad? +Reading zero bytes is almost certainly not the intended behavior. + +### Known problems +In theory, a very unusual read implementation could assign some semantic meaning +to zero-byte reads. But it seems exceptionally unlikely that code intending to do +a zero-byte read would allocate a `Vec` for it. + +### Example +``` +use std::io; +fn foo(mut f: F) { + let mut data = Vec::with_capacity(100); + f.read(&mut data).unwrap(); +} +``` +Use instead: +``` +use std::io; +fn foo(mut f: F) { + let mut data = Vec::with_capacity(100); + data.resize(100, 0); + f.read(&mut data).unwrap(); +} +``` \ No newline at end of file diff --git a/src/docs/recursive_format_impl.txt b/src/docs/recursive_format_impl.txt new file mode 100644 index 000000000000..32fffd84cf43 --- /dev/null +++ b/src/docs/recursive_format_impl.txt @@ -0,0 +1,32 @@ +### What it does +Checks for format trait implementations (e.g. `Display`) with a recursive call to itself +which uses `self` as a parameter. +This is typically done indirectly with the `write!` macro or with `to_string()`. + +### Why is this bad? +This will lead to infinite recursion and a stack overflow. + +### Example + +``` +use std::fmt; + +struct Structure(i32); +impl fmt::Display for Structure { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.to_string()) + } +} + +``` +Use instead: +``` +use std::fmt; + +struct Structure(i32); +impl fmt::Display for Structure { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.0) + } +} +``` \ No newline at end of file diff --git a/src/docs/redundant_allocation.txt b/src/docs/redundant_allocation.txt new file mode 100644 index 000000000000..86bf51e8dfec --- /dev/null +++ b/src/docs/redundant_allocation.txt @@ -0,0 +1,17 @@ +### What it does +Checks for use of redundant allocations anywhere in the code. + +### Why is this bad? +Expressions such as `Rc<&T>`, `Rc>`, `Rc>`, `Rc>`, `Arc<&T>`, `Arc>`, +`Arc>`, `Arc>`, `Box<&T>`, `Box>`, `Box>`, `Box>`, add an unnecessary level of indirection. + +### Example +``` +fn foo(bar: Rc<&usize>) {} +``` + +Better: + +``` +fn foo(bar: &usize) {} +``` \ No newline at end of file diff --git a/src/docs/redundant_clone.txt b/src/docs/redundant_clone.txt new file mode 100644 index 000000000000..b29aed0b5e77 --- /dev/null +++ b/src/docs/redundant_clone.txt @@ -0,0 +1,23 @@ +### What it does +Checks for a redundant `clone()` (and its relatives) which clones an owned +value that is going to be dropped without further use. + +### Why is this bad? +It is not always possible for the compiler to eliminate useless +allocations and deallocations generated by redundant `clone()`s. + +### Known problems +False-negatives: analysis performed by this lint is conservative and limited. + +### Example +``` +{ + let x = Foo::new(); + call(x.clone()); + call(x.clone()); // this can just pass `x` +} + +["lorem", "ipsum"].join(" ").to_string(); + +Path::new("/a/b").join("c").to_path_buf(); +``` \ No newline at end of file diff --git a/src/docs/redundant_closure.txt b/src/docs/redundant_closure.txt new file mode 100644 index 000000000000..0faa9513f97f --- /dev/null +++ b/src/docs/redundant_closure.txt @@ -0,0 +1,25 @@ +### What it does +Checks for closures which just call another function where +the function can be called directly. `unsafe` functions or calls where types +get adjusted are ignored. + +### Why is this bad? +Needlessly creating a closure adds code for no benefit +and gives the optimizer more work. + +### Known problems +If creating the closure inside the closure has a side- +effect then moving the closure creation out will change when that side- +effect runs. +See [#1439](https://github.com/rust-lang/rust-clippy/issues/1439) for more details. + +### Example +``` +xs.map(|x| foo(x)) +``` + +Use instead: +``` +// where `foo(_)` is a plain function that takes the exact argument type of `x`. +xs.map(foo) +``` \ No newline at end of file diff --git a/src/docs/redundant_closure_call.txt b/src/docs/redundant_closure_call.txt new file mode 100644 index 000000000000..913d1a705e29 --- /dev/null +++ b/src/docs/redundant_closure_call.txt @@ -0,0 +1,17 @@ +### What it does +Detects closures called in the same expression where they +are defined. + +### Why is this bad? +It is unnecessarily adding to the expression's +complexity. + +### Example +``` +let a = (|| 42)(); +``` + +Use instead: +``` +let a = 42; +``` \ No newline at end of file diff --git a/src/docs/redundant_closure_for_method_calls.txt b/src/docs/redundant_closure_for_method_calls.txt new file mode 100644 index 000000000000..865510e14755 --- /dev/null +++ b/src/docs/redundant_closure_for_method_calls.txt @@ -0,0 +1,15 @@ +### What it does +Checks for closures which only invoke a method on the closure +argument and can be replaced by referencing the method directly. + +### Why is this bad? +It's unnecessary to create the closure. + +### Example +``` +Some('a').map(|s| s.to_uppercase()); +``` +may be rewritten as +``` +Some('a').map(char::to_uppercase); +``` \ No newline at end of file diff --git a/src/docs/redundant_else.txt b/src/docs/redundant_else.txt new file mode 100644 index 000000000000..3f4e86917603 --- /dev/null +++ b/src/docs/redundant_else.txt @@ -0,0 +1,30 @@ +### What it does +Checks for `else` blocks that can be removed without changing semantics. + +### Why is this bad? +The `else` block adds unnecessary indentation and verbosity. + +### Known problems +Some may prefer to keep the `else` block for clarity. + +### Example +``` +fn my_func(count: u32) { + if count == 0 { + print!("Nothing to do"); + return; + } else { + print!("Moving on..."); + } +} +``` +Use instead: +``` +fn my_func(count: u32) { + if count == 0 { + print!("Nothing to do"); + return; + } + print!("Moving on..."); +} +``` \ No newline at end of file diff --git a/src/docs/redundant_feature_names.txt b/src/docs/redundant_feature_names.txt new file mode 100644 index 000000000000..5bd6925ed47d --- /dev/null +++ b/src/docs/redundant_feature_names.txt @@ -0,0 +1,23 @@ +### What it does +Checks for feature names with prefix `use-`, `with-` or suffix `-support` + +### Why is this bad? +These prefixes and suffixes have no significant meaning. + +### Example +``` +[features] +default = ["use-abc", "with-def", "ghi-support"] +use-abc = [] // redundant +with-def = [] // redundant +ghi-support = [] // redundant +``` + +Use instead: +``` +[features] +default = ["abc", "def", "ghi"] +abc = [] +def = [] +ghi = [] +``` diff --git a/src/docs/redundant_field_names.txt b/src/docs/redundant_field_names.txt new file mode 100644 index 000000000000..35f20a466b37 --- /dev/null +++ b/src/docs/redundant_field_names.txt @@ -0,0 +1,22 @@ +### What it does +Checks for fields in struct literals where shorthands +could be used. + +### Why is this bad? +If the field and variable names are the same, +the field name is redundant. + +### Example +``` +let bar: u8 = 123; + +struct Foo { + bar: u8, +} + +let foo = Foo { bar: bar }; +``` +the last line can be simplified to +``` +let foo = Foo { bar }; +``` \ No newline at end of file diff --git a/src/docs/redundant_pattern.txt b/src/docs/redundant_pattern.txt new file mode 100644 index 000000000000..45f6cfc86702 --- /dev/null +++ b/src/docs/redundant_pattern.txt @@ -0,0 +1,22 @@ +### What it does +Checks for patterns in the form `name @ _`. + +### Why is this bad? +It's almost always more readable to just use direct +bindings. + +### Example +``` +match v { + Some(x) => (), + y @ _ => (), +} +``` + +Use instead: +``` +match v { + Some(x) => (), + y => (), +} +``` \ No newline at end of file diff --git a/src/docs/redundant_pattern_matching.txt b/src/docs/redundant_pattern_matching.txt new file mode 100644 index 000000000000..77b1021e0db3 --- /dev/null +++ b/src/docs/redundant_pattern_matching.txt @@ -0,0 +1,45 @@ +### What it does +Lint for redundant pattern matching over `Result`, `Option`, +`std::task::Poll` or `std::net::IpAddr` + +### Why is this bad? +It's more concise and clear to just use the proper +utility function + +### Known problems +This will change the drop order for the matched type. Both `if let` and +`while let` will drop the value at the end of the block, both `if` and `while` will drop the +value before entering the block. For most types this change will not matter, but for a few +types this will not be an acceptable change (e.g. locks). See the +[reference](https://doc.rust-lang.org/reference/destructors.html#drop-scopes) for more about +drop order. + +### Example +``` +if let Ok(_) = Ok::(42) {} +if let Err(_) = Err::(42) {} +if let None = None::<()> {} +if let Some(_) = Some(42) {} +if let Poll::Pending = Poll::Pending::<()> {} +if let Poll::Ready(_) = Poll::Ready(42) {} +if let IpAddr::V4(_) = IpAddr::V4(Ipv4Addr::LOCALHOST) {} +if let IpAddr::V6(_) = IpAddr::V6(Ipv6Addr::LOCALHOST) {} +match Ok::(42) { + Ok(_) => true, + Err(_) => false, +}; +``` + +The more idiomatic use would be: + +``` +if Ok::(42).is_ok() {} +if Err::(42).is_err() {} +if None::<()>.is_none() {} +if Some(42).is_some() {} +if Poll::Pending::<()>.is_pending() {} +if Poll::Ready(42).is_ready() {} +if IpAddr::V4(Ipv4Addr::LOCALHOST).is_ipv4() {} +if IpAddr::V6(Ipv6Addr::LOCALHOST).is_ipv6() {} +Ok::(42).is_ok(); +``` \ No newline at end of file diff --git a/src/docs/redundant_pub_crate.txt b/src/docs/redundant_pub_crate.txt new file mode 100644 index 000000000000..a527bb5acda1 --- /dev/null +++ b/src/docs/redundant_pub_crate.txt @@ -0,0 +1,21 @@ +### What it does +Checks for items declared `pub(crate)` that are not crate visible because they +are inside a private module. + +### Why is this bad? +Writing `pub(crate)` is misleading when it's redundant due to the parent +module's visibility. + +### Example +``` +mod internal { + pub(crate) fn internal_fn() { } +} +``` +This function is not visible outside the module and it can be declared with `pub` or +private visibility +``` +mod internal { + pub fn internal_fn() { } +} +``` \ No newline at end of file diff --git a/src/docs/redundant_slicing.txt b/src/docs/redundant_slicing.txt new file mode 100644 index 000000000000..6798911ed76c --- /dev/null +++ b/src/docs/redundant_slicing.txt @@ -0,0 +1,24 @@ +### What it does +Checks for redundant slicing expressions which use the full range, and +do not change the type. + +### Why is this bad? +It unnecessarily adds complexity to the expression. + +### Known problems +If the type being sliced has an implementation of `Index` +that actually changes anything then it can't be removed. However, this would be surprising +to people reading the code and should have a note with it. + +### Example +``` +fn get_slice(x: &[u32]) -> &[u32] { + &x[..] +} +``` +Use instead: +``` +fn get_slice(x: &[u32]) -> &[u32] { + x +} +``` \ No newline at end of file diff --git a/src/docs/redundant_static_lifetimes.txt b/src/docs/redundant_static_lifetimes.txt new file mode 100644 index 000000000000..edb8e7b5c62b --- /dev/null +++ b/src/docs/redundant_static_lifetimes.txt @@ -0,0 +1,19 @@ +### What it does +Checks for constants and statics with an explicit `'static` lifetime. + +### Why is this bad? +Adding `'static` to every reference can create very +complicated types. + +### Example +``` +const FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] = +&[...] +static FOO: &'static [(&'static str, &'static str, fn(&Bar) -> bool)] = +&[...] +``` +This code can be rewritten as +``` + const FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...] + static FOO: &[(&str, &str, fn(&Bar) -> bool)] = &[...] +``` \ No newline at end of file diff --git a/src/docs/ref_binding_to_reference.txt b/src/docs/ref_binding_to_reference.txt new file mode 100644 index 000000000000..dc391cd988e5 --- /dev/null +++ b/src/docs/ref_binding_to_reference.txt @@ -0,0 +1,21 @@ +### What it does +Checks for `ref` bindings which create a reference to a reference. + +### Why is this bad? +The address-of operator at the use site is clearer about the need for a reference. + +### Example +``` +let x = Some(""); +if let Some(ref x) = x { + // use `x` here +} +``` + +Use instead: +``` +let x = Some(""); +if let Some(x) = x { + // use `&x` here +} +``` \ No newline at end of file diff --git a/src/docs/ref_option_ref.txt b/src/docs/ref_option_ref.txt new file mode 100644 index 000000000000..951c7bd7f7ec --- /dev/null +++ b/src/docs/ref_option_ref.txt @@ -0,0 +1,19 @@ +### What it does +Checks for usage of `&Option<&T>`. + +### Why is this bad? +Since `&` is Copy, it's useless to have a +reference on `Option<&T>`. + +### Known problems +It may be irrelevant to use this lint on +public API code as it will make a breaking change to apply it. + +### Example +``` +let x: &Option<&u32> = &Some(&0u32); +``` +Use instead: +``` +let x: Option<&u32> = Some(&0u32); +``` \ No newline at end of file diff --git a/src/docs/repeat_once.txt b/src/docs/repeat_once.txt new file mode 100644 index 000000000000..3ba189c1945d --- /dev/null +++ b/src/docs/repeat_once.txt @@ -0,0 +1,25 @@ +### What it does +Checks for usage of `.repeat(1)` and suggest the following method for each types. +- `.to_string()` for `str` +- `.clone()` for `String` +- `.to_vec()` for `slice` + +The lint will evaluate constant expressions and values as arguments of `.repeat(..)` and emit a message if +they are equivalent to `1`. (Related discussion in [rust-clippy#7306](https://github.com/rust-lang/rust-clippy/issues/7306)) + +### Why is this bad? +For example, `String.repeat(1)` is equivalent to `.clone()`. If cloning +the string is the intention behind this, `clone()` should be used. + +### Example +``` +fn main() { + let x = String::from("hello world").repeat(1); +} +``` +Use instead: +``` +fn main() { + let x = String::from("hello world").clone(); +} +``` \ No newline at end of file diff --git a/src/docs/rest_pat_in_fully_bound_structs.txt b/src/docs/rest_pat_in_fully_bound_structs.txt new file mode 100644 index 000000000000..40ebbe754a37 --- /dev/null +++ b/src/docs/rest_pat_in_fully_bound_structs.txt @@ -0,0 +1,24 @@ +### What it does +Checks for unnecessary '..' pattern binding on struct when all fields are explicitly matched. + +### Why is this bad? +Correctness and readability. It's like having a wildcard pattern after +matching all enum variants explicitly. + +### Example +``` +let a = A { a: 5 }; + +match a { + A { a: 5, .. } => {}, + _ => {}, +} +``` + +Use instead: +``` +match a { + A { a: 5 } => {}, + _ => {}, +} +``` \ No newline at end of file diff --git a/src/docs/result_large_err.txt b/src/docs/result_large_err.txt new file mode 100644 index 000000000000..e5fab3c5cfcf --- /dev/null +++ b/src/docs/result_large_err.txt @@ -0,0 +1,36 @@ +### What it does +Checks for functions that return `Result` with an unusually large +`Err`-variant. + +### Why is this bad? +A `Result` is at least as large as the `Err`-variant. While we +expect that variant to be seldomly used, the compiler needs to reserve +and move that much memory every single time. + +### Known problems +The size determined by Clippy is platform-dependent. + +### Examples +``` +pub enum ParseError { + UnparsedBytes([u8; 512]), + UnexpectedEof, +} + +// The `Result` has at least 512 bytes, even in the `Ok`-case +pub fn parse() -> Result<(), ParseError> { + Ok(()) +} +``` +should be +``` +pub enum ParseError { + UnparsedBytes(Box<[u8; 512]>), + UnexpectedEof, +} + +// The `Result` is slightly larger than a pointer +pub fn parse() -> Result<(), ParseError> { + Ok(()) +} +``` \ No newline at end of file diff --git a/src/docs/result_map_or_into_option.txt b/src/docs/result_map_or_into_option.txt new file mode 100644 index 000000000000..899d98c307c8 --- /dev/null +++ b/src/docs/result_map_or_into_option.txt @@ -0,0 +1,16 @@ +### What it does +Checks for usage of `_.map_or(None, Some)`. + +### Why is this bad? +Readability, this can be written more concisely as +`_.ok()`. + +### Example +``` +assert_eq!(Some(1), r.map_or(None, Some)); +``` + +Use instead: +``` +assert_eq!(Some(1), r.ok()); +``` \ No newline at end of file diff --git a/src/docs/result_map_unit_fn.txt b/src/docs/result_map_unit_fn.txt new file mode 100644 index 000000000000..3455c5c1f9b8 --- /dev/null +++ b/src/docs/result_map_unit_fn.txt @@ -0,0 +1,26 @@ +### What it does +Checks for usage of `result.map(f)` where f is a function +or closure that returns the unit type `()`. + +### Why is this bad? +Readability, this can be written more clearly with +an if let statement + +### Example +``` +let x: Result = do_stuff(); +x.map(log_err_msg); +x.map(|msg| log_err_msg(format_msg(msg))); +``` + +The correct use would be: + +``` +let x: Result = do_stuff(); +if let Ok(msg) = x { + log_err_msg(msg); +}; +if let Ok(msg) = x { + log_err_msg(format_msg(msg)); +}; +``` \ No newline at end of file diff --git a/src/docs/result_unit_err.txt b/src/docs/result_unit_err.txt new file mode 100644 index 000000000000..7c8ec2ffcf94 --- /dev/null +++ b/src/docs/result_unit_err.txt @@ -0,0 +1,40 @@ +### What it does +Checks for public functions that return a `Result` +with an `Err` type of `()`. It suggests using a custom type that +implements `std::error::Error`. + +### Why is this bad? +Unit does not implement `Error` and carries no +further information about what went wrong. + +### Known problems +Of course, this lint assumes that `Result` is used +for a fallible operation (which is after all the intended use). However +code may opt to (mis)use it as a basic two-variant-enum. In that case, +the suggestion is misguided, and the code should use a custom enum +instead. + +### Examples +``` +pub fn read_u8() -> Result { Err(()) } +``` +should become +``` +use std::fmt; + +#[derive(Debug)] +pub struct EndOfStream; + +impl fmt::Display for EndOfStream { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "End of Stream") + } +} + +impl std::error::Error for EndOfStream { } + +pub fn read_u8() -> Result { Err(EndOfStream) } +``` + +Note that there are crates that simplify creating the error type, e.g. +[`thiserror`](https://docs.rs/thiserror). \ No newline at end of file diff --git a/src/docs/return_self_not_must_use.txt b/src/docs/return_self_not_must_use.txt new file mode 100644 index 000000000000..4a4fd2c6e517 --- /dev/null +++ b/src/docs/return_self_not_must_use.txt @@ -0,0 +1,46 @@ +### What it does +This lint warns when a method returning `Self` doesn't have the `#[must_use]` attribute. + +### Why is this bad? +Methods returning `Self` often create new values, having the `#[must_use]` attribute +prevents users from "forgetting" to use the newly created value. + +The `#[must_use]` attribute can be added to the type itself to ensure that instances +are never forgotten. Functions returning a type marked with `#[must_use]` will not be +linted, as the usage is already enforced by the type attribute. + +### Limitations +This lint is only applied on methods taking a `self` argument. It would be mostly noise +if it was added on constructors for example. + +### Example +``` +pub struct Bar; +impl Bar { + // Missing attribute + pub fn bar(&self) -> Self { + Self + } +} +``` + +Use instead: +``` +// It's better to have the `#[must_use]` attribute on the method like this: +pub struct Bar; +impl Bar { + #[must_use] + pub fn bar(&self) -> Self { + Self + } +} + +// Or on the type definition like this: +#[must_use] +pub struct Bar; +impl Bar { + pub fn bar(&self) -> Self { + Self + } +} +``` \ No newline at end of file diff --git a/src/docs/reversed_empty_ranges.txt b/src/docs/reversed_empty_ranges.txt new file mode 100644 index 000000000000..39f481193866 --- /dev/null +++ b/src/docs/reversed_empty_ranges.txt @@ -0,0 +1,26 @@ +### What it does +Checks for range expressions `x..y` where both `x` and `y` +are constant and `x` is greater or equal to `y`. + +### Why is this bad? +Empty ranges yield no values so iterating them is a no-op. +Moreover, trying to use a reversed range to index a slice will panic at run-time. + +### Example +``` +fn main() { + (10..=0).for_each(|x| println!("{}", x)); + + let arr = [1, 2, 3, 4, 5]; + let sub = &arr[3..1]; +} +``` +Use instead: +``` +fn main() { + (0..=10).rev().for_each(|x| println!("{}", x)); + + let arr = [1, 2, 3, 4, 5]; + let sub = &arr[1..3]; +} +``` \ No newline at end of file diff --git a/src/docs/same_functions_in_if_condition.txt b/src/docs/same_functions_in_if_condition.txt new file mode 100644 index 000000000000..a0a90eec681e --- /dev/null +++ b/src/docs/same_functions_in_if_condition.txt @@ -0,0 +1,41 @@ +### What it does +Checks for consecutive `if`s with the same function call. + +### Why is this bad? +This is probably a copy & paste error. +Despite the fact that function can have side effects and `if` works as +intended, such an approach is implicit and can be considered a "code smell". + +### Example +``` +if foo() == bar { + … +} else if foo() == bar { + … +} +``` + +This probably should be: +``` +if foo() == bar { + … +} else if foo() == baz { + … +} +``` + +or if the original code was not a typo and called function mutates a state, +consider move the mutation out of the `if` condition to avoid similarity to +a copy & paste error: + +``` +let first = foo(); +if first == bar { + … +} else { + let second = foo(); + if second == bar { + … + } +} +``` \ No newline at end of file diff --git a/src/docs/same_item_push.txt b/src/docs/same_item_push.txt new file mode 100644 index 000000000000..7e724073f8aa --- /dev/null +++ b/src/docs/same_item_push.txt @@ -0,0 +1,29 @@ +### What it does +Checks whether a for loop is being used to push a constant +value into a Vec. + +### Why is this bad? +This kind of operation can be expressed more succinctly with +`vec![item; SIZE]` or `vec.resize(NEW_SIZE, item)` and using these alternatives may also +have better performance. + +### Example +``` +let item1 = 2; +let item2 = 3; +let mut vec: Vec = Vec::new(); +for _ in 0..20 { + vec.push(item1); +} +for _ in 0..30 { + vec.push(item2); +} +``` + +Use instead: +``` +let item1 = 2; +let item2 = 3; +let mut vec: Vec = vec![item1; 20]; +vec.resize(20 + 30, item2); +``` \ No newline at end of file diff --git a/src/docs/same_name_method.txt b/src/docs/same_name_method.txt new file mode 100644 index 000000000000..792dd717fc64 --- /dev/null +++ b/src/docs/same_name_method.txt @@ -0,0 +1,23 @@ +### What it does +It lints if a struct has two methods with the same name: +one from a trait, another not from trait. + +### Why is this bad? +Confusing. + +### Example +``` +trait T { + fn foo(&self) {} +} + +struct S; + +impl T for S { + fn foo(&self) {} +} + +impl S { + fn foo(&self) {} +} +``` \ No newline at end of file diff --git a/src/docs/search_is_some.txt b/src/docs/search_is_some.txt new file mode 100644 index 000000000000..67292d54585f --- /dev/null +++ b/src/docs/search_is_some.txt @@ -0,0 +1,24 @@ +### What it does +Checks for an iterator or string search (such as `find()`, +`position()`, or `rposition()`) followed by a call to `is_some()` or `is_none()`. + +### Why is this bad? +Readability, this can be written more concisely as: +* `_.any(_)`, or `_.contains(_)` for `is_some()`, +* `!_.any(_)`, or `!_.contains(_)` for `is_none()`. + +### Example +``` +let vec = vec![1]; +vec.iter().find(|x| **x == 0).is_some(); + +"hello world".find("world").is_none(); +``` + +Use instead: +``` +let vec = vec![1]; +vec.iter().any(|x| *x == 0); + +!"hello world".contains("world"); +``` \ No newline at end of file diff --git a/src/docs/self_assignment.txt b/src/docs/self_assignment.txt new file mode 100644 index 000000000000..ea60ea077ab5 --- /dev/null +++ b/src/docs/self_assignment.txt @@ -0,0 +1,32 @@ +### What it does +Checks for explicit self-assignments. + +### Why is this bad? +Self-assignments are redundant and unlikely to be +intentional. + +### Known problems +If expression contains any deref coercions or +indexing operations they are assumed not to have any side effects. + +### Example +``` +struct Event { + x: i32, +} + +fn copy_position(a: &mut Event, b: &Event) { + a.x = a.x; +} +``` + +Should be: +``` +struct Event { + x: i32, +} + +fn copy_position(a: &mut Event, b: &Event) { + a.x = b.x; +} +``` \ No newline at end of file diff --git a/src/docs/self_named_constructors.txt b/src/docs/self_named_constructors.txt new file mode 100644 index 000000000000..a01669a84542 --- /dev/null +++ b/src/docs/self_named_constructors.txt @@ -0,0 +1,26 @@ +### What it does +Warns when constructors have the same name as their types. + +### Why is this bad? +Repeating the name of the type is redundant. + +### Example +``` +struct Foo {} + +impl Foo { + pub fn foo() -> Foo { + Foo {} + } +} +``` +Use instead: +``` +struct Foo {} + +impl Foo { + pub fn new() -> Foo { + Foo {} + } +} +``` \ No newline at end of file diff --git a/src/docs/self_named_module_files.txt b/src/docs/self_named_module_files.txt new file mode 100644 index 000000000000..73e805136288 --- /dev/null +++ b/src/docs/self_named_module_files.txt @@ -0,0 +1,22 @@ +### What it does +Checks that module layout uses only `mod.rs` files. + +### Why is this bad? +Having multiple module layout styles in a project can be confusing. + +### Example +``` +src/ + stuff/ + stuff_files.rs + stuff.rs + lib.rs +``` +Use instead: +``` +src/ + stuff/ + stuff_files.rs + mod.rs + lib.rs +``` \ No newline at end of file diff --git a/src/docs/semicolon_if_nothing_returned.txt b/src/docs/semicolon_if_nothing_returned.txt new file mode 100644 index 000000000000..30c963ca211b --- /dev/null +++ b/src/docs/semicolon_if_nothing_returned.txt @@ -0,0 +1,20 @@ +### What it does +Looks for blocks of expressions and fires if the last expression returns +`()` but is not followed by a semicolon. + +### Why is this bad? +The semicolon might be optional but when extending the block with new +code, it doesn't require a change in previous last line. + +### Example +``` +fn main() { + println!("Hello world") +} +``` +Use instead: +``` +fn main() { + println!("Hello world"); +} +``` \ No newline at end of file diff --git a/src/docs/separated_literal_suffix.txt b/src/docs/separated_literal_suffix.txt new file mode 100644 index 000000000000..226a6b8a9876 --- /dev/null +++ b/src/docs/separated_literal_suffix.txt @@ -0,0 +1,17 @@ +### What it does +Warns if literal suffixes are separated by an underscore. +To enforce separated literal suffix style, +see the `unseparated_literal_suffix` lint. + +### Why is this bad? +Suffix style should be consistent. + +### Example +``` +123832_i32 +``` + +Use instead: +``` +123832i32 +``` \ No newline at end of file diff --git a/src/docs/serde_api_misuse.txt b/src/docs/serde_api_misuse.txt new file mode 100644 index 000000000000..8a3c89ac11ad --- /dev/null +++ b/src/docs/serde_api_misuse.txt @@ -0,0 +1,10 @@ +### What it does +Checks for mis-uses of the serde API. + +### Why is this bad? +Serde is very finnicky about how its API should be +used, but the type system can't be used to enforce it (yet?). + +### Example +Implementing `Visitor::visit_string` but not +`Visitor::visit_str`. \ No newline at end of file diff --git a/src/docs/shadow_reuse.txt b/src/docs/shadow_reuse.txt new file mode 100644 index 000000000000..9eb8e7ad164b --- /dev/null +++ b/src/docs/shadow_reuse.txt @@ -0,0 +1,20 @@ +### What it does +Checks for bindings that shadow other bindings already in +scope, while reusing the original value. + +### Why is this bad? +Not too much, in fact it's a common pattern in Rust +code. Still, some argue that name shadowing like this hurts readability, +because a value may be bound to different things depending on position in +the code. + +### Example +``` +let x = 2; +let x = x + 1; +``` +use different variable name: +``` +let x = 2; +let y = x + 1; +``` \ No newline at end of file diff --git a/src/docs/shadow_same.txt b/src/docs/shadow_same.txt new file mode 100644 index 000000000000..3cd96f560a5e --- /dev/null +++ b/src/docs/shadow_same.txt @@ -0,0 +1,18 @@ +### What it does +Checks for bindings that shadow other bindings already in +scope, while just changing reference level or mutability. + +### Why is this bad? +Not much, in fact it's a very common pattern in Rust +code. Still, some may opt to avoid it in their code base, they can set this +lint to `Warn`. + +### Example +``` +let x = &x; +``` + +Use instead: +``` +let y = &x; // use different variable name +``` \ No newline at end of file diff --git a/src/docs/shadow_unrelated.txt b/src/docs/shadow_unrelated.txt new file mode 100644 index 000000000000..436251c520a9 --- /dev/null +++ b/src/docs/shadow_unrelated.txt @@ -0,0 +1,22 @@ +### What it does +Checks for bindings that shadow other bindings already in +scope, either without an initialization or with one that does not even use +the original value. + +### Why is this bad? +Name shadowing can hurt readability, especially in +large code bases, because it is easy to lose track of the active binding at +any place in the code. This can be alleviated by either giving more specific +names to bindings or introducing more scopes to contain the bindings. + +### Example +``` +let x = y; +let x = z; // shadows the earlier binding +``` + +Use instead: +``` +let x = y; +let w = z; // use different variable name +``` \ No newline at end of file diff --git a/src/docs/short_circuit_statement.txt b/src/docs/short_circuit_statement.txt new file mode 100644 index 000000000000..31492bed03d4 --- /dev/null +++ b/src/docs/short_circuit_statement.txt @@ -0,0 +1,14 @@ +### What it does +Checks for the use of short circuit boolean conditions as +a +statement. + +### Why is this bad? +Using a short circuit boolean condition as a statement +may hide the fact that the second part is executed or not depending on the +outcome of the first part. + +### Example +``` +f() && g(); // We should write `if f() { g(); }`. +``` \ No newline at end of file diff --git a/src/docs/should_implement_trait.txt b/src/docs/should_implement_trait.txt new file mode 100644 index 000000000000..02e74751ae03 --- /dev/null +++ b/src/docs/should_implement_trait.txt @@ -0,0 +1,22 @@ +### What it does +Checks for methods that should live in a trait +implementation of a `std` trait (see [llogiq's blog +post](http://llogiq.github.io/2015/07/30/traits.html) for further +information) instead of an inherent implementation. + +### Why is this bad? +Implementing the traits improve ergonomics for users of +the code, often with very little cost. Also people seeing a `mul(...)` +method +may expect `*` to work equally, so you should have good reason to disappoint +them. + +### Example +``` +struct X; +impl X { + fn add(&self, other: &X) -> X { + // .. + } +} +``` \ No newline at end of file diff --git a/src/docs/significant_drop_in_scrutinee.txt b/src/docs/significant_drop_in_scrutinee.txt new file mode 100644 index 000000000000..f869def0ddb7 --- /dev/null +++ b/src/docs/significant_drop_in_scrutinee.txt @@ -0,0 +1,43 @@ +### What it does +Check for temporaries returned from function calls in a match scrutinee that have the +`clippy::has_significant_drop` attribute. + +### Why is this bad? +The `clippy::has_significant_drop` attribute can be added to types whose Drop impls have +an important side-effect, such as unlocking a mutex, making it important for users to be +able to accurately understand their lifetimes. When a temporary is returned in a function +call in a match scrutinee, its lifetime lasts until the end of the match block, which may +be surprising. + +For `Mutex`es this can lead to a deadlock. This happens when the match scrutinee uses a +function call that returns a `MutexGuard` and then tries to lock again in one of the match +arms. In that case the `MutexGuard` in the scrutinee will not be dropped until the end of +the match block and thus will not unlock. + +### Example +``` +let mutex = Mutex::new(State {}); + +match mutex.lock().unwrap().foo() { + true => { + mutex.lock().unwrap().bar(); // Deadlock! + } + false => {} +}; + +println!("All done!"); +``` +Use instead: +``` +let mutex = Mutex::new(State {}); + +let is_foo = mutex.lock().unwrap().foo(); +match is_foo { + true => { + mutex.lock().unwrap().bar(); + } + false => {} +}; + +println!("All done!"); +``` \ No newline at end of file diff --git a/src/docs/similar_names.txt b/src/docs/similar_names.txt new file mode 100644 index 000000000000..13aca9c0bb75 --- /dev/null +++ b/src/docs/similar_names.txt @@ -0,0 +1,12 @@ +### What it does +Checks for names that are very similar and thus confusing. + +### Why is this bad? +It's hard to distinguish between names that differ only +by a single character. + +### Example +``` +let checked_exp = something; +let checked_expr = something_else; +``` \ No newline at end of file diff --git a/src/docs/single_char_add_str.txt b/src/docs/single_char_add_str.txt new file mode 100644 index 000000000000..cf23dc0c89bb --- /dev/null +++ b/src/docs/single_char_add_str.txt @@ -0,0 +1,18 @@ +### What it does +Warns when using `push_str`/`insert_str` with a single-character string literal +where `push`/`insert` with a `char` would work fine. + +### Why is this bad? +It's less clear that we are pushing a single character. + +### Example +``` +string.insert_str(0, "R"); +string.push_str("R"); +``` + +Use instead: +``` +string.insert(0, 'R'); +string.push('R'); +``` \ No newline at end of file diff --git a/src/docs/single_char_lifetime_names.txt b/src/docs/single_char_lifetime_names.txt new file mode 100644 index 000000000000..92dd24bf247e --- /dev/null +++ b/src/docs/single_char_lifetime_names.txt @@ -0,0 +1,28 @@ +### What it does +Checks for lifetimes with names which are one character +long. + +### Why is this bad? +A single character is likely not enough to express the +purpose of a lifetime. Using a longer name can make code +easier to understand, especially for those who are new to +Rust. + +### Known problems +Rust programmers and learning resources tend to use single +character lifetimes, so this lint is at odds with the +ecosystem at large. In addition, the lifetime's purpose may +be obvious or, rarely, expressible in one character. + +### Example +``` +struct DiagnosticCtx<'a> { + source: &'a str, +} +``` +Use instead: +``` +struct DiagnosticCtx<'src> { + source: &'src str, +} +``` \ No newline at end of file diff --git a/src/docs/single_char_pattern.txt b/src/docs/single_char_pattern.txt new file mode 100644 index 000000000000..9e5ad1e7d639 --- /dev/null +++ b/src/docs/single_char_pattern.txt @@ -0,0 +1,20 @@ +### What it does +Checks for string methods that receive a single-character +`str` as an argument, e.g., `_.split("x")`. + +### Why is this bad? +Performing these methods using a `char` is faster than +using a `str`. + +### Known problems +Does not catch multi-byte unicode characters. + +### Example +``` +_.split("x"); +``` + +Use instead: +``` +_.split('x'); +``` \ No newline at end of file diff --git a/src/docs/single_component_path_imports.txt b/src/docs/single_component_path_imports.txt new file mode 100644 index 000000000000..3a026388183e --- /dev/null +++ b/src/docs/single_component_path_imports.txt @@ -0,0 +1,21 @@ +### What it does +Checking for imports with single component use path. + +### Why is this bad? +Import with single component use path such as `use cratename;` +is not necessary, and thus should be removed. + +### Example +``` +use regex; + +fn main() { + regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap(); +} +``` +Better as +``` +fn main() { + regex::Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap(); +} +``` \ No newline at end of file diff --git a/src/docs/single_element_loop.txt b/src/docs/single_element_loop.txt new file mode 100644 index 000000000000..6f0c15a85f77 --- /dev/null +++ b/src/docs/single_element_loop.txt @@ -0,0 +1,21 @@ +### What it does +Checks whether a for loop has a single element. + +### Why is this bad? +There is no reason to have a loop of a +single element. + +### Example +``` +let item1 = 2; +for item in &[item1] { + println!("{}", item); +} +``` + +Use instead: +``` +let item1 = 2; +let item = &item1; +println!("{}", item); +``` \ No newline at end of file diff --git a/src/docs/single_match.txt b/src/docs/single_match.txt new file mode 100644 index 000000000000..31dde4da8489 --- /dev/null +++ b/src/docs/single_match.txt @@ -0,0 +1,21 @@ +### What it does +Checks for matches with a single arm where an `if let` +will usually suffice. + +### Why is this bad? +Just readability – `if let` nests less than a `match`. + +### Example +``` +match x { + Some(ref foo) => bar(foo), + _ => (), +} +``` + +Use instead: +``` +if let Some(ref foo) = x { + bar(foo); +} +``` \ No newline at end of file diff --git a/src/docs/single_match_else.txt b/src/docs/single_match_else.txt new file mode 100644 index 000000000000..29a447af09b8 --- /dev/null +++ b/src/docs/single_match_else.txt @@ -0,0 +1,29 @@ +### What it does +Checks for matches with two arms where an `if let else` will +usually suffice. + +### Why is this bad? +Just readability – `if let` nests less than a `match`. + +### Known problems +Personal style preferences may differ. + +### Example +Using `match`: + +``` +match x { + Some(ref foo) => bar(foo), + _ => bar(&other_ref), +} +``` + +Using `if let` with `else`: + +``` +if let Some(ref foo) = x { + bar(foo); +} else { + bar(&other_ref); +} +``` \ No newline at end of file diff --git a/src/docs/size_of_in_element_count.txt b/src/docs/size_of_in_element_count.txt new file mode 100644 index 000000000000..d893ec6a2a01 --- /dev/null +++ b/src/docs/size_of_in_element_count.txt @@ -0,0 +1,16 @@ +### What it does +Detects expressions where +`size_of::` or `size_of_val::` is used as a +count of elements of type `T` + +### Why is this bad? +These functions expect a count +of `T` and not a number of bytes + +### Example +``` +const SIZE: usize = 128; +let x = [2u8; SIZE]; +let mut y = [2u8; SIZE]; +unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; +``` \ No newline at end of file diff --git a/src/docs/skip_while_next.txt b/src/docs/skip_while_next.txt new file mode 100644 index 000000000000..1ec8a3a28d5b --- /dev/null +++ b/src/docs/skip_while_next.txt @@ -0,0 +1,16 @@ +### What it does +Checks for usage of `_.skip_while(condition).next()`. + +### Why is this bad? +Readability, this can be written more concisely as +`_.find(!condition)`. + +### Example +``` +vec.iter().skip_while(|x| **x == 0).next(); +``` + +Use instead: +``` +vec.iter().find(|x| **x != 0); +``` \ No newline at end of file diff --git a/src/docs/slow_vector_initialization.txt b/src/docs/slow_vector_initialization.txt new file mode 100644 index 000000000000..53442e179654 --- /dev/null +++ b/src/docs/slow_vector_initialization.txt @@ -0,0 +1,24 @@ +### What it does +Checks slow zero-filled vector initialization + +### Why is this bad? +These structures are non-idiomatic and less efficient than simply using +`vec![0; len]`. + +### Example +``` +let mut vec1 = Vec::with_capacity(len); +vec1.resize(len, 0); + +let mut vec1 = Vec::with_capacity(len); +vec1.resize(vec1.capacity(), 0); + +let mut vec2 = Vec::with_capacity(len); +vec2.extend(repeat(0).take(len)); +``` + +Use instead: +``` +let mut vec1 = vec![0; len]; +let mut vec2 = vec![0; len]; +``` \ No newline at end of file diff --git a/src/docs/stable_sort_primitive.txt b/src/docs/stable_sort_primitive.txt new file mode 100644 index 000000000000..6465dbee46b1 --- /dev/null +++ b/src/docs/stable_sort_primitive.txt @@ -0,0 +1,31 @@ +### What it does +When sorting primitive values (integers, bools, chars, as well +as arrays, slices, and tuples of such items), it is typically better to +use an unstable sort than a stable sort. + +### Why is this bad? +Typically, using a stable sort consumes more memory and cpu cycles. +Because values which compare equal are identical, preserving their +relative order (the guarantee that a stable sort provides) means +nothing, while the extra costs still apply. + +### Known problems + +As pointed out in +[issue #8241](https://github.com/rust-lang/rust-clippy/issues/8241), +a stable sort can instead be significantly faster for certain scenarios +(eg. when a sorted vector is extended with new data and resorted). + +For more information and benchmarking results, please refer to the +issue linked above. + +### Example +``` +let mut vec = vec![2, 1, 3]; +vec.sort(); +``` +Use instead: +``` +let mut vec = vec![2, 1, 3]; +vec.sort_unstable(); +``` \ No newline at end of file diff --git a/src/docs/std_instead_of_alloc.txt b/src/docs/std_instead_of_alloc.txt new file mode 100644 index 000000000000..c2d32704e505 --- /dev/null +++ b/src/docs/std_instead_of_alloc.txt @@ -0,0 +1,18 @@ +### What it does + +Finds items imported through `std` when available through `alloc`. + +### Why is this bad? + +Crates which have `no_std` compatibility and require alloc may wish to ensure types are imported from +alloc to ensure disabling `std` does not cause the crate to fail to compile. This lint is also useful +for crates migrating to become `no_std` compatible. + +### Example +``` +use std::vec::Vec; +``` +Use instead: +``` +use alloc::vec::Vec; +``` \ No newline at end of file diff --git a/src/docs/std_instead_of_core.txt b/src/docs/std_instead_of_core.txt new file mode 100644 index 000000000000..f1e1518c6a62 --- /dev/null +++ b/src/docs/std_instead_of_core.txt @@ -0,0 +1,18 @@ +### What it does + +Finds items imported through `std` when available through `core`. + +### Why is this bad? + +Crates which have `no_std` compatibility may wish to ensure types are imported from core to ensure +disabling `std` does not cause the crate to fail to compile. This lint is also useful for crates +migrating to become `no_std` compatible. + +### Example +``` +use std::hash::Hasher; +``` +Use instead: +``` +use core::hash::Hasher; +``` \ No newline at end of file diff --git a/src/docs/str_to_string.txt b/src/docs/str_to_string.txt new file mode 100644 index 000000000000..a24755223747 --- /dev/null +++ b/src/docs/str_to_string.txt @@ -0,0 +1,18 @@ +### What it does +This lint checks for `.to_string()` method calls on values of type `&str`. + +### Why is this bad? +The `to_string` method is also used on other types to convert them to a string. +When called on a `&str` it turns the `&str` into the owned variant `String`, which can be better +expressed with `.to_owned()`. + +### Example +``` +// example code where clippy issues a warning +let _ = "str".to_string(); +``` +Use instead: +``` +// example code which does not raise clippy warning +let _ = "str".to_owned(); +``` \ No newline at end of file diff --git a/src/docs/string_add.txt b/src/docs/string_add.txt new file mode 100644 index 000000000000..23dafd0d0333 --- /dev/null +++ b/src/docs/string_add.txt @@ -0,0 +1,27 @@ +### What it does +Checks for all instances of `x + _` where `x` is of type +`String`, but only if [`string_add_assign`](#string_add_assign) does *not* +match. + +### Why is this bad? +It's not bad in and of itself. However, this particular +`Add` implementation is asymmetric (the other operand need not be `String`, +but `x` does), while addition as mathematically defined is symmetric, also +the `String::push_str(_)` function is a perfectly good replacement. +Therefore, some dislike it and wish not to have it in their code. + +That said, other people think that string addition, having a long tradition +in other languages is actually fine, which is why we decided to make this +particular lint `allow` by default. + +### Example +``` +let x = "Hello".to_owned(); +x + ", World"; +``` + +Use instead: +``` +let mut x = "Hello".to_owned(); +x.push_str(", World"); +``` \ No newline at end of file diff --git a/src/docs/string_add_assign.txt b/src/docs/string_add_assign.txt new file mode 100644 index 000000000000..7438be855db8 --- /dev/null +++ b/src/docs/string_add_assign.txt @@ -0,0 +1,17 @@ +### What it does +Checks for string appends of the form `x = x + y` (without +`let`!). + +### Why is this bad? +It's not really bad, but some people think that the +`.push_str(_)` method is more readable. + +### Example +``` +let mut x = "Hello".to_owned(); +x = x + ", World"; + +// More readable +x += ", World"; +x.push_str(", World"); +``` \ No newline at end of file diff --git a/src/docs/string_extend_chars.txt b/src/docs/string_extend_chars.txt new file mode 100644 index 000000000000..619ea3e11867 --- /dev/null +++ b/src/docs/string_extend_chars.txt @@ -0,0 +1,23 @@ +### What it does +Checks for the use of `.extend(s.chars())` where s is a +`&str` or `String`. + +### Why is this bad? +`.push_str(s)` is clearer + +### Example +``` +let abc = "abc"; +let def = String::from("def"); +let mut s = String::new(); +s.extend(abc.chars()); +s.extend(def.chars()); +``` +The correct use would be: +``` +let abc = "abc"; +let def = String::from("def"); +let mut s = String::new(); +s.push_str(abc); +s.push_str(&def); +``` \ No newline at end of file diff --git a/src/docs/string_from_utf8_as_bytes.txt b/src/docs/string_from_utf8_as_bytes.txt new file mode 100644 index 000000000000..9102d73471cb --- /dev/null +++ b/src/docs/string_from_utf8_as_bytes.txt @@ -0,0 +1,15 @@ +### What it does +Check if the string is transformed to byte array and casted back to string. + +### Why is this bad? +It's unnecessary, the string can be used directly. + +### Example +``` +std::str::from_utf8(&"Hello World!".as_bytes()[6..11]).unwrap(); +``` + +Use instead: +``` +&"Hello World!"[6..11]; +``` \ No newline at end of file diff --git a/src/docs/string_lit_as_bytes.txt b/src/docs/string_lit_as_bytes.txt new file mode 100644 index 000000000000..a125b97ed656 --- /dev/null +++ b/src/docs/string_lit_as_bytes.txt @@ -0,0 +1,39 @@ +### What it does +Checks for the `as_bytes` method called on string literals +that contain only ASCII characters. + +### Why is this bad? +Byte string literals (e.g., `b"foo"`) can be used +instead. They are shorter but less discoverable than `as_bytes()`. + +### Known problems +`"str".as_bytes()` and the suggested replacement of `b"str"` are not +equivalent because they have different types. The former is `&[u8]` +while the latter is `&[u8; 3]`. That means in general they will have a +different set of methods and different trait implementations. + +``` +fn f(v: Vec) {} + +f("...".as_bytes().to_owned()); // works +f(b"...".to_owned()); // does not work, because arg is [u8; 3] not Vec + +fn g(r: impl std::io::Read) {} + +g("...".as_bytes()); // works +g(b"..."); // does not work +``` + +The actual equivalent of `"str".as_bytes()` with the same type is not +`b"str"` but `&b"str"[..]`, which is a great deal of punctuation and not +more readable than a function call. + +### Example +``` +let bstr = "a byte string".as_bytes(); +``` + +Use instead: +``` +let bstr = b"a byte string"; +``` \ No newline at end of file diff --git a/src/docs/string_slice.txt b/src/docs/string_slice.txt new file mode 100644 index 000000000000..3d9e49dd39eb --- /dev/null +++ b/src/docs/string_slice.txt @@ -0,0 +1,17 @@ +### What it does +Checks for slice operations on strings + +### Why is this bad? +UTF-8 characters span multiple bytes, and it is easy to inadvertently confuse character +counts and string indices. This may lead to panics, and should warrant some test cases +containing wide UTF-8 characters. This lint is most useful in code that should avoid +panics at all costs. + +### Known problems +Probably lots of false positives. If an index comes from a known valid position (e.g. +obtained via `char_indices` over the same string), it is totally OK. + +# Example +``` +&"Ölkanne"[1..]; +``` \ No newline at end of file diff --git a/src/docs/string_to_string.txt b/src/docs/string_to_string.txt new file mode 100644 index 000000000000..deb7eebe7842 --- /dev/null +++ b/src/docs/string_to_string.txt @@ -0,0 +1,19 @@ +### What it does +This lint checks for `.to_string()` method calls on values of type `String`. + +### Why is this bad? +The `to_string` method is also used on other types to convert them to a string. +When called on a `String` it only clones the `String`, which can be better expressed with `.clone()`. + +### Example +``` +// example code where clippy issues a warning +let msg = String::from("Hello World"); +let _ = msg.to_string(); +``` +Use instead: +``` +// example code which does not raise clippy warning +let msg = String::from("Hello World"); +let _ = msg.clone(); +``` \ No newline at end of file diff --git a/src/docs/strlen_on_c_strings.txt b/src/docs/strlen_on_c_strings.txt new file mode 100644 index 000000000000..0454abf55a20 --- /dev/null +++ b/src/docs/strlen_on_c_strings.txt @@ -0,0 +1,20 @@ +### What it does +Checks for usage of `libc::strlen` on a `CString` or `CStr` value, +and suggest calling `as_bytes().len()` or `to_bytes().len()` respectively instead. + +### Why is this bad? +This avoids calling an unsafe `libc` function. +Currently, it also avoids calculating the length. + +### Example +``` +use std::ffi::CString; +let cstring = CString::new("foo").expect("CString::new failed"); +let len = unsafe { libc::strlen(cstring.as_ptr()) }; +``` +Use instead: +``` +use std::ffi::CString; +let cstring = CString::new("foo").expect("CString::new failed"); +let len = cstring.as_bytes().len(); +``` \ No newline at end of file diff --git a/src/docs/struct_excessive_bools.txt b/src/docs/struct_excessive_bools.txt new file mode 100644 index 000000000000..9e197c786201 --- /dev/null +++ b/src/docs/struct_excessive_bools.txt @@ -0,0 +1,29 @@ +### What it does +Checks for excessive +use of bools in structs. + +### Why is this bad? +Excessive bools in a struct +is often a sign that it's used as a state machine, +which is much better implemented as an enum. +If it's not the case, excessive bools usually benefit +from refactoring into two-variant enums for better +readability and API. + +### Example +``` +struct S { + is_pending: bool, + is_processing: bool, + is_finished: bool, +} +``` + +Use instead: +``` +enum S { + Pending, + Processing, + Finished, +} +``` \ No newline at end of file diff --git a/src/docs/suboptimal_flops.txt b/src/docs/suboptimal_flops.txt new file mode 100644 index 000000000000..f1c9c665b085 --- /dev/null +++ b/src/docs/suboptimal_flops.txt @@ -0,0 +1,50 @@ +### What it does +Looks for floating-point expressions that +can be expressed using built-in methods to improve both +accuracy and performance. + +### Why is this bad? +Negatively impacts accuracy and performance. + +### Example +``` +use std::f32::consts::E; + +let a = 3f32; +let _ = (2f32).powf(a); +let _ = E.powf(a); +let _ = a.powf(1.0 / 2.0); +let _ = a.log(2.0); +let _ = a.log(10.0); +let _ = a.log(E); +let _ = a.powf(2.0); +let _ = a * 2.0 + 4.0; +let _ = if a < 0.0 { + -a +} else { + a +}; +let _ = if a < 0.0 { + a +} else { + -a +}; +``` + +is better expressed as + +``` +use std::f32::consts::E; + +let a = 3f32; +let _ = a.exp2(); +let _ = a.exp(); +let _ = a.sqrt(); +let _ = a.log2(); +let _ = a.log10(); +let _ = a.ln(); +let _ = a.powi(2); +let _ = a.mul_add(2.0, 4.0); +let _ = a.abs(); +let _ = -a.abs(); +``` \ No newline at end of file diff --git a/src/docs/suspicious_arithmetic_impl.txt b/src/docs/suspicious_arithmetic_impl.txt new file mode 100644 index 000000000000..d67ff279346d --- /dev/null +++ b/src/docs/suspicious_arithmetic_impl.txt @@ -0,0 +1,17 @@ +### What it does +Lints for suspicious operations in impls of arithmetic operators, e.g. +subtracting elements in an Add impl. + +### Why is this bad? +This is probably a typo or copy-and-paste error and not intended. + +### Example +``` +impl Add for Foo { + type Output = Foo; + + fn add(self, other: Foo) -> Foo { + Foo(self.0 - other.0) + } +} +``` \ No newline at end of file diff --git a/src/docs/suspicious_assignment_formatting.txt b/src/docs/suspicious_assignment_formatting.txt new file mode 100644 index 000000000000..b889827cdf27 --- /dev/null +++ b/src/docs/suspicious_assignment_formatting.txt @@ -0,0 +1,12 @@ +### What it does +Checks for use of the non-existent `=*`, `=!` and `=-` +operators. + +### Why is this bad? +This is either a typo of `*=`, `!=` or `-=` or +confusing. + +### Example +``` +a =- 42; // confusing, should it be `a -= 42` or `a = -42`? +``` \ No newline at end of file diff --git a/src/docs/suspicious_else_formatting.txt b/src/docs/suspicious_else_formatting.txt new file mode 100644 index 000000000000..3cf2f74868eb --- /dev/null +++ b/src/docs/suspicious_else_formatting.txt @@ -0,0 +1,30 @@ +### What it does +Checks for formatting of `else`. It lints if the `else` +is followed immediately by a newline or the `else` seems to be missing. + +### Why is this bad? +This is probably some refactoring remnant, even if the +code is correct, it might look confusing. + +### Example +``` +if foo { +} { // looks like an `else` is missing here +} + +if foo { +} if bar { // looks like an `else` is missing here +} + +if foo { +} else + +{ // this is the `else` block of the previous `if`, but should it be? +} + +if foo { +} else + +if bar { // this is the `else` block of the previous `if`, but should it be? +} +``` \ No newline at end of file diff --git a/src/docs/suspicious_map.txt b/src/docs/suspicious_map.txt new file mode 100644 index 000000000000..d8fa52c43fb0 --- /dev/null +++ b/src/docs/suspicious_map.txt @@ -0,0 +1,13 @@ +### What it does +Checks for calls to `map` followed by a `count`. + +### Why is this bad? +It looks suspicious. Maybe `map` was confused with `filter`. +If the `map` call is intentional, this should be rewritten +using `inspect`. Or, if you intend to drive the iterator to +completion, you can just use `for_each` instead. + +### Example +``` +let _ = (0..3).map(|x| x + 2).count(); +``` \ No newline at end of file diff --git a/src/docs/suspicious_op_assign_impl.txt b/src/docs/suspicious_op_assign_impl.txt new file mode 100644 index 000000000000..81abfbecae07 --- /dev/null +++ b/src/docs/suspicious_op_assign_impl.txt @@ -0,0 +1,15 @@ +### What it does +Lints for suspicious operations in impls of OpAssign, e.g. +subtracting elements in an AddAssign impl. + +### Why is this bad? +This is probably a typo or copy-and-paste error and not intended. + +### Example +``` +impl AddAssign for Foo { + fn add_assign(&mut self, other: Foo) { + *self = *self - other; + } +} +``` \ No newline at end of file diff --git a/src/docs/suspicious_operation_groupings.txt b/src/docs/suspicious_operation_groupings.txt new file mode 100644 index 000000000000..81ede5d3da57 --- /dev/null +++ b/src/docs/suspicious_operation_groupings.txt @@ -0,0 +1,41 @@ +### What it does +Checks for unlikely usages of binary operators that are almost +certainly typos and/or copy/paste errors, given the other usages +of binary operators nearby. + +### Why is this bad? +They are probably bugs and if they aren't then they look like bugs +and you should add a comment explaining why you are doing such an +odd set of operations. + +### Known problems +There may be some false positives if you are trying to do something +unusual that happens to look like a typo. + +### Example +``` +struct Vec3 { + x: f64, + y: f64, + z: f64, +} + +impl Eq for Vec3 {} + +impl PartialEq for Vec3 { + fn eq(&self, other: &Self) -> bool { + // This should trigger the lint because `self.x` is compared to `other.y` + self.x == other.y && self.y == other.y && self.z == other.z + } +} +``` +Use instead: +``` +// same as above except: +impl PartialEq for Vec3 { + fn eq(&self, other: &Self) -> bool { + // Note we now compare other.x to self.x + self.x == other.x && self.y == other.y && self.z == other.z + } +} +``` \ No newline at end of file diff --git a/src/docs/suspicious_splitn.txt b/src/docs/suspicious_splitn.txt new file mode 100644 index 000000000000..79a3dbfa6f4a --- /dev/null +++ b/src/docs/suspicious_splitn.txt @@ -0,0 +1,22 @@ +### What it does +Checks for calls to [`splitn`] +(https://doc.rust-lang.org/std/primitive.str.html#method.splitn) and +related functions with either zero or one splits. + +### Why is this bad? +These calls don't actually split the value and are +likely to be intended as a different number. + +### Example +``` +for x in s.splitn(1, ":") { + // .. +} +``` + +Use instead: +``` +for x in s.splitn(2, ":") { + // .. +} +``` \ No newline at end of file diff --git a/src/docs/suspicious_to_owned.txt b/src/docs/suspicious_to_owned.txt new file mode 100644 index 000000000000..8cbf61dc7175 --- /dev/null +++ b/src/docs/suspicious_to_owned.txt @@ -0,0 +1,39 @@ +### What it does +Checks for the usage of `_.to_owned()`, on a `Cow<'_, _>`. + +### Why is this bad? +Calling `to_owned()` on a `Cow` creates a clone of the `Cow` +itself, without taking ownership of the `Cow` contents (i.e. +it's equivalent to calling `Cow::clone`). +The similarly named `into_owned` method, on the other hand, +clones the `Cow` contents, effectively turning any `Cow::Borrowed` +into a `Cow::Owned`. + +Given the potential ambiguity, consider replacing `to_owned` +with `clone` for better readability or, if getting a `Cow::Owned` +was the original intent, using `into_owned` instead. + +### Example +``` +let s = "Hello world!"; +let cow = Cow::Borrowed(s); + +let data = cow.to_owned(); +assert!(matches!(data, Cow::Borrowed(_))) +``` +Use instead: +``` +let s = "Hello world!"; +let cow = Cow::Borrowed(s); + +let data = cow.clone(); +assert!(matches!(data, Cow::Borrowed(_))) +``` +or +``` +let s = "Hello world!"; +let cow = Cow::Borrowed(s); + +let data = cow.into_owned(); +assert!(matches!(data, String)) +``` \ No newline at end of file diff --git a/src/docs/suspicious_unary_op_formatting.txt b/src/docs/suspicious_unary_op_formatting.txt new file mode 100644 index 000000000000..06fb09db76d0 --- /dev/null +++ b/src/docs/suspicious_unary_op_formatting.txt @@ -0,0 +1,18 @@ +### What it does +Checks the formatting of a unary operator on the right hand side +of a binary operator. It lints if there is no space between the binary and unary operators, +but there is a space between the unary and its operand. + +### Why is this bad? +This is either a typo in the binary operator or confusing. + +### Example +``` +// &&! looks like a different operator +if foo &&! bar {} +``` + +Use instead: +``` +if foo && !bar {} +``` \ No newline at end of file diff --git a/src/docs/swap_ptr_to_ref.txt b/src/docs/swap_ptr_to_ref.txt new file mode 100644 index 000000000000..0215d1e8a421 --- /dev/null +++ b/src/docs/swap_ptr_to_ref.txt @@ -0,0 +1,23 @@ +### What it does +Checks for calls to `core::mem::swap` where either parameter is derived from a pointer + +### Why is this bad? +When at least one parameter to `swap` is derived from a pointer it may overlap with the +other. This would then lead to undefined behavior. + +### Example +``` +unsafe fn swap(x: &[*mut u32], y: &[*mut u32]) { + for (&x, &y) in x.iter().zip(y) { + core::mem::swap(&mut *x, &mut *y); + } +} +``` +Use instead: +``` +unsafe fn swap(x: &[*mut u32], y: &[*mut u32]) { + for (&x, &y) in x.iter().zip(y) { + core::ptr::swap(x, y); + } +} +``` \ No newline at end of file diff --git a/src/docs/tabs_in_doc_comments.txt b/src/docs/tabs_in_doc_comments.txt new file mode 100644 index 000000000000..f83dbe2b73cb --- /dev/null +++ b/src/docs/tabs_in_doc_comments.txt @@ -0,0 +1,44 @@ +### What it does +Checks doc comments for usage of tab characters. + +### Why is this bad? +The rust style-guide promotes spaces instead of tabs for indentation. +To keep a consistent view on the source, also doc comments should not have tabs. +Also, explaining ascii-diagrams containing tabs can get displayed incorrectly when the +display settings of the author and reader differ. + +### Example +``` +/// +/// Struct to hold two strings: +/// - first one +/// - second one +pub struct DoubleString { + /// + /// - First String: + /// - needs to be inside here + first_string: String, + /// + /// - Second String: + /// - needs to be inside here + second_string: String, +} +``` + +Will be converted to: +``` +/// +/// Struct to hold two strings: +/// - first one +/// - second one +pub struct DoubleString { + /// + /// - First String: + /// - needs to be inside here + first_string: String, + /// + /// - Second String: + /// - needs to be inside here + second_string: String, +} +``` \ No newline at end of file diff --git a/src/docs/temporary_assignment.txt b/src/docs/temporary_assignment.txt new file mode 100644 index 000000000000..195b42cf0d49 --- /dev/null +++ b/src/docs/temporary_assignment.txt @@ -0,0 +1,12 @@ +### What it does +Checks for construction of a structure or tuple just to +assign a value in it. + +### Why is this bad? +Readability. If the structure is only created to be +updated, why not write the structure you want in the first place? + +### Example +``` +(0, 0).0 = 1 +``` \ No newline at end of file diff --git a/src/docs/to_digit_is_some.txt b/src/docs/to_digit_is_some.txt new file mode 100644 index 000000000000..eee8375adf7a --- /dev/null +++ b/src/docs/to_digit_is_some.txt @@ -0,0 +1,15 @@ +### What it does +Checks for `.to_digit(..).is_some()` on `char`s. + +### Why is this bad? +This is a convoluted way of checking if a `char` is a digit. It's +more straight forward to use the dedicated `is_digit` method. + +### Example +``` +let is_digit = c.to_digit(radix).is_some(); +``` +can be written as: +``` +let is_digit = c.is_digit(radix); +``` \ No newline at end of file diff --git a/src/docs/to_string_in_format_args.txt b/src/docs/to_string_in_format_args.txt new file mode 100644 index 000000000000..34b20583585a --- /dev/null +++ b/src/docs/to_string_in_format_args.txt @@ -0,0 +1,17 @@ +### What it does +Checks for [`ToString::to_string`](https://doc.rust-lang.org/std/string/trait.ToString.html#tymethod.to_string) +applied to a type that implements [`Display`](https://doc.rust-lang.org/std/fmt/trait.Display.html) +in a macro that does formatting. + +### Why is this bad? +Since the type implements `Display`, the use of `to_string` is +unnecessary. + +### Example +``` +println!("error: something failed at {}", Location::caller().to_string()); +``` +Use instead: +``` +println!("error: something failed at {}", Location::caller()); +``` \ No newline at end of file diff --git a/src/docs/todo.txt b/src/docs/todo.txt new file mode 100644 index 000000000000..661eb1ac5cff --- /dev/null +++ b/src/docs/todo.txt @@ -0,0 +1,10 @@ +### What it does +Checks for usage of `todo!`. + +### Why is this bad? +This macro should not be present in production code + +### Example +``` +todo!(); +``` \ No newline at end of file diff --git a/src/docs/too_many_arguments.txt b/src/docs/too_many_arguments.txt new file mode 100644 index 000000000000..4669f9f82e66 --- /dev/null +++ b/src/docs/too_many_arguments.txt @@ -0,0 +1,14 @@ +### What it does +Checks for functions with too many parameters. + +### Why is this bad? +Functions with lots of parameters are considered bad +style and reduce readability (“what does the 5th parameter mean?”). Consider +grouping some parameters into a new type. + +### Example +``` +fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: f32) { + // .. +} +``` \ No newline at end of file diff --git a/src/docs/too_many_lines.txt b/src/docs/too_many_lines.txt new file mode 100644 index 000000000000..425db348bbd7 --- /dev/null +++ b/src/docs/too_many_lines.txt @@ -0,0 +1,17 @@ +### What it does +Checks for functions with a large amount of lines. + +### Why is this bad? +Functions with a lot of lines are harder to understand +due to having to look at a larger amount of code to understand what the +function is doing. Consider splitting the body of the function into +multiple functions. + +### Example +``` +fn im_too_long() { + println!(""); + // ... 100 more LoC + println!(""); +} +``` \ No newline at end of file diff --git a/src/docs/toplevel_ref_arg.txt b/src/docs/toplevel_ref_arg.txt new file mode 100644 index 000000000000..96a9e2db8b7e --- /dev/null +++ b/src/docs/toplevel_ref_arg.txt @@ -0,0 +1,28 @@ +### What it does +Checks for function arguments and let bindings denoted as +`ref`. + +### Why is this bad? +The `ref` declaration makes the function take an owned +value, but turns the argument into a reference (which means that the value +is destroyed when exiting the function). This adds not much value: either +take a reference type, or take an owned value and create references in the +body. + +For let bindings, `let x = &foo;` is preferred over `let ref x = foo`. The +type of `x` is more obvious with the former. + +### Known problems +If the argument is dereferenced within the function, +removing the `ref` will lead to errors. This can be fixed by removing the +dereferences, e.g., changing `*x` to `x` within the function. + +### Example +``` +fn foo(ref _x: u8) {} +``` + +Use instead: +``` +fn foo(_x: &u8) {} +``` \ No newline at end of file diff --git a/src/docs/trailing_empty_array.txt b/src/docs/trailing_empty_array.txt new file mode 100644 index 000000000000..db1908cc96d0 --- /dev/null +++ b/src/docs/trailing_empty_array.txt @@ -0,0 +1,22 @@ +### What it does +Displays a warning when a struct with a trailing zero-sized array is declared without a `repr` attribute. + +### Why is this bad? +Zero-sized arrays aren't very useful in Rust itself, so such a struct is likely being created to pass to C code or in some other situation where control over memory layout matters (for example, in conjunction with manual allocation to make it easy to compute the offset of the array). Either way, `#[repr(C)]` (or another `repr` attribute) is needed. + +### Example +``` +struct RarelyUseful { + some_field: u32, + last: [u32; 0], +} +``` + +Use instead: +``` +#[repr(C)] +struct MoreOftenUseful { + some_field: usize, + last: [u32; 0], +} +``` \ No newline at end of file diff --git a/src/docs/trait_duplication_in_bounds.txt b/src/docs/trait_duplication_in_bounds.txt new file mode 100644 index 000000000000..509736bb3644 --- /dev/null +++ b/src/docs/trait_duplication_in_bounds.txt @@ -0,0 +1,37 @@ +### What it does +Checks for cases where generics are being used and multiple +syntax specifications for trait bounds are used simultaneously. + +### Why is this bad? +Duplicate bounds makes the code +less readable than specifying them only once. + +### Example +``` +fn func(arg: T) where T: Clone + Default {} +``` + +Use instead: +``` +fn func(arg: T) {} + +// or + +fn func(arg: T) where T: Clone + Default {} +``` + +``` +fn foo(bar: T) {} +``` +Use instead: +``` +fn foo(bar: T) {} +``` + +``` +fn foo(bar: T) where T: Default + Default {} +``` +Use instead: +``` +fn foo(bar: T) where T: Default {} +``` \ No newline at end of file diff --git a/src/docs/transmute_bytes_to_str.txt b/src/docs/transmute_bytes_to_str.txt new file mode 100644 index 000000000000..75889b9c73ae --- /dev/null +++ b/src/docs/transmute_bytes_to_str.txt @@ -0,0 +1,27 @@ +### What it does +Checks for transmutes from a `&[u8]` to a `&str`. + +### Why is this bad? +Not every byte slice is a valid UTF-8 string. + +### Known problems +- [`from_utf8`] which this lint suggests using is slower than `transmute` +as it needs to validate the input. +If you are certain that the input is always a valid UTF-8, +use [`from_utf8_unchecked`] which is as fast as `transmute` +but has a semantically meaningful name. +- You might want to handle errors returned from [`from_utf8`] instead of calling `unwrap`. + +[`from_utf8`]: https://doc.rust-lang.org/std/str/fn.from_utf8.html +[`from_utf8_unchecked`]: https://doc.rust-lang.org/std/str/fn.from_utf8_unchecked.html + +### Example +``` +let b: &[u8] = &[1_u8, 2_u8]; +unsafe { + let _: &str = std::mem::transmute(b); // where b: &[u8] +} + +// should be: +let _ = std::str::from_utf8(b).unwrap(); +``` \ No newline at end of file diff --git a/src/docs/transmute_float_to_int.txt b/src/docs/transmute_float_to_int.txt new file mode 100644 index 000000000000..1877e5a465a4 --- /dev/null +++ b/src/docs/transmute_float_to_int.txt @@ -0,0 +1,16 @@ +### What it does +Checks for transmutes from a float to an integer. + +### Why is this bad? +Transmutes are dangerous and error-prone, whereas `to_bits` is intuitive +and safe. + +### Example +``` +unsafe { + let _: u32 = std::mem::transmute(1f32); +} + +// should be: +let _: u32 = 1f32.to_bits(); +``` \ No newline at end of file diff --git a/src/docs/transmute_int_to_bool.txt b/src/docs/transmute_int_to_bool.txt new file mode 100644 index 000000000000..07c10f8d0bca --- /dev/null +++ b/src/docs/transmute_int_to_bool.txt @@ -0,0 +1,16 @@ +### What it does +Checks for transmutes from an integer to a `bool`. + +### Why is this bad? +This might result in an invalid in-memory representation of a `bool`. + +### Example +``` +let x = 1_u8; +unsafe { + let _: bool = std::mem::transmute(x); // where x: u8 +} + +// should be: +let _: bool = x != 0; +``` \ No newline at end of file diff --git a/src/docs/transmute_int_to_char.txt b/src/docs/transmute_int_to_char.txt new file mode 100644 index 000000000000..836d22d3f99c --- /dev/null +++ b/src/docs/transmute_int_to_char.txt @@ -0,0 +1,27 @@ +### What it does +Checks for transmutes from an integer to a `char`. + +### Why is this bad? +Not every integer is a Unicode scalar value. + +### Known problems +- [`from_u32`] which this lint suggests using is slower than `transmute` +as it needs to validate the input. +If you are certain that the input is always a valid Unicode scalar value, +use [`from_u32_unchecked`] which is as fast as `transmute` +but has a semantically meaningful name. +- You might want to handle `None` returned from [`from_u32`] instead of calling `unwrap`. + +[`from_u32`]: https://doc.rust-lang.org/std/char/fn.from_u32.html +[`from_u32_unchecked`]: https://doc.rust-lang.org/std/char/fn.from_u32_unchecked.html + +### Example +``` +let x = 1_u32; +unsafe { + let _: char = std::mem::transmute(x); // where x: u32 +} + +// should be: +let _ = std::char::from_u32(x).unwrap(); +``` \ No newline at end of file diff --git a/src/docs/transmute_int_to_float.txt b/src/docs/transmute_int_to_float.txt new file mode 100644 index 000000000000..75cdc62e9727 --- /dev/null +++ b/src/docs/transmute_int_to_float.txt @@ -0,0 +1,16 @@ +### What it does +Checks for transmutes from an integer to a float. + +### Why is this bad? +Transmutes are dangerous and error-prone, whereas `from_bits` is intuitive +and safe. + +### Example +``` +unsafe { + let _: f32 = std::mem::transmute(1_u32); // where x: u32 +} + +// should be: +let _: f32 = f32::from_bits(1_u32); +``` \ No newline at end of file diff --git a/src/docs/transmute_num_to_bytes.txt b/src/docs/transmute_num_to_bytes.txt new file mode 100644 index 000000000000..a2c39a1b947e --- /dev/null +++ b/src/docs/transmute_num_to_bytes.txt @@ -0,0 +1,16 @@ +### What it does +Checks for transmutes from a number to an array of `u8` + +### Why this is bad? +Transmutes are dangerous and error-prone, whereas `to_ne_bytes` +is intuitive and safe. + +### Example +``` +unsafe { + let x: [u8; 8] = std::mem::transmute(1i64); +} + +// should be +let x: [u8; 8] = 0i64.to_ne_bytes(); +``` \ No newline at end of file diff --git a/src/docs/transmute_ptr_to_ptr.txt b/src/docs/transmute_ptr_to_ptr.txt new file mode 100644 index 000000000000..65777db98618 --- /dev/null +++ b/src/docs/transmute_ptr_to_ptr.txt @@ -0,0 +1,21 @@ +### What it does +Checks for transmutes from a pointer to a pointer, or +from a reference to a reference. + +### Why is this bad? +Transmutes are dangerous, and these can instead be +written as casts. + +### Example +``` +let ptr = &1u32 as *const u32; +unsafe { + // pointer-to-pointer transmute + let _: *const f32 = std::mem::transmute(ptr); + // ref-ref transmute + let _: &f32 = std::mem::transmute(&1u32); +} +// These can be respectively written: +let _ = ptr as *const f32; +let _ = unsafe{ &*(&1u32 as *const u32 as *const f32) }; +``` \ No newline at end of file diff --git a/src/docs/transmute_ptr_to_ref.txt b/src/docs/transmute_ptr_to_ref.txt new file mode 100644 index 000000000000..aca550f5036e --- /dev/null +++ b/src/docs/transmute_ptr_to_ref.txt @@ -0,0 +1,21 @@ +### What it does +Checks for transmutes from a pointer to a reference. + +### Why is this bad? +This can always be rewritten with `&` and `*`. + +### Known problems +- `mem::transmute` in statics and constants is stable from Rust 1.46.0, +while dereferencing raw pointer is not stable yet. +If you need to do this in those places, +you would have to use `transmute` instead. + +### Example +``` +unsafe { + let _: &T = std::mem::transmute(p); // where p: *const T +} + +// can be written: +let _: &T = &*p; +``` \ No newline at end of file diff --git a/src/docs/transmute_undefined_repr.txt b/src/docs/transmute_undefined_repr.txt new file mode 100644 index 000000000000..5ee6aaf4ca92 --- /dev/null +++ b/src/docs/transmute_undefined_repr.txt @@ -0,0 +1,22 @@ +### What it does +Checks for transmutes between types which do not have a representation defined relative to +each other. + +### Why is this bad? +The results of such a transmute are not defined. + +### Known problems +This lint has had multiple problems in the past and was moved to `nursery`. See issue +[#8496](https://github.com/rust-lang/rust-clippy/issues/8496) for more details. + +### Example +``` +struct Foo(u32, T); +let _ = unsafe { core::mem::transmute::, Foo>(Foo(0u32, 0u32)) }; +``` +Use instead: +``` +#[repr(C)] +struct Foo(u32, T); +let _ = unsafe { core::mem::transmute::, Foo>(Foo(0u32, 0u32)) }; +``` \ No newline at end of file diff --git a/src/docs/transmutes_expressible_as_ptr_casts.txt b/src/docs/transmutes_expressible_as_ptr_casts.txt new file mode 100644 index 000000000000..b68a8cda9c74 --- /dev/null +++ b/src/docs/transmutes_expressible_as_ptr_casts.txt @@ -0,0 +1,16 @@ +### What it does +Checks for transmutes that could be a pointer cast. + +### Why is this bad? +Readability. The code tricks people into thinking that +something complex is going on. + +### Example + +``` +unsafe { std::mem::transmute::<*const [i32], *const [u16]>(p) }; +``` +Use instead: +``` +p as *const [u16]; +``` \ No newline at end of file diff --git a/src/docs/transmuting_null.txt b/src/docs/transmuting_null.txt new file mode 100644 index 000000000000..f8bacfc0b90b --- /dev/null +++ b/src/docs/transmuting_null.txt @@ -0,0 +1,15 @@ +### What it does +Checks for transmute calls which would receive a null pointer. + +### Why is this bad? +Transmuting a null pointer is undefined behavior. + +### Known problems +Not all cases can be detected at the moment of this writing. +For example, variables which hold a null pointer and are then fed to a `transmute` +call, aren't detectable yet. + +### Example +``` +let null_ref: &u64 = unsafe { std::mem::transmute(0 as *const u64) }; +``` \ No newline at end of file diff --git a/src/docs/trim_split_whitespace.txt b/src/docs/trim_split_whitespace.txt new file mode 100644 index 000000000000..f7e3e7858f94 --- /dev/null +++ b/src/docs/trim_split_whitespace.txt @@ -0,0 +1,14 @@ +### What it does +Warns about calling `str::trim` (or variants) before `str::split_whitespace`. + +### Why is this bad? +`split_whitespace` already ignores leading and trailing whitespace. + +### Example +``` +" A B C ".trim().split_whitespace(); +``` +Use instead: +``` +" A B C ".split_whitespace(); +``` \ No newline at end of file diff --git a/src/docs/trivial_regex.txt b/src/docs/trivial_regex.txt new file mode 100644 index 000000000000..f71d667fd771 --- /dev/null +++ b/src/docs/trivial_regex.txt @@ -0,0 +1,18 @@ +### What it does +Checks for trivial [regex](https://crates.io/crates/regex) +creation (with `Regex::new`, `RegexBuilder::new`, or `RegexSet::new`). + +### Why is this bad? +Matching the regex can likely be replaced by `==` or +`str::starts_with`, `str::ends_with` or `std::contains` or other `str` +methods. + +### Known problems +If the same regex is going to be applied to multiple +inputs, the precomputations done by `Regex` construction can give +significantly better performance than any of the `str`-based methods. + +### Example +``` +Regex::new("^foobar") +``` \ No newline at end of file diff --git a/src/docs/trivially_copy_pass_by_ref.txt b/src/docs/trivially_copy_pass_by_ref.txt new file mode 100644 index 000000000000..f54cce5e2bd7 --- /dev/null +++ b/src/docs/trivially_copy_pass_by_ref.txt @@ -0,0 +1,43 @@ +### What it does +Checks for functions taking arguments by reference, where +the argument type is `Copy` and small enough to be more efficient to always +pass by value. + +### Why is this bad? +In many calling conventions instances of structs will +be passed through registers if they fit into two or less general purpose +registers. + +### Known problems +This lint is target register size dependent, it is +limited to 32-bit to try and reduce portability problems between 32 and +64-bit, but if you are compiling for 8 or 16-bit targets then the limit +will be different. + +The configuration option `trivial_copy_size_limit` can be set to override +this limit for a project. + +This lint attempts to allow passing arguments by reference if a reference +to that argument is returned. This is implemented by comparing the lifetime +of the argument and return value for equality. However, this can cause +false positives in cases involving multiple lifetimes that are bounded by +each other. + +Also, it does not take account of other similar cases where getting memory addresses +matters; namely, returning the pointer to the argument in question, +and passing the argument, as both references and pointers, +to a function that needs the memory address. For further details, refer to +[this issue](https://github.com/rust-lang/rust-clippy/issues/5953) +that explains a real case in which this false positive +led to an **undefined behavior** introduced with unsafe code. + +### Example + +``` +fn foo(v: &u32) {} +``` + +Use instead: +``` +fn foo(v: u32) {} +``` \ No newline at end of file diff --git a/src/docs/try_err.txt b/src/docs/try_err.txt new file mode 100644 index 000000000000..e3d4ef3a09df --- /dev/null +++ b/src/docs/try_err.txt @@ -0,0 +1,28 @@ +### What it does +Checks for usages of `Err(x)?`. + +### Why is this bad? +The `?` operator is designed to allow calls that +can fail to be easily chained. For example, `foo()?.bar()` or +`foo(bar()?)`. Because `Err(x)?` can't be used that way (it will +always return), it is more clear to write `return Err(x)`. + +### Example +``` +fn foo(fail: bool) -> Result { + if fail { + Err("failed")?; + } + Ok(0) +} +``` +Could be written: + +``` +fn foo(fail: bool) -> Result { + if fail { + return Err("failed".into()); + } + Ok(0) +} +``` \ No newline at end of file diff --git a/src/docs/type_complexity.txt b/src/docs/type_complexity.txt new file mode 100644 index 000000000000..69cd87500504 --- /dev/null +++ b/src/docs/type_complexity.txt @@ -0,0 +1,14 @@ +### What it does +Checks for types used in structs, parameters and `let` +declarations above a certain complexity threshold. + +### Why is this bad? +Too complex types make the code less readable. Consider +using a `type` definition to simplify them. + +### Example +``` +struct Foo { + inner: Rc>>>, +} +``` \ No newline at end of file diff --git a/src/docs/type_repetition_in_bounds.txt b/src/docs/type_repetition_in_bounds.txt new file mode 100644 index 000000000000..18ed372fd13e --- /dev/null +++ b/src/docs/type_repetition_in_bounds.txt @@ -0,0 +1,16 @@ +### What it does +This lint warns about unnecessary type repetitions in trait bounds + +### Why is this bad? +Repeating the type for every bound makes the code +less readable than combining the bounds + +### Example +``` +pub fn foo(t: T) where T: Copy, T: Clone {} +``` + +Use instead: +``` +pub fn foo(t: T) where T: Copy + Clone {} +``` \ No newline at end of file diff --git a/src/docs/undocumented_unsafe_blocks.txt b/src/docs/undocumented_unsafe_blocks.txt new file mode 100644 index 000000000000..f3af4753c5f7 --- /dev/null +++ b/src/docs/undocumented_unsafe_blocks.txt @@ -0,0 +1,43 @@ +### What it does +Checks for `unsafe` blocks and impls without a `// SAFETY: ` comment +explaining why the unsafe operations performed inside +the block are safe. + +Note the comment must appear on the line(s) preceding the unsafe block +with nothing appearing in between. The following is ok: +``` +foo( + // SAFETY: + // This is a valid safety comment + unsafe { *x } +) +``` +But neither of these are: +``` +// SAFETY: +// This is not a valid safety comment +foo( + /* SAFETY: Neither is this */ unsafe { *x }, +); +``` + +### Why is this bad? +Undocumented unsafe blocks and impls can make it difficult to +read and maintain code, as well as uncover unsoundness +and bugs. + +### Example +``` +use std::ptr::NonNull; +let a = &mut 42; + +let ptr = unsafe { NonNull::new_unchecked(a) }; +``` +Use instead: +``` +use std::ptr::NonNull; +let a = &mut 42; + +// SAFETY: references are guaranteed to be non-null. +let ptr = unsafe { NonNull::new_unchecked(a) }; +``` \ No newline at end of file diff --git a/src/docs/undropped_manually_drops.txt b/src/docs/undropped_manually_drops.txt new file mode 100644 index 000000000000..85e3ec56653c --- /dev/null +++ b/src/docs/undropped_manually_drops.txt @@ -0,0 +1,22 @@ +### What it does +Prevents the safe `std::mem::drop` function from being called on `std::mem::ManuallyDrop`. + +### Why is this bad? +The safe `drop` function does not drop the inner value of a `ManuallyDrop`. + +### Known problems +Does not catch cases if the user binds `std::mem::drop` +to a different name and calls it that way. + +### Example +``` +struct S; +drop(std::mem::ManuallyDrop::new(S)); +``` +Use instead: +``` +struct S; +unsafe { + std::mem::ManuallyDrop::drop(&mut std::mem::ManuallyDrop::new(S)); +} +``` \ No newline at end of file diff --git a/src/docs/unicode_not_nfc.txt b/src/docs/unicode_not_nfc.txt new file mode 100644 index 000000000000..c660c51dadb2 --- /dev/null +++ b/src/docs/unicode_not_nfc.txt @@ -0,0 +1,12 @@ +### What it does +Checks for string literals that contain Unicode in a form +that is not equal to its +[NFC-recomposition](http://www.unicode.org/reports/tr15/#Norm_Forms). + +### Why is this bad? +If such a string is compared to another, the results +may be surprising. + +### Example +You may not see it, but "à"" and "à"" aren't the same string. The +former when escaped is actually `"a\u{300}"` while the latter is `"\u{e0}"`. \ No newline at end of file diff --git a/src/docs/unimplemented.txt b/src/docs/unimplemented.txt new file mode 100644 index 000000000000..7095594fb2e7 --- /dev/null +++ b/src/docs/unimplemented.txt @@ -0,0 +1,10 @@ +### What it does +Checks for usage of `unimplemented!`. + +### Why is this bad? +This macro should not be present in production code + +### Example +``` +unimplemented!(); +``` \ No newline at end of file diff --git a/src/docs/uninit_assumed_init.txt b/src/docs/uninit_assumed_init.txt new file mode 100644 index 000000000000..cca24093d40d --- /dev/null +++ b/src/docs/uninit_assumed_init.txt @@ -0,0 +1,28 @@ +### What it does +Checks for `MaybeUninit::uninit().assume_init()`. + +### Why is this bad? +For most types, this is undefined behavior. + +### Known problems +For now, we accept empty tuples and tuples / arrays +of `MaybeUninit`. There may be other types that allow uninitialized +data, but those are not yet rigorously defined. + +### Example +``` +// Beware the UB +use std::mem::MaybeUninit; + +let _: usize = unsafe { MaybeUninit::uninit().assume_init() }; +``` + +Note that the following is OK: + +``` +use std::mem::MaybeUninit; + +let _: [MaybeUninit; 5] = unsafe { + MaybeUninit::uninit().assume_init() +}; +``` \ No newline at end of file diff --git a/src/docs/uninit_vec.txt b/src/docs/uninit_vec.txt new file mode 100644 index 000000000000..cd50afe78f6f --- /dev/null +++ b/src/docs/uninit_vec.txt @@ -0,0 +1,41 @@ +### What it does +Checks for `set_len()` call that creates `Vec` with uninitialized elements. +This is commonly caused by calling `set_len()` right after allocating or +reserving a buffer with `new()`, `default()`, `with_capacity()`, or `reserve()`. + +### Why is this bad? +It creates a `Vec` with uninitialized data, which leads to +undefined behavior with most safe operations. Notably, uninitialized +`Vec` must not be used with generic `Read`. + +Moreover, calling `set_len()` on a `Vec` created with `new()` or `default()` +creates out-of-bound values that lead to heap memory corruption when used. + +### Known Problems +This lint only checks directly adjacent statements. + +### Example +``` +let mut vec: Vec = Vec::with_capacity(1000); +unsafe { vec.set_len(1000); } +reader.read(&mut vec); // undefined behavior! +``` + +### How to fix? +1. Use an initialized buffer: + ```rust,ignore + let mut vec: Vec = vec![0; 1000]; + reader.read(&mut vec); + ``` +2. Wrap the content in `MaybeUninit`: + ```rust,ignore + let mut vec: Vec> = Vec::with_capacity(1000); + vec.set_len(1000); // `MaybeUninit` can be uninitialized + ``` +3. If you are on 1.60.0 or later, `Vec::spare_capacity_mut()` is available: + ```rust,ignore + let mut vec: Vec = Vec::with_capacity(1000); + let remaining = vec.spare_capacity_mut(); // `&mut [MaybeUninit]` + // perform initialization with `remaining` + vec.set_len(...); // Safe to call `set_len()` on initialized part + ``` \ No newline at end of file diff --git a/src/docs/unit_arg.txt b/src/docs/unit_arg.txt new file mode 100644 index 000000000000..eb83403bb275 --- /dev/null +++ b/src/docs/unit_arg.txt @@ -0,0 +1,14 @@ +### What it does +Checks for passing a unit value as an argument to a function without using a +unit literal (`()`). + +### Why is this bad? +This is likely the result of an accidental semicolon. + +### Example +``` +foo({ + let a = bar(); + baz(a); +}) +``` \ No newline at end of file diff --git a/src/docs/unit_cmp.txt b/src/docs/unit_cmp.txt new file mode 100644 index 000000000000..6f3d62010dc5 --- /dev/null +++ b/src/docs/unit_cmp.txt @@ -0,0 +1,33 @@ +### What it does +Checks for comparisons to unit. This includes all binary +comparisons (like `==` and `<`) and asserts. + +### Why is this bad? +Unit is always equal to itself, and thus is just a +clumsily written constant. Mostly this happens when someone accidentally +adds semicolons at the end of the operands. + +### Example +``` +if { + foo(); +} == { + bar(); +} { + baz(); +} +``` +is equal to +``` +{ + foo(); + bar(); + baz(); +} +``` + +For asserts: +``` +assert_eq!({ foo(); }, { bar(); }); +``` +will always succeed \ No newline at end of file diff --git a/src/docs/unit_hash.txt b/src/docs/unit_hash.txt new file mode 100644 index 000000000000..a22d2994602a --- /dev/null +++ b/src/docs/unit_hash.txt @@ -0,0 +1,20 @@ +### What it does +Detects `().hash(_)`. + +### Why is this bad? +Hashing a unit value doesn't do anything as the implementation of `Hash` for `()` is a no-op. + +### Example +``` +match my_enum { + Empty => ().hash(&mut state), + WithValue(x) => x.hash(&mut state), +} +``` +Use instead: +``` +match my_enum { + Empty => 0_u8.hash(&mut state), + WithValue(x) => x.hash(&mut state), +} +``` \ No newline at end of file diff --git a/src/docs/unit_return_expecting_ord.txt b/src/docs/unit_return_expecting_ord.txt new file mode 100644 index 000000000000..781feac5afcf --- /dev/null +++ b/src/docs/unit_return_expecting_ord.txt @@ -0,0 +1,20 @@ +### What it does +Checks for functions that expect closures of type +Fn(...) -> Ord where the implemented closure returns the unit type. +The lint also suggests to remove the semi-colon at the end of the statement if present. + +### Why is this bad? +Likely, returning the unit type is unintentional, and +could simply be caused by an extra semi-colon. Since () implements Ord +it doesn't cause a compilation error. +This is the same reasoning behind the unit_cmp lint. + +### Known problems +If returning unit is intentional, then there is no +way of specifying this without triggering needless_return lint + +### Example +``` +let mut twins = vec!((1, 1), (2, 2)); +twins.sort_by_key(|x| { x.1; }); +``` \ No newline at end of file diff --git a/src/docs/unnecessary_cast.txt b/src/docs/unnecessary_cast.txt new file mode 100644 index 000000000000..603f2606099c --- /dev/null +++ b/src/docs/unnecessary_cast.txt @@ -0,0 +1,19 @@ +### What it does +Checks for casts to the same type, casts of int literals to integer types +and casts of float literals to float types. + +### Why is this bad? +It's just unnecessary. + +### Example +``` +let _ = 2i32 as i32; +let _ = 0.5 as f32; +``` + +Better: + +``` +let _ = 2_i32; +let _ = 0.5_f32; +``` \ No newline at end of file diff --git a/src/docs/unnecessary_filter_map.txt b/src/docs/unnecessary_filter_map.txt new file mode 100644 index 000000000000..b19341ecf660 --- /dev/null +++ b/src/docs/unnecessary_filter_map.txt @@ -0,0 +1,23 @@ +### What it does +Checks for `filter_map` calls that could be replaced by `filter` or `map`. +More specifically it checks if the closure provided is only performing one of the +filter or map operations and suggests the appropriate option. + +### Why is this bad? +Complexity. The intent is also clearer if only a single +operation is being performed. + +### Example +``` +let _ = (0..3).filter_map(|x| if x > 2 { Some(x) } else { None }); + +// As there is no transformation of the argument this could be written as: +let _ = (0..3).filter(|&x| x > 2); +``` + +``` +let _ = (0..4).filter_map(|x| Some(x + 1)); + +// As there is no conditional check on the argument this could be written as: +let _ = (0..4).map(|x| x + 1); +``` \ No newline at end of file diff --git a/src/docs/unnecessary_find_map.txt b/src/docs/unnecessary_find_map.txt new file mode 100644 index 000000000000..f9444dc48ad6 --- /dev/null +++ b/src/docs/unnecessary_find_map.txt @@ -0,0 +1,23 @@ +### What it does +Checks for `find_map` calls that could be replaced by `find` or `map`. More +specifically it checks if the closure provided is only performing one of the +find or map operations and suggests the appropriate option. + +### Why is this bad? +Complexity. The intent is also clearer if only a single +operation is being performed. + +### Example +``` +let _ = (0..3).find_map(|x| if x > 2 { Some(x) } else { None }); + +// As there is no transformation of the argument this could be written as: +let _ = (0..3).find(|&x| x > 2); +``` + +``` +let _ = (0..4).find_map(|x| Some(x + 1)); + +// As there is no conditional check on the argument this could be written as: +let _ = (0..4).map(|x| x + 1).next(); +``` \ No newline at end of file diff --git a/src/docs/unnecessary_fold.txt b/src/docs/unnecessary_fold.txt new file mode 100644 index 000000000000..e1b0e65f5197 --- /dev/null +++ b/src/docs/unnecessary_fold.txt @@ -0,0 +1,17 @@ +### What it does +Checks for using `fold` when a more succinct alternative exists. +Specifically, this checks for `fold`s which could be replaced by `any`, `all`, +`sum` or `product`. + +### Why is this bad? +Readability. + +### Example +``` +(0..3).fold(false, |acc, x| acc || x > 2); +``` + +Use instead: +``` +(0..3).any(|x| x > 2); +``` \ No newline at end of file diff --git a/src/docs/unnecessary_join.txt b/src/docs/unnecessary_join.txt new file mode 100644 index 000000000000..ee4e78601f84 --- /dev/null +++ b/src/docs/unnecessary_join.txt @@ -0,0 +1,25 @@ +### What it does +Checks for use of `.collect::>().join("")` on iterators. + +### Why is this bad? +`.collect::()` is more concise and might be more performant + +### Example +``` +let vector = vec!["hello", "world"]; +let output = vector.iter().map(|item| item.to_uppercase()).collect::>().join(""); +println!("{}", output); +``` +The correct use would be: +``` +let vector = vec!["hello", "world"]; +let output = vector.iter().map(|item| item.to_uppercase()).collect::(); +println!("{}", output); +``` +### Known problems +While `.collect::()` is sometimes more performant, there are cases where +using `.collect::()` over `.collect::>().join("")` +will prevent loop unrolling and will result in a negative performance impact. + +Additionally, differences have been observed between aarch64 and x86_64 assembly output, +with aarch64 tending to producing faster assembly in more cases when using `.collect::()` \ No newline at end of file diff --git a/src/docs/unnecessary_lazy_evaluations.txt b/src/docs/unnecessary_lazy_evaluations.txt new file mode 100644 index 000000000000..208188ce971a --- /dev/null +++ b/src/docs/unnecessary_lazy_evaluations.txt @@ -0,0 +1,32 @@ +### What it does +As the counterpart to `or_fun_call`, this lint looks for unnecessary +lazily evaluated closures on `Option` and `Result`. + +This lint suggests changing the following functions, when eager evaluation results in +simpler code: + - `unwrap_or_else` to `unwrap_or` + - `and_then` to `and` + - `or_else` to `or` + - `get_or_insert_with` to `get_or_insert` + - `ok_or_else` to `ok_or` + +### Why is this bad? +Using eager evaluation is shorter and simpler in some cases. + +### Known problems +It is possible, but not recommended for `Deref` and `Index` to have +side effects. Eagerly evaluating them can change the semantics of the program. + +### Example +``` +// example code where clippy issues a warning +let opt: Option = None; + +opt.unwrap_or_else(|| 42); +``` +Use instead: +``` +let opt: Option = None; + +opt.unwrap_or(42); +``` \ No newline at end of file diff --git a/src/docs/unnecessary_mut_passed.txt b/src/docs/unnecessary_mut_passed.txt new file mode 100644 index 000000000000..2f8bdd113dfd --- /dev/null +++ b/src/docs/unnecessary_mut_passed.txt @@ -0,0 +1,17 @@ +### What it does +Detects passing a mutable reference to a function that only +requires an immutable reference. + +### Why is this bad? +The mutable reference rules out all other references to +the value. Also the code misleads about the intent of the call site. + +### Example +``` +vec.push(&mut value); +``` + +Use instead: +``` +vec.push(&value); +``` \ No newline at end of file diff --git a/src/docs/unnecessary_operation.txt b/src/docs/unnecessary_operation.txt new file mode 100644 index 000000000000..7f455e264cb3 --- /dev/null +++ b/src/docs/unnecessary_operation.txt @@ -0,0 +1,12 @@ +### What it does +Checks for expression statements that can be reduced to a +sub-expression. + +### Why is this bad? +Expressions by themselves often have no side-effects. +Having such expressions reduces readability. + +### Example +``` +compute_array()[0]; +``` \ No newline at end of file diff --git a/src/docs/unnecessary_owned_empty_strings.txt b/src/docs/unnecessary_owned_empty_strings.txt new file mode 100644 index 000000000000..8cd9fba603e0 --- /dev/null +++ b/src/docs/unnecessary_owned_empty_strings.txt @@ -0,0 +1,16 @@ +### What it does + +Detects cases of owned empty strings being passed as an argument to a function expecting `&str` + +### Why is this bad? + +This results in longer and less readable code + +### Example +``` +vec!["1", "2", "3"].join(&String::new()); +``` +Use instead: +``` +vec!["1", "2", "3"].join(""); +``` \ No newline at end of file diff --git a/src/docs/unnecessary_self_imports.txt b/src/docs/unnecessary_self_imports.txt new file mode 100644 index 000000000000..b909cd5a76da --- /dev/null +++ b/src/docs/unnecessary_self_imports.txt @@ -0,0 +1,19 @@ +### What it does +Checks for imports ending in `::{self}`. + +### Why is this bad? +In most cases, this can be written much more cleanly by omitting `::{self}`. + +### Known problems +Removing `::{self}` will cause any non-module items at the same path to also be imported. +This might cause a naming conflict (https://github.com/rust-lang/rustfmt/issues/3568). This lint makes no attempt +to detect this scenario and that is why it is a restriction lint. + +### Example +``` +use std::io::{self}; +``` +Use instead: +``` +use std::io; +``` \ No newline at end of file diff --git a/src/docs/unnecessary_sort_by.txt b/src/docs/unnecessary_sort_by.txt new file mode 100644 index 000000000000..6913b62c48eb --- /dev/null +++ b/src/docs/unnecessary_sort_by.txt @@ -0,0 +1,21 @@ +### What it does +Detects uses of `Vec::sort_by` passing in a closure +which compares the two arguments, either directly or indirectly. + +### Why is this bad? +It is more clear to use `Vec::sort_by_key` (or `Vec::sort` if +possible) than to use `Vec::sort_by` and a more complicated +closure. + +### Known problems +If the suggested `Vec::sort_by_key` uses Reverse and it isn't already +imported by a use statement, then it will need to be added manually. + +### Example +``` +vec.sort_by(|a, b| a.foo().cmp(&b.foo())); +``` +Use instead: +``` +vec.sort_by_key(|a| a.foo()); +``` \ No newline at end of file diff --git a/src/docs/unnecessary_to_owned.txt b/src/docs/unnecessary_to_owned.txt new file mode 100644 index 000000000000..5d4213bdaf89 --- /dev/null +++ b/src/docs/unnecessary_to_owned.txt @@ -0,0 +1,24 @@ +### What it does +Checks for unnecessary calls to [`ToOwned::to_owned`](https://doc.rust-lang.org/std/borrow/trait.ToOwned.html#tymethod.to_owned) +and other `to_owned`-like functions. + +### Why is this bad? +The unnecessary calls result in useless allocations. + +### Known problems +`unnecessary_to_owned` can falsely trigger if `IntoIterator::into_iter` is applied to an +owned copy of a resource and the resource is later used mutably. See +[#8148](https://github.com/rust-lang/rust-clippy/issues/8148). + +### Example +``` +let path = std::path::Path::new("x"); +foo(&path.to_string_lossy().to_string()); +fn foo(s: &str) {} +``` +Use instead: +``` +let path = std::path::Path::new("x"); +foo(&path.to_string_lossy()); +fn foo(s: &str) {} +``` \ No newline at end of file diff --git a/src/docs/unnecessary_unwrap.txt b/src/docs/unnecessary_unwrap.txt new file mode 100644 index 000000000000..50ae845bb44f --- /dev/null +++ b/src/docs/unnecessary_unwrap.txt @@ -0,0 +1,20 @@ +### What it does +Checks for calls of `unwrap[_err]()` that cannot fail. + +### Why is this bad? +Using `if let` or `match` is more idiomatic. + +### Example +``` +if option.is_some() { + do_something_with(option.unwrap()) +} +``` + +Could be written: + +``` +if let Some(value) = option { + do_something_with(value) +} +``` \ No newline at end of file diff --git a/src/docs/unnecessary_wraps.txt b/src/docs/unnecessary_wraps.txt new file mode 100644 index 000000000000..c0a23d492889 --- /dev/null +++ b/src/docs/unnecessary_wraps.txt @@ -0,0 +1,36 @@ +### What it does +Checks for private functions that only return `Ok` or `Some`. + +### Why is this bad? +It is not meaningful to wrap values when no `None` or `Err` is returned. + +### Known problems +There can be false positives if the function signature is designed to +fit some external requirement. + +### Example +``` +fn get_cool_number(a: bool, b: bool) -> Option { + if a && b { + return Some(50); + } + if a { + Some(0) + } else { + Some(10) + } +} +``` +Use instead: +``` +fn get_cool_number(a: bool, b: bool) -> i32 { + if a && b { + return 50; + } + if a { + 0 + } else { + 10 + } +} +``` \ No newline at end of file diff --git a/src/docs/unneeded_field_pattern.txt b/src/docs/unneeded_field_pattern.txt new file mode 100644 index 000000000000..3cd00a0f3e38 --- /dev/null +++ b/src/docs/unneeded_field_pattern.txt @@ -0,0 +1,26 @@ +### What it does +Checks for structure field patterns bound to wildcards. + +### Why is this bad? +Using `..` instead is shorter and leaves the focus on +the fields that are actually bound. + +### Example +``` +let f = Foo { a: 0, b: 0, c: 0 }; + +match f { + Foo { a: _, b: 0, .. } => {}, + Foo { a: _, b: _, c: _ } => {}, +} +``` + +Use instead: +``` +let f = Foo { a: 0, b: 0, c: 0 }; + +match f { + Foo { b: 0, .. } => {}, + Foo { .. } => {}, +} +``` \ No newline at end of file diff --git a/src/docs/unneeded_wildcard_pattern.txt b/src/docs/unneeded_wildcard_pattern.txt new file mode 100644 index 000000000000..817061efd162 --- /dev/null +++ b/src/docs/unneeded_wildcard_pattern.txt @@ -0,0 +1,28 @@ +### What it does +Checks for tuple patterns with a wildcard +pattern (`_`) is next to a rest pattern (`..`). + +_NOTE_: While `_, ..` means there is at least one element left, `..` +means there are 0 or more elements left. This can make a difference +when refactoring, but shouldn't result in errors in the refactored code, +since the wildcard pattern isn't used anyway. + +### Why is this bad? +The wildcard pattern is unneeded as the rest pattern +can match that element as well. + +### Example +``` +match t { + TupleStruct(0, .., _) => (), + _ => (), +} +``` + +Use instead: +``` +match t { + TupleStruct(0, ..) => (), + _ => (), +} +``` \ No newline at end of file diff --git a/src/docs/unnested_or_patterns.txt b/src/docs/unnested_or_patterns.txt new file mode 100644 index 000000000000..49c45d4ee5e9 --- /dev/null +++ b/src/docs/unnested_or_patterns.txt @@ -0,0 +1,22 @@ +### What it does +Checks for unnested or-patterns, e.g., `Some(0) | Some(2)` and +suggests replacing the pattern with a nested one, `Some(0 | 2)`. + +Another way to think of this is that it rewrites patterns in +*disjunctive normal form (DNF)* into *conjunctive normal form (CNF)*. + +### Why is this bad? +In the example above, `Some` is repeated, which unnecessarily complicates the pattern. + +### Example +``` +fn main() { + if let Some(0) | Some(2) = Some(0) {} +} +``` +Use instead: +``` +fn main() { + if let Some(0 | 2) = Some(0) {} +} +``` \ No newline at end of file diff --git a/src/docs/unreachable.txt b/src/docs/unreachable.txt new file mode 100644 index 000000000000..10469ca77454 --- /dev/null +++ b/src/docs/unreachable.txt @@ -0,0 +1,10 @@ +### What it does +Checks for usage of `unreachable!`. + +### Why is this bad? +This macro can cause code to panic + +### Example +``` +unreachable!(); +``` \ No newline at end of file diff --git a/src/docs/unreadable_literal.txt b/src/docs/unreadable_literal.txt new file mode 100644 index 000000000000..e168f90a84c1 --- /dev/null +++ b/src/docs/unreadable_literal.txt @@ -0,0 +1,16 @@ +### What it does +Warns if a long integral or floating-point constant does +not contain underscores. + +### Why is this bad? +Reading long numbers is difficult without separators. + +### Example +``` +61864918973511 +``` + +Use instead: +``` +61_864_918_973_511 +``` \ No newline at end of file diff --git a/src/docs/unsafe_derive_deserialize.txt b/src/docs/unsafe_derive_deserialize.txt new file mode 100644 index 000000000000..f56c48044f4f --- /dev/null +++ b/src/docs/unsafe_derive_deserialize.txt @@ -0,0 +1,27 @@ +### What it does +Checks for deriving `serde::Deserialize` on a type that +has methods using `unsafe`. + +### Why is this bad? +Deriving `serde::Deserialize` will create a constructor +that may violate invariants hold by another constructor. + +### Example +``` +use serde::Deserialize; + +#[derive(Deserialize)] +pub struct Foo { + // .. +} + +impl Foo { + pub fn new() -> Self { + // setup here .. + } + + pub unsafe fn parts() -> (&str, &str) { + // assumes invariants hold + } +} +``` \ No newline at end of file diff --git a/src/docs/unsafe_removed_from_name.txt b/src/docs/unsafe_removed_from_name.txt new file mode 100644 index 000000000000..6f55c1815dd6 --- /dev/null +++ b/src/docs/unsafe_removed_from_name.txt @@ -0,0 +1,15 @@ +### What it does +Checks for imports that remove "unsafe" from an item's +name. + +### Why is this bad? +Renaming makes it less clear which traits and +structures are unsafe. + +### Example +``` +use std::cell::{UnsafeCell as TotallySafeCell}; + +extern crate crossbeam; +use crossbeam::{spawn_unsafe as spawn}; +``` \ No newline at end of file diff --git a/src/docs/unseparated_literal_suffix.txt b/src/docs/unseparated_literal_suffix.txt new file mode 100644 index 000000000000..d80248e34d0c --- /dev/null +++ b/src/docs/unseparated_literal_suffix.txt @@ -0,0 +1,18 @@ +### What it does +Warns if literal suffixes are not separated by an +underscore. +To enforce unseparated literal suffix style, +see the `separated_literal_suffix` lint. + +### Why is this bad? +Suffix style should be consistent. + +### Example +``` +123832i32 +``` + +Use instead: +``` +123832_i32 +``` \ No newline at end of file diff --git a/src/docs/unsound_collection_transmute.txt b/src/docs/unsound_collection_transmute.txt new file mode 100644 index 000000000000..29db9258e83f --- /dev/null +++ b/src/docs/unsound_collection_transmute.txt @@ -0,0 +1,25 @@ +### What it does +Checks for transmutes between collections whose +types have different ABI, size or alignment. + +### Why is this bad? +This is undefined behavior. + +### Known problems +Currently, we cannot know whether a type is a +collection, so we just lint the ones that come with `std`. + +### Example +``` +// different size, therefore likely out-of-bounds memory access +// You absolutely do not want this in your code! +unsafe { + std::mem::transmute::<_, Vec>(vec![2_u16]) +}; +``` + +You must always iterate, map and collect the values: + +``` +vec![2_u16].into_iter().map(u32::from).collect::>(); +``` \ No newline at end of file diff --git a/src/docs/unused_async.txt b/src/docs/unused_async.txt new file mode 100644 index 000000000000..26def11aa17a --- /dev/null +++ b/src/docs/unused_async.txt @@ -0,0 +1,23 @@ +### What it does +Checks for functions that are declared `async` but have no `.await`s inside of them. + +### Why is this bad? +Async functions with no async code create overhead, both mentally and computationally. +Callers of async methods either need to be calling from an async function themselves or run it on an executor, both of which +causes runtime overhead and hassle for the caller. + +### Example +``` +async fn get_random_number() -> i64 { + 4 // Chosen by fair dice roll. Guaranteed to be random. +} +let number_future = get_random_number(); +``` + +Use instead: +``` +fn get_random_number_improved() -> i64 { + 4 // Chosen by fair dice roll. Guaranteed to be random. +} +let number_future = async { get_random_number_improved() }; +``` \ No newline at end of file diff --git a/src/docs/unused_io_amount.txt b/src/docs/unused_io_amount.txt new file mode 100644 index 000000000000..fbc4c299c7bb --- /dev/null +++ b/src/docs/unused_io_amount.txt @@ -0,0 +1,31 @@ +### What it does +Checks for unused written/read amount. + +### Why is this bad? +`io::Write::write(_vectored)` and +`io::Read::read(_vectored)` are not guaranteed to +process the entire buffer. They return how many bytes were processed, which +might be smaller +than a given buffer's length. If you don't need to deal with +partial-write/read, use +`write_all`/`read_exact` instead. + +When working with asynchronous code (either with the `futures` +crate or with `tokio`), a similar issue exists for +`AsyncWriteExt::write()` and `AsyncReadExt::read()` : these +functions are also not guaranteed to process the entire +buffer. Your code should either handle partial-writes/reads, or +call the `write_all`/`read_exact` methods on those traits instead. + +### Known problems +Detects only common patterns. + +### Examples +``` +use std::io; +fn foo(w: &mut W) -> io::Result<()> { + // must be `w.write_all(b"foo")?;` + w.write(b"foo")?; + Ok(()) +} +``` \ No newline at end of file diff --git a/src/docs/unused_peekable.txt b/src/docs/unused_peekable.txt new file mode 100644 index 000000000000..268de1ce3bec --- /dev/null +++ b/src/docs/unused_peekable.txt @@ -0,0 +1,26 @@ +### What it does +Checks for the creation of a `peekable` iterator that is never `.peek()`ed + +### Why is this bad? +Creating a peekable iterator without using any of its methods is likely a mistake, +or just a leftover after a refactor. + +### Example +``` +let collection = vec![1, 2, 3]; +let iter = collection.iter().peekable(); + +for item in iter { + // ... +} +``` + +Use instead: +``` +let collection = vec![1, 2, 3]; +let iter = collection.iter(); + +for item in iter { + // ... +} +``` \ No newline at end of file diff --git a/src/docs/unused_rounding.txt b/src/docs/unused_rounding.txt new file mode 100644 index 000000000000..70947aceee77 --- /dev/null +++ b/src/docs/unused_rounding.txt @@ -0,0 +1,17 @@ +### What it does + +Detects cases where a whole-number literal float is being rounded, using +the `floor`, `ceil`, or `round` methods. + +### Why is this bad? + +This is unnecessary and confusing to the reader. Doing this is probably a mistake. + +### Example +``` +let x = 1f32.ceil(); +``` +Use instead: +``` +let x = 1f32; +``` \ No newline at end of file diff --git a/src/docs/unused_self.txt b/src/docs/unused_self.txt new file mode 100644 index 000000000000..a8d0fc759895 --- /dev/null +++ b/src/docs/unused_self.txt @@ -0,0 +1,23 @@ +### What it does +Checks methods that contain a `self` argument but don't use it + +### Why is this bad? +It may be clearer to define the method as an associated function instead +of an instance method if it doesn't require `self`. + +### Example +``` +struct A; +impl A { + fn method(&self) {} +} +``` + +Could be written: + +``` +struct A; +impl A { + fn method() {} +} +``` \ No newline at end of file diff --git a/src/docs/unused_unit.txt b/src/docs/unused_unit.txt new file mode 100644 index 000000000000..48d16ca65523 --- /dev/null +++ b/src/docs/unused_unit.txt @@ -0,0 +1,18 @@ +### What it does +Checks for unit (`()`) expressions that can be removed. + +### Why is this bad? +Such expressions add no value, but can make the code +less readable. Depending on formatting they can make a `break` or `return` +statement look like a function call. + +### Example +``` +fn return_unit() -> () { + () +} +``` +is equivalent to +``` +fn return_unit() {} +``` \ No newline at end of file diff --git a/src/docs/unusual_byte_groupings.txt b/src/docs/unusual_byte_groupings.txt new file mode 100644 index 000000000000..9a1f132a6112 --- /dev/null +++ b/src/docs/unusual_byte_groupings.txt @@ -0,0 +1,12 @@ +### What it does +Warns if hexadecimal or binary literals are not grouped +by nibble or byte. + +### Why is this bad? +Negatively impacts readability. + +### Example +``` +let x: u32 = 0xFFF_FFF; +let y: u8 = 0b01_011_101; +``` \ No newline at end of file diff --git a/src/docs/unwrap_in_result.txt b/src/docs/unwrap_in_result.txt new file mode 100644 index 000000000000..7497dd863d35 --- /dev/null +++ b/src/docs/unwrap_in_result.txt @@ -0,0 +1,39 @@ +### What it does +Checks for functions of type `Result` that contain `expect()` or `unwrap()` + +### Why is this bad? +These functions promote recoverable errors to non-recoverable errors which may be undesirable in code bases which wish to avoid panics. + +### Known problems +This can cause false positives in functions that handle both recoverable and non recoverable errors. + +### Example +Before: +``` +fn divisible_by_3(i_str: String) -> Result<(), String> { + let i = i_str + .parse::() + .expect("cannot divide the input by three"); + + if i % 3 != 0 { + Err("Number is not divisible by 3")? + } + + Ok(()) +} +``` + +After: +``` +fn divisible_by_3(i_str: String) -> Result<(), String> { + let i = i_str + .parse::() + .map_err(|e| format!("cannot divide the input by three: {}", e))?; + + if i % 3 != 0 { + Err("Number is not divisible by 3")? + } + + Ok(()) +} +``` \ No newline at end of file diff --git a/src/docs/unwrap_or_else_default.txt b/src/docs/unwrap_or_else_default.txt new file mode 100644 index 000000000000..34b4cf088581 --- /dev/null +++ b/src/docs/unwrap_or_else_default.txt @@ -0,0 +1,18 @@ +### What it does +Checks for usages of `_.unwrap_or_else(Default::default)` on `Option` and +`Result` values. + +### Why is this bad? +Readability, these can be written as `_.unwrap_or_default`, which is +simpler and more concise. + +### Examples +``` +x.unwrap_or_else(Default::default); +x.unwrap_or_else(u32::default); +``` + +Use instead: +``` +x.unwrap_or_default(); +``` \ No newline at end of file diff --git a/src/docs/unwrap_used.txt b/src/docs/unwrap_used.txt new file mode 100644 index 000000000000..9b4713df515d --- /dev/null +++ b/src/docs/unwrap_used.txt @@ -0,0 +1,37 @@ +### What it does +Checks for `.unwrap()` or `.unwrap_err()` calls on `Result`s and `.unwrap()` call on `Option`s. + +### Why is this bad? +It is better to handle the `None` or `Err` case, +or at least call `.expect(_)` with a more helpful message. Still, for a lot of +quick-and-dirty code, `unwrap` is a good choice, which is why this lint is +`Allow` by default. + +`result.unwrap()` will let the thread panic on `Err` values. +Normally, you want to implement more sophisticated error handling, +and propagate errors upwards with `?` operator. + +Even if you want to panic on errors, not all `Error`s implement good +messages on display. Therefore, it may be beneficial to look at the places +where they may get displayed. Activate this lint to do just that. + +### Examples +``` +option.unwrap(); +result.unwrap(); +``` + +Use instead: +``` +option.expect("more helpful message"); +result.expect("more helpful message"); +``` + +If [expect_used](#expect_used) is enabled, instead: +``` +option?; + +// or + +result?; +``` \ No newline at end of file diff --git a/src/docs/upper_case_acronyms.txt b/src/docs/upper_case_acronyms.txt new file mode 100644 index 000000000000..a1e39c7e10c6 --- /dev/null +++ b/src/docs/upper_case_acronyms.txt @@ -0,0 +1,25 @@ +### What it does +Checks for fully capitalized names and optionally names containing a capitalized acronym. + +### Why is this bad? +In CamelCase, acronyms count as one word. +See [naming conventions](https://rust-lang.github.io/api-guidelines/naming.html#casing-conforms-to-rfc-430-c-case) +for more. + +By default, the lint only triggers on fully-capitalized names. +You can use the `upper-case-acronyms-aggressive: true` config option to enable linting +on all camel case names + +### Known problems +When two acronyms are contiguous, the lint can't tell where +the first acronym ends and the second starts, so it suggests to lowercase all of +the letters in the second acronym. + +### Example +``` +struct HTTPResponse; +``` +Use instead: +``` +struct HttpResponse; +``` \ No newline at end of file diff --git a/src/docs/use_debug.txt b/src/docs/use_debug.txt new file mode 100644 index 000000000000..94d4a6fd29ae --- /dev/null +++ b/src/docs/use_debug.txt @@ -0,0 +1,12 @@ +### What it does +Checks for use of `Debug` formatting. The purpose of this +lint is to catch debugging remnants. + +### Why is this bad? +The purpose of the `Debug` trait is to facilitate +debugging Rust code. It should not be used in user-facing output. + +### Example +``` +println!("{:?}", foo); +``` \ No newline at end of file diff --git a/src/docs/use_self.txt b/src/docs/use_self.txt new file mode 100644 index 000000000000..bd37ed1e0025 --- /dev/null +++ b/src/docs/use_self.txt @@ -0,0 +1,31 @@ +### What it does +Checks for unnecessary repetition of structure name when a +replacement with `Self` is applicable. + +### Why is this bad? +Unnecessary repetition. Mixed use of `Self` and struct +name +feels inconsistent. + +### Known problems +- Unaddressed false negative in fn bodies of trait implementations +- False positive with associated types in traits (#4140) + +### Example +``` +struct Foo; +impl Foo { + fn new() -> Foo { + Foo {} + } +} +``` +could be +``` +struct Foo; +impl Foo { + fn new() -> Self { + Self {} + } +} +``` \ No newline at end of file diff --git a/src/docs/used_underscore_binding.txt b/src/docs/used_underscore_binding.txt new file mode 100644 index 000000000000..ed67c41eb0db --- /dev/null +++ b/src/docs/used_underscore_binding.txt @@ -0,0 +1,19 @@ +### What it does +Checks for the use of bindings with a single leading +underscore. + +### Why is this bad? +A single leading underscore is usually used to indicate +that a binding will not be used. Using such a binding breaks this +expectation. + +### Known problems +The lint does not work properly with desugaring and +macro, it has been allowed in the mean time. + +### Example +``` +let _x = 0; +let y = _x + 1; // Here we are using `_x`, even though it has a leading + // underscore. We should rename `_x` to `x` +``` \ No newline at end of file diff --git a/src/docs/useless_asref.txt b/src/docs/useless_asref.txt new file mode 100644 index 000000000000..f777cd3775ed --- /dev/null +++ b/src/docs/useless_asref.txt @@ -0,0 +1,17 @@ +### What it does +Checks for usage of `.as_ref()` or `.as_mut()` where the +types before and after the call are the same. + +### Why is this bad? +The call is unnecessary. + +### Example +``` +let x: &[i32] = &[1, 2, 3, 4, 5]; +do_stuff(x.as_ref()); +``` +The correct use would be: +``` +let x: &[i32] = &[1, 2, 3, 4, 5]; +do_stuff(x); +``` \ No newline at end of file diff --git a/src/docs/useless_attribute.txt b/src/docs/useless_attribute.txt new file mode 100644 index 000000000000..e02d4c907898 --- /dev/null +++ b/src/docs/useless_attribute.txt @@ -0,0 +1,36 @@ +### What it does +Checks for `extern crate` and `use` items annotated with +lint attributes. + +This lint permits lint attributes for lints emitted on the items themself. +For `use` items these lints are: +* deprecated +* unreachable_pub +* unused_imports +* clippy::enum_glob_use +* clippy::macro_use_imports +* clippy::wildcard_imports + +For `extern crate` items these lints are: +* `unused_imports` on items with `#[macro_use]` + +### Why is this bad? +Lint attributes have no effect on crate imports. Most +likely a `!` was forgotten. + +### Example +``` +#[deny(dead_code)] +extern crate foo; +#[forbid(dead_code)] +use foo::bar; +``` + +Use instead: +``` +#[allow(unused_imports)] +use foo::baz; +#[allow(unused_imports)] +#[macro_use] +extern crate baz; +``` \ No newline at end of file diff --git a/src/docs/useless_conversion.txt b/src/docs/useless_conversion.txt new file mode 100644 index 000000000000..06000a7ad98d --- /dev/null +++ b/src/docs/useless_conversion.txt @@ -0,0 +1,17 @@ +### What it does +Checks for `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` calls +which uselessly convert to the same type. + +### Why is this bad? +Redundant code. + +### Example +``` +// format!() returns a `String` +let s: String = format!("hello").into(); +``` + +Use instead: +``` +let s: String = format!("hello"); +``` \ No newline at end of file diff --git a/src/docs/useless_format.txt b/src/docs/useless_format.txt new file mode 100644 index 000000000000..eb4819da1e95 --- /dev/null +++ b/src/docs/useless_format.txt @@ -0,0 +1,22 @@ +### What it does +Checks for the use of `format!("string literal with no +argument")` and `format!("{}", foo)` where `foo` is a string. + +### Why is this bad? +There is no point of doing that. `format!("foo")` can +be replaced by `"foo".to_owned()` if you really need a `String`. The even +worse `&format!("foo")` is often encountered in the wild. `format!("{}", +foo)` can be replaced by `foo.clone()` if `foo: String` or `foo.to_owned()` +if `foo: &str`. + +### Examples +``` +let foo = "foo"; +format!("{}", foo); +``` + +Use instead: +``` +let foo = "foo"; +foo.to_owned(); +``` \ No newline at end of file diff --git a/src/docs/useless_let_if_seq.txt b/src/docs/useless_let_if_seq.txt new file mode 100644 index 000000000000..c6dcd57eb2e2 --- /dev/null +++ b/src/docs/useless_let_if_seq.txt @@ -0,0 +1,39 @@ +### What it does +Checks for variable declarations immediately followed by a +conditional affectation. + +### Why is this bad? +This is not idiomatic Rust. + +### Example +``` +let foo; + +if bar() { + foo = 42; +} else { + foo = 0; +} + +let mut baz = None; + +if bar() { + baz = Some(42); +} +``` + +should be written + +``` +let foo = if bar() { + 42 +} else { + 0 +}; + +let baz = if bar() { + Some(42) +} else { + None +}; +``` \ No newline at end of file diff --git a/src/docs/useless_transmute.txt b/src/docs/useless_transmute.txt new file mode 100644 index 000000000000..1d3a17588145 --- /dev/null +++ b/src/docs/useless_transmute.txt @@ -0,0 +1,12 @@ +### What it does +Checks for transmutes to the original type of the object +and transmutes that could be a cast. + +### Why is this bad? +Readability. The code tricks people into thinking that +something complex is going on. + +### Example +``` +core::intrinsics::transmute(t); // where the result type is the same as `t`'s +``` \ No newline at end of file diff --git a/src/docs/useless_vec.txt b/src/docs/useless_vec.txt new file mode 100644 index 000000000000..ee5afc99e4bf --- /dev/null +++ b/src/docs/useless_vec.txt @@ -0,0 +1,18 @@ +### What it does +Checks for usage of `&vec![..]` when using `&[..]` would +be possible. + +### Why is this bad? +This is less efficient. + +### Example +``` +fn foo(_x: &[u8]) {} + +foo(&vec![1, 2]); +``` + +Use instead: +``` +foo(&[1, 2]); +``` \ No newline at end of file diff --git a/src/docs/vec_box.txt b/src/docs/vec_box.txt new file mode 100644 index 000000000000..701b1c9ce9b9 --- /dev/null +++ b/src/docs/vec_box.txt @@ -0,0 +1,26 @@ +### What it does +Checks for use of `Vec>` where T: Sized anywhere in the code. +Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information. + +### Why is this bad? +`Vec` already keeps its contents in a separate area on +the heap. So if you `Box` its contents, you just add another level of indirection. + +### Known problems +Vec> makes sense if T is a large type (see [#3530](https://github.com/rust-lang/rust-clippy/issues/3530), +1st comment). + +### Example +``` +struct X { + values: Vec>, +} +``` + +Better: + +``` +struct X { + values: Vec, +} +``` \ No newline at end of file diff --git a/src/docs/vec_init_then_push.txt b/src/docs/vec_init_then_push.txt new file mode 100644 index 000000000000..445f2874796b --- /dev/null +++ b/src/docs/vec_init_then_push.txt @@ -0,0 +1,23 @@ +### What it does +Checks for calls to `push` immediately after creating a new `Vec`. + +If the `Vec` is created using `with_capacity` this will only lint if the capacity is a +constant and the number of pushes is greater than or equal to the initial capacity. + +If the `Vec` is extended after the initial sequence of pushes and it was default initialized +then this will only lint after there were at least four pushes. This number may change in +the future. + +### Why is this bad? +The `vec![]` macro is both more performant and easier to read than +multiple `push` calls. + +### Example +``` +let mut v = Vec::new(); +v.push(0); +``` +Use instead: +``` +let v = vec![0]; +``` \ No newline at end of file diff --git a/src/docs/vec_resize_to_zero.txt b/src/docs/vec_resize_to_zero.txt new file mode 100644 index 000000000000..0b92686772bb --- /dev/null +++ b/src/docs/vec_resize_to_zero.txt @@ -0,0 +1,15 @@ +### What it does +Finds occurrences of `Vec::resize(0, an_int)` + +### Why is this bad? +This is probably an argument inversion mistake. + +### Example +``` +vec!(1, 2, 3, 4, 5).resize(0, 5) +``` + +Use instead: +``` +vec!(1, 2, 3, 4, 5).clear() +``` \ No newline at end of file diff --git a/src/docs/verbose_bit_mask.txt b/src/docs/verbose_bit_mask.txt new file mode 100644 index 000000000000..87a84702925e --- /dev/null +++ b/src/docs/verbose_bit_mask.txt @@ -0,0 +1,15 @@ +### What it does +Checks for bit masks that can be replaced by a call +to `trailing_zeros` + +### Why is this bad? +`x.trailing_zeros() > 4` is much clearer than `x & 15 +== 0` + +### Known problems +llvm generates better code for `x & 15 == 0` on x86 + +### Example +``` +if x & 0b1111 == 0 { } +``` \ No newline at end of file diff --git a/src/docs/verbose_file_reads.txt b/src/docs/verbose_file_reads.txt new file mode 100644 index 000000000000..9703df423a57 --- /dev/null +++ b/src/docs/verbose_file_reads.txt @@ -0,0 +1,17 @@ +### What it does +Checks for use of File::read_to_end and File::read_to_string. + +### Why is this bad? +`fs::{read, read_to_string}` provide the same functionality when `buf` is empty with fewer imports and no intermediate values. +See also: [fs::read docs](https://doc.rust-lang.org/std/fs/fn.read.html), [fs::read_to_string docs](https://doc.rust-lang.org/std/fs/fn.read_to_string.html) + +### Example +``` +let mut f = File::open("foo.txt").unwrap(); +let mut bytes = Vec::new(); +f.read_to_end(&mut bytes).unwrap(); +``` +Can be written more concisely as +``` +let mut bytes = fs::read("foo.txt").unwrap(); +``` \ No newline at end of file diff --git a/src/docs/vtable_address_comparisons.txt b/src/docs/vtable_address_comparisons.txt new file mode 100644 index 000000000000..4a34e4ba78ef --- /dev/null +++ b/src/docs/vtable_address_comparisons.txt @@ -0,0 +1,17 @@ +### What it does +Checks for comparisons with an address of a trait vtable. + +### Why is this bad? +Comparing trait objects pointers compares an vtable addresses which +are not guaranteed to be unique and could vary between different code generation units. +Furthermore vtables for different types could have the same address after being merged +together. + +### Example +``` +let a: Rc = ... +let b: Rc = ... +if Rc::ptr_eq(&a, &b) { + ... +} +``` \ No newline at end of file diff --git a/src/docs/while_immutable_condition.txt b/src/docs/while_immutable_condition.txt new file mode 100644 index 000000000000..71800701f489 --- /dev/null +++ b/src/docs/while_immutable_condition.txt @@ -0,0 +1,20 @@ +### What it does +Checks whether variables used within while loop condition +can be (and are) mutated in the body. + +### Why is this bad? +If the condition is unchanged, entering the body of the loop +will lead to an infinite loop. + +### Known problems +If the `while`-loop is in a closure, the check for mutation of the +condition variables in the body can cause false negatives. For example when only `Upvar` `a` is +in the condition and only `Upvar` `b` gets mutated in the body, the lint will not trigger. + +### Example +``` +let i = 0; +while i > 10 { + println!("let me loop forever!"); +} +``` \ No newline at end of file diff --git a/src/docs/while_let_loop.txt b/src/docs/while_let_loop.txt new file mode 100644 index 000000000000..ab7bf60975ec --- /dev/null +++ b/src/docs/while_let_loop.txt @@ -0,0 +1,25 @@ +### What it does +Detects `loop + match` combinations that are easier +written as a `while let` loop. + +### Why is this bad? +The `while let` loop is usually shorter and more +readable. + +### Known problems +Sometimes the wrong binding is displayed ([#383](https://github.com/rust-lang/rust-clippy/issues/383)). + +### Example +``` +loop { + let x = match y { + Some(x) => x, + None => break, + }; + // .. do something with x +} +// is easier written as +while let Some(x) = y { + // .. do something with x +}; +``` \ No newline at end of file diff --git a/src/docs/while_let_on_iterator.txt b/src/docs/while_let_on_iterator.txt new file mode 100644 index 000000000000..af053c541199 --- /dev/null +++ b/src/docs/while_let_on_iterator.txt @@ -0,0 +1,20 @@ +### What it does +Checks for `while let` expressions on iterators. + +### Why is this bad? +Readability. A simple `for` loop is shorter and conveys +the intent better. + +### Example +``` +while let Some(val) = iter.next() { + .. +} +``` + +Use instead: +``` +for val in &mut iter { + .. +} +``` \ No newline at end of file diff --git a/src/docs/wildcard_dependencies.txt b/src/docs/wildcard_dependencies.txt new file mode 100644 index 000000000000..2affaf9740d9 --- /dev/null +++ b/src/docs/wildcard_dependencies.txt @@ -0,0 +1,13 @@ +### What it does +Checks for wildcard dependencies in the `Cargo.toml`. + +### Why is this bad? +[As the edition guide says](https://rust-lang-nursery.github.io/edition-guide/rust-2018/cargo-and-crates-io/crates-io-disallows-wildcard-dependencies.html), +it is highly unlikely that you work with any possible version of your dependency, +and wildcard dependencies would cause unnecessary breakage in the ecosystem. + +### Example +``` +[dependencies] +regex = "*" +``` \ No newline at end of file diff --git a/src/docs/wildcard_enum_match_arm.txt b/src/docs/wildcard_enum_match_arm.txt new file mode 100644 index 000000000000..09807c01c652 --- /dev/null +++ b/src/docs/wildcard_enum_match_arm.txt @@ -0,0 +1,25 @@ +### What it does +Checks for wildcard enum matches using `_`. + +### Why is this bad? +New enum variants added by library updates can be missed. + +### Known problems +Suggested replacements may be incorrect if guards exhaustively cover some +variants, and also may not use correct path to enum if it's not present in the current scope. + +### Example +``` +match x { + Foo::A(_) => {}, + _ => {}, +} +``` + +Use instead: +``` +match x { + Foo::A(_) => {}, + Foo::B(_) => {}, +} +``` \ No newline at end of file diff --git a/src/docs/wildcard_imports.txt b/src/docs/wildcard_imports.txt new file mode 100644 index 000000000000..bd56aa5b0828 --- /dev/null +++ b/src/docs/wildcard_imports.txt @@ -0,0 +1,45 @@ +### What it does +Checks for wildcard imports `use _::*`. + +### Why is this bad? +wildcard imports can pollute the namespace. This is especially bad if +you try to import something through a wildcard, that already has been imported by name from +a different source: + +``` +use crate1::foo; // Imports a function named foo +use crate2::*; // Has a function named foo + +foo(); // Calls crate1::foo +``` + +This can lead to confusing error messages at best and to unexpected behavior at worst. + +### Exceptions +Wildcard imports are allowed from modules named `prelude`. Many crates (including the standard library) +provide modules named "prelude" specifically designed for wildcard import. + +`use super::*` is allowed in test modules. This is defined as any module with "test" in the name. + +These exceptions can be disabled using the `warn-on-all-wildcard-imports` configuration flag. + +### Known problems +If macros are imported through the wildcard, this macro is not included +by the suggestion and has to be added by hand. + +Applying the suggestion when explicit imports of the things imported with a glob import +exist, may result in `unused_imports` warnings. + +### Example +``` +use crate1::*; + +foo(); +``` + +Use instead: +``` +use crate1::foo; + +foo(); +``` \ No newline at end of file diff --git a/src/docs/wildcard_in_or_patterns.txt b/src/docs/wildcard_in_or_patterns.txt new file mode 100644 index 000000000000..70468ca41e0b --- /dev/null +++ b/src/docs/wildcard_in_or_patterns.txt @@ -0,0 +1,22 @@ +### What it does +Checks for wildcard pattern used with others patterns in same match arm. + +### Why is this bad? +Wildcard pattern already covers any other pattern as it will match anyway. +It makes the code less readable, especially to spot wildcard pattern use in match arm. + +### Example +``` +match s { + "a" => {}, + "bar" | _ => {}, +} +``` + +Use instead: +``` +match s { + "a" => {}, + _ => {}, +} +``` \ No newline at end of file diff --git a/src/docs/write_literal.txt b/src/docs/write_literal.txt new file mode 100644 index 000000000000..9c41a48f9f73 --- /dev/null +++ b/src/docs/write_literal.txt @@ -0,0 +1,21 @@ +### What it does +This lint warns about the use of literals as `write!`/`writeln!` args. + +### Why is this bad? +Using literals as `writeln!` args is inefficient +(c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary +(i.e., just put the literal in the format string) + +### Known problems +Will also warn with macro calls as arguments that expand to literals +-- e.g., `writeln!(buf, "{}", env!("FOO"))`. + +### Example +``` +writeln!(buf, "{}", "foo"); +``` + +Use instead: +``` +writeln!(buf, "foo"); +``` \ No newline at end of file diff --git a/src/docs/write_with_newline.txt b/src/docs/write_with_newline.txt new file mode 100644 index 000000000000..22845fd6515b --- /dev/null +++ b/src/docs/write_with_newline.txt @@ -0,0 +1,18 @@ +### What it does +This lint warns when you use `write!()` with a format +string that +ends in a newline. + +### Why is this bad? +You should use `writeln!()` instead, which appends the +newline. + +### Example +``` +write!(buf, "Hello {}!\n", name); +``` + +Use instead: +``` +writeln!(buf, "Hello {}!", name); +``` \ No newline at end of file diff --git a/src/docs/writeln_empty_string.txt b/src/docs/writeln_empty_string.txt new file mode 100644 index 000000000000..3b3aeb79a48b --- /dev/null +++ b/src/docs/writeln_empty_string.txt @@ -0,0 +1,16 @@ +### What it does +This lint warns when you use `writeln!(buf, "")` to +print a newline. + +### Why is this bad? +You should use `writeln!(buf)`, which is simpler. + +### Example +``` +writeln!(buf, ""); +``` + +Use instead: +``` +writeln!(buf); +``` \ No newline at end of file diff --git a/src/docs/wrong_self_convention.txt b/src/docs/wrong_self_convention.txt new file mode 100644 index 000000000000..d6b69ab87f86 --- /dev/null +++ b/src/docs/wrong_self_convention.txt @@ -0,0 +1,39 @@ +### What it does +Checks for methods with certain name prefixes and which +doesn't match how self is taken. The actual rules are: + +|Prefix |Postfix |`self` taken | `self` type | +|-------|------------|-------------------------------|--------------| +|`as_` | none |`&self` or `&mut self` | any | +|`from_`| none | none | any | +|`into_`| none |`self` | any | +|`is_` | none |`&mut self` or `&self` or none | any | +|`to_` | `_mut` |`&mut self` | any | +|`to_` | not `_mut` |`self` | `Copy` | +|`to_` | not `_mut` |`&self` | not `Copy` | + +Note: Clippy doesn't trigger methods with `to_` prefix in: +- Traits definition. +Clippy can not tell if a type that implements a trait is `Copy` or not. +- Traits implementation, when `&self` is taken. +The method signature is controlled by the trait and often `&self` is required for all types that implement the trait +(see e.g. the `std::string::ToString` trait). + +Clippy allows `Pin<&Self>` and `Pin<&mut Self>` if `&self` and `&mut self` is required. + +Please find more info here: +https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv + +### Why is this bad? +Consistency breeds readability. If you follow the +conventions, your users won't be surprised that they, e.g., need to supply a +mutable reference to a `as_..` function. + +### Example +``` +impl X { + fn as_str(self) -> &'static str { + // .. + } +} +``` \ No newline at end of file diff --git a/src/docs/wrong_transmute.txt b/src/docs/wrong_transmute.txt new file mode 100644 index 000000000000..9fc71e0e382e --- /dev/null +++ b/src/docs/wrong_transmute.txt @@ -0,0 +1,15 @@ +### What it does +Checks for transmutes that can't ever be correct on any +architecture. + +### Why is this bad? +It's basically guaranteed to be undefined behavior. + +### Known problems +When accessing C, users might want to store pointer +sized objects in `extradata` arguments to save an allocation. + +### Example +``` +let ptr: *const T = core::intrinsics::transmute('x') +``` \ No newline at end of file diff --git a/src/docs/zero_divided_by_zero.txt b/src/docs/zero_divided_by_zero.txt new file mode 100644 index 000000000000..394de20c0c0c --- /dev/null +++ b/src/docs/zero_divided_by_zero.txt @@ -0,0 +1,15 @@ +### What it does +Checks for `0.0 / 0.0`. + +### Why is this bad? +It's less readable than `f32::NAN` or `f64::NAN`. + +### Example +``` +let nan = 0.0f32 / 0.0; +``` + +Use instead: +``` +let nan = f32::NAN; +``` \ No newline at end of file diff --git a/src/docs/zero_prefixed_literal.txt b/src/docs/zero_prefixed_literal.txt new file mode 100644 index 000000000000..5c5588725363 --- /dev/null +++ b/src/docs/zero_prefixed_literal.txt @@ -0,0 +1,32 @@ +### What it does +Warns if an integral constant literal starts with `0`. + +### Why is this bad? +In some languages (including the infamous C language +and most of its +family), this marks an octal constant. In Rust however, this is a decimal +constant. This could +be confusing for both the writer and a reader of the constant. + +### Example + +In Rust: +``` +fn main() { + let a = 0123; + println!("{}", a); +} +``` + +prints `123`, while in C: + +``` +#include + +int main() { + int a = 0123; + printf("%d\n", a); +} +``` + +prints `83` (as `83 == 0o123` while `123 == 0o173`). \ No newline at end of file diff --git a/src/docs/zero_ptr.txt b/src/docs/zero_ptr.txt new file mode 100644 index 000000000000..e768a0236600 --- /dev/null +++ b/src/docs/zero_ptr.txt @@ -0,0 +1,16 @@ +### What it does +Catch casts from `0` to some pointer type + +### Why is this bad? +This generally means `null` and is better expressed as +{`std`, `core`}`::ptr::`{`null`, `null_mut`}. + +### Example +``` +let a = 0 as *const u32; +``` + +Use instead: +``` +let a = std::ptr::null::(); +``` \ No newline at end of file diff --git a/src/docs/zero_sized_map_values.txt b/src/docs/zero_sized_map_values.txt new file mode 100644 index 000000000000..0502bdbf3950 --- /dev/null +++ b/src/docs/zero_sized_map_values.txt @@ -0,0 +1,24 @@ +### What it does +Checks for maps with zero-sized value types anywhere in the code. + +### Why is this bad? +Since there is only a single value for a zero-sized type, a map +containing zero sized values is effectively a set. Using a set in that case improves +readability and communicates intent more clearly. + +### Known problems +* A zero-sized type cannot be recovered later if it contains private fields. +* This lints the signature of public items + +### Example +``` +fn unique_words(text: &str) -> HashMap<&str, ()> { + todo!(); +} +``` +Use instead: +``` +fn unique_words(text: &str) -> HashSet<&str> { + todo!(); +} +``` \ No newline at end of file diff --git a/src/docs/zst_offset.txt b/src/docs/zst_offset.txt new file mode 100644 index 000000000000..5810455ee955 --- /dev/null +++ b/src/docs/zst_offset.txt @@ -0,0 +1,11 @@ +### What it does +Checks for `offset(_)`, `wrapping_`{`add`, `sub`}, etc. on raw pointers to +zero-sized types + +### Why is this bad? +This is a no-op, and likely unintended + +### Example +``` +unsafe { (&() as *const ()).offset(1) }; +``` \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 9ee4a40cbf24..4a32e0e54a81 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,8 @@ use std::env; use std::path::PathBuf; use std::process::{self, Command}; +mod docs; + const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code. Usage: @@ -17,6 +19,7 @@ Common options: --fix Automatically apply lint suggestions. This flag implies `--no-deps` -h, --help Print this message -V, --version Print version info and exit + --explain LINT Print the documentation for a given lint Other options are the same as `cargo check`. @@ -54,6 +57,16 @@ pub fn main() { return; } + if let Some(pos) = env::args().position(|a| a == "--explain") { + if let Some(mut lint) = env::args().nth(pos + 1) { + lint.make_ascii_lowercase(); + docs::explain(&lint.strip_prefix("clippy::").unwrap_or(&lint).replace('-', "_")); + } else { + show_help(); + } + return; + } + if let Err(code) = process(env::args().skip(2)) { process::exit(code); } From dd897927155a6f30d122259d47b5fbc6baaae5b3 Mon Sep 17 00:00:00 2001 From: Matt Hamrick Date: Fri, 2 Sep 2022 13:47:00 -0700 Subject: [PATCH 4110/5092] Add -api-level to pm command As of ~Aug 30th, `pm build` commands require an `api-level` flag. This flag should match the fuchsia api-level that's being targeted by the code. Since this is dependent on the version of the SDK that's being used, we may want to change this to something a bit more robust in the future. --- src/doc/rustc/src/platform-support/fuchsia.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md index 53a510f080ec..98bfbcee3cf1 100644 --- a/src/doc/rustc/src/platform-support/fuchsia.md +++ b/src/doc/rustc/src/platform-support/fuchsia.md @@ -414,6 +414,7 @@ Next, we'll build a package manifest as defined by our manifest: ```sh ${SDK_PATH}/tools/${ARCH}/pm \ + -api-level 8 \ -o pkg/hello_fuchsia_manifest \ -m pkg/hello_fuchsia.manifest \ build \ From fcc61337a8e784d56b96d5dc2512464560b0ae58 Mon Sep 17 00:00:00 2001 From: ice1000 Date: Tue, 23 Aug 2022 04:59:41 +0000 Subject: [PATCH 4111/5092] Remove alias definition naively --- crates/ide-assists/src/handlers/inline_type_alias.rs | 9 ++++++--- crates/ide-assists/src/tests/generated.rs | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/crates/ide-assists/src/handlers/inline_type_alias.rs b/crates/ide-assists/src/handlers/inline_type_alias.rs index 9adf6381c1cb..ee560c6193c4 100644 --- a/crates/ide-assists/src/handlers/inline_type_alias.rs +++ b/crates/ide-assists/src/handlers/inline_type_alias.rs @@ -31,7 +31,7 @@ use crate::{ // ``` // -> // ``` -// type A = i32; +// // fn id(x: i32) -> i32 { // x // }; @@ -84,6 +84,9 @@ pub(crate) fn inline_type_alias_uses(acc: &mut Assists, ctx: &AssistContext<'_>) for (file_id, refs) in usages.into_iter() { inline_refs_for_file(file_id, refs); } + + builder.edit_file(ctx.file_id()); + builder.delete(ast_alias.syntax().text_range()); }, ) } @@ -929,7 +932,7 @@ fn foo() { } "#, r#" -type A = u32; + fn foo() { let _: u32 = 3; @@ -960,7 +963,7 @@ fn foo() { r#" //- /lib.rs mod foo; -type T = Vec; + fn f() -> Vec<&str> { vec!["hello"] } diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index a8c8622c1c1d..227e2300f92a 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -1390,7 +1390,7 @@ fn foo() { } "#####, r#####" -type A = i32; + fn id(x: i32) -> i32 { x }; From 79e5c366cda0f03cc9a087e43152f8631e61d356 Mon Sep 17 00:00:00 2001 From: ice1000 Date: Wed, 24 Aug 2022 04:50:12 +0000 Subject: [PATCH 4112/5092] Extract shared logic --- .../ide-assists/src/handlers/inline_call.rs | 37 ++++++++++--------- .../src/handlers/inline_type_alias.rs | 32 ++++++++++------ 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/crates/ide-assists/src/handlers/inline_call.rs b/crates/ide-assists/src/handlers/inline_call.rs index 96890ad51a6f..9f51cdaf8b1e 100644 --- a/crates/ide-assists/src/handlers/inline_call.rs +++ b/crates/ide-assists/src/handlers/inline_call.rs @@ -7,6 +7,7 @@ use ide_db::{ imports::insert_use::remove_path_if_in_use_stmt, path_transform::PathTransform, search::{FileReference, SearchScope}, + source_change::SourceChangeBuilder, syntax_helpers::{insert_whitespace_into_node::insert_ws_into, node_ext::expr_as_name_ref}, RootDatabase, }; @@ -100,18 +101,7 @@ pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext<'_>) -> builder.edit_file(file_id); let count = refs.len(); // The collects are required as we are otherwise iterating while mutating 🙅‍♀️🙅‍♂️ - let (name_refs, name_refs_use): (Vec<_>, Vec<_>) = refs - .into_iter() - .filter_map(|file_ref| match file_ref.name { - ast::NameLike::NameRef(name_ref) => Some(name_ref), - _ => None, - }) - .partition_map(|name_ref| { - match name_ref.syntax().ancestors().find_map(ast::UseTree::cast) { - Some(use_tree) => Either::Right(builder.make_mut(use_tree)), - None => Either::Left(name_ref), - } - }); + let (name_refs, name_refs_use) = split_refs_and_uses(builder, refs, Some); let call_infos: Vec<_> = name_refs .into_iter() .filter_map(CallInfo::from_name_ref) @@ -130,11 +120,7 @@ pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext<'_>) -> .count(); if replaced + name_refs_use.len() == count { // we replaced all usages in this file, so we can remove the imports - name_refs_use.into_iter().for_each(|use_tree| { - if let Some(path) = use_tree.path() { - remove_path_if_in_use_stmt(&path); - } - }) + name_refs_use.iter().for_each(remove_path_if_in_use_stmt); } else { remove_def = false; } @@ -153,6 +139,23 @@ pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext<'_>) -> ) } +pub(super) fn split_refs_and_uses( + builder: &mut SourceChangeBuilder, + iter: impl IntoIterator, + mut map_ref: impl FnMut(ast::NameRef) -> Option, +) -> (Vec, Vec) { + iter.into_iter() + .filter_map(|file_ref| match file_ref.name { + ast::NameLike::NameRef(name_ref) => Some(name_ref), + _ => None, + }) + .filter_map(|name_ref| match name_ref.syntax().ancestors().find_map(ast::UseTree::cast) { + Some(use_tree) => builder.make_mut(use_tree).path().map(Either::Right), + None => map_ref(name_ref).map(Either::Left), + }) + .partition_map(|either| either) +} + // Assist: inline_call // // Inlines a function or method body creating a `let` statement per parameter unless the parameter diff --git a/crates/ide-assists/src/handlers/inline_type_alias.rs b/crates/ide-assists/src/handlers/inline_type_alias.rs index ee560c6193c4..4afe890c783e 100644 --- a/crates/ide-assists/src/handlers/inline_type_alias.rs +++ b/crates/ide-assists/src/handlers/inline_type_alias.rs @@ -3,7 +3,9 @@ // - Remove unused aliases if there are no longer any users, see inline_call.rs. use hir::{HasSource, PathResolution}; -use ide_db::{defs::Definition, search::FileReference}; +use ide_db::{ + defs::Definition, imports::insert_use::remove_path_if_in_use_stmt, search::FileReference, +}; use itertools::Itertools; use std::collections::HashMap; use syntax::{ @@ -16,6 +18,8 @@ use crate::{ AssistId, AssistKind, }; +use super::inline_call::split_refs_and_uses; + // Assist: inline_type_alias_uses // // Inline a type alias into all of its uses where possible. @@ -31,7 +35,7 @@ use crate::{ // ``` // -> // ``` -// +// // fn id(x: i32) -> i32 { // x // }; @@ -62,15 +66,10 @@ pub(crate) fn inline_type_alias_uses(acc: &mut Assists, ctx: &AssistContext<'_>) let mut inline_refs_for_file = |file_id, refs: Vec| { builder.edit_file(file_id); - let path_types: Vec = refs - .into_iter() - .filter_map(|file_ref| match file_ref.name { - ast::NameLike::NameRef(path_type) => { - path_type.syntax().ancestors().nth(3).and_then(ast::PathType::cast) - } - _ => None, - }) - .collect(); + let (path_types, path_type_uses) = + split_refs_and_uses(builder, refs, |path_type| { + path_type.syntax().ancestors().nth(3).and_then(ast::PathType::cast) + }); for (target, replacement) in path_types.into_iter().filter_map(|path_type| { let replacement = inline(&ast_alias, &path_type)?.to_text(&concrete_type); @@ -79,6 +78,10 @@ pub(crate) fn inline_type_alias_uses(acc: &mut Assists, ctx: &AssistContext<'_>) }) { builder.replace(target, replacement); } + if !path_type_uses.is_empty() { + builder.edit_file(file_id); + path_type_uses.iter().for_each(remove_path_if_in_use_stmt); + } }; for (file_id, refs) in usages.into_iter() { @@ -993,7 +996,12 @@ fn foo() { } "#, r#" -use super::I; +//- /lib.rs +mod foo; + + +//- /foo.rs + fn foo() { let _: i32 = 0; } From 277df02ff562e152baac5cba93844d7499d806b5 Mon Sep 17 00:00:00 2001 From: ice1000 Date: Wed, 24 Aug 2022 05:49:59 +0000 Subject: [PATCH 4113/5092] This should work, but I got mysterious errors --- crates/ide-assists/src/handlers/inline_type_alias.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/crates/ide-assists/src/handlers/inline_type_alias.rs b/crates/ide-assists/src/handlers/inline_type_alias.rs index 4afe890c783e..a7f1cf49e3a4 100644 --- a/crates/ide-assists/src/handlers/inline_type_alias.rs +++ b/crates/ide-assists/src/handlers/inline_type_alias.rs @@ -71,6 +71,7 @@ pub(crate) fn inline_type_alias_uses(acc: &mut Assists, ctx: &AssistContext<'_>) path_type.syntax().ancestors().nth(3).and_then(ast::PathType::cast) }); + path_type_uses.iter().for_each(remove_path_if_in_use_stmt); for (target, replacement) in path_types.into_iter().filter_map(|path_type| { let replacement = inline(&ast_alias, &path_type)?.to_text(&concrete_type); let target = path_type.syntax().text_range(); @@ -78,10 +79,6 @@ pub(crate) fn inline_type_alias_uses(acc: &mut Assists, ctx: &AssistContext<'_>) }) { builder.replace(target, replacement); } - if !path_type_uses.is_empty() { - builder.edit_file(file_id); - path_type_uses.iter().for_each(remove_path_if_in_use_stmt); - } }; for (file_id, refs) in usages.into_iter() { @@ -1001,7 +998,6 @@ mod foo; //- /foo.rs - fn foo() { let _: i32 = 0; } From 37e20decadb4aecbae3b88502d4c130c9d9f31f4 Mon Sep 17 00:00:00 2001 From: ice1000 Date: Mon, 29 Aug 2022 20:27:53 +0000 Subject: [PATCH 4114/5092] Address comments --- crates/ide-assists/src/handlers/inline_type_alias.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/crates/ide-assists/src/handlers/inline_type_alias.rs b/crates/ide-assists/src/handlers/inline_type_alias.rs index a7f1cf49e3a4..95aeb09437f8 100644 --- a/crates/ide-assists/src/handlers/inline_type_alias.rs +++ b/crates/ide-assists/src/handlers/inline_type_alias.rs @@ -62,6 +62,7 @@ pub(crate) fn inline_type_alias_uses(acc: &mut Assists, ctx: &AssistContext<'_>) name.syntax().text_range(), |builder| { let usages = usages.all(); + let mut definition_deleted = false; let mut inline_refs_for_file = |file_id, refs: Vec| { builder.edit_file(file_id); @@ -79,14 +80,19 @@ pub(crate) fn inline_type_alias_uses(acc: &mut Assists, ctx: &AssistContext<'_>) }) { builder.replace(target, replacement); } + + if file_id == ctx.file_id() { + builder.delete(ast_alias.syntax().text_range()); + definition_deleted = true; + } }; for (file_id, refs) in usages.into_iter() { inline_refs_for_file(file_id, refs); } - - builder.edit_file(ctx.file_id()); - builder.delete(ast_alias.syntax().text_range()); + if !definition_deleted { + builder.delete(ast_alias.syntax().text_range()); + } }, ) } From a695e900f6722088f1385ae5f174c8643cb54fdb Mon Sep 17 00:00:00 2001 From: ice1000 Date: Fri, 2 Sep 2022 05:06:51 +0000 Subject: [PATCH 4115/5092] Create `trait Removable`, replace `ted` APIs with builder APIs --- .../src/handlers/add_missing_match_arms.rs | 1 + .../src/handlers/inline_type_alias.rs | 8 +++-- .../ide-assists/src/handlers/merge_imports.rs | 4 +-- .../ide-assists/src/handlers/move_bounds.rs | 2 +- .../ide-assists/src/handlers/unmerge_use.rs | 2 +- crates/ide-assists/src/utils.rs | 2 +- crates/ide-db/src/imports/insert_use.rs | 31 ++++++++++++------- crates/syntax/src/ast/edit_in_place.rs | 22 ++++++++----- 8 files changed, 45 insertions(+), 27 deletions(-) diff --git a/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/crates/ide-assists/src/handlers/add_missing_match_arms.rs index b16f6fe03ae8..1a7919a5a104 100644 --- a/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -5,6 +5,7 @@ use hir::{Adt, Crate, HasAttrs, HasSource, ModuleDef, Semantics}; use ide_db::RootDatabase; use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast}; use itertools::Itertools; +use syntax::ast::edit_in_place::Removable; use syntax::ast::{self, make, AstNode, HasName, MatchArmList, MatchExpr, Pat}; use crate::{ diff --git a/crates/ide-assists/src/handlers/inline_type_alias.rs b/crates/ide-assists/src/handlers/inline_type_alias.rs index 95aeb09437f8..fc24659d1f1a 100644 --- a/crates/ide-assists/src/handlers/inline_type_alias.rs +++ b/crates/ide-assists/src/handlers/inline_type_alias.rs @@ -4,7 +4,8 @@ use hir::{HasSource, PathResolution}; use ide_db::{ - defs::Definition, imports::insert_use::remove_path_if_in_use_stmt, search::FileReference, + defs::Definition, imports::insert_use::ast_to_remove_for_path_in_use_stmt, + search::FileReference, }; use itertools::Itertools; use std::collections::HashMap; @@ -72,7 +73,10 @@ pub(crate) fn inline_type_alias_uses(acc: &mut Assists, ctx: &AssistContext<'_>) path_type.syntax().ancestors().nth(3).and_then(ast::PathType::cast) }); - path_type_uses.iter().for_each(remove_path_if_in_use_stmt); + path_type_uses + .iter() + .flat_map(ast_to_remove_for_path_in_use_stmt) + .for_each(|x| builder.delete(x.syntax().text_range())); for (target, replacement) in path_types.into_iter().filter_map(|path_type| { let replacement = inline(&ast_alias, &path_type)?.to_text(&concrete_type); let target = path_type.syntax().text_range(); diff --git a/crates/ide-assists/src/handlers/merge_imports.rs b/crates/ide-assists/src/handlers/merge_imports.rs index 7e102ceba891..20abf5636312 100644 --- a/crates/ide-assists/src/handlers/merge_imports.rs +++ b/crates/ide-assists/src/handlers/merge_imports.rs @@ -1,6 +1,6 @@ use either::Either; use ide_db::imports::merge_imports::{try_merge_imports, try_merge_trees, MergeBehavior}; -use syntax::{algo::neighbor, ast, match_ast, ted, AstNode, SyntaxElement, SyntaxNode}; +use syntax::{algo::neighbor, ast::{self, edit_in_place::Removable}, match_ast, ted, AstNode, SyntaxElement, SyntaxNode}; use crate::{ assist_context::{AssistContext, Assists}, @@ -76,7 +76,7 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio .collect(); for edit in edits_mut { match edit { - Remove(it) => it.as_ref().either(ast::Use::remove, ast::UseTree::remove), + Remove(it) => it.as_ref().either(Removable::remove, Removable::remove), Replace(old, new) => ted::replace(old, new), } } diff --git a/crates/ide-assists/src/handlers/move_bounds.rs b/crates/ide-assists/src/handlers/move_bounds.rs index 176a3bf5803f..788fc22c8716 100644 --- a/crates/ide-assists/src/handlers/move_bounds.rs +++ b/crates/ide-assists/src/handlers/move_bounds.rs @@ -1,5 +1,5 @@ use syntax::{ - ast::{self, edit_in_place::GenericParamsOwnerEdit, make, AstNode, HasName, HasTypeBounds}, + ast::{self, edit_in_place::{GenericParamsOwnerEdit, Removable}, make, AstNode, HasName, HasTypeBounds}, match_ast, }; diff --git a/crates/ide-assists/src/handlers/unmerge_use.rs b/crates/ide-assists/src/handlers/unmerge_use.rs index 3ce028e93065..266275972810 100644 --- a/crates/ide-assists/src/handlers/unmerge_use.rs +++ b/crates/ide-assists/src/handlers/unmerge_use.rs @@ -1,5 +1,5 @@ use syntax::{ - ast::{self, make, HasVisibility}, + ast::{self, make, HasVisibility, edit_in_place::Removable}, ted::{self, Position}, AstNode, SyntaxKind, }; diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs index 103e3259fa2e..4ab6e2627fa7 100644 --- a/crates/ide-assists/src/utils.rs +++ b/crates/ide-assists/src/utils.rs @@ -12,7 +12,7 @@ use syntax::{ ast::{ self, edit::{self, AstNodeEdit}, - edit_in_place::AttrsOwnerEdit, + edit_in_place::{AttrsOwnerEdit, Removable}, make, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace, }, ted, AstNode, AstToken, Direction, SmolStr, SourceFile, diff --git a/crates/ide-db/src/imports/insert_use.rs b/crates/ide-db/src/imports/insert_use.rs index c14182279d05..9be1d3663493 100644 --- a/crates/ide-db/src/imports/insert_use.rs +++ b/crates/ide-db/src/imports/insert_use.rs @@ -7,7 +7,10 @@ use std::cmp::Ordering; use hir::Semantics; use syntax::{ algo, - ast::{self, make, AstNode, HasAttrs, HasModuleItem, HasVisibility, PathSegmentKind}, + ast::{ + self, edit_in_place::Removable, make, AstNode, HasAttrs, HasModuleItem, HasVisibility, + PathSegmentKind, + }, ted, Direction, NodeOrToken, SyntaxKind, SyntaxNode, }; @@ -192,20 +195,24 @@ pub fn insert_use(scope: &ImportScope, path: ast::Path, cfg: &InsertUseConfig) { insert_use_(scope, &path, cfg.group, use_item); } -pub fn remove_path_if_in_use_stmt(path: &ast::Path) { +pub fn ast_to_remove_for_path_in_use_stmt(path: &ast::Path) -> Option> { // FIXME: improve this if path.parent_path().is_some() { - return; + return None; } - if let Some(use_tree) = path.syntax().parent().and_then(ast::UseTree::cast) { - if use_tree.use_tree_list().is_some() || use_tree.star_token().is_some() { - return; - } - if let Some(use_) = use_tree.syntax().parent().and_then(ast::Use::cast) { - use_.remove(); - return; - } - use_tree.remove(); + let use_tree = path.syntax().parent().and_then(ast::UseTree::cast)?; + if use_tree.use_tree_list().is_some() || use_tree.star_token().is_some() { + return None; + } + if let Some(use_) = use_tree.syntax().parent().and_then(ast::Use::cast) { + return Some(Box::new(use_)); + } + Some(Box::new(use_tree)) +} + +pub fn remove_path_if_in_use_stmt(path: &ast::Path) { + if let Some(node) = ast_to_remove_for_path_in_use_stmt(path) { + node.remove(); } } diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs index 8efd58e2c39a..1e4bd2ef2574 100644 --- a/crates/syntax/src/ast/edit_in_place.rs +++ b/crates/syntax/src/ast/edit_in_place.rs @@ -248,8 +248,12 @@ impl ast::WhereClause { } } -impl ast::TypeBoundList { - pub fn remove(&self) { +pub trait Removable : AstNode { + fn remove(&self); +} + +impl Removable for ast::TypeBoundList { + fn remove(&self) { match self.syntax().siblings_with_tokens(Direction::Prev).find(|it| it.kind() == T![:]) { Some(colon) => ted::remove_all(colon..=self.syntax().clone().into()), None => ted::remove(self.syntax()), @@ -267,8 +271,8 @@ impl ast::PathSegment { } } -impl ast::UseTree { - pub fn remove(&self) { +impl Removable for ast::UseTree { + fn remove(&self) { for dir in [Direction::Next, Direction::Prev] { if let Some(next_use_tree) = neighbor(self, dir) { let separators = self @@ -282,7 +286,9 @@ impl ast::UseTree { } ted::remove(self.syntax()); } +} +impl ast::UseTree { pub fn get_or_create_use_tree_list(&self) -> ast::UseTreeList { match self.use_tree_list() { Some(it) => it, @@ -373,8 +379,8 @@ impl ast::UseTreeList { } } -impl ast::Use { - pub fn remove(&self) { +impl Removable for ast::Use { + fn remove(&self) { let next_ws = self .syntax() .next_sibling_or_token() @@ -444,8 +450,8 @@ impl ast::Fn { } } -impl ast::MatchArm { - pub fn remove(&self) { +impl Removable for ast::MatchArm { + fn remove(&self) { if let Some(sibling) = self.syntax().prev_sibling_or_token() { if sibling.kind() == SyntaxKind::WHITESPACE { ted::remove(sibling); From 68eabf1bf1f95afe2a0d4459dd8b7c748b6a54cc Mon Sep 17 00:00:00 2001 From: ice1000 Date: Fri, 2 Sep 2022 05:13:02 +0000 Subject: [PATCH 4116/5092] Fix test --- crates/ide-assists/src/handlers/inline_type_alias.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/ide-assists/src/handlers/inline_type_alias.rs b/crates/ide-assists/src/handlers/inline_type_alias.rs index fc24659d1f1a..353d467ed19f 100644 --- a/crates/ide-assists/src/handlers/inline_type_alias.rs +++ b/crates/ide-assists/src/handlers/inline_type_alias.rs @@ -95,6 +95,7 @@ pub(crate) fn inline_type_alias_uses(acc: &mut Assists, ctx: &AssistContext<'_>) inline_refs_for_file(file_id, refs); } if !definition_deleted { + builder.edit_file(ctx.file_id()); builder.delete(ast_alias.syntax().text_range()); } }, @@ -979,7 +980,7 @@ fn f() -> Vec<&str> { } //- /foo.rs -use super::T; + fn foo() { let _: Vec = Vec::new(); } @@ -1008,6 +1009,7 @@ mod foo; //- /foo.rs + fn foo() { let _: i32 = 0; } From 364d9c49103865c0f1f02c035f9da5c6377eaab7 Mon Sep 17 00:00:00 2001 From: ice1000 Date: Fri, 2 Sep 2022 05:13:33 +0000 Subject: [PATCH 4117/5092] Fmt --- crates/ide-assists/src/handlers/merge_imports.rs | 6 +++++- crates/ide-assists/src/handlers/move_bounds.rs | 6 +++++- crates/ide-assists/src/handlers/unmerge_use.rs | 2 +- crates/syntax/src/ast/edit_in_place.rs | 2 +- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/crates/ide-assists/src/handlers/merge_imports.rs b/crates/ide-assists/src/handlers/merge_imports.rs index 20abf5636312..2bdbec93b1f9 100644 --- a/crates/ide-assists/src/handlers/merge_imports.rs +++ b/crates/ide-assists/src/handlers/merge_imports.rs @@ -1,6 +1,10 @@ use either::Either; use ide_db::imports::merge_imports::{try_merge_imports, try_merge_trees, MergeBehavior}; -use syntax::{algo::neighbor, ast::{self, edit_in_place::Removable}, match_ast, ted, AstNode, SyntaxElement, SyntaxNode}; +use syntax::{ + algo::neighbor, + ast::{self, edit_in_place::Removable}, + match_ast, ted, AstNode, SyntaxElement, SyntaxNode, +}; use crate::{ assist_context::{AssistContext, Assists}, diff --git a/crates/ide-assists/src/handlers/move_bounds.rs b/crates/ide-assists/src/handlers/move_bounds.rs index 788fc22c8716..1dd376ac3fd5 100644 --- a/crates/ide-assists/src/handlers/move_bounds.rs +++ b/crates/ide-assists/src/handlers/move_bounds.rs @@ -1,5 +1,9 @@ use syntax::{ - ast::{self, edit_in_place::{GenericParamsOwnerEdit, Removable}, make, AstNode, HasName, HasTypeBounds}, + ast::{ + self, + edit_in_place::{GenericParamsOwnerEdit, Removable}, + make, AstNode, HasName, HasTypeBounds, + }, match_ast, }; diff --git a/crates/ide-assists/src/handlers/unmerge_use.rs b/crates/ide-assists/src/handlers/unmerge_use.rs index 266275972810..dac216b69b72 100644 --- a/crates/ide-assists/src/handlers/unmerge_use.rs +++ b/crates/ide-assists/src/handlers/unmerge_use.rs @@ -1,5 +1,5 @@ use syntax::{ - ast::{self, make, HasVisibility, edit_in_place::Removable}, + ast::{self, edit_in_place::Removable, make, HasVisibility}, ted::{self, Position}, AstNode, SyntaxKind, }; diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs index 1e4bd2ef2574..eadebbe8a212 100644 --- a/crates/syntax/src/ast/edit_in_place.rs +++ b/crates/syntax/src/ast/edit_in_place.rs @@ -248,7 +248,7 @@ impl ast::WhereClause { } } -pub trait Removable : AstNode { +pub trait Removable: AstNode { fn remove(&self); } From 7fb0a89bec84cd4c7018553e1b4fcecf1b1fea63 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 2 Sep 2022 15:08:23 +0200 Subject: [PATCH 4118/5092] Clean up themes CSS --- src/librustdoc/html/static/css/rustdoc.css | 26 +++++++++++++ src/librustdoc/html/static/css/themes/ayu.css | 35 ++++------------- .../html/static/css/themes/dark.css | 39 ++++--------------- .../html/static/css/themes/light.css | 38 ++++-------------- 4 files changed, 47 insertions(+), 91 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index ae0e3572a08c..fc8fde3c8ecd 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -987,6 +987,9 @@ so that we can apply CSS-filters to change the arrow color in themes */ width: 100%; background-color: var(--button-background-color); } +.search-input:focus { + border-color: var(--search-input-focused-border-color); +} .search-results { display: none; @@ -1167,6 +1170,12 @@ so that we can apply CSS-filters to change the arrow color in themes */ float: right; } +.rightside:not(a), +.out-of-band { + color: var(--right-side-color); +} + + .impl-items .srclink, .impl .srclink, .methods .srclink { /* Override header settings otherwise it's too bold */ font-weight: normal; @@ -1205,6 +1214,7 @@ a.test-arrow:hover { .code-attribute { font-weight: 300; + color: var(--code-attribute-color); } .item-spacer { @@ -1478,6 +1488,16 @@ pre.rust { background-color: var(--button-background-color); } +#copy-path { + color: var(--copy-path-button-color); +} +#copy-path > img { + filter: var(--copy-path-img-filter); +} +#copy-path:hover > img { + filter: var(--copy-path-img-hover-filter); +} + @keyframes rotating { from { transform: rotate(0deg); @@ -1601,6 +1621,12 @@ details.rustdoc-toggle > summary::before { opacity: .5; } +details.rustdoc-toggle > summary.hideme > span, +details.rustdoc-toggle > summary::before, +.more-examples-toggle summary, .more-examples-toggle .hide-more { + color: var(--toggles-color); +} + /* Screen readers see the text version at the end the line. Visual readers see the icon at the start of the line, but small and transparent. */ details.rustdoc-toggle > summary::after { diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css index 4f6dd645c272..be359a8e72d2 100644 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -16,6 +16,13 @@ Original by Dempfi (https://github.com/dempfi/ayu) --headings-border-bottom-color: #5c6773; --border-color: #5c6773; --button-background-color: #141920; + --right-side-color: grey; + --code-attribute-color: #999; + --toggles-color: #999; + --search-input-focused-border-color: #5c6773; /* Same as `--border-color`. */ + --copy-path-button-color: #fff; + --copy-path-img-filter: invert(70%); + --copy-path-img-hover-filter: invert(100%); } .slider { @@ -158,11 +165,6 @@ body.source .example-wrap pre.rust a { background: #333; } -details.rustdoc-toggle > summary.hideme > span, -details.rustdoc-toggle > summary::before { - color: #999; -} - details.rustdoc-toggle > summary::before { filter: invert(100%); } @@ -197,11 +199,6 @@ details.rustdoc-toggle > summary::before { background: none; } -.rightside:not(a), -.out-of-band { - color: grey; -} - .result-name .primitive > i, .result-name .keyword > i { color: #788797; } @@ -242,10 +239,6 @@ a.test-arrow:hover { color: #c5c5c5; } -.code-attribute { - color: #999; -} - :target { background: rgba(255, 236, 164, 0.06); border-right: 3px solid rgba(255, 180, 76, 0.85); @@ -341,7 +334,6 @@ individually rather than as a group) */ /* FIXME: these rules should be at the bottom of the file but currently must be above the `@media (max-width: 700px)` rules due to a bug in the css checker */ /* see https://github.com/rust-lang/rust/pull/71237#issuecomment-618170143 */ -.search-input:focus {} .content span.attr,.content a.attr,.block a.current.attr,.content span.derive,.content a.derive, .block a.current.derive,.content span.macro,.content a.macro,.block a.current.macro {} .content span.struct,.content a.struct,.block a.current.struct {} @@ -428,16 +420,6 @@ kbd { filter: invert(100); } -#copy-path { - color: #fff; -} -#copy-path > img { - filter: invert(70%); -} -#copy-path:hover > img { - filter: invert(100%); -} - #settings-menu > a:hover, #settings-menu > a:focus, #help-button > button:hover, #help-button > button:focus { border-color: #e0e0e0; @@ -471,9 +453,6 @@ kbd { border-color: white; color: white; } -.more-examples-toggle summary, .more-examples-toggle .hide-more { - color: #999; -} .scraped-example .example-wrap .rust span.highlight { background: rgb(91, 59, 1); } diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css index a37bbac5306a..f633abe94e5a 100644 --- a/src/librustdoc/html/static/css/themes/dark.css +++ b/src/librustdoc/html/static/css/themes/dark.css @@ -11,6 +11,13 @@ --headings-border-bottom-color: #d2d2d2; --border-color: #e0e0e0; --button-background-color: #f0f0f0; + --right-side-color: grey; + --code-attribute-color: #999; + --toggles-color: #999; + --search-input-focused-border-color: #008dfd; + --copy-path-button-color: #999; + --copy-path-img-filter: invert(50%); + --copy-path-img-hover-filter: invert(65%); } .slider { @@ -129,18 +136,12 @@ body.source .example-wrap pre.rust a { background: #333; } -details.rustdoc-toggle > summary.hideme > span, -details.rustdoc-toggle > summary::before { - color: #999; -} - details.rustdoc-toggle > summary::before { filter: invert(100%); } .search-input { color: #111; - border-color: #f0f0f0; } #crate-search-div::after { @@ -154,10 +155,6 @@ details.rustdoc-toggle > summary::before { filter: invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg) brightness(100%) contrast(91%); } -.search-input:focus { - border-color: #008dfd; -} - .stab { background: #314559; } .stab.portability > code { @@ -165,11 +162,6 @@ details.rustdoc-toggle > summary::before { background: none; } -.rightside:not(a), -.out-of-band { - color: grey; -} - .line-numbers :target { background-color: transparent; } /* Code highlighting */ @@ -197,10 +189,6 @@ a.test-arrow:hover{ background-color: #4e8bca; } -.code-attribute { - color: #999; -} - :target { background-color: #494a3d; border-right: 3px solid #bb7410; @@ -301,16 +289,6 @@ kbd { border-color: #ffb900; } -#copy-path { - color: #999; -} -#copy-path > img { - filter: invert(50%); -} -#copy-path:hover > img { - filter: invert(65%); -} - .search-results .result-name span.alias { color: #fff; } @@ -334,9 +312,6 @@ kbd { border-color: white; color: white; } -.more-examples-toggle summary, .more-examples-toggle .hide-more { - color: #999; -} .scraped-example .example-wrap .rust span.highlight { background: rgb(91, 59, 1); } diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css index 3d8e866fdc61..875bb7930256 100644 --- a/src/librustdoc/html/static/css/themes/light.css +++ b/src/librustdoc/html/static/css/themes/light.css @@ -11,6 +11,13 @@ --headings-border-bottom-color: #ddd; --border-color: #e0e0e0; --button-background-color: #fff; + --right-side-color: grey; + --code-attribute-color: #999; + --toggles-color: #999; + --search-input-focused-border-color: #66afe9; + --copy-path-button-color: #999; + --copy-path-img-filter: invert(50%); + --copy-path-img-hover-filter: invert(35%); } .slider { @@ -125,11 +132,6 @@ body.source .example-wrap pre.rust a { background: #eee; } -details.rustdoc-toggle > summary.hideme > span, -details.rustdoc-toggle > summary::before { - color: #999; -} - #crate-search-div::after { /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */ filter: invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg) brightness(114%) contrast(76%); @@ -141,18 +143,9 @@ details.rustdoc-toggle > summary::before { filter: invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg) brightness(96%) contrast(93%); } -.search-input:focus { - border-color: #66afe9; -} - .stab { background: #FFF5D6; border-color: #FFC600; } .stab.portability > code { background: none; } -.rightside:not(a), -.out-of-band { - color: grey; -} - .line-numbers :target { background-color: transparent; } /* Code highlighting */ @@ -182,10 +175,6 @@ a.test-arrow:hover{ background-color: #4e8bca; } -.code-attribute { - color: #999; -} - :target { background: #FDFFD3; border-right: 3px solid #AD7C37; @@ -281,16 +270,6 @@ kbd { border-color: #717171; } -#copy-path { - color: #999; -} -#copy-path > img { - filter: invert(50%); -} -#copy-path:hover > img { - filter: invert(35%); -} - .search-results .result-name span.alias { color: #000; } @@ -313,9 +292,6 @@ kbd { border-color: black; color: black; } -.more-examples-toggle summary, .more-examples-toggle .hide-more { - color: #999; -} .scraped-example .example-wrap .rust span.highlight { background: #fcffd6; } From 30bdf54827703fe76ec3a6718044a2749bb4704d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 2 Sep 2022 17:40:28 +0200 Subject: [PATCH 4119/5092] Update rustdoc-gui tests for search-input border color on dark theme --- src/test/rustdoc-gui/search-form-elements.goml | 2 +- src/test/rustdoc-gui/search-input.goml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/rustdoc-gui/search-form-elements.goml b/src/test/rustdoc-gui/search-form-elements.goml index c35a86ccd1ca..1c64974e9162 100644 --- a/src/test/rustdoc-gui/search-form-elements.goml +++ b/src/test/rustdoc-gui/search-form-elements.goml @@ -92,7 +92,7 @@ reload: assert-css: ( ".search-input", { - "border-color": "rgb(240, 240, 240)", + "border-color": "rgb(224, 224, 224)", "background-color": "rgb(240, 240, 240)", "color": "rgb(17, 17, 17)", }, diff --git a/src/test/rustdoc-gui/search-input.goml b/src/test/rustdoc-gui/search-input.goml index 6903e1a1bf5c..fd61c4f43d18 100644 --- a/src/test/rustdoc-gui/search-input.goml +++ b/src/test/rustdoc-gui/search-input.goml @@ -3,7 +3,7 @@ goto: file://|DOC_PATH|/test_docs/index.html local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "dark"} reload: -assert-css: (".search-input", {"border-color": "rgb(240, 240, 240)"}) +assert-css: (".search-input", {"border-color": "rgb(224, 224, 224)"}) click: ".search-input" assert-css: (".search-input", {"border-color": "rgb(0, 141, 253)"}) From 584000a792b1016677fe4e0e78706d14a8034eb2 Mon Sep 17 00:00:00 2001 From: Lukas Lueg Date: Tue, 30 Aug 2022 22:27:21 +0200 Subject: [PATCH 4120/5092] Use `approx_ty_size` for `large_enum_variant` --- clippy_lints/src/large_enum_variant.rs | 98 ++++++---- src/docs/large_enum_variant.txt | 7 +- tests/ui/large_enum_variant.rs | 24 +++ tests/ui/large_enum_variant.stderr | 258 ++++++++++++++++--------- tests/ui/result_large_err.rs | 1 + tests/ui/result_large_err.stderr | 22 +-- 6 files changed, 269 insertions(+), 141 deletions(-) diff --git a/clippy_lints/src/large_enum_variant.rs b/clippy_lints/src/large_enum_variant.rs index c58df126d624..eb13d0869c03 100644 --- a/clippy_lints/src/large_enum_variant.rs +++ b/clippy_lints/src/large_enum_variant.rs @@ -1,13 +1,12 @@ //! lint when there is a large size difference between variants on an enum use clippy_utils::source::snippet_with_applicability; -use clippy_utils::{diagnostics::span_lint_and_then, ty::is_copy}; +use clippy_utils::{diagnostics::span_lint_and_then, ty::approx_ty_size, ty::is_copy}; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; -use rustc_middle::ty::layout::LayoutOf; -use rustc_middle::ty::{Adt, Ty}; +use rustc_middle::ty::{Adt, AdtDef, GenericArg, List, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; @@ -17,7 +16,7 @@ declare_clippy_lint! { /// `enum`s. /// /// ### Why is this bad? - /// Enum size is bounded by the largest variant. Having a + /// Enum size is bounded by the largest variant. Having one /// large variant can penalize the memory layout of that enum. /// /// ### Known problems @@ -33,8 +32,9 @@ declare_clippy_lint! { /// use case it may be possible to store the large data in an auxiliary /// structure (e.g. Arena or ECS). /// - /// The lint will ignore generic types if the layout depends on the - /// generics, even if the size difference will be large anyway. + /// The lint will ignore the impact of generic types to the type layout by + /// assuming every type parameter is zero-sized. Depending on your use case, + /// this may lead to a false positive. /// /// ### Example /// ```rust @@ -83,6 +83,38 @@ struct VariantInfo { fields_size: Vec, } +fn variants_size<'tcx>( + cx: &LateContext<'tcx>, + adt: AdtDef<'tcx>, + subst: &'tcx List>, +) -> Vec { + let mut variants_size = adt + .variants() + .iter() + .enumerate() + .map(|(i, variant)| { + let mut fields_size = variant + .fields + .iter() + .enumerate() + .map(|(i, f)| FieldInfo { + ind: i, + size: approx_ty_size(cx, f.ty(cx.tcx, subst)), + }) + .collect::>(); + fields_size.sort_by(|a, b| (a.size.cmp(&b.size))); + + VariantInfo { + ind: i, + size: fields_size.iter().map(|info| info.size).sum(), + fields_size, + } + }) + .collect::>(); + variants_size.sort_by(|a, b| (b.size.cmp(&a.size))); + variants_size +} + impl_lint_pass!(LargeEnumVariant => [LARGE_ENUM_VARIANT]); impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant { @@ -92,36 +124,14 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant { } if let ItemKind::Enum(ref def, _) = item.kind { let ty = cx.tcx.type_of(item.def_id); - let adt = ty.ty_adt_def().expect("already checked whether this is an enum"); + let (adt, subst) = match ty.kind() { + Adt(adt, subst) => (adt, subst), + _ => panic!("already checked whether this is an enum"), + }; if adt.variants().len() <= 1 { return; } - let mut variants_size: Vec = Vec::new(); - for (i, variant) in adt.variants().iter().enumerate() { - let mut fields_size = Vec::new(); - for (i, f) in variant.fields.iter().enumerate() { - let ty = cx.tcx.type_of(f.did); - // don't lint variants which have a field of generic type. - match cx.layout_of(ty) { - Ok(l) => { - let fsize = l.size.bytes(); - fields_size.push(FieldInfo { ind: i, size: fsize }); - }, - Err(_) => { - return; - }, - } - } - let size: u64 = fields_size.iter().map(|info| info.size).sum(); - - variants_size.push(VariantInfo { - ind: i, - size, - fields_size, - }); - } - - variants_size.sort_by(|a, b| (b.size.cmp(&a.size))); + let variants_size = variants_size(cx, *adt, subst); let mut difference = variants_size[0].size - variants_size[1].size; if difference > self.maximum_size_difference_allowed { @@ -129,20 +139,30 @@ impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant { span_lint_and_then( cx, LARGE_ENUM_VARIANT, - def.variants[variants_size[0].ind].span, + item.span, "large size difference between variants", |diag| { diag.span_label( - def.variants[variants_size[0].ind].span, - &format!("this variant is {} bytes", variants_size[0].size), + item.span, + format!("the entire enum is at least {} bytes", approx_ty_size(cx, ty)), ); - diag.span_note( + diag.span_label( + def.variants[variants_size[0].ind].span, + format!("the largest variant contains at least {} bytes", variants_size[0].size), + ); + diag.span_label( def.variants[variants_size[1].ind].span, - &format!("and the second-largest variant is {} bytes:", variants_size[1].size), + &if variants_size[1].fields_size.is_empty() { + "the second-largest variant carries no data at all".to_owned() + } else { + format!( + "the second-largest variant contains at least {} bytes", + variants_size[1].size + ) + }, ); let fields = def.variants[variants_size[0].ind].data.fields(); - variants_size[0].fields_size.sort_by(|a, b| (a.size.cmp(&b.size))); let mut applicability = Applicability::MaybeIncorrect; if is_copy(cx, ty) || maybe_copy(cx, ty) { diag.span_note( diff --git a/src/docs/large_enum_variant.txt b/src/docs/large_enum_variant.txt index 787e8e027e12..1f95430790d2 100644 --- a/src/docs/large_enum_variant.txt +++ b/src/docs/large_enum_variant.txt @@ -3,7 +3,7 @@ Checks for large size differences between variants on `enum`s. ### Why is this bad? -Enum size is bounded by the largest variant. Having a +Enum size is bounded by the largest variant. Having one large variant can penalize the memory layout of that enum. ### Known problems @@ -19,8 +19,9 @@ still be `Clone`, but that is worse ergonomically. Depending on the use case it may be possible to store the large data in an auxiliary structure (e.g. Arena or ECS). -The lint will ignore generic types if the layout depends on the -generics, even if the size difference will be large anyway. +The lint will ignore the impact of generic types to the type layout by +assuming every type parameter is zero-sized. Depending on your use case, +this may lead to a false positive. ### Example ``` diff --git a/tests/ui/large_enum_variant.rs b/tests/ui/large_enum_variant.rs index 23152a13322e..717009e4c4cc 100644 --- a/tests/ui/large_enum_variant.rs +++ b/tests/ui/large_enum_variant.rs @@ -130,6 +130,30 @@ impl Clone for SomeGenericPossiblyCopyEnum { impl Copy for SomeGenericPossiblyCopyEnum {} +enum LargeEnumWithGenerics { + Small, + Large((T, [u8; 512])), +} + +struct Foo { + foo: T, +} + +enum WithGenerics { + Large([Foo; 64]), + Small(u8), +} + +enum PossiblyLargeEnumWithConst { + SmallBuffer([u8; 4]), + MightyBuffer([u16; U]), +} + +enum LargeEnumOfConst { + Ok, + Error(PossiblyLargeEnumWithConst<256>), +} + fn main() { large_enum_variant!(); } diff --git a/tests/ui/large_enum_variant.stderr b/tests/ui/large_enum_variant.stderr index 0248327262da..e1ed2460e08a 100644 --- a/tests/ui/large_enum_variant.stderr +++ b/tests/ui/large_enum_variant.stderr @@ -1,143 +1,177 @@ error: large size difference between variants - --> $DIR/large_enum_variant.rs:12:5 + --> $DIR/large_enum_variant.rs:10:1 | -LL | B([i32; 8000]), - | ^^^^^^^^^^^^^^ this variant is 32000 bytes +LL | / enum LargeEnum { +LL | | A(i32), + | | ------ the second-largest variant contains at least 4 bytes +LL | | B([i32; 8000]), + | | -------------- the largest variant contains at least 32000 bytes +LL | | } + | |_^ the entire enum is at least 32004 bytes | = note: `-D clippy::large-enum-variant` implied by `-D warnings` -note: and the second-largest variant is 4 bytes: - --> $DIR/large_enum_variant.rs:11:5 - | -LL | A(i32), - | ^^^^^^ help: consider boxing the large fields to reduce the total size of the enum | LL | B(Box<[i32; 8000]>), | ~~~~~~~~~~~~~~~~ error: large size difference between variants - --> $DIR/large_enum_variant.rs:36:5 + --> $DIR/large_enum_variant.rs:34:1 | -LL | ContainingLargeEnum(LargeEnum), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32004 bytes +LL | / enum LargeEnum2 { +LL | | VariantOk(i32, u32), + | | ------------------- the second-largest variant contains at least 8 bytes +LL | | ContainingLargeEnum(LargeEnum), + | | ------------------------------ the largest variant contains at least 32004 bytes +LL | | } + | |_^ the entire enum is at least 32008 bytes | -note: and the second-largest variant is 8 bytes: - --> $DIR/large_enum_variant.rs:35:5 - | -LL | VariantOk(i32, u32), - | ^^^^^^^^^^^^^^^^^^^ help: consider boxing the large fields to reduce the total size of the enum | LL | ContainingLargeEnum(Box), | ~~~~~~~~~~~~~~ error: large size difference between variants - --> $DIR/large_enum_variant.rs:40:5 + --> $DIR/large_enum_variant.rs:39:1 | -LL | ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 70004 bytes +LL | / enum LargeEnum3 { +LL | | ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]), + | | --------------------------------------------------------- the largest variant contains at least 70004 bytes +LL | | VoidVariant, +LL | | StructLikeLittle { x: i32, y: i32 }, + | | ----------------------------------- the second-largest variant contains at least 8 bytes +LL | | } + | |_^ the entire enum is at least 70008 bytes | -note: and the second-largest variant is 8 bytes: - --> $DIR/large_enum_variant.rs:42:5 - | -LL | StructLikeLittle { x: i32, y: i32 }, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider boxing the large fields to reduce the total size of the enum | LL | ContainingMoreThanOneField(i32, Box<[i32; 8000]>, Box<[i32; 9500]>), | ~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~ error: large size difference between variants - --> $DIR/large_enum_variant.rs:47:5 + --> $DIR/large_enum_variant.rs:45:1 | -LL | StructLikeLarge { x: [i32; 8000], y: i32 }, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32004 bytes +LL | / enum LargeEnum4 { +LL | | VariantOk(i32, u32), + | | ------------------- the second-largest variant contains at least 8 bytes +LL | | StructLikeLarge { x: [i32; 8000], y: i32 }, + | | ------------------------------------------ the largest variant contains at least 32004 bytes +LL | | } + | |_^ the entire enum is at least 32008 bytes | -note: and the second-largest variant is 8 bytes: - --> $DIR/large_enum_variant.rs:46:5 - | -LL | VariantOk(i32, u32), - | ^^^^^^^^^^^^^^^^^^^ help: consider boxing the large fields to reduce the total size of the enum | LL | StructLikeLarge { x: Box<[i32; 8000]>, y: i32 }, | ~~~~~~~~~~~~~~~~ error: large size difference between variants - --> $DIR/large_enum_variant.rs:52:5 + --> $DIR/large_enum_variant.rs:50:1 | -LL | StructLikeLarge2 { x: [i32; 8000] }, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 32000 bytes +LL | / enum LargeEnum5 { +LL | | VariantOk(i32, u32), + | | ------------------- the second-largest variant contains at least 8 bytes +LL | | StructLikeLarge2 { x: [i32; 8000] }, + | | ----------------------------------- the largest variant contains at least 32000 bytes +LL | | } + | |_^ the entire enum is at least 32004 bytes | -note: and the second-largest variant is 8 bytes: - --> $DIR/large_enum_variant.rs:51:5 - | -LL | VariantOk(i32, u32), - | ^^^^^^^^^^^^^^^^^^^ help: consider boxing the large fields to reduce the total size of the enum | LL | StructLikeLarge2 { x: Box<[i32; 8000]> }, | ~~~~~~~~~~~~~~~~ error: large size difference between variants - --> $DIR/large_enum_variant.rs:68:5 + --> $DIR/large_enum_variant.rs:66:1 | -LL | B([u8; 1255]), - | ^^^^^^^^^^^^^ this variant is 1255 bytes +LL | / enum LargeEnum7 { +LL | | A, +LL | | B([u8; 1255]), + | | ------------- the largest variant contains at least 1255 bytes +LL | | C([u8; 200]), + | | ------------ the second-largest variant contains at least 200 bytes +LL | | } + | |_^ the entire enum is at least 1256 bytes | -note: and the second-largest variant is 200 bytes: - --> $DIR/large_enum_variant.rs:69:5 - | -LL | C([u8; 200]), - | ^^^^^^^^^^^^ help: consider boxing the large fields to reduce the total size of the enum | LL | B(Box<[u8; 1255]>), | ~~~~~~~~~~~~~~~ error: large size difference between variants - --> $DIR/large_enum_variant.rs:74:5 + --> $DIR/large_enum_variant.rs:72:1 | -LL | ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; 30]), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this variant is 70128 bytes +LL | / enum LargeEnum8 { +LL | | VariantOk(i32, u32), + | | ------------------- the second-largest variant contains at least 8 bytes +LL | | ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; 30]), + | | ------------------------------------------------------------------------- the largest variant contains at least 70128 bytes +LL | | } + | |_^ the entire enum is at least 70132 bytes | -note: and the second-largest variant is 8 bytes: - --> $DIR/large_enum_variant.rs:73:5 - | -LL | VariantOk(i32, u32), - | ^^^^^^^^^^^^^^^^^^^ help: consider boxing the large fields to reduce the total size of the enum | LL | ContainingMoreThanOneField(Box<[i32; 8000]>, [i32; 2], Box<[i32; 9500]>, [i32; 30]), | ~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~ error: large size difference between variants - --> $DIR/large_enum_variant.rs:79:5 + --> $DIR/large_enum_variant.rs:77:1 | -LL | B(Struct2), - | ^^^^^^^^^^ this variant is 32000 bytes +LL | / enum LargeEnum9 { +LL | | A(Struct<()>), + | | ------------- the second-largest variant contains at least 4 bytes +LL | | B(Struct2), + | | ---------- the largest variant contains at least 32000 bytes +LL | | } + | |_^ the entire enum is at least 32004 bytes | -note: and the second-largest variant is 4 bytes: - --> $DIR/large_enum_variant.rs:78:5 - | -LL | A(Struct<()>), - | ^^^^^^^^^^^^^ help: consider boxing the large fields to reduce the total size of the enum | LL | B(Box), | ~~~~~~~~~~~~ error: large size difference between variants - --> $DIR/large_enum_variant.rs:104:5 + --> $DIR/large_enum_variant.rs:82:1 | -LL | B([u128; 4000]), - | ^^^^^^^^^^^^^^^ this variant is 64000 bytes +LL | / enum LargeEnumOk2 { +LL | | A(T), + | | ---- the second-largest variant contains at least 0 bytes +LL | | B(Struct2), + | | ---------- the largest variant contains at least 32000 bytes +LL | | } + | |_^ the entire enum is at least 32000 bytes | -note: and the second-largest variant is 1 bytes: - --> $DIR/large_enum_variant.rs:103:5 +help: consider boxing the large fields to reduce the total size of the enum + | +LL | B(Box), + | ~~~~~~~~~~~~ + +error: large size difference between variants + --> $DIR/large_enum_variant.rs:87:1 + | +LL | / enum LargeEnumOk3 { +LL | | A(Struct), + | | ------------ the second-largest variant contains at least 4 bytes +LL | | B(Struct2), + | | ---------- the largest variant contains at least 32000 bytes +LL | | } + | |_^ the entire enum is at least 32000 bytes + | +help: consider boxing the large fields to reduce the total size of the enum + | +LL | B(Box), + | ~~~~~~~~~~~~ + +error: large size difference between variants + --> $DIR/large_enum_variant.rs:102:1 + | +LL | / enum CopyableLargeEnum { +LL | | A(bool), + | | ------- the second-largest variant contains at least 1 bytes +LL | | B([u128; 4000]), + | | --------------- the largest variant contains at least 64000 bytes +LL | | } + | |_^ the entire enum is at least 64008 bytes | -LL | A(bool), - | ^^^^^^^ note: boxing a variant would require the type no longer be `Copy` --> $DIR/large_enum_variant.rs:102:6 | @@ -150,16 +184,16 @@ LL | B([u128; 4000]), | ^^^^^^^^^^^^^^^ error: large size difference between variants - --> $DIR/large_enum_variant.rs:109:5 + --> $DIR/large_enum_variant.rs:107:1 | -LL | B([u128; 4000]), - | ^^^^^^^^^^^^^^^ this variant is 64000 bytes +LL | / enum ManuallyCopyLargeEnum { +LL | | A(bool), + | | ------- the second-largest variant contains at least 1 bytes +LL | | B([u128; 4000]), + | | --------------- the largest variant contains at least 64000 bytes +LL | | } + | |_^ the entire enum is at least 64008 bytes | -note: and the second-largest variant is 1 bytes: - --> $DIR/large_enum_variant.rs:108:5 - | -LL | A(bool), - | ^^^^^^^ note: boxing a variant would require the type no longer be `Copy` --> $DIR/large_enum_variant.rs:107:6 | @@ -172,16 +206,16 @@ LL | B([u128; 4000]), | ^^^^^^^^^^^^^^^ error: large size difference between variants - --> $DIR/large_enum_variant.rs:122:5 + --> $DIR/large_enum_variant.rs:120:1 | -LL | B([u64; 4000]), - | ^^^^^^^^^^^^^^ this variant is 32000 bytes +LL | / enum SomeGenericPossiblyCopyEnum { +LL | | A(bool, std::marker::PhantomData), + | | ------------------------------------ the second-largest variant contains at least 1 bytes +LL | | B([u64; 4000]), + | | -------------- the largest variant contains at least 32000 bytes +LL | | } + | |_^ the entire enum is at least 32008 bytes | -note: and the second-largest variant is 1 bytes: - --> $DIR/large_enum_variant.rs:121:5 - | -LL | A(bool, std::marker::PhantomData), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: boxing a variant would require the type no longer be `Copy` --> $DIR/large_enum_variant.rs:120:6 | @@ -193,5 +227,53 @@ help: consider boxing the large fields to reduce the total size of the enum LL | B([u64; 4000]), | ^^^^^^^^^^^^^^ -error: aborting due to 11 previous errors +error: large size difference between variants + --> $DIR/large_enum_variant.rs:133:1 + | +LL | / enum LargeEnumWithGenerics { +LL | | Small, + | | ----- the second-largest variant carries no data at all +LL | | Large((T, [u8; 512])), + | | --------------------- the largest variant contains at least 512 bytes +LL | | } + | |_^ the entire enum is at least 512 bytes + | +help: consider boxing the large fields to reduce the total size of the enum + | +LL | Large(Box<(T, [u8; 512])>), + | ~~~~~~~~~~~~~~~~~~~ + +error: large size difference between variants + --> $DIR/large_enum_variant.rs:142:1 + | +LL | / enum WithGenerics { +LL | | Large([Foo; 64]), + | | --------------------- the largest variant contains at least 512 bytes +LL | | Small(u8), + | | --------- the second-largest variant contains at least 1 bytes +LL | | } + | |_^ the entire enum is at least 520 bytes + | +help: consider boxing the large fields to reduce the total size of the enum + | +LL | Large(Box<[Foo; 64]>), + | ~~~~~~~~~~~~~~~~~~~ + +error: large size difference between variants + --> $DIR/large_enum_variant.rs:152:1 + | +LL | / enum LargeEnumOfConst { +LL | | Ok, + | | -- the second-largest variant carries no data at all +LL | | Error(PossiblyLargeEnumWithConst<256>), + | | -------------------------------------- the largest variant contains at least 514 bytes +LL | | } + | |_^ the entire enum is at least 514 bytes + | +help: consider boxing the large fields to reduce the total size of the enum + | +LL | Error(Box>), + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 16 previous errors diff --git a/tests/ui/result_large_err.rs b/tests/ui/result_large_err.rs index 78d8f76fe669..f7df3b856550 100644 --- a/tests/ui/result_large_err.rs +++ b/tests/ui/result_large_err.rs @@ -1,4 +1,5 @@ #![warn(clippy::result_large_err)] +#![allow(clippy::large_enum_variant)] pub fn small_err() -> Result<(), u128> { Ok(()) diff --git a/tests/ui/result_large_err.stderr b/tests/ui/result_large_err.stderr index 0f1f39d72cba..ef19f2854ab1 100644 --- a/tests/ui/result_large_err.stderr +++ b/tests/ui/result_large_err.stderr @@ -1,5 +1,5 @@ error: the `Err`-variant returned from this function is very large - --> $DIR/result_large_err.rs:7:23 + --> $DIR/result_large_err.rs:8:23 | LL | pub fn large_err() -> Result<(), [u8; 512]> { | ^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes @@ -8,7 +8,7 @@ LL | pub fn large_err() -> Result<(), [u8; 512]> { = help: try reducing the size of `[u8; 512]`, for example by boxing large elements or replacing it with `Box<[u8; 512]>` error: the `Err`-variant returned from this function is very large - --> $DIR/result_large_err.rs:18:21 + --> $DIR/result_large_err.rs:19:21 | LL | pub fn ret() -> Result<(), Self> { | ^^^^^^^^^^^^^^^^ the `Err`-variant is at least 240 bytes @@ -16,7 +16,7 @@ LL | pub fn ret() -> Result<(), Self> { = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box` error: the `Err`-variant returned from this function is very large - --> $DIR/result_large_err.rs:23:26 + --> $DIR/result_large_err.rs:24:26 | LL | pub fn struct_error() -> Result<(), FullyDefinedLargeError> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 240 bytes @@ -24,7 +24,7 @@ LL | pub fn struct_error() -> Result<(), FullyDefinedLargeError> { = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box` error: the `Err`-variant returned from this function is very large - --> $DIR/result_large_err.rs:28:45 + --> $DIR/result_large_err.rs:29:45 | LL | pub fn large_err_via_type_alias(x: T) -> Fdlr { | ^^^^^^^ the `Err`-variant is at least 240 bytes @@ -32,7 +32,7 @@ LL | pub fn large_err_via_type_alias(x: T) -> Fdlr { = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box` error: the `Err`-variant returned from this function is very large - --> $DIR/result_large_err.rs:36:34 + --> $DIR/result_large_err.rs:37:34 | LL | pub fn param_large_error() -> Result<(), (u128, R, FullyDefinedLargeError)> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 256 bytes @@ -40,7 +40,7 @@ LL | pub fn param_large_error() -> Result<(), (u128, R, FullyDefinedLargeErro = help: try reducing the size of `(u128, R, FullyDefinedLargeError)`, for example by boxing large elements or replacing it with `Box<(u128, R, FullyDefinedLargeError)>` error: the `Err`-variant returned from this function is very large - --> $DIR/result_large_err.rs:47:34 + --> $DIR/result_large_err.rs:48:34 | LL | pub fn large_enum_error() -> Result<(), Self> { | ^^^^^^^^^^^^^^^^ the `Err`-variant is at least 513 bytes @@ -48,7 +48,7 @@ LL | pub fn large_enum_error() -> Result<(), Self> { = help: try reducing the size of `LargeErrorVariants<()>`, for example by boxing large elements or replacing it with `Box>` error: the `Err`-variant returned from this function is very large - --> $DIR/result_large_err.rs:53:25 + --> $DIR/result_large_err.rs:54:25 | LL | fn large_error() -> Result<(), [u8; 512]> { | ^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes @@ -56,7 +56,7 @@ LL | fn large_error() -> Result<(), [u8; 512]> { = help: try reducing the size of `[u8; 512]`, for example by boxing large elements or replacing it with `Box<[u8; 512]>` error: the `Err`-variant returned from this function is very large - --> $DIR/result_large_err.rs:72:29 + --> $DIR/result_large_err.rs:73:29 | LL | pub fn large_union_err() -> Result<(), FullyDefinedUnionError> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes @@ -64,7 +64,7 @@ LL | pub fn large_union_err() -> Result<(), FullyDefinedUnionError> { = help: try reducing the size of `FullyDefinedUnionError`, for example by boxing large elements or replacing it with `Box` error: the `Err`-variant returned from this function is very large - --> $DIR/result_large_err.rs:81:40 + --> $DIR/result_large_err.rs:82:40 | LL | pub fn param_large_union() -> Result<(), UnionError> { | ^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes @@ -72,7 +72,7 @@ LL | pub fn param_large_union() -> Result<(), UnionError> { = help: try reducing the size of `UnionError`, for example by boxing large elements or replacing it with `Box>` error: the `Err`-variant returned from this function is very large - --> $DIR/result_large_err.rs:90:34 + --> $DIR/result_large_err.rs:91:34 | LL | pub fn array_error_subst() -> Result<(), ArrayError> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 128 bytes @@ -80,7 +80,7 @@ LL | pub fn array_error_subst() -> Result<(), ArrayError> { = help: try reducing the size of `ArrayError`, for example by boxing large elements or replacing it with `Box>` error: the `Err`-variant returned from this function is very large - --> $DIR/result_large_err.rs:94:31 + --> $DIR/result_large_err.rs:95:31 | LL | pub fn array_error() -> Result<(), ArrayError<(i32, T), U>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 128 bytes From c528f70325260dff830fad52b2ecdd0b7af77d38 Mon Sep 17 00:00:00 2001 From: Matt Hamrick Date: Fri, 2 Sep 2022 15:16:51 -0700 Subject: [PATCH 4121/5092] ffx component run should provide a collection In the future,`ffx component run` will not default to the using the `/core/ffx-laboratory` collection. Updated the run commands to include this. --- src/doc/rustc/src/platform-support/fuchsia.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md index 53a510f080ec..e256594b1538 100644 --- a/src/doc/rustc/src/platform-support/fuchsia.md +++ b/src/doc/rustc/src/platform-support/fuchsia.md @@ -562,6 +562,7 @@ Finally, run the component: ```sh ${SDK_PATH}/tools/${ARCH}/ffx component run \ + /core/ffx-laboratory:hello_fuchsia \ fuchsia-pkg://hello-fuchsia/hello_fuchsia_manifest#meta/hello_fuchsia.cm ``` @@ -571,6 +572,7 @@ passed. ```sh ${SDK_PATH}/tools/${ARCH}/ffx component run \ --recreate \ + /core/ffx-laboratory:hello_fuchsia \ fuchsia-pkg://hello-fuchsia/hello_fuchsia_manifest#meta/hello_fuchsia.cm ``` From 80e035c9e4f43bba282ec061dcbeae44ddb20f5f Mon Sep 17 00:00:00 2001 From: asquared31415 <34665709+asquared31415@users.noreply.github.com> Date: Fri, 2 Sep 2022 18:53:20 -0400 Subject: [PATCH 4122/5092] implement IsZero for Saturating and Wrapping --- library/alloc/src/lib.rs | 1 + library/alloc/src/vec/is_zero.rs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index ad6d19bbc687..e5cf9033c860 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -134,6 +134,7 @@ #![feature(ptr_metadata)] #![feature(ptr_sub_ptr)] #![feature(receiver_trait)] +#![feature(saturating_int_impl)] #![feature(set_ptr_value)] #![feature(slice_from_ptr_range)] #![feature(slice_group_by)] diff --git a/library/alloc/src/vec/is_zero.rs b/library/alloc/src/vec/is_zero.rs index 92a32779b8e6..2e025c8a4a5d 100644 --- a/library/alloc/src/vec/is_zero.rs +++ b/library/alloc/src/vec/is_zero.rs @@ -1,3 +1,5 @@ +use core::num::{Saturating, Wrapping}; + use crate::boxed::Box; #[rustc_specialization_trait] @@ -144,3 +146,17 @@ impl_is_zero_option_of_nonzero!( NonZeroUsize, NonZeroIsize, ); + +unsafe impl IsZero for Wrapping { + #[inline] + fn is_zero(&self) -> bool { + self.0.is_zero() + } +} + +unsafe impl IsZero for Saturating { + #[inline] + fn is_zero(&self) -> bool { + self.0.is_zero() + } +} From 91674cc56c2ce35097cf44262096c6ecbe067194 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 3 Sep 2022 05:39:46 +0000 Subject: [PATCH 4123/5092] Suggest removing unnecessary prefix let in patterns --- compiler/rustc_ast/src/token.rs | 24 +++++++++++++++++++ .../locales/en-US/parser.ftl | 3 +++ .../rustc_parse/src/parser/diagnostics.rs | 8 +++++++ compiler/rustc_parse/src/parser/pat.rs | 9 ++++++- src/test/ui/parser/unnecessary-let.rs | 11 +++++++++ src/test/ui/parser/unnecessary-let.stderr | 20 ++++++++++++++++ 6 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/parser/unnecessary-let.rs create mode 100644 src/test/ui/parser/unnecessary-let.stderr diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index dd98946b4cc5..bfc4db32d375 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -398,6 +398,30 @@ impl Token { } } + /// Returns `true` if the token can appear at the start of an pattern. + /// + /// Shamelessly borrowed from `can_begin_expr`, only used for diagnostics right now. + pub fn can_begin_pattern(&self) -> bool { + match self.uninterpolate().kind { + Ident(name, is_raw) => + ident_can_begin_expr(name, self.span, is_raw), // value name or keyword + | OpenDelim(Delimiter::Bracket | Delimiter::Parenthesis) // tuple or array + | Literal(..) // literal + | BinOp(Minus) // unary minus + | BinOp(And) // reference + | AndAnd // double reference + // DotDotDot is no longer supported + | DotDot | DotDotDot | DotDotEq // ranges + | Lt | BinOp(Shl) // associated path + | ModSep => true, // global path + Interpolated(ref nt) => matches!(**nt, NtLiteral(..) | + NtPat(..) | + NtBlock(..) | + NtPath(..)), + _ => false, + } + } + /// Returns `true` if the token can appear at the start of a type. pub fn can_begin_type(&self) -> bool { match self.uninterpolate().kind { diff --git a/compiler/rustc_error_messages/locales/en-US/parser.ftl b/compiler/rustc_error_messages/locales/en-US/parser.ftl index 3b37a393846b..bc17754c56ae 100644 --- a/compiler/rustc_error_messages/locales/en-US/parser.ftl +++ b/compiler/rustc_error_messages/locales/en-US/parser.ftl @@ -150,3 +150,6 @@ parser_dotdotdot = unexpected token: `...` parser_left_arrow_operator = unexpected token: `<-` .suggestion = if you meant to write a comparison against a negative value, add a space in between `<` and `-` + +parser_remove_let = expected pattern, found `let` + .suggestion = remove the unnecessary `let` keyword diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index dd806e2130e9..a299ee0a1046 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -705,6 +705,14 @@ pub(crate) struct LeftArrowOperator { pub span: Span, } +#[derive(SessionDiagnostic)] +#[diag(parser::remove_let)] +pub(crate) struct RemoveLet { + #[primary_span] + #[suggestion(applicability = "machine-applicable", code = "")] + pub span: Span, +} + // SnapshotParser is used to create a snapshot of the parser // without causing duplicate errors being emitted when the `Parser` // is dropped. diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 8b3200d45fcc..6c8f3f664e25 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -1,4 +1,5 @@ use super::{ForceCollect, Parser, PathStyle, TrailingToken}; +use crate::parser::diagnostics::RemoveLet; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor}; use rustc_ast::ptr::P; @@ -320,7 +321,13 @@ impl<'a> Parser<'a> { maybe_recover_from_interpolated_ty_qpath!(self, true); maybe_whole!(self, NtPat, |x| x); - let lo = self.token.span; + let mut lo = self.token.span; + + if self.token.is_keyword(kw::Let) && self.look_ahead(1, |tok| tok.can_begin_pattern()) { + self.bump(); + self.sess.emit_err(RemoveLet { span: lo }); + lo = self.token.span; + } let pat = if self.check(&token::BinOp(token::And)) || self.token.kind == token::AndAnd { self.parse_pat_deref(expected)? diff --git a/src/test/ui/parser/unnecessary-let.rs b/src/test/ui/parser/unnecessary-let.rs new file mode 100644 index 000000000000..6279109621d7 --- /dev/null +++ b/src/test/ui/parser/unnecessary-let.rs @@ -0,0 +1,11 @@ +fn main() { + for let x of [1, 2, 3] {} + //~^ ERROR expected pattern, found `let` + //~| ERROR missing `in` in `for` loop + + match 1 { + let 1 => {} + //~^ ERROR expected pattern, found `let` + _ => {} + } +} diff --git a/src/test/ui/parser/unnecessary-let.stderr b/src/test/ui/parser/unnecessary-let.stderr new file mode 100644 index 000000000000..952119cae3e2 --- /dev/null +++ b/src/test/ui/parser/unnecessary-let.stderr @@ -0,0 +1,20 @@ +error: expected pattern, found `let` + --> $DIR/unnecessary-let.rs:2:9 + | +LL | for let x of [1, 2, 3] {} + | ^^^ help: remove the unnecessary `let` keyword + +error: missing `in` in `for` loop + --> $DIR/unnecessary-let.rs:2:15 + | +LL | for let x of [1, 2, 3] {} + | ^^ help: try using `in` here instead + +error: expected pattern, found `let` + --> $DIR/unnecessary-let.rs:7:9 + | +LL | let 1 => {} + | ^^^ help: remove the unnecessary `let` keyword + +error: aborting due to 3 previous errors + From b0f3a551f2974eccf65b4477c9d7b2e42036d52f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 2 Sep 2022 02:17:44 +0000 Subject: [PATCH 4124/5092] Shrink suggestion span of argument mismatch error --- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 23 ++++++++--- src/test/ui/argument-suggestions/basic.stderr | 10 ++--- .../ui/argument-suggestions/complex.stderr | 2 +- .../argument-suggestions/exotic-calls.stderr | 8 ++-- .../extra_arguments.stderr | 28 +++++++------- .../argument-suggestions/issue-96638.stderr | 2 +- .../argument-suggestions/issue-97197.stderr | 2 +- .../argument-suggestions/issue-97484.stderr | 2 +- .../argument-suggestions/issue-98894.stderr | 2 +- .../argument-suggestions/issue-98897.stderr | 2 +- .../argument-suggestions/issue-99482.stderr | 2 +- .../missing_arguments.stderr | 38 +++++++++---------- .../argument-suggestions/mixed_cases.stderr | 12 +++--- .../permuted_arguments.stderr | 4 +- .../swapped_arguments.stderr | 10 ++--- src/test/ui/c-variadic/variadic-ffi-1.stderr | 4 +- src/test/ui/error-codes/E0057.stderr | 4 +- src/test/ui/error-codes/E0060.stderr | 2 +- src/test/ui/error-codes/E0061.stderr | 4 +- .../issue-58451.stderr | 2 +- src/test/ui/issues/issue-16939.stderr | 2 +- src/test/ui/issues/issue-18819.stderr | 2 +- src/test/ui/issues/issue-4935.stderr | 2 +- src/test/ui/lifetimes/issue-26638.stderr | 2 +- .../ui/methods/method-call-err-msg.stderr | 8 ++-- .../overloaded-calls-bad.stderr | 4 +- src/test/ui/not-enough-arguments.stderr | 4 +- .../resolve/resolve-primitive-fallback.stderr | 2 +- src/test/ui/span/issue-34264.stderr | 4 +- src/test/ui/span/missing-unit-argument.stderr | 12 +++--- .../args-instead-of-tuple-errors.stderr | 6 +-- .../suggestions/args-instead-of-tuple.stderr | 2 +- src/test/ui/tuple/wrong_argument_ice-3.stderr | 2 +- src/test/ui/tuple/wrong_argument_ice-4.stderr | 2 +- ...priority-higher-than-other-inherent.stderr | 2 +- ...e-ascription-instead-of-initializer.stderr | 2 +- .../ui/typeck/remove-extra-argument.stderr | 2 +- .../ui/typeck/struct-enum-wrong-args.stderr | 16 ++++---- 38 files changed, 125 insertions(+), 114 deletions(-) diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 7ff4aef2d257..ce0e59d06226 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -1056,11 +1056,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if let Some(suggestion_text) = suggestion_text { let source_map = self.sess().source_map(); - let mut suggestion = format!( - "{}(", - source_map.span_to_snippet(full_call_span).unwrap_or_else(|_| fn_def_id - .map_or("".to_string(), |fn_def_id| tcx.item_name(fn_def_id).to_string())) - ); + let (mut suggestion, suggestion_span) = + if let Some(call_span) = full_call_span.find_ancestor_inside(error_span) { + ("(".to_string(), call_span.shrink_to_hi().to(error_span.shrink_to_hi())) + } else { + ( + format!( + "{}(", + source_map.span_to_snippet(full_call_span).unwrap_or_else(|_| { + fn_def_id.map_or("".to_string(), |fn_def_id| { + tcx.item_name(fn_def_id).to_string() + }) + }) + ), + error_span, + ) + }; let mut needs_comma = false; for (expected_idx, provided_idx) in matched_inputs.iter_enumerated() { if needs_comma { @@ -1088,7 +1099,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } suggestion += ")"; err.span_suggestion_verbose( - error_span, + suggestion_span, &suggestion_text, suggestion, Applicability::HasPlaceholders, diff --git a/src/test/ui/argument-suggestions/basic.stderr b/src/test/ui/argument-suggestions/basic.stderr index c495ad6b842f..b118ce1bd0ea 100644 --- a/src/test/ui/argument-suggestions/basic.stderr +++ b/src/test/ui/argument-suggestions/basic.stderr @@ -26,7 +26,7 @@ LL | fn extra() {} help: remove the extra argument | LL | extra(); - | ~~~~~~~ + | ~~ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/basic.rs:22:5 @@ -42,7 +42,7 @@ LL | fn missing(_i: u32) {} help: provide the argument | LL | missing(/* u32 */); - | ~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~ error[E0308]: arguments to this function are incorrect --> $DIR/basic.rs:23:5 @@ -60,7 +60,7 @@ LL | fn swapped(_i: u32, _s: &str) {} help: swap these arguments | LL | swapped(1, ""); - | ~~~~~~~~~~~~~~ + | ~~~~~~~ error[E0308]: arguments to this function are incorrect --> $DIR/basic.rs:24:5 @@ -79,7 +79,7 @@ LL | fn permuted(_x: X, _y: Y, _z: Z) {} help: reorder these arguments | LL | permuted(X {}, Y {}, Z {}); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~ error[E0057]: this function takes 1 argument but 0 arguments were supplied --> $DIR/basic.rs:27:5 @@ -95,7 +95,7 @@ LL | let closure = |x| x; help: provide the argument | LL | closure(/* value */); - | ~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~ error: aborting due to 6 previous errors diff --git a/src/test/ui/argument-suggestions/complex.stderr b/src/test/ui/argument-suggestions/complex.stderr index bf49e7444583..205a852983a3 100644 --- a/src/test/ui/argument-suggestions/complex.stderr +++ b/src/test/ui/argument-suggestions/complex.stderr @@ -12,7 +12,7 @@ LL | fn complex(_i: u32, _s: &str, _e: E, _f: F, _g: G, _x: X, _y: Y, _z: Z ) {} help: did you mean | LL | complex(/* u32 */, &"", /* E */, F::X2, G{}, X {}, Y {}, Z {}); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/argument-suggestions/exotic-calls.stderr b/src/test/ui/argument-suggestions/exotic-calls.stderr index ca93ecc4e381..0580e53c510a 100644 --- a/src/test/ui/argument-suggestions/exotic-calls.stderr +++ b/src/test/ui/argument-suggestions/exotic-calls.stderr @@ -12,7 +12,7 @@ LL | fn foo(t: T) { help: remove the extra argument | LL | t(); - | ~~~ + | ~~ error[E0057]: this function takes 0 arguments but 1 argument was supplied --> $DIR/exotic-calls.rs:7:5 @@ -28,7 +28,7 @@ LL | fn bar(t: impl Fn()) { help: remove the extra argument | LL | t(); - | ~~~ + | ~~ error[E0057]: this function takes 0 arguments but 1 argument was supplied --> $DIR/exotic-calls.rs:16:5 @@ -44,7 +44,7 @@ LL | fn baz() -> impl Fn() { help: remove the extra argument | LL | baz()() - | + | ~~ error[E0057]: this function takes 0 arguments but 1 argument was supplied --> $DIR/exotic-calls.rs:22:5 @@ -60,7 +60,7 @@ LL | let x = || {}; help: remove the extra argument | LL | x(); - | ~~~ + | ~~ error: aborting due to 4 previous errors diff --git a/src/test/ui/argument-suggestions/extra_arguments.stderr b/src/test/ui/argument-suggestions/extra_arguments.stderr index 32b1e15737ab..48787b0c352c 100644 --- a/src/test/ui/argument-suggestions/extra_arguments.stderr +++ b/src/test/ui/argument-suggestions/extra_arguments.stderr @@ -12,7 +12,7 @@ LL | fn empty() {} help: remove the extra argument | LL | empty(); - | ~~~~~~~ + | ~~ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:9:3 @@ -28,7 +28,7 @@ LL | fn one_arg(_a: i32) {} help: remove the extra argument | LL | one_arg(1); - | ~~~~~~~~~~ + | ~~~ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:10:3 @@ -44,7 +44,7 @@ LL | fn one_arg(_a: i32) {} help: remove the extra argument | LL | one_arg(1); - | ~~~~~~~~~~ + | ~~~ error[E0061]: this function takes 1 argument but 3 arguments were supplied --> $DIR/extra_arguments.rs:11:3 @@ -62,7 +62,7 @@ LL | fn one_arg(_a: i32) {} help: remove the extra arguments | LL | one_arg(1); - | ~~~~~~~~~~ + | ~~~ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:13:3 @@ -78,7 +78,7 @@ LL | fn two_arg_same(_a: i32, _b: i32) {} help: remove the extra argument | LL | two_arg_same(1, 1); - | ~~~~~~~~~~~~~~~~~~ + | ~~~~~~ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:14:3 @@ -94,7 +94,7 @@ LL | fn two_arg_same(_a: i32, _b: i32) {} help: remove the extra argument | LL | two_arg_same(1, 1); - | ~~~~~~~~~~~~~~~~~~ + | ~~~~~~ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:16:3 @@ -110,7 +110,7 @@ LL | fn two_arg_diff(_a: i32, _b: &str) {} help: remove the extra argument | LL | two_arg_diff(1, ""); - | ~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:17:3 @@ -126,7 +126,7 @@ LL | fn two_arg_diff(_a: i32, _b: &str) {} help: remove the extra argument | LL | two_arg_diff(1, ""); - | ~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~ error[E0061]: this function takes 2 arguments but 4 arguments were supplied --> $DIR/extra_arguments.rs:18:3 @@ -144,7 +144,7 @@ LL | fn two_arg_diff(_a: i32, _b: &str) {} help: remove the extra arguments | LL | two_arg_diff(1, ""); - | ~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~ error[E0061]: this function takes 2 arguments but 4 arguments were supplied --> $DIR/extra_arguments.rs:19:3 @@ -162,7 +162,7 @@ LL | fn two_arg_diff(_a: i32, _b: &str) {} help: remove the extra arguments | LL | two_arg_diff(1, ""); - | ~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:22:3 @@ -178,7 +178,7 @@ LL | fn two_arg_same(_a: i32, _b: i32) {} help: remove the extra argument | LL | two_arg_same(1, 1); - | ~~~~~~~~~~~~~~~~~~ + | ~~~~~~ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:23:3 @@ -194,7 +194,7 @@ LL | fn two_arg_diff(_a: i32, _b: &str) {} help: remove the extra argument | LL | two_arg_diff(1, ""); - | ~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:24:3 @@ -213,7 +213,7 @@ LL | fn two_arg_same(_a: i32, _b: i32) {} help: remove the extra argument | LL | two_arg_same(1, 1); - | ~~~~~~~~~~~~~~~~~~ + | ~~~~~~ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:30:3 @@ -232,7 +232,7 @@ LL | fn two_arg_diff(_a: i32, _b: &str) {} help: remove the extra argument | LL | two_arg_diff(1, ""); - | ~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~ error: aborting due to 14 previous errors diff --git a/src/test/ui/argument-suggestions/issue-96638.stderr b/src/test/ui/argument-suggestions/issue-96638.stderr index 804cb1aa3221..4d18b97c98be 100644 --- a/src/test/ui/argument-suggestions/issue-96638.stderr +++ b/src/test/ui/argument-suggestions/issue-96638.stderr @@ -14,7 +14,7 @@ LL | fn f(_: usize, _: &usize, _: usize) {} help: provide the argument | LL | f(/* usize */, &x, /* usize */); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/argument-suggestions/issue-97197.stderr b/src/test/ui/argument-suggestions/issue-97197.stderr index ac54adc5eeb9..de221ba1fe18 100644 --- a/src/test/ui/argument-suggestions/issue-97197.stderr +++ b/src/test/ui/argument-suggestions/issue-97197.stderr @@ -12,7 +12,7 @@ LL | pub fn g(a1: (), a2: bool, a3: bool, a4: bool, a5: bool, a6: ()) -> () {} help: provide the arguments | LL | g((), /* bool */, /* bool */, /* bool */, /* bool */, ()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/argument-suggestions/issue-97484.stderr b/src/test/ui/argument-suggestions/issue-97484.stderr index b5dedf0f4fa0..caa50f14b43e 100644 --- a/src/test/ui/argument-suggestions/issue-97484.stderr +++ b/src/test/ui/argument-suggestions/issue-97484.stderr @@ -20,7 +20,7 @@ LL | foo(&&A, B, C, D, &E, F, G); help: remove the extra arguments | LL | foo(&&A, D, /* &E */, G); - | ~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/argument-suggestions/issue-98894.stderr b/src/test/ui/argument-suggestions/issue-98894.stderr index 0c8b94901e16..f64a83ab7106 100644 --- a/src/test/ui/argument-suggestions/issue-98894.stderr +++ b/src/test/ui/argument-suggestions/issue-98894.stderr @@ -12,7 +12,7 @@ LL | (|_, ()| ())(if true {} else {return;}); help: provide the argument | LL | (|_, ()| ())(if true {} else {return;}, ()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/argument-suggestions/issue-98897.stderr b/src/test/ui/argument-suggestions/issue-98897.stderr index 8f0d98d09e89..f2c47d353efa 100644 --- a/src/test/ui/argument-suggestions/issue-98897.stderr +++ b/src/test/ui/argument-suggestions/issue-98897.stderr @@ -12,7 +12,7 @@ LL | (|_, ()| ())([return, ()]); help: provide the argument | LL | (|_, ()| ())([return, ()], ()); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/argument-suggestions/issue-99482.stderr b/src/test/ui/argument-suggestions/issue-99482.stderr index bc005e82a2c4..bcf36e37cdcc 100644 --- a/src/test/ui/argument-suggestions/issue-99482.stderr +++ b/src/test/ui/argument-suggestions/issue-99482.stderr @@ -12,7 +12,7 @@ LL | let f = |_: (), f: fn()| f; help: provide the argument | LL | let _f = f((), main); - | ~~~~~~~~~~~ + | ~~~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/argument-suggestions/missing_arguments.stderr b/src/test/ui/argument-suggestions/missing_arguments.stderr index 2509d22d7ff8..ba9ece040bec 100644 --- a/src/test/ui/argument-suggestions/missing_arguments.stderr +++ b/src/test/ui/argument-suggestions/missing_arguments.stderr @@ -12,7 +12,7 @@ LL | fn one_arg(_a: i32) {} help: provide the argument | LL | one_arg(/* i32 */); - | ~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~ error[E0061]: this function takes 2 arguments but 0 arguments were supplied --> $DIR/missing_arguments.rs:14:3 @@ -28,7 +28,7 @@ LL | fn two_same(_a: i32, _b: i32) {} help: provide the arguments | LL | two_same(/* i32 */, /* i32 */); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~ error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/missing_arguments.rs:15:3 @@ -44,7 +44,7 @@ LL | fn two_same(_a: i32, _b: i32) {} help: provide the argument | LL | two_same(1, /* i32 */); - | ~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~ error[E0061]: this function takes 2 arguments but 0 arguments were supplied --> $DIR/missing_arguments.rs:16:3 @@ -60,7 +60,7 @@ LL | fn two_diff(_a: i32, _b: f32) {} help: provide the arguments | LL | two_diff(/* i32 */, /* f32 */); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~ error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/missing_arguments.rs:17:3 @@ -76,7 +76,7 @@ LL | fn two_diff(_a: i32, _b: f32) {} help: provide the argument | LL | two_diff(1, /* f32 */); - | ~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~ error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/missing_arguments.rs:18:3 @@ -92,7 +92,7 @@ LL | fn two_diff(_a: i32, _b: f32) {} help: provide the argument | LL | two_diff(/* i32 */, 1.0); - | ~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~ error[E0061]: this function takes 3 arguments but 0 arguments were supplied --> $DIR/missing_arguments.rs:21:3 @@ -108,7 +108,7 @@ LL | fn three_same(_a: i32, _b: i32, _c: i32) {} help: provide the arguments | LL | three_same(/* i32 */, /* i32 */, /* i32 */); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0061]: this function takes 3 arguments but 1 argument was supplied --> $DIR/missing_arguments.rs:22:3 @@ -124,7 +124,7 @@ LL | fn three_same(_a: i32, _b: i32, _c: i32) {} help: provide the arguments | LL | three_same(1, /* i32 */, /* i32 */); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0061]: this function takes 3 arguments but 2 arguments were supplied --> $DIR/missing_arguments.rs:23:3 @@ -140,7 +140,7 @@ LL | fn three_same(_a: i32, _b: i32, _c: i32) {} help: provide the argument | LL | three_same(1, 1, /* i32 */); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~ error[E0061]: this function takes 3 arguments but 2 arguments were supplied --> $DIR/missing_arguments.rs:26:3 @@ -156,7 +156,7 @@ LL | fn three_diff(_a: i32, _b: f32, _c: &str) {} help: provide the argument | LL | three_diff(/* i32 */, 1.0, ""); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~ error[E0061]: this function takes 3 arguments but 2 arguments were supplied --> $DIR/missing_arguments.rs:27:3 @@ -172,7 +172,7 @@ LL | fn three_diff(_a: i32, _b: f32, _c: &str) {} help: provide the argument | LL | three_diff(1, /* f32 */, ""); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~ error[E0061]: this function takes 3 arguments but 2 arguments were supplied --> $DIR/missing_arguments.rs:28:3 @@ -188,7 +188,7 @@ LL | fn three_diff(_a: i32, _b: f32, _c: &str) {} help: provide the argument | LL | three_diff(1, 1.0, /* &str */); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~ error[E0061]: this function takes 3 arguments but 1 argument was supplied --> $DIR/missing_arguments.rs:29:3 @@ -204,7 +204,7 @@ LL | fn three_diff(_a: i32, _b: f32, _c: &str) {} help: provide the arguments | LL | three_diff(/* i32 */, /* f32 */, ""); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0061]: this function takes 3 arguments but 1 argument was supplied --> $DIR/missing_arguments.rs:30:3 @@ -223,7 +223,7 @@ LL | fn three_diff(_a: i32, _b: f32, _c: &str) {} help: provide the arguments | LL | three_diff(/* i32 */, 1.0, /* &str */); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0061]: this function takes 3 arguments but 1 argument was supplied --> $DIR/missing_arguments.rs:31:3 @@ -239,7 +239,7 @@ LL | fn three_diff(_a: i32, _b: f32, _c: &str) {} help: provide the arguments | LL | three_diff(1, /* f32 */, /* &str */); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0061]: this function takes 4 arguments but 0 arguments were supplied --> $DIR/missing_arguments.rs:34:3 @@ -255,7 +255,7 @@ LL | fn four_repeated(_a: i32, _b: f32, _c: f32, _d: &str) {} help: provide the arguments | LL | four_repeated(/* i32 */, /* f32 */, /* f32 */, /* &str */); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0061]: this function takes 4 arguments but 2 arguments were supplied --> $DIR/missing_arguments.rs:35:3 @@ -271,7 +271,7 @@ LL | fn four_repeated(_a: i32, _b: f32, _c: f32, _d: &str) {} help: provide the arguments | LL | four_repeated(1, /* f32 */, /* f32 */, ""); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0061]: this function takes 5 arguments but 0 arguments were supplied --> $DIR/missing_arguments.rs:38:3 @@ -287,7 +287,7 @@ LL | fn complex(_a: i32, _b: f32, _c: i32, _d: f32, _e: &str) {} help: provide the arguments | LL | complex(/* i32 */, /* f32 */, /* i32 */, /* f32 */, /* &str */); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0061]: this function takes 5 arguments but 2 arguments were supplied --> $DIR/missing_arguments.rs:39:3 @@ -303,7 +303,7 @@ LL | fn complex(_a: i32, _b: f32, _c: i32, _d: f32, _e: &str) {} help: provide the arguments | LL | complex(1, /* f32 */, /* i32 */, /* f32 */, ""); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 19 previous errors diff --git a/src/test/ui/argument-suggestions/mixed_cases.stderr b/src/test/ui/argument-suggestions/mixed_cases.stderr index a52a30d7884f..8c525db1ac66 100644 --- a/src/test/ui/argument-suggestions/mixed_cases.stderr +++ b/src/test/ui/argument-suggestions/mixed_cases.stderr @@ -14,7 +14,7 @@ LL | fn two_args(_a: i32, _b: f32) {} help: remove the extra argument | LL | two_args(1, /* f32 */); - | ~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~ error[E0061]: this function takes 3 arguments but 4 arguments were supplied --> $DIR/mixed_cases.rs:11:3 @@ -33,7 +33,7 @@ LL | fn three_args(_a: i32, _b: f32, _c: &str) {} help: did you mean | LL | three_args(1, /* f32 */, ""); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~ error[E0061]: this function takes 3 arguments but 2 arguments were supplied --> $DIR/mixed_cases.rs:14:3 @@ -52,7 +52,7 @@ LL | fn three_args(_a: i32, _b: f32, _c: &str) {} help: provide the argument | LL | three_args(1, /* f32 */, /* &str */); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0308]: arguments to this function are incorrect --> $DIR/mixed_cases.rs:17:3 @@ -70,7 +70,7 @@ LL | fn three_args(_a: i32, _b: f32, _c: &str) {} help: did you mean | LL | three_args(1, /* f32 */, ""); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~ error[E0308]: arguments to this function are incorrect --> $DIR/mixed_cases.rs:20:3 @@ -89,7 +89,7 @@ LL | fn three_args(_a: i32, _b: f32, _c: &str) {} help: swap these arguments | LL | three_args(1, /* f32 */, ""); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~ error[E0061]: this function takes 3 arguments but 2 arguments were supplied --> $DIR/mixed_cases.rs:23:3 @@ -109,7 +109,7 @@ LL | fn three_args(_a: i32, _b: f32, _c: &str) {} help: did you mean | LL | three_args(1, /* f32 */, ""); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~ error: aborting due to 6 previous errors diff --git a/src/test/ui/argument-suggestions/permuted_arguments.stderr b/src/test/ui/argument-suggestions/permuted_arguments.stderr index f16d22860d80..655807a7f382 100644 --- a/src/test/ui/argument-suggestions/permuted_arguments.stderr +++ b/src/test/ui/argument-suggestions/permuted_arguments.stderr @@ -15,7 +15,7 @@ LL | fn three_args(_a: i32, _b: f32, _c: &str) {} help: reorder these arguments | LL | three_args(1, 1.0, ""); - | ~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~ error[E0308]: arguments to this function are incorrect --> $DIR/permuted_arguments.rs:12:3 @@ -36,7 +36,7 @@ LL | fn many_args(_a: i32, _b: f32, _c: &str, _d: X, _e: Y) {} help: reorder these arguments | LL | many_args(1, 1.0, "", X {}, Y {}); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 2 previous errors diff --git a/src/test/ui/argument-suggestions/swapped_arguments.stderr b/src/test/ui/argument-suggestions/swapped_arguments.stderr index a90792d0c534..dabf5e952b26 100644 --- a/src/test/ui/argument-suggestions/swapped_arguments.stderr +++ b/src/test/ui/argument-suggestions/swapped_arguments.stderr @@ -14,7 +14,7 @@ LL | fn two_args(_a: i32, _b: f32) {} help: swap these arguments | LL | two_args(1, 1.0); - | ~~~~~~~~~~~~~~~~ + | ~~~~~~~~ error[E0308]: arguments to this function are incorrect --> $DIR/swapped_arguments.rs:9:3 @@ -32,7 +32,7 @@ LL | fn three_args(_a: i32, _b: f32, _c: &str) {} help: swap these arguments | LL | three_args(1, 1.0, ""); - | ~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~ error[E0308]: arguments to this function are incorrect --> $DIR/swapped_arguments.rs:10:3 @@ -50,7 +50,7 @@ LL | fn three_args(_a: i32, _b: f32, _c: &str) {} help: swap these arguments | LL | three_args(1, 1.0, ""); - | ~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~ error[E0308]: arguments to this function are incorrect --> $DIR/swapped_arguments.rs:11:3 @@ -68,7 +68,7 @@ LL | fn three_args(_a: i32, _b: f32, _c: &str) {} help: swap these arguments | LL | three_args(1, 1.0, ""); - | ~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~ error[E0308]: arguments to this function are incorrect --> $DIR/swapped_arguments.rs:13:3 @@ -88,7 +88,7 @@ LL | fn four_args(_a: i32, _b: f32, _c: &str, _d: X) {} help: did you mean | LL | four_args(1, 1.0, "", X {}); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~ error: aborting due to 5 previous errors diff --git a/src/test/ui/c-variadic/variadic-ffi-1.stderr b/src/test/ui/c-variadic/variadic-ffi-1.stderr index 176bec819d67..2ffb80f7ef61 100644 --- a/src/test/ui/c-variadic/variadic-ffi-1.stderr +++ b/src/test/ui/c-variadic/variadic-ffi-1.stderr @@ -18,7 +18,7 @@ LL | fn foo(f: isize, x: u8, ...); help: provide the arguments | LL | foo(/* isize */, /* u8 */); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~~ error[E0060]: this function takes at least 2 arguments but 1 argument was supplied --> $DIR/variadic-ffi-1.rs:21:9 @@ -34,7 +34,7 @@ LL | fn foo(f: isize, x: u8, ...); help: provide the argument | LL | foo(1, /* u8 */); - | ~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~ error[E0308]: mismatched types --> $DIR/variadic-ffi-1.rs:23:56 diff --git a/src/test/ui/error-codes/E0057.stderr b/src/test/ui/error-codes/E0057.stderr index 2307f52c93bc..bea226f09dcb 100644 --- a/src/test/ui/error-codes/E0057.stderr +++ b/src/test/ui/error-codes/E0057.stderr @@ -12,7 +12,7 @@ LL | let f = |x| x * 3; help: provide the argument | LL | let a = f(/* value */); - | ~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~ error[E0057]: this function takes 1 argument but 2 arguments were supplied --> $DIR/E0057.rs:5:13 @@ -28,7 +28,7 @@ LL | let f = |x| x * 3; help: remove the extra argument | LL | let c = f(2); - | ~~~~ + | ~~~ error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0060.stderr b/src/test/ui/error-codes/E0060.stderr index 644fd5983387..934a18d896dc 100644 --- a/src/test/ui/error-codes/E0060.stderr +++ b/src/test/ui/error-codes/E0060.stderr @@ -12,7 +12,7 @@ LL | fn printf(_: *const u8, ...) -> u32; help: provide the argument | LL | unsafe { printf(/* *const u8 */); } - | ~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0061.stderr b/src/test/ui/error-codes/E0061.stderr index fa55db0924d2..fa4ccbe6677c 100644 --- a/src/test/ui/error-codes/E0061.stderr +++ b/src/test/ui/error-codes/E0061.stderr @@ -12,7 +12,7 @@ LL | fn f(a: u16, b: &str) {} help: provide the argument | LL | f(0, /* &str */); - | ~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/E0061.rs:9:5 @@ -28,7 +28,7 @@ LL | fn f2(a: u16) {} help: provide the argument | LL | f2(/* u16 */); - | ~~~~~~~~~~~~~ + | ~~~~~~~~~~~ error: aborting due to 2 previous errors diff --git a/src/test/ui/higher-rank-trait-bounds/issue-58451.stderr b/src/test/ui/higher-rank-trait-bounds/issue-58451.stderr index 22ba63c3e86f..09e25f4dc966 100644 --- a/src/test/ui/higher-rank-trait-bounds/issue-58451.stderr +++ b/src/test/ui/higher-rank-trait-bounds/issue-58451.stderr @@ -12,7 +12,7 @@ LL | fn f(i: I) help: provide the argument | LL | f(&[f(/* value */)]); - | ~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-16939.stderr b/src/test/ui/issues/issue-16939.stderr index aaa3c49b3d83..76645645464e 100644 --- a/src/test/ui/issues/issue-16939.stderr +++ b/src/test/ui/issues/issue-16939.stderr @@ -12,7 +12,7 @@ LL | fn _foo (f: F) { help: remove the extra argument | LL | |t| f(); - | ~~~ + | ~~ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-18819.stderr b/src/test/ui/issues/issue-18819.stderr index e499d0572f60..767fdd5caf06 100644 --- a/src/test/ui/issues/issue-18819.stderr +++ b/src/test/ui/issues/issue-18819.stderr @@ -23,7 +23,7 @@ LL | print_x(&X); help: provide the argument | LL | print_x(/* &dyn Foo */, /* &str */); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-4935.stderr b/src/test/ui/issues/issue-4935.stderr index aab19a699ace..bb45fa083381 100644 --- a/src/test/ui/issues/issue-4935.stderr +++ b/src/test/ui/issues/issue-4935.stderr @@ -12,7 +12,7 @@ LL | fn foo(a: usize) {} help: remove the extra argument | LL | fn main() { foo(5) } - | ~~~~~~ + | ~~~ error: aborting due to previous error diff --git a/src/test/ui/lifetimes/issue-26638.stderr b/src/test/ui/lifetimes/issue-26638.stderr index f3af5cf5a357..98d39d614d0e 100644 --- a/src/test/ui/lifetimes/issue-26638.stderr +++ b/src/test/ui/lifetimes/issue-26638.stderr @@ -54,7 +54,7 @@ LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() } help: provide the argument | LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter(/* &u8 */) } - | ~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~ error[E0308]: mismatched types --> $DIR/issue-26638.rs:5:47 diff --git a/src/test/ui/methods/method-call-err-msg.stderr b/src/test/ui/methods/method-call-err-msg.stderr index e9b49c89bf16..a4ffb864dad9 100644 --- a/src/test/ui/methods/method-call-err-msg.stderr +++ b/src/test/ui/methods/method-call-err-msg.stderr @@ -12,7 +12,7 @@ LL | fn zero(self) -> Foo { self } help: remove the extra argument | LL | x.zero() - | ~~~~~~ + | ~~ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/method-call-err-msg.rs:14:7 @@ -28,7 +28,7 @@ LL | fn one(self, _: isize) -> Foo { self } help: provide the argument | LL | .one(/* isize */) - | ~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~ error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/method-call-err-msg.rs:15:7 @@ -44,7 +44,7 @@ LL | fn two(self, _: isize, _: isize) -> Foo { self } help: provide the argument | LL | .two(0, /* isize */); - | ~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~ error[E0599]: `Foo` is not an iterator --> $DIR/method-call-err-msg.rs:19:7 @@ -84,7 +84,7 @@ LL | fn three(self, _: T, _: T, _: T) -> Foo { self } help: provide the arguments | LL | y.three::(/* usize */, /* usize */, /* usize */); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 5 previous errors diff --git a/src/test/ui/mismatched_types/overloaded-calls-bad.stderr b/src/test/ui/mismatched_types/overloaded-calls-bad.stderr index 475ea9dfaf1b..fb3597aa8530 100644 --- a/src/test/ui/mismatched_types/overloaded-calls-bad.stderr +++ b/src/test/ui/mismatched_types/overloaded-calls-bad.stderr @@ -26,7 +26,7 @@ LL | impl FnMut<(isize,)> for S { help: provide the argument | LL | let ans = s(/* isize */); - | ~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~ error[E0057]: this function takes 1 argument but 2 arguments were supplied --> $DIR/overloaded-calls-bad.rs:31:15 @@ -44,7 +44,7 @@ LL | impl FnMut<(isize,)> for S { help: remove the extra argument | LL | let ans = s(/* isize */); - | ~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~ error: aborting due to 3 previous errors diff --git a/src/test/ui/not-enough-arguments.stderr b/src/test/ui/not-enough-arguments.stderr index b1df578ea80a..8b2dafb4e1d0 100644 --- a/src/test/ui/not-enough-arguments.stderr +++ b/src/test/ui/not-enough-arguments.stderr @@ -12,7 +12,7 @@ LL | fn foo(a: isize, b: isize, c: isize, d:isize) { help: provide the argument | LL | foo(1, 2, 3, /* isize */); - | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~ error[E0061]: this function takes 6 arguments but 3 arguments were supplied --> $DIR/not-enough-arguments.rs:29:3 @@ -40,7 +40,7 @@ LL | f: i32, help: provide the arguments | LL | bar(1, 2, 3, /* i32 */, /* i32 */, /* i32 */); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 2 previous errors diff --git a/src/test/ui/resolve/resolve-primitive-fallback.stderr b/src/test/ui/resolve/resolve-primitive-fallback.stderr index f0eb1a4f4873..6d5d5bad9fe1 100644 --- a/src/test/ui/resolve/resolve-primitive-fallback.stderr +++ b/src/test/ui/resolve/resolve-primitive-fallback.stderr @@ -34,7 +34,7 @@ LL | pub const fn size_of() -> usize { help: remove the extra argument | LL | std::mem::size_of(); - | ~~~~~~~~~~~~~~~~~~~ + | ~~ error: aborting due to 3 previous errors diff --git a/src/test/ui/span/issue-34264.stderr b/src/test/ui/span/issue-34264.stderr index 28a911d0c5bf..15179954adcd 100644 --- a/src/test/ui/span/issue-34264.stderr +++ b/src/test/ui/span/issue-34264.stderr @@ -64,7 +64,7 @@ LL | fn foo(Option, String) {} help: remove the extra argument | LL | foo(Some(42), 2); - | ~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~ error[E0308]: mismatched types --> $DIR/issue-34264.rs:8:13 @@ -94,7 +94,7 @@ LL | fn bar(x, y: usize) {} help: remove the extra argument | LL | bar(1, 2); - | ~~~~~~~~~ + | ~~~~~~ error: aborting due to 6 previous errors diff --git a/src/test/ui/span/missing-unit-argument.stderr b/src/test/ui/span/missing-unit-argument.stderr index d2afd277ecf7..b76a3ab307ae 100644 --- a/src/test/ui/span/missing-unit-argument.stderr +++ b/src/test/ui/span/missing-unit-argument.stderr @@ -12,7 +12,7 @@ LL | Ok(#[stable(feature = "rust1", since = "1.0.0")] T), help: provide the argument | LL | let _: Result<(), String> = Ok(()); - | ~~~~~~ + | ~~~~ error[E0061]: this function takes 2 arguments but 0 arguments were supplied --> $DIR/missing-unit-argument.rs:12:5 @@ -28,7 +28,7 @@ LL | fn foo(():(), ():()) {} help: provide the arguments | LL | foo((), ()); - | ~~~~~~~~~~~ + | ~~~~~~~~ error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/missing-unit-argument.rs:13:5 @@ -44,7 +44,7 @@ LL | fn foo(():(), ():()) {} help: provide the argument | LL | foo((), ()); - | ~~~~~~~~~~~ + | ~~~~~~~~ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/missing-unit-argument.rs:14:5 @@ -60,7 +60,7 @@ LL | fn bar(():()) {} help: provide the argument | LL | bar(()); - | ~~~~~~~ + | ~~~~ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/missing-unit-argument.rs:15:7 @@ -76,7 +76,7 @@ LL | fn baz(self, (): ()) { } help: provide the argument | LL | S.baz(()); - | ~~~~~~~ + | ~~~~ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/missing-unit-argument.rs:16:7 @@ -92,7 +92,7 @@ LL | fn generic(self, _: T) { } help: provide the argument | LL | S.generic::<()>(()); - | ~~~~~~~~~~~~~~~~~ + | ~~~~ error: aborting due to 6 previous errors diff --git a/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr b/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr index 4c952669cfaf..0a91c442d2c6 100644 --- a/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr +++ b/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr @@ -19,7 +19,7 @@ LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), help: remove the extra argument | LL | let _: Option<(i32, bool)> = Some(/* (i32, bool) */); - | ~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/args-instead-of-tuple-errors.rs:8:5 @@ -42,7 +42,7 @@ LL | fn int_bool(_: (i32, bool)) { help: remove the extra argument | LL | int_bool(/* (i32, bool) */); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~ error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied --> $DIR/args-instead-of-tuple-errors.rs:11:28 @@ -58,7 +58,7 @@ LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), help: provide the argument | LL | let _: Option<(i8,)> = Some(/* (i8,) */); - | ~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~ error[E0308]: mismatched types --> $DIR/args-instead-of-tuple-errors.rs:14:34 diff --git a/src/test/ui/suggestions/args-instead-of-tuple.stderr b/src/test/ui/suggestions/args-instead-of-tuple.stderr index 2448a5149654..20f9e5259a4e 100644 --- a/src/test/ui/suggestions/args-instead-of-tuple.stderr +++ b/src/test/ui/suggestions/args-instead-of-tuple.stderr @@ -44,7 +44,7 @@ LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), help: provide the argument | LL | let _: Option<()> = Some(()); - | ~~~~~~~~ + | ~~~~ error[E0308]: mismatched types --> $DIR/args-instead-of-tuple.rs:14:34 diff --git a/src/test/ui/tuple/wrong_argument_ice-3.stderr b/src/test/ui/tuple/wrong_argument_ice-3.stderr index 968cb75db763..f3a547fa2382 100644 --- a/src/test/ui/tuple/wrong_argument_ice-3.stderr +++ b/src/test/ui/tuple/wrong_argument_ice-3.stderr @@ -19,7 +19,7 @@ LL | pub fn push(&mut self, value: T) { help: remove the extra argument | LL | groups.push(/* (Vec, Vec) */); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/tuple/wrong_argument_ice-4.stderr b/src/test/ui/tuple/wrong_argument_ice-4.stderr index 828ae21b4808..a2686ab9440e 100644 --- a/src/test/ui/tuple/wrong_argument_ice-4.stderr +++ b/src/test/ui/tuple/wrong_argument_ice-4.stderr @@ -16,7 +16,7 @@ LL | (|| {})(|| { help: remove the extra argument | LL | (|| {})(); - | ~~~~~~~~~ + | ~~ error: aborting due to previous error diff --git a/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr b/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr index 006253f84320..eb58ee73ca21 100644 --- a/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr +++ b/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr @@ -12,7 +12,7 @@ LL | V(u8) help: provide the argument | LL | ::V(/* u8 */); - | ~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~ error[E0308]: mismatched types --> $DIR/enum-variant-priority-higher-than-other-inherent.rs:22:17 diff --git a/src/test/ui/type/type-ascription-instead-of-initializer.stderr b/src/test/ui/type/type-ascription-instead-of-initializer.stderr index fcac6c495c4b..de578ca93ed5 100644 --- a/src/test/ui/type/type-ascription-instead-of-initializer.stderr +++ b/src/test/ui/type/type-ascription-instead-of-initializer.stderr @@ -21,7 +21,7 @@ LL | pub fn with_capacity(capacity: usize) -> Self { help: remove the extra argument | LL | let x: Vec::with_capacity(10); - | ~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~ error: aborting due to 2 previous errors diff --git a/src/test/ui/typeck/remove-extra-argument.stderr b/src/test/ui/typeck/remove-extra-argument.stderr index 703032a83223..b734bcd4eb04 100644 --- a/src/test/ui/typeck/remove-extra-argument.stderr +++ b/src/test/ui/typeck/remove-extra-argument.stderr @@ -12,7 +12,7 @@ LL | fn l(_a: Vec) {} help: remove the extra argument | LL | l(vec![]) - | + | ~~~~~~~~ error: aborting due to previous error diff --git a/src/test/ui/typeck/struct-enum-wrong-args.stderr b/src/test/ui/typeck/struct-enum-wrong-args.stderr index f72082d53016..ea94bcbc2903 100644 --- a/src/test/ui/typeck/struct-enum-wrong-args.stderr +++ b/src/test/ui/typeck/struct-enum-wrong-args.stderr @@ -12,7 +12,7 @@ LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), help: remove the extra argument | LL | let _ = Some(3); - | ~~~~~~~ + | ~~~ error[E0061]: this enum variant takes 1 argument but 3 arguments were supplied --> $DIR/struct-enum-wrong-args.rs:7:13 @@ -30,7 +30,7 @@ LL | Ok(#[stable(feature = "rust1", since = "1.0.0")] T), help: remove the extra arguments | LL | let _ = Ok(3); - | ~~~~~ + | ~~~ error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied --> $DIR/struct-enum-wrong-args.rs:8:13 @@ -46,7 +46,7 @@ LL | Ok(#[stable(feature = "rust1", since = "1.0.0")] T), help: provide the argument | LL | let _ = Ok(/* value */); - | ~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~ error[E0061]: this struct takes 1 argument but 0 arguments were supplied --> $DIR/struct-enum-wrong-args.rs:9:13 @@ -62,7 +62,7 @@ LL | struct Wrapper(i32); help: provide the argument | LL | let _ = Wrapper(/* i32 */); - | ~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~ error[E0061]: this struct takes 1 argument but 2 arguments were supplied --> $DIR/struct-enum-wrong-args.rs:10:13 @@ -78,7 +78,7 @@ LL | struct Wrapper(i32); help: remove the extra argument | LL | let _ = Wrapper(5); - | ~~~~~~~~~~ + | ~~~ error[E0061]: this struct takes 2 arguments but 0 arguments were supplied --> $DIR/struct-enum-wrong-args.rs:11:13 @@ -94,7 +94,7 @@ LL | struct DoubleWrapper(i32, i32); help: provide the arguments | LL | let _ = DoubleWrapper(/* i32 */, /* i32 */); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~~~~~~~~~ error[E0061]: this struct takes 2 arguments but 1 argument was supplied --> $DIR/struct-enum-wrong-args.rs:12:13 @@ -110,7 +110,7 @@ LL | struct DoubleWrapper(i32, i32); help: provide the argument | LL | let _ = DoubleWrapper(5, /* i32 */); - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | ~~~~~~~~~~~~~~ error[E0061]: this struct takes 2 arguments but 3 arguments were supplied --> $DIR/struct-enum-wrong-args.rs:13:13 @@ -126,7 +126,7 @@ LL | struct DoubleWrapper(i32, i32); help: remove the extra argument | LL | let _ = DoubleWrapper(5, 2); - | ~~~~~~~~~~~~~~~~~~~ + | ~~~~~~ error: aborting due to 8 previous errors From 57198b549f20a63650113b11b806f535a9d35fbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 3 Sep 2022 07:58:41 +0200 Subject: [PATCH 4125/5092] remove redundant clones --- compiler/rustc_parse/src/parser/attr_wrapper.rs | 2 +- src/librustdoc/json/conversions.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index f353ee6df9bc..2e58605cf19b 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -52,7 +52,7 @@ impl AttrWrapper { // Prepend `self.attrs` to `attrs`. // FIXME: require passing an NT to prevent misuse of this method pub(crate) fn prepend_to_nt_inner(self, attrs: &mut AttrVec) { - let mut self_attrs = self.attrs.clone(); + let mut self_attrs = self.attrs; std::mem::swap(attrs, &mut self_attrs); attrs.extend(self_attrs); } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 20b9eb1c27e9..5c0c023c64e5 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -486,7 +486,7 @@ impl FromWithTcx for Type { }, QPath(box clean::QPathData { assoc, self_type, trait_, .. }) => Type::QualifiedPath { name: assoc.name.to_string(), - args: Box::new(assoc.args.clone().into_tcx(tcx)), + args: Box::new(assoc.args.into_tcx(tcx)), self_type: Box::new(self_type.into_tcx(tcx)), trait_: trait_.into_tcx(tcx), }, From 0fe54d46509abbbe54292d0ff85f8429301be002 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sat, 3 Sep 2022 07:15:08 +0100 Subject: [PATCH 4126/5092] Restore old behaviour on broken UNC paths --- library/std/src/sys/windows/path.rs | 9 +------ library/std/src/sys/windows/path/tests.rs | 29 +++++++++++++++-------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/library/std/src/sys/windows/path.rs b/library/std/src/sys/windows/path.rs index a0f822070992..beeca1917a9a 100644 --- a/library/std/src/sys/windows/path.rs +++ b/library/std/src/sys/windows/path.rs @@ -198,14 +198,7 @@ fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) { match path.bytes().iter().position(|&x| separator(x)) { Some(separator_start) => { - let mut separator_end = separator_start + 1; - - // a series of multiple separator characters is treated as a single separator, - // except in verbatim paths - while !verbatim && separator_end < path.len() && separator(path.bytes()[separator_end]) - { - separator_end += 1; - } + let separator_end = separator_start + 1; let component = &path.bytes()[..separator_start]; diff --git a/library/std/src/sys/windows/path/tests.rs b/library/std/src/sys/windows/path/tests.rs index a71175069052..623c6236166d 100644 --- a/library/std/src/sys/windows/path/tests.rs +++ b/library/std/src/sys/windows/path/tests.rs @@ -31,16 +31,6 @@ fn test_parse_next_component() { parse_next_component(OsStr::new(r"servershare"), false), (OsStr::new(r"servershare"), OsStr::new("")) ); - - assert_eq!( - parse_next_component(OsStr::new(r"server/\//\/\\\\/////\/share"), false), - (OsStr::new(r"server"), OsStr::new(r"share")) - ); - - assert_eq!( - parse_next_component(OsStr::new(r"server\\\\\\\\\\\\\\share"), true), - (OsStr::new(r"server"), OsStr::new(r"\\\\\\\\\\\\\share")) - ); } #[test] @@ -126,3 +116,22 @@ fn test_windows_prefix_components() { assert_eq!(drive.as_os_str(), OsStr::new("C:")); assert_eq!(components.as_path(), Path::new("")); } + +/// See #101358. +/// +/// Note that the exact behaviour here may change in the future. +/// In which case this test will need to adjusted. +#[test] +fn broken_unc_path() { + use crate::path::Component; + + let mut components = Path::new(r"\\foo\\bar\\").components(); + assert_eq!(components.next(), Some(Component::RootDir)); + assert_eq!(components.next(), Some(Component::Normal("foo".as_ref()))); + assert_eq!(components.next(), Some(Component::Normal("bar".as_ref()))); + + let mut components = Path::new("//foo//bar//").components(); + assert_eq!(components.next(), Some(Component::RootDir)); + assert_eq!(components.next(), Some(Component::Normal("foo".as_ref()))); + assert_eq!(components.next(), Some(Component::Normal("bar".as_ref()))); +} From 12a49523697f4a64609558b467c460b9a4b333c1 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 3 Sep 2022 07:24:55 +0000 Subject: [PATCH 4127/5092] Suggest associated method on deref types --- .../rustc_typeck/src/check/method/suggest.rs | 62 ++++++++++++++++++- src/test/ui/suggestions/deref-path-method.rs | 6 ++ .../ui/suggestions/deref-path-method.stderr | 14 +++++ 3 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/suggestions/deref-path-method.rs create mode 100644 src/test/ui/suggestions/deref-path-method.stderr diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index e99782fdc652..998405bcbe1c 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -16,8 +16,8 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi use rustc_middle::traits::util::supertraits; use rustc_middle::ty::fast_reject::{simplify_type, TreatParams}; use rustc_middle::ty::print::with_crate_prefix; -use rustc_middle::ty::ToPolyTraitRef; use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeVisitable}; +use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef}; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Symbol; use rustc_span::{lev_distance, source_map, ExpnKind, FileName, MacroKind, Span}; @@ -30,7 +30,7 @@ use rustc_trait_selection::traits::{ use std::cmp::Ordering; use std::iter; -use super::probe::{Mode, ProbeScope}; +use super::probe::{IsSuggestion, Mode, ProbeScope}; use super::{CandidateSource, MethodError, NoMatchData}; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -1069,6 +1069,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + self.check_for_deref_method(&mut err, source, rcvr_ty, item_name); + return Some(err); } @@ -1651,6 +1653,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + fn check_for_deref_method( + &self, + err: &mut Diagnostic, + self_source: SelfSource<'tcx>, + rcvr_ty: Ty<'tcx>, + item_name: Ident, + ) { + let SelfSource::QPath(ty) = self_source else { return; }; + for (deref_ty, _) in self.autoderef(rustc_span::DUMMY_SP, rcvr_ty).skip(1) { + if let Ok(pick) = self.probe_for_name( + ty.span, + Mode::Path, + item_name, + IsSuggestion(true), + deref_ty, + ty.hir_id, + ProbeScope::TraitsInScope, + ) { + if deref_ty.is_suggestable(self.tcx, true) + // If this method receives `&self`, then the provided + // argument _should_ coerce, so it's valid to suggest + // just changing the path. + && pick.item.fn_has_self_parameter + && let Some(self_ty) = + self.tcx.fn_sig(pick.item.def_id).inputs().skip_binder().get(0) + && self_ty.is_ref() + { + let suggested_path = match deref_ty.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Adt(_, _) + | ty::Str + | ty::Projection(_) + | ty::Param(_) => format!("{deref_ty}"), + _ => format!("<{deref_ty}>"), + }; + err.span_suggestion_verbose( + ty.span, + format!("the function `{item_name}` is implemented on `{deref_ty}`"), + suggested_path, + Applicability::MaybeIncorrect, + ); + } else { + err.span_note( + ty.span, + format!("the function `{item_name}` is implemented on `{deref_ty}`"), + ); + } + return; + } + } + } + /// Print out the type for use in value namespace. fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String { match ty.kind() { diff --git a/src/test/ui/suggestions/deref-path-method.rs b/src/test/ui/suggestions/deref-path-method.rs new file mode 100644 index 000000000000..0281cdb6b37c --- /dev/null +++ b/src/test/ui/suggestions/deref-path-method.rs @@ -0,0 +1,6 @@ +fn main() { + let vec = Vec::new(); + Vec::contains(&vec, &0); + //~^ ERROR no function or associated item named `contains` found for struct `Vec<_, _>` in the current scope + //~| HELP the function `contains` is implemented on `[_]` +} diff --git a/src/test/ui/suggestions/deref-path-method.stderr b/src/test/ui/suggestions/deref-path-method.stderr new file mode 100644 index 000000000000..1cc37d61151c --- /dev/null +++ b/src/test/ui/suggestions/deref-path-method.stderr @@ -0,0 +1,14 @@ +error[E0599]: no function or associated item named `contains` found for struct `Vec<_, _>` in the current scope + --> $DIR/deref-path-method.rs:3:10 + | +LL | Vec::contains(&vec, &0); + | ^^^^^^^^ function or associated item not found in `Vec<_, _>` + | +help: the function `contains` is implemented on `[_]` + | +LL | <[_]>::contains(&vec, &0); + | ~~~~~ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. From fdbede7ad85d4ccdabc5da1cdaa41fa93fac2457 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 3 Sep 2022 07:29:57 +0000 Subject: [PATCH 4128/5092] Suggest copied or cloned --- compiler/rustc_typeck/src/check/demand.rs | 1 + .../src/check/fn_ctxt/suggestions.rs | 64 ++++++++++++++ .../ui/suggestions/copied-and-cloned.fixed | 23 +++++ src/test/ui/suggestions/copied-and-cloned.rs | 23 +++++ .../ui/suggestions/copied-and-cloned.stderr | 83 +++++++++++++++++++ 5 files changed, 194 insertions(+) create mode 100644 src/test/ui/suggestions/copied-and-cloned.fixed create mode 100644 src/test/ui/suggestions/copied-and-cloned.rs create mode 100644 src/test/ui/suggestions/copied-and-cloned.stderr diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index b9054898a2e5..4a3d69f5b6c6 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -42,6 +42,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty); self.suggest_missing_parentheses(err, expr); self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected); + self.suggest_copied_or_cloned(err, expr, expr_ty, expected); self.note_type_is_not_clone(err, expected, expr_ty, expr); self.note_need_for_fn_pointer(err, expected, expr_ty); self.note_internal_mutation_in_method(err, expr, expected, expr_ty); diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index 939f4612d44e..d8527b9267e5 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -17,6 +17,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Binder, IsSuggestable, Subst, ToPredicate, Ty}; use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -925,6 +926,69 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + pub(crate) fn suggest_copied_or_cloned( + &self, + diag: &mut Diagnostic, + expr: &hir::Expr<'_>, + expr_ty: Ty<'tcx>, + expected_ty: Ty<'tcx>, + ) { + let ty::Adt(adt_def, substs) = expr_ty.kind() else { return; }; + let ty::Adt(expected_adt_def, expected_substs) = expected_ty.kind() else { return; }; + if adt_def != expected_adt_def { + return; + } + + let mut suggest_copied_or_cloned = || { + let expr_inner_ty = substs.type_at(0); + let expected_inner_ty = expected_substs.type_at(0); + if let ty::Ref(_, ty, hir::Mutability::Not) = expr_inner_ty.kind() + && self.can_eq(self.param_env, *ty, expected_inner_ty).is_ok() + { + let def_path = self.tcx.def_path_str(adt_def.did()); + if self.type_is_copy_modulo_regions(self.param_env, *ty, expr.span) { + diag.span_suggestion_verbose( + expr.span.shrink_to_hi(), + format!( + "use `{def_path}::copied` to copy the value inside the `{def_path}`" + ), + ".copied()", + Applicability::MachineApplicable, + ); + } else if let Some(clone_did) = self.tcx.lang_items().clone_trait() + && rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions( + self, + self.param_env, + *ty, + clone_did, + expr.span + ) + { + diag.span_suggestion_verbose( + expr.span.shrink_to_hi(), + format!( + "use `{def_path}::cloned` to clone the value inside the `{def_path}`" + ), + ".cloned()", + Applicability::MachineApplicable, + ); + } + } + }; + + if let Some(result_did) = self.tcx.get_diagnostic_item(sym::Result) + && adt_def.did() == result_did + // Check that the error types are equal + && self.can_eq(self.param_env, substs.type_at(1), expected_substs.type_at(1)).is_ok() + { + suggest_copied_or_cloned(); + } else if let Some(option_did) = self.tcx.get_diagnostic_item(sym::Option) + && adt_def.did() == option_did + { + suggest_copied_or_cloned(); + } + } + /// Suggest wrapping the block in square brackets instead of curly braces /// in case the block was mistaken array syntax, e.g. `{ 1 }` -> `[ 1 ]`. pub(crate) fn suggest_block_to_brackets( diff --git a/src/test/ui/suggestions/copied-and-cloned.fixed b/src/test/ui/suggestions/copied-and-cloned.fixed new file mode 100644 index 000000000000..f801403feec4 --- /dev/null +++ b/src/test/ui/suggestions/copied-and-cloned.fixed @@ -0,0 +1,23 @@ +// run-rustfix + +fn expect(_: T) {} + +fn main() { + let x = Some(&()); + expect::>(x.copied()); + //~^ ERROR mismatched types + //~| HELP use `Option::copied` to copy the value inside the `Option` + let x = Ok(&()); + expect::>(x.copied()); + //~^ ERROR mismatched types + //~| HELP use `Result::copied` to copy the value inside the `Result` + let s = String::new(); + let x = Some(&s); + expect::>(x.cloned()); + //~^ ERROR mismatched types + //~| HELP use `Option::cloned` to clone the value inside the `Option` + let x = Ok(&s); + expect::>(x.cloned()); + //~^ ERROR mismatched types + //~| HELP use `Result::cloned` to clone the value inside the `Result` +} diff --git a/src/test/ui/suggestions/copied-and-cloned.rs b/src/test/ui/suggestions/copied-and-cloned.rs new file mode 100644 index 000000000000..640450b76552 --- /dev/null +++ b/src/test/ui/suggestions/copied-and-cloned.rs @@ -0,0 +1,23 @@ +// run-rustfix + +fn expect(_: T) {} + +fn main() { + let x = Some(&()); + expect::>(x); + //~^ ERROR mismatched types + //~| HELP use `Option::copied` to copy the value inside the `Option` + let x = Ok(&()); + expect::>(x); + //~^ ERROR mismatched types + //~| HELP use `Result::copied` to copy the value inside the `Result` + let s = String::new(); + let x = Some(&s); + expect::>(x); + //~^ ERROR mismatched types + //~| HELP use `Option::cloned` to clone the value inside the `Option` + let x = Ok(&s); + expect::>(x); + //~^ ERROR mismatched types + //~| HELP use `Result::cloned` to clone the value inside the `Result` +} diff --git a/src/test/ui/suggestions/copied-and-cloned.stderr b/src/test/ui/suggestions/copied-and-cloned.stderr new file mode 100644 index 000000000000..a6336281b407 --- /dev/null +++ b/src/test/ui/suggestions/copied-and-cloned.stderr @@ -0,0 +1,83 @@ +error[E0308]: mismatched types + --> $DIR/copied-and-cloned.rs:7:26 + | +LL | expect::>(x); + | -------------------- ^ expected `()`, found `&()` + | | + | arguments to this function are incorrect + | + = note: expected enum `Option<()>` + found enum `Option<&()>` +note: function defined here + --> $DIR/copied-and-cloned.rs:3:4 + | +LL | fn expect(_: T) {} + | ^^^^^^ ---- +help: use `Option::copied` to copy the value inside the `Option` + | +LL | expect::>(x.copied()); + | +++++++++ + +error[E0308]: mismatched types + --> $DIR/copied-and-cloned.rs:11:30 + | +LL | expect::>(x); + | ------------------------ ^ expected `()`, found `&()` + | | + | arguments to this function are incorrect + | + = note: expected enum `Result<(), ()>` + found enum `Result<&(), _>` +note: function defined here + --> $DIR/copied-and-cloned.rs:3:4 + | +LL | fn expect(_: T) {} + | ^^^^^^ ---- +help: use `Result::copied` to copy the value inside the `Result` + | +LL | expect::>(x.copied()); + | +++++++++ + +error[E0308]: mismatched types + --> $DIR/copied-and-cloned.rs:16:30 + | +LL | expect::>(x); + | ------------------------ ^ expected struct `String`, found `&String` + | | + | arguments to this function are incorrect + | + = note: expected enum `Option` + found enum `Option<&String>` +note: function defined here + --> $DIR/copied-and-cloned.rs:3:4 + | +LL | fn expect(_: T) {} + | ^^^^^^ ---- +help: use `Option::cloned` to clone the value inside the `Option` + | +LL | expect::>(x.cloned()); + | +++++++++ + +error[E0308]: mismatched types + --> $DIR/copied-and-cloned.rs:20:34 + | +LL | expect::>(x); + | ---------------------------- ^ expected struct `String`, found `&String` + | | + | arguments to this function are incorrect + | + = note: expected enum `Result` + found enum `Result<&String, _>` +note: function defined here + --> $DIR/copied-and-cloned.rs:3:4 + | +LL | fn expect(_: T) {} + | ^^^^^^ ---- +help: use `Result::cloned` to clone the value inside the `Result` + | +LL | expect::>(x.cloned()); + | +++++++++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. From e9b01c745d52e5bb05ee2e8c184c188b92a349fb Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 3 Sep 2022 08:05:48 +0000 Subject: [PATCH 4129/5092] Fix global_asm macro pretty printing --- compiler/rustc_ast_pretty/src/pprust/state/item.rs | 2 ++ src/test/ui/asm/unpretty-expanded.rs | 3 +++ src/test/ui/asm/unpretty-expanded.stdout | 9 +++++++++ 3 files changed, 14 insertions(+) create mode 100644 src/test/ui/asm/unpretty-expanded.rs create mode 100644 src/test/ui/asm/unpretty-expanded.stdout diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index bd87987010e8..54bac29a6cee 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -218,6 +218,8 @@ impl<'a> State<'a> { ast::ItemKind::GlobalAsm(ref asm) => { self.head(visibility_qualified(&item.vis, "global_asm!")); self.print_inline_asm(asm); + self.word(";"); + self.end(); self.end(); } ast::ItemKind::TyAlias(box ast::TyAlias { diff --git a/src/test/ui/asm/unpretty-expanded.rs b/src/test/ui/asm/unpretty-expanded.rs new file mode 100644 index 000000000000..6128f49b89a3 --- /dev/null +++ b/src/test/ui/asm/unpretty-expanded.rs @@ -0,0 +1,3 @@ +// check-pass +// compile-flags: -Zunpretty=expanded +core::arch::global_asm!("x: .byte 42"); diff --git a/src/test/ui/asm/unpretty-expanded.stdout b/src/test/ui/asm/unpretty-expanded.stdout new file mode 100644 index 000000000000..15b60d1559c6 --- /dev/null +++ b/src/test/ui/asm/unpretty-expanded.stdout @@ -0,0 +1,9 @@ +#![feature(prelude_import)] +#![no_std] +#[prelude_import] +use ::std::prelude::rust_2015::*; +#[macro_use] +extern crate std; +// check-pass +// compile-flags: -Zunpretty=expanded +global_asm! ("x: .byte 42"); From be53bd838097a835ae7486d8994d721225782bf4 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 3 Sep 2022 03:01:35 +0000 Subject: [PATCH 4130/5092] Include enum path in variant suggestion --- compiler/rustc_middle/src/thir.rs | 38 +++++++++++++----- .../src/thir/pattern/usefulness.rs | 2 +- .../match/non-exhaustive-match.rs | 2 +- .../match/non-exhaustive-match.stderr | 8 ++-- src/test/ui/empty/empty-never-array.rs | 2 +- src/test/ui/empty/empty-never-array.stderr | 4 +- src/test/ui/error-codes/E0004.stderr | 6 +-- ...te-non_exhaustive_omitted_patterns_lint.rs | 2 +- ...on_exhaustive_omitted_patterns_lint.stderr | 6 +-- src/test/ui/issue-94866.stderr | 6 +-- src/test/ui/match/match_non_exhaustive.rs | 2 +- src/test/ui/match/match_non_exhaustive.stderr | 8 ++-- .../usefulness/doc-hidden-non-exhaustive.rs | 8 ++-- .../doc-hidden-non-exhaustive.stderr | 24 +++++------ .../empty-match.exhaustive_patterns.stderr | 28 ++++++------- .../usefulness/empty-match.normal.stderr | 28 ++++++------- src/test/ui/pattern/usefulness/empty-match.rs | 12 +++--- src/test/ui/pattern/usefulness/issue-15129.rs | 2 +- .../ui/pattern/usefulness/issue-15129.stderr | 6 +-- src/test/ui/pattern/usefulness/issue-31561.rs | 2 +- .../ui/pattern/usefulness/issue-31561.stderr | 4 +- .../ui/pattern/usefulness/issue-35609.stderr | 32 +++++++-------- .../ui/pattern/usefulness/issue-39362.stderr | 4 +- .../ui/pattern/usefulness/issue-40221.stderr | 6 +-- src/test/ui/pattern/usefulness/issue-50900.rs | 2 +- .../ui/pattern/usefulness/issue-50900.stderr | 6 +-- src/test/ui/pattern/usefulness/issue-56379.rs | 2 +- .../ui/pattern/usefulness/issue-56379.stderr | 6 +-- src/test/ui/pattern/usefulness/issue-72377.rs | 2 +- .../ui/pattern/usefulness/issue-72377.stderr | 4 +- .../pattern/usefulness/match-arm-statics-2.rs | 4 +- .../usefulness/match-arm-statics-2.stderr | 12 +++--- .../usefulness/non-exhaustive-defined-here.rs | 32 +++++++-------- .../non-exhaustive-defined-here.stderr | 40 +++++++++---------- .../usefulness/non-exhaustive-match-nested.rs | 2 +- .../non-exhaustive-match-nested.stderr | 6 +-- .../usefulness/non-exhaustive-match.rs | 6 +-- .../usefulness/non-exhaustive-match.stderr | 20 +++++----- .../non-exhaustive-pattern-witness.rs | 10 ++--- .../non-exhaustive-pattern-witness.stderr | 28 ++++++------- .../usefulness/stable-gated-patterns.rs | 2 +- .../usefulness/stable-gated-patterns.stderr | 6 +-- .../struct-like-enum-nonexhaustive.stderr | 6 +-- .../usefulness/unstable-gated-patterns.rs | 2 +- .../usefulness/unstable-gated-patterns.stderr | 6 +-- .../enum_same_crate_empty_match.rs | 4 +- .../enum_same_crate_empty_match.stderr | 12 +++--- .../omitted-patterns.stderr | 16 ++++---- .../stable-omitted-patterns.stderr | 2 +- .../uninhabited/match.stderr | 6 +-- .../uninhabited/match_same_crate.stderr | 6 +-- .../match_with_exhaustive_patterns.stderr | 6 +-- .../ui/uninhabited/uninhabited-irrefutable.rs | 2 +- .../uninhabited-irrefutable.stderr | 4 +- 54 files changed, 260 insertions(+), 244 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 59e14337f4ed..7e543929b0f3 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -23,7 +23,7 @@ use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, AdtDef, Ty, UpvarSubsts}; use rustc_middle::ty::{CanonicalUserType, CanonicalUserTypeAnnotation}; use rustc_span::def_id::LocalDefId; -use rustc_span::{Span, Symbol, DUMMY_SP}; +use rustc_span::{sym, Span, Symbol, DUMMY_SP}; use rustc_target::abi::VariantIdx; use rustc_target::asm::InlineAsmRegOrRegClass; use std::fmt; @@ -695,17 +695,32 @@ impl<'tcx> fmt::Display for Pat<'tcx> { Ok(()) } PatKind::Variant { ref subpatterns, .. } | PatKind::Leaf { ref subpatterns } => { - let variant = match self.kind { - PatKind::Variant { adt_def, variant_index, .. } => { - Some(adt_def.variant(variant_index)) - } - _ => self.ty.ty_adt_def().and_then(|adt| { - if !adt.is_enum() { Some(adt.non_enum_variant()) } else { None } + let variant_and_name = match self.kind { + PatKind::Variant { adt_def, variant_index, .. } => ty::tls::with(|tcx| { + let variant = adt_def.variant(variant_index); + let adt_did = adt_def.did(); + let name = if tcx.get_diagnostic_item(sym::Option) == Some(adt_did) + || tcx.get_diagnostic_item(sym::Result) == Some(adt_did) + { + variant.name.to_string() + } else { + format!("{}::{}", tcx.def_path_str(adt_def.did()), variant.name) + }; + Some((variant, name)) + }), + _ => self.ty.ty_adt_def().and_then(|adt_def| { + if !adt_def.is_enum() { + ty::tls::with(|tcx| { + Some((adt_def.non_enum_variant(), tcx.def_path_str(adt_def.did()))) + }) + } else { + None + } }), }; - if let Some(variant) = variant { - write!(f, "{}", variant.name)?; + if let Some((variant, name)) = &variant_and_name { + write!(f, "{}", name)?; // Only for Adt we can have `S {...}`, // which we handle separately here. @@ -730,8 +745,9 @@ impl<'tcx> fmt::Display for Pat<'tcx> { } } - let num_fields = variant.map_or(subpatterns.len(), |v| v.fields.len()); - if num_fields != 0 || variant.is_none() { + let num_fields = + variant_and_name.as_ref().map_or(subpatterns.len(), |(v, _)| v.fields.len()); + if num_fields != 0 || variant_and_name.is_none() { write!(f, "(")?; for i in 0..num_fields { write!(f, "{}", start_or_comma())?; diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 319183eb9b33..115d34ff8fa2 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -754,8 +754,8 @@ fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>( hir_id: HirId, witnesses: Vec>, ) { - let joined_patterns = joined_uncovered_patterns(cx, &witnesses); cx.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, hir_id, sp, |build| { + let joined_patterns = joined_uncovered_patterns(cx, &witnesses); let mut lint = build.build("some variants are not matched explicitly"); lint.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns)); lint.help( diff --git a/src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.rs b/src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.rs index 318673ef847e..972c24c23b01 100644 --- a/src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.rs +++ b/src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.rs @@ -24,7 +24,7 @@ fn main() { let _a = || { match l1 { L1::A => (), L1::B => () } }; // (except if the match is already non-exhaustive) let _b = || { match l1 { L1::A => () } }; - //~^ ERROR: non-exhaustive patterns: `B` not covered [E0004] + //~^ ERROR: non-exhaustive patterns: `L1::B` not covered [E0004] // l2 should not be captured as it is a non-exhaustive SingleVariant // defined in this crate diff --git a/src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr b/src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr index e0678bc718fa..3a5fad15421c 100644 --- a/src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr +++ b/src/test/ui/closures/2229_closure_analysis/match/non-exhaustive-match.stderr @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: `B` not covered +error[E0004]: non-exhaustive patterns: `L1::B` not covered --> $DIR/non-exhaustive-match.rs:26:25 | LL | let _b = || { match l1 { L1::A => () } }; - | ^^ pattern `B` not covered + | ^^ pattern `L1::B` not covered | note: `L1` defined here --> $DIR/non-exhaustive-match.rs:12:14 @@ -12,8 +12,8 @@ LL | enum L1 { A, B } = note: the matched value is of type `L1` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL | let _b = || { match l1 { L1::A => (), B => todo!() } }; - | ++++++++++++++ +LL | let _b = || { match l1 { L1::A => (), L1::B => todo!() } }; + | ++++++++++++++++++ error[E0004]: non-exhaustive patterns: type `E1` is non-empty --> $DIR/non-exhaustive-match.rs:37:25 diff --git a/src/test/ui/empty/empty-never-array.rs b/src/test/ui/empty/empty-never-array.rs index 01b99134a445..3de2b1a78a3d 100644 --- a/src/test/ui/empty/empty-never-array.rs +++ b/src/test/ui/empty/empty-never-array.rs @@ -8,7 +8,7 @@ enum Helper { fn transmute(t: T) -> U { let Helper::U(u) = Helper::T(t, []); - //~^ ERROR refutable pattern in local binding: `T(_, _)` not covered + //~^ ERROR refutable pattern in local binding: `Helper::T(_, _)` not covered u } diff --git a/src/test/ui/empty/empty-never-array.stderr b/src/test/ui/empty/empty-never-array.stderr index 909aa73a74a3..8c80b05ee3ae 100644 --- a/src/test/ui/empty/empty-never-array.stderr +++ b/src/test/ui/empty/empty-never-array.stderr @@ -1,8 +1,8 @@ -error[E0005]: refutable pattern in local binding: `T(_, _)` not covered +error[E0005]: refutable pattern in local binding: `Helper::T(_, _)` not covered --> $DIR/empty-never-array.rs:10:9 | LL | let Helper::U(u) = Helper::T(t, []); - | ^^^^^^^^^^^^ pattern `T(_, _)` not covered + | ^^^^^^^^^^^^ pattern `Helper::T(_, _)` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html diff --git a/src/test/ui/error-codes/E0004.stderr b/src/test/ui/error-codes/E0004.stderr index 8ba151d9e65f..4ac8c904f053 100644 --- a/src/test/ui/error-codes/E0004.stderr +++ b/src/test/ui/error-codes/E0004.stderr @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: `HastaLaVistaBaby` not covered +error[E0004]: non-exhaustive patterns: `Terminator::HastaLaVistaBaby` not covered --> $DIR/E0004.rs:9:11 | LL | match x { - | ^ pattern `HastaLaVistaBaby` not covered + | ^ pattern `Terminator::HastaLaVistaBaby` not covered | note: `Terminator` defined here --> $DIR/E0004.rs:2:5 @@ -15,7 +15,7 @@ LL | HastaLaVistaBaby, help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ Terminator::TalkToMyHand => {} -LL + HastaLaVistaBaby => todo!() +LL + Terminator::HastaLaVistaBaby => todo!() | error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs b/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs index 29a6e1f8a016..9b646060adfd 100644 --- a/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs +++ b/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs @@ -21,7 +21,7 @@ fn main() { Foo::A => {} Foo::B => {} } - //~^^^^ ERROR non-exhaustive patterns: `C` not covered + //~^^^^ ERROR non-exhaustive patterns: `Foo::C` not covered match Foo::A { Foo::A => {} diff --git a/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr b/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr index dbeef6c2d2ae..3de08e215dad 100644 --- a/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr +++ b/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr @@ -99,11 +99,11 @@ LL | #[warn(non_exhaustive_omitted_patterns)] = note: see issue #89554 for more information = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable -error[E0004]: non-exhaustive patterns: `C` not covered +error[E0004]: non-exhaustive patterns: `Foo::C` not covered --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:20:11 | LL | match Foo::A { - | ^^^^^^ pattern `C` not covered + | ^^^^^^ pattern `Foo::C` not covered | note: `Foo` defined here --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:12:15 @@ -116,7 +116,7 @@ LL | A, B, C, help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ Foo::B => {} -LL + C => todo!() +LL + Foo::C => todo!() | error: aborting due to previous error; 10 warnings emitted diff --git a/src/test/ui/issue-94866.stderr b/src/test/ui/issue-94866.stderr index 5477d83f4492..b3c17ce8974d 100644 --- a/src/test/ui/issue-94866.stderr +++ b/src/test/ui/issue-94866.stderr @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: `B` not covered +error[E0004]: non-exhaustive patterns: `Enum::B` not covered --> $DIR/issue-94866.rs:10:11 | LL | match Enum::A { - | ^^^^^^^ pattern `B` not covered + | ^^^^^^^ pattern `Enum::B` not covered | note: `Enum` defined here --> $DIR/issue-94866.rs:7:16 @@ -13,7 +13,7 @@ LL | enum Enum { A, B } help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ Enum::A => m!(), -LL + B => todo!() +LL + Enum::B => todo!() | error: aborting due to previous error diff --git a/src/test/ui/match/match_non_exhaustive.rs b/src/test/ui/match/match_non_exhaustive.rs index 8219f0eb1357..f162dd60f503 100644 --- a/src/test/ui/match/match_non_exhaustive.rs +++ b/src/test/ui/match/match_non_exhaustive.rs @@ -21,7 +21,7 @@ fn main() { match l { L::A => (), L::B => () }; // (except if the match is already non-exhaustive) match l { L::A => () }; - //~^ ERROR: non-exhaustive patterns: `B` not covered [E0004] + //~^ ERROR: non-exhaustive patterns: `L::B` not covered [E0004] // E1 is not visibly uninhabited from here let (e1, e2) = bar(); diff --git a/src/test/ui/match/match_non_exhaustive.stderr b/src/test/ui/match/match_non_exhaustive.stderr index 9d92f8fdbb4b..46ee8d5179e6 100644 --- a/src/test/ui/match/match_non_exhaustive.stderr +++ b/src/test/ui/match/match_non_exhaustive.stderr @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: `B` not covered +error[E0004]: non-exhaustive patterns: `L::B` not covered --> $DIR/match_non_exhaustive.rs:23:11 | LL | match l { L::A => () }; - | ^ pattern `B` not covered + | ^ pattern `L::B` not covered | note: `L` defined here --> $DIR/match_non_exhaustive.rs:10:13 @@ -12,8 +12,8 @@ LL | enum L { A, B } = note: the matched value is of type `L` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL | match l { L::A => (), B => todo!() }; - | ++++++++++++++ +LL | match l { L::A => (), L::B => todo!() }; + | +++++++++++++++++ error[E0004]: non-exhaustive patterns: type `E1` is non-empty --> $DIR/match_non_exhaustive.rs:28:11 diff --git a/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs b/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs index d968c48fb1ab..5d4181a30f05 100644 --- a/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs +++ b/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs @@ -22,22 +22,22 @@ fn main() { HiddenEnum::A => {} HiddenEnum::C => {} } - //~^^^^ non-exhaustive patterns: `B` not covered + //~^^^^ non-exhaustive patterns: `HiddenEnum::B` not covered match HiddenEnum::A { HiddenEnum::A => {} } - //~^^^ non-exhaustive patterns: `B` and `_` not covered + //~^^^ non-exhaustive patterns: `HiddenEnum::B` and `_` not covered match None { None => {} Some(HiddenEnum::A) => {} } - //~^^^^ non-exhaustive patterns: `Some(B)` and `Some(_)` not covered + //~^^^^ non-exhaustive patterns: `Some(HiddenEnum::B)` and `Some(_)` not covered match InCrate::A { InCrate::A => {} InCrate::B => {} } - //~^^^^ non-exhaustive patterns: `C` not covered + //~^^^^ non-exhaustive patterns: `InCrate::C` not covered } diff --git a/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr b/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr index 643e734f9d4f..b450a9aeddf8 100644 --- a/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr +++ b/src/test/ui/pattern/usefulness/doc-hidden-non-exhaustive.stderr @@ -16,11 +16,11 @@ LL ~ HiddenEnum::B => {} LL + _ => todo!() | -error[E0004]: non-exhaustive patterns: `B` not covered +error[E0004]: non-exhaustive patterns: `HiddenEnum::B` not covered --> $DIR/doc-hidden-non-exhaustive.rs:21:11 | LL | match HiddenEnum::A { - | ^^^^^^^^^^^^^ pattern `B` not covered + | ^^^^^^^^^^^^^ pattern `HiddenEnum::B` not covered | note: `HiddenEnum` defined here --> $DIR/auxiliary/hidden.rs:3:5 @@ -34,14 +34,14 @@ LL | B, help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ HiddenEnum::C => {} -LL + B => todo!() +LL + HiddenEnum::B => todo!() | -error[E0004]: non-exhaustive patterns: `B` and `_` not covered +error[E0004]: non-exhaustive patterns: `HiddenEnum::B` and `_` not covered --> $DIR/doc-hidden-non-exhaustive.rs:27:11 | LL | match HiddenEnum::A { - | ^^^^^^^^^^^^^ patterns `B` and `_` not covered + | ^^^^^^^^^^^^^ patterns `HiddenEnum::B` and `_` not covered | note: `HiddenEnum` defined here --> $DIR/auxiliary/hidden.rs:3:5 @@ -55,14 +55,14 @@ LL | B, help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ HiddenEnum::A => {} -LL + B | _ => todo!() +LL + HiddenEnum::B | _ => todo!() | -error[E0004]: non-exhaustive patterns: `Some(B)` and `Some(_)` not covered +error[E0004]: non-exhaustive patterns: `Some(HiddenEnum::B)` and `Some(_)` not covered --> $DIR/doc-hidden-non-exhaustive.rs:32:11 | LL | match None { - | ^^^^ patterns `Some(B)` and `Some(_)` not covered + | ^^^^ patterns `Some(HiddenEnum::B)` and `Some(_)` not covered | note: `Option` defined here --> $SRC_DIR/core/src/option.rs:LL:COL @@ -76,14 +76,14 @@ LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ Some(HiddenEnum::A) => {} -LL + Some(B) | Some(_) => todo!() +LL + Some(HiddenEnum::B) | Some(_) => todo!() | -error[E0004]: non-exhaustive patterns: `C` not covered +error[E0004]: non-exhaustive patterns: `InCrate::C` not covered --> $DIR/doc-hidden-non-exhaustive.rs:38:11 | LL | match InCrate::A { - | ^^^^^^^^^^ pattern `C` not covered + | ^^^^^^^^^^ pattern `InCrate::C` not covered | note: `InCrate` defined here --> $DIR/doc-hidden-non-exhaustive.rs:11:5 @@ -97,7 +97,7 @@ LL | C, help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ InCrate::B => {} -LL + C => todo!() +LL + InCrate::C => todo!() | error: aborting due to 5 previous errors diff --git a/src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr b/src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr index d31ee0dbd14e..5e12bc1d22f0 100644 --- a/src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr +++ b/src/test/ui/pattern/usefulness/empty-match.exhaustive_patterns.stderr @@ -105,11 +105,11 @@ LL | union NonEmptyUnion2 { = note: the matched value is of type `NonEmptyUnion2` = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern -error[E0004]: non-exhaustive patterns: `Foo(_)` not covered +error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered --> $DIR/empty-match.rs:83:20 | LL | match_no_arms!(NonEmptyEnum1::Foo(true)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered + | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered | note: `NonEmptyEnum1` defined here --> $DIR/empty-match.rs:24:5 @@ -121,11 +121,11 @@ LL | Foo(bool), = note: the matched value is of type `NonEmptyEnum1` = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern -error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered +error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered --> $DIR/empty-match.rs:84:20 | LL | match_no_arms!(NonEmptyEnum2::Foo(true)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered + | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered | note: `NonEmptyEnum2` defined here --> $DIR/empty-match.rs:27:5 @@ -139,11 +139,11 @@ LL | Bar, = note: the matched value is of type `NonEmptyEnum2` = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms -error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered +error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered --> $DIR/empty-match.rs:85:20 | LL | match_no_arms!(NonEmptyEnum5::V1); - | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered + | ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered | note: `NonEmptyEnum5` defined here --> $DIR/empty-match.rs:30:6 @@ -238,11 +238,11 @@ LL ~ _ if false => {} LL + NonEmptyUnion2 { .. } => todo!() | -error[E0004]: non-exhaustive patterns: `Foo(_)` not covered +error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered --> $DIR/empty-match.rs:92:24 | LL | match_guarded_arm!(NonEmptyEnum1::Foo(true)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered + | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered | note: `NonEmptyEnum1` defined here --> $DIR/empty-match.rs:24:5 @@ -255,14 +255,14 @@ LL | Foo(bool), help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ _ if false => {} -LL + Foo(_) => todo!() +LL + NonEmptyEnum1::Foo(_) => todo!() | -error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered +error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered --> $DIR/empty-match.rs:93:24 | LL | match_guarded_arm!(NonEmptyEnum2::Foo(true)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered + | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered | note: `NonEmptyEnum2` defined here --> $DIR/empty-match.rs:27:5 @@ -277,14 +277,14 @@ LL | Bar, help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ _ if false => {} -LL + Foo(_) | Bar => todo!() +LL + NonEmptyEnum2::Foo(_) | NonEmptyEnum2::Bar => todo!() | -error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered +error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered --> $DIR/empty-match.rs:94:24 | LL | match_guarded_arm!(NonEmptyEnum5::V1); - | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered + | ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered | note: `NonEmptyEnum5` defined here --> $DIR/empty-match.rs:30:6 diff --git a/src/test/ui/pattern/usefulness/empty-match.normal.stderr b/src/test/ui/pattern/usefulness/empty-match.normal.stderr index d31ee0dbd14e..5e12bc1d22f0 100644 --- a/src/test/ui/pattern/usefulness/empty-match.normal.stderr +++ b/src/test/ui/pattern/usefulness/empty-match.normal.stderr @@ -105,11 +105,11 @@ LL | union NonEmptyUnion2 { = note: the matched value is of type `NonEmptyUnion2` = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern -error[E0004]: non-exhaustive patterns: `Foo(_)` not covered +error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered --> $DIR/empty-match.rs:83:20 | LL | match_no_arms!(NonEmptyEnum1::Foo(true)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered + | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered | note: `NonEmptyEnum1` defined here --> $DIR/empty-match.rs:24:5 @@ -121,11 +121,11 @@ LL | Foo(bool), = note: the matched value is of type `NonEmptyEnum1` = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern -error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered +error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered --> $DIR/empty-match.rs:84:20 | LL | match_no_arms!(NonEmptyEnum2::Foo(true)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered + | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered | note: `NonEmptyEnum2` defined here --> $DIR/empty-match.rs:27:5 @@ -139,11 +139,11 @@ LL | Bar, = note: the matched value is of type `NonEmptyEnum2` = help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or multiple match arms -error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered +error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered --> $DIR/empty-match.rs:85:20 | LL | match_no_arms!(NonEmptyEnum5::V1); - | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered + | ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered | note: `NonEmptyEnum5` defined here --> $DIR/empty-match.rs:30:6 @@ -238,11 +238,11 @@ LL ~ _ if false => {} LL + NonEmptyUnion2 { .. } => todo!() | -error[E0004]: non-exhaustive patterns: `Foo(_)` not covered +error[E0004]: non-exhaustive patterns: `NonEmptyEnum1::Foo(_)` not covered --> $DIR/empty-match.rs:92:24 | LL | match_guarded_arm!(NonEmptyEnum1::Foo(true)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo(_)` not covered + | ^^^^^^^^^^^^^^^^^^^^^^^^ pattern `NonEmptyEnum1::Foo(_)` not covered | note: `NonEmptyEnum1` defined here --> $DIR/empty-match.rs:24:5 @@ -255,14 +255,14 @@ LL | Foo(bool), help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ _ if false => {} -LL + Foo(_) => todo!() +LL + NonEmptyEnum1::Foo(_) => todo!() | -error[E0004]: non-exhaustive patterns: `Foo(_)` and `Bar` not covered +error[E0004]: non-exhaustive patterns: `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered --> $DIR/empty-match.rs:93:24 | LL | match_guarded_arm!(NonEmptyEnum2::Foo(true)); - | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `Foo(_)` and `Bar` not covered + | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered | note: `NonEmptyEnum2` defined here --> $DIR/empty-match.rs:27:5 @@ -277,14 +277,14 @@ LL | Bar, help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ _ if false => {} -LL + Foo(_) | Bar => todo!() +LL + NonEmptyEnum2::Foo(_) | NonEmptyEnum2::Bar => todo!() | -error[E0004]: non-exhaustive patterns: `V1`, `V2`, `V3` and 2 more not covered +error[E0004]: non-exhaustive patterns: `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered --> $DIR/empty-match.rs:94:24 | LL | match_guarded_arm!(NonEmptyEnum5::V1); - | ^^^^^^^^^^^^^^^^^ patterns `V1`, `V2`, `V3` and 2 more not covered + | ^^^^^^^^^^^^^^^^^ patterns `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered | note: `NonEmptyEnum5` defined here --> $DIR/empty-match.rs:30:6 diff --git a/src/test/ui/pattern/usefulness/empty-match.rs b/src/test/ui/pattern/usefulness/empty-match.rs index 8110ec013d7c..9cdc0413ba10 100644 --- a/src/test/ui/pattern/usefulness/empty-match.rs +++ b/src/test/ui/pattern/usefulness/empty-match.rs @@ -80,16 +80,16 @@ fn main() { match_no_arms!(NonEmptyStruct2(true)); //~ ERROR type `NonEmptyStruct2` is non-empty match_no_arms!((NonEmptyUnion1 { foo: () })); //~ ERROR type `NonEmptyUnion1` is non-empty match_no_arms!((NonEmptyUnion2 { foo: () })); //~ ERROR type `NonEmptyUnion2` is non-empty - match_no_arms!(NonEmptyEnum1::Foo(true)); //~ ERROR `Foo(_)` not covered - match_no_arms!(NonEmptyEnum2::Foo(true)); //~ ERROR `Foo(_)` and `Bar` not covered - match_no_arms!(NonEmptyEnum5::V1); //~ ERROR `V1`, `V2`, `V3` and 2 more not covered + match_no_arms!(NonEmptyEnum1::Foo(true)); //~ ERROR `NonEmptyEnum1::Foo(_)` not covered + match_no_arms!(NonEmptyEnum2::Foo(true)); //~ ERROR `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered + match_no_arms!(NonEmptyEnum5::V1); //~ ERROR `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered match_guarded_arm!(0u8); //~ ERROR `_` not covered match_guarded_arm!(NonEmptyStruct1); //~ ERROR `NonEmptyStruct1` not covered match_guarded_arm!(NonEmptyStruct2(true)); //~ ERROR `NonEmptyStruct2(_)` not covered match_guarded_arm!((NonEmptyUnion1 { foo: () })); //~ ERROR `NonEmptyUnion1 { .. }` not covered match_guarded_arm!((NonEmptyUnion2 { foo: () })); //~ ERROR `NonEmptyUnion2 { .. }` not covered - match_guarded_arm!(NonEmptyEnum1::Foo(true)); //~ ERROR `Foo(_)` not covered - match_guarded_arm!(NonEmptyEnum2::Foo(true)); //~ ERROR `Foo(_)` and `Bar` not covered - match_guarded_arm!(NonEmptyEnum5::V1); //~ ERROR `V1`, `V2`, `V3` and 2 more not covered + match_guarded_arm!(NonEmptyEnum1::Foo(true)); //~ ERROR `NonEmptyEnum1::Foo(_)` not covered + match_guarded_arm!(NonEmptyEnum2::Foo(true)); //~ ERROR `NonEmptyEnum2::Foo(_)` and `NonEmptyEnum2::Bar` not covered + match_guarded_arm!(NonEmptyEnum5::V1); //~ ERROR `NonEmptyEnum5::V1`, `NonEmptyEnum5::V2`, `NonEmptyEnum5::V3` and 2 more not covered } diff --git a/src/test/ui/pattern/usefulness/issue-15129.rs b/src/test/ui/pattern/usefulness/issue-15129.rs index d2b72a86b74c..f02e5c0c6f8a 100644 --- a/src/test/ui/pattern/usefulness/issue-15129.rs +++ b/src/test/ui/pattern/usefulness/issue-15129.rs @@ -10,7 +10,7 @@ pub enum V { fn main() { match (T::T1(()), V::V2(true)) { - //~^ ERROR non-exhaustive patterns: `(T1(()), V2(_))` and `(T2(()), V1(_))` not covered + //~^ ERROR non-exhaustive patterns: `(T::T1(()), V::V2(_))` and `(T::T2(()), V::V1(_))` not covered (T::T1(()), V::V1(i)) => (), (T::T2(()), V::V2(b)) => (), } diff --git a/src/test/ui/pattern/usefulness/issue-15129.stderr b/src/test/ui/pattern/usefulness/issue-15129.stderr index af60f3ff50bf..ee8410b76508 100644 --- a/src/test/ui/pattern/usefulness/issue-15129.stderr +++ b/src/test/ui/pattern/usefulness/issue-15129.stderr @@ -1,14 +1,14 @@ -error[E0004]: non-exhaustive patterns: `(T1(()), V2(_))` and `(T2(()), V1(_))` not covered +error[E0004]: non-exhaustive patterns: `(T::T1(()), V::V2(_))` and `(T::T2(()), V::V1(_))` not covered --> $DIR/issue-15129.rs:12:11 | LL | match (T::T1(()), V::V2(true)) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `(T1(()), V2(_))` and `(T2(()), V1(_))` not covered + | ^^^^^^^^^^^^^^^^^^^^^^^^ patterns `(T::T1(()), V::V2(_))` and `(T::T2(()), V::V1(_))` not covered | = note: the matched value is of type `(T, V)` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ (T::T2(()), V::V2(b)) => (), -LL ~ (T1(()), V2(_)) | (T2(()), V1(_)) => todo!(), +LL ~ (T::T1(()), V::V2(_)) | (T::T2(()), V::V1(_)) => todo!(), | error: aborting due to previous error diff --git a/src/test/ui/pattern/usefulness/issue-31561.rs b/src/test/ui/pattern/usefulness/issue-31561.rs index 813b2409cc8e..5b878851a314 100644 --- a/src/test/ui/pattern/usefulness/issue-31561.rs +++ b/src/test/ui/pattern/usefulness/issue-31561.rs @@ -6,5 +6,5 @@ enum Thing { fn main() { let Thing::Foo(y) = Thing::Foo(1); - //~^ ERROR refutable pattern in local binding: `Bar` and `Baz` not covered + //~^ ERROR refutable pattern in local binding: `Thing::Bar` and `Thing::Baz` not covered } diff --git a/src/test/ui/pattern/usefulness/issue-31561.stderr b/src/test/ui/pattern/usefulness/issue-31561.stderr index 9da6b5eeead2..46aebccc5fff 100644 --- a/src/test/ui/pattern/usefulness/issue-31561.stderr +++ b/src/test/ui/pattern/usefulness/issue-31561.stderr @@ -1,8 +1,8 @@ -error[E0005]: refutable pattern in local binding: `Bar` and `Baz` not covered +error[E0005]: refutable pattern in local binding: `Thing::Bar` and `Thing::Baz` not covered --> $DIR/issue-31561.rs:8:9 | LL | let Thing::Foo(y) = Thing::Foo(1); - | ^^^^^^^^^^^^^ patterns `Bar` and `Baz` not covered + | ^^^^^^^^^^^^^ patterns `Thing::Bar` and `Thing::Baz` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html diff --git a/src/test/ui/pattern/usefulness/issue-35609.stderr b/src/test/ui/pattern/usefulness/issue-35609.stderr index 2247b818d438..c9781d52e6dc 100644 --- a/src/test/ui/pattern/usefulness/issue-35609.stderr +++ b/src/test/ui/pattern/usefulness/issue-35609.stderr @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: `(B, _)`, `(C, _)`, `(D, _)` and 2 more not covered +error[E0004]: non-exhaustive patterns: `(Enum::B, _)`, `(Enum::C, _)`, `(Enum::D, _)` and 2 more not covered --> $DIR/issue-35609.rs:10:11 | LL | match (A, ()) { - | ^^^^^^^ patterns `(B, _)`, `(C, _)`, `(D, _)` and 2 more not covered + | ^^^^^^^ patterns `(Enum::B, _)`, `(Enum::C, _)`, `(Enum::D, _)` and 2 more not covered | = note: the matched value is of type `(Enum, ())` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms @@ -11,11 +11,11 @@ LL ~ (A, _) => {} LL + _ => todo!() | -error[E0004]: non-exhaustive patterns: `(_, B)`, `(_, C)`, `(_, D)` and 2 more not covered +error[E0004]: non-exhaustive patterns: `(_, Enum::B)`, `(_, Enum::C)`, `(_, Enum::D)` and 2 more not covered --> $DIR/issue-35609.rs:14:11 | LL | match (A, A) { - | ^^^^^^ patterns `(_, B)`, `(_, C)`, `(_, D)` and 2 more not covered + | ^^^^^^ patterns `(_, Enum::B)`, `(_, Enum::C)`, `(_, Enum::D)` and 2 more not covered | = note: the matched value is of type `(Enum, Enum)` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms @@ -24,11 +24,11 @@ LL ~ (_, A) => {} LL + _ => todo!() | -error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered +error[E0004]: non-exhaustive patterns: `((Enum::B, _), _)`, `((Enum::C, _), _)`, `((Enum::D, _), _)` and 2 more not covered --> $DIR/issue-35609.rs:18:11 | LL | match ((A, ()), ()) { - | ^^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered + | ^^^^^^^^^^^^^ patterns `((Enum::B, _), _)`, `((Enum::C, _), _)`, `((Enum::D, _), _)` and 2 more not covered | = note: the matched value is of type `((Enum, ()), ())` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms @@ -37,11 +37,11 @@ LL ~ ((A, ()), _) => {} LL + _ => todo!() | -error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered +error[E0004]: non-exhaustive patterns: `((Enum::B, _), _)`, `((Enum::C, _), _)`, `((Enum::D, _), _)` and 2 more not covered --> $DIR/issue-35609.rs:22:11 | LL | match ((A, ()), A) { - | ^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered + | ^^^^^^^^^^^^ patterns `((Enum::B, _), _)`, `((Enum::C, _), _)`, `((Enum::D, _), _)` and 2 more not covered | = note: the matched value is of type `((Enum, ()), Enum)` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms @@ -50,11 +50,11 @@ LL ~ ((A, ()), _) => {} LL + _ => todo!() | -error[E0004]: non-exhaustive patterns: `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered +error[E0004]: non-exhaustive patterns: `((Enum::B, _), _)`, `((Enum::C, _), _)`, `((Enum::D, _), _)` and 2 more not covered --> $DIR/issue-35609.rs:26:11 | LL | match ((A, ()), ()) { - | ^^^^^^^^^^^^^ patterns `((B, _), _)`, `((C, _), _)`, `((D, _), _)` and 2 more not covered + | ^^^^^^^^^^^^^ patterns `((Enum::B, _), _)`, `((Enum::C, _), _)`, `((Enum::D, _), _)` and 2 more not covered | = note: the matched value is of type `((Enum, ()), ())` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms @@ -63,11 +63,11 @@ LL ~ ((A, _), _) => {} LL + _ => todo!() | -error[E0004]: non-exhaustive patterns: `S(B, _)`, `S(C, _)`, `S(D, _)` and 2 more not covered +error[E0004]: non-exhaustive patterns: `S(Enum::B, _)`, `S(Enum::C, _)`, `S(Enum::D, _)` and 2 more not covered --> $DIR/issue-35609.rs:31:11 | LL | match S(A, ()) { - | ^^^^^^^^ patterns `S(B, _)`, `S(C, _)`, `S(D, _)` and 2 more not covered + | ^^^^^^^^ patterns `S(Enum::B, _)`, `S(Enum::C, _)`, `S(Enum::D, _)` and 2 more not covered | note: `S` defined here --> $DIR/issue-35609.rs:6:8 @@ -81,11 +81,11 @@ LL ~ S(A, _) => {} LL + _ => todo!() | -error[E0004]: non-exhaustive patterns: `Sd { x: B, .. }`, `Sd { x: C, .. }`, `Sd { x: D, .. }` and 2 more not covered +error[E0004]: non-exhaustive patterns: `Sd { x: Enum::B, .. }`, `Sd { x: Enum::C, .. }`, `Sd { x: Enum::D, .. }` and 2 more not covered --> $DIR/issue-35609.rs:35:11 | LL | match (Sd { x: A, y: () }) { - | ^^^^^^^^^^^^^^^^^^^^ patterns `Sd { x: B, .. }`, `Sd { x: C, .. }`, `Sd { x: D, .. }` and 2 more not covered + | ^^^^^^^^^^^^^^^^^^^^ patterns `Sd { x: Enum::B, .. }`, `Sd { x: Enum::C, .. }`, `Sd { x: Enum::D, .. }` and 2 more not covered | note: `Sd` defined here --> $DIR/issue-35609.rs:7:8 @@ -99,11 +99,11 @@ LL ~ Sd { x: A, y: _ } => {} LL + _ => todo!() | -error[E0004]: non-exhaustive patterns: `Some(B)`, `Some(C)`, `Some(D)` and 2 more not covered +error[E0004]: non-exhaustive patterns: `Some(Enum::B)`, `Some(Enum::C)`, `Some(Enum::D)` and 2 more not covered --> $DIR/issue-35609.rs:39:11 | LL | match Some(A) { - | ^^^^^^^ patterns `Some(B)`, `Some(C)`, `Some(D)` and 2 more not covered + | ^^^^^^^ patterns `Some(Enum::B)`, `Some(Enum::C)`, `Some(Enum::D)` and 2 more not covered | note: `Option` defined here --> $SRC_DIR/core/src/option.rs:LL:COL diff --git a/src/test/ui/pattern/usefulness/issue-39362.stderr b/src/test/ui/pattern/usefulness/issue-39362.stderr index ca37af6fb809..b8b17918aef8 100644 --- a/src/test/ui/pattern/usefulness/issue-39362.stderr +++ b/src/test/ui/pattern/usefulness/issue-39362.stderr @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered +error[E0004]: non-exhaustive patterns: `Foo::Bar { bar: Bar::C, .. }`, `Foo::Bar { bar: Bar::D, .. }`, `Foo::Bar { bar: Bar::E, .. }` and 1 more not covered --> $DIR/issue-39362.rs:10:11 | LL | match f { - | ^ patterns `Bar { bar: C, .. }`, `Bar { bar: D, .. }`, `Bar { bar: E, .. }` and 1 more not covered + | ^ patterns `Foo::Bar { bar: Bar::C, .. }`, `Foo::Bar { bar: Bar::D, .. }`, `Foo::Bar { bar: Bar::E, .. }` and 1 more not covered | note: `Foo` defined here --> $DIR/issue-39362.rs:2:5 diff --git a/src/test/ui/pattern/usefulness/issue-40221.stderr b/src/test/ui/pattern/usefulness/issue-40221.stderr index c477e4353350..4973e42b0544 100644 --- a/src/test/ui/pattern/usefulness/issue-40221.stderr +++ b/src/test/ui/pattern/usefulness/issue-40221.stderr @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: `C(QA)` not covered +error[E0004]: non-exhaustive patterns: `P::C(PC::QA)` not covered --> $DIR/issue-40221.rs:11:11 | LL | match proto { - | ^^^^^ pattern `C(QA)` not covered + | ^^^^^ pattern `P::C(PC::QA)` not covered | note: `P` defined here --> $DIR/issue-40221.rs:2:5 @@ -15,7 +15,7 @@ LL | C(PC), help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ P::C(PC::Q) => (), -LL ~ C(QA) => todo!(), +LL ~ P::C(PC::QA) => todo!(), | error: aborting due to previous error diff --git a/src/test/ui/pattern/usefulness/issue-50900.rs b/src/test/ui/pattern/usefulness/issue-50900.rs index 27135af95758..9cc760e9a10d 100644 --- a/src/test/ui/pattern/usefulness/issue-50900.rs +++ b/src/test/ui/pattern/usefulness/issue-50900.rs @@ -13,7 +13,7 @@ impl Tag { fn main() { match Tag::ExifIFDPointer { - //~^ ERROR: non-exhaustive patterns: `Tag(Exif, _)` not covered + //~^ ERROR: non-exhaustive patterns: `Tag(Context::Exif, _)` not covered Tag::ExifIFDPointer => {} } } diff --git a/src/test/ui/pattern/usefulness/issue-50900.stderr b/src/test/ui/pattern/usefulness/issue-50900.stderr index 2bdbecabbbea..348246d28aac 100644 --- a/src/test/ui/pattern/usefulness/issue-50900.stderr +++ b/src/test/ui/pattern/usefulness/issue-50900.stderr @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: `Tag(Exif, _)` not covered +error[E0004]: non-exhaustive patterns: `Tag(Context::Exif, _)` not covered --> $DIR/issue-50900.rs:15:11 | LL | match Tag::ExifIFDPointer { - | ^^^^^^^^^^^^^^^^^^^ pattern `Tag(Exif, _)` not covered + | ^^^^^^^^^^^^^^^^^^^ pattern `Tag(Context::Exif, _)` not covered | note: `Tag` defined here --> $DIR/issue-50900.rs:2:12 @@ -13,7 +13,7 @@ LL | pub struct Tag(pub Context, pub u16); help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ Tag::ExifIFDPointer => {} -LL + Tag(Exif, _) => todo!() +LL + Tag(Context::Exif, _) => todo!() | error: aborting due to previous error diff --git a/src/test/ui/pattern/usefulness/issue-56379.rs b/src/test/ui/pattern/usefulness/issue-56379.rs index 9bccccca9c2b..097cf98d0126 100644 --- a/src/test/ui/pattern/usefulness/issue-56379.rs +++ b/src/test/ui/pattern/usefulness/issue-56379.rs @@ -6,7 +6,7 @@ enum Foo { fn main() { match Foo::A(true) { - //~^ ERROR non-exhaustive patterns: `A(false)`, `B(false)` and `C(false)` not covered + //~^ ERROR non-exhaustive patterns: `Foo::A(false)`, `Foo::B(false)` and `Foo::C(false)` not covered Foo::A(true) => {} Foo::B(true) => {} Foo::C(true) => {} diff --git a/src/test/ui/pattern/usefulness/issue-56379.stderr b/src/test/ui/pattern/usefulness/issue-56379.stderr index f6261001c5e0..6eed6bfae4c9 100644 --- a/src/test/ui/pattern/usefulness/issue-56379.stderr +++ b/src/test/ui/pattern/usefulness/issue-56379.stderr @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: `A(false)`, `B(false)` and `C(false)` not covered +error[E0004]: non-exhaustive patterns: `Foo::A(false)`, `Foo::B(false)` and `Foo::C(false)` not covered --> $DIR/issue-56379.rs:8:11 | LL | match Foo::A(true) { - | ^^^^^^^^^^^^ patterns `A(false)`, `B(false)` and `C(false)` not covered + | ^^^^^^^^^^^^ patterns `Foo::A(false)`, `Foo::B(false)` and `Foo::C(false)` not covered | note: `Foo` defined here --> $DIR/issue-56379.rs:2:5 @@ -19,7 +19,7 @@ LL | C(bool), help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ Foo::C(true) => {} -LL + A(false) | B(false) | C(false) => todo!() +LL + Foo::A(false) | Foo::B(false) | Foo::C(false) => todo!() | error: aborting due to previous error diff --git a/src/test/ui/pattern/usefulness/issue-72377.rs b/src/test/ui/pattern/usefulness/issue-72377.rs index b0d8a53ed93b..b5ad3075ca72 100644 --- a/src/test/ui/pattern/usefulness/issue-72377.rs +++ b/src/test/ui/pattern/usefulness/issue-72377.rs @@ -6,7 +6,7 @@ fn main() { let y = Some(X::A); match (x, y) { - //~^ ERROR non-exhaustive patterns: `(A, Some(A))`, `(A, Some(B))`, `(B, Some(B))` and 2 + //~^ ERROR non-exhaustive patterns: `(X::A, Some(X::A))`, `(X::A, Some(X::B))`, `(X::B, Some(X::B))` and 2 //~| more not covered (_, None) => false, (v, Some(w)) if v == w => true, diff --git a/src/test/ui/pattern/usefulness/issue-72377.stderr b/src/test/ui/pattern/usefulness/issue-72377.stderr index 20f002dd3db1..123dd051d249 100644 --- a/src/test/ui/pattern/usefulness/issue-72377.stderr +++ b/src/test/ui/pattern/usefulness/issue-72377.stderr @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: `(A, Some(A))`, `(A, Some(B))`, `(B, Some(B))` and 2 more not covered +error[E0004]: non-exhaustive patterns: `(X::A, Some(X::A))`, `(X::A, Some(X::B))`, `(X::B, Some(X::B))` and 2 more not covered --> $DIR/issue-72377.rs:8:11 | LL | match (x, y) { - | ^^^^^^ patterns `(A, Some(A))`, `(A, Some(B))`, `(B, Some(B))` and 2 more not covered + | ^^^^^^ patterns `(X::A, Some(X::A))`, `(X::A, Some(X::B))`, `(X::B, Some(X::B))` and 2 more not covered | = note: the matched value is of type `(X, Option)` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown, or multiple match arms diff --git a/src/test/ui/pattern/usefulness/match-arm-statics-2.rs b/src/test/ui/pattern/usefulness/match-arm-statics-2.rs index 4c5f2d356491..3c9c16561c02 100644 --- a/src/test/ui/pattern/usefulness/match-arm-statics-2.rs +++ b/src/test/ui/pattern/usefulness/match-arm-statics-2.rs @@ -27,7 +27,7 @@ const EAST: Direction = East; fn nonexhaustive_2() { match Some(Some(North)) { - //~^ ERROR non-exhaustive patterns: `Some(Some(West))` not covered + //~^ ERROR non-exhaustive patterns: `Some(Some(Direction::West))` not covered Some(NONE) => (), Some(Some(North)) => (), Some(Some(EAST)) => (), @@ -46,7 +46,7 @@ const STATIC_FOO: Foo = Foo { bar: None, baz: NEW_FALSE }; fn nonexhaustive_3() { match (Foo { bar: Some(North), baz: NewBool(true) }) { - //~^ ERROR non-exhaustive patterns: `Foo { bar: Some(North), baz: NewBool(true) }` + //~^ ERROR non-exhaustive patterns: `Foo { bar: Some(Direction::North), baz: NewBool(true) }` Foo { bar: None, baz: NewBool(true) } => (), Foo { bar: _, baz: NEW_FALSE } => (), Foo { bar: Some(West), baz: NewBool(true) } => (), diff --git a/src/test/ui/pattern/usefulness/match-arm-statics-2.stderr b/src/test/ui/pattern/usefulness/match-arm-statics-2.stderr index a2b66f5ed675..b0d7fe5eb689 100644 --- a/src/test/ui/pattern/usefulness/match-arm-statics-2.stderr +++ b/src/test/ui/pattern/usefulness/match-arm-statics-2.stderr @@ -11,11 +11,11 @@ LL ~ (false, true) => (), LL + (true, false) => todo!() | -error[E0004]: non-exhaustive patterns: `Some(Some(West))` not covered +error[E0004]: non-exhaustive patterns: `Some(Some(Direction::West))` not covered --> $DIR/match-arm-statics-2.rs:29:11 | LL | match Some(Some(North)) { - | ^^^^^^^^^^^^^^^^^ pattern `Some(Some(West))` not covered + | ^^^^^^^^^^^^^^^^^ pattern `Some(Some(Direction::West))` not covered | note: `Option>` defined here --> $SRC_DIR/core/src/option.rs:LL:COL @@ -32,14 +32,14 @@ LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ None => (), -LL + Some(Some(West)) => todo!() +LL + Some(Some(Direction::West)) => todo!() | -error[E0004]: non-exhaustive patterns: `Foo { bar: Some(North), baz: NewBool(true) }` not covered +error[E0004]: non-exhaustive patterns: `Foo { bar: Some(Direction::North), baz: NewBool(true) }` not covered --> $DIR/match-arm-statics-2.rs:48:11 | LL | match (Foo { bar: Some(North), baz: NewBool(true) }) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { bar: Some(North), baz: NewBool(true) }` not covered + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `Foo { bar: Some(Direction::North), baz: NewBool(true) }` not covered | note: `Foo` defined here --> $DIR/match-arm-statics-2.rs:40:8 @@ -50,7 +50,7 @@ LL | struct Foo { help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ Foo { bar: Some(EAST), .. } => (), -LL + Foo { bar: Some(North), baz: NewBool(true) } => todo!() +LL + Foo { bar: Some(Direction::North), baz: NewBool(true) } => todo!() | error: aborting due to 3 previous errors diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs b/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs index 2e15bc2d2a5f..af42fc1aeb46 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs +++ b/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.rs @@ -35,43 +35,43 @@ enum E { fn by_val(e: E) { let e1 = e.clone(); - match e1 { //~ ERROR non-exhaustive patterns: `B` and `C` not covered - //~^ NOTE patterns `B` and `C` not covered + match e1 { //~ ERROR non-exhaustive patterns: `E::B` and `E::C` not covered + //~^ NOTE patterns `E::B` and `E::C` not covered //~| NOTE the matched value is of type `E` E::A => {} } - let E::A = e; //~ ERROR refutable pattern in local binding: `B` and `C` not covered - //~^ NOTE patterns `B` and `C` not covered + let E::A = e; //~ ERROR refutable pattern in local binding: `E::B` and `E::C` not covered + //~^ NOTE patterns `E::B` and `E::C` not covered //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html //~| NOTE the matched value is of type `E` } fn by_ref_once(e: &E) { - match e { //~ ERROR non-exhaustive patterns: `&B` and `&C` not covered - //~^ NOTE patterns `&B` and `&C` not covered + match e { //~ ERROR non-exhaustive patterns: `&E::B` and `&E::C` not covered + //~^ NOTE patterns `&E::B` and `&E::C` not covered //~| NOTE the matched value is of type `&E` E::A => {} } - let E::A = e; //~ ERROR refutable pattern in local binding: `&B` and `&C` not covered - //~^ NOTE patterns `&B` and `&C` not covered + let E::A = e; //~ ERROR refutable pattern in local binding: `&E::B` and `&E::C` not covered + //~^ NOTE patterns `&E::B` and `&E::C` not covered //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html //~| NOTE the matched value is of type `&E` } fn by_ref_thrice(e: & &mut &E) { - match e { //~ ERROR non-exhaustive patterns: `&&mut &B` and `&&mut &C` not covered - //~^ NOTE patterns `&&mut &B` and `&&mut &C` not covered + match e { //~ ERROR non-exhaustive patterns: `&&mut &E::B` and `&&mut &E::C` not covered + //~^ NOTE patterns `&&mut &E::B` and `&&mut &E::C` not covered //~| NOTE the matched value is of type `&&mut &E` E::A => {} } let E::A = e; - //~^ ERROR refutable pattern in local binding: `&&mut &B` and `&&mut &C` not covered - //~| NOTE patterns `&&mut &B` and `&&mut &C` not covered + //~^ ERROR refutable pattern in local binding: `&&mut &E::B` and `&&mut &E::C` not covered + //~| NOTE patterns `&&mut &E::B` and `&&mut &E::C` not covered //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html //~| NOTE the matched value is of type `&&mut &E` @@ -89,15 +89,15 @@ enum Opt { } fn ref_pat(e: Opt) { - match e {//~ ERROR non-exhaustive patterns: `None` not covered - //~^ NOTE pattern `None` not covered + match e {//~ ERROR non-exhaustive patterns: `Opt::None` not covered + //~^ NOTE pattern `Opt::None` not covered //~| NOTE the matched value is of type `Opt` Opt::Some(ref _x) => {} } - let Opt::Some(ref _x) = e; //~ ERROR refutable pattern in local binding: `None` not covered + let Opt::Some(ref _x) = e; //~ ERROR refutable pattern in local binding: `Opt::None` not covered //~^ NOTE the matched value is of type `Opt` - //~| NOTE pattern `None` not covered + //~| NOTE pattern `Opt::None` not covered //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html } diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.stderr index 0f06c31c468b..ac2a9713e7d2 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.stderr +++ b/src/test/ui/pattern/usefulness/non-exhaustive-defined-here.stderr @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: `B` and `C` not covered +error[E0004]: non-exhaustive patterns: `E::B` and `E::C` not covered --> $DIR/non-exhaustive-defined-here.rs:38:11 | LL | match e1 { - | ^^ patterns `B` and `C` not covered + | ^^ patterns `E::B` and `E::C` not covered | note: `E` defined here --> $DIR/non-exhaustive-defined-here.rs:14:5 @@ -19,14 +19,14 @@ LL | C help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ E::A => {} -LL + B | C => todo!() +LL + E::B | E::C => todo!() | -error[E0005]: refutable pattern in local binding: `B` and `C` not covered +error[E0005]: refutable pattern in local binding: `E::B` and `E::C` not covered --> $DIR/non-exhaustive-defined-here.rs:44:9 | LL | let E::A = e; - | ^^^^ patterns `B` and `C` not covered + | ^^^^ patterns `E::B` and `E::C` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html @@ -47,11 +47,11 @@ help: you might want to use `if let` to ignore the variants that aren't matched LL | if let E::A = e { todo!() } | ++ ~~~~~~~~~~~ -error[E0004]: non-exhaustive patterns: `&B` and `&C` not covered +error[E0004]: non-exhaustive patterns: `&E::B` and `&E::C` not covered --> $DIR/non-exhaustive-defined-here.rs:52:11 | LL | match e { - | ^ patterns `&B` and `&C` not covered + | ^ patterns `&E::B` and `&E::C` not covered | note: `E` defined here --> $DIR/non-exhaustive-defined-here.rs:14:5 @@ -68,14 +68,14 @@ LL | C help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ E::A => {} -LL + &B | &C => todo!() +LL + &E::B | &E::C => todo!() | -error[E0005]: refutable pattern in local binding: `&B` and `&C` not covered +error[E0005]: refutable pattern in local binding: `&E::B` and `&E::C` not covered --> $DIR/non-exhaustive-defined-here.rs:58:9 | LL | let E::A = e; - | ^^^^ patterns `&B` and `&C` not covered + | ^^^^ patterns `&E::B` and `&E::C` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html @@ -96,11 +96,11 @@ help: you might want to use `if let` to ignore the variants that aren't matched LL | if let E::A = e { todo!() } | ++ ~~~~~~~~~~~ -error[E0004]: non-exhaustive patterns: `&&mut &B` and `&&mut &C` not covered +error[E0004]: non-exhaustive patterns: `&&mut &E::B` and `&&mut &E::C` not covered --> $DIR/non-exhaustive-defined-here.rs:66:11 | LL | match e { - | ^ patterns `&&mut &B` and `&&mut &C` not covered + | ^ patterns `&&mut &E::B` and `&&mut &E::C` not covered | note: `E` defined here --> $DIR/non-exhaustive-defined-here.rs:14:5 @@ -117,14 +117,14 @@ LL | C help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ E::A => {} -LL + &&mut &B | &&mut &C => todo!() +LL + &&mut &E::B | &&mut &E::C => todo!() | -error[E0005]: refutable pattern in local binding: `&&mut &B` and `&&mut &C` not covered +error[E0005]: refutable pattern in local binding: `&&mut &E::B` and `&&mut &E::C` not covered --> $DIR/non-exhaustive-defined-here.rs:72:9 | LL | let E::A = e; - | ^^^^ patterns `&&mut &B` and `&&mut &C` not covered + | ^^^^ patterns `&&mut &E::B` and `&&mut &E::C` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html @@ -145,11 +145,11 @@ help: you might want to use `if let` to ignore the variants that aren't matched LL | if let E::A = e { todo!() } | ++ ~~~~~~~~~~~ -error[E0004]: non-exhaustive patterns: `None` not covered +error[E0004]: non-exhaustive patterns: `Opt::None` not covered --> $DIR/non-exhaustive-defined-here.rs:92:11 | LL | match e { - | ^ pattern `None` not covered + | ^ pattern `Opt::None` not covered | note: `Opt` defined here --> $DIR/non-exhaustive-defined-here.rs:84:5 @@ -163,14 +163,14 @@ LL | None, help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ Opt::Some(ref _x) => {} -LL + None => todo!() +LL + Opt::None => todo!() | -error[E0005]: refutable pattern in local binding: `None` not covered +error[E0005]: refutable pattern in local binding: `Opt::None` not covered --> $DIR/non-exhaustive-defined-here.rs:98:9 | LL | let Opt::Some(ref _x) = e; - | ^^^^^^^^^^^^^^^^^ pattern `None` not covered + | ^^^^^^^^^^^^^^^^^ pattern `Opt::None` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.rs b/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.rs index d198144790be..69c3c76580a7 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.rs +++ b/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.rs @@ -12,7 +12,7 @@ fn match_nested_vecs<'a, T>(l1: Option<&'a [T]>, l2: Result<&'a [T], ()>) -> &'s fn main() { let x = T::A(U::C); - match x { //~ ERROR non-exhaustive patterns: `A(C)` not covered + match x { //~ ERROR non-exhaustive patterns: `T::A(U::C)` not covered T::A(U::D) => { panic!("hello"); } T::B => { panic!("goodbye"); } } diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.stderr index cbbd544f943b..44f327421109 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.stderr +++ b/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.stderr @@ -11,11 +11,11 @@ LL ~ (None, Ok(&[_, _, ..])) => "None, Ok(at least two elements)", LL + (Some(&[]), Err(_)) => todo!() | -error[E0004]: non-exhaustive patterns: `A(C)` not covered +error[E0004]: non-exhaustive patterns: `T::A(U::C)` not covered --> $DIR/non-exhaustive-match-nested.rs:15:11 | LL | match x { - | ^ pattern `A(C)` not covered + | ^ pattern `T::A(U::C)` not covered | note: `T` defined here --> $DIR/non-exhaustive-match-nested.rs:1:10 @@ -26,7 +26,7 @@ LL | enum T { A(U), B } help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ T::B => { panic!("goodbye"); } -LL + A(C) => todo!() +LL + T::A(U::C) => todo!() | error: aborting due to 2 previous errors diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match.rs b/src/test/ui/pattern/usefulness/non-exhaustive-match.rs index 4ff12aa2ff5e..1cb58b8cebef 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-match.rs +++ b/src/test/ui/pattern/usefulness/non-exhaustive-match.rs @@ -4,7 +4,7 @@ enum T { A, B } fn main() { let x = T::A; - match x { T::B => { } } //~ ERROR non-exhaustive patterns: `A` not covered + match x { T::B => { } } //~ ERROR non-exhaustive patterns: `T::A` not covered match true { //~ ERROR non-exhaustive patterns: `false` not covered true => {} } @@ -15,11 +15,11 @@ fn main() { // and `(_, _, 5_i32..=i32::MAX)` not covered (_, _, 4) => {} } - match (T::A, T::A) { //~ ERROR non-exhaustive patterns: `(A, A)` and `(B, B)` not covered + match (T::A, T::A) { //~ ERROR non-exhaustive patterns: `(T::A, T::A)` and `(T::B, T::B)` not covered (T::A, T::B) => {} (T::B, T::A) => {} } - match T::A { //~ ERROR non-exhaustive patterns: `B` not covered + match T::A { //~ ERROR non-exhaustive patterns: `T::B` not covered T::A => {} } // This is exhaustive, though the algorithm got it wrong at one point diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr index f2362c316dfb..4234600d0d02 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr +++ b/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: `A` not covered +error[E0004]: non-exhaustive patterns: `T::A` not covered --> $DIR/non-exhaustive-match.rs:7:11 | LL | match x { T::B => { } } - | ^ pattern `A` not covered + | ^ pattern `T::A` not covered | note: `T` defined here --> $DIR/non-exhaustive-match.rs:3:10 @@ -12,8 +12,8 @@ LL | enum T { A, B } = note: the matched value is of type `T` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL | match x { T::B => { }, A => todo!() } - | ++++++++++++++ +LL | match x { T::B => { }, T::A => todo!() } + | +++++++++++++++++ error[E0004]: non-exhaustive patterns: `false` not covered --> $DIR/non-exhaustive-match.rs:8:11 @@ -62,24 +62,24 @@ LL ~ (_, _, 4) => {} LL + (_, _, i32::MIN..=3_i32) | (_, _, 5_i32..=i32::MAX) => todo!() | -error[E0004]: non-exhaustive patterns: `(A, A)` and `(B, B)` not covered +error[E0004]: non-exhaustive patterns: `(T::A, T::A)` and `(T::B, T::B)` not covered --> $DIR/non-exhaustive-match.rs:18:11 | LL | match (T::A, T::A) { - | ^^^^^^^^^^^^ patterns `(A, A)` and `(B, B)` not covered + | ^^^^^^^^^^^^ patterns `(T::A, T::A)` and `(T::B, T::B)` not covered | = note: the matched value is of type `(T, T)` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ (T::B, T::A) => {} -LL + (A, A) | (B, B) => todo!() +LL + (T::A, T::A) | (T::B, T::B) => todo!() | -error[E0004]: non-exhaustive patterns: `B` not covered +error[E0004]: non-exhaustive patterns: `T::B` not covered --> $DIR/non-exhaustive-match.rs:22:11 | LL | match T::A { - | ^^^^ pattern `B` not covered + | ^^^^ pattern `T::B` not covered | note: `T` defined here --> $DIR/non-exhaustive-match.rs:3:13 @@ -90,7 +90,7 @@ LL | enum T { A, B } help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ T::A => {} -LL + B => todo!() +LL + T::B => todo!() | error[E0004]: non-exhaustive patterns: `[]` not covered diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.rs b/src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.rs index abb4ea8daf57..4bd34421922b 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.rs +++ b/src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.rs @@ -21,7 +21,7 @@ enum Color { fn enum_with_single_missing_variant() { match Color::Red { - //~^ ERROR non-exhaustive patterns: `Red` not covered + //~^ ERROR non-exhaustive patterns: `Color::Red` not covered Color::CustomRGBA { .. } => (), Color::Green => () } @@ -33,7 +33,7 @@ enum Direction { fn enum_with_multiple_missing_variants() { match Direction::North { - //~^ ERROR non-exhaustive patterns: `East`, `South` and `West` not covered + //~^ ERROR non-exhaustive patterns: `Direction::East`, `Direction::South` and `Direction::West` not covered Direction::North => () } } @@ -44,7 +44,7 @@ enum ExcessiveEnum { fn enum_with_excessive_missing_variants() { match ExcessiveEnum::First { - //~^ ERROR `Second`, `Third`, `Fourth` and 8 more not covered + //~^ ERROR `ExcessiveEnum::Second`, `ExcessiveEnum::Third`, `ExcessiveEnum::Fourth` and 8 more not covered ExcessiveEnum::First => () } @@ -52,7 +52,7 @@ fn enum_with_excessive_missing_variants() { fn enum_struct_variant() { match Color::Red { - //~^ ERROR non-exhaustive patterns: `CustomRGBA { a: true, .. }` not covered + //~^ ERROR non-exhaustive patterns: `Color::CustomRGBA { a: true, .. }` not covered Color::Red => (), Color::Green => (), Color::CustomRGBA { a: false, r: _, g: _, b: 0 } => (), @@ -68,7 +68,7 @@ enum Enum { fn vectors_with_nested_enums() { let x: &'static [Enum] = &[Enum::First, Enum::Second(false)]; match *x { - //~^ ERROR non-exhaustive patterns: `[Second(true), Second(false)]` not covered + //~^ ERROR non-exhaustive patterns: `[Enum::Second(true), Enum::Second(false)]` not covered [] => (), [_] => (), [Enum::First, _] => (), diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr index b0cfd631fb07..b8af566de7c6 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr +++ b/src/test/ui/pattern/usefulness/non-exhaustive-pattern-witness.stderr @@ -16,11 +16,11 @@ LL ~ Foo { first: false, second: Some([1, 2, 3, 4]) } => (), LL + Foo { first: false, second: Some([_, _, _, _]) } => todo!() | -error[E0004]: non-exhaustive patterns: `Red` not covered +error[E0004]: non-exhaustive patterns: `Color::Red` not covered --> $DIR/non-exhaustive-pattern-witness.rs:23:11 | LL | match Color::Red { - | ^^^^^^^^^^ pattern `Red` not covered + | ^^^^^^^^^^ pattern `Color::Red` not covered | note: `Color` defined here --> $DIR/non-exhaustive-pattern-witness.rs:17:5 @@ -33,14 +33,14 @@ LL | Red, help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ Color::Green => (), -LL + Red => todo!() +LL + Color::Red => todo!() | -error[E0004]: non-exhaustive patterns: `East`, `South` and `West` not covered +error[E0004]: non-exhaustive patterns: `Direction::East`, `Direction::South` and `Direction::West` not covered --> $DIR/non-exhaustive-pattern-witness.rs:35:11 | LL | match Direction::North { - | ^^^^^^^^^^^^^^^^ patterns `East`, `South` and `West` not covered + | ^^^^^^^^^^^^^^^^ patterns `Direction::East`, `Direction::South` and `Direction::West` not covered | note: `Direction` defined here --> $DIR/non-exhaustive-pattern-witness.rs:31:12 @@ -56,14 +56,14 @@ LL | North, East, South, West help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ Direction::North => (), -LL + East | South | West => todo!() +LL + Direction::East | Direction::South | Direction::West => todo!() | -error[E0004]: non-exhaustive patterns: `Second`, `Third`, `Fourth` and 8 more not covered +error[E0004]: non-exhaustive patterns: `ExcessiveEnum::Second`, `ExcessiveEnum::Third`, `ExcessiveEnum::Fourth` and 8 more not covered --> $DIR/non-exhaustive-pattern-witness.rs:46:11 | LL | match ExcessiveEnum::First { - | ^^^^^^^^^^^^^^^^^^^^ patterns `Second`, `Third`, `Fourth` and 8 more not covered + | ^^^^^^^^^^^^^^^^^^^^ patterns `ExcessiveEnum::Second`, `ExcessiveEnum::Third`, `ExcessiveEnum::Fourth` and 8 more not covered | note: `ExcessiveEnum` defined here --> $DIR/non-exhaustive-pattern-witness.rs:41:6 @@ -77,11 +77,11 @@ LL ~ ExcessiveEnum::First => (), LL + _ => todo!() | -error[E0004]: non-exhaustive patterns: `CustomRGBA { a: true, .. }` not covered +error[E0004]: non-exhaustive patterns: `Color::CustomRGBA { a: true, .. }` not covered --> $DIR/non-exhaustive-pattern-witness.rs:54:11 | LL | match Color::Red { - | ^^^^^^^^^^ pattern `CustomRGBA { a: true, .. }` not covered + | ^^^^^^^^^^ pattern `Color::CustomRGBA { a: true, .. }` not covered | note: `Color` defined here --> $DIR/non-exhaustive-pattern-witness.rs:19:5 @@ -95,20 +95,20 @@ LL | CustomRGBA { a: bool, r: u8, g: u8, b: u8 } help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ Color::CustomRGBA { a: false, r: _, g: _, b: _ } => (), -LL + CustomRGBA { a: true, .. } => todo!() +LL + Color::CustomRGBA { a: true, .. } => todo!() | -error[E0004]: non-exhaustive patterns: `[Second(true), Second(false)]` not covered +error[E0004]: non-exhaustive patterns: `[Enum::Second(true), Enum::Second(false)]` not covered --> $DIR/non-exhaustive-pattern-witness.rs:70:11 | LL | match *x { - | ^^ pattern `[Second(true), Second(false)]` not covered + | ^^ pattern `[Enum::Second(true), Enum::Second(false)]` not covered | = note: the matched value is of type `[Enum]` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ [_, _, ref tail @ .., _] => (), -LL + [Second(true), Second(false)] => todo!() +LL + [Enum::Second(true), Enum::Second(false)] => todo!() | error[E0004]: non-exhaustive patterns: `((), false)` not covered diff --git a/src/test/ui/pattern/usefulness/stable-gated-patterns.rs b/src/test/ui/pattern/usefulness/stable-gated-patterns.rs index ff1c472e24fd..03db01160dda 100644 --- a/src/test/ui/pattern/usefulness/stable-gated-patterns.rs +++ b/src/test/ui/pattern/usefulness/stable-gated-patterns.rs @@ -8,7 +8,7 @@ fn main() { match UnstableEnum::Stable { UnstableEnum::Stable => {} } - //~^^^ non-exhaustive patterns: `Stable2` and `_` not covered + //~^^^ non-exhaustive patterns: `UnstableEnum::Stable2` and `_` not covered match UnstableEnum::Stable { UnstableEnum::Stable => {} diff --git a/src/test/ui/pattern/usefulness/stable-gated-patterns.stderr b/src/test/ui/pattern/usefulness/stable-gated-patterns.stderr index 98c75953add8..7b8588a3c735 100644 --- a/src/test/ui/pattern/usefulness/stable-gated-patterns.stderr +++ b/src/test/ui/pattern/usefulness/stable-gated-patterns.stderr @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: `Stable2` and `_` not covered +error[E0004]: non-exhaustive patterns: `UnstableEnum::Stable2` and `_` not covered --> $DIR/stable-gated-patterns.rs:8:11 | LL | match UnstableEnum::Stable { - | ^^^^^^^^^^^^^^^^^^^^ patterns `Stable2` and `_` not covered + | ^^^^^^^^^^^^^^^^^^^^ patterns `UnstableEnum::Stable2` and `_` not covered | note: `UnstableEnum` defined here --> $DIR/auxiliary/unstable.rs:9:5 @@ -16,7 +16,7 @@ LL | Stable2, help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ UnstableEnum::Stable => {} -LL + Stable2 | _ => todo!() +LL + UnstableEnum::Stable2 | _ => todo!() | error[E0004]: non-exhaustive patterns: `_` not covered diff --git a/src/test/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr b/src/test/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr index 6127fad3f7d5..85c97be29d6d 100644 --- a/src/test/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr +++ b/src/test/ui/pattern/usefulness/struct-like-enum-nonexhaustive.stderr @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: `B { x: Some(_) }` not covered +error[E0004]: non-exhaustive patterns: `A::B { x: Some(_) }` not covered --> $DIR/struct-like-enum-nonexhaustive.rs:8:11 | LL | match x { - | ^ pattern `B { x: Some(_) }` not covered + | ^ pattern `A::B { x: Some(_) }` not covered | note: `A` defined here --> $DIR/struct-like-enum-nonexhaustive.rs:2:5 @@ -15,7 +15,7 @@ LL | B { x: Option }, help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ A::B { x: None } => {} -LL + B { x: Some(_) } => todo!() +LL + A::B { x: Some(_) } => todo!() | error: aborting due to previous error diff --git a/src/test/ui/pattern/usefulness/unstable-gated-patterns.rs b/src/test/ui/pattern/usefulness/unstable-gated-patterns.rs index bdab327fd57a..7046555e0d2f 100644 --- a/src/test/ui/pattern/usefulness/unstable-gated-patterns.rs +++ b/src/test/ui/pattern/usefulness/unstable-gated-patterns.rs @@ -11,7 +11,7 @@ fn main() { UnstableEnum::Stable => {} UnstableEnum::Stable2 => {} } - //~^^^^ non-exhaustive patterns: `Unstable` not covered + //~^^^^ non-exhaustive patterns: `UnstableEnum::Unstable` not covered // Ok: all variants are explicitly matched match UnstableEnum::Stable { diff --git a/src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr b/src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr index f07a25ca89b2..6dc9a4058398 100644 --- a/src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr +++ b/src/test/ui/pattern/usefulness/unstable-gated-patterns.stderr @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: `Unstable` not covered +error[E0004]: non-exhaustive patterns: `UnstableEnum::Unstable` not covered --> $DIR/unstable-gated-patterns.rs:10:11 | LL | match UnstableEnum::Stable { - | ^^^^^^^^^^^^^^^^^^^^ pattern `Unstable` not covered + | ^^^^^^^^^^^^^^^^^^^^ pattern `UnstableEnum::Unstable` not covered | note: `UnstableEnum` defined here --> $DIR/auxiliary/unstable.rs:11:5 @@ -16,7 +16,7 @@ LL | Unstable, help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ UnstableEnum::Stable2 => {} -LL + Unstable => todo!() +LL + UnstableEnum::Unstable => todo!() | error: aborting due to previous error diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.rs b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.rs index 70253a4fc901..69a283c31633 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.rs @@ -31,7 +31,7 @@ fn empty_non_exhaustive(x: EmptyNonExhaustiveEnum) { fn main() { match NonExhaustiveEnum::Unit {} - //~^ ERROR `Unit`, `Tuple(_)` and `Struct { .. }` not covered [E0004] + //~^ ERROR `NonExhaustiveEnum::Unit`, `NonExhaustiveEnum::Tuple(_)` and `NonExhaustiveEnum::Struct { .. }` not covered [E0004] match NormalEnum::Unit {} - //~^ ERROR `Unit`, `Tuple(_)` and `Struct { .. }` not covered [E0004] + //~^ ERROR `NormalEnum::Unit`, `NormalEnum::Tuple(_)` and `NormalEnum::Struct { .. }` not covered [E0004] } diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr index 1f20904483fe..de1bf8be8854 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/enum_same_crate_empty_match.stderr @@ -10,11 +10,11 @@ note: the lint level is defined here LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ -error[E0004]: non-exhaustive patterns: `Unit`, `Tuple(_)` and `Struct { .. }` not covered +error[E0004]: non-exhaustive patterns: `NonExhaustiveEnum::Unit`, `NonExhaustiveEnum::Tuple(_)` and `NonExhaustiveEnum::Struct { .. }` not covered --> $DIR/enum_same_crate_empty_match.rs:33:11 | LL | match NonExhaustiveEnum::Unit {} - | ^^^^^^^^^^^^^^^^^^^^^^^ patterns `Unit`, `Tuple(_)` and `Struct { .. }` not covered + | ^^^^^^^^^^^^^^^^^^^^^^^ patterns `NonExhaustiveEnum::Unit`, `NonExhaustiveEnum::Tuple(_)` and `NonExhaustiveEnum::Struct { .. }` not covered | note: `NonExhaustiveEnum` defined here --> $DIR/enum_same_crate_empty_match.rs:5:5 @@ -33,15 +33,15 @@ LL | Struct { field: u32 } help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ match NonExhaustiveEnum::Unit { -LL + Unit | Tuple(_) | Struct { .. } => todo!(), +LL + NonExhaustiveEnum::Unit | NonExhaustiveEnum::Tuple(_) | NonExhaustiveEnum::Struct { .. } => todo!(), LL + } | -error[E0004]: non-exhaustive patterns: `Unit`, `Tuple(_)` and `Struct { .. }` not covered +error[E0004]: non-exhaustive patterns: `NormalEnum::Unit`, `NormalEnum::Tuple(_)` and `NormalEnum::Struct { .. }` not covered --> $DIR/enum_same_crate_empty_match.rs:35:11 | LL | match NormalEnum::Unit {} - | ^^^^^^^^^^^^^^^^ patterns `Unit`, `Tuple(_)` and `Struct { .. }` not covered + | ^^^^^^^^^^^^^^^^ patterns `NormalEnum::Unit`, `NormalEnum::Tuple(_)` and `NormalEnum::Struct { .. }` not covered | note: `NormalEnum` defined here --> $DIR/enum_same_crate_empty_match.rs:14:5 @@ -60,7 +60,7 @@ LL | Struct { field: u32 } help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ match NormalEnum::Unit { -LL + Unit | Tuple(_) | Struct { .. } => todo!(), +LL + NormalEnum::Unit | NormalEnum::Tuple(_) | NormalEnum::Struct { .. } => todo!(), LL + } | diff --git a/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr index a9885449f3f0..4b9f8564d237 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/omitted-patterns.stderr @@ -81,7 +81,7 @@ error: some variants are not matched explicitly --> $DIR/omitted-patterns.rs:58:9 | LL | _ => {} - | ^ pattern `Struct { .. }` not covered + | ^ pattern `NonExhaustiveEnum::Struct { .. }` not covered | note: the lint level is defined here --> $DIR/omitted-patterns.rs:57:16 @@ -95,7 +95,7 @@ error: some variants are not matched explicitly --> $DIR/omitted-patterns.rs:65:9 | LL | _ => {} - | ^ pattern `Tuple(_)` not covered + | ^ pattern `NonExhaustiveEnum::Tuple(_)` not covered | note: the lint level is defined here --> $DIR/omitted-patterns.rs:64:16 @@ -109,7 +109,7 @@ error: some variants are not matched explicitly --> $DIR/omitted-patterns.rs:75:9 | LL | _ => {} - | ^ pattern `Unit` not covered + | ^ pattern `NonExhaustiveEnum::Unit` not covered | note: the lint level is defined here --> $DIR/omitted-patterns.rs:74:16 @@ -123,7 +123,7 @@ error: some variants are not matched explicitly --> $DIR/omitted-patterns.rs:92:32 | LL | NestedNonExhaustive::A(_) => {} - | ^ patterns `Tuple(_)` and `Struct { .. }` not covered + | ^ patterns `NonExhaustiveEnum::Tuple(_)` and `NonExhaustiveEnum::Struct { .. }` not covered | note: the lint level is defined here --> $DIR/omitted-patterns.rs:89:12 @@ -137,7 +137,7 @@ error: some variants are not matched explicitly --> $DIR/omitted-patterns.rs:94:9 | LL | _ => {} - | ^ pattern `C` not covered + | ^ pattern `NestedNonExhaustive::C` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `NestedNonExhaustive` and the `non_exhaustive_omitted_patterns` attribute was found @@ -146,7 +146,7 @@ error: some variants are not matched explicitly --> $DIR/omitted-patterns.rs:132:9 | LL | _ => {} - | ^ pattern `A(_)` not covered + | ^ pattern `NonExhaustiveSingleVariant::A(_)` not covered | note: the lint level is defined here --> $DIR/omitted-patterns.rs:130:12 @@ -160,7 +160,7 @@ error: some variants are not matched explicitly --> $DIR/omitted-patterns.rs:144:9 | LL | _ => {} - | ^ pattern `Unstable` not covered + | ^ pattern `UnstableEnum::Unstable` not covered | note: the lint level is defined here --> $DIR/omitted-patterns.rs:143:16 @@ -174,7 +174,7 @@ error: some variants are not matched explicitly --> $DIR/omitted-patterns.rs:168:9 | LL | _ => {} - | ^ pattern `Unstable2` not covered + | ^ pattern `OnlyUnstableEnum::Unstable2` not covered | note: the lint level is defined here --> $DIR/omitted-patterns.rs:165:12 diff --git a/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr index 7cce178988aa..533e8abf2d68 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/stable-omitted-patterns.stderr @@ -16,7 +16,7 @@ error: some variants are not matched explicitly --> $DIR/stable-omitted-patterns.rs:23:9 | LL | _ => {} - | ^ pattern `Stable2` not covered + | ^ pattern `UnstableEnum::Stable2` not covered | note: the lint level is defined here --> $DIR/stable-omitted-patterns.rs:22:16 diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr index 32a5c07f1968..a9c54af0418a 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr @@ -55,11 +55,11 @@ LL + _ => todo!(), LL ~ } | -error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered +error[E0004]: non-exhaustive patterns: `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered --> $DIR/match.rs:31:11 | LL | match x {} - | ^ patterns `Tuple(_)` and `Struct { .. }` not covered + | ^ patterns `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered | note: `UninhabitedVariants` defined here --> $DIR/auxiliary/uninhabited.rs:17:23 @@ -74,7 +74,7 @@ LL | #[non_exhaustive] Struct { x: ! } help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ match x { -LL + Tuple(_) | Struct { .. } => todo!(), +LL + UninhabitedVariants::Tuple(_) | UninhabitedVariants::Struct { .. } => todo!(), LL ~ } | diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr index c89c70ae6cc1..ec2a2f6f0553 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr @@ -36,11 +36,11 @@ LL + _ => todo!(), LL ~ } | -error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered +error[E0004]: non-exhaustive patterns: `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered --> $DIR/match_same_crate.rs:38:11 | LL | match x {} - | ^ patterns `Tuple(_)` and `Struct { .. }` not covered + | ^ patterns `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered | note: `UninhabitedVariants` defined here --> $DIR/match_same_crate.rs:16:23 @@ -55,7 +55,7 @@ LL | #[non_exhaustive] Struct { x: ! } help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ match x { -LL + Tuple(_) | Struct { .. } => todo!(), +LL + UninhabitedVariants::Tuple(_) | UninhabitedVariants::Struct { .. } => todo!(), LL ~ } | diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr index d854ea28ff68..b6b777ec56c4 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr @@ -55,11 +55,11 @@ LL + _ => todo!(), LL ~ } | -error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered +error[E0004]: non-exhaustive patterns: `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered --> $DIR/match_with_exhaustive_patterns.rs:34:11 | LL | match x {} - | ^ patterns `Tuple(_)` and `Struct { .. }` not covered + | ^ patterns `UninhabitedVariants::Tuple(_)` and `UninhabitedVariants::Struct { .. }` not covered | note: `UninhabitedVariants` defined here --> $DIR/auxiliary/uninhabited.rs:17:23 @@ -74,7 +74,7 @@ LL | #[non_exhaustive] Struct { x: ! } help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ match x { -LL + Tuple(_) | Struct { .. } => todo!(), +LL + UninhabitedVariants::Tuple(_) | UninhabitedVariants::Struct { .. } => todo!(), LL ~ } | diff --git a/src/test/ui/uninhabited/uninhabited-irrefutable.rs b/src/test/ui/uninhabited/uninhabited-irrefutable.rs index 661b5486adc1..1a0f3c5e5504 100644 --- a/src/test/ui/uninhabited/uninhabited-irrefutable.rs +++ b/src/test/ui/uninhabited/uninhabited-irrefutable.rs @@ -24,5 +24,5 @@ enum Foo { fn main() { let x: Foo = Foo::D(123, 456); - let Foo::D(_y, _z) = x; //~ ERROR refutable pattern in local binding: `A(_)` not covered + let Foo::D(_y, _z) = x; //~ ERROR refutable pattern in local binding: `Foo::A(_)` not covered } diff --git a/src/test/ui/uninhabited/uninhabited-irrefutable.stderr b/src/test/ui/uninhabited/uninhabited-irrefutable.stderr index c571e17a7b37..feeaa89e76f1 100644 --- a/src/test/ui/uninhabited/uninhabited-irrefutable.stderr +++ b/src/test/ui/uninhabited/uninhabited-irrefutable.stderr @@ -1,8 +1,8 @@ -error[E0005]: refutable pattern in local binding: `A(_)` not covered +error[E0005]: refutable pattern in local binding: `Foo::A(_)` not covered --> $DIR/uninhabited-irrefutable.rs:27:9 | LL | let Foo::D(_y, _z) = x; - | ^^^^^^^^^^^^^^ pattern `A(_)` not covered + | ^^^^^^^^^^^^^^ pattern `Foo::A(_)` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html From c011126f1a286c5867e9d18005362e0cd1d221cb Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sat, 3 Sep 2022 06:44:20 +0200 Subject: [PATCH 4131/5092] Fix build with `#[unix_sigpipe = "..."]` support in rustc --- rust-version | 2 +- src/eval.rs | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 0b9f9bba0ad4..1b1d2b0f2b57 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9353538c7bea6edb245457712cec720305c4576e +8c6ce6b91b172f77c795a74bfeaf74b865146b3f diff --git a/src/eval.rs b/src/eval.rs index f7bc11a445d9..bf04e4271311 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -277,7 +277,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Call start function. match entry_type { - EntryFnType::Main => { + EntryFnType::Main { .. } => { let start_id = tcx.lang_items().start_fn().unwrap(); let main_ret_ty = tcx.fn_sig(entry_id).output(); let main_ret_ty = main_ret_ty.no_bound_vars().unwrap(); @@ -292,10 +292,17 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let main_ptr = ecx.create_fn_alloc_ptr(FnVal::Instance(entry_instance)); + let sigpipe = 2; // Inlining of `DEFAULT` from https://github.com/rust-lang/rust/blob/master/compiler/rustc_session/src/config/sigpipe.rs + ecx.call_function( start_instance, Abi::Rust, - &[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv], + &[ + Scalar::from_pointer(main_ptr, &ecx).into(), + argc.into(), + argv, + Scalar::from_u8(sigpipe).into(), + ], Some(&ret_place.into()), StackPopCleanup::Root { cleanup: true }, )?; From 8c37fdf2d702ff1fc805f1bbc5de634e1101a4da Mon Sep 17 00:00:00 2001 From: joboet Date: Sat, 3 Sep 2022 14:05:28 +0200 Subject: [PATCH 4132/5092] std: make `ReentrantMutex` movable and `const`; simplify `Stdout` initialization --- library/std/src/io/stdio.rs | 41 ++++++-------- library/std/src/sync/once_lock.rs | 55 ------------------- library/std/src/sys/hermit/mutex.rs | 3 - library/std/src/sys/itron/mutex.rs | 6 -- library/std/src/sys/sgx/mutex.rs | 3 - .../std/src/sys/unix/locks/fuchsia_mutex.rs | 3 - library/std/src/sys/unix/locks/futex_mutex.rs | 3 - .../std/src/sys/unix/locks/pthread_mutex.rs | 2 +- .../std/src/sys/unsupported/locks/mutex.rs | 3 - library/std/src/sys/windows/locks/mutex.rs | 2 - library/std/src/sys_common/remutex.rs | 46 ++++------------ library/std/src/sys_common/remutex/tests.rs | 37 ++++--------- 12 files changed, 39 insertions(+), 165 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 4d3736f79146..5d0ac690f815 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -8,7 +8,6 @@ use crate::io::prelude::*; use crate::cell::{Cell, RefCell}; use crate::fmt; use crate::io::{self, BufReader, IoSlice, IoSliceMut, LineWriter, Lines}; -use crate::pin::Pin; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sync::{Arc, Mutex, MutexGuard, OnceLock}; use crate::sys::stdio; @@ -526,7 +525,7 @@ pub struct Stdout { // FIXME: this should be LineWriter or BufWriter depending on the state of // stdout (tty or not). Note that if this is not line buffered it // should also flush-on-panic or some form of flush-on-abort. - inner: Pin<&'static ReentrantMutex>>>, + inner: &'static ReentrantMutex>>, } /// A locked reference to the [`Stdout`] handle. @@ -603,24 +602,20 @@ static STDOUT: OnceLock>>> = OnceLo #[stable(feature = "rust1", since = "1.0.0")] pub fn stdout() -> Stdout { Stdout { - inner: Pin::static_ref(&STDOUT).get_or_init_pin( - || unsafe { ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw()))) }, - |mutex| unsafe { mutex.init() }, - ), + inner: STDOUT + .get_or_init(|| ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw())))), } } pub fn cleanup() { - if let Some(instance) = STDOUT.get() { - // Flush the data and disable buffering during shutdown - // by replacing the line writer by one with zero - // buffering capacity. - // We use try_lock() instead of lock(), because someone - // might have leaked a StdoutLock, which would - // otherwise cause a deadlock here. - if let Some(lock) = Pin::static_ref(instance).try_lock() { - *lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw()); - } + // Flush the data and disable buffering during shutdown + // by replacing the line writer by one with zero + // buffering capacity. + // We use try_lock() instead of lock(), because someone + // might have leaked a StdoutLock, which would + // otherwise cause a deadlock here. + if let Some(lock) = STDOUT.get().and_then(ReentrantMutex::try_lock) { + *lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw()); } } @@ -761,7 +756,7 @@ impl fmt::Debug for StdoutLock<'_> { /// standard library or via raw Windows API calls, will fail. #[stable(feature = "rust1", since = "1.0.0")] pub struct Stderr { - inner: Pin<&'static ReentrantMutex>>, + inner: &'static ReentrantMutex>, } /// A locked reference to the [`Stderr`] handle. @@ -834,16 +829,12 @@ pub struct StderrLock<'a> { #[stable(feature = "rust1", since = "1.0.0")] pub fn stderr() -> Stderr { // Note that unlike `stdout()` we don't use `at_exit` here to register a - // destructor. Stderr is not buffered , so there's no need to run a + // destructor. Stderr is not buffered, so there's no need to run a // destructor for flushing the buffer - static INSTANCE: OnceLock>> = OnceLock::new(); + static INSTANCE: ReentrantMutex> = + ReentrantMutex::new(RefCell::new(stderr_raw())); - Stderr { - inner: Pin::static_ref(&INSTANCE).get_or_init_pin( - || unsafe { ReentrantMutex::new(RefCell::new(stderr_raw())) }, - |mutex| unsafe { mutex.init() }, - ), - } + Stderr { inner: &INSTANCE } } impl Stderr { diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs index 813516040cdb..37413ec62a71 100644 --- a/library/std/src/sync/once_lock.rs +++ b/library/std/src/sync/once_lock.rs @@ -3,7 +3,6 @@ use crate::fmt; use crate::marker::PhantomData; use crate::mem::MaybeUninit; use crate::panic::{RefUnwindSafe, UnwindSafe}; -use crate::pin::Pin; use crate::sync::Once; /// A synchronization primitive which can be written to only once. @@ -223,60 +222,6 @@ impl OnceLock { Ok(unsafe { self.get_unchecked() }) } - /// Internal-only API that gets the contents of the cell, initializing it - /// in two steps with `f` and `g` if the cell was empty. - /// - /// `f` is called to construct the value, which is then moved into the cell - /// and given as a (pinned) mutable reference to `g` to finish - /// initialization. - /// - /// This allows `g` to inspect an manipulate the value after it has been - /// moved into its final place in the cell, but before the cell is - /// considered initialized. - /// - /// # Panics - /// - /// If `f` or `g` panics, the panic is propagated to the caller, and the - /// cell remains uninitialized. - /// - /// With the current implementation, if `g` panics, the value from `f` will - /// not be dropped. This should probably be fixed if this is ever used for - /// a type where this matters. - /// - /// It is an error to reentrantly initialize the cell from `f`. The exact - /// outcome is unspecified. Current implementation deadlocks, but this may - /// be changed to a panic in the future. - pub(crate) fn get_or_init_pin(self: Pin<&Self>, f: F, g: G) -> Pin<&T> - where - F: FnOnce() -> T, - G: FnOnce(Pin<&mut T>), - { - if let Some(value) = self.get_ref().get() { - // SAFETY: The inner value was already initialized, and will not be - // moved anymore. - return unsafe { Pin::new_unchecked(value) }; - } - - let slot = &self.value; - - // Ignore poisoning from other threads - // If another thread panics, then we'll be able to run our closure - self.once.call_once_force(|_| { - let value = f(); - // SAFETY: We use the Once (self.once) to guarantee unique access - // to the UnsafeCell (slot). - let value: &mut T = unsafe { (&mut *slot.get()).write(value) }; - // SAFETY: The value has been written to its final place in - // self.value. We do not to move it anymore, which we promise here - // with a Pin<&mut T>. - g(unsafe { Pin::new_unchecked(value) }); - }); - - // SAFETY: The inner value has been initialized, and will not be moved - // anymore. - unsafe { Pin::new_unchecked(self.get_ref().get_unchecked()) } - } - /// Consumes the `OnceLock`, returning the wrapped value. Returns /// `None` if the cell was empty. /// diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs index eb15a04ffcff..e0184eb5baf6 100644 --- a/library/std/src/sys/hermit/mutex.rs +++ b/library/std/src/sys/hermit/mutex.rs @@ -174,9 +174,6 @@ impl Mutex { Mutex { inner: Spinlock::new(MutexInner::new()) } } - #[inline] - pub unsafe fn init(&mut self) {} - #[inline] pub unsafe fn lock(&self) { loop { diff --git a/library/std/src/sys/itron/mutex.rs b/library/std/src/sys/itron/mutex.rs index 715e94c3b3d6..085662e6d44b 100644 --- a/library/std/src/sys/itron/mutex.rs +++ b/library/std/src/sys/itron/mutex.rs @@ -31,12 +31,6 @@ impl Mutex { Mutex { mtx: SpinIdOnceCell::new() } } - pub unsafe fn init(&mut self) { - // Initialize `self.mtx` eagerly - let id = new_mtx().unwrap_or_else(|e| fail(e, &"acre_mtx")); - unsafe { self.mtx.set_unchecked((id, ())) }; - } - /// Get the inner mutex's ID, which is lazily created. fn raw(&self) -> abi::ID { match self.mtx.get_or_try_init(|| new_mtx().map(|id| (id, ()))) { diff --git a/library/std/src/sys/sgx/mutex.rs b/library/std/src/sys/sgx/mutex.rs index 513cd77fd2aa..aa747d56b0d3 100644 --- a/library/std/src/sys/sgx/mutex.rs +++ b/library/std/src/sys/sgx/mutex.rs @@ -20,9 +20,6 @@ impl Mutex { Mutex { inner: SpinMutex::new(WaitVariable::new(false)) } } - #[inline] - pub unsafe fn init(&mut self) {} - #[inline] pub unsafe fn lock(&self) { let mut guard = self.inner.lock(); diff --git a/library/std/src/sys/unix/locks/fuchsia_mutex.rs b/library/std/src/sys/unix/locks/fuchsia_mutex.rs index ce427599c3bd..41379f50c36c 100644 --- a/library/std/src/sys/unix/locks/fuchsia_mutex.rs +++ b/library/std/src/sys/unix/locks/fuchsia_mutex.rs @@ -85,9 +85,6 @@ impl Mutex { Mutex { futex: AtomicU32::new(UNLOCKED) } } - #[inline] - pub unsafe fn init(&mut self) {} - #[inline] pub unsafe fn try_lock(&self) -> bool { let thread_self = zx_thread_self(); diff --git a/library/std/src/sys/unix/locks/futex_mutex.rs b/library/std/src/sys/unix/locks/futex_mutex.rs index 99ba86e5f996..198754a28ef1 100644 --- a/library/std/src/sys/unix/locks/futex_mutex.rs +++ b/library/std/src/sys/unix/locks/futex_mutex.rs @@ -19,9 +19,6 @@ impl Mutex { Self { futex: AtomicU32::new(0) } } - #[inline] - pub unsafe fn init(&mut self) {} - #[inline] pub unsafe fn try_lock(&self) -> bool { self.futex.compare_exchange(0, 1, Acquire, Relaxed).is_ok() diff --git a/library/std/src/sys/unix/locks/pthread_mutex.rs b/library/std/src/sys/unix/locks/pthread_mutex.rs index 98afee69ba62..5964935ddb54 100644 --- a/library/std/src/sys/unix/locks/pthread_mutex.rs +++ b/library/std/src/sys/unix/locks/pthread_mutex.rs @@ -52,7 +52,7 @@ impl Mutex { Mutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) } } #[inline] - pub unsafe fn init(&mut self) { + unsafe fn init(&mut self) { // Issue #33770 // // A pthread mutex initialized with PTHREAD_MUTEX_INITIALIZER will have diff --git a/library/std/src/sys/unsupported/locks/mutex.rs b/library/std/src/sys/unsupported/locks/mutex.rs index d7cb12e0cf9a..2be0b34b985b 100644 --- a/library/std/src/sys/unsupported/locks/mutex.rs +++ b/library/std/src/sys/unsupported/locks/mutex.rs @@ -16,9 +16,6 @@ impl Mutex { Mutex { locked: Cell::new(false) } } - #[inline] - pub unsafe fn init(&mut self) {} - #[inline] pub unsafe fn lock(&self) { assert_eq!(self.locked.replace(true), false, "cannot recursively acquire mutex"); diff --git a/library/std/src/sys/windows/locks/mutex.rs b/library/std/src/sys/windows/locks/mutex.rs index f91e8f9f59a1..91207f5f4665 100644 --- a/library/std/src/sys/windows/locks/mutex.rs +++ b/library/std/src/sys/windows/locks/mutex.rs @@ -37,8 +37,6 @@ impl Mutex { pub const fn new() -> Mutex { Mutex { srwlock: UnsafeCell::new(c::SRWLOCK_INIT) } } - #[inline] - pub unsafe fn init(&mut self) {} #[inline] pub unsafe fn lock(&self) { diff --git a/library/std/src/sys_common/remutex.rs b/library/std/src/sys_common/remutex.rs index 8921af311d41..b448ae3a9977 100644 --- a/library/std/src/sys_common/remutex.rs +++ b/library/std/src/sys_common/remutex.rs @@ -1,13 +1,11 @@ #[cfg(all(test, not(target_os = "emscripten")))] mod tests; +use super::mutex as sys; use crate::cell::UnsafeCell; -use crate::marker::PhantomPinned; use crate::ops::Deref; use crate::panic::{RefUnwindSafe, UnwindSafe}; -use crate::pin::Pin; use crate::sync::atomic::{AtomicUsize, Ordering::Relaxed}; -use crate::sys::locks as sys; /// A re-entrant mutual exclusion /// @@ -41,11 +39,10 @@ use crate::sys::locks as sys; /// synchronization is left to the mutex, making relaxed memory ordering for /// the `owner` field fine in all cases. pub struct ReentrantMutex { - mutex: sys::Mutex, + mutex: sys::MovableMutex, owner: AtomicUsize, lock_count: UnsafeCell, data: T, - _pinned: PhantomPinned, } unsafe impl Send for ReentrantMutex {} @@ -68,39 +65,22 @@ impl RefUnwindSafe for ReentrantMutex {} /// guarded data. #[must_use = "if unused the ReentrantMutex will immediately unlock"] pub struct ReentrantMutexGuard<'a, T: 'a> { - lock: Pin<&'a ReentrantMutex>, + lock: &'a ReentrantMutex, } impl !Send for ReentrantMutexGuard<'_, T> {} impl ReentrantMutex { /// Creates a new reentrant mutex in an unlocked state. - /// - /// # Unsafety - /// - /// This function is unsafe because it is required that `init` is called - /// once this mutex is in its final resting place, and only then are the - /// lock/unlock methods safe. - pub const unsafe fn new(t: T) -> ReentrantMutex { + pub const fn new(t: T) -> ReentrantMutex { ReentrantMutex { - mutex: sys::Mutex::new(), + mutex: sys::MovableMutex::new(), owner: AtomicUsize::new(0), lock_count: UnsafeCell::new(0), data: t, - _pinned: PhantomPinned, } } - /// Initializes this mutex so it's ready for use. - /// - /// # Unsafety - /// - /// Unsafe to call more than once, and must be called after this will no - /// longer move in memory. - pub unsafe fn init(self: Pin<&mut Self>) { - self.get_unchecked_mut().mutex.init() - } - /// Acquires a mutex, blocking the current thread until it is able to do so. /// /// This function will block the caller until it is available to acquire the mutex. @@ -113,15 +93,14 @@ impl ReentrantMutex { /// If another user of this mutex panicked while holding the mutex, then /// this call will return failure if the mutex would otherwise be /// acquired. - pub fn lock(self: Pin<&Self>) -> ReentrantMutexGuard<'_, T> { + pub fn lock(&self) -> ReentrantMutexGuard<'_, T> { let this_thread = current_thread_unique_ptr(); - // Safety: We only touch lock_count when we own the lock, - // and since self is pinned we can safely call the lock() on the mutex. + // Safety: We only touch lock_count when we own the lock. unsafe { if self.owner.load(Relaxed) == this_thread { self.increment_lock_count(); } else { - self.mutex.lock(); + self.mutex.raw_lock(); self.owner.store(this_thread, Relaxed); debug_assert_eq!(*self.lock_count.get(), 0); *self.lock_count.get() = 1; @@ -142,10 +121,9 @@ impl ReentrantMutex { /// If another user of this mutex panicked while holding the mutex, then /// this call will return failure if the mutex would otherwise be /// acquired. - pub fn try_lock(self: Pin<&Self>) -> Option> { + pub fn try_lock(&self) -> Option> { let this_thread = current_thread_unique_ptr(); - // Safety: We only touch lock_count when we own the lock, - // and since self is pinned we can safely call the try_lock on the mutex. + // Safety: We only touch lock_count when we own the lock. unsafe { if self.owner.load(Relaxed) == this_thread { self.increment_lock_count(); @@ -179,12 +157,12 @@ impl Deref for ReentrantMutexGuard<'_, T> { impl Drop for ReentrantMutexGuard<'_, T> { #[inline] fn drop(&mut self) { - // Safety: We own the lock, and the lock is pinned. + // Safety: We own the lock. unsafe { *self.lock.lock_count.get() -= 1; if *self.lock.lock_count.get() == 0 { self.lock.owner.store(0, Relaxed); - self.lock.mutex.unlock(); + self.lock.mutex.raw_unlock(); } } } diff --git a/library/std/src/sys_common/remutex/tests.rs b/library/std/src/sys_common/remutex/tests.rs index 64873b850d3f..8e97ce11c34f 100644 --- a/library/std/src/sys_common/remutex/tests.rs +++ b/library/std/src/sys_common/remutex/tests.rs @@ -1,18 +1,11 @@ -use crate::boxed::Box; use crate::cell::RefCell; -use crate::pin::Pin; use crate::sync::Arc; use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; use crate::thread; #[test] fn smoke() { - let m = unsafe { - let mut m = Box::pin(ReentrantMutex::new(())); - m.as_mut().init(); - m - }; - let m = m.as_ref(); + let m = ReentrantMutex::new(()); { let a = m.lock(); { @@ -29,20 +22,15 @@ fn smoke() { #[test] fn is_mutex() { - let m = unsafe { - // FIXME: Simplify this if Arc gets an Arc::get_pin_mut. - let mut m = Arc::new(ReentrantMutex::new(RefCell::new(0))); - Pin::new_unchecked(Arc::get_mut_unchecked(&mut m)).init(); - Pin::new_unchecked(m) - }; + let m = Arc::new(ReentrantMutex::new(RefCell::new(0))); let m2 = m.clone(); - let lock = m.as_ref().lock(); + let lock = m.lock(); let child = thread::spawn(move || { - let lock = m2.as_ref().lock(); + let lock = m2.lock(); assert_eq!(*lock.borrow(), 4950); }); for i in 0..100 { - let lock = m.as_ref().lock(); + let lock = m.lock(); *lock.borrow_mut() += i; } drop(lock); @@ -51,22 +39,17 @@ fn is_mutex() { #[test] fn trylock_works() { - let m = unsafe { - // FIXME: Simplify this if Arc gets an Arc::get_pin_mut. - let mut m = Arc::new(ReentrantMutex::new(())); - Pin::new_unchecked(Arc::get_mut_unchecked(&mut m)).init(); - Pin::new_unchecked(m) - }; + let m = Arc::new(ReentrantMutex::new(())); let m2 = m.clone(); - let _lock = m.as_ref().try_lock(); - let _lock2 = m.as_ref().try_lock(); + let _lock = m.try_lock(); + let _lock2 = m.try_lock(); thread::spawn(move || { - let lock = m2.as_ref().try_lock(); + let lock = m2.try_lock(); assert!(lock.is_none()); }) .join() .unwrap(); - let _lock3 = m.as_ref().try_lock(); + let _lock3 = m.try_lock(); } pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell>); From 750a2d57bde6fca3bbd856410fe4fb54c4c068dc Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Sat, 3 Sep 2022 17:00:44 +0200 Subject: [PATCH 4133/5092] Fix `unnecessary_to_owned` false positive Fixes #9351. Note that this commit reworks that fix for #9317. The change is to check that the type implements `AsRef` before regarding `to_string` as an equivalent of `to_owned`. This was suggested by Jarcho in the #9317 issue comments. The benefit of this is that it moves some complexity out of `check_other_call_arg` and simplifies the module as a whole. --- .../src/methods/unnecessary_to_owned.rs | 205 ++++++++++++------ tests/ui/unnecessary_to_owned.fixed | 60 +++++ tests/ui/unnecessary_to_owned.rs | 60 +++++ tests/ui/unnecessary_to_owned.stderr | 8 +- 4 files changed, 262 insertions(+), 71 deletions(-) diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 44bf84352943..d59b26c31442 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -1,21 +1,25 @@ use super::implicit_clone::is_clone_like; use super::unnecessary_iter_cloned::{self, is_into_iter}; +use crate::rustc_middle::ty::Subst; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; -use clippy_utils::ty::{ - get_associated_type, get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, peel_mid_ty_refs, -}; -use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item}; +use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs}; +use clippy_utils::visitors::find_all_ret_expressions; +use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty}; use clippy_utils::{meets_msrv, msrvs}; use rustc_errors::Applicability; -use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind}; +use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, ItemKind, Node}; +use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::mir::Mutability; use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; -use rustc_middle::ty::{self, PredicateKind, ProjectionPredicate, TraitPredicate, Ty}; +use rustc_middle::ty::EarlyBinder; +use rustc_middle::ty::{self, ParamTy, PredicateKind, ProjectionPredicate, TraitPredicate, Ty}; use rustc_semver::RustcVersion; use rustc_span::{sym, Symbol}; +use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause}; +use rustc_typeck::check::{FnCtxt, Inherited}; use std::cmp::max; use super::UNNECESSARY_TO_OWNED; @@ -33,7 +37,7 @@ pub fn check<'tcx>( then { if is_cloned_or_copied(cx, method_name, method_def_id) { unnecessary_iter_cloned::check(cx, expr, method_name, receiver); - } else if is_to_owned_like(cx, method_name, method_def_id) { + } else if is_to_owned_like(cx, expr, method_name, method_def_id) { // At this point, we know the call is of a `to_owned`-like function. The functions // `check_addr_of_expr` and `check_call_arg` determine whether the call is unnecessary // based on its context, that is, whether it is a referent in an `AddrOf` expression, an @@ -245,12 +249,12 @@ fn check_other_call_arg<'tcx>( ) -> bool { if_chain! { if let Some((maybe_call, maybe_arg)) = skip_addr_of_ancestors(cx, expr); - if let Some((callee_def_id, call_substs, call_args)) = get_callee_substs_and_args(cx, maybe_call); + if let Some((callee_def_id, _, call_args)) = get_callee_substs_and_args(cx, maybe_call); let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder(); if let Some(i) = call_args.iter().position(|arg| arg.hir_id == maybe_arg.hir_id); if let Some(input) = fn_sig.inputs().get(i); let (input, n_refs) = peel_mid_ty_refs(*input); - if let (trait_predicates, projection_predicates) = get_input_traits_and_projections(cx, callee_def_id, input); + if let (trait_predicates, _) = get_input_traits_and_projections(cx, callee_def_id, input); if let Some(sized_def_id) = cx.tcx.lang_items().sized_trait(); if let [trait_predicate] = trait_predicates .iter() @@ -258,52 +262,13 @@ fn check_other_call_arg<'tcx>( .collect::>()[..]; if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref); if let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef); + if trait_predicate.def_id() == deref_trait_id || trait_predicate.def_id() == as_ref_trait_id; let receiver_ty = cx.typeck_results().expr_ty(receiver); - // If the callee has type parameters, they could appear in `projection_predicate.ty` or the - // types of `trait_predicate.trait_ref.substs`. - if if trait_predicate.def_id() == deref_trait_id { - if let [projection_predicate] = projection_predicates[..] { - let normalized_ty = - cx.tcx - .subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.term); - implements_trait(cx, receiver_ty, deref_trait_id, &[]) - && get_associated_type(cx, receiver_ty, deref_trait_id, "Target") - .map_or(false, |ty| ty::Term::Ty(ty) == normalized_ty) - } else { - false - } - } else if trait_predicate.def_id() == as_ref_trait_id { - let composed_substs = compose_substs( - cx, - &trait_predicate.trait_ref.substs.iter().skip(1).collect::>()[..], - call_substs, - ); - // if `expr` is a `String` and generic target is [u8], skip - // (https://github.com/rust-lang/rust-clippy/issues/9317). - if let [subst] = composed_substs[..] - && let GenericArgKind::Type(arg_ty) = subst.unpack() - && arg_ty.is_slice() - && let inner_ty = arg_ty.builtin_index().unwrap() - && let ty::Uint(ty::UintTy::U8) = inner_ty.kind() - && let self_ty = cx.typeck_results().expr_ty(expr).peel_refs() - && is_type_diagnostic_item(cx, self_ty, sym::String) { - false - } else { - implements_trait(cx, receiver_ty, as_ref_trait_id, &composed_substs) - } - } else { - false - }; + if can_change_type(cx, maybe_arg, receiver_ty); // We can't add an `&` when the trait is `Deref` because `Target = &T` won't match // `Target = T`. if n_refs > 0 || is_copy(cx, receiver_ty) || trait_predicate.def_id() != deref_trait_id; let n_refs = max(n_refs, if is_copy(cx, receiver_ty) { 0 } else { 1 }); - // If the trait is `AsRef` and the input type variable `T` occurs in the output type, then - // `T` must not be instantiated with a reference - // (https://github.com/rust-lang/rust-clippy/issues/8507). - if (n_refs == 0 && !receiver_ty.is_ref()) - || trait_predicate.def_id() != as_ref_trait_id - || !fn_sig.output().contains(input); if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); then { span_lint_and_sugg( @@ -389,22 +354,102 @@ fn get_input_traits_and_projections<'tcx>( (trait_predicates, projection_predicates) } -/// Composes two substitutions by applying the latter to the types of the former. -fn compose_substs<'tcx>( - cx: &LateContext<'tcx>, - left: &[GenericArg<'tcx>], - right: SubstsRef<'tcx>, -) -> Vec> { - left.iter() - .map(|arg| { - if let GenericArgKind::Type(arg_ty) = arg.unpack() { - let normalized_ty = cx.tcx.subst_and_normalize_erasing_regions(right, cx.param_env, arg_ty); - GenericArg::from(normalized_ty) - } else { - *arg +fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<'a>) -> bool { + for (_, node) in cx.tcx.hir().parent_iter(expr.hir_id) { + match node { + Node::Stmt(_) => return true, + Node::Block(..) => continue, + Node::Item(item) => { + if let ItemKind::Fn(_, _, body_id) = &item.kind + && let output_ty = return_ty(cx, item.hir_id()) + && let local_def_id = cx.tcx.hir().local_def_id(item.hir_id()) + && Inherited::build(cx.tcx, local_def_id).enter(|inherited| { + let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, item.hir_id()); + fn_ctxt.can_coerce(ty, output_ty) + }) { + if has_lifetime(output_ty) && has_lifetime(ty) { + return false; + } + let body = cx.tcx.hir().body(*body_id); + let body_expr = &body.value; + let mut count = 0; + return find_all_ret_expressions(cx, body_expr, |_| { count += 1; count <= 1 }); + } } - }) - .collect() + Node::Expr(parent_expr) => { + if let Some((callee_def_id, call_substs, call_args)) = get_callee_substs_and_args(cx, parent_expr) { + let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder(); + if let Some(arg_index) = call_args.iter().position(|arg| arg.hir_id == expr.hir_id) + && let Some(param_ty) = fn_sig.inputs().get(arg_index) + && let ty::Param(ParamTy { index: param_index , ..}) = param_ty.kind() + { + if fn_sig + .inputs() + .iter() + .enumerate() + .filter(|(i, _)| *i != arg_index) + .any(|(_, ty)| ty.contains(*param_ty)) + { + return false; + } + + let mut trait_predicates = cx.tcx.param_env(callee_def_id) + .caller_bounds().iter().filter(|predicate| { + if let PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder() + && trait_predicate.trait_ref.self_ty() == *param_ty { + true + } else { + false + } + }); + + let new_subst = cx.tcx.mk_substs( + call_substs.iter() + .enumerate() + .map(|(i, t)| + if i == (*param_index as usize) { + GenericArg::from(ty) + } else { + t + })); + + if trait_predicates.any(|predicate| { + let predicate = EarlyBinder(predicate).subst(cx.tcx, new_subst); + let obligation = Obligation::new(ObligationCause::dummy(), cx.param_env, predicate); + !cx.tcx + .infer_ctxt() + .enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation)) + }) { + return false; + } + + let output_ty = fn_sig.output(); + if output_ty.contains(*param_ty) { + if let Ok(new_ty) = cx.tcx.try_subst_and_normalize_erasing_regions( + new_subst, cx.param_env, output_ty) { + expr = parent_expr; + ty = new_ty; + continue; + } + return false; + } + + return true; + } + } else if let ExprKind::Block(..) = parent_expr.kind { + continue; + } + return false; + }, + _ => return false, + } + } + + false +} + +fn has_lifetime(ty: Ty<'_>) -> bool { + ty.walk().any(|t| matches!(t.unpack(), GenericArgKind::Lifetime(_))) } /// Returns true if the named method is `Iterator::cloned` or `Iterator::copied`. @@ -415,10 +460,10 @@ fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_def_id: /// Returns true if the named method can be used to convert the receiver to its "owned" /// representation. -fn is_to_owned_like(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool { +fn is_to_owned_like<'a>(cx: &LateContext<'a>, call_expr: &Expr<'a>, method_name: Symbol, method_def_id: DefId) -> bool { is_clone_like(cx, method_name.as_str(), method_def_id) || is_cow_into_owned(cx, method_name, method_def_id) - || is_to_string(cx, method_name, method_def_id) + || is_to_string_on_string_like(cx, call_expr, method_name, method_def_id) } /// Returns true if the named method is `Cow::into_owned`. @@ -426,7 +471,27 @@ fn is_cow_into_owned(cx: &LateContext<'_>, method_name: Symbol, method_def_id: D method_name.as_str() == "into_owned" && is_diag_item_method(cx, method_def_id, sym::Cow) } -/// Returns true if the named method is `ToString::to_string`. -fn is_to_string(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool { - method_name == sym::to_string && is_diag_trait_item(cx, method_def_id, sym::ToString) +/// Returns true if the named method is `ToString::to_string` and it's called on a type that +/// is string-like i.e. implements `AsRef` or `Deref`. +fn is_to_string_on_string_like<'a>( + cx: &LateContext<'_>, + call_expr: &'a Expr<'a>, + method_name: Symbol, + method_def_id: DefId, +) -> bool { + if method_name != sym::to_string || !is_diag_trait_item(cx, method_def_id, sym::ToString) { + return false; + } + + if let Some(substs) = cx.typeck_results().node_substs_opt(call_expr.hir_id) + && let [generic_arg] = substs.as_slice() + && let GenericArgKind::Type(ty) = generic_arg.unpack() + && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref) + && let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef) + && (implements_trait(cx, ty, deref_trait_id, &[cx.tcx.types.str_.into()]) || + implements_trait(cx, ty, as_ref_trait_id, &[cx.tcx.types.str_.into()])) { + true + } else { + false + } } diff --git a/tests/ui/unnecessary_to_owned.fixed b/tests/ui/unnecessary_to_owned.fixed index 9cd5bc73b1ec..a920c63b199c 100644 --- a/tests/ui/unnecessary_to_owned.fixed +++ b/tests/ui/unnecessary_to_owned.fixed @@ -357,3 +357,63 @@ mod issue_9317 { consume(b.to_string()); } } + +mod issue_9351 { + #![allow(dead_code)] + + use std::ops::Deref; + use std::path::{Path, PathBuf}; + + fn require_deref_path>(x: T) -> T { + x + } + + fn generic_arg_used_elsewhere>(_x: T, _y: T) {} + + fn id>(x: T) -> T { + x + } + + fn predicates_are_satisfied(_x: impl std::fmt::Write) {} + + // Should lint + fn single_return() -> impl AsRef { + id("abc") + } + + // Should not lint + fn multiple_returns(b: bool) -> impl AsRef { + if b { + return String::new(); + } + + id("abc".to_string()) + } + + struct S1(String); + + // Should not lint + fn fields1() -> S1 { + S1(id("abc".to_string())) + } + + struct S2 { + s: String, + } + + // Should not lint + fn fields2() { + let mut s = S2 { s: "abc".into() }; + s.s = id("abc".to_string()); + } + + pub fn main() { + let path = std::path::Path::new("x"); + let path_buf = path.to_owned(); + + // Should not lint. + let _x: PathBuf = require_deref_path(path.to_owned()); + generic_arg_used_elsewhere(path.to_owned(), path_buf); + predicates_are_satisfied(id("abc".to_string())); + } +} diff --git a/tests/ui/unnecessary_to_owned.rs b/tests/ui/unnecessary_to_owned.rs index 7f62ba3ab5d5..2128bdacddad 100644 --- a/tests/ui/unnecessary_to_owned.rs +++ b/tests/ui/unnecessary_to_owned.rs @@ -357,3 +357,63 @@ mod issue_9317 { consume(b.to_string()); } } + +mod issue_9351 { + #![allow(dead_code)] + + use std::ops::Deref; + use std::path::{Path, PathBuf}; + + fn require_deref_path>(x: T) -> T { + x + } + + fn generic_arg_used_elsewhere>(_x: T, _y: T) {} + + fn id>(x: T) -> T { + x + } + + fn predicates_are_satisfied(_x: impl std::fmt::Write) {} + + // Should lint + fn single_return() -> impl AsRef { + id("abc".to_string()) + } + + // Should not lint + fn multiple_returns(b: bool) -> impl AsRef { + if b { + return String::new(); + } + + id("abc".to_string()) + } + + struct S1(String); + + // Should not lint + fn fields1() -> S1 { + S1(id("abc".to_string())) + } + + struct S2 { + s: String, + } + + // Should not lint + fn fields2() { + let mut s = S2 { s: "abc".into() }; + s.s = id("abc".to_string()); + } + + pub fn main() { + let path = std::path::Path::new("x"); + let path_buf = path.to_owned(); + + // Should not lint. + let _x: PathBuf = require_deref_path(path.to_owned()); + generic_arg_used_elsewhere(path.to_owned(), path_buf); + predicates_are_satisfied(id("abc".to_string())); + } +} diff --git a/tests/ui/unnecessary_to_owned.stderr b/tests/ui/unnecessary_to_owned.stderr index 243b4599dba4..7deb90b06f3b 100644 --- a/tests/ui/unnecessary_to_owned.stderr +++ b/tests/ui/unnecessary_to_owned.stderr @@ -509,5 +509,11 @@ error: unnecessary use of `to_string` LL | Box::new(build(y.to_string())) | ^^^^^^^^^^^^^ help: use: `y` -error: aborting due to 78 previous errors +error: unnecessary use of `to_string` + --> $DIR/unnecessary_to_owned.rs:381:12 + | +LL | id("abc".to_string()) + | ^^^^^^^^^^^^^^^^^ help: use: `"abc"` + +error: aborting due to 79 previous errors From 020f6895e51c54be77cb2568cd27e93e04c27851 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 3 Sep 2022 17:08:18 +0200 Subject: [PATCH 4134/5092] Fix nested break expressions, expecting unknown types --- crates/hir-ty/src/infer/expr.rs | 43 +++++++++++++++---------------- crates/hir-ty/src/tests/simple.rs | 14 ++++++++++ 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index f3f4ee65bb2e..2d04a864a2cf 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -382,36 +382,35 @@ impl<'a> InferenceContext<'a> { TyKind::Never.intern(Interner) } Expr::Break { expr, label } => { - let mut coerce = match find_breakable(&mut self.breakables, label.as_ref()) { - Some(ctxt) => { - // avoiding the borrowck - mem::replace( - &mut ctxt.coerce, - CoerceMany::new(self.result.standard_types.unknown.clone()), - ) - } - None => CoerceMany::new(self.result.standard_types.unknown.clone()), - }; - let val_ty = if let Some(expr) = *expr { self.infer_expr(expr, &Expectation::none()) } else { TyBuilder::unit() }; - // FIXME: create a synthetic `()` during lowering so we have something to refer to here? - coerce.coerce(self, *expr, &val_ty); + match find_breakable(&mut self.breakables, label.as_ref()) { + Some(ctxt) => { + // avoiding the borrowck + let mut coerce = mem::replace( + &mut ctxt.coerce, + CoerceMany::new(self.result.standard_types.unknown.clone()), + ); - if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) { - ctxt.coerce = coerce; - ctxt.may_break = true; - } else { - self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop { - expr: tgt_expr, - is_break: true, - }); - }; + // FIXME: create a synthetic `()` during lowering so we have something to refer to here? + coerce.coerce(self, *expr, &val_ty); + let ctxt = find_breakable(&mut self.breakables, label.as_ref()) + .expect("breakable stack changed during coercion"); + ctxt.coerce = coerce; + ctxt.may_break = true; + } + None => { + self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop { + expr: tgt_expr, + is_break: true, + }); + } + } TyKind::Never.intern(Interner) } Expr::Return { expr } => { diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs index 707e9e84506a..4ea103e5d9ec 100644 --- a/crates/hir-ty/src/tests/simple.rs +++ b/crates/hir-ty/src/tests/simple.rs @@ -3069,3 +3069,17 @@ fn main() { "#, ); } + +#[test] +fn nested_break() { + check_no_mismatches( + r#" +fn func() { + let int = loop { + break 0; + break (break 0); + }; +} + "#, + ); +} From ee1c1e6d7850cc5ff366b5e1855918e0fc1d80b5 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 3 Sep 2022 12:13:47 -0400 Subject: [PATCH 4135/5092] Add support for BCRYPT_RNG_ALG_HANDLE --- rust-version | 2 +- src/shims/windows/foreign_items.rs | 33 +++++++++++++++++++++--------- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/rust-version b/rust-version index 1b1d2b0f2b57..5ce9544acc7b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8c6ce6b91b172f77c795a74bfeaf74b865146b3f +47d1cdb0bcac8e417071ce1929d261efe2399ae2 diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 9b8f32b0ab60..05014a3331da 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -288,19 +288,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [algorithm, ptr, len, flags] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let algorithm = this.read_scalar(algorithm)?; + let algorithm = algorithm.to_machine_usize(this)?; let ptr = this.read_pointer(ptr)?; let len = this.read_scalar(len)?.to_u32()?; let flags = this.read_scalar(flags)?.to_u32()?; - if flags != 2 { - // ^ BCRYPT_USE_SYSTEM_PREFERRED_RNG - throw_unsup_format!( - "BCryptGenRandom is supported only with the BCRYPT_USE_SYSTEM_PREFERRED_RNG flag" - ); - } - if algorithm.to_machine_usize(this)? != 0 { - throw_unsup_format!( - "BCryptGenRandom algorithm must be NULL when the flag is BCRYPT_USE_SYSTEM_PREFERRED_RNG" - ); + match flags { + 0 => { + // BCRYPT_RNG_ALG_HANDLE + if algorithm != 0x81 { + throw_unsup_format!( + "BCryptGenRandom algorithm must be BCRYPT_RNG_ALG_HANDLE when the flag is 0" + ); + } + } + 2 => { + // BCRYPT_USE_SYSTEM_PREFERRED_RNG + if algorithm != 0 { + throw_unsup_format!( + "BCryptGenRandom algorithm must be NULL when the flag is BCRYPT_USE_SYSTEM_PREFERRED_RNG" + ); + } + } + _ => { + throw_unsup_format!( + "BCryptGenRandom is only supported with BCRYPT_USE_SYSTEM_PREFERRED_RNG or BCRYPT_RNG_ALG_HANDLE" + ); + } } this.gen_random(ptr, len.into())?; this.write_null(dest)?; // STATUS_SUCCESS From 3afbc115f7f7f6b94c213bd3e5a19004cffe196f Mon Sep 17 00:00:00 2001 From: Bart Massey Date: Sat, 3 Sep 2022 11:09:06 -0700 Subject: [PATCH 4136/5092] updated description of File struct in std::fs --- library/std/src/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 28a2c99f7e5e..c6c78dc3939e 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -19,7 +19,7 @@ use crate::sys::fs as fs_imp; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; use crate::time::SystemTime; -/// A reference to an open file on the filesystem. +/// An object providing access to an open file on the filesystem. /// /// An instance of a `File` can be read and/or written depending on what options /// it was opened with. Files also implement [`Seek`] to alter the logical cursor From e7164267a2af0d7c146db719abccd64258745c42 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 30 Aug 2022 22:47:58 +0200 Subject: [PATCH 4137/5092] Do not call object_lifetime_default on lifetime params. --- compiler/rustc_metadata/src/rmeta/encoder.rs | 7 +-- compiler/rustc_middle/src/query/mod.rs | 11 ++-- compiler/rustc_passes/src/check_attr.rs | 35 +++++------ compiler/rustc_resolve/src/late/lifetimes.rs | 38 +++++++----- .../object-lifetime-default.rs | 42 ++++++++++--- .../object-lifetime-default.stderr | 60 +++++++++++-------- 6 files changed, 115 insertions(+), 78 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 8dc5ed2db7e4..15e74db8d745 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1162,10 +1162,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if should_encode_type(tcx, local_id, def_kind) { record!(self.tables.type_of[def_id] <- self.tcx.type_of(def_id)); } - if let DefKind::TyParam | DefKind::ConstParam = def_kind { - if let Some(default) = self.tcx.object_lifetime_default(def_id) { - record!(self.tables.object_lifetime_default[def_id] <- default); - } + if let DefKind::TyParam = def_kind { + let default = self.tcx.object_lifetime_default(def_id); + record!(self.tables.object_lifetime_default[def_id] <- default); } if let DefKind::Trait | DefKind::TraitAlias = def_kind { record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id)); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index abaef0354ade..8e7bacca262e 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1593,12 +1593,13 @@ rustc_queries! { query is_late_bound_map(_: LocalDefId) -> Option<&'tcx FxIndexSet> { desc { "testing if a region is late bound" } } - /// For a given item (like a struct), gets the default lifetimes to be used + /// For a given item's generic parameter, gets the default lifetimes to be used /// for each parameter if a trait object were to be passed for that parameter. - /// For example, for `struct Foo<'a, T, U>`, this would be `['static, 'static]`. - /// For `struct Foo<'a, T: 'a, U>`, this would instead be `['a, 'static]`. - query object_lifetime_default(key: DefId) -> Option { - desc { "looking up lifetime defaults for generic parameter `{:?}`", key } + /// For example, for `T` in `struct Foo<'a, T>`, this would be `'static`. + /// For `T` in `struct Foo<'a, T: 'a>`, this would instead be `'a`. + /// This query will panic if passed something that is not a type parameter. + query object_lifetime_default(key: DefId) -> ObjectLifetimeDefault { + desc { "looking up lifetime defaults for generic parameter `{}`", tcx.def_path_str(key) } separate_provide_extern } query late_bound_vars_map(_: LocalDefId) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 100adedfb505..a63af4159e8c 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -173,9 +173,7 @@ impl CheckAttrVisitor<'_> { sym::no_implicit_prelude => { self.check_generic_attr(hir_id, attr, target, &[Target::Mod]) } - sym::rustc_object_lifetime_default => { - self.check_object_lifetime_default(hir_id, span) - } + sym::rustc_object_lifetime_default => self.check_object_lifetime_default(hir_id), _ => {} } @@ -415,26 +413,21 @@ impl CheckAttrVisitor<'_> { } /// Debugging aid for `object_lifetime_default` query. - fn check_object_lifetime_default(&self, hir_id: HirId, span: Span) { + fn check_object_lifetime_default(&self, hir_id: HirId) { let tcx = self.tcx; if let Some(generics) = tcx.hir().get_generics(tcx.hir().local_def_id(hir_id)) { - let object_lifetime_default_reprs: String = generics - .params - .iter() - .filter_map(|p| { - let param_id = tcx.hir().local_def_id(p.hir_id); - let default = tcx.object_lifetime_default(param_id)?; - Some(match default { - ObjectLifetimeDefault::Empty => "BaseDefault".to_owned(), - ObjectLifetimeDefault::Static => "'static".to_owned(), - ObjectLifetimeDefault::Param(def_id) => tcx.item_name(def_id).to_string(), - ObjectLifetimeDefault::Ambiguous => "Ambiguous".to_owned(), - }) - }) - .collect::>() - .join(","); - - tcx.sess.span_err(span, &object_lifetime_default_reprs); + for p in generics.params { + let hir::GenericParamKind::Type { .. } = p.kind else { continue }; + let param_id = tcx.hir().local_def_id(p.hir_id); + let default = tcx.object_lifetime_default(param_id); + let repr = match default { + ObjectLifetimeDefault::Empty => "BaseDefault".to_owned(), + ObjectLifetimeDefault::Static => "'static".to_owned(), + ObjectLifetimeDefault::Param(def_id) => tcx.item_name(def_id).to_string(), + ObjectLifetimeDefault::Ambiguous => "Ambiguous".to_owned(), + }; + tcx.sess.span_err(p.span, &repr); + } } } diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index c16eab222f62..c72981ed96f6 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -1148,21 +1148,18 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } -fn object_lifetime_default<'tcx>( - tcx: TyCtxt<'tcx>, - param_def_id: DefId, -) -> Option { +fn object_lifetime_default<'tcx>(tcx: TyCtxt<'tcx>, param_def_id: DefId) -> ObjectLifetimeDefault { + debug_assert_eq!(tcx.def_kind(param_def_id), DefKind::TyParam); let param_def_id = param_def_id.expect_local(); let parent_def_id = tcx.local_parent(param_def_id); - let generics = tcx.hir().get_generics(parent_def_id)?; + let generics = tcx.hir().get_generics(parent_def_id).unwrap(); let param_hir_id = tcx.local_def_id_to_hir_id(param_def_id); - let param = generics.params.iter().find(|p| p.hir_id == param_hir_id)?; + let param = generics.params.iter().find(|p| p.hir_id == param_hir_id).unwrap(); // Scan the bounds and where-clauses on parameters to extract bounds // of the form `T:'a` so as to determine the `ObjectLifetimeDefault` // for each type parameter. match param.kind { - GenericParamKind::Lifetime { .. } => None, GenericParamKind::Type { .. } => { let mut set = Set1::Empty; @@ -1181,21 +1178,17 @@ fn object_lifetime_default<'tcx>( } } - Some(match set { + match set { Set1::Empty => ObjectLifetimeDefault::Empty, Set1::One(hir::LifetimeName::Static) => ObjectLifetimeDefault::Static, Set1::One(hir::LifetimeName::Param(param_def_id, _)) => { ObjectLifetimeDefault::Param(param_def_id.to_def_id()) } _ => ObjectLifetimeDefault::Ambiguous, - }) + } } - GenericParamKind::Const { .. } => { - // Generic consts don't impose any constraints. - // - // We still store a dummy value here to allow generic parameters - // in an arbitrary order. - Some(ObjectLifetimeDefault::Empty) + _ => { + bug!("object_lifetime_default_raw must only be called on a type parameter") } } } @@ -1512,7 +1505,20 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { generics .params .iter() - .filter_map(|param| self.tcx.object_lifetime_default(param.def_id)) + .filter_map(|param| { + match self.tcx.def_kind(param.def_id) { + // Generic consts don't impose any constraints. + // + // We still store a dummy value here to allow generic parameters + // in an arbitrary order. + DefKind::ConstParam => Some(ObjectLifetimeDefault::Empty), + DefKind::TyParam => Some(self.tcx.object_lifetime_default(param.def_id)), + // We may also get a `Trait` or `TraitAlias` because of how generics `Self` parameter + // works. Ignore it because it can't have a meaningful lifetime default. + DefKind::LifetimeParam | DefKind::Trait | DefKind::TraitAlias => None, + dk => bug!("unexpected def_kind {:?}", dk), + } + }) .map(set_to_region) .collect() }); diff --git a/src/test/ui/object-lifetime/object-lifetime-default.rs b/src/test/ui/object-lifetime/object-lifetime-default.rs index 60b6629e694d..74f5bb7ddb0e 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default.rs +++ b/src/test/ui/object-lifetime/object-lifetime-default.rs @@ -1,24 +1,50 @@ #![feature(rustc_attrs)] #[rustc_object_lifetime_default] -struct A(T); //~ ERROR BaseDefault +struct A< + T, //~ ERROR BaseDefault +>(T); #[rustc_object_lifetime_default] -struct B<'a,T>(&'a (), T); //~ ERROR BaseDefault +struct B< + 'a, + T, //~ ERROR BaseDefault +>(&'a (), T); #[rustc_object_lifetime_default] -struct C<'a,T:'a>(&'a T); //~ ERROR 'a +struct C< + 'a, + T: 'a, //~ ERROR 'a +>(&'a T); #[rustc_object_lifetime_default] -struct D<'a,'b,T:'a+'b>(&'a T, &'b T); //~ ERROR Ambiguous +struct D< + 'a, + 'b, + T: 'a + 'b, //~ ERROR Ambiguous +>(&'a T, &'b T); #[rustc_object_lifetime_default] -struct E<'a,'b:'a,T:'b>(&'a T, &'b T); //~ ERROR 'b +struct E< + 'a, + 'b: 'a, + T: 'b, //~ ERROR 'b +>(&'a T, &'b T); #[rustc_object_lifetime_default] -struct F<'a,'b,T:'a,U:'b>(&'a T, &'b U); //~ ERROR 'a,'b +struct F< + 'a, + 'b, + T: 'a, //~ ERROR 'a + U: 'b, //~ ERROR 'b +>(&'a T, &'b U); #[rustc_object_lifetime_default] -struct G<'a,'b,T:'a,U:'a+'b>(&'a T, &'b U); //~ ERROR 'a,Ambiguous +struct G< + 'a, + 'b, + T: 'a, //~ ERROR 'a + U: 'a + 'b, //~ ERROR Ambiguous +>(&'a T, &'b U); -fn main() { } +fn main() {} diff --git a/src/test/ui/object-lifetime/object-lifetime-default.stderr b/src/test/ui/object-lifetime/object-lifetime-default.stderr index 60cb98c8fd37..a58afad3ef2b 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default.stderr @@ -1,44 +1,56 @@ error: BaseDefault - --> $DIR/object-lifetime-default.rs:4:1 + --> $DIR/object-lifetime-default.rs:5:5 | -LL | struct A(T); - | ^^^^^^^^^^^^^^^ +LL | T, + | ^ error: BaseDefault - --> $DIR/object-lifetime-default.rs:7:1 + --> $DIR/object-lifetime-default.rs:11:5 | -LL | struct B<'a,T>(&'a (), T); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | T, + | ^ error: 'a - --> $DIR/object-lifetime-default.rs:10:1 + --> $DIR/object-lifetime-default.rs:17:5 | -LL | struct C<'a,T:'a>(&'a T); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | T: 'a, + | ^ error: Ambiguous - --> $DIR/object-lifetime-default.rs:13:1 + --> $DIR/object-lifetime-default.rs:24:5 | -LL | struct D<'a,'b,T:'a+'b>(&'a T, &'b T); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | T: 'a + 'b, + | ^ error: 'b - --> $DIR/object-lifetime-default.rs:16:1 + --> $DIR/object-lifetime-default.rs:31:5 | -LL | struct E<'a,'b:'a,T:'b>(&'a T, &'b T); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | T: 'b, + | ^ -error: 'a,'b - --> $DIR/object-lifetime-default.rs:19:1 +error: 'a + --> $DIR/object-lifetime-default.rs:38:5 | -LL | struct F<'a,'b,T:'a,U:'b>(&'a T, &'b U); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | T: 'a, + | ^ -error: 'a,Ambiguous - --> $DIR/object-lifetime-default.rs:22:1 +error: 'b + --> $DIR/object-lifetime-default.rs:39:5 | -LL | struct G<'a,'b,T:'a,U:'a+'b>(&'a T, &'b U); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | U: 'b, + | ^ -error: aborting due to 7 previous errors +error: 'a + --> $DIR/object-lifetime-default.rs:46:5 + | +LL | T: 'a, + | ^ + +error: Ambiguous + --> $DIR/object-lifetime-default.rs:47:5 + | +LL | U: 'a + 'b, + | ^ + +error: aborting due to 9 previous errors From 771456264b4219ea5ef5bce15cc74c5901afe820 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 3 Sep 2022 19:12:44 +0000 Subject: [PATCH 4138/5092] Don't delay invalid lhs bug unless we know it'll be replaced by one in check_overloaded_binop --- compiler/rustc_typeck/src/check/op.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index 952086e898fc..d51dccd1af5d 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -57,9 +57,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) .is_ok() { - // Suppress this error, since we already emitted - // a deref suggestion in check_overloaded_binop - err.downgrade_to_delayed_bug(); + // If LHS += RHS is an error, but *LHS += RHS is successful, then we will have + // emitted a better suggestion during error handling in check_overloaded_binop. + if self + .lookup_op_method( + lhs_ty, + Some(rhs_ty), + Some(rhs), + Op::Binary(op, IsAssign::Yes), + expected, + ) + .is_err() + { + err.downgrade_to_delayed_bug(); + } } } }); From 2c664bcbfbd31882a4b2a32f8058cc25e378186c Mon Sep 17 00:00:00 2001 From: Lukas Lueg Date: Sat, 3 Sep 2022 21:48:17 +0200 Subject: [PATCH 4139/5092] Tone down explanation on RefCell::get_mut --- library/core/src/cell.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index fb4454c94cb3..1abbb39497a0 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1021,15 +1021,18 @@ impl RefCell { /// Returns a mutable reference to the underlying data. /// - /// This call borrows `RefCell` mutably (at compile-time) so there is no - /// need for dynamic checks. + /// Since this method borrows `RefCell` mutably, it is statically guaranteed + /// that no borrows to the underlying data exist. The dynamic checks inherent + /// in [`borrow_mut`] and most other methods of `RefCell` are therefor + /// unnecessary. /// - /// However be cautious: this method expects `self` to be mutable, which is - /// generally not the case when using a `RefCell`. Take a look at the - /// [`borrow_mut`] method instead if `self` isn't mutable. + /// This method can only be called if `RefCell` can be mutably borrowed, + /// which in general is only the case directly after the `RefCell` has + /// been created. In these situations, skipping the aforementioned dynamic + /// borrowing checks may yield better ergonomics and runtime-performance. /// - /// Also, please be aware that this method is only for special circumstances and is usually - /// not what you want. In case of doubt, use [`borrow_mut`] instead. + /// In most situations where `RefCell` is used, it can't be borrowed mutably. + /// Use [`borrow_mut`] to get mutable access to the underlying data then. /// /// [`borrow_mut`]: RefCell::borrow_mut() /// From 6f4726541e56ae02a7e31cc42d1d14df81848c58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 3 Sep 2022 22:57:22 +0200 Subject: [PATCH 4140/5092] more clippy::perf fixes --- compiler/rustc_lint/src/context.rs | 2 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 18 +++++------------- compiler/rustc_resolve/src/diagnostics.rs | 2 +- library/std/src/sys/unix/thread.rs | 2 +- src/librustdoc/html/render/mod.rs | 4 ++-- src/librustdoc/html/render/write_shared.rs | 2 +- 6 files changed, 11 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index e3b6c0159870..9a163cf207e9 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -842,7 +842,7 @@ pub trait LintContext: Sized { if let Some(positional_arg_to_replace) = position_sp_to_replace { let name = if is_formatting_arg { named_arg_name + "$" } else { named_arg_name }; let span_to_replace = if let Ok(positional_arg_content) = - self.sess().source_map().span_to_snippet(positional_arg_to_replace) && positional_arg_content.starts_with(":") { + self.sess().source_map().span_to_snippet(positional_arg_to_replace) && positional_arg_content.starts_with(':') { positional_arg_to_replace.shrink_to_lo() } else { positional_arg_to_replace diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 8dc5ed2db7e4..8bd0b09ffc05 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1378,19 +1378,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let tcx = self.tcx; - let keys_and_jobs = tcx - .mir_keys(()) - .iter() - .filter_map(|&def_id| { - let (encode_const, encode_opt) = should_encode_mir(tcx, def_id); - if encode_const || encode_opt { - Some((def_id, encode_const, encode_opt)) - } else { - None - } - }) - .collect::>(); - for (def_id, encode_const, encode_opt) in keys_and_jobs.into_iter() { + let keys_and_jobs = tcx.mir_keys(()).iter().filter_map(|&def_id| { + let (encode_const, encode_opt) = should_encode_mir(tcx, def_id); + if encode_const || encode_opt { Some((def_id, encode_const, encode_opt)) } else { None } + }); + for (def_id, encode_const, encode_opt) in keys_and_jobs { debug_assert!(encode_const || encode_opt); debug!("EntryBuilder::encode_mir({:?})", def_id); diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 4fd6fe4e36c6..ab71fa0bc1d4 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1393,7 +1393,7 @@ impl<'a> Resolver<'a> { // If only some candidates are accessible, take just them if !candidates.iter().all(|v: &ImportSuggestion| !v.accessible) { - candidates = candidates.into_iter().filter(|x| x.accessible).collect(); + candidates.retain(|x| x.accessible) } candidates diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index 7db3065dee08..56bb71b5dcbd 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -429,7 +429,7 @@ mod cgroups { Some(b"") => Cgroup::V2, Some(controllers) if from_utf8(controllers) - .is_ok_and(|c| c.split(",").any(|c| c == "cpu")) => + .is_ok_and(|c| c.split(',').any(|c| c == "cpu")) => { Cgroup::V1 } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 7577c7196238..1e6f20d2b491 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -2367,9 +2367,9 @@ pub(crate) fn get_filtered_impls_for_reference<'a>( let Some(v) = shared.cache.impls.get(&def_id) else { return (Vec::new(), Vec::new(), Vec::new()) }; // Since there is no "direct implementation" on the reference primitive type, we filter out // every implementation which isn't a trait implementation. - let traits: Vec<_> = v.iter().filter(|i| i.inner_impl().trait_.is_some()).collect(); + let traits = v.iter().filter(|i| i.inner_impl().trait_.is_some()); let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) = - traits.into_iter().partition(|t| t.inner_impl().kind.is_auto()); + traits.partition(|t| t.inner_impl().kind.is_auto()); let (blanket_impl, concrete): (Vec<&Impl>, _) = concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket()); diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index f9abb46207d7..fc4d46fe6b6f 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -312,7 +312,7 @@ pub(super) fn write_shared( if line.starts_with(&prefix) { continue; } - if line.ends_with(",") { + if line.ends_with(',') { ret.push(line[..line.len() - 1].to_string()); } else { // No comma (it's the case for the last added crate line) From b76a012be16de964c242594afba4323997f436b2 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Sat, 3 Sep 2022 19:36:28 +0100 Subject: [PATCH 4141/5092] Rustdoc-Json: Add enum discriminant --- src/librustdoc/clean/mod.rs | 23 ++++++++-- src/librustdoc/clean/types.rs | 14 ++++-- src/librustdoc/clean/utils.rs | 34 +++++++++++---- src/librustdoc/fold.rs | 2 +- src/librustdoc/html/render/print_item.rs | 3 +- src/librustdoc/json/conversions.rs | 12 +++++- src/librustdoc/visit.rs | 2 +- src/rustdoc-json-types/lib.rs | 21 ++++++++- .../rustdoc-json/enums/discriminant/basic.rs | 12 ++++++ .../rustdoc-json/enums/discriminant/expr.rs | 39 +++++++++++++++++ .../rustdoc-json/enums/discriminant/limits.rs | 43 +++++++++++++++++++ .../discriminant/num_underscore_and_suffix.rs | 15 +++++++ .../only_some_have_discriminant.rs | 10 +++++ 13 files changed, 209 insertions(+), 21 deletions(-) create mode 100644 src/test/rustdoc-json/enums/discriminant/basic.rs create mode 100644 src/test/rustdoc-json/enums/discriminant/expr.rs create mode 100644 src/test/rustdoc-json/enums/discriminant/limits.rs create mode 100644 src/test/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs create mode 100644 src/test/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index ebf6c55ee35d..8cf9f46310bc 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1786,7 +1786,13 @@ pub(crate) fn clean_visibility(vis: ty::Visibility) -> Visibility { pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocContext<'tcx>) -> Item { let kind = match variant.ctor_kind { - CtorKind::Const => Variant::CLike, + CtorKind::Const => Variant::CLike(match variant.discr { + ty::VariantDiscr::Explicit(def_id) => Some(Discriminant { + expr: None, + value: print_evaluated_const(cx.tcx, def_id, false).unwrap(), + }), + ty::VariantDiscr::Relative(_) => None, + }), CtorKind::Fn => Variant::Tuple( variant.fields.iter().map(|field| clean_middle_field(field, cx)).collect(), ), @@ -1803,6 +1809,7 @@ pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocCont fn clean_variant_data<'tcx>( variant: &hir::VariantData<'tcx>, + disr_expr: &Option, cx: &mut DocContext<'tcx>, ) -> Variant { match variant { @@ -1813,7 +1820,17 @@ fn clean_variant_data<'tcx>( hir::VariantData::Tuple(..) => { Variant::Tuple(variant.fields().iter().map(|x| clean_field(x, cx)).collect()) } - hir::VariantData::Unit(..) => Variant::CLike, + hir::VariantData::Unit(..) => Variant::CLike(disr_expr.map(|disr| { + Discriminant { + expr: Some(print_const_expr(cx.tcx, disr.body)), + value: print_evaluated_const( + cx.tcx, + cx.tcx.hir().local_def_id(disr.hir_id).to_def_id(), + false, + ) + .unwrap(), + } + })), } } @@ -1967,7 +1984,7 @@ fn clean_maybe_renamed_item<'tcx>( } fn clean_variant<'tcx>(variant: &hir::Variant<'tcx>, cx: &mut DocContext<'tcx>) -> Item { - let kind = VariantItem(clean_variant_data(&variant.data, cx)); + let kind = VariantItem(clean_variant_data(&variant.data, &variant.disr_expr, cx)); let what_rustc_thinks = Item::from_hir_id_and_parts(variant.id, Some(variant.ident.name), kind, cx); // don't show `pub` for variants, which are always public diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 2808b400a0b5..8de9a80758e4 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2098,7 +2098,7 @@ impl Enum { #[derive(Clone, Debug)] pub(crate) enum Variant { - CLike, + CLike(Option), Tuple(Vec), Struct(VariantStruct), } @@ -2107,11 +2107,19 @@ impl Variant { pub(crate) fn has_stripped_entries(&self) -> Option { match *self { Self::Struct(ref struct_) => Some(struct_.has_stripped_entries()), - Self::CLike | Self::Tuple(_) => None, + Self::CLike(..) | Self::Tuple(_) => None, } } } +#[derive(Clone, Debug)] +pub(crate) struct Discriminant { + // In the case of cross crate re-exports, we don't have the nessesary information + // to reconstruct the expression of the discriminant, only the value. + pub(crate) expr: Option, + pub(crate) value: String, +} + /// Small wrapper around [`rustc_span::Span`] that adds helper methods /// and enforces calling [`rustc_span::Span::source_callsite()`]. #[derive(Copy, Clone, Debug)] @@ -2338,7 +2346,7 @@ impl ConstantKind { match *self { ConstantKind::TyConst { .. } | ConstantKind::Anonymous { .. } => None, ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => { - print_evaluated_const(tcx, def_id) + print_evaluated_const(tcx, def_id, true) } } } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index ac9ab3396167..a9d511ae11e8 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -261,7 +261,11 @@ pub(crate) fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String { } } -pub(crate) fn print_evaluated_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option { +pub(crate) fn print_evaluated_const( + tcx: TyCtxt<'_>, + def_id: DefId, + underscores_and_type: bool, +) -> Option { tcx.const_eval_poly(def_id).ok().and_then(|val| { let ty = tcx.type_of(def_id); match (val, ty.kind()) { @@ -269,7 +273,7 @@ pub(crate) fn print_evaluated_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option None, (ConstValue::Scalar(_), _) => { let const_ = mir::ConstantKind::from_value(val, ty); - Some(print_const_with_custom_print_scalar(tcx, const_)) + Some(print_const_with_custom_print_scalar(tcx, const_, underscores_and_type)) } _ => None, } @@ -302,23 +306,35 @@ fn format_integer_with_underscore_sep(num: &str) -> String { .collect() } -fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: mir::ConstantKind<'_>) -> String { +fn print_const_with_custom_print_scalar( + tcx: TyCtxt<'_>, + ct: mir::ConstantKind<'_>, + underscores_and_type: bool, +) -> String { // Use a slightly different format for integer types which always shows the actual value. // For all other types, fallback to the original `pretty_print_const`. match (ct, ct.ty().kind()) { (mir::ConstantKind::Val(ConstValue::Scalar(int), _), ty::Uint(ui)) => { - format!("{}{}", format_integer_with_underscore_sep(&int.to_string()), ui.name_str()) + if underscores_and_type { + format!("{}{}", format_integer_with_underscore_sep(&int.to_string()), ui.name_str()) + } else { + int.to_string() + } } (mir::ConstantKind::Val(ConstValue::Scalar(int), _), ty::Int(i)) => { let ty = tcx.lift(ct.ty()).unwrap(); let size = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size; let data = int.assert_bits(size); let sign_extended_data = size.sign_extend(data) as i128; - format!( - "{}{}", - format_integer_with_underscore_sep(&sign_extended_data.to_string()), - i.name_str() - ) + if underscores_and_type { + format!( + "{}{}", + format_integer_with_underscore_sep(&sign_extended_data.to_string()), + i.name_str() + ) + } else { + sign_extended_data.to_string() + } } _ => ct.to_string(), } diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index 6b7e67e2ce34..ed702f5c4a9c 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -46,7 +46,7 @@ pub(crate) trait DocFolder: Sized { let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect(); VariantItem(Variant::Tuple(fields)) } - Variant::CLike => VariantItem(Variant::CLike), + Variant::CLike(disr) => VariantItem(Variant::CLike(disr)), }, ExternCrateItem { src: _ } | ImportItem(_) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index d63d4c2d159b..cfa4509428f1 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1203,7 +1203,8 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: let name = v.name.unwrap(); match *v.kind { clean::VariantItem(ref var) => match var { - clean::Variant::CLike => write!(w, "{}", name), + // FIXME(#101337): Show discriminant + clean::Variant::CLike(..) => write!(w, "{}", name), clean::Variant::Tuple(ref s) => { write!(w, "{}(", name); print_tuple_struct_fields(w, cx, s); diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 20b9eb1c27e9..cc5c391d6bd5 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -662,7 +662,7 @@ impl FromWithTcx for Variant { fn from_tcx(variant: clean::Variant, tcx: TyCtxt<'_>) -> Self { use clean::Variant::*; match variant { - CLike => Variant::Plain, + CLike(disr) => Variant::Plain(disr.map(convert_discriminant)), Tuple(fields) => Variant::Tuple( fields .into_iter() @@ -678,6 +678,16 @@ impl FromWithTcx for Variant { } } +fn convert_discriminant(disr: clean::Discriminant) -> Discriminant { + Discriminant { + // expr is only none if going throught the inlineing path, which gets + // `rustc_middle` types, not `rustc_hir`, but because JSON never inlines + // the expr is always some. + expr: disr.expr.unwrap(), + value: disr.value, + } +} + impl FromWithTcx for Import { fn from_tcx(import: clean::Import, tcx: TyCtxt<'_>) -> Self { use clean::ImportKind::*; diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs index 0bb41977c97c..c40274394f34 100644 --- a/src/librustdoc/visit.rs +++ b/src/librustdoc/visit.rs @@ -20,7 +20,7 @@ pub(crate) trait DocVisitor: Sized { VariantItem(i) => match i { Variant::Struct(j) => j.fields.iter().for_each(|x| self.visit_item(x)), Variant::Tuple(fields) => fields.iter().for_each(|x| self.visit_item(x)), - Variant::CLike => {} + Variant::CLike(_) => {} }, ExternCrateItem { src: _ } | ImportItem(_) diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 7dcad66b1f99..d25f68b3743d 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -9,7 +9,7 @@ use std::path::PathBuf; use serde::{Deserialize, Serialize}; /// rustdoc format-version. -pub const FORMAT_VERSION: u32 = 18; +pub const FORMAT_VERSION: u32 = 19; /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information /// about the language items in the local crate, as well as info about external items to allow @@ -308,11 +308,28 @@ pub struct Enum { #[serde(rename_all = "snake_case")] #[serde(tag = "variant_kind", content = "variant_inner")] pub enum Variant { - Plain, + Plain(Option), Tuple(Vec), Struct(Vec), } +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct Discriminant { + /// The expression that produced the discriminant. + /// + /// Unlike `value`, this preserves the original formatting (eg suffixes, + /// hexadecimal, and underscores), making it unsuitable to be machine + /// interpreted. + /// + /// In some cases, when the value is to complex, this may be `"{ _ }"`. + /// When this occurs is unstable, and may change without notice. + pub expr: String, + /// The numerical value of the discriminant. Stored as a string due to + /// JSON's poor support for large integers, and the fact that it would need + /// to store from [`i128::MIN`] to [`u128::MAX`]. + pub value: String, +} + #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum StructType { diff --git a/src/test/rustdoc-json/enums/discriminant/basic.rs b/src/test/rustdoc-json/enums/discriminant/basic.rs new file mode 100644 index 000000000000..8c221615aa75 --- /dev/null +++ b/src/test/rustdoc-json/enums/discriminant/basic.rs @@ -0,0 +1,12 @@ +#[repr(i8)] +pub enum Ordering { + // @is "$.index[*][?(@.name=='Less')].inner.variant_inner.expr" '"-1"' + // @is "$.index[*][?(@.name=='Less')].inner.variant_inner.value" '"-1"' + Less = -1, + // @is "$.index[*][?(@.name=='Equal')].inner.variant_inner.expr" '"0"' + // @is "$.index[*][?(@.name=='Equal')].inner.variant_inner.value" '"0"' + Equal = 0, + // @is "$.index[*][?(@.name=='Greater')].inner.variant_inner.expr" '"1"' + // @is "$.index[*][?(@.name=='Greater')].inner.variant_inner.value" '"1"' + Greater = 1, +} diff --git a/src/test/rustdoc-json/enums/discriminant/expr.rs b/src/test/rustdoc-json/enums/discriminant/expr.rs new file mode 100644 index 000000000000..235b0b47381f --- /dev/null +++ b/src/test/rustdoc-json/enums/discriminant/expr.rs @@ -0,0 +1,39 @@ +pub enum Foo { + // @is "$.index[*][?(@.name=='Addition')].inner.variant_inner.value" '"0"' + // @is "$.index[*][?(@.name=='Addition')].inner.variant_inner.expr" '"{ _ }"' + Addition = 0 + 0, + // @is "$.index[*][?(@.name=='Bin')].inner.variant_inner.value" '"1"' + // @is "$.index[*][?(@.name=='Bin')].inner.variant_inner.expr" '"0b1"' + Bin = 0b1, + // @is "$.index[*][?(@.name=='Oct')].inner.variant_inner.value" '"2"' + // @is "$.index[*][?(@.name=='Oct')].inner.variant_inner.expr" '"0o2"' + Oct = 0o2, + // @is "$.index[*][?(@.name=='PubConst')].inner.variant_inner.value" '"3"' + // @is "$.index[*][?(@.name=='PubConst')].inner.variant_inner.expr" '"THREE"' + PubConst = THREE, + // @is "$.index[*][?(@.name=='Hex')].inner.variant_inner.value" '"4"' + // @is "$.index[*][?(@.name=='Hex')].inner.variant_inner.expr" '"0x4"' + Hex = 0x4, + // @is "$.index[*][?(@.name=='Cast')].inner.variant_inner.value" '"5"' + // @is "$.index[*][?(@.name=='Cast')].inner.variant_inner.expr" '"{ _ }"' + Cast = 5 as isize, + // @is "$.index[*][?(@.name=='PubCall')].inner.variant_inner.value" '"6"' + // @is "$.index[*][?(@.name=='PubCall')].inner.variant_inner.expr" '"{ _ }"' + PubCall = six(), + // @is "$.index[*][?(@.name=='PrivCall')].inner.variant_inner.value" '"7"' + // @is "$.index[*][?(@.name=='PrivCall')].inner.variant_inner.expr" '"{ _ }"' + PrivCall = seven(), + // @is "$.index[*][?(@.name=='PrivConst')].inner.variant_inner.value" '"8"' + // @is "$.index[*][?(@.name=='PrivConst')].inner.variant_inner.expr" '"EIGHT"' + PrivConst = EIGHT, +} + +pub const THREE: isize = 3; +const EIGHT: isize = 8; + +pub const fn six() -> isize { + 6 +} +const fn seven() -> isize { + 7 +} diff --git a/src/test/rustdoc-json/enums/discriminant/limits.rs b/src/test/rustdoc-json/enums/discriminant/limits.rs new file mode 100644 index 000000000000..8df73d78d237 --- /dev/null +++ b/src/test/rustdoc-json/enums/discriminant/limits.rs @@ -0,0 +1,43 @@ +// ignore-tidy-linelength +#![feature(repr128)] +#![allow(incomplete_features)] + +#[repr(u64)] +pub enum U64 { + // @is "$.index[*][?(@.name=='U64Min')].inner.variant_inner.value" '"0"' + // @is "$.index[*][?(@.name=='U64Min')].inner.variant_inner.expr" '"u64::MIN"' + U64Min = u64::MIN, + // @is "$.index[*][?(@.name=='U64Max')].inner.variant_inner.value" '"18446744073709551615"' + // @is "$.index[*][?(@.name=='U64Max')].inner.variant_inner.expr" '"u64::MAX"' + U64Max = u64::MAX, +} + +#[repr(i64)] +pub enum I64 { + // @is "$.index[*][?(@.name=='I64Min')].inner.variant_inner.value" '"-9223372036854775808"' + // @is "$.index[*][?(@.name=='I64Min')].inner.variant_inner.expr" '"i64::MIN"' + I64Min = i64::MIN, + // @is "$.index[*][?(@.name=='I64Max')].inner.variant_inner.value" '"9223372036854775807"' + // @is "$.index[*][?(@.name=='I64Max')].inner.variant_inner.expr" '"i64::MAX"' + I64Max = i64::MAX, +} + +#[repr(u128)] +pub enum U128 { + // @is "$.index[*][?(@.name=='U128Min')].inner.variant_inner.value" '"0"' + // @is "$.index[*][?(@.name=='U128Min')].inner.variant_inner.expr" '"u128::MIN"' + U128Min = u128::MIN, + // @is "$.index[*][?(@.name=='U128Max')].inner.variant_inner.value" '"340282366920938463463374607431768211455"' + // @is "$.index[*][?(@.name=='U128Max')].inner.variant_inner.expr" '"u128::MAX"' + U128Max = u128::MAX, +} + +#[repr(i128)] +pub enum I128 { + // @is "$.index[*][?(@.name=='I128Min')].inner.variant_inner.value" '"-170141183460469231731687303715884105728"' + // @is "$.index[*][?(@.name=='I128Min')].inner.variant_inner.expr" '"i128::MIN"' + I128Min = i128::MIN, + // @is "$.index[*][?(@.name=='I128Max')].inner.variant_inner.value" '"170141183460469231731687303715884105727"' + // @is "$.index[*][?(@.name=='I128Max')].inner.variant_inner.expr" '"i128::MAX"' + I128Max = i128::MAX, +} diff --git a/src/test/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs b/src/test/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs new file mode 100644 index 000000000000..3417baa0760e --- /dev/null +++ b/src/test/rustdoc-json/enums/discriminant/num_underscore_and_suffix.rs @@ -0,0 +1,15 @@ +#[repr(u32)] +pub enum Foo { + // @is "$.index[*][?(@.name=='Basic')].inner.variant_inner.value" '"0"' + // @is "$.index[*][?(@.name=='Basic')].inner.variant_inner.expr" '"0"' + Basic = 0, + // @is "$.index[*][?(@.name=='Suffix')].inner.variant_inner.value" '"10"' + // @is "$.index[*][?(@.name=='Suffix')].inner.variant_inner.expr" '"10u32"' + Suffix = 10u32, + // @is "$.index[*][?(@.name=='Underscore')].inner.variant_inner.value" '"100"' + // @is "$.index[*][?(@.name=='Underscore')].inner.variant_inner.expr" '"1_0_0"' + Underscore = 1_0_0, + // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.variant_inner.value" '"1000"' + // @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.variant_inner.expr" '"1_0_0_0u32"' + SuffixUnderscore = 1_0_0_0u32, +} diff --git a/src/test/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs b/src/test/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs new file mode 100644 index 000000000000..6af944a2219e --- /dev/null +++ b/src/test/rustdoc-json/enums/discriminant/only_some_have_discriminant.rs @@ -0,0 +1,10 @@ +pub enum Foo { + // @is "$.index[*][?(@.name=='Has')].inner.variant_inner" '{"expr":"0", "value":"0"}' + Has = 0, + // @is "$.index[*][?(@.name=='Doesnt')].inner.variant_inner" null + Doesnt, + // @is "$.index[*][?(@.name=='AlsoDoesnt')].inner.variant_inner" null + AlsoDoesnt, + // @is "$.index[*][?(@.name=='AlsoHas')].inner.variant_inner" '{"expr":"44", "value":"44"}' + AlsoHas = 44, +} From cee90dd77361406b94d8e1b8eca6bf657ba88ee5 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 2 Sep 2022 15:44:06 -0700 Subject: [PATCH 4142/5092] rustdoc: remove `.impl-items { flex-basis }` CSS, not in flex container Added in 34bd2b845b3acd84c5a9bddae3ff8081c19ec5e9 For this to actually do anything, [according to MDN] (and Firefox Dev Tools), it must be a "flex item", which only happens if its a direct child of a node with `display: flex` on it. It seems like it could not have worked at the time when this rule was added, because the only items in `rustdoc.css` with `display: flex` active were: * `#help` This should not contain anything like this. * `.impl-items h4, h4.impl, h3.impl` These are all headers, so they shouldn't contain `.impl-items` either. * `.content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant` Associated constants and methods definitely shouldn't contain a list of impl items, and the `.type` class seems to refer to type aliases, which, when shown inside of an impl, only show a link to the aliased type. [according to MDN]: https://developer.mozilla.org/en-US/docs/Web/CSS/flex-basis Nowadays, `display: flex` is a lot more prolific, but `.impl-items` still seems to only be used in plain block parents: * If it's not a trait impl, then it's nested below a `
` with an id but no class, added in a5216cf67d93de97091b41ecba85de2e08f39863. This will be `display: block`, probably. For example, [vec deref] * Inherent impls also get a `
` tag, for example [vec impl], and they are also wrapped by their own non-flexbox `
` tag. * If it's a tait implementation, then it's also nested below a `
` container, like [deref cstring]. [vec impl]: https://doc.rust-lang.org/1.63.0/std/vec/struct.Vec.html#impl [vec deref]: https://doc.rust-lang.org/1.63.0/std/vec/struct.Vec.html#deref-methods-%5BT%5D [deref cstring]: https://doc.rust-lang.org/1.63.0/std/ops/trait.Deref.html#impl-Deref Also, this would imply that trait items ought to take up as much space as possible, pushing everything else to the edge of the screen. If this is nested directly below the `.rustdoc` container, which has a row basis, that would be bad. --- src/librustdoc/html/static/css/rustdoc.css | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 38b6ebd66d39..fddff771f1cf 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -778,10 +778,6 @@ pre, .rustdoc.source .example-wrap { margin-bottom: .6em; } -.impl-items { - flex-basis: 100%; -} - #main-content > .item-info { margin-top: 0; margin-left: 0; From 4f30af52738c163c39e1d928c36664e627ee31db Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 3 Sep 2022 17:38:42 -0400 Subject: [PATCH 4143/5092] rustup: bring in Miri backtrace-rs pruning fix --- rust-version | 2 +- tests/panic/panic1.stderr | 22 ---------------------- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/rust-version b/rust-version index 5ce9544acc7b..0c6d053e9b4c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -47d1cdb0bcac8e417071ce1929d261efe2399ae2 +dec689432fac6720b2f18101ac28a21add98b1b8 diff --git a/tests/panic/panic1.stderr b/tests/panic/panic1.stderr index f86ce187b2c9..15834d58bc6e 100644 --- a/tests/panic/panic1.stderr +++ b/tests/panic/panic1.stderr @@ -6,26 +6,4 @@ stack backtrace: at $DIR/panic1.rs:LL:CC 2: >::call_once - shim(fn()) at RUSTLIB/core/src/ops/function.rs:LL:CC - 3: std::rt::lang_start::{closure#0} - at RUSTLIB/std/src/rt.rs:LL:CC - 4: std::ops::function::impls::call_once - at RUSTLIB/core/src/ops/function.rs:LL:CC - 5: std::panicking::r#try::do_call - at RUSTLIB/std/src/panicking.rs:LL:CC - 6: std::panicking::r#try - at RUSTLIB/std/src/panicking.rs:LL:CC - 7: std::panic::catch_unwind - at RUSTLIB/std/src/panic.rs:LL:CC - 8: std::rt::lang_start_internal::{closure#2} - at RUSTLIB/std/src/rt.rs:LL:CC - 9: std::panicking::r#try::do_call - at RUSTLIB/std/src/panicking.rs:LL:CC - 10: std::panicking::r#try - at RUSTLIB/std/src/panicking.rs:LL:CC - 11: std::panic::catch_unwind - at RUSTLIB/std/src/panic.rs:LL:CC - 12: std::rt::lang_start_internal - at RUSTLIB/std/src/rt.rs:LL:CC - 13: std::rt::lang_start - at RUSTLIB/std/src/rt.rs:LL:CC note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. From 69721defc21e9704c39aec65dea9e2be4377cb1b Mon Sep 17 00:00:00 2001 From: Christopher Durham Date: Sat, 3 Sep 2022 16:47:12 -0500 Subject: [PATCH 4144/5092] Forbid mixing `System` with sytem allocator calls --- library/std/src/alloc.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index a05e0db3af71..61c1ff578b2c 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -68,7 +68,10 @@ pub use alloc_crate::alloc::*; /// The default memory allocator provided by the operating system. /// /// This is based on `malloc` on Unix platforms and `HeapAlloc` on Windows, -/// plus related functions. +/// plus related functions. However, it is not valid to mix use of the backing +/// system allocator with `System`, as this implementation may include extra +/// work, such as to serve alignment requests greater than the alignment +/// provided directly by the backing system allocator. /// /// This type implements the `GlobalAlloc` trait and Rust programs by default /// work as if they had this definition: From 563a75b6e3201d200b975cc05b7b32d5ef2e5608 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Fri, 2 Sep 2022 21:22:43 -0400 Subject: [PATCH 4145/5092] Add a Machine hook for inline assembly --- compiler/rustc_const_eval/src/interpret/machine.rs | 10 ++++++++++ .../rustc_const_eval/src/interpret/terminator.rs | 13 +++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 5aabb14fba88..530e252b7c07 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -6,6 +6,7 @@ use std::borrow::{Borrow, Cow}; use std::fmt::Debug; use std::hash::Hash; +use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_middle::mir; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::DefId; @@ -323,6 +324,15 @@ pub trait Machine<'mir, 'tcx>: Sized { kind: Option>, ) -> InterpResult<'tcx, Cow<'b, Allocation>>; + fn eval_inline_asm( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _template: &'tcx [InlineAsmTemplatePiece], + _operands: &[mir::InlineAsmOperand<'tcx>], + _options: InlineAsmOptions, + ) -> InterpResult<'tcx> { + throw_unsup_format!("inline assembly is not supported") + } + /// Hook for performing extra checks on a memory read access. /// /// Takes read-only access to the allocation so we can keep all the memory read diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index ea366eba7724..50a82aa0e72c 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -1,5 +1,6 @@ use std::borrow::Cow; +use rustc_ast::ast::InlineAsmOptions; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf}; use rustc_middle::ty::Instance; use rustc_middle::{ @@ -166,8 +167,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { terminator.kind ), - // Inline assembly can't be interpreted. - InlineAsm { .. } => throw_unsup_format!("inline assembly is not supported"), + InlineAsm { template, ref operands, options, destination, .. } => { + M::eval_inline_asm(self, template, operands, options)?; + if options.contains(InlineAsmOptions::NORETURN) { + throw_ub_format!("returned from noreturn inline assembly"); + } + self.go_to_block( + destination + .expect("InlineAsm terminators without noreturn must have a destination"), + ) + } } Ok(()) From 3e743a064ec341548f2dfb6dafddc2b3d2d66c7f Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 3 Sep 2022 15:07:48 -0700 Subject: [PATCH 4146/5092] rustdoc: remove redundant mobile-sized `.source nav:not(.sidebar).sub` It's redundant because there's already a selector `.source nav.sub` with exactly the same margin-left at line 796. This selector was added in 1e98fb10274ea0245f865ddb1e295e454382000b, along with an identical desktop selector, but that desktop selector was removed in 6a5f8b1aef1417d7dc85b5d0a229d2db1930eb7c as part of a larger simplification. --- src/librustdoc/html/static/css/rustdoc.css | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 38b6ebd66d39..21b5c13e7149 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1887,10 +1887,6 @@ in storage.js plus the media query with (min-width: 701px) background-color: var(--sidebar-background-color); } - .source nav:not(.sidebar).sub { - margin-left: 32px; - } - .content { margin-left: 0px; } From c23fe81764281c35b58dcf578a494076bf2325c0 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 1 Sep 2022 19:52:39 +0000 Subject: [PATCH 4147/5092] Use head span for rustc_on_unimplemented's enclosing_scope attr --- .../src/traits/error_reporting/mod.rs | 2 +- .../on-unimplemented/enclosing-scope.stderr | 69 +++++++----------- .../disallowed-positions.stderr | 48 ++++-------- .../ui/try-trait/bad-interconversion.stderr | 73 +++++++------------ src/test/ui/try-trait/option-to-result.stderr | 24 +++--- .../try-on-option-diagnostics.stderr | 47 +++++------- src/test/ui/try-trait/try-on-option.stderr | 24 +++--- .../ui/try-trait/try-operator-on-main.stderr | 30 +++----- 8 files changed, 120 insertions(+), 197 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 99046bd126f9..8fd2e1de7a16 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -526,7 +526,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }); let enclosing_scope_span = - tcx.hir().span_with_body(tcx.hir().local_def_id_to_hir_id(body)); + tcx.hir().span(tcx.hir().local_def_id_to_hir_id(body)); err.span_label(enclosing_scope_span, s); } diff --git a/src/test/ui/on-unimplemented/enclosing-scope.stderr b/src/test/ui/on-unimplemented/enclosing-scope.stderr index 67759d02a161..4fe2ecd1e381 100644 --- a/src/test/ui/on-unimplemented/enclosing-scope.stderr +++ b/src/test/ui/on-unimplemented/enclosing-scope.stderr @@ -1,17 +1,12 @@ error[E0277]: the trait bound `Foo: Trait` is not satisfied --> $DIR/enclosing-scope.rs:14:11 | -LL | let x = || { - | _____________- -LL | | f(Foo{}); - | | - ^^^^^ the trait `Trait` is not implemented for `Foo` - | | | - | | required by a bound introduced by this call -LL | | let y = || { -LL | | f(Foo{}); -LL | | }; -LL | | }; - | |_____- in this scope +LL | let x = || { + | -- in this scope +LL | f(Foo{}); + | - ^^^^^ the trait `Trait` is not implemented for `Foo` + | | + | required by a bound introduced by this call | note: required by a bound in `f` --> $DIR/enclosing-scope.rs:10:9 @@ -22,14 +17,12 @@ LL | fn f(x: T) {} error[E0277]: the trait bound `Foo: Trait` is not satisfied --> $DIR/enclosing-scope.rs:16:15 | -LL | let y = || { - | _________________- -LL | | f(Foo{}); - | | - ^^^^^ the trait `Trait` is not implemented for `Foo` - | | | - | | required by a bound introduced by this call -LL | | }; - | |_________- in this scope +LL | let y = || { + | -- in this scope +LL | f(Foo{}); + | - ^^^^^ the trait `Trait` is not implemented for `Foo` + | | + | required by a bound introduced by this call | note: required by a bound in `f` --> $DIR/enclosing-scope.rs:10:9 @@ -40,19 +33,13 @@ LL | fn f(x: T) {} error[E0277]: the trait bound `Foo: Trait` is not satisfied --> $DIR/enclosing-scope.rs:22:15 | -LL | / fn main() { -LL | | let x = || { -LL | | f(Foo{}); -LL | | let y = || { -... | -LL | | f(Foo{}); - | | - ^^^^^ the trait `Trait` is not implemented for `Foo` - | | | - | | required by a bound introduced by this call -... | -LL | | f(Foo{}); -LL | | } - | |_- in this scope +LL | fn main() { + | --------- in this scope +... +LL | f(Foo{}); + | - ^^^^^ the trait `Trait` is not implemented for `Foo` + | | + | required by a bound introduced by this call | note: required by a bound in `f` --> $DIR/enclosing-scope.rs:10:9 @@ -63,17 +50,13 @@ LL | fn f(x: T) {} error[E0277]: the trait bound `Foo: Trait` is not satisfied --> $DIR/enclosing-scope.rs:26:7 | -LL | / fn main() { -LL | | let x = || { -LL | | f(Foo{}); -LL | | let y = || { -... | -LL | | f(Foo{}); - | | - ^^^^^ the trait `Trait` is not implemented for `Foo` - | | | - | | required by a bound introduced by this call -LL | | } - | |_- in this scope +LL | fn main() { + | --------- in this scope +... +LL | f(Foo{}); + | - ^^^^^ the trait `Trait` is not implemented for `Foo` + | | + | required by a bound introduced by this call | note: required by a bound in `f` --> $DIR/enclosing-scope.rs:10:9 diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr index fce0cdfe0d56..bc06fde49e99 100644 --- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr +++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr @@ -1493,17 +1493,11 @@ LL | if (let 0 = 0)? {} error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/disallowed-positions.rs:132:19 | -LL | / fn nested_within_if_expr() { -LL | | if &let 0 = 0 {} -LL | | -LL | | -... | -LL | | if (let 0 = 0)? {} - | | ^ cannot use the `?` operator in a function that returns `()` -... | -LL | | -LL | | } - | |_- this function should return `Result` or `Option` to accept `?` +LL | fn nested_within_if_expr() { + | -------------------------- this function should return `Result` or `Option` to accept `?` +... +LL | if (let 0 = 0)? {} + | ^ cannot use the `?` operator in a function that returns `()` | = help: the trait `FromResidual<_>` is not implemented for `()` @@ -1693,17 +1687,11 @@ LL | while (let 0 = 0)? {} error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/disallowed-positions.rs:224:22 | -LL | / fn nested_within_while_expr() { -LL | | while &let 0 = 0 {} -LL | | -LL | | -... | -LL | | while (let 0 = 0)? {} - | | ^ cannot use the `?` operator in a function that returns `()` -... | -LL | | -LL | | } - | |_- this function should return `Result` or `Option` to accept `?` +LL | fn nested_within_while_expr() { + | ----------------------------- this function should return `Result` or `Option` to accept `?` +... +LL | while (let 0 = 0)? {} + | ^ cannot use the `?` operator in a function that returns `()` | = help: the trait `FromResidual<_>` is not implemented for `()` @@ -1881,17 +1869,11 @@ LL | (let 0 = 0)?; error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/disallowed-positions.rs:325:16 | -LL | / fn outside_if_and_while_expr() { -LL | | &let 0 = 0; -LL | | -LL | | -... | -LL | | (let 0 = 0)?; - | | ^ cannot use the `?` operator in a function that returns `()` -... | -LL | | -LL | | } - | |_- this function should return `Result` or `Option` to accept `?` +LL | fn outside_if_and_while_expr() { + | ------------------------------ this function should return `Result` or `Option` to accept `?` +... +LL | (let 0 = 0)?; + | ^ cannot use the `?` operator in a function that returns `()` | = help: the trait `FromResidual<_>` is not implemented for `()` diff --git a/src/test/ui/try-trait/bad-interconversion.stderr b/src/test/ui/try-trait/bad-interconversion.stderr index 529f5f16c8fc..27e6a603acd9 100644 --- a/src/test/ui/try-trait/bad-interconversion.stderr +++ b/src/test/ui/try-trait/bad-interconversion.stderr @@ -22,13 +22,10 @@ LL | Ok(Err(123_i32)?) error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result` --> $DIR/bad-interconversion.rs:11:12 | -LL | / fn option_to_result() -> Result { -LL | | Some(3)?; - | | ^ use `.ok_or(...)?` to provide an error compatible with `Result` -LL | | -LL | | Ok(10) -LL | | } - | |_- this function returns a `Result` +LL | fn option_to_result() -> Result { + | -------------------------------------------- this function returns a `Result` +LL | Some(3)?; + | ^ use `.ok_or(...)?` to provide an error compatible with `Result` | = help: the trait `FromResidual>` is not implemented for `Result` = help: the following other types implement trait `FromResidual`: @@ -38,12 +35,10 @@ LL | | } error[E0277]: the `?` operator can only be used on `Result`s in a function that returns `Result` --> $DIR/bad-interconversion.rs:17:31 | -LL | / fn control_flow_to_result() -> Result { -LL | | Ok(ControlFlow::Break(123)?) - | | ^ this `?` produces `ControlFlow<{integer}, Infallible>`, which is incompatible with `Result` -LL | | -LL | | } - | |_- this function returns a `Result` +LL | fn control_flow_to_result() -> Result { + | -------------------------------------------------- this function returns a `Result` +LL | Ok(ControlFlow::Break(123)?) + | ^ this `?` produces `ControlFlow<{integer}, Infallible>`, which is incompatible with `Result` | = help: the trait `FromResidual>` is not implemented for `Result` = help: the following other types implement trait `FromResidual`: @@ -53,12 +48,10 @@ LL | | } error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option` --> $DIR/bad-interconversion.rs:22:22 | -LL | / fn result_to_option() -> Option { -LL | | Some(Err("hello")?) - | | ^ use `.ok()?` if you want to discard the `Result` error information -LL | | -LL | | } - | |_- this function returns an `Option` +LL | fn result_to_option() -> Option { + | ------------------------------------ this function returns an `Option` +LL | Some(Err("hello")?) + | ^ use `.ok()?` if you want to discard the `Result` error information | = help: the trait `FromResidual>` is not implemented for `Option` = help: the following other types implement trait `FromResidual`: @@ -68,12 +61,10 @@ LL | | } error[E0277]: the `?` operator can only be used on `Option`s in a function that returns `Option` --> $DIR/bad-interconversion.rs:27:33 | -LL | / fn control_flow_to_option() -> Option { -LL | | Some(ControlFlow::Break(123)?) - | | ^ this `?` produces `ControlFlow<{integer}, Infallible>`, which is incompatible with `Option` -LL | | -LL | | } - | |_- this function returns an `Option` +LL | fn control_flow_to_option() -> Option { + | ------------------------------------------ this function returns an `Option` +LL | Some(ControlFlow::Break(123)?) + | ^ this `?` produces `ControlFlow<{integer}, Infallible>`, which is incompatible with `Option` | = help: the trait `FromResidual>` is not implemented for `Option` = help: the following other types implement trait `FromResidual`: @@ -83,12 +74,10 @@ LL | | } error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow` --> $DIR/bad-interconversion.rs:32:39 | -LL | / fn result_to_control_flow() -> ControlFlow { -LL | | ControlFlow::Continue(Err("hello")?) - | | ^ this `?` produces `Result`, which is incompatible with `ControlFlow` -LL | | -LL | | } - | |_- this function returns a `ControlFlow` +LL | fn result_to_control_flow() -> ControlFlow { + | -------------------------------------------------- this function returns a `ControlFlow` +LL | ControlFlow::Continue(Err("hello")?) + | ^ this `?` produces `Result`, which is incompatible with `ControlFlow` | = help: the trait `FromResidual>` is not implemented for `ControlFlow` = help: the trait `FromResidual` is implemented for `ControlFlow` @@ -96,13 +85,10 @@ LL | | } error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow` --> $DIR/bad-interconversion.rs:37:12 | -LL | / fn option_to_control_flow() -> ControlFlow { -LL | | Some(3)?; - | | ^ this `?` produces `Option`, which is incompatible with `ControlFlow` -LL | | -LL | | ControlFlow::Break(10) -LL | | } - | |_- this function returns a `ControlFlow` +LL | fn option_to_control_flow() -> ControlFlow { + | ----------------------------------------------- this function returns a `ControlFlow` +LL | Some(3)?; + | ^ this `?` produces `Option`, which is incompatible with `ControlFlow` | = help: the trait `FromResidual>` is not implemented for `ControlFlow` = help: the trait `FromResidual` is implemented for `ControlFlow` @@ -110,13 +96,10 @@ LL | | } error[E0277]: the `?` operator in a function that returns `ControlFlow` can only be used on other `ControlFlow`s (with the same Break type) --> $DIR/bad-interconversion.rs:43:29 | -LL | / fn control_flow_to_control_flow() -> ControlFlow { -LL | | ControlFlow::Break(4_u8)?; - | | ^ this `?` produces `ControlFlow`, which is incompatible with `ControlFlow` -LL | | -LL | | ControlFlow::Continue(()) -LL | | } - | |_- this function returns a `ControlFlow` +LL | fn control_flow_to_control_flow() -> ControlFlow { + | ----------------------------------------------------- this function returns a `ControlFlow` +LL | ControlFlow::Break(4_u8)?; + | ^ this `?` produces `ControlFlow`, which is incompatible with `ControlFlow` | = help: the trait `FromResidual>` is not implemented for `ControlFlow` = note: unlike `Result`, there's no `From`-conversion performed for `ControlFlow` diff --git a/src/test/ui/try-trait/option-to-result.stderr b/src/test/ui/try-trait/option-to-result.stderr index ae5c3ad62828..fabc1ff2c762 100644 --- a/src/test/ui/try-trait/option-to-result.stderr +++ b/src/test/ui/try-trait/option-to-result.stderr @@ -1,13 +1,11 @@ error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result` --> $DIR/option-to-result.rs:5:6 | -LL | / fn test_result() -> Result<(),()> { -LL | | let a:Option<()> = Some(()); -LL | | a?; - | | ^ use `.ok_or(...)?` to provide an error compatible with `Result<(), ()>` -LL | | Ok(()) -LL | | } - | |_- this function returns a `Result` +LL | fn test_result() -> Result<(),()> { + | --------------------------------- this function returns a `Result` +LL | let a:Option<()> = Some(()); +LL | a?; + | ^ use `.ok_or(...)?` to provide an error compatible with `Result<(), ()>` | = help: the trait `FromResidual>` is not implemented for `Result<(), ()>` = help: the following other types implement trait `FromResidual`: @@ -17,13 +15,11 @@ LL | | } error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option` --> $DIR/option-to-result.rs:11:6 | -LL | / fn test_option() -> Option{ -LL | | let a:Result = Ok(5); -LL | | a?; - | | ^ use `.ok()?` if you want to discard the `Result` error information -LL | | Some(5) -LL | | } - | |_- this function returns an `Option` +LL | fn test_option() -> Option{ + | ------------------------------- this function returns an `Option` +LL | let a:Result = Ok(5); +LL | a?; + | ^ use `.ok()?` if you want to discard the `Result` error information | = help: the trait `FromResidual>` is not implemented for `Option` = help: the following other types implement trait `FromResidual`: diff --git a/src/test/ui/try-trait/try-on-option-diagnostics.stderr b/src/test/ui/try-trait/try-on-option-diagnostics.stderr index a6badd190388..9ee540c79fdd 100644 --- a/src/test/ui/try-trait/try-on-option-diagnostics.stderr +++ b/src/test/ui/try-trait/try-on-option-diagnostics.stderr @@ -1,51 +1,44 @@ error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/try-on-option-diagnostics.rs:7:6 | -LL | / fn a_function() -> u32 { -LL | | let x: Option = None; -LL | | x?; - | | ^ cannot use the `?` operator in a function that returns `u32` -LL | | 22 -LL | | } - | |_- this function should return `Result` or `Option` to accept `?` +LL | fn a_function() -> u32 { + | ---------------------- this function should return `Result` or `Option` to accept `?` +LL | let x: Option = None; +LL | x?; + | ^ cannot use the `?` operator in a function that returns `u32` | = help: the trait `FromResidual>` is not implemented for `u32` error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/try-on-option-diagnostics.rs:14:10 | -LL | let a_closure = || { - | _____________________- -LL | | let x: Option = None; -LL | | x?; - | | ^ cannot use the `?` operator in a closure that returns `{integer}` -LL | | 22 -LL | | }; - | |_____- this function should return `Result` or `Option` to accept `?` +LL | let a_closure = || { + | -- this function should return `Result` or `Option` to accept `?` +LL | let x: Option = None; +LL | x?; + | ^ cannot use the `?` operator in a closure that returns `{integer}` | = help: the trait `FromResidual>` is not implemented for `{integer}` error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/try-on-option-diagnostics.rs:26:14 | -LL | / fn a_method() { -LL | | let x: Option = None; -LL | | x?; - | | ^ cannot use the `?` operator in a method that returns `()` -LL | | } - | |_________- this function should return `Result` or `Option` to accept `?` +LL | fn a_method() { + | ------------- this function should return `Result` or `Option` to accept `?` +LL | let x: Option = None; +LL | x?; + | ^ cannot use the `?` operator in a method that returns `()` | = help: the trait `FromResidual>` is not implemented for `()` error[E0277]: the `?` operator can only be used in a trait method that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/try-on-option-diagnostics.rs:39:14 | -LL | / fn a_trait_method() { -LL | | let x: Option = None; -LL | | x?; - | | ^ cannot use the `?` operator in a trait method that returns `()` -LL | | } - | |_________- this function should return `Result` or `Option` to accept `?` +LL | fn a_trait_method() { + | ------------------- this function should return `Result` or `Option` to accept `?` +LL | let x: Option = None; +LL | x?; + | ^ cannot use the `?` operator in a trait method that returns `()` | = help: the trait `FromResidual>` is not implemented for `()` diff --git a/src/test/ui/try-trait/try-on-option.stderr b/src/test/ui/try-trait/try-on-option.stderr index ba85a7cada23..fad6a1fe8237 100644 --- a/src/test/ui/try-trait/try-on-option.stderr +++ b/src/test/ui/try-trait/try-on-option.stderr @@ -1,13 +1,11 @@ error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result` --> $DIR/try-on-option.rs:5:6 | -LL | / fn foo() -> Result { -LL | | let x: Option = None; -LL | | x?; - | | ^ use `.ok_or(...)?` to provide an error compatible with `Result` -LL | | Ok(22) -LL | | } - | |_- this function returns a `Result` +LL | fn foo() -> Result { + | --------------------------- this function returns a `Result` +LL | let x: Option = None; +LL | x?; + | ^ use `.ok_or(...)?` to provide an error compatible with `Result` | = help: the trait `FromResidual>` is not implemented for `Result` = help: the following other types implement trait `FromResidual`: @@ -17,13 +15,11 @@ LL | | } error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/try-on-option.rs:11:6 | -LL | / fn bar() -> u32 { -LL | | let x: Option = None; -LL | | x?; - | | ^ cannot use the `?` operator in a function that returns `u32` -LL | | 22 -LL | | } - | |_- this function should return `Result` or `Option` to accept `?` +LL | fn bar() -> u32 { + | --------------- this function should return `Result` or `Option` to accept `?` +LL | let x: Option = None; +LL | x?; + | ^ cannot use the `?` operator in a function that returns `u32` | = help: the trait `FromResidual>` is not implemented for `u32` diff --git a/src/test/ui/try-trait/try-operator-on-main.stderr b/src/test/ui/try-trait/try-operator-on-main.stderr index ad55f40b5b63..7cd38e0cf95e 100644 --- a/src/test/ui/try-trait/try-operator-on-main.stderr +++ b/src/test/ui/try-trait/try-operator-on-main.stderr @@ -1,15 +1,11 @@ error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/try-operator-on-main.rs:7:31 | -LL | / fn main() { -LL | | // error for a `Try` type on a non-`Try` fn -LL | | std::fs::File::open("foo")?; - | | ^ cannot use the `?` operator in a function that returns `()` -LL | | -... | -LL | | try_trait_generic::<()>(); -LL | | } - | |_- this function should return `Result` or `Option` to accept `?` +LL | fn main() { + | --------- this function should return `Result` or `Option` to accept `?` +LL | // error for a `Try` type on a non-`Try` fn +LL | std::fs::File::open("foo")?; + | ^ cannot use the `?` operator in a function that returns `()` | = help: the trait `FromResidual>` is not implemented for `()` @@ -24,17 +20,11 @@ LL | ()?; error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/try-operator-on-main.rs:10:7 | -LL | / fn main() { -LL | | // error for a `Try` type on a non-`Try` fn -LL | | std::fs::File::open("foo")?; -LL | | -LL | | // a non-`Try` type on a non-`Try` fn -LL | | ()?; - | | ^ cannot use the `?` operator in a function that returns `()` -... | -LL | | try_trait_generic::<()>(); -LL | | } - | |_- this function should return `Result` or `Option` to accept `?` +LL | fn main() { + | --------- this function should return `Result` or `Option` to accept `?` +... +LL | ()?; + | ^ cannot use the `?` operator in a function that returns `()` | = help: the trait `FromResidual<_>` is not implemented for `()` From edba0c92de737ff6d65255865366e0fddf76780c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 4 Sep 2022 02:10:31 +0000 Subject: [PATCH 4148/5092] Address nits, rename enclosing_scope => parent_label --- compiler/rustc_span/src/symbol.rs | 2 +- .../src/traits/error_reporting/mod.rs | 10 +-- .../src/traits/on_unimplemented.rs | 24 +++--- library/core/src/ops/try_trait.rs | 84 ++++++++++++++++++- .../ui/on-unimplemented/enclosing-scope.rs | 27 ------ src/test/ui/on-unimplemented/parent-label.rs | 27 ++++++ ...osing-scope.stderr => parent-label.stderr} | 32 +++---- 7 files changed, 141 insertions(+), 65 deletions(-) delete mode 100644 src/test/ui/on-unimplemented/enclosing-scope.rs create mode 100644 src/test/ui/on-unimplemented/parent-label.rs rename src/test/ui/on-unimplemented/{enclosing-scope.stderr => parent-label.stderr} (67%) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 64b919587e80..1da8c69490bd 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -661,7 +661,6 @@ symbols! { emit_struct, emit_struct_field, enable, - enclosing_scope, encode, end, env, @@ -1063,6 +1062,7 @@ symbols! { panic_unwind, panicking, param_attrs, + parent_label, partial_cmp, partial_ord, passes, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 8fd2e1de7a16..6ebadb42d9ef 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -349,7 +349,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { message, label, note, - enclosing_scope, + parent_label, append_const_msg, } = self.on_unimplemented_note(trait_ref, &obligation); let have_alt_message = message.is_some() || label.is_some(); @@ -515,7 +515,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // If it has a custom `#[rustc_on_unimplemented]` note, let's display it err.note(s.as_str()); } - if let Some(ref s) = enclosing_scope { + if let Some(ref s) = parent_label { let body = tcx .hir() .opt_local_def_id(obligation.cause.body_id) @@ -524,11 +524,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { hir_id: obligation.cause.body_id, }) }); - - let enclosing_scope_span = - tcx.hir().span(tcx.hir().local_def_id_to_hir_id(body)); - - err.span_label(enclosing_scope_span, s); + err.span_label(tcx.def_span(body), s); } self.suggest_floating_point_literal(&obligation, &mut err, &trait_ref); diff --git a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs index 3d8840e9e742..4a4f34b76805 100644 --- a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs @@ -22,7 +22,7 @@ pub struct OnUnimplementedDirective { pub message: Option, pub label: Option, pub note: Option, - pub enclosing_scope: Option, + pub parent_label: Option, pub append_const_msg: Option>, } @@ -31,7 +31,7 @@ pub struct OnUnimplementedNote { pub message: Option, pub label: Option, pub note: Option, - pub enclosing_scope: Option, + pub parent_label: Option, /// Append a message for `~const Trait` errors. `None` means not requested and /// should fallback to a generic message, `Some(None)` suggests using the default /// appended message, `Some(Some(s))` suggests use the `s` message instead of the @@ -74,7 +74,7 @@ impl<'tcx> OnUnimplementedDirective { let mut message = None; let mut label = None; let mut note = None; - let mut enclosing_scope = None; + let mut parent_label = None; let mut subcommands = vec![]; let mut append_const_msg = None; @@ -94,9 +94,9 @@ impl<'tcx> OnUnimplementedDirective { note = parse_value(note_)?; continue; } - } else if item.has_name(sym::enclosing_scope) && enclosing_scope.is_none() { - if let Some(enclosing_scope_) = item.value_str() { - enclosing_scope = parse_value(enclosing_scope_)?; + } else if item.has_name(sym::parent_label) && parent_label.is_none() { + if let Some(parent_label_) = item.value_str() { + parent_label = parse_value(parent_label_)?; continue; } } else if item.has_name(sym::on) @@ -135,7 +135,7 @@ impl<'tcx> OnUnimplementedDirective { message, label, note, - enclosing_scope, + parent_label, append_const_msg, }) } @@ -160,7 +160,7 @@ impl<'tcx> OnUnimplementedDirective { attr.span, )?), note: None, - enclosing_scope: None, + parent_label: None, append_const_msg: None, })) } else { @@ -181,7 +181,7 @@ impl<'tcx> OnUnimplementedDirective { let mut message = None; let mut label = None; let mut note = None; - let mut enclosing_scope = None; + let mut parent_label = None; let mut append_const_msg = None; info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options); @@ -217,8 +217,8 @@ impl<'tcx> OnUnimplementedDirective { note = Some(note_.clone()); } - if let Some(ref enclosing_scope_) = command.enclosing_scope { - enclosing_scope = Some(enclosing_scope_.clone()); + if let Some(ref parent_label_) = command.parent_label { + parent_label = Some(parent_label_.clone()); } append_const_msg = command.append_const_msg; @@ -228,7 +228,7 @@ impl<'tcx> OnUnimplementedDirective { label: label.map(|l| l.format(tcx, trait_ref, &options_map)), message: message.map(|m| m.format(tcx, trait_ref, &options_map)), note: note.map(|n| n.format(tcx, trait_ref, &options_map)), - enclosing_scope: enclosing_scope.map(|e_s| e_s.format(tcx, trait_ref, &options_map)), + parent_label: parent_label.map(|e_s| e_s.format(tcx, trait_ref, &options_map)), append_const_msg, } } diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs index 02f7f62bfe22..10f041344095 100644 --- a/library/core/src/ops/try_trait.rs +++ b/library/core/src/ops/try_trait.rs @@ -222,7 +222,87 @@ pub trait Try: FromResidual { /// Every `Try` type needs to be recreatable from its own associated /// `Residual` type, but can also have additional `FromResidual` implementations /// to support interconversion with other `Try` types. -#[rustc_on_unimplemented( +#[cfg_attr(not(bootstrap), rustc_on_unimplemented( + on( + all( + from_desugaring = "QuestionMark", + _Self = "std::result::Result", + R = "std::option::Option" + ), + message = "the `?` operator can only be used on `Result`s, not `Option`s, \ + in {ItemContext} that returns `Result`", + label = "use `.ok_or(...)?` to provide an error compatible with `{Self}`", + parent_label = "this function returns a `Result`" + ), + on( + all( + from_desugaring = "QuestionMark", + _Self = "std::result::Result", + ), + // There's a special error message in the trait selection code for + // `From` in `?`, so this is not shown for result-in-result errors, + // and thus it can be phrased more strongly than `ControlFlow`'s. + message = "the `?` operator can only be used on `Result`s \ + in {ItemContext} that returns `Result`", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + parent_label = "this function returns a `Result`" + ), + on( + all( + from_desugaring = "QuestionMark", + _Self = "std::option::Option", + R = "std::result::Result", + ), + message = "the `?` operator can only be used on `Option`s, not `Result`s, \ + in {ItemContext} that returns `Option`", + label = "use `.ok()?` if you want to discard the `{R}` error information", + parent_label = "this function returns an `Option`" + ), + on( + all( + from_desugaring = "QuestionMark", + _Self = "std::option::Option", + ), + // `Option`-in-`Option` always works, as there's only one possible + // residual, so this can also be phrased strongly. + message = "the `?` operator can only be used on `Option`s \ + in {ItemContext} that returns `Option`", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + parent_label = "this function returns an `Option`" + ), + on( + all( + from_desugaring = "QuestionMark", + _Self = "std::ops::ControlFlow", + R = "std::ops::ControlFlow", + ), + message = "the `?` operator in {ItemContext} that returns `ControlFlow` \ + can only be used on other `ControlFlow`s (with the same Break type)", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + parent_label = "this function returns a `ControlFlow`", + note = "unlike `Result`, there's no `From`-conversion performed for `ControlFlow`" + ), + on( + all( + from_desugaring = "QuestionMark", + _Self = "std::ops::ControlFlow", + // `R` is not a `ControlFlow`, as that case was matched previously + ), + message = "the `?` operator can only be used on `ControlFlow`s \ + in {ItemContext} that returns `ControlFlow`", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + parent_label = "this function returns a `ControlFlow`", + ), + on( + all(from_desugaring = "QuestionMark"), + message = "the `?` operator can only be used in {ItemContext} \ + that returns `Result` or `Option` \ + (or another type that implements `{FromResidual}`)", + label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`", + parent_label = "this function should return `Result` or `Option` to accept `?`" + ), +))] +#[cfg_attr(bootstrap, rustc_on_unimplemented( on( all( from_desugaring = "QuestionMark", @@ -301,7 +381,7 @@ pub trait Try: FromResidual { label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`", enclosing_scope = "this function should return `Result` or `Option` to accept `?`" ), -)] +))] #[rustc_diagnostic_item = "FromResidual"] #[unstable(feature = "try_trait_v2", issue = "84277")] pub trait FromResidual::Residual> { diff --git a/src/test/ui/on-unimplemented/enclosing-scope.rs b/src/test/ui/on-unimplemented/enclosing-scope.rs deleted file mode 100644 index 881bff63f5f6..000000000000 --- a/src/test/ui/on-unimplemented/enclosing-scope.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Test scope annotations from `enclosing_scope` parameter - -#![feature(rustc_attrs)] - -#[rustc_on_unimplemented(enclosing_scope="in this scope")] -trait Trait{} - -struct Foo; - -fn f(x: T) {} - -fn main() { - let x = || { - f(Foo{}); //~ ERROR the trait bound `Foo: Trait` is not satisfied - let y = || { - f(Foo{}); //~ ERROR the trait bound `Foo: Trait` is not satisfied - }; - }; - - { - { - f(Foo{}); //~ ERROR the trait bound `Foo: Trait` is not satisfied - } - } - - f(Foo{}); //~ ERROR the trait bound `Foo: Trait` is not satisfied -} diff --git a/src/test/ui/on-unimplemented/parent-label.rs b/src/test/ui/on-unimplemented/parent-label.rs new file mode 100644 index 000000000000..b65f6496831e --- /dev/null +++ b/src/test/ui/on-unimplemented/parent-label.rs @@ -0,0 +1,27 @@ +// Test scope annotations from `parent_label` parameter + +#![feature(rustc_attrs)] + +#[rustc_on_unimplemented(parent_label = "in this scope")] +trait Trait {} + +struct Foo; + +fn f(x: T) {} + +fn main() { + let x = || { + f(Foo {}); //~ ERROR the trait bound `Foo: Trait` is not satisfied + let y = || { + f(Foo {}); //~ ERROR the trait bound `Foo: Trait` is not satisfied + }; + }; + + { + { + f(Foo {}); //~ ERROR the trait bound `Foo: Trait` is not satisfied + } + } + + f(Foo {}); //~ ERROR the trait bound `Foo: Trait` is not satisfied +} diff --git a/src/test/ui/on-unimplemented/enclosing-scope.stderr b/src/test/ui/on-unimplemented/parent-label.stderr similarity index 67% rename from src/test/ui/on-unimplemented/enclosing-scope.stderr rename to src/test/ui/on-unimplemented/parent-label.stderr index 4fe2ecd1e381..8cd7412fd9d3 100644 --- a/src/test/ui/on-unimplemented/enclosing-scope.stderr +++ b/src/test/ui/on-unimplemented/parent-label.stderr @@ -1,65 +1,65 @@ error[E0277]: the trait bound `Foo: Trait` is not satisfied - --> $DIR/enclosing-scope.rs:14:11 + --> $DIR/parent-label.rs:14:11 | LL | let x = || { | -- in this scope -LL | f(Foo{}); - | - ^^^^^ the trait `Trait` is not implemented for `Foo` +LL | f(Foo {}); + | - ^^^^^^ the trait `Trait` is not implemented for `Foo` | | | required by a bound introduced by this call | note: required by a bound in `f` - --> $DIR/enclosing-scope.rs:10:9 + --> $DIR/parent-label.rs:10:9 | LL | fn f(x: T) {} | ^^^^^ required by this bound in `f` error[E0277]: the trait bound `Foo: Trait` is not satisfied - --> $DIR/enclosing-scope.rs:16:15 + --> $DIR/parent-label.rs:16:15 | LL | let y = || { | -- in this scope -LL | f(Foo{}); - | - ^^^^^ the trait `Trait` is not implemented for `Foo` +LL | f(Foo {}); + | - ^^^^^^ the trait `Trait` is not implemented for `Foo` | | | required by a bound introduced by this call | note: required by a bound in `f` - --> $DIR/enclosing-scope.rs:10:9 + --> $DIR/parent-label.rs:10:9 | LL | fn f(x: T) {} | ^^^^^ required by this bound in `f` error[E0277]: the trait bound `Foo: Trait` is not satisfied - --> $DIR/enclosing-scope.rs:22:15 + --> $DIR/parent-label.rs:22:15 | LL | fn main() { | --------- in this scope ... -LL | f(Foo{}); - | - ^^^^^ the trait `Trait` is not implemented for `Foo` +LL | f(Foo {}); + | - ^^^^^^ the trait `Trait` is not implemented for `Foo` | | | required by a bound introduced by this call | note: required by a bound in `f` - --> $DIR/enclosing-scope.rs:10:9 + --> $DIR/parent-label.rs:10:9 | LL | fn f(x: T) {} | ^^^^^ required by this bound in `f` error[E0277]: the trait bound `Foo: Trait` is not satisfied - --> $DIR/enclosing-scope.rs:26:7 + --> $DIR/parent-label.rs:26:7 | LL | fn main() { | --------- in this scope ... -LL | f(Foo{}); - | - ^^^^^ the trait `Trait` is not implemented for `Foo` +LL | f(Foo {}); + | - ^^^^^^ the trait `Trait` is not implemented for `Foo` | | | required by a bound introduced by this call | note: required by a bound in `f` - --> $DIR/enclosing-scope.rs:10:9 + --> $DIR/parent-label.rs:10:9 | LL | fn f(x: T) {} | ^^^^^ required by this bound in `f` From 98f4b20abc9ad5ff77874119bbec305f4c7c6226 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 3 Sep 2022 19:13:17 +0000 Subject: [PATCH 4149/5092] Also suggest dereferencing LHS when both &mut T and T are valid binop LHS --- compiler/rustc_typeck/src/check/op.rs | 8 ++++++++ .../ui/typeck/assign-non-lval-needs-deref.rs | 19 +++++++++++++++++++ .../typeck/assign-non-lval-needs-deref.stderr | 16 ++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 src/test/ui/typeck/assign-non-lval-needs-deref.rs create mode 100644 src/test/ui/typeck/assign-non-lval-needs-deref.stderr diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index d51dccd1af5d..0d9dbb5bc11c 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -70,6 +70,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .is_err() { err.downgrade_to_delayed_bug(); + } else { + // Otherwise, it's valid to suggest dereferencing the LHS here. + err.span_suggestion_verbose( + lhs.span.shrink_to_lo(), + "consider dereferencing the left-hand side of this operation", + "*", + Applicability::MaybeIncorrect, + ); } } } diff --git a/src/test/ui/typeck/assign-non-lval-needs-deref.rs b/src/test/ui/typeck/assign-non-lval-needs-deref.rs new file mode 100644 index 000000000000..c979d76b4f41 --- /dev/null +++ b/src/test/ui/typeck/assign-non-lval-needs-deref.rs @@ -0,0 +1,19 @@ +// issue #101376 + +use std::ops::AddAssign; +struct Foo; + +impl AddAssign<()> for Foo { + fn add_assign(&mut self, _: ()) {} +} + +impl AddAssign<()> for &mut Foo { + fn add_assign(&mut self, _: ()) {} +} + +fn main() { + (&mut Foo) += (); + //~^ ERROR invalid left-hand side of assignment + //~| NOTE cannot assign to this expression + //~| HELP consider dereferencing the left-hand side of this operation +} diff --git a/src/test/ui/typeck/assign-non-lval-needs-deref.stderr b/src/test/ui/typeck/assign-non-lval-needs-deref.stderr new file mode 100644 index 000000000000..ee83b1453213 --- /dev/null +++ b/src/test/ui/typeck/assign-non-lval-needs-deref.stderr @@ -0,0 +1,16 @@ +error[E0067]: invalid left-hand side of assignment + --> $DIR/assign-non-lval-needs-deref.rs:15:16 + | +LL | (&mut Foo) += (); + | ---------- ^^ + | | + | cannot assign to this expression + | +help: consider dereferencing the left-hand side of this operation + | +LL | *(&mut Foo) += (); + | + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0067`. From 0e0756cf0d1b55f3de4815088276a584e2c31f14 Mon Sep 17 00:00:00 2001 From: beetrees Date: Sun, 4 Sep 2022 10:22:36 +0100 Subject: [PATCH 4150/5092] Don't duplicate file descriptors into stdio fds --- library/std/src/os/fd/owned.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index a463bc41db7a..71e33fb9ed86 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -104,7 +104,8 @@ impl BorrowedFd<'_> { #[cfg(target_os = "espidf")] let cmd = libc::F_DUPFD; - let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) })?; + // Avoid using file descriptors below 3 as they are used for stdio + let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 3) })?; Ok(unsafe { OwnedFd::from_raw_fd(fd) }) } From efbd8f62ed2f9201d410721fae69e6233d385ba6 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Sun, 4 Sep 2022 12:53:25 +0100 Subject: [PATCH 4151/5092] rustdoc: Compute enum discriminant on demand --- src/librustdoc/clean/mod.rs | 18 ++++-------------- src/librustdoc/clean/types.rs | 16 ++++++++++++++-- src/librustdoc/json/conversions.rs | 18 ++++++++++-------- 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 8cf9f46310bc..be2227f47af6 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1787,10 +1787,7 @@ pub(crate) fn clean_visibility(vis: ty::Visibility) -> Visibility { pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocContext<'tcx>) -> Item { let kind = match variant.ctor_kind { CtorKind::Const => Variant::CLike(match variant.discr { - ty::VariantDiscr::Explicit(def_id) => Some(Discriminant { - expr: None, - value: print_evaluated_const(cx.tcx, def_id, false).unwrap(), - }), + ty::VariantDiscr::Explicit(def_id) => Some(Discriminant { expr: None, value: def_id }), ty::VariantDiscr::Relative(_) => None, }), CtorKind::Fn => Variant::Tuple( @@ -1820,16 +1817,9 @@ fn clean_variant_data<'tcx>( hir::VariantData::Tuple(..) => { Variant::Tuple(variant.fields().iter().map(|x| clean_field(x, cx)).collect()) } - hir::VariantData::Unit(..) => Variant::CLike(disr_expr.map(|disr| { - Discriminant { - expr: Some(print_const_expr(cx.tcx, disr.body)), - value: print_evaluated_const( - cx.tcx, - cx.tcx.hir().local_def_id(disr.hir_id).to_def_id(), - false, - ) - .unwrap(), - } + hir::VariantData::Unit(..) => Variant::CLike(disr_expr.map(|disr| Discriminant { + expr: Some(disr.body), + value: cx.tcx.hir().local_def_id(disr.hir_id).to_def_id(), })), } } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 8de9a80758e4..d6bb7c6c4fc8 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2116,8 +2116,20 @@ impl Variant { pub(crate) struct Discriminant { // In the case of cross crate re-exports, we don't have the nessesary information // to reconstruct the expression of the discriminant, only the value. - pub(crate) expr: Option, - pub(crate) value: String, + pub(super) expr: Option, + pub(super) value: DefId, +} + +impl Discriminant { + /// Will be `None` in the case of cross-crate reexports, and may be + /// simplified + pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> Option { + self.expr.map(|body| print_const_expr(tcx, body)) + } + /// Will always be a machine readable number, without underscores or suffixes. + pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> String { + print_evaluated_const(tcx, self.value, false).unwrap() + } } /// Small wrapper around [`rustc_span::Span`] that adds helper methods diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index cc5c391d6bd5..f6347b4f0f66 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -662,7 +662,7 @@ impl FromWithTcx for Variant { fn from_tcx(variant: clean::Variant, tcx: TyCtxt<'_>) -> Self { use clean::Variant::*; match variant { - CLike(disr) => Variant::Plain(disr.map(convert_discriminant)), + CLike(disr) => Variant::Plain(disr.map(|disr| disr.into_tcx(tcx))), Tuple(fields) => Variant::Tuple( fields .into_iter() @@ -678,13 +678,15 @@ impl FromWithTcx for Variant { } } -fn convert_discriminant(disr: clean::Discriminant) -> Discriminant { - Discriminant { - // expr is only none if going throught the inlineing path, which gets - // `rustc_middle` types, not `rustc_hir`, but because JSON never inlines - // the expr is always some. - expr: disr.expr.unwrap(), - value: disr.value, +impl FromWithTcx for Discriminant { + fn from_tcx(disr: clean::Discriminant, tcx: TyCtxt<'_>) -> Self { + Discriminant { + // expr is only none if going throught the inlineing path, which gets + // `rustc_middle` types, not `rustc_hir`, but because JSON never inlines + // the expr is always some. + expr: disr.expr(tcx).unwrap(), + value: disr.value(tcx), + } } } From 075084f772abbc53263fc946c047a01e0dd65f80 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Tue, 23 Aug 2022 00:07:26 +0000 Subject: [PATCH 4152/5092] Make `const_eval_select` a real intrinsic --- compiler/rustc_codegen_ssa/src/mir/block.rs | 3 +- .../src/const_eval/machine.rs | 16 +- compiler/rustc_hir/src/lang_items.rs | 2 - .../rustc_middle/src/ty/consts/valtree.rs | 5 +- compiler/rustc_middle/src/ty/layout.rs | 175 +++++++++--------- compiler/rustc_mir_transform/src/lib.rs | 68 ++++++- compiler/rustc_monomorphize/src/collector.rs | 8 +- compiler/rustc_span/src/symbol.rs | 1 - .../rustc_typeck/src/check/fn_ctxt/checks.rs | 33 +++- library/core/src/intrinsics.rs | 143 +++++++------- library/core/src/mem/valid_align.rs | 2 +- library/core/src/num/f32.rs | 22 ++- library/core/src/num/f64.rs | 22 ++- library/core/src/num/nonzero.rs | 2 +- library/core/src/ptr/const_ptr.rs | 5 +- library/core/src/ptr/mod.rs | 8 +- library/core/src/slice/index.rs | 20 +- library/core/src/slice/mod.rs | 15 +- library/core/src/slice/raw.rs | 4 +- library/core/src/str/mod.rs | 2 + .../const-float-bits-reject-conv.stderr | 40 ---- .../const-eval-select-backtrace-std.rs | 6 + ...const-eval-select-backtrace-std.run.stderr | 2 + .../intrinsics/const-eval-select-backtrace.rs | 18 ++ .../const-eval-select-backtrace.run.stderr | 2 + .../ui/intrinsics/const-eval-select-bad.rs | 12 +- .../intrinsics/const-eval-select-bad.stderr | 83 ++++++--- 27 files changed, 432 insertions(+), 287 deletions(-) create mode 100644 src/test/ui/intrinsics/const-eval-select-backtrace-std.rs create mode 100644 src/test/ui/intrinsics/const-eval-select-backtrace-std.run.stderr create mode 100644 src/test/ui/intrinsics/const-eval-select-backtrace.rs create mode 100644 src/test/ui/intrinsics/const-eval-select-backtrace.run.stderr diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 5c67d3b6431f..3154f12a7796 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -13,8 +13,7 @@ use rustc_ast as ast; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_hir::lang_items::LangItem; use rustc_index::vec::Idx; -use rustc_middle::mir::AssertKind; -use rustc_middle::mir::{self, SwitchTargets}; +use rustc_middle::mir::{self, AssertKind, SwitchTargets}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, Instance, Ty, TypeVisitable}; diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 9ea9fbe0e0e5..6e5c840bdfd6 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -35,21 +35,7 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> { // All `#[rustc_do_not_const_check]` functions should be hooked here. let def_id = instance.def_id(); - if Some(def_id) == self.tcx.lang_items().const_eval_select() { - // redirect to const_eval_select_ct - if let Some(const_eval_select) = self.tcx.lang_items().const_eval_select_ct() { - return Ok(Some( - ty::Instance::resolve( - *self.tcx, - ty::ParamEnv::reveal_all(), - const_eval_select, - instance.substs, - ) - .unwrap() - .unwrap(), - )); - } - } else if Some(def_id) == self.tcx.lang_items().panic_display() + if Some(def_id) == self.tcx.lang_items().panic_display() || Some(def_id) == self.tcx.lang_items().begin_panic_fn() { // &str or &&str diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index f19d07d98dcb..bc1ea1c4c736 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -269,8 +269,6 @@ language_item_table! { DropInPlace, sym::drop_in_place, drop_in_place_fn, Target::Fn, GenericRequirement::Minimum(1); Oom, sym::oom, oom, Target::Fn, GenericRequirement::None; AllocLayout, sym::alloc_layout, alloc_layout, Target::Struct, GenericRequirement::None; - ConstEvalSelect, sym::const_eval_select, const_eval_select, Target::Fn, GenericRequirement::Exact(4); - ConstConstEvalSelect, sym::const_eval_select_ct,const_eval_select_ct, Target::Fn, GenericRequirement::Exact(4); Start, sym::start, start_fn, Target::Fn, GenericRequirement::Exact(1); diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 93707bb18cee..a803fca0d5b8 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -18,7 +18,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable}; /// `ValTree` does not have this problem with representation, as it only contains integers or /// lists of (nested) `ValTree`. pub enum ValTree<'tcx> { - /// ZSTs, integers, `bool`, `char` are represented as scalars. + /// integers, `bool`, `char` are represented as scalars. /// See the `ScalarInt` documentation for how `ScalarInt` guarantees that equal values /// of these types have the same representation. Leaf(ScalarInt), @@ -27,8 +27,11 @@ pub enum ValTree<'tcx> { // dont use SliceOrStr for now /// The fields of any kind of aggregate. Structs, tuples and arrays are represented by /// listing their fields' values in order. + /// /// Enums are represented by storing their discriminant as a field, followed by all /// the fields of the variant. + /// + /// ZST types are represented as an empty slice. Branch(&'tcx [ValTree<'tcx>]), } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 26b60e4f3398..2c587b76f025 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -263,6 +263,7 @@ fn layout_of<'tcx>( Ok(layout) } +#[derive(Clone, Copy)] pub struct LayoutCx<'tcx, C> { pub tcx: C, pub param_env: ty::ParamEnv<'tcx>, @@ -3063,6 +3064,93 @@ fn fn_abi_of_instance<'tcx>( ) } +// Handle safe Rust thin and fat pointers. +pub fn adjust_for_rust_scalar<'tcx>( + cx: LayoutCx<'tcx, TyCtxt<'tcx>>, + attrs: &mut ArgAttributes, + scalar: Scalar, + layout: TyAndLayout<'tcx>, + offset: Size, + is_return: bool, +) { + // Booleans are always a noundef i1 that needs to be zero-extended. + if scalar.is_bool() { + attrs.ext(ArgExtension::Zext); + attrs.set(ArgAttribute::NoUndef); + return; + } + + // Scalars which have invalid values cannot be undef. + if !scalar.is_always_valid(&cx) { + attrs.set(ArgAttribute::NoUndef); + } + + // Only pointer types handled below. + let Scalar::Initialized { value: Pointer, valid_range} = scalar else { return }; + + if !valid_range.contains(0) { + attrs.set(ArgAttribute::NonNull); + } + + if let Some(pointee) = layout.pointee_info_at(&cx, offset) { + if let Some(kind) = pointee.safe { + attrs.pointee_align = Some(pointee.align); + + // `Box` (`UniqueBorrowed`) are not necessarily dereferenceable + // for the entire duration of the function as they can be deallocated + // at any time. Same for shared mutable references. If LLVM had a + // way to say "dereferenceable on entry" we could use it here. + attrs.pointee_size = match kind { + PointerKind::UniqueBorrowed + | PointerKind::UniqueBorrowedPinned + | PointerKind::Frozen => pointee.size, + PointerKind::SharedMutable | PointerKind::UniqueOwned => Size::ZERO, + }; + + // `Box`, `&T`, and `&mut T` cannot be undef. + // Note that this only applies to the value of the pointer itself; + // this attribute doesn't make it UB for the pointed-to data to be undef. + attrs.set(ArgAttribute::NoUndef); + + // The aliasing rules for `Box` are still not decided, but currently we emit + // `noalias` for it. This can be turned off using an unstable flag. + // See https://github.com/rust-lang/unsafe-code-guidelines/issues/326 + let noalias_for_box = cx.tcx.sess.opts.unstable_opts.box_noalias.unwrap_or(true); + + // `&mut` pointer parameters never alias other parameters, + // or mutable global data + // + // `&T` where `T` contains no `UnsafeCell` is immutable, + // and can be marked as both `readonly` and `noalias`, as + // LLVM's definition of `noalias` is based solely on memory + // dependencies rather than pointer equality + // + // Due to past miscompiles in LLVM, we apply a separate NoAliasMutRef attribute + // for UniqueBorrowed arguments, so that the codegen backend can decide whether + // or not to actually emit the attribute. It can also be controlled with the + // `-Zmutable-noalias` debugging option. + let no_alias = match kind { + PointerKind::SharedMutable + | PointerKind::UniqueBorrowed + | PointerKind::UniqueBorrowedPinned => false, + PointerKind::UniqueOwned => noalias_for_box, + PointerKind::Frozen => !is_return, + }; + if no_alias { + attrs.set(ArgAttribute::NoAlias); + } + + if kind == PointerKind::Frozen && !is_return { + attrs.set(ArgAttribute::ReadOnly); + } + + if kind == PointerKind::UniqueBorrowed && !is_return { + attrs.set(ArgAttribute::NoAliasMutRef); + } + } + } +} + impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // FIXME(eddyb) perhaps group the signature/type-containing (or all of them?) // arguments of this method, into a separate `struct`. @@ -3118,91 +3206,6 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { use SpecAbi::*; let rust_abi = matches!(sig.abi, RustIntrinsic | PlatformIntrinsic | Rust | RustCall); - // Handle safe Rust thin and fat pointers. - let adjust_for_rust_scalar = |attrs: &mut ArgAttributes, - scalar: Scalar, - layout: TyAndLayout<'tcx>, - offset: Size, - is_return: bool| { - // Booleans are always a noundef i1 that needs to be zero-extended. - if scalar.is_bool() { - attrs.ext(ArgExtension::Zext); - attrs.set(ArgAttribute::NoUndef); - return; - } - - // Scalars which have invalid values cannot be undef. - if !scalar.is_always_valid(self) { - attrs.set(ArgAttribute::NoUndef); - } - - // Only pointer types handled below. - let Scalar::Initialized { value: Pointer, valid_range} = scalar else { return }; - - if !valid_range.contains(0) { - attrs.set(ArgAttribute::NonNull); - } - - if let Some(pointee) = layout.pointee_info_at(self, offset) { - if let Some(kind) = pointee.safe { - attrs.pointee_align = Some(pointee.align); - - // `Box` (`UniqueBorrowed`) are not necessarily dereferenceable - // for the entire duration of the function as they can be deallocated - // at any time. Same for shared mutable references. If LLVM had a - // way to say "dereferenceable on entry" we could use it here. - attrs.pointee_size = match kind { - PointerKind::UniqueBorrowed - | PointerKind::UniqueBorrowedPinned - | PointerKind::Frozen => pointee.size, - PointerKind::SharedMutable | PointerKind::UniqueOwned => Size::ZERO, - }; - - // `Box`, `&T`, and `&mut T` cannot be undef. - // Note that this only applies to the value of the pointer itself; - // this attribute doesn't make it UB for the pointed-to data to be undef. - attrs.set(ArgAttribute::NoUndef); - - // The aliasing rules for `Box` are still not decided, but currently we emit - // `noalias` for it. This can be turned off using an unstable flag. - // See https://github.com/rust-lang/unsafe-code-guidelines/issues/326 - let noalias_for_box = - self.tcx().sess.opts.unstable_opts.box_noalias.unwrap_or(true); - - // `&mut` pointer parameters never alias other parameters, - // or mutable global data - // - // `&T` where `T` contains no `UnsafeCell` is immutable, - // and can be marked as both `readonly` and `noalias`, as - // LLVM's definition of `noalias` is based solely on memory - // dependencies rather than pointer equality - // - // Due to past miscompiles in LLVM, we apply a separate NoAliasMutRef attribute - // for UniqueBorrowed arguments, so that the codegen backend can decide whether - // or not to actually emit the attribute. It can also be controlled with the - // `-Zmutable-noalias` debugging option. - let no_alias = match kind { - PointerKind::SharedMutable - | PointerKind::UniqueBorrowed - | PointerKind::UniqueBorrowedPinned => false, - PointerKind::UniqueOwned => noalias_for_box, - PointerKind::Frozen => !is_return, - }; - if no_alias { - attrs.set(ArgAttribute::NoAlias); - } - - if kind == PointerKind::Frozen && !is_return { - attrs.set(ArgAttribute::ReadOnly); - } - - if kind == PointerKind::UniqueBorrowed && !is_return { - attrs.set(ArgAttribute::NoAliasMutRef); - } - } - } - }; - let arg_of = |ty: Ty<'tcx>, arg_idx: Option| -> Result<_, FnAbiError<'tcx>> { let is_return = arg_idx.is_none(); @@ -3218,7 +3221,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let mut arg = ArgAbi::new(self, layout, |layout, scalar, offset| { let mut attrs = ArgAttributes::new(); - adjust_for_rust_scalar(&mut attrs, scalar, *layout, offset, is_return); + adjust_for_rust_scalar(*self, &mut attrs, scalar, *layout, offset, is_return); attrs }); diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 0b674b38f328..69b49604250b 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -10,6 +10,7 @@ #![feature(trusted_step)] #![feature(try_blocks)] #![feature(yeet_expr)] +#![feature(if_let_guard)] #![recursion_limit = "256"] #[macro_use] @@ -27,10 +28,13 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_index::vec::IndexVec; use rustc_middle::mir::visit::Visitor as _; use rustc_middle::mir::{ - traversal, AnalysisPhase, Body, ConstQualifs, MirPass, MirPhase, Promoted, RuntimePhase, + traversal, AnalysisPhase, Body, ConstQualifs, Constant, LocalDecl, MirPass, MirPhase, Operand, + Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo, Statement, StatementKind, + TerminatorKind, }; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitable}; +use rustc_span::sym; #[macro_use] mod pass_manager; @@ -140,6 +144,64 @@ pub fn provide(providers: &mut Providers) { }; } +fn remap_mir_for_const_eval_select<'tcx>( + tcx: TyCtxt<'tcx>, + mut body: Body<'tcx>, + context: hir::Constness, +) -> Body<'tcx> { + for bb in body.basic_blocks.as_mut().iter_mut() { + let terminator = bb.terminator.as_mut().expect("invalid terminator"); + match terminator.kind { + TerminatorKind::Call { + func: Operand::Constant(box Constant { ref literal, .. }), + ref mut args, + destination, + target, + cleanup, + fn_span, + .. + } if let ty::FnDef(def_id, _) = *literal.ty().kind() + && tcx.item_name(def_id) == sym::const_eval_select + && tcx.is_intrinsic(def_id) => + { + let [tupled_args, called_in_const, called_at_rt]: [_; 3] = std::mem::take(args).try_into().unwrap(); + let ty = tupled_args.ty(&body.local_decls, tcx); + let fields = ty.tuple_fields(); + let num_args = fields.len(); + let func = if context == hir::Constness::Const { called_in_const } else { called_at_rt }; + let (method, place): (fn(Place<'tcx>) -> Operand<'tcx>, Place<'tcx>) = match tupled_args { + Operand::Constant(_) => { + // there is no good way of extracting a tuple arg from a constant (const generic stuff) + // so we just create a temporary and deconstruct that. + let local = body.local_decls.push(LocalDecl::new(ty, fn_span)); + bb.statements.push(Statement { + source_info: SourceInfo::outermost(fn_span), + kind: StatementKind::Assign(Box::new((local.into(), Rvalue::Use(tupled_args.clone())))), + }); + (Operand::Move, local.into()) + } + Operand::Move(place) => (Operand::Move, place), + Operand::Copy(place) => (Operand::Copy, place), + }; + let place_elems = place.projection; + let arguments = (0..num_args).map(|x| { + let mut place_elems = place_elems.to_vec(); + place_elems.push(ProjectionElem::Field(x.into(), fields[x])); + let projection = tcx.intern_place_elems(&place_elems); + let place = Place { + local: place.local, + projection, + }; + method(place) + }).collect(); + terminator.kind = TerminatorKind::Call { func, args: arguments, destination, target, cleanup, from_hir_call: false, fn_span }; + } + _ => {} + } + } + body +} + fn is_mir_available(tcx: TyCtxt<'_>, def_id: DefId) -> bool { let def_id = def_id.expect_local(); tcx.mir_keys(()).contains(&def_id) @@ -354,7 +416,7 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) - debug_assert!(!body.has_free_regions(), "Free regions in MIR for CTFE"); - body + remap_mir_for_const_eval_select(tcx, body, hir::Constness::Const) } /// Obtain just the main MIR (no promoteds) and run some cleanups on it. This also runs @@ -565,7 +627,7 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> { debug_assert!(!body.has_free_regions(), "Free regions in optimized MIR"); - body + remap_mir_for_const_eval_select(tcx, body, hir::Constness::NotConst) } /// Fetch all the promoteds of an item and prepare their MIR bodies to be ready for diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 4e37da0dedb1..be74a9d11e3c 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -112,12 +112,6 @@ //! method in operand position, we treat it as a neighbor of the current //! mono item. Calls are just a special case of that. //! -//! #### Closures -//! In a way, closures are a simple case. Since every closure object needs to be -//! constructed somewhere, we can reliably discover them by observing -//! `RValue::Aggregate` expressions with `AggregateKind::Closure`. This is also -//! true for closures inlined from other crates. -//! //! #### Drop glue //! Drop glue mono items are introduced by MIR drop-statements. The //! generated mono item will again have drop-glue item neighbors if the @@ -835,7 +829,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { mir::TerminatorKind::Call { ref func, .. } => { let callee_ty = func.ty(self.body, tcx); let callee_ty = self.monomorphize(callee_ty); - visit_fn_use(self.tcx, callee_ty, true, source, &mut self.output); + visit_fn_use(self.tcx, callee_ty, true, source, &mut self.output) } mir::TerminatorKind::Drop { ref place, .. } | mir::TerminatorKind::DropAndReplace { ref place, .. } => { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index c501fba21c60..f6ce7675c8fa 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -510,7 +510,6 @@ symbols! { const_deallocate, const_eval_limit, const_eval_select, - const_eval_select_ct, const_evaluatable_checked, const_extern_fn, const_fn, diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index ce0e59d06226..d1d27db9131f 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -31,7 +31,7 @@ use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty, TypeSuperVisitable, TypeVisitor}; use rustc_session::Session; use rustc_span::symbol::Ident; -use rustc_span::{self, Span}; +use rustc_span::{self, sym, Span}; use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext}; use std::iter; @@ -224,6 +224,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let minimum_input_count = expected_input_tys.len(); let provided_arg_count = provided_args.len(); + let is_const_eval_select = matches!(fn_def_id, Some(def_id) if + self.tcx.def_kind(def_id) == hir::def::DefKind::Fn + && self.tcx.is_intrinsic(def_id) + && self.tcx.item_name(def_id) == sym::const_eval_select); + // We introduce a helper function to demand that a given argument satisfy a given input // This is more complicated than just checking type equality, as arguments could be coerced // This version writes those types back so further type checking uses the narrowed types @@ -259,6 +264,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return Compatibility::Incompatible(coerce_error); } + // Check that second and third argument of `const_eval_select` must be `FnDef`, and additionally that + // the second argument must be `const fn`. The first argument must be a tuple, but this is already expressed + // in the function signature (`F: FnOnce`), so I did not bother to add another check here. + // + // This check is here because there is currently no way to express a trait bound for `FnDef` types only. + if is_const_eval_select && (1..=2).contains(&idx) { + if let ty::FnDef(def_id, _) = checked_ty.kind() { + if idx == 1 && !self.tcx.is_const_fn_raw(*def_id) { + self.tcx + .sess + .struct_span_err(provided_arg.span, "this argument must be a `const fn`") + .help("consult the documentation on `const_eval_select` for more information") + .emit(); + } + } else { + self.tcx + .sess + .struct_span_err(provided_arg.span, "this argument must be a function item") + .note(format!("expected a function item, found {checked_ty}")) + .help( + "consult the documentation on `const_eval_select` for more information", + ) + .emit(); + } + } + // 3. Check if the formal type is a supertype of the checked one // and register any such obligations for future type checks let supertype_error = self diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index d610f0a02f40..12e4dfe74fb8 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -54,7 +54,9 @@ )] #![allow(missing_docs)] -use crate::marker::{Destruct, DiscriminantKind}; +#[cfg(bootstrap)] +use crate::marker::Destruct; +use crate::marker::DiscriminantKind; use crate::mem; // These imports are used for simplifying intra-doc links @@ -2085,6 +2087,65 @@ extern "rust-intrinsic" { /// `ptr` must point to a vtable. /// The intrinsic will return the alignment stored in that vtable. pub fn vtable_align(ptr: *const ()) -> usize; + + /// Selects which function to call depending on the context. + /// + /// If this function is evaluated at compile-time, then a call to this + /// intrinsic will be replaced with a call to `called_in_const`. It gets + /// replaced with a call to `called_at_rt` otherwise. + /// + /// # Type Requirements + /// + /// The two functions must be both function items. They cannot be function + /// pointers or closures. The first function must be a `const fn`. + /// + /// `arg` will be the tupled arguments that will be passed to either one of + /// the two functions, therefore, both functions must accept the same type of + /// arguments. Both functions must return RET. + /// + /// # Safety + /// + /// The two functions must behave observably equivalent. Safe code in other + /// crates may assume that calling a `const fn` at compile-time and at run-time + /// produces the same result. A function that produces a different result when + /// evaluated at run-time, or has any other observable side-effects, is + /// *unsound*. + /// + /// Here is an example of how this could cause a problem: + /// ```no_run + /// #![feature(const_eval_select)] + /// #![feature(core_intrinsics)] + /// use std::hint::unreachable_unchecked; + /// use std::intrinsics::const_eval_select; + /// + /// // Crate A + /// pub const fn inconsistent() -> i32 { + /// fn runtime() -> i32 { 1 } + /// const fn compiletime() -> i32 { 2 } + /// + /// unsafe { + // // ⚠ This code violates the required equivalence of `compiletime` + /// // and `runtime`. + /// const_eval_select((), compiletime, runtime) + /// } + /// } + /// + /// // Crate B + /// const X: i32 = inconsistent(); + /// let x = inconsistent(); + /// if x != X { unsafe { unreachable_unchecked(); }} + /// ``` + /// + /// This code causes Undefined Behavior when being run, since the + /// `unreachable_unchecked` is actually being reached. The bug is in *crate A*, + /// which violates the principle that a `const fn` must behave the same at + /// compile-time and at run-time. The unsafe code in crate B is fine. + #[cfg(not(bootstrap))] + #[rustc_const_unstable(feature = "const_eval_select", issue = "none")] + pub fn const_eval_select(arg: ARG, called_in_const: F, called_at_rt: G) -> RET + where + G: FnOnce, + F: FnOnce; } // Some functions are defined here because they accidentally got made @@ -2095,6 +2156,11 @@ extern "rust-intrinsic" { /// Check that the preconditions of an unsafe function are followed, if debug_assertions are on, /// and only at runtime. /// +/// This macro should be called as `assert_unsafe_precondition!([Generics](name: Type) => Expression)` +/// where the names specified will be moved into the macro as captured variables, and defines an item +/// to call `const_eval_select` on. The tokens inside the square brackets are used to denote generics +/// for the function declaractions and can be omitted if there is no generics. +/// /// # Safety /// /// Invoking this macro is only sound if the following code is already UB when the passed @@ -2109,18 +2175,20 @@ extern "rust-intrinsic" { /// the occasional mistake, and this check should help them figure things out. #[allow_internal_unstable(const_eval_select)] // permit this to be called in stably-const fn macro_rules! assert_unsafe_precondition { - ($e:expr) => { + ($([$($tt:tt)*])?($($i:ident:$ty:ty),*$(,)?) => $e:expr) => { if cfg!(debug_assertions) { - // Use a closure so that we can capture arbitrary expressions from the invocation - let runtime = || { + // allow non_snake_case to allow capturing const generics + #[allow(non_snake_case)] + fn runtime$(<$($tt)*>)?($($i:$ty),*) { if !$e { // abort instead of panicking to reduce impact on code size ::core::intrinsics::abort(); } - }; - const fn comptime() {} + } + #[allow(non_snake_case)] + const fn comptime$(<$($tt)*>)?($(_:$ty),*) {} - ::core::intrinsics::const_eval_select((), comptime, runtime); + ::core::intrinsics::const_eval_select(($($i,)*), comptime, runtime); } }; } @@ -2243,7 +2311,7 @@ pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: us // SAFETY: the safety contract for `copy_nonoverlapping` must be // upheld by the caller. unsafe { - assert_unsafe_precondition!( + assert_unsafe_precondition!([T](src: *const T, dst: *mut T, count: usize) => is_aligned_and_not_null(src) && is_aligned_and_not_null(dst) && is_nonoverlapping(src, dst, count) @@ -2329,7 +2397,8 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { // SAFETY: the safety contract for `copy` must be upheld by the caller. unsafe { - assert_unsafe_precondition!(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)); + assert_unsafe_precondition!([T](src: *const T, dst: *mut T) => + is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)); copy(src, dst, count) } } @@ -2397,63 +2466,12 @@ pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { // SAFETY: the safety contract for `write_bytes` must be upheld by the caller. unsafe { - assert_unsafe_precondition!(is_aligned_and_not_null(dst)); + assert_unsafe_precondition!([T](dst: *mut T) => is_aligned_and_not_null(dst)); write_bytes(dst, val, count) } } -/// Selects which function to call depending on the context. -/// -/// If this function is evaluated at compile-time, then a call to this -/// intrinsic will be replaced with a call to `called_in_const`. It gets -/// replaced with a call to `called_at_rt` otherwise. -/// -/// # Type Requirements -/// -/// The two functions must be both function items. They cannot be function -/// pointers or closures. -/// -/// `arg` will be the arguments that will be passed to either one of the -/// two functions, therefore, both functions must accept the same type of -/// arguments. Both functions must return RET. -/// -/// # Safety -/// -/// The two functions must behave observably equivalent. Safe code in other -/// crates may assume that calling a `const fn` at compile-time and at run-time -/// produces the same result. A function that produces a different result when -/// evaluated at run-time, or has any other observable side-effects, is -/// *unsound*. -/// -/// Here is an example of how this could cause a problem: -/// ```no_run -/// #![feature(const_eval_select)] -/// #![feature(core_intrinsics)] -/// use std::hint::unreachable_unchecked; -/// use std::intrinsics::const_eval_select; -/// -/// // Crate A -/// pub const fn inconsistent() -> i32 { -/// fn runtime() -> i32 { 1 } -/// const fn compiletime() -> i32 { 2 } -/// -/// unsafe { -// // ⚠ This code violates the required equivalence of `compiletime` -/// // and `runtime`. -/// const_eval_select((), compiletime, runtime) -/// } -/// } -/// -/// // Crate B -/// const X: i32 = inconsistent(); -/// let x = inconsistent(); -/// if x != X { unsafe { unreachable_unchecked(); }} -/// ``` -/// -/// This code causes Undefined Behavior when being run, since the -/// `unreachable_unchecked` is actually being reached. The bug is in *crate A*, -/// which violates the principle that a `const fn` must behave the same at -/// compile-time and at run-time. The unsafe code in crate B is fine. +#[cfg(bootstrap)] #[unstable( feature = "const_eval_select", issue = "none", @@ -2475,6 +2493,7 @@ where called_at_rt.call_once(arg) } +#[cfg(bootstrap)] #[unstable( feature = "const_eval_select", issue = "none", diff --git a/library/core/src/mem/valid_align.rs b/library/core/src/mem/valid_align.rs index b9ccc0b4c799..32b2afb72b0d 100644 --- a/library/core/src/mem/valid_align.rs +++ b/library/core/src/mem/valid_align.rs @@ -28,7 +28,7 @@ impl ValidAlign { #[inline] pub(crate) const unsafe fn new_unchecked(align: usize) -> Self { // SAFETY: Precondition passed to the caller. - unsafe { assert_unsafe_precondition!(align.is_power_of_two()) }; + unsafe { assert_unsafe_precondition!((align: usize) => align.is_power_of_two()) }; // SAFETY: By precondition, this must be a power of two, and // our variants encompass all possible powers of two. diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index da41ea536357..6983d83808db 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1033,10 +1033,13 @@ impl f32 { } } } - // SAFETY: `u32` is a plain old datatype so we can always... uh... - // ...look, just pretend you forgot what you just read. - // Stability concerns. - let rt_f32_to_u32 = |rt| unsafe { mem::transmute::(rt) }; + + fn rt_f32_to_u32(x: f32) -> u32 { + // SAFETY: `u32` is a plain old datatype so we can always... uh... + // ...look, just pretend you forgot what you just read. + // Stability concerns. + unsafe { mem::transmute(x) } + } // SAFETY: We use internal implementations that either always work or fail at compile time. unsafe { intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32) } } @@ -1121,10 +1124,13 @@ impl f32 { } } } - // SAFETY: `u32` is a plain old datatype so we can always... uh... - // ...look, just pretend you forgot what you just read. - // Stability concerns. - let rt_u32_to_f32 = |rt| unsafe { mem::transmute::(rt) }; + + fn rt_u32_to_f32(x: u32) -> f32 { + // SAFETY: `u32` is a plain old datatype so we can always... uh... + // ...look, just pretend you forgot what you just read. + // Stability concerns. + unsafe { mem::transmute(x) } + } // SAFETY: We use internal implementations that either always work or fail at compile time. unsafe { intrinsics::const_eval_select((v,), ct_u32_to_f32, rt_u32_to_f32) } } diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 631d559df5f7..ce64afc0bd89 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1026,10 +1026,13 @@ impl f64 { } } } - // SAFETY: `u64` is a plain old datatype so we can always... uh... - // ...look, just pretend you forgot what you just read. - // Stability concerns. - let rt_f64_to_u64 = |rt| unsafe { mem::transmute::(rt) }; + + fn rt_f64_to_u64(rt: f64) -> u64 { + // SAFETY: `u64` is a plain old datatype so we can always... uh... + // ...look, just pretend you forgot what you just read. + // Stability concerns. + unsafe { mem::transmute::(rt) } + } // SAFETY: We use internal implementations that either always work or fail at compile time. unsafe { intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64) } } @@ -1119,10 +1122,13 @@ impl f64 { } } } - // SAFETY: `u64` is a plain old datatype so we can always... uh... - // ...look, just pretend you forgot what you just read. - // Stability concerns. - let rt_u64_to_f64 = |rt| unsafe { mem::transmute::(rt) }; + + fn rt_u64_to_f64(rt: u64) -> f64 { + // SAFETY: `u64` is a plain old datatype so we can always... uh... + // ...look, just pretend you forgot what you just read. + // Stability concerns. + unsafe { mem::transmute::(rt) } + } // SAFETY: We use internal implementations that either always work or fail at compile time. unsafe { intrinsics::const_eval_select((v,), ct_u64_to_f64, rt_u64_to_f64) } } diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 1cf306f2103b..532a09736a7a 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -56,7 +56,7 @@ macro_rules! nonzero_integers { pub const unsafe fn new_unchecked(n: $Int) -> Self { // SAFETY: this is guaranteed to be safe by the caller. unsafe { - core::intrinsics::assert_unsafe_precondition!(n != 0); + core::intrinsics::assert_unsafe_precondition!((n: $Int) => n != 0); Self(n) } } diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index f5c72d797553..80bff74f3e9f 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -755,9 +755,12 @@ impl *const T { where T: Sized, { + let this = self; // SAFETY: The comparison has no side-effects, and the intrinsic // does this check internally in the CTFE implementation. - unsafe { assert_unsafe_precondition!(self >= origin) }; + unsafe { + assert_unsafe_precondition!([T](this: *const T, origin: *const T) => this >= origin) + }; let pointee_size = mem::size_of::(); assert!(0 < pointee_size && pointee_size <= isize::MAX as usize); diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 41a2685d361c..e976abed774b 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -886,7 +886,7 @@ pub const unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { // SAFETY: the caller must guarantee that `x` and `y` are // valid for writes and properly aligned. unsafe { - assert_unsafe_precondition!( + assert_unsafe_precondition!([T](x: *mut T, y: *mut T, count: usize) => is_aligned_and_not_null(x) && is_aligned_and_not_null(y) && is_nonoverlapping(x, y, count) @@ -983,7 +983,7 @@ pub const unsafe fn replace(dst: *mut T, mut src: T) -> T { // and cannot overlap `src` since `dst` must point to a distinct // allocated object. unsafe { - assert_unsafe_precondition!(is_aligned_and_not_null(dst)); + assert_unsafe_precondition!([T](dst: *mut T) => is_aligned_and_not_null(dst)); mem::swap(&mut *dst, &mut src); // cannot overlap } src @@ -1470,7 +1470,7 @@ pub const unsafe fn write_unaligned(dst: *mut T, src: T) { pub unsafe fn read_volatile(src: *const T) -> T { // SAFETY: the caller must uphold the safety contract for `volatile_load`. unsafe { - assert_unsafe_precondition!(is_aligned_and_not_null(src)); + assert_unsafe_precondition!([T](src: *const T) => is_aligned_and_not_null(src)); intrinsics::volatile_load(src) } } @@ -1541,7 +1541,7 @@ pub unsafe fn read_volatile(src: *const T) -> T { pub unsafe fn write_volatile(dst: *mut T, src: T) { // SAFETY: the caller must uphold the safety contract for `volatile_store`. unsafe { - assert_unsafe_precondition!(is_aligned_and_not_null(dst)); + assert_unsafe_precondition!([T](dst: *mut T) => is_aligned_and_not_null(dst)); intrinsics::volatile_store(dst, src); } } diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index fd7ecf3daf31..3403a5a86f7c 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -48,10 +48,12 @@ const fn slice_start_index_len_fail(index: usize, len: usize) -> ! { } // FIXME const-hack +#[track_caller] fn slice_start_index_len_fail_rt(index: usize, len: usize) -> ! { panic!("range start index {index} out of range for slice of length {len}"); } +#[track_caller] const fn slice_start_index_len_fail_ct(_: usize, _: usize) -> ! { panic!("slice start index is out of range for slice"); } @@ -69,10 +71,12 @@ const fn slice_end_index_len_fail(index: usize, len: usize) -> ! { } // FIXME const-hack +#[track_caller] fn slice_end_index_len_fail_rt(index: usize, len: usize) -> ! { panic!("range end index {index} out of range for slice of length {len}"); } +#[track_caller] const fn slice_end_index_len_fail_ct(_: usize, _: usize) -> ! { panic!("slice end index is out of range for slice"); } @@ -88,10 +92,12 @@ const fn slice_index_order_fail(index: usize, end: usize) -> ! { } // FIXME const-hack +#[track_caller] fn slice_index_order_fail_rt(index: usize, end: usize) -> ! { panic!("slice index starts at {index} but ends at {end}"); } +#[track_caller] const fn slice_index_order_fail_ct(_: usize, _: usize) -> ! { panic!("slice index start is larger than end"); } @@ -217,21 +223,23 @@ unsafe impl const SliceIndex<[T]> for usize { #[inline] unsafe fn get_unchecked(self, slice: *const [T]) -> *const T { + let this = self; // SAFETY: the caller guarantees that `slice` is not dangling, so it // cannot be longer than `isize::MAX`. They also guarantee that // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, // so the call to `add` is safe. unsafe { - assert_unsafe_precondition!(self < slice.len()); + assert_unsafe_precondition!([T](this: usize, slice: *const [T]) => this < slice.len()); slice.as_ptr().add(self) } } #[inline] unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T { + let this = self; // SAFETY: see comments for `get_unchecked` above. unsafe { - assert_unsafe_precondition!(self < slice.len()); + assert_unsafe_precondition!([T](this: usize, slice: *mut [T]) => this < slice.len()); slice.as_mut_ptr().add(self) } } @@ -276,22 +284,26 @@ unsafe impl const SliceIndex<[T]> for ops::Range { #[inline] unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + let this = ops::Range { start: self.start, end: self.end }; // SAFETY: the caller guarantees that `slice` is not dangling, so it // cannot be longer than `isize::MAX`. They also guarantee that // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, // so the call to `add` is safe. unsafe { - assert_unsafe_precondition!(self.end >= self.start && self.end <= slice.len()); + assert_unsafe_precondition!([T](this: ops::Range, slice: *const [T]) => + this.end >= this.start && this.end <= slice.len()); ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start) } } #[inline] unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { + let this = ops::Range { start: self.start, end: self.end }; // SAFETY: see comments for `get_unchecked` above. unsafe { - assert_unsafe_precondition!(self.end >= self.start && self.end <= slice.len()); + assert_unsafe_precondition!([T](this: ops::Range, slice: *mut [T]) => + this.end >= this.start && this.end <= slice.len()); ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start) } } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 1958745b5868..6a7150d2986e 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -656,10 +656,11 @@ impl [T] { #[unstable(feature = "slice_swap_unchecked", issue = "88539")] #[rustc_const_unstable(feature = "const_swap", issue = "83163")] pub const unsafe fn swap_unchecked(&mut self, a: usize, b: usize) { - let ptr = self.as_mut_ptr(); + let this = self; + let ptr = this.as_mut_ptr(); // SAFETY: caller has to guarantee that `a < self.len()` and `b < self.len()` unsafe { - assert_unsafe_precondition!(a < self.len() && b < self.len()); + assert_unsafe_precondition!([T](a: usize, b: usize, this: &mut [T]) => a < this.len() && b < this.len()); ptr::swap(ptr.add(a), ptr.add(b)); } } @@ -972,9 +973,10 @@ impl [T] { #[inline] #[must_use] pub unsafe fn as_chunks_unchecked(&self) -> &[[T; N]] { + let this = self; // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length let new_len = unsafe { - assert_unsafe_precondition!(N != 0 && self.len() % N == 0); + assert_unsafe_precondition!([T](this: &[T], N: usize) => N != 0 && this.len() % N == 0); exact_div(self.len(), N) }; // SAFETY: We cast a slice of `new_len * N` elements into @@ -1111,10 +1113,11 @@ impl [T] { #[inline] #[must_use] pub unsafe fn as_chunks_unchecked_mut(&mut self) -> &mut [[T; N]] { + let this = &*self; // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length let new_len = unsafe { - assert_unsafe_precondition!(N != 0 && self.len() % N == 0); - exact_div(self.len(), N) + assert_unsafe_precondition!([T](this: &[T], N: usize) => N != 0 && this.len() % N == 0); + exact_div(this.len(), N) }; // SAFETY: We cast a slice of `new_len * N` elements into // a slice of `new_len` many `N` elements chunks. @@ -1687,7 +1690,7 @@ impl [T] { // `[ptr; mid]` and `[mid; len]` are not overlapping, so returning a mutable reference // is fine. unsafe { - assert_unsafe_precondition!(mid <= len); + assert_unsafe_precondition!((mid: usize, len: usize) => mid <= len); (from_raw_parts_mut(ptr, mid), from_raw_parts_mut(ptr.add(mid), len - mid)) } } diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs index 107e71ab68b0..f1e8bc79bf4a 100644 --- a/library/core/src/slice/raw.rs +++ b/library/core/src/slice/raw.rs @@ -90,7 +90,7 @@ use crate::ptr; pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { // SAFETY: the caller must uphold the safety contract for `from_raw_parts`. unsafe { - assert_unsafe_precondition!( + assert_unsafe_precondition!([T](data: *const T, len: usize) => is_aligned_and_not_null(data) && crate::mem::size_of::().saturating_mul(len) <= isize::MAX as usize ); @@ -134,7 +134,7 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] { // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`. unsafe { - assert_unsafe_precondition!( + assert_unsafe_precondition!([T](data: *mut T, len: usize) => is_aligned_and_not_null(data) && crate::mem::size_of::().saturating_mul(len) <= isize::MAX as usize ); diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 2120bf61d759..f673aa2a44b1 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -91,10 +91,12 @@ const fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! { } } +#[track_caller] const fn slice_error_fail_ct(_: &str, _: usize, _: usize) -> ! { panic!("failed to slice string"); } +#[track_caller] fn slice_error_fail_rt(s: &str, begin: usize, end: usize) -> ! { const MAX_DISPLAY_LENGTH: usize = 256; let trunc_len = s.floor_char_boundary(MAX_DISPLAY_LENGTH); diff --git a/src/test/ui/consts/const-float-bits-reject-conv.stderr b/src/test/ui/consts/const-float-bits-reject-conv.stderr index d6e993a10101..01f2f4895645 100644 --- a/src/test/ui/consts/const-float-bits-reject-conv.stderr +++ b/src/test/ui/consts/const-float-bits-reject-conv.stderr @@ -10,16 +10,6 @@ LL | panic!("const-eval error: cannot use f32::to_bits on a LL | unsafe { intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32) } | -------------------------------------------------------------------- inside `core::f32::::to_bits` at $SRC_DIR/core/src/num/f32.rs:LL:COL | - ::: $SRC_DIR/core/src/ops/function.rs:LL:COL - | -LL | extern "rust-call" fn call_once(self, args: Args) -> Self::Output; - | ------------------------------------------------------------------ inside ` u32 {core::f32::::to_bits::ct_f32_to_u32} as FnOnce<(f32,)>>::call_once - shim(fn(f32) -> u32 {core::f32::::to_bits::ct_f32_to_u32})` at $SRC_DIR/core/src/ops/function.rs:LL:COL - | - ::: $SRC_DIR/core/src/intrinsics.rs:LL:COL - | -LL | called_in_const.call_once(arg) - | ------------------------------ inside `const_eval_select::<(f32,), fn(f32) -> u32 {core::f32::::to_bits::ct_f32_to_u32}, [closure@core::f32::::to_bits::{closure#0}], u32>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL - | ::: $DIR/const-float-bits-reject-conv.rs:27:30 | LL | const MASKED_NAN1: u32 = f32::NAN.to_bits() ^ 0x002A_AAAA; @@ -39,16 +29,6 @@ LL | panic!("const-eval error: cannot use f32::to_bits on a LL | unsafe { intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32) } | -------------------------------------------------------------------- inside `core::f32::::to_bits` at $SRC_DIR/core/src/num/f32.rs:LL:COL | - ::: $SRC_DIR/core/src/ops/function.rs:LL:COL - | -LL | extern "rust-call" fn call_once(self, args: Args) -> Self::Output; - | ------------------------------------------------------------------ inside ` u32 {core::f32::::to_bits::ct_f32_to_u32} as FnOnce<(f32,)>>::call_once - shim(fn(f32) -> u32 {core::f32::::to_bits::ct_f32_to_u32})` at $SRC_DIR/core/src/ops/function.rs:LL:COL - | - ::: $SRC_DIR/core/src/intrinsics.rs:LL:COL - | -LL | called_in_const.call_once(arg) - | ------------------------------ inside `const_eval_select::<(f32,), fn(f32) -> u32 {core::f32::::to_bits::ct_f32_to_u32}, [closure@core::f32::::to_bits::{closure#0}], u32>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL - | ::: $DIR/const-float-bits-reject-conv.rs:28:30 | LL | const MASKED_NAN2: u32 = f32::NAN.to_bits() ^ 0x0055_5555; @@ -117,16 +97,6 @@ LL | panic!("const-eval error: cannot use f64::to_bits on a LL | unsafe { intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64) } | -------------------------------------------------------------------- inside `core::f64::::to_bits` at $SRC_DIR/core/src/num/f64.rs:LL:COL | - ::: $SRC_DIR/core/src/ops/function.rs:LL:COL - | -LL | extern "rust-call" fn call_once(self, args: Args) -> Self::Output; - | ------------------------------------------------------------------ inside ` u64 {core::f64::::to_bits::ct_f64_to_u64} as FnOnce<(f64,)>>::call_once - shim(fn(f64) -> u64 {core::f64::::to_bits::ct_f64_to_u64})` at $SRC_DIR/core/src/ops/function.rs:LL:COL - | - ::: $SRC_DIR/core/src/intrinsics.rs:LL:COL - | -LL | called_in_const.call_once(arg) - | ------------------------------ inside `const_eval_select::<(f64,), fn(f64) -> u64 {core::f64::::to_bits::ct_f64_to_u64}, [closure@core::f64::::to_bits::{closure#0}], u64>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL - | ::: $DIR/const-float-bits-reject-conv.rs:54:30 | LL | const MASKED_NAN1: u64 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA; @@ -146,16 +116,6 @@ LL | panic!("const-eval error: cannot use f64::to_bits on a LL | unsafe { intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64) } | -------------------------------------------------------------------- inside `core::f64::::to_bits` at $SRC_DIR/core/src/num/f64.rs:LL:COL | - ::: $SRC_DIR/core/src/ops/function.rs:LL:COL - | -LL | extern "rust-call" fn call_once(self, args: Args) -> Self::Output; - | ------------------------------------------------------------------ inside ` u64 {core::f64::::to_bits::ct_f64_to_u64} as FnOnce<(f64,)>>::call_once - shim(fn(f64) -> u64 {core::f64::::to_bits::ct_f64_to_u64})` at $SRC_DIR/core/src/ops/function.rs:LL:COL - | - ::: $SRC_DIR/core/src/intrinsics.rs:LL:COL - | -LL | called_in_const.call_once(arg) - | ------------------------------ inside `const_eval_select::<(f64,), fn(f64) -> u64 {core::f64::::to_bits::ct_f64_to_u64}, [closure@core::f64::::to_bits::{closure#0}], u64>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL - | ::: $DIR/const-float-bits-reject-conv.rs:55:30 | LL | const MASKED_NAN2: u64 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555; diff --git a/src/test/ui/intrinsics/const-eval-select-backtrace-std.rs b/src/test/ui/intrinsics/const-eval-select-backtrace-std.rs new file mode 100644 index 000000000000..29aefe07162b --- /dev/null +++ b/src/test/ui/intrinsics/const-eval-select-backtrace-std.rs @@ -0,0 +1,6 @@ +// See issue #100696. +// run-fail +// check-run-results +fn main() { + &""[1..]; +} diff --git a/src/test/ui/intrinsics/const-eval-select-backtrace-std.run.stderr b/src/test/ui/intrinsics/const-eval-select-backtrace-std.run.stderr new file mode 100644 index 000000000000..e53e6034620c --- /dev/null +++ b/src/test/ui/intrinsics/const-eval-select-backtrace-std.run.stderr @@ -0,0 +1,2 @@ +thread 'main' panicked at 'byte index 1 is out of bounds of ``', $DIR/const-eval-select-backtrace-std.rs:5:6 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/src/test/ui/intrinsics/const-eval-select-backtrace.rs b/src/test/ui/intrinsics/const-eval-select-backtrace.rs new file mode 100644 index 000000000000..99f0725200c1 --- /dev/null +++ b/src/test/ui/intrinsics/const-eval-select-backtrace.rs @@ -0,0 +1,18 @@ +#![feature(core_intrinsics)] +// See issue #100696. +// run-fail +// check-run-results + +#[track_caller] +fn uhoh() { + panic!("Aaah!") +} + +const fn c() {} + +fn main() { + // safety: this is unsound and just used to test + unsafe { + std::intrinsics::const_eval_select((), c, uhoh); + } +} diff --git a/src/test/ui/intrinsics/const-eval-select-backtrace.run.stderr b/src/test/ui/intrinsics/const-eval-select-backtrace.run.stderr new file mode 100644 index 000000000000..2fd730ac7a68 --- /dev/null +++ b/src/test/ui/intrinsics/const-eval-select-backtrace.run.stderr @@ -0,0 +1,2 @@ +thread 'main' panicked at 'Aaah!', $DIR/const-eval-select-backtrace.rs:16:9 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/src/test/ui/intrinsics/const-eval-select-bad.rs b/src/test/ui/intrinsics/const-eval-select-bad.rs index e5640f5ab53b..fa14efad7b4a 100644 --- a/src/test/ui/intrinsics/const-eval-select-bad.rs +++ b/src/test/ui/intrinsics/const-eval-select-bad.rs @@ -5,10 +5,13 @@ use std::intrinsics::const_eval_select; const fn not_fn_items() { const_eval_select((), || {}, || {}); - //~^ ERROR the trait bound + //~^ ERROR this argument must be a function item + //~| ERROR this argument must be a function item const_eval_select((), 42, 0xDEADBEEF); - //~^ ERROR the trait bound + //~^ ERROR expected a `FnOnce<()>` closure //~| ERROR expected a `FnOnce<()>` closure + //~| ERROR this argument must be a function item + //~| ERROR this argument must be a function item } const fn foo(n: i32) -> i32 { @@ -35,4 +38,9 @@ const fn args_ty_mismatch() { //~^ ERROR type mismatch } +const fn non_const_fn() { + const_eval_select((1,), bar, bar); + //~^ ERROR this argument must be a `const fn` +} + fn main() {} diff --git a/src/test/ui/intrinsics/const-eval-select-bad.stderr b/src/test/ui/intrinsics/const-eval-select-bad.stderr index 904e83624b3f..3720528ad4e4 100644 --- a/src/test/ui/intrinsics/const-eval-select-bad.stderr +++ b/src/test/ui/intrinsics/const-eval-select-bad.stderr @@ -1,42 +1,57 @@ -error[E0277]: the trait bound `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]: FnOnce<()>` is not satisfied - --> $DIR/const-eval-select-bad.rs:7:27 - | -LL | const_eval_select((), || {}, || {}); - | ----------------- ^^^^^ expected an `FnOnce<()>` closure, found `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]` - | | - | required by a bound introduced by this call - | - = help: the trait `~const FnOnce<()>` is not implemented for closure `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]` -note: the trait `FnOnce<()>` is implemented for `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]`, but that implementation is not `const` +error: this argument must be a function item --> $DIR/const-eval-select-bad.rs:7:27 | LL | const_eval_select((), || {}, || {}); | ^^^^^ - = note: wrap the `[closure@$DIR/const-eval-select-bad.rs:7:27: 7:29]` in a closure with no arguments: `|| { /* code */ }` -note: required by a bound in `const_eval_select` - --> $SRC_DIR/core/src/intrinsics.rs:LL:COL | -LL | F: ~const FnOnce, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select` + = note: expected a function item, found [closure@$DIR/const-eval-select-bad.rs:7:27: 7:29] + = help: consult the documentation on `const_eval_select` for more information -error[E0277]: the trait bound `{integer}: FnOnce<()>` is not satisfied - --> $DIR/const-eval-select-bad.rs:9:27 +error: this argument must be a function item + --> $DIR/const-eval-select-bad.rs:7:34 + | +LL | const_eval_select((), || {}, || {}); + | ^^^^^ + | + = note: expected a function item, found [closure@$DIR/const-eval-select-bad.rs:7:34: 7:36] + = help: consult the documentation on `const_eval_select` for more information + +error: this argument must be a function item + --> $DIR/const-eval-select-bad.rs:10:27 + | +LL | const_eval_select((), 42, 0xDEADBEEF); + | ^^ + | + = note: expected a function item, found {integer} + = help: consult the documentation on `const_eval_select` for more information + +error[E0277]: expected a `FnOnce<()>` closure, found `{integer}` + --> $DIR/const-eval-select-bad.rs:10:27 | LL | const_eval_select((), 42, 0xDEADBEEF); | ----------------- ^^ expected an `FnOnce<()>` closure, found `{integer}` | | | required by a bound introduced by this call | - = help: the trait `~const FnOnce<()>` is not implemented for `{integer}` + = help: the trait `FnOnce<()>` is not implemented for `{integer}` = note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }` note: required by a bound in `const_eval_select` --> $SRC_DIR/core/src/intrinsics.rs:LL:COL | -LL | F: ~const FnOnce, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select` +LL | F: FnOnce; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select` + +error: this argument must be a function item + --> $DIR/const-eval-select-bad.rs:10:31 + | +LL | const_eval_select((), 42, 0xDEADBEEF); + | ^^^^^^^^^^ + | + = note: expected a function item, found {integer} + = help: consult the documentation on `const_eval_select` for more information error[E0277]: expected a `FnOnce<()>` closure, found `{integer}` - --> $DIR/const-eval-select-bad.rs:9:31 + --> $DIR/const-eval-select-bad.rs:10:31 | LL | const_eval_select((), 42, 0xDEADBEEF); | ----------------- ^^^^^^^^^^ expected an `FnOnce<()>` closure, found `{integer}` @@ -48,11 +63,11 @@ LL | const_eval_select((), 42, 0xDEADBEEF); note: required by a bound in `const_eval_select` --> $SRC_DIR/core/src/intrinsics.rs:LL:COL | -LL | G: FnOnce + ~const Destruct, - | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select` +LL | G: FnOnce, + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select` error[E0271]: expected `fn(i32) -> bool {bar}` to be a fn item that returns `i32`, but it returns `bool` - --> $DIR/const-eval-select-bad.rs:29:34 + --> $DIR/const-eval-select-bad.rs:32:34 | LL | const_eval_select((1,), foo, bar); | ----------------- ^^^ expected `i32`, found `bool` @@ -62,11 +77,11 @@ LL | const_eval_select((1,), foo, bar); note: required by a bound in `const_eval_select` --> $SRC_DIR/core/src/intrinsics.rs:LL:COL | -LL | G: FnOnce + ~const Destruct, - | ^^^^^^^^^^^^ required by this bound in `const_eval_select` +LL | G: FnOnce, + | ^^^^^^^^^^^^ required by this bound in `const_eval_select` error[E0631]: type mismatch in function arguments - --> $DIR/const-eval-select-bad.rs:34:32 + --> $DIR/const-eval-select-bad.rs:37:32 | LL | const fn foo(n: i32) -> i32 { | --------------------------- found signature defined here @@ -81,10 +96,18 @@ LL | const_eval_select((true,), foo, baz); note: required by a bound in `const_eval_select` --> $SRC_DIR/core/src/intrinsics.rs:LL:COL | -LL | F: ~const FnOnce, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select` +LL | F: FnOnce; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select` -error: aborting due to 5 previous errors +error: this argument must be a `const fn` + --> $DIR/const-eval-select-bad.rs:42:29 + | +LL | const_eval_select((1,), bar, bar); + | ^^^ + | + = help: consult the documentation on `const_eval_select` for more information + +error: aborting due to 9 previous errors Some errors have detailed explanations: E0271, E0277, E0631. For more information about an error, try `rustc --explain E0271`. From bd61b8fb3ff04de61f40ea62043b17dc1e418c4c Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Fri, 26 Aug 2022 16:44:07 +0000 Subject: [PATCH 4153/5092] Add `inline(always)` to function generated by macro --- library/core/src/intrinsics.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 12e4dfe74fb8..56f5824efd4c 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2179,6 +2179,7 @@ macro_rules! assert_unsafe_precondition { if cfg!(debug_assertions) { // allow non_snake_case to allow capturing const generics #[allow(non_snake_case)] + #[inline(always)] fn runtime$(<$($tt)*>)?($($i:$ty),*) { if !$e { // abort instead of panicking to reduce impact on code size From 58c8823e3183611160207a47c9914bcbf84f9eb1 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 31 Aug 2022 13:28:55 +0000 Subject: [PATCH 4154/5092] remap mir before running optimization passes --- compiler/rustc_mir_transform/src/lib.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 69b49604250b..162f7d969b18 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -387,7 +387,9 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) - .body_const_context(def.did) .expect("mir_for_ctfe should not be used for runtime functions"); - let mut body = tcx.mir_drops_elaborated_and_const_checked(def).borrow().clone(); + let body = tcx.mir_drops_elaborated_and_const_checked(def).borrow().clone(); + + let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::Const); match context { // Do not const prop functions, either they get executed at runtime or exported to metadata, @@ -416,7 +418,7 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) - debug_assert!(!body.has_free_regions(), "Free regions in MIR for CTFE"); - remap_mir_for_const_eval_select(tcx, body, hir::Constness::Const) + body } /// Obtain just the main MIR (no promoteds) and run some cleanups on it. This also runs @@ -620,14 +622,15 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> { Some(other) => panic!("do not use `optimized_mir` for constants: {:?}", other), } debug!("about to call mir_drops_elaborated..."); - let mut body = + let body = tcx.mir_drops_elaborated_and_const_checked(ty::WithOptConstParam::unknown(did)).steal(); + let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::NotConst); debug!("body: {:#?}", body); run_optimization_passes(tcx, &mut body); debug_assert!(!body.has_free_regions(), "Free regions in optimized MIR"); - remap_mir_for_const_eval_select(tcx, body, hir::Constness::NotConst) + body } /// Fetch all the promoteds of an item and prepare their MIR bodies to be ready for From 65b685e82d26600ac8b468ef58954526163dfdf2 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Thu, 1 Sep 2022 18:53:17 +0800 Subject: [PATCH 4155/5092] Add `inline(always)` to rt functions --- library/core/src/num/f32.rs | 2 ++ library/core/src/num/f64.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 6983d83808db..c83b928efc18 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -1034,6 +1034,7 @@ impl f32 { } } + #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491 fn rt_f32_to_u32(x: f32) -> u32 { // SAFETY: `u32` is a plain old datatype so we can always... uh... // ...look, just pretend you forgot what you just read. @@ -1125,6 +1126,7 @@ impl f32 { } } + #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491 fn rt_u32_to_f32(x: u32) -> f32 { // SAFETY: `u32` is a plain old datatype so we can always... uh... // ...look, just pretend you forgot what you just read. diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index ce64afc0bd89..28d23f733deb 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -1027,6 +1027,7 @@ impl f64 { } } + #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491 fn rt_f64_to_u64(rt: f64) -> u64 { // SAFETY: `u64` is a plain old datatype so we can always... uh... // ...look, just pretend you forgot what you just read. @@ -1123,6 +1124,7 @@ impl f64 { } } + #[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491 fn rt_u64_to_f64(rt: u64) -> f64 { // SAFETY: `u64` is a plain old datatype so we can always... uh... // ...look, just pretend you forgot what you just read. From 41703e649b152d8ed9547f9c403cd9f20c46f4b1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 4 Sep 2022 15:16:55 +0200 Subject: [PATCH 4156/5092] Remove duplicated test (superseeded by search-form-elements.goml) --- src/test/rustdoc-gui/search-input.goml | 22 ---------------------- 1 file changed, 22 deletions(-) delete mode 100644 src/test/rustdoc-gui/search-input.goml diff --git a/src/test/rustdoc-gui/search-input.goml b/src/test/rustdoc-gui/search-input.goml deleted file mode 100644 index fd61c4f43d18..000000000000 --- a/src/test/rustdoc-gui/search-input.goml +++ /dev/null @@ -1,22 +0,0 @@ -// Ensures that the search input border color changes on focus. -goto: file://|DOC_PATH|/test_docs/index.html -local-storage: {"rustdoc-use-system-theme": "false", "rustdoc-theme": "dark"} -reload: - -assert-css: (".search-input", {"border-color": "rgb(224, 224, 224)"}) -click: ".search-input" -assert-css: (".search-input", {"border-color": "rgb(0, 141, 253)"}) - -local-storage: {"rustdoc-theme": "light"} -reload: - -assert-css: (".search-input", {"border-color": "rgb(224, 224, 224)"}) -click: ".search-input" -assert-css: (".search-input", {"border-color": "rgb(102, 175, 233)"}) - -local-storage: {"rustdoc-theme": "ayu"} -reload: - -assert-css: (".search-input", {"border-color": "rgb(92, 103, 115)"}) -click: ".search-input" -assert-css: (".search-input", {"border-color": "rgb(92, 103, 115)"}) From a2cdbf89637cd38fa5f1badbbc26b049a14345dd Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 21 Aug 2022 02:06:41 +0400 Subject: [PATCH 4157/5092] Make code worling w/ pointers in `library/std/src/sys/sgx/abi/usercalls/alloc.rs` nicer - Use `.addr()` instead of `as`-cast - Use `add` instead of `offset` and remove some `as isize` casts by doing that - Remove some casts --- .../std/src/sys/sgx/abi/usercalls/alloc.rs | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/library/std/src/sys/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/sgx/abi/usercalls/alloc.rs index 5409bd1777c2..0d934318c22a 100644 --- a/library/std/src/sys/sgx/abi/usercalls/alloc.rs +++ b/library/std/src/sys/sgx/abi/usercalls/alloc.rs @@ -316,9 +316,9 @@ where // | small1 | Chunk smaller than 8 bytes // +--------+ fn region_as_aligned_chunks(ptr: *const u8, len: usize) -> (usize, usize, usize) { - let small0_size = if ptr as usize % 8 == 0 { 0 } else { 8 - ptr as usize % 8 }; - let small1_size = (len - small0_size as usize) % 8; - let big_size = len - small0_size as usize - small1_size as usize; + let small0_size = if ptr.is_aligned_to(8) { 0 } else { 8 - ptr.addr() % 8 }; + let small1_size = (len - small0_size) % 8; + let big_size = len - small0_size - small1_size; (small0_size, big_size, small1_size) } @@ -364,8 +364,8 @@ pub(crate) unsafe fn copy_to_userspace(src: *const u8, dst: *mut u8, len: usize) mfence lfence ", - val = in(reg_byte) *src.offset(off as isize), - dst = in(reg) dst.offset(off as isize), + val = in(reg_byte) *src.add(off), + dst = in(reg) dst.add(off), seg_sel = in(reg) &mut seg_sel, options(nostack, att_syntax) ); @@ -378,8 +378,8 @@ pub(crate) unsafe fn copy_to_userspace(src: *const u8, dst: *mut u8, len: usize) assert!(is_enclave_range(src, len)); assert!(is_user_range(dst, len)); assert!(len < isize::MAX as usize); - assert!(!(src as usize).overflowing_add(len).1); - assert!(!(dst as usize).overflowing_add(len).1); + assert!(!src.addr().overflowing_add(len).1); + assert!(!dst.addr().overflowing_add(len).1); if len < 8 { // Can't align on 8 byte boundary: copy safely byte per byte @@ -404,17 +404,17 @@ pub(crate) unsafe fn copy_to_userspace(src: *const u8, dst: *mut u8, len: usize) unsafe { // Copy small0 - copy_bytewise_to_userspace(src, dst, small0_size as _); + copy_bytewise_to_userspace(src, dst, small0_size); // Copy big - let big_src = src.offset(small0_size as _); - let big_dst = dst.offset(small0_size as _); - copy_quadwords(big_src as _, big_dst, big_size); + let big_src = src.add(small0_size); + let big_dst = dst.add(small0_size); + copy_quadwords(big_src, big_dst, big_size); // Copy small1 - let small1_src = src.offset(big_size as isize + small0_size as isize); - let small1_dst = dst.offset(big_size as isize + small0_size as isize); - copy_bytewise_to_userspace(small1_src, small1_dst, small1_size as _); + let small1_src = src.add(big_size + small0_size); + let small1_dst = dst.add(big_size + small0_size); + copy_bytewise_to_userspace(small1_src, small1_dst, small1_size); } } } From 495fa48790fad465edcdb7965d349617854a86c3 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 21 Aug 2022 02:16:51 +0400 Subject: [PATCH 4158/5092] use `pointer::add` in memchr impl --- library/core/src/slice/memchr.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/slice/memchr.rs b/library/core/src/slice/memchr.rs index dffeaf6a834e..d8a4fd6c1ce0 100644 --- a/library/core/src/slice/memchr.rs +++ b/library/core/src/slice/memchr.rs @@ -124,8 +124,8 @@ pub fn memrchr(x: u8, text: &[u8]) -> Option { // SAFETY: offset starts at len - suffix.len(), as long as it is greater than // min_aligned_offset (prefix.len()) the remaining distance is at least 2 * chunk_bytes. unsafe { - let u = *(ptr.offset(offset as isize - 2 * chunk_bytes as isize) as *const Chunk); - let v = *(ptr.offset(offset as isize - chunk_bytes as isize) as *const Chunk); + let u = *(ptr.add(offset - 2 * chunk_bytes) as *const Chunk); + let v = *(ptr.add(offset - chunk_bytes) as *const Chunk); // Break if there is a matching byte. let zu = contains_zero_byte(u ^ repeated_x); From 31b71816cd66d53b544902f38b7043c773d3ecda Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 21 Aug 2022 02:18:16 +0400 Subject: [PATCH 4159/5092] Replace `offset` with `add` in `fmt/num.rs` & remove some casts --- library/core/src/fmt/num.rs | 124 ++++++++++++++++++------------------ 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index 25789d37c269..b11ed6b0b42a 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -211,7 +211,7 @@ macro_rules! impl_Display { fn $name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { // 2^128 is about 3*10^38, so 39 gives an extra byte of space let mut buf = [MaybeUninit::::uninit(); 39]; - let mut curr = buf.len() as isize; + let mut curr = buf.len(); let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf); let lut_ptr = DEC_DIGITS_LUT.as_ptr(); @@ -228,7 +228,7 @@ macro_rules! impl_Display { // eagerly decode 4 characters at a time while n >= 10000 { - let rem = (n % 10000) as isize; + let rem = (n % 10000) as usize; n /= 10000; let d1 = (rem / 100) << 1; @@ -238,29 +238,29 @@ macro_rules! impl_Display { // We are allowed to copy to `buf_ptr[curr..curr + 3]` here since // otherwise `curr < 0`. But then `n` was originally at least `10000^10` // which is `10^40 > 2^128 > n`. - ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2); - ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2); + ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2); + ptr::copy_nonoverlapping(lut_ptr.add(d2), buf_ptr.add(curr + 2), 2); } // if we reach here numbers are <= 9999, so at most 4 chars long - let mut n = n as isize; // possibly reduce 64bit math + let mut n = n as usize; // possibly reduce 64bit math // decode 2 more chars, if > 2 chars if n >= 100 { let d1 = (n % 100) << 1; n /= 100; curr -= 2; - ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2); + ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2); } // decode last 1 or 2 chars if n < 10 { curr -= 1; - *buf_ptr.offset(curr) = (n as u8) + b'0'; + *buf_ptr.add(curr) = (n as u8) + b'0'; } else { let d1 = n << 1; curr -= 2; - ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2); + ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2); } } @@ -268,7 +268,7 @@ macro_rules! impl_Display { // UTF-8 since `DEC_DIGITS_LUT` is let buf_slice = unsafe { str::from_utf8_unchecked( - slice::from_raw_parts(buf_ptr.offset(curr), buf.len() - curr as usize)) + slice::from_raw_parts(buf_ptr.add(curr), buf.len() - curr)) }; f.pad_integral(is_nonnegative, "", buf_slice) } @@ -339,18 +339,18 @@ macro_rules! impl_Exp { // Since `curr` always decreases by the number of digits copied, this means // that `curr >= 0`. let mut buf = [MaybeUninit::::uninit(); 40]; - let mut curr = buf.len() as isize; //index for buf + let mut curr = buf.len(); //index for buf let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf); let lut_ptr = DEC_DIGITS_LUT.as_ptr(); // decode 2 chars at a time while n >= 100 { - let d1 = ((n % 100) as isize) << 1; + let d1 = ((n % 100) << 1) as usize; curr -= 2; // SAFETY: `d1 <= 198`, so we can copy from `lut_ptr[d1..d1 + 2]` since // `DEC_DIGITS_LUT` has a length of 200. unsafe { - ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2); + ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2); } n /= 100; exponent += 2; @@ -362,7 +362,7 @@ macro_rules! impl_Exp { curr -= 1; // SAFETY: Safe since `40 > curr >= 0` (see comment) unsafe { - *buf_ptr.offset(curr) = (n as u8 % 10_u8) + b'0'; + *buf_ptr.add(curr) = (n as u8 % 10_u8) + b'0'; } n /= 10; exponent += 1; @@ -372,7 +372,7 @@ macro_rules! impl_Exp { curr -= 1; // SAFETY: Safe since `40 > curr >= 0` unsafe { - *buf_ptr.offset(curr) = b'.'; + *buf_ptr.add(curr) = b'.'; } } @@ -380,10 +380,10 @@ macro_rules! impl_Exp { let buf_slice = unsafe { // decode last character curr -= 1; - *buf_ptr.offset(curr) = (n as u8) + b'0'; + *buf_ptr.add(curr) = (n as u8) + b'0'; let len = buf.len() - curr as usize; - slice::from_raw_parts(buf_ptr.offset(curr), len) + slice::from_raw_parts(buf_ptr.add(curr), len) }; // stores 'e' (or 'E') and the up to 2-digit exponent @@ -392,13 +392,13 @@ macro_rules! impl_Exp { // SAFETY: In either case, `exp_buf` is written within bounds and `exp_ptr[..len]` // is contained within `exp_buf` since `len <= 3`. let exp_slice = unsafe { - *exp_ptr.offset(0) = if upper { b'E' } else { b'e' }; + *exp_ptr.add(0) = if upper { b'E' } else { b'e' }; let len = if exponent < 10 { - *exp_ptr.offset(1) = (exponent as u8) + b'0'; + *exp_ptr.add(1) = (exponent as u8) + b'0'; 2 } else { let off = exponent << 1; - ptr::copy_nonoverlapping(lut_ptr.offset(off), exp_ptr.offset(1), 2); + ptr::copy_nonoverlapping(lut_ptr.add(off), exp_ptr.add(1), 2); 3 }; slice::from_raw_parts(exp_ptr, len) @@ -479,7 +479,7 @@ mod imp { impl_Exp!(i128, u128 as u128 via to_u128 named exp_u128); /// Helper function for writing a u64 into `buf` going from last to first, with `curr`. -fn parse_u64_into(mut n: u64, buf: &mut [MaybeUninit; N], curr: &mut isize) { +fn parse_u64_into(mut n: u64, buf: &mut [MaybeUninit; N], curr: &mut usize) { let buf_ptr = MaybeUninit::slice_as_mut_ptr(buf); let lut_ptr = DEC_DIGITS_LUT.as_ptr(); assert!(*curr > 19); @@ -494,41 +494,41 @@ fn parse_u64_into(mut n: u64, buf: &mut [MaybeUninit; N], cu n /= 1e16 as u64; // Some of these are nops but it looks more elegant this way. - let d1 = ((to_parse / 1e14 as u64) % 100) << 1; - let d2 = ((to_parse / 1e12 as u64) % 100) << 1; - let d3 = ((to_parse / 1e10 as u64) % 100) << 1; - let d4 = ((to_parse / 1e8 as u64) % 100) << 1; - let d5 = ((to_parse / 1e6 as u64) % 100) << 1; - let d6 = ((to_parse / 1e4 as u64) % 100) << 1; - let d7 = ((to_parse / 1e2 as u64) % 100) << 1; - let d8 = ((to_parse / 1e0 as u64) % 100) << 1; + let d1 = (((to_parse / 1e14 as u64) % 100) << 1) as usize; + let d2 = (((to_parse / 1e12 as u64) % 100) << 1) as usize; + let d3 = (((to_parse / 1e10 as u64) % 100) << 1) as usize; + let d4 = (((to_parse / 1e8 as u64) % 100) << 1) as usize; + let d5 = (((to_parse / 1e6 as u64) % 100) << 1) as usize; + let d6 = (((to_parse / 1e4 as u64) % 100) << 1) as usize; + let d7 = (((to_parse / 1e2 as u64) % 100) << 1) as usize; + let d8 = (((to_parse / 1e0 as u64) % 100) << 1) as usize; *curr -= 16; - ptr::copy_nonoverlapping(lut_ptr.offset(d1 as isize), buf_ptr.offset(*curr + 0), 2); - ptr::copy_nonoverlapping(lut_ptr.offset(d2 as isize), buf_ptr.offset(*curr + 2), 2); - ptr::copy_nonoverlapping(lut_ptr.offset(d3 as isize), buf_ptr.offset(*curr + 4), 2); - ptr::copy_nonoverlapping(lut_ptr.offset(d4 as isize), buf_ptr.offset(*curr + 6), 2); - ptr::copy_nonoverlapping(lut_ptr.offset(d5 as isize), buf_ptr.offset(*curr + 8), 2); - ptr::copy_nonoverlapping(lut_ptr.offset(d6 as isize), buf_ptr.offset(*curr + 10), 2); - ptr::copy_nonoverlapping(lut_ptr.offset(d7 as isize), buf_ptr.offset(*curr + 12), 2); - ptr::copy_nonoverlapping(lut_ptr.offset(d8 as isize), buf_ptr.offset(*curr + 14), 2); + ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(*curr + 0), 2); + ptr::copy_nonoverlapping(lut_ptr.add(d2), buf_ptr.add(*curr + 2), 2); + ptr::copy_nonoverlapping(lut_ptr.add(d3), buf_ptr.add(*curr + 4), 2); + ptr::copy_nonoverlapping(lut_ptr.add(d4), buf_ptr.add(*curr + 6), 2); + ptr::copy_nonoverlapping(lut_ptr.add(d5), buf_ptr.add(*curr + 8), 2); + ptr::copy_nonoverlapping(lut_ptr.add(d6), buf_ptr.add(*curr + 10), 2); + ptr::copy_nonoverlapping(lut_ptr.add(d7), buf_ptr.add(*curr + 12), 2); + ptr::copy_nonoverlapping(lut_ptr.add(d8), buf_ptr.add(*curr + 14), 2); } if n >= 1e8 as u64 { let to_parse = n % 1e8 as u64; n /= 1e8 as u64; // Some of these are nops but it looks more elegant this way. - let d1 = ((to_parse / 1e6 as u64) % 100) << 1; - let d2 = ((to_parse / 1e4 as u64) % 100) << 1; - let d3 = ((to_parse / 1e2 as u64) % 100) << 1; - let d4 = ((to_parse / 1e0 as u64) % 100) << 1; + let d1 = (((to_parse / 1e6 as u64) % 100) << 1) as usize; + let d2 = (((to_parse / 1e4 as u64) % 100) << 1) as usize; + let d3 = (((to_parse / 1e2 as u64) % 100) << 1) as usize; + let d4 = (((to_parse / 1e0 as u64) % 100) << 1) as usize; *curr -= 8; - ptr::copy_nonoverlapping(lut_ptr.offset(d1 as isize), buf_ptr.offset(*curr + 0), 2); - ptr::copy_nonoverlapping(lut_ptr.offset(d2 as isize), buf_ptr.offset(*curr + 2), 2); - ptr::copy_nonoverlapping(lut_ptr.offset(d3 as isize), buf_ptr.offset(*curr + 4), 2); - ptr::copy_nonoverlapping(lut_ptr.offset(d4 as isize), buf_ptr.offset(*curr + 6), 2); + ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(*curr + 0), 2); + ptr::copy_nonoverlapping(lut_ptr.add(d2), buf_ptr.add(*curr + 2), 2); + ptr::copy_nonoverlapping(lut_ptr.add(d3), buf_ptr.add(*curr + 4), 2); + ptr::copy_nonoverlapping(lut_ptr.add(d4), buf_ptr.add(*curr + 6), 2); } // `n` < 1e8 < (1 << 32) let mut n = n as u32; @@ -536,31 +536,31 @@ fn parse_u64_into(mut n: u64, buf: &mut [MaybeUninit; N], cu let to_parse = n % 1e4 as u32; n /= 1e4 as u32; - let d1 = (to_parse / 100) << 1; - let d2 = (to_parse % 100) << 1; + let d1 = ((to_parse / 100) << 1) as usize; + let d2 = ((to_parse % 100) << 1) as usize; *curr -= 4; - ptr::copy_nonoverlapping(lut_ptr.offset(d1 as isize), buf_ptr.offset(*curr + 0), 2); - ptr::copy_nonoverlapping(lut_ptr.offset(d2 as isize), buf_ptr.offset(*curr + 2), 2); + ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(*curr + 0), 2); + ptr::copy_nonoverlapping(lut_ptr.add(d2), buf_ptr.add(*curr + 2), 2); } // `n` < 1e4 < (1 << 16) let mut n = n as u16; if n >= 100 { - let d1 = (n % 100) << 1; + let d1 = ((n % 100) << 1) as usize; n /= 100; *curr -= 2; - ptr::copy_nonoverlapping(lut_ptr.offset(d1 as isize), buf_ptr.offset(*curr), 2); + ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(*curr), 2); } // decode last 1 or 2 chars if n < 10 { *curr -= 1; - *buf_ptr.offset(*curr) = (n as u8) + b'0'; + *buf_ptr.add(*curr) = (n as u8) + b'0'; } else { - let d1 = n << 1; + let d1 = (n << 1) as usize; *curr -= 2; - ptr::copy_nonoverlapping(lut_ptr.offset(d1 as isize), buf_ptr.offset(*curr), 2); + ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(*curr), 2); } } } @@ -593,21 +593,21 @@ impl fmt::Display for i128 { fn fmt_u128(n: u128, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { // 2^128 is about 3*10^38, so 39 gives an extra byte of space let mut buf = [MaybeUninit::::uninit(); 39]; - let mut curr = buf.len() as isize; + let mut curr = buf.len(); let (n, rem) = udiv_1e19(n); parse_u64_into(rem, &mut buf, &mut curr); if n != 0 { // 0 pad up to point - let target = (buf.len() - 19) as isize; + let target = buf.len() - 19; // SAFETY: Guaranteed that we wrote at most 19 bytes, and there must be space // remaining since it has length 39 unsafe { ptr::write_bytes( - MaybeUninit::slice_as_mut_ptr(&mut buf).offset(target), + MaybeUninit::slice_as_mut_ptr(&mut buf).add(target), b'0', - (curr - target) as usize, + curr - target, ); } curr = target; @@ -616,16 +616,16 @@ fn fmt_u128(n: u128, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::R parse_u64_into(rem, &mut buf, &mut curr); // Should this following branch be annotated with unlikely? if n != 0 { - let target = (buf.len() - 38) as isize; + let target = buf.len() - 38; // The raw `buf_ptr` pointer is only valid until `buf` is used the next time, // buf `buf` is not used in this scope so we are good. let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf); // SAFETY: At this point we wrote at most 38 bytes, pad up to that point, // There can only be at most 1 digit remaining. unsafe { - ptr::write_bytes(buf_ptr.offset(target), b'0', (curr - target) as usize); + ptr::write_bytes(buf_ptr.add(target), b'0', curr - target); curr = target - 1; - *buf_ptr.offset(curr) = (n as u8) + b'0'; + *buf_ptr.add(curr) = (n as u8) + b'0'; } } } @@ -634,8 +634,8 @@ fn fmt_u128(n: u128, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::R // UTF-8 since `DEC_DIGITS_LUT` is let buf_slice = unsafe { str::from_utf8_unchecked(slice::from_raw_parts( - MaybeUninit::slice_as_mut_ptr(&mut buf).offset(curr), - buf.len() - curr as usize, + MaybeUninit::slice_as_mut_ptr(&mut buf).add(curr), + buf.len() - curr, )) }; f.pad_integral(is_nonnegative, "", buf_slice) From e295f0c29cc41be34fee364fe1fcf1a1b0bbd31a Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sun, 4 Sep 2022 13:26:00 +0000 Subject: [PATCH 4160/5092] Insert whitespaces into static & const bodies if they are expanded from macro on hover Macro expansion erases whitespace information, and so we end with invalid Rust code. --- crates/ide/src/hover/render.rs | 21 ++++++++++-- crates/ide/src/hover/tests.rs | 59 ++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 3 deletions(-) diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index d52adaee535f..c5c50d88dd28 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -2,12 +2,13 @@ use std::fmt::Display; use either::Either; -use hir::{AsAssocItem, AttributeTemplate, HasAttrs, HirDisplay, Semantics, TypeInfo}; +use hir::{AsAssocItem, AttributeTemplate, HasAttrs, HasSource, HirDisplay, Semantics, TypeInfo}; use ide_db::{ base_db::SourceDatabase, defs::Definition, famous_defs::FamousDefs, generated::lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES}, + syntax_helpers::insert_whitespace_into_node, RootDatabase, }; use itertools::Itertools; @@ -350,10 +351,24 @@ pub(super) fn definition( let body = it.eval(db); match body { Ok(x) => Some(format!("{}", x)), - Err(_) => it.value(db).map(|x| format!("{}", x)), + Err(_) => { + let source = it.source(db)?; + let mut body = source.value.body()?.syntax().clone(); + if source.file_id.is_macro() { + body = insert_whitespace_into_node::insert_ws_into(body); + } + Some(body.to_string()) + } } }), - Definition::Static(it) => label_value_and_docs(db, it, |it| it.value(db)), + Definition::Static(it) => label_value_and_docs(db, it, |it| { + let source = it.source(db)?; + let mut body = source.value.body()?.syntax().clone(); + if source.file_id.is_macro() { + body = insert_whitespace_into_node::insert_ws_into(body); + } + Some(body.to_string()) + }), Definition::Trait(it) => label_and_docs(db, it), Definition::TypeAlias(it) => label_and_docs(db, it), Definition::BuiltinType(it) => { diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 685eb4521ebd..d49bc4f99cfd 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -5113,3 +5113,62 @@ fn f() { "#]], ); } + +#[test] +fn static_const_macro_expanded_body() { + check( + r#" +macro_rules! m { + () => { + pub const V: i8 = { + let e = 123; + f(e) // Prevent const eval from evaluating this constant, we want to print the body's code. + }; + }; +} +m!(); +fn main() { $0V; } +"#, + expect![[r#" + *V* + + ```rust + test + ``` + + ```rust + pub const V: i8 = { + let e = 123; + f(e) + } + ``` + "#]], + ); + check( + r#" +macro_rules! m { + () => { + pub static V: i8 = { + let e = 123; + }; + }; +} +m!(); +fn main() { $0V; } +"#, + expect![[r#" + *V* + + ```rust + test + ``` + + ```rust + pub static V: i8 = { + let e = 123; + + } + ``` + "#]], + ); +} From 26b5f1f92fa50215a2b70fb5211c300d56f290f2 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sun, 4 Sep 2022 14:24:16 +0000 Subject: [PATCH 4161/5092] Do not insert a newline after `;` if the next token is a `}` This creates double newline. --- .../ide-db/src/syntax_helpers/insert_whitespace_into_node.rs | 2 +- crates/ide/src/hover/tests.rs | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs b/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs index f54ae6c92022..8bc093a85a21 100644 --- a/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs +++ b/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs @@ -95,7 +95,7 @@ pub fn insert_ws_into(syn: SyntaxNode) -> SyntaxNode { AS_KW | DYN_KW | IMPL_KW | CONST_KW => { mods.push(do_ws(after, tok)); } - T![;] => { + T![;] if is_next(|it| it != R_CURLY, true) => { if indent > 0 { mods.push(do_indent(after, tok, indent)); } diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index d49bc4f99cfd..4b8b47783d12 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -5135,7 +5135,7 @@ fn main() { $0V; } ```rust test ``` - + ```rust pub const V: i8 = { let e = 123; @@ -5162,11 +5162,10 @@ fn main() { $0V; } ```rust test ``` - + ```rust pub static V: i8 = { let e = 123; - } ``` "#]], From 4a3e169da746783fa7bf7cc61faa077e16989c5b Mon Sep 17 00:00:00 2001 From: Sage Mitchell Date: Fri, 2 Sep 2022 20:52:28 -0700 Subject: [PATCH 4162/5092] Make `char::is_lowercase` and `char::is_uppercase` const Implements #101400. --- library/core/src/char/methods.rs | 22 +++++++++++-- library/core/src/lib.rs | 1 + library/core/src/unicode/unicode_data.rs | 33 ++++++++++--------- .../src/range_search.rs | 11 ++++--- .../src/raw_emitter.rs | 15 ++++++--- 5 files changed, 55 insertions(+), 27 deletions(-) diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 2433139a592b..b7a63b7c6756 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -746,10 +746,19 @@ impl char { /// assert!(!'中'.is_lowercase()); /// assert!(!' '.is_lowercase()); /// ``` + /// + /// In a const context: + /// + /// ``` + /// #![feature(const_unicode_case_lookup)] + /// const CAPITAL_DELTA_IS_LOWERCASE: bool = 'Δ'.is_lowercase(); + /// assert!(!CAPITAL_DELTA_IS_LOWERCASE); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")] #[inline] - pub fn is_lowercase(self) -> bool { + pub const fn is_lowercase(self) -> bool { match self { 'a'..='z' => true, c => c > '\x7f' && unicode::Lowercase(c), @@ -779,10 +788,19 @@ impl char { /// assert!(!'中'.is_uppercase()); /// assert!(!' '.is_uppercase()); /// ``` + /// + /// In a const context: + /// + /// ``` + /// #![feature(const_unicode_case_lookup)] + /// const CAPITAL_DELTA_IS_UPPERCASE: bool = 'Δ'.is_uppercase(); + /// assert!(CAPITAL_DELTA_IS_UPPERCASE); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")] #[inline] - pub fn is_uppercase(self) -> bool { + pub const fn is_uppercase(self) -> bool { match self { 'A'..='Z' => true, c => c > '\x7f' && unicode::Uppercase(c), diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 9d857eb63da9..5b1e2045fff6 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -143,6 +143,7 @@ #![feature(const_type_id)] #![feature(const_type_name)] #![feature(const_default_impls)] +#![feature(const_unicode_case_lookup)] #![feature(const_unsafecell_get_mut)] #![feature(core_panic)] #![feature(duration_consts_float)] diff --git a/library/core/src/unicode/unicode_data.rs b/library/core/src/unicode/unicode_data.rs index c1eff3a36e6e..2bbedf0e2d29 100644 --- a/library/core/src/unicode/unicode_data.rs +++ b/library/core/src/unicode/unicode_data.rs @@ -1,7 +1,8 @@ ///! This file is generated by src/tools/unicode-table-generator; do not edit manually! +#[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")] #[inline(always)] -fn bitset_search< +const fn bitset_search< const N: usize, const CHUNK_SIZE: usize, const N1: usize, @@ -17,14 +18,14 @@ fn bitset_search< let bucket_idx = (needle / 64) as usize; let chunk_map_idx = bucket_idx / CHUNK_SIZE; let chunk_piece = bucket_idx % CHUNK_SIZE; - let chunk_idx = if let Some(&v) = chunk_idx_map.get(chunk_map_idx) { - v + let chunk_idx = if chunk_map_idx < chunk_idx_map.len() { + chunk_idx_map[chunk_map_idx] } else { return false; }; let idx = bitset_chunk_idx[chunk_idx as usize][chunk_piece] as usize; - let word = if let Some(word) = bitset_canonical.get(idx) { - *word + let word = if idx < bitset_canonical.len() { + bitset_canonical[idx] } else { let (real_idx, mapping) = bitset_canonicalized[idx - bitset_canonical.len()]; let mut word = bitset_canonical[real_idx as usize]; @@ -318,14 +319,14 @@ pub mod grapheme_extend { #[rustfmt::skip] pub mod lowercase { - static BITSET_CHUNKS_MAP: [u8; 123] = [ + const BITSET_CHUNKS_MAP: [u8; 123] = [ 14, 17, 0, 0, 9, 0, 0, 12, 13, 10, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 1, 0, 15, 0, 8, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 3, 0, 0, 7, ]; - static BITSET_INDEX_CHUNKS: [[u8; 16]; 19] = [ + const BITSET_INDEX_CHUNKS: [[u8; 16]; 19] = [ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 14, 55, 0], @@ -346,7 +347,7 @@ pub mod lowercase { [16, 49, 2, 20, 66, 9, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0], [63, 39, 54, 12, 73, 61, 18, 1, 6, 62, 71, 19, 68, 69, 3, 44], ]; - static BITSET_CANONICAL: [u64; 55] = [ + const BITSET_CANONICAL: [u64; 55] = [ 0b0000000000000000000000000000000000000000000000000000000000000000, 0b1111111111111111110000000000000000000000000011111111111111111111, 0b1010101010101010101010101010101010101010101010101010100000000010, @@ -403,13 +404,14 @@ pub mod lowercase { 0b1110011111111111111111111111111111111111111111110000000000000000, 0b1110101111000000000000000000000000001111111111111111111111111100, ]; - static BITSET_MAPPING: [(u8, u8); 20] = [ + const BITSET_MAPPING: [(u8, u8); 20] = [ (0, 64), (1, 188), (1, 183), (1, 176), (1, 109), (1, 124), (1, 126), (1, 66), (1, 70), (1, 77), (2, 146), (2, 144), (2, 83), (3, 12), (3, 6), (4, 156), (4, 78), (5, 187), (6, 132), (7, 93), ]; - pub fn lookup(c: char) -> bool { + #[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")] + pub const fn lookup(c: char) -> bool { super::bitset_search( c as u32, &BITSET_CHUNKS_MAP, @@ -454,14 +456,14 @@ pub mod n { #[rustfmt::skip] pub mod uppercase { - static BITSET_CHUNKS_MAP: [u8; 125] = [ + const BITSET_CHUNKS_MAP: [u8; 125] = [ 12, 15, 6, 6, 0, 6, 6, 2, 4, 11, 6, 16, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 8, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 6, 14, 6, 10, 6, 6, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 13, 6, 6, 6, 6, 9, 6, 3, ]; - static BITSET_INDEX_CHUNKS: [[u8; 16]; 17] = [ + const BITSET_INDEX_CHUNKS: [[u8; 16]; 17] = [ [43, 43, 5, 34, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 5, 1], [43, 43, 5, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43], [43, 43, 39, 43, 43, 43, 43, 43, 17, 17, 62, 17, 42, 29, 24, 23], @@ -480,7 +482,7 @@ pub mod uppercase { [57, 19, 2, 18, 10, 47, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43], [57, 37, 17, 27, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43], ]; - static BITSET_CANONICAL: [u64; 43] = [ + const BITSET_CANONICAL: [u64; 43] = [ 0b0000011111111111111111111111111000000000000000000000000000000000, 0b0000000000111111111111111111111111111111111111111111111111111111, 0b0101010101010101010101010101010101010101010101010101010000000001, @@ -525,13 +527,14 @@ pub mod uppercase { 0b1111011111111111000000000000000000000000000000000000000000000000, 0b1111111100000000111111110000000000111111000000001111111100000000, ]; - static BITSET_MAPPING: [(u8, u8); 25] = [ + const BITSET_MAPPING: [(u8, u8); 25] = [ (0, 187), (0, 177), (0, 171), (0, 167), (0, 164), (0, 32), (0, 47), (0, 51), (0, 121), (0, 117), (0, 109), (1, 150), (1, 148), (1, 142), (1, 134), (1, 131), (1, 64), (2, 164), (2, 146), (2, 20), (3, 146), (3, 140), (3, 134), (4, 178), (4, 171), ]; - pub fn lookup(c: char) -> bool { + #[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")] + pub const fn lookup(c: char) -> bool { super::bitset_search( c as u32, &BITSET_CHUNKS_MAP, diff --git a/src/tools/unicode-table-generator/src/range_search.rs b/src/tools/unicode-table-generator/src/range_search.rs index 39b47ce703f3..727ae3e9f78f 100644 --- a/src/tools/unicode-table-generator/src/range_search.rs +++ b/src/tools/unicode-table-generator/src/range_search.rs @@ -1,5 +1,6 @@ +#[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")] #[inline(always)] -fn bitset_search< +const fn bitset_search< const N: usize, const CHUNK_SIZE: usize, const N1: usize, @@ -15,14 +16,14 @@ fn bitset_search< let bucket_idx = (needle / 64) as usize; let chunk_map_idx = bucket_idx / CHUNK_SIZE; let chunk_piece = bucket_idx % CHUNK_SIZE; - let chunk_idx = if let Some(&v) = chunk_idx_map.get(chunk_map_idx) { - v + let chunk_idx = if chunk_map_idx < chunk_idx_map.len() { + chunk_idx_map[chunk_map_idx] } else { return false; }; let idx = bitset_chunk_idx[chunk_idx as usize][chunk_piece] as usize; - let word = if let Some(word) = bitset_canonical.get(idx) { - *word + let word = if idx < bitset_canonical.len() { + bitset_canonical[idx] } else { let (real_idx, mapping) = bitset_canonicalized[idx - bitset_canonical.len()]; let mut word = bitset_canonical[real_idx as usize]; diff --git a/src/tools/unicode-table-generator/src/raw_emitter.rs b/src/tools/unicode-table-generator/src/raw_emitter.rs index 13eed7b10997..5a0aabf62834 100644 --- a/src/tools/unicode-table-generator/src/raw_emitter.rs +++ b/src/tools/unicode-table-generator/src/raw_emitter.rs @@ -76,7 +76,7 @@ impl RawEmitter { writeln!( &mut self.file, - "static BITSET_CANONICAL: [u64; {}] = [{}];", + "const BITSET_CANONICAL: [u64; {}] = [{}];", canonicalized.canonical_words.len(), fmt_list(canonicalized.canonical_words.iter().map(|v| Bits(*v))), ) @@ -84,7 +84,7 @@ impl RawEmitter { self.bytes_used += 8 * canonicalized.canonical_words.len(); writeln!( &mut self.file, - "static BITSET_MAPPING: [(u8, u8); {}] = [{}];", + "const BITSET_MAPPING: [(u8, u8); {}] = [{}];", canonicalized.canonicalized_words.len(), fmt_list(&canonicalized.canonicalized_words), ) @@ -96,7 +96,12 @@ impl RawEmitter { self.blank_line(); - writeln!(&mut self.file, "pub fn lookup(c: char) -> bool {{").unwrap(); + writeln!( + &mut self.file, + r#"#[rustc_const_unstable(feature = "const_unicode_case_lookup", issue = "101400")]"# + ) + .unwrap(); + writeln!(&mut self.file, "pub const fn lookup(c: char) -> bool {{").unwrap(); writeln!(&mut self.file, " super::bitset_search(",).unwrap(); writeln!(&mut self.file, " c as u32,").unwrap(); writeln!(&mut self.file, " &BITSET_CHUNKS_MAP,").unwrap(); @@ -130,7 +135,7 @@ impl RawEmitter { writeln!( &mut self.file, - "static BITSET_CHUNKS_MAP: [u8; {}] = [{}];", + "const BITSET_CHUNKS_MAP: [u8; {}] = [{}];", chunk_indices.len(), fmt_list(&chunk_indices), ) @@ -138,7 +143,7 @@ impl RawEmitter { self.bytes_used += chunk_indices.len(); writeln!( &mut self.file, - "static BITSET_INDEX_CHUNKS: [[u8; {}]; {}] = [{}];", + "const BITSET_INDEX_CHUNKS: [[u8; {}]; {}] = [{}];", chunk_length, chunks.len(), fmt_list(chunks.iter()), From 2b328ea5ee537078abd72f309934f8e6bf004764 Mon Sep 17 00:00:00 2001 From: Sage Mitchell Date: Sun, 4 Sep 2022 08:07:00 -0700 Subject: [PATCH 4163/5092] Address feedback from PR #101401 --- library/core/src/unicode/unicode_data.rs | 20 +++++++++++-------- .../src/range_search.rs | 4 ++++ .../src/raw_emitter.rs | 8 ++++---- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/library/core/src/unicode/unicode_data.rs b/library/core/src/unicode/unicode_data.rs index 2bbedf0e2d29..7301da2afec4 100644 --- a/library/core/src/unicode/unicode_data.rs +++ b/library/core/src/unicode/unicode_data.rs @@ -18,12 +18,16 @@ const fn bitset_search< let bucket_idx = (needle / 64) as usize; let chunk_map_idx = bucket_idx / CHUNK_SIZE; let chunk_piece = bucket_idx % CHUNK_SIZE; + // FIXME: const-hack: Revert to `slice::get` after `const_slice_index` + // feature stabilizes. let chunk_idx = if chunk_map_idx < chunk_idx_map.len() { chunk_idx_map[chunk_map_idx] } else { return false; }; let idx = bitset_chunk_idx[chunk_idx as usize][chunk_piece] as usize; + // FIXME: const-hack: Revert to `slice::get` after `const_slice_index` + // feature stabilizes. let word = if idx < bitset_canonical.len() { bitset_canonical[idx] } else { @@ -319,14 +323,14 @@ pub mod grapheme_extend { #[rustfmt::skip] pub mod lowercase { - const BITSET_CHUNKS_MAP: [u8; 123] = [ + const BITSET_CHUNKS_MAP: &'static [u8; 123] = &[ 14, 17, 0, 0, 9, 0, 0, 12, 13, 10, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 1, 0, 15, 0, 8, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 3, 0, 0, 7, ]; - const BITSET_INDEX_CHUNKS: [[u8; 16]; 19] = [ + const BITSET_INDEX_CHUNKS: &'static [[u8; 16]; 19] = &[ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 14, 55, 0], @@ -347,7 +351,7 @@ pub mod lowercase { [16, 49, 2, 20, 66, 9, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0], [63, 39, 54, 12, 73, 61, 18, 1, 6, 62, 71, 19, 68, 69, 3, 44], ]; - const BITSET_CANONICAL: [u64; 55] = [ + const BITSET_CANONICAL: &'static [u64; 55] = &[ 0b0000000000000000000000000000000000000000000000000000000000000000, 0b1111111111111111110000000000000000000000000011111111111111111111, 0b1010101010101010101010101010101010101010101010101010100000000010, @@ -404,7 +408,7 @@ pub mod lowercase { 0b1110011111111111111111111111111111111111111111110000000000000000, 0b1110101111000000000000000000000000001111111111111111111111111100, ]; - const BITSET_MAPPING: [(u8, u8); 20] = [ + const BITSET_MAPPING: &'static [(u8, u8); 20] = &[ (0, 64), (1, 188), (1, 183), (1, 176), (1, 109), (1, 124), (1, 126), (1, 66), (1, 70), (1, 77), (2, 146), (2, 144), (2, 83), (3, 12), (3, 6), (4, 156), (4, 78), (5, 187), (6, 132), (7, 93), @@ -456,14 +460,14 @@ pub mod n { #[rustfmt::skip] pub mod uppercase { - const BITSET_CHUNKS_MAP: [u8; 125] = [ + const BITSET_CHUNKS_MAP: &'static [u8; 125] = &[ 12, 15, 6, 6, 0, 6, 6, 2, 4, 11, 6, 16, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 8, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 6, 14, 6, 10, 6, 6, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 13, 6, 6, 6, 6, 9, 6, 3, ]; - const BITSET_INDEX_CHUNKS: [[u8; 16]; 17] = [ + const BITSET_INDEX_CHUNKS: &'static [[u8; 16]; 17] = &[ [43, 43, 5, 34, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 5, 1], [43, 43, 5, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43], [43, 43, 39, 43, 43, 43, 43, 43, 17, 17, 62, 17, 42, 29, 24, 23], @@ -482,7 +486,7 @@ pub mod uppercase { [57, 19, 2, 18, 10, 47, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43], [57, 37, 17, 27, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43], ]; - const BITSET_CANONICAL: [u64; 43] = [ + const BITSET_CANONICAL: &'static [u64; 43] = &[ 0b0000011111111111111111111111111000000000000000000000000000000000, 0b0000000000111111111111111111111111111111111111111111111111111111, 0b0101010101010101010101010101010101010101010101010101010000000001, @@ -527,7 +531,7 @@ pub mod uppercase { 0b1111011111111111000000000000000000000000000000000000000000000000, 0b1111111100000000111111110000000000111111000000001111111100000000, ]; - const BITSET_MAPPING: [(u8, u8); 25] = [ + const BITSET_MAPPING: &'static [(u8, u8); 25] = &[ (0, 187), (0, 177), (0, 171), (0, 167), (0, 164), (0, 32), (0, 47), (0, 51), (0, 121), (0, 117), (0, 109), (1, 150), (1, 148), (1, 142), (1, 134), (1, 131), (1, 64), (2, 164), (2, 146), (2, 20), (3, 146), (3, 140), (3, 134), (4, 178), (4, 171), diff --git a/src/tools/unicode-table-generator/src/range_search.rs b/src/tools/unicode-table-generator/src/range_search.rs index 727ae3e9f78f..3a5b869f72f7 100644 --- a/src/tools/unicode-table-generator/src/range_search.rs +++ b/src/tools/unicode-table-generator/src/range_search.rs @@ -16,12 +16,16 @@ const fn bitset_search< let bucket_idx = (needle / 64) as usize; let chunk_map_idx = bucket_idx / CHUNK_SIZE; let chunk_piece = bucket_idx % CHUNK_SIZE; + // FIXME: const-hack: Revert to `slice::get` after `const_slice_index` + // feature stabilizes. let chunk_idx = if chunk_map_idx < chunk_idx_map.len() { chunk_idx_map[chunk_map_idx] } else { return false; }; let idx = bitset_chunk_idx[chunk_idx as usize][chunk_piece] as usize; + // FIXME: const-hack: Revert to `slice::get` after `const_slice_index` + // feature stabilizes. let word = if idx < bitset_canonical.len() { bitset_canonical[idx] } else { diff --git a/src/tools/unicode-table-generator/src/raw_emitter.rs b/src/tools/unicode-table-generator/src/raw_emitter.rs index 5a0aabf62834..890ff986c2be 100644 --- a/src/tools/unicode-table-generator/src/raw_emitter.rs +++ b/src/tools/unicode-table-generator/src/raw_emitter.rs @@ -76,7 +76,7 @@ impl RawEmitter { writeln!( &mut self.file, - "const BITSET_CANONICAL: [u64; {}] = [{}];", + "const BITSET_CANONICAL: &'static [u64; {}] = &[{}];", canonicalized.canonical_words.len(), fmt_list(canonicalized.canonical_words.iter().map(|v| Bits(*v))), ) @@ -84,7 +84,7 @@ impl RawEmitter { self.bytes_used += 8 * canonicalized.canonical_words.len(); writeln!( &mut self.file, - "const BITSET_MAPPING: [(u8, u8); {}] = [{}];", + "const BITSET_MAPPING: &'static [(u8, u8); {}] = &[{}];", canonicalized.canonicalized_words.len(), fmt_list(&canonicalized.canonicalized_words), ) @@ -135,7 +135,7 @@ impl RawEmitter { writeln!( &mut self.file, - "const BITSET_CHUNKS_MAP: [u8; {}] = [{}];", + "const BITSET_CHUNKS_MAP: &'static [u8; {}] = &[{}];", chunk_indices.len(), fmt_list(&chunk_indices), ) @@ -143,7 +143,7 @@ impl RawEmitter { self.bytes_used += chunk_indices.len(); writeln!( &mut self.file, - "const BITSET_INDEX_CHUNKS: [[u8; {}]; {}] = [{}];", + "const BITSET_INDEX_CHUNKS: &'static [[u8; {}]; {}] = &[{}];", chunk_length, chunks.len(), fmt_list(chunks.iter()), From 2cc20e32451cd6ee3b1336616d6ef7990de96009 Mon Sep 17 00:00:00 2001 From: kraktus <56031107+kraktus@users.noreply.github.com> Date: Sun, 4 Sep 2022 16:29:30 +0200 Subject: [PATCH 4164/5092] fix wording for `derivable_impls` --- clippy_lints/src/derivable_impls.rs | 2 +- src/docs/derivable_impls.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs index 4d7f4076d7b5..ef9eeecc6a93 100644 --- a/clippy_lints/src/derivable_impls.rs +++ b/clippy_lints/src/derivable_impls.rs @@ -40,7 +40,7 @@ declare_clippy_lint! { /// /// ### Known problems /// Derive macros [sometimes use incorrect bounds](https://github.com/rust-lang/rust/issues/26925) - /// in generic types and the user defined `impl` maybe is more generalized or + /// in generic types and the user defined `impl` may be more generalized or /// specialized than what derive will produce. This lint can't detect the manual `impl` /// has exactly equal bounds, and therefore this lint is disabled for types with /// generic parameters. diff --git a/src/docs/derivable_impls.txt b/src/docs/derivable_impls.txt index 8e4a80a672cc..5cee43956cc3 100644 --- a/src/docs/derivable_impls.txt +++ b/src/docs/derivable_impls.txt @@ -29,7 +29,7 @@ struct Foo { ### Known problems Derive macros [sometimes use incorrect bounds](https://github.com/rust-lang/rust/issues/26925) -in generic types and the user defined `impl` maybe is more generalized or +in generic types and the user defined `impl` may be more generalized or specialized than what derive will produce. This lint can't detect the manual `impl` has exactly equal bounds, and therefore this lint is disabled for types with generic parameters. \ No newline at end of file From 835a4612d2d974c98a8f972aa43cea5d1fbea8ed Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 4 Sep 2022 16:51:11 +0100 Subject: [PATCH 4165/5092] Test internal documentation --- src/ci/docker/host-x86_64/mingw-check/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile index c6723d91c8bb..52a7776153da 100644 --- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile @@ -45,7 +45,8 @@ ENV SCRIPT python3 ../x.py --stage 2 test src/tools/expand-yaml-anchors && \ python3 ../x.py test --stage 0 src/tools/compiletest && \ python3 ../x.py test --stage 2 src/tools/tidy && \ python3 ../x.py test --stage 0 core alloc std test proc_macro && \ - python3 ../x.py doc --stage 0 library/test && \ + # Build both public and internal documentation. + RUSTDOCFLAGS="--document-private-items" python3 ../x.py doc --stage 0 library/test && \ /scripts/validate-toolstate.sh && \ /scripts/validate-error-codes.sh && \ reuse lint && \ From fcd42d628cced5169ebbb791a992a8832d220ab6 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 4 Sep 2022 18:26:48 +0400 Subject: [PATCH 4166/5092] Don't fire `rust_2021_incompatible_closure_captures` in edition = 2021 --- compiler/rustc_lint_defs/src/builtin.rs | 4 ++-- compiler/rustc_typeck/src/check/upvar.rs | 4 ++++ src/test/ui/lint/issue-101284.rs | 15 +++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/lint/issue-101284.rs diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index ca01599acc8b..2e3a06fcbb74 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3407,7 +3407,7 @@ declare_lint! { /// /// ### Example of drop reorder /// - /// ```rust,compile_fail + /// ```rust,edition2018,compile_fail /// #![deny(rust_2021_incompatible_closure_captures)] /// # #![allow(unused)] /// @@ -3443,7 +3443,7 @@ declare_lint! { /// /// ### Example of auto-trait /// - /// ```rust,compile_fail + /// ```rust,edition2018,compile_fail /// #![deny(rust_2021_incompatible_closure_captures)] /// use std::thread; /// diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 0afc153300bf..0b207a6c0bee 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -2024,6 +2024,10 @@ fn should_do_rust_2021_incompatible_closure_captures_analysis( tcx: TyCtxt<'_>, closure_id: hir::HirId, ) -> bool { + if tcx.sess.rust_2021() { + return false; + } + let (level, _) = tcx.lint_level_at_node(lint::builtin::RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES, closure_id); diff --git a/src/test/ui/lint/issue-101284.rs b/src/test/ui/lint/issue-101284.rs new file mode 100644 index 000000000000..1381d4f17272 --- /dev/null +++ b/src/test/ui/lint/issue-101284.rs @@ -0,0 +1,15 @@ +// check-pass +// edition:2021 +#![deny(rust_2021_compatibility)] + +pub struct Warns { + // `Arc` has significant drop + _significant_drop: std::sync::Arc<()>, + field: String, +} + +pub fn test(w: Warns) { + _ = || drop(w.field); +} + +fn main() {} From 29729abc3c9736ca70bc0828e36e6670fb36b5bc Mon Sep 17 00:00:00 2001 From: Stanislav Date: Sun, 4 Sep 2022 19:10:04 +0300 Subject: [PATCH 4167/5092] Retain imports on find-all-references --- crates/ide/src/references.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 99614b645e48..fad44930fec2 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -79,6 +79,8 @@ pub(crate) fn find_all_refs( retain_adt_literal_usages(&mut usages, def, sema); } + retain_import_usages(&mut usages, sema); + let references = usages .into_iter() .map(|(file_id, refs)| { @@ -112,6 +114,32 @@ pub(crate) fn find_all_refs( } } +fn retain_import_usages(usages: &mut UsageSearchResult, sema: &Semantics<'_, RootDatabase>) { + for (file_id, refs) in &mut usages.references { + refs.retain(|x| { + let file_sema = sema.parse(file_id.clone()).syntax().clone(); + + let maybe_node = file_sema.child_or_token_at_range(x.range.clone()); + + if let Some(node) = maybe_node { + let res = match node { + syntax::NodeOrToken::Node(x) => { + if matches!(x.kind(), USE) { + false + } else { + true + } + } + syntax::NodeOrToken::Token(_) => true, + }; + res + } else { + true + } + }); + } +} + pub(crate) fn find_defs<'a>( sema: &'a Semantics<'_, RootDatabase>, syntax: &SyntaxNode, From ba40aa72ac1e2d5ddd1f0732e27a84b87692ccae Mon Sep 17 00:00:00 2001 From: Stanislav Date: Sun, 4 Sep 2022 19:41:06 +0300 Subject: [PATCH 4168/5092] Update crates/ide/src/references.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Laurențiu Nicola --- crates/ide/src/references.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index fad44930fec2..021596618ddd 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -123,7 +123,7 @@ fn retain_import_usages(usages: &mut UsageSearchResult, sema: &Semantics<'_, Roo if let Some(node) = maybe_node { let res = match node { - syntax::NodeOrToken::Node(x) => { + syntax::NodeOrToken::Node(x) => !matches!(x.kind(), USE), if matches!(x.kind(), USE) { false } else { From fff92d523812d0c56673e40c7e4d1bfd666c54e9 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 4 Sep 2022 20:45:29 +0400 Subject: [PATCH 4169/5092] remove some integer casts from slice iter --- library/core/src/slice/iter/macros.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index 47455760a4bd..6c9e7574e174 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -64,7 +64,7 @@ macro_rules! iterator { // backwards by `n`. `n` must not exceed `self.len()`. macro_rules! zst_shrink { ($self: ident, $n: ident) => { - $self.end = $self.end.wrapping_byte_offset(-$n); + $self.end = $self.end.wrapping_byte_sub($n); } } @@ -82,7 +82,7 @@ macro_rules! iterator { // returning the old start. // Unsafe because the offset must not exceed `self.len()`. #[inline(always)] - unsafe fn post_inc_start(&mut self, offset: isize) -> * $raw_mut T { + unsafe fn post_inc_start(&mut self, offset: usize) -> * $raw_mut T { if mem::size_of::() == 0 { zst_shrink!(self, offset); self.ptr.as_ptr() @@ -90,7 +90,7 @@ macro_rules! iterator { let old = self.ptr.as_ptr(); // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`, // so this new pointer is inside `self` and thus guaranteed to be non-null. - self.ptr = unsafe { NonNull::new_unchecked(self.ptr.as_ptr().offset(offset)) }; + self.ptr = unsafe { NonNull::new_unchecked(self.ptr.as_ptr().add(offset)) }; old } } @@ -99,7 +99,7 @@ macro_rules! iterator { // returning the new end. // Unsafe because the offset must not exceed `self.len()`. #[inline(always)] - unsafe fn pre_dec_end(&mut self, offset: isize) -> * $raw_mut T { + unsafe fn pre_dec_end(&mut self, offset: usize) -> * $raw_mut T { if mem::size_of::() == 0 { zst_shrink!(self, offset); self.ptr.as_ptr() @@ -107,7 +107,7 @@ macro_rules! iterator { // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`, // which is guaranteed to not overflow an `isize`. Also, the resulting pointer // is in bounds of `slice`, which fulfills the other requirements for `offset`. - self.end = unsafe { self.end.offset(-offset) }; + self.end = unsafe { self.end.sub(offset) }; self.end } } @@ -180,7 +180,7 @@ macro_rules! iterator { } // SAFETY: We are in bounds. `post_inc_start` does the right thing even for ZSTs. unsafe { - self.post_inc_start(n as isize); + self.post_inc_start(n); Some(next_unchecked!(self)) } } @@ -189,7 +189,7 @@ macro_rules! iterator { fn advance_by(&mut self, n: usize) -> Result<(), usize> { let advance = cmp::min(len!(self), n); // SAFETY: By construction, `advance` does not exceed `self.len()`. - unsafe { self.post_inc_start(advance as isize) }; + unsafe { self.post_inc_start(advance) }; if advance == n { Ok(()) } else { Err(advance) } } @@ -375,7 +375,7 @@ macro_rules! iterator { } // SAFETY: We are in bounds. `pre_dec_end` does the right thing even for ZSTs. unsafe { - self.pre_dec_end(n as isize); + self.pre_dec_end(n); Some(next_back_unchecked!(self)) } } @@ -384,7 +384,7 @@ macro_rules! iterator { fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { let advance = cmp::min(len!(self), n); // SAFETY: By construction, `advance` does not exceed `self.len()`. - unsafe { self.pre_dec_end(advance as isize) }; + unsafe { self.pre_dec_end(advance) }; if advance == n { Ok(()) } else { Err(advance) } } } From 6001e7dfb191f68332e2daf2eec692bbc2ae244f Mon Sep 17 00:00:00 2001 From: Stanislav Date: Sun, 4 Sep 2022 19:45:50 +0300 Subject: [PATCH 4170/5092] fix --- crates/ide/src/references.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 021596618ddd..53a7a3a21730 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -124,12 +124,6 @@ fn retain_import_usages(usages: &mut UsageSearchResult, sema: &Semantics<'_, Roo if let Some(node) = maybe_node { let res = match node { syntax::NodeOrToken::Node(x) => !matches!(x.kind(), USE), - if matches!(x.kind(), USE) { - false - } else { - true - } - } syntax::NodeOrToken::Token(_) => true, }; res From 5a672921a3cd6d474751b86690161f6477a501a6 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Sun, 4 Sep 2022 20:54:51 +0400 Subject: [PATCH 4171/5092] replace `as usize` casts with `usize::from` in slice sort --- library/core/src/slice/sort.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs index 8b025da2a46e..c6c03c0b0db9 100644 --- a/library/core/src/slice/sort.rs +++ b/library/core/src/slice/sort.rs @@ -365,12 +365,12 @@ where if count > 0 { macro_rules! left { () => { - l.add(*start_l as usize) + l.add(usize::from(*start_l)) }; } macro_rules! right { () => { - r.sub((*start_r as usize) + 1) + r.sub(usize::from(*start_r) + 1) }; } @@ -458,7 +458,7 @@ where // the last block, so the `l.offset` calls are valid. unsafe { end_l = end_l.sub(1); - ptr::swap(l.add(*end_l as usize), r.sub(1)); + ptr::swap(l.add(usize::from(*end_l)), r.sub(1)); r = r.sub(1); } } @@ -471,7 +471,7 @@ where // SAFETY: See the reasoning in [remaining-elements-safety]. unsafe { end_r = end_r.sub(1); - ptr::swap(l, r.sub((*end_r as usize) + 1)); + ptr::swap(l, r.sub(usize::from(*end_r) + 1)); l = l.add(1); } } From 30875e9d0b3d06c3d271be0e869728a4baa0ddeb Mon Sep 17 00:00:00 2001 From: sashashura <93376818+sashashura@users.noreply.github.com> Date: Sun, 4 Sep 2022 19:56:28 +0300 Subject: [PATCH 4172/5092] add actions: write --- .github/workflows/ci.yml | 6 ++++++ src/ci/github-actions/ci.yml | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9ebbc9c1c4bb..91b139664c8b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,6 +32,8 @@ defaults: shell: bash jobs: pr: + permissions: + actions: write # for rust-lang/simpleinfra/github-actions/cancel-outdated-builds name: PR env: CI_JOB_NAME: "${{ matrix.name }}" @@ -144,6 +146,8 @@ jobs: AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}" if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')" auto: + permissions: + actions: write # for rust-lang/simpleinfra/github-actions/cancel-outdated-builds name: auto env: CI_JOB_NAME: "${{ matrix.name }}" @@ -549,6 +553,8 @@ jobs: AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}" if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')" try: + permissions: + actions: write # for rust-lang/simpleinfra/github-actions/cancel-outdated-builds name: try env: CI_JOB_NAME: "${{ matrix.name }}" diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 42ce0576d49e..0f748ed0c62d 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -276,6 +276,8 @@ defaults: jobs: pr: + permissions: + actions: write <<: *base-ci-job name: PR env: @@ -296,6 +298,8 @@ jobs: <<: *job-linux-xl auto: + permissions: + actions: write <<: *base-ci-job name: auto env: @@ -722,6 +726,8 @@ jobs: <<: *job-windows-xl try: + permissions: + actions: write # for rust-lang/simpleinfra/github-actions/cancel-outdated-builds <<: *base-ci-job name: try env: From 294d0e9e3166e9119f43bde3328c8106016e3212 Mon Sep 17 00:00:00 2001 From: sashashura <93376818+sashashura@users.noreply.github.com> Date: Sun, 4 Sep 2022 20:08:45 +0300 Subject: [PATCH 4173/5092] Regenerate --- src/ci/github-actions/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 0f748ed0c62d..43aa9be11a48 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -277,7 +277,7 @@ defaults: jobs: pr: permissions: - actions: write + actions: write # for rust-lang/simpleinfra/github-actions/cancel-outdated-builds <<: *base-ci-job name: PR env: @@ -299,7 +299,7 @@ jobs: auto: permissions: - actions: write + actions: write # for rust-lang/simpleinfra/github-actions/cancel-outdated-builds <<: *base-ci-job name: auto env: From d7ef3f51ec393560cfb0c05f2e16b97ae533e935 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 4 Sep 2022 17:56:01 +0100 Subject: [PATCH 4174/5092] fix: correct broken logic for return complition It seems that we've accidentally deleted the tests here couple of years ago, and then fairly recently made a typo during refactor as well. Reinstall tests, with coverage marks this time :-) --- crates/ide-completion/src/completions/expr.rs | 24 +++++++++--- crates/ide-completion/src/tests/expression.rs | 38 ++++++++++++++++++- 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs index 4d66af9e8d5b..588b52cc1ee3 100644 --- a/crates/ide-completion/src/completions/expr.rs +++ b/crates/ide-completion/src/completions/expr.rs @@ -282,14 +282,26 @@ pub(crate) fn complete_expr_path( } } - if let Some(ty) = innermost_ret_ty { + if let Some(ret_ty) = innermost_ret_ty { add_keyword( "return", - match (in_block_expr, ty.is_unit()) { - (true, true) => "return ;", - (true, false) => "return;", - (false, true) => "return $0", - (false, false) => "return", + match (ret_ty.is_unit(), in_block_expr) { + (true, true) => { + cov_mark::hit!(return_unit_block); + "return;" + } + (true, false) => { + cov_mark::hit!(return_unit_no_block); + "return" + } + (false, true) => { + cov_mark::hit!(return_value_block); + "return $0;" + } + (false, false) => { + cov_mark::hit!(return_value_no_block); + "return $0" + } }, ); } diff --git a/crates/ide-completion/src/tests/expression.rs b/crates/ide-completion/src/tests/expression.rs index 925081ebf660..38e24ebc732d 100644 --- a/crates/ide-completion/src/tests/expression.rs +++ b/crates/ide-completion/src/tests/expression.rs @@ -1,7 +1,7 @@ //! Completion tests for expressions. use expect_test::{expect, Expect}; -use crate::tests::{completion_list, BASE_ITEMS_FIXTURE}; +use crate::tests::{check_edit, completion_list, BASE_ITEMS_FIXTURE}; fn check(ra_fixture: &str, expect: Expect) { let actual = completion_list(&format!("{}{}", BASE_ITEMS_FIXTURE, ra_fixture)); @@ -670,3 +670,39 @@ fn main() { "#]], ); } + +#[test] +fn return_unit_block() { + cov_mark::check!(return_unit_block); + check_edit("return", r#"fn f() { if true { $0 } }"#, r#"fn f() { if true { return; } }"#); +} + +#[test] +fn return_unit_no_block() { + cov_mark::check!(return_unit_no_block); + check_edit( + "return", + r#"fn f() { match () { () => $0 } }"#, + r#"fn f() { match () { () => return } }"#, + ); +} + +#[test] +fn return_value_block() { + cov_mark::check!(return_value_block); + check_edit( + "return", + r#"fn f() -> i32 { if true { $0 } }"#, + r#"fn f() -> i32 { if true { return $0; } }"#, + ); +} + +#[test] +fn return_value_no_block() { + cov_mark::check!(return_value_no_block); + check_edit( + "return", + r#"fn f() -> i32 { match () { () => $0 } }"#, + r#"fn f() -> i32 { match () { () => return $0 } }"#, + ); +} From bd5aad3ee28fbc1f7cb4bd2c52763dbadaeae34a Mon Sep 17 00:00:00 2001 From: sashashura <93376818+sashashura@users.noreply.github.com> Date: Sun, 4 Sep 2022 20:39:33 +0300 Subject: [PATCH 4175/5092] Regenerate --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 91b139664c8b..6693182e0c57 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,7 +33,7 @@ defaults: jobs: pr: permissions: - actions: write # for rust-lang/simpleinfra/github-actions/cancel-outdated-builds + actions: write name: PR env: CI_JOB_NAME: "${{ matrix.name }}" @@ -147,7 +147,7 @@ jobs: if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')" auto: permissions: - actions: write # for rust-lang/simpleinfra/github-actions/cancel-outdated-builds + actions: write name: auto env: CI_JOB_NAME: "${{ matrix.name }}" @@ -554,7 +554,7 @@ jobs: if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')" try: permissions: - actions: write # for rust-lang/simpleinfra/github-actions/cancel-outdated-builds + actions: write name: try env: CI_JOB_NAME: "${{ matrix.name }}" From efda49712b35009c0096217ce2aa262fc5ab8174 Mon Sep 17 00:00:00 2001 From: Nika Layzell Date: Sun, 4 Sep 2022 12:53:29 -0400 Subject: [PATCH 4176/5092] proc_macro/bridge: use the cross-thread executor for nested proc-macros While working on some other changes in the bridge, I noticed that when running a nested proc-macro (which is currently only possible using the unstable `TokenStream::expand_expr`), any symbols held by the proc-macro client would be invalidated, as the same thread would be used for the nested macro by default, and the interner doesn't handle nested use. After discussing with @eddyb, we decided the best approach might be to force the use of the cross-thread executor for nested invocations, as it will never re-use thread-local storage, avoiding the issue. This shouldn't impact performance, as expand_expr is still unstable, and infrequently used. This was chosen rather than making the client symbol interner handle nested invocations, as that would require replacing the internal interner `Vec` with a `BTreeMap` (as valid symbol id ranges could now be disjoint), and the symbol interner is known to be fairly perf-sensitive. This patch adds checks to the execution strategy to use the cross-thread executor when doing nested invocations. An alternative implementation strategy could be to track this information in the `ExtCtxt`, however a thread-local in the `proc_macro` crate was chosen to add an assertion so that `rust-analyzer` is aware of the issue if it implements `expand_expr` in the future. r? @eddyb --- library/proc_macro/src/bridge/server.rs | 37 ++++++++++++++++++- .../ui/proc-macro/auxiliary/expand-expr.rs | 23 ++++++++++-- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/library/proc_macro/src/bridge/server.rs b/library/proc_macro/src/bridge/server.rs index e47a77f6c135..8202c40d6317 100644 --- a/library/proc_macro/src/bridge/server.rs +++ b/library/proc_macro/src/bridge/server.rs @@ -2,6 +2,7 @@ use super::*; +use std::cell::Cell; use std::marker::PhantomData; // FIXME(eddyb) generate the definition of `HandleStore` in `server.rs`. @@ -143,6 +144,38 @@ pub trait ExecutionStrategy { ) -> Buffer; } +thread_local! { + /// While running a proc-macro with the same-thread executor, this flag will + /// be set, forcing nested proc-macro invocations (e.g. due to + /// `TokenStream::expand_expr`) to be run using a cross-thread executor. + /// + /// This is required as the thread-local state in the proc_macro client does + /// not handle being re-entered, and will invalidate all `Symbol`s when + /// entering a nested macro. + static ALREADY_RUNNING_SAME_THREAD: Cell = Cell::new(false); +} + +/// Keep `ALREADY_RUNNING_SAME_THREAD` (see also its documentation) +/// set to `true`, preventing same-thread reentrance. +struct RunningSameThreadGuard(()); + +impl RunningSameThreadGuard { + fn new() -> Self { + let already_running = ALREADY_RUNNING_SAME_THREAD.replace(true); + assert!( + !already_running, + "same-thread nesting (\"reentrance\") of proc macro executions is not supported" + ); + RunningSameThreadGuard(()) + } +} + +impl Drop for RunningSameThreadGuard { + fn drop(&mut self) { + ALREADY_RUNNING_SAME_THREAD.set(false); + } +} + pub struct MaybeCrossThread

{ cross_thread: bool, marker: PhantomData

, @@ -165,7 +198,7 @@ where run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, force_show_panics: bool, ) -> Buffer { - if self.cross_thread { + if self.cross_thread || ALREADY_RUNNING_SAME_THREAD.get() { >::new().run_bridge_and_client( dispatcher, input, @@ -188,6 +221,8 @@ impl ExecutionStrategy for SameThread { run_client: extern "C" fn(BridgeConfig<'_>) -> Buffer, force_show_panics: bool, ) -> Buffer { + let _guard = RunningSameThreadGuard::new(); + let mut dispatch = |buf| dispatcher.dispatch(buf); run_client(BridgeConfig { diff --git a/src/test/ui/proc-macro/auxiliary/expand-expr.rs b/src/test/ui/proc-macro/auxiliary/expand-expr.rs index 5463e79d74e0..1d6ef8a13610 100644 --- a/src/test/ui/proc-macro/auxiliary/expand-expr.rs +++ b/src/test/ui/proc-macro/auxiliary/expand-expr.rs @@ -80,13 +80,21 @@ fn assert_ts_eq(lhs: &TokenStream, rhs: &TokenStream) { pub fn expand_expr_is(input: TokenStream) -> TokenStream { let mut iter = input.into_iter(); let mut expected_tts = Vec::new(); - loop { + let comma = loop { match iter.next() { - Some(TokenTree::Punct(ref p)) if p.as_char() == ',' => break, + Some(TokenTree::Punct(p)) if p.as_char() == ',' => break p, Some(tt) => expected_tts.push(tt), None => panic!("expected comma"), } - } + }; + + // Make sure that `Ident` and `Literal` objects from this proc-macro's + // environment are not invalidated when `expand_expr` recursively invokes + // another macro by taking a local copy, and checking it after the fact. + let pre_expand_span = comma.span(); + let pre_expand_ident = Ident::new("ident", comma.span()); + let pre_expand_literal = Literal::string("literal"); + let pre_expand_call_site = Span::call_site(); let expected = expected_tts.into_iter().collect::(); let expanded = iter.collect::().expand_expr().expect("expand_expr failed"); @@ -100,6 +108,15 @@ pub fn expand_expr_is(input: TokenStream) -> TokenStream { // Also compare the raw tts to make sure they line up. assert_ts_eq(&expected, &expanded); + assert!(comma.span().eq(&pre_expand_span), "pre-expansion span is still equal"); + assert_eq!(pre_expand_ident.to_string(), "ident", "pre-expansion identifier is still valid"); + assert_eq!( + pre_expand_literal.to_string(), + "\"literal\"", + "pre-expansion literal is still valid" + ); + assert!(Span::call_site().eq(&pre_expand_call_site), "pre-expansion call-site is still equal"); + TokenStream::new() } From f5cd2230069d2029eea67cf10b85b0889d16b3cb Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 4 Sep 2022 21:11:31 +0200 Subject: [PATCH 4177/5092] Revert "Mention rust-analyzer maintainers when `proc_macro` bridge is changed" --- triagebot.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/triagebot.toml b/triagebot.toml index 89d1574726f0..89edab91fcd7 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -316,9 +316,6 @@ Examples of `T-libs-api` changes: * Changing observable runtime behavior of library APIs """ -[mentions."library/proc_macro/src/bridge"] -cc = ["@rust-lang/wg-rls-2"] - [mentions."src/librustdoc/clean/types.rs"] cc = ["@camelid"] From 748567cba574e0b15359f11f74b649927d313d05 Mon Sep 17 00:00:00 2001 From: austaras Date: Sat, 3 Sep 2022 00:58:24 +0800 Subject: [PATCH 4178/5092] complete full struct in enum varaint --- crates/ide-completion/src/tests/expression.rs | 39 +++++++++++++++++++ crates/ide-db/src/active_parameter.rs | 8 ++-- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/crates/ide-completion/src/tests/expression.rs b/crates/ide-completion/src/tests/expression.rs index 38e24ebc732d..8e26d889f9b6 100644 --- a/crates/ide-completion/src/tests/expression.rs +++ b/crates/ide-completion/src/tests/expression.rs @@ -671,6 +671,45 @@ fn main() { ); } +#[test] +fn varaiant_with_struct() { + check_empty( + r#" +pub struct YoloVariant { + pub f: usize +} + +pub enum HH { + Yolo(YoloVariant), +} + +fn brr() { + let t = HH::Yolo(Y$0); +} +"#, + expect![[r#" + en HH + fn brr() fn() + st YoloVariant + st YoloVariant {…} YoloVariant { f: usize } + bt u32 + kw crate:: + kw false + kw for + kw if + kw if let + kw loop + kw match + kw return + kw self:: + kw true + kw unsafe + kw while + kw while let + "#]], + ); +} + #[test] fn return_unit_block() { cov_mark::check!(return_unit_block); diff --git a/crates/ide-db/src/active_parameter.rs b/crates/ide-db/src/active_parameter.rs index 7303ef8b7bb5..7109c6fd188f 100644 --- a/crates/ide-db/src/active_parameter.rs +++ b/crates/ide-db/src/active_parameter.rs @@ -12,7 +12,7 @@ use crate::RootDatabase; #[derive(Debug)] pub struct ActiveParameter { pub ty: Type, - pub pat: Either, + pub pat: Option>, } impl ActiveParameter { @@ -27,12 +27,12 @@ impl ActiveParameter { return None; } let (pat, ty) = params.swap_remove(idx); - pat.map(|pat| ActiveParameter { ty, pat }) + Some(ActiveParameter { ty, pat }) } pub fn ident(&self) -> Option { - self.pat.as_ref().right().and_then(|param| match param { - ast::Pat::IdentPat(ident) => ident.name(), + self.pat.as_ref().and_then(|param| match param { + Either::Right(ast::Pat::IdentPat(ident)) => ident.name(), _ => None, }) } From e1bb09edffc4ae4fae512a73ee37aa62931d2bc8 Mon Sep 17 00:00:00 2001 From: kraktus Date: Sun, 4 Sep 2022 21:46:28 +0200 Subject: [PATCH 4179/5092] Fix `hir::Local` doc to match with the variable name used: `init` --- compiler/rustc_hir/src/hir.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 81d544c7b96d..14c51010a39d 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1273,7 +1273,7 @@ pub enum StmtKind<'hir> { Semi(&'hir Expr<'hir>), } -/// Represents a `let` statement (i.e., `let : = ;`). +/// Represents a `let` statement (i.e., `let : = ;`). #[derive(Debug, HashStable_Generic)] pub struct Local<'hir> { pub pat: &'hir Pat<'hir>, From f0e586c2511019a58ad3e56be16bba76dfc7eba8 Mon Sep 17 00:00:00 2001 From: relrelb Date: Tue, 16 Aug 2022 23:26:03 +0300 Subject: [PATCH 4180/5092] Suggest `Entry::or_default` for `Entry::or_insert(Default::default())` Unlike past similar work done in #6228, expand the existing `or_fun_call` lint to detect `or_insert` calls with a `T::new()` or `T::default()` argument, much like currently done for `unwrap_or` calls. In that case, suggest the use of `or_default`, which is more idiomatic. Note that even with this change, `or_insert_with(T::default)` calls aren't detected as candidates for `or_default()`, in the same manner that currently `unwrap_or_else(T::default)` calls aren't detected as candidates for `unwrap_or_default()`. Also, as a nearby cleanup, change `KNOW_TYPES` from `static` to `const`, since as far as I understand it's preferred (should Clippy have a lint for that?). Fixes #3812. --- clippy_lints/src/methods/mod.rs | 5 +++-- clippy_lints/src/methods/or_fun_call.rs | 13 +++++++++---- src/docs/or_fun_call.txt | 5 +++-- tests/ui/or_fun_call.fixed | 8 ++++---- tests/ui/or_fun_call.stderr | 26 ++++++++++++++++++++++++- 5 files changed, 44 insertions(+), 13 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a0d190a58aff..b7d2d980db80 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -825,8 +825,9 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does /// Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`, - /// etc., and suggests to use `or_else`, `unwrap_or_else`, etc., or - /// `unwrap_or_default` instead. + /// `.or_insert(foo(..))` etc., and suggests to use `.or_else(|| foo(..))`, + /// `.unwrap_or_else(|| foo(..))`, `.unwrap_or_default()` or `.or_default()` + /// etc. instead. /// /// ### Why is this bad? /// The function will always be called and potentially diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 6af134019a47..c97f714680ef 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -22,7 +22,8 @@ pub(super) fn check<'tcx>( name: &str, args: &'tcx [hir::Expr<'_>], ) { - /// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`. + /// Checks for `unwrap_or(T::new())`, `unwrap_or(T::default())`, + /// `or_insert(T::new())` or `or_insert(T::default())`. #[allow(clippy::too_many_arguments)] fn check_unwrap_or_default( cx: &LateContext<'_>, @@ -42,7 +43,11 @@ pub(super) fn check<'tcx>( if_chain! { if !or_has_args; - if name == "unwrap_or"; + if let Some(sugg) = match name { + "unwrap_or" => Some("unwrap_or_default"), + "or_insert" => Some("or_default"), + _ => None, + }; if let hir::ExprKind::Path(ref qpath) = fun.kind; if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default); let path = last_path_segment(qpath).ident.name; @@ -58,7 +63,7 @@ pub(super) fn check<'tcx>( method_span.with_hi(span.hi()), &format!("use of `{}` followed by a call to `{}`", name, path), "try this", - "unwrap_or_default()".to_string(), + format!("{}()", sugg), Applicability::MachineApplicable, ); @@ -82,7 +87,7 @@ pub(super) fn check<'tcx>( fun_span: Option, ) { // (path, fn_has_argument, methods, suffix) - static KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [ + const KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [ (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"), (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"), (&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"), diff --git a/src/docs/or_fun_call.txt b/src/docs/or_fun_call.txt index 5605e96c98ee..6ce77cc268c5 100644 --- a/src/docs/or_fun_call.txt +++ b/src/docs/or_fun_call.txt @@ -1,7 +1,8 @@ ### What it does Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`, -etc., and suggests to use `or_else`, `unwrap_or_else`, etc., or -`unwrap_or_default` instead. +`.or_insert(foo(..))` etc., and suggests to use `.or_else(|| foo(..))`, +`.unwrap_or_else(|| foo(..))`, `.unwrap_or_default()` or `.or_default()` +etc. instead. ### Why is this bad? The function will always be called and potentially diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index 18ea4e550292..5991188ab637 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -79,16 +79,16 @@ fn or_fun_call() { without_default.unwrap_or_else(Foo::new); let mut map = HashMap::::new(); - map.entry(42).or_insert(String::new()); + map.entry(42).or_default(); let mut map_vec = HashMap::>::new(); - map_vec.entry(42).or_insert(vec![]); + map_vec.entry(42).or_default(); let mut btree = BTreeMap::::new(); - btree.entry(42).or_insert(String::new()); + btree.entry(42).or_default(); let mut btree_vec = BTreeMap::>::new(); - btree_vec.entry(42).or_insert(vec![]); + btree_vec.entry(42).or_default(); let stringy = Some(String::new()); let _ = stringy.unwrap_or_default(); diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index 887f23ac9761..e3dab4cb1477 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -66,6 +66,30 @@ error: use of `unwrap_or` followed by a function call LL | without_default.unwrap_or(Foo::new()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)` +error: use of `or_insert` followed by a call to `new` + --> $DIR/or_fun_call.rs:82:19 + | +LL | map.entry(42).or_insert(String::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_default()` + +error: use of `or_insert` followed by a call to `new` + --> $DIR/or_fun_call.rs:85:23 + | +LL | map_vec.entry(42).or_insert(vec![]); + | ^^^^^^^^^^^^^^^^^ help: try this: `or_default()` + +error: use of `or_insert` followed by a call to `new` + --> $DIR/or_fun_call.rs:88:21 + | +LL | btree.entry(42).or_insert(String::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_default()` + +error: use of `or_insert` followed by a call to `new` + --> $DIR/or_fun_call.rs:91:25 + | +LL | btree_vec.entry(42).or_insert(vec![]); + | ^^^^^^^^^^^^^^^^^ help: try this: `or_default()` + error: use of `unwrap_or` followed by a call to `new` --> $DIR/or_fun_call.rs:94:21 | @@ -132,5 +156,5 @@ error: use of `unwrap_or` followed by a call to `new` LL | .unwrap_or(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()` -error: aborting due to 22 previous errors +error: aborting due to 26 previous errors From 3b3c7063c23d43b30077fb5f997456e60e5806a6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 4 Sep 2022 20:48:39 +0000 Subject: [PATCH 4181/5092] Point at type parameter in plain path expr --- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 20 +++++++++---------- .../point-at-type-param-in-path-expr.rs | 6 ++++++ .../point-at-type-param-in-path-expr.stderr | 17 ++++++++++++++++ 3 files changed, 33 insertions(+), 10 deletions(-) create mode 100644 src/test/ui/typeck/point-at-type-param-in-path-expr.rs create mode 100644 src/test/ui/typeck/point-at-type-param-in-path-expr.stderr diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index ce0e59d06226..2f6d0b193686 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -1780,16 +1780,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return true; } } - // Notably, we only point to params that are local to the - // item we're checking, since those are the ones we are able - // to look in the final `hir::PathSegment` for. Everything else - // would require a deeper search into the `qpath` than I think - // is worthwhile. - if let Some(param_to_point_at) = param_to_point_at - && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath) - { - return true; - } + } + // Notably, we only point to params that are local to the + // item we're checking, since those are the ones we are able + // to look in the final `hir::PathSegment` for. Everything else + // would require a deeper search into the `qpath` than I think + // is worthwhile. + if let Some(param_to_point_at) = param_to_point_at + && self.point_at_path_if_possible(error, def_id, param_to_point_at, qpath) + { + return true; } } hir::ExprKind::MethodCall(segment, args, ..) => { diff --git a/src/test/ui/typeck/point-at-type-param-in-path-expr.rs b/src/test/ui/typeck/point-at-type-param-in-path-expr.rs new file mode 100644 index 000000000000..9a21536f9b12 --- /dev/null +++ b/src/test/ui/typeck/point-at-type-param-in-path-expr.rs @@ -0,0 +1,6 @@ +fn foo() {} + +fn main() { + let x = foo::<()>; + //~^ ERROR `()` doesn't implement `std::fmt::Display` +} diff --git a/src/test/ui/typeck/point-at-type-param-in-path-expr.stderr b/src/test/ui/typeck/point-at-type-param-in-path-expr.stderr new file mode 100644 index 000000000000..1feaa0508bfa --- /dev/null +++ b/src/test/ui/typeck/point-at-type-param-in-path-expr.stderr @@ -0,0 +1,17 @@ +error[E0277]: `()` doesn't implement `std::fmt::Display` + --> $DIR/point-at-type-param-in-path-expr.rs:4:19 + | +LL | let x = foo::<()>; + | ^^ `()` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `()` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead +note: required by a bound in `foo` + --> $DIR/point-at-type-param-in-path-expr.rs:1:11 + | +LL | fn foo() {} + | ^^^^^^^^^^^^^^^^^ required by this bound in `foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From 3b985b4dd6c51e2939b23a0782579944fdf7a08c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Mon, 5 Sep 2022 00:17:46 +0200 Subject: [PATCH 4182/5092] Hermit: Add File::set_time stub This is not supported on hermit yet. This change is required for compiling std. --- library/std/src/sys/hermit/fs.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/library/std/src/sys/hermit/fs.rs b/library/std/src/sys/hermit/fs.rs index 1c5efa94bd36..f921839cf529 100644 --- a/library/std/src/sys/hermit/fs.rs +++ b/library/std/src/sys/hermit/fs.rs @@ -41,6 +41,9 @@ pub struct OpenOptions { mode: i32, } +#[derive(Copy, Clone, Debug, Default)] +pub struct FileTimes {} + pub struct FilePermissions(!); pub struct FileType(!); @@ -110,6 +113,11 @@ impl fmt::Debug for FilePermissions { } } +impl FileTimes { + pub fn set_accessed(&mut self, _t: SystemTime) {} + pub fn set_modified(&mut self, _t: SystemTime) {} +} + impl FileType { pub fn is_dir(&self) -> bool { self.0 @@ -344,6 +352,10 @@ impl File { pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { Err(Error::from_raw_os_error(22)) } + + pub fn set_times(&self, _times: FileTimes) -> io::Result<()> { + Err(Error::from_raw_os_error(22)) + } } impl DirBuilder { From 11af142c9312e0e906d3a05352f129d285d7e614 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Mon, 5 Sep 2022 00:21:13 +0200 Subject: [PATCH 4183/5092] Hermit: Fix unused_imports --- library/std/src/sys/hermit/mutex.rs | 1 - library/std/src/sys/hermit/rwlock.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs index eb15a04ffcff..d7b7a0bb0568 100644 --- a/library/std/src/sys/hermit/mutex.rs +++ b/library/std/src/sys/hermit/mutex.rs @@ -2,7 +2,6 @@ use crate::cell::UnsafeCell; use crate::collections::VecDeque; use crate::hint; use crate::ops::{Deref, DerefMut, Drop}; -use crate::ptr; use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sys::hermit::abi; diff --git a/library/std/src/sys/hermit/rwlock.rs b/library/std/src/sys/hermit/rwlock.rs index 9701bab1f660..1adf0b2be6b7 100644 --- a/library/std/src/sys/hermit/rwlock.rs +++ b/library/std/src/sys/hermit/rwlock.rs @@ -1,6 +1,5 @@ use crate::cell::UnsafeCell; use crate::sys::locks::{MovableCondvar, Mutex}; -use crate::sys_common::lazy_box::{LazyBox, LazyInit}; pub struct RwLock { lock: Mutex, From ce305f8f8e1fc022fb943e2828bb9fe56d6dc765 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kr=C3=B6ning?= Date: Mon, 5 Sep 2022 00:23:25 +0200 Subject: [PATCH 4184/5092] Hermit: Remove unused socklen_t (dead_code) --- library/std/src/sys/hermit/net.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/std/src/sys/hermit/net.rs b/library/std/src/sys/hermit/net.rs index 74547617150b..8a13879d8cc8 100644 --- a/library/std/src/sys/hermit/net.rs +++ b/library/std/src/sys/hermit/net.rs @@ -487,6 +487,4 @@ pub mod netc { #[derive(Copy, Clone)] pub struct sockaddr {} - - pub type socklen_t = usize; } From d565d51071e2dd64626df9386bcc97981e474ebd Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 5 Sep 2022 10:59:00 +1000 Subject: [PATCH 4185/5092] Put size assertions together. As has already been done in various other places in the compiler. --- compiler/rustc_middle/src/ty/mod.rs | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index ed04e7660339..f59d14a4a0c1 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -463,15 +463,6 @@ pub(crate) struct TyS<'tcx> { outer_exclusive_binder: ty::DebruijnIndex, } -// `TyS` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(TyS<'_>, 40); - -// We are actually storing a stable hash cache next to the type, so let's -// also check the full size -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(WithStableHash>, 56); - /// Use this rather than `TyS`, whenever possible. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)] #[rustc_diagnostic_item = "Ty"] @@ -528,10 +519,6 @@ pub(crate) struct PredicateS<'tcx> { outer_exclusive_binder: ty::DebruijnIndex, } -// This type is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(PredicateS<'_>, 56); - /// Use this rather than `PredicateS`, whenever possible. #[derive(Clone, Copy, PartialEq, Eq, Hash)] #[rustc_pass_by_value] @@ -2534,3 +2521,14 @@ pub struct DestructuredConst<'tcx> { pub variant: Option, pub fields: &'tcx [ty::Const<'tcx>], } + +// Some types are used a lot. Make sure they don't unintentionally get bigger. +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +mod size_asserts { + use super::*; + use rustc_data_structures::static_assert_size; + // These are in alphabetical order, which is easy to maintain. + static_assert_size!(PredicateS<'_>, 56); + static_assert_size!(TyS<'_>, 40); + static_assert_size!(WithStableHash>, 56); +} From 49b90573ac84d0f18ff1737e5f4fd4d0afc869f2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 31 Aug 2022 09:05:42 +1000 Subject: [PATCH 4186/5092] Add some blank lines to the definition of `Res`. To make the spacing consistent. Also shorten an overly long comment line. --- compiler/rustc_hir/src/def.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 2d2648a8f35a..d5ac07f1e631 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -308,6 +308,7 @@ pub enum Res { /// /// **Belongs to the type namespace.** PrimTy(hir::PrimTy), + /// The `Self` type, optionally with the [`DefId`] of the trait it belongs to and /// optionally with the [`DefId`] of the item introducing the `Self` type alias. /// @@ -355,7 +356,8 @@ pub enum Res { /// const fn baz() -> usize { 10 } /// ``` /// We do however allow `Self` in repeat expression even if it is generic to not break code - /// which already works on stable while causing the `const_evaluatable_unchecked` future compat lint: + /// which already works on stable while causing the `const_evaluatable_unchecked` future compat + /// lint: /// ``` /// fn foo() { /// let _bar = [1_u8; std::mem::size_of::<*mut T>()]; @@ -370,6 +372,7 @@ pub enum Res { /// from mentioning generics (i.e. when used in an anonymous constant). alias_to: Option<(DefId, bool)>, }, + /// A tool attribute module; e.g., the `rustfmt` in `#[rustfmt::skip]`. /// /// **Belongs to the type namespace.** @@ -383,6 +386,7 @@ pub enum Res { /// /// *See also [`Res::SelfTy`].* SelfCtor(DefId), + /// A local variable or function parameter. /// /// **Belongs to the value namespace.** From ee244bf1961cec6279bd4a91f9bcdc1339f74c97 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 31 Aug 2022 09:08:46 +1000 Subject: [PATCH 4187/5092] Remove dead code from `print_generic_args`. --- compiler/rustc_hir_pretty/src/lib.rs | 34 ++++++---------------------- 1 file changed, 7 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 42663da8a3f9..3c145bbc81f7 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1189,7 +1189,7 @@ impl<'a> State<'a> { let generic_args = segment.args(); if !generic_args.args.is_empty() || !generic_args.bindings.is_empty() { - self.print_generic_args(generic_args, segment.infer_args, true); + self.print_generic_args(generic_args, true); } self.print_call_post(base_args) @@ -1592,7 +1592,7 @@ impl<'a> State<'a> { } if segment.ident.name != kw::PathRoot { self.print_ident(segment.ident); - self.print_generic_args(segment.args(), segment.infer_args, colons_before_params); + self.print_generic_args(segment.args(), colons_before_params); } } } @@ -1600,7 +1600,7 @@ impl<'a> State<'a> { pub fn print_path_segment(&mut self, segment: &hir::PathSegment<'_>) { if segment.ident.name != kw::PathRoot { self.print_ident(segment.ident); - self.print_generic_args(segment.args(), segment.infer_args, false); + self.print_generic_args(segment.args(), false); } } @@ -1619,11 +1619,7 @@ impl<'a> State<'a> { } if segment.ident.name != kw::PathRoot { self.print_ident(segment.ident); - self.print_generic_args( - segment.args(), - segment.infer_args, - colons_before_params, - ); + self.print_generic_args(segment.args(), colons_before_params); } } @@ -1631,11 +1627,7 @@ impl<'a> State<'a> { self.word("::"); let item_segment = path.segments.last().unwrap(); self.print_ident(item_segment.ident); - self.print_generic_args( - item_segment.args(), - item_segment.infer_args, - colons_before_params, - ) + self.print_generic_args(item_segment.args(), colons_before_params) } hir::QPath::TypeRelative(qself, item_segment) => { // If we've got a compound-qualified-path, let's push an additional pair of angle @@ -1651,11 +1643,7 @@ impl<'a> State<'a> { self.word("::"); self.print_ident(item_segment.ident); - self.print_generic_args( - item_segment.args(), - item_segment.infer_args, - colons_before_params, - ) + self.print_generic_args(item_segment.args(), colons_before_params) } hir::QPath::LangItem(lang_item, span, _) => { self.word("#[lang = \""); @@ -1668,7 +1656,6 @@ impl<'a> State<'a> { fn print_generic_args( &mut self, generic_args: &hir::GenericArgs<'_>, - infer_args: bool, colons_before_params: bool, ) { if generic_args.parenthesized { @@ -1715,13 +1702,6 @@ impl<'a> State<'a> { ); } - // FIXME(eddyb): this would leak into error messages (e.g., - // "non-exhaustive patterns: `Some::<..>(_)` not covered"). - if infer_args && false { - start_or_comma(self); - self.word(".."); - } - for binding in generic_args.bindings { start_or_comma(self); self.print_type_binding(binding); @@ -1735,7 +1715,7 @@ impl<'a> State<'a> { pub fn print_type_binding(&mut self, binding: &hir::TypeBinding<'_>) { self.print_ident(binding.ident); - self.print_generic_args(binding.gen_args, false, false); + self.print_generic_args(binding.gen_args, false); self.space(); match binding.kind { hir::TypeBindingKind::Equality { ref term } => { From 6d850d936bae9745b68b08c6e1d62a1b1cc6bc84 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 30 Aug 2022 15:10:28 +1000 Subject: [PATCH 4188/5092] Make `hir::PathSegment::res` non-optional. --- compiler/rustc_ast_lowering/src/expr.rs | 5 ++-- compiler/rustc_ast_lowering/src/item.rs | 7 ++++-- compiler/rustc_ast_lowering/src/lib.rs | 8 ++++--- compiler/rustc_ast_lowering/src/pat.rs | 19 ++++++++------- compiler/rustc_ast_lowering/src/path.rs | 2 +- compiler/rustc_hir/src/hir.rs | 15 +++++------- .../infer/error_reporting/need_type_info.rs | 2 +- .../trait_impl_difference.rs | 15 ++++-------- compiler/rustc_lint/src/internal.rs | 3 +-- compiler/rustc_passes/src/stability.rs | 2 +- .../rustc_save_analysis/src/dump_visitor.rs | 2 +- compiler/rustc_save_analysis/src/lib.rs | 9 +++---- .../src/traits/error_reporting/mod.rs | 4 ++-- compiler/rustc_typeck/src/astconv/mod.rs | 24 +++++++++---------- compiler/rustc_typeck/src/check/check.rs | 7 +----- compiler/rustc_typeck/src/check/wfcheck.rs | 2 +- compiler/rustc_typeck/src/collect/type_of.rs | 8 ++----- .../clippy_lints/src/operators/op_ref.rs | 2 +- .../clippy/clippy_lints/src/ref_option_ref.rs | 3 +-- .../clippy/clippy_lints/src/trait_bounds.rs | 2 +- 20 files changed, 65 insertions(+), 76 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 7df3520422c1..a41d4b01e0e3 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1776,12 +1776,13 @@ impl<'hir> LoweringContext<'_, 'hir> { binding: hir::HirId, attrs: AttrVec, ) -> hir::Expr<'hir> { + let res = Res::Local(binding); let expr_path = hir::ExprKind::Path(hir::QPath::Resolved( None, self.arena.alloc(hir::Path { span: self.lower_span(span), - res: Res::Local(binding), - segments: arena_vec![self; hir::PathSegment::from_ident(ident)], + res, + segments: arena_vec![self; hir::PathSegment::from_ident(ident, res)], }), )); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index fd338ffc0c5e..e3f02968d4d7 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1431,10 +1431,13 @@ impl<'hir> LoweringContext<'_, 'hir> { GenericParamKind::Const { .. } => None, GenericParamKind::Type { .. } => { let def_id = self.local_def_id(id).to_def_id(); + let res = Res::Def(DefKind::TyParam, def_id); let ty_path = self.arena.alloc(hir::Path { span: param_span, - res: Res::Def(DefKind::TyParam, def_id), - segments: self.arena.alloc_from_iter([hir::PathSegment::from_ident(ident)]), + res, + segments: self + .arena + .alloc_from_iter([hir::PathSegment::from_ident(ident, res)]), }); let ty_id = self.next_id(); let bounded_ty = diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 9a960356a85f..bc183c6e3135 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1267,7 +1267,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.arena.alloc(hir::Path { res, segments: arena_vec![self; hir::PathSegment::from_ident( - Ident::with_dummy_span(kw::SelfUpper) + Ident::with_dummy_span(kw::SelfUpper), + res )], span: self.lower_span(t.span), }), @@ -2193,12 +2194,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::PredicateOrigin::ImplTrait, ); + let res = Res::Def(DefKind::TyParam, def_id.to_def_id()); let ty = hir::TyKind::Path(hir::QPath::Resolved( None, self.arena.alloc(hir::Path { span: self.lower_span(span), - res: Res::Def(DefKind::TyParam, def_id.to_def_id()), - segments: arena_vec![self; hir::PathSegment::from_ident(self.lower_ident(ident))], + res, + segments: arena_vec![self; hir::PathSegment::from_ident(self.lower_ident(ident), res)], }), )); diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 1efa19a3a828..61c32816e171 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -254,14 +254,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { lower_sub(self), ) } - Some(res) => hir::PatKind::Path(hir::QPath::Resolved( - None, - self.arena.alloc(hir::Path { - span: self.lower_span(ident.span), - res: self.lower_res(res), - segments: arena_vec![self; hir::PathSegment::from_ident(self.lower_ident(ident))], - }), - )), + Some(res) => { + let res = self.lower_res(res); + hir::PatKind::Path(hir::QPath::Resolved( + None, + self.arena.alloc(hir::Path { + span: self.lower_span(ident.span), + res, + segments: arena_vec![self; hir::PathSegment::from_ident(self.lower_ident(ident), res)], + }), + )) + } } } diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 897c7215805e..6ec8bcbc1e57 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -259,7 +259,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::PathSegment { ident: self.lower_ident(segment.ident), hir_id: Some(id), - res: Some(self.lower_res(res)), + res: self.lower_res(res), infer_args, args: if generic_args.is_empty() && generic_args.span.is_empty() { None diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index a069c49b0cc1..bd53e7670a6e 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -202,13 +202,10 @@ impl Path<'_> { pub struct PathSegment<'hir> { /// The identifier portion of this path segment. pub ident: Ident, - // `id` and `res` are optional. We currently only use these in save-analysis, - // any path segments without these will not have save-analysis info and - // therefore will not have 'jump to def' in IDEs, but otherwise will not be - // affected. (In general, we don't bother to get the defs for synthesized - // segments, only for segments which have come from the AST). + pub hir_id: Option, - pub res: Option, + + pub res: Res, /// Type/lifetime parameters attached to this path. They come in /// two flavors: `Path` and `Path(A,B) -> C`. Note that @@ -226,12 +223,12 @@ pub struct PathSegment<'hir> { impl<'hir> PathSegment<'hir> { /// Converts an identifier to the corresponding segment. - pub fn from_ident(ident: Ident) -> PathSegment<'hir> { - PathSegment { ident, hir_id: None, res: None, infer_args: true, args: None } + pub fn from_ident(ident: Ident, res: Res) -> PathSegment<'hir> { + PathSegment { ident, hir_id: None, res, infer_args: true, args: None } } pub fn invalid() -> Self { - Self::from_ident(Ident::empty()) + Self::from_ident(Ident::empty(), Res::Err) } pub fn args(&self) -> &GenericArgs<'hir> { diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 91a05367eee0..a20bcd93045f 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -957,7 +957,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { path.segments .iter() .filter_map(move |segment| { - let res = segment.res?; + let res = segment.res; let generics_def_id = tcx.res_generics_def_id(res)?; let generics = tcx.generics_of(generics_def_id); if generics.has_impl_trait() { diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index da465a764299..a6a39d062d51 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -154,16 +154,11 @@ impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> { } hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments { [segment] - if segment - .res - .map(|res| { - matches!( - res, - Res::SelfTy { trait_: _, alias_to: _ } - | Res::Def(hir::def::DefKind::TyParam, _) - ) - }) - .unwrap_or(false) => + if matches!( + segment.res, + Res::SelfTy { trait_: _, alias_to: _ } + | Res::Def(hir::def::DefKind::TyParam, _) + ) => { self.types.push(path.span); } diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 16b7d2cbbaea..4a41b345d3ba 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -118,8 +118,7 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { _: rustc_hir::HirId, ) { if let Some(segment) = path.segments.iter().nth_back(1) - && let Some(res) = &segment.res - && lint_ty_kind_usage(cx, res) + && lint_ty_kind_usage(cx, &segment.res) { let span = path.span.with_hi( segment.args.map_or(segment.ident.span, |a| a.span_ext).hi() diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index f884e04a9511..a24b191aebfc 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -832,7 +832,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { // added, such as `core::intrinsics::transmute` let parents = path.segments.iter().rev().skip(1); for path_segment in parents { - if let Some(def_id) = path_segment.res.as_ref().and_then(Res::opt_def_id) { + if let Some(def_id) = path_segment.res.opt_def_id() { // use `None` for id to prevent deprecation check self.tcx.check_stability_allow_unstable( def_id, diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs index ac6c3663b637..769d3243d584 100644 --- a/compiler/rustc_save_analysis/src/dump_visitor.rs +++ b/compiler/rustc_save_analysis/src/dump_visitor.rs @@ -912,7 +912,7 @@ impl<'tcx> DumpVisitor<'tcx> { _, ) | Res::SelfTy { .. } => { - self.dump_path_segment_ref(id, &hir::PathSegment::from_ident(ident)); + self.dump_path_segment_ref(id, &hir::PathSegment::from_ident(ident, Res::Err)); } def => { error!("unexpected definition kind when processing collected idents: {:?}", def) diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index 16af53385104..4b110b824e00 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -596,13 +596,14 @@ impl<'tcx> SaveContext<'tcx> { Node::TraitRef(tr) => tr.path.res, Node::Item(&hir::Item { kind: hir::ItemKind::Use(path, _), .. }) => path.res, - Node::PathSegment(seg) => match seg.res { - Some(res) if res != Res::Err => res, - _ => { + Node::PathSegment(seg) => { + if seg.res != Res::Err { + seg.res + } else { let parent_node = self.tcx.hir().get_parent_node(hir_id); self.get_path_res(parent_node) } - }, + } Node::Expr(&hir::Expr { kind: hir::ExprKind::Struct(ref qpath, ..), .. }) => { self.typeck_results().qpath_res(qpath, hir_id) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 34b877d3f725..9b8bb9e36201 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -2210,12 +2210,12 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { && let [ .., trait_path_segment @ hir::PathSegment { - res: Some(rustc_hir::def::Res::Def(rustc_hir::def::DefKind::Trait, trait_id)), + res: rustc_hir::def::Res::Def(rustc_hir::def::DefKind::Trait, trait_id), .. }, hir::PathSegment { ident: assoc_item_name, - res: Some(rustc_hir::def::Res::Def(_, item_id)), + res: rustc_hir::def::Res::Def(_, item_id), .. } ] = path.segments diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index ef927058df4e..a49244d16d04 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -1114,7 +1114,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let item_segment = hir::PathSegment { ident, hir_id: Some(binding.hir_id), - res: None, + res: Res::Err, args: Some(binding.gen_args), infer_args: false, }; @@ -1845,7 +1845,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { [.., hir::PathSegment { ident, args, - res: Some(Res::Def(DefKind::Enum, _)), + res: Res::Def(DefKind::Enum, _), .. }, _] => ( // We need to include the `::` in `Type::Variant::` @@ -2127,24 +2127,22 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let types_and_spans: Vec<_> = segments .clone() .flat_map(|segment| { - segment.res.and_then(|res| { - if segment.args().args.is_empty() { - None - } else { - Some(( - match res { - Res::PrimTy(ty) => format!("{} `{}`", res.descr(), ty.name()), + if segment.args().args.is_empty() { + None + } else { + Some(( + match segment.res { + Res::PrimTy(ty) => format!("{} `{}`", segment.res.descr(), ty.name()), Res::Def(_, def_id) if let Some(name) = self.tcx().opt_item_name(def_id) => { - format!("{} `{name}`", res.descr()) + format!("{} `{name}`", segment.res.descr()) } Res::Err => "this type".to_string(), - _ => res.descr().to_string(), + _ => segment.res.descr().to_string(), }, segment.ident.span, )) - } - }) + } }) .collect(); let this_type = match &types_and_spans[..] { diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 29a128f27b84..46135caa9bce 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -610,12 +610,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>( fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) { match arg.kind { hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments { - [ - PathSegment { - res: Some(Res::SelfTy { trait_: _, alias_to: impl_ref }), - .. - }, - ] => { + [PathSegment { res: Res::SelfTy { trait_: _, alias_to: impl_ref }, .. }] => { let impl_ty_name = impl_ref.map(|(def_id, _)| self.tcx.def_path_str(def_id)); self.selftys.push((path.span, impl_ty_name)); diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 86cf12d22404..5c6c8aca1734 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -768,7 +768,7 @@ impl<'tcx> TypeVisitor<'tcx> for GATSubstCollector<'tcx> { fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool { match ty.kind { hir::TyKind::TraitObject([trait_ref], ..) => match trait_ref.trait_ref.path.segments { - [s] => s.res.and_then(|r| r.opt_def_id()) == Some(trait_def_id.to_def_id()), + [s] => s.res.opt_def_id() == Some(trait_def_id.to_def_id()), _ => false, }, _ => false, diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 9f931de6fded..d7c93af5fddc 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -1,6 +1,5 @@ use rustc_errors::{Applicability, StashKey}; use rustc_hir as hir; -use rustc_hir::def::Res; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit; use rustc_hir::intravisit::Visitor; @@ -179,15 +178,12 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< return None; }; - // Try to use the segment resolution if it is valid, otherwise we - // default to the path resolution. - let res = segment.res.filter(|&r| r != Res::Err).unwrap_or(path.res); - let generics = match tcx.res_generics_def_id(res) { + let generics = match tcx.res_generics_def_id(segment.res) { Some(def_id) => tcx.generics_of(def_id), None => { tcx.sess.delay_span_bug( tcx.def_span(def_id), - &format!("unexpected anon const res {:?} in path: {:?}", res, path), + &format!("unexpected anon const res {:?} in path: {:?}", segment.res, path), ); return None; } diff --git a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs index 1805672e3725..1085e6089441 100644 --- a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs +++ b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs @@ -185,7 +185,7 @@ fn in_impl<'tcx>( if let ItemKind::Impl(item) = &item.kind; if let Some(of_trait) = &item.of_trait; if let Some(seg) = of_trait.path.segments.last(); - if let Some(Res::Def(_, trait_id)) = seg.res; + if let Res::Def(_, trait_id) = seg.res; if trait_id == bin_op; if let Some(generic_args) = seg.args; if let Some(GenericArg::Type(other_ty)) = generic_args.args.last(); diff --git a/src/tools/clippy/clippy_lints/src/ref_option_ref.rs b/src/tools/clippy/clippy_lints/src/ref_option_ref.rs index 909d6971a549..42514f861be1 100644 --- a/src/tools/clippy/clippy_lints/src/ref_option_ref.rs +++ b/src/tools/clippy/clippy_lints/src/ref_option_ref.rs @@ -43,8 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for RefOptionRef { if mut_ty.mutbl == Mutability::Not; if let TyKind::Path(ref qpath) = &mut_ty.ty.kind; let last = last_path_segment(qpath); - if let Some(res) = last.res; - if let Some(def_id) = res.opt_def_id(); + if let Some(def_id) = last.res.opt_def_id(); if cx.tcx.is_diagnostic_item(sym::Option, def_id); if let Some(params) = last_path_segment(qpath).args ; diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index 2ffa022b04f7..a25be93b8d61 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -128,7 +128,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { if !bound_predicate.span.from_expansion(); if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind; if let Some(PathSegment { - res: Some(Res::SelfTy{ trait_: Some(def_id), alias_to: _ }), .. + res: Res::SelfTy{ trait_: Some(def_id), alias_to: _ }, .. }) = segments.first(); if let Some( Node::Item( From bb0ae3c446e21002324f030efdfcdd80d1242450 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 30 Aug 2022 16:54:42 +1000 Subject: [PATCH 4189/5092] Make `hir::PathSegment::hir_id` non-optional. --- compiler/rustc_ast_lowering/src/expr.rs | 3 +- compiler/rustc_ast_lowering/src/index.rs | 4 +- compiler/rustc_ast_lowering/src/item.rs | 3 +- compiler/rustc_ast_lowering/src/lib.rs | 5 +- compiler/rustc_ast_lowering/src/pat.rs | 3 +- compiler/rustc_ast_lowering/src/path.rs | 6 +- .../src/diagnostics/mutability_errors.rs | 9 +- compiler/rustc_hir/src/hir.rs | 8 +- compiler/rustc_hir/src/hir_id.rs | 3 + compiler/rustc_hir/src/intravisit.rs | 2 +- .../infer/error_reporting/need_type_info.rs | 6 +- .../rustc_save_analysis/src/dump_visitor.rs | 5 +- compiler/rustc_save_analysis/src/lib.rs | 2 +- compiler/rustc_typeck/src/astconv/mod.rs | 2 +- .../wrong_number_of_generic_args.rs | 105 +++++++++--------- src/librustdoc/html/render/span_map.rs | 34 +++--- 16 files changed, 103 insertions(+), 97 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index a41d4b01e0e3..d31ec91fcaad 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1776,13 +1776,14 @@ impl<'hir> LoweringContext<'_, 'hir> { binding: hir::HirId, attrs: AttrVec, ) -> hir::Expr<'hir> { + let hir_id = self.next_id(); let res = Res::Local(binding); let expr_path = hir::ExprKind::Path(hir::QPath::Resolved( None, self.arena.alloc(hir::Path { span: self.lower_span(span), res, - segments: arena_vec![self; hir::PathSegment::from_ident(ident, res)], + segments: arena_vec![self; hir::PathSegment::from_ident(ident, hir_id, res)], }), )); diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 219e1b81d1ea..61470d93bdb2 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -246,9 +246,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { } fn visit_path_segment(&mut self, path_span: Span, path_segment: &'hir PathSegment<'hir>) { - if let Some(hir_id) = path_segment.hir_id { - self.insert(path_span, hir_id, Node::PathSegment(path_segment)); - } + self.insert(path_span, path_segment.hir_id, Node::PathSegment(path_segment)); intravisit::walk_path_segment(self, path_span, path_segment); } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index e3f02968d4d7..778203acf7df 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1431,13 +1431,14 @@ impl<'hir> LoweringContext<'_, 'hir> { GenericParamKind::Const { .. } => None, GenericParamKind::Type { .. } => { let def_id = self.local_def_id(id).to_def_id(); + let hir_id = self.next_id(); let res = Res::Def(DefKind::TyParam, def_id); let ty_path = self.arena.alloc(hir::Path { span: param_span, res, segments: self .arena - .alloc_from_iter([hir::PathSegment::from_ident(ident, res)]), + .alloc_from_iter([hir::PathSegment::from_ident(ident, hir_id, res)]), }); let ty_id = self.next_id(); let bounded_ty = diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index bc183c6e3135..097855bb6bf6 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1260,6 +1260,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { return self.lower_path_ty(t, qself, path, ParamMode::Explicit, itctx); } TyKind::ImplicitSelf => { + let hir_id = self.lower_node_id(t.id); let res = self.expect_full_res(t.id); let res = self.lower_res(res); hir::TyKind::Path(hir::QPath::Resolved( @@ -1268,6 +1269,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { res, segments: arena_vec![self; hir::PathSegment::from_ident( Ident::with_dummy_span(kw::SelfUpper), + hir_id, res )], span: self.lower_span(t.span), @@ -2194,13 +2196,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::PredicateOrigin::ImplTrait, ); + let hir_id = self.next_id(); let res = Res::Def(DefKind::TyParam, def_id.to_def_id()); let ty = hir::TyKind::Path(hir::QPath::Resolved( None, self.arena.alloc(hir::Path { span: self.lower_span(span), res, - segments: arena_vec![self; hir::PathSegment::from_ident(self.lower_ident(ident), res)], + segments: arena_vec![self; hir::PathSegment::from_ident(self.lower_ident(ident), hir_id, res)], }), )); diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 61c32816e171..a23f5fddc57e 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -255,13 +255,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) } Some(res) => { + let hir_id = self.next_id(); let res = self.lower_res(res); hir::PatKind::Path(hir::QPath::Resolved( None, self.arena.alloc(hir::Path { span: self.lower_span(ident.span), res, - segments: arena_vec![self; hir::PathSegment::from_ident(self.lower_ident(ident), res)], + segments: arena_vec![self; hir::PathSegment::from_ident(self.lower_ident(ident), hir_id, res)], }), )) } diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 6ec8bcbc1e57..5f0ddd5ac1c6 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -250,15 +250,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } let res = self.expect_full_res(segment.id); - let id = self.lower_node_id(segment.id); + let hir_id = self.lower_node_id(segment.id); debug!( "lower_path_segment: ident={:?} original-id={:?} new-id={:?}", - segment.ident, segment.id, id, + segment.ident, segment.id, hir_id, ); hir::PathSegment { ident: self.lower_ident(segment.ident), - hir_id: Some(id), + hir_id, res: self.lower_res(res), infer_args, args: if generic_args.is_empty() && generic_args.span.is_empty() { diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index dd9590016b99..66d2614b190d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -935,10 +935,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { _, ) = hir_map.body(fn_body_id).value.kind { - let opt_suggestions = path_segment - .hir_id - .map(|path_hir_id| self.infcx.tcx.typeck(path_hir_id.owner)) - .and_then(|typeck| typeck.type_dependent_def_id(*hir_id)) + let opt_suggestions = self + .infcx + .tcx + .typeck(path_segment.hir_id.owner) + .type_dependent_def_id(*hir_id) .and_then(|def_id| self.infcx.tcx.impl_of_method(def_id)) .map(|def_id| self.infcx.tcx.associated_items(def_id)) .map(|assoc_items| { diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index bd53e7670a6e..561045ff4ef0 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -203,7 +203,7 @@ pub struct PathSegment<'hir> { /// The identifier portion of this path segment. pub ident: Ident, - pub hir_id: Option, + pub hir_id: HirId, pub res: Res, @@ -223,12 +223,12 @@ pub struct PathSegment<'hir> { impl<'hir> PathSegment<'hir> { /// Converts an identifier to the corresponding segment. - pub fn from_ident(ident: Ident, res: Res) -> PathSegment<'hir> { - PathSegment { ident, hir_id: None, res, infer_args: true, args: None } + pub fn from_ident(ident: Ident, hir_id: HirId, res: Res) -> PathSegment<'hir> { + PathSegment { ident, hir_id, res, infer_args: true, args: None } } pub fn invalid() -> Self { - Self::from_ident(Ident::empty(), Res::Err) + Self::from_ident(Ident::empty(), HirId::INVALID, Res::Err) } pub fn args(&self) -> &GenericArgs<'hir> { diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs index 346ac9e96440..e586d5cd5d94 100644 --- a/compiler/rustc_hir/src/hir_id.rs +++ b/compiler/rustc_hir/src/hir_id.rs @@ -20,6 +20,9 @@ pub struct HirId { } impl HirId { + /// Signal local id which should never be used. + pub const INVALID: HirId = HirId { owner: CRATE_DEF_ID, local_id: ItemLocalId::INVALID }; + #[inline] pub fn expect_owner(self) -> LocalDefId { assert_eq!(self.local_id.index(), 0); diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 3d5e22add718..036becf4b7cc 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -724,7 +724,7 @@ pub fn walk_path_segment<'v, V: Visitor<'v>>( segment: &'v PathSegment<'v>, ) { visitor.visit_ident(segment.ident); - walk_list!(visitor, visit_id, segment.hir_id); + visitor.visit_id(segment.hir_id); if let Some(ref args) = segment.args { visitor.visit_generic_args(path_span, args); } diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index a20bcd93045f..126c39c3bad5 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -909,7 +909,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { None? } let substs = self.node_substs_opt(expr.hir_id)?; - let span = tcx.hir().span(segment.hir_id?); + let span = tcx.hir().span(segment.hir_id); let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi()); InsertableGenericArgs { insert_span, @@ -963,7 +963,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { if generics.has_impl_trait() { return None; } - let span = tcx.hir().span(segment.hir_id?); + let span = tcx.hir().span(segment.hir_id); let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi()); Some(InsertableGenericArgs { insert_span, @@ -996,7 +996,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { if !segment.infer_args || generics.has_impl_trait() { None?; } - let span = tcx.hir().span(segment.hir_id?); + let span = tcx.hir().span(segment.hir_id); let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi()); InsertableGenericArgs { insert_span, substs, generics_def_id: def_id, def_id } }; diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs index 769d3243d584..f2b2daaf20bf 100644 --- a/compiler/rustc_save_analysis/src/dump_visitor.rs +++ b/compiler/rustc_save_analysis/src/dump_visitor.rs @@ -912,7 +912,10 @@ impl<'tcx> DumpVisitor<'tcx> { _, ) | Res::SelfTy { .. } => { - self.dump_path_segment_ref(id, &hir::PathSegment::from_ident(ident, Res::Err)); + self.dump_path_segment_ref( + id, + &hir::PathSegment::from_ident(ident, hir::HirId::INVALID, Res::Err), + ); } def => { error!("unexpected definition kind when processing collected idents: {:?}", def) diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index 4b110b824e00..c58ccde43907 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -649,7 +649,7 @@ impl<'tcx> SaveContext<'tcx> { } pub fn get_path_segment_data(&self, path_seg: &hir::PathSegment<'_>) -> Option { - self.get_path_segment_data_with_id(path_seg, path_seg.hir_id?) + self.get_path_segment_data_with_id(path_seg, path_seg.hir_id) } pub fn get_path_segment_data_with_id( diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index a49244d16d04..faf3d7a1000c 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -1113,7 +1113,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let ident = Ident::new(assoc_item.name, binding.item_name.span); let item_segment = hir::PathSegment { ident, - hir_id: Some(binding.hir_id), + hir_id: binding.hir_id, res: Res::Err, args: Some(binding.gen_args), infer_args: false, diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs index d4b5e5e2fe44..eeb0e9ce738d 100644 --- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs @@ -291,62 +291,60 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { // Creates lifetime name suggestions from the lifetime parameter names fn get_lifetime_args_suggestions_from_param_names( &self, - path_hir_id: Option, + path_hir_id: hir::HirId, num_params_to_take: usize, ) -> String { debug!(?path_hir_id); - if let Some(path_hir_id) = path_hir_id { - let mut ret = Vec::new(); - for (id, node) in self.tcx.hir().parent_iter(path_hir_id) { - debug!(?id); - let params = if let Some(generics) = node.generics() { - generics.params - } else if let hir::Node::Ty(ty) = node - && let hir::TyKind::BareFn(bare_fn) = ty.kind - { - bare_fn.generic_params - } else { - &[] - }; - ret.extend(params.iter().filter_map(|p| { - let hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit } - = p.kind - else { return None }; - let hir::ParamName::Plain(name) = p.name else { return None }; - Some(name.to_string()) - })); - // Suggest `'static` when in const/static item-like. - if let hir::Node::Item(hir::Item { - kind: hir::ItemKind::Static { .. } | hir::ItemKind::Const { .. }, - .. - }) - | hir::Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Const { .. }, - .. - }) - | hir::Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Const { .. }, - .. - }) - | hir::Node::ForeignItem(hir::ForeignItem { - kind: hir::ForeignItemKind::Static { .. }, - .. - }) - | hir::Node::AnonConst(..) = node - { - ret.extend( - std::iter::repeat("'static".to_owned()) - .take(num_params_to_take.saturating_sub(ret.len())), - ); - } - if ret.len() >= num_params_to_take { - return ret[..num_params_to_take].join(", "); - } - // We cannot refer to lifetimes defined in an outer function. - if let hir::Node::Item(_) = node { - break; - } + let mut ret = Vec::new(); + for (id, node) in self.tcx.hir().parent_iter(path_hir_id) { + debug!(?id); + let params = if let Some(generics) = node.generics() { + generics.params + } else if let hir::Node::Ty(ty) = node + && let hir::TyKind::BareFn(bare_fn) = ty.kind + { + bare_fn.generic_params + } else { + &[] + }; + ret.extend(params.iter().filter_map(|p| { + let hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit } + = p.kind + else { return None }; + let hir::ParamName::Plain(name) = p.name else { return None }; + Some(name.to_string()) + })); + // Suggest `'static` when in const/static item-like. + if let hir::Node::Item(hir::Item { + kind: hir::ItemKind::Static { .. } | hir::ItemKind::Const { .. }, + .. + }) + | hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Const { .. }, + .. + }) + | hir::Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::Const { .. }, + .. + }) + | hir::Node::ForeignItem(hir::ForeignItem { + kind: hir::ForeignItemKind::Static { .. }, + .. + }) + | hir::Node::AnonConst(..) = node + { + ret.extend( + std::iter::repeat("'static".to_owned()) + .take(num_params_to_take.saturating_sub(ret.len())), + ); + } + if ret.len() >= num_params_to_take { + return ret[..num_params_to_take].join(", "); + } + // We cannot refer to lifetimes defined in an outer function. + if let hir::Node::Item(_) = node { + break; } } @@ -690,8 +688,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { num = num_trait_generics_except_self, ); - if let Some(hir_id) = self.path_segment.hir_id - && let Some(parent_node) = self.tcx.hir().find_parent_node(hir_id) + if let Some(parent_node) = self.tcx.hir().find_parent_node(self.path_segment.hir_id) && let Some(parent_node) = self.tcx.hir().find(parent_node) && let hir::Node::Expr(expr) = parent_node { match expr.kind { diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index 34d590fb2448..151ec2b28adc 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -166,25 +166,23 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) { if let ExprKind::MethodCall(segment, ..) = expr.kind { - if let Some(hir_id) = segment.hir_id { - let hir = self.tcx.hir(); - let body_id = hir.enclosing_body_owner(hir_id); - // FIXME: this is showing error messages for parts of the code that are not - // compiled (because of cfg)! - // - // See discussion in https://github.com/rust-lang/rust/issues/69426#issuecomment-1019412352 - let typeck_results = self.tcx.typeck_body( - hir.maybe_body_owned_by(body_id).expect("a body which isn't a body"), + let hir = self.tcx.hir(); + let body_id = hir.enclosing_body_owner(segment.hir_id); + // FIXME: this is showing error messages for parts of the code that are not + // compiled (because of cfg)! + // + // See discussion in https://github.com/rust-lang/rust/issues/69426#issuecomment-1019412352 + let typeck_results = self + .tcx + .typeck_body(hir.maybe_body_owned_by(body_id).expect("a body which isn't a body")); + if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) { + self.matches.insert( + segment.ident.span, + match hir.span_if_local(def_id) { + Some(span) => LinkFromSrc::Local(clean::Span::new(span)), + None => LinkFromSrc::External(def_id), + }, ); - if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) { - self.matches.insert( - segment.ident.span, - match hir.span_if_local(def_id) { - Some(span) => LinkFromSrc::Local(clean::Span::new(span)), - None => LinkFromSrc::External(def_id), - }, - ); - } } } else if self.handle_macro(expr.span) { // We don't want to go deeper into the macro. From 25f6f188345bb2fc5d826ea8eb9346a1d51ce98c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 30 Aug 2022 15:10:28 +1000 Subject: [PATCH 4190/5092] Make `hir::PathSegment::res` non-optional. --- clippy_lints/src/operators/op_ref.rs | 2 +- clippy_lints/src/ref_option_ref.rs | 3 +-- clippy_lints/src/trait_bounds.rs | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/operators/op_ref.rs b/clippy_lints/src/operators/op_ref.rs index 1805672e3725..1085e6089441 100644 --- a/clippy_lints/src/operators/op_ref.rs +++ b/clippy_lints/src/operators/op_ref.rs @@ -185,7 +185,7 @@ fn in_impl<'tcx>( if let ItemKind::Impl(item) = &item.kind; if let Some(of_trait) = &item.of_trait; if let Some(seg) = of_trait.path.segments.last(); - if let Some(Res::Def(_, trait_id)) = seg.res; + if let Res::Def(_, trait_id) = seg.res; if trait_id == bin_op; if let Some(generic_args) = seg.args; if let Some(GenericArg::Type(other_ty)) = generic_args.args.last(); diff --git a/clippy_lints/src/ref_option_ref.rs b/clippy_lints/src/ref_option_ref.rs index 909d6971a549..42514f861be1 100644 --- a/clippy_lints/src/ref_option_ref.rs +++ b/clippy_lints/src/ref_option_ref.rs @@ -43,8 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for RefOptionRef { if mut_ty.mutbl == Mutability::Not; if let TyKind::Path(ref qpath) = &mut_ty.ty.kind; let last = last_path_segment(qpath); - if let Some(res) = last.res; - if let Some(def_id) = res.opt_def_id(); + if let Some(def_id) = last.res.opt_def_id(); if cx.tcx.is_diagnostic_item(sym::Option, def_id); if let Some(params) = last_path_segment(qpath).args ; diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs index 2ffa022b04f7..a25be93b8d61 100644 --- a/clippy_lints/src/trait_bounds.rs +++ b/clippy_lints/src/trait_bounds.rs @@ -128,7 +128,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { if !bound_predicate.span.from_expansion(); if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind; if let Some(PathSegment { - res: Some(Res::SelfTy{ trait_: Some(def_id), alias_to: _ }), .. + res: Res::SelfTy{ trait_: Some(def_id), alias_to: _ }, .. }) = segments.first(); if let Some( Node::Item( From 08a00eb0da303f82057174ab79d5b079d762bb61 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 1 Sep 2022 08:44:20 +1000 Subject: [PATCH 4191/5092] Address review comments. --- compiler/rustc_ast_lowering/src/expr.rs | 2 +- compiler/rustc_ast_lowering/src/item.rs | 2 +- compiler/rustc_ast_lowering/src/lib.rs | 5 +++-- compiler/rustc_ast_lowering/src/pat.rs | 2 +- compiler/rustc_hir/src/hir.rs | 6 ++---- compiler/rustc_save_analysis/src/dump_visitor.rs | 2 +- 6 files changed, 9 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index d31ec91fcaad..22245692d138 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1783,7 +1783,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.arena.alloc(hir::Path { span: self.lower_span(span), res, - segments: arena_vec![self; hir::PathSegment::from_ident(ident, hir_id, res)], + segments: arena_vec![self; hir::PathSegment::new(ident, hir_id, res)], }), )); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 778203acf7df..8ca52269d6e1 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1438,7 +1438,7 @@ impl<'hir> LoweringContext<'_, 'hir> { res, segments: self .arena - .alloc_from_iter([hir::PathSegment::from_ident(ident, hir_id, res)]), + .alloc_from_iter([hir::PathSegment::new(ident, hir_id, res)]), }); let ty_id = self.next_id(); let bounded_ty = diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 097855bb6bf6..5832bf917908 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1267,7 +1267,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { None, self.arena.alloc(hir::Path { res, - segments: arena_vec![self; hir::PathSegment::from_ident( + segments: arena_vec![self; hir::PathSegment::new( Ident::with_dummy_span(kw::SelfUpper), hir_id, res @@ -2203,7 +2203,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.arena.alloc(hir::Path { span: self.lower_span(span), res, - segments: arena_vec![self; hir::PathSegment::from_ident(self.lower_ident(ident), hir_id, res)], + segments: + arena_vec![self; hir::PathSegment::new(self.lower_ident(ident), hir_id, res)], }), )); diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index a23f5fddc57e..87ccf5861e1c 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -262,7 +262,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.arena.alloc(hir::Path { span: self.lower_span(ident.span), res, - segments: arena_vec![self; hir::PathSegment::from_ident(self.lower_ident(ident), hir_id, res)], + segments: arena_vec![self; hir::PathSegment::new(self.lower_ident(ident), hir_id, res)], }), )) } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 561045ff4ef0..b395917cd7ab 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -202,9 +202,7 @@ impl Path<'_> { pub struct PathSegment<'hir> { /// The identifier portion of this path segment. pub ident: Ident, - pub hir_id: HirId, - pub res: Res, /// Type/lifetime parameters attached to this path. They come in @@ -223,12 +221,12 @@ pub struct PathSegment<'hir> { impl<'hir> PathSegment<'hir> { /// Converts an identifier to the corresponding segment. - pub fn from_ident(ident: Ident, hir_id: HirId, res: Res) -> PathSegment<'hir> { + pub fn new(ident: Ident, hir_id: HirId, res: Res) -> PathSegment<'hir> { PathSegment { ident, hir_id, res, infer_args: true, args: None } } pub fn invalid() -> Self { - Self::from_ident(Ident::empty(), HirId::INVALID, Res::Err) + Self::new(Ident::empty(), HirId::INVALID, Res::Err) } pub fn args(&self) -> &GenericArgs<'hir> { diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs index f2b2daaf20bf..d95ade594fbb 100644 --- a/compiler/rustc_save_analysis/src/dump_visitor.rs +++ b/compiler/rustc_save_analysis/src/dump_visitor.rs @@ -914,7 +914,7 @@ impl<'tcx> DumpVisitor<'tcx> { | Res::SelfTy { .. } => { self.dump_path_segment_ref( id, - &hir::PathSegment::from_ident(ident, hir::HirId::INVALID, Res::Err), + &hir::PathSegment::new(ident, hir::HirId::INVALID, Res::Err), ); } def => { From 41d4ea231410004f8f07bc097c51a5fe991b4ba5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 5 Sep 2022 04:26:37 +0000 Subject: [PATCH 4192/5092] Don't suggest reborrow if usage is inside a closure --- .../src/diagnostics/conflict_errors.rs | 3 ++- src/test/ui/borrowck/issue-101119.rs | 16 ++++++++++++++++ src/test/ui/borrowck/issue-101119.stderr | 15 +++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/borrowck/issue-101119.rs create mode 100644 src/test/ui/borrowck/issue-101119.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 5971f7623f21..f2204c24263c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -258,7 +258,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let ty = place.ty(self.body, self.infcx.tcx).ty; // If we're in pattern, we do nothing in favor of the previous suggestion (#80913). - if is_loop_move & !in_pattern { + // Same for if we're in a loop, see #101119. + if is_loop_move & !in_pattern && !matches!(use_spans, UseSpans::ClosureUse { .. }) { if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() { // We have a `&mut` ref, we need to reborrow on each iteration (#62112). err.span_suggestion_verbose( diff --git a/src/test/ui/borrowck/issue-101119.rs b/src/test/ui/borrowck/issue-101119.rs new file mode 100644 index 000000000000..64e52eaac06e --- /dev/null +++ b/src/test/ui/borrowck/issue-101119.rs @@ -0,0 +1,16 @@ +struct State; + +fn once(_: impl FnOnce()) {} + +fn fill_memory_blocks_mt(state: &mut State) { + loop { + once(move || { + //~^ ERROR use of moved value: `state` + fill_segment(state); + }); + } +} + +fn fill_segment(_: &mut State) {} + +fn main() {} diff --git a/src/test/ui/borrowck/issue-101119.stderr b/src/test/ui/borrowck/issue-101119.stderr new file mode 100644 index 000000000000..a22afdc67648 --- /dev/null +++ b/src/test/ui/borrowck/issue-101119.stderr @@ -0,0 +1,15 @@ +error[E0382]: use of moved value: `state` + --> $DIR/issue-101119.rs:7:14 + | +LL | fn fill_memory_blocks_mt(state: &mut State) { + | ----- move occurs because `state` has type `&mut State`, which does not implement the `Copy` trait +LL | loop { +LL | once(move || { + | ^^^^^^^ value moved into closure here, in previous iteration of loop +LL | +LL | fill_segment(state); + | ----- use occurs due to use in closure + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. From 7e226e6d3f5dc5c39a222091f7a234c1480e1cbd Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 5 Sep 2022 05:00:26 +0000 Subject: [PATCH 4193/5092] Look at move place's type when suggesting mutable reborrow --- .../src/diagnostics/conflict_errors.rs | 1 - .../rustc_borrowck/src/diagnostics/mod.rs | 9 ++++--- .../src/diagnostics/move_errors.rs | 2 +- .../reborrow-sugg-move-then-borrow.rs | 26 +++++++++++++++++++ .../reborrow-sugg-move-then-borrow.stderr | 24 +++++++++++++++++ 5 files changed, 56 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/borrowck/reborrow-sugg-move-then-borrow.rs create mode 100644 src/test/ui/borrowck/reborrow-sugg-move-then-borrow.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 5971f7623f21..a2e4641f66d5 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -198,7 +198,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { move_span, move_spans, *moved_place, - Some(used_place), partially_str, loop_message, move_msg, diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 683084cf09d4..2d849316f929 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -970,7 +970,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { move_span: Span, move_spans: UseSpans<'tcx>, moved_place: Place<'tcx>, - used_place: Option>, partially_str: &str, loop_message: &str, move_msg: &str, @@ -1058,9 +1057,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { place_name, partially_str, loop_message ), ); - // If we have a `&mut` ref, we need to reborrow. - if let Some(ty::Ref(_, _, hir::Mutability::Mut)) = used_place - .map(|used_place| used_place.ty(self.body, self.infcx.tcx).ty.kind()) + // If the moved place was a `&mut` ref, then we can + // suggest to reborrow it where it was moved, so it + // will still be valid by the time we get to the usage. + if let ty::Ref(_, _, hir::Mutability::Mut) = + moved_place.ty(self.body, self.infcx.tcx).ty.kind() { // If we are in a loop this will be suggested later. if !is_loop_move { diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 16c2f9ccc6aa..bb06a94635c4 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -401,7 +401,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }; if let Some(use_spans) = use_spans { self.explain_captures( - &mut err, span, span, use_spans, move_place, None, "", "", "", false, true, + &mut err, span, span, use_spans, move_place, "", "", "", false, true, ); } err diff --git a/src/test/ui/borrowck/reborrow-sugg-move-then-borrow.rs b/src/test/ui/borrowck/reborrow-sugg-move-then-borrow.rs new file mode 100644 index 000000000000..31eba0740084 --- /dev/null +++ b/src/test/ui/borrowck/reborrow-sugg-move-then-borrow.rs @@ -0,0 +1,26 @@ +// Tests the suggestion to reborrow the first move site +// when we move then borrow a `&mut` ref. + +struct State; + +impl IntoIterator for &mut State { + type IntoIter = std::vec::IntoIter<()>; + type Item = (); + + fn into_iter(self) -> Self::IntoIter { + vec![].into_iter() + } +} + +fn once(f: impl FnOnce()) {} + +fn fill_memory_blocks_mt(state: &mut State) { + for _ in state {} + //~^ HELP consider creating a fresh reborrow of `state` here + fill_segment(state); + //~^ ERROR borrow of moved value: `state` +} + +fn fill_segment(state: &mut State) {} + +fn main() {} diff --git a/src/test/ui/borrowck/reborrow-sugg-move-then-borrow.stderr b/src/test/ui/borrowck/reborrow-sugg-move-then-borrow.stderr new file mode 100644 index 000000000000..13a2005e2ef4 --- /dev/null +++ b/src/test/ui/borrowck/reborrow-sugg-move-then-borrow.stderr @@ -0,0 +1,24 @@ +error[E0382]: borrow of moved value: `state` + --> $DIR/reborrow-sugg-move-then-borrow.rs:20:18 + | +LL | fn fill_memory_blocks_mt(state: &mut State) { + | ----- move occurs because `state` has type `&mut State`, which does not implement the `Copy` trait +LL | for _ in state {} + | ----- `state` moved due to this implicit call to `.into_iter()` +LL | +LL | fill_segment(state); + | ^^^^^ value borrowed here after move + | +note: this function takes ownership of the receiver `self`, which moves `state` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + | +LL | fn into_iter(self) -> Self::IntoIter; + | ^^^^ +help: consider creating a fresh reborrow of `state` here + | +LL | for _ in &mut *state {} + | ++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. From 79db32b64ec946afbef2ed50282f03b71d933480 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 5 Sep 2022 14:03:53 +1000 Subject: [PATCH 4194/5092] Pack `Term` in the same way as `GenericArg`. This shrinks the `PredicateS` type, which is instanted frequently. --- .../src/infer/error_reporting/mod.rs | 45 +++---- compiler/rustc_infer/src/infer/mod.rs | 9 +- compiler/rustc_middle/src/ty/flags.rs | 14 +-- compiler/rustc_middle/src/ty/mod.rs | 110 +++++++++++++++--- compiler/rustc_middle/src/ty/print/pretty.rs | 20 ++-- compiler/rustc_middle/src/ty/relate.rs | 10 +- .../rustc_middle/src/ty/structural_impls.rs | 13 ++- compiler/rustc_middle/src/ty/walk.rs | 6 +- .../src/typeid/typeid_itanium_cxx_abi.rs | 12 +- compiler/rustc_symbol_mangling/src/v0.rs | 6 +- .../src/traits/auto_trait.rs | 4 +- .../src/traits/project.rs | 2 +- .../rustc_trait_selection/src/traits/wf.rs | 6 +- compiler/rustc_typeck/src/astconv/mod.rs | 16 +-- compiler/rustc_typeck/src/check/method/mod.rs | 4 +- .../rustc_typeck/src/variance/constraints.rs | 6 +- src/librustdoc/clean/mod.rs | 6 +- .../clippy/clippy_lints/src/dereference.rs | 2 +- .../clippy/clippy_lints/src/methods/mod.rs | 6 +- .../src/methods/unnecessary_to_owned.rs | 2 +- 20 files changed, 191 insertions(+), 108 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 6dad9873d613..f5b7489af562 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1586,28 +1586,31 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Some(values) => { let values = self.resolve_vars_if_possible(values); let (is_simple_error, exp_found) = match values { - ValuePairs::Terms(infer::ExpectedFound { - expected: ty::Term::Ty(expected), - found: ty::Term::Ty(found), - }) => { - let is_simple_err = expected.is_simple_text() && found.is_simple_text(); - OpaqueTypesVisitor::visit_expected_found(self.tcx, expected, found, span) - .report(diag); + ValuePairs::Terms(infer::ExpectedFound { expected, found }) => { + match (expected.unpack(), found.unpack()) { + (ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => { + let is_simple_err = + expected.is_simple_text() && found.is_simple_text(); + OpaqueTypesVisitor::visit_expected_found( + self.tcx, expected, found, span, + ) + .report(diag); - ( - is_simple_err, - Mismatch::Variable(infer::ExpectedFound { expected, found }), - ) + ( + is_simple_err, + Mismatch::Variable(infer::ExpectedFound { expected, found }), + ) + } + (ty::TermKind::Const(_), ty::TermKind::Const(_)) => { + (false, Mismatch::Fixed("constant")) + } + _ => (false, Mismatch::Fixed("type")), + } } - ValuePairs::Terms(infer::ExpectedFound { - expected: ty::Term::Const(_), - found: ty::Term::Const(_), - }) => (false, Mismatch::Fixed("constant")), ValuePairs::TraitRefs(_) | ValuePairs::PolyTraitRefs(_) => { (false, Mismatch::Fixed("trait")) } ValuePairs::Regions(_) => (false, Mismatch::Fixed("lifetime")), - _ => (false, Mismatch::Fixed("type")), }; let vals = match self.values_str(values) { Some((expected, found)) => Some((expected, found)), @@ -2273,11 +2276,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { return None; } - Some(match (exp_found.expected, exp_found.found) { - (ty::Term::Ty(expected), ty::Term::Ty(found)) => self.cmp(expected, found), - (expected, found) => ( - DiagnosticStyledString::highlighted(expected.to_string()), - DiagnosticStyledString::highlighted(found.to_string()), + Some(match (exp_found.expected.unpack(), exp_found.found.unpack()) { + (ty::TermKind::Ty(expected), ty::TermKind::Ty(found)) => self.cmp(expected, found), + _ => ( + DiagnosticStyledString::highlighted(exp_found.expected.to_string()), + DiagnosticStyledString::highlighted(exp_found.found.to_string()), ), }) } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index fe037a458a7f..bbbc044b85a4 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -353,12 +353,11 @@ pub enum ValuePairs<'tcx> { impl<'tcx> ValuePairs<'tcx> { pub fn ty(&self) -> Option<(Ty<'tcx>, Ty<'tcx>)> { - if let ValuePairs::Terms(ExpectedFound { - expected: ty::Term::Ty(expected), - found: ty::Term::Ty(found), - }) = self + if let ValuePairs::Terms(ExpectedFound { expected, found }) = self + && let Some(expected) = expected.ty() + && let Some(found) = found.ty() { - Some((*expected, *found)) + Some((expected, found)) } else { None } diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index ea6bb8a7abd4..c22c899c5cce 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -1,5 +1,5 @@ use crate::ty::subst::{GenericArg, GenericArgKind}; -use crate::ty::{self, InferConst, Term, Ty, TypeFlags}; +use crate::ty::{self, InferConst, Ty, TypeFlags}; use std::slice; #[derive(Debug)] @@ -243,9 +243,9 @@ impl FlagComputation { } ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => { self.add_projection_ty(projection_ty); - match term { - Term::Ty(ty) => self.add_ty(ty), - Term::Const(c) => self.add_const(c), + match term.unpack() { + ty::TermKind::Ty(ty) => self.add_ty(ty), + ty::TermKind::Const(c) => self.add_const(c), } } ty::PredicateKind::WellFormed(arg) => { @@ -320,9 +320,9 @@ impl FlagComputation { fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) { self.add_substs(projection.substs); - match projection.term { - ty::Term::Ty(ty) => self.add_ty(ty), - ty::Term::Const(ct) => self.add_const(ct), + match projection.term.unpack() { + ty::TermKind::Ty(ty) => self.add_ty(ty), + ty::TermKind::Const(ct) => self.add_const(ct), } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index f59d14a4a0c1..4e9ccf039613 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -40,6 +40,7 @@ use rustc_hir::Node; use rustc_index::vec::IndexVec; use rustc_macros::HashStable; use rustc_query_system::ich::StableHashingContext; +use rustc_serialize::{Decodable, Encodable}; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{ExpnId, Span}; @@ -49,6 +50,9 @@ pub use vtable::*; use std::fmt::Debug; use std::hash::{Hash, Hasher}; +use std::marker::PhantomData; +use std::mem; +use std::num::NonZeroUsize; use std::ops::ControlFlow; use std::{fmt, str}; @@ -902,42 +906,122 @@ pub struct CoercePredicate<'tcx> { } pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>; -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable)] -pub enum Term<'tcx> { - Ty(Ty<'tcx>), - Const(Const<'tcx>), +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Term<'tcx> { + ptr: NonZeroUsize, + marker: PhantomData<(Ty<'tcx>, Const<'tcx>)>, } impl<'tcx> From> for Term<'tcx> { fn from(ty: Ty<'tcx>) -> Self { - Term::Ty(ty) + TermKind::Ty(ty).pack() } } impl<'tcx> From> for Term<'tcx> { fn from(c: Const<'tcx>) -> Self { - Term::Const(c) + TermKind::Const(c).pack() + } +} + +impl<'a, 'tcx> HashStable> for Term<'tcx> { + fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { + self.unpack().hash_stable(hcx, hasher); + } +} + +impl<'tcx> TypeFoldable<'tcx> for Term<'tcx> { + fn try_fold_with>(self, folder: &mut F) -> Result { + Ok(self.unpack().try_fold_with(folder)?.pack()) + } +} + +impl<'tcx> TypeVisitable<'tcx> for Term<'tcx> { + fn visit_with>(&self, visitor: &mut V) -> ControlFlow { + self.unpack().visit_with(visitor) + } +} + +impl<'tcx, E: TyEncoder>> Encodable for Term<'tcx> { + fn encode(&self, e: &mut E) { + self.unpack().encode(e) + } +} + +impl<'tcx, D: TyDecoder>> Decodable for Term<'tcx> { + fn decode(d: &mut D) -> Self { + let res: TermKind<'tcx> = Decodable::decode(d); + res.pack() } } impl<'tcx> Term<'tcx> { + #[inline] + pub fn unpack(self) -> TermKind<'tcx> { + let ptr = self.ptr.get(); + // SAFETY: use of `Interned::new_unchecked` here is ok because these + // pointers were originally created from `Interned` types in `pack()`, + // and this is just going in the other direction. + unsafe { + match ptr & TAG_MASK { + TYPE_TAG => TermKind::Ty(Ty(Interned::new_unchecked( + &*((ptr & !TAG_MASK) as *const WithStableHash>), + ))), + CONST_TAG => TermKind::Const(ty::Const(Interned::new_unchecked( + &*((ptr & !TAG_MASK) as *const ty::ConstS<'tcx>), + ))), + _ => core::intrinsics::unreachable(), + } + } + } + pub fn ty(&self) -> Option> { - if let Term::Ty(ty) = self { Some(*ty) } else { None } + if let TermKind::Ty(ty) = self.unpack() { Some(ty) } else { None } } pub fn ct(&self) -> Option> { - if let Term::Const(c) = self { Some(*c) } else { None } + if let TermKind::Const(c) = self.unpack() { Some(c) } else { None } } pub fn into_arg(self) -> GenericArg<'tcx> { - match self { - Term::Ty(ty) => ty.into(), - Term::Const(c) => c.into(), + match self.unpack() { + TermKind::Ty(ty) => ty.into(), + TermKind::Const(c) => c.into(), } } } +const TAG_MASK: usize = 0b11; +const TYPE_TAG: usize = 0b00; +const CONST_TAG: usize = 0b01; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)] +#[derive(HashStable, TypeFoldable, TypeVisitable)] +pub enum TermKind<'tcx> { + Ty(Ty<'tcx>), + Const(Const<'tcx>), +} + +impl<'tcx> TermKind<'tcx> { + #[inline] + fn pack(self) -> Term<'tcx> { + let (tag, ptr) = match self { + TermKind::Ty(ty) => { + // Ensure we can use the tag bits. + assert_eq!(mem::align_of_val(&*ty.0.0) & TAG_MASK, 0); + (TYPE_TAG, ty.0.0 as *const WithStableHash> as usize) + } + TermKind::Const(ct) => { + // Ensure we can use the tag bits. + assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0); + (CONST_TAG, ct.0.0 as *const ty::ConstS<'tcx> as usize) + } + }; + + Term { ptr: unsafe { NonZeroUsize::new_unchecked(ptr | tag) }, marker: PhantomData } + } +} + /// This kind of predicate has no *direct* correspondent in the /// syntax, but it roughly corresponds to the syntactic forms: /// @@ -2528,7 +2612,7 @@ mod size_asserts { use super::*; use rustc_data_structures::static_assert_size; // These are in alphabetical order, which is easy to maintain. - static_assert_size!(PredicateS<'_>, 56); + static_assert_size!(PredicateS<'_>, 48); static_assert_size!(TyS<'_>, 40); static_assert_size!(WithStableHash>, 56); } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 329478f27b73..1ae3063dae4e 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1,7 +1,7 @@ use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar}; use crate::ty::subst::{GenericArg, GenericArgKind, Subst}; use crate::ty::{ - self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, Ty, TyCtxt, TypeFoldable, + self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, TermKind, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, }; use rustc_apfloat::ieee::{Double, Single}; @@ -855,7 +855,7 @@ pub trait PrettyPrinter<'tcx>: } p!(")"); - if let Term::Ty(ty) = return_ty.skip_binder() { + if let Some(ty) = return_ty.skip_binder().ty() { if !ty.is_unit() { p!(" -> ", print(return_ty)); } @@ -942,13 +942,9 @@ pub trait PrettyPrinter<'tcx>: p!(write("{} = ", tcx.associated_item(assoc_item_def_id).name)); - match term { - Term::Ty(ty) => { - p!(print(ty)) - } - Term::Const(c) => { - p!(print(c)); - } + match term.unpack() { + TermKind::Ty(ty) => p!(print(ty)), + TermKind::Const(c) => p!(print(c)), }; } @@ -2608,9 +2604,9 @@ define_print_and_forward_display! { } ty::Term<'tcx> { - match self { - ty::Term::Ty(ty) => p!(print(ty)), - ty::Term::Const(c) => p!(print(c)), + match self.unpack() { + ty::TermKind::Ty(ty) => p!(print(ty)), + ty::TermKind::Const(c) => p!(print(c)), } } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 818affa7113a..109a4df83b02 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -6,7 +6,7 @@ use crate::ty::error::{ExpectedFound, TypeError}; use crate::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef}; -use crate::ty::{self, ImplSubject, Term, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, ImplSubject, Term, TermKind, Ty, TyCtxt, TypeFoldable}; use rustc_hir as ast; use rustc_hir::def_id::DefId; use rustc_span::DUMMY_SP; @@ -803,15 +803,15 @@ impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> { } } -impl<'tcx> Relate<'tcx> for ty::Term<'tcx> { +impl<'tcx> Relate<'tcx> for Term<'tcx> { fn relate>( relation: &mut R, a: Self, b: Self, ) -> RelateResult<'tcx, Self> { - Ok(match (a, b) { - (Term::Ty(a), Term::Ty(b)) => relation.relate(a, b)?.into(), - (Term::Const(a), Term::Const(b)) => relation.relate(a, b)?.into(), + Ok(match (a.unpack(), b.unpack()) { + (TermKind::Ty(a), TermKind::Ty(b)) => relation.relate(a, b)?.into(), + (TermKind::Const(a), TermKind::Const(b)) => relation.relate(a, b)?.into(), _ => return Err(TypeError::Mismatch), }) } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 57555433f55b..e6bd2eed565a 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -7,7 +7,7 @@ use crate::mir::ProjectionKind; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer}; use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; -use crate::ty::{self, InferConst, Lift, Term, Ty, TyCtxt}; +use crate::ty::{self, InferConst, Lift, Term, TermKind, Ty, TyCtxt}; use rustc_data_structures::functor::IdFunctor; use rustc_hir as hir; use rustc_hir::def::Namespace; @@ -344,10 +344,13 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialPredicate<'a> { impl<'a, 'tcx> Lift<'tcx> for Term<'a> { type Lifted = ty::Term<'tcx>; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { - Some(match self { - Term::Ty(ty) => Term::Ty(tcx.lift(ty)?), - Term::Const(c) => Term::Const(tcx.lift(c)?), - }) + Some( + match self.unpack() { + TermKind::Ty(ty) => TermKind::Ty(tcx.lift(ty)?), + TermKind::Const(c) => TermKind::Const(tcx.lift(c)?), + } + .pack(), + ) } } diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index 02fe1f3a7bde..831724bc4b09 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -165,9 +165,9 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) } }; - substs.iter().rev().chain(opt_ty.map(|term| match term { - ty::Term::Ty(ty) => ty.into(), - ty::Term::Const(ct) => ct.into(), + substs.iter().rev().chain(opt_ty.map(|term| match term.unpack() { + ty::TermKind::Ty(ty) => ty.into(), + ty::TermKind::Const(ct) => ct.into(), })) })); } diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index cb61f76af1d7..b1de979e8f8e 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -13,7 +13,7 @@ use rustc_hir as hir; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use rustc_middle::ty::{ self, Binder, Const, ExistentialPredicate, FloatTy, FnSig, IntTy, List, Region, RegionKind, - Term, Ty, TyCtxt, UintTy, + TermKind, Ty, TyCtxt, UintTy, }; use rustc_span::def_id::DefId; use rustc_span::symbol::sym; @@ -243,13 +243,9 @@ fn encode_predicate<'tcx>( let name = encode_ty_name(tcx, projection.item_def_id); let _ = write!(s, "u{}{}", name.len(), &name); s.push_str(&encode_substs(tcx, projection.substs, dict, options)); - match projection.term { - Term::Ty(ty) => { - s.push_str(&encode_ty(tcx, ty, dict, options)); - } - Term::Const(c) => { - s.push_str(&encode_const(tcx, c, dict, options)); - } + match projection.term.unpack() { + TermKind::Ty(ty) => s.push_str(&encode_ty(tcx, ty, dict, options)), + TermKind::Const(c) => s.push_str(&encode_const(tcx, c, dict, options)), } } ty::ExistentialPredicate::AutoTrait(def_id) => { diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 71fa5a448870..cfb8d47e5453 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -543,9 +543,9 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> { let name = cx.tcx.associated_item(projection.item_def_id).name; cx.push("p"); cx.push_ident(name.as_str()); - cx = match projection.term { - ty::Term::Ty(ty) => ty.print(cx), - ty::Term::Const(c) => c.print(cx), + cx = match projection.term.unpack() { + ty::TermKind::Ty(ty) => ty.print(cx), + ty::TermKind::Const(c) => c.print(cx), }?; } ty::ExistentialPredicate::AutoTrait(def_id) => { diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 1223c7ced7ab..98e93ad3fc50 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -10,7 +10,7 @@ use crate::traits::project::ProjectAndUnifyResult; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::visit::TypeVisitable; -use rustc_middle::ty::{Region, RegionVid, Term}; +use rustc_middle::ty::{Region, RegionVid}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -612,7 +612,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { } fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool { - if let Term::Ty(ty) = p.term().skip_binder() { + if let Some(ty) = p.term().skip_binder().ty() { matches!(ty.kind(), ty::Projection(proj) if proj == &p.skip_binder().projection_ty) } else { false diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 398635674abc..76c1ade0680c 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -552,7 +552,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { ) .ok() .flatten() - .unwrap_or_else(|| ty::Term::Ty(ty.super_fold_with(self))) + .unwrap_or_else(|| ty.super_fold_with(self).into()) }; // For cases like #95134 we would like to catch overflows early // otherwise they slip away away and cause ICE. diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index bb6009cb22a3..018ead2e1302 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -129,9 +129,9 @@ pub fn predicate_obligations<'a, 'tcx>( } ty::PredicateKind::Projection(t) => { wf.compute_projection(t.projection_ty); - wf.compute(match t.term { - ty::Term::Ty(ty) => ty.into(), - ty::Term::Const(c) => c.into(), + wf.compute(match t.term.unpack() { + ty::TermKind::Ty(ty) => ty.into(), + ty::TermKind::Const(c) => c.into(), }) } ty::PredicateKind::WellFormed(arg) => { diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index ef927058df4e..c61032787e06 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -1183,11 +1183,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // `::Item = u32` let assoc_item_def_id = projection_ty.skip_binder().item_def_id; let def_kind = tcx.def_kind(assoc_item_def_id); - match (def_kind, term) { - (hir::def::DefKind::AssocTy, ty::Term::Ty(_)) - | (hir::def::DefKind::AssocConst, ty::Term::Const(_)) => (), + match (def_kind, term.unpack()) { + (hir::def::DefKind::AssocTy, ty::TermKind::Ty(_)) + | (hir::def::DefKind::AssocConst, ty::TermKind::Const(_)) => (), (_, _) => { - let got = if let ty::Term::Ty(_) = term { "type" } else { "constant" }; + let got = if let Some(_) = term.ty() { "type" } else { "constant" }; let expected = def_kind.descr(assoc_item_def_id); tcx.sess .struct_span_err( @@ -1375,9 +1375,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let pred = bound_predicate.rebind(pred); // A `Self` within the original bound will be substituted with a // `trait_object_dummy_self`, so check for that. - let references_self = match pred.skip_binder().term { - ty::Term::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()), - ty::Term::Const(c) => c.ty().walk().any(|arg| arg == dummy_self.into()), + let references_self = match pred.skip_binder().term.unpack() { + ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()), + ty::TermKind::Const(c) => { + c.ty().walk().any(|arg| arg == dummy_self.into()) + } }; // If the projection output contains `Self`, force the user to diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs index a9071cd1fd94..c597efbe7468 100644 --- a/compiler/rustc_typeck/src/check/method/mod.rs +++ b/compiler/rustc_typeck/src/check/method/mod.rs @@ -21,7 +21,7 @@ use rustc_infer::infer::{self, InferOk}; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; use rustc_middle::ty::{ - self, AssocKind, DefIdTree, GenericParamDefKind, ProjectionPredicate, ProjectionTy, Term, + self, AssocKind, DefIdTree, GenericParamDefKind, ProjectionPredicate, ProjectionTy, ToPredicate, Ty, TypeVisitable, }; use rustc_span::symbol::Ident; @@ -349,7 +349,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { opt_output_ty.zip(opt_output_assoc_item).map(|(output_ty, output_assoc_item)| { ty::Binder::dummy(ty::PredicateKind::Projection(ProjectionPredicate { projection_ty: ProjectionTy { substs, item_def_id: output_assoc_item.def_id }, - term: Term::Ty(output_ty), + term: output_ty.into(), })) .to_predicate(self.tcx) }); diff --git a/compiler/rustc_typeck/src/variance/constraints.rs b/compiler/rustc_typeck/src/variance/constraints.rs index d79450e1ae70..4fe213ffeea3 100644 --- a/compiler/rustc_typeck/src/variance/constraints.rs +++ b/compiler/rustc_typeck/src/variance/constraints.rs @@ -271,11 +271,11 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } for projection in data.projection_bounds() { - match projection.skip_binder().term { - ty::Term::Ty(ty) => { + match projection.skip_binder().term.unpack() { + ty::TermKind::Ty(ty) => { self.add_constraints_from_ty(current, ty, self.invariant); } - ty::Term::Const(c) => { + ty::TermKind::Const(c) => { self.add_constraints_from_const(current, c, self.invariant) } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index ebf6c55ee35d..bc6af88ba30b 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -370,9 +370,9 @@ fn clean_type_outlives_predicate<'tcx>( } fn clean_middle_term<'tcx>(term: ty::Term<'tcx>, cx: &mut DocContext<'tcx>) -> Term { - match term { - ty::Term::Ty(ty) => Term::Type(clean_middle_ty(ty, cx, None)), - ty::Term::Const(c) => Term::Constant(clean_middle_const(c, cx)), + match term.unpack() { + ty::TermKind::Ty(ty) => Term::Type(clean_middle_ty(ty, cx, None)), + ty::TermKind::Const(c) => Term::Constant(clean_middle_const(c, cx)), } } diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 1506ea604f0d..7e29257e36a3 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -1174,7 +1174,7 @@ fn replace_types<'tcx>( if replaced.insert(param_ty.index) { for projection_predicate in projection_predicates { if projection_predicate.projection_ty.self_ty() == param_ty.to_ty(cx.tcx) - && let ty::Term::Ty(term_ty) = projection_predicate.term + && let Some(term_ty) = projection_predicate.term.ty() && let ty::Param(term_param_ty) = term_ty.kind() { let item_def_id = projection_predicate.projection_ty.item_def_id; diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index a0d190a58aff..46ffe59b2d14 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -3302,9 +3302,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods { // one of the associated types must be Self for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) { if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() { - let assoc_ty = match projection_predicate.term { - ty::Term::Ty(ty) => ty, - ty::Term::Const(_c) => continue, + let assoc_ty = match projection_predicate.term.unpack() { + ty::TermKind::Ty(ty) => ty, + ty::TermKind::Const(_c) => continue, }; // walk the associated type and check for Self if let Some(self_adt) = self_ty.ty_adt_def() { diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index 44bf84352943..2dcb191555a4 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -268,7 +268,7 @@ fn check_other_call_arg<'tcx>( .subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.term); implements_trait(cx, receiver_ty, deref_trait_id, &[]) && get_associated_type(cx, receiver_ty, deref_trait_id, "Target") - .map_or(false, |ty| ty::Term::Ty(ty) == normalized_ty) + .map_or(false, |ty| ty::TermKind::Ty(ty) == normalized_ty.unpack()) } else { false } From 2d4349c22d855f4735f89d5fcfc397ecb11f5b9c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 5 Sep 2022 14:03:53 +1000 Subject: [PATCH 4195/5092] Pack `Term` in the same way as `GenericArg`. This shrinks the `PredicateS` type, which is instanted frequently. --- clippy_lints/src/dereference.rs | 2 +- clippy_lints/src/methods/mod.rs | 6 +++--- clippy_lints/src/methods/unnecessary_to_owned.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 1506ea604f0d..7e29257e36a3 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -1174,7 +1174,7 @@ fn replace_types<'tcx>( if replaced.insert(param_ty.index) { for projection_predicate in projection_predicates { if projection_predicate.projection_ty.self_ty() == param_ty.to_ty(cx.tcx) - && let ty::Term::Ty(term_ty) = projection_predicate.term + && let Some(term_ty) = projection_predicate.term.ty() && let ty::Param(term_param_ty) = term_ty.kind() { let item_def_id = projection_predicate.projection_ty.item_def_id; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a0d190a58aff..46ffe59b2d14 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3302,9 +3302,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods { // one of the associated types must be Self for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) { if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() { - let assoc_ty = match projection_predicate.term { - ty::Term::Ty(ty) => ty, - ty::Term::Const(_c) => continue, + let assoc_ty = match projection_predicate.term.unpack() { + ty::TermKind::Ty(ty) => ty, + ty::TermKind::Const(_c) => continue, }; // walk the associated type and check for Self if let Some(self_adt) = self_ty.ty_adt_def() { diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 44bf84352943..2dcb191555a4 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -268,7 +268,7 @@ fn check_other_call_arg<'tcx>( .subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.term); implements_trait(cx, receiver_ty, deref_trait_id, &[]) && get_associated_type(cx, receiver_ty, deref_trait_id, "Target") - .map_or(false, |ty| ty::Term::Ty(ty) == normalized_ty) + .map_or(false, |ty| ty::TermKind::Ty(ty) == normalized_ty.unpack()) } else { false } From 321e60bf3429d32c5ab1d03f22e3e4654bc0c388 Mon Sep 17 00:00:00 2001 From: Jhonny Bill Mena Date: Mon, 5 Sep 2022 00:15:50 -0400 Subject: [PATCH 4196/5092] UPDATE - into_diagnostic to take a Handler instead of a ParseSess Suggested by the team in this Zulip Topic https://rust-lang.zulipchat.com/#narrow/stream/336883-i18n/topic/.23100717.20SessionDiagnostic.20on.20Handler Handler already has almost all the capabilities of ParseSess when it comes to diagnostic emission, in this migration we only needed to add the ability to access source_map from the emitter in order to get a Snippet and the start_point. Not sure if this is the best way to address this gap --- .../rustc_attr/src/session_diagnostics.rs | 18 +++++++++------ compiler/rustc_errors/src/lib.rs | 22 +++++++++++++++++++ .../infer/error_reporting/need_type_info.rs | 14 ++++++------ compiler/rustc_lint/src/errors.rs | 8 +++---- .../src/diagnostics/diagnostic.rs | 2 +- compiler/rustc_metadata/src/errors.rs | 12 +++++----- compiler/rustc_monomorphize/src/errors.rs | 5 +++-- compiler/rustc_parse/src/parser/expr.rs | 5 +++-- compiler/rustc_query_system/src/query/job.rs | 2 +- compiler/rustc_session/src/parse.rs | 6 ++--- compiler/rustc_session/src/session.rs | 6 ++--- compiler/rustc_trait_selection/src/errors.rs | 8 +++---- compiler/rustc_typeck/src/errors.rs | 12 +++++----- .../ui-fulldeps/internal-lints/diagnostics.rs | 22 +++++++++---------- 14 files changed, 85 insertions(+), 57 deletions(-) diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs index 25cd960dbf1d..f74540e9655b 100644 --- a/compiler/rustc_attr/src/session_diagnostics.rs +++ b/compiler/rustc_attr/src/session_diagnostics.rs @@ -1,9 +1,11 @@ use std::num::IntErrorKind; use rustc_ast as ast; -use rustc_errors::{error_code, fluent, Applicability, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{ + error_code, fluent, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler, +}; use rustc_macros::SessionDiagnostic; -use rustc_session::{parse::ParseSess, SessionDiagnostic}; +use rustc_session::SessionDiagnostic; use rustc_span::{Span, Symbol}; use crate::UnsupportedLiteralReason; @@ -49,9 +51,9 @@ pub(crate) struct UnknownMetaItem<'a> { // Manual implementation to be able to format `expected` items correctly. impl<'a> SessionDiagnostic<'a> for UnknownMetaItem<'_> { - fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> { let expected = self.expected.iter().map(|name| format!("`{}`", name)).collect::>(); - let mut diag = sess.span_diagnostic.struct_span_err_with_code( + let mut diag = handler.struct_span_err_with_code( self.span, fluent::attr::unknown_meta_item, error_code!(E0541), @@ -207,8 +209,8 @@ pub(crate) struct UnsupportedLiteral { } impl<'a> SessionDiagnostic<'a> for UnsupportedLiteral { - fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - let mut diag = sess.span_diagnostic.struct_span_err_with_code( + fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + let mut diag = handler.struct_span_err_with_code( self.span, match self.reason { UnsupportedLiteralReason::Generic => fluent::attr::unsupported_literal_generic, @@ -223,8 +225,10 @@ impl<'a> SessionDiagnostic<'a> for UnsupportedLiteral { error_code!(E0565), ); if self.is_bytestr { + let start_point = handler.span_start_point_from_emitter(self.span).unwrap_or(self.span); + diag.span_suggestion( - sess.source_map().start_point(self.span), + start_point, fluent::attr::unsupported_literal_suggestion, "", Applicability::MaybeIncorrect, diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 68abdd0bad1f..af554db30137 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1098,6 +1098,28 @@ impl Handler { ); std::mem::take(&mut self.inner.borrow_mut().fulfilled_expectations) } + + pub fn span_to_snippet_from_emitter( + &self, + span: rustc_span::Span, + ) -> Option> { + self.inner + .borrow() + .emitter + .source_map() + .map_or_else(|| Option::None, |sm| Some(sm.span_to_snippet(span))) + } + + pub fn span_start_point_from_emitter( + &self, + span: rustc_span::Span, + ) -> Option { + self.inner + .borrow() + .emitter + .source_map() + .map_or_else(|| Option::None, |sm| Some(sm.start_point(span))) + } } impl HandlerInner { diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 91a05367eee0..44c8084d732d 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -341,7 +341,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { multi_suggestions, bad_label, } - .into_diagnostic(&self.tcx.sess.parse_sess), + .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic), TypeAnnotationNeeded::E0283 => AmbigousImpl { span, source_kind, @@ -351,7 +351,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { multi_suggestions, bad_label, } - .into_diagnostic(&self.tcx.sess.parse_sess), + .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic), TypeAnnotationNeeded::E0284 => AmbigousReturn { span, source_kind, @@ -361,7 +361,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { multi_suggestions, bad_label, } - .into_diagnostic(&self.tcx.sess.parse_sess), + .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic), } } @@ -537,7 +537,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { multi_suggestions, bad_label: None, } - .into_diagnostic(&self.tcx.sess.parse_sess), + .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic), TypeAnnotationNeeded::E0283 => AmbigousImpl { span, source_kind, @@ -547,7 +547,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { multi_suggestions, bad_label: None, } - .into_diagnostic(&self.tcx.sess.parse_sess), + .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic), TypeAnnotationNeeded::E0284 => AmbigousReturn { span, source_kind, @@ -557,7 +557,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { multi_suggestions, bad_label: None, } - .into_diagnostic(&self.tcx.sess.parse_sess), + .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic), } } @@ -575,7 +575,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { span, generator_kind: GeneratorKindAsDiagArg(kind), } - .into_diagnostic(&self.tcx.sess.parse_sess) + .into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic) } } diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs index 606d8bda8aaf..5c183d4091ea 100644 --- a/compiler/rustc_lint/src/errors.rs +++ b/compiler/rustc_lint/src/errors.rs @@ -1,6 +1,6 @@ -use rustc_errors::{fluent, AddSubdiagnostic, ErrorGuaranteed}; +use rustc_errors::{fluent, AddSubdiagnostic, ErrorGuaranteed, Handler}; use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; -use rustc_session::{lint::Level, parse::ParseSess, SessionDiagnostic}; +use rustc_session::{lint::Level, SessionDiagnostic}; use rustc_span::{Span, Symbol}; #[derive(SessionDiagnostic)] @@ -122,9 +122,9 @@ pub struct CheckNameUnknown { impl SessionDiagnostic<'_> for CheckNameUnknown { fn into_diagnostic( self, - sess: &ParseSess, + handler: &Handler, ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = sess.struct_err(fluent::lint::check_name_unknown); + let mut diag = handler.struct_err(fluent::lint::check_name_unknown); diag.code(rustc_errors::error_code!(E0602)); if let Some(suggestion) = self.suggestion { diag.help(fluent::lint::help); diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index 244edec28415..cf1c59455291 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -88,7 +88,7 @@ impl<'a> SessionDiagnosticDerive<'a> { { fn into_diagnostic( self, - #sess: &'__session_diagnostic_sess rustc_session::parse::ParseSess + #sess: &'__session_diagnostic_sess rustc_errors::Handler ) -> rustc_errors::DiagnosticBuilder<'__session_diagnostic_sess, G> { use rustc_errors::IntoDiagnosticArg; #implementation diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index 18d0248333a5..8378d2b791d0 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -424,9 +424,9 @@ pub(crate) struct MultipleCandidates { impl SessionDiagnostic<'_> for MultipleCandidates { fn into_diagnostic( self, - sess: &'_ rustc_session::parse::ParseSess, + handler: &'_ rustc_errors::Handler, ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = sess.struct_err(rustc_errors::fluent::metadata::multiple_candidates); + let mut diag = handler.struct_err(rustc_errors::fluent::metadata::multiple_candidates); diag.set_arg("crate_name", self.crate_name); diag.set_arg("flavor", self.flavor); diag.code(error_code!(E0465)); @@ -540,9 +540,9 @@ pub struct InvalidMetadataFiles { impl SessionDiagnostic<'_> for InvalidMetadataFiles { fn into_diagnostic( self, - sess: &'_ rustc_session::parse::ParseSess, + handler: &'_ rustc_errors::Handler, ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = sess.struct_err(rustc_errors::fluent::metadata::invalid_meta_files); + let mut diag = handler.struct_err(rustc_errors::fluent::metadata::invalid_meta_files); diag.set_arg("crate_name", self.crate_name); diag.set_arg("add_info", self.add_info); diag.code(error_code!(E0786)); @@ -568,9 +568,9 @@ pub struct CannotFindCrate { impl SessionDiagnostic<'_> for CannotFindCrate { fn into_diagnostic( self, - sess: &'_ rustc_session::parse::ParseSess, + handler: &'_ rustc_errors::Handler, ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = sess.struct_err(rustc_errors::fluent::metadata::cannot_find_crate); + let mut diag = handler.struct_err(rustc_errors::fluent::metadata::cannot_find_crate); diag.set_arg("crate_name", self.crate_name); diag.set_arg("add_info", self.add_info); diag.set_arg("locator_triple", self.locator_triple.triple()); diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index 77b6cfa1f69f..d5f05e790d38 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -47,9 +47,10 @@ pub struct UnusedGenericParams { impl SessionDiagnostic<'_> for UnusedGenericParams { fn into_diagnostic( self, - sess: &'_ rustc_session::parse::ParseSess, + handler: &'_ rustc_errors::Handler, ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = sess.struct_err(rustc_errors::fluent::monomorphize::unused_generic_params); + let mut diag = + handler.struct_err(rustc_errors::fluent::monomorphize::unused_generic_params); diag.set_span(self.span); for (span, name) in self.param_spans.into_iter().zip(self.param_names) { // FIXME: I can figure out how to do a label with a fluent string with a fixed message, diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index d4828a201207..7addf519872f 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1997,7 +1997,7 @@ impl<'a> Parser<'a> { return Err(MissingSemicolonBeforeArray { open_delim: open_delim_span, semicolon: prev_span.shrink_to_hi(), - }.into_diagnostic(self.sess)); + }.into_diagnostic(&self.sess.span_diagnostic)); } Ok(_) => (), Err(err) => err.cancel(), @@ -2745,7 +2745,8 @@ impl<'a> Parser<'a> { fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, P> { let (attrs, body) = self.parse_inner_attrs_and_block()?; if self.eat_keyword(kw::Catch) { - Err(CatchAfterTry { span: self.prev_token.span }.into_diagnostic(self.sess)) + Err(CatchAfterTry { span: self.prev_token.span } + .into_diagnostic(&self.sess.span_diagnostic)) } else { let span = span_lo.to(body.span); self.sess.gated_spans.gate(sym::try_blocks, span); diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index ddb5cd063440..45b4079fb54f 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -572,7 +572,7 @@ pub(crate) fn report_cycle<'a>( stack_count, }; - cycle_diag.into_diagnostic(&sess.parse_sess) + cycle_diag.into_diagnostic(&sess.parse_sess.span_diagnostic) } pub fn print_query_stack( diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 5b95d73bd4d3..9bc7fbfbe149 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -343,7 +343,7 @@ impl ParseSess { &'a self, err: impl SessionDiagnostic<'a>, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - err.into_diagnostic(self) + err.into_diagnostic(&self.span_diagnostic) } pub fn emit_err<'a>(&'a self, err: impl SessionDiagnostic<'a>) -> ErrorGuaranteed { @@ -354,7 +354,7 @@ impl ParseSess { &'a self, warning: impl SessionDiagnostic<'a, ()>, ) -> DiagnosticBuilder<'a, ()> { - warning.into_diagnostic(self) + warning.into_diagnostic(&self.span_diagnostic) } pub fn emit_warning<'a>(&'a self, warning: impl SessionDiagnostic<'a, ()>) { @@ -365,7 +365,7 @@ impl ParseSess { &'a self, fatal: impl SessionDiagnostic<'a, !>, ) -> DiagnosticBuilder<'a, !> { - fatal.into_diagnostic(self) + fatal.into_diagnostic(&self.span_diagnostic) } pub fn emit_fatal<'a>(&'a self, fatal: impl SessionDiagnostic<'a, !>) -> ! { diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index a49af23be231..557edad548c6 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -21,7 +21,7 @@ use rustc_errors::json::JsonEmitter; use rustc_errors::registry::Registry; use rustc_errors::{ error_code, fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, - EmissionGuarantee, ErrorGuaranteed, FluentBundle, LazyFallbackBundle, MultiSpan, + EmissionGuarantee, ErrorGuaranteed, FluentBundle, Handler, LazyFallbackBundle, MultiSpan, }; use rustc_macros::HashStable_Generic; pub use rustc_span::def_id::StableCrateId; @@ -220,9 +220,9 @@ pub struct PerfStats { /// `#[derive(SessionDiagnostic)]` -- see [rustc_macros::SessionDiagnostic]. #[rustc_diagnostic_item = "SessionDiagnostic"] pub trait SessionDiagnostic<'a, T: EmissionGuarantee = ErrorGuaranteed> { - /// Write out as a diagnostic out of `sess`. + /// Write out as a diagnostic out of `Handler`. #[must_use] - fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, T>; + fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, T>; } impl Session { diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 81977f25ca21..ab0afc545146 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -1,7 +1,7 @@ -use rustc_errors::{fluent, ErrorGuaranteed}; +use rustc_errors::{fluent, ErrorGuaranteed, Handler}; use rustc_macros::SessionDiagnostic; use rustc_middle::ty::{PolyTraitRef, Ty, Unevaluated}; -use rustc_session::{parse::ParseSess, Limit, SessionDiagnostic}; +use rustc_session::{Limit, SessionDiagnostic}; use rustc_span::{Span, Symbol}; #[derive(SessionDiagnostic)] @@ -69,9 +69,9 @@ pub struct NegativePositiveConflict<'a> { impl SessionDiagnostic<'_> for NegativePositiveConflict<'_> { fn into_diagnostic( self, - sess: &ParseSess, + handler: &Handler, ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = sess.struct_err(fluent::trait_selection::negative_positive_conflict); + let mut diag = handler.struct_err(fluent::trait_selection::negative_positive_conflict); diag.set_arg("trait_desc", self.trait_desc); diag.set_arg( "self_desc", diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs index 14c0558cdde9..bfe03d625751 100644 --- a/compiler/rustc_typeck/src/errors.rs +++ b/compiler/rustc_typeck/src/errors.rs @@ -1,8 +1,8 @@ //! Errors emitted by typeck. -use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler}; use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic}; use rustc_middle::ty::Ty; -use rustc_session::{parse::ParseSess, SessionDiagnostic}; +use rustc_session::SessionDiagnostic; use rustc_span::{symbol::Ident, Span, Symbol}; #[derive(SessionDiagnostic)] @@ -250,8 +250,8 @@ pub struct MissingTypeParams { // Manual implementation of `SessionDiagnostic` to be able to call `span_to_snippet`. impl<'a> SessionDiagnostic<'a> for MissingTypeParams { - fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - let mut err = sess.span_diagnostic.struct_span_err_with_code( + fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + let mut err = handler.struct_span_err_with_code( self.span, rustc_errors::fluent::typeck::missing_type_params, error_code!(E0393), @@ -269,8 +269,8 @@ impl<'a> SessionDiagnostic<'a> for MissingTypeParams { err.span_label(self.def_span, rustc_errors::fluent::typeck::label); let mut suggested = false; - if let (Ok(snippet), true) = ( - sess.source_map().span_to_snippet(self.span), + if let (Some(Ok(snippet)), true) = ( + handler.span_to_snippet_from_emitter(self.span), // Don't suggest setting the type params if there are some already: the order is // tricky to get right and the user will already know what the syntax is. self.empty_generic_args, diff --git a/src/test/ui-fulldeps/internal-lints/diagnostics.rs b/src/test/ui-fulldeps/internal-lints/diagnostics.rs index 0e449256153a..89997585db25 100644 --- a/src/test/ui-fulldeps/internal-lints/diagnostics.rs +++ b/src/test/ui-fulldeps/internal-lints/diagnostics.rs @@ -11,9 +11,9 @@ extern crate rustc_macros; extern crate rustc_session; extern crate rustc_span; -use rustc_errors::{AddSubdiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, fluent}; +use rustc_errors::{AddSubdiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, Handler, fluent}; use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; -use rustc_session::{parse::ParseSess, SessionDiagnostic}; +use rustc_session::SessionDiagnostic; use rustc_span::Span; #[derive(SessionDiagnostic)] @@ -33,8 +33,8 @@ struct Note { pub struct UntranslatableInSessionDiagnostic; impl<'a> SessionDiagnostic<'a, ErrorGuaranteed> for UntranslatableInSessionDiagnostic { - fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - sess.struct_err("untranslatable diagnostic") + fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + handler.struct_err("untranslatable diagnostic") //~^ ERROR diagnostics should be created using translatable messages } } @@ -42,8 +42,8 @@ impl<'a> SessionDiagnostic<'a, ErrorGuaranteed> for UntranslatableInSessionDiagn pub struct TranslatableInSessionDiagnostic; impl<'a> SessionDiagnostic<'a, ErrorGuaranteed> for TranslatableInSessionDiagnostic { - fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - sess.struct_err(fluent::parser::expect_path) + fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + handler.struct_err(fluent::parser::expect_path) } } @@ -64,11 +64,11 @@ impl AddSubdiagnostic for TranslatableInAddSubdiagnostic { } } -pub fn make_diagnostics<'a>(sess: &'a ParseSess) { - let _diag = sess.struct_err(fluent::parser::expect_path); +pub fn make_diagnostics<'a>(handler: &'a Handler) { + let _diag = handler.struct_err(fluent::parser::expect_path); //~^ ERROR diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls - let _diag = sess.struct_err("untranslatable diagnostic"); + let _diag = handler.struct_err("untranslatable diagnostic"); //~^ ERROR diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls //~^^ ERROR diagnostics should be created using translatable messages } @@ -76,6 +76,6 @@ pub fn make_diagnostics<'a>(sess: &'a ParseSess) { // Check that `rustc_lint_diagnostics`-annotated functions aren't themselves linted. #[rustc_lint_diagnostics] -pub fn skipped_because_of_annotation<'a>(sess: &'a ParseSess) { - let _diag = sess.struct_err("untranslatable diagnostic"); // okay! +pub fn skipped_because_of_annotation<'a>(handler: &'a Handler) { + let _diag = handler.struct_err("untranslatable diagnostic"); // okay! } From 46130a1d182c23dc967b6fc211019ce882f312b4 Mon Sep 17 00:00:00 2001 From: Jakob Degen Date: Sun, 4 Sep 2022 22:35:47 -0700 Subject: [PATCH 4197/5092] Remove unnecessary `EMIT_MIR_FOR_EACH_BITWIDTH --- src/test/mir-opt/array-index-is-temporary.rs | 2 +- ...implifyCfg-elaborate-drops.after.64bit.mir | 64 ------- ...ain.SimplifyCfg-elaborate-drops.after.mir} | 0 .../mir-opt/inline/inline-into-box-place.rs | 2 +- ...line_into_box_place.main.Inline.64bit.diff | 82 --------- ...=> inline_into_box_place.main.Inline.diff} | 0 src/test/mir-opt/issue-41697.rs | 2 +- src/test/mir-opt/issue-72181.rs | 4 +- src/test/mir-opt/issue-73223.rs | 2 +- ...SimplifyCfg-promote-consts.after.64bit.mir | 20 --- ...t#0}.SimplifyCfg-promote-consts.after.mir} | 0 .../issue_72181.bar.mir_map.0.64bit.mir | 17 -- ...2bit.mir => issue_72181.bar.mir_map.0.mir} | 0 .../issue_72181.foo.mir_map.0.64bit.mir | 27 --- ...2bit.mir => issue_72181.foo.mir_map.0.mir} | 0 .../issue_72181.main.mir_map.0.64bit.mir | 62 ------- ...bit.mir => issue_72181.main.mir_map.0.mir} | 0 ..._73223.main.SimplifyArmIdentity.64bit.diff | 161 ------------------ ...issue_73223.main.SimplifyArmIdentity.diff} | 0 ...s.bar.MatchBranchSimplification.64bit.diff | 88 ---------- ...anches.bar.MatchBranchSimplification.diff} | 0 ...s.foo.MatchBranchSimplification.64bit.diff | 55 ------ ...anches.foo.MatchBranchSimplification.diff} | 0 ...ed_if.MatchBranchSimplification.64bit.diff | 113 ------------ ..._nested_if.MatchBranchSimplification.diff} | 0 src/test/mir-opt/matches_reduce_branches.rs | 2 +- ...match.MatchBranchSimplification.64bit.diff | 32 ---- ...tive_match.MatchBranchSimplification.diff} | 0 ...ch_i8.MatchBranchSimplification.64bit.diff | 32 ---- ...e_match_i8.MatchBranchSimplification.diff} | 0 src/test/mir-opt/matches_u8.rs | 2 +- .../mir-opt/packed-struct-drop-aligned.rs | 2 +- ...implifyCfg-elaborate-drops.after.64bit.mir | 60 ------- ...ain.SimplifyCfg-elaborate-drops.after.mir} | 0 ...arate_const_switch.identity.ConstProp.diff | 146 ---------------- ...const_switch.identity.PreCodegen.after.mir | 124 -------------- ...te_const_switch.too_complex.ConstProp.diff | 103 ----------- ...st_switch.too_complex.PreCodegen.after.mir | 73 -------- src/test/mir-opt/simple-match.rs | 2 +- ...imple_match.match_bool.mir_map.0.64bit.mir | 29 ---- ... => simple_match.match_bool.mir_map.0.mir} | 0 ...ocals-removes-unused-discriminant-reads.rs | 1 - ...minant_reads.map.SimplifyLocals.64bit.diff | 52 ------ ...iscriminant_reads.map.SimplifyLocals.diff} | 0 src/test/mir-opt/slice-drop-shim.rs | 2 +- ...g].AddMovesForPackedDrops.before.64bit.mir | 101 ----------- ...String].AddMovesForPackedDrops.before.mir} | 0 src/test/mir-opt/unusual-item-types.rs | 2 +- ...types.E-V-{constant#0}.mir_map.0.64bit.mir | 10 -- ...item_types.E-V-{constant#0}.mir_map.0.mir} | 0 ...Test-X-{constructor#0}.mir_map.0.64bit.mir | 12 -- ...ypes.Test-X-{constructor#0}.mir_map.0.mir} | 0 ...2_.AddMovesForPackedDrops.before.64bit.mir | 39 ----- ...ec_i32_.AddMovesForPackedDrops.before.mir} | 0 ...0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir | 10 -- ...impl#0}-ASSOCIATED_CONSTANT.mir_map.0.mir} | 0 ...oops.change_loop_body.ConstProp.64bit.diff | 55 ------ ...let_loops.change_loop_body.ConstProp.diff} | 0 ...hange_loop_body.PreCodegen.after.64bit.mir | 17 -- ...ops.change_loop_body.PreCodegen.after.mir} | 0 src/test/mir-opt/while_let_loops.rs | 1 - 61 files changed, 12 insertions(+), 1598 deletions(-) delete mode 100644 src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir rename src/test/mir-opt/{array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir => array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir} (100%) delete mode 100644 src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff rename src/test/mir-opt/inline/{inline_into_box_place.main.Inline.32bit.diff => inline_into_box_place.main.Inline.diff} (100%) delete mode 100644 src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir rename src/test/mir-opt/{issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.32bit.mir => issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.mir} (100%) delete mode 100644 src/test/mir-opt/issue_72181.bar.mir_map.0.64bit.mir rename src/test/mir-opt/{issue_72181.bar.mir_map.0.32bit.mir => issue_72181.bar.mir_map.0.mir} (100%) delete mode 100644 src/test/mir-opt/issue_72181.foo.mir_map.0.64bit.mir rename src/test/mir-opt/{issue_72181.foo.mir_map.0.32bit.mir => issue_72181.foo.mir_map.0.mir} (100%) delete mode 100644 src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir rename src/test/mir-opt/{issue_72181.main.mir_map.0.32bit.mir => issue_72181.main.mir_map.0.mir} (100%) delete mode 100644 src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff rename src/test/mir-opt/{issue_73223.main.SimplifyArmIdentity.32bit.diff => issue_73223.main.SimplifyArmIdentity.diff} (100%) delete mode 100644 src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff rename src/test/mir-opt/{matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff => matches_reduce_branches.bar.MatchBranchSimplification.diff} (100%) delete mode 100644 src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff rename src/test/mir-opt/{matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff => matches_reduce_branches.foo.MatchBranchSimplification.diff} (100%) delete mode 100644 src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff rename src/test/mir-opt/{matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff => matches_reduce_branches.match_nested_if.MatchBranchSimplification.diff} (100%) delete mode 100644 src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.64bit.diff rename src/test/mir-opt/{matches_u8.exhaustive_match.MatchBranchSimplification.32bit.diff => matches_u8.exhaustive_match.MatchBranchSimplification.diff} (100%) delete mode 100644 src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.64bit.diff rename src/test/mir-opt/{matches_u8.exhaustive_match_i8.MatchBranchSimplification.32bit.diff => matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff} (100%) delete mode 100644 src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.64bit.mir rename src/test/mir-opt/{packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.32bit.mir => packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir} (100%) delete mode 100644 src/test/mir-opt/separate_const_switch.identity.ConstProp.diff delete mode 100644 src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir delete mode 100644 src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff delete mode 100644 src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir delete mode 100644 src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir rename src/test/mir-opt/{simple_match.match_bool.mir_map.0.32bit.mir => simple_match.match_bool.mir_map.0.mir} (100%) delete mode 100644 src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff rename src/test/mir-opt/{simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff => simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff} (100%) delete mode 100644 src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.64bit.mir rename src/test/mir-opt/{slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.32bit.mir => slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir} (100%) delete mode 100644 src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.64bit.mir rename src/test/mir-opt/{unusual_item_types.E-V-{constant#0}.mir_map.0.32bit.mir => unusual_item_types.E-V-{constant#0}.mir_map.0.mir} (100%) delete mode 100644 src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir rename src/test/mir-opt/{unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir => unusual_item_types.Test-X-{constructor#0}.mir_map.0.mir} (100%) delete mode 100644 src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir rename src/test/mir-opt/{unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir => unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir} (100%) delete mode 100644 src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir rename src/test/mir-opt/{unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir => unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.mir} (100%) delete mode 100644 src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.64bit.diff rename src/test/mir-opt/{while_let_loops.change_loop_body.ConstProp.32bit.diff => while_let_loops.change_loop_body.ConstProp.diff} (100%) delete mode 100644 src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir rename src/test/mir-opt/{while_let_loops.change_loop_body.PreCodegen.after.32bit.mir => while_let_loops.change_loop_body.PreCodegen.after.mir} (100%) diff --git a/src/test/mir-opt/array-index-is-temporary.rs b/src/test/mir-opt/array-index-is-temporary.rs index 0e4c486e4640..e7bde81d4ca3 100644 --- a/src/test/mir-opt/array-index-is-temporary.rs +++ b/src/test/mir-opt/array-index-is-temporary.rs @@ -7,7 +7,7 @@ unsafe fn foo(z: *mut usize) -> u32 { 99 } -// EMIT_MIR_FOR_EACH_BIT_WIDTH + // EMIT_MIR array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir fn main() { let mut x = [42, 43, 44]; diff --git a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir deleted file mode 100644 index 27f883ed321a..000000000000 --- a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir +++ /dev/null @@ -1,64 +0,0 @@ -// MIR for `main` after SimplifyCfg-elaborate-drops - -fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/array-index-is-temporary.rs:+0:11: +0:11 - let mut _1: [u32; 3]; // in scope 0 at $DIR/array-index-is-temporary.rs:+1:9: +1:14 - let mut _4: &mut usize; // in scope 0 at $DIR/array-index-is-temporary.rs:+3:25: +3:31 - let mut _5: u32; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:12: +4:29 - let mut _6: *mut usize; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:25: +4:26 - let _7: usize; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:7: +4:8 - let mut _8: usize; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:5: +4:9 - let mut _9: bool; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:5: +4:9 - scope 1 { - debug x => _1; // in scope 1 at $DIR/array-index-is-temporary.rs:+1:9: +1:14 - let mut _2: usize; // in scope 1 at $DIR/array-index-is-temporary.rs:+2:9: +2:14 - scope 2 { - debug y => _2; // in scope 2 at $DIR/array-index-is-temporary.rs:+2:9: +2:14 - let _3: *mut usize; // in scope 2 at $DIR/array-index-is-temporary.rs:+3:9: +3:10 - scope 3 { - debug z => _3; // in scope 3 at $DIR/array-index-is-temporary.rs:+3:9: +3:10 - scope 4 { - } - } - } - } - - bb0: { - StorageLive(_1); // scope 0 at $DIR/array-index-is-temporary.rs:+1:9: +1:14 - _1 = [const 42_u32, const 43_u32, const 44_u32]; // scope 0 at $DIR/array-index-is-temporary.rs:+1:17: +1:29 - StorageLive(_2); // scope 1 at $DIR/array-index-is-temporary.rs:+2:9: +2:14 - _2 = const 1_usize; // scope 1 at $DIR/array-index-is-temporary.rs:+2:17: +2:18 - StorageLive(_3); // scope 2 at $DIR/array-index-is-temporary.rs:+3:9: +3:10 - StorageLive(_4); // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31 - _4 = &mut _2; // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31 - _3 = &raw mut (*_4); // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31 - StorageDead(_4); // scope 2 at $DIR/array-index-is-temporary.rs:+3:31: +3:32 - StorageLive(_5); // scope 3 at $DIR/array-index-is-temporary.rs:+4:12: +4:29 - StorageLive(_6); // scope 4 at $DIR/array-index-is-temporary.rs:+4:25: +4:26 - _6 = _3; // scope 4 at $DIR/array-index-is-temporary.rs:+4:25: +4:26 - _5 = foo(move _6) -> bb1; // scope 4 at $DIR/array-index-is-temporary.rs:+4:21: +4:27 - // mir::Constant - // + span: $DIR/array-index-is-temporary.rs:16:21: 16:24 - // + literal: Const { ty: unsafe fn(*mut usize) -> u32 {foo}, val: Value() } - } - - bb1: { - StorageDead(_6); // scope 4 at $DIR/array-index-is-temporary.rs:+4:26: +4:27 - StorageLive(_7); // scope 3 at $DIR/array-index-is-temporary.rs:+4:7: +4:8 - _7 = _2; // scope 3 at $DIR/array-index-is-temporary.rs:+4:7: +4:8 - _8 = Len(_1); // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9 - _9 = Lt(_7, _8); // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9 - assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9 - } - - bb2: { - _1[_7] = move _5; // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:29 - StorageDead(_5); // scope 3 at $DIR/array-index-is-temporary.rs:+4:28: +4:29 - StorageDead(_7); // scope 3 at $DIR/array-index-is-temporary.rs:+4:29: +4:30 - _0 = const (); // scope 0 at $DIR/array-index-is-temporary.rs:+0:11: +5:2 - StorageDead(_3); // scope 2 at $DIR/array-index-is-temporary.rs:+5:1: +5:2 - StorageDead(_2); // scope 1 at $DIR/array-index-is-temporary.rs:+5:1: +5:2 - StorageDead(_1); // scope 0 at $DIR/array-index-is-temporary.rs:+5:1: +5:2 - return; // scope 0 at $DIR/array-index-is-temporary.rs:+5:2: +5:2 - } -} diff --git a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir similarity index 100% rename from src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir rename to src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir diff --git a/src/test/mir-opt/inline/inline-into-box-place.rs b/src/test/mir-opt/inline/inline-into-box-place.rs index 049a97816f68..232bcc7b27d4 100644 --- a/src/test/mir-opt/inline/inline-into-box-place.rs +++ b/src/test/mir-opt/inline/inline-into-box-place.rs @@ -1,7 +1,7 @@ // ignore-endian-big // ignore-wasm32-bare compiled with panic=abort by default // compile-flags: -Z mir-opt-level=4 -// EMIT_MIR_FOR_EACH_BIT_WIDTH + #![feature(box_syntax)] // EMIT_MIR inline_into_box_place.main.Inline.diff fn main() { diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff deleted file mode 100644 index 7017413ad38a..000000000000 --- a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff +++ /dev/null @@ -1,82 +0,0 @@ -- // MIR for `main` before Inline -+ // MIR for `main` after Inline - - fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/inline-into-box-place.rs:+0:11: +0:11 - let _1: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:9: +1:11 - let mut _2: usize; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - let mut _3: usize; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - let mut _4: *mut u8; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - let mut _5: std::boxed::Box>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - let mut _6: (); // in scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43 - let mut _7: *const std::vec::Vec; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 -+ let mut _8: &mut std::vec::Vec; // in scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 - scope 1 { - debug _x => _1; // in scope 1 at $DIR/inline-into-box-place.rs:+1:9: +1:11 - } - scope 2 { - } -+ scope 3 (inlined Vec::::new) { // at $DIR/inline-into-box-place.rs:8:33: 8:43 -+ let mut _9: alloc::raw_vec::RawVec; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -+ } - - bb0: { - StorageLive(_1); // scope 0 at $DIR/inline-into-box-place.rs:+1:9: +1:11 - _2 = SizeOf(std::vec::Vec); // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - _3 = AlignOf(std::vec::Vec); // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - // mir::Constant - // + span: $DIR/inline-into-box-place.rs:8:29: 8:43 - // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value() } - } - - bb1: { - StorageLive(_5); // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - _5 = ShallowInitBox(move _4, std::vec::Vec); // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - _7 = (((_5.0: std::ptr::Unique>).0: std::ptr::NonNull>).0: *const std::vec::Vec); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 -- (*_7) = Vec::::new() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 -+ StorageLive(_8); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 -+ _8 = &mut (*_7); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 -+ StorageLive(_9); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -+ _9 = const alloc::raw_vec::RawVec::::NEW; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL - // mir::Constant -- // + span: $DIR/inline-into-box-place.rs:8:33: 8:41 -- // + user_ty: UserType(1) -- // + literal: Const { ty: fn() -> Vec {Vec::::new}, val: Value() } -- } -- -- bb2: { -+ // + span: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -+ // + user_ty: UserType(0) -+ // + literal: Const { ty: alloc::raw_vec::RawVec, val: Unevaluated(alloc::raw_vec::RawVec::::NEW, [u32], None) } -+ Deinit((*_8)); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -+ ((*_8).0: alloc::raw_vec::RawVec) = move _9; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -+ ((*_8).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -+ StorageDead(_9); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -+ StorageDead(_8); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 - _1 = move _5; // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - StorageDead(_5); // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43 - _0 = const (); // scope 0 at $DIR/inline-into-box-place.rs:+0:11: +2:2 -- drop(_1) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2 -+ drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2 - } - -- bb3: { -+ bb2: { - StorageDead(_1); // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2 - return; // scope 0 at $DIR/inline-into-box-place.rs:+2:2: +2:2 - } - -- bb4 (cleanup): { -+ bb3 (cleanup): { - resume; // scope 0 at $DIR/inline-into-box-place.rs:+0:1: +2:2 -- } -- -- bb5 (cleanup): { -- _6 = alloc::alloc::box_free::, std::alloc::Global>(move (_5.0: std::ptr::Unique>), move (_5.1: std::alloc::Global)) -> bb4; // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43 -- // mir::Constant -- // + span: $DIR/inline-into-box-place.rs:8:42: 8:43 -- // + literal: Const { ty: unsafe fn(Unique>, std::alloc::Global) {alloc::alloc::box_free::, std::alloc::Global>}, val: Value() } - } - } - diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff similarity index 100% rename from src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff rename to src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff diff --git a/src/test/mir-opt/issue-41697.rs b/src/test/mir-opt/issue-41697.rs index 5c34d8e68d0c..cbd8633a345c 100644 --- a/src/test/mir-opt/issue-41697.rs +++ b/src/test/mir-opt/issue-41697.rs @@ -13,7 +13,7 @@ trait Foo { fn get(&self) -> [u8; 2]; } -// EMIT_MIR_FOR_EACH_BIT_WIDTH + // EMIT_MIR issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.mir impl Foo for [u8; 1+1] { fn get(&self) -> [u8; 2] { diff --git a/src/test/mir-opt/issue-72181.rs b/src/test/mir-opt/issue-72181.rs index 844d53a4b2bc..ebb5f5042fcc 100644 --- a/src/test/mir-opt/issue-72181.rs +++ b/src/test/mir-opt/issue-72181.rs @@ -11,14 +11,14 @@ union Foo { b: Never } -// EMIT_MIR_FOR_EACH_BIT_WIDTH + // EMIT_MIR issue_72181.foo.mir_map.0.mir fn foo(xs: [(Never, u32); 1]) -> u32 { xs[0].1 } // EMIT_MIR issue_72181.bar.mir_map.0.mir fn bar([(_, x)]: [(Never, u32); 1]) -> u32 { x } -// EMIT_MIR_FOR_EACH_BIT_WIDTH + // EMIT_MIR issue_72181.main.mir_map.0.mir fn main() { let _ = mem::size_of::(); diff --git a/src/test/mir-opt/issue-73223.rs b/src/test/mir-opt/issue-73223.rs index 9e731c409087..be114cab719c 100644 --- a/src/test/mir-opt/issue-73223.rs +++ b/src/test/mir-opt/issue-73223.rs @@ -8,5 +8,5 @@ fn main() { assert_eq!(split, 1); } -// EMIT_MIR_FOR_EACH_BIT_WIDTH + // EMIT_MIR issue_73223.main.SimplifyArmIdentity.diff diff --git a/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir b/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir deleted file mode 100644 index 047b24db4664..000000000000 --- a/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir +++ /dev/null @@ -1,20 +0,0 @@ -// MIR for `::{constant#0}` after SimplifyCfg-promote-consts - -::{constant#0}: usize = { - let mut _0: usize; // return place in scope 0 at $DIR/issue-41697.rs:+0:19: +0:22 - let mut _1: (usize, bool); // in scope 0 at $DIR/issue-41697.rs:+0:19: +0:22 - - bb0: { - _1 = CheckedAdd(const 1_usize, const 1_usize); // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22 - assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_usize, const 1_usize) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22 - } - - bb1: { - _0 = move (_1.0: usize); // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22 - return; // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22 - } - - bb2 (cleanup): { - resume; // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22 - } -} diff --git a/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.32bit.mir b/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.mir similarity index 100% rename from src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.32bit.mir rename to src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.mir diff --git a/src/test/mir-opt/issue_72181.bar.mir_map.0.64bit.mir b/src/test/mir-opt/issue_72181.bar.mir_map.0.64bit.mir deleted file mode 100644 index 972ce1d50785..000000000000 --- a/src/test/mir-opt/issue_72181.bar.mir_map.0.64bit.mir +++ /dev/null @@ -1,17 +0,0 @@ -// MIR for `bar` 0 mir_map - -fn bar(_1: [(Never, u32); 1]) -> u32 { - let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:+0:40: +0:43 - let _2: u32; // in scope 0 at $DIR/issue-72181.rs:+0:13: +0:14 - scope 1 { - debug x => _2; // in scope 1 at $DIR/issue-72181.rs:+0:13: +0:14 - } - - bb0: { - StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:+0:13: +0:14 - _2 = (_1[0 of 1].1: u32); // scope 0 at $DIR/issue-72181.rs:+0:13: +0:14 - _0 = _2; // scope 1 at $DIR/issue-72181.rs:+0:46: +0:47 - StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:+0:48: +0:49 - return; // scope 0 at $DIR/issue-72181.rs:+0:49: +0:49 - } -} diff --git a/src/test/mir-opt/issue_72181.bar.mir_map.0.32bit.mir b/src/test/mir-opt/issue_72181.bar.mir_map.0.mir similarity index 100% rename from src/test/mir-opt/issue_72181.bar.mir_map.0.32bit.mir rename to src/test/mir-opt/issue_72181.bar.mir_map.0.mir diff --git a/src/test/mir-opt/issue_72181.foo.mir_map.0.64bit.mir b/src/test/mir-opt/issue_72181.foo.mir_map.0.64bit.mir deleted file mode 100644 index 534f131ea936..000000000000 --- a/src/test/mir-opt/issue_72181.foo.mir_map.0.64bit.mir +++ /dev/null @@ -1,27 +0,0 @@ -// MIR for `foo` 0 mir_map - -fn foo(_1: [(Never, u32); 1]) -> u32 { - debug xs => _1; // in scope 0 at $DIR/issue-72181.rs:+0:8: +0:10 - let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:+0:34: +0:37 - let _2: usize; // in scope 0 at $DIR/issue-72181.rs:+0:43: +0:44 - let mut _3: usize; // in scope 0 at $DIR/issue-72181.rs:+0:40: +0:45 - let mut _4: bool; // in scope 0 at $DIR/issue-72181.rs:+0:40: +0:45 - - bb0: { - StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:+0:43: +0:44 - _2 = const 0_usize; // scope 0 at $DIR/issue-72181.rs:+0:43: +0:44 - _3 = Len(_1); // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45 - _4 = Lt(_2, _3); // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45 - assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, _2) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45 - } - - bb1: { - _0 = (_1[_2].1: u32); // scope 0 at $DIR/issue-72181.rs:+0:40: +0:47 - StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:+0:48: +0:49 - return; // scope 0 at $DIR/issue-72181.rs:+0:49: +0:49 - } - - bb2 (cleanup): { - resume; // scope 0 at $DIR/issue-72181.rs:+0:1: +0:49 - } -} diff --git a/src/test/mir-opt/issue_72181.foo.mir_map.0.32bit.mir b/src/test/mir-opt/issue_72181.foo.mir_map.0.mir similarity index 100% rename from src/test/mir-opt/issue_72181.foo.mir_map.0.32bit.mir rename to src/test/mir-opt/issue_72181.foo.mir_map.0.mir diff --git a/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir b/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir deleted file mode 100644 index 425906f84fcd..000000000000 --- a/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir +++ /dev/null @@ -1,62 +0,0 @@ -// MIR for `main` 0 mir_map - -fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/issue-72181.rs:+0:11: +0:11 - let mut _1: usize; // in scope 0 at $DIR/issue-72181.rs:+1:13: +1:34 - let mut _3: Foo; // in scope 0 at $DIR/issue-72181.rs:+3:14: +3:27 - let mut _4: Foo; // in scope 0 at $DIR/issue-72181.rs:+3:29: +3:42 - let mut _5: u64; // in scope 0 at $DIR/issue-72181.rs:+4:13: +4:30 - let _6: usize; // in scope 0 at $DIR/issue-72181.rs:+4:24: +4:25 - let mut _7: usize; // in scope 0 at $DIR/issue-72181.rs:+4:22: +4:26 - let mut _8: bool; // in scope 0 at $DIR/issue-72181.rs:+4:22: +4:26 - scope 1 { - let _2: [Foo; 2]; // in scope 1 at $DIR/issue-72181.rs:+3:9: +3:10 - scope 2 { - debug f => _2; // in scope 2 at $DIR/issue-72181.rs:+3:9: +3:10 - scope 3 { - } - scope 4 { - } - } - } - - bb0: { - StorageLive(_1); // scope 0 at $DIR/issue-72181.rs:+1:13: +1:34 - _1 = std::mem::size_of::() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-72181.rs:+1:13: +1:34 - // mir::Constant - // + span: $DIR/issue-72181.rs:24:13: 24:32 - // + literal: Const { ty: fn() -> usize {std::mem::size_of::}, val: Value() } - } - - bb1: { - StorageDead(_1); // scope 0 at $DIR/issue-72181.rs:+1:34: +1:35 - StorageLive(_2); // scope 1 at $DIR/issue-72181.rs:+3:9: +3:10 - StorageLive(_3); // scope 1 at $DIR/issue-72181.rs:+3:14: +3:27 - _3 = Foo { a: const 42_u64 }; // scope 1 at $DIR/issue-72181.rs:+3:14: +3:27 - StorageLive(_4); // scope 1 at $DIR/issue-72181.rs:+3:29: +3:42 - _4 = Foo { a: const 10_u64 }; // scope 1 at $DIR/issue-72181.rs:+3:29: +3:42 - _2 = [move _3, move _4]; // scope 1 at $DIR/issue-72181.rs:+3:13: +3:43 - StorageDead(_4); // scope 1 at $DIR/issue-72181.rs:+3:42: +3:43 - StorageDead(_3); // scope 1 at $DIR/issue-72181.rs:+3:42: +3:43 - FakeRead(ForLet(None), _2); // scope 1 at $DIR/issue-72181.rs:+3:9: +3:10 - StorageLive(_5); // scope 2 at $DIR/issue-72181.rs:+4:13: +4:30 - StorageLive(_6); // scope 4 at $DIR/issue-72181.rs:+4:24: +4:25 - _6 = const 0_usize; // scope 4 at $DIR/issue-72181.rs:+4:24: +4:25 - _7 = Len(_2); // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26 - _8 = Lt(_6, _7); // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26 - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb2, unwind: bb3]; // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26 - } - - bb2: { - _5 = (_2[_6].0: u64); // scope 4 at $DIR/issue-72181.rs:+4:22: +4:28 - StorageDead(_6); // scope 2 at $DIR/issue-72181.rs:+4:30: +4:31 - StorageDead(_5); // scope 2 at $DIR/issue-72181.rs:+4:30: +4:31 - _0 = const (); // scope 0 at $DIR/issue-72181.rs:+0:11: +5:2 - StorageDead(_2); // scope 1 at $DIR/issue-72181.rs:+5:1: +5:2 - return; // scope 0 at $DIR/issue-72181.rs:+5:2: +5:2 - } - - bb3 (cleanup): { - resume; // scope 0 at $DIR/issue-72181.rs:+0:1: +5:2 - } -} diff --git a/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir b/src/test/mir-opt/issue_72181.main.mir_map.0.mir similarity index 100% rename from src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir rename to src/test/mir-opt/issue_72181.main.mir_map.0.mir diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff deleted file mode 100644 index ac7fe31f3b39..000000000000 --- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff +++ /dev/null @@ -1,161 +0,0 @@ -- // MIR for `main` before SimplifyArmIdentity -+ // MIR for `main` after SimplifyArmIdentity - - fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/issue-73223.rs:+0:11: +0:11 - let _1: i32; // in scope 0 at $DIR/issue-73223.rs:+1:9: +1:14 - let mut _2: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - let mut _3: isize; // in scope 0 at $DIR/issue-73223.rs:+2:9: +2:16 - let _4: i32; // in scope 0 at $DIR/issue-73223.rs:+2:14: +2:15 - let mut _5: !; // in scope 0 at $DIR/issue-73223.rs:+3:17: +3:23 - let mut _7: i32; // in scope 0 at $DIR/issue-73223.rs:+6:22: +6:27 - let _8: (); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _9: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _10: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _11: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _12: i32; // in scope 0 at $DIR/issue-73223.rs:+7:23: +7:24 - let mut _15: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _16: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _17: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _18: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _19: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _21: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _22: core::panicking::AssertKind; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _23: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _24: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _25: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _26: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _27: std::option::Option; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - scope 1 { - debug split => _1; // in scope 1 at $DIR/issue-73223.rs:+1:9: +1:14 - let _6: std::option::Option; // in scope 1 at $DIR/issue-73223.rs:+6:9: +6:14 - scope 3 { - debug _prev => _6; // in scope 3 at $DIR/issue-73223.rs:+6:9: +6:14 - let _13: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _14: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _28: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - scope 4 { - debug left_val => _13; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - debug right_val => _14; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _20: core::panicking::AssertKind; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - scope 5 { - debug kind => _20; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - } - } - } - scope 2 { - debug v => _4; // in scope 2 at $DIR/issue-73223.rs:+2:14: +2:15 - } - - bb0: { - StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:+1:9: +1:14 - StorageLive(_2); // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - Deinit(_2); // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - _3 = const 1_isize; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - goto -> bb3; // scope 0 at $DIR/issue-73223.rs:+1:17: +1:30 - } - - bb1: { - nop; // scope 0 at $DIR/issue-73223.rs:+3:17: +3:23 - StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:+4:6: +4:7 - StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:+8:1: +8:2 - return; // scope 0 at $DIR/issue-73223.rs:+8:2: +8:2 - } - - bb2: { - unreachable; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30 - } - - bb3: { - StorageLive(_4); // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15 - _4 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15 - _1 = _4; // scope 2 at $DIR/issue-73223.rs:+2:20: +2:21 - StorageDead(_4); // scope 0 at $DIR/issue-73223.rs:+2:20: +2:21 - StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:+4:6: +4:7 - StorageLive(_6); // scope 1 at $DIR/issue-73223.rs:+6:9: +6:14 - StorageLive(_7); // scope 1 at $DIR/issue-73223.rs:+6:22: +6:27 - _7 = _1; // scope 1 at $DIR/issue-73223.rs:+6:22: +6:27 - Deinit(_6); // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28 - ((_6 as Some).0: i32) = move _7; // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28 - discriminant(_6) = 1; // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28 - StorageDead(_7); // scope 1 at $DIR/issue-73223.rs:+6:27: +6:28 - StorageLive(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_10); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _10 = &_1; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_11); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _28 = const main::promoted[0]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - // mir::Constant - // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) } - _11 = _28; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - Deinit(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_9.0: &i32) = move _10; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_9.1: &i32) = move _11; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_11); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_10); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_13); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _13 = (_9.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_14); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _14 = (_9.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_17); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _17 = (*_13); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_18); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _18 = const 1_i32; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _16 = Eq(move _17, const 1_i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_18); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_17); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _15 = Not(move _16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - switchInt(move _15) -> [false: bb5, otherwise: bb4]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - - bb4: { - StorageLive(_20); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - Deinit(_20); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - discriminant(_20) = 0; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_21); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_22); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _22 = const core::panicking::AssertKind::Eq; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - // mir::Constant - // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) } - StorageLive(_23); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_24); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _24 = _13; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _23 = _24; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_25); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_26); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _26 = _14; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _25 = _26; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_27); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - Deinit(_27); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - discriminant(_27) = 0; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _21 = core::panicking::assert_failed::(const core::panicking::AssertKind::Eq, move _23, move _25, move _27); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - // mir::Constant - // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option>) -> ! {core::panicking::assert_failed::}, val: Value() } - // mir::Constant - // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) } - } - - bb5: { - nop; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_14); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_13); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - nop; // scope 0 at $DIR/issue-73223.rs:+0:11: +8:2 - StorageDead(_6); // scope 1 at $DIR/issue-73223.rs:+8:1: +8:2 - StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:+8:1: +8:2 - return; // scope 0 at $DIR/issue-73223.rs:+8:2: +8:2 - } - } - diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff similarity index 100% rename from src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff rename to src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff deleted file mode 100644 index f9eeb1ea5b96..000000000000 --- a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff +++ /dev/null @@ -1,88 +0,0 @@ -- // MIR for `bar` before MatchBranchSimplification -+ // MIR for `bar` after MatchBranchSimplification - - fn bar(_1: i32) -> (bool, bool, bool, bool) { - debug i => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:9 - let mut _0: (bool, bool, bool, bool); // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:19: +0:43 - let _2: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:10 - let _6: (); // in scope 0 at $DIR/matches_reduce_branches.rs:+6:5: +21:6 - let mut _7: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+23:6: +23:7 - let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+23:9: +23:10 - let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+23:12: +23:13 - let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+23:15: +23:16 -+ let mut _11: i32; // in scope 0 at $DIR/matches_reduce_branches.rs:+6:5: +6:12 - scope 1 { - debug a => _2; // in scope 1 at $DIR/matches_reduce_branches.rs:+1:9: +1:10 - let _3: bool; // in scope 1 at $DIR/matches_reduce_branches.rs:+2:9: +2:10 - scope 2 { - debug b => _3; // in scope 2 at $DIR/matches_reduce_branches.rs:+2:9: +2:10 - let _4: bool; // in scope 2 at $DIR/matches_reduce_branches.rs:+3:9: +3:10 - scope 3 { - debug c => _4; // in scope 3 at $DIR/matches_reduce_branches.rs:+3:9: +3:10 - let _5: bool; // in scope 3 at $DIR/matches_reduce_branches.rs:+4:9: +4:10 - scope 4 { - debug d => _5; // in scope 4 at $DIR/matches_reduce_branches.rs:+4:9: +4:10 - } - } - } - } - - bb0: { - StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:10 - StorageLive(_3); // scope 1 at $DIR/matches_reduce_branches.rs:+2:9: +2:10 - StorageLive(_4); // scope 2 at $DIR/matches_reduce_branches.rs:+3:9: +3:10 - StorageLive(_5); // scope 3 at $DIR/matches_reduce_branches.rs:+4:9: +4:10 - StorageLive(_6); // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +21:6 -- switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12 -- } -- -- bb1: { -- _2 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+15:13: +15:21 -- _3 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+16:13: +16:22 -- _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+17:13: +17:22 -- _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+18:13: +18:21 -- Deinit(_6); // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15 -- goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:+19:13: +19:15 -- } -- -- bb2: { -- _2 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+8:13: +8:22 -- _3 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+9:13: +9:21 -+ StorageLive(_11); // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12 -+ _11 = _1; // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12 -+ _2 = Ne(_11, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:+8:13: +8:22 -+ _3 = Eq(_11, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:+9:13: +9:21 - _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:+10:13: +10:22 - _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:+11:13: +11:21 - Deinit(_6); // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15 -- goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:+12:13: +12:15 -- } -- -- bb3: { -+ StorageDead(_11); // scope 4 at $DIR/matches_reduce_branches.rs:+6:5: +6:12 - StorageDead(_6); // scope 4 at $DIR/matches_reduce_branches.rs:+21:6: +21:7 - StorageLive(_7); // scope 4 at $DIR/matches_reduce_branches.rs:+23:6: +23:7 - _7 = _2; // scope 4 at $DIR/matches_reduce_branches.rs:+23:6: +23:7 - StorageLive(_8); // scope 4 at $DIR/matches_reduce_branches.rs:+23:9: +23:10 - _8 = _3; // scope 4 at $DIR/matches_reduce_branches.rs:+23:9: +23:10 - StorageLive(_9); // scope 4 at $DIR/matches_reduce_branches.rs:+23:12: +23:13 - _9 = _4; // scope 4 at $DIR/matches_reduce_branches.rs:+23:12: +23:13 - StorageLive(_10); // scope 4 at $DIR/matches_reduce_branches.rs:+23:15: +23:16 - _10 = _5; // scope 4 at $DIR/matches_reduce_branches.rs:+23:15: +23:16 - Deinit(_0); // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17 - (_0.0: bool) = move _7; // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17 - (_0.1: bool) = move _8; // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17 - (_0.2: bool) = move _9; // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17 - (_0.3: bool) = move _10; // scope 4 at $DIR/matches_reduce_branches.rs:+23:5: +23:17 - StorageDead(_10); // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17 - StorageDead(_9); // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17 - StorageDead(_8); // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17 - StorageDead(_7); // scope 4 at $DIR/matches_reduce_branches.rs:+23:16: +23:17 - StorageDead(_5); // scope 3 at $DIR/matches_reduce_branches.rs:+24:1: +24:2 - StorageDead(_4); // scope 2 at $DIR/matches_reduce_branches.rs:+24:1: +24:2 - StorageDead(_3); // scope 1 at $DIR/matches_reduce_branches.rs:+24:1: +24:2 - StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+24:1: +24:2 - return; // scope 0 at $DIR/matches_reduce_branches.rs:+24:2: +24:2 - } - } - diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff similarity index 100% rename from src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff rename to src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff deleted file mode 100644 index 0b40b3be8bdd..000000000000 --- a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff +++ /dev/null @@ -1,55 +0,0 @@ -- // MIR for `foo` before MatchBranchSimplification -+ // MIR for `foo` after MatchBranchSimplification - - fn foo(_1: Option<()>) -> () { - debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:+0:8: +0:11 - let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:25 - let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _3: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:22: +1:26 -+ let mut _4: isize; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - - bb0: { - StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _3 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+1:17: +1:20 -- switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -+ StorageLive(_4); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -+ _4 = move _3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -+ _2 = Eq(_4, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -+ StorageDead(_4); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -+ switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - } - - bb1: { -- _2 = const false; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -- goto -> bb3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -- } -- -- bb2: { -- _2 = const true; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -- goto -> bb3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -- } -- -- bb3: { -- switchInt(move _2) -> [false: bb5, otherwise: bb4]; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -- } -- -- bb4: { - Deinit(_0); // scope 0 at $DIR/matches_reduce_branches.rs:+2:9: +2:11 -- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6 -+ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6 - } - -- bb5: { -+ bb2: { - _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:+3:6: +3:6 -- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6 -+ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+1:5: +3:6 - } - -- bb6: { -+ bb3: { - StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+3:5: +3:6 - return; // scope 0 at $DIR/matches_reduce_branches.rs:+4:2: +4:2 - } - } - diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff similarity index 100% rename from src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff rename to src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff diff --git a/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff deleted file mode 100644 index b8c7722cd371..000000000000 --- a/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.64bit.diff +++ /dev/null @@ -1,113 +0,0 @@ -- // MIR for `match_nested_if` before MatchBranchSimplification -+ // MIR for `match_nested_if` after MatchBranchSimplification - - fn match_nested_if() -> bool { - let mut _0: bool; // return place in scope 0 at $DIR/matches_reduce_branches.rs:+0:25: +0:29 - let _1: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:12 - let mut _2: (); // in scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23 - let mut _3: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10 - let mut _4: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76 - let mut _5: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52 - let mut _6: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 -+ let mut _7: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 -+ let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52 -+ let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76 -+ let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10 - scope 1 { - debug val => _1; // in scope 1 at $DIR/matches_reduce_branches.rs:+1:9: +1:12 - } - - bb0: { - StorageLive(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+1:9: +1:12 - StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23 - Deinit(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+1:21: +1:23 - StorageLive(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10 - StorageLive(_4); // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76 - StorageLive(_5); // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52 - StorageLive(_6); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 - _6 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 -- switchInt(move _6) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 -- } -- -- bb1: { -- _5 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:31: +2:35 -- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52 -- } -- -- bb2: { -- _5 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+2:45: +2:50 -- goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52 -- } -- -- bb3: { -+ StorageLive(_7); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 -+ _7 = move _6; // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 -+ _5 = Ne(_7, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+2:45: +2:50 -+ StorageDead(_7); // scope 0 at $DIR/matches_reduce_branches.rs:+2:24: +2:28 - StorageDead(_6); // scope 0 at $DIR/matches_reduce_branches.rs:+2:51: +2:52 -- switchInt(move _5) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52 -- } -- -- bb4: { -- _4 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+2:55: +2:59 -- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76 -- } -- -- bb5: { -- _4 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+2:69: +2:74 -- goto -> bb6; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76 -- } -- -- bb6: { -+ StorageLive(_8); // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52 -+ _8 = move _5; // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52 -+ _4 = Ne(_8, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+2:69: +2:74 -+ StorageDead(_8); // scope 0 at $DIR/matches_reduce_branches.rs:+2:21: +2:52 - StorageDead(_5); // scope 0 at $DIR/matches_reduce_branches.rs:+2:75: +2:76 -- switchInt(move _4) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76 -- } -- -- bb7: { -- _3 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+3:13: +3:17 -- goto -> bb9; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10 -- } -- -- bb8: { -- _3 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+5:13: +5:18 -- goto -> bb9; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10 -- } -- -- bb9: { -- switchInt(move _3) -> [false: bb11, otherwise: bb10]; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10 -- } -- -- bb10: { -+ StorageLive(_9); // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76 -+ _9 = move _4; // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76 -+ _3 = Ne(_9, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+5:13: +5:18 -+ StorageDead(_9); // scope 0 at $DIR/matches_reduce_branches.rs:+2:18: +2:76 -+ StorageLive(_10); // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10 -+ _10 = move _3; // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10 - StorageDead(_4); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10 - StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10 -- _1 = const true; // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17 -- goto -> bb12; // scope 0 at $DIR/matches_reduce_branches.rs:+8:13: +8:17 -- } -- -- bb11: { -- StorageDead(_4); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10 -- StorageDead(_3); // scope 0 at $DIR/matches_reduce_branches.rs:+6:9: +6:10 -- _1 = const false; // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19 -- goto -> bb12; // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19 -- } -- -- bb12: { -+ _1 = Ne(_10, const false); // scope 0 at $DIR/matches_reduce_branches.rs:+10:14: +10:19 -+ StorageDead(_10); // scope 0 at $DIR/matches_reduce_branches.rs:+2:15: +6:10 - StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:+11:6: +11:7 - _0 = _1; // scope 1 at $DIR/matches_reduce_branches.rs:+12:5: +12:8 - StorageDead(_1); // scope 0 at $DIR/matches_reduce_branches.rs:+13:1: +13:2 - return; // scope 0 at $DIR/matches_reduce_branches.rs:+13:2: +13:2 - } - } - diff --git a/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.diff similarity index 100% rename from src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.32bit.diff rename to src/test/mir-opt/matches_reduce_branches.match_nested_if.MatchBranchSimplification.diff diff --git a/src/test/mir-opt/matches_reduce_branches.rs b/src/test/mir-opt/matches_reduce_branches.rs index c122b4c69d15..a81d5f7b4e8b 100644 --- a/src/test/mir-opt/matches_reduce_branches.rs +++ b/src/test/mir-opt/matches_reduce_branches.rs @@ -1,6 +1,6 @@ // unit-test: MatchBranchSimplification -// EMIT_MIR_FOR_EACH_BIT_WIDTH + // EMIT_MIR matches_reduce_branches.foo.MatchBranchSimplification.diff // EMIT_MIR matches_reduce_branches.bar.MatchBranchSimplification.diff // EMIT_MIR matches_reduce_branches.match_nested_if.MatchBranchSimplification.diff diff --git a/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.64bit.diff deleted file mode 100644 index 1b4dddc1d43a..000000000000 --- a/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.64bit.diff +++ /dev/null @@ -1,32 +0,0 @@ -- // MIR for `exhaustive_match` before MatchBranchSimplification -+ // MIR for `exhaustive_match` after MatchBranchSimplification - - fn exhaustive_match(_1: E) -> u8 { - debug e => _1; // in scope 0 at $DIR/matches_u8.rs:+0:25: +0:26 - let mut _0: u8; // return place in scope 0 at $DIR/matches_u8.rs:+0:34: +0:36 - let mut _2: isize; // in scope 0 at $DIR/matches_u8.rs:+2:9: +2:13 - - bb0: { - _2 = discriminant(_1); // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12 - switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/matches_u8.rs:+1:5: +1:12 - } - - bb1: { - _0 = const 1_u8; // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18 - goto -> bb4; // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18 - } - - bb2: { - unreachable; // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12 - } - - bb3: { - _0 = const 0_u8; // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18 - goto -> bb4; // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18 - } - - bb4: { - return; // scope 0 at $DIR/matches_u8.rs:+5:2: +5:2 - } - } - diff --git a/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff similarity index 100% rename from src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.32bit.diff rename to src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff diff --git a/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.64bit.diff deleted file mode 100644 index 6e734852e1af..000000000000 --- a/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.64bit.diff +++ /dev/null @@ -1,32 +0,0 @@ -- // MIR for `exhaustive_match_i8` before MatchBranchSimplification -+ // MIR for `exhaustive_match_i8` after MatchBranchSimplification - - fn exhaustive_match_i8(_1: E) -> i8 { - debug e => _1; // in scope 0 at $DIR/matches_u8.rs:+0:28: +0:29 - let mut _0: i8; // return place in scope 0 at $DIR/matches_u8.rs:+0:37: +0:39 - let mut _2: isize; // in scope 0 at $DIR/matches_u8.rs:+2:9: +2:13 - - bb0: { - _2 = discriminant(_1); // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12 - switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/matches_u8.rs:+1:5: +1:12 - } - - bb1: { - _0 = const 1_i8; // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18 - goto -> bb4; // scope 0 at $DIR/matches_u8.rs:+3:17: +3:18 - } - - bb2: { - unreachable; // scope 0 at $DIR/matches_u8.rs:+1:11: +1:12 - } - - bb3: { - _0 = const 0_i8; // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18 - goto -> bb4; // scope 0 at $DIR/matches_u8.rs:+2:17: +2:18 - } - - bb4: { - return; // scope 0 at $DIR/matches_u8.rs:+5:2: +5:2 - } - } - diff --git a/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff similarity index 100% rename from src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.32bit.diff rename to src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff diff --git a/src/test/mir-opt/matches_u8.rs b/src/test/mir-opt/matches_u8.rs index 2c748b02a8b7..422c3a95e8ef 100644 --- a/src/test/mir-opt/matches_u8.rs +++ b/src/test/mir-opt/matches_u8.rs @@ -1,6 +1,6 @@ // unit-test: MatchBranchSimplification -// EMIT_MIR_FOR_EACH_BIT_WIDTH + // EMIT_MIR matches_u8.exhaustive_match.MatchBranchSimplification.diff // EMIT_MIR matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff diff --git a/src/test/mir-opt/packed-struct-drop-aligned.rs b/src/test/mir-opt/packed-struct-drop-aligned.rs index 6c2e265d5146..cb6524260908 100644 --- a/src/test/mir-opt/packed-struct-drop-aligned.rs +++ b/src/test/mir-opt/packed-struct-drop-aligned.rs @@ -1,6 +1,6 @@ // ignore-wasm32-bare compiled with panic=abort by default -// EMIT_MIR_FOR_EACH_BIT_WIDTH + // EMIT_MIR packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir fn main() { let mut x = Packed(Aligned(Droppy(0))); diff --git a/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.64bit.mir b/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.64bit.mir deleted file mode 100644 index f9ed1036f006..000000000000 --- a/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.64bit.mir +++ /dev/null @@ -1,60 +0,0 @@ -// MIR for `main` after SimplifyCfg-elaborate-drops - -fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:11: +0:11 - let mut _1: Packed; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14 - let mut _2: Aligned; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42 - let mut _3: Droppy; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41 - let mut _4: Aligned; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29 - let mut _5: Droppy; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28 - let mut _6: Aligned; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8 - scope 1 { - debug x => _1; // in scope 1 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14 - } - - bb0: { - StorageLive(_1); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14 - StorageLive(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42 - StorageLive(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41 - Deinit(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41 - (_3.0: usize) = const 0_usize; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41 - Deinit(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42 - (_2.0: Droppy) = move _3; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42 - StorageDead(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:41: +1:42 - Deinit(_1); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:17: +1:43 - (_1.0: Aligned) = move _2; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:17: +1:43 - StorageDead(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:42: +1:43 - StorageLive(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29 - StorageLive(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28 - Deinit(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28 - (_5.0: usize) = const 0_usize; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28 - Deinit(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29 - (_4.0: Droppy) = move _5; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29 - StorageDead(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:28: +2:29 - StorageLive(_6); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8 - _6 = move (_1.0: Aligned); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8 - drop(_6) -> [return: bb4, unwind: bb3]; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8 - } - - bb1: { - StorageDead(_1); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2 - return; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:2: +3:2 - } - - bb2 (cleanup): { - resume; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:1: +3:2 - } - - bb3 (cleanup): { - (_1.0: Aligned) = move _4; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8 - drop(_1) -> bb2; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2 - } - - bb4: { - StorageDead(_6); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8 - (_1.0: Aligned) = move _4; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8 - StorageDead(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:28: +2:29 - _0 = const (); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:11: +3:2 - drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2 - } -} diff --git a/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.32bit.mir b/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir similarity index 100% rename from src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.32bit.mir rename to src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir diff --git a/src/test/mir-opt/separate_const_switch.identity.ConstProp.diff b/src/test/mir-opt/separate_const_switch.identity.ConstProp.diff deleted file mode 100644 index 28536dc28a72..000000000000 --- a/src/test/mir-opt/separate_const_switch.identity.ConstProp.diff +++ /dev/null @@ -1,146 +0,0 @@ -- // MIR for `identity` before ConstProp -+ // MIR for `identity` after ConstProp - - fn identity(_1: Result) -> Result { - debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:+0:13: +0:14 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:37: +0:53 - let mut _2: i32; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - let mut _3: std::ops::ControlFlow, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - let mut _4: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9 - let mut _5: isize; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - let _6: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - let mut _7: !; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - let mut _8: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - let _9: i32; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - scope 1 { - debug residual => _6; // in scope 1 at $DIR/separate_const_switch.rs:+1:9: +1:10 - scope 2 { - scope 8 (inlined #[track_caller] as FromResidual>>::from_residual) { // at $DIR/separate_const_switch.rs:29:8: 29:10 - debug residual => _8; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - let _16: i32; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _17: i32; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _18: i32; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - scope 9 { - debug e => _16; // in scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - scope 10 (inlined >::from) { // at $SRC_DIR/core/src/result.rs:LL:COL - debug t => _18; // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL - } - } - } - } - } - scope 3 { - debug val => _9; // in scope 3 at $DIR/separate_const_switch.rs:+1:8: +1:10 - scope 4 { - } - } - scope 5 (inlined as Try>::branch) { // at $DIR/separate_const_switch.rs:29:8: 29:10 - debug self => _4; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _10: isize; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - let _11: i32; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _12: i32; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - let _13: i32; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _14: std::result::Result; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _15: i32; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - scope 6 { - debug v => _11; // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - } - scope 7 { - debug e => _13; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - } - } - - bb0: { - StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - StorageLive(_3); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9 - _4 = _1; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9 - _10 = discriminant(_4); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - switchInt(move _10) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - } - - bb1: { - StorageLive(_9); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - _9 = ((_3 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - _2 = _9; // scope 4 at $DIR/separate_const_switch.rs:+1:8: +1:10 - StorageDead(_9); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - Deinit(_0); // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11 - ((_0 as Ok).0: i32) = move _2; // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11 - discriminant(_0) = 0; // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11 - StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11 - StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2 - return; // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2 - } - - bb2: { - unreachable; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - } - - bb3: { - StorageLive(_6); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - _6 = ((_3 as Break).0: std::result::Result); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageLive(_8); // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10 - _8 = _6; // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageLive(_16); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - _16 = move ((_8 as Err).0: i32); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - StorageLive(_17); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - StorageLive(_18); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - _18 = move _16; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - _17 = move _18; // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL - StorageDead(_18); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - Deinit(_0); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - ((_0 as Err).0: i32) = move _17; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - discriminant(_0) = 1; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_17); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_16); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_8); // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11 - StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2 - return; // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2 - } - - bb4: { - StorageLive(_13); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - _13 = move ((_4 as Err).0: i32); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - StorageLive(_14); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - StorageLive(_15); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - _15 = move _13; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - Deinit(_14); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - ((_14 as Err).0: i32) = move _15; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - discriminant(_14) = 1; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_15); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - Deinit(_3); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - ((_3 as Break).0: std::result::Result) = move _14; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - discriminant(_3) = 1; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_14); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_13); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 -- _5 = discriminant(_3); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 -- switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 -+ _5 = const 1_isize; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 -+ switchInt(const 1_isize) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - } - - bb5: { - unreachable; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - } - - bb6: { - StorageLive(_11); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - _11 = move ((_4 as Ok).0: i32); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - StorageLive(_12); // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - _12 = move _11; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - Deinit(_3); // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - ((_3 as Continue).0: i32) = move _12; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - discriminant(_3) = 0; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_12); // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_11); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 -- _5 = discriminant(_3); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 -- switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 -+ _5 = const 0_isize; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 -+ switchInt(const 0_isize) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - } - } - diff --git a/src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir b/src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir deleted file mode 100644 index df20f0ed36b6..000000000000 --- a/src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir +++ /dev/null @@ -1,124 +0,0 @@ -// MIR for `identity` after PreCodegen - -fn identity(_1: Result) -> Result { - debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:+0:13: +0:14 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:37: +0:53 - let mut _2: i32; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - let mut _3: std::ops::ControlFlow, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - let mut _4: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9 - let _5: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - let mut _6: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - let _7: i32; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - scope 1 { - debug residual => _5; // in scope 1 at $DIR/separate_const_switch.rs:+1:9: +1:10 - scope 2 { - scope 8 (inlined #[track_caller] as FromResidual>>::from_residual) { // at $DIR/separate_const_switch.rs:29:8: 29:10 - debug residual => _6; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - let _14: i32; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _15: i32; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _16: i32; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - scope 9 { - debug e => _14; // in scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - scope 10 (inlined >::from) { // at $SRC_DIR/core/src/result.rs:LL:COL - debug t => _16; // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL - } - } - } - } - } - scope 3 { - debug val => _7; // in scope 3 at $DIR/separate_const_switch.rs:+1:8: +1:10 - scope 4 { - } - } - scope 5 (inlined as Try>::branch) { // at $DIR/separate_const_switch.rs:29:8: 29:10 - debug self => _4; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _8: isize; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - let _9: i32; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _10: i32; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - let _11: i32; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _12: std::result::Result; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _13: i32; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - scope 6 { - debug v => _9; // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - } - scope 7 { - debug e => _11; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - } - } - - bb0: { - StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - StorageLive(_3); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9 - _4 = _1; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9 - _8 = discriminant(_4); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - switchInt(move _8) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - } - - bb1: { - StorageLive(_11); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - _11 = move ((_4 as Err).0: i32); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - StorageLive(_12); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - StorageLive(_13); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - _13 = move _11; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - Deinit(_12); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - ((_12 as Err).0: i32) = move _13; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - discriminant(_12) = 1; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_13); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - Deinit(_3); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - ((_3 as Break).0: std::result::Result) = move _12; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - discriminant(_3) = 1; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_12); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_11); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageLive(_5); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - _5 = ((_3 as Break).0: std::result::Result); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageLive(_6); // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10 - _6 = _5; // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageLive(_14); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - _14 = move ((_6 as Err).0: i32); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - StorageLive(_15); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - StorageLive(_16); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - _16 = move _14; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - _15 = move _16; // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL - StorageDead(_16); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - Deinit(_0); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - ((_0 as Err).0: i32) = move _15; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - discriminant(_0) = 1; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_15); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_14); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_6); // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageDead(_5); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11 - StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2 - return; // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2 - } - - bb2: { - unreachable; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - } - - bb3: { - StorageLive(_9); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - _9 = move ((_4 as Ok).0: i32); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - StorageLive(_10); // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - _10 = move _9; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - Deinit(_3); // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - ((_3 as Continue).0: i32) = move _10; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - discriminant(_3) = 0; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_10); // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_9); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageLive(_7); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - _7 = ((_3 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - _2 = _7; // scope 4 at $DIR/separate_const_switch.rs:+1:8: +1:10 - StorageDead(_7); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - Deinit(_0); // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11 - ((_0 as Ok).0: i32) = move _2; // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11 - discriminant(_0) = 0; // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11 - StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11 - StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2 - return; // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2 - } -} diff --git a/src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff b/src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff deleted file mode 100644 index 28269165e1c2..000000000000 --- a/src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff +++ /dev/null @@ -1,103 +0,0 @@ -- // MIR for `too_complex` before ConstProp -+ // MIR for `too_complex` after ConstProp - - fn too_complex(_1: Result) -> Option { - debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:+0:16: +0:17 - let mut _0: std::option::Option; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:42: +0:53 - let mut _2: std::ops::ControlFlow; // in scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 - let mut _3: isize; // in scope 0 at $DIR/separate_const_switch.rs:+7:13: +7:18 - let _4: i32; // in scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17 - let mut _5: i32; // in scope 0 at $DIR/separate_const_switch.rs:+7:44: +7:45 - let _6: usize; // in scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18 - let mut _7: usize; // in scope 0 at $DIR/separate_const_switch.rs:+8:42: +8:43 - let mut _8: isize; // in scope 0 at $DIR/separate_const_switch.rs:+11:9: +11:33 - let _9: i32; // in scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32 - let mut _10: i32; // in scope 0 at $DIR/separate_const_switch.rs:+11:42: +11:43 - let _11: usize; // in scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29 - scope 1 { - debug v => _4; // in scope 1 at $DIR/separate_const_switch.rs:+7:16: +7:17 - } - scope 2 { - debug r => _6; // in scope 2 at $DIR/separate_const_switch.rs:+8:17: +8:18 - } - scope 3 { - debug v => _9; // in scope 3 at $DIR/separate_const_switch.rs:+11:31: +11:32 - } - scope 4 { - debug r => _11; // in scope 4 at $DIR/separate_const_switch.rs:+12:28: +12:29 - } - - bb0: { - StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 - _3 = discriminant(_1); // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16 - switchInt(move _3) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+6:9: +6:16 - } - - bb1: { - StorageLive(_6); // scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18 - _6 = ((_1 as Err).0: usize); // scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18 - StorageLive(_7); // scope 2 at $DIR/separate_const_switch.rs:+8:42: +8:43 - _7 = _6; // scope 2 at $DIR/separate_const_switch.rs:+8:42: +8:43 - Deinit(_2); // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44 - ((_2 as Break).0: usize) = move _7; // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44 - discriminant(_2) = 1; // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44 - StorageDead(_7); // scope 2 at $DIR/separate_const_switch.rs:+8:43: +8:44 - StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:+8:43: +8:44 -- _8 = discriminant(_2); // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 -- switchInt(move _8) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6 -+ _8 = const 1_isize; // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 -+ switchInt(const 1_isize) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6 - } - - bb2: { - unreachable; // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16 - } - - bb3: { - StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17 - _4 = ((_1 as Ok).0: i32); // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17 - StorageLive(_5); // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45 - _5 = _4; // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45 - Deinit(_2); // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46 - ((_2 as Continue).0: i32) = move _5; // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46 - discriminant(_2) = 0; // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46 - StorageDead(_5); // scope 1 at $DIR/separate_const_switch.rs:+7:45: +7:46 - StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:+7:45: +7:46 -- _8 = discriminant(_2); // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 -- switchInt(move _8) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6 -+ _8 = const 0_isize; // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 -+ switchInt(const 0_isize) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6 - } - - bb4: { - StorageLive(_11); // scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29 - _11 = ((_2 as Break).0: usize); // scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29 - Deinit(_0); // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38 - discriminant(_0) = 0; // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38 - StorageDead(_11); // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38 - goto -> bb7; // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38 - } - - bb5: { - unreachable; // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 - } - - bb6: { - StorageLive(_9); // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32 - _9 = ((_2 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32 - StorageLive(_10); // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43 - _10 = _9; // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43 - Deinit(_0); // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44 - ((_0 as Some).0: i32) = move _10; // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44 - discriminant(_0) = 1; // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44 - StorageDead(_10); // scope 3 at $DIR/separate_const_switch.rs:+11:43: +11:44 - StorageDead(_9); // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44 - goto -> bb7; // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44 - } - - bb7: { - StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+14:1: +14:2 - return; // scope 0 at $DIR/separate_const_switch.rs:+14:2: +14:2 - } - } - diff --git a/src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir b/src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir deleted file mode 100644 index 0ee070619e79..000000000000 --- a/src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir +++ /dev/null @@ -1,73 +0,0 @@ -// MIR for `too_complex` after PreCodegen - -fn too_complex(_1: Result) -> Option { - debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:+0:16: +0:17 - let mut _0: std::option::Option; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:42: +0:53 - let mut _2: std::ops::ControlFlow; // in scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 - let mut _3: isize; // in scope 0 at $DIR/separate_const_switch.rs:+7:13: +7:18 - let _4: i32; // in scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17 - let mut _5: i32; // in scope 0 at $DIR/separate_const_switch.rs:+7:44: +7:45 - let _6: usize; // in scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18 - let _7: i32; // in scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32 - let mut _8: i32; // in scope 0 at $DIR/separate_const_switch.rs:+11:42: +11:43 - let _9: usize; // in scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29 - scope 1 { - debug v => _4; // in scope 1 at $DIR/separate_const_switch.rs:+7:16: +7:17 - } - scope 2 { - debug r => _6; // in scope 2 at $DIR/separate_const_switch.rs:+8:17: +8:18 - } - scope 3 { - debug v => _7; // in scope 3 at $DIR/separate_const_switch.rs:+11:31: +11:32 - } - scope 4 { - debug r => _9; // in scope 4 at $DIR/separate_const_switch.rs:+12:28: +12:29 - } - - bb0: { - StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 - _3 = discriminant(_1); // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16 - switchInt(move _3) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+6:9: +6:16 - } - - bb1: { - StorageLive(_6); // scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18 - StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:+8:43: +8:44 - StorageLive(_9); // scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29 - Deinit(_0); // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38 - discriminant(_0) = 0; // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38 - StorageDead(_9); // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38 - goto -> bb4; // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38 - } - - bb2: { - unreachable; // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16 - } - - bb3: { - StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17 - _4 = ((_1 as Ok).0: i32); // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17 - StorageLive(_5); // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45 - _5 = _4; // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45 - Deinit(_2); // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46 - ((_2 as Continue).0: i32) = move _5; // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46 - discriminant(_2) = 0; // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46 - StorageDead(_5); // scope 1 at $DIR/separate_const_switch.rs:+7:45: +7:46 - StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:+7:45: +7:46 - StorageLive(_7); // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32 - _7 = ((_2 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32 - StorageLive(_8); // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43 - _8 = _7; // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43 - Deinit(_0); // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44 - ((_0 as Some).0: i32) = move _8; // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44 - discriminant(_0) = 1; // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44 - StorageDead(_8); // scope 3 at $DIR/separate_const_switch.rs:+11:43: +11:44 - StorageDead(_7); // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44 - goto -> bb4; // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44 - } - - bb4: { - StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+14:1: +14:2 - return; // scope 0 at $DIR/separate_const_switch.rs:+14:2: +14:2 - } -} diff --git a/src/test/mir-opt/simple-match.rs b/src/test/mir-opt/simple-match.rs index 44adc55b6f7f..103033c4e2b8 100644 --- a/src/test/mir-opt/simple-match.rs +++ b/src/test/mir-opt/simple-match.rs @@ -1,6 +1,6 @@ // Test that we don't generate unnecessarily large MIR for very simple matches -// EMIT_MIR_FOR_EACH_BIT_WIDTH + // EMIT_MIR simple_match.match_bool.mir_map.0.mir fn match_bool(x: bool) -> usize { match x { diff --git a/src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir b/src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir deleted file mode 100644 index 3bef6aa0579a..000000000000 --- a/src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir +++ /dev/null @@ -1,29 +0,0 @@ -// MIR for `match_bool` 0 mir_map - -fn match_bool(_1: bool) -> usize { - debug x => _1; // in scope 0 at $DIR/simple-match.rs:+0:15: +0:16 - let mut _0: usize; // return place in scope 0 at $DIR/simple-match.rs:+0:27: +0:32 - - bb0: { - FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/simple-match.rs:+1:11: +1:12 - switchInt(_1) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/simple-match.rs:+1:5: +1:12 - } - - bb1: { - falseEdge -> [real: bb3, imaginary: bb2]; // scope 0 at $DIR/simple-match.rs:+2:9: +2:13 - } - - bb2: { - _0 = const 20_usize; // scope 0 at $DIR/simple-match.rs:+3:14: +3:16 - goto -> bb4; // scope 0 at $DIR/simple-match.rs:+3:14: +3:16 - } - - bb3: { - _0 = const 10_usize; // scope 0 at $DIR/simple-match.rs:+2:17: +2:19 - goto -> bb4; // scope 0 at $DIR/simple-match.rs:+2:17: +2:19 - } - - bb4: { - return; // scope 0 at $DIR/simple-match.rs:+5:2: +5:2 - } -} diff --git a/src/test/mir-opt/simple_match.match_bool.mir_map.0.32bit.mir b/src/test/mir-opt/simple_match.match_bool.mir_map.0.mir similarity index 100% rename from src/test/mir-opt/simple_match.match_bool.mir_map.0.32bit.mir rename to src/test/mir-opt/simple_match.match_bool.mir_map.0.mir diff --git a/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs b/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs index 62a15df04b14..d09bd92c4e81 100644 --- a/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs +++ b/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs @@ -11,5 +11,4 @@ fn main() { map(None); } -// EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff diff --git a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff deleted file mode 100644 index 51d26b08b2a1..000000000000 --- a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff +++ /dev/null @@ -1,52 +0,0 @@ -- // MIR for `map` before SimplifyLocals -+ // MIR for `map` after SimplifyLocals - - fn map(_1: Option>) -> Option> { - debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:8: +0:9 - let mut _0: std::option::Option>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:31: +0:46 - let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:9: +2:13 - let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15 - let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26 -- let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2 -- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2 -- let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2 - scope 1 { - debug x => _3; // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15 - } - - bb0: { -- _5 = const false; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12 -- _5 = const true; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12 - _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12 - switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:5: +1:12 - } - - bb1: { - StorageLive(_3); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15 - _3 = move ((_1 as Some).0: std::boxed::Box<()>); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15 - StorageLive(_4); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26 - _4 = move _3; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26 - Deinit(_0); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27 - ((_0 as Some).0: std::boxed::Box<()>) = move _4; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27 - discriminant(_0) = 1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27 - StorageDead(_4); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27 - StorageDead(_3); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27 - goto -> bb4; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27 - } - - bb2: { - unreachable; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12 - } - - bb3: { - Deinit(_0); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21 - discriminant(_0) = 0; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21 - goto -> bb4; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21 - } - - bb4: { -- _6 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2 - return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:2: +5:2 - } - } - diff --git a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff similarity index 100% rename from src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff rename to src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff diff --git a/src/test/mir-opt/slice-drop-shim.rs b/src/test/mir-opt/slice-drop-shim.rs index 0fd32906db6b..344c1af2c913 100644 --- a/src/test/mir-opt/slice-drop-shim.rs +++ b/src/test/mir-opt/slice-drop-shim.rs @@ -1,6 +1,6 @@ // compile-flags: -Zmir-opt-level=0 -// EMIT_MIR_FOR_EACH_BIT_WIDTH + // EMIT_MIR core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir fn main() { let _fn = std::ptr::drop_in_place::<[String]> as unsafe fn(_); diff --git a/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.64bit.mir b/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.64bit.mir deleted file mode 100644 index b4b317e84afb..000000000000 --- a/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.64bit.mir +++ /dev/null @@ -1,101 +0,0 @@ -// MIR for `std::ptr::drop_in_place` before AddMovesForPackedDrops - -fn std::ptr::drop_in_place(_1: *mut [String]) -> () { - let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _2: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _3: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _4: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _5: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _6: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _7: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _8: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _9: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _10: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _11: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _12: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _13: *mut std::string::String; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _14: bool; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _15: *mut [std::string::String]; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - - bb0: { - goto -> bb15; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb1: { - return; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb2 (cleanup): { - resume; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb3 (cleanup): { - _5 = &raw mut (*_1)[_4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - drop((*_5)) -> bb4; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb4 (cleanup): { - _6 = Eq(_4, _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - switchInt(move _6) -> [false: bb3, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb5: { - _7 = &raw mut (*_1)[_4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _4 = Add(move _4, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - drop((*_7)) -> [return: bb6, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb6: { - _8 = Eq(_4, _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - switchInt(move _8) -> [false: bb5, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb7: { - _4 = const 0_usize; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - goto -> bb6; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb8: { - goto -> bb7; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb9 (cleanup): { - _11 = _9; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - drop((*_11)) -> bb10; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb10 (cleanup): { - _12 = Eq(_9, _10); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - switchInt(move _12) -> [false: bb9, otherwise: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb11: { - _13 = _9; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _9 = Offset(move _9, const 1_usize); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - drop((*_13)) -> [return: bb12, unwind: bb10]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb12: { - _14 = Eq(_9, _10); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - switchInt(move _14) -> [false: bb11, otherwise: bb1]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb13: { - _15 = &raw mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _9 = move _15 as *mut std::string::String (Misc); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _10 = Offset(_9, move _3); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - goto -> bb12; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb14: { - goto -> bb13; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb15: { - _2 = SizeOf(std::string::String); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _3 = Len((*_1)); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - switchInt(move _2) -> [0_usize: bb8, otherwise: bb14]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } -} diff --git a/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.32bit.mir b/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir similarity index 100% rename from src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.32bit.mir rename to src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir diff --git a/src/test/mir-opt/unusual-item-types.rs b/src/test/mir-opt/unusual-item-types.rs index 670f61cd5ce3..9ef3d86472db 100644 --- a/src/test/mir-opt/unusual-item-types.rs +++ b/src/test/mir-opt/unusual-item-types.rs @@ -1,7 +1,7 @@ // Test that we don't ICE when trying to dump MIR for unusual item types and // that we don't create filenames containing `<` and `>` // compile-flags: -Zmir-opt-level=0 -// EMIT_MIR_FOR_EACH_BIT_WIDTH + struct A; diff --git a/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.64bit.mir b/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.64bit.mir deleted file mode 100644 index a72e00ecde75..000000000000 --- a/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.64bit.mir +++ /dev/null @@ -1,10 +0,0 @@ -// MIR for `E::V::{constant#0}` 0 mir_map - -E::V::{constant#0}: isize = { - let mut _0: isize; // return place in scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10 - - bb0: { - _0 = const 5_isize; // scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10 - return; // scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10 - } -} diff --git a/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.32bit.mir b/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.mir similarity index 100% rename from src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.32bit.mir rename to src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.mir diff --git a/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir deleted file mode 100644 index 0686af46ed58..000000000000 --- a/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir +++ /dev/null @@ -1,12 +0,0 @@ -// MIR for `Test::X` 0 mir_map - -fn Test::X(_1: usize) -> Test { - let mut _0: Test; // return place in scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6 - - bb0: { - Deinit(_0); // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6 - ((_0 as X).0: usize) = move _1; // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6 - discriminant(_0) = 0; // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6 - return; // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6 - } -} diff --git a/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.mir similarity index 100% rename from src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir rename to src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.mir diff --git a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir deleted file mode 100644 index 7ffd242e0dc3..000000000000 --- a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir +++ /dev/null @@ -1,39 +0,0 @@ -// MIR for `std::ptr::drop_in_place` before AddMovesForPackedDrops - -fn std::ptr::drop_in_place(_1: *mut Vec) -> () { - let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _2: &mut std::vec::Vec; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - let mut _3: (); // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - - bb0: { - goto -> bb6; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb1: { - return; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb2 (cleanup): { - resume; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb3: { - goto -> bb1; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb4 (cleanup): { - drop(((*_1).0: alloc::raw_vec::RawVec)) -> bb2; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb5: { - drop(((*_1).0: alloc::raw_vec::RawVec)) -> [return: bb3, unwind: bb2]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - } - - bb6: { - _2 = &mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - _3 = as Drop>::drop(move _2) -> [return: bb5, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:+0:1: +0:56 - // mir::Constant - // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL - // + literal: Const { ty: for<'r> fn(&'r mut Vec) { as Drop>::drop}, val: Value() } - } -} diff --git a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir similarity index 100% rename from src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir rename to src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir diff --git a/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir b/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir deleted file mode 100644 index e2633f61b5fe..000000000000 --- a/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir +++ /dev/null @@ -1,10 +0,0 @@ -// MIR for `::ASSOCIATED_CONSTANT` 0 mir_map - -const ::ASSOCIATED_CONSTANT: i32 = { - let mut _0: i32; // return place in scope 0 at $DIR/unusual-item-types.rs:+0:32: +0:35 - - bb0: { - _0 = const 2_i32; // scope 0 at $DIR/unusual-item-types.rs:+0:38: +0:39 - return; // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:39 - } -} diff --git a/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir b/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.mir similarity index 100% rename from src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir rename to src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.mir diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.64bit.diff b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.64bit.diff deleted file mode 100644 index eef7011149d3..000000000000 --- a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.64bit.diff +++ /dev/null @@ -1,55 +0,0 @@ -- // MIR for `change_loop_body` before ConstProp -+ // MIR for `change_loop_body` after ConstProp - - fn change_loop_body() -> () { - let mut _0: (); // return place in scope 0 at $DIR/while_let_loops.rs:+0:27: +0:27 - let mut _1: i32; // in scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15 - let mut _2: (); // in scope 0 at $DIR/while_let_loops.rs:+0:1: +6:2 - let mut _3: std::option::Option; // in scope 0 at $DIR/while_let_loops.rs:+2:28: +2:32 - let mut _4: isize; // in scope 0 at $DIR/while_let_loops.rs:+2:15: +2:25 - let mut _5: !; // in scope 0 at $DIR/while_let_loops.rs:+2:33: +5:6 - let mut _6: !; // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6 - let _7: (); // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6 - let mut _8: !; // in scope 0 at $DIR/while_let_loops.rs:+2:5: +5:6 - scope 1 { - debug _x => _1; // in scope 1 at $DIR/while_let_loops.rs:+1:9: +1:15 - scope 2 { - } - } - - bb0: { - StorageLive(_1); // scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15 - _1 = const 0_i32; // scope 0 at $DIR/while_let_loops.rs:+1:18: +1:19 - StorageLive(_3); // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32 - Deinit(_3); // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32 - discriminant(_3) = 0; // scope 2 at $DIR/while_let_loops.rs:+2:28: +2:32 -- _4 = discriminant(_3); // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25 -- switchInt(move _4) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25 -+ _4 = const 0_isize; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25 -+ switchInt(const 0_isize) -> [1_isize: bb1, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25 - } - - bb1: { - switchInt(((_3 as Some).0: u32)) -> [0_u32: bb2, otherwise: bb3]; // scope 2 at $DIR/while_let_loops.rs:+2:15: +2:25 - } - - bb2: { - _1 = const 1_i32; // scope 2 at $DIR/while_let_loops.rs:+3:9: +3:15 - nop; // scope 2 at $DIR/while_let_loops.rs:+4:9: +4:14 - goto -> bb4; // scope 2 at $DIR/while_let_loops.rs:+4:9: +4:14 - } - - bb3: { - StorageLive(_7); // scope 1 at $DIR/while_let_loops.rs:+2:5: +5:6 - nop; // scope 1 at $DIR/while_let_loops.rs:+2:5: +5:6 - StorageDead(_7); // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6 - goto -> bb4; // scope 1 at no-location - } - - bb4: { - StorageDead(_3); // scope 1 at $DIR/while_let_loops.rs:+5:5: +5:6 - StorageDead(_1); // scope 0 at $DIR/while_let_loops.rs:+6:1: +6:2 - return; // scope 0 at $DIR/while_let_loops.rs:+6:2: +6:2 - } - } - diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.32bit.diff b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff similarity index 100% rename from src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.32bit.diff rename to src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir deleted file mode 100644 index 15b0aece8f54..000000000000 --- a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir +++ /dev/null @@ -1,17 +0,0 @@ -// MIR for `change_loop_body` after PreCodegen - -fn change_loop_body() -> () { - let mut _0: (); // return place in scope 0 at $DIR/while_let_loops.rs:+0:27: +0:27 - let mut _1: i32; // in scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15 - scope 1 { - debug _x => _1; // in scope 1 at $DIR/while_let_loops.rs:+1:9: +1:15 - scope 2 { - } - } - - bb0: { - StorageLive(_1); // scope 0 at $DIR/while_let_loops.rs:+1:9: +1:15 - StorageDead(_1); // scope 0 at $DIR/while_let_loops.rs:+6:1: +6:2 - return; // scope 0 at $DIR/while_let_loops.rs:+6:2: +6:2 - } -} diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.32bit.mir b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir similarity index 100% rename from src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.32bit.mir rename to src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir diff --git a/src/test/mir-opt/while_let_loops.rs b/src/test/mir-opt/while_let_loops.rs index f320a218c852..fc56cd6985d6 100644 --- a/src/test/mir-opt/while_let_loops.rs +++ b/src/test/mir-opt/while_let_loops.rs @@ -1,6 +1,5 @@ // EMIT_MIR while_let_loops.change_loop_body.ConstProp.diff // EMIT_MIR while_let_loops.change_loop_body.PreCodegen.after.mir -// EMIT_MIR_FOR_EACH_BIT_WIDTH pub fn change_loop_body() { let mut _x = 0; From 76b494a9dd7ba5a151882afc7c85a75c5aeb94db Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 5 Sep 2022 06:44:33 +0000 Subject: [PATCH 4198/5092] Normalize before erasing late-bound regions in equal_up_to_regions --- .../src/transform/validate.rs | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index b79886258395..f42e8aa53d14 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -89,20 +89,21 @@ pub fn equal_up_to_regions<'tcx>( // Normalize lifetimes away on both sides, then compare. let normalize = |ty: Ty<'tcx>| { - let ty = ty.fold_with(&mut BottomUpFolder { - tcx, - // FIXME: We erase all late-bound lifetimes, but this is not fully correct. - // If you have a type like ` fn(&'a u32) as SomeTrait>::Assoc`, - // this is not necessarily equivalent to `::Assoc`, - // since one may have an `impl SomeTrait for fn(&32)` and - // `impl SomeTrait for fn(&'static u32)` at the same time which - // specify distinct values for Assoc. (See also #56105) - lt_op: |_| tcx.lifetimes.re_erased, - // Leave consts and types unchanged. - ct_op: |ct| ct, - ty_op: |ty| ty, - }); - tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty) + tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty).fold_with( + &mut BottomUpFolder { + tcx, + // FIXME: We erase all late-bound lifetimes, but this is not fully correct. + // If you have a type like ` fn(&'a u32) as SomeTrait>::Assoc`, + // this is not necessarily equivalent to `::Assoc`, + // since one may have an `impl SomeTrait for fn(&32)` and + // `impl SomeTrait for fn(&'static u32)` at the same time which + // specify distinct values for Assoc. (See also #56105) + lt_op: |_| tcx.lifetimes.re_erased, + // Leave consts and types unchanged. + ct_op: |ct| ct, + ty_op: |ty| ty, + }, + ) }; tcx.infer_ctxt().enter(|infcx| infcx.can_eq(param_env, normalize(src), normalize(dest)).is_ok()) } From 774cadfbfa3a1b0ae3a0f8b142b556124fd552b5 Mon Sep 17 00:00:00 2001 From: joboet Date: Mon, 5 Sep 2022 09:08:07 +0200 Subject: [PATCH 4199/5092] std: fix cleanup for uninitialized stdout (#101375) --- library/std/src/io/stdio.rs | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index dd4ff4952fde..91cff3217d21 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -607,15 +607,24 @@ pub fn stdout() -> Stdout { } } +// Flush the data and disable buffering during shutdown +// by replacing the line writer by one with zero +// buffering capacity. pub fn cleanup() { - // Flush the data and disable buffering during shutdown - // by replacing the line writer by one with zero - // buffering capacity. - // We use try_lock() instead of lock(), because someone - // might have leaked a StdoutLock, which would - // otherwise cause a deadlock here. - if let Some(lock) = STDOUT.get().and_then(ReentrantMutex::try_lock) { - *lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw()); + let mut initialized = false; + let stdout = STDOUT.get_or_init(|| { + initialized = true; + ReentrantMutex::new(RefCell::new(LineWriter::with_capacity(0, stdout_raw()))) + }); + + if !initialized { + // The buffer was previously initialized, overwrite it here. + // We use try_lock() instead of lock(), because someone + // might have leaked a StdoutLock, which would + // otherwise cause a deadlock here. + if let Some(lock) = stdout.try_lock() { + *lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw()); + } } } From 265c75c53ffbc2c4cd13014e958af6e2f743e9bf Mon Sep 17 00:00:00 2001 From: Ryo Yoshida Date: Mon, 5 Sep 2022 18:35:50 +0900 Subject: [PATCH 4200/5092] fix: sort all bounds on trait object types --- crates/hir-ty/src/chalk_ext.rs | 2 + crates/hir-ty/src/lower.rs | 73 +++++++++++++++++++++---------- crates/hir-ty/src/tests/traits.rs | 28 ++++++++++++ 3 files changed, 81 insertions(+), 22 deletions(-) diff --git a/crates/hir-ty/src/chalk_ext.rs b/crates/hir-ty/src/chalk_ext.rs index a9c124b42dc2..4a5533c6487e 100644 --- a/crates/hir-ty/src/chalk_ext.rs +++ b/crates/hir-ty/src/chalk_ext.rs @@ -164,6 +164,8 @@ impl TyExt for Ty { fn dyn_trait(&self) -> Option { let trait_ref = match self.kind(Interner) { + // The principal trait bound should be the first element of the bounds. This is an + // invariant ensured by `TyLoweringContext::lower_dyn_trait()`. TyKind::Dyn(dyn_ty) => dyn_ty.bounds.skip_binders().interned().get(0).and_then(|b| { match b.skip_binders() { WhereClause::Implemented(trait_ref) => Some(trait_ref), diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 4a37a7945330..532544fee595 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -981,43 +981,72 @@ impl<'a> TyLoweringContext<'a> { fn lower_dyn_trait(&self, bounds: &[Interned]) -> Ty { let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner); + // INVARIANT: The principal trait bound must come first. Others may be in any order but + // should be in the same order for the same set but possibly different order of bounds in + // the input. + // This invariant is used by `TyExt::dyn_trait()` and chalk. let bounds = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { - let bounds = - bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)); + let mut bounds: Vec<_> = bounds + .iter() + .flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)) + .collect(); - let mut auto_traits = SmallVec::<[_; 8]>::new(); - let mut regular_traits = SmallVec::<[_; 2]>::new(); - let mut other_bounds = SmallVec::<[_; 8]>::new(); - for bound in bounds { - if let Some(id) = bound.trait_id() { - if ctx.db.trait_data(from_chalk_trait_id(id)).is_auto { - auto_traits.push(bound); - } else { - regular_traits.push(bound); + let mut multiple_regular_traits = false; + let mut multiple_same_projection = false; + bounds.sort_unstable_by(|lhs, rhs| { + use std::cmp::Ordering; + match (lhs.skip_binders(), rhs.skip_binders()) { + (WhereClause::Implemented(lhs), WhereClause::Implemented(rhs)) => { + let lhs_id = lhs.trait_id; + let lhs_is_auto = ctx.db.trait_data(from_chalk_trait_id(lhs_id)).is_auto; + let rhs_id = rhs.trait_id; + let rhs_is_auto = ctx.db.trait_data(from_chalk_trait_id(rhs_id)).is_auto; + + if !lhs_is_auto && !rhs_is_auto { + multiple_regular_traits = true; + } + // Note that the ordering here is important; this ensures the invariant + // mentioned above. + (lhs_is_auto, lhs_id).cmp(&(rhs_is_auto, rhs_id)) } - } else { - other_bounds.push(bound); + (WhereClause::Implemented(_), _) => Ordering::Less, + (_, WhereClause::Implemented(_)) => Ordering::Greater, + (WhereClause::AliasEq(lhs), WhereClause::AliasEq(rhs)) => { + match (&lhs.alias, &rhs.alias) { + (AliasTy::Projection(lhs_proj), AliasTy::Projection(rhs_proj)) => { + // We only compare the `associated_ty_id`s. We shouldn't have + // multiple bounds for an associated type in the correct Rust code, + // and if we do, we error out. + if lhs_proj.associated_ty_id == rhs_proj.associated_ty_id { + multiple_same_projection = true; + } + lhs_proj.associated_ty_id.cmp(&rhs_proj.associated_ty_id) + } + // We don't produce `AliasTy::Opaque`s yet. + _ => unreachable!(), + } + } + // We don't produce `WhereClause::{TypeOutlives, LifetimeOutlives}` yet. + _ => unreachable!(), } - } + }); - if regular_traits.len() > 1 { + if multiple_regular_traits || multiple_same_projection { return None; } - auto_traits.sort_unstable_by_key(|b| b.trait_id().unwrap()); - auto_traits.dedup(); + // As multiple occurrences of the same auto traits *are* permitted, we dedulicate the + // bounds. We shouldn't have repeated elements besides auto traits at this point. + bounds.dedup(); - Some(QuantifiedWhereClauses::from_iter( - Interner, - regular_traits.into_iter().chain(other_bounds).chain(auto_traits), - )) + Some(QuantifiedWhereClauses::from_iter(Interner, bounds)) }); if let Some(bounds) = bounds { let bounds = crate::make_single_type_binders(bounds); TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner) } else { - // FIXME: report error (additional non-auto traits) + // FIXME: report error (additional non-auto traits or associated type rebound) TyKind::Error.intern(Interner) } } diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs index e67c27aa2db9..21a86319763f 100644 --- a/crates/hir-ty/src/tests/traits.rs +++ b/crates/hir-ty/src/tests/traits.rs @@ -3900,6 +3900,34 @@ fn g(t: &(dyn Sync + T + Send)) { ); } +#[test] +fn dyn_multiple_projection_bounds() { + check_no_mismatches( + r#" +trait Trait { + type T; + type U; +} + +fn f(t: &dyn Trait) {} +fn g(t: &dyn Trait) { + f(t); +} + "#, + ); + + check_types( + r#" +trait Trait { + type T; +} + +fn f(t: &dyn Trait) {} + //^&{unknown} + "#, + ); +} + #[test] fn dyn_duplicate_auto_trait() { check_no_mismatches( From 016626ab129f1ef25be66f12b0b66fcd1f093d60 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Mon, 5 Sep 2022 19:45:53 +0900 Subject: [PATCH 4201/5092] suggest introducing an explicit lifetime if it does not exist --- .../src/infer/error_reporting/mod.rs | 28 +++++++++++++------ ...introducing-and-adding-missing-lifetime.rs | 9 ++++++ ...oducing-and-adding-missing-lifetime.stderr | 23 +++++++++++++++ .../missing-lifetimes-in-signature-2.stderr | 4 +-- .../missing-lifetimes-in-signature.stderr | 18 ++++++------ 5 files changed, 63 insertions(+), 19 deletions(-) create mode 100644 src/test/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.rs create mode 100644 src/test/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.stderr diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 6dad9873d613..d9252d426d82 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2395,19 +2395,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { type_param_span: Option<(Span, bool)>, bound_kind: GenericKind<'tcx>, sub: S, + add_lt_sugg: Option<(Span, String)>, ) { let msg = "consider adding an explicit lifetime bound"; if let Some((sp, has_lifetimes)) = type_param_span { let suggestion = if has_lifetimes { format!(" + {}", sub) } else { format!(": {}", sub) }; - err.span_suggestion_verbose( - sp, - &format!("{}...", msg), - suggestion, + let mut suggestions = vec![(sp, suggestion)]; + if let Some(add_lt_sugg) = add_lt_sugg { + suggestions.push(add_lt_sugg); + } + err.multipart_suggestion_verbose( + format!("{msg}..."), + suggestions, Applicability::MaybeIncorrect, // Issue #41966 ); } else { - let consider = format!("{} `{}: {}`...", msg, bound_kind, sub,); + let consider = format!("{} `{}: {}`...", msg, bound_kind, sub); err.help(&consider); } } @@ -2423,7 +2427,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }; let mut sugg = vec![(sp, suggestion), (span.shrink_to_hi(), format!(" + {}", new_lt))]; - if let Some(lt) = add_lt_sugg { + if let Some(lt) = add_lt_sugg.clone() { sugg.push(lt); sugg.rotate_right(1); } @@ -2529,7 +2533,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // for the bound is not suitable for suggestions when `-Zverbose` is set because it // uses `Debug` output, so we handle it specially here so that suggestions are // always correct. - binding_suggestion(&mut err, type_param_span, bound_kind, name); + binding_suggestion(&mut err, type_param_span, bound_kind, name, None); err } @@ -2542,7 +2546,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "{} may not live long enough", labeled_user_string ); - binding_suggestion(&mut err, type_param_span, bound_kind, "'static"); + binding_suggestion(&mut err, type_param_span, bound_kind, "'static", None); err } @@ -2576,7 +2580,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { new_binding_suggestion(&mut err, type_param_span); } _ => { - binding_suggestion(&mut err, type_param_span, bound_kind, new_lt); + binding_suggestion( + &mut err, + type_param_span, + bound_kind, + new_lt, + add_lt_sugg, + ); } } } diff --git a/src/test/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.rs b/src/test/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.rs new file mode 100644 index 000000000000..645bc7db0dda --- /dev/null +++ b/src/test/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.rs @@ -0,0 +1,9 @@ +fn no_restriction(x: &()) -> &() { + with_restriction::(x) //~ ERROR the parameter type `T` may not live long enough +} + +fn with_restriction<'b, T: 'b>(x: &'b ()) -> &'b () { + x +} + +fn main() {} diff --git a/src/test/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.stderr b/src/test/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.stderr new file mode 100644 index 000000000000..a8b0996d8b0c --- /dev/null +++ b/src/test/ui/lifetimes/suggest-introducing-and-adding-missing-lifetime.stderr @@ -0,0 +1,23 @@ +error[E0311]: the parameter type `T` may not live long enough + --> $DIR/suggest-introducing-and-adding-missing-lifetime.rs:2:5 + | +LL | with_restriction::(x) + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: the parameter type `T` must be valid for the anonymous lifetime defined here... + --> $DIR/suggest-introducing-and-adding-missing-lifetime.rs:1:25 + | +LL | fn no_restriction(x: &()) -> &() { + | ^^^ +note: ...so that the type `T` will meet its required lifetime bounds + --> $DIR/suggest-introducing-and-adding-missing-lifetime.rs:2:5 + | +LL | with_restriction::(x) + | ^^^^^^^^^^^^^^^^^^^^^ +help: consider adding an explicit lifetime bound... + | +LL | fn no_restriction<'a, T: 'a>(x: &()) -> &() { + | +++ ++++ + +error: aborting due to previous error + diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr index 0212c2d712cb..e5d2ead6ad67 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr @@ -22,8 +22,8 @@ LL | | }); | |______^ help: consider adding an explicit lifetime bound... | -LL | fn func(foo: &Foo, t: T) { - | ++++ +LL | fn func<'a, T: Test + 'a>(foo: &Foo, t: T) { + | +++ ++++ error: aborting due to previous error diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index 0d749f04bea7..ed1b91676a21 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -47,8 +47,10 @@ LL | | } | |_____^ help: consider adding an explicit lifetime bound... | -LL | G: Get + 'a, - | ++++ +LL ~ fn bar<'a, G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ +LL | where +LL ~ G: Get + 'a, + | error[E0311]: the parameter type `G` may not live long enough --> $DIR/missing-lifetimes-in-signature.rs:52:5 @@ -74,8 +76,8 @@ LL | | } | |_____^ help: consider adding an explicit lifetime bound... | -LL | fn qux<'a, G: 'a + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ - | ++++ +LL | fn qux<'b, 'a, G: 'a + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + | +++ ++++ error[E0311]: the parameter type `G` may not live long enough --> $DIR/missing-lifetimes-in-signature.rs:61:9 @@ -101,8 +103,8 @@ LL | | } | |_________^ help: consider adding an explicit lifetime bound... | -LL | fn qux<'b, G: Get + 'b + 'c, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { - | ++++ +LL | fn qux<'c, 'b, G: Get + 'b + 'c, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { + | +++ ++++ error[E0311]: the parameter type `G` may not live long enough --> $DIR/missing-lifetimes-in-signature.rs:73:5 @@ -130,8 +132,8 @@ LL | | } | |_____^ help: consider adding an explicit lifetime bound... | -LL | fn bat<'a, G: 'a + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a - | ++++ +LL | fn bat<'b, 'a, G: 'a + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a + | +++ ++++ error[E0621]: explicit lifetime required in the type of `dest` --> $DIR/missing-lifetimes-in-signature.rs:73:5 From 2d8460ef43d902f34ba2133fe38f66ee8d2fdafc Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 15 Jul 2022 19:17:10 +0200 Subject: [PATCH 4202/5092] Add matrix based test for documenting the let / let else temporary drop order The drop order of let and let else is supposed to be the same, and in order to ensure this, the test checks that this holds for the given list of cases. The test also ensures that we drop the temporaries of the condition before executing the else block. We made the test matrix based so it can check all the possible combinations and find out possible edge cases. --- src/test/ui/let-else/let-else-drop-order.rs | 270 ++++++++++++++++++ .../let-else/let-else-drop-order.run.stdout | 51 ++++ 2 files changed, 321 insertions(+) create mode 100644 src/test/ui/let-else/let-else-drop-order.rs create mode 100644 src/test/ui/let-else/let-else-drop-order.run.stdout diff --git a/src/test/ui/let-else/let-else-drop-order.rs b/src/test/ui/let-else/let-else-drop-order.rs new file mode 100644 index 000000000000..0054f3d4182e --- /dev/null +++ b/src/test/ui/let-else/let-else-drop-order.rs @@ -0,0 +1,270 @@ +// run-pass +// edition:2021 +// check-run-results +// +// Drop order tests for let else +// +// Mostly this ensures two things: +// 1. That let and let else temporary drop order is the same. +// This is a specific design request: https://github.com/rust-lang/rust/pull/93628#issuecomment-1047140316 +// 2. That the else block truly only runs after the +// temporaries have dropped. +// +// We also print some nice tables for an overview by humans. +// Changes in those tables are considered breakages, but the +// important properties 1 and 2 are also enforced by the code. +// This is important as it's easy to update the stdout file +// with a --bless and miss the impact of that change. + +#![feature(let_else)] +#![allow(irrefutable_let_patterns)] + +use std::cell::RefCell; +use std::rc::Rc; + +#[derive(Clone)] +struct DropAccountant(Rc>>>); + +impl DropAccountant { + fn new() -> Self { + Self(Default::default()) + } + fn build_droppy(&self, v: u32) -> Droppy { + Droppy(self.clone(), v) + } + fn build_droppy_enum_none(&self, _v: u32) -> ((), DroppyEnum) { + ((), DroppyEnum::None(self.clone())) + } + fn new_list(&self, s: impl ToString) { + self.0.borrow_mut().push(vec![s.to_string()]); + } + fn push(&self, s: impl ToString) { + let s = s.to_string(); + let mut accounts = self.0.borrow_mut(); + accounts.last_mut().unwrap().push(s); + } + fn print_table(&self) { + println!(); + + let accounts = self.0.borrow(); + let before_last = &accounts[accounts.len() - 2]; + let last = &accounts[accounts.len() - 1]; + let before_last = get_comma_list(before_last); + let last = get_comma_list(last); + const LINES: &[&str] = &[ + "vanilla", + "&", + "&mut", + "move", + "fn(this)", + "tuple", + "array", + "ref &", + "ref mut &mut", + ]; + let max_len = LINES.iter().map(|v| v.len()).max().unwrap(); + let max_len_before = before_last.iter().map(|v| v.len()).max().unwrap(); + let max_len_last = last.iter().map(|v| v.len()).max().unwrap(); + + println!( + "| {: Vec { + std::iter::once(sl[0].clone()) + .chain(sl[1..].chunks(2).map(|c| c.join(","))) + .collect::>() +} + +struct Droppy(DropAccountant, T); + +impl Drop for Droppy { + fn drop(&mut self) { + self.0.push("drop"); + } +} + +#[allow(dead_code)] +enum DroppyEnum { + Some(DropAccountant, T), + None(DropAccountant), +} + +impl Drop for DroppyEnum { + fn drop(&mut self) { + match self { + DroppyEnum::Some(acc, _inner) => acc, + DroppyEnum::None(acc) => acc, + } + .push("drop"); + } +} + +macro_rules! nestings_with { + ($construct:ident, $binding:pat, $exp:expr) => { + // vanilla: + $construct!($binding, $exp.1); + + // &: + $construct!(&$binding, &$exp.1); + + // &mut: + $construct!(&mut $binding, &mut ($exp.1)); + + { + // move: + let w = $exp; + $construct!( + $binding, + { + let w = w; + w + } + .1 + ); + } + + // fn(this): + $construct!($binding, std::convert::identity($exp).1); + }; +} + +macro_rules! nestings { + ($construct:ident, $binding:pat, $exp:expr) => { + nestings_with!($construct, $binding, $exp); + + // tuple: + $construct!(($binding, 77), ($exp.1, 77)); + + // array: + $construct!([$binding], [$exp.1]); + }; +} + +macro_rules! let_else { + ($acc:expr, $v:expr, $binding:pat, $build:ident) => { + let acc = $acc; + let v = $v; + + macro_rules! let_else_construct { + ($arg:pat, $exp:expr) => { + loop { + let $arg = $exp else { + acc.push("else"); + break; + }; + acc.push("body"); + break; + } + }; + } + nestings!(let_else_construct, $binding, acc.$build(v)); + // ref &: + let_else_construct!($binding, &acc.$build(v).1); + + // ref mut &mut: + let_else_construct!($binding, &mut acc.$build(v).1); + }; +} + +macro_rules! let_ { + ($acc:expr, $binding:tt) => { + let acc = $acc; + + macro_rules! let_construct { + ($arg:pat, $exp:expr) => {{ + let $arg = $exp; + acc.push("body"); + }}; + } + let v = 0; + { + nestings_with!(let_construct, $binding, acc.build_droppy(v)); + } + acc.push("n/a"); + acc.push("n/a"); + acc.push("n/a"); + acc.push("n/a"); + + // ref &: + let_construct!($binding, &acc.build_droppy(v).1); + + // ref mut &mut: + let_construct!($binding, &mut acc.build_droppy(v).1); + }; +} + +fn main() { + let acc = DropAccountant::new(); + + println!(" --- matching cases ---"); + + // Ensure that let and let else have the same behaviour + acc.new_list("let _"); + let_!(&acc, _); + acc.new_list("let else _"); + let_else!(&acc, 0, _, build_droppy); + acc.assert_equality_last_two_lists(); + acc.print_table(); + + // Ensure that let and let else have the same behaviour + acc.new_list("let _v"); + let_!(&acc, _v); + acc.new_list("let else _v"); + let_else!(&acc, 0, _v, build_droppy); + acc.assert_equality_last_two_lists(); + acc.print_table(); + + println!(); + + println!(" --- mismatching cases ---"); + + acc.new_list("let else _ mismatch"); + let_else!(&acc, 1, DroppyEnum::Some(_, _), build_droppy_enum_none); + acc.new_list("let else _v mismatch"); + let_else!(&acc, 1, DroppyEnum::Some(_, _v), build_droppy_enum_none); + acc.print_table(); + // This ensures that we always drop before visiting the else case + acc.assert_all_equal_to("drop,else"); + + acc.new_list("let else 0 mismatch"); + let_else!(&acc, 1, 0, build_droppy); + acc.new_list("let else 0 mismatch"); + let_else!(&acc, 1, 0, build_droppy); + acc.print_table(); + // This ensures that we always drop before visiting the else case + acc.assert_all_equal_to("drop,else"); +} diff --git a/src/test/ui/let-else/let-else-drop-order.run.stdout b/src/test/ui/let-else/let-else-drop-order.run.stdout new file mode 100644 index 000000000000..01cf2f73e17c --- /dev/null +++ b/src/test/ui/let-else/let-else-drop-order.run.stdout @@ -0,0 +1,51 @@ + --- matching cases --- + +| construct | let _ | let else _ | +| ------------ | --------- | ---------- | +| vanilla | drop,body | drop,body | +| & | body,drop | body,drop | +| &mut | body,drop | body,drop | +| move | drop,body | drop,body | +| fn(this) | drop,body | drop,body | +| tuple | n/a,n/a | drop,body | +| array | n/a,n/a | drop,body | +| ref & | body,drop | body,drop | +| ref mut &mut | body,drop | body,drop | + +| construct | let _v | let else _v | +| ------------ | --------- | ----------- | +| vanilla | drop,body | drop,body | +| & | body,drop | body,drop | +| &mut | body,drop | body,drop | +| move | drop,body | drop,body | +| fn(this) | drop,body | drop,body | +| tuple | n/a,n/a | drop,body | +| array | n/a,n/a | drop,body | +| ref & | body,drop | body,drop | +| ref mut &mut | body,drop | body,drop | + + --- mismatching cases --- + +| construct | let else _ mismatch | let else _v mismatch | +| ------------ | ------------------- | -------------------- | +| vanilla | drop,else | drop,else | +| & | drop,else | drop,else | +| &mut | drop,else | drop,else | +| move | drop,else | drop,else | +| fn(this) | drop,else | drop,else | +| tuple | drop,else | drop,else | +| array | drop,else | drop,else | +| ref & | drop,else | drop,else | +| ref mut &mut | drop,else | drop,else | + +| construct | let else 0 mismatch | let else 0 mismatch | +| ------------ | ------------------- | ------------------- | +| vanilla | drop,else | drop,else | +| & | drop,else | drop,else | +| &mut | drop,else | drop,else | +| move | drop,else | drop,else | +| fn(this) | drop,else | drop,else | +| tuple | drop,else | drop,else | +| array | drop,else | drop,else | +| ref & | drop,else | drop,else | +| ref mut &mut | drop,else | drop,else | From 037ab1d1833f8396aca8fc98074e667597129709 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 14 Aug 2022 18:25:19 +0200 Subject: [PATCH 4203/5092] Remove generics_def_id_map from the resolver. --- compiler/rustc_ast_lowering/src/item.rs | 1 + compiler/rustc_ast_lowering/src/lib.rs | 83 +++++++++++-------------- compiler/rustc_middle/src/ty/mod.rs | 5 -- compiler/rustc_resolve/src/lib.rs | 8 --- 4 files changed, 39 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index fd338ffc0c5e..175209b2c233 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -85,6 +85,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { allow_try_trait: Some([sym::try_trait_v2, sym::yeet_desugar_details][..].into()), allow_gen_future: Some([sym::gen_future][..].into()), allow_into_future: Some([sym::into_future][..].into()), + generics_def_id_map: Default::default(), }; lctx.with_hir_id_owner(owner, |lctx| f(lctx)); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 9a960356a85f..4b63d74dd92b 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -132,6 +132,12 @@ struct LoweringContext<'a, 'hir> { allow_try_trait: Option>, allow_gen_future: Option>, allow_into_future: Option>, + + /// Mapping from generics `def_id`s to TAIT generics `def_id`s. + /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic + /// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this + /// field from the original parameter 'a to the new parameter 'a1. + generics_def_id_map: Vec>, } trait ResolverAstLoweringExt { @@ -142,12 +148,6 @@ trait ResolverAstLoweringExt { fn get_lifetime_res(&self, id: NodeId) -> Option; fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)>; fn decl_macro_kind(&self, def_id: LocalDefId) -> MacroKind; - /// Record the map from `from` local def id to `to` local def id, on `generics_def_id_map` - /// field. - fn record_def_id_remap(&mut self, from: LocalDefId, to: LocalDefId); - /// Get the previously recorded `to` local def id given the `from` local def id, obtained using - /// `generics_def_id_map` field. - fn get_remapped_def_id(&self, local_def_id: LocalDefId) -> LocalDefId; } impl ResolverAstLoweringExt for ResolverAstLowering { @@ -215,41 +215,6 @@ impl ResolverAstLoweringExt for ResolverAstLowering { fn decl_macro_kind(&self, def_id: LocalDefId) -> MacroKind { self.builtin_macro_kinds.get(&def_id).copied().unwrap_or(MacroKind::Bang) } - - /// Push a remapping into the top-most map. - /// Panics if no map has been pushed. - /// Remapping is used when creating lowering `-> impl Trait` return - /// types to create the resulting opaque type. - #[instrument(level = "debug", skip(self))] - fn record_def_id_remap(&mut self, from: LocalDefId, to: LocalDefId) { - self.generics_def_id_map.last_mut().expect("no map pushed").insert(from, to); - } - - fn get_remapped_def_id(&self, mut local_def_id: LocalDefId) -> LocalDefId { - // `generics_def_id_map` is a stack of mappings. As we go deeper in impl traits nesting we - // push new mappings so we need to try first the latest mappings, hence `iter().rev()`. - // - // Consider: - // - // `fn test<'a, 'b>() -> impl Trait<&'a u8, Ty = impl Sized + 'b> {}` - // - // We would end with a generics_def_id_map like: - // - // `[[fn#'b -> impl_trait#'b], [fn#'b -> impl_sized#'b]]` - // - // for the opaque type generated on `impl Sized + 'b`, We want the result to be: - // impl_sized#'b, so iterating forward is the wrong thing to do. - for map in self.generics_def_id_map.iter().rev() { - if let Some(r) = map.get(&local_def_id) { - debug!("def_id_remapper: remapping from `{local_def_id:?}` to `{r:?}`"); - local_def_id = *r; - } else { - debug!("def_id_remapper: no remapping for `{local_def_id:?}` found in map"); - } - } - - local_def_id - } } /// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree, @@ -522,13 +487,41 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.resolver .node_id_to_def_id .get(&node) - .map(|local_def_id| self.resolver.get_remapped_def_id(*local_def_id)) + .map(|local_def_id| self.get_remapped_def_id(*local_def_id)) } fn local_def_id(&self, node: NodeId) -> LocalDefId { self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node)) } + /// Get the previously recorded `to` local def id given the `from` local def id, obtained using + /// `generics_def_id_map` field. + fn get_remapped_def_id(&self, mut local_def_id: LocalDefId) -> LocalDefId { + // `generics_def_id_map` is a stack of mappings. As we go deeper in impl traits nesting we + // push new mappings so we need to try first the latest mappings, hence `iter().rev()`. + // + // Consider: + // + // `fn test<'a, 'b>() -> impl Trait<&'a u8, Ty = impl Sized + 'b> {}` + // + // We would end with a generics_def_id_map like: + // + // `[[fn#'b -> impl_trait#'b], [fn#'b -> impl_sized#'b]]` + // + // for the opaque type generated on `impl Sized + 'b`, We want the result to be: + // impl_sized#'b, so iterating forward is the wrong thing to do. + for map in self.generics_def_id_map.iter().rev() { + if let Some(r) = map.get(&local_def_id) { + debug!("def_id_remapper: remapping from `{local_def_id:?}` to `{r:?}`"); + local_def_id = *r; + } else { + debug!("def_id_remapper: no remapping for `{local_def_id:?}` found in map"); + } + } + + local_def_id + } + /// Freshen the `LoweringContext` and ready it to lower a nested item. /// The lowered item is registered into `self.children`. /// @@ -597,9 +590,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { remap: FxHashMap, f: impl FnOnce(&mut Self) -> R, ) -> R { - self.resolver.generics_def_id_map.push(remap); + self.generics_def_id_map.push(remap); let res = f(self); - self.resolver.generics_def_id_map.pop(); + self.generics_def_id_map.pop(); res } @@ -2024,7 +2017,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let name = match res { LifetimeRes::Param { param, .. } => { let p_name = ParamName::Plain(ident); - let param = self.resolver.get_remapped_def_id(param); + let param = self.get_remapped_def_id(param); hir::LifetimeName::Param(param, p_name) } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index ed04e7660339..8235a05fb53f 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -178,11 +178,6 @@ pub struct ResolverAstLowering { pub label_res_map: NodeMap, /// Resolutions for lifetimes. pub lifetimes_res_map: NodeMap, - /// Mapping from generics `def_id`s to TAIT generics `def_id`s. - /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic - /// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this - /// field from the original parameter 'a to the new parameter 'a1. - pub generics_def_id_map: Vec>, /// Lifetime parameters that lowering will have to introduce. pub extra_lifetime_params_map: NodeMap>, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index a15a0c298a95..aaa9ae6f3251 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -911,11 +911,6 @@ pub struct Resolver<'a> { label_res_map: NodeMap, /// Resolutions for lifetimes. lifetimes_res_map: NodeMap, - /// Mapping from generics `def_id`s to TAIT generics `def_id`s. - /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic - /// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this - /// field from the original parameter 'a to the new parameter 'a1. - generics_def_id_map: Vec>, /// Lifetime parameters that lowering will have to introduce. extra_lifetime_params_map: NodeMap>, @@ -1278,7 +1273,6 @@ impl<'a> Resolver<'a> { import_res_map: Default::default(), label_res_map: Default::default(), lifetimes_res_map: Default::default(), - generics_def_id_map: Vec::new(), extra_lifetime_params_map: Default::default(), extern_crate_map: Default::default(), reexport_map: FxHashMap::default(), @@ -1445,7 +1439,6 @@ impl<'a> Resolver<'a> { import_res_map: self.import_res_map, label_res_map: self.label_res_map, lifetimes_res_map: self.lifetimes_res_map, - generics_def_id_map: self.generics_def_id_map, extra_lifetime_params_map: self.extra_lifetime_params_map, next_node_id: self.next_node_id, node_id_to_def_id: self.node_id_to_def_id, @@ -1490,7 +1483,6 @@ impl<'a> Resolver<'a> { import_res_map: self.import_res_map.clone(), label_res_map: self.label_res_map.clone(), lifetimes_res_map: self.lifetimes_res_map.clone(), - generics_def_id_map: self.generics_def_id_map.clone(), extra_lifetime_params_map: self.extra_lifetime_params_map.clone(), next_node_id: self.next_node_id.clone(), node_id_to_def_id: self.node_id_to_def_id.clone(), From ce3d526027669a3a6accaa34a789301dc4dc64e4 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 5 Sep 2022 05:57:46 -0700 Subject: [PATCH 4204/5092] Add `const_extern_fn` to 1.62 release notes. --- RELEASES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 72b2c16a01f8..89fd4f2703b5 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -217,6 +217,7 @@ Language - [Fix constants not getting dropped if part of a diverging expression][94775] - [Support unit struct/enum variant in destructuring assignment][95380] - [Remove mutable_borrow_reservation_conflict lint and allow the code pattern][96268] +- [`const` functions may now specify `extern "C"` or `extern "Rust"`][95346] Compiler -------- @@ -306,6 +307,7 @@ and related tools. [94872]: https://github.com/rust-lang/rust/pull/94872/ [95006]: https://github.com/rust-lang/rust/pull/95006/ [95035]: https://github.com/rust-lang/rust/pull/95035/ +[95346]: https://github.com/rust-lang/rust/pull/95346/ [95372]: https://github.com/rust-lang/rust/pull/95372/ [95380]: https://github.com/rust-lang/rust/pull/95380/ [95431]: https://github.com/rust-lang/rust/pull/95431/ From cbf3b2432e612fca1db0f320003745d7adc431b9 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Wed, 31 Aug 2022 13:18:46 +0200 Subject: [PATCH 4205/5092] Add test for #98294 Add a test to make that the failure condition for this pattern is optimized away. Fixes #98294. --- ...issue-98294-get-mut-copy-from-slice-opt.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/test/codegen/issue-98294-get-mut-copy-from-slice-opt.rs diff --git a/src/test/codegen/issue-98294-get-mut-copy-from-slice-opt.rs b/src/test/codegen/issue-98294-get-mut-copy-from-slice-opt.rs new file mode 100644 index 000000000000..7da29cd79529 --- /dev/null +++ b/src/test/codegen/issue-98294-get-mut-copy-from-slice-opt.rs @@ -0,0 +1,19 @@ +// min-llvm-version: 15.0.0 +// ignore-debug: The debug assertions get in the way +// compile-flags: -O + +#![crate_type = "lib"] + +// There should be no calls to panic / len_mismatch_fail. + +#[no_mangle] +pub fn test(a: &mut [u8], offset: usize, bytes: &[u8]) { + // CHECK-LABEL: @test( + // CHECK-NOT: call + // CHECK: call void @llvm.memcpy + // CHECK-NOT: call + // CHECK: } + if let Some(dst) = a.get_mut(offset..offset + bytes.len()) { + dst.copy_from_slice(bytes); + } +} From 87c6da363f04fe2e81eedaff6289f5cacb6e5538 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Thu, 1 Sep 2022 13:27:31 +0900 Subject: [PATCH 4206/5092] separate the receiver from arguments in HIR --- compiler/rustc_ast_lowering/src/expr.rs | 8 +++---- .../src/diagnostics/mutability_errors.rs | 12 ++++------ .../src/diagnostics/region_errors.rs | 8 +++---- compiler/rustc_hir/src/hir.rs | 4 ++-- compiler/rustc_hir/src/intravisit.rs | 3 ++- compiler/rustc_hir_pretty/src/lib.rs | 19 ++++++++++------ .../infer/error_reporting/need_type_info.rs | 10 ++++----- compiler/rustc_lint/src/array_into_iter.rs | 4 ++-- compiler/rustc_lint/src/builtin.rs | 4 ++-- compiler/rustc_lint/src/internal.rs | 2 +- compiler/rustc_lint/src/methods.rs | 18 +++++++++------ compiler/rustc_lint/src/noop_method_call.rs | 3 +-- compiler/rustc_lint/src/types.rs | 10 ++++----- compiler/rustc_mir_build/src/thir/cx/expr.rs | 9 +++++--- compiler/rustc_passes/src/liveness.rs | 7 ++++-- .../rustc_save_analysis/src/dump_visitor.rs | 6 ++++- compiler/rustc_typeck/src/check/demand.rs | 12 +++++----- compiler/rustc_typeck/src/check/expr.rs | 22 +++++++------------ .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 2 +- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 18 ++++++++++----- .../src/check/fn_ctxt/suggestions.rs | 2 +- .../drop_ranges/cfg_build.rs | 3 ++- .../src/check/method/prelude2021.rs | 1 - .../rustc_typeck/src/check/method/suggest.rs | 11 +++++----- compiler/rustc_typeck/src/expr_use_visitor.rs | 3 ++- .../wrong_number_of_generic_args.rs | 8 +++---- src/librustdoc/scrape_examples.rs | 2 +- 27 files changed, 115 insertions(+), 96 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 7df3520422c1..8a45cd22953f 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -68,10 +68,10 @@ impl<'hir> LoweringContext<'_, 'hir> { ParenthesizedGenericArgs::Err, ImplTraitContext::Disallowed(ImplTraitPosition::Path), )); - let args = self.arena.alloc_from_iter( - [&*receiver].into_iter().chain(args.iter()).map(|x| self.lower_expr_mut(x)), - ); - hir::ExprKind::MethodCall(hir_seg, args, self.lower_span(span)) + let receiver = self.lower_expr(receiver); + let args = + self.arena.alloc_from_iter(args.iter().map(|x| self.lower_expr_mut(x))); + hir::ExprKind::MethodCall(hir_seg, receiver, args, self.lower_span(span)) } ExprKind::Binary(binop, ref lhs, ref rhs) => { let binop = self.lower_binop(binop); diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index dd9590016b99..f168a44c0435 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -711,8 +711,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { Applicability::MachineApplicable, ); self.suggested = true; - } else if let hir::ExprKind::MethodCall(_path, args @ [_, ..], sp) = expr.kind - && let hir::ExprKind::Index(val, index) = args[0].kind + } else if let hir::ExprKind::MethodCall(_path, receiver, _, sp) = expr.kind + && let hir::ExprKind::Index(val, index) = receiver.kind && expr.span == self.assign_span { // val[index].path(args..); @@ -724,7 +724,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { ".get_mut(".to_string(), ), ( - index.span.shrink_to_hi().with_hi(args[0].span.hi()), + index.span.shrink_to_hi().with_hi(receiver.span.hi()), ").map(|val| val".to_string(), ), (sp.shrink_to_hi(), ")".to_string()), @@ -911,11 +911,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { [ Expr { kind: - MethodCall( - path_segment, - _args, - span, - ), + MethodCall(path_segment, _, _, span), hir_id, .. }, diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 082dd8690235..31233062e9b3 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -901,13 +901,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { match expr.kind { hir::ExprKind::MethodCall(.., args, _) => { // only the first closre parameter of the method. args[0] is MethodCall PathSegment - for i in 1..args.len() { + + for arg in args { if let hir::ExprKind::Closure(hir::Closure { capture_clause: hir::CaptureBy::Ref, .. - }) = args[i].kind - { - closure_span = Some(args[i].span.shrink_to_lo()); + }) = arg.kind { + closure_span = Some(arg.span.shrink_to_lo()); break; } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 08282f138972..3367df56a297 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1893,7 +1893,7 @@ pub enum ExprKind<'hir> { /// the `hir_id` of the `MethodCall` node itself. /// /// [`type_dependent_def_id`]: ../../rustc_middle/ty/struct.TypeckResults.html#method.type_dependent_def_id - MethodCall(&'hir PathSegment<'hir>, &'hir [Expr<'hir>], Span), + MethodCall(&'hir PathSegment<'hir>, &'hir Expr<'hir>, &'hir [Expr<'hir>], Span), /// A tuple (e.g., `(a, b, c, d)`). Tup(&'hir [Expr<'hir>]), /// A binary operation (e.g., `a + b`, `a * b`). @@ -3497,7 +3497,7 @@ mod size_asserts { // These are in alphabetical order, which is easy to maintain. static_assert_size!(Block<'_>, 48); static_assert_size!(Body<'_>, 32); - static_assert_size!(Expr<'_>, 56); + static_assert_size!(Expr<'_>, 64); static_assert_size!(ExprKind<'_>, 40); static_assert_size!(FnDecl<'_>, 40); static_assert_size!(ForeignItem<'_>, 72); diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 3d5e22add718..2f9b92bfb9fb 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1094,8 +1094,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) visitor.visit_expr(callee_expression); walk_list!(visitor, visit_expr, arguments); } - ExprKind::MethodCall(ref segment, arguments, _) => { + ExprKind::MethodCall(ref segment, receiver, arguments, _) => { visitor.visit_path_segment(expression.span, segment); + visitor.visit_expr(receiver); walk_list!(visitor, visit_expr, arguments); } ExprKind::Binary(_, ref left_expression, ref right_expression) => { diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 42663da8a3f9..bb694bacfd7e 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1181,9 +1181,14 @@ impl<'a> State<'a> { self.print_call_post(args) } - fn print_expr_method_call(&mut self, segment: &hir::PathSegment<'_>, args: &[hir::Expr<'_>]) { - let base_args = &args[1..]; - self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX); + fn print_expr_method_call( + &mut self, + segment: &hir::PathSegment<'_>, + receiver: &hir::Expr<'_>, + args: &[hir::Expr<'_>], + ) { + let base_args = args; + self.print_expr_maybe_paren(&receiver, parser::PREC_POSTFIX); self.word("."); self.print_ident(segment.ident); @@ -1394,8 +1399,8 @@ impl<'a> State<'a> { hir::ExprKind::Call(func, args) => { self.print_expr_call(func, args); } - hir::ExprKind::MethodCall(segment, args, _) => { - self.print_expr_method_call(segment, args); + hir::ExprKind::MethodCall(segment, receiver, args, _) => { + self.print_expr_method_call(segment, receiver, args); } hir::ExprKind::Binary(op, lhs, rhs) => { self.print_expr_binary(op, lhs, rhs); @@ -2413,9 +2418,9 @@ fn contains_exterior_struct_lit(value: &hir::Expr<'_>) -> bool { contains_exterior_struct_lit(x) } - hir::ExprKind::MethodCall(.., exprs, _) => { + hir::ExprKind::MethodCall(_, receiver, ..) => { // `X { y: 1 }.bar(...)` - contains_exterior_struct_lit(&exprs[0]) + contains_exterior_struct_lit(receiver) } _ => false, diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 91a05367eee0..9efd909f05b3 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -901,7 +901,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { } } } - hir::ExprKind::MethodCall(segment, _, _) => { + hir::ExprKind::MethodCall(segment, ..) => { if let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id) { let generics = tcx.generics_of(def_id); let insertable: Option<_> = try { @@ -1132,7 +1132,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { let generic_args = &generics.own_substs_no_defaults(tcx, substs) [generics.own_counts().lifetimes..]; let span = match expr.kind { - ExprKind::MethodCall(path, _, _) => path.ident.span, + ExprKind::MethodCall(path, ..) => path.ident.span, _ => expr.span, }; @@ -1181,7 +1181,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { }) .any(|generics| generics.has_impl_trait()) }; - if let ExprKind::MethodCall(path, args, span) = expr.kind + if let ExprKind::MethodCall(path, receiver, args, span) = expr.kind && let Some(substs) = self.node_substs_opt(expr.hir_id) && substs.iter().any(|arg| self.generic_arg_contains_target(arg)) && let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id) @@ -1189,12 +1189,12 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { && !has_impl_trait(def_id) { let successor = - args.get(1).map_or_else(|| (")", span.hi()), |arg| (", ", arg.span.lo())); + args.get(0).map_or_else(|| (")", span.hi()), |arg| (", ", arg.span.lo())); let substs = self.infcx.resolve_vars_if_possible(substs); self.update_infer_source(InferSource { span: path.ident.span, kind: InferSourceKind::FullyQualifiedMethodCall { - receiver: args.first().unwrap(), + receiver, successor, substs, def_id, diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs index 121fefdc6207..fb79daf29ee1 100644 --- a/compiler/rustc_lint/src/array_into_iter.rs +++ b/compiler/rustc_lint/src/array_into_iter.rs @@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter { } // We only care about method call expressions. - if let hir::ExprKind::MethodCall(call, args, _) = &expr.kind { + if let hir::ExprKind::MethodCall(call, receiver, ..) = &expr.kind { if call.ident.name != sym::into_iter { return; } @@ -75,7 +75,7 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter { }; // As this is a method call expression, we have at least one argument. - let receiver_arg = &args[0]; + let receiver_arg = receiver; let receiver_ty = cx.typeck_results().expr_ty(receiver_arg); let adjustments = cx.typeck_results().expr_adjustments(receiver_arg); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 48942211eba2..7d62d5ac98d6 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2412,13 +2412,13 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { _ => {} } } - } else if let hir::ExprKind::MethodCall(_, ref args, _) = expr.kind { + } else if let hir::ExprKind::MethodCall(_, receiver, ..) = expr.kind { // Find problematic calls to `MaybeUninit::assume_init`. let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?; if cx.tcx.is_diagnostic_item(sym::assume_init, def_id) { // This is a call to *some* method named `assume_init`. // See if the `self` parameter is one of the dangerous constructors. - if let hir::ExprKind::Call(ref path_expr, _) = args[0].kind { + if let hir::ExprKind::Call(ref path_expr, _) = receiver.kind { if let hir::ExprKind::Path(ref qpath) = path_expr.kind { let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?; match cx.tcx.get_diagnostic_name(def_id) { diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 16b7d2cbbaea..23e7f21adf8e 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -51,7 +51,7 @@ fn typeck_results_of_method_fn<'tcx>( expr: &Expr<'_>, ) -> Option<(Span, DefId, ty::subst::SubstsRef<'tcx>)> { match expr.kind { - ExprKind::MethodCall(segment, _, _) + ExprKind::MethodCall(segment, ..) if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) => { Some((segment.ident.span, def_id, cx.typeck_results().node_substs(expr.hir_id))) diff --git a/compiler/rustc_lint/src/methods.rs b/compiler/rustc_lint/src/methods.rs index ff5a01749c19..646812589e3c 100644 --- a/compiler/rustc_lint/src/methods.rs +++ b/compiler/rustc_lint/src/methods.rs @@ -44,9 +44,13 @@ fn in_macro(span: Span) -> bool { fn first_method_call<'tcx>( expr: &'tcx Expr<'tcx>, -) -> Option<(&'tcx PathSegment<'tcx>, &'tcx [Expr<'tcx>])> { - if let ExprKind::MethodCall(path, args, _) = &expr.kind { - if args.iter().any(|e| e.span.from_expansion()) { None } else { Some((path, *args)) } +) -> Option<(&'tcx PathSegment<'tcx>, &'tcx Expr<'tcx>)> { + if let ExprKind::MethodCall(path, receiver, args, ..) = &expr.kind { + if args.iter().any(|e| e.span.from_expansion()) || receiver.span.from_expansion() { + None + } else { + Some((path, *receiver)) + } } else { None } @@ -59,14 +63,14 @@ impl<'tcx> LateLintPass<'tcx> for TemporaryCStringAsPtr { } match first_method_call(expr) { - Some((path, args)) if path.ident.name == sym::as_ptr => { - let unwrap_arg = &args[0]; + Some((path, receiver)) if path.ident.name == sym::as_ptr => { + let unwrap_arg = receiver; let as_ptr_span = path.ident.span; match first_method_call(unwrap_arg) { - Some((path, args)) + Some((path, receiver)) if path.ident.name == sym::unwrap || path.ident.name == sym::expect => { - let source_arg = &args[0]; + let source_arg = receiver; lint_cstring_as_ptr(cx, as_ptr_span, source_arg, unwrap_arg); } _ => return, diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index 11a752ff0970..d1449496d331 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -41,7 +41,7 @@ declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL]); impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { // We only care about method calls. - let ExprKind::MethodCall(call, elements, _) = &expr.kind else { + let ExprKind::MethodCall(call, receiver, ..) = &expr.kind else { return }; // We only care about method calls corresponding to the `Clone`, `Deref` and `Borrow` @@ -81,7 +81,6 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { ) { return; } - let receiver = &elements[0]; let receiver_ty = cx.typeck_results().expr_ty(receiver); let expr_ty = cx.typeck_results().expr_ty_adjusted(expr); if receiver_ty != expr_ty { diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 031665199812..9736b5557036 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1458,7 +1458,7 @@ impl InvalidAtomicOrdering { sym::AtomicI64, sym::AtomicI128, ]; - if let ExprKind::MethodCall(ref method_path, args, _) = &expr.kind + if let ExprKind::MethodCall(ref method_path, _, args, _) = &expr.kind && recognized_names.contains(&method_path.ident.name) && let Some(m_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) && let Some(impl_did) = cx.tcx.impl_of_method(m_def_id) @@ -1494,8 +1494,8 @@ impl InvalidAtomicOrdering { fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) { if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::load, sym::store]) && let Some((ordering_arg, invalid_ordering)) = match method { - sym::load => Some((&args[1], sym::Release)), - sym::store => Some((&args[2], sym::Acquire)), + sym::load => Some((&args[0], sym::Release)), + sym::store => Some((&args[1], sym::Acquire)), _ => None, } && let Some(ordering) = Self::match_ordering(cx, ordering_arg) @@ -1536,8 +1536,8 @@ impl InvalidAtomicOrdering { else {return }; let fail_order_arg = match method { - sym::fetch_update => &args[2], - sym::compare_exchange | sym::compare_exchange_weak => &args[4], + sym::fetch_update => &args[1], + sym::compare_exchange | sym::compare_exchange_weak => &args[3], _ => return, }; diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 9ed1c064d2b7..b4b5a9d868d9 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -261,15 +261,18 @@ impl<'tcx> Cx<'tcx> { let kind = match expr.kind { // Here comes the interesting stuff: - hir::ExprKind::MethodCall(segment, ref args, fn_span) => { + hir::ExprKind::MethodCall(segment, receiver, ref args, fn_span) => { // Rewrite a.b(c) into UFCS form like Trait::b(a, c) let expr = self.method_callee(expr, segment.ident.span, None); // When we apply adjustments to the receiver, use the span of // the overall method call for better diagnostics. args[0] // is guaranteed to exist, since a method call always has a receiver. - let old_adjustment_span = self.adjustment_span.replace((args[0].hir_id, expr_span)); + let old_adjustment_span = self.adjustment_span.replace((receiver.hir_id, expr_span)); info!("Using method span: {:?}", expr.span); - let args = self.mirror_exprs(args); + let args = std::iter::once(receiver) + .chain(args.iter()) + .map(|expr| self.mirror_expr(expr)) + .collect(); self.adjustment_span = old_adjustment_span; ExprKind::Call { ty: expr.ty, diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 2a6889af7c2c..214d357cae00 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1039,9 +1039,12 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.propagate_through_expr(&f, succ) } - hir::ExprKind::MethodCall(.., ref args, _) => { + hir::ExprKind::MethodCall(.., receiver, ref args, _) => { let succ = self.check_is_ty_uninhabited(expr, succ); - self.propagate_through_exprs(args, succ) + std::iter::once(receiver) + .chain(args.iter()) + .rev() + .fold(succ, |succ, expr| self.propagate_through_expr(expr, succ)) } hir::ExprKind::Tup(ref exprs) => self.propagate_through_exprs(exprs, succ), diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs index c9fc6b9e47ac..1bd6b857e062 100644 --- a/compiler/rustc_save_analysis/src/dump_visitor.rs +++ b/compiler/rustc_save_analysis/src/dump_visitor.rs @@ -803,6 +803,7 @@ impl<'tcx> DumpVisitor<'tcx> { &mut self, ex: &'tcx hir::Expr<'tcx>, seg: &'tcx hir::PathSegment<'tcx>, + receiver: &'tcx hir::Expr<'tcx>, args: &'tcx [hir::Expr<'tcx>], ) { debug!("process_method_call {:?} {:?}", ex, ex.span); @@ -823,6 +824,7 @@ impl<'tcx> DumpVisitor<'tcx> { } // walk receiver and args + self.visit_expr(receiver); walk_list!(self, visit_expr, args); } @@ -1340,7 +1342,9 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { let res = self.save_ctxt.get_path_res(hir_expr.hir_id); self.process_struct_lit(ex, path, fields, adt.variant_of_res(res), *rest) } - hir::ExprKind::MethodCall(ref seg, args, _) => self.process_method_call(ex, seg, args), + hir::ExprKind::MethodCall(ref seg, receiver, args, _) => { + self.process_method_call(ex, seg, receiver, args) + } hir::ExprKind::Field(ref sub_ex, _) => { self.visit_expr(&sub_ex); diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index 4a3d69f5b6c6..7ea3ed06e612 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -590,7 +590,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let closure_params_len = closure_fn_decl.inputs.len(); let ( Some(Node::Expr(hir::Expr { - kind: hir::ExprKind::MethodCall(method_path, method_expr, _), + kind: hir::ExprKind::MethodCall(method_path, receiver, ..), .. })), 1, @@ -598,7 +598,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; }; - let self_ty = self.typeck_results.borrow().expr_ty(&method_expr[0]); + let self_ty = self.typeck_results.borrow().expr_ty(receiver); let name = method_path.ident.name; let is_as_ref_able = match self_ty.peel_refs().kind() { ty::Adt(def, _) => { @@ -767,11 +767,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if self.can_coerce(ref_ty, expected) { let mut sugg_sp = sp; - if let hir::ExprKind::MethodCall(ref segment, ref args, _) = expr.kind { + if let hir::ExprKind::MethodCall(ref segment, receiver, args, _) = expr.kind { let clone_trait = self.tcx.require_lang_item(LangItem::Clone, Some(segment.ident.span)); - if let ([arg], Some(true), sym::clone) = ( - &args[..], + if let (true, Some(true), sym::clone) = ( + args.is_empty(), self.typeck_results.borrow().type_dependent_def_id(expr.hir_id).map( |did| { let ai = self.tcx.associated_item(did); @@ -782,7 +782,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { // If this expression had a clone call when suggesting borrowing // we want to suggest removing it because it'd now be unnecessary. - sugg_sp = arg.span; + sugg_sp = receiver.span; } } if let Ok(src) = sm.span_to_snippet(sugg_sp) { diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 17ec8afc7379..5c7b8121a61e 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -324,8 +324,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ExprKind::Block(body, _) => self.check_block_with_expected(&body, expected), ExprKind::Call(callee, args) => self.check_call(expr, &callee, args, expected), - ExprKind::MethodCall(segment, args, _) => { - self.check_method_call(expr, segment, args, expected) + ExprKind::MethodCall(segment, receiver, args, _) => { + self.check_method_call(expr, segment, receiver, args, expected) } ExprKind::Cast(e, t) => self.check_expr_cast(e, t, expr), ExprKind::Type(e, t) => { @@ -1195,13 +1195,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, expr: &'tcx hir::Expr<'tcx>, segment: &hir::PathSegment<'_>, + receiver: &'tcx hir::Expr<'tcx>, args: &'tcx [hir::Expr<'tcx>], expected: Expectation<'tcx>, ) -> Ty<'tcx> { - let rcvr = &args[0]; + let rcvr = &receiver; let rcvr_t = self.check_expr(&rcvr); // no need to check for bot/err -- callee does that - let rcvr_t = self.structurally_resolved_type(args[0].span, rcvr_t); + let rcvr_t = self.structurally_resolved_type(receiver.span, rcvr_t); let span = segment.ident.span; let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr, args) { @@ -1218,9 +1219,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, rcvr_t, segment.ident, - SelfSource::MethodCall(&args[0]), + SelfSource::MethodCall(receiver), error, - Some(args), + Some((receiver, args)), ) { err.emit(); } @@ -1230,14 +1231,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Call the generic checker. - self.check_method_argument_types( - span, - expr, - method, - &args[1..], - DontTupleArguments, - expected, - ) + self.check_method_argument_types(span, expr, method, &args, DontTupleArguments, expected) } fn check_expr_cast( diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 7e746b7387ad..c59638f5d6f9 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -987,7 +987,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if found != self.tcx.types.unit { return; } - if let ExprKind::MethodCall(path_segment, [rcvr, ..], _) = expr.kind { + if let ExprKind::MethodCall(path_segment, rcvr, ..) = expr.kind { if self .typeck_results .borrow() diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index d1d27db9131f..3805de3cd4df 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -478,7 +478,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, None, false), - hir::ExprKind::MethodCall(path_segment, _, span) => { + hir::ExprKind::MethodCall(path_segment, _, _, span) => { let ident_span = path_segment.ident.span; let ident_span = if let Some(args) = path_segment.args { ident_span.with_hi(args.span_ext.hi()) @@ -530,13 +530,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .collect(); let callee_expr = match &call_expr.peel_blocks().kind { hir::ExprKind::Call(callee, _) => Some(*callee), - hir::ExprKind::MethodCall(_, callee, _) => { + hir::ExprKind::MethodCall(_, receiver, ..) => { if let Some((DefKind::AssocFn, def_id)) = self.typeck_results.borrow().type_dependent_def(call_expr.hir_id) && let Some(assoc) = tcx.opt_associated_item(def_id) && assoc.fn_has_self_parameter { - Some(&callee[0]) + Some(*receiver) } else { None } @@ -1805,6 +1805,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { param, *call_hir_id, callee.span, + None, args, ) { @@ -1823,7 +1824,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } - hir::ExprKind::MethodCall(segment, args, ..) => { + hir::ExprKind::MethodCall(segment, receiver, args, ..) => { for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] .into_iter() .flatten() @@ -1834,6 +1835,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { param, hir_id, segment.ident.span, + Some(receiver), args, ) { return true; @@ -1901,7 +1903,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { param_to_point_at: ty::GenericArg<'tcx>, call_hir_id: hir::HirId, callee_span: Span, - args: &[hir::Expr<'tcx>], + receiver: Option<&'tcx hir::Expr<'tcx>>, + args: &'tcx [hir::Expr<'tcx>], ) -> bool { let sig = self.tcx.fn_sig(def_id).skip_binder(); let args_referencing_param: Vec<_> = sig @@ -1910,6 +1913,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .enumerate() .filter(|(_, ty)| find_param_in_ty(**ty, param_to_point_at)) .collect(); + let args: Vec<&'tcx hir::Expr<'tcx>> = if let Some(receiver) = receiver { + std::iter::once(receiver).chain(args.iter()).collect() + } else { + args.iter().collect() + }; // If there's one field that references the given generic, great! if let [(idx, _)] = args_referencing_param.as_slice() && let Some(arg) = args.get(*idx) { diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index d8527b9267e5..3d9677ecf75c 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -1049,7 +1049,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { found_ty: Ty<'tcx>, expr: &hir::Expr<'_>, ) { - let hir::ExprKind::MethodCall(segment, &[ref callee_expr], _) = expr.kind else { return; }; + let hir::ExprKind::MethodCall(segment, callee_expr, &[], _) = expr.kind else { return; }; let Some(clone_trait_did) = self.tcx.lang_items().clone_trait() else { return; }; let ty::Ref(_, pointee_ty, _) = found_ty.kind() else { return }; let results = self.typeck_results.borrow(); diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs index 3e96b3ffb094..016f4056bd90 100644 --- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs +++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs @@ -434,7 +434,8 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> { self.handle_uninhabited_return(expr); } - ExprKind::MethodCall(_, exprs, _) => { + ExprKind::MethodCall(_, receiver, exprs, _) => { + self.visit_expr(receiver); for expr in exprs { self.visit_expr(expr); } diff --git a/compiler/rustc_typeck/src/check/method/prelude2021.rs b/compiler/rustc_typeck/src/check/method/prelude2021.rs index 7c68d9304055..392695cca684 100644 --- a/compiler/rustc_typeck/src/check/method/prelude2021.rs +++ b/compiler/rustc_typeck/src/check/method/prelude2021.rs @@ -160,7 +160,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if precise { let args = args .iter() - .skip(1) .map(|arg| { let span = arg.span.find_ancestor_inside(sp).unwrap_or_default(); format!( diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 998405bcbe1c..124ac5c24fa5 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -95,7 +95,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item_name: Ident, source: SelfSource<'tcx>, error: MethodError<'tcx>, - args: Option<&'tcx [hir::Expr<'tcx>]>, + args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>, ) -> Option> { // Avoid suggestions when we don't know what's going on. if rcvr_ty.references_error() { @@ -998,7 +998,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, rcvr_ty, item_name, - args.map(|args| args.len()), + args.map(|(_, args)| args.len() + 1), source, out_of_scope_traits, &unsatisfied_predicates, @@ -2310,7 +2310,7 @@ pub fn all_traits(tcx: TyCtxt<'_>) -> Vec { fn print_disambiguation_help<'tcx>( item_name: Ident, - args: Option<&'tcx [hir::Expr<'tcx>]>, + args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>, err: &mut Diagnostic, trait_name: String, rcvr_ty: Ty<'_>, @@ -2322,7 +2322,7 @@ fn print_disambiguation_help<'tcx>( fn_has_self_parameter: bool, ) { let mut applicability = Applicability::MachineApplicable; - let (span, sugg) = if let (ty::AssocKind::Fn, Some(args)) = (kind, args) { + let (span, sugg) = if let (ty::AssocKind::Fn, Some((receiver, args))) = (kind, args) { let args = format!( "({}{})", if rcvr_ty.is_region_ptr() { @@ -2330,7 +2330,8 @@ fn print_disambiguation_help<'tcx>( } else { "" }, - args.iter() + std::iter::once(receiver) + .chain(args.iter()) .map(|arg| source_map.span_to_snippet(arg.span).unwrap_or_else(|_| { applicability = Applicability::HasPlaceholders; "_".to_owned() diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index bfc4f061b70f..f483342b445f 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -233,8 +233,9 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { self.consume_exprs(args); } - hir::ExprKind::MethodCall(.., args, _) => { + hir::ExprKind::MethodCall(.., receiver, args, _) => { // callee.m(args) + self.consume_expr(receiver); self.consume_exprs(args); } diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs index d4b5e5e2fe44..ec5d03300b17 100644 --- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs @@ -758,13 +758,13 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { num_assoc_fn_excess_args: usize, num_trait_generics_except_self: usize, ) { - if let hir::ExprKind::MethodCall(_, args, _) = expr.kind { - assert_eq!(args.len(), 1); + if let hir::ExprKind::MethodCall(_, receiver, args, ..) = expr.kind { + assert_eq!(args.len(), 0); if num_assoc_fn_excess_args == num_trait_generics_except_self { if let Some(gen_args) = self.gen_args.span_ext() && let Ok(gen_args) = self.tcx.sess.source_map().span_to_snippet(gen_args) - && let Ok(args) = self.tcx.sess.source_map().span_to_snippet(args[0].span) { - let sugg = format!("{}::{}::{}({})", self.tcx.item_name(trait_), gen_args, self.tcx.item_name(self.def_id), args); + && let Ok(receiver) = self.tcx.sess.source_map().span_to_snippet(receiver.span) { + let sugg = format!("{}::{}::{}({})", self.tcx.item_name(trait_), gen_args, self.tcx.item_name(self.def_id), receiver); err.span_suggestion(expr.span, msg, sugg, Applicability::MaybeIncorrect); } } diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index 0d9684025033..ca86ac89e858 100644 --- a/src/librustdoc/scrape_examples.rs +++ b/src/librustdoc/scrape_examples.rs @@ -159,7 +159,7 @@ where return; } } - hir::ExprKind::MethodCall(path, _, call_span) => { + hir::ExprKind::MethodCall(path, _, _, call_span) => { let types = tcx.typeck(ex.hir_id.owner); let Some(def_id) = types.type_dependent_def_id(ex.hir_id) else { trace!("type_dependent_def_id({}) = None", ex.hir_id); From 4bcaddeeb23544eb2c86b600c3d775e2773758c2 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Thu, 1 Sep 2022 18:43:35 +0900 Subject: [PATCH 4207/5092] separate the receiver from arguments in HIR under /clippy --- .../development/common_tools_writing_lints.md | 2 +- .../src/assertions_on_result_states.rs | 2 +- clippy_lints/src/blocks_in_if_conditions.rs | 5 +- clippy_lints/src/booleans.rs | 6 +- .../src/casts/cast_abs_to_unsigned.rs | 4 +- .../src/casts/cast_possible_truncation.rs | 6 +- clippy_lints/src/casts/cast_ptr_alignment.rs | 4 +- clippy_lints/src/casts/cast_sign_loss.rs | 4 +- clippy_lints/src/default_numeric_fallback.rs | 23 ++-- clippy_lints/src/dereference.rs | 47 ++++---- clippy_lints/src/doc.rs | 2 +- clippy_lints/src/entry.rs | 4 +- clippy_lints/src/eta_reduction.rs | 25 +++-- clippy_lints/src/explicit_write.rs | 4 +- clippy_lints/src/fallible_impl_from.rs | 2 +- clippy_lints/src/floating_point_arithmetic.rs | 79 +++++++------- clippy_lints/src/format_args.rs | 20 ++-- clippy_lints/src/format_impl.rs | 2 +- clippy_lints/src/format_push_string.rs | 2 +- clippy_lints/src/functions/must_use.rs | 20 +++- .../src/functions/not_unsafe_ptr_arg_deref.rs | 3 +- clippy_lints/src/if_let_mutex.rs | 2 +- clippy_lints/src/infinite_iter.rs | 100 +++++++++--------- clippy_lints/src/len_zero.rs | 10 +- clippy_lints/src/loops/manual_memcpy.rs | 4 +- clippy_lints/src/loops/missing_spin_loop.rs | 2 +- clippy_lints/src/loops/mod.rs | 2 +- clippy_lints/src/loops/needless_collect.rs | 14 +-- clippy_lints/src/loops/needless_range_loop.rs | 11 +- clippy_lints/src/loops/never_loop.rs | 5 +- clippy_lints/src/loops/same_item_push.rs | 5 +- clippy_lints/src/loops/single_element_loop.rs | 33 +++--- clippy_lints/src/loops/while_let_loop.rs | 9 +- .../src/loops/while_let_on_iterator.rs | 2 +- clippy_lints/src/manual_bits.rs | 2 +- clippy_lints/src/manual_retain.rs | 22 ++-- clippy_lints/src/manual_string_new.rs | 13 +-- clippy_lints/src/manual_strip.rs | 4 +- clippy_lints/src/map_unit_fn.rs | 11 +- clippy_lints/src/match_result_ok.rs | 2 +- .../src/matches/match_str_case_mismatch.rs | 2 +- .../src/matches/redundant_pattern_match.rs | 2 +- .../matches/significant_drop_in_scrutinee.rs | 5 +- clippy_lints/src/methods/bytecount.rs | 6 +- clippy_lints/src/methods/chars_cmp.rs | 4 +- .../src/methods/chars_cmp_with_unwrap.rs | 2 +- clippy_lints/src/methods/clone_on_copy.rs | 14 ++- clippy_lints/src/methods/clone_on_ref_ptr.rs | 12 ++- .../src/methods/collapsible_str_replace.rs | 6 +- clippy_lints/src/methods/expect_fun_call.rs | 24 ++--- clippy_lints/src/methods/extend_with_drain.rs | 2 +- clippy_lints/src/methods/filter_map.rs | 12 +-- clippy_lints/src/methods/get_last_with_len.rs | 2 +- .../src/methods/inefficient_to_string.rs | 14 ++- clippy_lints/src/methods/into_iter_on_ref.rs | 4 +- clippy_lints/src/methods/iter_with_drain.rs | 2 +- clippy_lints/src/methods/map_clone.rs | 2 +- clippy_lints/src/methods/mod.rs | 96 +++++++++-------- clippy_lints/src/methods/open_options.rs | 10 +- .../src/methods/option_as_ref_deref.rs | 7 +- clippy_lints/src/methods/or_fun_call.rs | 7 +- .../src/methods/range_zip_with_len.rs | 2 +- .../src/methods/single_char_add_str.rs | 6 +- .../src/methods/single_char_insert_string.rs | 8 +- .../src/methods/single_char_pattern.rs | 58 +++++----- .../src/methods/single_char_push_string.rs | 6 +- clippy_lints/src/methods/str_splitn.rs | 6 +- .../src/methods/string_extend_chars.rs | 2 +- .../src/methods/unnecessary_iter_cloned.rs | 2 +- .../src/methods/unnecessary_lazy_eval.rs | 2 +- .../src/methods/unnecessary_sort_by.rs | 8 +- .../src/methods/unnecessary_to_owned.rs | 22 ++-- clippy_lints/src/methods/utils.rs | 6 +- clippy_lints/src/minmax.rs | 35 +++--- clippy_lints/src/mut_reference.rs | 14 ++- clippy_lints/src/needless_for_each.rs | 4 +- .../src/non_octal_unix_permissions.rs | 2 +- clippy_lints/src/only_used_in_recursion.rs | 4 +- clippy_lints/src/operators/cmp_owned.rs | 2 +- clippy_lints/src/operators/duration_subsec.rs | 2 +- clippy_lints/src/operators/float_cmp.rs | 2 +- clippy_lints/src/ptr.rs | 7 +- clippy_lints/src/ptr_offset_with_cast.rs | 2 +- clippy_lints/src/question_mark.rs | 2 +- clippy_lints/src/read_zero_byte_vec.rs | 2 +- clippy_lints/src/size_of_in_element_count.rs | 2 +- .../src/slow_vector_initialization.rs | 10 +- clippy_lints/src/strings.rs | 28 ++--- clippy_lints/src/strlen_on_c_strings.rs | 2 +- clippy_lints/src/to_digit_is_some.rs | 10 +- clippy_lints/src/uninit_vec.rs | 4 +- clippy_lints/src/unit_return_expecting_ord.rs | 3 +- clippy_lints/src/unit_types/let_unit_value.rs | 13 ++- clippy_lints/src/unit_types/unit_arg.rs | 39 +++---- clippy_lints/src/unused_io_amount.rs | 8 +- clippy_lints/src/unused_peekable.rs | 3 +- clippy_lints/src/unwrap.rs | 10 +- clippy_lints/src/unwrap_in_result.rs | 4 +- clippy_lints/src/useless_conversion.rs | 2 +- clippy_lints/src/utils/author.rs | 7 +- clippy_lints/src/utils/internal_lints.rs | 2 +- clippy_lints/src/vec_init_then_push.rs | 4 +- clippy_utils/src/check_proc_macro.rs | 4 +- clippy_utils/src/diagnostics.rs | 8 +- clippy_utils/src/eager_or_lazy.rs | 18 ++-- clippy_utils/src/hir_utils.rs | 13 ++- clippy_utils/src/lib.rs | 26 ++--- clippy_utils/src/ptr.rs | 2 +- clippy_utils/src/sugg.rs | 24 +++-- clippy_utils/src/visitors.rs | 8 +- tests/ui/author/struct.stdout | 6 +- 111 files changed, 662 insertions(+), 558 deletions(-) diff --git a/book/src/development/common_tools_writing_lints.md b/book/src/development/common_tools_writing_lints.md index 15e00c7d7ce4..2bc275ceff0b 100644 --- a/book/src/development/common_tools_writing_lints.md +++ b/book/src/development/common_tools_writing_lints.md @@ -66,7 +66,7 @@ Starting with an `expr`, you can check whether it is calling a specific method impl<'tcx> LateLintPass<'tcx> for MyStructLint { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { // Check our expr is calling a method - if let hir::ExprKind::MethodCall(path, _, [_self_arg, ..]) = &expr.kind + if let hir::ExprKind::MethodCall(path, _, _self_arg, ..) = &expr.kind // Check the name of this method is `some_method` && path.ident.name == sym!(some_method) // Optionally, check the type of the self argument. diff --git a/clippy_lints/src/assertions_on_result_states.rs b/clippy_lints/src/assertions_on_result_states.rs index 6a6554f968b3..7cd198ace86c 100644 --- a/clippy_lints/src/assertions_on_result_states.rs +++ b/clippy_lints/src/assertions_on_result_states.rs @@ -43,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { && matches!(cx.tcx.get_diagnostic_name(macro_call.def_id), Some(sym::assert_macro)) && let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn) && matches!(panic_expn, PanicExpn::Empty) - && let ExprKind::MethodCall(method_segment, [recv], _) = condition.kind + && let ExprKind::MethodCall(method_segment, recv, [], _) = condition.kind && let result_type_with_refs = cx.typeck_results().expr_ty(recv) && let result_type = result_type_with_refs.peel_refs() && is_type_diagnostic_item(cx, result_type, sym::Result) diff --git a/clippy_lints/src/blocks_in_if_conditions.rs b/clippy_lints/src/blocks_in_if_conditions.rs index ad206b5fb304..d9e2c9c8578f 100644 --- a/clippy_lints/src/blocks_in_if_conditions.rs +++ b/clippy_lints/src/blocks_in_if_conditions.rs @@ -55,7 +55,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ExVisitor<'a, 'tcx> { // do not lint if the closure is called using an iterator (see #1141) if_chain! { if let Some(parent) = get_parent_expr(self.cx, expr); - if let ExprKind::MethodCall(_, [self_arg, ..], _) = &parent.kind; + if let ExprKind::MethodCall(_, self_arg, ..) = &parent.kind; let caller = self.cx.typeck_results().expr_ty(self_arg); if let Some(iter_id) = self.cx.tcx.get_diagnostic_item(sym::Iterator); if implements_trait(self.cx, caller, iter_id, &[]); @@ -117,7 +117,8 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInIfConditions { ); } } else { - let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span); + let span = + block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span); if span.from_expansion() || expr.span.from_expansion() { return; } diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 6eb78d21e826..656d639f0efd 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -270,8 +270,8 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { )) }) }, - ExprKind::MethodCall(path, args, _) if args.len() == 1 => { - let type_of_receiver = cx.typeck_results().expr_ty(&args[0]); + ExprKind::MethodCall(path, receiver, [], _) => { + let type_of_receiver = cx.typeck_results().expr_ty(receiver); if !is_type_diagnostic_item(cx, type_of_receiver, sym::Option) && !is_type_diagnostic_item(cx, type_of_receiver, sym::Result) { @@ -285,7 +285,7 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { let path: &str = path.ident.name.as_str(); a == path }) - .and_then(|(_, neg_method)| Some(format!("{}.{}()", snippet_opt(cx, args[0].span)?, neg_method))) + .and_then(|(_, neg_method)| Some(format!("{}.{}()", snippet_opt(cx, receiver.span)?, neg_method))) }, _ => None, } diff --git a/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/clippy_lints/src/casts/cast_abs_to_unsigned.rs index 6426e8c25ac1..3f1edabe6c50 100644 --- a/clippy_lints/src/casts/cast_abs_to_unsigned.rs +++ b/clippy_lints/src/casts/cast_abs_to_unsigned.rs @@ -20,7 +20,7 @@ pub(super) fn check( if meets_msrv(msrv, msrvs::UNSIGNED_ABS) && let ty::Int(from) = cast_from.kind() && let ty::Uint(to) = cast_to.kind() - && let ExprKind::MethodCall(method_path, args, _) = cast_expr.kind + && let ExprKind::MethodCall(method_path, receiver, ..) = cast_expr.kind && method_path.ident.name.as_str() == "abs" { let span = if from.bit_width() == to.bit_width() { @@ -37,7 +37,7 @@ pub(super) fn check( span, &format!("casting the result of `{cast_from}::abs()` to {cast_to}"), "replace with", - format!("{}.unsigned_abs()", Sugg::hir(cx, &args[0], "..").maybe_par()), + format!("{}.unsigned_abs()", Sugg::hir(cx, receiver, "..").maybe_par()), Applicability::MachineApplicable, ); } diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs index 64f87c80f8d1..406547a4454e 100644 --- a/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -44,7 +44,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b .saturating_sub(constant_int(cx, right).map_or(0, |s| u64::try_from(s).expect("shift too high"))), _ => nbits, }, - ExprKind::MethodCall(method, [left, right], _) => { + ExprKind::MethodCall(method, left, [right], _) => { if signed { return nbits; } @@ -55,7 +55,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b }; apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::max_value())) }, - ExprKind::MethodCall(method, [_, lo, hi], _) => { + ExprKind::MethodCall(method, _, [lo, hi], _) => { if method.ident.as_str() == "clamp" { //FIXME: make this a diagnostic item if let (Some(lo_bits), Some(hi_bits)) = (get_constant_bits(cx, lo), get_constant_bits(cx, hi)) { @@ -64,7 +64,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b } nbits }, - ExprKind::MethodCall(method, [_value], _) => { + ExprKind::MethodCall(method, _value, [], _) => { if method.ident.name.as_str() == "signum" { 0 // do not lint if cast comes from a `signum` function } else { diff --git a/clippy_lints/src/casts/cast_ptr_alignment.rs b/clippy_lints/src/casts/cast_ptr_alignment.rs index d476a1a7646c..da7b12f67266 100644 --- a/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -18,7 +18,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { cx.typeck_results().expr_ty(expr), ); lint_cast_ptr_alignment(cx, expr, cast_from, cast_to); - } else if let ExprKind::MethodCall(method_path, [self_arg, ..], _) = &expr.kind { + } else if let ExprKind::MethodCall(method_path, self_arg, ..) = &expr.kind { if method_path.ident.name == sym!(cast) && let Some(generic_args) = method_path.args && let [GenericArg::Type(cast_to)] = generic_args.args @@ -64,7 +64,7 @@ fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { return false; }; match parent.kind { - ExprKind::MethodCall(name, [self_arg, ..], _) if self_arg.hir_id == e.hir_id => { + ExprKind::MethodCall(name, self_arg, ..) if self_arg.hir_id == e.hir_id => { if matches!(name.ident.as_str(), "read_unaligned" | "write_unaligned") && let Some(def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id) && let Some(def_id) = cx.tcx.impl_of_method(def_id) diff --git a/clippy_lints/src/casts/cast_sign_loss.rs b/clippy_lints/src/casts/cast_sign_loss.rs index 75f70b77ed4e..5b59350be042 100644 --- a/clippy_lints/src/casts/cast_sign_loss.rs +++ b/clippy_lints/src/casts/cast_sign_loss.rs @@ -41,14 +41,14 @@ fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast } // Don't lint for the result of methods that always return non-negative values. - if let ExprKind::MethodCall(path, _, _) = cast_op.kind { + if let ExprKind::MethodCall(path, ..) = cast_op.kind { let mut method_name = path.ident.name.as_str(); let allowed_methods = ["abs", "checked_abs", "rem_euclid", "checked_rem_euclid"]; if_chain! { if method_name == "unwrap"; if let Some(arglist) = method_chain_args(cast_op, &["unwrap"]); - if let ExprKind::MethodCall(inner_path, _, _) = &arglist[0][0].kind; + if let ExprKind::MethodCall(inner_path, ..) = &arglist[0].0.kind; then { method_name = inner_path.ident.name.as_str(); } diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs index fb418a3251f5..64c5de510420 100644 --- a/clippy_lints/src/default_numeric_fallback.rs +++ b/clippy_lints/src/default_numeric_fallback.rs @@ -69,10 +69,7 @@ struct NumericFallbackVisitor<'a, 'tcx> { impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> { fn new(cx: &'a LateContext<'tcx>) -> Self { - Self { - ty_bounds: vec![TyBound::Nothing], - cx, - } + Self { ty_bounds: vec![TyBound::Nothing], cx } } /// Check whether a passed literal has potential to cause fallback or not. @@ -129,19 +126,21 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { } return; } - }, + } - ExprKind::MethodCall(_, args, _) => { + ExprKind::MethodCall(_, receiver, args, _) => { if let Some(def_id) = self.cx.typeck_results().type_dependent_def_id(expr.hir_id) { let fn_sig = self.cx.tcx.fn_sig(def_id).skip_binder(); - for (expr, bound) in iter::zip(*args, fn_sig.inputs()) { + for (expr, bound) in + iter::zip(std::iter::once(*receiver).chain(args.iter()), fn_sig.inputs()) + { self.ty_bounds.push(TyBound::Ty(*bound)); self.visit_expr(expr); self.ty_bounds.pop(); } return; } - }, + } ExprKind::Struct(_, fields, base) => { let ty = self.cx.typeck_results().expr_ty(expr); @@ -176,15 +175,15 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { return; } } - }, + } ExprKind::Lit(lit) => { let ty = self.cx.typeck_results().expr_ty(expr); self.check_lit(lit, ty, expr.hir_id); return; - }, + } - _ => {}, + _ => {} } walk_expr(self, expr); @@ -198,7 +197,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { } else { self.ty_bounds.push(TyBound::Nothing); } - }, + } _ => self.ty_bounds.push(TyBound::Nothing), } diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index 1506ea604f0d..fd6ed36cb192 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -581,7 +581,7 @@ fn try_parse_ref_op<'tcx>( expr: &'tcx Expr<'_>, ) -> Option<(RefOp, &'tcx Expr<'tcx>)> { let (def_id, arg) = match expr.kind { - ExprKind::MethodCall(_, [arg], _) => (typeck.type_dependent_def_id(expr.hir_id)?, arg), + ExprKind::MethodCall(_, arg, [], _) => (typeck.type_dependent_def_id(expr.hir_id)?, arg), ExprKind::Call( Expr { kind: ExprKind::Path(path), @@ -796,16 +796,19 @@ fn walk_parents<'tcx>( }, }) }), - ExprKind::MethodCall(_, args, _) => { + ExprKind::MethodCall(_, receiver, args, _) => { let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap(); - args.iter().position(|arg| arg.hir_id == child_id).map(|i| { - if i == 0 { - // Check for calls to trait methods where the trait is implemented on a reference. - // Two cases need to be handled: - // * `self` methods on `&T` will never have auto-borrow - // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take - // priority. - if e.hir_id != child_id { + std::iter::once(receiver) + .chain(args.iter()) + .position(|arg| arg.hir_id == child_id) + .map(|i| { + if i == 0 { + // Check for calls to trait methods where the trait is implemented on a reference. + // Two cases need to be handled: + // * `self` methods on `&T` will never have auto-borrow + // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take + // priority. + if e.hir_id != child_id { Position::ReborrowStable(precedence) } else if let Some(trait_id) = cx.tcx.trait_of_item(id) && let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e)) @@ -834,20 +837,20 @@ fn walk_parents<'tcx>( } else { Position::MethodReceiver } - } else { - let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i]; - if let ty::Param(param_ty) = ty.kind() { - needless_borrow_impl_arg_position(cx, parent, i, *param_ty, e, precedence, msrv) } else { - ty_auto_deref_stability( - cx, - cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)), - precedence, - ) - .position_for_arg() + let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i]; + if let ty::Param(param_ty) = ty.kind() { + needless_borrow_impl_arg_position(cx, parent, i, *param_ty, e, precedence, msrv) + } else { + ty_auto_deref_stability( + cx, + cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)), + precedence, + ) + .position_for_arg() + } } - } - }) + }) }, ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess(name.name)), ExprKind::Unary(UnOp::Deref, child) if child.hir_id == e.hir_id => Some(Position::Deref), diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index da111e7378ea..512872cedc1e 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -828,7 +828,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> { // check for `unwrap` if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { - let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); + let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs(); if is_type_diagnostic_item(self.cx, receiver_ty, sym::Option) || is_type_diagnostic_item(self.cx, receiver_ty, sym::Result) { diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 4e3ae4c96141..e70df3f53c75 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -245,8 +245,8 @@ fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Optio match expr.kind { ExprKind::MethodCall( _, + map, [ - map, Expr { kind: ExprKind::AddrOf(_, _, key), span: key_span, @@ -280,7 +280,7 @@ struct InsertExpr<'tcx> { value: &'tcx Expr<'tcx>, } fn try_parse_insert<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option> { - if let ExprKind::MethodCall(_, [map, key, value], _) = expr.kind { + if let ExprKind::MethodCall(_, map, [key, value], _) = expr.kind { let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?; if match_def_path(cx, id, &paths::BTREEMAP_INSERT) || match_def_path(cx, id, &paths::HASHMAP_INSERT) { Some(InsertExpr { map, key, value }) diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 4f9ff97f1fd1..1c0a93c71fde 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -106,7 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { if !is_adjusted(cx, &body.value); if let ExprKind::Call(callee, args) = body.value.kind; if let ExprKind::Path(_) = callee.kind; - if check_inputs(cx, body.params, args); + if check_inputs(cx, body.params, None, args); let callee_ty = cx.typeck_results().expr_ty_adjusted(callee); let call_ty = cx.typeck_results().type_dependent_def_id(body.value.hir_id) .map_or(callee_ty, |id| cx.tcx.type_of(id)); @@ -146,8 +146,8 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { if_chain!( if !is_adjusted(cx, &body.value); - if let ExprKind::MethodCall(path, args, _) = body.value.kind; - if check_inputs(cx, body.params, args); + if let ExprKind::MethodCall(path, receiver, args, _) = body.value.kind; + if check_inputs(cx, body.params, Some(receiver), args); let method_def_id = cx.typeck_results().type_dependent_def_id(body.value.hir_id).unwrap(); let substs = cx.typeck_results().node_substs(body.value.hir_id); let call_ty = cx.tcx.bound_type_of(method_def_id).subst(cx.tcx, substs); @@ -167,12 +167,17 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { } } -fn check_inputs(cx: &LateContext<'_>, params: &[Param<'_>], call_args: &[Expr<'_>]) -> bool { - if params.len() != call_args.len() { +fn check_inputs( + cx: &LateContext<'_>, + params: &[Param<'_>], + receiver: Option<&Expr<'_>>, + call_args: &[Expr<'_>], +) -> bool { + if receiver.map_or(params.len() != call_args.len(), |_| params.len() != call_args.len() + 1) { return false; } let binding_modes = cx.typeck_results().pat_binding_modes(); - std::iter::zip(params, call_args).all(|(param, arg)| { + let check_inputs = |param: &Param<'_>, arg| { match param.pat.kind { PatKind::Binding(_, id, ..) if path_to_local_id(arg, id) => {}, _ => return false, @@ -200,7 +205,13 @@ fn check_inputs(cx: &LateContext<'_>, params: &[Param<'_>], call_args: &[Expr<'_ }, _ => false, } - }) + }; + if let Some(receiver) = receiver { + std::iter::zip(params, std::iter::once(receiver).chain(call_args.iter())) + .all(|(param, arg)| check_inputs(param, arg)) + } else { + std::iter::zip(params, call_args).all(|(param, arg)| check_inputs(param, arg)) + } } fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tcx>) -> bool { diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index 5bf4313b41a4..9c76f63f5f75 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -45,10 +45,10 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { // match call to unwrap - if let ExprKind::MethodCall(unwrap_fun, [write_call], _) = expr.kind; + if let ExprKind::MethodCall(unwrap_fun, write_call, [], _) = expr.kind; if unwrap_fun.ident.name == sym::unwrap; // match call to write_fmt - if let ExprKind::MethodCall(write_fun, [write_recv, write_arg], _) = look_in_block(cx, &write_call.kind); + if let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = look_in_block(cx, &write_call.kind); if write_fun.ident.name == sym!(write_fmt); // match calls to std::io::stdout() / std::io::stderr () if let Some(dest_name) = if match_function_call(cx, write_recv, &paths::STDOUT).is_some() { diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index b88e53aeca69..790eea63f58c 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -84,7 +84,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h // check for `unwrap` if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { - let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); + let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs(); if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option) || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result) { diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index bb50e8fcabbb..728db41d6004 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -164,15 +164,15 @@ fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>) -> Su suggestion.maybe_par() } -fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { - if let Some(method) = get_specialized_log_method(cx, &args[1]) { +fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) { + if let Some(method) = get_specialized_log_method(cx, &args[0]) { span_lint_and_sugg( cx, SUBOPTIMAL_FLOPS, expr.span, "logarithm for bases 2, 10 and e can be computed more accurately", "consider using", - format!("{}.{}()", Sugg::hir(cx, &args[0], "..").maybe_par(), method), + format!("{}.{}()", Sugg::hir(cx, receiver, "..").maybe_par(), method), Applicability::MachineApplicable, ); } @@ -180,14 +180,14 @@ fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { // TODO: Lint expressions of the form `(x + y).ln()` where y > 1 and // suggest usage of `(x + (y - 1)).ln_1p()` instead -fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { +fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) { if let ExprKind::Binary( Spanned { node: BinOpKind::Add, .. }, lhs, rhs, - ) = &args[0].kind + ) = receiver.kind { let recv = match ( constant(cx, cx.typeck_results(), lhs), @@ -235,9 +235,9 @@ fn get_integer_from_float_constant(value: &Constant) -> Option { } } -fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { +fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) { // Check receiver - if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) { + if let Some((value, _)) = constant(cx, cx.typeck_results(), receiver) { let method = if F32(f32_consts::E) == value || F64(f64_consts::E) == value { "exp" } else if F32(2.0) == value || F64(2.0) == value { @@ -252,24 +252,24 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { expr.span, "exponent for bases 2 and e can be computed more accurately", "consider using", - format!("{}.{}()", prepare_receiver_sugg(cx, &args[1]), method), + format!("{}.{}()", prepare_receiver_sugg(cx, &args[0]), method), Applicability::MachineApplicable, ); } // Check argument - if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[1]) { + if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) { let (lint, help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value { ( SUBOPTIMAL_FLOPS, "square-root of a number can be computed more efficiently and accurately", - format!("{}.sqrt()", Sugg::hir(cx, &args[0], "..").maybe_par()), + format!("{}.sqrt()", Sugg::hir(cx, receiver, "..").maybe_par()), ) } else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value { ( IMPRECISE_FLOPS, "cube-root of a number can be computed more accurately", - format!("{}.cbrt()", Sugg::hir(cx, &args[0], "..").maybe_par()), + format!("{}.cbrt()", Sugg::hir(cx, receiver, "..").maybe_par()), ) } else if let Some(exponent) = get_integer_from_float_constant(&value) { ( @@ -277,7 +277,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { "exponentiation with integer powers can be computed more efficiently", format!( "{}.powi({})", - Sugg::hir(cx, &args[0], "..").maybe_par(), + Sugg::hir(cx, receiver, "..").maybe_par(), numeric_literal::format(&exponent.to_string(), None, false) ), ) @@ -297,13 +297,14 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { } } -fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { - if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[1]) { +fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) { + if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) { if value == Int(2) { if let Some(parent) = get_parent_expr(cx, expr) { if let Some(grandparent) = get_parent_expr(cx, parent) { - if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, args, _) = grandparent.kind { - if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() { + if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = grandparent.kind + { + if method_name.as_str() == "sqrt" && detect_hypot(cx, receiver).is_some() { return; } } @@ -327,8 +328,8 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { "consider using", format!( "{}.mul_add({}, {})", - Sugg::hir(cx, &args[0], "..").maybe_par(), - Sugg::hir(cx, &args[0], ".."), + Sugg::hir(cx, receiver, "..").maybe_par(), + Sugg::hir(cx, receiver, ".."), Sugg::hir(cx, other_addend, ".."), ), Applicability::MachineApplicable, @@ -339,14 +340,14 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { } } -fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option { +fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option { if let ExprKind::Binary( Spanned { node: BinOpKind::Add, .. }, add_lhs, add_rhs, - ) = args[0].kind + ) = receiver.kind { // check if expression of the form x * x + y * y if_chain! { @@ -363,12 +364,12 @@ fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option { if_chain! { if let ExprKind::MethodCall( PathSegment { ident: lmethod_name, .. }, - [largs_0, largs_1, ..], + largs_0, [largs_1, ..], _ ) = &add_lhs.kind; if let ExprKind::MethodCall( PathSegment { ident: rmethod_name, .. }, - [rargs_0, rargs_1, ..], + rargs_0, [rargs_1, ..], _ ) = &add_rhs.kind; if lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi"; @@ -384,8 +385,8 @@ fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option { None } -fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { - if let Some(message) = detect_hypot(cx, args) { +fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) { + if let Some(message) = detect_hypot(cx, receiver) { span_lint_and_sugg( cx, IMPRECISE_FLOPS, @@ -406,7 +407,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) { if cx.typeck_results().expr_ty(lhs).is_floating_point(); if let Some((value, _)) = constant(cx, cx.typeck_results(), rhs); if F32(1.0) == value || F64(1.0) == value; - if let ExprKind::MethodCall(path, [self_arg, ..], _) = &lhs.kind; + if let ExprKind::MethodCall(path, self_arg, ..) = &lhs.kind; if cx.typeck_results().expr_ty(self_arg).is_floating_point(); if path.ident.name.as_str() == "exp"; then { @@ -450,8 +451,8 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) { ) = &expr.kind { if let Some(parent) = get_parent_expr(cx, expr) { - if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, args, _) = parent.kind { - if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() { + if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = parent.kind { + if method_name.as_str() == "sqrt" && detect_hypot(cx, receiver).is_some() { return; } } @@ -586,14 +587,14 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) { fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool { if_chain! { - if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, args_a, _) = expr_a.kind; - if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, args_b, _) = expr_b.kind; + if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, _, args_a, _) = expr_a.kind; + if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, _, args_b, _) = expr_b.kind; then { return method_name_a.as_str() == method_name_b.as_str() && args_a.len() == args_b.len() && ( ["ln", "log2", "log10"].contains(&method_name_a.as_str()) || - method_name_a.as_str() == "log" && args_a.len() == 2 && eq_expr_value(cx, &args_a[1], &args_b[1]) + method_name_a.as_str() == "log" && args_a.len() == 1 && eq_expr_value(cx, &args_a[0], &args_b[0]) ); } } @@ -612,8 +613,8 @@ fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) { rhs, ) = &expr.kind; if are_same_base_logs(cx, lhs, rhs); - if let ExprKind::MethodCall(_, [largs_self, ..], _) = &lhs.kind; - if let ExprKind::MethodCall(_, [rargs_self, ..], _) = &rhs.kind; + if let ExprKind::MethodCall(_, largs_self, ..) = &lhs.kind; + if let ExprKind::MethodCall(_, rargs_self, ..) = &rhs.kind; then { span_lint_and_sugg( cx, @@ -711,16 +712,16 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic { return; } - if let ExprKind::MethodCall(path, args, _) = &expr.kind { - let recv_ty = cx.typeck_results().expr_ty(&args[0]); + if let ExprKind::MethodCall(path, receiver, args, _) = &expr.kind { + let recv_ty = cx.typeck_results().expr_ty(receiver); if recv_ty.is_floating_point() { match path.ident.name.as_str() { - "ln" => check_ln1p(cx, expr, args), - "log" => check_log_base(cx, expr, args), - "powf" => check_powf(cx, expr, args), - "powi" => check_powi(cx, expr, args), - "sqrt" => check_hypot(cx, expr, args), + "ln" => check_ln1p(cx, expr, receiver), + "log" => check_log_base(cx, expr, receiver, args), + "powf" => check_powf(cx, expr, receiver, args), + "powi" => check_powi(cx, expr, receiver, args), + "sqrt" => check_hypot(cx, expr, receiver), _ => {}, } } diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 9fb9fd99748b..2a55c48cf773 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -99,7 +99,12 @@ fn outermost_expn_data(expn_data: ExpnData) -> ExpnData { } } -fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symbol, arg: &Expr<'_>) { +fn check_format_in_format_args( + cx: &LateContext<'_>, + call_site: Span, + name: Symbol, + arg: &Expr<'_>, +) { let expn_data = arg.span.ctxt().outer_expn_data(); if expn_data.call_site.from_expansion() { return; @@ -126,7 +131,7 @@ fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symb fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Expr<'_>) { if_chain! { if !value.span.from_expansion(); - if let ExprKind::MethodCall(_, [receiver], _) = value.kind; + if let ExprKind::MethodCall(_, receiver, [], _) = value.kind; if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id); if is_diag_trait_item(cx, method_def_id, sym::ToString); let receiver_ty = cx.typeck_results().expr_ty(receiver); @@ -177,10 +182,7 @@ fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Ex // Returns true if `hir_id` is referred to by multiple format params fn is_aliased(args: &FormatArgsExpn<'_>, hir_id: HirId) -> bool { - args.params() - .filter(|param| param.value.hir_id == hir_id) - .at_most_one() - .is_err() + args.params().filter(|param| param.value.hir_id == hir_id).at_most_one().is_err() } fn count_needed_derefs<'tcx, I>(mut ty: Ty<'tcx>, mut iter: I) -> (usize, Ty<'tcx>) @@ -190,11 +192,7 @@ where let mut n_total = 0; let mut n_needed = 0; loop { - if let Some(Adjustment { - kind: Adjust::Deref(overloaded_deref), - target, - }) = iter.next() - { + if let Some(Adjustment { kind: Adjust::Deref(overloaded_deref), target }) = iter.next() { n_total += 1; if overloaded_deref.is_some() { n_needed = n_total; diff --git a/clippy_lints/src/format_impl.rs b/clippy_lints/src/format_impl.rs index d8bc0bf08f2b..b628fd9f7581 100644 --- a/clippy_lints/src/format_impl.rs +++ b/clippy_lints/src/format_impl.rs @@ -139,7 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatImpl { fn check_to_string_in_display(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { // Get the hir_id of the object we are calling the method on - if let ExprKind::MethodCall(path, [ref self_arg, ..], _) = expr.kind; + if let ExprKind::MethodCall(path, self_arg, ..) = expr.kind; // Is the method to_string() ? if path.ident.name == sym::to_string; // Is the method a part of the ToString trait? (i.e. not to_string() implemented diff --git a/clippy_lints/src/format_push_string.rs b/clippy_lints/src/format_push_string.rs index ebf5ab086dce..9b9f1872bfc1 100644 --- a/clippy_lints/src/format_push_string.rs +++ b/clippy_lints/src/format_push_string.rs @@ -54,7 +54,7 @@ fn is_format(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { impl<'tcx> LateLintPass<'tcx> for FormatPushString { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let arg = match expr.kind { - ExprKind::MethodCall(_, [_, arg], _) => { + ExprKind::MethodCall(_, _, [arg], _) => { if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) && match_def_path(cx, fn_def_id, &paths::PUSH_STR) { arg diff --git a/clippy_lints/src/functions/must_use.rs b/clippy_lints/src/functions/must_use.rs index 6672a6cb0b58..a17b23f5edc8 100644 --- a/clippy_lints/src/functions/must_use.rs +++ b/clippy_lints/src/functions/must_use.rs @@ -212,7 +212,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> { return; } match expr.kind { - Call(_, args) | MethodCall(_, args, _) => { + Call(_, args) => { let mut tys = DefIdSet::default(); for arg in args { if self.cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id()) @@ -230,6 +230,24 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> { tys.clear(); } }, + MethodCall(_, receiver, args, _) => { + let mut tys = DefIdSet::default(); + for arg in std::iter::once(receiver).chain(args.iter()) { + if self.cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id()) + && is_mutable_ty( + self.cx, + self.cx.tcx.typeck(arg.hir_id.owner).expr_ty(arg), + arg.span, + &mut tys, + ) + && is_mutated_static(arg) + { + self.mutates_static = true; + return; + } + tys.clear(); + } + }, Assign(target, ..) | AssignOp(_, target, _) | AddrOf(_, hir::Mutability::Mut, target) => { self.mutates_static |= is_mutated_static(target); }, diff --git a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs index 565a1c871d75..3bbfa52e8103 100644 --- a/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs +++ b/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs @@ -88,11 +88,12 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> { } } }, - hir::ExprKind::MethodCall(_, args, _) => { + hir::ExprKind::MethodCall(_, receiver, args, _) => { let def_id = self.typeck_results.type_dependent_def_id(expr.hir_id).unwrap(); let base_type = self.cx.tcx.type_of(def_id); if type_is_unsafe_function(self.cx, base_type) { + self.check_arg(receiver); for arg in args { self.check_arg(arg); } diff --git a/clippy_lints/src/if_let_mutex.rs b/clippy_lints/src/if_let_mutex.rs index 4d703d691acc..9ea8c494cfcd 100644 --- a/clippy_lints/src/if_let_mutex.rs +++ b/clippy_lints/src/if_let_mutex.rs @@ -129,7 +129,7 @@ impl<'tcx, 'l> ArmVisitor<'tcx, 'l> { fn is_mutex_lock_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { if_chain! { - if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind; + if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind; if path.ident.as_str() == "lock"; let ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); if is_type_diagnostic_item(cx, ty, sym::Mutex); diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index 01c7eef4e04d..fca3cb46a2e9 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -123,43 +123,43 @@ use self::Heuristic::{All, Always, Any, First}; /// is an upper bound, e.g., some methods can return a possibly /// infinite iterator at worst, e.g., `take_while`. const HEURISTICS: [(&str, usize, Heuristic, Finiteness); 19] = [ - ("zip", 2, All, Infinite), - ("chain", 2, Any, Infinite), - ("cycle", 1, Always, Infinite), - ("map", 2, First, Infinite), - ("by_ref", 1, First, Infinite), - ("cloned", 1, First, Infinite), - ("rev", 1, First, Infinite), - ("inspect", 1, First, Infinite), - ("enumerate", 1, First, Infinite), - ("peekable", 2, First, Infinite), - ("fuse", 1, First, Infinite), - ("skip", 2, First, Infinite), - ("skip_while", 1, First, Infinite), - ("filter", 2, First, Infinite), - ("filter_map", 2, First, Infinite), - ("flat_map", 2, First, Infinite), - ("unzip", 1, First, Infinite), - ("take_while", 2, First, MaybeInfinite), - ("scan", 3, First, MaybeInfinite), + ("zip", 1, All, Infinite), + ("chain", 1, Any, Infinite), + ("cycle", 0, Always, Infinite), + ("map", 1, First, Infinite), + ("by_ref", 0, First, Infinite), + ("cloned", 0, First, Infinite), + ("rev", 0, First, Infinite), + ("inspect", 0, First, Infinite), + ("enumerate", 0, First, Infinite), + ("peekable", 1, First, Infinite), + ("fuse", 0, First, Infinite), + ("skip", 1, First, Infinite), + ("skip_while", 0, First, Infinite), + ("filter", 1, First, Infinite), + ("filter_map", 1, First, Infinite), + ("flat_map", 1, First, Infinite), + ("unzip", 0, First, Infinite), + ("take_while", 1, First, MaybeInfinite), + ("scan", 2, First, MaybeInfinite), ]; fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { match expr.kind { - ExprKind::MethodCall(method, args, _) => { + ExprKind::MethodCall(method, receiver, args, _) => { for &(name, len, heuristic, cap) in &HEURISTICS { if method.ident.name.as_str() == name && args.len() == len { return (match heuristic { Always => Infinite, - First => is_infinite(cx, &args[0]), - Any => is_infinite(cx, &args[0]).or(is_infinite(cx, &args[1])), - All => is_infinite(cx, &args[0]).and(is_infinite(cx, &args[1])), + First => is_infinite(cx, receiver), + Any => is_infinite(cx, receiver).or(is_infinite(cx, &args[0])), + All => is_infinite(cx, receiver).and(is_infinite(cx, &args[0])), }) .and(cap); } } - if method.ident.name == sym!(flat_map) && args.len() == 2 { - if let ExprKind::Closure(&Closure { body, .. }) = args[1].kind { + if method.ident.name == sym!(flat_map) && args.len() == 1 { + if let ExprKind::Closure(&Closure { body, .. }) = args[0].kind { let body = cx.tcx.hir().body(body); return is_infinite(cx, &body.value); } @@ -179,29 +179,29 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { /// the names and argument lengths of methods that *may* exhaust their /// iterators const POSSIBLY_COMPLETING_METHODS: [(&str, usize); 6] = [ - ("find", 2), - ("rfind", 2), - ("position", 2), - ("rposition", 2), - ("any", 2), - ("all", 2), + ("find", 1), + ("rfind", 1), + ("position", 1), + ("rposition", 1), + ("any", 1), + ("all", 1), ]; /// the names and argument lengths of methods that *always* exhaust /// their iterators const COMPLETING_METHODS: [(&str, usize); 12] = [ - ("count", 1), - ("fold", 3), - ("for_each", 2), - ("partition", 2), - ("max", 1), - ("max_by", 2), - ("max_by_key", 2), - ("min", 1), - ("min_by", 2), - ("min_by_key", 2), - ("sum", 1), - ("product", 1), + ("count", 0), + ("fold", 2), + ("for_each", 1), + ("partition", 1), + ("max", 0), + ("max_by", 1), + ("max_by_key", 1), + ("min", 0), + ("min_by", 1), + ("min_by_key", 1), + ("sum", 0), + ("product", 0), ]; /// the paths of types that are known to be infinitely allocating @@ -218,26 +218,26 @@ const INFINITE_COLLECTORS: &[Symbol] = &[ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { match expr.kind { - ExprKind::MethodCall(method, args, _) => { + ExprKind::MethodCall(method, receiver, args, _) => { for &(name, len) in &COMPLETING_METHODS { if method.ident.name.as_str() == name && args.len() == len { - return is_infinite(cx, &args[0]); + return is_infinite(cx, receiver); } } for &(name, len) in &POSSIBLY_COMPLETING_METHODS { if method.ident.name.as_str() == name && args.len() == len { - return MaybeInfinite.and(is_infinite(cx, &args[0])); + return MaybeInfinite.and(is_infinite(cx, receiver)); } } - if method.ident.name == sym!(last) && args.len() == 1 { + if method.ident.name == sym!(last) { let not_double_ended = cx .tcx .get_diagnostic_item(sym::DoubleEndedIterator) .map_or(false, |id| { - !implements_trait(cx, cx.typeck_results().expr_ty(&args[0]), id, &[]) + !implements_trait(cx, cx.typeck_results().expr_ty(receiver), id, &[]) }); if not_double_ended { - return is_infinite(cx, &args[0]); + return is_infinite(cx, receiver); } } else if method.ident.name == sym!(collect) { let ty = cx.typeck_results().expr_ty(expr); @@ -245,7 +245,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { .iter() .any(|diag_item| is_type_diagnostic_item(cx, ty, *diag_item)) { - return is_infinite(cx, &args[0]); + return is_infinite(cx, receiver); } } }, diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 246f5aad8fba..25f366bfe6a8 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -370,7 +370,7 @@ fn check_for_is_empty<'tcx>( } fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) { - if let (&ExprKind::MethodCall(method_path, args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) { + if let (&ExprKind::MethodCall(method_path, receiver, ..), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) { // check if we are in an is_empty() method if let Some(name) = get_item_name(cx, method) { if name.as_str() == "is_empty" { @@ -378,7 +378,7 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_> } } - check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to); + check_len(cx, span, method_path.ident.name, receiver, &lit.node, op, compare_to); } else { check_empty_expr(cx, span, method, lit, op); } @@ -388,7 +388,7 @@ fn check_len( cx: &LateContext<'_>, span: Span, method_name: Symbol, - args: &[Expr<'_>], + receiver: &Expr<'_>, lit: &LitKind, op: &str, compare_to: u32, @@ -399,7 +399,7 @@ fn check_len( return; } - if method_name == sym::len && args.len() == 1 && has_is_empty(cx, &args[0]) { + if method_name == sym::len && has_is_empty(cx, receiver) { let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, @@ -410,7 +410,7 @@ fn check_len( format!( "{}{}.is_empty()", op, - snippet_with_applicability(cx, args[0].span, "_", &mut applicability) + snippet_with_applicability(cx, receiver.span, "_", &mut applicability) ), applicability, ); diff --git a/clippy_lints/src/loops/manual_memcpy.rs b/clippy_lints/src/loops/manual_memcpy.rs index a65df48e413e..3fc569af89ec 100644 --- a/clippy_lints/src/loops/manual_memcpy.rs +++ b/clippy_lints/src/loops/manual_memcpy.rs @@ -119,7 +119,7 @@ fn build_manual_memcpy_suggestion<'tcx>( let print_limit = |end: &Expr<'_>, end_str: &str, base: &Expr<'_>, sugg: MinifyingSugg<'static>| { if_chain! { - if let ExprKind::MethodCall(method, [recv], _) = end.kind; + if let ExprKind::MethodCall(method, recv, [], _) = end.kind; if method.ident.name == sym::len; if path_to_local(recv) == path_to_local(base); then { @@ -341,7 +341,7 @@ fn get_slice_like_element_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Opti fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> { if_chain! { - if let ExprKind::MethodCall(method, [arg], _) = expr.kind; + if let ExprKind::MethodCall(method, arg, [], _) = expr.kind; if method.ident.name == sym::clone; then { arg } else { expr } } diff --git a/clippy_lints/src/loops/missing_spin_loop.rs b/clippy_lints/src/loops/missing_spin_loop.rs index 0696afa39225..8412875b11b7 100644 --- a/clippy_lints/src/loops/missing_spin_loop.rs +++ b/clippy_lints/src/loops/missing_spin_loop.rs @@ -33,7 +33,7 @@ fn unpack_cond<'tcx>(cond: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> { pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &'tcx Expr<'_>) { if_chain! { if let ExprKind::Block(Block { stmts: [], expr: None, ..}, _) = body.kind; - if let ExprKind::MethodCall(method, [callee, ..], _) = unpack_cond(cond).kind; + if let ExprKind::MethodCall(method, callee, ..) = unpack_cond(cond).kind; if [sym::load, sym::compare_exchange, sym::compare_exchange_weak].contains(&method.ident.name); if let ty::Adt(def, _substs) = cx.typeck_results().expr_ty(callee).kind(); if cx.tcx.is_diagnostic_item(sym::AtomicBool, def.did()); diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs index ed270bd490d7..74f3bda9f43e 100644 --- a/clippy_lints/src/loops/mod.rs +++ b/clippy_lints/src/loops/mod.rs @@ -742,7 +742,7 @@ fn check_for_loop<'tcx>( fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) { let mut next_loop_linted = false; // whether or not ITER_NEXT_LOOP lint was used - if let ExprKind::MethodCall(method, [self_arg], _) = arg.kind { + if let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind { let method_name = method.ident.as_str(); // check for looping over x.iter() or x.iter_mut(), could use &x or &mut x match method_name { diff --git a/clippy_lints/src/loops/needless_collect.rs b/clippy_lints/src/loops/needless_collect.rs index 6d987f393fa5..6e6faa79adc9 100644 --- a/clippy_lints/src/loops/needless_collect.rs +++ b/clippy_lints/src/loops/needless_collect.rs @@ -25,11 +25,11 @@ pub(super) fn check<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) { } fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) { if_chain! { - if let ExprKind::MethodCall(method, args, _) = expr.kind; - if let ExprKind::MethodCall(chain_method, _, _) = args[0].kind; - if chain_method.ident.name == sym!(collect) && is_trait_method(cx, &args[0], sym::Iterator); + if let ExprKind::MethodCall(method, receiver, args, _) = expr.kind; + if let ExprKind::MethodCall(chain_method, ..) = receiver.kind; + if chain_method.ident.name == sym!(collect) && is_trait_method(cx, receiver, sym::Iterator); then { - let ty = cx.typeck_results().expr_ty(&args[0]); + let ty = cx.typeck_results().expr_ty(receiver); let mut applicability = Applicability::MaybeIncorrect; let is_empty_sugg = "next().is_none()".to_string(); let method_name = method.ident.name.as_str(); @@ -41,7 +41,7 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont "len" => "count()".to_string(), "is_empty" => is_empty_sugg, "contains" => { - let contains_arg = snippet_with_applicability(cx, args[1].span, "??", &mut applicability); + let contains_arg = snippet_with_applicability(cx, args[0].span, "??", &mut applicability); let (arg, pred) = contains_arg .strip_prefix('&') .map_or(("&x", &*contains_arg), |s| ("x", s)); @@ -80,7 +80,7 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo if let StmtKind::Local(local) = stmt.kind; if let PatKind::Binding(_, id, ..) = local.pat.kind; if let Some(init_expr) = local.init; - if let ExprKind::MethodCall(method_name, &[ref iter_source], ..) = init_expr.kind; + if let ExprKind::MethodCall(method_name, iter_source, [], ..) = init_expr.kind; if method_name.ident.name == sym!(collect) && is_trait_method(cx, init_expr, sym::Iterator); let ty = cx.typeck_results().expr_ty(init_expr); if is_type_diagnostic_item(cx, ty, sym::Vec) || @@ -203,7 +203,7 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { // Check function calls on our collection - if let ExprKind::MethodCall(method_name, [recv, args @ ..], _) = &expr.kind { + if let ExprKind::MethodCall(method_name, recv, [args @ ..], _) = &expr.kind { if method_name.ident.name == sym!(collect) && is_trait_method(self.cx, expr, sym::Iterator) { self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(recv)); self.visit_expr(recv); diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index 7ca4a7c4ebfc..ffcf83e4605e 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -188,7 +188,7 @@ pub(super) fn check<'tcx>( fn is_len_call(expr: &Expr<'_>, var: Symbol) -> bool { if_chain! { - if let ExprKind::MethodCall(method, [recv], _) = expr.kind; + if let ExprKind::MethodCall(method, recv, [], _) = expr.kind; if method.ident.name == sym::len; if let ExprKind::Path(QPath::Resolved(_, path)) = recv.kind; if path.segments.len() == 1; @@ -301,7 +301,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { if_chain! { // a range index op - if let ExprKind::MethodCall(meth, [args_0, args_1, ..], _) = &expr.kind; + if let ExprKind::MethodCall(meth, args_0, [args_1, ..], _) = &expr.kind; if (meth.ident.name == sym::index && match_trait_method(self.cx, expr, &paths::INDEX)) || (meth.ident.name == sym::index_mut && match_trait_method(self.cx, expr, &paths::INDEX_MUT)); if !self.check(args_1, args_0, expr); @@ -356,9 +356,12 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { self.visit_expr(expr); } }, - ExprKind::MethodCall(_, args, _) => { + ExprKind::MethodCall(_, receiver, args, _) => { let def_id = self.cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap(); - for (ty, expr) in iter::zip(self.cx.tcx.fn_sig(def_id).inputs().skip_binder(), args) { + for (ty, expr) in iter::zip( + self.cx.tcx.fn_sig(def_id).inputs().skip_binder(), + std::iter::once(receiver).chain(args.iter()), + ) { self.prefer_mutable = false; if let ty::Ref(_, _, mutbl) = *ty.kind() { if mutbl == Mutability::Mut { diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs index 5448360049d2..116e589cad6f 100644 --- a/clippy_lints/src/loops/never_loop.rs +++ b/clippy_lints/src/loops/never_loop.rs @@ -120,8 +120,9 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult { | ExprKind::Repeat(e, _) | ExprKind::DropTemps(e) => never_loop_expr(e, main_loop_id), ExprKind::Let(let_expr) => never_loop_expr(let_expr.init, main_loop_id), - ExprKind::Array(es) | ExprKind::MethodCall(_, es, _) | ExprKind::Tup(es) => { - never_loop_expr_all(&mut es.iter(), main_loop_id) + ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(&mut es.iter(), main_loop_id), + ExprKind::MethodCall(_, receiver, es, _) => { + never_loop_expr_all(&mut std::iter::once(receiver).chain(es.iter()), main_loop_id) }, ExprKind::Struct(_, fields, base) => { let fields = never_loop_expr_all(&mut fields.iter().map(|f| f.expr), main_loop_id); diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs index 1439f1f4c75d..23f47091f77f 100644 --- a/clippy_lints/src/loops/same_item_push.rs +++ b/clippy_lints/src/loops/same_item_push.rs @@ -180,10 +180,9 @@ fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(& if_chain! { // Extract method being called if let StmtKind::Semi(semi_stmt) = &stmt.kind; - if let ExprKind::MethodCall(path, args, _) = &semi_stmt.kind; + if let ExprKind::MethodCall(path, self_expr, args, _) = &semi_stmt.kind; // Figure out the parameters for the method call - if let Some(self_expr) = args.get(0); - if let Some(pushed_item) = args.get(1); + if let Some(pushed_item) = args.get(0); // Check that the method being called is push() on a Vec if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec); if path.ident.name.as_str() == "push"; diff --git a/clippy_lints/src/loops/single_element_loop.rs b/clippy_lints/src/loops/single_element_loop.rs index a0bd7ad0ac64..f4b47808dfaa 100644 --- a/clippy_lints/src/loops/single_element_loop.rs +++ b/clippy_lints/src/loops/single_element_loop.rs @@ -35,32 +35,29 @@ pub(super) fn check<'tcx>( ) => (arg, "&mut "), ExprKind::MethodCall( method, - [ - Expr { - kind: ExprKind::Array([arg]), - .. - }, - ], + Expr { + kind: ExprKind::Array([arg]), + .. + }, + [], _, ) if method.ident.name == rustc_span::sym::iter => (arg, "&"), ExprKind::MethodCall( method, - [ - Expr { - kind: ExprKind::Array([arg]), - .. - }, - ], + Expr { + kind: ExprKind::Array([arg]), + .. + }, + [], _, ) if method.ident.name.as_str() == "iter_mut" => (arg, "&mut "), ExprKind::MethodCall( method, - [ - Expr { - kind: ExprKind::Array([arg]), - .. - }, - ], + Expr { + kind: ExprKind::Array([arg]), + .. + }, + [], _, ) if method.ident.name == rustc_span::sym::into_iter => (arg, ""), // Only check for arrays edition 2021 or later, as this case will trigger a compiler error otherwise. diff --git a/clippy_lints/src/loops/while_let_loop.rs b/clippy_lints/src/loops/while_let_loop.rs index ca617859db49..735d704a43ce 100644 --- a/clippy_lints/src/loops/while_let_loop.rs +++ b/clippy_lints/src/loops/while_let_loop.rs @@ -11,7 +11,14 @@ use rustc_lint::LateContext; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) { let (init, has_trailing_exprs) = match (loop_block.stmts, loop_block.expr) { ([stmt, stmts @ ..], expr) => { - if let StmtKind::Local(&Local { init: Some(e), els: None, .. }) | StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind { + if let StmtKind::Local(&Local { + init: Some(e), + els: None, + .. + }) + | StmtKind::Semi(e) + | StmtKind::Expr(e) = stmt.kind + { (e, !stmts.is_empty() || expr.is_some()) } else { return; diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs index e9e215e662f1..2c54033f8597 100644 --- a/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/clippy_lints/src/loops/while_let_on_iterator.rs @@ -23,7 +23,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let Res::Def(_, pat_did) = pat_path.res; if match_def_path(cx, pat_did, &paths::OPTION_SOME); // check for call to `Iterator::next` - if let ExprKind::MethodCall(method_name, [iter_expr], _) = let_expr.kind; + if let ExprKind::MethodCall(method_name, iter_expr, [], _) = let_expr.kind; if method_name.ident.name == sym::next; if is_trait_method(cx, let_expr, sym::Iterator); if let Some(iter_expr_struct) = try_parse_iter_expr(cx, iter_expr); diff --git a/clippy_lints/src/manual_bits.rs b/clippy_lints/src/manual_bits.rs index 940601a44fb0..6655c92b1da8 100644 --- a/clippy_lints/src/manual_bits.rs +++ b/clippy_lints/src/manual_bits.rs @@ -134,7 +134,7 @@ fn create_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, base_sugg: String) -> Stri fn is_ty_conversion(expr: &Expr<'_>) -> bool { if let ExprKind::Cast(..) = expr.kind { true - } else if let ExprKind::MethodCall(path, [_], _) = expr.kind + } else if let ExprKind::MethodCall(path, _, [], _) = expr.kind && path.ident.name == rustc_span::sym::try_into { // This is only called for `usize` which implements `TryInto`. Therefore, diff --git a/clippy_lints/src/manual_retain.rs b/clippy_lints/src/manual_retain.rs index 42d2577cc316..f28c37d3dca7 100644 --- a/clippy_lints/src/manual_retain.rs +++ b/clippy_lints/src/manual_retain.rs @@ -66,9 +66,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualRetain { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { if let Some(parent_expr) = get_parent_expr(cx, expr) && let Assign(left_expr, collect_expr, _) = &parent_expr.kind - && let hir::ExprKind::MethodCall(seg, _, _) = &collect_expr.kind + && let hir::ExprKind::MethodCall(seg, ..) = &collect_expr.kind && seg.args.is_none() - && let hir::ExprKind::MethodCall(_, [target_expr], _) = &collect_expr.kind + && let hir::ExprKind::MethodCall(_, target_expr, [], _) = &collect_expr.kind && let Some(collect_def_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id) && match_def_path(cx, collect_def_id, &paths::CORE_ITER_COLLECT) { check_into_iter(cx, parent_expr, left_expr, target_expr, self.msrv); @@ -87,10 +87,10 @@ fn check_into_iter( target_expr: &hir::Expr<'_>, msrv: Option, ) { - if let hir::ExprKind::MethodCall(_, [into_iter_expr, _], _) = &target_expr.kind + if let hir::ExprKind::MethodCall(_, into_iter_expr, [_], _) = &target_expr.kind && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id) && match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER) - && let hir::ExprKind::MethodCall(_, [struct_expr], _) = &into_iter_expr.kind + && let hir::ExprKind::MethodCall(_, struct_expr, [], _) = &into_iter_expr.kind && let Some(into_iter_def_id) = cx.typeck_results().type_dependent_def_id(into_iter_expr.hir_id) && match_def_path(cx, into_iter_def_id, &paths::CORE_ITER_INTO_ITER) && match_acceptable_type(cx, left_expr, msrv) @@ -106,14 +106,14 @@ fn check_iter( target_expr: &hir::Expr<'_>, msrv: Option, ) { - if let hir::ExprKind::MethodCall(_, [filter_expr], _) = &target_expr.kind + if let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind && let Some(copied_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id) && (match_def_path(cx, copied_def_id, &paths::CORE_ITER_COPIED) || match_def_path(cx, copied_def_id, &paths::CORE_ITER_CLONED)) - && let hir::ExprKind::MethodCall(_, [iter_expr, _], _) = &filter_expr.kind + && let hir::ExprKind::MethodCall(_, iter_expr, [_], _) = &filter_expr.kind && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id) && match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER) - && let hir::ExprKind::MethodCall(_, [struct_expr], _) = &iter_expr.kind + && let hir::ExprKind::MethodCall(_, struct_expr, [], _) = &iter_expr.kind && let Some(iter_expr_def_id) = cx.typeck_results().type_dependent_def_id(iter_expr.hir_id) && match_acceptable_def_path(cx, iter_expr_def_id) && match_acceptable_type(cx, left_expr, msrv) @@ -130,13 +130,13 @@ fn check_to_owned( msrv: Option, ) { if meets_msrv(msrv, msrvs::STRING_RETAIN) - && let hir::ExprKind::MethodCall(_, [filter_expr], _) = &target_expr.kind + && let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind && let Some(to_owned_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id) && match_def_path(cx, to_owned_def_id, &paths::TO_OWNED_METHOD) - && let hir::ExprKind::MethodCall(_, [chars_expr, _], _) = &filter_expr.kind + && let hir::ExprKind::MethodCall(_, chars_expr, [_], _) = &filter_expr.kind && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id) && match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER) - && let hir::ExprKind::MethodCall(_, [str_expr], _) = &chars_expr.kind + && let hir::ExprKind::MethodCall(_, str_expr, [], _) = &chars_expr.kind && let Some(chars_expr_def_id) = cx.typeck_results().type_dependent_def_id(chars_expr.hir_id) && match_def_path(cx, chars_expr_def_id, &paths::STR_CHARS) && let ty = cx.typeck_results().expr_ty(str_expr).peel_refs() @@ -147,7 +147,7 @@ fn check_to_owned( } fn suggest(cx: &LateContext<'_>, parent_expr: &hir::Expr<'_>, left_expr: &hir::Expr<'_>, filter_expr: &hir::Expr<'_>) { - if let hir::ExprKind::MethodCall(_, [_, closure], _) = filter_expr.kind + if let hir::ExprKind::MethodCall(_, _, [closure], _) = filter_expr.kind && let hir::ExprKind::Closure(&hir::Closure { body, ..}) = closure.kind && let filter_body = cx.tcx.hir().body(body) && let [filter_params] = filter_body.params diff --git a/clippy_lints/src/manual_string_new.rs b/clippy_lints/src/manual_string_new.rs index a90eaa8fdcbe..6acfb2ae3471 100644 --- a/clippy_lints/src/manual_string_new.rs +++ b/clippy_lints/src/manual_string_new.rs @@ -55,8 +55,8 @@ impl LateLintPass<'_> for ManualStringNew { ExprKind::Call(func, args) => { parse_call(cx, expr.span, func, args); }, - ExprKind::MethodCall(path_segment, args, _) => { - parse_method_call(cx, expr.span, path_segment, args); + ExprKind::MethodCall(path_segment, receiver, ..) => { + parse_method_call(cx, expr.span, path_segment, receiver); }, _ => (), } @@ -88,14 +88,9 @@ fn warn_then_suggest(cx: &LateContext<'_>, span: Span) { } /// Tries to parse an expression as a method call, emitting the warning if necessary. -fn parse_method_call(cx: &LateContext<'_>, span: Span, path_segment: &PathSegment<'_>, args: &[Expr<'_>]) { - if args.is_empty() { - // When parsing TryFrom::try_from(...).expect(...), we will have more than 1 arg. - return; - } - +fn parse_method_call(cx: &LateContext<'_>, span: Span, path_segment: &PathSegment<'_>, receiver: &Expr<'_>) { let ident = path_segment.ident.as_str(); - let method_arg_kind = &args[0].kind; + let method_arg_kind = &receiver.kind; if ["to_string", "to_owned", "into"].contains(&ident) && is_expr_kind_empty_str(method_arg_kind) { warn_then_suggest(cx, span); } else if let ExprKind::Call(func, args) = method_arg_kind { diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index dfb3efc4e28b..7941c8c9c7e3 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { if_chain! { if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr); - if let ExprKind::MethodCall(_, [target_arg, pattern], _) = cond.kind; + if let ExprKind::MethodCall(_, target_arg, [pattern], _) = cond.kind; if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id); if let ExprKind::Path(target_path) = &target_arg.kind; then { @@ -132,7 +132,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { // Returns `Some(arg)` if `expr` matches `arg.len()` and `None` otherwise. fn len_arg<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { if_chain! { - if let ExprKind::MethodCall(_, [arg], _) = expr.kind; + if let ExprKind::MethodCall(_, arg, [], _) = expr.kind; if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if match_def_path(cx, method_def_id, &paths::STR_LEN); then { diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 6db852c3ffe7..33d744815299 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -200,8 +200,13 @@ fn suggestion_msg(function_type: &str, map_type: &str) -> String { ) } -fn lint_map_unit_fn(cx: &LateContext<'_>, stmt: &hir::Stmt<'_>, expr: &hir::Expr<'_>, map_args: &[hir::Expr<'_>]) { - let var_arg = &map_args[0]; +fn lint_map_unit_fn( + cx: &LateContext<'_>, + stmt: &hir::Stmt<'_>, + expr: &hir::Expr<'_>, + map_args: (&hir::Expr<'_>, &[hir::Expr<'_>]), +) { + let var_arg = &map_args.0; let (map_type, variant, lint) = if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::Option) { ("Option", "Some", OPTION_MAP_UNIT_FN) @@ -210,7 +215,7 @@ fn lint_map_unit_fn(cx: &LateContext<'_>, stmt: &hir::Stmt<'_>, expr: &hir::Expr } else { return; }; - let fn_arg = &map_args[1]; + let fn_arg = &map_args.1[0]; if is_unit_function(cx, fn_arg) { let mut applicability = Applicability::MachineApplicable; diff --git a/clippy_lints/src/match_result_ok.rs b/clippy_lints/src/match_result_ok.rs index 3349b85f1347..8588ab1ed8db 100644 --- a/clippy_lints/src/match_result_ok.rs +++ b/clippy_lints/src/match_result_ok.rs @@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchResultOk { }; if_chain! { - if let ExprKind::MethodCall(ok_path, [ref result_types_0, ..], _) = let_expr.kind; //check is expr.ok() has type Result.ok(, _) + if let ExprKind::MethodCall(ok_path, result_types_0, ..) = let_expr.kind; //check is expr.ok() has type Result.ok(, _) if let PatKind::TupleStruct(QPath::Resolved(_, x), y, _) = let_pat.kind; //get operation if method_chain_args(let_expr, &["ok"]).is_some(); //test to see if using ok() method use std::marker::Sized; if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(result_types_0), sym::Result); diff --git a/clippy_lints/src/matches/match_str_case_mismatch.rs b/clippy_lints/src/matches/match_str_case_mismatch.rs index fa3b8d1fceaa..1e80b6cf2d83 100644 --- a/clippy_lints/src/matches/match_str_case_mismatch.rs +++ b/clippy_lints/src/matches/match_str_case_mismatch.rs @@ -48,7 +48,7 @@ struct MatchExprVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for MatchExprVisitor<'a, 'tcx> { fn visit_expr(&mut self, ex: &'tcx Expr<'_>) { match ex.kind { - ExprKind::MethodCall(segment, [receiver], _) if self.case_altered(segment.ident.as_str(), receiver) => {}, + ExprKind::MethodCall(segment, receiver, [], _) if self.case_altered(segment.ident.as_str(), receiver) => {}, _ => walk_expr(self, ex), } } diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs index 8499e050af24..f7443471e31d 100644 --- a/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/clippy_lints/src/matches/redundant_pattern_match.rs @@ -120,7 +120,7 @@ fn find_sugg_for_if_let<'tcx>( // check that `while_let_on_iterator` lint does not trigger if_chain! { if keyword == "while"; - if let ExprKind::MethodCall(method_path, _, _) = let_expr.kind; + if let ExprKind::MethodCall(method_path, ..) = let_expr.kind; if method_path.ident.name == sym::next; if is_trait_method(cx, let_expr, sym::Iterator); then { diff --git a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index b0b15b3f54cd..86a9df034979 100644 --- a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -291,7 +291,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> { self.is_chain_end = false; match ex.kind { - ExprKind::MethodCall(_, [ref expr, ..], _) => { + ExprKind::MethodCall(_, expr, ..) => { self.visit_expr(expr); } ExprKind::Binary(_, left, right) => { @@ -331,8 +331,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> { ExprKind::Index(..) | ExprKind::Ret(..) | ExprKind::Repeat(..) | - ExprKind::Yield(..) | - ExprKind::MethodCall(..) => walk_expr(self, ex), + ExprKind::Yield(..) => walk_expr(self, ex), ExprKind::AddrOf(_, _, _) | ExprKind::Block(_, _) | ExprKind::Break(_, _) | diff --git a/clippy_lints/src/methods/bytecount.rs b/clippy_lints/src/methods/bytecount.rs index 6a7c63d76f72..fef90f6eba49 100644 --- a/clippy_lints/src/methods/bytecount.rs +++ b/clippy_lints/src/methods/bytecount.rs @@ -42,11 +42,11 @@ pub(super) fn check<'tcx>( if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(needle).peel_refs().kind(); if !is_local_used(cx, needle, arg_id); then { - let haystack = if let ExprKind::MethodCall(path, args, _) = + let haystack = if let ExprKind::MethodCall(path, receiver, [], _) = filter_recv.kind { let p = path.ident.name; - if (p == sym::iter || p == sym!(iter_mut)) && args.len() == 1 { - &args[0] + if p == sym::iter || p == sym!(iter_mut) { + receiver } else { filter_recv } diff --git a/clippy_lints/src/methods/chars_cmp.rs b/clippy_lints/src/methods/chars_cmp.rs index f7b79f0839ba..51aec21527a7 100644 --- a/clippy_lints/src/methods/chars_cmp.rs +++ b/clippy_lints/src/methods/chars_cmp.rs @@ -23,7 +23,7 @@ pub(super) fn check( if Some(id) == cx.tcx.lang_items().option_some_variant(); then { let mut applicability = Applicability::MachineApplicable; - let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0][0]).peel_refs(); + let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0].0).peel_refs(); if *self_ty.kind() != ty::Str { return false; @@ -37,7 +37,7 @@ pub(super) fn check( "like this", format!("{}{}.{}({})", if info.eq { "" } else { "!" }, - snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability), + snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability), suggest, snippet_with_applicability(cx, arg_char.span, "..", &mut applicability)), applicability, diff --git a/clippy_lints/src/methods/chars_cmp_with_unwrap.rs b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs index a7c0e43923e1..b85bfec2b12b 100644 --- a/clippy_lints/src/methods/chars_cmp_with_unwrap.rs +++ b/clippy_lints/src/methods/chars_cmp_with_unwrap.rs @@ -30,7 +30,7 @@ pub(super) fn check<'tcx>( "like this", format!("{}{}.{}('{}')", if info.eq { "" } else { "!" }, - snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability), + snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability), suggest, c.escape_default()), applicability, diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index 60e1355f9b92..9ae6297ec2f6 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -14,9 +14,15 @@ use super::CLONE_ON_COPY; /// Checks for the `CLONE_ON_COPY` lint. #[allow(clippy::too_many_lines)] -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, args: &[Expr<'_>]) { +pub(super) fn check( + cx: &LateContext<'_>, + expr: &Expr<'_>, + method_name: Symbol, + receiver: &Expr<'_>, + args: &[Expr<'_>], +) { let arg = match args { - [arg] if method_name == sym::clone => arg, + [] if method_name == sym::clone => receiver, _ => return, }; if cx @@ -81,7 +87,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, // &*x is a nop, &x.clone() is not ExprKind::AddrOf(..) => return, // (*x).func() is useless, x.clone().func() can work in case func borrows self - ExprKind::MethodCall(_, [self_arg, ..], _) + ExprKind::MethodCall(_, self_arg, ..) if expr.hir_id == self_arg.hir_id && ty != cx.typeck_results().expr_ty_adjusted(expr) => { return; @@ -91,7 +97,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, hir_callee.kind, ExprKind::Path(QPath::LangItem(rustc_hir::LangItem::TryTraitBranch, _, _)) ), - ExprKind::MethodCall(_, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true, + ExprKind::MethodCall(_, self_arg, ..) if expr.hir_id == self_arg.hir_id => true, ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar) | ExprKind::Field(..) | ExprKind::Index(..) => true, diff --git a/clippy_lints/src/methods/clone_on_ref_ptr.rs b/clippy_lints/src/methods/clone_on_ref_ptr.rs index 6417bc813047..7098d564cfc8 100644 --- a/clippy_lints/src/methods/clone_on_ref_ptr.rs +++ b/clippy_lints/src/methods/clone_on_ref_ptr.rs @@ -10,11 +10,17 @@ use rustc_span::symbol::{sym, Symbol}; use super::CLONE_ON_REF_PTR; -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) { - if !(args.len() == 1 && method_name == sym::clone) { +pub(super) fn check( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + method_name: Symbol, + receiver: &hir::Expr<'_>, + args: &[hir::Expr<'_>], +) { + if !(args.is_empty() && method_name == sym::clone) { return; } - let arg = &args[0]; + let arg = receiver; let obj_ty = cx.typeck_results().expr_ty(arg).peel_refs(); if let ty::Adt(_, subst) = obj_ty.kind() { diff --git a/clippy_lints/src/methods/collapsible_str_replace.rs b/clippy_lints/src/methods/collapsible_str_replace.rs index 561033be5b6a..501646863fe1 100644 --- a/clippy_lints/src/methods/collapsible_str_replace.rs +++ b/clippy_lints/src/methods/collapsible_str_replace.rs @@ -23,7 +23,7 @@ pub(super) fn check<'tcx>( // If the parent node's `to` argument is the same as the `to` argument // of the last replace call in the current chain, don't lint as it was already linted if let Some(parent) = get_parent_expr(cx, expr) - && let Some(("replace", [_, current_from, current_to], _)) = method_call(parent) + && let Some(("replace", _, [current_from, current_to], _)) = method_call(parent) && eq_expr_value(cx, to, current_to) && from_kind == cx.typeck_results().expr_ty(current_from).peel_refs().kind() { @@ -48,7 +48,7 @@ fn collect_replace_calls<'tcx>( let mut from_args = VecDeque::new(); let _: Option<()> = for_each_expr(expr, |e| { - if let Some(("replace", [_, from, to], _)) = method_call(e) { + if let Some(("replace", _, [from, to], _)) = method_call(e) { if eq_expr_value(cx, to_arg, to) && cx.typeck_results().expr_ty(from).peel_refs().is_char() { methods.push_front(e); from_args.push_front(from); @@ -78,7 +78,7 @@ fn check_consecutive_replace_calls<'tcx>( .collect(); let app = Applicability::MachineApplicable; let earliest_replace_call = replace_methods.methods.front().unwrap(); - if let Some((_, [..], span_lo)) = method_call(earliest_replace_call) { + if let Some((_, _, [..], span_lo)) = method_call(earliest_replace_call) { span_lint_and_sugg( cx, COLLAPSIBLE_STR_REPLACE, diff --git a/clippy_lints/src/methods/expect_fun_call.rs b/clippy_lints/src/methods/expect_fun_call.rs index 6f2307d8f18f..bd846d71d466 100644 --- a/clippy_lints/src/methods/expect_fun_call.rs +++ b/clippy_lints/src/methods/expect_fun_call.rs @@ -19,6 +19,7 @@ pub(super) fn check<'tcx>( expr: &hir::Expr<'_>, method_span: Span, name: &str, + receiver: &'tcx hir::Expr<'tcx>, args: &'tcx [hir::Expr<'tcx>], ) { // Strip `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or @@ -28,16 +29,13 @@ pub(super) fn check<'tcx>( loop { arg_root = match &arg_root.kind { hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => expr, - hir::ExprKind::MethodCall(method_name, call_args, _) => { - if call_args.len() == 1 - && (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref) - && { - let arg_type = cx.typeck_results().expr_ty(&call_args[0]); - let base_type = arg_type.peel_refs(); - *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym::String) - } - { - &call_args[0] + hir::ExprKind::MethodCall(method_name, receiver, [], ..) => { + if (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref) && { + let arg_type = cx.typeck_results().expr_ty(receiver); + let base_type = arg_type.peel_refs(); + *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym::String) + } { + receiver } else { break; } @@ -114,11 +112,11 @@ pub(super) fn check<'tcx>( } } - if args.len() != 2 || name != "expect" || !is_call(&args[1].kind) { + if args.len() != 1 || name != "expect" || !is_call(&args[0].kind) { return; } - let receiver_type = cx.typeck_results().expr_ty_adjusted(&args[0]); + let receiver_type = cx.typeck_results().expr_ty_adjusted(receiver); let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym::Option) { "||" } else if is_type_diagnostic_item(cx, receiver_type, sym::Result) { @@ -127,7 +125,7 @@ pub(super) fn check<'tcx>( return; }; - let arg_root = get_arg_root(cx, &args[1]); + let arg_root = get_arg_root(cx, &args[0]); let span_replace_word = method_span.with_hi(expr.span.hi()); diff --git a/clippy_lints/src/methods/extend_with_drain.rs b/clippy_lints/src/methods/extend_with_drain.rs index a15fe6094022..37b28463527c 100644 --- a/clippy_lints/src/methods/extend_with_drain.rs +++ b/clippy_lints/src/methods/extend_with_drain.rs @@ -14,7 +14,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: if_chain! { if is_type_diagnostic_item(cx, ty, sym::Vec); //check source object - if let ExprKind::MethodCall(src_method, [drain_vec, drain_arg], _) = &arg.kind; + if let ExprKind::MethodCall(src_method, drain_vec, [drain_arg], _) = &arg.kind; if src_method.ident.as_str() == "drain"; let src_ty = cx.typeck_results().expr_ty(drain_vec); //check if actual src type is mutable for code suggestion diff --git a/clippy_lints/src/methods/filter_map.rs b/clippy_lints/src/methods/filter_map.rs index 692e22a7c5cf..9dc839afc625 100644 --- a/clippy_lints/src/methods/filter_map.rs +++ b/clippy_lints/src/methods/filter_map.rs @@ -28,11 +28,11 @@ fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy let closure_expr = peel_blocks(&body.value); let arg_id = body.params[0].pat.hir_id; match closure_expr.kind { - hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, args, _) => { + hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => { if_chain! { if ident.name == method_name; - if let hir::ExprKind::Path(path) = &args[0].kind; - if let Res::Local(ref local) = cx.qpath_res(path, args[0].hir_id); + if let hir::ExprKind::Path(path) = &receiver.kind; + if let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id); then { return arg_id == *local } @@ -106,7 +106,7 @@ pub(super) fn check<'tcx>( }; // closure ends with is_some() or is_ok() if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind; - if let ExprKind::MethodCall(path, [filter_arg], _) = filter_body.value.kind; + if let ExprKind::MethodCall(path, filter_arg, [], _) = filter_body.value.kind; if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).peel_refs().ty_adt_def(); if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did()) { Some(false) @@ -123,13 +123,13 @@ pub(super) fn check<'tcx>( if let [map_param] = map_body.params; if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind; // closure ends with expect() or unwrap() - if let ExprKind::MethodCall(seg, [map_arg, ..], _) = map_body.value.kind; + if let ExprKind::MethodCall(seg, map_arg, ..) = map_body.value.kind; if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or); // .filter(..).map(|y| f(y).copied().unwrap()) // ~~~~ let map_arg_peeled = match map_arg.kind { - ExprKind::MethodCall(method, [original_arg], _) if acceptable_methods(method) => { + ExprKind::MethodCall(method, original_arg, [], _) if acceptable_methods(method) => { original_arg }, _ => map_arg, diff --git a/clippy_lints/src/methods/get_last_with_len.rs b/clippy_lints/src/methods/get_last_with_len.rs index 23368238ef5c..02aada87202c 100644 --- a/clippy_lints/src/methods/get_last_with_len.rs +++ b/clippy_lints/src/methods/get_last_with_len.rs @@ -22,7 +22,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: ) = arg.kind // LHS of subtraction is "x.len()" - && let ExprKind::MethodCall(lhs_path, [lhs_recv], _) = &lhs.kind + && let ExprKind::MethodCall(lhs_path, lhs_recv, [], _) = &lhs.kind && lhs_path.ident.name == sym::len // RHS of subtraction is 1 diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index f52170df662c..e1c9b5248a8a 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -12,13 +12,19 @@ use rustc_span::symbol::{sym, Symbol}; use super::INEFFICIENT_TO_STRING; /// Checks for the `INEFFICIENT_TO_STRING` lint -pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) { +pub fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &hir::Expr<'_>, + method_name: Symbol, + receiver: &hir::Expr<'_>, + args: &[hir::Expr<'_>], +) { if_chain! { - if args.len() == 1 && method_name == sym::to_string; + if args.is_empty() && method_name == sym::to_string; if let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if match_def_path(cx, to_string_meth_did, &paths::TO_STRING_METHOD); if let Some(substs) = cx.typeck_results().node_substs_opt(expr.hir_id); - let arg_ty = cx.typeck_results().expr_ty_adjusted(&args[0]); + let arg_ty = cx.typeck_results().expr_ty_adjusted(receiver); let self_ty = substs.type_at(0); let (deref_self_ty, deref_count) = walk_ptrs_ty_depth(self_ty); if deref_count >= 1; @@ -35,7 +41,7 @@ pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy self_ty, deref_self_ty )); let mut applicability = Applicability::MachineApplicable; - let arg_snippet = snippet_with_applicability(cx, args[0].span, "..", &mut applicability); + let arg_snippet = snippet_with_applicability(cx, receiver.span, "..", &mut applicability); diag.span_suggestion( expr.span, "try dereferencing the receiver", diff --git a/clippy_lints/src/methods/into_iter_on_ref.rs b/clippy_lints/src/methods/into_iter_on_ref.rs index da13b4ba37a5..11e76841e9f0 100644 --- a/clippy_lints/src/methods/into_iter_on_ref.rs +++ b/clippy_lints/src/methods/into_iter_on_ref.rs @@ -16,9 +16,9 @@ pub(super) fn check( expr: &hir::Expr<'_>, method_span: Span, method_name: Symbol, - args: &[hir::Expr<'_>], + receiver: &hir::Expr<'_>, ) { - let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0]); + let self_ty = cx.typeck_results().expr_ty_adjusted(receiver); if_chain! { if let ty::Ref(..) = self_ty.kind(); if method_name == sym::into_iter; diff --git a/clippy_lints/src/methods/iter_with_drain.rs b/clippy_lints/src/methods/iter_with_drain.rs index 152072e09c77..a669cbbbcc60 100644 --- a/clippy_lints/src/methods/iter_with_drain.rs +++ b/clippy_lints/src/methods/iter_with_drain.rs @@ -35,7 +35,7 @@ fn is_full_range(cx: &LateContext<'_>, container: &Expr<'_>, range: Range<'_>) - && range.end.map_or(true, |e| { if range.limits == RangeLimits::HalfOpen && let ExprKind::Path(QPath::Resolved(None, container_path)) = container.kind - && let ExprKind::MethodCall(name, [self_arg], _) = e.kind + && let ExprKind::MethodCall(name, self_arg, [], _) = e.kind && name.ident.name == sym::len && let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind { diff --git a/clippy_lints/src/methods/map_clone.rs b/clippy_lints/src/methods/map_clone.rs index ffedda95ff8e..e04bb1c50792 100644 --- a/clippy_lints/src/methods/map_clone.rs +++ b/clippy_lints/src/methods/map_clone.rs @@ -48,7 +48,7 @@ pub(super) fn check<'tcx>( } } }, - hir::ExprKind::MethodCall(method, [obj], _) => if_chain! { + hir::ExprKind::MethodCall(method, obj, [], _) => if_chain! { if ident_eq(name, obj) && method.ident.name == sym::clone; if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id); if let Some(trait_id) = cx.tcx.trait_of_item(fn_id); diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a0d190a58aff..16fdd36c0260 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3161,11 +3161,13 @@ impl_lint_pass!(Methods => [ ]); /// Extracts a method call name, args, and `Span` of the method name. -fn method_call<'tcx>(recv: &'tcx hir::Expr<'tcx>) -> Option<(&'tcx str, &'tcx [hir::Expr<'tcx>], Span)> { - if let ExprKind::MethodCall(path, args, _) = recv.kind { - if !args.iter().any(|e| e.span.from_expansion()) { +fn method_call<'tcx>( + recv: &'tcx hir::Expr<'tcx>, +) -> Option<(&'tcx str, &'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], Span)> { + if let ExprKind::MethodCall(path, receiver, args, _) = recv.kind { + if !args.iter().any(|e| e.span.from_expansion()) && !receiver.span.from_expansion() { let name = path.ident.name.as_str(); - return Some((name, args, path.ident.span)); + return Some((name, receiver, args, path.ident.span)); } } None @@ -3183,17 +3185,17 @@ impl<'tcx> LateLintPass<'tcx> for Methods { hir::ExprKind::Call(func, args) => { from_iter_instead_of_collect::check(cx, expr, args, func); }, - hir::ExprKind::MethodCall(method_call, args, _) => { + hir::ExprKind::MethodCall(method_call, receiver, args, _) => { let method_span = method_call.ident.span; - or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), args); - expect_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), args); - clone_on_copy::check(cx, expr, method_call.ident.name, args); - clone_on_ref_ptr::check(cx, expr, method_call.ident.name, args); - inefficient_to_string::check(cx, expr, method_call.ident.name, args); - single_char_add_str::check(cx, expr, args); - into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, args); - single_char_pattern::check(cx, expr, method_call.ident.name, args); - unnecessary_to_owned::check(cx, expr, method_call.ident.name, args, self.msrv); + or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args); + expect_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args); + clone_on_copy::check(cx, expr, method_call.ident.name, receiver, args); + clone_on_ref_ptr::check(cx, expr, method_call.ident.name, receiver, args); + inefficient_to_string::check(cx, expr, method_call.ident.name, receiver, args); + single_char_add_str::check(cx, expr, receiver, args); + into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, receiver); + single_char_pattern::check(cx, expr, method_call.ident.name, receiver, args); + unnecessary_to_owned::check(cx, expr, method_call.ident.name, receiver, args, self.msrv); }, hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => { let mut info = BinaryExprInfo { @@ -3379,7 +3381,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { impl Methods { #[allow(clippy::too_many_lines)] fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let Some((name, [recv, args @ ..], span)) = method_call(expr) { + if let Some((name, recv, [args @ ..], span)) = method_call(expr) { match (name, args) { ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => { zst_offset::check(cx, expr, recv); @@ -3399,13 +3401,13 @@ impl Methods { ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv), ("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, self.msrv), ("collect", []) => match method_call(recv) { - Some((name @ ("cloned" | "copied"), [recv2], _)) => { + Some((name @ ("cloned" | "copied"), recv2, [], _)) => { iter_cloned_collect::check(cx, name, expr, recv2); }, - Some(("map", [m_recv, m_arg], _)) => { + Some(("map", m_recv, [m_arg], _)) => { map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv); }, - Some(("take", [take_self_arg, take_arg], _)) => { + Some(("take", take_self_arg, [take_arg], _)) => { if meets_msrv(self.msrv, msrvs::STR_REPEAT) { manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg); } @@ -3413,26 +3415,26 @@ impl Methods { _ => {}, }, ("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) { - Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false), - Some((name2 @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => { + Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false), + Some((name2 @ ("into_iter" | "iter" | "iter_mut"), recv2, [], _)) => { iter_count::check(cx, expr, recv2, name2); }, - Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg), - Some(("filter", [recv2, arg], _)) => bytecount::check(cx, expr, recv2, arg), - Some(("bytes", [recv2], _)) => bytes_count_to_len::check(cx, expr, recv, recv2), + Some(("map", _, [arg], _)) => suspicious_map::check(cx, expr, recv, arg), + Some(("filter", recv2, [arg], _)) => bytecount::check(cx, expr, recv2, arg), + Some(("bytes", recv2, [], _)) => bytes_count_to_len::check(cx, expr, recv, recv2), _ => {}, }, ("drain", [arg]) => { iter_with_drain::check(cx, expr, recv, span, arg); }, ("ends_with", [arg]) => { - if let ExprKind::MethodCall(_, _, span) = expr.kind { + if let ExprKind::MethodCall(.., span) = expr.kind { case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg); } }, ("expect", [_]) => match method_call(recv) { - Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv), - Some(("err", [recv], err_span)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span), + Some(("ok", recv, [], _)) => ok_expect::check(cx, expr, recv), + Some(("err", recv, [], err_span)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span), _ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests), }, ("expect_err", [_]) => expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests), @@ -3452,13 +3454,13 @@ impl Methods { flat_map_option::check(cx, expr, arg, span); }, ("flatten", []) => match method_call(recv) { - Some(("map", [recv, map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span), - Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true), + Some(("map", recv, [map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span), + Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true), _ => {}, }, ("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span), ("for_each", [_]) => { - if let Some(("inspect", [_, _], span2)) = method_call(recv) { + if let Some(("inspect", _, [_], span2)) = method_call(recv) { inspect_for_each::check(cx, expr, span2); } }, @@ -3478,12 +3480,12 @@ impl Methods { iter_on_single_or_empty_collections::check(cx, expr, name, recv); }, ("join", [join_arg]) => { - if let Some(("collect", _, span)) = method_call(recv) { + if let Some(("collect", _, _, span)) = method_call(recv) { unnecessary_join::check(cx, expr, recv, join_arg, span); } }, ("last", []) | ("skip", [_]) => { - if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) { + if let Some((name2, recv2, [args2 @ ..], _span2)) = method_call(recv) { if let ("cloned", []) = (name2, args2) { iter_overeager_cloned::check(cx, expr, recv, recv2, false, false); } @@ -3498,7 +3500,7 @@ impl Methods { } else { map_err_ignore::check(cx, expr, m_arg); } - if let Some((name, [recv2, args @ ..], span2)) = method_call(recv) { + if let Some((name, recv2, [args @ ..], span2)) = method_call(recv) { match (name, args) { ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv), ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv), @@ -3518,7 +3520,7 @@ impl Methods { manual_ok_or::check(cx, expr, recv, def, map); }, ("next", []) => { - if let Some((name2, [recv2, args2 @ ..], _)) = method_call(recv) { + if let Some((name2, recv2, [args2 @ ..], _)) = method_call(recv) { match (name2, args2) { ("cloned", []) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false), ("filter", [arg]) => filter_next::check(cx, expr, recv2, arg), @@ -3531,10 +3533,10 @@ impl Methods { } }, ("nth", [n_arg]) => match method_call(recv) { - Some(("bytes", [recv2], _)) => bytes_nth::check(cx, expr, recv2, n_arg), - Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false), - Some(("iter", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false), - Some(("iter_mut", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true), + Some(("bytes", recv2, [], _)) => bytes_nth::check(cx, expr, recv2, n_arg), + Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false), + Some(("iter", recv2, [], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false), + Some(("iter_mut", recv2, [], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true), _ => iter_nth_zero::check(cx, expr, recv, n_arg), }, ("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"), @@ -3591,7 +3593,7 @@ impl Methods { }, ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg), ("take", [_arg]) => { - if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) { + if let Some((name2, recv2, [args2 @ ..], _span2)) = method_call(recv) { if let ("cloned", []) = (name2, args2) { iter_overeager_cloned::check(cx, expr, recv, recv2, false, false); } @@ -3614,13 +3616,13 @@ impl Methods { }, ("unwrap", []) => { match method_call(recv) { - Some(("get", [recv, get_arg], _)) => { + Some(("get", recv, [get_arg], _)) => { get_unwrap::check(cx, expr, recv, get_arg, false); }, - Some(("get_mut", [recv, get_arg], _)) => { + Some(("get_mut", recv, [get_arg], _)) => { get_unwrap::check(cx, expr, recv, get_arg, true); }, - Some(("or", [recv, or_arg], or_span)) => { + Some(("or", recv, [or_arg], or_span)) => { or_then_unwrap::check(cx, expr, recv, or_arg, or_span); }, _ => {}, @@ -3629,19 +3631,19 @@ impl Methods { }, ("unwrap_err", []) => unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests), ("unwrap_or", [u_arg]) => match method_call(recv) { - Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => { + Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), lhs, [rhs], _)) => { manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]); }, - Some(("map", [m_recv, m_arg], span)) => { + Some(("map", m_recv, [m_arg], span)) => { option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span); }, - Some(("then_some", [t_recv, t_arg], _)) => { + Some(("then_some", t_recv, [t_arg], _)) => { obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg); }, _ => {}, }, ("unwrap_or_else", [u_arg]) => match method_call(recv) { - Some(("map", [recv, map_arg], _)) + Some(("map", recv, [map_arg], _)) if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, self.msrv) => {}, _ => { unwrap_or_else_default::check(cx, expr, recv, u_arg); @@ -3649,7 +3651,7 @@ impl Methods { }, }, ("zip", [arg]) => { - if let ExprKind::MethodCall(name, [iter_recv], _) = recv.kind + if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind && name.ident.name == sym::iter { range_zip_with_len::check(cx, expr, iter_recv, arg); @@ -3662,7 +3664,7 @@ impl Methods { } fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, is_some: bool) { - if let Some((name @ ("find" | "position" | "rposition"), [f_recv, arg], span)) = method_call(recv) { + if let Some((name @ ("find" | "position" | "rposition"), f_recv, [arg], span)) = method_call(recv) { search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span); } } diff --git a/clippy_lints/src/methods/open_options.rs b/clippy_lints/src/methods/open_options.rs index c3112823e346..903fa306f935 100644 --- a/clippy_lints/src/methods/open_options.rs +++ b/clippy_lints/src/methods/open_options.rs @@ -36,12 +36,12 @@ enum OpenOption { } fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec<(OpenOption, Argument)>) { - if let ExprKind::MethodCall(path, arguments, _) = argument.kind { - let obj_ty = cx.typeck_results().expr_ty(&arguments[0]).peel_refs(); + if let ExprKind::MethodCall(path, receiver, arguments, _) = argument.kind { + let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs(); // Only proceed if this is a call on some object of type std::fs::OpenOptions - if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 2 { - let argument_option = match arguments[1].kind { + if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 1 { + let argument_option = match arguments[0].kind { ExprKind::Lit(ref span) => { if let Spanned { node: LitKind::Bool(lit), @@ -77,7 +77,7 @@ fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec _ => (), } - get_open_options(cx, &arguments[0], options); + get_open_options(cx, receiver, options); } } } diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs index 20cad0f181e9..81c67b4ca6a5 100644 --- a/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/clippy_lints/src/methods/option_as_ref_deref.rs @@ -56,13 +56,12 @@ pub(super) fn check<'tcx>( let closure_expr = peel_blocks(&closure_body.value); match &closure_expr.kind { - hir::ExprKind::MethodCall(_, args, _) => { + hir::ExprKind::MethodCall(_, receiver, [], _) => { if_chain! { - if args.len() == 1; - if path_to_local_id(&args[0], closure_body.params[0].pat.hir_id); + if path_to_local_id(receiver, closure_body.params[0].pat.hir_id); let adj = cx .typeck_results() - .expr_adjustments(&args[0]) + .expr_adjustments(receiver) .iter() .map(|x| &x.kind) .collect::>(); diff --git a/clippy_lints/src/methods/or_fun_call.rs b/clippy_lints/src/methods/or_fun_call.rs index 6af134019a47..76876d866293 100644 --- a/clippy_lints/src/methods/or_fun_call.rs +++ b/clippy_lints/src/methods/or_fun_call.rs @@ -20,6 +20,7 @@ pub(super) fn check<'tcx>( expr: &hir::Expr<'_>, method_span: Span, name: &str, + receiver: &'tcx hir::Expr<'_>, args: &'tcx [hir::Expr<'_>], ) { /// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`. @@ -144,7 +145,7 @@ pub(super) fn check<'tcx>( } } - if let [self_arg, arg] = args { + if let [arg] = args { let inner_arg = if let hir::ExprKind::Block( hir::Block { stmts: [], @@ -163,11 +164,11 @@ pub(super) fn check<'tcx>( let or_has_args = !or_args.is_empty(); if !check_unwrap_or_default(cx, name, fun, arg, or_has_args, expr.span, method_span) { let fun_span = if or_has_args { None } else { Some(fun.span) }; - check_general_case(cx, name, method_span, self_arg, arg, expr.span, fun_span); + check_general_case(cx, name, method_span, receiver, arg, expr.span, fun_span); } }, hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => { - check_general_case(cx, name, method_span, self_arg, arg, expr.span, None); + check_general_case(cx, name, method_span, receiver, arg, expr.span, None); }, _ => (), } diff --git a/clippy_lints/src/methods/range_zip_with_len.rs b/clippy_lints/src/methods/range_zip_with_len.rs index 00a2a0d14d11..867a3b402377 100644 --- a/clippy_lints/src/methods/range_zip_with_len.rs +++ b/clippy_lints/src/methods/range_zip_with_len.rs @@ -16,7 +16,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &' if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg); if is_integer_const(cx, start, 0); // `.len()` call - if let ExprKind::MethodCall(len_path, [len_recv], _) = end.kind; + if let ExprKind::MethodCall(len_path, len_recv, [], _) = end.kind; if len_path.ident.name == sym::len; // `.iter()` and `.len()` called on same `Path` if let ExprKind::Path(QPath::Resolved(_, iter_path)) = recv.kind; diff --git a/clippy_lints/src/methods/single_char_add_str.rs b/clippy_lints/src/methods/single_char_add_str.rs index 9a5fabcf7cd5..81450fd8c6c3 100644 --- a/clippy_lints/src/methods/single_char_add_str.rs +++ b/clippy_lints/src/methods/single_char_add_str.rs @@ -3,12 +3,12 @@ use clippy_utils::{match_def_path, paths}; use rustc_hir as hir; use rustc_lint::LateContext; -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) { if match_def_path(cx, fn_def_id, &paths::PUSH_STR) { - single_char_push_string::check(cx, expr, args); + single_char_push_string::check(cx, expr, receiver, args); } else if match_def_path(cx, fn_def_id, &paths::INSERT_STR) { - single_char_insert_string::check(cx, expr, args); + single_char_insert_string::check(cx, expr, receiver, args); } } } diff --git a/clippy_lints/src/methods/single_char_insert_string.rs b/clippy_lints/src/methods/single_char_insert_string.rs index 6cdc954c03be..18b6b5be175d 100644 --- a/clippy_lints/src/methods/single_char_insert_string.rs +++ b/clippy_lints/src/methods/single_char_insert_string.rs @@ -8,12 +8,12 @@ use rustc_lint::LateContext; use super::SINGLE_CHAR_ADD_STR; /// lint for length-1 `str`s as argument for `insert_str` -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let mut applicability = Applicability::MachineApplicable; - if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[2], &mut applicability) { + if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) { let base_string_snippet = - snippet_with_applicability(cx, args[0].span.source_callsite(), "_", &mut applicability); - let pos_arg = snippet_with_applicability(cx, args[1].span, "..", &mut applicability); + snippet_with_applicability(cx, receiver.span.source_callsite(), "_", &mut applicability); + let pos_arg = snippet_with_applicability(cx, args[0].span, "..", &mut applicability); let sugg = format!("{}.insert({}, {})", base_string_snippet, pos_arg, extension_string); span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/single_char_pattern.rs b/clippy_lints/src/methods/single_char_pattern.rs index bf9006c69062..4221c52d5cd7 100644 --- a/clippy_lints/src/methods/single_char_pattern.rs +++ b/clippy_lints/src/methods/single_char_pattern.rs @@ -10,37 +10,43 @@ use rustc_span::symbol::Symbol; use super::SINGLE_CHAR_PATTERN; const PATTERN_METHODS: [(&str, usize); 24] = [ - ("contains", 1), - ("starts_with", 1), - ("ends_with", 1), - ("find", 1), - ("rfind", 1), - ("split", 1), - ("split_inclusive", 1), - ("rsplit", 1), - ("split_terminator", 1), - ("rsplit_terminator", 1), - ("splitn", 2), - ("rsplitn", 2), - ("split_once", 1), - ("rsplit_once", 1), - ("matches", 1), - ("rmatches", 1), - ("match_indices", 1), - ("rmatch_indices", 1), - ("strip_prefix", 1), - ("strip_suffix", 1), - ("trim_start_matches", 1), - ("trim_end_matches", 1), - ("replace", 1), - ("replacen", 1), + ("contains", 0), + ("starts_with", 0), + ("ends_with", 0), + ("find", 0), + ("rfind", 0), + ("split", 0), + ("split_inclusive", 0), + ("rsplit", 0), + ("split_terminator", 0), + ("rsplit_terminator", 0), + ("splitn", 1), + ("rsplitn", 1), + ("split_once", 0), + ("rsplit_once", 0), + ("matches", 0), + ("rmatches", 0), + ("match_indices", 0), + ("rmatch_indices", 0), + ("strip_prefix", 0), + ("strip_suffix", 0), + ("trim_start_matches", 0), + ("trim_end_matches", 0), + ("replace", 0), + ("replacen", 0), ]; /// lint for length-1 `str`s for methods in `PATTERN_METHODS` -pub(super) fn check(cx: &LateContext<'_>, _expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) { +pub(super) fn check( + cx: &LateContext<'_>, + _expr: &hir::Expr<'_>, + method_name: Symbol, + receiver: &hir::Expr<'_>, + args: &[hir::Expr<'_>], +) { for &(method, pos) in &PATTERN_METHODS { if_chain! { - if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(&args[0]).kind(); + if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind(); if *ty.kind() == ty::Str; if method_name.as_str() == method && args.len() > pos; let arg = &args[pos]; diff --git a/clippy_lints/src/methods/single_char_push_string.rs b/clippy_lints/src/methods/single_char_push_string.rs index 0237d39cbdb4..9ea6751956ab 100644 --- a/clippy_lints/src/methods/single_char_push_string.rs +++ b/clippy_lints/src/methods/single_char_push_string.rs @@ -8,11 +8,11 @@ use rustc_lint::LateContext; use super::SINGLE_CHAR_ADD_STR; /// lint for length-1 `str`s as argument for `push_str` -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let mut applicability = Applicability::MachineApplicable; - if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) { + if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[0], &mut applicability) { let base_string_snippet = - snippet_with_applicability(cx, args[0].span.source_callsite(), "..", &mut applicability); + snippet_with_applicability(cx, receiver.span.source_callsite(), "..", &mut applicability); let sugg = format!("{}.push({})", base_string_snippet, extension_string); span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs index 4ac738272d08..8f2f47525147 100644 --- a/clippy_lints/src/methods/str_splitn.rs +++ b/clippy_lints/src/methods/str_splitn.rs @@ -292,7 +292,7 @@ fn parse_iter_usage<'tcx>( ) -> Option { let (kind, span) = match iter.next() { Some((_, Node::Expr(e))) if e.span.ctxt() == ctxt => { - let (name, args) = if let ExprKind::MethodCall(name, [_, args @ ..], _) = e.kind { + let (name, args) = if let ExprKind::MethodCall(name, _, [args @ ..], _) = e.kind { (name, args) } else { return None; @@ -327,7 +327,7 @@ fn parse_iter_usage<'tcx>( } else { if_chain! { if let Some((_, Node::Expr(next_expr))) = iter.next(); - if let ExprKind::MethodCall(next_name, [_], _) = next_expr.kind; + if let ExprKind::MethodCall(next_name, _, [], _) = next_expr.kind; if next_name.ident.name == sym::next; if next_expr.span.ctxt() == ctxt; if let Some(next_id) = cx.typeck_results().type_dependent_def_id(next_expr.hir_id); @@ -367,7 +367,7 @@ fn parse_iter_usage<'tcx>( } }, _ if e.span.ctxt() != ctxt => (None, span), - ExprKind::MethodCall(name, [_], _) + ExprKind::MethodCall(name, _, [], _) if name.ident.name == sym::unwrap && cx .typeck_results() diff --git a/clippy_lints/src/methods/string_extend_chars.rs b/clippy_lints/src/methods/string_extend_chars.rs index d06658f2a5e6..143dcee35052 100644 --- a/clippy_lints/src/methods/string_extend_chars.rs +++ b/clippy_lints/src/methods/string_extend_chars.rs @@ -16,7 +16,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr return; } if let Some(arglists) = method_chain_args(arg, &["chars"]) { - let target = &arglists[0][0]; + let target = &arglists[0].0; let self_ty = cx.typeck_results().expr_ty(target).peel_refs(); let ref_str = if *self_ty.kind() == ty::Str { "" diff --git a/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 19037093e20a..95138c0e25b0 100644 --- a/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -43,7 +43,7 @@ pub fn check_for_loop_iter( if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); then { let snippet = if_chain! { - if let ExprKind::MethodCall(maybe_iter_method_name, [collection], _) = receiver.kind; + if let ExprKind::MethodCall(maybe_iter_method_name, collection, [], _) = receiver.kind; if maybe_iter_method_name.ident.name == sym::iter; if let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator); diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 1876c7fb9d05..a187a8d6016f 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -54,7 +54,7 @@ pub(super) fn check<'tcx>( // This is a duplicate of what's happening in clippy_lints::methods::method_call, // which isn't ideal, We want to get the method call span, // but prefer to avoid changing the signature of the function itself. - if let hir::ExprKind::MethodCall(_, _, span) = expr.kind { + if let hir::ExprKind::MethodCall(.., span) = expr.kind { span_lint_and_then(cx, UNNECESSARY_LAZY_EVALUATIONS, expr.span, msg, |diag| { diag.span_suggestion( span, diff --git a/clippy_lints/src/methods/unnecessary_sort_by.rs b/clippy_lints/src/methods/unnecessary_sort_by.rs index 1966990bd774..6f25acca1de6 100644 --- a/clippy_lints/src/methods/unnecessary_sort_by.rs +++ b/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -50,9 +50,13 @@ fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident // The two exprs are method calls. // Check to see that the function is the same and the arguments are mirrored // This is enough because the receiver of the method is listed in the arguments - (ExprKind::MethodCall(left_segment, left_args, _), ExprKind::MethodCall(right_segment, right_args, _)) => { + ( + ExprKind::MethodCall(left_segment, left_receiver, left_args, _), + ExprKind::MethodCall(right_segment, right_receiver, right_args, _), + ) => { left_segment.ident == right_segment.ident && iter::zip(*left_args, *right_args).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident)) + && mirrored_exprs(left_receiver, a_ident, right_receiver, b_ident) }, // Two tuples with mirrored contents (ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) => { @@ -125,7 +129,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Exp Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..}, Param { pat: Pat { kind: PatKind::Binding(_, _, right_ident, _), .. }, .. } ] = &closure_body.params; - if let ExprKind::MethodCall(method_path, [left_expr, right_expr], _) = closure_body.value.kind; + if let ExprKind::MethodCall(method_path, left_expr, [right_expr], _) = closure_body.value.kind; if method_path.ident.name == sym::cmp; if is_trait_method(cx, &closure_body.value, sym::Ord); then { diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs index 44bf84352943..9dceb9af2f22 100644 --- a/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -24,12 +24,13 @@ pub fn check<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol, - args: &'tcx [Expr<'tcx>], + receiver: &'tcx Expr<'_>, + args: &'tcx [Expr<'_>], msrv: Option, ) { if_chain! { if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if let [receiver] = args; + if args.is_empty(); then { if is_cloned_or_copied(cx, method_name, method_def_id) { unnecessary_iter_cloned::check(cx, expr, method_name, receiver); @@ -245,9 +246,14 @@ fn check_other_call_arg<'tcx>( ) -> bool { if_chain! { if let Some((maybe_call, maybe_arg)) = skip_addr_of_ancestors(cx, expr); - if let Some((callee_def_id, call_substs, call_args)) = get_callee_substs_and_args(cx, maybe_call); + if let Some((callee_def_id, call_substs, call_receiver, call_args)) = get_callee_substs_and_args(cx, maybe_call); let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder(); - if let Some(i) = call_args.iter().position(|arg| arg.hir_id == maybe_arg.hir_id); + let index = if let Some(call_receiver) = call_receiver { + std::iter::once(call_receiver).chain(call_args.iter()).position(|arg| arg.hir_id == maybe_arg.hir_id) + } else { + call_args.iter().position(|arg| arg.hir_id == maybe_arg.hir_id) + }; + if let Some(i) = index; if let Some(input) = fn_sig.inputs().get(i); let (input, n_refs) = peel_mid_ty_refs(*input); if let (trait_predicates, projection_predicates) = get_input_traits_and_projections(cx, callee_def_id, input); @@ -342,22 +348,22 @@ fn skip_addr_of_ancestors<'tcx>( fn get_callee_substs_and_args<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, -) -> Option<(DefId, SubstsRef<'tcx>, &'tcx [Expr<'tcx>])> { +) -> Option<(DefId, SubstsRef<'tcx>, Option<&'tcx Expr<'tcx>>, &'tcx [Expr<'tcx>])> { if_chain! { if let ExprKind::Call(callee, args) = expr.kind; let callee_ty = cx.typeck_results().expr_ty(callee); if let ty::FnDef(callee_def_id, _) = callee_ty.kind(); then { let substs = cx.typeck_results().node_substs(callee.hir_id); - return Some((*callee_def_id, substs, args)); + return Some((*callee_def_id, substs, None, args)); } } if_chain! { - if let ExprKind::MethodCall(_, args, _) = expr.kind; + if let ExprKind::MethodCall(_, receiver, args, _) = expr.kind; if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); then { let substs = cx.typeck_results().node_substs(expr.hir_id); - return Some((method_def_id, substs, args)); + return Some((method_def_id, substs, Some(receiver), args)); } } None diff --git a/clippy_lints/src/methods/utils.rs b/clippy_lints/src/methods/utils.rs index 3015531e8439..ae6b165fdc36 100644 --- a/clippy_lints/src/methods/utils.rs +++ b/clippy_lints/src/methods/utils.rs @@ -28,7 +28,7 @@ pub(super) fn derefs_to_slice<'tcx>( } } - if let hir::ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind { + if let hir::ExprKind::MethodCall(path, self_arg, ..) = &expr.kind { if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(self_arg)) { Some(self_arg) } else { @@ -139,9 +139,9 @@ impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> { self.addr_of_exprs.push(parent); return; }, - ExprKind::MethodCall(_, args, _) => { + ExprKind::MethodCall(.., args, _) => { if_chain! { - if args.iter().skip(1).all(|arg| !self.is_binding(arg)); + if args.iter().all(|arg| !self.is_binding(arg)); if let Some(method_def_id) = self.cx.typeck_results().type_dependent_def_id(parent.hir_id); let method_ty = self.cx.tcx.type_of(method_def_id); let self_ty = method_ty.fn_sig(self.cx.tcx).input(0).skip_binder(); diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index a081cde85725..c618f6b5d926 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -75,23 +75,22 @@ fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Cons .qpath_res(qpath, path.hir_id) .opt_def_id() .and_then(|def_id| match cx.tcx.get_diagnostic_name(def_id) { - Some(sym::cmp_min) => fetch_const(cx, args, MinMax::Min), - Some(sym::cmp_max) => fetch_const(cx, args, MinMax::Max), + Some(sym::cmp_min) => fetch_const(cx, None, args, MinMax::Min), + Some(sym::cmp_max) => fetch_const(cx, None, args, MinMax::Max), _ => None, }) } else { None } }, - ExprKind::MethodCall(path, args, _) => { + ExprKind::MethodCall(path, receiver, args @ [_], _) => { if_chain! { - if let [obj, _] = args; - if cx.typeck_results().expr_ty(obj).is_floating_point() || match_trait_method(cx, expr, &paths::ORD); + if cx.typeck_results().expr_ty(receiver).is_floating_point() || match_trait_method(cx, expr, &paths::ORD); then { if path.ident.name == sym!(max) { - fetch_const(cx, args, MinMax::Max) + fetch_const(cx, Some(receiver), args, MinMax::Max) } else if path.ident.name == sym!(min) { - fetch_const(cx, args, MinMax::Min) + fetch_const(cx, Some(receiver), args, MinMax::Min) } else { None } @@ -104,16 +103,26 @@ fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Cons } } -fn fetch_const<'a>(cx: &LateContext<'_>, args: &'a [Expr<'a>], m: MinMax) -> Option<(MinMax, Constant, &'a Expr<'a>)> { - if args.len() != 2 { +fn fetch_const<'a>( + cx: &LateContext<'_>, + receiver: Option<&'a Expr<'a>>, + args: &'a [Expr<'a>], + m: MinMax, +) -> Option<(MinMax, Constant, &'a Expr<'a>)> { + if (receiver.is_some() && args.len() != 1) || (receiver.is_none() && args.len() != 2) { return None; } - constant_simple(cx, cx.typeck_results(), &args[0]).map_or_else( - || constant_simple(cx, cx.typeck_results(), &args[1]).map(|c| (m, c, &args[0])), + let (arg0, arg1) = if let Some(receiver) = receiver { + (receiver, &args[0]) + } else { + (&args[0], &args[1]) + }; + constant_simple(cx, cx.typeck_results(), arg0).map_or_else( + || constant_simple(cx, cx.typeck_results(), arg1).map(|c| (m, c, arg0)), |c| { - if constant_simple(cx, cx.typeck_results(), &args[1]).is_none() { + if constant_simple(cx, cx.typeck_results(), arg1).is_none() { // otherwise ignore - Some((m, c, &args[1])) + Some((m, c, arg1)) } else { None } diff --git a/clippy_lints/src/mut_reference.rs b/clippy_lints/src/mut_reference.rs index f434a655f8af..82dc03ef5c5b 100644 --- a/clippy_lints/src/mut_reference.rs +++ b/clippy_lints/src/mut_reference.rs @@ -43,18 +43,24 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed { if let ExprKind::Path(ref path) = fn_expr.kind { check_arguments( cx, - arguments, + arguments.iter().collect(), cx.typeck_results().expr_ty(fn_expr), &rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)), "function", ); } }, - ExprKind::MethodCall(path, arguments, _) => { + ExprKind::MethodCall(path, receiver, arguments, _) => { let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap(); let substs = cx.typeck_results().node_substs(e.hir_id); let method_type = cx.tcx.bound_type_of(def_id).subst(cx.tcx, substs); - check_arguments(cx, arguments, method_type, path.ident.as_str(), "method"); + check_arguments( + cx, + std::iter::once(receiver).chain(arguments.iter()).collect(), + method_type, + path.ident.as_str(), + "method", + ); }, _ => (), } @@ -63,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed { fn check_arguments<'tcx>( cx: &LateContext<'tcx>, - arguments: &[Expr<'_>], + arguments: Vec<&Expr<'_>>, type_definition: Ty<'tcx>, name: &str, fn_kind: &str, diff --git a/clippy_lints/src/needless_for_each.rs b/clippy_lints/src/needless_for_each.rs index 10e188ecb79a..f8cc3fbb3cdf 100644 --- a/clippy_lints/src/needless_for_each.rs +++ b/clippy_lints/src/needless_for_each.rs @@ -56,12 +56,12 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { if_chain! { // Check the method name is `for_each`. - if let ExprKind::MethodCall(method_name, [for_each_recv, for_each_arg], _) = expr.kind; + if let ExprKind::MethodCall(method_name, for_each_recv, [for_each_arg], _) = expr.kind; if method_name.ident.name == Symbol::intern("for_each"); // Check `for_each` is an associated function of `Iterator`. if is_trait_method(cx, expr, sym::Iterator); // Checks the receiver of `for_each` is also a method call. - if let ExprKind::MethodCall(_, [iter_recv], _) = for_each_recv.kind; + if let ExprKind::MethodCall(_, iter_recv, [], _) = for_each_recv.kind; // Skip the lint if the call chain is too long. e.g. `v.field.iter().for_each()` or // `v.foo().iter().for_each()` must be skipped. if matches!( diff --git a/clippy_lints/src/non_octal_unix_permissions.rs b/clippy_lints/src/non_octal_unix_permissions.rs index ed022b9d5291..25fb4f0f4cff 100644 --- a/clippy_lints/src/non_octal_unix_permissions.rs +++ b/clippy_lints/src/non_octal_unix_permissions.rs @@ -43,7 +43,7 @@ declare_lint_pass!(NonOctalUnixPermissions => [NON_OCTAL_UNIX_PERMISSIONS]); impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { match &expr.kind { - ExprKind::MethodCall(path, [func, param], _) => { + ExprKind::MethodCall(path, func, [param], _) => { let obj_ty = cx.typeck_results().expr_ty(func).peel_refs(); if_chain! { diff --git a/clippy_lints/src/only_used_in_recursion.rs b/clippy_lints/src/only_used_in_recursion.rs index 774a3540d1e0..17d5fa2152bb 100644 --- a/clippy_lints/src/only_used_in_recursion.rs +++ b/clippy_lints/src/only_used_in_recursion.rs @@ -304,13 +304,13 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { } return; }, - ExprKind::MethodCall(_, args, _) + ExprKind::MethodCall(_, receiver, args, _) if typeck.type_dependent_def_id(parent.hir_id).map_or(false, |id| { id == param.fn_id && has_matching_substs(param.fn_kind, typeck.node_substs(parent.hir_id)) }) => { - if let Some(idx) = args.iter().position(|arg| arg.hir_id == child_id) { + if let Some(idx) = std::iter::once(receiver).chain(args.iter()).position(|arg| arg.hir_id == child_id) { param.uses.push(Usage::new(span, idx)); } return; diff --git a/clippy_lints/src/operators/cmp_owned.rs b/clippy_lints/src/operators/cmp_owned.rs index e1f9b5906f66..638a514ff9b3 100644 --- a/clippy_lints/src/operators/cmp_owned.rs +++ b/clippy_lints/src/operators/cmp_owned.rs @@ -38,7 +38,7 @@ fn symmetric_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'t fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) { let typeck = cx.typeck_results(); let (arg, arg_span) = match expr.kind { - ExprKind::MethodCall(.., [arg], _) + ExprKind::MethodCall(_, arg, [], _) if typeck .type_dependent_def_id(expr.hir_id) .and_then(|id| cx.tcx.trait_of_item(id)) diff --git a/clippy_lints/src/operators/duration_subsec.rs b/clippy_lints/src/operators/duration_subsec.rs index 0d067d1e1968..827a2b267093 100644 --- a/clippy_lints/src/operators/duration_subsec.rs +++ b/clippy_lints/src/operators/duration_subsec.rs @@ -17,7 +17,7 @@ pub(crate) fn check<'tcx>( right: &'tcx Expr<'_>, ) { if op == BinOpKind::Div - && let ExprKind::MethodCall(method_path, [self_arg], _) = left.kind + && let ExprKind::MethodCall(method_path, self_arg, [], _) = left.kind && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_arg).peel_refs(), sym::Duration) && let Some((Constant::Int(divisor), _)) = constant(cx, cx.typeck_results(), right) { diff --git a/clippy_lints/src/operators/float_cmp.rs b/clippy_lints/src/operators/float_cmp.rs index 0ef793443ff4..97ddcdb24799 100644 --- a/clippy_lints/src/operators/float_cmp.rs +++ b/clippy_lints/src/operators/float_cmp.rs @@ -113,7 +113,7 @@ fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { } if_chain! { - if let ExprKind::MethodCall(method_name, [ref self_arg, ..], _) = expr.kind; + if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind; if sym!(signum) == method_name.ident.name; // Check that the receiver of the signum() is a float (expressions[0] is the receiver of // the method call) diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 3c5ea2d94144..63c9faf0396f 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -591,8 +591,11 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: set_skip_flag(); } }, - ExprKind::MethodCall(name, expr_args @ [self_arg, ..], _) => { - let i = expr_args.iter().position(|arg| arg.hir_id == child_id).unwrap_or(0); + ExprKind::MethodCall(name, self_arg, expr_args, _) => { + let i = std::iter::once(self_arg) + .chain(expr_args.iter()) + .position(|arg| arg.hir_id == child_id) + .unwrap_or(0); if i == 0 { // Check if the method can be renamed. let name = name.ident.as_str(); diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs index b907f38afbb9..4dc65da3ea1f 100644 --- a/clippy_lints/src/ptr_offset_with_cast.rs +++ b/clippy_lints/src/ptr_offset_with_cast.rs @@ -93,7 +93,7 @@ fn expr_as_ptr_offset_call<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, ) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Method)> { - if let ExprKind::MethodCall(path_segment, [arg_0, arg_1, ..], _) = &expr.kind { + if let ExprKind::MethodCall(path_segment, arg_0, [arg_1, ..], _) = &expr.kind { if is_expr_ty_raw_ptr(cx, arg_0) { if path_segment.ident.name == sym::offset { return Some((arg_0, arg_1, Method::Offset)); diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index b432ccb1ee32..6fddbd419bcd 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -86,7 +86,7 @@ fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Ex if_chain! { if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr); if !is_else_clause(cx.tcx, expr); - if let ExprKind::MethodCall(segment, [caller, ..], _) = &cond.kind; + if let ExprKind::MethodCall(segment, caller, ..) = &cond.kind; let caller_ty = cx.typeck_results().expr_ty(caller); let if_block = IfBlockType::IfIs(caller, caller_ty, segment.ident.name, then, r#else); if is_early_return(sym::Option, cx, &if_block) || is_early_return(sym::Result, cx, &if_block); diff --git a/clippy_lints/src/read_zero_byte_vec.rs b/clippy_lints/src/read_zero_byte_vec.rs index 9538a8104739..94dec191103c 100644 --- a/clippy_lints/src/read_zero_byte_vec.rs +++ b/clippy_lints/src/read_zero_byte_vec.rs @@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { // finds use of `_.read(&mut v)` let mut read_found = false; let mut visitor = expr_visitor_no_bodies(|expr| { - if let ExprKind::MethodCall(path, [_self, arg], _) = expr.kind + if let ExprKind::MethodCall(path, _self, [arg], _) = expr.kind && let PathSegment { ident: read_or_read_exact, .. } = *path && matches!(read_or_read_exact.as_str(), "read" | "read_exact") && let ExprKind::AddrOf(_, hir::Mutability::Mut, inner) = arg.kind diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs index bfb9f0d01e1d..ac4e29e9dfdf 100644 --- a/clippy_lints/src/size_of_in_element_count.rs +++ b/clippy_lints/src/size_of_in_element_count.rs @@ -108,7 +108,7 @@ fn get_pointee_ty_and_count_expr<'tcx>( }; if_chain! { // Find calls to copy_{from,to}{,_nonoverlapping} and write_bytes methods - if let ExprKind::MethodCall(method_path, [ptr_self, .., count], _) = expr.kind; + if let ExprKind::MethodCall(method_path, ptr_self, [.., count], _) = expr.kind; let method_ident = method_path.ident.as_str(); if METHODS.iter().any(|m| *m == method_ident); diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs index b59a25e3a400..b35782184670 100644 --- a/clippy_lints/src/slow_vector_initialization.rs +++ b/clippy_lints/src/slow_vector_initialization.rs @@ -201,7 +201,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { fn search_slow_extend_filling(&mut self, expr: &'tcx Expr<'_>) { if_chain! { if self.initialization_found; - if let ExprKind::MethodCall(path, [self_arg, extend_arg], _) = expr.kind; + if let ExprKind::MethodCall(path, self_arg, [extend_arg], _) = expr.kind; if path_to_local_id(self_arg, self.vec_alloc.local_id); if path.ident.name == sym!(extend); if self.is_repeat_take(extend_arg); @@ -215,7 +215,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { /// Checks if the given expression is resizing a vector with 0 fn search_slow_resize_filling(&mut self, expr: &'tcx Expr<'_>) { if self.initialization_found - && let ExprKind::MethodCall(path, [self_arg, len_arg, fill_arg], _) = expr.kind + && let ExprKind::MethodCall(path, self_arg, [len_arg, fill_arg], _) = expr.kind && path_to_local_id(self_arg, self.vec_alloc.local_id) && path.ident.name == sym!(resize) // Check that is filled with 0 @@ -224,7 +224,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { // Check that len expression is equals to `with_capacity` expression if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) { self.slow_expression = Some(InitializationType::Resize(expr)); - } else if let ExprKind::MethodCall(path, _, _) = len_arg.kind && path.ident.as_str() == "capacity" { + } else if let ExprKind::MethodCall(path, ..) = len_arg.kind && path.ident.as_str() == "capacity" { self.slow_expression = Some(InitializationType::Resize(expr)); } } @@ -233,7 +233,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { /// Returns `true` if give expression is `repeat(0).take(...)` fn is_repeat_take(&self, expr: &Expr<'_>) -> bool { if_chain! { - if let ExprKind::MethodCall(take_path, [recv, len_arg, ..], _) = expr.kind; + if let ExprKind::MethodCall(take_path, recv, [len_arg, ..], _) = expr.kind; if take_path.ident.name == sym!(take); // Check that take is applied to `repeat(0)` if self.is_repeat_zero(recv); @@ -241,7 +241,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { // Check that len expression is equals to `with_capacity` expression if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) { return true; - } else if let ExprKind::MethodCall(path, _, _) = len_arg.kind && path.ident.as_str() == "capacity" { + } else if let ExprKind::MethodCall(path, ..) = len_arg.kind && path.ident.as_str() == "capacity" { return true; } } diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 22eb06b36463..662d399ca538 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -262,7 +262,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { let (method_names, expressions, _) = method_calls(left, 1); if method_names.len() == 1; if expressions.len() == 1; - if expressions[0].len() == 1; + if expressions[0].1.is_empty(); if method_names[0] == sym!(as_bytes); // Check for slicer @@ -270,7 +270,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { then { let mut applicability = Applicability::MachineApplicable; - let string_expression = &expressions[0][0]; + let string_expression = &expressions[0].0; let snippet_app = snippet_with_applicability( cx, @@ -291,12 +291,12 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { } if_chain! { - if let ExprKind::MethodCall(path, args, _) = &e.kind; + if let ExprKind::MethodCall(path, receiver, ..) = &e.kind; if path.ident.name == sym!(as_bytes); - if let ExprKind::Lit(lit) = &args[0].kind; + if let ExprKind::Lit(lit) = &receiver.kind; if let LitKind::Str(lit_content, _) = &lit.node; then { - let callsite = snippet(cx, args[0].span.source_callsite(), r#""foo""#); + let callsite = snippet(cx, receiver.span.source_callsite(), r#""foo""#); let mut applicability = Applicability::MachineApplicable; if callsite.starts_with("include_str!") { span_lint_and_sugg( @@ -305,7 +305,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { e.span, "calling `as_bytes()` on `include_str!(..)`", "consider using `include_bytes!(..)` instead", - snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability).replacen( + snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability).replacen( "include_str", "include_bytes", 1, @@ -314,7 +314,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { ); } else if lit_content.as_str().is_ascii() && lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT - && !args[0].span.from_expansion() + && !receiver.span.from_expansion() { span_lint_and_sugg( cx, @@ -324,7 +324,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { "consider using a byte string literal instead", format!( "b{}", - snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability) + snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability) ), applicability, ); @@ -333,9 +333,9 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { } if_chain! { - if let ExprKind::MethodCall(path, [recv], _) = &e.kind; + if let ExprKind::MethodCall(path, recv, [], _) = &e.kind; if path.ident.name == sym!(into_bytes); - if let ExprKind::MethodCall(path, [recv], _) = &recv.kind; + if let ExprKind::MethodCall(path, recv, [], _) = &recv.kind; if matches!(path.ident.name.as_str(), "to_owned" | "to_string"); if let ExprKind::Lit(lit) = &recv.kind; if let LitKind::Str(lit_content, _) = &lit.node; @@ -393,7 +393,7 @@ declare_lint_pass!(StrToString => [STR_TO_STRING]); impl<'tcx> LateLintPass<'tcx> for StrToString { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { if_chain! { - if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind; + if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind; if path.ident.name == sym::to_string; let ty = cx.typeck_results().expr_ty(self_arg); if let ty::Ref(_, ty, ..) = ty.kind(); @@ -443,7 +443,7 @@ declare_lint_pass!(StringToString => [STRING_TO_STRING]); impl<'tcx> LateLintPass<'tcx> for StringToString { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { if_chain! { - if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind; + if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind; if path.ident.name == sym::to_string; let ty = cx.typeck_results().expr_ty(self_arg); if is_type_diagnostic_item(cx, ty, sym::String); @@ -487,11 +487,11 @@ impl<'tcx> LateLintPass<'tcx> for TrimSplitWhitespace { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { let tyckres = cx.typeck_results(); if_chain! { - if let ExprKind::MethodCall(path, [split_recv], split_ws_span) = expr.kind; + if let ExprKind::MethodCall(path, split_recv, [], split_ws_span) = expr.kind; if path.ident.name == sym!(split_whitespace); if let Some(split_ws_def_id) = tyckres.type_dependent_def_id(expr.hir_id); if cx.tcx.is_diagnostic_item(sym::str_split_whitespace, split_ws_def_id); - if let ExprKind::MethodCall(path, [_trim_recv], trim_span) = split_recv.kind; + if let ExprKind::MethodCall(path, _trim_recv, [], trim_span) = split_recv.kind; if let trim_fn_name @ ("trim" | "trim_start" | "trim_end") = path.ident.name.as_str(); if let Some(trim_def_id) = tyckres.type_dependent_def_id(split_recv.hir_id); if is_one_of_trim_diagnostic_items(cx, trim_def_id); diff --git a/clippy_lints/src/strlen_on_c_strings.rs b/clippy_lints/src/strlen_on_c_strings.rs index 7bc9cf742e65..78403d9fdb7e 100644 --- a/clippy_lints/src/strlen_on_c_strings.rs +++ b/clippy_lints/src/strlen_on_c_strings.rs @@ -47,7 +47,7 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings { if let ExprKind::Path(path) = &func.kind; if let Some(did) = cx.qpath_res(path, func.hir_id).opt_def_id(); if match_libc_symbol(cx, did, "strlen"); - if let ExprKind::MethodCall(path, [self_arg], _) = recv.kind; + if let ExprKind::MethodCall(path, self_arg, [], _) = recv.kind; if !recv.span.from_expansion(); if path.ident.name == sym::as_ptr; then { diff --git a/clippy_lints/src/to_digit_is_some.rs b/clippy_lints/src/to_digit_is_some.rs index aa6c01b3a7cd..651201f34ed2 100644 --- a/clippy_lints/src/to_digit_is_some.rs +++ b/clippy_lints/src/to_digit_is_some.rs @@ -39,19 +39,17 @@ declare_lint_pass!(ToDigitIsSome => [TO_DIGIT_IS_SOME]); impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { if_chain! { - if let hir::ExprKind::MethodCall(is_some_path, is_some_args, _) = &expr.kind; + if let hir::ExprKind::MethodCall(is_some_path, to_digit_expr, [], _) = &expr.kind; if is_some_path.ident.name.as_str() == "is_some"; - if let [to_digit_expr] = &**is_some_args; then { let match_result = match &to_digit_expr.kind { - hir::ExprKind::MethodCall(to_digits_path, to_digit_args, _) => { + hir::ExprKind::MethodCall(to_digits_path, char_arg, [radix_arg], _) => { if_chain! { - if let [char_arg, radix_arg] = &**to_digit_args; if to_digits_path.ident.name.as_str() == "to_digit"; let char_arg_ty = cx.typeck_results().expr_ty_adjusted(char_arg); if *char_arg_ty.kind() == ty::Char; then { - Some((true, char_arg, radix_arg)) + Some((true, *char_arg, radix_arg)) } else { None } @@ -59,7 +57,7 @@ impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome { } hir::ExprKind::Call(to_digits_call, to_digit_args) => { if_chain! { - if let [char_arg, radix_arg] = &**to_digit_args; + if let [char_arg, radix_arg] = *to_digit_args; if let hir::ExprKind::Path(to_digits_path) = &to_digits_call.kind; if let to_digits_call_res = cx.qpath_res(to_digits_path, to_digits_call.hir_id); if let Some(to_digits_def_id) = to_digits_call_res.opt_def_id(); diff --git a/clippy_lints/src/uninit_vec.rs b/clippy_lints/src/uninit_vec.rs index 9a41603f2f4c..3f99bd3f3156 100644 --- a/clippy_lints/src/uninit_vec.rs +++ b/clippy_lints/src/uninit_vec.rs @@ -177,7 +177,7 @@ fn extract_init_or_reserve_target<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt }); } }, - ExprKind::MethodCall(path, [self_expr, _], _) if is_reserve(cx, path, self_expr) => { + ExprKind::MethodCall(path, self_expr, [_], _) if is_reserve(cx, path, self_expr) => { return Some(TargetVec { location: VecLocation::Expr(self_expr), init_kind: None, @@ -211,7 +211,7 @@ fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Opt } }); match expr.kind { - ExprKind::MethodCall(path, [self_expr, _], _) => { + ExprKind::MethodCall(path, self_expr, [_], _) => { let self_type = cx.typeck_results().expr_ty(self_expr).peel_refs(); if is_type_diagnostic_item(cx, self_type, sym::Vec) && path.ident.name.as_str() == "set_len" { Some((self_expr, expr.span)) diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs index b0fce91abeb7..851eef7b3324 100644 --- a/clippy_lints/src/unit_return_expecting_ord.rs +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -144,8 +144,9 @@ fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Spa impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if let ExprKind::MethodCall(_, args, _) = expr.kind { + if let ExprKind::MethodCall(_, receiver, args, _) = expr.kind { let arg_indices = get_args_to_check(cx, expr); + let args = std::iter::once(receiver).chain(args.iter()).collect::>(); for (i, trait_name) in arg_indices { if i < args.len() { match check_arg(cx, &args[i]) { diff --git a/clippy_lints/src/unit_types/let_unit_value.rs b/clippy_lints/src/unit_types/let_unit_value.rs index aec028d5c482..35824b03170a 100644 --- a/clippy_lints/src/unit_types/let_unit_value.rs +++ b/clippy_lints/src/unit_types/let_unit_value.rs @@ -128,7 +128,7 @@ fn needs_inferred_result_ty( locals_to_check: &mut Vec, seen_locals: &mut HirIdSet, ) -> bool { - let (id, args) = match e.kind { + let (id, receiver, args) = match e.kind { ExprKind::Call( Expr { kind: ExprKind::Path(ref path), @@ -137,11 +137,11 @@ fn needs_inferred_result_ty( }, args, ) => match cx.qpath_res(path, *hir_id) { - Res::Def(DefKind::AssocFn | DefKind::Fn, id) => (id, args), + Res::Def(DefKind::AssocFn | DefKind::Fn, id) => (id, None, args), _ => return false, }, - ExprKind::MethodCall(_, args, _) => match cx.typeck_results().type_dependent_def_id(e.hir_id) { - Some(id) => (id, args), + ExprKind::MethodCall(_, receiver, args, _) => match cx.typeck_results().type_dependent_def_id(e.hir_id) { + Some(id) => (id, Some(receiver), args), None => return false, }, ExprKind::Path(QPath::Resolved(None, path)) => { @@ -156,6 +156,11 @@ fn needs_inferred_result_ty( }; let sig = cx.tcx.fn_sig(id).skip_binder(); if let ty::Param(output_ty) = *sig.output().kind() { + let args: Vec<&Expr<'_>> = if let Some(receiver) = receiver { + std::iter::once(receiver).chain(args.iter()).collect() + } else { + args.iter().collect() + }; sig.inputs().iter().zip(args).all(|(&ty, arg)| { !ty.is_param(output_ty.index) || each_value_source_needs_inference(cx, arg, locals_to_check, seen_locals) }) diff --git a/clippy_lints/src/unit_types/unit_arg.rs b/clippy_lints/src/unit_types/unit_arg.rs index 16da2f11b81a..7ffb53dcf455 100644 --- a/clippy_lints/src/unit_types/unit_arg.rs +++ b/clippy_lints/src/unit_types/unit_arg.rs @@ -30,26 +30,27 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { } } - match expr.kind { - ExprKind::Call(_, args) | ExprKind::MethodCall(_, args, _) => { - let args_to_recover = args - .iter() - .filter(|arg| { - if cx.typeck_results().expr_ty(arg).is_unit() && !utils::is_unit_literal(arg) { - !matches!( - &arg.kind, - ExprKind::Match(.., MatchSource::TryDesugar) | ExprKind::Path(..) - ) - } else { - false - } - }) - .collect::>(); - if !args_to_recover.is_empty() && !is_from_proc_macro(cx, expr) { - lint_unit_args(cx, expr, &args_to_recover); + let args: Vec<_> = match expr.kind { + ExprKind::Call(_, args) => args.iter().collect(), + ExprKind::MethodCall(_, receiver, args, _) => std::iter::once(receiver).chain(args.iter()).collect(), + _ => return, + }; + + let args_to_recover = args + .into_iter() + .filter(|arg| { + if cx.typeck_results().expr_ty(arg).is_unit() && !utils::is_unit_literal(arg) { + !matches!( + &arg.kind, + ExprKind::Match(.., MatchSource::TryDesugar) | ExprKind::Path(..) + ) + } else { + false } - }, - _ => (), + }) + .collect::>(); + if !args_to_recover.is_empty() && !is_from_proc_macro(cx, expr) { + lint_unit_args(cx, expr, &args_to_recover.as_slice()); } } diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index 323cf83ffcff..b38d71784fcf 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount { check_map_error(cx, res, expr); } }, - hir::ExprKind::MethodCall(path, [ref arg_0, ..], _) => match path.ident.as_str() { + hir::ExprKind::MethodCall(path, arg_0, ..) => match path.ident.as_str() { "expect" | "unwrap" | "unwrap_or" | "unwrap_or_else" => { check_map_error(cx, arg_0, expr); }, @@ -94,9 +94,9 @@ fn try_remove_await<'a>(expr: &'a hir::Expr<'a>) -> Option<&hir::Expr<'a>> { fn check_map_error(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) { let mut call = call; - while let hir::ExprKind::MethodCall(path, args, _) = call.kind { + while let hir::ExprKind::MethodCall(path, receiver, ..) = call.kind { if matches!(path.ident.as_str(), "or" | "or_else" | "ok") { - call = &args[0]; + call = receiver; } else { break; } @@ -110,7 +110,7 @@ fn check_map_error(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr< } fn check_method_call(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>, is_await: bool) { - if let hir::ExprKind::MethodCall(path, _, _) = call.kind { + if let hir::ExprKind::MethodCall(path, ..) = call.kind { let symbol = path.ident.as_str(); let read_trait = if is_await { match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCREADEXT) diff --git a/clippy_lints/src/unused_peekable.rs b/clippy_lints/src/unused_peekable.rs index ac73173697e8..7fbfecf96ec3 100644 --- a/clippy_lints/src/unused_peekable.rs +++ b/clippy_lints/src/unused_peekable.rs @@ -149,7 +149,8 @@ impl<'tcx> Visitor<'_> for PeekableVisitor<'_, 'tcx> { ident: method_name_ident, .. }, - [self_arg, remaining_args @ ..], + self_arg, + [remaining_args @ ..], _, ) => { let method_name = method_name_ident.name.as_str(); diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index d3f9e5abfd73..9092156be150 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -154,13 +154,13 @@ fn collect_unwrap_info<'tcx>( return collect_unwrap_info(cx, if_expr, expr, branch, !invert, false); } else { if_chain! { - if let ExprKind::MethodCall(method_name, args, _) = &expr.kind; - if let Some(local_id) = path_to_local(&args[0]); - let ty = cx.typeck_results().expr_ty(&args[0]); + if let ExprKind::MethodCall(method_name, receiver, args, _) = &expr.kind; + if let Some(local_id) = path_to_local(receiver); + let ty = cx.typeck_results().expr_ty(receiver); let name = method_name.ident.as_str(); if is_relevant_option_call(cx, ty, name) || is_relevant_result_call(cx, ty, name); then { - assert!(args.len() == 1); + assert!(args.len() == 0); let unwrappable = match name { "is_some" | "is_ok" => true, "is_err" | "is_none" => false, @@ -231,7 +231,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> { } else { // find `unwrap[_err]()` calls: if_chain! { - if let ExprKind::MethodCall(method_name, [self_arg, ..], _) = expr.kind; + if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind; if let Some(id) = path_to_local(self_arg); if [sym::unwrap, sym::expect, sym!(unwrap_err)].contains(&method_name.ident.name); let call_to_unwrap = [sym::unwrap, sym::expect].contains(&method_name.ident.name); diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index b32be238cd55..b3ca15f7648b 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -83,7 +83,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { // check for `expect` if let Some(arglists) = method_chain_args(expr, &["expect"]) { - let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); + let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs(); if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option) || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result) { @@ -93,7 +93,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> { // check for `unwrap` if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { - let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); + let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs(); if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option) || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result) { diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index b6738e2891d3..f1b6463ad0f7 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { } }, - ExprKind::MethodCall(name, .., [recv, ..], _) => { + ExprKind::MethodCall(name, recv, ..) => { if is_trait_method(cx, e, sym::Into) && name.ident.as_str() == "into" { let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(recv); diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 3ffcaa90af3e..fec4ee93e7bc 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -402,10 +402,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { self.expr(func); self.slice(args, |e| self.expr(e)); }, - ExprKind::MethodCall(method_name, args, _) => { - bind!(self, method_name, args); - kind!("MethodCall({method_name}, {args}, _)"); + ExprKind::MethodCall(method_name, receiver, args, _) => { + bind!(self, method_name, receiver, args); + kind!("MethodCall({method_name}, {receiver}, {args}, _)"); self.ident(field!(method_name.ident)); + self.expr(receiver); self.slice(args, |e| self.expr(e)); }, ExprKind::Tup(elements) => { diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index eb34085a2abf..ae1c11ef83c3 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -687,7 +687,7 @@ impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass { if let ["expn_data", "outer_expn"] = method_names.as_slice(); let args = arg_lists[1]; if args.len() == 1; - let self_arg = &args[0]; + let self_arg = &args.0; let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); if match_type(cx, self_ty, &paths::SYNTAX_CONTEXT); then { diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs index 35db45e2b0c9..542c6a37d567 100644 --- a/clippy_lints/src/vec_init_then_push.rs +++ b/clippy_lints/src/vec_init_then_push.rs @@ -100,7 +100,7 @@ impl VecPushSearcher { || get_parent_expr(cx, last_place) .map_or(false, |e| matches!(e.kind, ExprKind::AddrOf(_, Mutability::Mut, _))); }, - ExprKind::MethodCall(_, [recv, ..], _) + ExprKind::MethodCall(_, recv, ..) if recv.hir_id == e.hir_id && adjusted_mut == Mutability::Mut && !adjusted_ty.peel_refs().is_slice() => @@ -201,7 +201,7 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { if let Some(searcher) = self.searcher.take() { if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind - && let ExprKind::MethodCall(name, [self_arg, _], _) = expr.kind + && let ExprKind::MethodCall(name, self_arg, [_], _) = expr.kind && path_to_local_id(self_arg, searcher.local_id) && name.ident.as_str() == "push" { diff --git a/clippy_utils/src/check_proc_macro.rs b/clippy_utils/src/check_proc_macro.rs index 8335ffae81eb..e8d2d579f097 100644 --- a/clippy_utils/src/check_proc_macro.rs +++ b/clippy_utils/src/check_proc_macro.rs @@ -118,9 +118,9 @@ fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) { ExprKind::Unary(UnOp::Neg, e) => (Pat::Str("-"), expr_search_pat(tcx, e).1), ExprKind::Lit(ref lit) => lit_search_pat(&lit.node), ExprKind::Array(_) | ExprKind::Repeat(..) => (Pat::Str("["), Pat::Str("]")), - ExprKind::Call(e, []) | ExprKind::MethodCall(_, [e], _) => (expr_search_pat(tcx, e).0, Pat::Str("(")), + ExprKind::Call(e, []) | ExprKind::MethodCall(_, e, [], _) => (expr_search_pat(tcx, e).0, Pat::Str("(")), ExprKind::Call(first, [.., last]) - | ExprKind::MethodCall(_, [first, .., last], _) + | ExprKind::MethodCall(_, first, [.., last], _) | ExprKind::Binary(_, first, last) | ExprKind::Tup([first, .., last]) | ExprKind::Assign(first, last, _) diff --git a/clippy_utils/src/diagnostics.rs b/clippy_utils/src/diagnostics.rs index 7f55db3b31f7..ad95369b9ef7 100644 --- a/clippy_utils/src/diagnostics.rs +++ b/clippy_utils/src/diagnostics.rs @@ -155,13 +155,7 @@ where }); } -pub fn span_lint_hir( - cx: &LateContext<'_>, - lint: &'static Lint, - hir_id: HirId, - sp: Span, - msg: &str, -) { +pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: &str) { cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |diag| { let mut diag = diag.build(msg); docs_link(&mut diag, lint); diff --git a/clippy_utils/src/eager_or_lazy.rs b/clippy_utils/src/eager_or_lazy.rs index 730724b95b96..124a00d81784 100644 --- a/clippy_utils/src/eager_or_lazy.rs +++ b/clippy_utils/src/eager_or_lazy.rs @@ -45,12 +45,7 @@ impl ops::BitOrAssign for EagernessSuggestion { } /// Determine the eagerness of the given function call. -fn fn_eagerness<'tcx>( - cx: &LateContext<'tcx>, - fn_id: DefId, - name: Symbol, - args: &'tcx [Expr<'_>], -) -> EagernessSuggestion { +fn fn_eagerness<'tcx>(cx: &LateContext<'tcx>, fn_id: DefId, name: Symbol, have_one_arg: bool) -> EagernessSuggestion { use EagernessSuggestion::{Eager, Lazy, NoChange}; let name = name.as_str(); @@ -59,7 +54,7 @@ fn fn_eagerness<'tcx>( None => return Lazy, }; - if (name.starts_with("as_") || name == "len" || name == "is_empty") && args.len() == 1 { + if (name.starts_with("as_") || name == "len" || name == "is_empty") && have_one_arg { if matches!( cx.tcx.crate_name(fn_id.krate), sym::std | sym::core | sym::alloc | sym::proc_macro @@ -127,10 +122,11 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS }, Res::Def(_, id) => match path { QPath::Resolved(_, p) => { - self.eagerness |= fn_eagerness(self.cx, id, p.segments.last().unwrap().ident.name, args); + self.eagerness |= + fn_eagerness(self.cx, id, p.segments.last().unwrap().ident.name, !args.is_empty()); }, QPath::TypeRelative(_, name) => { - self.eagerness |= fn_eagerness(self.cx, id, name.ident.name, args); + self.eagerness |= fn_eagerness(self.cx, id, name.ident.name, !args.is_empty()); }, QPath::LangItem(..) => self.eagerness = Lazy, }, @@ -141,12 +137,12 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS self.eagerness |= NoChange; return; }, - ExprKind::MethodCall(name, args, _) => { + ExprKind::MethodCall(name, ..) => { self.eagerness |= self .cx .typeck_results() .type_dependent_def_id(e.hir_id) - .map_or(Lazy, |id| fn_eagerness(self.cx, id, name.ident.name, args)); + .map_or(Lazy, |id| fn_eagerness(self.cx, id, name.ident.name, true)); }, ExprKind::Index(_, e) => { let ty = self.cx.typeck_results().expr_ty_adjusted(e); diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index 1834e2a2de87..6cb6544df4bc 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -282,8 +282,14 @@ impl HirEqInterExpr<'_, '_, '_> { && self.eq_expr(l.body, r.body) }) }, - (&ExprKind::MethodCall(l_path, l_args, _), &ExprKind::MethodCall(r_path, r_args, _)) => { - self.inner.allow_side_effects && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args) + ( + &ExprKind::MethodCall(l_path, l_receiver, l_args, _), + &ExprKind::MethodCall(r_path, r_receiver, r_args, _), + ) => { + self.inner.allow_side_effects + && self.eq_path_segment(l_path, r_path) + && self.eq_expr(l_receiver, r_receiver) + && self.eq_exprs(l_args, r_args) }, (&ExprKind::Repeat(le, ll), &ExprKind::Repeat(re, rl)) => { self.eq_expr(le, re) && self.eq_array_length(ll, rl) @@ -743,8 +749,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { s.hash(&mut self.s); }, - ExprKind::MethodCall(path, args, ref _fn_span) => { + ExprKind::MethodCall(path, receiver, args, ref _fn_span) => { self.hash_name(path.ident.name); + self.hash_expr(receiver); self.hash_exprs(args); }, ExprKind::ConstBlock(ref l_id) => { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index f3a08e98688e..ed1f8af989fe 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -1036,21 +1036,21 @@ pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<' pub fn method_calls<'tcx>( expr: &'tcx Expr<'tcx>, max_depth: usize, -) -> (Vec, Vec<&'tcx [Expr<'tcx>]>, Vec) { +) -> (Vec, Vec<(&'tcx Expr<'tcx>, &'tcx [Expr<'tcx>])>, Vec) { let mut method_names = Vec::with_capacity(max_depth); let mut arg_lists = Vec::with_capacity(max_depth); let mut spans = Vec::with_capacity(max_depth); let mut current = expr; for _ in 0..max_depth { - if let ExprKind::MethodCall(path, args, _) = ¤t.kind { - if args.iter().any(|e| e.span.from_expansion()) { + if let ExprKind::MethodCall(path, receiver, args, _) = ¤t.kind { + if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) { break; } method_names.push(path.ident.name); - arg_lists.push(&**args); + arg_lists.push((*receiver, &**args)); spans.push(path.ident.span); - current = &args[0]; + current = receiver; } else { break; } @@ -1065,18 +1065,18 @@ pub fn method_calls<'tcx>( /// `method_chain_args(expr, &["bar", "baz"])` will return a `Vec` /// containing the `Expr`s for /// `.bar()` and `.baz()` -pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option]>> { +pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option, &'a [Expr<'a>])>> { let mut current = expr; let mut matched = Vec::with_capacity(methods.len()); for method_name in methods.iter().rev() { // method chains are stored last -> first - if let ExprKind::MethodCall(path, args, _) = current.kind { + if let ExprKind::MethodCall(path, receiver, args, _) = current.kind { if path.ident.name.as_str() == *method_name { - if args.iter().any(|e| e.span.from_expansion()) { + if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) { return None; } - matched.push(args); // build up `matched` backwards - current = &args[0]; // go to parent expression + matched.push((receiver, args)); // build up `matched` backwards + current = receiver; // go to parent expression } else { return None; } @@ -1239,8 +1239,10 @@ pub fn get_enclosing_loop_or_multi_call_closure<'tcx>( ty_is_fn_once_param(cx.tcx, ty.skip_binder(), predicates).then_some(()) }) }, - ExprKind::MethodCall(_, args, _) => { - let i = args.iter().position(|arg| arg.hir_id == id)?; + ExprKind::MethodCall(_, receiver, args, _) => { + let i = std::iter::once(receiver) + .chain(args.iter()) + .position(|arg| arg.hir_id == id)?; let id = cx.typeck_results().type_dependent_def_id(e.hir_id)?; let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i]; ty_is_fn_once_param(cx.tcx, ty, cx.tcx.param_env(id).caller_bounds()).then_some(()) diff --git a/clippy_utils/src/ptr.rs b/clippy_utils/src/ptr.rs index 649b7b9940af..0226f74906b5 100644 --- a/clippy_utils/src/ptr.rs +++ b/clippy_utils/src/ptr.rs @@ -36,7 +36,7 @@ fn extract_clone_suggestions<'tcx>( if abort { return false; } - if let ExprKind::MethodCall(seg, [recv], _) = expr.kind { + if let ExprKind::MethodCall(seg, recv, [], _) = expr.kind { if path_to_local_id(recv, id) { if seg.ident.name.as_str() == "capacity" { abort = true; diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs index 081c98e2f3ce..cca71bbf76e2 100644 --- a/clippy_utils/src/sugg.rs +++ b/clippy_utils/src/sugg.rs @@ -373,12 +373,14 @@ fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String { | AssocOp::LessEqual | AssocOp::NotEqual | AssocOp::Greater - | AssocOp::GreaterEqual => format!( - "{} {} {}", - lhs, - op.to_ast_binop().expect("Those are AST ops").to_string(), - rhs - ), + | AssocOp::GreaterEqual => { + format!( + "{} {} {}", + lhs, + op.to_ast_binop().expect("Those are AST ops").to_string(), + rhs + ) + }, AssocOp::Assign => format!("{} = {}", lhs, rhs), AssocOp::AssignOp(op) => { format!("{} {}= {}", lhs, token_kind_to_string(&token::BinOp(op)), rhs) @@ -868,15 +870,15 @@ impl<'tcx> DerefDelegate<'_, 'tcx> { /// indicates whether the function from `parent_expr` takes its args by double reference fn func_takes_arg_by_double_ref(&self, parent_expr: &'tcx hir::Expr<'_>, cmt_hir_id: HirId) -> bool { let ty = match parent_expr.kind { - ExprKind::MethodCall(_, call_args, _) => { + ExprKind::MethodCall(_, receiver, call_args, _) => { if let Some(sig) = self .cx .typeck_results() .type_dependent_def_id(parent_expr.hir_id) .map(|did| self.cx.tcx.fn_sig(did).skip_binder()) { - call_args - .iter() + std::iter::once(receiver) + .chain(call_args.iter()) .position(|arg| arg.hir_id == cmt_hir_id) .map(|i| sig.inputs()[i]) } else { @@ -933,14 +935,14 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { match &parent_expr.kind { // given expression is the self argument and will be handled completely by the compiler // i.e.: `|x| x.is_something()` - ExprKind::MethodCall(_, [self_expr, ..], _) if self_expr.hir_id == cmt.hir_id => { + ExprKind::MethodCall(_, self_expr, ..) if self_expr.hir_id == cmt.hir_id => { let _ = write!(self.suggestion_start, "{}{}", start_snip, ident_str_with_proj); self.next_pos = span.hi(); return; }, // item is used in a call // i.e.: `Call`: `|x| please(x)` or `MethodCall`: `|x| [1, 2, 3].contains(x)` - ExprKind::Call(_, [call_args @ ..]) | ExprKind::MethodCall(_, [_, call_args @ ..], _) => { + ExprKind::Call(_, [call_args @ ..]) | ExprKind::MethodCall(_, _, [call_args @ ..], _) => { let expr = self.cx.tcx.hir().expect_expr(cmt.hir_id); let arg_ty_kind = self.cx.typeck_results().expr_ty(expr).kind(); diff --git a/clippy_utils/src/visitors.rs b/clippy_utils/src/visitors.rs index bae8ad9f5659..6a62002a4d12 100644 --- a/clippy_utils/src/visitors.rs +++ b/clippy_utils/src/visitors.rs @@ -620,7 +620,13 @@ pub fn for_each_unconsumed_temporary<'tcx, B>( helper(typeck, true, arg, f)?; } }, - ExprKind::MethodCall(_, args, _) | ExprKind::Tup(args) | ExprKind::Array(args) => { + ExprKind::MethodCall(_, receiver, args, _) => { + helper(typeck, true, receiver, f)?; + for arg in args { + helper(typeck, true, arg, f)?; + } + }, + ExprKind::Tup(args) | ExprKind::Array(args) => { for arg in args { helper(typeck, true, arg, f)?; } diff --git a/tests/ui/author/struct.stdout b/tests/ui/author/struct.stdout index 5e78b7c9de7e..b5bbc9e213c6 100644 --- a/tests/ui/author/struct.stdout +++ b/tests/ui/author/struct.stdout @@ -53,11 +53,11 @@ if_chain! { } } if_chain! { - if let ExprKind::MethodCall(method_name, args, _) = expr.kind; + if let ExprKind::MethodCall(method_name, receiver, args, _) = expr.kind; if method_name.ident.as_str() == "test"; - if args.len() == 1; - if let ExprKind::Path(ref qpath) = args[0].kind; + if let ExprKind::Path(ref qpath) = receiver.kind; if match_qpath(qpath, &["test_method_call"]); + if args.is_empty(); then { // report your lint here } From 3955dc3480cfb60116586ce94f9c332744fcacbb Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Thu, 1 Sep 2022 18:43:35 +0900 Subject: [PATCH 4208/5092] separate the receiver from arguments in HIR under /clippy --- .../portable-simd/crates/std_float/src/lib.rs | 6 +- .../development/common_tools_writing_lints.md | 2 +- .../src/assertions_on_result_states.rs | 2 +- .../src/blocks_in_if_conditions.rs | 5 +- src/tools/clippy/clippy_lints/src/booleans.rs | 6 +- .../src/casts/cast_abs_to_unsigned.rs | 4 +- .../src/casts/cast_possible_truncation.rs | 6 +- .../src/casts/cast_ptr_alignment.rs | 4 +- .../clippy_lints/src/casts/cast_sign_loss.rs | 4 +- .../src/default_numeric_fallback.rs | 23 ++-- .../clippy/clippy_lints/src/dereference.rs | 47 ++++---- src/tools/clippy/clippy_lints/src/doc.rs | 2 +- src/tools/clippy/clippy_lints/src/entry.rs | 4 +- .../clippy/clippy_lints/src/eta_reduction.rs | 25 +++-- .../clippy/clippy_lints/src/explicit_write.rs | 4 +- .../clippy_lints/src/fallible_impl_from.rs | 2 +- .../src/floating_point_arithmetic.rs | 79 +++++++------- .../clippy/clippy_lints/src/format_args.rs | 20 ++-- .../clippy/clippy_lints/src/format_impl.rs | 2 +- .../clippy_lints/src/format_push_string.rs | 2 +- .../clippy_lints/src/functions/must_use.rs | 20 +++- .../src/functions/not_unsafe_ptr_arg_deref.rs | 3 +- .../clippy/clippy_lints/src/if_let_mutex.rs | 2 +- .../clippy/clippy_lints/src/infinite_iter.rs | 100 +++++++++--------- src/tools/clippy/clippy_lints/src/len_zero.rs | 10 +- .../clippy_lints/src/loops/manual_memcpy.rs | 4 +- .../src/loops/missing_spin_loop.rs | 2 +- .../clippy/clippy_lints/src/loops/mod.rs | 2 +- .../src/loops/needless_collect.rs | 14 +-- .../src/loops/needless_range_loop.rs | 11 +- .../clippy_lints/src/loops/never_loop.rs | 5 +- .../clippy_lints/src/loops/same_item_push.rs | 5 +- .../src/loops/single_element_loop.rs | 33 +++--- .../clippy_lints/src/loops/while_let_loop.rs | 9 +- .../src/loops/while_let_on_iterator.rs | 2 +- .../clippy/clippy_lints/src/manual_bits.rs | 2 +- .../clippy/clippy_lints/src/manual_retain.rs | 22 ++-- .../clippy_lints/src/manual_string_new.rs | 13 +-- .../clippy/clippy_lints/src/manual_strip.rs | 4 +- .../clippy/clippy_lints/src/map_unit_fn.rs | 11 +- .../clippy_lints/src/match_result_ok.rs | 2 +- .../src/matches/match_str_case_mismatch.rs | 2 +- .../src/matches/redundant_pattern_match.rs | 2 +- .../matches/significant_drop_in_scrutinee.rs | 5 +- .../clippy_lints/src/methods/bytecount.rs | 6 +- .../clippy_lints/src/methods/chars_cmp.rs | 4 +- .../src/methods/chars_cmp_with_unwrap.rs | 2 +- .../clippy_lints/src/methods/clone_on_copy.rs | 14 ++- .../src/methods/clone_on_ref_ptr.rs | 12 ++- .../src/methods/collapsible_str_replace.rs | 6 +- .../src/methods/expect_fun_call.rs | 24 ++--- .../src/methods/extend_with_drain.rs | 2 +- .../clippy_lints/src/methods/filter_map.rs | 12 +-- .../src/methods/get_last_with_len.rs | 2 +- .../src/methods/inefficient_to_string.rs | 14 ++- .../src/methods/into_iter_on_ref.rs | 4 +- .../src/methods/iter_with_drain.rs | 2 +- .../clippy_lints/src/methods/map_clone.rs | 2 +- .../clippy/clippy_lints/src/methods/mod.rs | 96 +++++++++-------- .../clippy_lints/src/methods/open_options.rs | 10 +- .../src/methods/option_as_ref_deref.rs | 7 +- .../clippy_lints/src/methods/or_fun_call.rs | 7 +- .../src/methods/range_zip_with_len.rs | 2 +- .../src/methods/single_char_add_str.rs | 6 +- .../src/methods/single_char_insert_string.rs | 8 +- .../src/methods/single_char_pattern.rs | 58 +++++----- .../src/methods/single_char_push_string.rs | 6 +- .../clippy_lints/src/methods/str_splitn.rs | 6 +- .../src/methods/string_extend_chars.rs | 2 +- .../src/methods/unnecessary_iter_cloned.rs | 2 +- .../src/methods/unnecessary_lazy_eval.rs | 2 +- .../src/methods/unnecessary_sort_by.rs | 8 +- .../src/methods/unnecessary_to_owned.rs | 22 ++-- .../clippy/clippy_lints/src/methods/utils.rs | 6 +- src/tools/clippy/clippy_lints/src/minmax.rs | 35 +++--- .../clippy/clippy_lints/src/mut_reference.rs | 14 ++- .../clippy_lints/src/needless_for_each.rs | 4 +- .../src/non_octal_unix_permissions.rs | 2 +- .../src/only_used_in_recursion.rs | 4 +- .../clippy_lints/src/operators/cmp_owned.rs | 2 +- .../src/operators/duration_subsec.rs | 2 +- .../clippy_lints/src/operators/float_cmp.rs | 2 +- src/tools/clippy/clippy_lints/src/ptr.rs | 7 +- .../clippy_lints/src/ptr_offset_with_cast.rs | 2 +- .../clippy/clippy_lints/src/question_mark.rs | 2 +- .../clippy_lints/src/read_zero_byte_vec.rs | 2 +- .../src/size_of_in_element_count.rs | 2 +- .../src/slow_vector_initialization.rs | 10 +- src/tools/clippy/clippy_lints/src/strings.rs | 28 ++--- .../clippy_lints/src/strlen_on_c_strings.rs | 2 +- .../clippy_lints/src/to_digit_is_some.rs | 10 +- .../clippy/clippy_lints/src/uninit_vec.rs | 4 +- .../src/unit_return_expecting_ord.rs | 3 +- .../src/unit_types/let_unit_value.rs | 13 ++- .../clippy_lints/src/unit_types/unit_arg.rs | 39 +++---- .../clippy_lints/src/unused_io_amount.rs | 8 +- .../clippy_lints/src/unused_peekable.rs | 3 +- src/tools/clippy/clippy_lints/src/unwrap.rs | 10 +- .../clippy_lints/src/unwrap_in_result.rs | 4 +- .../clippy_lints/src/useless_conversion.rs | 2 +- .../clippy/clippy_lints/src/utils/author.rs | 7 +- .../clippy_lints/src/utils/internal_lints.rs | 2 +- .../clippy_lints/src/vec_init_then_push.rs | 4 +- .../clippy_utils/src/check_proc_macro.rs | 4 +- .../clippy/clippy_utils/src/diagnostics.rs | 8 +- .../clippy/clippy_utils/src/eager_or_lazy.rs | 18 ++-- .../clippy/clippy_utils/src/hir_utils.rs | 13 ++- src/tools/clippy/clippy_utils/src/lib.rs | 26 ++--- src/tools/clippy/clippy_utils/src/ptr.rs | 2 +- src/tools/clippy/clippy_utils/src/sugg.rs | 24 +++-- src/tools/clippy/clippy_utils/src/visitors.rs | 8 +- .../clippy/tests/ui/author/struct.stdout | 6 +- 112 files changed, 663 insertions(+), 563 deletions(-) diff --git a/library/portable-simd/crates/std_float/src/lib.rs b/library/portable-simd/crates/std_float/src/lib.rs index 4bd4d4c05e3b..4ac60b10c92e 100644 --- a/library/portable-simd/crates/std_float/src/lib.rs +++ b/library/portable-simd/crates/std_float/src/lib.rs @@ -1,9 +1,5 @@ #![cfg_attr(feature = "as_crate", no_std)] // We are std! -#![cfg_attr( - feature = "as_crate", - feature(platform_intrinsics), - feature(portable_simd) -)] +#![cfg_attr(feature = "as_crate", feature(platform_intrinsics), feature(portable_simd))] #[cfg(not(feature = "as_crate"))] use core::simd; #[cfg(feature = "as_crate")] diff --git a/src/tools/clippy/book/src/development/common_tools_writing_lints.md b/src/tools/clippy/book/src/development/common_tools_writing_lints.md index 15e00c7d7ce4..2bc275ceff0b 100644 --- a/src/tools/clippy/book/src/development/common_tools_writing_lints.md +++ b/src/tools/clippy/book/src/development/common_tools_writing_lints.md @@ -66,7 +66,7 @@ Starting with an `expr`, you can check whether it is calling a specific method impl<'tcx> LateLintPass<'tcx> for MyStructLint { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { // Check our expr is calling a method - if let hir::ExprKind::MethodCall(path, _, [_self_arg, ..]) = &expr.kind + if let hir::ExprKind::MethodCall(path, _, _self_arg, ..) = &expr.kind // Check the name of this method is `some_method` && path.ident.name == sym!(some_method) // Optionally, check the type of the self argument. diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs index 6a6554f968b3..7cd198ace86c 100644 --- a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs +++ b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs @@ -43,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { && matches!(cx.tcx.get_diagnostic_name(macro_call.def_id), Some(sym::assert_macro)) && let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn) && matches!(panic_expn, PanicExpn::Empty) - && let ExprKind::MethodCall(method_segment, [recv], _) = condition.kind + && let ExprKind::MethodCall(method_segment, recv, [], _) = condition.kind && let result_type_with_refs = cx.typeck_results().expr_ty(recv) && let result_type = result_type_with_refs.peel_refs() && is_type_diagnostic_item(cx, result_type, sym::Result) diff --git a/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs b/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs index ad206b5fb304..d9e2c9c8578f 100644 --- a/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs +++ b/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs @@ -55,7 +55,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ExVisitor<'a, 'tcx> { // do not lint if the closure is called using an iterator (see #1141) if_chain! { if let Some(parent) = get_parent_expr(self.cx, expr); - if let ExprKind::MethodCall(_, [self_arg, ..], _) = &parent.kind; + if let ExprKind::MethodCall(_, self_arg, ..) = &parent.kind; let caller = self.cx.typeck_results().expr_ty(self_arg); if let Some(iter_id) = self.cx.tcx.get_diagnostic_item(sym::Iterator); if implements_trait(self.cx, caller, iter_id, &[]); @@ -117,7 +117,8 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInIfConditions { ); } } else { - let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span); + let span = + block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span); if span.from_expansion() || expr.span.from_expansion() { return; } diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs index 6eb78d21e826..656d639f0efd 100644 --- a/src/tools/clippy/clippy_lints/src/booleans.rs +++ b/src/tools/clippy/clippy_lints/src/booleans.rs @@ -270,8 +270,8 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { )) }) }, - ExprKind::MethodCall(path, args, _) if args.len() == 1 => { - let type_of_receiver = cx.typeck_results().expr_ty(&args[0]); + ExprKind::MethodCall(path, receiver, [], _) => { + let type_of_receiver = cx.typeck_results().expr_ty(receiver); if !is_type_diagnostic_item(cx, type_of_receiver, sym::Option) && !is_type_diagnostic_item(cx, type_of_receiver, sym::Result) { @@ -285,7 +285,7 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { let path: &str = path.ident.name.as_str(); a == path }) - .and_then(|(_, neg_method)| Some(format!("{}.{}()", snippet_opt(cx, args[0].span)?, neg_method))) + .and_then(|(_, neg_method)| Some(format!("{}.{}()", snippet_opt(cx, receiver.span)?, neg_method))) }, _ => None, } diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs index 6426e8c25ac1..3f1edabe6c50 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs @@ -20,7 +20,7 @@ pub(super) fn check( if meets_msrv(msrv, msrvs::UNSIGNED_ABS) && let ty::Int(from) = cast_from.kind() && let ty::Uint(to) = cast_to.kind() - && let ExprKind::MethodCall(method_path, args, _) = cast_expr.kind + && let ExprKind::MethodCall(method_path, receiver, ..) = cast_expr.kind && method_path.ident.name.as_str() == "abs" { let span = if from.bit_width() == to.bit_width() { @@ -37,7 +37,7 @@ pub(super) fn check( span, &format!("casting the result of `{cast_from}::abs()` to {cast_to}"), "replace with", - format!("{}.unsigned_abs()", Sugg::hir(cx, &args[0], "..").maybe_par()), + format!("{}.unsigned_abs()", Sugg::hir(cx, receiver, "..").maybe_par()), Applicability::MachineApplicable, ); } diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs index 64f87c80f8d1..406547a4454e 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs @@ -44,7 +44,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b .saturating_sub(constant_int(cx, right).map_or(0, |s| u64::try_from(s).expect("shift too high"))), _ => nbits, }, - ExprKind::MethodCall(method, [left, right], _) => { + ExprKind::MethodCall(method, left, [right], _) => { if signed { return nbits; } @@ -55,7 +55,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b }; apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::max_value())) }, - ExprKind::MethodCall(method, [_, lo, hi], _) => { + ExprKind::MethodCall(method, _, [lo, hi], _) => { if method.ident.as_str() == "clamp" { //FIXME: make this a diagnostic item if let (Some(lo_bits), Some(hi_bits)) = (get_constant_bits(cx, lo), get_constant_bits(cx, hi)) { @@ -64,7 +64,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b } nbits }, - ExprKind::MethodCall(method, [_value], _) => { + ExprKind::MethodCall(method, _value, [], _) => { if method.ident.name.as_str() == "signum" { 0 // do not lint if cast comes from a `signum` function } else { diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs index d476a1a7646c..da7b12f67266 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -18,7 +18,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { cx.typeck_results().expr_ty(expr), ); lint_cast_ptr_alignment(cx, expr, cast_from, cast_to); - } else if let ExprKind::MethodCall(method_path, [self_arg, ..], _) = &expr.kind { + } else if let ExprKind::MethodCall(method_path, self_arg, ..) = &expr.kind { if method_path.ident.name == sym!(cast) && let Some(generic_args) = method_path.args && let [GenericArg::Type(cast_to)] = generic_args.args @@ -64,7 +64,7 @@ fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { return false; }; match parent.kind { - ExprKind::MethodCall(name, [self_arg, ..], _) if self_arg.hir_id == e.hir_id => { + ExprKind::MethodCall(name, self_arg, ..) if self_arg.hir_id == e.hir_id => { if matches!(name.ident.as_str(), "read_unaligned" | "write_unaligned") && let Some(def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id) && let Some(def_id) = cx.tcx.impl_of_method(def_id) diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs index 75f70b77ed4e..5b59350be042 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs @@ -41,14 +41,14 @@ fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast } // Don't lint for the result of methods that always return non-negative values. - if let ExprKind::MethodCall(path, _, _) = cast_op.kind { + if let ExprKind::MethodCall(path, ..) = cast_op.kind { let mut method_name = path.ident.name.as_str(); let allowed_methods = ["abs", "checked_abs", "rem_euclid", "checked_rem_euclid"]; if_chain! { if method_name == "unwrap"; if let Some(arglist) = method_chain_args(cast_op, &["unwrap"]); - if let ExprKind::MethodCall(inner_path, _, _) = &arglist[0][0].kind; + if let ExprKind::MethodCall(inner_path, ..) = &arglist[0].0.kind; then { method_name = inner_path.ident.name.as_str(); } diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs index fb418a3251f5..64c5de510420 100644 --- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs +++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs @@ -69,10 +69,7 @@ struct NumericFallbackVisitor<'a, 'tcx> { impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> { fn new(cx: &'a LateContext<'tcx>) -> Self { - Self { - ty_bounds: vec![TyBound::Nothing], - cx, - } + Self { ty_bounds: vec![TyBound::Nothing], cx } } /// Check whether a passed literal has potential to cause fallback or not. @@ -129,19 +126,21 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { } return; } - }, + } - ExprKind::MethodCall(_, args, _) => { + ExprKind::MethodCall(_, receiver, args, _) => { if let Some(def_id) = self.cx.typeck_results().type_dependent_def_id(expr.hir_id) { let fn_sig = self.cx.tcx.fn_sig(def_id).skip_binder(); - for (expr, bound) in iter::zip(*args, fn_sig.inputs()) { + for (expr, bound) in + iter::zip(std::iter::once(*receiver).chain(args.iter()), fn_sig.inputs()) + { self.ty_bounds.push(TyBound::Ty(*bound)); self.visit_expr(expr); self.ty_bounds.pop(); } return; } - }, + } ExprKind::Struct(_, fields, base) => { let ty = self.cx.typeck_results().expr_ty(expr); @@ -176,15 +175,15 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { return; } } - }, + } ExprKind::Lit(lit) => { let ty = self.cx.typeck_results().expr_ty(expr); self.check_lit(lit, ty, expr.hir_id); return; - }, + } - _ => {}, + _ => {} } walk_expr(self, expr); @@ -198,7 +197,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { } else { self.ty_bounds.push(TyBound::Nothing); } - }, + } _ => self.ty_bounds.push(TyBound::Nothing), } diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 1506ea604f0d..fd6ed36cb192 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -581,7 +581,7 @@ fn try_parse_ref_op<'tcx>( expr: &'tcx Expr<'_>, ) -> Option<(RefOp, &'tcx Expr<'tcx>)> { let (def_id, arg) = match expr.kind { - ExprKind::MethodCall(_, [arg], _) => (typeck.type_dependent_def_id(expr.hir_id)?, arg), + ExprKind::MethodCall(_, arg, [], _) => (typeck.type_dependent_def_id(expr.hir_id)?, arg), ExprKind::Call( Expr { kind: ExprKind::Path(path), @@ -796,16 +796,19 @@ fn walk_parents<'tcx>( }, }) }), - ExprKind::MethodCall(_, args, _) => { + ExprKind::MethodCall(_, receiver, args, _) => { let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap(); - args.iter().position(|arg| arg.hir_id == child_id).map(|i| { - if i == 0 { - // Check for calls to trait methods where the trait is implemented on a reference. - // Two cases need to be handled: - // * `self` methods on `&T` will never have auto-borrow - // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take - // priority. - if e.hir_id != child_id { + std::iter::once(receiver) + .chain(args.iter()) + .position(|arg| arg.hir_id == child_id) + .map(|i| { + if i == 0 { + // Check for calls to trait methods where the trait is implemented on a reference. + // Two cases need to be handled: + // * `self` methods on `&T` will never have auto-borrow + // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take + // priority. + if e.hir_id != child_id { Position::ReborrowStable(precedence) } else if let Some(trait_id) = cx.tcx.trait_of_item(id) && let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e)) @@ -834,20 +837,20 @@ fn walk_parents<'tcx>( } else { Position::MethodReceiver } - } else { - let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i]; - if let ty::Param(param_ty) = ty.kind() { - needless_borrow_impl_arg_position(cx, parent, i, *param_ty, e, precedence, msrv) } else { - ty_auto_deref_stability( - cx, - cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)), - precedence, - ) - .position_for_arg() + let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i]; + if let ty::Param(param_ty) = ty.kind() { + needless_borrow_impl_arg_position(cx, parent, i, *param_ty, e, precedence, msrv) + } else { + ty_auto_deref_stability( + cx, + cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)), + precedence, + ) + .position_for_arg() + } } - } - }) + }) }, ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess(name.name)), ExprKind::Unary(UnOp::Deref, child) if child.hir_id == e.hir_id => Some(Position::Deref), diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs index da111e7378ea..512872cedc1e 100644 --- a/src/tools/clippy/clippy_lints/src/doc.rs +++ b/src/tools/clippy/clippy_lints/src/doc.rs @@ -828,7 +828,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> { // check for `unwrap` if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { - let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); + let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs(); if is_type_diagnostic_item(self.cx, receiver_ty, sym::Option) || is_type_diagnostic_item(self.cx, receiver_ty, sym::Result) { diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs index 4e3ae4c96141..e70df3f53c75 100644 --- a/src/tools/clippy/clippy_lints/src/entry.rs +++ b/src/tools/clippy/clippy_lints/src/entry.rs @@ -245,8 +245,8 @@ fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Optio match expr.kind { ExprKind::MethodCall( _, + map, [ - map, Expr { kind: ExprKind::AddrOf(_, _, key), span: key_span, @@ -280,7 +280,7 @@ struct InsertExpr<'tcx> { value: &'tcx Expr<'tcx>, } fn try_parse_insert<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option> { - if let ExprKind::MethodCall(_, [map, key, value], _) = expr.kind { + if let ExprKind::MethodCall(_, map, [key, value], _) = expr.kind { let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?; if match_def_path(cx, id, &paths::BTREEMAP_INSERT) || match_def_path(cx, id, &paths::HASHMAP_INSERT) { Some(InsertExpr { map, key, value }) diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index 4f9ff97f1fd1..1c0a93c71fde 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -106,7 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { if !is_adjusted(cx, &body.value); if let ExprKind::Call(callee, args) = body.value.kind; if let ExprKind::Path(_) = callee.kind; - if check_inputs(cx, body.params, args); + if check_inputs(cx, body.params, None, args); let callee_ty = cx.typeck_results().expr_ty_adjusted(callee); let call_ty = cx.typeck_results().type_dependent_def_id(body.value.hir_id) .map_or(callee_ty, |id| cx.tcx.type_of(id)); @@ -146,8 +146,8 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { if_chain!( if !is_adjusted(cx, &body.value); - if let ExprKind::MethodCall(path, args, _) = body.value.kind; - if check_inputs(cx, body.params, args); + if let ExprKind::MethodCall(path, receiver, args, _) = body.value.kind; + if check_inputs(cx, body.params, Some(receiver), args); let method_def_id = cx.typeck_results().type_dependent_def_id(body.value.hir_id).unwrap(); let substs = cx.typeck_results().node_substs(body.value.hir_id); let call_ty = cx.tcx.bound_type_of(method_def_id).subst(cx.tcx, substs); @@ -167,12 +167,17 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { } } -fn check_inputs(cx: &LateContext<'_>, params: &[Param<'_>], call_args: &[Expr<'_>]) -> bool { - if params.len() != call_args.len() { +fn check_inputs( + cx: &LateContext<'_>, + params: &[Param<'_>], + receiver: Option<&Expr<'_>>, + call_args: &[Expr<'_>], +) -> bool { + if receiver.map_or(params.len() != call_args.len(), |_| params.len() != call_args.len() + 1) { return false; } let binding_modes = cx.typeck_results().pat_binding_modes(); - std::iter::zip(params, call_args).all(|(param, arg)| { + let check_inputs = |param: &Param<'_>, arg| { match param.pat.kind { PatKind::Binding(_, id, ..) if path_to_local_id(arg, id) => {}, _ => return false, @@ -200,7 +205,13 @@ fn check_inputs(cx: &LateContext<'_>, params: &[Param<'_>], call_args: &[Expr<'_ }, _ => false, } - }) + }; + if let Some(receiver) = receiver { + std::iter::zip(params, std::iter::once(receiver).chain(call_args.iter())) + .all(|(param, arg)| check_inputs(param, arg)) + } else { + std::iter::zip(params, call_args).all(|(param, arg)| check_inputs(param, arg)) + } } fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tcx>) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs index 5bf4313b41a4..9c76f63f5f75 100644 --- a/src/tools/clippy/clippy_lints/src/explicit_write.rs +++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs @@ -45,10 +45,10 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { // match call to unwrap - if let ExprKind::MethodCall(unwrap_fun, [write_call], _) = expr.kind; + if let ExprKind::MethodCall(unwrap_fun, write_call, [], _) = expr.kind; if unwrap_fun.ident.name == sym::unwrap; // match call to write_fmt - if let ExprKind::MethodCall(write_fun, [write_recv, write_arg], _) = look_in_block(cx, &write_call.kind); + if let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = look_in_block(cx, &write_call.kind); if write_fun.ident.name == sym!(write_fmt); // match calls to std::io::stdout() / std::io::stderr () if let Some(dest_name) = if match_function_call(cx, write_recv, &paths::STDOUT).is_some() { diff --git a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs index b88e53aeca69..790eea63f58c 100644 --- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs +++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs @@ -84,7 +84,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h // check for `unwrap` if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { - let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); + let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs(); if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option) || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result) { diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs index bb50e8fcabbb..728db41d6004 100644 --- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs @@ -164,15 +164,15 @@ fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>) -> Su suggestion.maybe_par() } -fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { - if let Some(method) = get_specialized_log_method(cx, &args[1]) { +fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) { + if let Some(method) = get_specialized_log_method(cx, &args[0]) { span_lint_and_sugg( cx, SUBOPTIMAL_FLOPS, expr.span, "logarithm for bases 2, 10 and e can be computed more accurately", "consider using", - format!("{}.{}()", Sugg::hir(cx, &args[0], "..").maybe_par(), method), + format!("{}.{}()", Sugg::hir(cx, receiver, "..").maybe_par(), method), Applicability::MachineApplicable, ); } @@ -180,14 +180,14 @@ fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { // TODO: Lint expressions of the form `(x + y).ln()` where y > 1 and // suggest usage of `(x + (y - 1)).ln_1p()` instead -fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { +fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) { if let ExprKind::Binary( Spanned { node: BinOpKind::Add, .. }, lhs, rhs, - ) = &args[0].kind + ) = receiver.kind { let recv = match ( constant(cx, cx.typeck_results(), lhs), @@ -235,9 +235,9 @@ fn get_integer_from_float_constant(value: &Constant) -> Option { } } -fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { +fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) { // Check receiver - if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) { + if let Some((value, _)) = constant(cx, cx.typeck_results(), receiver) { let method = if F32(f32_consts::E) == value || F64(f64_consts::E) == value { "exp" } else if F32(2.0) == value || F64(2.0) == value { @@ -252,24 +252,24 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { expr.span, "exponent for bases 2 and e can be computed more accurately", "consider using", - format!("{}.{}()", prepare_receiver_sugg(cx, &args[1]), method), + format!("{}.{}()", prepare_receiver_sugg(cx, &args[0]), method), Applicability::MachineApplicable, ); } // Check argument - if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[1]) { + if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) { let (lint, help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value { ( SUBOPTIMAL_FLOPS, "square-root of a number can be computed more efficiently and accurately", - format!("{}.sqrt()", Sugg::hir(cx, &args[0], "..").maybe_par()), + format!("{}.sqrt()", Sugg::hir(cx, receiver, "..").maybe_par()), ) } else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value { ( IMPRECISE_FLOPS, "cube-root of a number can be computed more accurately", - format!("{}.cbrt()", Sugg::hir(cx, &args[0], "..").maybe_par()), + format!("{}.cbrt()", Sugg::hir(cx, receiver, "..").maybe_par()), ) } else if let Some(exponent) = get_integer_from_float_constant(&value) { ( @@ -277,7 +277,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { "exponentiation with integer powers can be computed more efficiently", format!( "{}.powi({})", - Sugg::hir(cx, &args[0], "..").maybe_par(), + Sugg::hir(cx, receiver, "..").maybe_par(), numeric_literal::format(&exponent.to_string(), None, false) ), ) @@ -297,13 +297,14 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { } } -fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { - if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[1]) { +fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) { + if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) { if value == Int(2) { if let Some(parent) = get_parent_expr(cx, expr) { if let Some(grandparent) = get_parent_expr(cx, parent) { - if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, args, _) = grandparent.kind { - if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() { + if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = grandparent.kind + { + if method_name.as_str() == "sqrt" && detect_hypot(cx, receiver).is_some() { return; } } @@ -327,8 +328,8 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { "consider using", format!( "{}.mul_add({}, {})", - Sugg::hir(cx, &args[0], "..").maybe_par(), - Sugg::hir(cx, &args[0], ".."), + Sugg::hir(cx, receiver, "..").maybe_par(), + Sugg::hir(cx, receiver, ".."), Sugg::hir(cx, other_addend, ".."), ), Applicability::MachineApplicable, @@ -339,14 +340,14 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { } } -fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option { +fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option { if let ExprKind::Binary( Spanned { node: BinOpKind::Add, .. }, add_lhs, add_rhs, - ) = args[0].kind + ) = receiver.kind { // check if expression of the form x * x + y * y if_chain! { @@ -363,12 +364,12 @@ fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option { if_chain! { if let ExprKind::MethodCall( PathSegment { ident: lmethod_name, .. }, - [largs_0, largs_1, ..], + largs_0, [largs_1, ..], _ ) = &add_lhs.kind; if let ExprKind::MethodCall( PathSegment { ident: rmethod_name, .. }, - [rargs_0, rargs_1, ..], + rargs_0, [rargs_1, ..], _ ) = &add_rhs.kind; if lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi"; @@ -384,8 +385,8 @@ fn detect_hypot(cx: &LateContext<'_>, args: &[Expr<'_>]) -> Option { None } -fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { - if let Some(message) = detect_hypot(cx, args) { +fn check_hypot(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) { + if let Some(message) = detect_hypot(cx, receiver) { span_lint_and_sugg( cx, IMPRECISE_FLOPS, @@ -406,7 +407,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) { if cx.typeck_results().expr_ty(lhs).is_floating_point(); if let Some((value, _)) = constant(cx, cx.typeck_results(), rhs); if F32(1.0) == value || F64(1.0) == value; - if let ExprKind::MethodCall(path, [self_arg, ..], _) = &lhs.kind; + if let ExprKind::MethodCall(path, self_arg, ..) = &lhs.kind; if cx.typeck_results().expr_ty(self_arg).is_floating_point(); if path.ident.name.as_str() == "exp"; then { @@ -450,8 +451,8 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) { ) = &expr.kind { if let Some(parent) = get_parent_expr(cx, expr) { - if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, args, _) = parent.kind { - if method_name.as_str() == "sqrt" && detect_hypot(cx, args).is_some() { + if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = parent.kind { + if method_name.as_str() == "sqrt" && detect_hypot(cx, receiver).is_some() { return; } } @@ -586,14 +587,14 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) { fn are_same_base_logs(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool { if_chain! { - if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, args_a, _) = expr_a.kind; - if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, args_b, _) = expr_b.kind; + if let ExprKind::MethodCall(PathSegment { ident: method_name_a, .. }, _, args_a, _) = expr_a.kind; + if let ExprKind::MethodCall(PathSegment { ident: method_name_b, .. }, _, args_b, _) = expr_b.kind; then { return method_name_a.as_str() == method_name_b.as_str() && args_a.len() == args_b.len() && ( ["ln", "log2", "log10"].contains(&method_name_a.as_str()) || - method_name_a.as_str() == "log" && args_a.len() == 2 && eq_expr_value(cx, &args_a[1], &args_b[1]) + method_name_a.as_str() == "log" && args_a.len() == 1 && eq_expr_value(cx, &args_a[0], &args_b[0]) ); } } @@ -612,8 +613,8 @@ fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) { rhs, ) = &expr.kind; if are_same_base_logs(cx, lhs, rhs); - if let ExprKind::MethodCall(_, [largs_self, ..], _) = &lhs.kind; - if let ExprKind::MethodCall(_, [rargs_self, ..], _) = &rhs.kind; + if let ExprKind::MethodCall(_, largs_self, ..) = &lhs.kind; + if let ExprKind::MethodCall(_, rargs_self, ..) = &rhs.kind; then { span_lint_and_sugg( cx, @@ -711,16 +712,16 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic { return; } - if let ExprKind::MethodCall(path, args, _) = &expr.kind { - let recv_ty = cx.typeck_results().expr_ty(&args[0]); + if let ExprKind::MethodCall(path, receiver, args, _) = &expr.kind { + let recv_ty = cx.typeck_results().expr_ty(receiver); if recv_ty.is_floating_point() { match path.ident.name.as_str() { - "ln" => check_ln1p(cx, expr, args), - "log" => check_log_base(cx, expr, args), - "powf" => check_powf(cx, expr, args), - "powi" => check_powi(cx, expr, args), - "sqrt" => check_hypot(cx, expr, args), + "ln" => check_ln1p(cx, expr, receiver), + "log" => check_log_base(cx, expr, receiver, args), + "powf" => check_powf(cx, expr, receiver, args), + "powi" => check_powi(cx, expr, receiver, args), + "sqrt" => check_hypot(cx, expr, receiver), _ => {}, } } diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs index 9fb9fd99748b..2a55c48cf773 100644 --- a/src/tools/clippy/clippy_lints/src/format_args.rs +++ b/src/tools/clippy/clippy_lints/src/format_args.rs @@ -99,7 +99,12 @@ fn outermost_expn_data(expn_data: ExpnData) -> ExpnData { } } -fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symbol, arg: &Expr<'_>) { +fn check_format_in_format_args( + cx: &LateContext<'_>, + call_site: Span, + name: Symbol, + arg: &Expr<'_>, +) { let expn_data = arg.span.ctxt().outer_expn_data(); if expn_data.call_site.from_expansion() { return; @@ -126,7 +131,7 @@ fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symb fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Expr<'_>) { if_chain! { if !value.span.from_expansion(); - if let ExprKind::MethodCall(_, [receiver], _) = value.kind; + if let ExprKind::MethodCall(_, receiver, [], _) = value.kind; if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id); if is_diag_trait_item(cx, method_def_id, sym::ToString); let receiver_ty = cx.typeck_results().expr_ty(receiver); @@ -177,10 +182,7 @@ fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Ex // Returns true if `hir_id` is referred to by multiple format params fn is_aliased(args: &FormatArgsExpn<'_>, hir_id: HirId) -> bool { - args.params() - .filter(|param| param.value.hir_id == hir_id) - .at_most_one() - .is_err() + args.params().filter(|param| param.value.hir_id == hir_id).at_most_one().is_err() } fn count_needed_derefs<'tcx, I>(mut ty: Ty<'tcx>, mut iter: I) -> (usize, Ty<'tcx>) @@ -190,11 +192,7 @@ where let mut n_total = 0; let mut n_needed = 0; loop { - if let Some(Adjustment { - kind: Adjust::Deref(overloaded_deref), - target, - }) = iter.next() - { + if let Some(Adjustment { kind: Adjust::Deref(overloaded_deref), target }) = iter.next() { n_total += 1; if overloaded_deref.is_some() { n_needed = n_total; diff --git a/src/tools/clippy/clippy_lints/src/format_impl.rs b/src/tools/clippy/clippy_lints/src/format_impl.rs index d8bc0bf08f2b..b628fd9f7581 100644 --- a/src/tools/clippy/clippy_lints/src/format_impl.rs +++ b/src/tools/clippy/clippy_lints/src/format_impl.rs @@ -139,7 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatImpl { fn check_to_string_in_display(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { // Get the hir_id of the object we are calling the method on - if let ExprKind::MethodCall(path, [ref self_arg, ..], _) = expr.kind; + if let ExprKind::MethodCall(path, self_arg, ..) = expr.kind; // Is the method to_string() ? if path.ident.name == sym::to_string; // Is the method a part of the ToString trait? (i.e. not to_string() implemented diff --git a/src/tools/clippy/clippy_lints/src/format_push_string.rs b/src/tools/clippy/clippy_lints/src/format_push_string.rs index ebf5ab086dce..9b9f1872bfc1 100644 --- a/src/tools/clippy/clippy_lints/src/format_push_string.rs +++ b/src/tools/clippy/clippy_lints/src/format_push_string.rs @@ -54,7 +54,7 @@ fn is_format(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { impl<'tcx> LateLintPass<'tcx> for FormatPushString { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { let arg = match expr.kind { - ExprKind::MethodCall(_, [_, arg], _) => { + ExprKind::MethodCall(_, _, [arg], _) => { if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) && match_def_path(cx, fn_def_id, &paths::PUSH_STR) { arg diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index 6672a6cb0b58..a17b23f5edc8 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -212,7 +212,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> { return; } match expr.kind { - Call(_, args) | MethodCall(_, args, _) => { + Call(_, args) => { let mut tys = DefIdSet::default(); for arg in args { if self.cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id()) @@ -230,6 +230,24 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> { tys.clear(); } }, + MethodCall(_, receiver, args, _) => { + let mut tys = DefIdSet::default(); + for arg in std::iter::once(receiver).chain(args.iter()) { + if self.cx.tcx.has_typeck_results(arg.hir_id.owner.to_def_id()) + && is_mutable_ty( + self.cx, + self.cx.tcx.typeck(arg.hir_id.owner).expr_ty(arg), + arg.span, + &mut tys, + ) + && is_mutated_static(arg) + { + self.mutates_static = true; + return; + } + tys.clear(); + } + }, Assign(target, ..) | AssignOp(_, target, _) | AddrOf(_, hir::Mutability::Mut, target) => { self.mutates_static |= is_mutated_static(target); }, diff --git a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs index 565a1c871d75..3bbfa52e8103 100644 --- a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs +++ b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs @@ -88,11 +88,12 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> { } } }, - hir::ExprKind::MethodCall(_, args, _) => { + hir::ExprKind::MethodCall(_, receiver, args, _) => { let def_id = self.typeck_results.type_dependent_def_id(expr.hir_id).unwrap(); let base_type = self.cx.tcx.type_of(def_id); if type_is_unsafe_function(self.cx, base_type) { + self.check_arg(receiver); for arg in args { self.check_arg(arg); } diff --git a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs index 4d703d691acc..9ea8c494cfcd 100644 --- a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs +++ b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs @@ -129,7 +129,7 @@ impl<'tcx, 'l> ArmVisitor<'tcx, 'l> { fn is_mutex_lock_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { if_chain! { - if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind; + if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind; if path.ident.as_str() == "lock"; let ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); if is_type_diagnostic_item(cx, ty, sym::Mutex); diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs index 01c7eef4e04d..fca3cb46a2e9 100644 --- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs +++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs @@ -123,43 +123,43 @@ use self::Heuristic::{All, Always, Any, First}; /// is an upper bound, e.g., some methods can return a possibly /// infinite iterator at worst, e.g., `take_while`. const HEURISTICS: [(&str, usize, Heuristic, Finiteness); 19] = [ - ("zip", 2, All, Infinite), - ("chain", 2, Any, Infinite), - ("cycle", 1, Always, Infinite), - ("map", 2, First, Infinite), - ("by_ref", 1, First, Infinite), - ("cloned", 1, First, Infinite), - ("rev", 1, First, Infinite), - ("inspect", 1, First, Infinite), - ("enumerate", 1, First, Infinite), - ("peekable", 2, First, Infinite), - ("fuse", 1, First, Infinite), - ("skip", 2, First, Infinite), - ("skip_while", 1, First, Infinite), - ("filter", 2, First, Infinite), - ("filter_map", 2, First, Infinite), - ("flat_map", 2, First, Infinite), - ("unzip", 1, First, Infinite), - ("take_while", 2, First, MaybeInfinite), - ("scan", 3, First, MaybeInfinite), + ("zip", 1, All, Infinite), + ("chain", 1, Any, Infinite), + ("cycle", 0, Always, Infinite), + ("map", 1, First, Infinite), + ("by_ref", 0, First, Infinite), + ("cloned", 0, First, Infinite), + ("rev", 0, First, Infinite), + ("inspect", 0, First, Infinite), + ("enumerate", 0, First, Infinite), + ("peekable", 1, First, Infinite), + ("fuse", 0, First, Infinite), + ("skip", 1, First, Infinite), + ("skip_while", 0, First, Infinite), + ("filter", 1, First, Infinite), + ("filter_map", 1, First, Infinite), + ("flat_map", 1, First, Infinite), + ("unzip", 0, First, Infinite), + ("take_while", 1, First, MaybeInfinite), + ("scan", 2, First, MaybeInfinite), ]; fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { match expr.kind { - ExprKind::MethodCall(method, args, _) => { + ExprKind::MethodCall(method, receiver, args, _) => { for &(name, len, heuristic, cap) in &HEURISTICS { if method.ident.name.as_str() == name && args.len() == len { return (match heuristic { Always => Infinite, - First => is_infinite(cx, &args[0]), - Any => is_infinite(cx, &args[0]).or(is_infinite(cx, &args[1])), - All => is_infinite(cx, &args[0]).and(is_infinite(cx, &args[1])), + First => is_infinite(cx, receiver), + Any => is_infinite(cx, receiver).or(is_infinite(cx, &args[0])), + All => is_infinite(cx, receiver).and(is_infinite(cx, &args[0])), }) .and(cap); } } - if method.ident.name == sym!(flat_map) && args.len() == 2 { - if let ExprKind::Closure(&Closure { body, .. }) = args[1].kind { + if method.ident.name == sym!(flat_map) && args.len() == 1 { + if let ExprKind::Closure(&Closure { body, .. }) = args[0].kind { let body = cx.tcx.hir().body(body); return is_infinite(cx, &body.value); } @@ -179,29 +179,29 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { /// the names and argument lengths of methods that *may* exhaust their /// iterators const POSSIBLY_COMPLETING_METHODS: [(&str, usize); 6] = [ - ("find", 2), - ("rfind", 2), - ("position", 2), - ("rposition", 2), - ("any", 2), - ("all", 2), + ("find", 1), + ("rfind", 1), + ("position", 1), + ("rposition", 1), + ("any", 1), + ("all", 1), ]; /// the names and argument lengths of methods that *always* exhaust /// their iterators const COMPLETING_METHODS: [(&str, usize); 12] = [ - ("count", 1), - ("fold", 3), - ("for_each", 2), - ("partition", 2), - ("max", 1), - ("max_by", 2), - ("max_by_key", 2), - ("min", 1), - ("min_by", 2), - ("min_by_key", 2), - ("sum", 1), - ("product", 1), + ("count", 0), + ("fold", 2), + ("for_each", 1), + ("partition", 1), + ("max", 0), + ("max_by", 1), + ("max_by_key", 1), + ("min", 0), + ("min_by", 1), + ("min_by_key", 1), + ("sum", 0), + ("product", 0), ]; /// the paths of types that are known to be infinitely allocating @@ -218,26 +218,26 @@ const INFINITE_COLLECTORS: &[Symbol] = &[ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { match expr.kind { - ExprKind::MethodCall(method, args, _) => { + ExprKind::MethodCall(method, receiver, args, _) => { for &(name, len) in &COMPLETING_METHODS { if method.ident.name.as_str() == name && args.len() == len { - return is_infinite(cx, &args[0]); + return is_infinite(cx, receiver); } } for &(name, len) in &POSSIBLY_COMPLETING_METHODS { if method.ident.name.as_str() == name && args.len() == len { - return MaybeInfinite.and(is_infinite(cx, &args[0])); + return MaybeInfinite.and(is_infinite(cx, receiver)); } } - if method.ident.name == sym!(last) && args.len() == 1 { + if method.ident.name == sym!(last) { let not_double_ended = cx .tcx .get_diagnostic_item(sym::DoubleEndedIterator) .map_or(false, |id| { - !implements_trait(cx, cx.typeck_results().expr_ty(&args[0]), id, &[]) + !implements_trait(cx, cx.typeck_results().expr_ty(receiver), id, &[]) }); if not_double_ended { - return is_infinite(cx, &args[0]); + return is_infinite(cx, receiver); } } else if method.ident.name == sym!(collect) { let ty = cx.typeck_results().expr_ty(expr); @@ -245,7 +245,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { .iter() .any(|diag_item| is_type_diagnostic_item(cx, ty, *diag_item)) { - return is_infinite(cx, &args[0]); + return is_infinite(cx, receiver); } } }, diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 246f5aad8fba..25f366bfe6a8 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -370,7 +370,7 @@ fn check_for_is_empty<'tcx>( } fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) { - if let (&ExprKind::MethodCall(method_path, args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) { + if let (&ExprKind::MethodCall(method_path, receiver, ..), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) { // check if we are in an is_empty() method if let Some(name) = get_item_name(cx, method) { if name.as_str() == "is_empty" { @@ -378,7 +378,7 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_> } } - check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to); + check_len(cx, span, method_path.ident.name, receiver, &lit.node, op, compare_to); } else { check_empty_expr(cx, span, method, lit, op); } @@ -388,7 +388,7 @@ fn check_len( cx: &LateContext<'_>, span: Span, method_name: Symbol, - args: &[Expr<'_>], + receiver: &Expr<'_>, lit: &LitKind, op: &str, compare_to: u32, @@ -399,7 +399,7 @@ fn check_len( return; } - if method_name == sym::len && args.len() == 1 && has_is_empty(cx, &args[0]) { + if method_name == sym::len && has_is_empty(cx, receiver) { let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, @@ -410,7 +410,7 @@ fn check_len( format!( "{}{}.is_empty()", op, - snippet_with_applicability(cx, args[0].span, "_", &mut applicability) + snippet_with_applicability(cx, receiver.span, "_", &mut applicability) ), applicability, ); diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs index a65df48e413e..3fc569af89ec 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs @@ -119,7 +119,7 @@ fn build_manual_memcpy_suggestion<'tcx>( let print_limit = |end: &Expr<'_>, end_str: &str, base: &Expr<'_>, sugg: MinifyingSugg<'static>| { if_chain! { - if let ExprKind::MethodCall(method, [recv], _) = end.kind; + if let ExprKind::MethodCall(method, recv, [], _) = end.kind; if method.ident.name == sym::len; if path_to_local(recv) == path_to_local(base); then { @@ -341,7 +341,7 @@ fn get_slice_like_element_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Opti fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> { if_chain! { - if let ExprKind::MethodCall(method, [arg], _) = expr.kind; + if let ExprKind::MethodCall(method, arg, [], _) = expr.kind; if method.ident.name == sym::clone; then { arg } else { expr } } diff --git a/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs b/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs index 0696afa39225..8412875b11b7 100644 --- a/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/missing_spin_loop.rs @@ -33,7 +33,7 @@ fn unpack_cond<'tcx>(cond: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> { pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &'tcx Expr<'_>) { if_chain! { if let ExprKind::Block(Block { stmts: [], expr: None, ..}, _) = body.kind; - if let ExprKind::MethodCall(method, [callee, ..], _) = unpack_cond(cond).kind; + if let ExprKind::MethodCall(method, callee, ..) = unpack_cond(cond).kind; if [sym::load, sym::compare_exchange, sym::compare_exchange_weak].contains(&method.ident.name); if let ty::Adt(def, _substs) = cx.typeck_results().expr_ty(callee).kind(); if cx.tcx.is_diagnostic_item(sym::AtomicBool, def.did()); diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs index ed270bd490d7..74f3bda9f43e 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mod.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs @@ -742,7 +742,7 @@ fn check_for_loop<'tcx>( fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) { let mut next_loop_linted = false; // whether or not ITER_NEXT_LOOP lint was used - if let ExprKind::MethodCall(method, [self_arg], _) = arg.kind { + if let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind { let method_name = method.ident.as_str(); // check for looping over x.iter() or x.iter_mut(), could use &x or &mut x match method_name { diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs index 6d987f393fa5..6e6faa79adc9 100644 --- a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs @@ -25,11 +25,11 @@ pub(super) fn check<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) { } fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) { if_chain! { - if let ExprKind::MethodCall(method, args, _) = expr.kind; - if let ExprKind::MethodCall(chain_method, _, _) = args[0].kind; - if chain_method.ident.name == sym!(collect) && is_trait_method(cx, &args[0], sym::Iterator); + if let ExprKind::MethodCall(method, receiver, args, _) = expr.kind; + if let ExprKind::MethodCall(chain_method, ..) = receiver.kind; + if chain_method.ident.name == sym!(collect) && is_trait_method(cx, receiver, sym::Iterator); then { - let ty = cx.typeck_results().expr_ty(&args[0]); + let ty = cx.typeck_results().expr_ty(receiver); let mut applicability = Applicability::MaybeIncorrect; let is_empty_sugg = "next().is_none()".to_string(); let method_name = method.ident.name.as_str(); @@ -41,7 +41,7 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont "len" => "count()".to_string(), "is_empty" => is_empty_sugg, "contains" => { - let contains_arg = snippet_with_applicability(cx, args[1].span, "??", &mut applicability); + let contains_arg = snippet_with_applicability(cx, args[0].span, "??", &mut applicability); let (arg, pred) = contains_arg .strip_prefix('&') .map_or(("&x", &*contains_arg), |s| ("x", s)); @@ -80,7 +80,7 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo if let StmtKind::Local(local) = stmt.kind; if let PatKind::Binding(_, id, ..) = local.pat.kind; if let Some(init_expr) = local.init; - if let ExprKind::MethodCall(method_name, &[ref iter_source], ..) = init_expr.kind; + if let ExprKind::MethodCall(method_name, iter_source, [], ..) = init_expr.kind; if method_name.ident.name == sym!(collect) && is_trait_method(cx, init_expr, sym::Iterator); let ty = cx.typeck_results().expr_ty(init_expr); if is_type_diagnostic_item(cx, ty, sym::Vec) || @@ -203,7 +203,7 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { // Check function calls on our collection - if let ExprKind::MethodCall(method_name, [recv, args @ ..], _) = &expr.kind { + if let ExprKind::MethodCall(method_name, recv, [args @ ..], _) = &expr.kind { if method_name.ident.name == sym!(collect) && is_trait_method(self.cx, expr, sym::Iterator) { self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(recv)); self.visit_expr(recv); diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs index 7ca4a7c4ebfc..ffcf83e4605e 100644 --- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs @@ -188,7 +188,7 @@ pub(super) fn check<'tcx>( fn is_len_call(expr: &Expr<'_>, var: Symbol) -> bool { if_chain! { - if let ExprKind::MethodCall(method, [recv], _) = expr.kind; + if let ExprKind::MethodCall(method, recv, [], _) = expr.kind; if method.ident.name == sym::len; if let ExprKind::Path(QPath::Resolved(_, path)) = recv.kind; if path.segments.len() == 1; @@ -301,7 +301,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { if_chain! { // a range index op - if let ExprKind::MethodCall(meth, [args_0, args_1, ..], _) = &expr.kind; + if let ExprKind::MethodCall(meth, args_0, [args_1, ..], _) = &expr.kind; if (meth.ident.name == sym::index && match_trait_method(self.cx, expr, &paths::INDEX)) || (meth.ident.name == sym::index_mut && match_trait_method(self.cx, expr, &paths::INDEX_MUT)); if !self.check(args_1, args_0, expr); @@ -356,9 +356,12 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { self.visit_expr(expr); } }, - ExprKind::MethodCall(_, args, _) => { + ExprKind::MethodCall(_, receiver, args, _) => { let def_id = self.cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap(); - for (ty, expr) in iter::zip(self.cx.tcx.fn_sig(def_id).inputs().skip_binder(), args) { + for (ty, expr) in iter::zip( + self.cx.tcx.fn_sig(def_id).inputs().skip_binder(), + std::iter::once(receiver).chain(args.iter()), + ) { self.prefer_mutable = false; if let ty::Ref(_, _, mutbl) = *ty.kind() { if mutbl == Mutability::Mut { diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs index 5448360049d2..116e589cad6f 100644 --- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs @@ -120,8 +120,9 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult { | ExprKind::Repeat(e, _) | ExprKind::DropTemps(e) => never_loop_expr(e, main_loop_id), ExprKind::Let(let_expr) => never_loop_expr(let_expr.init, main_loop_id), - ExprKind::Array(es) | ExprKind::MethodCall(_, es, _) | ExprKind::Tup(es) => { - never_loop_expr_all(&mut es.iter(), main_loop_id) + ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(&mut es.iter(), main_loop_id), + ExprKind::MethodCall(_, receiver, es, _) => { + never_loop_expr_all(&mut std::iter::once(receiver).chain(es.iter()), main_loop_id) }, ExprKind::Struct(_, fields, base) => { let fields = never_loop_expr_all(&mut fields.iter().map(|f| f.expr), main_loop_id); diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs index 1439f1f4c75d..23f47091f77f 100644 --- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs +++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs @@ -180,10 +180,9 @@ fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(& if_chain! { // Extract method being called if let StmtKind::Semi(semi_stmt) = &stmt.kind; - if let ExprKind::MethodCall(path, args, _) = &semi_stmt.kind; + if let ExprKind::MethodCall(path, self_expr, args, _) = &semi_stmt.kind; // Figure out the parameters for the method call - if let Some(self_expr) = args.get(0); - if let Some(pushed_item) = args.get(1); + if let Some(pushed_item) = args.get(0); // Check that the method being called is push() on a Vec if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec); if path.ident.name.as_str() == "push"; diff --git a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs index a0bd7ad0ac64..f4b47808dfaa 100644 --- a/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs @@ -35,32 +35,29 @@ pub(super) fn check<'tcx>( ) => (arg, "&mut "), ExprKind::MethodCall( method, - [ - Expr { - kind: ExprKind::Array([arg]), - .. - }, - ], + Expr { + kind: ExprKind::Array([arg]), + .. + }, + [], _, ) if method.ident.name == rustc_span::sym::iter => (arg, "&"), ExprKind::MethodCall( method, - [ - Expr { - kind: ExprKind::Array([arg]), - .. - }, - ], + Expr { + kind: ExprKind::Array([arg]), + .. + }, + [], _, ) if method.ident.name.as_str() == "iter_mut" => (arg, "&mut "), ExprKind::MethodCall( method, - [ - Expr { - kind: ExprKind::Array([arg]), - .. - }, - ], + Expr { + kind: ExprKind::Array([arg]), + .. + }, + [], _, ) if method.ident.name == rustc_span::sym::into_iter => (arg, ""), // Only check for arrays edition 2021 or later, as this case will trigger a compiler error otherwise. diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs index ca617859db49..735d704a43ce 100644 --- a/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs @@ -11,7 +11,14 @@ use rustc_lint::LateContext; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) { let (init, has_trailing_exprs) = match (loop_block.stmts, loop_block.expr) { ([stmt, stmts @ ..], expr) => { - if let StmtKind::Local(&Local { init: Some(e), els: None, .. }) | StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind { + if let StmtKind::Local(&Local { + init: Some(e), + els: None, + .. + }) + | StmtKind::Semi(e) + | StmtKind::Expr(e) = stmt.kind + { (e, !stmts.is_empty() || expr.is_some()) } else { return; diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs index e9e215e662f1..2c54033f8597 100644 --- a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs @@ -23,7 +23,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let Res::Def(_, pat_did) = pat_path.res; if match_def_path(cx, pat_did, &paths::OPTION_SOME); // check for call to `Iterator::next` - if let ExprKind::MethodCall(method_name, [iter_expr], _) = let_expr.kind; + if let ExprKind::MethodCall(method_name, iter_expr, [], _) = let_expr.kind; if method_name.ident.name == sym::next; if is_trait_method(cx, let_expr, sym::Iterator); if let Some(iter_expr_struct) = try_parse_iter_expr(cx, iter_expr); diff --git a/src/tools/clippy/clippy_lints/src/manual_bits.rs b/src/tools/clippy/clippy_lints/src/manual_bits.rs index 940601a44fb0..6655c92b1da8 100644 --- a/src/tools/clippy/clippy_lints/src/manual_bits.rs +++ b/src/tools/clippy/clippy_lints/src/manual_bits.rs @@ -134,7 +134,7 @@ fn create_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, base_sugg: String) -> Stri fn is_ty_conversion(expr: &Expr<'_>) -> bool { if let ExprKind::Cast(..) = expr.kind { true - } else if let ExprKind::MethodCall(path, [_], _) = expr.kind + } else if let ExprKind::MethodCall(path, _, [], _) = expr.kind && path.ident.name == rustc_span::sym::try_into { // This is only called for `usize` which implements `TryInto`. Therefore, diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs index 42d2577cc316..f28c37d3dca7 100644 --- a/src/tools/clippy/clippy_lints/src/manual_retain.rs +++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs @@ -66,9 +66,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualRetain { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { if let Some(parent_expr) = get_parent_expr(cx, expr) && let Assign(left_expr, collect_expr, _) = &parent_expr.kind - && let hir::ExprKind::MethodCall(seg, _, _) = &collect_expr.kind + && let hir::ExprKind::MethodCall(seg, ..) = &collect_expr.kind && seg.args.is_none() - && let hir::ExprKind::MethodCall(_, [target_expr], _) = &collect_expr.kind + && let hir::ExprKind::MethodCall(_, target_expr, [], _) = &collect_expr.kind && let Some(collect_def_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id) && match_def_path(cx, collect_def_id, &paths::CORE_ITER_COLLECT) { check_into_iter(cx, parent_expr, left_expr, target_expr, self.msrv); @@ -87,10 +87,10 @@ fn check_into_iter( target_expr: &hir::Expr<'_>, msrv: Option, ) { - if let hir::ExprKind::MethodCall(_, [into_iter_expr, _], _) = &target_expr.kind + if let hir::ExprKind::MethodCall(_, into_iter_expr, [_], _) = &target_expr.kind && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id) && match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER) - && let hir::ExprKind::MethodCall(_, [struct_expr], _) = &into_iter_expr.kind + && let hir::ExprKind::MethodCall(_, struct_expr, [], _) = &into_iter_expr.kind && let Some(into_iter_def_id) = cx.typeck_results().type_dependent_def_id(into_iter_expr.hir_id) && match_def_path(cx, into_iter_def_id, &paths::CORE_ITER_INTO_ITER) && match_acceptable_type(cx, left_expr, msrv) @@ -106,14 +106,14 @@ fn check_iter( target_expr: &hir::Expr<'_>, msrv: Option, ) { - if let hir::ExprKind::MethodCall(_, [filter_expr], _) = &target_expr.kind + if let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind && let Some(copied_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id) && (match_def_path(cx, copied_def_id, &paths::CORE_ITER_COPIED) || match_def_path(cx, copied_def_id, &paths::CORE_ITER_CLONED)) - && let hir::ExprKind::MethodCall(_, [iter_expr, _], _) = &filter_expr.kind + && let hir::ExprKind::MethodCall(_, iter_expr, [_], _) = &filter_expr.kind && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id) && match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER) - && let hir::ExprKind::MethodCall(_, [struct_expr], _) = &iter_expr.kind + && let hir::ExprKind::MethodCall(_, struct_expr, [], _) = &iter_expr.kind && let Some(iter_expr_def_id) = cx.typeck_results().type_dependent_def_id(iter_expr.hir_id) && match_acceptable_def_path(cx, iter_expr_def_id) && match_acceptable_type(cx, left_expr, msrv) @@ -130,13 +130,13 @@ fn check_to_owned( msrv: Option, ) { if meets_msrv(msrv, msrvs::STRING_RETAIN) - && let hir::ExprKind::MethodCall(_, [filter_expr], _) = &target_expr.kind + && let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind && let Some(to_owned_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id) && match_def_path(cx, to_owned_def_id, &paths::TO_OWNED_METHOD) - && let hir::ExprKind::MethodCall(_, [chars_expr, _], _) = &filter_expr.kind + && let hir::ExprKind::MethodCall(_, chars_expr, [_], _) = &filter_expr.kind && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id) && match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER) - && let hir::ExprKind::MethodCall(_, [str_expr], _) = &chars_expr.kind + && let hir::ExprKind::MethodCall(_, str_expr, [], _) = &chars_expr.kind && let Some(chars_expr_def_id) = cx.typeck_results().type_dependent_def_id(chars_expr.hir_id) && match_def_path(cx, chars_expr_def_id, &paths::STR_CHARS) && let ty = cx.typeck_results().expr_ty(str_expr).peel_refs() @@ -147,7 +147,7 @@ fn check_to_owned( } fn suggest(cx: &LateContext<'_>, parent_expr: &hir::Expr<'_>, left_expr: &hir::Expr<'_>, filter_expr: &hir::Expr<'_>) { - if let hir::ExprKind::MethodCall(_, [_, closure], _) = filter_expr.kind + if let hir::ExprKind::MethodCall(_, _, [closure], _) = filter_expr.kind && let hir::ExprKind::Closure(&hir::Closure { body, ..}) = closure.kind && let filter_body = cx.tcx.hir().body(body) && let [filter_params] = filter_body.params diff --git a/src/tools/clippy/clippy_lints/src/manual_string_new.rs b/src/tools/clippy/clippy_lints/src/manual_string_new.rs index a90eaa8fdcbe..6acfb2ae3471 100644 --- a/src/tools/clippy/clippy_lints/src/manual_string_new.rs +++ b/src/tools/clippy/clippy_lints/src/manual_string_new.rs @@ -55,8 +55,8 @@ impl LateLintPass<'_> for ManualStringNew { ExprKind::Call(func, args) => { parse_call(cx, expr.span, func, args); }, - ExprKind::MethodCall(path_segment, args, _) => { - parse_method_call(cx, expr.span, path_segment, args); + ExprKind::MethodCall(path_segment, receiver, ..) => { + parse_method_call(cx, expr.span, path_segment, receiver); }, _ => (), } @@ -88,14 +88,9 @@ fn warn_then_suggest(cx: &LateContext<'_>, span: Span) { } /// Tries to parse an expression as a method call, emitting the warning if necessary. -fn parse_method_call(cx: &LateContext<'_>, span: Span, path_segment: &PathSegment<'_>, args: &[Expr<'_>]) { - if args.is_empty() { - // When parsing TryFrom::try_from(...).expect(...), we will have more than 1 arg. - return; - } - +fn parse_method_call(cx: &LateContext<'_>, span: Span, path_segment: &PathSegment<'_>, receiver: &Expr<'_>) { let ident = path_segment.ident.as_str(); - let method_arg_kind = &args[0].kind; + let method_arg_kind = &receiver.kind; if ["to_string", "to_owned", "into"].contains(&ident) && is_expr_kind_empty_str(method_arg_kind) { warn_then_suggest(cx, span); } else if let ExprKind::Call(func, args) = method_arg_kind { diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs index dfb3efc4e28b..7941c8c9c7e3 100644 --- a/src/tools/clippy/clippy_lints/src/manual_strip.rs +++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs @@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { if_chain! { if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr); - if let ExprKind::MethodCall(_, [target_arg, pattern], _) = cond.kind; + if let ExprKind::MethodCall(_, target_arg, [pattern], _) = cond.kind; if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id); if let ExprKind::Path(target_path) = &target_arg.kind; then { @@ -132,7 +132,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { // Returns `Some(arg)` if `expr` matches `arg.len()` and `None` otherwise. fn len_arg<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { if_chain! { - if let ExprKind::MethodCall(_, [arg], _) = expr.kind; + if let ExprKind::MethodCall(_, arg, [], _) = expr.kind; if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if match_def_path(cx, method_def_id, &paths::STR_LEN); then { diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs index 6db852c3ffe7..33d744815299 100644 --- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs +++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs @@ -200,8 +200,13 @@ fn suggestion_msg(function_type: &str, map_type: &str) -> String { ) } -fn lint_map_unit_fn(cx: &LateContext<'_>, stmt: &hir::Stmt<'_>, expr: &hir::Expr<'_>, map_args: &[hir::Expr<'_>]) { - let var_arg = &map_args[0]; +fn lint_map_unit_fn( + cx: &LateContext<'_>, + stmt: &hir::Stmt<'_>, + expr: &hir::Expr<'_>, + map_args: (&hir::Expr<'_>, &[hir::Expr<'_>]), +) { + let var_arg = &map_args.0; let (map_type, variant, lint) = if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::Option) { ("Option", "Some", OPTION_MAP_UNIT_FN) @@ -210,7 +215,7 @@ fn lint_map_unit_fn(cx: &LateContext<'_>, stmt: &hir::Stmt<'_>, expr: &hir::Expr } else { return; }; - let fn_arg = &map_args[1]; + let fn_arg = &map_args.1[0]; if is_unit_function(cx, fn_arg) { let mut applicability = Applicability::MachineApplicable; diff --git a/src/tools/clippy/clippy_lints/src/match_result_ok.rs b/src/tools/clippy/clippy_lints/src/match_result_ok.rs index 3349b85f1347..8588ab1ed8db 100644 --- a/src/tools/clippy/clippy_lints/src/match_result_ok.rs +++ b/src/tools/clippy/clippy_lints/src/match_result_ok.rs @@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchResultOk { }; if_chain! { - if let ExprKind::MethodCall(ok_path, [ref result_types_0, ..], _) = let_expr.kind; //check is expr.ok() has type Result.ok(, _) + if let ExprKind::MethodCall(ok_path, result_types_0, ..) = let_expr.kind; //check is expr.ok() has type Result.ok(, _) if let PatKind::TupleStruct(QPath::Resolved(_, x), y, _) = let_pat.kind; //get operation if method_chain_args(let_expr, &["ok"]).is_some(); //test to see if using ok() method use std::marker::Sized; if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(result_types_0), sym::Result); diff --git a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs index fa3b8d1fceaa..1e80b6cf2d83 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs @@ -48,7 +48,7 @@ struct MatchExprVisitor<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for MatchExprVisitor<'a, 'tcx> { fn visit_expr(&mut self, ex: &'tcx Expr<'_>) { match ex.kind { - ExprKind::MethodCall(segment, [receiver], _) if self.case_altered(segment.ident.as_str(), receiver) => {}, + ExprKind::MethodCall(segment, receiver, [], _) if self.case_altered(segment.ident.as_str(), receiver) => {}, _ => walk_expr(self, ex), } } diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs index 8499e050af24..f7443471e31d 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs @@ -120,7 +120,7 @@ fn find_sugg_for_if_let<'tcx>( // check that `while_let_on_iterator` lint does not trigger if_chain! { if keyword == "while"; - if let ExprKind::MethodCall(method_path, _, _) = let_expr.kind; + if let ExprKind::MethodCall(method_path, ..) = let_expr.kind; if method_path.ident.name == sym::next; if is_trait_method(cx, let_expr, sym::Iterator); then { diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index b0b15b3f54cd..86a9df034979 100644 --- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -291,7 +291,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> { self.is_chain_end = false; match ex.kind { - ExprKind::MethodCall(_, [ref expr, ..], _) => { + ExprKind::MethodCall(_, expr, ..) => { self.visit_expr(expr); } ExprKind::Binary(_, left, right) => { @@ -331,8 +331,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> { ExprKind::Index(..) | ExprKind::Ret(..) | ExprKind::Repeat(..) | - ExprKind::Yield(..) | - ExprKind::MethodCall(..) => walk_expr(self, ex), + ExprKind::Yield(..) => walk_expr(self, ex), ExprKind::AddrOf(_, _, _) | ExprKind::Block(_, _) | ExprKind::Break(_, _) | diff --git a/src/tools/clippy/clippy_lints/src/methods/bytecount.rs b/src/tools/clippy/clippy_lints/src/methods/bytecount.rs index 6a7c63d76f72..fef90f6eba49 100644 --- a/src/tools/clippy/clippy_lints/src/methods/bytecount.rs +++ b/src/tools/clippy/clippy_lints/src/methods/bytecount.rs @@ -42,11 +42,11 @@ pub(super) fn check<'tcx>( if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(needle).peel_refs().kind(); if !is_local_used(cx, needle, arg_id); then { - let haystack = if let ExprKind::MethodCall(path, args, _) = + let haystack = if let ExprKind::MethodCall(path, receiver, [], _) = filter_recv.kind { let p = path.ident.name; - if (p == sym::iter || p == sym!(iter_mut)) && args.len() == 1 { - &args[0] + if p == sym::iter || p == sym!(iter_mut) { + receiver } else { filter_recv } diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs b/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs index f7b79f0839ba..51aec21527a7 100644 --- a/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs +++ b/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs @@ -23,7 +23,7 @@ pub(super) fn check( if Some(id) == cx.tcx.lang_items().option_some_variant(); then { let mut applicability = Applicability::MachineApplicable; - let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0][0]).peel_refs(); + let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0].0).peel_refs(); if *self_ty.kind() != ty::Str { return false; @@ -37,7 +37,7 @@ pub(super) fn check( "like this", format!("{}{}.{}({})", if info.eq { "" } else { "!" }, - snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability), + snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability), suggest, snippet_with_applicability(cx, arg_char.span, "..", &mut applicability)), applicability, diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs index a7c0e43923e1..b85bfec2b12b 100644 --- a/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs @@ -30,7 +30,7 @@ pub(super) fn check<'tcx>( "like this", format!("{}{}.{}('{}')", if info.eq { "" } else { "!" }, - snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability), + snippet_with_applicability(cx, args[0].0.span, "..", &mut applicability), suggest, c.escape_default()), applicability, diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs index 60e1355f9b92..9ae6297ec2f6 100644 --- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs +++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs @@ -14,9 +14,15 @@ use super::CLONE_ON_COPY; /// Checks for the `CLONE_ON_COPY` lint. #[allow(clippy::too_many_lines)] -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, args: &[Expr<'_>]) { +pub(super) fn check( + cx: &LateContext<'_>, + expr: &Expr<'_>, + method_name: Symbol, + receiver: &Expr<'_>, + args: &[Expr<'_>], +) { let arg = match args { - [arg] if method_name == sym::clone => arg, + [] if method_name == sym::clone => receiver, _ => return, }; if cx @@ -81,7 +87,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, // &*x is a nop, &x.clone() is not ExprKind::AddrOf(..) => return, // (*x).func() is useless, x.clone().func() can work in case func borrows self - ExprKind::MethodCall(_, [self_arg, ..], _) + ExprKind::MethodCall(_, self_arg, ..) if expr.hir_id == self_arg.hir_id && ty != cx.typeck_results().expr_ty_adjusted(expr) => { return; @@ -91,7 +97,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, hir_callee.kind, ExprKind::Path(QPath::LangItem(rustc_hir::LangItem::TryTraitBranch, _, _)) ), - ExprKind::MethodCall(_, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true, + ExprKind::MethodCall(_, self_arg, ..) if expr.hir_id == self_arg.hir_id => true, ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar) | ExprKind::Field(..) | ExprKind::Index(..) => true, diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs index 6417bc813047..7098d564cfc8 100644 --- a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs @@ -10,11 +10,17 @@ use rustc_span::symbol::{sym, Symbol}; use super::CLONE_ON_REF_PTR; -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) { - if !(args.len() == 1 && method_name == sym::clone) { +pub(super) fn check( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + method_name: Symbol, + receiver: &hir::Expr<'_>, + args: &[hir::Expr<'_>], +) { + if !(args.is_empty() && method_name == sym::clone) { return; } - let arg = &args[0]; + let arg = receiver; let obj_ty = cx.typeck_results().expr_ty(arg).peel_refs(); if let ty::Adt(_, subst) = obj_ty.kind() { diff --git a/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs b/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs index 561033be5b6a..501646863fe1 100644 --- a/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs +++ b/src/tools/clippy/clippy_lints/src/methods/collapsible_str_replace.rs @@ -23,7 +23,7 @@ pub(super) fn check<'tcx>( // If the parent node's `to` argument is the same as the `to` argument // of the last replace call in the current chain, don't lint as it was already linted if let Some(parent) = get_parent_expr(cx, expr) - && let Some(("replace", [_, current_from, current_to], _)) = method_call(parent) + && let Some(("replace", _, [current_from, current_to], _)) = method_call(parent) && eq_expr_value(cx, to, current_to) && from_kind == cx.typeck_results().expr_ty(current_from).peel_refs().kind() { @@ -48,7 +48,7 @@ fn collect_replace_calls<'tcx>( let mut from_args = VecDeque::new(); let _: Option<()> = for_each_expr(expr, |e| { - if let Some(("replace", [_, from, to], _)) = method_call(e) { + if let Some(("replace", _, [from, to], _)) = method_call(e) { if eq_expr_value(cx, to_arg, to) && cx.typeck_results().expr_ty(from).peel_refs().is_char() { methods.push_front(e); from_args.push_front(from); @@ -78,7 +78,7 @@ fn check_consecutive_replace_calls<'tcx>( .collect(); let app = Applicability::MachineApplicable; let earliest_replace_call = replace_methods.methods.front().unwrap(); - if let Some((_, [..], span_lo)) = method_call(earliest_replace_call) { + if let Some((_, _, [..], span_lo)) = method_call(earliest_replace_call) { span_lint_and_sugg( cx, COLLAPSIBLE_STR_REPLACE, diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs index 6f2307d8f18f..bd846d71d466 100644 --- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs @@ -19,6 +19,7 @@ pub(super) fn check<'tcx>( expr: &hir::Expr<'_>, method_span: Span, name: &str, + receiver: &'tcx hir::Expr<'tcx>, args: &'tcx [hir::Expr<'tcx>], ) { // Strip `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or @@ -28,16 +29,13 @@ pub(super) fn check<'tcx>( loop { arg_root = match &arg_root.kind { hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => expr, - hir::ExprKind::MethodCall(method_name, call_args, _) => { - if call_args.len() == 1 - && (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref) - && { - let arg_type = cx.typeck_results().expr_ty(&call_args[0]); - let base_type = arg_type.peel_refs(); - *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym::String) - } - { - &call_args[0] + hir::ExprKind::MethodCall(method_name, receiver, [], ..) => { + if (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref) && { + let arg_type = cx.typeck_results().expr_ty(receiver); + let base_type = arg_type.peel_refs(); + *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym::String) + } { + receiver } else { break; } @@ -114,11 +112,11 @@ pub(super) fn check<'tcx>( } } - if args.len() != 2 || name != "expect" || !is_call(&args[1].kind) { + if args.len() != 1 || name != "expect" || !is_call(&args[0].kind) { return; } - let receiver_type = cx.typeck_results().expr_ty_adjusted(&args[0]); + let receiver_type = cx.typeck_results().expr_ty_adjusted(receiver); let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym::Option) { "||" } else if is_type_diagnostic_item(cx, receiver_type, sym::Result) { @@ -127,7 +125,7 @@ pub(super) fn check<'tcx>( return; }; - let arg_root = get_arg_root(cx, &args[1]); + let arg_root = get_arg_root(cx, &args[0]); let span_replace_word = method_span.with_hi(expr.span.hi()); diff --git a/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs b/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs index a15fe6094022..37b28463527c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs +++ b/src/tools/clippy/clippy_lints/src/methods/extend_with_drain.rs @@ -14,7 +14,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: if_chain! { if is_type_diagnostic_item(cx, ty, sym::Vec); //check source object - if let ExprKind::MethodCall(src_method, [drain_vec, drain_arg], _) = &arg.kind; + if let ExprKind::MethodCall(src_method, drain_vec, [drain_arg], _) = &arg.kind; if src_method.ident.as_str() == "drain"; let src_ty = cx.typeck_results().expr_ty(drain_vec); //check if actual src type is mutable for code suggestion diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs index 692e22a7c5cf..9dc839afc625 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs @@ -28,11 +28,11 @@ fn is_method<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy let closure_expr = peel_blocks(&body.value); let arg_id = body.params[0].pat.hir_id; match closure_expr.kind { - hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, args, _) => { + hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => { if_chain! { if ident.name == method_name; - if let hir::ExprKind::Path(path) = &args[0].kind; - if let Res::Local(ref local) = cx.qpath_res(path, args[0].hir_id); + if let hir::ExprKind::Path(path) = &receiver.kind; + if let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id); then { return arg_id == *local } @@ -106,7 +106,7 @@ pub(super) fn check<'tcx>( }; // closure ends with is_some() or is_ok() if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind; - if let ExprKind::MethodCall(path, [filter_arg], _) = filter_body.value.kind; + if let ExprKind::MethodCall(path, filter_arg, [], _) = filter_body.value.kind; if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).peel_refs().ty_adt_def(); if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did()) { Some(false) @@ -123,13 +123,13 @@ pub(super) fn check<'tcx>( if let [map_param] = map_body.params; if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind; // closure ends with expect() or unwrap() - if let ExprKind::MethodCall(seg, [map_arg, ..], _) = map_body.value.kind; + if let ExprKind::MethodCall(seg, map_arg, ..) = map_body.value.kind; if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or); // .filter(..).map(|y| f(y).copied().unwrap()) // ~~~~ let map_arg_peeled = match map_arg.kind { - ExprKind::MethodCall(method, [original_arg], _) if acceptable_methods(method) => { + ExprKind::MethodCall(method, original_arg, [], _) if acceptable_methods(method) => { original_arg }, _ => map_arg, diff --git a/src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs b/src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs index 23368238ef5c..02aada87202c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs +++ b/src/tools/clippy/clippy_lints/src/methods/get_last_with_len.rs @@ -22,7 +22,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: ) = arg.kind // LHS of subtraction is "x.len()" - && let ExprKind::MethodCall(lhs_path, [lhs_recv], _) = &lhs.kind + && let ExprKind::MethodCall(lhs_path, lhs_recv, [], _) = &lhs.kind && lhs_path.ident.name == sym::len // RHS of subtraction is 1 diff --git a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs index f52170df662c..e1c9b5248a8a 100644 --- a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs +++ b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs @@ -12,13 +12,19 @@ use rustc_span::symbol::{sym, Symbol}; use super::INEFFICIENT_TO_STRING; /// Checks for the `INEFFICIENT_TO_STRING` lint -pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) { +pub fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &hir::Expr<'_>, + method_name: Symbol, + receiver: &hir::Expr<'_>, + args: &[hir::Expr<'_>], +) { if_chain! { - if args.len() == 1 && method_name == sym::to_string; + if args.is_empty() && method_name == sym::to_string; if let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if match_def_path(cx, to_string_meth_did, &paths::TO_STRING_METHOD); if let Some(substs) = cx.typeck_results().node_substs_opt(expr.hir_id); - let arg_ty = cx.typeck_results().expr_ty_adjusted(&args[0]); + let arg_ty = cx.typeck_results().expr_ty_adjusted(receiver); let self_ty = substs.type_at(0); let (deref_self_ty, deref_count) = walk_ptrs_ty_depth(self_ty); if deref_count >= 1; @@ -35,7 +41,7 @@ pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, method_name: Sy self_ty, deref_self_ty )); let mut applicability = Applicability::MachineApplicable; - let arg_snippet = snippet_with_applicability(cx, args[0].span, "..", &mut applicability); + let arg_snippet = snippet_with_applicability(cx, receiver.span, "..", &mut applicability); diag.span_suggestion( expr.span, "try dereferencing the receiver", diff --git a/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs b/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs index da13b4ba37a5..11e76841e9f0 100644 --- a/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs +++ b/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs @@ -16,9 +16,9 @@ pub(super) fn check( expr: &hir::Expr<'_>, method_span: Span, method_name: Symbol, - args: &[hir::Expr<'_>], + receiver: &hir::Expr<'_>, ) { - let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0]); + let self_ty = cx.typeck_results().expr_ty_adjusted(receiver); if_chain! { if let ty::Ref(..) = self_ty.kind(); if method_name == sym::into_iter; diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs b/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs index 152072e09c77..a669cbbbcc60 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_with_drain.rs @@ -35,7 +35,7 @@ fn is_full_range(cx: &LateContext<'_>, container: &Expr<'_>, range: Range<'_>) - && range.end.map_or(true, |e| { if range.limits == RangeLimits::HalfOpen && let ExprKind::Path(QPath::Resolved(None, container_path)) = container.kind - && let ExprKind::MethodCall(name, [self_arg], _) = e.kind + && let ExprKind::MethodCall(name, self_arg, [], _) = e.kind && name.ident.name == sym::len && let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind { diff --git a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs index ffedda95ff8e..e04bb1c50792 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs @@ -48,7 +48,7 @@ pub(super) fn check<'tcx>( } } }, - hir::ExprKind::MethodCall(method, [obj], _) => if_chain! { + hir::ExprKind::MethodCall(method, obj, [], _) => if_chain! { if ident_eq(name, obj) && method.ident.name == sym::clone; if let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id); if let Some(trait_id) = cx.tcx.trait_of_item(fn_id); diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index a0d190a58aff..16fdd36c0260 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -3161,11 +3161,13 @@ impl_lint_pass!(Methods => [ ]); /// Extracts a method call name, args, and `Span` of the method name. -fn method_call<'tcx>(recv: &'tcx hir::Expr<'tcx>) -> Option<(&'tcx str, &'tcx [hir::Expr<'tcx>], Span)> { - if let ExprKind::MethodCall(path, args, _) = recv.kind { - if !args.iter().any(|e| e.span.from_expansion()) { +fn method_call<'tcx>( + recv: &'tcx hir::Expr<'tcx>, +) -> Option<(&'tcx str, &'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], Span)> { + if let ExprKind::MethodCall(path, receiver, args, _) = recv.kind { + if !args.iter().any(|e| e.span.from_expansion()) && !receiver.span.from_expansion() { let name = path.ident.name.as_str(); - return Some((name, args, path.ident.span)); + return Some((name, receiver, args, path.ident.span)); } } None @@ -3183,17 +3185,17 @@ impl<'tcx> LateLintPass<'tcx> for Methods { hir::ExprKind::Call(func, args) => { from_iter_instead_of_collect::check(cx, expr, args, func); }, - hir::ExprKind::MethodCall(method_call, args, _) => { + hir::ExprKind::MethodCall(method_call, receiver, args, _) => { let method_span = method_call.ident.span; - or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), args); - expect_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), args); - clone_on_copy::check(cx, expr, method_call.ident.name, args); - clone_on_ref_ptr::check(cx, expr, method_call.ident.name, args); - inefficient_to_string::check(cx, expr, method_call.ident.name, args); - single_char_add_str::check(cx, expr, args); - into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, args); - single_char_pattern::check(cx, expr, method_call.ident.name, args); - unnecessary_to_owned::check(cx, expr, method_call.ident.name, args, self.msrv); + or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args); + expect_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args); + clone_on_copy::check(cx, expr, method_call.ident.name, receiver, args); + clone_on_ref_ptr::check(cx, expr, method_call.ident.name, receiver, args); + inefficient_to_string::check(cx, expr, method_call.ident.name, receiver, args); + single_char_add_str::check(cx, expr, receiver, args); + into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, receiver); + single_char_pattern::check(cx, expr, method_call.ident.name, receiver, args); + unnecessary_to_owned::check(cx, expr, method_call.ident.name, receiver, args, self.msrv); }, hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => { let mut info = BinaryExprInfo { @@ -3379,7 +3381,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { impl Methods { #[allow(clippy::too_many_lines)] fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let Some((name, [recv, args @ ..], span)) = method_call(expr) { + if let Some((name, recv, [args @ ..], span)) = method_call(expr) { match (name, args) { ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => { zst_offset::check(cx, expr, recv); @@ -3399,13 +3401,13 @@ impl Methods { ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv), ("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, self.msrv), ("collect", []) => match method_call(recv) { - Some((name @ ("cloned" | "copied"), [recv2], _)) => { + Some((name @ ("cloned" | "copied"), recv2, [], _)) => { iter_cloned_collect::check(cx, name, expr, recv2); }, - Some(("map", [m_recv, m_arg], _)) => { + Some(("map", m_recv, [m_arg], _)) => { map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv); }, - Some(("take", [take_self_arg, take_arg], _)) => { + Some(("take", take_self_arg, [take_arg], _)) => { if meets_msrv(self.msrv, msrvs::STR_REPEAT) { manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg); } @@ -3413,26 +3415,26 @@ impl Methods { _ => {}, }, ("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) { - Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false), - Some((name2 @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => { + Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, true, false), + Some((name2 @ ("into_iter" | "iter" | "iter_mut"), recv2, [], _)) => { iter_count::check(cx, expr, recv2, name2); }, - Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg), - Some(("filter", [recv2, arg], _)) => bytecount::check(cx, expr, recv2, arg), - Some(("bytes", [recv2], _)) => bytes_count_to_len::check(cx, expr, recv, recv2), + Some(("map", _, [arg], _)) => suspicious_map::check(cx, expr, recv, arg), + Some(("filter", recv2, [arg], _)) => bytecount::check(cx, expr, recv2, arg), + Some(("bytes", recv2, [], _)) => bytes_count_to_len::check(cx, expr, recv, recv2), _ => {}, }, ("drain", [arg]) => { iter_with_drain::check(cx, expr, recv, span, arg); }, ("ends_with", [arg]) => { - if let ExprKind::MethodCall(_, _, span) = expr.kind { + if let ExprKind::MethodCall(.., span) = expr.kind { case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg); } }, ("expect", [_]) => match method_call(recv) { - Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv), - Some(("err", [recv], err_span)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span), + Some(("ok", recv, [], _)) => ok_expect::check(cx, expr, recv), + Some(("err", recv, [], err_span)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span), _ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests), }, ("expect_err", [_]) => expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests), @@ -3452,13 +3454,13 @@ impl Methods { flat_map_option::check(cx, expr, arg, span); }, ("flatten", []) => match method_call(recv) { - Some(("map", [recv, map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span), - Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true), + Some(("map", recv, [map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span), + Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true), _ => {}, }, ("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span), ("for_each", [_]) => { - if let Some(("inspect", [_, _], span2)) = method_call(recv) { + if let Some(("inspect", _, [_], span2)) = method_call(recv) { inspect_for_each::check(cx, expr, span2); } }, @@ -3478,12 +3480,12 @@ impl Methods { iter_on_single_or_empty_collections::check(cx, expr, name, recv); }, ("join", [join_arg]) => { - if let Some(("collect", _, span)) = method_call(recv) { + if let Some(("collect", _, _, span)) = method_call(recv) { unnecessary_join::check(cx, expr, recv, join_arg, span); } }, ("last", []) | ("skip", [_]) => { - if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) { + if let Some((name2, recv2, [args2 @ ..], _span2)) = method_call(recv) { if let ("cloned", []) = (name2, args2) { iter_overeager_cloned::check(cx, expr, recv, recv2, false, false); } @@ -3498,7 +3500,7 @@ impl Methods { } else { map_err_ignore::check(cx, expr, m_arg); } - if let Some((name, [recv2, args @ ..], span2)) = method_call(recv) { + if let Some((name, recv2, [args @ ..], span2)) = method_call(recv) { match (name, args) { ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv), ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv), @@ -3518,7 +3520,7 @@ impl Methods { manual_ok_or::check(cx, expr, recv, def, map); }, ("next", []) => { - if let Some((name2, [recv2, args2 @ ..], _)) = method_call(recv) { + if let Some((name2, recv2, [args2 @ ..], _)) = method_call(recv) { match (name2, args2) { ("cloned", []) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false), ("filter", [arg]) => filter_next::check(cx, expr, recv2, arg), @@ -3531,10 +3533,10 @@ impl Methods { } }, ("nth", [n_arg]) => match method_call(recv) { - Some(("bytes", [recv2], _)) => bytes_nth::check(cx, expr, recv2, n_arg), - Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false), - Some(("iter", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false), - Some(("iter_mut", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true), + Some(("bytes", recv2, [], _)) => bytes_nth::check(cx, expr, recv2, n_arg), + Some(("cloned", recv2, [], _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false), + Some(("iter", recv2, [], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false), + Some(("iter_mut", recv2, [], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true), _ => iter_nth_zero::check(cx, expr, recv, n_arg), }, ("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"), @@ -3591,7 +3593,7 @@ impl Methods { }, ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg), ("take", [_arg]) => { - if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) { + if let Some((name2, recv2, [args2 @ ..], _span2)) = method_call(recv) { if let ("cloned", []) = (name2, args2) { iter_overeager_cloned::check(cx, expr, recv, recv2, false, false); } @@ -3614,13 +3616,13 @@ impl Methods { }, ("unwrap", []) => { match method_call(recv) { - Some(("get", [recv, get_arg], _)) => { + Some(("get", recv, [get_arg], _)) => { get_unwrap::check(cx, expr, recv, get_arg, false); }, - Some(("get_mut", [recv, get_arg], _)) => { + Some(("get_mut", recv, [get_arg], _)) => { get_unwrap::check(cx, expr, recv, get_arg, true); }, - Some(("or", [recv, or_arg], or_span)) => { + Some(("or", recv, [or_arg], or_span)) => { or_then_unwrap::check(cx, expr, recv, or_arg, or_span); }, _ => {}, @@ -3629,19 +3631,19 @@ impl Methods { }, ("unwrap_err", []) => unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests), ("unwrap_or", [u_arg]) => match method_call(recv) { - Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => { + Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), lhs, [rhs], _)) => { manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]); }, - Some(("map", [m_recv, m_arg], span)) => { + Some(("map", m_recv, [m_arg], span)) => { option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span); }, - Some(("then_some", [t_recv, t_arg], _)) => { + Some(("then_some", t_recv, [t_arg], _)) => { obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg); }, _ => {}, }, ("unwrap_or_else", [u_arg]) => match method_call(recv) { - Some(("map", [recv, map_arg], _)) + Some(("map", recv, [map_arg], _)) if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, self.msrv) => {}, _ => { unwrap_or_else_default::check(cx, expr, recv, u_arg); @@ -3649,7 +3651,7 @@ impl Methods { }, }, ("zip", [arg]) => { - if let ExprKind::MethodCall(name, [iter_recv], _) = recv.kind + if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind && name.ident.name == sym::iter { range_zip_with_len::check(cx, expr, iter_recv, arg); @@ -3662,7 +3664,7 @@ impl Methods { } fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, is_some: bool) { - if let Some((name @ ("find" | "position" | "rposition"), [f_recv, arg], span)) = method_call(recv) { + if let Some((name @ ("find" | "position" | "rposition"), f_recv, [arg], span)) = method_call(recv) { search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/open_options.rs b/src/tools/clippy/clippy_lints/src/methods/open_options.rs index c3112823e346..903fa306f935 100644 --- a/src/tools/clippy/clippy_lints/src/methods/open_options.rs +++ b/src/tools/clippy/clippy_lints/src/methods/open_options.rs @@ -36,12 +36,12 @@ enum OpenOption { } fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec<(OpenOption, Argument)>) { - if let ExprKind::MethodCall(path, arguments, _) = argument.kind { - let obj_ty = cx.typeck_results().expr_ty(&arguments[0]).peel_refs(); + if let ExprKind::MethodCall(path, receiver, arguments, _) = argument.kind { + let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs(); // Only proceed if this is a call on some object of type std::fs::OpenOptions - if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 2 { - let argument_option = match arguments[1].kind { + if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && arguments.len() >= 1 { + let argument_option = match arguments[0].kind { ExprKind::Lit(ref span) => { if let Spanned { node: LitKind::Bool(lit), @@ -77,7 +77,7 @@ fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec _ => (), } - get_open_options(cx, &arguments[0], options); + get_open_options(cx, receiver, options); } } } diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs index 20cad0f181e9..81c67b4ca6a5 100644 --- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs @@ -56,13 +56,12 @@ pub(super) fn check<'tcx>( let closure_expr = peel_blocks(&closure_body.value); match &closure_expr.kind { - hir::ExprKind::MethodCall(_, args, _) => { + hir::ExprKind::MethodCall(_, receiver, [], _) => { if_chain! { - if args.len() == 1; - if path_to_local_id(&args[0], closure_body.params[0].pat.hir_id); + if path_to_local_id(receiver, closure_body.params[0].pat.hir_id); let adj = cx .typeck_results() - .expr_adjustments(&args[0]) + .expr_adjustments(receiver) .iter() .map(|x| &x.kind) .collect::>(); diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs index 6af134019a47..76876d866293 100644 --- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs @@ -20,6 +20,7 @@ pub(super) fn check<'tcx>( expr: &hir::Expr<'_>, method_span: Span, name: &str, + receiver: &'tcx hir::Expr<'_>, args: &'tcx [hir::Expr<'_>], ) { /// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`. @@ -144,7 +145,7 @@ pub(super) fn check<'tcx>( } } - if let [self_arg, arg] = args { + if let [arg] = args { let inner_arg = if let hir::ExprKind::Block( hir::Block { stmts: [], @@ -163,11 +164,11 @@ pub(super) fn check<'tcx>( let or_has_args = !or_args.is_empty(); if !check_unwrap_or_default(cx, name, fun, arg, or_has_args, expr.span, method_span) { let fun_span = if or_has_args { None } else { Some(fun.span) }; - check_general_case(cx, name, method_span, self_arg, arg, expr.span, fun_span); + check_general_case(cx, name, method_span, receiver, arg, expr.span, fun_span); } }, hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => { - check_general_case(cx, name, method_span, self_arg, arg, expr.span, None); + check_general_case(cx, name, method_span, receiver, arg, expr.span, None); }, _ => (), } diff --git a/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs b/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs index 00a2a0d14d11..867a3b402377 100644 --- a/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs +++ b/src/tools/clippy/clippy_lints/src/methods/range_zip_with_len.rs @@ -16,7 +16,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &' if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg); if is_integer_const(cx, start, 0); // `.len()` call - if let ExprKind::MethodCall(len_path, [len_recv], _) = end.kind; + if let ExprKind::MethodCall(len_path, len_recv, [], _) = end.kind; if len_path.ident.name == sym::len; // `.iter()` and `.len()` called on same `Path` if let ExprKind::Path(QPath::Resolved(_, iter_path)) = recv.kind; diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_add_str.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_add_str.rs index 9a5fabcf7cd5..81450fd8c6c3 100644 --- a/src/tools/clippy/clippy_lints/src/methods/single_char_add_str.rs +++ b/src/tools/clippy/clippy_lints/src/methods/single_char_add_str.rs @@ -3,12 +3,12 @@ use clippy_utils::{match_def_path, paths}; use rustc_hir as hir; use rustc_lint::LateContext; -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) { if match_def_path(cx, fn_def_id, &paths::PUSH_STR) { - single_char_push_string::check(cx, expr, args); + single_char_push_string::check(cx, expr, receiver, args); } else if match_def_path(cx, fn_def_id, &paths::INSERT_STR) { - single_char_insert_string::check(cx, expr, args); + single_char_insert_string::check(cx, expr, receiver, args); } } } diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs index 6cdc954c03be..18b6b5be175d 100644 --- a/src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs +++ b/src/tools/clippy/clippy_lints/src/methods/single_char_insert_string.rs @@ -8,12 +8,12 @@ use rustc_lint::LateContext; use super::SINGLE_CHAR_ADD_STR; /// lint for length-1 `str`s as argument for `insert_str` -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let mut applicability = Applicability::MachineApplicable; - if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[2], &mut applicability) { + if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) { let base_string_snippet = - snippet_with_applicability(cx, args[0].span.source_callsite(), "_", &mut applicability); - let pos_arg = snippet_with_applicability(cx, args[1].span, "..", &mut applicability); + snippet_with_applicability(cx, receiver.span.source_callsite(), "_", &mut applicability); + let pos_arg = snippet_with_applicability(cx, args[0].span, "..", &mut applicability); let sugg = format!("{}.insert({}, {})", base_string_snippet, pos_arg, extension_string); span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs index bf9006c69062..4221c52d5cd7 100644 --- a/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs +++ b/src/tools/clippy/clippy_lints/src/methods/single_char_pattern.rs @@ -10,37 +10,43 @@ use rustc_span::symbol::Symbol; use super::SINGLE_CHAR_PATTERN; const PATTERN_METHODS: [(&str, usize); 24] = [ - ("contains", 1), - ("starts_with", 1), - ("ends_with", 1), - ("find", 1), - ("rfind", 1), - ("split", 1), - ("split_inclusive", 1), - ("rsplit", 1), - ("split_terminator", 1), - ("rsplit_terminator", 1), - ("splitn", 2), - ("rsplitn", 2), - ("split_once", 1), - ("rsplit_once", 1), - ("matches", 1), - ("rmatches", 1), - ("match_indices", 1), - ("rmatch_indices", 1), - ("strip_prefix", 1), - ("strip_suffix", 1), - ("trim_start_matches", 1), - ("trim_end_matches", 1), - ("replace", 1), - ("replacen", 1), + ("contains", 0), + ("starts_with", 0), + ("ends_with", 0), + ("find", 0), + ("rfind", 0), + ("split", 0), + ("split_inclusive", 0), + ("rsplit", 0), + ("split_terminator", 0), + ("rsplit_terminator", 0), + ("splitn", 1), + ("rsplitn", 1), + ("split_once", 0), + ("rsplit_once", 0), + ("matches", 0), + ("rmatches", 0), + ("match_indices", 0), + ("rmatch_indices", 0), + ("strip_prefix", 0), + ("strip_suffix", 0), + ("trim_start_matches", 0), + ("trim_end_matches", 0), + ("replace", 0), + ("replacen", 0), ]; /// lint for length-1 `str`s for methods in `PATTERN_METHODS` -pub(super) fn check(cx: &LateContext<'_>, _expr: &hir::Expr<'_>, method_name: Symbol, args: &[hir::Expr<'_>]) { +pub(super) fn check( + cx: &LateContext<'_>, + _expr: &hir::Expr<'_>, + method_name: Symbol, + receiver: &hir::Expr<'_>, + args: &[hir::Expr<'_>], +) { for &(method, pos) in &PATTERN_METHODS { if_chain! { - if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(&args[0]).kind(); + if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(receiver).kind(); if *ty.kind() == ty::Str; if method_name.as_str() == method && args.len() > pos; let arg = &args[pos]; diff --git a/src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs b/src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs index 0237d39cbdb4..9ea6751956ab 100644 --- a/src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs +++ b/src/tools/clippy/clippy_lints/src/methods/single_char_push_string.rs @@ -8,11 +8,11 @@ use rustc_lint::LateContext; use super::SINGLE_CHAR_ADD_STR; /// lint for length-1 `str`s as argument for `push_str` -pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let mut applicability = Applicability::MachineApplicable; - if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) { + if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[0], &mut applicability) { let base_string_snippet = - snippet_with_applicability(cx, args[0].span.source_callsite(), "..", &mut applicability); + snippet_with_applicability(cx, receiver.span.source_callsite(), "..", &mut applicability); let sugg = format!("{}.push({})", base_string_snippet, extension_string); span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs index 4ac738272d08..8f2f47525147 100644 --- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs +++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs @@ -292,7 +292,7 @@ fn parse_iter_usage<'tcx>( ) -> Option { let (kind, span) = match iter.next() { Some((_, Node::Expr(e))) if e.span.ctxt() == ctxt => { - let (name, args) = if let ExprKind::MethodCall(name, [_, args @ ..], _) = e.kind { + let (name, args) = if let ExprKind::MethodCall(name, _, [args @ ..], _) = e.kind { (name, args) } else { return None; @@ -327,7 +327,7 @@ fn parse_iter_usage<'tcx>( } else { if_chain! { if let Some((_, Node::Expr(next_expr))) = iter.next(); - if let ExprKind::MethodCall(next_name, [_], _) = next_expr.kind; + if let ExprKind::MethodCall(next_name, _, [], _) = next_expr.kind; if next_name.ident.name == sym::next; if next_expr.span.ctxt() == ctxt; if let Some(next_id) = cx.typeck_results().type_dependent_def_id(next_expr.hir_id); @@ -367,7 +367,7 @@ fn parse_iter_usage<'tcx>( } }, _ if e.span.ctxt() != ctxt => (None, span), - ExprKind::MethodCall(name, [_], _) + ExprKind::MethodCall(name, _, [], _) if name.ident.name == sym::unwrap && cx .typeck_results() diff --git a/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs b/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs index d06658f2a5e6..143dcee35052 100644 --- a/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs +++ b/src/tools/clippy/clippy_lints/src/methods/string_extend_chars.rs @@ -16,7 +16,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr return; } if let Some(arglists) = method_chain_args(arg, &["chars"]) { - let target = &arglists[0][0]; + let target = &arglists[0].0; let self_ty = cx.typeck_results().expr_ty(target).peel_refs(); let ref_str = if *self_ty.kind() == ty::Str { "" diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs index 19037093e20a..95138c0e25b0 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs @@ -43,7 +43,7 @@ pub fn check_for_loop_iter( if let Some(receiver_snippet) = snippet_opt(cx, receiver.span); then { let snippet = if_chain! { - if let ExprKind::MethodCall(maybe_iter_method_name, [collection], _) = receiver.kind; + if let ExprKind::MethodCall(maybe_iter_method_name, collection, [], _) = receiver.kind; if maybe_iter_method_name.ident.name == sym::iter; if let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator); diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 1876c7fb9d05..a187a8d6016f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -54,7 +54,7 @@ pub(super) fn check<'tcx>( // This is a duplicate of what's happening in clippy_lints::methods::method_call, // which isn't ideal, We want to get the method call span, // but prefer to avoid changing the signature of the function itself. - if let hir::ExprKind::MethodCall(_, _, span) = expr.kind { + if let hir::ExprKind::MethodCall(.., span) = expr.kind { span_lint_and_then(cx, UNNECESSARY_LAZY_EVALUATIONS, expr.span, msg, |diag| { diag.span_suggestion( span, diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs index 1966990bd774..6f25acca1de6 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -50,9 +50,13 @@ fn mirrored_exprs(a_expr: &Expr<'_>, a_ident: &Ident, b_expr: &Expr<'_>, b_ident // The two exprs are method calls. // Check to see that the function is the same and the arguments are mirrored // This is enough because the receiver of the method is listed in the arguments - (ExprKind::MethodCall(left_segment, left_args, _), ExprKind::MethodCall(right_segment, right_args, _)) => { + ( + ExprKind::MethodCall(left_segment, left_receiver, left_args, _), + ExprKind::MethodCall(right_segment, right_receiver, right_args, _), + ) => { left_segment.ident == right_segment.ident && iter::zip(*left_args, *right_args).all(|(left, right)| mirrored_exprs(left, a_ident, right, b_ident)) + && mirrored_exprs(left_receiver, a_ident, right_receiver, b_ident) }, // Two tuples with mirrored contents (ExprKind::Tup(left_exprs), ExprKind::Tup(right_exprs)) => { @@ -125,7 +129,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Exp Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..}, Param { pat: Pat { kind: PatKind::Binding(_, _, right_ident, _), .. }, .. } ] = &closure_body.params; - if let ExprKind::MethodCall(method_path, [left_expr, right_expr], _) = closure_body.value.kind; + if let ExprKind::MethodCall(method_path, left_expr, [right_expr], _) = closure_body.value.kind; if method_path.ident.name == sym::cmp; if is_trait_method(cx, &closure_body.value, sym::Ord); then { diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index 44bf84352943..9dceb9af2f22 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -24,12 +24,13 @@ pub fn check<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol, - args: &'tcx [Expr<'tcx>], + receiver: &'tcx Expr<'_>, + args: &'tcx [Expr<'_>], msrv: Option, ) { if_chain! { if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); - if let [receiver] = args; + if args.is_empty(); then { if is_cloned_or_copied(cx, method_name, method_def_id) { unnecessary_iter_cloned::check(cx, expr, method_name, receiver); @@ -245,9 +246,14 @@ fn check_other_call_arg<'tcx>( ) -> bool { if_chain! { if let Some((maybe_call, maybe_arg)) = skip_addr_of_ancestors(cx, expr); - if let Some((callee_def_id, call_substs, call_args)) = get_callee_substs_and_args(cx, maybe_call); + if let Some((callee_def_id, call_substs, call_receiver, call_args)) = get_callee_substs_and_args(cx, maybe_call); let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder(); - if let Some(i) = call_args.iter().position(|arg| arg.hir_id == maybe_arg.hir_id); + let index = if let Some(call_receiver) = call_receiver { + std::iter::once(call_receiver).chain(call_args.iter()).position(|arg| arg.hir_id == maybe_arg.hir_id) + } else { + call_args.iter().position(|arg| arg.hir_id == maybe_arg.hir_id) + }; + if let Some(i) = index; if let Some(input) = fn_sig.inputs().get(i); let (input, n_refs) = peel_mid_ty_refs(*input); if let (trait_predicates, projection_predicates) = get_input_traits_and_projections(cx, callee_def_id, input); @@ -342,22 +348,22 @@ fn skip_addr_of_ancestors<'tcx>( fn get_callee_substs_and_args<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, -) -> Option<(DefId, SubstsRef<'tcx>, &'tcx [Expr<'tcx>])> { +) -> Option<(DefId, SubstsRef<'tcx>, Option<&'tcx Expr<'tcx>>, &'tcx [Expr<'tcx>])> { if_chain! { if let ExprKind::Call(callee, args) = expr.kind; let callee_ty = cx.typeck_results().expr_ty(callee); if let ty::FnDef(callee_def_id, _) = callee_ty.kind(); then { let substs = cx.typeck_results().node_substs(callee.hir_id); - return Some((*callee_def_id, substs, args)); + return Some((*callee_def_id, substs, None, args)); } } if_chain! { - if let ExprKind::MethodCall(_, args, _) = expr.kind; + if let ExprKind::MethodCall(_, receiver, args, _) = expr.kind; if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); then { let substs = cx.typeck_results().node_substs(expr.hir_id); - return Some((method_def_id, substs, args)); + return Some((method_def_id, substs, Some(receiver), args)); } } None diff --git a/src/tools/clippy/clippy_lints/src/methods/utils.rs b/src/tools/clippy/clippy_lints/src/methods/utils.rs index 3015531e8439..ae6b165fdc36 100644 --- a/src/tools/clippy/clippy_lints/src/methods/utils.rs +++ b/src/tools/clippy/clippy_lints/src/methods/utils.rs @@ -28,7 +28,7 @@ pub(super) fn derefs_to_slice<'tcx>( } } - if let hir::ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind { + if let hir::ExprKind::MethodCall(path, self_arg, ..) = &expr.kind { if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(self_arg)) { Some(self_arg) } else { @@ -139,9 +139,9 @@ impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> { self.addr_of_exprs.push(parent); return; }, - ExprKind::MethodCall(_, args, _) => { + ExprKind::MethodCall(.., args, _) => { if_chain! { - if args.iter().skip(1).all(|arg| !self.is_binding(arg)); + if args.iter().all(|arg| !self.is_binding(arg)); if let Some(method_def_id) = self.cx.typeck_results().type_dependent_def_id(parent.hir_id); let method_ty = self.cx.tcx.type_of(method_def_id); let self_ty = method_ty.fn_sig(self.cx.tcx).input(0).skip_binder(); diff --git a/src/tools/clippy/clippy_lints/src/minmax.rs b/src/tools/clippy/clippy_lints/src/minmax.rs index a081cde85725..c618f6b5d926 100644 --- a/src/tools/clippy/clippy_lints/src/minmax.rs +++ b/src/tools/clippy/clippy_lints/src/minmax.rs @@ -75,23 +75,22 @@ fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Cons .qpath_res(qpath, path.hir_id) .opt_def_id() .and_then(|def_id| match cx.tcx.get_diagnostic_name(def_id) { - Some(sym::cmp_min) => fetch_const(cx, args, MinMax::Min), - Some(sym::cmp_max) => fetch_const(cx, args, MinMax::Max), + Some(sym::cmp_min) => fetch_const(cx, None, args, MinMax::Min), + Some(sym::cmp_max) => fetch_const(cx, None, args, MinMax::Max), _ => None, }) } else { None } }, - ExprKind::MethodCall(path, args, _) => { + ExprKind::MethodCall(path, receiver, args @ [_], _) => { if_chain! { - if let [obj, _] = args; - if cx.typeck_results().expr_ty(obj).is_floating_point() || match_trait_method(cx, expr, &paths::ORD); + if cx.typeck_results().expr_ty(receiver).is_floating_point() || match_trait_method(cx, expr, &paths::ORD); then { if path.ident.name == sym!(max) { - fetch_const(cx, args, MinMax::Max) + fetch_const(cx, Some(receiver), args, MinMax::Max) } else if path.ident.name == sym!(min) { - fetch_const(cx, args, MinMax::Min) + fetch_const(cx, Some(receiver), args, MinMax::Min) } else { None } @@ -104,16 +103,26 @@ fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Cons } } -fn fetch_const<'a>(cx: &LateContext<'_>, args: &'a [Expr<'a>], m: MinMax) -> Option<(MinMax, Constant, &'a Expr<'a>)> { - if args.len() != 2 { +fn fetch_const<'a>( + cx: &LateContext<'_>, + receiver: Option<&'a Expr<'a>>, + args: &'a [Expr<'a>], + m: MinMax, +) -> Option<(MinMax, Constant, &'a Expr<'a>)> { + if (receiver.is_some() && args.len() != 1) || (receiver.is_none() && args.len() != 2) { return None; } - constant_simple(cx, cx.typeck_results(), &args[0]).map_or_else( - || constant_simple(cx, cx.typeck_results(), &args[1]).map(|c| (m, c, &args[0])), + let (arg0, arg1) = if let Some(receiver) = receiver { + (receiver, &args[0]) + } else { + (&args[0], &args[1]) + }; + constant_simple(cx, cx.typeck_results(), arg0).map_or_else( + || constant_simple(cx, cx.typeck_results(), arg1).map(|c| (m, c, arg0)), |c| { - if constant_simple(cx, cx.typeck_results(), &args[1]).is_none() { + if constant_simple(cx, cx.typeck_results(), arg1).is_none() { // otherwise ignore - Some((m, c, &args[1])) + Some((m, c, arg1)) } else { None } diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs index f434a655f8af..82dc03ef5c5b 100644 --- a/src/tools/clippy/clippy_lints/src/mut_reference.rs +++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs @@ -43,18 +43,24 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed { if let ExprKind::Path(ref path) = fn_expr.kind { check_arguments( cx, - arguments, + arguments.iter().collect(), cx.typeck_results().expr_ty(fn_expr), &rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)), "function", ); } }, - ExprKind::MethodCall(path, arguments, _) => { + ExprKind::MethodCall(path, receiver, arguments, _) => { let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap(); let substs = cx.typeck_results().node_substs(e.hir_id); let method_type = cx.tcx.bound_type_of(def_id).subst(cx.tcx, substs); - check_arguments(cx, arguments, method_type, path.ident.as_str(), "method"); + check_arguments( + cx, + std::iter::once(receiver).chain(arguments.iter()).collect(), + method_type, + path.ident.as_str(), + "method", + ); }, _ => (), } @@ -63,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed { fn check_arguments<'tcx>( cx: &LateContext<'tcx>, - arguments: &[Expr<'_>], + arguments: Vec<&Expr<'_>>, type_definition: Ty<'tcx>, name: &str, fn_kind: &str, diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs index 10e188ecb79a..f8cc3fbb3cdf 100644 --- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs +++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs @@ -56,12 +56,12 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { if_chain! { // Check the method name is `for_each`. - if let ExprKind::MethodCall(method_name, [for_each_recv, for_each_arg], _) = expr.kind; + if let ExprKind::MethodCall(method_name, for_each_recv, [for_each_arg], _) = expr.kind; if method_name.ident.name == Symbol::intern("for_each"); // Check `for_each` is an associated function of `Iterator`. if is_trait_method(cx, expr, sym::Iterator); // Checks the receiver of `for_each` is also a method call. - if let ExprKind::MethodCall(_, [iter_recv], _) = for_each_recv.kind; + if let ExprKind::MethodCall(_, iter_recv, [], _) = for_each_recv.kind; // Skip the lint if the call chain is too long. e.g. `v.field.iter().for_each()` or // `v.foo().iter().for_each()` must be skipped. if matches!( diff --git a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs index ed022b9d5291..25fb4f0f4cff 100644 --- a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs +++ b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs @@ -43,7 +43,7 @@ declare_lint_pass!(NonOctalUnixPermissions => [NON_OCTAL_UNIX_PERMISSIONS]); impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { match &expr.kind { - ExprKind::MethodCall(path, [func, param], _) => { + ExprKind::MethodCall(path, func, [param], _) => { let obj_ty = cx.typeck_results().expr_ty(func).peel_refs(); if_chain! { diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs index 774a3540d1e0..17d5fa2152bb 100644 --- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs @@ -304,13 +304,13 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { } return; }, - ExprKind::MethodCall(_, args, _) + ExprKind::MethodCall(_, receiver, args, _) if typeck.type_dependent_def_id(parent.hir_id).map_or(false, |id| { id == param.fn_id && has_matching_substs(param.fn_kind, typeck.node_substs(parent.hir_id)) }) => { - if let Some(idx) = args.iter().position(|arg| arg.hir_id == child_id) { + if let Some(idx) = std::iter::once(receiver).chain(args.iter()).position(|arg| arg.hir_id == child_id) { param.uses.push(Usage::new(span, idx)); } return; diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs index e1f9b5906f66..638a514ff9b3 100644 --- a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs +++ b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs @@ -38,7 +38,7 @@ fn symmetric_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'t fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) { let typeck = cx.typeck_results(); let (arg, arg_span) = match expr.kind { - ExprKind::MethodCall(.., [arg], _) + ExprKind::MethodCall(_, arg, [], _) if typeck .type_dependent_def_id(expr.hir_id) .and_then(|id| cx.tcx.trait_of_item(id)) diff --git a/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs index 0d067d1e1968..827a2b267093 100644 --- a/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs +++ b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs @@ -17,7 +17,7 @@ pub(crate) fn check<'tcx>( right: &'tcx Expr<'_>, ) { if op == BinOpKind::Div - && let ExprKind::MethodCall(method_path, [self_arg], _) = left.kind + && let ExprKind::MethodCall(method_path, self_arg, [], _) = left.kind && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_arg).peel_refs(), sym::Duration) && let Some((Constant::Int(divisor), _)) = constant(cx, cx.typeck_results(), right) { diff --git a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs index 0ef793443ff4..97ddcdb24799 100644 --- a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs +++ b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs @@ -113,7 +113,7 @@ fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { } if_chain! { - if let ExprKind::MethodCall(method_name, [ref self_arg, ..], _) = expr.kind; + if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind; if sym!(signum) == method_name.ident.name; // Check that the receiver of the signum() is a float (expressions[0] is the receiver of // the method call) diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index 3c5ea2d94144..63c9faf0396f 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -591,8 +591,11 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: set_skip_flag(); } }, - ExprKind::MethodCall(name, expr_args @ [self_arg, ..], _) => { - let i = expr_args.iter().position(|arg| arg.hir_id == child_id).unwrap_or(0); + ExprKind::MethodCall(name, self_arg, expr_args, _) => { + let i = std::iter::once(self_arg) + .chain(expr_args.iter()) + .position(|arg| arg.hir_id == child_id) + .unwrap_or(0); if i == 0 { // Check if the method can be renamed. let name = name.ident.as_str(); diff --git a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs index b907f38afbb9..4dc65da3ea1f 100644 --- a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs +++ b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs @@ -93,7 +93,7 @@ fn expr_as_ptr_offset_call<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, ) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Method)> { - if let ExprKind::MethodCall(path_segment, [arg_0, arg_1, ..], _) = &expr.kind { + if let ExprKind::MethodCall(path_segment, arg_0, [arg_1, ..], _) = &expr.kind { if is_expr_ty_raw_ptr(cx, arg_0) { if path_segment.ident.name == sym::offset { return Some((arg_0, arg_1, Method::Offset)); diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index b432ccb1ee32..6fddbd419bcd 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -86,7 +86,7 @@ fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Ex if_chain! { if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr); if !is_else_clause(cx.tcx, expr); - if let ExprKind::MethodCall(segment, [caller, ..], _) = &cond.kind; + if let ExprKind::MethodCall(segment, caller, ..) = &cond.kind; let caller_ty = cx.typeck_results().expr_ty(caller); let if_block = IfBlockType::IfIs(caller, caller_ty, segment.ident.name, then, r#else); if is_early_return(sym::Option, cx, &if_block) || is_early_return(sym::Result, cx, &if_block); diff --git a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs index 9538a8104739..94dec191103c 100644 --- a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs +++ b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs @@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { // finds use of `_.read(&mut v)` let mut read_found = false; let mut visitor = expr_visitor_no_bodies(|expr| { - if let ExprKind::MethodCall(path, [_self, arg], _) = expr.kind + if let ExprKind::MethodCall(path, _self, [arg], _) = expr.kind && let PathSegment { ident: read_or_read_exact, .. } = *path && matches!(read_or_read_exact.as_str(), "read" | "read_exact") && let ExprKind::AddrOf(_, hir::Mutability::Mut, inner) = arg.kind diff --git a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs index bfb9f0d01e1d..ac4e29e9dfdf 100644 --- a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs +++ b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs @@ -108,7 +108,7 @@ fn get_pointee_ty_and_count_expr<'tcx>( }; if_chain! { // Find calls to copy_{from,to}{,_nonoverlapping} and write_bytes methods - if let ExprKind::MethodCall(method_path, [ptr_self, .., count], _) = expr.kind; + if let ExprKind::MethodCall(method_path, ptr_self, [.., count], _) = expr.kind; let method_ident = method_path.ident.as_str(); if METHODS.iter().any(|m| *m == method_ident); diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs index b59a25e3a400..b35782184670 100644 --- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs @@ -201,7 +201,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { fn search_slow_extend_filling(&mut self, expr: &'tcx Expr<'_>) { if_chain! { if self.initialization_found; - if let ExprKind::MethodCall(path, [self_arg, extend_arg], _) = expr.kind; + if let ExprKind::MethodCall(path, self_arg, [extend_arg], _) = expr.kind; if path_to_local_id(self_arg, self.vec_alloc.local_id); if path.ident.name == sym!(extend); if self.is_repeat_take(extend_arg); @@ -215,7 +215,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { /// Checks if the given expression is resizing a vector with 0 fn search_slow_resize_filling(&mut self, expr: &'tcx Expr<'_>) { if self.initialization_found - && let ExprKind::MethodCall(path, [self_arg, len_arg, fill_arg], _) = expr.kind + && let ExprKind::MethodCall(path, self_arg, [len_arg, fill_arg], _) = expr.kind && path_to_local_id(self_arg, self.vec_alloc.local_id) && path.ident.name == sym!(resize) // Check that is filled with 0 @@ -224,7 +224,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { // Check that len expression is equals to `with_capacity` expression if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) { self.slow_expression = Some(InitializationType::Resize(expr)); - } else if let ExprKind::MethodCall(path, _, _) = len_arg.kind && path.ident.as_str() == "capacity" { + } else if let ExprKind::MethodCall(path, ..) = len_arg.kind && path.ident.as_str() == "capacity" { self.slow_expression = Some(InitializationType::Resize(expr)); } } @@ -233,7 +233,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { /// Returns `true` if give expression is `repeat(0).take(...)` fn is_repeat_take(&self, expr: &Expr<'_>) -> bool { if_chain! { - if let ExprKind::MethodCall(take_path, [recv, len_arg, ..], _) = expr.kind; + if let ExprKind::MethodCall(take_path, recv, [len_arg, ..], _) = expr.kind; if take_path.ident.name == sym!(take); // Check that take is applied to `repeat(0)` if self.is_repeat_zero(recv); @@ -241,7 +241,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { // Check that len expression is equals to `with_capacity` expression if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) { return true; - } else if let ExprKind::MethodCall(path, _, _) = len_arg.kind && path.ident.as_str() == "capacity" { + } else if let ExprKind::MethodCall(path, ..) = len_arg.kind && path.ident.as_str() == "capacity" { return true; } } diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index 22eb06b36463..662d399ca538 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs @@ -262,7 +262,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { let (method_names, expressions, _) = method_calls(left, 1); if method_names.len() == 1; if expressions.len() == 1; - if expressions[0].len() == 1; + if expressions[0].1.is_empty(); if method_names[0] == sym!(as_bytes); // Check for slicer @@ -270,7 +270,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { then { let mut applicability = Applicability::MachineApplicable; - let string_expression = &expressions[0][0]; + let string_expression = &expressions[0].0; let snippet_app = snippet_with_applicability( cx, @@ -291,12 +291,12 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { } if_chain! { - if let ExprKind::MethodCall(path, args, _) = &e.kind; + if let ExprKind::MethodCall(path, receiver, ..) = &e.kind; if path.ident.name == sym!(as_bytes); - if let ExprKind::Lit(lit) = &args[0].kind; + if let ExprKind::Lit(lit) = &receiver.kind; if let LitKind::Str(lit_content, _) = &lit.node; then { - let callsite = snippet(cx, args[0].span.source_callsite(), r#""foo""#); + let callsite = snippet(cx, receiver.span.source_callsite(), r#""foo""#); let mut applicability = Applicability::MachineApplicable; if callsite.starts_with("include_str!") { span_lint_and_sugg( @@ -305,7 +305,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { e.span, "calling `as_bytes()` on `include_str!(..)`", "consider using `include_bytes!(..)` instead", - snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability).replacen( + snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability).replacen( "include_str", "include_bytes", 1, @@ -314,7 +314,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { ); } else if lit_content.as_str().is_ascii() && lit_content.as_str().len() <= MAX_LENGTH_BYTE_STRING_LIT - && !args[0].span.from_expansion() + && !receiver.span.from_expansion() { span_lint_and_sugg( cx, @@ -324,7 +324,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { "consider using a byte string literal instead", format!( "b{}", - snippet_with_applicability(cx, args[0].span, r#""foo""#, &mut applicability) + snippet_with_applicability(cx, receiver.span, r#""foo""#, &mut applicability) ), applicability, ); @@ -333,9 +333,9 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { } if_chain! { - if let ExprKind::MethodCall(path, [recv], _) = &e.kind; + if let ExprKind::MethodCall(path, recv, [], _) = &e.kind; if path.ident.name == sym!(into_bytes); - if let ExprKind::MethodCall(path, [recv], _) = &recv.kind; + if let ExprKind::MethodCall(path, recv, [], _) = &recv.kind; if matches!(path.ident.name.as_str(), "to_owned" | "to_string"); if let ExprKind::Lit(lit) = &recv.kind; if let LitKind::Str(lit_content, _) = &lit.node; @@ -393,7 +393,7 @@ declare_lint_pass!(StrToString => [STR_TO_STRING]); impl<'tcx> LateLintPass<'tcx> for StrToString { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { if_chain! { - if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind; + if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind; if path.ident.name == sym::to_string; let ty = cx.typeck_results().expr_ty(self_arg); if let ty::Ref(_, ty, ..) = ty.kind(); @@ -443,7 +443,7 @@ declare_lint_pass!(StringToString => [STRING_TO_STRING]); impl<'tcx> LateLintPass<'tcx> for StringToString { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { if_chain! { - if let ExprKind::MethodCall(path, [self_arg, ..], _) = &expr.kind; + if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind; if path.ident.name == sym::to_string; let ty = cx.typeck_results().expr_ty(self_arg); if is_type_diagnostic_item(cx, ty, sym::String); @@ -487,11 +487,11 @@ impl<'tcx> LateLintPass<'tcx> for TrimSplitWhitespace { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { let tyckres = cx.typeck_results(); if_chain! { - if let ExprKind::MethodCall(path, [split_recv], split_ws_span) = expr.kind; + if let ExprKind::MethodCall(path, split_recv, [], split_ws_span) = expr.kind; if path.ident.name == sym!(split_whitespace); if let Some(split_ws_def_id) = tyckres.type_dependent_def_id(expr.hir_id); if cx.tcx.is_diagnostic_item(sym::str_split_whitespace, split_ws_def_id); - if let ExprKind::MethodCall(path, [_trim_recv], trim_span) = split_recv.kind; + if let ExprKind::MethodCall(path, _trim_recv, [], trim_span) = split_recv.kind; if let trim_fn_name @ ("trim" | "trim_start" | "trim_end") = path.ident.name.as_str(); if let Some(trim_def_id) = tyckres.type_dependent_def_id(split_recv.hir_id); if is_one_of_trim_diagnostic_items(cx, trim_def_id); diff --git a/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs b/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs index 7bc9cf742e65..78403d9fdb7e 100644 --- a/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs +++ b/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs @@ -47,7 +47,7 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings { if let ExprKind::Path(path) = &func.kind; if let Some(did) = cx.qpath_res(path, func.hir_id).opt_def_id(); if match_libc_symbol(cx, did, "strlen"); - if let ExprKind::MethodCall(path, [self_arg], _) = recv.kind; + if let ExprKind::MethodCall(path, self_arg, [], _) = recv.kind; if !recv.span.from_expansion(); if path.ident.name == sym::as_ptr; then { diff --git a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs index aa6c01b3a7cd..651201f34ed2 100644 --- a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs +++ b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs @@ -39,19 +39,17 @@ declare_lint_pass!(ToDigitIsSome => [TO_DIGIT_IS_SOME]); impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { if_chain! { - if let hir::ExprKind::MethodCall(is_some_path, is_some_args, _) = &expr.kind; + if let hir::ExprKind::MethodCall(is_some_path, to_digit_expr, [], _) = &expr.kind; if is_some_path.ident.name.as_str() == "is_some"; - if let [to_digit_expr] = &**is_some_args; then { let match_result = match &to_digit_expr.kind { - hir::ExprKind::MethodCall(to_digits_path, to_digit_args, _) => { + hir::ExprKind::MethodCall(to_digits_path, char_arg, [radix_arg], _) => { if_chain! { - if let [char_arg, radix_arg] = &**to_digit_args; if to_digits_path.ident.name.as_str() == "to_digit"; let char_arg_ty = cx.typeck_results().expr_ty_adjusted(char_arg); if *char_arg_ty.kind() == ty::Char; then { - Some((true, char_arg, radix_arg)) + Some((true, *char_arg, radix_arg)) } else { None } @@ -59,7 +57,7 @@ impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome { } hir::ExprKind::Call(to_digits_call, to_digit_args) => { if_chain! { - if let [char_arg, radix_arg] = &**to_digit_args; + if let [char_arg, radix_arg] = *to_digit_args; if let hir::ExprKind::Path(to_digits_path) = &to_digits_call.kind; if let to_digits_call_res = cx.qpath_res(to_digits_path, to_digits_call.hir_id); if let Some(to_digits_def_id) = to_digits_call_res.opt_def_id(); diff --git a/src/tools/clippy/clippy_lints/src/uninit_vec.rs b/src/tools/clippy/clippy_lints/src/uninit_vec.rs index 9a41603f2f4c..3f99bd3f3156 100644 --- a/src/tools/clippy/clippy_lints/src/uninit_vec.rs +++ b/src/tools/clippy/clippy_lints/src/uninit_vec.rs @@ -177,7 +177,7 @@ fn extract_init_or_reserve_target<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt }); } }, - ExprKind::MethodCall(path, [self_expr, _], _) if is_reserve(cx, path, self_expr) => { + ExprKind::MethodCall(path, self_expr, [_], _) if is_reserve(cx, path, self_expr) => { return Some(TargetVec { location: VecLocation::Expr(self_expr), init_kind: None, @@ -211,7 +211,7 @@ fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Opt } }); match expr.kind { - ExprKind::MethodCall(path, [self_expr, _], _) => { + ExprKind::MethodCall(path, self_expr, [_], _) => { let self_type = cx.typeck_results().expr_ty(self_expr).peel_refs(); if is_type_diagnostic_item(cx, self_type, sym::Vec) && path.ident.name.as_str() == "set_len" { Some((self_expr, expr.span)) diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs index b0fce91abeb7..851eef7b3324 100644 --- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs +++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs @@ -144,8 +144,9 @@ fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Spa impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if let ExprKind::MethodCall(_, args, _) = expr.kind { + if let ExprKind::MethodCall(_, receiver, args, _) = expr.kind { let arg_indices = get_args_to_check(cx, expr); + let args = std::iter::once(receiver).chain(args.iter()).collect::>(); for (i, trait_name) in arg_indices { if i < args.len() { match check_arg(cx, &args[i]) { diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs index aec028d5c482..35824b03170a 100644 --- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs +++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs @@ -128,7 +128,7 @@ fn needs_inferred_result_ty( locals_to_check: &mut Vec, seen_locals: &mut HirIdSet, ) -> bool { - let (id, args) = match e.kind { + let (id, receiver, args) = match e.kind { ExprKind::Call( Expr { kind: ExprKind::Path(ref path), @@ -137,11 +137,11 @@ fn needs_inferred_result_ty( }, args, ) => match cx.qpath_res(path, *hir_id) { - Res::Def(DefKind::AssocFn | DefKind::Fn, id) => (id, args), + Res::Def(DefKind::AssocFn | DefKind::Fn, id) => (id, None, args), _ => return false, }, - ExprKind::MethodCall(_, args, _) => match cx.typeck_results().type_dependent_def_id(e.hir_id) { - Some(id) => (id, args), + ExprKind::MethodCall(_, receiver, args, _) => match cx.typeck_results().type_dependent_def_id(e.hir_id) { + Some(id) => (id, Some(receiver), args), None => return false, }, ExprKind::Path(QPath::Resolved(None, path)) => { @@ -156,6 +156,11 @@ fn needs_inferred_result_ty( }; let sig = cx.tcx.fn_sig(id).skip_binder(); if let ty::Param(output_ty) = *sig.output().kind() { + let args: Vec<&Expr<'_>> = if let Some(receiver) = receiver { + std::iter::once(receiver).chain(args.iter()).collect() + } else { + args.iter().collect() + }; sig.inputs().iter().zip(args).all(|(&ty, arg)| { !ty.is_param(output_ty.index) || each_value_source_needs_inference(cx, arg, locals_to_check, seen_locals) }) diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs index 16da2f11b81a..7ffb53dcf455 100644 --- a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs +++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs @@ -30,26 +30,27 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { } } - match expr.kind { - ExprKind::Call(_, args) | ExprKind::MethodCall(_, args, _) => { - let args_to_recover = args - .iter() - .filter(|arg| { - if cx.typeck_results().expr_ty(arg).is_unit() && !utils::is_unit_literal(arg) { - !matches!( - &arg.kind, - ExprKind::Match(.., MatchSource::TryDesugar) | ExprKind::Path(..) - ) - } else { - false - } - }) - .collect::>(); - if !args_to_recover.is_empty() && !is_from_proc_macro(cx, expr) { - lint_unit_args(cx, expr, &args_to_recover); + let args: Vec<_> = match expr.kind { + ExprKind::Call(_, args) => args.iter().collect(), + ExprKind::MethodCall(_, receiver, args, _) => std::iter::once(receiver).chain(args.iter()).collect(), + _ => return, + }; + + let args_to_recover = args + .into_iter() + .filter(|arg| { + if cx.typeck_results().expr_ty(arg).is_unit() && !utils::is_unit_literal(arg) { + !matches!( + &arg.kind, + ExprKind::Match(.., MatchSource::TryDesugar) | ExprKind::Path(..) + ) + } else { + false } - }, - _ => (), + }) + .collect::>(); + if !args_to_recover.is_empty() && !is_from_proc_macro(cx, expr) { + lint_unit_args(cx, expr, &args_to_recover.as_slice()); } } diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs index 323cf83ffcff..b38d71784fcf 100644 --- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs +++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs @@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount { check_map_error(cx, res, expr); } }, - hir::ExprKind::MethodCall(path, [ref arg_0, ..], _) => match path.ident.as_str() { + hir::ExprKind::MethodCall(path, arg_0, ..) => match path.ident.as_str() { "expect" | "unwrap" | "unwrap_or" | "unwrap_or_else" => { check_map_error(cx, arg_0, expr); }, @@ -94,9 +94,9 @@ fn try_remove_await<'a>(expr: &'a hir::Expr<'a>) -> Option<&hir::Expr<'a>> { fn check_map_error(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) { let mut call = call; - while let hir::ExprKind::MethodCall(path, args, _) = call.kind { + while let hir::ExprKind::MethodCall(path, receiver, ..) = call.kind { if matches!(path.ident.as_str(), "or" | "or_else" | "ok") { - call = &args[0]; + call = receiver; } else { break; } @@ -110,7 +110,7 @@ fn check_map_error(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr< } fn check_method_call(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>, is_await: bool) { - if let hir::ExprKind::MethodCall(path, _, _) = call.kind { + if let hir::ExprKind::MethodCall(path, ..) = call.kind { let symbol = path.ident.as_str(); let read_trait = if is_await { match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCREADEXT) diff --git a/src/tools/clippy/clippy_lints/src/unused_peekable.rs b/src/tools/clippy/clippy_lints/src/unused_peekable.rs index ac73173697e8..7fbfecf96ec3 100644 --- a/src/tools/clippy/clippy_lints/src/unused_peekable.rs +++ b/src/tools/clippy/clippy_lints/src/unused_peekable.rs @@ -149,7 +149,8 @@ impl<'tcx> Visitor<'_> for PeekableVisitor<'_, 'tcx> { ident: method_name_ident, .. }, - [self_arg, remaining_args @ ..], + self_arg, + [remaining_args @ ..], _, ) => { let method_name = method_name_ident.name.as_str(); diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs index d3f9e5abfd73..9092156be150 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap.rs @@ -154,13 +154,13 @@ fn collect_unwrap_info<'tcx>( return collect_unwrap_info(cx, if_expr, expr, branch, !invert, false); } else { if_chain! { - if let ExprKind::MethodCall(method_name, args, _) = &expr.kind; - if let Some(local_id) = path_to_local(&args[0]); - let ty = cx.typeck_results().expr_ty(&args[0]); + if let ExprKind::MethodCall(method_name, receiver, args, _) = &expr.kind; + if let Some(local_id) = path_to_local(receiver); + let ty = cx.typeck_results().expr_ty(receiver); let name = method_name.ident.as_str(); if is_relevant_option_call(cx, ty, name) || is_relevant_result_call(cx, ty, name); then { - assert!(args.len() == 1); + assert!(args.len() == 0); let unwrappable = match name { "is_some" | "is_ok" => true, "is_err" | "is_none" => false, @@ -231,7 +231,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> { } else { // find `unwrap[_err]()` calls: if_chain! { - if let ExprKind::MethodCall(method_name, [self_arg, ..], _) = expr.kind; + if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind; if let Some(id) = path_to_local(self_arg); if [sym::unwrap, sym::expect, sym!(unwrap_err)].contains(&method_name.ident.name); let call_to_unwrap = [sym::unwrap, sym::expect].contains(&method_name.ident.name); diff --git a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs index b32be238cd55..b3ca15f7648b 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs @@ -83,7 +83,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { // check for `expect` if let Some(arglists) = method_chain_args(expr, &["expect"]) { - let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); + let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs(); if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option) || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result) { @@ -93,7 +93,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> { // check for `unwrap` if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { - let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); + let receiver_ty = self.typeck_results.expr_ty(&arglists[0].0).peel_refs(); if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option) || is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result) { diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index b6738e2891d3..f1b6463ad0f7 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { } }, - ExprKind::MethodCall(name, .., [recv, ..], _) => { + ExprKind::MethodCall(name, recv, ..) => { if is_trait_method(cx, e, sym::Into) && name.ident.as_str() == "into" { let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(recv); diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 3ffcaa90af3e..fec4ee93e7bc 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -402,10 +402,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { self.expr(func); self.slice(args, |e| self.expr(e)); }, - ExprKind::MethodCall(method_name, args, _) => { - bind!(self, method_name, args); - kind!("MethodCall({method_name}, {args}, _)"); + ExprKind::MethodCall(method_name, receiver, args, _) => { + bind!(self, method_name, receiver, args); + kind!("MethodCall({method_name}, {receiver}, {args}, _)"); self.ident(field!(method_name.ident)); + self.expr(receiver); self.slice(args, |e| self.expr(e)); }, ExprKind::Tup(elements) => { diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs index eb34085a2abf..ae1c11ef83c3 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs @@ -687,7 +687,7 @@ impl<'tcx> LateLintPass<'tcx> for OuterExpnDataPass { if let ["expn_data", "outer_expn"] = method_names.as_slice(); let args = arg_lists[1]; if args.len() == 1; - let self_arg = &args[0]; + let self_arg = &args.0; let self_ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); if match_type(cx, self_ty, &paths::SYNTAX_CONTEXT); then { diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs index 35db45e2b0c9..542c6a37d567 100644 --- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs +++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs @@ -100,7 +100,7 @@ impl VecPushSearcher { || get_parent_expr(cx, last_place) .map_or(false, |e| matches!(e.kind, ExprKind::AddrOf(_, Mutability::Mut, _))); }, - ExprKind::MethodCall(_, [recv, ..], _) + ExprKind::MethodCall(_, recv, ..) if recv.hir_id == e.hir_id && adjusted_mut == Mutability::Mut && !adjusted_ty.peel_refs().is_slice() => @@ -201,7 +201,7 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { if let Some(searcher) = self.searcher.take() { if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind - && let ExprKind::MethodCall(name, [self_arg, _], _) = expr.kind + && let ExprKind::MethodCall(name, self_arg, [_], _) = expr.kind && path_to_local_id(self_arg, searcher.local_id) && name.ident.as_str() == "push" { diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index 8335ffae81eb..e8d2d579f097 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -118,9 +118,9 @@ fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) { ExprKind::Unary(UnOp::Neg, e) => (Pat::Str("-"), expr_search_pat(tcx, e).1), ExprKind::Lit(ref lit) => lit_search_pat(&lit.node), ExprKind::Array(_) | ExprKind::Repeat(..) => (Pat::Str("["), Pat::Str("]")), - ExprKind::Call(e, []) | ExprKind::MethodCall(_, [e], _) => (expr_search_pat(tcx, e).0, Pat::Str("(")), + ExprKind::Call(e, []) | ExprKind::MethodCall(_, e, [], _) => (expr_search_pat(tcx, e).0, Pat::Str("(")), ExprKind::Call(first, [.., last]) - | ExprKind::MethodCall(_, [first, .., last], _) + | ExprKind::MethodCall(_, first, [.., last], _) | ExprKind::Binary(_, first, last) | ExprKind::Tup([first, .., last]) | ExprKind::Assign(first, last, _) diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs index 7f55db3b31f7..ad95369b9ef7 100644 --- a/src/tools/clippy/clippy_utils/src/diagnostics.rs +++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs @@ -155,13 +155,7 @@ where }); } -pub fn span_lint_hir( - cx: &LateContext<'_>, - lint: &'static Lint, - hir_id: HirId, - sp: Span, - msg: &str, -) { +pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: &str) { cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |diag| { let mut diag = diag.build(msg); docs_link(&mut diag, lint); diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs index 730724b95b96..124a00d81784 100644 --- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs +++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs @@ -45,12 +45,7 @@ impl ops::BitOrAssign for EagernessSuggestion { } /// Determine the eagerness of the given function call. -fn fn_eagerness<'tcx>( - cx: &LateContext<'tcx>, - fn_id: DefId, - name: Symbol, - args: &'tcx [Expr<'_>], -) -> EagernessSuggestion { +fn fn_eagerness<'tcx>(cx: &LateContext<'tcx>, fn_id: DefId, name: Symbol, have_one_arg: bool) -> EagernessSuggestion { use EagernessSuggestion::{Eager, Lazy, NoChange}; let name = name.as_str(); @@ -59,7 +54,7 @@ fn fn_eagerness<'tcx>( None => return Lazy, }; - if (name.starts_with("as_") || name == "len" || name == "is_empty") && args.len() == 1 { + if (name.starts_with("as_") || name == "len" || name == "is_empty") && have_one_arg { if matches!( cx.tcx.crate_name(fn_id.krate), sym::std | sym::core | sym::alloc | sym::proc_macro @@ -127,10 +122,11 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS }, Res::Def(_, id) => match path { QPath::Resolved(_, p) => { - self.eagerness |= fn_eagerness(self.cx, id, p.segments.last().unwrap().ident.name, args); + self.eagerness |= + fn_eagerness(self.cx, id, p.segments.last().unwrap().ident.name, !args.is_empty()); }, QPath::TypeRelative(_, name) => { - self.eagerness |= fn_eagerness(self.cx, id, name.ident.name, args); + self.eagerness |= fn_eagerness(self.cx, id, name.ident.name, !args.is_empty()); }, QPath::LangItem(..) => self.eagerness = Lazy, }, @@ -141,12 +137,12 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS self.eagerness |= NoChange; return; }, - ExprKind::MethodCall(name, args, _) => { + ExprKind::MethodCall(name, ..) => { self.eagerness |= self .cx .typeck_results() .type_dependent_def_id(e.hir_id) - .map_or(Lazy, |id| fn_eagerness(self.cx, id, name.ident.name, args)); + .map_or(Lazy, |id| fn_eagerness(self.cx, id, name.ident.name, true)); }, ExprKind::Index(_, e) => { let ty = self.cx.typeck_results().expr_ty_adjusted(e); diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 1834e2a2de87..6cb6544df4bc 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -282,8 +282,14 @@ impl HirEqInterExpr<'_, '_, '_> { && self.eq_expr(l.body, r.body) }) }, - (&ExprKind::MethodCall(l_path, l_args, _), &ExprKind::MethodCall(r_path, r_args, _)) => { - self.inner.allow_side_effects && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args) + ( + &ExprKind::MethodCall(l_path, l_receiver, l_args, _), + &ExprKind::MethodCall(r_path, r_receiver, r_args, _), + ) => { + self.inner.allow_side_effects + && self.eq_path_segment(l_path, r_path) + && self.eq_expr(l_receiver, r_receiver) + && self.eq_exprs(l_args, r_args) }, (&ExprKind::Repeat(le, ll), &ExprKind::Repeat(re, rl)) => { self.eq_expr(le, re) && self.eq_array_length(ll, rl) @@ -743,8 +749,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { s.hash(&mut self.s); }, - ExprKind::MethodCall(path, args, ref _fn_span) => { + ExprKind::MethodCall(path, receiver, args, ref _fn_span) => { self.hash_name(path.ident.name); + self.hash_expr(receiver); self.hash_exprs(args); }, ExprKind::ConstBlock(ref l_id) => { diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index f3a08e98688e..ed1f8af989fe 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1036,21 +1036,21 @@ pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<' pub fn method_calls<'tcx>( expr: &'tcx Expr<'tcx>, max_depth: usize, -) -> (Vec, Vec<&'tcx [Expr<'tcx>]>, Vec) { +) -> (Vec, Vec<(&'tcx Expr<'tcx>, &'tcx [Expr<'tcx>])>, Vec) { let mut method_names = Vec::with_capacity(max_depth); let mut arg_lists = Vec::with_capacity(max_depth); let mut spans = Vec::with_capacity(max_depth); let mut current = expr; for _ in 0..max_depth { - if let ExprKind::MethodCall(path, args, _) = ¤t.kind { - if args.iter().any(|e| e.span.from_expansion()) { + if let ExprKind::MethodCall(path, receiver, args, _) = ¤t.kind { + if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) { break; } method_names.push(path.ident.name); - arg_lists.push(&**args); + arg_lists.push((*receiver, &**args)); spans.push(path.ident.span); - current = &args[0]; + current = receiver; } else { break; } @@ -1065,18 +1065,18 @@ pub fn method_calls<'tcx>( /// `method_chain_args(expr, &["bar", "baz"])` will return a `Vec` /// containing the `Expr`s for /// `.bar()` and `.baz()` -pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option]>> { +pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option, &'a [Expr<'a>])>> { let mut current = expr; let mut matched = Vec::with_capacity(methods.len()); for method_name in methods.iter().rev() { // method chains are stored last -> first - if let ExprKind::MethodCall(path, args, _) = current.kind { + if let ExprKind::MethodCall(path, receiver, args, _) = current.kind { if path.ident.name.as_str() == *method_name { - if args.iter().any(|e| e.span.from_expansion()) { + if receiver.span.from_expansion() || args.iter().any(|e| e.span.from_expansion()) { return None; } - matched.push(args); // build up `matched` backwards - current = &args[0]; // go to parent expression + matched.push((receiver, args)); // build up `matched` backwards + current = receiver; // go to parent expression } else { return None; } @@ -1239,8 +1239,10 @@ pub fn get_enclosing_loop_or_multi_call_closure<'tcx>( ty_is_fn_once_param(cx.tcx, ty.skip_binder(), predicates).then_some(()) }) }, - ExprKind::MethodCall(_, args, _) => { - let i = args.iter().position(|arg| arg.hir_id == id)?; + ExprKind::MethodCall(_, receiver, args, _) => { + let i = std::iter::once(receiver) + .chain(args.iter()) + .position(|arg| arg.hir_id == id)?; let id = cx.typeck_results().type_dependent_def_id(e.hir_id)?; let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i]; ty_is_fn_once_param(cx.tcx, ty, cx.tcx.param_env(id).caller_bounds()).then_some(()) diff --git a/src/tools/clippy/clippy_utils/src/ptr.rs b/src/tools/clippy/clippy_utils/src/ptr.rs index 649b7b9940af..0226f74906b5 100644 --- a/src/tools/clippy/clippy_utils/src/ptr.rs +++ b/src/tools/clippy/clippy_utils/src/ptr.rs @@ -36,7 +36,7 @@ fn extract_clone_suggestions<'tcx>( if abort { return false; } - if let ExprKind::MethodCall(seg, [recv], _) = expr.kind { + if let ExprKind::MethodCall(seg, recv, [], _) = expr.kind { if path_to_local_id(recv, id) { if seg.ident.name.as_str() == "capacity" { abort = true; diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index 081c98e2f3ce..cca71bbf76e2 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -373,12 +373,14 @@ fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String { | AssocOp::LessEqual | AssocOp::NotEqual | AssocOp::Greater - | AssocOp::GreaterEqual => format!( - "{} {} {}", - lhs, - op.to_ast_binop().expect("Those are AST ops").to_string(), - rhs - ), + | AssocOp::GreaterEqual => { + format!( + "{} {} {}", + lhs, + op.to_ast_binop().expect("Those are AST ops").to_string(), + rhs + ) + }, AssocOp::Assign => format!("{} = {}", lhs, rhs), AssocOp::AssignOp(op) => { format!("{} {}= {}", lhs, token_kind_to_string(&token::BinOp(op)), rhs) @@ -868,15 +870,15 @@ impl<'tcx> DerefDelegate<'_, 'tcx> { /// indicates whether the function from `parent_expr` takes its args by double reference fn func_takes_arg_by_double_ref(&self, parent_expr: &'tcx hir::Expr<'_>, cmt_hir_id: HirId) -> bool { let ty = match parent_expr.kind { - ExprKind::MethodCall(_, call_args, _) => { + ExprKind::MethodCall(_, receiver, call_args, _) => { if let Some(sig) = self .cx .typeck_results() .type_dependent_def_id(parent_expr.hir_id) .map(|did| self.cx.tcx.fn_sig(did).skip_binder()) { - call_args - .iter() + std::iter::once(receiver) + .chain(call_args.iter()) .position(|arg| arg.hir_id == cmt_hir_id) .map(|i| sig.inputs()[i]) } else { @@ -933,14 +935,14 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { match &parent_expr.kind { // given expression is the self argument and will be handled completely by the compiler // i.e.: `|x| x.is_something()` - ExprKind::MethodCall(_, [self_expr, ..], _) if self_expr.hir_id == cmt.hir_id => { + ExprKind::MethodCall(_, self_expr, ..) if self_expr.hir_id == cmt.hir_id => { let _ = write!(self.suggestion_start, "{}{}", start_snip, ident_str_with_proj); self.next_pos = span.hi(); return; }, // item is used in a call // i.e.: `Call`: `|x| please(x)` or `MethodCall`: `|x| [1, 2, 3].contains(x)` - ExprKind::Call(_, [call_args @ ..]) | ExprKind::MethodCall(_, [_, call_args @ ..], _) => { + ExprKind::Call(_, [call_args @ ..]) | ExprKind::MethodCall(_, _, [call_args @ ..], _) => { let expr = self.cx.tcx.hir().expect_expr(cmt.hir_id); let arg_ty_kind = self.cx.typeck_results().expr_ty(expr).kind(); diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs index bae8ad9f5659..6a62002a4d12 100644 --- a/src/tools/clippy/clippy_utils/src/visitors.rs +++ b/src/tools/clippy/clippy_utils/src/visitors.rs @@ -620,7 +620,13 @@ pub fn for_each_unconsumed_temporary<'tcx, B>( helper(typeck, true, arg, f)?; } }, - ExprKind::MethodCall(_, args, _) | ExprKind::Tup(args) | ExprKind::Array(args) => { + ExprKind::MethodCall(_, receiver, args, _) => { + helper(typeck, true, receiver, f)?; + for arg in args { + helper(typeck, true, arg, f)?; + } + }, + ExprKind::Tup(args) | ExprKind::Array(args) => { for arg in args { helper(typeck, true, arg, f)?; } diff --git a/src/tools/clippy/tests/ui/author/struct.stdout b/src/tools/clippy/tests/ui/author/struct.stdout index 5e78b7c9de7e..b5bbc9e213c6 100644 --- a/src/tools/clippy/tests/ui/author/struct.stdout +++ b/src/tools/clippy/tests/ui/author/struct.stdout @@ -53,11 +53,11 @@ if_chain! { } } if_chain! { - if let ExprKind::MethodCall(method_name, args, _) = expr.kind; + if let ExprKind::MethodCall(method_name, receiver, args, _) = expr.kind; if method_name.ident.as_str() == "test"; - if args.len() == 1; - if let ExprKind::Path(ref qpath) = args[0].kind; + if let ExprKind::Path(ref qpath) = receiver.kind; if match_qpath(qpath, &["test_method_call"]); + if args.is_empty(); then { // report your lint here } From 097ef517fedd6c1c9ab4d35309b83e6b62ab703c Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Fri, 2 Sep 2022 22:48:14 +0900 Subject: [PATCH 4209/5092] refactor: remove unnecessary variables --- clippy_lints/src/dereference.rs | 94 ++++++++++---------- clippy_lints/src/infinite_iter.rs | 10 +-- clippy_lints/src/len_zero.rs | 7 +- clippy_lints/src/methods/clone_on_copy.rs | 5 +- clippy_lints/src/methods/clone_on_ref_ptr.rs | 5 +- clippy_lints/src/methods/mod.rs | 10 +-- clippy_lints/src/minmax.rs | 10 +-- clippy_lints/src/unused_peekable.rs | 2 +- 8 files changed, 67 insertions(+), 76 deletions(-) diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs index fd6ed36cb192..6ee9e2e9754c 100644 --- a/clippy_lints/src/dereference.rs +++ b/clippy_lints/src/dereference.rs @@ -798,57 +798,55 @@ fn walk_parents<'tcx>( }), ExprKind::MethodCall(_, receiver, args, _) => { let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap(); - std::iter::once(receiver) - .chain(args.iter()) + if receiver.hir_id == child_id { + // Check for calls to trait methods where the trait is implemented on a reference. + // Two cases need to be handled: + // * `self` methods on `&T` will never have auto-borrow + // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take + // priority. + if e.hir_id != child_id { + return Some(Position::ReborrowStable(precedence)) + } else if let Some(trait_id) = cx.tcx.trait_of_item(id) + && let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e)) + && let ty::Ref(_, sub_ty, _) = *arg_ty.kind() + && let subs = match cx + .typeck_results() + .node_substs_opt(parent.hir_id) + .and_then(|subs| subs.get(1..)) + { + Some(subs) => cx.tcx.mk_substs(subs.iter().copied()), + None => cx.tcx.mk_substs(std::iter::empty::>()), + } && let impl_ty = if cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref() { + // Trait methods taking `&self` + sub_ty + } else { + // Trait methods taking `self` + arg_ty + } && impl_ty.is_ref() + && cx.tcx.infer_ctxt().enter(|infcx| + infcx + .type_implements_trait(trait_id, impl_ty, subs, cx.param_env) + .must_apply_modulo_regions() + ) + { + return Some(Position::MethodReceiverRefImpl) + } else { + return Some(Position::MethodReceiver) + } + } + args.iter() .position(|arg| arg.hir_id == child_id) .map(|i| { - if i == 0 { - // Check for calls to trait methods where the trait is implemented on a reference. - // Two cases need to be handled: - // * `self` methods on `&T` will never have auto-borrow - // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take - // priority. - if e.hir_id != child_id { - Position::ReborrowStable(precedence) - } else if let Some(trait_id) = cx.tcx.trait_of_item(id) - && let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e)) - && let ty::Ref(_, sub_ty, _) = *arg_ty.kind() - && let subs = match cx - .typeck_results() - .node_substs_opt(parent.hir_id) - .and_then(|subs| subs.get(1..)) - { - Some(subs) => cx.tcx.mk_substs(subs.iter().copied()), - None => cx.tcx.mk_substs(std::iter::empty::>()), - } && let impl_ty = if cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref() { - // Trait methods taking `&self` - sub_ty - } else { - // Trait methods taking `self` - arg_ty - } && impl_ty.is_ref() - && cx.tcx.infer_ctxt().enter(|infcx| - infcx - .type_implements_trait(trait_id, impl_ty, subs, cx.param_env) - .must_apply_modulo_regions() + let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i + 1]; + if let ty::Param(param_ty) = ty.kind() { + needless_borrow_impl_arg_position(cx, parent, i + 1, *param_ty, e, precedence, msrv) + } else { + ty_auto_deref_stability( + cx, + cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i + 1)), + precedence, ) - { - Position::MethodReceiverRefImpl - } else { - Position::MethodReceiver - } - } else { - let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i]; - if let ty::Param(param_ty) = ty.kind() { - needless_borrow_impl_arg_position(cx, parent, i, *param_ty, e, precedence, msrv) - } else { - ty_auto_deref_stability( - cx, - cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)), - precedence, - ) - .position_for_arg() - } + .position_for_arg() } }) }, diff --git a/clippy_lints/src/infinite_iter.rs b/clippy_lints/src/infinite_iter.rs index fca3cb46a2e9..d55a8e1ead17 100644 --- a/clippy_lints/src/infinite_iter.rs +++ b/clippy_lints/src/infinite_iter.rs @@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for InfiniteIter { MaybeInfinite => (MAYBE_INFINITE_ITER, "possible infinite iteration detected"), Finite => { return; - }, + } }; span_lint(cx, lint, expr.span, msg); } @@ -229,11 +229,9 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { return MaybeInfinite.and(is_infinite(cx, receiver)); } } - if method.ident.name == sym!(last) { - let not_double_ended = cx - .tcx - .get_diagnostic_item(sym::DoubleEndedIterator) - .map_or(false, |id| { + if method.ident.name == sym!(last) && args.is_empty() { + let not_double_ended = + cx.tcx.get_diagnostic_item(sym::DoubleEndedIterator).map_or(false, |id| { !implements_trait(cx, cx.typeck_results().expr_ty(receiver), id, &[]) }); if not_double_ended { diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 25f366bfe6a8..3cbdaff407b0 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -370,7 +370,7 @@ fn check_for_is_empty<'tcx>( } fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) { - if let (&ExprKind::MethodCall(method_path, receiver, ..), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) { + if let (&ExprKind::MethodCall(method_path, receiver, args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) { // check if we are in an is_empty() method if let Some(name) = get_item_name(cx, method) { if name.as_str() == "is_empty" { @@ -378,7 +378,7 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_> } } - check_len(cx, span, method_path.ident.name, receiver, &lit.node, op, compare_to); + check_len(cx, span, method_path.ident.name, receiver, args, &lit.node, op, compare_to); } else { check_empty_expr(cx, span, method, lit, op); } @@ -389,6 +389,7 @@ fn check_len( span: Span, method_name: Symbol, receiver: &Expr<'_>, + args: &[Expr<'_>], lit: &LitKind, op: &str, compare_to: u32, @@ -399,7 +400,7 @@ fn check_len( return; } - if method_name == sym::len && has_is_empty(cx, receiver) { + if method_name == sym::len && args.is_empty() && has_is_empty(cx, receiver) { let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/clone_on_copy.rs b/clippy_lints/src/methods/clone_on_copy.rs index 9ae6297ec2f6..25a9e6dafea1 100644 --- a/clippy_lints/src/methods/clone_on_copy.rs +++ b/clippy_lints/src/methods/clone_on_copy.rs @@ -21,10 +21,7 @@ pub(super) fn check( receiver: &Expr<'_>, args: &[Expr<'_>], ) { - let arg = match args { - [] if method_name == sym::clone => receiver, - _ => return, - }; + let arg = if method_name == sym::clone && args.is_empty() { receiver } else { return }; if cx .typeck_results() .type_dependent_def_id(expr.hir_id) diff --git a/clippy_lints/src/methods/clone_on_ref_ptr.rs b/clippy_lints/src/methods/clone_on_ref_ptr.rs index 7098d564cfc8..f82ca8912006 100644 --- a/clippy_lints/src/methods/clone_on_ref_ptr.rs +++ b/clippy_lints/src/methods/clone_on_ref_ptr.rs @@ -20,8 +20,7 @@ pub(super) fn check( if !(args.is_empty() && method_name == sym::clone) { return; } - let arg = receiver; - let obj_ty = cx.typeck_results().expr_ty(arg).peel_refs(); + let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs(); if let ty::Adt(_, subst) = obj_ty.kind() { let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) { @@ -34,7 +33,7 @@ pub(super) fn check( return; }; - let snippet = snippet_with_macro_callsite(cx, arg.span, ".."); + let snippet = snippet_with_macro_callsite(cx, receiver.span, ".."); span_lint_and_sugg( cx, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 16fdd36c0260..fc9ba15d82a4 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3381,7 +3381,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { impl Methods { #[allow(clippy::too_many_lines)] fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let Some((name, recv, [args @ ..], span)) = method_call(expr) { + if let Some((name, recv, args, span)) = method_call(expr) { match (name, args) { ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => { zst_offset::check(cx, expr, recv); @@ -3485,7 +3485,7 @@ impl Methods { } }, ("last", []) | ("skip", [_]) => { - if let Some((name2, recv2, [args2 @ ..], _span2)) = method_call(recv) { + if let Some((name2, recv2, args2, _span2)) = method_call(recv) { if let ("cloned", []) = (name2, args2) { iter_overeager_cloned::check(cx, expr, recv, recv2, false, false); } @@ -3500,7 +3500,7 @@ impl Methods { } else { map_err_ignore::check(cx, expr, m_arg); } - if let Some((name, recv2, [args @ ..], span2)) = method_call(recv) { + if let Some((name, recv2, args, span2)) = method_call(recv) { match (name, args) { ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv), ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv), @@ -3520,7 +3520,7 @@ impl Methods { manual_ok_or::check(cx, expr, recv, def, map); }, ("next", []) => { - if let Some((name2, recv2, [args2 @ ..], _)) = method_call(recv) { + if let Some((name2, recv2, args2, _)) = method_call(recv) { match (name2, args2) { ("cloned", []) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false), ("filter", [arg]) => filter_next::check(cx, expr, recv2, arg), @@ -3593,7 +3593,7 @@ impl Methods { }, ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg), ("take", [_arg]) => { - if let Some((name2, recv2, [args2 @ ..], _span2)) = method_call(recv) { + if let Some((name2, recv2, args2, _span2)) = method_call(recv) { if let ("cloned", []) = (name2, args2) { iter_overeager_cloned::check(cx, expr, recv, recv2, false, false); } diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs index c618f6b5d926..44b21e7b080d 100644 --- a/clippy_lints/src/minmax.rs +++ b/clippy_lints/src/minmax.rs @@ -109,14 +109,12 @@ fn fetch_const<'a>( args: &'a [Expr<'a>], m: MinMax, ) -> Option<(MinMax, Constant, &'a Expr<'a>)> { - if (receiver.is_some() && args.len() != 1) || (receiver.is_none() && args.len() != 2) { + let mut args = receiver.into_iter().chain(args.into_iter()); + let arg0 = args.next()?; + let arg1 = args.next()?; + if args.next().is_some() { return None; } - let (arg0, arg1) = if let Some(receiver) = receiver { - (receiver, &args[0]) - } else { - (&args[0], &args[1]) - }; constant_simple(cx, cx.typeck_results(), arg0).map_or_else( || constant_simple(cx, cx.typeck_results(), arg1).map(|c| (m, c, arg0)), |c| { diff --git a/clippy_lints/src/unused_peekable.rs b/clippy_lints/src/unused_peekable.rs index 7fbfecf96ec3..cfc181e435b9 100644 --- a/clippy_lints/src/unused_peekable.rs +++ b/clippy_lints/src/unused_peekable.rs @@ -150,7 +150,7 @@ impl<'tcx> Visitor<'_> for PeekableVisitor<'_, 'tcx> { .. }, self_arg, - [remaining_args @ ..], + remaining_args, _, ) => { let method_name = method_name_ident.name.as_str(); From fea1c5f5c82318102d759bbc83d4cc48aa876db9 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Fri, 2 Sep 2022 22:48:14 +0900 Subject: [PATCH 4210/5092] refactor: remove unnecessary variables --- .../src/diagnostics/region_errors.rs | 3 +- compiler/rustc_hir/src/hir.rs | 6 +- compiler/rustc_lint/src/array_into_iter.rs | 3 +- compiler/rustc_lint/src/methods.rs | 6 +- compiler/rustc_mir_build/src/thir/cx/expr.rs | 3 +- compiler/rustc_passes/src/liveness.rs | 7 +- compiler/rustc_typeck/src/check/demand.rs | 11 +-- compiler/rustc_typeck/src/check/expr.rs | 9 +- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 10 +- .../clippy/clippy_lints/src/dereference.rs | 94 +++++++++---------- .../clippy/clippy_lints/src/infinite_iter.rs | 10 +- src/tools/clippy/clippy_lints/src/len_zero.rs | 7 +- .../clippy_lints/src/methods/clone_on_copy.rs | 5 +- .../src/methods/clone_on_ref_ptr.rs | 5 +- .../clippy/clippy_lints/src/methods/mod.rs | 10 +- src/tools/clippy/clippy_lints/src/minmax.rs | 10 +- .../clippy_lints/src/unused_peekable.rs | 2 +- 17 files changed, 93 insertions(+), 108 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 31233062e9b3..10b4633a3b21 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -906,7 +906,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if let hir::ExprKind::Closure(hir::Closure { capture_clause: hir::CaptureBy::Ref, .. - }) = arg.kind { + }) = arg.kind + { closure_span = Some(arg.span.shrink_to_lo()); break; } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 3367df56a297..01df564a7c2e 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1881,11 +1881,11 @@ pub enum ExprKind<'hir> { /// /// The `PathSegment` represents the method name and its generic arguments /// (within the angle brackets). - /// The first element of the `&[Expr]` is the expression that evaluates + /// The `&Expr` is the expression that evaluates /// to the object on which the method is being called on (the receiver), - /// and the remaining elements are the rest of the arguments. + /// and the `&[Expr]` is the rest of the arguments. /// Thus, `x.foo::(a, b, c, d)` is represented as - /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d], span)`. + /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, x, [a, b, c, d], span)`. /// The final `Span` represents the span of the function and arguments /// (e.g. `foo::(a, b, c, d)` in `x.foo::(a, b, c, d)` /// diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs index fb79daf29ee1..b97f8acb37f8 100644 --- a/compiler/rustc_lint/src/array_into_iter.rs +++ b/compiler/rustc_lint/src/array_into_iter.rs @@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter { } // We only care about method call expressions. - if let hir::ExprKind::MethodCall(call, receiver, ..) = &expr.kind { + if let hir::ExprKind::MethodCall(call, receiver_arg, ..) = &expr.kind { if call.ident.name != sym::into_iter { return; } @@ -75,7 +75,6 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter { }; // As this is a method call expression, we have at least one argument. - let receiver_arg = receiver; let receiver_ty = cx.typeck_results().expr_ty(receiver_arg); let adjustments = cx.typeck_results().expr_adjustments(receiver_arg); diff --git a/compiler/rustc_lint/src/methods.rs b/compiler/rustc_lint/src/methods.rs index 646812589e3c..5f7f03480c04 100644 --- a/compiler/rustc_lint/src/methods.rs +++ b/compiler/rustc_lint/src/methods.rs @@ -63,15 +63,13 @@ impl<'tcx> LateLintPass<'tcx> for TemporaryCStringAsPtr { } match first_method_call(expr) { - Some((path, receiver)) if path.ident.name == sym::as_ptr => { - let unwrap_arg = receiver; + Some((path, unwrap_arg)) if path.ident.name == sym::as_ptr => { let as_ptr_span = path.ident.span; match first_method_call(unwrap_arg) { Some((path, receiver)) if path.ident.name == sym::unwrap || path.ident.name == sym::expect => { - let source_arg = receiver; - lint_cstring_as_ptr(cx, as_ptr_span, source_arg, unwrap_arg); + lint_cstring_as_ptr(cx, as_ptr_span, receiver, unwrap_arg); } _ => return, } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index b4b5a9d868d9..d059877f8e71 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -267,7 +267,8 @@ impl<'tcx> Cx<'tcx> { // When we apply adjustments to the receiver, use the span of // the overall method call for better diagnostics. args[0] // is guaranteed to exist, since a method call always has a receiver. - let old_adjustment_span = self.adjustment_span.replace((receiver.hir_id, expr_span)); + let old_adjustment_span = + self.adjustment_span.replace((receiver.hir_id, expr_span)); info!("Using method span: {:?}", expr.span); let args = std::iter::once(receiver) .chain(args.iter()) diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 214d357cae00..a9ea79c2fe39 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1041,10 +1041,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprKind::MethodCall(.., receiver, ref args, _) => { let succ = self.check_is_ty_uninhabited(expr, succ); - std::iter::once(receiver) - .chain(args.iter()) + let succ = args + .iter() .rev() - .fold(succ, |succ, expr| self.propagate_through_expr(expr, succ)) + .fold(succ, |succ, expr| self.propagate_through_expr(expr, succ)); + self.propagate_through_expr(receiver, succ) } hir::ExprKind::Tup(ref exprs) => self.propagate_through_exprs(exprs, succ), diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index 7ea3ed06e612..d078252ebd4e 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -770,16 +770,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let hir::ExprKind::MethodCall(ref segment, receiver, args, _) = expr.kind { let clone_trait = self.tcx.require_lang_item(LangItem::Clone, Some(segment.ident.span)); - if let (true, Some(true), sym::clone) = ( - args.is_empty(), - self.typeck_results.borrow().type_dependent_def_id(expr.hir_id).map( + if args.is_empty() + && self.typeck_results.borrow().type_dependent_def_id(expr.hir_id).map( |did| { let ai = self.tcx.associated_item(did); ai.trait_container(self.tcx) == Some(clone_trait) }, - ), - segment.ident.name, - ) { + ) == Some(true) + && segment.ident.name == sym::clone + { // If this expression had a clone call when suggesting borrowing // we want to suggest removing it because it'd now be unnecessary. sugg_sp = receiver.span; diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 5c7b8121a61e..e4141647d7d2 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1195,14 +1195,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, expr: &'tcx hir::Expr<'tcx>, segment: &hir::PathSegment<'_>, - receiver: &'tcx hir::Expr<'tcx>, + rcvr: &'tcx hir::Expr<'tcx>, args: &'tcx [hir::Expr<'tcx>], expected: Expectation<'tcx>, ) -> Ty<'tcx> { - let rcvr = &receiver; let rcvr_t = self.check_expr(&rcvr); // no need to check for bot/err -- callee does that - let rcvr_t = self.structurally_resolved_type(receiver.span, rcvr_t); + let rcvr_t = self.structurally_resolved_type(rcvr.span, rcvr_t); let span = segment.ident.span; let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr, args) { @@ -1219,9 +1218,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, rcvr_t, segment.ident, - SelfSource::MethodCall(receiver), + SelfSource::MethodCall(rcvr), error, - Some((receiver, args)), + Some((rcvr, args)), ) { err.emit(); } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 3805de3cd4df..9157b83330dd 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -1913,14 +1913,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .enumerate() .filter(|(_, ty)| find_param_in_ty(**ty, param_to_point_at)) .collect(); - let args: Vec<&'tcx hir::Expr<'tcx>> = if let Some(receiver) = receiver { - std::iter::once(receiver).chain(args.iter()).collect() - } else { - args.iter().collect() - }; - // If there's one field that references the given generic, great! - if let [(idx, _)] = args_referencing_param.as_slice() && let Some(arg) = args.get(*idx) { + if let [(idx, _)] = args_referencing_param.as_slice() + && let Some(arg) = receiver + .map_or(args.get(*idx), |rcvr| if *idx == 0 { Some(rcvr) } else { args.get(*idx - 1) }) { error.obligation.cause.span = arg.span.find_ancestor_in_same_ctxt(error.obligation.cause.span).unwrap_or(arg.span); error.obligation.cause.map_code(|parent_code| { ObligationCauseCode::FunctionArgumentObligation { diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index fd6ed36cb192..6ee9e2e9754c 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -798,57 +798,55 @@ fn walk_parents<'tcx>( }), ExprKind::MethodCall(_, receiver, args, _) => { let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap(); - std::iter::once(receiver) - .chain(args.iter()) + if receiver.hir_id == child_id { + // Check for calls to trait methods where the trait is implemented on a reference. + // Two cases need to be handled: + // * `self` methods on `&T` will never have auto-borrow + // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take + // priority. + if e.hir_id != child_id { + return Some(Position::ReborrowStable(precedence)) + } else if let Some(trait_id) = cx.tcx.trait_of_item(id) + && let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e)) + && let ty::Ref(_, sub_ty, _) = *arg_ty.kind() + && let subs = match cx + .typeck_results() + .node_substs_opt(parent.hir_id) + .and_then(|subs| subs.get(1..)) + { + Some(subs) => cx.tcx.mk_substs(subs.iter().copied()), + None => cx.tcx.mk_substs(std::iter::empty::>()), + } && let impl_ty = if cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref() { + // Trait methods taking `&self` + sub_ty + } else { + // Trait methods taking `self` + arg_ty + } && impl_ty.is_ref() + && cx.tcx.infer_ctxt().enter(|infcx| + infcx + .type_implements_trait(trait_id, impl_ty, subs, cx.param_env) + .must_apply_modulo_regions() + ) + { + return Some(Position::MethodReceiverRefImpl) + } else { + return Some(Position::MethodReceiver) + } + } + args.iter() .position(|arg| arg.hir_id == child_id) .map(|i| { - if i == 0 { - // Check for calls to trait methods where the trait is implemented on a reference. - // Two cases need to be handled: - // * `self` methods on `&T` will never have auto-borrow - // * `&self` methods on `&T` can have auto-borrow, but `&self` methods on `T` will take - // priority. - if e.hir_id != child_id { - Position::ReborrowStable(precedence) - } else if let Some(trait_id) = cx.tcx.trait_of_item(id) - && let arg_ty = cx.tcx.erase_regions(cx.typeck_results().expr_ty_adjusted(e)) - && let ty::Ref(_, sub_ty, _) = *arg_ty.kind() - && let subs = match cx - .typeck_results() - .node_substs_opt(parent.hir_id) - .and_then(|subs| subs.get(1..)) - { - Some(subs) => cx.tcx.mk_substs(subs.iter().copied()), - None => cx.tcx.mk_substs(std::iter::empty::>()), - } && let impl_ty = if cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref() { - // Trait methods taking `&self` - sub_ty - } else { - // Trait methods taking `self` - arg_ty - } && impl_ty.is_ref() - && cx.tcx.infer_ctxt().enter(|infcx| - infcx - .type_implements_trait(trait_id, impl_ty, subs, cx.param_env) - .must_apply_modulo_regions() + let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i + 1]; + if let ty::Param(param_ty) = ty.kind() { + needless_borrow_impl_arg_position(cx, parent, i + 1, *param_ty, e, precedence, msrv) + } else { + ty_auto_deref_stability( + cx, + cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i + 1)), + precedence, ) - { - Position::MethodReceiverRefImpl - } else { - Position::MethodReceiver - } - } else { - let ty = cx.tcx.fn_sig(id).skip_binder().inputs()[i]; - if let ty::Param(param_ty) = ty.kind() { - needless_borrow_impl_arg_position(cx, parent, i, *param_ty, e, precedence, msrv) - } else { - ty_auto_deref_stability( - cx, - cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)), - precedence, - ) - .position_for_arg() - } + .position_for_arg() } }) }, diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs index fca3cb46a2e9..d55a8e1ead17 100644 --- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs +++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs @@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for InfiniteIter { MaybeInfinite => (MAYBE_INFINITE_ITER, "possible infinite iteration detected"), Finite => { return; - }, + } }; span_lint(cx, lint, expr.span, msg); } @@ -229,11 +229,9 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { return MaybeInfinite.and(is_infinite(cx, receiver)); } } - if method.ident.name == sym!(last) { - let not_double_ended = cx - .tcx - .get_diagnostic_item(sym::DoubleEndedIterator) - .map_or(false, |id| { + if method.ident.name == sym!(last) && args.is_empty() { + let not_double_ended = + cx.tcx.get_diagnostic_item(sym::DoubleEndedIterator).map_or(false, |id| { !implements_trait(cx, cx.typeck_results().expr_ty(receiver), id, &[]) }); if not_double_ended { diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 25f366bfe6a8..3cbdaff407b0 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -370,7 +370,7 @@ fn check_for_is_empty<'tcx>( } fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) { - if let (&ExprKind::MethodCall(method_path, receiver, ..), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) { + if let (&ExprKind::MethodCall(method_path, receiver, args, _), &ExprKind::Lit(ref lit)) = (&method.kind, &lit.kind) { // check if we are in an is_empty() method if let Some(name) = get_item_name(cx, method) { if name.as_str() == "is_empty" { @@ -378,7 +378,7 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_> } } - check_len(cx, span, method_path.ident.name, receiver, &lit.node, op, compare_to); + check_len(cx, span, method_path.ident.name, receiver, args, &lit.node, op, compare_to); } else { check_empty_expr(cx, span, method, lit, op); } @@ -389,6 +389,7 @@ fn check_len( span: Span, method_name: Symbol, receiver: &Expr<'_>, + args: &[Expr<'_>], lit: &LitKind, op: &str, compare_to: u32, @@ -399,7 +400,7 @@ fn check_len( return; } - if method_name == sym::len && has_is_empty(cx, receiver) { + if method_name == sym::len && args.is_empty() && has_is_empty(cx, receiver) { let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs index 9ae6297ec2f6..25a9e6dafea1 100644 --- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs +++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs @@ -21,10 +21,7 @@ pub(super) fn check( receiver: &Expr<'_>, args: &[Expr<'_>], ) { - let arg = match args { - [] if method_name == sym::clone => receiver, - _ => return, - }; + let arg = if method_name == sym::clone && args.is_empty() { receiver } else { return }; if cx .typeck_results() .type_dependent_def_id(expr.hir_id) diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs index 7098d564cfc8..f82ca8912006 100644 --- a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs @@ -20,8 +20,7 @@ pub(super) fn check( if !(args.is_empty() && method_name == sym::clone) { return; } - let arg = receiver; - let obj_ty = cx.typeck_results().expr_ty(arg).peel_refs(); + let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs(); if let ty::Adt(_, subst) = obj_ty.kind() { let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) { @@ -34,7 +33,7 @@ pub(super) fn check( return; }; - let snippet = snippet_with_macro_callsite(cx, arg.span, ".."); + let snippet = snippet_with_macro_callsite(cx, receiver.span, ".."); span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 16fdd36c0260..fc9ba15d82a4 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -3381,7 +3381,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { impl Methods { #[allow(clippy::too_many_lines)] fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let Some((name, recv, [args @ ..], span)) = method_call(expr) { + if let Some((name, recv, args, span)) = method_call(expr) { match (name, args) { ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => { zst_offset::check(cx, expr, recv); @@ -3485,7 +3485,7 @@ impl Methods { } }, ("last", []) | ("skip", [_]) => { - if let Some((name2, recv2, [args2 @ ..], _span2)) = method_call(recv) { + if let Some((name2, recv2, args2, _span2)) = method_call(recv) { if let ("cloned", []) = (name2, args2) { iter_overeager_cloned::check(cx, expr, recv, recv2, false, false); } @@ -3500,7 +3500,7 @@ impl Methods { } else { map_err_ignore::check(cx, expr, m_arg); } - if let Some((name, recv2, [args @ ..], span2)) = method_call(recv) { + if let Some((name, recv2, args, span2)) = method_call(recv) { match (name, args) { ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv), ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv), @@ -3520,7 +3520,7 @@ impl Methods { manual_ok_or::check(cx, expr, recv, def, map); }, ("next", []) => { - if let Some((name2, recv2, [args2 @ ..], _)) = method_call(recv) { + if let Some((name2, recv2, args2, _)) = method_call(recv) { match (name2, args2) { ("cloned", []) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false), ("filter", [arg]) => filter_next::check(cx, expr, recv2, arg), @@ -3593,7 +3593,7 @@ impl Methods { }, ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg), ("take", [_arg]) => { - if let Some((name2, recv2, [args2 @ ..], _span2)) = method_call(recv) { + if let Some((name2, recv2, args2, _span2)) = method_call(recv) { if let ("cloned", []) = (name2, args2) { iter_overeager_cloned::check(cx, expr, recv, recv2, false, false); } diff --git a/src/tools/clippy/clippy_lints/src/minmax.rs b/src/tools/clippy/clippy_lints/src/minmax.rs index c618f6b5d926..44b21e7b080d 100644 --- a/src/tools/clippy/clippy_lints/src/minmax.rs +++ b/src/tools/clippy/clippy_lints/src/minmax.rs @@ -109,14 +109,12 @@ fn fetch_const<'a>( args: &'a [Expr<'a>], m: MinMax, ) -> Option<(MinMax, Constant, &'a Expr<'a>)> { - if (receiver.is_some() && args.len() != 1) || (receiver.is_none() && args.len() != 2) { + let mut args = receiver.into_iter().chain(args.into_iter()); + let arg0 = args.next()?; + let arg1 = args.next()?; + if args.next().is_some() { return None; } - let (arg0, arg1) = if let Some(receiver) = receiver { - (receiver, &args[0]) - } else { - (&args[0], &args[1]) - }; constant_simple(cx, cx.typeck_results(), arg0).map_or_else( || constant_simple(cx, cx.typeck_results(), arg1).map(|c| (m, c, arg0)), |c| { diff --git a/src/tools/clippy/clippy_lints/src/unused_peekable.rs b/src/tools/clippy/clippy_lints/src/unused_peekable.rs index 7fbfecf96ec3..cfc181e435b9 100644 --- a/src/tools/clippy/clippy_lints/src/unused_peekable.rs +++ b/src/tools/clippy/clippy_lints/src/unused_peekable.rs @@ -150,7 +150,7 @@ impl<'tcx> Visitor<'_> for PeekableVisitor<'_, 'tcx> { .. }, self_arg, - [remaining_args @ ..], + remaining_args, _, ) => { let method_name = method_name_ident.name.as_str(); From 8931da40e304f071d01ed59a312561a7d0a6e024 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Mon, 5 Sep 2022 14:26:00 +0900 Subject: [PATCH 4211/5092] use `propagate_through_exprs` instead of `propagate_through_expr` fix `ExprKind` static_assert_size fix hir-stats --- clippy_lints/src/eta_reduction.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs index 1c0a93c71fde..1342a4697b99 100644 --- a/clippy_lints/src/eta_reduction.rs +++ b/clippy_lints/src/eta_reduction.rs @@ -206,12 +206,8 @@ fn check_inputs( _ => false, } }; - if let Some(receiver) = receiver { - std::iter::zip(params, std::iter::once(receiver).chain(call_args.iter())) - .all(|(param, arg)| check_inputs(param, arg)) - } else { - std::iter::zip(params, call_args).all(|(param, arg)| check_inputs(param, arg)) - } + std::iter::zip(params, receiver.into_iter().chain(call_args.iter())) + .all(|(param, arg)| check_inputs(param, arg)) } fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tcx>) -> bool { From 9cde34e1807208493b3975c155e0c5389820a8ce Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Mon, 5 Sep 2022 14:26:00 +0900 Subject: [PATCH 4212/5092] use `propagate_through_exprs` instead of `propagate_through_expr` fix `ExprKind` static_assert_size fix hir-stats --- .../src/diagnostics/region_errors.rs | 2 - compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_passes/src/liveness.rs | 5 +-- src/test/ui/stats/hir-stats.stderr | 44 +++++++++---------- .../clippy/clippy_lints/src/eta_reduction.rs | 8 +--- 5 files changed, 26 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 10b4633a3b21..9615025fa576 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -900,8 +900,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let mut closure_span = None::; match expr.kind { hir::ExprKind::MethodCall(.., args, _) => { - // only the first closre parameter of the method. args[0] is MethodCall PathSegment - for arg in args { if let hir::ExprKind::Closure(hir::Closure { capture_clause: hir::CaptureBy::Ref, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 01df564a7c2e..8fa5d610ffae 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3498,7 +3498,7 @@ mod size_asserts { static_assert_size!(Block<'_>, 48); static_assert_size!(Body<'_>, 32); static_assert_size!(Expr<'_>, 64); - static_assert_size!(ExprKind<'_>, 40); + static_assert_size!(ExprKind<'_>, 48); static_assert_size!(FnDecl<'_>, 40); static_assert_size!(ForeignItem<'_>, 72); static_assert_size!(ForeignItemKind<'_>, 40); diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index a9ea79c2fe39..6a4cd79cde71 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1041,10 +1041,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprKind::MethodCall(.., receiver, ref args, _) => { let succ = self.check_is_ty_uninhabited(expr, succ); - let succ = args - .iter() - .rev() - .fold(succ, |succ, expr| self.propagate_through_expr(expr, succ)); + let succ = self.propagate_through_exprs(args, succ); self.propagate_through_expr(receiver, succ) } diff --git a/src/test/ui/stats/hir-stats.stderr b/src/test/ui/stats/hir-stats.stderr index 78f709975556..0a736f7be834 100644 --- a/src/test/ui/stats/hir-stats.stderr +++ b/src/test/ui/stats/hir-stats.stderr @@ -121,15 +121,15 @@ hir-stats ---------------------------------------------------------------- hir-stats ForeignItemRef 24 ( 0.2%) 1 24 hir-stats Mod 32 ( 0.3%) 1 32 hir-stats ExprField 40 ( 0.4%) 1 40 -hir-stats TraitItemRef 56 ( 0.6%) 2 28 +hir-stats TraitItemRef 56 ( 0.5%) 2 28 hir-stats Param 64 ( 0.6%) 2 32 hir-stats Local 64 ( 0.6%) 1 64 hir-stats InlineAsm 72 ( 0.7%) 1 72 hir-stats ImplItemRef 72 ( 0.7%) 2 36 -hir-stats FieldDef 96 ( 1.0%) 2 48 -hir-stats Arm 96 ( 1.0%) 2 48 -hir-stats Body 96 ( 1.0%) 3 32 -hir-stats Stmt 96 ( 1.0%) 3 32 +hir-stats FieldDef 96 ( 0.9%) 2 48 +hir-stats Arm 96 ( 0.9%) 2 48 +hir-stats Body 96 ( 0.9%) 3 32 +hir-stats Stmt 96 ( 0.9%) 3 32 hir-stats - Local 32 ( 0.3%) 1 hir-stats - Semi 32 ( 0.3%) 1 hir-stats - Expr 32 ( 0.3%) 1 @@ -144,34 +144,34 @@ hir-stats GenericBound 192 ( 1.9%) 4 48 hir-stats - Trait 192 ( 1.9%) 4 hir-stats WherePredicate 216 ( 2.1%) 3 72 hir-stats - BoundPredicate 216 ( 2.1%) 3 -hir-stats Block 288 ( 2.9%) 6 48 -hir-stats GenericParam 400 ( 4.0%) 5 80 -hir-stats Pat 440 ( 4.4%) 5 88 +hir-stats Block 288 ( 2.8%) 6 48 +hir-stats GenericParam 400 ( 3.9%) 5 80 +hir-stats Pat 440 ( 4.3%) 5 88 hir-stats - Wild 88 ( 0.9%) 1 hir-stats - Struct 88 ( 0.9%) 1 hir-stats - Binding 264 ( 2.6%) 3 hir-stats Generics 560 ( 5.5%) 10 56 -hir-stats Expr 672 ( 6.7%) 12 56 -hir-stats - Path 56 ( 0.6%) 1 -hir-stats - Struct 56 ( 0.6%) 1 -hir-stats - Match 56 ( 0.6%) 1 -hir-stats - InlineAsm 56 ( 0.6%) 1 -hir-stats - Lit 112 ( 1.1%) 2 -hir-stats - Block 336 ( 3.3%) 6 -hir-stats Item 960 ( 9.5%) 12 80 +hir-stats Expr 768 ( 7.5%) 12 64 +hir-stats - Path 64 ( 0.6%) 1 +hir-stats - Struct 64 ( 0.6%) 1 +hir-stats - Match 64 ( 0.6%) 1 +hir-stats - InlineAsm 64 ( 0.6%) 1 +hir-stats - Lit 128 ( 1.3%) 2 +hir-stats - Block 384 ( 3.8%) 6 +hir-stats Item 960 ( 9.4%) 12 80 hir-stats - Trait 80 ( 0.8%) 1 hir-stats - Enum 80 ( 0.8%) 1 hir-stats - ExternCrate 80 ( 0.8%) 1 hir-stats - ForeignMod 80 ( 0.8%) 1 hir-stats - Impl 80 ( 0.8%) 1 hir-stats - Fn 160 ( 1.6%) 2 -hir-stats - Use 400 ( 4.0%) 5 -hir-stats Ty 1_080 (10.7%) 15 72 +hir-stats - Use 400 ( 3.9%) 5 +hir-stats Ty 1_080 (10.6%) 15 72 hir-stats - Ptr 72 ( 0.7%) 1 hir-stats - Rptr 72 ( 0.7%) 1 -hir-stats - Path 936 ( 9.3%) 13 -hir-stats Path 1_536 (15.2%) 32 48 -hir-stats PathSegment 2_240 (22.2%) 40 56 +hir-stats - Path 936 ( 9.2%) 13 +hir-stats Path 1_536 (15.1%) 32 48 +hir-stats PathSegment 2_240 (22.0%) 40 56 hir-stats ---------------------------------------------------------------- -hir-stats Total 10_104 +hir-stats Total 10_200 hir-stats diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index 1c0a93c71fde..1342a4697b99 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -206,12 +206,8 @@ fn check_inputs( _ => false, } }; - if let Some(receiver) = receiver { - std::iter::zip(params, std::iter::once(receiver).chain(call_args.iter())) - .all(|(param, arg)| check_inputs(param, arg)) - } else { - std::iter::zip(params, call_args).all(|(param, arg)| check_inputs(param, arg)) - } + std::iter::zip(params, receiver.into_iter().chain(call_args.iter())) + .all(|(param, arg)| check_inputs(param, arg)) } fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tcx>) -> bool { From a42c0d79da8e04d6c7bd17363efe4234e2a9547c Mon Sep 17 00:00:00 2001 From: 111 Date: Mon, 5 Sep 2022 23:18:18 +0800 Subject: [PATCH 4213/5092] fix comment --- compiler/rustc_error_messages/locales/en-US/middle.ftl | 2 +- compiler/rustc_middle/src/error.rs | 2 +- compiler/rustc_middle/src/traits/query.rs | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/middle.ftl b/compiler/rustc_error_messages/locales/en-US/middle.ftl index 3a55064c7077..ed834886453c 100644 --- a/compiler/rustc_error_messages/locales/en-US/middle.ftl +++ b/compiler/rustc_error_messages/locales/en-US/middle.ftl @@ -1,6 +1,6 @@ middle_drop_check_overflow = overflow while adding drop-check rules for {$ty} - .note = {$note} + .note = overflowed on {$overflow_ty} middle_opaque_hidden_type_mismatch = concrete type differs from previous defining opaque type use diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index 0dfe6374cf30..18b31a75bcc0 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -10,7 +10,7 @@ pub struct DropCheckOverflow<'tcx> { #[primary_span] pub span: Span, pub ty: Ty<'tcx>, - pub note: String, + pub overflow_ty: Ty<'tcx>, } #[derive(SessionDiagnostic)] diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 8002f9286130..0e6cacb9fd0f 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -117,8 +117,7 @@ pub struct DropckOutlivesResult<'tcx> { impl<'tcx> DropckOutlivesResult<'tcx> { pub fn report_overflows(&self, tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) { if let Some(overflow_ty) = self.overflows.get(0) { - let note = format!("overflowed on {}", overflow_ty); - tcx.sess.emit_err(DropCheckOverflow { span, ty, note }); + tcx.sess.emit_err(DropCheckOverflow { span, ty, overflow_ty: *overflow_ty }); } } From 850090d99c81dde7615e2a7e2111c09650868a48 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Mon, 5 Sep 2022 08:37:20 -0700 Subject: [PATCH 4214/5092] Avoid UB in the Windows filesystem code in... bootstrap? --- src/bootstrap/Cargo.toml | 1 + src/bootstrap/util.rs | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 2dad41bb18fc..95e711737738 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -67,6 +67,7 @@ features = [ "psapi", "impl-default", "timezoneapi", + "winbase", ] [dev-dependencies] diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 3a00e258e00e..0ebabbd5ca5c 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -197,9 +197,11 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> { ptr::null_mut(), ); - let mut data = [0u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize]; - let db = data.as_mut_ptr() as *mut REPARSE_MOUNTPOINT_DATA_BUFFER; - let buf = &mut (*db).ReparseTarget as *mut u16; + #[repr(C, align(8))] + struct Align8(T); + let mut data = Align8([0u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize]); + let db = data.0.as_mut_ptr() as *mut REPARSE_MOUNTPOINT_DATA_BUFFER; + let buf = core::ptr::addr_of_mut!((*db).ReparseTarget) as *mut u16; let mut i = 0; // FIXME: this conversion is very hacky let v = br"\??\"; @@ -219,7 +221,7 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> { let res = DeviceIoControl( h as *mut _, FSCTL_SET_REPARSE_POINT, - data.as_ptr() as *mut _, + db.cast(), (*db).ReparseDataLength + 8, ptr::null_mut(), 0, From 1524b59444109cf71916653d7906e4d41bd4ba6e Mon Sep 17 00:00:00 2001 From: Jhonny Bill Mena Date: Mon, 5 Sep 2022 11:42:48 -0400 Subject: [PATCH 4215/5092] UPDATE - avoid exposing source_map methods from Handler --- compiler/rustc_attr/src/builtin.rs | 2 +- .../rustc_attr/src/session_diagnostics.rs | 11 +++++----- compiler/rustc_errors/src/lib.rs | 22 ------------------- compiler/rustc_typeck/src/astconv/errors.rs | 1 + compiler/rustc_typeck/src/errors.rs | 11 +++++----- 5 files changed, 13 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index a8ed510866d8..faba9856f02a 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -63,7 +63,7 @@ fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) { sess.emit_err(session_diagnostics::MultipleStabilityLevels { span }); } AttrError::UnsupportedLiteral(reason, is_bytestr) => { - sess.emit_err(session_diagnostics::UnsupportedLiteral { span, reason, is_bytestr }); + sess.emit_err(session_diagnostics::UnsupportedLiteral { span, reason, is_bytestr, source_map: sess.source_map() }); } } } diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs index f74540e9655b..3f5a51fbd838 100644 --- a/compiler/rustc_attr/src/session_diagnostics.rs +++ b/compiler/rustc_attr/src/session_diagnostics.rs @@ -6,7 +6,7 @@ use rustc_errors::{ }; use rustc_macros::SessionDiagnostic; use rustc_session::SessionDiagnostic; -use rustc_span::{Span, Symbol}; +use rustc_span::{Span, Symbol, source_map::SourceMap}; use crate::UnsupportedLiteralReason; @@ -202,13 +202,14 @@ pub(crate) struct InvalidReprHintNoValue { } // Error code: E0565 -pub(crate) struct UnsupportedLiteral { +pub(crate) struct UnsupportedLiteral<'a> { pub span: Span, pub reason: UnsupportedLiteralReason, pub is_bytestr: bool, + pub source_map: &'a SourceMap, } -impl<'a> SessionDiagnostic<'a> for UnsupportedLiteral { +impl<'a> SessionDiagnostic<'a> for UnsupportedLiteral<'a> { fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> { let mut diag = handler.struct_span_err_with_code( self.span, @@ -225,10 +226,8 @@ impl<'a> SessionDiagnostic<'a> for UnsupportedLiteral { error_code!(E0565), ); if self.is_bytestr { - let start_point = handler.span_start_point_from_emitter(self.span).unwrap_or(self.span); - diag.span_suggestion( - start_point, + self.source_map.start_point(self.span), fluent::attr::unsupported_literal_suggestion, "", Applicability::MaybeIncorrect, diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index af554db30137..68abdd0bad1f 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1098,28 +1098,6 @@ impl Handler { ); std::mem::take(&mut self.inner.borrow_mut().fulfilled_expectations) } - - pub fn span_to_snippet_from_emitter( - &self, - span: rustc_span::Span, - ) -> Option> { - self.inner - .borrow() - .emitter - .source_map() - .map_or_else(|| Option::None, |sm| Some(sm.span_to_snippet(span))) - } - - pub fn span_start_point_from_emitter( - &self, - span: rustc_span::Span, - ) -> Option { - self.inner - .borrow() - .emitter - .source_map() - .map_or_else(|| Option::None, |sm| Some(sm.start_point(span))) - } } impl HandlerInner { diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs index ff39bf36129b..1262dd7dcc7f 100644 --- a/compiler/rustc_typeck/src/astconv/errors.rs +++ b/compiler/rustc_typeck/src/astconv/errors.rs @@ -29,6 +29,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.tcx().sess.emit_err(MissingTypeParams { span, def_span: self.tcx().def_span(def_id), + source_map: self.tcx().sess.source_map(), missing_type_params, empty_generic_args, }); diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs index bfe03d625751..7b553a46e3b6 100644 --- a/compiler/rustc_typeck/src/errors.rs +++ b/compiler/rustc_typeck/src/errors.rs @@ -3,7 +3,7 @@ use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic}; use rustc_middle::ty::Ty; use rustc_session::SessionDiagnostic; -use rustc_span::{symbol::Ident, Span, Symbol}; +use rustc_span::{symbol::Ident, Span, Symbol, source_map::SourceMap}; #[derive(SessionDiagnostic)] #[diag(typeck::field_multiply_specified_in_initializer, code = "E0062")] @@ -241,15 +241,16 @@ pub struct UnconstrainedOpaqueType { pub name: Symbol, } -pub struct MissingTypeParams { +pub struct MissingTypeParams<'a> { pub span: Span, pub def_span: Span, pub missing_type_params: Vec, pub empty_generic_args: bool, + pub source_map: &'a SourceMap, } // Manual implementation of `SessionDiagnostic` to be able to call `span_to_snippet`. -impl<'a> SessionDiagnostic<'a> for MissingTypeParams { +impl<'a> SessionDiagnostic<'a> for MissingTypeParams<'a> { fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> { let mut err = handler.struct_span_err_with_code( self.span, @@ -269,8 +270,8 @@ impl<'a> SessionDiagnostic<'a> for MissingTypeParams { err.span_label(self.def_span, rustc_errors::fluent::typeck::label); let mut suggested = false; - if let (Some(Ok(snippet)), true) = ( - handler.span_to_snippet_from_emitter(self.span), + if let (Ok(snippet), true) = ( + self.source_map.span_to_snippet(self.span), // Don't suggest setting the type params if there are some already: the order is // tricky to get right and the user will already know what the syntax is. self.empty_generic_args, From 72f766ae716eee2a1ce4dde092817cd404d19a37 Mon Sep 17 00:00:00 2001 From: Jhonny Bill Mena Date: Mon, 5 Sep 2022 12:05:14 -0400 Subject: [PATCH 4216/5092] FIX - broken translatable diagnostics tests --- .../ui-fulldeps/internal-lints/diagnostics.rs | 4 +++- .../internal-lints/diagnostics.stderr | 24 +++++++++---------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/test/ui-fulldeps/internal-lints/diagnostics.rs b/src/test/ui-fulldeps/internal-lints/diagnostics.rs index 89997585db25..e9e809fa4161 100644 --- a/src/test/ui-fulldeps/internal-lints/diagnostics.rs +++ b/src/test/ui-fulldeps/internal-lints/diagnostics.rs @@ -11,7 +11,9 @@ extern crate rustc_macros; extern crate rustc_session; extern crate rustc_span; -use rustc_errors::{AddSubdiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, Handler, fluent}; +use rustc_errors::{ + AddSubdiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, Handler, fluent +}; use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; use rustc_session::SessionDiagnostic; use rustc_span::Span; diff --git a/src/test/ui-fulldeps/internal-lints/diagnostics.stderr b/src/test/ui-fulldeps/internal-lints/diagnostics.stderr index ed5105dabcd3..53d70c83183a 100644 --- a/src/test/ui-fulldeps/internal-lints/diagnostics.stderr +++ b/src/test/ui-fulldeps/internal-lints/diagnostics.stderr @@ -1,8 +1,8 @@ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:37:14 + --> $DIR/diagnostics.rs:37:17 | -LL | sess.struct_err("untranslatable diagnostic") - | ^^^^^^^^^^ +LL | handler.struct_err("untranslatable diagnostic") + | ^^^^^^^^^^ | note: the lint level is defined here --> $DIR/diagnostics.rs:6:9 @@ -17,10 +17,10 @@ LL | diag.note("untranslatable diagnostic"); | ^^^^ error: diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls - --> $DIR/diagnostics.rs:68:22 + --> $DIR/diagnostics.rs:68:25 | -LL | let _diag = sess.struct_err(fluent::parser::expect_path); - | ^^^^^^^^^^ +LL | let _diag = handler.struct_err(fluent::parser::expect_path); + | ^^^^^^^^^^ | note: the lint level is defined here --> $DIR/diagnostics.rs:7:9 @@ -29,16 +29,16 @@ LL | #![deny(rustc::diagnostic_outside_of_impl)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls - --> $DIR/diagnostics.rs:71:22 + --> $DIR/diagnostics.rs:71:25 | -LL | let _diag = sess.struct_err("untranslatable diagnostic"); - | ^^^^^^^^^^ +LL | let _diag = handler.struct_err("untranslatable diagnostic"); + | ^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:71:22 + --> $DIR/diagnostics.rs:71:25 | -LL | let _diag = sess.struct_err("untranslatable diagnostic"); - | ^^^^^^^^^^ +LL | let _diag = handler.struct_err("untranslatable diagnostic"); + | ^^^^^^^^^^ error: aborting due to 5 previous errors From d14b3af6db3445cdcd7b85090bc3402c1c78c9a1 Mon Sep 17 00:00:00 2001 From: Jhonny Bill Mena Date: Mon, 5 Sep 2022 12:09:10 -0400 Subject: [PATCH 4217/5092] [Gardening] UPDATE - tidy fixes --- compiler/rustc_attr/src/builtin.rs | 7 ++++++- compiler/rustc_attr/src/session_diagnostics.rs | 2 +- compiler/rustc_typeck/src/errors.rs | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index faba9856f02a..2c3fc4d9fe66 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -63,7 +63,12 @@ fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) { sess.emit_err(session_diagnostics::MultipleStabilityLevels { span }); } AttrError::UnsupportedLiteral(reason, is_bytestr) => { - sess.emit_err(session_diagnostics::UnsupportedLiteral { span, reason, is_bytestr, source_map: sess.source_map() }); + sess.emit_err(session_diagnostics::UnsupportedLiteral { + span, + reason, + is_bytestr, + source_map: sess.source_map(), + }); } } } diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs index 3f5a51fbd838..b8942e51306d 100644 --- a/compiler/rustc_attr/src/session_diagnostics.rs +++ b/compiler/rustc_attr/src/session_diagnostics.rs @@ -6,7 +6,7 @@ use rustc_errors::{ }; use rustc_macros::SessionDiagnostic; use rustc_session::SessionDiagnostic; -use rustc_span::{Span, Symbol, source_map::SourceMap}; +use rustc_span::{source_map::SourceMap, Span, Symbol}; use crate::UnsupportedLiteralReason; diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs index 7b553a46e3b6..ae6f8d2a51c8 100644 --- a/compiler/rustc_typeck/src/errors.rs +++ b/compiler/rustc_typeck/src/errors.rs @@ -3,7 +3,7 @@ use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic}; use rustc_middle::ty::Ty; use rustc_session::SessionDiagnostic; -use rustc_span::{symbol::Ident, Span, Symbol, source_map::SourceMap}; +use rustc_span::{source_map::SourceMap, symbol::Ident, Span, Symbol}; #[derive(SessionDiagnostic)] #[diag(typeck::field_multiply_specified_in_initializer, code = "E0062")] From 31e9f40bcf638d73985974d64402b2ba1622a46b Mon Sep 17 00:00:00 2001 From: Jhonny Bill Mena Date: Mon, 5 Sep 2022 12:59:56 -0400 Subject: [PATCH 4218/5092] FIX - broken translatable diagnostics tests --- src/test/ui-fulldeps/internal-lints/diagnostics.stderr | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/ui-fulldeps/internal-lints/diagnostics.stderr b/src/test/ui-fulldeps/internal-lints/diagnostics.stderr index 53d70c83183a..e5c5bc2e9987 100644 --- a/src/test/ui-fulldeps/internal-lints/diagnostics.stderr +++ b/src/test/ui-fulldeps/internal-lints/diagnostics.stderr @@ -1,5 +1,5 @@ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:37:17 + --> $DIR/diagnostics.rs:39:17 | LL | handler.struct_err("untranslatable diagnostic") | ^^^^^^^^^^ @@ -11,13 +11,13 @@ LL | #![deny(rustc::untranslatable_diagnostic)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:54:14 + --> $DIR/diagnostics.rs:56:14 | LL | diag.note("untranslatable diagnostic"); | ^^^^ error: diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls - --> $DIR/diagnostics.rs:68:25 + --> $DIR/diagnostics.rs:70:25 | LL | let _diag = handler.struct_err(fluent::parser::expect_path); | ^^^^^^^^^^ @@ -29,13 +29,13 @@ LL | #![deny(rustc::diagnostic_outside_of_impl)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls - --> $DIR/diagnostics.rs:71:25 + --> $DIR/diagnostics.rs:73:25 | LL | let _diag = handler.struct_err("untranslatable diagnostic"); | ^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:71:25 + --> $DIR/diagnostics.rs:73:25 | LL | let _diag = handler.struct_err("untranslatable diagnostic"); | ^^^^^^^^^^ From 11e66e155df3fa12243d253e48196c394d422034 Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Mon, 5 Sep 2022 18:34:53 +0100 Subject: [PATCH 4219/5092] Update cargo 8 commits in 4ed54cecce3ce9ab6ff058781f4c8a500ee6b8b5..646e9a0b9ea8354cc409d05f10e8dc752c5de78e 2022-08-27 18:41:39 +0000 to 2022-09-02 14:29:28 +0000 - Support inheriting jobserver fd for external subcommands (rust-lang/cargo#10511) - refactor(cli): Lazy load config (rust-lang/cargo#11029) - chore: Don't show genned docs in ripgrep (rust-lang/cargo#11040) - Document private items for Cargo and publish under contributor guide (rust-lang/cargo#11019) - Add names to CI jobs (rust-lang/cargo#11039) - Rework test error handling (rust-lang/cargo#11028) - Very slight `cargo add` documentation improvements (rust-lang/cargo#11033) - Update compiling requirements. (rust-lang/cargo#11030) --- Cargo.lock | 8 ++++---- src/tools/cargo | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0f1f16cbce21..68ea8b51c555 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -577,9 +577,9 @@ dependencies = [ [[package]] name = "clap" -version = "3.2.5" +version = "3.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53da17d37dba964b9b3ecb5c5a1f193a2762c700e6829201e645b9381c99dc7" +checksum = "23b71c3ce99b7611011217b366d923f1d0a7e07a92bb2dbf1e84508c673ca3bd" dependencies = [ "atty", "bitflags", @@ -603,9 +603,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "3.2.5" +version = "3.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c11d40217d16aee8508cc8e5fde8b4ff24639758608e5374e731b53f85749fb9" +checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" dependencies = [ "heck", "proc-macro-error", diff --git a/src/tools/cargo b/src/tools/cargo index 4ed54cecce3c..646e9a0b9ea8 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 4ed54cecce3ce9ab6ff058781f4c8a500ee6b8b5 +Subproject commit 646e9a0b9ea8354cc409d05f10e8dc752c5de78e From fdf56cfc7c4101e31eaf969eaceda78a51f84fa7 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 5 Sep 2022 15:51:34 +0200 Subject: [PATCH 4220/5092] Add test. --- ...issue-100521-change-struct-name-assocty.rs | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 src/test/incremental/issue-100521-change-struct-name-assocty.rs diff --git a/src/test/incremental/issue-100521-change-struct-name-assocty.rs b/src/test/incremental/issue-100521-change-struct-name-assocty.rs new file mode 100644 index 000000000000..7f8d1e608819 --- /dev/null +++ b/src/test/incremental/issue-100521-change-struct-name-assocty.rs @@ -0,0 +1,65 @@ +// revisions: rpass1 rpass2 + +pub fn foo() { + bar(); + baz::<()>(); +} + +fn bar() +where + <() as Table>::AllColumns:, +{ +} + +fn baz() +where + W: AsQuery, + ::Query:, +{ +} + +trait AsQuery { + type Query; +} + +trait UnimplementedTrait {} + +impl AsQuery for T +where + T: UnimplementedTrait, +{ + type Query = (); +} + +struct Wrapper(Expr); + +impl AsQuery for Wrapper { + type Query = (); +} + +impl AsQuery for () +where + Wrapper<<() as Table>::AllColumns>: AsQuery, +{ + type Query = (); +} + +trait Table { + type AllColumns; +} + +#[cfg(rpass1)] +impl Table for () { + type AllColumns = Checksum1; +} +#[cfg(rpass1)] +struct Checksum1; + +#[cfg(rpass2)] +impl Table for () { + type AllColumns = Checksum2; +} +#[cfg(rpass2)] +struct Checksum2; + +fn main() {} From fbf11cfc1314e577bfdae7d53953220798ffa12b Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Mon, 5 Sep 2022 16:09:57 +0000 Subject: [PATCH 4221/5092] Recover from using `;` as separator between fields --- compiler/rustc_parse/src/parser/item.rs | 11 +++++++ src/test/ui/parser/recover-field-semi.rs | 16 ++++++++++ src/test/ui/parser/recover-field-semi.stderr | 29 +++++++++++++++++++ .../parser/removed-syntax-field-semicolon.rs | 2 +- .../removed-syntax-field-semicolon.stderr | 4 +-- 5 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/parser/recover-field-semi.rs create mode 100644 src/test/ui/parser/recover-field-semi.stderr diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 5b75d1d5f221..29b484a3954c 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1526,6 +1526,17 @@ impl<'a> Parser<'a> { if self.token == token::Comma { seen_comma = true; } + if self.eat(&token::Semi) { + let sp = self.prev_token.span; + let mut err = self.struct_span_err(sp, format!("{adt_ty} fields are separated by `,`")); + err.span_suggestion_short( + sp, + "replace `;` with `,`", + ",", + Applicability::MachineApplicable, + ); + return Err(err); + } match self.token.kind { token::Comma => { self.bump(); diff --git a/src/test/ui/parser/recover-field-semi.rs b/src/test/ui/parser/recover-field-semi.rs new file mode 100644 index 000000000000..b703578860ec --- /dev/null +++ b/src/test/ui/parser/recover-field-semi.rs @@ -0,0 +1,16 @@ +struct Foo { + foo: i32; + //~^ ERROR struct fields are separated by `,` +} + +union Bar { //~ ERROR + foo: i32; + //~^ ERROR union fields are separated by `,` +} + +enum Baz { + Qux { foo: i32; } + //~^ ERROR struct fields are separated by `,` +} + +fn main() {} diff --git a/src/test/ui/parser/recover-field-semi.stderr b/src/test/ui/parser/recover-field-semi.stderr new file mode 100644 index 000000000000..657366db9b4b --- /dev/null +++ b/src/test/ui/parser/recover-field-semi.stderr @@ -0,0 +1,29 @@ +error: struct fields are separated by `,` + --> $DIR/recover-field-semi.rs:2:13 + | +LL | foo: i32; + | ^ help: replace `;` with `,` + +error: union fields are separated by `,` + --> $DIR/recover-field-semi.rs:7:13 + | +LL | foo: i32; + | ^ help: replace `;` with `,` + +error: struct fields are separated by `,` + --> $DIR/recover-field-semi.rs:12:19 + | +LL | Qux { foo: i32; } + | ^ help: replace `;` with `,` + +error: unions cannot have zero fields + --> $DIR/recover-field-semi.rs:6:1 + | +LL | / union Bar { +LL | | foo: i32; +LL | | +LL | | } + | |_^ + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/parser/removed-syntax-field-semicolon.rs b/src/test/ui/parser/removed-syntax-field-semicolon.rs index ac28e21ae032..808f2a5cc381 100644 --- a/src/test/ui/parser/removed-syntax-field-semicolon.rs +++ b/src/test/ui/parser/removed-syntax-field-semicolon.rs @@ -1,6 +1,6 @@ struct S { bar: (); - //~^ ERROR expected `,`, or `}`, found `;` + //~^ ERROR struct fields are separated by `,` } fn main() {} diff --git a/src/test/ui/parser/removed-syntax-field-semicolon.stderr b/src/test/ui/parser/removed-syntax-field-semicolon.stderr index fbefeb26a501..e4f75f672063 100644 --- a/src/test/ui/parser/removed-syntax-field-semicolon.stderr +++ b/src/test/ui/parser/removed-syntax-field-semicolon.stderr @@ -1,8 +1,8 @@ -error: expected `,`, or `}`, found `;` +error: struct fields are separated by `,` --> $DIR/removed-syntax-field-semicolon.rs:2:12 | LL | bar: (); - | ^ + | ^ help: replace `;` with `,` error: aborting due to previous error From bee48e3fdc44d8c322fb6b86b7c18dc0faf76beb Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 5 Sep 2022 00:23:02 +0000 Subject: [PATCH 4222/5092] Fix ICE, generalize 'move generics to trait' suggestion for >0 non-rcvr arguments --- .../wrong_number_of_generic_args.rs | 44 ++++++++++++++----- src/test/ui/suggestions/issue-101421.rs | 12 +++++ src/test/ui/suggestions/issue-101421.stderr | 17 +++++++ ...-generic-to-trait-in-method-with-params.rs | 18 ++++++++ ...eric-to-trait-in-method-with-params.stderr | 24 ++++++++++ 5 files changed, 104 insertions(+), 11 deletions(-) create mode 100644 src/test/ui/suggestions/issue-101421.rs create mode 100644 src/test/ui/suggestions/issue-101421.stderr create mode 100644 src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.rs create mode 100644 src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs index cddb0ce2346a..4359124646df 100644 --- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs @@ -749,23 +749,45 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { fn suggest_moving_args_from_assoc_fn_to_trait_for_method_call( &self, err: &mut Diagnostic, - trait_: DefId, + trait_def_id: DefId, expr: &'tcx hir::Expr<'tcx>, msg: String, num_assoc_fn_excess_args: usize, num_trait_generics_except_self: usize, ) { - if let hir::ExprKind::MethodCall(_, receiver, args, ..) = expr.kind { - assert_eq!(args.len(), 0); - if num_assoc_fn_excess_args == num_trait_generics_except_self { - if let Some(gen_args) = self.gen_args.span_ext() - && let Ok(gen_args) = self.tcx.sess.source_map().span_to_snippet(gen_args) - && let Ok(receiver) = self.tcx.sess.source_map().span_to_snippet(receiver.span) { - let sugg = format!("{}::{}::{}({})", self.tcx.item_name(trait_), gen_args, self.tcx.item_name(self.def_id), receiver); - err.span_suggestion(expr.span, msg, sugg, Applicability::MaybeIncorrect); - } - } + let sm = self.tcx.sess.source_map(); + let hir::ExprKind::MethodCall(_, rcvr, args, _) = expr.kind else { return; }; + if num_assoc_fn_excess_args != num_trait_generics_except_self { + return; } + let Some(gen_args) = self.gen_args.span_ext() else { return; }; + let Ok(generics) = sm.span_to_snippet(gen_args) else { return; }; + let Ok(rcvr) = sm.span_to_snippet( + rcvr.span.find_ancestor_inside(expr.span).unwrap_or(rcvr.span) + ) else { return; }; + let Ok(rest) = + (match args { + [] => Ok(String::new()), + [arg] => sm.span_to_snippet( + arg.span.find_ancestor_inside(expr.span).unwrap_or(arg.span), + ), + [first, .., last] => { + let first_span = + first.span.find_ancestor_inside(expr.span).unwrap_or(first.span); + let last_span = + last.span.find_ancestor_inside(expr.span).unwrap_or(last.span); + sm.span_to_snippet(first_span.to(last_span)) + } + }) else { return; }; + let comma = if args.len() > 0 { ", " } else { "" }; + let trait_path = self.tcx.def_path_str(trait_def_id); + let method_name = self.tcx.item_name(self.def_id); + err.span_suggestion( + expr.span, + msg, + format!("{trait_path}::{generics}::{method_name}({rcvr}{comma}{rest})"), + Applicability::MaybeIncorrect, + ); } /// Suggests to remove redundant argument(s): diff --git a/src/test/ui/suggestions/issue-101421.rs b/src/test/ui/suggestions/issue-101421.rs new file mode 100644 index 000000000000..b615997d1a9a --- /dev/null +++ b/src/test/ui/suggestions/issue-101421.rs @@ -0,0 +1,12 @@ +pub trait Ice { + fn f(&self, _: ()); +} + +impl Ice for () { + fn f(&self, _: ()) {} +} + +fn main() { + ().f::<()>(()); + //~^ ERROR this associated function takes 0 generic arguments but 1 generic argument was supplied +} diff --git a/src/test/ui/suggestions/issue-101421.stderr b/src/test/ui/suggestions/issue-101421.stderr new file mode 100644 index 000000000000..f8e1efb88202 --- /dev/null +++ b/src/test/ui/suggestions/issue-101421.stderr @@ -0,0 +1,17 @@ +error[E0107]: this associated function takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/issue-101421.rs:10:8 + | +LL | ().f::<()>(()); + | ^------ help: remove these generics + | | + | expected 0 generic arguments + | +note: associated function defined here, with 0 generic parameters + --> $DIR/issue-101421.rs:2:8 + | +LL | fn f(&self, _: ()); + | ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0107`. diff --git a/src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.rs b/src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.rs new file mode 100644 index 000000000000..2f540060a349 --- /dev/null +++ b/src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.rs @@ -0,0 +1,18 @@ +// Generalizes the suggestion introduced in #100838 + +trait Foo { + fn bar(&self, _: T); +} + +impl Foo for i32 { + fn bar(&self, x: i32) { + println!("{}", self + x); + } +} + +fn main() { + 1.bar::(0); + //~^ ERROR this associated function takes 0 generic arguments but 1 generic argument was supplied + //~| HELP consider moving this generic argument to the `Foo` trait, which takes up to 1 argument + //~| HELP remove these generics +} diff --git a/src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr b/src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr new file mode 100644 index 000000000000..9557220f6bb5 --- /dev/null +++ b/src/test/ui/suggestions/move-generic-to-trait-in-method-with-params.stderr @@ -0,0 +1,24 @@ +error[E0107]: this associated function takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/move-generic-to-trait-in-method-with-params.rs:14:7 + | +LL | 1.bar::(0); + | ^^^ expected 0 generic arguments + | +note: associated function defined here, with 0 generic parameters + --> $DIR/move-generic-to-trait-in-method-with-params.rs:4:8 + | +LL | fn bar(&self, _: T); + | ^^^ +help: consider moving this generic argument to the `Foo` trait, which takes up to 1 argument + | +LL | Foo::::bar(1, 0); + | ~~~~~~~~~~~~~~~~~~~~~ +help: remove these generics + | +LL - 1.bar::(0); +LL + 1.bar(0); + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0107`. From 1254b324797317a46315ff86395e8a9b43ebcc9b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 3 Sep 2022 03:46:41 +0000 Subject: [PATCH 4223/5092] Point out when a callable is not actually callable because its return is not sized --- compiler/rustc_trait_selection/src/infer.rs | 17 +++++++++++++ compiler/rustc_typeck/src/check/callee.rs | 25 ++++++++++++++++--- compiler/rustc_typeck/src/check/cast.rs | 13 ++-------- .../src/check/fn_ctxt/suggestions.rs | 7 ++++-- src/test/ui/issues/issue-41139.stderr | 4 +-- 5 files changed, 47 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 9d30374f8b8a..ba403ab2da2b 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -24,6 +24,13 @@ pub trait InferCtxtExt<'tcx> { span: Span, ) -> bool; + fn type_is_sized_modulo_regions( + &self, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + span: Span, + ) -> bool; + fn partially_normalize_associated_types_in( &self, cause: ObligationCause<'tcx>, @@ -74,6 +81,16 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id, span) } + fn type_is_sized_modulo_regions( + &self, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + span: Span, + ) -> bool { + let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); + traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item, span) + } + /// Normalizes associated types in `value`, potentially returning /// new obligations that must further be processed. fn partially_normalize_associated_types_in( diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index 75f5aced8557..0d35c2479dda 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -1,5 +1,5 @@ use super::method::MethodCallee; -use super::{Expectation, FnCtxt, TupleArgumentsFlag}; +use super::{DefIdOrName, Expectation, FnCtxt, TupleArgumentsFlag}; use crate::type_error_struct; use rustc_errors::{struct_span_err, Applicability, Diagnostic}; @@ -24,7 +24,8 @@ use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; use rustc_target::spec::abi; use rustc_trait_selection::autoderef::Autoderef; -use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; +use rustc_trait_selection::infer::InferCtxtExt as _; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use std::iter; @@ -471,7 +472,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) { - err.span_label(call_expr.span, "call expression requires function"); + if let Some((maybe_def, output_ty, _)) = self.extract_callable_info(callee_expr, callee_ty) + && !self.type_is_sized_modulo_regions(self.param_env, output_ty, callee_expr.span) + { + let descr = match maybe_def { + DefIdOrName::DefId(def_id) => self.tcx.def_kind(def_id).descr(def_id), + DefIdOrName::Name(name) => name, + }; + err.span_label( + callee_expr.span, + format!("this {descr} returns an unsized value `{output_ty}`, so it cannot be called") + ); + if let DefIdOrName::DefId(def_id) = maybe_def + && let Some(def_span) = self.tcx.hir().span_if_local(def_id) + { + err.span_label(def_span, "the callable type is defined here"); + } + } else { + err.span_label(call_expr.span, "call expression requires function"); + } } if let Some(span) = self.tcx.hir().res_span(def) { diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index 6c7b2a2889fa..a3fcda5864b3 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -35,7 +35,6 @@ use crate::type_error_struct; use hir::def_id::LOCAL_CRATE; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; -use rustc_hir::lang_items::LangItem; use rustc_middle::mir::Mutability; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::cast::{CastKind, CastTy}; @@ -47,7 +46,6 @@ use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::Span; use rustc_trait_selection::infer::InferCtxtExt; -use rustc_trait_selection::traits; use rustc_trait_selection::traits::error_reporting::report_object_safety_error; /// Reifies a cast check to be checked once we have full type information for @@ -97,7 +95,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return Err(reported); } - if self.type_is_known_to_be_sized_modulo_regions(t, span) { + if self.type_is_sized_modulo_regions(self.param_env, t, span) { return Ok(Some(PointerKind::Thin)); } @@ -705,7 +703,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty); - if !fcx.type_is_known_to_be_sized_modulo_regions(self.cast_ty, self.span) + if !fcx.type_is_sized_modulo_regions(fcx.param_env, self.cast_ty, self.span) && !self.cast_ty.has_infer_types() { self.report_cast_to_unsized_type(fcx); @@ -1084,10 +1082,3 @@ impl<'a, 'tcx> CastCheck<'tcx> { ); } } - -impl<'a, 'tcx> FnCtxt<'a, 'tcx> { - fn type_is_known_to_be_sized_modulo_regions(&self, ty: Ty<'tcx>, span: Span) -> bool { - let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); - traits::type_known_to_meet_bound_modulo_regions(self, self.param_env, ty, lang_item, span) - } -} diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index 3d9677ecf75c..2bfee9a53643 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -144,7 +144,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false } - fn extract_callable_info( + /// Extracts information about a callable type for diagnostics. This is a + /// heuristic -- it doesn't necessarily mean that a type is always callable, + /// because the callable type must also be well-formed to be called. + pub(in super::super) fn extract_callable_info( &self, expr: &Expr<'_>, found: Ty<'tcx>, @@ -1130,7 +1133,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } -enum DefIdOrName { +pub enum DefIdOrName { DefId(DefId), Name(&'static str), } diff --git a/src/test/ui/issues/issue-41139.stderr b/src/test/ui/issues/issue-41139.stderr index 48b22bca20f0..97492e6e0fa2 100644 --- a/src/test/ui/issues/issue-41139.stderr +++ b/src/test/ui/issues/issue-41139.stderr @@ -5,9 +5,7 @@ LL | fn get_function<'a>() -> &'a dyn Fn() -> dyn Trait { | -------------------------------------------------- `get_function` defined here returns `&dyn Fn() -> (dyn Trait + 'static)` ... LL | let t: &dyn Trait = &get_function()(); - | ^^^^^^^^^^^^^^-- - | | - | call expression requires function + | ^^^^^^^^^^^^^^ this trait object returns an unsized value `(dyn Trait + 'static)`, so it cannot be called error: aborting due to previous error From dd5850b8faf04e1b98542cf0813920385a6cc4db Mon Sep 17 00:00:00 2001 From: Jhonny Bill Mena Date: Mon, 5 Sep 2022 17:26:57 -0400 Subject: [PATCH 4224/5092] UPDATE - accept start_point and snippet instead of SourceMap --- compiler/rustc_attr/src/builtin.rs | 2 +- compiler/rustc_attr/src/session_diagnostics.rs | 10 +++++----- compiler/rustc_typeck/src/astconv/errors.rs | 2 +- compiler/rustc_typeck/src/errors.rs | 12 ++++++------ 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 2c3fc4d9fe66..e1404ab15efa 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -67,7 +67,7 @@ fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) { span, reason, is_bytestr, - source_map: sess.source_map(), + start_point_span: sess.source_map().start_point(span), }); } } diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs index b8942e51306d..085175d4bed1 100644 --- a/compiler/rustc_attr/src/session_diagnostics.rs +++ b/compiler/rustc_attr/src/session_diagnostics.rs @@ -6,7 +6,7 @@ use rustc_errors::{ }; use rustc_macros::SessionDiagnostic; use rustc_session::SessionDiagnostic; -use rustc_span::{source_map::SourceMap, Span, Symbol}; +use rustc_span::{Span, Symbol}; use crate::UnsupportedLiteralReason; @@ -202,14 +202,14 @@ pub(crate) struct InvalidReprHintNoValue { } // Error code: E0565 -pub(crate) struct UnsupportedLiteral<'a> { +pub(crate) struct UnsupportedLiteral { pub span: Span, pub reason: UnsupportedLiteralReason, pub is_bytestr: bool, - pub source_map: &'a SourceMap, + pub start_point_span: Span, } -impl<'a> SessionDiagnostic<'a> for UnsupportedLiteral<'a> { +impl<'a> SessionDiagnostic<'a> for UnsupportedLiteral { fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> { let mut diag = handler.struct_span_err_with_code( self.span, @@ -227,7 +227,7 @@ impl<'a> SessionDiagnostic<'a> for UnsupportedLiteral<'a> { ); if self.is_bytestr { diag.span_suggestion( - self.source_map.start_point(self.span), + self.start_point_span, fluent::attr::unsupported_literal_suggestion, "", Applicability::MaybeIncorrect, diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs index 1262dd7dcc7f..a9152bdc5978 100644 --- a/compiler/rustc_typeck/src/astconv/errors.rs +++ b/compiler/rustc_typeck/src/astconv/errors.rs @@ -29,7 +29,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.tcx().sess.emit_err(MissingTypeParams { span, def_span: self.tcx().def_span(def_id), - source_map: self.tcx().sess.source_map(), + span_snippet: self.tcx().sess.source_map().span_to_snippet(span).ok(), missing_type_params, empty_generic_args, }); diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs index ae6f8d2a51c8..d280fa5156bd 100644 --- a/compiler/rustc_typeck/src/errors.rs +++ b/compiler/rustc_typeck/src/errors.rs @@ -3,7 +3,7 @@ use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic}; use rustc_middle::ty::Ty; use rustc_session::SessionDiagnostic; -use rustc_span::{source_map::SourceMap, symbol::Ident, Span, Symbol}; +use rustc_span::{symbol::Ident, Span, Symbol}; #[derive(SessionDiagnostic)] #[diag(typeck::field_multiply_specified_in_initializer, code = "E0062")] @@ -241,16 +241,16 @@ pub struct UnconstrainedOpaqueType { pub name: Symbol, } -pub struct MissingTypeParams<'a> { +pub struct MissingTypeParams { pub span: Span, pub def_span: Span, + pub span_snippet: Option, pub missing_type_params: Vec, pub empty_generic_args: bool, - pub source_map: &'a SourceMap, } // Manual implementation of `SessionDiagnostic` to be able to call `span_to_snippet`. -impl<'a> SessionDiagnostic<'a> for MissingTypeParams<'a> { +impl<'a> SessionDiagnostic<'a> for MissingTypeParams { fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> { let mut err = handler.struct_span_err_with_code( self.span, @@ -270,8 +270,8 @@ impl<'a> SessionDiagnostic<'a> for MissingTypeParams<'a> { err.span_label(self.def_span, rustc_errors::fluent::typeck::label); let mut suggested = false; - if let (Ok(snippet), true) = ( - self.source_map.span_to_snippet(self.span), + if let (Some(snippet), true) = ( + self.span_snippet, // Don't suggest setting the type params if there are some already: the order is // tricky to get right and the user will already know what the syntax is. self.empty_generic_args, From 46ba27d5b54e4271e1c3934197afbae269237639 Mon Sep 17 00:00:00 2001 From: Jhonny Bill Mena Date: Mon, 5 Sep 2022 17:32:23 -0400 Subject: [PATCH 4225/5092] [Gardening] UPDATE - use let chain to unwrap snippet and evaluate flag --- compiler/rustc_typeck/src/errors.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs index d280fa5156bd..0d2e66745859 100644 --- a/compiler/rustc_typeck/src/errors.rs +++ b/compiler/rustc_typeck/src/errors.rs @@ -270,12 +270,9 @@ impl<'a> SessionDiagnostic<'a> for MissingTypeParams { err.span_label(self.def_span, rustc_errors::fluent::typeck::label); let mut suggested = false; - if let (Some(snippet), true) = ( - self.span_snippet, - // Don't suggest setting the type params if there are some already: the order is - // tricky to get right and the user will already know what the syntax is. - self.empty_generic_args, - ) { + // Don't suggest setting the type params if there are some already: the order is + // tricky to get right and the user will already know what the syntax is. + if let Some(snippet) = self.span_snippet && self.empty_generic_args { if snippet.ends_with('>') { // The user wrote `Trait<'a, T>` or similar. To provide an accurate suggestion // we would have to preserve the right order. For now, as clearly the user is From 065e0b9c9cf3d03f286c5d0b98fbae7185e41b75 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Mon, 5 Sep 2022 22:17:50 +0100 Subject: [PATCH 4226/5092] Rustdoc-Json: Store Variant Fields as their own item. Closes #100587 Closes #92945 --- src/etc/check_missing_items.py | 6 +- src/librustdoc/json/conversions.rs | 32 ++++--- src/rustdoc-json-types/lib.rs | 33 ++++++- .../field_hidden.rs} | 2 +- src/test/rustdoc-json/enums/kind.rs | 37 ++++++++ .../rustdoc-json/enums/struct_field_hidden.rs | 17 ++++ .../rustdoc-json/enums/tuple_fields_hidden.rs | 94 +++++++++++++++++++ 7 files changed, 203 insertions(+), 18 deletions(-) rename src/test/rustdoc-json/{enum_variant_hidden.rs => enums/field_hidden.rs} (96%) create mode 100644 src/test/rustdoc-json/enums/kind.rs create mode 100644 src/test/rustdoc-json/enums/struct_field_hidden.rs create mode 100644 src/test/rustdoc-json/enums/tuple_fields_hidden.rs diff --git a/src/etc/check_missing_items.py b/src/etc/check_missing_items.py index 025f320e3a10..27fb018aecad 100644 --- a/src/etc/check_missing_items.py +++ b/src/etc/check_missing_items.py @@ -144,10 +144,10 @@ while work_list: ) - visited elif item["kind"] == "variant": if item["inner"]["variant_kind"] == "tuple": - for ty in item["inner"]["variant_inner"]: - check_type(ty) + for field_id in filter(None, item["inner"]["variant_inner"]): + work_list.add(field_id) elif item["inner"]["variant_kind"] == "struct": - work_list |= set(item["inner"]["variant_inner"]) - visited + work_list |= set(item["inner"]["variant_inner"]["fields"]) - visited elif item["kind"] in ("function", "method"): check_generics(item["inner"]["generics"]) check_decl(item["inner"]["decl"]) diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 4d0093167300..c2d3543942db 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -663,17 +663,11 @@ impl FromWithTcx for Variant { use clean::Variant::*; match variant { CLike(disr) => Variant::Plain(disr.map(|disr| disr.into_tcx(tcx))), - Tuple(fields) => Variant::Tuple( - fields - .into_iter() - .filter_map(|f| match *f.kind { - clean::StructFieldItem(ty) => Some(ty.into_tcx(tcx)), - clean::StrippedItem(_) => None, - _ => unreachable!(), - }) - .collect(), - ), - Struct(s) => Variant::Struct(ids(s.fields, tcx)), + Tuple(fields) => Variant::Tuple(ids_keeping_stripped(fields, tcx)), + Struct(s) => Variant::Struct { + fields_stripped: s.has_stripped_entries(), + fields: ids(s.fields, tcx), + }, } } } @@ -796,3 +790,19 @@ fn ids(items: impl IntoIterator, tcx: TyCtxt<'_>) -> Vec .map(|i| from_item_id_with_name(i.item_id, tcx, i.name)) .collect() } + +fn ids_keeping_stripped( + items: impl IntoIterator, + tcx: TyCtxt<'_>, +) -> Vec> { + items + .into_iter() + .map(|i| { + if !i.is_stripped() && !i.is_keyword() { + Some(from_item_id_with_name(i.item_id, tcx, i.name)) + } else { + None + } + }) + .collect() +} diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index d25f68b3743d..eea62f3af5ab 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -9,7 +9,7 @@ use std::path::PathBuf; use serde::{Deserialize, Serialize}; /// rustdoc format-version. -pub const FORMAT_VERSION: u32 = 19; +pub const FORMAT_VERSION: u32 = 20; /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information /// about the language items in the local crate, as well as info about external items to allow @@ -308,9 +308,36 @@ pub struct Enum { #[serde(rename_all = "snake_case")] #[serde(tag = "variant_kind", content = "variant_inner")] pub enum Variant { + /// A variant with no parentheses, and possible discriminant. + /// + /// ```rust + /// enum Demo { + /// PlainVariant, + /// PlainWithDiscriminant = 1, + /// } + /// ``` Plain(Option), - Tuple(Vec), - Struct(Vec), + /// A variant with unnamed fields. + /// + /// Unlike most of json, `#[doc(hidden)]` fields will be given as `None` + /// instead of being ommited, because order matters. + /// + /// ```rust + /// enum Demo { + /// TupleVariant(i32), + /// EmptyTupleVariant(), + /// } + /// ``` + Tuple(Vec>), + /// A variant with named fields. + /// + /// ```rust + /// enum Demo { + /// StructVariant { x: i32 }, + /// EmptyStructVariant {}, + /// } + /// ``` + Struct { fields: Vec, fields_stripped: bool }, } #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] diff --git a/src/test/rustdoc-json/enum_variant_hidden.rs b/src/test/rustdoc-json/enums/field_hidden.rs similarity index 96% rename from src/test/rustdoc-json/enum_variant_hidden.rs rename to src/test/rustdoc-json/enums/field_hidden.rs index c5e063a055c5..e6310cc3b997 100644 --- a/src/test/rustdoc-json/enum_variant_hidden.rs +++ b/src/test/rustdoc-json/enums/field_hidden.rs @@ -6,7 +6,7 @@ // @has "$.index[*][?(@.name=='ParseError')]" // @has "$.index[*][?(@.name=='UnexpectedEndTag')]" // @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.variant_kind" '"tuple"' -// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.variant_inner" [] +// @is "$.index[*][?(@.name=='UnexpectedEndTag')].inner.variant_inner" [null] pub enum ParseError { UnexpectedEndTag(#[doc(hidden)] u32), diff --git a/src/test/rustdoc-json/enums/kind.rs b/src/test/rustdoc-json/enums/kind.rs new file mode 100644 index 000000000000..e9ea3ae23c22 --- /dev/null +++ b/src/test/rustdoc-json/enums/kind.rs @@ -0,0 +1,37 @@ +// ignore-tidy-linelength + +#![feature(no_core)] +#![no_core] + +pub enum Foo { + // @set Unit = "$.index[*][?(@.name=='Unit')].id" + // @is "$.index[*][?(@.name=='Unit')].inner.variant_kind" '"plain"' + // @is "$.index[*][?(@.name=='Unit')].inner.variant_inner" null + Unit, + // @set Named = "$.index[*][?(@.name=='Named')].id" + // @is "$.index[*][?(@.name=='Named')].inner.variant_kind" '"struct"' + // @is "$.index[*][?(@.name=='Named')].inner.variant_inner" '{"fields": [], "fields_stripped": false}' + Named {}, + // @set Tuple = "$.index[*][?(@.name=='Tuple')].id" + // @is "$.index[*][?(@.name=='Tuple')].inner.variant_kind" '"tuple"' + // @is "$.index[*][?(@.name=='Tuple')].inner.variant_inner" [] + Tuple(), + // @set NamedField = "$.index[*][?(@.name=='NamedField')].id" + // @set x = "$.index[*][?(@.name=='x' && @.kind=='struct_field')].id" + // @is "$.index[*][?(@.name=='NamedField')].inner.variant_kind" '"struct"' + // @is "$.index[*][?(@.name=='NamedField')].inner.variant_inner.fields[*]" $x + // @is "$.index[*][?(@.name=='NamedField')].inner.variant_inner.fields_stripped" false + NamedField { x: i32 }, + // @set TupleField = "$.index[*][?(@.name=='TupleField')].id" + // @is "$.index[*][?(@.name=='TupleField')].inner.variant_kind" '"tuple"' + // @set tup_field = "$.index[*][?(@.name=='0' && @.kind=='struct_field')].id" + // @is "$.index[*][?(@.name=='TupleField')].inner.variant_inner[*]" $tup_field + TupleField(i32), +} + +// @is "$.index[*][?(@.name=='Foo')].inner.variants[0]" $Unit +// @is "$.index[*][?(@.name=='Foo')].inner.variants[1]" $Named +// @is "$.index[*][?(@.name=='Foo')].inner.variants[2]" $Tuple +// @is "$.index[*][?(@.name=='Foo')].inner.variants[3]" $NamedField +// @is "$.index[*][?(@.name=='Foo')].inner.variants[4]" $TupleField +// @count "$.index[*][?(@.name=='Foo')].inner.variants[*]" 5 diff --git a/src/test/rustdoc-json/enums/struct_field_hidden.rs b/src/test/rustdoc-json/enums/struct_field_hidden.rs new file mode 100644 index 000000000000..f612a34a4927 --- /dev/null +++ b/src/test/rustdoc-json/enums/struct_field_hidden.rs @@ -0,0 +1,17 @@ +pub enum Foo { + Variant { + #[doc(hidden)] + a: i32, + // @set b = "$.index[*][?(@.name=='b')].id" + b: i32, + #[doc(hidden)] + x: i32, + // @set y = "$.index[*][?(@.name=='y')].id" + y: i32, + }, + // @is "$.index[*][?(@.name=='Variant')].inner.variant_kind" '"struct"' + // @is "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields_stripped" true + // @is "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields[0]" $b + // @is "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields[1]" $y + // @count "$.index[*][?(@.name=='Variant')].inner.variant_inner.fields[*]" 2 +} diff --git a/src/test/rustdoc-json/enums/tuple_fields_hidden.rs b/src/test/rustdoc-json/enums/tuple_fields_hidden.rs new file mode 100644 index 000000000000..f546eaa0d172 --- /dev/null +++ b/src/test/rustdoc-json/enums/tuple_fields_hidden.rs @@ -0,0 +1,94 @@ +#![feature(no_core)] +#![no_core] + +// @set 1.1.0 = "$.index[*][?(@.docs=='1.1.0')].id" +// @set 2.1.0 = "$.index[*][?(@.docs=='2.1.0')].id" +// @set 2.1.1 = "$.index[*][?(@.docs=='2.1.1')].id" +// @set 2.2.1 = "$.index[*][?(@.docs=='2.2.1')].id" +// @set 2.3.0 = "$.index[*][?(@.docs=='2.3.0')].id" +// @set 3.1.1 = "$.index[*][?(@.docs=='3.1.1')].id" +// @set 3.1.2 = "$.index[*][?(@.docs=='3.1.2')].id" +// @set 3.2.0 = "$.index[*][?(@.docs=='3.2.0')].id" +// @set 3.2.2 = "$.index[*][?(@.docs=='3.2.2')].id" +// @set 3.3.0 = "$.index[*][?(@.docs=='3.3.0')].id" +// @set 3.3.1 = "$.index[*][?(@.docs=='3.3.1')].id" + +pub enum EnumWithStrippedTupleVariants { + // @is "$.index[*][?(@.name=='None')].inner.variant_kind" '"tuple"' + // @count "$.index[*][?(@.name=='None')].inner.variant_inner[*]" 0 + None(), + + // @is "$.index[*][?(@.name=='One')].inner.variant_kind" '"tuple"' + // @count "$.index[*][?(@.name=='One')].inner.variant_inner[*]" 1 + // @is "$.index[*][?(@.name=='One')].inner.variant_inner[0]" $1.1.0 + One(/** 1.1.0*/ bool), + // @is "$.index[*][?(@.name=='OneHidden')].inner.variant_kind" '"tuple"' + // @count "$.index[*][?(@.name=='OneHidden')].inner.variant_inner[*]" 1 + // @is "$.index[*][?(@.name=='OneHidden')].inner.variant_inner[0]" null + OneHidden(#[doc(hidden)] bool), + + // @is "$.index[*][?(@.name=='Two')].inner.variant_kind" '"tuple"' + // @count "$.index[*][?(@.name=='Two')].inner.variant_inner[*]" 2 + // @is "$.index[*][?(@.name=='Two')].inner.variant_inner[0]" $2.1.0 + // @is "$.index[*][?(@.name=='Two')].inner.variant_inner[1]" $2.1.1 + Two(/** 2.1.0*/ bool, /** 2.1.1*/ bool), + // @is "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_kind" '"tuple"' + // @count "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_inner[*]" 2 + // @is "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_inner[0]" null + // @is "$.index[*][?(@.name=='TwoLeftHidden')].inner.variant_inner[1]" $2.2.1 + TwoLeftHidden(#[doc(hidden)] bool, /** 2.2.1*/ bool), + // @is "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_kind" '"tuple"' + // @count "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_inner[*]" 2 + // @is "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_inner[0]" $2.3.0 + // @is "$.index[*][?(@.name=='TwoRightHidden')].inner.variant_inner[1]" null + TwoRightHidden(/** 2.3.0*/ bool, #[doc(hidden)] bool), + // @is "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_kind" '"tuple"' + // @count "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_inner[*]" 2 + // @is "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_inner[0]" null + // @is "$.index[*][?(@.name=='TwoBothHidden')].inner.variant_inner[1]" null + TwoBothHidden(#[doc(hidden)] bool, #[doc(hidden)] bool), + + // @is "$.index[*][?(@.name=='Three1')].inner.variant_kind" '"tuple"' + // @count "$.index[*][?(@.name=='Three1')].inner.variant_inner[*]" 3 + // @is "$.index[*][?(@.name=='Three1')].inner.variant_inner[0]" null + // @is "$.index[*][?(@.name=='Three1')].inner.variant_inner[1]" $3.1.1 + // @is "$.index[*][?(@.name=='Three1')].inner.variant_inner[2]" $3.1.2 + Three1(#[doc(hidden)] bool, /** 3.1.1*/ bool, /** 3.1.2*/ bool), + // @is "$.index[*][?(@.name=='Three2')].inner.variant_kind" '"tuple"' + // @count "$.index[*][?(@.name=='Three2')].inner.variant_inner[*]" 3 + // @is "$.index[*][?(@.name=='Three2')].inner.variant_inner[0]" $3.2.0 + // @is "$.index[*][?(@.name=='Three2')].inner.variant_inner[1]" null + // @is "$.index[*][?(@.name=='Three2')].inner.variant_inner[2]" $3.2.2 + Three2(/** 3.2.0*/ bool, #[doc(hidden)] bool, /** 3.2.2*/ bool), + // @is "$.index[*][?(@.name=='Three3')].inner.variant_kind" '"tuple"' + // @count "$.index[*][?(@.name=='Three3')].inner.variant_inner[*]" 3 + // @is "$.index[*][?(@.name=='Three3')].inner.variant_inner[0]" $3.3.0 + // @is "$.index[*][?(@.name=='Three3')].inner.variant_inner[1]" $3.3.1 + // @is "$.index[*][?(@.name=='Three3')].inner.variant_inner[2]" null + Three3(/** 3.3.0*/ bool, /** 3.3.1*/ bool, #[doc(hidden)] bool), +} + + +// @is "$.index[*][?(@.docs=='1.1.0')].name" '"0"' +// @is "$.index[*][?(@.docs=='2.1.0')].name" '"0"' +// @is "$.index[*][?(@.docs=='2.1.1')].name" '"1"' +// @is "$.index[*][?(@.docs=='2.2.1')].name" '"1"' +// @is "$.index[*][?(@.docs=='2.3.0')].name" '"0"' +// @is "$.index[*][?(@.docs=='3.1.1')].name" '"1"' +// @is "$.index[*][?(@.docs=='3.1.2')].name" '"2"' +// @is "$.index[*][?(@.docs=='3.2.0')].name" '"0"' +// @is "$.index[*][?(@.docs=='3.2.2')].name" '"2"' +// @is "$.index[*][?(@.docs=='3.3.0')].name" '"0"' +// @is "$.index[*][?(@.docs=='3.3.1')].name" '"1"' + +// @is "$.index[*][?(@.docs=='1.1.0')].inner" '{"kind": "primitive", "inner": "bool"}' +// @is "$.index[*][?(@.docs=='2.1.0')].inner" '{"kind": "primitive", "inner": "bool"}' +// @is "$.index[*][?(@.docs=='2.1.1')].inner" '{"kind": "primitive", "inner": "bool"}' +// @is "$.index[*][?(@.docs=='2.2.1')].inner" '{"kind": "primitive", "inner": "bool"}' +// @is "$.index[*][?(@.docs=='2.3.0')].inner" '{"kind": "primitive", "inner": "bool"}' +// @is "$.index[*][?(@.docs=='3.1.1')].inner" '{"kind": "primitive", "inner": "bool"}' +// @is "$.index[*][?(@.docs=='3.1.2')].inner" '{"kind": "primitive", "inner": "bool"}' +// @is "$.index[*][?(@.docs=='3.2.0')].inner" '{"kind": "primitive", "inner": "bool"}' +// @is "$.index[*][?(@.docs=='3.2.2')].inner" '{"kind": "primitive", "inner": "bool"}' +// @is "$.index[*][?(@.docs=='3.3.0')].inner" '{"kind": "primitive", "inner": "bool"}' +// @is "$.index[*][?(@.docs=='3.3.1')].inner" '{"kind": "primitive", "inner": "bool"}' From b21d9d307b5fdb1e423d786f9899757b42957b07 Mon Sep 17 00:00:00 2001 From: xphoniex Date: Tue, 6 Sep 2022 04:38:29 +0000 Subject: [PATCH 4227/5092] Suggest `unwrap_or_default` when closure returns `"".to_string` Signed-off-by: xphoniex --- .../src/methods/unwrap_or_else_default.rs | 24 +++++++++++++++++-- tests/ui/unwrap_or_else_default.fixed | 3 +++ tests/ui/unwrap_or_else_default.rs | 3 +++ tests/ui/unwrap_or_else_default.stderr | 8 ++++++- 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/methods/unwrap_or_else_default.rs b/clippy_lints/src/methods/unwrap_or_else_default.rs index f3af281d6cac..d3630b7d08ea 100644 --- a/clippy_lints/src/methods/unwrap_or_else_default.rs +++ b/clippy_lints/src/methods/unwrap_or_else_default.rs @@ -5,10 +5,11 @@ use clippy_utils::{ diagnostics::span_lint_and_sugg, is_default_equivalent_call, source::snippet_with_applicability, ty::is_type_diagnostic_item, }; +use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; -use rustc_span::sym; +use rustc_span::{sym, symbol}; pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, @@ -25,7 +26,7 @@ pub(super) fn check<'tcx>( if_chain! { if is_option || is_result; - if is_default_equivalent_call(cx, u_arg); + if closure_body_returns_empty_to_string(cx, u_arg) || is_default_equivalent_call(cx, u_arg); then { let mut applicability = Applicability::MachineApplicable; @@ -44,3 +45,22 @@ pub(super) fn check<'tcx>( } } } + +fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool { + if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = e.kind { + let body = cx.tcx.hir().body(body); + + if body.params.is_empty() + && let hir::Expr{ kind, .. } = &body.value + && let hir::ExprKind::MethodCall(hir::PathSegment {ident, ..}, [self_arg], _) = kind + && ident == &symbol::Ident::from_str("to_string") + && let hir::Expr{ kind, .. } = self_arg + && let hir::ExprKind::Lit(lit) = kind + && let LitKind::Str(symbol::kw::Empty, _) = lit.node + { + return true; + } + } + + false +} diff --git a/tests/ui/unwrap_or_else_default.fixed b/tests/ui/unwrap_or_else_default.fixed index c2b9bd2c881f..84f779569ff9 100644 --- a/tests/ui/unwrap_or_else_default.fixed +++ b/tests/ui/unwrap_or_else_default.fixed @@ -69,6 +69,9 @@ fn unwrap_or_else_default() { let with_default_type: Option> = None; with_default_type.unwrap_or_default(); + + let empty_string = None::; + empty_string.unwrap_or_default(); } fn main() {} diff --git a/tests/ui/unwrap_or_else_default.rs b/tests/ui/unwrap_or_else_default.rs index d55664990aeb..1735bd5808e5 100644 --- a/tests/ui/unwrap_or_else_default.rs +++ b/tests/ui/unwrap_or_else_default.rs @@ -69,6 +69,9 @@ fn unwrap_or_else_default() { let with_default_type: Option> = None; with_default_type.unwrap_or_else(Vec::new); + + let empty_string = None::; + empty_string.unwrap_or_else(|| "".to_string()); } fn main() {} diff --git a/tests/ui/unwrap_or_else_default.stderr b/tests/ui/unwrap_or_else_default.stderr index 53e31d85edfc..d2b9212223f7 100644 --- a/tests/ui/unwrap_or_else_default.stderr +++ b/tests/ui/unwrap_or_else_default.stderr @@ -30,5 +30,11 @@ error: use of `.unwrap_or_else(..)` to construct default value LL | with_default_type.unwrap_or_else(Vec::new); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `with_default_type.unwrap_or_default()` -error: aborting due to 5 previous errors +error: use of `.unwrap_or_else(..)` to construct default value + --> $DIR/unwrap_or_else_default.rs:74:5 + | +LL | empty_string.unwrap_or_else(|| "".to_string()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `empty_string.unwrap_or_default()` + +error: aborting due to 6 previous errors From 246d126edd63a4f8867e078a2f3fb8e22e2385bc Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 1 Sep 2022 08:57:51 +1000 Subject: [PATCH 4228/5092] Add more size assertions for MIR types. And move them into a module, as has been done previously for AST, HIR, etc. --- compiler/rustc_middle/src/mir/mod.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index f3676604bb0e..c5a450b0e2e5 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -839,10 +839,6 @@ pub struct LocalDecl<'tcx> { pub source_info: SourceInfo, } -// `LocalDecl` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(LocalDecl<'_>, 56); - /// Extra information about a some locals that's used for diagnostics and for /// classifying variables into local variables, statics, etc, which is needed e.g. /// for unsafety checking. @@ -1317,10 +1313,6 @@ pub struct Statement<'tcx> { pub kind: StatementKind<'tcx>, } -// `Statement` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(Statement<'_>, 32); - impl Statement<'_> { /// Changes a statement to a nop. This is both faster than deleting instructions and avoids /// invalidating statement indices in `Location`s. @@ -2900,3 +2892,17 @@ impl Location { } } } + +// Some nodes are used a lot. Make sure they don't unintentionally get bigger. +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +mod size_asserts { + use super::*; + use rustc_data_structures::static_assert_size; + // These are in alphabetical order, which is easy to maintain. + static_assert_size!(BasicBlockData<'_>, 144); + static_assert_size!(LocalDecl<'_>, 56); + static_assert_size!(Statement<'_>, 32); + static_assert_size!(StatementKind<'_>, 16); + static_assert_size!(Terminator<'_>, 112); + static_assert_size!(TerminatorKind<'_>, 96); +} From 00b10a5552c575e884a40de808a3cb64a647a442 Mon Sep 17 00:00:00 2001 From: yukang Date: Tue, 6 Sep 2022 14:16:54 +0800 Subject: [PATCH 4229/5092] get_attr should check that no duplicates are allowed --- compiler/rustc_codegen_llvm/src/attributes.rs | 3 ++- compiler/rustc_feature/src/builtin_attrs.rs | 8 ++++++++ compiler/rustc_feature/src/lib.rs | 4 ++-- compiler/rustc_middle/src/ty/mod.rs | 6 +++++- compiler/rustc_typeck/src/check/check.rs | 2 +- src/test/ui/attributes/issue-100631.rs | 8 ++++++++ src/test/ui/attributes/issue-100631.stderr | 12 ++++++++++++ 7 files changed, 38 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/attributes/issue-100631.rs create mode 100644 src/test/ui/attributes/issue-100631.stderr diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index aabbe8ac276d..b38684a63e41 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -386,7 +386,8 @@ pub fn from_fn_attrs<'ll, 'tcx>( ) { let span = cx .tcx - .get_attr(instance.def_id(), sym::target_feature) + .get_attrs(instance.def_id(), sym::target_feature) + .next() .map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span); let msg = format!( "the target features {} must all be either enabled or disabled together", diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index e359d50c4e9e..38a02cb1d7ce 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -823,6 +823,14 @@ pub fn is_builtin_only_local(name: Symbol) -> bool { BUILTIN_ATTRIBUTE_MAP.get(&name).map_or(false, |attr| attr.only_local) } +pub fn is_valid_for_get_attr(name: Symbol) -> bool { + BUILTIN_ATTRIBUTE_MAP.get(&name).map_or(false, |attr| match attr.duplicates { + WarnFollowing | ErrorFollowing | ErrorPreceding | FutureWarnFollowing + | FutureWarnPreceding => true, + DuplicatesOk | WarnFollowingWordOnly => false, + }) +} + pub static BUILTIN_ATTRIBUTE_MAP: LazyLock> = LazyLock::new(|| { let mut map = FxHashMap::default(); diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index e44c9291f848..bdaa0ee88eba 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -151,7 +151,7 @@ pub use active::{Features, ACTIVE_FEATURES, INCOMPATIBLE_FEATURES}; pub use builtin_attrs::AttributeDuplicates; pub use builtin_attrs::{ deprecated_attributes, find_gated_cfg, is_builtin_attr_name, is_builtin_only_local, - AttributeGate, AttributeTemplate, AttributeType, BuiltinAttribute, GatedCfg, - BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP, + is_valid_for_get_attr, AttributeGate, AttributeTemplate, AttributeType, BuiltinAttribute, + GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP, }; pub use removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES}; diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index ed04e7660339..58b0657a5b01 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2274,7 +2274,11 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn get_attr(self, did: DefId, attr: Symbol) -> Option<&'tcx ast::Attribute> { - self.get_attrs(did, attr).next() + if cfg!(debug_assertions) && !rustc_feature::is_valid_for_get_attr(attr) { + bug!("get_attr: unexpected called with DefId `{:?}`, attr `{:?}`", did, attr); + } else { + self.get_attrs(did, attr).next() + } } /// Determines whether an item is annotated with an attribute. diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 46135caa9bce..43893263be13 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -1459,7 +1459,7 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L def.destructor(tcx); // force the destructor to be evaluated if vs.is_empty() { - if let Some(attr) = tcx.get_attr(def_id.to_def_id(), sym::repr) { + if let Some(attr) = tcx.get_attrs(def_id.to_def_id(), sym::repr).next() { struct_span_err!( tcx.sess, attr.span, diff --git a/src/test/ui/attributes/issue-100631.rs b/src/test/ui/attributes/issue-100631.rs new file mode 100644 index 000000000000..0fefcf83fd51 --- /dev/null +++ b/src/test/ui/attributes/issue-100631.rs @@ -0,0 +1,8 @@ +// issue #100631, make sure `TyCtxt::get_attr` only called by case that compiler +// can reasonably deal with multiple attributes. +// `repr` will use `TyCtxt::get_attrs` since it's `DuplicatesOk`. +#[repr(C)] //~ ERROR: unsupported representation for zero-variant enum [E0084] +#[repr(C)] +enum Foo {} + +fn main() {} diff --git a/src/test/ui/attributes/issue-100631.stderr b/src/test/ui/attributes/issue-100631.stderr new file mode 100644 index 000000000000..caa5351ddc7a --- /dev/null +++ b/src/test/ui/attributes/issue-100631.stderr @@ -0,0 +1,12 @@ +error[E0084]: unsupported representation for zero-variant enum + --> $DIR/issue-100631.rs:4:1 + | +LL | #[repr(C)] + | ^^^^^^^^^^ +LL | #[repr(C)] +LL | enum Foo {} + | -------- zero-variant enum + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0084`. From 38935bbe6a91212e77d535dbad31d369e9a4a453 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 6 Sep 2022 07:08:12 +0000 Subject: [PATCH 4230/5092] Report number of delayed bugs properly with -Ztreat-err-as-bug --- compiler/rustc_errors/src/lib.rs | 39 ++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 68abdd0bad1f..37ff6dcff7d7 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1250,14 +1250,14 @@ impl HandlerInner { fn treat_err_as_bug(&self) -> bool { self.flags.treat_err_as_bug.map_or(false, |c| { - self.err_count() - + self.lint_err_count - + self.delayed_span_bugs.len() - + self.delayed_good_path_bugs.len() - >= c.get() + self.err_count() + self.lint_err_count + self.delayed_bug_count() >= c.get() }) } + fn delayed_bug_count(&self) -> usize { + self.delayed_span_bugs.len() + self.delayed_good_path_bugs.len() + } + fn print_error_count(&mut self, registry: &Registry) { self.emit_stashed_diagnostics(); @@ -1412,12 +1412,7 @@ impl HandlerInner { // incrementing `err_count` by one, so we need to +1 the comparing. // FIXME: Would be nice to increment err_count in a more coherent way. if self.flags.treat_err_as_bug.map_or(false, |c| { - self.err_count() - + self.lint_err_count - + self.delayed_span_bugs.len() - + self.delayed_good_path_bugs.len() - + 1 - >= c.get() + self.err_count() + self.lint_err_count + self.delayed_bug_count() + 1 >= c.get() }) { // FIXME: don't abort here if report_delayed_bugs is off self.span_bug(sp, msg); @@ -1518,14 +1513,24 @@ impl HandlerInner { if self.treat_err_as_bug() { match ( self.err_count() + self.lint_err_count, + self.delayed_bug_count(), self.flags.treat_err_as_bug.map(|c| c.get()).unwrap_or(0), ) { - (1, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"), - (0 | 1, _) => {} - (count, as_bug) => panic!( - "aborting after {} errors due to `-Z treat-err-as-bug={}`", - count, as_bug, - ), + (1, 0, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"), + (0, 1, 1) => panic!("aborting due delayed bug with `-Z treat-err-as-bug=1`"), + (count, delayed_count, as_bug) => { + if delayed_count > 0 { + panic!( + "aborting after {} errors and {} delayed bugs due to `-Z treat-err-as-bug={}`", + count, delayed_count, as_bug, + ) + } else { + panic!( + "aborting after {} errors due to `-Z treat-err-as-bug={}`", + count, as_bug, + ) + } + } } } } From b67271507d5a26416f83f1afe0e8f43cc77567ba Mon Sep 17 00:00:00 2001 From: Daniil Belov Date: Mon, 15 Aug 2022 13:15:01 +0300 Subject: [PATCH 4231/5092] change stdlib circular dependencies handling --- compiler/rustc_codegen_ssa/src/back/link.rs | 68 +++---------------- compiler/rustc_codegen_ssa/src/back/linker.rs | 42 ------------ compiler/rustc_codegen_ssa/src/base.rs | 44 +++++++----- compiler/rustc_codegen_ssa/src/lib.rs | 3 - compiler/rustc_hir/src/weak_lang_items.rs | 6 ++ 5 files changed, 41 insertions(+), 122 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index e9171823c242..d37a2cc8c8ec 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1,6 +1,6 @@ use rustc_arena::TypedArena; use rustc_ast::CRATE_NODE_ID; -use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_errors::{ErrorGuaranteed, Handler}; @@ -1714,6 +1714,13 @@ fn add_post_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor /// that are necessary for the linking. They are only present in symbol table but not actually /// used in any sections, so the linker will therefore pick relevant rlibs for linking, but /// unused `#[no_mangle]` or `#[used]` can still be discard by GC sections. +/// +/// There's a few internal crates in the standard library (aka libcore and +/// libstd) which actually have a circular dependence upon one another. This +/// currently arises through "weak lang items" where libcore requires things +/// like `rust_begin_unwind` but libstd ends up defining it. To get this +/// circular dependence to work correctly we declare some of these things +/// in this synthetic object. fn add_linked_symbol_object( cmd: &mut dyn Linker, sess: &Session, @@ -2333,65 +2340,10 @@ fn add_upstream_rust_crates<'a>( // crates. let deps = &codegen_results.crate_info.used_crates; - // There's a few internal crates in the standard library (aka libcore and - // libstd) which actually have a circular dependence upon one another. This - // currently arises through "weak lang items" where libcore requires things - // like `rust_begin_unwind` but libstd ends up defining it. To get this - // circular dependence to work correctly in all situations we'll need to be - // sure to correctly apply the `--start-group` and `--end-group` options to - // GNU linkers, otherwise if we don't use any other symbol from the standard - // library it'll get discarded and the whole application won't link. - // - // In this loop we're calculating the `group_end`, after which crate to - // pass `--end-group` and `group_start`, before which crate to pass - // `--start-group`. We currently do this by passing `--end-group` after - // the first crate (when iterating backwards) that requires a lang item - // defined somewhere else. Once that's set then when we've defined all the - // necessary lang items we'll pass `--start-group`. - // - // Note that this isn't amazing logic for now but it should do the trick - // for the current implementation of the standard library. - let mut group_end = None; - let mut group_start = None; - // Crates available for linking thus far. - let mut available = FxHashSet::default(); - // Crates required to satisfy dependencies discovered so far. - let mut required = FxHashSet::default(); - - let info = &codegen_results.crate_info; - for &cnum in deps.iter().rev() { - if let Some(missing) = info.missing_lang_items.get(&cnum) { - let missing_crates = missing.iter().map(|i| info.lang_item_to_crate.get(i).copied()); - required.extend(missing_crates); - } - - required.insert(Some(cnum)); - available.insert(Some(cnum)); - - if required.len() > available.len() && group_end.is_none() { - group_end = Some(cnum); - } - if required.len() == available.len() && group_end.is_some() { - group_start = Some(cnum); - break; - } - } - - // If we didn't end up filling in all lang items from upstream crates then - // we'll be filling it in with our crate. This probably means we're the - // standard library itself, so skip this for now. - if group_end.is_some() && group_start.is_none() { - group_end = None; - } - let mut compiler_builtins = None; let search_path = OnceCell::new(); for &cnum in deps.iter() { - if group_start == Some(cnum) { - cmd.group_start(); - } - // We may not pass all crates through to the linker. Some crates may // appear statically in an existing dylib, meaning we'll pick up all the // symbols from the dylib. @@ -2470,10 +2422,6 @@ fn add_upstream_rust_crates<'a>( } Linkage::Dynamic => add_dynamic_crate(cmd, sess, &src.dylib.as_ref().unwrap().0), } - - if group_end == Some(cnum) { - cmd.group_end(); - } } // compiler-builtins are always placed last to ensure that they're diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 8c6f526b054b..949a356fce1f 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -183,8 +183,6 @@ pub trait Linker { fn no_default_libraries(&mut self); fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]); fn subsystem(&mut self, subsystem: &str); - fn group_start(&mut self); - fn group_end(&mut self); fn linker_plugin_lto(&mut self); fn add_eh_frame_header(&mut self) {} fn add_no_exec(&mut self) {} @@ -730,18 +728,6 @@ impl<'a> Linker for GccLinker<'a> { self.hint_dynamic(); // Reset to default before returning the composed command line. } - fn group_start(&mut self) { - if self.takes_hints() { - self.linker_arg("--start-group"); - } - } - - fn group_end(&mut self) { - if self.takes_hints() { - self.linker_arg("--end-group"); - } - } - fn linker_plugin_lto(&mut self) { match self.sess.opts.cg.linker_plugin_lto { LinkerPluginLto::Disabled => { @@ -1019,10 +1005,6 @@ impl<'a> Linker for MsvcLinker<'a> { } } - // MSVC doesn't need group indicators - fn group_start(&mut self) {} - fn group_end(&mut self) {} - fn linker_plugin_lto(&mut self) { // Do nothing } @@ -1165,10 +1147,6 @@ impl<'a> Linker for EmLinker<'a> { // noop } - // Appears not necessary on Emscripten - fn group_start(&mut self) {} - fn group_end(&mut self) {} - fn linker_plugin_lto(&mut self) { // Do nothing } @@ -1344,10 +1322,6 @@ impl<'a> Linker for WasmLd<'a> { fn subsystem(&mut self, _subsystem: &str) {} - // Not needed for now with LLD - fn group_start(&mut self) {} - fn group_end(&mut self) {} - fn linker_plugin_lto(&mut self) { // Do nothing for now } @@ -1476,14 +1450,6 @@ impl<'a> Linker for L4Bender<'a> { self.hint_static(); // Reset to default before returning the composed command line. } - fn group_start(&mut self) { - self.cmd.arg("--start-group"); - } - - fn group_end(&mut self) { - self.cmd.arg("--end-group"); - } - fn linker_plugin_lto(&mut self) {} fn control_flow_guard(&mut self) {} @@ -1664,10 +1630,6 @@ impl<'a> Linker for PtxLinker<'a> { fn subsystem(&mut self, _subsystem: &str) {} - fn group_start(&mut self) {} - - fn group_end(&mut self) {} - fn linker_plugin_lto(&mut self) {} } @@ -1777,9 +1739,5 @@ impl<'a> Linker for BpfLinker<'a> { fn subsystem(&mut self, _subsystem: &str) {} - fn group_start(&mut self) {} - - fn group_end(&mut self) {} - fn linker_plugin_lto(&mut self) {} } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 6e482062383d..545f161139a0 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -12,7 +12,7 @@ use crate::traits::*; use crate::{CachedModuleCodegen, CompiledModule, CrateInfo, MemFlags, ModuleCodegen, ModuleKind}; use rustc_attr as attr; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; use rustc_data_structures::sync::par_iter; @@ -21,10 +21,12 @@ use rustc_data_structures::sync::ParallelIterator; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; +use rustc_hir::weak_lang_items::WEAK_ITEMS_SYMBOLS; use rustc_index::vec::Idx; use rustc_metadata::EncodedMetadata; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::middle::exported_symbols; +use rustc_middle::middle::exported_symbols::SymbolExportKind; use rustc_middle::middle::lang_items; use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; @@ -34,6 +36,7 @@ use rustc_session::cgu_reuse_tracker::CguReuse; use rustc_session::config::{self, CrateType, EntryFnType, OutputType}; use rustc_session::Session; use rustc_span::symbol::sym; +use rustc_span::Symbol; use rustc_span::{DebuggerVisualizerFile, DebuggerVisualizerType}; use rustc_target::abi::{Align, VariantIdx}; @@ -815,21 +818,16 @@ impl CrateInfo { crate_name: Default::default(), used_crates, used_crate_source: Default::default(), - lang_item_to_crate: Default::default(), - missing_lang_items: Default::default(), dependency_formats: tcx.dependency_formats(()).clone(), windows_subsystem, natvis_debugger_visualizers: Default::default(), }; - let lang_items = tcx.lang_items(); - let crates = tcx.crates(()); let n_crates = crates.len(); info.native_libraries.reserve(n_crates); info.crate_name.reserve(n_crates); info.used_crate_source.reserve(n_crates); - info.missing_lang_items.reserve(n_crates); for &cnum in crates.iter() { info.native_libraries @@ -847,19 +845,31 @@ impl CrateInfo { if tcx.is_no_builtins(cnum) { info.is_no_builtins.insert(cnum); } - let missing = tcx.missing_lang_items(cnum); - for &item in missing.iter() { - if let Ok(id) = lang_items.require(item) { - info.lang_item_to_crate.insert(item, id.krate); - } - } - - // No need to look for lang items that don't actually need to exist. - let missing = - missing.iter().cloned().filter(|&l| lang_items::required(tcx, l)).collect(); - info.missing_lang_items.insert(cnum, missing); } + // Handle circular dependencies in the standard library. + // See comment before `add_linked_symbol_object` function for the details. + let missing_weak_lang_items: FxHashSet<&Symbol> = info + .used_crates + .iter() + .flat_map(|cnum| { + tcx.missing_lang_items(*cnum) + .iter() + .filter(|l| lang_items::required(tcx, **l)) + .filter_map(|item| WEAK_ITEMS_SYMBOLS.get(item)) + }) + .collect(); + info.linked_symbols + .iter_mut() + .filter(|(crate_type, _)| !matches!(crate_type, CrateType::Rlib | CrateType::Staticlib)) + .for_each(|(_, linked_symbols)| { + linked_symbols.extend( + missing_weak_lang_items + .iter() + .map(|item| (item.to_string(), SymbolExportKind::Text)), + ) + }); + let embed_visualizers = tcx.sess.crate_types().iter().any(|&crate_type| match crate_type { CrateType::Executable | CrateType::Dylib | CrateType::Cdylib => { // These are crate types for which we invoke the linker and can embed diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 0faf51b062b4..52da7abcac54 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -25,7 +25,6 @@ use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; use rustc_hir::def_id::CrateNum; -use rustc_hir::LangItem; use rustc_middle::dep_graph::WorkProduct; use rustc_middle::middle::dependency_format::Dependencies; use rustc_middle::middle::exported_symbols::SymbolExportKind; @@ -152,8 +151,6 @@ pub struct CrateInfo { pub used_libraries: Vec, pub used_crate_source: FxHashMap>, pub used_crates: Vec, - pub lang_item_to_crate: FxHashMap, - pub missing_lang_items: FxHashMap>, pub dependency_formats: Lrc, pub windows_subsystem: Option, pub natvis_debugger_visualizers: BTreeSet, diff --git a/compiler/rustc_hir/src/weak_lang_items.rs b/compiler/rustc_hir/src/weak_lang_items.rs index b6a85c0472e0..da9c9c1216e9 100644 --- a/compiler/rustc_hir/src/weak_lang_items.rs +++ b/compiler/rustc_hir/src/weak_lang_items.rs @@ -18,6 +18,12 @@ pub static WEAK_ITEMS_REFS: LazyLock> = LazyLock::n map }); +pub static WEAK_ITEMS_SYMBOLS: LazyLock> = LazyLock::new(|| { + let mut map = FxIndexMap::default(); + $(map.insert(LangItem::$item, sym::$sym);)* + map +}); + pub fn link_name(attrs: &[ast::Attribute]) -> Option { lang_items::extract(attrs).and_then(|(name, _)| { From c34047cbd5222c239bdaaf306a5962d881908007 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 2 Sep 2022 14:31:08 +0300 Subject: [PATCH 4232/5092] Fix CI failures on windows and aarch64-linux --- compiler/rustc_codegen_ssa/src/back/link.rs | 8 ++++ compiler/rustc_codegen_ssa/src/base.rs | 48 ++++++++++++--------- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index d37a2cc8c8ec..a3fed88cc4ba 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2403,6 +2403,14 @@ fn add_upstream_rust_crates<'a>( bundle: Some(false), whole_archive: Some(false) | None, } => { + // HACK/FIXME: Fixup a circular dependency between libgcc and libc + // with glibc. This logic should be moved to the libc crate. + if sess.target.os == "linux" + && sess.target.env == "gnu" + && name == "c" + { + cmd.link_staticlib("gcc", false); + } cmd.link_staticlib(name, lib.verbatim.unwrap_or(false)); } NativeLibKind::LinkArg => { diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 545f161139a0..5f140d709d83 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -849,26 +849,34 @@ impl CrateInfo { // Handle circular dependencies in the standard library. // See comment before `add_linked_symbol_object` function for the details. - let missing_weak_lang_items: FxHashSet<&Symbol> = info - .used_crates - .iter() - .flat_map(|cnum| { - tcx.missing_lang_items(*cnum) - .iter() - .filter(|l| lang_items::required(tcx, **l)) - .filter_map(|item| WEAK_ITEMS_SYMBOLS.get(item)) - }) - .collect(); - info.linked_symbols - .iter_mut() - .filter(|(crate_type, _)| !matches!(crate_type, CrateType::Rlib | CrateType::Staticlib)) - .for_each(|(_, linked_symbols)| { - linked_symbols.extend( - missing_weak_lang_items + // With msvc-like linkers it's both unnecessary (they support circular dependencies), + // and causes linking issues (when weak lang item symbols are "privatized" by LTO). + let target = &tcx.sess.target; + if !target.is_like_msvc { + let missing_weak_lang_items: FxHashSet<&Symbol> = info + .used_crates + .iter() + .flat_map(|cnum| { + tcx.missing_lang_items(*cnum) .iter() - .map(|item| (item.to_string(), SymbolExportKind::Text)), - ) - }); + .filter(|l| lang_items::required(tcx, **l)) + .filter_map(|item| WEAK_ITEMS_SYMBOLS.get(item)) + }) + .collect(); + let prefix = if target.is_like_windows && target.arch == "x86" { "_" } else { "" }; + info.linked_symbols + .iter_mut() + .filter(|(crate_type, _)| { + !matches!(crate_type, CrateType::Rlib | CrateType::Staticlib) + }) + .for_each(|(_, linked_symbols)| { + linked_symbols.extend( + missing_weak_lang_items + .iter() + .map(|item| (format!("{prefix}{item}"), SymbolExportKind::Text)), + ) + }); + } let embed_visualizers = tcx.sess.crate_types().iter().any(|&crate_type| match crate_type { CrateType::Executable | CrateType::Dylib | CrateType::Cdylib => { @@ -888,7 +896,7 @@ impl CrateInfo { } }); - if tcx.sess.target.is_like_msvc && embed_visualizers { + if target.is_like_msvc && embed_visualizers { info.natvis_debugger_visualizers = collect_debugger_visualizers_transitive(tcx, DebuggerVisualizerType::Natvis); } From 774e71228cdea918a258f7d1d44251973ff4889d Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 6 Sep 2022 12:39:46 +0100 Subject: [PATCH 4233/5092] Fix compile errors for uwp-windows-msvc targets --- library/std/src/sys/windows/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index c2ad592dfea7..155d0297e49a 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -403,7 +403,7 @@ impl File { mem::size_of::().try_into().unwrap(), ))?; if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { - reparse_tag = attr_tag.ReparseTag; + attr.reparse_tag = attr_tag.ReparseTag; } } Ok(attr) From 3f45dc1472d2150bfca6d3b88ca29fc16ea24536 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 5 Sep 2022 21:58:12 -0300 Subject: [PATCH 4234/5092] fix RPIT ICE for implicit HRTB when missing dyn --- compiler/rustc_ast_lowering/src/lib.rs | 3 +-- ...plicit-hrtb-without-dyn.edition2015.stderr | 9 ++++++++ ...plicit-hrtb-without-dyn.edition2021.stderr | 22 +++++++++++++++++++ .../generic-with-implicit-hrtb-without-dyn.rs | 12 ++++++++++ 4 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2015.stderr create mode 100644 src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr create mode 100644 src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 85d6ed4f3ac8..17cdb6d2bb0c 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1568,8 +1568,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { LifetimeRes::Fresh { param, binder: _ } => { debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime); - let old_def_id = self.local_def_id(param); - if remapping.get(&old_def_id).is_none() { + if let Some(old_def_id) = self.opt_local_def_id(param) && remapping.get(&old_def_id).is_none() { let node_id = self.next_node_id(); let new_def_id = self.create_def( diff --git a/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2015.stderr b/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2015.stderr new file mode 100644 index 000000000000..fd2e454e7e45 --- /dev/null +++ b/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2015.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `(): AsRef<(dyn for<'r> Fn(&'r ()) + 'static)>` is not satisfied + --> $DIR/generic-with-implicit-hrtb-without-dyn.rs:6:13 + | +LL | fn ice() -> impl AsRef { + | ^^^^^^^^^^^^^^^^^^^ the trait `AsRef<(dyn for<'r> Fn(&'r ()) + 'static)>` is not implemented for `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr b/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr new file mode 100644 index 000000000000..c01c33a89312 --- /dev/null +++ b/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.edition2021.stderr @@ -0,0 +1,22 @@ +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/generic-with-implicit-hrtb-without-dyn.rs:6:24 + | +LL | fn ice() -> impl AsRef { + | ^^^^^^^ + | +help: add `dyn` keyword before this trait + | +LL - fn ice() -> impl AsRef { +LL + fn ice() -> impl AsRef { + | + +error[E0277]: the trait bound `(): AsRef<(dyn for<'r> Fn(&'r ()) + 'static)>` is not satisfied + --> $DIR/generic-with-implicit-hrtb-without-dyn.rs:6:13 + | +LL | fn ice() -> impl AsRef { + | ^^^^^^^^^^^^^^^^^^^ the trait `AsRef<(dyn for<'r> Fn(&'r ()) + 'static)>` is not implemented for `()` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0782. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs b/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs new file mode 100644 index 000000000000..856dc7a3f5a2 --- /dev/null +++ b/src/test/ui/impl-trait/generic-with-implicit-hrtb-without-dyn.rs @@ -0,0 +1,12 @@ +// revisions: edition2015 edition2021 +//[edition2021]edition:2021 + +#![allow(warnings)] + +fn ice() -> impl AsRef { + //~^ ERROR: the trait bound `(): AsRef<(dyn for<'r> Fn(&'r ()) + 'static)>` is not satisfied [E0277] + //[edition2021]~| ERROR: trait objects must include the `dyn` keyword [E0782] + todo!() +} + +fn main() {} From 9c4fb018cac37099a6e0981aa6248ee039aab42a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 6 Sep 2022 14:09:49 +0000 Subject: [PATCH 4235/5092] Remove dead broken code from const zst handling in backends --- compiler/rustc_codegen_gcc/src/common.rs | 4 ---- compiler/rustc_codegen_llvm/src/common.rs | 4 ---- compiler/rustc_codegen_ssa/src/mir/operand.rs | 9 +-------- compiler/rustc_codegen_ssa/src/traits/consts.rs | 1 - 4 files changed, 1 insertion(+), 17 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index ccb6cbbc2c8a..aa1c271c31cb 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -158,10 +158,6 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { None } - fn zst_to_backend(&self, _ty: Type<'gcc>) -> RValue<'gcc> { - self.const_undef(self.type_ix(0)) - } - fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) -> RValue<'gcc> { let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() }; match cv { diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 13e437cfbf7f..488ea72c3b77 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -226,10 +226,6 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { }) } - fn zst_to_backend(&self, _llty: &'ll Type) -> &'ll Value { - self.const_undef(self.type_ix(0)) - } - fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: &'ll Type) -> &'ll Value { let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() }; match cv { diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index c612634fce2a..37b1e036247b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -72,10 +72,6 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { ) -> Self { let layout = bx.layout_of(ty); - if layout.is_zst() { - return OperandRef::new_zst(bx, layout); - } - let val = match val { ConstValue::Scalar(x) => { let Abi::Scalar(scalar) = layout.abi else { @@ -84,10 +80,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let llval = bx.scalar_to_backend(x, scalar, bx.immediate_backend_type(layout)); OperandValue::Immediate(llval) } - ConstValue::ZeroSized => { - let llval = bx.zst_to_backend(bx.immediate_backend_type(layout)); - OperandValue::Immediate(llval) - } + ConstValue::ZeroSized => return OperandRef::new_zst(bx, layout), ConstValue::Slice { data, start, end } => { let Abi::ScalarPair(a_scalar, _) = layout.abi else { bug!("from_const: invalid ScalarPair layout: {:#?}", layout); diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs index 8a91d4735ba0..fdc7a30e841e 100644 --- a/compiler/rustc_codegen_ssa/src/traits/consts.rs +++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs @@ -29,7 +29,6 @@ pub trait ConstMethods<'tcx>: BackendTypes { fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value; fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value; - fn zst_to_backend(&self, llty: Self::Type) -> Self::Value; fn from_const_alloc( &self, layout: TyAndLayout<'tcx>, From 3f076451202409bca6262d7b5bf9a4fee3d18fb9 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 30 Jun 2022 08:16:05 +0000 Subject: [PATCH 4236/5092] Lower the assume intrinsic to a MIR statement --- compiler/rustc_borrowck/src/dataflow.rs | 1 + compiler/rustc_borrowck/src/invalidation.rs | 19 ++--- compiler/rustc_borrowck/src/lib.rs | 19 ++--- compiler/rustc_borrowck/src/type_check/mod.rs | 1 + compiler/rustc_codegen_cranelift/src/base.rs | 2 + .../rustc_codegen_cranelift/src/constant.rs | 1 + .../src/intrinsics/mod.rs | 3 - .../rustc_codegen_ssa/src/mir/intrinsic.rs | 4 -- .../rustc_codegen_ssa/src/mir/statement.rs | 5 ++ .../src/interpret/intrinsics.rs | 6 -- .../rustc_const_eval/src/interpret/step.rs | 9 +++ .../src/transform/check_consts/check.rs | 1 + .../src/transform/validate.rs | 9 +++ compiler/rustc_middle/src/mir/mod.rs | 1 + compiler/rustc_middle/src/mir/spanview.rs | 1 + compiler/rustc_middle/src/mir/syntax.rs | 8 +++ compiler/rustc_middle/src/mir/visit.rs | 3 + .../rustc_mir_dataflow/src/impls/liveness.rs | 1 + .../src/impls/storage_liveness.rs | 1 + .../src/move_paths/builder.rs | 1 + .../rustc_mir_transform/src/check_unsafety.rs | 3 + .../rustc_mir_transform/src/coverage/spans.rs | 1 + .../src/dead_store_elimination.rs | 1 + compiler/rustc_mir_transform/src/dest_prop.rs | 1 + compiler/rustc_mir_transform/src/generator.rs | 1 + .../src/lower_intrinsics.rs | 11 +++ .../src/remove_noop_landing_pads.rs | 1 + .../src/separate_const_switch.rs | 2 + compiler/rustc_mir_transform/src/simplify.rs | 1 + ...wer_intrinsics.assume.LowerIntrinsics.diff | 26 +++++++ ...f_copy_nonoverlapping.LowerIntrinsics.diff | 72 +++++++++++++++++++ src/test/mir-opt/lower_intrinsics.rs | 23 +++++- .../clippy_utils/src/qualify_min_const_fn.rs | 3 + 33 files changed, 212 insertions(+), 30 deletions(-) create mode 100644 src/test/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff create mode 100644 src/test/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 816288eb50b2..ec5fa76ff8ba 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -392,6 +392,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { | mir::StatementKind::AscribeUserType(..) | mir::StatementKind::Coverage(..) | mir::StatementKind::CopyNonOverlapping(..) + | mir::StatementKind::Assume(..) | mir::StatementKind::Nop => {} } } diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs index ec521b1cf0af..03ad973cf490 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/invalidation.rs @@ -72,14 +72,14 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { self.consume_operand(location, dst); self.consume_operand(location, count); } - StatementKind::Nop + // Only relevant for mir typeck + StatementKind::AscribeUserType(..) + // Doesn't have any language semantics | StatementKind::Coverage(..) - | StatementKind::AscribeUserType(..) - | StatementKind::Retag { .. } - | StatementKind::StorageLive(..) => { - // `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant - // to borrow check. - } + // Takes a `bool` argument, and has no return value, thus being irrelevant for borrowck + | StatementKind::Assume(..) + // Does not actually affect borrowck + | StatementKind::StorageLive(..) => {} StatementKind::StorageDead(local) => { self.access_place( location, @@ -88,7 +88,10 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { LocalMutationIsAllowed::Yes, ); } - StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => { + StatementKind::Nop + | StatementKind::Retag { .. } + | StatementKind::Deinit(..) + | StatementKind::SetDiscriminant { .. } => { bug!("Statement not allowed in this MIR phase") } } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 20c22575bd1f..663c880d0ae3 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -599,14 +599,14 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx "Unexpected CopyNonOverlapping, should only appear after lower_intrinsics", ) } - StatementKind::Nop + // Only relevant for mir typeck + StatementKind::AscribeUserType(..) + // Doesn't have any language semantics | StatementKind::Coverage(..) - | StatementKind::AscribeUserType(..) - | StatementKind::Retag { .. } - | StatementKind::StorageLive(..) => { - // `Nop`, `AscribeUserType`, `Retag`, and `StorageLive` are irrelevant - // to borrow check. - } + // Takes a `bool` argument, and has no return value, thus being irrelevant for borrowck + | StatementKind::Assume(..) + // Does not actually affect borrowck + | StatementKind::StorageLive(..) => {} StatementKind::StorageDead(local) => { self.access_place( location, @@ -616,7 +616,10 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx flow_state, ); } - StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => { + StatementKind::Nop + | StatementKind::Retag { .. } + | StatementKind::Deinit(..) + | StatementKind::SetDiscriminant { .. } => { bug!("Statement not allowed in this MIR phase") } } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index a620c987052b..e7713bda82c6 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1309,6 +1309,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { "Unexpected StatementKind::CopyNonOverlapping, should only appear after lowering_intrinsics", ), StatementKind::FakeRead(..) + | StatementKind::Assume(..) | StatementKind::StorageLive(..) | StatementKind::StorageDead(..) | StatementKind::Retag { .. } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index c412e451a033..1f49ead93a3e 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -791,6 +791,8 @@ fn codegen_stmt<'tcx>( | StatementKind::Nop | StatementKind::FakeRead(..) | StatementKind::Retag { .. } + // We ignore `assume` intrinsics, they are only useful for optimizations + | StatementKind::Assume(..) | StatementKind::AscribeUserType(..) => {} StatementKind::Coverage { .. } => fx.tcx.sess.fatal("-Zcoverage is unimplemented"), diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 9224f499339c..f75de9096f3a 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -540,6 +540,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( return None; } // conservative handling StatementKind::Assign(_) + | StatementKind::Assume(_) | StatementKind::FakeRead(_) | StatementKind::SetDiscriminant { .. } | StatementKind::Deinit(_) diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 39e9e784a478..0cd9332a58be 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -357,9 +357,6 @@ fn codegen_regular_intrinsic_call<'tcx>( let usize_layout = fx.layout_of(fx.tcx.types.usize); match intrinsic { - sym::assume => { - intrinsic_args!(fx, args => (_a); intrinsic); - } sym::likely | sym::unlikely => { intrinsic_args!(fx, args => (a); intrinsic); diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 16aad07194da..6393dd9d634f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -77,10 +77,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout); let llval = match name { - sym::assume => { - bx.assume(args[0].immediate()); - return; - } sym::abort => { bx.abort(); return; diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs index f452f29883f9..9869e61280dc 100644 --- a/compiler/rustc_codegen_ssa/src/mir/statement.rs +++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs @@ -93,6 +93,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.memcpy(dst, align, src, align, bytes, crate::MemFlags::empty()); bx } + mir::StatementKind::Assume(box ref op) => { + let op_val = self.codegen_operand(&mut bx, op); + bx.assume(op_val.immediate()); + bx + } mir::StatementKind::FakeRead(..) | mir::StatementKind::Retag { .. } | mir::StatementKind::AscribeUserType(..) diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index adda9639990d..8157ae2e5b83 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -506,12 +506,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // These just return their argument self.copy_op(&args[0], dest, /*allow_transmute*/ false)?; } - sym::assume => { - let cond = self.read_scalar(&args[0])?.to_bool()?; - if !cond { - throw_ub_format!("`assume` intrinsic called with `false`"); - } - } sym::raw_eq => { let result = self.raw_eq_intrinsic(&args[0], &args[1])?; self.write_scalar(result, dest)?; diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 6b827149f505..3ac1d1b31985 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -122,6 +122,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.copy_intrinsic(&src, &dst, &count, /* nonoverlapping */ true)?; } + // Call Assume + Assume(box op) => { + let op = self.eval_operand(op, None)?; + let cond = self.read_scalar(&op)?.to_bool()?; + if !cond { + throw_ub_format!("`assume` called with `false`"); + } + } + // Statements we do not track. AscribeUserType(..) => {} diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index cbfdb47dd1a4..347c31ceeeba 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -679,6 +679,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) | StatementKind::CopyNonOverlapping(..) + | StatementKind::Assume(..) | StatementKind::Nop => {} } } diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index b79886258395..dea445f60669 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -636,6 +636,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } } + StatementKind::Assume(box ref op) => { + let ty = op.ty(&self.body.local_decls, self.tcx); + if !ty.is_bool() { + self.fail( + location, + format!("`assume` argument must be `bool`, but got: `{}`", ty), + ); + } + } StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { ref src, ref dst, diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index f3676604bb0e..48eb292c4904 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1377,6 +1377,7 @@ impl Debug for Statement<'_> { }) => { write!(fmt, "copy_nonoverlapping(src={:?}, dst={:?}, count={:?})", src, dst, count) } + Assume(box ref cond) => write!(fmt, "assume({:?})", cond), Nop => write!(fmt, "nop"), } } diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs index 6e64a3b80c1f..cb5adee6910e 100644 --- a/compiler/rustc_middle/src/mir/spanview.rs +++ b/compiler/rustc_middle/src/mir/spanview.rs @@ -250,6 +250,7 @@ pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str { AscribeUserType(..) => "AscribeUserType", Coverage(..) => "Coverage", CopyNonOverlapping(..) => "CopyNonOverlapping", + Assume(..) => "Assume", Nop => "Nop", } } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index d7b9d59eced5..01ac2456a138 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -342,6 +342,14 @@ pub enum StatementKind<'tcx> { /// I vaguely remember Ralf saying somewhere that he thought it should not be. CopyNonOverlapping(Box>), + /// Denotes a call to the intrinsic function `assume`. + /// + /// The operand must be a boolean. Optimizers may use the value of the boolean to backtrack its + /// computation to infer information about other variables. So if the boolean came from a + /// `x < y` operation, subsequent operations on `x` and `y` could elide various bound checks. + /// If the argument is `false`, this operation is equivalent to `TerminatorKind::Unreachable`. + Assume(Box>), + /// No-op. Useful for deleting instructions without affecting statement indices. Nop, } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 7bd65f42e3f9..a0273e78b8f6 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -434,6 +434,9 @@ macro_rules! make_mir_visitor { self.visit_operand(dst, location); self.visit_operand(count, location) } + StatementKind::Assume(box ref $($mutability)? val) => { + self.visit_operand(val, location) + } StatementKind::Nop => {} } } diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index 483c1e274aa7..f3ea84e63507 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -271,6 +271,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) | StatementKind::CopyNonOverlapping(..) + | StatementKind::Assume(..) | StatementKind::Nop => None, }; if let Some(destination) = destination { diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index f6b5af90a85c..bab224a7e040 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -143,6 +143,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc | StatementKind::Nop | StatementKind::Retag(..) | StatementKind::CopyNonOverlapping(..) + | StatementKind::Assume(..) | StatementKind::StorageLive(..) => {} } } diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index c32583862239..d7ea3339a699 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -331,6 +331,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) | StatementKind::CopyNonOverlapping(..) + | StatementKind::Assume(..) | StatementKind::Nop => {} } } diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index 0f5fd77f7ab1..1a360a8d40bf 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -105,6 +105,9 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> { // safe (at least as emitted during MIR construction) } + // Move to above list once mir construction uses it. + StatementKind::Assume(..) => unreachable!(), + StatementKind::CopyNonOverlapping(..) => unreachable!(), } self.super_statement(statement, location); diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 423e78317aad..f5e91371b586 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -826,6 +826,7 @@ pub(super) fn filtered_statement_span(statement: &Statement<'_>) -> Option // Retain spans from all other statements StatementKind::FakeRead(box (_, _)) // Not including `ForGuardBinding` | StatementKind::CopyNonOverlapping(..) + | StatementKind::Assume(..) | StatementKind::Assign(_) | StatementKind::SetDiscriminant { .. } | StatementKind::Deinit(..) diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs index 9163672f5703..e95c5d888b2b 100644 --- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -53,6 +53,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS | StatementKind::StorageDead(_) | StatementKind::Coverage(_) | StatementKind::CopyNonOverlapping(_) + | StatementKind::Assume(_) | StatementKind::Nop => (), StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => { diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index da55510920e1..a2e12e40be99 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -538,6 +538,7 @@ impl<'a> Conflicts<'a> { | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) | StatementKind::CopyNonOverlapping(..) + | StatementKind::Assume(..) | StatementKind::Nop => {} } } diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index dbff4a6bd696..2bfcd82de5ee 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -1453,6 +1453,7 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> { | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) | StatementKind::CopyNonOverlapping(..) + | StatementKind::Assume(..) | StatementKind::Nop => {} } } diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index b7ba616510c2..652c344ee146 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -62,6 +62,17 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { drop(args); terminator.kind = TerminatorKind::Goto { target }; } + sym::assume => { + let target = target.unwrap(); + let mut args = args.drain(..); + block.statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assume(Box::new(args.next().unwrap())), + }); + assert_eq!(args.next(), None, "Extra argument for assume intrinsic"); + drop(args); + terminator.kind = TerminatorKind::Goto { target }; + } sym::wrapping_add | sym::wrapping_sub | sym::wrapping_mul => { if let Some(target) = *target { let lhs; diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs index 41a0bfac41ae..7d1ab06c3bdc 100644 --- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs +++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs @@ -52,6 +52,7 @@ impl RemoveNoopLandingPads { | StatementKind::SetDiscriminant { .. } | StatementKind::Deinit(..) | StatementKind::CopyNonOverlapping(..) + | StatementKind::Assume(..) | StatementKind::Retag { .. } => { return false; } diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs index 190f9c1ac158..34df693cf680 100644 --- a/compiler/rustc_mir_transform/src/separate_const_switch.rs +++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs @@ -250,6 +250,7 @@ fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData< | StatementKind::Coverage(_) | StatementKind::StorageDead(_) | StatementKind::CopyNonOverlapping(_) + | StatementKind::Assume(_) | StatementKind::Nop => {} } } @@ -318,6 +319,7 @@ fn find_determining_place<'tcx>( | StatementKind::AscribeUserType(_, _) | StatementKind::Coverage(_) | StatementKind::CopyNonOverlapping(_) + | StatementKind::Assume(_) | StatementKind::Nop => {} // If the discriminant is set, it is always set diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index bed48db959a5..b51d6d6f4feb 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -500,6 +500,7 @@ impl<'tcx> Visitor<'tcx> for UsedLocals { fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { match statement.kind { StatementKind::CopyNonOverlapping(..) + | StatementKind::Assume(..) | StatementKind::Retag(..) | StatementKind::Coverage(..) | StatementKind::FakeRead(..) diff --git a/src/test/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff new file mode 100644 index 000000000000..1a20fe136c21 --- /dev/null +++ b/src/test/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff @@ -0,0 +1,26 @@ +- // MIR for `assume` before LowerIntrinsics ++ // MIR for `assume` after LowerIntrinsics + + fn assume() -> () { + let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:17: +0:17 + let _1: (); // in scope 0 at $DIR/lower_intrinsics.rs:+2:9: +2:38 + scope 1 { + } + + bb0: { + StorageLive(_1); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38 +- _1 = std::intrinsics::assume(const true) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:97:9: 97:32 +- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(bool) {std::intrinsics::assume}, val: Value() } ++ assume(const true); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38 ++ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38 + } + + bb1: { + StorageDead(_1); // scope 1 at $DIR/lower_intrinsics.rs:+2:38: +2:39 + _0 = const (); // scope 1 at $DIR/lower_intrinsics.rs:+1:5: +3:6 + return; // scope 0 at $DIR/lower_intrinsics.rs:+4:2: +4:2 + } + } + diff --git a/src/test/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff new file mode 100644 index 000000000000..9681e3f696bf --- /dev/null +++ b/src/test/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff @@ -0,0 +1,72 @@ +- // MIR for `f_copy_nonoverlapping` before LowerIntrinsics ++ // MIR for `f_copy_nonoverlapping` after LowerIntrinsics + + fn f_copy_nonoverlapping() -> () { + let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:32: +0:32 + let _1: (); // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:12 + let _3: (); // in scope 0 at $DIR/lower_intrinsics.rs:+4:9: +4:95 + let mut _4: *const i32; // in scope 0 at $DIR/lower_intrinsics.rs:+4:29: +4:59 + let mut _5: *const (); // in scope 0 at $DIR/lower_intrinsics.rs:+4:29: +4:45 + let mut _6: *const (); // in scope 0 at $DIR/lower_intrinsics.rs:+4:29: +4:45 + let _7: &(); // in scope 0 at $DIR/lower_intrinsics.rs:+4:29: +4:33 + let mut _8: *mut i32; // in scope 0 at $DIR/lower_intrinsics.rs:+4:61: +4:91 + let mut _9: *mut (); // in scope 0 at $DIR/lower_intrinsics.rs:+4:61: +4:79 + let mut _10: *mut (); // in scope 0 at $DIR/lower_intrinsics.rs:+4:61: +4:79 + let mut _11: &mut (); // in scope 0 at $DIR/lower_intrinsics.rs:+4:61: +4:69 + scope 1 { + debug src => _1; // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:12 + let mut _2: (); // in scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:16 + scope 2 { + debug dst => _2; // in scope 2 at $DIR/lower_intrinsics.rs:+2:9: +2:16 + scope 3 { + } + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:12 + Deinit(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:15: +1:17 + StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:16 + Deinit(_2); // scope 1 at $DIR/lower_intrinsics.rs:+2:19: +2:21 + StorageLive(_3); // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95 + StorageLive(_4); // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:59 + StorageLive(_5); // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:45 + StorageLive(_6); // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:45 + StorageLive(_7); // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:33 + _7 = &_1; // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:33 + _6 = &raw const (*_7); // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:33 + _5 = _6; // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:45 + _4 = move _5 as *const i32 (Misc); // scope 3 at $DIR/lower_intrinsics.rs:+4:29: +4:59 + StorageDead(_5); // scope 3 at $DIR/lower_intrinsics.rs:+4:58: +4:59 + StorageLive(_8); // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:91 + StorageLive(_9); // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:79 + StorageLive(_10); // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:79 + StorageLive(_11); // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:69 + _11 = &mut _2; // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:69 + _10 = &raw mut (*_11); // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:69 + _9 = _10; // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:79 + _8 = move _9 as *mut i32 (Misc); // scope 3 at $DIR/lower_intrinsics.rs:+4:61: +4:91 + StorageDead(_9); // scope 3 at $DIR/lower_intrinsics.rs:+4:90: +4:91 +- _3 = copy_nonoverlapping::(move _4, move _8, const 0_usize) -> bb1; // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95 +- // mir::Constant +- // + span: $DIR/lower_intrinsics.rs:90:9: 90:28 +- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32, *mut i32, usize) {copy_nonoverlapping::}, val: Value() } ++ copy_nonoverlapping(src=move _4, dst=move _8, count=const 0_usize); // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95 ++ goto -> bb1; // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95 + } + + bb1: { + StorageDead(_8); // scope 3 at $DIR/lower_intrinsics.rs:+4:94: +4:95 + StorageDead(_4); // scope 3 at $DIR/lower_intrinsics.rs:+4:94: +4:95 + StorageDead(_11); // scope 3 at $DIR/lower_intrinsics.rs:+4:95: +4:96 + StorageDead(_10); // scope 3 at $DIR/lower_intrinsics.rs:+4:95: +4:96 + StorageDead(_7); // scope 3 at $DIR/lower_intrinsics.rs:+4:95: +4:96 + StorageDead(_6); // scope 3 at $DIR/lower_intrinsics.rs:+4:95: +4:96 + StorageDead(_3); // scope 3 at $DIR/lower_intrinsics.rs:+4:95: +4:96 + _0 = const (); // scope 3 at $DIR/lower_intrinsics.rs:+3:5: +5:6 + StorageDead(_2); // scope 1 at $DIR/lower_intrinsics.rs:+6:1: +6:2 + StorageDead(_1); // scope 0 at $DIR/lower_intrinsics.rs:+6:1: +6:2 + return; // scope 0 at $DIR/lower_intrinsics.rs:+6:2: +6:2 + } + } + diff --git a/src/test/mir-opt/lower_intrinsics.rs b/src/test/mir-opt/lower_intrinsics.rs index 195543d42bb5..66dae0e46b9d 100644 --- a/src/test/mir-opt/lower_intrinsics.rs +++ b/src/test/mir-opt/lower_intrinsics.rs @@ -1,7 +1,7 @@ // unit-test: LowerIntrinsics // ignore-wasm32 compiled with panic=abort by default -#![feature(core_intrinsics)] +#![feature(core_intrinsics, intrinsics)] #![crate_type = "lib"] // EMIT_MIR lower_intrinsics.wrapping.LowerIntrinsics.diff @@ -51,3 +51,24 @@ pub fn discriminant(t: T) { core::intrinsics::discriminant_value(&()); core::intrinsics::discriminant_value(&E::B); } + +extern "rust-intrinsic" { + // Cannot use `std::intrinsics::copy_nonoverlapping` as that is a wrapper function + fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); +} + +// EMIT_MIR lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff +pub fn f_copy_nonoverlapping() { + let src = (); + let mut dst = (); + unsafe { + copy_nonoverlapping(&src as *const _ as *const i32, &mut dst as *mut _ as *mut i32, 0); + } +} + +// EMIT_MIR lower_intrinsics.assume.LowerIntrinsics.diff +pub fn assume() { + unsafe { + std::intrinsics::assume(true); + } +} diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 74c222bbcbeb..1c12da7f7416 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -211,6 +211,9 @@ fn check_statement<'tcx>( StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => { check_place(tcx, **place, span, body) }, + StatementKind::Assume(box op) => { + check_operand(tcx, op, span, body) + }, StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { dst, src, count }) => { check_operand(tcx, dst, span, body)?; From b7413511dc85ec01ef4b91785f86614589ac6103 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 12 Jul 2022 10:05:00 +0000 Subject: [PATCH 4237/5092] Generalize the Assume intrinsic statement to a general Intrinsic statement --- compiler/rustc_borrowck/src/dataflow.rs | 3 +- compiler/rustc_borrowck/src/invalidation.rs | 11 ++-- compiler/rustc_borrowck/src/lib.rs | 14 +++--- compiler/rustc_borrowck/src/type_check/mod.rs | 14 +++--- compiler/rustc_codegen_cranelift/src/base.rs | 41 +++++++++------ .../rustc_codegen_cranelift/src/constant.rs | 9 ++-- .../rustc_codegen_ssa/src/mir/statement.rs | 19 ++++--- .../rustc_const_eval/src/interpret/step.rs | 23 +++++---- .../src/transform/check_consts/check.rs | 3 +- .../src/transform/validate.rs | 17 +++---- compiler/rustc_middle/src/mir/mod.rs | 9 +--- compiler/rustc_middle/src/mir/spanview.rs | 3 +- compiler/rustc_middle/src/mir/syntax.rs | 50 +++++++++++++++---- compiler/rustc_middle/src/mir/visit.rs | 20 ++++---- .../rustc_mir_dataflow/src/impls/liveness.rs | 3 +- .../src/impls/storage_liveness.rs | 3 +- .../src/move_paths/builder.rs | 3 +- .../rustc_mir_transform/src/check_unsafety.rs | 4 +- .../rustc_mir_transform/src/coverage/spans.rs | 3 +- .../src/dead_store_elimination.rs | 3 +- compiler/rustc_mir_transform/src/dest_prop.rs | 3 +- compiler/rustc_mir_transform/src/generator.rs | 3 +- .../src/lower_intrinsics.rs | 24 ++++++--- .../src/remove_noop_landing_pads.rs | 3 +- .../src/separate_const_switch.rs | 6 +-- compiler/rustc_mir_transform/src/simplify.rs | 3 +- ...f_copy_nonoverlapping.LowerIntrinsics.diff | 2 +- .../clippy_utils/src/qualify_min_const_fn.rs | 10 ++-- 28 files changed, 166 insertions(+), 143 deletions(-) diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index ec5fa76ff8ba..9f7a4d49989a 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -391,8 +391,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { | mir::StatementKind::Retag { .. } | mir::StatementKind::AscribeUserType(..) | mir::StatementKind::Coverage(..) - | mir::StatementKind::CopyNonOverlapping(..) - | mir::StatementKind::Assume(..) + | mir::StatementKind::Intrinsic(..) | mir::StatementKind::Nop => {} } } diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs index 03ad973cf490..3157f861d93b 100644 --- a/compiler/rustc_borrowck/src/invalidation.rs +++ b/compiler/rustc_borrowck/src/invalidation.rs @@ -1,6 +1,6 @@ use rustc_data_structures::graph::dominators::Dominators; use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{BasicBlock, Body, Location, Place, Rvalue}; +use rustc_middle::mir::{self, BasicBlock, Body, Location, NonDivergingIntrinsic, Place, Rvalue}; use rustc_middle::mir::{BorrowKind, Mutability, Operand}; use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind}; use rustc_middle::mir::{Statement, StatementKind}; @@ -63,11 +63,14 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { StatementKind::FakeRead(box (_, _)) => { // Only relevant for initialized/liveness/safety checks. } - StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { + StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => { + self.consume_operand(location, op); + } + StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping { ref src, ref dst, ref count, - }) => { + })) => { self.consume_operand(location, src); self.consume_operand(location, dst); self.consume_operand(location, count); @@ -76,8 +79,6 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { StatementKind::AscribeUserType(..) // Doesn't have any language semantics | StatementKind::Coverage(..) - // Takes a `bool` argument, and has no return value, thus being irrelevant for borrowck - | StatementKind::Assume(..) // Does not actually affect borrowck | StatementKind::StorageLive(..) => {} StatementKind::StorageDead(local) => { diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 663c880d0ae3..3b2bcd7e6d3a 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -26,8 +26,8 @@ use rustc_index::bit_set::ChunkedBitSet; use rustc_index::vec::IndexVec; use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt}; use rustc_middle::mir::{ - traversal, Body, ClearCrossCrate, Local, Location, Mutability, Operand, Place, PlaceElem, - PlaceRef, VarDebugInfoContents, + traversal, Body, ClearCrossCrate, Local, Location, Mutability, NonDivergingIntrinsic, Operand, + Place, PlaceElem, PlaceRef, VarDebugInfoContents, }; use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind}; use rustc_middle::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind}; @@ -591,10 +591,10 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx flow_state, ); } - StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { - .. - }) => { - span_bug!( + StatementKind::Intrinsic(box ref kind) => match kind { + // Takes a `bool` argument, and has no return value, thus being irrelevant for borrowck + NonDivergingIntrinsic::Assume(..) => {}, + NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!( span, "Unexpected CopyNonOverlapping, should only appear after lower_intrinsics", ) @@ -603,8 +603,6 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx StatementKind::AscribeUserType(..) // Doesn't have any language semantics | StatementKind::Coverage(..) - // Takes a `bool` argument, and has no return value, thus being irrelevant for borrowck - | StatementKind::Assume(..) // Does not actually affect borrowck | StatementKind::StorageLive(..) => {} StatementKind::StorageDead(local) => { diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index e7713bda82c6..2ba9b2be9018 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1302,14 +1302,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); } } - StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { - .. - }) => span_bug!( - stmt.source_info.span, - "Unexpected StatementKind::CopyNonOverlapping, should only appear after lowering_intrinsics", - ), + StatementKind::Intrinsic(box ref kind) => match kind { + NonDivergingIntrinsic::Assume(..) => {} + NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!( + stmt.source_info.span, + "Unexpected NonDivergingIntrinsic::CopyNonOverlapping, should only appear after lowering_intrinsics", + ), + }, StatementKind::FakeRead(..) - | StatementKind::Assume(..) | StatementKind::StorageLive(..) | StatementKind::StorageDead(..) | StatementKind::Retag { .. } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 1f49ead93a3e..2aa11ac2eeaa 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -791,25 +791,34 @@ fn codegen_stmt<'tcx>( | StatementKind::Nop | StatementKind::FakeRead(..) | StatementKind::Retag { .. } - // We ignore `assume` intrinsics, they are only useful for optimizations - | StatementKind::Assume(..) | StatementKind::AscribeUserType(..) => {} StatementKind::Coverage { .. } => fx.tcx.sess.fatal("-Zcoverage is unimplemented"), - StatementKind::CopyNonOverlapping(inner) => { - let dst = codegen_operand(fx, &inner.dst); - let pointee = dst - .layout() - .pointee_info_at(fx, rustc_target::abi::Size::ZERO) - .expect("Expected pointer"); - let dst = dst.load_scalar(fx); - let src = codegen_operand(fx, &inner.src).load_scalar(fx); - let count = codegen_operand(fx, &inner.count).load_scalar(fx); - let elem_size: u64 = pointee.size.bytes(); - let bytes = - if elem_size != 1 { fx.bcx.ins().imul_imm(count, elem_size as i64) } else { count }; - fx.bcx.call_memcpy(fx.target_config, dst, src, bytes); - } + StatementKind::Intrinsic(ref intrinsic) => match &**intrinsic { + // We ignore `assume` intrinsics, they are only useful for optimizations + NonDivergingIntrinsic::Assume(_) => {} + NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping { + src, + dst, + count, + }) => { + let dst = codegen_operand(fx, dst); + let pointee = dst + .layout() + .pointee_info_at(fx, rustc_target::abi::Size::ZERO) + .expect("Expected pointer"); + let dst = dst.load_scalar(fx); + let src = codegen_operand(fx, src).load_scalar(fx); + let count = codegen_operand(fx, count).load_scalar(fx); + let elem_size: u64 = pointee.size.bytes(); + let bytes = if elem_size != 1 { + fx.bcx.ins().imul_imm(count, elem_size as i64) + } else { + count + }; + fx.bcx.call_memcpy(fx.target_config, dst, src, bytes); + } + }, } } diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index f75de9096f3a..0305341da784 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -536,11 +536,12 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( { return None; } - StatementKind::CopyNonOverlapping(_) => { - return None; - } // conservative handling + StatementKind::Intrinsic(ref intrinsic) => match **intrinsic { + NonDivergingIntrinsic::CopyNonOverlapping(..) => return None, + NonDivergingIntrinsic::Assume(..) => {} + }, + // conservative handling StatementKind::Assign(_) - | StatementKind::Assume(_) | StatementKind::FakeRead(_) | StatementKind::SetDiscriminant { .. } | StatementKind::Deinit(_) diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs index 9869e61280dc..1db0fb3a6f1b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/statement.rs +++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs @@ -1,4 +1,5 @@ use rustc_middle::mir; +use rustc_middle::mir::NonDivergingIntrinsic; use super::FunctionCx; use super::LocalRef; @@ -73,11 +74,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.codegen_coverage(&mut bx, coverage.clone(), statement.source_info.scope); bx } - mir::StatementKind::CopyNonOverlapping(box mir::CopyNonOverlapping { - ref src, - ref dst, - ref count, - }) => { + mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(ref op)) => { + let op_val = self.codegen_operand(&mut bx, op); + bx.assume(op_val.immediate()); + bx + } + mir::StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping( + mir::CopyNonOverlapping { ref count, ref src, ref dst }, + )) => { let dst_val = self.codegen_operand(&mut bx, dst); let src_val = self.codegen_operand(&mut bx, src); let count = self.codegen_operand(&mut bx, count).immediate(); @@ -93,11 +97,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.memcpy(dst, align, src, align, bytes, crate::MemFlags::empty()); bx } - mir::StatementKind::Assume(box ref op) => { - let op_val = self.codegen_operand(&mut bx, op); - bx.assume(op_val.immediate()); - bx - } mir::StatementKind::FakeRead(..) | mir::StatementKind::Retag { .. } | mir::StatementKind::AscribeUserType(..) diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 3ac1d1b31985..3cf38258b758 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -2,8 +2,8 @@ //! //! The main entry point is the `step` method. -use rustc_middle::mir; use rustc_middle::mir::interpret::{InterpResult, Scalar}; +use rustc_middle::mir::{self, NonDivergingIntrinsic}; use rustc_middle::ty::layout::LayoutOf; use super::{InterpCx, Machine}; @@ -114,22 +114,23 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { M::retag(self, *kind, &dest)?; } - // Call CopyNonOverlapping - CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { src, dst, count }) => { - let src = self.eval_operand(src, None)?; - let dst = self.eval_operand(dst, None)?; - let count = self.eval_operand(count, None)?; - self.copy_intrinsic(&src, &dst, &count, /* nonoverlapping */ true)?; - } - - // Call Assume - Assume(box op) => { + Intrinsic(box NonDivergingIntrinsic::Assume(op)) => { let op = self.eval_operand(op, None)?; let cond = self.read_scalar(&op)?.to_bool()?; if !cond { throw_ub_format!("`assume` called with `false`"); } } + Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping { + ref count, + ref src, + ref dst, + })) => { + let src = self.eval_operand(src, None)?; + let dst = self.eval_operand(dst, None)?; + let count = self.eval_operand(count, None)?; + self.copy_intrinsic(&src, &dst, &count, /* nonoverlapping */ true)?; + } // Statements we do not track. AscribeUserType(..) => {} diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 347c31ceeeba..3fa40dc30595 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -678,8 +678,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { | StatementKind::Retag { .. } | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) - | StatementKind::CopyNonOverlapping(..) - | StatementKind::Assume(..) + | StatementKind::Intrinsic(..) | StatementKind::Nop => {} } } diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index dea445f60669..783ab350faac 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -7,9 +7,10 @@ use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::visit::NonUseContext::VarDebugInfo; use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::{ - traversal, AggregateKind, BasicBlock, BinOp, Body, BorrowKind, CastKind, Local, Location, - MirPass, MirPhase, Operand, Place, PlaceElem, PlaceRef, ProjectionElem, RuntimePhase, Rvalue, - SourceScope, Statement, StatementKind, Terminator, TerminatorKind, UnOp, START_BLOCK, + traversal, AggregateKind, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping, + Local, Location, MirPass, MirPhase, NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef, + ProjectionElem, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, Terminator, + TerminatorKind, UnOp, START_BLOCK, }; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::subst::Subst; @@ -636,7 +637,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } } - StatementKind::Assume(box ref op) => { + StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => { let ty = op.ty(&self.body.local_decls, self.tcx); if !ty.is_bool() { self.fail( @@ -645,11 +646,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } } - StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { - ref src, - ref dst, - ref count, - }) => { + StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping( + CopyNonOverlapping { src, dst, count }, + )) => { let src_ty = src.ty(&self.body.local_decls, self.tcx); let op_src_ty = if let Some(src_deref) = src_ty.builtin_deref(true) { src_deref.ty diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 48eb292c4904..091cc84af3ce 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1370,14 +1370,7 @@ impl Debug for Statement<'_> { write!(fmt, "Coverage::{:?} for {:?}", kind, rgn) } Coverage(box ref coverage) => write!(fmt, "Coverage::{:?}", coverage.kind), - CopyNonOverlapping(box crate::mir::CopyNonOverlapping { - ref src, - ref dst, - ref count, - }) => { - write!(fmt, "copy_nonoverlapping(src={:?}, dst={:?}, count={:?})", src, dst, count) - } - Assume(box ref cond) => write!(fmt, "assume({:?})", cond), + Intrinsic(box ref intrinsic) => write!(fmt, "{intrinsic}"), Nop => write!(fmt, "nop"), } } diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs index cb5adee6910e..4e06d91012c0 100644 --- a/compiler/rustc_middle/src/mir/spanview.rs +++ b/compiler/rustc_middle/src/mir/spanview.rs @@ -249,8 +249,7 @@ pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str { Retag(..) => "Retag", AscribeUserType(..) => "AscribeUserType", Coverage(..) => "Coverage", - CopyNonOverlapping(..) => "CopyNonOverlapping", - Assume(..) => "Assume", + Intrinsic(..) => "Intrinsic", Nop => "Nop", } } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 01ac2456a138..62306159e880 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -327,6 +327,34 @@ pub enum StatementKind<'tcx> { /// executed. Coverage(Box), + /// Denotes a call to an intrinsic that does not require an unwind path. This avoids + /// adding a new block and a terminator for simple intrinsics. + Intrinsic(Box>), + + /// No-op. Useful for deleting instructions without affecting statement indices. + Nop, +} + +#[derive( + Clone, + TyEncodable, + TyDecodable, + Debug, + PartialEq, + Hash, + HashStable, + TypeFoldable, + TypeVisitable +)] +pub enum NonDivergingIntrinsic<'tcx> { + /// Denotes a call to the intrinsic function `assume`. + /// + /// The operand must be a boolean. Optimizers may use the value of the boolean to backtrack its + /// computation to infer information about other variables. So if the boolean came from a + /// `x < y` operation, subsequent operations on `x` and `y` could elide various bound checks. + /// If the argument is `false`, this operation is equivalent to `TerminatorKind::Unreachable`. + Assume(Operand<'tcx>), + /// Denotes a call to the intrinsic function `copy_nonoverlapping`. /// /// First, all three operands are evaluated. `src` and `dest` must each be a reference, pointer, @@ -340,18 +368,18 @@ pub enum StatementKind<'tcx> { /// /// **Needs clarification**: Is this typed or not, ie is there a typed load and store involved? /// I vaguely remember Ralf saying somewhere that he thought it should not be. - CopyNonOverlapping(Box>), + CopyNonOverlapping(CopyNonOverlapping<'tcx>), +} - /// Denotes a call to the intrinsic function `assume`. - /// - /// The operand must be a boolean. Optimizers may use the value of the boolean to backtrack its - /// computation to infer information about other variables. So if the boolean came from a - /// `x < y` operation, subsequent operations on `x` and `y` could elide various bound checks. - /// If the argument is `false`, this operation is equivalent to `TerminatorKind::Unreachable`. - Assume(Box>), - - /// No-op. Useful for deleting instructions without affecting statement indices. - Nop, +impl std::fmt::Display for NonDivergingIntrinsic<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Assume(op) => write!(f, "assume({op:?})"), + Self::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => { + write!(f, "copy_nonoverlapping(dst = {dst:?}, src = {src:?}, count = {count:?})") + } + } + } } /// Describes what kind of retag is to be performed. diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index a0273e78b8f6..708ea4398c85 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -425,17 +425,15 @@ macro_rules! make_mir_visitor { location ) } - StatementKind::CopyNonOverlapping(box crate::mir::CopyNonOverlapping{ - src, - dst, - count, - }) => { - self.visit_operand(src, location); - self.visit_operand(dst, location); - self.visit_operand(count, location) - } - StatementKind::Assume(box ref $($mutability)? val) => { - self.visit_operand(val, location) + StatementKind::Intrinsic(box ref $($mutability)? intrinsic) => { + match intrinsic { + NonDivergingIntrinsic::Assume(op) => self.visit_operand(op, location), + NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => { + self.visit_operand(src, location); + self.visit_operand(dst, location); + self.visit_operand(count, location); + } + } } StatementKind::Nop => {} } diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs index f3ea84e63507..3e08a8799ef9 100644 --- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs @@ -270,8 +270,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> { | StatementKind::Retag(..) | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) - | StatementKind::CopyNonOverlapping(..) - | StatementKind::Assume(..) + | StatementKind::Intrinsic(..) | StatementKind::Nop => None, }; if let Some(destination) = destination { diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index bab224a7e040..18760b6c6fa5 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -142,8 +142,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc | StatementKind::FakeRead(..) | StatementKind::Nop | StatementKind::Retag(..) - | StatementKind::CopyNonOverlapping(..) - | StatementKind::Assume(..) + | StatementKind::Intrinsic(..) | StatementKind::StorageLive(..) => {} } } diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index d7ea3339a699..f46fd118bde5 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -330,8 +330,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { StatementKind::Retag { .. } | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) - | StatementKind::CopyNonOverlapping(..) - | StatementKind::Assume(..) + | StatementKind::Intrinsic(..) | StatementKind::Nop => {} } } diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index 1a360a8d40bf..beff19a3ab2e 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -106,9 +106,7 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> { } // Move to above list once mir construction uses it. - StatementKind::Assume(..) => unreachable!(), - - StatementKind::CopyNonOverlapping(..) => unreachable!(), + StatementKind::Intrinsic(..) => unreachable!(), } self.super_statement(statement, location); } diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index f5e91371b586..9f842c929dc2 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -825,8 +825,7 @@ pub(super) fn filtered_statement_span(statement: &Statement<'_>) -> Option // Retain spans from all other statements StatementKind::FakeRead(box (_, _)) // Not including `ForGuardBinding` - | StatementKind::CopyNonOverlapping(..) - | StatementKind::Assume(..) + | StatementKind::Intrinsic(..) | StatementKind::Assign(_) | StatementKind::SetDiscriminant { .. } | StatementKind::Deinit(..) diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs index e95c5d888b2b..3f3870cc7bad 100644 --- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs +++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs @@ -52,8 +52,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS | StatementKind::StorageLive(_) | StatementKind::StorageDead(_) | StatementKind::Coverage(_) - | StatementKind::CopyNonOverlapping(_) - | StatementKind::Assume(_) + | StatementKind::Intrinsic(_) | StatementKind::Nop => (), StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => { diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index a2e12e40be99..9bc47613e4c6 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -537,8 +537,7 @@ impl<'a> Conflicts<'a> { | StatementKind::FakeRead(..) | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) - | StatementKind::CopyNonOverlapping(..) - | StatementKind::Assume(..) + | StatementKind::Intrinsic(..) | StatementKind::Nop => {} } } diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index 2bfcd82de5ee..705cf776fb29 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -1452,8 +1452,7 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> { | StatementKind::Retag(..) | StatementKind::AscribeUserType(..) | StatementKind::Coverage(..) - | StatementKind::CopyNonOverlapping(..) - | StatementKind::Assume(..) + | StatementKind::Intrinsic(..) | StatementKind::Nop => {} } } diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index 652c344ee146..9892580e63dc 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -46,12 +46,14 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { let mut args = args.drain(..); block.statements.push(Statement { source_info: terminator.source_info, - kind: StatementKind::CopyNonOverlapping(Box::new( - rustc_middle::mir::CopyNonOverlapping { - src: args.next().unwrap(), - dst: args.next().unwrap(), - count: args.next().unwrap(), - }, + kind: StatementKind::Intrinsic(Box::new( + NonDivergingIntrinsic::CopyNonOverlapping( + rustc_middle::mir::CopyNonOverlapping { + src: args.next().unwrap(), + dst: args.next().unwrap(), + count: args.next().unwrap(), + }, + ), )), }); assert_eq!( @@ -67,9 +69,15 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { let mut args = args.drain(..); block.statements.push(Statement { source_info: terminator.source_info, - kind: StatementKind::Assume(Box::new(args.next().unwrap())), + kind: StatementKind::Intrinsic(Box::new( + NonDivergingIntrinsic::Assume(args.next().unwrap()), + )), }); - assert_eq!(args.next(), None, "Extra argument for assume intrinsic"); + assert_eq!( + args.next(), + None, + "Extra argument for copy_non_overlapping intrinsic" + ); drop(args); terminator.kind = TerminatorKind::Goto { target }; } diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs index 7d1ab06c3bdc..f1bbf2ea7e8e 100644 --- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs +++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs @@ -51,8 +51,7 @@ impl RemoveNoopLandingPads { StatementKind::Assign { .. } | StatementKind::SetDiscriminant { .. } | StatementKind::Deinit(..) - | StatementKind::CopyNonOverlapping(..) - | StatementKind::Assume(..) + | StatementKind::Intrinsic(..) | StatementKind::Retag { .. } => { return false; } diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs index 34df693cf680..2f116aaa9584 100644 --- a/compiler/rustc_mir_transform/src/separate_const_switch.rs +++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs @@ -249,8 +249,7 @@ fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData< | StatementKind::AscribeUserType(_, _) | StatementKind::Coverage(_) | StatementKind::StorageDead(_) - | StatementKind::CopyNonOverlapping(_) - | StatementKind::Assume(_) + | StatementKind::Intrinsic(_) | StatementKind::Nop => {} } } @@ -318,8 +317,7 @@ fn find_determining_place<'tcx>( | StatementKind::Retag(_, _) | StatementKind::AscribeUserType(_, _) | StatementKind::Coverage(_) - | StatementKind::CopyNonOverlapping(_) - | StatementKind::Assume(_) + | StatementKind::Intrinsic(_) | StatementKind::Nop => {} // If the discriminant is set, it is always set diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index b51d6d6f4feb..57d372fda569 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -499,8 +499,7 @@ impl UsedLocals { impl<'tcx> Visitor<'tcx> for UsedLocals { fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { match statement.kind { - StatementKind::CopyNonOverlapping(..) - | StatementKind::Assume(..) + StatementKind::Intrinsic(..) | StatementKind::Retag(..) | StatementKind::Coverage(..) | StatementKind::FakeRead(..) diff --git a/src/test/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff index 9681e3f696bf..74e22ebb7ffc 100644 --- a/src/test/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff @@ -51,7 +51,7 @@ - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:90:9: 90:28 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32, *mut i32, usize) {copy_nonoverlapping::}, val: Value() } -+ copy_nonoverlapping(src=move _4, dst=move _8, count=const 0_usize); // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95 ++ copy_nonoverlapping(dst = move _8, src = move _4, count = const 0_usize); // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95 + goto -> bb1; // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95 } diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 1c12da7f7416..b22a9c817460 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -7,7 +7,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::mir::{ Body, CastKind, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, - TerminatorKind, + TerminatorKind, NonDivergingIntrinsic }; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt}; @@ -211,15 +211,19 @@ fn check_statement<'tcx>( StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => { check_place(tcx, **place, span, body) }, - StatementKind::Assume(box op) => { + + StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => { check_operand(tcx, op, span, body) }, - StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { dst, src, count }) => { + StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping( + rustc_middle::mir::CopyNonOverlapping { dst, src, count }, + )) => { check_operand(tcx, dst, span, body)?; check_operand(tcx, src, span, body)?; check_operand(tcx, count, span, body) }, + // These are all NOPs StatementKind::StorageLive(_) | StatementKind::StorageDead(_) From 104f97e5aa26287ed4b1c2bb4258557700a49da6 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 31 Aug 2022 15:23:41 +0000 Subject: [PATCH 4238/5092] Move CTFE handling of nondiverging intrinsics to intrinsics.rs --- .../src/interpret/intrinsics.rs | 28 ++++++++++++++++++- .../rustc_const_eval/src/interpret/step.rs | 20 ++----------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 8157ae2e5b83..2f415a8c9c70 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -8,7 +8,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::mir::{ self, interpret::{ConstValue, GlobalId, InterpResult, PointerArithmetic, Scalar}, - BinOp, + BinOp, NonDivergingIntrinsic, }; use rustc_middle::ty; use rustc_middle::ty::layout::LayoutOf as _; @@ -530,6 +530,32 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(true) } + pub(super) fn emulate_nondiverging_intrinsic( + &mut self, + intrinsic: &NonDivergingIntrinsic<'tcx>, + ) -> InterpResult<'tcx> { + match intrinsic { + NonDivergingIntrinsic::Assume(op) => { + let op = self.eval_operand(op, None)?; + let cond = self.read_scalar(&op)?.to_bool()?; + if !cond { + throw_ub_format!("`assume` called with `false`"); + } + Ok(()) + } + NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping { + count, + src, + dst, + }) => { + let src = self.eval_operand(src, None)?; + let dst = self.eval_operand(dst, None)?; + let count = self.eval_operand(count, None)?; + self.copy_intrinsic(&src, &dst, &count, /* nonoverlapping */ true) + } + } + } + pub fn exact_div( &mut self, a: &ImmTy<'tcx, M::Provenance>, diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 3cf38258b758..c6e04cbfb6bf 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -2,8 +2,8 @@ //! //! The main entry point is the `step` method. +use rustc_middle::mir; use rustc_middle::mir::interpret::{InterpResult, Scalar}; -use rustc_middle::mir::{self, NonDivergingIntrinsic}; use rustc_middle::ty::layout::LayoutOf; use super::{InterpCx, Machine}; @@ -114,23 +114,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { M::retag(self, *kind, &dest)?; } - Intrinsic(box NonDivergingIntrinsic::Assume(op)) => { - let op = self.eval_operand(op, None)?; - let cond = self.read_scalar(&op)?.to_bool()?; - if !cond { - throw_ub_format!("`assume` called with `false`"); - } - } - Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping { - ref count, - ref src, - ref dst, - })) => { - let src = self.eval_operand(src, None)?; - let dst = self.eval_operand(dst, None)?; - let count = self.eval_operand(count, None)?; - self.copy_intrinsic(&src, &dst, &count, /* nonoverlapping */ true)?; - } + Intrinsic(box ref intrinsic) => self.emulate_nondiverging_intrinsic(intrinsic)?, // Statements we do not track. AscribeUserType(..) => {} From e1b3483ee807716e579324f0d107b5365e81d30f Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 30 Jun 2022 08:16:05 +0000 Subject: [PATCH 4239/5092] Lower the assume intrinsic to a MIR statement --- clippy_utils/src/qualify_min_const_fn.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 74c222bbcbeb..1c12da7f7416 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -211,6 +211,9 @@ fn check_statement<'tcx>( StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => { check_place(tcx, **place, span, body) }, + StatementKind::Assume(box op) => { + check_operand(tcx, op, span, body) + }, StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { dst, src, count }) => { check_operand(tcx, dst, span, body)?; From 7348284073e31c1ff357ff1e7810bf7a07fcf7e9 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 31 Aug 2022 15:24:22 +0000 Subject: [PATCH 4240/5092] Update docs --- compiler/rustc_middle/src/mir/syntax.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 62306159e880..bf63b8efaf7a 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -327,8 +327,8 @@ pub enum StatementKind<'tcx> { /// executed. Coverage(Box), - /// Denotes a call to an intrinsic that does not require an unwind path. This avoids - /// adding a new block and a terminator for simple intrinsics. + /// Denotes a call to an intrinsic that does not require an unwind path and always returns. + /// This avoids adding a new block and a terminator for simple intrinsics. Intrinsic(Box>), /// No-op. Useful for deleting instructions without affecting statement indices. From 9cbbd4a80e2bb633c6cfc53a3e9cb08b1910ce5f Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 12 Jul 2022 10:05:00 +0000 Subject: [PATCH 4241/5092] Generalize the Assume intrinsic statement to a general Intrinsic statement --- clippy_utils/src/qualify_min_const_fn.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/clippy_utils/src/qualify_min_const_fn.rs b/clippy_utils/src/qualify_min_const_fn.rs index 1c12da7f7416..b22a9c817460 100644 --- a/clippy_utils/src/qualify_min_const_fn.rs +++ b/clippy_utils/src/qualify_min_const_fn.rs @@ -7,7 +7,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::mir::{ Body, CastKind, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, - TerminatorKind, + TerminatorKind, NonDivergingIntrinsic }; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt}; @@ -211,15 +211,19 @@ fn check_statement<'tcx>( StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => { check_place(tcx, **place, span, body) }, - StatementKind::Assume(box op) => { + + StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => { check_operand(tcx, op, span, body) }, - StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { dst, src, count }) => { + StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping( + rustc_middle::mir::CopyNonOverlapping { dst, src, count }, + )) => { check_operand(tcx, dst, span, body)?; check_operand(tcx, src, span, body)?; check_operand(tcx, count, span, body) }, + // These are all NOPs StatementKind::StorageLive(_) | StatementKind::StorageDead(_) From cd928b0ecfc8a3d2cb9579ed93b48ab76cd78e67 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 6 Sep 2022 14:59:46 +0000 Subject: [PATCH 4242/5092] Test bump --- ...wer_intrinsics.assume.LowerIntrinsics.diff | 2 +- ...f_copy_nonoverlapping.LowerIntrinsics.diff | 2 +- ...arate_const_switch.identity.ConstProp.diff | 146 ------------------ ...const_switch.identity.PreCodegen.after.mir | 124 --------------- ...te_const_switch.too_complex.ConstProp.diff | 103 ------------ ...st_switch.too_complex.PreCodegen.after.mir | 73 --------- 6 files changed, 2 insertions(+), 448 deletions(-) delete mode 100644 src/test/mir-opt/separate_const_switch.identity.ConstProp.diff delete mode 100644 src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir delete mode 100644 src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff delete mode 100644 src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir diff --git a/src/test/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff index 1a20fe136c21..d9898d8e0f01 100644 --- a/src/test/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.assume.LowerIntrinsics.diff @@ -11,7 +11,7 @@ StorageLive(_1); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38 - _1 = std::intrinsics::assume(const true) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:97:9: 97:32 +- // + span: $DIR/lower_intrinsics.rs:72:9: 72:32 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(bool) {std::intrinsics::assume}, val: Value() } + assume(const true); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38 + goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38 diff --git a/src/test/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff index 74e22ebb7ffc..4fb6752b6196 100644 --- a/src/test/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.f_copy_nonoverlapping.LowerIntrinsics.diff @@ -49,7 +49,7 @@ StorageDead(_9); // scope 3 at $DIR/lower_intrinsics.rs:+4:90: +4:91 - _3 = copy_nonoverlapping::(move _4, move _8, const 0_usize) -> bb1; // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95 - // mir::Constant -- // + span: $DIR/lower_intrinsics.rs:90:9: 90:28 +- // + span: $DIR/lower_intrinsics.rs:65:9: 65:28 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32, *mut i32, usize) {copy_nonoverlapping::}, val: Value() } + copy_nonoverlapping(dst = move _8, src = move _4, count = const 0_usize); // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95 + goto -> bb1; // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95 diff --git a/src/test/mir-opt/separate_const_switch.identity.ConstProp.diff b/src/test/mir-opt/separate_const_switch.identity.ConstProp.diff deleted file mode 100644 index 28536dc28a72..000000000000 --- a/src/test/mir-opt/separate_const_switch.identity.ConstProp.diff +++ /dev/null @@ -1,146 +0,0 @@ -- // MIR for `identity` before ConstProp -+ // MIR for `identity` after ConstProp - - fn identity(_1: Result) -> Result { - debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:+0:13: +0:14 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:37: +0:53 - let mut _2: i32; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - let mut _3: std::ops::ControlFlow, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - let mut _4: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9 - let mut _5: isize; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - let _6: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - let mut _7: !; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - let mut _8: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - let _9: i32; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - scope 1 { - debug residual => _6; // in scope 1 at $DIR/separate_const_switch.rs:+1:9: +1:10 - scope 2 { - scope 8 (inlined #[track_caller] as FromResidual>>::from_residual) { // at $DIR/separate_const_switch.rs:29:8: 29:10 - debug residual => _8; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - let _16: i32; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _17: i32; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _18: i32; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - scope 9 { - debug e => _16; // in scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - scope 10 (inlined >::from) { // at $SRC_DIR/core/src/result.rs:LL:COL - debug t => _18; // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL - } - } - } - } - } - scope 3 { - debug val => _9; // in scope 3 at $DIR/separate_const_switch.rs:+1:8: +1:10 - scope 4 { - } - } - scope 5 (inlined as Try>::branch) { // at $DIR/separate_const_switch.rs:29:8: 29:10 - debug self => _4; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _10: isize; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - let _11: i32; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _12: i32; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - let _13: i32; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _14: std::result::Result; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _15: i32; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - scope 6 { - debug v => _11; // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - } - scope 7 { - debug e => _13; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - } - } - - bb0: { - StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - StorageLive(_3); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9 - _4 = _1; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9 - _10 = discriminant(_4); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - switchInt(move _10) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - } - - bb1: { - StorageLive(_9); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - _9 = ((_3 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - _2 = _9; // scope 4 at $DIR/separate_const_switch.rs:+1:8: +1:10 - StorageDead(_9); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - Deinit(_0); // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11 - ((_0 as Ok).0: i32) = move _2; // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11 - discriminant(_0) = 0; // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11 - StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11 - StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2 - return; // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2 - } - - bb2: { - unreachable; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - } - - bb3: { - StorageLive(_6); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - _6 = ((_3 as Break).0: std::result::Result); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageLive(_8); // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10 - _8 = _6; // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageLive(_16); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - _16 = move ((_8 as Err).0: i32); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - StorageLive(_17); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - StorageLive(_18); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - _18 = move _16; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - _17 = move _18; // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL - StorageDead(_18); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - Deinit(_0); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - ((_0 as Err).0: i32) = move _17; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - discriminant(_0) = 1; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_17); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_16); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_8); // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11 - StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2 - return; // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2 - } - - bb4: { - StorageLive(_13); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - _13 = move ((_4 as Err).0: i32); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - StorageLive(_14); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - StorageLive(_15); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - _15 = move _13; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - Deinit(_14); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - ((_14 as Err).0: i32) = move _15; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - discriminant(_14) = 1; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_15); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - Deinit(_3); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - ((_3 as Break).0: std::result::Result) = move _14; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - discriminant(_3) = 1; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_14); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_13); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 -- _5 = discriminant(_3); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 -- switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 -+ _5 = const 1_isize; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 -+ switchInt(const 1_isize) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - } - - bb5: { - unreachable; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - } - - bb6: { - StorageLive(_11); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - _11 = move ((_4 as Ok).0: i32); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - StorageLive(_12); // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - _12 = move _11; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - Deinit(_3); // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - ((_3 as Continue).0: i32) = move _12; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - discriminant(_3) = 0; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_12); // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_11); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 -- _5 = discriminant(_3); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 -- switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 -+ _5 = const 0_isize; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 -+ switchInt(const 0_isize) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - } - } - diff --git a/src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir b/src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir deleted file mode 100644 index df20f0ed36b6..000000000000 --- a/src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir +++ /dev/null @@ -1,124 +0,0 @@ -// MIR for `identity` after PreCodegen - -fn identity(_1: Result) -> Result { - debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:+0:13: +0:14 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:37: +0:53 - let mut _2: i32; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - let mut _3: std::ops::ControlFlow, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - let mut _4: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9 - let _5: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - let mut _6: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - let _7: i32; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - scope 1 { - debug residual => _5; // in scope 1 at $DIR/separate_const_switch.rs:+1:9: +1:10 - scope 2 { - scope 8 (inlined #[track_caller] as FromResidual>>::from_residual) { // at $DIR/separate_const_switch.rs:29:8: 29:10 - debug residual => _6; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - let _14: i32; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _15: i32; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _16: i32; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - scope 9 { - debug e => _14; // in scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - scope 10 (inlined >::from) { // at $SRC_DIR/core/src/result.rs:LL:COL - debug t => _16; // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL - } - } - } - } - } - scope 3 { - debug val => _7; // in scope 3 at $DIR/separate_const_switch.rs:+1:8: +1:10 - scope 4 { - } - } - scope 5 (inlined as Try>::branch) { // at $DIR/separate_const_switch.rs:29:8: 29:10 - debug self => _4; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _8: isize; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - let _9: i32; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _10: i32; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - let _11: i32; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _12: std::result::Result; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _13: i32; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - scope 6 { - debug v => _9; // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - } - scope 7 { - debug e => _11; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - } - } - - bb0: { - StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - StorageLive(_3); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9 - _4 = _1; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9 - _8 = discriminant(_4); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - switchInt(move _8) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - } - - bb1: { - StorageLive(_11); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - _11 = move ((_4 as Err).0: i32); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - StorageLive(_12); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - StorageLive(_13); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - _13 = move _11; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - Deinit(_12); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - ((_12 as Err).0: i32) = move _13; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - discriminant(_12) = 1; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_13); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - Deinit(_3); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - ((_3 as Break).0: std::result::Result) = move _12; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - discriminant(_3) = 1; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_12); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_11); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageLive(_5); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - _5 = ((_3 as Break).0: std::result::Result); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageLive(_6); // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10 - _6 = _5; // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageLive(_14); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - _14 = move ((_6 as Err).0: i32); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - StorageLive(_15); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - StorageLive(_16); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - _16 = move _14; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - _15 = move _16; // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL - StorageDead(_16); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - Deinit(_0); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - ((_0 as Err).0: i32) = move _15; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - discriminant(_0) = 1; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_15); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_14); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_6); // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageDead(_5); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11 - StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2 - return; // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2 - } - - bb2: { - unreachable; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - } - - bb3: { - StorageLive(_9); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - _9 = move ((_4 as Ok).0: i32); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - StorageLive(_10); // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - _10 = move _9; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - Deinit(_3); // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - ((_3 as Continue).0: i32) = move _10; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - discriminant(_3) = 0; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_10); // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_9); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - StorageLive(_7); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - _7 = ((_3 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 - _2 = _7; // scope 4 at $DIR/separate_const_switch.rs:+1:8: +1:10 - StorageDead(_7); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 - Deinit(_0); // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11 - ((_0 as Ok).0: i32) = move _2; // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11 - discriminant(_0) = 0; // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11 - StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11 - StorageDead(_3); // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2 - return; // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2 - } -} diff --git a/src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff b/src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff deleted file mode 100644 index 28269165e1c2..000000000000 --- a/src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff +++ /dev/null @@ -1,103 +0,0 @@ -- // MIR for `too_complex` before ConstProp -+ // MIR for `too_complex` after ConstProp - - fn too_complex(_1: Result) -> Option { - debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:+0:16: +0:17 - let mut _0: std::option::Option; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:42: +0:53 - let mut _2: std::ops::ControlFlow; // in scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 - let mut _3: isize; // in scope 0 at $DIR/separate_const_switch.rs:+7:13: +7:18 - let _4: i32; // in scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17 - let mut _5: i32; // in scope 0 at $DIR/separate_const_switch.rs:+7:44: +7:45 - let _6: usize; // in scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18 - let mut _7: usize; // in scope 0 at $DIR/separate_const_switch.rs:+8:42: +8:43 - let mut _8: isize; // in scope 0 at $DIR/separate_const_switch.rs:+11:9: +11:33 - let _9: i32; // in scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32 - let mut _10: i32; // in scope 0 at $DIR/separate_const_switch.rs:+11:42: +11:43 - let _11: usize; // in scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29 - scope 1 { - debug v => _4; // in scope 1 at $DIR/separate_const_switch.rs:+7:16: +7:17 - } - scope 2 { - debug r => _6; // in scope 2 at $DIR/separate_const_switch.rs:+8:17: +8:18 - } - scope 3 { - debug v => _9; // in scope 3 at $DIR/separate_const_switch.rs:+11:31: +11:32 - } - scope 4 { - debug r => _11; // in scope 4 at $DIR/separate_const_switch.rs:+12:28: +12:29 - } - - bb0: { - StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 - _3 = discriminant(_1); // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16 - switchInt(move _3) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+6:9: +6:16 - } - - bb1: { - StorageLive(_6); // scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18 - _6 = ((_1 as Err).0: usize); // scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18 - StorageLive(_7); // scope 2 at $DIR/separate_const_switch.rs:+8:42: +8:43 - _7 = _6; // scope 2 at $DIR/separate_const_switch.rs:+8:42: +8:43 - Deinit(_2); // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44 - ((_2 as Break).0: usize) = move _7; // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44 - discriminant(_2) = 1; // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44 - StorageDead(_7); // scope 2 at $DIR/separate_const_switch.rs:+8:43: +8:44 - StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:+8:43: +8:44 -- _8 = discriminant(_2); // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 -- switchInt(move _8) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6 -+ _8 = const 1_isize; // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 -+ switchInt(const 1_isize) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6 - } - - bb2: { - unreachable; // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16 - } - - bb3: { - StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17 - _4 = ((_1 as Ok).0: i32); // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17 - StorageLive(_5); // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45 - _5 = _4; // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45 - Deinit(_2); // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46 - ((_2 as Continue).0: i32) = move _5; // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46 - discriminant(_2) = 0; // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46 - StorageDead(_5); // scope 1 at $DIR/separate_const_switch.rs:+7:45: +7:46 - StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:+7:45: +7:46 -- _8 = discriminant(_2); // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 -- switchInt(move _8) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6 -+ _8 = const 0_isize; // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 -+ switchInt(const 0_isize) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6 - } - - bb4: { - StorageLive(_11); // scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29 - _11 = ((_2 as Break).0: usize); // scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29 - Deinit(_0); // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38 - discriminant(_0) = 0; // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38 - StorageDead(_11); // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38 - goto -> bb7; // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38 - } - - bb5: { - unreachable; // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 - } - - bb6: { - StorageLive(_9); // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32 - _9 = ((_2 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32 - StorageLive(_10); // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43 - _10 = _9; // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43 - Deinit(_0); // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44 - ((_0 as Some).0: i32) = move _10; // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44 - discriminant(_0) = 1; // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44 - StorageDead(_10); // scope 3 at $DIR/separate_const_switch.rs:+11:43: +11:44 - StorageDead(_9); // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44 - goto -> bb7; // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44 - } - - bb7: { - StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+14:1: +14:2 - return; // scope 0 at $DIR/separate_const_switch.rs:+14:2: +14:2 - } - } - diff --git a/src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir b/src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir deleted file mode 100644 index 0ee070619e79..000000000000 --- a/src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir +++ /dev/null @@ -1,73 +0,0 @@ -// MIR for `too_complex` after PreCodegen - -fn too_complex(_1: Result) -> Option { - debug x => _1; // in scope 0 at $DIR/separate_const_switch.rs:+0:16: +0:17 - let mut _0: std::option::Option; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:42: +0:53 - let mut _2: std::ops::ControlFlow; // in scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 - let mut _3: isize; // in scope 0 at $DIR/separate_const_switch.rs:+7:13: +7:18 - let _4: i32; // in scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17 - let mut _5: i32; // in scope 0 at $DIR/separate_const_switch.rs:+7:44: +7:45 - let _6: usize; // in scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18 - let _7: i32; // in scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32 - let mut _8: i32; // in scope 0 at $DIR/separate_const_switch.rs:+11:42: +11:43 - let _9: usize; // in scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29 - scope 1 { - debug v => _4; // in scope 1 at $DIR/separate_const_switch.rs:+7:16: +7:17 - } - scope 2 { - debug r => _6; // in scope 2 at $DIR/separate_const_switch.rs:+8:17: +8:18 - } - scope 3 { - debug v => _7; // in scope 3 at $DIR/separate_const_switch.rs:+11:31: +11:32 - } - scope 4 { - debug r => _9; // in scope 4 at $DIR/separate_const_switch.rs:+12:28: +12:29 - } - - bb0: { - StorageLive(_2); // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6 - _3 = discriminant(_1); // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16 - switchInt(move _3) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+6:9: +6:16 - } - - bb1: { - StorageLive(_6); // scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18 - StorageDead(_6); // scope 0 at $DIR/separate_const_switch.rs:+8:43: +8:44 - StorageLive(_9); // scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29 - Deinit(_0); // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38 - discriminant(_0) = 0; // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38 - StorageDead(_9); // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38 - goto -> bb4; // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38 - } - - bb2: { - unreachable; // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16 - } - - bb3: { - StorageLive(_4); // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17 - _4 = ((_1 as Ok).0: i32); // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17 - StorageLive(_5); // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45 - _5 = _4; // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45 - Deinit(_2); // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46 - ((_2 as Continue).0: i32) = move _5; // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46 - discriminant(_2) = 0; // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46 - StorageDead(_5); // scope 1 at $DIR/separate_const_switch.rs:+7:45: +7:46 - StorageDead(_4); // scope 0 at $DIR/separate_const_switch.rs:+7:45: +7:46 - StorageLive(_7); // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32 - _7 = ((_2 as Continue).0: i32); // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32 - StorageLive(_8); // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43 - _8 = _7; // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43 - Deinit(_0); // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44 - ((_0 as Some).0: i32) = move _8; // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44 - discriminant(_0) = 1; // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44 - StorageDead(_8); // scope 3 at $DIR/separate_const_switch.rs:+11:43: +11:44 - StorageDead(_7); // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44 - goto -> bb4; // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44 - } - - bb4: { - StorageDead(_2); // scope 0 at $DIR/separate_const_switch.rs:+14:1: +14:2 - return; // scope 0 at $DIR/separate_const_switch.rs:+14:2: +14:2 - } -} From ad275f50967854050857d181da7694a95bc4173f Mon Sep 17 00:00:00 2001 From: asquared31415 <34665709+asquared31415@users.noreply.github.com> Date: Tue, 6 Sep 2022 11:02:42 -0400 Subject: [PATCH 4243/5092] add list of recognized repr attributes to the unrecognized repr error --- compiler/rustc_attr/src/builtin.rs | 22 ++++++------ compiler/rustc_passes/src/check_attr.rs | 1 + src/test/ui/issues/issue-43988.stderr | 4 +++ src/test/ui/repr/invalid_repr_list_help.rs | 17 +++++++++ .../ui/repr/invalid_repr_list_help.stderr | 35 +++++++++++++++++++ 5 files changed, 67 insertions(+), 12 deletions(-) create mode 100644 src/test/ui/repr/invalid_repr_list_help.rs create mode 100644 src/test/ui/repr/invalid_repr_list_help.stderr diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index a8ed510866d8..71be973546e8 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -1040,18 +1040,16 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec { &name, ), }); - } else { - if matches!( - meta_item.name_or_empty(), - sym::C | sym::simd | sym::transparent - ) || int_type_of_word(meta_item.name_or_empty()).is_some() - { - recognised = true; - sess.emit_err(session_diagnostics::InvalidReprHintNoValue { - span: meta_item.span, - name: meta_item.name_or_empty().to_ident_string(), - }); - } + } else if matches!( + meta_item.name_or_empty(), + sym::C | sym::simd | sym::transparent + ) || int_type_of_word(meta_item.name_or_empty()).is_some() + { + recognised = true; + sess.emit_err(session_diagnostics::InvalidReprHintNoValue { + span: meta_item.span, + name: meta_item.name_or_empty().to_ident_string(), + }); } } else if let MetaItemKind::List(_) = meta_item.kind { if meta_item.has_name(sym::align) { diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index f376da29bd91..827e6f0ddcac 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1658,6 +1658,7 @@ impl CheckAttrVisitor<'_> { E0552, "unrecognized representation hint" ) + .help("valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`") .emit(); continue; diff --git a/src/test/ui/issues/issue-43988.stderr b/src/test/ui/issues/issue-43988.stderr index 03aa37f52075..02c5dd5bfb77 100644 --- a/src/test/ui/issues/issue-43988.stderr +++ b/src/test/ui/issues/issue-43988.stderr @@ -31,12 +31,16 @@ error[E0552]: unrecognized representation hint | LL | #[repr(nothing)] | ^^^^^^^ + | + = help: valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` error[E0552]: unrecognized representation hint --> $DIR/issue-43988.rs:18:12 | LL | #[repr(something_not_real)] | ^^^^^^^^^^^^^^^^^^ + | + = help: valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` error[E0518]: attribute should be applied to function or closure --> $DIR/issue-43988.rs:30:5 diff --git a/src/test/ui/repr/invalid_repr_list_help.rs b/src/test/ui/repr/invalid_repr_list_help.rs new file mode 100644 index 000000000000..c320984536ca --- /dev/null +++ b/src/test/ui/repr/invalid_repr_list_help.rs @@ -0,0 +1,17 @@ +#![crate_type = "lib"] + +#[repr(uwu)] //~ERROR: unrecognized representation hint +pub struct OwO; + +#[repr(uwu = "a")] //~ERROR: unrecognized representation hint +pub struct OwO2(i32); + +#[repr(uwu(4))] //~ERROR: unrecognized representation hint +pub struct OwO3 { + x: i32, +} + +#[repr(uwu, u8)] //~ERROR: unrecognized representation hint +pub enum OwO4 { + UwU = 1, +} diff --git a/src/test/ui/repr/invalid_repr_list_help.stderr b/src/test/ui/repr/invalid_repr_list_help.stderr new file mode 100644 index 000000000000..2acd56d9a323 --- /dev/null +++ b/src/test/ui/repr/invalid_repr_list_help.stderr @@ -0,0 +1,35 @@ +error[E0552]: unrecognized representation hint + --> $DIR/invalid_repr_list_help.rs:3:8 + | +LL | #[repr(uwu)] + | ^^^ + | + = help: valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` + +error[E0552]: unrecognized representation hint + --> $DIR/invalid_repr_list_help.rs:6:8 + | +LL | #[repr(uwu = "a")] + | ^^^^^^^^^ + | + = help: valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` + +error[E0552]: unrecognized representation hint + --> $DIR/invalid_repr_list_help.rs:9:8 + | +LL | #[repr(uwu(4))] + | ^^^^^^ + | + = help: valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` + +error[E0552]: unrecognized representation hint + --> $DIR/invalid_repr_list_help.rs:14:8 + | +LL | #[repr(uwu, u8)] + | ^^^ + | + = help: valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0552`. From a0130e62ecc6d0b450c34b25843f89e1e3ff63f0 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 6 Sep 2022 15:32:35 +0000 Subject: [PATCH 4244/5092] Check all operands, they may contain indirections in their place --- compiler/rustc_borrowck/src/lib.rs | 3 +-- compiler/rustc_borrowck/src/type_check/mod.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 3b2bcd7e6d3a..ec652f852179 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -592,8 +592,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx ); } StatementKind::Intrinsic(box ref kind) => match kind { - // Takes a `bool` argument, and has no return value, thus being irrelevant for borrowck - NonDivergingIntrinsic::Assume(..) => {}, + NonDivergingIntrinsic::Assume(op) => self.consume_operand(location, (op, span), flow_state), NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!( span, "Unexpected CopyNonOverlapping, should only appear after lower_intrinsics", diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 2ba9b2be9018..fc0e95f30c98 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1303,7 +1303,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } StatementKind::Intrinsic(box ref kind) => match kind { - NonDivergingIntrinsic::Assume(..) => {} + NonDivergingIntrinsic::Assume(op) => self.check_operand(op, location), NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!( stmt.source_info.span, "Unexpected NonDivergingIntrinsic::CopyNonOverlapping, should only appear after lowering_intrinsics", From af3343ae299c81a019d9d62d15c10cb99d7ceb89 Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Sun, 28 Aug 2022 19:45:19 +0300 Subject: [PATCH 4245/5092] Migrate E0623 --- .../locales/en-US/infer.ftl | 31 +++- compiler/rustc_infer/src/errors.rs | 173 +++++++++++++++++- .../nice_region_error/different_lifetimes.rs | 147 ++++----------- compiler/rustc_infer/src/lib.rs | 4 + 4 files changed, 234 insertions(+), 121 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index 60086cd6e477..478a4bdf8a96 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -104,9 +104,36 @@ infer_relate_object_bound = ...so that it can be closed over into an object infer_data_borrowed = ...so that the type `{$name}` is not borrowed for too long infer_reference_outlives_referent = ...so that the reference type `{$name}` does not outlive the data it points at infer_relate_param_bound = ...so that the type `{$name}` will meet its required lifetime bounds{$continues -> -[true] ... -*[false] {""} + [true] ... + *[false] {""} } infer_relate_param_bound_2 = ...that is required by this bound infer_relate_region_param_bound = ...so that the declared lifetime parameter bounds are satisfied infer_compare_impl_item_obligation = ...so that the definition in impl matches the definition from the trait + +infer_nothing = {""} + +infer_lifetime_mismatch = lifetime mismatch + +infer_declared_different = this parameter and the return type are declared with different lifetimes... +infer_data_returned = ...but data{$label_var1_exists -> + [true] {" "}from `{$label_var1}` + *[false] {""} +} is returned here + +infer_data_lifetime_flow = ...but data with one lifetime flows into the other here +infer_declared_multiple = this type is declared with multiple lifetimes... +infer_types_declared_different = these two types are declared with different lifetimes... +infer_data_flows = ...but data{$label_var1_exists -> + [true] -> {" "}from `{$label_var1}` + *[false] -> {""} +} flows{$label_var2_exists -> + [true] -> {" "}into `{$label_var2}` + *[false] -> {""} +} here + +infer_lifetime_param_suggestion = consider introducing a named lifetime parameter{$is_impl -> + [true] {" "}and update trait if needed + *[false] {""} +} +infer_lifetime_param_suggestion_elided = each elided lifetime in input position becomes a distinct lifetime diff --git a/compiler/rustc_infer/src/errors.rs b/compiler/rustc_infer/src/errors.rs index 938f8aa77a5b..932ba1f35afc 100644 --- a/compiler/rustc_infer/src/errors.rs +++ b/compiler/rustc_infer/src/errors.rs @@ -1,7 +1,13 @@ -use rustc_errors::{fluent, AddSubdiagnostic, DiagnosticMessage, DiagnosticStyledString}; -use rustc_hir::FnRetTy; +use hir::GenericParamKind; +use rustc_errors::{ + fluent, AddSubdiagnostic, Applicability, DiagnosticMessage, DiagnosticStyledString, +}; +use rustc_hir as hir; +use rustc_hir::{FnRetTy, Ty}; use rustc_macros::SessionDiagnostic; -use rustc_span::{BytePos, Span}; +use rustc_middle::ty::{Region, TyCtxt}; +use rustc_span::symbol::kw; +use rustc_span::{symbol::Ident, BytePos, Span}; use crate::infer::error_reporting::{ need_type_info::{GeneratorKindAsDiagArg, UnderspecifiedArgKind}, @@ -252,3 +258,164 @@ impl AddSubdiagnostic for RegionOriginNote<'_> { }; } } + +pub enum LifetimeMismatchLabels { + InRet { + param_span: Span, + ret_span: Span, + span: Span, + label_var1: Option, + }, + Normal { + hir_equal: bool, + ty_sup: Span, + ty_sub: Span, + span: Span, + label_var1: Option, + label_var2: Option, + }, +} + +impl AddSubdiagnostic for LifetimeMismatchLabels { + fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { + match self { + LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => { + diag.span_label(param_span, fluent::infer::declared_different); + diag.span_label(ret_span, fluent::infer::nothing); + diag.span_label(span, fluent::infer::data_returned); + diag.set_arg("label_var1_exists", label_var1.is_some()); + diag.set_arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default()); + } + LifetimeMismatchLabels::Normal { + hir_equal, + ty_sup, + ty_sub, + span, + label_var1, + label_var2, + } => { + if hir_equal { + diag.span_label(ty_sup, fluent::infer::declared_multiple); + diag.span_label(ty_sub, fluent::infer::nothing); + diag.span_label(span, fluent::infer::data_lifetime_flow); + } else { + diag.span_label(ty_sup, fluent::infer::types_declared_different); + diag.span_label(ty_sub, fluent::infer::nothing); + diag.span_label(span, fluent::infer::data_flows); + diag.set_arg("label_var1_exists", label_var1.is_some()); + diag.set_arg( + "label_var1", + label_var1.map(|x| x.to_string()).unwrap_or_default(), + ); + diag.set_arg("label_var2_exists", label_var2.is_some()); + diag.set_arg( + "label_var2", + label_var2.map(|x| x.to_string()).unwrap_or_default(), + ); + } + } + } + } +} + +pub struct AddLifetimeParamsSuggestion<'a> { + pub tcx: TyCtxt<'a>, + pub sub: Region<'a>, + pub ty_sup: &'a Ty<'a>, + pub ty_sub: &'a Ty<'a>, + pub add_note: bool, +} + +impl AddSubdiagnostic for AddLifetimeParamsSuggestion<'_> { + fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { + let mut mk_suggestion = || { + let ( + hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. }, + hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. }, + ) = (self.ty_sub, self.ty_sup) else { + return false; + }; + + if !lifetime_sub.name.is_anonymous() || !lifetime_sup.name.is_anonymous() { + return false; + }; + + let Some(anon_reg) = self.tcx.is_suitable_region(self.sub) else { + return false; + }; + + let hir_id = self.tcx.hir().local_def_id_to_hir_id(anon_reg.def_id); + + let node = self.tcx.hir().get(hir_id); + let is_impl = matches!(&node, hir::Node::ImplItem(_)); + let generics = match node { + hir::Node::Item(&hir::Item { + kind: hir::ItemKind::Fn(_, ref generics, ..), + .. + }) + | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. }) + | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics, + _ => return false, + }; + + let suggestion_param_name = generics + .params + .iter() + .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. })) + .map(|p| p.name.ident().name) + .find(|i| *i != kw::UnderscoreLifetime); + let introduce_new = suggestion_param_name.is_none(); + let suggestion_param_name = + suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned()); + + debug!(?lifetime_sup.span); + debug!(?lifetime_sub.span); + let make_suggestion = |span: rustc_span::Span| { + if span.is_empty() { + (span, format!("{}, ", suggestion_param_name)) + } else if let Ok("&") = self.tcx.sess.source_map().span_to_snippet(span).as_deref() + { + (span.shrink_to_hi(), format!("{} ", suggestion_param_name)) + } else { + (span, suggestion_param_name.clone()) + } + }; + let mut suggestions = + vec![make_suggestion(lifetime_sub.span), make_suggestion(lifetime_sup.span)]; + + if introduce_new { + let new_param_suggestion = if let Some(first) = + generics.params.iter().find(|p| !p.name.ident().span.is_empty()) + { + (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name)) + } else { + (generics.span, format!("<{}>", suggestion_param_name)) + }; + + suggestions.push(new_param_suggestion); + } + + diag.multipart_suggestion( + fluent::infer::lifetime_param_suggestion, + suggestions, + Applicability::MaybeIncorrect, + ); + diag.set_arg("is_impl", is_impl); + true + }; + if mk_suggestion() && self.add_note { + diag.note(fluent::infer::lifetime_param_suggestion_elided); + } + } +} + +#[derive(SessionDiagnostic)] +#[diag(infer::lifetime_mismatch, code = "E0623")] +pub struct LifetimeMismatch<'a> { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub labels: LifetimeMismatchLabels, + #[subdiagnostic] + pub suggestion: AddLifetimeParamsSuggestion<'a>, +} diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs index 9a2ab3e32248..ebd59a3fef79 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs @@ -1,6 +1,9 @@ //! Error Reporting for Anonymous Region Lifetime Errors //! where both the regions are anonymous. +use crate::errors::AddLifetimeParamsSuggestion; +use crate::errors::LifetimeMismatch; +use crate::errors::LifetimeMismatchLabels; use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type; use crate::infer::error_reporting::nice_region_error::util::AnonymousParamInfo; use crate::infer::error_reporting::nice_region_error::NiceRegionError; @@ -8,11 +11,10 @@ use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::SubregionOrigin; use crate::infer::TyCtxt; -use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed}; -use rustc_hir as hir; -use rustc_hir::{GenericParamKind, Ty}; +use rustc_errors::AddSubdiagnostic; +use rustc_errors::{Diagnostic, ErrorGuaranteed}; +use rustc_hir::Ty; use rustc_middle::ty::Region; -use rustc_span::symbol::kw; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// Print the error message for lifetime errors when both the concerned regions are anonymous. @@ -98,137 +100,50 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let sub_is_ret_type = self.is_return_type_anon(scope_def_id_sub, bregion_sub, ty_fndecl_sub); - let span_label_var1 = match anon_param_sup.pat.simple_ident() { - Some(simple_ident) => format!(" from `{}`", simple_ident), - None => String::new(), - }; - - let span_label_var2 = match anon_param_sub.pat.simple_ident() { - Some(simple_ident) => format!(" into `{}`", simple_ident), - None => String::new(), - }; - debug!( "try_report_anon_anon_conflict: sub_is_ret_type={:?} sup_is_ret_type={:?}", sub_is_ret_type, sup_is_ret_type ); - let mut err = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch"); - - match (sup_is_ret_type, sub_is_ret_type) { + let labels = match (sup_is_ret_type, sub_is_ret_type) { (ret_capture @ Some(ret_span), _) | (_, ret_capture @ Some(ret_span)) => { let param_span = if sup_is_ret_type == ret_capture { ty_sub.span } else { ty_sup.span }; - - err.span_label( + LifetimeMismatchLabels::InRet { param_span, - "this parameter and the return type are declared with different lifetimes...", - ); - err.span_label(ret_span, ""); - err.span_label(span, format!("...but data{} is returned here", span_label_var1)); - } - - (None, None) => { - if ty_sup.hir_id == ty_sub.hir_id { - err.span_label(ty_sup.span, "this type is declared with multiple lifetimes..."); - err.span_label(ty_sub.span, ""); - err.span_label(span, "...but data with one lifetime flows into the other here"); - } else { - err.span_label( - ty_sup.span, - "these two types are declared with different lifetimes...", - ); - err.span_label(ty_sub.span, ""); - err.span_label( - span, - format!("...but data{} flows{} here", span_label_var1, span_label_var2), - ); + ret_span, + span, + label_var1: anon_param_sup.pat.simple_ident(), } } - } - if suggest_adding_lifetime_params(self.tcx(), sub, ty_sup, ty_sub, &mut err) { - err.note("each elided lifetime in input position becomes a distinct lifetime"); - } + (None, None) => LifetimeMismatchLabels::Normal { + hir_equal: ty_sup.hir_id == ty_sub.hir_id, + ty_sup: ty_sup.span, + ty_sub: ty_sub.span, + span, + label_var1: anon_param_sup.pat.simple_ident(), + label_var2: anon_param_sub.pat.simple_ident(), + }, + }; - let reported = err.emit(); + let suggestion = + AddLifetimeParamsSuggestion { tcx: self.tcx(), sub, ty_sup, ty_sub, add_note: true }; + let err = LifetimeMismatch { span, labels, suggestion }; + let reported = self.tcx().sess.emit_err(err); Some(reported) } } +/// Currently only used in rustc_borrowck, probably should be +/// removed in favour of public_errors::AddLifetimeParamsSuggestion pub fn suggest_adding_lifetime_params<'tcx>( tcx: TyCtxt<'tcx>, sub: Region<'tcx>, - ty_sup: &Ty<'_>, - ty_sub: &Ty<'_>, + ty_sup: &'tcx Ty<'_>, + ty_sub: &'tcx Ty<'_>, err: &mut Diagnostic, -) -> bool { - let ( - hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. }, - hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. }, - ) = (ty_sub, ty_sup) else { - return false; - }; - - if !lifetime_sub.name.is_anonymous() || !lifetime_sup.name.is_anonymous() { - return false; - }; - - let Some(anon_reg) = tcx.is_suitable_region(sub) else { - return false; - }; - - let hir_id = tcx.hir().local_def_id_to_hir_id(anon_reg.def_id); - - let node = tcx.hir().get(hir_id); - let is_impl = matches!(&node, hir::Node::ImplItem(_)); - let generics = match node { - hir::Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, ref generics, ..), .. }) - | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. }) - | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics, - _ => return false, - }; - - let suggestion_param_name = generics - .params - .iter() - .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. })) - .map(|p| p.name.ident().name) - .find(|i| *i != kw::UnderscoreLifetime); - let introduce_new = suggestion_param_name.is_none(); - let suggestion_param_name = - suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned()); - - debug!(?lifetime_sup.span); - debug!(?lifetime_sub.span); - let make_suggestion = |span: rustc_span::Span| { - if span.is_empty() { - (span, format!("{}, ", suggestion_param_name)) - } else if let Ok("&") = tcx.sess.source_map().span_to_snippet(span).as_deref() { - (span.shrink_to_hi(), format!("{} ", suggestion_param_name)) - } else { - (span, suggestion_param_name.clone()) - } - }; - let mut suggestions = - vec![make_suggestion(lifetime_sub.span), make_suggestion(lifetime_sup.span)]; - - if introduce_new { - let new_param_suggestion = - if let Some(first) = generics.params.iter().find(|p| !p.name.ident().span.is_empty()) { - (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name)) - } else { - (generics.span, format!("<{}>", suggestion_param_name)) - }; - - suggestions.push(new_param_suggestion); - } - - let mut sugg = String::from("consider introducing a named lifetime parameter"); - if is_impl { - sugg.push_str(" and update trait if needed"); - } - err.multipart_suggestion(sugg, suggestions, Applicability::MaybeIncorrect); - - true +) { + let suggestion = AddLifetimeParamsSuggestion { tcx, sub, ty_sup, ty_sub, add_note: false }; + suggestion.add_to_diagnostic(err); } diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 931ebca7d014..5810616fcdbf 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -36,5 +36,9 @@ extern crate tracing; extern crate rustc_middle; mod errors; +pub mod public_errors { + // Probably would be useful in rustc_borrowck + pub use super::errors::AddLifetimeParamsSuggestion; +} pub mod infer; pub mod traits; From e0e9b21c78e4e6a7a5515944ace4cb0c1f2f9253 Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Tue, 30 Aug 2022 18:28:50 +0300 Subject: [PATCH 4246/5092] Mugrate mismatched_static_lifetime.rs --- .../locales/en-US/infer.ftl | 31 +++ .../src/{errors.rs => errors/mod.rs} | 68 +++++++ .../src/errors/note_and_explain.rs | 176 ++++++++++++++++++ .../mismatched_static_lifetime.rs | 48 +++-- 4 files changed, 303 insertions(+), 20 deletions(-) rename compiler/rustc_infer/src/{errors.rs => errors/mod.rs} (88%) create mode 100644 compiler/rustc_infer/src/errors/note_and_explain.rs diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index 478a4bdf8a96..2899b8304bc1 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -137,3 +137,34 @@ infer_lifetime_param_suggestion = consider introducing a named lifetime paramete *[false] {""} } infer_lifetime_param_suggestion_elided = each elided lifetime in input position becomes a distinct lifetime + +infer_region_explanation = {$pref_kind -> + *[should_not_happen] [{$pref_kind}] + [empty] {""} +}{$pref_kind -> + [empty] {""} + *[other] {" "} +}{$desc_kind -> + *[should_not_happen] [{$desc_kind}] + [restatic] the static lifetime + [reempty] the empty lifetime + [reemptyuni] the empty lifetime in universe {$desc_arg} + [revar] lifetime {$desc_arg} + + [as_defined] the lifetime `{$desc_arg}` as defined here + [as_defined_anon] the anonymous lifetime as defined here + [defined_here] the anonymous lifetime defined here + [anon_num_here] the anonymous lifetime #{$desc_num_arg} defined here + [defined_here_reg] the lifetime `{$desc_arg}` as defined here +}{$suff_kind -> + *[should_not_happen] [{$suff_kind}] + [empty]{""} + [continues] ... +} + +infer_mismatched_static_lifetime = incompatible lifetime on type +infer_msl_impl_note = ...does not necessarily outlive the static lifetime introduced by the compatible `impl` +infer_msl_introduces_static = introduces a `'static` lifetime requirement +infer_msl_unmet_req = because this has an unmet lifetime requirement +infer_msl_trait_note = this has an implicit `'static` lifetime requirement +infer_msl_trait_sugg = consider relaxing the implicit `'static` requirement diff --git a/compiler/rustc_infer/src/errors.rs b/compiler/rustc_infer/src/errors/mod.rs similarity index 88% rename from compiler/rustc_infer/src/errors.rs rename to compiler/rustc_infer/src/errors/mod.rs index 932ba1f35afc..ad8eb2945fa9 100644 --- a/compiler/rustc_infer/src/errors.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -14,6 +14,8 @@ use crate::infer::error_reporting::{ ObligationCauseAsDiagArg, }; +pub mod note_and_explain; + #[derive(SessionDiagnostic)] #[diag(infer::opaque_hidden_type)] pub struct OpaqueHiddenTypeDiag { @@ -419,3 +421,69 @@ pub struct LifetimeMismatch<'a> { #[subdiagnostic] pub suggestion: AddLifetimeParamsSuggestion<'a>, } + +pub mod mismatched_static_lifetime { + use rustc_errors::{self, fluent, AddSubdiagnostic, MultiSpan}; + use rustc_span::Span; + + use super::note_and_explain; + + pub struct LabeledMultiSpan { + pub multi_span: MultiSpan, + pub binding_span: Span, + } + + impl AddSubdiagnostic for LabeledMultiSpan { + fn add_to_diagnostic(mut self, diag: &mut rustc_errors::Diagnostic) { + self.multi_span + .push_span_label(self.binding_span, fluent::infer::msl_introduces_static); + diag.span_note(self.multi_span, fluent::infer::msl_unmet_req); + } + } + + pub struct ImplNote { + pub impl_span: Option, + } + + impl AddSubdiagnostic for ImplNote { + fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { + match self.impl_span { + Some(span) => diag.span_note(span, fluent::infer::msl_impl_note), + None => diag.note(fluent::infer::msl_impl_note), + }; + } + } + + #[derive(SessionSubdiagnostic)] + pub enum TraitSubdiag { + #[note(infer::msl_trait_note)] + Note { + #[primary_span] + span: Span, + }, + #[suggestion_verbose( + infer::msl_trait_sugg, + code = " + '_", + applicability = "maybe-incorrect" + )] + Sugg { + #[primary_span] + span: Span, + }, + } + + #[derive(SessionDiagnostic)] + #[diag(infer::mismatched_static_lifetime)] + pub struct MismatchedStaticLifetime<'a> { + #[primary_span] + pub cause_span: Span, + #[subdiagnostic] + pub multispan_subdiag: LabeledMultiSpan, + #[subdiagnostic] + pub expl: Option>, + #[subdiagnostic] + pub impl_note: ImplNote, + #[subdiagnostic] + pub trait_subdiags: Vec, + } +} diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs new file mode 100644 index 000000000000..92bf3ecd131d --- /dev/null +++ b/compiler/rustc_infer/src/errors/note_and_explain.rs @@ -0,0 +1,176 @@ +use crate::infer::error_reporting::nice_region_error::find_anon_type; +use rustc_errors::{self, fluent, AddSubdiagnostic}; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::{symbol::kw, Span}; + +#[derive(Default)] +struct DescriptionCtx<'a> { + span: Option, + kind: &'a str, + arg: String, + num_arg: u32, +} + +impl<'a> DescriptionCtx<'a> { + fn new<'tcx>( + tcx: TyCtxt<'tcx>, + region: ty::Region<'tcx>, + alt_span: Option, + ) -> Option { + let mut me = DescriptionCtx::default(); + me.span = alt_span; + match *region { + ty::ReEarlyBound(_) | ty::ReFree(_) => { + return Self::from_early_bound_and_free_regions(tcx, region); + } + ty::ReStatic => { + me.kind = "restatic"; + } + + ty::ReEmpty(ty::UniverseIndex::ROOT) => me.kind = "reempty", + + // uh oh, hope no user ever sees THIS + ty::ReEmpty(ui) => { + me.kind = "reemptyuni"; + me.arg = format!("{:?}", ui); + } + + ty::RePlaceholder(_) => return None, + + // FIXME(#13998) RePlaceholder should probably print like + // ReFree rather than dumping Debug output on the user. + // + // We shouldn't really be having unification failures with ReVar + // and ReLateBound though. + ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => { + me.kind = "revar"; + me.arg = format!("{:?}", region); + } + }; + Some(me) + } + + fn from_early_bound_and_free_regions<'tcx>( + tcx: TyCtxt<'tcx>, + region: ty::Region<'tcx>, + ) -> Option { + let mut me = DescriptionCtx::default(); + let scope = region.free_region_binding_scope(tcx).expect_local(); + match *region { + ty::ReEarlyBound(ref br) => { + let mut sp = tcx.def_span(scope); + if let Some(param) = + tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name)) + { + sp = param.span; + } + if br.has_name() { + me.kind = "as_defined"; + me.arg = br.name.to_string(); + } else { + me.kind = "as_defined_anon"; + }; + me.span = Some(sp) + } + ty::ReFree(ref fr) => { + if !fr.bound_region.is_named() + && let Some((ty, _)) = find_anon_type(tcx, region, &fr.bound_region) + { + me.kind = "defined_here"; + me.span = Some(ty.span); + } else { + match fr.bound_region { + ty::BoundRegionKind::BrNamed(_, name) => { + let mut sp = tcx.def_span(scope); + if let Some(param) = + tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name)) + { + sp = param.span; + } + if name == kw::UnderscoreLifetime { + me.kind = "as_defined_anon"; + } else { + me.kind = "as_defined"; + me.arg = name.to_string(); + }; + me.span = Some(sp); + } + ty::BrAnon(idx) => { + me.kind = "anon_num_here"; + me.num_arg = idx+1; + me.span = Some(tcx.def_span(scope)); + }, + _ => { + me.kind = "defined_here_reg"; + me.arg = region.to_string(); + me.span = Some(tcx.def_span(scope)); + }, + } + } + } + _ => bug!(), + } + Some(me) + } + + fn add_to(self, diag: &mut rustc_errors::Diagnostic) { + diag.set_arg("desc_kind", self.kind); + diag.set_arg("desc_arg", self.arg); + diag.set_arg("desc_num_arg", self.num_arg); + } +} + +pub enum PrefixKind { + Empty, +} + +pub enum SuffixKind { + Continues, +} + +impl PrefixKind { + fn add_to(self, diag: &mut rustc_errors::Diagnostic) { + match self { + Self::Empty => diag.set_arg("pref_kind", "empty"), + }; + } +} + +impl SuffixKind { + fn add_to(self, diag: &mut rustc_errors::Diagnostic) { + match self { + Self::Continues => diag.set_arg("suff_kind", "continues"), + }; + } +} + +pub struct RegionExplanation<'a> { + desc: DescriptionCtx<'a>, + prefix: PrefixKind, + suffix: SuffixKind, +} + +impl RegionExplanation<'_> { + pub fn new<'tcx>( + tcx: TyCtxt<'tcx>, + region: ty::Region<'tcx>, + alt_span: Option, + prefix: PrefixKind, + suffix: SuffixKind, + ) -> Option { + Some(Self { desc: DescriptionCtx::new(tcx, region, alt_span)?, prefix, suffix }) + } +} + +impl AddSubdiagnostic for RegionExplanation<'_> { + fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { + if let Some(span) = self.desc.span { + diag.span_note(span, fluent::infer::region_explanation); + } else { + diag.note(fluent::infer::region_explanation); + } + self.desc.add_to(diag); + self.prefix.add_to(diag); + self.suffix.add_to(diag); + } +} diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs index c20b96cae2e4..832a0eaba3b8 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs @@ -1,13 +1,14 @@ //! Error Reporting for when the lifetime for a type doesn't match the `impl` selected for a predicate //! to hold. +use crate::errors::mismatched_static_lifetime::{ImplNote, MismatchedStaticLifetime, TraitSubdiag}; +use crate::errors::{mismatched_static_lifetime::LabeledMultiSpan, note_and_explain}; use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::infer::error_reporting::note_and_explain_region; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::{SubregionOrigin, TypeTrace}; use crate::traits::ObligationCauseCode; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan}; +use rustc_errors::{ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::intravisit::Visitor; use rustc_middle::ty::TypeVisitor; @@ -39,12 +40,20 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { = *parent.code() else { return None; }; - let mut err = self.tcx().sess.struct_span_err(cause.span, "incompatible lifetime on type"); + // FIXME: we should point at the lifetime - let mut multi_span: MultiSpan = vec![binding_span].into(); - multi_span.push_span_label(binding_span, "introduces a `'static` lifetime requirement"); - err.span_note(multi_span, "because this has an unmet lifetime requirement"); - note_and_explain_region(self.tcx(), &mut err, "", sup, "...", Some(binding_span)); + let multi_span: MultiSpan = vec![binding_span].into(); + let multispan_subdiag = LabeledMultiSpan { multi_span, binding_span }; + + let expl = note_and_explain::RegionExplanation::new( + self.tcx(), + sup, + Some(binding_span), + note_and_explain::PrefixKind::Empty, + note_and_explain::SuffixKind::Continues, + ); + let mut impl_span = None; + let mut trait_subdiags = Vec::new(); if let Some(impl_node) = self.tcx().hir().get_if_local(*impl_def_id) { // If an impl is local, then maybe this isn't what they want. Try to // be as helpful as possible with implicit lifetimes. @@ -73,31 +82,30 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // there aren't trait objects or because none are implicit, then just // write a single note on the impl itself. - let impl_span = self.tcx().def_span(*impl_def_id); - err.span_note(impl_span, "...does not necessarily outlive the static lifetime introduced by the compatible `impl`"); + impl_span = Some(self.tcx().def_span(*impl_def_id)); } else { // Otherwise, point at all implicit static lifetimes - err.note("...does not necessarily outlive the static lifetime introduced by the compatible `impl`"); for span in &traits { - err.span_note(*span, "this has an implicit `'static` lifetime requirement"); + trait_subdiags.push(TraitSubdiag::Note { span: *span }); // It would be nice to put this immediately under the above note, but they get // pushed to the end. - err.span_suggestion_verbose( - span.shrink_to_hi(), - "consider relaxing the implicit `'static` requirement", - " + '_", - Applicability::MaybeIncorrect, - ); + trait_subdiags.push(TraitSubdiag::Sugg { span: span.shrink_to_hi() }); } } } else { // Otherwise just point out the impl. - let impl_span = self.tcx().def_span(*impl_def_id); - err.span_note(impl_span, "...does not necessarily outlive the static lifetime introduced by the compatible `impl`"); + impl_span = Some(self.tcx().def_span(*impl_def_id)); } - let reported = err.emit(); + let err = MismatchedStaticLifetime { + cause_span: cause.span, + multispan_subdiag, + expl, + impl_note: ImplNote { impl_span }, + trait_subdiags, + }; + let reported = self.tcx().sess.emit_err(err); Some(reported) } } From 3190522294dac32db63b11b579f6b75a4f2f7d8e Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Wed, 31 Aug 2022 15:02:11 +0300 Subject: [PATCH 4247/5092] Address some comments --- compiler/rustc_infer/src/errors/mod.rs | 123 ++++++++---------- .../src/errors/note_and_explain.rs | 2 +- .../nice_region_error/different_lifetimes.rs | 4 +- .../mismatched_static_lifetime.rs | 11 +- compiler/rustc_infer/src/lib.rs | 4 - 5 files changed, 66 insertions(+), 78 deletions(-) diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index ad8eb2945fa9..e191147cdfe4 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1,6 +1,6 @@ use hir::GenericParamKind; use rustc_errors::{ - fluent, AddSubdiagnostic, Applicability, DiagnosticMessage, DiagnosticStyledString, + fluent, AddSubdiagnostic, Applicability, DiagnosticMessage, DiagnosticStyledString, MultiSpan, }; use rustc_hir as hir; use rustc_hir::{FnRetTy, Ty}; @@ -273,8 +273,8 @@ pub enum LifetimeMismatchLabels { ty_sup: Span, ty_sub: Span, span: Span, - label_var1: Option, - label_var2: Option, + sup: Option, + sub: Option, }, } @@ -293,8 +293,8 @@ impl AddSubdiagnostic for LifetimeMismatchLabels { ty_sup, ty_sub, span, - label_var1, - label_var2, + sup: label_var1, + sub: label_var2, } => { if hir_equal { diag.span_label(ty_sup, fluent::infer::declared_multiple); @@ -422,68 +422,57 @@ pub struct LifetimeMismatch<'a> { pub suggestion: AddLifetimeParamsSuggestion<'a>, } -pub mod mismatched_static_lifetime { - use rustc_errors::{self, fluent, AddSubdiagnostic, MultiSpan}; - use rustc_span::Span; +pub struct IntroducesStaticBecauseUnmetLifetimeReq { + pub unmet_requirements: MultiSpan, + pub binding_span: Span, +} - use super::note_and_explain; - - pub struct LabeledMultiSpan { - pub multi_span: MultiSpan, - pub binding_span: Span, - } - - impl AddSubdiagnostic for LabeledMultiSpan { - fn add_to_diagnostic(mut self, diag: &mut rustc_errors::Diagnostic) { - self.multi_span - .push_span_label(self.binding_span, fluent::infer::msl_introduces_static); - diag.span_note(self.multi_span, fluent::infer::msl_unmet_req); - } - } - - pub struct ImplNote { - pub impl_span: Option, - } - - impl AddSubdiagnostic for ImplNote { - fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { - match self.impl_span { - Some(span) => diag.span_note(span, fluent::infer::msl_impl_note), - None => diag.note(fluent::infer::msl_impl_note), - }; - } - } - - #[derive(SessionSubdiagnostic)] - pub enum TraitSubdiag { - #[note(infer::msl_trait_note)] - Note { - #[primary_span] - span: Span, - }, - #[suggestion_verbose( - infer::msl_trait_sugg, - code = " + '_", - applicability = "maybe-incorrect" - )] - Sugg { - #[primary_span] - span: Span, - }, - } - - #[derive(SessionDiagnostic)] - #[diag(infer::mismatched_static_lifetime)] - pub struct MismatchedStaticLifetime<'a> { - #[primary_span] - pub cause_span: Span, - #[subdiagnostic] - pub multispan_subdiag: LabeledMultiSpan, - #[subdiagnostic] - pub expl: Option>, - #[subdiagnostic] - pub impl_note: ImplNote, - #[subdiagnostic] - pub trait_subdiags: Vec, +impl AddSubdiagnostic for IntroducesStaticBecauseUnmetLifetimeReq { + fn add_to_diagnostic(mut self, diag: &mut rustc_errors::Diagnostic) { + self.unmet_requirements + .push_span_label(self.binding_span, fluent::infer::msl_introduces_static); + diag.span_note(self.unmet_requirements, fluent::infer::msl_unmet_req); } } + +pub struct ImplNote { + pub impl_span: Option, +} + +impl AddSubdiagnostic for ImplNote { + fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { + match self.impl_span { + Some(span) => diag.span_note(span, fluent::infer::msl_impl_note), + None => diag.note(fluent::infer::msl_impl_note), + }; + } +} + +#[derive(SessionSubdiagnostic)] +pub enum TraitSubdiag { + #[note(infer::msl_trait_note)] + Note { + #[primary_span] + span: Span, + }, + #[suggestion_verbose(infer::msl_trait_sugg, code = " + '_", applicability = "maybe-incorrect")] + Sugg { + #[primary_span] + span: Span, + }, +} + +#[derive(SessionDiagnostic)] +#[diag(infer::mismatched_static_lifetime)] +pub struct MismatchedStaticLifetime<'a> { + #[primary_span] + pub cause_span: Span, + #[subdiagnostic] + pub unmet_lifetime_reqs: IntroducesStaticBecauseUnmetLifetimeReq, + #[subdiagnostic] + pub expl: Option>, + #[subdiagnostic] + pub impl_note: ImplNote, + #[subdiagnostic] + pub trait_subdiags: Vec, +} diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs index 92bf3ecd131d..c9df277c744c 100644 --- a/compiler/rustc_infer/src/errors/note_and_explain.rs +++ b/compiler/rustc_infer/src/errors/note_and_explain.rs @@ -91,7 +91,7 @@ impl<'a> DescriptionCtx<'a> { me.kind = "as_defined_anon"; } else { me.kind = "as_defined"; - me.arg = name.to_string(); + me.arg = name.to_string(); }; me.span = Some(sp); } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs index ebd59a3fef79..3a4320a9a8f1 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs @@ -122,8 +122,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { ty_sup: ty_sup.span, ty_sub: ty_sub.span, span, - label_var1: anon_param_sup.pat.simple_ident(), - label_var2: anon_param_sub.pat.simple_ident(), + sup: anon_param_sup.pat.simple_ident(), + sub: anon_param_sub.pat.simple_ident(), }, }; diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs index 832a0eaba3b8..1410e2b63b0b 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs @@ -1,8 +1,8 @@ //! Error Reporting for when the lifetime for a type doesn't match the `impl` selected for a predicate //! to hold. -use crate::errors::mismatched_static_lifetime::{ImplNote, MismatchedStaticLifetime, TraitSubdiag}; -use crate::errors::{mismatched_static_lifetime::LabeledMultiSpan, note_and_explain}; +use crate::errors::{note_and_explain, IntroducesStaticBecauseUnmetLifetimeReq}; +use crate::errors::{ImplNote, MismatchedStaticLifetime, TraitSubdiag}; use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::{SubregionOrigin, TypeTrace}; @@ -43,7 +43,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // FIXME: we should point at the lifetime let multi_span: MultiSpan = vec![binding_span].into(); - let multispan_subdiag = LabeledMultiSpan { multi_span, binding_span }; + let multispan_subdiag = IntroducesStaticBecauseUnmetLifetimeReq { + unmet_requirements: multi_span, + binding_span, + }; let expl = note_and_explain::RegionExplanation::new( self.tcx(), @@ -100,7 +103,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } let err = MismatchedStaticLifetime { cause_span: cause.span, - multispan_subdiag, + unmet_lifetime_reqs: multispan_subdiag, expl, impl_note: ImplNote { impl_span }, trait_subdiags, diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 5810616fcdbf..931ebca7d014 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -36,9 +36,5 @@ extern crate tracing; extern crate rustc_middle; mod errors; -pub mod public_errors { - // Probably would be useful in rustc_borrowck - pub use super::errors::AddLifetimeParamsSuggestion; -} pub mod infer; pub mod traits; From e750d7faa7e18fb3af51de96b35baebcce4123a2 Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Fri, 2 Sep 2022 16:05:00 +0300 Subject: [PATCH 4248/5092] Remove a comment and use IntoDiagnosticArg instead of add_to() where feasible --- .../src/errors/note_and_explain.rs | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs index c9df277c744c..6f1f9522c869 100644 --- a/compiler/rustc_infer/src/errors/note_and_explain.rs +++ b/compiler/rustc_infer/src/errors/note_and_explain.rs @@ -1,5 +1,5 @@ use crate::infer::error_reporting::nice_region_error::find_anon_type; -use rustc_errors::{self, fluent, AddSubdiagnostic}; +use rustc_errors::{self, fluent, AddSubdiagnostic, IntoDiagnosticArg}; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{symbol::kw, Span}; @@ -29,7 +29,6 @@ impl<'a> DescriptionCtx<'a> { ty::ReEmpty(ty::UniverseIndex::ROOT) => me.kind = "reempty", - // uh oh, hope no user ever sees THIS ty::ReEmpty(ui) => { me.kind = "reemptyuni"; me.arg = format!("{:?}", ui); @@ -128,19 +127,23 @@ pub enum SuffixKind { Continues, } -impl PrefixKind { - fn add_to(self, diag: &mut rustc_errors::Diagnostic) { - match self { - Self::Empty => diag.set_arg("pref_kind", "empty"), - }; +impl IntoDiagnosticArg for PrefixKind { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + let kind = match self { + Self::Empty => "empty", + } + .into(); + rustc_errors::DiagnosticArgValue::Str(kind) } } -impl SuffixKind { - fn add_to(self, diag: &mut rustc_errors::Diagnostic) { - match self { - Self::Continues => diag.set_arg("suff_kind", "continues"), - }; +impl IntoDiagnosticArg for SuffixKind { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + let kind = match self { + Self::Continues => "continues", + } + .into(); + rustc_errors::DiagnosticArgValue::Str(kind) } } @@ -170,7 +173,7 @@ impl AddSubdiagnostic for RegionExplanation<'_> { diag.note(fluent::infer::region_explanation); } self.desc.add_to(diag); - self.prefix.add_to(diag); - self.suffix.add_to(diag); + diag.set_arg("pref_kind", self.prefix); + diag.set_arg("suff_kind", self.suffix); } } From 59c567296a8dd2b6c36765dbb14caf68cc9cf9af Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Mon, 5 Sep 2022 19:04:35 +0300 Subject: [PATCH 4249/5092] Use untranslated messages for now --- compiler/rustc_infer/src/errors/mod.rs | 35 ++++++++++++++++++-------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index e191147cdfe4..911381b367f4 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -448,18 +448,31 @@ impl AddSubdiagnostic for ImplNote { } } -#[derive(SessionSubdiagnostic)] pub enum TraitSubdiag { - #[note(infer::msl_trait_note)] - Note { - #[primary_span] - span: Span, - }, - #[suggestion_verbose(infer::msl_trait_sugg, code = " + '_", applicability = "maybe-incorrect")] - Sugg { - #[primary_span] - span: Span, - }, + Note { span: Span }, + Sugg { span: Span }, +} + +// FIXME We can't rely on Vec working well at the moment, +// as only the args from one of the subdiagnostics will actually be used. +// This results in an incorrect diagnostic if more than two subdiags with the same slug are added. +// Use untranslated messages for now. +impl AddSubdiagnostic for TraitSubdiag { + fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { + match self { + TraitSubdiag::Note { span } => { + diag.span_note(span, "this has an implicit `'static` lifetime requirement"); + } + TraitSubdiag::Sugg { span } => { + diag.span_suggestion_verbose( + span, + "consider relaxing the implicit `'static` requirement", + " + '_".to_owned(), + rustc_errors::Applicability::MaybeIncorrect, + ); + } + } + } } #[derive(SessionDiagnostic)] From cb7ad9e54853aa5bc217a147d74e3289f6c45489 Mon Sep 17 00:00:00 2001 From: IQuant Date: Tue, 6 Sep 2022 17:54:29 +0300 Subject: [PATCH 4250/5092] Slightly more concise comment Co-authored-by: David Wood --- compiler/rustc_infer/src/errors/mod.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 911381b367f4..5eedca78489b 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -453,10 +453,7 @@ pub enum TraitSubdiag { Sugg { span: Span }, } -// FIXME We can't rely on Vec working well at the moment, -// as only the args from one of the subdiagnostics will actually be used. -// This results in an incorrect diagnostic if more than two subdiags with the same slug are added. -// Use untranslated messages for now. +// FIXME(#100717) used in `Vec` so requires eager translation/list support impl AddSubdiagnostic for TraitSubdiag { fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { match self { From 056d6338c8962b52b4398decda48187d010865bf Mon Sep 17 00:00:00 2001 From: Matt Hamrick Date: Tue, 6 Sep 2022 09:04:28 -0700 Subject: [PATCH 4251/5092] Update src/doc/rustc/src/platform-support/fuchsia.md Co-authored-by: Andrew Pollack --- src/doc/rustc/src/platform-support/fuchsia.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md index 98bfbcee3cf1..51ad735f070a 100644 --- a/src/doc/rustc/src/platform-support/fuchsia.md +++ b/src/doc/rustc/src/platform-support/fuchsia.md @@ -414,7 +414,7 @@ Next, we'll build a package manifest as defined by our manifest: ```sh ${SDK_PATH}/tools/${ARCH}/pm \ - -api-level 8 \ + -api-level $(${SDK_PATH}/tools/${ARCH}/ffx version -v | grep "api-level" | head -1 | awk -F ' ' '{print $2}') \ -o pkg/hello_fuchsia_manifest \ -m pkg/hello_fuchsia.manifest \ build \ From 428280270641849d87a0716d36faf6e45b03a2b1 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 6 Sep 2022 09:12:17 -0700 Subject: [PATCH 4252/5092] rustdoc: remove unused CSS `#results > table` This code was added in 96ef2f8ab9bbea24b71c7441ee534407949848db to improve rendering of the search results table, but results have not used a table since b615c0c85469c94041a5e68b9d8b68dcf799f9f1 switched it to rendering with `

` tags. --- src/librustdoc/html/static/css/rustdoc.css | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 3502d97d470f..f3a6c5a9c0f7 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -609,11 +609,6 @@ h2.location a { text-align: center; } -#results > table { - width: 100%; - table-layout: fixed; -} - .content > .example-wrap pre.line-numbers { position: relative; -webkit-user-select: none; From e1f5d4f23f8136a7842c6bc38a1cde78566149b7 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 6 Sep 2022 10:33:58 -0700 Subject: [PATCH 4253/5092] rustdoc: remove outdated CSS `.sub-variant > div > .item-info` This CSS still matches sometimes, as you can see in , but since nothing else is setting `margin-top`, putting it back to `initial` does nothing. This selector was added in 2fd378b82b14f2746462018e8510e15a079818a0 (but it was called `.stability` instead of `.item-info` at the time), probably as an override for the selector immediately above it that sets a negative margin. That negative margin was removed in 593d6d1cb15c55c88319470dabb40126c7b7f1e2. --- src/librustdoc/html/static/css/rustdoc.css | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 3502d97d470f..1f293c96757d 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -770,10 +770,6 @@ pre, .rustdoc.source .example-wrap { margin-left: 24px; } -.sub-variant > div > .item-info { - margin-top: initial; -} - .content .impl-items .docblock, .content .impl-items .item-info { margin-bottom: .6em; } From 1e384423a9cfd678f976cf0183c81a770da2a325 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 7 Sep 2022 02:37:18 +0900 Subject: [PATCH 4254/5092] suggest adding array lengths to references to arrays --- compiler/rustc_hir/src/hir.rs | 8 +++ compiler/rustc_typeck/src/check/expr.rs | 47 ++++++------- .../suggest-array-length.fixed | 12 ++++ .../array-slice-vec/suggest-array-length.rs | 12 ++++ .../suggest-array-length.stderr | 70 +++++++++++++++++-- 5 files changed, 120 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 9535ccfe8b69..c17702d624a7 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2396,6 +2396,14 @@ impl<'hir> Ty<'hir> { _ => None, } } + + pub fn peel_refs(&self) -> &Self { + let mut final_ty = self; + while let TyKind::Rptr(_, MutTy { ty, .. }) = &final_ty.kind { + final_ty = &ty; + } + final_ty + } } /// Not represented directly in the AST; referred to by name through a `ty_path`. diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index e4141647d7d2..44f845bde615 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1305,31 +1305,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } fn suggest_array_len(&self, expr: &'tcx hir::Expr<'tcx>, array_len: u64) { - if let Some(parent_hir_id) = self.tcx.hir().find_parent_node(expr.hir_id) { - let ty = match self.tcx.hir().find(parent_hir_id) { - Some( - hir::Node::Local(hir::Local { ty: Some(ty), .. }) - | hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _), .. }), - ) => Some(ty), - _ => None, - }; - if let Some(ty) = ty - && let hir::TyKind::Array(_, length) = ty.kind - && let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length - && let Some(span) = self.tcx.hir().opt_span(hir_id) - { - match self.tcx.sess.diagnostic().steal_diagnostic(span, StashKey::UnderscoreForArrayLengths) { - Some(mut err) => { - err.span_suggestion( - span, - "consider specifying the array length", - array_len, - Applicability::MaybeIncorrect, - ); - err.emit(); - } - None => () + let parent_node = self.tcx.hir().parent_iter(expr.hir_id).find(|(_, node)| { + !matches!(node, hir::Node::Expr(hir::Expr { kind: hir::ExprKind::AddrOf(..), .. })) + }); + let Some((_, + hir::Node::Local(hir::Local { ty: Some(ty), .. }) + | hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _), .. })) + ) = parent_node else { + return + }; + if let hir::TyKind::Array(_, length) = ty.peel_refs().kind + && let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length + && let Some(span) = self.tcx.hir().opt_span(hir_id) + { + match self.tcx.sess.diagnostic().steal_diagnostic(span, StashKey::UnderscoreForArrayLengths) { + Some(mut err) => { + err.span_suggestion( + span, + "consider specifying the array length", + array_len, + Applicability::MaybeIncorrect, + ); + err.emit(); } + None => () } } } diff --git a/src/test/ui/array-slice-vec/suggest-array-length.fixed b/src/test/ui/array-slice-vec/suggest-array-length.fixed index bae3ab74af67..867c18a7d5e6 100644 --- a/src/test/ui/array-slice-vec/suggest-array-length.fixed +++ b/src/test/ui/array-slice-vec/suggest-array-length.fixed @@ -5,10 +5,22 @@ fn main() { const Foo: [i32; 3] = [1, 2, 3]; //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment //~| ERROR using `_` for array lengths is unstable + const REF_FOO: &[u8; 1] = &[1]; + //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment + //~| ERROR using `_` for array lengths is unstable let foo: [i32; 3] = [1, 2, 3]; //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment //~| ERROR using `_` for array lengths is unstable let bar: [i32; 3] = [0; 3]; //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment //~| ERROR using `_` for array lengths is unstable + let ref_foo: &[i32; 3] = &[1, 2, 3]; + //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment + //~| ERROR using `_` for array lengths is unstable + let ref_bar: &[i32; 3] = &[0; 3]; + //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment + //~| ERROR using `_` for array lengths is unstable + let multiple_ref_foo: &&[i32; 3] = &&[1, 2, 3]; + //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment + //~| ERROR using `_` for array lengths is unstable } diff --git a/src/test/ui/array-slice-vec/suggest-array-length.rs b/src/test/ui/array-slice-vec/suggest-array-length.rs index b0867f4e3967..f66b3d4a8999 100644 --- a/src/test/ui/array-slice-vec/suggest-array-length.rs +++ b/src/test/ui/array-slice-vec/suggest-array-length.rs @@ -5,10 +5,22 @@ fn main() { const Foo: [i32; _] = [1, 2, 3]; //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment //~| ERROR using `_` for array lengths is unstable + const REF_FOO: &[u8; _] = &[1]; + //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment + //~| ERROR using `_` for array lengths is unstable let foo: [i32; _] = [1, 2, 3]; //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment //~| ERROR using `_` for array lengths is unstable let bar: [i32; _] = [0; 3]; //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment //~| ERROR using `_` for array lengths is unstable + let ref_foo: &[i32; _] = &[1, 2, 3]; + //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment + //~| ERROR using `_` for array lengths is unstable + let ref_bar: &[i32; _] = &[0; 3]; + //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment + //~| ERROR using `_` for array lengths is unstable + let multiple_ref_foo: &&[i32; _] = &&[1, 2, 3]; + //~^ ERROR in expressions, `_` can only be used on the left-hand side of an assignment + //~| ERROR using `_` for array lengths is unstable } diff --git a/src/test/ui/array-slice-vec/suggest-array-length.stderr b/src/test/ui/array-slice-vec/suggest-array-length.stderr index 9000f7160285..16c90a04784d 100644 --- a/src/test/ui/array-slice-vec/suggest-array-length.stderr +++ b/src/test/ui/array-slice-vec/suggest-array-length.stderr @@ -1,21 +1,45 @@ error: in expressions, `_` can only be used on the left-hand side of an assignment - --> $DIR/suggest-array-length.rs:8:20 + --> $DIR/suggest-array-length.rs:11:20 | LL | let foo: [i32; _] = [1, 2, 3]; | ^ `_` not allowed here error: in expressions, `_` can only be used on the left-hand side of an assignment - --> $DIR/suggest-array-length.rs:11:20 + --> $DIR/suggest-array-length.rs:14:20 | LL | let bar: [i32; _] = [0; 3]; | ^ `_` not allowed here +error: in expressions, `_` can only be used on the left-hand side of an assignment + --> $DIR/suggest-array-length.rs:17:25 + | +LL | let ref_foo: &[i32; _] = &[1, 2, 3]; + | ^ `_` not allowed here + +error: in expressions, `_` can only be used on the left-hand side of an assignment + --> $DIR/suggest-array-length.rs:20:25 + | +LL | let ref_bar: &[i32; _] = &[0; 3]; + | ^ `_` not allowed here + +error: in expressions, `_` can only be used on the left-hand side of an assignment + --> $DIR/suggest-array-length.rs:23:35 + | +LL | let multiple_ref_foo: &&[i32; _] = &&[1, 2, 3]; + | ^ `_` not allowed here + error: in expressions, `_` can only be used on the left-hand side of an assignment --> $DIR/suggest-array-length.rs:5:22 | LL | const Foo: [i32; _] = [1, 2, 3]; | ^ `_` not allowed here +error: in expressions, `_` can only be used on the left-hand side of an assignment + --> $DIR/suggest-array-length.rs:8:26 + | +LL | const REF_FOO: &[u8; _] = &[1]; + | ^ `_` not allowed here + error[E0658]: using `_` for array lengths is unstable --> $DIR/suggest-array-length.rs:5:22 | @@ -26,7 +50,16 @@ LL | const Foo: [i32; _] = [1, 2, 3]; = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable error[E0658]: using `_` for array lengths is unstable - --> $DIR/suggest-array-length.rs:8:20 + --> $DIR/suggest-array-length.rs:8:26 + | +LL | const REF_FOO: &[u8; _] = &[1]; + | ^ help: consider specifying the array length: `1` + | + = note: see issue #85077 for more information + = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable + +error[E0658]: using `_` for array lengths is unstable + --> $DIR/suggest-array-length.rs:11:20 | LL | let foo: [i32; _] = [1, 2, 3]; | ^ help: consider specifying the array length: `3` @@ -35,7 +68,7 @@ LL | let foo: [i32; _] = [1, 2, 3]; = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable error[E0658]: using `_` for array lengths is unstable - --> $DIR/suggest-array-length.rs:11:20 + --> $DIR/suggest-array-length.rs:14:20 | LL | let bar: [i32; _] = [0; 3]; | ^ help: consider specifying the array length: `3` @@ -43,6 +76,33 @@ LL | let bar: [i32; _] = [0; 3]; = note: see issue #85077 for more information = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable -error: aborting due to 6 previous errors +error[E0658]: using `_` for array lengths is unstable + --> $DIR/suggest-array-length.rs:17:25 + | +LL | let ref_foo: &[i32; _] = &[1, 2, 3]; + | ^ help: consider specifying the array length: `3` + | + = note: see issue #85077 for more information + = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable + +error[E0658]: using `_` for array lengths is unstable + --> $DIR/suggest-array-length.rs:20:25 + | +LL | let ref_bar: &[i32; _] = &[0; 3]; + | ^ help: consider specifying the array length: `3` + | + = note: see issue #85077 for more information + = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable + +error[E0658]: using `_` for array lengths is unstable + --> $DIR/suggest-array-length.rs:23:35 + | +LL | let multiple_ref_foo: &&[i32; _] = &&[1, 2, 3]; + | ^ help: consider specifying the array length: `3` + | + = note: see issue #85077 for more information + = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable + +error: aborting due to 14 previous errors For more information about this error, try `rustc --explain E0658`. From d6f385fe75979c0d919367bcd3e1c65df793421d Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Tue, 6 Sep 2022 10:49:09 -0700 Subject: [PATCH 4255/5092] rustdoc mobile: move notable traits to return type These were originally on the left, but were moved to the return type in c90fb7185a5febb00b7f8ccb49abceacd41bad6e. The CSS rule for mobile did not get updated at the time, so updating it now. --- src/librustdoc/html/static/css/rustdoc.css | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 83fe14550cc2..88a412314e05 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1973,12 +1973,6 @@ in storage.js plus the media query with (min-width: 701px) display: none !important; } - .notable-traits { - position: absolute; - left: -22px; - top: 24px; - } - #titles > button > div.count { float: left; width: 100%; From d8b382105f1cb6faeb7e500481720d3433bf87ae Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 6 Sep 2022 20:08:04 +0200 Subject: [PATCH 4256/5092] Compile spin_loop_hint as pause on x86 even without sse2 enabled The x86 `pause` instruction was introduced with sse2, but because it is encoded as `rep nop`, it works just fine on cpu's without sse2 support. It just doesn't do anything. --- library/core/src/hint.rs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 20340d42962e..764e2796202c 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -160,19 +160,16 @@ pub const unsafe fn unreachable_unchecked() -> ! { #[inline] #[stable(feature = "renamed_spin_loop", since = "1.49.0")] pub fn spin_loop() { - #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse2"))] + #[cfg(target_arch = "x86")] { - #[cfg(target_arch = "x86")] - { - // SAFETY: the `cfg` attr ensures that we only execute this on x86 targets. - unsafe { crate::arch::x86::_mm_pause() }; - } + // SAFETY: the `cfg` attr ensures that we only execute this on x86 targets. + unsafe { crate::arch::x86::_mm_pause() }; + } - #[cfg(target_arch = "x86_64")] - { - // SAFETY: the `cfg` attr ensures that we only execute this on x86_64 targets. - unsafe { crate::arch::x86_64::_mm_pause() }; - } + #[cfg(target_arch = "x86_64")] + { + // SAFETY: the `cfg` attr ensures that we only execute this on x86_64 targets. + unsafe { crate::arch::x86_64::_mm_pause() }; } // RISC-V platform spin loop hint implementation From 2166a362452467516a1308048d7b40dc8428e5c2 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Fri, 2 Sep 2022 17:38:58 -0300 Subject: [PATCH 4257/5092] Pass ImplTraitContext as &mut to avoid the need of ImplTraitContext::reborrow later on --- compiler/rustc_ast_lowering/src/asm.rs | 2 +- compiler/rustc_ast_lowering/src/block.rs | 7 +- compiler/rustc_ast_lowering/src/expr.rs | 34 ++++---- compiler/rustc_ast_lowering/src/item.rs | 99 ++++++++++++++---------- compiler/rustc_ast_lowering/src/lib.rs | 61 ++++++++------- compiler/rustc_ast_lowering/src/pat.rs | 6 +- compiler/rustc_ast_lowering/src/path.rs | 18 +++-- 7 files changed, 125 insertions(+), 102 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index b0e9fe0469c4..90bb01aa2165 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -220,7 +220,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &sym.qself, &sym.path, ParamMode::Optional, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path), ); hir::InlineAsmOperand::SymStatic { path, def_id } } else { diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index 7cbfe143b4d8..7465706d1a9b 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -84,10 +84,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn lower_local(&mut self, l: &Local) -> &'hir hir::Local<'hir> { - let ty = l - .ty - .as_ref() - .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Variable))); + let ty = l.ty.as_ref().map(|t| { + self.lower_ty(t, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Variable)) + }); let init = l.kind.init().map(|init| self.lower_expr(init)); let hir_id = self.lower_node_id(l.id); let pat = self.lower_pat(&l.pat); diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 77babeb5d39d..6fa8d7f0fcdd 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -66,7 +66,7 @@ impl<'hir> LoweringContext<'_, 'hir> { seg, ParamMode::Optional, ParenthesizedGenericArgs::Err, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path), )); let receiver = self.lower_expr(receiver); let args = @@ -89,14 +89,14 @@ impl<'hir> LoweringContext<'_, 'hir> { } ExprKind::Cast(ref expr, ref ty) => { let expr = self.lower_expr(expr); - let ty = - self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)); + let ty = self + .lower_ty(ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type)); hir::ExprKind::Cast(expr, ty) } ExprKind::Type(ref expr, ref ty) => { let expr = self.lower_expr(expr); - let ty = - self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)); + let ty = self + .lower_ty(ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type)); hir::ExprKind::Type(expr, ty) } ExprKind::AddrOf(k, m, ref ohs) => { @@ -219,7 +219,7 @@ impl<'hir> LoweringContext<'_, 'hir> { qself, path, ParamMode::Optional, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path), ); hir::ExprKind::Path(qpath) } @@ -253,7 +253,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &se.qself, &se.path, ParamMode::Optional, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path), )), self.arena .alloc_from_iter(se.fields.iter().map(|x| self.lower_expr_field(x))), @@ -550,12 +550,14 @@ impl<'hir> LoweringContext<'_, 'hir> { async_gen_kind: hir::AsyncGeneratorKind, body: impl FnOnce(&mut Self) -> hir::Expr<'hir>, ) -> hir::ExprKind<'hir> { - let output = match ret_ty { - Some(ty) => hir::FnRetTy::Return( - self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock)), - ), - None => hir::FnRetTy::DefaultReturn(self.lower_span(span)), - }; + let output = + match ret_ty { + Some(ty) => hir::FnRetTy::Return(self.lower_ty( + &ty, + &mut ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock), + )), + None => hir::FnRetTy::DefaultReturn(self.lower_span(span)), + }; // Resume argument type. We let the compiler infer this to simplify the lowering. It is // fully constrained by `future::from_generator`. @@ -1123,7 +1125,7 @@ impl<'hir> LoweringContext<'_, 'hir> { qself, path, ParamMode::Optional, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path), ); // Destructure like a tuple struct. let tuple_struct_pat = @@ -1139,7 +1141,7 @@ impl<'hir> LoweringContext<'_, 'hir> { qself, path, ParamMode::Optional, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path), ); // Destructure like a unit struct. let unit_struct_pat = hir::PatKind::Path(qpath); @@ -1163,7 +1165,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &se.qself, &se.path, ParamMode::Optional, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path), ); let fields_omitted = match &se.rest { StructRest::Base(e) => { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 76f63d1d78a9..f0717b51d4b1 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -264,8 +264,8 @@ impl<'hir> LoweringContext<'_, 'hir> { let body_id = this.lower_maybe_async_body(span, &decl, asyncness, body.as_deref()); - let itctx = ImplTraitContext::Universal; - let (generics, decl) = this.lower_generics(generics, id, itctx, |this| { + let mut itctx = ImplTraitContext::Universal; + let (generics, decl) = this.lower_generics(generics, id, &mut itctx, |this| { let ret_id = asyncness.opt_return_id(); this.lower_fn_decl(&decl, Some(id), FnDeclKind::Fn, ret_id) }); @@ -311,8 +311,8 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, ty) = self.lower_generics( &generics, id, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), - |this| this.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + |this| this.lower_ty(ty, &mut ImplTraitContext::TypeAliasesOpaqueTy), ); hir::ItemKind::TyAlias(ty, generics) } @@ -324,7 +324,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, ty) = self.lower_generics( &generics, id, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| this.arena.alloc(this.ty(span, hir::TyKind::Err)), ); hir::ItemKind::TyAlias(ty, generics) @@ -333,7 +333,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, variants) = self.lower_generics( generics, id, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { this.arena.alloc_from_iter( enum_definition.variants.iter().map(|x| this.lower_variant(x)), @@ -346,7 +346,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, struct_def) = self.lower_generics( generics, id, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| this.lower_variant_data(hir_id, struct_def), ); hir::ItemKind::Struct(struct_def, generics) @@ -355,7 +355,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, vdata) = self.lower_generics( generics, id, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| this.lower_variant_data(hir_id, vdata), ); hir::ItemKind::Union(vdata, generics) @@ -383,18 +383,20 @@ impl<'hir> LoweringContext<'_, 'hir> { // method, it will not be considered an in-band // lifetime to be added, but rather a reference to a // parent lifetime. - let itctx = ImplTraitContext::Universal; + let mut itctx = ImplTraitContext::Universal; let (generics, (trait_ref, lowered_ty)) = - self.lower_generics(ast_generics, id, itctx, |this| { + self.lower_generics(ast_generics, id, &mut itctx, |this| { let trait_ref = trait_ref.as_ref().map(|trait_ref| { this.lower_trait_ref( trait_ref, - ImplTraitContext::Disallowed(ImplTraitPosition::Trait), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Trait), ) }); - let lowered_ty = this - .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)); + let lowered_ty = this.lower_ty( + ty, + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type), + ); (trait_ref, lowered_ty) }); @@ -433,11 +435,11 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, (unsafety, items, bounds)) = self.lower_generics( generics, id, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { let bounds = this.lower_param_bounds( bounds, - ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Bound), ); let items = this.arena.alloc_from_iter( items.iter().map(|item| this.lower_trait_item_ref(item)), @@ -452,11 +454,11 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, bounds) = self.lower_generics( generics, id, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { this.lower_param_bounds( bounds, - ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Bound), ) }, ); @@ -479,7 +481,7 @@ impl<'hir> LoweringContext<'_, 'hir> { span: Span, body: Option<&Expr>, ) -> (&'hir hir::Ty<'hir>, hir::BodyId) { - let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)); + let ty = self.lower_ty(ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type)); (ty, self.lower_const_body(span, body)) } @@ -652,9 +654,9 @@ impl<'hir> LoweringContext<'_, 'hir> { kind: match i.kind { ForeignItemKind::Fn(box Fn { ref sig, ref generics, .. }) => { let fdec = &sig.decl; - let itctx = ImplTraitContext::Universal; + let mut itctx = ImplTraitContext::Universal; let (generics, (fn_dec, fn_args)) = - self.lower_generics(generics, i.id, itctx, |this| { + self.lower_generics(generics, i.id, &mut itctx, |this| { ( // Disallow `impl Trait` in foreign items. this.lower_fn_decl(fdec, None, FnDeclKind::ExternFn, None), @@ -665,8 +667,8 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ForeignItemKind::Fn(fn_dec, fn_args, generics) } ForeignItemKind::Static(ref t, m, _) => { - let ty = - self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Type)); + let ty = self + .lower_ty(t, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type)); hir::ForeignItemKind::Static(ty, m) } ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type, @@ -734,11 +736,11 @@ impl<'hir> LoweringContext<'_, 'hir> { qself, path, ParamMode::ExplicitNamed, // no `'_` in declarations (Issue #61124) - ImplTraitContext::Disallowed(ImplTraitPosition::Path), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path), ); self.arena.alloc(t) } else { - self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)) + self.lower_ty(&f.ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type)) }; let hir_id = self.lower_node_id(f.id); self.lower_attrs(hir_id, &f.attrs); @@ -761,7 +763,8 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, kind, has_default) = match i.kind { AssocItemKind::Const(_, ref ty, ref default) => { - let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)); + let ty = + self.lower_ty(ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type)); let body = default.as_ref().map(|x| self.lower_const_body(i.span, Some(x))); (hir::Generics::empty(), hir::TraitItemKind::Const(ty, body), body.is_some()) } @@ -796,15 +799,18 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, kind) = self.lower_generics( &generics, i.id, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| { let ty = ty.as_ref().map(|x| { - this.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Type)) + this.lower_ty( + x, + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type), + ) }); hir::TraitItemKind::Type( this.lower_param_bounds( bounds, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic), ), ty, ) @@ -857,7 +863,8 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, kind) = match &i.kind { AssocItemKind::Const(_, ty, expr) => { - let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)); + let ty = + self.lower_ty(ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type)); ( hir::Generics::empty(), hir::ImplItemKind::Const(ty, self.lower_const_body(i.span, expr.as_deref())), @@ -884,14 +891,14 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_generics( &generics, i.id, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Generic), |this| match ty { None => { let ty = this.arena.alloc(this.ty(i.span, hir::TyKind::Err)); hir::ImplItemKind::TyAlias(ty) } Some(ty) => { - let ty = this.lower_ty(ty, ImplTraitContext::TypeAliasesOpaqueTy); + let ty = this.lower_ty(ty, &mut ImplTraitContext::TypeAliasesOpaqueTy); hir::ImplItemKind::TyAlias(ty) } }, @@ -1234,8 +1241,8 @@ impl<'hir> LoweringContext<'_, 'hir> { is_async: Option, ) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) { let header = self.lower_fn_header(sig.header); - let itctx = ImplTraitContext::Universal; - let (generics, decl) = self.lower_generics(generics, id, itctx, |this| { + let mut itctx = ImplTraitContext::Universal; + let (generics, decl) = self.lower_generics(generics, id, &mut itctx, |this| { this.lower_fn_decl(&sig.decl, Some(id), kind, is_async) }); (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) }) @@ -1301,7 +1308,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, generics: &Generics, parent_node_id: NodeId, - itctx: ImplTraitContext, + itctx: &mut ImplTraitContext, f: impl FnOnce(&mut Self) -> T, ) -> (&'hir hir::Generics<'hir>, T) { debug_assert!(self.impl_trait_defs.is_empty()); @@ -1406,7 +1413,7 @@ impl<'hir> LoweringContext<'_, 'hir> { id: NodeId, kind: &GenericParamKind, bounds: &[GenericBound], - itctx: ImplTraitContext, + itctx: &mut ImplTraitContext, origin: PredicateOrigin, ) -> Option> { // Do not create a clause if we do not have anything inside it. @@ -1481,12 +1488,14 @@ impl<'hir> LoweringContext<'_, 'hir> { span, }) => hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { bound_generic_params: self.lower_generic_params(bound_generic_params), - bounded_ty: self - .lower_ty(bounded_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)), + bounded_ty: self.lower_ty( + bounded_ty, + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type), + ), bounds: self.arena.alloc_from_iter(bounds.iter().map(|bound| { self.lower_param_bound( bound, - ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Bound), ) })), span: self.lower_span(span), @@ -1501,16 +1510,20 @@ impl<'hir> LoweringContext<'_, 'hir> { lifetime: self.lower_lifetime(lifetime), bounds: self.lower_param_bounds( bounds, - ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Bound), ), in_where_clause: true, }), WherePredicate::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty, span }) => { hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { - lhs_ty: self - .lower_ty(lhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)), - rhs_ty: self - .lower_ty(rhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)), + lhs_ty: self.lower_ty( + lhs_ty, + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type), + ), + rhs_ty: self.lower_ty( + rhs_ty, + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type), + ), span: self.lower_span(span), }) } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 3a94c7a91b23..1ab4aa28c45d 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -953,7 +953,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_assoc_ty_constraint( &mut self, constraint: &AssocConstraint, - itctx: ImplTraitContext, + itctx: &mut ImplTraitContext, ) -> hir::TypeBinding<'hir> { debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx); // lower generic arguments of identifier in constraint @@ -976,6 +976,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } else { self.arena.alloc(hir::GenericArgs::none()) }; + let mut itctx_tait = ImplTraitContext::TypeAliasesOpaqueTy; let kind = match constraint.kind { AssocConstraintKind::Equality { ref term } => { @@ -1014,7 +1015,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // // FIXME: this is only needed until `impl Trait` is allowed in type aliases. ImplTraitContext::Disallowed(_) if self.is_in_dyn_type => { - (true, ImplTraitContext::TypeAliasesOpaqueTy) + (true, &mut itctx_tait) } // We are in the parameter position, but not within a dyn type: @@ -1096,7 +1097,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_generic_arg( &mut self, arg: &ast::GenericArg, - itctx: ImplTraitContext, + itctx: &mut ImplTraitContext, ) -> hir::GenericArg<'hir> { match arg { ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(<)), @@ -1158,7 +1159,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } #[instrument(level = "debug", skip(self))] - fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> &'hir hir::Ty<'hir> { + fn lower_ty(&mut self, t: &Ty, itctx: &mut ImplTraitContext) -> &'hir hir::Ty<'hir> { self.arena.alloc(self.lower_ty_direct(t, itctx)) } @@ -1168,7 +1169,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself: &Option, path: &Path, param_mode: ParamMode, - itctx: ImplTraitContext, + itctx: &mut ImplTraitContext, ) -> hir::Ty<'hir> { // Check whether we should interpret this as a bare trait object. // This check mirrors the one in late resolution. We only introduce this special case in @@ -1210,7 +1211,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.ty(span, hir::TyKind::Tup(tys)) } - fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> { + fn lower_ty_direct(&mut self, t: &Ty, itctx: &mut ImplTraitContext) -> hir::Ty<'hir> { let kind = match t.kind { TyKind::Infer => hir::TyKind::Infer, TyKind::Err => hir::TyKind::Err, @@ -1307,16 +1308,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let span = t.span; match itctx { ImplTraitContext::ReturnPositionOpaqueTy { origin } => { - self.lower_opaque_impl_trait(span, origin, def_node_id, bounds, itctx) + self.lower_opaque_impl_trait(span, *origin, def_node_id, bounds, itctx) } ImplTraitContext::TypeAliasesOpaqueTy => { - let nested_itctx = ImplTraitContext::TypeAliasesOpaqueTy; + let mut nested_itctx = ImplTraitContext::TypeAliasesOpaqueTy; self.lower_opaque_impl_trait( span, hir::OpaqueTyOrigin::TyAlias, def_node_id, bounds, - nested_itctx, + &mut nested_itctx, ) } ImplTraitContext::Universal => { @@ -1388,7 +1389,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { origin: hir::OpaqueTyOrigin, opaque_ty_node_id: NodeId, bounds: &GenericBounds, - itctx: ImplTraitContext, + itctx: &mut ImplTraitContext, ) -> hir::TyKind<'hir> { // Make sure we know that some funky desugaring has been going on here. // This is a first: there is code in other places like for loop @@ -1636,11 +1637,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| { if fn_node_id.is_some() { - self.lower_ty_direct(¶m.ty, ImplTraitContext::Universal) + self.lower_ty_direct(¶m.ty, &mut ImplTraitContext::Universal) } else { self.lower_ty_direct( ¶m.ty, - ImplTraitContext::Disallowed(match kind { + &mut ImplTraitContext::Disallowed(match kind { FnDeclKind::Fn | FnDeclKind::Inherent => { unreachable!("fn should allow in-band lifetimes") } @@ -1663,7 +1664,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } else { match decl.output { FnRetTy::Ty(ref ty) => { - let context = match fn_node_id { + let mut context = match fn_node_id { Some(fn_node_id) if kind.impl_trait_return_allowed() => { let fn_def_id = self.local_def_id(fn_node_id); ImplTraitContext::ReturnPositionOpaqueTy { @@ -1681,7 +1682,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { FnDeclKind::Impl => ImplTraitPosition::ImplReturn, }), }; - hir::FnRetTy::Return(self.lower_ty(ty, context)) + hir::FnRetTy::Return(self.lower_ty(ty, &mut context)) } FnRetTy::Default(span) => hir::FnRetTy::DefaultReturn(self.lower_span(span)), } @@ -1960,10 +1961,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Not `OpaqueTyOrigin::AsyncFn`: that's only used for the // `impl Future` opaque type that `async fn` implicitly // generates. - let context = ImplTraitContext::ReturnPositionOpaqueTy { + let mut context = ImplTraitContext::ReturnPositionOpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id), }; - self.lower_ty(ty, context) + self.lower_ty(ty, &mut context) } FnRetTy::Default(ret_ty_span) => self.arena.alloc(self.ty_tup(*ret_ty_span, &[])), }; @@ -1989,7 +1990,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_param_bound( &mut self, tpb: &GenericBound, - itctx: ImplTraitContext, + itctx: &mut ImplTraitContext, ) -> hir::GenericBound<'hir> { match tpb { GenericBound::Trait(p, modifier) => hir::GenericBound::Trait( @@ -2101,7 +2102,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { GenericParamKind::Type { ref default, .. } => { let kind = hir::GenericParamKind::Type { default: default.as_ref().map(|x| { - self.lower_ty(x, ImplTraitContext::Disallowed(ImplTraitPosition::Type)) + self.lower_ty(x, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type)) }), synthetic: false, }; @@ -2109,7 +2110,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { (hir::ParamName::Plain(self.lower_ident(param.ident)), kind) } GenericParamKind::Const { ref ty, kw_span: _, ref default } => { - let ty = self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)); + let ty = + self.lower_ty(&ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::Type)); let default = default.as_ref().map(|def| self.lower_anon_const(def)); ( hir::ParamName::Plain(self.lower_ident(param.ident)), @@ -2119,7 +2121,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - fn lower_trait_ref(&mut self, p: &TraitRef, itctx: ImplTraitContext) -> hir::TraitRef<'hir> { + fn lower_trait_ref( + &mut self, + p: &TraitRef, + itctx: &mut ImplTraitContext, + ) -> hir::TraitRef<'hir> { let path = match self.lower_qpath(p.ref_id, &None, &p.path, ParamMode::Explicit, itctx) { hir::QPath::Resolved(None, path) => path, qpath => panic!("lower_trait_ref: unexpected QPath `{:?}`", qpath), @@ -2131,7 +2137,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_poly_trait_ref( &mut self, p: &PolyTraitRef, - itctx: ImplTraitContext, + itctx: &mut ImplTraitContext, ) -> hir::PolyTraitRef<'hir> { let bound_generic_params = self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params); @@ -2139,23 +2145,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) } } - fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> { + fn lower_mt(&mut self, mt: &MutTy, itctx: &mut ImplTraitContext) -> hir::MutTy<'hir> { hir::MutTy { ty: self.lower_ty(&mt.ty, itctx), mutbl: mt.mutbl } } fn lower_param_bounds( &mut self, bounds: &[GenericBound], - itctx: ImplTraitContext, + itctx: &mut ImplTraitContext, ) -> hir::GenericBounds<'hir> { self.arena.alloc_from_iter(self.lower_param_bounds_mut(bounds, itctx)) } - fn lower_param_bounds_mut<'s>( + fn lower_param_bounds_mut<'s, 'b>( &'s mut self, bounds: &'s [GenericBound], - itctx: ImplTraitContext, - ) -> impl Iterator> + Captures<'s> + Captures<'a> { + itctx: &'b mut ImplTraitContext, + ) -> impl Iterator> + Captures<'s> + Captures<'a> + Captures<'b> + { bounds.iter().map(move |bound| self.lower_param_bound(bound, itctx)) } @@ -2184,7 +2191,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { node_id, &GenericParamKind::Type { default: None }, bounds, - ImplTraitContext::Universal, + &mut ImplTraitContext::Universal, hir::PredicateOrigin::ImplTrait, ); diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index a1eee1be7984..69e6c2c8ad0b 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -37,7 +37,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself, path, ParamMode::Optional, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path), ); let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct"); break hir::PatKind::TupleStruct(qpath, pats, ddpos); @@ -53,7 +53,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself, path, ParamMode::Optional, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path), ); break hir::PatKind::Path(qpath); } @@ -63,7 +63,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself, path, ParamMode::Optional, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path), ); let fs = self.arena.alloc_from_iter(fields.iter().map(|f| { diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index de1467b1b07d..a3d864023a9f 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -22,7 +22,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { qself: &Option, p: &Path, param_mode: ParamMode, - itctx: ImplTraitContext, + itctx: &mut ImplTraitContext, ) -> hir::QPath<'hir> { let qself_position = qself.as_ref().map(|q| q.position); let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx)); @@ -156,7 +156,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { segment, param_mode, ParenthesizedGenericArgs::Err, - ImplTraitContext::Disallowed(ImplTraitPosition::Path), + &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path), ) })), span: self.lower_span(p.span), @@ -180,7 +180,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { segment: &PathSegment, param_mode: ParamMode, parenthesized_generic_args: ParenthesizedGenericArgs, - itctx: ImplTraitContext, + itctx: &mut ImplTraitContext, ) -> hir::PathSegment<'hir> { debug!("path_span: {:?}, lower_path_segment(segment: {:?})", path_span, segment,); let (mut generic_args, infer_args) = if let Some(ref generic_args) = segment.args { @@ -316,7 +316,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, data: &AngleBracketedArgs, param_mode: ParamMode, - itctx: ImplTraitContext, + itctx: &mut ImplTraitContext, ) -> (GenericArgsCtor<'hir>, bool) { let has_non_lt_args = data.args.iter().any(|arg| match arg { AngleBracketedArg::Arg(ast::GenericArg::Lifetime(_)) @@ -350,12 +350,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // we generally don't permit such things (see #51008). let ParenthesizedArgs { span, inputs, inputs_span, output } = data; let inputs = self.arena.alloc_from_iter(inputs.iter().map(|ty| { - self.lower_ty_direct(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam)) + self.lower_ty_direct( + ty, + &mut ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam), + ) })); let output_ty = match output { - FnRetTy::Ty(ty) => { - self.lower_ty(&ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)) - } + FnRetTy::Ty(ty) => self + .lower_ty(&ty, &mut ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)), FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])), }; let args = smallvec![GenericArg::Type(self.arena.alloc(self.ty_tup(*inputs_span, inputs)))]; From 0126f7f3a924da2da84d9645cf02d90e9aae214d Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 6 Sep 2022 14:23:03 -0400 Subject: [PATCH 4258/5092] Allow lint passes to be bound by `TyCtxt` --- compiler/rustc_lint/src/context.rs | 28 +- compiler/rustc_lint/src/late.rs | 15 +- compiler/rustc_lint/src/lib.rs | 43 +- compiler/rustc_lint/src/passes.rs | 2 +- .../auxiliary/issue-40001-plugin.rs | 2 +- .../auxiliary/lint-for-crate-rpass.rs | 6 +- .../ui-fulldeps/auxiliary/lint-for-crate.rs | 2 +- .../auxiliary/lint-group-plugin-test.rs | 2 +- src/tools/clippy/clippy_dev/src/new_lint.rs | 6 +- src/tools/clippy/clippy_lints/src/lib.rs | 414 +++++++++--------- 10 files changed, 274 insertions(+), 246 deletions(-) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 9a163cf207e9..7ca6ec5d9623 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -50,6 +50,10 @@ use std::cell::Cell; use std::iter; use std::slice; +type EarlyLintPassFactory = dyn Fn() -> EarlyLintPassObject + sync::Send + sync::Sync; +type LateLintPassFactory = + dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::Send + sync::Sync; + /// Information about the registered lints. /// /// This is basically the subset of `Context` that we can @@ -64,11 +68,11 @@ pub struct LintStore { /// interior mutability, we don't enforce this (and lints should, in theory, /// be compatible with being constructed more than once, though not /// necessarily in a sane manner. This is safe though.) - pub pre_expansion_passes: Vec EarlyLintPassObject + sync::Send + sync::Sync>>, - pub early_passes: Vec EarlyLintPassObject + sync::Send + sync::Sync>>, - pub late_passes: Vec LateLintPassObject + sync::Send + sync::Sync>>, + pub pre_expansion_passes: Vec>, + pub early_passes: Vec>, + pub late_passes: Vec>, /// This is unique in that we construct them per-module, so not once. - pub late_module_passes: Vec LateLintPassObject + sync::Send + sync::Sync>>, + pub late_module_passes: Vec>, /// Lints indexed by name. by_name: FxHashMap, @@ -186,14 +190,20 @@ impl LintStore { pub fn register_late_pass( &mut self, - pass: impl Fn() -> LateLintPassObject + 'static + sync::Send + sync::Sync, + pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + + 'static + + sync::Send + + sync::Sync, ) { self.late_passes.push(Box::new(pass)); } pub fn register_late_mod_pass( &mut self, - pass: impl Fn() -> LateLintPassObject + 'static + sync::Send + sync::Sync, + pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + + 'static + + sync::Send + + sync::Sync, ) { self.late_module_passes.push(Box::new(pass)); } @@ -558,7 +568,7 @@ pub trait LintPassObject: Sized {} impl LintPassObject for EarlyLintPassObject {} -impl LintPassObject for LateLintPassObject {} +impl LintPassObject for LateLintPassObject<'_> {} pub trait LintContext: Sized { type PassObject: LintPassObject; @@ -949,8 +959,8 @@ impl<'a> EarlyContext<'a> { } } -impl LintContext for LateContext<'_> { - type PassObject = LateLintPassObject; +impl<'tcx> LintContext for LateContext<'tcx> { + type PassObject = LateLintPassObject<'tcx>; /// Gets the overall compiler `Session` object. fn sess(&self) -> &Session { diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index 8a336844dc2f..66dc3ed59a38 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -306,12 +306,12 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas } } -struct LateLintPassObjects<'a> { - lints: &'a mut [LateLintPassObject], +struct LateLintPassObjects<'a, 'tcx> { + lints: &'a mut [LateLintPassObject<'tcx>], } #[allow(rustc::lint_pass_impl_without_macro)] -impl LintPass for LateLintPassObjects<'_> { +impl LintPass for LateLintPassObjects<'_, '_> { fn name(&self) -> &'static str { panic!() } @@ -329,7 +329,7 @@ macro_rules! expand_late_lint_pass_impl_methods { macro_rules! late_lint_pass_impl { ([], [$hir:tt], $methods:tt) => { - impl<$hir> LateLintPass<$hir> for LateLintPassObjects<'_> { + impl<$hir> LateLintPass<$hir> for LateLintPassObjects<'_, $hir> { expand_late_lint_pass_impl_methods!([$hir], $methods); } }; @@ -382,7 +382,7 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx>>( late_lint_mod_pass(tcx, module_def_id, builtin_lints); let mut passes: Vec<_> = - unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)()).collect(); + unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)(tcx)).collect(); if !passes.is_empty() { late_lint_mod_pass(tcx, module_def_id, LateLintPassObjects { lints: &mut passes[..] }); @@ -418,7 +418,8 @@ fn late_lint_pass_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, pass: T) } fn late_lint_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, builtin_lints: T) { - let mut passes = unerased_lint_store(tcx).late_passes.iter().map(|p| (p)()).collect::>(); + let mut passes = + unerased_lint_store(tcx).late_passes.iter().map(|p| (p)(tcx)).collect::>(); if !tcx.sess.opts.unstable_opts.no_interleave_lints { if !passes.is_empty() { @@ -434,7 +435,7 @@ fn late_lint_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, builtin_lints } let mut passes: Vec<_> = - unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)()).collect(); + unerased_lint_store(tcx).late_module_passes.iter().map(|pass| (pass)(tcx)).collect(); for pass in &mut passes { tcx.sess.prof.extra_verbose_generic_activity("run_late_module_lint", pass.name()).run( diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 370a75cf7006..e0e6f1a8c080 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -260,26 +260,41 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { ) } - macro_rules! register_pass { + macro_rules! register_early_pass { ($method:ident, $ty:ident, $constructor:expr) => { store.register_lints(&$ty::get_lints()); store.$method(|| Box::new($constructor)); }; } - macro_rules! register_passes { + macro_rules! register_late_pass { + ($method:ident, $ty:ident, $constructor:expr) => { + store.register_lints(&$ty::get_lints()); + store.$method(|_| Box::new($constructor)); + }; + } + + macro_rules! register_early_passes { ($method:ident, [$($passes:ident: $constructor:expr,)*]) => ( $( - register_pass!($method, $passes, $constructor); + register_early_pass!($method, $passes, $constructor); + )* + ) + } + + macro_rules! register_late_passes { + ($method:ident, [$($passes:ident: $constructor:expr,)*]) => ( + $( + register_late_pass!($method, $passes, $constructor); )* ) } if no_interleave_lints { - pre_expansion_lint_passes!(register_passes, register_pre_expansion_pass); - early_lint_passes!(register_passes, register_early_pass); - late_lint_passes!(register_passes, register_late_pass); - late_lint_mod_passes!(register_passes, register_late_mod_pass); + pre_expansion_lint_passes!(register_early_passes, register_pre_expansion_pass); + early_lint_passes!(register_early_passes, register_early_pass); + late_lint_passes!(register_late_passes, register_late_pass); + late_lint_mod_passes!(register_late_passes, register_late_mod_pass); } else { store.register_lints(&BuiltinCombinedPreExpansionLintPass::get_lints()); store.register_lints(&BuiltinCombinedEarlyLintPass::get_lints()); @@ -510,19 +525,19 @@ fn register_internals(store: &mut LintStore) { store.register_lints(&LintPassImpl::get_lints()); store.register_early_pass(|| Box::new(LintPassImpl)); store.register_lints(&DefaultHashTypes::get_lints()); - store.register_late_pass(|| Box::new(DefaultHashTypes)); + store.register_late_pass(|_| Box::new(DefaultHashTypes)); store.register_lints(&QueryStability::get_lints()); - store.register_late_pass(|| Box::new(QueryStability)); + store.register_late_pass(|_| Box::new(QueryStability)); store.register_lints(&ExistingDocKeyword::get_lints()); - store.register_late_pass(|| Box::new(ExistingDocKeyword)); + store.register_late_pass(|_| Box::new(ExistingDocKeyword)); store.register_lints(&TyTyKind::get_lints()); - store.register_late_pass(|| Box::new(TyTyKind)); + store.register_late_pass(|_| Box::new(TyTyKind)); store.register_lints(&Diagnostics::get_lints()); - store.register_late_pass(|| Box::new(Diagnostics)); + store.register_late_pass(|_| Box::new(Diagnostics)); store.register_lints(&BadOptAccess::get_lints()); - store.register_late_pass(|| Box::new(BadOptAccess)); + store.register_late_pass(|_| Box::new(BadOptAccess)); store.register_lints(&PassByValue::get_lints()); - store.register_late_pass(|| Box::new(PassByValue)); + store.register_late_pass(|_| Box::new(PassByValue)); // FIXME(davidtwco): deliberately do not include `UNTRANSLATABLE_DIAGNOSTIC` and // `DIAGNOSTIC_OUTSIDE_OF_IMPL` here because `-Wrustc::internal` is provided to every crate and // these lints will trigger all of the time - change this once migration to diagnostic structs diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index 90c554c2e040..666e61b85acf 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -244,4 +244,4 @@ macro_rules! declare_combined_early_lint_pass { /// A lint pass boxed up as a trait object. pub type EarlyLintPassObject = Box; -pub type LateLintPassObject = Box LateLintPass<'tcx> + sync::Send + 'static>; +pub type LateLintPassObject<'tcx> = Box + sync::Send + 'tcx>; diff --git a/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs b/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs index 802b867a301a..03ad3ca82614 100644 --- a/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs +++ b/src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs @@ -21,7 +21,7 @@ use rustc_span::source_map; #[no_mangle] fn __rustc_plugin_registrar(reg: &mut Registry) { reg.lint_store.register_lints(&[&MISSING_ALLOWED_ATTR]); - reg.lint_store.register_late_pass(|| Box::new(MissingAllowedAttrPass)); + reg.lint_store.register_late_pass(|_| Box::new(MissingAllowedAttrPass)); } declare_lint! { diff --git a/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs b/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs index bc153faa8925..a3b570ad8c40 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs @@ -74,7 +74,7 @@ fn __rustc_plugin_registrar(reg: &mut Registry) { &CRATE_NOT_GREY, &CRATE_NOT_GREEN, ]); - reg.lint_store.register_late_pass(|| Box::new(PassOkay)); - reg.lint_store.register_late_pass(|| Box::new(PassRedBlue)); - reg.lint_store.register_late_pass(|| Box::new(PassGreyGreen)); + reg.lint_store.register_late_pass(|_| Box::new(PassOkay)); + reg.lint_store.register_late_pass(|_| Box::new(PassRedBlue)); + reg.lint_store.register_late_pass(|_| Box::new(PassGreyGreen)); } diff --git a/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs index 29d0abfbe538..0b1534939b77 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs @@ -39,5 +39,5 @@ impl<'tcx> LateLintPass<'tcx> for Pass { #[no_mangle] fn __rustc_plugin_registrar(reg: &mut Registry) { reg.lint_store.register_lints(&[&CRATE_NOT_OKAY]); - reg.lint_store.register_late_pass(|| Box::new(Pass)); + reg.lint_store.register_late_pass(|_| Box::new(Pass)); } diff --git a/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs b/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs index 691cfb97d921..2d41b5f30e97 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs @@ -36,7 +36,7 @@ impl<'tcx> LateLintPass<'tcx> for Pass { #[no_mangle] fn __rustc_plugin_registrar(reg: &mut Registry) { reg.lint_store.register_lints(&[&TEST_LINT, &PLEASE_LINT]); - reg.lint_store.register_late_pass(|| Box::new(Pass)); + reg.lint_store.register_late_pass(|_| Box::new(Pass)); reg.lint_store.register_group( true, "lint_me", diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs index be05e67d724d..331b76484b8a 100644 --- a/src/tools/clippy/clippy_dev/src/new_lint.rs +++ b/src/tools/clippy/clippy_dev/src/new_lint.rs @@ -120,15 +120,17 @@ fn add_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> { let new_lint = if enable_msrv { format!( - "store.register_{lint_pass}_pass(move || Box::new({module_name}::{camel_name}::new(msrv)));\n ", + "store.register_{lint_pass}_pass(move |{ctor_arg}| Box::new({module_name}::{camel_name}::new(msrv)));\n ", lint_pass = lint.pass, + ctor_arg = if lint.pass == "late" { "_" } else { "" }, module_name = lint.name, camel_name = to_camel_case(lint.name), ) } else { format!( - "store.register_{lint_pass}_pass(|| Box::new({module_name}::{camel_name}));\n ", + "store.register_{lint_pass}_pass(|{ctor_arg}| Box::new({module_name}::{camel_name}));\n ", lint_pass = lint.pass, + ctor_arg = if lint.pass == "late" { "_" } else { "" }, module_name = lint.name, camel_name = to_camel_case(lint.name), ) diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index dfdaf90f09f4..c70aa79ac8dc 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -523,7 +523,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: #[cfg(feature = "internal")] { if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) { - store.register_late_pass(|| Box::new(utils::internal_lints::metadata_collector::MetadataCollector::new())); + store.register_late_pass(|_| Box::new(utils::internal_lints::metadata_collector::MetadataCollector::new())); return; } } @@ -533,69 +533,69 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: { store.register_early_pass(|| Box::new(utils::internal_lints::ClippyLintsInternal)); store.register_early_pass(|| Box::new(utils::internal_lints::ProduceIce)); - store.register_late_pass(|| Box::new(utils::internal_lints::CollapsibleCalls)); - store.register_late_pass(|| Box::new(utils::internal_lints::CompilerLintFunctions::new())); - store.register_late_pass(|| Box::new(utils::internal_lints::IfChainStyle)); - store.register_late_pass(|| Box::new(utils::internal_lints::InvalidPaths)); - store.register_late_pass(|| Box::new(utils::internal_lints::InterningDefinedSymbol::default())); - store.register_late_pass(|| Box::new(utils::internal_lints::LintWithoutLintPass::default())); - store.register_late_pass(|| Box::new(utils::internal_lints::MatchTypeOnDiagItem)); - store.register_late_pass(|| Box::new(utils::internal_lints::OuterExpnDataPass)); - store.register_late_pass(|| Box::new(utils::internal_lints::MsrvAttrImpl)); + store.register_late_pass(|_| Box::new(utils::internal_lints::CollapsibleCalls)); + store.register_late_pass(|_| Box::new(utils::internal_lints::CompilerLintFunctions::new())); + store.register_late_pass(|_| Box::new(utils::internal_lints::IfChainStyle)); + store.register_late_pass(|_| Box::new(utils::internal_lints::InvalidPaths)); + store.register_late_pass(|_| Box::new(utils::internal_lints::InterningDefinedSymbol::default())); + store.register_late_pass(|_| Box::new(utils::internal_lints::LintWithoutLintPass::default())); + store.register_late_pass(|_| Box::new(utils::internal_lints::MatchTypeOnDiagItem)); + store.register_late_pass(|_| Box::new(utils::internal_lints::OuterExpnDataPass)); + store.register_late_pass(|_| Box::new(utils::internal_lints::MsrvAttrImpl)); } let arithmetic_allowed = conf.arithmetic_allowed.clone(); - store.register_late_pass(move || Box::new(operators::arithmetic::Arithmetic::new(arithmetic_allowed.clone()))); - store.register_late_pass(|| Box::new(utils::dump_hir::DumpHir)); - store.register_late_pass(|| Box::new(utils::author::Author)); + store.register_late_pass(move |_| Box::new(operators::arithmetic::Arithmetic::new(arithmetic_allowed.clone()))); + store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir)); + store.register_late_pass(|_| Box::new(utils::author::Author)); let await_holding_invalid_types = conf.await_holding_invalid_types.clone(); - store.register_late_pass(move || { + store.register_late_pass(move |_| { Box::new(await_holding_invalid::AwaitHolding::new( await_holding_invalid_types.clone(), )) }); - store.register_late_pass(|| Box::new(serde_api::SerdeApi)); + store.register_late_pass(|_| Box::new(serde_api::SerdeApi)); let vec_box_size_threshold = conf.vec_box_size_threshold; let type_complexity_threshold = conf.type_complexity_threshold; let avoid_breaking_exported_api = conf.avoid_breaking_exported_api; - store.register_late_pass(move || { + store.register_late_pass(move |_| { Box::new(types::Types::new( vec_box_size_threshold, type_complexity_threshold, avoid_breaking_exported_api, )) }); - store.register_late_pass(|| Box::new(booleans::NonminimalBool)); - store.register_late_pass(|| Box::new(enum_clike::UnportableVariant)); - store.register_late_pass(|| Box::new(float_literal::FloatLiteral)); - store.register_late_pass(|| Box::new(ptr::Ptr)); - store.register_late_pass(|| Box::new(needless_bool::NeedlessBool)); - store.register_late_pass(|| Box::new(needless_bool::BoolComparison)); - store.register_late_pass(|| Box::new(needless_for_each::NeedlessForEach)); - store.register_late_pass(|| Box::new(misc::MiscLints)); - store.register_late_pass(|| Box::new(eta_reduction::EtaReduction)); - store.register_late_pass(|| Box::new(mut_mut::MutMut)); - store.register_late_pass(|| Box::new(mut_reference::UnnecessaryMutPassed)); - store.register_late_pass(|| Box::new(len_zero::LenZero)); - store.register_late_pass(|| Box::new(attrs::Attributes)); - store.register_late_pass(|| Box::new(blocks_in_if_conditions::BlocksInIfConditions)); - store.register_late_pass(|| Box::new(unicode::Unicode)); - store.register_late_pass(|| Box::new(uninit_vec::UninitVec)); - store.register_late_pass(|| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd)); - store.register_late_pass(|| Box::new(strings::StringAdd)); - store.register_late_pass(|| Box::new(implicit_return::ImplicitReturn)); - store.register_late_pass(|| Box::new(implicit_saturating_sub::ImplicitSaturatingSub)); - store.register_late_pass(|| Box::new(default_numeric_fallback::DefaultNumericFallback)); - store.register_late_pass(|| Box::new(inconsistent_struct_constructor::InconsistentStructConstructor)); - store.register_late_pass(|| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions)); + store.register_late_pass(|_| Box::new(booleans::NonminimalBool)); + store.register_late_pass(|_| Box::new(enum_clike::UnportableVariant)); + store.register_late_pass(|_| Box::new(float_literal::FloatLiteral)); + store.register_late_pass(|_| Box::new(ptr::Ptr)); + store.register_late_pass(|_| Box::new(needless_bool::NeedlessBool)); + store.register_late_pass(|_| Box::new(needless_bool::BoolComparison)); + store.register_late_pass(|_| Box::new(needless_for_each::NeedlessForEach)); + store.register_late_pass(|_| Box::new(misc::MiscLints)); + store.register_late_pass(|_| Box::new(eta_reduction::EtaReduction)); + store.register_late_pass(|_| Box::new(mut_mut::MutMut)); + store.register_late_pass(|_| Box::new(mut_reference::UnnecessaryMutPassed)); + store.register_late_pass(|_| Box::new(len_zero::LenZero)); + store.register_late_pass(|_| Box::new(attrs::Attributes)); + store.register_late_pass(|_| Box::new(blocks_in_if_conditions::BlocksInIfConditions)); + store.register_late_pass(|_| Box::new(unicode::Unicode)); + store.register_late_pass(|_| Box::new(uninit_vec::UninitVec)); + store.register_late_pass(|_| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd)); + store.register_late_pass(|_| Box::new(strings::StringAdd)); + store.register_late_pass(|_| Box::new(implicit_return::ImplicitReturn)); + store.register_late_pass(|_| Box::new(implicit_saturating_sub::ImplicitSaturatingSub)); + store.register_late_pass(|_| Box::new(default_numeric_fallback::DefaultNumericFallback)); + store.register_late_pass(|_| Box::new(inconsistent_struct_constructor::InconsistentStructConstructor)); + store.register_late_pass(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions)); store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports)); let msrv = read_msrv(conf, sess); let avoid_breaking_exported_api = conf.avoid_breaking_exported_api; let allow_expect_in_tests = conf.allow_expect_in_tests; let allow_unwrap_in_tests = conf.allow_unwrap_in_tests; - store.register_late_pass(move || Box::new(approx_const::ApproxConstant::new(msrv))); - store.register_late_pass(move || { + store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(msrv))); + store.register_late_pass(move |_| { Box::new(methods::Methods::new( avoid_breaking_exported_api, msrv, @@ -603,74 +603,74 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: allow_unwrap_in_tests, )) }); - store.register_late_pass(move || Box::new(matches::Matches::new(msrv))); + store.register_late_pass(move |_| Box::new(matches::Matches::new(msrv))); store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(msrv))); - store.register_late_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv))); - store.register_late_pass(move || Box::new(manual_strip::ManualStrip::new(msrv))); + store.register_late_pass(move |_| Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv))); + store.register_late_pass(move |_| Box::new(manual_strip::ManualStrip::new(msrv))); store.register_early_pass(move || Box::new(redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv))); store.register_early_pass(move || Box::new(redundant_field_names::RedundantFieldNames::new(msrv))); - store.register_late_pass(move || Box::new(checked_conversions::CheckedConversions::new(msrv))); - store.register_late_pass(move || Box::new(mem_replace::MemReplace::new(msrv))); - store.register_late_pass(move || Box::new(ranges::Ranges::new(msrv))); - store.register_late_pass(move || Box::new(from_over_into::FromOverInto::new(msrv))); - store.register_late_pass(move || Box::new(use_self::UseSelf::new(msrv))); - store.register_late_pass(move || Box::new(missing_const_for_fn::MissingConstForFn::new(msrv))); - store.register_late_pass(move || Box::new(needless_question_mark::NeedlessQuestionMark)); - store.register_late_pass(move || Box::new(casts::Casts::new(msrv))); + store.register_late_pass(move |_| Box::new(checked_conversions::CheckedConversions::new(msrv))); + store.register_late_pass(move |_| Box::new(mem_replace::MemReplace::new(msrv))); + store.register_late_pass(move |_| Box::new(ranges::Ranges::new(msrv))); + store.register_late_pass(move |_| Box::new(from_over_into::FromOverInto::new(msrv))); + store.register_late_pass(move |_| Box::new(use_self::UseSelf::new(msrv))); + store.register_late_pass(move |_| Box::new(missing_const_for_fn::MissingConstForFn::new(msrv))); + store.register_late_pass(move |_| Box::new(needless_question_mark::NeedlessQuestionMark)); + store.register_late_pass(move |_| Box::new(casts::Casts::new(msrv))); store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv))); - store.register_late_pass(|| Box::new(size_of_in_element_count::SizeOfInElementCount)); - store.register_late_pass(|| Box::new(same_name_method::SameNameMethod)); + store.register_late_pass(|_| Box::new(size_of_in_element_count::SizeOfInElementCount)); + store.register_late_pass(|_| Box::new(same_name_method::SameNameMethod)); let max_suggested_slice_pattern_length = conf.max_suggested_slice_pattern_length; - store.register_late_pass(move || { + store.register_late_pass(move |_| { Box::new(index_refutable_slice::IndexRefutableSlice::new( max_suggested_slice_pattern_length, msrv, )) }); - store.register_late_pass(|| Box::new(shadow::Shadow::default())); - store.register_late_pass(|| Box::new(unit_types::UnitTypes)); - store.register_late_pass(|| Box::new(loops::Loops)); - store.register_late_pass(|| Box::new(main_recursion::MainRecursion::default())); - store.register_late_pass(|| Box::new(lifetimes::Lifetimes)); - store.register_late_pass(|| Box::new(entry::HashMapPass)); - store.register_late_pass(|| Box::new(minmax::MinMaxPass)); - store.register_late_pass(|| Box::new(zero_div_zero::ZeroDiv)); - store.register_late_pass(|| Box::new(mutex_atomic::Mutex)); - store.register_late_pass(|| Box::new(needless_update::NeedlessUpdate)); - store.register_late_pass(|| Box::new(needless_borrowed_ref::NeedlessBorrowedRef)); - store.register_late_pass(|| Box::new(borrow_deref_ref::BorrowDerefRef)); - store.register_late_pass(|| Box::new(no_effect::NoEffect)); - store.register_late_pass(|| Box::new(temporary_assignment::TemporaryAssignment)); - store.register_late_pass(move || Box::new(transmute::Transmute::new(msrv))); + store.register_late_pass(|_| Box::new(shadow::Shadow::default())); + store.register_late_pass(|_| Box::new(unit_types::UnitTypes)); + store.register_late_pass(|_| Box::new(loops::Loops)); + store.register_late_pass(|_| Box::new(main_recursion::MainRecursion::default())); + store.register_late_pass(|_| Box::new(lifetimes::Lifetimes)); + store.register_late_pass(|_| Box::new(entry::HashMapPass)); + store.register_late_pass(|_| Box::new(minmax::MinMaxPass)); + store.register_late_pass(|_| Box::new(zero_div_zero::ZeroDiv)); + store.register_late_pass(|_| Box::new(mutex_atomic::Mutex)); + store.register_late_pass(|_| Box::new(needless_update::NeedlessUpdate)); + store.register_late_pass(|_| Box::new(needless_borrowed_ref::NeedlessBorrowedRef)); + store.register_late_pass(|_| Box::new(borrow_deref_ref::BorrowDerefRef)); + store.register_late_pass(|_| Box::new(no_effect::NoEffect)); + store.register_late_pass(|_| Box::new(temporary_assignment::TemporaryAssignment)); + store.register_late_pass(move |_| Box::new(transmute::Transmute::new(msrv))); let cognitive_complexity_threshold = conf.cognitive_complexity_threshold; - store.register_late_pass(move || { + store.register_late_pass(move |_| { Box::new(cognitive_complexity::CognitiveComplexity::new( cognitive_complexity_threshold, )) }); let too_large_for_stack = conf.too_large_for_stack; - store.register_late_pass(move || Box::new(escape::BoxedLocal { too_large_for_stack })); - store.register_late_pass(move || Box::new(vec::UselessVec { too_large_for_stack })); - store.register_late_pass(|| Box::new(panic_unimplemented::PanicUnimplemented)); - store.register_late_pass(|| Box::new(strings::StringLitAsBytes)); - store.register_late_pass(|| Box::new(derive::Derive)); - store.register_late_pass(|| Box::new(derivable_impls::DerivableImpls)); - store.register_late_pass(|| Box::new(drop_forget_ref::DropForgetRef)); - store.register_late_pass(|| Box::new(empty_enum::EmptyEnum)); - store.register_late_pass(|| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons)); - store.register_late_pass(|| Box::new(regex::Regex)); - store.register_late_pass(|| Box::new(copies::CopyAndPaste)); - store.register_late_pass(|| Box::new(copy_iterator::CopyIterator)); - store.register_late_pass(|| Box::new(format::UselessFormat)); - store.register_late_pass(|| Box::new(swap::Swap)); - store.register_late_pass(|| Box::new(overflow_check_conditional::OverflowCheckConditional)); - store.register_late_pass(|| Box::new(new_without_default::NewWithoutDefault::default())); + store.register_late_pass(move |_| Box::new(escape::BoxedLocal { too_large_for_stack })); + store.register_late_pass(move |_| Box::new(vec::UselessVec { too_large_for_stack })); + store.register_late_pass(|_| Box::new(panic_unimplemented::PanicUnimplemented)); + store.register_late_pass(|_| Box::new(strings::StringLitAsBytes)); + store.register_late_pass(|_| Box::new(derive::Derive)); + store.register_late_pass(|_| Box::new(derivable_impls::DerivableImpls)); + store.register_late_pass(|_| Box::new(drop_forget_ref::DropForgetRef)); + store.register_late_pass(|_| Box::new(empty_enum::EmptyEnum)); + store.register_late_pass(|_| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons)); + store.register_late_pass(|_| Box::new(regex::Regex)); + store.register_late_pass(|_| Box::new(copies::CopyAndPaste)); + store.register_late_pass(|_| Box::new(copy_iterator::CopyIterator)); + store.register_late_pass(|_| Box::new(format::UselessFormat)); + store.register_late_pass(|_| Box::new(swap::Swap)); + store.register_late_pass(|_| Box::new(overflow_check_conditional::OverflowCheckConditional)); + store.register_late_pass(|_| Box::new(new_without_default::NewWithoutDefault::default())); let disallowed_names = conf.disallowed_names.iter().cloned().collect::>(); - store.register_late_pass(move || Box::new(disallowed_names::DisallowedNames::new(disallowed_names.clone()))); + store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(disallowed_names.clone()))); let too_many_arguments_threshold = conf.too_many_arguments_threshold; let too_many_lines_threshold = conf.too_many_lines_threshold; let large_error_threshold = conf.large_error_threshold; - store.register_late_pass(move || { + store.register_late_pass(move |_| { Box::new(functions::Functions::new( too_many_arguments_threshold, too_many_lines_threshold, @@ -678,73 +678,73 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: )) }); let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::>(); - store.register_late_pass(move || Box::new(doc::DocMarkdown::new(doc_valid_idents.clone()))); - store.register_late_pass(|| Box::new(neg_multiply::NegMultiply)); - store.register_late_pass(|| Box::new(mem_forget::MemForget)); - store.register_late_pass(|| Box::new(let_if_seq::LetIfSeq)); - store.register_late_pass(|| Box::new(mixed_read_write_in_expression::EvalOrderDependence)); - store.register_late_pass(|| Box::new(missing_doc::MissingDoc::new())); - store.register_late_pass(|| Box::new(missing_inline::MissingInline)); - store.register_late_pass(move || Box::new(exhaustive_items::ExhaustiveItems)); - store.register_late_pass(|| Box::new(match_result_ok::MatchResultOk)); - store.register_late_pass(|| Box::new(partialeq_ne_impl::PartialEqNeImpl)); - store.register_late_pass(|| Box::new(unused_io_amount::UnusedIoAmount)); + store.register_late_pass(move |_| Box::new(doc::DocMarkdown::new(doc_valid_idents.clone()))); + store.register_late_pass(|_| Box::new(neg_multiply::NegMultiply)); + store.register_late_pass(|_| Box::new(mem_forget::MemForget)); + store.register_late_pass(|_| Box::new(let_if_seq::LetIfSeq)); + store.register_late_pass(|_| Box::new(mixed_read_write_in_expression::EvalOrderDependence)); + store.register_late_pass(|_| Box::new(missing_doc::MissingDoc::new())); + store.register_late_pass(|_| Box::new(missing_inline::MissingInline)); + store.register_late_pass(move |_| Box::new(exhaustive_items::ExhaustiveItems)); + store.register_late_pass(|_| Box::new(match_result_ok::MatchResultOk)); + store.register_late_pass(|_| Box::new(partialeq_ne_impl::PartialEqNeImpl)); + store.register_late_pass(|_| Box::new(unused_io_amount::UnusedIoAmount)); let enum_variant_size_threshold = conf.enum_variant_size_threshold; - store.register_late_pass(move || Box::new(large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold))); - store.register_late_pass(|| Box::new(explicit_write::ExplicitWrite)); - store.register_late_pass(|| Box::new(needless_pass_by_value::NeedlessPassByValue)); + store.register_late_pass(move |_| Box::new(large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold))); + store.register_late_pass(|_| Box::new(explicit_write::ExplicitWrite)); + store.register_late_pass(|_| Box::new(needless_pass_by_value::NeedlessPassByValue)); let pass_by_ref_or_value = pass_by_ref_or_value::PassByRefOrValue::new( conf.trivial_copy_size_limit, conf.pass_by_value_size_limit, conf.avoid_breaking_exported_api, &sess.target, ); - store.register_late_pass(move || Box::new(pass_by_ref_or_value)); - store.register_late_pass(|| Box::new(ref_option_ref::RefOptionRef)); - store.register_late_pass(|| Box::new(infinite_iter::InfiniteIter)); - store.register_late_pass(|| Box::new(inline_fn_without_body::InlineFnWithoutBody)); - store.register_late_pass(|| Box::new(useless_conversion::UselessConversion::default())); - store.register_late_pass(|| Box::new(implicit_hasher::ImplicitHasher)); - store.register_late_pass(|| Box::new(fallible_impl_from::FallibleImplFrom)); - store.register_late_pass(|| Box::new(question_mark::QuestionMark)); + store.register_late_pass(move |_| Box::new(pass_by_ref_or_value)); + store.register_late_pass(|_| Box::new(ref_option_ref::RefOptionRef)); + store.register_late_pass(|_| Box::new(infinite_iter::InfiniteIter)); + store.register_late_pass(|_| Box::new(inline_fn_without_body::InlineFnWithoutBody)); + store.register_late_pass(|_| Box::new(useless_conversion::UselessConversion::default())); + store.register_late_pass(|_| Box::new(implicit_hasher::ImplicitHasher)); + store.register_late_pass(|_| Box::new(fallible_impl_from::FallibleImplFrom)); + store.register_late_pass(|_| Box::new(question_mark::QuestionMark)); store.register_early_pass(|| Box::new(suspicious_operation_groupings::SuspiciousOperationGroupings)); - store.register_late_pass(|| Box::new(suspicious_trait_impl::SuspiciousImpl)); - store.register_late_pass(|| Box::new(map_unit_fn::MapUnit)); - store.register_late_pass(|| Box::new(inherent_impl::MultipleInherentImpl)); - store.register_late_pass(|| Box::new(neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd)); - store.register_late_pass(|| Box::new(unwrap::Unwrap)); - store.register_late_pass(|| Box::new(indexing_slicing::IndexingSlicing)); - store.register_late_pass(|| Box::new(non_copy_const::NonCopyConst)); - store.register_late_pass(|| Box::new(ptr_offset_with_cast::PtrOffsetWithCast)); - store.register_late_pass(|| Box::new(redundant_clone::RedundantClone)); - store.register_late_pass(|| Box::new(slow_vector_initialization::SlowVectorInit)); - store.register_late_pass(move || Box::new(unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api))); - store.register_late_pass(|| Box::new(assertions_on_constants::AssertionsOnConstants)); - store.register_late_pass(|| Box::new(assertions_on_result_states::AssertionsOnResultStates)); - store.register_late_pass(|| Box::new(inherent_to_string::InherentToString)); + store.register_late_pass(|_| Box::new(suspicious_trait_impl::SuspiciousImpl)); + store.register_late_pass(|_| Box::new(map_unit_fn::MapUnit)); + store.register_late_pass(|_| Box::new(inherent_impl::MultipleInherentImpl)); + store.register_late_pass(|_| Box::new(neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd)); + store.register_late_pass(|_| Box::new(unwrap::Unwrap)); + store.register_late_pass(|_| Box::new(indexing_slicing::IndexingSlicing)); + store.register_late_pass(|_| Box::new(non_copy_const::NonCopyConst)); + store.register_late_pass(|_| Box::new(ptr_offset_with_cast::PtrOffsetWithCast)); + store.register_late_pass(|_| Box::new(redundant_clone::RedundantClone)); + store.register_late_pass(|_| Box::new(slow_vector_initialization::SlowVectorInit)); + store.register_late_pass(move |_| Box::new(unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api))); + store.register_late_pass(|_| Box::new(assertions_on_constants::AssertionsOnConstants)); + store.register_late_pass(|_| Box::new(assertions_on_result_states::AssertionsOnResultStates)); + store.register_late_pass(|_| Box::new(inherent_to_string::InherentToString)); let max_trait_bounds = conf.max_trait_bounds; - store.register_late_pass(move || Box::new(trait_bounds::TraitBounds::new(max_trait_bounds))); - store.register_late_pass(|| Box::new(comparison_chain::ComparisonChain)); - store.register_late_pass(|| Box::new(mut_key::MutableKeyType)); + store.register_late_pass(move |_| Box::new(trait_bounds::TraitBounds::new(max_trait_bounds))); + store.register_late_pass(|_| Box::new(comparison_chain::ComparisonChain)); + store.register_late_pass(|_| Box::new(mut_key::MutableKeyType)); store.register_early_pass(|| Box::new(reference::DerefAddrOf)); store.register_early_pass(|| Box::new(double_parens::DoubleParens)); - store.register_late_pass(|| Box::new(format_impl::FormatImpl::new())); + store.register_late_pass(|_| Box::new(format_impl::FormatImpl::new())); store.register_early_pass(|| Box::new(unsafe_removed_from_name::UnsafeNameRemoval)); store.register_early_pass(|| Box::new(else_if_without_else::ElseIfWithoutElse)); store.register_early_pass(|| Box::new(int_plus_one::IntPlusOne)); store.register_early_pass(|| Box::new(formatting::Formatting)); store.register_early_pass(|| Box::new(misc_early::MiscEarlyLints)); store.register_early_pass(|| Box::new(redundant_closure_call::RedundantClosureCall)); - store.register_late_pass(|| Box::new(redundant_closure_call::RedundantClosureCall)); + store.register_late_pass(|_| Box::new(redundant_closure_call::RedundantClosureCall)); store.register_early_pass(|| Box::new(unused_unit::UnusedUnit)); - store.register_late_pass(|| Box::new(returns::Return)); + store.register_late_pass(|_| Box::new(returns::Return)); store.register_early_pass(|| Box::new(collapsible_if::CollapsibleIf)); store.register_early_pass(|| Box::new(items_after_statements::ItemsAfterStatements)); store.register_early_pass(|| Box::new(precedence::Precedence)); - store.register_late_pass(|| Box::new(needless_parens_on_range_literals::NeedlessParensOnRangeLiterals)); + store.register_late_pass(|_| Box::new(needless_parens_on_range_literals::NeedlessParensOnRangeLiterals)); store.register_early_pass(|| Box::new(needless_continue::NeedlessContinue)); store.register_early_pass(|| Box::new(redundant_else::RedundantElse)); - store.register_late_pass(|| Box::new(create_dir::CreateDir)); + store.register_late_pass(|_| Box::new(create_dir::CreateDir)); store.register_early_pass(|| Box::new(needless_arbitrary_self_type::NeedlessArbitrarySelfType)); let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions; store.register_early_pass(move || { @@ -759,7 +759,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: )) }); let enum_variant_name_threshold = conf.enum_variant_name_threshold; - store.register_late_pass(move || { + store.register_late_pass(move |_| { Box::new(enum_variants::EnumVariantNames::new( enum_variant_name_threshold, avoid_breaking_exported_api, @@ -767,23 +767,23 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: }); store.register_early_pass(|| Box::new(tabs_in_doc_comments::TabsInDocComments)); let upper_case_acronyms_aggressive = conf.upper_case_acronyms_aggressive; - store.register_late_pass(move || { + store.register_late_pass(move |_| { Box::new(upper_case_acronyms::UpperCaseAcronyms::new( avoid_breaking_exported_api, upper_case_acronyms_aggressive, )) }); - store.register_late_pass(|| Box::new(default::Default::default())); - store.register_late_pass(move || Box::new(unused_self::UnusedSelf::new(avoid_breaking_exported_api))); - store.register_late_pass(|| Box::new(mutable_debug_assertion::DebugAssertWithMutCall)); - store.register_late_pass(|| Box::new(exit::Exit)); - store.register_late_pass(|| Box::new(to_digit_is_some::ToDigitIsSome)); + store.register_late_pass(|_| Box::new(default::Default::default())); + store.register_late_pass(move |_| Box::new(unused_self::UnusedSelf::new(avoid_breaking_exported_api))); + store.register_late_pass(|_| Box::new(mutable_debug_assertion::DebugAssertWithMutCall)); + store.register_late_pass(|_| Box::new(exit::Exit)); + store.register_late_pass(|_| Box::new(to_digit_is_some::ToDigitIsSome)); let array_size_threshold = conf.array_size_threshold; - store.register_late_pass(move || Box::new(large_stack_arrays::LargeStackArrays::new(array_size_threshold))); - store.register_late_pass(move || Box::new(large_const_arrays::LargeConstArrays::new(array_size_threshold))); - store.register_late_pass(|| Box::new(floating_point_arithmetic::FloatingPointArithmetic)); + store.register_late_pass(move |_| Box::new(large_stack_arrays::LargeStackArrays::new(array_size_threshold))); + store.register_late_pass(move |_| Box::new(large_const_arrays::LargeConstArrays::new(array_size_threshold))); + store.register_late_pass(|_| Box::new(floating_point_arithmetic::FloatingPointArithmetic)); store.register_early_pass(|| Box::new(as_conversions::AsConversions)); - store.register_late_pass(|| Box::new(let_underscore::LetUnderscore)); + store.register_late_pass(|_| Box::new(let_underscore::LetUnderscore)); store.register_early_pass(|| Box::new(single_component_path_imports::SingleComponentPathImports)); let max_fn_params_bools = conf.max_fn_params_bools; let max_struct_bools = conf.max_struct_bools; @@ -795,17 +795,17 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: }); store.register_early_pass(|| Box::new(option_env_unwrap::OptionEnvUnwrap)); let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports; - store.register_late_pass(move || Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports))); - store.register_late_pass(|| Box::new(redundant_pub_crate::RedundantPubCrate::default())); - store.register_late_pass(|| Box::new(unnamed_address::UnnamedAddress)); - store.register_late_pass(move || Box::new(dereference::Dereferencing::new(msrv))); - store.register_late_pass(|| Box::new(option_if_let_else::OptionIfLetElse)); - store.register_late_pass(|| Box::new(future_not_send::FutureNotSend)); - store.register_late_pass(|| Box::new(if_let_mutex::IfLetMutex)); - store.register_late_pass(|| Box::new(if_not_else::IfNotElse)); - store.register_late_pass(|| Box::new(equatable_if_let::PatternEquality)); - store.register_late_pass(|| Box::new(manual_async_fn::ManualAsyncFn)); - store.register_late_pass(|| Box::new(panic_in_result_fn::PanicInResultFn)); + store.register_late_pass(move |_| Box::new(wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports))); + store.register_late_pass(|_| Box::new(redundant_pub_crate::RedundantPubCrate::default())); + store.register_late_pass(|_| Box::new(unnamed_address::UnnamedAddress)); + store.register_late_pass(move |_| Box::new(dereference::Dereferencing::new(msrv))); + store.register_late_pass(|_| Box::new(option_if_let_else::OptionIfLetElse)); + store.register_late_pass(|_| Box::new(future_not_send::FutureNotSend)); + store.register_late_pass(|_| Box::new(if_let_mutex::IfLetMutex)); + store.register_late_pass(|_| Box::new(if_not_else::IfNotElse)); + store.register_late_pass(|_| Box::new(equatable_if_let::PatternEquality)); + store.register_late_pass(|_| Box::new(manual_async_fn::ManualAsyncFn)); + store.register_late_pass(|_| Box::new(panic_in_result_fn::PanicInResultFn)); let single_char_binding_names_threshold = conf.single_char_binding_names_threshold; store.register_early_pass(move || { Box::new(non_expressive_names::NonExpressiveNames { @@ -814,92 +814,92 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: }); let macro_matcher = conf.standard_macro_braces.iter().cloned().collect::>(); store.register_early_pass(move || Box::new(nonstandard_macro_braces::MacroBraces::new(¯o_matcher))); - store.register_late_pass(|| Box::new(macro_use::MacroUseImports::default())); - store.register_late_pass(|| Box::new(pattern_type_mismatch::PatternTypeMismatch)); - store.register_late_pass(|| Box::new(unwrap_in_result::UnwrapInResult)); - store.register_late_pass(|| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned)); - store.register_late_pass(|| Box::new(async_yields_async::AsyncYieldsAsync)); + store.register_late_pass(|_| Box::new(macro_use::MacroUseImports::default())); + store.register_late_pass(|_| Box::new(pattern_type_mismatch::PatternTypeMismatch)); + store.register_late_pass(|_| Box::new(unwrap_in_result::UnwrapInResult)); + store.register_late_pass(|_| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned)); + store.register_late_pass(|_| Box::new(async_yields_async::AsyncYieldsAsync)); let disallowed_methods = conf.disallowed_methods.clone(); - store.register_late_pass(move || Box::new(disallowed_methods::DisallowedMethods::new(disallowed_methods.clone()))); + store.register_late_pass(move |_| Box::new(disallowed_methods::DisallowedMethods::new(disallowed_methods.clone()))); store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86AttSyntax)); store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86IntelSyntax)); - store.register_late_pass(|| Box::new(empty_drop::EmptyDrop)); - store.register_late_pass(|| Box::new(strings::StrToString)); - store.register_late_pass(|| Box::new(strings::StringToString)); - store.register_late_pass(|| Box::new(zero_sized_map_values::ZeroSizedMapValues)); - store.register_late_pass(|| Box::new(vec_init_then_push::VecInitThenPush::default())); - store.register_late_pass(|| Box::new(redundant_slicing::RedundantSlicing)); - store.register_late_pass(|| Box::new(from_str_radix_10::FromStrRadix10)); - store.register_late_pass(move || Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv))); - store.register_late_pass(|| Box::new(bool_assert_comparison::BoolAssertComparison)); + store.register_late_pass(|_| Box::new(empty_drop::EmptyDrop)); + store.register_late_pass(|_| Box::new(strings::StrToString)); + store.register_late_pass(|_| Box::new(strings::StringToString)); + store.register_late_pass(|_| Box::new(zero_sized_map_values::ZeroSizedMapValues)); + store.register_late_pass(|_| Box::new(vec_init_then_push::VecInitThenPush::default())); + store.register_late_pass(|_| Box::new(redundant_slicing::RedundantSlicing)); + store.register_late_pass(|_| Box::new(from_str_radix_10::FromStrRadix10)); + store.register_late_pass(move |_| Box::new(if_then_some_else_none::IfThenSomeElseNone::new(msrv))); + store.register_late_pass(|_| Box::new(bool_assert_comparison::BoolAssertComparison)); store.register_early_pass(move || Box::new(module_style::ModStyle)); - store.register_late_pass(|| Box::new(unused_async::UnusedAsync)); + store.register_late_pass(|_| Box::new(unused_async::UnusedAsync)); let disallowed_types = conf.disallowed_types.clone(); - store.register_late_pass(move || Box::new(disallowed_types::DisallowedTypes::new(disallowed_types.clone()))); + store.register_late_pass(move |_| Box::new(disallowed_types::DisallowedTypes::new(disallowed_types.clone()))); let import_renames = conf.enforced_import_renames.clone(); - store.register_late_pass(move || { + store.register_late_pass(move |_| { Box::new(missing_enforced_import_rename::ImportRename::new( import_renames.clone(), )) }); let scripts = conf.allowed_scripts.clone(); store.register_early_pass(move || Box::new(disallowed_script_idents::DisallowedScriptIdents::new(&scripts))); - store.register_late_pass(|| Box::new(strlen_on_c_strings::StrlenOnCStrings)); - store.register_late_pass(move || Box::new(self_named_constructors::SelfNamedConstructors)); - store.register_late_pass(move || Box::new(iter_not_returning_iterator::IterNotReturningIterator)); - store.register_late_pass(move || Box::new(manual_assert::ManualAssert)); + store.register_late_pass(|_| Box::new(strlen_on_c_strings::StrlenOnCStrings)); + store.register_late_pass(move |_| Box::new(self_named_constructors::SelfNamedConstructors)); + store.register_late_pass(move |_| Box::new(iter_not_returning_iterator::IterNotReturningIterator)); + store.register_late_pass(move |_| Box::new(manual_assert::ManualAssert)); let enable_raw_pointer_heuristic_for_send = conf.enable_raw_pointer_heuristic_for_send; - store.register_late_pass(move || { + store.register_late_pass(move |_| { Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new( enable_raw_pointer_heuristic_for_send, )) }); - store.register_late_pass(move || Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks)); - store.register_late_pass(move || Box::new(format_args::FormatArgs)); - store.register_late_pass(|| Box::new(trailing_empty_array::TrailingEmptyArray)); + store.register_late_pass(move |_| Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks)); + store.register_late_pass(move |_| Box::new(format_args::FormatArgs)); + store.register_late_pass(|_| Box::new(trailing_empty_array::TrailingEmptyArray)); store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes)); - store.register_late_pass(|| Box::new(needless_late_init::NeedlessLateInit)); - store.register_late_pass(|| Box::new(return_self_not_must_use::ReturnSelfNotMustUse)); - store.register_late_pass(|| Box::new(init_numbered_fields::NumberedFields)); + store.register_late_pass(|_| Box::new(needless_late_init::NeedlessLateInit)); + store.register_late_pass(|_| Box::new(return_self_not_must_use::ReturnSelfNotMustUse)); + store.register_late_pass(|_| Box::new(init_numbered_fields::NumberedFields)); store.register_early_pass(|| Box::new(single_char_lifetime_names::SingleCharLifetimeNames)); - store.register_late_pass(move || Box::new(manual_bits::ManualBits::new(msrv))); - store.register_late_pass(|| Box::new(default_union_representation::DefaultUnionRepresentation)); + store.register_late_pass(move |_| Box::new(manual_bits::ManualBits::new(msrv))); + store.register_late_pass(|_| Box::new(default_union_representation::DefaultUnionRepresentation)); store.register_early_pass(|| Box::new(doc_link_with_quotes::DocLinkWithQuotes)); - store.register_late_pass(|| Box::new(only_used_in_recursion::OnlyUsedInRecursion::default())); + store.register_late_pass(|_| Box::new(only_used_in_recursion::OnlyUsedInRecursion::default())); let allow_dbg_in_tests = conf.allow_dbg_in_tests; - store.register_late_pass(move || Box::new(dbg_macro::DbgMacro::new(allow_dbg_in_tests))); + store.register_late_pass(move |_| Box::new(dbg_macro::DbgMacro::new(allow_dbg_in_tests))); let cargo_ignore_publish = conf.cargo_ignore_publish; - store.register_late_pass(move || { + store.register_late_pass(move |_| { Box::new(cargo::Cargo { ignore_publish: cargo_ignore_publish, }) }); store.register_early_pass(|| Box::new(crate_in_macro_def::CrateInMacroDef)); store.register_early_pass(|| Box::new(empty_structs_with_brackets::EmptyStructsWithBrackets)); - store.register_late_pass(|| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings)); + store.register_late_pass(|_| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings)); store.register_early_pass(|| Box::new(pub_use::PubUse)); - store.register_late_pass(|| Box::new(format_push_string::FormatPushString)); + store.register_late_pass(|_| Box::new(format_push_string::FormatPushString)); let max_include_file_size = conf.max_include_file_size; - store.register_late_pass(move || Box::new(large_include_file::LargeIncludeFile::new(max_include_file_size))); - store.register_late_pass(|| Box::new(strings::TrimSplitWhitespace)); - store.register_late_pass(|| Box::new(rc_clone_in_vec_init::RcCloneInVecInit)); + store.register_late_pass(move |_| Box::new(large_include_file::LargeIncludeFile::new(max_include_file_size))); + store.register_late_pass(|_| Box::new(strings::TrimSplitWhitespace)); + store.register_late_pass(|_| Box::new(rc_clone_in_vec_init::RcCloneInVecInit)); store.register_early_pass(|| Box::new(duplicate_mod::DuplicateMod::default())); store.register_early_pass(|| Box::new(unused_rounding::UnusedRounding)); store.register_early_pass(move || Box::new(almost_complete_letter_range::AlmostCompleteLetterRange::new(msrv))); - store.register_late_pass(|| Box::new(swap_ptr_to_ref::SwapPtrToRef)); - store.register_late_pass(|| Box::new(mismatching_type_param_order::TypeParamMismatch)); - store.register_late_pass(|| Box::new(read_zero_byte_vec::ReadZeroByteVec)); - store.register_late_pass(|| Box::new(default_instead_of_iter_empty::DefaultIterEmpty)); - store.register_late_pass(move || Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv))); - store.register_late_pass(move || Box::new(manual_retain::ManualRetain::new(msrv))); + store.register_late_pass(|_| Box::new(swap_ptr_to_ref::SwapPtrToRef)); + store.register_late_pass(|_| Box::new(mismatching_type_param_order::TypeParamMismatch)); + store.register_late_pass(|_| Box::new(read_zero_byte_vec::ReadZeroByteVec)); + store.register_late_pass(|_| Box::new(default_instead_of_iter_empty::DefaultIterEmpty)); + store.register_late_pass(move |_| Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv))); + store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(msrv))); let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold; - store.register_late_pass(move || Box::new(operators::Operators::new(verbose_bit_mask_threshold))); - store.register_late_pass(|| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked)); - store.register_late_pass(|| Box::new(std_instead_of_core::StdReexports::default())); - store.register_late_pass(|| Box::new(manual_instant_elapsed::ManualInstantElapsed)); - store.register_late_pass(|| Box::new(partialeq_to_none::PartialeqToNone)); - store.register_late_pass(|| Box::new(manual_string_new::ManualStringNew)); - store.register_late_pass(|| Box::new(unused_peekable::UnusedPeekable)); + store.register_late_pass(move |_| Box::new(operators::Operators::new(verbose_bit_mask_threshold))); + store.register_late_pass(|_| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked)); + store.register_late_pass(|_| Box::new(std_instead_of_core::StdReexports::default())); + store.register_late_pass(|_| Box::new(manual_instant_elapsed::ManualInstantElapsed)); + store.register_late_pass(|_| Box::new(partialeq_to_none::PartialeqToNone)); + store.register_late_pass(|_| Box::new(manual_string_new::ManualStringNew)); + store.register_late_pass(|_| Box::new(unused_peekable::UnusedPeekable)); store.register_early_pass(|| Box::new(multi_assignments::MultiAssignments)); // add lints here, do not remove this comment, it's used in `new_lint` } From b2e4f9dcb32aafcfa1bd2ab6b291ca84b7db0121 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 6 Sep 2022 10:49:34 +0100 Subject: [PATCH 4259/5092] Open a BCrypt algorithm handle --- library/std/src/sys/windows/c.rs | 14 ++++- library/std/src/sys/windows/rand.rs | 82 ++++++++++++++++++++++------- 2 files changed, 76 insertions(+), 20 deletions(-) diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index 78d6ce3eff49..89d0ab59be89 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -66,6 +66,7 @@ pub type LPSYSTEM_INFO = *mut SYSTEM_INFO; pub type LPWSABUF = *mut WSABUF; pub type LPWSAOVERLAPPED = *mut c_void; pub type LPWSAOVERLAPPED_COMPLETION_ROUTINE = *mut c_void; +pub type BCRYPT_ALG_HANDLE = LPVOID; pub type PCONDITION_VARIABLE = *mut CONDITION_VARIABLE; pub type PLARGE_INTEGER = *mut c_longlong; @@ -278,6 +279,7 @@ pub const STATUS_INVALID_PARAMETER: NTSTATUS = 0xc000000d_u32 as _; pub const STATUS_PENDING: NTSTATUS = 0x103 as _; pub const STATUS_END_OF_FILE: NTSTATUS = 0xC0000011_u32 as _; pub const STATUS_NOT_IMPLEMENTED: NTSTATUS = 0xC0000002_u32 as _; +pub const STATUS_NOT_SUPPORTED: NTSTATUS = 0xC00000BB_u32 as _; // Equivalent to the `NT_SUCCESS` C preprocessor macro. // See: https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values @@ -285,7 +287,8 @@ pub fn nt_success(status: NTSTATUS) -> bool { status >= 0 } -pub const BCRYPT_RNG_ALG_HANDLE: usize = 0x81; +// "RNG\0" +pub const BCRYPT_RNG_ALGORITHM: &[u16] = &[b'R' as u16, b'N' as u16, b'G' as u16, 0]; #[repr(C)] pub struct UNICODE_STRING { @@ -1229,11 +1232,18 @@ extern "system" { // >= Vista / Server 2008 // https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom pub fn BCryptGenRandom( - hAlgorithm: LPVOID, + hAlgorithm: BCRYPT_ALG_HANDLE, pBuffer: *mut u8, cbBuffer: ULONG, dwFlags: ULONG, ) -> NTSTATUS; + pub fn BCryptOpenAlgorithmProvider( + phalgorithm: *mut BCRYPT_ALG_HANDLE, + pszAlgId: LPCWSTR, + pszimplementation: LPCWSTR, + dwflags: ULONG, + ) -> NTSTATUS; + pub fn BCryptCloseAlgorithmProvider(hAlgorithm: BCRYPT_ALG_HANDLE, dwFlags: ULONG) -> NTSTATUS; } // Functions that aren't available on every version of Windows that we support, diff --git a/library/std/src/sys/windows/rand.rs b/library/std/src/sys/windows/rand.rs index 8b9697884364..3dfa8dba9774 100644 --- a/library/std/src/sys/windows/rand.rs +++ b/library/std/src/sys/windows/rand.rs @@ -22,7 +22,6 @@ //! [`RtlGenRandom`]: https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom //! [`BCryptGenRandom`]: https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom //! [Pseudo-handle]: https://docs.microsoft.com/en-us/windows/win32/seccng/cng-algorithm-pseudo-handles -use crate::io; use crate::mem; use crate::ptr; use crate::sys::c; @@ -34,35 +33,82 @@ use crate::sys::c; /// [`HashMap`]: crate::collections::HashMap /// [`RandomState`]: crate::collections::hash_map::RandomState pub fn hashmap_random_keys() -> (u64, u64) { - let mut v = (0, 0); - let ret = unsafe { - let size = mem::size_of_val(&v).try_into().unwrap(); - c::BCryptGenRandom( - // BCRYPT_RNG_ALG_HANDLE is only supported in Windows 10+. - // So for Windows 8.1 and Windows 7 we'll need a fallback when this fails. - ptr::invalid_mut(c::BCRYPT_RNG_ALG_HANDLE), - ptr::addr_of_mut!(v).cast(), - size, - 0, - ) - }; - if ret != 0 { fallback_rng() } else { v } + Rng::open().and_then(|rng| rng.gen_random_keys()).unwrap_or_else(fallback_rng) +} + +struct Rng(c::BCRYPT_ALG_HANDLE); +impl Rng { + // Open a handle to the RNG algorithm. + fn open() -> Result { + use crate::sync::atomic::AtomicPtr; + use crate::sync::atomic::Ordering::{Acquire, Release}; + const ERROR_VALUE: c::LPVOID = ptr::invalid_mut(usize::MAX); + + // An atomic is used so we don't need to reopen the handle every time. + static HANDLE: AtomicPtr = AtomicPtr::new(ptr::null_mut()); + + let mut handle = HANDLE.load(Acquire); + // We use a sentinel value to designate an error occurred last time. + if handle == ERROR_VALUE { + Err(c::STATUS_NOT_SUPPORTED) + } else if handle.is_null() { + let status = unsafe { + c::BCryptOpenAlgorithmProvider( + &mut handle, + c::BCRYPT_RNG_ALGORITHM.as_ptr(), + ptr::null(), + 0, + ) + }; + if c::nt_success(status) { + // If another thread opens a handle first then use that handle instead. + let result = HANDLE.compare_exchange(ptr::null_mut(), handle, Release, Acquire); + if let Err(previous_handle) = result { + // Close our handle and return the previous one. + unsafe { c::BCryptCloseAlgorithmProvider(handle, 0) }; + handle = previous_handle; + } + Ok(Self(handle)) + } else { + HANDLE.store(ERROR_VALUE, Release); + Err(status) + } + } else { + Ok(Self(handle)) + } + } + + fn gen_random_keys(self) -> Result<(u64, u64), c::NTSTATUS> { + let mut v = (0, 0); + let status = unsafe { + let size = mem::size_of_val(&v).try_into().unwrap(); + c::BCryptGenRandom(self.0, ptr::addr_of_mut!(v).cast(), size, 0) + }; + if c::nt_success(status) { Ok(v) } else { Err(status) } + } } /// Generate random numbers using the fallback RNG function (RtlGenRandom) #[cfg(not(target_vendor = "uwp"))] #[inline(never)] -fn fallback_rng() -> (u64, u64) { +fn fallback_rng(rng_status: c::NTSTATUS) -> (u64, u64) { let mut v = (0, 0); let ret = unsafe { c::RtlGenRandom(&mut v as *mut _ as *mut u8, mem::size_of_val(&v) as c::ULONG) }; - if ret != 0 { v } else { panic!("fallback RNG broken: {}", io::Error::last_os_error()) } + if ret != 0 { + v + } else { + panic!( + "RNG broken: {rng_status:#x}, fallback RNG broken: {}", + crate::io::Error::last_os_error() + ) + } } /// We can't use RtlGenRandom with UWP, so there is no fallback #[cfg(target_vendor = "uwp")] #[inline(never)] -fn fallback_rng() -> (u64, u64) { - panic!("fallback RNG broken: RtlGenRandom() not supported on UWP"); +fn fallback_rng(rng_status: c::NTSTATUS) -> (u64, u64) { + panic!("RNG broken: {rng_status:#x} fallback RNG broken: RtlGenRandom() not supported on UWP"); } From 5d94d424859933da5beb76d0ad9818fd095b382b Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 4 Sep 2022 00:55:53 +0200 Subject: [PATCH 4260/5092] Shrink span for bindings with subpatterns. --- compiler/rustc_mir_build/src/build/mod.rs | 2 +- .../rustc_mir_build/src/thir/pattern/mod.rs | 7 ++- ....match_tuple.SimplifyCfg-initial.after.mir | 16 +++--- ...ove_out.move_out_by_subslice.mir_map.0.mir | 8 +-- ...atterns-slice-patterns-box-patterns.stderr | 30 ++++++------ .../borrowck/borrowck-describe-lvalue.stderr | 8 +-- .../borrowck-move-out-from-array-match.stderr | 6 +-- ...ove-out-from-array-no-overlap-match.stderr | 6 +-- ...rowck-move-out-from-array-use-match.stderr | 10 ++-- ...out-from-array-use-no-overlap-match.stderr | 6 +-- .../borrowck-move-out-from-array-use.stderr | 20 ++++---- .../borrowck-move-out-from-array.stderr | 16 +++--- ...ck-slice-pattern-element-loan-array.stderr | 8 +-- ...ck-slice-pattern-element-loan-slice.stderr | 8 +-- .../borrowck-vec-pattern-move-tail.stderr | 2 +- .../borrowck-vec-pattern-nesting.stderr | 2 +- .../ui/moves/move-out-of-array-ref.stderr | 4 +- src/test/ui/moves/move-out-of-slice-2.stderr | 8 +-- src/test/ui/nll/issue-51244.stderr | 2 +- ...can-live-while-the-other-survives-1.stderr | 10 ++-- ...nd-by-move-no-subbindings-fun-param.stderr | 5 +- .../borrowck-move-and-move.stderr | 34 ++++++------- .../borrowck-pat-at-and-box.stderr | 30 +++++------- ...orrowck-pat-by-move-and-ref-inverse.stderr | 40 ++++++--------- .../borrowck-pat-by-move-and-ref.stderr | 49 ++++++++----------- .../borrowck-pat-ref-mut-and-ref.stderr | 42 +++++++--------- .../borrowck-pat-ref-mut-twice.stderr | 32 +++++------- .../copy-and-move-mixed.stderr | 5 +- ...inding-modes-both-sides-independent.stderr | 2 +- .../nested-binding-modes-mut.stderr | 2 +- .../borrowck-move-ref-pattern.stderr | 6 +-- 31 files changed, 190 insertions(+), 236 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 763038c52d7f..7f992c18a18e 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -1036,7 +1036,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { VarBindingForm { binding_mode, opt_ty_info, - opt_match_place: Some((Some(place), span)), + opt_match_place: Some((None, span)), pat_span: span, }, ))))) diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index d2f93b679acc..7e09efe5972a 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -202,6 +202,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box> { let mut ty = self.typeck_results.node_type(pat.hir_id); + let mut span = pat.span; let kind = match pat.kind { hir::PatKind::Wild => PatKind::Wild, @@ -262,6 +263,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } hir::PatKind::Binding(_, id, ident, ref sub) => { + if let Some(ident_span) = ident.span.find_ancestor_inside(span) { + span = span.with_hi(ident_span.hi()); + } + let bm = *self .typeck_results .pat_binding_modes() @@ -326,7 +331,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { hir::PatKind::Or(ref pats) => PatKind::Or { pats: self.lower_patterns(pats) }, }; - Box::new(Pat { span: pat.span, ty, kind }) + Box::new(Pat { span, ty, kind }) } fn lower_tuple_subpats( diff --git a/src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir b/src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir index d39145973624..96716a39a2bf 100644 --- a/src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir +++ b/src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir @@ -8,13 +8,13 @@ fn match_tuple(_1: (u32, bool, Option, u32)) -> u32 { let mut _4: bool; // in scope 0 at $DIR/exponential-or.rs:+2:70: +2:77 let mut _5: bool; // in scope 0 at $DIR/exponential-or.rs:+2:62: +2:67 let mut _6: bool; // in scope 0 at $DIR/exponential-or.rs:+2:62: +2:67 - let _7: u32; // in scope 0 at $DIR/exponential-or.rs:+2:10: +2:21 - let _8: u32; // in scope 0 at $DIR/exponential-or.rs:+2:57: +2:78 + let _7: u32; // in scope 0 at $DIR/exponential-or.rs:+2:10: +2:11 + let _8: u32; // in scope 0 at $DIR/exponential-or.rs:+2:57: +2:58 let mut _9: u32; // in scope 0 at $DIR/exponential-or.rs:+2:83: +2:84 let mut _10: u32; // in scope 0 at $DIR/exponential-or.rs:+2:87: +2:88 scope 1 { - debug y => _7; // in scope 1 at $DIR/exponential-or.rs:+2:10: +2:21 - debug z => _8; // in scope 1 at $DIR/exponential-or.rs:+2:57: +2:78 + debug y => _7; // in scope 1 at $DIR/exponential-or.rs:+2:10: +2:11 + debug z => _8; // in scope 1 at $DIR/exponential-or.rs:+2:57: +2:58 } bb0: { @@ -61,10 +61,10 @@ fn match_tuple(_1: (u32, bool, Option, u32)) -> u32 { } bb9: { - StorageLive(_7); // scope 0 at $DIR/exponential-or.rs:+2:10: +2:21 - _7 = (_1.0: u32); // scope 0 at $DIR/exponential-or.rs:+2:10: +2:21 - StorageLive(_8); // scope 0 at $DIR/exponential-or.rs:+2:57: +2:78 - _8 = (_1.3: u32); // scope 0 at $DIR/exponential-or.rs:+2:57: +2:78 + StorageLive(_7); // scope 0 at $DIR/exponential-or.rs:+2:10: +2:11 + _7 = (_1.0: u32); // scope 0 at $DIR/exponential-or.rs:+2:10: +2:11 + StorageLive(_8); // scope 0 at $DIR/exponential-or.rs:+2:57: +2:58 + _8 = (_1.3: u32); // scope 0 at $DIR/exponential-or.rs:+2:57: +2:58 StorageLive(_9); // scope 1 at $DIR/exponential-or.rs:+2:83: +2:84 _9 = _7; // scope 1 at $DIR/exponential-or.rs:+2:83: +2:84 StorageLive(_10); // scope 1 at $DIR/exponential-or.rs:+2:87: +2:88 diff --git a/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir b/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir index 6e9a8b4d975f..6a5021139cf6 100644 --- a/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir +++ b/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir @@ -15,9 +15,9 @@ fn move_out_by_subslice() -> () { let mut _11: std::boxed::Box; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26 scope 1 { debug a => _1; // in scope 1 at $DIR/uniform_array_move_out.rs:+1:9: +1:10 - let _12: [std::boxed::Box; 2]; // in scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:17 + let _12: [std::boxed::Box; 2]; // in scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:12 scope 4 { - debug _y => _12; // in scope 4 at $DIR/uniform_array_move_out.rs:+2:10: +2:17 + debug _y => _12; // in scope 4 at $DIR/uniform_array_move_out.rs:+2:10: +2:12 } } scope 2 { @@ -77,8 +77,8 @@ fn move_out_by_subslice() -> () { bb6: { StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27 FakeRead(ForLet(None), _1); // scope 0 at $DIR/uniform_array_move_out.rs:+1:9: +1:10 - StorageLive(_12); // scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:17 - _12 = move _1[0..2]; // scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:17 + StorageLive(_12); // scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:12 + _12 = move _1[0..2]; // scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:12 _0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:+0:27: +3:2 drop(_12) -> [return: bb7, unwind: bb9]; // scope 1 at $DIR/uniform_array_move_out.rs:+3:1: +3:2 } diff --git a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr index d4f81930843b..1fd1eb128511 100644 --- a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr +++ b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr @@ -23,7 +23,7 @@ LL | fn bindings_after_at_slice_patterns_move_binding(x: [String; 4]) { | - move occurs because `x` has type `[String; 4]`, which does not implement the `Copy` trait LL | match x { LL | a @ [.., _] => (), - | ----------- value moved here + | - value moved here ... LL | &x; | ^^ value borrowed here after move @@ -32,7 +32,7 @@ error[E0502]: cannot borrow `x` as immutable because it is also borrowed as muta --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:28:5 | LL | ref mut foo @ [.., _] => Some(foo), - | --------------------- mutable borrow occurs here + | ----------- mutable borrow occurs here ... LL | &x; | ^^ immutable borrow occurs here @@ -44,7 +44,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:50:5 | LL | [ref foo @ .., ref bar] => Some(foo), - | ------------ immutable borrow occurs here + | ------- immutable borrow occurs here ... LL | &mut x; | ^^^^^^ mutable borrow occurs here @@ -56,7 +56,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:62:5 | LL | ref foo @ [.., ref bar] => Some(foo), - | ----------------------- immutable borrow occurs here + | ------- immutable borrow occurs here ... LL | &mut x; | ^^^^^^ mutable borrow occurs here @@ -71,7 +71,7 @@ LL | fn bindings_after_at_or_patterns_move(x: Option) { | - move occurs because `x` has type `Option`, which does not implement the `Copy` trait LL | match x { LL | foo @ Some(Test::Foo | Test::Bar) => (), - | --------------------------------- + | --- | | | value moved here | value moved here @@ -83,7 +83,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:86:5 | LL | ref foo @ Some(Test::Foo | Test::Bar) => Some(foo), - | ------------------------------------- immutable borrow occurs here + | ------- immutable borrow occurs here ... LL | &mut x; | ^^^^^^ mutable borrow occurs here @@ -95,7 +95,7 @@ error[E0502]: cannot borrow `x` as immutable because it is also borrowed as muta --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:98:5 | LL | ref mut foo @ Some(Test::Foo | Test::Bar) => Some(foo), - | ----------------------------------------- mutable borrow occurs here + | ----------- mutable borrow occurs here ... LL | &x; | ^^ immutable borrow occurs here @@ -107,7 +107,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:112:5 | LL | ref foo @ Some(box ref s) => Some(foo), - | ------------------------- immutable borrow occurs here + | ------- immutable borrow occurs here ... LL | &mut x; | ^^^^^^ mutable borrow occurs here @@ -122,7 +122,7 @@ LL | fn bindings_after_at_slice_patterns_or_patterns_moves(x: [Option; 4]) | - move occurs because `x` has type `[Option; 4]`, which does not implement the `Copy` trait LL | match x { LL | a @ [.., Some(Test::Foo | Test::Bar)] => (), - | ------------------------------------- + | - | | | value moved here | value moved here @@ -134,7 +134,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:144:5 | LL | ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(a), - | ------------------------------------------------- immutable borrow occurs here + | ----- immutable borrow occurs here ... LL | &mut x; | ^^^^^^ mutable borrow occurs here @@ -146,7 +146,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:156:5 | LL | ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(b), - | ---------- immutable borrow occurs here + | ----- immutable borrow occurs here ... LL | &mut x; | ^^^^^^ mutable borrow occurs here @@ -158,7 +158,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:170:5 | LL | [_, ref a @ Some(box ref b), ..] => Some(a), - | ----------------------- immutable borrow occurs here + | ----- immutable borrow occurs here ... LL | &mut x; | ^^^^^^ mutable borrow occurs here @@ -170,7 +170,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:186:5 | LL | [_, ref a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a), - | ------------------------------------------- immutable borrow occurs here + | ----- immutable borrow occurs here ... LL | &mut x; | ^^^^^^ mutable borrow occurs here @@ -182,7 +182,7 @@ error[E0502]: cannot borrow `x` as immutable because it is also borrowed as muta --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:200:5 | LL | [_, ref mut a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a), - | ----------------------------------------------- mutable borrow occurs here + | --------- mutable borrow occurs here ... LL | &x; | ^^ immutable borrow occurs here @@ -194,7 +194,7 @@ error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immuta --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:214:5 | LL | ref a @ [_, ref b @ Some(box Test::Foo | box Test::Bar), ..] => Some(a), - | ------------------------------------------------------------ immutable borrow occurs here + | ----- immutable borrow occurs here ... LL | &mut x; | ^^^^^^ mutable borrow occurs here diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.stderr b/src/test/ui/borrowck/borrowck-describe-lvalue.stderr index cfcc62de4383..2c1b9c10d466 100644 --- a/src/test/ui/borrowck/borrowck-describe-lvalue.stderr +++ b/src/test/ui/borrowck/borrowck-describe-lvalue.stderr @@ -200,7 +200,7 @@ LL | let x = &mut v; | ------ borrow of `v` occurs here LL | match v { LL | &[x @ ..] => println!("{:?}", x), - | ^^^^^^ use of borrowed `v` + | ^ use of borrowed `v` ... LL | drop(x); | - borrow later used here @@ -212,7 +212,7 @@ LL | let x = &mut v; | ------ borrow of `v` occurs here ... LL | &[_, x @ ..] => println!("{:?}", x), - | ^^^^^^ use of borrowed `v` + | ^ use of borrowed `v` ... LL | drop(x); | - borrow later used here @@ -224,7 +224,7 @@ LL | let x = &mut v; | ------ borrow of `v` occurs here ... LL | &[x @ .., _] => println!("{:?}", x), - | ^^^^^^ use of borrowed `v` + | ^ use of borrowed `v` ... LL | drop(x); | - borrow later used here @@ -236,7 +236,7 @@ LL | let x = &mut v; | ------ borrow of `v` occurs here ... LL | &[_, x @ .., _] => println!("{:?}", x), - | ^^^^^^ use of borrowed `v` + | ^ use of borrowed `v` ... LL | drop(x); | - borrow later used here diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr index 3249aae8f44a..346b82a26664 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr @@ -79,7 +79,7 @@ error[E0382]: use of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array-match.rs:89:11 | LL | [_y @ .., _, _] => {} - | ------- value moved here + | -- value moved here ... LL | [(_x, _), _, _] => {} | ^^ value used here after move @@ -90,7 +90,7 @@ error[E0382]: use of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array-match.rs:99:15 | LL | [_, _, _y @ ..] => {} - | ------- value moved here + | -- value moved here ... LL | [.., (_x, _)] => {} | ^^ value used here after move @@ -101,7 +101,7 @@ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-match.rs:110:11 | LL | [x @ .., _] => {} - | ------ value partially moved here + | - value partially moved here LL | } LL | match a { | ^ value used here after partial move diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr index c198002265b7..6c6a25c251e7 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr @@ -68,7 +68,7 @@ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:85:11 | LL | [_, _y @ ..] => {} - | ------- value partially moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move @@ -79,7 +79,7 @@ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:96:11 | LL | [_y @ .., _] => {} - | ------- value partially moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move @@ -90,7 +90,7 @@ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:109:11 | LL | [x @ .., _, _] => {} - | ------ value partially moved here + | - value partially moved here LL | } LL | match a { | ^ value used here after partial move diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr index 8f2da9d203b0..77702e145df8 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr @@ -79,7 +79,7 @@ error[E0382]: borrow of moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-use-match.rs:89:11 | LL | [_y @ .., _, _] => {} - | ------- value moved here + | -- value moved here ... LL | [(ref _x, _), _, _] => {} | ^^^^^^ value borrowed here after move @@ -90,7 +90,7 @@ error[E0382]: borrow of moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-use-match.rs:99:15 | LL | [_, _, _y @ ..] => {} - | ------- value moved here + | -- value moved here ... LL | [.., (ref _x, _)] => {} | ^^^^^^ value borrowed here after move @@ -101,7 +101,7 @@ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:110:11 | LL | [x @ .., _] => {} - | ------ value partially moved here + | - value partially moved here LL | } LL | match a { | ^ value used here after partial move @@ -134,7 +134,7 @@ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:139:5 | LL | [_, _, _x @ ..] => {} - | ------- value partially moved here + | -- value partially moved here LL | } LL | a[0] = Default::default(); | ^^^^ value used here after partial move @@ -145,7 +145,7 @@ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:147:5 | LL | [_, _, _x @ ..] => {} - | ------- value partially moved here + | -- value partially moved here LL | } LL | a[0].1 = Default::default(); | ^^^^ value used here after partial move diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr index 4b27f03dc458..6cc2c2f7a984 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr @@ -68,7 +68,7 @@ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:85:11 | LL | [_, _y @ ..] => {} - | ------- value partially moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move @@ -79,7 +79,7 @@ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:96:11 | LL | [_y @ .., _] => {} - | ------- value partially moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move @@ -90,7 +90,7 @@ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:109:11 | LL | [x @ .., _, _] => {} - | ------ value partially moved here + | - value partially moved here LL | } LL | match a { | ^ value used here after partial move diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr index b0bad6e99788..9add7553afa7 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr @@ -34,7 +34,7 @@ error[E0382]: borrow of partially moved value: `a` LL | let [_x, _, _] = a; | -- value partially moved here LL | let [ref _y @ .., _, _] = a; - | ^^^^^^^^^^^ value borrowed here after partial move + | ^^^^^^ value borrowed here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait @@ -44,7 +44,7 @@ error[E0382]: borrow of partially moved value: `a` LL | let [.., _x] = a; | -- value partially moved here LL | let [_, _, ref _y @ ..] = a; - | ^^^^^^^^^^^ value borrowed here after partial move + | ^^^^^^ value borrowed here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait @@ -54,7 +54,7 @@ error[E0382]: borrow of partially moved value: `a` LL | let [(_x, _), _, _] = a; | -- value partially moved here LL | let [ref _y @ .., _, _] = a; - | ^^^^^^^^^^^ value borrowed here after partial move + | ^^^^^^ value borrowed here after partial move | = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait @@ -64,7 +64,7 @@ error[E0382]: borrow of partially moved value: `a` LL | let [.., (_x, _)] = a; | -- value partially moved here LL | let [_, _, ref _y @ ..] = a; - | ^^^^^^^^^^^ value borrowed here after partial move + | ^^^^^^ value borrowed here after partial move | = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait @@ -72,7 +72,7 @@ error[E0382]: borrow of moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-use.rs:54:11 | LL | let [_y @ .., _, _] = a; - | ------- value moved here + | -- value moved here LL | let [(ref _x, _), _, _] = a; | ^^^^^^ value borrowed here after move | @@ -82,7 +82,7 @@ error[E0382]: borrow of moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-use.rs:60:15 | LL | let [_, _, _y @ ..] = a; - | ------- value moved here + | -- value moved here LL | let [.., (ref _x, _)] = a; | ^^^^^^ value borrowed here after move | @@ -92,9 +92,9 @@ error[E0382]: borrow of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:68:13 | LL | let [x @ .., _] = a; - | ------ value partially moved here + | - value partially moved here LL | let [_, ref _y @ ..] = a; - | ^^^^^^^^^^^ value borrowed here after partial move + | ^^^^^^ value borrowed here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait @@ -122,7 +122,7 @@ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:88:5 | LL | let [_, _, _x @ ..] = a; - | ------- value partially moved here + | -- value partially moved here LL | a[0] = Default::default(); | ^^^^ value used here after partial move | @@ -132,7 +132,7 @@ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:94:5 | LL | let [_, _, _x @ ..] = a; - | ------- value partially moved here + | -- value partially moved here LL | a[0].1 = Default::default(); | ^^^^ value used here after partial move | diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array.stderr index 1fc2b292b84c..363effcfe532 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array.stderr @@ -34,7 +34,7 @@ error[E0382]: use of partially moved value: `a` LL | let [_x, _, _] = a; | -- value partially moved here LL | let [_y @ .., _, _] = a; - | ^^^^^^^ value used here after partial move + | ^^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait @@ -44,7 +44,7 @@ error[E0382]: use of partially moved value: `a` LL | let [.., _x] = a; | -- value partially moved here LL | let [_, _, _y @ ..] = a; - | ^^^^^^^ value used here after partial move + | ^^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait @@ -54,7 +54,7 @@ error[E0382]: use of partially moved value: `a` LL | let [(_x, _), _, _] = a; | -- value partially moved here LL | let [_y @ .., _, _] = a; - | ^^^^^^^ value used here after partial move + | ^^ value used here after partial move | = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait @@ -64,7 +64,7 @@ error[E0382]: use of partially moved value: `a` LL | let [.., (_x, _)] = a; | -- value partially moved here LL | let [_, _, _y @ ..] = a; - | ^^^^^^^ value used here after partial move + | ^^ value used here after partial move | = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait @@ -72,7 +72,7 @@ error[E0382]: use of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array.rs:54:11 | LL | let [_y @ .., _, _] = a; - | ------- value moved here + | -- value moved here LL | let [(_x, _), _, _] = a; | ^^ value used here after move | @@ -82,7 +82,7 @@ error[E0382]: use of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array.rs:60:15 | LL | let [_, _, _y @ ..] = a; - | ------- value moved here + | -- value moved here LL | let [.., (_x, _)] = a; | ^^ value used here after move | @@ -92,9 +92,9 @@ error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array.rs:68:13 | LL | let [x @ .., _] = a; - | ------ value partially moved here + | - value partially moved here LL | let [_, _y @ ..] = a; - | ^^^^^^^ value used here after partial move + | ^^ value used here after partial move | = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr index b8ac7a3a4469..f4324110ccb8 100644 --- a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr +++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-array.stderr @@ -57,7 +57,7 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im LL | let [ref first, ref second, ..] = *s; | ---------- immutable borrow occurs here LL | let [_, ref mut tail @ ..] = *s; - | ^^^^^^^^^^^^^^^^^ mutable borrow occurs here + | ^^^^^^^^^^^^ mutable borrow occurs here LL | nop(&[first, second]); | ------ immutable borrow later used here @@ -67,7 +67,7 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im LL | let [.., ref second, ref first] = *s; | ---------- immutable borrow occurs here LL | let [ref mut tail @ .., _] = *s; - | ^^^^^^^^^^^^^^^^^ mutable borrow occurs here + | ^^^^^^^^^^^^ mutable borrow occurs here LL | nop(&[first, second]); | ------ immutable borrow later used here @@ -75,9 +75,9 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im --> $DIR/borrowck-slice-pattern-element-loan-array.rs:46:10 | LL | let [_, ref s1 @ ..] = *s; - | ----------- immutable borrow occurs here + | ------ immutable borrow occurs here LL | let [ref mut s2 @ .., _, _] = *s; - | ^^^^^^^^^^^^^^^ mutable borrow occurs here + | ^^^^^^^^^^ mutable borrow occurs here LL | nop_subslice(s1); | -- immutable borrow later used here diff --git a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr index d3388e071aa5..f9a63bd49dd5 100644 --- a/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr +++ b/src/test/ui/borrowck/borrowck-slice-pattern-element-loan-slice.stderr @@ -88,7 +88,7 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im LL | if let [ref first, ref second, ..] = *s { | ---------- immutable borrow occurs here LL | if let [_, ref mut tail @ ..] = *s { - | ^^^^^^^^^^^^^^^^^ mutable borrow occurs here + | ^^^^^^^^^^^^ mutable borrow occurs here LL | nop(&[first, second]); | ------ immutable borrow later used here @@ -98,7 +98,7 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im LL | if let [.., ref second, ref first] = *s { | ---------- immutable borrow occurs here LL | if let [ref mut tail @ .., _] = *s { - | ^^^^^^^^^^^^^^^^^ mutable borrow occurs here + | ^^^^^^^^^^^^ mutable borrow occurs here LL | nop(&[first, second]); | ------ immutable borrow later used here @@ -106,9 +106,9 @@ error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as im --> $DIR/borrowck-slice-pattern-element-loan-slice.rs:65:17 | LL | if let [_, _, _, ref s1 @ ..] = *s { - | ----------- immutable borrow occurs here + | ------ immutable borrow occurs here LL | if let [ref mut s2 @ .., _, _, _] = *s { - | ^^^^^^^^^^^^^^^ mutable borrow occurs here + | ^^^^^^^^^^ mutable borrow occurs here LL | nop_subslice(s1); | -- immutable borrow later used here diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.stderr b/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.stderr index ff70ba9fcca8..0ac7df944d78 100644 --- a/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.stderr +++ b/src/test/ui/borrowck/borrowck-vec-pattern-move-tail.stderr @@ -2,7 +2,7 @@ error[E0506]: cannot assign to `a[_]` because it is borrowed --> $DIR/borrowck-vec-pattern-move-tail.rs:8:5 | LL | [1, 2, ref tail @ ..] => tail, - | ------------- borrow of `a[_]` occurs here + | -------- borrow of `a[_]` occurs here ... LL | a[2] = 0; | ^^^^^^^^ assignment to borrowed `a[_]` occurs here diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr index ddd89afe5bf9..c3bcb7de65da 100644 --- a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr +++ b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr @@ -14,7 +14,7 @@ error[E0506]: cannot assign to `vec[_]` because it is borrowed --> $DIR/borrowck-vec-pattern-nesting.rs:23:13 | LL | &mut [ref _b @ ..] => { - | ----------- borrow of `vec[_]` occurs here + | ------ borrow of `vec[_]` occurs here LL | LL | vec[0] = Box::new(4); | ^^^^^^ assignment to borrowed `vec[_]` occurs here diff --git a/src/test/ui/moves/move-out-of-array-ref.stderr b/src/test/ui/moves/move-out-of-array-ref.stderr index fd682e56ae1d..0caa0b83a4c7 100644 --- a/src/test/ui/moves/move-out-of-array-ref.stderr +++ b/src/test/ui/moves/move-out-of-array-ref.stderr @@ -13,7 +13,7 @@ error[E0508]: cannot move out of type `[D; 4]`, a non-copy array --> $DIR/move-out-of-array-ref.rs:13:27 | LL | let [_, s @ .. , _] = *a; - | ------ ^^ + | - ^^ | | | | | cannot move out of here | | help: consider borrowing here: `&*a` @@ -35,7 +35,7 @@ error[E0508]: cannot move out of type `[D; 4]`, a non-copy array --> $DIR/move-out-of-array-ref.rs:23:27 | LL | let [_, s @ .. , _] = *a; - | ------ ^^ + | - ^^ | | | | | cannot move out of here | | help: consider borrowing here: `&*a` diff --git a/src/test/ui/moves/move-out-of-slice-2.stderr b/src/test/ui/moves/move-out-of-slice-2.stderr index 9a863bf31a7f..93b0dcfc2d18 100644 --- a/src/test/ui/moves/move-out-of-slice-2.stderr +++ b/src/test/ui/moves/move-out-of-slice-2.stderr @@ -14,7 +14,7 @@ LL | match *a { | ^^ cannot move out of here LL | LL | [a @ ..] => {} - | ------ + | - | | | data moved here | move occurs because `a` has type `[A]`, which does not implement the `Copy` trait @@ -26,7 +26,7 @@ LL | match *b { | ^^ cannot move out of here LL | LL | [_, _, b @ .., _] => {} - | ------ + | - | | | data moved here | move occurs because `b` has type `[A]`, which does not implement the `Copy` trait @@ -38,7 +38,7 @@ LL | match *c { | ^^ cannot move out of here LL | LL | [c @ ..] => {} - | ------ + | - | | | data moved here | move occurs because `c` has type `[C]`, which does not implement the `Copy` trait @@ -50,7 +50,7 @@ LL | match *d { | ^^ cannot move out of here LL | LL | [_, _, d @ .., _] => {} - | ------ + | - | | | data moved here | move occurs because `d` has type `[C]`, which does not implement the `Copy` trait diff --git a/src/test/ui/nll/issue-51244.stderr b/src/test/ui/nll/issue-51244.stderr index 19f0223a357a..dcb6f9fec18b 100644 --- a/src/test/ui/nll/issue-51244.stderr +++ b/src/test/ui/nll/issue-51244.stderr @@ -2,7 +2,7 @@ error[E0594]: cannot assign to `*my_ref`, which is behind a `&` reference --> $DIR/issue-51244.rs:3:5 | LL | let ref my_ref @ _ = 0; - | -------------- help: consider changing this to be a mutable reference: `ref mut my_ref @ _` + | ---------- help: consider changing this to be a mutable reference: `ref mut my_ref` LL | *my_ref = 0; | ^^^^^^^^^^^ `my_ref` is a `&` reference, so the data it refers to cannot be written diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr index 4249a74b3ed6..fad84dda0e19 100644 --- a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr +++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr @@ -40,9 +40,8 @@ error[E0382]: borrow of moved value --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:12:14 | LL | Some(ref _y @ _z) => {} - | ^^^^^^^^^-- - | | | - | | value moved here + | ^^^^^^ -- value moved here + | | | value borrowed here after move | = note: move occurs because value has type `X`, which does not implement the `Copy` trait @@ -55,9 +54,8 @@ error[E0382]: borrow of moved value --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:26:14 | LL | Some(ref mut _y @ _z) => {} - | ^^^^^^^^^^^^^-- - | | | - | | value moved here + | ^^^^^^^^^^ -- value moved here + | | | value borrowed here after move | = note: move occurs because value has type `X`, which does not implement the `Copy` trait diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr index ee0885a014aa..a481ca468338 100644 --- a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr +++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr @@ -2,9 +2,8 @@ error[E0382]: use of partially moved value --> $DIR/bind-by-move-no-subbindings-fun-param.rs:7:6 | LL | fn f(a @ A(u): A) -> Box { - | ^^^^^^-^ - | | | - | | value partially moved here + | ^ - value partially moved here + | | | value used here after partial move | = note: partial move occurs because value has type `Box`, which does not implement the `Copy` trait diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr index 8e00bf5c328b..83751843b1b8 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value --> $DIR/borrowck-move-and-move.rs:11:9 | LL | let a @ b = U; - | ^^^^- - move occurs because value has type `U`, which does not implement the `Copy` trait + | ^ - - move occurs because value has type `U`, which does not implement the `Copy` trait | | | | | value moved here | value used here after move @@ -11,9 +11,8 @@ error[E0382]: use of partially moved value --> $DIR/borrowck-move-and-move.rs:13:9 | LL | let a @ (b, c) = (U, U); - | ^^^^^^^^-^ - | | | - | | value partially moved here + | ^ - value partially moved here + | | | value used here after partial move | = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait @@ -22,9 +21,8 @@ error[E0382]: use of partially moved value --> $DIR/borrowck-move-and-move.rs:15:9 | LL | let a @ (b, c) = (u(), u()); - | ^^^^^^^^-^ - | | | - | | value partially moved here + | ^ - value partially moved here + | | | value used here after partial move | = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait @@ -35,9 +33,8 @@ error[E0382]: use of moved value LL | match Ok(U) { | ----- move occurs because value has type `Result`, which does not implement the `Copy` trait LL | a @ Ok(b) | a @ Err(b) => {} - | -------^- - | | | - | | value used here after move + | - ^ value used here after move + | | | value moved here error[E0382]: use of moved value @@ -46,18 +43,16 @@ error[E0382]: use of moved value LL | match Ok(U) { | ----- move occurs because value has type `Result`, which does not implement the `Copy` trait LL | a @ Ok(b) | a @ Err(b) => {} - | --------^- - | | | - | | value used here after move + | - ^ value used here after move + | | | value moved here error[E0382]: use of partially moved value --> $DIR/borrowck-move-and-move.rs:25:9 | LL | xs @ [a, .., b] => {} - | ^^^^^^^^^^^^^-^ - | | | - | | value partially moved here + | ^^ - value partially moved here + | | | value used here after partial move | = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait @@ -66,9 +61,8 @@ error[E0382]: use of partially moved value --> $DIR/borrowck-move-and-move.rs:29:9 | LL | xs @ [_, ys @ .., _] => {} - | ^^^^^^^^^-------^^^^ - | | | - | | value partially moved here + | ^^ -- value partially moved here + | | | value used here after partial move | = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait @@ -77,7 +71,7 @@ error[E0382]: use of moved value --> $DIR/borrowck-move-and-move.rs:22:12 | LL | fn fun(a @ b: U) {} - | ^^^^- + | ^---- | | | | | value moved here | value used here after move diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr index 4b2048855ebb..002c7609f610 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr @@ -74,9 +74,8 @@ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-at-and-box.rs:31:9 | LL | let ref a @ box b = Box::new(NC); - | ^^^^^^^^^^^^- - | | | - | | value moved here + | ^^^^^ - value moved here + | | | value borrowed here after move | = note: move occurs because value has type `NC`, which does not implement the `Copy` trait @@ -85,9 +84,8 @@ error[E0502]: cannot borrow value as immutable because it is also borrowed as mu --> $DIR/borrowck-pat-at-and-box.rs:38:9 | LL | let ref a @ box ref mut b = Box::new(NC); - | ^^^^^^^^^^^^--------- - | | | - | | mutable borrow occurs here + | ^^^^^ --------- mutable borrow occurs here + | | | immutable borrow occurs here ... LL | *b = NC; @@ -97,9 +95,8 @@ error[E0502]: cannot borrow value as immutable because it is also borrowed as mu --> $DIR/borrowck-pat-at-and-box.rs:42:9 | LL | let ref a @ box ref mut b = Box::new(NC); - | ^^^^^^^^^^^^--------- - | | | - | | mutable borrow occurs here + | ^^^^^ --------- mutable borrow occurs here + | | | immutable borrow occurs here ... LL | *b = NC; @@ -109,9 +106,8 @@ error[E0502]: cannot borrow value as mutable because it is also borrowed as immu --> $DIR/borrowck-pat-at-and-box.rs:48:9 | LL | let ref mut a @ box ref b = Box::new(NC); - | ^^^^^^^^^^^^^^^^----- - | | | - | | immutable borrow occurs here + | ^^^^^^^^^ ----- immutable borrow occurs here + | | | mutable borrow occurs here ... LL | drop(b); @@ -121,9 +117,8 @@ error[E0502]: cannot borrow value as mutable because it is also borrowed as immu --> $DIR/borrowck-pat-at-and-box.rs:62:9 | LL | ref mut a @ box ref b => { - | ^^^^^^^^^^^^^^^^----- - | | | - | | immutable borrow occurs here + | ^^^^^^^^^ ----- immutable borrow occurs here + | | | mutable borrow occurs here ... LL | drop(b); @@ -133,9 +128,8 @@ error[E0502]: cannot borrow value as mutable because it is also borrowed as immu --> $DIR/borrowck-pat-at-and-box.rs:54:11 | LL | fn f5(ref mut a @ box ref b: Box) { - | ^^^^^^^^^^^^^^^^----- - | | | - | | immutable borrow occurs here + | ^^^^^^^^^ ----- immutable borrow occurs here + | | | mutable borrow occurs here ... LL | drop(b); diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr index bc2c1625fd0e..a9e66de08424 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr @@ -262,9 +262,8 @@ error[E0382]: use of partially moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:9 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); - | ^^^^^^^^^^^^^^^^^^^^^^^^---------^ - | | | - | | value partially moved here + | ^ - value partially moved here + | | | value used here after partial move | = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait @@ -273,9 +272,8 @@ error[E0382]: use of partially moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:9 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); - | ^^^^^^^^^^^^^^^^^^^^^^^^---------^ - | | | - | | value partially moved here + | ^ - value partially moved here + | | | value used here after partial move | = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait @@ -286,10 +284,7 @@ error[E0382]: use of moved value LL | match Some((U, U)) { | ------------ move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} - | -----------------------------^^^^^^^^^-- - | | | - | | value used here after move - | value moved here + | - value moved here ^ value used here after move error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:55:30 @@ -297,9 +292,8 @@ error[E0382]: borrow of moved value LL | match Some([U, U]) { | ------------ move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait LL | mut a @ Some([ref b, ref mut c]) => {} - | ---------------------^^^^^^^^^-- - | | | - | | value borrowed here after move + | ----- ^^^^^^^^^ value borrowed here after move + | | | value moved here error[E0382]: borrow of moved value @@ -308,9 +302,8 @@ error[E0382]: borrow of moved value LL | match Some(u()) { | --------- move occurs because value has type `Option`, which does not implement the `Copy` trait LL | a @ Some(ref b) => {} - | ---------^^^^^- - | | | - | | value borrowed here after move + | - ^^^^^ value borrowed here after move + | | | value moved here error[E0382]: use of moved value @@ -319,10 +312,7 @@ error[E0382]: use of moved value LL | match Some((u(), u())) { | ---------------- move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} - | -----------------------------^^^^^^^^^-- - | | | - | | value used here after move - | value moved here + | - value moved here ^ value used here after move error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:75:30 @@ -330,18 +320,16 @@ error[E0382]: borrow of moved value LL | match Some([u(), u()]) { | ---------------- move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait LL | mut a @ Some([ref b, ref mut c]) => {} - | ---------------------^^^^^^^^^-- - | | | - | | value borrowed here after move + | ----- ^^^^^^^^^ value borrowed here after move + | | | value moved here error[E0382]: use of partially moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:11 | LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} - | ^^^^^^^^^^^^^^^^^^^^-------------^ - | | | - | | value partially moved here + | ^^^^^ ----- value partially moved here + | | | value used here after partial move | = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr index c019aae3dfc9..e03a9298214e 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr @@ -237,9 +237,8 @@ error[E0382]: borrow of partially moved value --> $DIR/borrowck-pat-by-move-and-ref.rs:30:9 | LL | let ref mut a @ [b, mut c] = [U, U]; - | ^^^^^^^^^^^^^^^^-----^ - | | | - | | value partially moved here + | ^^^^^^^^^ ----- value partially moved here + | | | value borrowed here after partial move | = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait @@ -248,7 +247,7 @@ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref.rs:33:9 | LL | let ref a @ b = u(); - | ^^^^^^^^- --- move occurs because value has type `U`, which does not implement the `Copy` trait + | ^^^^^ - --- move occurs because value has type `U`, which does not implement the `Copy` trait | | | | | value moved here | value borrowed here after move @@ -257,9 +256,8 @@ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref.rs:36:18 | LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); - | ^^^^^^^^----- - | | | - | | value moved here + | ^^^^^ ----- value moved here + | | | value borrowed here after move | = note: move occurs because value has type `U`, which does not implement the `Copy` trait @@ -268,9 +266,8 @@ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref.rs:36:33 | LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); - | ^^^^^^^^- - | | | - | | value moved here + | ^^^^^ - value moved here + | | | value borrowed here after move | = note: move occurs because value has type `U`, which does not implement the `Copy` trait @@ -279,9 +276,8 @@ error[E0382]: borrow of partially moved value --> $DIR/borrowck-pat-by-move-and-ref.rs:42:9 | LL | let ref mut a @ [b, mut c] = [u(), u()]; - | ^^^^^^^^^^^^^^^^-----^ - | | | - | | value partially moved here + | ^^^^^^^^^ ----- value partially moved here + | | | value borrowed here after partial move | = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait @@ -290,9 +286,8 @@ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref.rs:69:23 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} - | ^^^^^^^^----- - | | | - | | value moved here + | ^^^^^ ----- value moved here + | | | value borrowed here after move | = note: move occurs because value has type `U`, which does not implement the `Copy` trait @@ -305,9 +300,8 @@ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref.rs:69:38 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} - | ^^^^^^^^- - | | | - | | value moved here + | ^^^^^ - value moved here + | | | value borrowed here after move | = note: move occurs because value has type `U`, which does not implement the `Copy` trait @@ -320,7 +314,7 @@ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref.rs:11:11 | LL | fn f1(ref a @ b: U) {} - | ^^^^^^^^- + | ^^^^^---- | | | | | value moved here | value borrowed here after move @@ -330,9 +324,8 @@ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref.rs:14:20 | LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} - | ^^^^^^^^----- - | | | - | | value moved here + | ^^^^^ ----- value moved here + | | | value borrowed here after move | = note: move occurs because value has type `U`, which does not implement the `Copy` trait @@ -341,9 +334,8 @@ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref.rs:14:35 | LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} - | ^^^^^^^^- - | | | - | | value moved here + | ^^^^^ - value moved here + | | | value borrowed here after move | = note: move occurs because value has type `U`, which does not implement the `Copy` trait @@ -352,9 +344,8 @@ error[E0382]: borrow of partially moved value --> $DIR/borrowck-pat-by-move-and-ref.rs:20:11 | LL | fn f3(ref mut a @ [b, mut c]: [U; 2]) {} - | ^^^^^^^^^^^^^^^^-----^ - | | | - | | value partially moved here + | ^^^^^^^^^ ----- value partially moved here + | | | value borrowed here after partial move | = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr index 2ae78d1084e0..9fd5e229afd0 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr @@ -298,9 +298,8 @@ error[E0502]: cannot borrow value as immutable because it is also borrowed as mu --> $DIR/borrowck-pat-ref-mut-and-ref.rs:8:31 | LL | ref mut z @ &mut Some(ref a) => { - | ----------------------^^^^^- - | | | - | | immutable borrow occurs here + | --------- ^^^^^ immutable borrow occurs here + | | | mutable borrow occurs here ... LL | **z = None; @@ -310,9 +309,8 @@ error[E0502]: cannot borrow value as mutable because it is also borrowed as immu --> $DIR/borrowck-pat-ref-mut-and-ref.rs:46:9 | LL | let ref mut a @ ref b = u(); - | ^^^^^^^^^^^^----- - | | | - | | immutable borrow occurs here + | ^^^^^^^^^ ----- immutable borrow occurs here + | | | mutable borrow occurs here ... LL | drop(b); @@ -322,9 +320,8 @@ error[E0502]: cannot borrow value as immutable because it is also borrowed as mu --> $DIR/borrowck-pat-ref-mut-and-ref.rs:51:9 | LL | let ref a @ ref mut b = u(); - | ^^^^^^^^--------- - | | | - | | mutable borrow occurs here + | ^^^^^ --------- mutable borrow occurs here + | | | immutable borrow occurs here ... LL | *b = u(); @@ -334,9 +331,8 @@ error[E0502]: cannot borrow value as mutable because it is also borrowed as immu --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:20 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { - | -----------^^^^^^^^^- - | | | - | | mutable borrow occurs here + | ----- ^^^^^^^^^ mutable borrow occurs here + | | | immutable borrow occurs here ... LL | drop(a); @@ -346,9 +342,8 @@ error[E0502]: cannot borrow value as mutable because it is also borrowed as immu --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:45 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { - | ------------^^^^^^^^^- - | | | - | | mutable borrow occurs here + | ----- ^^^^^^^^^ mutable borrow occurs here + | | | immutable borrow occurs here ... LL | drop(a); @@ -406,9 +401,8 @@ error[E0502]: cannot borrow value as immutable because it is also borrowed as mu --> $DIR/borrowck-pat-ref-mut-and-ref.rs:117:9 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); - | ^^^^^^^^^---------^^^^^^^^^^^^ - | | | - | | mutable borrow occurs here + | ^^^^^ --------- mutable borrow occurs here + | | | immutable borrow occurs here ... LL | *b = U; @@ -418,9 +412,8 @@ error[E0502]: cannot borrow value as immutable because it is also borrowed as mu --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:9 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); - | ^^^^^^^^^---------^^^^^^^^^^^^ - | | | - | | mutable borrow occurs here + | ^^^^^ --------- mutable borrow occurs here + | | | immutable borrow occurs here ... LL | *b = U; @@ -430,9 +423,8 @@ error[E0502]: cannot borrow value as immutable because it is also borrowed as mu --> $DIR/borrowck-pat-ref-mut-and-ref.rs:129:9 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); - | ^^^^^^^^^---------^^^^^^^^^^^^ - | | | - | | mutable borrow occurs here + | ^^^^^ --------- mutable borrow occurs here + | | | immutable borrow occurs here LL | LL | *b = U; @@ -442,7 +434,7 @@ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:30 | LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {} - | --------^^^^^^^^^^^^- + | --------^^^^^^^^^---- | | | | | | | value moved here | | value borrowed here after move diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr index aa02230419b5..e47aea9c77e6 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr @@ -262,9 +262,8 @@ error[E0499]: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:29:9 | LL | let ref mut a @ ref mut b = U; - | ^^^^^^^^^^^^--------- - | | | - | | first mutable borrow occurs here + | ^^^^^^^^^ --------- first mutable borrow occurs here + | | | second mutable borrow occurs here ... LL | drop(b); @@ -274,9 +273,8 @@ error[E0499]: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:39:9 | LL | let ref mut a @ ref mut b = U; - | ^^^^^^^^^^^^--------- - | | | - | | first mutable borrow occurs here + | ^^^^^^^^^ --------- first mutable borrow occurs here + | | | second mutable borrow occurs here ... LL | *b = U; @@ -286,9 +284,8 @@ error[E0499]: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:89:24 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { - | ---------------^^^^^^^^^- - | | | - | | second mutable borrow occurs here + | --------- ^^^^^^^^^ second mutable borrow occurs here + | | | first mutable borrow occurs here ... LL | *a = Err(U); @@ -298,9 +295,8 @@ error[E0499]: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:89:53 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { - | ----------------^^^^^^^^^- - | | | - | | second mutable borrow occurs here + | --------- ^^^^^^^^^ second mutable borrow occurs here + | | | first mutable borrow occurs here ... LL | *a = Err(U); @@ -310,9 +306,8 @@ error[E0499]: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:101:24 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { - | ---------------^^^^^^^^^- - | | | - | | second mutable borrow occurs here + | --------- ^^^^^^^^^ second mutable borrow occurs here + | | | first mutable borrow occurs here ... LL | drop(a); @@ -322,9 +317,8 @@ error[E0499]: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:101:53 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { - | ----------------^^^^^^^^^- - | | | - | | second mutable borrow occurs here + | --------- ^^^^^^^^^ second mutable borrow occurs here + | | | first mutable borrow occurs here ... LL | drop(a); @@ -334,7 +328,7 @@ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-ref-mut-twice.rs:21:34 | LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {} - | ------------^^^^^^^^^^^^- + | ------------^^^^^^^^^---- | | | | | | | value moved here | | value borrowed here after move diff --git a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr index d290144b6155..cd3234952fa5 100644 --- a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr +++ b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr @@ -2,9 +2,8 @@ error[E0382]: use of partially moved value --> $DIR/copy-and-move-mixed.rs:12:9 | LL | let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C)); - | ^^^^^^^^^^------------^ - | | | - | | value partially moved here + | ^ - value partially moved here + | | | value used here after partial move | = note: partial move occurs because value has type `NC`, which does not implement the `Copy` trait diff --git a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr index d78faa682b50..840a513d6c67 100644 --- a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr +++ b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr @@ -48,7 +48,7 @@ error[E0382]: borrow of moved value --> $DIR/default-binding-modes-both-sides-independent.rs:29:9 | LL | let ref mut a @ b = NotCopy; - | ^^^^^^^^^^^^- ------- move occurs because value has type `NotCopy`, which does not implement the `Copy` trait + | ^^^^^^^^^ - ------- move occurs because value has type `NotCopy`, which does not implement the `Copy` trait | | | | | value moved here | value borrowed here after move diff --git a/src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr b/src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr index 3180bd0afc10..70beb5d42322 100644 --- a/src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr +++ b/src/test/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr @@ -11,7 +11,7 @@ error[E0596]: cannot borrow `not_mut` as mutable, as it is not declared as mutab --> $DIR/nested-binding-modes-mut.rs:9:5 | LL | let not_mut @ mut is_mut = 42; - | -------------------- help: consider changing this to be mutable: `mut not_mut` + | ------- help: consider changing this to be mutable: `mut not_mut` LL | &mut is_mut; LL | &mut not_mut; | ^^^^^^^^^^^^ cannot borrow as mutable diff --git a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr index 5beca04d2859..bac2db6ce825 100644 --- a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr +++ b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr @@ -35,7 +35,7 @@ error[E0502]: cannot borrow `arr[..]` as mutable because it is also borrowed as --> $DIR/borrowck-move-ref-pattern.rs:13:16 | LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; - | ---------------- immutable borrow occurs here + | ----------- immutable borrow occurs here ... LL | let [_, _, ref mut _x2, _x3, mut _x4] = arr; | ^^^^^^^^^^^ mutable borrow occurs here @@ -47,7 +47,7 @@ error[E0505]: cannot move out of `arr[..]` because it is borrowed --> $DIR/borrowck-move-ref-pattern.rs:13:29 | LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; - | ---------------- borrow of `arr[..]` occurs here + | ----------- borrow of `arr[..]` occurs here ... LL | let [_, _, ref mut _x2, _x3, mut _x4] = arr; | ^^^ move out of `arr[..]` occurs here @@ -59,7 +59,7 @@ error[E0505]: cannot move out of `arr[..]` because it is borrowed --> $DIR/borrowck-move-ref-pattern.rs:13:34 | LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; - | ---------------- borrow of `arr[..]` occurs here + | ----------- borrow of `arr[..]` occurs here ... LL | let [_, _, ref mut _x2, _x3, mut _x4] = arr; | ^^^^^^^ move out of `arr[..]` occurs here From 7ac124803f696b7e28d9fdae2f676093024de378 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Wed, 7 Sep 2022 03:59:47 +0900 Subject: [PATCH 4261/5092] do not suggest a semicolon for a macro without `!` --- compiler/rustc_parse/src/parser/expr.rs | 3 +++ ...-array.rs => do-not-suggest-semicolon-before-array.rs} | 0 ...tderr => do-not-suggest-semicolon-before-array.stderr} | 2 +- ...on-between-macro-without-exclamation-mark-and-array.rs | 3 +++ ...etween-macro-without-exclamation-mark-and-array.stderr | 8 ++++++++ ...e-array.fixed => suggest-semicolon-before-array.fixed} | 0 ...-before-array.rs => suggest-semicolon-before-array.rs} | 0 ...array.stderr => suggest-semicolon-before-array.stderr} | 2 +- 8 files changed, 16 insertions(+), 2 deletions(-) rename src/test/ui/parser/{do-not-suggest-suggest-semicolon-before-array.rs => do-not-suggest-semicolon-before-array.rs} (100%) rename src/test/ui/parser/{do-not-suggest-suggest-semicolon-before-array.stderr => do-not-suggest-semicolon-before-array.stderr} (76%) create mode 100644 src/test/ui/parser/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.rs create mode 100644 src/test/ui/parser/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.stderr rename src/test/ui/parser/{suggest-suggest-semicolon-before-array.fixed => suggest-semicolon-before-array.fixed} (100%) rename src/test/ui/parser/{suggest-suggest-semicolon-before-array.rs => suggest-semicolon-before-array.rs} (100%) rename src/test/ui/parser/{suggest-suggest-semicolon-before-array.stderr => suggest-semicolon-before-array.stderr} (75%) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index d4828a201207..10cd353062e8 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1977,6 +1977,9 @@ impl<'a> Parser<'a> { open_delim_span: Span, ) -> PResult<'a, ()> { if self.token.kind == token::Comma { + if !self.sess.source_map().is_multiline(prev_span.until(self.token.span)) { + return Ok(()); + } let mut snapshot = self.create_snapshot_for_diagnostic(); snapshot.bump(); match snapshot.parse_seq_to_before_end( diff --git a/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.rs b/src/test/ui/parser/do-not-suggest-semicolon-before-array.rs similarity index 100% rename from src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.rs rename to src/test/ui/parser/do-not-suggest-semicolon-before-array.rs diff --git a/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.stderr b/src/test/ui/parser/do-not-suggest-semicolon-before-array.stderr similarity index 76% rename from src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.stderr rename to src/test/ui/parser/do-not-suggest-semicolon-before-array.stderr index d6e8db803299..a9dd526321f5 100644 --- a/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.stderr +++ b/src/test/ui/parser/do-not-suggest-semicolon-before-array.stderr @@ -1,5 +1,5 @@ error: expected one of `.`, `?`, `]`, or an operator, found `,` - --> $DIR/do-not-suggest-suggest-semicolon-before-array.rs:5:5 + --> $DIR/do-not-suggest-semicolon-before-array.rs:5:5 | LL | [1, 3) | ^ ^ help: `]` may belong here diff --git a/src/test/ui/parser/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.rs b/src/test/ui/parser/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.rs new file mode 100644 index 000000000000..d6f7981813fc --- /dev/null +++ b/src/test/ui/parser/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.rs @@ -0,0 +1,3 @@ +fn main() { + let _x = vec[1, 2, 3]; //~ ERROR expected one of `.`, `?`, `]`, or an operator +} diff --git a/src/test/ui/parser/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.stderr b/src/test/ui/parser/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.stderr new file mode 100644 index 000000000000..2fe6a28eeb41 --- /dev/null +++ b/src/test/ui/parser/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.stderr @@ -0,0 +1,8 @@ +error: expected one of `.`, `?`, `]`, or an operator, found `,` + --> $DIR/do-not-suggest-semicolon-between-macro-without-exclamation-mark-and-array.rs:2:19 + | +LL | let _x = vec[1, 2, 3]; + | ^ expected one of `.`, `?`, `]`, or an operator + +error: aborting due to previous error + diff --git a/src/test/ui/parser/suggest-suggest-semicolon-before-array.fixed b/src/test/ui/parser/suggest-semicolon-before-array.fixed similarity index 100% rename from src/test/ui/parser/suggest-suggest-semicolon-before-array.fixed rename to src/test/ui/parser/suggest-semicolon-before-array.fixed diff --git a/src/test/ui/parser/suggest-suggest-semicolon-before-array.rs b/src/test/ui/parser/suggest-semicolon-before-array.rs similarity index 100% rename from src/test/ui/parser/suggest-suggest-semicolon-before-array.rs rename to src/test/ui/parser/suggest-semicolon-before-array.rs diff --git a/src/test/ui/parser/suggest-suggest-semicolon-before-array.stderr b/src/test/ui/parser/suggest-semicolon-before-array.stderr similarity index 75% rename from src/test/ui/parser/suggest-suggest-semicolon-before-array.stderr rename to src/test/ui/parser/suggest-semicolon-before-array.stderr index bf86b43554d1..8a33321fbd56 100644 --- a/src/test/ui/parser/suggest-suggest-semicolon-before-array.stderr +++ b/src/test/ui/parser/suggest-semicolon-before-array.stderr @@ -1,5 +1,5 @@ error: expected `;`, found `[` - --> $DIR/suggest-suggest-semicolon-before-array.rs:8:5 + --> $DIR/suggest-semicolon-before-array.rs:8:5 | LL | [1, 3] | ^ From ee74f925f57c866669c69eecaa5579c327031674 Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Tue, 6 Sep 2022 22:18:56 +0300 Subject: [PATCH 4262/5092] Replace manual impl with a derive macro as multipart suggestions are now supported by them --- compiler/rustc_infer/src/errors/mod.rs | 89 +++++++++++-------- .../infer/error_reporting/need_type_info.rs | 10 +-- 2 files changed, 55 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 5eedca78489b..f5519b989b64 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -147,55 +147,66 @@ pub enum SourceKindSubdiag<'a> { }, } -// Has to be implemented manually because multipart suggestions are not supported by the derive macro. -// Would be a part of `SourceKindSubdiag` otherwise. +#[derive(SessionSubdiagnostic)] pub enum SourceKindMultiSuggestion<'a> { + #[multipart_suggestion_verbose( + infer::source_kind_fully_qualified, + applicability = "has-placeholders" + )] FullyQualified { + #[suggestion_part(code = "{def_path}({adjustment}")] + span_lo: Span, + #[suggestion_part(code = "{successor_pos}")] + span_hi: Span, + def_path: String, + adjustment: &'a str, + successor_pos: &'a str, + }, + #[multipart_suggestion_verbose( + infer::source_kind_closure_return, + applicability = "has-placeholders" + )] + ClosureReturn { + #[suggestion_part(code = "{start_span_code}")] + start_span: Span, + start_span_code: String, + #[suggestion_part(code = "}}")] + end_span: Option, + }, +} + +impl<'a> SourceKindMultiSuggestion<'a> { + pub fn new_fully_qualified( span: Span, def_path: String, adjustment: &'a str, successor: (&'a str, BytePos), - }, - ClosureReturn { + ) -> Self { + Self::FullyQualified { + span_lo: span.shrink_to_lo(), + span_hi: span.shrink_to_hi().with_hi(successor.1), + def_path, + adjustment, + successor_pos: successor.0, + } + } + + pub fn new_closure_return( ty_info: String, data: &'a FnRetTy<'a>, should_wrap_expr: Option, - }, -} - -impl AddSubdiagnostic for SourceKindMultiSuggestion<'_> { - fn add_to_diagnostic(self, diag: &mut rustc_errors::Diagnostic) { - match self { - Self::FullyQualified { span, def_path, adjustment, successor } => { - let suggestion = vec![ - (span.shrink_to_lo(), format!("{def_path}({adjustment}")), - (span.shrink_to_hi().with_hi(successor.1), successor.0.to_string()), - ]; - diag.multipart_suggestion_verbose( - fluent::infer::source_kind_fully_qualified, - suggestion, - rustc_errors::Applicability::HasPlaceholders, - ); + ) -> Self { + let (arrow, post) = match data { + FnRetTy::DefaultReturn(_) => ("-> ", " "), + _ => ("", ""), + }; + let (start_span, start_span_code, end_span) = match should_wrap_expr { + Some(end_span) => { + (data.span(), format!("{}{}{}{{ ", arrow, ty_info, post), Some(end_span)) } - Self::ClosureReturn { ty_info, data, should_wrap_expr } => { - let (arrow, post) = match data { - FnRetTy::DefaultReturn(_) => ("-> ", " "), - _ => ("", ""), - }; - let suggestion = match should_wrap_expr { - Some(end_span) => vec![ - (data.span(), format!("{}{}{}{{ ", arrow, ty_info, post)), - (end_span, " }".to_string()), - ], - None => vec![(data.span(), format!("{}{}{}", arrow, ty_info, post))], - }; - diag.multipart_suggestion_verbose( - fluent::infer::source_kind_closure_return, - suggestion, - rustc_errors::Applicability::HasPlaceholders, - ); - } - } + None => (data.span(), format!("{}{}{}", arrow, ty_info, post), None), + }; + Self::ClosureReturn { start_span, start_span_code, end_span } } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 232b9b11455d..b0f5897e34b0 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -511,20 +511,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { _ => "", }; - multi_suggestions.push(SourceKindMultiSuggestion::FullyQualified { - span: receiver.span, + multi_suggestions.push(SourceKindMultiSuggestion::new_fully_qualified( + receiver.span, def_path, adjustment, successor, - }); + )); } InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => { let ty_info = ty_to_string(self, ty); - multi_suggestions.push(SourceKindMultiSuggestion::ClosureReturn { + multi_suggestions.push(SourceKindMultiSuggestion::new_closure_return( ty_info, data, should_wrap_expr, - }); + )); } } match error_code { From 3d70be7240b826c54411c76d18d3b203f657425a Mon Sep 17 00:00:00 2001 From: Nikita Tomashevich Date: Tue, 6 Sep 2022 22:55:49 +0300 Subject: [PATCH 4263/5092] Whoops forgot a space --- compiler/rustc_infer/src/errors/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index f5519b989b64..d232a1864624 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -170,7 +170,7 @@ pub enum SourceKindMultiSuggestion<'a> { #[suggestion_part(code = "{start_span_code}")] start_span: Span, start_span_code: String, - #[suggestion_part(code = "}}")] + #[suggestion_part(code = " }}")] end_span: Option, }, } From 71b40b9dd3feddd7132073cba3de32da49402233 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 6 Sep 2022 14:29:46 -0700 Subject: [PATCH 4264/5092] rustdoc: remove unused CSS `#main-content > .since` I missed one from 096efc29f1be25daca6675f5f7684780ff294613. --- src/librustdoc/html/static/css/rustdoc.css | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 3502d97d470f..fcb357e8d8ec 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -704,9 +704,6 @@ pre, .rustdoc.source .example-wrap { #main-content { position: relative; } -#main-content > .since { - top: inherit; -} .content table { border-spacing: 0 5px; From bd0eeb3f041cc57dad3ac40ed6cfcc08f1055638 Mon Sep 17 00:00:00 2001 From: Stanislav Date: Wed, 7 Sep 2022 03:01:06 +0300 Subject: [PATCH 4265/5092] Update crates/ide/src/references.rs Co-authored-by: Lukas Wirth --- crates/ide/src/references.rs | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 53a7a3a21730..d4c431f75f70 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -116,19 +116,10 @@ pub(crate) fn find_all_refs( fn retain_import_usages(usages: &mut UsageSearchResult, sema: &Semantics<'_, RootDatabase>) { for (file_id, refs) in &mut usages.references { - refs.retain(|x| { - let file_sema = sema.parse(file_id.clone()).syntax().clone(); - - let maybe_node = file_sema.child_or_token_at_range(x.range.clone()); - - if let Some(node) = maybe_node { - let res = match node { - syntax::NodeOrToken::Node(x) => !matches!(x.kind(), USE), - syntax::NodeOrToken::Token(_) => true, - }; - res - } else { - true + refs.retain(|it| { + match if.name.as_name_ref() { + Some(name_ref) => name_ref.syntax().ancestors().any(|it| !matches(it.kind(), USE)), + None => true, } }); } From 92d54f9b304092f20645d8ef0d54d7b724810428 Mon Sep 17 00:00:00 2001 From: Stanislav Date: Wed, 7 Sep 2022 03:23:21 +0300 Subject: [PATCH 4266/5092] typo and draft --- crates/ide/src/references.rs | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index d4c431f75f70..e495bfee5567 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -115,12 +115,32 @@ pub(crate) fn find_all_refs( } fn retain_import_usages(usages: &mut UsageSearchResult, sema: &Semantics<'_, RootDatabase>) { - for (file_id, refs) in &mut usages.references { + // todo use this https://github.com/rust-lang/rust-analyzer/blob/master/crates/rust-analyzer/src/config.rs#L432 + + for (_file_id, refs) in &mut usages.references { refs.retain(|it| { - match if.name.as_name_ref() { - Some(name_ref) => name_ref.syntax().ancestors().any(|it| !matches(it.kind(), USE)), + match it.name.as_name_ref() { + Some(name_ref) => name_ref.syntax().ancestors().any(|it_ref| { + dbg!(&it_ref); + !matches!(it_ref.kind(), USE) + }), None => true, } + + // this works: + // let file_sema = sema.parse(file_id.clone()).syntax().clone(); + + // let maybe_node = file_sema.child_or_token_at_range(it.range.clone()); + + // if let Some(node) = maybe_node { + // let res = match node { + // syntax::NodeOrToken::Node(x) => !matches!(x.kind(), USE), + // syntax::NodeOrToken::Token(_) => true, + // }; + // res + // } else { + // true + // } }); } } From 4856affd90df68b0b56dee73c431e9d9cdfc977a Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Thu, 1 Sep 2022 20:43:12 -0500 Subject: [PATCH 4267/5092] Make `HandleCycleError` an enum instead of a macro-generated closure - Add a `HandleCycleError` enum to rustc_query_system, along with a `handle_cycle_error` function - Move `Value` to rustc_query_system, so `handle_cycle_error` can use it - Move the `Value` impls from rustc_query_impl to rustc_middle. This is necessary due to orphan rules. --- compiler/rustc_middle/src/lib.rs | 1 + .../src/values.rs | 33 ++++++---------- compiler/rustc_query_impl/src/lib.rs | 3 -- compiler/rustc_query_impl/src/plumbing.rs | 24 ++++++------ compiler/rustc_query_system/src/error.rs | 7 ++++ compiler/rustc_query_system/src/lib.rs | 4 ++ .../rustc_query_system/src/query/config.rs | 5 ++- .../rustc_query_system/src/query/plumbing.rs | 38 +++++++++++++++++-- compiler/rustc_query_system/src/values.rs | 14 +++++++ 9 files changed, 86 insertions(+), 43 deletions(-) rename compiler/{rustc_query_impl => rustc_middle}/src/values.rs (65%) create mode 100644 compiler/rustc_query_system/src/values.rs diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index be9e5865e541..7edc9a16cc17 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -95,6 +95,7 @@ pub mod mir; pub mod thir; pub mod traits; pub mod ty; +mod values; pub mod util { pub mod bug; diff --git a/compiler/rustc_query_impl/src/values.rs b/compiler/rustc_middle/src/values.rs similarity index 65% rename from compiler/rustc_query_impl/src/values.rs rename to compiler/rustc_middle/src/values.rs index 0ed48f8d4a05..7fbe9ae2a841 100644 --- a/compiler/rustc_query_impl/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -1,39 +1,28 @@ -use super::QueryCtxt; -use rustc_middle::ty::{self, AdtSizedConstraint, Ty}; +use rustc_middle::ty::{self, AdtSizedConstraint, Ty, TyCtxt}; +use rustc_query_system::Value; -pub(super) trait Value<'tcx>: Sized { - fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> Self; -} - -impl<'tcx, T> Value<'tcx> for T { - default fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> T { - tcx.sess.abort_if_errors(); - bug!("Value::from_cycle_error called without errors"); - } -} - -impl<'tcx> Value<'tcx> for Ty<'_> { - fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> Self { +impl<'tcx> Value> for Ty<'_> { + fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self { // SAFETY: This is never called when `Self` is not `Ty<'tcx>`. // FIXME: Represent the above fact in the trait system somehow. unsafe { std::mem::transmute::, Ty<'_>>(tcx.ty_error()) } } } -impl<'tcx> Value<'tcx> for ty::SymbolName<'_> { - fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> Self { +impl<'tcx> Value> for ty::SymbolName<'_> { + fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self { // SAFETY: This is never called when `Self` is not `SymbolName<'tcx>`. // FIXME: Represent the above fact in the trait system somehow. unsafe { std::mem::transmute::, ty::SymbolName<'_>>(ty::SymbolName::new( - *tcx, "", + tcx, "", )) } } } -impl<'tcx> Value<'tcx> for AdtSizedConstraint<'_> { - fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> Self { +impl<'tcx> Value> for AdtSizedConstraint<'_> { + fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self { // SAFETY: This is never called when `Self` is not `AdtSizedConstraint<'tcx>`. // FIXME: Represent the above fact in the trait system somehow. unsafe { @@ -44,8 +33,8 @@ impl<'tcx> Value<'tcx> for AdtSizedConstraint<'_> { } } -impl<'tcx> Value<'tcx> for ty::Binder<'_, ty::FnSig<'_>> { - fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> Self { +impl<'tcx> Value> for ty::Binder<'_, ty::FnSig<'_>> { + fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self { let err = tcx.ty_error(); // FIXME(compiler-errors): It would be nice if we could get the // query key, so we could at least generate a fn signature that diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 8ea09880694e..26d397f70e0c 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -34,9 +34,6 @@ pub use rustc_query_system::query::{deadlock, QueryContext}; mod keys; use keys::Key; -mod values; -use self::values::Value; - pub use rustc_query_system::query::QueryConfig; pub(crate) use rustc_query_system::query::{QueryDescription, QueryVTable}; diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 274df5b5e5e9..1e375deb20d1 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -18,6 +18,7 @@ use rustc_query_system::query::{ force_query, QueryConfig, QueryContext, QueryDescription, QueryJobId, QueryMap, QuerySideEffects, QueryStackFrame, }; +use rustc_query_system::Value; use std::any::Any; use std::num::NonZeroU64; use thin_vec::ThinVec; @@ -174,21 +175,17 @@ impl<'tcx> QueryCtxt<'tcx> { } macro_rules! handle_cycle_error { - ([][$tcx: expr, $error:expr]) => {{ - $error.emit(); - Value::from_cycle_error($tcx) + ([]) => {{ + rustc_query_system::HandleCycleError::Error }}; - ([(fatal_cycle) $($rest:tt)*][$tcx:expr, $error:expr]) => {{ - $error.emit(); - $tcx.sess.abort_if_errors(); - unreachable!() + ([(fatal_cycle) $($rest:tt)*]) => {{ + rustc_query_system::HandleCycleError::Fatal }}; - ([(cycle_delay_bug) $($rest:tt)*][$tcx:expr, $error:expr]) => {{ - $error.delay_as_bug(); - Value::from_cycle_error($tcx) + ([(cycle_delay_bug) $($rest:tt)*]) => {{ + rustc_query_system::HandleCycleError::DelayBug }}; - ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => { - handle_cycle_error!([$($modifiers)*][$($args)*]) + ([$other:tt $($modifiers:tt)*]) => { + handle_cycle_error!([$($modifiers)*]) }; } @@ -320,6 +317,7 @@ fn force_from_dep_node<'tcx, Q>(tcx: TyCtxt<'tcx>, dep_node: DepNode) -> bool where Q: QueryDescription>, Q::Key: DepNodeParams>, + Q::Value: Value>, { if let Some(key) = Q::Key::recover(tcx, &dep_node) { #[cfg(debug_assertions)] @@ -418,7 +416,7 @@ macro_rules! define_queries { depth_limit: depth_limit!([$($modifiers)*]), dep_kind: dep_graph::DepKind::$name, hash_result: hash_result!([$($modifiers)*]), - handle_cycle_error: |tcx, mut error| handle_cycle_error!([$($modifiers)*][tcx, error]), + handle_cycle_error: handle_cycle_error!([$($modifiers)*]), compute, cache_on_disk, try_load_from_disk: Self::TRY_LOAD_FROM_DISK, diff --git a/compiler/rustc_query_system/src/error.rs b/compiler/rustc_query_system/src/error.rs index 5f992ec9e21e..3fb06cbedbd5 100644 --- a/compiler/rustc_query_system/src/error.rs +++ b/compiler/rustc_query_system/src/error.rs @@ -12,6 +12,13 @@ impl AddSubdiagnostic for CycleStack { } } +#[derive(Copy, Clone)] +pub enum HandleCycleError { + Error, + Fatal, + DelayBug, +} + #[derive(SessionSubdiagnostic)] pub enum StackCount { #[note(query_system::cycle_stack_single)] diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index 7067bc5f09cf..8a88b5c33407 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -20,3 +20,7 @@ pub mod dep_graph; mod error; pub mod ich; pub mod query; +mod values; + +pub use error::HandleCycleError; +pub use values::Value; diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs index ea38df836cbf..c63e110a62e3 100644 --- a/compiler/rustc_query_system/src/query/config.rs +++ b/compiler/rustc_query_system/src/query/config.rs @@ -2,12 +2,12 @@ use crate::dep_graph::DepNode; use crate::dep_graph::SerializedDepNodeIndex; +use crate::error::HandleCycleError; use crate::ich::StableHashingContext; use crate::query::caches::QueryCache; use crate::query::{QueryContext, QueryState}; use rustc_data_structures::fingerprint::Fingerprint; -use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed}; use std::fmt::Debug; use std::hash::Hash; @@ -19,6 +19,7 @@ pub trait QueryConfig { type Stored: Clone; } +#[derive(Copy, Clone)] pub struct QueryVTable { pub anon: bool, pub dep_kind: CTX::DepKind, @@ -28,7 +29,7 @@ pub struct QueryVTable { pub compute: fn(CTX::DepContext, K) -> V, pub hash_result: Option, &V) -> Fingerprint>, - pub handle_cycle_error: fn(CTX, DiagnosticBuilder<'_, ErrorGuaranteed>) -> V, + pub handle_cycle_error: HandleCycleError, pub try_load_from_disk: Option Option>, } diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 7bbc22e8293a..e39e39860cbb 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -7,6 +7,8 @@ use crate::query::caches::QueryCache; use crate::query::config::{QueryDescription, QueryVTable}; use crate::query::job::{report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo}; use crate::query::{QueryContext, QueryMap, QuerySideEffects, QueryStackFrame}; +use crate::values::Value; +use crate::HandleCycleError; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; #[cfg(parallel_compiler)] @@ -118,19 +120,46 @@ where fn mk_cycle( tcx: CTX, error: CycleError, - handle_cycle_error: fn(CTX, DiagnosticBuilder<'_, ErrorGuaranteed>) -> V, + handler: HandleCycleError, cache: &dyn crate::query::QueryStorage, ) -> R where CTX: QueryContext, - V: std::fmt::Debug, + V: std::fmt::Debug + Value, R: Clone, { let error = report_cycle(tcx.dep_context().sess(), error); - let value = handle_cycle_error(tcx, error); + let value = handle_cycle_error(*tcx.dep_context(), error, handler); cache.store_nocache(value) } +fn handle_cycle_error( + tcx: CTX, + mut error: DiagnosticBuilder<'_, ErrorGuaranteed>, + handler: HandleCycleError, +) -> V +where + CTX: DepContext, + V: Value, +{ + use HandleCycleError::*; + match handler { + Error => { + error.emit(); + Value::from_cycle_error(tcx) + } + Fatal => { + error.emit(); + tcx.sess().abort_if_errors(); + unreachable!() + } + DelayBug => { + error.delay_as_bug(); + Value::from_cycle_error(tcx) + } + } +} + impl<'tcx, K> JobOwner<'tcx, K> where K: Eq + Hash + Clone, @@ -336,6 +365,7 @@ fn try_execute_query( where C: QueryCache, C::Key: Clone + DepNodeParams, + C::Value: Value, CTX: QueryContext, { match JobOwner::<'_, C::Key>::try_start(&tcx, state, span, key.clone()) { @@ -686,6 +716,7 @@ pub fn get_query(tcx: CTX, span: Span, key: Q::Key, mode: QueryMode) -> where Q: QueryDescription, Q::Key: DepNodeParams, + Q::Value: Value, CTX: QueryContext, { let query = Q::make_vtable(tcx, &key); @@ -718,6 +749,7 @@ pub fn force_query(tcx: CTX, key: Q::Key, dep_node: DepNode, Q::Key: DepNodeParams, + Q::Value: Value, CTX: QueryContext, { // We may be concurrently trying both execute and force a query. diff --git a/compiler/rustc_query_system/src/values.rs b/compiler/rustc_query_system/src/values.rs new file mode 100644 index 000000000000..aeef66f86dac --- /dev/null +++ b/compiler/rustc_query_system/src/values.rs @@ -0,0 +1,14 @@ +use crate::dep_graph::DepContext; + +pub trait Value: Sized { + fn from_cycle_error(tcx: CTX) -> Self; +} + +impl Value for T { + default fn from_cycle_error(tcx: CTX) -> T { + tcx.sess().abort_if_errors(); + // Ideally we would use `bug!` here. But bug! is only defined in rustc_middle, and it's + // non-trivial to define it earlier. + panic!("Value::from_cycle_error called without errors"); + } +} From eba54c2fc9c15ec6480385486b7f711a7f2ca39e Mon Sep 17 00:00:00 2001 From: Stanislav Date: Wed, 7 Sep 2022 04:09:25 +0300 Subject: [PATCH 4268/5092] pretty solition works --- crates/ide/src/references.rs | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index e495bfee5567..6c8ae812c97c 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -79,7 +79,7 @@ pub(crate) fn find_all_refs( retain_adt_literal_usages(&mut usages, def, sema); } - retain_import_usages(&mut usages, sema); + retain_import_usages(&mut usages); let references = usages .into_iter() @@ -114,33 +114,15 @@ pub(crate) fn find_all_refs( } } -fn retain_import_usages(usages: &mut UsageSearchResult, sema: &Semantics<'_, RootDatabase>) { +fn retain_import_usages(usages: &mut UsageSearchResult) { // todo use this https://github.com/rust-lang/rust-analyzer/blob/master/crates/rust-analyzer/src/config.rs#L432 for (_file_id, refs) in &mut usages.references { - refs.retain(|it| { - match it.name.as_name_ref() { - Some(name_ref) => name_ref.syntax().ancestors().any(|it_ref| { - dbg!(&it_ref); - !matches!(it_ref.kind(), USE) - }), - None => true, + refs.retain(|it| match it.name.as_name_ref() { + Some(name_ref) => { + !name_ref.syntax().ancestors().any(|it_ref| matches!(it_ref.kind(), USE)) } - - // this works: - // let file_sema = sema.parse(file_id.clone()).syntax().clone(); - - // let maybe_node = file_sema.child_or_token_at_range(it.range.clone()); - - // if let Some(node) = maybe_node { - // let res = match node { - // syntax::NodeOrToken::Node(x) => !matches!(x.kind(), USE), - // syntax::NodeOrToken::Token(_) => true, - // }; - // res - // } else { - // true - // } + None => true, }); } } From 5d126a18b4cb779644bace0dfdadb31b058fb618 Mon Sep 17 00:00:00 2001 From: Joseph Ryan Date: Tue, 6 Sep 2022 18:27:17 -0700 Subject: [PATCH 4269/5092] Use proc-macro-srv from sysroot in rust-project.json --- crates/rust-analyzer/src/reload.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index f23bbca63876..e47f70fff39e 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -314,7 +314,9 @@ impl GlobalState { let mut args = args.clone(); let mut path = path.clone(); - if let ProjectWorkspace::Cargo { sysroot, .. } = ws { + if let ProjectWorkspace::Cargo { sysroot, .. } + | ProjectWorkspace::Json { sysroot, .. } = ws + { tracing::debug!("Found a cargo workspace..."); if let Some(sysroot) = sysroot.as_ref() { tracing::debug!("Found a cargo workspace with a sysroot..."); From d2c53caee218296482c11a56354688a9a7e9636f Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 29 Aug 2022 19:30:25 -0500 Subject: [PATCH 4270/5092] Move `Queries::new` out of the macro --- compiler/rustc_data_structures/src/sync.rs | 2 +- compiler/rustc_query_impl/src/plumbing.rs | 35 ++++++++++++---------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 258780ecaea2..9c0fb8265cff 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -48,7 +48,7 @@ cfg_if! { /// the native atomic types. /// You should use this type through the `AtomicU64`, `AtomicUsize`, etc, type aliases /// as it's not intended to be used separately. - #[derive(Debug)] + #[derive(Debug, Default)] pub struct Atomic(Cell); impl Atomic { diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 274df5b5e5e9..f8e165a1fd50 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -5,7 +5,7 @@ use crate::keys::Key; use crate::{on_disk_cache, Queries}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::Lock; +use rustc_data_structures::sync::{AtomicU64, Lock}; use rustc_errors::{Diagnostic, Handler}; use rustc_middle::dep_graph::{ self, DepKind, DepKindStruct, DepNode, DepNodeIndex, SerializedDepNodeIndex, @@ -501,9 +501,28 @@ macro_rules! define_queries { } } +use crate::{ExternProviders, OnDiskCache, Providers}; + +impl<'tcx> Queries<'tcx> { + pub fn new( + local_providers: Providers, + extern_providers: ExternProviders, + on_disk_cache: Option>, + ) -> Self { + Queries { + local_providers: Box::new(local_providers), + extern_providers: Box::new(extern_providers), + on_disk_cache, + jobs: AtomicU64::new(1), + ..Queries::default() + } + } +} + macro_rules! define_queries_struct { ( input: ($(([$($modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => { + #[derive(Default)] pub struct Queries<'tcx> { local_providers: Box, extern_providers: Box, @@ -516,20 +535,6 @@ macro_rules! define_queries_struct { } impl<'tcx> Queries<'tcx> { - pub fn new( - local_providers: Providers, - extern_providers: ExternProviders, - on_disk_cache: Option>, - ) -> Self { - Queries { - local_providers: Box::new(local_providers), - extern_providers: Box::new(extern_providers), - on_disk_cache, - jobs: AtomicU64::new(1), - $($name: Default::default()),* - } - } - pub(crate) fn try_collect_active_jobs( &'tcx self, tcx: TyCtxt<'tcx>, From 05886e28a4c3fbb7bc22d56bf5a52ba7cfa491d9 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 29 Aug 2022 17:45:18 -0500 Subject: [PATCH 4271/5092] Further simplify the macros generated by `rustc_queries` - Add a new `rustc_query_names` macro. This allows a much simpler syntax for the matchers in the macros passed to it as a callback. - Convert `define_dep_nodes` and `alloc_once` to use `rustc_query_names`. This is possible because they only use the names (despite the quite complicated matchers in `define_dep_nodes`, none of the other arguments are used). - Get rid of `rustc_dep_node_append`. --- compiler/rustc_macros/src/query.rs | 22 +++++++---------- .../rustc_middle/src/dep_graph/dep_node.rs | 24 ++++++------------- .../rustc_query_impl/src/profiling_support.rs | 4 ++-- 3 files changed, 18 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index f93fe2d51950..2a1bb10fdfc8 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -328,7 +328,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { let mut query_stream = quote! {}; let mut query_description_stream = quote! {}; - let mut dep_node_def_stream = quote! {}; + let mut all_names = quote! {}; let mut cached_queries = quote! {}; for query in queries.0 { @@ -344,6 +344,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { #name, }); } + all_names.extend(quote! { #name, }); let mut attributes = Vec::new(); @@ -400,35 +401,30 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { [#attribute_stream] fn #name(#arg) #result, }); - // Create a dep node for the query - dep_node_def_stream.extend(quote! { - [#attribute_stream] #name(#arg), - }); - add_query_description_impl(&query, &mut query_description_stream); } TokenStream::from(quote! { #[macro_export] macro_rules! rustc_query_append { - ($macro:ident !) => { + ($macro:ident!) => { $macro! { #query_stream } } } - macro_rules! rustc_dep_node_append { - ($macro:ident! [$($other:tt)*]) => { + #[macro_export] + macro_rules! rustc_query_names { + ($macro:ident! $( [$($other:tt)*] )?) => { $macro!( - $($other)* - - #dep_node_def_stream + $( $($other)* )? + #all_names ); } } #[macro_export] macro_rules! rustc_cached_queries { - ( $macro:ident! ) => { + ($macro:ident!) => { $macro!(#cached_queries); } } diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index 7718906ac4ee..f54d75c24e20 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -144,10 +144,7 @@ impl DepKind { macro_rules! define_dep_nodes { ( - $( - [$($attrs:tt)*] - $variant:ident $(( $tuple_arg_ty:ty $(,)? ))* - ,)* + $( $variant:ident, )* ) => ( #[macro_export] macro_rules! make_dep_kind_array { @@ -179,21 +176,14 @@ macro_rules! define_dep_nodes { ); } -rustc_dep_node_append!(define_dep_nodes![ +rustc_query_names!(define_dep_nodes![ // We use this for most things when incr. comp. is turned off. - [] Null, - + Null, // We use this to create a forever-red node. - [] Red, - - [anon] TraitSelect, - - // WARNING: if `Symbol` is changed, make sure you update `make_compile_codegen_unit` below. - [] CompileCodegenUnit(Symbol), - - // WARNING: if `MonoItem` is changed, make sure you update `make_compile_mono_item` below. - // Only used by rustc_codegen_cranelift - [] CompileMonoItem(MonoItem), + Red, + TraitSelect, + CompileCodegenUnit, + CompileMonoItem, ]); // WARNING: `construct` is generic and does not know that `CompileCodegenUnit` takes `Symbol`s as keys. diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs index 260af0d54081..a8e0210e8d66 100644 --- a/compiler/rustc_query_impl/src/profiling_support.rs +++ b/compiler/rustc_query_impl/src/profiling_support.rs @@ -307,7 +307,7 @@ pub fn alloc_self_profile_query_strings(tcx: TyCtxt<'_>) { macro_rules! alloc_once { ( - $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident($K:ty) -> $V:ty,)* + $($name:ident,)* ) => { $({ alloc_self_profile_query_strings_for_query_cache( @@ -320,5 +320,5 @@ pub fn alloc_self_profile_query_strings(tcx: TyCtxt<'_>) { } } - rustc_query_append! { alloc_once! } + rustc_query_names! { alloc_once! } } From c630c87ceb0c49c5dc2b1a6119c67e9033dce828 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Mon, 29 Aug 2022 18:46:56 -0500 Subject: [PATCH 4272/5092] Support doc-comments in `define_dep_nodes` --- compiler/rustc_macros/src/query.rs | 8 ++++++-- compiler/rustc_middle/src/dep_graph/dep_node.rs | 8 ++++---- compiler/rustc_query_impl/src/profiling_support.rs | 4 ++-- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 2a1bb10fdfc8..046a144913e0 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -344,7 +344,6 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { #name, }); } - all_names.extend(quote! { #name, }); let mut attributes = Vec::new(); @@ -394,13 +393,18 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { // be very useful. let span = name.span(); let attribute_stream = quote_spanned! {span=> #(#attributes),*}; - let doc_comments = query.doc_comments.iter(); + let doc_comments = &query.doc_comments; // Add the query to the group query_stream.extend(quote! { #(#doc_comments)* [#attribute_stream] fn #name(#arg) #result, }); + all_names.extend(quote! { + #(#doc_comments)* + #name, + }); + add_query_description_impl(&query, &mut query_description_stream); } diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index f54d75c24e20..21d174af4444 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -144,7 +144,7 @@ impl DepKind { macro_rules! define_dep_nodes { ( - $( $variant:ident, )* + $( $( #[$attr:meta] )* $variant:ident, )+ ) => ( #[macro_export] macro_rules! make_dep_kind_array { @@ -155,7 +155,7 @@ macro_rules! define_dep_nodes { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] #[allow(non_camel_case_types)] pub enum DepKind { - $($variant),* + $( $( #[$attr] )* $variant),* } fn dep_kind_from_label_string(label: &str) -> Result { @@ -177,9 +177,9 @@ macro_rules! define_dep_nodes { } rustc_query_names!(define_dep_nodes![ - // We use this for most things when incr. comp. is turned off. + /// We use this for most things when incr. comp. is turned off. Null, - // We use this to create a forever-red node. + /// We use this to create a forever-red node. Red, TraitSelect, CompileCodegenUnit, diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs index a8e0210e8d66..a9bb4756dbcc 100644 --- a/compiler/rustc_query_impl/src/profiling_support.rs +++ b/compiler/rustc_query_impl/src/profiling_support.rs @@ -307,7 +307,7 @@ pub fn alloc_self_profile_query_strings(tcx: TyCtxt<'_>) { macro_rules! alloc_once { ( - $($name:ident,)* + $( $( #[$attr:meta] )* $name:ident, )+ ) => { $({ alloc_self_profile_query_strings_for_query_cache( @@ -316,7 +316,7 @@ pub fn alloc_self_profile_query_strings(tcx: TyCtxt<'_>) { &tcx.query_caches.$name, &mut string_cache, ); - })* + })+ } } From 3a4e3c778889fdf2c4ccb7af26f1e81fc324e98b Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Tue, 6 Sep 2022 21:26:02 -0500 Subject: [PATCH 4273/5092] Get rid of the emitted `rustc_query_names` and `rustc_cached_queries` macro We can avoid these by adding slightly more information to `rustc_query_append` instead. --- compiler/rustc_macros/src/query.rs | 29 +++++-------------- .../rustc_middle/src/dep_graph/dep_node.rs | 19 ++++++------ compiler/rustc_query_impl/src/plumbing.rs | 20 ++++++++++--- .../rustc_query_impl/src/profiling_support.rs | 10 +++---- 4 files changed, 38 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 046a144913e0..505b2d62a79d 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -328,7 +328,6 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { let mut query_stream = quote! {}; let mut query_description_stream = quote! {}; - let mut all_names = quote! {}; let mut cached_queries = quote! {}; for query in queries.0 { @@ -384,6 +383,10 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { if let Some(remap_env_constness) = &modifiers.remap_env_constness { attributes.push(quote! { (#remap_env_constness) }); } + // Pass on the const modifier + if modifiers.cache.is_some() { + attributes.push(quote! { (cache) }); + } // This uses the span of the query definition for the commas, // which can be important if we later encounter any ambiguity @@ -400,38 +403,20 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { [#attribute_stream] fn #name(#arg) #result, }); - all_names.extend(quote! { - #(#doc_comments)* - #name, - }); - add_query_description_impl(&query, &mut query_description_stream); } TokenStream::from(quote! { #[macro_export] macro_rules! rustc_query_append { - ($macro:ident!) => { + ($macro:ident! $( [$($other:tt)*] )?) => { $macro! { + $( $($other)* )? #query_stream } } } - #[macro_export] - macro_rules! rustc_query_names { - ($macro:ident! $( [$($other:tt)*] )?) => { - $macro!( - $( $($other)* )? - #all_names - ); - } - } - #[macro_export] - macro_rules! rustc_cached_queries { - ($macro:ident!) => { - $macro!(#cached_queries); - } - } + #[macro_export] macro_rules! rustc_query_description { #query_description_stream diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index 21d174af4444..1fa0c6bababe 100644 --- a/compiler/rustc_middle/src/dep_graph/dep_node.rs +++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs @@ -144,8 +144,9 @@ impl DepKind { macro_rules! define_dep_nodes { ( - $( $( #[$attr:meta] )* $variant:ident, )+ - ) => ( + $($(#[$attr:meta])* + [$($modifiers:tt)*] fn $variant:ident($($K:tt)*) -> $V:ty,)*) => { + #[macro_export] macro_rules! make_dep_kind_array { ($mod:ident) => {[ $($mod::$variant()),* ]}; @@ -173,17 +174,17 @@ macro_rules! define_dep_nodes { pub const $variant: &str = stringify!($variant); )* } - ); + }; } -rustc_query_names!(define_dep_nodes![ +rustc_query_append!(define_dep_nodes![ /// We use this for most things when incr. comp. is turned off. - Null, + [] fn Null() -> (), /// We use this to create a forever-red node. - Red, - TraitSelect, - CompileCodegenUnit, - CompileMonoItem, + [] fn Red() -> (), + [] fn TraitSelect() -> (), + [] fn CompileCodegenUnit() -> (), + [] fn CompileMonoItem() -> (), ]); // WARNING: `construct` is generic and does not know that `CompileCodegenUnit` takes `Symbol`s as keys. diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 274df5b5e5e9..7e48125307a2 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -148,19 +148,31 @@ impl<'tcx> QueryCtxt<'tcx> { encoder: &mut on_disk_cache::CacheEncoder<'_, 'tcx>, query_result_index: &mut on_disk_cache::EncodedDepNodeIndex, ) { + macro_rules! expand_if_cached { + ([] $encode:expr) => {}; + ([(cache) $($rest:tt)*] $encode:expr) => { + $encode + }; + ([$other:tt $($modifiers:tt)*] $encode:expr) => { + expand_if_cached!([$($modifiers)*] $encode) + }; + } + macro_rules! encode_queries { - ($($query:ident,)*) => { + ( + $($(#[$attr:meta])* + [$($modifiers:tt)*] fn $query:ident($($K:tt)*) -> $V:ty,)*) => { $( - on_disk_cache::encode_query_results::<_, super::queries::$query<'_>>( + expand_if_cached!([$($modifiers)*] on_disk_cache::encode_query_results::<_, super::queries::$query<'_>>( self, encoder, query_result_index - ); + )); )* } } - rustc_cached_queries!(encode_queries!); + rustc_query_append!(encode_queries!); } pub fn try_print_query_stack( diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs index a9bb4756dbcc..98ec3bc09773 100644 --- a/compiler/rustc_query_impl/src/profiling_support.rs +++ b/compiler/rustc_query_impl/src/profiling_support.rs @@ -307,18 +307,18 @@ pub fn alloc_self_profile_query_strings(tcx: TyCtxt<'_>) { macro_rules! alloc_once { ( - $( $( #[$attr:meta] )* $name:ident, )+ - ) => { - $({ + $($(#[$attr:meta])* + [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => { + $( alloc_self_profile_query_strings_for_query_cache( tcx, stringify!($name), &tcx.query_caches.$name, &mut string_cache, ); - })+ + )+ } } - rustc_query_names! { alloc_once! } + rustc_query_append! { alloc_once! } } From 1c8de173238a02abeb5642c25c3cef1eea52ac18 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Wed, 7 Sep 2022 09:37:22 +0100 Subject: [PATCH 4274/5092] Rustdoc-Json: More accurate struct type. Closes #101489 --- src/etc/check_missing_items.py | 8 ++-- src/librustdoc/json/conversions.rs | 36 +++++----------- src/rustdoc-json-types/lib.rs | 42 +++++++++++++------ src/rustdoc-json-types/tests.rs | 4 +- src/test/rustdoc-json/nested.rs | 2 +- .../rustdoc-json/structs/plain_all_pub.rs | 11 +++++ .../rustdoc-json/structs/plain_doc_hidden.rs | 11 +++++ src/test/rustdoc-json/structs/plain_empty.rs | 9 ++-- .../rustdoc-json/structs/plain_pub_priv.rs | 9 ++++ src/test/rustdoc-json/structs/tuple.rs | 7 ++-- src/test/rustdoc-json/structs/tuple_empty.rs | 2 + .../rustdoc-json/structs/tuple_pub_priv.rs | 13 ++++++ src/test/rustdoc-json/structs/unit.rs | 7 ++-- .../rustdoc-json/structs/with_generics.rs | 16 +++---- .../rustdoc-json/structs/with_primitives.rs | 12 +++--- 15 files changed, 118 insertions(+), 71 deletions(-) create mode 100644 src/test/rustdoc-json/structs/plain_all_pub.rs create mode 100644 src/test/rustdoc-json/structs/plain_doc_hidden.rs create mode 100644 src/test/rustdoc-json/structs/plain_pub_priv.rs create mode 100644 src/test/rustdoc-json/structs/tuple_empty.rs create mode 100644 src/test/rustdoc-json/structs/tuple_pub_priv.rs diff --git a/src/etc/check_missing_items.py b/src/etc/check_missing_items.py index 27fb018aecad..991c881bae10 100644 --- a/src/etc/check_missing_items.py +++ b/src/etc/check_missing_items.py @@ -132,9 +132,11 @@ while work_list: work_list |= set(item["inner"]["items"]) - visited elif item["kind"] == "struct": check_generics(item["inner"]["generics"]) - work_list |= ( - set(item["inner"]["fields"]) | set(item["inner"]["impls"]) - ) - visited + work_list |= set(item["inner"]["impls"]) - visited + if "tuple" in item["inner"]["kind"]: + work_list |= set(filter(None, item["inner"]["kind"]["tuple"])) - visited + elif "plain" in item["inner"]["kind"]: + work_list |= set(item["inner"]["kind"]["plain"]["fields"]) - visited elif item["kind"] == "struct_field": check_type(item["inner"]) elif item["kind"] == "enum": diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index c2d3543942db..1177d482ac06 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -304,11 +304,19 @@ impl FromWithTcx for Struct { fn from_tcx(struct_: clean::Struct, tcx: TyCtxt<'_>) -> Self { let fields_stripped = struct_.has_stripped_entries(); let clean::Struct { struct_type, generics, fields } = struct_; + + let kind = match struct_type { + CtorKind::Fn => StructKind::Tuple(ids_keeping_stripped(fields, tcx)), + CtorKind::Const => { + assert!(fields.is_empty()); + StructKind::Unit + } + CtorKind::Fictive => StructKind::Plain { fields: ids(fields, tcx), fields_stripped }, + }; + Struct { - struct_type: from_ctor_kind(struct_type), + kind, generics: generics.into_tcx(tcx), - fields_stripped, - fields: ids(fields, tcx), impls: Vec::new(), // Added in JsonRenderer::item } } @@ -327,14 +335,6 @@ impl FromWithTcx for Union { } } -pub(crate) fn from_ctor_kind(struct_type: CtorKind) -> StructType { - match struct_type { - CtorKind::Fictive => StructType::Plain, - CtorKind::Fn => StructType::Tuple, - CtorKind::Const => StructType::Unit, - } -} - pub(crate) fn from_fn_header(header: &rustc_hir::FnHeader) -> Header { Header { async_: header.is_async(), @@ -644,20 +644,6 @@ impl FromWithTcx for Enum { } } -impl FromWithTcx for Struct { - fn from_tcx(struct_: clean::VariantStruct, tcx: TyCtxt<'_>) -> Self { - let fields_stripped = struct_.has_stripped_entries(); - let clean::VariantStruct { struct_type, fields } = struct_; - Struct { - struct_type: from_ctor_kind(struct_type), - generics: Generics { params: vec![], where_predicates: vec![] }, - fields_stripped, - fields: ids(fields, tcx), - impls: Vec::new(), - } - } -} - impl FromWithTcx for Variant { fn from_tcx(variant: clean::Variant, tcx: TyCtxt<'_>) -> Self { use clean::Variant::*; diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index eea62f3af5ab..13bafa506e4a 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -9,7 +9,7 @@ use std::path::PathBuf; use serde::{Deserialize, Serialize}; /// rustdoc format-version. -pub const FORMAT_VERSION: u32 = 20; +pub const FORMAT_VERSION: u32 = 21; /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information /// about the language items in the local crate, as well as info about external items to allow @@ -289,13 +289,39 @@ pub struct Union { #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Struct { - pub struct_type: StructType, + pub kind: StructKind, pub generics: Generics, - pub fields_stripped: bool, - pub fields: Vec, pub impls: Vec, } +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum StructKind { + /// A struct with no fields and no parentheses. + /// + /// ```rust + /// pub struct Unit; + /// ``` + Unit, + /// A struct with unnamed fields. + /// + /// ```rust + /// pub struct TupleStruct(i32); + /// pub struct EmptyTupleStruct(); + /// ``` + /// + /// All [`Id`]'s will point to [`ItemEnum::StructField`]. Private and + /// `#[doc(hidden)]` fields will be given as `None` + Tuple(Vec>), + /// A struct with nammed fields. + /// + /// ```rust + /// pub struct PlainStruct { x: i32 } + /// pub struct EmptyPlainStruct {} + /// ``` + Plain { fields: Vec, fields_stripped: bool }, +} + #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Enum { pub generics: Generics, @@ -357,14 +383,6 @@ pub struct Discriminant { pub value: String, } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[serde(rename_all = "snake_case")] -pub enum StructType { - Plain, - Tuple, - Unit, -} - #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Header { #[serde(rename = "const")] diff --git a/src/rustdoc-json-types/tests.rs b/src/rustdoc-json-types/tests.rs index e7f6447ed875..399ff54b2949 100644 --- a/src/rustdoc-json-types/tests.rs +++ b/src/rustdoc-json-types/tests.rs @@ -3,10 +3,8 @@ use super::*; #[test] fn test_struct_info_roundtrip() { let s = ItemEnum::Struct(Struct { - struct_type: StructType::Plain, generics: Generics { params: vec![], where_predicates: vec![] }, - fields_stripped: false, - fields: vec![], + kind: StructKind::Plain { fields: vec![], fields_stripped: false }, impls: vec![], }); diff --git a/src/test/rustdoc-json/nested.rs b/src/test/rustdoc-json/nested.rs index 73ec9392ce94..ee2d2efa960e 100644 --- a/src/test/rustdoc-json/nested.rs +++ b/src/test/rustdoc-json/nested.rs @@ -17,7 +17,7 @@ pub mod l1 { pub mod l3 { // @is "$.index[*][?(@.name=='L4')].kind" \"struct\" - // @is "$.index[*][?(@.name=='L4')].inner.struct_type" \"unit\" + // @is "$.index[*][?(@.name=='L4')].inner.kind" \"unit\" // @set l4_id = "$.index[*][?(@.name=='L4')].id" // @ismany "$.index[*][?(@.name=='l3')].inner.items[*]" $l4_id pub struct L4; diff --git a/src/test/rustdoc-json/structs/plain_all_pub.rs b/src/test/rustdoc-json/structs/plain_all_pub.rs new file mode 100644 index 000000000000..b86ab93c264d --- /dev/null +++ b/src/test/rustdoc-json/structs/plain_all_pub.rs @@ -0,0 +1,11 @@ +pub struct Demo { + pub x: i32, + pub y: i32, +} + +// @set x = "$.index[*][?(@.name=='x')].id" +// @set y = "$.index[*][?(@.name=='y')].id" +// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[0]" $x +// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[1]" $y +// @count "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[*]" 2 +// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields_stripped" false diff --git a/src/test/rustdoc-json/structs/plain_doc_hidden.rs b/src/test/rustdoc-json/structs/plain_doc_hidden.rs new file mode 100644 index 000000000000..7800b55a481a --- /dev/null +++ b/src/test/rustdoc-json/structs/plain_doc_hidden.rs @@ -0,0 +1,11 @@ +pub struct Demo { + pub x: i32, + #[doc(hidden)] + pub y: i32, +} + +// @set x = "$.index[*][?(@.name=='x')].id" +// @!has "$.index[*][?(@.name=='y')].id" +// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[0]" $x +// @count "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[*]" 1 +// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields_stripped" true diff --git a/src/test/rustdoc-json/structs/plain_empty.rs b/src/test/rustdoc-json/structs/plain_empty.rs index 2ad9e86096c3..1d01b8bc14a8 100644 --- a/src/test/rustdoc-json/structs/plain_empty.rs +++ b/src/test/rustdoc-json/structs/plain_empty.rs @@ -1,6 +1,5 @@ -// @has "$.index[*][?(@.name=='PlainEmpty')].visibility" \"public\" -// @has "$.index[*][?(@.name=='PlainEmpty')].kind" \"struct\" -// @has "$.index[*][?(@.name=='PlainEmpty')].inner.struct_type" \"plain\" -// @has "$.index[*][?(@.name=='PlainEmpty')].inner.fields_stripped" false -// @has "$.index[*][?(@.name=='PlainEmpty')].inner.fields" [] +// @is "$.index[*][?(@.name=='PlainEmpty')].visibility" \"public\" +// @is "$.index[*][?(@.name=='PlainEmpty')].kind" \"struct\" +// @is "$.index[*][?(@.name=='PlainEmpty')].inner.kind.plain.fields_stripped" false +// @is "$.index[*][?(@.name=='PlainEmpty')].inner.kind.plain.fields" [] pub struct PlainEmpty {} diff --git a/src/test/rustdoc-json/structs/plain_pub_priv.rs b/src/test/rustdoc-json/structs/plain_pub_priv.rs new file mode 100644 index 000000000000..9b771224d974 --- /dev/null +++ b/src/test/rustdoc-json/structs/plain_pub_priv.rs @@ -0,0 +1,9 @@ +pub struct Demo { + pub x: i32, + y: i32, +} + +// @set x = "$.index[*][?(@.name=='x')].id" +// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[0]" $x +// @count "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[*]" 1 +// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields_stripped" true diff --git a/src/test/rustdoc-json/structs/tuple.rs b/src/test/rustdoc-json/structs/tuple.rs index 91fac359422e..6bdb753ee013 100644 --- a/src/test/rustdoc-json/structs/tuple.rs +++ b/src/test/rustdoc-json/structs/tuple.rs @@ -1,5 +1,4 @@ -// @has "$.index[*][?(@.name=='Tuple')].visibility" \"public\" -// @has "$.index[*][?(@.name=='Tuple')].kind" \"struct\" -// @has "$.index[*][?(@.name=='Tuple')].inner.struct_type" \"tuple\" -// @has "$.index[*][?(@.name=='Tuple')].inner.fields_stripped" true +// @is "$.index[*][?(@.name=='Tuple')].visibility" \"public\" +// @is "$.index[*][?(@.name=='Tuple')].kind" \"struct\" +// @is "$.index[*][?(@.name=='Tuple')].inner.kind.tuple" '[null, null]' pub struct Tuple(u32, String); diff --git a/src/test/rustdoc-json/structs/tuple_empty.rs b/src/test/rustdoc-json/structs/tuple_empty.rs new file mode 100644 index 000000000000..0ad6a89547fc --- /dev/null +++ b/src/test/rustdoc-json/structs/tuple_empty.rs @@ -0,0 +1,2 @@ +// @is "$.index[*][?(@.name=='TupleUnit')].inner.kind.tuple" [] +pub struct TupleUnit(); diff --git a/src/test/rustdoc-json/structs/tuple_pub_priv.rs b/src/test/rustdoc-json/structs/tuple_pub_priv.rs new file mode 100644 index 000000000000..9d5a1d1c8be7 --- /dev/null +++ b/src/test/rustdoc-json/structs/tuple_pub_priv.rs @@ -0,0 +1,13 @@ +pub struct Demo( + i32, + /// field + pub i32, + #[doc(hidden)] i32, +); + +// @set field = "$.index[*][?(@.docs=='field')].id" + +// @is "$.index[*][?(@.name=='Demo')].inner.kind.tuple[0]" null +// @is "$.index[*][?(@.name=='Demo')].inner.kind.tuple[1]" $field +// @is "$.index[*][?(@.name=='Demo')].inner.kind.tuple[2]" null +// @count "$.index[*][?(@.name=='Demo')].inner.kind.tuple[*]" 3 diff --git a/src/test/rustdoc-json/structs/unit.rs b/src/test/rustdoc-json/structs/unit.rs index 85a515b5e78a..265709717212 100644 --- a/src/test/rustdoc-json/structs/unit.rs +++ b/src/test/rustdoc-json/structs/unit.rs @@ -1,5 +1,4 @@ -// @has "$.index[*][?(@.name=='Unit')].visibility" \"public\" -// @has "$.index[*][?(@.name=='Unit')].kind" \"struct\" -// @has "$.index[*][?(@.name=='Unit')].inner.struct_type" \"unit\" -// @has "$.index[*][?(@.name=='Unit')].inner.fields" [] +// @is "$.index[*][?(@.name=='Unit')].visibility" \"public\" +// @is "$.index[*][?(@.name=='Unit')].kind" \"struct\" +// @is "$.index[*][?(@.name=='Unit')].inner.kind" \"unit\" pub struct Unit; diff --git a/src/test/rustdoc-json/structs/with_generics.rs b/src/test/rustdoc-json/structs/with_generics.rs index b0ad1883f8a2..00474800a0e5 100644 --- a/src/test/rustdoc-json/structs/with_generics.rs +++ b/src/test/rustdoc-json/structs/with_generics.rs @@ -1,13 +1,13 @@ use std::collections::HashMap; -// @has "$.index[*][?(@.name=='WithGenerics')].visibility" \"public\" -// @has "$.index[*][?(@.name=='WithGenerics')].kind" \"struct\" -// @has "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[0].name" \"T\" -// @has "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[0].kind.type" -// @has "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[1].name" \"U\" -// @has "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[1].kind.type" -// @has "$.index[*][?(@.name=='WithGenerics')].inner.struct_type" \"plain\" -// @has "$.index[*][?(@.name=='WithGenerics')].inner.fields_stripped" true +// @is "$.index[*][?(@.name=='WithGenerics')].visibility" \"public\" +// @is "$.index[*][?(@.name=='WithGenerics')].kind" \"struct\" +// @is "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[0].name" \"T\" +// @is "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[0].kind.type.bounds" [] +// @is "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[1].name" \"U\" +// @is "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[1].kind.type.bounds" [] +// @is "$.index[*][?(@.name=='WithGenerics')].inner.kind.plain.fields_stripped" true +// @is "$.index[*][?(@.name=='WithGenerics')].inner.kind.plain.fields" [] pub struct WithGenerics { stuff: Vec, things: HashMap, diff --git a/src/test/rustdoc-json/structs/with_primitives.rs b/src/test/rustdoc-json/structs/with_primitives.rs index b74050dde786..9c5a37f3957c 100644 --- a/src/test/rustdoc-json/structs/with_primitives.rs +++ b/src/test/rustdoc-json/structs/with_primitives.rs @@ -1,9 +1,9 @@ -// @has "$.index[*][?(@.name=='WithPrimitives')].visibility" \"public\" -// @has "$.index[*][?(@.name=='WithPrimitives')].kind" \"struct\" -// @has "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].name" \"\'a\" -// @has "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].kind.lifetime.outlives" [] -// @has "$.index[*][?(@.name=='WithPrimitives')].inner.struct_type" \"plain\" -// @has "$.index[*][?(@.name=='WithPrimitives')].inner.fields_stripped" true +// @is "$.index[*][?(@.name=='WithPrimitives')].visibility" \"public\" +// @is "$.index[*][?(@.name=='WithPrimitives')].kind" \"struct\" +// @is "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].name" \"\'a\" +// @is "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].kind.lifetime.outlives" [] +// @is "$.index[*][?(@.name=='WithPrimitives')].inner.kind.plain.fields_stripped" true +// @is "$.index[*][?(@.name=='WithPrimitives')].inner.kind.plain.fields" [] pub struct WithPrimitives<'a> { num: u32, s: &'a str, From d8d3b83e3ae6ade8498862d8c110c302abf859d9 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 28 Aug 2022 00:10:06 +0300 Subject: [PATCH 4275/5092] rustc: Parameterize `ty::Visibility` over used ID It allows using `LocalDefId` instead of `DefId` when possible, and also encode cheaper `Visibility` into metadata. --- compiler/rustc_metadata/src/rmeta/decoder.rs | 15 +++- .../src/rmeta/decoder/cstore_impl.rs | 6 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 7 +- compiler/rustc_metadata/src/rmeta/mod.rs | 2 +- compiler/rustc_middle/src/metadata.rs | 3 +- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/ty/assoc.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 6 ++ compiler/rustc_middle/src/ty/mod.rs | 61 +++++++++------ compiler/rustc_middle/src/ty/parameterized.rs | 4 +- compiler/rustc_privacy/src/lib.rs | 76 +++++++++---------- .../rustc_resolve/src/build_reduced_graph.rs | 46 ++++++----- compiler/rustc_resolve/src/ident.rs | 13 ++-- compiler/rustc_resolve/src/imports.rs | 4 +- compiler/rustc_resolve/src/lib.rs | 16 ++-- compiler/rustc_span/src/def_id.rs | 6 ++ .../src/traits/error_reporting/mod.rs | 4 +- compiler/rustc_typeck/src/check/demand.rs | 2 +- compiler/rustc_typeck/src/check/expr.rs | 6 +- .../rustc_typeck/src/check/method/suggest.rs | 2 +- compiler/rustc_typeck/src/check/pat.rs | 2 +- src/librustdoc/clean/mod.rs | 6 +- src/tools/clippy/clippy_lints/src/default.rs | 2 +- src/tools/clippy/clippy_lints/src/derive.rs | 4 +- 24 files changed, 170 insertions(+), 127 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 6f026678170b..562246f4e8a1 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -911,8 +911,14 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { self.root.tables.generics_of.get(self, item_id).unwrap().decode((self, sess)) } - fn get_visibility(self, id: DefIndex) -> ty::Visibility { - self.root.tables.visibility.get(self, id).unwrap().decode(self) + fn get_visibility(self, id: DefIndex) -> ty::Visibility { + self.root + .tables + .visibility + .get(self, id) + .unwrap() + .decode(self) + .map_id(|index| self.local_def_id(index)) } fn get_trait_item_def_id(self, id: DefIndex) -> Option { @@ -1182,7 +1188,10 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .map(move |index| respan(self.get_span(index, sess), self.item_name(index))) } - fn get_struct_field_visibilities(self, id: DefIndex) -> impl Iterator + 'a { + fn get_struct_field_visibilities( + self, + id: DefIndex, + ) -> impl Iterator> + 'a { self.root .tables .children diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 6b447ebd9991..dede1b2122a3 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -210,7 +210,6 @@ provide! { tcx, def_id, other, cdata, lookup_const_stability => { table } lookup_default_body_stability => { table } lookup_deprecation_entry => { table } - visibility => { table } unused_generic_params => { table } opt_def_kind => { table_direct } impl_parent => { table } @@ -225,6 +224,7 @@ provide! { tcx, def_id, other, cdata, generator_kind => { table } trait_def => { table } + visibility => { cdata.get_visibility(def_id.index) } adt_def => { cdata.get_adt_def(def_id.index, tcx) } adt_destructor => { let _ = cdata; @@ -485,7 +485,7 @@ impl CStore { pub fn struct_field_visibilities_untracked( &self, def: DefId, - ) -> impl Iterator + '_ { + ) -> impl Iterator> + '_ { self.get_crate_data(def.krate).get_struct_field_visibilities(def.index) } @@ -493,7 +493,7 @@ impl CStore { self.get_crate_data(def.krate).get_ctor_def_id_and_kind(def.index) } - pub fn visibility_untracked(&self, def: DefId) -> Visibility { + pub fn visibility_untracked(&self, def: DefId) -> Visibility { self.get_crate_data(def.krate).get_visibility(def.index) } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 039486ba02c3..b807663b10fd 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1138,7 +1138,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.codegen_fn_attrs[def_id] <- self.tcx.codegen_fn_attrs(def_id)); } if should_encode_visibility(def_kind) { - record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id)); + let vis = + self.tcx.local_visibility(local_id).map_id(|def_id| def_id.local_def_index); + record!(self.tables.visibility[def_id] <- vis); } if should_encode_stability(def_kind) { self.encode_stability(def_id); @@ -1727,7 +1729,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.tables.opt_def_kind.set(LOCAL_CRATE.as_def_id().index, DefKind::Mod); record!(self.tables.def_span[LOCAL_CRATE.as_def_id()] <- tcx.def_span(LOCAL_CRATE.as_def_id())); self.encode_attrs(LOCAL_CRATE.as_def_id().expect_local()); - record!(self.tables.visibility[LOCAL_CRATE.as_def_id()] <- tcx.visibility(LOCAL_CRATE.as_def_id())); + let vis = tcx.local_visibility(CRATE_DEF_ID).map_id(|def_id| def_id.local_def_index); + record!(self.tables.visibility[LOCAL_CRATE.as_def_id()] <- vis); if let Some(stability) = stability { record!(self.tables.lookup_stability[LOCAL_CRATE.as_def_id()] <- stability); } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 6f849a58580e..748b3afec37c 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -338,7 +338,7 @@ define_tables! { children: Table>, opt_def_kind: Table, - visibility: Table>, + visibility: Table>>, def_span: Table>, def_ident_span: Table>, lookup_stability: Table>, diff --git a/compiler/rustc_middle/src/metadata.rs b/compiler/rustc_middle/src/metadata.rs index c8e78747d8e7..5ff014c7815a 100644 --- a/compiler/rustc_middle/src/metadata.rs +++ b/compiler/rustc_middle/src/metadata.rs @@ -2,6 +2,7 @@ use crate::ty; use rustc_hir::def::Res; use rustc_macros::HashStable; +use rustc_span::def_id::DefId; use rustc_span::symbol::Ident; use rustc_span::Span; @@ -18,7 +19,7 @@ pub struct ModChild { /// Local variables cannot be exported, so this `Res` doesn't need the ID parameter. pub res: Res, /// Visibility of the item. - pub vis: ty::Visibility, + pub vis: ty::Visibility, /// Span of the item. pub span: Span, /// A proper `macro_rules` item (not a reexport). diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 8e7bacca262e..4478b45cf143 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1607,7 +1607,7 @@ rustc_queries! { desc { "looking up late bound vars" } } - query visibility(def_id: DefId) -> ty::Visibility { + query visibility(def_id: DefId) -> ty::Visibility { desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) } separate_provide_extern } diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index c97156ac17ff..55ee5bd2f810 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -42,7 +42,7 @@ impl AssocItem { } #[inline] - pub fn visibility(&self, tcx: TyCtxt<'_>) -> Visibility { + pub fn visibility(&self, tcx: TyCtxt<'_>) -> Visibility { tcx.visibility(self.def_id) } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 262d59f8ff8a..c2e5decfc786 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -22,6 +22,7 @@ use crate::ty::{ FloatVar, FloatVid, GenericParamDefKind, InferConst, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy, PolyFnSig, Predicate, PredicateKind, PredicateS, ProjectionTy, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy, + Visibility, }; use rustc_ast as ast; use rustc_data_structures::fingerprint::Fingerprint; @@ -1728,6 +1729,11 @@ impl<'tcx> TyCtxt<'tcx> { .chain(self.crates(()).iter().copied()) .flat_map(move |cnum| self.traits_in_crate(cnum).iter().copied()) } + + #[inline] + pub fn local_visibility(self, def_id: LocalDefId) -> Visibility { + self.visibility(def_id.to_def_id()).expect_local() + } } /// A trait implemented for all `X<'a>` types that can be safely and diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a3f7880b9a56..e39a75400e7f 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -259,11 +259,11 @@ impl fmt::Display for ImplPolarity { } #[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, Encodable, Decodable, HashStable)] -pub enum Visibility { +pub enum Visibility { /// Visible everywhere (including in other crates). Public, /// Visible only in the given crate-local module. - Restricted(DefId), + Restricted(Id), } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)] @@ -354,28 +354,45 @@ impl<'tcx> DefIdTree for TyCtxt<'tcx> { } } -impl Visibility { - /// Returns `true` if an item with this visibility is accessible from the given block. - pub fn is_accessible_from(self, module: DefId, tree: T) -> bool { - let restriction = match self { - // Public items are visible everywhere. - Visibility::Public => return true, - // Restricted items are visible in an arbitrary local module. - Visibility::Restricted(other) if other.krate != module.krate => return false, - Visibility::Restricted(module) => module, - }; +impl Visibility { + pub fn is_public(self) -> bool { + matches!(self, Visibility::Public) + } - tree.is_descendant_of(module, restriction) + pub fn map_id(self, f: impl FnOnce(Id) -> OutId) -> Visibility { + match self { + Visibility::Public => Visibility::Public, + Visibility::Restricted(id) => Visibility::Restricted(f(id)), + } + } +} + +impl> Visibility { + pub fn to_def_id(self) -> Visibility { + self.map_id(Into::into) + } + + /// Returns `true` if an item with this visibility is accessible from the given module. + pub fn is_accessible_from(self, module: impl Into, tree: impl DefIdTree) -> bool { + match self { + // Public items are visible everywhere. + Visibility::Public => true, + Visibility::Restricted(id) => tree.is_descendant_of(module.into(), id.into()), + } } /// Returns `true` if this visibility is at least as accessible as the given visibility - pub fn is_at_least(self, vis: Visibility, tree: T) -> bool { - let vis_restriction = match vis { - Visibility::Public => return self == Visibility::Public, - Visibility::Restricted(module) => module, - }; + pub fn is_at_least(self, vis: Visibility>, tree: impl DefIdTree) -> bool { + match vis { + Visibility::Public => self.is_public(), + Visibility::Restricted(id) => self.is_accessible_from(id, tree), + } + } +} - self.is_accessible_from(vis_restriction, tree) +impl Visibility { + pub fn expect_local(self) -> Visibility { + self.map_id(|id| id.expect_local()) } // Returns `true` if this item is visible anywhere in the local crate. @@ -385,10 +402,6 @@ impl Visibility { Visibility::Restricted(def_id) => def_id.is_local(), } } - - pub fn is_public(self) -> bool { - matches!(self, Visibility::Public) - } } /// The crate variances map is computed during typeck and contains the @@ -1790,7 +1803,7 @@ pub enum VariantDiscr { pub struct FieldDef { pub did: DefId, pub name: Symbol, - pub vis: Visibility, + pub vis: Visibility, } impl PartialEq for FieldDef { diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index ca24c0d1ce38..9c8dc30e2db3 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -1,4 +1,4 @@ -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, DefIndex}; use rustc_index::vec::{Idx, IndexVec}; use crate::middle::exported_symbols::ExportedSymbol; @@ -60,7 +60,7 @@ trivially_parameterized_over_tcx! { ty::ImplPolarity, ty::ReprOptions, ty::TraitDef, - ty::Visibility, + ty::Visibility, ty::adjustment::CoerceUnsizedInfo, ty::fast_reject::SimplifiedTypeGen, rustc_ast::Attribute, diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index ba69bc23118b..b2966f0d2180 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1,6 +1,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(associated_type_defaults)] #![feature(control_flow_enum)] +#![feature(let_else)] #![feature(rustc_private)] #![feature(try_blocks)] #![recursion_limit = "256"] @@ -334,7 +335,9 @@ impl<'a, 'tcx, VL: VisibilityLike> DefIdVisitor<'tcx> for FindMin<'a, 'tcx, VL> _kind: &str, _descr: &dyn fmt::Display, ) -> ControlFlow { - self.min = VL::new_min(self, def_id); + if let Some(def_id) = def_id.as_local() { + self.min = VL::new_min(self, def_id); + } ControlFlow::CONTINUE } } @@ -342,7 +345,7 @@ impl<'a, 'tcx, VL: VisibilityLike> DefIdVisitor<'tcx> for FindMin<'a, 'tcx, VL> trait VisibilityLike: Sized { const MAX: Self; const SHALLOW: bool = false; - fn new_min(find: &FindMin<'_, '_, Self>, def_id: DefId) -> Self; + fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self; // Returns an over-approximation (`skip_assoc_tys` = true) of visibility due to // associated types for which we can't determine visibility precisely. @@ -357,8 +360,8 @@ trait VisibilityLike: Sized { } impl VisibilityLike for ty::Visibility { const MAX: Self = ty::Visibility::Public; - fn new_min(find: &FindMin<'_, '_, Self>, def_id: DefId) -> Self { - min(find.tcx.visibility(def_id), find.min, find.tcx) + fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self { + min(find.tcx.local_visibility(def_id), find.min, find.tcx) } } impl VisibilityLike for Option { @@ -373,15 +376,8 @@ impl VisibilityLike for Option { // both "shallow" version of its self type and "shallow" version of its trait if it exists // (which require reaching the `DefId`s in them). const SHALLOW: bool = true; - fn new_min(find: &FindMin<'_, '_, Self>, def_id: DefId) -> Self { - cmp::min( - if let Some(def_id) = def_id.as_local() { - find.access_levels.map.get(&def_id).copied() - } else { - Self::MAX - }, - find.min, - ) + fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self { + cmp::min(find.access_levels.map.get(&def_id).copied(), find.min) } } @@ -511,15 +507,15 @@ impl<'tcx> EmbargoVisitor<'tcx> { let module = self.tcx.hir().get_module(module_def_id).0; for item_id in module.item_ids { let def_kind = self.tcx.def_kind(item_id.def_id); - let vis = self.tcx.visibility(item_id.def_id); + let vis = self.tcx.local_visibility(item_id.def_id); self.update_macro_reachable_def(item_id.def_id, def_kind, vis, defining_mod); } if let Some(exports) = self.tcx.module_reexports(module_def_id) { for export in exports { - if export.vis.is_accessible_from(defining_mod.to_def_id(), self.tcx) { + if export.vis.is_accessible_from(defining_mod, self.tcx) { if let Res::Def(def_kind, def_id) = export.res { if let Some(def_id) = def_id.as_local() { - let vis = self.tcx.visibility(def_id.to_def_id()); + let vis = self.tcx.local_visibility(def_id); self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod); } } @@ -542,7 +538,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { match def_kind { // No type privacy, so can be directly marked as reachable. DefKind::Const | DefKind::Static(_) | DefKind::TraitAlias | DefKind::TyAlias => { - if vis.is_accessible_from(module.to_def_id(), self.tcx) { + if vis.is_accessible_from(module, self.tcx) { self.update(def_id, level); } } @@ -554,7 +550,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { DefKind::Macro(_) => { let item = self.tcx.hir().expect_item(def_id); if let hir::ItemKind::Macro(MacroDef { macro_rules: false, .. }, _) = item.kind { - if vis.is_accessible_from(module.to_def_id(), self.tcx) { + if vis.is_accessible_from(module, self.tcx) { self.update(def_id, level); } } @@ -565,7 +561,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { // hygiene these don't need to be marked reachable. The contents of // the module, however may be reachable. DefKind::Mod => { - if vis.is_accessible_from(module.to_def_id(), self.tcx) { + if vis.is_accessible_from(module, self.tcx) { self.update_macro_reachable(def_id, module); } } @@ -579,8 +575,8 @@ impl<'tcx> EmbargoVisitor<'tcx> { { for field in struct_def.fields() { let def_id = self.tcx.hir().local_def_id(field.hir_id); - let field_vis = self.tcx.visibility(def_id); - if field_vis.is_accessible_from(module.to_def_id(), self.tcx) { + let field_vis = self.tcx.local_visibility(def_id); + if field_vis.is_accessible_from(module, self.tcx) { self.reach(def_id, level).ty(); } } @@ -654,7 +650,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { hir::ItemKind::Impl(ref impl_) => { for impl_item_ref in impl_.items { if impl_.of_trait.is_some() - || self.tcx.visibility(impl_item_ref.id.def_id) == ty::Visibility::Public + || self.tcx.visibility(impl_item_ref.id.def_id).is_public() { self.update(impl_item_ref.id.def_id, item_level); } @@ -682,7 +678,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { } hir::ItemKind::ForeignMod { items, .. } => { for foreign_item in items { - if self.tcx.visibility(foreign_item.id.def_id) == ty::Visibility::Public { + if self.tcx.visibility(foreign_item.id.def_id).is_public() { self.update(foreign_item.id.def_id, item_level); } } @@ -1117,7 +1113,7 @@ impl<'tcx> TypePrivacyVisitor<'tcx> { } fn item_is_accessible(&self, did: DefId) -> bool { - self.tcx.visibility(did).is_accessible_from(self.current_item.to_def_id(), self.tcx) + self.tcx.visibility(did).is_accessible_from(self.current_item, self.tcx) } // Take node-id of an expression or pattern and check its type for privacy. @@ -1609,8 +1605,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { let mut found_pub_static = false; for impl_item_ref in impl_.items { if self.access_levels.is_reachable(impl_item_ref.id.def_id) - || self.tcx.visibility(impl_item_ref.id.def_id) - == ty::Visibility::Public + || self.tcx.visibility(impl_item_ref.id.def_id).is_public() { let impl_item = self.tcx.hir().impl_item(impl_item_ref.id); match impl_item_ref.kind { @@ -1780,17 +1775,17 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { ); } - let hir_id = match def_id.as_local() { - Some(def_id) => self.tcx.hir().local_def_id_to_hir_id(def_id), - None => return false, + let Some(local_def_id) = def_id.as_local() else { + return false; }; - let vis = self.tcx.visibility(def_id); + let vis = self.tcx.local_visibility(local_def_id); if !vis.is_at_least(self.required_visibility, self.tcx) { + let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id); let vis_descr = match vis { ty::Visibility::Public => "public", ty::Visibility::Restricted(vis_def_id) => { - if vis_def_id == self.tcx.parent_module(hir_id).to_def_id() { + if vis_def_id == self.tcx.parent_module(hir_id) { "private" } else if vis_def_id.is_top_level_module() { "crate-private" @@ -1906,7 +1901,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> { pub fn check_item(&mut self, id: ItemId) { let tcx = self.tcx; - let item_visibility = tcx.visibility(id.def_id); + let item_visibility = tcx.local_visibility(id.def_id); let def_kind = tcx.def_kind(id.def_id); match def_kind { @@ -1957,7 +1952,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> { let item = tcx.hir().item(id); if let hir::ItemKind::ForeignMod { items, .. } = item.kind { for foreign_item in items { - let vis = tcx.visibility(foreign_item.id.def_id); + let vis = tcx.local_visibility(foreign_item.id.def_id); self.check(foreign_item.id.def_id, vis).generics().predicates().ty(); } } @@ -1972,7 +1967,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> { for field in struct_def.fields() { let def_id = tcx.hir().local_def_id(field.hir_id); - let field_visibility = tcx.visibility(def_id); + let field_visibility = tcx.local_visibility(def_id); self.check(def_id, min(item_visibility, field_visibility, tcx)).ty(); } } @@ -1992,7 +1987,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> { } for impl_item_ref in impl_.items { let impl_item_vis = if impl_.of_trait.is_none() { - min(tcx.visibility(impl_item_ref.id.def_id), impl_vis, tcx) + min(tcx.local_visibility(impl_item_ref.id.def_id), impl_vis, tcx) } else { impl_vis }; @@ -2019,8 +2014,11 @@ pub fn provide(providers: &mut Providers) { }; } -fn visibility(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Visibility { - let def_id = def_id.expect_local(); +fn visibility(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Visibility { + local_visibility(tcx, def_id.expect_local()).to_def_id() +} + +fn local_visibility(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Visibility { match tcx.resolutions(()).visibilities.get(&def_id) { Some(vis) => *vis, None => { @@ -2037,7 +2035,7 @@ fn visibility(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Visibility { | Node::Item(hir::Item { kind: hir::ItemKind::Use(_, hir::UseKind::ListStem) | hir::ItemKind::OpaqueTy(..), .. - }) => ty::Visibility::Restricted(tcx.parent_module(hir_id).to_def_id()), + }) => ty::Visibility::Restricted(tcx.parent_module(hir_id)), // Visibilities of trait impl items are inherited from their traits // and are not filled in resolve. Node::ImplItem(impl_item) => { @@ -2050,7 +2048,7 @@ fn visibility(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Visibility { tcx.sess.delay_span_bug(tr.path.span, "trait without a def-id"); ty::Visibility::Public }, - |def_id| tcx.visibility(def_id), + |def_id| tcx.visibility(def_id).expect_local(), ), _ => span_bug!(impl_item.span, "the parent is not a trait impl"), } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 51e8c24b9c25..9cb735b36856 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -39,24 +39,26 @@ use std::ptr; type Res = def::Res; -impl<'a> ToNameBinding<'a> for (Module<'a>, ty::Visibility, Span, LocalExpnId) { +impl<'a, Id: Into> ToNameBinding<'a> + for (Module<'a>, ty::Visibility, Span, LocalExpnId) +{ fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> { arenas.alloc_name_binding(NameBinding { kind: NameBindingKind::Module(self.0), ambiguity: None, - vis: self.1, + vis: self.1.to_def_id(), span: self.2, expansion: self.3, }) } } -impl<'a> ToNameBinding<'a> for (Res, ty::Visibility, Span, LocalExpnId) { +impl<'a, Id: Into> ToNameBinding<'a> for (Res, ty::Visibility, Span, LocalExpnId) { fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> { arenas.alloc_name_binding(NameBinding { kind: NameBindingKind::Res(self.0, false), ambiguity: None, - vis: self.1, + vis: self.1.to_def_id(), span: self.2, expansion: self.3, }) @@ -70,7 +72,7 @@ impl<'a> ToNameBinding<'a> for (Res, ty::Visibility, Span, LocalExpnId, IsMacroE arenas.alloc_name_binding(NameBinding { kind: NameBindingKind::Res(self.0, true), ambiguity: None, - vis: self.1, + vis: self.1.to_def_id(), span: self.2, expansion: self.3, }) @@ -260,7 +262,9 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { self.r.visibilities[&def_id.expect_local()] } // Otherwise, the visibility is restricted to the nearest parent `mod` item. - _ => ty::Visibility::Restricted(self.parent_scope.module.nearest_parent_mod()), + _ => ty::Visibility::Restricted( + self.parent_scope.module.nearest_parent_mod().expect_local(), + ), }) } ast::VisibilityKind::Restricted { ref path, id, .. } => { @@ -311,7 +315,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { } else { let vis = ty::Visibility::Restricted(res.def_id()); if self.r.is_accessible_from(vis, parent_scope.module) { - Ok(vis) + Ok(vis.expect_local()) } else { Err(VisResolutionError::AncestorOnly(path.span)) } @@ -649,7 +653,9 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { true, // The whole `use` item item, - ty::Visibility::Restricted(self.parent_scope.module.nearest_parent_mod()), + ty::Visibility::Restricted( + self.parent_scope.module.nearest_parent_mod().expect_local(), + ), root_span, ); } @@ -765,10 +771,10 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { if let Some(ctor_node_id) = vdata.ctor_id() { // If the structure is marked as non_exhaustive then lower the visibility // to within the crate. - let mut ctor_vis = if vis == ty::Visibility::Public + let mut ctor_vis = if vis.is_public() && self.r.session.contains_name(&item.attrs, sym::non_exhaustive) { - ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id()) + ty::Visibility::Restricted(CRATE_DEF_ID) } else { vis }; @@ -785,7 +791,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { if ctor_vis.is_at_least(field_vis, &*self.r) { ctor_vis = field_vis; } - ret_fields.push(field_vis); + ret_fields.push(field_vis.to_def_id()); } let ctor_def_id = self.r.local_def_id(ctor_node_id); let ctor_res = Res::Def( @@ -795,7 +801,9 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion)); self.r.visibilities.insert(ctor_def_id, ctor_vis); - self.r.struct_constructors.insert(def_id, (ctor_res, ctor_vis, ret_fields)); + self.r + .struct_constructors + .insert(def_id, (ctor_res, ctor_vis.to_def_id(), ret_fields)); } } @@ -867,8 +875,8 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { } .map(|module| { let used = self.process_macro_use_imports(item, module); - let binding = - (module, ty::Visibility::Public, sp, expansion).to_name_binding(self.r.arenas); + let vis = ty::Visibility::::Public; + let binding = (module, vis, sp, expansion).to_name_binding(self.r.arenas); (used, Some(ModuleOrUniformRoot::Module(module)), binding) }) .unwrap_or((true, None, self.r.dummy_binding)); @@ -1117,7 +1125,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { root_span: span, span, module_path: Vec::new(), - vis: Cell::new(Some(ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id()))), + vis: Cell::new(Some(ty::Visibility::Restricted(CRATE_DEF_ID))), used: Cell::new(false), }) }; @@ -1263,7 +1271,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { let vis = if is_macro_export { ty::Visibility::Public } else { - ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id()) + ty::Visibility::Restricted(CRATE_DEF_ID) }; let binding = (res, vis, span, expansion).to_name_binding(self.r.arenas); self.r.set_binding_parent_module(binding, parent_scope.module); @@ -1294,7 +1302,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { } _ => self.resolve_visibility(&item.vis), }; - if vis != ty::Visibility::Public { + if !vis.is_public() { self.insert_unused_macro(ident, def_id, item.id, &rule_spans); } self.r.define(module, ident, MacroNS, (res, vis, span, expansion)); @@ -1507,10 +1515,10 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { self.r.visibilities.insert(def_id, vis); // If the variant is marked as non_exhaustive then lower the visibility to within the crate. - let ctor_vis = if vis == ty::Visibility::Public + let ctor_vis = if vis.is_public() && self.r.session.contains_name(&variant.attrs, sym::non_exhaustive) { - ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id()) + ty::Visibility::Restricted(CRATE_DEF_ID) } else { vis }; diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index b84a610833dd..2287aa1eb256 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -6,6 +6,7 @@ use rustc_middle::bug; use rustc_middle::ty; use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK; use rustc_session::lint::BuiltinLintDiagnostics; +use rustc_span::def_id::LocalDefId; use rustc_span::edition::Edition; use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext}; use rustc_span::symbol::{kw, Ident}; @@ -26,6 +27,8 @@ use Determinacy::*; use Namespace::*; use RibKind::*; +type Visibility = ty::Visibility; + impl<'a> Resolver<'a> { /// A generic scope visitor. /// Visits scopes in order to resolve some identifier in them or perform other actions. @@ -424,8 +427,7 @@ impl<'a> Resolver<'a> { let ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt)); let ok = |res, span, arenas| { Ok(( - (res, ty::Visibility::Public, span, LocalExpnId::ROOT) - .to_name_binding(arenas), + (res, Visibility::Public, span, LocalExpnId::ROOT).to_name_binding(arenas), Flags::empty(), )) }; @@ -438,7 +440,7 @@ impl<'a> Resolver<'a> { { let binding = ( Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper), - ty::Visibility::Public, + Visibility::Public, attr.span, expn_id, ) @@ -841,9 +843,8 @@ impl<'a> Resolver<'a> { if ns == TypeNS { if ident.name == kw::Crate || ident.name == kw::DollarCrate { let module = self.resolve_crate_root(ident); - let binding = - (module, ty::Visibility::Public, module.span, LocalExpnId::ROOT) - .to_name_binding(self.arenas); + let binding = (module, Visibility::Public, module.span, LocalExpnId::ROOT) + .to_name_binding(self.arenas); return Ok(binding); } else if ident.name == kw::Super || ident.name == kw::SelfLower { // FIXME: Implement these with renaming requirements so that e.g. diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 27745cee52df..c133c272bac2 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -214,7 +214,7 @@ impl<'a> Resolver<'a> { binding: &'a NameBinding<'a>, import: &'a Import<'a>, ) -> &'a NameBinding<'a> { - let import_vis = import.expect_vis(); + let import_vis = import.expect_vis().to_def_id(); let vis = if binding.vis.is_at_least(import_vis, self) || pub_use_of_private_extern_crate_hack(import, binding) { @@ -227,7 +227,7 @@ impl<'a> Resolver<'a> { if vis == import_vis || max_vis.get().map_or(true, |max_vis| vis.is_at_least(max_vis, self)) { - max_vis.set(Some(vis)) + max_vis.set(Some(vis.expect_local())) } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index aaa9ae6f3251..f7b7313d1049 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -648,7 +648,7 @@ pub struct NameBinding<'a> { ambiguity: Option<(&'a NameBinding<'a>, AmbiguityKind)>, expansion: LocalExpnId, span: Span, - vis: ty::Visibility, + vis: ty::Visibility, } pub trait ToNameBinding<'a> { @@ -1012,7 +1012,7 @@ pub struct Resolver<'a> { /// Table for mapping struct IDs into struct constructor IDs, /// it's not used during normal resolution, only for better error reporting. /// Also includes of list of each fields visibility - struct_constructors: DefIdMap<(Res, ty::Visibility, Vec)>, + struct_constructors: DefIdMap<(Res, ty::Visibility, Vec>)>, /// Features enabled for this crate. active_features: FxHashSet, @@ -1808,7 +1808,11 @@ impl<'a> Resolver<'a> { self.pat_span_map.insert(node, span); } - fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool { + fn is_accessible_from( + &self, + vis: ty::Visibility>, + module: Module<'a>, + ) -> bool { vis.is_accessible_from(module.nearest_parent_mod(), self) } @@ -1862,10 +1866,8 @@ impl<'a> Resolver<'a> { self.crate_loader.maybe_process_path_extern(ident.name)? }; let crate_root = self.expect_module(crate_id.as_def_id()); - Some( - (crate_root, ty::Visibility::Public, DUMMY_SP, LocalExpnId::ROOT) - .to_name_binding(self.arenas), - ) + let vis = ty::Visibility::::Public; + Some((crate_root, vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(self.arenas)) } }) } diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index a1533fe46b3e..ceb6b6c68b05 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -305,6 +305,12 @@ impl DefId { } } +impl From for DefId { + fn from(local: LocalDefId) -> DefId { + local.to_def_id() + } +} + impl Encodable for DefId { default fn encode(&self, s: &mut E) { self.krate.encode(s); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 9b8bb9e36201..efdb1ace1399 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1895,9 +1895,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { // FIXME(compiler-errors): This could be generalized, both to // be more granular, and probably look past other `#[fundamental]` // types, too. - self.tcx - .visibility(def.did()) - .is_accessible_from(body_id.owner.to_def_id(), self.tcx) + self.tcx.visibility(def.did()).is_accessible_from(body_id.owner, self.tcx) } else { true } diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index d078252ebd4e..e1d55ff82cba 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -375,7 +375,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let field_is_local = sole_field.did.is_local(); let field_is_accessible = - sole_field.vis.is_accessible_from(expr.hir_id.owner.to_def_id(), self.tcx) + sole_field.vis.is_accessible_from(expr.hir_id.owner, self.tcx) // Skip suggestions for unstable public fields (for example `Pin::pointer`) && matches!(self.tcx.eval_stability(sole_field.did, None, expr.span, None), EvalResult::Allow | EvalResult::Unmarked); diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index e4141647d7d2..0e6a8ef8265b 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1729,9 +1729,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let private_fields: Vec<&ty::FieldDef> = variant .fields .iter() - .filter(|field| { - !field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx) - }) + .filter(|field| !field.vis.is_accessible_from(tcx.parent_module(expr_id), tcx)) .collect(); if !private_fields.is_empty() { @@ -2343,7 +2341,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let ty::Adt(def, _) = output_ty.kind() && !def.is_enum() { def.non_enum_variant().fields.iter().any(|field| { field.ident(self.tcx) == ident - && field.vis.is_accessible_from(expr.hir_id.owner.to_def_id(), self.tcx) + && field.vis.is_accessible_from(expr.hir_id.owner, self.tcx) }) } else if let ty::Tuple(tys) = output_ty.kind() && let Ok(idx) = ident.as_str().parse::() diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 124ac5c24fa5..8065b848ad6f 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -1161,7 +1161,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => None, }); if let Some((field, field_ty)) = field_receiver { - let scope = tcx.parent_module(self.body_id).to_def_id(); + let scope = tcx.parent_module(self.body_id); let is_accessible = field.vis.is_accessible_from(scope, tcx); if is_accessible { diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 9096fc442d49..9fb915a056ab 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -1397,7 +1397,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter() .copied() .filter(|(field, _)| { - field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx) + field.vis.is_accessible_from(tcx.parent_module(pat.hir_id), tcx) && !matches!( tcx.eval_stability(field.did, None, DUMMY_SP, None), EvalResult::Deny { .. } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index be2227f47af6..944c44f017a5 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1777,7 +1777,7 @@ fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool { } } -pub(crate) fn clean_visibility(vis: ty::Visibility) -> Visibility { +pub(crate) fn clean_visibility(vis: ty::Visibility) -> Visibility { match vis { ty::Visibility::Public => Visibility::Public, ty::Visibility::Restricted(module) => Visibility::Restricted(module), @@ -2111,8 +2111,8 @@ fn clean_use_statement<'tcx>( // `pub(super)` or higher. If the current module is the top level // module, there isn't really a parent module, which makes the results // meaningless. In this case, we make sure the answer is `false`. - let is_visible_from_parent_mod = visibility.is_accessible_from(parent_mod.to_def_id(), cx.tcx) - && !current_mod.is_top_level_module(); + let is_visible_from_parent_mod = + visibility.is_accessible_from(parent_mod, cx.tcx) && !current_mod.is_top_level_module(); if pub_underscore { if let Some(ref inline) = inline_attr { diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs index 74f7df611778..4e68d6810e29 100644 --- a/src/tools/clippy/clippy_lints/src/default.rs +++ b/src/tools/clippy/clippy_lints/src/default.rs @@ -142,7 +142,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { if adt.is_struct(); let variant = adt.non_enum_variant(); if adt.did().is_local() || !variant.is_field_list_non_exhaustive(); - let module_did = cx.tcx.parent_module(stmt.hir_id).to_def_id(); + let module_did = cx.tcx.parent_module(stmt.hir_id); if variant .fields .iter() diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index 9ca443b7dff6..23c86482b46c 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -15,7 +15,7 @@ use rustc_middle::hir::nested_filter; use rustc_middle::traits::Reveal; use rustc_middle::ty::{ self, Binder, BoundConstness, GenericParamDefKind, ImplPolarity, ParamEnv, PredicateKind, TraitPredicate, TraitRef, - Ty, TyCtxt, Visibility, + Ty, TyCtxt, }; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; @@ -464,7 +464,7 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> { fn check_partial_eq_without_eq<'tcx>(cx: &LateContext<'tcx>, span: Span, trait_ref: &hir::TraitRef<'_>, ty: Ty<'tcx>) { if_chain! { if let ty::Adt(adt, substs) = ty.kind(); - if cx.tcx.visibility(adt.did()) == Visibility::Public; + if cx.tcx.visibility(adt.did()).is_public(); if let Some(eq_trait_def_id) = cx.tcx.get_diagnostic_item(sym::Eq); if let Some(def_id) = trait_ref.trait_def_id(); if cx.tcx.is_diagnostic_item(sym::PartialEq, def_id); From 2991a7c7153946e02db0928eb5bfb2a53607219f Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 21 Jul 2022 11:51:06 +0100 Subject: [PATCH 4276/5092] middle: comment -> doc comment Drive-by change of a regular comment to a documentation comment on `TyCtxt::is_suitable_region`. Signed-off-by: David Wood --- compiler/rustc_middle/src/ty/context.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 262d59f8ff8a..c97b96f66d15 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1596,7 +1596,7 @@ impl<'tcx> TyCtxt<'tcx> { }) } - // Returns the `DefId` and the `BoundRegionKind` corresponding to the given region. + /// Returns the `DefId` and the `BoundRegionKind` corresponding to the given region. pub fn is_suitable_region(self, region: Region<'tcx>) -> Option { let (suitable_region_binding_scope, bound_region) = match *region { ty::ReFree(ref free_region) => { From 9cef1ee11376be184b374e9ce9f4724bb9367892 Mon Sep 17 00:00:00 2001 From: Ikko Ashimine Date: Wed, 7 Sep 2022 19:32:28 +0900 Subject: [PATCH 4277/5092] Fix typo in pass_manager.rs overriden -> overridden --- compiler/rustc_mir_transform/src/pass_manager.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index 67ea5cfdb3c0..67dae71468f9 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -103,7 +103,7 @@ fn run_passes_inner<'tcx>( let name = pass.name(); // Gather information about what we should be doing for this pass - let overriden = + let overridden = overridden_passes.iter().rev().find(|(s, _)| s == &*name).map(|(_name, polarity)| { trace!( pass = %name, @@ -112,7 +112,7 @@ fn run_passes_inner<'tcx>( ); *polarity }); - let is_enabled = overriden.unwrap_or_else(|| pass.is_enabled(&tcx.sess)); + let is_enabled = overridden.unwrap_or_else(|| pass.is_enabled(&tcx.sess)); let new_phase = pass.phase_change(); let dump_enabled = (is_enabled && pass.is_mir_dump_enabled()) || new_phase.is_some(); let validate = (validate && is_enabled) From da464dc00e139225da81421567f67a03f4cca5ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 7 Sep 2022 13:21:38 +0200 Subject: [PATCH 4278/5092] Update LLVM used in x86 CI dist builds to `15.0.0` --- src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh index 1025f5bce802..fa780e1e45ea 100755 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh @@ -4,7 +4,7 @@ set -ex source shared.sh -LLVM=llvmorg-14.0.5 +LLVM=llvmorg-15.0.0 mkdir llvm-project cd llvm-project From 1dac6da408dac324e51e2e615483c72e358d9725 Mon Sep 17 00:00:00 2001 From: Maurits van Riezen <12109031+mousetail@users.noreply.github.com> Date: Wed, 7 Sep 2022 14:01:30 +0200 Subject: [PATCH 4279/5092] This example was broken The provided example to the `sign_plus` method on `fmt` is broken, it displays the `-` sign twice for negative numbers. --- library/core/src/fmt/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 9d3e9abf5577..0d370e384317 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -1819,7 +1819,7 @@ impl<'a> Formatter<'a> { /// write!(formatter, /// "Foo({}{})", /// if self.0 < 0 { '-' } else { '+' }, - /// self.0) + /// self.0.abs()) /// } else { /// write!(formatter, "Foo({})", self.0) /// } From 5f25154813b6eeb353bd7f0f758c4475cd239ffd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Tue, 6 Sep 2022 15:54:20 +0200 Subject: [PATCH 4280/5092] fix lld-wrapper lld flavor detection --- src/tools/lld-wrapper/src/main.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/tools/lld-wrapper/src/main.rs b/src/tools/lld-wrapper/src/main.rs index 1795f3d7fe5b..b5e977b2637d 100644 --- a/src/tools/lld-wrapper/src/main.rs +++ b/src/tools/lld-wrapper/src/main.rs @@ -11,9 +11,10 @@ //! obtained from the wrapper's name as the first two arguments. //! On Windows it spawns a `..\rust-lld.exe` child process. +use std::env::{self, consts::EXE_SUFFIX}; use std::fmt::Display; use std::path::{Path, PathBuf}; -use std::{env, process}; +use std::process; trait UnwrapOrExitWith { fn unwrap_or_exit_with(self, context: &str) -> T; @@ -42,7 +43,7 @@ impl UnwrapOrExitWith for Result { /// Exits if the parent directory cannot be determined. fn get_rust_lld_path(current_exe_path: &Path) -> PathBuf { let mut rust_lld_exe_name = "rust-lld".to_owned(); - rust_lld_exe_name.push_str(env::consts::EXE_SUFFIX); + rust_lld_exe_name.push_str(EXE_SUFFIX); let mut rust_lld_path = current_exe_path .parent() .unwrap_or_exit_with("directory containing current executable could not be determined") @@ -55,13 +56,14 @@ fn get_rust_lld_path(current_exe_path: &Path) -> PathBuf { /// Extract LLD flavor name from the lld-wrapper executable name. fn get_lld_flavor(current_exe_path: &Path) -> Result<&'static str, String> { - let stem = current_exe_path.file_stem(); - Ok(match stem.and_then(|s| s.to_str()) { + let file = current_exe_path.file_name(); + let stem = file.and_then(|s| s.to_str()).map(|s| s.trim_end_matches(EXE_SUFFIX)); + Ok(match stem { Some("ld.lld") => "gnu", Some("ld64.lld") => "darwin", Some("lld-link") => "link", Some("wasm-ld") => "wasm", - _ => return Err(format!("{:?}", stem)), + _ => return Err(format!("{:?}", file)), }) } From c805c62562e2d19116e8a4099c498276ae08aebf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Tue, 6 Sep 2022 17:19:46 +0200 Subject: [PATCH 4281/5092] fix compiletest detection of needs-rust-lld tests for both windows and unixes --- src/tools/compiletest/src/header.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 8f097f47b451..3ff1cbf20cd2 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -897,15 +897,27 @@ pub fn make_test_description( let has_hwasan = util::HWASAN_SUPPORTED_TARGETS.contains(&&*config.target); let has_memtag = util::MEMTAG_SUPPORTED_TARGETS.contains(&&*config.target); let has_shadow_call_stack = util::SHADOWCALLSTACK_SUPPORTED_TARGETS.contains(&&*config.target); - // for `-Z gcc-ld=lld` + + // For tests using the `needs-rust-lld` directive (e.g. for `-Zgcc-ld=lld`), we need to find + // whether `rust-lld` is present in the compiler under test. + // + // The --compile-lib-path is the path to host shared libraries, but depends on the OS. For + // example: + // - on linux, it can be /lib + // - on windows, it can be /bin + // + // However, `rust-lld` is only located under the lib path, so we look for it there. let has_rust_lld = config .compile_lib_path + .parent() + .expect("couldn't traverse to the parent of the specified --compile-lib-path") + .join("lib") .join("rustlib") .join(&config.target) .join("bin") - .join("gcc-ld") - .join(if config.host.contains("windows") { "ld.exe" } else { "ld" }) + .join(if config.host.contains("windows") { "rust-lld.exe" } else { "rust-lld" }) .exists(); + iter_header(path, src, &mut |revision, ln| { if revision.is_some() && revision != cfg { return; From 318d0eba8b5ffc02651ae40738e4276c1f4cf950 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Tue, 6 Sep 2022 23:39:37 +0200 Subject: [PATCH 4282/5092] ignore `-Zgcc-ld=lld` test on msvc now that CI correctly detects rust-lld in run-make tests, we ignore this test since it relies on `-Zgcc-ld=lld` which is not made to work on the windows-msvc targets: it requires a gcc flavor. --- src/test/run-make/issue-71519/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/run-make/issue-71519/Makefile b/src/test/run-make/issue-71519/Makefile index 4475649ca927..16d9a56e6bf7 100644 --- a/src/test/run-make/issue-71519/Makefile +++ b/src/test/run-make/issue-71519/Makefile @@ -1,5 +1,6 @@ include ../../run-make-fulldeps/tools.mk +# ignore-msvc # needs-rust-lld all: RUSTC_LOG=rustc_codegen_ssa::back::link=info $(RUSTC) -Z gcc-ld=lld -C link-args=-Wl,-v main.rs 2> $(TMPDIR)/output.txt From 38958aa8bdd2b46dd7f9213bda1c9c6433282a68 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 21 Jul 2022 16:19:22 +0100 Subject: [PATCH 4283/5092] ssa: implement `#[collapse_debuginfo]` Debuginfo line information for macro invocations are collapsed by default - line information are replaced by the line of the outermost expansion site. Using `-Zdebug-macros` disables this behaviour. When the `collapse_debuginfo` feature is enabled, the default behaviour is reversed so that debuginfo is not collapsed by default. In addition, the `#[collapse_debuginfo]` attribute is available and can be applied to macro definitions which will then have their line information collapsed. Signed-off-by: David Wood --- .../src/debuginfo/line_info.rs | 6 +- .../rustc_codegen_ssa/src/mir/debuginfo.rs | 8 +- .../locales/en-US/passes.ftl | 3 + compiler/rustc_expand/src/base.rs | 39 +-- compiler/rustc_feature/src/active.rs | 2 + compiler/rustc_feature/src/builtin_attrs.rs | 6 + compiler/rustc_middle/src/ty/mod.rs | 17 ++ compiler/rustc_passes/src/check_attr.rs | 14 ++ compiler/rustc_passes/src/errors.rs | 9 + compiler/rustc_span/src/hygiene.rs | 28 ++- compiler/rustc_span/src/lib.rs | 7 + compiler/rustc_span/src/symbol.rs | 1 + .../collapse-debuginfo-no-attr-flag.rs | 61 +++++ .../debuginfo/collapse-debuginfo-no-attr.rs | 60 +++++ .../collapse-debuginfo-with-attr-flag.rs | 63 +++++ .../debuginfo/collapse-debuginfo-with-attr.rs | 59 +++++ .../attributes/collapse-debuginfo-invalid.rs | 110 +++++++++ .../collapse-debuginfo-invalid.stderr | 222 ++++++++++++++++++ .../feature-gate-collapse_debuginfo.rs | 7 + .../feature-gate-collapse_debuginfo.stderr | 12 + 20 files changed, 699 insertions(+), 35 deletions(-) create mode 100644 src/test/debuginfo/collapse-debuginfo-no-attr-flag.rs create mode 100644 src/test/debuginfo/collapse-debuginfo-no-attr.rs create mode 100644 src/test/debuginfo/collapse-debuginfo-with-attr-flag.rs create mode 100644 src/test/debuginfo/collapse-debuginfo-with-attr.rs create mode 100644 src/test/ui/attributes/collapse-debuginfo-invalid.rs create mode 100644 src/test/ui/attributes/collapse-debuginfo-invalid.stderr create mode 100644 src/test/ui/feature-gates/feature-gate-collapse_debuginfo.rs create mode 100644 src/test/ui/feature-gates/feature-gate-collapse_debuginfo.stderr diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs index 3ad0c420eaf0..463de6a91c74 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs @@ -68,9 +68,9 @@ impl DebugContext { ) -> (Lrc, u64, u64) { // Based on https://github.com/rust-lang/rust/blob/e369d87b015a84653343032833d65d0545fd3f26/src/librustc_codegen_ssa/mir/mod.rs#L116-L131 // In order to have a good line stepping behavior in debugger, we overwrite debug - // locations of macro expansions with that of the outermost expansion site - // (unless the crate is being compiled with `-Z debug-macros`). - let span = if !span.from_expansion() || tcx.sess.opts.unstable_opts.debug_macros { + // locations of macro expansions with that of the outermost expansion site (when the macro is + // annotated with `#[collapse_debuginfo]` or when `-Zdebug-macros` is provided). + let span = if tcx.should_collapse_debuginfo(span) { span } else { // Walk up the macro expansion chain until we reach a non-expanded span. diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 8c3186efc630..157c1c82311d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -3,7 +3,7 @@ use rustc_index::vec::IndexVec; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir; use rustc_middle::ty; -use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; use rustc_session::config::DebugInfo; use rustc_span::symbol::{kw, Symbol}; use rustc_span::{BytePos, Span}; @@ -93,15 +93,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } /// In order to have a good line stepping behavior in debugger, we overwrite debug - /// locations of macro expansions with that of the outermost expansion site - /// (unless the crate is being compiled with `-Z debug-macros`). + /// locations of macro expansions with that of the outermost expansion site (when the macro is + /// annotated with `#[collapse_debuginfo]` or when `-Zdebug-macros` is provided). fn adjust_span_for_debugging(&self, mut span: Span) -> Span { // Bail out if debug info emission is not enabled. if self.debug_context.is_none() { return span; } - if span.from_expansion() && !self.cx.sess().opts.unstable_opts.debug_macros { + if self.cx.tcx().should_collapse_debuginfo(span) { // Walk up the macro expansion chain until we reach a non-expanded span. // We also stop at the function body level because no line stepping can occur // at the level above that. diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 7374f6d3f27d..556a6452f1a1 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -265,3 +265,6 @@ passes_rustc_lint_opt_deny_field_access = `#[rustc_lint_opt_deny_field_access]` passes_link_ordinal = attribute should be applied to a foreign function or static .label = not a foreign function or static + +passes_collapse_debuginfo = `collapse_debuginfo` attribute should be applied to macro definitions + .label = not a macro definition diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 2bb522caa2d4..e1da3ecdec7f 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -693,10 +693,6 @@ pub struct SyntaxExtension { pub span: Span, /// List of unstable features that are treated as stable inside this macro. pub allow_internal_unstable: Option>, - /// Suppresses the `unsafe_code` lint for code produced by this macro. - pub allow_internal_unsafe: bool, - /// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro. - pub local_inner_macros: bool, /// The macro's stability info. pub stability: Option, /// The macro's deprecation info. @@ -708,6 +704,13 @@ pub struct SyntaxExtension { /// Built-in macros have a couple of special properties like availability /// in `#[no_implicit_prelude]` modules, so we have to keep this flag. pub builtin_name: Option, + /// Suppresses the `unsafe_code` lint for code produced by this macro. + pub allow_internal_unsafe: bool, + /// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro. + pub local_inner_macros: bool, + /// Should debuginfo for the macro be collapsed to the outermost expansion site (in other + /// words, was the macro definition annotated with `#[collapse_debuginfo]`)? + pub collapse_debuginfo: bool, } impl SyntaxExtension { @@ -729,14 +732,15 @@ impl SyntaxExtension { SyntaxExtension { span: DUMMY_SP, allow_internal_unstable: None, - allow_internal_unsafe: false, - local_inner_macros: false, stability: None, deprecation: None, helper_attrs: Vec::new(), edition, builtin_name: None, kind, + allow_internal_unsafe: false, + local_inner_macros: false, + collapse_debuginfo: false, } } @@ -754,12 +758,13 @@ impl SyntaxExtension { let allow_internal_unstable = attr::allow_internal_unstable(sess, &attrs).collect::>(); - let mut local_inner_macros = false; - if let Some(macro_export) = sess.find_by_name(attrs, sym::macro_export) { - if let Some(l) = macro_export.meta_item_list() { - local_inner_macros = attr::list_contains_name(&l, sym::local_inner_macros); - } - } + let allow_internal_unsafe = sess.contains_name(attrs, sym::allow_internal_unsafe); + let local_inner_macros = sess + .find_by_name(attrs, sym::macro_export) + .and_then(|macro_export| macro_export.meta_item_list()) + .map_or(false, |l| attr::list_contains_name(&l, sym::local_inner_macros)); + let collapse_debuginfo = sess.contains_name(attrs, sym::collapse_debuginfo); + tracing::debug!(?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe); let (builtin_name, helper_attrs) = sess .find_by_name(attrs, sym::rustc_builtin_macro) @@ -801,13 +806,14 @@ impl SyntaxExtension { span, allow_internal_unstable: (!allow_internal_unstable.is_empty()) .then(|| allow_internal_unstable.into()), - allow_internal_unsafe: sess.contains_name(attrs, sym::allow_internal_unsafe), - local_inner_macros, stability: stability.map(|(s, _)| s), deprecation: attr::find_deprecation(&sess, attrs).map(|(d, _)| d), helper_attrs, edition, builtin_name, + allow_internal_unsafe, + local_inner_macros, + collapse_debuginfo, } } @@ -852,11 +858,12 @@ impl SyntaxExtension { call_site, self.span, self.allow_internal_unstable.clone(), - self.allow_internal_unsafe, - self.local_inner_macros, self.edition, macro_def_id, parent_module, + self.allow_internal_unsafe, + self.local_inner_macros, + self.collapse_debuginfo, ) } } diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index f71b3d59e2c0..8f795b62bbc6 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -336,6 +336,8 @@ declare_features! ( (active, closure_track_caller, "1.57.0", Some(87417), None), /// Allows to use the `#[cmse_nonsecure_entry]` attribute. (active, cmse_nonsecure_entry, "1.48.0", Some(75835), None), + /// Allows use of the `#[collapse_debuginfo]` attribute. + (active, collapse_debuginfo, "CURRENT_RUSTC_VERSION", Some(100758), None), /// Allows `async {}` expressions in const contexts. (active, const_async_blocks, "1.53.0", Some(85368), None), // Allows limiting the evaluation steps of const expressions diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 38a02cb1d7ce..8fa30b7f4025 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -481,6 +481,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ experimental!(deprecated_safe), ), + // `#[collapse_debuginfo]` + gated!( + collapse_debuginfo, Normal, template!(Word), WarnFollowing, + experimental!(collapse_debuginfo) + ), + // ========================================================================== // Internal attributes: Stability, deprecation, and unsafe: // ========================================================================== diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a3f7880b9a56..d77842e32dfe 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2373,6 +2373,23 @@ impl<'tcx> TyCtxt<'tcx> { (ident, scope) } + /// Returns `true` if the debuginfo for `span` should be collapsed to the outermost expansion + /// site. Only applies when `Span` is the result of macro expansion. + /// + /// - If the `collapse_debuginfo` feature is enabled then debuginfo is not collapsed by default + /// and only when a macro definition is annotated with `#[collapse_debuginfo]`. + /// - If `collapse_debuginfo` is not enabled, then debuginfo is collapsed by default. + /// + /// When `-Zdebug-macros` is provided then debuginfo will never be collapsed. + pub fn should_collapse_debuginfo(self, span: Span) -> bool { + !self.sess.opts.unstable_opts.debug_macros + && if self.features().collapse_debuginfo { + span.in_macro_expansion_with_collapse_debuginfo() + } else { + span.from_expansion() + } + } + pub fn is_object_safe(self, key: DefId) -> bool { self.object_safety_violations(key).is_empty() } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index d0b46aa2c453..4f73f71f5014 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -131,6 +131,7 @@ impl CheckAttrVisitor<'_> { | sym::rustc_if_this_changed | sym::rustc_then_this_would_need => self.check_rustc_dirty_clean(&attr), sym::cmse_nonsecure_entry => self.check_cmse_nonsecure_entry(attr, span, target), + sym::collapse_debuginfo => self.check_collapse_debuginfo(attr, span, target), sym::const_trait => self.check_const_trait(attr, span, target), sym::must_not_suspend => self.check_must_not_suspend(&attr, span, target), sym::must_use => self.check_must_use(hir_id, &attr, span, target), @@ -431,6 +432,19 @@ impl CheckAttrVisitor<'_> { } } + /// Checks if `#[collapse_debuginfo]` is applied to a macro. + fn check_collapse_debuginfo(&self, attr: &Attribute, span: Span, target: Target) -> bool { + match target { + Target::MacroDef => true, + _ => { + self.tcx + .sess + .emit_err(errors::CollapseDebuginfo { attr_span: attr.span, defn_span: span }); + false + } + } + } + /// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid. fn check_track_caller( &self, diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 901f56ad96d1..96cc8ae988cd 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -649,3 +649,12 @@ pub struct RustcLintOptDenyFieldAccess { #[label] pub span: Span, } + +#[derive(SessionDiagnostic)] +#[diag(passes::collapse_debuginfo)] +pub struct CollapseDebuginfo { + #[primary_span] + pub attr_span: Span, + #[label] + pub defn_span: Span, +} diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index e8ddb4ed17a3..191186af6fa0 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -944,12 +944,6 @@ pub struct ExpnData { /// internally without forcing the whole crate to opt-in /// to them. pub allow_internal_unstable: Option>, - /// Whether the macro is allowed to use `unsafe` internally - /// even if the user crate has `#![forbid(unsafe_code)]`. - pub allow_internal_unsafe: bool, - /// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) - /// for a given macro. - pub local_inner_macros: bool, /// Edition of the crate in which the macro is defined. pub edition: Edition, /// The `DefId` of the macro being invoked, @@ -957,6 +951,13 @@ pub struct ExpnData { pub macro_def_id: Option, /// The normal module (`mod`) in which the expanded macro was defined. pub parent_module: Option, + /// Suppresses the `unsafe_code` lint for code produced by this macro. + pub allow_internal_unsafe: bool, + /// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro. + pub local_inner_macros: bool, + /// Should debuginfo for the macro be collapsed to the outermost expansion site (in other + /// words, was the macro definition annotated with `#[collapse_debuginfo]`)? + pub collapse_debuginfo: bool, } impl !PartialEq for ExpnData {} @@ -969,11 +970,12 @@ impl ExpnData { call_site: Span, def_site: Span, allow_internal_unstable: Option>, - allow_internal_unsafe: bool, - local_inner_macros: bool, edition: Edition, macro_def_id: Option, parent_module: Option, + allow_internal_unsafe: bool, + local_inner_macros: bool, + collapse_debuginfo: bool, ) -> ExpnData { ExpnData { kind, @@ -981,12 +983,13 @@ impl ExpnData { call_site, def_site, allow_internal_unstable, - allow_internal_unsafe, - local_inner_macros, edition, macro_def_id, parent_module, disambiguator: 0, + allow_internal_unsafe, + local_inner_macros, + collapse_debuginfo, } } @@ -1004,12 +1007,13 @@ impl ExpnData { call_site, def_site: DUMMY_SP, allow_internal_unstable: None, - allow_internal_unsafe: false, - local_inner_macros: false, edition, macro_def_id, parent_module, disambiguator: 0, + allow_internal_unsafe: false, + local_inner_macros: false, + collapse_debuginfo: false, } } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 34e2e92bdfce..26b4ebeab1b3 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -564,6 +564,13 @@ impl Span { self.ctxt() != SyntaxContext::root() } + /// Returns `true` if `span` originates in a macro's expansion where debuginfo should be + /// collapsed. + pub fn in_macro_expansion_with_collapse_debuginfo(self) -> bool { + let outer_expn = self.ctxt().outer_expn_data(); + matches!(outer_expn.kind, ExpnKind::Macro(..)) && outer_expn.collapse_debuginfo + } + /// Returns `true` if `span` originates in a derive-macro's expansion. pub fn in_derive_expansion(self) -> bool { matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _)) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 75b1dfc856ac..e69a7d2ab341 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -487,6 +487,7 @@ symbols! { cmse_nonsecure_entry, coerce_unsized, cold, + collapse_debuginfo, column, column_macro, compare_and_swap, diff --git a/src/test/debuginfo/collapse-debuginfo-no-attr-flag.rs b/src/test/debuginfo/collapse-debuginfo-no-attr-flag.rs new file mode 100644 index 000000000000..413f6120105e --- /dev/null +++ b/src/test/debuginfo/collapse-debuginfo-no-attr-flag.rs @@ -0,0 +1,61 @@ +// ignore-lldb +#![feature(collapse_debuginfo)] + +// Test that line numbers are not replaced with those of the outermost expansion site when the +// `collapse_debuginfo` is active, `-Zdebug-macros` is provided and `#[collapse_debuginfo]` not +// being used. + +// compile-flags:-g -Zdebug-macros + +// === GDB TESTS =================================================================================== + +// gdb-command:run +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc1[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc2[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc3[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc4[...] +// gdb-command:continue + +fn one() { + println!("one"); +} +fn two() { + println!("two"); +} +fn three() { + println!("three"); +} +fn four() { + println!("four"); +} + +macro_rules! outer { + ($b:block) => { + one(); // #loc1 + inner!(); + $b + }; +} + +macro_rules! inner { + () => { + two(); // #loc2 + }; +} + +fn main() { + let ret = 0; // #break + outer!({ + three(); // #loc3 + four(); // #loc4 + }); + std::process::exit(ret); +} diff --git a/src/test/debuginfo/collapse-debuginfo-no-attr.rs b/src/test/debuginfo/collapse-debuginfo-no-attr.rs new file mode 100644 index 000000000000..230c8795be36 --- /dev/null +++ b/src/test/debuginfo/collapse-debuginfo-no-attr.rs @@ -0,0 +1,60 @@ +// ignore-lldb +#![feature(collapse_debuginfo)] + +// Test that line numbers are not replaced with those of the outermost expansion site when the +// `collapse_debuginfo` feature is active and the attribute is not provided. + +// compile-flags:-g + +// === GDB TESTS =================================================================================== + +// gdb-command:run +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc1[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc2[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc3[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc4[...] +// gdb-command:continue + +fn one() { + println!("one"); +} +fn two() { + println!("two"); +} +fn three() { + println!("three"); +} +fn four() { + println!("four"); +} + +macro_rules! outer { + ($b:block) => { + one(); // #loc1 + inner!(); + $b + }; +} + +macro_rules! inner { + () => { + two(); // #loc2 + }; +} + +fn main() { + let ret = 0; // #break + outer!({ + three(); // #loc3 + four(); // #loc4 + }); + std::process::exit(ret); +} diff --git a/src/test/debuginfo/collapse-debuginfo-with-attr-flag.rs b/src/test/debuginfo/collapse-debuginfo-with-attr-flag.rs new file mode 100644 index 000000000000..183cf537e85d --- /dev/null +++ b/src/test/debuginfo/collapse-debuginfo-with-attr-flag.rs @@ -0,0 +1,63 @@ +// ignore-lldb +#![feature(collapse_debuginfo)] + +// Test that line numbers are not replaced with those of the outermost expansion site when the +// `collapse_debuginfo` is active and `-Zdebug-macros` is provided, despite `#[collapse_debuginfo]` +// being used. + +// compile-flags:-g -Zdebug-macros + +// === GDB TESTS =================================================================================== + +// gdb-command:run +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc1[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc2[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc3[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc4[...] +// gdb-command:continue + +fn one() { + println!("one"); +} +fn two() { + println!("two"); +} +fn three() { + println!("three"); +} +fn four() { + println!("four"); +} + +#[collapse_debuginfo] +macro_rules! outer { + ($b:block) => { + one(); // #loc1 + inner!(); + $b + }; +} + +#[collapse_debuginfo] +macro_rules! inner { + () => { + two(); // #loc2 + }; +} + +fn main() { + let ret = 0; // #break + outer!({ + three(); // #loc3 + four(); // #loc4 + }); + std::process::exit(ret); +} diff --git a/src/test/debuginfo/collapse-debuginfo-with-attr.rs b/src/test/debuginfo/collapse-debuginfo-with-attr.rs new file mode 100644 index 000000000000..34d03c18bc72 --- /dev/null +++ b/src/test/debuginfo/collapse-debuginfo-with-attr.rs @@ -0,0 +1,59 @@ +// ignore-lldb +#![feature(collapse_debuginfo)] + +// Test that line numbers are replaced with those of the outermost expansion site when the +// `collapse_debuginfo` feature is active and the attribute is provided. + +// compile-flags:-g + +// === GDB TESTS =================================================================================== + +// gdb-command:run +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc1[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc2[...] +// gdb-command:next +// gdb-command:frame +// gdb-check:[...]#loc3[...] +// gdb-command:continue + +fn one() { + println!("one"); +} +fn two() { + println!("two"); +} +fn three() { + println!("three"); +} +fn four() { + println!("four"); +} + +#[collapse_debuginfo] +macro_rules! outer { + ($b:block) => { + one(); + inner!(); + $b + }; +} + +#[collapse_debuginfo] +macro_rules! inner { + () => { + two(); + }; +} + +fn main() { + let ret = 0; // #break + outer!({ // #loc1 + three(); // #loc2 + four(); // #loc3 + }); + std::process::exit(ret); +} diff --git a/src/test/ui/attributes/collapse-debuginfo-invalid.rs b/src/test/ui/attributes/collapse-debuginfo-invalid.rs new file mode 100644 index 000000000000..42d8982c1186 --- /dev/null +++ b/src/test/ui/attributes/collapse-debuginfo-invalid.rs @@ -0,0 +1,110 @@ +#![feature(collapse_debuginfo)] +#![feature(stmt_expr_attributes)] +#![feature(type_alias_impl_trait)] +#![no_std] + +// Test that the `#[collapse_debuginfo]` attribute can only be used on macro definitions. + +#[collapse_debuginfo] +//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions +extern crate std; + +#[collapse_debuginfo] +//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions +use std::collections::HashMap; + +#[collapse_debuginfo] +//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions +static FOO: u32 = 3; + +#[collapse_debuginfo] +//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions +const BAR: u32 = 3; + +#[collapse_debuginfo] +//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions +fn foo() { + let _ = #[collapse_debuginfo] || { }; +//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions + #[collapse_debuginfo] +//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions + let _ = 3; + let _ = #[collapse_debuginfo] 3; +//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions + match (3, 4) { + #[collapse_debuginfo] +//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions + _ => (), + } +} + +#[collapse_debuginfo] +//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions +mod bar { +} + +#[collapse_debuginfo] +//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions +type Map = HashMap; + +#[collapse_debuginfo] +//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions +enum Foo { + #[collapse_debuginfo] +//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions + Variant, +} + +#[collapse_debuginfo] +//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions +struct Bar { + #[collapse_debuginfo] +//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions + field: u32, +} + +#[collapse_debuginfo] +//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions +union Qux { + a: u32, + b: u16 +} + +#[collapse_debuginfo] +//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions +trait Foobar { + #[collapse_debuginfo] +//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions + type Bar; +} + +#[collapse_debuginfo] +//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions +type AFoobar = impl Foobar; + +impl Foobar for Bar { + type Bar = u32; +} + +fn constraining() -> AFoobar { + Bar { field: 3 } +} + +#[collapse_debuginfo] +//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions +impl Bar { + #[collapse_debuginfo] +//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions + const FOO: u32 = 3; + + #[collapse_debuginfo] +//~^ ERROR `collapse_debuginfo` attribute should be applied to macro definitions + fn bar(&self) {} +} + +#[collapse_debuginfo] +macro_rules! finally { + ($e:expr) => { $e } +} + +fn main() {} diff --git a/src/test/ui/attributes/collapse-debuginfo-invalid.stderr b/src/test/ui/attributes/collapse-debuginfo-invalid.stderr new file mode 100644 index 000000000000..01c476091082 --- /dev/null +++ b/src/test/ui/attributes/collapse-debuginfo-invalid.stderr @@ -0,0 +1,222 @@ +error: `collapse_debuginfo` attribute should be applied to macro definitions + --> $DIR/collapse-debuginfo-invalid.rs:8:1 + | +LL | #[collapse_debuginfo] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | extern crate std; + | ----------------- not a macro definition + +error: `collapse_debuginfo` attribute should be applied to macro definitions + --> $DIR/collapse-debuginfo-invalid.rs:12:1 + | +LL | #[collapse_debuginfo] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | use std::collections::HashMap; + | ------------------------------ not a macro definition + +error: `collapse_debuginfo` attribute should be applied to macro definitions + --> $DIR/collapse-debuginfo-invalid.rs:16:1 + | +LL | #[collapse_debuginfo] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | static FOO: u32 = 3; + | -------------------- not a macro definition + +error: `collapse_debuginfo` attribute should be applied to macro definitions + --> $DIR/collapse-debuginfo-invalid.rs:20:1 + | +LL | #[collapse_debuginfo] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | const BAR: u32 = 3; + | ------------------- not a macro definition + +error: `collapse_debuginfo` attribute should be applied to macro definitions + --> $DIR/collapse-debuginfo-invalid.rs:24:1 + | +LL | #[collapse_debuginfo] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | / fn foo() { +LL | | let _ = #[collapse_debuginfo] || { }; +LL | | +LL | | #[collapse_debuginfo] +... | +LL | | } +LL | | } + | |_- not a macro definition + +error: `collapse_debuginfo` attribute should be applied to macro definitions + --> $DIR/collapse-debuginfo-invalid.rs:27:13 + | +LL | let _ = #[collapse_debuginfo] || { }; + | ^^^^^^^^^^^^^^^^^^^^^ ------ not a macro definition + +error: `collapse_debuginfo` attribute should be applied to macro definitions + --> $DIR/collapse-debuginfo-invalid.rs:29:5 + | +LL | #[collapse_debuginfo] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | let _ = 3; + | ---------- not a macro definition + +error: `collapse_debuginfo` attribute should be applied to macro definitions + --> $DIR/collapse-debuginfo-invalid.rs:32:13 + | +LL | let _ = #[collapse_debuginfo] 3; + | ^^^^^^^^^^^^^^^^^^^^^ - not a macro definition + +error: `collapse_debuginfo` attribute should be applied to macro definitions + --> $DIR/collapse-debuginfo-invalid.rs:35:9 + | +LL | #[collapse_debuginfo] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | _ => (), + | ------- not a macro definition + +error: `collapse_debuginfo` attribute should be applied to macro definitions + --> $DIR/collapse-debuginfo-invalid.rs:41:1 + | +LL | #[collapse_debuginfo] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | / mod bar { +LL | | } + | |_- not a macro definition + +error: `collapse_debuginfo` attribute should be applied to macro definitions + --> $DIR/collapse-debuginfo-invalid.rs:46:1 + | +LL | #[collapse_debuginfo] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | type Map = HashMap; + | ----------------------------- not a macro definition + +error: `collapse_debuginfo` attribute should be applied to macro definitions + --> $DIR/collapse-debuginfo-invalid.rs:50:1 + | +LL | #[collapse_debuginfo] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | / enum Foo { +LL | | #[collapse_debuginfo] +LL | | +LL | | Variant, +LL | | } + | |_- not a macro definition + +error: `collapse_debuginfo` attribute should be applied to macro definitions + --> $DIR/collapse-debuginfo-invalid.rs:53:5 + | +LL | #[collapse_debuginfo] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | Variant, + | ------- not a macro definition + +error: `collapse_debuginfo` attribute should be applied to macro definitions + --> $DIR/collapse-debuginfo-invalid.rs:58:1 + | +LL | #[collapse_debuginfo] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | / struct Bar { +LL | | #[collapse_debuginfo] +LL | | +LL | | field: u32, +LL | | } + | |_- not a macro definition + +error: `collapse_debuginfo` attribute should be applied to macro definitions + --> $DIR/collapse-debuginfo-invalid.rs:61:5 + | +LL | #[collapse_debuginfo] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | field: u32, + | ---------- not a macro definition + +error: `collapse_debuginfo` attribute should be applied to macro definitions + --> $DIR/collapse-debuginfo-invalid.rs:66:1 + | +LL | #[collapse_debuginfo] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | / union Qux { +LL | | a: u32, +LL | | b: u16 +LL | | } + | |_- not a macro definition + +error: `collapse_debuginfo` attribute should be applied to macro definitions + --> $DIR/collapse-debuginfo-invalid.rs:73:1 + | +LL | #[collapse_debuginfo] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | / trait Foobar { +LL | | #[collapse_debuginfo] +LL | | +LL | | type Bar; +LL | | } + | |_- not a macro definition + +error: `collapse_debuginfo` attribute should be applied to macro definitions + --> $DIR/collapse-debuginfo-invalid.rs:81:1 + | +LL | #[collapse_debuginfo] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | type AFoobar = impl Foobar; + | --------------------------- not a macro definition + +error: `collapse_debuginfo` attribute should be applied to macro definitions + --> $DIR/collapse-debuginfo-invalid.rs:93:1 + | +LL | #[collapse_debuginfo] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | / impl Bar { +LL | | #[collapse_debuginfo] +LL | | +LL | | const FOO: u32 = 3; +... | +LL | | fn bar(&self) {} +LL | | } + | |_- not a macro definition + +error: `collapse_debuginfo` attribute should be applied to macro definitions + --> $DIR/collapse-debuginfo-invalid.rs:76:5 + | +LL | #[collapse_debuginfo] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | type Bar; + | --------- not a macro definition + +error: `collapse_debuginfo` attribute should be applied to macro definitions + --> $DIR/collapse-debuginfo-invalid.rs:96:5 + | +LL | #[collapse_debuginfo] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | const FOO: u32 = 3; + | ------------------- not a macro definition + +error: `collapse_debuginfo` attribute should be applied to macro definitions + --> $DIR/collapse-debuginfo-invalid.rs:100:5 + | +LL | #[collapse_debuginfo] + | ^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | fn bar(&self) {} + | ---------------- not a macro definition + +error: aborting due to 22 previous errors + diff --git a/src/test/ui/feature-gates/feature-gate-collapse_debuginfo.rs b/src/test/ui/feature-gates/feature-gate-collapse_debuginfo.rs new file mode 100644 index 000000000000..f73bf579f6d1 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-collapse_debuginfo.rs @@ -0,0 +1,7 @@ +#[collapse_debuginfo] +//~^ ERROR the `#[collapse_debuginfo]` attribute is an experimental feature +macro_rules! foo { + ($e:expr) => { $e } +} + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-collapse_debuginfo.stderr b/src/test/ui/feature-gates/feature-gate-collapse_debuginfo.stderr new file mode 100644 index 000000000000..2cbde893af9b --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-collapse_debuginfo.stderr @@ -0,0 +1,12 @@ +error[E0658]: the `#[collapse_debuginfo]` attribute is an experimental feature + --> $DIR/feature-gate-collapse_debuginfo.rs:1:1 + | +LL | #[collapse_debuginfo] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #100758 for more information + = help: add `#![feature(collapse_debuginfo)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. From 832c7af0ea93ec0d0dd121cf0988d82621582475 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 7 Sep 2022 13:14:27 +0100 Subject: [PATCH 4284/5092] Don't break windows/rand for miri --- library/std/src/sys/windows/rand.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/library/std/src/sys/windows/rand.rs b/library/std/src/sys/windows/rand.rs index 3dfa8dba9774..d6cd8f802716 100644 --- a/library/std/src/sys/windows/rand.rs +++ b/library/std/src/sys/windows/rand.rs @@ -38,6 +38,18 @@ pub fn hashmap_random_keys() -> (u64, u64) { struct Rng(c::BCRYPT_ALG_HANDLE); impl Rng { + #[cfg(miri)] + fn open() -> Result { + const BCRYPT_RNG_ALG_HANDLE: c::BCRYPT_ALG_HANDLE = ptr::invalid_mut(0x81); + let _ = ( + c::BCryptOpenAlgorithmProvider, + c::BCryptCloseAlgorithmProvider, + c::BCRYPT_RNG_ALGORITHM, + c::STATUS_NOT_SUPPORTED, + ); + Ok(Self(BCRYPT_RNG_ALG_HANDLE)) + } + #[cfg(not(miri))] // Open a handle to the RNG algorithm. fn open() -> Result { use crate::sync::atomic::AtomicPtr; From 0d078c9fd6881a011713d810773aec03e17d793f Mon Sep 17 00:00:00 2001 From: Caio Date: Wed, 7 Sep 2022 10:00:45 -0300 Subject: [PATCH 4285/5092] [Arithmetic] Consider literals --- clippy_lints/src/operators/arithmetic.rs | 118 +++++++++++++++++------ clippy_lints/src/operators/mod.rs | 22 +++-- src/docs/arithmetic.txt | 21 ++-- tests/ui/arithmetic.fixed | 27 ------ tests/ui/arithmetic.rs | 38 +++++++- tests/ui/arithmetic.stderr | 22 +++++ 6 files changed, 168 insertions(+), 80 deletions(-) delete mode 100644 tests/ui/arithmetic.fixed create mode 100644 tests/ui/arithmetic.stderr diff --git a/clippy_lints/src/operators/arithmetic.rs b/clippy_lints/src/operators/arithmetic.rs index 800cf249f5c7..27eef92deef4 100644 --- a/clippy_lints/src/operators/arithmetic.rs +++ b/clippy_lints/src/operators/arithmetic.rs @@ -5,13 +5,21 @@ use super::ARITHMETIC; use clippy_utils::{consts::constant_simple, diagnostics::span_lint}; +use rustc_ast as ast; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::Ty; use rustc_session::impl_lint_pass; -use rustc_span::source_map::Span; +use rustc_span::source_map::{Span, Spanned}; -const HARD_CODED_ALLOWED: &[&str] = &["std::num::Saturating", "std::string::String", "std::num::Wrapping"]; +const HARD_CODED_ALLOWED: &[&str] = &[ + "f32", + "f64", + "std::num::Saturating", + "std::string::String", + "std::num::Wrapping", +]; #[derive(Debug)] pub struct Arithmetic { @@ -34,6 +42,27 @@ impl Arithmetic { } } + /// Checks assign operators (+=, -=, *=, /=) of integers in a non-constant environment that + /// won't overflow. + fn has_valid_assign_op(op: &Spanned, rhs: &hir::Expr<'_>, rhs_refs: Ty<'_>) -> bool { + if !Self::is_literal_integer(rhs, rhs_refs) { + return false; + } + if let hir::BinOpKind::Div | hir::BinOpKind::Mul = op.node + && let hir::ExprKind::Lit(ref lit) = rhs.kind + && let ast::LitKind::Int(1, _) = lit.node + { + return true; + } + false + } + + /// Checks "raw" binary operators (+, -, *, /) of integers in a non-constant environment + /// already handled by the CTFE. + fn has_valid_bin_op(lhs: &hir::Expr<'_>, lhs_refs: Ty<'_>, rhs: &hir::Expr<'_>, rhs_refs: Ty<'_>) -> bool { + Self::is_literal_integer(lhs, lhs_refs) && Self::is_literal_integer(rhs, rhs_refs) + } + /// Checks if the given `expr` has any of the inner `allowed` elements. fn is_allowed_ty(&self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { self.allowed.contains( @@ -46,40 +75,66 @@ impl Arithmetic { ) } + /// Explicit integers like `1` or `i32::MAX`. Does not take into consideration references. + fn is_literal_integer(expr: &hir::Expr<'_>, expr_refs: Ty<'_>) -> bool { + let is_integral = expr_refs.is_integral(); + let is_literal = matches!(expr.kind, hir::ExprKind::Lit(_)); + is_integral && is_literal + } + fn issue_lint(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) { span_lint(cx, ARITHMETIC, expr.span, "arithmetic detected"); self.expr_span = Some(expr.span); } + + /// Manages when the lint should be triggered. Operations in constant environments, hard coded + /// types, custom allowed types and non-constant operations that won't overflow are ignored. + fn manage_bin_ops( + &mut self, + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + op: &Spanned, + lhs: &hir::Expr<'_>, + rhs: &hir::Expr<'_>, + ) { + if constant_simple(cx, cx.typeck_results(), expr).is_some() { + return; + } + if !matches!( + op.node, + hir::BinOpKind::Add + | hir::BinOpKind::Sub + | hir::BinOpKind::Mul + | hir::BinOpKind::Div + | hir::BinOpKind::Rem + | hir::BinOpKind::Shl + | hir::BinOpKind::Shr + ) { + return; + }; + if self.is_allowed_ty(cx, lhs) || self.is_allowed_ty(cx, rhs) { + return; + } + let lhs_refs = cx.typeck_results().expr_ty(lhs).peel_refs(); + let rhs_refs = cx.typeck_results().expr_ty(rhs).peel_refs(); + let has_valid_assign_op = Self::has_valid_assign_op(op, rhs, rhs_refs); + if has_valid_assign_op || Self::has_valid_bin_op(lhs, lhs_refs, rhs, rhs_refs) { + return; + } + self.issue_lint(cx, expr); + } } impl<'tcx> LateLintPass<'tcx> for Arithmetic { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { - if self.expr_span.is_some() { - return; - } - if let Some(span) = self.const_span && span.contains(expr.span) { + if self.expr_span.is_some() || self.const_span.map_or(false, |sp| sp.contains(expr.span)) { return; } match &expr.kind { hir::ExprKind::Binary(op, lhs, rhs) | hir::ExprKind::AssignOp(op, lhs, rhs) => { - let ( - hir::BinOpKind::Add - | hir::BinOpKind::Sub - | hir::BinOpKind::Mul - | hir::BinOpKind::Div - | hir::BinOpKind::Rem - | hir::BinOpKind::Shl - | hir::BinOpKind::Shr - ) = op.node else { - return; - }; - if self.is_allowed_ty(cx, lhs) || self.is_allowed_ty(cx, rhs) { - return; - } - self.issue_lint(cx, expr); + self.manage_bin_ops(cx, expr, op, lhs, rhs); }, hir::ExprKind::Unary(hir::UnOp::Neg, _) => { - // CTFE already takes care of things like `-1` that do not overflow. if constant_simple(cx, cx.typeck_results(), expr).is_none() { self.issue_lint(cx, expr); } @@ -89,16 +144,15 @@ impl<'tcx> LateLintPass<'tcx> for Arithmetic { } fn check_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) { - let body_owner = cx.tcx.hir().body_owner_def_id(body.id()); - match cx.tcx.hir().body_owner_kind(body_owner) { - hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => { - let body_span = cx.tcx.def_span(body_owner); - if let Some(span) = self.const_span && span.contains(body_span) { - return; - } - self.const_span = Some(body_span); - }, - hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => {}, + let body_owner = cx.tcx.hir().body_owner(body.id()); + let body_owner_def_id = cx.tcx.hir().local_def_id(body_owner); + let body_owner_kind = cx.tcx.hir().body_owner_kind(body_owner_def_id); + if let hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) = body_owner_kind { + let body_span = cx.tcx.hir().span_with_body(body_owner); + if let Some(span) = self.const_span && span.contains(body_span) { + return; + } + self.const_span = Some(body_span); } } diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index bb6d99406b49..c7b0633b79ca 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -61,25 +61,29 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for any kind of arithmetic operation of any type. + /// Checks any kind of arithmetic operation of any type. /// /// Operators like `+`, `-`, `*` or `<<` are usually capable of overflowing according to the [Rust /// Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow), - /// or can panic (`/`, `%`). Known safe built-in types like `Wrapping` or `Saturing` are filtered - /// away. + /// or can panic (`/`, `%`). + /// + /// Known safe built-in types like `Wrapping` or `Saturing`, floats, operations in constant + /// environments, allowed types and non-constant operations that won't overflow are ignored. /// /// ### Why is this bad? - /// Integer overflow will trigger a panic in debug builds or will wrap in - /// release mode. Division by zero will cause a panic in either mode. In some applications one - /// wants explicitly checked, wrapping or saturating arithmetic. + /// For integers, overflow will trigger a panic in debug builds or wrap the result in + /// release mode; division by zero will cause a panic in either mode. As a result, it is + /// desirable to explicitly call checked, wrapping or saturating arithmetic methods. /// /// #### Example /// ```rust - /// # let a = 0; - /// a + 1; + /// // `n` can be any number, including `i32::MAX`. + /// fn foo(n: i32) -> i32 { + /// n + 1 + /// } /// ``` /// - /// Third-party types also tend to overflow. + /// Third-party types can also overflow or present unwanted side-effects. /// /// #### Example /// ```ignore,rust diff --git a/src/docs/arithmetic.txt b/src/docs/arithmetic.txt index 0b3f07d95056..f04125060fbd 100644 --- a/src/docs/arithmetic.txt +++ b/src/docs/arithmetic.txt @@ -1,22 +1,27 @@ ### What it does -Checks for any kind of arithmetic operation of any type. +Checks any kind of arithmetic operation of any type. Operators like `+`, `-`, `*` or `<<` are usually capable of overflowing according to the [Rust Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow), -or can panic (`/`, `%`). Known safe built-in types like `Wrapping` or `Saturing` are filtered -away. +or can panic (`/`, `%`). + +Known safe built-in types like `Wrapping` or `Saturing`, floats, operations in constant +environments, allowed types and non-constant operations that won't overflow are ignored. ### Why is this bad? -Integer overflow will trigger a panic in debug builds or will wrap in -release mode. Division by zero will cause a panic in either mode. In some applications one -wants explicitly checked, wrapping or saturating arithmetic. +For integers, overflow will trigger a panic in debug builds or wrap the result in +release mode; division by zero will cause a panic in either mode. As a result, it is +desirable to explicitly call checked, wrapping or saturating arithmetic methods. #### Example ``` -a + 1; +// `n` can be any number, including `i32::MAX`. +fn foo(n: i32) -> i32 { + n + 1 +} ``` -Third-party types also tend to overflow. +Third-party types can also overflow or present unwanted side-effects. #### Example ``` diff --git a/tests/ui/arithmetic.fixed b/tests/ui/arithmetic.fixed deleted file mode 100644 index a2a1c4394c21..000000000000 --- a/tests/ui/arithmetic.fixed +++ /dev/null @@ -1,27 +0,0 @@ -// run-rustfix - -#![allow(clippy::unnecessary_owned_empty_strings)] -#![feature(saturating_int_impl)] -#![warn(clippy::arithmetic)] - -use core::num::{Saturating, Wrapping}; - -pub fn hard_coded_allowed() { - let _ = Saturating(0u32) + Saturating(0u32); - let _ = String::new() + ""; - let _ = Wrapping(0u32) + Wrapping(0u32); - - let saturating: Saturating = Saturating(0u32); - let string: String = String::new(); - let wrapping: Wrapping = Wrapping(0u32); - - let inferred_saturating = saturating + saturating; - let inferred_string = string + ""; - let inferred_wrapping = wrapping + wrapping; - - let _ = inferred_saturating + inferred_saturating; - let _ = inferred_string + ""; - let _ = inferred_wrapping + inferred_wrapping; -} - -fn main() {} diff --git a/tests/ui/arithmetic.rs b/tests/ui/arithmetic.rs index a2a1c4394c21..a9ac46e9a190 100644 --- a/tests/ui/arithmetic.rs +++ b/tests/ui/arithmetic.rs @@ -1,12 +1,13 @@ -// run-rustfix - -#![allow(clippy::unnecessary_owned_empty_strings)] -#![feature(saturating_int_impl)] +#![allow(clippy::assign_op_pattern, clippy::unnecessary_owned_empty_strings)] +#![feature(inline_const, saturating_int_impl)] #![warn(clippy::arithmetic)] use core::num::{Saturating, Wrapping}; pub fn hard_coded_allowed() { + let _ = 1f32 + 1f32; + let _ = 1f64 + 1f64; + let _ = Saturating(0u32) + Saturating(0u32); let _ = String::new() + ""; let _ = Wrapping(0u32) + Wrapping(0u32); @@ -24,4 +25,33 @@ pub fn hard_coded_allowed() { let _ = inferred_wrapping + inferred_wrapping; } +#[rustfmt::skip] +pub fn non_overflowing_ops() { + const _: i32 = { let mut n = 1; n += 1; n }; + let _ = const { let mut n = 1; n += 1; n }; + + const _: i32 = { let mut n = 1; n = n + 1; n }; + let _ = const { let mut n = 1; n = n + 1; n }; + + const _: i32 = { let mut n = 1; n = 1 + n; n }; + let _ = const { let mut n = 1; n = 1 + n; n }; + + const _: i32 = 1 + 1; + let _ = 1 + 1; + let _ = const { 1 + 1 }; + + let mut _a = 1; + _a *= 1; + _a /= 1; +} + +#[rustfmt::skip] +pub fn overflowing_ops() { + let mut _a = 1; _a += 1; + + let mut _b = 1; _b = _b + 1; + + let mut _c = 1; _c = 1 + _c; +} + fn main() {} diff --git a/tests/ui/arithmetic.stderr b/tests/ui/arithmetic.stderr new file mode 100644 index 000000000000..a51cf6ba6005 --- /dev/null +++ b/tests/ui/arithmetic.stderr @@ -0,0 +1,22 @@ +error: arithmetic detected + --> $DIR/arithmetic.rs:50:21 + | +LL | let mut _a = 1; _a += 1; + | ^^^^^^^ + | + = note: `-D clippy::arithmetic` implied by `-D warnings` + +error: arithmetic detected + --> $DIR/arithmetic.rs:52:26 + | +LL | let mut _b = 1; _b = _b + 1; + | ^^^^^^ + +error: arithmetic detected + --> $DIR/arithmetic.rs:54:26 + | +LL | let mut _c = 1; _c = 1 + _c; + | ^^^^^^ + +error: aborting due to 3 previous errors + From dfbc1f712d61340dab653ac8d54bdc701b64e2ec Mon Sep 17 00:00:00 2001 From: Usama Arif Date: Sun, 4 Sep 2022 18:43:18 +0100 Subject: [PATCH 4286/5092] stdio: Document no support for writing to non-blocking stdio/stderr Printing to stdio/stderr that have been opened with non-blocking (O_NONBLOCK in linux) can result in an error, which is not handled by std::io module causing a panic. Signed-off-by: Usama Arif --- library/std/src/io/stdio.rs | 3 +++ library/std/src/macros.rs | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 91cff3217d21..2dc12a18a8a6 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -992,6 +992,9 @@ pub fn set_output_capture(sink: Option) -> Option { /// the global stream. /// /// However, if the actual I/O causes an error, this function does panic. +/// +/// Writing to non-blocking stdout/stderr can cause an error, which will lead +/// this function to panic. fn print_to(args: fmt::Arguments<'_>, global_s: fn() -> T, label: &str) where T: Write, diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs index a5003c66fcad..6e4ba1404e55 100644 --- a/library/std/src/macros.rs +++ b/library/std/src/macros.rs @@ -49,6 +49,9 @@ macro_rules! panic { /// /// Panics if writing to `io::stdout()` fails. /// +/// Writing to non-blocking stdout can cause an error, which will lead +/// this macro to panic. +/// /// # Examples /// /// ``` @@ -107,6 +110,9 @@ macro_rules! print { /// /// Panics if writing to [`io::stdout`] fails. /// +/// Writing to non-blocking stdout can cause an error, which will lead +/// this macro to panic. +/// /// [`io::stdout`]: crate::io::stdout /// /// # Examples @@ -147,6 +153,9 @@ macro_rules! println { /// /// Panics if writing to `io::stderr` fails. /// +/// Writing to non-blocking stdout can cause an error, which will lead +/// this macro to panic. +/// /// # Examples /// /// ``` @@ -179,6 +188,9 @@ macro_rules! eprint { /// /// Panics if writing to `io::stderr` fails. /// +/// Writing to non-blocking stdout can cause an error, which will lead +/// this macro to panic. +/// /// # Examples /// /// ``` From f9ff70cef9c1bc5ad6c1592f6de73e3cdc10b579 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 7 Sep 2022 13:26:35 +0000 Subject: [PATCH 4287/5092] Rustup --- rust-version | 2 +- tests/fail/intrinsics/assume.rs | 2 +- tests/fail/intrinsics/assume.stderr | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index 0c6d053e9b4c..cbec52128d37 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -dec689432fac6720b2f18101ac28a21add98b1b8 +e7c7aa7288559f8e5ea7ce3543ff946b09783628 diff --git a/tests/fail/intrinsics/assume.rs b/tests/fail/intrinsics/assume.rs index be06d0a7a554..c34827427ef0 100644 --- a/tests/fail/intrinsics/assume.rs +++ b/tests/fail/intrinsics/assume.rs @@ -5,6 +5,6 @@ fn main() { unsafe { std::intrinsics::assume(x < 10); std::intrinsics::assume(x > 1); - std::intrinsics::assume(x > 42); //~ ERROR: `assume` intrinsic called with `false` + std::intrinsics::assume(x > 42); //~ ERROR: `assume` called with `false` } } diff --git a/tests/fail/intrinsics/assume.stderr b/tests/fail/intrinsics/assume.stderr index 17e4cc6698d4..c1909570d99f 100644 --- a/tests/fail/intrinsics/assume.stderr +++ b/tests/fail/intrinsics/assume.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: `assume` intrinsic called with `false` +error: Undefined Behavior: `assume` called with `false` --> $DIR/assume.rs:LL:CC | LL | std::intrinsics::assume(x > 42); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `assume` intrinsic called with `false` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `assume` called with `false` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information From 88fa621bab003279a0244ef7693eb161a3f755d7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 7 Sep 2022 15:34:16 +0200 Subject: [PATCH 4288/5092] Add documentation for Attr::is_doc_comment --- compiler/rustc_ast/src/attr/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 5b72ec2b6015..6b0dac7c2f0b 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -232,6 +232,8 @@ impl AttrItem { } impl Attribute { + /// Returns `true` if it is a sugared doc comment (`///` or `//!` for example). + /// So `#[doc = "doc"]` will return `false`. pub fn is_doc_comment(&self) -> bool { match self.kind { AttrKind::Normal(..) => false, From a3b60f1769303cad5221e44f8a0c4d76182db346 Mon Sep 17 00:00:00 2001 From: Krasimir Georgiev Date: Wed, 7 Sep 2022 12:08:06 +0000 Subject: [PATCH 4289/5092] llvm-wrapper: adapt for LLVM API changes No functional changes intended. Adapts PassWrapper for two recent LLVM API changes: * https://github.com/llvm/llvm-project/commit/e7bac3b9fa739f8d167a390a547068aad1d424a7 * https://github.com/llvm/llvm-project/commit/93600eb50ceeec83c488ded24fa0fd25f997fec6 * https://github.com/llvm/llvm-project/commit/5e38b2a456df6e263a509af60a731cec57310498 --- compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 05d2a214d0b7..bc49dfe7eae3 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -936,12 +936,14 @@ LLVMRustOptimizeWithNewPassManager( /*CompileKernel=*/false); OptimizerLastEPCallbacks.push_back( [Options](ModulePassManager &MPM, OptimizationLevel Level) { -#if LLVM_VERSION_GE(14, 0) +#if LLVM_VERSION_GE(14, 0) && LLVM_VERSION_LT(16, 0) MPM.addPass(ModuleMemorySanitizerPass(Options)); #else MPM.addPass(MemorySanitizerPass(Options)); #endif +#if LLVM_VERSION_LT(16, 0) MPM.addPass(createModuleToFunctionPassAdaptor(MemorySanitizerPass(Options))); +#endif } ); } @@ -972,7 +974,11 @@ LLVMRustOptimizeWithNewPassManager( /*UseAfterScope=*/true, AsanDetectStackUseAfterReturnMode::Runtime, }; +#if LLVM_VERSION_LT(16, 0) MPM.addPass(ModuleAddressSanitizerPass(opts)); +#else + MPM.addPass(AddressSanitizerPass(opts)); +#endif #else MPM.addPass(ModuleAddressSanitizerPass( /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover)); From 210c851dcdf1a713e0cfef0d468a529b077a2bc2 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 7 Sep 2022 06:42:36 -0700 Subject: [PATCH 4290/5092] rustdoc: remove unused mobile CSS `.rustdoc { flex-direction }` According to MDN, [flex-direction] only applies to [flex containers], which are boxes with `display: flex` or `inline-flex`. However, the `.rustdoc` body container is not a flex-container on mobile. A few lines above, it's set to `display: block`, so this selector does not have any effect. [flex-direction]: https://developer.mozilla.org/en-US/docs/Web/CSS/flex-direction [flex containers]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox#the_flex_container --- src/librustdoc/html/static/css/rustdoc.css | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index c117e3ac40da..c216dac4fee2 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1762,7 +1762,6 @@ in storage.js plus the media query with (min-width: 701px) padding-top: 0px; } - .rustdoc, .main-heading { flex-direction: column; } From e3a738a9427859e13e352d6ac00a9389172eff47 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 6 Sep 2022 17:24:36 -0300 Subject: [PATCH 4291/5092] Add instrument and debug calls --- compiler/rustc_ast_lowering/src/lib.rs | 6 +++++- .../rustc_infer/src/infer/outlives/verify.rs | 6 ++++-- compiler/rustc_middle/src/ty/generics.rs | 1 + compiler/rustc_resolve/src/late/lifetimes.rs | 3 +++ .../rustc_trait_selection/src/traits/wf.rs | 3 +++ compiler/rustc_typeck/src/astconv/mod.rs | 5 ++--- compiler/rustc_typeck/src/collect.rs | 21 +++++++++++-------- .../rustc_typeck/src/collect/item_bounds.rs | 3 +++ 8 files changed, 33 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 3a94c7a91b23..d9a7f91a4d9c 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -660,6 +660,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// actually used in the HIR, as that would trigger an assertion in the /// `HirIdValidator` later on, which makes sure that all `NodeId`s got mapped /// properly. Calling the method twice with the same `NodeId` is fine though. + #[instrument(level = "debug", skip(self), ret)] fn lower_node_id(&mut self, ast_node_id: NodeId) -> hir::HirId { assert_ne!(ast_node_id, DUMMY_NODE_ID); @@ -693,6 +694,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } /// Generate a new `HirId` without a backing `NodeId`. + #[instrument(level = "debug", skip(self), ret)] fn next_id(&mut self) -> hir::HirId { let owner = self.current_hir_id_owner; let local_id = self.item_local_id_counter; @@ -1381,7 +1383,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// added explicitly in the HIR). But this includes all the lifetimes, and we only want to /// capture the lifetimes that are referenced in the bounds. Therefore, we add *extra* lifetime parameters /// for the lifetimes that get captured (`'x`, in our example above) and reference those. - #[instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self), ret)] fn lower_opaque_impl_trait( &mut self, span: Span, @@ -2143,6 +2145,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::MutTy { ty: self.lower_ty(&mt.ty, itctx), mutbl: mt.mutbl } } + #[instrument(level = "debug", skip(self), ret)] fn lower_param_bounds( &mut self, bounds: &[GenericBound], @@ -2159,6 +2162,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { bounds.iter().map(move |bound| self.lower_param_bound(bound, itctx)) } + #[instrument(level = "debug", skip(self), ret)] fn lower_generic_and_bounds( &mut self, node_id: NodeId, diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index c7d7ef40d9d4..75233495040c 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -50,13 +50,13 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> { - debug!("param_bound(param_ty={:?})", param_ty); - // Start with anything like `T: 'a` we can scrape from the // environment. If the environment contains something like // `for<'a> T: 'a`, then we know that `T` outlives everything. let declared_bounds_from_env = self.declared_generic_bounds_from_env(param_ty); + debug!(?declared_bounds_from_env); let mut param_bounds = vec![]; for declared_bound in declared_bounds_from_env { let bound_region = declared_bound.map_bound(|outlives| outlives.1); @@ -65,6 +65,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { param_bounds.push(VerifyBound::OutlivedBy(region)); } else { // This is `for<'a> T: 'a`. This means that `T` outlives everything! All done here. + debug!("found that {param_ty:?} outlives any lifetime, returning empty vector"); return VerifyBound::AllBounds(vec![]); } } @@ -72,6 +73,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { // Add in the default bound of fn body that applies to all in // scope type parameters: if let Some(r) = self.implicit_region_bound { + debug!("adding implicit region bound of {r:?}"); param_bounds.push(VerifyBound::OutlivedBy(r)); } diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index a1d980af921a..8631ee91fa45 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -328,6 +328,7 @@ impl<'tcx> GenericPredicates<'tcx> { } } + #[instrument(level = "debug", skip(self, tcx))] fn instantiate_into( &self, tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index c72981ed96f6..101679aa6dc9 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -525,6 +525,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { match &item.kind { hir::ItemKind::Impl(hir::Impl { of_trait, .. }) => { @@ -839,6 +840,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { use self::hir::TraitItemKind::*; match trait_item.kind { @@ -888,6 +890,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } + #[instrument(level = "debug", skip(self))] fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { use self::hir::ImplItemKind::*; match impl_item.kind { diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index bb6009cb22a3..20d0c15e8e42 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -434,6 +434,7 @@ impl<'tcx> WfPredicates<'tcx> { } /// Pushes all the predicates needed to validate that `ty` is WF into `out`. + #[instrument(level = "debug", skip(self))] fn compute(&mut self, arg: GenericArg<'tcx>) { let mut walker = arg.walk(); let param_env = self.param_env; @@ -488,6 +489,8 @@ impl<'tcx> WfPredicates<'tcx> { } }; + debug!("wf bounds for ty={:?} ty.kind={:#?}", ty, ty.kind()); + match *ty.kind() { ty::Bool | ty::Char diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 14f04ddc8688..c1e258f5e891 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -2695,6 +2695,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { result_ty } + #[instrument(level = "debug", skip(self), ret)] fn impl_trait_ty_to_ty( &self, def_id: DefId, @@ -2743,9 +2744,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }); debug!("impl_trait_ty_to_ty: substs={:?}", substs); - let ty = tcx.mk_opaque(def_id, substs); - debug!("impl_trait_ty_to_ty: {}", ty); - ty + tcx.mk_opaque(def_id, substs) } pub fn ty_of_arg(&self, ty: &hir::Ty<'_>, expected_ty: Option>) -> Ty<'tcx> { diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 6236ad370df6..e70f728d7dcc 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -573,6 +573,7 @@ fn get_new_lifetime_name<'tcx>( /// Returns the predicates defined on `item_def_id` of the form /// `X: Foo` where `X` is the type parameter `def_id`. +#[instrument(level = "trace", skip(tcx))] fn type_param_predicates( tcx: TyCtxt<'_>, (item_def_id, def_id, assoc_name): (DefId, LocalDefId, Ident), @@ -679,7 +680,7 @@ impl<'tcx> ItemCtxt<'tcx> { assoc_name: Option, ) -> Vec<(ty::Predicate<'tcx>, Span)> { let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id(); - debug!(?param_def_id); + trace!(?param_def_id); ast_generics .predicates .iter() @@ -708,9 +709,8 @@ impl<'tcx> ItemCtxt<'tcx> { .collect() } + #[instrument(level = "trace", skip(self))] fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool { - debug!("bound_defines_assoc_item(b={:?}, assoc_name={:?})", b, assoc_name); - match b { hir::GenericBound::Trait(poly_trait_ref, _) => { let trait_ref = &poly_trait_ref.trait_ref; @@ -2105,11 +2105,10 @@ fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> { /// Returns a list of user-specified type predicates for the definition with ID `def_id`. /// N.B., this does not include any implied/inferred constraints. +#[instrument(level = "trace", skip(tcx), ret)] fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> { use rustc_hir::*; - debug!("explicit_predicates_of(def_id={:?})", def_id); - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); let node = tcx.hir().get(hir_id); @@ -2224,6 +2223,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP + has_own_self as u32 + early_bound_lifetimes_from_generics(tcx, ast_generics).count() as u32; + trace!(?predicates); + trace!(?ast_generics); + // Collect the predicates that were written inline by the user on each // type parameter (e.g., ``). for param in ast_generics.params { @@ -2244,7 +2246,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP Some((param.hir_id, ast_generics.predicates)), param.span, ); + trace!(?bounds); predicates.extend(bounds.predicates(tcx, param_ty)); + trace!(?predicates); } GenericParamKind::Const { .. } => { // Bounds on const parameters are currently not possible. @@ -2253,6 +2257,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP } } + trace!(?predicates); // Add in the bounds that appear in the where-clause. for predicate in ast_generics.predicates { match predicate { @@ -2338,12 +2343,10 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP ); } - let result = ty::GenericPredicates { + ty::GenericPredicates { parent: generics.parent, predicates: tcx.arena.alloc_from_iter(predicates), - }; - debug!("explicit_predicates_of(def_id={:?}) = {:?}", def_id, result); - result + } } fn const_evaluatable_predicates_of<'tcx>( diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_typeck/src/collect/item_bounds.rs index 0d2b75d3328f..318e8f581f7c 100644 --- a/compiler/rustc_typeck/src/collect/item_bounds.rs +++ b/compiler/rustc_typeck/src/collect/item_bounds.rs @@ -53,6 +53,7 @@ fn associated_type_bounds<'tcx>( /// impl trait it isn't possible to write a suitable predicate on the /// containing function and for type-alias impl trait we don't have a backwards /// compatibility issue. +#[instrument(level = "trace", skip(tcx), ret)] fn opaque_type_bounds<'tcx>( tcx: TyCtxt<'tcx>, opaque_def_id: DefId, @@ -67,6 +68,8 @@ fn opaque_type_bounds<'tcx>( let mut bounds = >::compute_bounds(&icx, item_ty, ast_bounds); // Opaque types are implicitly sized unless a `?Sized` bound is found >::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span); + debug!(?bounds); + tcx.arena.alloc_from_iter(bounds.predicates(tcx, item_ty)) }) } From d42afd2bd19a33e99bad027909b88becab1068c4 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 6 Sep 2022 17:26:05 -0300 Subject: [PATCH 4292/5092] Format hir_id_validator error using pretty print --- compiler/rustc_passes/src/hir_id_validator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs index 212ea9e57a37..3bb8c0bb48c5 100644 --- a/compiler/rustc_passes/src/hir_id_validator.rs +++ b/compiler/rustc_passes/src/hir_id_validator.rs @@ -103,7 +103,7 @@ impl<'a, 'hir> HirIdValidator<'a, 'hir> { self.error(|| { format!( "ItemLocalIds not assigned densely in {}. \ - Max ItemLocalId = {}, missing IDs = {:?}; seens IDs = {:?}", + Max ItemLocalId = {}, missing IDs = {:#?}; seens IDs = {:#?}", self.hir_map.def_path(owner).to_string_no_crate_verbose(), max, missing_items, From dc2af5f876812dc90f62466ffdc8591f4a646e56 Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 7 Sep 2022 15:47:44 +0200 Subject: [PATCH 4293/5092] Fix error printing mistake in tidy --- src/tools/tidy/src/features.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index de292d3305db..b306a527a7ce 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -199,8 +199,7 @@ pub fn check( if channel != "nightly" && since == Version::CurrentPlaceholder { tidy_error!( bad, - "The placeholder use of {kind} feature `{feature_name}` is not allowed on the {} channel", - version::VERSION_PLACEHOLDER + "The placeholder use of {kind} feature `{feature_name}` is not allowed on the {channel} channel", ); } } From 0a9b49c794a4179a4dcfd5fc07cea76321e51ad0 Mon Sep 17 00:00:00 2001 From: Maurits van Riezen <12109031+mousetail@users.noreply.github.com> Date: Wed, 7 Sep 2022 16:36:32 +0200 Subject: [PATCH 4294/5092] Add doctest --- library/core/src/fmt/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 0d370e384317..1abb729a4c00 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -1827,6 +1827,7 @@ impl<'a> Formatter<'a> { /// } /// /// assert_eq!(&format!("{:+}", Foo(23)), "Foo(+23)"); + /// assert_eq!(&format!("{:+}", Foo(-32)), "Foo(-23)"); /// assert_eq!(&format!("{}", Foo(23)), "Foo(23)"); /// ``` #[must_use] From 419c4e1c4ffff2d293264ed788268b5f165b4328 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 7 Sep 2022 08:43:29 +0000 Subject: [PATCH 4295/5092] Update miri submodule --- compiler/rustc_middle/src/mir/mod.rs | 4 +++- src/tools/miri | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index f3676604bb0e..0c346b02c418 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1478,7 +1478,9 @@ impl<'tcx> Place<'tcx> { /// It's guaranteed to be in the first place pub fn has_deref(&self) -> bool { // To make sure this is not accidently used in wrong mir phase - debug_assert!(!self.projection[1..].contains(&PlaceElem::Deref)); + debug_assert!( + self.projection.is_empty() || !self.projection[1..].contains(&PlaceElem::Deref) + ); self.projection.first() == Some(&PlaceElem::Deref) } diff --git a/src/tools/miri b/src/tools/miri index dba35d2be72f..ef3f649e4960 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit dba35d2be72f4b78343d1a0f0b4737306f310672 +Subproject commit ef3f649e49607a1fad64eb0a5139110df3efa2a7 From 10fc2ff806cf11eb19c5376c7cdc929faf055b04 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 7 Sep 2022 08:42:31 -0700 Subject: [PATCH 4296/5092] rustdoc: remove unused CSS `.content .methods > div` This selector has its roots in these commits: * current version: `.content .methods > div:not(.notable-traits):not(.method)` from 9077d540da944c41678a7129e04e7fc5d7e38582 * intermediate version: `.content .methods > div:not(.important-traits)` from d86621f69e827361e47bc6c4b2c7fd5319155227 * original version: `.content .methods > div { margin-left: 40px; }` from 0a46933c4d81573e78ce16cd215ba155a3114fce Based on the call stack, where [`class='methods'`] calls `trait_item` and [`trait_item`] calls [`document`], this div selector was probably intended to target docblock and stability tags. In the current version of the code, neither of these can possibly be nested directly below the `class='methods'` wrapper, because the [current version of the `trait_item` function] always wraps them in a `
` tag if they exist. The only div tag that can possibly be nested directly below it now is the one with class `method`, which is explicitly excluded. [`class='methods'`]: https://github.com/rust-lang/rust/blob/0a46933c4d81573e78ce16cd215ba155a3114fce/src/librustdoc/html/render.rs#L1811-L1842 [`trait_item`]: https://github.com/rust-lang/rust/blob/0a46933c4d81573e78ce16cd215ba155a3114fce/src/librustdoc/html/render.rs#L1807 [`document`]: https://github.com/rust-lang/rust/blob/0a46933c4d81573e78ce16cd215ba155a3114fce/src/librustdoc/html/render.rs#L1515-L1523 [current version of the `trait_item` function]: https://github.com/rust-lang/rust/blob/e7c7aa7288559f8e5ea7ce3543ff946b09783628/src/librustdoc/html/render/print_item.rs#L710 --- src/librustdoc/html/static/css/rustdoc.css | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 2f6d13422607..8ff329b9f500 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -747,11 +747,6 @@ pre, .rustdoc.source .example-wrap { font-size: 0.875rem; } -.content .methods > div:not(.notable-traits):not(.method) { - margin-left: 40px; - margin-bottom: 15px; -} - .item-info { display: block; } From 5fbe485ecca977e3981d9dbcc5370183528d50a7 Mon Sep 17 00:00:00 2001 From: Maurits van Riezen <12109031+mousetail@users.noreply.github.com> Date: Wed, 7 Sep 2022 17:53:47 +0200 Subject: [PATCH 4297/5092] Typo --- library/core/src/fmt/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 1abb729a4c00..905212eb372b 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -1827,7 +1827,7 @@ impl<'a> Formatter<'a> { /// } /// /// assert_eq!(&format!("{:+}", Foo(23)), "Foo(+23)"); - /// assert_eq!(&format!("{:+}", Foo(-32)), "Foo(-23)"); + /// assert_eq!(&format!("{:+}", Foo(-23)), "Foo(-23)"); /// assert_eq!(&format!("{}", Foo(23)), "Foo(23)"); /// ``` #[must_use] From 43681db48df8ada9e213e7e6512f2dc1f5774e97 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 6 Sep 2022 14:47:04 -0700 Subject: [PATCH 4298/5092] rustdoc: remove unused CSS `#main-content > table td` This rule was added in 4e2c59a970695b2809a0f68f2ffe415ebdb04913 to benefit the module items table. However, the module items table stopped using table tags when 6020c79ddeafe8d9760b27c14c39da81bac9b4a6 switched us over to grid layout. You can see when this one used to be triggered by visiting in a very narrow window, but it doesn't any more, because the module table is now rendered using `
` tags. --- src/librustdoc/html/static/css/rustdoc.css | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 3502d97d470f..3dbd68545216 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -2047,11 +2047,6 @@ in storage.js plus the media query with (min-width: 701px) height: 73px; } - #main-content > table td { - word-break: break-word; - width: 50%; - } - #crate-search { border-radius: 4px; } From 15859323ea424b4fb9556d9d45c8b5d374e57f9e Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Wed, 7 Sep 2022 15:26:44 -0400 Subject: [PATCH 4299/5092] Fix hang in `vec_init_then_push` --- clippy_lints/src/vec_init_then_push.rs | 2 +- tests/ui/vec_init_then_push.rs | 6 ++++++ tests/ui/vec_init_then_push.stderr | 9 ++++++++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/vec_init_then_push.rs b/clippy_lints/src/vec_init_then_push.rs index 35db45e2b0c9..d77a21d668e6 100644 --- a/clippy_lints/src/vec_init_then_push.rs +++ b/clippy_lints/src/vec_init_then_push.rs @@ -86,7 +86,7 @@ impl VecPushSearcher { }, ExprKind::Unary(UnOp::Deref, _) | ExprKind::Index(..) if !needs_mut => { let mut last_place = parent; - while let Some(parent) = get_parent_expr(cx, parent) { + while let Some(parent) = get_parent_expr(cx, last_place) { if matches!(parent.kind, ExprKind::Unary(UnOp::Deref, _) | ExprKind::Field(..)) || matches!(parent.kind, ExprKind::Index(e, _) if e.hir_id == last_place.hir_id) { diff --git a/tests/ui/vec_init_then_push.rs b/tests/ui/vec_init_then_push.rs index 531745424a7d..8dd098a5b540 100644 --- a/tests/ui/vec_init_then_push.rs +++ b/tests/ui/vec_init_then_push.rs @@ -104,3 +104,9 @@ fn _cond_push_with_large_start(x: bool) -> Vec { v2 } + +fn f() { + let mut v = Vec::new(); + v.push((0i32, 0i32)); + let y = v[0].0.abs(); +} diff --git a/tests/ui/vec_init_then_push.stderr b/tests/ui/vec_init_then_push.stderr index 50b029fc3372..a9da1c520197 100644 --- a/tests/ui/vec_init_then_push.stderr +++ b/tests/ui/vec_init_then_push.stderr @@ -62,5 +62,12 @@ LL | | v2.push(1); LL | | v2.push(0); | |_______________^ help: consider using the `vec![]` macro: `let mut v2 = vec![..];` -error: aborting due to 7 previous errors +error: calls to `push` immediately after creation + --> $DIR/vec_init_then_push.rs:109:5 + | +LL | / let mut v = Vec::new(); +LL | | v.push((0i32, 0i32)); + | |_________________________^ help: consider using the `vec![]` macro: `let v = vec![..];` + +error: aborting due to 8 previous errors From 1a08b96a0bb7c170130144214787b4a46aa5eb17 Mon Sep 17 00:00:00 2001 From: Michael Benfield Date: Thu, 25 Aug 2022 01:14:23 +0000 Subject: [PATCH 4300/5092] Change name of "dataful" variant to "untagged" This is in anticipation of a new enum layout, in which the niche optimization may be applied even when multiple variants have data. --- .../src/discriminant.rs | 11 +++++----- .../src/debuginfo/metadata/enums/cpp_like.rs | 18 ++++++++--------- .../src/debuginfo/metadata/enums/mod.rs | 6 +++--- .../src/debuginfo/metadata/enums/native.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/place.rs | 8 ++++---- .../rustc_const_eval/src/interpret/operand.rs | 6 +++--- .../rustc_const_eval/src/interpret/place.rs | 4 ++-- compiler/rustc_middle/src/ty/layout.rs | 20 +++++++++---------- compiler/rustc_target/src/abi/mod.rs | 4 ++-- src/test/debuginfo/msvc-pretty-enums.rs | 6 +++--- ...-scalarpair-payload-might-be-uninit.stderr | 4 ++-- .../layout/zero-sized-array-enum-niche.stderr | 2 +- 12 files changed, 46 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/discriminant.rs b/compiler/rustc_codegen_cranelift/src/discriminant.rs index e41ae1fbdbac..97b395bcd051 100644 --- a/compiler/rustc_codegen_cranelift/src/discriminant.rs +++ b/compiler/rustc_codegen_cranelift/src/discriminant.rs @@ -42,10 +42,10 @@ pub(crate) fn codegen_set_discriminant<'tcx>( Variants::Multiple { tag: _, tag_field, - tag_encoding: TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start }, + tag_encoding: TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start }, variants: _, } => { - if variant_index != dataful_variant { + if variant_index != untagged_variant { let niche = place.place_field(fx, mir::Field::new(tag_field)); let niche_value = variant_index.as_u32() - niche_variants.start().as_u32(); let niche_value = ty::ScalarInt::try_from_uint( @@ -113,7 +113,7 @@ pub(crate) fn codegen_get_discriminant<'tcx>( let res = CValue::by_val(val, dest_layout); dest.write_cvalue(fx, res); } - TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => { + TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => { // Rebase from niche values to discriminants, and check // whether the result is in range for the niche variants. @@ -169,8 +169,9 @@ pub(crate) fn codegen_get_discriminant<'tcx>( fx.bcx.ins().iadd_imm(relative_discr, i64::from(niche_variants.start().as_u32())) }; - let dataful_variant = fx.bcx.ins().iconst(cast_to, i64::from(dataful_variant.as_u32())); - let discr = fx.bcx.ins().select(is_niche, niche_discr, dataful_variant); + let untagged_variant = + fx.bcx.ins().iconst(cast_to, i64::from(untagged_variant.as_u32())); + let discr = fx.bcx.ins().select(is_niche, niche_discr, untagged_variant); let res = CValue::by_val(discr, dest_layout); dest.write_cvalue(fx, res); } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs index daec9303b2c6..129e336c7e43 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs @@ -99,7 +99,7 @@ const SINGLE_VARIANT_VIRTUAL_DISR: u64 = 0; /// compiler versions. /// /// Niche-tag enums have one special variant, usually called the -/// "dataful variant". This variant has a field that +/// "untagged variant". This variant has a field that /// doubles as the tag of the enum. The variant is active when the value of /// that field is within a pre-defined range. Therefore the variant struct /// has a `DISCR_BEGIN` and `DISCR_END` field instead of `DISCR_EXACT` in @@ -249,7 +249,7 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>( None, ), Variants::Multiple { - tag_encoding: TagEncoding::Niche { dataful_variant, .. }, + tag_encoding: TagEncoding::Niche { untagged_variant, .. }, ref variants, tag_field, .. @@ -260,7 +260,7 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>( enum_type_di_node, variants.indices(), tag_field, - Some(dataful_variant), + Some(untagged_variant), ), } }, @@ -391,7 +391,7 @@ fn build_union_fields_for_enum<'ll, 'tcx>( enum_type_di_node: &'ll DIType, variant_indices: impl Iterator + Clone, tag_field: usize, - dataful_variant_index: Option, + untagged_variant_index: Option, ) -> SmallVec<&'ll DIType> { let tag_base_type = super::tag_base_type(cx, enum_type_and_layout); @@ -436,7 +436,7 @@ fn build_union_fields_for_enum<'ll, 'tcx>( variant_names_type_di_node, tag_base_type, tag_field, - dataful_variant_index, + untagged_variant_index, ) } @@ -472,7 +472,7 @@ fn build_variant_struct_wrapper_type_di_node<'ll, 'tcx>( enum_or_generator_type_and_layout: TyAndLayout<'tcx>, enum_or_generator_type_di_node: &'ll DIType, variant_index: VariantIdx, - dataful_variant_index: Option, + untagged_variant_index: Option, variant_struct_type_di_node: &'ll DIType, variant_names_type_di_node: &'ll DIType, tag_base_type_di_node: &'ll DIType, @@ -517,7 +517,7 @@ fn build_variant_struct_wrapper_type_di_node<'ll, 'tcx>( } } DiscrResult::Range(min, max) => { - assert_eq!(Some(variant_index), dataful_variant_index); + assert_eq!(Some(variant_index), untagged_variant_index); if is_128_bits { DiscrKind::Range128(min, max) } else { @@ -757,7 +757,7 @@ fn build_union_fields_for_direct_tag_enum_or_generator<'ll, 'tcx>( discr_type_di_node: &'ll DIType, tag_base_type: Ty<'tcx>, tag_field: usize, - dataful_variant_index: Option, + untagged_variant_index: Option, ) -> SmallVec<&'ll DIType> { let tag_base_type_di_node = type_di_node(cx, tag_base_type); let mut unions_fields = SmallVec::with_capacity(variant_field_infos.len() + 1); @@ -776,7 +776,7 @@ fn build_union_fields_for_direct_tag_enum_or_generator<'ll, 'tcx>( enum_type_and_layout, enum_type_di_node, variant_member_info.variant_index, - dataful_variant_index, + untagged_variant_index, variant_member_info.variant_struct_type_di_node, discr_type_di_node, tag_base_type_di_node, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs index 9b3d080bfd6a..14044d0f99b9 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs @@ -417,7 +417,7 @@ impl DiscrResult { /// Returns the discriminant value corresponding to the variant index. /// /// Will return `None` if there is less than two variants (because then the enum won't have) -/// a tag, and if this is the dataful variant of a niche-layout enum (because then there is no +/// a tag, and if this is the untagged variant of a niche-layout enum (because then there is no /// single discriminant value). fn compute_discriminant_value<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, @@ -430,11 +430,11 @@ fn compute_discriminant_value<'ll, 'tcx>( enum_type_and_layout.ty.discriminant_for_variant(cx.tcx, variant_index).unwrap().val, ), &Variants::Multiple { - tag_encoding: TagEncoding::Niche { ref niche_variants, niche_start, dataful_variant }, + tag_encoding: TagEncoding::Niche { ref niche_variants, niche_start, untagged_variant }, tag, .. } => { - if variant_index == dataful_variant { + if variant_index == untagged_variant { let valid_range = enum_type_and_layout .for_variant(cx, variant_index) .largest_niche diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs index dae90a43f265..becbccc434d9 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs @@ -378,7 +378,7 @@ fn build_discr_member_di_node<'ll, 'tcx>( /// /// The DW_AT_discr_value is optional, and is omitted if /// - This is the only variant of a univariant enum (i.e. their is no discriminant) -/// - This is the "dataful" variant of a niche-layout enum +/// - This is the "untagged" variant of a niche-layout enum /// (where only the other variants are identified by a single value) /// /// There is only ever a single member, the type of which is a struct that describes the diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 04b8c8636f63..13d8f6eddd1d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -244,7 +244,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { }; bx.intcast(tag.immediate(), cast_to, signed) } - TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => { + TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => { // Rebase from niche values to discriminants, and check // whether the result is in range for the niche variants. let niche_llty = bx.cx().immediate_backend_type(tag.layout); @@ -302,7 +302,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { bx.select( is_niche, niche_discr, - bx.cx().const_uint(cast_to, dataful_variant.as_u32() as u64), + bx.cx().const_uint(cast_to, untagged_variant.as_u32() as u64), ) } } @@ -337,11 +337,11 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { } Variants::Multiple { tag_encoding: - TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start }, + TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start }, tag_field, .. } => { - if variant_index != dataful_variant { + if variant_index != untagged_variant { let niche = self.project_field(bx, tag_field); let niche_llty = bx.cx().immediate_backend_type(niche.layout); let niche_value = variant_index.as_u32() - niche_variants.start().as_u32(); diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 35c2cf8102dc..efa33e185108 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -718,7 +718,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Return the cast value, and the index. (discr_val, index.0) } - TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start } => { + TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => { let tag_val = tag_val.to_scalar(); // Compute the variant this niche value/"tag" corresponds to. With niche layout, // discriminant (encoded in niche/tag) and variant index are the same. @@ -736,7 +736,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if !ptr_valid { throw_ub!(InvalidTag(dbg_val)) } - dataful_variant + untagged_variant } Ok(tag_bits) => { let tag_bits = tag_bits.assert_bits(tag_layout.size); @@ -766,7 +766,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { assert!(usize::try_from(variant_index).unwrap() < variants_len); VariantIdx::from_u32(variant_index) } else { - dataful_variant + untagged_variant } } }; diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index a03b0dfb6038..81b0b5a74598 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -817,7 +817,7 @@ where } abi::Variants::Multiple { tag_encoding: - TagEncoding::Niche { dataful_variant, ref niche_variants, niche_start }, + TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start }, tag: tag_layout, tag_field, .. @@ -825,7 +825,7 @@ where // No need to validate that the discriminant here because the // `TyAndLayout::for_variant()` call earlier already checks the variant is valid. - if variant_index != dataful_variant { + if variant_index != untagged_variant { let variants_start = niche_variants.start().as_u32(); let variant_index_relative = variant_index .as_u32() diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 2c587b76f025..0a5463a021fe 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1047,7 +1047,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { assert!(def.is_enum()); // The current code for niche-filling relies on variant indices - // instead of actual discriminants, so dataful enums with + // instead of actual discriminants, so untagged enums with // explicit discriminants (RFC #2363) would misbehave. let no_explicit_discriminants = def .variants() @@ -1058,7 +1058,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // Niche-filling enum optimization. if !def.repr().inhibit_enum_layout_opt() && no_explicit_discriminants { - let mut dataful_variant = None; + let mut untagged_variant = None; let mut niche_variants = VariantIdx::MAX..=VariantIdx::new(0); // Find one non-ZST variant. @@ -1068,11 +1068,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } for f in fields { if !f.is_zst() { - if dataful_variant.is_none() { - dataful_variant = Some(v); + if untagged_variant.is_none() { + untagged_variant = Some(v); continue 'variants; } else { - dataful_variant = None; + untagged_variant = None; break 'variants; } } @@ -1081,10 +1081,10 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } if niche_variants.start() > niche_variants.end() { - dataful_variant = None; + untagged_variant = None; } - if let Some(i) = dataful_variant { + if let Some(i) = untagged_variant { let count = (niche_variants.end().as_u32() - niche_variants.start().as_u32() + 1) as u128; @@ -1152,7 +1152,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { variants: Variants::Multiple { tag: niche_scalar, tag_encoding: TagEncoding::Niche { - dataful_variant: i, + untagged_variant: i, niche_variants, niche_start, }, @@ -2559,11 +2559,11 @@ where // using more niches than just null (e.g., the first page of // the address space, or unaligned pointers). Variants::Multiple { - tag_encoding: TagEncoding::Niche { dataful_variant, .. }, + tag_encoding: TagEncoding::Niche { untagged_variant, .. }, tag_field, .. } if this.fields.offset(tag_field) == offset => { - Some(this.for_variant(cx, dataful_variant)) + Some(this.for_variant(cx, untagged_variant)) } _ => Some(this), }; diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index 92ce4d91d84d..bcaf209f84b6 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -1130,7 +1130,7 @@ pub enum TagEncoding { /// Niche (values invalid for a type) encoding the discriminant: /// Discriminant and variant index coincide. - /// The variant `dataful_variant` contains a niche at an arbitrary + /// The variant `untagged_variant` contains a niche at an arbitrary /// offset (field `tag_field` of the enum), which for a variant with /// discriminant `d` is set to /// `(d - niche_variants.start).wrapping_add(niche_start)`. @@ -1139,7 +1139,7 @@ pub enum TagEncoding { /// `None` has a null pointer for the second tuple field, and /// `Some` is the identity function (with a non-null reference). Niche { - dataful_variant: VariantIdx, + untagged_variant: VariantIdx, niche_variants: RangeInclusive, niche_start: u128, }, diff --git a/src/test/debuginfo/msvc-pretty-enums.rs b/src/test/debuginfo/msvc-pretty-enums.rs index 45d5ddf5c0eb..7f1be6f27847 100644 --- a/src/test/debuginfo/msvc-pretty-enums.rs +++ b/src/test/debuginfo/msvc-pretty-enums.rs @@ -53,8 +53,8 @@ // cdb-command: dx niche128_none // cdb-check: niche128_none : None [Type: enum2$ >] -// cdb-command: dx wrapping_niche128_dataful -// cdb-check: wrapping_niche128_dataful : X [Type: enum2$] +// cdb-command: dx wrapping_niche128_untagged +// cdb-check: wrapping_niche128_untagged : X [Type: enum2$] // cdb-check: [+0x[...]] __0 [Type: msvc_pretty_enums::Wrapping128] // cdb-command: dx wrapping_niche128_none1 @@ -213,7 +213,7 @@ fn main() { let niche128_some = Some(NonZeroI128::new(123456).unwrap()); let niche128_none: Option = None; - let wrapping_niche128_dataful = + let wrapping_niche128_untagged = unsafe { Wrapping128Niche::X(Wrapping128(340282366920938463463374607431768211454)) }; let wrapping_niche128_none1 = Wrapping128Niche::Y; let wrapping_niche128_none2 = Wrapping128Niche::Z; diff --git a/src/test/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr b/src/test/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr index 6deb1f271a72..bfabe2d12f7f 100644 --- a/src/test/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr +++ b/src/test/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr @@ -411,7 +411,7 @@ error: layout_of(NicheFirst) = Layout { valid_range: 0..=4, }, tag_encoding: Niche { - dataful_variant: 0, + untagged_variant: 0, niche_variants: 1..=2, niche_start: 3, }, @@ -555,7 +555,7 @@ error: layout_of(NicheSecond) = Layout { valid_range: 0..=4, }, tag_encoding: Niche { - dataful_variant: 0, + untagged_variant: 0, niche_variants: 1..=2, niche_start: 3, }, diff --git a/src/test/ui/layout/zero-sized-array-enum-niche.stderr b/src/test/ui/layout/zero-sized-array-enum-niche.stderr index 56d3a52bb7ff..a3e82070e0f5 100644 --- a/src/test/ui/layout/zero-sized-array-enum-niche.stderr +++ b/src/test/ui/layout/zero-sized-array-enum-niche.stderr @@ -353,7 +353,7 @@ error: layout_of(std::result::Result<[u32; 0], Packed>) = Layout { valid_range: 0..=1, }, tag_encoding: Niche { - dataful_variant: 1, + untagged_variant: 1, niche_variants: 0..=0, niche_start: 1, }, From d7a750b50436fbd228b176f6438566625e235990 Mon Sep 17 00:00:00 2001 From: Michael Benfield Date: Tue, 8 Mar 2022 19:07:01 +0000 Subject: [PATCH 4301/5092] Use niche-filling optimization even when multiple variants have data. Fixes #46213 --- compiler/rustc_ast/src/ast.rs | 3 +- .../rustc_const_eval/src/interpret/operand.rs | 10 +- .../rustc_const_eval/src/interpret/place.rs | 6 +- .../src/obligation_forest/mod.rs | 4 + compiler/rustc_errors/src/lib.rs | 4 +- compiler/rustc_hir/src/hir.rs | 15 +- compiler/rustc_middle/src/mir/syntax.rs | 3 +- compiler/rustc_middle/src/thir.rs | 12 +- compiler/rustc_middle/src/ty/layout.rs | 312 +++++++++++------- src/librustdoc/clean/types.rs | 3 +- src/test/ui/stats/hir-stats.rs | 1 + src/test/ui/stats/hir-stats.stderr | 44 +-- src/test/ui/structs-enums/type-sizes.rs | 79 +++++ 13 files changed, 338 insertions(+), 158 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index f25fdc942b08..e38572f609b3 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3075,7 +3075,8 @@ mod size_asserts { static_assert_size!(Block, 48); static_assert_size!(Expr, 104); static_assert_size!(ExprKind, 72); - static_assert_size!(Fn, 192); + #[cfg(not(bootstrap))] + static_assert_size!(Fn, 184); static_assert_size!(ForeignItem, 96); static_assert_size!(ForeignItemKind, 24); static_assert_size!(GenericArg, 24); diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index efa33e185108..ba041810bd19 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -780,13 +780,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } // Some nodes are used a lot. Make sure they don't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64", not(bootstrap)))] mod size_asserts { use super::*; use rustc_data_structures::static_assert_size; // These are in alphabetical order, which is easy to maintain. - static_assert_size!(Immediate, 56); - static_assert_size!(ImmTy<'_>, 72); - static_assert_size!(Operand, 64); - static_assert_size!(OpTy<'_>, 88); + static_assert_size!(Immediate, 48); + static_assert_size!(ImmTy<'_>, 64); + static_assert_size!(Operand, 56); + static_assert_size!(OpTy<'_>, 80); } diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 81b0b5a74598..b328892906df 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -890,6 +890,8 @@ mod size_asserts { static_assert_size!(MemPlaceMeta, 24); static_assert_size!(MemPlace, 40); static_assert_size!(MPlaceTy<'_>, 64); - static_assert_size!(Place, 48); - static_assert_size!(PlaceTy<'_>, 72); + #[cfg(not(bootstrap))] + static_assert_size!(Place, 40); + #[cfg(not(bootstrap))] + static_assert_size!(PlaceTy<'_>, 64); } diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs index 07a96dd7dbbf..e351b650a16c 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs @@ -117,6 +117,10 @@ pub trait ObligationProcessor { } /// The result type used by `process_obligation`. +// `repr(C)` to inhibit the niche filling optimization. Otherwise, the `match` appearing +// in `process_obligations` is significantly slower, which can substantially affect +// benchmarks like `rustc-perf`'s inflate and keccak. +#[repr(C)] #[derive(Debug)] pub enum ProcessResult { Unchanged, diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 37ff6dcff7d7..513225e16064 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -69,8 +69,8 @@ pub type PResult<'a, T> = Result>; // (See also the comment on `DiagnosticBuilder`'s `diagnostic` field.) #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(PResult<'_, ()>, 16); -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(PResult<'_, bool>, 24); +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64", not(bootstrap)))] +rustc_data_structures::static_assert_size!(PResult<'_, bool>, 16); #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)] pub enum SuggestionStyle { diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 50e7c5d2d04c..a668c0e95ce4 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3473,12 +3473,15 @@ mod size_asserts { static_assert_size!(FnDecl<'_>, 40); static_assert_size!(ForeignItem<'_>, 72); static_assert_size!(ForeignItemKind<'_>, 40); - static_assert_size!(GenericArg<'_>, 40); + #[cfg(not(bootstrap))] + static_assert_size!(GenericArg<'_>, 32); static_assert_size!(GenericBound<'_>, 48); static_assert_size!(Generics<'_>, 56); static_assert_size!(Impl<'_>, 80); - static_assert_size!(ImplItem<'_>, 88); - static_assert_size!(ImplItemKind<'_>, 40); + #[cfg(not(bootstrap))] + static_assert_size!(ImplItem<'_>, 80); + #[cfg(not(bootstrap))] + static_assert_size!(ImplItemKind<'_>, 32); static_assert_size!(Item<'_>, 80); static_assert_size!(ItemKind<'_>, 48); static_assert_size!(Local<'_>, 64); @@ -3490,8 +3493,10 @@ mod size_asserts { static_assert_size!(QPath<'_>, 24); static_assert_size!(Stmt<'_>, 32); static_assert_size!(StmtKind<'_>, 16); - static_assert_size!(TraitItem<'_>, 96); - static_assert_size!(TraitItemKind<'_>, 56); + #[cfg(not(bootstrap))] + static_assert_size!(TraitItem<'static>, 88); + #[cfg(not(bootstrap))] + static_assert_size!(TraitItemKind<'_>, 48); static_assert_size!(Ty<'_>, 72); static_assert_size!(TyKind<'_>, 56); } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index bf63b8efaf7a..e149535bec7b 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1231,7 +1231,8 @@ pub enum BinOp { mod size_asserts { use super::*; // These are in alphabetical order, which is easy to maintain. - static_assert_size!(AggregateKind<'_>, 48); + #[cfg(not(bootstrap))] + static_assert_size!(AggregateKind<'_>, 40); static_assert_size!(Operand<'_>, 24); static_assert_size!(Place<'_>, 16); static_assert_size!(PlaceElem<'_>, 24); diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 7e543929b0f3..c50f8b0eebe1 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -825,8 +825,12 @@ mod size_asserts { static_assert_size!(Block, 56); static_assert_size!(Expr<'_>, 64); static_assert_size!(ExprKind<'_>, 40); - static_assert_size!(Pat<'_>, 72); - static_assert_size!(PatKind<'_>, 56); - static_assert_size!(Stmt<'_>, 56); - static_assert_size!(StmtKind<'_>, 48); + #[cfg(not(bootstrap))] + static_assert_size!(Pat<'_>, 64); + #[cfg(not(bootstrap))] + static_assert_size!(PatKind<'_>, 48); + #[cfg(not(bootstrap))] + static_assert_size!(Stmt<'_>, 48); + #[cfg(not(bootstrap))] + static_assert_size!(StmtKind<'_>, 40); } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 0a5463a021fe..abb7ddd88b14 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -22,7 +22,7 @@ use rustc_target::abi::call::{ use rustc_target::abi::*; use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Target}; -use std::cmp; +use std::cmp::{self, Ordering}; use std::fmt; use std::iter; use std::num::NonZeroUsize; @@ -1046,131 +1046,191 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // that allow representation optimization.) assert!(def.is_enum()); - // The current code for niche-filling relies on variant indices - // instead of actual discriminants, so untagged enums with - // explicit discriminants (RFC #2363) would misbehave. - let no_explicit_discriminants = def - .variants() - .iter_enumerated() - .all(|(i, v)| v.discr == ty::VariantDiscr::Relative(i.as_u32())); + // Until we've decided whether to use the tagged or + // niche filling LayoutS, we don't want to intern the + // variant layouts, so we can't store them in the + // overall LayoutS. Store the overall LayoutS + // and the variant LayoutSs here until then. + struct TmpLayout<'tcx> { + layout: LayoutS<'tcx>, + variants: IndexVec>, + } - let mut niche_filling_layout = None; - - // Niche-filling enum optimization. - if !def.repr().inhibit_enum_layout_opt() && no_explicit_discriminants { - let mut untagged_variant = None; - let mut niche_variants = VariantIdx::MAX..=VariantIdx::new(0); - - // Find one non-ZST variant. - 'variants: for (v, fields) in variants.iter_enumerated() { - if absent(fields) { - continue 'variants; + let calculate_niche_filling_layout = + || -> Result>, LayoutError<'tcx>> { + // The current code for niche-filling relies on variant indices + // instead of actual discriminants, so enums with + // explicit discriminants (RFC #2363) would misbehave. + if def.repr().inhibit_enum_layout_opt() + || def + .variants() + .iter_enumerated() + .any(|(i, v)| v.discr != ty::VariantDiscr::Relative(i.as_u32())) + { + return Ok(None); } - for f in fields { - if !f.is_zst() { - if untagged_variant.is_none() { - untagged_variant = Some(v); - continue 'variants; - } else { - untagged_variant = None; - break 'variants; - } - } + + if variants.len() < 2 { + return Ok(None); } - niche_variants = *niche_variants.start().min(&v)..=v; - } - if niche_variants.start() > niche_variants.end() { - untagged_variant = None; - } + let mut align = dl.aggregate_align; + let mut variant_layouts = variants + .iter_enumerated() + .map(|(j, v)| { + let mut st = self.univariant_uninterned( + ty, + v, + &def.repr(), + StructKind::AlwaysSized, + )?; + st.variants = Variants::Single { index: j }; - if let Some(i) = untagged_variant { - let count = (niche_variants.end().as_u32() - - niche_variants.start().as_u32() - + 1) as u128; + align = align.max(st.align); + + Ok(st) + }) + .collect::, _>>()?; + + let largest_variant_index = match variant_layouts + .iter_enumerated() + .max_by_key(|(_i, layout)| layout.size.bytes()) + .map(|(i, _layout)| i) + { + None => return Ok(None), + Some(i) => i, + }; + + let all_indices = VariantIdx::new(0)..=VariantIdx::new(variants.len() - 1); + let needs_disc = |index: VariantIdx| { + index != largest_variant_index && !absent(&variants[index]) + }; + let niche_variants = all_indices.clone().find(|v| needs_disc(*v)).unwrap() + ..=all_indices.rev().find(|v| needs_disc(*v)).unwrap(); + + let count = niche_variants.size_hint().1.unwrap() as u128; // Find the field with the largest niche - let niche_candidate = variants[i] + let (field_index, niche, (niche_start, niche_scalar)) = match variants + [largest_variant_index] .iter() .enumerate() .filter_map(|(j, field)| Some((j, field.largest_niche?))) - .max_by_key(|(_, niche)| niche.available(dl)); - - if let Some((field_index, niche, (niche_start, niche_scalar))) = - niche_candidate.and_then(|(field_index, niche)| { - Some((field_index, niche, niche.reserve(self, count)?)) - }) + .max_by_key(|(_, niche)| niche.available(dl)) + .and_then(|(j, niche)| Some((j, niche, niche.reserve(self, count)?))) { - let mut align = dl.aggregate_align; - let st = variants - .iter_enumerated() - .map(|(j, v)| { - let mut st = self.univariant_uninterned( - ty, - v, - &def.repr(), - StructKind::AlwaysSized, - )?; - st.variants = Variants::Single { index: j }; + None => return Ok(None), + Some(x) => x, + }; - align = align.max(st.align); + let niche_offset = niche.offset + + variant_layouts[largest_variant_index].fields.offset(field_index); + let niche_size = niche.value.size(dl); + let size = variant_layouts[largest_variant_index].size.align_to(align.abi); - Ok(tcx.intern_layout(st)) - }) - .collect::, _>>()?; + let all_variants_fit = + variant_layouts.iter_enumerated_mut().all(|(i, layout)| { + if i == largest_variant_index { + return true; + } - let offset = st[i].fields().offset(field_index) + niche.offset; + layout.largest_niche = None; - // Align the total size to the largest alignment. - let size = st[i].size().align_to(align.abi); + if layout.size <= niche_offset { + // This variant will fit before the niche. + return true; + } - let abi = if st.iter().all(|v| v.abi().is_uninhabited()) { - Abi::Uninhabited - } else if align == st[i].align() && size == st[i].size() { - // When the total alignment and size match, we can use the - // same ABI as the scalar variant with the reserved niche. - match st[i].abi() { - Abi::Scalar(_) => Abi::Scalar(niche_scalar), - Abi::ScalarPair(first, second) => { - // Only the niche is guaranteed to be initialised, - // so use union layout for the other primitive. - if offset.bytes() == 0 { - Abi::ScalarPair(niche_scalar, second.to_union()) - } else { - Abi::ScalarPair(first.to_union(), niche_scalar) + // Determine if it'll fit after the niche. + let this_align = layout.align.abi; + let this_offset = (niche_offset + niche_size).align_to(this_align); + + if this_offset + layout.size > size { + return false; + } + + // It'll fit, but we need to make some adjustments. + match layout.fields { + FieldsShape::Arbitrary { ref mut offsets, .. } => { + for (j, offset) in offsets.iter_mut().enumerate() { + if !variants[i][j].is_zst() { + *offset += this_offset; + } } } - _ => Abi::Aggregate { sized: true }, + _ => { + panic!("Layout of fields should be Arbitrary for variants") + } } - } else { - Abi::Aggregate { sized: true } - }; - let largest_niche = Niche::from_scalar(dl, offset, niche_scalar); + // It can't be a Scalar or ScalarPair because the offset isn't 0. + if !layout.abi.is_uninhabited() { + layout.abi = Abi::Aggregate { sized: true }; + } + layout.size += this_offset; - niche_filling_layout = Some(LayoutS { - variants: Variants::Multiple { - tag: niche_scalar, - tag_encoding: TagEncoding::Niche { - untagged_variant: i, - niche_variants, - niche_start, - }, - tag_field: 0, - variants: st, - }, - fields: FieldsShape::Arbitrary { - offsets: vec![offset], - memory_index: vec![0], - }, - abi, - largest_niche, - size, - align, + true }); + + if !all_variants_fit { + return Ok(None); } - } - } + + let largest_niche = Niche::from_scalar(dl, niche_offset, niche_scalar); + + let others_zst = variant_layouts.iter_enumerated().all(|(i, layout)| { + i == largest_variant_index || layout.size == Size::ZERO + }); + let same_size = size == variant_layouts[largest_variant_index].size; + let same_align = align == variant_layouts[largest_variant_index].align; + + let abi = if variant_layouts.iter().all(|v| v.abi.is_uninhabited()) { + Abi::Uninhabited + } else if same_size && same_align && others_zst { + match variant_layouts[largest_variant_index].abi { + // When the total alignment and size match, we can use the + // same ABI as the scalar variant with the reserved niche. + Abi::Scalar(_) => Abi::Scalar(niche_scalar), + Abi::ScalarPair(first, second) => { + // Only the niche is guaranteed to be initialised, + // so use union layouts for the other primitive. + if niche_offset == Size::ZERO { + Abi::ScalarPair(niche_scalar, second.to_union()) + } else { + Abi::ScalarPair(first.to_union(), niche_scalar) + } + } + _ => Abi::Aggregate { sized: true }, + } + } else { + Abi::Aggregate { sized: true } + }; + + let layout = LayoutS { + variants: Variants::Multiple { + tag: niche_scalar, + tag_encoding: TagEncoding::Niche { + untagged_variant: largest_variant_index, + niche_variants, + niche_start, + }, + tag_field: 0, + variants: IndexVec::new(), + }, + fields: FieldsShape::Arbitrary { + offsets: vec![niche_offset], + memory_index: vec![0], + }, + abi, + largest_niche, + size, + align, + }; + + Ok(Some(TmpLayout { layout, variants: variant_layouts })) + }; + + let niche_filling_layout = calculate_niche_filling_layout()?; let (mut min, mut max) = (i128::MAX, i128::MIN); let discr_type = def.repr().discr_type(); @@ -1425,15 +1485,12 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag); - let layout_variants = - layout_variants.into_iter().map(|v| tcx.intern_layout(v)).collect(); - let tagged_layout = LayoutS { variants: Variants::Multiple { tag, tag_encoding: TagEncoding::Direct, tag_field: 0, - variants: layout_variants, + variants: IndexVec::new(), }, fields: FieldsShape::Arbitrary { offsets: vec![Size::ZERO], @@ -1445,20 +1502,45 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { size, }; - let best_layout = match (tagged_layout, niche_filling_layout) { - (tagged_layout, Some(niche_filling_layout)) => { + let tagged_layout = TmpLayout { layout: tagged_layout, variants: layout_variants }; + + let mut best_layout = match (tagged_layout, niche_filling_layout) { + (tl, Some(nl)) => { // Pick the smaller layout; otherwise, // pick the layout with the larger niche; otherwise, // pick tagged as it has simpler codegen. - cmp::min_by_key(tagged_layout, niche_filling_layout, |layout| { - let niche_size = layout.largest_niche.map_or(0, |n| n.available(dl)); - (layout.size, cmp::Reverse(niche_size)) - }) + use Ordering::*; + let niche_size = |tmp_l: &TmpLayout<'_>| { + tmp_l.layout.largest_niche.map_or(0, |n| n.available(dl)) + }; + match ( + tl.layout.size.cmp(&nl.layout.size), + niche_size(&tl).cmp(&niche_size(&nl)), + ) { + (Greater, _) => nl, + (Equal, Less) => nl, + _ => tl, + } } - (tagged_layout, None) => tagged_layout, + (tl, None) => tl, }; - tcx.intern_layout(best_layout) + // Now we can intern the variant layouts and store them in the enum layout. + best_layout.layout.variants = match best_layout.layout.variants { + Variants::Multiple { tag, tag_encoding, tag_field, .. } => Variants::Multiple { + tag, + tag_encoding, + tag_field, + variants: best_layout + .variants + .into_iter() + .map(|layout| tcx.intern_layout(layout)) + .collect(), + }, + _ => bug!(), + }; + + tcx.intern_layout(best_layout.layout) } // Types with no meaningful known layout. diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index d6bb7c6c4fc8..2077cf71b2ef 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2532,7 +2532,8 @@ mod size_asserts { // These are in alphabetical order, which is easy to maintain. static_assert_size!(Crate, 72); // frequently moved by-value static_assert_size!(DocFragment, 32); - static_assert_size!(GenericArg, 64); + #[cfg(not(bootstrap))] + static_assert_size!(GenericArg, 56); static_assert_size!(GenericArgs, 32); static_assert_size!(GenericParamDef, 56); static_assert_size!(Item, 56); diff --git a/src/test/ui/stats/hir-stats.rs b/src/test/ui/stats/hir-stats.rs index a24b3ada57e5..5102574d4be3 100644 --- a/src/test/ui/stats/hir-stats.rs +++ b/src/test/ui/stats/hir-stats.rs @@ -1,6 +1,7 @@ // check-pass // compile-flags: -Zhir-stats // only-x86_64 +// ignore-stage1 // The aim here is to include at least one of every different type of top-level // AST/HIR node reported by `-Zhir-stats`. diff --git a/src/test/ui/stats/hir-stats.stderr b/src/test/ui/stats/hir-stats.stderr index 0a736f7be834..c8ceb6ff22df 100644 --- a/src/test/ui/stats/hir-stats.stderr +++ b/src/test/ui/stats/hir-stats.stderr @@ -21,39 +21,39 @@ ast-stats-1 - MacCall 32 ( 0.4%) 1 ast-stats-1 - Expr 96 ( 1.1%) 3 ast-stats-1 Param 160 ( 1.9%) 4 40 ast-stats-1 FnDecl 200 ( 2.4%) 5 40 -ast-stats-1 Variant 240 ( 2.8%) 2 120 +ast-stats-1 Variant 240 ( 2.9%) 2 120 ast-stats-1 Block 288 ( 3.4%) 6 48 ast-stats-1 GenericBound 352 ( 4.2%) 4 88 ast-stats-1 - Trait 352 ( 4.2%) 4 ast-stats-1 AssocItem 416 ( 4.9%) 4 104 ast-stats-1 - TyAlias 208 ( 2.5%) 2 ast-stats-1 - Fn 208 ( 2.5%) 2 -ast-stats-1 GenericParam 520 ( 6.1%) 5 104 -ast-stats-1 PathSegment 720 ( 8.5%) 30 24 -ast-stats-1 Expr 832 ( 9.8%) 8 104 +ast-stats-1 GenericParam 480 ( 5.7%) 5 96 +ast-stats-1 PathSegment 720 ( 8.6%) 30 24 +ast-stats-1 Expr 832 ( 9.9%) 8 104 ast-stats-1 - Path 104 ( 1.2%) 1 ast-stats-1 - Match 104 ( 1.2%) 1 ast-stats-1 - Struct 104 ( 1.2%) 1 ast-stats-1 - Lit 208 ( 2.5%) 2 ast-stats-1 - Block 312 ( 3.7%) 3 -ast-stats-1 Pat 840 ( 9.9%) 7 120 +ast-stats-1 Pat 840 (10.0%) 7 120 ast-stats-1 - Struct 120 ( 1.4%) 1 ast-stats-1 - Wild 120 ( 1.4%) 1 ast-stats-1 - Ident 600 ( 7.1%) 5 -ast-stats-1 Ty 1_344 (15.9%) 14 96 +ast-stats-1 Ty 1_344 (16.0%) 14 96 ast-stats-1 - Rptr 96 ( 1.1%) 1 ast-stats-1 - Ptr 96 ( 1.1%) 1 ast-stats-1 - ImplicitSelf 192 ( 2.3%) 2 ast-stats-1 - Path 960 (11.4%) 10 -ast-stats-1 Item 1_656 (19.6%) 9 184 +ast-stats-1 Item 1_656 (19.7%) 9 184 ast-stats-1 - Trait 184 ( 2.2%) 1 ast-stats-1 - Enum 184 ( 2.2%) 1 ast-stats-1 - ForeignMod 184 ( 2.2%) 1 ast-stats-1 - Impl 184 ( 2.2%) 1 ast-stats-1 - Fn 368 ( 4.4%) 2 -ast-stats-1 - Use 552 ( 6.5%) 3 +ast-stats-1 - Use 552 ( 6.6%) 3 ast-stats-1 ---------------------------------------------------------------- -ast-stats-1 Total 8_456 +ast-stats-1 Total 8_416 ast-stats-1 ast-stats-2 POST EXPANSION AST STATS ast-stats-2 Name Accumulated Size Count Item Size @@ -86,12 +86,12 @@ ast-stats-2 - Trait 352 ( 3.8%) 4 ast-stats-2 AssocItem 416 ( 4.5%) 4 104 ast-stats-2 - TyAlias 208 ( 2.3%) 2 ast-stats-2 - Fn 208 ( 2.3%) 2 -ast-stats-2 GenericParam 520 ( 5.7%) 5 104 -ast-stats-2 PathSegment 792 ( 8.6%) 33 24 -ast-stats-2 Pat 840 ( 9.1%) 7 120 +ast-stats-2 GenericParam 480 ( 5.2%) 5 96 +ast-stats-2 PathSegment 792 ( 8.7%) 33 24 +ast-stats-2 Pat 840 ( 9.2%) 7 120 ast-stats-2 - Struct 120 ( 1.3%) 1 ast-stats-2 - Wild 120 ( 1.3%) 1 -ast-stats-2 - Ident 600 ( 6.5%) 5 +ast-stats-2 - Ident 600 ( 6.6%) 5 ast-stats-2 Expr 936 (10.2%) 9 104 ast-stats-2 - Path 104 ( 1.1%) 1 ast-stats-2 - Match 104 ( 1.1%) 1 @@ -99,12 +99,12 @@ ast-stats-2 - Struct 104 ( 1.1%) 1 ast-stats-2 - InlineAsm 104 ( 1.1%) 1 ast-stats-2 - Lit 208 ( 2.3%) 2 ast-stats-2 - Block 312 ( 3.4%) 3 -ast-stats-2 Ty 1_344 (14.6%) 14 96 +ast-stats-2 Ty 1_344 (14.7%) 14 96 ast-stats-2 - Rptr 96 ( 1.0%) 1 ast-stats-2 - Ptr 96 ( 1.0%) 1 ast-stats-2 - ImplicitSelf 192 ( 2.1%) 2 ast-stats-2 - Path 960 (10.5%) 10 -ast-stats-2 Item 2_024 (22.0%) 11 184 +ast-stats-2 Item 2_024 (22.1%) 11 184 ast-stats-2 - Trait 184 ( 2.0%) 1 ast-stats-2 - Enum 184 ( 2.0%) 1 ast-stats-2 - ExternCrate 184 ( 2.0%) 1 @@ -113,7 +113,7 @@ ast-stats-2 - Impl 184 ( 2.0%) 1 ast-stats-2 - Fn 368 ( 4.0%) 2 ast-stats-2 - Use 736 ( 8.0%) 4 ast-stats-2 ---------------------------------------------------------------- -ast-stats-2 Total 9_184 +ast-stats-2 Total 9_144 ast-stats-2 hir-stats HIR STATS hir-stats Name Accumulated Size Count Item Size @@ -121,7 +121,7 @@ hir-stats ---------------------------------------------------------------- hir-stats ForeignItemRef 24 ( 0.2%) 1 24 hir-stats Mod 32 ( 0.3%) 1 32 hir-stats ExprField 40 ( 0.4%) 1 40 -hir-stats TraitItemRef 56 ( 0.5%) 2 28 +hir-stats TraitItemRef 56 ( 0.6%) 2 28 hir-stats Param 64 ( 0.6%) 2 32 hir-stats Local 64 ( 0.6%) 1 64 hir-stats InlineAsm 72 ( 0.7%) 1 72 @@ -135,11 +135,11 @@ hir-stats - Semi 32 ( 0.3%) 1 hir-stats - Expr 32 ( 0.3%) 1 hir-stats FnDecl 120 ( 1.2%) 3 40 hir-stats Attribute 128 ( 1.3%) 4 32 +hir-stats GenericArg 128 ( 1.3%) 4 32 +hir-stats - Type 32 ( 0.3%) 1 +hir-stats - Lifetime 96 ( 0.9%) 3 hir-stats GenericArgs 144 ( 1.4%) 3 48 hir-stats Variant 160 ( 1.6%) 2 80 -hir-stats GenericArg 160 ( 1.6%) 4 40 -hir-stats - Type 40 ( 0.4%) 1 -hir-stats - Lifetime 120 ( 1.2%) 3 hir-stats GenericBound 192 ( 1.9%) 4 48 hir-stats - Trait 192 ( 1.9%) 4 hir-stats WherePredicate 216 ( 2.1%) 3 72 @@ -151,7 +151,7 @@ hir-stats - Wild 88 ( 0.9%) 1 hir-stats - Struct 88 ( 0.9%) 1 hir-stats - Binding 264 ( 2.6%) 3 hir-stats Generics 560 ( 5.5%) 10 56 -hir-stats Expr 768 ( 7.5%) 12 64 +hir-stats Expr 768 ( 7.6%) 12 64 hir-stats - Path 64 ( 0.6%) 1 hir-stats - Struct 64 ( 0.6%) 1 hir-stats - Match 64 ( 0.6%) 1 @@ -173,5 +173,5 @@ hir-stats - Path 936 ( 9.2%) 13 hir-stats Path 1_536 (15.1%) 32 48 hir-stats PathSegment 2_240 (22.0%) 40 56 hir-stats ---------------------------------------------------------------- -hir-stats Total 10_200 +hir-stats Total 10_168 hir-stats diff --git a/src/test/ui/structs-enums/type-sizes.rs b/src/test/ui/structs-enums/type-sizes.rs index 73a11a5e743f..7a23f13630a4 100644 --- a/src/test/ui/structs-enums/type-sizes.rs +++ b/src/test/ui/structs-enums/type-sizes.rs @@ -120,6 +120,54 @@ pub enum AlwaysTaggedBecauseItHasNoNiche { B } +pub enum NicheFilledMultipleFields { + A(bool, u8), + B(u8), + C(u8), + D(bool), + E, + F, + G, +} + +struct BoolInTheMiddle(std::num::NonZeroU16, bool, u8); + +enum NicheWithData { + A, + B([u16; 5]), + Largest { a1: u32, a2: BoolInTheMiddle, a3: u32 }, + C, + D(u32, u32), +} + +// A type with almost 2^16 invalid values. +#[repr(u16)] +pub enum NicheU16 { + _0, +} + +pub enum EnumManyVariant { + Dataful(u8, X), + + // 0x100 niche variants. + _00, _01, _02, _03, _04, _05, _06, _07, _08, _09, _0A, _0B, _0C, _0D, _0E, _0F, + _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _1A, _1B, _1C, _1D, _1E, _1F, + _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _2A, _2B, _2C, _2D, _2E, _2F, + _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _3A, _3B, _3C, _3D, _3E, _3F, + _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _4A, _4B, _4C, _4D, _4E, _4F, + _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _5A, _5B, _5C, _5D, _5E, _5F, + _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _6A, _6B, _6C, _6D, _6E, _6F, + _70, _71, _72, _73, _74, _75, _76, _77, _78, _79, _7A, _7B, _7C, _7D, _7E, _7F, + _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _8A, _8B, _8C, _8D, _8E, _8F, + _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _9A, _9B, _9C, _9D, _9E, _9F, + _A0, _A1, _A2, _A3, _A4, _A5, _A6, _A7, _A8, _A9, _AA, _AB, _AC, _AD, _AE, _AF, + _B0, _B1, _B2, _B3, _B4, _B5, _B6, _B7, _B8, _B9, _BA, _BB, _BC, _BD, _BE, _BF, + _C0, _C1, _C2, _C3, _C4, _C5, _C6, _C7, _C8, _C9, _CA, _CB, _CC, _CD, _CE, _CF, + _D0, _D1, _D2, _D3, _D4, _D5, _D6, _D7, _D8, _D9, _DA, _DB, _DC, _DD, _DE, _DF, + _E0, _E1, _E2, _E3, _E4, _E5, _E6, _E7, _E8, _E9, _EA, _EB, _EC, _ED, _EE, _EF, + _F0, _F1, _F2, _F3, _F4, _F5, _F6, _F7, _F8, _F9, _FA, _FB, _FC, _FD, _FE, _FF, +} + pub fn main() { assert_eq!(size_of::(), 1 as usize); assert_eq!(size_of::(), 4 as usize); @@ -170,4 +218,35 @@ pub fn main() { assert_eq!(size_of::(), 8); assert_eq!(size_of::>(), 8); assert_eq!(size_of::>>(), 8); + + assert_eq!(size_of::(), 2); + assert_eq!(size_of::>(), 2); + assert_eq!(size_of::>>(), 2); + + struct S1{ a: u16, b: std::num::NonZeroU16, c: u16, d: u8, e: u32, f: u64, g:[u8;2] } + assert_eq!(size_of::(), 24); + assert_eq!(size_of::>(), 24); + + assert_eq!(size_of::(), 12); + assert_eq!(size_of::>(), 12); + assert_eq!(size_of::>>(), 12); + assert_eq!( + size_of::>>>(), + size_of::<(&(), NicheWithData)>() + ); + + pub enum FillPadding { A(std::num::NonZeroU8, u32), B } + assert_eq!(size_of::(), 8); + assert_eq!(size_of::>(), 8); + assert_eq!(size_of::>>(), 8); + + assert_eq!(size_of::>(), 4); + assert_eq!(size_of::>>(), 4); + assert_eq!(size_of::>(), 4); + + assert_eq!(size_of::>(), 6); + assert_eq!(size_of::>(), 4); + assert_eq!(size_of::>>(), 4); + assert_eq!(size_of::>>(), 6); + assert_eq!(size_of::>>(), 6); } From 36fa12f1a4c638f4d48462bfe94721b1b843004a Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 18 Aug 2022 14:26:59 -0300 Subject: [PATCH 4302/5092] Allow lower_lifetime_binder receive a closure --- compiler/rustc_ast_lowering/src/expr.rs | 59 +++++++++++++------------ compiler/rustc_ast_lowering/src/lib.rs | 53 +++++++++++++--------- 2 files changed, 63 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 77babeb5d39d..89655eafea92 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -847,21 +847,22 @@ impl<'hir> LoweringContext<'_, 'hir> { (body_id, generator_option) }); - let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params); - // Lower outside new scope to preserve `is_in_loop_condition`. - let fn_decl = self.lower_fn_decl(decl, None, FnDeclKind::Closure, None); + self.lower_lifetime_binder(closure_id, generic_params, |lctx, bound_generic_params| { + // Lower outside new scope to preserve `is_in_loop_condition`. + let fn_decl = lctx.lower_fn_decl(decl, None, FnDeclKind::Closure, None); - let c = self.arena.alloc(hir::Closure { - binder: binder_clause, - capture_clause, - bound_generic_params, - fn_decl, - body: body_id, - fn_decl_span: self.lower_span(fn_decl_span), - movability: generator_option, - }); + let c = lctx.arena.alloc(hir::Closure { + binder: binder_clause, + capture_clause, + bound_generic_params, + fn_decl, + body: body_id, + fn_decl_span: lctx.lower_span(fn_decl_span), + movability: generator_option, + }); - hir::ExprKind::Closure(c) + hir::ExprKind::Closure(c) + }) } fn generator_movability_for_fn( @@ -948,23 +949,23 @@ impl<'hir> LoweringContext<'_, 'hir> { body_id }); - let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params); + self.lower_lifetime_binder(closure_id, generic_params, |lctx, bound_generic_params| { + // We need to lower the declaration outside the new scope, because we + // have to conserve the state of being inside a loop condition for the + // closure argument types. + let fn_decl = lctx.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None); - // We need to lower the declaration outside the new scope, because we - // have to conserve the state of being inside a loop condition for the - // closure argument types. - let fn_decl = self.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None); - - let c = self.arena.alloc(hir::Closure { - binder: binder_clause, - capture_clause, - bound_generic_params, - fn_decl, - body, - fn_decl_span: self.lower_span(fn_decl_span), - movability: None, - }); - hir::ExprKind::Closure(c) + let c = lctx.arena.alloc(hir::Closure { + binder: binder_clause, + capture_clause, + bound_generic_params, + fn_decl, + body, + fn_decl_span: lctx.lower_span(fn_decl_span), + movability: None, + }); + hir::ExprKind::Closure(c) + }) } /// Destructure the LHS of complex assignments. diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 3a94c7a91b23..b8becd9b149c 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -808,23 +808,31 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// name resolver owing to lifetime elision; this also populates the resolver's node-id->def-id /// map, so that later calls to `opt_node_id_to_def_id` that refer to these extra lifetime /// parameters will be successful. - #[instrument(level = "debug", skip(self))] + #[instrument(level = "debug", skip(self, in_binder))] #[inline] - fn lower_lifetime_binder( + fn lower_lifetime_binder( &mut self, binder: NodeId, generic_params: &[GenericParam], - ) -> &'hir [hir::GenericParam<'hir>] { - let mut generic_params: Vec<_> = self.lower_generic_params_mut(generic_params).collect(); + in_binder: impl FnOnce(&mut Self, &'hir [hir::GenericParam<'hir>]) -> R, + ) -> R { let extra_lifetimes = self.resolver.take_extra_lifetime_params(binder); debug!(?extra_lifetimes); - generic_params.extend(extra_lifetimes.into_iter().filter_map(|(ident, node_id, res)| { - self.lifetime_res_to_generic_param(ident, node_id, res) - })); + let extra_lifetimes: Vec<_> = extra_lifetimes + .into_iter() + .filter_map(|(ident, node_id, res)| { + self.lifetime_res_to_generic_param(ident, node_id, res) + }) + .collect(); + + let generic_params: Vec<_> = self + .lower_generic_params_mut(generic_params) + .chain(extra_lifetimes.into_iter()) + .collect(); let generic_params = self.arena.alloc_from_iter(generic_params); debug!(?generic_params); - generic_params + in_binder(self, generic_params) } fn with_dyn_type_scope(&mut self, in_scope: bool, f: impl FnOnce(&mut Self) -> T) -> T { @@ -1233,14 +1241,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::TyKind::Rptr(lifetime, self.lower_mt(mt, itctx)) } TyKind::BareFn(ref f) => { - let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params); - hir::TyKind::BareFn(self.arena.alloc(hir::BareFnTy { - generic_params, - unsafety: self.lower_unsafety(f.unsafety), - abi: self.lower_extern(f.ext), - decl: self.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None), - param_names: self.lower_fn_params_to_names(&f.decl), - })) + self.lower_lifetime_binder(t.id, &f.generic_params, |lctx, generic_params| { + hir::TyKind::BareFn(lctx.arena.alloc(hir::BareFnTy { + generic_params, + unsafety: lctx.lower_unsafety(f.unsafety), + abi: lctx.lower_extern(f.ext), + decl: lctx.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None), + param_names: lctx.lower_fn_params_to_names(&f.decl), + })) + }) } TyKind::Never => hir::TyKind::Never, TyKind::Tup(ref tys) => hir::TyKind::Tup( @@ -2133,10 +2142,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { p: &PolyTraitRef, itctx: ImplTraitContext, ) -> hir::PolyTraitRef<'hir> { - let bound_generic_params = - self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params); - let trait_ref = self.lower_trait_ref(&p.trait_ref, itctx); - hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) } + self.lower_lifetime_binder( + p.trait_ref.ref_id, + &p.bound_generic_params, + |lctx, bound_generic_params| { + let trait_ref = lctx.lower_trait_ref(&p.trait_ref, itctx); + hir::PolyTraitRef { bound_generic_params, trait_ref, span: lctx.lower_span(p.span) } + }, + ) } fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> { From bdc865d8f7f50482ae67e942a98bd554e51dda30 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Thu, 8 Sep 2022 06:15:33 +0900 Subject: [PATCH 4303/5092] remove unnecessary `PartialOrd` and `Ord` --- .../rustc_borrowck/src/region_infer/mod.rs | 1 - compiler/rustc_errors/src/lib.rs | 2 +- compiler/rustc_hir/src/def.rs | 2 +- compiler/rustc_lexer/src/lib.rs | 2 +- compiler/rustc_middle/src/mir/syntax.rs | 2 +- compiler/rustc_middle/src/mir/terminator.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 23 ++----------------- 7 files changed, 7 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 8dc9368a0b99..de70b17e44cc 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -135,7 +135,6 @@ pub struct RegionInferenceContext<'tcx> { /// adds a new lower bound to the SCC it is analyzing: so you wind up /// with `'R: 'O` where `'R` is the pick-region and `'O` is the /// minimal viable option. -#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] pub(crate) struct AppliedMemberConstraint { /// The SCC that was affected. (The "member region".) /// diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 68abdd0bad1f..b5f0e22f9254 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -456,7 +456,7 @@ struct HandlerInner { } /// A key denoting where from a diagnostic was stashed. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash)] pub enum StashKey { ItemNoType, UnderscoreForArrayLengths, diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index d5ac07f1e631..b44ee02cfe3b 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -457,7 +457,7 @@ impl PartialRes { /// Different kinds of symbols can coexist even if they share the same textual name. /// Therefore, they each have a separate universe (known as a "namespace"). -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum Namespace { /// The type namespace includes `struct`s, `enum`s, `union`s, `trait`s, and `mod`s /// (and, by extension, crates). diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 178366f7d804..a79c982649af 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -141,7 +141,7 @@ pub enum TokenKind { Unknown, } -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum DocStyle { Outer, Inner, diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index d7b9d59eced5..b49fd6f64587 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -705,7 +705,7 @@ pub enum TerminatorKind<'tcx> { } /// Information about an assertion failure. -#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, PartialOrd)] +#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)] pub enum AssertKind { BoundsCheck { len: O, index: O }, Overflow(BinOp, O, O), diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 9ccf5aea63ca..02a9958525b2 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -14,7 +14,7 @@ use std::slice; pub use super::query::*; -#[derive(Debug, Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, PartialOrd)] +#[derive(Debug, Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)] pub struct SwitchTargets { /// Possible values. The locations to branch to in each case /// are found in the corresponding indices from the `targets` vector. diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index a15a0c298a95..f8a3e5b8bb04 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -57,7 +57,7 @@ use rustc_span::{Span, DUMMY_SP}; use smallvec::{smallvec, SmallVec}; use std::cell::{Cell, RefCell}; use std::collections::BTreeSet; -use std::{cmp, fmt, ptr}; +use std::{fmt, ptr}; use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion}; use imports::{Import, ImportKind, ImportResolver, NameResolution}; @@ -163,7 +163,6 @@ enum ImplTraitContext { Universal(LocalDefId), } -#[derive(Eq)] struct BindingError { name: Symbol, origin: BTreeSet, @@ -171,24 +170,6 @@ struct BindingError { could_be_path: bool, } -impl PartialOrd for BindingError { - fn partial_cmp(&self, other: &BindingError) -> Option { - Some(self.cmp(other)) - } -} - -impl PartialEq for BindingError { - fn eq(&self, other: &BindingError) -> bool { - self.name == other.name - } -} - -impl Ord for BindingError { - fn cmp(&self, other: &BindingError) -> cmp::Ordering { - self.name.cmp(&other.name) - } -} - enum ResolutionError<'a> { /// Error E0401: can't use type or const parameters from outer function. GenericParamsFromOuterFunction(Res, HasGenericParams), @@ -845,7 +826,7 @@ impl<'a> NameBinding<'a> { } } -#[derive(Debug, Default, Clone)] +#[derive(Default, Clone)] pub struct ExternPreludeEntry<'a> { extern_crate_item: Option<&'a NameBinding<'a>>, pub introduced_by_item: bool, From 9f6553e1d66130325a61bfc412b4ea8335f8a28a Mon Sep 17 00:00:00 2001 From: Stanislav Date: Thu, 8 Sep 2022 01:53:20 +0300 Subject: [PATCH 4304/5092] add config for import filtering --- crates/ide/src/annotations.rs | 1 + crates/ide/src/lib.rs | 5 ++++- crates/ide/src/references.rs | 9 ++++++--- crates/rust-analyzer/src/config.rs | 7 +++++++ crates/rust-analyzer/src/handlers.rs | 8 ++++++-- editors/code/package.json | 5 +++++ 6 files changed, 29 insertions(+), 6 deletions(-) diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs index 210c5c7facd2..ba4c330bf3d5 100644 --- a/crates/ide/src/annotations.rs +++ b/crates/ide/src/annotations.rs @@ -158,6 +158,7 @@ pub(crate) fn resolve_annotation(db: &RootDatabase, mut annotation: Annotation) &Semantics::new(db), FilePosition { file_id, offset: annotation.range.start() }, None, + false, ) .map(|result| { result diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index d61d69a090b3..5ad922ddbc27 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -425,8 +425,11 @@ impl Analysis { &self, position: FilePosition, search_scope: Option, + exclude_imports: bool, ) -> Cancellable>> { - self.with_db(|db| references::find_all_refs(&Semantics::new(db), position, search_scope)) + self.with_db(|db| { + references::find_all_refs(&Semantics::new(db), position, search_scope, exclude_imports) + }) } /// Finds all methods and free functions for the file. Does not return tests! diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 6c8ae812c97c..73d118d8bb20 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs @@ -54,6 +54,7 @@ pub(crate) fn find_all_refs( sema: &Semantics<'_, RootDatabase>, position: FilePosition, search_scope: Option, + exclude_imports: bool, ) -> Option> { let _p = profile::span("find_all_refs"); let syntax = sema.parse(position.file_id).syntax().clone(); @@ -79,7 +80,9 @@ pub(crate) fn find_all_refs( retain_adt_literal_usages(&mut usages, def, sema); } - retain_import_usages(&mut usages); + if exclude_imports { + filter_import_references(&mut usages); + } let references = usages .into_iter() @@ -114,7 +117,7 @@ pub(crate) fn find_all_refs( } } -fn retain_import_usages(usages: &mut UsageSearchResult) { +fn filter_import_references(usages: &mut UsageSearchResult) { // todo use this https://github.com/rust-lang/rust-analyzer/blob/master/crates/rust-analyzer/src/config.rs#L432 for (_file_id, refs) in &mut usages.references { @@ -1109,7 +1112,7 @@ impl Foo { fn check_with_scope(ra_fixture: &str, search_scope: Option, expect: Expect) { let (analysis, pos) = fixture::position(ra_fixture); - let refs = analysis.find_all_refs(pos, search_scope).unwrap().unwrap(); + let refs = analysis.find_all_refs(pos, search_scope, false).unwrap().unwrap(); let mut actual = String::new(); for refs in refs { diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 54dcb42d99c7..2fdede40dde8 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -220,6 +220,9 @@ config_data! { /// Controls file watching implementation. files_watcher: FilesWatcherDef = "\"client\"", + /// Exclude imports in "Find All References" + findAllRefs_excludeImports: bool = "false", + /// Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords. highlightRelated_breakPoints_enable: bool = "true", /// Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`). @@ -1147,6 +1150,10 @@ impl Config { } } + pub fn find_all_refs_exclude_imports(&self) -> bool { + self.data.findAllRefs_excludeImports + } + pub fn snippet_cap(&self) -> bool { self.experimental("snippetTextEdit") } diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index d9b669afbe81..70dc37e0c6bf 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs @@ -1012,7 +1012,9 @@ pub(crate) fn handle_references( let _p = profile::span("handle_references"); let position = from_proto::file_position(&snap, params.text_document_position)?; - let refs = match snap.analysis.find_all_refs(position, None)? { + let exclude_imports = snap.config.find_all_refs_exclude_imports(); + + let refs = match snap.analysis.find_all_refs(position, None, exclude_imports)? { None => return Ok(None), Some(refs) => refs, }; @@ -1652,7 +1654,9 @@ fn show_ref_command_link( position: &FilePosition, ) -> Option { if snap.config.hover_actions().references && snap.config.client_commands().show_reference { - if let Some(ref_search_res) = snap.analysis.find_all_refs(*position, None).unwrap_or(None) { + if let Some(ref_search_res) = + snap.analysis.find_all_refs(*position, None, false).unwrap_or(None) + { let uri = to_proto::url(snap, position.file_id); let line_index = snap.file_line_index(position.file_id).ok()?; let position = to_proto::position(&line_index, position.offset); diff --git a/editors/code/package.json b/editors/code/package.json index 767c5875bf7e..3af18dacd495 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -839,6 +839,11 @@ "type": "integer", "minimum": 0 }, + "rust-analyzer.findAllRefs.excludeImports": { + "markdownDescription": "Exclude imports from Find All References results", + "default": false, + "type": "boolean" + }, "rust-analyzer.inlayHints.closureReturnTypeHints.enable": { "markdownDescription": "Whether to show inlay type hints for return types of closures.", "default": "never", From 578fc49fc1bbc5498138c84eecad68ee3de54173 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Wed, 7 Sep 2022 14:46:04 -0700 Subject: [PATCH 4305/5092] Use HashStable_Generic in rustc_type_ir A lot of the types in this crate implemented HashStable directly to avoid circular dependencies. One way around that is to use HashStable_Generic. We adopt that here to avoid a lot of boilerplate. This doesn't update all the types, because some would require `I: Interner + HashStable`. --- Cargo.lock | 1 + compiler/rustc_query_system/Cargo.toml | 1 + .../src/ich/impls_syntax.rs | 2 + compiler/rustc_type_ir/src/lib.rs | 49 ++++--------------- compiler/rustc_type_ir/src/sty.rs | 6 +-- 5 files changed, 16 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 68ea8b51c555..90bcc2e4be42 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3958,6 +3958,7 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", + "rustc_type_ir", "smallvec", "thin-vec", "tracing", diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml index bafc6b0a0823..d7599a56c0b6 100644 --- a/compiler/rustc_query_system/Cargo.toml +++ b/compiler/rustc_query_system/Cargo.toml @@ -21,6 +21,7 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } +rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec = "0.2.8" tracing = "0.1" diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs index d7732cb1825b..0bc811eb0441 100644 --- a/compiler/rustc_query_system/src/ich/impls_syntax.rs +++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs @@ -148,3 +148,5 @@ impl<'tcx> HashStable> for rustc_feature::Features { }); } } + +impl<'ctx> rustc_type_ir::HashStableContext for StableHashingContext<'ctx> {} diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 5488bca8f471..da30344ef7ec 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -23,6 +23,9 @@ pub mod sty; pub use codec::*; pub use sty::*; +/// Needed so we can use #[derive(HashStable_Generic)] +pub trait HashStableContext {} + pub trait Interner { type AdtDef: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord; type SubstsRef: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord; @@ -295,6 +298,7 @@ rustc_index::newtype_index! { /// is the outer fn. /// /// [dbi]: https://en.wikipedia.org/wiki/De_Bruijn_index + #[derive(HashStable_Generic)] pub struct DebruijnIndex { DEBUG_FORMAT = "DebruijnIndex({})", const INNERMOST = 0, @@ -366,7 +370,7 @@ impl DebruijnIndex { } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[derive(Encodable, Decodable)] +#[derive(Encodable, Decodable, HashStable_Generic)] pub enum IntTy { Isize, I8, @@ -413,7 +417,7 @@ impl IntTy { } #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Debug)] -#[derive(Encodable, Decodable)] +#[derive(Encodable, Decodable, HashStable_Generic)] pub enum UintTy { Usize, U8, @@ -460,7 +464,7 @@ impl UintTy { } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[derive(Encodable, Decodable)] +#[derive(Encodable, Decodable, HashStable_Generic)] pub enum FloatTy { F32, F64, @@ -597,7 +601,7 @@ impl UnifyKey for FloatVid { } } -#[derive(Copy, Clone, PartialEq, Decodable, Encodable, Hash)] +#[derive(Copy, Clone, PartialEq, Decodable, Encodable, Hash, HashStable_Generic)] #[rustc_pass_by_value] pub enum Variance { Covariant, // T <: T iff A <: B -- e.g., function return type @@ -666,30 +670,6 @@ impl Variance { } } -impl HashStable for DebruijnIndex { - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - self.as_u32().hash_stable(ctx, hasher); - } -} - -impl HashStable for IntTy { - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - discriminant(self).hash_stable(ctx, hasher); - } -} - -impl HashStable for UintTy { - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - discriminant(self).hash_stable(ctx, hasher); - } -} - -impl HashStable for FloatTy { - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - discriminant(self).hash_stable(ctx, hasher); - } -} - impl HashStable for InferTy { fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { use InferTy::*; @@ -703,12 +683,6 @@ impl HashStable for InferTy { } } -impl HashStable for Variance { - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - discriminant(self).hash_stable(ctx, hasher); - } -} - impl fmt::Debug for IntVarValue { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { @@ -811,6 +785,7 @@ rustc_index::newtype_index! { /// declared, but a type name in a non-zero universe is a placeholder /// type -- an idealized representative of "types in general" that we /// use for checking generic functions. + #[derive(HashStable_Generic)] pub struct UniverseIndex { DEBUG_FORMAT = "U{}", } @@ -850,9 +825,3 @@ impl UniverseIndex { self.private < other.private } } - -impl HashStable for UniverseIndex { - fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { - self.private.hash_stable(ctx, hasher); - } -} diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs index 74737e30bb4d..26e48d2d2147 100644 --- a/compiler/rustc_type_ir/src/sty.rs +++ b/compiler/rustc_type_ir/src/sty.rs @@ -3,7 +3,6 @@ use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}; use std::{fmt, hash}; -use crate::DebruijnIndex; use crate::FloatTy; use crate::IntTy; use crate::Interner; @@ -11,6 +10,7 @@ use crate::TyDecoder; use crate::TyEncoder; use crate::UintTy; use crate::UniverseIndex; +use crate::{DebruijnIndex, HashStableContext}; use self::RegionKind::*; use self::TyKind::*; @@ -774,7 +774,7 @@ where // This is not a derived impl because a derive would require `I: HashStable` #[allow(rustc::usage_of_ty_tykind)] -impl HashStable for TyKind +impl HashStable for TyKind where I::AdtDef: HashStable, I::DefId: HashStable, @@ -1286,7 +1286,7 @@ where } // This is not a derived impl because a derive would require `I: HashStable` -impl HashStable for RegionKind +impl HashStable for RegionKind where I::EarlyBoundRegion: HashStable, I::BoundRegion: HashStable, From 6d2935da17da24f196fa90a4cfe6b9b43bfff927 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 7 Sep 2022 17:51:18 -0700 Subject: [PATCH 4306/5092] rustdoc: remove unused CSS `#implementations-list > h3 > span.in-band` This was added in 51f26acaea46afd630fbab4ca441748802d20670 to help with the display of an `

` tag that has a `` inside. The way implementation lists were rendered was changed in 34bd2b845b3acd84c5a9bddae3ff8081c19ec5e9 to have ``, making this CSS unused. Then it was turned into a `
` in 9077d540da944c41678a7129e04e7fc5d7e38582 without issue. Finally, the header itself acquired the `in-band` class in 76a3b609d0b93c5d8da5e4e3db37bd03e5cb1c30. --- src/librustdoc/html/static/css/rustdoc.css | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 7665417cb5c9..736a4352465f 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1528,10 +1528,6 @@ kbd { cursor: default; } -#implementations-list > h3 > span.in-band { - width: 100%; -} - #main-content > ul { padding-left: 10px; } From 00c9d3d2ee99d7350bd9625fc098a4297c9a3523 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 4 Sep 2022 21:11:50 +0000 Subject: [PATCH 4307/5092] Avoid source-map call in operator error --- compiler/rustc_typeck/src/check/op.rs | 34 ++++++++----------- .../ui/binop/binary-op-on-double-ref.stderr | 2 +- .../ui/typeck/assign-non-lval-derefmut.stderr | 4 +-- .../ui/typeck/assign-non-lval-mut-ref.stderr | 4 +-- 4 files changed, 20 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index 0d9dbb5bc11c..fa0fac93276d 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -313,7 +313,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // error types are considered "builtin" Err(_) if lhs_ty.references_error() || rhs_ty.references_error() => self.tcx.ty_error(), Err(errors) => { - let source_map = self.tcx.sess.source_map(); let (mut err, missing_trait, use_output) = match is_assign { IsAssign::Yes => { let mut err = struct_span_err!( @@ -448,24 +447,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) .is_ok() { - if let Ok(lstring) = source_map.span_to_snippet(lhs_expr.span) { - let msg = &format!( - "`{}{}` can be used on `{}`, you can dereference `{}`", - op.node.as_str(), - match is_assign { - IsAssign::Yes => "=", - IsAssign::No => "", - }, - lhs_deref_ty.peel_refs(), - lstring, - ); - err.span_suggestion_verbose( - lhs_expr.span.shrink_to_lo(), - msg, - "*", - rustc_errors::Applicability::MachineApplicable, - ); - } + let msg = &format!( + "`{}{}` can be used on `{}` if you dereference the left-hand side", + op.node.as_str(), + match is_assign { + IsAssign::Yes => "=", + IsAssign::No => "", + }, + lhs_deref_ty, + ); + err.span_suggestion_verbose( + lhs_expr.span.shrink_to_lo(), + msg, + "*", + rustc_errors::Applicability::MachineApplicable, + ); } }; diff --git a/src/test/ui/binop/binary-op-on-double-ref.stderr b/src/test/ui/binop/binary-op-on-double-ref.stderr index 1651f70d5cde..34826d2f4bf7 100644 --- a/src/test/ui/binop/binary-op-on-double-ref.stderr +++ b/src/test/ui/binop/binary-op-on-double-ref.stderr @@ -6,7 +6,7 @@ LL | x % 2 == 0 | | | &&{integer} | -help: `%` can be used on `{integer}`, you can dereference `x` +help: `%` can be used on `&{integer}` if you dereference the left-hand side | LL | *x % 2 == 0 | + diff --git a/src/test/ui/typeck/assign-non-lval-derefmut.stderr b/src/test/ui/typeck/assign-non-lval-derefmut.stderr index a6fcdfe21f48..e394cf8206ed 100644 --- a/src/test/ui/typeck/assign-non-lval-derefmut.stderr +++ b/src/test/ui/typeck/assign-non-lval-derefmut.stderr @@ -19,7 +19,7 @@ LL | x.lock().unwrap() += 1; | | | cannot use `+=` on type `MutexGuard<'_, usize>` | -help: `+=` can be used on `usize`, you can dereference `x.lock().unwrap()` +help: `+=` can be used on `usize` if you dereference the left-hand side | LL | *x.lock().unwrap() += 1; | + @@ -47,7 +47,7 @@ LL | y += 1; | | | cannot use `+=` on type `MutexGuard<'_, usize>` | -help: `+=` can be used on `usize`, you can dereference `y` +help: `+=` can be used on `usize` if you dereference the left-hand side | LL | *y += 1; | + diff --git a/src/test/ui/typeck/assign-non-lval-mut-ref.stderr b/src/test/ui/typeck/assign-non-lval-mut-ref.stderr index be2e9fe95e87..cbdc960baab8 100644 --- a/src/test/ui/typeck/assign-non-lval-mut-ref.stderr +++ b/src/test/ui/typeck/assign-non-lval-mut-ref.stderr @@ -19,7 +19,7 @@ LL | x.last_mut().unwrap() += 1; | | | cannot use `+=` on type `&mut usize` | -help: `+=` can be used on `usize`, you can dereference `x.last_mut().unwrap()` +help: `+=` can be used on `usize` if you dereference the left-hand side | LL | *x.last_mut().unwrap() += 1; | + @@ -45,7 +45,7 @@ LL | y += 1; | | | cannot use `+=` on type `&mut usize` | -help: `+=` can be used on `usize`, you can dereference `y` +help: `+=` can be used on `usize` if you dereference the left-hand side | LL | *y += 1; | + From d0746e886383af7eb9d3ed68f53ff1c19914ec39 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 4 Sep 2022 21:35:13 +0000 Subject: [PATCH 4308/5092] Simplify printing operator lang item paths in error message --- compiler/rustc_typeck/src/check/op.rs | 259 +++++++++++--------------- 1 file changed, 109 insertions(+), 150 deletions(-) diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index fa0fac93276d..c269a9a0c46c 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -11,6 +11,7 @@ use rustc_infer::traits::ObligationCauseCode; use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, }; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor, }; @@ -313,7 +314,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // error types are considered "builtin" Err(_) if lhs_ty.references_error() || rhs_ty.references_error() => self.tcx.ty_error(), Err(errors) => { - let (mut err, missing_trait, use_output) = match is_assign { + let (_, item) = lang_item_for_op(self.tcx, Op::Binary(op, is_assign), op.span); + let missing_trait = + item.map(|def_id| with_no_trimmed_paths!(self.tcx.def_path_str(def_id))); + let (mut err, use_output) = match is_assign { IsAssign::Yes => { let mut err = struct_span_err!( self.tcx.sess, @@ -327,112 +331,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_expr.span, format!("cannot use `{}=` on type `{}`", op.node.as_str(), lhs_ty), ); - let missing_trait = match op.node { - hir::BinOpKind::Add => Some("std::ops::AddAssign"), - hir::BinOpKind::Sub => Some("std::ops::SubAssign"), - hir::BinOpKind::Mul => Some("std::ops::MulAssign"), - hir::BinOpKind::Div => Some("std::ops::DivAssign"), - hir::BinOpKind::Rem => Some("std::ops::RemAssign"), - hir::BinOpKind::BitAnd => Some("std::ops::BitAndAssign"), - hir::BinOpKind::BitXor => Some("std::ops::BitXorAssign"), - hir::BinOpKind::BitOr => Some("std::ops::BitOrAssign"), - hir::BinOpKind::Shl => Some("std::ops::ShlAssign"), - hir::BinOpKind::Shr => Some("std::ops::ShrAssign"), - _ => None, - }; self.note_unmet_impls_on_type(&mut err, errors); - (err, missing_trait, false) + (err, false) } IsAssign::No => { - let (message, missing_trait, use_output) = match op.node { - hir::BinOpKind::Add => ( - format!("cannot add `{rhs_ty}` to `{lhs_ty}`"), - Some("std::ops::Add"), - true, - ), - hir::BinOpKind::Sub => ( - format!("cannot subtract `{rhs_ty}` from `{lhs_ty}`"), - Some("std::ops::Sub"), - true, - ), - hir::BinOpKind::Mul => ( - format!("cannot multiply `{lhs_ty}` by `{rhs_ty}`"), - Some("std::ops::Mul"), - true, - ), - hir::BinOpKind::Div => ( - format!("cannot divide `{lhs_ty}` by `{rhs_ty}`"), - Some("std::ops::Div"), - true, - ), - hir::BinOpKind::Rem => ( - format!("cannot mod `{lhs_ty}` by `{rhs_ty}`"), - Some("std::ops::Rem"), - true, - ), - hir::BinOpKind::BitAnd => ( - format!("no implementation for `{lhs_ty} & {rhs_ty}`"), - Some("std::ops::BitAnd"), - true, - ), - hir::BinOpKind::BitXor => ( - format!("no implementation for `{lhs_ty} ^ {rhs_ty}`"), - Some("std::ops::BitXor"), - true, - ), - hir::BinOpKind::BitOr => ( - format!("no implementation for `{lhs_ty} | {rhs_ty}`"), - Some("std::ops::BitOr"), - true, - ), - hir::BinOpKind::Shl => ( - format!("no implementation for `{lhs_ty} << {rhs_ty}`"), - Some("std::ops::Shl"), - true, - ), - hir::BinOpKind::Shr => ( - format!("no implementation for `{lhs_ty} >> {rhs_ty}`"), - Some("std::ops::Shr"), - true, - ), - hir::BinOpKind::Eq | hir::BinOpKind::Ne => ( - format!( - "binary operation `{}` cannot be applied to type `{}`", - op.node.as_str(), - lhs_ty - ), - Some("std::cmp::PartialEq"), - false, - ), - hir::BinOpKind::Lt - | hir::BinOpKind::Le - | hir::BinOpKind::Gt - | hir::BinOpKind::Ge => ( - format!( - "binary operation `{}` cannot be applied to type `{}`", - op.node.as_str(), - lhs_ty - ), - Some("std::cmp::PartialOrd"), - false, - ), - _ => ( - format!( - "binary operation `{}` cannot be applied to type `{}`", - op.node.as_str(), - lhs_ty - ), - None, - false, + let message = match op.node { + hir::BinOpKind::Add => { + format!("cannot add `{rhs_ty}` to `{lhs_ty}`") + } + hir::BinOpKind::Sub => { + format!("cannot subtract `{rhs_ty}` from `{lhs_ty}`") + } + hir::BinOpKind::Mul => { + format!("cannot multiply `{lhs_ty}` by `{rhs_ty}`") + } + hir::BinOpKind::Div => { + format!("cannot divide `{lhs_ty}` by `{rhs_ty}`") + } + hir::BinOpKind::Rem => { + format!("cannot mod `{lhs_ty}` by `{rhs_ty}`") + } + hir::BinOpKind::BitAnd => { + format!("no implementation for `{lhs_ty} & {rhs_ty}`") + } + hir::BinOpKind::BitXor => { + format!("no implementation for `{lhs_ty} ^ {rhs_ty}`") + } + hir::BinOpKind::BitOr => { + format!("no implementation for `{lhs_ty} | {rhs_ty}`") + } + hir::BinOpKind::Shl => { + format!("no implementation for `{lhs_ty} << {rhs_ty}`") + } + hir::BinOpKind::Shr => { + format!("no implementation for `{lhs_ty} >> {rhs_ty}`") + } + _ => format!( + "binary operation `{}` cannot be applied to type `{}`", + op.node.as_str(), + lhs_ty ), }; + let use_output = item.map_or(false, |def_id| { + self.tcx.associated_item_def_ids(def_id).iter().any(|item_def_id| { + self.tcx.opt_associated_item(*item_def_id).unwrap().name + == sym::Output + }) + }); let mut err = struct_span_err!(self.tcx.sess, op.span, E0369, "{message}"); if !lhs_expr.span.eq(&rhs_expr.span) { err.span_label(lhs_expr.span, lhs_ty.to_string()); err.span_label(rhs_expr.span, rhs_ty.to_string()); } self.note_unmet_impls_on_type(&mut err, errors); - (err, missing_trait, use_output) + (err, use_output) } }; @@ -773,64 +725,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { op: Op, expected: Expectation<'tcx>, ) -> Result, Vec>> { - let lang = self.tcx.lang_items(); - let span = match op { Op::Binary(op, _) => op.span, Op::Unary(_, span) => span, }; - let (opname, trait_did) = if let Op::Binary(op, IsAssign::Yes) = op { - match op.node { - hir::BinOpKind::Add => (sym::add_assign, lang.add_assign_trait()), - hir::BinOpKind::Sub => (sym::sub_assign, lang.sub_assign_trait()), - hir::BinOpKind::Mul => (sym::mul_assign, lang.mul_assign_trait()), - hir::BinOpKind::Div => (sym::div_assign, lang.div_assign_trait()), - hir::BinOpKind::Rem => (sym::rem_assign, lang.rem_assign_trait()), - hir::BinOpKind::BitXor => (sym::bitxor_assign, lang.bitxor_assign_trait()), - hir::BinOpKind::BitAnd => (sym::bitand_assign, lang.bitand_assign_trait()), - hir::BinOpKind::BitOr => (sym::bitor_assign, lang.bitor_assign_trait()), - hir::BinOpKind::Shl => (sym::shl_assign, lang.shl_assign_trait()), - hir::BinOpKind::Shr => (sym::shr_assign, lang.shr_assign_trait()), - hir::BinOpKind::Lt - | hir::BinOpKind::Le - | hir::BinOpKind::Ge - | hir::BinOpKind::Gt - | hir::BinOpKind::Eq - | hir::BinOpKind::Ne - | hir::BinOpKind::And - | hir::BinOpKind::Or => { - span_bug!(span, "impossible assignment operation: {}=", op.node.as_str()) - } - } - } else if let Op::Binary(op, IsAssign::No) = op { - match op.node { - hir::BinOpKind::Add => (sym::add, lang.add_trait()), - hir::BinOpKind::Sub => (sym::sub, lang.sub_trait()), - hir::BinOpKind::Mul => (sym::mul, lang.mul_trait()), - hir::BinOpKind::Div => (sym::div, lang.div_trait()), - hir::BinOpKind::Rem => (sym::rem, lang.rem_trait()), - hir::BinOpKind::BitXor => (sym::bitxor, lang.bitxor_trait()), - hir::BinOpKind::BitAnd => (sym::bitand, lang.bitand_trait()), - hir::BinOpKind::BitOr => (sym::bitor, lang.bitor_trait()), - hir::BinOpKind::Shl => (sym::shl, lang.shl_trait()), - hir::BinOpKind::Shr => (sym::shr, lang.shr_trait()), - hir::BinOpKind::Lt => (sym::lt, lang.partial_ord_trait()), - hir::BinOpKind::Le => (sym::le, lang.partial_ord_trait()), - hir::BinOpKind::Ge => (sym::ge, lang.partial_ord_trait()), - hir::BinOpKind::Gt => (sym::gt, lang.partial_ord_trait()), - hir::BinOpKind::Eq => (sym::eq, lang.eq_trait()), - hir::BinOpKind::Ne => (sym::ne, lang.eq_trait()), - hir::BinOpKind::And | hir::BinOpKind::Or => { - span_bug!(span, "&& and || are not overloadable") - } - } - } else if let Op::Unary(hir::UnOp::Not, _) = op { - (sym::not, lang.not_trait()) - } else if let Op::Unary(hir::UnOp::Neg, _) = op { - (sym::neg, lang.neg_trait()) - } else { - bug!("lookup_op_method: op not supported: {:?}", op) - }; + let (opname, trait_did) = lang_item_for_op(self.tcx, op, span); debug!( "lookup_op_method(lhs_ty={:?}, op={:?}, opname={:?}, trait_did={:?})", @@ -891,6 +790,66 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } +fn lang_item_for_op( + tcx: TyCtxt<'_>, + op: Op, + span: Span, +) -> (rustc_span::Symbol, Option) { + let lang = tcx.lang_items(); + if let Op::Binary(op, IsAssign::Yes) = op { + match op.node { + hir::BinOpKind::Add => (sym::add_assign, lang.add_assign_trait()), + hir::BinOpKind::Sub => (sym::sub_assign, lang.sub_assign_trait()), + hir::BinOpKind::Mul => (sym::mul_assign, lang.mul_assign_trait()), + hir::BinOpKind::Div => (sym::div_assign, lang.div_assign_trait()), + hir::BinOpKind::Rem => (sym::rem_assign, lang.rem_assign_trait()), + hir::BinOpKind::BitXor => (sym::bitxor_assign, lang.bitxor_assign_trait()), + hir::BinOpKind::BitAnd => (sym::bitand_assign, lang.bitand_assign_trait()), + hir::BinOpKind::BitOr => (sym::bitor_assign, lang.bitor_assign_trait()), + hir::BinOpKind::Shl => (sym::shl_assign, lang.shl_assign_trait()), + hir::BinOpKind::Shr => (sym::shr_assign, lang.shr_assign_trait()), + hir::BinOpKind::Lt + | hir::BinOpKind::Le + | hir::BinOpKind::Ge + | hir::BinOpKind::Gt + | hir::BinOpKind::Eq + | hir::BinOpKind::Ne + | hir::BinOpKind::And + | hir::BinOpKind::Or => { + span_bug!(span, "impossible assignment operation: {}=", op.node.as_str()) + } + } + } else if let Op::Binary(op, IsAssign::No) = op { + match op.node { + hir::BinOpKind::Add => (sym::add, lang.add_trait()), + hir::BinOpKind::Sub => (sym::sub, lang.sub_trait()), + hir::BinOpKind::Mul => (sym::mul, lang.mul_trait()), + hir::BinOpKind::Div => (sym::div, lang.div_trait()), + hir::BinOpKind::Rem => (sym::rem, lang.rem_trait()), + hir::BinOpKind::BitXor => (sym::bitxor, lang.bitxor_trait()), + hir::BinOpKind::BitAnd => (sym::bitand, lang.bitand_trait()), + hir::BinOpKind::BitOr => (sym::bitor, lang.bitor_trait()), + hir::BinOpKind::Shl => (sym::shl, lang.shl_trait()), + hir::BinOpKind::Shr => (sym::shr, lang.shr_trait()), + hir::BinOpKind::Lt => (sym::lt, lang.partial_ord_trait()), + hir::BinOpKind::Le => (sym::le, lang.partial_ord_trait()), + hir::BinOpKind::Ge => (sym::ge, lang.partial_ord_trait()), + hir::BinOpKind::Gt => (sym::gt, lang.partial_ord_trait()), + hir::BinOpKind::Eq => (sym::eq, lang.eq_trait()), + hir::BinOpKind::Ne => (sym::ne, lang.eq_trait()), + hir::BinOpKind::And | hir::BinOpKind::Or => { + span_bug!(span, "&& and || are not overloadable") + } + } + } else if let Op::Unary(hir::UnOp::Not, _) = op { + (sym::not, lang.not_trait()) + } else if let Op::Unary(hir::UnOp::Neg, _) = op { + (sym::neg, lang.neg_trait()) + } else { + bug!("lookup_op_method: op not supported: {:?}", op) + } +} + // Binary operator categories. These categories summarize the behavior // with respect to the builtin operations supported. enum BinOpCategory { From 0dbbf0f49398d6c74fd3337dd171fac6c7aa3d12 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 4 Sep 2022 21:55:38 +0000 Subject: [PATCH 4309/5092] Remove TypeParamVisitor --- compiler/rustc_typeck/src/check/op.rs | 36 ++++++--------------------- 1 file changed, 7 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index c269a9a0c46c..a7e080c13c7d 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -12,9 +12,7 @@ use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, }; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor, -}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable}; use rustc_span::source_map::Spanned; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; @@ -23,8 +21,6 @@ use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt as use rustc_trait_selection::traits::{FulfillmentError, TraitEngine, TraitEngineExt}; use rustc_type_ir::sty::TyKind::*; -use std::ops::ControlFlow; - impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Checks a `a = b` pub fn check_binop_assign( @@ -462,9 +458,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if let Some(missing_trait) = missing_trait { - let mut visitor = TypeParamVisitor(vec![]); - visitor.visit_ty(lhs_ty); - if op.node == hir::BinOpKind::Add && self.check_str_addition( lhs_expr, rhs_expr, lhs_ty, rhs_ty, &mut err, is_assign, op, @@ -473,7 +466,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This has nothing here because it means we did string // concatenation (e.g., "Hello " + "World!"). This means // we don't want the note in the else clause to be emitted - } else if let [ty] = &visitor.0[..] { + } else if lhs_ty.has_param_types_or_consts() { // Look for a TraitPredicate in the Fulfillment errors, // and use it to generate a suggestion. // @@ -513,7 +506,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } } - } else if *ty != lhs_ty { + } else { // When we know that a missing bound is responsible, we don't show // this note as it is redundant. err.note(&format!( @@ -650,14 +643,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("cannot apply unary operator `{}`", op.as_str()), ); - let mut visitor = TypeParamVisitor(vec![]); - visitor.visit_ty(operand_ty); - if let [_] = &visitor.0[..] && let ty::Param(_) = *operand_ty.kind() { - let predicates = errors - .iter() - .filter_map(|error| { - error.obligation.predicate.to_opt_poly_trait_pred() - }); + if operand_ty.has_param_types_or_consts() { + let predicates = errors.iter().filter_map(|error| { + error.obligation.predicate.to_opt_poly_trait_pred() + }); for pred in predicates { self.suggest_restricting_param_bound( &mut err, @@ -972,17 +961,6 @@ fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>, rhs: Ty<'tcx>, op: hir::BinOp) -> bool } } -struct TypeParamVisitor<'tcx>(Vec>); - -impl<'tcx> TypeVisitor<'tcx> for TypeParamVisitor<'tcx> { - fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { - if let ty::Param(_) = ty.kind() { - self.0.push(ty); - } - ty.super_visit_with(self) - } -} - struct TypeParamEraser<'a, 'tcx>(&'a FnCtxt<'a, 'tcx>, Span); impl<'tcx> TypeFolder<'tcx> for TypeParamEraser<'_, 'tcx> { From 30e3673d437d7ca049d6080eee19e696c3d7429f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 4 Sep 2022 22:21:15 +0000 Subject: [PATCH 4310/5092] Add associated item binding to non-param-ty where clause suggestions --- compiler/rustc_middle/src/traits/mod.rs | 4 +- compiler/rustc_middle/src/ty/diagnostics.rs | 14 +++++- .../src/traits/error_reporting/suggestions.rs | 24 +++++----- .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 2 +- compiler/rustc_typeck/src/check/method/mod.rs | 26 ++-------- compiler/rustc_typeck/src/check/op.rs | 47 ++++++++++++------- .../traits/resolution-in-overloaded-op.stderr | 4 +- 7 files changed, 65 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index ab7e5ba3a106..a56fac7c4dd2 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -12,7 +12,7 @@ pub mod util; use crate::infer::canonical::Canonical; use crate::ty::abstract_const::NotConstEvaluatable; use crate::ty::subst::SubstsRef; -use crate::ty::{self, AdtKind, Predicate, Ty, TyCtxt}; +use crate::ty::{self, AdtKind, Ty, TyCtxt}; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, Diagnostic}; @@ -416,7 +416,7 @@ pub enum ObligationCauseCode<'tcx> { BinOp { rhs_span: Option, is_lit: bool, - output_pred: Option>, + output_ty: Option>, }, } diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index dd2f43210603..fc6a77d400d4 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -102,13 +102,25 @@ pub fn suggest_arbitrary_trait_bound<'tcx>( generics: &hir::Generics<'_>, err: &mut Diagnostic, trait_pred: PolyTraitPredicate<'tcx>, + associated_ty: Option<(&'static str, Ty<'tcx>)>, ) -> bool { if !trait_pred.is_suggestable(tcx, false) { return false; } let param_name = trait_pred.skip_binder().self_ty().to_string(); - let constraint = trait_pred.print_modifiers_and_trait_path().to_string(); + let mut constraint = trait_pred.print_modifiers_and_trait_path().to_string(); + + if let Some((name, term)) = associated_ty { + // FIXME: this case overlaps with code in TyCtxt::note_and_explain_type_err. + // That should be extracted into a helper function. + if constraint.ends_with('>') { + constraint = format!("{}, {}={}>", &constraint[..constraint.len() - 1], name, term); + } else { + constraint.push_str(&format!("<{}={}>", name, term)); + } + } + let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name); // Skip, there is a param named Self diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index b012073f7719..595c68166bc8 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -25,8 +25,7 @@ use rustc_middle::hir::map; use rustc_middle::ty::{ self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree, GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, IsSuggestable, - ProjectionPredicate, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, - TypeVisitable, + ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, }; use rustc_middle::ty::{TypeAndMut, TypeckResults}; use rustc_session::Limit; @@ -174,7 +173,7 @@ pub trait InferCtxtExt<'tcx> { &self, err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, - proj_pred: Option>, + associated_item: Option<(&'static str, Ty<'tcx>)>, body_id: hir::HirId, ); @@ -467,7 +466,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &self, mut err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, - proj_pred: Option>, + associated_ty: Option<(&'static str, Ty<'tcx>)>, body_id: hir::HirId, ) { let trait_pred = self.resolve_numeric_literals_with_default(trait_pred); @@ -604,21 +603,18 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { trait_pred.print_modifiers_and_trait_path().to_string() ); - if let Some(proj_pred) = proj_pred { - let ProjectionPredicate { projection_ty, term } = proj_pred.skip_binder(); - let item = self.tcx.associated_item(projection_ty.item_def_id); - + if let Some((name, term)) = associated_ty { // FIXME: this case overlaps with code in TyCtxt::note_and_explain_type_err. // That should be extracted into a helper function. if constraint.ends_with('>') { constraint = format!( "{}, {}={}>", &constraint[..constraint.len() - 1], - item.name, + name, term ); } else { - constraint.push_str(&format!("<{}={}>", item.name, term)); + constraint.push_str(&format!("<{}={}>", name, term)); } } @@ -648,7 +644,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { .. }) if !param_ty => { // Missing generic type parameter bound. - if suggest_arbitrary_trait_bound(self.tcx, generics, &mut err, trait_pred) { + if suggest_arbitrary_trait_bound( + self.tcx, + generics, + &mut err, + trait_pred, + associated_ty, + ) { return; } } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index c59638f5d6f9..2196a799fd0b 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -409,7 +409,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rhs_span: opt_input_expr.map(|expr| expr.span), is_lit: opt_input_expr .map_or(false, |expr| matches!(expr.kind, ExprKind::Lit(_))), - output_pred: None, + output_ty: None, }, ), self.param_env, diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs index c597efbe7468..249e9c66ba72 100644 --- a/compiler/rustc_typeck/src/check/method/mod.rs +++ b/compiler/rustc_typeck/src/check/method/mod.rs @@ -20,10 +20,7 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::{self, InferOk}; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; -use rustc_middle::ty::{ - self, AssocKind, DefIdTree, GenericParamDefKind, ProjectionPredicate, ProjectionTy, - ToPredicate, Ty, TypeVisitable, -}; +use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, ToPredicate, Ty, TypeVisitable}; use rustc_span::symbol::Ident; use rustc_span::Span; use rustc_trait_selection::traits; @@ -337,22 +334,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Construct an obligation let poly_trait_ref = ty::Binder::dummy(trait_ref); - let opt_output_ty = - expected.only_has_type(self).and_then(|ty| (!ty.needs_infer()).then(|| ty)); - let opt_output_assoc_item = self.tcx.associated_items(trait_def_id).find_by_name_and_kind( - self.tcx, - Ident::from_str("Output"), - AssocKind::Type, - trait_def_id, - ); - let output_pred = - opt_output_ty.zip(opt_output_assoc_item).map(|(output_ty, output_assoc_item)| { - ty::Binder::dummy(ty::PredicateKind::Projection(ProjectionPredicate { - projection_ty: ProjectionTy { substs, item_def_id: output_assoc_item.def_id }, - term: output_ty.into(), - })) - .to_predicate(self.tcx) - }); + let output_ty = expected.only_has_type(self).and_then(|ty| (!ty.needs_infer()).then(|| ty)); ( traits::Obligation::new( @@ -363,7 +345,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rhs_span: opt_input_expr.map(|expr| expr.span), is_lit: opt_input_expr .map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))), - output_pred, + output_ty, }, ), self.param_env, @@ -518,7 +500,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rhs_span: opt_input_expr.map(|expr| expr.span), is_lit: opt_input_expr .map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))), - output_pred: None, + output_ty: None, }, ) } else { diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index a7e080c13c7d..4754717c29ab 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -12,7 +12,7 @@ use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, }; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable}; +use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable}; use rustc_span::source_map::Spanned; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; @@ -310,10 +310,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // error types are considered "builtin" Err(_) if lhs_ty.references_error() || rhs_ty.references_error() => self.tcx.ty_error(), Err(errors) => { - let (_, item) = lang_item_for_op(self.tcx, Op::Binary(op, is_assign), op.span); - let missing_trait = - item.map(|def_id| with_no_trimmed_paths!(self.tcx.def_path_str(def_id))); - let (mut err, use_output) = match is_assign { + let (_, trait_def_id) = + lang_item_for_op(self.tcx, Op::Binary(op, is_assign), op.span); + let missing_trait = trait_def_id + .map(|def_id| with_no_trimmed_paths!(self.tcx.def_path_str(def_id))); + let (mut err, output_def_id) = match is_assign { IsAssign::Yes => { let mut err = struct_span_err!( self.tcx.sess, @@ -328,7 +329,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("cannot use `{}=` on type `{}`", op.node.as_str(), lhs_ty), ); self.note_unmet_impls_on_type(&mut err, errors); - (err, false) + (err, None) } IsAssign::No => { let message = match op.node { @@ -368,11 +369,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_ty ), }; - let use_output = item.map_or(false, |def_id| { - self.tcx.associated_item_def_ids(def_id).iter().any(|item_def_id| { - self.tcx.opt_associated_item(*item_def_id).unwrap().name - == sym::Output - }) + let output_def_id = trait_def_id.and_then(|def_id| { + self.tcx + .associated_item_def_ids(def_id) + .iter() + .find(|item_def_id| { + self.tcx.associated_item(*item_def_id).name == sym::Output + }) + .cloned() }); let mut err = struct_span_err!(self.tcx.sess, op.span, E0369, "{message}"); if !lhs_expr.span.eq(&rhs_expr.span) { @@ -380,7 +384,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(rhs_expr.span, rhs_ty.to_string()); } self.note_unmet_impls_on_type(&mut err, errors); - (err, use_output) + (err, output_def_id) } }; @@ -488,12 +492,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(trait_pred) = error.obligation.predicate.to_opt_poly_trait_pred() { - let proj_pred = match error.obligation.cause.code() { + let output_associated_item = match error.obligation.cause.code() + { ObligationCauseCode::BinOp { - output_pred: Some(output_pred), + output_ty: Some(output_ty), .. - } if use_output => { - output_pred.to_opt_poly_projection_pred() + } => { + // Make sure that we're attaching `Output = ..` to the right trait predicate + if let Some(output_def_id) = output_def_id + && let Some(trait_def_id) = trait_def_id + && self.tcx.parent(output_def_id) == trait_def_id + { + Some(("Output", *output_ty)) + } else { + None + } } _ => None, }; @@ -501,7 +514,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.suggest_restricting_param_bound( &mut err, trait_pred, - proj_pred, + output_associated_item, self.body_id, ); } diff --git a/src/test/ui/traits/resolution-in-overloaded-op.stderr b/src/test/ui/traits/resolution-in-overloaded-op.stderr index 34fae64e4d20..b67e334d40ac 100644 --- a/src/test/ui/traits/resolution-in-overloaded-op.stderr +++ b/src/test/ui/traits/resolution-in-overloaded-op.stderr @@ -8,8 +8,8 @@ LL | a * b | help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement | -LL | fn foo>(a: &T, b: f64) -> f64 where &T: Mul { - | ++++++++++++++++++ +LL | fn foo>(a: &T, b: f64) -> f64 where &T: Mul { + | ++++++++++++++++++++++++++++++ error: aborting due to previous error From 48281b003ff84b230947f64aad9054113f757795 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 4 Sep 2022 22:38:12 +0000 Subject: [PATCH 4311/5092] Adjust spacing in suggestion, add a test --- compiler/rustc_middle/src/ty/diagnostics.rs | 4 +-- .../src/traits/error_reporting/suggestions.rs | 4 +-- .../missing-bounds.fixed | 2 +- .../missing-bounds.stderr | 4 +-- src/test/ui/suggestions/issue-97677.fixed | 2 +- src/test/ui/suggestions/issue-97677.stderr | 4 +-- .../ui/suggestions/restrict-type-not-param.rs | 12 +++++++++ .../restrict-type-not-param.stderr | 26 +++++++++++++++++++ .../traits/resolution-in-overloaded-op.stderr | 4 +-- 9 files changed, 50 insertions(+), 12 deletions(-) create mode 100644 src/test/ui/suggestions/restrict-type-not-param.rs create mode 100644 src/test/ui/suggestions/restrict-type-not-param.stderr diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index fc6a77d400d4..e4ad96b659b0 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -115,9 +115,9 @@ pub fn suggest_arbitrary_trait_bound<'tcx>( // FIXME: this case overlaps with code in TyCtxt::note_and_explain_type_err. // That should be extracted into a helper function. if constraint.ends_with('>') { - constraint = format!("{}, {}={}>", &constraint[..constraint.len() - 1], name, term); + constraint = format!("{}, {} = {}>", &constraint[..constraint.len() - 1], name, term); } else { - constraint.push_str(&format!("<{}={}>", name, term)); + constraint.push_str(&format!("<{} = {}>", name, term)); } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 595c68166bc8..ecbeb9d79b11 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -608,13 +608,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // That should be extracted into a helper function. if constraint.ends_with('>') { constraint = format!( - "{}, {}={}>", + "{}, {} = {}>", &constraint[..constraint.len() - 1], name, term ); } else { - constraint.push_str(&format!("<{}={}>", name, term)); + constraint.push_str(&format!("<{} = {}>", name, term)); } } diff --git a/src/test/ui/generic-associated-types/missing-bounds.fixed b/src/test/ui/generic-associated-types/missing-bounds.fixed index 2315810a47ac..ee758f19ec10 100644 --- a/src/test/ui/generic-associated-types/missing-bounds.fixed +++ b/src/test/ui/generic-associated-types/missing-bounds.fixed @@ -24,7 +24,7 @@ impl> Add for C { struct D(B); -impl> Add for D { +impl> Add for D { type Output = Self; fn add(self, rhs: Self) -> Self { diff --git a/src/test/ui/generic-associated-types/missing-bounds.stderr b/src/test/ui/generic-associated-types/missing-bounds.stderr index 138c642dd795..c913483a8747 100644 --- a/src/test/ui/generic-associated-types/missing-bounds.stderr +++ b/src/test/ui/generic-associated-types/missing-bounds.stderr @@ -66,8 +66,8 @@ LL | Self(self.0 + rhs.0) | help: consider restricting type parameter `B` | -LL | impl> Add for D { - | +++++++++++++++++++++++++ +LL | impl> Add for D { + | +++++++++++++++++++++++++++ error[E0308]: mismatched types --> $DIR/missing-bounds.rs:42:14 diff --git a/src/test/ui/suggestions/issue-97677.fixed b/src/test/ui/suggestions/issue-97677.fixed index 73ca9f97b43a..1e7569fa4510 100644 --- a/src/test/ui/suggestions/issue-97677.fixed +++ b/src/test/ui/suggestions/issue-97677.fixed @@ -1,6 +1,6 @@ // run-rustfix -fn add_ten>(n: N) -> N { +fn add_ten>(n: N) -> N { n + 10 //~^ ERROR cannot add `{integer}` to `N` } diff --git a/src/test/ui/suggestions/issue-97677.stderr b/src/test/ui/suggestions/issue-97677.stderr index 069b184ac636..575d79267f20 100644 --- a/src/test/ui/suggestions/issue-97677.stderr +++ b/src/test/ui/suggestions/issue-97677.stderr @@ -8,8 +8,8 @@ LL | n + 10 | help: consider restricting type parameter `N` | -LL | fn add_ten>(n: N) -> N { - | ++++++++++++++++++++++++++++++ +LL | fn add_ten>(n: N) -> N { + | ++++++++++++++++++++++++++++++++ error: aborting due to previous error diff --git a/src/test/ui/suggestions/restrict-type-not-param.rs b/src/test/ui/suggestions/restrict-type-not-param.rs new file mode 100644 index 000000000000..60f5ba45c268 --- /dev/null +++ b/src/test/ui/suggestions/restrict-type-not-param.rs @@ -0,0 +1,12 @@ +use std::ops::Add; + +struct Wrapper(T); + +trait Foo {} + +fn qux(a: Wrapper, b: T) -> T { + a + b + //~^ ERROR cannot add `T` to `Wrapper` +} + +fn main() {} diff --git a/src/test/ui/suggestions/restrict-type-not-param.stderr b/src/test/ui/suggestions/restrict-type-not-param.stderr new file mode 100644 index 000000000000..e7d9c5ecbe48 --- /dev/null +++ b/src/test/ui/suggestions/restrict-type-not-param.stderr @@ -0,0 +1,26 @@ +error[E0369]: cannot add `T` to `Wrapper` + --> $DIR/restrict-type-not-param.rs:8:7 + | +LL | a + b + | - ^ - T + | | + | Wrapper + | +note: an implementation of `Add<_>` might be missing for `Wrapper` + --> $DIR/restrict-type-not-param.rs:3:1 + | +LL | struct Wrapper(T); + | ^^^^^^^^^^^^^^^^^ must implement `Add<_>` +note: the following trait must be implemented + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL + | +LL | pub trait Add { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + | +LL | fn qux(a: Wrapper, b: T) -> T where Wrapper: Add { + | ++++++++++++++++++++++++++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0369`. diff --git a/src/test/ui/traits/resolution-in-overloaded-op.stderr b/src/test/ui/traits/resolution-in-overloaded-op.stderr index b67e334d40ac..fe5e1d6d2854 100644 --- a/src/test/ui/traits/resolution-in-overloaded-op.stderr +++ b/src/test/ui/traits/resolution-in-overloaded-op.stderr @@ -8,8 +8,8 @@ LL | a * b | help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement | -LL | fn foo>(a: &T, b: f64) -> f64 where &T: Mul { - | ++++++++++++++++++++++++++++++ +LL | fn foo>(a: &T, b: f64) -> f64 where &T: Mul { + | ++++++++++++++++++++++++++++++++ error: aborting due to previous error From 2c94102df522aa6c2f69175ad929761cfbe284ac Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 8 Sep 2022 02:34:22 +0000 Subject: [PATCH 4312/5092] Generator return doesn't need to be a lang item --- compiler/rustc_hir/src/lang_items.rs | 1 - compiler/rustc_middle/src/ty/print/pretty.rs | 6 ++++-- compiler/rustc_span/src/symbol.rs | 1 - library/core/src/ops/generator.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index bc1ea1c4c736..ea17c1de9b70 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -238,7 +238,6 @@ language_item_table! { Future, sym::future_trait, future_trait, Target::Trait, GenericRequirement::Exact(0); GeneratorState, sym::generator_state, gen_state, Target::Enum, GenericRequirement::None; Generator, sym::generator, gen_trait, Target::Trait, GenericRequirement::Minimum(1); - GeneratorReturn, sym::generator_return, generator_return, Target::AssocTy, GenericRequirement::None; Unpin, sym::unpin, unpin_trait, Target::Trait, GenericRequirement::None; Pin, sym::pin, pin_type, Target::Struct, GenericRequirement::None; diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 1ae3063dae4e..b46813e08f10 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -916,8 +916,10 @@ pub trait PrettyPrinter<'tcx>: // Skip printing `<[generator@] as Generator<_>>::Return` from async blocks, // unless we can find out what generator return type it comes from. let term = if let Some(ty) = term.skip_binder().ty() - && let ty::Projection(ty::ProjectionTy { item_def_id, substs }) = ty.kind() - && Some(*item_def_id) == tcx.lang_items().generator_return() + && let ty::Projection(proj) = ty.kind() + && let assoc = tcx.associated_item(proj.item_def_id) + && assoc.trait_container(tcx) == tcx.lang_items().gen_trait() + && assoc.name == rustc_span::sym::Return { if let ty::Generator(_, substs, _) = substs.type_at(0).kind() { let return_ty = substs.as_generator().return_ty(); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 75b1dfc856ac..363a2f53e106 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -763,7 +763,6 @@ symbols! { gen_future, gen_kill, generator, - generator_return, generator_state, generators, generic_arg_infer, diff --git a/library/core/src/ops/generator.rs b/library/core/src/ops/generator.rs index b651b7b233ed..3ebd6f8cdbdc 100644 --- a/library/core/src/ops/generator.rs +++ b/library/core/src/ops/generator.rs @@ -83,7 +83,7 @@ pub trait Generator { /// `return` statement or implicitly as the last expression of a generator /// literal. For example futures would use this as `Result` as it /// represents a completed future. - #[lang = "generator_return"] + #[cfg_attr(bootstrap, lang = "generator_return")] type Return; /// Resumes the execution of this generator. From 97668a558955ded299db6ef145933be7677e7fbc Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 8 Sep 2022 02:42:00 +0000 Subject: [PATCH 4313/5092] We can print futures with {integer} too --- compiler/rustc_middle/src/ty/print/pretty.rs | 2 +- .../ui/suggestions/expected-boxed-future-isnt-pinned.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index b46813e08f10..979a72d400fe 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -923,7 +923,7 @@ pub trait PrettyPrinter<'tcx>: { if let ty::Generator(_, substs, _) = substs.type_at(0).kind() { let return_ty = substs.as_generator().return_ty(); - if !return_ty.is_ty_infer() { + if !return_ty.is_ty_var() { return_ty.into() } else { continue; diff --git a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr index e43a4e79bfe8..77cef485f30e 100644 --- a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr +++ b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr @@ -91,7 +91,7 @@ LL | pub const fn from_generator(gen: T) -> impl Future | ------------------------------- the found opaque type | = note: expected struct `Pin + Send + 'static)>>` - found opaque type `impl Future` + found opaque type `impl Future` help: you need to pin and box this expression | LL ~ Box::pin(async { From 4314615ff87d6b07290efddd1d1132a50bff9b0d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 1 Sep 2022 12:06:48 +1000 Subject: [PATCH 4314/5092] Arena-allocate `hir::Lifetime`. This shrinks `hir::Ty` from 72 to 48 bytes. `visit_lifetime` is added to the HIR stats collector because these types are now stored in memory on their own, instead of being within other types. --- compiler/rustc_ast_lowering/src/lib.rs | 21 +++--- compiler/rustc_hir/src/hir.rs | 18 ++--- compiler/rustc_passes/src/hir_stats.rs | 5 ++ src/librustdoc/clean/mod.rs | 6 +- src/test/ui/stats/hir-stats.stderr | 69 ++++++++++--------- .../clippy/clippy_utils/src/hir_utils.rs | 2 +- 6 files changed, 65 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index e7bbf7dbdec2..e484f77cad44 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1196,7 +1196,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let lifetime_bound = this.elided_dyn_bound(t.span); (bounds, lifetime_bound) }); - let kind = hir::TyKind::TraitObject(bounds, lifetime_bound, TraitObjectSyntax::None); + let kind = hir::TyKind::TraitObject(bounds, &lifetime_bound, TraitObjectSyntax::None); return hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.next_id() }; } @@ -1934,8 +1934,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let res = res.unwrap_or( self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error), ); - let l = self.new_named_lifetime_with_res(id, span, ident, res); - hir::GenericArg::Lifetime(l) + hir::GenericArg::Lifetime(self.new_named_lifetime_with_res(id, span, ident, res)) }, )); @@ -2004,7 +2003,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime { + fn lower_lifetime(&mut self, l: &Lifetime) -> &'hir hir::Lifetime { let span = self.lower_span(l.ident.span); let ident = self.lower_ident(l.ident); self.new_named_lifetime(l.id, l.id, span, ident) @@ -2017,7 +2016,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: Span, ident: Ident, res: LifetimeRes, - ) -> hir::Lifetime { + ) -> &'hir hir::Lifetime { let name = match res { LifetimeRes::Param { param, .. } => { let p_name = ParamName::Plain(ident); @@ -2038,7 +2037,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; debug!(?name); - hir::Lifetime { hir_id: self.lower_node_id(id), span: self.lower_span(span), name } + self.arena.alloc(hir::Lifetime { + hir_id: self.lower_node_id(id), + span: self.lower_span(span), + name, + }) } #[instrument(level = "debug", skip(self))] @@ -2048,7 +2051,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { new_id: NodeId, span: Span, ident: Ident, - ) -> hir::Lifetime { + ) -> &'hir hir::Lifetime { let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error); self.new_named_lifetime_with_res(new_id, span, ident, res) } @@ -2462,14 +2465,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { /// bound, like the bound in `Box`. This method is not invoked /// when the bound is written, even if it is written with `'_` like in /// `Box`. In those cases, `lower_lifetime` is invoked. - fn elided_dyn_bound(&mut self, span: Span) -> hir::Lifetime { + fn elided_dyn_bound(&mut self, span: Span) -> &'hir hir::Lifetime { let r = hir::Lifetime { hir_id: self.next_id(), span: self.lower_span(span), name: hir::LifetimeName::ImplicitObjectLifetimeDefault, }; debug!("elided_dyn_bound: r={:?}", r); - r + self.arena.alloc(r) } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index a668c0e95ce4..8eb0f6dd812d 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -259,7 +259,7 @@ impl InferArg { #[derive(Debug, HashStable_Generic)] pub enum GenericArg<'hir> { - Lifetime(Lifetime), + Lifetime(&'hir Lifetime), Type(&'hir Ty<'hir>), Const(ConstArg), Infer(InferArg), @@ -430,7 +430,7 @@ pub enum GenericBound<'hir> { Trait(PolyTraitRef<'hir>, TraitBoundModifier), // FIXME(davidtwco): Introduce `PolyTraitRef::LangItem` LangItemTrait(LangItem, Span, HirId, &'hir GenericArgs<'hir>), - Outlives(Lifetime), + Outlives(&'hir Lifetime), } impl GenericBound<'_> { @@ -756,7 +756,7 @@ impl<'hir> WhereBoundPredicate<'hir> { pub struct WhereRegionPredicate<'hir> { pub span: Span, pub in_where_clause: bool, - pub lifetime: Lifetime, + pub lifetime: &'hir Lifetime, pub bounds: GenericBounds<'hir>, } @@ -2499,7 +2499,7 @@ pub enum TyKind<'hir> { /// A raw pointer (i.e., `*const T` or `*mut T`). Ptr(MutTy<'hir>), /// A reference (i.e., `&'a T` or `&'a mut T`). - Rptr(Lifetime, MutTy<'hir>), + Rptr(&'hir Lifetime, MutTy<'hir>), /// A bare function (e.g., `fn(usize) -> bool`). BareFn(&'hir BareFnTy<'hir>), /// The never type (`!`). @@ -2518,7 +2518,7 @@ pub enum TyKind<'hir> { OpaqueDef(ItemId, &'hir [GenericArg<'hir>]), /// A trait object type `Bound1 + Bound2 + Bound3` /// where `Bound` is a trait or a lifetime. - TraitObject(&'hir [PolyTraitRef<'hir>], Lifetime, TraitObjectSyntax), + TraitObject(&'hir [PolyTraitRef<'hir>], &'hir Lifetime, TraitObjectSyntax), /// Unused for now. Typeof(AnonConst), /// `TyKind::Infer` means the type should be inferred instead of it having been @@ -3474,7 +3474,7 @@ mod size_asserts { static_assert_size!(ForeignItem<'_>, 72); static_assert_size!(ForeignItemKind<'_>, 40); #[cfg(not(bootstrap))] - static_assert_size!(GenericArg<'_>, 32); + static_assert_size!(GenericArg<'_>, 24); static_assert_size!(GenericBound<'_>, 48); static_assert_size!(Generics<'_>, 56); static_assert_size!(Impl<'_>, 80); @@ -3494,9 +3494,9 @@ mod size_asserts { static_assert_size!(Stmt<'_>, 32); static_assert_size!(StmtKind<'_>, 16); #[cfg(not(bootstrap))] - static_assert_size!(TraitItem<'static>, 88); + static_assert_size!(TraitItem<'_>, 88); #[cfg(not(bootstrap))] static_assert_size!(TraitItemKind<'_>, 48); - static_assert_size!(Ty<'_>, 72); - static_assert_size!(TyKind<'_>, 56); + static_assert_size!(Ty<'_>, 48); + static_assert_size!(TyKind<'_>, 32); } diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 81ac0e1b6d44..075069feb52d 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -437,6 +437,11 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { } } + fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) { + self.record("Lifetime", Id::Node(lifetime.hir_id), lifetime); + hir_visit::walk_lifetime(self, lifetime) + } + fn visit_path(&mut self, path: &'v hir::Path<'v>, _id: hir::HirId) { self.record("Path", Id::None, path); hir_visit::walk_path(self, path) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 980a1485b59b..2829ab45d474 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -190,7 +190,7 @@ fn clean_poly_trait_ref_with_bindings<'tcx>( ) } -fn clean_lifetime<'tcx>(lifetime: hir::Lifetime, cx: &mut DocContext<'tcx>) -> Lifetime { +fn clean_lifetime<'tcx>(lifetime: &hir::Lifetime, cx: &mut DocContext<'tcx>) -> Lifetime { let def = cx.tcx.named_region(lifetime.hir_id); if let Some( rl::Region::EarlyBound(node_id) @@ -495,7 +495,7 @@ fn clean_generic_param<'tcx>( .filter(|bp| !bp.in_where_clause) .flat_map(|bp| bp.bounds) .map(|bound| match bound { - hir::GenericBound::Outlives(lt) => clean_lifetime(*lt, cx), + hir::GenericBound::Outlives(lt) => clean_lifetime(lt, cx), _ => panic!(), }) .collect() @@ -1392,7 +1392,7 @@ fn maybe_expand_private_type_alias<'tcx>( } _ => None, }); - if let Some(lt) = lifetime.cloned() { + if let Some(lt) = lifetime { let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id); let cleaned = if !lt.is_elided() { clean_lifetime(lt, cx) } else { Lifetime::elided() }; diff --git a/src/test/ui/stats/hir-stats.stderr b/src/test/ui/stats/hir-stats.stderr index c8ceb6ff22df..24c281a0c995 100644 --- a/src/test/ui/stats/hir-stats.stderr +++ b/src/test/ui/stats/hir-stats.stderr @@ -119,59 +119,60 @@ hir-stats HIR STATS hir-stats Name Accumulated Size Count Item Size hir-stats ---------------------------------------------------------------- hir-stats ForeignItemRef 24 ( 0.2%) 1 24 +hir-stats Lifetime 32 ( 0.3%) 1 32 hir-stats Mod 32 ( 0.3%) 1 32 hir-stats ExprField 40 ( 0.4%) 1 40 hir-stats TraitItemRef 56 ( 0.6%) 2 28 -hir-stats Param 64 ( 0.6%) 2 32 -hir-stats Local 64 ( 0.6%) 1 64 +hir-stats Local 64 ( 0.7%) 1 64 +hir-stats Param 64 ( 0.7%) 2 32 hir-stats InlineAsm 72 ( 0.7%) 1 72 hir-stats ImplItemRef 72 ( 0.7%) 2 36 -hir-stats FieldDef 96 ( 0.9%) 2 48 -hir-stats Arm 96 ( 0.9%) 2 48 -hir-stats Body 96 ( 0.9%) 3 32 -hir-stats Stmt 96 ( 0.9%) 3 32 +hir-stats Body 96 ( 1.0%) 3 32 +hir-stats GenericArg 96 ( 1.0%) 4 24 +hir-stats - Type 24 ( 0.2%) 1 +hir-stats - Lifetime 72 ( 0.7%) 3 +hir-stats FieldDef 96 ( 1.0%) 2 48 +hir-stats Arm 96 ( 1.0%) 2 48 +hir-stats Stmt 96 ( 1.0%) 3 32 hir-stats - Local 32 ( 0.3%) 1 hir-stats - Semi 32 ( 0.3%) 1 hir-stats - Expr 32 ( 0.3%) 1 hir-stats FnDecl 120 ( 1.2%) 3 40 hir-stats Attribute 128 ( 1.3%) 4 32 -hir-stats GenericArg 128 ( 1.3%) 4 32 -hir-stats - Type 32 ( 0.3%) 1 -hir-stats - Lifetime 96 ( 0.9%) 3 -hir-stats GenericArgs 144 ( 1.4%) 3 48 +hir-stats GenericArgs 144 ( 1.5%) 3 48 hir-stats Variant 160 ( 1.6%) 2 80 -hir-stats GenericBound 192 ( 1.9%) 4 48 -hir-stats - Trait 192 ( 1.9%) 4 -hir-stats WherePredicate 216 ( 2.1%) 3 72 -hir-stats - BoundPredicate 216 ( 2.1%) 3 -hir-stats Block 288 ( 2.8%) 6 48 -hir-stats GenericParam 400 ( 3.9%) 5 80 -hir-stats Pat 440 ( 4.3%) 5 88 +hir-stats WherePredicate 168 ( 1.7%) 3 56 +hir-stats - BoundPredicate 168 ( 1.7%) 3 +hir-stats GenericBound 192 ( 2.0%) 4 48 +hir-stats - Trait 192 ( 2.0%) 4 +hir-stats Block 288 ( 3.0%) 6 48 +hir-stats GenericParam 400 ( 4.1%) 5 80 +hir-stats Pat 440 ( 4.5%) 5 88 hir-stats - Wild 88 ( 0.9%) 1 hir-stats - Struct 88 ( 0.9%) 1 -hir-stats - Binding 264 ( 2.6%) 3 -hir-stats Generics 560 ( 5.5%) 10 56 -hir-stats Expr 768 ( 7.6%) 12 64 -hir-stats - Path 64 ( 0.6%) 1 -hir-stats - Struct 64 ( 0.6%) 1 -hir-stats - Match 64 ( 0.6%) 1 -hir-stats - InlineAsm 64 ( 0.6%) 1 +hir-stats - Binding 264 ( 2.7%) 3 +hir-stats Generics 560 ( 5.7%) 10 56 +hir-stats Ty 720 ( 7.4%) 15 48 +hir-stats - Ptr 48 ( 0.5%) 1 +hir-stats - Rptr 48 ( 0.5%) 1 +hir-stats - Path 624 ( 6.4%) 13 +hir-stats Expr 768 ( 7.9%) 12 64 +hir-stats - Path 64 ( 0.7%) 1 +hir-stats - Struct 64 ( 0.7%) 1 +hir-stats - Match 64 ( 0.7%) 1 +hir-stats - InlineAsm 64 ( 0.7%) 1 hir-stats - Lit 128 ( 1.3%) 2 -hir-stats - Block 384 ( 3.8%) 6 -hir-stats Item 960 ( 9.4%) 12 80 +hir-stats - Block 384 ( 3.9%) 6 +hir-stats Item 960 ( 9.8%) 12 80 hir-stats - Trait 80 ( 0.8%) 1 hir-stats - Enum 80 ( 0.8%) 1 hir-stats - ExternCrate 80 ( 0.8%) 1 hir-stats - ForeignMod 80 ( 0.8%) 1 hir-stats - Impl 80 ( 0.8%) 1 hir-stats - Fn 160 ( 1.6%) 2 -hir-stats - Use 400 ( 3.9%) 5 -hir-stats Ty 1_080 (10.6%) 15 72 -hir-stats - Ptr 72 ( 0.7%) 1 -hir-stats - Rptr 72 ( 0.7%) 1 -hir-stats - Path 936 ( 9.2%) 13 -hir-stats Path 1_536 (15.1%) 32 48 -hir-stats PathSegment 2_240 (22.0%) 40 56 +hir-stats - Use 400 ( 4.1%) 5 +hir-stats Path 1_536 (15.7%) 32 48 +hir-stats PathSegment 2_240 (23.0%) 40 56 hir-stats ---------------------------------------------------------------- -hir-stats Total 10_168 +hir-stats Total 9_760 hir-stats diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 57448f716d49..ff23ed5fffa3 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -929,7 +929,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } } - pub fn hash_lifetime(&mut self, lifetime: Lifetime) { + pub fn hash_lifetime(&mut self, lifetime: &Lifetime) { std::mem::discriminant(&lifetime.name).hash(&mut self.s); if let LifetimeName::Param(param_id, ref name) = lifetime.name { std::mem::discriminant(name).hash(&mut self.s); From e67f39f8bcb12dc4c985abe922d78c0daad7e5cd Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 1 Sep 2022 13:29:57 +1000 Subject: [PATCH 4315/5092] Introduce `DotDotPos`. This shrinks `hir::Pat` from 88 to 72 bytes. --- compiler/rustc_ast_lowering/src/expr.rs | 11 ++++-- compiler/rustc_ast_lowering/src/pat.rs | 4 +- compiler/rustc_hir/src/hir.rs | 39 ++++++++++++++++--- compiler/rustc_hir/src/pat_util.rs | 6 +-- compiler/rustc_hir_pretty/src/lib.rs | 5 ++- .../rustc_mir_build/src/thir/pattern/mod.rs | 2 +- compiler/rustc_passes/src/dead.rs | 11 ++---- compiler/rustc_typeck/src/check/pat.rs | 8 ++-- src/test/ui/stats/hir-stats.stderr | 24 ++++++------ .../clippy_lints/src/equatable_if_let.rs | 4 +- .../src/matches/match_same_arms.rs | 4 +- .../clippy_lints/src/matches/single_match.rs | 2 + .../clippy/clippy_lints/src/question_mark.rs | 3 +- .../src/unit_types/let_unit_value.rs | 6 ++- src/tools/clippy/clippy_utils/src/lib.rs | 3 +- 15 files changed, 85 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 6fa8d7f0fcdd..f9f273acb7e6 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1128,8 +1128,11 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut ImplTraitContext::Disallowed(ImplTraitPosition::Path), ); // Destructure like a tuple struct. - let tuple_struct_pat = - hir::PatKind::TupleStruct(qpath, pats, rest.map(|r| r.0)); + let tuple_struct_pat = hir::PatKind::TupleStruct( + qpath, + pats, + hir::DotDotPos::new(rest.map(|r| r.0)), + ); return self.pat_without_dbm(lhs.span, tuple_struct_pat); } } @@ -1184,13 +1187,13 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::Tup(elements) => { let (pats, rest) = self.destructure_sequence(elements, "tuple", eq_sign_span, assignments); - let tuple_pat = hir::PatKind::Tuple(pats, rest.map(|r| r.0)); + let tuple_pat = hir::PatKind::Tuple(pats, hir::DotDotPos::new(rest.map(|r| r.0))); return self.pat_without_dbm(lhs.span, tuple_pat); } ExprKind::Paren(e) => { // We special-case `(..)` for consistency with patterns. if let ExprKind::Range(None, None, RangeLimits::HalfOpen) = e.kind { - let tuple_pat = hir::PatKind::Tuple(&[], Some(0)); + let tuple_pat = hir::PatKind::Tuple(&[], hir::DotDotPos::new(Some(0))); return self.pat_without_dbm(lhs.span, tuple_pat); } else { return self.destructure_assign_mut(e, eq_sign_span, assignments); diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 69e6c2c8ad0b..1ea76fdbfcbb 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -116,7 +116,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, pats: &[P], ctx: &str, - ) -> (&'hir [hir::Pat<'hir>], Option) { + ) -> (&'hir [hir::Pat<'hir>], hir::DotDotPos) { let mut elems = Vec::with_capacity(pats.len()); let mut rest = None; @@ -160,7 +160,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - (self.arena.alloc_from_iter(elems), rest.map(|(ddpos, _)| ddpos)) + (self.arena.alloc_from_iter(elems), hir::DotDotPos::new(rest.map(|(ddpos, _)| ddpos))) } /// Lower a slice pattern of form `[pat_0, ..., pat_n]` into diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 8eb0f6dd812d..cc5aed6cb548 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1059,6 +1059,35 @@ impl fmt::Display for RangeEnd { } } +// Equivalent to `Option`. That type takes up 16 bytes on 64-bit, but +// this type only takes up 4 bytes, at the cost of being restricted to a +// maximum value of `u32::MAX - 1`. In practice, this is more than enough. +#[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable_Generic)] +pub struct DotDotPos(u32); + +impl DotDotPos { + // Panics if n >= u32::MAX. + pub fn new(n: Option) -> Self { + match n { + Some(n) => { + assert!(n < u32::MAX as usize); + Self(n as u32) + } + None => Self(u32::MAX), + } + } + + pub fn as_opt_usize(&self) -> Option { + if self.0 == u32::MAX { None } else { Some(self.0 as usize) } + } +} + +impl fmt::Debug for DotDotPos { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.as_opt_usize().fmt(f) + } +} + #[derive(Debug, HashStable_Generic)] pub enum PatKind<'hir> { /// Represents a wildcard pattern (i.e., `_`). @@ -1075,9 +1104,9 @@ pub enum PatKind<'hir> { Struct(QPath<'hir>, &'hir [PatField<'hir>], bool), /// A tuple struct/variant pattern `Variant(x, y, .., z)`. - /// If the `..` pattern fragment is present, then `Option` denotes its position. + /// If the `..` pattern fragment is present, then `DotDotPos` denotes its position. /// `0 <= position <= subpats.len()` - TupleStruct(QPath<'hir>, &'hir [Pat<'hir>], Option), + TupleStruct(QPath<'hir>, &'hir [Pat<'hir>], DotDotPos), /// An or-pattern `A | B | C`. /// Invariant: `pats.len() >= 2`. @@ -1089,7 +1118,7 @@ pub enum PatKind<'hir> { /// A tuple pattern (e.g., `(a, b)`). /// If the `..` pattern fragment is present, then `Option` denotes its position. /// `0 <= position <= subpats.len()` - Tuple(&'hir [Pat<'hir>], Option), + Tuple(&'hir [Pat<'hir>], DotDotPos), /// A `box` pattern. Box(&'hir Pat<'hir>), @@ -3486,8 +3515,8 @@ mod size_asserts { static_assert_size!(ItemKind<'_>, 48); static_assert_size!(Local<'_>, 64); static_assert_size!(Param<'_>, 32); - static_assert_size!(Pat<'_>, 88); - static_assert_size!(PatKind<'_>, 64); + static_assert_size!(Pat<'_>, 72); + static_assert_size!(PatKind<'_>, 48); static_assert_size!(Path<'_>, 48); static_assert_size!(PathSegment<'_>, 56); static_assert_size!(QPath<'_>, 24); diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs index 9baaf9390f2c..0c1819bb0c74 100644 --- a/compiler/rustc_hir/src/pat_util.rs +++ b/compiler/rustc_hir/src/pat_util.rs @@ -35,7 +35,7 @@ pub trait EnumerateAndAdjustIterator { fn enumerate_and_adjust( self, expected_len: usize, - gap_pos: Option, + gap_pos: hir::DotDotPos, ) -> EnumerateAndAdjust where Self: Sized; @@ -45,7 +45,7 @@ impl EnumerateAndAdjustIterator for T { fn enumerate_and_adjust( self, expected_len: usize, - gap_pos: Option, + gap_pos: hir::DotDotPos, ) -> EnumerateAndAdjust where Self: Sized, @@ -53,7 +53,7 @@ impl EnumerateAndAdjustIterator for T { let actual_len = self.len(); EnumerateAndAdjust { enumerate: self.enumerate(), - gap_pos: gap_pos.unwrap_or(expected_len), + gap_pos: gap_pos.as_opt_usize().unwrap_or(expected_len), gap_len: expected_len - actual_len, } } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 1220755f44b3..35a58296e370 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1761,7 +1761,8 @@ impl<'a> State<'a> { PatKind::TupleStruct(ref qpath, elts, ddpos) => { self.print_qpath(qpath, true); self.popen(); - if let Some(ddpos) = ddpos { + if let Some(ddpos) = ddpos.as_opt_usize() { + let ddpos = ddpos as usize; self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p)); if ddpos != 0 { self.word_space(","); @@ -1804,7 +1805,7 @@ impl<'a> State<'a> { } PatKind::Tuple(elts, ddpos) => { self.popen(); - if let Some(ddpos) = ddpos { + if let Some(ddpos) = ddpos.as_opt_usize() { self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p)); if ddpos != 0 { self.word_space(","); diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index d2f93b679acc..9803cecd4459 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -333,7 +333,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { &mut self, pats: &'tcx [hir::Pat<'tcx>], expected_len: usize, - gap_pos: Option, + gap_pos: hir::DotDotPos, ) -> Vec> { pats.iter() .enumerate_and_adjust(expected_len, gap_pos) diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 625c854ea77a..a7ce0f312af8 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -226,19 +226,16 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { lhs: &hir::Pat<'_>, res: Res, pats: &[hir::Pat<'_>], - dotdot: Option, + dotdot: hir::DotDotPos, ) { let variant = match self.typeck_results().node_type(lhs.hir_id).kind() { ty::Adt(adt, _) => adt.variant_of_res(res), _ => span_bug!(lhs.span, "non-ADT in tuple struct pattern"), }; - let first_n = pats.iter().enumerate().take(dotdot.unwrap_or(pats.len())); + let dotdot = dotdot.as_opt_usize().unwrap_or(pats.len()); + let first_n = pats.iter().enumerate().take(dotdot); let missing = variant.fields.len() - pats.len(); - let last_n = pats - .iter() - .enumerate() - .skip(dotdot.unwrap_or(pats.len())) - .map(|(idx, pat)| (idx + missing, pat)); + let last_n = pats.iter().enumerate().skip(dotdot).map(|(idx, pat)| (idx + missing, pat)); for (idx, pat) in first_n.chain(last_n) { if let PatKind::Wild = pat.kind { continue; diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 9096fc442d49..52948cbb4289 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -981,7 +981,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat: &'tcx Pat<'tcx>, qpath: &'tcx hir::QPath<'tcx>, subpats: &'tcx [Pat<'tcx>], - ddpos: Option, + ddpos: hir::DotDotPos, expected: Ty<'tcx>, def_bm: BindingMode, ti: TopInfo<'tcx>, @@ -1066,7 +1066,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Type-check subpatterns. if subpats.len() == variant.fields.len() - || subpats.len() < variant.fields.len() && ddpos.is_some() + || subpats.len() < variant.fields.len() && ddpos.as_opt_usize().is_some() { let ty::Adt(_, substs) = pat_ty.kind() else { bug!("unexpected pattern type {:?}", pat_ty); @@ -1254,14 +1254,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, span: Span, elements: &'tcx [Pat<'tcx>], - ddpos: Option, + ddpos: hir::DotDotPos, expected: Ty<'tcx>, def_bm: BindingMode, ti: TopInfo<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; let mut expected_len = elements.len(); - if ddpos.is_some() { + if ddpos.as_opt_usize().is_some() { // Require known type only when `..` is present. if let ty::Tuple(tys) = self.structurally_resolved_type(span, expected).kind() { expected_len = tys.len(); diff --git a/src/test/ui/stats/hir-stats.stderr b/src/test/ui/stats/hir-stats.stderr index 24c281a0c995..8d9776065308 100644 --- a/src/test/ui/stats/hir-stats.stderr +++ b/src/test/ui/stats/hir-stats.stderr @@ -140,18 +140,18 @@ hir-stats - Expr 32 ( 0.3%) 1 hir-stats FnDecl 120 ( 1.2%) 3 40 hir-stats Attribute 128 ( 1.3%) 4 32 hir-stats GenericArgs 144 ( 1.5%) 3 48 -hir-stats Variant 160 ( 1.6%) 2 80 +hir-stats Variant 160 ( 1.7%) 2 80 hir-stats WherePredicate 168 ( 1.7%) 3 56 hir-stats - BoundPredicate 168 ( 1.7%) 3 hir-stats GenericBound 192 ( 2.0%) 4 48 hir-stats - Trait 192 ( 2.0%) 4 hir-stats Block 288 ( 3.0%) 6 48 +hir-stats Pat 360 ( 3.7%) 5 72 +hir-stats - Wild 72 ( 0.7%) 1 +hir-stats - Struct 72 ( 0.7%) 1 +hir-stats - Binding 216 ( 2.2%) 3 hir-stats GenericParam 400 ( 4.1%) 5 80 -hir-stats Pat 440 ( 4.5%) 5 88 -hir-stats - Wild 88 ( 0.9%) 1 -hir-stats - Struct 88 ( 0.9%) 1 -hir-stats - Binding 264 ( 2.7%) 3 -hir-stats Generics 560 ( 5.7%) 10 56 +hir-stats Generics 560 ( 5.8%) 10 56 hir-stats Ty 720 ( 7.4%) 15 48 hir-stats - Ptr 48 ( 0.5%) 1 hir-stats - Rptr 48 ( 0.5%) 1 @@ -162,17 +162,17 @@ hir-stats - Struct 64 ( 0.7%) 1 hir-stats - Match 64 ( 0.7%) 1 hir-stats - InlineAsm 64 ( 0.7%) 1 hir-stats - Lit 128 ( 1.3%) 2 -hir-stats - Block 384 ( 3.9%) 6 -hir-stats Item 960 ( 9.8%) 12 80 +hir-stats - Block 384 ( 4.0%) 6 +hir-stats Item 960 ( 9.9%) 12 80 hir-stats - Trait 80 ( 0.8%) 1 hir-stats - Enum 80 ( 0.8%) 1 hir-stats - ExternCrate 80 ( 0.8%) 1 hir-stats - ForeignMod 80 ( 0.8%) 1 hir-stats - Impl 80 ( 0.8%) 1 -hir-stats - Fn 160 ( 1.6%) 2 +hir-stats - Fn 160 ( 1.7%) 2 hir-stats - Use 400 ( 4.1%) 5 -hir-stats Path 1_536 (15.7%) 32 48 -hir-stats PathSegment 2_240 (23.0%) 40 56 +hir-stats Path 1_536 (15.9%) 32 48 +hir-stats PathSegment 2_240 (23.1%) 40 56 hir-stats ---------------------------------------------------------------- -hir-stats Total 9_760 +hir-stats Total 9_680 hir-stats diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs index fdfb821ac789..bce49165e5b1 100644 --- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs +++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs @@ -51,7 +51,9 @@ fn unary_pattern(pat: &Pat<'_>) -> bool { false }, PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)), - PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => !etc.is_some() && array_rec(a), + PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => { + !etc.as_opt_usize().is_some() && array_rec(a) + } PatKind::Ref(x, _) | PatKind::Box(x) => unary_pattern(x), PatKind::Path(_) | PatKind::Lit(_) => true, } diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs index e32ef9933afe..93874b103b46 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs @@ -248,7 +248,7 @@ impl<'a> NormalizedPat<'a> { } else { (None, adt.non_enum_variant()) }; - let (front, back) = match wild_idx { + let (front, back) = match wild_idx.as_opt_usize() { Some(i) => pats.split_at(i), None => (pats, [].as_slice()), }; @@ -268,7 +268,7 @@ impl<'a> NormalizedPat<'a> { ty::Tuple(subs) => subs.len(), _ => return Self::Wild, }; - let (front, back) = match wild_idx { + let (front, back) = match wild_idx.as_opt_usize() { Some(i) => pats.split_at(i), None => (pats, [].as_slice()), }; diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs index 95478af45b4b..1bf1c4d10789 100644 --- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs @@ -200,6 +200,8 @@ fn form_exhaustive_matches<'a>(cx: &LateContext<'a>, ty: Ty<'a>, left: &Pat<'_>, // We don't actually know the position and the presence of the `..` (dotdot) operator // in the arms, so we need to evaluate the correct offsets here in order to iterate in // both arms at the same time. + let left_pos = left_pos.as_opt_usize(); + let right_pos = right_pos.as_opt_usize(); let len = max( left_in.len() + { if left_pos.is_some() { 1 } else { 0 } diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index f4f1fd336df7..569870ab2b7f 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -122,7 +122,8 @@ fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: if_chain! { if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else }) = higher::IfLet::hir(cx, expr); if !is_else_clause(cx.tcx, expr); - if let PatKind::TupleStruct(ref path1, [field], None) = let_pat.kind; + if let PatKind::TupleStruct(ref path1, [field], ddpos) = let_pat.kind; + if ddpos.as_opt_usize().is_none(); if let PatKind::Binding(BindingAnnotation(by_ref, _), bind_id, ident, None) = field.kind; let caller_ty = cx.typeck_results().expr_ty(let_expr); let if_block = IfBlockType::IfLet(path1, caller_ty, ident.name, let_expr, if_then, if_else); diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs index 35824b03170a..ce9ebad8c89a 100644 --- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs +++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs @@ -19,10 +19,12 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) { && cx.typeck_results().pat_ty(local.pat).is_unit() { if (local.ty.map_or(false, |ty| !matches!(ty.kind, TyKind::Infer)) - || matches!(local.pat.kind, PatKind::Tuple([], None))) + || matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none())) && expr_needs_inferred_result(cx, init) { - if !matches!(local.pat.kind, PatKind::Wild | PatKind::Tuple([], None)) { + if !matches!(local.pat.kind, PatKind::Wild) + && !matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none()) + { span_lint_and_then( cx, LET_UNIT_VALUE, diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index b27439cbec27..3cf043f22df5 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1552,7 +1552,8 @@ pub fn iter_input_pats<'tcx>(decl: &FnDecl<'_>, body: &'tcx Body<'_>) -> impl It pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { fn is_ok(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { if_chain! { - if let PatKind::TupleStruct(ref path, pat, None) = arm.pat.kind; + if let PatKind::TupleStruct(ref path, pat, ddpos) = arm.pat.kind; + if ddpos.as_opt_usize().is_none(); if is_lang_ctor(cx, path, ResultOk); if let PatKind::Binding(_, hir_id, _, None) = pat[0].kind; if path_to_local_id(arm.body, hir_id); From 60b49581c4bbbb94967f5ac170bf6152e4eba5cf Mon Sep 17 00:00:00 2001 From: Luis Cardoso <61982523+LuisCardosoOliveira@users.noreply.github.com> Date: Fri, 26 Aug 2022 16:06:27 +0200 Subject: [PATCH 4316/5092] translations(rustc_session): migrates session.rs and config.rs --- .../locales/en-US/session.ftl | 26 ++++ compiler/rustc_session/src/config.rs | 3 +- compiler/rustc_session/src/errors.rs | 69 ++++++++++- compiler/rustc_session/src/session.rs | 114 ++++++++++++------ 4 files changed, 174 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/session.ftl b/compiler/rustc_error_messages/locales/en-US/session.ftl index 983e5cee8237..998196403e74 100644 --- a/compiler/rustc_error_messages/locales/en-US/session.ftl +++ b/compiler/rustc_error_messages/locales/en-US/session.ftl @@ -14,3 +14,29 @@ session_feature_diagnostic_for_issue = session_feature_diagnostic_help = add `#![feature({$feature})]` to the crate attributes to enable + +session_target_data_layout_parse_error = {$err} + +session_not_circumvent_feature = `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine + +session_profile_use_file_does_not_exist = File `{$path}` passed to `-C profile-use` does not exist. + +session_linker_plugin_lto_windows_not_supported = Linker plugin based LTO is not supported together with `-C prefer-dynamic` when targeting Windows-like targets" + +session_profile_sample_use_file_does_not_exist = File `{$path}` passed to `-C profile-sample-use` does not exist. + +session_target_requires_unwind_tables = target requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no`." + +session_sanitizer_not_supported = {$us} sanitizer is not supported for this target + +session_sanitizers_not_supported = {$us} sanitizers are not supported for this target + +session_cannot_mix_and_match_sanitizers = `-Zsanitizer={$first}` is incompatible with `-Zsanitizer={$second}` + +session_cannot_enable_crt_static_linux = sanitizer is incompatible with statically linked libc, disable it using `-C target-feature=-crt-static` + +session_sanitizer_cfi_enabled = `-Zsanitizer=cfi` requires `-Clto` + +session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination` requires `-Clto` + +session_unsupported_dwarf_version = requested DWARF version {$dwarf_version} is greater than 5 diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 04bd685f1900..0018346c72c4 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1,6 +1,7 @@ //! Contains infrastructure for configuring the compiler, including parsing //! command-line options. +use crate::errors::TargetDataLayoutParseError; pub use crate::options::*; use crate::search_paths::SearchPath; @@ -898,7 +899,7 @@ fn default_configuration(sess: &Session) -> CrateConfig { let max_atomic_width = sess.target.max_atomic_width(); let atomic_cas = sess.target.atomic_cas; let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| { - sess.fatal(&err); + sess.emit_fatal(TargetDataLayoutParseError { err }); }); let mut ret = CrateConfig::default(); diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 7252f1799dac..7aa8d6682410 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -1,7 +1,7 @@ use std::num::NonZeroU32; -use crate as rustc_session; use crate::cgu_reuse_tracker::CguReuse; +use crate::{self as rustc_session}; use rustc_errors::MultiSpan; use rustc_macros::SessionDiagnostic; use rustc_span::{Span, Symbol}; @@ -43,3 +43,70 @@ pub struct FeatureDiagnosticForIssue { pub struct FeatureDiagnosticHelp { pub feature: Symbol, } + +#[derive(SessionDiagnostic)] +#[diag(session::target_data_layout_parse_error)] +pub struct TargetDataLayoutParseError { + pub err: String, +} + +#[derive(SessionDiagnostic)] +#[diag(session::not_circumvent_feature)] +pub struct NotCircumventFeature; + +#[derive(SessionDiagnostic)] +#[diag(session::linker_plugin_lto_windows_not_supported)] +pub struct LinkerPluginToWindowsNotSupported; + +#[derive(SessionDiagnostic)] +#[diag(session::profile_use_file_does_not_exist)] +pub struct ProfileUseFileDoesNotExist<'a> { + pub path: &'a std::path::Path, +} + +#[derive(SessionDiagnostic)] +#[diag(session::profile_sample_use_file_does_not_exist)] +pub struct ProfileSampleUseFileDoesNotExist<'a> { + pub path: &'a std::path::Path, +} + +#[derive(SessionDiagnostic)] +#[diag(session::target_requires_unwind_tables)] +pub struct TargetRequiresUnwindTables; + +#[derive(SessionDiagnostic)] +#[diag(session::sanitizer_not_supported)] +pub struct SanitizerNotSupported { + pub us: String, +} + +#[derive(SessionDiagnostic)] +#[diag(session::sanitizers_not_supported)] +pub struct SanitizersNotSupported { + pub us: String, +} + +#[derive(SessionDiagnostic)] +#[diag(session::cannot_mix_and_match_sanitizers)] +pub struct CannotMixAndMatchSanitizers { + pub first: String, + pub second: String, +} + +#[derive(SessionDiagnostic)] +#[diag(session::cannot_enable_crt_static_linux)] +pub struct CannotEnableCrtStaticLinux; + +#[derive(SessionDiagnostic)] +#[diag(session::sanitizer_cfi_enabled)] +pub struct SanitizerCfiEnabled; + +#[derive(SessionDiagnostic)] +#[diag(session::unstable_virtual_function_elimination)] +pub struct UnstableVirtualFunctionElimination; + +#[derive(SessionDiagnostic)] +#[diag(session::unsupported_dwarf_version)] +pub struct UnsupportedDwarfVersion { + pub dwarf_version: u32, +} diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 557edad548c6..4fe0e1de5b33 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -2,6 +2,12 @@ use crate::cgu_reuse_tracker::CguReuseTracker; use crate::code_stats::CodeStats; pub use crate::code_stats::{DataTypeKind, FieldInfo, SizeKind, VariantInfo}; use crate::config::{self, CrateType, InstrumentCoverage, OptLevel, OutputType, SwitchWithOptPath}; +use crate::errors::{ + CannotEnableCrtStaticLinux, CannotMixAndMatchSanitizers, LinkerPluginToWindowsNotSupported, + NotCircumventFeature, ProfileSampleUseFileDoesNotExist, ProfileUseFileDoesNotExist, + SanitizerCfiEnabled, SanitizerNotSupported, SanitizersNotSupported, TargetRequiresUnwindTables, + UnstableVirtualFunctionElimination, UnsupportedDwarfVersion, +}; use crate::parse::{add_feature_diagnostics, ParseSess}; use crate::search_paths::{PathKind, SearchPath}; use crate::{filesearch, lint}; @@ -235,6 +241,9 @@ impl Session { if !unleashed_features.is_empty() { let mut must_err = false; // Create a diagnostic pointing at where things got unleashed. + // FIXME: We need to correctly migrate this. I couldn't find a way to migrate this. + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] let mut diag = self.struct_warn("skipping const checks"); for &(span, feature_gate) in unleashed_features.iter() { // FIXME: `span_label` doesn't do anything, so we use "help" as a hack. @@ -250,10 +259,7 @@ impl Session { // If we should err, make sure we did. if must_err && self.has_errors().is_none() { // We have skipped a feature gate, and not run into other errors... reject. - self.err( - "`-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature \ - gates, except when testing error paths in the CTFE engine", - ); + self.emit_err(NotCircumventFeature); } } } @@ -290,6 +296,8 @@ impl Session { } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_warn>( &self, sp: S, @@ -298,6 +306,8 @@ impl Session { self.diagnostic().struct_span_warn(sp, msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_warn_with_expectation>( &self, sp: S, @@ -307,6 +317,8 @@ impl Session { self.diagnostic().struct_span_warn_with_expectation(sp, msg, id) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_warn_with_code>( &self, sp: S, @@ -316,6 +328,8 @@ impl Session { self.diagnostic().struct_span_warn_with_code(sp, msg, code) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_warn(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_warn(msg) } @@ -328,6 +342,8 @@ impl Session { self.diagnostic().struct_warn_with_expectation(msg, id) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_allow>( &self, sp: S, @@ -336,10 +352,14 @@ impl Session { self.diagnostic().struct_span_allow(sp, msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_allow(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_allow(msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_expect( &self, msg: impl Into, @@ -348,6 +368,8 @@ impl Session { self.diagnostic().struct_expect(msg, id) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_err>( &self, sp: S, @@ -356,6 +378,8 @@ impl Session { self.diagnostic().struct_span_err(sp, msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_err_with_code>( &self, sp: S, @@ -366,6 +390,8 @@ impl Session { } // FIXME: This method should be removed (every error should have an associated error code). #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_err( &self, msg: impl Into, @@ -373,6 +399,8 @@ impl Session { self.parse_sess.struct_err(msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_err_with_code( &self, msg: impl Into, @@ -381,6 +409,8 @@ impl Session { self.diagnostic().struct_err_with_code(msg, code) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_warn_with_code( &self, msg: impl Into, @@ -389,6 +419,8 @@ impl Session { self.diagnostic().struct_warn_with_code(msg, code) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_fatal>( &self, sp: S, @@ -397,6 +429,8 @@ impl Session { self.diagnostic().struct_span_fatal(sp, msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_fatal_with_code>( &self, sp: S, @@ -406,15 +440,21 @@ impl Session { self.diagnostic().struct_span_fatal_with_code(sp, msg, code) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_fatal(&self, msg: impl Into) -> DiagnosticBuilder<'_, !> { self.diagnostic().struct_fatal(msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_fatal>(&self, sp: S, msg: impl Into) -> ! { self.diagnostic().span_fatal(sp, msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_fatal_with_code>( &self, sp: S, @@ -424,10 +464,14 @@ impl Session { self.diagnostic().span_fatal_with_code(sp, msg, code) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn fatal(&self, msg: impl Into) -> ! { self.diagnostic().fatal(msg).raise() } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_err_or_warn>( &self, is_warning: bool, @@ -441,6 +485,8 @@ impl Session { } } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_err>( &self, sp: S, @@ -449,6 +495,8 @@ impl Session { self.diagnostic().span_err(sp, msg) } #[rustc_lint_diagnostics] + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_err_with_code>( &self, sp: S, @@ -534,9 +582,13 @@ impl Session { Err(ErrorGuaranteed::unchecked_claim_error_was_emitted()) } } + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_warn>(&self, sp: S, msg: impl Into) { self.diagnostic().span_warn(sp, msg) } + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_warn_with_code>( &self, sp: S, @@ -585,6 +637,8 @@ impl Session { ) { self.diagnostic().span_note_without_error(sp, msg) } + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_note_without_error( &self, msg: impl Into, @@ -1469,40 +1523,28 @@ fn validate_commandline_args_with_session_available(sess: &Session) { && sess.opts.cg.prefer_dynamic && sess.target.is_like_windows { - sess.err( - "Linker plugin based LTO is not supported together with \ - `-C prefer-dynamic` when targeting Windows-like targets", - ); + sess.emit_err(LinkerPluginToWindowsNotSupported); } // Make sure that any given profiling data actually exists so LLVM can't // decide to silently skip PGO. if let Some(ref path) = sess.opts.cg.profile_use { if !path.exists() { - sess.err(&format!( - "File `{}` passed to `-C profile-use` does not exist.", - path.display() - )); + sess.emit_err(ProfileUseFileDoesNotExist { path }); } } // Do the same for sample profile data. if let Some(ref path) = sess.opts.unstable_opts.profile_sample_use { if !path.exists() { - sess.err(&format!( - "File `{}` passed to `-C profile-sample-use` does not exist.", - path.display() - )); + sess.emit_err(ProfileSampleUseFileDoesNotExist { path }); } } // Unwind tables cannot be disabled if the target requires them. if let Some(include_uwtables) = sess.opts.cg.force_unwind_tables { if sess.target.requires_uwtable && !include_uwtables { - sess.err( - "target requires unwind tables, they cannot be disabled with \ - `-C force-unwind-tables=no`.", - ); + sess.emit_err(TargetRequiresUnwindTables); } } @@ -1512,39 +1554,33 @@ fn validate_commandline_args_with_session_available(sess: &Session) { match unsupported_sanitizers.into_iter().count() { 0 => {} 1 => { - sess.err(&format!( - "{} sanitizer is not supported for this target", - unsupported_sanitizers - )); + sess.emit_err(SanitizerNotSupported { us: unsupported_sanitizers.to_string() }); } _ => { - sess.err(&format!( - "{} sanitizers are not supported for this target", - unsupported_sanitizers - )); + sess.emit_err(SanitizersNotSupported { us: unsupported_sanitizers.to_string() }); } } // Cannot mix and match sanitizers. let mut sanitizer_iter = sess.opts.unstable_opts.sanitizer.into_iter(); if let (Some(first), Some(second)) = (sanitizer_iter.next(), sanitizer_iter.next()) { - sess.err(&format!("`-Zsanitizer={first}` is incompatible with `-Zsanitizer={second}`")); + sess.emit_err(CannotMixAndMatchSanitizers { + first: first.to_string(), + second: second.to_string(), + }); } // Cannot enable crt-static with sanitizers on Linux if sess.crt_static(None) && !sess.opts.unstable_opts.sanitizer.is_empty() { - sess.err( - "sanitizer is incompatible with statically linked libc, \ - disable it using `-C target-feature=-crt-static`", - ); + sess.emit_err(CannotEnableCrtStaticLinux); } // LLVM CFI and VFE both require LTO. if sess.lto() != config::Lto::Fat { if sess.is_sanitizer_cfi_enabled() { - sess.err("`-Zsanitizer=cfi` requires `-Clto`"); + sess.emit_err(SanitizerCfiEnabled); } if sess.opts.unstable_opts.virtual_function_elimination { - sess.err("`-Zvirtual-function-elimination` requires `-Clto`"); + sess.emit_err(UnstableVirtualFunctionElimination); } } @@ -1559,7 +1595,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) { if let Some(dwarf_version) = sess.opts.unstable_opts.dwarf_version { if dwarf_version > 5 { - sess.err(&format!("requested DWARF version {} is greater than 5", dwarf_version)); + sess.emit_err(UnsupportedDwarfVersion { dwarf_version }); } } @@ -1614,14 +1650,20 @@ fn early_error_handler(output: config::ErrorOutputType) -> rustc_errors::Handler rustc_errors::Handler::with_emitter(true, None, emitter) } +#[allow(rustc::untranslatable_diagnostic)] +#[allow(rustc::diagnostic_outside_of_impl)] pub fn early_error_no_abort(output: config::ErrorOutputType, msg: &str) -> ErrorGuaranteed { early_error_handler(output).struct_err(msg).emit() } +#[allow(rustc::untranslatable_diagnostic)] +#[allow(rustc::diagnostic_outside_of_impl)] pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! { early_error_handler(output).struct_fatal(msg).emit() } +#[allow(rustc::untranslatable_diagnostic)] +#[allow(rustc::diagnostic_outside_of_impl)] pub fn early_warn(output: config::ErrorOutputType, msg: &str) { early_error_handler(output).struct_warn(msg).emit() } From 0f06320c2491acc8cf9e61c976041785acb06aca Mon Sep 17 00:00:00 2001 From: Luis Cardoso <61982523+LuisCardosoOliveira@users.noreply.github.com> Date: Fri, 2 Sep 2022 19:29:52 +0200 Subject: [PATCH 4317/5092] translations(rustc_session): migrate TargetDataLayout::parse --- .../locales/en-US/session.ftl | 14 +++++ compiler/rustc_errors/src/diagnostic.rs | 2 + compiler/rustc_middle/src/ty/context.rs | 3 +- compiler/rustc_session/src/errors.rs | 61 ++++++++++++++++-- compiler/rustc_target/src/abi/mod.rs | 63 +++++++++++-------- 5 files changed, 111 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/session.ftl b/compiler/rustc_error_messages/locales/en-US/session.ftl index 998196403e74..c5d23f292501 100644 --- a/compiler/rustc_error_messages/locales/en-US/session.ftl +++ b/compiler/rustc_error_messages/locales/en-US/session.ftl @@ -40,3 +40,17 @@ session_sanitizer_cfi_enabled = `-Zsanitizer=cfi` requires `-Clto` session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination` requires `-Clto` session_unsupported_dwarf_version = requested DWARF version {$dwarf_version} is greater than 5 + +session_target_invalid_address_space = invalid address space `{$addr_space}` for `{$cause}` in "data-layout": {$err} + +session_target_invalid_bits = invalid {$kind} `{$bit}` for `{$cause}` in "data-layout": {$err} + +session_target_missing_alignment = missing alignment for `{$cause}` in "data-layout" + +session_target_invalid_alignment = invalid alignment for `{$cause}` in "data-layout": {$err} + +session_target_inconsistent_architecture = inconsistent target specification: "data-layout" claims architecture is {$dl}-endian, while "target-endian" is `{$target}` + +session_target_inconsistent_pointer_width = inconsistent target specification: "data-layout" claims pointers are {$pointer_size}-bit, while "target-pointer-width" is `{$target}` + +session_target_invalid_bits_size = {$err} diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index a052aaee0475..b88292b893ce 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -14,6 +14,7 @@ use rustc_target::spec::PanicStrategy; use std::borrow::Cow; use std::fmt; use std::hash::{Hash, Hasher}; +use std::num::ParseIntError; use std::path::{Path, PathBuf}; /// Error type for `Diagnostic`'s `suggestions` field, indicating that @@ -91,6 +92,7 @@ into_diagnostic_arg_using_display!( Edition, Ident, MacroRulesNormalizedIdent, + ParseIntError, ); impl IntoDiagnosticArg for bool { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 262d59f8ff8a..583f682f568c 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -52,6 +52,7 @@ use rustc_query_system::ich::StableHashingContext; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_session::config::{CrateType, OutputFilenames}; use rustc_session::cstore::CrateStoreDyn; +use rustc_session::errors::TargetDataLayoutParseError; use rustc_session::lint::{Level, Lint}; use rustc_session::Limit; use rustc_session::Session; @@ -1251,7 +1252,7 @@ impl<'tcx> TyCtxt<'tcx> { output_filenames: OutputFilenames, ) -> GlobalCtxt<'tcx> { let data_layout = TargetDataLayout::parse(&s.target).unwrap_or_else(|err| { - s.fatal(&err); + s.emit_fatal(TargetDataLayoutParseError { err }); }); let interners = CtxtInterners::new(arena); let common_types = CommonTypes::new( diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 7aa8d6682410..226e09589276 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -1,10 +1,12 @@ use std::num::NonZeroU32; use crate::cgu_reuse_tracker::CguReuse; +use crate::parse::ParseSess; use crate::{self as rustc_session}; -use rustc_errors::MultiSpan; +use rustc_errors::{fluent, MultiSpan}; use rustc_macros::SessionDiagnostic; use rustc_span::{Span, Symbol}; +use rustc_target::abi::TargetDataLayoutErrors; #[derive(SessionDiagnostic)] #[diag(session::incorrect_cgu_reuse_type)] @@ -44,10 +46,59 @@ pub struct FeatureDiagnosticHelp { pub feature: Symbol, } -#[derive(SessionDiagnostic)] -#[diag(session::target_data_layout_parse_error)] -pub struct TargetDataLayoutParseError { - pub err: String, +pub struct TargetDataLayoutParseError<'a> { + pub err: TargetDataLayoutErrors<'a>, +} + +impl crate::SessionDiagnostic<'_, !> for TargetDataLayoutParseError<'_> { + fn into_diagnostic(self, sess: &ParseSess) -> rustc_errors::DiagnosticBuilder<'_, !> { + let mut diag; + match self.err { + TargetDataLayoutErrors::InvalidAddressSpace { addr_space, err, cause } => { + diag = sess.struct_fatal(fluent::session::target_invalid_address_space); + diag.set_arg("addr_space", addr_space); + diag.set_arg("cause", cause); + diag.set_arg("err", err); + diag + } + TargetDataLayoutErrors::InvalidBits { kind, bit, cause, err } => { + diag = sess.struct_fatal(fluent::session::target_invalid_bits); + diag.set_arg("kind", kind); + diag.set_arg("bit", bit); + diag.set_arg("cause", cause); + diag.set_arg("err", err); + diag + } + TargetDataLayoutErrors::MissingAlignment { cause } => { + diag = sess.struct_fatal(fluent::session::target_missing_alignment); + diag.set_arg("cause", cause); + diag + } + TargetDataLayoutErrors::InvalidAlignment { cause, err } => { + diag = sess.struct_fatal(fluent::session::target_invalid_alignment); + diag.set_arg("cause", cause); + diag.set_arg("err", err); + diag + } + TargetDataLayoutErrors::InconsistentTargetArchitecture { dl, target } => { + diag = sess.struct_fatal(fluent::session::target_inconsistent_architecture); + diag.set_arg("dl", dl); + diag.set_arg("target", target); + diag + } + TargetDataLayoutErrors::InconsistentTargetPointerWidth { pointer_size, target } => { + diag = sess.struct_fatal(fluent::session::target_inconsistent_pointer_width); + diag.set_arg("pointer_size", pointer_size); + diag.set_arg("target", target); + diag + } + TargetDataLayoutErrors::InvalidBitsSize { err } => { + diag = sess.struct_fatal(fluent::session::target_invalid_bits_size); + diag.set_arg("err", err); + diag + } + } + } } #[derive(SessionDiagnostic)] diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index bcaf209f84b6..ec334e5887ab 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -7,7 +7,7 @@ use crate::spec::Target; use std::convert::{TryFrom, TryInto}; use std::fmt; use std::iter::Step; -use std::num::NonZeroUsize; +use std::num::{NonZeroUsize, ParseIntError}; use std::ops::{Add, AddAssign, Deref, Mul, RangeInclusive, Sub}; use std::str::FromStr; @@ -69,34 +69,46 @@ impl Default for TargetDataLayout { } } +pub enum TargetDataLayoutErrors<'a> { + InvalidAddressSpace { addr_space: &'a str, cause: &'a str, err: ParseIntError }, + InvalidBits { kind: &'a str, bit: &'a str, cause: &'a str, err: ParseIntError }, + MissingAlignment { cause: &'a str }, + InvalidAlignment { cause: &'a str, err: String }, + InconsistentTargetArchitecture { dl: &'a str, target: &'a str }, + InconsistentTargetPointerWidth { pointer_size: u64, target: u32 }, + InvalidBitsSize { err: String }, +} + impl TargetDataLayout { - pub fn parse(target: &Target) -> Result { + pub fn parse<'a>(target: &'a Target) -> Result> { // Parse an address space index from a string. - let parse_address_space = |s: &str, cause: &str| { + let parse_address_space = |s: &'a str, cause: &'a str| { s.parse::().map(AddressSpace).map_err(|err| { - format!("invalid address space `{}` for `{}` in \"data-layout\": {}", s, cause, err) + TargetDataLayoutErrors::InvalidAddressSpace { addr_space: s, cause, err } }) }; // Parse a bit count from a string. - let parse_bits = |s: &str, kind: &str, cause: &str| { - s.parse::().map_err(|err| { - format!("invalid {} `{}` for `{}` in \"data-layout\": {}", kind, s, cause, err) + let parse_bits = |s: &'a str, kind: &'a str, cause: &'a str| { + s.parse::().map_err(|err| TargetDataLayoutErrors::InvalidBits { + kind, + bit: s, + cause, + err, }) }; // Parse a size string. - let size = |s: &str, cause: &str| parse_bits(s, "size", cause).map(Size::from_bits); + let size = |s: &'a str, cause: &'a str| parse_bits(s, "size", cause).map(Size::from_bits); // Parse an alignment string. - let align = |s: &[&str], cause: &str| { + let align = |s: &[&'a str], cause: &'a str| { if s.is_empty() { - return Err(format!("missing alignment for `{}` in \"data-layout\"", cause)); + return Err(TargetDataLayoutErrors::MissingAlignment { cause }); } let align_from_bits = |bits| { - Align::from_bits(bits).map_err(|err| { - format!("invalid alignment for `{}` in \"data-layout\": {}", cause, err) - }) + Align::from_bits(bits) + .map_err(|err| TargetDataLayoutErrors::InvalidAlignment { cause, err }) }; let abi = parse_bits(s[0], "alignment", cause)?; let pref = s.get(1).map_or(Ok(abi), |pref| parse_bits(pref, "alignment", cause))?; @@ -158,25 +170,24 @@ impl TargetDataLayout { // Perform consistency checks against the Target information. if dl.endian != target.endian { - return Err(format!( - "inconsistent target specification: \"data-layout\" claims \ - architecture is {}-endian, while \"target-endian\" is `{}`", - dl.endian.as_str(), - target.endian.as_str(), - )); + return Err(TargetDataLayoutErrors::InconsistentTargetArchitecture { + dl: dl.endian.as_str(), + target: target.endian.as_str(), + }); } let target_pointer_width: u64 = target.pointer_width.into(); if dl.pointer_size.bits() != target_pointer_width { - return Err(format!( - "inconsistent target specification: \"data-layout\" claims \ - pointers are {}-bit, while \"target-pointer-width\" is `{}`", - dl.pointer_size.bits(), - target.pointer_width - )); + return Err(TargetDataLayoutErrors::InconsistentTargetPointerWidth { + pointer_size: dl.pointer_size.bits(), + target: target.pointer_width, + }); } - dl.c_enum_min_size = Integer::from_size(Size::from_bits(target.c_enum_min_bits))?; + dl.c_enum_min_size = match Integer::from_size(Size::from_bits(target.c_enum_min_bits)) { + Ok(bits) => bits, + Err(err) => return Err(TargetDataLayoutErrors::InvalidBitsSize { err }), + }; Ok(dl) } From 24de9435e2d4efe2bde043f389579a72fb532c6f Mon Sep 17 00:00:00 2001 From: Luis Cardoso <61982523+LuisCardosoOliveira@users.noreply.github.com> Date: Mon, 5 Sep 2022 07:58:05 +0200 Subject: [PATCH 4318/5092] translations(rustc_session): remove lint allow rule to the methods marked with rustc_lint_diagnostic This commit removes the allows rules for the SessionDiagnostic lint that were being used in the session.rs file. Thanks to the PR #101230 we do not need to annotate the methods with the allow rule as they are part of the diagnostic machinery. --- .../locales/en-US/session.ftl | 8 ++-- compiler/rustc_middle/src/ty/context.rs | 3 +- compiler/rustc_session/src/config.rs | 3 +- compiler/rustc_session/src/errors.rs | 15 +++---- compiler/rustc_session/src/session.rs | 44 +------------------ 5 files changed, 12 insertions(+), 61 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/session.ftl b/compiler/rustc_error_messages/locales/en-US/session.ftl index c5d23f292501..a9ed8b4835b7 100644 --- a/compiler/rustc_error_messages/locales/en-US/session.ftl +++ b/compiler/rustc_error_messages/locales/en-US/session.ftl @@ -19,13 +19,13 @@ session_target_data_layout_parse_error = {$err} session_not_circumvent_feature = `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine -session_profile_use_file_does_not_exist = File `{$path}` passed to `-C profile-use` does not exist. +session_profile_use_file_does_not_exist = file `{$path}` passed to `-C profile-use` does not exist. -session_linker_plugin_lto_windows_not_supported = Linker plugin based LTO is not supported together with `-C prefer-dynamic` when targeting Windows-like targets" +session_linker_plugin_lto_windows_not_supported = linker plugin based LTO is not supported together with `-C prefer-dynamic` when targeting Windows-like targets -session_profile_sample_use_file_does_not_exist = File `{$path}` passed to `-C profile-sample-use` does not exist. +session_profile_sample_use_file_does_not_exist = file `{$path}` passed to `-C profile-sample-use` does not exist. -session_target_requires_unwind_tables = target requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no`." +session_target_requires_unwind_tables = target requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no` session_sanitizer_not_supported = {$us} sanitizer is not supported for this target diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 583f682f568c..ccdcf47b4688 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -52,7 +52,6 @@ use rustc_query_system::ich::StableHashingContext; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_session::config::{CrateType, OutputFilenames}; use rustc_session::cstore::CrateStoreDyn; -use rustc_session::errors::TargetDataLayoutParseError; use rustc_session::lint::{Level, Lint}; use rustc_session::Limit; use rustc_session::Session; @@ -1252,7 +1251,7 @@ impl<'tcx> TyCtxt<'tcx> { output_filenames: OutputFilenames, ) -> GlobalCtxt<'tcx> { let data_layout = TargetDataLayout::parse(&s.target).unwrap_or_else(|err| { - s.emit_fatal(TargetDataLayoutParseError { err }); + s.emit_fatal(err); }); let interners = CtxtInterners::new(arena); let common_types = CommonTypes::new( diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 0018346c72c4..8bb3878fbbb4 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1,7 +1,6 @@ //! Contains infrastructure for configuring the compiler, including parsing //! command-line options. -use crate::errors::TargetDataLayoutParseError; pub use crate::options::*; use crate::search_paths::SearchPath; @@ -899,7 +898,7 @@ fn default_configuration(sess: &Session) -> CrateConfig { let max_atomic_width = sess.target.max_atomic_width(); let atomic_cas = sess.target.atomic_cas; let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| { - sess.emit_fatal(TargetDataLayoutParseError { err }); + sess.emit_fatal(err); }); let mut ret = CrateConfig::default(); diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 226e09589276..a4e13e22ae22 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -1,9 +1,8 @@ use std::num::NonZeroU32; use crate::cgu_reuse_tracker::CguReuse; -use crate::parse::ParseSess; -use crate::{self as rustc_session}; -use rustc_errors::{fluent, MultiSpan}; +use crate::{self as rustc_session, SessionDiagnostic}; +use rustc_errors::{fluent, DiagnosticBuilder, Handler, MultiSpan}; use rustc_macros::SessionDiagnostic; use rustc_span::{Span, Symbol}; use rustc_target::abi::TargetDataLayoutErrors; @@ -46,14 +45,10 @@ pub struct FeatureDiagnosticHelp { pub feature: Symbol, } -pub struct TargetDataLayoutParseError<'a> { - pub err: TargetDataLayoutErrors<'a>, -} - -impl crate::SessionDiagnostic<'_, !> for TargetDataLayoutParseError<'_> { - fn into_diagnostic(self, sess: &ParseSess) -> rustc_errors::DiagnosticBuilder<'_, !> { +impl SessionDiagnostic<'_, !> for TargetDataLayoutErrors<'_> { + fn into_diagnostic(self, sess: &Handler) -> DiagnosticBuilder<'_, !> { let mut diag; - match self.err { + match self { TargetDataLayoutErrors::InvalidAddressSpace { addr_space, err, cause } => { diag = sess.struct_fatal(fluent::session::target_invalid_address_space); diag.set_arg("addr_space", addr_space); diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 4fe0e1de5b33..6add576cdff3 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -241,7 +241,7 @@ impl Session { if !unleashed_features.is_empty() { let mut must_err = false; // Create a diagnostic pointing at where things got unleashed. - // FIXME: We need to correctly migrate this. I couldn't find a way to migrate this. + // FIXME(#100717): needs eager translation/lists #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] let mut diag = self.struct_warn("skipping const checks"); @@ -296,8 +296,6 @@ impl Session { } #[rustc_lint_diagnostics] - #[allow(rustc::untranslatable_diagnostic)] - #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_warn>( &self, sp: S, @@ -306,8 +304,6 @@ impl Session { self.diagnostic().struct_span_warn(sp, msg) } #[rustc_lint_diagnostics] - #[allow(rustc::untranslatable_diagnostic)] - #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_warn_with_expectation>( &self, sp: S, @@ -317,8 +313,6 @@ impl Session { self.diagnostic().struct_span_warn_with_expectation(sp, msg, id) } #[rustc_lint_diagnostics] - #[allow(rustc::untranslatable_diagnostic)] - #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_warn_with_code>( &self, sp: S, @@ -328,8 +322,6 @@ impl Session { self.diagnostic().struct_span_warn_with_code(sp, msg, code) } #[rustc_lint_diagnostics] - #[allow(rustc::untranslatable_diagnostic)] - #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_warn(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_warn(msg) } @@ -342,8 +334,6 @@ impl Session { self.diagnostic().struct_warn_with_expectation(msg, id) } #[rustc_lint_diagnostics] - #[allow(rustc::untranslatable_diagnostic)] - #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_allow>( &self, sp: S, @@ -352,14 +342,10 @@ impl Session { self.diagnostic().struct_span_allow(sp, msg) } #[rustc_lint_diagnostics] - #[allow(rustc::untranslatable_diagnostic)] - #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_allow(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { self.diagnostic().struct_allow(msg) } #[rustc_lint_diagnostics] - #[allow(rustc::untranslatable_diagnostic)] - #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_expect( &self, msg: impl Into, @@ -368,8 +354,6 @@ impl Session { self.diagnostic().struct_expect(msg, id) } #[rustc_lint_diagnostics] - #[allow(rustc::untranslatable_diagnostic)] - #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_err>( &self, sp: S, @@ -378,8 +362,6 @@ impl Session { self.diagnostic().struct_span_err(sp, msg) } #[rustc_lint_diagnostics] - #[allow(rustc::untranslatable_diagnostic)] - #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_err_with_code>( &self, sp: S, @@ -390,8 +372,6 @@ impl Session { } // FIXME: This method should be removed (every error should have an associated error code). #[rustc_lint_diagnostics] - #[allow(rustc::untranslatable_diagnostic)] - #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_err( &self, msg: impl Into, @@ -399,8 +379,6 @@ impl Session { self.parse_sess.struct_err(msg) } #[rustc_lint_diagnostics] - #[allow(rustc::untranslatable_diagnostic)] - #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_err_with_code( &self, msg: impl Into, @@ -409,8 +387,6 @@ impl Session { self.diagnostic().struct_err_with_code(msg, code) } #[rustc_lint_diagnostics] - #[allow(rustc::untranslatable_diagnostic)] - #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_warn_with_code( &self, msg: impl Into, @@ -419,8 +395,6 @@ impl Session { self.diagnostic().struct_warn_with_code(msg, code) } #[rustc_lint_diagnostics] - #[allow(rustc::untranslatable_diagnostic)] - #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_fatal>( &self, sp: S, @@ -429,8 +403,6 @@ impl Session { self.diagnostic().struct_span_fatal(sp, msg) } #[rustc_lint_diagnostics] - #[allow(rustc::untranslatable_diagnostic)] - #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_span_fatal_with_code>( &self, sp: S, @@ -440,21 +412,15 @@ impl Session { self.diagnostic().struct_span_fatal_with_code(sp, msg, code) } #[rustc_lint_diagnostics] - #[allow(rustc::untranslatable_diagnostic)] - #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_fatal(&self, msg: impl Into) -> DiagnosticBuilder<'_, !> { self.diagnostic().struct_fatal(msg) } #[rustc_lint_diagnostics] - #[allow(rustc::untranslatable_diagnostic)] - #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_fatal>(&self, sp: S, msg: impl Into) -> ! { self.diagnostic().span_fatal(sp, msg) } #[rustc_lint_diagnostics] - #[allow(rustc::untranslatable_diagnostic)] - #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_fatal_with_code>( &self, sp: S, @@ -464,14 +430,10 @@ impl Session { self.diagnostic().span_fatal_with_code(sp, msg, code) } #[rustc_lint_diagnostics] - #[allow(rustc::untranslatable_diagnostic)] - #[allow(rustc::diagnostic_outside_of_impl)] pub fn fatal(&self, msg: impl Into) -> ! { self.diagnostic().fatal(msg).raise() } #[rustc_lint_diagnostics] - #[allow(rustc::untranslatable_diagnostic)] - #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_err_or_warn>( &self, is_warning: bool, @@ -485,8 +447,6 @@ impl Session { } } #[rustc_lint_diagnostics] - #[allow(rustc::untranslatable_diagnostic)] - #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_err>( &self, sp: S, @@ -495,8 +455,6 @@ impl Session { self.diagnostic().span_err(sp, msg) } #[rustc_lint_diagnostics] - #[allow(rustc::untranslatable_diagnostic)] - #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_err_with_code>( &self, sp: S, From ddb225f1f57882c4f87d99d585fab982461d1fd9 Mon Sep 17 00:00:00 2001 From: yukang Date: Wed, 7 Sep 2022 12:26:50 +0800 Subject: [PATCH 4319/5092] fixes #101477: Recover from typo where == is used in place of = --- .../locales/en-US/parser.ftl | 3 +++ compiler/rustc_parse/src/parser/diagnostics.rs | 16 ++++++++++++++++ src/test/ui/parser/issue-101477-enum.fixed | 10 ++++++++++ src/test/ui/parser/issue-101477-enum.rs | 10 ++++++++++ src/test/ui/parser/issue-101477-enum.stderr | 14 ++++++++++++++ src/test/ui/parser/issue-101477-let.fixed | 6 ++++++ src/test/ui/parser/issue-101477-let.rs | 6 ++++++ src/test/ui/parser/issue-101477-let.stderr | 8 ++++++++ 8 files changed, 73 insertions(+) create mode 100644 src/test/ui/parser/issue-101477-enum.fixed create mode 100644 src/test/ui/parser/issue-101477-enum.rs create mode 100644 src/test/ui/parser/issue-101477-enum.stderr create mode 100644 src/test/ui/parser/issue-101477-let.fixed create mode 100644 src/test/ui/parser/issue-101477-let.rs create mode 100644 src/test/ui/parser/issue-101477-let.stderr diff --git a/compiler/rustc_error_messages/locales/en-US/parser.ftl b/compiler/rustc_error_messages/locales/en-US/parser.ftl index bc17754c56ae..f74df3d9746a 100644 --- a/compiler/rustc_error_messages/locales/en-US/parser.ftl +++ b/compiler/rustc_error_messages/locales/en-US/parser.ftl @@ -153,3 +153,6 @@ parser_left_arrow_operator = unexpected token: `<-` parser_remove_let = expected pattern, found `let` .suggestion = remove the unnecessary `let` keyword + +parser_use_eq_instead = unexpected `==` + .suggestion = try using `=` instead diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index ad49227222b2..be524db785bc 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -713,6 +713,14 @@ pub(crate) struct RemoveLet { pub span: Span, } +#[derive(SessionDiagnostic)] +#[diag(parser::use_eq_instead)] +pub(crate) struct UseEqInstead { + #[primary_span] + #[suggestion_short(applicability = "machine-applicable", code = "=")] + pub span: Span, +} + // SnapshotParser is used to create a snapshot of the parser // without causing duplicate errors being emitted when the `Parser` // is dropped. @@ -957,6 +965,14 @@ impl<'a> Parser<'a> { } } + if self.token.kind == TokenKind::EqEq + && self.prev_token.is_ident() + && expected.iter().any(|tok| matches!(tok, TokenType::Token(TokenKind::Eq))) + { + // Likely typo: `=` → `==` in let expr or enum item + return Err(self.sess.create_err(UseEqInstead { span: self.token.span })); + } + let expect = tokens_to_string(&expected); let actual = super::token_descr(&self.token); let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 { diff --git a/src/test/ui/parser/issue-101477-enum.fixed b/src/test/ui/parser/issue-101477-enum.fixed new file mode 100644 index 000000000000..1dfeae22aea2 --- /dev/null +++ b/src/test/ui/parser/issue-101477-enum.fixed @@ -0,0 +1,10 @@ +// run-rustfix + +#[allow(dead_code)] +enum Demo { + A = 1, + B = 2 //~ ERROR unexpected `==` + //~^ expected item, found `==` +} + +fn main() {} diff --git a/src/test/ui/parser/issue-101477-enum.rs b/src/test/ui/parser/issue-101477-enum.rs new file mode 100644 index 000000000000..ea7051d69a4c --- /dev/null +++ b/src/test/ui/parser/issue-101477-enum.rs @@ -0,0 +1,10 @@ +// run-rustfix + +#[allow(dead_code)] +enum Demo { + A = 1, + B == 2 //~ ERROR unexpected `==` + //~^ expected item, found `==` +} + +fn main() {} diff --git a/src/test/ui/parser/issue-101477-enum.stderr b/src/test/ui/parser/issue-101477-enum.stderr new file mode 100644 index 000000000000..bffc881bdc84 --- /dev/null +++ b/src/test/ui/parser/issue-101477-enum.stderr @@ -0,0 +1,14 @@ +error: unexpected `==` + --> $DIR/issue-101477-enum.rs:6:7 + | +LL | B == 2 + | ^^ help: try using `=` instead + +error: expected item, found `==` + --> $DIR/issue-101477-enum.rs:6:7 + | +LL | B == 2 + | ^^ expected item + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/parser/issue-101477-let.fixed b/src/test/ui/parser/issue-101477-let.fixed new file mode 100644 index 000000000000..9989ad81524e --- /dev/null +++ b/src/test/ui/parser/issue-101477-let.fixed @@ -0,0 +1,6 @@ +// run-rustfix + +fn main() { + let x = 2; //~ ERROR unexpected `==` + println!("x: {}", x) +} diff --git a/src/test/ui/parser/issue-101477-let.rs b/src/test/ui/parser/issue-101477-let.rs new file mode 100644 index 000000000000..8b0e8bee1799 --- /dev/null +++ b/src/test/ui/parser/issue-101477-let.rs @@ -0,0 +1,6 @@ +// run-rustfix + +fn main() { + let x == 2; //~ ERROR unexpected `==` + println!("x: {}", x) +} diff --git a/src/test/ui/parser/issue-101477-let.stderr b/src/test/ui/parser/issue-101477-let.stderr new file mode 100644 index 000000000000..1b30d4b17861 --- /dev/null +++ b/src/test/ui/parser/issue-101477-let.stderr @@ -0,0 +1,8 @@ +error: unexpected `==` + --> $DIR/issue-101477-let.rs:4:11 + | +LL | let x == 2; + | ^^ help: try using `=` instead + +error: aborting due to previous error + From 52fd25de9ce061dcc76606cf0ea7552a5987f90e Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Thu, 8 Sep 2022 17:02:59 +0900 Subject: [PATCH 4320/5092] Link UEFI target documentation from target list --- src/doc/rustc/src/platform-support.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 742fbe11d9c6..fe090a73327c 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -213,7 +213,7 @@ target | std | host | notes [`aarch64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ | `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD `aarch64-unknown-hermit` | ✓ | | ARM64 HermitCore -`aarch64-unknown-uefi` | * | | ARM64 UEFI +[`aarch64-unknown-uefi`](platform-support/unknown-uefi.md) | * | | ARM64 UEFI `aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI) `aarch64-unknown-netbsd` | ✓ | ✓ | [`aarch64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | ARM64 OpenBSD @@ -250,7 +250,7 @@ target | std | host | notes `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku `i686-unknown-netbsd` | ✓ | ✓ | NetBSD/i386 with SSE2 [`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD -`i686-unknown-uefi` | * | | 32-bit UEFI +[`i686-unknown-uefi`](platform-support/unknown-uefi.md) | * | | 32-bit UEFI `i686-uwp-windows-gnu` | ? | | `i686-uwp-windows-msvc` | ? | | `i686-wrs-vxworks` | ? | | @@ -307,7 +307,7 @@ target | std | host | notes `x86_64-unknown-l4re-uclibc` | ? | | `x86_64-unknown-none-linuxkernel` | * | | Linux kernel modules [`x86_64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 64-bit OpenBSD -`x86_64-unknown-uefi` | * | | 64-bit UEFI +[`x86_64-unknown-uefi`](platform-support/unknown-uefi.md) | * | | 64-bit UEFI `x86_64-uwp-windows-gnu` | ✓ | | `x86_64-uwp-windows-msvc` | ✓ | | `x86_64-wrs-vxworks` | ? | | From 5c9d28d303f316c6cc6895ec742839b79392720a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 5 Jul 2022 13:56:51 +0000 Subject: [PATCH 4321/5092] Opaque types' generic params do not imply anything about their hidden type's lifetimes --- compiler/rustc_middle/src/ty/visit.rs | 2 +- .../type-alias-impl-trait/constrain_inputs.rs | 24 +++++++-- .../constrain_inputs.stderr | 52 +++++++++++++++++++ .../constrain_inputs_unsound.rs | 31 +++++++++++ .../constrain_inputs_unsound.stderr | 9 ++++ 5 files changed, 113 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/type-alias-impl-trait/constrain_inputs.stderr create mode 100644 src/test/ui/type-alias-impl-trait/constrain_inputs_unsound.rs create mode 100644 src/test/ui/type-alias-impl-trait/constrain_inputs_unsound.stderr diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index 5e042c3acfce..5f8cb5782021 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -666,7 +666,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { // ignore the inputs to a projection, as they may not appear // in the normalized form if self.just_constrained { - if let ty::Projection(..) = t.kind() { + if let ty::Projection(..) | ty::Opaque(..) = t.kind() { return ControlFlow::CONTINUE; } } diff --git a/src/test/ui/type-alias-impl-trait/constrain_inputs.rs b/src/test/ui/type-alias-impl-trait/constrain_inputs.rs index c32174288ee6..1300a2e45d57 100644 --- a/src/test/ui/type-alias-impl-trait/constrain_inputs.rs +++ b/src/test/ui/type-alias-impl-trait/constrain_inputs.rs @@ -1,17 +1,33 @@ -// check-pass - #![feature(type_alias_impl_trait)] -mod foo { +mod lifetime_params { type Ty<'a> = impl Sized; fn defining(s: &str) -> Ty<'_> { s } fn execute(ty: Ty<'_>) -> &str { todo!() } + //~^ ERROR return type references an anonymous lifetime, which is not constrained by the fn input types + + type BadFnSig = fn(Ty<'_>) -> &str; + //~^ ERROR return type references an anonymous lifetime, which is not constrained by the fn input types + type BadTraitRef = dyn Fn(Ty<'_>) -> &str; + //~^ ERROR binding for associated type `Output` references an anonymous lifetime } -mod bar { +mod type_params { type Ty<'a> = impl FnOnce() -> &'a str; fn defining(s: &str) -> Ty<'_> { move || s } fn execute(ty: Ty<'_>) -> &str { ty() } + //~^ ERROR return type references an anonymous lifetime, which is not constrained by the fn input types +} + +// regression test for https://github.com/rust-lang/rust/issues/97104 +mod type_params2 { + type Ty = impl Sized; + fn define(s: T) -> Ty { s } + + type BadFnSig = fn(Ty<&str>) -> &str; + //~^ ERROR return type references an anonymous lifetime, which is not constrained by the fn input types + type BadTraitRef = dyn Fn(Ty<&str>) -> &str; + //~^ ERROR binding for associated type `Output` references an anonymous lifetime } fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/constrain_inputs.stderr b/src/test/ui/type-alias-impl-trait/constrain_inputs.stderr new file mode 100644 index 000000000000..c35b55df6438 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/constrain_inputs.stderr @@ -0,0 +1,52 @@ +error[E0581]: return type references an anonymous lifetime, which is not constrained by the fn input types + --> $DIR/constrain_inputs.rs:6:31 + | +LL | fn execute(ty: Ty<'_>) -> &str { todo!() } + | ^^^^ + | + = note: lifetimes appearing in an associated type are not considered constrained + +error[E0581]: return type references an anonymous lifetime, which is not constrained by the fn input types + --> $DIR/constrain_inputs.rs:9:35 + | +LL | type BadFnSig = fn(Ty<'_>) -> &str; + | ^^^^ + | + = note: lifetimes appearing in an associated type are not considered constrained + +error[E0582]: binding for associated type `Output` references an anonymous lifetime, which does not appear in the trait input types + --> $DIR/constrain_inputs.rs:11:42 + | +LL | type BadTraitRef = dyn Fn(Ty<'_>) -> &str; + | ^^^^ + | + = note: lifetimes appearing in an associated type are not considered constrained + +error[E0581]: return type references an anonymous lifetime, which is not constrained by the fn input types + --> $DIR/constrain_inputs.rs:18:31 + | +LL | fn execute(ty: Ty<'_>) -> &str { ty() } + | ^^^^ + | + = note: lifetimes appearing in an associated type are not considered constrained + +error[E0581]: return type references an anonymous lifetime, which is not constrained by the fn input types + --> $DIR/constrain_inputs.rs:27:37 + | +LL | type BadFnSig = fn(Ty<&str>) -> &str; + | ^^^^ + | + = note: lifetimes appearing in an associated type are not considered constrained + +error[E0582]: binding for associated type `Output` references an anonymous lifetime, which does not appear in the trait input types + --> $DIR/constrain_inputs.rs:29:44 + | +LL | type BadTraitRef = dyn Fn(Ty<&str>) -> &str; + | ^^^^ + | + = note: lifetimes appearing in an associated type are not considered constrained + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0581, E0582. +For more information about an error, try `rustc --explain E0581`. diff --git a/src/test/ui/type-alias-impl-trait/constrain_inputs_unsound.rs b/src/test/ui/type-alias-impl-trait/constrain_inputs_unsound.rs new file mode 100644 index 000000000000..937ca48a52db --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/constrain_inputs_unsound.rs @@ -0,0 +1,31 @@ +#![feature(type_alias_impl_trait)] + +trait Static: 'static {} +impl Static for () {} + +type Gal = impl Static; +fn _defining() -> Gal {} + +trait Callable { type Output; } + +/// We can infer `>::Output: 'static`, +/// because we know `C: 'static` and `Arg: 'static`, +fn box_str(s: C::Output) -> Box + 'static> +where + Arg: Static, + C: ?Sized + Callable + 'static, + C::Output: AsRef, +{ + Box::new(s) +} + +fn extend_lifetime(s: &str) -> Box + 'static> { + type MalformedTy = dyn for<'a> Callable, Output = &'a str>; + //~^ ERROR binding for associated type `Output` references lifetime `'a` + box_str::(s) +} + +fn main() { + //let extended = extend_lifetime(&String::from("hello")); + //println!("{}", extended.as_ref().as_ref()); +} diff --git a/src/test/ui/type-alias-impl-trait/constrain_inputs_unsound.stderr b/src/test/ui/type-alias-impl-trait/constrain_inputs_unsound.stderr new file mode 100644 index 000000000000..d5fc46cb1f59 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/constrain_inputs_unsound.stderr @@ -0,0 +1,9 @@ +error[E0582]: binding for associated type `Output` references lifetime `'a`, which does not appear in the trait input types + --> $DIR/constrain_inputs_unsound.rs:23:58 + | +LL | type MalformedTy = dyn for<'a> Callable, Output = &'a str>; + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0582`. From 5cd3cc134a41c92616ff74f652556135404ead8a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 25 Aug 2022 10:23:22 +0000 Subject: [PATCH 4322/5092] Uncomment unsound code example --- src/test/ui/type-alias-impl-trait/constrain_inputs_unsound.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/ui/type-alias-impl-trait/constrain_inputs_unsound.rs b/src/test/ui/type-alias-impl-trait/constrain_inputs_unsound.rs index 937ca48a52db..3bae0f173099 100644 --- a/src/test/ui/type-alias-impl-trait/constrain_inputs_unsound.rs +++ b/src/test/ui/type-alias-impl-trait/constrain_inputs_unsound.rs @@ -26,6 +26,6 @@ fn extend_lifetime(s: &str) -> Box + 'static> { } fn main() { - //let extended = extend_lifetime(&String::from("hello")); - //println!("{}", extended.as_ref().as_ref()); + let extended = extend_lifetime(&String::from("hello")); + println!("{}", extended.as_ref().as_ref()); } From 64d11fc8e336344a8b8a55a55131ded4be26cebd Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 25 Aug 2022 10:30:46 +0000 Subject: [PATCH 4323/5092] Clarify some diagnostic messages --- compiler/rustc_typeck/src/astconv/mod.rs | 3 ++- src/test/ui/associated-types/issue-62200.rs | 3 ++- .../ui/associated-types/issue-62200.stderr | 3 ++- src/test/ui/issues/issue-47511.stderr | 3 ++- .../type-alias-impl-trait/constrain_inputs.rs | 4 ++-- .../constrain_inputs.stderr | 18 ++++++++++++------ 6 files changed, 22 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 801063583e63..d66cf6d099ad 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -2940,8 +2940,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // though we can easily give a hint that ought to be // relevant. err.note( - "lifetimes appearing in an associated type are not considered constrained", + "lifetimes appearing in an associated or opaque type are not considered constrained", ); + err.note("consider introducing a named lifetime parameter"); } err.emit(); diff --git a/src/test/ui/associated-types/issue-62200.rs b/src/test/ui/associated-types/issue-62200.rs index 9d18690e9604..499bbd6b6fad 100644 --- a/src/test/ui/associated-types/issue-62200.rs +++ b/src/test/ui/associated-types/issue-62200.rs @@ -10,6 +10,7 @@ impl T<'_> for S { fn foo(x: impl Fn(>::A) -> >::A) {} //~^ ERROR binding for associated type `Output` references an anonymous lifetime -//~^^ NOTE lifetimes appearing in an associated type are not considered constrained +//~| NOTE lifetimes appearing in an associated or opaque type are not considered constrained +//~| NOTE consider introducing a named lifetime parameter fn main() {} diff --git a/src/test/ui/associated-types/issue-62200.stderr b/src/test/ui/associated-types/issue-62200.stderr index f14cd81fdfe1..04f0728f58ea 100644 --- a/src/test/ui/associated-types/issue-62200.stderr +++ b/src/test/ui/associated-types/issue-62200.stderr @@ -4,7 +4,8 @@ error[E0582]: binding for associated type `Output` references an anonymous lifet LL | fn foo(x: impl Fn(>::A) -> >::A) {} | ^^^^^^^^^^^^^^^ | - = note: lifetimes appearing in an associated type are not considered constrained + = note: lifetimes appearing in an associated or opaque type are not considered constrained + = note: consider introducing a named lifetime parameter error: aborting due to previous error diff --git a/src/test/ui/issues/issue-47511.stderr b/src/test/ui/issues/issue-47511.stderr index 5b84f7ed62c3..9998ee0e8d0c 100644 --- a/src/test/ui/issues/issue-47511.stderr +++ b/src/test/ui/issues/issue-47511.stderr @@ -4,7 +4,8 @@ error[E0581]: return type references an anonymous lifetime, which is not constra LL | fn f(_: X) -> X { | ^ | - = note: lifetimes appearing in an associated type are not considered constrained + = note: lifetimes appearing in an associated or opaque type are not considered constrained + = note: consider introducing a named lifetime parameter error[E0581]: return type references lifetime `'a`, which is not constrained by the fn input types --> $DIR/issue-47511.rs:12:23 diff --git a/src/test/ui/type-alias-impl-trait/constrain_inputs.rs b/src/test/ui/type-alias-impl-trait/constrain_inputs.rs index 1300a2e45d57..03fb64b7b94d 100644 --- a/src/test/ui/type-alias-impl-trait/constrain_inputs.rs +++ b/src/test/ui/type-alias-impl-trait/constrain_inputs.rs @@ -12,7 +12,7 @@ mod lifetime_params { //~^ ERROR binding for associated type `Output` references an anonymous lifetime } -mod type_params { +mod lifetime_params_2 { type Ty<'a> = impl FnOnce() -> &'a str; fn defining(s: &str) -> Ty<'_> { move || s } fn execute(ty: Ty<'_>) -> &str { ty() } @@ -20,7 +20,7 @@ mod type_params { } // regression test for https://github.com/rust-lang/rust/issues/97104 -mod type_params2 { +mod type_params { type Ty = impl Sized; fn define(s: T) -> Ty { s } diff --git a/src/test/ui/type-alias-impl-trait/constrain_inputs.stderr b/src/test/ui/type-alias-impl-trait/constrain_inputs.stderr index c35b55df6438..93953fd06d1f 100644 --- a/src/test/ui/type-alias-impl-trait/constrain_inputs.stderr +++ b/src/test/ui/type-alias-impl-trait/constrain_inputs.stderr @@ -4,7 +4,8 @@ error[E0581]: return type references an anonymous lifetime, which is not constra LL | fn execute(ty: Ty<'_>) -> &str { todo!() } | ^^^^ | - = note: lifetimes appearing in an associated type are not considered constrained + = note: lifetimes appearing in an associated or opaque type are not considered constrained + = note: consider introducing a named lifetime parameter error[E0581]: return type references an anonymous lifetime, which is not constrained by the fn input types --> $DIR/constrain_inputs.rs:9:35 @@ -12,7 +13,8 @@ error[E0581]: return type references an anonymous lifetime, which is not constra LL | type BadFnSig = fn(Ty<'_>) -> &str; | ^^^^ | - = note: lifetimes appearing in an associated type are not considered constrained + = note: lifetimes appearing in an associated or opaque type are not considered constrained + = note: consider introducing a named lifetime parameter error[E0582]: binding for associated type `Output` references an anonymous lifetime, which does not appear in the trait input types --> $DIR/constrain_inputs.rs:11:42 @@ -20,7 +22,8 @@ error[E0582]: binding for associated type `Output` references an anonymous lifet LL | type BadTraitRef = dyn Fn(Ty<'_>) -> &str; | ^^^^ | - = note: lifetimes appearing in an associated type are not considered constrained + = note: lifetimes appearing in an associated or opaque type are not considered constrained + = note: consider introducing a named lifetime parameter error[E0581]: return type references an anonymous lifetime, which is not constrained by the fn input types --> $DIR/constrain_inputs.rs:18:31 @@ -28,7 +31,8 @@ error[E0581]: return type references an anonymous lifetime, which is not constra LL | fn execute(ty: Ty<'_>) -> &str { ty() } | ^^^^ | - = note: lifetimes appearing in an associated type are not considered constrained + = note: lifetimes appearing in an associated or opaque type are not considered constrained + = note: consider introducing a named lifetime parameter error[E0581]: return type references an anonymous lifetime, which is not constrained by the fn input types --> $DIR/constrain_inputs.rs:27:37 @@ -36,7 +40,8 @@ error[E0581]: return type references an anonymous lifetime, which is not constra LL | type BadFnSig = fn(Ty<&str>) -> &str; | ^^^^ | - = note: lifetimes appearing in an associated type are not considered constrained + = note: lifetimes appearing in an associated or opaque type are not considered constrained + = note: consider introducing a named lifetime parameter error[E0582]: binding for associated type `Output` references an anonymous lifetime, which does not appear in the trait input types --> $DIR/constrain_inputs.rs:29:44 @@ -44,7 +49,8 @@ error[E0582]: binding for associated type `Output` references an anonymous lifet LL | type BadTraitRef = dyn Fn(Ty<&str>) -> &str; | ^^^^ | - = note: lifetimes appearing in an associated type are not considered constrained + = note: lifetimes appearing in an associated or opaque type are not considered constrained + = note: consider introducing a named lifetime parameter error: aborting due to 6 previous errors From 060f3e0c657d7556e51a19a6290cca050b29dc57 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 4 Jul 2022 15:35:21 +0200 Subject: [PATCH 4324/5092] generalize: no need to cache errors --- compiler/rustc_infer/src/infer/combine.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index d4350aa5734d..644c92ed0e54 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -486,7 +486,7 @@ struct Generalizer<'cx, 'tcx> { param_env: ty::ParamEnv<'tcx>, - cache: SsoHashMap, RelateResult<'tcx, Ty<'tcx>>>, + cache: SsoHashMap, Ty<'tcx>>, } /// Result from a generalization operation. This includes @@ -593,8 +593,8 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { assert_eq!(t, t2); // we are abusing TypeRelation here; both LHS and RHS ought to be == - if let Some(result) = self.cache.get(&t) { - return result.clone(); + if let Some(&result) = self.cache.get(&t) { + return Ok(result); } debug!("generalize: t={:?}", t); @@ -664,10 +664,10 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { Ok(t) } _ => relate::super_relate_tys(self, t, t), - }; + }?; - self.cache.insert(t, result.clone()); - return result; + self.cache.insert(t, result); + Ok(result) } fn regions( From 01adb7e98d5656c06497f33dd2747df144e78356 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 4 Jul 2022 18:25:37 +0200 Subject: [PATCH 4325/5092] stop evaluating constants in `Relate` --- compiler/rustc_middle/src/ty/relate.rs | 4 --- .../src/traits/project.rs | 2 +- .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 9 ++--- src/test/ui/closures/issue-52437.rs | 1 - src/test/ui/closures/issue-52437.stderr | 13 ++----- src/test/ui/issues/issue-66706.rs | 3 -- src/test/ui/issues/issue-66706.stderr | 35 +++---------------- 7 files changed, 11 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 109a4df83b02..81476195d299 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -594,10 +594,6 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>( ); } - let eagerly_eval = |x: ty::Const<'tcx>| x.eval(tcx, relation.param_env()); - let a = eagerly_eval(a); - let b = eagerly_eval(b); - // Currently, the values that can be unified are primitive types, // and those that derive both `PartialEq` and `Eq`, corresponding // to structural-match types. diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 76c1ade0680c..1d9468a96b64 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -635,7 +635,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { #[instrument(skip(self), level = "debug")] fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> { - if self.selcx.tcx().lazy_normalization() || !self.eager_inference_replacement { + if self.selcx.tcx().lazy_normalization() { constant } else { let constant = constant.super_fold_with(self); diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index c59638f5d6f9..b07edd43c071 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -495,13 +495,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn to_const(&self, ast_c: &hir::AnonConst) -> ty::Const<'tcx> { let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id); + let span = self.tcx.hir().span(ast_c.hir_id); let c = ty::Const::from_anon_const(self.tcx, const_def_id); - self.register_wf_obligation( - c.into(), - self.tcx.hir().span(ast_c.hir_id), - ObligationCauseCode::WellFormed(None), - ); - c + self.register_wf_obligation(c.into(), span, ObligationCauseCode::WellFormed(None)); + self.normalize_associated_types_in(span, c) } pub fn const_arg_to_const( diff --git a/src/test/ui/closures/issue-52437.rs b/src/test/ui/closures/issue-52437.rs index f79a0bd35486..6ac5380a5aa2 100644 --- a/src/test/ui/closures/issue-52437.rs +++ b/src/test/ui/closures/issue-52437.rs @@ -2,5 +2,4 @@ fn main() { [(); &(&'static: loop { |x| {}; }) as *const _ as usize] //~^ ERROR: invalid label name `'static` //~| ERROR: type annotations needed - //~| ERROR mismatched types } diff --git a/src/test/ui/closures/issue-52437.stderr b/src/test/ui/closures/issue-52437.stderr index 38d9d08ce36a..4c24a54bbbe0 100644 --- a/src/test/ui/closures/issue-52437.stderr +++ b/src/test/ui/closures/issue-52437.stderr @@ -15,15 +15,6 @@ help: consider giving this closure parameter an explicit type LL | [(); &(&'static: loop { |x: _| {}; }) as *const _ as usize] | +++ -error[E0308]: mismatched types - --> $DIR/issue-52437.rs:2:5 - | -LL | fn main() { - | - expected `()` because of default return type -LL | [(); &(&'static: loop { |x| {}; }) as *const _ as usize] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found array `[(); _]` +error: aborting due to 2 previous errors -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0282, E0308. -For more information about an error, try `rustc --explain E0282`. +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/issues/issue-66706.rs b/src/test/ui/issues/issue-66706.rs index 4585bcc8cd57..835fdfae86c0 100644 --- a/src/test/ui/issues/issue-66706.rs +++ b/src/test/ui/issues/issue-66706.rs @@ -2,7 +2,6 @@ fn a() { [0; [|_: _ &_| ()].len()] //~^ ERROR expected `,`, found `&` //~| ERROR type annotations needed - //~| ERROR mismatched types } fn b() { @@ -13,13 +12,11 @@ fn b() { fn c() { [0; [|&_: _ &_| {}; 0 ].len()] //~^ ERROR expected `,`, found `&` - //~| ERROR mismatched types } fn d() { [0; match [|f @ &ref _| () ] {} ] //~^ ERROR expected identifier, found reserved identifier `_` - //~| ERROR mismatched types } fn main() {} diff --git a/src/test/ui/issues/issue-66706.stderr b/src/test/ui/issues/issue-66706.stderr index 1c55560cb7c7..8a30c0cad39c 100644 --- a/src/test/ui/issues/issue-66706.stderr +++ b/src/test/ui/issues/issue-66706.stderr @@ -7,13 +7,13 @@ LL | [0; [|_: _ &_| ()].len()] | help: missing `,` error: expected identifier, found reserved identifier `_` - --> $DIR/issue-66706.rs:9:20 + --> $DIR/issue-66706.rs:8:20 | LL | [0; [|f @ &ref _| {} ; 0 ].len() ]; | ^ expected identifier, found reserved identifier error: expected `,`, found `&` - --> $DIR/issue-66706.rs:14:17 + --> $DIR/issue-66706.rs:13:17 | LL | [0; [|&_: _ &_| {}; 0 ].len()] | -^ expected `,` @@ -21,7 +21,7 @@ LL | [0; [|&_: _ &_| {}; 0 ].len()] | help: missing `,` error: expected identifier, found reserved identifier `_` - --> $DIR/issue-66706.rs:20:26 + --> $DIR/issue-66706.rs:18:26 | LL | [0; match [|f @ &ref _| () ] {} ] | ^ expected identifier, found reserved identifier @@ -32,31 +32,6 @@ error[E0282]: type annotations needed LL | [0; [|_: _ &_| ()].len()] | ^ cannot infer type -error[E0308]: mismatched types - --> $DIR/issue-66706.rs:2:5 - | -LL | fn a() { - | - help: try adding a return type: `-> [i32; _]` -LL | [0; [|_: _ &_| ()].len()] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found array `[{integer}; _]` +error: aborting due to 5 previous errors -error[E0308]: mismatched types - --> $DIR/issue-66706.rs:14:5 - | -LL | fn c() { - | - help: try adding a return type: `-> [i32; _]` -LL | [0; [|&_: _ &_| {}; 0 ].len()] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found array `[{integer}; _]` - -error[E0308]: mismatched types - --> $DIR/issue-66706.rs:20:5 - | -LL | fn d() { - | - help: try adding a return type: `-> [i32; _]` -LL | [0; match [|f @ &ref _| () ] {} ] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found array `[{integer}; _]` - -error: aborting due to 8 previous errors - -Some errors have detailed explanations: E0282, E0308. -For more information about an error, try `rustc --explain E0282`. +For more information about this error, try `rustc --explain E0282`. From d15b00af487c356a426d08b333e64155ff386694 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 4 Jul 2022 18:38:35 +0200 Subject: [PATCH 4326/5092] don't evaluate with escaping bound vars --- compiler/rustc_infer/src/infer/combine.rs | 8 +--- compiler/rustc_middle/src/ty/consts/kind.rs | 1 + .../src/traits/project.rs | 48 +++++++++++++++++-- .../src/traits/query/normalize.rs | 19 ++++---- 4 files changed, 57 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 644c92ed0e54..c1fb59009d36 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -743,9 +743,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { } } } - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) - if self.tcx().lazy_normalization() => - { + ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => { assert_eq!(promoted, None); let substs = self.relate_with_variance( ty::Variance::Invariant, @@ -967,9 +965,7 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { } } } - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) - if self.tcx().lazy_normalization() => - { + ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => { assert_eq!(promoted, None); let substs = self.relate_with_variance( ty::Variance::Invariant, diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index 3840e79cebd8..ff20da65c016 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -180,6 +180,7 @@ impl<'tcx> ConstKind<'tcx> { param_env: ParamEnv<'tcx>, eval_mode: EvalMode, ) -> Option, ErrorGuaranteed>> { + assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}"); if let ConstKind::Unevaluated(unevaluated) = self { use crate::mir::interpret::ErrorHandled; diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 1d9468a96b64..8a093bf4281c 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -635,13 +635,18 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { #[instrument(skip(self), level = "debug")] fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> { - if self.selcx.tcx().lazy_normalization() { + let tcx = self.selcx.tcx(); + if tcx.lazy_normalization() { constant } else { let constant = constant.super_fold_with(self); - debug!(?constant); - debug!("self.param_env: {:?}", self.param_env); - constant.eval(self.selcx.tcx(), self.param_env) + debug!(?constant, ?self.param_env); + with_replaced_escaping_bound_vars( + self.selcx.infcx(), + &mut self.universes, + constant, + |constant| constant.eval(tcx, self.param_env), + ) } } @@ -671,6 +676,41 @@ pub struct BoundVarReplacer<'me, 'tcx> { universe_indices: &'me mut Vec>, } +/// Executes `f` on `value` after replacing all escaping bound variables with placeholders +/// and then replaces these placeholders with the original bound variables in the result. +/// +/// In most places, bound variables should be replaced right when entering a binder, making +/// this function unnecessary. However, normalization currently does not do that, so we have +/// to do this lazily. +/// +/// You should not add any additional uses of this function, at least not without first +/// discussing it with t-types. +/// +/// FIXME(@lcnr): We may even consider experimenting with eagerly replacing bound vars during +/// normalization as well, at which point this function will be unnecessary and can be removed. +pub fn with_replaced_escaping_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>, R: TypeFoldable<'tcx>>( + infcx: &'a InferCtxt<'a, 'tcx>, + universe_indices: &'a mut Vec>, + value: T, + f: impl FnOnce(T) -> R, +) -> R { + if value.has_escaping_bound_vars() { + let (value, mapped_regions, mapped_types, mapped_consts) = + BoundVarReplacer::replace_bound_vars(infcx, universe_indices, value); + let result = f(value); + PlaceholderReplacer::replace_placeholders( + infcx, + mapped_regions, + mapped_types, + mapped_consts, + universe_indices, + result, + ) + } else { + f(value) + } +} + impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> { /// Returns `Some` if we *were* able to replace bound vars. If there are any bound vars that /// use a binding level above `universe_indices.len()`, we fail. diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 61c556b726d6..f65fc5bad0d9 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -6,7 +6,7 @@ use crate::infer::at::At; use crate::infer::canonical::OriginalQueryValues; use crate::infer::{InferCtxt, InferOk}; use crate::traits::error_reporting::InferCtxtExt; -use crate::traits::project::needs_normalization; +use crate::traits::project::{needs_normalization, BoundVarReplacer, PlaceholderReplacer}; use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -283,11 +283,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { let tcx = self.infcx.tcx; let infcx = self.infcx; let (data, mapped_regions, mapped_types, mapped_consts) = - crate::traits::project::BoundVarReplacer::replace_bound_vars( - infcx, - &mut self.universes, - data, - ); + BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); let data = data.try_fold_with(self)?; let mut orig_values = OriginalQueryValues::default(); @@ -313,8 +309,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { debug!("QueryNormalizer: result = {:#?}", result); debug!("QueryNormalizer: obligations = {:#?}", obligations); self.obligations.extend(obligations); - - let res = crate::traits::project::PlaceholderReplacer::replace_placeholders( + let res = PlaceholderReplacer::replace_placeholders( infcx, mapped_regions, mapped_types, @@ -343,7 +338,13 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { constant: ty::Const<'tcx>, ) -> Result, Self::Error> { let constant = constant.try_super_fold_with(self)?; - Ok(constant.eval(self.infcx.tcx, self.param_env)) + debug!(?constant, ?self.param_env); + Ok(crate::traits::project::with_replaced_escaping_bound_vars( + self.infcx, + &mut self.universes, + constant, + |constant| constant.eval(self.infcx.tcx, self.param_env), + )) } fn try_fold_mir_const( From e6660326a31d4fcd0031562d83d9fd648fb28e56 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 4 Jul 2022 19:13:53 +0200 Subject: [PATCH 4327/5092] bound variables during ctfe are a bug --- compiler/rustc_const_eval/src/interpret/intrinsics.rs | 2 +- compiler/rustc_const_eval/src/interpret/operand.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 2f415a8c9c70..7dba5059307e 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -79,9 +79,9 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>( ty::Projection(_) | ty::Opaque(_, _) | ty::Param(_) - | ty::Bound(_, _) | ty::Placeholder(_) | ty::Infer(_) => throw_inval!(TooGeneric), + ty::Bound(_, _) => bug!("bound ty during ctfe"), ty::Bool | ty::Char | ty::Int(_) diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index ba041810bd19..f6c4f7dd1122 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -559,7 +559,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { layout: Option>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { match c.kind() { - ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric), + ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(..) => throw_inval!(TooGeneric), ty::ConstKind::Error(DelaySpanBugEmitted { reported, .. }) => { throw_inval!(AlreadyReported(reported)) } @@ -567,7 +567,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let instance = self.resolve(uv.def, uv.substs)?; Ok(self.eval_to_allocation(GlobalId { instance, promoted: uv.promoted })?.into()) } - ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => { + ty::ConstKind::Bound(..) | ty::ConstKind::Infer(..) => { span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", c) } ty::ConstKind::Value(valtree) => { From 0e497a714ebfefbee094b8475ea9aa4eeaa7b692 Mon Sep 17 00:00:00 2001 From: Luis Cardoso <61982523+LuisCardosoOliveira@users.noreply.github.com> Date: Thu, 8 Sep 2022 08:15:37 +0200 Subject: [PATCH 4328/5092] translations(rustc_session): migrates two diagnostics in session.rs --- .../locales/en-US/session.ftl | 6 ++++-- compiler/rustc_errors/src/diagnostic.rs | 5 ++++- compiler/rustc_session/src/errors.rs | 14 ++++++++++++++ compiler/rustc_session/src/session.rs | 18 ++++++++---------- 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/session.ftl b/compiler/rustc_error_messages/locales/en-US/session.ftl index a9ed8b4835b7..d2a2958f6243 100644 --- a/compiler/rustc_error_messages/locales/en-US/session.ftl +++ b/compiler/rustc_error_messages/locales/en-US/session.ftl @@ -15,8 +15,6 @@ session_feature_diagnostic_for_issue = session_feature_diagnostic_help = add `#![feature({$feature})]` to the crate attributes to enable -session_target_data_layout_parse_error = {$err} - session_not_circumvent_feature = `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine session_profile_use_file_does_not_exist = file `{$path}` passed to `-C profile-use` does not exist. @@ -54,3 +52,7 @@ session_target_inconsistent_architecture = inconsistent target specification: "d session_target_inconsistent_pointer_width = inconsistent target specification: "data-layout" claims pointers are {$pointer_size}-bit, while "target-pointer-width" is `{$target}` session_target_invalid_bits_size = {$err} + +session_target_stack_protector_not_supported = `-Z stack-protector={$stack_protector}` is not supported for target {$target_triple} and will be ignored + +session_split_debuginfo_unstable_platform = `-Csplit-debuginfo={$debuginfo}` is unstable on this platform diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index b88292b893ce..a774b52c8a59 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -10,7 +10,7 @@ use rustc_lint_defs::{Applicability, LintExpectationId}; use rustc_span::edition::LATEST_STABLE_EDITION; use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol}; use rustc_span::{edition::Edition, Span, DUMMY_SP}; -use rustc_target::spec::PanicStrategy; +use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple}; use std::borrow::Cow; use std::fmt; use std::hash::{Hash, Hasher}; @@ -93,6 +93,9 @@ into_diagnostic_arg_using_display!( Ident, MacroRulesNormalizedIdent, ParseIntError, + StackProtector, + &TargetTriple, + SplitDebuginfo ); impl IntoDiagnosticArg for bool { diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index a4e13e22ae22..3c93cfab183d 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -6,6 +6,7 @@ use rustc_errors::{fluent, DiagnosticBuilder, Handler, MultiSpan}; use rustc_macros::SessionDiagnostic; use rustc_span::{Span, Symbol}; use rustc_target::abi::TargetDataLayoutErrors; +use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple}; #[derive(SessionDiagnostic)] #[diag(session::incorrect_cgu_reuse_type)] @@ -156,3 +157,16 @@ pub struct UnstableVirtualFunctionElimination; pub struct UnsupportedDwarfVersion { pub dwarf_version: u32, } + +#[derive(SessionDiagnostic)] +#[diag(session::target_stack_protector_not_supported)] +pub struct StackProtectorNotSupportedForTarget<'a> { + pub stack_protector: StackProtector, + pub target_triple: &'a TargetTriple, +} + +#[derive(SessionDiagnostic)] +#[diag(session::split_debuginfo_unstable_platform)] +pub struct SplitDebugInfoUnstablePlatform { + pub debuginfo: SplitDebuginfo, +} diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 6add576cdff3..caf9d582ab09 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -5,8 +5,9 @@ use crate::config::{self, CrateType, InstrumentCoverage, OptLevel, OutputType, S use crate::errors::{ CannotEnableCrtStaticLinux, CannotMixAndMatchSanitizers, LinkerPluginToWindowsNotSupported, NotCircumventFeature, ProfileSampleUseFileDoesNotExist, ProfileUseFileDoesNotExist, - SanitizerCfiEnabled, SanitizerNotSupported, SanitizersNotSupported, TargetRequiresUnwindTables, - UnstableVirtualFunctionElimination, UnsupportedDwarfVersion, + SanitizerCfiEnabled, SanitizerNotSupported, SanitizersNotSupported, + SplitDebugInfoUnstablePlatform, StackProtectorNotSupportedForTarget, + TargetRequiresUnwindTables, UnstableVirtualFunctionElimination, UnsupportedDwarfVersion, }; use crate::parse::{add_feature_diagnostics, ParseSess}; use crate::search_paths::{PathKind, SearchPath}; @@ -1544,10 +1545,10 @@ fn validate_commandline_args_with_session_available(sess: &Session) { if sess.opts.unstable_opts.stack_protector != StackProtector::None { if !sess.target.options.supports_stack_protector { - sess.warn(&format!( - "`-Z stack-protector={}` is not supported for target {} and will be ignored", - sess.opts.unstable_opts.stack_protector, sess.opts.target_triple - )) + sess.emit_warning(StackProtectorNotSupportedForTarget { + stack_protector: sess.opts.unstable_opts.stack_protector, + target_triple: &sess.opts.target_triple, + }); } } @@ -1560,10 +1561,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) { if !sess.target.options.supported_split_debuginfo.contains(&sess.split_debuginfo()) && !sess.opts.unstable_opts.unstable_options { - sess.err(&format!( - "`-Csplit-debuginfo={}` is unstable on this platform", - sess.split_debuginfo() - )); + sess.emit_err(SplitDebugInfoUnstablePlatform { debuginfo: sess.split_debuginfo() }); } } From 28c62d28de27d44d9e9b5787b550fd6dc791f592 Mon Sep 17 00:00:00 2001 From: Yiming Lei Date: Wed, 31 Aug 2022 14:28:28 -0700 Subject: [PATCH 4329/5092] fix the suggestion of format for asm_sub_register modified: compiler/rustc_typeck/src/check/intrinsicck.rs modified: src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr modified: src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr modified: src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr modified: src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr modified: src/test/ui/asm/type-check-1.rs modified: src/test/ui/asm/type-check-1.stderr modified: src/test/ui/asm/x86_64/type-check-3.stderr --- .../rustc_typeck/src/check/intrinsicck.rs | 4 +- src/test/ui/asm/aarch64/type-check-3.stderr | 40 +++++++++---------- .../bad-template.aarch64_mirunsafeck.stderr | 4 +- .../bad-template.aarch64_thirunsafeck.stderr | 4 +- .../bad-template.x86_64_mirunsafeck.stderr | 4 +- .../bad-template.x86_64_thirunsafeck.stderr | 4 +- src/test/ui/asm/x86_64/type-check-3.stderr | 16 ++++---- 7 files changed, 38 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_typeck/src/check/intrinsicck.rs b/compiler/rustc_typeck/src/check/intrinsicck.rs index 721ebba65147..d8fe63dbf084 100644 --- a/compiler/rustc_typeck/src/check/intrinsicck.rs +++ b/compiler/rustc_typeck/src/check/intrinsicck.rs @@ -333,10 +333,10 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { let mut err = lint.build(msg); err.span_label(expr.span, "for this argument"); err.help(&format!( - "use the `{suggested_modifier}` modifier to have the register formatted as `{suggested_result}`", + "use `{{{idx}:{suggested_modifier}}}` to have the register formatted as `{suggested_result}`", )); err.help(&format!( - "or use the `{default_modifier}` modifier to keep the default formatting of `{default_result}`", + "or use `{{{idx}:{default_modifier}}}` to keep the default formatting of `{default_result}`", )); err.emit(); }, diff --git a/src/test/ui/asm/aarch64/type-check-3.stderr b/src/test/ui/asm/aarch64/type-check-3.stderr index b320abdc01b7..49292982eec7 100644 --- a/src/test/ui/asm/aarch64/type-check-3.stderr +++ b/src/test/ui/asm/aarch64/type-check-3.stderr @@ -5,8 +5,8 @@ LL | asm!("{}", in(reg) 0u8); | ^^ --- for this argument | = note: `#[warn(asm_sub_register)]` on by default - = help: use the `w` modifier to have the register formatted as `w0` - = help: or use the `x` modifier to keep the default formatting of `x0` + = help: use `{0:w}` to have the register formatted as `w0` + = help: or use `{0:x}` to keep the default formatting of `x0` warning: formatting may not be suitable for sub-register argument --> $DIR/type-check-3.rs:50:15 @@ -14,8 +14,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{}", in(reg) 0u16); | ^^ ---- for this argument | - = help: use the `w` modifier to have the register formatted as `w0` - = help: or use the `x` modifier to keep the default formatting of `x0` + = help: use `{0:w}` to have the register formatted as `w0` + = help: or use `{0:x}` to keep the default formatting of `x0` warning: formatting may not be suitable for sub-register argument --> $DIR/type-check-3.rs:52:15 @@ -23,8 +23,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{}", in(reg) 0i32); | ^^ ---- for this argument | - = help: use the `w` modifier to have the register formatted as `w0` - = help: or use the `x` modifier to keep the default formatting of `x0` + = help: use `{0:w}` to have the register formatted as `w0` + = help: or use `{0:x}` to keep the default formatting of `x0` warning: formatting may not be suitable for sub-register argument --> $DIR/type-check-3.rs:54:15 @@ -32,8 +32,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{}", in(reg) 0f32); | ^^ ---- for this argument | - = help: use the `w` modifier to have the register formatted as `w0` - = help: or use the `x` modifier to keep the default formatting of `x0` + = help: use `{0:w}` to have the register formatted as `w0` + = help: or use `{0:x}` to keep the default formatting of `x0` warning: formatting may not be suitable for sub-register argument --> $DIR/type-check-3.rs:57:15 @@ -41,8 +41,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{}", in(vreg) 0i16); | ^^ ---- for this argument | - = help: use the `h` modifier to have the register formatted as `h0` - = help: or use the `v` modifier to keep the default formatting of `v0` + = help: use `{0:h}` to have the register formatted as `h0` + = help: or use `{0:v}` to keep the default formatting of `v0` warning: formatting may not be suitable for sub-register argument --> $DIR/type-check-3.rs:59:15 @@ -50,8 +50,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{}", in(vreg) 0f32); | ^^ ---- for this argument | - = help: use the `s` modifier to have the register formatted as `s0` - = help: or use the `v` modifier to keep the default formatting of `v0` + = help: use `{0:s}` to have the register formatted as `s0` + = help: or use `{0:v}` to keep the default formatting of `v0` warning: formatting may not be suitable for sub-register argument --> $DIR/type-check-3.rs:61:15 @@ -59,8 +59,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{}", in(vreg) 0f64); | ^^ ---- for this argument | - = help: use the `d` modifier to have the register formatted as `d0` - = help: or use the `v` modifier to keep the default formatting of `v0` + = help: use `{0:d}` to have the register formatted as `d0` + = help: or use `{0:v}` to keep the default formatting of `v0` warning: formatting may not be suitable for sub-register argument --> $DIR/type-check-3.rs:63:15 @@ -68,8 +68,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{}", in(vreg_low16) 0f64); | ^^ ---- for this argument | - = help: use the `d` modifier to have the register formatted as `d0` - = help: or use the `v` modifier to keep the default formatting of `v0` + = help: use `{0:d}` to have the register formatted as `d0` + = help: or use `{0:v}` to keep the default formatting of `v0` warning: formatting may not be suitable for sub-register argument --> $DIR/type-check-3.rs:66:15 @@ -77,8 +77,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{0} {0}", in(reg) 0i16); | ^^^ ^^^ ---- for this argument | - = help: use the `w` modifier to have the register formatted as `w0` - = help: or use the `x` modifier to keep the default formatting of `x0` + = help: use `{0:w}` to have the register formatted as `w0` + = help: or use `{0:x}` to keep the default formatting of `x0` warning: formatting may not be suitable for sub-register argument --> $DIR/type-check-3.rs:68:15 @@ -86,8 +86,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{0} {0:x}", in(reg) 0i16); | ^^^ ---- for this argument | - = help: use the `w` modifier to have the register formatted as `w0` - = help: or use the `x` modifier to keep the default formatting of `x0` + = help: use `{0:w}` to have the register formatted as `w0` + = help: or use `{0:x}` to keep the default formatting of `x0` error: type `i128` cannot be used with this register class --> $DIR/type-check-3.rs:73:28 diff --git a/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr b/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr index 7ef93e15f5ba..5dac693cc274 100644 --- a/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr +++ b/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr @@ -190,8 +190,8 @@ LL | asm!("{:foo}", in(reg) foo); | ^^^^^^ --- for this argument | = note: `#[warn(asm_sub_register)]` on by default - = help: use the `w` modifier to have the register formatted as `w0` - = help: or use the `x` modifier to keep the default formatting of `x0` + = help: use `{0:w}` to have the register formatted as `w0` + = help: or use `{0:x}` to keep the default formatting of `x0` error: aborting due to 21 previous errors; 1 warning emitted diff --git a/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr b/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr index 7ef93e15f5ba..5dac693cc274 100644 --- a/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr +++ b/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr @@ -190,8 +190,8 @@ LL | asm!("{:foo}", in(reg) foo); | ^^^^^^ --- for this argument | = note: `#[warn(asm_sub_register)]` on by default - = help: use the `w` modifier to have the register formatted as `w0` - = help: or use the `x` modifier to keep the default formatting of `x0` + = help: use `{0:w}` to have the register formatted as `w0` + = help: or use `{0:x}` to keep the default formatting of `x0` error: aborting due to 21 previous errors; 1 warning emitted diff --git a/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr b/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr index 250bc3be42eb..b29b74bac80b 100644 --- a/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr +++ b/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr @@ -190,8 +190,8 @@ LL | asm!("{:foo}", in(reg) foo); | ^^^^^^ --- for this argument | = note: `#[warn(asm_sub_register)]` on by default - = help: use the `e` modifier to have the register formatted as `eax` - = help: or use the `r` modifier to keep the default formatting of `rax` + = help: use `{0:e}` to have the register formatted as `eax` + = help: or use `{0:r}` to keep the default formatting of `rax` error: aborting due to 21 previous errors; 1 warning emitted diff --git a/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr b/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr index 250bc3be42eb..b29b74bac80b 100644 --- a/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr +++ b/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr @@ -190,8 +190,8 @@ LL | asm!("{:foo}", in(reg) foo); | ^^^^^^ --- for this argument | = note: `#[warn(asm_sub_register)]` on by default - = help: use the `e` modifier to have the register formatted as `eax` - = help: or use the `r` modifier to keep the default formatting of `rax` + = help: use `{0:e}` to have the register formatted as `eax` + = help: or use `{0:r}` to keep the default formatting of `rax` error: aborting due to 21 previous errors; 1 warning emitted diff --git a/src/test/ui/asm/x86_64/type-check-3.stderr b/src/test/ui/asm/x86_64/type-check-3.stderr index b38ea8cc4d8e..366038fea234 100644 --- a/src/test/ui/asm/x86_64/type-check-3.stderr +++ b/src/test/ui/asm/x86_64/type-check-3.stderr @@ -45,8 +45,8 @@ LL | asm!("{0} {0}", in(reg) 0i16); | ^^^ ^^^ ---- for this argument | = note: `#[warn(asm_sub_register)]` on by default - = help: use the `x` modifier to have the register formatted as `ax` - = help: or use the `r` modifier to keep the default formatting of `rax` + = help: use `{0:x}` to have the register formatted as `ax` + = help: or use `{0:r}` to keep the default formatting of `rax` warning: formatting may not be suitable for sub-register argument --> $DIR/type-check-3.rs:36:15 @@ -54,8 +54,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{0} {0:x}", in(reg) 0i16); | ^^^ ---- for this argument | - = help: use the `x` modifier to have the register formatted as `ax` - = help: or use the `r` modifier to keep the default formatting of `rax` + = help: use `{0:x}` to have the register formatted as `ax` + = help: or use `{0:r}` to keep the default formatting of `rax` warning: formatting may not be suitable for sub-register argument --> $DIR/type-check-3.rs:38:15 @@ -63,8 +63,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{}", in(reg) 0i32); | ^^ ---- for this argument | - = help: use the `e` modifier to have the register formatted as `eax` - = help: or use the `r` modifier to keep the default formatting of `rax` + = help: use `{0:e}` to have the register formatted as `eax` + = help: or use `{0:r}` to keep the default formatting of `rax` warning: formatting may not be suitable for sub-register argument --> $DIR/type-check-3.rs:41:15 @@ -72,8 +72,8 @@ warning: formatting may not be suitable for sub-register argument LL | asm!("{}", in(ymm_reg) 0i64); | ^^ ---- for this argument | - = help: use the `x` modifier to have the register formatted as `xmm0` - = help: or use the `y` modifier to keep the default formatting of `ymm0` + = help: use `{0:x}` to have the register formatted as `xmm0` + = help: or use `{0:y}` to keep the default formatting of `ymm0` error: type `i8` cannot be used with this register class --> $DIR/type-check-3.rs:52:28 From b79a2b3f73f0710150a8ccc71b72e847d6c1c7c2 Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 8 Sep 2022 15:10:49 +0200 Subject: [PATCH 4330/5092] update `ParamKindOrd` --- compiler/rustc_ast/src/ast.rs | 36 ++----------------- .../rustc_ast_passes/src/ast_validation.rs | 4 +-- compiler/rustc_hir/src/hir.rs | 6 ++-- compiler/rustc_middle/src/ty/generics.rs | 5 +-- compiler/rustc_typeck/src/collect/type_of.rs | 4 +-- 5 files changed, 13 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index e38572f609b3..6c7670378fd4 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -33,7 +33,6 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; -use std::cmp::Ordering; use std::convert::TryFrom; use std::fmt; use std::mem; @@ -324,46 +323,17 @@ pub type GenericBounds = Vec; /// Specifies the enforced ordering for generic parameters. In the future, /// if we wanted to relax this order, we could override `PartialEq` and /// `PartialOrd`, to allow the kinds to be unordered. -#[derive(Hash, Clone, Copy)] +#[derive(Hash, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub enum ParamKindOrd { Lifetime, - Type, - Const, - // `Infer` is not actually constructed directly from the AST, but is implicitly constructed - // during HIR lowering, and `ParamKindOrd` will implicitly order inferred variables last. - Infer, + TypeOrConst, } -impl Ord for ParamKindOrd { - fn cmp(&self, other: &Self) -> Ordering { - use ParamKindOrd::*; - let to_int = |v| match v { - Lifetime => 0, - Infer | Type | Const => 1, - }; - - to_int(*self).cmp(&to_int(*other)) - } -} -impl PartialOrd for ParamKindOrd { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} -impl PartialEq for ParamKindOrd { - fn eq(&self, other: &Self) -> bool { - self.cmp(other) == Ordering::Equal - } -} -impl Eq for ParamKindOrd {} - impl fmt::Display for ParamKindOrd { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { ParamKindOrd::Lifetime => "lifetime".fmt(f), - ParamKindOrd::Type => "type".fmt(f), - ParamKindOrd::Const { .. } => "const".fmt(f), - ParamKindOrd::Infer => "infer".fmt(f), + ParamKindOrd::TypeOrConst => "type or const".fmt(f), } } } diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index d6d8881a53a1..26813f2c19c7 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -845,10 +845,10 @@ fn validate_generic_param_order( let (kind, bounds, span) = (¶m.kind, ¶m.bounds, ident.span); let (ord_kind, ident) = match ¶m.kind { GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident.to_string()), - GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident.to_string()), + GenericParamKind::Type { default: _ } => (ParamKindOrd::TypeOrConst, ident.to_string()), GenericParamKind::Const { ref ty, kw_span: _, default: _ } => { let ty = pprust::ty_to_string(ty); - (ParamKindOrd::Const, format!("const {}: {}", ident, ty)) + (ParamKindOrd::TypeOrConst, format!("const {}: {}", ident, ty)) } }; param_idents.push((kind, ord_kind, bounds, idx, ident)); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index a668c0e95ce4..ce60bab9e027 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -300,9 +300,9 @@ impl GenericArg<'_> { pub fn to_ord(&self) -> ast::ParamKindOrd { match self { GenericArg::Lifetime(_) => ast::ParamKindOrd::Lifetime, - GenericArg::Type(_) => ast::ParamKindOrd::Type, - GenericArg::Const(_) => ast::ParamKindOrd::Const, - GenericArg::Infer(_) => ast::ParamKindOrd::Infer, + GenericArg::Type(_) | GenericArg::Const(_) | GenericArg::Infer(_) => { + ast::ParamKindOrd::TypeOrConst + } } } diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 8631ee91fa45..0c8bdde9c8bc 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -27,8 +27,9 @@ impl GenericParamDefKind { pub fn to_ord(&self) -> ast::ParamKindOrd { match self { GenericParamDefKind::Lifetime => ast::ParamKindOrd::Lifetime, - GenericParamDefKind::Type { .. } => ast::ParamKindOrd::Type, - GenericParamDefKind::Const { .. } => ast::ParamKindOrd::Const, + GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { + ast::ParamKindOrd::TypeOrConst + } } } diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index a0280ddca4bd..dd894dc709bd 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -65,8 +65,8 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< let ty = item_ctxt.ast_ty_to_ty(hir_ty); // Iterate through the generics of the projection to find the one that corresponds to - // the def_id that this query was called with. We filter to only const args here as a - // precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't + // the def_id that this query was called with. We filter to only type and const args here + // as a precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't // but it can't hurt to be safe ^^ if let ty::Projection(projection) = ty.kind() { let generics = tcx.generics_of(projection.item_def_id); From dcf30047defdc946578709f1cb26d9b73a18be22 Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 8 Sep 2022 15:53:22 +0200 Subject: [PATCH 4331/5092] update ui tests --- src/test/ui/const-generics/argument_order.stderr | 4 ++-- .../ui/const-generics/const-param-before-other-params.rs | 2 +- .../const-generics/const-param-before-other-params.stderr | 2 +- .../ui/const-generics/defaults/intermixed-lifetime.rs | 4 ++-- .../ui/const-generics/defaults/intermixed-lifetime.stderr | 4 ++-- .../defaults/param-order-err-pretty-prints-default.rs | 2 +- .../defaults/param-order-err-pretty-prints-default.stderr | 2 +- src/test/ui/generics/issue-59508-1.rs | 2 +- src/test/ui/generics/issue-59508-1.stderr | 2 +- src/test/ui/generics/issue-59508.fixed | 2 +- src/test/ui/generics/issue-59508.rs | 2 +- src/test/ui/generics/issue-59508.stderr | 2 +- .../issue-80512-param-reordering-with-defaults.rs | 2 +- .../issue-80512-param-reordering-with-defaults.stderr | 2 +- src/test/ui/generics/lifetime-before-type-params.rs | 8 ++++---- src/test/ui/generics/lifetime-before-type-params.stderr | 8 ++++---- src/test/ui/parser/issues/issue-14303-enum.rs | 2 +- src/test/ui/parser/issues/issue-14303-enum.stderr | 2 +- src/test/ui/parser/issues/issue-14303-fn-def.rs | 2 +- src/test/ui/parser/issues/issue-14303-fn-def.stderr | 2 +- src/test/ui/parser/issues/issue-14303-impl.rs | 2 +- src/test/ui/parser/issues/issue-14303-impl.stderr | 2 +- src/test/ui/parser/issues/issue-14303-struct.rs | 2 +- src/test/ui/parser/issues/issue-14303-struct.stderr | 2 +- src/test/ui/parser/issues/issue-14303-trait.rs | 2 +- src/test/ui/parser/issues/issue-14303-trait.stderr | 2 +- src/test/ui/suggestions/suggest-move-lifetimes.stderr | 8 ++++---- src/test/ui/suggestions/suggest-move-types.stderr | 4 ++-- 28 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/test/ui/const-generics/argument_order.stderr b/src/test/ui/const-generics/argument_order.stderr index 6b33dffb434e..a3a54b497a76 100644 --- a/src/test/ui/const-generics/argument_order.stderr +++ b/src/test/ui/const-generics/argument_order.stderr @@ -1,4 +1,4 @@ -error: lifetime parameters must be declared prior to const parameters +error: lifetime parameters must be declared prior to type or const parameters --> $DIR/argument_order.rs:6:32 | LL | struct AlsoBad { @@ -11,7 +11,7 @@ LL | let _: AlsoBad<7, 'static, u32, 'static, 17, u16>; | ^^^^^^^ | = note: lifetime arguments must be provided before type arguments - = help: reorder the arguments: lifetimes, then consts: `<'a, 'b, N, T, M, U>` + = help: reorder the arguments: lifetimes, then type or consts: `<'a, 'b, N, T, M, U>` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/const-param-before-other-params.rs b/src/test/ui/const-generics/const-param-before-other-params.rs index da06aca308e1..b481000bb7f5 100644 --- a/src/test/ui/const-generics/const-param-before-other-params.rs +++ b/src/test/ui/const-generics/const-param-before-other-params.rs @@ -1,5 +1,5 @@ fn bar(_: &'a ()) { - //~^ ERROR lifetime parameters must be declared prior to const parameters + //~^ ERROR lifetime parameters must be declared prior to type or const parameters } fn foo(_: &T) {} diff --git a/src/test/ui/const-generics/const-param-before-other-params.stderr b/src/test/ui/const-generics/const-param-before-other-params.stderr index 607d20c4a25f..049c58ba4fae 100644 --- a/src/test/ui/const-generics/const-param-before-other-params.stderr +++ b/src/test/ui/const-generics/const-param-before-other-params.stderr @@ -1,4 +1,4 @@ -error: lifetime parameters must be declared prior to const parameters +error: lifetime parameters must be declared prior to type or const parameters --> $DIR/const-param-before-other-params.rs:1:21 | LL | fn bar(_: &'a ()) { diff --git a/src/test/ui/const-generics/defaults/intermixed-lifetime.rs b/src/test/ui/const-generics/defaults/intermixed-lifetime.rs index 578938db4c43..9e4a32121bb3 100644 --- a/src/test/ui/const-generics/defaults/intermixed-lifetime.rs +++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.rs @@ -1,9 +1,9 @@ // Checks that lifetimes cannot be interspersed between consts and types. struct Foo(&'a (), T); -//~^ Error lifetime parameters must be declared prior to const parameters +//~^ ERROR lifetime parameters must be declared prior to type or const parameters struct Bar(&'a (), T); -//~^ Error lifetime parameters must be declared prior to type parameters +//~^ ERROR lifetime parameters must be declared prior to type or const parameters fn main() {} diff --git a/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr b/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr index e27976deb2b5..b8aa18c942bc 100644 --- a/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr +++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr @@ -1,10 +1,10 @@ -error: lifetime parameters must be declared prior to const parameters +error: lifetime parameters must be declared prior to type or const parameters --> $DIR/intermixed-lifetime.rs:3:28 | LL | struct Foo(&'a (), T); | -----------------^^---------- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T = u32>` -error: lifetime parameters must be declared prior to type parameters +error: lifetime parameters must be declared prior to type or const parameters --> $DIR/intermixed-lifetime.rs:6:37 | LL | struct Bar(&'a (), T); diff --git a/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.rs b/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.rs index da087ffc3c4a..ae897e59a974 100644 --- a/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.rs +++ b/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.rs @@ -1,4 +1,4 @@ struct Foo(&'a u32); -//~^ Error lifetime parameters must be declared prior to const parameters +//~^ ERROR lifetime parameters must be declared prior to type or const parameters fn main() {} diff --git a/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.stderr b/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.stderr index 55f5a5353853..b4bfc5410390 100644 --- a/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.stderr +++ b/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.stderr @@ -1,4 +1,4 @@ -error: lifetime parameters must be declared prior to const parameters +error: lifetime parameters must be declared prior to type or const parameters --> $DIR/param-order-err-pretty-prints-default.rs:1:33 | LL | struct Foo(&'a u32); diff --git a/src/test/ui/generics/issue-59508-1.rs b/src/test/ui/generics/issue-59508-1.rs index 7e1dd7707044..646ece33ca34 100644 --- a/src/test/ui/generics/issue-59508-1.rs +++ b/src/test/ui/generics/issue-59508-1.rs @@ -8,7 +8,7 @@ struct A; impl A { pub fn do_things() { - //~^ ERROR lifetime parameters must be declared prior to type parameters + //~^ ERROR lifetime parameters must be declared prior to type or const parameters println!("panic"); } } diff --git a/src/test/ui/generics/issue-59508-1.stderr b/src/test/ui/generics/issue-59508-1.stderr index d162365ea4bf..1ca99c6ab76c 100644 --- a/src/test/ui/generics/issue-59508-1.stderr +++ b/src/test/ui/generics/issue-59508-1.stderr @@ -1,4 +1,4 @@ -error: lifetime parameters must be declared prior to type parameters +error: lifetime parameters must be declared prior to type or const parameters --> $DIR/issue-59508-1.rs:10:25 | LL | pub fn do_things() { diff --git a/src/test/ui/generics/issue-59508.fixed b/src/test/ui/generics/issue-59508.fixed index b5c60a1626f5..557bcc1f716c 100644 --- a/src/test/ui/generics/issue-59508.fixed +++ b/src/test/ui/generics/issue-59508.fixed @@ -8,7 +8,7 @@ struct A; impl A { pub fn do_things<'a, 'b: 'a, T>() { - //~^ ERROR lifetime parameters must be declared prior to type parameters + //~^ ERROR lifetime parameters must be declared prior to type or const parameters println!("panic"); } } diff --git a/src/test/ui/generics/issue-59508.rs b/src/test/ui/generics/issue-59508.rs index 0b39c5d8f2ae..0b290a6085f9 100644 --- a/src/test/ui/generics/issue-59508.rs +++ b/src/test/ui/generics/issue-59508.rs @@ -8,7 +8,7 @@ struct A; impl A { pub fn do_things() { - //~^ ERROR lifetime parameters must be declared prior to type parameters + //~^ ERROR lifetime parameters must be declared prior to type or const parameters println!("panic"); } } diff --git a/src/test/ui/generics/issue-59508.stderr b/src/test/ui/generics/issue-59508.stderr index c52ae4182b86..e8926c13a113 100644 --- a/src/test/ui/generics/issue-59508.stderr +++ b/src/test/ui/generics/issue-59508.stderr @@ -1,4 +1,4 @@ -error: lifetime parameters must be declared prior to type parameters +error: lifetime parameters must be declared prior to type or const parameters --> $DIR/issue-59508.rs:10:25 | LL | pub fn do_things() { diff --git a/src/test/ui/generics/issue-80512-param-reordering-with-defaults.rs b/src/test/ui/generics/issue-80512-param-reordering-with-defaults.rs index fe3e4fbc7e0b..598f95d9a0ba 100644 --- a/src/test/ui/generics/issue-80512-param-reordering-with-defaults.rs +++ b/src/test/ui/generics/issue-80512-param-reordering-with-defaults.rs @@ -1,4 +1,4 @@ #![crate_type = "lib"] struct S(&'a T); -//~^ ERROR lifetime parameters must be declared prior to type parameters +//~^ ERROR lifetime parameters must be declared prior to type or const parameters diff --git a/src/test/ui/generics/issue-80512-param-reordering-with-defaults.stderr b/src/test/ui/generics/issue-80512-param-reordering-with-defaults.stderr index 119b1a0d2070..69680a801019 100644 --- a/src/test/ui/generics/issue-80512-param-reordering-with-defaults.stderr +++ b/src/test/ui/generics/issue-80512-param-reordering-with-defaults.stderr @@ -1,4 +1,4 @@ -error: lifetime parameters must be declared prior to type parameters +error: lifetime parameters must be declared prior to type or const parameters --> $DIR/issue-80512-param-reordering-with-defaults.rs:3:18 | LL | struct S(&'a T); diff --git a/src/test/ui/generics/lifetime-before-type-params.rs b/src/test/ui/generics/lifetime-before-type-params.rs index 5a71d6efeda6..4904ae61caaf 100644 --- a/src/test/ui/generics/lifetime-before-type-params.rs +++ b/src/test/ui/generics/lifetime-before-type-params.rs @@ -1,11 +1,11 @@ #![allow(unused)] fn first() {} -//~^ ERROR lifetime parameters must be declared prior to type parameters +//~^ ERROR lifetime parameters must be declared prior to type or const parameters fn second<'a, T, 'b>() {} -//~^ ERROR lifetime parameters must be declared prior to type parameters +//~^ ERROR lifetime parameters must be declared prior to type or const parameters fn third() {} -//~^ ERROR lifetime parameters must be declared prior to type parameters +//~^ ERROR lifetime parameters must be declared prior to type or const parameters fn fourth<'a, T, 'b, U, 'c, V>() {} -//~^ ERROR lifetime parameters must be declared prior to type parameters +//~^ ERROR lifetime parameters must be declared prior to type or const parameters fn main() {} diff --git a/src/test/ui/generics/lifetime-before-type-params.stderr b/src/test/ui/generics/lifetime-before-type-params.stderr index 62d95e45329f..7bb4f826409b 100644 --- a/src/test/ui/generics/lifetime-before-type-params.stderr +++ b/src/test/ui/generics/lifetime-before-type-params.stderr @@ -1,22 +1,22 @@ -error: lifetime parameters must be declared prior to type parameters +error: lifetime parameters must be declared prior to type or const parameters --> $DIR/lifetime-before-type-params.rs:2:13 | LL | fn first() {} | ----^^--^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>` -error: lifetime parameters must be declared prior to type parameters +error: lifetime parameters must be declared prior to type or const parameters --> $DIR/lifetime-before-type-params.rs:4:18 | LL | fn second<'a, T, 'b>() {} | --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>` -error: lifetime parameters must be declared prior to type parameters +error: lifetime parameters must be declared prior to type or const parameters --> $DIR/lifetime-before-type-params.rs:6:16 | LL | fn third() {} | -------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, T, U>` -error: lifetime parameters must be declared prior to type parameters +error: lifetime parameters must be declared prior to type or const parameters --> $DIR/lifetime-before-type-params.rs:8:18 | LL | fn fourth<'a, T, 'b, U, 'c, V>() {} diff --git a/src/test/ui/parser/issues/issue-14303-enum.rs b/src/test/ui/parser/issues/issue-14303-enum.rs index a6106159805b..c5f510da8932 100644 --- a/src/test/ui/parser/issues/issue-14303-enum.rs +++ b/src/test/ui/parser/issues/issue-14303-enum.rs @@ -1,5 +1,5 @@ enum X<'a, T, 'b> { -//~^ ERROR lifetime parameters must be declared prior to type parameters +//~^ ERROR lifetime parameters must be declared prior to type or const parameters A(&'a &'b T) } diff --git a/src/test/ui/parser/issues/issue-14303-enum.stderr b/src/test/ui/parser/issues/issue-14303-enum.stderr index 55cef4cabacf..6bb7b623a4e3 100644 --- a/src/test/ui/parser/issues/issue-14303-enum.stderr +++ b/src/test/ui/parser/issues/issue-14303-enum.stderr @@ -1,4 +1,4 @@ -error: lifetime parameters must be declared prior to type parameters +error: lifetime parameters must be declared prior to type or const parameters --> $DIR/issue-14303-enum.rs:1:15 | LL | enum X<'a, T, 'b> { diff --git a/src/test/ui/parser/issues/issue-14303-fn-def.rs b/src/test/ui/parser/issues/issue-14303-fn-def.rs index 221bd311e747..558efe488abc 100644 --- a/src/test/ui/parser/issues/issue-14303-fn-def.rs +++ b/src/test/ui/parser/issues/issue-14303-fn-def.rs @@ -1,4 +1,4 @@ fn foo<'a, T, 'b>(x: &'a T) {} -//~^ ERROR lifetime parameters must be declared prior to type parameters +//~^ ERROR lifetime parameters must be declared prior to type or const parameters fn main() {} diff --git a/src/test/ui/parser/issues/issue-14303-fn-def.stderr b/src/test/ui/parser/issues/issue-14303-fn-def.stderr index bacc922969d9..87f9e446c279 100644 --- a/src/test/ui/parser/issues/issue-14303-fn-def.stderr +++ b/src/test/ui/parser/issues/issue-14303-fn-def.stderr @@ -1,4 +1,4 @@ -error: lifetime parameters must be declared prior to type parameters +error: lifetime parameters must be declared prior to type or const parameters --> $DIR/issue-14303-fn-def.rs:1:15 | LL | fn foo<'a, T, 'b>(x: &'a T) {} diff --git a/src/test/ui/parser/issues/issue-14303-impl.rs b/src/test/ui/parser/issues/issue-14303-impl.rs index 4dc2c6660180..0e86ae482331 100644 --- a/src/test/ui/parser/issues/issue-14303-impl.rs +++ b/src/test/ui/parser/issues/issue-14303-impl.rs @@ -1,6 +1,6 @@ struct X(T); impl<'a, T, 'b> X {} -//~^ ERROR lifetime parameters must be declared prior to type parameters +//~^ ERROR lifetime parameters must be declared prior to type or const parameters fn main() {} diff --git a/src/test/ui/parser/issues/issue-14303-impl.stderr b/src/test/ui/parser/issues/issue-14303-impl.stderr index d6be02f70fd2..f2117d626fdf 100644 --- a/src/test/ui/parser/issues/issue-14303-impl.stderr +++ b/src/test/ui/parser/issues/issue-14303-impl.stderr @@ -1,4 +1,4 @@ -error: lifetime parameters must be declared prior to type parameters +error: lifetime parameters must be declared prior to type or const parameters --> $DIR/issue-14303-impl.rs:3:13 | LL | impl<'a, T, 'b> X {} diff --git a/src/test/ui/parser/issues/issue-14303-struct.rs b/src/test/ui/parser/issues/issue-14303-struct.rs index 0bd10b4d0851..ea5e3317ddde 100644 --- a/src/test/ui/parser/issues/issue-14303-struct.rs +++ b/src/test/ui/parser/issues/issue-14303-struct.rs @@ -1,5 +1,5 @@ struct X<'a, T, 'b> { -//~^ ERROR lifetime parameters must be declared prior to type parameters +//~^ ERROR lifetime parameters must be declared prior to type or const parameters x: &'a &'b T } diff --git a/src/test/ui/parser/issues/issue-14303-struct.stderr b/src/test/ui/parser/issues/issue-14303-struct.stderr index fa62a39f2416..2dcbeffefebc 100644 --- a/src/test/ui/parser/issues/issue-14303-struct.stderr +++ b/src/test/ui/parser/issues/issue-14303-struct.stderr @@ -1,4 +1,4 @@ -error: lifetime parameters must be declared prior to type parameters +error: lifetime parameters must be declared prior to type or const parameters --> $DIR/issue-14303-struct.rs:1:17 | LL | struct X<'a, T, 'b> { diff --git a/src/test/ui/parser/issues/issue-14303-trait.rs b/src/test/ui/parser/issues/issue-14303-trait.rs index f253de92d92d..a736ffdfa151 100644 --- a/src/test/ui/parser/issues/issue-14303-trait.rs +++ b/src/test/ui/parser/issues/issue-14303-trait.rs @@ -1,4 +1,4 @@ trait Foo<'a, T, 'b> {} -//~^ ERROR lifetime parameters must be declared prior to type parameters +//~^ ERROR lifetime parameters must be declared prior to type or const parameters fn main() {} diff --git a/src/test/ui/parser/issues/issue-14303-trait.stderr b/src/test/ui/parser/issues/issue-14303-trait.stderr index 75cd67a9ded8..ddaa7b12c2fc 100644 --- a/src/test/ui/parser/issues/issue-14303-trait.stderr +++ b/src/test/ui/parser/issues/issue-14303-trait.stderr @@ -1,4 +1,4 @@ -error: lifetime parameters must be declared prior to type parameters +error: lifetime parameters must be declared prior to type or const parameters --> $DIR/issue-14303-trait.rs:1:18 | LL | trait Foo<'a, T, 'b> {} diff --git a/src/test/ui/suggestions/suggest-move-lifetimes.stderr b/src/test/ui/suggestions/suggest-move-lifetimes.stderr index f52631caed17..f7ff3697e1da 100644 --- a/src/test/ui/suggestions/suggest-move-lifetimes.stderr +++ b/src/test/ui/suggestions/suggest-move-lifetimes.stderr @@ -1,22 +1,22 @@ -error: lifetime parameters must be declared prior to type parameters +error: lifetime parameters must be declared prior to type or const parameters --> $DIR/suggest-move-lifetimes.rs:1:13 | LL | struct A { | ----^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, T>` -error: lifetime parameters must be declared prior to type parameters +error: lifetime parameters must be declared prior to type or const parameters --> $DIR/suggest-move-lifetimes.rs:5:13 | LL | struct B { | ----^^---- help: reorder the parameters: lifetimes, then consts and types: `<'a, T, U>` -error: lifetime parameters must be declared prior to type parameters +error: lifetime parameters must be declared prior to type or const parameters --> $DIR/suggest-move-lifetimes.rs:10:16 | LL | struct C { | -------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, T, U>` -error: lifetime parameters must be declared prior to type parameters +error: lifetime parameters must be declared prior to type or const parameters --> $DIR/suggest-move-lifetimes.rs:15:16 | LL | struct D { diff --git a/src/test/ui/suggestions/suggest-move-types.stderr b/src/test/ui/suggestions/suggest-move-types.stderr index 1a6032db0010..3037b7f92ed6 100644 --- a/src/test/ui/suggestions/suggest-move-types.stderr +++ b/src/test/ui/suggestions/suggest-move-types.stderr @@ -121,7 +121,7 @@ LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime` + = help: reorder the arguments: lifetimes, then type or consts: `<'a, 'b, 'c, T, U, V>` error[E0747]: lifetime provided when a type was expected --> $DIR/suggest-move-types.rs:82:56 @@ -130,7 +130,7 @@ LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime` + = help: reorder the arguments: lifetimes, then type or consts: `<'a, 'b, 'c, T, U, V>` error: aborting due to 12 previous errors From 4c75b32e9965acae7e9f7efa20fc505b1ca7a2a0 Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 8 Sep 2022 15:56:32 +0200 Subject: [PATCH 4332/5092] merge tests --- src/test/ui/parser/issues/issue-14303-enum.rs | 6 --- .../ui/parser/issues/issue-14303-enum.stderr | 8 ---- .../ui/parser/issues/issue-14303-fn-def.rs | 4 -- .../parser/issues/issue-14303-fn-def.stderr | 8 ---- src/test/ui/parser/issues/issue-14303-impl.rs | 6 --- .../ui/parser/issues/issue-14303-impl.stderr | 8 ---- src/test/ui/parser/issues/issue-14303-path.rs | 13 ------- .../ui/parser/issues/issue-14303-path.stderr | 9 ----- .../ui/parser/issues/issue-14303-struct.rs | 6 --- .../parser/issues/issue-14303-struct.stderr | 8 ---- .../ui/parser/issues/issue-14303-trait.rs | 4 -- .../ui/parser/issues/issue-14303-trait.stderr | 8 ---- src/test/ui/parser/issues/issue-14303.rs | 33 ++++++++++++++++ src/test/ui/parser/issues/issue-14303.stderr | 39 +++++++++++++++++++ 14 files changed, 72 insertions(+), 88 deletions(-) delete mode 100644 src/test/ui/parser/issues/issue-14303-enum.rs delete mode 100644 src/test/ui/parser/issues/issue-14303-enum.stderr delete mode 100644 src/test/ui/parser/issues/issue-14303-fn-def.rs delete mode 100644 src/test/ui/parser/issues/issue-14303-fn-def.stderr delete mode 100644 src/test/ui/parser/issues/issue-14303-impl.rs delete mode 100644 src/test/ui/parser/issues/issue-14303-impl.stderr delete mode 100644 src/test/ui/parser/issues/issue-14303-path.rs delete mode 100644 src/test/ui/parser/issues/issue-14303-path.stderr delete mode 100644 src/test/ui/parser/issues/issue-14303-struct.rs delete mode 100644 src/test/ui/parser/issues/issue-14303-struct.stderr delete mode 100644 src/test/ui/parser/issues/issue-14303-trait.rs delete mode 100644 src/test/ui/parser/issues/issue-14303-trait.stderr create mode 100644 src/test/ui/parser/issues/issue-14303.rs create mode 100644 src/test/ui/parser/issues/issue-14303.stderr diff --git a/src/test/ui/parser/issues/issue-14303-enum.rs b/src/test/ui/parser/issues/issue-14303-enum.rs deleted file mode 100644 index c5f510da8932..000000000000 --- a/src/test/ui/parser/issues/issue-14303-enum.rs +++ /dev/null @@ -1,6 +0,0 @@ -enum X<'a, T, 'b> { -//~^ ERROR lifetime parameters must be declared prior to type or const parameters - A(&'a &'b T) -} - -fn main() {} diff --git a/src/test/ui/parser/issues/issue-14303-enum.stderr b/src/test/ui/parser/issues/issue-14303-enum.stderr deleted file mode 100644 index 6bb7b623a4e3..000000000000 --- a/src/test/ui/parser/issues/issue-14303-enum.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: lifetime parameters must be declared prior to type or const parameters - --> $DIR/issue-14303-enum.rs:1:15 - | -LL | enum X<'a, T, 'b> { - | --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>` - -error: aborting due to previous error - diff --git a/src/test/ui/parser/issues/issue-14303-fn-def.rs b/src/test/ui/parser/issues/issue-14303-fn-def.rs deleted file mode 100644 index 558efe488abc..000000000000 --- a/src/test/ui/parser/issues/issue-14303-fn-def.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn foo<'a, T, 'b>(x: &'a T) {} -//~^ ERROR lifetime parameters must be declared prior to type or const parameters - -fn main() {} diff --git a/src/test/ui/parser/issues/issue-14303-fn-def.stderr b/src/test/ui/parser/issues/issue-14303-fn-def.stderr deleted file mode 100644 index 87f9e446c279..000000000000 --- a/src/test/ui/parser/issues/issue-14303-fn-def.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: lifetime parameters must be declared prior to type or const parameters - --> $DIR/issue-14303-fn-def.rs:1:15 - | -LL | fn foo<'a, T, 'b>(x: &'a T) {} - | --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>` - -error: aborting due to previous error - diff --git a/src/test/ui/parser/issues/issue-14303-impl.rs b/src/test/ui/parser/issues/issue-14303-impl.rs deleted file mode 100644 index 0e86ae482331..000000000000 --- a/src/test/ui/parser/issues/issue-14303-impl.rs +++ /dev/null @@ -1,6 +0,0 @@ -struct X(T); - -impl<'a, T, 'b> X {} -//~^ ERROR lifetime parameters must be declared prior to type or const parameters - -fn main() {} diff --git a/src/test/ui/parser/issues/issue-14303-impl.stderr b/src/test/ui/parser/issues/issue-14303-impl.stderr deleted file mode 100644 index f2117d626fdf..000000000000 --- a/src/test/ui/parser/issues/issue-14303-impl.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: lifetime parameters must be declared prior to type or const parameters - --> $DIR/issue-14303-impl.rs:3:13 - | -LL | impl<'a, T, 'b> X {} - | --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>` - -error: aborting due to previous error - diff --git a/src/test/ui/parser/issues/issue-14303-path.rs b/src/test/ui/parser/issues/issue-14303-path.rs deleted file mode 100644 index 89ef914aba23..000000000000 --- a/src/test/ui/parser/issues/issue-14303-path.rs +++ /dev/null @@ -1,13 +0,0 @@ -mod foo { - pub struct X<'a, 'b, 'c, T> { - a: &'a str, - b: &'b str, - c: &'c str, - t: T, - } -} - -fn bar<'a, 'b, 'c, T>(x: foo::X<'a, T, 'b, 'c>) {} -//~^ ERROR type provided when a lifetime was expected - -fn main() {} diff --git a/src/test/ui/parser/issues/issue-14303-path.stderr b/src/test/ui/parser/issues/issue-14303-path.stderr deleted file mode 100644 index 841e63ecbe9d..000000000000 --- a/src/test/ui/parser/issues/issue-14303-path.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0747]: type provided when a lifetime was expected - --> $DIR/issue-14303-path.rs:10:37 - | -LL | fn bar<'a, 'b, 'c, T>(x: foo::X<'a, T, 'b, 'c>) {} - | ^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0747`. diff --git a/src/test/ui/parser/issues/issue-14303-struct.rs b/src/test/ui/parser/issues/issue-14303-struct.rs deleted file mode 100644 index ea5e3317ddde..000000000000 --- a/src/test/ui/parser/issues/issue-14303-struct.rs +++ /dev/null @@ -1,6 +0,0 @@ -struct X<'a, T, 'b> { -//~^ ERROR lifetime parameters must be declared prior to type or const parameters - x: &'a &'b T -} - -fn main() {} diff --git a/src/test/ui/parser/issues/issue-14303-struct.stderr b/src/test/ui/parser/issues/issue-14303-struct.stderr deleted file mode 100644 index 2dcbeffefebc..000000000000 --- a/src/test/ui/parser/issues/issue-14303-struct.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: lifetime parameters must be declared prior to type or const parameters - --> $DIR/issue-14303-struct.rs:1:17 - | -LL | struct X<'a, T, 'b> { - | --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>` - -error: aborting due to previous error - diff --git a/src/test/ui/parser/issues/issue-14303-trait.rs b/src/test/ui/parser/issues/issue-14303-trait.rs deleted file mode 100644 index a736ffdfa151..000000000000 --- a/src/test/ui/parser/issues/issue-14303-trait.rs +++ /dev/null @@ -1,4 +0,0 @@ -trait Foo<'a, T, 'b> {} -//~^ ERROR lifetime parameters must be declared prior to type or const parameters - -fn main() {} diff --git a/src/test/ui/parser/issues/issue-14303-trait.stderr b/src/test/ui/parser/issues/issue-14303-trait.stderr deleted file mode 100644 index ddaa7b12c2fc..000000000000 --- a/src/test/ui/parser/issues/issue-14303-trait.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: lifetime parameters must be declared prior to type or const parameters - --> $DIR/issue-14303-trait.rs:1:18 - | -LL | trait Foo<'a, T, 'b> {} - | --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>` - -error: aborting due to previous error - diff --git a/src/test/ui/parser/issues/issue-14303.rs b/src/test/ui/parser/issues/issue-14303.rs new file mode 100644 index 000000000000..e44b57746605 --- /dev/null +++ b/src/test/ui/parser/issues/issue-14303.rs @@ -0,0 +1,33 @@ +enum Enum<'a, T, 'b> { +//~^ ERROR lifetime parameters must be declared prior to type or const parameters + A(&'a &'b T) +} + +struct Struct<'a, T, 'b> { +//~^ ERROR lifetime parameters must be declared prior to type or const parameters + x: &'a &'b T +} + +trait Trait<'a, T, 'b> {} +//~^ ERROR lifetime parameters must be declared prior to type or const parameters + +fn foo<'a, T, 'b>(x: &'a T) {} +//~^ ERROR lifetime parameters must be declared prior to type or const parameters + +struct Y(T); +impl<'a, T, 'b> Y {} +//~^ ERROR lifetime parameters must be declared prior to type or const parameters + +mod bar { + pub struct X<'a, 'b, 'c, T> { + a: &'a str, + b: &'b str, + c: &'c str, + t: T, + } +} + +fn bar<'a, 'b, 'c, T>(x: bar::X<'a, T, 'b, 'c>) {} +//~^ ERROR type provided when a lifetime was expected + +fn main() {} diff --git a/src/test/ui/parser/issues/issue-14303.stderr b/src/test/ui/parser/issues/issue-14303.stderr new file mode 100644 index 000000000000..3579159245ac --- /dev/null +++ b/src/test/ui/parser/issues/issue-14303.stderr @@ -0,0 +1,39 @@ +error: lifetime parameters must be declared prior to type or const parameters + --> $DIR/issue-14303.rs:1:18 + | +LL | enum Enum<'a, T, 'b> { + | --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>` + +error: lifetime parameters must be declared prior to type or const parameters + --> $DIR/issue-14303.rs:6:22 + | +LL | struct Struct<'a, T, 'b> { + | --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>` + +error: lifetime parameters must be declared prior to type or const parameters + --> $DIR/issue-14303.rs:11:20 + | +LL | trait Trait<'a, T, 'b> {} + | --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>` + +error: lifetime parameters must be declared prior to type or const parameters + --> $DIR/issue-14303.rs:14:15 + | +LL | fn foo<'a, T, 'b>(x: &'a T) {} + | --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>` + +error: lifetime parameters must be declared prior to type or const parameters + --> $DIR/issue-14303.rs:18:13 + | +LL | impl<'a, T, 'b> Y {} + | --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>` + +error[E0747]: type provided when a lifetime was expected + --> $DIR/issue-14303.rs:30:37 + | +LL | fn bar<'a, 'b, 'c, T>(x: bar::X<'a, T, 'b, 'c>) {} + | ^ + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0747`. From 51d8b6c6643abb048987bd0befdeb6f46db0f6b5 Mon Sep 17 00:00:00 2001 From: Caio Date: Thu, 8 Sep 2022 12:04:55 -0300 Subject: [PATCH 4333/5092] Rename the `arithmetic` lint --- CHANGELOG.md | 2 +- clippy_lints/src/lib.register_lints.rs | 2 +- clippy_lints/src/lib.register_restriction.rs | 2 +- clippy_lints/src/lib.rs | 8 ++++++-- .../{arithmetic.rs => arithmetic_side_effects.rs} | 12 ++++++------ clippy_lints/src/operators/mod.rs | 10 +++++----- clippy_lints/src/utils/conf.rs | 2 +- src/docs.rs | 2 +- .../{arithmetic.txt => arithmetic_side_effects.txt} | 2 +- tests/ui-toml/arithmetic_allowed/clippy.toml | 1 - .../arithmetic_side_effects_allowed.rs} | 2 +- .../arithmetic_side_effects_allowed/clippy.toml | 1 + .../ui-toml/toml_unknown_key/conf_unknown_key.stderr | 2 +- .../ui/{arithmetic.rs => arithmetic_side_effects.rs} | 2 +- ...thmetic.stderr => arithmetic_side_effects.stderr} | 8 ++++---- 15 files changed, 31 insertions(+), 27 deletions(-) rename clippy_lints/src/operators/{arithmetic.rs => arithmetic_side_effects.rs} (95%) rename src/docs/{arithmetic.txt => arithmetic_side_effects.txt} (91%) delete mode 100644 tests/ui-toml/arithmetic_allowed/clippy.toml rename tests/ui-toml/{arithmetic_allowed/arithmetic_allowed.rs => arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs} (89%) create mode 100644 tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml rename tests/ui/{arithmetic.rs => arithmetic_side_effects.rs} (97%) rename tests/ui/{arithmetic.stderr => arithmetic_side_effects.stderr} (63%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 257add86b6e5..d847e4c74948 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3583,7 +3583,7 @@ Released 2018-09-13 [`almost_complete_letter_range`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_letter_range [`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped [`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant -[`arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic +[`arithmetic_side_effects`]: https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects [`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions [`as_underscore`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_underscore [`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 13b573beea1b..962e67220069 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -437,7 +437,7 @@ store.register_lints(&[ octal_escapes::OCTAL_ESCAPES, only_used_in_recursion::ONLY_USED_IN_RECURSION, operators::ABSURD_EXTREME_COMPARISONS, - operators::ARITHMETIC, + operators::ARITHMETIC_SIDE_EFFECTS, operators::ASSIGN_OP_PATTERN, operators::BAD_BIT_MASK, operators::CMP_NAN, diff --git a/clippy_lints/src/lib.register_restriction.rs b/clippy_lints/src/lib.register_restriction.rs index dd1e1e1a8e33..6eb9b3d3b9b7 100644 --- a/clippy_lints/src/lib.register_restriction.rs +++ b/clippy_lints/src/lib.register_restriction.rs @@ -50,7 +50,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve LintId::of(mixed_read_write_in_expression::MIXED_READ_WRITE_IN_EXPRESSION), LintId::of(module_style::MOD_MODULE_FILES), LintId::of(module_style::SELF_NAMED_MODULE_FILES), - LintId::of(operators::ARITHMETIC), + LintId::of(operators::ARITHMETIC_SIDE_EFFECTS), LintId::of(operators::FLOAT_ARITHMETIC), LintId::of(operators::FLOAT_CMP_CONST), LintId::of(operators::INTEGER_ARITHMETIC), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index a26e129f094e..7633bf347c3d 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -544,8 +544,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(utils::internal_lints::MsrvAttrImpl)); } - let arithmetic_allowed = conf.arithmetic_allowed.clone(); - store.register_late_pass(move || Box::new(operators::arithmetic::Arithmetic::new(arithmetic_allowed.clone()))); + let arithmetic_side_effects_allowed = conf.arithmetic_side_effects_allowed.clone(); + store.register_late_pass(move || { + Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new( + arithmetic_side_effects_allowed.clone(), + )) + }); store.register_late_pass(|| Box::new(utils::dump_hir::DumpHir)); store.register_late_pass(|| Box::new(utils::author::Author)); let await_holding_invalid_types = conf.await_holding_invalid_types.clone(); diff --git a/clippy_lints/src/operators/arithmetic.rs b/clippy_lints/src/operators/arithmetic_side_effects.rs similarity index 95% rename from clippy_lints/src/operators/arithmetic.rs rename to clippy_lints/src/operators/arithmetic_side_effects.rs index 27eef92deef4..83b69fbb3116 100644 --- a/clippy_lints/src/operators/arithmetic.rs +++ b/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -3,7 +3,7 @@ clippy::match_same_arms )] -use super::ARITHMETIC; +use super::ARITHMETIC_SIDE_EFFECTS; use clippy_utils::{consts::constant_simple, diagnostics::span_lint}; use rustc_ast as ast; use rustc_data_structures::fx::FxHashSet; @@ -22,16 +22,16 @@ const HARD_CODED_ALLOWED: &[&str] = &[ ]; #[derive(Debug)] -pub struct Arithmetic { +pub struct ArithmeticSideEffects { allowed: FxHashSet, // Used to check whether expressions are constants, such as in enum discriminants and consts const_span: Option, expr_span: Option, } -impl_lint_pass!(Arithmetic => [ARITHMETIC]); +impl_lint_pass!(ArithmeticSideEffects => [ARITHMETIC_SIDE_EFFECTS]); -impl Arithmetic { +impl ArithmeticSideEffects { #[must_use] pub fn new(mut allowed: FxHashSet) -> Self { allowed.extend(HARD_CODED_ALLOWED.iter().copied().map(String::from)); @@ -83,7 +83,7 @@ impl Arithmetic { } fn issue_lint(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) { - span_lint(cx, ARITHMETIC, expr.span, "arithmetic detected"); + span_lint(cx, ARITHMETIC_SIDE_EFFECTS, expr.span, "arithmetic detected"); self.expr_span = Some(expr.span); } @@ -125,7 +125,7 @@ impl Arithmetic { } } -impl<'tcx> LateLintPass<'tcx> for Arithmetic { +impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { if self.expr_span.is_some() || self.const_span.map_or(false, |sp| sp.contains(expr.span)) { return; diff --git a/clippy_lints/src/operators/mod.rs b/clippy_lints/src/operators/mod.rs index c7b0633b79ca..c32b4df4f75c 100644 --- a/clippy_lints/src/operators/mod.rs +++ b/clippy_lints/src/operators/mod.rs @@ -21,7 +21,7 @@ mod ptr_eq; mod self_assignment; mod verbose_bit_mask; -pub(crate) mod arithmetic; +pub(crate) mod arithmetic_side_effects; use rustc_hir::{Body, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; @@ -92,11 +92,11 @@ declare_clippy_lint! { /// ``` /// /// ### Allowed types - /// Custom allowed types can be specified through the "arithmetic-allowed" filter. + /// Custom allowed types can be specified through the "arithmetic-side-effects-allowed" filter. #[clippy::version = "1.64.0"] - pub ARITHMETIC, + pub ARITHMETIC_SIDE_EFFECTS, restriction, - "any arithmetic expression that could overflow or panic" + "any arithmetic expression that can cause side effects like overflows or panics" } declare_clippy_lint! { @@ -789,7 +789,7 @@ pub struct Operators { } impl_lint_pass!(Operators => [ ABSURD_EXTREME_COMPARISONS, - ARITHMETIC, + ARITHMETIC_SIDE_EFFECTS, INTEGER_ARITHMETIC, FLOAT_ARITHMETIC, ASSIGN_OP_PATTERN, diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index 84e65d5fa0b7..a8500beb2574 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -208,7 +208,7 @@ define_Conf! { /// Lint: Arithmetic. /// /// Suppress checking of the passed type names. - (arithmetic_allowed: rustc_data_structures::fx::FxHashSet = <_>::default()), + (arithmetic_side_effects_allowed: rustc_data_structures::fx::FxHashSet = <_>::default()), /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX. /// /// Suppress lints whenever the suggested change would cause breakage for other crates. diff --git a/src/docs.rs b/src/docs.rs index 69243bf4d9c9..f3a5048e7fa8 100644 --- a/src/docs.rs +++ b/src/docs.rs @@ -26,7 +26,7 @@ docs! { "almost_complete_letter_range", "almost_swapped", "approx_constant", - "arithmetic", + "arithmetic_side_effects", "as_conversions", "as_underscore", "assertions_on_constants", diff --git a/src/docs/arithmetic.txt b/src/docs/arithmetic_side_effects.txt similarity index 91% rename from src/docs/arithmetic.txt rename to src/docs/arithmetic_side_effects.txt index f04125060fbd..6c7d51a4989e 100644 --- a/src/docs/arithmetic.txt +++ b/src/docs/arithmetic_side_effects.txt @@ -30,4 +30,4 @@ let _n = Decimal::MAX + Decimal::MAX; ``` ### Allowed types -Custom allowed types can be specified through the "arithmetic-allowed" filter. \ No newline at end of file +Custom allowed types can be specified through the "arithmetic-side-effects-allowed" filter. \ No newline at end of file diff --git a/tests/ui-toml/arithmetic_allowed/clippy.toml b/tests/ui-toml/arithmetic_allowed/clippy.toml deleted file mode 100644 index cc40570b12a0..000000000000 --- a/tests/ui-toml/arithmetic_allowed/clippy.toml +++ /dev/null @@ -1 +0,0 @@ -arithmetic-allowed = ["Point"] diff --git a/tests/ui-toml/arithmetic_allowed/arithmetic_allowed.rs b/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs similarity index 89% rename from tests/ui-toml/arithmetic_allowed/arithmetic_allowed.rs rename to tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs index 195fabdbf710..1aed09b7c7bd 100644 --- a/tests/ui-toml/arithmetic_allowed/arithmetic_allowed.rs +++ b/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs @@ -1,4 +1,4 @@ -#![warn(clippy::arithmetic)] +#![warn(clippy::arithmetic_side_effects)] use core::ops::Add; diff --git a/tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml b/tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml new file mode 100644 index 000000000000..e736256f29a4 --- /dev/null +++ b/tests/ui-toml/arithmetic_side_effects_allowed/clippy.toml @@ -0,0 +1 @@ +arithmetic-side-effects-allowed = ["Point"] diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index a52a0b5289fe..f27f78d15d3a 100644 --- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -3,7 +3,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie allow-expect-in-tests allow-unwrap-in-tests allowed-scripts - arithmetic-allowed + arithmetic-side-effects-allowed array-size-threshold avoid-breaking-exported-api await-holding-invalid-types diff --git a/tests/ui/arithmetic.rs b/tests/ui/arithmetic_side_effects.rs similarity index 97% rename from tests/ui/arithmetic.rs rename to tests/ui/arithmetic_side_effects.rs index a9ac46e9a190..f5390c746425 100644 --- a/tests/ui/arithmetic.rs +++ b/tests/ui/arithmetic_side_effects.rs @@ -1,6 +1,6 @@ #![allow(clippy::assign_op_pattern, clippy::unnecessary_owned_empty_strings)] #![feature(inline_const, saturating_int_impl)] -#![warn(clippy::arithmetic)] +#![warn(clippy::arithmetic_side_effects)] use core::num::{Saturating, Wrapping}; diff --git a/tests/ui/arithmetic.stderr b/tests/ui/arithmetic_side_effects.stderr similarity index 63% rename from tests/ui/arithmetic.stderr rename to tests/ui/arithmetic_side_effects.stderr index a51cf6ba6005..6c4c8bdec0f0 100644 --- a/tests/ui/arithmetic.stderr +++ b/tests/ui/arithmetic_side_effects.stderr @@ -1,19 +1,19 @@ error: arithmetic detected - --> $DIR/arithmetic.rs:50:21 + --> $DIR/arithmetic_side_effects.rs:50:21 | LL | let mut _a = 1; _a += 1; | ^^^^^^^ | - = note: `-D clippy::arithmetic` implied by `-D warnings` + = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings` error: arithmetic detected - --> $DIR/arithmetic.rs:52:26 + --> $DIR/arithmetic_side_effects.rs:52:26 | LL | let mut _b = 1; _b = _b + 1; | ^^^^^^ error: arithmetic detected - --> $DIR/arithmetic.rs:54:26 + --> $DIR/arithmetic_side_effects.rs:54:26 | LL | let mut _c = 1; _c = 1 + _c; | ^^^^^^ From 064c9ef9e27ed9c427dedd6b4a1a042cb5cdc3e7 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 31 Aug 2022 18:54:19 +0200 Subject: [PATCH 4334/5092] Make clicking closing brace hint go to the opening brace --- crates/ide/src/inlay_hints.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 4ad6aa0e0497..d1b1d2c331a5 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -129,6 +129,11 @@ impl fmt::Debug for InlayHintLabel { pub struct InlayHintLabelPart { pub text: String, + /// Source location represented by this label part. The client will use this to fetch the part's + /// hover tooltip, and Ctrl+Clicking the label part will navigate to the definition the location + /// refers to (not necessarily the location itself). + /// When setting this, no tooltip must be set on the containing hint, or VS Code will display + /// them both. pub linked_location: Option, } @@ -266,10 +271,10 @@ fn closing_brace_hints( ) -> Option<()> { let min_lines = config.closing_brace_hints_min_lines?; - let name = |it: ast::Name| it.syntax().text_range().start(); + let name = |it: ast::Name| it.syntax().text_range(); let mut closing_token; - let (label, name_offset) = if let Some(item_list) = ast::AssocItemList::cast(node.clone()) { + let (label, name_range) = if let Some(item_list) = ast::AssocItemList::cast(node.clone()) { closing_token = item_list.r_curly_token()?; let parent = item_list.syntax().parent()?; @@ -279,11 +284,11 @@ fn closing_brace_hints( let imp = sema.to_def(&imp)?; let ty = imp.self_ty(sema.db); let trait_ = imp.trait_(sema.db); - - (match trait_ { + let hint_text = match trait_ { Some(tr) => format!("impl {} for {}", tr.name(sema.db), ty.display_truncated(sema.db, config.max_length)), None => format!("impl {}", ty.display_truncated(sema.db, config.max_length)), - }, None) + }; + (hint_text, None) }, ast::Trait(tr) => { (format!("trait {}", tr.name()?), tr.name().map(name)) @@ -327,7 +332,7 @@ fn closing_brace_hints( ( format!("{}!", mac.path()?), - mac.path().and_then(|it| it.segment()).map(|it| it.syntax().text_range().start()), + mac.path().and_then(|it| it.segment()).map(|it| it.syntax().text_range()), ) } else { return None; @@ -352,11 +357,12 @@ fn closing_brace_hints( return None; } + let linked_location = name_range.map(|range| FileRange { file_id, range }); acc.push(InlayHint { range: closing_token.text_range(), kind: InlayKind::ClosingBraceHint, - label: label.into(), - tooltip: name_offset.map(|it| InlayTooltip::HoverOffset(file_id, it)), + label: InlayHintLabel { parts: vec![InlayHintLabelPart { text: label, linked_location }] }, + tooltip: None, // provided by label part location }); None From 50e5d03e16790400f0c5b6ce6d3a27f6a71c5298 Mon Sep 17 00:00:00 2001 From: yukang Date: Sun, 14 Aug 2022 14:09:16 +0800 Subject: [PATCH 4335/5092] Avoid infinite loop in function arguments checking --- .../src/check/fn_ctxt/arg_matrix.rs | 21 +++-- .../ui/argument-suggestions/issue-100478.rs | 52 ++++++++++++ .../argument-suggestions/issue-100478.stderr | 81 +++++++++++++++++++ 3 files changed, 147 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/argument-suggestions/issue-100478.rs create mode 100644 src/test/ui/argument-suggestions/issue-100478.stderr diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs b/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs index 7602f2550e85..90a2589d747e 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs @@ -130,14 +130,17 @@ impl<'tcx> ArgMatrix<'tcx> { let ai = &self.expected_indices; let ii = &self.provided_indices; + // Issue: 100478, when we end the iteration, + // `next_unmatched_idx` will point to the index of the first unmatched + let mut next_unmatched_idx = 0; for i in 0..cmp::max(ai.len(), ii.len()) { - // If we eliminate the last row, any left-over inputs are considered missing + // If we eliminate the last row, any left-over arguments are considered missing if i >= mat.len() { - return Some(Issue::Missing(i)); + return Some(Issue::Missing(next_unmatched_idx)); } - // If we eliminate the last column, any left-over arguments are extra + // If we eliminate the last column, any left-over inputs are extra if mat[i].len() == 0 { - return Some(Issue::Extra(i)); + return Some(Issue::Extra(next_unmatched_idx)); } // Make sure we don't pass the bounds of our matrix @@ -145,6 +148,7 @@ impl<'tcx> ArgMatrix<'tcx> { let is_input = i < ii.len(); if is_arg && is_input && matches!(mat[i][i], Compatibility::Compatible) { // This is a satisfied input, so move along + next_unmatched_idx += 1; continue; } @@ -163,7 +167,7 @@ impl<'tcx> ArgMatrix<'tcx> { if is_input { for j in 0..ai.len() { // If we find at least one argument that could satisfy this input - // this argument isn't useless + // this input isn't useless if matches!(mat[i][j], Compatibility::Compatible) { useless = false; break; @@ -309,7 +313,8 @@ impl<'tcx> ArgMatrix<'tcx> { } while !self.provided_indices.is_empty() || !self.expected_indices.is_empty() { - match self.find_issue() { + let res = self.find_issue(); + match res { Some(Issue::Invalid(idx)) => { let compatibility = self.compatibility_matrix[idx][idx].clone(); let input_idx = self.provided_indices[idx]; @@ -364,7 +369,9 @@ impl<'tcx> ArgMatrix<'tcx> { None => { // We didn't find any issues, so we need to push the algorithm forward // First, eliminate any arguments that currently satisfy their inputs - for (inp, arg) in self.eliminate_satisfied() { + let eliminated = self.eliminate_satisfied(); + assert!(!eliminated.is_empty(), "didn't eliminated any indice in this round"); + for (inp, arg) in eliminated { matched_inputs[arg] = Some(inp); } } diff --git a/src/test/ui/argument-suggestions/issue-100478.rs b/src/test/ui/argument-suggestions/issue-100478.rs new file mode 100644 index 000000000000..6bef6ad10386 --- /dev/null +++ b/src/test/ui/argument-suggestions/issue-100478.rs @@ -0,0 +1,52 @@ +use std::sync::Arc; +macro_rules! GenT { + ($name:tt) => { + #[derive(Default, Debug)] + struct $name { + #[allow(unused)] + val: i32, + } + + impl $name { + #[allow(unused)] + fn new(val: i32) -> Self { + $name { val } + } + } + }; +} + +GenT!(T1); +GenT!(T2); +GenT!(T3); +GenT!(T4); +GenT!(T5); +GenT!(T6); +GenT!(T7); +GenT!(T8); + +#[allow(unused)] +fn foo(p1: T1, p2: Arc, p3: T3, p4: Arc, p5: T5, p6: T6, p7: T7, p8: Arc) {} +fn three_diff(_a: T1, _b: T2, _c: T3) {} +fn four_shuffle(_a: T1, _b: T2, _c: T3, _d: T4) {} + +fn main() { + three_diff(T2::new(0)); //~ ERROR this function takes + four_shuffle(T3::default(), T4::default(), T1::default(), T2::default()); //~ ERROR 35:5: 35:17: arguments to this function are incorrect [E0308] + four_shuffle(T3::default(), T2::default(), T1::default(), T3::default()); //~ ERROR 36:5: 36:17: arguments to this function are incorrect [E0308] + + let p1 = T1::new(0); + let p2 = Arc::new(T2::new(0)); + let p3 = T3::new(0); + let p4 = Arc::new(T4::new(1)); + let p5 = T5::new(0); + let p6 = T6::new(0); + let p7 = T7::new(0); + let p8 = Arc::default(); + + foo( + //~^ 47:5: 47:8: this function takes 8 arguments but 7 arguments were supplied [E0061] + p1, //p2, + p3, p4, p5, p6, p7, p8, + ); +} diff --git a/src/test/ui/argument-suggestions/issue-100478.stderr b/src/test/ui/argument-suggestions/issue-100478.stderr new file mode 100644 index 000000000000..a77889a9679c --- /dev/null +++ b/src/test/ui/argument-suggestions/issue-100478.stderr @@ -0,0 +1,81 @@ +error[E0061]: this function takes 3 arguments but 1 argument was supplied + --> $DIR/issue-100478.rs:34:5 + | +LL | three_diff(T2::new(0)); + | ^^^^^^^^^^------------ + | || + | |an argument of type `T1` is missing + | an argument of type `T3` is missing + | +note: function defined here + --> $DIR/issue-100478.rs:30:4 + | +LL | fn three_diff(_a: T1, _b: T2, _c: T3) {} + | ^^^^^^^^^^ ------ ------ ------ +help: provide the arguments + | +LL | three_diff(/* T1 */, T2::new(0), /* T3 */); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0308]: arguments to this function are incorrect + --> $DIR/issue-100478.rs:35:5 + | +LL | four_shuffle(T3::default(), T4::default(), T1::default(), T2::default()); + | ^^^^^^^^^^^^ ------------- ------------- ------------- ------------- expected `T4`, found `T2` + | | | | + | | | expected `T3`, found `T1` + | | expected `T2`, found `T4` + | expected `T1`, found `T3` + | +note: function defined here + --> $DIR/issue-100478.rs:31:4 + | +LL | fn four_shuffle(_a: T1, _b: T2, _c: T3, _d: T4) {} + | ^^^^^^^^^^^^ ------ ------ ------ ------ +help: did you mean + | +LL | four_shuffle(T1::default(), T2::default(), T3::default(), T4::default()); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0308]: arguments to this function are incorrect + --> $DIR/issue-100478.rs:36:5 + | +LL | four_shuffle(T3::default(), T2::default(), T1::default(), T3::default()); + | ^^^^^^^^^^^^ ------------- ------------- ------------- expected struct `T4`, found struct `T3` + | | | + | | expected `T3`, found `T1` + | expected `T1`, found `T3` + | +note: function defined here + --> $DIR/issue-100478.rs:31:4 + | +LL | fn four_shuffle(_a: T1, _b: T2, _c: T3, _d: T4) {} + | ^^^^^^^^^^^^ ------ ------ ------ ------ +help: swap these arguments + | +LL | four_shuffle(T1::default(), T2::default(), T3::default(), /* T4 */); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error[E0061]: this function takes 8 arguments but 7 arguments were supplied + --> $DIR/issue-100478.rs:47:5 + | +LL | foo( + | ^^^ +... +LL | p3, p4, p5, p6, p7, p8, + | -- an argument of type `Arc` is missing + | +note: function defined here + --> $DIR/issue-100478.rs:29:4 + | +LL | fn foo(p1: T1, p2: Arc, p3: T3, p4: Arc, p5: T5, p6: T6, p7: T7, p8: Arc) {} + | ^^^ ------ ----------- ------ ----------- ------ ------ ------ ----------- +help: provide the argument + | +LL | foo(p1, /* Arc */, p3, p4, p5, p6, p7, p8); + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0061, E0308. +For more information about an error, try `rustc --explain E0061`. From 2c5524f835ccd163dd3de9bd39b2cdc21337bf9c Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Thu, 8 Sep 2022 15:29:26 +0000 Subject: [PATCH 4336/5092] Update cargo in lintcheck_crates.toml --- lintcheck/lintcheck_crates.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lintcheck/lintcheck_crates.toml b/lintcheck/lintcheck_crates.toml index 4fbae8614ca3..ebbe9c9ae675 100644 --- a/lintcheck/lintcheck_crates.toml +++ b/lintcheck/lintcheck_crates.toml @@ -1,6 +1,6 @@ [crates] # some of these are from cargotest -cargo = {name = "cargo", versions = ['0.49.0']} +cargo = {name = "cargo", versions = ['0.64.0']} iron = {name = "iron", versions = ['0.6.1']} ripgrep = {name = "ripgrep", versions = ['12.1.1']} xsv = {name = "xsv", versions = ['0.13.0']} From f7b10b96cb34fbbc4574954d3a8363be58936393 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 8 Sep 2022 08:51:18 -0700 Subject: [PATCH 4337/5092] rustdoc: remove unused CSS `div.impl-items > div` This was added in 9077d540da944c41678a7129e04e7fc5d7e38582 to override the style on `
` tags that were acting as headers. These `
` tags were replaced with `
` tags in 32f62607c3142dfc9eb56a0bd72dee298ca43358, but this CSS was probably already redundant even then (the headers had already been replaced with real `

` and `

` tags in 76a3b609d0b93c5d8da5e4e3db37bd03e5cb1c30). --- src/librustdoc/html/static/css/rustdoc.css | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 7665417cb5c9..889b7ea8a112 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -197,10 +197,6 @@ h4.code-header { position: relative; } -div.impl-items > div { - padding-left: 0; -} - h1, h2, h3, h4, h5, h6, .sidebar, .mobile-topbar, @@ -212,7 +208,6 @@ a.source, span.since, #source-sidebar, #sidebar-toggle, details.rustdoc-toggle > summary::before, -div.impl-items > div:not(.docblock):not(.item-info), .content ul.crate a.crate, a.srclink, #help-button > button, From c4eadab016cf16bd32b90ba7ecc71361592a4f28 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Thu, 8 Sep 2022 18:33:53 +0200 Subject: [PATCH 4338/5092] Update crates/rust-analyzer/src/to_proto.rs Co-authored-by: Lukas Wirth --- crates/rust-analyzer/src/to_proto.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index de151f0d92c1..e083b9d0e337 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -467,7 +467,7 @@ pub(crate) fn inlay_hint( | InlayKind::ImplicitReborrowHint | InlayKind::TypeHint | InlayKind::ClosingBraceHint => false, - InlayKind::BindingModeHint => inlay_hint.label.to_string() != "&", + InlayKind::BindingModeHint => inlay_hint.label.as_simple_str() != Some("&"), InlayKind::ParameterHint | InlayKind::LifetimeHint => true, }), kind: match inlay_hint.kind { From d9a1faaa9cff6eab069ea8e5cd7862d0ae48e231 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 6 Sep 2022 15:36:13 -0300 Subject: [PATCH 4339/5092] Introduce lowering_arena to avoid creating AST nodes on the fly --- compiler/rustc_ast_lowering/src/item.rs | 4 +- compiler/rustc_ast_lowering/src/lib.rs | 55 ++++++++++++++++--------- 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 76f63d1d78a9..b175333fee28 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1,6 +1,6 @@ use super::errors::{InvalidAbi, MisplacedRelaxTraitBound}; use super::ResolverAstLoweringExt; -use super::{AstOwner, ImplTraitContext, ImplTraitPosition}; +use super::{Arena, AstOwner, ImplTraitContext, ImplTraitPosition}; use super::{FnDeclKind, LoweringContext, ParamMode}; use rustc_ast::ptr::P; @@ -25,6 +25,7 @@ use std::iter; pub(super) struct ItemLowerer<'a, 'hir> { pub(super) tcx: TyCtxt<'hir>, pub(super) resolver: &'a mut ResolverAstLowering, + pub(super) ast_arena: &'a Arena<'static>, pub(super) ast_index: &'a IndexVec>, pub(super) owners: &'a mut IndexVec>>, } @@ -60,6 +61,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { tcx: self.tcx, resolver: self.resolver, arena: self.tcx.hir_arena, + ast_arena: self.ast_arena, // HirId handling. bodies: Vec::new(), diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 3a94c7a91b23..cec91757e983 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -44,6 +44,7 @@ extern crate tracing; use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait}; +use rustc_arena::declare_arena; use rustc_ast::ptr::P; use rustc_ast::visit; use rustc_ast::{self as ast, *}; @@ -95,6 +96,13 @@ struct LoweringContext<'a, 'hir> { /// Used to allocate HIR nodes. arena: &'hir hir::Arena<'hir>, + /// Used to allocate temporary AST nodes for use during lowering. + /// This allows us to create "fake" AST -- these nodes can sometimes + /// be allocated on the stack, but other times we need them to live longer + /// than the current stack frame, so they can be collected into vectors + /// and things like that. + ast_arena: &'a Arena<'static>, + /// Bodies inside the owner being lowered. bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>, /// Attributes inside the owner being lowered. @@ -140,6 +148,15 @@ struct LoweringContext<'a, 'hir> { generics_def_id_map: Vec>, } +declare_arena!([ + [] tys: rustc_ast::Ty, + [] aba: rustc_ast::AngleBracketedArgs, + [] ptr: rustc_ast::PolyTraitRef, + // This _marker field is needed because `declare_arena` creates `Arena<'tcx>` and we need to + // use `'tcx`. If we don't have this we get a compile error. + [] _marker: std::marker::PhantomData<&'tcx ()>, +]); + trait ResolverAstLoweringExt { fn legacy_const_generic_args(&self, expr: &Expr) -> Option>; fn get_partial_res(&self, id: NodeId) -> Option; @@ -401,10 +418,13 @@ pub fn lower_to_hir<'hir>(tcx: TyCtxt<'hir>, (): ()) -> hir::Crate<'hir> { tcx.definitions_untracked().def_index_count(), ); + let ast_arena = Arena::default(); + for def_id in ast_index.indices() { item::ItemLowerer { tcx, resolver: &mut resolver, + ast_arena: &ast_arena, ast_index: &ast_index, owners: &mut owners, } @@ -964,12 +984,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } GenericArgs::Parenthesized(ref data) => { self.emit_bad_parenthesized_trait_in_assoc_ty(data); - self.lower_angle_bracketed_parameter_data( - &data.as_angle_bracketed_args(), - ParamMode::Explicit, - itctx, - ) - .0 + let aba = self.ast_arena.aba.alloc(data.as_angle_bracketed_args()); + self.lower_angle_bracketed_parameter_data(aba, ParamMode::Explicit, itctx).0 } }; gen_args_ctor.into_generic_args(self) @@ -1037,15 +1053,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.with_dyn_type_scope(false, |this| { let node_id = this.next_node_id(); - let ty = this.lower_ty( - &Ty { - id: node_id, - kind: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()), - span: this.lower_span(constraint.span), - tokens: None, - }, - itctx, - ); + let ty = this.ast_arena.tys.alloc(Ty { + id: node_id, + kind: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()), + span: this.lower_span(constraint.span), + tokens: None, + }); + let ty = this.lower_ty(ty, itctx); hir::TypeBindingKind::Equality { term: ty.into() } }) @@ -1181,12 +1195,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { && let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = partial_res.base_res() { let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| { + let poly_trait_ref = this.ast_arena.ptr.alloc(PolyTraitRef { + bound_generic_params: vec![], + trait_ref: TraitRef { path: path.clone(), ref_id: t.id }, + span: t.span + }); let bound = this.lower_poly_trait_ref( - &PolyTraitRef { - bound_generic_params: vec![], - trait_ref: TraitRef { path: path.clone(), ref_id: t.id }, - span: t.span - }, + poly_trait_ref, itctx, ); let bounds = this.arena.alloc_from_iter([bound]); From b9093f40081c0204361e46bd787e6ba7abd58cdd Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 8 Sep 2022 10:33:15 -0700 Subject: [PATCH 4340/5092] rustdoc: remove no-op CSS `#settings-menu { padding: 0 }` This CSS was added in 5e01ba36c9f1037c4cf3e7421413fc6c41f85d05, and served to override CSS right above it that set a 5px padding for several kinds of buttons in the same toolbar. The CSS that it overrode is still there, but now it only applies to `#settings-menu > a`, so there's nothing to override. --- src/librustdoc/html/static/css/rustdoc.css | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 7665417cb5c9..574409a88af3 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1449,9 +1449,7 @@ pre.rust { border-radius: 2px; cursor: pointer; } -#settings-menu { - padding: 0; -} + #settings-menu > a, #help-button > button { padding: 5px; height: 100%; From a6d8afd958e35cb0f424de8be11c42116133e23a Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Thu, 8 Sep 2022 20:04:43 +0200 Subject: [PATCH 4341/5092] Fix `range_{plus,minus}_one` bad suggestions Fixes #9431. The current `range_plus_one` and `range_minus_one` suggestions are completely incorrect when macros are involved. This commit resolves this by disabling the lints for any range expression that is expanded from a macro. The reasons for this are that it is very difficult to create a correct suggestion in this case and that false negatives are less important for pedantic lints. --- clippy_lints/src/ranges.rs | 11 +++-------- tests/ui/range_plus_minus_one.fixed | 19 +++++++++++++++++++ tests/ui/range_plus_minus_one.rs | 19 +++++++++++++++++++ tests/ui/range_plus_minus_one.stderr | 18 +++++++++--------- 4 files changed, 50 insertions(+), 17 deletions(-) diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 490f345d2970..918d624eec6f 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -350,6 +350,7 @@ fn check_range_bounds<'a>(cx: &'a LateContext<'_>, ex: &'a Expr<'_>) -> Option, expr: &Expr<'_>) { if_chain! { + if expr.span.can_be_used_for_suggestions(); if let Some(higher::Range { start, end: Some(end), @@ -357,14 +358,7 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) { }) = higher::Range::hir(expr); if let Some(y) = y_plus_one(cx, end); then { - let span = if expr.span.from_expansion() { - expr.span - .ctxt() - .outer_expn_data() - .call_site - } else { - expr.span - }; + let span = expr.span; span_lint_and_then( cx, RANGE_PLUS_ONE, @@ -399,6 +393,7 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) { // inclusive range minus one: `x..=(y-1)` fn check_inclusive_range_minus_one(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { + if expr.span.can_be_used_for_suggestions(); if let Some(higher::Range { start, end: Some(end), limits: RangeLimits::Closed }) = higher::Range::hir(expr); if let Some(y) = y_minus_one(cx, end); then { diff --git a/tests/ui/range_plus_minus_one.fixed b/tests/ui/range_plus_minus_one.fixed index 40d7791df281..a16a3e54d45e 100644 --- a/tests/ui/range_plus_minus_one.fixed +++ b/tests/ui/range_plus_minus_one.fixed @@ -6,6 +6,22 @@ fn f() -> usize { 42 } +macro_rules! macro_plus_one { + ($m: literal) => { + for i in 0..$m + 1 { + println!("{}", i); + } + }; +} + +macro_rules! macro_minus_one { + ($m: literal) => { + for i in 0..=$m - 1 { + println!("{}", i); + } + }; +} + #[warn(clippy::range_plus_one)] #[warn(clippy::range_minus_one)] fn main() { @@ -39,4 +55,7 @@ fn main() { let mut vec: Vec<()> = std::vec::Vec::new(); vec.drain(..); + + macro_plus_one!(5); + macro_minus_one!(5); } diff --git a/tests/ui/range_plus_minus_one.rs b/tests/ui/range_plus_minus_one.rs index a8ddd9b5f751..bd6cb4d21be5 100644 --- a/tests/ui/range_plus_minus_one.rs +++ b/tests/ui/range_plus_minus_one.rs @@ -6,6 +6,22 @@ fn f() -> usize { 42 } +macro_rules! macro_plus_one { + ($m: literal) => { + for i in 0..$m + 1 { + println!("{}", i); + } + }; +} + +macro_rules! macro_minus_one { + ($m: literal) => { + for i in 0..=$m - 1 { + println!("{}", i); + } + }; +} + #[warn(clippy::range_plus_one)] #[warn(clippy::range_minus_one)] fn main() { @@ -39,4 +55,7 @@ fn main() { let mut vec: Vec<()> = std::vec::Vec::new(); vec.drain(..); + + macro_plus_one!(5); + macro_minus_one!(5); } diff --git a/tests/ui/range_plus_minus_one.stderr b/tests/ui/range_plus_minus_one.stderr index fb4f1658597a..0223696243b2 100644 --- a/tests/ui/range_plus_minus_one.stderr +++ b/tests/ui/range_plus_minus_one.stderr @@ -1,5 +1,5 @@ error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:15:14 + --> $DIR/range_plus_minus_one.rs:31:14 | LL | for _ in 0..3 + 1 {} | ^^^^^^^^ help: use: `0..=3` @@ -7,25 +7,25 @@ LL | for _ in 0..3 + 1 {} = note: `-D clippy::range-plus-one` implied by `-D warnings` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:18:14 + --> $DIR/range_plus_minus_one.rs:34:14 | LL | for _ in 0..1 + 5 {} | ^^^^^^^^ help: use: `0..=5` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:21:14 + --> $DIR/range_plus_minus_one.rs:37:14 | LL | for _ in 1..1 + 1 {} | ^^^^^^^^ help: use: `1..=1` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:27:14 + --> $DIR/range_plus_minus_one.rs:43:14 | LL | for _ in 0..(1 + f()) {} | ^^^^^^^^^^^^ help: use: `0..=f()` error: an exclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:31:13 + --> $DIR/range_plus_minus_one.rs:47:13 | LL | let _ = ..=11 - 1; | ^^^^^^^^^ help: use: `..11` @@ -33,25 +33,25 @@ LL | let _ = ..=11 - 1; = note: `-D clippy::range-minus-one` implied by `-D warnings` error: an exclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:32:13 + --> $DIR/range_plus_minus_one.rs:48:13 | LL | let _ = ..=(11 - 1); | ^^^^^^^^^^^ help: use: `..11` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:33:13 + --> $DIR/range_plus_minus_one.rs:49:13 | LL | let _ = (1..11 + 1); | ^^^^^^^^^^^ help: use: `(1..=11)` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:34:13 + --> $DIR/range_plus_minus_one.rs:50:13 | LL | let _ = (f() + 1)..(f() + 1); | ^^^^^^^^^^^^^^^^^^^^ help: use: `((f() + 1)..=f())` error: an inclusive range would be more readable - --> $DIR/range_plus_minus_one.rs:38:14 + --> $DIR/range_plus_minus_one.rs:54:14 | LL | for _ in 1..ONE + ONE {} | ^^^^^^^^^^^^ help: use: `1..=ONE` From df536c9086471c1484c29d904aff9091d762e151 Mon Sep 17 00:00:00 2001 From: Philipp Krones Date: Thu, 8 Sep 2022 21:27:37 +0200 Subject: [PATCH 4342/5092] Bump nightly version -> 2022-09-08 --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 85b60fefd60f..b6976366dafc 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2022-08-27" +channel = "nightly-2022-09-08" components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] From 1764c425186142e4078e4dc1774321871f6f2eee Mon Sep 17 00:00:00 2001 From: Stanislav Date: Thu, 8 Sep 2022 22:36:36 +0300 Subject: [PATCH 4343/5092] fix comment --- crates/rust-analyzer/src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 2fdede40dde8..48a20189cc4c 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -220,7 +220,7 @@ config_data! { /// Controls file watching implementation. files_watcher: FilesWatcherDef = "\"client\"", - /// Exclude imports in "Find All References" + /// Exclude imports in `Find All References` findAllRefs_excludeImports: bool = "false", /// Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords. From 0240294759379bc6807d2f1b87391075c84f6bf3 Mon Sep 17 00:00:00 2001 From: Stanislav Date: Thu, 8 Sep 2022 22:47:39 +0300 Subject: [PATCH 4344/5092] fix comment round 2 --- crates/rust-analyzer/src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 48a20189cc4c..80a4b709e7cd 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -220,7 +220,7 @@ config_data! { /// Controls file watching implementation. files_watcher: FilesWatcherDef = "\"client\"", - /// Exclude imports in `Find All References` + /// Exclude imports from find-all-references. findAllRefs_excludeImports: bool = "false", /// Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords. From ab0b64b26c95bd0cf60af2c299f35c6860c34431 Mon Sep 17 00:00:00 2001 From: Stanislav Date: Thu, 8 Sep 2022 22:55:04 +0300 Subject: [PATCH 4345/5092] fix comment round 3 --- docs/user/generated_config.adoc | 5 +++++ editors/code/package.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index 72b925726479..517a73edd33f 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -260,6 +260,11 @@ also need to add the folders to Code's `files.watcherExclude`. [[rust-analyzer.files.watcher]]rust-analyzer.files.watcher (default: `"client"`):: + -- +Find All References config. +-- +[[rust-analyzer.findAllRefs.excludeImports]]rust-analyzer.findAllRefs.excludeImports (default: `false`):: ++ +-- Controls file watching implementation. -- [[rust-analyzer.highlightRelated.breakPoints.enable]]rust-analyzer.highlightRelated.breakPoints.enable (default: `true`):: diff --git a/editors/code/package.json b/editors/code/package.json index 3af18dacd495..189f20fc0cd9 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -840,7 +840,7 @@ "minimum": 0 }, "rust-analyzer.findAllRefs.excludeImports": { - "markdownDescription": "Exclude imports from Find All References results", + "markdownDescription": "Exclude imports from find-all-references.", "default": false, "type": "boolean" }, From ef36af2f9d44b8b57660e6b6eea227e1e99bcf2b Mon Sep 17 00:00:00 2001 From: Ellen Date: Thu, 8 Sep 2022 21:09:23 +0100 Subject: [PATCH 4346/5092] ptr: 43276834268743978 --- compiler/rustc_middle/src/ty/mod.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 37136ff2ef5d..4635a9d5575d 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -915,12 +915,25 @@ pub struct CoercePredicate<'tcx> { } pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>; -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Term<'tcx> { ptr: NonZeroUsize, marker: PhantomData<(Ty<'tcx>, Const<'tcx>)>, } +impl Debug for Term<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let data = if let Some(ty) = self.ty() { + format!("Term::Ty({:?})", ty) + } else if let Some(ct) = self.ct() { + format!("Term::Ct({:?})", ct) + } else { + unreachable!() + }; + f.write_str(&data) + } +} + impl<'tcx> From> for Term<'tcx> { fn from(ty: Ty<'tcx>) -> Self { TermKind::Ty(ty).pack() From 6fc6d87fd069470893b6a539a46fa1e2f10ae906 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Tue, 30 Aug 2022 12:20:49 +0000 Subject: [PATCH 4347/5092] Migrate write.rs to a late pass --- clippy_lints/src/format.rs | 2 +- clippy_lints/src/format_args.rs | 2 +- clippy_lints/src/lib.register_all.rs | 1 - clippy_lints/src/lib.register_lints.rs | 1 - clippy_lints/src/lib.register_suspicious.rs | 1 - clippy_lints/src/lib.rs | 3 +- clippy_lints/src/renamed_lints.rs | 1 + clippy_lints/src/utils/conf.rs | 2 +- clippy_lints/src/write.rs | 813 ++++++------------ clippy_utils/src/macros.rs | 11 +- src/docs.rs | 1 - .../positional_named_format_parameters.txt | 15 - src/docs/print_literal.txt | 4 - src/docs/print_stderr.txt | 8 +- src/docs/print_stdout.txt | 8 +- src/docs/write_literal.txt | 4 - tests/ui/eprint_with_newline.rs | 10 +- tests/ui/eprint_with_newline.stderr | 18 +- tests/ui/format.fixed | 4 - tests/ui/format.rs | 4 - tests/ui/format.stderr | 44 +- .../positional_named_format_parameters.fixed | 56 -- .../ui/positional_named_format_parameters.rs | 56 -- .../positional_named_format_parameters.stderr | 418 --------- tests/ui/print_literal.rs | 2 + tests/ui/print_literal.stderr | 86 +- tests/ui/print_with_newline.rs | 10 +- tests/ui/print_with_newline.stderr | 18 +- tests/ui/println_empty_string.stderr | 24 +- tests/ui/rename.fixed | 2 + tests/ui/rename.rs | 2 + tests/ui/rename.stderr | 82 +- tests/ui/write_literal.rs | 2 + tests/ui/write_literal.stderr | 86 +- tests/ui/write_literal_2.rs | 9 +- tests/ui/write_literal_2.stderr | 80 +- tests/ui/write_with_newline.rs | 8 + tests/ui/write_with_newline.stderr | 38 +- tests/ui/writeln_empty_string.stderr | 12 +- 39 files changed, 597 insertions(+), 1351 deletions(-) delete mode 100644 src/docs/positional_named_format_parameters.txt delete mode 100644 tests/ui/positional_named_format_parameters.fixed delete mode 100644 tests/ui/positional_named_format_parameters.rs delete mode 100644 tests/ui/positional_named_format_parameters.stderr diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 0c5851cdbed2..f10d82569536 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -71,12 +71,12 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat { let value = arg.param.value; if_chain! { if format_args.format_string.parts == [kw::Empty]; + if arg.format.is_default(); if match cx.typeck_results().expr_ty(value).peel_refs().kind() { ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(sym::String, adt.did()), ty::Str => true, _ => false, }; - if !arg.format.has_string_formatting(); then { let is_new_string = match value.kind { ExprKind::Binary(..) => true, diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs index 97024be16fa4..e1c46fd0bfd4 100644 --- a/clippy_lints/src/format_args.rs +++ b/clippy_lints/src/format_args.rs @@ -77,7 +77,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs { if let ExpnKind::Macro(_, name) = outermost_expn_data.kind; then { for arg in &format_args.args { - if arg.format.has_string_formatting() { + if !arg.format.is_default() { continue; } if is_aliased(&format_args, arg.param.value.hir_id) { diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index 1f85382347aa..39ab175341f4 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -352,7 +352,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(useless_conversion::USELESS_CONVERSION), LintId::of(vec::USELESS_VEC), LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH), - LintId::of(write::POSITIONAL_NAMED_FORMAT_PARAMETERS), LintId::of(write::PRINTLN_EMPTY_STRING), LintId::of(write::PRINT_LITERAL), LintId::of(write::PRINT_WITH_NEWLINE), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index 962e67220069..c16f2d86ae0a 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -595,7 +595,6 @@ store.register_lints(&[ vec_init_then_push::VEC_INIT_THEN_PUSH, wildcard_imports::ENUM_GLOB_USE, wildcard_imports::WILDCARD_IMPORTS, - write::POSITIONAL_NAMED_FORMAT_PARAMETERS, write::PRINTLN_EMPTY_STRING, write::PRINT_LITERAL, write::PRINT_STDERR, diff --git a/clippy_lints/src/lib.register_suspicious.rs b/clippy_lints/src/lib.register_suspicious.rs index 8f131bbf98be..f463ad9f6d2e 100644 --- a/clippy_lints/src/lib.register_suspicious.rs +++ b/clippy_lints/src/lib.register_suspicious.rs @@ -36,5 +36,4 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec! LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), LintId::of(swap_ptr_to_ref::SWAP_PTR_TO_REF), LintId::of(unused_peekable::UNUSED_PEEKABLE), - LintId::of(write::POSITIONAL_NAMED_FORMAT_PARAMETERS), ]) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index ec96999896e2..83fdc15c9f02 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -40,7 +40,6 @@ extern crate rustc_lint; extern crate rustc_middle; extern crate rustc_mir_dataflow; extern crate rustc_parse; -extern crate rustc_parse_format; extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; @@ -425,7 +424,6 @@ pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Se }) }); - store.register_pre_expansion_pass(|| Box::new(write::Write::default())); store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes { msrv })); } @@ -879,6 +877,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: ignore_publish: cargo_ignore_publish, }) }); + store.register_late_pass(|| Box::new(write::Write::default())); store.register_early_pass(|| Box::new(crate_in_macro_def::CrateInMacroDef)); store.register_early_pass(|| Box::new(empty_structs_with_brackets::EmptyStructsWithBrackets)); store.register_late_pass(|| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings)); diff --git a/clippy_lints/src/renamed_lints.rs b/clippy_lints/src/renamed_lints.rs index 6bea6dc0773d..d320eea1c377 100644 --- a/clippy_lints/src/renamed_lints.rs +++ b/clippy_lints/src/renamed_lints.rs @@ -36,6 +36,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[ ("clippy::invalid_ref", "invalid_value"), ("clippy::mem_discriminant_non_enum", "enum_intrinsics_non_enums"), ("clippy::panic_params", "non_fmt_panics"), + ("clippy::positional_named_format_parameters", "named_arguments_used_positionally"), ("clippy::temporary_cstring_as_ptr", "temporary_cstring_as_ptr"), ("clippy::unknown_clippy_lints", "unknown_lints"), ("clippy::unused_label", "unused_labels"), diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs index a8500beb2574..2be3fa99c811 100644 --- a/clippy_lints/src/utils/conf.rs +++ b/clippy_lints/src/utils/conf.rs @@ -476,7 +476,7 @@ pub fn format_error(error: Box) -> String { let mut msg = String::from(prefix); for row in 0..rows { - write!(msg, "\n").unwrap(); + writeln!(msg).unwrap(); for (column, column_width) in column_widths.iter().copied().enumerate() { let index = column * rows + row; let field = fields.get(index).copied().unwrap_or_default(); diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index 640a09a7a912..06e7d7017017 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -1,20 +1,12 @@ -use std::borrow::Cow; -use std::iter; -use std::ops::{Deref, Range}; - -use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; -use rustc_ast::ast::{Expr, ExprKind, Impl, Item, ItemKind, MacCall, Path, StrLit, StrStyle}; -use rustc_ast::ptr::P; -use rustc_ast::token::{self, LitKind}; -use rustc_ast::tokenstream::TokenStream; -use rustc_errors::{Applicability, DiagnosticBuilder}; -use rustc_lexer::unescape::{self, EscapeError}; -use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; -use rustc_parse::parser; +use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn, MacroCall}; +use clippy_utils::source::snippet_opt; +use rustc_ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, HirIdMap, Impl, Item, ItemKind}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::symbol::{kw, Symbol}; -use rustc_span::{sym, BytePos, InnerSpan, Span, DUMMY_SP}; +use rustc_span::{sym, BytePos, Span}; declare_clippy_lint! { /// ### What it does @@ -74,13 +66,7 @@ declare_clippy_lint! { /// application and might forget to remove those prints afterward. /// /// ### Known problems - /// * Only catches `print!` and `println!` calls. - /// * The lint level is unaffected by crate attributes. The level can still - /// be set for functions, modules and other items. To change the level for - /// the entire crate, please use command line flags. More information and a - /// configuration example can be found in [clippy#6610]. - /// - /// [clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558 + /// Only catches `print!` and `println!` calls. /// /// ### Example /// ```rust @@ -102,13 +88,7 @@ declare_clippy_lint! { /// application and might forget to remove those prints afterward. /// /// ### Known problems - /// * Only catches `eprint!` and `eprintln!` calls. - /// * The lint level is unaffected by crate attributes. The level can still - /// be set for functions, modules and other items. To change the level for - /// the entire crate, please use command line flags. More information and a - /// configuration example can be found in [clippy#6610]. - /// - /// [clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558 + /// Only catches `eprint!` and `eprintln!` calls. /// /// ### Example /// ```rust @@ -149,10 +129,6 @@ declare_clippy_lint! { /// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary /// (i.e., just put the literal in the format string) /// - /// ### Known problems - /// Will also warn with macro calls as arguments that expand to literals - /// -- e.g., `println!("{}", env!("FOO"))`. - /// /// ### Example /// ```rust /// println!("{}", "foo"); @@ -234,10 +210,6 @@ declare_clippy_lint! { /// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary /// (i.e., just put the literal in the format string) /// - /// ### Known problems - /// Will also warn with macro calls as arguments that expand to literals - /// -- e.g., `writeln!(buf, "{}", env!("FOO"))`. - /// /// ### Example /// ```rust /// # use std::fmt::Write; @@ -257,28 +229,6 @@ declare_clippy_lint! { "writing a literal with a format string" } -declare_clippy_lint! { - /// ### What it does - /// This lint warns when a named parameter in a format string is used as a positional one. - /// - /// ### Why is this bad? - /// It may be confused for an assignment and obfuscates which parameter is being used. - /// - /// ### Example - /// ```rust - /// println!("{}", x = 10); - /// ``` - /// - /// Use instead: - /// ```rust - /// println!("{x}", x = 10); - /// ``` - #[clippy::version = "1.63.0"] - pub POSITIONAL_NAMED_FORMAT_PARAMETERS, - suspicious, - "named parameter in a format string is used positionally" -} - #[derive(Default)] pub struct Write { in_debug_impl: bool, @@ -294,537 +244,308 @@ impl_lint_pass!(Write => [ WRITE_WITH_NEWLINE, WRITELN_EMPTY_STRING, WRITE_LITERAL, - POSITIONAL_NAMED_FORMAT_PARAMETERS, ]); -impl EarlyLintPass for Write { - fn check_item(&mut self, _: &EarlyContext<'_>, item: &Item) { - if let ItemKind::Impl(box Impl { - of_trait: Some(trait_ref), - .. - }) = &item.kind - { - let trait_name = trait_ref - .path - .segments - .iter() - .last() - .expect("path has at least one segment") - .ident - .name; - if trait_name == sym::Debug { - self.in_debug_impl = true; - } +impl<'tcx> LateLintPass<'tcx> for Write { + fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { + if is_debug_impl(cx, item) { + self.in_debug_impl = true; } } - fn check_item_post(&mut self, _: &EarlyContext<'_>, _: &Item) { - self.in_debug_impl = false; + fn check_item_post(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { + if is_debug_impl(cx, item) { + self.in_debug_impl = false; + } } - fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &MacCall) { - fn is_build_script(cx: &EarlyContext<'_>) -> bool { - // Cargo sets the crate name for build scripts to `build_script_build` - cx.sess() - .opts - .crate_name - .as_ref() - .map_or(false, |crate_name| crate_name == "build_script_build") - } + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return }; + let Some(diag_name) = cx.tcx.get_diagnostic_name(macro_call.def_id) else { return }; + let Some(name) = diag_name.as_str().strip_suffix("_macro") else { return }; - if mac.path == sym!(print) { - if !is_build_script(cx) { - span_lint(cx, PRINT_STDOUT, mac.span(), "use of `print!`"); - } - self.lint_print_with_newline(cx, mac); - } else if mac.path == sym!(println) { - if !is_build_script(cx) { - span_lint(cx, PRINT_STDOUT, mac.span(), "use of `println!`"); - } - self.lint_println_empty_string(cx, mac); - } else if mac.path == sym!(eprint) { - span_lint(cx, PRINT_STDERR, mac.span(), "use of `eprint!`"); - self.lint_print_with_newline(cx, mac); - } else if mac.path == sym!(eprintln) { - span_lint(cx, PRINT_STDERR, mac.span(), "use of `eprintln!`"); - self.lint_println_empty_string(cx, mac); - } else if mac.path == sym!(write) { - if let (Some(fmt_str), dest) = self.check_tts(cx, mac.args.inner_tokens(), true) { - if check_newlines(&fmt_str) { - let (nl_span, only_nl) = newline_span(&fmt_str); - let nl_span = match (dest, only_nl) { - // Special case of `write!(buf, "\n")`: Mark everything from the end of - // `buf` for removal so no trailing comma [`writeln!(buf, )`] remains. - (Some(dest_expr), true) => nl_span.with_lo(dest_expr.span.hi()), - _ => nl_span, - }; - span_lint_and_then( - cx, - WRITE_WITH_NEWLINE, - mac.span(), - "using `write!()` with a format string that ends in a single newline", - |err| { - err.multipart_suggestion( - "use `writeln!()` instead", - vec![(mac.path.span, String::from("writeln")), (nl_span, String::new())], - Applicability::MachineApplicable, - ); - }, - ); + let is_build_script = cx + .sess() + .opts + .crate_name + .as_ref() + .map_or(false, |crate_name| crate_name == "build_script_build"); + + match diag_name { + sym::print_macro | sym::println_macro => { + if !is_build_script { + span_lint(cx, PRINT_STDOUT, macro_call.span, &format!("use of `{name}!`")); } - } - } else if mac.path == sym!(writeln) { - if let (Some(fmt_str), expr) = self.check_tts(cx, mac.args.inner_tokens(), true) { - if fmt_str.symbol == kw::Empty { - let mut applicability = Applicability::MachineApplicable; - let suggestion = if let Some(e) = expr { - snippet_with_applicability(cx, e.span, "v", &mut applicability) - } else { - applicability = Applicability::HasPlaceholders; - Cow::Borrowed("v") - }; + }, + sym::eprint_macro | sym::eprintln_macro => { + span_lint(cx, PRINT_STDERR, macro_call.span, &format!("use of `{name}!`")); + }, + sym::write_macro | sym::writeln_macro => {}, + _ => return, + } - span_lint_and_sugg( - cx, - WRITELN_EMPTY_STRING, - mac.span(), - format!("using `writeln!({}, \"\")`", suggestion).as_str(), - "replace it with", - format!("writeln!({})", suggestion), - applicability, - ); + let Some(format_args) = FormatArgsExpn::find_nested(cx, expr, macro_call.expn) else { return }; + + // ignore `writeln!(w)` and `write!(v, some_macro!())` + if format_args.format_string.span.from_expansion() { + return; + } + + match diag_name { + sym::print_macro | sym::eprint_macro | sym::write_macro => { + check_newline(cx, &format_args, ¯o_call, name); + }, + sym::println_macro | sym::eprintln_macro | sym::writeln_macro => { + check_empty_string(cx, &format_args, ¯o_call, name); + }, + _ => {}, + } + + check_literal(cx, &format_args, name); + + if !self.in_debug_impl { + for arg in &format_args.args { + if arg.format.r#trait == sym::Debug { + span_lint(cx, USE_DEBUG, arg.span, "use of `Debug`-based formatting"); } } } } } - -/// Given a format string that ends in a newline and its span, calculates the span of the -/// newline, or the format string itself if the format string consists solely of a newline. -/// Return this and a boolean indicating whether it only consisted of a newline. -fn newline_span(fmtstr: &StrLit) -> (Span, bool) { - let sp = fmtstr.span; - let contents = fmtstr.symbol.as_str(); - - if contents == r"\n" { - return (sp, true); - } - - let newline_sp_hi = sp.hi() - - match fmtstr.style { - StrStyle::Cooked => BytePos(1), - StrStyle::Raw(hashes) => BytePos((1 + hashes).into()), - }; - - let newline_sp_len = if contents.ends_with('\n') { - BytePos(1) - } else if contents.ends_with(r"\n") { - BytePos(2) +fn is_debug_impl(cx: &LateContext<'_>, item: &Item<'_>) -> bool { + if let ItemKind::Impl(Impl { of_trait: Some(trait_ref), .. }) = &item.kind + && let Some(trait_id) = trait_ref.trait_def_id() + { + cx.tcx.is_diagnostic_item(sym::Debug, trait_id) } else { - panic!("expected format string to contain a newline"); + false + } +} + +fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, macro_call: &MacroCall, name: &str) { + let format_string_parts = &format_args.format_string.parts; + let mut format_string_span = format_args.format_string.span; + + let Some(last) = format_string_parts.last() else { return }; + + let count_vertical_whitespace = || { + format_string_parts + .iter() + .flat_map(|part| part.as_str().chars()) + .filter(|ch| matches!(ch, '\r' | '\n')) + .count() }; - (sp.with_lo(newline_sp_hi - newline_sp_len).with_hi(newline_sp_hi), false) -} + if last.as_str().ends_with('\n') + // ignore format strings with other internal vertical whitespace + && count_vertical_whitespace() == 1 -/// Stores a list of replacement spans for each argument, but only if all the replacements used an -/// empty format string. -#[derive(Default)] -struct SimpleFormatArgs { - unnamed: Vec>, - complex_unnamed: Vec>, - named: Vec<(Symbol, Vec)>, -} -impl SimpleFormatArgs { - fn get_unnamed(&self) -> impl Iterator { - self.unnamed.iter().map(|x| match x.as_slice() { - // Ignore the dummy span added from out of order format arguments. - [DUMMY_SP] => &[], - x => x, - }) - } + // ignore trailing arguments: `print!("Issue\n{}", 1265);` + && format_string_parts.len() > format_args.args.len() + { + let lint = if name == "write" { + format_string_span = expand_past_previous_comma(cx, format_string_span); - fn get_complex_unnamed(&self) -> impl Iterator { - self.complex_unnamed.iter().map(Vec::as_slice) - } - - fn get_named(&self, n: &Path) -> &[Span] { - self.named.iter().find(|x| *n == x.0).map_or(&[], |x| x.1.as_slice()) - } - - fn push(&mut self, arg: rustc_parse_format::Argument<'_>, span: Span) { - use rustc_parse_format::{ - AlignUnknown, ArgumentImplicitlyIs, ArgumentIs, ArgumentNamed, CountImplied, FormatSpec, + WRITE_WITH_NEWLINE + } else { + PRINT_WITH_NEWLINE }; - const SIMPLE: FormatSpec<'_> = FormatSpec { - fill: None, - align: AlignUnknown, - flags: 0, - precision: CountImplied, - precision_span: None, - width: CountImplied, - width_span: None, - ty: "", - ty_span: None, - }; + span_lint_and_then( + cx, + lint, + macro_call.span, + &format!("using `{name}!()` with a format string that ends in a single newline"), + |diag| { + let name_span = cx.sess().source_map().span_until_char(macro_call.span, '!'); + let Some(format_snippet) = snippet_opt(cx, format_string_span) else { return }; - match arg.position { - ArgumentIs(n) | ArgumentImplicitlyIs(n) => { - if self.unnamed.len() <= n { - // Use a dummy span to mark all unseen arguments. - self.unnamed.resize_with(n, || vec![DUMMY_SP]); - if arg.format == SIMPLE { - self.unnamed.push(vec![span]); - } else { - self.unnamed.push(Vec::new()); - } - } else { - let args = &mut self.unnamed[n]; - match (args.as_mut_slice(), arg.format == SIMPLE) { - // A non-empty format string has been seen already. - ([], _) => (), - // Replace the dummy span, if it exists. - ([dummy @ DUMMY_SP], true) => *dummy = span, - ([_, ..], true) => args.push(span), - ([_, ..], false) => *args = Vec::new(), - } + if format_string_parts.len() == 1 && last.as_str() == "\n" { + // print!("\n"), write!(f, "\n") + + diag.multipart_suggestion( + &format!("use `{name}ln!` instead"), + vec![(name_span, format!("{name}ln")), (format_string_span, String::new())], + Applicability::MachineApplicable, + ); + } else if format_snippet.ends_with("\\n\"") { + // print!("...\n"), write!(f, "...\n") + + let hi = format_string_span.hi(); + let newline_span = format_string_span.with_lo(hi - BytePos(3)).with_hi(hi - BytePos(1)); + + diag.multipart_suggestion( + &format!("use `{name}ln!` instead"), + vec![(name_span, format!("{name}ln")), (newline_span, String::new())], + Applicability::MachineApplicable, + ); } }, - ArgumentNamed(n) => { - let n = Symbol::intern(n); - if let Some(x) = self.named.iter_mut().find(|x| x.0 == n) { - match x.1.as_slice() { - // A non-empty format string has been seen already. - [] => (), - [_, ..] if arg.format == SIMPLE => x.1.push(span), - [_, ..] => x.1 = Vec::new(), - } - } else if arg.format == SIMPLE { - self.named.push((n, vec![span])); - } else { - self.named.push((n, Vec::new())); - } - }, - }; - } - - fn push_to_complex(&mut self, span: Span, position: usize) { - if self.complex_unnamed.len() <= position { - self.complex_unnamed.resize_with(position, Vec::new); - self.complex_unnamed.push(vec![span]); - } else { - let args: &mut Vec = &mut self.complex_unnamed[position]; - args.push(span); - } - } - - fn push_complex( - &mut self, - cx: &EarlyContext<'_>, - arg: rustc_parse_format::Argument<'_>, - str_lit_span: Span, - fmt_span: Span, - ) { - use rustc_parse_format::{ArgumentImplicitlyIs, ArgumentIs, CountIsParam, CountIsStar}; - - let snippet = snippet_opt(cx, fmt_span); - - let end = snippet - .as_ref() - .and_then(|s| s.find(':')) - .or_else(|| fmt_span.hi().0.checked_sub(fmt_span.lo().0 + 1).map(|u| u as usize)); - - if let (ArgumentIs(n) | ArgumentImplicitlyIs(n), Some(end)) = (arg.position, end) { - let span = fmt_span.from_inner(InnerSpan::new(1, end)); - self.push_to_complex(span, n); - }; - - if let (CountIsParam(n) | CountIsStar(n), Some(span)) = (arg.format.precision, arg.format.precision_span) { - // We need to do this hack as precision spans should be converted from .* to .foo$ - let hack = if snippet.as_ref().and_then(|s| s.find('*')).is_some() { - 0 - } else { - 1 - }; - - let span = str_lit_span.from_inner(InnerSpan { - start: span.start + 1, - end: span.end - hack, - }); - self.push_to_complex(span, n); - }; - - if let (CountIsParam(n), Some(span)) = (arg.format.width, arg.format.width_span) { - let span = str_lit_span.from_inner(InnerSpan { - start: span.start, - end: span.end - 1, - }); - self.push_to_complex(span, n); - }; + ); } } -impl Write { - /// Parses a format string into a collection of spans for each argument. This only keeps track - /// of empty format arguments. Will also lint usages of debug format strings outside of debug - /// impls. - fn parse_fmt_string(&self, cx: &EarlyContext<'_>, str_lit: &StrLit) -> Option { - use rustc_parse_format::{ParseMode, Parser, Piece}; +fn check_empty_string(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, macro_call: &MacroCall, name: &str) { + if let [part] = &format_args.format_string.parts[..] + && let mut span = format_args.format_string.span + && part.as_str() == "\n" + { + let lint = if name == "writeln" { + span = expand_past_previous_comma(cx, span); - let str_sym = str_lit.symbol_unescaped.as_str(); - let style = match str_lit.style { - StrStyle::Cooked => None, - StrStyle::Raw(n) => Some(n as usize), - }; - - let mut parser = Parser::new(str_sym, style, snippet_opt(cx, str_lit.span), false, ParseMode::Format); - let mut args = SimpleFormatArgs::default(); - - while let Some(arg) = parser.next() { - let arg = match arg { - Piece::String(_) => continue, - Piece::NextArgument(arg) => arg, - }; - let span = parser - .arg_places - .last() - .map_or(DUMMY_SP, |&x| str_lit.span.from_inner(InnerSpan::new(x.start, x.end))); - - if !self.in_debug_impl && arg.format.ty == "?" { - // FIXME: modify rustc's fmt string parser to give us the current span - span_lint(cx, USE_DEBUG, span, "use of `Debug`-based formatting"); - } - args.push(arg, span); - args.push_complex(cx, arg, str_lit.span, span); - } - - parser.errors.is_empty().then_some(args) - } - - /// Checks the arguments of `print[ln]!` and `write[ln]!` calls. It will return a tuple of two - /// `Option`s. The first `Option` of the tuple is the macro's format string. It includes - /// the contents of the string, whether it's a raw string, and the span of the literal in the - /// source. The second `Option` in the tuple is, in the `write[ln]!` case, the expression the - /// `format_str` should be written to. - /// - /// Example: - /// - /// Calling this function on - /// ```rust - /// # use std::fmt::Write; - /// # let mut buf = String::new(); - /// # let something = "something"; - /// writeln!(buf, "string to write: {}", something); - /// ``` - /// will return - /// ```rust,ignore - /// (Some("string to write: {}"), Some(buf)) - /// ``` - fn check_tts<'a>(&self, cx: &EarlyContext<'a>, tts: TokenStream, is_write: bool) -> (Option, Option) { - let mut parser = parser::Parser::new(&cx.sess().parse_sess, tts, false, None); - let expr = if is_write { - match parser - .parse_expr() - .map(rustc_ast::ptr::P::into_inner) - .map_err(DiagnosticBuilder::cancel) - { - // write!(e, ...) - Ok(p) if parser.eat(&token::Comma) => Some(p), - // write!(e) or error - e => return (None, e.ok()), - } + WRITELN_EMPTY_STRING } else { - None + PRINTLN_EMPTY_STRING }; - let fmtstr = match parser.parse_str_lit() { - Ok(fmtstr) => fmtstr, - Err(_) => return (None, expr), - }; - - let args = match self.parse_fmt_string(cx, &fmtstr) { - Some(args) => args, - None => return (Some(fmtstr), expr), - }; - - let lint = if is_write { WRITE_LITERAL } else { PRINT_LITERAL }; - let mut unnamed_args = args.get_unnamed(); - let mut complex_unnamed_args = args.get_complex_unnamed(); - loop { - if !parser.eat(&token::Comma) { - return (Some(fmtstr), expr); - } - - let comma_span = parser.prev_token.span; - let token_expr = if let Ok(expr) = parser.parse_expr().map_err(DiagnosticBuilder::cancel) { - expr - } else { - return (Some(fmtstr), None); - }; - let complex_unnamed_arg = complex_unnamed_args.next(); - - let (fmt_spans, lit) = match &token_expr.kind { - ExprKind::Lit(lit) => (unnamed_args.next().unwrap_or(&[]), lit), - ExprKind::Assign(lhs, rhs, _) => { - if let Some(span) = complex_unnamed_arg { - for x in span { - Self::report_positional_named_param(cx, *x, lhs, rhs); - } - } - match (&lhs.kind, &rhs.kind) { - (ExprKind::Path(_, p), ExprKind::Lit(lit)) => (args.get_named(p), lit), - _ => continue, - } - }, - _ => { - unnamed_args.next(); - continue; - }, - }; - - let replacement: String = match lit.token_lit.kind { - LitKind::StrRaw(_) | LitKind::ByteStrRaw(_) if matches!(fmtstr.style, StrStyle::Raw(_)) => { - lit.token_lit.symbol.as_str().replace('{', "{{").replace('}', "}}") - }, - LitKind::Str | LitKind::ByteStr if matches!(fmtstr.style, StrStyle::Cooked) => { - lit.token_lit.symbol.as_str().replace('{', "{{").replace('}', "}}") - }, - LitKind::StrRaw(_) - | LitKind::Str - | LitKind::ByteStrRaw(_) - | LitKind::ByteStr - | LitKind::Integer - | LitKind::Float - | LitKind::Err => continue, - LitKind::Byte | LitKind::Char => match lit.token_lit.symbol.as_str() { - "\"" if matches!(fmtstr.style, StrStyle::Cooked) => "\\\"", - "\"" if matches!(fmtstr.style, StrStyle::Raw(0)) => continue, - "\\\\" if matches!(fmtstr.style, StrStyle::Raw(_)) => "\\", - "\\'" => "'", - "{" => "{{", - "}" => "}}", - x if matches!(fmtstr.style, StrStyle::Raw(_)) && x.starts_with('\\') => continue, - x => x, - } - .into(), - LitKind::Bool => lit.token_lit.symbol.as_str().deref().into(), - }; - - if !fmt_spans.is_empty() { - span_lint_and_then( - cx, - lint, - token_expr.span, - "literal with an empty format string", - |diag| { - diag.multipart_suggestion( - "try this", - iter::once((comma_span.to(token_expr.span), String::new())) - .chain(fmt_spans.iter().copied().zip(iter::repeat(replacement))) - .collect(), - Applicability::MachineApplicable, - ); - }, - ); - } - } - } - - fn report_positional_named_param(cx: &EarlyContext<'_>, span: Span, lhs: &P, _rhs: &P) { - if let ExprKind::Path(_, _p) = &lhs.kind { - let mut applicability = Applicability::MachineApplicable; - let name = snippet_with_applicability(cx, lhs.span, "name", &mut applicability); - // We need to do this hack as precision spans should be converted from .* to .foo$ - let hack = snippet(cx, span, "").contains('*'); - - span_lint_and_sugg( - cx, - POSITIONAL_NAMED_FORMAT_PARAMETERS, - span, - &format!("named parameter {} is used as a positional parameter", name), - "replace it with", - if hack { - format!("{}$", name) - } else { - format!("{}", name) - }, - applicability, - ); - }; - } - - fn lint_println_empty_string(&self, cx: &EarlyContext<'_>, mac: &MacCall) { - if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) { - if fmt_str.symbol == kw::Empty { - let name = mac.path.segments[0].ident.name; - span_lint_and_sugg( - cx, - PRINTLN_EMPTY_STRING, - mac.span(), - &format!("using `{}!(\"\")`", name), - "replace it with", - format!("{}!()", name), + span_lint_and_then( + cx, + lint, + macro_call.span, + &format!("empty string literal in `{name}!`"), + |diag| { + diag.span_suggestion( + span, + "remove the empty string", + String::new(), Applicability::MachineApplicable, ); - } - } + }, + ); + } +} + +fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, name: &str) { + let mut counts = HirIdMap::::default(); + for param in format_args.params() { + *counts.entry(param.value.hir_id).or_default() += 1; } - fn lint_print_with_newline(&self, cx: &EarlyContext<'_>, mac: &MacCall) { - if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) { - if check_newlines(&fmt_str) { - let name = mac.path.segments[0].ident.name; - let suggested = format!("{}ln", name); - span_lint_and_then( - cx, - PRINT_WITH_NEWLINE, - mac.span(), - &format!("using `{}!()` with a format string that ends in a single newline", name), - |err| { - err.multipart_suggestion( - &format!("use `{}!` instead", suggested), - vec![(mac.path.span, suggested), (newline_span(&fmt_str).0, String::new())], + for arg in &format_args.args { + let value = arg.param.value; + + if counts[&value.hir_id] == 1 + && arg.format.is_default() + && let ExprKind::Lit(lit) = &value.kind + && !value.span.from_expansion() + && let Some(value_string) = snippet_opt(cx, value.span) + { + let (replacement, replace_raw) = match lit.node { + LitKind::Str(..) => extract_str_literal(&value_string), + LitKind::Char(ch) => ( + match ch { + '"' => "\\\"", + '\'' => "'", + _ => &value_string[1..value_string.len() - 1], + } + .to_string(), + false, + ), + LitKind::Bool(b) => (b.to_string(), false), + _ => continue, + }; + + let lint = if name.starts_with("write") { + WRITE_LITERAL + } else { + PRINT_LITERAL + }; + + let format_string_is_raw = format_args.format_string.style.is_some(); + let replacement = match (format_string_is_raw, replace_raw) { + (false, false) => Some(replacement), + (false, true) => Some(replacement.replace('"', "\\\"").replace('\\', "\\\\")), + (true, false) => match conservative_unescape(&replacement) { + Ok(unescaped) => Some(unescaped), + Err(UnescapeErr::Lint) => None, + Err(UnescapeErr::Ignore) => continue, + }, + (true, true) => { + if replacement.contains(['#', '"']) { + None + } else { + Some(replacement) + } + }, + }; + + span_lint_and_then( + cx, + lint, + value.span, + "literal with an empty format string", + |diag| { + if let Some(replacement) = replacement { + // `format!("{}", "a")`, `format!("{named}", named = "b") + // ~~~~~ ~~~~~~~~~~~~~ + let value_span = expand_past_previous_comma(cx, value.span); + + let replacement = replacement.replace('{', "{{").replace('}', "}}"); + diag.multipart_suggestion( + "try this", + vec![(arg.span, replacement), (value_span, String::new())], Applicability::MachineApplicable, ); - }, - ); - } + } + }, + ); } } } -/// Checks if the format string contains a single newline that terminates it. +/// Removes the raw marker, `#`s and quotes from a str, and returns if the literal is raw /// -/// Literal and escaped newlines are both checked (only literal for raw strings). -fn check_newlines(fmtstr: &StrLit) -> bool { - let mut has_internal_newline = false; - let mut last_was_cr = false; - let mut should_lint = false; - - let contents = fmtstr.symbol.as_str(); - - let mut cb = |r: Range, c: Result| { - let c = match c { - Ok(c) => c, - Err(e) if !e.is_fatal() => return, - Err(e) => panic!("{:?}", e), - }; - - if r.end == contents.len() && c == '\n' && !last_was_cr && !has_internal_newline { - should_lint = true; - } else { - last_was_cr = c == '\r'; - if c == '\n' { - has_internal_newline = true; - } - } +/// `r#"a"#` -> (`a`, true) +/// +/// `"b"` -> (`b`, false) +fn extract_str_literal(literal: &str) -> (String, bool) { + let (literal, raw) = match literal.strip_prefix('r') { + Some(stripped) => (stripped.trim_matches('#'), true), + None => (literal, false), }; - match fmtstr.style { - StrStyle::Cooked => unescape::unescape_literal(contents, unescape::Mode::Str, &mut cb), - StrStyle::Raw(_) => unescape::unescape_literal(contents, unescape::Mode::RawStr, &mut cb), + (literal[1..literal.len() - 1].to_string(), raw) +} + +enum UnescapeErr { + /// Should still be linted, can be manually resolved by author, e.g. + /// + /// ```ignore + /// print!(r"{}", '"'); + /// ``` + Lint, + /// Should not be linted, e.g. + /// + /// ```ignore + /// print!(r"{}", '\r'); + /// ``` + Ignore, +} + +/// Unescape a normal string into a raw string +fn conservative_unescape(literal: &str) -> Result { + let mut unescaped = String::with_capacity(literal.len()); + let mut chars = literal.chars(); + let mut err = false; + + while let Some(ch) = chars.next() { + match ch { + '#' => err = true, + '\\' => match chars.next() { + Some('\\') => unescaped.push('\\'), + Some('"') => err = true, + _ => return Err(UnescapeErr::Ignore), + }, + _ => unescaped.push(ch), + } } - should_lint + if err { Err(UnescapeErr::Lint) } else { Ok(unescaped) } +} + +// Expand from `writeln!(o, "")` to `writeln!(o, "")` +// ^^ ^^^^ +fn expand_past_previous_comma(cx: &LateContext<'_>, span: Span) -> Span { + let extended = cx.sess().source_map().span_extend_to_prev_char(span, ',', true); + extended.with_lo(extended.lo() - BytePos(1)) } diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs index bd89ff977f87..8855b7394801 100644 --- a/clippy_utils/src/macros.rs +++ b/clippy_utils/src/macros.rs @@ -711,9 +711,14 @@ impl<'tcx> FormatSpec<'tcx> { }) } - /// Returns true if this format spec would change the contents of a string when formatted - pub fn has_string_formatting(&self) -> bool { - self.r#trait != sym::Display || !self.width.is_implied() || !self.precision.is_implied() + /// Returns true if this format spec is unchanged from the default. e.g. returns true for `{}`, + /// `{foo}` and `{2}`, but false for `{:?}`, `{foo:5}` and `{3:.5}` + pub fn is_default(&self) -> bool { + self.r#trait == sym::Display + && self.width.is_implied() + && self.precision.is_implied() + && self.align == Alignment::AlignUnknown + && self.flags == 0 } } diff --git a/src/docs.rs b/src/docs.rs index f3a5048e7fa8..9f6f1fb47276 100644 --- a/src/docs.rs +++ b/src/docs.rs @@ -391,7 +391,6 @@ docs! { "partialeq_to_none", "path_buf_push_overwrite", "pattern_type_mismatch", - "positional_named_format_parameters", "possible_missing_comma", "precedence", "print_in_format_impl", diff --git a/src/docs/positional_named_format_parameters.txt b/src/docs/positional_named_format_parameters.txt deleted file mode 100644 index e391d2406677..000000000000 --- a/src/docs/positional_named_format_parameters.txt +++ /dev/null @@ -1,15 +0,0 @@ -### What it does -This lint warns when a named parameter in a format string is used as a positional one. - -### Why is this bad? -It may be confused for an assignment and obfuscates which parameter is being used. - -### Example -``` -println!("{}", x = 10); -``` - -Use instead: -``` -println!("{x}", x = 10); -``` \ No newline at end of file diff --git a/src/docs/print_literal.txt b/src/docs/print_literal.txt index 160073414f9a..a6252a68780b 100644 --- a/src/docs/print_literal.txt +++ b/src/docs/print_literal.txt @@ -6,10 +6,6 @@ Using literals as `println!` args is inefficient (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary (i.e., just put the literal in the format string) -### Known problems -Will also warn with macro calls as arguments that expand to literals --- e.g., `println!("{}", env!("FOO"))`. - ### Example ``` println!("{}", "foo"); diff --git a/src/docs/print_stderr.txt b/src/docs/print_stderr.txt index fc14511cd6a6..9c6edeeef125 100644 --- a/src/docs/print_stderr.txt +++ b/src/docs/print_stderr.txt @@ -7,13 +7,7 @@ People often print on *stderr* while debugging an application and might forget to remove those prints afterward. ### Known problems -* Only catches `eprint!` and `eprintln!` calls. -* The lint level is unaffected by crate attributes. The level can still - be set for functions, modules and other items. To change the level for - the entire crate, please use command line flags. More information and a - configuration example can be found in [clippy#6610]. - -[clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558 +Only catches `eprint!` and `eprintln!` calls. ### Example ``` diff --git a/src/docs/print_stdout.txt b/src/docs/print_stdout.txt index 6c9a4b98e1e6..d2cbd811d1b2 100644 --- a/src/docs/print_stdout.txt +++ b/src/docs/print_stdout.txt @@ -7,13 +7,7 @@ People often print on *stdout* while debugging an application and might forget to remove those prints afterward. ### Known problems -* Only catches `print!` and `println!` calls. -* The lint level is unaffected by crate attributes. The level can still - be set for functions, modules and other items. To change the level for - the entire crate, please use command line flags. More information and a - configuration example can be found in [clippy#6610]. - -[clippy#6610]: https://github.com/rust-lang/rust-clippy/issues/6610#issuecomment-977120558 +Only catches `print!` and `println!` calls. ### Example ``` diff --git a/src/docs/write_literal.txt b/src/docs/write_literal.txt index 9c41a48f9f73..a7a884d08711 100644 --- a/src/docs/write_literal.txt +++ b/src/docs/write_literal.txt @@ -6,10 +6,6 @@ Using literals as `writeln!` args is inefficient (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary (i.e., just put the literal in the format string) -### Known problems -Will also warn with macro calls as arguments that expand to literals --- e.g., `writeln!(buf, "{}", env!("FOO"))`. - ### Example ``` writeln!(buf, "{}", "foo"); diff --git a/tests/ui/eprint_with_newline.rs b/tests/ui/eprint_with_newline.rs index 8df32649ad94..de5e121be877 100644 --- a/tests/ui/eprint_with_newline.rs +++ b/tests/ui/eprint_with_newline.rs @@ -45,5 +45,13 @@ fn main() { eprint!("\r\n"); eprint!("foo\r\n"); eprint!("\\r\n"); //~ ERROR - eprint!("foo\rbar\n") // ~ ERROR + eprint!("foo\rbar\n"); + + // Ignore expanded format strings + macro_rules! newline { + () => { + "\n" + }; + } + eprint!(newline!()); } diff --git a/tests/ui/eprint_with_newline.stderr b/tests/ui/eprint_with_newline.stderr index f137787bff0c..0eefb9f0ca97 100644 --- a/tests/ui/eprint_with_newline.stderr +++ b/tests/ui/eprint_with_newline.stderr @@ -83,7 +83,7 @@ LL | | ); help: use `eprintln!` instead | LL ~ eprintln!( -LL ~ "" +LL ~ | error: using `eprint!()` with a format string that ends in a single newline @@ -98,7 +98,7 @@ LL | | ); help: use `eprintln!` instead | LL ~ eprintln!( -LL ~ r"" +LL ~ | error: using `eprint!()` with a format string that ends in a single newline @@ -113,17 +113,5 @@ LL - eprint!("/r/n"); //~ ERROR LL + eprintln!("/r"); //~ ERROR | -error: using `eprint!()` with a format string that ends in a single newline - --> $DIR/eprint_with_newline.rs:48:5 - | -LL | eprint!("foo/rbar/n") // ~ ERROR - | ^^^^^^^^^^^^^^^^^^^^^ - | -help: use `eprintln!` instead - | -LL - eprint!("foo/rbar/n") // ~ ERROR -LL + eprintln!("foo/rbar") // ~ ERROR - | - -error: aborting due to 10 previous errors +error: aborting due to 9 previous errors diff --git a/tests/ui/format.fixed b/tests/ui/format.fixed index b56d6aec508d..e0c5f692740a 100644 --- a/tests/ui/format.fixed +++ b/tests/ui/format.fixed @@ -28,8 +28,6 @@ fn main() { format!("{:?}", "foo"); // Don't warn about `Debug`. format!("{:8}", "foo"); format!("{:width$}", "foo", width = 8); - "foo".to_string(); // Warn when the format makes no difference. - "foo".to_string(); // Warn when the format makes no difference. format!("foo {}", "bar"); format!("{} bar", "foo"); @@ -38,8 +36,6 @@ fn main() { format!("{:?}", arg); // Don't warn about debug. format!("{:8}", arg); format!("{:width$}", arg, width = 8); - arg.to_string(); // Warn when the format makes no difference. - arg.to_string(); // Warn when the format makes no difference. format!("foo {}", arg); format!("{} bar", arg); diff --git a/tests/ui/format.rs b/tests/ui/format.rs index 4c1a3a840ed9..ff83cd64bf09 100644 --- a/tests/ui/format.rs +++ b/tests/ui/format.rs @@ -30,8 +30,6 @@ fn main() { format!("{:?}", "foo"); // Don't warn about `Debug`. format!("{:8}", "foo"); format!("{:width$}", "foo", width = 8); - format!("{:+}", "foo"); // Warn when the format makes no difference. - format!("{:<}", "foo"); // Warn when the format makes no difference. format!("foo {}", "bar"); format!("{} bar", "foo"); @@ -40,8 +38,6 @@ fn main() { format!("{:?}", arg); // Don't warn about debug. format!("{:8}", arg); format!("{:width$}", arg, width = 8); - format!("{:+}", arg); // Warn when the format makes no difference. - format!("{:<}", arg); // Warn when the format makes no difference. format!("foo {}", arg); format!("{} bar", arg); diff --git a/tests/ui/format.stderr b/tests/ui/format.stderr index 6c35caeb034d..0ef0ac655d39 100644 --- a/tests/ui/format.stderr +++ b/tests/ui/format.stderr @@ -46,82 +46,58 @@ LL | format!("{}", "foo"); | ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` error: useless use of `format!` - --> $DIR/format.rs:33:5 - | -LL | format!("{:+}", "foo"); // Warn when the format makes no difference. - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` - -error: useless use of `format!` - --> $DIR/format.rs:34:5 - | -LL | format!("{:<}", "foo"); // Warn when the format makes no difference. - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` - -error: useless use of `format!` - --> $DIR/format.rs:39:5 + --> $DIR/format.rs:37:5 | LL | format!("{}", arg); | ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()` error: useless use of `format!` - --> $DIR/format.rs:43:5 - | -LL | format!("{:+}", arg); // Warn when the format makes no difference. - | ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()` - -error: useless use of `format!` - --> $DIR/format.rs:44:5 - | -LL | format!("{:<}", arg); // Warn when the format makes no difference. - | ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()` - -error: useless use of `format!` - --> $DIR/format.rs:71:5 + --> $DIR/format.rs:67:5 | LL | format!("{}", 42.to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()` error: useless use of `format!` - --> $DIR/format.rs:73:5 + --> $DIR/format.rs:69:5 | LL | format!("{}", x.display().to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()` error: useless use of `format!` - --> $DIR/format.rs:77:18 + --> $DIR/format.rs:73:18 | LL | let _ = Some(format!("{}", a + "bar")); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `a + "bar"` error: useless use of `format!` - --> $DIR/format.rs:81:22 + --> $DIR/format.rs:77:22 | LL | let _s: String = format!("{}", &*v.join("/n")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("/n")).to_string()` error: useless use of `format!` - --> $DIR/format.rs:87:13 + --> $DIR/format.rs:83:13 | LL | let _ = format!("{x}"); | ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()` error: useless use of `format!` - --> $DIR/format.rs:89:13 + --> $DIR/format.rs:85:13 | LL | let _ = format!("{y}", y = x); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()` error: useless use of `format!` - --> $DIR/format.rs:93:13 + --> $DIR/format.rs:89:13 | LL | let _ = format!("{abc}"); | ^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `abc.to_string()` error: useless use of `format!` - --> $DIR/format.rs:95:13 + --> $DIR/format.rs:91:13 | LL | let _ = format!("{xx}"); | ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `xx.to_string()` -error: aborting due to 19 previous errors +error: aborting due to 15 previous errors diff --git a/tests/ui/positional_named_format_parameters.fixed b/tests/ui/positional_named_format_parameters.fixed deleted file mode 100644 index 4170e1098204..000000000000 --- a/tests/ui/positional_named_format_parameters.fixed +++ /dev/null @@ -1,56 +0,0 @@ -// run-rustfix -#![allow(unused_must_use)] -#![allow(named_arguments_used_positionally)] // Unstable at time of writing. -#![warn(clippy::positional_named_format_parameters)] - -use std::io::Write; - -fn main() { - let mut v = Vec::new(); - let hello = "Hello"; - - println!("{hello:.foo$}", foo = 2); - writeln!(v, "{hello:.foo$}", foo = 2); - - // Warnings - println!("{zero} {one:?}", zero = 0, one = 1); - println!("This is a test {zero} {one:?}", zero = 0, one = 1); - println!("Hello {one} is {two:.zero$}", zero = 5, one = hello, two = 0.01); - println!("Hello {one:zero$}!", zero = 5, one = 1); - println!("Hello {zero:one$}!", zero = 4, one = 1); - println!("Hello {zero:0one$}!", zero = 4, one = 1); - println!("Hello is {one:.zero$}", zero = 5, one = 0.01); - println!("Hello is {one:<6.zero$}", zero = 5, one = 0.01); - println!("{zero}, `{two:>8.one$}` has 3", zero = hello, one = 3, two = hello); - println!("Hello {one} is {two:.zero$}", zero = 5, one = hello, two = 0.01); - println!("Hello {world} {world}!", world = 5); - - writeln!(v, "{zero} {one:?}", zero = 0, one = 1); - writeln!(v, "This is a test {zero} {one:?}", zero = 0, one = 1); - writeln!(v, "Hello {one} is {two:.zero$}", zero = 5, one = hello, two = 0.01); - writeln!(v, "Hello {one:zero$}!", zero = 4, one = 1); - writeln!(v, "Hello {zero:one$}!", zero = 4, one = 1); - writeln!(v, "Hello {zero:0one$}!", zero = 4, one = 1); - writeln!(v, "Hello is {one:.zero$}", zero = 3, one = 0.01); - writeln!(v, "Hello is {one:<6.zero$}", zero = 2, one = 0.01); - writeln!(v, "{zero}, `{two:>8.one$}` has 3", zero = hello, one = 3, two = hello); - writeln!(v, "Hello {one} is {two:.zero$}", zero = 1, one = hello, two = 0.01); - writeln!(v, "Hello {world} {world}!", world = 0); - - // Tests from other files - println!("{w:w$}", w = 1); - println!("{p:.p$}", p = 1); - println!("{v}", v = 1); - println!("{v:v$}", v = 1); - println!("{v:v$}", v = 1); - println!("{v:v$.v$}", v = 1); - println!("{v:v$.v$}", v = 1); - println!("{v:v$.v$}", v = 1); - println!("{v:v$.v$}", v = 1); - println!("{v:v$.v$}", v = 1); - println!("{v:v$.v$}", v = 1); - println!("{v:v$.v$}", v = 1); - println!("{w:w$}", w = 1); - println!("{p:.p$}", p = 1); - println!("{:p$.w$}", 1, w = 1, p = 1); -} diff --git a/tests/ui/positional_named_format_parameters.rs b/tests/ui/positional_named_format_parameters.rs deleted file mode 100644 index 553d8494ecc0..000000000000 --- a/tests/ui/positional_named_format_parameters.rs +++ /dev/null @@ -1,56 +0,0 @@ -// run-rustfix -#![allow(unused_must_use)] -#![allow(named_arguments_used_positionally)] // Unstable at time of writing. -#![warn(clippy::positional_named_format_parameters)] - -use std::io::Write; - -fn main() { - let mut v = Vec::new(); - let hello = "Hello"; - - println!("{hello:.foo$}", foo = 2); - writeln!(v, "{hello:.foo$}", foo = 2); - - // Warnings - println!("{} {1:?}", zero = 0, one = 1); - println!("This is a test { } {000001:?}", zero = 0, one = 1); - println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); - println!("Hello {1:0$}!", zero = 5, one = 1); - println!("Hello {0:1$}!", zero = 4, one = 1); - println!("Hello {0:01$}!", zero = 4, one = 1); - println!("Hello is {1:.*}", zero = 5, one = 0.01); - println!("Hello is {:<6.*}", zero = 5, one = 0.01); - println!("{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello); - println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); - println!("Hello {world} {}!", world = 5); - - writeln!(v, "{} {1:?}", zero = 0, one = 1); - writeln!(v, "This is a test { } {000001:?}", zero = 0, one = 1); - writeln!(v, "Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); - writeln!(v, "Hello {1:0$}!", zero = 4, one = 1); - writeln!(v, "Hello {0:1$}!", zero = 4, one = 1); - writeln!(v, "Hello {0:01$}!", zero = 4, one = 1); - writeln!(v, "Hello is {1:.*}", zero = 3, one = 0.01); - writeln!(v, "Hello is {:<6.*}", zero = 2, one = 0.01); - writeln!(v, "{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello); - writeln!(v, "Hello {1} is {2:.0$}", zero = 1, one = hello, two = 0.01); - writeln!(v, "Hello {world} {}!", world = 0); - - // Tests from other files - println!("{:w$}", w = 1); - println!("{:.p$}", p = 1); - println!("{}", v = 1); - println!("{:0$}", v = 1); - println!("{0:0$}", v = 1); - println!("{:0$.0$}", v = 1); - println!("{0:0$.0$}", v = 1); - println!("{0:0$.v$}", v = 1); - println!("{0:v$.0$}", v = 1); - println!("{v:0$.0$}", v = 1); - println!("{v:v$.0$}", v = 1); - println!("{v:0$.v$}", v = 1); - println!("{:w$}", w = 1); - println!("{:.p$}", p = 1); - println!("{:p$.w$}", 1, w = 1, p = 1); -} diff --git a/tests/ui/positional_named_format_parameters.stderr b/tests/ui/positional_named_format_parameters.stderr deleted file mode 100644 index 48ddb6d67ad2..000000000000 --- a/tests/ui/positional_named_format_parameters.stderr +++ /dev/null @@ -1,418 +0,0 @@ -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:16:16 - | -LL | println!("{} {1:?}", zero = 0, one = 1); - | ^ help: replace it with: `zero` - | - = note: `-D clippy::positional-named-format-parameters` implied by `-D warnings` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:16:19 - | -LL | println!("{} {1:?}", zero = 0, one = 1); - | ^ help: replace it with: `one` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:17:31 - | -LL | println!("This is a test { } {000001:?}", zero = 0, one = 1); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:17:35 - | -LL | println!("This is a test { } {000001:?}", zero = 0, one = 1); - | ^^^^^^ help: replace it with: `one` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:18:32 - | -LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:18:22 - | -LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); - | ^ help: replace it with: `one` - -error: named parameter two is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:18:29 - | -LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); - | ^ help: replace it with: `two` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:19:24 - | -LL | println!("Hello {1:0$}!", zero = 5, one = 1); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:19:22 - | -LL | println!("Hello {1:0$}!", zero = 5, one = 1); - | ^ help: replace it with: `one` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:20:22 - | -LL | println!("Hello {0:1$}!", zero = 4, one = 1); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:20:24 - | -LL | println!("Hello {0:1$}!", zero = 4, one = 1); - | ^ help: replace it with: `one` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:21:22 - | -LL | println!("Hello {0:01$}!", zero = 4, one = 1); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:21:25 - | -LL | println!("Hello {0:01$}!", zero = 4, one = 1); - | ^ help: replace it with: `one` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:22:28 - | -LL | println!("Hello is {1:.*}", zero = 5, one = 0.01); - | ^ help: replace it with: `zero$` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:22:25 - | -LL | println!("Hello is {1:.*}", zero = 5, one = 0.01); - | ^ help: replace it with: `one` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:23:29 - | -LL | println!("Hello is {:<6.*}", zero = 5, one = 0.01); - | ^ help: replace it with: `zero$` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:23:25 - | -LL | println!("Hello is {:<6.*}", zero = 5, one = 0.01); - | ^ help: replace it with: `one` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:24:16 - | -LL | println!("{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:24:28 - | -LL | println!("{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello); - | ^ help: replace it with: `one$` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:25:32 - | -LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:25:22 - | -LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); - | ^ help: replace it with: `one` - -error: named parameter two is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:25:29 - | -LL | println!("Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); - | ^ help: replace it with: `two` - -error: named parameter world is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:26:30 - | -LL | println!("Hello {world} {}!", world = 5); - | ^ help: replace it with: `world` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:28:19 - | -LL | writeln!(v, "{} {1:?}", zero = 0, one = 1); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:28:22 - | -LL | writeln!(v, "{} {1:?}", zero = 0, one = 1); - | ^ help: replace it with: `one` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:29:34 - | -LL | writeln!(v, "This is a test { } {000001:?}", zero = 0, one = 1); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:29:38 - | -LL | writeln!(v, "This is a test { } {000001:?}", zero = 0, one = 1); - | ^^^^^^ help: replace it with: `one` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:30:35 - | -LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:30:25 - | -LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); - | ^ help: replace it with: `one` - -error: named parameter two is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:30:32 - | -LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 5, one = hello, two = 0.01); - | ^ help: replace it with: `two` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:31:27 - | -LL | writeln!(v, "Hello {1:0$}!", zero = 4, one = 1); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:31:25 - | -LL | writeln!(v, "Hello {1:0$}!", zero = 4, one = 1); - | ^ help: replace it with: `one` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:32:25 - | -LL | writeln!(v, "Hello {0:1$}!", zero = 4, one = 1); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:32:27 - | -LL | writeln!(v, "Hello {0:1$}!", zero = 4, one = 1); - | ^ help: replace it with: `one` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:33:25 - | -LL | writeln!(v, "Hello {0:01$}!", zero = 4, one = 1); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:33:28 - | -LL | writeln!(v, "Hello {0:01$}!", zero = 4, one = 1); - | ^ help: replace it with: `one` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:34:31 - | -LL | writeln!(v, "Hello is {1:.*}", zero = 3, one = 0.01); - | ^ help: replace it with: `zero$` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:34:28 - | -LL | writeln!(v, "Hello is {1:.*}", zero = 3, one = 0.01); - | ^ help: replace it with: `one` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:35:32 - | -LL | writeln!(v, "Hello is {:<6.*}", zero = 2, one = 0.01); - | ^ help: replace it with: `zero$` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:35:28 - | -LL | writeln!(v, "Hello is {:<6.*}", zero = 2, one = 0.01); - | ^ help: replace it with: `one` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:36:19 - | -LL | writeln!(v, "{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:36:31 - | -LL | writeln!(v, "{}, `{two:>8.*}` has 3", zero = hello, one = 3, two = hello); - | ^ help: replace it with: `one$` - -error: named parameter zero is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:37:35 - | -LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 1, one = hello, two = 0.01); - | ^ help: replace it with: `zero` - -error: named parameter one is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:37:25 - | -LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 1, one = hello, two = 0.01); - | ^ help: replace it with: `one` - -error: named parameter two is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:37:32 - | -LL | writeln!(v, "Hello {1} is {2:.0$}", zero = 1, one = hello, two = 0.01); - | ^ help: replace it with: `two` - -error: named parameter world is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:38:33 - | -LL | writeln!(v, "Hello {world} {}!", world = 0); - | ^ help: replace it with: `world` - -error: named parameter w is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:41:16 - | -LL | println!("{:w$}", w = 1); - | ^ help: replace it with: `w` - -error: named parameter p is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:42:16 - | -LL | println!("{:.p$}", p = 1); - | ^ help: replace it with: `p` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:43:16 - | -LL | println!("{}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:44:16 - | -LL | println!("{:0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:44:17 - | -LL | println!("{:0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:45:16 - | -LL | println!("{0:0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:45:18 - | -LL | println!("{0:0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:46:16 - | -LL | println!("{:0$.0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:46:20 - | -LL | println!("{:0$.0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:46:17 - | -LL | println!("{:0$.0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:47:16 - | -LL | println!("{0:0$.0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:47:21 - | -LL | println!("{0:0$.0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:47:18 - | -LL | println!("{0:0$.0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:48:16 - | -LL | println!("{0:0$.v$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:48:18 - | -LL | println!("{0:0$.v$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:49:16 - | -LL | println!("{0:v$.0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:49:21 - | -LL | println!("{0:v$.0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:50:21 - | -LL | println!("{v:0$.0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:50:18 - | -LL | println!("{v:0$.0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:51:21 - | -LL | println!("{v:v$.0$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter v is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:52:18 - | -LL | println!("{v:0$.v$}", v = 1); - | ^ help: replace it with: `v` - -error: named parameter w is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:53:16 - | -LL | println!("{:w$}", w = 1); - | ^ help: replace it with: `w` - -error: named parameter p is used as a positional parameter - --> $DIR/positional_named_format_parameters.rs:54:16 - | -LL | println!("{:.p$}", p = 1); - | ^ help: replace it with: `p` - -error: aborting due to 69 previous errors - diff --git a/tests/ui/print_literal.rs b/tests/ui/print_literal.rs index 8665a3bb28ae..3f6639c14585 100644 --- a/tests/ui/print_literal.rs +++ b/tests/ui/print_literal.rs @@ -20,11 +20,13 @@ fn main() { println!("{} of {:b} people know binary, the other half doesn't", 1, 2); println!("10 / 4 is {}", 2.5); println!("2 + 1 = {}", 3); + println!("From expansion {}", stringify!(not a string literal)); // these should throw warnings print!("Hello {}", "world"); println!("Hello {} {}", world, "world"); println!("Hello {}", "world"); + println!("{} {:.4}", "a literal", 5); // positional args don't change the fact // that we're using a literal -- this should diff --git a/tests/ui/print_literal.stderr b/tests/ui/print_literal.stderr index 72aae0756033..23e6dbc3e341 100644 --- a/tests/ui/print_literal.stderr +++ b/tests/ui/print_literal.stderr @@ -1,5 +1,5 @@ error: literal with an empty format string - --> $DIR/print_literal.rs:25:24 + --> $DIR/print_literal.rs:26:24 | LL | print!("Hello {}", "world"); | ^^^^^^^ @@ -12,7 +12,7 @@ LL + print!("Hello world"); | error: literal with an empty format string - --> $DIR/print_literal.rs:26:36 + --> $DIR/print_literal.rs:27:36 | LL | println!("Hello {} {}", world, "world"); | ^^^^^^^ @@ -24,7 +24,7 @@ LL + println!("Hello {} world", world); | error: literal with an empty format string - --> $DIR/print_literal.rs:27:26 + --> $DIR/print_literal.rs:28:26 | LL | println!("Hello {}", "world"); | ^^^^^^^ @@ -36,7 +36,19 @@ LL + println!("Hello world"); | error: literal with an empty format string - --> $DIR/print_literal.rs:32:25 + --> $DIR/print_literal.rs:29:26 + | +LL | println!("{} {:.4}", "a literal", 5); + | ^^^^^^^^^^^ + | +help: try this + | +LL - println!("{} {:.4}", "a literal", 5); +LL + println!("a literal {:.4}", 5); + | + +error: literal with an empty format string + --> $DIR/print_literal.rs:34:25 | LL | println!("{0} {1}", "hello", "world"); | ^^^^^^^ @@ -48,7 +60,7 @@ LL + println!("hello {1}", "world"); | error: literal with an empty format string - --> $DIR/print_literal.rs:32:34 + --> $DIR/print_literal.rs:34:34 | LL | println!("{0} {1}", "hello", "world"); | ^^^^^^^ @@ -60,19 +72,7 @@ LL + println!("{0} world", "hello"); | error: literal with an empty format string - --> $DIR/print_literal.rs:33:25 - | -LL | println!("{1} {0}", "hello", "world"); - | ^^^^^^^ - | -help: try this - | -LL - println!("{1} {0}", "hello", "world"); -LL + println!("{1} hello", "world"); - | - -error: literal with an empty format string - --> $DIR/print_literal.rs:33:34 + --> $DIR/print_literal.rs:35:34 | LL | println!("{1} {0}", "hello", "world"); | ^^^^^^^ @@ -84,10 +84,22 @@ LL + println!("world {0}", "hello"); | error: literal with an empty format string - --> $DIR/print_literal.rs:36:29 + --> $DIR/print_literal.rs:35:25 + | +LL | println!("{1} {0}", "hello", "world"); + | ^^^^^^^ + | +help: try this + | +LL - println!("{1} {0}", "hello", "world"); +LL + println!("{1} hello", "world"); + | + +error: literal with an empty format string + --> $DIR/print_literal.rs:38:35 | LL | println!("{foo} {bar}", foo = "hello", bar = "world"); - | ^^^^^^^^^^^^^ + | ^^^^^^^ | help: try this | @@ -96,10 +108,10 @@ LL + println!("hello {bar}", bar = "world"); | error: literal with an empty format string - --> $DIR/print_literal.rs:36:44 + --> $DIR/print_literal.rs:38:50 | LL | println!("{foo} {bar}", foo = "hello", bar = "world"); - | ^^^^^^^^^^^^^ + | ^^^^^^^ | help: try this | @@ -108,22 +120,10 @@ LL + println!("{foo} world", foo = "hello"); | error: literal with an empty format string - --> $DIR/print_literal.rs:37:29 + --> $DIR/print_literal.rs:39:50 | LL | println!("{bar} {foo}", foo = "hello", bar = "world"); - | ^^^^^^^^^^^^^ - | -help: try this - | -LL - println!("{bar} {foo}", foo = "hello", bar = "world"); -LL + println!("{bar} hello", bar = "world"); - | - -error: literal with an empty format string - --> $DIR/print_literal.rs:37:44 - | -LL | println!("{bar} {foo}", foo = "hello", bar = "world"); - | ^^^^^^^^^^^^^ + | ^^^^^^^ | help: try this | @@ -131,5 +131,17 @@ LL - println!("{bar} {foo}", foo = "hello", bar = "world"); LL + println!("world {foo}", foo = "hello"); | -error: aborting due to 11 previous errors +error: literal with an empty format string + --> $DIR/print_literal.rs:39:35 + | +LL | println!("{bar} {foo}", foo = "hello", bar = "world"); + | ^^^^^^^ + | +help: try this + | +LL - println!("{bar} {foo}", foo = "hello", bar = "world"); +LL + println!("{bar} hello", bar = "world"); + | + +error: aborting due to 12 previous errors diff --git a/tests/ui/print_with_newline.rs b/tests/ui/print_with_newline.rs index a43a1fc4f524..b8c29d207ada 100644 --- a/tests/ui/print_with_newline.rs +++ b/tests/ui/print_with_newline.rs @@ -48,5 +48,13 @@ fn main() { print!("\r\n"); print!("foo\r\n"); print!("\\r\n"); //~ ERROR - print!("foo\rbar\n") // ~ ERROR + print!("foo\rbar\n"); + + // Ignore expanded format strings + macro_rules! newline { + () => { + "\n" + }; + } + print!(newline!()); } diff --git a/tests/ui/print_with_newline.stderr b/tests/ui/print_with_newline.stderr index edbaa1cdf979..b9f5675faec7 100644 --- a/tests/ui/print_with_newline.stderr +++ b/tests/ui/print_with_newline.stderr @@ -83,7 +83,7 @@ LL | | ); help: use `println!` instead | LL ~ println!( -LL ~ "" +LL ~ | error: using `print!()` with a format string that ends in a single newline @@ -98,7 +98,7 @@ LL | | ); help: use `println!` instead | LL ~ println!( -LL ~ r"" +LL ~ | error: using `print!()` with a format string that ends in a single newline @@ -113,17 +113,5 @@ LL - print!("/r/n"); //~ ERROR LL + println!("/r"); //~ ERROR | -error: using `print!()` with a format string that ends in a single newline - --> $DIR/print_with_newline.rs:51:5 - | -LL | print!("foo/rbar/n") // ~ ERROR - | ^^^^^^^^^^^^^^^^^^^^ - | -help: use `println!` instead - | -LL - print!("foo/rbar/n") // ~ ERROR -LL + println!("foo/rbar") // ~ ERROR - | - -error: aborting due to 10 previous errors +error: aborting due to 9 previous errors diff --git a/tests/ui/println_empty_string.stderr b/tests/ui/println_empty_string.stderr index 17fe4ea74790..3cc8bb947bd3 100644 --- a/tests/ui/println_empty_string.stderr +++ b/tests/ui/println_empty_string.stderr @@ -1,28 +1,36 @@ -error: using `println!("")` +error: empty string literal in `println!` --> $DIR/println_empty_string.rs:6:5 | LL | println!(""); - | ^^^^^^^^^^^^ help: replace it with: `println!()` + | ^^^^^^^^^--^ + | | + | help: remove the empty string | = note: `-D clippy::println-empty-string` implied by `-D warnings` -error: using `println!("")` +error: empty string literal in `println!` --> $DIR/println_empty_string.rs:9:14 | LL | _ => println!(""), - | ^^^^^^^^^^^^ help: replace it with: `println!()` + | ^^^^^^^^^--^ + | | + | help: remove the empty string -error: using `eprintln!("")` +error: empty string literal in `eprintln!` --> $DIR/println_empty_string.rs:13:5 | LL | eprintln!(""); - | ^^^^^^^^^^^^^ help: replace it with: `eprintln!()` + | ^^^^^^^^^^--^ + | | + | help: remove the empty string -error: using `eprintln!("")` +error: empty string literal in `eprintln!` --> $DIR/println_empty_string.rs:16:14 | LL | _ => eprintln!(""), - | ^^^^^^^^^^^^^ help: replace it with: `eprintln!()` + | ^^^^^^^^^^--^ + | | + | help: remove the empty string error: aborting due to 4 previous errors diff --git a/tests/ui/rename.fixed b/tests/ui/rename.fixed index 9cbad2269a09..a6e7bdba77c6 100644 --- a/tests/ui/rename.fixed +++ b/tests/ui/rename.fixed @@ -32,6 +32,7 @@ #![allow(invalid_value)] #![allow(enum_intrinsics_non_enums)] #![allow(non_fmt_panics)] +#![allow(named_arguments_used_positionally)] #![allow(temporary_cstring_as_ptr)] #![allow(unknown_lints)] #![allow(unused_labels)] @@ -69,6 +70,7 @@ #![warn(invalid_value)] #![warn(enum_intrinsics_non_enums)] #![warn(non_fmt_panics)] +#![warn(named_arguments_used_positionally)] #![warn(temporary_cstring_as_ptr)] #![warn(unknown_lints)] #![warn(unused_labels)] diff --git a/tests/ui/rename.rs b/tests/ui/rename.rs index 9153c0dab029..e8f57597d02b 100644 --- a/tests/ui/rename.rs +++ b/tests/ui/rename.rs @@ -32,6 +32,7 @@ #![allow(invalid_value)] #![allow(enum_intrinsics_non_enums)] #![allow(non_fmt_panics)] +#![allow(named_arguments_used_positionally)] #![allow(temporary_cstring_as_ptr)] #![allow(unknown_lints)] #![allow(unused_labels)] @@ -69,6 +70,7 @@ #![warn(clippy::invalid_ref)] #![warn(clippy::mem_discriminant_non_enum)] #![warn(clippy::panic_params)] +#![warn(clippy::positional_named_format_parameters)] #![warn(clippy::temporary_cstring_as_ptr)] #![warn(clippy::unknown_clippy_lints)] #![warn(clippy::unused_label)] diff --git a/tests/ui/rename.stderr b/tests/ui/rename.stderr index 9c03ea914bb6..31865a7f66d6 100644 --- a/tests/ui/rename.stderr +++ b/tests/ui/rename.stderr @@ -1,5 +1,5 @@ error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` - --> $DIR/rename.rs:38:9 + --> $DIR/rename.rs:39:9 | LL | #![warn(clippy::blacklisted_name)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` @@ -7,220 +7,226 @@ LL | #![warn(clippy::blacklisted_name)] = note: `-D renamed-and-removed-lints` implied by `-D warnings` error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:39:9 + --> $DIR/rename.rs:40:9 | LL | #![warn(clippy::block_in_if_condition_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:40:9 + --> $DIR/rename.rs:41:9 | LL | #![warn(clippy::block_in_if_condition_stmt)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` - --> $DIR/rename.rs:41:9 + --> $DIR/rename.rs:42:9 | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> $DIR/rename.rs:42:9 + --> $DIR/rename.rs:43:9 | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> $DIR/rename.rs:43:9 + --> $DIR/rename.rs:44:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> $DIR/rename.rs:44:9 + --> $DIR/rename.rs:45:9 | LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` - --> $DIR/rename.rs:45:9 + --> $DIR/rename.rs:46:9 | LL | #![warn(clippy::disallowed_type)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` - --> $DIR/rename.rs:46:9 + --> $DIR/rename.rs:47:9 | LL | #![warn(clippy::eval_order_dependence)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` error: lint `clippy::for_loop_over_option` has been renamed to `clippy::for_loops_over_fallibles` - --> $DIR/rename.rs:47:9 + --> $DIR/rename.rs:48:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `clippy::for_loops_over_fallibles` - --> $DIR/rename.rs:48:9 + --> $DIR/rename.rs:49:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> $DIR/rename.rs:49:9 + --> $DIR/rename.rs:50:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> $DIR/rename.rs:50:9 + --> $DIR/rename.rs:51:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` - --> $DIR/rename.rs:51:9 + --> $DIR/rename.rs:52:9 | LL | #![warn(clippy::logic_bug)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> $DIR/rename.rs:52:9 + --> $DIR/rename.rs:53:9 | LL | #![warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` - --> $DIR/rename.rs:53:9 + --> $DIR/rename.rs:54:9 | LL | #![warn(clippy::option_and_then_some)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:54:9 + --> $DIR/rename.rs:55:9 | LL | #![warn(clippy::option_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:55:9 + --> $DIR/rename.rs:56:9 | LL | #![warn(clippy::option_map_unwrap_or)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:56:9 + --> $DIR/rename.rs:57:9 | LL | #![warn(clippy::option_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:57:9 + --> $DIR/rename.rs:58:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` - --> $DIR/rename.rs:58:9 + --> $DIR/rename.rs:59:9 | LL | #![warn(clippy::ref_in_deref)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:59:9 + --> $DIR/rename.rs:60:9 | LL | #![warn(clippy::result_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:60:9 + --> $DIR/rename.rs:61:9 | LL | #![warn(clippy::result_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:61:9 + --> $DIR/rename.rs:62:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> $DIR/rename.rs:62:9 + --> $DIR/rename.rs:63:9 | LL | #![warn(clippy::single_char_push_str)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> $DIR/rename.rs:63:9 + --> $DIR/rename.rs:64:9 | LL | #![warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` - --> $DIR/rename.rs:64:9 + --> $DIR/rename.rs:65:9 | LL | #![warn(clippy::to_string_in_display)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> $DIR/rename.rs:65:9 + --> $DIR/rename.rs:66:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> $DIR/rename.rs:66:9 + --> $DIR/rename.rs:67:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> $DIR/rename.rs:67:9 + --> $DIR/rename.rs:68:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> $DIR/rename.rs:68:9 + --> $DIR/rename.rs:69:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> $DIR/rename.rs:69:9 + --> $DIR/rename.rs:70:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:70:9 + --> $DIR/rename.rs:71:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> $DIR/rename.rs:71:9 + --> $DIR/rename.rs:72:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` +error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` + --> $DIR/rename.rs:73:9 + | +LL | #![warn(clippy::positional_named_format_parameters)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` + error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> $DIR/rename.rs:72:9 + --> $DIR/rename.rs:74:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> $DIR/rename.rs:73:9 + --> $DIR/rename.rs:75:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> $DIR/rename.rs:74:9 + --> $DIR/rename.rs:76:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` -error: aborting due to 37 previous errors +error: aborting due to 38 previous errors diff --git a/tests/ui/write_literal.rs b/tests/ui/write_literal.rs index 446691744116..5892818aa9a6 100644 --- a/tests/ui/write_literal.rs +++ b/tests/ui/write_literal.rs @@ -25,11 +25,13 @@ fn main() { writeln!(v, "{} of {:b} people know binary, the other half doesn't", 1, 2); writeln!(v, "10 / 4 is {}", 2.5); writeln!(v, "2 + 1 = {}", 3); + writeln!(v, "From expansion {}", stringify!(not a string literal)); // these should throw warnings write!(v, "Hello {}", "world"); writeln!(v, "Hello {} {}", world, "world"); writeln!(v, "Hello {}", "world"); + writeln!(v, "{} {:.4}", "a literal", 5); // positional args don't change the fact // that we're using a literal -- this should diff --git a/tests/ui/write_literal.stderr b/tests/ui/write_literal.stderr index 3c5ec91d3e0f..1e306ae28a26 100644 --- a/tests/ui/write_literal.stderr +++ b/tests/ui/write_literal.stderr @@ -1,5 +1,5 @@ error: literal with an empty format string - --> $DIR/write_literal.rs:30:27 + --> $DIR/write_literal.rs:31:27 | LL | write!(v, "Hello {}", "world"); | ^^^^^^^ @@ -12,7 +12,7 @@ LL + write!(v, "Hello world"); | error: literal with an empty format string - --> $DIR/write_literal.rs:31:39 + --> $DIR/write_literal.rs:32:39 | LL | writeln!(v, "Hello {} {}", world, "world"); | ^^^^^^^ @@ -24,7 +24,7 @@ LL + writeln!(v, "Hello {} world", world); | error: literal with an empty format string - --> $DIR/write_literal.rs:32:29 + --> $DIR/write_literal.rs:33:29 | LL | writeln!(v, "Hello {}", "world"); | ^^^^^^^ @@ -36,7 +36,19 @@ LL + writeln!(v, "Hello world"); | error: literal with an empty format string - --> $DIR/write_literal.rs:37:28 + --> $DIR/write_literal.rs:34:29 + | +LL | writeln!(v, "{} {:.4}", "a literal", 5); + | ^^^^^^^^^^^ + | +help: try this + | +LL - writeln!(v, "{} {:.4}", "a literal", 5); +LL + writeln!(v, "a literal {:.4}", 5); + | + +error: literal with an empty format string + --> $DIR/write_literal.rs:39:28 | LL | writeln!(v, "{0} {1}", "hello", "world"); | ^^^^^^^ @@ -48,7 +60,7 @@ LL + writeln!(v, "hello {1}", "world"); | error: literal with an empty format string - --> $DIR/write_literal.rs:37:37 + --> $DIR/write_literal.rs:39:37 | LL | writeln!(v, "{0} {1}", "hello", "world"); | ^^^^^^^ @@ -60,19 +72,7 @@ LL + writeln!(v, "{0} world", "hello"); | error: literal with an empty format string - --> $DIR/write_literal.rs:38:28 - | -LL | writeln!(v, "{1} {0}", "hello", "world"); - | ^^^^^^^ - | -help: try this - | -LL - writeln!(v, "{1} {0}", "hello", "world"); -LL + writeln!(v, "{1} hello", "world"); - | - -error: literal with an empty format string - --> $DIR/write_literal.rs:38:37 + --> $DIR/write_literal.rs:40:37 | LL | writeln!(v, "{1} {0}", "hello", "world"); | ^^^^^^^ @@ -84,10 +84,22 @@ LL + writeln!(v, "world {0}", "hello"); | error: literal with an empty format string - --> $DIR/write_literal.rs:41:32 + --> $DIR/write_literal.rs:40:28 + | +LL | writeln!(v, "{1} {0}", "hello", "world"); + | ^^^^^^^ + | +help: try this + | +LL - writeln!(v, "{1} {0}", "hello", "world"); +LL + writeln!(v, "{1} hello", "world"); + | + +error: literal with an empty format string + --> $DIR/write_literal.rs:43:38 | LL | writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); - | ^^^^^^^^^^^^^ + | ^^^^^^^ | help: try this | @@ -96,10 +108,10 @@ LL + writeln!(v, "hello {bar}", bar = "world"); | error: literal with an empty format string - --> $DIR/write_literal.rs:41:47 + --> $DIR/write_literal.rs:43:53 | LL | writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); - | ^^^^^^^^^^^^^ + | ^^^^^^^ | help: try this | @@ -108,22 +120,10 @@ LL + writeln!(v, "{foo} world", foo = "hello"); | error: literal with an empty format string - --> $DIR/write_literal.rs:42:32 + --> $DIR/write_literal.rs:44:53 | LL | writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); - | ^^^^^^^^^^^^^ - | -help: try this - | -LL - writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); -LL + writeln!(v, "{bar} hello", bar = "world"); - | - -error: literal with an empty format string - --> $DIR/write_literal.rs:42:47 - | -LL | writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); - | ^^^^^^^^^^^^^ + | ^^^^^^^ | help: try this | @@ -131,5 +131,17 @@ LL - writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); LL + writeln!(v, "world {foo}", foo = "hello"); | -error: aborting due to 11 previous errors +error: literal with an empty format string + --> $DIR/write_literal.rs:44:38 + | +LL | writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); + | ^^^^^^^ + | +help: try this + | +LL - writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); +LL + writeln!(v, "{bar} hello", bar = "world"); + | + +error: aborting due to 12 previous errors diff --git a/tests/ui/write_literal_2.rs b/tests/ui/write_literal_2.rs index ba0d7be5eaa6..55a11daa1d34 100644 --- a/tests/ui/write_literal_2.rs +++ b/tests/ui/write_literal_2.rs @@ -10,7 +10,7 @@ fn main() { writeln!(v, r"{}", r"{hello}"); writeln!(v, "{}", '\''); writeln!(v, "{}", '"'); - writeln!(v, r"{}", '"'); // don't lint + writeln!(v, r"{}", '"'); writeln!(v, r"{}", '\''); writeln!( v, @@ -24,4 +24,11 @@ fn main() { {} \\ {}", "1", "2", "3", ); + writeln!(v, "{}", "\\"); + writeln!(v, r"{}", "\\"); + writeln!(v, r#"{}"#, "\\"); + writeln!(v, "{}", r"\"); + writeln!(v, "{}", "\r"); + writeln!(v, r#"{}{}"#, '#', '"'); // hard mode + writeln!(v, r"{}", "\r"); // should not lint } diff --git a/tests/ui/write_literal_2.stderr b/tests/ui/write_literal_2.stderr index 9ff297069c40..d5956db9ff0b 100644 --- a/tests/ui/write_literal_2.stderr +++ b/tests/ui/write_literal_2.stderr @@ -47,6 +47,12 @@ LL - writeln!(v, "{}", '"'); LL + writeln!(v, "/""); | +error: literal with an empty format string + --> $DIR/write_literal_2.rs:13:24 + | +LL | writeln!(v, r"{}", '"'); + | ^^^ + error: literal with an empty format string --> $DIR/write_literal_2.rs:14:24 | @@ -108,5 +114,77 @@ LL ~ {} / 3", LL ~ "1", "2", | -error: aborting due to 9 previous errors +error: literal with an empty format string + --> $DIR/write_literal_2.rs:27:23 + | +LL | writeln!(v, "{}", "/"); + | ^^^^ + | +help: try this + | +LL - writeln!(v, "{}", "/"); +LL + writeln!(v, "/"); + | + +error: literal with an empty format string + --> $DIR/write_literal_2.rs:28:24 + | +LL | writeln!(v, r"{}", "/"); + | ^^^^ + | +help: try this + | +LL - writeln!(v, r"{}", "/"); +LL + writeln!(v, r"/"); + | + +error: literal with an empty format string + --> $DIR/write_literal_2.rs:29:26 + | +LL | writeln!(v, r#"{}"#, "/"); + | ^^^^ + | +help: try this + | +LL - writeln!(v, r#"{}"#, "/"); +LL + writeln!(v, r#"/"#); + | + +error: literal with an empty format string + --> $DIR/write_literal_2.rs:30:23 + | +LL | writeln!(v, "{}", r"/"); + | ^^^^ + | +help: try this + | +LL - writeln!(v, "{}", r"/"); +LL + writeln!(v, "/"); + | + +error: literal with an empty format string + --> $DIR/write_literal_2.rs:31:23 + | +LL | writeln!(v, "{}", "/r"); + | ^^^^ + | +help: try this + | +LL - writeln!(v, "{}", "/r"); +LL + writeln!(v, "/r"); + | + +error: literal with an empty format string + --> $DIR/write_literal_2.rs:32:28 + | +LL | writeln!(v, r#"{}{}"#, '#', '"'); // hard mode + | ^^^ + +error: literal with an empty format string + --> $DIR/write_literal_2.rs:32:33 + | +LL | writeln!(v, r#"{}{}"#, '#', '"'); // hard mode + | ^^^ + +error: aborting due to 17 previous errors diff --git a/tests/ui/write_with_newline.rs b/tests/ui/write_with_newline.rs index 446d6914d346..b79364c8758c 100644 --- a/tests/ui/write_with_newline.rs +++ b/tests/ui/write_with_newline.rs @@ -56,4 +56,12 @@ fn main() { write!(v, "foo\r\n"); write!(v, "\\r\n"); //~ ERROR write!(v, "foo\rbar\n"); + + // Ignore expanded format strings + macro_rules! newline { + () => { + "\n" + }; + } + write!(v, newline!()); } diff --git a/tests/ui/write_with_newline.stderr b/tests/ui/write_with_newline.stderr index 5f55431be0bd..2baaea166d8e 100644 --- a/tests/ui/write_with_newline.stderr +++ b/tests/ui/write_with_newline.stderr @@ -5,7 +5,7 @@ LL | write!(v, "Hello/n"); | ^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::write-with-newline` implied by `-D warnings` -help: use `writeln!()` instead +help: use `writeln!` instead | LL - write!(v, "Hello/n"); LL + writeln!(v, "Hello"); @@ -17,7 +17,7 @@ error: using `write!()` with a format string that ends in a single newline LL | write!(v, "Hello {}/n", "world"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use `writeln!()` instead +help: use `writeln!` instead | LL - write!(v, "Hello {}/n", "world"); LL + writeln!(v, "Hello {}", "world"); @@ -29,7 +29,7 @@ error: using `write!()` with a format string that ends in a single newline LL | write!(v, "Hello {} {}/n", "world", "#2"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use `writeln!()` instead +help: use `writeln!` instead | LL - write!(v, "Hello {} {}/n", "world", "#2"); LL + writeln!(v, "Hello {} {}", "world", "#2"); @@ -41,7 +41,7 @@ error: using `write!()` with a format string that ends in a single newline LL | write!(v, "{}/n", 1265); | ^^^^^^^^^^^^^^^^^^^^^^^ | -help: use `writeln!()` instead +help: use `writeln!` instead | LL - write!(v, "{}/n", 1265); LL + writeln!(v, "{}", 1265); @@ -53,7 +53,7 @@ error: using `write!()` with a format string that ends in a single newline LL | write!(v, "/n"); | ^^^^^^^^^^^^^^^ | -help: use `writeln!()` instead +help: use `writeln!` instead | LL - write!(v, "/n"); LL + writeln!(v); @@ -65,7 +65,7 @@ error: using `write!()` with a format string that ends in a single newline LL | write!(v, "//n"); // should fail | ^^^^^^^^^^^^^^^^^ | -help: use `writeln!()` instead +help: use `writeln!` instead | LL - write!(v, "//n"); // should fail LL + writeln!(v, "/"); // should fail @@ -81,11 +81,10 @@ LL | | " LL | | ); | |_____^ | -help: use `writeln!()` instead +help: use `writeln!` instead | LL ~ writeln!( -LL | v, -LL ~ "" +LL ~ v | error: using `write!()` with a format string that ends in a single newline @@ -98,11 +97,10 @@ LL | | " LL | | ); | |_____^ | -help: use `writeln!()` instead +help: use `writeln!` instead | LL ~ writeln!( -LL | v, -LL ~ r"" +LL ~ v | error: using `write!()` with a format string that ends in a single newline @@ -111,23 +109,11 @@ error: using `write!()` with a format string that ends in a single newline LL | write!(v, "/r/n"); //~ ERROR | ^^^^^^^^^^^^^^^^^^ | -help: use `writeln!()` instead +help: use `writeln!` instead | LL - write!(v, "/r/n"); //~ ERROR LL + writeln!(v, "/r"); //~ ERROR | -error: using `write!()` with a format string that ends in a single newline - --> $DIR/write_with_newline.rs:58:5 - | -LL | write!(v, "foo/rbar/n"); - | ^^^^^^^^^^^^^^^^^^^^^^^ - | -help: use `writeln!()` instead - | -LL - write!(v, "foo/rbar/n"); -LL + writeln!(v, "foo/rbar"); - | - -error: aborting due to 10 previous errors +error: aborting due to 9 previous errors diff --git a/tests/ui/writeln_empty_string.stderr b/tests/ui/writeln_empty_string.stderr index ac65aadfc0e8..25e69ec48e7e 100644 --- a/tests/ui/writeln_empty_string.stderr +++ b/tests/ui/writeln_empty_string.stderr @@ -1,16 +1,20 @@ -error: using `writeln!(v, "")` +error: empty string literal in `writeln!` --> $DIR/writeln_empty_string.rs:11:5 | LL | writeln!(v, ""); - | ^^^^^^^^^^^^^^^ help: replace it with: `writeln!(v)` + | ^^^^^^^^^^----^ + | | + | help: remove the empty string | = note: `-D clippy::writeln-empty-string` implied by `-D warnings` -error: using `writeln!(suggestion, "")` +error: empty string literal in `writeln!` --> $DIR/writeln_empty_string.rs:14:5 | LL | writeln!(suggestion, ""); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `writeln!(suggestion)` + | ^^^^^^^^^^^^^^^^^^^----^ + | | + | help: remove the empty string error: aborting due to 2 previous errors From 8b25e53d507f576c03749851d4ecf9a8143c493c Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Thu, 8 Sep 2022 20:42:03 +0000 Subject: [PATCH 4348/5092] Replace u128 with u64 in large_enum_variant uitest A u128 has an 8 byte alignment on x86, but a 16 byte alignment on aarch64 which changes the size of the enums due to extra padding --- tests/ui/large_enum_variant.rs | 4 ++-- tests/ui/large_enum_variant.stderr | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/ui/large_enum_variant.rs b/tests/ui/large_enum_variant.rs index 717009e4c4cc..3b96f09d7b1d 100644 --- a/tests/ui/large_enum_variant.rs +++ b/tests/ui/large_enum_variant.rs @@ -101,12 +101,12 @@ struct Struct2 { #[derive(Copy, Clone)] enum CopyableLargeEnum { A(bool), - B([u128; 4000]), + B([u64; 8000]), } enum ManuallyCopyLargeEnum { A(bool), - B([u128; 4000]), + B([u64; 8000]), } impl Clone for ManuallyCopyLargeEnum { diff --git a/tests/ui/large_enum_variant.stderr b/tests/ui/large_enum_variant.stderr index e1ed2460e08a..a006e3d13b36 100644 --- a/tests/ui/large_enum_variant.stderr +++ b/tests/ui/large_enum_variant.stderr @@ -167,8 +167,8 @@ error: large size difference between variants LL | / enum CopyableLargeEnum { LL | | A(bool), | | ------- the second-largest variant contains at least 1 bytes -LL | | B([u128; 4000]), - | | --------------- the largest variant contains at least 64000 bytes +LL | | B([u64; 8000]), + | | -------------- the largest variant contains at least 64000 bytes LL | | } | |_^ the entire enum is at least 64008 bytes | @@ -180,8 +180,8 @@ LL | enum CopyableLargeEnum { help: consider boxing the large fields to reduce the total size of the enum --> $DIR/large_enum_variant.rs:104:5 | -LL | B([u128; 4000]), - | ^^^^^^^^^^^^^^^ +LL | B([u64; 8000]), + | ^^^^^^^^^^^^^^ error: large size difference between variants --> $DIR/large_enum_variant.rs:107:1 @@ -189,8 +189,8 @@ error: large size difference between variants LL | / enum ManuallyCopyLargeEnum { LL | | A(bool), | | ------- the second-largest variant contains at least 1 bytes -LL | | B([u128; 4000]), - | | --------------- the largest variant contains at least 64000 bytes +LL | | B([u64; 8000]), + | | -------------- the largest variant contains at least 64000 bytes LL | | } | |_^ the entire enum is at least 64008 bytes | @@ -202,8 +202,8 @@ LL | enum ManuallyCopyLargeEnum { help: consider boxing the large fields to reduce the total size of the enum --> $DIR/large_enum_variant.rs:109:5 | -LL | B([u128; 4000]), - | ^^^^^^^^^^^^^^^ +LL | B([u64; 8000]), + | ^^^^^^^^^^^^^^ error: large size difference between variants --> $DIR/large_enum_variant.rs:120:1 From c7fefd522347a57460058c78d0c96b78eac535f7 Mon Sep 17 00:00:00 2001 From: Peh <20146907+randomicon00@users.noreply.github.com> Date: Thu, 8 Sep 2022 22:37:31 +0100 Subject: [PATCH 4349/5092] fix: add semicolon completion to mod --- .../src/completions/.mod_.rs.swp | Bin 0 -> 24576 bytes crates/ide-completion/src/completions/mod_.rs | 20 ++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 crates/ide-completion/src/completions/.mod_.rs.swp diff --git a/crates/ide-completion/src/completions/.mod_.rs.swp b/crates/ide-completion/src/completions/.mod_.rs.swp new file mode 100644 index 0000000000000000000000000000000000000000..52d5cea48b2a7a54bbe6a0cd34a00d38a14829f6 GIT binary patch literal 24576 zcmYc?2=nw+u+TGNU|?VnU|V(P z=HSp$SCFjllAm0fo0?Zrte=>dm{VDmTBMtnUzDw%T$EUnTCAU$k_t8}C$%IqKTp57 zC|Mt5G=y8MpPQc&uUAxz!~9X<(GVC70URMvT9T$~!OLK5WM}|Vp{%5+AS@ILVvgd` z5Eu=C(GVC7fzc2c4S~@R7!85Z5Eu=C5fTC=1uP8p3=9lRQ2$y$X+|`f1k)MGNRn~j0t0viLvN;U?DXf_50 zF*XKsc8XCb2Rww6HQTWV13bII}V^Xs|LcoM2&KsAOSaP-0o816GMFdSiGVA#gQz_6N$fgzKLfx(4|fkA?a zf#EhI1H(K1zK@tTdP|JYC0W)(FlTvf^3QCJJG}NutHLXz;WTq*A)=re>rKA?c zCnpxAmgp6y=4K}6=j7+bm*i)s=4oi^WfsTh<>#epXev~rXwFG3QOGSVQ2^VZV5?AE znv|QLQks(*pO=`Mim*s8Ex#x}H8D9uqXtz;4U&O+X_+}CsYMz!AiXsTim4Tu#U+_} z>G2@Tn7$h2;pPQ`I+ z5BIc!tu2yVNq&4zetvd5D0JXTia~Bf4Q7z>*xiR+6r>*HOAJqfBx)5>bBa@u!W|@t zjB%R@QiUf7LDDd+fd~OmByKngw7kktcO6Q7uu z5}#U8lA2eXnV+YjX^+F3cw$JeAh9SluLPu*n7G1>D5c!|6eW;Hu}I})CMhY@C@AG7 zX6Av_fMN;N#}HqFJcH(T%xEb}Eh#O^1BWaktARo*Gfg42qC`Q_RskH?N=3y=*m5p7 z`{;m_YNF)bg2a*x?7@j@4Jh{`A`&$^Fb#xy+$8l*M9v?w_>z9>JxL=Pkc z&LN--rlE#V3*u|qBTR#qAMv?~1<1t=NEvc5gH}j@LkMALa$;UeW=dj7YCK4vCMXPZ zAtf482?UnYODv8rN=?&1lsQlbAX|=V9I`WrP>jn}AV;aeU6q!ZmkBBs!Hz<5OeUx- zh470J!N~wG6Kc^a0=R+jf;Jwi4-^t0=cdMIrs(AtWu|B5CFX#w(?~9<&`U{z*aAv< z$)!c0+yg4IOLJ27ki!gO7)*yAIF|6+2@5VzIzv+lvI~Sk&I0+f1|nYrs>@1qQb8dE zavI#R;EGJIB(6u&1Z9ep)HDrfd4y~gYW)Y&fR-I0u8&X5OHM5=$uBC_(A3K-$Hr6RHuB4lx=KSULll zC8@dbIhn;JkZwRRs6h;hWlaTLI|cs&P|ahbp=k#VLQqp3sViZnpoSEKkb)<Kg9N*Zfpr1{LuqlU0@x%gt7=eJBDJE#$_lDIGd~aNARU;A znfZC1C8@c{{Nh?`h%v?Bq-14PomgC=qu^Lv;+LP2s-u8NVYSu_wUB)5R^gFYoDrN_ zqN5O$pI_pVSdy5OSPWL2o0OjeN{$f!gGA#~lB}$%gTeJSOr>i@iH<^8T5&*PNk**> z*cX{8sSuT5UPfk-l~pw)x9BK9XowMT=a!^cS%De`)(i~#`id|grWT_ITCpAjsQ>?t zg@NH28>Igao1cFI?fdWHXJFXC&%iK=pMjy4pMjy0pMfC(+W$9#_Wwos85sEa85sEZ z85o%O85pkcF)$qEV_?|I$H1_XkAYzU9|OY_J_d#^J_d$*J_d$bJ_d$NJ_d$ZJ_d$J zJ_ZH{J_ZI2J_ZIcJ_ZJEJ_ZI>J_ZIBJ_d#(ybKIkybKKHybKI1ybKH{c^DX4c^DXC zc^DYNco-Pmc^DX^c^DWtc^DYJaWgPn=VoBo&CS3tgPVb&iJO5To|}Qeg`0svl$(L! z6Bh%+V=e}U<6I03Yq%H~rf@MZv~e*o)N(N})NnB{6mT&xm~k;MsBnuCEsnS+6Wn}dPjCp!bfJ9Y+!7wilS&p~4l>kVP{}aW@ljFW@ljd$;QC&j*Wrg z1sf!upRh47JZ58Hcm#@b8jLB88aWyQqaiRF0)r$3YHJxFjUfmLY8NB*IzU_{<=9wA ztqkJ9aBhl1QeqXPT8D|HRurTrmncR@7bz<-C@JeOq~(DWfrdn|TJZKVvs{nZe zIhep+f+rXxO(2CJNtkzGQfc}5AgQ!G1<;dQhp7wAOUo}RDa}hPNzJL$QAo?kuqj2Q#U;s*(pz6&K}#VoAFd^>C_fi$ zFJue?G0dfqSd^+zP?TSgU!0l(vmUH9xiT4K8Av`cCnvugGDHB16i6b6%uT_xB<7_k zlw>4=I{f7sm0(lT^Yc>_O7bCIEh*1eD9OmoOE0#9X>mgJ71$z$q|6e9;)2xV%)}fW zkb^4~z?Lgy=7PMOnU@X{MDH zi*hQ-tsJOXInttL%ma_`#AoKg#vvgCEAfbu37&Le=@uN6km3lGgrQ{-hzY{rf(Wbx z#DigQ5mbd;xCliUrBnhHMQM2o&>A2z1l4XJA$??dP|gJxE>$3hqqH}wKwIOX z@-Qu^^)ARnP}zkf3sMj2{|j?4Fx-dE|HIbz-{EIqxXsVNuoK$f7w2bS;O1vw;NoXs z_{GP-@Cw?W2le6k_!ty;@iH)Y@-i^6@-i?y;$dJo%EQ30ori&89uEUU z84m+PG!FyAZ*B&LHQWpgq1+4%dfW^QBHRoN-?KvP10N>?!&{i!2T5ad)ET28Fd71*Aut*OqaiRF z0s|fbutpk)MzrfdJP-yiXd7KJr=Xw!p5w+`rUVKk%wPkFf@hXN6O!OHfS~!|(Is;@ zR~>=^42DOS%t43GU;zT6l}4A$X&|o)0)+`^<{z;(475IObjcieIa&?U0%X*ccc2Af z&?PDu3#Z^caXrw?ICMQ9WML6_{S{;s1QhT?ddXa7ejYfGV9T699@0zB&&f$mF0rz* zfiF+6iMO-U(6k26|I0EkFf0Wf03g7?0NcO6gr9+-ou7fBnxBE8il2cYm!E+lo1cLp zi=TnPm7jsZke`7;3OW|>n2&*B5g!9X3LgW5Cm#cY2_FN49v=e(2Xqd90WSkXJ1+x6 zDK7(q8!rQc3NHf#6E6e9ULFR93LXZAR2~KfEgl92DINxftK19>OSl;r`neex+_@PT zEV&sN^tl-r)VUcL)VLWK-b2R;Ky&!9Tnr4+Tnr3RTnr5QTnr4t(0O~%Siv<;28L=* z28IAm28K@@3=EGs7#I$6Ffgp;U|?9n!N9PHgMnco2Lr*clksK3t9ySJs#cT`=-E0gD#cT`=iEIoEVQdTx0c;Em{%i~k z&TI?}LTn5S%xnw{pII3gp0hGA++$^6xXa4GaGRBZ;XEq?!(mnihW)Gz3=3Hq7^bl@ zFic=&VCZLMU}$D#U`S+TUTFfin@FffF&Ffcf?FfdrKFfbUgFfbUhFfgdHFfjaM zW?*>F%)oG;nStRFGXujhW(I~`%nS@Wm>C$BF*7jCVrF2N#>~J_%gn%##>~JF!py+n z$;`mu%*?>x#LU28#>~LL$;`m;i;02Z6%zx)JthW*t4s_GCz%)+4l*$?Y-EC@yCtBs zhp(v!9`r(Ol@u`IxYKh4urHMI6lNO*RBt#IjRvW$+6SB~=C^0@Qv!bN5C>5#$wB8cDv;ZMv zrJz<^QUuyO0$TQ9rQix){s3AS3N90nmRN#Hk7D>zR8T7fw3-yU78Rrp;#_bkV`Wth z;pspPthENGRInKe)eOqf$!X~tAf9F{19a^MsQnAJ6U5LfN-aw*DozD8V35lbq=rsd zYBH>egRBB=TL?%BywW+fSWyFYF)o(%=P5~=dS!_@rKzaPE@4ZTHR6%>3xG`4D@n{w zjW5s0%t_U#K{Xw==>en+)E>36DlSbL_5CfT{wv7(68j>IzWg zgO=BV0!+b{K@+r+7ZfUx6{E1FyeUam3Th}TRl%W*YPJ=0nJIX=3pD#DXC!8VwhqRF z*48Fw=0Ugcfu{aJ!vY$xhy(dhucW9lJ}o~dMFXR4C5P&xtQCDMH?CLFdSGD#2a` zX$E0Xjt9}mSOe?~4W;6uWF_dvKTRFTz8Vdsq|7|HAf|gXA=CB9rh(YFy#$U{^lg9G z4FMU1*jWHhU(l2VN>k`&;BX1V5cHj2AW>ut%W{|=1gXO98P|#xo&XgVkc@#XexO+nq#L*ML9PUE9)aW}a4`Z|@c|xG0hfIKkUb30h4rw~ z58Vw`3TjXlki>4WPXkdWk71@g?~hiOI>R zsS6YmAO#Axux0(wjSE&*d8y?Z!IiLG2C!O52fU{QHqeonm!7JjsiU9<9{Sd_W&i-@ C7_F`V literal 0 HcmV?d00001 diff --git a/crates/ide-completion/src/completions/mod_.rs b/crates/ide-completion/src/completions/mod_.rs index 9c975b929533..950731eb4ca8 100644 --- a/crates/ide-completion/src/completions/mod_.rs +++ b/crates/ide-completion/src/completions/mod_.rs @@ -53,6 +53,7 @@ pub(crate) fn complete_mod( let existing_mod_declarations = current_module .children(ctx.db) .filter_map(|module| Some(module.name(ctx.db)?.to_string())) + .filter(|module| module != ctx.original_token.text()) .collect::>(); let module_declaration_file = @@ -351,4 +352,23 @@ fn ignored_bar() {} "#]], ); } + + #[test] + fn semi_colon_completion() { + check( + r#" +//- /lib.rs +mod foo; +//- /foo.rs +mod bar { + mod baz$0 +} +//- /foo/bar/baz.rs +fn baz() {} +"#, + expect![[r#" + md baz; + "#]], + ); + } } From bd3feea8bc90745fceca0a259b58e301f1d6df51 Mon Sep 17 00:00:00 2001 From: Peh <20146907+randomicon00@users.noreply.github.com> Date: Thu, 8 Sep 2022 22:44:10 +0100 Subject: [PATCH 4350/5092] fix: removed swap file --- .../ide-completion/src/completions/.mod_.rs.swp | Bin 24576 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 crates/ide-completion/src/completions/.mod_.rs.swp diff --git a/crates/ide-completion/src/completions/.mod_.rs.swp b/crates/ide-completion/src/completions/.mod_.rs.swp deleted file mode 100644 index 52d5cea48b2a7a54bbe6a0cd34a00d38a14829f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24576 zcmYc?2=nw+u+TGNU|?VnU|V(P z=HSp$SCFjllAm0fo0?Zrte=>dm{VDmTBMtnUzDw%T$EUnTCAU$k_t8}C$%IqKTp57 zC|Mt5G=y8MpPQc&uUAxz!~9X<(GVC70URMvT9T$~!OLK5WM}|Vp{%5+AS@ILVvgd` z5Eu=C(GVC7fzc2c4S~@R7!85Z5Eu=C5fTC=1uP8p3=9lRQ2$y$X+|`f1k)MGNRn~j0t0viLvN;U?DXf_50 zF*XKsc8XCb2Rww6HQTWV13bII}V^Xs|LcoM2&KsAOSaP-0o816GMFdSiGVA#gQz_6N$fgzKLfx(4|fkA?a zf#EhI1H(K1zK@tTdP|JYC0W)(FlTvf^3QCJJG}NutHLXz;WTq*A)=re>rKA?c zCnpxAmgp6y=4K}6=j7+bm*i)s=4oi^WfsTh<>#epXev~rXwFG3QOGSVQ2^VZV5?AE znv|QLQks(*pO=`Mim*s8Ex#x}H8D9uqXtz;4U&O+X_+}CsYMz!AiXsTim4Tu#U+_} z>G2@Tn7$h2;pPQ`I+ z5BIc!tu2yVNq&4zetvd5D0JXTia~Bf4Q7z>*xiR+6r>*HOAJqfBx)5>bBa@u!W|@t zjB%R@QiUf7LDDd+fd~OmByKngw7kktcO6Q7uu z5}#U8lA2eXnV+YjX^+F3cw$JeAh9SluLPu*n7G1>D5c!|6eW;Hu}I})CMhY@C@AG7 zX6Av_fMN;N#}HqFJcH(T%xEb}Eh#O^1BWaktARo*Gfg42qC`Q_RskH?N=3y=*m5p7 z`{;m_YNF)bg2a*x?7@j@4Jh{`A`&$^Fb#xy+$8l*M9v?w_>z9>JxL=Pkc z&LN--rlE#V3*u|qBTR#qAMv?~1<1t=NEvc5gH}j@LkMALa$;UeW=dj7YCK4vCMXPZ zAtf482?UnYODv8rN=?&1lsQlbAX|=V9I`WrP>jn}AV;aeU6q!ZmkBBs!Hz<5OeUx- zh470J!N~wG6Kc^a0=R+jf;Jwi4-^t0=cdMIrs(AtWu|B5CFX#w(?~9<&`U{z*aAv< z$)!c0+yg4IOLJ27ki!gO7)*yAIF|6+2@5VzIzv+lvI~Sk&I0+f1|nYrs>@1qQb8dE zavI#R;EGJIB(6u&1Z9ep)HDrfd4y~gYW)Y&fR-I0u8&X5OHM5=$uBC_(A3K-$Hr6RHuB4lx=KSULll zC8@dbIhn;JkZwRRs6h;hWlaTLI|cs&P|ahbp=k#VLQqp3sViZnpoSEKkb)<Kg9N*Zfpr1{LuqlU0@x%gt7=eJBDJE#$_lDIGd~aNARU;A znfZC1C8@c{{Nh?`h%v?Bq-14PomgC=qu^Lv;+LP2s-u8NVYSu_wUB)5R^gFYoDrN_ zqN5O$pI_pVSdy5OSPWL2o0OjeN{$f!gGA#~lB}$%gTeJSOr>i@iH<^8T5&*PNk**> z*cX{8sSuT5UPfk-l~pw)x9BK9XowMT=a!^cS%De`)(i~#`id|grWT_ITCpAjsQ>?t zg@NH28>Igao1cFI?fdWHXJFXC&%iK=pMjy4pMjy0pMfC(+W$9#_Wwos85sEa85sEZ z85o%O85pkcF)$qEV_?|I$H1_XkAYzU9|OY_J_d#^J_d$*J_d$bJ_d$NJ_d$ZJ_d$J zJ_ZH{J_ZI2J_ZIcJ_ZJEJ_ZI>J_ZIBJ_d#(ybKIkybKKHybKI1ybKH{c^DX4c^DXC zc^DYNco-Pmc^DX^c^DWtc^DYJaWgPn=VoBo&CS3tgPVb&iJO5To|}Qeg`0svl$(L! z6Bh%+V=e}U<6I03Yq%H~rf@MZv~e*o)N(N})NnB{6mT&xm~k;MsBnuCEsnS+6Wn}dPjCp!bfJ9Y+!7wilS&p~4l>kVP{}aW@ljFW@ljd$;QC&j*Wrg z1sf!upRh47JZ58Hcm#@b8jLB88aWyQqaiRF0)r$3YHJxFjUfmLY8NB*IzU_{<=9wA ztqkJ9aBhl1QeqXPT8D|HRurTrmncR@7bz<-C@JeOq~(DWfrdn|TJZKVvs{nZe zIhep+f+rXxO(2CJNtkzGQfc}5AgQ!G1<;dQhp7wAOUo}RDa}hPNzJL$QAo?kuqj2Q#U;s*(pz6&K}#VoAFd^>C_fi$ zFJue?G0dfqSd^+zP?TSgU!0l(vmUH9xiT4K8Av`cCnvugGDHB16i6b6%uT_xB<7_k zlw>4=I{f7sm0(lT^Yc>_O7bCIEh*1eD9OmoOE0#9X>mgJ71$z$q|6e9;)2xV%)}fW zkb^4~z?Lgy=7PMOnU@X{MDH zi*hQ-tsJOXInttL%ma_`#AoKg#vvgCEAfbu37&Le=@uN6km3lGgrQ{-hzY{rf(Wbx z#DigQ5mbd;xCliUrBnhHMQM2o&>A2z1l4XJA$??dP|gJxE>$3hqqH}wKwIOX z@-Qu^^)ARnP}zkf3sMj2{|j?4Fx-dE|HIbz-{EIqxXsVNuoK$f7w2bS;O1vw;NoXs z_{GP-@Cw?W2le6k_!ty;@iH)Y@-i^6@-i?y;$dJo%EQ30ori&89uEUU z84m+PG!FyAZ*B&LHQWpgq1+4%dfW^QBHRoN-?KvP10N>?!&{i!2T5ad)ET28Fd71*Aut*OqaiRF z0s|fbutpk)MzrfdJP-yiXd7KJr=Xw!p5w+`rUVKk%wPkFf@hXN6O!OHfS~!|(Is;@ zR~>=^42DOS%t43GU;zT6l}4A$X&|o)0)+`^<{z;(475IObjcieIa&?U0%X*ccc2Af z&?PDu3#Z^caXrw?ICMQ9WML6_{S{;s1QhT?ddXa7ejYfGV9T699@0zB&&f$mF0rz* zfiF+6iMO-U(6k26|I0EkFf0Wf03g7?0NcO6gr9+-ou7fBnxBE8il2cYm!E+lo1cLp zi=TnPm7jsZke`7;3OW|>n2&*B5g!9X3LgW5Cm#cY2_FN49v=e(2Xqd90WSkXJ1+x6 zDK7(q8!rQc3NHf#6E6e9ULFR93LXZAR2~KfEgl92DINxftK19>OSl;r`neex+_@PT zEV&sN^tl-r)VUcL)VLWK-b2R;Ky&!9Tnr4+Tnr3RTnr5QTnr4t(0O~%Siv<;28L=* z28IAm28K@@3=EGs7#I$6Ffgp;U|?9n!N9PHgMnco2Lr*clksK3t9ySJs#cT`=-E0gD#cT`=iEIoEVQdTx0c;Em{%i~k z&TI?}LTn5S%xnw{pII3gp0hGA++$^6xXa4GaGRBZ;XEq?!(mnihW)Gz3=3Hq7^bl@ zFic=&VCZLMU}$D#U`S+TUTFfin@FffF&Ffcf?FfdrKFfbUgFfbUhFfgdHFfjaM zW?*>F%)oG;nStRFGXujhW(I~`%nS@Wm>C$BF*7jCVrF2N#>~J_%gn%##>~JF!py+n z$;`mu%*?>x#LU28#>~LL$;`m;i;02Z6%zx)JthW*t4s_GCz%)+4l*$?Y-EC@yCtBs zhp(v!9`r(Ol@u`IxYKh4urHMI6lNO*RBt#IjRvW$+6SB~=C^0@Qv!bN5C>5#$wB8cDv;ZMv zrJz<^QUuyO0$TQ9rQix){s3AS3N90nmRN#Hk7D>zR8T7fw3-yU78Rrp;#_bkV`Wth z;pspPthENGRInKe)eOqf$!X~tAf9F{19a^MsQnAJ6U5LfN-aw*DozD8V35lbq=rsd zYBH>egRBB=TL?%BywW+fSWyFYF)o(%=P5~=dS!_@rKzaPE@4ZTHR6%>3xG`4D@n{w zjW5s0%t_U#K{Xw==>en+)E>36DlSbL_5CfT{wv7(68j>IzWg zgO=BV0!+b{K@+r+7ZfUx6{E1FyeUam3Th}TRl%W*YPJ=0nJIX=3pD#DXC!8VwhqRF z*48Fw=0Ugcfu{aJ!vY$xhy(dhucW9lJ}o~dMFXR4C5P&xtQCDMH?CLFdSGD#2a` zX$E0Xjt9}mSOe?~4W;6uWF_dvKTRFTz8Vdsq|7|HAf|gXA=CB9rh(YFy#$U{^lg9G z4FMU1*jWHhU(l2VN>k`&;BX1V5cHj2AW>ut%W{|=1gXO98P|#xo&XgVkc@#XexO+nq#L*ML9PUE9)aW}a4`Z|@c|xG0hfIKkUb30h4rw~ z58Vw`3TjXlki>4WPXkdWk71@g?~hiOI>R zsS6YmAO#Axux0(wjSE&*d8y?Z!IiLG2C!O52fU{QHqeonm!7JjsiU9<9{Sd_W&i-@ C7_F`V From cc87d53da9018eb985af69caea22b2ad79b2505a Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Sun, 19 Jun 2022 10:47:40 -0400 Subject: [PATCH 4351/5092] Don't use reempty as an implicit_outlives_region --- compiler/rustc_infer/src/infer/error_reporting/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 0196bd262179..ed85c7533603 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -386,7 +386,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { RegionResolutionError::UpperBoundUniverseConflict( _, _, - var_universe, + _, sup_origin, sup_r, ) => { @@ -397,7 +397,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // placeholder. In practice, we expect more // tailored errors that don't really use this // value. - let sub_r = self.tcx.mk_region(ty::ReEmpty(var_universe)); + let sub_r = self.tcx.lifetimes.re_erased; self.report_placeholder_failure(sup_origin, sub_r, sup_r).emit(); } From f29c91bf1245fc01853b0f1d8913139b3b355f63 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Sun, 26 Jun 2022 00:10:07 -0400 Subject: [PATCH 4352/5092] Create VarValue::Empty --- .../src/region_infer/opaque_types.rs | 2 +- .../src/infer/lexical_region_resolve/mod.rs | 201 ++++++++++++++++-- .../rustc_trait_selection/src/traits/wf.rs | 4 + compiler/rustc_typeck/src/check/dropck.rs | 2 + compiler/rustc_typeck/src/check/wfcheck.rs | 1 + compiler/rustc_typeck/src/collect.rs | 3 +- 6 files changed, 191 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 0392367288c4..3e6a48195f8c 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -109,7 +109,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { .iter() .find(|ur_vid| self.eval_equal(vid, **ur_vid)) .and_then(|ur_vid| self.definitions[*ur_vid].external_name) - .unwrap_or(infcx.tcx.lifetimes.re_root_empty), + .unwrap_or(infcx.tcx.lifetimes.re_erased), _ => region, }); diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index 13b7e8eb9643..41695d6807bc 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -51,6 +51,13 @@ pub struct LexicalRegionResolutions<'tcx> { #[derive(Copy, Clone, Debug)] pub(crate) enum VarValue<'tcx> { + /// Empty lifetime is for data that is never accessed. We tag the + /// empty lifetime with a universe -- the idea is that we don't + /// want `exists<'a> { forall<'b> { 'b: 'a } }` to be satisfiable. + /// Therefore, the `'empty` in a universe `U` is less than all + /// regions visible from `U`, but not less than regions not visible + /// from `U`. + Empty(ty::UniverseIndex), Value(Region<'tcx>), ErrorValue, } @@ -117,7 +124,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { &mut self, errors: &mut Vec>, ) -> LexicalRegionResolutions<'tcx> { - let mut var_data = self.construct_var_data(self.tcx()); + let mut var_data = self.construct_var_data(); if cfg!(debug_assertions) { self.dump_constraints(); @@ -137,13 +144,12 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { /// Initially, the value for all variables is set to `'empty`, the /// empty region. The `expansion` phase will grow this larger. - fn construct_var_data(&self, tcx: TyCtxt<'tcx>) -> LexicalRegionResolutions<'tcx> { + fn construct_var_data(&self) -> LexicalRegionResolutions<'tcx> { LexicalRegionResolutions { values: IndexVec::from_fn_n( |vid| { let vid_universe = self.var_infos[vid].universe; - let re_empty = tcx.mk_region(ty::ReEmpty(vid_universe)); - VarValue::Value(re_empty) + VarValue::Empty(vid_universe) }, self.num_vars(), ), @@ -190,19 +196,132 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) { + // In the first pass, we expand region vids according to constraints we + // have previously found. In the second pass, we loop through the region + // vids we expanded and expand *across* region vids (effectively + // "expanding" new `RegSubVar` constraints). + + // Tracks the `VarSubVar` constraints generated for each region vid. We + // later use this to expand across vids. let mut constraints = IndexVec::from_elem_n(Vec::new(), var_values.values.len()); + // Tracks the changed region vids. let mut changes = Vec::new(); for constraint in self.data.constraints.keys() { - let (a_vid, a_region, b_vid, b_data) = match *constraint { + match *constraint { Constraint::RegSubVar(a_region, b_vid) => { let b_data = var_values.value_mut(b_vid); - (None, a_region, b_vid, b_data) + + if self.expand_node(a_region, b_vid, b_data) { + changes.push(b_vid); + } } Constraint::VarSubVar(a_vid, b_vid) => match *var_values.value(a_vid) { VarValue::ErrorValue => continue, + VarValue::Empty(a_universe) => { + let b_data = var_values.value_mut(b_vid); + + let changed = (|| match *b_data { + VarValue::Empty(b_universe) => { + // Empty regions are ordered according to the universe + // they are associated with. + let ui = a_universe.min(b_universe); + + debug!( + "Expanding value of {:?} \ + from empty lifetime with universe {:?} \ + to empty lifetime with universe {:?}", + b_vid, b_universe, ui + ); + + *b_data = VarValue::Empty(ui); + true + } + VarValue::Value(cur_region) => { + let lub = match *cur_region { + ReLateBound(..) | ReErased => { + bug!("cannot relate region: {:?}", cur_region); + } + + ReVar(v_id) => { + span_bug!( + self.var_infos[v_id].origin.span(), + "lub_concrete_regions invoked with non-concrete regions: {:?}", + cur_region, + ); + } + + ReStatic => { + // nothing lives longer than `'static` + self.tcx().lifetimes.re_static + } + + ReEarlyBound(_) | ReFree(_) => { + // All empty regions are less than early-bound, free, + // and scope regions. + cur_region + } + + ReEmpty(b_ui) => { + // Empty regions are ordered according to the universe + // they are associated with. + let ui = a_universe.min(b_ui); + self.tcx().mk_region(ReEmpty(ui)) + } + + RePlaceholder(placeholder) => { + // If the empty and placeholder regions are in the same universe, + // then the LUB is the Placeholder region (which is the cur_region). + // If they are not in the same universe, the LUB is the Static lifetime. + if a_universe == placeholder.universe { + cur_region + } else { + self.tcx().lifetimes.re_static + } + } + }; + + if lub == cur_region { + return false; + } + + debug!( + "Expanding value of {:?} from {:?} to {:?}", + b_vid, cur_region, lub + ); + + *b_data = VarValue::Value(lub); + true + } + + VarValue::ErrorValue => false, + })(); + + if changed { + changes.push(b_vid); + } + match b_data { + VarValue::Value(Region(Interned(ReStatic, _))) + | VarValue::ErrorValue => (), + _ => { + constraints[a_vid].push((a_vid, b_vid)); + constraints[b_vid].push((a_vid, b_vid)); + } + } + } VarValue::Value(a_region) => { let b_data = var_values.value_mut(b_vid); - (Some(a_vid), a_region, b_vid, b_data) + + if self.expand_node(a_region, b_vid, b_data) { + changes.push(b_vid); + } + match b_data { + VarValue::Value(Region(Interned(ReStatic, _))) + | VarValue::ErrorValue => (), + _ => { + constraints[a_vid].push((a_vid, b_vid)); + constraints[b_vid].push((a_vid, b_vid)); + } + } } }, Constraint::RegSubReg(..) | Constraint::VarSubReg(..) => { @@ -210,18 +329,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // is done, in `collect_errors`. continue; } - }; - if self.expand_node(a_region, b_vid, b_data) { - changes.push(b_vid); - } - if let Some(a_vid) = a_vid { - match b_data { - VarValue::Value(Region(Interned(ReStatic, _))) | VarValue::ErrorValue => (), - _ => { - constraints[a_vid].push((a_vid, b_vid)); - constraints[b_vid].push((a_vid, b_vid)); - } - } } } @@ -242,6 +349,10 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } } + /// Expands the value of the region represented with `b_vid` with current + /// value `b_data` to the lub of `b_data` and `a_region`. The corresponds + /// with the constraint `'?b: 'a` (`'a <: '?b`), where `'a` is some known + /// region and `'?b` is some region variable. fn expand_node( &self, a_region: Region<'tcx>, @@ -263,6 +374,55 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } match *b_data { + VarValue::Empty(empty_ui) => { + let lub = match *a_region { + ReLateBound(..) | ReErased => { + bug!("cannot relate region: {:?}", a_region); + } + + ReVar(v_id) => { + span_bug!( + self.var_infos[v_id].origin.span(), + "expand_node invoked with non-concrete regions: {:?}", + a_region, + ); + } + + ReStatic => { + // nothing lives longer than `'static` + self.tcx().lifetimes.re_static + } + + ReEarlyBound(_) | ReFree(_) => { + // All empty regions are less than early-bound, free, + // and scope regions. + a_region + } + + ReEmpty(a_ui) => { + // Empty regions are ordered according to the universe + // they are associated with. + let ui = a_ui.min(empty_ui); + self.tcx().mk_region(ReEmpty(ui)) + } + + RePlaceholder(placeholder) => { + // If this empty region is from a universe that can + // name the placeholder, then the placeholder is + // larger; otherwise, the only ancestor is `'static`. + if empty_ui.can_name(placeholder.universe) { + self.tcx().mk_region(RePlaceholder(placeholder)) + } else { + self.tcx().lifetimes.re_static + } + } + }; + + debug!("Expanding value of {:?} from empty lifetime to {:?}", b_vid, lub); + + *b_data = VarValue::Value(lub); + true + } VarValue::Value(cur_region) => { // This is a specialized version of the `lub_concrete_regions` // check below for a common case, here purely as an @@ -508,7 +668,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { for (node_vid, value) in var_data.values.iter_enumerated() { match *value { - VarValue::Value(_) => { /* Inference successful */ } + VarValue::Empty(_) | VarValue::Value(_) => { /* Inference successful */ } VarValue::ErrorValue => { // Inference impossible: this value contains // inconsistent constraints. @@ -876,6 +1036,7 @@ impl<'tcx> LexicalRegionResolutions<'tcx> { ) -> ty::Region<'tcx> { let result = match *r { ty::ReVar(rid) => match self.values[rid] { + VarValue::Empty(vid_universe) => tcx.mk_region(ty::ReEmpty(vid_universe)), VarValue::Value(r) => r, VarValue::ErrorValue => tcx.lifetimes.re_static, }, diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 9a571837e9f5..9d3a1a4a031a 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -101,6 +101,7 @@ pub fn trait_obligations<'a, 'tcx>( wf.normalize(infcx) } +#[instrument(skip(infcx), ret)] pub fn predicate_obligations<'a, 'tcx>( infcx: &InferCtxt<'a, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -440,6 +441,7 @@ impl<'tcx> WfPredicates<'tcx> { let param_env = self.param_env; let depth = self.recursion_depth; while let Some(arg) = walker.next() { + debug!(?arg, ?self.out); let ty = match arg.unpack() { GenericArgKind::Type(ty) => ty, @@ -689,6 +691,8 @@ impl<'tcx> WfPredicates<'tcx> { )); } } + + debug!(?self.out); } } diff --git a/compiler/rustc_typeck/src/check/dropck.rs b/compiler/rustc_typeck/src/check/dropck.rs index 321064ec0fc9..ab143c059820 100644 --- a/compiler/rustc_typeck/src/check/dropck.rs +++ b/compiler/rustc_typeck/src/check/dropck.rs @@ -144,6 +144,8 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( let assumptions_in_impl_context = generic_assumptions.instantiate(tcx, &self_to_impl_substs); let assumptions_in_impl_context = assumptions_in_impl_context.predicates; + debug!(?assumptions_in_impl_context, ?dtor_predicates.predicates); + let self_param_env = tcx.param_env(self_type_did); // An earlier version of this code attempted to do this checking diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 5c6c8aca1734..b0ce0de1469b 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -1816,6 +1816,7 @@ fn report_bivariance( impl<'tcx> WfCheckingCtxt<'_, 'tcx> { /// Feature gates RFC 2056 -- trivial bounds, checking for global bounds that /// aren't true. + #[instrument(level = "debug", skip(self))] fn check_false_global_bounds(&mut self) { let tcx = self.ocx.infcx.tcx; let mut span = self.span; diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index e70f728d7dcc..c2a34b91ad67 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1808,6 +1808,7 @@ pub fn get_infer_ret_ty<'hir>(output: &'hir hir::FnRetTy<'hir>) -> Option<&'hir None } +#[instrument(level = "debug", skip(tcx))] fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { use rustc_hir::Node::*; use rustc_hir::*; @@ -2038,8 +2039,8 @@ fn early_bound_lifetimes_from_generics<'a, 'tcx: 'a>( /// Returns a list of type predicates for the definition with ID `def_id`, including inferred /// lifetime constraints. This includes all predicates returned by `explicit_predicates_of`, plus /// inferred constraints concerning which regions outlive other regions. +#[instrument(level = "debug", skip(tcx))] fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> { - debug!("predicates_defined_on({:?})", def_id); let mut result = tcx.explicit_predicates_of(def_id); debug!("predicates_defined_on: explicit_predicates_of({:?}) = {:?}", def_id, result,); let inferred_outlives = tcx.inferred_outlives_of(def_id); From e7e5feb637ca0e130f2890800da054771410d321 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Sun, 26 Jun 2022 12:01:05 -0400 Subject: [PATCH 4353/5092] In ReverseMapper, don't fallback to ReEmpty, instead ReStatic --- .../src/region_infer/opaque_types.rs | 32 +++++++------------ compiler/rustc_middle/src/ty/context.rs | 9 +----- 2 files changed, 12 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 3e6a48195f8c..0b8ed0fcf270 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -433,7 +433,7 @@ struct ReverseMapper<'tcx> { key: ty::OpaqueTypeKey<'tcx>, map: FxHashMap, GenericArg<'tcx>>, - map_missing_regions_to_empty: bool, + do_not_error: bool, /// initially `Some`, set to `None` once error has been reported hidden_ty: Option>, @@ -450,29 +450,19 @@ impl<'tcx> ReverseMapper<'tcx> { hidden_ty: Ty<'tcx>, span: Span, ) -> Self { - Self { - tcx, - key, - map, - map_missing_regions_to_empty: false, - hidden_ty: Some(hidden_ty), - span, - } + Self { tcx, key, map, do_not_error: false, hidden_ty: Some(hidden_ty), span } } - fn fold_kind_mapping_missing_regions_to_empty( - &mut self, - kind: GenericArg<'tcx>, - ) -> GenericArg<'tcx> { - assert!(!self.map_missing_regions_to_empty); - self.map_missing_regions_to_empty = true; + fn fold_kind_no_missing_regions_error(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> { + assert!(!self.do_not_error); + self.do_not_error = true; let kind = kind.fold_with(self); - self.map_missing_regions_to_empty = false; + self.do_not_error = false; kind } fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> { - assert!(!self.map_missing_regions_to_empty); + assert!(!self.do_not_error); kind.fold_with(self) } } @@ -510,7 +500,7 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { match self.map.get(&r.into()).map(|k| k.unpack()) { Some(GenericArgKind::Lifetime(r1)) => r1, Some(u) => panic!("region mapped to unexpected kind: {:?}", u), - None if self.map_missing_regions_to_empty => self.tcx.lifetimes.re_root_empty, + None if self.do_not_error => self.tcx.lifetimes.re_static, None if generics.parent.is_some() => { if let Some(hidden_ty) = self.hidden_ty.take() { unexpected_hidden_region_diagnostic( @@ -522,7 +512,7 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { ) .emit(); } - self.tcx.lifetimes.re_root_empty + self.tcx.lifetimes.re_static } None => { self.tcx @@ -574,7 +564,7 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| { if index < generics.parent_count { // Accommodate missing regions in the parent kinds... - self.fold_kind_mapping_missing_regions_to_empty(kind) + self.fold_kind_no_missing_regions_error(kind) } else { // ...but not elsewhere. self.fold_kind_normally(kind) @@ -589,7 +579,7 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> { let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| { if index < generics.parent_count { // Accommodate missing regions in the parent kinds... - self.fold_kind_mapping_missing_regions_to_empty(kind) + self.fold_kind_no_missing_regions_error(kind) } else { // ...but not elsewhere. self.fold_kind_normally(kind) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 53e91e48c24d..afb2d5b2ba5e 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -276,9 +276,6 @@ pub struct CommonTypes<'tcx> { } pub struct CommonLifetimes<'tcx> { - /// `ReEmpty` in the root universe. - pub re_root_empty: Region<'tcx>, - /// `ReStatic` pub re_static: Region<'tcx>, @@ -987,11 +984,7 @@ impl<'tcx> CommonLifetimes<'tcx> { )) }; - CommonLifetimes { - re_root_empty: mk(ty::ReEmpty(ty::UniverseIndex::ROOT)), - re_static: mk(ty::ReStatic), - re_erased: mk(ty::ReErased), - } + CommonLifetimes { re_static: mk(ty::ReStatic), re_erased: mk(ty::ReErased) } } } From dd0335a27f03c0b654c49d188e122c3a0776c6a3 Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Sun, 26 Jun 2022 15:08:35 -0400 Subject: [PATCH 4354/5092] Don't construct ReEmpty regions in resolve_var --- .../src/infer/lexical_region_resolve/mod.rs | 107 +++++++++++++++++- 1 file changed, 102 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index 41695d6807bc..99f956bede7a 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -460,6 +460,90 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } } + /// True if `a <= b`. + fn sub_region_values(&self, a: VarValue<'tcx>, b: VarValue<'tcx>) -> bool { + match (a, b) { + // Error region is `'static` + (VarValue::ErrorValue, _) | (_, VarValue::ErrorValue) => return true, + (VarValue::Empty(a_ui), VarValue::Empty(b_ui)) => { + // Empty regions are ordered according to the universe + // they are associated with. + a_ui.min(b_ui) == b_ui + } + (VarValue::Value(a), VarValue::Empty(b_ui)) => { + match *a { + ReLateBound(..) | ReErased => { + bug!("cannot relate region: {:?}", a); + } + + ReVar(v_id) => { + span_bug!( + self.var_infos[v_id].origin.span(), + "lub_concrete_regions invoked with non-concrete region: {:?}", + a + ); + } + + ReStatic | ReEarlyBound(_) | ReFree(_) => { + // nothing lives longer than `'static` + + // All empty regions are less than early-bound, free, + // and scope regions. + + false + } + + ReEmpty(a_ui) => { + // Empty regions are ordered according to the universe + // they are associated with. + a_ui.min(b_ui) == b_ui + } + + RePlaceholder(_) => { + // The LUB is either `a` or `'static` + false + } + } + } + (VarValue::Empty(a_ui), VarValue::Value(b)) => { + match *b { + ReLateBound(..) | ReErased => { + bug!("cannot relate region: {:?}", b); + } + + ReVar(v_id) => { + span_bug!( + self.var_infos[v_id].origin.span(), + "lub_concrete_regions invoked with non-concrete regions: {:?}", + b + ); + } + + ReStatic | ReEarlyBound(_) | ReFree(_) => { + // nothing lives longer than `'static` + // All empty regions are less than early-bound, free, + // and scope regions. + true + } + + ReEmpty(b_ui) => { + // Empty regions are ordered according to the universe + // they are associated with. + a_ui.min(b_ui) == b_ui + } + + RePlaceholder(placeholder) => { + // If this empty region is from a universe that can + // name the placeholder, then the placeholder is + // larger; otherwise, the only ancestor is `'static`. + if a_ui.can_name(placeholder.universe) { true } else { false } + } + } + } + (VarValue::Value(a), VarValue::Value(b)) => self.sub_concrete_regions(a, b), + } + } + /// True if `a <= b`, but not defined over inference variables. #[instrument(level = "trace", skip(self))] fn sub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> bool { @@ -989,12 +1073,25 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { } VerifyBound::OutlivedBy(r) => { - self.sub_concrete_regions(min, var_values.normalize(self.tcx(), *r)) + let a = match *min { + ty::ReVar(rid) => var_values.values[rid], + _ => VarValue::Value(min), + }; + let b = match **r { + ty::ReVar(rid) => var_values.values[rid], + _ => VarValue::Value(*r), + }; + self.sub_region_values(a, b) } - VerifyBound::IsEmpty => { - matches!(*min, ty::ReEmpty(_)) - } + VerifyBound::IsEmpty => match *min { + ty::ReVar(rid) => match var_values.values[rid] { + VarValue::ErrorValue => false, + VarValue::Empty(_) => true, + VarValue::Value(min) => matches!(*min, ty::ReEmpty(_)), + }, + _ => matches!(*min, ty::ReEmpty(_)), + }, VerifyBound::AnyBound(bs) => { bs.iter().any(|b| self.bound_is_met(b, var_values, generic_ty, min)) @@ -1036,7 +1133,7 @@ impl<'tcx> LexicalRegionResolutions<'tcx> { ) -> ty::Region<'tcx> { let result = match *r { ty::ReVar(rid) => match self.values[rid] { - VarValue::Empty(vid_universe) => tcx.mk_region(ty::ReEmpty(vid_universe)), + VarValue::Empty(_) => r, VarValue::Value(r) => r, VarValue::ErrorValue => tcx.lifetimes.re_static, }, From 01fc1313427af10e42d027529fb563c21e8cb45b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 8 Sep 2022 23:40:13 +0200 Subject: [PATCH 4355/5092] Clean up themes a bit more --- src/librustdoc/html/static/css/rustdoc.css | 36 +++++++++++++ src/librustdoc/html/static/css/themes/ayu.css | 52 ++----------------- .../html/static/css/themes/dark.css | 52 ++----------------- .../html/static/css/themes/light.css | 52 ++----------------- src/test/rustdoc-gui/code-tags.goml | 4 +- src/test/rustdoc-gui/src/test_docs/lib.rs | 6 +++ 6 files changed, 56 insertions(+), 146 deletions(-) diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 7665417cb5c9..1b8b28f0432a 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1165,6 +1165,42 @@ pre.rust .question-mark { font-weight: bold; } +pre.compile_fail, +pre.should_panic { + border-left: 2px solid var(--codeblock-error-color); +} + +pre.ignore { + border-left: 2px solid var(--codeblock-ignore-color); +} + +pre.compile_fail:hover, .information:hover + .example-wrap pre.compile_fail, +pre.should_panic:hover, .information:hover + .example-wrap pre.should_panic { + border-left: 2px solid var(--codeblock-error-hover-color); +} + +pre.ignore:hover, .information:hover + .example-wrap pre.ignore { + border-left: 2px solid var(--codeblock-ignore-hover-color); +} + +.tooltip.compile_fail, +.tooltip.should_panic { + color: var(--codeblock-error-color); +} + +.tooltip.ignore { + color: var(--codeblock-ignore-color); +} + +.information > .compile_fail:hover, +.information > .should_panic:hover { + color: var(--codeblock-error-hover-color); +} + +.information > .ignore:hover { + color: var(--codeblock-ignore-hover-color); +} + a.test-arrow { display: inline-block; visibility: hidden; diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css index be359a8e72d2..74de113495c2 100644 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -23,6 +23,10 @@ Original by Dempfi (https://github.com/dempfi/ayu) --copy-path-button-color: #fff; --copy-path-img-filter: invert(70%); --copy-path-img-hover-filter: invert(100%); + --codeblock-error-hover-color: rgb(255, 0, 0); + --codeblock-error-color: rgba(255, 0, 0, .5); + --codeblock-ignore-hover-color: rgb(255, 142, 0); + --codeblock-ignore-color: rgba(255, 142, 0, .6); } .slider { @@ -244,54 +248,6 @@ a.test-arrow:hover { border-right: 3px solid rgba(255, 180, 76, 0.85); } -pre.compile_fail { - border-left: 2px solid rgba(255,0,0,.4); -} - -pre.compile_fail:hover, .information:hover + pre.compile_fail { - border-left: 2px solid #f00; -} - -pre.should_panic { - border-left: 2px solid rgba(255,0,0,.4); -} - -pre.should_panic:hover, .information:hover + pre.should_panic { - border-left: 2px solid #f00; -} - -pre.ignore { - border-left: 2px solid rgba(255,142,0,.6); -} - -pre.ignore:hover, .information:hover + pre.ignore { - border-left: 2px solid #ff9200; -} - -.tooltip.compile_fail { - color: rgba(255,0,0,.5); -} - -.information > .compile_fail:hover { - color: #f00; -} - -.tooltip.should_panic { - color: rgba(255,0,0,.5); -} - -.information > .should_panic:hover { - color: #f00; -} - -.tooltip.ignore { - color: rgba(255,142,0,.6); -} - -.information > .ignore:hover { - color: #ff9200; -} - .search-failed a { color: #39AFD7; } diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css index f633abe94e5a..153b40f05d8d 100644 --- a/src/librustdoc/html/static/css/themes/dark.css +++ b/src/librustdoc/html/static/css/themes/dark.css @@ -18,6 +18,10 @@ --copy-path-button-color: #999; --copy-path-img-filter: invert(50%); --copy-path-img-hover-filter: invert(65%); + --codeblock-error-hover-color: rgb(255, 0, 0); + --codeblock-error-color: rgba(255, 0, 0, .5); + --codeblock-ignore-hover-color: rgb(255, 142, 0); + --codeblock-ignore-color: rgba(255, 142, 0, .6); } .slider { @@ -194,54 +198,6 @@ a.test-arrow:hover{ border-right: 3px solid #bb7410; } -pre.compile_fail { - border-left: 2px solid rgba(255,0,0,.8); -} - -pre.compile_fail:hover, .information:hover + pre.compile_fail { - border-left: 2px solid #f00; -} - -pre.should_panic { - border-left: 2px solid rgba(255,0,0,.8); -} - -pre.should_panic:hover, .information:hover + pre.should_panic { - border-left: 2px solid #f00; -} - -pre.ignore { - border-left: 2px solid rgba(255,142,0,.6); -} - -pre.ignore:hover, .information:hover + pre.ignore { - border-left: 2px solid #ff9200; -} - -.tooltip.compile_fail { - color: rgba(255,0,0,.8); -} - -.information > .compile_fail:hover { - color: #f00; -} - -.tooltip.should_panic { - color: rgba(255,0,0,.8); -} - -.information > .should_panic:hover { - color: #f00; -} - -.tooltip.ignore { - color: rgba(255,142,0,.6); -} - -.information > .ignore:hover { - color: #ff9200; -} - .search-failed a { color: #0089ff; } diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css index 875bb7930256..9ced9e7b5ce3 100644 --- a/src/librustdoc/html/static/css/themes/light.css +++ b/src/librustdoc/html/static/css/themes/light.css @@ -18,6 +18,10 @@ --copy-path-button-color: #999; --copy-path-img-filter: invert(50%); --copy-path-img-hover-filter: invert(35%); + --codeblock-error-hover-color: rgb(255, 0, 0); + --codeblock-error-color: rgba(255, 0, 0, .5); + --codeblock-ignore-hover-color: rgb(255, 142, 0); + --codeblock-ignore-color: rgba(255, 142, 0, .6); } .slider { @@ -180,54 +184,6 @@ a.test-arrow:hover{ border-right: 3px solid #AD7C37; } -pre.compile_fail { - border-left: 2px solid rgba(255,0,0,.5); -} - -pre.compile_fail:hover, .information:hover + pre.compile_fail { - border-left: 2px solid #f00; -} - -pre.should_panic { - border-left: 2px solid rgba(255,0,0,.5); -} - -pre.should_panic:hover, .information:hover + pre.should_panic { - border-left: 2px solid #f00; -} - -pre.ignore { - border-left: 2px solid rgba(255,142,0,.6); -} - -pre.ignore:hover, .information:hover + pre.ignore { - border-left: 2px solid #ff9200; -} - -.tooltip.compile_fail { - color: rgba(255,0,0,.5); -} - -.information > .compile_fail:hover { - color: #f00; -} - -.tooltip.should_panic { - color: rgba(255,0,0,.5); -} - -.information > .should_panic:hover { - color: #f00; -} - -.tooltip.ignore { - color: rgba(255,142,0,.6); -} - -.information > .ignore:hover { - color: #ff9200; -} - .search-failed a { color: #3873AD; } diff --git a/src/test/rustdoc-gui/code-tags.goml b/src/test/rustdoc-gui/code-tags.goml index 200569a28d4a..8d399a9a5897 100644 --- a/src/test/rustdoc-gui/code-tags.goml +++ b/src/test/rustdoc-gui/code-tags.goml @@ -1,9 +1,9 @@ // This test ensures that items and documentation code blocks are wrapped in

 goto: file://|DOC_PATH|/test_docs/fn.foo.html
 size: (1080, 600)
-// There should be three doc codeblocks
+// There should be four doc codeblocks.
 // Check that their content is inside 

-assert-count: (".example-wrap pre > code", 3)
+assert-count: (".example-wrap pre > code", 4)
 // Check that function signature is inside 

 assert: "pre.rust.fn > code"
 
diff --git a/src/test/rustdoc-gui/src/test_docs/lib.rs b/src/test/rustdoc-gui/src/test_docs/lib.rs
index a02d5934cc24..4eedf7f15c3d 100644
--- a/src/test/rustdoc-gui/src/test_docs/lib.rs
+++ b/src/test/rustdoc-gui/src/test_docs/lib.rs
@@ -28,6 +28,12 @@ use std::fmt;
 /// Let's say I'm just some text will ya?
 /// ```
 ///
+/// A failing to run one:
+///
+/// ```should_panic
+/// panic!("tadam");
+/// ```
+///
 /// An inlined `code`!
 pub fn foo() {}
 

From f9da510cff278acabdfbf3b6fa1190558938d977 Mon Sep 17 00:00:00 2001
From: Guillaume Gomez 
Date: Thu, 8 Sep 2022 23:41:29 +0200
Subject: [PATCH 4356/5092] Add gui test for codeblocks tooltip colors

---
 src/test/rustdoc-gui/codeblock-tooltip.goml | 96 +++++++++++++++++++++
 1 file changed, 96 insertions(+)
 create mode 100644 src/test/rustdoc-gui/codeblock-tooltip.goml

diff --git a/src/test/rustdoc-gui/codeblock-tooltip.goml b/src/test/rustdoc-gui/codeblock-tooltip.goml
new file mode 100644
index 000000000000..a0bb40fce8e7
--- /dev/null
+++ b/src/test/rustdoc-gui/codeblock-tooltip.goml
@@ -0,0 +1,96 @@
+// Checking the colors of the codeblocks tooltips.
+goto: file://|DOC_PATH|/test_docs/fn.foo.html
+show-text: true
+
+// Dark theme.
+local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"}
+reload:
+
+// compile_fail block
+assert-css: (".docblock .information .compile_fail", {"color": "rgba(255, 0, 0, 0.5)"})
+assert-css: (".docblock .example-wrap .compile_fail", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
+
+move-cursor-to: ".docblock .information .compile_fail"
+
+assert-css: (".docblock .information .compile_fail", {"color": "rgb(255, 0, 0)"})
+assert-css: (".docblock .example-wrap .compile_fail", {"border-left": "2px solid rgb(255, 0, 0)"})
+
+// should_panic block
+assert-css: (".docblock .information .should_panic", {"color": "rgba(255, 0, 0, 0.5)"})
+assert-css: (".docblock .example-wrap .should_panic", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
+
+move-cursor-to: ".docblock .information .should_panic"
+
+assert-css: (".docblock .information .should_panic", {"color": "rgb(255, 0, 0)"})
+assert-css: (".docblock .example-wrap .should_panic", {"border-left": "2px solid rgb(255, 0, 0)"})
+
+// ignore block
+assert-css: (".docblock .information .ignore", {"color": "rgba(255, 142, 0, 0.6)"})
+assert-css: (".docblock .example-wrap .ignore", {"border-left": "2px solid rgba(255, 142, 0, 0.6)"})
+
+move-cursor-to: ".docblock .information .ignore"
+
+assert-css: (".docblock .information .ignore", {"color": "rgb(255, 142, 0)"})
+assert-css: (".docblock .example-wrap .ignore", {"border-left": "2px solid rgb(255, 142, 0)"})
+
+
+// Light theme.
+local-storage: {"rustdoc-theme": "light"}
+reload:
+
+assert-css: (".docblock .information .compile_fail", {"color": "rgba(255, 0, 0, 0.5)"})
+assert-css: (".docblock .example-wrap .compile_fail", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
+
+move-cursor-to: ".docblock .information .compile_fail"
+
+assert-css: (".docblock .information .compile_fail", {"color": "rgb(255, 0, 0)"})
+assert-css: (".docblock .example-wrap .compile_fail", {"border-left": "2px solid rgb(255, 0, 0)"})
+
+// should_panic block
+assert-css: (".docblock .information .should_panic", {"color": "rgba(255, 0, 0, 0.5)"})
+assert-css: (".docblock .example-wrap .should_panic", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
+
+move-cursor-to: ".docblock .information .should_panic"
+
+assert-css: (".docblock .information .should_panic", {"color": "rgb(255, 0, 0)"})
+assert-css: (".docblock .example-wrap .should_panic", {"border-left": "2px solid rgb(255, 0, 0)"})
+
+// ignore block
+assert-css: (".docblock .information .ignore", {"color": "rgba(255, 142, 0, 0.6)"})
+assert-css: (".docblock .example-wrap .ignore", {"border-left": "2px solid rgba(255, 142, 0, 0.6)"})
+
+move-cursor-to: ".docblock .information .ignore"
+
+assert-css: (".docblock .information .ignore", {"color": "rgb(255, 142, 0)"})
+assert-css: (".docblock .example-wrap .ignore", {"border-left": "2px solid rgb(255, 142, 0)"})
+
+
+// Ayu theme.
+local-storage: {"rustdoc-theme": "ayu"}
+reload:
+
+assert-css: (".docblock .information .compile_fail", {"color": "rgba(255, 0, 0, 0.5)"})
+assert-css: (".docblock .example-wrap .compile_fail", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
+
+move-cursor-to: ".docblock .information .compile_fail"
+
+assert-css: (".docblock .information .compile_fail", {"color": "rgb(255, 0, 0)"})
+assert-css: (".docblock .example-wrap .compile_fail", {"border-left": "2px solid rgb(255, 0, 0)"})
+
+// should_panic block
+assert-css: (".docblock .information .should_panic", {"color": "rgba(255, 0, 0, 0.5)"})
+assert-css: (".docblock .example-wrap .should_panic", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
+
+move-cursor-to: ".docblock .information .should_panic"
+
+assert-css: (".docblock .information .should_panic", {"color": "rgb(255, 0, 0)"})
+assert-css: (".docblock .example-wrap .should_panic", {"border-left": "2px solid rgb(255, 0, 0)"})
+
+// ignore block
+assert-css: (".docblock .information .ignore", {"color": "rgba(255, 142, 0, 0.6)"})
+assert-css: (".docblock .example-wrap .ignore", {"border-left": "2px solid rgba(255, 142, 0, 0.6)"})
+
+move-cursor-to: ".docblock .information .ignore"
+
+assert-css: (".docblock .information .ignore", {"color": "rgb(255, 142, 0)"})
+assert-css: (".docblock .example-wrap .ignore", {"border-left": "2px solid rgb(255, 142, 0)"})

From 773f9b38e39033576201a7901bb4b321871e8cb5 Mon Sep 17 00:00:00 2001
From: Stanislav 
Date: Fri, 9 Sep 2022 01:19:34 +0300
Subject: [PATCH 4357/5092] fix. round 4

---
 docs/user/generated_config.adoc |  4 ++--
 editors/code/package.json       | 10 +++++-----
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index 517a73edd33f..337629e17fd9 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -260,12 +260,12 @@ also need to add the folders to Code's `files.watcherExclude`.
 [[rust-analyzer.files.watcher]]rust-analyzer.files.watcher (default: `"client"`)::
 +
 --
-Find All References config.
+Controls file watching implementation.
 --
 [[rust-analyzer.findAllRefs.excludeImports]]rust-analyzer.findAllRefs.excludeImports (default: `false`)::
 +
 --
-Controls file watching implementation.
+Exclude imports from find-all-references.
 --
 [[rust-analyzer.highlightRelated.breakPoints.enable]]rust-analyzer.highlightRelated.breakPoints.enable (default: `true`)::
 +
diff --git a/editors/code/package.json b/editors/code/package.json
index 189f20fc0cd9..07e9a08e1bd7 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -706,6 +706,11 @@
                         "Use server-side file watching"
                     ]
                 },
+                "rust-analyzer.findAllRefs.excludeImports": {
+                    "markdownDescription": "Exclude imports from find-all-references.",
+                    "default": false,
+                    "type": "boolean"
+                },
                 "rust-analyzer.highlightRelated.breakPoints.enable": {
                     "markdownDescription": "Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.",
                     "default": true,
@@ -839,11 +844,6 @@
                     "type": "integer",
                     "minimum": 0
                 },
-                "rust-analyzer.findAllRefs.excludeImports": {
-                    "markdownDescription": "Exclude imports from find-all-references.",
-                    "default": false,
-                    "type": "boolean"
-                },
                 "rust-analyzer.inlayHints.closureReturnTypeHints.enable": {
                     "markdownDescription": "Whether to show inlay type hints for return types of closures.",
                     "default": "never",

From ed0f0377e2620ed3c70a42890ca420c1472eb788 Mon Sep 17 00:00:00 2001
From: Eric Huss 
Date: Thu, 8 Sep 2022 16:08:53 -0700
Subject: [PATCH 4358/5092] Fix ICE report flags display.

---
 compiler/rustc_driver/src/lib.rs | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index a193d5db6916..d6f51d7eee1a 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -1119,22 +1119,25 @@ fn extra_compiler_flags() -> Option<(Vec, bool)> {
     while let Some(arg) = args.next() {
         if let Some(a) = ICE_REPORT_COMPILER_FLAGS.iter().find(|a| arg.starts_with(*a)) {
             let content = if arg.len() == a.len() {
+                // A space-separated option, like `-C incremental=foo` or `--crate-type rlib`
                 match args.next() {
                     Some(arg) => arg.to_string(),
                     None => continue,
                 }
             } else if arg.get(a.len()..a.len() + 1) == Some("=") {
+                // An equals option, like `--crate-type=rlib`
                 arg[a.len() + 1..].to_string()
             } else {
+                // A non-space option, like `-Cincremental=foo`
                 arg[a.len()..].to_string()
             };
-            if ICE_REPORT_COMPILER_FLAGS_EXCLUDE.iter().any(|exc| content.starts_with(exc)) {
+            let option = content.split_once('=').map(|s| s.0).unwrap_or(&content);
+            if ICE_REPORT_COMPILER_FLAGS_EXCLUDE.iter().any(|exc| option == *exc) {
                 excluded_cargo_defaults = true;
             } else {
                 result.push(a.to_string());
-                match ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.iter().find(|s| content.starts_with(*s))
-                {
-                    Some(s) => result.push(s.to_string()),
+                match ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.iter().find(|s| option == **s) {
+                    Some(s) => result.push(format!("{}=[REDACTED]", s)),
                     None => result.push(content),
                 }
             }

From 1ca9eb8ec3bcf8860d08a4e92f0eb8ebbf112fc4 Mon Sep 17 00:00:00 2001
From: Jack Huey <31162821+jackh726@users.noreply.github.com>
Date: Sun, 26 Jun 2022 15:40:45 -0400
Subject: [PATCH 4359/5092] Remove ReEmpty

---
 .../src/diagnostics/region_name.rs            |  6 +-
 .../src/region_infer/opaque_types.rs          |  4 +-
 .../src/type_check/free_region_relations.rs   |  7 --
 .../rustc_borrowck/src/universal_regions.rs   | 19 +-----
 .../src/errors/note_and_explain.rs            |  7 --
 .../src/infer/canonical/canonicalizer.rs      | 11 +--
 compiler/rustc_infer/src/infer/combine.rs     |  2 -
 .../src/infer/error_reporting/mod.rs          | 19 +-----
 compiler/rustc_infer/src/infer/freshen.rs     |  1 -
 .../src/infer/lexical_region_resolve/mod.rs   | 68 ++-----------------
 .../src/infer/region_constraints/mod.rs       |  1 -
 compiler/rustc_middle/src/ty/print/pretty.rs  | 10 +--
 compiler/rustc_middle/src/ty/sty.rs           |  8 +--
 .../src/typeid/typeid_itanium_cxx_abi.rs      |  3 +-
 compiler/rustc_traits/src/chalk/lowering.rs   |  8 +--
 compiler/rustc_type_ir/src/sty.rs             | 33 ++-------
 compiler/rustc_typeck/src/outlives/utils.rs   |  6 --
 .../rustc_typeck/src/variance/constraints.rs  |  6 +-
 src/librustdoc/clean/mod.rs                   |  9 ---
 .../nll/named_lifetimes_basic.use_x.nll.0.mir | 27 ++++----
 ...egion_subtyping_basic.main.nll.0.32bit.mir | 23 +++----
 ...egion_subtyping_basic.main.nll.0.64bit.mir | 23 +++----
 .../mir-opt/storage_ranges.main.nll.0.mir     | 11 ++-
 .../closure-print-generic-verbose-1.stderr    |  2 +-
 ...oximated-shorter-to-static-no-bound.stderr |  2 +-
 ...mated-shorter-to-static-wrong-bound.stderr |  2 +-
 .../src/needless_pass_by_value.rs             |  2 +-
 27 files changed, 64 insertions(+), 256 deletions(-)

diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 75fde53b6cde..ce7c2841662b 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -357,11 +357,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                 ty::BoundRegionKind::BrAnon(_) => None,
             },
 
-            ty::ReLateBound(..)
-            | ty::ReVar(..)
-            | ty::RePlaceholder(..)
-            | ty::ReEmpty(_)
-            | ty::ReErased => None,
+            ty::ReLateBound(..) | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReErased => None,
         }
     }
 
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 0b8ed0fcf270..9d088642f777 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -486,9 +486,9 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
             ty::ReErased => return r,
 
             // The regions that we expect from borrow checking.
-            ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {}
+            ty::ReEarlyBound(_) | ty::ReFree(_) => {}
 
-            ty::ReEmpty(_) | ty::RePlaceholder(_) | ty::ReVar(_) => {
+            ty::RePlaceholder(_) | ty::ReVar(_) => {
                 // All of the regions in the type should either have been
                 // erased by writeback, or mapped back to named regions by
                 // borrow checking.
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index 7c10047e9dc8..f1b1c33a1054 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -347,13 +347,6 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
 
             match outlives_bound {
                 OutlivesBound::RegionSubRegion(r1, r2) => {
-                    // `where Type:` is lowered to `where Type: 'empty` so that
-                    // we check `Type` is well formed, but there's no use for
-                    // this bound here.
-                    if r1.is_empty() {
-                        return;
-                    }
-
                     // The bound says that `r1 <= r2`; we store `r2: r1`.
                     let r1 = self.universal_regions.to_region_vid(r1);
                     let r2 = self.universal_regions.to_region_vid(r2);
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index b9b181681ec4..8cf9ed53d39d 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -54,13 +54,6 @@ pub struct UniversalRegions<'tcx> {
     /// The total number of universal region variables instantiated.
     num_universals: usize,
 
-    /// A special region variable created for the `'empty(U0)` region.
-    /// Note that this is **not** a "universal" region, as it doesn't
-    /// represent a universally bound placeholder or any such thing.
-    /// But we do create it here in this type because it's a useful region
-    /// to have around in a few limited cases.
-    pub root_empty: RegionVid,
-
     /// The "defining" type for this function, with all universal
     /// regions instantiated. For a closure or generator, this is the
     /// closure type, but for a top-level function it's the `FnDef`.
@@ -323,11 +316,7 @@ impl<'tcx> UniversalRegions<'tcx> {
 
     /// See `UniversalRegionIndices::to_region_vid`.
     pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
-        if let ty::ReEmpty(ty::UniverseIndex::ROOT) = *r {
-            self.root_empty
-        } else {
-            self.indices.to_region_vid(r)
-        }
+        self.indices.to_region_vid(r)
     }
 
     /// As part of the NLL unit tests, you can annotate a function with
@@ -501,16 +490,10 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
             _ => None,
         };
 
-        let root_empty = self
-            .infcx
-            .next_nll_region_var(NllRegionVariableOrigin::Existential { from_forall: true })
-            .to_region_vid();
-
         UniversalRegions {
             indices,
             fr_static,
             fr_fn_body,
-            root_empty,
             first_extern_index,
             first_local_index,
             num_universals,
diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs
index 6f1f9522c869..7e051835b4bd 100644
--- a/compiler/rustc_infer/src/errors/note_and_explain.rs
+++ b/compiler/rustc_infer/src/errors/note_and_explain.rs
@@ -27,13 +27,6 @@ impl<'a> DescriptionCtx<'a> {
                 me.kind = "restatic";
             }
 
-            ty::ReEmpty(ty::UniverseIndex::ROOT) => me.kind = "reempty",
-
-            ty::ReEmpty(ui) => {
-                me.kind = "reemptyuni";
-                me.arg = format!("{:?}", ui);
-            }
-
             ty::RePlaceholder(_) => return None,
 
             // FIXME(#13998) RePlaceholder should probably print like
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 46f8c0e8d8b9..9488d0a6cbb6 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -180,11 +180,7 @@ impl CanonicalizeMode for CanonicalizeQueryResponse {
         r: ty::Region<'tcx>,
     ) -> ty::Region<'tcx> {
         match *r {
-            ty::ReFree(_)
-            | ty::ReErased
-            | ty::ReStatic
-            | ty::ReEmpty(ty::UniverseIndex::ROOT)
-            | ty::ReEarlyBound(..) => r,
+            ty::ReFree(_) | ty::ReErased | ty::ReStatic | ty::ReEarlyBound(..) => r,
 
             ty::RePlaceholder(placeholder) => canonicalizer.canonical_var_for_region(
                 CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderRegion(placeholder) },
@@ -199,10 +195,6 @@ impl CanonicalizeMode for CanonicalizeQueryResponse {
                 )
             }
 
-            ty::ReEmpty(ui) => {
-                bug!("canonicalizing 'empty in universe {:?}", ui) // FIXME
-            }
-
             _ => {
                 // Other than `'static` or `'empty`, the query
                 // response should be executing in a fully
@@ -381,7 +373,6 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
             ty::ReStatic
             | ty::ReEarlyBound(..)
             | ty::ReFree(_)
-            | ty::ReEmpty(_)
             | ty::RePlaceholder(..)
             | ty::ReErased => self.canonicalize_mode.canonicalize_free_region(self, r),
         }
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index c1fb59009d36..524383e381fe 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -688,7 +688,6 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
 
             ty::RePlaceholder(..)
             | ty::ReVar(..)
-            | ty::ReEmpty(_)
             | ty::ReStatic
             | ty::ReEarlyBound(..)
             | ty::ReFree(..) => {
@@ -900,7 +899,6 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
 
             ty::RePlaceholder(..)
             | ty::ReVar(..)
-            | ty::ReEmpty(_)
             | ty::ReStatic
             | ty::ReEarlyBound(..)
             | ty::ReFree(..) => {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index ed85c7533603..720d74b1ce61 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -96,11 +96,6 @@ pub(super) fn note_and_explain_region<'tcx>(
             msg_span_from_free_region(tcx, region, alt_span)
         }
 
-        ty::ReEmpty(ty::UniverseIndex::ROOT) => ("the empty lifetime".to_owned(), alt_span),
-
-        // uh oh, hope no user ever sees THIS
-        ty::ReEmpty(ui) => (format!("the empty lifetime in universe {:?}", ui), alt_span),
-
         ty::RePlaceholder(_) => return,
 
         // FIXME(#13998) RePlaceholder should probably print like
@@ -139,8 +134,6 @@ fn msg_span_from_free_region<'tcx>(
             (msg, Some(span))
         }
         ty::ReStatic => ("the static lifetime".to_owned(), alt_span),
-        ty::ReEmpty(ty::UniverseIndex::ROOT) => ("an empty lifetime".to_owned(), alt_span),
-        ty::ReEmpty(ui) => (format!("an empty lifetime in universe {:?}", ui), alt_span),
         _ => bug!("{:?}", region),
     }
 }
@@ -250,17 +243,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
 
     // Explain the region we are capturing.
     match *hidden_region {
-        ty::ReEmpty(ty::UniverseIndex::ROOT) => {
-            // All lifetimes shorter than the function body are `empty` in
-            // lexical region resolution. The default explanation of "an empty
-            // lifetime" isn't really accurate here.
-            let message = format!(
-                "hidden type `{}` captures lifetime smaller than the function body",
-                hidden_ty
-            );
-            err.span_note(span, &message);
-        }
-        ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic | ty::ReEmpty(_) => {
+        ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic => {
             // Assuming regionck succeeded (*), we ought to always be
             // capturing *some* region from the fn header, and hence it
             // ought to be free. So under normal circumstances, we will go
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index 84004d2b21f9..fee15afc7b3a 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -126,7 +126,6 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
             | ty::ReFree(_)
             | ty::ReVar(_)
             | ty::RePlaceholder(..)
-            | ty::ReEmpty(_)
             | ty::ReErased => {
                 // replace all free regions with 'erased
                 self.tcx().lifetimes.re_erased
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index 99f956bede7a..0ed57706790a 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -16,7 +16,7 @@ use rustc_data_structures::intern::Interned;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_middle::ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic};
+use rustc_middle::ty::{ReEarlyBound, ReErased, ReFree, ReStatic};
 use rustc_middle::ty::{ReLateBound, RePlaceholder, ReVar};
 use rustc_middle::ty::{Region, RegionVid};
 use rustc_span::Span;
@@ -261,13 +261,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
                                         cur_region
                                     }
 
-                                    ReEmpty(b_ui) => {
-                                        // Empty regions are ordered according to the universe
-                                        // they are associated with.
-                                        let ui = a_universe.min(b_ui);
-                                        self.tcx().mk_region(ReEmpty(ui))
-                                    }
-
                                     RePlaceholder(placeholder) => {
                                         // If the empty and placeholder regions are in the same universe,
                                         // then the LUB is the Placeholder region (which is the cur_region).
@@ -399,13 +392,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
                         a_region
                     }
 
-                    ReEmpty(a_ui) => {
-                        // Empty regions are ordered according to the universe
-                        // they are associated with.
-                        let ui = a_ui.min(empty_ui);
-                        self.tcx().mk_region(ReEmpty(ui))
-                    }
-
                     RePlaceholder(placeholder) => {
                         // If this empty region is from a universe that can
                         // name the placeholder, then the placeholder is
@@ -428,9 +414,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
                 // check below for a common case, here purely as an
                 // optimization.
                 let b_universe = self.var_infos[b_vid].universe;
-                if let ReEmpty(a_universe) = *a_region && a_universe == b_universe {
-                    return false;
-                }
 
                 let mut lub = self.lub_concrete_regions(a_region, cur_region);
                 if lub == cur_region {
@@ -470,7 +453,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
                 // they are associated with.
                 a_ui.min(b_ui) == b_ui
             }
-            (VarValue::Value(a), VarValue::Empty(b_ui)) => {
+            (VarValue::Value(a), VarValue::Empty(_)) => {
                 match *a {
                     ReLateBound(..) | ReErased => {
                         bug!("cannot relate region: {:?}", a);
@@ -493,12 +476,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
                         false
                     }
 
-                    ReEmpty(a_ui) => {
-                        // Empty regions are ordered according to the universe
-                        // they are associated with.
-                        a_ui.min(b_ui) == b_ui
-                    }
-
                     RePlaceholder(_) => {
                         // The LUB is either `a` or `'static`
                         false
@@ -526,12 +503,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
                         true
                     }
 
-                    ReEmpty(b_ui) => {
-                        // Empty regions are ordered according to the universe
-                        // they are associated with.
-                        a_ui.min(b_ui) == b_ui
-                    }
-
                     RePlaceholder(placeholder) => {
                         // If this empty region is from a universe that can
                         // name the placeholder, then the placeholder is
@@ -599,37 +570,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
                 self.tcx().lifetimes.re_static
             }
 
-            (ReEmpty(_), ReEarlyBound(_) | ReFree(_)) => {
-                // All empty regions are less than early-bound, free,
-                // and scope regions.
-                b
-            }
-
-            (ReEarlyBound(_) | ReFree(_), ReEmpty(_)) => {
-                // All empty regions are less than early-bound, free,
-                // and scope regions.
-                a
-            }
-
-            (ReEmpty(a_ui), ReEmpty(b_ui)) => {
-                // Empty regions are ordered according to the universe
-                // they are associated with.
-                let ui = a_ui.min(b_ui);
-                self.tcx().mk_region(ReEmpty(ui))
-            }
-
-            (ReEmpty(empty_ui), RePlaceholder(placeholder))
-            | (RePlaceholder(placeholder), ReEmpty(empty_ui)) => {
-                // If this empty region is from a universe that can
-                // name the placeholder, then the placeholder is
-                // larger; otherwise, the only ancestor is `'static`.
-                if empty_ui.can_name(placeholder.universe) {
-                    self.tcx().mk_region(RePlaceholder(placeholder))
-                } else {
-                    self.tcx().lifetimes.re_static
-                }
-            }
-
             (ReEarlyBound(_) | ReFree(_), ReEarlyBound(_) | ReFree(_)) => {
                 self.region_rels.lub_free_regions(a, b)
             }
@@ -1088,9 +1028,9 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
                 ty::ReVar(rid) => match var_values.values[rid] {
                     VarValue::ErrorValue => false,
                     VarValue::Empty(_) => true,
-                    VarValue::Value(min) => matches!(*min, ty::ReEmpty(_)),
+                    VarValue::Value(_) => false,
                 },
-                _ => matches!(*min, ty::ReEmpty(_)),
+                _ => false,
             },
 
             VerifyBound::AnyBound(bs) => {
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index 780e6ead10ef..764ef8fa4bb7 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -699,7 +699,6 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
             ty::ReStatic | ty::ReErased | ty::ReFree(..) | ty::ReEarlyBound(..) => {
                 ty::UniverseIndex::ROOT
             }
-            ty::ReEmpty(ui) => ui,
             ty::RePlaceholder(placeholder) => placeholder.universe,
             ty::ReVar(vid) => self.var_universe(vid),
             ty::ReLateBound(..) => bug!("universe(): encountered bound region {:?}", region),
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 1ae3063dae4e..9dbefe337725 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1978,7 +1978,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> {
 
             ty::ReVar(_) | ty::ReErased => false,
 
-            ty::ReStatic | ty::ReEmpty(_) => true,
+            ty::ReStatic => true,
         }
     }
 
@@ -2062,14 +2062,6 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
                 p!("'static");
                 return Ok(self);
             }
-            ty::ReEmpty(ty::UniverseIndex::ROOT) => {
-                p!("'");
-                return Ok(self);
-            }
-            ty::ReEmpty(ui) => {
-                p!(write("'", ui));
-                return Ok(self);
-            }
         }
 
         p!("'_");
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 9fb91b5fe870..a8d2ca4a24eb 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1511,7 +1511,6 @@ impl<'tcx> Region<'tcx> {
             ty::ReStatic => true,
             ty::ReVar(..) => false,
             ty::RePlaceholder(placeholder) => placeholder.name.is_named(),
-            ty::ReEmpty(_) => false,
             ty::ReErased => false,
         }
     }
@@ -1536,11 +1535,6 @@ impl<'tcx> Region<'tcx> {
         matches!(*self, ty::RePlaceholder(..))
     }
 
-    #[inline]
-    pub fn is_empty(self) -> bool {
-        matches!(*self, ty::ReEmpty(..))
-    }
-
     #[inline]
     pub fn bound_at_or_above_binder(self, index: ty::DebruijnIndex) -> bool {
         match *self {
@@ -1572,7 +1566,7 @@ impl<'tcx> Region<'tcx> {
                 flags = flags | TypeFlags::HAS_FREE_REGIONS;
                 flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
             }
-            ty::ReEmpty(_) | ty::ReStatic => {
+            ty::ReStatic => {
                 flags = flags | TypeFlags::HAS_FREE_REGIONS;
             }
             ty::ReLateBound(..) => {
diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
index b1de979e8f8e..bd8126f61777 100644
--- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
@@ -305,8 +305,7 @@ fn encode_region<'tcx>(
         | RegionKind::ReFree(..)
         | RegionKind::ReStatic
         | RegionKind::ReVar(..)
-        | RegionKind::RePlaceholder(..)
-        | RegionKind::ReEmpty(..) => {
+        | RegionKind::RePlaceholder(..) => {
             bug!("encode_region: unexpected `{:?}`", region.kind());
         }
     }
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index a166371fed1e..a6a098ce73f8 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -485,10 +485,6 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Lifetime>> for Region<'t
                 })
                 .intern(interner)
             }
-            ty::ReEmpty(ui) => {
-                chalk_ir::LifetimeData::Empty(chalk_ir::UniverseIndex { counter: ui.index() })
-                    .intern(interner)
-            }
             ty::ReErased => chalk_ir::LifetimeData::Erased.intern(interner),
         }
     }
@@ -510,8 +506,8 @@ impl<'tcx> LowerInto<'tcx, Region<'tcx>> for &chalk_ir::Lifetime return interner.tcx.lifetimes.re_static,
-            chalk_ir::LifetimeData::Empty(ui) => {
-                ty::ReEmpty(ty::UniverseIndex::from_usize(ui.counter))
+            chalk_ir::LifetimeData::Empty(_) => {
+                bug!("Chalk should not have been passed an empty lifetime.")
             }
             chalk_ir::LifetimeData::Erased => return interner.tcx.lifetimes.re_erased,
             chalk_ir::LifetimeData::Phantom(void, _) => match *void {},
diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs
index 26e48d2d2147..e164aaed6b4b 100644
--- a/compiler/rustc_type_ir/src/sty.rs
+++ b/compiler/rustc_type_ir/src/sty.rs
@@ -3,14 +3,14 @@
 use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
 use std::{fmt, hash};
 
+use crate::DebruijnIndex;
 use crate::FloatTy;
+use crate::HashStableContext;
 use crate::IntTy;
 use crate::Interner;
 use crate::TyDecoder;
 use crate::TyEncoder;
 use crate::UintTy;
-use crate::UniverseIndex;
-use crate::{DebruijnIndex, HashStableContext};
 
 use self::RegionKind::*;
 use self::TyKind::*;
@@ -1023,14 +1023,6 @@ pub enum RegionKind {
     /// Should not exist outside of type inference.
     RePlaceholder(I::PlaceholderRegion),
 
-    /// Empty lifetime is for data that is never accessed.  We tag the
-    /// empty lifetime with a universe -- the idea is that we don't
-    /// want `exists<'a> { forall<'b> { 'b: 'a } }` to be satisfiable.
-    /// Therefore, the `'empty` in a universe `U` is less than all
-    /// regions visible from `U`, but not less than regions not visible
-    /// from `U`.
-    ReEmpty(UniverseIndex),
-
     /// Erased region, used by trait selection, in MIR and during codegen.
     ReErased,
 }
@@ -1046,8 +1038,7 @@ const fn regionkind_discriminant(value: &RegionKind) -> usize {
         ReStatic => 3,
         ReVar(_) => 4,
         RePlaceholder(_) => 5,
-        ReEmpty(_) => 6,
-        ReErased => 7,
+        ReErased => 6,
     }
 }
 
@@ -1072,7 +1063,6 @@ impl Clone for RegionKind {
             ReStatic => ReStatic,
             ReVar(a) => ReVar(a.clone()),
             RePlaceholder(a) => RePlaceholder(a.clone()),
-            ReEmpty(a) => ReEmpty(a.clone()),
             ReErased => ReErased,
         }
     }
@@ -1099,7 +1089,6 @@ impl PartialEq for RegionKind {
                 (&RePlaceholder(ref __self_0), &RePlaceholder(ref __arg_1_0)) => {
                     __self_0 == __arg_1_0
                 }
-                (&ReEmpty(ref __self_0), &ReEmpty(ref __arg_1_0)) => __self_0 == __arg_1_0,
                 (&ReErased, &ReErased) => true,
                 _ => true,
             }
@@ -1144,7 +1133,6 @@ impl Ord for RegionKind {
                 (&RePlaceholder(ref __self_0), &RePlaceholder(ref __arg_1_0)) => {
                     Ord::cmp(__self_0, __arg_1_0)
                 }
-                (&ReEmpty(ref __self_0), &ReEmpty(ref __arg_1_0)) => Ord::cmp(__self_0, __arg_1_0),
                 (&ReErased, &ReErased) => Ordering::Equal,
                 _ => Ordering::Equal,
             }
@@ -1182,10 +1170,6 @@ impl hash::Hash for RegionKind {
                 hash::Hash::hash(®ionkind_discriminant(self), state);
                 hash::Hash::hash(__self_0, state)
             }
-            (&ReEmpty(ref __self_0),) => {
-                hash::Hash::hash(®ionkind_discriminant(self), state);
-                hash::Hash::hash(__self_0, state)
-            }
             (&ReErased,) => {
                 hash::Hash::hash(®ionkind_discriminant(self), state);
             }
@@ -1211,8 +1195,6 @@ impl fmt::Debug for RegionKind {
 
             RePlaceholder(placeholder) => write!(f, "RePlaceholder({:?})", placeholder),
 
-            ReEmpty(ui) => write!(f, "ReEmpty({:?})", ui),
-
             ReErased => write!(f, "ReErased"),
         }
     }
@@ -1247,9 +1229,6 @@ where
             RePlaceholder(a) => e.emit_enum_variant(disc, |e| {
                 a.encode(e);
             }),
-            ReEmpty(a) => e.emit_enum_variant(disc, |e| {
-                a.encode(e);
-            }),
             ReErased => e.emit_enum_variant(disc, |_| {}),
         }
     }
@@ -1272,8 +1251,7 @@ where
             3 => ReStatic,
             4 => ReVar(Decodable::decode(d)),
             5 => RePlaceholder(Decodable::decode(d)),
-            6 => ReEmpty(Decodable::decode(d)),
-            7 => ReErased,
+            6 => ReErased,
             _ => panic!(
                 "{}",
                 format!(
@@ -1305,9 +1283,6 @@ where
             ReErased | ReStatic => {
                 // No variant fields to hash for these ...
             }
-            ReEmpty(universe) => {
-                universe.hash_stable(hcx, hasher);
-            }
             ReLateBound(db, br) => {
                 db.hash_stable(hcx, hasher);
                 br.hash_stable(hcx, hasher);
diff --git a/compiler/rustc_typeck/src/outlives/utils.rs b/compiler/rustc_typeck/src/outlives/utils.rs
index b718ca942133..3e8d023fb551 100644
--- a/compiler/rustc_typeck/src/outlives/utils.rs
+++ b/compiler/rustc_typeck/src/outlives/utils.rs
@@ -161,12 +161,6 @@ fn is_free_region(region: Region<'_>) -> bool {
         // ignore it.  We can't put it on the struct header anyway.
         ty::ReLateBound(..) => false,
 
-        // This can appear in `where Self: ` bounds (#64855):
-        //
-        //     struct Bar(::Type) where Self: ;
-        //     struct Baz<'a>(&'a Self) where Self: ;
-        ty::ReEmpty(_) => false,
-
         // These regions don't appear in types from type declarations:
         ty::ReErased | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReFree(..) => {
             bug!("unexpected region in outlives inference: {:?}", region);
diff --git a/compiler/rustc_typeck/src/variance/constraints.rs b/compiler/rustc_typeck/src/variance/constraints.rs
index 4fe213ffeea3..840f0c978484 100644
--- a/compiler/rustc_typeck/src/variance/constraints.rs
+++ b/compiler/rustc_typeck/src/variance/constraints.rs
@@ -411,11 +411,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 // way early-bound regions do, so we skip them here.
             }
 
-            ty::ReFree(..)
-            | ty::ReVar(..)
-            | ty::RePlaceholder(..)
-            | ty::ReEmpty(_)
-            | ty::ReErased => {
+            ty::ReFree(..) | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReErased => {
                 // We don't expect to see anything but 'static or bound
                 // regions when visiting member types or method types.
                 bug!(
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 66f766bfbe8d..a132a029fca2 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -241,7 +241,6 @@ pub(crate) fn clean_middle_region<'tcx>(region: ty::Region<'tcx>) -> Option {
             debug!("cannot clean region {:?}", region);
             None
@@ -338,10 +337,6 @@ fn clean_region_outlives_predicate<'tcx>(
 ) -> Option {
     let ty::OutlivesPredicate(a, b) = pred;
 
-    if a.is_empty() && b.is_empty() {
-        return None;
-    }
-
     Some(WherePredicate::RegionPredicate {
         lifetime: clean_middle_region(a).expect("failed to clean lifetime"),
         bounds: vec![GenericBound::Outlives(
@@ -356,10 +351,6 @@ fn clean_type_outlives_predicate<'tcx>(
 ) -> Option {
     let ty::OutlivesPredicate(ty, lt) = pred;
 
-    if lt.is_empty() {
-        return None;
-    }
-
     Some(WherePredicate::BoundPredicate {
         ty: clean_middle_ty(ty, cx, None),
         bounds: vec![GenericBound::Outlives(
diff --git a/src/test/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir b/src/test/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir
index cbfdf8c5d563..0ab9d712d9f6 100644
--- a/src/test/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir
+++ b/src/test/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir
@@ -13,11 +13,10 @@
 | '_#2r | U0 | {bb0[0..=1], '_#2r}
 | '_#3r | U0 | {bb0[0..=1], '_#3r}
 | '_#4r | U0 | {bb0[0..=1], '_#4r}
-| '_#5r | U0 | {}
-| '_#6r | U0 | {bb0[0..=1], '_#1r}
-| '_#7r | U0 | {bb0[0..=1], '_#2r}
-| '_#8r | U0 | {bb0[0..=1], '_#1r}
-| '_#9r | U0 | {bb0[0..=1], '_#3r}
+| '_#5r | U0 | {bb0[0..=1], '_#1r}
+| '_#6r | U0 | {bb0[0..=1], '_#2r}
+| '_#7r | U0 | {bb0[0..=1], '_#1r}
+| '_#8r | U0 | {bb0[0..=1], '_#3r}
 |
 | Inference Constraints
 | '_#0r live at {bb0[0..=1]}
@@ -25,16 +24,16 @@
 | '_#2r live at {bb0[0..=1]}
 | '_#3r live at {bb0[0..=1]}
 | '_#4r live at {bb0[0..=1]}
-| '_#1r: '_#6r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27) ($DIR/named-lifetimes-basic.rs:12:26: 12:27 (#0)
-| '_#1r: '_#8r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55) ($DIR/named-lifetimes-basic.rs:12:54: 12:55 (#0)
-| '_#2r: '_#7r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43) ($DIR/named-lifetimes-basic.rs:12:42: 12:43 (#0)
-| '_#3r: '_#9r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67) ($DIR/named-lifetimes-basic.rs:12:66: 12:67 (#0)
-| '_#6r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27) ($DIR/named-lifetimes-basic.rs:12:26: 12:27 (#0)
-| '_#7r: '_#2r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43) ($DIR/named-lifetimes-basic.rs:12:42: 12:43 (#0)
-| '_#8r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55) ($DIR/named-lifetimes-basic.rs:12:54: 12:55 (#0)
-| '_#9r: '_#3r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67) ($DIR/named-lifetimes-basic.rs:12:66: 12:67 (#0)
+| '_#1r: '_#5r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27) ($DIR/named-lifetimes-basic.rs:12:26: 12:27 (#0)
+| '_#1r: '_#7r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55) ($DIR/named-lifetimes-basic.rs:12:54: 12:55 (#0)
+| '_#2r: '_#6r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43) ($DIR/named-lifetimes-basic.rs:12:42: 12:43 (#0)
+| '_#3r: '_#8r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67) ($DIR/named-lifetimes-basic.rs:12:66: 12:67 (#0)
+| '_#5r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27) ($DIR/named-lifetimes-basic.rs:12:26: 12:27 (#0)
+| '_#6r: '_#2r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43) ($DIR/named-lifetimes-basic.rs:12:42: 12:43 (#0)
+| '_#7r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55) ($DIR/named-lifetimes-basic.rs:12:54: 12:55 (#0)
+| '_#8r: '_#3r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67) ($DIR/named-lifetimes-basic.rs:12:66: 12:67 (#0)
 |
-fn use_x(_1: &'_#6r mut i32, _2: &'_#7r u32, _3: &'_#8r u32, _4: &'_#9r u32) -> bool {
+fn use_x(_1: &'_#5r mut i32, _2: &'_#6r u32, _3: &'_#7r u32, _4: &'_#8r u32) -> bool {
     debug w => _1;                       // in scope 0 at $DIR/named-lifetimes-basic.rs:+0:26: +0:27
     debug x => _2;                       // in scope 0 at $DIR/named-lifetimes-basic.rs:+0:42: +0:43
     debug y => _3;                       // in scope 0 at $DIR/named-lifetimes-basic.rs:+0:54: +0:55
diff --git a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir
index 55e7faf9ee47..36705d18e016 100644
--- a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir
+++ b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir
@@ -7,19 +7,18 @@
 | Inferred Region Values
 | '_#0r | U0 | {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0], '_#0r, '_#1r}
 | '_#1r | U0 | {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0], '_#1r}
-| '_#2r | U0 | {}
-| '_#3r | U0 | {bb1[0..=7], bb2[0..=2]}
-| '_#4r | U0 | {bb1[1..=7], bb2[0..=2]}
-| '_#5r | U0 | {bb1[4..=7], bb2[0..=2]}
+| '_#2r | U0 | {bb1[0..=7], bb2[0..=2]}
+| '_#3r | U0 | {bb1[1..=7], bb2[0..=2]}
+| '_#4r | U0 | {bb1[4..=7], bb2[0..=2]}
 |
 | Inference Constraints
 | '_#0r live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0]}
 | '_#1r live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0]}
-| '_#3r live at {bb1[0]}
-| '_#4r live at {bb1[1..=3]}
-| '_#5r live at {bb1[4..=7], bb2[0..=2]}
-| '_#3r: '_#4r due to Assignment at Single(bb1[0]) ($DIR/region-subtyping-basic.rs:18:13: 18:18 (#0)
-| '_#4r: '_#5r due to Assignment at Single(bb1[3]) ($DIR/region-subtyping-basic.rs:19:13: 19:14 (#0)
+| '_#2r live at {bb1[0]}
+| '_#3r live at {bb1[1..=3]}
+| '_#4r live at {bb1[4..=7], bb2[0..=2]}
+| '_#2r: '_#3r due to Assignment at Single(bb1[0]) ($DIR/region-subtyping-basic.rs:18:13: 18:18 (#0)
+| '_#3r: '_#4r due to Assignment at Single(bb1[3]) ($DIR/region-subtyping-basic.rs:19:13: 19:14 (#0)
 |
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/region-subtyping-basic.rs:+0:11: +0:11
@@ -33,10 +32,10 @@ fn main() -> () {
     let _10: bool;                       // in scope 0 at $DIR/region-subtyping-basic.rs:+7:9: +7:18
     scope 1 {
         debug v => _1;                   // in scope 1 at $DIR/region-subtyping-basic.rs:+1:9: +1:14
-        let _2: &'_#4r usize;            // in scope 1 at $DIR/region-subtyping-basic.rs:+2:9: +2:10
+        let _2: &'_#3r usize;            // in scope 1 at $DIR/region-subtyping-basic.rs:+2:9: +2:10
         scope 2 {
             debug p => _2;               // in scope 2 at $DIR/region-subtyping-basic.rs:+2:9: +2:10
-            let _6: &'_#5r usize;        // in scope 2 at $DIR/region-subtyping-basic.rs:+3:9: +3:10
+            let _6: &'_#4r usize;        // in scope 2 at $DIR/region-subtyping-basic.rs:+3:9: +3:10
             scope 3 {
                 debug q => _6;           // in scope 3 at $DIR/region-subtyping-basic.rs:+3:9: +3:10
             }
@@ -56,7 +55,7 @@ fn main() -> () {
     }
 
     bb1: {
-        _2 = &'_#3r _1[_3];              // bb1[0]: scope 1 at $DIR/region-subtyping-basic.rs:+2:13: +2:18
+        _2 = &'_#2r _1[_3];              // bb1[0]: scope 1 at $DIR/region-subtyping-basic.rs:+2:13: +2:18
         FakeRead(ForLet(None), _2);      // bb1[1]: scope 1 at $DIR/region-subtyping-basic.rs:+2:9: +2:10
         StorageLive(_6);                 // bb1[2]: scope 2 at $DIR/region-subtyping-basic.rs:+3:9: +3:10
         _6 = _2;                         // bb1[3]: scope 2 at $DIR/region-subtyping-basic.rs:+3:13: +3:14
diff --git a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir
index 2647c94335f8..4f6256a67f46 100644
--- a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir
+++ b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir
@@ -7,19 +7,18 @@
 | Inferred Region Values
 | '_#0r | U0 | {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0], '_#0r, '_#1r}
 | '_#1r | U0 | {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0], '_#1r}
-| '_#2r | U0 | {}
-| '_#3r | U0 | {bb1[0..=7], bb2[0..=2]}
-| '_#4r | U0 | {bb1[1..=7], bb2[0..=2]}
-| '_#5r | U0 | {bb1[4..=7], bb2[0..=2]}
+| '_#2r | U0 | {bb1[0..=7], bb2[0..=2]}
+| '_#3r | U0 | {bb1[1..=7], bb2[0..=2]}
+| '_#4r | U0 | {bb1[4..=7], bb2[0..=2]}
 |
 | Inference Constraints
 | '_#0r live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0]}
 | '_#1r live at {bb0[0..=8], bb1[0..=7], bb2[0..=3], bb3[0..=3], bb4[0..=1], bb5[0..=2], bb6[0..=5], bb7[0]}
-| '_#3r live at {bb1[0]}
-| '_#4r live at {bb1[1..=3]}
-| '_#5r live at {bb1[4..=7], bb2[0..=2]}
-| '_#3r: '_#4r due to Assignment at Single(bb1[0]) ($DIR/region-subtyping-basic.rs:18:13: 18:18 (#0)
-| '_#4r: '_#5r due to Assignment at Single(bb1[3]) ($DIR/region-subtyping-basic.rs:19:13: 19:14 (#0)
+| '_#2r live at {bb1[0]}
+| '_#3r live at {bb1[1..=3]}
+| '_#4r live at {bb1[4..=7], bb2[0..=2]}
+| '_#2r: '_#3r due to Assignment at Single(bb1[0]) ($DIR/region-subtyping-basic.rs:18:13: 18:18 (#0)
+| '_#3r: '_#4r due to Assignment at Single(bb1[3]) ($DIR/region-subtyping-basic.rs:19:13: 19:14 (#0)
 |
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/region-subtyping-basic.rs:+0:11: +0:11
@@ -33,10 +32,10 @@ fn main() -> () {
     let _10: bool;                       // in scope 0 at $DIR/region-subtyping-basic.rs:+7:9: +7:18
     scope 1 {
         debug v => _1;                   // in scope 1 at $DIR/region-subtyping-basic.rs:+1:9: +1:14
-        let _2: &'_#4r usize;            // in scope 1 at $DIR/region-subtyping-basic.rs:+2:9: +2:10
+        let _2: &'_#3r usize;            // in scope 1 at $DIR/region-subtyping-basic.rs:+2:9: +2:10
         scope 2 {
             debug p => _2;               // in scope 2 at $DIR/region-subtyping-basic.rs:+2:9: +2:10
-            let _6: &'_#5r usize;        // in scope 2 at $DIR/region-subtyping-basic.rs:+3:9: +3:10
+            let _6: &'_#4r usize;        // in scope 2 at $DIR/region-subtyping-basic.rs:+3:9: +3:10
             scope 3 {
                 debug q => _6;           // in scope 3 at $DIR/region-subtyping-basic.rs:+3:9: +3:10
             }
@@ -56,7 +55,7 @@ fn main() -> () {
     }
 
     bb1: {
-        _2 = &'_#3r _1[_3];              // bb1[0]: scope 1 at $DIR/region-subtyping-basic.rs:+2:13: +2:18
+        _2 = &'_#2r _1[_3];              // bb1[0]: scope 1 at $DIR/region-subtyping-basic.rs:+2:13: +2:18
         FakeRead(ForLet(None), _2);      // bb1[1]: scope 1 at $DIR/region-subtyping-basic.rs:+2:9: +2:10
         StorageLive(_6);                 // bb1[2]: scope 2 at $DIR/region-subtyping-basic.rs:+3:9: +3:10
         _6 = _2;                         // bb1[3]: scope 2 at $DIR/region-subtyping-basic.rs:+3:13: +3:14
diff --git a/src/test/mir-opt/storage_ranges.main.nll.0.mir b/src/test/mir-opt/storage_ranges.main.nll.0.mir
index 812eb3b82a6d..8e10e70f192d 100644
--- a/src/test/mir-opt/storage_ranges.main.nll.0.mir
+++ b/src/test/mir-opt/storage_ranges.main.nll.0.mir
@@ -7,16 +7,15 @@
 | Inferred Region Values
 | '_#0r | U0 | {bb0[0..=22], '_#0r, '_#1r}
 | '_#1r | U0 | {bb0[0..=22], '_#1r}
-| '_#2r | U0 | {}
-| '_#3r | U0 | {bb0[10..=11]}
-| '_#4r | U0 | {bb0[11]}
+| '_#2r | U0 | {bb0[10..=11]}
+| '_#3r | U0 | {bb0[11]}
 |
 | Inference Constraints
 | '_#0r live at {bb0[0..=22]}
 | '_#1r live at {bb0[0..=22]}
-| '_#3r live at {bb0[10]}
-| '_#4r live at {bb0[11]}
-| '_#3r: '_#4r due to Assignment at Single(bb0[10]) ($DIR/storage_ranges.rs:6:17: 6:25 (#0)
+| '_#2r live at {bb0[10]}
+| '_#3r live at {bb0[11]}
+| '_#2r: '_#3r due to Assignment at Single(bb0[10]) ($DIR/storage_ranges.rs:6:17: 6:25 (#0)
 |
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/storage_ranges.rs:+0:11: +0:11
diff --git a/src/test/ui/closures/print/closure-print-generic-verbose-1.stderr b/src/test/ui/closures/print/closure-print-generic-verbose-1.stderr
index fdaf353fe3d2..3ab7c66d11f2 100644
--- a/src/test/ui/closures/print/closure-print-generic-verbose-1.stderr
+++ b/src/test/ui/closures/print/closure-print-generic-verbose-1.stderr
@@ -2,7 +2,7 @@ error[E0382]: use of moved value: `c`
   --> $DIR/closure-print-generic-verbose-1.rs:17:5
    |
 LL |     let c = to_fn_once(move|| {
-   |         - move occurs because `c` has type `[f::{closure#0} closure_kind_ty=i32 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=(Foo<&'_#10r str>, T)]`, which does not implement the `Copy` trait
+   |         - move occurs because `c` has type `[f::{closure#0} closure_kind_ty=i32 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=(Foo<&'_#9r str>, T)]`, which does not implement the `Copy` trait
 ...
 LL |     c();
    |     --- `c` moved due to this call
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
index c3c7eb1bd9e5..296131111e83 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
@@ -46,7 +46,7 @@ LL | |     });
    | |______`cell_a` escapes the function body here
    |        argument requires that `'a` must outlive `'static`
    |
-   = note: requirement occurs because of the type `Cell<&'_#10r u32>`, which makes the generic argument `&'_#10r u32` invariant
+   = note: requirement occurs because of the type `Cell<&'_#9r u32>`, which makes the generic argument `&'_#9r u32` invariant
    = note: the struct `Cell` is invariant over the parameter `T`
    = help: see  for more information about variance
 
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
index 846e5aedb3e7..96a1bd1f07b6 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
@@ -46,7 +46,7 @@ LL | |     });
    | |______`cell_a` escapes the function body here
    |        argument requires that `'a` must outlive `'static`
    |
-   = note: requirement occurs because of the type `Cell<&'_#11r u32>`, which makes the generic argument `&'_#11r u32` invariant
+   = note: requirement occurs because of the type `Cell<&'_#10r u32>`, which makes the generic argument `&'_#10r u32` invariant
    = note: the struct `Cell` is invariant over the parameter `T`
    = help: see  for more information about variance
 
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 6d17c7a7346f..060037ed4969 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -173,7 +173,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                 (
                     preds.iter().any(|t| cx.tcx.is_diagnostic_item(sym::Borrow, t.def_id())),
                     !preds.is_empty() && {
-                        let ty_empty_region = cx.tcx.mk_imm_ref(cx.tcx.lifetimes.re_root_empty, ty);
+                        let ty_empty_region = cx.tcx.mk_imm_ref(cx.tcx.lifetimes.re_erased, ty);
                         preds.iter().all(|t| {
                             let ty_params = t.trait_ref.substs.iter().skip(1).collect::>();
                             implements_trait(cx, ty_empty_region, t.def_id(), &ty_params)

From f6d2995fb8b0ec9e4a7ce4f0ec21e7ecc3fb5c49 Mon Sep 17 00:00:00 2001
From: Jack Huey <31162821+jackh726@users.noreply.github.com>
Date: Sun, 26 Jun 2022 18:57:46 -0400
Subject: [PATCH 4360/5092] Make some functions pub(super)

---
 .../src/infer/region_constraints/mod.rs       | 28 +++++++++----------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index 764ef8fa4bb7..e43d28ee56e3 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -426,21 +426,21 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
         data
     }
 
-    pub fn data(&self) -> &RegionConstraintData<'tcx> {
+    pub(super) fn data(&self) -> &RegionConstraintData<'tcx> {
         &self.data
     }
 
-    pub fn start_snapshot(&mut self) -> RegionSnapshot {
+    pub(super) fn start_snapshot(&mut self) -> RegionSnapshot {
         debug!("RegionConstraintCollector: start_snapshot");
         RegionSnapshot { any_unifications: self.any_unifications }
     }
 
-    pub fn rollback_to(&mut self, snapshot: RegionSnapshot) {
+    pub(super) fn rollback_to(&mut self, snapshot: RegionSnapshot) {
         debug!("RegionConstraintCollector: rollback_to({:?})", snapshot);
         self.any_unifications = snapshot.any_unifications;
     }
 
-    pub fn new_region_var(
+    pub(super) fn new_region_var(
         &mut self,
         universe: ty::UniverseIndex,
         origin: RegionVariableOrigin,
@@ -455,12 +455,12 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
     }
 
     /// Returns the universe for the given variable.
-    pub fn var_universe(&self, vid: RegionVid) -> ty::UniverseIndex {
+    pub(super) fn var_universe(&self, vid: RegionVid) -> ty::UniverseIndex {
         self.var_infos[vid].universe
     }
 
     /// Returns the origin for the given variable.
-    pub fn var_origin(&self, vid: RegionVid) -> RegionVariableOrigin {
+    pub(super) fn var_origin(&self, vid: RegionVid) -> RegionVariableOrigin {
         self.var_infos[vid].origin
     }
 
@@ -492,7 +492,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
         self.undo_log.push(AddVerify(index));
     }
 
-    pub fn add_given(&mut self, sub: Region<'tcx>, sup: ty::RegionVid) {
+    pub(super) fn add_given(&mut self, sub: Region<'tcx>, sup: ty::RegionVid) {
         // cannot add givens once regions are resolved
         if self.data.givens.insert((sub, sup)) {
             debug!("add_given({:?} <= {:?})", sub, sup);
@@ -501,7 +501,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
         }
     }
 
-    pub fn make_eqregion(
+    pub(super) fn make_eqregion(
         &mut self,
         origin: SubregionOrigin<'tcx>,
         sub: Region<'tcx>,
@@ -530,7 +530,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
         }
     }
 
-    pub fn member_constraint(
+    pub(super) fn member_constraint(
         &mut self,
         key: ty::OpaqueTypeKey<'tcx>,
         definition_span: Span,
@@ -554,7 +554,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
     }
 
     #[instrument(skip(self, origin), level = "debug")]
-    pub fn make_subregion(
+    pub(super) fn make_subregion(
         &mut self,
         origin: SubregionOrigin<'tcx>,
         sub: Region<'tcx>,
@@ -585,7 +585,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
         }
     }
 
-    pub fn verify_generic_bound(
+    pub(super) fn verify_generic_bound(
         &mut self,
         origin: SubregionOrigin<'tcx>,
         kind: GenericKind<'tcx>,
@@ -595,7 +595,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
         self.add_verify(Verify { kind, origin, region: sub, bound });
     }
 
-    pub fn lub_regions(
+    pub(super) fn lub_regions(
         &mut self,
         tcx: TyCtxt<'tcx>,
         origin: SubregionOrigin<'tcx>,
@@ -613,7 +613,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
         }
     }
 
-    pub fn glb_regions(
+    pub(super) fn glb_regions(
         &mut self,
         tcx: TyCtxt<'tcx>,
         origin: SubregionOrigin<'tcx>,
@@ -634,7 +634,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
     }
 
     /// Resolves the passed RegionVid to the root RegionVid in the unification table
-    pub fn opportunistic_resolve_var(&mut self, rid: ty::RegionVid) -> ty::RegionVid {
+    pub(super) fn opportunistic_resolve_var(&mut self, rid: ty::RegionVid) -> ty::RegionVid {
         self.unification_table().find(rid).vid
     }
 

From 1e54fcc1adeb3932ea7844ec1f86389a680ab86d Mon Sep 17 00:00:00 2001
From: Jack Huey <31162821+jackh726@users.noreply.github.com>
Date: Thu, 8 Sep 2022 18:36:55 -0400
Subject: [PATCH 4361/5092] Combine logic from lubs into lub_empty function

---
 .../src/infer/lexical_region_resolve/mod.rs   | 111 ++++++++----------
 1 file changed, 46 insertions(+), 65 deletions(-)

diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index 0ed57706790a..5f13b2b3deb1 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -15,6 +15,7 @@ use rustc_data_structures::graph::implementation::{
 use rustc_data_structures::intern::Interned;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::ty::fold::TypeFoldable;
+use rustc_middle::ty::PlaceholderRegion;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{ReEarlyBound, ReErased, ReFree, ReStatic};
 use rustc_middle::ty::{ReLateBound, RePlaceholder, ReVar};
@@ -195,6 +196,36 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
         }
     }
 
+    /// Gets the LUb of a given region and the empty region
+    fn lub_empty(&self, a_region: Region<'tcx>) -> Result, PlaceholderRegion> {
+        match *a_region {
+            ReLateBound(..) | ReErased => {
+                bug!("cannot relate region: {:?}", a_region);
+            }
+
+            ReVar(v_id) => {
+                span_bug!(
+                    self.var_infos[v_id].origin.span(),
+                    "lub invoked with non-concrete regions: {:?}",
+                    a_region,
+                );
+            }
+
+            ReStatic => {
+                // nothing lives longer than `'static`
+                Ok(self.tcx().lifetimes.re_static)
+            }
+
+            ReEarlyBound(_) | ReFree(_) => {
+                // All empty regions are less than early-bound, free,
+                // and scope regions.
+                Ok(a_region)
+            }
+
+            RePlaceholder(placeholder) => Err(placeholder),
+        }
+    }
+
     fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) {
         // In the first pass, we expand region vids according to constraints we
         // have previously found. In the second pass, we loop through the region
@@ -237,40 +268,15 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
                                 true
                             }
                             VarValue::Value(cur_region) => {
-                                let lub = match *cur_region {
-                                    ReLateBound(..) | ReErased => {
-                                        bug!("cannot relate region: {:?}", cur_region);
-                                    }
-
-                                    ReVar(v_id) => {
-                                        span_bug!(
-                                            self.var_infos[v_id].origin.span(),
-                                            "lub_concrete_regions invoked with non-concrete regions: {:?}",
-                                            cur_region,
-                                        );
-                                    }
-
-                                    ReStatic => {
-                                        // nothing lives longer than `'static`
-                                        self.tcx().lifetimes.re_static
-                                    }
-
-                                    ReEarlyBound(_) | ReFree(_) => {
-                                        // All empty regions are less than early-bound, free,
-                                        // and scope regions.
+                                let lub = match self.lub_empty(cur_region) {
+                                    Ok(r) => r,
+                                    // If the empty and placeholder regions are in the same universe,
+                                    // then the LUB is the Placeholder region (which is the cur_region).
+                                    // If they are not in the same universe, the LUB is the Static lifetime.
+                                    Err(placeholder) if a_universe == placeholder.universe => {
                                         cur_region
                                     }
-
-                                    RePlaceholder(placeholder) => {
-                                        // If the empty and placeholder regions are in the same universe,
-                                        // then the LUB is the Placeholder region (which is the cur_region).
-                                        // If they are not in the same universe, the LUB is the Static lifetime.
-                                        if a_universe == placeholder.universe {
-                                            cur_region
-                                        } else {
-                                            self.tcx().lifetimes.re_static
-                                        }
-                                    }
+                                    Err(_) => self.tcx().lifetimes.re_static,
                                 };
 
                                 if lub == cur_region {
@@ -368,40 +374,15 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
 
         match *b_data {
             VarValue::Empty(empty_ui) => {
-                let lub = match *a_region {
-                    ReLateBound(..) | ReErased => {
-                        bug!("cannot relate region: {:?}", a_region);
-                    }
-
-                    ReVar(v_id) => {
-                        span_bug!(
-                            self.var_infos[v_id].origin.span(),
-                            "expand_node invoked with non-concrete regions: {:?}",
-                            a_region,
-                        );
-                    }
-
-                    ReStatic => {
-                        // nothing lives longer than `'static`
-                        self.tcx().lifetimes.re_static
-                    }
-
-                    ReEarlyBound(_) | ReFree(_) => {
-                        // All empty regions are less than early-bound, free,
-                        // and scope regions.
-                        a_region
-                    }
-
-                    RePlaceholder(placeholder) => {
-                        // If this empty region is from a universe that can
-                        // name the placeholder, then the placeholder is
-                        // larger; otherwise, the only ancestor is `'static`.
-                        if empty_ui.can_name(placeholder.universe) {
-                            self.tcx().mk_region(RePlaceholder(placeholder))
-                        } else {
-                            self.tcx().lifetimes.re_static
-                        }
+                let lub = match self.lub_empty(a_region) {
+                    Ok(r) => r,
+                    // If this empty region is from a universe that can
+                    // name the placeholder, then the placeholder is
+                    // larger; otherwise, the only ancestor is `'static`.
+                    Err(placeholder) if empty_ui.can_name(placeholder.universe) => {
+                        self.tcx().mk_region(RePlaceholder(placeholder))
                     }
+                    Err(_) => self.tcx().lifetimes.re_static,
                 };
 
                 debug!("Expanding value of {:?} from empty lifetime to {:?}", b_vid, lub);

From 78b962a4f348c0b901d2eae9e5852cb3675b1233 Mon Sep 17 00:00:00 2001
From: Michael Goulet 
Date: Wed, 31 Aug 2022 03:04:44 +0000
Subject: [PATCH 4362/5092] RPITIT placeholder items

---
 compiler/rustc_hir/src/def.rs                     |  5 +++++
 compiler/rustc_hir/src/hir.rs                     | 11 +++++++++++
 compiler/rustc_hir/src/intravisit.rs              |  7 +++++++
 compiler/rustc_hir/src/target.rs                  |  3 +++
 compiler/rustc_hir_pretty/src/lib.rs              |  4 ++++
 compiler/rustc_metadata/src/rmeta/encoder.rs      |  5 +++++
 compiler/rustc_metadata/src/rmeta/table.rs        |  1 +
 compiler/rustc_middle/src/hir/map/mod.rs          |  2 ++
 compiler/rustc_monomorphize/src/polymorphize.rs   |  1 +
 compiler/rustc_passes/src/check_attr.rs           |  1 +
 compiler/rustc_passes/src/reachable.rs            |  1 +
 compiler/rustc_privacy/src/lib.rs                 |  5 +++++
 compiler/rustc_resolve/src/build_reduced_graph.rs |  1 +
 compiler/rustc_resolve/src/late/lifetimes.rs      |  3 +++
 compiler/rustc_save_analysis/src/lib.rs           |  1 +
 compiler/rustc_save_analysis/src/sig.rs           |  5 +++++
 compiler/rustc_ty_utils/src/implied_bounds.rs     |  1 +
 compiler/rustc_typeck/src/astconv/mod.rs          |  3 +++
 compiler/rustc_typeck/src/collect.rs              |  5 +++++
 compiler/rustc_typeck/src/collect/type_of.rs      |  3 +++
 src/librustdoc/clean/utils.rs                     |  4 ++--
 21 files changed, 70 insertions(+), 2 deletions(-)

diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index b44ee02cfe3b..8563b588585b 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -109,6 +109,8 @@ pub enum DefKind {
     InlineConst,
     /// Opaque type, aka `impl Trait`.
     OpaqueTy,
+    /// A return-position `impl Trait` in a trait definition
+    ImplTraitPlaceholder,
     Field,
     /// Lifetime parameter: the `'a` in `struct Foo<'a> { ... }`
     LifetimeParam,
@@ -138,6 +140,7 @@ impl DefKind {
                 panic!("impossible struct constructor")
             }
             DefKind::OpaqueTy => "opaque type",
+            DefKind::ImplTraitPlaceholder => "opaque type in trait",
             DefKind::TyAlias => "type alias",
             DefKind::TraitAlias => "trait alias",
             DefKind::AssocTy => "associated type",
@@ -190,6 +193,7 @@ impl DefKind {
             | DefKind::Variant
             | DefKind::Trait
             | DefKind::OpaqueTy
+            | DefKind::ImplTraitPlaceholder
             | DefKind::TyAlias
             | DefKind::ForeignTy
             | DefKind::TraitAlias
@@ -254,6 +258,7 @@ impl DefKind {
             | DefKind::Use
             | DefKind::ForeignMod
             | DefKind::OpaqueTy
+            | DefKind::ImplTraitPlaceholder
             | DefKind::Impl
             | DefKind::Field
             | DefKind::TyParam
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index cc5aed6cb548..334d4fd0b042 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2518,6 +2518,12 @@ pub enum OpaqueTyOrigin {
     TyAlias,
 }
 
+/// Placeholder representation of an `impl Trait` in a trait. Since this never gets lowered into a `ty::Opaque` of its own, we just keep this as
+#[derive(Debug, HashStable_Generic)]
+pub struct ImplTraitPlaceholder<'hir> {
+    pub bounds: GenericBounds<'hir>,
+}
+
 /// The various kinds of types recognized by the compiler.
 #[derive(Debug, HashStable_Generic)]
 pub enum TyKind<'hir> {
@@ -2545,6 +2551,8 @@ pub enum TyKind<'hir> {
     /// The generic argument list contains the lifetimes (and in the future
     /// possibly parameters) that are actually bound on the `impl Trait`.
     OpaqueDef(ItemId, &'hir [GenericArg<'hir>]),
+    /// The placeholder
+    ImplTraitInTrait(ItemId),
     /// A trait object type `Bound1 + Bound2 + Bound3`
     /// where `Bound` is a trait or a lifetime.
     TraitObject(&'hir [PolyTraitRef<'hir>], &'hir Lifetime, TraitObjectSyntax),
@@ -3000,6 +3008,8 @@ pub enum ItemKind<'hir> {
     TyAlias(&'hir Ty<'hir>, &'hir Generics<'hir>),
     /// An opaque `impl Trait` type alias, e.g., `type Foo = impl Bar;`.
     OpaqueTy(OpaqueTy<'hir>),
+    /// An `impl Trait` in a trait
+    ImplTraitPlaceholder(ImplTraitPlaceholder<'hir>),
     /// An enum definition, e.g., `enum Foo {C, D}`.
     Enum(EnumDef<'hir>, &'hir Generics<'hir>),
     /// A struct definition, e.g., `struct Foo {x: A}`.
@@ -3068,6 +3078,7 @@ impl ItemKind<'_> {
             ItemKind::Trait(..) => "trait",
             ItemKind::TraitAlias(..) => "trait alias",
             ItemKind::Impl(..) => "implementation",
+            ItemKind::ImplTraitPlaceholder(..) => "opaque type in trait",
         }
     }
 }
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 20ec788463ac..3e9ab10b1f7e 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -562,6 +562,10 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
             walk_generics(visitor, generics);
             walk_list!(visitor, visit_param_bound, bounds);
         }
+        ItemKind::ImplTraitPlaceholder(ImplTraitPlaceholder { bounds }) => {
+            visitor.visit_id(item.hir_id());
+            walk_list!(visitor, visit_param_bound, bounds);
+        }
         ItemKind::Enum(ref enum_definition, ref generics) => {
             visitor.visit_generics(generics);
             // `visit_enum_def()` takes care of visiting the `Item`'s `HirId`.
@@ -674,6 +678,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) {
             visitor.visit_nested_item(item_id);
             walk_list!(visitor, visit_generic_arg, lifetimes);
         }
+        TyKind::ImplTraitInTrait(item_id) => {
+            visitor.visit_nested_item(item_id);
+        }
         TyKind::Array(ref ty, ref length) => {
             visitor.visit_ty(ty);
             visitor.visit_array_length(length)
diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs
index 78bfd7191dba..ea23c48cc535 100644
--- a/compiler/rustc_hir/src/target.rs
+++ b/compiler/rustc_hir/src/target.rs
@@ -36,6 +36,7 @@ pub enum Target {
     GlobalAsm,
     TyAlias,
     OpaqueTy,
+    ImplTraitPlaceholder,
     Enum,
     Variant,
     Struct,
@@ -80,6 +81,7 @@ impl Target {
             ItemKind::GlobalAsm(..) => Target::GlobalAsm,
             ItemKind::TyAlias(..) => Target::TyAlias,
             ItemKind::OpaqueTy(..) => Target::OpaqueTy,
+            ItemKind::ImplTraitPlaceholder(..) => Target::ImplTraitPlaceholder,
             ItemKind::Enum(..) => Target::Enum,
             ItemKind::Struct(..) => Target::Struct,
             ItemKind::Union(..) => Target::Union,
@@ -157,6 +159,7 @@ impl Target {
             Target::GlobalAsm => "global asm",
             Target::TyAlias => "type alias",
             Target::OpaqueTy => "opaque type",
+            Target::ImplTraitPlaceholder => "opaque type in trait",
             Target::Enum => "enum",
             Target::Variant => "enum variant",
             Target::Struct => "struct",
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 35a58296e370..01f445c8a52d 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -327,6 +327,7 @@ impl<'a> State<'a> {
                 self.print_ty_fn(f.abi, f.unsafety, f.decl, None, f.generic_params, f.param_names);
             }
             hir::TyKind::OpaqueDef(..) => self.word("/*impl Trait*/"),
+            hir::TyKind::ImplTraitInTrait(..) => self.word("/*impl Trait*/"),
             hir::TyKind::Path(ref qpath) => self.print_qpath(qpath, false),
             hir::TyKind::TraitObject(bounds, ref lifetime, syntax) => {
                 if syntax == ast::TraitObjectSyntax::Dyn {
@@ -608,6 +609,9 @@ impl<'a> State<'a> {
                     state.print_bounds("= impl", real_bounds);
                 });
             }
+            hir::ItemKind::ImplTraitPlaceholder(..) => {
+                unreachable!("FIXME(RPITIT): I don't think this ever gets called here...");
+            }
             hir::ItemKind::Enum(ref enum_definition, params) => {
                 self.print_enum_def(enum_definition, params, item.ident.name, item.span);
             }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index b807663b10fd..02ca34181cd0 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -847,6 +847,7 @@ fn should_encode_visibility(def_kind: DefKind) -> bool {
         | DefKind::Use
         | DefKind::ForeignMod
         | DefKind::OpaqueTy
+        | DefKind::ImplTraitPlaceholder
         | DefKind::Impl
         | DefKind::Field => true,
         DefKind::TyParam
@@ -879,6 +880,7 @@ fn should_encode_stability(def_kind: DefKind) -> bool {
         | DefKind::ForeignMod
         | DefKind::TyAlias
         | DefKind::OpaqueTy
+        | DefKind::ImplTraitPlaceholder
         | DefKind::Enum
         | DefKind::Union
         | DefKind::Impl
@@ -967,6 +969,7 @@ fn should_encode_variances(def_kind: DefKind) -> bool {
         | DefKind::ForeignMod
         | DefKind::TyAlias
         | DefKind::OpaqueTy
+        | DefKind::ImplTraitPlaceholder
         | DefKind::Impl
         | DefKind::Trait
         | DefKind::TraitAlias
@@ -1003,6 +1006,7 @@ fn should_encode_generics(def_kind: DefKind) -> bool {
         | DefKind::AnonConst
         | DefKind::InlineConst
         | DefKind::OpaqueTy
+        | DefKind::ImplTraitPlaceholder
         | DefKind::Impl
         | DefKind::Field
         | DefKind::TyParam
@@ -1493,6 +1497,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             }
             hir::ItemKind::OpaqueTy(..) => {
                 self.encode_explicit_item_bounds(def_id);
+                EntryKind::OpaqueTy
             }
             hir::ItemKind::Enum(..) => {
                 let adt_def = self.tcx.adt_def(def_id);
diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs
index d5f151f0ed8e..e7c1abd126e0 100644
--- a/compiler/rustc_metadata/src/rmeta/table.rs
+++ b/compiler/rustc_metadata/src/rmeta/table.rs
@@ -90,6 +90,7 @@ fixed_size_enum! {
         ( AnonConst                                )
         ( InlineConst                              )
         ( OpaqueTy                                 )
+        ( ImplTraitPlaceholder                     )
         ( Field                                    )
         ( LifetimeParam                            )
         ( GlobalAsm                                )
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 6217bffb8f76..1a0bea68293e 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -213,6 +213,7 @@ impl<'hir> Map<'hir> {
                 ItemKind::Macro(_, macro_kind) => DefKind::Macro(macro_kind),
                 ItemKind::Mod(..) => DefKind::Mod,
                 ItemKind::OpaqueTy(..) => DefKind::OpaqueTy,
+                ItemKind::ImplTraitPlaceholder(..) => DefKind::ImplTraitPlaceholder,
                 ItemKind::TyAlias(..) => DefKind::TyAlias,
                 ItemKind::Enum(..) => DefKind::Enum,
                 ItemKind::Struct(..) => DefKind::Struct,
@@ -1188,6 +1189,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
                 ItemKind::GlobalAsm(..) => "global asm",
                 ItemKind::TyAlias(..) => "ty",
                 ItemKind::OpaqueTy(..) => "opaque type",
+                ItemKind::ImplTraitPlaceholder(..) => "opaque type in trait",
                 ItemKind::Enum(..) => "enum",
                 ItemKind::Struct(..) => "struct",
                 ItemKind::Union(..) => "union",
diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs
index af4b35db3bac..98156a94ec4b 100644
--- a/compiler/rustc_monomorphize/src/polymorphize.rs
+++ b/compiler/rustc_monomorphize/src/polymorphize.rs
@@ -170,6 +170,7 @@ fn mark_used_by_default_parameters<'tcx>(
         | DefKind::AnonConst
         | DefKind::InlineConst
         | DefKind::OpaqueTy
+        | DefKind::ImplTraitPlaceholder
         | DefKind::Field
         | DefKind::LifetimeParam
         | DefKind::GlobalAsm
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index d0b46aa2c453..bb684e784c58 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -661,6 +661,7 @@ impl CheckAttrVisitor<'_> {
             | Target::GlobalAsm
             | Target::TyAlias
             | Target::OpaqueTy
+            | Target::ImplTraitPlaceholder
             | Target::Enum
             | Target::Variant
             | Target::Struct
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index f7e3fac6b2e2..74c5ccf9cd20 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -235,6 +235,7 @@ impl<'tcx> ReachableContext<'tcx> {
                     hir::ItemKind::ExternCrate(_)
                     | hir::ItemKind::Use(..)
                     | hir::ItemKind::OpaqueTy(..)
+                    | hir::ItemKind::ImplTraitPlaceholder(..)
                     | hir::ItemKind::TyAlias(..)
                     | hir::ItemKind::Macro(..)
                     | hir::ItemKind::Mod(..)
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index b2966f0d2180..309eb753553b 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -596,6 +596,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
             | DefKind::ForeignTy
             | DefKind::Fn
             | DefKind::OpaqueTy
+            | DefKind::ImplTraitPlaceholder
             | DefKind::AssocFn
             | DefKind::Trait
             | DefKind::TyParam
@@ -685,6 +686,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
             }
 
             hir::ItemKind::OpaqueTy(..)
+            | hir::ItemKind::ImplTraitPlaceholder(..)
             | hir::ItemKind::Use(..)
             | hir::ItemKind::Static(..)
             | hir::ItemKind::Const(..)
@@ -720,6 +722,9 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
                     self.reach(item.def_id, exist_level).generics().predicates().ty();
                 }
             }
+            hir::ItemKind::ImplTraitPlaceholder(..) => {
+                // FIXME(RPITIT): Do we need to do anything here?
+            }
             // Visit everything.
             hir::ItemKind::Const(..)
             | hir::ItemKind::Static(..)
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 9cb735b36856..81b67b758f7e 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -972,6 +972,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                 | DefKind::TyAlias
                 | DefKind::ForeignTy
                 | DefKind::OpaqueTy
+                | DefKind::ImplTraitPlaceholder
                 | DefKind::TraitAlias
                 | DefKind::AssocTy,
                 _,
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index 101679aa6dc9..b72b033534b9 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -596,6 +596,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     }
                 }
             }
+            hir::ItemKind::ImplTraitPlaceholder(..) => {
+                // FIXME(RPITIT): We don't need to do anything here, right?
+            }
             hir::ItemKind::TyAlias(_, ref generics)
             | hir::ItemKind::Enum(_, ref generics)
             | hir::ItemKind::Struct(_, ref generics)
diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs
index 89bca39512f5..ebe44a56449d 100644
--- a/compiler/rustc_save_analysis/src/lib.rs
+++ b/compiler/rustc_save_analysis/src/lib.rs
@@ -685,6 +685,7 @@ impl<'tcx> SaveContext<'tcx> {
                 | HirDefKind::AssocTy
                 | HirDefKind::Trait
                 | HirDefKind::OpaqueTy
+                | HirDefKind::ImplTraitPlaceholder
                 | HirDefKind::TyParam,
                 def_id,
             ) => Some(Ref { kind: RefKind::Type, span, ref_id: id_from_def_id(def_id) }),
diff --git a/compiler/rustc_save_analysis/src/sig.rs b/compiler/rustc_save_analysis/src/sig.rs
index d1286c9b8b0d..ea9c82b3597d 100644
--- a/compiler/rustc_save_analysis/src/sig.rs
+++ b/compiler/rustc_save_analysis/src/sig.rs
@@ -320,6 +320,10 @@ impl<'hir> Sig for hir::Ty<'hir> {
                 let item = scx.tcx.hir().item(item_id);
                 item.make(offset, Some(item_id.hir_id()), scx)
             }
+            hir::TyKind::ImplTraitInTrait(item_id) => {
+                let item = scx.tcx.hir().item(item_id);
+                item.make(offset, Some(item_id.hir_id()), scx)
+            }
             hir::TyKind::Typeof(_) | hir::TyKind::Infer | hir::TyKind::Err => Err("Ty"),
         }
     }
@@ -562,6 +566,7 @@ impl<'hir> Sig for hir::Item<'hir> {
             hir::ItemKind::GlobalAsm(_) => Err("global asm"),
             hir::ItemKind::ExternCrate(_) => Err("extern crate"),
             hir::ItemKind::OpaqueTy(..) => Err("opaque type"),
+            hir::ItemKind::ImplTraitPlaceholder(..) => Err("opaque type in trait"),
             // FIXME should implement this (e.g., pub use).
             hir::ItemKind::Use(..) => Err("import"),
         }
diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs
index a77ea440aaae..f0d8c240ea58 100644
--- a/compiler/rustc_ty_utils/src/implied_bounds.rs
+++ b/compiler/rustc_ty_utils/src/implied_bounds.rs
@@ -51,6 +51,7 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx ty::List dyn AstConv<'tcx> + 'o {
                     ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
                 }
             }
+            hir::TyKind::ImplTraitInTrait(..) => {
+                span_bug!(ast_ty.span, "not yet implemented")
+            }
             hir::TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => {
                 debug!(?qself, ?segment);
                 let ty = self.ast_ty_to_ty_inner(qself, false, true);
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index e70f728d7dcc..293a32051b9f 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -815,6 +815,11 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
             tcx.ensure().predicates_of(def_id);
             tcx.ensure().explicit_item_bounds(def_id);
         }
+        hir::ItemKind::ImplTraitPlaceholder(..) => {
+            tcx.ensure().generics_of(def_id);
+            tcx.ensure().predicates_of(def_id);
+            tcx.ensure().explicit_item_bounds(def_id);
+        }
         hir::ItemKind::TyAlias(..)
         | hir::ItemKind::Static(..)
         | hir::ItemKind::Const(..)
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs
index a0280ddca4bd..ded2ac1308e5 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_typeck/src/collect/type_of.rs
@@ -336,6 +336,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                 ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner), .. }) => {
                     find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
                 }
+                ItemKind::ImplTraitPlaceholder(..) => {
+                    span_bug!(item.span, "not yet implemented")
+                }
                 ItemKind::Trait(..)
                 | ItemKind::TraitAlias(..)
                 | ItemKind::Macro(..)
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index a9d511ae11e8..395f213ca87c 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -511,8 +511,8 @@ pub(crate) fn register_res(cx: &mut DocContext<'_>, res: Res) -> DefId {
         | Res::Err => return res.def_id(),
         Res::Def(
             TyParam | ConstParam | Ctor(..) | ExternCrate | Use | ForeignMod | AnonConst
-            | InlineConst | OpaqueTy | Field | LifetimeParam | GlobalAsm | Impl | Closure
-            | Generator,
+            | InlineConst | OpaqueTy | ImplTraitPlaceholder | Field | LifetimeParam | GlobalAsm
+            | Impl | Closure | Generator,
             id,
         ) => return id,
     };

From d34cb98fb0bbaf86860b4ad5ff0c3d79b077f565 Mon Sep 17 00:00:00 2001
From: Michael Goulet 
Date: Wed, 31 Aug 2022 04:03:24 +0000
Subject: [PATCH 4363/5092] Lower RPITIT to ImplTraitPlaceholder item

---
 compiler/rustc_ast_lowering/src/lib.rs        | 47 ++++++++++++++++++-
 compiler/rustc_feature/src/active.rs          |  2 +
 compiler/rustc_hir/src/target.rs              |  1 +
 compiler/rustc_middle/src/ty/error.rs         |  5 +-
 compiler/rustc_middle/src/ty/sty.rs           |  5 +-
 compiler/rustc_resolve/src/late/lifetimes.rs  |  3 +-
 compiler/rustc_span/src/symbol.rs             |  1 +
 .../src/traits/project.rs                     |  5 ++
 compiler/rustc_typeck/src/astconv/mod.rs      |  5 +-
 compiler/rustc_typeck/src/collect.rs          |  5 ++
 .../rustc_typeck/src/collect/item_bounds.rs   | 28 +++++++++++
 11 files changed, 99 insertions(+), 8 deletions(-)

diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index f57c92fd70c2..2e8fcd7dca45 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -255,6 +255,8 @@ enum ImplTraitContext {
     },
     /// Impl trait in type aliases.
     TypeAliasesOpaqueTy,
+    /// Return-position `impl Trait` in trait definition
+    InTrait,
     /// `impl Trait` is not accepted in this position.
     Disallowed(ImplTraitPosition),
 }
@@ -323,9 +325,17 @@ enum FnDeclKind {
 }
 
 impl FnDeclKind {
-    fn impl_trait_return_allowed(&self) -> bool {
+    fn impl_trait_return_allowed(&self, tcx: TyCtxt<'_>) -> bool {
         match self {
             FnDeclKind::Fn | FnDeclKind::Inherent => true,
+            FnDeclKind::Impl if tcx.features().return_position_impl_trait_in_trait => true,
+            _ => false,
+        }
+    }
+
+    fn impl_trait_in_trait_allowed(&self, tcx: TyCtxt<'_>) -> bool {
+        match self {
+            FnDeclKind::Trait if tcx.features().return_position_impl_trait_in_trait => true,
             _ => false,
         }
     }
@@ -1346,6 +1356,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                             &mut nested_itctx,
                         )
                     }
+                    ImplTraitContext::InTrait => {
+                        // FIXME(RPITIT): Should we use def_node_id here?
+                        self.lower_impl_trait_in_trait(span, def_node_id, bounds)
+                    }
                     ImplTraitContext::Universal => {
                         let span = t.span;
                         let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span);
@@ -1532,6 +1546,32 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         hir::TyKind::OpaqueDef(hir::ItemId { def_id: opaque_ty_def_id }, lifetimes)
     }
 
+    #[tracing::instrument(level = "debug", skip(self))]
+    fn lower_impl_trait_in_trait(
+        &mut self,
+        span: Span,
+        opaque_ty_node_id: NodeId,
+        bounds: &GenericBounds,
+    ) -> hir::TyKind<'hir> {
+        let opaque_ty_def_id = self.local_def_id(opaque_ty_node_id);
+        self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
+            // FIXME(RPITIT): This should be a more descriptive ImplTraitPosition, i.e. nested RPITIT
+            // FIXME(RPITIT): We _also_ should support this eventually
+            let hir_bounds = lctx
+                .lower_param_bounds(bounds, ImplTraitContext::Disallowed(ImplTraitPosition::Trait));
+            let rpitit_placeholder = hir::ImplTraitPlaceholder { bounds: hir_bounds };
+            let rpitit_item = hir::Item {
+                def_id: opaque_ty_def_id,
+                ident: Ident::empty(),
+                kind: hir::ItemKind::ImplTraitPlaceholder(rpitit_placeholder),
+                span: lctx.lower_span(span),
+                vis_span: lctx.lower_span(span.shrink_to_lo()),
+            };
+            hir::OwnerNode::Item(lctx.arena.alloc(rpitit_item))
+        });
+        hir::TyKind::ImplTraitInTrait(hir::ItemId { def_id: opaque_ty_def_id })
+    }
+
     /// Registers a new opaque type with the proper `NodeId`s and
     /// returns the lowered node-ID for the opaque type.
     fn generate_opaque_type(
@@ -1690,12 +1730,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             match decl.output {
                 FnRetTy::Ty(ref ty) => {
                     let mut context = match fn_node_id {
-                        Some(fn_node_id) if kind.impl_trait_return_allowed() => {
+                        Some(fn_node_id) if kind.impl_trait_return_allowed(self.tcx) => {
                             let fn_def_id = self.local_def_id(fn_node_id);
                             ImplTraitContext::ReturnPositionOpaqueTy {
                                 origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
                             }
                         }
+                        Some(_) if kind.impl_trait_in_trait_allowed(self.tcx) => {
+                            ImplTraitContext::InTrait
+                        }
                         _ => ImplTraitContext::Disallowed(match kind {
                             FnDeclKind::Fn | FnDeclKind::Inherent => {
                                 unreachable!("fn should allow in-band lifetimes")
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index f71b3d59e2c0..3b8032040e76 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -487,6 +487,8 @@ declare_features! (
     (incomplete, repr128, "1.16.0", Some(56071), None),
     /// Allows `repr(simd)` and importing the various simd intrinsics.
     (active, repr_simd, "1.4.0", Some(27731), None),
+    /// Allows return-position `impl Trait` in traits.
+    (incomplete, return_position_impl_trait_in_trait, "CURRENT_RUSTC_VERSION", Some(91611), None),
     /// Allows `extern "rust-cold"`.
     (active, rust_cold_cc, "1.63.0", Some(97544), None),
     /// Allows the use of SIMD types in functions declared in `extern` blocks.
diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs
index ea23c48cc535..0e9b05729d29 100644
--- a/compiler/rustc_hir/src/target.rs
+++ b/compiler/rustc_hir/src/target.rs
@@ -105,6 +105,7 @@ impl Target {
             DefKind::GlobalAsm => Target::GlobalAsm,
             DefKind::TyAlias => Target::TyAlias,
             DefKind::OpaqueTy => Target::OpaqueTy,
+            DefKind::ImplTraitPlaceholder => Target::ImplTraitPlaceholder,
             DefKind::Enum => Target::Enum,
             DefKind::Struct => Target::Struct,
             DefKind::Union => Target::Union,
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index da564c66a70e..279c8c8d6d16 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -2,6 +2,7 @@ use crate::traits::{ObligationCause, ObligationCauseCode};
 use crate::ty::diagnostics::suggest_constraining_type_param;
 use crate::ty::print::{FmtPrinter, Printer};
 use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt};
+use hir::def::DefKind;
 use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
 use rustc_errors::{pluralize, Diagnostic, MultiSpan};
 use rustc_hir as hir;
@@ -538,7 +539,7 @@ impl Trait for X {
                             diag.span_label(p_span, "this type parameter");
                         }
                     }
-                    (ty::Projection(proj_ty), _) => {
+                    (ty::Projection(proj_ty), _) if self.def_kind(proj_ty.item_def_id) != DefKind::ImplTraitPlaceholder => {
                         self.expected_projection(
                             diag,
                             proj_ty,
@@ -547,7 +548,7 @@ impl Trait for X {
                             cause.code(),
                         );
                     }
-                    (_, ty::Projection(proj_ty)) => {
+                    (_, ty::Projection(proj_ty)) if self.def_kind(proj_ty.item_def_id) != DefKind::ImplTraitPlaceholder => {
                         let msg = format!(
                             "consider constraining the associated type `{}` to `{}`",
                             values.found, values.expected,
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 9fb91b5fe870..c5c5d3473418 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -11,6 +11,7 @@ use crate::ty::{
     TypeVisitor,
 };
 use crate::ty::{List, ParamEnv};
+use hir::def::DefKind;
 use polonius_engine::Atom;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::intern::Interned;
@@ -1196,7 +1197,9 @@ pub struct ProjectionTy<'tcx> {
 
 impl<'tcx> ProjectionTy<'tcx> {
     pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
-        tcx.parent(self.item_def_id)
+        let parent = tcx.parent(self.item_def_id);
+        assert_eq!(tcx.def_kind(parent), DefKind::Trait);
+        parent
     }
 
     /// Extracts the underlying trait reference and own substs from this projection.
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index b72b033534b9..e9e4f8fc483c 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -597,7 +597,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 }
             }
             hir::ItemKind::ImplTraitPlaceholder(..) => {
-                // FIXME(RPITIT): We don't need to do anything here, right?
+                // FIXME(RPITIT): We don't need to do anything special here, right?
+                intravisit::walk_item(self, item);
             }
             hir::ItemKind::TyAlias(_, ref generics)
             | hir::ItemKind::Enum(_, ref generics)
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 75b1dfc856ac..4fd9e7407ce1 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1183,6 +1183,7 @@ symbols! {
         require,
         residual,
         result,
+        return_position_impl_trait_in_trait,
         rhs,
         rintf32,
         rintf64,
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 8a093bf4281c..cd6b42be5ad7 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1465,6 +1465,11 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
     obligation: &ProjectionTyObligation<'tcx>,
     candidate_set: &mut ProjectionCandidateSet<'tcx>,
 ) {
+    // Can't assemble candidate from impl for RPITIT
+    if selcx.tcx().def_kind(obligation.predicate.item_def_id) == DefKind::ImplTraitPlaceholder {
+        return;
+    }
+
     // If we are resolving `>::Item == Type`,
     // start out by selecting the predicate `T as TraitRef<...>`:
     let poly_trait_ref = ty::Binder::dummy(obligation.predicate.trait_ref(selcx.tcx()));
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 1f43221a420a..6eec2c57639c 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -2638,8 +2638,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
                 }
             }
-            hir::TyKind::ImplTraitInTrait(..) => {
-                span_bug!(ast_ty.span, "not yet implemented")
+            hir::TyKind::ImplTraitInTrait(item_id) => {
+                let def_id = item_id.def_id.to_def_id();
+                tcx.mk_projection(def_id, InternalSubsts::identity_for_item(tcx, def_id))
             }
             hir::TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => {
                 debug!(?qself, ?segment);
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index 293a32051b9f..5429598871d9 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -1600,6 +1600,11 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
                 // inherit the generics of the item.
                 Some(parent_id.to_def_id())
             }
+            ItemKind::ImplTraitPlaceholder(_) => {
+                let parent_id = tcx.hir().get_parent_item(hir_id).to_def_id();
+                assert_eq!(tcx.def_kind(parent_id), DefKind::AssocFn);
+                Some(parent_id)
+            }
             _ => None,
         },
         _ => None,
diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_typeck/src/collect/item_bounds.rs
index 318e8f581f7c..fe8d8f54f047 100644
--- a/compiler/rustc_typeck/src/collect/item_bounds.rs
+++ b/compiler/rustc_typeck/src/collect/item_bounds.rs
@@ -74,6 +74,29 @@ fn opaque_type_bounds<'tcx>(
     })
 }
 
+/// Opaque types don't inherit bounds from their parent: for return position
+/// impl trait it isn't possible to write a suitable predicate on the
+/// containing function and for type-alias impl trait we don't have a backwards
+/// compatibility issue.
+fn impl_trait_in_trait_item_bounds<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    opaque_def_id: DefId,
+    ast_bounds: &'tcx [hir::GenericBound<'tcx>],
+    span: Span,
+) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
+    ty::print::with_no_queries!({
+        // FIXME(RPITIT): DRY-er code please
+        let item_ty =
+            tcx.mk_projection(opaque_def_id, InternalSubsts::identity_for_item(tcx, opaque_def_id));
+
+        let icx = ItemCtxt::new(tcx, opaque_def_id);
+        let mut bounds = >::compute_bounds(&icx, item_ty, ast_bounds);
+        // RPITITs are implicitly sized unless a `?Sized` bound is found
+        >::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span);
+        tcx.arena.alloc_from_iter(bounds.predicates(tcx, item_ty))
+    })
+}
+
 pub(super) fn explicit_item_bounds(
     tcx: TyCtxt<'_>,
     def_id: DefId,
@@ -90,6 +113,11 @@ pub(super) fn explicit_item_bounds(
             span,
             ..
         }) => opaque_type_bounds(tcx, def_id, bounds, *span),
+        hir::Node::Item(hir::Item {
+            kind: hir::ItemKind::ImplTraitPlaceholder(hir::ImplTraitPlaceholder { bounds }),
+            span,
+            ..
+        }) => impl_trait_in_trait_item_bounds(tcx, def_id, bounds, *span),
         _ => bug!("item_bounds called on {:?}", def_id),
     }
 }

From 4265ef8cb2946496b9de8be4b697a2b94bd92229 Mon Sep 17 00:00:00 2001
From: Michael Goulet 
Date: Wed, 31 Aug 2022 04:41:16 +0000
Subject: [PATCH 4364/5092] Implement projection for ImplTraitPlaceholder

---
 compiler/rustc_privacy/src/lib.rs             |   4 +-
 .../src/traits/project.rs                     | 117 ++++++++++++++++++
 2 files changed, 120 insertions(+), 1 deletion(-)

diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 309eb753553b..3657fb213404 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -2038,7 +2038,9 @@ fn local_visibility(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Visibility {
                 //   Visibility on them should have no effect, but to avoid the visibility
                 //   query failing on some items, we provide it for opaque types as well.
                 | Node::Item(hir::Item {
-                    kind: hir::ItemKind::Use(_, hir::UseKind::ListStem) | hir::ItemKind::OpaqueTy(..),
+                    kind: hir::ItemKind::Use(_, hir::UseKind::ListStem)
+                        | hir::ItemKind::OpaqueTy(..)
+                        | hir::ItemKind::ImplTraitPlaceholder(..),
                     ..
                 }) => ty::Visibility::Restricted(tcx.parent_module(hir_id)),
                 // Visibilities of trait impl items are inherited from their traits
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index cd6b42be5ad7..6ccb91c8cab6 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -32,6 +32,7 @@ use rustc_middle::traits::select::OverflowError;
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable};
+use rustc_middle::ty::DefIdTree;
 use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt};
 use rustc_span::symbol::sym;
 
@@ -70,6 +71,8 @@ enum ProjectionCandidate<'tcx> {
 
     /// From an "impl" (or a "pseudo-impl" returned by select)
     Select(Selection<'tcx>),
+
+    ImplTraitInTrait(ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>),
 }
 
 enum ProjectionCandidateSet<'tcx> {
@@ -1265,6 +1268,8 @@ fn project<'cx, 'tcx>(
 
     let mut candidates = ProjectionCandidateSet::None;
 
+    assemble_candidate_for_impl_trait_in_trait(selcx, obligation, &mut candidates);
+
     // Make sure that the following procedures are kept in order. ParamEnv
     // needs to be first because it has highest priority, and Select checks
     // the return value of push_candidate which assumes it's ran at last.
@@ -1303,6 +1308,48 @@ fn project<'cx, 'tcx>(
     }
 }
 
+/// The first thing we have to do is scan through the parameter
+/// environment to see whether there are any projection predicates
+/// there that can answer this question.
+fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>(
+    selcx: &mut SelectionContext<'cx, 'tcx>,
+    obligation: &ProjectionTyObligation<'tcx>,
+    candidate_set: &mut ProjectionCandidateSet<'tcx>,
+) {
+    let tcx = selcx.tcx();
+    if tcx.def_kind(obligation.predicate.item_def_id) == DefKind::ImplTraitPlaceholder {
+        let trait_fn_def_id = tcx.parent(obligation.predicate.item_def_id);
+        let trait_def_id = tcx.parent(trait_fn_def_id);
+        let trait_substs =
+            obligation.predicate.substs.truncate_to(tcx, tcx.generics_of(trait_def_id));
+        // FIXME(named-returns): Binders
+        let trait_predicate =
+            ty::Binder::dummy(ty::TraitRef { def_id: trait_def_id, substs: trait_substs })
+                .to_poly_trait_predicate();
+
+        let _ =
+            selcx.infcx().commit_if_ok(|_| match selcx.select(&obligation.with(trait_predicate)) {
+                Ok(Some(super::ImplSource::UserDefined(data))) => {
+                    candidate_set.push_candidate(ProjectionCandidate::ImplTraitInTrait(data));
+                    Ok(())
+                }
+                Ok(None) => {
+                    candidate_set.mark_ambiguous();
+                    return Err(());
+                }
+                Ok(Some(_)) => {
+                    // Don't know enough about the impl to provide a useful signature
+                    return Err(());
+                }
+                Err(e) => {
+                    debug!(error = ?e, "selection error");
+                    candidate_set.mark_error(e);
+                    return Err(());
+                }
+            });
+    }
+}
+
 /// The first thing we have to do is scan through the parameter
 /// environment to see whether there are any projection predicates
 /// there that can answer this question.
@@ -1745,6 +1792,9 @@ fn confirm_candidate<'cx, 'tcx>(
         ProjectionCandidate::Select(impl_source) => {
             confirm_select_candidate(selcx, obligation, impl_source)
         }
+        ProjectionCandidate::ImplTraitInTrait(data) => {
+            confirm_impl_trait_in_trait_candidate(selcx, obligation, data)
+        }
     };
 
     // When checking for cycle during evaluation, we compare predicates with
@@ -2107,6 +2157,73 @@ fn confirm_impl_candidate<'cx, 'tcx>(
     }
 }
 
+fn confirm_impl_trait_in_trait_candidate<'tcx>(
+    selcx: &mut SelectionContext<'_, 'tcx>,
+    obligation: &ProjectionTyObligation<'tcx>,
+    data: ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>,
+) -> Progress<'tcx> {
+    let tcx = selcx.tcx();
+    let mut obligations = data.nested;
+
+    let trait_fn_def_id = tcx.parent(obligation.predicate.item_def_id);
+    let Ok(leaf_def) = assoc_def(selcx, data.impl_def_id, trait_fn_def_id) else {
+        return Progress { term: tcx.ty_error().into(), obligations };
+    };
+    if !leaf_def.item.defaultness(tcx).has_value() {
+        return Progress { term: tcx.ty_error().into(), obligations };
+    }
+
+    let impl_fn_def_id = leaf_def.item.def_id;
+    let impl_fn_substs = obligation.predicate.substs.rebase_onto(tcx, trait_fn_def_id, data.substs);
+
+    let sig = tcx
+        .bound_fn_sig(impl_fn_def_id)
+        .map_bound(|fn_sig| tcx.liberate_late_bound_regions(impl_fn_def_id, fn_sig))
+        .subst(tcx, impl_fn_substs);
+
+    let cause = ObligationCause::new(
+        obligation.cause.span,
+        obligation.cause.body_id,
+        super::ItemObligation(impl_fn_def_id),
+    );
+    let predicates = normalize_with_depth_to(
+        selcx,
+        obligation.param_env,
+        cause.clone(),
+        obligation.recursion_depth + 1,
+        tcx.predicates_of(impl_fn_def_id).instantiate(tcx, impl_fn_substs),
+        &mut obligations,
+    );
+    obligations.extend(std::iter::zip(predicates.predicates, predicates.spans).map(
+        |(pred, span)| {
+            Obligation::with_depth(
+                ObligationCause::new(
+                    obligation.cause.span,
+                    obligation.cause.body_id,
+                    if span.is_dummy() {
+                        super::ItemObligation(impl_fn_def_id)
+                    } else {
+                        super::BindingObligation(impl_fn_def_id, span)
+                    },
+                ),
+                obligation.recursion_depth + 1,
+                obligation.param_env,
+                pred,
+            )
+        },
+    ));
+
+    let ty = super::normalize_to(
+        selcx,
+        obligation.param_env,
+        cause.clone(),
+        sig.output(),
+        &mut obligations,
+    );
+
+    Progress { term: ty.into(), obligations }
+}
+
 // Get obligations corresponding to the predicates from the where-clause of the
 // associated type itself.
 // Note: `feature(generic_associated_types)` is required to write such

From a4d1807d6d19a446f2f620773d42b5de2dbed757 Mon Sep 17 00:00:00 2001
From: Michael Goulet 
Date: Wed, 31 Aug 2022 04:41:20 +0000
Subject: [PATCH 4365/5092] Rustdoc support

---
 src/librustdoc/clean/mod.rs                      | 10 ++++++++++
 src/librustdoc/formats/item_type.rs              |  1 +
 src/librustdoc/passes/collect_intra_doc_links.rs |  4 ++--
 src/librustdoc/visit_ast.rs                      |  1 +
 4 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 66f766bfbe8d..03752c9b6dbb 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1500,6 +1500,16 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
                 unreachable!()
             }
         }
+        TyKind::ImplTraitInTrait(item_id) => {
+            let item = cx.tcx.hir().item(item_id);
+            if let hir::ItemKind::ImplTraitPlaceholder(hir::ImplTraitPlaceholder { bounds }) =
+                item.kind
+            {
+                ImplTrait(bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect())
+            } else {
+                unreachable!()
+            }
+        }
         TyKind::Path(_) => clean_qpath(ty, cx),
         TyKind::TraitObject(bounds, ref lifetime, _) => {
             let bounds = bounds.iter().map(|bound| clean_poly_trait_ref(bound, cx)).collect();
diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs
index 0a7ee2005915..f21e60a64e00 100644
--- a/src/librustdoc/formats/item_type.rs
+++ b/src/librustdoc/formats/item_type.rs
@@ -135,6 +135,7 @@ impl From for ItemType {
             | DefKind::AnonConst
             | DefKind::InlineConst
             | DefKind::OpaqueTy
+            | DefKind::ImplTraitPlaceholder
             | DefKind::Field
             | DefKind::LifetimeParam
             | DefKind::GlobalAsm
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index c27f0ce18c14..cfd6ce402c28 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -1805,8 +1805,8 @@ fn resolution_failure(
                                 }
                                 return;
                             }
-                            Trait | TyAlias | ForeignTy | OpaqueTy | TraitAlias | TyParam
-                            | Static(_) => "associated item",
+                            Trait | TyAlias | ForeignTy | OpaqueTy | ImplTraitPlaceholder
+                            | TraitAlias | TyParam | Static(_) => "associated item",
                             Impl | GlobalAsm => unreachable!("not a path"),
                         }
                     } else {
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index ca7a20bf3688..7fe391f420f6 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -362,6 +362,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             | hir::ItemKind::Union(..)
             | hir::ItemKind::TyAlias(..)
             | hir::ItemKind::OpaqueTy(..)
+            | hir::ItemKind::ImplTraitPlaceholder(..)
             | hir::ItemKind::Static(..)
             | hir::ItemKind::Trait(..)
             | hir::ItemKind::TraitAlias(..) => om.items.push((item, renamed)),

From e8fa74ae45024d1120a73c15a3c21f675b25f1f4 Mon Sep 17 00:00:00 2001
From: Michael Goulet 
Date: Wed, 31 Aug 2022 05:12:40 +0000
Subject: [PATCH 4366/5092] Check that impl types actually satisfy RPITIT
 bounds

---
 .../rustc_typeck/src/check/compare_method.rs  | 24 +++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index b6bc244d2b14..e55f43994b9f 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -391,6 +391,30 @@ fn compare_predicate_entailment<'tcx>(
             return Err(diag.emit());
         }
 
+        // Check that an impl's fn return satisfies the bounds of the
+        // FIXME(RPITIT): Generalize this to nested impl traits
+        if let ty::Projection(proj) = tcx.fn_sig(trait_m.def_id).skip_binder().output().kind()
+            && tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder
+        {
+            let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span();
+
+            for (predicate, span) in tcx
+                .bound_explicit_item_bounds(proj.item_def_id)
+                .transpose_iter()
+                .map(|pred| pred.map_bound(|pred| *pred).subst(tcx, trait_to_placeholder_substs))
+            {
+                ocx.register_obligation(traits::Obligation::new(
+                    traits::ObligationCause::new(
+                        return_span,
+                        impl_m_hir_id,
+                        ObligationCauseCode::BindingObligation(proj.item_def_id, span),
+                    ),
+                    param_env,
+                    predicate,
+                ));
+            }
+        }
+
         // Check that all obligations are satisfied by the implementation's
         // version.
         let errors = ocx.select_all_or_error();

From 81badff860091b4af165e6736b2a094e53c322a3 Mon Sep 17 00:00:00 2001
From: Michael Goulet 
Date: Wed, 31 Aug 2022 04:46:54 +0000
Subject: [PATCH 4367/5092] Add tests

---
 ...ate-return_position_impl_trait_in_trait.rs |  5 +++
 ...return_position_impl_trait_in_trait.stderr |  9 +++++
 .../ui/impl-trait/in-trait/doesnt-satisfy.rs  | 13 ++++++
 .../impl-trait/in-trait/doesnt-satisfy.stderr | 17 ++++++++
 .../in-trait/opaque-in-impl-is-opaque.rs      | 19 +++++++++
 .../in-trait/opaque-in-impl-is-opaque.stderr  | 17 ++++++++
 .../ui/impl-trait/in-trait/opaque-in-impl.rs  | 20 ++++++++++
 src/test/ui/impl-trait/in-trait/success.rs    | 40 +++++++++++++++++++
 8 files changed, 140 insertions(+)
 create mode 100644 src/test/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.rs
 create mode 100644 src/test/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.stderr
 create mode 100644 src/test/ui/impl-trait/in-trait/doesnt-satisfy.rs
 create mode 100644 src/test/ui/impl-trait/in-trait/doesnt-satisfy.stderr
 create mode 100644 src/test/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs
 create mode 100644 src/test/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr
 create mode 100644 src/test/ui/impl-trait/in-trait/opaque-in-impl.rs
 create mode 100644 src/test/ui/impl-trait/in-trait/success.rs

diff --git a/src/test/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.rs b/src/test/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.rs
new file mode 100644
index 000000000000..de7966c66b05
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.rs
@@ -0,0 +1,5 @@
+trait Foo {
+    fn bar() -> impl Sized; //~ ERROR `impl Trait` only allowed in function and inherent method return types, not in trait method return
+}
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.stderr b/src/test/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.stderr
new file mode 100644
index 000000000000..a41f5789fdbf
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.stderr
@@ -0,0 +1,9 @@
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in trait method return
+  --> $DIR/feature-gate-return_position_impl_trait_in_trait.rs:2:17
+   |
+LL |     fn bar() -> impl Sized;
+   |                 ^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0562`.
diff --git a/src/test/ui/impl-trait/in-trait/doesnt-satisfy.rs b/src/test/ui/impl-trait/in-trait/doesnt-satisfy.rs
new file mode 100644
index 000000000000..bb4e0d44f3ef
--- /dev/null
+++ b/src/test/ui/impl-trait/in-trait/doesnt-satisfy.rs
@@ -0,0 +1,13 @@
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+trait Foo {
+    fn bar() -> impl std::fmt::Display;
+}
+
+impl Foo for () {
+    fn bar() -> () {}
+    //~^ ERROR `()` doesn't implement `std::fmt::Display`
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/in-trait/doesnt-satisfy.stderr b/src/test/ui/impl-trait/in-trait/doesnt-satisfy.stderr
new file mode 100644
index 000000000000..aa5492d285ed
--- /dev/null
+++ b/src/test/ui/impl-trait/in-trait/doesnt-satisfy.stderr
@@ -0,0 +1,17 @@
+error[E0277]: `()` doesn't implement `std::fmt::Display`
+  --> $DIR/doesnt-satisfy.rs:9:17
+   |
+LL |     fn bar() -> () {}
+   |                 ^^ `()` cannot be formatted with the default formatter
+   |
+   = help: the trait `std::fmt::Display` is not implemented for `()`
+   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+note: required by a bound in `Foo::bar::{opaque#0}`
+  --> $DIR/doesnt-satisfy.rs:5:22
+   |
+LL |     fn bar() -> impl std::fmt::Display;
+   |                      ^^^^^^^^^^^^^^^^^ required by this bound in `Foo::bar::{opaque#0}`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs b/src/test/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs
new file mode 100644
index 000000000000..3ac264e8ebac
--- /dev/null
+++ b/src/test/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.rs
@@ -0,0 +1,19 @@
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+use std::fmt::Display;
+
+trait Foo {
+    fn bar(&self) -> impl Display;
+}
+
+impl Foo for () {
+    fn bar(&self) -> impl Display {
+        "Hello, world"
+    }
+}
+
+fn main() {
+    let x: &str = ().bar();
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr b/src/test/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr
new file mode 100644
index 000000000000..15edda483401
--- /dev/null
+++ b/src/test/ui/impl-trait/in-trait/opaque-in-impl-is-opaque.stderr
@@ -0,0 +1,17 @@
+error[E0308]: mismatched types
+  --> $DIR/opaque-in-impl-is-opaque.rs:17:19
+   |
+LL |     fn bar(&self) -> impl Display {
+   |                      ------------ the found opaque type
+...
+LL |     let x: &str = ().bar();
+   |            ----   ^^^^^^^^ expected `&str`, found opaque type
+   |            |
+   |            expected due to this
+   |
+   = note: expected reference `&str`
+            found opaque type `impl std::fmt::Display`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/impl-trait/in-trait/opaque-in-impl.rs b/src/test/ui/impl-trait/in-trait/opaque-in-impl.rs
new file mode 100644
index 000000000000..a777cbcd529a
--- /dev/null
+++ b/src/test/ui/impl-trait/in-trait/opaque-in-impl.rs
@@ -0,0 +1,20 @@
+// check-pass
+
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+use std::fmt::Display;
+
+trait Foo {
+    fn bar(&self) -> impl Display;
+}
+
+impl Foo for () {
+    fn bar(&self) -> impl Display {
+        "Hello, world"
+    }
+}
+
+fn main() {
+    println!("{}", ().bar());
+}
diff --git a/src/test/ui/impl-trait/in-trait/success.rs b/src/test/ui/impl-trait/in-trait/success.rs
new file mode 100644
index 000000000000..4cbe682b46f7
--- /dev/null
+++ b/src/test/ui/impl-trait/in-trait/success.rs
@@ -0,0 +1,40 @@
+// check-pass
+
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+use std::fmt::Display;
+
+trait Foo {
+    fn bar(&self) -> impl Display;
+}
+
+impl Foo for i32 {
+    fn bar(&self) -> i32 {
+        *self
+    }
+}
+
+impl Foo for &'static str {
+    fn bar(&self) -> &'static str {
+        *self
+    }
+}
+
+struct Yay;
+
+impl Foo for Yay {
+    fn bar(&self) -> String {
+        String::from(":^)")
+    }
+}
+
+fn foo_generically(t: T) {
+    println!("{}", t.bar());
+}
+
+fn main() {
+    println!("{}", "Hello, world.".bar());
+    println!("The answer is {}!", 42.bar());
+    foo_generically(Yay);
+}

From ed2a32f22cfb7e43a3d8c732ac8fa8007c061c5f Mon Sep 17 00:00:00 2001
From: Michael Goulet 
Date: Wed, 31 Aug 2022 05:29:36 +0000
Subject: [PATCH 4368/5092] Make clippy happy

---
 src/tools/clippy/clippy_lints/src/dereference.rs    | 2 +-
 src/tools/clippy/clippy_lints/src/missing_doc.rs    | 3 ++-
 src/tools/clippy/clippy_lints/src/missing_inline.rs | 1 +
 src/tools/clippy/clippy_utils/src/hir_utils.rs      | 3 +++
 4 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index d1ab7fb67962..09a073f4234d 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -959,7 +959,7 @@ fn binding_ty_auto_deref_stability<'tcx>(
                     ))
                     .is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()),
             ),
-            TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::Err => {
+            TyKind::OpaqueDef(..) | TyKind::ImplTraitInTrait(..) | TyKind::Infer | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::Err => {
                 Position::ReborrowStable(precedence)
             },
         };
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index 3701fdb4adbf..9f518c7aaa39 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -147,7 +147,8 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
             | hir::ItemKind::TraitAlias(..)
             | hir::ItemKind::TyAlias(..)
             | hir::ItemKind::Union(..)
-            | hir::ItemKind::OpaqueTy(..) => {},
+            | hir::ItemKind::OpaqueTy(..)
+            | hir::ItemKind::ImplTraitPlaceholder(..) => {},
             hir::ItemKind::ExternCrate(..)
             | hir::ItemKind::ForeignMod { .. }
             | hir::ItemKind::GlobalAsm(..)
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index 07bc2ca5d3cd..9fd1a475d749 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -128,6 +128,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
             | hir::ItemKind::TyAlias(..)
             | hir::ItemKind::Union(..)
             | hir::ItemKind::OpaqueTy(..)
+            | hir::ItemKind::ImplTraitPlaceholder(..)
             | hir::ItemKind::ExternCrate(..)
             | hir::ItemKind::ForeignMod { .. }
             | hir::ItemKind::Impl { .. }
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index ff23ed5fffa3..9f8500d41a85 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -990,6 +990,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
             TyKind::OpaqueDef(_, arg_list) => {
                 self.hash_generic_args(arg_list);
             },
+            TyKind::ImplTraitInTrait(_) => {
+                // Do nothing
+            }
             TyKind::TraitObject(_, lifetime, _) => {
                 self.hash_lifetime(*lifetime);
             },

From 5be30f9d79b2e08128704ddb29f7925e2fb3ef88 Mon Sep 17 00:00:00 2001
From: Michael Goulet 
Date: Fri, 2 Sep 2022 15:57:31 +0000
Subject: [PATCH 4369/5092] Make async fn in traits work

---
 compiler/rustc_ast/src/ast.rs                 |  4 ++--
 compiler/rustc_ast_lowering/src/errors.rs     | 11 ++++++++++
 compiler/rustc_ast_lowering/src/expr.rs       |  5 +++--
 compiler/rustc_ast_lowering/src/item.rs       | 14 +++++++++----
 compiler/rustc_ast_lowering/src/lib.rs        | 21 ++++++++++++-------
 .../rustc_ast_passes/src/ast_validation.rs    |  7 -------
 compiler/rustc_ast_passes/src/errors.rs       | 11 ----------
 .../locales/en-US/ast_lowering.ftl            |  6 ++++++
 .../locales/en-US/ast_passes.ftl              |  6 ------
 compiler/rustc_resolve/src/late.rs            |  2 +-
 10 files changed, 46 insertions(+), 41 deletions(-)

diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index e38572f609b3..c07ba88ae204 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2367,9 +2367,9 @@ impl Async {
     }
 
     /// In this case this is an `async` return, the `NodeId` for the generated `impl Trait` item.
-    pub fn opt_return_id(self) -> Option {
+    pub fn opt_return_id(self) -> Option<(NodeId, Span)> {
         match self {
-            Async::Yes { return_impl_trait_id, .. } => Some(return_impl_trait_id),
+            Async::Yes { return_impl_trait_id, span, .. } => Some((return_impl_trait_id, span)),
             Async::No => None,
         }
     }
diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs
index 4adeaef9bbfa..c87d0ca96570 100644
--- a/compiler/rustc_ast_lowering/src/errors.rs
+++ b/compiler/rustc_ast_lowering/src/errors.rs
@@ -334,3 +334,14 @@ pub struct InclusiveRangeWithNoEnd {
     #[primary_span]
     pub span: Span,
 }
+
+#[derive(SessionDiagnostic, Clone, Copy)]
+#[diag(ast_lowering::trait_fn_async, code = "E0706")]
+#[note]
+#[note(ast_lowering::note2)]
+pub struct TraitFnAsync {
+    #[primary_span]
+    pub fn_span: Span,
+    #[label]
+    pub span: Span,
+}
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 5346f1ced829..f929549d7044 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -851,7 +851,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
         self.lower_lifetime_binder(closure_id, generic_params, |lctx, bound_generic_params| {
             // Lower outside new scope to preserve `is_in_loop_condition`.
-            let fn_decl = lctx.lower_fn_decl(decl, None, FnDeclKind::Closure, None);
+            let fn_decl = lctx.lower_fn_decl(decl, None, fn_decl_span, FnDeclKind::Closure, None);
 
             let c = lctx.arena.alloc(hir::Closure {
                 binder: binder_clause,
@@ -955,7 +955,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
             // We need to lower the declaration outside the new scope, because we
             // have to conserve the state of being inside a loop condition for the
             // closure argument types.
-            let fn_decl = lctx.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None);
+            let fn_decl =
+                lctx.lower_fn_decl(&outer_decl, None, fn_decl_span, FnDeclKind::Closure, None);
 
             let c = lctx.arena.alloc(hir::Closure {
                 binder: binder_clause,
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 9e05fbbdc197..96e281ca5c84 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -269,7 +269,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     let mut itctx = ImplTraitContext::Universal;
                     let (generics, decl) = this.lower_generics(generics, id, &mut itctx, |this| {
                         let ret_id = asyncness.opt_return_id();
-                        this.lower_fn_decl(&decl, Some(id), FnDeclKind::Fn, ret_id)
+                        this.lower_fn_decl(&decl, Some(id), fn_sig_span, FnDeclKind::Fn, ret_id)
                     });
                     let sig = hir::FnSig {
                         decl,
@@ -661,7 +661,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         self.lower_generics(generics, i.id, &mut itctx, |this| {
                             (
                                 // Disallow `impl Trait` in foreign items.
-                                this.lower_fn_decl(fdec, None, FnDeclKind::ExternFn, None),
+                                this.lower_fn_decl(
+                                    fdec,
+                                    None,
+                                    sig.span,
+                                    FnDeclKind::ExternFn,
+                                    None,
+                                ),
                                 this.lower_fn_params_to_names(fdec),
                             )
                         });
@@ -1240,12 +1246,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
         sig: &FnSig,
         id: NodeId,
         kind: FnDeclKind,
-        is_async: Option,
+        is_async: Option<(NodeId, Span)>,
     ) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
         let header = self.lower_fn_header(sig.header);
         let mut itctx = ImplTraitContext::Universal;
         let (generics, decl) = self.lower_generics(generics, id, &mut itctx, |this| {
-            this.lower_fn_decl(&sig.decl, Some(id), kind, is_async)
+            this.lower_fn_decl(&sig.decl, Some(id), sig.span, kind, is_async)
         });
         (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
     }
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 2e8fcd7dca45..de7e64351b94 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -42,7 +42,7 @@
 #[macro_use]
 extern crate tracing;
 
-use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait};
+use crate::errors::{AssocTyParentheses, AssocTyParenthesesSub, MisplacedImplTrait, TraitFnAsync};
 
 use rustc_arena::declare_arena;
 use rustc_ast::ptr::P;
@@ -1274,7 +1274,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         generic_params,
                         unsafety: lctx.lower_unsafety(f.unsafety),
                         abi: lctx.lower_extern(f.ext),
-                        decl: lctx.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None),
+                        decl: lctx.lower_fn_decl(&f.decl, None, t.span, FnDeclKind::Pointer, None),
                         param_names: lctx.lower_fn_params_to_names(&f.decl),
                     }))
                 })
@@ -1677,19 +1677,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     // `fn_def_id`: if `Some`, impl Trait arguments are lowered into generic parameters on the
     //      given DefId, otherwise impl Trait is disallowed. Must be `Some` if
     //      `make_ret_async` is also `Some`.
-    // `impl_trait_return_allow`: determines whether `impl Trait` can be used in return position.
-    //      This guards against trait declarations and implementations where `impl Trait` is
-    //      disallowed.
     // `make_ret_async`: if `Some`, converts `-> T` into `-> impl Future` in the
     //      return type. This is used for `async fn` declarations. The `NodeId` is the ID of the
-    //      return type `impl Trait` item.
+    //      return type `impl Trait` item, and the `Span` points to the `async` keyword.
     #[instrument(level = "debug", skip(self))]
     fn lower_fn_decl(
         &mut self,
         decl: &FnDecl,
         fn_node_id: Option,
+        fn_span: Span,
         kind: FnDeclKind,
-        make_ret_async: Option,
+        make_ret_async: Option<(NodeId, Span)>,
     ) -> &'hir hir::FnDecl<'hir> {
         let c_variadic = decl.c_variadic();
 
@@ -1720,7 +1718,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             }
         }));
 
-        let output = if let Some(ret_id) = make_ret_async {
+        let output = if let Some((ret_id, span)) = make_ret_async {
+            if !self.tcx.features().return_position_impl_trait_in_trait {
+                self.tcx.sess.emit_feature_err(
+                    TraitFnAsync { fn_span, span },
+                    sym::return_position_impl_trait_in_trait,
+                );
+            }
+
             self.lower_async_fn_ret_ty(
                 &decl.output,
                 fn_node_id.expect("`make_ret_async` but no `fn_def_id`"),
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index d6d8881a53a1..6c754f38d144 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -290,12 +290,6 @@ impl<'a> AstValidator<'a> {
         }
     }
 
-    fn check_trait_fn_not_async(&self, fn_span: Span, asyncness: Async) {
-        if let Async::Yes { span, .. } = asyncness {
-            self.session.emit_err(TraitFnAsync { fn_span, span });
-        }
-    }
-
     fn check_trait_fn_not_const(&self, constness: Const) {
         if let Const::Yes(span) = constness {
             self.session.emit_err(TraitFnConst { span });
@@ -1596,7 +1590,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             self.invalid_visibility(&item.vis, None);
             if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
                 self.check_trait_fn_not_const(sig.header.constness);
-                self.check_trait_fn_not_async(item.span, sig.header.asyncness);
             }
         }
 
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 21467e576519..4f3b09c58711 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -79,17 +79,6 @@ pub enum InvalidVisibilityNote {
     IndividualForeignItems,
 }
 
-#[derive(SessionDiagnostic)]
-#[diag(ast_passes::trait_fn_async, code = "E0706")]
-#[note]
-#[note(ast_passes::note2)]
-pub struct TraitFnAsync {
-    #[primary_span]
-    pub fn_span: Span,
-    #[label]
-    pub span: Span,
-}
-
 #[derive(SessionDiagnostic)]
 #[diag(ast_passes::trait_fn_const, code = "E0379")]
 pub struct TraitFnConst {
diff --git a/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl b/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl
index f2790531aba4..c45e045b4dba 100644
--- a/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/ast_lowering.ftl
@@ -131,3 +131,9 @@ ast_lowering_arbitrary_expression_in_pattern =
     arbitrary expressions aren't allowed in patterns
 
 ast_lowering_inclusive_range_with_no_end = inclusive range with no end
+
+ast_lowering_trait_fn_async =
+    functions in traits cannot be declared `async`
+    .label = `async` because of this
+    .note = `async` trait functions are not currently supported
+    .note2 = consider using the `async-trait` crate: https://crates.io/crates/async-trait
diff --git a/compiler/rustc_error_messages/locales/en-US/ast_passes.ftl b/compiler/rustc_error_messages/locales/en-US/ast_passes.ftl
index d7108e1e2de3..e5cd1142b20c 100644
--- a/compiler/rustc_error_messages/locales/en-US/ast_passes.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/ast_passes.ftl
@@ -26,12 +26,6 @@ ast_passes_invalid_visibility =
     .individual_impl_items = place qualifiers on individual impl items instead
     .individual_foreign_items = place qualifiers on individual foreign items instead
 
-ast_passes_trait_fn_async =
-    functions in traits cannot be declared `async`
-    .label = `async` because of this
-    .note = `async` trait functions are not currently supported
-    .note2 = consider using the `async-trait` crate: https://crates.io/crates/async-trait
-
 ast_passes_trait_fn_const =
     functions in traits cannot be declared const
     .label = functions in traits cannot be const
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index b37feb15890b..2d6e76c451bf 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -851,7 +851,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                         // We include all lifetime parameters, either named or "Fresh".
                         // The order of those parameters does not matter, as long as it is
                         // deterministic.
-                        if let Some(async_node_id) = async_node_id {
+                        if let Some((async_node_id, _)) = async_node_id {
                             let mut extra_lifetime_params = this
                                 .r
                                 .extra_lifetime_params_map

From 249ede4195a40147c45411f1fa27e376d40f4f95 Mon Sep 17 00:00:00 2001
From: Michael Goulet 
Date: Fri, 2 Sep 2022 16:45:30 +0000
Subject: [PATCH 4370/5092] Address rebase issues, make async fn in trait work

---
 compiler/rustc_ast_lowering/src/item.rs      | 10 ++-
 compiler/rustc_ast_lowering/src/lib.rs       | 92 ++++++++++++++++----
 compiler/rustc_metadata/src/rmeta/encoder.rs |  6 +-
 3 files changed, 89 insertions(+), 19 deletions(-)

diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 96e281ca5c84..52273778dcc0 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -777,9 +777,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 (hir::Generics::empty(), hir::TraitItemKind::Const(ty, body), body.is_some())
             }
             AssocItemKind::Fn(box Fn { ref sig, ref generics, body: None, .. }) => {
+                let asyncness = sig.header.asyncness;
                 let names = self.lower_fn_params_to_names(&sig.decl);
-                let (generics, sig) =
-                    self.lower_method_sig(generics, sig, i.id, FnDeclKind::Trait, None);
+                let (generics, sig) = self.lower_method_sig(
+                    generics,
+                    sig,
+                    i.id,
+                    FnDeclKind::Trait,
+                    asyncness.opt_return_id(),
+                );
                 (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false)
             }
             AssocItemKind::Fn(box Fn { ref sig, ref generics, body: Some(ref body), .. }) => {
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index de7e64351b94..8814d184c558 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1358,7 +1358,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     }
                     ImplTraitContext::InTrait => {
                         // FIXME(RPITIT): Should we use def_node_id here?
-                        self.lower_impl_trait_in_trait(span, def_node_id, bounds)
+                        self.lower_impl_trait_in_trait(span, def_node_id, |lctx| {
+                            lctx.lower_param_bounds(
+                                bounds,
+                                ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
+                            )
+                        })
                     }
                     ImplTraitContext::Universal => {
                         let span = t.span;
@@ -1546,19 +1551,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         hir::TyKind::OpaqueDef(hir::ItemId { def_id: opaque_ty_def_id }, lifetimes)
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
+    #[instrument(level = "debug", skip(self, lower_bounds))]
     fn lower_impl_trait_in_trait(
         &mut self,
         span: Span,
         opaque_ty_node_id: NodeId,
-        bounds: &GenericBounds,
+        lower_bounds: impl FnOnce(&mut Self) -> hir::GenericBounds<'hir>,
     ) -> hir::TyKind<'hir> {
         let opaque_ty_def_id = self.local_def_id(opaque_ty_node_id);
         self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
             // FIXME(RPITIT): This should be a more descriptive ImplTraitPosition, i.e. nested RPITIT
             // FIXME(RPITIT): We _also_ should support this eventually
-            let hir_bounds = lctx
-                .lower_param_bounds(bounds, ImplTraitContext::Disallowed(ImplTraitPosition::Trait));
+            let hir_bounds = lower_bounds(lctx);
             let rpitit_placeholder = hir::ImplTraitPlaceholder { bounds: hir_bounds };
             let rpitit_item = hir::Item {
                 def_id: opaque_ty_def_id,
@@ -1719,18 +1723,44 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         }));
 
         let output = if let Some((ret_id, span)) = make_ret_async {
-            if !self.tcx.features().return_position_impl_trait_in_trait {
-                self.tcx.sess.emit_feature_err(
-                    TraitFnAsync { fn_span, span },
-                    sym::return_position_impl_trait_in_trait,
-                );
+            match kind {
+                FnDeclKind::Trait => {
+                    if !kind.impl_trait_in_trait_allowed(self.tcx) {
+                        self.tcx
+                            .sess
+                            .create_feature_err(
+                                TraitFnAsync { fn_span, span },
+                                sym::return_position_impl_trait_in_trait,
+                            )
+                            .emit();
+                    }
+                    self.lower_async_fn_ret_ty_in_trait(
+                        &decl.output,
+                        fn_node_id.expect("`make_ret_async` but no `fn_def_id`"),
+                        ret_id,
+                    )
+                }
+                _ => {
+                    if !kind.impl_trait_return_allowed(self.tcx) {
+                        if kind == FnDeclKind::Impl {
+                            self.tcx
+                                .sess
+                                .create_feature_err(
+                                    TraitFnAsync { fn_span, span },
+                                    sym::return_position_impl_trait_in_trait,
+                                )
+                                .emit();
+                        } else {
+                            self.tcx.sess.emit_err(TraitFnAsync { fn_span, span });
+                        }
+                    }
+                    self.lower_async_fn_ret_ty(
+                        &decl.output,
+                        fn_node_id.expect("`make_ret_async` but no `fn_def_id`"),
+                        ret_id,
+                    )
+                }
             }
-
-            self.lower_async_fn_ret_ty(
-                &decl.output,
-                fn_node_id.expect("`make_ret_async` but no `fn_def_id`"),
-                ret_id,
-            )
         } else {
             match decl.output {
                 FnRetTy::Ty(ref ty) => {
@@ -2020,6 +2050,36 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         hir::FnRetTy::Return(self.arena.alloc(opaque_ty))
     }
 
+    // Transforms `-> T` for `async fn` into `-> OpaqueTy { .. }`
+    // combined with the following definition of `OpaqueTy`:
+    //
+    //     type OpaqueTy = impl Future;
+    //
+    // `output`: unlowered output type (`T` in `-> T`)
+    // `fn_def_id`: `DefId` of the parent function (used to create child impl trait definition)
+    // `opaque_ty_node_id`: `NodeId` of the opaque `impl Trait` type that should be created
+    #[instrument(level = "debug", skip(self))]
+    fn lower_async_fn_ret_ty_in_trait(
+        &mut self,
+        output: &FnRetTy,
+        fn_node_id: NodeId,
+        opaque_ty_node_id: NodeId,
+    ) -> hir::FnRetTy<'hir> {
+        let span = output.span();
+
+        let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, None);
+
+        let fn_def_id = self.local_def_id(fn_node_id);
+
+        let kind = self.lower_impl_trait_in_trait(output.span(), opaque_ty_node_id, |lctx| {
+            let bound =
+                lctx.lower_async_fn_output_type_to_future_bound(output, fn_def_id, output.span());
+            arena_vec![lctx; bound]
+        });
+        let opaque_ty = self.ty(opaque_ty_span, kind);
+        hir::FnRetTy::Return(self.arena.alloc(opaque_ty))
+    }
+
     /// Transforms `-> T` into `Future`.
     fn lower_async_fn_output_type_to_future_bound(
         &mut self,
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 02ca34181cd0..d45d814c3b0f 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1036,6 +1036,7 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) ->
         | DefKind::Static(..)
         | DefKind::TyAlias
         | DefKind::OpaqueTy
+        | DefKind::ImplTraitPlaceholder
         | DefKind::ForeignTy
         | DefKind::Impl
         | DefKind::AssocFn
@@ -1085,6 +1086,7 @@ fn should_encode_const(def_kind: DefKind) -> bool {
         | DefKind::Static(..)
         | DefKind::TyAlias
         | DefKind::OpaqueTy
+        | DefKind::ImplTraitPlaceholder
         | DefKind::ForeignTy
         | DefKind::Impl
         | DefKind::AssocFn
@@ -1497,7 +1499,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             }
             hir::ItemKind::OpaqueTy(..) => {
                 self.encode_explicit_item_bounds(def_id);
-                EntryKind::OpaqueTy
+            }
+            hir::ItemKind::ImplTraitPlaceholder(..) => {
+                self.encode_explicit_item_bounds(def_id);
             }
             hir::ItemKind::Enum(..) => {
                 let adt_def = self.tcx.adt_def(def_id);

From 70775304cd83bf01bf91d5cf206923064fca68ef Mon Sep 17 00:00:00 2001
From: Michael Goulet 
Date: Fri, 2 Sep 2022 16:55:24 +0000
Subject: [PATCH 4371/5092] Address nits

---
 compiler/rustc_ast_lowering/src/lib.rs               | 1 -
 compiler/rustc_hir/src/def.rs                        | 4 ++--
 compiler/rustc_hir/src/hir.rs                        | 5 ++++-
 compiler/rustc_trait_selection/src/traits/project.rs | 6 +++---
 4 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 8814d184c558..8fa2c593193e 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1357,7 +1357,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         )
                     }
                     ImplTraitContext::InTrait => {
-                        // FIXME(RPITIT): Should we use def_node_id here?
                         self.lower_impl_trait_in_trait(span, def_node_id, |lctx| {
                             lctx.lower_param_bounds(
                                 bounds,
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index 8563b588585b..e7c26bd726fb 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -193,7 +193,6 @@ impl DefKind {
             | DefKind::Variant
             | DefKind::Trait
             | DefKind::OpaqueTy
-            | DefKind::ImplTraitPlaceholder
             | DefKind::TyAlias
             | DefKind::ForeignTy
             | DefKind::TraitAlias
@@ -221,7 +220,8 @@ impl DefKind {
             | DefKind::Use
             | DefKind::ForeignMod
             | DefKind::GlobalAsm
-            | DefKind::Impl => None,
+            | DefKind::Impl
+            | DefKind::ImplTraitPlaceholder => None,
         }
     }
 
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 334d4fd0b042..8b1ebe34cb00 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2551,7 +2551,10 @@ pub enum TyKind<'hir> {
     /// The generic argument list contains the lifetimes (and in the future
     /// possibly parameters) that are actually bound on the `impl Trait`.
     OpaqueDef(ItemId, &'hir [GenericArg<'hir>]),
-    /// The placeholder
+    /// A type that represents an `impl Trait` in a trait function. This is
+    /// not an opaque type, since it acts more like an associated type than
+    /// an opaque, and since it needs no generics since it inherits those
+    /// from the item's parent.
     ImplTraitInTrait(ItemId),
     /// A trait object type `Bound1 + Bound2 + Bound3`
     /// where `Bound` is a trait or a lifetime.
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 6ccb91c8cab6..6c9efea8ca87 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1308,9 +1308,9 @@ fn project<'cx, 'tcx>(
     }
 }
 
-/// The first thing we have to do is scan through the parameter
-/// environment to see whether there are any projection predicates
-/// there that can answer this question.
+/// If the predicate's item is an `ImplTraitPlaceholder`, we do a select on the
+/// corresponding trait ref. If this yields an `impl`, then we're able to project
+/// to a concrete type, since we have an `impl`'s method  to provide the RPITIT.
 fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,

From 1f03edeabe7a2ba1eed35cd7beb93c1bc0364bc5 Mon Sep 17 00:00:00 2001
From: Michael Goulet 
Date: Fri, 2 Sep 2022 17:54:58 +0000
Subject: [PATCH 4372/5092] Bless tests, fix ICE with ImplTraitPlaceholder

---
 compiler/rustc_ast_lowering/src/lib.rs        |  31 +--
 compiler/rustc_typeck/src/check/closure.rs    |  12 +-
 src/test/ui/async-await/async-trait-fn.rs     |   3 +
 src/test/ui/async-await/async-trait-fn.stderr |  95 ++++++---
 .../edition-deny-async-fns-2015.rs            |   3 +-
 .../edition-deny-async-fns-2015.stderr        |  30 ++-
 .../ui/async-await/issues/issue-95307.stderr  |   2 +
 src/test/ui/parser/fn-header-semantic-fail.rs |   2 -
 .../ui/parser/fn-header-semantic-fail.stderr  | 184 ++++++++----------
 ...ue-70736-async-fn-no-body-def-collector.rs |   1 -
 ...0736-async-fn-no-body-def-collector.stderr |  43 ++--
 ...021-incompatible-closure-captures-93117.rs |   5 +-
 ...incompatible-closure-captures-93117.stderr |  46 +++--
 13 files changed, 255 insertions(+), 202 deletions(-)

diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 8fa2c593193e..e8201c0ddcae 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1960,8 +1960,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 //
                 // Then, we will create `fn foo(..) -> Foo<'_, '_>`, and
                 // hence the elision takes place at the fn site.
-                let future_bound =
-                    this.lower_async_fn_output_type_to_future_bound(output, fn_def_id, span);
+                let future_bound = this.lower_async_fn_output_type_to_future_bound(
+                    output,
+                    span,
+                    ImplTraitContext::ReturnPositionOpaqueTy {
+                        origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
+                    },
+                );
 
                 let generic_params = this.arena.alloc_from_iter(collected_lifetimes.iter().map(
                     |&(new_node_id, lifetime, _)| {
@@ -2064,17 +2069,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         fn_node_id: NodeId,
         opaque_ty_node_id: NodeId,
     ) -> hir::FnRetTy<'hir> {
-        let span = output.span();
-
-        let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, None);
-
-        let fn_def_id = self.local_def_id(fn_node_id);
-
         let kind = self.lower_impl_trait_in_trait(output.span(), opaque_ty_node_id, |lctx| {
-            let bound =
-                lctx.lower_async_fn_output_type_to_future_bound(output, fn_def_id, output.span());
+            let bound = lctx.lower_async_fn_output_type_to_future_bound(
+                output,
+                output.span(),
+                ImplTraitContext::Disallowed(ImplTraitPosition::TraitReturn),
+            );
             arena_vec![lctx; bound]
         });
+
+        let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, output.span(), None);
         let opaque_ty = self.ty(opaque_ty_span, kind);
         hir::FnRetTy::Return(self.arena.alloc(opaque_ty))
     }
@@ -2083,8 +2087,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_async_fn_output_type_to_future_bound(
         &mut self,
         output: &FnRetTy,
-        fn_def_id: LocalDefId,
         span: Span,
+        mut nested_impl_trait_context: ImplTraitContext,
     ) -> hir::GenericBound<'hir> {
         // Compute the `T` in `Future` from the return type.
         let output_ty = match output {
@@ -2092,10 +2096,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 // Not `OpaqueTyOrigin::AsyncFn`: that's only used for the
                 // `impl Future` opaque type that `async fn` implicitly
                 // generates.
-                let mut context = ImplTraitContext::ReturnPositionOpaqueTy {
-                    origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
-                };
-                self.lower_ty(ty, &mut context)
+                self.lower_ty(ty, &mut nested_impl_trait_context)
             }
             FnRetTy::Default(ret_ty_span) => self.arena.alloc(self.ty_tup(*ret_ty_span, &[])),
         };
diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs
index bc3fec6e7d66..55cbaf71e7cf 100644
--- a/compiler/rustc_typeck/src/check/closure.rs
+++ b/compiler/rustc_typeck/src/check/closure.rs
@@ -4,6 +4,7 @@ use super::{check_fn, Expectation, FnCtxt, GeneratorTypes};
 
 use crate::astconv::AstConv;
 use crate::rustc_middle::ty::subst::Subst;
+use hir::def::DefKind;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
@@ -680,9 +681,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .map(|e| e.map_bound(|e| *e).transpose_tuple2())
                 .find_map(|(p, s)| get_future_output(p.subst(self.tcx, substs), s.0))?,
             ty::Error(_) => return None,
+            ty::Projection(proj)
+                if self.tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder =>
+            {
+                self.tcx
+                    .bound_explicit_item_bounds(proj.item_def_id)
+                    .transpose_iter()
+                    .map(|e| e.map_bound(|e| *e).transpose_tuple2())
+                    .find_map(|(p, s)| get_future_output(p.subst(self.tcx, proj.substs), s.0))?
+            }
             _ => span_bug!(
                 self.tcx.def_span(expr_def_id),
-                "async fn generator return type not an inference variable"
+                "async fn generator return type not an inference variable: {ret_ty}"
             ),
         };
 
diff --git a/src/test/ui/async-await/async-trait-fn.rs b/src/test/ui/async-await/async-trait-fn.rs
index e2062e82725c..0ea685986db4 100644
--- a/src/test/ui/async-await/async-trait-fn.rs
+++ b/src/test/ui/async-await/async-trait-fn.rs
@@ -1,8 +1,11 @@
 // edition:2018
 trait T {
     async fn foo() {} //~ ERROR functions in traits cannot be declared `async`
+    //~^ ERROR mismatched types
     async fn bar(&self) {} //~ ERROR functions in traits cannot be declared `async`
+    //~^ ERROR mismatched types
     async fn baz() { //~ ERROR functions in traits cannot be declared `async`
+        //~^ ERROR mismatched types
         // Nested item must not ICE.
         fn a() {}
     }
diff --git a/src/test/ui/async-await/async-trait-fn.stderr b/src/test/ui/async-await/async-trait-fn.stderr
index 1eb8969a80d2..e30dfb1e1a70 100644
--- a/src/test/ui/async-await/async-trait-fn.stderr
+++ b/src/test/ui/async-await/async-trait-fn.stderr
@@ -2,40 +2,89 @@ error[E0706]: functions in traits cannot be declared `async`
   --> $DIR/async-trait-fn.rs:3:5
    |
 LL |     async fn foo() {}
-   |     -----^^^^^^^^^^^^
-   |     |
-   |     `async` because of this
-   |
-   = note: `async` trait functions are not currently supported
-   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
-
-error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/async-trait-fn.rs:4:5
-   |
-LL |     async fn bar(&self) {}
-   |     -----^^^^^^^^^^^^^^^^^
+   |     -----^^^^^^^^^
    |     |
    |     `async` because of this
    |
    = note: `async` trait functions are not currently supported
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611  for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
 
 error[E0706]: functions in traits cannot be declared `async`
   --> $DIR/async-trait-fn.rs:5:5
    |
-LL |       async fn baz() {
-   |       ^----
-   |       |
-   |  _____`async` because of this
-   | |
-LL | |         // Nested item must not ICE.
-LL | |         fn a() {}
-LL | |     }
-   | |_____^
+LL |     async fn bar(&self) {}
+   |     -----^^^^^^^^^^^^^^
+   |     |
+   |     `async` because of this
    |
    = note: `async` trait functions are not currently supported
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611  for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
 
-error: aborting due to 3 previous errors
+error[E0706]: functions in traits cannot be declared `async`
+  --> $DIR/async-trait-fn.rs:7:5
+   |
+LL |     async fn baz() {
+   |     -----^^^^^^^^^
+   |     |
+   |     `async` because of this
+   |
+   = note: `async` trait functions are not currently supported
+   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611  for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
 
-For more information about this error, try `rustc --explain E0706`.
+error[E0308]: mismatched types
+  --> $DIR/async-trait-fn.rs:3:20
+   |
+LL |     async fn foo() {}
+   |                    ^^ expected associated type, found opaque type
+   |
+  ::: $SRC_DIR/core/src/future/mod.rs:LL:COL
+   |
+LL | pub const fn from_generator(gen: T) -> impl Future
+   |                                           ------------------------------- the found opaque type
+   |
+   = note: expected associated type `::foo::{opaque#0}`
+                  found opaque type `impl Future`
+
+error[E0308]: mismatched types
+  --> $DIR/async-trait-fn.rs:5:25
+   |
+LL |     async fn bar(&self) {}
+   |                         ^^ expected associated type, found opaque type
+   |
+  ::: $SRC_DIR/core/src/future/mod.rs:LL:COL
+   |
+LL | pub const fn from_generator(gen: T) -> impl Future
+   |                                           ------------------------------- the found opaque type
+   |
+   = note: expected associated type `::bar::{opaque#0}`
+                  found opaque type `impl Future`
+
+error[E0308]: mismatched types
+  --> $DIR/async-trait-fn.rs:7:20
+   |
+LL |       async fn baz() {
+   |  ____________________^
+LL | |
+LL | |         // Nested item must not ICE.
+LL | |         fn a() {}
+LL | |     }
+   | |_____^ expected associated type, found opaque type
+   |
+  ::: $SRC_DIR/core/src/future/mod.rs:LL:COL
+   |
+LL |   pub const fn from_generator(gen: T) -> impl Future
+   |                                             ------------------------------- the found opaque type
+   |
+   = note: expected associated type `::baz::{opaque#0}`
+                  found opaque type `impl Future`
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0308, E0706.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/async-await/edition-deny-async-fns-2015.rs b/src/test/ui/async-await/edition-deny-async-fns-2015.rs
index e5dc9c8a5fee..22a61dcd25f9 100644
--- a/src/test/ui/async-await/edition-deny-async-fns-2015.rs
+++ b/src/test/ui/async-await/edition-deny-async-fns-2015.rs
@@ -16,7 +16,8 @@ impl Foo {
 
 trait Bar {
     async fn foo() {} //~ ERROR `async fn` is not permitted in Rust 2015
-                      //~^ ERROR functions in traits cannot be declared `async`
+    //~^ ERROR functions in traits cannot be declared `async`
+    //~| ERROR mismatched types
 }
 
 fn main() {
diff --git a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr
index 35f9c581c7b2..2f40ef1ccbb1 100644
--- a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr
+++ b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr
@@ -53,7 +53,7 @@ LL |     async fn foo() {}
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
-  --> $DIR/edition-deny-async-fns-2015.rs:36:9
+  --> $DIR/edition-deny-async-fns-2015.rs:37:9
    |
 LL |         async fn bar() {}
    |         ^^^^^ to use `async fn`, switch to Rust 2018 or later
@@ -62,7 +62,7 @@ LL |         async fn bar() {}
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
-  --> $DIR/edition-deny-async-fns-2015.rs:26:9
+  --> $DIR/edition-deny-async-fns-2015.rs:27:9
    |
 LL |         async fn foo() {}
    |         ^^^^^ to use `async fn`, switch to Rust 2018 or later
@@ -71,7 +71,7 @@ LL |         async fn foo() {}
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0670]: `async fn` is not permitted in Rust 2015
-  --> $DIR/edition-deny-async-fns-2015.rs:31:13
+  --> $DIR/edition-deny-async-fns-2015.rs:32:13
    |
 LL |             async fn bar() {}
    |             ^^^^^ to use `async fn`, switch to Rust 2018 or later
@@ -83,14 +83,30 @@ error[E0706]: functions in traits cannot be declared `async`
   --> $DIR/edition-deny-async-fns-2015.rs:18:5
    |
 LL |     async fn foo() {}
-   |     -----^^^^^^^^^^^^
+   |     -----^^^^^^^^^
    |     |
    |     `async` because of this
    |
    = note: `async` trait functions are not currently supported
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611  for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
 
-error: aborting due to 10 previous errors
+error[E0308]: mismatched types
+  --> $DIR/edition-deny-async-fns-2015.rs:18:20
+   |
+LL |     async fn foo() {}
+   |                    ^^ expected associated type, found opaque type
+   |
+  ::: $SRC_DIR/core/src/future/mod.rs:LL:COL
+   |
+LL | pub const fn from_generator(gen: T) -> impl Future
+   |                                           ------------------------------- the found opaque type
+   |
+   = note: expected associated type `::foo::{opaque#0}`
+                  found opaque type `impl Future`
 
-Some errors have detailed explanations: E0670, E0706.
-For more information about an error, try `rustc --explain E0670`.
+error: aborting due to 11 previous errors
+
+Some errors have detailed explanations: E0308, E0670, E0706.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/async-await/issues/issue-95307.stderr b/src/test/ui/async-await/issues/issue-95307.stderr
index 29aebb719d66..1c12f1e4862e 100644
--- a/src/test/ui/async-await/issues/issue-95307.stderr
+++ b/src/test/ui/async-await/issues/issue-95307.stderr
@@ -8,6 +8,8 @@ LL |     async fn new() -> [u8; _];
    |
    = note: `async` trait functions are not currently supported
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611  for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
 
 error: in expressions, `_` can only be used on the left-hand side of an assignment
   --> $DIR/issue-95307.rs:7:28
diff --git a/src/test/ui/parser/fn-header-semantic-fail.rs b/src/test/ui/parser/fn-header-semantic-fail.rs
index 8ff14fb1f304..cf5d3dab4aad 100644
--- a/src/test/ui/parser/fn-header-semantic-fail.rs
+++ b/src/test/ui/parser/fn-header-semantic-fail.rs
@@ -27,7 +27,6 @@ fn main() {
     struct Y;
     impl X for Y {
         async fn ft1() {} //~ ERROR functions in traits cannot be declared `async`
-        //~^ ERROR has an incompatible type for trait
         unsafe fn ft2() {} // OK.
         const fn ft3() {} //~ ERROR functions in traits cannot be declared const
         extern "C" fn ft4() {}
@@ -36,7 +35,6 @@ fn main() {
         //~| ERROR functions in traits cannot be declared const
         //~| ERROR functions cannot be both `const` and `async`
         //~| ERROR cycle detected
-        //~| ERROR has an incompatible type for trait
     }
 
     impl Y {
diff --git a/src/test/ui/parser/fn-header-semantic-fail.stderr b/src/test/ui/parser/fn-header-semantic-fail.stderr
index bc51ba8b8c5c..36304779df36 100644
--- a/src/test/ui/parser/fn-header-semantic-fail.stderr
+++ b/src/test/ui/parser/fn-header-semantic-fail.stderr
@@ -7,17 +7,6 @@ LL |     const async unsafe extern "C" fn ff5() {}
    |     |     `async` because of this
    |     `const` because of this
 
-error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:17:9
-   |
-LL |         async fn ft1();
-   |         -----^^^^^^^^^^
-   |         |
-   |         `async` because of this
-   |
-   = note: `async` trait functions are not currently supported
-   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
-
 error[E0379]: functions in traits cannot be declared const
   --> $DIR/fn-header-semantic-fail.rs:19:9
    |
@@ -30,17 +19,6 @@ error[E0379]: functions in traits cannot be declared const
 LL |         const async unsafe extern "C" fn ft5();
    |         ^^^^^ functions in traits cannot be const
 
-error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:21:9
-   |
-LL |         const async unsafe extern "C" fn ft5();
-   |         ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |               |
-   |               `async` because of this
-   |
-   = note: `async` trait functions are not currently supported
-   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
-
 error: functions cannot be both `const` and `async`
   --> $DIR/fn-header-semantic-fail.rs:21:9
    |
@@ -50,42 +28,20 @@ LL |         const async unsafe extern "C" fn ft5();
    |         |     `async` because of this
    |         `const` because of this
 
-error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:29:9
-   |
-LL |         async fn ft1() {}
-   |         -----^^^^^^^^^^^^
-   |         |
-   |         `async` because of this
-   |
-   = note: `async` trait functions are not currently supported
-   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
-
 error[E0379]: functions in traits cannot be declared const
-  --> $DIR/fn-header-semantic-fail.rs:32:9
+  --> $DIR/fn-header-semantic-fail.rs:31:9
    |
 LL |         const fn ft3() {}
    |         ^^^^^ functions in traits cannot be const
 
 error[E0379]: functions in traits cannot be declared const
-  --> $DIR/fn-header-semantic-fail.rs:34:9
+  --> $DIR/fn-header-semantic-fail.rs:33:9
    |
 LL |         const async unsafe extern "C" fn ft5() {}
    |         ^^^^^ functions in traits cannot be const
 
-error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/fn-header-semantic-fail.rs:34:9
-   |
-LL |         const async unsafe extern "C" fn ft5() {}
-   |         ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |               |
-   |               `async` because of this
-   |
-   = note: `async` trait functions are not currently supported
-   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
-
 error: functions cannot be both `const` and `async`
-  --> $DIR/fn-header-semantic-fail.rs:34:9
+  --> $DIR/fn-header-semantic-fail.rs:33:9
    |
 LL |         const async unsafe extern "C" fn ft5() {}
    |         ^^^^^-^^^^^------------------------------
@@ -94,7 +50,7 @@ LL |         const async unsafe extern "C" fn ft5() {}
    |         `const` because of this
 
 error: functions cannot be both `const` and `async`
-  --> $DIR/fn-header-semantic-fail.rs:47:9
+  --> $DIR/fn-header-semantic-fail.rs:45:9
    |
 LL |         const async unsafe extern "C" fn fi5() {}
    |         ^^^^^-^^^^^------------------------------
@@ -103,7 +59,7 @@ LL |         const async unsafe extern "C" fn fi5() {}
    |         `const` because of this
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:53:18
+  --> $DIR/fn-header-semantic-fail.rs:51:18
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
@@ -116,7 +72,7 @@ LL |         fn fe1();
    |         ~~
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:54:19
+  --> $DIR/fn-header-semantic-fail.rs:52:19
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
@@ -130,7 +86,7 @@ LL |         fn fe2();
    |         ~~
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:55:18
+  --> $DIR/fn-header-semantic-fail.rs:53:18
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
@@ -144,7 +100,7 @@ LL |         fn fe3();
    |         ~~
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:56:23
+  --> $DIR/fn-header-semantic-fail.rs:54:23
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
@@ -158,7 +114,7 @@ LL |         fn fe4();
    |         ~~
 
 error: functions in `extern` blocks cannot have qualifiers
-  --> $DIR/fn-header-semantic-fail.rs:57:42
+  --> $DIR/fn-header-semantic-fail.rs:55:42
    |
 LL |     extern "C" {
    |     ---------- in this `extern` block
@@ -172,7 +128,7 @@ LL |         fn fe5();
    |         ~~
 
 error: functions cannot be both `const` and `async`
-  --> $DIR/fn-header-semantic-fail.rs:57:9
+  --> $DIR/fn-header-semantic-fail.rs:55:9
    |
 LL |         const async unsafe extern "C" fn fe5();
    |         ^^^^^-^^^^^----------------------------
@@ -180,6 +136,58 @@ LL |         const async unsafe extern "C" fn fe5();
    |         |     `async` because of this
    |         `const` because of this
 
+error[E0706]: functions in traits cannot be declared `async`
+  --> $DIR/fn-header-semantic-fail.rs:17:9
+   |
+LL |         async fn ft1();
+   |         -----^^^^^^^^^^
+   |         |
+   |         `async` because of this
+   |
+   = note: `async` trait functions are not currently supported
+   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611  for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
+
+error[E0706]: functions in traits cannot be declared `async`
+  --> $DIR/fn-header-semantic-fail.rs:21:9
+   |
+LL |         const async unsafe extern "C" fn ft5();
+   |         ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |               |
+   |               `async` because of this
+   |
+   = note: `async` trait functions are not currently supported
+   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611  for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
+
+error[E0706]: functions in traits cannot be declared `async`
+  --> $DIR/fn-header-semantic-fail.rs:29:9
+   |
+LL |         async fn ft1() {}
+   |         -----^^^^^^^^^
+   |         |
+   |         `async` because of this
+   |
+   = note: `async` trait functions are not currently supported
+   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611  for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
+
+error[E0706]: functions in traits cannot be declared `async`
+  --> $DIR/fn-header-semantic-fail.rs:33:9
+   |
+LL |         const async unsafe extern "C" fn ft5() {}
+   |         ^^^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |               |
+   |               `async` because of this
+   |
+   = note: `async` trait functions are not currently supported
+   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611  for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
+
 error[E0391]: cycle detected when computing type of `main::ff5::{opaque#0}`
   --> $DIR/fn-header-semantic-fail.rs:12:44
    |
@@ -216,60 +224,24 @@ LL | |     }
 LL | | }
    | |_^
 
-error[E0053]: method `ft1` has an incompatible type for trait
-  --> $DIR/fn-header-semantic-fail.rs:29:24
-   |
-LL |         async fn ft1() {}
-   |                        ^
-   |                        |
-   |                        checked the `Output` of this `async fn`, found opaque type
-   |                        expected `()`, found opaque type
-   |
-   = note: while checking the return type of the `async fn`
-note: type in trait
-  --> $DIR/fn-header-semantic-fail.rs:17:23
-   |
-LL |         async fn ft1();
-   |                       ^
-   = note: expected fn pointer `fn()`
-              found fn pointer `fn() -> impl Future`
-
-error[E0053]: method `ft5` has an incompatible type for trait
-  --> $DIR/fn-header-semantic-fail.rs:34:48
-   |
-LL |         const async unsafe extern "C" fn ft5() {}
-   |                                                ^
-   |                                                |
-   |                                                checked the `Output` of this `async fn`, found opaque type
-   |                                                expected `()`, found opaque type
-   |
-   = note: while checking the return type of the `async fn`
-note: type in trait
-  --> $DIR/fn-header-semantic-fail.rs:21:47
-   |
-LL |         const async unsafe extern "C" fn ft5();
-   |                                               ^
-   = note: expected fn pointer `unsafe extern "C" fn()`
-              found fn pointer `unsafe extern "C" fn() -> impl Future`
-
 error[E0391]: cycle detected when computing type of `main::::ft5::{opaque#0}`
-  --> $DIR/fn-header-semantic-fail.rs:34:48
+  --> $DIR/fn-header-semantic-fail.rs:33:48
    |
 LL |         const async unsafe extern "C" fn ft5() {}
    |                                                ^
    |
 note: ...which requires borrow-checking `main::::ft5`...
-  --> $DIR/fn-header-semantic-fail.rs:34:9
+  --> $DIR/fn-header-semantic-fail.rs:33:9
    |
 LL |         const async unsafe extern "C" fn ft5() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: ...which requires processing `main::::ft5`...
-  --> $DIR/fn-header-semantic-fail.rs:34:9
+  --> $DIR/fn-header-semantic-fail.rs:33:9
    |
 LL |         const async unsafe extern "C" fn ft5() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: ...which requires const checking `main::::ft5`...
-  --> $DIR/fn-header-semantic-fail.rs:34:9
+  --> $DIR/fn-header-semantic-fail.rs:33:9
    |
 LL |         const async unsafe extern "C" fn ft5() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -288,30 +260,30 @@ LL | |     }
 LL | | }
    | |_^
 
-error[E0391]: cycle detected when computing type of `main::::fi5::{opaque#0}`
-  --> $DIR/fn-header-semantic-fail.rs:47:48
+error[E0391]: cycle detected when computing type of `main::::fi5::{opaque#0}`
+  --> $DIR/fn-header-semantic-fail.rs:45:48
    |
 LL |         const async unsafe extern "C" fn fi5() {}
    |                                                ^
    |
-note: ...which requires borrow-checking `main::::fi5`...
-  --> $DIR/fn-header-semantic-fail.rs:47:9
+note: ...which requires borrow-checking `main::::fi5`...
+  --> $DIR/fn-header-semantic-fail.rs:45:9
    |
 LL |         const async unsafe extern "C" fn fi5() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires processing `main::::fi5`...
-  --> $DIR/fn-header-semantic-fail.rs:47:9
+note: ...which requires processing `main::::fi5`...
+  --> $DIR/fn-header-semantic-fail.rs:45:9
    |
 LL |         const async unsafe extern "C" fn fi5() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires const checking `main::::fi5`...
-  --> $DIR/fn-header-semantic-fail.rs:47:9
+note: ...which requires const checking `main::::fi5`...
+  --> $DIR/fn-header-semantic-fail.rs:45:9
    |
 LL |         const async unsafe extern "C" fn fi5() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: ...which requires computing whether `impl core::future::future::Future` is freeze...
    = note: ...which requires evaluating trait selection obligation `impl core::future::future::Future: core::marker::Freeze`...
-   = note: ...which again requires computing type of `main::::fi5::{opaque#0}`, completing the cycle
+   = note: ...which again requires computing type of `main::::fi5::{opaque#0}`, completing the cycle
 note: cycle used when checking item types in top-level module
   --> $DIR/fn-header-semantic-fail.rs:5:1
    |
@@ -324,7 +296,7 @@ LL | |     }
 LL | | }
    | |_^
 
-error: aborting due to 23 previous errors
+error: aborting due to 21 previous errors
 
-Some errors have detailed explanations: E0053, E0379, E0391, E0706.
-For more information about an error, try `rustc --explain E0053`.
+Some errors have detailed explanations: E0379, E0391, E0706.
+For more information about an error, try `rustc --explain E0379`.
diff --git a/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs
index aaf0f7eaef0d..49462f52fb4c 100644
--- a/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs
+++ b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.rs
@@ -14,7 +14,6 @@ trait B {
 impl B for A {
     async fn associated(); //~ ERROR without body
     //~^ ERROR cannot be declared `async`
-    //~| ERROR has an incompatible type for trait
 }
 
 fn main() {}
diff --git a/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr
index d3214458eac1..55c3b66f1363 100644
--- a/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr
+++ b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr
@@ -14,6 +14,14 @@ LL |     async fn inherent();
    |                        |
    |                        help: provide a definition for the function: `{  }`
 
+error: associated function in `impl` without body
+  --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:15:5
+   |
+LL |     async fn associated();
+   |     ^^^^^^^^^^^^^^^^^^^^^-
+   |                          |
+   |                          help: provide a definition for the function: `{  }`
+
 error[E0706]: functions in traits cannot be declared `async`
   --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:11:5
    |
@@ -24,14 +32,8 @@ LL |     async fn associated();
    |
    = note: `async` trait functions are not currently supported
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
-
-error: associated function in `impl` without body
-  --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:15:5
-   |
-LL |     async fn associated();
-   |     ^^^^^^^^^^^^^^^^^^^^^-
-   |                          |
-   |                          help: provide a definition for the function: `{  }`
+   = note: see issue #91611  for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
 
 error[E0706]: functions in traits cannot be declared `async`
   --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:15:5
@@ -43,26 +45,9 @@ LL |     async fn associated();
    |
    = note: `async` trait functions are not currently supported
    = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611  for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
 
-error[E0053]: method `associated` has an incompatible type for trait
-  --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:15:26
-   |
-LL |     async fn associated();
-   |                          ^
-   |                          |
-   |                          checked the `Output` of this `async fn`, found opaque type
-   |                          expected `()`, found opaque type
-   |
-   = note: while checking the return type of the `async fn`
-note: type in trait
-  --> $DIR/issue-70736-async-fn-no-body-def-collector.rs:11:26
-   |
-LL |     async fn associated();
-   |                          ^
-   = note: expected fn pointer `fn()`
-              found fn pointer `fn() -> impl Future`
+error: aborting due to 5 previous errors
 
-error: aborting due to 6 previous errors
-
-Some errors have detailed explanations: E0053, E0706.
-For more information about an error, try `rustc --explain E0053`.
+For more information about this error, try `rustc --explain E0706`.
diff --git a/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs b/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs
index b280c8ab6e2b..94f578af209a 100644
--- a/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs
+++ b/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs
@@ -12,7 +12,8 @@ impl A {
 
 trait C{async fn new(val: T) {} //~ ERROR  `async fn` is not permitted in Rust 2015
 //~^ ERROR functions in traits cannot be declared `async`
-//~^^ ERROR cannot find type `T` in this scope
-//~^^^ WARN changes to closure capture in Rust 2021 will affect drop order [rust_2021_incompatible_closure_captures]
+//~| ERROR mismatched types
+//~| ERROR cannot find type `T` in this scope
+//~| WARN changes to closure capture in Rust 2021 will affect drop order [rust_2021_incompatible_closure_captures]
 
 //~ ERROR  this file contains an unclosed delimiter
diff --git a/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.stderr b/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.stderr
index 50de2322907e..9819f6501378 100644
--- a/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.stderr
+++ b/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.stderr
@@ -1,5 +1,5 @@
 error: this file contains an unclosed delimiter
-  --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:18:53
+  --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:19:53
    |
 LL | trait C{async fn new(val: T) {}
    |        - unclosed delimiter
@@ -25,17 +25,6 @@ LL | trait C{async fn new(val: T) {}
    = help: pass `--edition 2021` to `rustc`
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
-error[E0706]: functions in traits cannot be declared `async`
-  --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:13:9
-   |
-LL | trait C{async fn new(val: T) {}
-   |         -----^^^^^^^^^^^^^^^^^^
-   |         |
-   |         `async` because of this
-   |
-   = note: `async` trait functions are not currently supported
-   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
-
 error[E0423]: expected function, found module `crate`
   --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:9:5
    |
@@ -51,6 +40,19 @@ LL | pub struct A {}
 LL | trait C{async fn new(val: T) {}
    |                           ^ help: a struct with a similar name exists: `A`
 
+error[E0706]: functions in traits cannot be declared `async`
+  --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:13:9
+   |
+LL | trait C{async fn new(val: T) {}
+   |         -----^^^^^^^^^^^^^^^
+   |         |
+   |         `async` because of this
+   |
+   = note: `async` trait functions are not currently supported
+   = note: consider using the `async-trait` crate: https://crates.io/crates/async-trait
+   = note: see issue #91611  for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
+
 warning: changes to closure capture in Rust 2021 will affect drop order
   --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:6:57
    |
@@ -72,6 +74,20 @@ help: add a dummy let to cause `path` to be fully captured
 LL |     async fn create(path: impl AsRef)  { let _ = &path;
    |                                                           ++++++++++++++
 
+error[E0308]: mismatched types
+  --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:13:30
+   |
+LL | trait C{async fn new(val: T) {}
+   |                              ^^ expected associated type, found opaque type
+   |
+  ::: $SRC_DIR/core/src/future/mod.rs:LL:COL
+   |
+LL | pub const fn from_generator(gen: T) -> impl Future
+   |                                           ------------------------------- the found opaque type
+   |
+   = note: expected associated type `::new::{opaque#0}`
+                  found opaque type `impl Future`
+
 warning: changes to closure capture in Rust 2021 will affect drop order
   --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:13:30
    |
@@ -87,7 +103,7 @@ help: add a dummy let to cause `val` to be fully captured
 LL | trait C{async fn new(val: T) { let _ = &val;}
    |                                +++++++++++++
 
-error: aborting due to 6 previous errors; 2 warnings emitted
+error: aborting due to 7 previous errors; 2 warnings emitted
 
-Some errors have detailed explanations: E0412, E0423, E0670, E0706.
-For more information about an error, try `rustc --explain E0412`.
+Some errors have detailed explanations: E0308, E0412, E0423, E0670, E0706.
+For more information about an error, try `rustc --explain E0308`.

From cdf78073c5d24cdc4c89a515b05f9d8e09321711 Mon Sep 17 00:00:00 2001
From: Michael Goulet 
Date: Fri, 2 Sep 2022 21:02:59 +0000
Subject: [PATCH 4373/5092] Deeply check that method signatures match, and
 allow for nested RPITITs

---
 compiler/rustc_ast_lowering/src/lib.rs        |   9 +-
 compiler/rustc_middle/src/arena.rs            |   2 +
 compiler/rustc_middle/src/query/mod.rs        |   7 +
 compiler/rustc_middle/src/ty/mod.rs           |   8 +
 compiler/rustc_middle/src/ty/util.rs          |   7 +
 .../src/traits/project.rs                     |  13 +-
 .../rustc_typeck/src/check/compare_method.rs  | 147 +++++++++++++-----
 compiler/rustc_typeck/src/check/mod.rs        |   2 +
 compiler/rustc_typeck/src/collect.rs          |   5 +-
 .../impl-trait/in-trait/deep-match-works.rs   |  16 ++
 src/test/ui/impl-trait/in-trait/deep-match.rs |  15 ++
 .../ui/impl-trait/in-trait/deep-match.stderr  |  20 +++
 .../ui/impl-trait/in-trait/nested-rpitit.rs   |  32 ++++
 13 files changed, 231 insertions(+), 52 deletions(-)
 create mode 100644 src/test/ui/impl-trait/in-trait/deep-match-works.rs
 create mode 100644 src/test/ui/impl-trait/in-trait/deep-match.rs
 create mode 100644 src/test/ui/impl-trait/in-trait/deep-match.stderr
 create mode 100644 src/test/ui/impl-trait/in-trait/nested-rpitit.rs

diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index e8201c0ddcae..eecf01c92fbd 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1358,10 +1358,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     }
                     ImplTraitContext::InTrait => {
                         self.lower_impl_trait_in_trait(span, def_node_id, |lctx| {
-                            lctx.lower_param_bounds(
-                                bounds,
-                                ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
-                            )
+                            lctx.lower_param_bounds(bounds, ImplTraitContext::InTrait)
                         })
                     }
                     ImplTraitContext::Universal => {
@@ -1559,8 +1556,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     ) -> hir::TyKind<'hir> {
         let opaque_ty_def_id = self.local_def_id(opaque_ty_node_id);
         self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
-            // FIXME(RPITIT): This should be a more descriptive ImplTraitPosition, i.e. nested RPITIT
-            // FIXME(RPITIT): We _also_ should support this eventually
             let hir_bounds = lower_bounds(lctx);
             let rpitit_placeholder = hir::ImplTraitPlaceholder { bounds: hir_bounds };
             let rpitit_item = hir::Item {
@@ -2073,7 +2068,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             let bound = lctx.lower_async_fn_output_type_to_future_bound(
                 output,
                 output.span(),
-                ImplTraitContext::Disallowed(ImplTraitPosition::TraitReturn),
+                ImplTraitContext::InTrait,
             );
             arena_vec![lctx; bound]
         });
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index 65d5f755f724..9b1fedd0b533 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -101,6 +101,8 @@ macro_rules! arena_types {
             [decode] impl_source: rustc_middle::traits::ImplSource<'tcx, ()>,
 
             [] dep_kind: rustc_middle::dep_graph::DepKindStruct<'tcx>,
+
+            [] trait_impl_trait_tys: rustc_data_structures::fx::FxHashMap>,
         ]);
     )
 }
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 4478b45cf143..adf479c42360 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -161,6 +161,13 @@ rustc_queries! {
         separate_provide_extern
     }
 
+    query compare_predicates_and_trait_impl_trait_tys(key: DefId)
+        -> Result<&'tcx FxHashMap>, ErrorGuaranteed>
+    {
+        desc { "better description please" }
+        separate_provide_extern
+    }
+
     query analysis(key: ()) -> Result<(), ErrorGuaranteed> {
         eval_always
         desc { "running analysis passes on this crate" }
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 4635a9d5575d..df72260597f9 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -2484,6 +2484,14 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn is_const_default_method(self, def_id: DefId) -> bool {
         matches!(self.trait_of_item(def_id), Some(trait_id) if self.has_attr(trait_id, sym::const_trait))
     }
+
+    pub fn impl_trait_in_trait_parent(self, mut def_id: DefId) -> DefId {
+        while let def_kind = self.def_kind(def_id) && def_kind != DefKind::AssocFn {
+            debug_assert_eq!(def_kind, DefKind::ImplTraitPlaceholder);
+            def_id = self.parent(def_id);
+        }
+        def_id
+    }
 }
 
 /// Yields the parent function's `LocalDefId` if `def_id` is an `impl Trait` definition.
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index a3837512bce2..0c73ae54bc31 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -651,6 +651,13 @@ impl<'tcx> TyCtxt<'tcx> {
         ty::EarlyBinder(self.type_of(def_id))
     }
 
+    pub fn bound_trait_impl_trait_tys(
+        self,
+        def_id: DefId,
+    ) -> ty::EarlyBinder>, ErrorGuaranteed>> {
+        ty::EarlyBinder(self.compare_predicates_and_trait_impl_trait_tys(def_id))
+    }
+
     pub fn bound_fn_sig(self, def_id: DefId) -> ty::EarlyBinder> {
         ty::EarlyBinder(self.fn_sig(def_id))
     }
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 6c9efea8ca87..7253ab21b3a0 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1318,7 +1318,7 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>(
 ) {
     let tcx = selcx.tcx();
     if tcx.def_kind(obligation.predicate.item_def_id) == DefKind::ImplTraitPlaceholder {
-        let trait_fn_def_id = tcx.parent(obligation.predicate.item_def_id);
+        let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.item_def_id);
         let trait_def_id = tcx.parent(trait_fn_def_id);
         let trait_substs =
             obligation.predicate.substs.truncate_to(tcx, tcx.generics_of(trait_def_id));
@@ -2176,11 +2176,6 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
     let impl_fn_def_id = leaf_def.item.def_id;
     let impl_fn_substs = obligation.predicate.substs.rebase_onto(tcx, trait_fn_def_id, data.substs);
 
-    let sig = tcx
-        .bound_fn_sig(impl_fn_def_id)
-        .map_bound(|fn_sig| tcx.liberate_late_bound_regions(impl_fn_def_id, fn_sig))
-        .subst(tcx, impl_fn_substs);
-
     let cause = ObligationCause::new(
         obligation.cause.span,
         obligation.cause.body_id,
@@ -2217,7 +2212,11 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
         selcx,
         obligation.param_env,
         cause.clone(),
-        sig.output(),
+        tcx.bound_trait_impl_trait_tys(impl_fn_def_id)
+            .map_bound(|tys| {
+                tys.map_or_else(|_| tcx.ty_error(), |tys| tys[&obligation.predicate.item_def_id])
+            })
+            .subst(tcx, impl_fn_substs),
         &mut obligations,
     );
 
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index e55f43994b9f..da45469863e4 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -1,18 +1,22 @@
 use super::potentially_plural_count;
 use crate::errors::LifetimesOrBoundsMismatchOnTrait;
-use rustc_data_structures::fx::FxHashSet;
+use hir::def_id::DefId;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit;
 use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{self, TyCtxtInferExt};
 use rustc_infer::traits::util;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
 use rustc_middle::ty::util::ExplicitSelf;
-use rustc_middle::ty::{self, DefIdTree};
+use rustc_middle::ty::{
+    self, DefIdTree, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
+};
 use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
 use rustc_span::Span;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
@@ -64,10 +68,7 @@ pub(crate) fn compare_impl_method<'tcx>(
         return;
     }
 
-    if let Err(_) = compare_predicate_entailment(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref)
-    {
-        return;
-    }
+    tcx.ensure().compare_predicates_and_trait_impl_trait_tys(impl_m.def_id);
 }
 
 /// This function is best explained by example. Consider a trait:
@@ -136,13 +137,15 @@ pub(crate) fn compare_impl_method<'tcx>(
 ///
 /// Finally we register each of these predicates as an obligation and check that
 /// they hold.
-fn compare_predicate_entailment<'tcx>(
+pub(super) fn compare_predicates_and_trait_impl_trait_tys<'tcx>(
     tcx: TyCtxt<'tcx>,
-    impl_m: &ty::AssocItem,
-    impl_m_span: Span,
-    trait_m: &ty::AssocItem,
-    impl_trait_ref: ty::TraitRef<'tcx>,
-) -> Result<(), ErrorGuaranteed> {
+    def_id: DefId,
+) -> Result<&'tcx FxHashMap>, ErrorGuaranteed> {
+    let impl_m = tcx.opt_associated_item(def_id).unwrap();
+    let impl_m_span = tcx.def_span(def_id);
+    let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap();
+    let impl_trait_ref = tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap();
+
     let trait_to_impl_substs = impl_trait_ref.substs;
 
     // This node-id should be used for the `body_id` field on each
@@ -161,6 +164,7 @@ fn compare_predicate_entailment<'tcx>(
             kind: impl_m.kind,
         },
     );
+    let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span();
 
     // Create mapping from impl to placeholder.
     let impl_to_placeholder_substs = InternalSubsts::identity_for_item(tcx, impl_m.def_id);
@@ -266,6 +270,13 @@ fn compare_predicate_entailment<'tcx>(
 
         let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs);
         let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig);
+        let mut collector =
+            ImplTraitInTraitCollector::new(&ocx, return_span, param_env, impl_m_hir_id);
+        // FIXME(RPITIT): This should only be needed on the output type, but
+        // RPITIT placeholders shouldn't show up anywhere except for there,
+        // so I think this is fine.
+        let trait_sig = trait_sig.fold_with(&mut collector);
+
         // Next, add all inputs and output as well-formed tys. Importantly,
         // we have to do this before normalization, since the normalized ty may
         // not contain the input parameters. See issue #87748.
@@ -391,30 +402,6 @@ fn compare_predicate_entailment<'tcx>(
             return Err(diag.emit());
         }
 
-        // Check that an impl's fn return satisfies the bounds of the
-        // FIXME(RPITIT): Generalize this to nested impl traits
-        if let ty::Projection(proj) = tcx.fn_sig(trait_m.def_id).skip_binder().output().kind()
-            && tcx.def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder
-        {
-            let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span();
-
-            for (predicate, span) in tcx
-                .bound_explicit_item_bounds(proj.item_def_id)
-                .transpose_iter()
-                .map(|pred| pred.map_bound(|pred| *pred).subst(tcx, trait_to_placeholder_substs))
-            {
-                ocx.register_obligation(traits::Obligation::new(
-                    traits::ObligationCause::new(
-                        return_span,
-                        impl_m_hir_id,
-                        ObligationCauseCode::BindingObligation(proj.item_def_id, span),
-                    ),
-                    param_env,
-                    predicate,
-                ));
-            }
-        }
-
         // Check that all obligations are satisfied by the implementation's
         // version.
         let errors = ocx.select_all_or_error();
@@ -435,10 +422,96 @@ fn compare_predicate_entailment<'tcx>(
             &outlives_environment,
         );
 
-        Ok(())
+        let mut collected_tys = FxHashMap::default();
+        for (def_id, ty) in collector.types {
+            match infcx.fully_resolve(ty) {
+                Ok(ty) => {
+                    collected_tys.insert(def_id, ty);
+                }
+                Err(err) => {
+                    tcx.sess.delay_span_bug(
+                        return_span,
+                        format!("could not fully resolve: {ty} => {err:?}"),
+                    );
+                    collected_tys.insert(def_id, tcx.ty_error());
+                }
+            }
+        }
+
+        Ok(&*tcx.arena.alloc(collected_tys))
     })
 }
 
+struct ImplTraitInTraitCollector<'a, 'tcx> {
+    ocx: &'a ObligationCtxt<'a, 'tcx>,
+    types: FxHashMap>,
+    span: Span,
+    param_env: ty::ParamEnv<'tcx>,
+    body_id: hir::HirId,
+}
+
+impl<'a, 'tcx> ImplTraitInTraitCollector<'a, 'tcx> {
+    fn new(
+        ocx: &'a ObligationCtxt<'a, 'tcx>,
+        span: Span,
+        param_env: ty::ParamEnv<'tcx>,
+        body_id: hir::HirId,
+    ) -> Self {
+        ImplTraitInTraitCollector { ocx, types: FxHashMap::default(), span, param_env, body_id }
+    }
+}
+
+impl<'tcx> TypeFolder<'tcx> for ImplTraitInTraitCollector<'_, 'tcx> {
+    fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
+        self.ocx.infcx.tcx
+    }
+
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        if let ty::Projection(proj) = ty.kind()
+            && self.tcx().def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder
+        {
+            if let Some(ty) = self.types.get(&proj.item_def_id) {
+                return *ty;
+            }
+            //FIXME(RPITIT): Deny nested RPITIT in substs too
+            if proj.substs.has_escaping_bound_vars() {
+                bug!("FIXME(RPITIT): error here");
+            }
+            // Replace with infer var
+            let infer_ty = self.ocx.infcx.next_ty_var(TypeVariableOrigin {
+                span: self.span,
+                kind: TypeVariableOriginKind::MiscVariable,
+            });
+            self.types.insert(proj.item_def_id, infer_ty);
+            // Recurse into bounds
+            for pred in self.tcx().bound_explicit_item_bounds(proj.item_def_id).transpose_iter() {
+                let pred_span = pred.0.1;
+
+                let pred = pred.map_bound(|(pred, _)| *pred).subst(self.tcx(), proj.substs);
+                let pred = pred.fold_with(self);
+                let pred = self.ocx.normalize(
+                    ObligationCause::misc(self.span, self.body_id),
+                    self.param_env,
+                    pred,
+                );
+
+                self.ocx.register_obligation(traits::Obligation::new(
+                    ObligationCause::new(
+                        self.span,
+                        self.body_id,
+                        ObligationCauseCode::BindingObligation(proj.item_def_id, pred_span),
+                    ),
+                    self.param_env,
+                    pred,
+                ));
+            }
+            infer_ty
+        } else {
+            ty.super_fold_with(self)
+        }
+    }
+}
+
 fn check_region_bounds_on_impl_item<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_m: &ty::AssocItem,
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index 69eb34b5f802..8811b38fc555 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -132,6 +132,7 @@ use crate::require_c_abi_if_c_variadic;
 use crate::util::common::indenter;
 
 use self::coercion::DynamicCoerceMany;
+use self::compare_method::compare_predicates_and_trait_impl_trait_tys;
 use self::region::region_scope_tree;
 pub use self::Expectation::*;
 
@@ -249,6 +250,7 @@ pub fn provide(providers: &mut Providers) {
         used_trait_imports,
         check_mod_item_types,
         region_scope_tree,
+        compare_predicates_and_trait_impl_trait_tys,
         ..*providers
     };
 }
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index 5429598871d9..e5e82a4ff6b0 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -1602,7 +1602,10 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
             }
             ItemKind::ImplTraitPlaceholder(_) => {
                 let parent_id = tcx.hir().get_parent_item(hir_id).to_def_id();
-                assert_eq!(tcx.def_kind(parent_id), DefKind::AssocFn);
+                assert!(matches!(
+                    tcx.def_kind(parent_id),
+                    DefKind::AssocFn | DefKind::ImplTraitPlaceholder
+                ));
                 Some(parent_id)
             }
             _ => None,
diff --git a/src/test/ui/impl-trait/in-trait/deep-match-works.rs b/src/test/ui/impl-trait/in-trait/deep-match-works.rs
new file mode 100644
index 000000000000..772da845ee1f
--- /dev/null
+++ b/src/test/ui/impl-trait/in-trait/deep-match-works.rs
@@ -0,0 +1,16 @@
+// check-pass
+
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+struct Wrapper(T);
+
+trait Foo {
+    fn bar() -> Wrapper;
+}
+
+impl Foo for () {
+    fn bar() -> Wrapper { Wrapper(0) }
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/in-trait/deep-match.rs b/src/test/ui/impl-trait/in-trait/deep-match.rs
new file mode 100644
index 000000000000..5a220bc3f198
--- /dev/null
+++ b/src/test/ui/impl-trait/in-trait/deep-match.rs
@@ -0,0 +1,15 @@
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+struct Wrapper(T);
+
+trait Foo {
+    fn bar() -> Wrapper;
+}
+
+impl Foo for () {
+    fn bar() -> i32 { 0 }
+    //~^ ERROR method `bar` has an incompatible type for trait
+}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/in-trait/deep-match.stderr b/src/test/ui/impl-trait/in-trait/deep-match.stderr
new file mode 100644
index 000000000000..af449869cb35
--- /dev/null
+++ b/src/test/ui/impl-trait/in-trait/deep-match.stderr
@@ -0,0 +1,20 @@
+error[E0053]: method `bar` has an incompatible type for trait
+  --> $DIR/deep-match.rs:11:17
+   |
+LL |     fn bar() -> i32 { 0 }
+   |                 ^^^
+   |                 |
+   |                 expected struct `Wrapper`, found `i32`
+   |                 help: change the output type to match the trait: `Wrapper<_>`
+   |
+note: type in trait
+  --> $DIR/deep-match.rs:7:17
+   |
+LL |     fn bar() -> Wrapper;
+   |                 ^^^^^^^^^^^^^^^^^^^
+   = note: expected fn pointer `fn() -> Wrapper<_>`
+              found fn pointer `fn() -> i32`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0053`.
diff --git a/src/test/ui/impl-trait/in-trait/nested-rpitit.rs b/src/test/ui/impl-trait/in-trait/nested-rpitit.rs
new file mode 100644
index 000000000000..65285e3a3cca
--- /dev/null
+++ b/src/test/ui/impl-trait/in-trait/nested-rpitit.rs
@@ -0,0 +1,32 @@
+// check-pass
+
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+use std::fmt::Display;
+use std::ops::Deref;
+
+trait Foo {
+    fn bar(self) -> impl Deref;
+}
+
+struct A;
+
+impl Foo for A {
+    fn bar(self) -> &'static str {
+        "Hello, world"
+    }
+}
+
+struct B;
+
+impl Foo for B {
+    fn bar(self) -> Box {
+        Box::new(42)
+    }
+}
+
+fn main() {
+    println!("Message for you: {:?}", &*A.bar());
+    println!("Another for you: {:?}", &*B.bar());
+}

From 05812df603ab5940c1dffe6514b25c665dccfcf1 Mon Sep 17 00:00:00 2001
From: Camille GILLOT 
Date: Tue, 6 Sep 2022 17:37:00 +0200
Subject: [PATCH 4374/5092] Handle generic parameters.

---
 compiler/rustc_ast_lowering/src/lib.rs        | 120 ++++++------------
 .../src/diagnostics/region_name.rs            |   2 +-
 compiler/rustc_hir/src/hir.rs                 |  19 +--
 compiler/rustc_hir/src/intravisit.rs          |   9 +-
 compiler/rustc_hir/src/target.rs              |   9 +-
 compiler/rustc_hir_pretty/src/lib.rs          |   4 -
 .../nice_region_error/static_impl_trait.rs    |   2 +-
 compiler/rustc_metadata/src/rmeta/encoder.rs  |   3 -
 compiler/rustc_middle/src/hir/map/mod.rs      |  18 ++-
 compiler/rustc_middle/src/ty/diagnostics.rs   |   2 +-
 compiler/rustc_passes/src/dead.rs             |   2 +-
 compiler/rustc_passes/src/reachable.rs        |   1 -
 compiler/rustc_privacy/src/lib.rs             |  11 +-
 compiler/rustc_resolve/src/late/lifetimes.rs  |   6 +-
 .../rustc_save_analysis/src/dump_visitor.rs   |   2 +-
 compiler/rustc_save_analysis/src/sig.rs       |  15 ++-
 .../src/traits/project.rs                     |   2 +-
 compiler/rustc_typeck/src/astconv/mod.rs      |  13 +-
 .../rustc_typeck/src/check/compare_method.rs  |  27 +++-
 compiler/rustc_typeck/src/collect.rs          |  25 ++--
 .../rustc_typeck/src/collect/item_bounds.rs   |  41 ++----
 compiler/rustc_typeck/src/collect/type_of.rs  |  11 +-
 src/librustdoc/clean/mod.rs                   |  12 +-
 src/librustdoc/visit_ast.rs                   |   1 -
 .../ui/impl-trait/in-trait/opaque-in-impl.rs  |  38 +++++-
 25 files changed, 171 insertions(+), 224 deletions(-)

diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index eecf01c92fbd..1a987c6e2d79 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -252,11 +252,10 @@ enum ImplTraitContext {
     ReturnPositionOpaqueTy {
         /// Origin: Either OpaqueTyOrigin::FnReturn or OpaqueTyOrigin::AsyncFn,
         origin: hir::OpaqueTyOrigin,
+        in_trait: bool,
     },
     /// Impl trait in type aliases.
     TypeAliasesOpaqueTy,
-    /// Return-position `impl Trait` in trait definition
-    InTrait,
     /// `impl Trait` is not accepted in this position.
     Disallowed(ImplTraitPosition),
 }
@@ -1343,9 +1342,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             TyKind::ImplTrait(def_node_id, ref bounds) => {
                 let span = t.span;
                 match itctx {
-                    ImplTraitContext::ReturnPositionOpaqueTy { origin } => {
-                        self.lower_opaque_impl_trait(span, *origin, def_node_id, bounds, itctx)
-                    }
+                    ImplTraitContext::ReturnPositionOpaqueTy { origin, in_trait } => self
+                        .lower_opaque_impl_trait(
+                            span,
+                            *origin,
+                            def_node_id,
+                            bounds,
+                            *in_trait,
+                            itctx,
+                        ),
                     ImplTraitContext::TypeAliasesOpaqueTy => {
                         let mut nested_itctx = ImplTraitContext::TypeAliasesOpaqueTy;
                         self.lower_opaque_impl_trait(
@@ -1353,14 +1358,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                             hir::OpaqueTyOrigin::TyAlias,
                             def_node_id,
                             bounds,
-                            &mut nested_itctx,
+                            false,
+                            nested_itctx,
                         )
                     }
-                    ImplTraitContext::InTrait => {
-                        self.lower_impl_trait_in_trait(span, def_node_id, |lctx| {
-                            lctx.lower_param_bounds(bounds, ImplTraitContext::InTrait)
-                        })
-                    }
                     ImplTraitContext::Universal => {
                         let span = t.span;
                         let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span);
@@ -1430,6 +1431,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         origin: hir::OpaqueTyOrigin,
         opaque_ty_node_id: NodeId,
         bounds: &GenericBounds,
+        in_trait: bool,
         itctx: &mut ImplTraitContext,
     ) -> hir::TyKind<'hir> {
         // Make sure we know that some funky desugaring has been going on here.
@@ -1518,6 +1520,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     }),
                     bounds: hir_bounds,
                     origin,
+                    in_trait,
                 };
                 debug!(?opaque_ty_item);
 
@@ -1544,30 +1547,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         debug!(?lifetimes);
 
         // `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
-        hir::TyKind::OpaqueDef(hir::ItemId { def_id: opaque_ty_def_id }, lifetimes)
-    }
-
-    #[instrument(level = "debug", skip(self, lower_bounds))]
-    fn lower_impl_trait_in_trait(
-        &mut self,
-        span: Span,
-        opaque_ty_node_id: NodeId,
-        lower_bounds: impl FnOnce(&mut Self) -> hir::GenericBounds<'hir>,
-    ) -> hir::TyKind<'hir> {
-        let opaque_ty_def_id = self.local_def_id(opaque_ty_node_id);
-        self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
-            let hir_bounds = lower_bounds(lctx);
-            let rpitit_placeholder = hir::ImplTraitPlaceholder { bounds: hir_bounds };
-            let rpitit_item = hir::Item {
-                def_id: opaque_ty_def_id,
-                ident: Ident::empty(),
-                kind: hir::ItemKind::ImplTraitPlaceholder(rpitit_placeholder),
-                span: lctx.lower_span(span),
-                vis_span: lctx.lower_span(span.shrink_to_lo()),
-            };
-            hir::OwnerNode::Item(lctx.arena.alloc(rpitit_item))
-        });
-        hir::TyKind::ImplTraitInTrait(hir::ItemId { def_id: opaque_ty_def_id })
+        hir::TyKind::OpaqueDef(hir::ItemId { def_id: opaque_ty_def_id }, lifetimes, in_trait)
     }
 
     /// Registers a new opaque type with the proper `NodeId`s and
@@ -1728,30 +1708,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                             )
                             .emit();
                     }
-                    self.lower_async_fn_ret_ty_in_trait(
+                    self.lower_async_fn_ret_ty(
                         &decl.output,
                         fn_node_id.expect("`make_ret_async` but no `fn_def_id`"),
                         ret_id,
+                        true,
                     )
                 }
                 _ => {
                     if !kind.impl_trait_return_allowed(self.tcx) {
-                        if kind == FnDeclKind::Impl {
-                            self.tcx
-                                .sess
-                                .create_feature_err(
-                                    TraitFnAsync { fn_span, span },
-                                    sym::return_position_impl_trait_in_trait,
-                                )
-                                .emit();
-                        } else {
-                            self.tcx.sess.emit_err(TraitFnAsync { fn_span, span });
-                        }
+                        self.tcx
+                            .sess
+                            .create_feature_err(
+                                TraitFnAsync { fn_span, span },
+                                sym::return_position_impl_trait_in_trait,
+                            )
+                            .emit();
                     }
                     self.lower_async_fn_ret_ty(
                         &decl.output,
                         fn_node_id.expect("`make_ret_async` but no `fn_def_id`"),
                         ret_id,
+                        false,
                     )
                 }
             }
@@ -1763,10 +1741,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                             let fn_def_id = self.local_def_id(fn_node_id);
                             ImplTraitContext::ReturnPositionOpaqueTy {
                                 origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
+                                in_trait: false,
                             }
                         }
-                        Some(_) if kind.impl_trait_in_trait_allowed(self.tcx) => {
-                            ImplTraitContext::InTrait
+                        Some(fn_node_id) if kind.impl_trait_in_trait_allowed(self.tcx) => {
+                            let fn_def_id = self.local_def_id(fn_node_id);
+                            ImplTraitContext::ReturnPositionOpaqueTy {
+                                origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
+                                in_trait: true,
+                            }
                         }
                         _ => ImplTraitContext::Disallowed(match kind {
                             FnDeclKind::Fn | FnDeclKind::Inherent => {
@@ -1829,6 +1812,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         output: &FnRetTy,
         fn_node_id: NodeId,
         opaque_ty_node_id: NodeId,
+        in_trait: bool,
     ) -> hir::FnRetTy<'hir> {
         let span = output.span();
 
@@ -1960,6 +1944,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     span,
                     ImplTraitContext::ReturnPositionOpaqueTy {
                         origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
+                        in_trait,
                     },
                 );
 
@@ -1999,6 +1984,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     }),
                     bounds: arena_vec![this; future_bound],
                     origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
+                    in_trait,
                 };
 
                 trace!("exist ty from async fn def id: {:#?}", opaque_ty_def_id);
@@ -2043,41 +2029,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         // Foo = impl Trait` is, internally, created as a child of the
         // async fn, so the *type parameters* are inherited.  It's
         // only the lifetime parameters that we must supply.
-        let opaque_ty_ref =
-            hir::TyKind::OpaqueDef(hir::ItemId { def_id: opaque_ty_def_id }, generic_args);
+        let opaque_ty_ref = hir::TyKind::OpaqueDef(
+            hir::ItemId { def_id: opaque_ty_def_id },
+            generic_args,
+            in_trait,
+        );
         let opaque_ty = self.ty(opaque_ty_span, opaque_ty_ref);
         hir::FnRetTy::Return(self.arena.alloc(opaque_ty))
     }
 
-    // Transforms `-> T` for `async fn` into `-> OpaqueTy { .. }`
-    // combined with the following definition of `OpaqueTy`:
-    //
-    //     type OpaqueTy = impl Future;
-    //
-    // `output`: unlowered output type (`T` in `-> T`)
-    // `fn_def_id`: `DefId` of the parent function (used to create child impl trait definition)
-    // `opaque_ty_node_id`: `NodeId` of the opaque `impl Trait` type that should be created
-    #[instrument(level = "debug", skip(self))]
-    fn lower_async_fn_ret_ty_in_trait(
-        &mut self,
-        output: &FnRetTy,
-        fn_node_id: NodeId,
-        opaque_ty_node_id: NodeId,
-    ) -> hir::FnRetTy<'hir> {
-        let kind = self.lower_impl_trait_in_trait(output.span(), opaque_ty_node_id, |lctx| {
-            let bound = lctx.lower_async_fn_output_type_to_future_bound(
-                output,
-                output.span(),
-                ImplTraitContext::InTrait,
-            );
-            arena_vec![lctx; bound]
-        });
-
-        let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, output.span(), None);
-        let opaque_ty = self.ty(opaque_ty_span, kind);
-        hir::FnRetTy::Return(self.arena.alloc(opaque_ty))
-    }
-
     /// Transforms `-> T` into `Future`.
     fn lower_async_fn_output_type_to_future_bound(
         &mut self,
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 75fde53b6cde..0707ff5ed02a 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -772,7 +772,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
     fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
         let hir = self.infcx.tcx.hir();
 
-        let hir::TyKind::OpaqueDef(id, _) = hir_ty.kind else {
+        let hir::TyKind::OpaqueDef(id, _, _) = hir_ty.kind else {
             span_bug!(
                 hir_ty.span,
                 "lowered return type of async fn is not OpaqueDef: {:?}",
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 8b1ebe34cb00..a57fdc3bfb12 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2505,6 +2505,7 @@ pub struct OpaqueTy<'hir> {
     pub generics: &'hir Generics<'hir>,
     pub bounds: GenericBounds<'hir>,
     pub origin: OpaqueTyOrigin,
+    pub in_trait: bool,
 }
 
 /// From whence the opaque type came.
@@ -2518,12 +2519,6 @@ pub enum OpaqueTyOrigin {
     TyAlias,
 }
 
-/// Placeholder representation of an `impl Trait` in a trait. Since this never gets lowered into a `ty::Opaque` of its own, we just keep this as
-#[derive(Debug, HashStable_Generic)]
-pub struct ImplTraitPlaceholder<'hir> {
-    pub bounds: GenericBounds<'hir>,
-}
-
 /// The various kinds of types recognized by the compiler.
 #[derive(Debug, HashStable_Generic)]
 pub enum TyKind<'hir> {
@@ -2550,12 +2545,9 @@ pub enum TyKind<'hir> {
     ///
     /// The generic argument list contains the lifetimes (and in the future
     /// possibly parameters) that are actually bound on the `impl Trait`.
-    OpaqueDef(ItemId, &'hir [GenericArg<'hir>]),
-    /// A type that represents an `impl Trait` in a trait function. This is
-    /// not an opaque type, since it acts more like an associated type than
-    /// an opaque, and since it needs no generics since it inherits those
-    /// from the item's parent.
-    ImplTraitInTrait(ItemId),
+    ///
+    /// The last parameter specifies whether this opaque appears in a trait definition.
+    OpaqueDef(ItemId, &'hir [GenericArg<'hir>], bool),
     /// A trait object type `Bound1 + Bound2 + Bound3`
     /// where `Bound` is a trait or a lifetime.
     TraitObject(&'hir [PolyTraitRef<'hir>], &'hir Lifetime, TraitObjectSyntax),
@@ -3011,8 +3003,6 @@ pub enum ItemKind<'hir> {
     TyAlias(&'hir Ty<'hir>, &'hir Generics<'hir>),
     /// An opaque `impl Trait` type alias, e.g., `type Foo = impl Bar;`.
     OpaqueTy(OpaqueTy<'hir>),
-    /// An `impl Trait` in a trait
-    ImplTraitPlaceholder(ImplTraitPlaceholder<'hir>),
     /// An enum definition, e.g., `enum Foo {C, D}`.
     Enum(EnumDef<'hir>, &'hir Generics<'hir>),
     /// A struct definition, e.g., `struct Foo {x: A}`.
@@ -3081,7 +3071,6 @@ impl ItemKind<'_> {
             ItemKind::Trait(..) => "trait",
             ItemKind::TraitAlias(..) => "trait alias",
             ItemKind::Impl(..) => "implementation",
-            ItemKind::ImplTraitPlaceholder(..) => "opaque type in trait",
         }
     }
 }
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 3e9ab10b1f7e..bf4ab06638bb 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -562,10 +562,6 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
             walk_generics(visitor, generics);
             walk_list!(visitor, visit_param_bound, bounds);
         }
-        ItemKind::ImplTraitPlaceholder(ImplTraitPlaceholder { bounds }) => {
-            visitor.visit_id(item.hir_id());
-            walk_list!(visitor, visit_param_bound, bounds);
-        }
         ItemKind::Enum(ref enum_definition, ref generics) => {
             visitor.visit_generics(generics);
             // `visit_enum_def()` takes care of visiting the `Item`'s `HirId`.
@@ -674,13 +670,10 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) {
         TyKind::Path(ref qpath) => {
             visitor.visit_qpath(qpath, typ.hir_id, typ.span);
         }
-        TyKind::OpaqueDef(item_id, lifetimes) => {
+        TyKind::OpaqueDef(item_id, lifetimes, _in_trait) => {
             visitor.visit_nested_item(item_id);
             walk_list!(visitor, visit_generic_arg, lifetimes);
         }
-        TyKind::ImplTraitInTrait(item_id) => {
-            visitor.visit_nested_item(item_id);
-        }
         TyKind::Array(ref ty, ref length) => {
             visitor.visit_ty(ty);
             visitor.visit_array_length(length)
diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs
index 0e9b05729d29..5917d5e346e3 100644
--- a/compiler/rustc_hir/src/target.rs
+++ b/compiler/rustc_hir/src/target.rs
@@ -80,8 +80,13 @@ impl Target {
             ItemKind::ForeignMod { .. } => Target::ForeignMod,
             ItemKind::GlobalAsm(..) => Target::GlobalAsm,
             ItemKind::TyAlias(..) => Target::TyAlias,
-            ItemKind::OpaqueTy(..) => Target::OpaqueTy,
-            ItemKind::ImplTraitPlaceholder(..) => Target::ImplTraitPlaceholder,
+            ItemKind::OpaqueTy(ref opaque) => {
+                if opaque.in_trait {
+                    Target::ImplTraitPlaceholder
+                } else {
+                    Target::OpaqueTy
+                }
+            }
             ItemKind::Enum(..) => Target::Enum,
             ItemKind::Struct(..) => Target::Struct,
             ItemKind::Union(..) => Target::Union,
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 01f445c8a52d..35a58296e370 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -327,7 +327,6 @@ impl<'a> State<'a> {
                 self.print_ty_fn(f.abi, f.unsafety, f.decl, None, f.generic_params, f.param_names);
             }
             hir::TyKind::OpaqueDef(..) => self.word("/*impl Trait*/"),
-            hir::TyKind::ImplTraitInTrait(..) => self.word("/*impl Trait*/"),
             hir::TyKind::Path(ref qpath) => self.print_qpath(qpath, false),
             hir::TyKind::TraitObject(bounds, ref lifetime, syntax) => {
                 if syntax == ast::TraitObjectSyntax::Dyn {
@@ -609,9 +608,6 @@ impl<'a> State<'a> {
                     state.print_bounds("= impl", real_bounds);
                 });
             }
-            hir::ItemKind::ImplTraitPlaceholder(..) => {
-                unreachable!("FIXME(RPITIT): I don't think this ever gets called here...");
-            }
             hir::ItemKind::Enum(ref enum_definition, params) => {
                 self.print_enum_def(enum_definition, params, item.ident.name, item.span);
             }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index f804569b0747..b115ac8b3df9 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -300,7 +300,7 @@ pub fn suggest_new_region_bound(
             continue;
         }
         match fn_return.kind {
-            TyKind::OpaqueDef(item_id, _) => {
+            TyKind::OpaqueDef(item_id, _, _) => {
                 let item = tcx.hir().item(item_id);
                 let ItemKind::OpaqueTy(opaque) = &item.kind else {
                     return;
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index d45d814c3b0f..f967ac9a4dc3 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1500,9 +1500,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             hir::ItemKind::OpaqueTy(..) => {
                 self.encode_explicit_item_bounds(def_id);
             }
-            hir::ItemKind::ImplTraitPlaceholder(..) => {
-                self.encode_explicit_item_bounds(def_id);
-            }
             hir::ItemKind::Enum(..) => {
                 let adt_def = self.tcx.adt_def(def_id);
                 record!(self.tables.repr_options[def_id] <- adt_def.repr());
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 1a0bea68293e..5a65ec9a4765 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -212,8 +212,13 @@ impl<'hir> Map<'hir> {
                 ItemKind::Fn(..) => DefKind::Fn,
                 ItemKind::Macro(_, macro_kind) => DefKind::Macro(macro_kind),
                 ItemKind::Mod(..) => DefKind::Mod,
-                ItemKind::OpaqueTy(..) => DefKind::OpaqueTy,
-                ItemKind::ImplTraitPlaceholder(..) => DefKind::ImplTraitPlaceholder,
+                ItemKind::OpaqueTy(ref opaque) => {
+                    if opaque.in_trait {
+                        DefKind::ImplTraitPlaceholder
+                    } else {
+                        DefKind::OpaqueTy
+                    }
+                }
                 ItemKind::TyAlias(..) => DefKind::TyAlias,
                 ItemKind::Enum(..) => DefKind::Enum,
                 ItemKind::Struct(..) => DefKind::Struct,
@@ -1188,8 +1193,13 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
                 ItemKind::ForeignMod { .. } => "foreign mod",
                 ItemKind::GlobalAsm(..) => "global asm",
                 ItemKind::TyAlias(..) => "ty",
-                ItemKind::OpaqueTy(..) => "opaque type",
-                ItemKind::ImplTraitPlaceholder(..) => "opaque type in trait",
+                ItemKind::OpaqueTy(ref opaque) => {
+                    if opaque.in_trait {
+                        "opaque type in trait"
+                    } else {
+                        "opaque type"
+                    }
+                }
                 ItemKind::Enum(..) => "enum",
                 ItemKind::Struct(..) => "struct",
                 ItemKind::Union(..) => "union",
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index e4ad96b659b0..648f5f7161fa 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -408,7 +408,7 @@ impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
             ) => {
                 self.0.push(ty);
             }
-            hir::TyKind::OpaqueDef(item_id, _) => {
+            hir::TyKind::OpaqueDef(item_id, _, _) => {
                 self.0.push(ty);
                 let item = self.1.item(item_id);
                 hir::intravisit::walk_item(self, item);
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index a7ce0f312af8..f141d7beeb92 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -447,7 +447,7 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
     }
 
     fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
-        if let TyKind::OpaqueDef(item_id, _) = ty.kind {
+        if let TyKind::OpaqueDef(item_id, _, _) = ty.kind {
             let item = self.tcx.hir().item(item_id);
             intravisit::walk_item(self, item);
         }
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index 74c5ccf9cd20..f7e3fac6b2e2 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -235,7 +235,6 @@ impl<'tcx> ReachableContext<'tcx> {
                     hir::ItemKind::ExternCrate(_)
                     | hir::ItemKind::Use(..)
                     | hir::ItemKind::OpaqueTy(..)
-                    | hir::ItemKind::ImplTraitPlaceholder(..)
                     | hir::ItemKind::TyAlias(..)
                     | hir::ItemKind::Macro(..)
                     | hir::ItemKind::Mod(..)
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 3657fb213404..afd423dc5fa1 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -686,7 +686,6 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
             }
 
             hir::ItemKind::OpaqueTy(..)
-            | hir::ItemKind::ImplTraitPlaceholder(..)
             | hir::ItemKind::Use(..)
             | hir::ItemKind::Static(..)
             | hir::ItemKind::Const(..)
@@ -708,12 +707,12 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
             hir::ItemKind::Use(..) => {}
             // The interface is empty.
             hir::ItemKind::GlobalAsm(..) => {}
-            hir::ItemKind::OpaqueTy(..) => {
+            hir::ItemKind::OpaqueTy(ref opaque) => {
                 // HACK(jynelson): trying to infer the type of `impl trait` breaks `async-std` (and `pub async fn` in general)
                 // Since rustdoc never needs to do codegen and doesn't care about link-time reachability,
                 // mark this as unreachable.
                 // See https://github.com/rust-lang/rust/issues/75100
-                if !self.tcx.sess.opts.actually_rustdoc {
+                if !opaque.in_trait && !self.tcx.sess.opts.actually_rustdoc {
                     // FIXME: This is some serious pessimization intended to workaround deficiencies
                     // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time
                     // reachable if they are returned via `impl Trait`, even from private functions.
@@ -722,9 +721,6 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
                     self.reach(item.def_id, exist_level).generics().predicates().ty();
                 }
             }
-            hir::ItemKind::ImplTraitPlaceholder(..) => {
-                // FIXME(RPITIT): Do we need to do anything here?
-            }
             // Visit everything.
             hir::ItemKind::Const(..)
             | hir::ItemKind::Static(..)
@@ -2039,8 +2035,7 @@ fn local_visibility(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Visibility {
                 //   query failing on some items, we provide it for opaque types as well.
                 | Node::Item(hir::Item {
                     kind: hir::ItemKind::Use(_, hir::UseKind::ListStem)
-                        | hir::ItemKind::OpaqueTy(..)
-                        | hir::ItemKind::ImplTraitPlaceholder(..),
+                        | hir::ItemKind::OpaqueTy(..),
                     ..
                 }) => ty::Visibility::Restricted(tcx.parent_module(hir_id)),
                 // Visibilities of trait impl items are inherited from their traits
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index e9e4f8fc483c..6ff56f9a8911 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -596,10 +596,6 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     }
                 }
             }
-            hir::ItemKind::ImplTraitPlaceholder(..) => {
-                // FIXME(RPITIT): We don't need to do anything special here, right?
-                intravisit::walk_item(self, item);
-            }
             hir::ItemKind::TyAlias(_, ref generics)
             | hir::ItemKind::Enum(_, ref generics)
             | hir::ItemKind::Struct(_, ref generics)
@@ -719,7 +715,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 };
                 self.with(scope, |this| this.visit_ty(&mt.ty));
             }
-            hir::TyKind::OpaqueDef(item_id, lifetimes) => {
+            hir::TyKind::OpaqueDef(item_id, lifetimes, _in_trait) => {
                 // Resolve the lifetimes in the bounds to the lifetime defs in the generics.
                 // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to
                 // `type MyAnonTy<'b> = impl MyTrait<'b>;`
diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs
index 6658892881d4..94f222251d3d 100644
--- a/compiler/rustc_save_analysis/src/dump_visitor.rs
+++ b/compiler/rustc_save_analysis/src/dump_visitor.rs
@@ -1321,7 +1321,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
                         }),
                 }
             }
-            hir::TyKind::OpaqueDef(item_id, _) => {
+            hir::TyKind::OpaqueDef(item_id, _, _) => {
                 let item = self.tcx.hir().item(item_id);
                 self.nest_typeck_results(item_id.def_id, |v| v.visit_item(item));
             }
diff --git a/compiler/rustc_save_analysis/src/sig.rs b/compiler/rustc_save_analysis/src/sig.rs
index ea9c82b3597d..bae1828cd182 100644
--- a/compiler/rustc_save_analysis/src/sig.rs
+++ b/compiler/rustc_save_analysis/src/sig.rs
@@ -316,11 +316,7 @@ impl<'hir> Sig for hir::Ty<'hir> {
                 let text = format!("[{}; {}]", nested_ty.text, expr);
                 Ok(replace_text(nested_ty, text))
             }
-            hir::TyKind::OpaqueDef(item_id, _) => {
-                let item = scx.tcx.hir().item(item_id);
-                item.make(offset, Some(item_id.hir_id()), scx)
-            }
-            hir::TyKind::ImplTraitInTrait(item_id) => {
+            hir::TyKind::OpaqueDef(item_id, _, _) => {
                 let item = scx.tcx.hir().item(item_id);
                 item.make(offset, Some(item_id.hir_id()), scx)
             }
@@ -565,8 +561,13 @@ impl<'hir> Sig for hir::Item<'hir> {
             hir::ItemKind::ForeignMod { .. } => Err("extern mod"),
             hir::ItemKind::GlobalAsm(_) => Err("global asm"),
             hir::ItemKind::ExternCrate(_) => Err("extern crate"),
-            hir::ItemKind::OpaqueTy(..) => Err("opaque type"),
-            hir::ItemKind::ImplTraitPlaceholder(..) => Err("opaque type in trait"),
+            hir::ItemKind::OpaqueTy(ref opaque) => {
+                if opaque.in_trait {
+                    Err("opaque type in trait")
+                } else {
+                    Err("opaque type")
+                }
+            }
             // FIXME should implement this (e.g., pub use).
             hir::ItemKind::Use(..) => Err("import"),
         }
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 7253ab21b3a0..8a65262a0072 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -2165,7 +2165,7 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
     let tcx = selcx.tcx();
     let mut obligations = data.nested;
 
-    let trait_fn_def_id = tcx.parent(obligation.predicate.item_def_id);
+    let trait_fn_def_id = tcx.impl_trait_in_trait_parent(obligation.predicate.item_def_id);
     let Ok(leaf_def) = assoc_def(selcx, data.impl_def_id, trait_fn_def_id) else {
         return Progress { term: tcx.ty_error().into(), obligations };
     };
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 6eec2c57639c..d9789d5aaf03 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -2360,7 +2360,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
         let span = path.span;
         match path.res {
-            Res::Def(DefKind::OpaqueTy, did) => {
+            Res::Def(DefKind::OpaqueTy | DefKind::ImplTraitPlaceholder, did) => {
                 // Check for desugared `impl Trait`.
                 assert!(ty::is_impl_trait_defn(tcx, did).is_none());
                 let item_segment = path.segments.split_last().unwrap();
@@ -2627,21 +2627,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 let opt_self_ty = maybe_qself.as_ref().map(|qself| self.ast_ty_to_ty(qself));
                 self.res_to_ty(opt_self_ty, path, false)
             }
-            hir::TyKind::OpaqueDef(item_id, lifetimes) => {
+            hir::TyKind::OpaqueDef(item_id, lifetimes, in_trait) => {
                 let opaque_ty = tcx.hir().item(item_id);
                 let def_id = item_id.def_id.to_def_id();
 
                 match opaque_ty.kind {
                     hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
-                        self.impl_trait_ty_to_ty(def_id, lifetimes, origin)
+                        self.impl_trait_ty_to_ty(def_id, lifetimes, origin, in_trait)
                     }
                     ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
                 }
             }
-            hir::TyKind::ImplTraitInTrait(item_id) => {
-                let def_id = item_id.def_id.to_def_id();
-                tcx.mk_projection(def_id, InternalSubsts::identity_for_item(tcx, def_id))
-            }
             hir::TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => {
                 debug!(?qself, ?segment);
                 let ty = self.ast_ty_to_ty_inner(qself, false, true);
@@ -2707,6 +2703,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         def_id: DefId,
         lifetimes: &[hir::GenericArg<'_>],
         origin: OpaqueTyOrigin,
+        in_trait: bool,
     ) -> Ty<'tcx> {
         debug!("impl_trait_ty_to_ty(def_id={:?}, lifetimes={:?})", def_id, lifetimes);
         let tcx = self.tcx();
@@ -2750,7 +2747,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         });
         debug!("impl_trait_ty_to_ty: substs={:?}", substs);
 
-        tcx.mk_opaque(def_id, substs)
+        if in_trait { tcx.mk_projection(def_id, substs) } else { tcx.mk_opaque(def_id, substs) }
     }
 
     pub fn ty_of_arg(&self, ty: &hir::Ty<'_>, expected_ty: Option>) -> Ty<'tcx> {
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index da45469863e4..a6c8dbb2555d 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -423,9 +423,28 @@ pub(super) fn compare_predicates_and_trait_impl_trait_tys<'tcx>(
         );
 
         let mut collected_tys = FxHashMap::default();
-        for (def_id, ty) in collector.types {
+        for (def_id, (ty, substs)) in collector.types {
             match infcx.fully_resolve(ty) {
                 Ok(ty) => {
+                    // `ty` contains free regions that we created earlier while liberating the
+                    // trait fn signature.  However, projection normalization expects `ty` to
+                    // contains `def_id`'s early-bound regions.
+                    let id_substs = InternalSubsts::identity_for_item(tcx, def_id);
+                    debug!(?id_substs, ?substs);
+                    let map: FxHashMap, ty::GenericArg<'tcx>> = substs
+                        .iter()
+                        .enumerate()
+                        .map(|(index, arg)| (arg, id_substs[index]))
+                        .collect();
+                    debug!(?map);
+
+                    let ty = tcx.fold_regions(ty, |region, _| {
+                        if let ty::ReFree(_) = region.kind() {
+                            map[®ion.into()].expect_region()
+                        } else {
+                            region
+                        }
+                    });
                     collected_tys.insert(def_id, ty);
                 }
                 Err(err) => {
@@ -444,7 +463,7 @@ pub(super) fn compare_predicates_and_trait_impl_trait_tys<'tcx>(
 
 struct ImplTraitInTraitCollector<'a, 'tcx> {
     ocx: &'a ObligationCtxt<'a, 'tcx>,
-    types: FxHashMap>,
+    types: FxHashMap, ty::SubstsRef<'tcx>)>,
     span: Span,
     param_env: ty::ParamEnv<'tcx>,
     body_id: hir::HirId,
@@ -470,7 +489,7 @@ impl<'tcx> TypeFolder<'tcx> for ImplTraitInTraitCollector<'_, 'tcx> {
         if let ty::Projection(proj) = ty.kind()
             && self.tcx().def_kind(proj.item_def_id) == DefKind::ImplTraitPlaceholder
         {
-            if let Some(ty) = self.types.get(&proj.item_def_id) {
+            if let Some((ty, _)) = self.types.get(&proj.item_def_id) {
                 return *ty;
             }
             //FIXME(RPITIT): Deny nested RPITIT in substs too
@@ -482,7 +501,7 @@ impl<'tcx> TypeFolder<'tcx> for ImplTraitInTraitCollector<'_, 'tcx> {
                 span: self.span,
                 kind: TypeVariableOriginKind::MiscVariable,
             });
-            self.types.insert(proj.item_def_id, infer_ty);
+            self.types.insert(proj.item_def_id, (infer_ty, proj.substs));
             // Recurse into bounds
             for pred in self.tcx().bound_explicit_item_bounds(proj.item_def_id).transpose_iter() {
                 let pred_span = pred.0.1;
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index e5e82a4ff6b0..ceb5684fdf0a 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -815,11 +815,6 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
             tcx.ensure().predicates_of(def_id);
             tcx.ensure().explicit_item_bounds(def_id);
         }
-        hir::ItemKind::ImplTraitPlaceholder(..) => {
-            tcx.ensure().generics_of(def_id);
-            tcx.ensure().predicates_of(def_id);
-            tcx.ensure().explicit_item_bounds(def_id);
-        }
         hir::ItemKind::TyAlias(..)
         | hir::ItemKind::Static(..)
         | hir::ItemKind::Const(..)
@@ -1590,8 +1585,16 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
             ItemKind::OpaqueTy(hir::OpaqueTy {
                 origin:
                     hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
+                in_trait,
                 ..
-            }) => Some(fn_def_id.to_def_id()),
+            }) => {
+                if in_trait {
+                    assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn))
+                } else {
+                    assert!(matches!(tcx.def_kind(fn_def_id), DefKind::AssocFn | DefKind::Fn))
+                }
+                Some(fn_def_id.to_def_id())
+            }
             ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
                 let parent_id = tcx.hir().get_parent_item(hir_id);
                 assert_ne!(parent_id, CRATE_DEF_ID);
@@ -1600,14 +1603,6 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
                 // inherit the generics of the item.
                 Some(parent_id.to_def_id())
             }
-            ItemKind::ImplTraitPlaceholder(_) => {
-                let parent_id = tcx.hir().get_parent_item(hir_id).to_def_id();
-                assert!(matches!(
-                    tcx.def_kind(parent_id),
-                    DefKind::AssocFn | DefKind::ImplTraitPlaceholder
-                ));
-                Some(parent_id)
-            }
             _ => None,
         },
         _ => None,
@@ -1800,7 +1795,7 @@ fn is_suggestable_infer_ty(ty: &hir::Ty<'_>) -> bool {
         }
         Tup(tys) => tys.iter().any(is_suggestable_infer_ty),
         Ptr(mut_ty) | Rptr(_, mut_ty) => is_suggestable_infer_ty(mut_ty.ty),
-        OpaqueDef(_, generic_args) => are_suggestable_generic_args(generic_args),
+        OpaqueDef(_, generic_args, _) => are_suggestable_generic_args(generic_args),
         Path(hir::QPath::TypeRelative(ty, segment)) => {
             is_suggestable_infer_ty(ty) || are_suggestable_generic_args(segment.args().args)
         }
diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_typeck/src/collect/item_bounds.rs
index fe8d8f54f047..0d34a8bfee33 100644
--- a/compiler/rustc_typeck/src/collect/item_bounds.rs
+++ b/compiler/rustc_typeck/src/collect/item_bounds.rs
@@ -59,10 +59,15 @@ fn opaque_type_bounds<'tcx>(
     opaque_def_id: DefId,
     ast_bounds: &'tcx [hir::GenericBound<'tcx>],
     span: Span,
+    in_trait: bool,
 ) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
     ty::print::with_no_queries!({
-        let item_ty =
-            tcx.mk_opaque(opaque_def_id, InternalSubsts::identity_for_item(tcx, opaque_def_id));
+        let substs = InternalSubsts::identity_for_item(tcx, opaque_def_id);
+        let item_ty = if in_trait {
+            tcx.mk_projection(opaque_def_id, substs)
+        } else {
+            tcx.mk_opaque(opaque_def_id, substs)
+        };
 
         let icx = ItemCtxt::new(tcx, opaque_def_id);
         let mut bounds = >::compute_bounds(&icx, item_ty, ast_bounds);
@@ -74,29 +79,6 @@ fn opaque_type_bounds<'tcx>(
     })
 }
 
-/// Opaque types don't inherit bounds from their parent: for return position
-/// impl trait it isn't possible to write a suitable predicate on the
-/// containing function and for type-alias impl trait we don't have a backwards
-/// compatibility issue.
-fn impl_trait_in_trait_item_bounds<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    opaque_def_id: DefId,
-    ast_bounds: &'tcx [hir::GenericBound<'tcx>],
-    span: Span,
-) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
-    ty::print::with_no_queries!({
-        // FIXME(RPITIT): DRY-er code please
-        let item_ty =
-            tcx.mk_projection(opaque_def_id, InternalSubsts::identity_for_item(tcx, opaque_def_id));
-
-        let icx = ItemCtxt::new(tcx, opaque_def_id);
-        let mut bounds = >::compute_bounds(&icx, item_ty, ast_bounds);
-        // RPITITs are implicitly sized unless a `?Sized` bound is found
-        >::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span);
-        tcx.arena.alloc_from_iter(bounds.predicates(tcx, item_ty))
-    })
-}
-
 pub(super) fn explicit_item_bounds(
     tcx: TyCtxt<'_>,
     def_id: DefId,
@@ -109,15 +91,10 @@ pub(super) fn explicit_item_bounds(
             ..
         }) => associated_type_bounds(tcx, def_id, bounds, *span),
         hir::Node::Item(hir::Item {
-            kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, .. }),
+            kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, in_trait, .. }),
             span,
             ..
-        }) => opaque_type_bounds(tcx, def_id, bounds, *span),
-        hir::Node::Item(hir::Item {
-            kind: hir::ItemKind::ImplTraitPlaceholder(hir::ImplTraitPlaceholder { bounds }),
-            span,
-            ..
-        }) => impl_trait_in_trait_item_bounds(tcx, def_id, bounds, *span),
+        }) => opaque_type_bounds(tcx, def_id, bounds, *span, *in_trait),
         _ => bug!("item_bounds called on {:?}", def_id),
     }
 }
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs
index ded2ac1308e5..a26e26cb3899 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_typeck/src/collect/type_of.rs
@@ -333,11 +333,12 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                     find_opaque_ty_constraints_for_tait(tcx, def_id)
                 }
                 // Opaque types desugared from `impl Trait`.
-                ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner), .. }) => {
-                    find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
-                }
-                ItemKind::ImplTraitPlaceholder(..) => {
-                    span_bug!(item.span, "not yet implemented")
+                ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner), in_trait, .. }) => {
+                    if in_trait {
+                        span_bug!(item.span, "impl-trait in trait has no default")
+                    } else {
+                        find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
+                    }
                 }
                 ItemKind::Trait(..)
                 | ItemKind::TraitAlias(..)
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 03752c9b6dbb..08b696e65eb3 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1492,7 +1492,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
             Array(Box::new(clean_ty(ty, cx)), length)
         }
         TyKind::Tup(tys) => Tuple(tys.iter().map(|ty| clean_ty(ty, cx)).collect()),
-        TyKind::OpaqueDef(item_id, _) => {
+        TyKind::OpaqueDef(item_id, _, _) => {
             let item = cx.tcx.hir().item(item_id);
             if let hir::ItemKind::OpaqueTy(ref ty) = item.kind {
                 ImplTrait(ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect())
@@ -1500,16 +1500,6 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
                 unreachable!()
             }
         }
-        TyKind::ImplTraitInTrait(item_id) => {
-            let item = cx.tcx.hir().item(item_id);
-            if let hir::ItemKind::ImplTraitPlaceholder(hir::ImplTraitPlaceholder { bounds }) =
-                item.kind
-            {
-                ImplTrait(bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect())
-            } else {
-                unreachable!()
-            }
-        }
         TyKind::Path(_) => clean_qpath(ty, cx),
         TyKind::TraitObject(bounds, ref lifetime, _) => {
             let bounds = bounds.iter().map(|bound| clean_poly_trait_ref(bound, cx)).collect();
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 7fe391f420f6..ca7a20bf3688 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -362,7 +362,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             | hir::ItemKind::Union(..)
             | hir::ItemKind::TyAlias(..)
             | hir::ItemKind::OpaqueTy(..)
-            | hir::ItemKind::ImplTraitPlaceholder(..)
             | hir::ItemKind::Static(..)
             | hir::ItemKind::Trait(..)
             | hir::ItemKind::TraitAlias(..) => om.items.push((item, renamed)),
diff --git a/src/test/ui/impl-trait/in-trait/opaque-in-impl.rs b/src/test/ui/impl-trait/in-trait/opaque-in-impl.rs
index a777cbcd529a..2e06629699aa 100644
--- a/src/test/ui/impl-trait/in-trait/opaque-in-impl.rs
+++ b/src/test/ui/impl-trait/in-trait/opaque-in-impl.rs
@@ -3,18 +3,46 @@
 #![feature(return_position_impl_trait_in_trait)]
 #![allow(incomplete_features)]
 
-use std::fmt::Display;
+use std::fmt::Debug;
 
 trait Foo {
-    fn bar(&self) -> impl Display;
+    fn foo(&self) -> impl Debug;
 }
 
 impl Foo for () {
-    fn bar(&self) -> impl Display {
+    fn foo(&self) -> impl Debug {
         "Hello, world"
     }
 }
 
-fn main() {
-    println!("{}", ().bar());
+impl Foo for std::marker::PhantomData {
+    fn foo(&self) -> impl Debug {
+        T::default()
+    }
+}
+
+trait Bar {
+    fn bar(&self) -> impl Debug;
+}
+
+impl Bar for () {
+    fn bar(&self) -> impl Debug {
+        format!("Hello with generic {}", std::any::type_name::())
+    }
+}
+
+trait Baz {
+    fn baz(&self) -> impl Debug + '_;
+}
+
+impl Baz for String {
+    fn baz(&self) -> impl Debug + '_ {
+        (self,)
+    }
+}
+
+fn main() {
+    println!("{:?}", ().foo());
+    println!("{:?}", ().bar::());
+    println!("{:?}", "hi".to_string().baz());
 }

From 55df9201fe5d8d67102ea8a8b70415d0312ab813 Mon Sep 17 00:00:00 2001
From: Michael Goulet 
Date: Tue, 6 Sep 2022 17:16:08 +0000
Subject: [PATCH 4375/5092] Tweak feature error, add test

---
 compiler/rustc_ast_lowering/src/lib.rs        | 32 ++++++++++++++-----
 src/test/ui/async-await/async-trait-fn.stderr |  2 +-
 ...return_position_impl_trait_in_trait.stderr |  3 ++
 src/test/ui/impl-trait/in-trait/reveal.rs     | 18 +++++++++++
 src/test/ui/impl-trait/where-allowed.stderr   |  6 ++++
 5 files changed, 52 insertions(+), 9 deletions(-)
 create mode 100644 src/test/ui/impl-trait/in-trait/reveal.rs

diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 1a987c6e2d79..9b4ee9b5a657 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -312,7 +312,7 @@ impl std::fmt::Display for ImplTraitPosition {
     }
 }
 
-#[derive(Debug)]
+#[derive(Debug, PartialEq, Eq)]
 enum FnDeclKind {
     Fn,
     Inherent,
@@ -1373,6 +1373,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         }
                         path
                     }
+                    ImplTraitContext::Disallowed(
+                        position @ (ImplTraitPosition::TraitReturn | ImplTraitPosition::ImplReturn),
+                    ) => {
+                        self.tcx.sess.create_feature_err(
+                            MisplacedImplTrait {
+                                span: t.span,
+                                position: DiagnosticArgFromDisplay(&position),
+                            },
+                            sym::return_position_impl_trait_in_trait,
+                        ).emit();
+                        hir::TyKind::Err
+                    }
                     ImplTraitContext::Disallowed(position) => {
                         self.tcx.sess.emit_err(MisplacedImplTrait {
                             span: t.span,
@@ -1717,13 +1729,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 }
                 _ => {
                     if !kind.impl_trait_return_allowed(self.tcx) {
-                        self.tcx
-                            .sess
-                            .create_feature_err(
-                                TraitFnAsync { fn_span, span },
-                                sym::return_position_impl_trait_in_trait,
-                            )
-                            .emit();
+                        if kind == FnDeclKind::Impl {
+                            self.tcx
+                                .sess
+                                .create_feature_err(
+                                    TraitFnAsync { fn_span, span },
+                                    sym::return_position_impl_trait_in_trait,
+                                )
+                                .emit();
+                        } else {
+                            self.tcx.sess.emit_err(TraitFnAsync { fn_span, span });
+                        }
                     }
                     self.lower_async_fn_ret_ty(
                         &decl.output,
diff --git a/src/test/ui/async-await/async-trait-fn.stderr b/src/test/ui/async-await/async-trait-fn.stderr
index e30dfb1e1a70..6c17077d90b9 100644
--- a/src/test/ui/async-await/async-trait-fn.stderr
+++ b/src/test/ui/async-await/async-trait-fn.stderr
@@ -62,7 +62,7 @@ LL |     async fn bar(&self) {}
 LL | pub const fn from_generator(gen: T) -> impl Future
    |                                           ------------------------------- the found opaque type
    |
-   = note: expected associated type `::bar::{opaque#0}`
+   = note: expected associated type `::bar::{opaque#0}<'_>`
                   found opaque type `impl Future`
 
 error[E0308]: mismatched types
diff --git a/src/test/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.stderr b/src/test/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.stderr
index a41f5789fdbf..36177bbe1583 100644
--- a/src/test/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.stderr
+++ b/src/test/ui/feature-gates/feature-gate-return_position_impl_trait_in_trait.stderr
@@ -3,6 +3,9 @@ error[E0562]: `impl Trait` only allowed in function and inherent method return t
    |
 LL |     fn bar() -> impl Sized;
    |                 ^^^^^^^^^^
+   |
+   = note: see issue #91611  for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/impl-trait/in-trait/reveal.rs b/src/test/ui/impl-trait/in-trait/reveal.rs
new file mode 100644
index 000000000000..d6ede1cc495c
--- /dev/null
+++ b/src/test/ui/impl-trait/in-trait/reveal.rs
@@ -0,0 +1,18 @@
+// check-pass
+
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+trait Foo {
+    fn f() -> Box;
+}
+
+impl Foo for () {
+    fn f() -> Box {
+        Box::new(String::new())
+    }
+}
+
+fn main() {
+    let x: Box = <() as Foo>::f();
+}
diff --git a/src/test/ui/impl-trait/where-allowed.stderr b/src/test/ui/impl-trait/where-allowed.stderr
index 58a2f79efb4c..9b346387d610 100644
--- a/src/test/ui/impl-trait/where-allowed.stderr
+++ b/src/test/ui/impl-trait/where-allowed.stderr
@@ -162,12 +162,18 @@ error[E0562]: `impl Trait` only allowed in function and inherent method return t
    |
 LL |     fn in_return() -> impl Debug;
    |                       ^^^^^^^^^^
+   |
+   = note: see issue #91611  for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
 
 error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `impl` method return
   --> $DIR/where-allowed.rs:125:34
    |
 LL |     fn in_trait_impl_return() -> impl Debug { () }
    |                                  ^^^^^^^^^^
+   |
+   = note: see issue #91611  for more information
+   = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
 
 error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `extern fn` param
   --> $DIR/where-allowed.rs:138:33

From 526511e86b597c0b5c6b5e1676320a6d53117068 Mon Sep 17 00:00:00 2001
From: Michael Goulet 
Date: Tue, 6 Sep 2022 17:27:47 +0000
Subject: [PATCH 4376/5092] Appease clippy again

---
 compiler/rustc_ast_lowering/src/lib.rs          | 17 ++++++++++-------
 .../clippy/clippy_lints/src/dereference.rs      |  2 +-
 src/tools/clippy/clippy_lints/src/lifetimes.rs  |  2 +-
 .../clippy/clippy_lints/src/manual_async_fn.rs  |  2 +-
 .../clippy/clippy_lints/src/missing_doc.rs      |  3 +--
 .../clippy/clippy_lints/src/missing_inline.rs   |  1 -
 src/tools/clippy/clippy_utils/src/hir_utils.rs  |  6 ++----
 7 files changed, 16 insertions(+), 17 deletions(-)

diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 9b4ee9b5a657..6b636288137a 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1376,13 +1376,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     ImplTraitContext::Disallowed(
                         position @ (ImplTraitPosition::TraitReturn | ImplTraitPosition::ImplReturn),
                     ) => {
-                        self.tcx.sess.create_feature_err(
-                            MisplacedImplTrait {
-                                span: t.span,
-                                position: DiagnosticArgFromDisplay(&position),
-                            },
-                            sym::return_position_impl_trait_in_trait,
-                        ).emit();
+                        self.tcx
+                            .sess
+                            .create_feature_err(
+                                MisplacedImplTrait {
+                                    span: t.span,
+                                    position: DiagnosticArgFromDisplay(&position),
+                                },
+                                sym::return_position_impl_trait_in_trait,
+                            )
+                            .emit();
                         hir::TyKind::Err
                     }
                     ImplTraitContext::Disallowed(position) => {
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 09a073f4234d..d1ab7fb67962 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -959,7 +959,7 @@ fn binding_ty_auto_deref_stability<'tcx>(
                     ))
                     .is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()),
             ),
-            TyKind::OpaqueDef(..) | TyKind::ImplTraitInTrait(..) | TyKind::Infer | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::Err => {
+            TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::Err => {
                 Position::ReborrowStable(precedence)
             },
         };
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 573a7c016b8e..5995675bd969 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -441,7 +441,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
 
     fn visit_ty(&mut self, ty: &'tcx Ty<'_>) {
         match ty.kind {
-            TyKind::OpaqueDef(item, bounds) => {
+            TyKind::OpaqueDef(item, bounds, _) => {
                 let map = self.cx.tcx.hir();
                 let item = map.item(item);
                 let len = self.lts.len();
diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
index 2502c8f880dd..754b0e78a148 100644
--- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
@@ -103,7 +103,7 @@ fn future_trait_ref<'tcx>(
     ty: &'tcx Ty<'tcx>,
 ) -> Option<(&'tcx TraitRef<'tcx>, Vec)> {
     if_chain! {
-        if let TyKind::OpaqueDef(item_id, bounds) = ty.kind;
+        if let TyKind::OpaqueDef(item_id, bounds, false) = ty.kind;
         let item = cx.tcx.hir().item(item_id);
         if let ItemKind::OpaqueTy(opaque) = &item.kind;
         if let Some(trait_ref) = opaque.bounds.iter().find_map(|bound| {
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index 9f518c7aaa39..3701fdb4adbf 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -147,8 +147,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
             | hir::ItemKind::TraitAlias(..)
             | hir::ItemKind::TyAlias(..)
             | hir::ItemKind::Union(..)
-            | hir::ItemKind::OpaqueTy(..)
-            | hir::ItemKind::ImplTraitPlaceholder(..) => {},
+            | hir::ItemKind::OpaqueTy(..) => {},
             hir::ItemKind::ExternCrate(..)
             | hir::ItemKind::ForeignMod { .. }
             | hir::ItemKind::GlobalAsm(..)
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index 9fd1a475d749..07bc2ca5d3cd 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -128,7 +128,6 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
             | hir::ItemKind::TyAlias(..)
             | hir::ItemKind::Union(..)
             | hir::ItemKind::OpaqueTy(..)
-            | hir::ItemKind::ImplTraitPlaceholder(..)
             | hir::ItemKind::ExternCrate(..)
             | hir::ItemKind::ForeignMod { .. }
             | hir::ItemKind::Impl { .. }
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 9f8500d41a85..f45cec9f0b43 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -987,12 +987,10 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 }
             },
             TyKind::Path(ref qpath) => self.hash_qpath(qpath),
-            TyKind::OpaqueDef(_, arg_list) => {
+            TyKind::OpaqueDef(_, arg_list, in_trait) => {
                 self.hash_generic_args(arg_list);
+                in_trait.hash(&mut self.s);
             },
-            TyKind::ImplTraitInTrait(_) => {
-                // Do nothing
-            }
             TyKind::TraitObject(_, lifetime, _) => {
                 self.hash_lifetime(*lifetime);
             },

From ec170bef0d8c6ec91c35b89c38da9a0ed10e00fd Mon Sep 17 00:00:00 2001
From: Michael Goulet 
Date: Thu, 8 Sep 2022 00:26:01 +0000
Subject: [PATCH 4377/5092] Rebase fallout

---
 compiler/rustc_ast_lowering/src/lib.rs | 19 ++++++++-----------
 1 file changed, 8 insertions(+), 11 deletions(-)

diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 6b636288137a..0720f23ed756 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1351,17 +1351,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                             *in_trait,
                             itctx,
                         ),
-                    ImplTraitContext::TypeAliasesOpaqueTy => {
-                        let mut nested_itctx = ImplTraitContext::TypeAliasesOpaqueTy;
-                        self.lower_opaque_impl_trait(
-                            span,
-                            hir::OpaqueTyOrigin::TyAlias,
-                            def_node_id,
-                            bounds,
-                            false,
-                            nested_itctx,
-                        )
-                    }
+                    ImplTraitContext::TypeAliasesOpaqueTy => self.lower_opaque_impl_trait(
+                        span,
+                        hir::OpaqueTyOrigin::TyAlias,
+                        def_node_id,
+                        bounds,
+                        false,
+                        &mut ImplTraitContext::TypeAliasesOpaqueTy,
+                    ),
                     ImplTraitContext::Universal => {
                         let span = t.span;
                         let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span);

From 270b776ef9da03b85edc7ddff89a7c6ac188dc4a Mon Sep 17 00:00:00 2001
From: Michael Goulet 
Date: Thu, 8 Sep 2022 00:45:09 +0000
Subject: [PATCH 4378/5092] Adjust pretty printing of RPITITs

---
 .../rustc_infer/src/infer/error_reporting/mod.rs   | 14 ++++++++++++++
 compiler/rustc_middle/src/ty/print/pretty.rs       |  8 +++++++-
 src/test/ui/async-await/async-trait-fn.stderr      | 12 ++++++------
 .../async-await/edition-deny-async-fns-2015.stderr |  4 ++--
 ...2021-incompatible-closure-captures-93117.stderr |  4 ++--
 5 files changed, 31 insertions(+), 11 deletions(-)

diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 0196bd262179..95a36dd8a56a 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -61,6 +61,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed, IntoDiagnosticArg};
 use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString, MultiSpan};
 use rustc_hir as hir;
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::Node;
@@ -1682,6 +1683,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                                 pos.col.to_usize() + 1,
                             )
                         }
+                        (true, ty::Projection(proj))
+                            if self.tcx.def_kind(proj.item_def_id)
+                                == DefKind::ImplTraitPlaceholder =>
+                        {
+                            let sm = self.tcx.sess.source_map();
+                            let pos = sm.lookup_char_pos(self.tcx.def_span(proj.item_def_id).lo());
+                            format!(
+                                " (trait associated opaque type at <{}:{}:{}>)",
+                                sm.filename_for_diagnostics(&pos.file.name),
+                                pos.line,
+                                pos.col.to_usize() + 1,
+                            )
+                        }
                         (true, _) => format!(" ({})", ty.sort_string(self.tcx)),
                         (false, _) => "".to_string(),
                     };
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 1ae3063dae4e..f134e2cd1bc6 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -632,7 +632,13 @@ pub trait PrettyPrinter<'tcx>:
             ty::Foreign(def_id) => {
                 p!(print_def_path(def_id, &[]));
             }
-            ty::Projection(ref data) => p!(print(data)),
+            ty::Projection(ref data) => {
+                if self.tcx().def_kind(data.item_def_id) == DefKind::ImplTraitPlaceholder {
+                    return self.pretty_print_opaque_impl_type(data.item_def_id, data.substs);
+                } else {
+                    p!(print(data))
+                }
+            }
             ty::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)),
             ty::Opaque(def_id, substs) => {
                 // FIXME(eddyb) print this with `print_def_path`.
diff --git a/src/test/ui/async-await/async-trait-fn.stderr b/src/test/ui/async-await/async-trait-fn.stderr
index 6c17077d90b9..e5c584e31e81 100644
--- a/src/test/ui/async-await/async-trait-fn.stderr
+++ b/src/test/ui/async-await/async-trait-fn.stderr
@@ -48,8 +48,8 @@ LL |     async fn foo() {}
 LL | pub const fn from_generator(gen: T) -> impl Future
    |                                           ------------------------------- the found opaque type
    |
-   = note: expected associated type `::foo::{opaque#0}`
-                  found opaque type `impl Future`
+   = note: expected associated type `impl Future` (trait associated opaque type at <$DIR/async-trait-fn.rs:3:20>)
+                  found opaque type `impl Future` (opaque type at <$SRC_DIR/core/src/future/mod.rs:LL:COL>)
 
 error[E0308]: mismatched types
   --> $DIR/async-trait-fn.rs:5:25
@@ -62,8 +62,8 @@ LL |     async fn bar(&self) {}
 LL | pub const fn from_generator(gen: T) -> impl Future
    |                                           ------------------------------- the found opaque type
    |
-   = note: expected associated type `::bar::{opaque#0}<'_>`
-                  found opaque type `impl Future`
+   = note: expected associated type `impl Future` (trait associated opaque type at <$DIR/async-trait-fn.rs:5:25>)
+                  found opaque type `impl Future` (opaque type at <$SRC_DIR/core/src/future/mod.rs:LL:COL>)
 
 error[E0308]: mismatched types
   --> $DIR/async-trait-fn.rs:7:20
@@ -81,8 +81,8 @@ LL | |     }
 LL |   pub const fn from_generator(gen: T) -> impl Future
    |                                             ------------------------------- the found opaque type
    |
-   = note: expected associated type `::baz::{opaque#0}`
-                  found opaque type `impl Future`
+   = note: expected associated type `impl Future` (trait associated opaque type at <$DIR/async-trait-fn.rs:7:20>)
+                  found opaque type `impl Future` (opaque type at <$SRC_DIR/core/src/future/mod.rs:LL:COL>)
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr
index 2f40ef1ccbb1..8c2902d9b00d 100644
--- a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr
+++ b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr
@@ -103,8 +103,8 @@ LL |     async fn foo() {}
 LL | pub const fn from_generator(gen: T) -> impl Future
    |                                           ------------------------------- the found opaque type
    |
-   = note: expected associated type `::foo::{opaque#0}`
-                  found opaque type `impl Future`
+   = note: expected associated type `impl Future` (trait associated opaque type at <$DIR/edition-deny-async-fns-2015.rs:18:20>)
+                  found opaque type `impl Future` (opaque type at <$SRC_DIR/core/src/future/mod.rs:LL:COL>)
 
 error: aborting due to 11 previous errors
 
diff --git a/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.stderr b/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.stderr
index 9819f6501378..3814c568e72c 100644
--- a/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.stderr
+++ b/src/test/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.stderr
@@ -85,8 +85,8 @@ LL | trait C{async fn new(val: T) {}
 LL | pub const fn from_generator(gen: T) -> impl Future
    |                                           ------------------------------- the found opaque type
    |
-   = note: expected associated type `::new::{opaque#0}`
-                  found opaque type `impl Future`
+   = note: expected associated type `impl Future` (trait associated opaque type at <$DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:13:30>)
+                  found opaque type `impl Future` (opaque type at <$SRC_DIR/core/src/future/mod.rs:LL:COL>)
 
 warning: changes to closure capture in Rust 2021 will affect drop order
   --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-93117.rs:13:30

From 6876c94d800433ad7f2ea72da64d963eb2269589 Mon Sep 17 00:00:00 2001
From: Michael Goulet 
Date: Fri, 9 Sep 2022 01:31:36 +0000
Subject: [PATCH 4379/5092] Fix documentation lint failures

---
 compiler/rustc_infer/src/infer/error_reporting/mod.rs | 2 +-
 compiler/rustc_typeck/src/check/compare_method.rs     | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 95a36dd8a56a..08460463998f 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -1772,7 +1772,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
         // In some (most?) cases cause.body_id points to actual body, but in some cases
         // it's an actual definition. According to the comments (e.g. in
-        // librustc_typeck/check/compare_method.rs:compare_predicate_entailment) the latter
+        // librustc_typeck/check/compare_method.rs:compare_predicates_and_trait_impl_trait_tys) the latter
         // is relied upon by some other code. This might (or might not) need cleanup.
         let body_owner_def_id =
             self.tcx.hir().opt_local_def_id(cause.body_id).unwrap_or_else(|| {
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index a6c8dbb2555d..1152a2477a2a 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -1307,7 +1307,7 @@ pub(crate) fn compare_ty_impl<'tcx>(
     })();
 }
 
-/// The equivalent of [compare_predicate_entailment], but for associated types
+/// The equivalent of [compare_predicates_and_trait_impl_trait_tys], but for associated types
 /// instead of associated functions.
 fn compare_type_predicate_entailment<'tcx>(
     tcx: TyCtxt<'tcx>,

From 7e7dfb83dc1fe63d1ce14101339f5eee5b76159d Mon Sep 17 00:00:00 2001
From: chenyukang 
Date: Tue, 30 Aug 2022 10:03:02 +0800
Subject: [PATCH 4380/5092] fix #101097, avoid infinite loop in fn arguments
 checking

---
 .../src/check/fn_ctxt/arg_matrix.rs           |   4 +-
 .../argument-suggestions/issue-100478.stderr  |   8 +-
 .../ui/argument-suggestions/issue-101097.rs   |  21 +++
 .../argument-suggestions/issue-101097.stderr  | 160 ++++++++++++++++++
 4 files changed, 187 insertions(+), 6 deletions(-)
 create mode 100644 src/test/ui/argument-suggestions/issue-101097.rs
 create mode 100644 src/test/ui/argument-suggestions/issue-101097.stderr

diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs b/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs
index 90a2589d747e..fc83994caf53 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs
@@ -236,8 +236,8 @@ impl<'tcx> ArgMatrix<'tcx> {
                             if matches!(c, Compatibility::Compatible) { Some(i) } else { None }
                         })
                         .collect();
-                if compat.len() != 1 {
-                    // this could go into multiple slots, don't bother exploring both
+                if compat.len() < 1 {
+                    // try to find a cycle even when this could go into multiple slots, see #101097
                     is_cycle = false;
                     break;
                 }
diff --git a/src/test/ui/argument-suggestions/issue-100478.stderr b/src/test/ui/argument-suggestions/issue-100478.stderr
index a77889a9679c..df02a312cf11 100644
--- a/src/test/ui/argument-suggestions/issue-100478.stderr
+++ b/src/test/ui/argument-suggestions/issue-100478.stderr
@@ -15,7 +15,7 @@ LL | fn three_diff(_a: T1, _b: T2, _c: T3) {}
 help: provide the arguments
    |
 LL |     three_diff(/* T1 */, T2::new(0), /* T3 */);
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+   |               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0308]: arguments to this function are incorrect
   --> $DIR/issue-100478.rs:35:5
@@ -35,7 +35,7 @@ LL | fn four_shuffle(_a: T1, _b: T2, _c: T3, _d: T4) {}
 help: did you mean
    |
 LL |     four_shuffle(T1::default(), T2::default(), T3::default(), T4::default());
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+   |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0308]: arguments to this function are incorrect
   --> $DIR/issue-100478.rs:36:5
@@ -54,7 +54,7 @@ LL | fn four_shuffle(_a: T1, _b: T2, _c: T3, _d: T4) {}
 help: swap these arguments
    |
 LL |     four_shuffle(T1::default(), T2::default(), T3::default(), /* T4 */);
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+   |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error[E0061]: this function takes 8 arguments but 7 arguments were supplied
   --> $DIR/issue-100478.rs:47:5
@@ -73,7 +73,7 @@ LL | fn foo(p1: T1, p2: Arc, p3: T3, p4: Arc, p5: T5, p6: T6, p7: T7, p8
 help: provide the argument
    |
 LL |     foo(p1, /* Arc */, p3, p4, p5, p6, p7, p8);
-   |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+   |        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/argument-suggestions/issue-101097.rs b/src/test/ui/argument-suggestions/issue-101097.rs
new file mode 100644
index 000000000000..7994d3cd9959
--- /dev/null
+++ b/src/test/ui/argument-suggestions/issue-101097.rs
@@ -0,0 +1,21 @@
+struct A;
+struct B;
+struct C;
+struct D;
+
+fn f(
+    a1: A,
+    a2: A,
+    b1: B,
+    b2: B,
+    c1: C,
+    c2: C,
+) {}
+
+fn main() {
+    f(C, A, A, A, B, B, C); //~ ERROR this function takes 6 arguments but 7 arguments were supplied [E0061]
+    f(C, C, A, A, B, B);  //~ ERROR arguments to this function are incorrect [E0308]
+    f(A, A, D, D, B, B);  //~ arguments to this function are incorrect [E0308]
+    f(C, C, B, B, A, A);  //~ arguments to this function are incorrect [E0308]
+    f(C, C, A, B, A, A);  //~ arguments to this function are incorrect [E0308]
+}
diff --git a/src/test/ui/argument-suggestions/issue-101097.stderr b/src/test/ui/argument-suggestions/issue-101097.stderr
new file mode 100644
index 000000000000..096f8c226f2a
--- /dev/null
+++ b/src/test/ui/argument-suggestions/issue-101097.stderr
@@ -0,0 +1,160 @@
+error[E0061]: this function takes 6 arguments but 7 arguments were supplied
+  --> $DIR/issue-101097.rs:16:5
+   |
+LL |     f(C, A, A, A, B, B, C);
+   |     ^ -     -  -  - expected `C`, found `B`
+   |       |     |  |
+   |       |     |  argument of type `A` unexpected
+   |       |     expected `B`, found `A`
+   |       expected `A`, found `C`
+   |
+note: function defined here
+  --> $DIR/issue-101097.rs:6:4
+   |
+LL | fn f(
+   |    ^
+LL |     a1: A,
+   |     -----
+LL |     a2: A,
+   |     -----
+LL |     b1: B,
+   |     -----
+LL |     b2: B,
+   |     -----
+LL |     c1: C,
+   |     -----
+LL |     c2: C,
+   |     -----
+help: did you mean
+   |
+LL |     f(A, A, B, B, C, C);
+   |      ~~~~~~~~~~~~~~~~~~
+
+error[E0308]: arguments to this function are incorrect
+  --> $DIR/issue-101097.rs:17:5
+   |
+LL |     f(C, C, A, A, B, B);
+   |     ^
+   |
+note: function defined here
+  --> $DIR/issue-101097.rs:6:4
+   |
+LL | fn f(
+   |    ^
+LL |     a1: A,
+   |     -----
+LL |     a2: A,
+   |     -----
+LL |     b1: B,
+   |     -----
+LL |     b2: B,
+   |     -----
+LL |     c1: C,
+   |     -----
+LL |     c2: C,
+   |     -----
+help: did you mean
+   |
+LL |     f(A, A, B, B, C, C);
+   |      ~~~~~~~~~~~~~~~~~~
+
+error[E0308]: arguments to this function are incorrect
+  --> $DIR/issue-101097.rs:18:5
+   |
+LL |     f(A, A, D, D, B, B);
+   |     ^       -  -  ---- two arguments of type `C` and `C` are missing
+   |             |  |
+   |             |  argument of type `D` unexpected
+   |             argument of type `D` unexpected
+   |
+note: function defined here
+  --> $DIR/issue-101097.rs:6:4
+   |
+LL | fn f(
+   |    ^
+LL |     a1: A,
+   |     -----
+LL |     a2: A,
+   |     -----
+LL |     b1: B,
+   |     -----
+LL |     b2: B,
+   |     -----
+LL |     c1: C,
+   |     -----
+LL |     c2: C,
+   |     -----
+help: did you mean
+   |
+LL |     f(A, A, B, B, /* C */, /* C */);
+   |      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0308]: arguments to this function are incorrect
+  --> $DIR/issue-101097.rs:19:5
+   |
+LL |     f(C, C, B, B, A, A);
+   |     ^ -  -        -  - expected `C`, found `A`
+   |       |  |        |
+   |       |  |        expected `C`, found `A`
+   |       |  expected `A`, found `C`
+   |       expected `A`, found `C`
+   |
+note: function defined here
+  --> $DIR/issue-101097.rs:6:4
+   |
+LL | fn f(
+   |    ^
+LL |     a1: A,
+   |     -----
+LL |     a2: A,
+   |     -----
+LL |     b1: B,
+   |     -----
+LL |     b2: B,
+   |     -----
+LL |     c1: C,
+   |     -----
+LL |     c2: C,
+   |     -----
+help: did you mean
+   |
+LL |     f(A, A, B, B, C, C);
+   |      ~~~~~~~~~~~~~~~~~~
+
+error[E0308]: arguments to this function are incorrect
+  --> $DIR/issue-101097.rs:20:5
+   |
+LL |     f(C, C, A, B, A, A);
+   |     ^ -  -  -     -  - expected `C`, found `A`
+   |       |  |  |     |
+   |       |  |  |     expected `C`, found `A`
+   |       |  |  expected struct `B`, found struct `A`
+   |       |  expected `A`, found `C`
+   |       expected `A`, found `C`
+   |
+note: function defined here
+  --> $DIR/issue-101097.rs:6:4
+   |
+LL | fn f(
+   |    ^
+LL |     a1: A,
+   |     -----
+LL |     a2: A,
+   |     -----
+LL |     b1: B,
+   |     -----
+LL |     b2: B,
+   |     -----
+LL |     c1: C,
+   |     -----
+LL |     c2: C,
+   |     -----
+help: did you mean
+   |
+LL |     f(A, A, /* B */, B, C, C);
+   |      ~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0061, E0308.
+For more information about an error, try `rustc --explain E0061`.

From 890e759ffcf61a2c66f722bb448432b9a78fdaaf Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote 
Date: Fri, 9 Sep 2022 11:51:23 +1000
Subject: [PATCH 4381/5092] Move `Spacing` out of `AttrAnnotatedTokenStream`.

And into `AttrAnnotatedTokenTree::Token`.

PR #99887 did the same thing for `TokenStream`.
---
 compiler/rustc_ast/src/attr/mod.rs            | 13 +++++------
 compiler/rustc_ast/src/mut_visit.rs           |  4 ++--
 compiler/rustc_ast/src/tokenstream.rs         | 23 ++++++-------------
 compiler/rustc_expand/src/config.rs           | 22 +++++++++---------
 .../rustc_parse/src/parser/attr_wrapper.rs    | 16 ++++++-------
 5 files changed, 34 insertions(+), 44 deletions(-)

diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 6b0dac7c2f0b..d4251f5cc8a9 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -303,13 +303,12 @@ impl Attribute {
                 .as_ref()
                 .unwrap_or_else(|| panic!("attribute is missing tokens: {:?}", self))
                 .create_token_stream(),
-            AttrKind::DocComment(comment_kind, data) => AttrAnnotatedTokenStream::from((
-                AttrAnnotatedTokenTree::Token(Token::new(
-                    token::DocComment(comment_kind, self.style, data),
-                    self.span,
-                )),
-                Spacing::Alone,
-            )),
+            AttrKind::DocComment(comment_kind, data) => {
+                AttrAnnotatedTokenStream::new(vec![AttrAnnotatedTokenTree::Token(
+                    Token::new(token::DocComment(comment_kind, self.style, data), self.span),
+                    Spacing::Alone,
+                )])
+            }
         }
     }
 }
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 458d1156ec25..d5be9b667c61 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -644,7 +644,7 @@ pub fn noop_flat_map_param(mut param: Param, vis: &mut T) -> Smal
 // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
 pub fn visit_attr_annotated_tt(tt: &mut AttrAnnotatedTokenTree, vis: &mut T) {
     match tt {
-        AttrAnnotatedTokenTree::Token(token) => {
+        AttrAnnotatedTokenTree::Token(token, _) => {
             visit_token(token, vis);
         }
         AttrAnnotatedTokenTree::Delimited(DelimSpan { open, close }, _delim, tts) => {
@@ -696,7 +696,7 @@ pub fn visit_attr_annotated_tts(
 ) {
     if T::VISIT_TOKENS && !tts.is_empty() {
         let tts = Lrc::make_mut(tts);
-        visit_vec(tts, |(tree, _is_joint)| visit_attr_annotated_tt(tree, vis));
+        visit_vec(tts, |tree| visit_attr_annotated_tt(tree, vis));
     }
 }
 
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index b6684c0669b4..4b9a90fea33f 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -177,12 +177,12 @@ impl HashStable for LazyTokenStream {
 /// during expansion to perform early cfg-expansion, and to process attributes
 /// during proc-macro invocations.
 #[derive(Clone, Debug, Default, Encodable, Decodable)]
-pub struct AttrAnnotatedTokenStream(pub Lrc>);
+pub struct AttrAnnotatedTokenStream(pub Lrc>);
 
 /// Like `TokenTree`, but for `AttrAnnotatedTokenStream`
 #[derive(Clone, Debug, Encodable, Decodable)]
 pub enum AttrAnnotatedTokenTree {
-    Token(Token),
+    Token(Token, Spacing),
     Delimited(DelimSpan, Delimiter, AttrAnnotatedTokenStream),
     /// Stores the attributes for an attribute target,
     /// along with the tokens for that attribute target.
@@ -191,7 +191,7 @@ pub enum AttrAnnotatedTokenTree {
 }
 
 impl AttrAnnotatedTokenStream {
-    pub fn new(tokens: Vec<(AttrAnnotatedTokenTree, Spacing)>) -> AttrAnnotatedTokenStream {
+    pub fn new(tokens: Vec) -> AttrAnnotatedTokenStream {
         AttrAnnotatedTokenStream(Lrc::new(tokens))
     }
 
@@ -204,9 +204,9 @@ impl AttrAnnotatedTokenStream {
         let trees: Vec<_> = self
             .0
             .iter()
-            .flat_map(|tree| match &tree.0 {
-                AttrAnnotatedTokenTree::Token(inner) => {
-                    smallvec![TokenTree::Token(inner.clone(), tree.1)].into_iter()
+            .flat_map(|tree| match &tree {
+                AttrAnnotatedTokenTree::Token(inner, spacing) => {
+                    smallvec![TokenTree::Token(inner.clone(), *spacing)].into_iter()
                 }
                 AttrAnnotatedTokenTree::Delimited(span, delim, stream) => {
                     smallvec![TokenTree::Delimited(*span, *delim, stream.to_tokenstream()),]
@@ -363,12 +363,6 @@ impl TokenStream {
     }
 }
 
-impl From<(AttrAnnotatedTokenTree, Spacing)> for AttrAnnotatedTokenStream {
-    fn from((tree, spacing): (AttrAnnotatedTokenTree, Spacing)) -> AttrAnnotatedTokenStream {
-        AttrAnnotatedTokenStream::new(vec![(tree, spacing)])
-    }
-}
-
 impl iter::FromIterator for TokenStream {
     fn from_iter>(iter: I) -> Self {
         TokenStream::new(iter.into_iter().collect::>())
@@ -428,10 +422,7 @@ impl TokenStream {
         } else {
             let attr_data =
                 AttributesData { attrs: attrs.iter().cloned().collect(), tokens: tokens.clone() };
-            AttrAnnotatedTokenStream::new(vec![(
-                AttrAnnotatedTokenTree::Attributes(attr_data),
-                Spacing::Alone,
-            )])
+            AttrAnnotatedTokenStream::new(vec![AttrAnnotatedTokenTree::Attributes(attr_data)])
         };
         Some(attr_annotated.to_tokenstream())
     }
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 48ee23d2c3d1..720bb2f0e23d 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -276,9 +276,9 @@ impl<'a> StripUnconfigured<'a> {
     /// Normal cfg-expansion operates on parsed AST nodes via the `configure` method
     fn configure_tokens(&self, stream: &AttrAnnotatedTokenStream) -> AttrAnnotatedTokenStream {
         fn can_skip(stream: &AttrAnnotatedTokenStream) -> bool {
-            stream.0.iter().all(|(tree, _spacing)| match tree {
+            stream.0.iter().all(|tree| match tree {
                 AttrAnnotatedTokenTree::Attributes(_) => false,
-                AttrAnnotatedTokenTree::Token(_) => true,
+                AttrAnnotatedTokenTree::Token(..) => true,
                 AttrAnnotatedTokenTree::Delimited(_, _, inner) => can_skip(inner),
             })
         }
@@ -290,7 +290,7 @@ impl<'a> StripUnconfigured<'a> {
         let trees: Vec<_> = stream
             .0
             .iter()
-            .flat_map(|(tree, spacing)| match tree.clone() {
+            .flat_map(|tree| match tree.clone() {
                 AttrAnnotatedTokenTree::Attributes(mut data) => {
                     data.attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
 
@@ -298,24 +298,24 @@ impl<'a> StripUnconfigured<'a> {
                         data.tokens = LazyTokenStream::new(
                             self.configure_tokens(&data.tokens.create_token_stream()),
                         );
-                        Some((AttrAnnotatedTokenTree::Attributes(data), *spacing)).into_iter()
+                        Some(AttrAnnotatedTokenTree::Attributes(data)).into_iter()
                     } else {
                         None.into_iter()
                     }
                 }
                 AttrAnnotatedTokenTree::Delimited(sp, delim, mut inner) => {
                     inner = self.configure_tokens(&inner);
-                    Some((AttrAnnotatedTokenTree::Delimited(sp, delim, inner), *spacing))
+                    Some(AttrAnnotatedTokenTree::Delimited(sp, delim, inner))
                         .into_iter()
                 }
-                AttrAnnotatedTokenTree::Token(ref token) if let TokenKind::Interpolated(ref nt) = token.kind => {
+                AttrAnnotatedTokenTree::Token(ref token, _) if let TokenKind::Interpolated(ref nt) = token.kind => {
                     panic!(
                         "Nonterminal should have been flattened at {:?}: {:?}",
                         token.span, nt
                     );
                 }
-                AttrAnnotatedTokenTree::Token(token) => {
-                    Some((AttrAnnotatedTokenTree::Token(token), *spacing)).into_iter()
+                AttrAnnotatedTokenTree::Token(token, spacing) => {
+                    Some(AttrAnnotatedTokenTree::Token(token, spacing)).into_iter()
                 }
             })
             .collect();
@@ -404,13 +404,13 @@ impl<'a> StripUnconfigured<'a> {
         };
         let pound_span = pound_token.span;
 
-        let mut trees = vec![(AttrAnnotatedTokenTree::Token(pound_token), Spacing::Alone)];
+        let mut trees = vec![AttrAnnotatedTokenTree::Token(pound_token, Spacing::Alone)];
         if attr.style == AttrStyle::Inner {
             // For inner attributes, we do the same thing for the `!` in `#![some_attr]`
             let TokenTree::Token(bang_token @ Token { kind: TokenKind::Not, .. }, _) = orig_trees.next().unwrap() else {
                 panic!("Bad tokens for attribute {:?}", attr);
             };
-            trees.push((AttrAnnotatedTokenTree::Token(bang_token), Spacing::Alone));
+            trees.push(AttrAnnotatedTokenTree::Token(bang_token, Spacing::Alone));
         }
         // We don't really have a good span to use for the synthesized `[]`
         // in `#[attr]`, so just use the span of the `#` token.
@@ -422,7 +422,7 @@ impl<'a> StripUnconfigured<'a> {
                 .unwrap_or_else(|| panic!("Missing tokens for {:?}", item))
                 .create_token_stream(),
         );
-        trees.push((bracket_group, Spacing::Alone));
+        trees.push(bracket_group);
         let tokens = Some(LazyTokenStream::new(AttrAnnotatedTokenStream::new(trees)));
         let attr = attr::mk_attr_from_item(item, tokens, attr.style, item_span);
         if attr.has_name(sym::crate_type) {
diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs
index 2e58605cf19b..6a78772643a3 100644
--- a/compiler/rustc_parse/src/parser/attr_wrapper.rs
+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs
@@ -397,7 +397,7 @@ fn make_token_stream(
     struct FrameData {
         // This is `None` for the first frame, `Some` for all others.
         open_delim_sp: Option<(Delimiter, Span)>,
-        inner: Vec<(AttrAnnotatedTokenTree, Spacing)>,
+        inner: Vec,
     }
     let mut stack = vec![FrameData { open_delim_sp: None, inner: vec![] }];
     let mut token_and_spacing = iter.next();
@@ -426,34 +426,34 @@ fn make_token_stream(
                         panic!("Bottom token frame is missing for token: {:?}", token)
                     })
                     .inner
-                    .push((delimited, Spacing::Alone));
+                    .push(delimited);
             }
             FlatToken::Token(token) => stack
                 .last_mut()
                 .expect("Bottom token frame is missing!")
                 .inner
-                .push((AttrAnnotatedTokenTree::Token(token), spacing)),
+                .push(AttrAnnotatedTokenTree::Token(token, spacing)),
             FlatToken::AttrTarget(data) => stack
                 .last_mut()
                 .expect("Bottom token frame is missing!")
                 .inner
-                .push((AttrAnnotatedTokenTree::Attributes(data), spacing)),
+                .push(AttrAnnotatedTokenTree::Attributes(data)),
             FlatToken::Empty => {}
         }
         token_and_spacing = iter.next();
     }
     let mut final_buf = stack.pop().expect("Missing final buf!");
     if break_last_token {
-        let (last_token, spacing) = final_buf.inner.pop().unwrap();
-        if let AttrAnnotatedTokenTree::Token(last_token) = last_token {
+        let last_token = final_buf.inner.pop().unwrap();
+        if let AttrAnnotatedTokenTree::Token(last_token, spacing) = last_token {
             let unglued_first = last_token.kind.break_two_token_op().unwrap().0;
 
             // An 'unglued' token is always two ASCII characters
             let mut first_span = last_token.span.shrink_to_lo();
             first_span = first_span.with_hi(first_span.lo() + rustc_span::BytePos(1));
 
-            final_buf.inner.push((
-                AttrAnnotatedTokenTree::Token(Token::new(unglued_first, first_span)),
+            final_buf.inner.push(AttrAnnotatedTokenTree::Token(
+                Token::new(unglued_first, first_span),
                 spacing,
             ));
         } else {

From a56d345490ed68ab57cf1854dd8978fefc9862d0 Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote 
Date: Fri, 9 Sep 2022 12:44:05 +1000
Subject: [PATCH 4382/5092] Rename `AttrAnnotatedToken{Stream,Tree}`.

These two type names are long and have long matching prefixes. I find
them hard to read, especially in combinations like
`AttrAnnotatedTokenStream::new(vec![AttrAnnotatedTokenTree::Token(..)])`.

This commit renames them as `AttrToken{Stream,Tree}`.
---
 compiler/rustc_ast/src/attr/mod.rs            |  6 +--
 compiler/rustc_ast/src/mut_visit.rs           | 19 ++++-----
 compiler/rustc_ast/src/tokenstream.rs         | 40 +++++++++---------
 compiler/rustc_builtin_macros/src/cfg_eval.rs |  6 +--
 compiler/rustc_expand/src/config.rs           | 42 +++++++++----------
 compiler/rustc_parse/src/parser/attr.rs       |  2 +-
 .../rustc_parse/src/parser/attr_wrapper.rs    | 33 +++++++--------
 compiler/rustc_parse/src/parser/mod.rs        | 16 +++----
 8 files changed, 80 insertions(+), 84 deletions(-)

diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index d4251f5cc8a9..e0bb47539329 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -7,7 +7,7 @@ use crate::ast::{MacArgs, MacArgsEq, MacDelimiter, MetaItem, MetaItemKind, Neste
 use crate::ast::{Path, PathSegment};
 use crate::ptr::P;
 use crate::token::{self, CommentKind, Delimiter, Token};
-use crate::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree};
+use crate::tokenstream::{AttrTokenStream, AttrTokenTree};
 use crate::tokenstream::{DelimSpan, Spacing, TokenTree};
 use crate::tokenstream::{LazyTokenStream, TokenStream};
 use crate::util::comments;
@@ -296,7 +296,7 @@ impl Attribute {
         }
     }
 
-    pub fn tokens(&self) -> AttrAnnotatedTokenStream {
+    pub fn tokens(&self) -> AttrTokenStream {
         match self.kind {
             AttrKind::Normal(ref normal) => normal
                 .tokens
@@ -304,7 +304,7 @@ impl Attribute {
                 .unwrap_or_else(|| panic!("attribute is missing tokens: {:?}", self))
                 .create_token_stream(),
             AttrKind::DocComment(comment_kind, data) => {
-                AttrAnnotatedTokenStream::new(vec![AttrAnnotatedTokenTree::Token(
+                AttrTokenStream::new(vec![AttrTokenTree::Token(
                     Token::new(token::DocComment(comment_kind, self.style, data), self.span),
                     Spacing::Alone,
                 )])
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index d5be9b667c61..27fb2d12760d 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -642,17 +642,17 @@ pub fn noop_flat_map_param(mut param: Param, vis: &mut T) -> Smal
 }
 
 // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
-pub fn visit_attr_annotated_tt(tt: &mut AttrAnnotatedTokenTree, vis: &mut T) {
+pub fn visit_attr_tt(tt: &mut AttrTokenTree, vis: &mut T) {
     match tt {
-        AttrAnnotatedTokenTree::Token(token, _) => {
+        AttrTokenTree::Token(token, _) => {
             visit_token(token, vis);
         }
-        AttrAnnotatedTokenTree::Delimited(DelimSpan { open, close }, _delim, tts) => {
+        AttrTokenTree::Delimited(DelimSpan { open, close }, _delim, tts) => {
             vis.visit_span(open);
             vis.visit_span(close);
-            visit_attr_annotated_tts(tts, vis);
+            visit_attr_tts(tts, vis);
         }
-        AttrAnnotatedTokenTree::Attributes(data) => {
+        AttrTokenTree::Attributes(data) => {
             for attr in &mut *data.attrs {
                 match &mut attr.kind {
                     AttrKind::Normal(normal) => {
@@ -690,13 +690,10 @@ pub fn visit_tts(TokenStream(tts): &mut TokenStream, vis: &mut T)
     }
 }
 
-pub fn visit_attr_annotated_tts(
-    AttrAnnotatedTokenStream(tts): &mut AttrAnnotatedTokenStream,
-    vis: &mut T,
-) {
+pub fn visit_attr_tts(AttrTokenStream(tts): &mut AttrTokenStream, vis: &mut T) {
     if T::VISIT_TOKENS && !tts.is_empty() {
         let tts = Lrc::make_mut(tts);
-        visit_vec(tts, |tree| visit_attr_annotated_tt(tree, vis));
+        visit_vec(tts, |tree| visit_attr_tt(tree, vis));
     }
 }
 
@@ -704,7 +701,7 @@ pub fn visit_lazy_tts_opt_mut(lazy_tts: Option<&mut LazyTokenStre
     if T::VISIT_TOKENS {
         if let Some(lazy_tts) = lazy_tts {
             let mut tts = lazy_tts.create_token_stream();
-            visit_attr_annotated_tts(&mut tts, vis);
+            visit_attr_tts(&mut tts, vis);
             *lazy_tts = LazyTokenStream::new(tts);
         }
     }
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index 4b9a90fea33f..4088e50fbe2c 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -122,11 +122,11 @@ where
 }
 
 pub trait CreateTokenStream: sync::Send + sync::Sync {
-    fn create_token_stream(&self) -> AttrAnnotatedTokenStream;
+    fn create_token_stream(&self) -> AttrTokenStream;
 }
 
-impl CreateTokenStream for AttrAnnotatedTokenStream {
-    fn create_token_stream(&self) -> AttrAnnotatedTokenStream {
+impl CreateTokenStream for AttrTokenStream {
+    fn create_token_stream(&self) -> AttrTokenStream {
         self.clone()
     }
 }
@@ -142,7 +142,7 @@ impl LazyTokenStream {
         LazyTokenStream(Lrc::new(Box::new(inner)))
     }
 
-    pub fn create_token_stream(&self) -> AttrAnnotatedTokenStream {
+    pub fn create_token_stream(&self) -> AttrTokenStream {
         self.0.create_token_stream()
     }
 }
@@ -172,31 +172,31 @@ impl HashStable for LazyTokenStream {
     }
 }
 
-/// A `AttrAnnotatedTokenStream` is similar to a `TokenStream`, but with extra
+/// An `AttrTokenStream` is similar to a `TokenStream`, but with extra
 /// information about the tokens for attribute targets. This is used
 /// during expansion to perform early cfg-expansion, and to process attributes
 /// during proc-macro invocations.
 #[derive(Clone, Debug, Default, Encodable, Decodable)]
-pub struct AttrAnnotatedTokenStream(pub Lrc>);
+pub struct AttrTokenStream(pub Lrc>);
 
-/// Like `TokenTree`, but for `AttrAnnotatedTokenStream`
+/// Like `TokenTree`, but for `AttrTokenStream`.
 #[derive(Clone, Debug, Encodable, Decodable)]
-pub enum AttrAnnotatedTokenTree {
+pub enum AttrTokenTree {
     Token(Token, Spacing),
-    Delimited(DelimSpan, Delimiter, AttrAnnotatedTokenStream),
+    Delimited(DelimSpan, Delimiter, AttrTokenStream),
     /// Stores the attributes for an attribute target,
     /// along with the tokens for that attribute target.
     /// See `AttributesData` for more information
     Attributes(AttributesData),
 }
 
-impl AttrAnnotatedTokenStream {
-    pub fn new(tokens: Vec) -> AttrAnnotatedTokenStream {
-        AttrAnnotatedTokenStream(Lrc::new(tokens))
+impl AttrTokenStream {
+    pub fn new(tokens: Vec) -> AttrTokenStream {
+        AttrTokenStream(Lrc::new(tokens))
     }
 
-    /// Converts this `AttrAnnotatedTokenStream` to a plain `TokenStream
-    /// During conversion, `AttrAnnotatedTokenTree::Attributes` get 'flattened'
+    /// Converts this `AttrTokenStream` to a plain `TokenStream`.
+    /// During conversion, `AttrTokenTree::Attributes` get 'flattened'
     /// back to a `TokenStream` of the form `outer_attr attr_target`.
     /// If there are inner attributes, they are inserted into the proper
     /// place in the attribute target tokens.
@@ -205,14 +205,14 @@ impl AttrAnnotatedTokenStream {
             .0
             .iter()
             .flat_map(|tree| match &tree {
-                AttrAnnotatedTokenTree::Token(inner, spacing) => {
+                AttrTokenTree::Token(inner, spacing) => {
                     smallvec![TokenTree::Token(inner.clone(), *spacing)].into_iter()
                 }
-                AttrAnnotatedTokenTree::Delimited(span, delim, stream) => {
+                AttrTokenTree::Delimited(span, delim, stream) => {
                     smallvec![TokenTree::Delimited(*span, *delim, stream.to_tokenstream()),]
                         .into_iter()
                 }
-                AttrAnnotatedTokenTree::Attributes(data) => {
+                AttrTokenTree::Attributes(data) => {
                     let mut outer_attrs = Vec::new();
                     let mut inner_attrs = Vec::new();
                     for attr in &data.attrs {
@@ -417,14 +417,14 @@ impl TokenStream {
     fn opt_from_ast(node: &(impl HasAttrs + HasTokens)) -> Option {
         let tokens = node.tokens()?;
         let attrs = node.attrs();
-        let attr_annotated = if attrs.is_empty() {
+        let attr_stream = if attrs.is_empty() {
             tokens.create_token_stream()
         } else {
             let attr_data =
                 AttributesData { attrs: attrs.iter().cloned().collect(), tokens: tokens.clone() };
-            AttrAnnotatedTokenStream::new(vec![AttrAnnotatedTokenTree::Attributes(attr_data)])
+            AttrTokenStream::new(vec![AttrTokenTree::Attributes(attr_data)])
         };
-        Some(attr_annotated.to_tokenstream())
+        Some(attr_stream.to_tokenstream())
     }
 
     // Create a token stream containing a single token with alone spacing.
diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs
index 89b2c329236d..e673dff0dea8 100644
--- a/compiler/rustc_builtin_macros/src/cfg_eval.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs
@@ -188,14 +188,14 @@ impl CfgEval<'_, '_> {
         let orig_tokens = annotatable.to_tokens().flattened();
 
         // Re-parse the tokens, setting the `capture_cfg` flag to save extra information
-        // to the captured `AttrAnnotatedTokenStream` (specifically, we capture
-        // `AttrAnnotatedTokenTree::AttributesData` for all occurrences of `#[cfg]` and `#[cfg_attr]`)
+        // to the captured `AttrTokenStream` (specifically, we capture
+        // `AttrTokenTree::AttributesData` for all occurrences of `#[cfg]` and `#[cfg_attr]`)
         let mut parser =
             rustc_parse::stream_to_parser(&self.cfg.sess.parse_sess, orig_tokens, None);
         parser.capture_cfg = true;
         annotatable = parse_annotatable_with(&mut parser);
 
-        // Now that we have our re-parsed `AttrAnnotatedTokenStream`, recursively configuring
+        // Now that we have our re-parsed `AttrTokenStream`, recursively configuring
         // our attribute target will correctly the tokens as well.
         flat_map_annotatable(self, annotatable)
     }
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 720bb2f0e23d..5d78a4a59ecd 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -2,7 +2,7 @@
 
 use rustc_ast::ptr::P;
 use rustc_ast::token::{Delimiter, Token, TokenKind};
-use rustc_ast::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree};
+use rustc_ast::tokenstream::{AttrTokenStream, AttrTokenTree};
 use rustc_ast::tokenstream::{DelimSpan, Spacing};
 use rustc_ast::tokenstream::{LazyTokenStream, TokenTree};
 use rustc_ast::NodeId;
@@ -259,8 +259,8 @@ impl<'a> StripUnconfigured<'a> {
     fn try_configure_tokens(&self, node: &mut T) {
         if self.config_tokens {
             if let Some(Some(tokens)) = node.tokens_mut() {
-                let attr_annotated_tokens = tokens.create_token_stream();
-                *tokens = LazyTokenStream::new(self.configure_tokens(&attr_annotated_tokens));
+                let attr_stream = tokens.create_token_stream();
+                *tokens = LazyTokenStream::new(self.configure_tokens(&attr_stream));
             }
         }
     }
@@ -270,16 +270,16 @@ impl<'a> StripUnconfigured<'a> {
         if self.in_cfg(&attrs) { Some(attrs) } else { None }
     }
 
-    /// Performs cfg-expansion on `stream`, producing a new `AttrAnnotatedTokenStream`.
+    /// Performs cfg-expansion on `stream`, producing a new `AttrTokenStream`.
     /// This is only used during the invocation of `derive` proc-macros,
     /// which require that we cfg-expand their entire input.
     /// Normal cfg-expansion operates on parsed AST nodes via the `configure` method
-    fn configure_tokens(&self, stream: &AttrAnnotatedTokenStream) -> AttrAnnotatedTokenStream {
-        fn can_skip(stream: &AttrAnnotatedTokenStream) -> bool {
+    fn configure_tokens(&self, stream: &AttrTokenStream) -> AttrTokenStream {
+        fn can_skip(stream: &AttrTokenStream) -> bool {
             stream.0.iter().all(|tree| match tree {
-                AttrAnnotatedTokenTree::Attributes(_) => false,
-                AttrAnnotatedTokenTree::Token(..) => true,
-                AttrAnnotatedTokenTree::Delimited(_, _, inner) => can_skip(inner),
+                AttrTokenTree::Attributes(_) => false,
+                AttrTokenTree::Token(..) => true,
+                AttrTokenTree::Delimited(_, _, inner) => can_skip(inner),
             })
         }
 
@@ -291,35 +291,35 @@ impl<'a> StripUnconfigured<'a> {
             .0
             .iter()
             .flat_map(|tree| match tree.clone() {
-                AttrAnnotatedTokenTree::Attributes(mut data) => {
+                AttrTokenTree::Attributes(mut data) => {
                     data.attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
 
                     if self.in_cfg(&data.attrs) {
                         data.tokens = LazyTokenStream::new(
                             self.configure_tokens(&data.tokens.create_token_stream()),
                         );
-                        Some(AttrAnnotatedTokenTree::Attributes(data)).into_iter()
+                        Some(AttrTokenTree::Attributes(data)).into_iter()
                     } else {
                         None.into_iter()
                     }
                 }
-                AttrAnnotatedTokenTree::Delimited(sp, delim, mut inner) => {
+                AttrTokenTree::Delimited(sp, delim, mut inner) => {
                     inner = self.configure_tokens(&inner);
-                    Some(AttrAnnotatedTokenTree::Delimited(sp, delim, inner))
+                    Some(AttrTokenTree::Delimited(sp, delim, inner))
                         .into_iter()
                 }
-                AttrAnnotatedTokenTree::Token(ref token, _) if let TokenKind::Interpolated(ref nt) = token.kind => {
+                AttrTokenTree::Token(ref token, _) if let TokenKind::Interpolated(ref nt) = token.kind => {
                     panic!(
                         "Nonterminal should have been flattened at {:?}: {:?}",
                         token.span, nt
                     );
                 }
-                AttrAnnotatedTokenTree::Token(token, spacing) => {
-                    Some(AttrAnnotatedTokenTree::Token(token, spacing)).into_iter()
+                AttrTokenTree::Token(token, spacing) => {
+                    Some(AttrTokenTree::Token(token, spacing)).into_iter()
                 }
             })
             .collect();
-        AttrAnnotatedTokenStream::new(trees)
+        AttrTokenStream::new(trees)
     }
 
     /// Parse and expand all `cfg_attr` attributes into a list of attributes
@@ -404,17 +404,17 @@ impl<'a> StripUnconfigured<'a> {
         };
         let pound_span = pound_token.span;
 
-        let mut trees = vec![AttrAnnotatedTokenTree::Token(pound_token, Spacing::Alone)];
+        let mut trees = vec![AttrTokenTree::Token(pound_token, Spacing::Alone)];
         if attr.style == AttrStyle::Inner {
             // For inner attributes, we do the same thing for the `!` in `#![some_attr]`
             let TokenTree::Token(bang_token @ Token { kind: TokenKind::Not, .. }, _) = orig_trees.next().unwrap() else {
                 panic!("Bad tokens for attribute {:?}", attr);
             };
-            trees.push(AttrAnnotatedTokenTree::Token(bang_token, Spacing::Alone));
+            trees.push(AttrTokenTree::Token(bang_token, Spacing::Alone));
         }
         // We don't really have a good span to use for the synthesized `[]`
         // in `#[attr]`, so just use the span of the `#` token.
-        let bracket_group = AttrAnnotatedTokenTree::Delimited(
+        let bracket_group = AttrTokenTree::Delimited(
             DelimSpan::from_single(pound_span),
             Delimiter::Bracket,
             item.tokens
@@ -423,7 +423,7 @@ impl<'a> StripUnconfigured<'a> {
                 .create_token_stream(),
         );
         trees.push(bracket_group);
-        let tokens = Some(LazyTokenStream::new(AttrAnnotatedTokenStream::new(trees)));
+        let tokens = Some(LazyTokenStream::new(AttrTokenStream::new(trees)));
         let attr = attr::mk_attr_from_item(item, tokens, attr.style, item_span);
         if attr.has_name(sym::crate_type) {
             self.sess.parse_sess.buffer_lint(
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index 77a6bde1c164..0cd742f63502 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -303,7 +303,7 @@ impl<'a> Parser<'a> {
                 // If we are currently capturing tokens, mark the location of this inner attribute.
                 // If capturing ends up creating a `LazyTokenStream`, we will include
                 // this replace range with it, removing the inner attribute from the final
-                // `AttrAnnotatedTokenStream`. Inner attributes are stored in the parsed AST note.
+                // `AttrTokenStream`. Inner attributes are stored in the parsed AST note.
                 // During macro expansion, they are selectively inserted back into the
                 // token stream (the first inner attribute is removed each time we invoke the
                 // corresponding macro).
diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs
index 6a78772643a3..a902e57ca2ae 100644
--- a/compiler/rustc_parse/src/parser/attr_wrapper.rs
+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs
@@ -1,7 +1,7 @@
 use super::{Capturing, FlatToken, ForceCollect, Parser, ReplaceRange, TokenCursor, TrailingToken};
 use rustc_ast::token::{self, Delimiter, Token, TokenKind};
-use rustc_ast::tokenstream::{AttrAnnotatedTokenStream, AttributesData, CreateTokenStream};
-use rustc_ast::tokenstream::{AttrAnnotatedTokenTree, DelimSpan, LazyTokenStream, Spacing};
+use rustc_ast::tokenstream::{AttrTokenStream, AttributesData, CreateTokenStream};
+use rustc_ast::tokenstream::{AttrTokenTree, DelimSpan, LazyTokenStream, Spacing};
 use rustc_ast::{self as ast};
 use rustc_ast::{AttrVec, Attribute, HasAttrs, HasTokens};
 use rustc_errors::PResult;
@@ -100,7 +100,7 @@ struct LazyTokenStreamImpl {
 rustc_data_structures::static_assert_size!(LazyTokenStreamImpl, 144);
 
 impl CreateTokenStream for LazyTokenStreamImpl {
-    fn create_token_stream(&self) -> AttrAnnotatedTokenStream {
+    fn create_token_stream(&self) -> AttrTokenStream {
         // The token produced by the final call to `{,inlined_}next` was not
         // actually consumed by the callback. The combination of chaining the
         // initial token and using `take` produces the desired result - we
@@ -298,7 +298,7 @@ impl<'a> Parser<'a> {
         // If we 'broke' the last token (e.g. breaking a '>>' token to two '>' tokens),
         // then extend the range of captured tokens to include it, since the parser
         // was not actually bumped past it. When the `LazyTokenStream` gets converted
-        // into an `AttrAnnotatedTokenStream`, we will create the proper token.
+        // into an `AttrTokenStream`, we will create the proper token.
         if self.token_cursor.break_last_token {
             assert_eq!(
                 trailing,
@@ -317,7 +317,7 @@ impl<'a> Parser<'a> {
         } else {
             // Grab any replace ranges that occur *inside* the current AST node.
             // We will perform the actual replacement when we convert the `LazyTokenStream`
-            // to an `AttrAnnotatedTokenStream`
+            // to an `AttrTokenStream`.
             let start_calls: u32 = cursor_snapshot_next_calls.try_into().unwrap();
             self.capture_state.replace_ranges[replace_ranges_start..replace_ranges_end]
                 .iter()
@@ -392,12 +392,12 @@ impl<'a> Parser<'a> {
 fn make_token_stream(
     mut iter: impl Iterator,
     break_last_token: bool,
-) -> AttrAnnotatedTokenStream {
+) -> AttrTokenStream {
     #[derive(Debug)]
     struct FrameData {
         // This is `None` for the first frame, `Some` for all others.
         open_delim_sp: Option<(Delimiter, Span)>,
-        inner: Vec,
+        inner: Vec,
     }
     let mut stack = vec![FrameData { open_delim_sp: None, inner: vec![] }];
     let mut token_and_spacing = iter.next();
@@ -418,8 +418,8 @@ fn make_token_stream(
                     open_delim, span
                 );
                 let dspan = DelimSpan::from_pair(open_sp, span);
-                let stream = AttrAnnotatedTokenStream::new(frame_data.inner);
-                let delimited = AttrAnnotatedTokenTree::Delimited(dspan, delim, stream);
+                let stream = AttrTokenStream::new(frame_data.inner);
+                let delimited = AttrTokenTree::Delimited(dspan, delim, stream);
                 stack
                     .last_mut()
                     .unwrap_or_else(|| {
@@ -432,12 +432,12 @@ fn make_token_stream(
                 .last_mut()
                 .expect("Bottom token frame is missing!")
                 .inner
-                .push(AttrAnnotatedTokenTree::Token(token, spacing)),
+                .push(AttrTokenTree::Token(token, spacing)),
             FlatToken::AttrTarget(data) => stack
                 .last_mut()
                 .expect("Bottom token frame is missing!")
                 .inner
-                .push(AttrAnnotatedTokenTree::Attributes(data)),
+                .push(AttrTokenTree::Attributes(data)),
             FlatToken::Empty => {}
         }
         token_and_spacing = iter.next();
@@ -445,21 +445,20 @@ fn make_token_stream(
     let mut final_buf = stack.pop().expect("Missing final buf!");
     if break_last_token {
         let last_token = final_buf.inner.pop().unwrap();
-        if let AttrAnnotatedTokenTree::Token(last_token, spacing) = last_token {
+        if let AttrTokenTree::Token(last_token, spacing) = last_token {
             let unglued_first = last_token.kind.break_two_token_op().unwrap().0;
 
             // An 'unglued' token is always two ASCII characters
             let mut first_span = last_token.span.shrink_to_lo();
             first_span = first_span.with_hi(first_span.lo() + rustc_span::BytePos(1));
 
-            final_buf.inner.push(AttrAnnotatedTokenTree::Token(
-                Token::new(unglued_first, first_span),
-                spacing,
-            ));
+            final_buf
+                .inner
+                .push(AttrTokenTree::Token(Token::new(unglued_first, first_span), spacing));
         } else {
             panic!("Unexpected last token {:?}", last_token)
         }
     }
     assert!(stack.is_empty(), "Stack should be empty: final_buf={:?} stack={:?}", final_buf, stack);
-    AttrAnnotatedTokenStream::new(final_buf.inner)
+    AttrTokenStream::new(final_buf.inner)
 }
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 5c8f374255c7..af8f55832a22 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -170,7 +170,7 @@ pub struct ClosureSpans {
 /// attribute, we parse a nested AST node that has `#[cfg]` or `#[cfg_attr]`
 /// In this case, we use a `ReplaceRange` to replace the entire inner AST node
 /// with `FlatToken::AttrTarget`, allowing us to perform eager cfg-expansion
-/// on an `AttrAnnotatedTokenStream`
+/// on an `AttrTokenStream`.
 ///
 /// 2. When we parse an inner attribute while collecting tokens. We
 /// remove inner attributes from the token stream entirely, and
@@ -183,7 +183,7 @@ pub type ReplaceRange = (Range, Vec<(FlatToken, Spacing)>);
 
 /// Controls how we capture tokens. Capturing can be expensive,
 /// so we try to avoid performing capturing in cases where
-/// we will never need an `AttrAnnotatedTokenStream`
+/// we will never need an `AttrTokenStream`.
 #[derive(Copy, Clone)]
 pub enum Capturing {
     /// We aren't performing any capturing - this is the default mode.
@@ -1464,11 +1464,11 @@ pub fn emit_unclosed_delims(unclosed_delims: &mut Vec, sess: &Pa
     }
 }
 
-/// A helper struct used when building an `AttrAnnotatedTokenStream` from
+/// A helper struct used when building an `AttrTokenStream` from
 /// a `LazyTokenStream`. Both delimiter and non-delimited tokens
 /// are stored as `FlatToken::Token`. A vector of `FlatToken`s
-/// is then 'parsed' to build up an `AttrAnnotatedTokenStream` with nested
-/// `AttrAnnotatedTokenTree::Delimited` tokens
+/// is then 'parsed' to build up an `AttrTokenStream` with nested
+/// `AttrTokenTree::Delimited` tokens.
 #[derive(Debug, Clone)]
 pub enum FlatToken {
     /// A token - this holds both delimiter (e.g. '{' and '}')
@@ -1476,11 +1476,11 @@ pub enum FlatToken {
     Token(Token),
     /// Holds the `AttributesData` for an AST node. The
     /// `AttributesData` is inserted directly into the
-    /// constructed `AttrAnnotatedTokenStream` as
-    /// an `AttrAnnotatedTokenTree::Attributes`
+    /// constructed `AttrTokenStream` as
+    /// an `AttrTokenTree::Attributes`.
     AttrTarget(AttributesData),
     /// A special 'empty' token that is ignored during the conversion
-    /// to an `AttrAnnotatedTokenStream`. This is used to simplify the
+    /// to an `AttrTokenStream`. This is used to simplify the
     /// handling of replace ranges.
     Empty,
 }

From b0cfeec2931cfb3bc9f8b11510684fb2fedee731 Mon Sep 17 00:00:00 2001
From: Luis Cardoso <61982523+LuisCardosoOliveira@users.noreply.github.com>
Date: Fri, 26 Aug 2022 16:06:27 +0200
Subject: [PATCH 4383/5092] translations(rustc_session): migrates session.rs
 and config.rs

---
 compiler/rustc_session/src/config.rs | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 8bb3878fbbb4..0018346c72c4 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -1,6 +1,7 @@
 //! Contains infrastructure for configuring the compiler, including parsing
 //! command-line options.
 
+use crate::errors::TargetDataLayoutParseError;
 pub use crate::options::*;
 
 use crate::search_paths::SearchPath;
@@ -898,7 +899,7 @@ fn default_configuration(sess: &Session) -> CrateConfig {
     let max_atomic_width = sess.target.max_atomic_width();
     let atomic_cas = sess.target.atomic_cas;
     let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
-        sess.emit_fatal(err);
+        sess.emit_fatal(TargetDataLayoutParseError { err });
     });
 
     let mut ret = CrateConfig::default();

From 208ca93cdad849e2659effbee1bfb0ece639f4a8 Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote 
Date: Fri, 9 Sep 2022 16:23:39 +1000
Subject: [PATCH 4384/5092] Change return type of `Attribute::tokens`.

The `AttrTokenStream` is always immediately turned into a `TokenStream`.
---
 compiler/rustc_ast/src/attr/mod.rs    | 16 +++++++---------
 compiler/rustc_ast/src/tokenstream.rs |  4 ++--
 compiler/rustc_expand/src/config.rs   |  2 +-
 3 files changed, 10 insertions(+), 12 deletions(-)

diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index e0bb47539329..8f1d7a71f15b 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -7,7 +7,6 @@ use crate::ast::{MacArgs, MacArgsEq, MacDelimiter, MetaItem, MetaItemKind, Neste
 use crate::ast::{Path, PathSegment};
 use crate::ptr::P;
 use crate::token::{self, CommentKind, Delimiter, Token};
-use crate::tokenstream::{AttrTokenStream, AttrTokenTree};
 use crate::tokenstream::{DelimSpan, Spacing, TokenTree};
 use crate::tokenstream::{LazyTokenStream, TokenStream};
 use crate::util::comments;
@@ -296,19 +295,18 @@ impl Attribute {
         }
     }
 
-    pub fn tokens(&self) -> AttrTokenStream {
+    pub fn tokens(&self) -> TokenStream {
         match self.kind {
             AttrKind::Normal(ref normal) => normal
                 .tokens
                 .as_ref()
                 .unwrap_or_else(|| panic!("attribute is missing tokens: {:?}", self))
-                .create_token_stream(),
-            AttrKind::DocComment(comment_kind, data) => {
-                AttrTokenStream::new(vec![AttrTokenTree::Token(
-                    Token::new(token::DocComment(comment_kind, self.style, data), self.span),
-                    Spacing::Alone,
-                )])
-            }
+                .create_token_stream()
+                .to_tokenstream(),
+            AttrKind::DocComment(comment_kind, data) => TokenStream::new(vec![TokenTree::Token(
+                Token::new(token::DocComment(comment_kind, self.style, data), self.span),
+                Spacing::Alone,
+            )]),
         }
     }
 }
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index 4088e50fbe2c..231bd000db0d 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -255,7 +255,7 @@ impl AttrTokenStream {
 
                                 let mut builder = TokenStreamBuilder::new();
                                 for inner_attr in inner_attrs {
-                                    builder.push(inner_attr.tokens().to_tokenstream());
+                                    builder.push(inner_attr.tokens());
                                 }
                                 builder.push(delim_tokens.clone());
                                 *tree = TokenTree::Delimited(*span, *delim, builder.build());
@@ -273,7 +273,7 @@ impl AttrTokenStream {
                     let mut flat: SmallVec<[_; 1]> = SmallVec::new();
                     for attr in outer_attrs {
                         // FIXME: Make this more efficient
-                        flat.extend(attr.tokens().to_tokenstream().0.clone().iter().cloned());
+                        flat.extend(attr.tokens().0.clone().iter().cloned());
                     }
                     flat.extend(target_tokens);
                     flat.into_iter()
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 5d78a4a59ecd..43a1a7caa2fd 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -388,7 +388,7 @@ impl<'a> StripUnconfigured<'a> {
         attr: &Attribute,
         (item, item_span): (ast::AttrItem, Span),
     ) -> Attribute {
-        let orig_tokens = attr.tokens().to_tokenstream();
+        let orig_tokens = attr.tokens();
 
         // We are taking an attribute of the form `#[cfg_attr(pred, attr)]`
         // and producing an attribute of the form `#[attr]`. We

From 81eaf877d651eb5d43829b536c0e212161301007 Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote 
Date: Fri, 9 Sep 2022 16:40:25 +1000
Subject: [PATCH 4385/5092] Tweak some formatting.

---
 compiler/rustc_ast/src/tokenstream.rs | 14 +++++---------
 1 file changed, 5 insertions(+), 9 deletions(-)

diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index 231bd000db0d..debcd172b1a5 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -217,12 +217,8 @@ impl AttrTokenStream {
                     let mut inner_attrs = Vec::new();
                     for attr in &data.attrs {
                         match attr.style {
-                            crate::AttrStyle::Outer => {
-                                outer_attrs.push(attr);
-                            }
-                            crate::AttrStyle::Inner => {
-                                inner_attrs.push(attr);
-                            }
+                            crate::AttrStyle::Outer => outer_attrs.push(attr),
+                            crate::AttrStyle::Inner => inner_attrs.push(attr),
                         }
                     }
 
@@ -239,9 +235,9 @@ impl AttrTokenStream {
                         // Check the last two trees (to account for a trailing semi)
                         for tree in target_tokens.iter_mut().rev().take(2) {
                             if let TokenTree::Delimited(span, delim, delim_tokens) = tree {
-                                // Inner attributes are only supported on extern blocks, functions, impls,
-                                // and modules. All of these have their inner attributes placed at
-                                // the beginning of the rightmost outermost braced group:
+                                // Inner attributes are only supported on extern blocks, functions,
+                                // impls, and modules. All of these have their inner attributes
+                                // placed at the beginning of the rightmost outermost braced group:
                                 // e.g. fn foo() { #![my_attr} }
                                 //
                                 // Therefore, we can insert them back into the right location

From f6c9e1df5937a8f4dad6739368e4eb5ed453dddd Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote 
Date: Fri, 9 Sep 2022 16:53:17 +1000
Subject: [PATCH 4386/5092] Inline and remove `TokenStream::opt_from_ast`.

---
 compiler/rustc_ast/src/lib.rs         |  1 +
 compiler/rustc_ast/src/tokenstream.rs | 27 ++++++++++++---------------
 2 files changed, 13 insertions(+), 15 deletions(-)

diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index e5435e3a3d4f..4d3620ee8b0f 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -15,6 +15,7 @@
 #![feature(if_let_guard)]
 #![cfg_attr(bootstrap, feature(label_break_value))]
 #![feature(let_chains)]
+#![feature(let_else)]
 #![feature(min_specialization)]
 #![feature(negative_impls)]
 #![feature(slice_internals)]
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index debcd172b1a5..b27eba9620da 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -410,19 +410,6 @@ impl TokenStream {
         TokenStream(Lrc::new(self.0.iter().enumerate().map(|(i, tree)| f(i, tree)).collect()))
     }
 
-    fn opt_from_ast(node: &(impl HasAttrs + HasTokens)) -> Option {
-        let tokens = node.tokens()?;
-        let attrs = node.attrs();
-        let attr_stream = if attrs.is_empty() {
-            tokens.create_token_stream()
-        } else {
-            let attr_data =
-                AttributesData { attrs: attrs.iter().cloned().collect(), tokens: tokens.clone() };
-            AttrTokenStream::new(vec![AttrTokenTree::Attributes(attr_data)])
-        };
-        Some(attr_stream.to_tokenstream())
-    }
-
     // Create a token stream containing a single token with alone spacing.
     pub fn token_alone(kind: TokenKind, span: Span) -> TokenStream {
         TokenStream::new(vec![TokenTree::token_alone(kind, span)])
@@ -439,8 +426,18 @@ impl TokenStream {
     }
 
     pub fn from_ast(node: &(impl HasAttrs + HasSpan + HasTokens + fmt::Debug)) -> TokenStream {
-        TokenStream::opt_from_ast(node)
-            .unwrap_or_else(|| panic!("missing tokens for node at {:?}: {:?}", node.span(), node))
+        let Some(tokens) = node.tokens() else {
+            panic!("missing tokens for node at {:?}: {:?}", node.span(), node);
+        };
+        let attrs = node.attrs();
+        let attr_stream = if attrs.is_empty() {
+            tokens.create_token_stream()
+        } else {
+            let attr_data =
+                AttributesData { attrs: attrs.iter().cloned().collect(), tokens: tokens.clone() };
+            AttrTokenStream::new(vec![AttrTokenTree::Attributes(attr_data)])
+        };
+        attr_stream.to_tokenstream()
     }
 
     pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream {

From d2df07c425f9b390c33e0ac31674ce4794352b3a Mon Sep 17 00:00:00 2001
From: Nicholas Nethercote 
Date: Fri, 9 Sep 2022 17:15:53 +1000
Subject: [PATCH 4387/5092] Rename `{Create,Lazy}TokenStream` as
 `{To,Lazy}AttrTokenStream`.

`To` is better than `Create` for indicating that this is a non-consuming
conversion, rather than creating something out of nothing.

And the addition of `Attr` is because the current names makes them sound
like they relate to `TokenStream`, but really they relate to
`AttrTokenStream`.
---
 compiler/rustc_ast/src/ast.rs                 | 28 ++++++-------
 compiler/rustc_ast/src/ast_traits.rs          | 38 ++++++++---------
 compiler/rustc_ast/src/attr/mod.rs            |  6 +--
 compiler/rustc_ast/src/mut_visit.rs           | 11 +++--
 compiler/rustc_ast/src/tokenstream.rs         | 42 +++++++++----------
 compiler/rustc_expand/src/config.rs           | 14 +++----
 compiler/rustc_parse/src/parser/attr.rs       |  2 +-
 .../rustc_parse/src/parser/attr_wrapper.rs    | 20 ++++-----
 compiler/rustc_parse/src/parser/mod.rs        |  4 +-
 9 files changed, 84 insertions(+), 81 deletions(-)

diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index e38572f609b3..c9354dbb684a 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -24,7 +24,7 @@ pub use UnsafeSource::*;
 
 use crate::ptr::P;
 use crate::token::{self, CommentKind, Delimiter};
-use crate::tokenstream::{DelimSpan, LazyTokenStream, TokenStream};
+use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_data_structures::sync::Lrc;
@@ -92,7 +92,7 @@ pub struct Path {
     /// The segments in the path: the things separated by `::`.
     /// Global paths begin with `kw::PathRoot`.
     pub segments: Vec,
-    pub tokens: Option,
+    pub tokens: Option,
 }
 
 impl PartialEq for Path {
@@ -564,7 +564,7 @@ pub struct Block {
     /// Distinguishes between `unsafe { ... }` and `{ ... }`.
     pub rules: BlockCheckMode,
     pub span: Span,
-    pub tokens: Option,
+    pub tokens: Option,
     /// The following *isn't* a parse error, but will cause multiple errors in following stages.
     /// ```compile_fail
     /// let x = {
@@ -583,7 +583,7 @@ pub struct Pat {
     pub id: NodeId,
     pub kind: PatKind,
     pub span: Span,
-    pub tokens: Option,
+    pub tokens: Option,
 }
 
 impl Pat {
@@ -967,8 +967,8 @@ impl Stmt {
     /// a trailing semicolon.
     ///
     /// This only modifies the parsed AST struct, not the attached
-    /// `LazyTokenStream`. The parser is responsible for calling
-    /// `CreateTokenStream::add_trailing_semi` when there is actually
+    /// `LazyAttrTokenStream`. The parser is responsible for calling
+    /// `ToAttrTokenStream::add_trailing_semi` when there is actually
     /// a semicolon in the tokenstream.
     pub fn add_trailing_semicolon(mut self) -> Self {
         self.kind = match self.kind {
@@ -1014,7 +1014,7 @@ pub struct MacCallStmt {
     pub mac: P,
     pub style: MacStmtStyle,
     pub attrs: AttrVec,
-    pub tokens: Option,
+    pub tokens: Option,
 }
 
 #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug)]
@@ -1039,7 +1039,7 @@ pub struct Local {
     pub kind: LocalKind,
     pub span: Span,
     pub attrs: AttrVec,
-    pub tokens: Option,
+    pub tokens: Option,
 }
 
 #[derive(Clone, Encodable, Decodable, Debug)]
@@ -1138,7 +1138,7 @@ pub struct Expr {
     pub kind: ExprKind,
     pub span: Span,
     pub attrs: AttrVec,
-    pub tokens: Option,
+    pub tokens: Option,
 }
 
 impl Expr {
@@ -1997,7 +1997,7 @@ pub struct Ty {
     pub id: NodeId,
     pub kind: TyKind,
     pub span: Span,
-    pub tokens: Option,
+    pub tokens: Option,
 }
 
 impl Clone for Ty {
@@ -2562,7 +2562,7 @@ impl Decodable for AttrId {
 pub struct AttrItem {
     pub path: Path,
     pub args: MacArgs,
-    pub tokens: Option,
+    pub tokens: Option,
 }
 
 /// A list of attributes.
@@ -2582,7 +2582,7 @@ pub struct Attribute {
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct NormalAttr {
     pub item: AttrItem,
-    pub tokens: Option,
+    pub tokens: Option,
 }
 
 #[derive(Clone, Encodable, Decodable, Debug)]
@@ -2633,7 +2633,7 @@ impl PolyTraitRef {
 pub struct Visibility {
     pub kind: VisibilityKind,
     pub span: Span,
-    pub tokens: Option,
+    pub tokens: Option,
 }
 
 #[derive(Clone, Encodable, Decodable, Debug)]
@@ -2719,7 +2719,7 @@ pub struct Item {
     ///
     /// Note that the tokens here do not include the outer attributes, but will
     /// include inner attributes.
-    pub tokens: Option,
+    pub tokens: Option,
 }
 
 impl Item {
diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs
index 79f5820230ed..1b31be07f7ad 100644
--- a/compiler/rustc_ast/src/ast_traits.rs
+++ b/compiler/rustc_ast/src/ast_traits.rs
@@ -4,7 +4,7 @@
 
 use crate::ptr::P;
 use crate::token::Nonterminal;
-use crate::tokenstream::LazyTokenStream;
+use crate::tokenstream::LazyAttrTokenStream;
 use crate::{Arm, Crate, ExprField, FieldDef, GenericParam, Param, PatField, Variant};
 use crate::{AssocItem, Expr, ForeignItem, Item, NodeId};
 use crate::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility};
@@ -124,18 +124,18 @@ impl HasSpan for AttrItem {
 
 /// A trait for AST nodes having (or not having) collected tokens.
 pub trait HasTokens {
-    fn tokens(&self) -> Option<&LazyTokenStream>;
-    fn tokens_mut(&mut self) -> Option<&mut Option>;
+    fn tokens(&self) -> Option<&LazyAttrTokenStream>;
+    fn tokens_mut(&mut self) -> Option<&mut Option>;
 }
 
 macro_rules! impl_has_tokens {
     ($($T:ty),+ $(,)?) => {
         $(
             impl HasTokens for $T {
-                fn tokens(&self) -> Option<&LazyTokenStream> {
+                fn tokens(&self) -> Option<&LazyAttrTokenStream> {
                     self.tokens.as_ref()
                 }
-                fn tokens_mut(&mut self) -> Option<&mut Option> {
+                fn tokens_mut(&mut self) -> Option<&mut Option> {
                     Some(&mut self.tokens)
                 }
             }
@@ -147,10 +147,10 @@ macro_rules! impl_has_tokens_none {
     ($($T:ty),+ $(,)?) => {
         $(
             impl HasTokens for $T {
-                fn tokens(&self) -> Option<&LazyTokenStream> {
+                fn tokens(&self) -> Option<&LazyAttrTokenStream> {
                     None
                 }
-                fn tokens_mut(&mut self) -> Option<&mut Option> {
+                fn tokens_mut(&mut self) -> Option<&mut Option> {
                     None
                 }
             }
@@ -162,25 +162,25 @@ impl_has_tokens!(AssocItem, AttrItem, Block, Expr, ForeignItem, Item, Pat, Path,
 impl_has_tokens_none!(Arm, ExprField, FieldDef, GenericParam, Param, PatField, Variant);
 
 impl> HasTokens for T {
-    fn tokens(&self) -> Option<&LazyTokenStream> {
+    fn tokens(&self) -> Option<&LazyAttrTokenStream> {
         self.ast_deref().tokens()
     }
-    fn tokens_mut(&mut self) -> Option<&mut Option> {
+    fn tokens_mut(&mut self) -> Option<&mut Option> {
         self.ast_deref_mut().tokens_mut()
     }
 }
 
 impl HasTokens for Option {
-    fn tokens(&self) -> Option<&LazyTokenStream> {
+    fn tokens(&self) -> Option<&LazyAttrTokenStream> {
         self.as_ref().and_then(|inner| inner.tokens())
     }
-    fn tokens_mut(&mut self) -> Option<&mut Option> {
+    fn tokens_mut(&mut self) -> Option<&mut Option> {
         self.as_mut().and_then(|inner| inner.tokens_mut())
     }
 }
 
 impl HasTokens for StmtKind {
-    fn tokens(&self) -> Option<&LazyTokenStream> {
+    fn tokens(&self) -> Option<&LazyAttrTokenStream> {
         match self {
             StmtKind::Local(local) => local.tokens.as_ref(),
             StmtKind::Item(item) => item.tokens(),
@@ -189,7 +189,7 @@ impl HasTokens for StmtKind {
             StmtKind::MacCall(mac) => mac.tokens.as_ref(),
         }
     }
-    fn tokens_mut(&mut self) -> Option<&mut Option> {
+    fn tokens_mut(&mut self) -> Option<&mut Option> {
         match self {
             StmtKind::Local(local) => Some(&mut local.tokens),
             StmtKind::Item(item) => item.tokens_mut(),
@@ -201,16 +201,16 @@ impl HasTokens for StmtKind {
 }
 
 impl HasTokens for Stmt {
-    fn tokens(&self) -> Option<&LazyTokenStream> {
+    fn tokens(&self) -> Option<&LazyAttrTokenStream> {
         self.kind.tokens()
     }
-    fn tokens_mut(&mut self) -> Option<&mut Option> {
+    fn tokens_mut(&mut self) -> Option<&mut Option> {
         self.kind.tokens_mut()
     }
 }
 
 impl HasTokens for Attribute {
-    fn tokens(&self) -> Option<&LazyTokenStream> {
+    fn tokens(&self) -> Option<&LazyAttrTokenStream> {
         match &self.kind {
             AttrKind::Normal(normal) => normal.tokens.as_ref(),
             kind @ AttrKind::DocComment(..) => {
@@ -218,7 +218,7 @@ impl HasTokens for Attribute {
             }
         }
     }
-    fn tokens_mut(&mut self) -> Option<&mut Option> {
+    fn tokens_mut(&mut self) -> Option<&mut Option> {
         Some(match &mut self.kind {
             AttrKind::Normal(normal) => &mut normal.tokens,
             kind @ AttrKind::DocComment(..) => {
@@ -229,7 +229,7 @@ impl HasTokens for Attribute {
 }
 
 impl HasTokens for Nonterminal {
-    fn tokens(&self) -> Option<&LazyTokenStream> {
+    fn tokens(&self) -> Option<&LazyAttrTokenStream> {
         match self {
             Nonterminal::NtItem(item) => item.tokens(),
             Nonterminal::NtStmt(stmt) => stmt.tokens(),
@@ -243,7 +243,7 @@ impl HasTokens for Nonterminal {
             Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None,
         }
     }
-    fn tokens_mut(&mut self) -> Option<&mut Option> {
+    fn tokens_mut(&mut self) -> Option<&mut Option> {
         match self {
             Nonterminal::NtItem(item) => item.tokens_mut(),
             Nonterminal::NtStmt(stmt) => stmt.tokens_mut(),
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 8f1d7a71f15b..a40508494cdc 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -8,7 +8,7 @@ use crate::ast::{Path, PathSegment};
 use crate::ptr::P;
 use crate::token::{self, CommentKind, Delimiter, Token};
 use crate::tokenstream::{DelimSpan, Spacing, TokenTree};
-use crate::tokenstream::{LazyTokenStream, TokenStream};
+use crate::tokenstream::{LazyAttrTokenStream, TokenStream};
 use crate::util::comments;
 
 use rustc_index::bit_set::GrowableBitSet;
@@ -301,7 +301,7 @@ impl Attribute {
                 .tokens
                 .as_ref()
                 .unwrap_or_else(|| panic!("attribute is missing tokens: {:?}", self))
-                .create_token_stream()
+                .to_attr_token_stream()
                 .to_tokenstream(),
             AttrKind::DocComment(comment_kind, data) => TokenStream::new(vec![TokenTree::Token(
                 Token::new(token::DocComment(comment_kind, self.style, data), self.span),
@@ -353,7 +353,7 @@ pub fn mk_attr(style: AttrStyle, path: Path, args: MacArgs, span: Span) -> Attri
 
 pub fn mk_attr_from_item(
     item: AttrItem,
-    tokens: Option,
+    tokens: Option,
     style: AttrStyle,
     span: Span,
 ) -> Attribute {
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 27fb2d12760d..ad68d6e755e0 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -697,17 +697,20 @@ pub fn visit_attr_tts(AttrTokenStream(tts): &mut AttrTokenStream,
     }
 }
 
-pub fn visit_lazy_tts_opt_mut(lazy_tts: Option<&mut LazyTokenStream>, vis: &mut T) {
+pub fn visit_lazy_tts_opt_mut(
+    lazy_tts: Option<&mut LazyAttrTokenStream>,
+    vis: &mut T,
+) {
     if T::VISIT_TOKENS {
         if let Some(lazy_tts) = lazy_tts {
-            let mut tts = lazy_tts.create_token_stream();
+            let mut tts = lazy_tts.to_attr_token_stream();
             visit_attr_tts(&mut tts, vis);
-            *lazy_tts = LazyTokenStream::new(tts);
+            *lazy_tts = LazyAttrTokenStream::new(tts);
         }
     }
 }
 
-pub fn visit_lazy_tts(lazy_tts: &mut Option, vis: &mut T) {
+pub fn visit_lazy_tts(lazy_tts: &mut Option, vis: &mut T) {
     visit_lazy_tts_opt_mut(lazy_tts.as_mut(), vis);
 }
 
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index b27eba9620da..875cd620dfc6 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -121,12 +121,12 @@ where
     }
 }
 
-pub trait CreateTokenStream: sync::Send + sync::Sync {
-    fn create_token_stream(&self) -> AttrTokenStream;
+pub trait ToAttrTokenStream: sync::Send + sync::Sync {
+    fn to_attr_token_stream(&self) -> AttrTokenStream;
 }
 
-impl CreateTokenStream for AttrTokenStream {
-    fn create_token_stream(&self) -> AttrTokenStream {
+impl ToAttrTokenStream for AttrTokenStream {
+    fn to_attr_token_stream(&self) -> AttrTokenStream {
         self.clone()
     }
 }
@@ -135,40 +135,40 @@ impl CreateTokenStream for AttrTokenStream {
 /// of an actual `TokenStream` until it is needed.
 /// `Box` is here only to reduce the structure size.
 #[derive(Clone)]
-pub struct LazyTokenStream(Lrc>);
+pub struct LazyAttrTokenStream(Lrc>);
 
-impl LazyTokenStream {
-    pub fn new(inner: impl CreateTokenStream + 'static) -> LazyTokenStream {
-        LazyTokenStream(Lrc::new(Box::new(inner)))
+impl LazyAttrTokenStream {
+    pub fn new(inner: impl ToAttrTokenStream + 'static) -> LazyAttrTokenStream {
+        LazyAttrTokenStream(Lrc::new(Box::new(inner)))
     }
 
-    pub fn create_token_stream(&self) -> AttrTokenStream {
-        self.0.create_token_stream()
+    pub fn to_attr_token_stream(&self) -> AttrTokenStream {
+        self.0.to_attr_token_stream()
     }
 }
 
-impl fmt::Debug for LazyTokenStream {
+impl fmt::Debug for LazyAttrTokenStream {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "LazyTokenStream({:?})", self.create_token_stream())
+        write!(f, "LazyAttrTokenStream({:?})", self.to_attr_token_stream())
     }
 }
 
-impl Encodable for LazyTokenStream {
+impl Encodable for LazyAttrTokenStream {
     fn encode(&self, s: &mut S) {
         // Used by AST json printing.
-        Encodable::encode(&self.create_token_stream(), s);
+        Encodable::encode(&self.to_attr_token_stream(), s);
     }
 }
 
-impl Decodable for LazyTokenStream {
+impl Decodable for LazyAttrTokenStream {
     fn decode(_d: &mut D) -> Self {
-        panic!("Attempted to decode LazyTokenStream");
+        panic!("Attempted to decode LazyAttrTokenStream");
     }
 }
 
-impl HashStable for LazyTokenStream {
+impl HashStable for LazyAttrTokenStream {
     fn hash_stable(&self, _hcx: &mut CTX, _hasher: &mut StableHasher) {
-        panic!("Attempted to compute stable hash for LazyTokenStream");
+        panic!("Attempted to compute stable hash for LazyAttrTokenStream");
     }
 }
 
@@ -224,7 +224,7 @@ impl AttrTokenStream {
 
                     let mut target_tokens: Vec<_> = data
                         .tokens
-                        .create_token_stream()
+                        .to_attr_token_stream()
                         .to_tokenstream()
                         .0
                         .iter()
@@ -296,7 +296,7 @@ pub struct AttributesData {
     pub attrs: AttrVec,
     /// The underlying tokens for the attribute target that `attrs`
     /// are applied to
-    pub tokens: LazyTokenStream,
+    pub tokens: LazyAttrTokenStream,
 }
 
 /// A `TokenStream` is an abstract sequence of tokens, organized into [`TokenTree`]s.
@@ -431,7 +431,7 @@ impl TokenStream {
         };
         let attrs = node.attrs();
         let attr_stream = if attrs.is_empty() {
-            tokens.create_token_stream()
+            tokens.to_attr_token_stream()
         } else {
             let attr_data =
                 AttributesData { attrs: attrs.iter().cloned().collect(), tokens: tokens.clone() };
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 43a1a7caa2fd..7d30596a936f 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -4,7 +4,7 @@ use rustc_ast::ptr::P;
 use rustc_ast::token::{Delimiter, Token, TokenKind};
 use rustc_ast::tokenstream::{AttrTokenStream, AttrTokenTree};
 use rustc_ast::tokenstream::{DelimSpan, Spacing};
-use rustc_ast::tokenstream::{LazyTokenStream, TokenTree};
+use rustc_ast::tokenstream::{LazyAttrTokenStream, TokenTree};
 use rustc_ast::NodeId;
 use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem};
 use rustc_attr as attr;
@@ -259,8 +259,8 @@ impl<'a> StripUnconfigured<'a> {
     fn try_configure_tokens(&self, node: &mut T) {
         if self.config_tokens {
             if let Some(Some(tokens)) = node.tokens_mut() {
-                let attr_stream = tokens.create_token_stream();
-                *tokens = LazyTokenStream::new(self.configure_tokens(&attr_stream));
+                let attr_stream = tokens.to_attr_token_stream();
+                *tokens = LazyAttrTokenStream::new(self.configure_tokens(&attr_stream));
             }
         }
     }
@@ -295,8 +295,8 @@ impl<'a> StripUnconfigured<'a> {
                     data.attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
 
                     if self.in_cfg(&data.attrs) {
-                        data.tokens = LazyTokenStream::new(
-                            self.configure_tokens(&data.tokens.create_token_stream()),
+                        data.tokens = LazyAttrTokenStream::new(
+                            self.configure_tokens(&data.tokens.to_attr_token_stream()),
                         );
                         Some(AttrTokenTree::Attributes(data)).into_iter()
                     } else {
@@ -420,10 +420,10 @@ impl<'a> StripUnconfigured<'a> {
             item.tokens
                 .as_ref()
                 .unwrap_or_else(|| panic!("Missing tokens for {:?}", item))
-                .create_token_stream(),
+                .to_attr_token_stream(),
         );
         trees.push(bracket_group);
-        let tokens = Some(LazyTokenStream::new(AttrTokenStream::new(trees)));
+        let tokens = Some(LazyAttrTokenStream::new(AttrTokenStream::new(trees)));
         let attr = attr::mk_attr_from_item(item, tokens, attr.style, item_span);
         if attr.has_name(sym::crate_type) {
             self.sess.parse_sess.buffer_lint(
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index 0cd742f63502..a37f828eafb9 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -301,7 +301,7 @@ impl<'a> Parser<'a> {
             if let Some(attr) = attr {
                 let end_pos: u32 = self.token_cursor.num_next_calls.try_into().unwrap();
                 // If we are currently capturing tokens, mark the location of this inner attribute.
-                // If capturing ends up creating a `LazyTokenStream`, we will include
+                // If capturing ends up creating a `LazyAttrTokenStream`, we will include
                 // this replace range with it, removing the inner attribute from the final
                 // `AttrTokenStream`. Inner attributes are stored in the parsed AST note.
                 // During macro expansion, they are selectively inserted back into the
diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs
index a902e57ca2ae..5fdafd187c66 100644
--- a/compiler/rustc_parse/src/parser/attr_wrapper.rs
+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs
@@ -1,7 +1,7 @@
 use super::{Capturing, FlatToken, ForceCollect, Parser, ReplaceRange, TokenCursor, TrailingToken};
 use rustc_ast::token::{self, Delimiter, Token, TokenKind};
-use rustc_ast::tokenstream::{AttrTokenStream, AttributesData, CreateTokenStream};
-use rustc_ast::tokenstream::{AttrTokenTree, DelimSpan, LazyTokenStream, Spacing};
+use rustc_ast::tokenstream::{AttrTokenStream, AttributesData, ToAttrTokenStream};
+use rustc_ast::tokenstream::{AttrTokenTree, DelimSpan, LazyAttrTokenStream, Spacing};
 use rustc_ast::{self as ast};
 use rustc_ast::{AttrVec, Attribute, HasAttrs, HasTokens};
 use rustc_errors::PResult;
@@ -88,7 +88,7 @@ fn has_cfg_or_cfg_attr(attrs: &[Attribute]) -> bool {
 // This also makes `Parser` very cheap to clone, since
 // there is no intermediate collection buffer to clone.
 #[derive(Clone)]
-struct LazyTokenStreamImpl {
+struct LazyAttrTokenStreamImpl {
     start_token: (Token, Spacing),
     cursor_snapshot: TokenCursor,
     num_calls: usize,
@@ -97,10 +97,10 @@ struct LazyTokenStreamImpl {
 }
 
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(LazyTokenStreamImpl, 144);
+rustc_data_structures::static_assert_size!(LazyAttrTokenStreamImpl, 144);
 
-impl CreateTokenStream for LazyTokenStreamImpl {
-    fn create_token_stream(&self) -> AttrTokenStream {
+impl ToAttrTokenStream for LazyAttrTokenStreamImpl {
+    fn to_attr_token_stream(&self) -> AttrTokenStream {
         // The token produced by the final call to `{,inlined_}next` was not
         // actually consumed by the callback. The combination of chaining the
         // initial token and using `take` produces the desired result - we
@@ -179,7 +179,7 @@ impl CreateTokenStream for LazyTokenStreamImpl {
 impl<'a> Parser<'a> {
     /// Records all tokens consumed by the provided callback,
     /// including the current token. These tokens are collected
-    /// into a `LazyTokenStream`, and returned along with the result
+    /// into a `LazyAttrTokenStream`, and returned along with the result
     /// of the callback.
     ///
     /// Note: If your callback consumes an opening delimiter
@@ -297,7 +297,7 @@ impl<'a> Parser<'a> {
 
         // If we 'broke' the last token (e.g. breaking a '>>' token to two '>' tokens),
         // then extend the range of captured tokens to include it, since the parser
-        // was not actually bumped past it. When the `LazyTokenStream` gets converted
+        // was not actually bumped past it. When the `LazyAttrTokenStream` gets converted
         // into an `AttrTokenStream`, we will create the proper token.
         if self.token_cursor.break_last_token {
             assert_eq!(
@@ -316,7 +316,7 @@ impl<'a> Parser<'a> {
             Box::new([])
         } else {
             // Grab any replace ranges that occur *inside* the current AST node.
-            // We will perform the actual replacement when we convert the `LazyTokenStream`
+            // We will perform the actual replacement when we convert the `LazyAttrTokenStream`
             // to an `AttrTokenStream`.
             let start_calls: u32 = cursor_snapshot_next_calls.try_into().unwrap();
             self.capture_state.replace_ranges[replace_ranges_start..replace_ranges_end]
@@ -329,7 +329,7 @@ impl<'a> Parser<'a> {
                 .collect()
         };
 
-        let tokens = LazyTokenStream::new(LazyTokenStreamImpl {
+        let tokens = LazyAttrTokenStream::new(LazyAttrTokenStreamImpl {
             start_token,
             num_calls,
             cursor_snapshot,
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index af8f55832a22..4cb198561e0a 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -237,7 +237,7 @@ struct TokenCursor {
     // the trailing `>>` token. The `break_last_token`
     // field is used to track this token - it gets
     // appended to the captured stream when
-    // we evaluate a `LazyTokenStream`
+    // we evaluate a `LazyAttrTokenStream`.
     break_last_token: bool,
 }
 
@@ -1465,7 +1465,7 @@ pub fn emit_unclosed_delims(unclosed_delims: &mut Vec, sess: &Pa
 }
 
 /// A helper struct used when building an `AttrTokenStream` from
-/// a `LazyTokenStream`. Both delimiter and non-delimited tokens
+/// a `LazyAttrTokenStream`. Both delimiter and non-delimited tokens
 /// are stored as `FlatToken::Token`. A vector of `FlatToken`s
 /// is then 'parsed' to build up an `AttrTokenStream` with nested
 /// `AttrTokenTree::Delimited` tokens.

From 1933b74dbdd598edd3e54fcbf1d8b236ed5e82fc Mon Sep 17 00:00:00 2001
From: Akhilesh Singhania 
Date: Fri, 9 Sep 2022 11:30:40 +0200
Subject: [PATCH 4388/5092] doc: fix minor typo

---
 library/std/src/thread/mod.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index a17185b6f707..ceea6986e333 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -116,7 +116,7 @@
 //! Threads are able to have associated names for identification purposes. By default, spawned
 //! threads are unnamed. To specify a name for a thread, build the thread with [`Builder`] and pass
 //! the desired thread name to [`Builder::name`]. To retrieve the thread name from within the
-//! thread, use [`Thread::name`]. A couple examples of where the name of a thread gets used:
+//! thread, use [`Thread::name`]. A couple of examples where the name of a thread gets used:
 //!
 //! * If a panic occurs in a named thread, the thread name will be printed in the panic message.
 //! * The thread name is provided to the OS where applicable (e.g., `pthread_setname_np` in

From 262193e044a4604807a82d2a249dfbbb72a1bade Mon Sep 17 00:00:00 2001
From: joboet 
Date: Tue, 6 Sep 2022 10:44:05 +0200
Subject: [PATCH 4389/5092] std: use futex-based locks and thread parker on
 Hermit

---
 Cargo.lock                                    |   7 +-
 library/std/Cargo.toml                        |   2 +-
 library/std/src/sys/hermit/condvar.rs         |  90 --------
 library/std/src/sys/hermit/futex.rs           |  39 ++++
 library/std/src/sys/hermit/mod.rs             |  15 +-
 library/std/src/sys/hermit/mutex.rs           | 212 ------------------
 library/std/src/sys/hermit/rwlock.rs          | 143 ------------
 .../std/src/sys_common/thread_parker/mod.rs   |   1 +
 8 files changed, 53 insertions(+), 456 deletions(-)
 delete mode 100644 library/std/src/sys/hermit/condvar.rs
 create mode 100644 library/std/src/sys/hermit/futex.rs
 delete mode 100644 library/std/src/sys/hermit/mutex.rs
 delete mode 100644 library/std/src/sys/hermit/rwlock.rs

diff --git a/Cargo.lock b/Cargo.lock
index 90bcc2e4be42..4e0e72d34153 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1656,12 +1656,13 @@ dependencies = [
 
 [[package]]
 name = "hermit-abi"
-version = "0.2.0"
+version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ab7905ea95c6d9af62940f9d7dd9596d54c334ae2c15300c482051292d5637f"
+checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
 dependencies = [
  "compiler_builtins",
  "libc",
+ "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
 ]
 
@@ -4608,7 +4609,7 @@ dependencies = [
  "dlmalloc",
  "fortanix-sgx-abi",
  "hashbrown",
- "hermit-abi 0.2.0",
+ "hermit-abi 0.2.6",
  "libc",
  "miniz_oxide 0.4.0",
  "object 0.26.2",
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 3da9565a86d7..324ecc804773 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -42,7 +42,7 @@ dlmalloc = { version = "0.2.3", features = ['rustc-dep-of-std'] }
 fortanix-sgx-abi = { version = "0.5.0", features = ['rustc-dep-of-std'] }
 
 [target.'cfg(target_os = "hermit")'.dependencies]
-hermit-abi = { version = "0.2.0", features = ['rustc-dep-of-std'] }
+hermit-abi = { version = "0.2.6", features = ['rustc-dep-of-std'] }
 
 [target.wasm32-wasi.dependencies]
 wasi = { version = "0.11.0", features = ['rustc-dep-of-std'], default-features = false }
diff --git a/library/std/src/sys/hermit/condvar.rs b/library/std/src/sys/hermit/condvar.rs
deleted file mode 100644
index 22059ca0dbe1..000000000000
--- a/library/std/src/sys/hermit/condvar.rs
+++ /dev/null
@@ -1,90 +0,0 @@
-use crate::ffi::c_void;
-use crate::ptr;
-use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
-use crate::sys::hermit::abi;
-use crate::sys::locks::Mutex;
-use crate::sys_common::lazy_box::{LazyBox, LazyInit};
-use crate::time::Duration;
-
-// The implementation is inspired by Andrew D. Birrell's paper
-// "Implementing Condition Variables with Semaphores"
-
-pub struct Condvar {
-    counter: AtomicUsize,
-    sem1: *const c_void,
-    sem2: *const c_void,
-}
-
-pub(crate) type MovableCondvar = LazyBox;
-
-impl LazyInit for Condvar {
-    fn init() -> Box {
-        Box::new(Self::new())
-    }
-}
-
-unsafe impl Send for Condvar {}
-unsafe impl Sync for Condvar {}
-
-impl Condvar {
-    pub fn new() -> Self {
-        let mut condvar =
-            Self { counter: AtomicUsize::new(0), sem1: ptr::null(), sem2: ptr::null() };
-        unsafe {
-            let _ = abi::sem_init(&mut condvar.sem1, 0);
-            let _ = abi::sem_init(&mut condvar.sem2, 0);
-        }
-        condvar
-    }
-
-    pub unsafe fn notify_one(&self) {
-        if self.counter.load(SeqCst) > 0 {
-            self.counter.fetch_sub(1, SeqCst);
-            abi::sem_post(self.sem1);
-            abi::sem_timedwait(self.sem2, 0);
-        }
-    }
-
-    pub unsafe fn notify_all(&self) {
-        let counter = self.counter.swap(0, SeqCst);
-        for _ in 0..counter {
-            abi::sem_post(self.sem1);
-        }
-        for _ in 0..counter {
-            abi::sem_timedwait(self.sem2, 0);
-        }
-    }
-
-    pub unsafe fn wait(&self, mutex: &Mutex) {
-        self.counter.fetch_add(1, SeqCst);
-        mutex.unlock();
-        abi::sem_timedwait(self.sem1, 0);
-        abi::sem_post(self.sem2);
-        mutex.lock();
-    }
-
-    pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
-        self.counter.fetch_add(1, SeqCst);
-        mutex.unlock();
-        let millis = dur.as_millis().min(u32::MAX as u128) as u32;
-
-        let res = if millis > 0 {
-            abi::sem_timedwait(self.sem1, millis)
-        } else {
-            abi::sem_trywait(self.sem1)
-        };
-
-        abi::sem_post(self.sem2);
-        mutex.lock();
-        res == 0
-    }
-}
-
-impl Drop for Condvar {
-    fn drop(&mut self) {
-        unsafe {
-            let _ = abi::sem_destroy(self.sem1);
-            let _ = abi::sem_destroy(self.sem2);
-        }
-    }
-}
diff --git a/library/std/src/sys/hermit/futex.rs b/library/std/src/sys/hermit/futex.rs
new file mode 100644
index 000000000000..b64c174b06c6
--- /dev/null
+++ b/library/std/src/sys/hermit/futex.rs
@@ -0,0 +1,39 @@
+use super::abi;
+use crate::ptr::null;
+use crate::sync::atomic::AtomicU32;
+use crate::time::Duration;
+
+pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option) -> bool {
+    // Calculate the timeout as a relative timespec.
+    //
+    // Overflows are rounded up to an infinite timeout (None).
+    let timespec = timeout.and_then(|dur| {
+        Some(abi::timespec {
+            tv_sec: dur.as_secs().try_into().ok()?,
+            tv_nsec: dur.subsec_nanos().into(),
+        })
+    });
+
+    let r = unsafe {
+        abi::futex_wait(
+            futex.as_mut_ptr(),
+            expected,
+            timespec.as_ref().map_or(null(), |t| t as *const abi::timespec),
+            abi::FUTEX_RELATIVE_TIMEOUT,
+        )
+    };
+
+    r != -abi::errno::ETIMEDOUT
+}
+
+#[inline]
+pub fn futex_wake(futex: &AtomicU32) -> bool {
+    unsafe { abi::futex_wake(futex.as_mut_ptr(), 1) > 0 }
+}
+
+#[inline]
+pub fn futex_wake_all(futex: &AtomicU32) {
+    unsafe {
+        abi::futex_wake(futex.as_mut_ptr(), i32::MAX);
+    }
+}
diff --git a/library/std/src/sys/hermit/mod.rs b/library/std/src/sys/hermit/mod.rs
index 61da096ae163..827d82900eae 100644
--- a/library/std/src/sys/hermit/mod.rs
+++ b/library/std/src/sys/hermit/mod.rs
@@ -25,6 +25,7 @@ pub mod cmath;
 pub mod env;
 pub mod fd;
 pub mod fs;
+pub mod futex;
 #[path = "../unsupported/io.rs"]
 pub mod io;
 pub mod memchr;
@@ -45,14 +46,14 @@ pub mod thread_local_dtor;
 pub mod thread_local_key;
 pub mod time;
 
-mod condvar;
-mod mutex;
-mod rwlock;
-
+#[path = "../unix/locks"]
 pub mod locks {
-    pub use super::condvar::*;
-    pub use super::mutex::*;
-    pub use super::rwlock::*;
+    mod futex_condvar;
+    mod futex_mutex;
+    mod futex_rwlock;
+    pub(crate) use futex_condvar::MovableCondvar;
+    pub(crate) use futex_mutex::{MovableMutex, Mutex};
+    pub(crate) use futex_rwlock::{MovableRwLock, RwLock};
 }
 
 use crate::io::ErrorKind;
diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs
deleted file mode 100644
index 30c8fc4562d5..000000000000
--- a/library/std/src/sys/hermit/mutex.rs
+++ /dev/null
@@ -1,212 +0,0 @@
-use crate::cell::UnsafeCell;
-use crate::collections::VecDeque;
-use crate::hint;
-use crate::ops::{Deref, DerefMut, Drop};
-use crate::sync::atomic::{AtomicUsize, Ordering};
-use crate::sys::hermit::abi;
-
-/// This type provides a lock based on busy waiting to realize mutual exclusion
-///
-/// # Description
-///
-/// This structure behaves a lot like a common mutex. There are some differences:
-///
-/// - By using busy waiting, it can be used outside the runtime.
-/// - It is a so called ticket lock and is completely fair.
-#[cfg_attr(target_arch = "x86_64", repr(align(128)))]
-#[cfg_attr(not(target_arch = "x86_64"), repr(align(64)))]
-struct Spinlock {
-    queue: AtomicUsize,
-    dequeue: AtomicUsize,
-    data: UnsafeCell,
-}
-
-unsafe impl Sync for Spinlock {}
-unsafe impl Send for Spinlock {}
-
-/// A guard to which the protected data can be accessed
-///
-/// When the guard falls out of scope it will release the lock.
-struct SpinlockGuard<'a, T: ?Sized + 'a> {
-    dequeue: &'a AtomicUsize,
-    data: &'a mut T,
-}
-
-impl Spinlock {
-    pub const fn new(user_data: T) -> Spinlock {
-        Spinlock {
-            queue: AtomicUsize::new(0),
-            dequeue: AtomicUsize::new(1),
-            data: UnsafeCell::new(user_data),
-        }
-    }
-
-    #[inline]
-    fn obtain_lock(&self) {
-        let ticket = self.queue.fetch_add(1, Ordering::SeqCst) + 1;
-        let mut counter: u16 = 0;
-        while self.dequeue.load(Ordering::SeqCst) != ticket {
-            counter += 1;
-            if counter < 100 {
-                hint::spin_loop();
-            } else {
-                counter = 0;
-                unsafe {
-                    abi::yield_now();
-                }
-            }
-        }
-    }
-
-    #[inline]
-    pub unsafe fn lock(&self) -> SpinlockGuard<'_, T> {
-        self.obtain_lock();
-        SpinlockGuard { dequeue: &self.dequeue, data: &mut *self.data.get() }
-    }
-}
-
-impl Default for Spinlock {
-    fn default() -> Spinlock {
-        Spinlock::new(Default::default())
-    }
-}
-
-impl<'a, T: ?Sized> Deref for SpinlockGuard<'a, T> {
-    type Target = T;
-    fn deref(&self) -> &T {
-        &*self.data
-    }
-}
-
-impl<'a, T: ?Sized> DerefMut for SpinlockGuard<'a, T> {
-    fn deref_mut(&mut self) -> &mut T {
-        &mut *self.data
-    }
-}
-
-impl<'a, T: ?Sized> Drop for SpinlockGuard<'a, T> {
-    /// The dropping of the SpinlockGuard will release the lock it was created from.
-    fn drop(&mut self) {
-        self.dequeue.fetch_add(1, Ordering::SeqCst);
-    }
-}
-
-/// Realize a priority queue for tasks
-struct PriorityQueue {
-    queues: [Option>; abi::NO_PRIORITIES],
-    prio_bitmap: u64,
-}
-
-impl PriorityQueue {
-    pub const fn new() -> PriorityQueue {
-        PriorityQueue {
-            queues: [
-                None, None, None, None, None, None, None, None, None, None, None, None, None, None,
-                None, None, None, None, None, None, None, None, None, None, None, None, None, None,
-                None, None, None,
-            ],
-            prio_bitmap: 0,
-        }
-    }
-
-    /// Add a task id by its priority to the queue
-    pub fn push(&mut self, prio: abi::Priority, id: abi::Tid) {
-        let i: usize = prio.into().into();
-        self.prio_bitmap |= (1 << i) as u64;
-        if let Some(queue) = &mut self.queues[i] {
-            queue.push_back(id);
-        } else {
-            let mut queue = VecDeque::new();
-            queue.push_back(id);
-            self.queues[i] = Some(queue);
-        }
-    }
-
-    fn pop_from_queue(&mut self, queue_index: usize) -> Option {
-        if let Some(queue) = &mut self.queues[queue_index] {
-            let id = queue.pop_front();
-
-            if queue.is_empty() {
-                self.prio_bitmap &= !(1 << queue_index as u64);
-            }
-
-            id
-        } else {
-            None
-        }
-    }
-
-    /// Pop the task handle with the highest priority from the queue
-    pub fn pop(&mut self) -> Option {
-        for i in 0..abi::NO_PRIORITIES {
-            if self.prio_bitmap & (1 << i) != 0 {
-                return self.pop_from_queue(i);
-            }
-        }
-
-        None
-    }
-}
-
-struct MutexInner {
-    locked: bool,
-    blocked_task: PriorityQueue,
-}
-
-impl MutexInner {
-    pub const fn new() -> MutexInner {
-        MutexInner { locked: false, blocked_task: PriorityQueue::new() }
-    }
-}
-
-pub struct Mutex {
-    inner: Spinlock,
-}
-
-pub type MovableMutex = Mutex;
-
-unsafe impl Send for Mutex {}
-unsafe impl Sync for Mutex {}
-
-impl Mutex {
-    pub const fn new() -> Mutex {
-        Mutex { inner: Spinlock::new(MutexInner::new()) }
-    }
-
-    #[inline]
-    pub unsafe fn lock(&self) {
-        loop {
-            let mut guard = self.inner.lock();
-            if guard.locked == false {
-                guard.locked = true;
-                return;
-            } else {
-                let prio = abi::get_priority();
-                let id = abi::getpid();
-
-                guard.blocked_task.push(prio, id);
-                abi::block_current_task();
-                drop(guard);
-                abi::yield_now();
-            }
-        }
-    }
-
-    #[inline]
-    pub unsafe fn unlock(&self) {
-        let mut guard = self.inner.lock();
-        guard.locked = false;
-        if let Some(tid) = guard.blocked_task.pop() {
-            abi::wakeup_task(tid);
-        }
-    }
-
-    #[inline]
-    pub unsafe fn try_lock(&self) -> bool {
-        let mut guard = self.inner.lock();
-        if guard.locked == false {
-            guard.locked = true;
-        }
-        guard.locked
-    }
-}
diff --git a/library/std/src/sys/hermit/rwlock.rs b/library/std/src/sys/hermit/rwlock.rs
deleted file mode 100644
index 1adf0b2be6b7..000000000000
--- a/library/std/src/sys/hermit/rwlock.rs
+++ /dev/null
@@ -1,143 +0,0 @@
-use crate::cell::UnsafeCell;
-use crate::sys::locks::{MovableCondvar, Mutex};
-
-pub struct RwLock {
-    lock: Mutex,
-    cond: MovableCondvar,
-    state: UnsafeCell,
-}
-
-pub type MovableRwLock = RwLock;
-
-enum State {
-    Unlocked,
-    Reading(usize),
-    Writing,
-}
-
-unsafe impl Send for RwLock {}
-unsafe impl Sync for RwLock {}
-
-// This rwlock implementation is a relatively simple implementation which has a
-// condition variable for readers/writers as well as a mutex protecting the
-// internal state of the lock. A current downside of the implementation is that
-// unlocking the lock will notify *all* waiters rather than just readers or just
-// writers. This can cause lots of "thundering stampede" problems. While
-// hopefully correct this implementation is very likely to want to be changed in
-// the future.
-
-impl RwLock {
-    pub const fn new() -> RwLock {
-        RwLock {
-            lock: Mutex::new(),
-            cond: MovableCondvar::new(),
-            state: UnsafeCell::new(State::Unlocked),
-        }
-    }
-
-    #[inline]
-    pub unsafe fn read(&self) {
-        self.lock.lock();
-        while !(*self.state.get()).inc_readers() {
-            self.cond.wait(&self.lock);
-        }
-        self.lock.unlock();
-    }
-
-    #[inline]
-    pub unsafe fn try_read(&self) -> bool {
-        self.lock.lock();
-        let ok = (*self.state.get()).inc_readers();
-        self.lock.unlock();
-        return ok;
-    }
-
-    #[inline]
-    pub unsafe fn write(&self) {
-        self.lock.lock();
-        while !(*self.state.get()).inc_writers() {
-            self.cond.wait(&self.lock);
-        }
-        self.lock.unlock();
-    }
-
-    #[inline]
-    pub unsafe fn try_write(&self) -> bool {
-        self.lock.lock();
-        let ok = (*self.state.get()).inc_writers();
-        self.lock.unlock();
-        return ok;
-    }
-
-    #[inline]
-    pub unsafe fn read_unlock(&self) {
-        self.lock.lock();
-        let notify = (*self.state.get()).dec_readers();
-        self.lock.unlock();
-        if notify {
-            // FIXME: should only wake up one of these some of the time
-            self.cond.notify_all();
-        }
-    }
-
-    #[inline]
-    pub unsafe fn write_unlock(&self) {
-        self.lock.lock();
-        (*self.state.get()).dec_writers();
-        self.lock.unlock();
-        // FIXME: should only wake up one of these some of the time
-        self.cond.notify_all();
-    }
-}
-
-impl State {
-    fn inc_readers(&mut self) -> bool {
-        match *self {
-            State::Unlocked => {
-                *self = State::Reading(1);
-                true
-            }
-            State::Reading(ref mut cnt) => {
-                *cnt += 1;
-                true
-            }
-            State::Writing => false,
-        }
-    }
-
-    fn inc_writers(&mut self) -> bool {
-        match *self {
-            State::Unlocked => {
-                *self = State::Writing;
-                true
-            }
-            State::Reading(_) | State::Writing => false,
-        }
-    }
-
-    fn dec_readers(&mut self) -> bool {
-        let zero = match *self {
-            State::Reading(ref mut cnt) => {
-                *cnt -= 1;
-                *cnt == 0
-            }
-            State::Unlocked | State::Writing => invalid(),
-        };
-        if zero {
-            *self = State::Unlocked;
-        }
-        zero
-    }
-
-    fn dec_writers(&mut self) {
-        match *self {
-            State::Writing => {}
-            State::Unlocked | State::Reading(_) => invalid(),
-        }
-        *self = State::Unlocked;
-    }
-}
-
-fn invalid() -> ! {
-    panic!("inconsistent rwlock");
-}
diff --git a/library/std/src/sys_common/thread_parker/mod.rs b/library/std/src/sys_common/thread_parker/mod.rs
index cbd7832eb7a4..f86a9a555d32 100644
--- a/library/std/src/sys_common/thread_parker/mod.rs
+++ b/library/std/src/sys_common/thread_parker/mod.rs
@@ -7,6 +7,7 @@ cfg_if::cfg_if! {
         target_os = "openbsd",
         target_os = "dragonfly",
         target_os = "fuchsia",
+        target_os = "hermit",
     ))] {
         mod futex;
         pub use futex::Parker;

From 14f2acd0ac5d20a58f3333276d1ea77510379ac0 Mon Sep 17 00:00:00 2001
From: lcnr 
Date: Thu, 8 Sep 2022 17:02:09 +0200
Subject: [PATCH 4390/5092] `resolve_instance`: remove `BoundVarsCollector`

---
 compiler/rustc_ty_utils/src/instance.rs | 111 +-----------------------
 1 file changed, 3 insertions(+), 108 deletions(-)

diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 661e413fc5b8..392aa6a88186 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -4,112 +4,12 @@ use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::traits::CodegenObligationError;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{
-    self, Binder, Instance, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
+    self, Instance, TyCtxt, TypeVisitable,
 };
 use rustc_span::{sym, DUMMY_SP};
 use rustc_trait_selection::traits;
 use traits::{translate_substs, Reveal};
 
-use rustc_data_structures::sso::SsoHashSet;
-use std::collections::btree_map::Entry;
-use std::collections::BTreeMap;
-use std::ops::ControlFlow;
-
-// FIXME(#86795): `BoundVarsCollector` here should **NOT** be used
-// outside of `resolve_associated_item`. It's just to address #64494,
-// #83765, and #85848 which are creating bound types/regions that lose
-// their `Binder` *unintentionally*.
-// It's ideal to remove `BoundVarsCollector` and just use
-// `ty::Binder::*` methods but we use this stopgap until we figure out
-// the "real" fix.
-struct BoundVarsCollector<'tcx> {
-    binder_index: ty::DebruijnIndex,
-    vars: BTreeMap,
-    // We may encounter the same variable at different levels of binding, so
-    // this can't just be `Ty`
-    visited: SsoHashSet<(ty::DebruijnIndex, Ty<'tcx>)>,
-}
-
-impl<'tcx> BoundVarsCollector<'tcx> {
-    fn new() -> Self {
-        BoundVarsCollector {
-            binder_index: ty::INNERMOST,
-            vars: BTreeMap::new(),
-            visited: SsoHashSet::default(),
-        }
-    }
-
-    fn into_vars(self, tcx: TyCtxt<'tcx>) -> &'tcx ty::List {
-        let max = self.vars.iter().map(|(k, _)| *k).max().unwrap_or(0);
-        for i in 0..max {
-            if let None = self.vars.get(&i) {
-                panic!("Unknown variable: {:?}", i);
-            }
-        }
-
-        tcx.mk_bound_variable_kinds(self.vars.into_iter().map(|(_, v)| v))
-    }
-}
-
-impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
-    type BreakTy = ();
-
-    fn visit_binder>(
-        &mut self,
-        t: &Binder<'tcx, T>,
-    ) -> ControlFlow {
-        self.binder_index.shift_in(1);
-        let result = t.super_visit_with(self);
-        self.binder_index.shift_out(1);
-        result
-    }
-
-    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow {
-        if t.outer_exclusive_binder() < self.binder_index
-            || !self.visited.insert((self.binder_index, t))
-        {
-            return ControlFlow::CONTINUE;
-        }
-        match *t.kind() {
-            ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
-                match self.vars.entry(bound_ty.var.as_u32()) {
-                    Entry::Vacant(entry) => {
-                        entry.insert(ty::BoundVariableKind::Ty(bound_ty.kind));
-                    }
-                    Entry::Occupied(entry) => match entry.get() {
-                        ty::BoundVariableKind::Ty(_) => {}
-                        _ => bug!("Conflicting bound vars"),
-                    },
-                }
-            }
-
-            _ => (),
-        };
-
-        t.super_visit_with(self)
-    }
-
-    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow {
-        match *r {
-            ty::ReLateBound(index, br) if index == self.binder_index => {
-                match self.vars.entry(br.var.as_u32()) {
-                    Entry::Vacant(entry) => {
-                        entry.insert(ty::BoundVariableKind::Region(br.kind));
-                    }
-                    Entry::Occupied(entry) => match entry.get() {
-                        ty::BoundVariableKind::Region(_) => {}
-                        _ => bug!("Conflicting bound vars"),
-                    },
-                }
-            }
-
-            _ => (),
-        };
-
-        r.super_visit_with(self)
-    }
-}
-
 fn resolve_instance<'tcx>(
     tcx: TyCtxt<'tcx>,
     key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)>,
@@ -201,19 +101,14 @@ fn resolve_associated_item<'tcx>(
 
     let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
 
-    // See FIXME on `BoundVarsCollector`.
-    let mut bound_vars_collector = BoundVarsCollector::new();
-    trait_ref.visit_with(&mut bound_vars_collector);
-    let trait_binder = ty::Binder::bind_with_vars(trait_ref, bound_vars_collector.into_vars(tcx));
-    let vtbl = match tcx.codegen_fulfill_obligation((param_env, trait_binder)) {
+    let vtbl = match tcx.codegen_fulfill_obligation((param_env, ty::Binder::dummy(trait_ref))) {
         Ok(vtbl) => vtbl,
         Err(CodegenObligationError::Ambiguity) => {
             let reported = tcx.sess.delay_span_bug(
                 tcx.def_span(trait_item_id),
                 &format!(
-                    "encountered ambiguity selecting `{:?}` during codegen, presuming due to \
+                    "encountered ambiguity selecting `{trait_ref:?}` during codegen, presuming due to \
                      overflow or prior type error",
-                    trait_binder
                 ),
             );
             return Err(reported);

From c63020a7c3e624f610f1f402a44a0db92bd21a88 Mon Sep 17 00:00:00 2001
From: lcnr 
Date: Fri, 9 Sep 2022 13:36:27 +0200
Subject: [PATCH 4391/5092] rename `codegen_fulfill_obligation`

---
 compiler/rustc_middle/src/query/mod.rs               | 7 ++-----
 compiler/rustc_middle/src/traits/mod.rs              | 2 +-
 compiler/rustc_monomorphize/src/lib.rs               | 2 +-
 compiler/rustc_trait_selection/src/traits/codegen.rs | 2 +-
 compiler/rustc_trait_selection/src/traits/mod.rs     | 2 +-
 compiler/rustc_ty_utils/src/instance.rs              | 6 ++----
 src/test/ui/const-generics/issues/issue-83765.stderr | 4 ++--
 7 files changed, 10 insertions(+), 15 deletions(-)

diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index adf479c42360..f72e7389fc60 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1202,14 +1202,11 @@ rustc_queries! {
         }
     }
 
-    query codegen_fulfill_obligation(
+    query codegen_select_candidate(
         key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)
     ) -> Result<&'tcx ImplSource<'tcx, ()>, traits::CodegenObligationError> {
         cache_on_disk_if { true }
-        desc { |tcx|
-            "checking if `{}` fulfills its obligations",
-            tcx.def_path_str(key.1.def_id())
-        }
+        desc { |tcx| "computing candidate for `{}`", key.1 }
     }
 
     /// Return all `impl` blocks in the current crate.
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index a56fac7c4dd2..755d9f8f6966 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -1024,7 +1024,7 @@ pub enum MethodViolationCode {
     UndispatchableReceiver(Option),
 }
 
-/// These are the error cases for `codegen_fulfill_obligation`.
+/// These are the error cases for `codegen_select_candidate`.
 #[derive(Copy, Clone, Debug, Hash, HashStable, Encodable, Decodable)]
 pub enum CodegenObligationError {
     /// Ambiguity can happen when monomorphizing during trans
diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs
index d64de44705bb..3afff7bcabf7 100644
--- a/compiler/rustc_monomorphize/src/lib.rs
+++ b/compiler/rustc_monomorphize/src/lib.rs
@@ -35,7 +35,7 @@ fn custom_coerce_unsize_info<'tcx>(
         substs: tcx.mk_substs_trait(source_ty, &[target_ty.into()]),
     });
 
-    match tcx.codegen_fulfill_obligation((ty::ParamEnv::reveal_all(), trait_ref)) {
+    match tcx.codegen_select_candidate((ty::ParamEnv::reveal_all(), trait_ref)) {
         Ok(traits::ImplSource::UserDefined(traits::ImplSourceUserDefinedData {
             impl_def_id,
             ..
diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs
index 26f8e7d34c6e..08adbcbd410c 100644
--- a/compiler/rustc_trait_selection/src/traits/codegen.rs
+++ b/compiler/rustc_trait_selection/src/traits/codegen.rs
@@ -18,7 +18,7 @@ use rustc_middle::ty::{self, TyCtxt};
 /// obligations *could be* resolved if we wanted to.
 ///
 /// This also expects that `trait_ref` is fully normalized.
-pub fn codegen_fulfill_obligation<'tcx>(
+pub fn codegen_select_candidate<'tcx>(
     tcx: TyCtxt<'tcx>,
     (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
 ) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> {
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 14e078096783..40596078f041 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -971,7 +971,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
     *providers = ty::query::Providers {
         specialization_graph_of: specialize::specialization_graph_provider,
         specializes: specialize::specializes,
-        codegen_fulfill_obligation: codegen::codegen_fulfill_obligation,
+        codegen_select_candidate: codegen::codegen_select_candidate,
         own_existential_vtable_entries,
         vtable_entries,
         vtable_trait_upcasting_coercion_new_vptr_slot,
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 392aa6a88186..b55302de2a73 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -3,9 +3,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::traits::CodegenObligationError;
 use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{
-    self, Instance, TyCtxt, TypeVisitable,
-};
+use rustc_middle::ty::{self, Instance, TyCtxt, TypeVisitable};
 use rustc_span::{sym, DUMMY_SP};
 use rustc_trait_selection::traits;
 use traits::{translate_substs, Reveal};
@@ -101,7 +99,7 @@ fn resolve_associated_item<'tcx>(
 
     let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
 
-    let vtbl = match tcx.codegen_fulfill_obligation((param_env, ty::Binder::dummy(trait_ref))) {
+    let vtbl = match tcx.codegen_select_candidate((param_env, ty::Binder::dummy(trait_ref))) {
         Ok(vtbl) => vtbl,
         Err(CodegenObligationError::Ambiguity) => {
             let reported = tcx.sess.delay_span_bug(
diff --git a/src/test/ui/const-generics/issues/issue-83765.stderr b/src/test/ui/const-generics/issues/issue-83765.stderr
index 28ddddf1be62..d5f914f46f87 100644
--- a/src/test/ui/const-generics/issues/issue-83765.stderr
+++ b/src/test/ui/const-generics/issues/issue-83765.stderr
@@ -4,13 +4,13 @@ error[E0391]: cycle detected when resolving instance ` as TensorDimension>`...
   --> $DIR/issue-83765.rs:4:1
    |
 LL | trait TensorDimension {
    | ^^^^^^^^^^^^^^^^^^^^^
    = note: ...which again requires resolving instance ` as TensorDimension>::DIM`, completing the cycle
-note: cycle used when checking if `TensorDimension` fulfills its obligations
+note: cycle used when computing candidate for ` as TensorDimension>`
   --> $DIR/issue-83765.rs:4:1
    |
 LL | trait TensorDimension {

From 5db69074988b0edf6751192336398d0673ee81a2 Mon Sep 17 00:00:00 2001
From: lcnr 
Date: Fri, 9 Sep 2022 14:28:57 +0200
Subject: [PATCH 4392/5092] review

---
 compiler/rustc_ast/src/ast.rs                          |  2 +-
 src/test/ui/const-generics/argument_order.stderr       |  4 ++--
 .../const-generics/const-param-before-other-params.rs  |  2 +-
 .../const-param-before-other-params.stderr             |  2 +-
 .../ui/const-generics/defaults/intermixed-lifetime.rs  |  4 ++--
 .../const-generics/defaults/intermixed-lifetime.stderr |  4 ++--
 .../defaults/param-order-err-pretty-prints-default.rs  |  2 +-
 .../param-order-err-pretty-prints-default.stderr       |  2 +-
 src/test/ui/generics/issue-59508-1.rs                  |  2 +-
 src/test/ui/generics/issue-59508-1.stderr              |  2 +-
 src/test/ui/generics/issue-59508.fixed                 |  2 +-
 src/test/ui/generics/issue-59508.rs                    |  2 +-
 src/test/ui/generics/issue-59508.stderr                |  2 +-
 .../issue-80512-param-reordering-with-defaults.rs      |  2 +-
 .../issue-80512-param-reordering-with-defaults.stderr  |  2 +-
 src/test/ui/generics/lifetime-before-type-params.rs    |  8 ++++----
 .../ui/generics/lifetime-before-type-params.stderr     |  8 ++++----
 src/test/ui/parser/issues/issue-14303.rs               | 10 +++++-----
 src/test/ui/parser/issues/issue-14303.stderr           | 10 +++++-----
 src/test/ui/suggestions/suggest-move-lifetimes.stderr  |  8 ++++----
 src/test/ui/suggestions/suggest-move-types.stderr      |  4 ++--
 21 files changed, 42 insertions(+), 42 deletions(-)

diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 6c7670378fd4..75cc5b72582e 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -333,7 +333,7 @@ impl fmt::Display for ParamKindOrd {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             ParamKindOrd::Lifetime => "lifetime".fmt(f),
-            ParamKindOrd::TypeOrConst => "type or const".fmt(f),
+            ParamKindOrd::TypeOrConst => "type and const".fmt(f),
         }
     }
 }
diff --git a/src/test/ui/const-generics/argument_order.stderr b/src/test/ui/const-generics/argument_order.stderr
index a3a54b497a76..99122c6f5e36 100644
--- a/src/test/ui/const-generics/argument_order.stderr
+++ b/src/test/ui/const-generics/argument_order.stderr
@@ -1,4 +1,4 @@
-error: lifetime parameters must be declared prior to type or const parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/argument_order.rs:6:32
    |
 LL | struct AlsoBad {
@@ -11,7 +11,7 @@ LL |     let _: AlsoBad<7, 'static, u32, 'static, 17, u16>;
    |                       ^^^^^^^
    |
    = note: lifetime arguments must be provided before type arguments
-   = help: reorder the arguments: lifetimes, then type or consts: `<'a, 'b, N, T, M, U>`
+   = help: reorder the arguments: lifetimes, then type and consts: `<'a, 'b, N, T, M, U>`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/const-param-before-other-params.rs b/src/test/ui/const-generics/const-param-before-other-params.rs
index b481000bb7f5..cb1cebe1f68a 100644
--- a/src/test/ui/const-generics/const-param-before-other-params.rs
+++ b/src/test/ui/const-generics/const-param-before-other-params.rs
@@ -1,5 +1,5 @@
 fn bar(_: &'a ()) {
-    //~^ ERROR lifetime parameters must be declared prior to type or const parameters
+    //~^ ERROR lifetime parameters must be declared prior to type and const parameters
 }
 
 fn foo(_: &T) {}
diff --git a/src/test/ui/const-generics/const-param-before-other-params.stderr b/src/test/ui/const-generics/const-param-before-other-params.stderr
index 049c58ba4fae..2c7a47bbc78c 100644
--- a/src/test/ui/const-generics/const-param-before-other-params.stderr
+++ b/src/test/ui/const-generics/const-param-before-other-params.stderr
@@ -1,4 +1,4 @@
-error: lifetime parameters must be declared prior to type or const parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/const-param-before-other-params.rs:1:21
    |
 LL | fn bar(_: &'a ()) {
diff --git a/src/test/ui/const-generics/defaults/intermixed-lifetime.rs b/src/test/ui/const-generics/defaults/intermixed-lifetime.rs
index 9e4a32121bb3..beaf7fc6001a 100644
--- a/src/test/ui/const-generics/defaults/intermixed-lifetime.rs
+++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.rs
@@ -1,9 +1,9 @@
 // Checks that lifetimes cannot be interspersed between consts and types.
 
 struct Foo(&'a (), T);
-//~^ ERROR lifetime parameters must be declared prior to type or const parameters
+//~^ ERROR lifetime parameters must be declared prior to type and const parameters
 
 struct Bar(&'a (), T);
-//~^ ERROR lifetime parameters must be declared prior to type or const parameters
+//~^ ERROR lifetime parameters must be declared prior to type and const parameters
 
 fn main() {}
diff --git a/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr b/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr
index b8aa18c942bc..5cff61dd9fb9 100644
--- a/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr
+++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr
@@ -1,10 +1,10 @@
-error: lifetime parameters must be declared prior to type or const parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/intermixed-lifetime.rs:3:28
    |
 LL | struct Foo(&'a (), T);
    |           -----------------^^---------- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T = u32>`
 
-error: lifetime parameters must be declared prior to type or const parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/intermixed-lifetime.rs:6:37
    |
 LL | struct Bar(&'a (), T);
diff --git a/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.rs b/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.rs
index ae897e59a974..f928fc9e75b7 100644
--- a/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.rs
+++ b/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.rs
@@ -1,4 +1,4 @@
 struct Foo(&'a u32);
-//~^ ERROR lifetime parameters must be declared prior to type or const parameters
+//~^ ERROR lifetime parameters must be declared prior to type and const parameters
 
 fn main() {}
diff --git a/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.stderr b/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.stderr
index b4bfc5410390..ba08b4646d0f 100644
--- a/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.stderr
+++ b/src/test/ui/const-generics/defaults/param-order-err-pretty-prints-default.stderr
@@ -1,4 +1,4 @@
-error: lifetime parameters must be declared prior to type or const parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/param-order-err-pretty-prints-default.rs:1:33
    |
 LL | struct Foo(&'a u32);
diff --git a/src/test/ui/generics/issue-59508-1.rs b/src/test/ui/generics/issue-59508-1.rs
index 646ece33ca34..8e27749e8fc6 100644
--- a/src/test/ui/generics/issue-59508-1.rs
+++ b/src/test/ui/generics/issue-59508-1.rs
@@ -8,7 +8,7 @@ struct A;
 
 impl A {
     pub fn do_things() {
-    //~^ ERROR lifetime parameters must be declared prior to type or const parameters
+    //~^ ERROR lifetime parameters must be declared prior to type and const parameters
         println!("panic");
     }
 }
diff --git a/src/test/ui/generics/issue-59508-1.stderr b/src/test/ui/generics/issue-59508-1.stderr
index 1ca99c6ab76c..1c510044f806 100644
--- a/src/test/ui/generics/issue-59508-1.stderr
+++ b/src/test/ui/generics/issue-59508-1.stderr
@@ -1,4 +1,4 @@
-error: lifetime parameters must be declared prior to type or const parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/issue-59508-1.rs:10:25
    |
 LL |     pub fn do_things() {
diff --git a/src/test/ui/generics/issue-59508.fixed b/src/test/ui/generics/issue-59508.fixed
index 557bcc1f716c..de8f47d4cff8 100644
--- a/src/test/ui/generics/issue-59508.fixed
+++ b/src/test/ui/generics/issue-59508.fixed
@@ -8,7 +8,7 @@ struct A;
 
 impl A {
     pub fn do_things<'a, 'b: 'a, T>() {
-    //~^ ERROR lifetime parameters must be declared prior to type or const parameters
+    //~^ ERROR lifetime parameters must be declared prior to type and const parameters
         println!("panic");
     }
 }
diff --git a/src/test/ui/generics/issue-59508.rs b/src/test/ui/generics/issue-59508.rs
index 0b290a6085f9..a4c7d4ff2626 100644
--- a/src/test/ui/generics/issue-59508.rs
+++ b/src/test/ui/generics/issue-59508.rs
@@ -8,7 +8,7 @@ struct A;
 
 impl A {
     pub fn do_things() {
-    //~^ ERROR lifetime parameters must be declared prior to type or const parameters
+    //~^ ERROR lifetime parameters must be declared prior to type and const parameters
         println!("panic");
     }
 }
diff --git a/src/test/ui/generics/issue-59508.stderr b/src/test/ui/generics/issue-59508.stderr
index e8926c13a113..fd23b6276f92 100644
--- a/src/test/ui/generics/issue-59508.stderr
+++ b/src/test/ui/generics/issue-59508.stderr
@@ -1,4 +1,4 @@
-error: lifetime parameters must be declared prior to type or const parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/issue-59508.rs:10:25
    |
 LL |     pub fn do_things() {
diff --git a/src/test/ui/generics/issue-80512-param-reordering-with-defaults.rs b/src/test/ui/generics/issue-80512-param-reordering-with-defaults.rs
index 598f95d9a0ba..0e208818ed45 100644
--- a/src/test/ui/generics/issue-80512-param-reordering-with-defaults.rs
+++ b/src/test/ui/generics/issue-80512-param-reordering-with-defaults.rs
@@ -1,4 +1,4 @@
 #![crate_type = "lib"]
 
 struct S(&'a T);
-//~^ ERROR lifetime parameters must be declared prior to type or const parameters
+//~^ ERROR lifetime parameters must be declared prior to type and const parameters
diff --git a/src/test/ui/generics/issue-80512-param-reordering-with-defaults.stderr b/src/test/ui/generics/issue-80512-param-reordering-with-defaults.stderr
index 69680a801019..70793a9c9208 100644
--- a/src/test/ui/generics/issue-80512-param-reordering-with-defaults.stderr
+++ b/src/test/ui/generics/issue-80512-param-reordering-with-defaults.stderr
@@ -1,4 +1,4 @@
-error: lifetime parameters must be declared prior to type or const parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/issue-80512-param-reordering-with-defaults.rs:3:18
    |
 LL | struct S(&'a T);
diff --git a/src/test/ui/generics/lifetime-before-type-params.rs b/src/test/ui/generics/lifetime-before-type-params.rs
index 4904ae61caaf..d64b1b0b44f6 100644
--- a/src/test/ui/generics/lifetime-before-type-params.rs
+++ b/src/test/ui/generics/lifetime-before-type-params.rs
@@ -1,11 +1,11 @@
 #![allow(unused)]
 fn first() {}
-//~^ ERROR lifetime parameters must be declared prior to type or const parameters
+//~^ ERROR lifetime parameters must be declared prior to type and const parameters
 fn second<'a, T, 'b>() {}
-//~^ ERROR lifetime parameters must be declared prior to type or const parameters
+//~^ ERROR lifetime parameters must be declared prior to type and const parameters
 fn third() {}
-//~^ ERROR lifetime parameters must be declared prior to type or const parameters
+//~^ ERROR lifetime parameters must be declared prior to type and const parameters
 fn fourth<'a, T, 'b, U, 'c, V>() {}
-//~^ ERROR lifetime parameters must be declared prior to type or const parameters
+//~^ ERROR lifetime parameters must be declared prior to type and const parameters
 
 fn main() {}
diff --git a/src/test/ui/generics/lifetime-before-type-params.stderr b/src/test/ui/generics/lifetime-before-type-params.stderr
index 7bb4f826409b..84825eb4ceb2 100644
--- a/src/test/ui/generics/lifetime-before-type-params.stderr
+++ b/src/test/ui/generics/lifetime-before-type-params.stderr
@@ -1,22 +1,22 @@
-error: lifetime parameters must be declared prior to type or const parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/lifetime-before-type-params.rs:2:13
    |
 LL | fn first() {}
    |         ----^^--^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>`
 
-error: lifetime parameters must be declared prior to type or const parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/lifetime-before-type-params.rs:4:18
    |
 LL | fn second<'a, T, 'b>() {}
    |          --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>`
 
-error: lifetime parameters must be declared prior to type or const parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/lifetime-before-type-params.rs:6:16
    |
 LL | fn third() {}
    |         -------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, T, U>`
 
-error: lifetime parameters must be declared prior to type or const parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/lifetime-before-type-params.rs:8:18
    |
 LL | fn fourth<'a, T, 'b, U, 'c, V>() {}
diff --git a/src/test/ui/parser/issues/issue-14303.rs b/src/test/ui/parser/issues/issue-14303.rs
index e44b57746605..82850d77aa92 100644
--- a/src/test/ui/parser/issues/issue-14303.rs
+++ b/src/test/ui/parser/issues/issue-14303.rs
@@ -1,22 +1,22 @@
 enum Enum<'a, T, 'b> {
-//~^ ERROR lifetime parameters must be declared prior to type or const parameters
+//~^ ERROR lifetime parameters must be declared prior to type and const parameters
     A(&'a &'b T)
 }
 
 struct Struct<'a, T, 'b> {
-//~^ ERROR lifetime parameters must be declared prior to type or const parameters
+//~^ ERROR lifetime parameters must be declared prior to type and const parameters
     x: &'a &'b T
 }
 
 trait Trait<'a, T, 'b> {}
-//~^ ERROR lifetime parameters must be declared prior to type or const parameters
+//~^ ERROR lifetime parameters must be declared prior to type and const parameters
 
 fn foo<'a, T, 'b>(x: &'a T) {}
-//~^ ERROR lifetime parameters must be declared prior to type or const parameters
+//~^ ERROR lifetime parameters must be declared prior to type and const parameters
 
 struct Y(T);
 impl<'a, T, 'b> Y {}
-//~^ ERROR lifetime parameters must be declared prior to type or const parameters
+//~^ ERROR lifetime parameters must be declared prior to type and const parameters
 
 mod bar {
     pub struct X<'a, 'b, 'c, T> {
diff --git a/src/test/ui/parser/issues/issue-14303.stderr b/src/test/ui/parser/issues/issue-14303.stderr
index 3579159245ac..f121107c0958 100644
--- a/src/test/ui/parser/issues/issue-14303.stderr
+++ b/src/test/ui/parser/issues/issue-14303.stderr
@@ -1,28 +1,28 @@
-error: lifetime parameters must be declared prior to type or const parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/issue-14303.rs:1:18
    |
 LL | enum Enum<'a, T, 'b> {
    |          --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>`
 
-error: lifetime parameters must be declared prior to type or const parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/issue-14303.rs:6:22
    |
 LL | struct Struct<'a, T, 'b> {
    |              --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>`
 
-error: lifetime parameters must be declared prior to type or const parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/issue-14303.rs:11:20
    |
 LL | trait Trait<'a, T, 'b> {}
    |            --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>`
 
-error: lifetime parameters must be declared prior to type or const parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/issue-14303.rs:14:15
    |
 LL | fn foo<'a, T, 'b>(x: &'a T) {}
    |       --------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, T>`
 
-error: lifetime parameters must be declared prior to type or const parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/issue-14303.rs:18:13
    |
 LL | impl<'a, T, 'b> Y {}
diff --git a/src/test/ui/suggestions/suggest-move-lifetimes.stderr b/src/test/ui/suggestions/suggest-move-lifetimes.stderr
index f7ff3697e1da..b1a49447d460 100644
--- a/src/test/ui/suggestions/suggest-move-lifetimes.stderr
+++ b/src/test/ui/suggestions/suggest-move-lifetimes.stderr
@@ -1,22 +1,22 @@
-error: lifetime parameters must be declared prior to type or const parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/suggest-move-lifetimes.rs:1:13
    |
 LL | struct A {
    |         ----^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, T>`
 
-error: lifetime parameters must be declared prior to type or const parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/suggest-move-lifetimes.rs:5:13
    |
 LL | struct B {
    |         ----^^---- help: reorder the parameters: lifetimes, then consts and types: `<'a, T, U>`
 
-error: lifetime parameters must be declared prior to type or const parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/suggest-move-lifetimes.rs:10:16
    |
 LL | struct C {
    |         -------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, T, U>`
 
-error: lifetime parameters must be declared prior to type or const parameters
+error: lifetime parameters must be declared prior to type and const parameters
   --> $DIR/suggest-move-lifetimes.rs:15:16
    |
 LL | struct D {
diff --git a/src/test/ui/suggestions/suggest-move-types.stderr b/src/test/ui/suggestions/suggest-move-types.stderr
index 3037b7f92ed6..b222e8142bab 100644
--- a/src/test/ui/suggestions/suggest-move-types.stderr
+++ b/src/test/ui/suggestions/suggest-move-types.stderr
@@ -121,7 +121,7 @@ LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime`
+   = help: reorder the arguments: lifetimes, then type and consts: `<'a, 'b, 'c, T, U, V>`
 
 error[E0747]: lifetime provided when a type was expected
   --> $DIR/suggest-move-types.rs:82:56
@@ -130,7 +130,7 @@ LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime`
+   = help: reorder the arguments: lifetimes, then type and consts: `<'a, 'b, 'c, T, U, V>`
 
 error: aborting due to 12 previous errors
 

From cbcb74e939527750740b0c715068723f5a6e595c Mon Sep 17 00:00:00 2001
From: Michael Howell 
Date: Thu, 8 Sep 2022 17:46:57 -0700
Subject: [PATCH 4393/5092] rustdoc: simplify the codeblock tooltip

This commit moves the tooltip into example-wrap, simplifying allowing several
overly-complex things to be fixed:

* The mousover javascript can be removed, because hovering example-wrap can
  style the tooltip inside.
* The sibling selecor can be removed, because hovering the tooltip also
  hovers the wrapper, which can hover the codeblock itself.
* The relative positioning of the `
  • ` tag, which was added in e861efd9f9ca45c1048a256812dfe8faffbb1367 to fix the positioning of the code tooltip, can now be removed, because example-wrap itself already has relative positioning. --- src/librustdoc/html/highlight.rs | 55 ++++++++++--------- src/librustdoc/html/static/css/rustdoc.css | 20 +++---- src/librustdoc/html/static/js/main.js | 23 +------- .../rustdoc-gui/check_info_sign_position.goml | 8 +-- src/test/rustdoc-gui/codeblock-tooltip.goml | 36 ++++++------ .../overflow-tooltip-information.goml | 2 +- 6 files changed, 61 insertions(+), 83 deletions(-) diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index bb8e46af7628..84781d898385 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -52,35 +52,14 @@ pub(crate) fn render_example_with_highlighting( tooltip: Tooltip, playground_button: Option<&str>, ) { - let class = match tooltip { - Tooltip::Ignore => " ignore", - Tooltip::CompileFail => " compile_fail", - Tooltip::ShouldPanic => " should_panic", - Tooltip::Edition(_) => " edition", - Tooltip::None => "", - }; - - if tooltip != Tooltip::None { - write!( - out, - "
    ", - class, - if let Tooltip::Edition(edition_info) = tooltip { - format!(" data-edition=\"{}\"", edition_info) - } else { - String::new() - }, - ); - } - - write_header(out, &format!("rust-example-rendered{}", class), None); + write_header(out, "rust-example-rendered", None, tooltip); write_code(out, src, None, None); write_footer(out, playground_button); } /// Highlights `src` as a macro, returning the HTML output. pub(crate) fn render_macro_with_highlighting(src: &str, out: &mut Buffer) { - write_header(out, "macro", None); + write_header(out, "macro", None, Tooltip::None); write_code(out, src, None, None); write_footer(out, None); } @@ -93,20 +72,42 @@ pub(crate) fn render_source_with_highlighting( href_context: HrefContext<'_, '_, '_>, decoration_info: DecorationInfo, ) { - write_header(out, "", Some(line_numbers)); + write_header(out, "", Some(line_numbers), Tooltip::None); write_code(out, src, Some(href_context), Some(decoration_info)); write_footer(out, None); } -fn write_header(out: &mut Buffer, class: &str, extra_content: Option) { +fn write_header(out: &mut Buffer, class: &str, extra_content: Option, tooltip: Tooltip) { write!(out, "
    "); + + let tooltip_class = match tooltip { + Tooltip::Ignore => " ignore", + Tooltip::CompileFail => " compile_fail", + Tooltip::ShouldPanic => " should_panic", + Tooltip::Edition(_) => " edition", + Tooltip::None => "", + }; + + if tooltip != Tooltip::None { + write!( + out, + "
    ", + tooltip_class, + if let Tooltip::Edition(edition_info) = tooltip { + format!(" data-edition=\"{}\"", edition_info) + } else { + String::new() + }, + ); + } + if let Some(extra) = extra_content { out.push_buffer(extra); } - if class.is_empty() { + if class.is_empty() && tooltip_class.is_empty() { write!(out, "
    ");
         } else {
    -        write!(out, "
    ", class);
    +        write!(out, "
    ");
         }
         write!(out, "");
     }
    diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
    index 1b8b28f0432a..7585824ee6e1 100644
    --- a/src/librustdoc/html/static/css/rustdoc.css
    +++ b/src/librustdoc/html/static/css/rustdoc.css
    @@ -352,10 +352,6 @@ img {
     	max-width: 100%;
     }
     
    -li {
    -	position: relative;
    -}
    -
     .source .content {
     	max-width: none;
     	overflow: visible;
    @@ -657,7 +653,7 @@ h2.location a {
     	position: relative;
     }
     
    -.docblock > :not(.information):not(.more-examples-toggle) {
    +.docblock > :not(.more-examples-toggle):not(.example-wrap) {
     	max-width: 100%;
     	overflow-x: auto;
     }
    @@ -1174,12 +1170,12 @@ pre.ignore {
     	border-left: 2px solid var(--codeblock-ignore-color);
     }
     
    -pre.compile_fail:hover, .information:hover + .example-wrap pre.compile_fail,
    -pre.should_panic:hover, .information:hover + .example-wrap pre.should_panic {
    +.example-wrap:hover pre.compile_fail,
    +.example-wrap:hover pre.should_panic {
     	border-left: 2px solid var(--codeblock-error-hover-color);
     }
     
    -pre.ignore:hover, .information:hover + .example-wrap pre.ignore {
    +.example-wrap:hover pre.ignore {
     	border-left: 2px solid var(--codeblock-ignore-hover-color);
     }
     
    @@ -1192,12 +1188,12 @@ pre.ignore:hover, .information:hover + .example-wrap pre.ignore {
     	color:  var(--codeblock-ignore-color);
     }
     
    -.information > .compile_fail:hover,
    -.information > .should_panic:hover {
    +.example-wrap:hover .tooltip.compile_fail,
    +.example-wrap:hover .tooltip.should_panic {
     	color: var(--codeblock-error-hover-color);
     }
     
    -.information > .ignore:hover {
    +.example-wrap:hover .tooltip.ignore {
     	color: var(--codeblock-ignore-hover-color);
     }
     
    @@ -1738,7 +1734,7 @@ in storage.js plus the media query with (max-width: 700px)
     	to prevent an overlay between the "collapse toggle" and the information tooltip.
     	However, it's not needed with smaller screen width because the doc/code block is always put
     	"one line" below. */
    -	.docblock > .information:first-child > .tooltip {
    +	.docblock > .example-wrap:first-child > .information > .tooltip {
     		margin-top: 16px;
     	}
     
    diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
    index 7f61c95e794b..6e9660ddcc96 100644
    --- a/src/librustdoc/html/static/js/main.js
    +++ b/src/librustdoc/html/static/js/main.js
    @@ -699,9 +699,8 @@ function loadCss(cssFileName) {
     
         (function() {
             // To avoid checking on "rustdoc-line-numbers" value on every loop...
    -        let lineNumbersFunc = () => {};
             if (getSettingValue("line-numbers") === "true") {
    -            lineNumbersFunc = x => {
    +            onEachLazy(document.getElementsByClassName("rust-example-rendered"), x => {
                     const count = x.textContent.split("\n").length;
                     const elems = [];
                     for (let i = 0; i < count; ++i) {
    @@ -711,26 +710,8 @@ function loadCss(cssFileName) {
                     addClass(node, "line-number");
                     node.innerHTML = elems.join("\n");
                     x.parentNode.insertBefore(node, x);
    -            };
    +            });
             }
    -        onEachLazy(document.getElementsByClassName("rust-example-rendered"), e => {
    -            if (hasClass(e, "compile_fail")) {
    -                e.addEventListener("mouseover", function() {
    -                    this.parentElement.previousElementSibling.childNodes[0].style.color = "#f00";
    -                });
    -                e.addEventListener("mouseout", function() {
    -                    this.parentElement.previousElementSibling.childNodes[0].style.color = "";
    -                });
    -            } else if (hasClass(e, "ignore")) {
    -                e.addEventListener("mouseover", function() {
    -                    this.parentElement.previousElementSibling.childNodes[0].style.color = "#ff9200";
    -                });
    -                e.addEventListener("mouseout", function() {
    -                    this.parentElement.previousElementSibling.childNodes[0].style.color = "";
    -                });
    -            }
    -            lineNumbersFunc(e);
    -        });
         }());
     
         let oldSidebarScrollPosition = null;
    diff --git a/src/test/rustdoc-gui/check_info_sign_position.goml b/src/test/rustdoc-gui/check_info_sign_position.goml
    index 3bed7a0a03ea..c249895503a9 100644
    --- a/src/test/rustdoc-gui/check_info_sign_position.goml
    +++ b/src/test/rustdoc-gui/check_info_sign_position.goml
    @@ -4,8 +4,8 @@ goto: file://|DOC_PATH|/test_docs/index.html
     goto: ./fn.check_list_code_block.html
     // If the codeblock is the first element of the docblock, the information tooltip must have
     // have some top margin to avoid going over the toggle (the "[+]").
    -assert-css: (".docblock > .information > .compile_fail", { "margin-top": "16px" })
    +assert-css: (".docblock > .example-wrap > .information > .compile_fail", { "margin-top": "16px" })
     // Checks that the other codeblocks don't have this top margin.
    -assert-css: ("ol > li > .information > .compile_fail", { "margin-top": "0px" })
    -assert-css: ("ol > li > .information > .ignore", { "margin-top": "0px" })
    -assert-css: (".docblock > .information > .ignore", { "margin-top": "0px" })
    +assert-css: ("ol > li > .example-wrap > .information > .compile_fail", { "margin-top": "0px" })
    +assert-css: ("ol > li > .example-wrap > .information > .ignore", { "margin-top": "0px" })
    +assert-css: (".docblock > .example-wrap > .information > .ignore", { "margin-top": "0px" })
    diff --git a/src/test/rustdoc-gui/codeblock-tooltip.goml b/src/test/rustdoc-gui/codeblock-tooltip.goml
    index a0bb40fce8e7..4e85c33c8944 100644
    --- a/src/test/rustdoc-gui/codeblock-tooltip.goml
    +++ b/src/test/rustdoc-gui/codeblock-tooltip.goml
    @@ -8,30 +8,30 @@ reload:
     
     // compile_fail block
     assert-css: (".docblock .information .compile_fail", {"color": "rgba(255, 0, 0, 0.5)"})
    -assert-css: (".docblock .example-wrap .compile_fail", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
    +assert-css: (".docblock .example-wrap pre.compile_fail", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
     
     move-cursor-to: ".docblock .information .compile_fail"
     
     assert-css: (".docblock .information .compile_fail", {"color": "rgb(255, 0, 0)"})
    -assert-css: (".docblock .example-wrap .compile_fail", {"border-left": "2px solid rgb(255, 0, 0)"})
    +assert-css: (".docblock .example-wrap pre.compile_fail", {"border-left": "2px solid rgb(255, 0, 0)"})
     
     // should_panic block
     assert-css: (".docblock .information .should_panic", {"color": "rgba(255, 0, 0, 0.5)"})
    -assert-css: (".docblock .example-wrap .should_panic", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
    +assert-css: (".docblock .example-wrap pre.should_panic", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
     
     move-cursor-to: ".docblock .information .should_panic"
     
     assert-css: (".docblock .information .should_panic", {"color": "rgb(255, 0, 0)"})
    -assert-css: (".docblock .example-wrap .should_panic", {"border-left": "2px solid rgb(255, 0, 0)"})
    +assert-css: (".docblock .example-wrap pre.should_panic", {"border-left": "2px solid rgb(255, 0, 0)"})
     
     // ignore block
     assert-css: (".docblock .information .ignore", {"color": "rgba(255, 142, 0, 0.6)"})
    -assert-css: (".docblock .example-wrap .ignore", {"border-left": "2px solid rgba(255, 142, 0, 0.6)"})
    +assert-css: (".docblock .example-wrap pre.ignore", {"border-left": "2px solid rgba(255, 142, 0, 0.6)"})
     
     move-cursor-to: ".docblock .information .ignore"
     
     assert-css: (".docblock .information .ignore", {"color": "rgb(255, 142, 0)"})
    -assert-css: (".docblock .example-wrap .ignore", {"border-left": "2px solid rgb(255, 142, 0)"})
    +assert-css: (".docblock .example-wrap pre.ignore", {"border-left": "2px solid rgb(255, 142, 0)"})
     
     
     // Light theme.
    @@ -39,30 +39,30 @@ local-storage: {"rustdoc-theme": "light"}
     reload:
     
     assert-css: (".docblock .information .compile_fail", {"color": "rgba(255, 0, 0, 0.5)"})
    -assert-css: (".docblock .example-wrap .compile_fail", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
    +assert-css: (".docblock .example-wrap pre.compile_fail", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
     
     move-cursor-to: ".docblock .information .compile_fail"
     
     assert-css: (".docblock .information .compile_fail", {"color": "rgb(255, 0, 0)"})
    -assert-css: (".docblock .example-wrap .compile_fail", {"border-left": "2px solid rgb(255, 0, 0)"})
    +assert-css: (".docblock .example-wrap pre.compile_fail", {"border-left": "2px solid rgb(255, 0, 0)"})
     
     // should_panic block
     assert-css: (".docblock .information .should_panic", {"color": "rgba(255, 0, 0, 0.5)"})
    -assert-css: (".docblock .example-wrap .should_panic", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
    +assert-css: (".docblock .example-wrap pre.should_panic", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
     
     move-cursor-to: ".docblock .information .should_panic"
     
     assert-css: (".docblock .information .should_panic", {"color": "rgb(255, 0, 0)"})
    -assert-css: (".docblock .example-wrap .should_panic", {"border-left": "2px solid rgb(255, 0, 0)"})
    +assert-css: (".docblock .example-wrap pre.should_panic", {"border-left": "2px solid rgb(255, 0, 0)"})
     
     // ignore block
     assert-css: (".docblock .information .ignore", {"color": "rgba(255, 142, 0, 0.6)"})
    -assert-css: (".docblock .example-wrap .ignore", {"border-left": "2px solid rgba(255, 142, 0, 0.6)"})
    +assert-css: (".docblock .example-wrap pre.ignore", {"border-left": "2px solid rgba(255, 142, 0, 0.6)"})
     
     move-cursor-to: ".docblock .information .ignore"
     
     assert-css: (".docblock .information .ignore", {"color": "rgb(255, 142, 0)"})
    -assert-css: (".docblock .example-wrap .ignore", {"border-left": "2px solid rgb(255, 142, 0)"})
    +assert-css: (".docblock .example-wrap pre.ignore", {"border-left": "2px solid rgb(255, 142, 0)"})
     
     
     // Ayu theme.
    @@ -70,27 +70,27 @@ local-storage: {"rustdoc-theme": "ayu"}
     reload:
     
     assert-css: (".docblock .information .compile_fail", {"color": "rgba(255, 0, 0, 0.5)"})
    -assert-css: (".docblock .example-wrap .compile_fail", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
    +assert-css: (".docblock .example-wrap pre.compile_fail", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
     
     move-cursor-to: ".docblock .information .compile_fail"
     
     assert-css: (".docblock .information .compile_fail", {"color": "rgb(255, 0, 0)"})
    -assert-css: (".docblock .example-wrap .compile_fail", {"border-left": "2px solid rgb(255, 0, 0)"})
    +assert-css: (".docblock .example-wrap pre.compile_fail", {"border-left": "2px solid rgb(255, 0, 0)"})
     
     // should_panic block
     assert-css: (".docblock .information .should_panic", {"color": "rgba(255, 0, 0, 0.5)"})
    -assert-css: (".docblock .example-wrap .should_panic", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
    +assert-css: (".docblock .example-wrap pre.should_panic", {"border-left": "2px solid rgba(255, 0, 0, 0.5)"})
     
     move-cursor-to: ".docblock .information .should_panic"
     
     assert-css: (".docblock .information .should_panic", {"color": "rgb(255, 0, 0)"})
    -assert-css: (".docblock .example-wrap .should_panic", {"border-left": "2px solid rgb(255, 0, 0)"})
    +assert-css: (".docblock .example-wrap pre.should_panic", {"border-left": "2px solid rgb(255, 0, 0)"})
     
     // ignore block
     assert-css: (".docblock .information .ignore", {"color": "rgba(255, 142, 0, 0.6)"})
    -assert-css: (".docblock .example-wrap .ignore", {"border-left": "2px solid rgba(255, 142, 0, 0.6)"})
    +assert-css: (".docblock .example-wrap pre.ignore", {"border-left": "2px solid rgba(255, 142, 0, 0.6)"})
     
     move-cursor-to: ".docblock .information .ignore"
     
     assert-css: (".docblock .information .ignore", {"color": "rgb(255, 142, 0)"})
    -assert-css: (".docblock .example-wrap .ignore", {"border-left": "2px solid rgb(255, 142, 0)"})
    +assert-css: (".docblock .example-wrap pre.ignore", {"border-left": "2px solid rgb(255, 142, 0)"})
    diff --git a/src/test/rustdoc-gui/overflow-tooltip-information.goml b/src/test/rustdoc-gui/overflow-tooltip-information.goml
    index 7ef85a4c4456..5be1aff8d3bc 100644
    --- a/src/test/rustdoc-gui/overflow-tooltip-information.goml
    +++ b/src/test/rustdoc-gui/overflow-tooltip-information.goml
    @@ -2,7 +2,7 @@
     // have overflow and max-width CSS rules set because they create a bug in firefox on
     // mac. For more information: https://github.com/rust-lang/rust/issues/89185
     goto: file://|DOC_PATH|/test_docs/fn.foo.html
    -assert-css: (".docblock > .information", {
    +assert-css: (".docblock > .example-wrap > .information", {
         "overflow-x": "visible",
         "max-width": "none"
     }, ALL)
    
    From 72791061666c45e830dade2445354a6f60699d69 Mon Sep 17 00:00:00 2001
    From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= 
    Date: Fri, 9 Sep 2022 00:00:00 +0000
    Subject: [PATCH 4394/5092] Introduce a fallible variant of
     LLVMConstIntGetZExtValue
    
    which verifies that a constant bit width is within 64 bits or fails.
    ---
     compiler/rustc_codegen_llvm/src/common.rs         |  6 +++++-
     compiler/rustc_codegen_llvm/src/llvm/ffi.rs       |  2 +-
     compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp  |  8 ++++++++
     src/test/ui/codegen/issue-101585-128bit-repeat.rs | 14 ++++++++++++++
     4 files changed, 28 insertions(+), 2 deletions(-)
     create mode 100644 src/test/ui/codegen/issue-101585-128bit-repeat.rs
    
    diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
    index 488ea72c3b77..acee9134fb96 100644
    --- a/compiler/rustc_codegen_llvm/src/common.rs
    +++ b/compiler/rustc_codegen_llvm/src/common.rs
    @@ -215,7 +215,11 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         }
     
         fn const_to_opt_uint(&self, v: &'ll Value) -> Option {
    -        try_as_const_integral(v).map(|v| unsafe { llvm::LLVMConstIntGetZExtValue(v) })
    +        try_as_const_integral(v).and_then(|v| unsafe {
    +            let mut i = 0u64;
    +            let success = llvm::LLVMRustConstIntGetZExtValue(v, &mut i);
    +            success.then_some(i)
    +        })
         }
     
         fn const_to_opt_u128(&self, v: &'ll Value, sign_ext: bool) -> Option {
    diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
    index 172684414fc5..ce27dc5a5d1e 100644
    --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
    +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
    @@ -1096,7 +1096,7 @@ extern "C" {
         pub fn LLVMConstInt(IntTy: &Type, N: c_ulonglong, SignExtend: Bool) -> &Value;
         pub fn LLVMConstIntOfArbitraryPrecision(IntTy: &Type, Wn: c_uint, Ws: *const u64) -> &Value;
         pub fn LLVMConstReal(RealTy: &Type, N: f64) -> &Value;
    -    pub fn LLVMConstIntGetZExtValue(ConstantVal: &ConstantInt) -> c_ulonglong;
    +    pub fn LLVMRustConstIntGetZExtValue(ConstantVal: &ConstantInt, Value: &mut u64) -> bool;
         pub fn LLVMRustConstInt128Get(
             ConstantVal: &ConstantInt,
             SExt: bool,
    diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
    index 931ce78721cb..6ee3c7d68213 100644
    --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
    +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
    @@ -1618,6 +1618,14 @@ extern "C" LLVMValueRef LLVMRustConstInBoundsGEP2(LLVMTypeRef Ty,
       return wrap(ConstantExpr::getInBoundsGetElementPtr(unwrap(Ty), Val, IdxList));
     }
     
    +extern "C" bool LLVMRustConstIntGetZExtValue(LLVMValueRef CV, uint64_t *value) {
    +    auto C = unwrap(CV);
    +    if (C->getBitWidth() > 64)
    +      return false;
    +    *value = C->getZExtValue();
    +    return true;
    +}
    +
     // Returns true if both high and low were successfully set. Fails in case constant wasn’t any of
     // the common sizes (1, 8, 16, 32, 64, 128 bits)
     extern "C" bool LLVMRustConstInt128Get(LLVMValueRef CV, bool sext, uint64_t *high, uint64_t *low)
    diff --git a/src/test/ui/codegen/issue-101585-128bit-repeat.rs b/src/test/ui/codegen/issue-101585-128bit-repeat.rs
    new file mode 100644
    index 000000000000..c6a686597e9c
    --- /dev/null
    +++ b/src/test/ui/codegen/issue-101585-128bit-repeat.rs
    @@ -0,0 +1,14 @@
    +// Regression test for issue 101585.
    +// run-pass
    +
    +fn main() {
    +    fn min_array_ok() -> [i128; 1] {
    +        [i128::MIN]
    +    }
    +    assert_eq!(min_array_ok(), [-170141183460469231731687303715884105728i128]);
    +
    +    fn min_array_nok() -> [i128; 1] {
    +        [i128::MIN; 1]
    +    }
    +    assert_eq!(min_array_nok(), [-170141183460469231731687303715884105728i128]);
    +}
    
    From e4d3abfe7720c05f0f2e752d3054236341cd5e9e Mon Sep 17 00:00:00 2001
    From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= 
    Date: Fri, 9 Sep 2022 00:00:00 +0000
    Subject: [PATCH 4395/5092] Use memset when repeating 128bit zero value
    
    ---
     compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
    index 26b9fbf44284..574746e340b7 100644
    --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
    +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
    @@ -87,7 +87,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         let size = bx.const_usize(dest.layout.size.bytes());
     
                         // Use llvm.memset.p0i8.* to initialize all zero arrays
    -                    if bx.cx().const_to_opt_uint(v) == Some(0) {
    +                    if bx.cx().const_to_opt_u128(v, false) == Some(0) {
                             let fill = bx.cx().const_u8(0);
                             bx.memset(start, fill, size, dest.align, MemFlags::empty());
                             return bx;
    
    From 052887e4b4c86426423ecd6f244e3e25cd71dd49 Mon Sep 17 00:00:00 2001
    From: Yan Chen 
    Date: Mon, 8 Aug 2022 16:58:27 -0700
    Subject: [PATCH 4396/5092] Add inline-llvm option for disabling/enabling LLVM
     inlining
    
    ---
     compiler/rustc_codegen_llvm/src/attributes.rs | 4 ++++
     compiler/rustc_session/src/options.rs         | 2 ++
     src/test/rustdoc-ui/z-help.stdout             | 1 +
     3 files changed, 7 insertions(+)
    
    diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
    index b38684a63e41..eff2436d41ca 100644
    --- a/compiler/rustc_codegen_llvm/src/attributes.rs
    +++ b/compiler/rustc_codegen_llvm/src/attributes.rs
    @@ -35,6 +35,10 @@ pub fn apply_to_callsite(callsite: &Value, idx: AttributePlace, attrs: &[&Attrib
     /// Get LLVM attribute for the provided inline heuristic.
     #[inline]
     fn inline_attr<'ll>(cx: &CodegenCx<'ll, '_>, inline: InlineAttr) -> Option<&'ll Attribute> {
    +    if !cx.tcx.sess.opts.unstable_opts.inline_llvm {
    +        // disable LLVM inlining
    +        return Some(AttributeKind::NoInline.create_attr(cx.llcx));
    +    }
         match inline {
             InlineAttr::Hint => Some(AttributeKind::InlineHint.create_attr(cx.llcx)),
             InlineAttr::Always => Some(AttributeKind::AlwaysInline.create_attr(cx.llcx)),
    diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
    index 9f07394b61ab..a25e3362a0c3 100644
    --- a/compiler/rustc_session/src/options.rs
    +++ b/compiler/rustc_session/src/options.rs
    @@ -1345,6 +1345,8 @@ options! {
             "hash spans relative to their parent item for incr. comp. (default: no)"),
         incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
             "verify incr. comp. hashes of green query instances (default: no)"),
    +    inline_llvm: bool = (true, parse_bool, [TRACKED],
    +        "enable LLVM inlining (default: yes)"),
         inline_mir: Option = (None, parse_opt_bool, [TRACKED],
             "enable MIR inlining (default: no)"),
         inline_mir_threshold: Option = (None, parse_opt_number, [TRACKED],
    diff --git a/src/test/rustdoc-ui/z-help.stdout b/src/test/rustdoc-ui/z-help.stdout
    index 236469ce9797..73aa0a577c4d 100644
    --- a/src/test/rustdoc-ui/z-help.stdout
    +++ b/src/test/rustdoc-ui/z-help.stdout
    @@ -54,6 +54,7 @@
         -Z                        incremental-info=val -- print high-level information about incremental reuse (or the lack thereof) (default: no)
         -Z              incremental-relative-spans=val -- hash spans relative to their parent item for incr. comp. (default: no)
         -Z                  incremental-verify-ich=val -- verify incr. comp. hashes of green query instances (default: no)
    +    -Z                             inline-llvm=val -- enable LLVM inlining (default: yes)
         -Z                              inline-mir=val -- enable MIR inlining (default: no)
         -Z                    inline-mir-threshold=val -- a default MIR inlining threshold (default: 50)
         -Z               inline-mir-hint-threshold=val -- inlining threshold for functions with inline hint (default: 100)
    
    From f632dbe46fb0041c786450f7a3c37a1a5b7208a9 Mon Sep 17 00:00:00 2001
    From: Oli Scherer 
    Date: Tue, 6 Sep 2022 14:08:59 +0000
    Subject: [PATCH 4397/5092] The `<*const T>::guaranteed_*` methods now return
     an option for the unknown case
    
    ---
     .../src/intrinsics/mod.rs                     |   9 +-
     .../rustc_codegen_ssa/src/mir/intrinsic.rs    |   8 +-
     .../src/const_eval/machine.rs                 |  49 +++---
     .../src/const_eval/valtrees.rs                |   2 +-
     compiler/rustc_span/src/symbol.rs             |   3 +-
     compiler/rustc_typeck/src/check/intrinsic.rs  |   7 +-
     library/core/src/intrinsics.rs                |  25 ++-
     library/core/src/ptr/const_ptr.rs             |  55 +++----
     library/core/src/ptr/mut_ptr.rs               |  49 +++---
     ...arate_const_switch.identity.ConstProp.diff | 146 ------------------
     ...const_switch.identity.PreCodegen.after.mir | 124 ---------------
     ...te_const_switch.too_complex.ConstProp.diff | 103 ------------
     ...st_switch.too_complex.PreCodegen.after.mir |  73 ---------
     src/test/ui/consts/miri_unleashed/slice_eq.rs |  12 +-
     src/test/ui/consts/ptr_comparisons.rs         |  24 +--
     src/test/ui/consts/ptr_comparisons.stderr     |  14 +-
     16 files changed, 119 insertions(+), 584 deletions(-)
     delete mode 100644 src/test/mir-opt/separate_const_switch.identity.ConstProp.diff
     delete mode 100644 src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir
     delete mode 100644 src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff
     delete mode 100644 src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir
    
    diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
    index 39e9e784a478..586c9489dd44 100644
    --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
    +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
    @@ -819,20 +819,13 @@ fn codegen_regular_intrinsic_call<'tcx>(
                 ret.write_cvalue(fx, val);
             }
     
    -        sym::ptr_guaranteed_eq => {
    +        sym::ptr_guaranteed_cmp => {
                 intrinsic_args!(fx, args => (a, b); intrinsic);
     
                 let val = crate::num::codegen_ptr_binop(fx, BinOp::Eq, a, b);
                 ret.write_cvalue(fx, val);
             }
     
    -        sym::ptr_guaranteed_ne => {
    -            intrinsic_args!(fx, args => (a, b); intrinsic);
    -
    -            let val = crate::num::codegen_ptr_binop(fx, BinOp::Ne, a, b);
    -            ret.write_cvalue(fx, val);
    -        }
    -
             sym::caller_location => {
                 intrinsic_args!(fx, args => (); intrinsic);
     
    diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
    index 16aad07194da..8818bf9237dd 100644
    --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
    +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
    @@ -555,14 +555,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     return;
                 }
     
    -            sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
    +            sym::ptr_guaranteed_cmp => {
                     let a = args[0].immediate();
                     let b = args[1].immediate();
    -                if name == sym::ptr_guaranteed_eq {
    -                    bx.icmp(IntPredicate::IntEQ, a, b)
    -                } else {
    -                    bx.icmp(IntPredicate::IntNE, a, b)
    -                }
    +                bx.icmp(IntPredicate::IntEQ, a, b)
                 }
     
                 sym::ptr_offset_from | sym::ptr_offset_from_unsigned => {
    diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
    index 6e5c840bdfd6..e5acacd91888 100644
    --- a/compiler/rustc_const_eval/src/const_eval/machine.rs
    +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
    @@ -191,34 +191,35 @@ impl interpret::MayLeak for ! {
     }
     
     impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
    -    fn guaranteed_eq(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, bool> {
    +    /// See documentation on the `ptr_guaranteed_cmp` intrinsic.
    +    fn guaranteed_cmp(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, u8> {
             Ok(match (a, b) {
                 // Comparisons between integers are always known.
    -            (Scalar::Int { .. }, Scalar::Int { .. }) => a == b,
    -            // Equality with integers can never be known for sure.
    -            (Scalar::Int { .. }, Scalar::Ptr(..)) | (Scalar::Ptr(..), Scalar::Int { .. }) => false,
    -            // FIXME: return `true` for when both sides are the same pointer, *except* that
    -            // some things (like functions and vtables) do not have stable addresses
    -            // so we need to be careful around them (see e.g. #73722).
    -            (Scalar::Ptr(..), Scalar::Ptr(..)) => false,
    -        })
    -    }
    -
    -    fn guaranteed_ne(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, bool> {
    -        Ok(match (a, b) {
    -            // Comparisons between integers are always known.
    -            (Scalar::Int(_), Scalar::Int(_)) => a != b,
    +            (Scalar::Int { .. }, Scalar::Int { .. }) => {
    +                if a == b {
    +                    1
    +                } else {
    +                    0
    +                }
    +            }
                 // Comparisons of abstract pointers with null pointers are known if the pointer
                 // is in bounds, because if they are in bounds, the pointer can't be null.
                 // Inequality with integers other than null can never be known for sure.
                 (Scalar::Int(int), ptr @ Scalar::Ptr(..))
    -            | (ptr @ Scalar::Ptr(..), Scalar::Int(int)) => {
    -                int.is_null() && !self.scalar_may_be_null(ptr)?
    +            | (ptr @ Scalar::Ptr(..), Scalar::Int(int))
    +                if int.is_null() && !self.scalar_may_be_null(ptr)? =>
    +            {
    +                0
                 }
    -            // FIXME: return `true` for at least some comparisons where we can reliably
    +            // Equality with integers can never be known for sure.
    +            (Scalar::Int { .. }, Scalar::Ptr(..)) | (Scalar::Ptr(..), Scalar::Int { .. }) => 2,
    +            // FIXME: return a `1` for when both sides are the same pointer, *except* that
    +            // some things (like functions and vtables) do not have stable addresses
    +            // so we need to be careful around them (see e.g. #73722).
    +            // FIXME: return `0` for at least some comparisons where we can reliably
                 // determine the result of runtime inequality tests at compile-time.
                 // Examples include comparison of addresses in different static items.
    -            (Scalar::Ptr(..), Scalar::Ptr(..)) => false,
    +            (Scalar::Ptr(..), Scalar::Ptr(..)) => 2,
             })
         }
     }
    @@ -329,15 +330,11 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
                 throw_unsup_format!("intrinsic `{intrinsic_name}` is not supported at compile-time");
             };
             match intrinsic_name {
    -            sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
    +            sym::ptr_guaranteed_cmp => {
                     let a = ecx.read_scalar(&args[0])?;
                     let b = ecx.read_scalar(&args[1])?;
    -                let cmp = if intrinsic_name == sym::ptr_guaranteed_eq {
    -                    ecx.guaranteed_eq(a, b)?
    -                } else {
    -                    ecx.guaranteed_ne(a, b)?
    -                };
    -                ecx.write_scalar(Scalar::from_bool(cmp), dest)?;
    +                let cmp = ecx.guaranteed_cmp(a, b)?;
    +                ecx.write_scalar(Scalar::from_u8(cmp), dest)?;
                 }
                 sym::const_allocate => {
                     let size = ecx.read_scalar(&args[0])?.to_machine_usize(ecx)?;
    diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
    index 8b7c3cf3377c..a964fe8465ee 100644
    --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
    +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
    @@ -97,7 +97,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
             }
     
             // Raw pointers are not allowed in type level constants, as we cannot properly test them for
    -        // equality at compile-time (see `ptr_guaranteed_eq`/`_ne`).
    +        // equality at compile-time (see `ptr_guaranteed_cmp`).
             // Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to
             // agree with runtime equality tests.
             ty::FnPtr(_) | ty::RawPtr(_) => Err(ValTreeCreationError::NonSupportedType),
    diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
    index 75b1dfc856ac..e32a6d5b9e18 100644
    --- a/compiler/rustc_span/src/symbol.rs
    +++ b/compiler/rustc_span/src/symbol.rs
    @@ -1118,8 +1118,7 @@ symbols! {
             profiler_builtins,
             profiler_runtime,
             ptr,
    -        ptr_guaranteed_eq,
    -        ptr_guaranteed_ne,
    +        ptr_guaranteed_cmp,
             ptr_mask,
             ptr_null,
             ptr_null_mut,
    diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs
    index 73dd7122e269..4fa33da50c9e 100644
    --- a/compiler/rustc_typeck/src/check/intrinsic.rs
    +++ b/compiler/rustc_typeck/src/check/intrinsic.rs
    @@ -95,8 +95,7 @@ pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety {
             | sym::type_id
             | sym::likely
             | sym::unlikely
    -        | sym::ptr_guaranteed_eq
    -        | sym::ptr_guaranteed_ne
    +        | sym::ptr_guaranteed_cmp
             | sym::minnumf32
             | sym::minnumf64
             | sym::maxnumf32
    @@ -302,8 +301,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
                     (1, vec![param(0), param(0)], tcx.intern_tup(&[param(0), tcx.types.bool]))
                 }
     
    -            sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
    -                (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.bool)
    +            sym::ptr_guaranteed_cmp => {
    +                (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.u8)
                 }
     
                 sym::const_allocate => {
    diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
    index 56f5824efd4c..11c75e2c9124 100644
    --- a/library/core/src/intrinsics.rs
    +++ b/library/core/src/intrinsics.rs
    @@ -2013,21 +2013,24 @@ extern "rust-intrinsic" {
         pub fn ptr_offset_from_unsigned(ptr: *const T, base: *const T) -> usize;
     
         /// See documentation of `<*const T>::guaranteed_eq` for details.
    +    /// Returns `2` if the result is unknown.
    +    /// Returns `1` if the pointers are guaranteed equal
    +    /// Returns `0` if the pointers are guaranteed inequal
         ///
         /// Note that, unlike most intrinsics, this is safe to call;
         /// it does not require an `unsafe` block.
         /// Therefore, implementations must not require the user to uphold
         /// any safety invariants.
         #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
    +    #[cfg(not(bootstrap))]
    +    pub fn ptr_guaranteed_cmp(ptr: *const T, other: *const T) -> u8;
    +
    +    #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
    +    #[cfg(bootstrap)]
         pub fn ptr_guaranteed_eq(ptr: *const T, other: *const T) -> bool;
     
    -    /// See documentation of `<*const T>::guaranteed_ne` for details.
    -    ///
    -    /// Note that, unlike most intrinsics, this is safe to call;
    -    /// it does not require an `unsafe` block.
    -    /// Therefore, implementations must not require the user to uphold
    -    /// any safety invariants.
         #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
    +    #[cfg(bootstrap)]
         pub fn ptr_guaranteed_ne(ptr: *const T, other: *const T) -> bool;
     
         /// Allocates a block of memory at compile time.
    @@ -2213,6 +2216,16 @@ pub(crate) fn is_nonoverlapping(src: *const T, dst: *const T, count: usize) -
         diff >= size
     }
     
    +#[cfg(bootstrap)]
    +pub const fn ptr_guaranteed_cmp(a: *const (), b: *const ()) -> u8 {
    +    match (ptr_guaranteed_eq(a, b), ptr_guaranteed_ne(a, b)) {
    +        (false, false) => 2,
    +        (true, false) => 1,
    +        (false, true) => 0,
    +        (true, true) => unreachable!(),
    +    }
    +}
    +
     /// Copies `count * size_of::()` bytes from `src` to `dst`. The source
     /// and destination must *not* overlap.
     ///
    diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
    index 80bff74f3e9f..fcdf69a7aaa4 100644
    --- a/library/core/src/ptr/const_ptr.rs
    +++ b/library/core/src/ptr/const_ptr.rs
    @@ -36,7 +36,10 @@ impl *const T {
         pub const fn is_null(self) -> bool {
             // Compare via a cast to a thin pointer, so fat pointers are only
             // considering their "data" part for null-ness.
    -        (self as *const u8).guaranteed_eq(null())
    +        match (self as *const u8).guaranteed_eq(null()) {
    +            None => false,
    +            Some(res) => res,
    +        }
         }
     
         /// Casts to a pointer of another type.
    @@ -770,20 +773,16 @@ impl *const T {
     
         /// Returns whether two pointers are guaranteed to be equal.
         ///
    -    /// At runtime this function behaves like `self == other`.
    +    /// At runtime this function behaves like `Some(self == other)`.
         /// However, in some contexts (e.g., compile-time evaluation),
         /// it is not always possible to determine equality of two pointers, so this function may
    -    /// spuriously return `false` for pointers that later actually turn out to be equal.
    -    /// But when it returns `true`, the pointers are guaranteed to be equal.
    +    /// spuriously return `None` for pointers that later actually turn out to have its equality known.
    +    /// But when it returns `Some`, the pointers' equality is guaranteed to be known.
         ///
    -    /// This function is the mirror of [`guaranteed_ne`], but not its inverse. There are pointer
    -    /// comparisons for which both functions return `false`.
    -    ///
    -    /// [`guaranteed_ne`]: #method.guaranteed_ne
    -    ///
    -    /// The return value may change depending on the compiler version and unsafe code must not
    +    /// The return value may change from `Some` to `None` and vice versa depending on the compiler
    +    /// version and unsafe code must not
         /// rely on the result of this function for soundness. It is suggested to only use this function
    -    /// for performance optimizations where spurious `false` return values by this function do not
    +    /// for performance optimizations where spurious `None` return values by this function do not
         /// affect the outcome, but just the performance.
         /// The consequences of using this method to make runtime and compile-time code behave
         /// differently have not been explored. This method should not be used to introduce such
    @@ -792,29 +791,28 @@ impl *const T {
         #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
         #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
         #[inline]
    -    pub const fn guaranteed_eq(self, other: *const T) -> bool
    +    pub const fn guaranteed_eq(self, other: *const T) -> Option
         where
             T: Sized,
         {
    -        intrinsics::ptr_guaranteed_eq(self, other)
    +        match intrinsics::ptr_guaranteed_cmp(self as _, other as _) {
    +            2 => None,
    +            other => Some(other == 1),
    +        }
         }
     
    -    /// Returns whether two pointers are guaranteed to be unequal.
    +    /// Returns whether two pointers are guaranteed to be inequal.
         ///
    -    /// At runtime this function behaves like `self != other`.
    +    /// At runtime this function behaves like `Some(self == other)`.
         /// However, in some contexts (e.g., compile-time evaluation),
    -    /// it is not always possible to determine the inequality of two pointers, so this function may
    -    /// spuriously return `false` for pointers that later actually turn out to be unequal.
    -    /// But when it returns `true`, the pointers are guaranteed to be unequal.
    +    /// it is not always possible to determine inequality of two pointers, so this function may
    +    /// spuriously return `None` for pointers that later actually turn out to have its inequality known.
    +    /// But when it returns `Some`, the pointers' inequality is guaranteed to be known.
         ///
    -    /// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer
    -    /// comparisons for which both functions return `false`.
    -    ///
    -    /// [`guaranteed_eq`]: #method.guaranteed_eq
    -    ///
    -    /// The return value may change depending on the compiler version and unsafe code must not
    +    /// The return value may change from `Some` to `None` and vice versa depending on the compiler
    +    /// version and unsafe code must not
         /// rely on the result of this function for soundness. It is suggested to only use this function
    -    /// for performance optimizations where spurious `false` return values by this function do not
    +    /// for performance optimizations where spurious `None` return values by this function do not
         /// affect the outcome, but just the performance.
         /// The consequences of using this method to make runtime and compile-time code behave
         /// differently have not been explored. This method should not be used to introduce such
    @@ -823,11 +821,14 @@ impl *const T {
         #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
         #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
         #[inline]
    -    pub const fn guaranteed_ne(self, other: *const T) -> bool
    +    pub const fn guaranteed_ne(self, other: *const T) -> Option
         where
             T: Sized,
         {
    -        intrinsics::ptr_guaranteed_ne(self, other)
    +        match self.guaranteed_eq(other) {
    +            None => None,
    +            Some(eq) => Some(!eq),
    +        }
         }
     
         /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`).
    diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
    index 3e4c3ae07567..460f3df5feea 100644
    --- a/library/core/src/ptr/mut_ptr.rs
    +++ b/library/core/src/ptr/mut_ptr.rs
    @@ -35,7 +35,10 @@ impl *mut T {
         pub const fn is_null(self) -> bool {
             // Compare via a cast to a thin pointer, so fat pointers are only
             // considering their "data" part for null-ness.
    -        (self as *mut u8).guaranteed_eq(null_mut())
    +        match (self as *mut u8).guaranteed_eq(null_mut()) {
    +            None => false,
    +            Some(res) => res,
    +        }
         }
     
         /// Casts to a pointer of another type.
    @@ -697,20 +700,16 @@ impl *mut T {
     
         /// Returns whether two pointers are guaranteed to be equal.
         ///
    -    /// At runtime this function behaves like `self == other`.
    +    /// At runtime this function behaves like `Some(self == other)`.
         /// However, in some contexts (e.g., compile-time evaluation),
         /// it is not always possible to determine equality of two pointers, so this function may
    -    /// spuriously return `false` for pointers that later actually turn out to be equal.
    -    /// But when it returns `true`, the pointers are guaranteed to be equal.
    +    /// spuriously return `None` for pointers that later actually turn out to have its equality known.
    +    /// But when it returns `Some`, the pointers' equality is guaranteed to be known.
         ///
    -    /// This function is the mirror of [`guaranteed_ne`], but not its inverse. There are pointer
    -    /// comparisons for which both functions return `false`.
    -    ///
    -    /// [`guaranteed_ne`]: #method.guaranteed_ne
    -    ///
    -    /// The return value may change depending on the compiler version and unsafe code might not
    +    /// The return value may change from `Some` to `None` and vice versa depending on the compiler
    +    /// version and unsafe code must not
         /// rely on the result of this function for soundness. It is suggested to only use this function
    -    /// for performance optimizations where spurious `false` return values by this function do not
    +    /// for performance optimizations where spurious `None` return values by this function do not
         /// affect the outcome, but just the performance.
         /// The consequences of using this method to make runtime and compile-time code behave
         /// differently have not been explored. This method should not be used to introduce such
    @@ -719,29 +718,25 @@ impl *mut T {
         #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
         #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
         #[inline]
    -    pub const fn guaranteed_eq(self, other: *mut T) -> bool
    +    pub const fn guaranteed_eq(self, other: *mut T) -> Option
         where
             T: Sized,
         {
    -        intrinsics::ptr_guaranteed_eq(self as *const _, other as *const _)
    +        (self as *const T).guaranteed_eq(other as _)
         }
     
    -    /// Returns whether two pointers are guaranteed to be unequal.
    +    /// Returns whether two pointers are guaranteed to be inequal.
         ///
    -    /// At runtime this function behaves like `self != other`.
    +    /// At runtime this function behaves like `Some(self == other)`.
         /// However, in some contexts (e.g., compile-time evaluation),
    -    /// it is not always possible to determine the inequality of two pointers, so this function may
    -    /// spuriously return `false` for pointers that later actually turn out to be unequal.
    -    /// But when it returns `true`, the pointers are guaranteed to be unequal.
    +    /// it is not always possible to determine inequality of two pointers, so this function may
    +    /// spuriously return `None` for pointers that later actually turn out to have its inequality known.
    +    /// But when it returns `Some`, the pointers' inequality is guaranteed to be known.
         ///
    -    /// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer
    -    /// comparisons for which both functions return `false`.
    -    ///
    -    /// [`guaranteed_eq`]: #method.guaranteed_eq
    -    ///
    -    /// The return value may change depending on the compiler version and unsafe code might not
    +    /// The return value may change from `Some` to `None` and vice versa depending on the compiler
    +    /// version and unsafe code must not
         /// rely on the result of this function for soundness. It is suggested to only use this function
    -    /// for performance optimizations where spurious `false` return values by this function do not
    +    /// for performance optimizations where spurious `None` return values by this function do not
         /// affect the outcome, but just the performance.
         /// The consequences of using this method to make runtime and compile-time code behave
         /// differently have not been explored. This method should not be used to introduce such
    @@ -750,11 +745,11 @@ impl *mut T {
         #[unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
         #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
         #[inline]
    -    pub const unsafe fn guaranteed_ne(self, other: *mut T) -> bool
    +    pub const fn guaranteed_ne(self, other: *mut T) -> Option
         where
             T: Sized,
         {
    -        intrinsics::ptr_guaranteed_ne(self as *const _, other as *const _)
    +        (self as *const T).guaranteed_ne(other as _)
         }
     
         /// Calculates the distance between two pointers. The returned value is in
    diff --git a/src/test/mir-opt/separate_const_switch.identity.ConstProp.diff b/src/test/mir-opt/separate_const_switch.identity.ConstProp.diff
    deleted file mode 100644
    index 28536dc28a72..000000000000
    --- a/src/test/mir-opt/separate_const_switch.identity.ConstProp.diff
    +++ /dev/null
    @@ -1,146 +0,0 @@
    -- // MIR for `identity` before ConstProp
    -+ // MIR for `identity` after ConstProp
    -  
    -  fn identity(_1: Result) -> Result {
    -      debug x => _1;                       // in scope 0 at $DIR/separate_const_switch.rs:+0:13: +0:14
    -      let mut _0: std::result::Result; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:37: +0:53
    -      let mut _2: i32;                     // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
    -      let mut _3: std::ops::ControlFlow, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
    -      let mut _4: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
    -      let mut _5: isize;                   // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
    -      let _6: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
    -      let mut _7: !;                       // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
    -      let mut _8: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
    -      let _9: i32;                         // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
    -      scope 1 {
    -          debug residual => _6;            // in scope 1 at $DIR/separate_const_switch.rs:+1:9: +1:10
    -          scope 2 {
    -              scope 8 (inlined #[track_caller]  as FromResidual>>::from_residual) { // at $DIR/separate_const_switch.rs:29:8: 29:10
    -                  debug residual => _8;    // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
    -                  let _16: i32;            // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
    -                  let mut _17: i32;        // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
    -                  let mut _18: i32;        // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
    -                  scope 9 {
    -                      debug e => _16;      // in scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
    -                      scope 10 (inlined >::from) { // at $SRC_DIR/core/src/result.rs:LL:COL
    -                          debug t => _18;  // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
    -                      }
    -                  }
    -              }
    -          }
    -      }
    -      scope 3 {
    -          debug val => _9;                 // in scope 3 at $DIR/separate_const_switch.rs:+1:8: +1:10
    -          scope 4 {
    -          }
    -      }
    -      scope 5 (inlined  as Try>::branch) { // at $DIR/separate_const_switch.rs:29:8: 29:10
    -          debug self => _4;                // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -          let mut _10: isize;              // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -          let _11: i32;                    // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -          let mut _12: i32;                // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -          let _13: i32;                    // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -          let mut _14: std::result::Result; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -          let mut _15: i32;                // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -          scope 6 {
    -              debug v => _11;              // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
    -          }
    -          scope 7 {
    -              debug e => _13;              // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
    -          }
    -      }
    -  
    -      bb0: {
    -          StorageLive(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
    -          StorageLive(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
    -          StorageLive(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
    -          _4 = _1;                         // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
    -          _10 = discriminant(_4);          // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -          switchInt(move _10) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -      }
    -  
    -      bb1: {
    -          StorageLive(_9);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
    -          _9 = ((_3 as Continue).0: i32);  // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
    -          _2 = _9;                         // scope 4 at $DIR/separate_const_switch.rs:+1:8: +1:10
    -          StorageDead(_9);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
    -          Deinit(_0);                      // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
    -          ((_0 as Ok).0: i32) = move _2;   // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
    -          discriminant(_0) = 0;            // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
    -          StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
    -          StorageDead(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
    -          return;                          // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
    -      }
    -  
    -      bb2: {
    -          unreachable;                     // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
    -      }
    -  
    -      bb3: {
    -          StorageLive(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
    -          _6 = ((_3 as Break).0: std::result::Result); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
    -          StorageLive(_8);                 // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
    -          _8 = _6;                         // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
    -          StorageLive(_16);                // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
    -          _16 = move ((_8 as Err).0: i32); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
    -          StorageLive(_17);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
    -          StorageLive(_18);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
    -          _18 = move _16;                  // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
    -          _17 = move _18;                  // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
    -          StorageDead(_18);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
    -          Deinit(_0);                      // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
    -          ((_0 as Err).0: i32) = move _17; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
    -          discriminant(_0) = 1;            // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
    -          StorageDead(_17);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
    -          StorageDead(_16);                // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
    -          StorageDead(_8);                 // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
    -          StorageDead(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
    -          StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
    -          StorageDead(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
    -          return;                          // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
    -      }
    -  
    -      bb4: {
    -          StorageLive(_13);                // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -          _13 = move ((_4 as Err).0: i32); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -          StorageLive(_14);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
    -          StorageLive(_15);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
    -          _15 = move _13;                  // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
    -          Deinit(_14);                     // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
    -          ((_14 as Err).0: i32) = move _15; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
    -          discriminant(_14) = 1;           // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
    -          StorageDead(_15);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
    -          Deinit(_3);                      // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
    -          ((_3 as Break).0: std::result::Result) = move _14; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
    -          discriminant(_3) = 1;            // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
    -          StorageDead(_14);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
    -          StorageDead(_13);                // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -          StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
    --         _5 = discriminant(_3);           // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
    --         switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
    -+         _5 = const 1_isize;              // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
    -+         switchInt(const 1_isize) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
    -      }
    -  
    -      bb5: {
    -          unreachable;                     // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -      }
    -  
    -      bb6: {
    -          StorageLive(_11);                // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -          _11 = move ((_4 as Ok).0: i32);  // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -          StorageLive(_12);                // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
    -          _12 = move _11;                  // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
    -          Deinit(_3);                      // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
    -          ((_3 as Continue).0: i32) = move _12; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
    -          discriminant(_3) = 0;            // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
    -          StorageDead(_12);                // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
    -          StorageDead(_11);                // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -          StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
    --         _5 = discriminant(_3);           // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
    --         switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
    -+         _5 = const 0_isize;              // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
    -+         switchInt(const 0_isize) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
    -      }
    -  }
    -  
    diff --git a/src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir b/src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir
    deleted file mode 100644
    index df20f0ed36b6..000000000000
    --- a/src/test/mir-opt/separate_const_switch.identity.PreCodegen.after.mir
    +++ /dev/null
    @@ -1,124 +0,0 @@
    -// MIR for `identity` after PreCodegen
    -
    -fn identity(_1: Result) -> Result {
    -    debug x => _1;                       // in scope 0 at $DIR/separate_const_switch.rs:+0:13: +0:14
    -    let mut _0: std::result::Result; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:37: +0:53
    -    let mut _2: i32;                     // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
    -    let mut _3: std::ops::ControlFlow, i32>; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
    -    let mut _4: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
    -    let _5: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
    -    let mut _6: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
    -    let _7: i32;                         // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
    -    scope 1 {
    -        debug residual => _5;            // in scope 1 at $DIR/separate_const_switch.rs:+1:9: +1:10
    -        scope 2 {
    -            scope 8 (inlined #[track_caller]  as FromResidual>>::from_residual) { // at $DIR/separate_const_switch.rs:29:8: 29:10
    -                debug residual => _6;    // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
    -                let _14: i32;            // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
    -                let mut _15: i32;        // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
    -                let mut _16: i32;        // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
    -                scope 9 {
    -                    debug e => _14;      // in scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
    -                    scope 10 (inlined >::from) { // at $SRC_DIR/core/src/result.rs:LL:COL
    -                        debug t => _16;  // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
    -                    }
    -                }
    -            }
    -        }
    -    }
    -    scope 3 {
    -        debug val => _7;                 // in scope 3 at $DIR/separate_const_switch.rs:+1:8: +1:10
    -        scope 4 {
    -        }
    -    }
    -    scope 5 (inlined  as Try>::branch) { // at $DIR/separate_const_switch.rs:29:8: 29:10
    -        debug self => _4;                // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -        let mut _8: isize;               // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -        let _9: i32;                     // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -        let mut _10: i32;                // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -        let _11: i32;                    // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -        let mut _12: std::result::Result; // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -        let mut _13: i32;                // in scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -        scope 6 {
    -            debug v => _9;               // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
    -        }
    -        scope 7 {
    -            debug e => _11;              // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
    -        }
    -    }
    -
    -    bb0: {
    -        StorageLive(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
    -        StorageLive(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
    -        StorageLive(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
    -        _4 = _1;                         // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:9
    -        _8 = discriminant(_4);           // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -        switchInt(move _8) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -    }
    -
    -    bb1: {
    -        StorageLive(_11);                // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -        _11 = move ((_4 as Err).0: i32); // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -        StorageLive(_12);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
    -        StorageLive(_13);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
    -        _13 = move _11;                  // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
    -        Deinit(_12);                     // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
    -        ((_12 as Err).0: i32) = move _13; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
    -        discriminant(_12) = 1;           // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
    -        StorageDead(_13);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
    -        Deinit(_3);                      // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
    -        ((_3 as Break).0: std::result::Result) = move _12; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
    -        discriminant(_3) = 1;            // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
    -        StorageDead(_12);                // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL
    -        StorageDead(_11);                // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -        StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
    -        StorageLive(_5);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
    -        _5 = ((_3 as Break).0: std::result::Result); // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
    -        StorageLive(_6);                 // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
    -        _6 = _5;                         // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
    -        StorageLive(_14);                // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
    -        _14 = move ((_6 as Err).0: i32); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
    -        StorageLive(_15);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
    -        StorageLive(_16);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
    -        _16 = move _14;                  // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
    -        _15 = move _16;                  // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
    -        StorageDead(_16);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
    -        Deinit(_0);                      // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
    -        ((_0 as Err).0: i32) = move _15; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
    -        discriminant(_0) = 1;            // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
    -        StorageDead(_15);                // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL
    -        StorageDead(_14);                // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL
    -        StorageDead(_6);                 // scope 2 at $DIR/separate_const_switch.rs:+1:9: +1:10
    -        StorageDead(_5);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
    -        StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
    -        StorageDead(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
    -        return;                          // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
    -    }
    -
    -    bb2: {
    -        unreachable;                     // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -    }
    -
    -    bb3: {
    -        StorageLive(_9);                 // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -        _9 = move ((_4 as Ok).0: i32);   // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -        StorageLive(_10);                // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
    -        _10 = move _9;                   // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
    -        Deinit(_3);                      // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
    -        ((_3 as Continue).0: i32) = move _10; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
    -        discriminant(_3) = 0;            // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
    -        StorageDead(_10);                // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
    -        StorageDead(_9);                 // scope 5 at $SRC_DIR/core/src/result.rs:LL:COL
    -        StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
    -        StorageLive(_7);                 // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
    -        _7 = ((_3 as Continue).0: i32);  // scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10
    -        _2 = _7;                         // scope 4 at $DIR/separate_const_switch.rs:+1:8: +1:10
    -        StorageDead(_7);                 // scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10
    -        Deinit(_0);                      // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
    -        ((_0 as Ok).0: i32) = move _2;   // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
    -        discriminant(_0) = 0;            // scope 0 at $DIR/separate_const_switch.rs:+1:5: +1:11
    -        StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+1:10: +1:11
    -        StorageDead(_3);                 // scope 0 at $DIR/separate_const_switch.rs:+2:1: +2:2
    -        return;                          // scope 0 at $DIR/separate_const_switch.rs:+2:2: +2:2
    -    }
    -}
    diff --git a/src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff b/src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff
    deleted file mode 100644
    index 28269165e1c2..000000000000
    --- a/src/test/mir-opt/separate_const_switch.too_complex.ConstProp.diff
    +++ /dev/null
    @@ -1,103 +0,0 @@
    -- // MIR for `too_complex` before ConstProp
    -+ // MIR for `too_complex` after ConstProp
    -  
    -  fn too_complex(_1: Result) -> Option {
    -      debug x => _1;                       // in scope 0 at $DIR/separate_const_switch.rs:+0:16: +0:17
    -      let mut _0: std::option::Option; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:42: +0:53
    -      let mut _2: std::ops::ControlFlow; // in scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
    -      let mut _3: isize;                   // in scope 0 at $DIR/separate_const_switch.rs:+7:13: +7:18
    -      let _4: i32;                         // in scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
    -      let mut _5: i32;                     // in scope 0 at $DIR/separate_const_switch.rs:+7:44: +7:45
    -      let _6: usize;                       // in scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18
    -      let mut _7: usize;                   // in scope 0 at $DIR/separate_const_switch.rs:+8:42: +8:43
    -      let mut _8: isize;                   // in scope 0 at $DIR/separate_const_switch.rs:+11:9: +11:33
    -      let _9: i32;                         // in scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
    -      let mut _10: i32;                    // in scope 0 at $DIR/separate_const_switch.rs:+11:42: +11:43
    -      let _11: usize;                      // in scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29
    -      scope 1 {
    -          debug v => _4;                   // in scope 1 at $DIR/separate_const_switch.rs:+7:16: +7:17
    -      }
    -      scope 2 {
    -          debug r => _6;                   // in scope 2 at $DIR/separate_const_switch.rs:+8:17: +8:18
    -      }
    -      scope 3 {
    -          debug v => _9;                   // in scope 3 at $DIR/separate_const_switch.rs:+11:31: +11:32
    -      }
    -      scope 4 {
    -          debug r => _11;                  // in scope 4 at $DIR/separate_const_switch.rs:+12:28: +12:29
    -      }
    -  
    -      bb0: {
    -          StorageLive(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
    -          _3 = discriminant(_1);           // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16
    -          switchInt(move _3) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+6:9: +6:16
    -      }
    -  
    -      bb1: {
    -          StorageLive(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18
    -          _6 = ((_1 as Err).0: usize);     // scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18
    -          StorageLive(_7);                 // scope 2 at $DIR/separate_const_switch.rs:+8:42: +8:43
    -          _7 = _6;                         // scope 2 at $DIR/separate_const_switch.rs:+8:42: +8:43
    -          Deinit(_2);                      // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44
    -          ((_2 as Break).0: usize) = move _7; // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44
    -          discriminant(_2) = 1;            // scope 2 at $DIR/separate_const_switch.rs:+8:23: +8:44
    -          StorageDead(_7);                 // scope 2 at $DIR/separate_const_switch.rs:+8:43: +8:44
    -          StorageDead(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+8:43: +8:44
    --         _8 = discriminant(_2);           // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
    --         switchInt(move _8) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
    -+         _8 = const 1_isize;              // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
    -+         switchInt(const 1_isize) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
    -      }
    -  
    -      bb2: {
    -          unreachable;                     // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16
    -      }
    -  
    -      bb3: {
    -          StorageLive(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
    -          _4 = ((_1 as Ok).0: i32);        // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
    -          StorageLive(_5);                 // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45
    -          _5 = _4;                         // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45
    -          Deinit(_2);                      // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
    -          ((_2 as Continue).0: i32) = move _5; // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
    -          discriminant(_2) = 0;            // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
    -          StorageDead(_5);                 // scope 1 at $DIR/separate_const_switch.rs:+7:45: +7:46
    -          StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+7:45: +7:46
    --         _8 = discriminant(_2);           // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
    --         switchInt(move _8) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
    -+         _8 = const 0_isize;              // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
    -+         switchInt(const 0_isize) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 0 at $DIR/separate_const_switch.rs:+5:5: +10:6
    -      }
    -  
    -      bb4: {
    -          StorageLive(_11);                // scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29
    -          _11 = ((_2 as Break).0: usize);  // scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29
    -          Deinit(_0);                      // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38
    -          discriminant(_0) = 0;            // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38
    -          StorageDead(_11);                // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38
    -          goto -> bb7;                     // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38
    -      }
    -  
    -      bb5: {
    -          unreachable;                     // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
    -      }
    -  
    -      bb6: {
    -          StorageLive(_9);                 // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
    -          _9 = ((_2 as Continue).0: i32);  // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
    -          StorageLive(_10);                // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43
    -          _10 = _9;                        // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43
    -          Deinit(_0);                      // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
    -          ((_0 as Some).0: i32) = move _10; // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
    -          discriminant(_0) = 1;            // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
    -          StorageDead(_10);                // scope 3 at $DIR/separate_const_switch.rs:+11:43: +11:44
    -          StorageDead(_9);                 // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44
    -          goto -> bb7;                     // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44
    -      }
    -  
    -      bb7: {
    -          StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+14:1: +14:2
    -          return;                          // scope 0 at $DIR/separate_const_switch.rs:+14:2: +14:2
    -      }
    -  }
    -  
    diff --git a/src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir b/src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir
    deleted file mode 100644
    index 0ee070619e79..000000000000
    --- a/src/test/mir-opt/separate_const_switch.too_complex.PreCodegen.after.mir
    +++ /dev/null
    @@ -1,73 +0,0 @@
    -// MIR for `too_complex` after PreCodegen
    -
    -fn too_complex(_1: Result) -> Option {
    -    debug x => _1;                       // in scope 0 at $DIR/separate_const_switch.rs:+0:16: +0:17
    -    let mut _0: std::option::Option; // return place in scope 0 at $DIR/separate_const_switch.rs:+0:42: +0:53
    -    let mut _2: std::ops::ControlFlow; // in scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
    -    let mut _3: isize;                   // in scope 0 at $DIR/separate_const_switch.rs:+7:13: +7:18
    -    let _4: i32;                         // in scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
    -    let mut _5: i32;                     // in scope 0 at $DIR/separate_const_switch.rs:+7:44: +7:45
    -    let _6: usize;                       // in scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18
    -    let _7: i32;                         // in scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
    -    let mut _8: i32;                     // in scope 0 at $DIR/separate_const_switch.rs:+11:42: +11:43
    -    let _9: usize;                       // in scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29
    -    scope 1 {
    -        debug v => _4;                   // in scope 1 at $DIR/separate_const_switch.rs:+7:16: +7:17
    -    }
    -    scope 2 {
    -        debug r => _6;                   // in scope 2 at $DIR/separate_const_switch.rs:+8:17: +8:18
    -    }
    -    scope 3 {
    -        debug v => _7;                   // in scope 3 at $DIR/separate_const_switch.rs:+11:31: +11:32
    -    }
    -    scope 4 {
    -        debug r => _9;                   // in scope 4 at $DIR/separate_const_switch.rs:+12:28: +12:29
    -    }
    -
    -    bb0: {
    -        StorageLive(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+5:11: +10:6
    -        _3 = discriminant(_1);           // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16
    -        switchInt(move _3) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/separate_const_switch.rs:+6:9: +6:16
    -    }
    -
    -    bb1: {
    -        StorageLive(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+8:17: +8:18
    -        StorageDead(_6);                 // scope 0 at $DIR/separate_const_switch.rs:+8:43: +8:44
    -        StorageLive(_9);                 // scope 0 at $DIR/separate_const_switch.rs:+12:28: +12:29
    -        Deinit(_0);                      // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38
    -        discriminant(_0) = 0;            // scope 4 at $DIR/separate_const_switch.rs:+12:34: +12:38
    -        StorageDead(_9);                 // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38
    -        goto -> bb4;                     // scope 0 at $DIR/separate_const_switch.rs:+12:37: +12:38
    -    }
    -
    -    bb2: {
    -        unreachable;                     // scope 0 at $DIR/separate_const_switch.rs:+6:15: +6:16
    -    }
    -
    -    bb3: {
    -        StorageLive(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
    -        _4 = ((_1 as Ok).0: i32);        // scope 0 at $DIR/separate_const_switch.rs:+7:16: +7:17
    -        StorageLive(_5);                 // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45
    -        _5 = _4;                         // scope 1 at $DIR/separate_const_switch.rs:+7:44: +7:45
    -        Deinit(_2);                      // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
    -        ((_2 as Continue).0: i32) = move _5; // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
    -        discriminant(_2) = 0;            // scope 1 at $DIR/separate_const_switch.rs:+7:22: +7:46
    -        StorageDead(_5);                 // scope 1 at $DIR/separate_const_switch.rs:+7:45: +7:46
    -        StorageDead(_4);                 // scope 0 at $DIR/separate_const_switch.rs:+7:45: +7:46
    -        StorageLive(_7);                 // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
    -        _7 = ((_2 as Continue).0: i32);  // scope 0 at $DIR/separate_const_switch.rs:+11:31: +11:32
    -        StorageLive(_8);                 // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43
    -        _8 = _7;                         // scope 3 at $DIR/separate_const_switch.rs:+11:42: +11:43
    -        Deinit(_0);                      // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
    -        ((_0 as Some).0: i32) = move _8; // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
    -        discriminant(_0) = 1;            // scope 3 at $DIR/separate_const_switch.rs:+11:37: +11:44
    -        StorageDead(_8);                 // scope 3 at $DIR/separate_const_switch.rs:+11:43: +11:44
    -        StorageDead(_7);                 // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44
    -        goto -> bb4;                     // scope 0 at $DIR/separate_const_switch.rs:+11:43: +11:44
    -    }
    -
    -    bb4: {
    -        StorageDead(_2);                 // scope 0 at $DIR/separate_const_switch.rs:+14:1: +14:2
    -        return;                          // scope 0 at $DIR/separate_const_switch.rs:+14:2: +14:2
    -    }
    -}
    diff --git a/src/test/ui/consts/miri_unleashed/slice_eq.rs b/src/test/ui/consts/miri_unleashed/slice_eq.rs
    index fd843105daf2..83e10bf1213e 100644
    --- a/src/test/ui/consts/miri_unleashed/slice_eq.rs
    +++ b/src/test/ui/consts/miri_unleashed/slice_eq.rs
    @@ -4,14 +4,10 @@
     #![feature(const_raw_ptr_comparison)]
     
     const EMPTY_SLICE: &[i32] = &[];
    -const EMPTY_EQ: bool = EMPTY_SLICE.as_ptr().guaranteed_eq(&[] as *const _);
    -const EMPTY_EQ2: bool = EMPTY_SLICE.as_ptr().guaranteed_ne(&[] as *const _);
    -const EMPTY_NE: bool = EMPTY_SLICE.as_ptr().guaranteed_ne(&[1] as *const _);
    -const EMPTY_NE2: bool = EMPTY_SLICE.as_ptr().guaranteed_eq(&[1] as *const _);
    +const EMPTY_EQ: Option = EMPTY_SLICE.as_ptr().guaranteed_eq(&[] as *const _);
    +const EMPTY_EQ2: Option = EMPTY_SLICE.as_ptr().guaranteed_eq(&[1] as *const _);
     
     fn main() {
    -    assert!(!EMPTY_EQ);
    -    assert!(!EMPTY_EQ2);
    -    assert!(!EMPTY_NE);
    -    assert!(!EMPTY_NE2);
    +    assert!(EMPTY_EQ.is_none());
    +    assert!(EMPTY_EQ2.is_none());
     }
    diff --git a/src/test/ui/consts/ptr_comparisons.rs b/src/test/ui/consts/ptr_comparisons.rs
    index 20233db09c90..0a3c2d4bedcb 100644
    --- a/src/test/ui/consts/ptr_comparisons.rs
    +++ b/src/test/ui/consts/ptr_comparisons.rs
    @@ -14,38 +14,30 @@ const FOO: &usize = &42;
     macro_rules! check {
         (eq, $a:expr, $b:expr) => {
             pub const _: () =
    -            assert!(std::intrinsics::ptr_guaranteed_eq($a as *const u8, $b as *const u8));
    +            assert!(std::intrinsics::ptr_guaranteed_cmp($a as *const u8, $b as *const u8) == 1);
         };
         (ne, $a:expr, $b:expr) => {
             pub const _: () =
    -            assert!(std::intrinsics::ptr_guaranteed_ne($a as *const u8, $b as *const u8));
    +            assert!(std::intrinsics::ptr_guaranteed_cmp($a as *const u8, $b as *const u8) == 0);
         };
    -    (!eq, $a:expr, $b:expr) => {
    +    (!, $a:expr, $b:expr) => {
             pub const _: () =
    -            assert!(!std::intrinsics::ptr_guaranteed_eq($a as *const u8, $b as *const u8));
    -    };
    -    (!ne, $a:expr, $b:expr) => {
    -        pub const _: () =
    -            assert!(!std::intrinsics::ptr_guaranteed_ne($a as *const u8, $b as *const u8));
    +            assert!(std::intrinsics::ptr_guaranteed_cmp($a as *const u8, $b as *const u8) == 2);
         };
     }
     
     check!(eq, 0, 0);
     check!(ne, 0, 1);
    -check!(!eq, 0, 1);
    -check!(!ne, 0, 0);
     check!(ne, FOO as *const _, 0);
    -check!(!eq, FOO as *const _, 0);
    +check!(ne, unsafe { (FOO as *const usize).offset(1) }, 0);
    +check!(ne, unsafe { (FOO as *const usize as *const u8).offset(3) }, 0);
    +
     // We want pointers to be equal to themselves, but aren't checking this yet because
     // there are some open questions (e.g. whether function pointers to the same function
     // compare equal, they don't necessarily at runtime).
     // The case tested here should work eventually, but does not work yet.
    -check!(!eq, FOO as *const _, FOO as *const _);
    -check!(ne, unsafe { (FOO as *const usize).offset(1) }, 0);
    -check!(!eq, unsafe { (FOO as *const usize).offset(1) }, 0);
    +check!(!, FOO as *const _, FOO as *const _);
     
    -check!(ne, unsafe { (FOO as *const usize as *const u8).offset(3) }, 0);
    -check!(!eq, unsafe { (FOO as *const usize as *const u8).offset(3) }, 0);
     
     ///////////////////////////////////////////////////////////////////////////////
     // If any of the below start compiling, make sure to add a `check` test for it.
    diff --git a/src/test/ui/consts/ptr_comparisons.stderr b/src/test/ui/consts/ptr_comparisons.stderr
    index 1d47f243f01c..3de2aba5b05e 100644
    --- a/src/test/ui/consts/ptr_comparisons.stderr
    +++ b/src/test/ui/consts/ptr_comparisons.stderr
    @@ -7,19 +7,19 @@ LL |         unsafe { intrinsics::offset(self, count) }
        |                  out-of-bounds pointer arithmetic: alloc3 has size $WORD, so pointer to $TWO_WORDS bytes starting at offset 0 is out-of-bounds
        |                  inside `ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
        |
    -  ::: $DIR/ptr_comparisons.rs:58:34
    +  ::: $DIR/ptr_comparisons.rs:50:34
        |
     LL | const _: *const usize = unsafe { (FOO as *const usize).offset(2) };
    -   |                                  ------------------------------- inside `_` at $DIR/ptr_comparisons.rs:58:34
    +   |                                  ------------------------------- inside `_` at $DIR/ptr_comparisons.rs:50:34
     
     error[E0080]: evaluation of constant value failed
    -  --> $DIR/ptr_comparisons.rs:61:33
    +  --> $DIR/ptr_comparisons.rs:53:33
        |
     LL |     unsafe { std::ptr::addr_of!((*(FOO as *const usize as *const [u8; 1000]))[999]) };
        |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: alloc3 has size $WORD, so pointer to 1000 bytes starting at offset 0 is out-of-bounds
     
     error: any use of this value will cause an error
    -  --> $DIR/ptr_comparisons.rs:65:27
    +  --> $DIR/ptr_comparisons.rs:57:27
        |
     LL | const _: usize = unsafe { std::mem::transmute::<*const usize, usize>(FOO) + 4 };
        | --------------            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
    @@ -31,7 +31,7 @@ LL | const _: usize = unsafe { std::mem::transmute::<*const usize, usize>(FOO) +
        = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
     
     error: any use of this value will cause an error
    -  --> $DIR/ptr_comparisons.rs:70:27
    +  --> $DIR/ptr_comparisons.rs:62:27
        |
     LL | const _: usize = unsafe { *std::mem::transmute::<&&usize, &usize>(&FOO) + 4 };
        | --------------            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
    @@ -46,7 +46,7 @@ error: aborting due to 4 previous errors
     For more information about this error, try `rustc --explain E0080`.
     Future incompatibility report: Future breakage diagnostic:
     error: any use of this value will cause an error
    -  --> $DIR/ptr_comparisons.rs:65:27
    +  --> $DIR/ptr_comparisons.rs:57:27
        |
     LL | const _: usize = unsafe { std::mem::transmute::<*const usize, usize>(FOO) + 4 };
        | --------------            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
    @@ -59,7 +59,7 @@ LL | const _: usize = unsafe { std::mem::transmute::<*const usize, usize>(FOO) +
     
     Future breakage diagnostic:
     error: any use of this value will cause an error
    -  --> $DIR/ptr_comparisons.rs:70:27
    +  --> $DIR/ptr_comparisons.rs:62:27
        |
     LL | const _: usize = unsafe { *std::mem::transmute::<&&usize, &usize>(&FOO) + 4 };
        | --------------            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unable to turn pointer into raw bytes
    
    From 022e3fe550406c3fbdb64f241381bc14b1937cfb Mon Sep 17 00:00:00 2001
    From: Michael Goulet 
    Date: Fri, 9 Sep 2022 14:59:54 +0000
    Subject: [PATCH 4398/5092] Equate fn outputs when inferring RPITIT hidden
     types
    
    ---
     .../rustc_typeck/src/check/compare_method.rs  | 19 +++++++++++++++++--
     1 file changed, 17 insertions(+), 2 deletions(-)
    
    diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
    index 1152a2477a2a..13a96df77b69 100644
    --- a/compiler/rustc_typeck/src/check/compare_method.rs
    +++ b/compiler/rustc_typeck/src/check/compare_method.rs
    @@ -295,12 +295,26 @@ pub(super) fn compare_predicates_and_trait_impl_trait_tys<'tcx>(
             // type would be more appropriate. In other places we have a `Vec`
             // corresponding to their `Vec`, but we don't have that here.
             // Fixing this would improve the output of test `issue-83765.rs`.
    -        let sub_result = infcx
    +        let mut result = infcx
                 .at(&cause, param_env)
                 .sup(trait_fty, impl_fty)
                 .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok));
     
    -        if let Err(terr) = sub_result {
    +        // HACK(RPITIT): #101614. When we are trying to infer the hidden types for
    +        // RPITITs, we need to equate the output tys instead of just subtyping. If
    +        // we just use `sup` above, we'll end up `&'static str <: _#1t`, which causes
    +        // us to infer `_#1t = #'_#2r str`, where `'_#2r` is unconstrained, which gets
    +        // fixed up to `ReEmpty`, and which is certainly not what we want.
    +        if trait_fty.has_infer_types() {
    +            result = result.and_then(|()| {
    +                infcx
    +                    .at(&cause, param_env)
    +                    .eq(trait_sig.output(), impl_sig.output())
    +                    .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok))
    +            });
    +        }
    +
    +        if let Err(terr) = result {
                 debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty);
     
                 let (impl_err_span, trait_err_span) =
    @@ -445,6 +459,7 @@ pub(super) fn compare_predicates_and_trait_impl_trait_tys<'tcx>(
                                 region
                             }
                         });
    +                    debug!(%ty);
                         collected_tys.insert(def_id, ty);
                     }
                     Err(err) => {
    
    From 76aefbeddb4db78400e0cba87ef783b7444cbdc8 Mon Sep 17 00:00:00 2001
    From: Tim Neumann 
    Date: Fri, 9 Sep 2022 16:15:08 +0000
    Subject: [PATCH 4399/5092] relax msan error-pattern due to LLVM changes
    
    ---
     src/test/ui/sanitize/memory-eager.rs | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/src/test/ui/sanitize/memory-eager.rs b/src/test/ui/sanitize/memory-eager.rs
    index 8a0590bf16c5..cc0593ec07dc 100644
    --- a/src/test/ui/sanitize/memory-eager.rs
    +++ b/src/test/ui/sanitize/memory-eager.rs
    @@ -10,7 +10,7 @@
     // run-fail
     // error-pattern: MemorySanitizer: use-of-uninitialized-value
     // error-pattern: Uninitialized value was created by an allocation
    -// error-pattern: in the stack frame of function 'random'
    +// error-pattern: in the stack frame
     //
     // This test case intentionally limits the usage of the std,
     // since it will be linked with an uninstrumented version of it.
    
    From b273c7502e363baeec293b972f671070e80f1391 Mon Sep 17 00:00:00 2001
    From: Michael Howell 
    Date: Fri, 9 Sep 2022 10:09:01 -0700
    Subject: [PATCH 4400/5092] rustdoc: remove unused CSS `#search { position:
     relative }`
    
    This was added in 611d0e6ccef8b60fa86ff5aa8fe3571cd36c444a, to allow its
    child `#results` element to be absolutely positioned inside it. The
    child stopped being absolute in 8c0469552e879f6319f8f96db660bab9eae1de5c.
    
    To keep the layout looking the same, the links need to not have
    `width: 100%` any more, relying instead on the box naturally growing to
    fit because it has `display: block`.
    ---
     src/librustdoc/html/static/css/rustdoc.css | 5 -----
     1 file changed, 5 deletions(-)
    
    diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
    index 22217a390124..3904568ef988 100644
    --- a/src/librustdoc/html/static/css/rustdoc.css
    +++ b/src/librustdoc/html/static/css/rustdoc.css
    @@ -596,10 +596,6 @@ h2.location a {
     	margin: 0;
     }
     
    -#search {
    -	position: relative;
    -}
    -
     .search-loading {
     	text-align: center;
     }
    @@ -977,7 +973,6 @@ so that we can apply CSS-filters to change the arrow color in themes */
     
     .search-results > a {
     	display: block;
    -	width: 100%;
     	/* A little margin ensures the browser's outlining of focused links has room to display. */
     	margin-left: 2px;
     	margin-right: 2px;
    
    From f7f4792f4f4492e62a9439bdf214acee797e0341 Mon Sep 17 00:00:00 2001
    From: Stanislav 
    Date: Fri, 9 Sep 2022 20:58:06 +0300
    Subject: [PATCH 4401/5092] fixes
    
    ---
     crates/ide/src/references.rs       |  2 --
     crates/rust-analyzer/src/config.rs |  9 ++++-----
     docs/user/generated_config.adoc    | 10 +++++-----
     editors/code/package.json          | 10 +++++-----
     4 files changed, 14 insertions(+), 17 deletions(-)
    
    diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
    index 73d118d8bb20..5b410c454d9d 100644
    --- a/crates/ide/src/references.rs
    +++ b/crates/ide/src/references.rs
    @@ -118,8 +118,6 @@ pub(crate) fn find_all_refs(
     }
     
     fn filter_import_references(usages: &mut UsageSearchResult) {
    -    // todo use this https://github.com/rust-lang/rust-analyzer/blob/master/crates/rust-analyzer/src/config.rs#L432
    -
         for (_file_id, refs) in &mut usages.references {
             refs.retain(|it| match it.name.as_name_ref() {
                 Some(name_ref) => {
    diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
    index 80a4b709e7cd..835eeb144a6a 100644
    --- a/crates/rust-analyzer/src/config.rs
    +++ b/crates/rust-analyzer/src/config.rs
    @@ -219,10 +219,6 @@ config_data! {
             files_excludeDirs: Vec = "[]",
             /// Controls file watching implementation.
             files_watcher: FilesWatcherDef = "\"client\"",
    -
    -        /// Exclude imports from find-all-references.
    -        findAllRefs_excludeImports: bool = "false",
    -
             /// Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.
             highlightRelated_breakPoints_enable: bool = "true",
             /// Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`).
    @@ -362,6 +358,9 @@ config_data! {
             /// this is rust-analyzer itself, but we override this in tests).
             procMacro_server: Option          = "null",
     
    +        /// Exclude imports from find-all-references.
    +        references_excludeImports: bool = "false",
    +
             /// Command to be executed instead of 'cargo' for runnables.
             runnables_command: Option = "null",
             /// Additional arguments to be passed to cargo for runnables such as
    @@ -1151,7 +1150,7 @@ impl Config {
         }
     
         pub fn find_all_refs_exclude_imports(&self) -> bool {
    -        self.data.findAllRefs_excludeImports
    +        self.data.references_excludeImports
         }
     
         pub fn snippet_cap(&self) -> bool {
    diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
    index 337629e17fd9..0e301e5d67d4 100644
    --- a/docs/user/generated_config.adoc
    +++ b/docs/user/generated_config.adoc
    @@ -262,11 +262,6 @@ also need to add the folders to Code's `files.watcherExclude`.
     --
     Controls file watching implementation.
     --
    -[[rust-analyzer.findAllRefs.excludeImports]]rust-analyzer.findAllRefs.excludeImports (default: `false`)::
    -+
    ---
    -Exclude imports from find-all-references.
    ---
     [[rust-analyzer.highlightRelated.breakPoints.enable]]rust-analyzer.highlightRelated.breakPoints.enable (default: `true`)::
     +
     --
    @@ -551,6 +546,11 @@ This config takes a map of crate names with the exported proc-macro names to ign
     Internal config, path to proc-macro server executable (typically,
     this is rust-analyzer itself, but we override this in tests).
     --
    +[[rust-analyzer.references.excludeImports]]rust-analyzer.references.excludeImports (default: `false`)::
    ++
    +--
    +Exclude imports from find-all-references.
    +--
     [[rust-analyzer.runnables.command]]rust-analyzer.runnables.command (default: `null`)::
     +
     --
    diff --git a/editors/code/package.json b/editors/code/package.json
    index 07e9a08e1bd7..9d39c7c296bb 100644
    --- a/editors/code/package.json
    +++ b/editors/code/package.json
    @@ -706,11 +706,6 @@
                             "Use server-side file watching"
                         ]
                     },
    -                "rust-analyzer.findAllRefs.excludeImports": {
    -                    "markdownDescription": "Exclude imports from find-all-references.",
    -                    "default": false,
    -                    "type": "boolean"
    -                },
                     "rust-analyzer.highlightRelated.breakPoints.enable": {
                         "markdownDescription": "Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.",
                         "default": true,
    @@ -1041,6 +1036,11 @@
                             "string"
                         ]
                     },
    +                "rust-analyzer.references.excludeImports": {
    +                    "markdownDescription": "Exclude imports from find-all-references.",
    +                    "default": false,
    +                    "type": "boolean"
    +                },
                     "rust-analyzer.runnables.command": {
                         "markdownDescription": "Command to be executed instead of 'cargo' for runnables.",
                         "default": null,
    
    From 7d19971666d50a0719e9a88f7dc67822ba96f87c Mon Sep 17 00:00:00 2001
    From: Lukas Wirth 
    Date: Fri, 9 Sep 2022 20:04:56 +0200
    Subject: [PATCH 4402/5092] Add config to unconditionally prefer core imports
     over std
    
    Fixes https://github.com/rust-lang/rust-analyzer/issues/12979
    ---
     crates/hir-def/src/find_path.rs               | 36 +++++++++++++++----
     crates/hir-ty/src/display.rs                  |  1 +
     crates/hir/src/lib.rs                         | 18 ++++++++--
     crates/ide-assists/src/assist_config.rs       |  1 +
     .../src/handlers/add_missing_match_arms.rs    | 17 ++++++---
     .../ide-assists/src/handlers/auto_import.rs   |  7 ++--
     .../src/handlers/convert_into_to_from.rs      |  2 +-
     .../src/handlers/extract_function.rs          |  1 +
     .../extract_struct_from_enum_variant.rs       |  1 +
     .../src/handlers/generate_deref.rs            |  6 ++--
     .../ide-assists/src/handlers/generate_new.rs  |  7 ++--
     .../src/handlers/qualify_method_call.rs       |  7 ++--
     .../ide-assists/src/handlers/qualify_path.rs  |  3 +-
     .../replace_derive_with_manual_impl.rs        |  2 +-
     .../replace_qualified_name_with_use.rs        |  1 +
     crates/ide-assists/src/tests.rs               |  1 +
     crates/ide-completion/src/completions.rs      |  4 ++-
     crates/ide-completion/src/completions/expr.rs |  8 +++--
     .../src/completions/flyimport.rs              | 14 ++++++--
     crates/ide-completion/src/config.rs           |  1 +
     crates/ide-completion/src/lib.rs              |  7 +++-
     crates/ide-completion/src/snippet.rs          |  8 +++--
     crates/ide-completion/src/tests.rs            |  1 +
     crates/ide-db/src/imports/import_assets.rs    | 13 ++++---
     crates/ide-db/src/path_transform.rs           |  3 +-
     .../src/handlers/json_is_not_rust.rs          |  2 ++
     .../src/handlers/missing_fields.rs            |  1 +
     crates/ide-diagnostics/src/lib.rs             |  2 ++
     crates/ide-ssr/src/matching.rs                |  7 ++--
     crates/rust-analyzer/src/config.rs            |  5 +++
     .../src/integrated_benchmarks.rs              |  2 ++
     docs/user/generated_config.adoc               |  5 +++
     editors/code/package.json                     |  5 +++
     33 files changed, 156 insertions(+), 43 deletions(-)
    
    diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs
    index 89e961f84fad..f46054e8cc5e 100644
    --- a/crates/hir-def/src/find_path.rs
    +++ b/crates/hir-def/src/find_path.rs
    @@ -16,9 +16,14 @@ use crate::{
     
     /// Find a path that can be used to refer to a certain item. This can depend on
     /// *from where* you're referring to the item, hence the `from` parameter.
    -pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option {
    +pub fn find_path(
    +    db: &dyn DefDatabase,
    +    item: ItemInNs,
    +    from: ModuleId,
    +    prefer_core: bool,
    +) -> Option {
         let _p = profile::span("find_path");
    -    find_path_inner(db, item, from, None)
    +    find_path_inner(db, item, from, None, prefer_core)
     }
     
     pub fn find_path_prefixed(
    @@ -26,9 +31,10 @@ pub fn find_path_prefixed(
         item: ItemInNs,
         from: ModuleId,
         prefix_kind: PrefixKind,
    +    prefer_core: bool,
     ) -> Option {
         let _p = profile::span("find_path_prefixed");
    -    find_path_inner(db, item, from, Some(prefix_kind))
    +    find_path_inner(db, item, from, Some(prefix_kind), prefer_core)
     }
     
     const MAX_PATH_LEN: usize = 15;
    @@ -100,12 +106,22 @@ fn find_path_inner(
         item: ItemInNs,
         from: ModuleId,
         prefixed: Option,
    +    prefer_core: bool,
     ) -> Option {
         // FIXME: Do fast path for std/core libs?
     
         let mut visited_modules = FxHashSet::default();
         let def_map = from.def_map(db);
    -    find_path_inner_(db, &def_map, from, item, MAX_PATH_LEN, prefixed, &mut visited_modules)
    +    find_path_inner_(
    +        db,
    +        &def_map,
    +        from,
    +        item,
    +        MAX_PATH_LEN,
    +        prefixed,
    +        &mut visited_modules,
    +        prefer_core,
    +    )
     }
     
     fn find_path_inner_(
    @@ -116,6 +132,7 @@ fn find_path_inner_(
         max_len: usize,
         mut prefixed: Option,
         visited_modules: &mut FxHashSet,
    +    prefer_core: bool,
     ) -> Option {
         if max_len == 0 {
             return None;
    @@ -191,7 +208,9 @@ fn find_path_inner_(
         // Recursive case:
         // - if the item is an enum variant, refer to it via the enum
         if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() {
    -        if let Some(mut path) = find_path(db, ItemInNs::Types(variant.parent.into()), from) {
    +        if let Some(mut path) =
    +            find_path(db, ItemInNs::Types(variant.parent.into()), from, prefer_core)
    +        {
                 let data = db.enum_data(variant.parent);
                 path.push_segment(data.variants[variant.local_id].name.clone());
                 return Some(path);
    @@ -202,7 +221,7 @@ fn find_path_inner_(
         }
     
         // - otherwise, look for modules containing (reexporting) it and import it from one of those
    -    let prefer_no_std = db.crate_supports_no_std(crate_root.krate);
    +    let prefer_no_std = prefer_core || db.crate_supports_no_std(crate_root.krate);
         let mut best_path = None;
         let mut best_path_len = max_len;
     
    @@ -223,6 +242,7 @@ fn find_path_inner_(
                     best_path_len - 1,
                     prefixed,
                     visited_modules,
    +                prefer_core,
                 ) {
                     path.push_segment(name);
     
    @@ -253,6 +273,7 @@ fn find_path_inner_(
                         best_path_len - 1,
                         prefixed,
                         visited_modules,
    +                    prefer_core,
                     )?;
                     cov_mark::hit!(partially_imported);
                     path.push_segment(info.path.segments.last()?.clone());
    @@ -428,7 +449,8 @@ mod tests {
                 .take_types()
                 .unwrap();
     
    -        let found_path = find_path_inner(&db, ItemInNs::Types(resolved), module, prefix_kind);
    +        let found_path =
    +            find_path_inner(&db, ItemInNs::Types(resolved), module, prefix_kind, false);
             assert_eq!(found_path, Some(mod_path), "{:?}", prefix_kind);
         }
     
    diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
    index d2f9c2b8b1e1..874abdaea837 100644
    --- a/crates/hir-ty/src/display.rs
    +++ b/crates/hir-ty/src/display.rs
    @@ -533,6 +533,7 @@ impl HirDisplay for Ty {
                                 f.db.upcast(),
                                 ItemInNs::Types((*def_id).into()),
                                 module_id,
    +                            false,
                             ) {
                                 write!(f, "{}", path)?;
                             } else {
    diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
    index e4bb63a86471..5fa4c1516248 100644
    --- a/crates/hir/src/lib.rs
    +++ b/crates/hir/src/lib.rs
    @@ -582,8 +582,13 @@ impl Module {
     
         /// Finds a path that can be used to refer to the given item from within
         /// this module, if possible.
    -    pub fn find_use_path(self, db: &dyn DefDatabase, item: impl Into) -> Option {
    -        hir_def::find_path::find_path(db, item.into().into(), self.into())
    +    pub fn find_use_path(
    +        self,
    +        db: &dyn DefDatabase,
    +        item: impl Into,
    +        prefer_core: bool,
    +    ) -> Option {
    +        hir_def::find_path::find_path(db, item.into().into(), self.into(), prefer_core)
         }
     
         /// Finds a path that can be used to refer to the given item from within
    @@ -593,8 +598,15 @@ impl Module {
             db: &dyn DefDatabase,
             item: impl Into,
             prefix_kind: PrefixKind,
    +        prefer_core: bool,
         ) -> Option {
    -        hir_def::find_path::find_path_prefixed(db, item.into().into(), self.into(), prefix_kind)
    +        hir_def::find_path::find_path_prefixed(
    +            db,
    +            item.into().into(),
    +            self.into(),
    +            prefix_kind,
    +            prefer_core,
    +        )
         }
     }
     
    diff --git a/crates/ide-assists/src/assist_config.rs b/crates/ide-assists/src/assist_config.rs
    index d4d148c77457..fe2dfca6d5e1 100644
    --- a/crates/ide-assists/src/assist_config.rs
    +++ b/crates/ide-assists/src/assist_config.rs
    @@ -13,4 +13,5 @@ pub struct AssistConfig {
         pub snippet_cap: Option,
         pub allowed: Option>,
         pub insert_use: InsertUseConfig,
    +    pub prefer_core: bool,
     }
    diff --git a/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/crates/ide-assists/src/handlers/add_missing_match_arms.rs
    index 1a7919a5a104..d4e21b778c51 100644
    --- a/crates/ide-assists/src/handlers/add_missing_match_arms.rs
    +++ b/crates/ide-assists/src/handlers/add_missing_match_arms.rs
    @@ -87,7 +87,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
                 .into_iter()
                 .filter_map(|variant| {
                     Some((
    -                    build_pat(ctx.db(), module, variant)?,
    +                    build_pat(ctx.db(), module, variant, ctx.config.prefer_core)?,
                         variant.should_be_hidden(ctx.db(), module.krate()),
                     ))
                 })
    @@ -132,8 +132,9 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
                     let is_hidden = variants
                         .iter()
                         .any(|variant| variant.should_be_hidden(ctx.db(), module.krate()));
    -                let patterns =
    -                    variants.into_iter().filter_map(|variant| build_pat(ctx.db(), module, variant));
    +                let patterns = variants.into_iter().filter_map(|variant| {
    +                    build_pat(ctx.db(), module, variant, ctx.config.prefer_core)
    +                });
     
                     (ast::Pat::from(make::tuple_pat(patterns)), is_hidden)
                 })
    @@ -349,10 +350,16 @@ fn resolve_tuple_of_enum_def(
             .collect()
     }
     
    -fn build_pat(db: &RootDatabase, module: hir::Module, var: ExtendedVariant) -> Option {
    +fn build_pat(
    +    db: &RootDatabase,
    +    module: hir::Module,
    +    var: ExtendedVariant,
    +    prefer_core: bool,
    +) -> Option {
         match var {
             ExtendedVariant::Variant(var) => {
    -            let path = mod_path_to_ast(&module.find_use_path(db, ModuleDef::from(var))?);
    +            let path =
    +                mod_path_to_ast(&module.find_use_path(db, ModuleDef::from(var), prefer_core)?);
     
                 // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though
                 let pat: ast::Pat = match var.source(db)?.value.kind() {
    diff --git a/crates/ide-assists/src/handlers/auto_import.rs b/crates/ide-assists/src/handlers/auto_import.rs
    index 949cf3167a8a..88a6b8558c95 100644
    --- a/crates/ide-assists/src/handlers/auto_import.rs
    +++ b/crates/ide-assists/src/handlers/auto_import.rs
    @@ -89,8 +89,11 @@ use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
     // ```
     pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
         let (import_assets, syntax_under_caret) = find_importable_node(ctx)?;
    -    let mut proposed_imports =
    -        import_assets.search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind);
    +    let mut proposed_imports = import_assets.search_for_imports(
    +        &ctx.sema,
    +        ctx.config.insert_use.prefix_kind,
    +        ctx.config.prefer_core,
    +    );
         if proposed_imports.is_empty() {
             return None;
         }
    diff --git a/crates/ide-assists/src/handlers/convert_into_to_from.rs b/crates/ide-assists/src/handlers/convert_into_to_from.rs
    index 30f6dd41a1d6..e0c0e9a48471 100644
    --- a/crates/ide-assists/src/handlers/convert_into_to_from.rs
    +++ b/crates/ide-assists/src/handlers/convert_into_to_from.rs
    @@ -50,7 +50,7 @@ pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext<'_>) -
                 _ => return None,
             };
     
    -        mod_path_to_ast(&module.find_use_path(ctx.db(), src_type_def)?)
    +        mod_path_to_ast(&module.find_use_path(ctx.db(), src_type_def, ctx.config.prefer_core)?)
         };
     
         let dest_type = match &ast_trait {
    diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs
    index 52a55ead3af9..749d94d5a928 100644
    --- a/crates/ide-assists/src/handlers/extract_function.rs
    +++ b/crates/ide-assists/src/handlers/extract_function.rs
    @@ -152,6 +152,7 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
                             ctx.sema.db,
                             ModuleDef::from(control_flow_enum),
                             ctx.config.insert_use.prefix_kind,
    +                        ctx.config.prefer_core,
                         );
     
                         if let Some(mod_path) = mod_path {
    diff --git a/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
    index ddc2052e7aa2..431f7b3c0fd6 100644
    --- a/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
    +++ b/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
    @@ -409,6 +409,7 @@ fn process_references(
                         ctx.sema.db,
                         *enum_module_def,
                         ctx.config.insert_use.prefix_kind,
    +                    ctx.config.prefer_core,
                     );
                     if let Some(mut mod_path) = mod_path {
                         mod_path.pop_segment();
    diff --git a/crates/ide-assists/src/handlers/generate_deref.rs b/crates/ide-assists/src/handlers/generate_deref.rs
    index b484635121eb..cf4ed84281ab 100644
    --- a/crates/ide-assists/src/handlers/generate_deref.rs
    +++ b/crates/ide-assists/src/handlers/generate_deref.rs
    @@ -58,7 +58,8 @@ fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
     
         let module = ctx.sema.to_def(&strukt)?.module(ctx.db());
         let trait_ = deref_type_to_generate.to_trait(&ctx.sema, module.krate())?;
    -    let trait_path = module.find_use_path(ctx.db(), ModuleDef::Trait(trait_))?;
    +    let trait_path =
    +        module.find_use_path(ctx.db(), ModuleDef::Trait(trait_), ctx.config.prefer_core)?;
     
         let field_type = field.ty()?;
         let field_name = field.name()?;
    @@ -98,7 +99,8 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()
     
         let module = ctx.sema.to_def(&strukt)?.module(ctx.db());
         let trait_ = deref_type_to_generate.to_trait(&ctx.sema, module.krate())?;
    -    let trait_path = module.find_use_path(ctx.db(), ModuleDef::Trait(trait_))?;
    +    let trait_path =
    +        module.find_use_path(ctx.db(), ModuleDef::Trait(trait_), ctx.config.prefer_core)?;
     
         let field_type = field.ty()?;
         let target = field.syntax().text_range();
    diff --git a/crates/ide-assists/src/handlers/generate_new.rs b/crates/ide-assists/src/handlers/generate_new.rs
    index 6c93875e9eb6..ceb7dac0fe97 100644
    --- a/crates/ide-assists/src/handlers/generate_new.rs
    +++ b/crates/ide-assists/src/handlers/generate_new.rs
    @@ -60,8 +60,11 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
     
                     let item_in_ns = hir::ItemInNs::from(hir::ModuleDef::from(ty.as_adt()?));
     
    -                let type_path = current_module
    -                    .find_use_path(ctx.sema.db, item_for_path_search(ctx.sema.db, item_in_ns)?)?;
    +                let type_path = current_module.find_use_path(
    +                    ctx.sema.db,
    +                    item_for_path_search(ctx.sema.db, item_in_ns)?,
    +                    ctx.config.prefer_core,
    +                )?;
     
                     let expr = use_trivial_constructor(
                         &ctx.sema.db,
    diff --git a/crates/ide-assists/src/handlers/qualify_method_call.rs b/crates/ide-assists/src/handlers/qualify_method_call.rs
    index 121f8b4a1368..cb81ebd22852 100644
    --- a/crates/ide-assists/src/handlers/qualify_method_call.rs
    +++ b/crates/ide-assists/src/handlers/qualify_method_call.rs
    @@ -44,8 +44,11 @@ pub(crate) fn qualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) ->
         let current_module = ctx.sema.scope(call.syntax())?.module();
         let target_module_def = ModuleDef::from(resolved_call);
         let item_in_ns = ItemInNs::from(target_module_def);
    -    let receiver_path = current_module
    -        .find_use_path(ctx.sema.db, item_for_path_search(ctx.sema.db, item_in_ns)?)?;
    +    let receiver_path = current_module.find_use_path(
    +        ctx.sema.db,
    +        item_for_path_search(ctx.sema.db, item_in_ns)?,
    +        ctx.config.prefer_core,
    +    )?;
     
         let qualify_candidate = QualifyCandidate::ImplMethod(ctx.sema.db, call, resolved_call);
     
    diff --git a/crates/ide-assists/src/handlers/qualify_path.rs b/crates/ide-assists/src/handlers/qualify_path.rs
    index 0c2e9da38639..232cd39e8ba2 100644
    --- a/crates/ide-assists/src/handlers/qualify_path.rs
    +++ b/crates/ide-assists/src/handlers/qualify_path.rs
    @@ -37,7 +37,8 @@ use crate::{
     // ```
     pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
         let (import_assets, syntax_under_caret) = find_importable_node(ctx)?;
    -    let mut proposed_imports = import_assets.search_for_relative_paths(&ctx.sema);
    +    let mut proposed_imports =
    +        import_assets.search_for_relative_paths(&ctx.sema, ctx.config.prefer_core);
         if proposed_imports.is_empty() {
             return None;
         }
    diff --git a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
    index d139f78a6f36..04a1366327f6 100644
    --- a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
    +++ b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
    @@ -85,7 +85,7 @@ pub(crate) fn replace_derive_with_manual_impl(
         })
         .flat_map(|trait_| {
             current_module
    -            .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_))
    +            .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_), ctx.config.prefer_core)
                 .as_ref()
                 .map(mod_path_to_ast)
                 .zip(Some(trait_))
    diff --git a/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs
    index 2419fa11c155..533e1670a045 100644
    --- a/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs
    +++ b/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs
    @@ -67,6 +67,7 @@ pub(crate) fn replace_qualified_name_with_use(
                     ctx.sema.db,
                     module,
                     ctx.config.insert_use.prefix_kind,
    +                ctx.config.prefer_core,
                 )
             })
             .flatten();
    diff --git a/crates/ide-assists/src/tests.rs b/crates/ide-assists/src/tests.rs
    index 9cd66c6b3b07..4e589dc86abb 100644
    --- a/crates/ide-assists/src/tests.rs
    +++ b/crates/ide-assists/src/tests.rs
    @@ -29,6 +29,7 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig {
             group: true,
             skip_glob_imports: true,
         },
    +    prefer_core: false,
     };
     
     pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) {
    diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs
    index 55c3e28392a4..89a971e544da 100644
    --- a/crates/ide-completion/src/completions.rs
    +++ b/crates/ide-completion/src/completions.rs
    @@ -551,7 +551,9 @@ fn enum_variants_with_paths(
         }
     
         for variant in variants {
    -        if let Some(path) = ctx.module.find_use_path(ctx.db, hir::ModuleDef::from(variant)) {
    +        if let Some(path) =
    +            ctx.module.find_use_path(ctx.db, hir::ModuleDef::from(variant), ctx.config.prefer_core)
    +        {
                 // Variants with trivial paths are already added by the existing completion logic,
                 // so we should avoid adding these twice
                 if path.segments().len() > 1 {
    diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs
    index 588b52cc1ee3..1ccf33a96b5c 100644
    --- a/crates/ide-completion/src/completions/expr.rs
    +++ b/crates/ide-completion/src/completions/expr.rs
    @@ -165,7 +165,11 @@ pub(crate) fn complete_expr_path(
                         hir::Adt::Struct(strukt) => {
                             let path = ctx
                                 .module
    -                            .find_use_path(ctx.db, hir::ModuleDef::from(strukt))
    +                            .find_use_path(
    +                                ctx.db,
    +                                hir::ModuleDef::from(strukt),
    +                                ctx.config.prefer_core,
    +                            )
                                 .filter(|it| it.len() > 1);
     
                             acc.add_struct_literal(ctx, path_ctx, strukt, path, None);
    @@ -183,7 +187,7 @@ pub(crate) fn complete_expr_path(
                         hir::Adt::Union(un) => {
                             let path = ctx
                                 .module
    -                            .find_use_path(ctx.db, hir::ModuleDef::from(un))
    +                            .find_use_path(ctx.db, hir::ModuleDef::from(un), ctx.config.prefer_core)
                                 .filter(|it| it.len() > 1);
     
                             acc.add_union_literal(ctx, un, path, None);
    diff --git a/crates/ide-completion/src/completions/flyimport.rs b/crates/ide-completion/src/completions/flyimport.rs
    index f04cc15d7fab..528959943bb9 100644
    --- a/crates/ide-completion/src/completions/flyimport.rs
    +++ b/crates/ide-completion/src/completions/flyimport.rs
    @@ -262,7 +262,11 @@ fn import_on_the_fly(
     
         acc.add_all(
             import_assets
    -            .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind)
    +            .search_for_imports(
    +                &ctx.sema,
    +                ctx.config.insert_use.prefix_kind,
    +                ctx.config.prefer_core,
    +            )
                 .into_iter()
                 .filter(ns_filter)
                 .filter(|import| {
    @@ -306,7 +310,11 @@ fn import_on_the_fly_pat_(
     
         acc.add_all(
             import_assets
    -            .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind)
    +            .search_for_imports(
    +                &ctx.sema,
    +                ctx.config.insert_use.prefix_kind,
    +                ctx.config.prefer_core,
    +            )
                 .into_iter()
                 .filter(ns_filter)
                 .filter(|import| {
    @@ -344,7 +352,7 @@ fn import_on_the_fly_method(
         let user_input_lowercased = potential_import_name.to_lowercase();
     
         import_assets
    -        .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind)
    +        .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind, ctx.config.prefer_core)
             .into_iter()
             .filter(|import| {
                 !ctx.is_item_hidden(&import.item_to_import)
    diff --git a/crates/ide-completion/src/config.rs b/crates/ide-completion/src/config.rs
    index 80d6af28168f..54ebce1eb798 100644
    --- a/crates/ide-completion/src/config.rs
    +++ b/crates/ide-completion/src/config.rs
    @@ -17,6 +17,7 @@ pub struct CompletionConfig {
         pub callable: Option,
         pub snippet_cap: Option,
         pub insert_use: InsertUseConfig,
    +    pub prefer_core: bool,
         pub snippets: Vec,
     }
     
    diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs
    index ae1a440d06da..7cefb6bb4a30 100644
    --- a/crates/ide-completion/src/lib.rs
    +++ b/crates/ide-completion/src/lib.rs
    @@ -234,7 +234,12 @@ pub fn resolve_completion_edits(
             );
             let import = items_with_name
                 .filter_map(|candidate| {
    -                current_module.find_use_path_prefixed(db, candidate, config.insert_use.prefix_kind)
    +                current_module.find_use_path_prefixed(
    +                    db,
    +                    candidate,
    +                    config.insert_use.prefix_kind,
    +                    config.prefer_core,
    +                )
                 })
                 .find(|mod_path| mod_path.to_string() == full_import_path);
             if let Some(import_path) = import {
    diff --git a/crates/ide-completion/src/snippet.rs b/crates/ide-completion/src/snippet.rs
    index dc1039fa623e..2dc62bbdc65c 100644
    --- a/crates/ide-completion/src/snippet.rs
    +++ b/crates/ide-completion/src/snippet.rs
    @@ -174,8 +174,12 @@ fn import_edits(ctx: &CompletionContext<'_>, requires: &[GreenNode]) -> Option def.into(),
                 _ => return None,
             };
    -        let path =
    -            ctx.module.find_use_path_prefixed(ctx.db, item, ctx.config.insert_use.prefix_kind)?;
    +        let path = ctx.module.find_use_path_prefixed(
    +            ctx.db,
    +            item,
    +            ctx.config.insert_use.prefix_kind,
    +            ctx.config.prefer_core,
    +        )?;
             Some((path.len() > 1).then(|| LocatedImport::new(path.clone(), item, item, None)))
         };
         let mut res = Vec::with_capacity(requires.len());
    diff --git a/crates/ide-completion/src/tests.rs b/crates/ide-completion/src/tests.rs
    index cf826648dcf7..d24c9148566f 100644
    --- a/crates/ide-completion/src/tests.rs
    +++ b/crates/ide-completion/src/tests.rs
    @@ -66,6 +66,7 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
         enable_private_editable: false,
         callable: Some(CallableSnippets::FillArguments),
         snippet_cap: SnippetCap::new(true),
    +    prefer_core: false,
         insert_use: InsertUseConfig {
             granularity: ImportGranularity::Crate,
             prefix_kind: PrefixKind::Plain,
    diff --git a/crates/ide-db/src/imports/import_assets.rs b/crates/ide-db/src/imports/import_assets.rs
    index 26ef86155e53..53bc516109a2 100644
    --- a/crates/ide-db/src/imports/import_assets.rs
    +++ b/crates/ide-db/src/imports/import_assets.rs
    @@ -212,18 +212,20 @@ impl ImportAssets {
             &self,
             sema: &Semantics<'_, RootDatabase>,
             prefix_kind: PrefixKind,
    +        prefer_core: bool,
         ) -> Vec {
             let _p = profile::span("import_assets::search_for_imports");
    -        self.search_for(sema, Some(prefix_kind))
    +        self.search_for(sema, Some(prefix_kind), prefer_core)
         }
     
         /// This may return non-absolute paths if a part of the returned path is already imported into scope.
         pub fn search_for_relative_paths(
             &self,
             sema: &Semantics<'_, RootDatabase>,
    +        prefer_core: bool,
         ) -> Vec {
             let _p = profile::span("import_assets::search_for_relative_paths");
    -        self.search_for(sema, None)
    +        self.search_for(sema, None, prefer_core)
         }
     
         pub fn path_fuzzy_name_to_exact(&mut self, case_sensitive: bool) {
    @@ -242,6 +244,7 @@ impl ImportAssets {
             &self,
             sema: &Semantics<'_, RootDatabase>,
             prefixed: Option,
    +        prefer_core: bool,
         ) -> Vec {
             let _p = profile::span("import_assets::search_for");
     
    @@ -252,6 +255,7 @@ impl ImportAssets {
                     item_for_path_search(sema.db, item)?,
                     &self.module_with_candidate,
                     prefixed,
    +                prefer_core,
                 )
             };
     
    @@ -564,11 +568,12 @@ fn get_mod_path(
         item_to_search: ItemInNs,
         module_with_candidate: &Module,
         prefixed: Option,
    +    prefer_core: bool,
     ) -> Option {
         if let Some(prefix_kind) = prefixed {
    -        module_with_candidate.find_use_path_prefixed(db, item_to_search, prefix_kind)
    +        module_with_candidate.find_use_path_prefixed(db, item_to_search, prefix_kind, prefer_core)
         } else {
    -        module_with_candidate.find_use_path(db, item_to_search)
    +        module_with_candidate.find_use_path(db, item_to_search, prefer_core)
         }
     }
     
    diff --git a/crates/ide-db/src/path_transform.rs b/crates/ide-db/src/path_transform.rs
    index 40af9e6fe2ad..12d873b4a0aa 100644
    --- a/crates/ide-db/src/path_transform.rs
    +++ b/crates/ide-db/src/path_transform.rs
    @@ -173,6 +173,7 @@ impl<'a> Ctx<'a> {
                                 let found_path = self.target_module.find_use_path(
                                     self.source_scope.db.upcast(),
                                     hir::ModuleDef::Trait(trait_ref),
    +                                false,
                                 )?;
                                 match ast::make::ty_path(mod_path_to_ast(&found_path)) {
                                     ast::Type::PathType(path_ty) => Some(path_ty),
    @@ -209,7 +210,7 @@ impl<'a> Ctx<'a> {
                     }
     
                     let found_path =
    -                    self.target_module.find_use_path(self.source_scope.db.upcast(), def)?;
    +                    self.target_module.find_use_path(self.source_scope.db.upcast(), def, false)?;
                     let res = mod_path_to_ast(&found_path).clone_for_update();
                     if let Some(args) = path.segment().and_then(|it| it.generic_arg_list()) {
                         if let Some(segment) = res.segment() {
    diff --git a/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
    index a21db5b2cec9..06073ca1b250 100644
    --- a/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
    +++ b/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
    @@ -137,6 +137,7 @@ pub(crate) fn json_in_items(
                                             sema.db,
                                             it,
                                             config.insert_use.prefix_kind,
    +                                        config.prefer_core,
                                         ) {
                                             insert_use(
                                                 &scope,
    @@ -152,6 +153,7 @@ pub(crate) fn json_in_items(
                                             sema.db,
                                             it,
                                             config.insert_use.prefix_kind,
    +                                        config.prefer_core,
                                         ) {
                                             insert_use(
                                                 &scope,
    diff --git a/crates/ide-diagnostics/src/handlers/missing_fields.rs b/crates/ide-diagnostics/src/handlers/missing_fields.rs
    index edb1fc0919c2..5a81a55d8221 100644
    --- a/crates/ide-diagnostics/src/handlers/missing_fields.rs
    +++ b/crates/ide-diagnostics/src/handlers/missing_fields.rs
    @@ -124,6 +124,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option ExprFillDefaultMode::Default,
                 },
                 insert_use: self.insert_use_config(),
    +            prefer_core: self.data.imports_prefer_core,
             }
         }
     
    @@ -1133,6 +1136,7 @@ impl Config {
                     CallableCompletionDef::None => None,
                 },
                 insert_use: self.insert_use_config(),
    +            prefer_core: self.data.imports_prefer_core,
                 snippet_cap: SnippetCap::new(try_or_def!(
                     self.caps
                         .text_document
    @@ -1156,6 +1160,7 @@ impl Config {
                 snippet_cap: SnippetCap::new(self.experimental("snippetTextEdit")),
                 allowed: None,
                 insert_use: self.insert_use_config(),
    +            prefer_core: self.data.imports_prefer_core,
             }
         }
     
    diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs
    index e49a98685a7f..5dbb64d7df19 100644
    --- a/crates/rust-analyzer/src/integrated_benchmarks.rs
    +++ b/crates/rust-analyzer/src/integrated_benchmarks.rs
    @@ -145,6 +145,7 @@ fn integrated_completion_benchmark() {
                     skip_glob_imports: true,
                 },
                 snippets: Vec::new(),
    +            prefer_core: false,
             };
             let position =
                 FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
    @@ -182,6 +183,7 @@ fn integrated_completion_benchmark() {
                     skip_glob_imports: true,
                 },
                 snippets: Vec::new(),
    +            prefer_core: false,
             };
             let position =
                 FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
    diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
    index 72b925726479..6757624aea6a 100644
    --- a/docs/user/generated_config.adoc
    +++ b/docs/user/generated_config.adoc
    @@ -353,6 +353,11 @@ Group inserted imports by the https://rust-analyzer.github.io/manual.html#auto-i
     --
     Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.
     --
    +[[rust-analyzer.imports.prefer.core]]rust-analyzer.imports.prefer.core (default: `false`)::
    ++
    +--
    +Prefer to use imports of the core crate over the std crate.
    +--
     [[rust-analyzer.imports.prefix]]rust-analyzer.imports.prefix (default: `"plain"`)::
     +
     --
    diff --git a/editors/code/package.json b/editors/code/package.json
    index 767c5875bf7e..7e91d989f156 100644
    --- a/editors/code/package.json
    +++ b/editors/code/package.json
    @@ -803,6 +803,11 @@
                         "default": true,
                         "type": "boolean"
                     },
    +                "rust-analyzer.imports.prefer.core": {
    +                    "markdownDescription": "Prefer to use imports of the core crate over the std crate.",
    +                    "default": false,
    +                    "type": "boolean"
    +                },
                     "rust-analyzer.imports.prefix": {
                         "markdownDescription": "The path structure for newly inserted paths to use.",
                         "default": "plain",
    
    From 0698ffbdb590d76cdeec0a1f06331fe82ff9aada Mon Sep 17 00:00:00 2001
    From: Michael Howell 
    Date: Fri, 9 Sep 2022 11:48:43 -0700
    Subject: [PATCH 4403/5092] rustdoc: update test cases
    
    Width changed by 2/4 pixels by b273c7502e363baeec293b972f671070e80f1391
    ---
     src/test/rustdoc-gui/search-result-display.goml | 4 ++--
     1 file changed, 2 insertions(+), 2 deletions(-)
    
    diff --git a/src/test/rustdoc-gui/search-result-display.goml b/src/test/rustdoc-gui/search-result-display.goml
    index db4907924faf..54482005fa60 100644
    --- a/src/test/rustdoc-gui/search-result-display.goml
    +++ b/src/test/rustdoc-gui/search-result-display.goml
    @@ -7,11 +7,11 @@ press-key: 'Enter'
     wait-for: "#crate-search"
     // The width is returned by "getComputedStyle" which returns the exact number instead of the
     // CSS rule which is "50%"...
    -assert-css: (".search-results div.desc", {"width": "295px"})
    +assert-css: (".search-results div.desc", {"width": "293px"})
     size: (600, 100)
     // As counter-intuitive as it may seem, in this width, the width is "100%", which is why
     // when computed it's larger.
    -assert-css: (".search-results div.desc", {"width": "570px"})
    +assert-css: (".search-results div.desc", {"width": "566px"})
     
     // Check that the crate filter `` is correctly handled when it goes to next line.
     // To do so we need to update the length of one of its `
  • \ - Back to list of error codes\ -